doublecmd-1.1.22/0000755000175000001440000000000014743153644012606 5ustar alexxusersdoublecmd-1.1.22/.gitattributes0000644000175000001440000000007214743153644015500 0ustar alexxusers*.sh text eol=lf *.bat -text language/*.po text eol=lf doublecmd-1.1.22/.gitignore0000644000175000001440000000070014743153644014573 0ustar alexxusers# Lazarus compiler-generated binaries (safe to delete) *.exe *.dll *.so *.dylib *.lrs *.res *.compiled *.dbg *.ppu *.o *.or *.a *.zdli *.dsx *.w?x units/ /doublecmd # Lazarus autogenerated files (duplicated info) *.rst *.rsj # Lazarus local files (user-specific info) *.lps # Lazarus backups and unit output folders. # These can be changed by user in Lazarus/project options. backup/ *.bak lib/ # Application bundle for Mac OS *.app/ .DS_Store doublecmd-1.1.22/LICENSE.md0000644000175000001440000004274714743153644014230 0ustar alexxusers### GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. ### Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. ### 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. one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands \`show w' and \`show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than \`show w' and \`show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl.html) instead of this License. doublecmd-1.1.22/README.md0000644000175000001440000000263314743153644014071 0ustar alexxusers**Double Commander** is a [free](https://www.gnu.org/philosophy/free-sw.html) cross-platform open source file manager with two panels side by side (or one above the other). It is inspired by Total Commander and features some innovative new ideas. Double Commander can be run on several platforms and operating systems. It supports 32-bit and 64-bit processors. See [Supported platforms](https://github.com/doublecmd/doublecmd/wiki/Supported-platforms) for a complete list. See Double Commander in action in the [Screenshot Gallery](https://doublecmd.sourceforge.io/gallery). ## Where to start ### Download Go to the [Double Commander download page](https://sourceforge.net/p/doublecmd/wiki/Download) to download the latest release. You can check the latest version on the [Versions](https://github.com/doublecmd/doublecmd/wiki/Versions) page. See if Double Commander is supported for your platform on the [Supported platforms](https://github.com/doublecmd/doublecmd/wiki/Supported-platforms) page. ### Develop For more information on the development of Double Commander, see the [Development](https://github.com/doublecmd/doublecmd/wiki/Development) page. ### Discuss Go to our [forum](https://doublecmd.h1n.ru) for discussions. There are English and Russian sections. If you want to stay up-to-date with the project, you can check out the available [news feeds](https://github.com/doublecmd/doublecmd/wiki/News-feeds). doublecmd-1.1.22/build.bat0000644000175000001440000000421414743153644014376 0ustar alexxusers@echo off rem Add Lazarus installation to path if [%LAZARUS_HOME%] == [] set LAZARUS_HOME=D:\Alexx\Prog\FreePascal\Lazarus set PATH=%LAZARUS_HOME%;%PATH% rem You can execute this script with different parameters: rem components - compiling components needed for doublecmd rem doublecmd - compiling doublecmd only (release mode) rem plugins - compiling all doublecmd plugins rem debug - compiling components, plugins and doublecmd (debug mode) rem release - compile in release mode (using by default) if not "%OS_TARGET%" == "" ( set DC_ARCH=%DC_ARCH% --os=%OS_TARGET% ) if not "%CPU_TARGET%" == "" ( set DC_ARCH=%DC_ARCH% --cpu=%CPU_TARGET% ) if not "%LCL_PLATFORM%" == "" ( set DC_ARCH=%DC_ARCH% --ws=%LCL_PLATFORM% ) if "%1"=="components" ( call :components ) else ( if "%1"=="plugins" ( call :plugins ) else ( if "%1"=="beta" ( call :release ) else ( if "%1"=="doublecmd" ( call :doublecmd ) else ( if "%1"=="release" ( call :release ) else ( if "%1"=="darkwin" ( call :darkwin ) else ( if "%1"=="debug" ( call :debug ) else ( if "%1"=="" ( call :release ) else ( echo ERROR: Mode not defined: %1 echo Available modes: components, plugins, doublecmd, release, darkwin, debug )))))))) GOTO:EOF :components call components\build.bat GOTO:EOF :plugins call plugins\build.bat GOTO:EOF :release call :components call :plugins call :doublecmd GOTO:EOF :debug call :components call :plugins rem Build Double Commander call :replace_old lazbuild src\doublecmd.lpi --bm=debug %DC_ARCH% GOTO:EOF :doublecmd rem Build Double Commander call :replace_old lazbuild src\doublecmd.lpi --bm=release %DC_ARCH% call :extract GOTO:EOF :darkwin call :components call :plugins rem Build Double Commander call :replace_old lazbuild src\doublecmd.lpi --bm=darkwin %DC_ARCH% call :extract GOTO:EOF :extract rem Build Dwarf LineInfo Extractor lazbuild tools\extractdwrflnfo.lpi rem Extract debug line info tools\extractdwrflnfo doublecmd.dbg GOTO:EOF :replace_old del /Q doublecmd.exe.old ren doublecmd.exe doublecmd.exe.old GOTO:EOF doublecmd-1.1.22/build.sh0000755000175000001440000000317014743153644014245 0ustar alexxusers#!/bin/sh set -e # You can execute this script with different parameters: # components - compiling components needed for doublecmd # doublecmd - compiling doublecmd only (release mode) # plugins - compiling all doublecmd plugins # debug - compiling components, plugins and doublecmd (debug mode) # release - compile in release mode (using by default) # path to lazbuild export lazbuild=$(which lazbuild) # Set up widgetset: gtk2 or qt or qt5 or cocoa # Set up processor architecture: i386 or x86_64 if [ $2 ] then export lcl=$2 fi if [ $lcl ] && [ $CPU_TARGET ] then export DC_ARCH=$(echo "--widgetset=$lcl")" "$(echo "--cpu=$CPU_TARGET") elif [ $lcl ] then export DC_ARCH=$(echo "--widgetset=$lcl") elif [ $CPU_TARGET ] then export DC_ARCH=$(echo "--cpu=$CPU_TARGET") fi build_doublecmd() { # Build Double Commander $lazbuild src/doublecmd.lpi --bm=release $DC_ARCH # Build Dwarf LineInfo Extractor $lazbuild tools/extractdwrflnfo.lpi # Extract debug line info chmod a+x tools/extractdwrflnfo if [ -f doublecmd.dSYM/Contents/Resources/DWARF/doublecmd ]; then mv -f doublecmd.dSYM/Contents/Resources/DWARF/doublecmd $(pwd)/doublecmd.dbg fi tools/extractdwrflnfo doublecmd.dbg # Strip debug info strip doublecmd } build_release() { components/build.sh plugins/build.sh build_doublecmd } build_debug() { components/build.sh plugins/build.sh # Build Double Commander $lazbuild src/doublecmd.lpi --bm=debug $DC_ARCH } case $1 in components) components/build.sh;; doublecmd) build_doublecmd;; plugins) plugins/build.sh;; debug) build_debug;; *) build_release;; esac doublecmd-1.1.22/clean.bat0000644000175000001440000000332314743153644014361 0ustar alexxusers@echo Clean up output directory @del /Q /S units\i386-win32-win32\*.* @del /Q /S units\x86_64-win64-win32\*.* @del /Q src\*.*~ @del /Q src\*.~* @del /Q doublecmd.dbg @del /Q doublecmd.zdli @del /Q doublecmd*.exe @del /Q doublecmd*.old @echo Remove generated help files @del /Q doc\en\dev-help\*.* @echo Clean up tools output directories @del /Q /S tools\lib\*.* @del /Q tools\extractdwrflnfo.exe @echo Clean up plugins output directories @del /Q /S plugins\*.dsx @del /Q /S plugins\*.w?x @del /Q /S plugins\dsx\DSXLocate\lib\*.* @del /Q /S plugins\wcx\base64\lib\*.* @del /Q /S plugins\wcx\cpio\lib\*.* @del /Q /S plugins\wcx\deb\lib\*.* @del /Q /S plugins\wcx\rpm\lib\*.* @del /Q /S plugins\wcx\sevenzip\lib\*.* @del /Q /S plugins\wcx\torrent\lib\*.* @del /Q /S plugins\wcx\unrar\lib\*.* @del /Q /S plugins\wcx\zip\lib\*.* @del /Q /S plugins\wdx\deb_wdx\lib\*.* @del /Q /S plugins\wdx\rpm_wdx\lib\*.* @del /Q /S plugins\wdx\audioinfo\lib\*.* @del /Q /S plugins\wfx\ftp\lib\*.* @del /Q /S plugins\wfx\sample\lib\*.* @del /Q /S plugins\wlx\preview\lib\*.* @del /Q /S plugins\wlx\richview\lib\*.* @del /Q /S plugins\wlx\simplewlx\lib\*.* @del /Q /S plugins\wlx\wmp\lib\*.* @echo Remove backup files @del /Q /S plugins\*.*~ @del /Q /S plugins\*.bak @echo Clean up components output directories @del /Q /S components\chsdet\lib\*.* @del /Q /S components\kascrypt\lib\*.* @del /Q /S components\doublecmd\lib\*.* @del /Q /S components\gifanim\lib\*.* @del /Q /S components\KASToolBar\lib\*.* @del /Q /S components\multithreadprocs\lib\*.* @del /Q /S components\viewer\lib\*.* @del /Q /S components\synunihighlighter\lib\*.* @del /Q /S components\virtualterminal\lib\*.* @echo Done.doublecmd-1.1.22/clean.sh0000755000175000001440000000234514743153644014233 0ustar alexxusers#!/bin/sh # Clean up output directories rm -f units/*/* # Clean up components output directories rm -rf components/chsdet/lib/* rm -rf components/kascrypt/lib/* rm -rf components/doublecmd/lib/* rm -rf components/gifanim/lib/* rm -rf components/Image32/lib/* rm -rf components/KASToolBar/lib/* rm -rf components/multithreadprocs/lib/* rm -rf components/viewer/lib/* rm -rf components/synunihighlighter/lib/* rm -rf components/virtualterminal/lib/* # Clean up all temporary files find . -iname '*.compiled' -delete find . -iname '*.ppu' -delete find . -iname '*.o' -delete find plugins -iname '*.w?x' -delete find plugins -iname '*.dsx' -delete find plugins -iname '*.or' -delete find plugins -iname '*.res' -not -path "*/sevenzip/src/*" -delete find plugins -iname '*.a' -delete rm -f src/doublecmd.res doublecmd rm -f tools/extractdwrflnfo rm -f plugins/wcx/unrar/lib/rarconfdlg.lfm rm -f plugins/wcx/unrar/lib/rarlng.rsj rm -f plugins/wcx/zip/lib/ZipConfDlg.lfm rm -f plugins/wcx/zip/lib/ZipLng.rsj rm -f plugins/wcx/zip/lib/abresstring.rs? rm -f plugins/wfx/ftp/lib/FtpConfDlg.lfm rm -f plugins/wfx/ftp/lib/ftppropdlg.lfm rm -f plugins/wfx/samba/lib/smbauthdlg.lfm # Remove debug files rm -f doublecmd.zdli doublecmd.dbg rm -rf doublecmd.dSYM doublecmd-1.1.22/components/0000755000175000001440000000000014743153644014773 5ustar alexxusersdoublecmd-1.1.22/components/Image32/0000755000175000001440000000000014743153644016162 5ustar alexxusersdoublecmd-1.1.22/components/Image32/Image32.lpk0000644000175000001440000000643014743153644020064 0ustar alexxusers doublecmd-1.1.22/components/Image32/Image32.pas0000644000175000001440000000061614743153644020061 0ustar alexxusers{ This file was automatically created by Lazarus. Do not edit! This source is only used to compile and install the package. } unit Image32; {$warn 5023 off : no warning about unused units} interface uses Img32.Draw, Img32.Extra, Img32.Fmt.SVG, Img32, Img32.Resamplers, Img32.SVG.Core, Img32.SVG.Path, Img32.SVG.Reader, Img32.Text, Img32.Transform, Img32.Vector; implementation end. doublecmd-1.1.22/components/Image32/LICENSE.txt0000644000175000001440000000247214743153644020012 0ustar alexxusersBoost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. doublecmd-1.1.22/components/Image32/README.md0000644000175000001440000000022514743153644017440 0ustar alexxusers# Image32 A 2D graphics library written in Delphi Pascal https://github.com/AngusJohnson/Image32 Version: 4.3+ (2022/10/16) Author: Angus Johnsondoublecmd-1.1.22/components/Image32/source/0000755000175000001440000000000014743153644017462 5ustar alexxusersdoublecmd-1.1.22/components/Image32/source/Img32.Draw.pas0000644000175000001440000020450214743153644021747 0ustar alexxusersunit Img32.Draw; (******************************************************************************* * Author : Angus Johnson * * Version : 4.3 * * Date : 27 September 2022 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2019-2021 * * * * Purpose : Polygon renderer for TImage32 * * * * License : Use, modification & distribution is subject to * * Boost Software License Ver 1 * * http://www.boost.org/LICENSE_1_0.txt * *******************************************************************************) interface {$I Img32.inc} {.$DEFINE MemCheck} //for debugging only (adds a minimal cost to performance) uses SysUtils, Classes, Types, Math, Img32, Img32.Vector; type TFillRule = Img32.Vector.TFillRule; //TGradientColor: used internally by both //TLinearGradientRenderer and TRadialGradientRenderer TGradientColor = record offset: double; color: TColor32; end; TArrayOfGradientColor = array of TGradientColor; TGradientFillStyle = (gfsClamp, gfsMirror, gfsRepeat); //TBoundsProc: Function template for TCustomRenderer. TBoundsProc = function(dist, colorsCnt: integer): integer; TBoundsProcD = function(dist: double; colorsCnt: integer): integer; TImage32ChangeProc = procedure of object; //TCustomRenderer: can accommodate pixels of any size TCustomRenderer = class {$IFDEF ABSTRACT_CLASSES} abstract {$ENDIF} private fImgWidth : integer; fImgHeight : integer; fImgBase : Pointer; fCurrY : integer; fCurrLinePtr : Pointer; fPixelSize : integer; fChangeProc : TImage32ChangeProc; protected procedure NotifyChange; function Initialize(imgBase: Pointer; imgWidth, imgHeight, pixelSize: integer): Boolean; overload; virtual; function Initialize(targetImage: TImage32): Boolean; overload; virtual; function GetDstPixel(x,y: integer): Pointer; //RenderProc: x & y refer to pixel coords in the destination image and //where x1 is the start (and left) and x2 is the end of the render procedure RenderProc(x1, x2, y: integer; alpha: PByte); virtual; abstract; property ImgWidth: integer read fImgWidth; property ImgHeight: integer read fImgHeight; property ImgBase: Pointer read fImgBase; property PixelSize: integer read fPixelSize; end; TColorRenderer = class(TCustomRenderer) private fAlpha: Byte; fColor: TColor32; protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; function Initialize(targetImage: TImage32): Boolean; override; public constructor Create(color: TColor32 = clNone32); procedure SetColor(value: TColor32); end; TAliasedColorRenderer = class(TCustomRenderer) private fColor: TColor32; protected function Initialize(targetImage: TImage32): Boolean; override; procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; public constructor Create(color: TColor32 = clNone32); end; TEraseRenderer = class(TCustomRenderer) protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; end; TInverseRenderer = class(TCustomRenderer) protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; end; TImageRenderer = class(TCustomRenderer) private fImage : TImage32; fOffset : TPoint; fBrushPixel : PARGB; fLastYY : integer; fMirrorY : Boolean; fBoundsProc : TBoundsProc; function GetFirstBrushPixel(x, y: integer): PARGB; protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; function Initialize(targetImage: TImage32): Boolean; override; public constructor Create(tileFillStyle: TTileFillStyle = tfsRepeat; brushImage: TImage32 = nil); destructor Destroy; override; procedure SetTileFillStyle(value: TTileFillStyle); property Image: TImage32 read fImage; property Offset: TPoint read fOffset write fOffset; end; //TCustomGradientRenderer is also an abstract class TCustomGradientRenderer = class(TCustomRenderer) private fBoundsProc : TBoundsProc; fGradientColors : TArrayOfGradientColor; protected fColors : TArrayOfColor32; fColorsCnt : integer; procedure SetGradientFillStyle(value: TGradientFillStyle); virtual; public constructor Create; procedure SetParameters(startColor, endColor: TColor32; gradFillStyle: TGradientFillStyle = gfsClamp); virtual; procedure InsertColorStop(offsetFrac: double; color: TColor32); procedure Clear; end; TLinearGradientRenderer = class(TCustomGradientRenderer) private fStartPt : TPointD; fEndPt : TPointD; fPerpendicOffsets: TArrayOfInteger; fIsVert : Boolean; protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; function Initialize(targetImage: TImage32): Boolean; override; public procedure SetParameters(const startPt, endPt: TPointD; startColor, endColor: TColor32; gradFillStyle: TGradientFillStyle = gfsClamp); reintroduce; end; TRadialGradientRenderer = class(TCustomGradientRenderer) private fCenterPt : TPointD; fScaleX : double; fScaleY : double; fColors : TArrayOfColor32; protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; function Initialize(targetImage: TImage32): Boolean; override; public procedure SetParameters(const focalRect: TRect; innerColor, outerColor: TColor32; gradientFillStyle: TGradientFillStyle = gfsClamp); reintroduce; end; TSvgRadialGradientRenderer = class(TCustomGradientRenderer) private fA, fB : double; fAA, fBB : double; fCenterPt : TPointD; fFocusPt : TPointD; fBoundsProcD : TBoundsProcD; protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; function Initialize(targetImage: TImage32): Boolean; override; public procedure SetParameters(const ellipseRect: TRect; const focus: TPoint; innerColor, outerColor: TColor32; gradientFillStyle: TGradientFillStyle = gfsClamp); reintroduce; end; //Barycentric rendering colorizes inside triangles TBarycentricRenderer = class(TCustomRenderer) private a: TPointD; c1, c2, c3: TARGB; v0, v1: TPointD; d00, d01, d11, invDenom: double; function GetColor(const pt: TPointD): TColor32; protected procedure RenderProc(x1, x2, y: integer; alpha: PByte); override; public procedure SetParameters(const a, b, c: TPointD; c1, c2, c3: TColor32); end; /////////////////////////////////////////////////////////////////////////// // DRAWING FUNCTIONS /////////////////////////////////////////////////////////////////////////// procedure DrawPoint(img: TImage32; const pt: TPointD; radius: double; color: TColor32); overload; procedure DrawPoint(img: TImage32; const pt: TPointD; radius: double; renderer: TCustomRenderer); overload; procedure DrawPoint(img: TImage32; const points: TPathD; radius: double; color: TColor32); overload; procedure DrawPoint(img: TImage32; const paths: TPathsD; radius: double; color: TColor32); overload; procedure DrawLine(img: TImage32; const pt1, pt2: TPointD; lineWidth: double; color: TColor32); overload; procedure DrawLine(img: TImage32; const line: TPathD; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto; miterLimit: double = 2); overload; procedure DrawLine(img: TImage32; const line: TPathD; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto; miterLimit: double = 2); overload; procedure DrawLine(img: TImage32; const lines: TPathsD; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto; miterLimit: double = 2); overload; procedure DrawLine(img: TImage32; const lines: TPathsD; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto; miterLimit: double = 2); overload; procedure DrawInvertedLine(img: TImage32; const line: TPathD; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawInvertedLine(img: TImage32; const lines: TPathsD; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawDashedLine(img: TImage32; const line: TPathD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawDashedLine(img: TImage32; const lines: TPathsD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawDashedLine(img: TImage32; const line: TPathD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawDashedLine(img: TImage32; const lines: TPathsD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawInvertedDashedLine(img: TImage32; const line: TPathD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawInvertedDashedLine(img: TImage32; const lines: TPathsD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); overload; procedure DrawPolygon(img: TImage32; const polygon: TPathD; fillRule: TFillRule; color: TColor32); overload; procedure DrawPolygon(img: TImage32; const polygon: TPathD; fillRule: TFillRule; renderer: TCustomRenderer); overload; procedure DrawPolygon(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; color: TColor32); overload; procedure DrawPolygon(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; renderer: TCustomRenderer); overload; // 'Clear Type' text rendering is quite useful for low resolution // displays (96 ppi). However it's of little to no benefit on higher // resolution displays and becomes unnecessary overhead. See also: // https://en.wikipedia.org/wiki/Subpixel_rendering // https://www.grc.com/ctwhat.htm // https://www.grc.com/cttech.htm procedure DrawPolygon_ClearType(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; color: TColor32; backColor: TColor32 = clWhite32); /////////////////////////////////////////////////////////////////////////// // MISCELLANEOUS FUNCTIONS /////////////////////////////////////////////////////////////////////////// procedure ErasePolygon(img: TImage32; const polygon: TPathD; fillRule: TFillRule); overload; procedure ErasePolygon(img: TImage32; const polygons: TPathsD; fillRule: TFillRule); overload; //Both DrawBoolMask and DrawAlphaMask require //'mask' length to equal 'img' width * height procedure DrawBoolMask(img: TImage32; const mask: TArrayOfByte; color: TColor32 = clBlack32); procedure DrawAlphaMask(img: TImage32; const mask: TArrayOfByte; color: TColor32 = clBlack32); procedure Rasterize(const paths: TPathsD; const clipRec: TRect; fillRule: TFillRule; renderer: TCustomRenderer); implementation {$IFDEF MemCheck} resourcestring sMemCheckError = 'Img32.Draw: Memory allocation error'; {$ENDIF} type //A horizontal scanline contains any number of line fragments. A fragment //can be a number of pixels wide but it can't be more than one pixel high. TFragment = record botX, topX, dy, dydx: double; end; TFragmentArray = array[0 .. (Maxint div SizeOf(TFragment)) -1] of TFragment; PFragments = ^TFragmentArray; PFragment = ^TFragment; TScanLine = record Y: integer; minX, maxX: integer; fragCnt: integer; {$IFDEF MemCheck} total: integer; {$ENDIF} fragments: PFragments; end; PScanline = ^TScanline; TArrayOfScanline = array of TScanline; //------------------------------------------------------------------------------ // ApplyClearType (see DrawPolygon_ClearType below) //------------------------------------------------------------------------------ type PArgbs = ^TArgbs; TArgbs = array [0.. (Maxint div SizeOf(TARGB)) -1] of TARGB; procedure ApplyClearType(img: TImage32; textColor: TColor32 = clBlack32; bkColor: TColor32 = clWhite32); const centerWeighting = 5; //0 <= centerWeighting <= 25 var h, w: integer; src, dst: PARGB; srcArr: PArgbs; fgColor: TARGB absolute textColor; bgColor: TARGB absolute bkColor; diff_R, diff_G, diff_B: integer; bg8_R, bg8_G, bg8_B: integer; rowBuffer: TArrayOfARGB; primeTbl, nearTbl, FarTbl: PByteArray; begin // Precondition: the background to text drawn onto 'img' must be transparent // 85 + (2 * 57) + (2 * 28) == 255 primeTbl := PByteArray(@MulTable[85 + centerWeighting *2]); nearTbl := PByteArray(@MulTable[57]); farTbl := PByteArray(@MulTable[28 - centerWeighting]); SetLength(rowBuffer, img.Width +4); for h := 0 to img.Height -1 do begin //each row of the image is copied into a temporary buffer ... //noting that while 'dst' (img.Pixels) is initially the source //it will later be destination (during image compression). dst := PARGB(@img.Pixels[h * img.Width]); src := PARGB(@rowBuffer[2]); Move(dst^, src^, img.Width * SizeOf(TColor32)); srcArr := PArgbs(rowBuffer); //using this buffer compress the image ... w := 2; while w < img.Width do begin dst.R := primeTbl[srcArr[w].A] + nearTbl[srcArr[w-1].A] + farTbl[srcArr[w-2].A] + nearTbl[srcArr[w+1].A] + farTbl[srcArr[w+2].A]; inc(w); dst.G := primeTbl[srcArr[w].A] + nearTbl[srcArr[w-1].A] + farTbl[srcArr[w-2].A] + nearTbl[srcArr[w+1].A] + farTbl[srcArr[w+2].A]; inc(w); dst.B := primeTbl[srcArr[w].A] + nearTbl[srcArr[w-1].A] + farTbl[srcArr[w-2].A] + nearTbl[srcArr[w+1].A] + farTbl[srcArr[w+2].A]; inc(w); dst.A := 255; inc(dst); end; end; //Following compression the right 2/3 of the image is redundant img.Crop(Types.Rect(0,0, img.Width div 3, img.Height)); //currently text is white and the background is black //so blend in the text and background colors ... diff_R := fgColor.R - bgColor.R; diff_G := fgColor.G - bgColor.G; diff_B := fgColor.B - bgColor.B; bg8_R := bgColor.R shl 8; bg8_G := bgColor.G shl 8; bg8_B := bgColor.B shl 8; dst := PARGB(img.PixelBase); for h := 0 to img.Width * img.Height -1 do begin if dst.R = 0 then dst.Color := bkColor else begin //blend front (text) and background colors ... dst.R := (bg8_R + diff_R * dst.R) shr 8; dst.G := (bg8_G + diff_G * dst.G) shr 8; dst.B := (bg8_B + diff_B * dst.B) shr 8; end; inc(dst); end; end; //------------------------------------------------------------------------------ // Other miscellaneous functions //------------------------------------------------------------------------------ ////__Trunc: An efficient Trunc() algorithm (ie rounds toward zero) //function __Trunc(val: double): integer; {$IFDEF INLINE} inline; {$ENDIF} //var // exp: integer; // i64: UInt64 absolute val; //begin // //https://en.wikipedia.org/wiki/Double-precision_floating-point_format // Result := 0; // if i64 = 0 then Exit; // exp := Integer(Cardinal(i64 shr 52) and $7FF) - 1023; // //nb: when exp == 1024 then val == INF or NAN. // if exp < 0 then Exit; // Result := ((i64 and $1FFFFFFFFFFFFF) shr (52-exp)) or (1 shl exp); // if val < 0 then Result := -Result; //end; //------------------------------------------------------------------------------ function ClampByte(val: double): byte; {$IFDEF INLINE} inline; {$ENDIF} begin if val < 0 then result := 0 else if val > 255 then result := 255 else result := Round(val); end; //------------------------------------------------------------------------------ function GetPixel(current: PARGB; delta: integer): PARGB; {$IFDEF INLINE} inline; {$ENDIF} begin Result := current; inc(Result, delta); end; //------------------------------------------------------------------------------ function ReverseColors(const colors: TArrayOfGradientColor): TArrayOfGradientColor; var i, highI: integer; begin highI := High(colors); SetLength(result, highI +1); for i := 0 to highI do begin result[i].color := colors[highI -i].color; result[i].offset := 1 - colors[highI -i].offset; end; end; //------------------------------------------------------------------------------ procedure SwapColors(var color1, color2: TColor32); var c: TColor32; begin c := color1; color1 := color2; color2 := c; end; //------------------------------------------------------------------------------ procedure SwapPoints(var point1, point2: TPoint); overload; var pt: TPoint; begin pt := point1; point1 := point2; point2 := pt; end; //------------------------------------------------------------------------------ procedure SwapPoints(var point1, point2: TPointD); overload; var pt: TPointD; begin pt := point1; point1 := point2; point2 := pt; end; //------------------------------------------------------------------------------ function ClampQ(q, endQ: integer): integer; begin if q < 0 then result := 0 else if q >= endQ then result := endQ -1 else result := q; end; //------------------------------------------------------------------------------ function ClampD(d: double; colorCnt: integer): integer; begin dec(colorCnt); if d < 0 then result := 0 else if d >= 1 then result := colorCnt else result := Round(d * colorCnt); end; //------------------------------------------------------------------------------ function MirrorQ(q, endQ: integer): integer; begin result := q mod endQ; if (result < 0) then result := -result; if Odd(q div endQ) then result := (endQ -1) - result; end; //------------------------------------------------------------------------------ function MirrorD(d: double; colorCnt: integer): integer; begin dec(colorCnt); if Odd(Round(d)) then result := Round((1 - frac(d)) * colorCnt) else result := Round(frac(d) * colorCnt); end; //------------------------------------------------------------------------------ function RepeatQ(q, endQ: integer): integer; begin if (q < 0) or (q >= endQ) then begin endQ := Abs(endQ); result := q mod endQ; if result < 0 then inc(result, endQ); end else result := q; end; //------------------------------------------------------------------------------ function SoftRptQ(q, endQ: integer): integer; begin if (q < 0) then result := endQ + (q mod endQ) else result := (q mod endQ); if result = 0 then result := endQ div 2; end; //------------------------------------------------------------------------------ function RepeatD(d: double; colorCnt: integer): integer; begin dec(colorCnt); if (d < 0) then result := Round((1 + frac(d)) * colorCnt) else result := Round(frac(d) * colorCnt); end; //------------------------------------------------------------------------------ function BlendColorUsingMask(bgColor, fgColor: TColor32; mask: Byte): TColor32; var bg: TARGB absolute bgColor; fg: TARGB absolute fgColor; res: TARGB absolute Result; R, invR: PByteArray; begin if fg.A = 0 then begin Result := bgColor; res.A := MulBytes(res.A, not mask); end else if bg.A = 0 then begin Result := fgColor; res.A := MulBytes(res.A, mask); end else if (mask = 0) then Result := bgColor else if (mask = 255) then Result := fgColor else begin R := PByteArray(@MulTable[mask]); InvR := PByteArray(@MulTable[not mask]); res.A := R[fg.A] + InvR[bg.A]; res.R := R[fg.R] + InvR[bg.R]; res.G := R[fg.G] + InvR[bg.G]; res.B := R[fg.B] + InvR[bg.B]; end; end; //------------------------------------------------------------------------------ //MakeColorGradient: using the supplied array of TGradientColor, //create an array of TColor32 of the specified length function MakeColorGradient(const gradColors: TArrayOfGradientColor; len: integer): TArrayOfColor32; var i,j, lenC: integer; dist, offset1, offset2, step, pos: double; color1, color2: TColor32; begin lenC := length(gradColors); if (len = 0) or (lenC < 2) then Exit; SetLength(result, len); color2 := gradColors[0].color; result[0] := color2; if len = 1 then Exit; step := 1/(len-1); pos := step; offset2 := 0; i := 1; j := 1; repeat offset1 := offset2; offset2 := gradColors[i].offset; dist := offset2 - offset1; color1 := color2; color2 := gradColors[i].color; while (pos <= dist) and (j < len) do begin result[j] := BlendColorUsingMask(color1, color2, Round(pos/dist * 255)); inc(j); pos := pos + step; end; pos := pos - dist; inc(i); until i = lenC; if j < len then result[j] := result[j-1]; end; //------------------------------------------------------------------------------ // Rasterize() support functions //------------------------------------------------------------------------------ procedure AllocateScanlines(const polygons: TPathsD; var scanlines: TArrayOfScanline; clipBottom, clipRight: integer); var i,j, highI, highJ: integer; y1, y2: integer; psl: PScanline; begin //first count how often each edge intersects with each horizontal scanline for i := 0 to high(polygons) do begin highJ := high(polygons[i]); if highJ < 2 then continue; y1 := Round(polygons[i][highJ].Y); for j := 0 to highJ do begin y2 := Round(polygons[i][j].Y); if y1 < y2 then begin //descending (but ignore edges outside the clipping range) if (y2 >= 0) and (y1 <= clipBottom) then begin if (y1 > 0) and (y1 <= clipBottom) then dec(scanlines[y1 -1].fragCnt); if y2 >= clipBottom then inc(scanlines[clipBottom].fragCnt) else inc(scanlines[y2].fragCnt); end; end else begin //ascending (but ignore edges outside the clipping range) if (y1 >= 0) and (y2 <= clipBottom) then begin if (y2 > 0) then dec(scanlines[y2 -1].fragCnt); if y1 >= clipBottom then inc(scanlines[clipBottom].fragCnt) else inc(scanlines[y1].fragCnt); end; end; y1 := y2; end; end; //convert 'count' accumulators into real counts and allocate storage j := 0; highI := high(scanlines); psl := @scanlines[highI]; //'fragments' is a pointer and not a dynamic array because //dynamic arrays are zero initialized (hence slower than GetMem). for i := highI downto 0 do begin inc(j, psl.fragCnt); //nb: psl.fragCnt may be < 0 here! if j > 0 then GetMem(psl.fragments, j * SizeOf(TFragment)); {$IFDEF MemCheck} psl.total := j; {$ENDIF} psl.fragCnt := 0; //reset for later psl.minX := clipRight; psl.maxX := 0; psl.Y := i; dec(psl); end; end; //------------------------------------------------------------------------------ procedure SplitEdgeIntoFragments(const pt1, pt2: TPointD; const scanlines: TArrayOfScanline; const clipRec: TRect); var x,y, dx,dy, absDx, dydx, dxdy: double; i, scanlineY, maxY, maxX: integer; psl: PScanLine; pFrag: PFragment; bot, top: TPointD; begin dy := pt1.Y - pt2.Y; dx := pt2.X - pt1.X; RectWidthHeight(clipRec, maxX, maxY); absDx := abs(dx); if dy > 0 then begin //ASCENDING EDGE (+VE WINDING DIR) if dy < 0.0001 then Exit; //ignore near horizontals bot := pt1; top := pt2; //exclude edges that are completely outside the top or bottom clip region if (top.Y >= maxY) or (bot.Y <= 0) then Exit; end else begin //DESCENDING EDGE (-VE WINDING DIR) if dy > -0.0001 then Exit; //ignore near horizontals bot := pt2; top := pt1; //exclude edges that are completely outside the top or bottom clip region if (top.Y >= maxY) or (bot.Y <= 0) then Exit; end; if absDx < 0.000001 then begin //VERTICAL EDGE top.X := bot.X; //this circumvents v. rare rounding issues. //exclude vertical edges that are outside the right clip region //but still update maxX for each scanline the edge passes if bot.X > maxX then begin for i := Min(maxY, Round(bot.Y)) downto Max(0, Round(top.Y)) do scanlines[i].maxX := maxX; Exit; end; dxdy := 0; if dy > 0 then dydx := 1 else dydx := -1; end else begin dxdy := dx/dy; dydx := dy/absDx; end; //TRIM EDGES THAT CROSS CLIPPING BOUNDARIES (EXCEPT THE LEFT BOUNDARY) if bot.X >= maxX then begin if top.X >= maxX then begin for i := Min(maxY, Round(bot.Y)) downto Max(0, Round(top.Y)) do scanlines[i].maxX := maxX; Exit; end; //here the edge must be oriented bottom-right to top-left y := bot.Y - (bot.X - maxX) * Abs(dydx); for i := Min(maxY, Round(bot.Y)) downto Max(0, Round(y)) do scanlines[i].maxX := maxX; bot.Y := y; if bot.Y <= 0 then Exit; bot.X := maxX; end else if top.X > maxX then begin //here the edge must be oriented bottom-left to top-right y := top.Y + (top.X - maxX) * Abs(dydx); for i := Min(maxY, Round(y)) downto Max(0, Round(top.Y)) do scanlines[i].maxX := maxX; top.Y := y; if top.Y >= maxY then Exit; top.X := maxX; end; if bot.Y > maxY then begin bot.X := bot.X + dxdy * (bot.Y - maxY); if (bot.X > maxX) then Exit; //nb: no clipping on the left bot.Y := maxY; end; if top.Y < 0 then begin top.X := top.X + (dxdy * top.Y); if (top.X > maxX) then Exit; //nb: no clipping on the left top.Y := 0; end; //SPLIT THE EDGE INTO MULTIPLE SCANLINE FRAGMENTS scanlineY := Round(bot.Y); if bot.Y = scanlineY then dec(scanlineY); //at the lower-most extent of the edge 'split' the first fragment if scanlineY < 0 then Exit; psl := @scanlines[scanlineY]; if not assigned(psl.fragments) then Exit; //a very rare event {$IFDEF MemCheck} if psl.fragCnt = psl.total then raise Exception.Create(sMemCheckError); {$ENDIF} pFrag := @psl.fragments[psl.fragCnt]; inc(psl.fragCnt); pFrag.botX := bot.X; if scanlineY <= top.Y then begin //the whole edge is within 1 scanline pFrag.topX := top.X; pFrag.dy := bot.Y - top.Y; pFrag.dydx := dydx; Exit; end; x := bot.X + (bot.Y - scanlineY) * dxdy; pFrag.topX := x; pFrag.dy := bot.Y - scanlineY; pFrag.dydx := dydx; //'split' subsequent fragments until the top fragment dec(psl); while psl.Y > top.Y do begin {$IFDEF MemCheck} if psl.fragCnt = psl.total then raise Exception.Create(sMemCheckError); {$ENDIF} pFrag := @psl.fragments[psl.fragCnt]; inc(psl.fragCnt); pFrag.botX := x; x := x + dxdy; pFrag.topX := x; pFrag.dy := 1; pFrag.dydx := dydx; dec(psl); end; //and finally the top fragment {$IFDEF MemCheck} if psl.fragCnt = psl.total then raise Exception.Create(sMemCheckError); {$ENDIF} pFrag := @psl.fragments[psl.fragCnt]; inc(psl.fragCnt); pFrag.botX := x; pFrag.topX := top.X; pFrag.dy := psl.Y + 1 - top.Y; pFrag.dydx := dydx; end; //------------------------------------------------------------------------------ procedure InitializeScanlines(var polygons: TPathsD; const scanlines: TArrayOfScanline; const clipRec: TRect); var i,j, highJ: integer; pt1, pt2: PPointD; begin for i := 0 to high(polygons) do begin highJ := high(polygons[i]); if highJ < 2 then continue; pt1 := @polygons[i][highJ]; pt2 := @polygons[i][0]; for j := 0 to highJ do begin SplitEdgeIntoFragments(pt1^, pt2^, scanlines, clipRec); pt1 := pt2; inc(pt2); end; end; end; //------------------------------------------------------------------------------ procedure ProcessScanlineFragments(var scanline: TScanLine; var buffer: TArrayOfDouble); var i,j, leftXi,rightXi: integer; fracX, yy, q, windDir: double; pd: PDouble; frag: PFragment; begin frag := @scanline.fragments[0]; for i := 1 to scanline.fragCnt do begin if frag.botX > frag.topX then begin //just swapping botX and topX simplifies code q := frag.botX; frag.botX := frag.topX; frag.topX := q; end; leftXi := Max(0, Round(frag.botX)); rightXi := Max(0, Round(frag.topX)); if (leftXi = rightXi) then begin if frag.dydx < 0 then windDir := -1.0 else windDir := 1.0; //the fragment is only one pixel wide if leftXi < scanline.minX then scanline.minX := leftXi; if rightXi > scanline.maxX then scanline.maxX := rightXi; pd := @buffer[leftXi]; if (frag.botX <= 0) then begin pd^ := pd^ + frag.dy * windDir; end else begin q := (frag.botX + frag.topX) * 0.5 - leftXi; pd^ := pd^ + (1-q) * frag.dy * windDir; inc(pd); pd^ := pd^ + q * frag.dy * windDir; end; end else begin if leftXi < scanline.minX then scanline.minX := leftXi; if rightXi > scanline.maxX then scanline.maxX := rightXi; pd := @buffer[leftXi]; //left pixel fracX := leftXi + 1 - frag.botX; yy := frag.dydx * fracX; q := fracX * yy * 0.5; pd^ := pd^ + q; q := yy - q; inc(pd); //middle pixels for j := leftXi +1 to rightXi -1 do begin pd^ := pd^ + q + frag.dydx * 0.5; q := frag.dydx * 0.5; inc(pd); end; //right pixel fracX := frag.topX - rightXi; yy := fracX * frag.dydx; pd^ := pd^ + q + (1 - fracX * 0.5) * yy; inc(pd); //overflow pd^ := pd^ + fracX * 0.5 * yy; end; inc(frag); end; end; //------------------------------------------------------------------------------ {$IFNDEF TROUNDINGMODE} type TRoundingMode = {$IFNDEF FPC}Math.{$ENDIF}TFPURoundingMode; {$ENDIF} procedure Rasterize(const paths: TPathsD; const clipRec: TRect; fillRule: TFillRule; renderer: TCustomRenderer); var i,j, xli,xri, maxW, maxH, aa: integer; clipRec2: TRect; paths2: TPathsD; accum: double; windingAccum: TArrayOfDouble; byteBuffer: TArrayOfByte; scanlines: TArrayOfScanline; scanline: PScanline; savedRoundMode: TRoundingMode; begin //See also https://nothings.org/gamedev/rasterize/ if not assigned(renderer) then Exit; Types.IntersectRect(clipRec2, clipRec, GetBounds(paths)); if IsEmptyRect(clipRec2) then Exit; paths2 := OffsetPath(paths, -clipRec2.Left, -clipRec2.Top); //Delphi's Round() function is *much* faster than its Trunc function, and //it's even a little faster than the __Trunc function above (except when //the FastMM4 memory manager is enabled.) savedRoundMode := SetRoundMode(rmDown); RectWidthHeight(clipRec2, maxW, maxH); SetLength(scanlines, maxH +1); SetLength(windingAccum, maxW +2); AllocateScanlines(paths2, scanlines, maxH, maxW-1); InitializeScanlines(paths2, scanlines, clipRec2); SetLength(byteBuffer, maxW); if byteBuffer = nil then Exit; scanline := @scanlines[0]; for i := 0 to high(scanlines) do begin if scanline.fragCnt = 0 then begin FreeMem(scanline.fragments); inc(scanline); Continue; end; //process each scanline to fill the winding count accumulation buffer ProcessScanlineFragments(scanline^, windingAccum); //it's faster to process only the modified sub-array of windingAccum xli := scanline.minX; xri := Min(maxW -1, scanline.maxX +1); FillChar(byteBuffer[xli], xri - xli +1, 0); //a 25% weighting has been added to the alpha channel to minimize any //background bleed-through where polygons join with a common edge. accum := 0; //winding count accumulator for j := xli to xri do begin accum := accum + windingAccum[j]; case fillRule of frEvenOdd: begin aa := Round(Abs(accum) * 1275) mod 2550; // *5 if aa > 1275 then byteBuffer[j] := Min(255, (2550 - aa) shr 2) else // /4 byteBuffer[j] := Min(255, aa shr 2); // /4 end; frNonZero: begin byteBuffer[j] := Min(255, Round(Abs(accum) * 318)); end; {$IFDEF REVERSE_ORIENTATION} frPositive: {$ELSE} frNegative: {$ENDIF} begin if accum > 0.002 then byteBuffer[j] := Min(255, Round(accum * 318)); end; {$IFDEF REVERSE_ORIENTATION} frNegative: {$ELSE} frPositive: {$ENDIF} begin if accum < -0.002 then byteBuffer[j] := Min(255, Round(-accum * 318)); end; end; end; renderer.RenderProc(clipRec2.Left + xli, clipRec2.Left + xri, clipRec2.Top + i, @byteBuffer[xli]); //cleanup and deallocate memory FillChar(windingAccum[xli], (xri - xli +1) * sizeOf(Double), 0); FreeMem(scanline.fragments); inc(scanline); end; SetRoundMode(savedRoundMode); end; //------------------------------------------------------------------------------ // TAbstractRenderer //------------------------------------------------------------------------------ function TCustomRenderer.Initialize(imgBase: Pointer; imgWidth, imgHeight, pixelSize: integer): Boolean; begin fImgBase := imgBase; fImgWidth := ImgWidth; fImgHeight := ImgHeight; fPixelSize := pixelSize; fCurrLinePtr := fImgBase; fCurrY := 0; result := true; end; //------------------------------------------------------------------------------ procedure TCustomRenderer.NotifyChange; begin if assigned(fChangeProc) then fChangeProc; end; //------------------------------------------------------------------------------ type THackedImage32 = class(TImage32); //exposes protected Changed method. function TCustomRenderer.Initialize(targetImage: TImage32): Boolean; begin fChangeProc := THackedImage32(targetImage).Changed; with targetImage do result := Initialize(PixelBase, Width, Height, SizeOf(TColor32)); end; //------------------------------------------------------------------------------ function TCustomRenderer.GetDstPixel(x, y: integer): Pointer; begin if (y <> fCurrY) then begin fCurrY := y; fCurrLinePtr := fImgBase; inc(PByte(fCurrLinePtr), fCurrY * fImgWidth * fPixelSize); end; Result := fCurrLinePtr; inc(PByte(Result), x * fPixelSize); end; //------------------------------------------------------------------------------ // TColorRenderer //------------------------------------------------------------------------------ constructor TColorRenderer.Create(color: TColor32 = clNone32); begin if color <> clNone32 then SetColor(color); end; //------------------------------------------------------------------------------ function TColorRenderer.Initialize(targetImage: TImage32): Boolean; begin //there's no point rendering if the color is fully transparent result := (fAlpha > 0) and inherited Initialize(targetImage); end; //------------------------------------------------------------------------------ procedure TColorRenderer.SetColor(value: TColor32); begin fColor := value and $FFFFFF; fAlpha := GetAlpha(value); end; //------------------------------------------------------------------------------ procedure TColorRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; dst: PColor32; begin dst := GetDstPixel(x1,y); for i := x1 to x2 do begin //BlendToAlpha is marginally slower than BlendToOpaque but it's used //here because it's universally applicable. //Ord() is used here because very old compilers define PByte as a PChar if Ord(alpha^) > 1 then dst^ := BlendToAlpha(dst^, ((Ord(alpha^) * fAlpha) shr 8) shl 24 or fColor); inc(dst); inc(alpha); end; end; //------------------------------------------------------------------------------ // TAliasedColorRenderer //------------------------------------------------------------------------------ constructor TAliasedColorRenderer.Create(color: TColor32 = clNone32); begin fColor := color; end; //------------------------------------------------------------------------------ function TAliasedColorRenderer.Initialize(targetImage: TImage32): Boolean; begin //there's no point rendering if the color is fully transparent result := (GetAlpha(fColor) > 0) and inherited Initialize(targetImage); end; //------------------------------------------------------------------------------ procedure TAliasedColorRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; dst: PColor32; begin dst := GetDstPixel(x1,y); for i := x1 to x2 do begin if Ord(alpha^) > 127 then dst^ := fColor; //ie no blending inc(dst); inc(alpha); end; end; //------------------------------------------------------------------------------ // TBrushImageRenderer //------------------------------------------------------------------------------ constructor TImageRenderer.Create(tileFillStyle: TTileFillStyle; brushImage: TImage32); begin fImage := TImage32.Create(brushImage); SetTileFillStyle(tileFillStyle); end; //------------------------------------------------------------------------------ destructor TImageRenderer.Destroy; begin fImage.Free; inherited; end; //------------------------------------------------------------------------------ procedure TImageRenderer.SetTileFillStyle(value: TTileFillStyle); begin case value of tfsRepeat: fBoundsProc := RepeatQ; tfsMirrorHorz: fBoundsProc := MirrorQ; tfsMirrorVert: fBoundsProc := RepeatQ; tfsRotate180 : fBoundsProc := MirrorQ; end; fMirrorY := value in [tfsMirrorVert, tfsRotate180]; end; //------------------------------------------------------------------------------ function TImageRenderer.Initialize(targetImage: TImage32): Boolean; begin result := inherited Initialize(targetImage) and (not fImage.IsEmpty); if not result then Exit; fLastYY := 0; fBrushPixel := PARGB(fImage.PixelBase); end; //------------------------------------------------------------------------------ procedure TImageRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; pDst: PColor32; pBrush: PARGB; begin pDst := GetDstPixel(x1,y); dec(x1, fOffset.X); dec(x2, fOffset.X); dec(y, fOffset.Y); pBrush := GetFirstBrushPixel(x1, y); for i := x1 to x2 do begin pDst^ := BlendToAlpha(pDst^, MulBytes(pBrush.A, Ord(alpha^)) shl 24 or (pBrush.Color and $FFFFFF)); inc(pDst); inc(alpha); pBrush := GetPixel(fBrushPixel, fBoundsProc(i, fImage.Width)); end; end; //------------------------------------------------------------------------------ function TImageRenderer.GetFirstBrushPixel(x, y: integer): PARGB; begin if fMirrorY then y := MirrorQ(y, fImage.Height) else y := RepeatQ(y, fImage.Height); if y <> fLastYY then begin fBrushPixel := PARGB(fImage.PixelRow[y]); fLastYY := y; end; x := fBoundsProc(x, fImage.Width); result := GetPixel(fBrushPixel, x); end; //------------------------------------------------------------------------------ // TGradientRenderer //------------------------------------------------------------------------------ constructor TCustomGradientRenderer.Create; begin fBoundsProc := ClampQ; //default proc end; //------------------------------------------------------------------------------ procedure TCustomGradientRenderer.Clear; begin fGradientColors := nil; fColors := nil; end; //------------------------------------------------------------------------------ procedure TCustomGradientRenderer.SetGradientFillStyle(value: TGradientFillStyle); begin case value of gfsClamp: fBoundsProc := ClampQ; gfsMirror: fBoundsProc := MirrorQ; else fBoundsProc := RepeatQ; end; end; //------------------------------------------------------------------------------ procedure TCustomGradientRenderer.SetParameters(startColor, endColor: TColor32; gradFillStyle: TGradientFillStyle = gfsClamp); begin SetGradientFillStyle(gradFillStyle); //reset gradient colors if perviously set SetLength(fGradientColors, 2); fGradientColors[0].offset := 0; fGradientColors[0].color := startColor; fGradientColors[1].offset := 1; fGradientColors[1].color := endColor; end; //------------------------------------------------------------------------------ procedure TCustomGradientRenderer.InsertColorStop(offsetFrac: double; color: TColor32); var i, len: integer; gradColor: TGradientColor; begin len := Length(fGradientColors); //colorstops can only be inserted after calling SetParameters if len = 0 then Exit; if offsetFrac < 0 then offsetFrac := 0 else if offsetFrac > 1 then offsetFrac := 1; if offsetFrac = 0 then begin fGradientColors[0].color := color; Exit; end else if offsetFrac = 1 then begin fGradientColors[len -1].color := color; Exit; end; gradColor.offset := offsetFrac; gradColor.color := color; i := 1; while (i < len-1) and (fGradientColors[i].offset <= offsetFrac) do inc(i); SetLength(fGradientColors, len +1); Move(fGradientColors[i], fGradientColors[i+1], (len -i) * SizeOf(TGradientColor)); fGradientColors[i] := gradColor; end; //------------------------------------------------------------------------------ // TLinearGradientRenderer //------------------------------------------------------------------------------ procedure TLinearGradientRenderer.SetParameters(const startPt, endPt: TPointD; startColor, endColor: TColor32; gradFillStyle: TGradientFillStyle); begin inherited SetParameters(startColor, endColor, gradFillStyle); fStartPt := startPt; fEndPt := endPt; end; //------------------------------------------------------------------------------ function TLinearGradientRenderer.Initialize(targetImage: TImage32): Boolean; var i: integer; dx,dy, dxdy,dydx: double; begin result := inherited Initialize(targetImage) and assigned(fGradientColors); if not result then Exit; if abs(fEndPt.Y - fStartPt.Y) > abs(fEndPt.X - fStartPt.X) then begin //gradient > 45 degrees if (fEndPt.Y < fStartPt.Y) then begin fGradientColors := ReverseColors(fGradientColors); SwapPoints(fStartPt, fEndPt); end; fIsVert := true; dx := (fEndPt.X - fStartPt.X); dy := (fEndPt.Y - fStartPt.Y); dxdy := dx/dy; fColorsCnt := Ceil(dy + dxdy * (fEndPt.X - fStartPt.X)); fColors := MakeColorGradient(fGradientColors, fColorsCnt); //get a list of perpendicular offsets for each SetLength(fPerpendicOffsets, ImgWidth); //from an imaginary line that's through fStartPt and perpendicular to //the gradient line, get a list of Y offsets for each X in image width for i := 0 to ImgWidth -1 do fPerpendicOffsets[i] := Round(dxdy * (fStartPt.X - i) + fStartPt.Y); end else //gradient <= 45 degrees begin if (fEndPt.X = fStartPt.X) then begin Result := false; Exit; end; if (fEndPt.X < fStartPt.X) then begin fGradientColors := ReverseColors(fGradientColors); SwapPoints(fStartPt, fEndPt); end; fIsVert := false; dx := (fEndPt.X - fStartPt.X); dy := (fEndPt.Y - fStartPt.Y); dydx := dy/dx; //perpendicular slope fColorsCnt := Ceil(dx + dydx * (fEndPt.Y - fStartPt.Y)); fColors := MakeColorGradient(fGradientColors, fColorsCnt); SetLength(fPerpendicOffsets, ImgHeight); //from an imaginary line that's through fStartPt and perpendicular to //the gradient line, get a list of X offsets for each Y in image height for i := 0 to ImgHeight -1 do fPerpendicOffsets[i] := Round(dydx * (fStartPt.Y - i) + fStartPt.X); end; end; //------------------------------------------------------------------------------ procedure TLinearGradientRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i, off: integer; pDst: PColor32; color: TARGB; begin pDst := GetDstPixel(x1,y); for i := x1 to x2 do begin if fIsVert then begin //when fIsVert = true, fPerpendicOffsets is an array of Y for each X off := fPerpendicOffsets[i]; color.Color := fColors[fBoundsProc(y - off, fColorsCnt)]; end else begin //when fIsVert = false, fPerpendicOffsets is an array of X for each Y off := fPerpendicOffsets[y]; color.Color := fColors[fBoundsProc(i - off, fColorsCnt)]; end; pDst^ := BlendToAlpha(pDst^, MulBytes(color.A, Ord(alpha^)) shl 24 or (color.Color and $FFFFFF)); inc(pDst); inc(alpha); end; end; //------------------------------------------------------------------------------ // TRadialGradientRenderer //------------------------------------------------------------------------------ function TRadialGradientRenderer.Initialize(targetImage: TImage32): Boolean; begin result := inherited Initialize(targetImage) and (fColorsCnt > 1); if result then fColors := MakeColorGradient(fGradientColors, fColorsCnt); end; //------------------------------------------------------------------------------ procedure TRadialGradientRenderer.SetParameters(const focalRect: TRect; innerColor, outerColor: TColor32; gradientFillStyle: TGradientFillStyle); var w,h: integer; radX,radY: double; begin inherited SetParameters(innerColor, outerColor, gradientFillStyle); fColorsCnt := 0; if IsEmptyRect(focalRect) then Exit; fCenterPt.X := (focalRect.Left + focalRect.Right) * 0.5; fCenterPt.Y := (focalRect.Top + focalRect.Bottom) * 0.5; RectWidthHeight(focalRect, w, h); radX := w * 0.5; radY := h * 0.5; if radX >= radY then begin fScaleX := 1; fScaleY := radX/radY; fColorsCnt := Ceil(radX) +1; end else begin fScaleX := radY/radX; fScaleY := 1; fColorsCnt := Ceil(radY) +1; end; end; //------------------------------------------------------------------------------ procedure TRadialGradientRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; dist: double; color: TARGB; pDst: PColor32; begin pDst := GetDstPixel(x1,y); for i := x1 to x2 do begin dist := Hypot((y - fCenterPt.Y) *fScaleY, (i - fCenterPt.X) *fScaleX); color.Color := fColors[fBoundsProc(Round(dist), fColorsCnt)]; pDst^ := BlendToAlpha(pDst^, MulBytes(color.A, Ord(alpha^)) shl 24 or (color.Color and $FFFFFF)); inc(pDst); inc(alpha); end; end; //------------------------------------------------------------------------------ // TSvgRadialGradientRenderer //------------------------------------------------------------------------------ function TSvgRadialGradientRenderer.Initialize(targetImage: TImage32): Boolean; begin result := inherited Initialize(targetImage) and (fColorsCnt > 1); if result then fColors := MakeColorGradient(fGradientColors, fColorsCnt); end; //------------------------------------------------------------------------------ procedure TSvgRadialGradientRenderer.SetParameters(const ellipseRect: TRect; const focus: TPoint; innerColor, outerColor: TColor32; gradientFillStyle: TGradientFillStyle = gfsClamp); var w, h : integer; begin inherited SetParameters(innerColor, outerColor); case gradientFillStyle of gfsMirror: fBoundsProcD := MirrorD; gfsRepeat: fBoundsProcD := RepeatD; else fBoundsProcD := ClampD; end; fColorsCnt := 0; if IsEmptyRect(ellipseRect) then Exit; fCenterPt := RectD(ellipseRect).MidPoint; RectWidthHeight(ellipseRect, w, h); fA := w * 0.5; fB := h * 0.5; fFocusPt.X := focus.X - fCenterPt.X; fFocusPt.Y := focus.Y - fCenterPt.Y; fColorsCnt := Ceil(Hypot(fA*2, fB*2)) +1; fAA := fA * fA; fBB := fB * fB; end; //------------------------------------------------------------------------------ procedure TSvgRadialGradientRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; q,m,c, qa,qb,qc,qs: double; dist, dist2: double; color: TARGB; pDst: PColor32; pt, ellipsePt: TPointD; begin //get the left-most pixel to render pDst := GetDstPixel(x1,y); pt.X := x1 - fCenterPt.X; pt.Y := y - fCenterPt.Y; for i := x1 to x2 do begin //equation of ellipse = (x*x)/aa + (y*y)/bb = 1 //equation of line = y = mx + c; if (pt.X = fFocusPt.X) then //vertical line begin //let x = pt.X, then y*y = b*b(1 - Sqr(pt.X)/aa) q := Sqrt(fBB*(1 - Sqr(pt.X)/fAA)); ellipsePt.X := pt.X; if pt.Y >= fFocusPt.Y then ellipsePt.Y := q else ellipsePt.Y := -q; dist := abs(pt.Y - fFocusPt.Y); dist2 := abs(ellipsePt.Y - fFocusPt.Y); if dist2 = 0 then q := 1 else q := dist/ dist2; end else begin //using simultaneous equations and substitution //given y = mx + c m := (pt.Y - fFocusPt.Y)/(pt.X - fFocusPt.X); c := pt.Y - m * pt.X; //given (x*x)/aa + (y*y)/bb = 1 //(x*x)/aa*bb + (y*y) = bb //bb/aa *(x*x) + Sqr(m*x +c) = bb //bb/aa *(x*x) + (m*m)*(x*x) + 2*m*x*c +c*c = b*b //(bb/aa +(m*m)) *(x*x) + 2*m*c*(x) + (c*c) - bb = 0 //solving quadratic equation qa := (fBB/fAA +(m*m)); qb := 2*m*c; qc := (c*c) - fBB; qs := (qb*qb) - 4*qa*qc; if qs >= 0 then begin qs := Sqrt(qs); if pt.X <= fFocusPt.X then ellipsePt.X := (-qb -qs)/(2 * qa) else ellipsePt.X := (-qb +qs)/(2 * qa); ellipsePt.Y := m * ellipsePt.X + c; dist := Hypot(pt.X - fFocusPt.X, pt.Y - fFocusPt.Y); dist2 := Hypot(ellipsePt.X - fFocusPt.X, ellipsePt.Y - fFocusPt.Y); if dist2 = 0 then q := 1 else q := dist/ dist2; end else q := 1; //shouldn't happen :) end; color.Color := fColors[fBoundsProcD(Abs(q), fColorsCnt)]; pDst^ := BlendToAlpha(pDst^, MulBytes(color.A, Ord(alpha^)) shl 24 or (color.Color and $FFFFFF)); inc(pDst); pt.X := pt.X + 1; inc(alpha); end; end; //------------------------------------------------------------------------------ // TEraseRenderer //------------------------------------------------------------------------------ procedure TEraseRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; dst: PARGB; begin dst := PARGB(GetDstPixel(x1,y)); for i := x1 to x2 do begin {$IFDEF PBYTE} dst.A := MulBytes(dst.A, not alpha^); {$ELSE} dst.A := MulBytes(dst.A, not Ord(alpha^)); {$ENDIF} inc(dst); inc(alpha); end; end; //------------------------------------------------------------------------------ // TInverseRenderer //------------------------------------------------------------------------------ procedure TInverseRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var i: integer; dst: PARGB; c: TARGB; begin dst := PARGB(GetDstPixel(x1,y)); for i := x1 to x2 do begin c.Color := not dst.Color; c.A := MulBytes(dst.A, Ord(alpha^)); dst.Color := BlendToAlpha(dst.Color, c.Color); inc(dst); inc(alpha); end; end; //------------------------------------------------------------------------------ procedure TBarycentricRenderer.SetParameters(const a, b, c: TPointD; c1, c2, c3: TColor32); begin self.a := a; self.c1.Color := c1; self.c2.Color := c2; self.c3.Color := c3; v0.X := b.X - a.X; v0.Y := b.Y - a.Y; v1.X := c.X - a.X; v1.Y := c.Y - a.Y; d00 := (v0.X * v0.X + v0.Y * v0.Y); d01 := (v0.X * v1.X + v0.Y * v1.Y); d11 := (v1.X * v1.X + v1.Y * v1.Y); invDenom := 1/(d00 * d11 - d01 * d01); end; //------------------------------------------------------------------------------ function TBarycentricRenderer.GetColor(const pt: TPointD): TColor32; var v2: TPointD; d20, d21, v, w, u: Double; res: TARGB absolute Result; begin Result := 0; v2.X := pt.X - a.X; v2.Y := pt.Y - a.Y; d20 := (v2.X * v0.X + v2.Y * v0.Y); d21 := (v2.X * v1.X + v2.Y * v1.Y); v := (d11 * d20 - d01 * d21) * invDenom; w := (d00 * d21 - d01 * d20) * invDenom; u := 1.0 - v - w; Res.A := ClampByte(c1.A * u + c2.A * v + c3.A * w); Res.R := ClampByte(c1.R * u + c2.R * v + c3.R * w); Res.G := ClampByte(c1.G * u + c2.G * v + c3.G * w); Res.B := ClampByte(c1.B * u + c2.B * v + c3.B * w); end; //------------------------------------------------------------------------------ procedure TBarycentricRenderer.RenderProc(x1, x2, y: integer; alpha: PByte); var x: integer; p: PARGB; c: TARGB; begin p := PARGB(fImgBase); inc(p, y * ImgWidth + x1); for x := x1 to x2 do begin c.Color := GetColor(PointD(x, y)); c.A := c.A * Ord(alpha^) shr 8; p.Color := BlendToAlpha(p.Color, c.Color); inc(p); inc(alpha); end; end; //------------------------------------------------------------------------------ // Draw functions //------------------------------------------------------------------------------ procedure DrawPoint(img: TImage32; const pt: TPointD; radius: double; color: TColor32); var path: TPathD; begin if radius <= 1 then path := Rectangle(pt.X-radius, pt.Y-radius, pt.X+radius, pt.Y+radius) else path := Ellipse(RectD(pt.X-radius, pt.Y-radius, pt.X+radius, pt.Y+radius)); DrawPolygon(img, path, frEvenOdd, color); end; //------------------------------------------------------------------------------ procedure DrawPoint(img: TImage32; const pt: TPointD; radius: double; renderer: TCustomRenderer); var path: TPathD; begin path := Ellipse(RectD(pt.X -radius, pt.Y -radius, pt.X +radius, pt.Y +radius)); DrawPolygon(img, path, frEvenOdd, renderer); end; //------------------------------------------------------------------------------ procedure DrawPoint(img: TImage32; const points: TPathD; radius: double; color: TColor32); var i: integer; begin for i := 0 to high(points) do DrawPoint(img, points[i], radius, color); end; //------------------------------------------------------------------------------ procedure DrawPoint(img: TImage32; const paths: TPathsD; radius: double; color: TColor32); var i: integer; begin for i := 0 to high(paths) do DrawPoint(img, paths[i], radius, color); end; //------------------------------------------------------------------------------ procedure DrawLine(img: TImage32; const pt1, pt2: TPointD; lineWidth: double; color: TColor32); var lines: TPathsD; begin setLength(lines, 1); setLength(lines[0], 2); lines[0][0] := pt1; lines[0][1] := pt2; DrawLine(img, lines, lineWidth, color, esRound); end; //------------------------------------------------------------------------------ procedure DrawLine(img: TImage32; const line: TPathD; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle; miterLimit: double); var lines: TPathsD; begin setLength(lines, 1); lines[0] := line; DrawLine(img, lines, lineWidth, color, endStyle, joinStyle, miterLimit); end; //------------------------------------------------------------------------------ procedure DrawLine(img: TImage32; const line: TPathD; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle; miterLimit: double); var lines: TPathsD; begin setLength(lines, 1); lines[0] := line; DrawLine(img, lines, lineWidth, renderer, endStyle, joinStyle, miterLimit); end; //------------------------------------------------------------------------------ procedure DrawInvertedLine(img: TImage32; const line: TPathD; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); var lines: TPathsD; begin setLength(lines, 1); lines[0] := line; DrawInvertedLine(img, lines, lineWidth, endStyle, joinStyle); end; //------------------------------------------------------------------------------ procedure DrawLine(img: TImage32; const lines: TPathsD; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle; miterLimit: double); var lines2: TPathsD; cr: TCustomRenderer; begin if not assigned(lines) then exit; if (lineWidth < MinStrokeWidth) then lineWidth := MinStrokeWidth; lines2 := Outline(lines, lineWidth, joinStyle, endStyle, miterLimit); if img.AntiAliased then cr := TColorRenderer.Create(color) else cr := TAliasedColorRenderer.Create(color); try if cr.Initialize(img) then begin Rasterize(lines2, img.bounds, frNonZero, cr); cr.NotifyChange; end; finally cr.free; end; end; //------------------------------------------------------------------------------ procedure DrawLine(img: TImage32; const lines: TPathsD; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle; miterLimit: double); var lines2: TPathsD; begin if (not assigned(lines)) or (not assigned(renderer)) then exit; if (lineWidth < MinStrokeWidth) then lineWidth := MinStrokeWidth; lines2 := Outline(lines, lineWidth, joinStyle, endStyle, miterLimit); if renderer.Initialize(img) then begin Rasterize(lines2, img.bounds, frNonZero, renderer); renderer.NotifyChange; end; end; //------------------------------------------------------------------------------ procedure DrawInvertedLine(img: TImage32; const lines: TPathsD; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); var lines2: TPathsD; ir: TInverseRenderer; begin if not assigned(lines) then exit; if (lineWidth < MinStrokeWidth) then lineWidth := MinStrokeWidth; lines2 := Outline(lines, lineWidth, joinStyle, endStyle, 2); ir := TInverseRenderer.Create; try if ir.Initialize(img) then begin Rasterize(lines2, img.bounds, frNonZero, ir); ir.NotifyChange; end; finally ir.free; end; end; //------------------------------------------------------------------------------ procedure DrawDashedLine(img: TImage32; const line: TPathD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle); var lines: TPathsD; cr: TColorRenderer; i: integer; begin if (lineWidth < MinStrokeWidth) then lineWidth := MinStrokeWidth; if not assigned(line) then exit; for i := 0 to High(dashPattern) do if dashPattern[i] <= 0 then dashPattern[i] := 1; lines := GetDashedPath(line, endStyle = esPolygon, dashPattern, patternOffset); if Length(lines) = 0 then Exit; case joinStyle of jsSquare, jsMiter: endStyle := esSquare; jsRound: endStyle := esRound; else endStyle := esButt; end; lines := Outline(lines, lineWidth, joinStyle, endStyle); cr := TColorRenderer.Create(color); try if cr.Initialize(img) then begin Rasterize(lines, img.bounds, frNonZero, cr); cr.NotifyChange; end; finally cr.free; end; end; //------------------------------------------------------------------------------ procedure DrawDashedLine(img: TImage32; const lines: TPathsD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; color: TColor32; endStyle: TEndStyle; joinStyle: TJoinStyle); var i: integer; begin if not assigned(lines) then exit; for i := 0 to high(lines) do DrawDashedLine(img, lines[i], dashPattern, patternOffset, lineWidth, color, endStyle, joinStyle); end; //------------------------------------------------------------------------------ procedure DrawDashedLine(img: TImage32; const line: TPathD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle); var i: integer; lines: TPathsD; begin if (not assigned(line)) or (not assigned(renderer)) then exit; if (lineWidth < MinStrokeWidth) then lineWidth := MinStrokeWidth; for i := 0 to High(dashPattern) do if dashPattern[i] <= 0 then dashPattern[i] := 1; lines := GetDashedPath(line, endStyle = esPolygon, dashPattern, patternOffset); if Length(lines) = 0 then Exit; lines := Outline(lines, lineWidth, joinStyle, endStyle); if renderer.Initialize(img) then begin Rasterize(lines, img.bounds, frNonZero, renderer); renderer.NotifyChange; end; end; //------------------------------------------------------------------------------ procedure DrawDashedLine(img: TImage32; const lines: TPathsD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; renderer: TCustomRenderer; endStyle: TEndStyle; joinStyle: TJoinStyle); var i: integer; begin if not assigned(lines) then exit; for i := 0 to high(lines) do DrawDashedLine(img, lines[i], dashPattern, patternOffset, lineWidth, renderer, endStyle, joinStyle); end; //------------------------------------------------------------------------------ procedure DrawInvertedDashedLine(img: TImage32; const line: TPathD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); var i: integer; lines: TPathsD; renderer: TInverseRenderer; begin if not assigned(line) then exit; if (lineWidth < MinStrokeWidth) then lineWidth := MinStrokeWidth; for i := 0 to High(dashPattern) do if dashPattern[i] <= 0 then dashPattern[i] := 1; lines := GetDashedPath(line, endStyle = esPolygon, dashPattern, patternOffset); if Length(lines) = 0 then Exit; lines := Outline(lines, lineWidth, joinStyle, endStyle); renderer := TInverseRenderer.Create; try if renderer.Initialize(img) then begin Rasterize(lines, img.bounds, frNonZero, renderer); renderer.NotifyChange; end; finally renderer.Free; end; end; //------------------------------------------------------------------------------ procedure DrawInvertedDashedLine(img: TImage32; const lines: TPathsD; dashPattern: TArrayOfInteger; patternOffset: PDouble; lineWidth: double; endStyle: TEndStyle; joinStyle: TJoinStyle = jsAuto); var i: integer; begin if not assigned(lines) then exit; for i := 0 to high(lines) do DrawInvertedDashedLine(img, lines[i], dashPattern, patternOffset, lineWidth, endStyle, joinStyle); end; //------------------------------------------------------------------------------ procedure DrawPolygon(img: TImage32; const polygon: TPathD; fillRule: TFillRule; color: TColor32); var polygons: TPathsD; begin if not assigned(polygon) then exit; setLength(polygons, 1); polygons[0] := polygon; DrawPolygon(img, polygons, fillRule, color); end; //------------------------------------------------------------------------------ procedure DrawPolygon(img: TImage32; const polygon: TPathD; fillRule: TFillRule; renderer: TCustomRenderer); var polygons: TPathsD; begin if (not assigned(polygon)) or (not assigned(renderer)) then exit; setLength(polygons, 1); polygons[0] := polygon; if renderer.Initialize(img) then begin Rasterize(polygons, img.Bounds, fillRule, renderer); renderer.NotifyChange; end; end; //------------------------------------------------------------------------------ procedure DrawPolygon(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; color: TColor32); var cr: TCustomRenderer; begin if not assigned(polygons) then exit; if img.AntiAliased then cr := TColorRenderer.Create(color) else cr := TAliasedColorRenderer.Create(color); try if cr.Initialize(img) then begin Rasterize(polygons, img.bounds, fillRule, cr); cr.NotifyChange; end; finally cr.free; end; end; //------------------------------------------------------------------------------ procedure DrawPolygon(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; renderer: TCustomRenderer); begin if (not assigned(polygons)) or (not assigned(renderer)) then exit; if renderer.Initialize(img) then begin Rasterize(polygons, img.bounds, fillRule, renderer); renderer.NotifyChange; end; end; //------------------------------------------------------------------------------ procedure DrawPolygon_ClearType(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; color: TColor32; backColor: TColor32); var w, h: integer; tmpImg: TImage32; rec: TRect; tmpPolygons: TPathsD; cr: TColorRenderer; begin if not assigned(polygons) then exit; rec := GetBounds(polygons); RectWidthHeight(rec, w, h); tmpImg := TImage32.Create(w *3, h); try tmpPolygons := OffsetPath(polygons, -rec.Left, -rec.Top); tmpPolygons := ScalePath(tmpPolygons, 3, 1); cr := TColorRenderer.Create(clBlack32); try if cr.Initialize(tmpImg) then Rasterize(tmpPolygons, tmpImg.bounds, fillRule, cr); finally cr.Free; end; ApplyClearType(tmpImg, color, backColor); img.CopyBlend(tmpImg, tmpImg.Bounds, rec, BlendToAlpha); finally tmpImg.Free; end; end; //------------------------------------------------------------------------------ procedure ErasePolygon(img: TImage32; const polygon: TPathD; fillRule: TFillRule); var polygons: TPathsD; begin if not assigned(polygon) then exit; setLength(polygons, 1); polygons[0] := polygon; ErasePolygon(img, polygons, fillRule); end; //------------------------------------------------------------------------------ procedure ErasePolygon(img: TImage32; const polygons: TPathsD; fillRule: TFillRule); var er: TEraseRenderer; begin er := TEraseRenderer.Create; try if er.Initialize(img) then begin Rasterize(polygons, img.bounds, fillRule, er); er.NotifyChange; end; finally er.Free; end; end; //------------------------------------------------------------------------------ procedure DrawBoolMask(img: TImage32; const mask: TArrayOfByte; color: TColor32); var i, len: integer; pc: PColor32; pb: PByte; begin len := Length(mask); if (len = 0) or (len <> img.Width * img.Height) then Exit; pc := img.PixelBase; pb := @mask[0]; for i := 0 to len -1 do begin {$IFDEF PBYTE} if pb^ > 0 then {$ELSE} if pb^ > #0 then {$ENDIF} pc^ := color else pc^ := clNone32; inc(pc); inc(pb); end; end; //------------------------------------------------------------------------------ procedure DrawAlphaMask(img: TImage32; const mask: TArrayOfByte; color: TColor32); var i, len: integer; pc: PColor32; pb: PByte; begin len := Length(mask); if (len = 0) or (len <> img.Width * img.Height) then Exit; color := color and $FFFFFF; //strip alpha value pc := img.PixelBase; pb := @mask[0]; for i := 0 to len -1 do begin {$IFDEF PBYTE} if pb^ > 0 then pc^ := color or pb^ shl 24 else pc^ := clNone32; {$ELSE} if pb^ > #0 then pc^ := color or Ord(pb^) shl 24 else pc^ := clNone32; {$ENDIF} inc(pc); inc(pb); end; end; //------------------------------------------------------------------------------ end. doublecmd-1.1.22/components/Image32/source/Img32.Extra.pas0000644000175000001440000027146714743153644022153 0ustar alexxusersunit Img32.Extra; (******************************************************************************* * Author : Angus Johnson * * Version : 4.3 * * Date : 27 September 2022 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2019-2021 * * * * Purpose : Miscellaneous routines for TImage32 that * * : don't obviously belong in other modules. * * * * License : Use, modification & distribution is subject to * * Boost Software License Ver 1 * * http://www.boost.org/LICENSE_1_0.txt * *******************************************************************************) interface {$I Img32.inc} uses SysUtils, Classes, Math, Types, Img32, Img32.Draw, Img32.Vector; type TButtonShape = (bsRound, bsSquare, bsDiamond); TButtonAttribute = (baShadow, ba3D, baEraseBeneath); TButtonAttributes = set of TButtonAttribute; type PPt = ^TPt; TPt = record pt : TPointD; vec : TPointD; len : double; next : PPt; prev : PPt; end; TFitCurveContainer = class private ppts : PPt; solution : TPathD; tolSqrd : double; function Count(first, last: PPt): integer; function AddPt(const pt: TPointD): PPt; procedure Clear; function ComputeLeftTangent(p: PPt): TPointD; function ComputeRightTangent(p: PPt): TPointD; function ComputeCenterTangent(p: PPt): TPointD; function ChordLengthParameterize( first: PPt; cnt: integer): TArrayOfDouble; function GenerateBezier(first, last: PPt; cnt: integer; const u: TArrayOfDouble; const firstTan, lastTan: TPointD): TPathD; function Reparameterize(first: PPt; cnt: integer; const u: TArrayOfDouble; const bezier: TPathD): TArrayOfDouble; function NewtonRaphsonRootFind(const q: TPathD; const pt: TPointD; u: double): double; function ComputeMaxErrorSqrd(first, last: PPt; const bezier: TPathD; const u: TArrayOfDouble; out SplitPoint: PPt): double; function FitCubic(first, last: PPt; firstTan, lastTan: TPointD): Boolean; procedure AppendSolution(const bezier: TPathD); public function FitCurve(const path: TPathD; closed: Boolean; tolerance: double; minSegLength: double): TPathD; end; procedure DrawEdge(img: TImage32; const rec: TRect; topLeftColor, bottomRightColor: TColor32; penWidth: double = 1.0); overload; procedure DrawEdge(img: TImage32; const rec: TRectD; topLeftColor, bottomRightColor: TColor32; penWidth: double = 1.0); overload; procedure DrawEdge(img: TImage32; const path: TPathD; topLeftColor, bottomRightColor: TColor32; penWidth: double = 1.0; closePath: Boolean = true); overload; //DrawShadowRect: is **much** faster than DrawShadow procedure DrawShadowRect(img: TImage32; const rec: TRect; depth: double; angle: double = angle45; color: TColor32 = $80000000); procedure DrawShadow(img: TImage32; const polygon: TPathD; fillRule: TFillRule; depth: double; angleRads: double = angle45; color: TColor32 = $80000000; cutoutInsideShadow: Boolean = false); overload; procedure DrawShadow(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; depth: double; angleRads: double = angle45; color: TColor32 = $80000000; cutoutInsideShadow: Boolean = false); overload; procedure DrawGlow(img: TImage32; const polygon: TPathD; fillRule: TFillRule; color: TColor32; blurRadius: integer); overload; procedure DrawGlow(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; color: TColor32; blurRadius: integer); overload; procedure TileImage(img: TImage32; const rec: TRect; tile: TImage32); overload; procedure TileImage(img: TImage32; const rec: TRect; tile: TImage32; const tileRec: TRect); overload; //FloodFill: If no CompareFunc is provided, FloodFill will fill whereever //adjoining pixels exactly match the starting pixel - Point(x,y). procedure FloodFill(img: TImage32; x, y: Integer; newColor: TColor32; tolerance: Byte = 0; compareFunc: TCompareFunctionEx = nil); procedure FastGaussianBlur(img: TImage32; const rec: TRect; stdDev: integer; repeats: integer); overload; procedure FastGaussianBlur(img: TImage32; const rec: TRect; stdDevX, stdDevY: integer; repeats: integer); overload; procedure GaussianBlur(img: TImage32; rec: TRect; radius: Integer); //Emboss: A smaller radius is sharper. Increasing depth increases contrast. //Luminance changes grayscale balance (unless preserveColor = true) procedure Emboss(img: TImage32; radius: Integer = 1; depth: Integer = 10; luminance: Integer = 75; preserveColor: Boolean = false); //Sharpen: Radius range is 1 - 10; amount range is 1 - 50.
//see https://en.wikipedia.org/wiki/Unsharp_masking procedure Sharpen(img: TImage32; radius: Integer = 2; amount: Integer = 10); //HatchBackground: Assumes the current image is semi-transparent. procedure HatchBackground(img: TImage32; color1: TColor32 = clWhite32; color2: TColor32= $FFE8E8E8; hatchSize: Integer = 10); overload; procedure HatchBackground(img: TImage32; const rec: TRect; color1: TColor32 = clWhite32; color2: TColor32= $FFE8E8E8; hatchSize: Integer = 10); overload; procedure GridBackground(img: TImage32; majorInterval, minorInterval: integer; fillColor: TColor32 = clWhite32; majColor: TColor32 = $30000000; minColor: TColor32 = $20000000); procedure ReplaceColor(img: TImage32; oldColor, newColor: TColor32); //EraseColor: Removes the specified color from the image, even from //pixels that are a blend of colors including the specified color.
//see https://stackoverflow.com/questions/9280902/ procedure EraseColor(img: TImage32; color: TColor32); //RedEyeRemove: Removes 'red eye' from flash photo images. procedure RedEyeRemove(img: TImage32; const rect: TRect); procedure PencilEffect(img: TImage32; intensity: integer = 0); procedure TraceContours(img: TImage32; intensity: integer); procedure EraseInsidePath(img: TImage32; const path: TPathD; fillRule: TFillRule); procedure EraseInsidePaths(img: TImage32; const paths: TPathsD; fillRule: TFillRule); procedure EraseOutsidePath(img: TImage32; const path: TPathD; fillRule: TFillRule; const outsideBounds: TRect); procedure EraseOutsidePaths(img: TImage32; const paths: TPathsD; fillRule: TFillRule; const outsideBounds: TRect); procedure Draw3D(img: TImage32; const polygon: TPathD; fillRule: TFillRule; height, blurRadius: double; colorLt: TColor32 = $DDFFFFFF; colorDk: TColor32 = $80000000; angleRads: double = angle225); overload; procedure Draw3D(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; height, blurRadius: double; colorLt: TColor32 = $DDFFFFFF; colorDk: TColor32 = $80000000; angleRads: double = angle225); overload; function RainbowColor(fraction: double): TColor32; function GradientColor(color1, color2: TColor32; frac: single): TColor32; function MakeDarker(color: TColor32; percent: cardinal): TColor32; function MakeLighter(color: TColor32; percent: cardinal): TColor32; function DrawButton(img: TImage32; const pt: TPointD; size: double; color: TColor32 = clNone32; buttonShape: TButtonShape = bsRound; buttonAttributes: TButtonAttributes = [baShadow, ba3D, baEraseBeneath]): TPathD; //Vectorize: convert an image into polygon vectors function Vectorize(img: TImage32; compareColor: TColor32; compareFunc: TCompareFunction; colorTolerance: Integer; roundingTolerance: integer = 2): TPathsD; function VectorizeMask(const mask: TArrayOfByte; maskWidth: integer): TPathsD; // RamerDouglasPeucker: simplifies paths, recursively removing vertices where // they deviate no more than 'epsilon' from their adjacent vertices. function RamerDouglasPeucker(const path: TPathD; epsilon: double): TPathD; overload; function RamerDouglasPeucker(const paths: TPathsD; epsilon: double): TPathsD; overload; // SmoothToCubicBezier - produces a series of cubic bezier control points. // This function is very useful in the following combination: // RamerDouglasPeucker(), SmoothToCubicBezier(), FlattenCBezier(). function SmoothToCubicBezier(const path: TPathD; pathIsClosed: Boolean; maxOffset: integer = 0): TPathD; //InterpolatePoints: smooths a simple line chart. //Points should be left to right and equidistant along the X axis function InterpolatePoints(const points: TPathD; tension: integer = 0): TPathD; function GetFloodFillMask(imgIn, imgMaskOut: TImage32; x, y: Integer; tolerance: Byte; compareFunc: TCompareFunctionEx): Boolean; procedure SymmetricCropTransparent(img: TImage32); //3 additional blend functions (see TImage32.CopyBlend) function BlendAverage(bgColor, fgColor: TColor32): TColor32; function BlendLinearBurn(bgColor, fgColor: TColor32): TColor32; function BlendColorDodge(bgColor, fgColor: TColor32): TColor32; //CurveFit: this function is based on - //"An Algorithm for Automatically Fitting Digitized Curves" //by Philip J. Schneider in "Graphics Gems", Academic Press, 1990 //Smooths out many very closely positioned points //tolerance range: 1..10 where 10 == max tolerance. function CurveFit(const path: TPathD; closed: Boolean; tolerance: double; minSegLength: double = 2): TPathD; overload; function CurveFit(const paths: TPathsD; closed: Boolean; tolerance: double; minSegLength: double = 2): TPathsD; overload; implementation uses {$IFNDEF MSWINDOWS} {$IFNDEF FPC} Img32.FMX, {$ENDIF} {$ENDIF} Img32.Transform; const FloodFillDefaultRGBTolerance: byte = 64; MaxBlur = 100; type PColor32Array = ^TColor32Array; TColor32Array = array [0.. maxint div SizeOf(TColor32) -1] of TColor32; PWeightedColorArray = ^TWeightedColorArray; TWeightedColorArray = array [0.. $FFFFFF] of TWeightedColor; //------------------------------------------------------------------------------ // Miscellaneous functions //------------------------------------------------------------------------------ function GetSymmetricCropTransparentRect(img: TImage32): TRect; var w,h, x,y, x1,y1: Integer; p1,p2: PARGB; opaquePxlFound: Boolean; begin Result := img.Bounds; w := img.Width; y1 := 0; opaquePxlFound := false; for y := 0 to (img.Height div 2) -1 do begin p1 := PARGB(img.PixelRow[y]); p2 := PARGB(img.PixelRow[img.Height - y -1]); for x := 0 to w -1 do begin if (p1.A > 0) or (p2.A > 0) then begin y1 := y; opaquePxlFound := true; break; end; inc(p1); inc(p2); end; if opaquePxlFound then break; end; // probably safeset not to resize empty images if not opaquePxlFound then Exit; if y1 > 0 then begin inc(Result.Top, y1); dec(Result.Bottom, y1); end; x1 := 0; h := RectHeight(Result); opaquePxlFound := false; for x := 0 to (w div 2) -1 do begin p1 := PARGB(@img.Pixels[Result.Top * w + x]); p2 := PARGB(@img.Pixels[Result.Top * w + (w -1) - x]); for y := 0 to h -1 do begin if (p1.A > 0) or (p2.A > 0) then begin x1 := x; opaquePxlFound := true; break; end; inc(p1, w); inc(p2, w); end; if opaquePxlFound then break; end; if not opaquePxlFound then Exit; inc(Result.Left, x1); dec(Result.Right, x1); end; //------------------------------------------------------------------------------ //SymmetricCropTransparent: after cropping, the image's midpoint //will be the same pixel as before cropping. (Important for rotating.) procedure SymmetricCropTransparent(img: TImage32); var rec: TRect; begin rec := GetSymmetricCropTransparentRect(img); if (rec.Top > 0) or (rec.Left > 0) then img.Crop(rec); end; //------------------------------------------------------------------------------ procedure DrawEdge(img: TImage32; const rec: TRect; topLeftColor, bottomRightColor: TColor32; penWidth: double = 1.0); begin DrawEdge(img, RectD(rec), topLeftColor, bottomRightColor, penWidth); end; //------------------------------------------------------------------------------ procedure DrawEdge(img: TImage32; const rec: TRectD; topLeftColor, bottomRightColor: TColor32; penWidth: double = 1.0); var p: TPathD; c: TColor32; begin if penWidth = 0 then Exit else if penWidth < 0 then begin c := topLeftColor; topLeftColor := bottomRightColor; bottomRightColor := c; penWidth := -penWidth; end; if topLeftColor <> bottomRightColor then begin with rec do begin p := Img32.Vector.MakePath([left, bottom, left, top, right, top]); DrawLine(img, p, penWidth, topLeftColor, esButt); p := Img32.Vector.MakePath([right, top, right, bottom, left, bottom]); DrawLine(img, p, penWidth, bottomRightColor, esButt); end; end else DrawLine(img, Rectangle(rec), penWidth, topLeftColor, esPolygon); end; //------------------------------------------------------------------------------ procedure DrawEdge(img: TImage32; const path: TPathD; topLeftColor, bottomRightColor: TColor32; penWidth: double = 1.0; closePath: Boolean = true); var i, highI, deg: integer; frac: double; c: TColor32; p: TPathD; const RadToDeg = 180/PI; begin if penWidth = 0 then Exit else if penWidth < 0 then begin c := topLeftColor; topLeftColor := bottomRightColor; bottomRightColor := c; penWidth := -penWidth; end; highI := high(path); if highI < 2 then Exit; p := path; if closePath and not PointsNearEqual(p[0], p[highI], 0.01) then begin AppendPath(p, p[0]); inc(highI); end; for i := 1 to highI do begin deg := Round(GetAngle(p[i-1], p[i]) * RadToDeg); case deg of -180..-136: frac := (-deg-135)/45; -135..0 : frac := 0; 1..44 : frac := deg/45; else frac := 1; end; c := GradientColor(topLeftColor, bottomRightColor, frac); DrawLine(img, p[i-1], p[i], penWidth, c); end; end; //------------------------------------------------------------------------------ procedure FillColorHorz(img: TImage32; x, endX, y: integer; color: TColor32); var i,dx: integer; p: PColor32; begin if (x < 0) or (x >= img.Width) then Exit; if (y < 0) or (y >= img.Height) then Exit; p := img.PixelRow[y]; inc(p, x); if endX >= img.Width then endX := img.Width -1 else if endX < 0 then endX := 0; if endX < x then dx := -1 else dx := 1; for i := 0 to Abs(x-endX) do begin p^ := color; inc(p, dx); end; end; //------------------------------------------------------------------------------ procedure FillColorVert(img: TImage32; x, y, endY: integer; color: TColor32); var i, dy: integer; p: PColor32; begin if (x < 0) or (x >= img.Width) then Exit; if (y < 0) or (y >= img.Height) then Exit; p := img.PixelRow[y]; inc(p, x); if endY >= img.Height then endY := img.Height -1 else if endY < 0 then endY := 0; dy := img.Width; if endY < y then dy := -dy; for i := 0 to Abs(y - endY) do begin p^ := color; inc(p, dy); end; end; //------------------------------------------------------------------------------ procedure DrawShadowRect(img: TImage32; const rec: TRect; depth: double; angle: double = angle45; color: TColor32 = $80000000); var i,j, sX,sY: integer; l,t,r,b: integer; tmpImg: TImage32; tmpRec: TRect; xx,yy: double; ss: TPointD; c: TColor32; begin GetSinCos(angle, yy, xx); ss.X := depth * xx; ss.Y := depth * yy; sX := Abs(Round(ss.X)); sY := Abs(Round(ss.Y)); if rec.Left + ss.X < 0 then ss.X := -rec.Left else if rec.Right + ss.X > img.Width then ss.X := img.Width - rec.Right -1; if rec.Top + ss.Y < 0 then ss.Y := -rec.Top else if rec.Bottom + ss.Y > img.Height then ss.Y := img.Height -rec.Bottom -1; tmpImg := TImage32.Create(sX*3 +1, sY*3 +1); try i := sX div 2; j := sY div 2; DrawPolygon(tmpImg, Rectangle(i,j,i+sX*2,j+sY*2), frNonZero, color); FastGaussianBlur(tmpImg, tmpImg.Bounds, Round(sX/4),Round(sY/4), 1); // t-l corner if (ss.X < 0) or (ss.Y < 0) then begin tmpRec := Rect(0, 0, sX, sY); l := rec.Left; t := rec.Top; if ss.X < 0 then dec(l, sX); if ss.Y < 0 then dec(t, sY); img.Copy(tmpImg, tmpRec, Rect(l,t,l+sX,t+sY)); end; // t-r corner if (ss.X > 0) or (ss.Y < 0) then begin tmpRec := Rect(sX*2+1, 0, sX*3+1, sY); l := rec.Right; t := rec.Top; if ss.X < 0 then dec(l, sX); if ss.Y < 0 then dec(t, sY); img.Copy(tmpImg, tmpRec, Rect(l,t,l+sX,t+sY)); end; // b-l corner if (ss.X < 0) or (ss.Y > 0) then begin tmpRec := Rect(0, sY*2+1, sX, sY*3+1); l := rec.Left; t := rec.Bottom; if ss.X < 0 then dec(l, sX); if ss.Y < 0 then dec(t, sY); img.Copy(tmpImg, tmpRec, Rect(l,t,l+sX,t+sY)); end; // b-r corner if (ss.X > 0) or (ss.Y > 0) then begin tmpRec := Rect(sX*2+1, sY*2+1, sX*3+1, sY*3+1); l := rec.Right; t := rec.Bottom; if ss.X < 0 then dec(l, sX); if ss.Y < 0 then dec(t, sY); img.Copy(tmpImg, tmpRec, Rect(l,t,l+sX,t+sY)); end; // l-edge if (ss.X < 0) then begin l := rec.Left; t := rec.Top+sY; b := rec.Bottom-1; if ss.Y < 0 then begin dec(t, sY); dec(b,sY); end; for i := 1 to sX do begin c := tmpImg.Pixel[sX-i, sY+1]; FillColorVert(img, l-i, t, b, c); end; end; // t-edge if (ss.Y < 0) then begin l := rec.Left+sX; r := rec.Right-1; t := rec.Top; if ss.X < 0 then begin dec(l, sX); dec(r,sX); end; for i := 1 to sY do begin c := tmpImg.Pixel[sX+1, sY-i]; FillColorHorz(img, l, r, t-i, c); end; end; // r-edge if (ss.X > 0) then begin r := rec.Right-1; t := rec.Top+sY; b := rec.Bottom-1; if ss.Y < 0 then begin dec(t, sY); dec(b,sY); end; for i := 1 to sX do begin c := tmpImg.Pixel[sX*2+i, sY+1]; FillColorVert(img, r+i, t, b, c); end; end; // b-edge if (ss.Y > 0) then begin l := rec.Left+sX; r := rec.Right-1; b := rec.Bottom-1; if ss.X < 0 then begin dec(l, sX); dec(r,sX); end; for i := 1 to sY do begin c := tmpImg.Pixel[sX+1, sY*2+i]; FillColorHorz(img, l, r, b+i, c); end; end; finally tmpImg.Free; end; end; //------------------------------------------------------------------------------ procedure DrawShadow(img: TImage32; const polygon: TPathD; fillRule: TFillRule; depth: double; angleRads: double; color: TColor32; cutoutInsideShadow: Boolean); var polygons: TPathsD; begin setlength(polygons, 1); polygons[0] := polygon; DrawShadow(img, polygons, fillRule, depth, angleRads, color, cutoutInsideShadow); end; //------------------------------------------------------------------------------ procedure DrawShadow(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; depth: double; angleRads: double; color: TColor32; cutoutInsideShadow: Boolean); var x, y: double; blurSize, w,h: integer; rec: TRect; polys, shadowPolys: TPathsD; shadowImg: TImage32; begin rec := GetBounds(polygons); if IsEmptyRect(rec) or (depth < 1) then Exit; if not ClockwiseRotationIsAnglePositive then angleRads := -angleRads; NormalizeAngle(angleRads); GetSinCos(angleRads, y, x); depth := depth * 0.5; x := depth * x; y := depth * y; blurSize := Max(1,Round(depth / 2)); Img32.Vector.InflateRect(rec, Ceil(depth*2), Ceil(depth*2)); polys := OffsetPath(polygons, -rec.Left, -rec.Top); shadowPolys := OffsetPath(polys, x, y); RectWidthHeight(rec, w, h); shadowImg := TImage32.Create(w, h); try DrawPolygon(shadowImg, shadowPolys, fillRule, color); FastGaussianBlur(shadowImg, shadowImg.Bounds, blurSize, 1); if cutoutInsideShadow then EraseInsidePaths(shadowImg, polys, fillRule); img.CopyBlend(shadowImg, shadowImg.Bounds, rec, BlendToAlpha); finally shadowImg.Free; end; end; //------------------------------------------------------------------------------ procedure DrawGlow(img: TImage32; const polygon: TPathD; fillRule: TFillRule; color: TColor32; blurRadius: integer); var polygons: TPathsD; begin setlength(polygons, 1); polygons[0] := polygon; DrawGlow(img, polygons, fillRule, color, blurRadius); end; //------------------------------------------------------------------------------ procedure DrawGlow(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; color: TColor32; blurRadius: integer); var w,h: integer; rec: TRect; glowPolys: TPathsD; glowImg: TImage32; begin rec := GetBounds(polygons); glowPolys := OffsetPath(polygons, blurRadius -rec.Left +1, blurRadius -rec.Top +1); Img32.Vector.InflateRect(rec, blurRadius +1, blurRadius +1); RectWidthHeight(rec, w, h); glowImg := TImage32.Create(w, h); try DrawPolygon(glowImg, glowPolys, fillRule, color); FastGaussianBlur(glowImg, glowImg.Bounds, blurRadius, 2); glowImg.ScaleAlpha(4); img.CopyBlend(glowImg, glowImg.Bounds, rec, BlendToAlpha); finally glowImg.Free; end; end; //------------------------------------------------------------------------------ procedure TileImage(img: TImage32; const rec: TRect; tile: TImage32); begin TileImage(img, rec, tile, tile.Bounds); end; //------------------------------------------------------------------------------ procedure TileImage(img: TImage32; const rec: TRect; tile: TImage32; const tileRec: TRect); var i, dstW, dstH, srcW, srcH, cnt: integer; dstRec, srcRec: TRect; begin if tile.IsEmpty or IsEmptyRect(tileRec) then Exit; RectWidthHeight(rec, dstW,dstH); RectWidthHeight(tileRec, srcW, srcH); cnt := Ceil(dstW / srcW); dstRec := Img32.Vector.Rect(rec.Left, rec.Top, rec.Left + srcW, rec.Top + srcH); for i := 1 to cnt do begin img.Copy(tile, tileRec, dstRec); Types.OffsetRect(dstRec, srcW, 0); end; cnt := Ceil(dstH / srcH) -1; srcRec := Img32.Vector.Rect(rec.Left, rec.Top, rec.Right, rec.Top + srcH); dstRec := srcRec; for i := 1 to cnt do begin Types.OffsetRect(dstRec, 0, srcH); img.Copy(img, srcRec, dstRec); end; end; //------------------------------------------------------------------------------ procedure Sharpen(img: TImage32; radius: Integer; amount: Integer); var i: Integer; amt: double; weightAmount: array [-255 .. 255] of Integer; bmpBlur: TImage32; pColor, pBlur: PARGB; begin if radius = 0 then Exit; amt := ClampRange(amount/10, 0.1, 5); radius := ClampRange(radius, 1, 10); for i := -255 to 255 do weightAmount[i] := Round(amt * i); bmpBlur := TImage32.Create(img); // clone self try pColor := PARGB(img.pixelBase); FastGaussianBlur(bmpBlur, bmpBlur.Bounds, radius, 2); pBlur := PARGB(bmpBlur.pixelBase); for i := 1 to img.Width * img.Height do begin if (pColor.A > 0) then begin pColor.R := ClampByte(pColor.R + weightAmount[pColor.R - pBlur.R]); pColor.G := ClampByte(pColor.G + weightAmount[pColor.G - pBlur.G]); pColor.B := ClampByte(pColor.B + weightAmount[pColor.B - pBlur.B]); end; Inc(pColor); Inc(pBlur); end; finally bmpBlur.Free; end; end; //------------------------------------------------------------------------------ procedure HatchBackground(img: TImage32; const rec: TRect; color1: TColor32 = clWhite32; color2: TColor32= $FFE8E8E8; hatchSize: Integer = 10); overload; var i,j: Integer; pc: PColor32; colors: array[boolean] of TColor32; hatch: Boolean; begin colors[false] := color1; colors[true] := color2; img.BeginUpdate; try for i := rec.Top to rec.Bottom -1 do begin pc := img.PixelRow[i]; inc(pc, rec.Left); hatch := Odd(i div hatchSize); for j := rec.Left to rec.Right -1 do begin if (j + 1) mod hatchSize = 0 then hatch := not hatch; pc^ := BlendToOpaque(pc^, colors[hatch]); inc(pc); end; end; finally img.EndUpdate; end; end; //------------------------------------------------------------------------------ procedure HatchBackground(img: TImage32; color1: TColor32; color2: TColor32; hatchSize: Integer); begin HatchBackground(img, img.Bounds, color1, color2, hatchSize); end; //------------------------------------------------------------------------------ procedure GridBackground(img: TImage32; majorInterval, minorInterval: integer; fillColor: TColor32; majColor: TColor32; minColor: TColor32); var i, x,y, w,h: integer; path: TPathD; begin img.Clear(fillColor); w := img.Width; h := img.Height; SetLength(path, 2); if minorInterval > 0 then begin x := minorInterval; path[0] := PointD(x, 0); path[1] := PointD(x, h);; for i := 1 to (w div minorInterval) do begin Img32.Draw.DrawLine(img, path, 1, minColor, esSquare); path[0].X := path[0].X + minorInterval; path[1].X := path[1].X + minorInterval; end; y := minorInterval; path[0] := PointD(0, y); path[1] := PointD(w, y); for i := 1 to (h div minorInterval) do begin Img32.Draw.DrawLine(img, path, 1, minColor, esSquare); path[0].Y := path[0].Y + minorInterval; path[1].Y := path[1].Y + minorInterval; end; end; if majorInterval > minorInterval then begin x := majorInterval; path[0] := PointD(x, 0); path[1] := PointD(x, h);; for i := 1 to (w div majorInterval) do begin Img32.Draw.DrawLine(img, path, 1, majColor, esSquare); path[0].X := path[0].X + majorInterval; path[1].X := path[1].X + majorInterval; end; y := majorInterval; path[0] := PointD(0, y); path[1] := PointD(w, y); for i := 1 to (h div majorInterval) do begin Img32.Draw.DrawLine(img, path, 1, majColor, esSquare); path[0].Y := path[0].Y + majorInterval; path[1].Y := path[1].Y + majorInterval; end; end; end; //------------------------------------------------------------------------------ function ColorDifference(color1, color2: TColor32): cardinal; {$IFDEF INLINE} inline; {$ENDIF} var c1: TARGB absolute color1; c2: TARGB absolute color2; begin result := Abs(c1.R - c2.R) + Abs(c1.G - c2.G) + Abs(c1.B - c2.B); result := (result * 341) shr 10; // divide by 3 end; //------------------------------------------------------------------------------ procedure ReplaceColor(img: TImage32; oldColor, newColor: TColor32); var color: PColor32; i: Integer; begin color := img.PixelBase; for i := 0 to img.Width * img.Height -1 do begin if color^ = oldColor then color^ := newColor; inc(color); end; end; //------------------------------------------------------------------------------ procedure EraseColor(img: TImage32; color: TColor32); var fg: TARGB absolute color; bg: PARGB; i: Integer; Q: byte; begin if fg.A = 0 then Exit; bg := PARGB(img.PixelBase); for i := 0 to img.Width * img.Height -1 do begin if bg.A > 0 then begin if (bg.R > fg.R) then Q := DivTable[bg.R - fg.R, not fg.R] else if (bg.R < fg.R) then Q := DivTable[fg.R - bg.R, fg.R] else Q := 0; if (bg.G > fg.G) then Q := Max(Q, DivTable[bg.G - fg.G, not fg.G]) else if (bg.G < fg.G) then Q := Max(Q, DivTable[fg.G - bg.G, fg.G]); if (bg.B > fg.B) then Q := Max(Q, DivTable[bg.B - fg.B, not fg.B]) else if (bg.B < fg.B) then Q := Max(Q, DivTable[fg.B - bg.B, fg.B]); if (Q > 0) then begin bg.A := MulTable[bg.A, Q]; bg.R := DivTable[bg.R - MulTable[fg.R, not Q], Q]; bg.G := DivTable[bg.G - MulTable[fg.G, not Q], Q]; bg.B := DivTable[bg.B - MulTable[fg.B, not Q], Q]; end else bg.Color := clNone32; end; inc(bg); end; end; //------------------------------------------------------------------------------ procedure RedEyeRemove(img: TImage32; const rect: TRect); var k: integer; cutout, mask: TImage32; path: TPathD; cutoutRec, rect3: TRect; radGrad: TRadialGradientRenderer; begin k := RectWidth(rect) * RectHeight(rect); if k < 120 then k := 2 else if k < 230 then k := 3 else k := 4; cutoutRec := rect; Img32.Vector.InflateRect(cutoutRec, k, k); cutout := TImage32.Create(img, cutoutRec); mask := TImage32.Create(cutout.Width, cutout.Height); radGrad := TRadialGradientRenderer.Create; try // fill behind the cutout with black also // blurring the fill to soften its edges rect3 := cutout.Bounds; Img32.Vector.InflateRect(rect3, -k, -k); path := Ellipse(rect3); DrawPolygon(mask, path, frNonZero, clBlack32); // given the very small area and small radius of the blur, the // speed improvement of BoxBlur over GaussianBlur is inconsequential. GaussianBlur(mask, mask.Bounds, k); img.CopyBlend(mask, mask.Bounds, cutoutRec, BlendToOpaque); // gradient fill to clNone32 a mask to soften cutout's edges path := Ellipse(cutoutRec); radGrad.SetParameters(rect3, clBlack32, clNone32); DrawPolygon(mask, path, frNonZero, radGrad); cutout.CopyBlend(mask, mask.Bounds, cutout.Bounds, BlendMask); // now remove red from the cutout EraseColor(cutout, clRed32); // finally replace the cutout ... img.CopyBlend(cutout, cutout.Bounds, cutoutRec, BlendToOpaque); finally mask.Free; cutout.Free; radGrad.Free; end; end; //------------------------------------------------------------------------------ procedure EraseInsidePath(img: TImage32; const path: TPathD; fillRule: TFillRule); begin if assigned(path) then ErasePolygon(img, path, fillRule); end; //------------------------------------------------------------------------------ procedure EraseInsidePaths(img: TImage32; const paths: TPathsD; fillRule: TFillRule); begin if assigned(paths) then ErasePolygon(img, paths, fillRule); end; //------------------------------------------------------------------------------ procedure EraseOutsidePath(img: TImage32; const path: TPathD; fillRule: TFillRule; const outsideBounds: TRect); var mask: TImage32; p: TPathD; w,h: integer; begin if not assigned(path) then Exit; RectWidthHeight(outsideBounds, w,h); mask := TImage32.Create(w, h); try p := OffsetPath(path, -outsideBounds.Left, -outsideBounds.top); DrawPolygon(mask, p, fillRule, clBlack32); img.CopyBlend(mask, mask.Bounds, outsideBounds, BlendMask); finally mask.Free; end; end; //------------------------------------------------------------------------------ procedure EraseOutsidePaths(img: TImage32; const paths: TPathsD; fillRule: TFillRule; const outsideBounds: TRect); var mask: TImage32; pp: TPathsD; w,h: integer; begin if not assigned(paths) then Exit; RectWidthHeight(outsideBounds, w,h); mask := TImage32.Create(w, h); try pp := OffsetPath(paths, -outsideBounds.Left, -outsideBounds.top); DrawPolygon(mask, pp, fillRule, clBlack32); img.CopyBlend(mask, mask.Bounds, outsideBounds, BlendMask); finally mask.Free; end; end; //------------------------------------------------------------------------------ procedure Draw3D(img: TImage32; const polygon: TPathD; fillRule: TFillRule; height, blurRadius: double; colorLt: TColor32; colorDk: TColor32; angleRads: double); var polygons: TPathsD; begin setLength(polygons, 1); polygons[0] := polygon; Draw3D(img, polygons, fillRule, height, blurRadius, colorLt, colorDk, angleRads); end; //------------------------------------------------------------------------------ procedure Draw3D(img: TImage32; const polygons: TPathsD; fillRule: TFillRule; height, blurRadius: double; colorLt: TColor32; colorDk: TColor32; angleRads: double); var tmp: TImage32; rec: TRect; paths, paths2: TPathsD; w,h: integer; x,y: double; begin rec := GetBounds(polygons); if IsEmptyRect(rec) then Exit; if not ClockwiseRotationIsAnglePositive then angleRads := -angleRads; GetSinCos(angleRads, y, x); paths := OffsetPath(polygons, -rec.Left, -rec.Top); RectWidthHeight(rec, w, h); tmp := TImage32.Create(w, h); try if GetAlpha(colorLt) > 0 then begin tmp.Clear(colorLt); paths2 := OffsetPath(paths, -height*x, -height*y); EraseInsidePaths(tmp, paths2, fillRule); FastGaussianBlur(tmp, tmp.Bounds, Round(blurRadius), 0); EraseOutsidePaths(tmp, paths, fillRule, tmp.Bounds); img.CopyBlend(tmp, tmp.Bounds, rec, BlendToAlpha); end; if GetAlpha(colorDk) > 0 then begin tmp.Clear(colorDk); paths2 := OffsetPath(paths, height*x, height*y); EraseInsidePaths(tmp, paths2, fillRule); FastGaussianBlur(tmp, tmp.Bounds, Round(blurRadius), 0); EraseOutsidePaths(tmp, paths, fillRule, tmp.Bounds); img.CopyBlend(tmp, tmp.Bounds, rec, BlendToAlpha); end; finally tmp.Free; end; end; //------------------------------------------------------------------------------ function RainbowColor(fraction: double): TColor32; var hsl: THsl; begin if (fraction > 0) and (fraction < 1) then begin hsl.hue := Round(fraction * 255); hsl.sat := 255; hsl.lum := 255; hsl.alpha := 255; Result := HslToRgb(hsl); end else result := clRed32 end; //------------------------------------------------------------------------------ function GradientColor(color1, color2: TColor32; frac: single): TColor32; var hsl1, hsl2: THsl; begin if (frac <= 0) then result := color1 else if (frac >= 1) then result := color2 else begin hsl1 := RgbToHsl(color1); hsl2 := RgbToHsl(color2); hsl1.hue := ClampByte(hsl1.hue*(1-frac) + hsl2.hue*frac); hsl1.sat := ClampByte(hsl1.sat*(1-frac) + hsl2.sat*frac); hsl1.lum := ClampByte(hsl1.lum*(1-frac) + hsl2.lum*frac); hsl1.alpha := ClampByte(hsl1.alpha*(1-frac) + hsl2.alpha*frac); Result := HslToRgb(hsl1); end; end; //------------------------------------------------------------------------------ function MakeDarker(color: TColor32; percent: cardinal): TColor32; var hsl: THsl; begin hsl := RgbToHsl(color); hsl.lum := ClampByte(hsl.lum - (percent/100 * hsl.lum)); Result := HslToRgb(hsl); end; //------------------------------------------------------------------------------ function MakeLighter(color: TColor32; percent: cardinal): TColor32; var hsl: THsl; begin hsl := RgbToHsl(color); hsl.lum := ClampByte(hsl.lum + percent/100 * (255 - hsl.lum)); Result := HslToRgb(hsl); end; //------------------------------------------------------------------------------ function DrawButton(img: TImage32; const pt: TPointD; size: double; color: TColor32; buttonShape: TButtonShape; buttonAttributes: TButtonAttributes): TPathD; var i: integer; radius: double; rec: TRectD; lightSize, lightAngle: double; begin if (size < 5) then Exit; radius := size * 0.5; lightSize := radius * 0.25; rec := RectD(pt.X -radius, pt.Y -radius, pt.X +radius, pt.Y +radius); if baEraseBeneath in buttonAttributes then img.Clear(Rect(rec)); case buttonShape of bsDiamond: begin SetLength(Result, 4); for i := 0 to 3 do Result[i] := pt; Result[0].X := Result[0].X -radius; Result[1].Y := Result[1].Y -radius; Result[2].X := Result[2].X +radius; Result[3].Y := Result[3].Y +radius; end; bsSquare: begin Img32.Vector.InflateRect(rec, -1,-1); Result := Rectangle(rec); end; else Result := Ellipse(rec); end; lightAngle := angle225; img.BeginUpdate; try // nb: only need to cutout the inside shadow if // the pending color fill is semi-transparent if baShadow in buttonAttributes then DrawShadow(img, Result, frNonZero, lightSize *2, (lightAngle + angle180), $AA000000, GetAlpha(color) < $FE); if GetAlpha(color) > 2 then DrawPolygon(img, Result, frNonZero, color); if ba3D in buttonAttributes then Draw3D(img, Result, frNonZero, lightSize*2, Ceil(lightSize), $CCFFFFFF, $AA000000, lightAngle); DrawLine(img, Result, dpiAware1, clBlack32, esPolygon); finally img.EndUpdate; end; end; //------------------------------------------------------------------------------ function AlphaAverage(color1, color2: TColor32): cardinal; {$IFDEF INLINE} inline; {$ENDIF} var c1: TARGB absolute color1; c2: TARGB absolute color2; begin result := (c1.A + c2.A) shr 1; end; //------------------------------------------------------------------------------ function BlendAverage(bgColor, fgColor: TColor32): TColor32; var res: TARGB absolute Result; bg: TARGB absolute bgColor; fg: TARGB absolute fgColor; begin res.A := (fg.A + bg.A) shr 1; res.R := (fg.R + bg.R) shr 1; res.G := (fg.G + bg.G) shr 1; res.B := (fg.B + bg.B) shr 1; end; //------------------------------------------------------------------------------ function BlendLinearBurn(bgColor, fgColor: TColor32): TColor32; var res: TARGB absolute Result; bg: TARGB absolute bgColor; fg: TARGB absolute fgColor; begin res.A := 255; res.R := Max(0, bg.R + fg.R - 255); res.G := Max(0, bg.G + fg.G - 255); res.B := Max(0, bg.B + fg.B - 255); end; //------------------------------------------------------------------------------ function BlendColorDodge(bgColor, fgColor: TColor32): TColor32; var res: TARGB absolute Result; bg: TARGB absolute bgColor; fg: TARGB absolute fgColor; begin res.A := 255; res.R := DivTable[bg.R, not fg.R]; res.G := DivTable[bg.G, not fg.G]; res.B := DivTable[bg.B, not fg.B]; end; //------------------------------------------------------------------------------ procedure PencilEffect(img: TImage32; intensity: integer); var img2: TImage32; begin if img.IsEmpty then Exit; intensity := max(1, min(10, intensity)); img.Grayscale; img2 := TImage32.Create(img); try img2.InvertColors; FastGaussianBlur(img2, img2.Bounds, intensity, 2); img.CopyBlend(img2, img2.Bounds, img.Bounds, BlendColorDodge); finally img2.Free; end; end; //------------------------------------------------------------------------------ procedure TraceContours(img: TImage32; intensity: integer); var i,j, w,h: integer; tmp, tmp2: TArrayOfColor32; s, s2: PColor32; d: PARGB; begin w := img.Width; h := img.Height; if w * h = 0 then Exit; SetLength(tmp, w * h); SetLength(tmp2, w * h); s := img.PixelRow[0]; d := @tmp[0]; for j := 0 to h-1 do begin s2 := IncPColor32(s, 1); for i := 0 to w-2 do begin d.A := ColorDifference(s^, s2^); inc(s); inc(s2); inc(d); end; inc(s); inc(d); end; for j := 0 to w-1 do begin s := @tmp[j]; d := @tmp2[j]; s2 := IncPColor32(s, w); for i := 0 to h-2 do begin d.A := AlphaAverage(s^, s2^); inc(s, w); inc(s2, w); inc(d, w); end; end; Move(tmp2[0], img.PixelBase^, w * h * sizeOf(TColor32)); if intensity < 1 then Exit; if intensity > 10 then intensity := 10; // range = 1-10 img.ScaleAlpha(intensity); end; //------------------------------------------------------------------------------ // FLOODFILL - AND SUPPORT FUNCTIONS //------------------------------------------------------------------------------ type PFloodFillRec = ^TFloodFillRec; TFloodFillRec = record xLeft : Integer; xRight : Integer; y : Integer; dirY : Integer; next : PFloodFillRec; end; TFloodFillStack = class first : PFloodFillRec; maxY : integer; constructor Create(maxY: integer); destructor Destroy; override; procedure Push(xLeft, xRight,y, direction: Integer); procedure Pop(out xLeft, xRight,y, direction: Integer); function IsEmpty: Boolean; end; TFloodFillMask = class private img : TImage32; mask : TImage32; colorsRow : PColor32Array; maskRow : PColor32Array; initialColor : TColor32; compareFunc : TCompareFunctionEx; tolerance : Integer; public function Execute(imgIn, imgMaskOut: TImage32; x,y: integer; aTolerance: Byte = 0; compFunc: TCompareFunctionEx = nil): Boolean; procedure SetCurrentY(y: Integer); function IsMatch(x: Integer): Boolean; end; //------------------------------------------------------------------------------ // TFloodFillStack methods //------------------------------------------------------------------------------ constructor TFloodFillStack.Create(maxY: integer); begin self.maxY := maxY; end; //------------------------------------------------------------------------------ destructor TFloodFillStack.Destroy; var ffr: PFloodFillRec; begin while assigned(first) do begin ffr := first; first := first.next; dispose(ffr); end; end; //------------------------------------------------------------------------------ procedure TFloodFillStack.Push(xLeft, xRight, y, direction: Integer); var ffr: PFloodFillRec; begin if ((y <= 0) and (direction = -1)) or ((y >= maxY) and (direction = 1)) then Exit; new(ffr); ffr.xLeft := xLeft; ffr.xRight := xRight; ffr.y := y; ffr.dirY := direction; ffr.next := first; first := ffr; end; //------------------------------------------------------------------------------ procedure TFloodFillStack.Pop(out xLeft, xRight, y, direction: Integer); var ffr: PFloodFillRec; begin xLeft := first.xLeft; xRight := first.xRight; direction := first.dirY; y := first.y + direction; ffr := first; first := first.next; dispose(ffr); end; //------------------------------------------------------------------------------ function TFloodFillStack.IsEmpty: Boolean; begin result := not assigned(first); end; //------------------------------------------------------------------------------ // TFloodFillMask methods //------------------------------------------------------------------------------ function TFloodFillMask.Execute(imgIn, imgMaskOut: TImage32; x,y: integer; aTolerance: Byte; compFunc: TCompareFunctionEx): Boolean; var ffs : TFloodFillStack; w,h : integer; xl, xr, xr2 : Integer; maxX : Integer; dirY : Integer; begin Result := Assigned(imgIn) and Assigned(imgMaskOut) and InRange(x,0,imgIn.Width -1) and InRange(y,0,imgIn.Height -1); if not Result then Exit; w := imgIn.Width; h := imgIn.Height; // make sure the mask is the size of the image imgMaskOut.SetSize(w,h); img := imgIn; mask := imgMaskOut; compareFunc := compFunc; tolerance := aTolerance; maxX := w -1; ffs := TFloodFillStack.create(h -1); try initialColor := imgIn.Pixel[x, y]; xl := x; xr := x; SetCurrentY(y); IsMatch(x); while (xl > 0) and IsMatch(xl -1) do dec(xl); while (xr < maxX) and IsMatch(xr +1) do inc(xr); ffs.Push(xl, xr, y, -1); // down ffs.Push(xl, xr, y, 1); // up while not ffs.IsEmpty do begin ffs.Pop(xl, xr, y, dirY); SetCurrentY(y); xr2 := xl; // check left ... if IsMatch(xl) then begin while (xl > 0) and IsMatch(xl-1) do dec(xl); if xl <= xr2 -2 then ffs.Push(xl, xr2-2, y, -dirY); while (xr2 < maxX) and IsMatch(xr2+1) do inc(xr2); ffs.Push(xl, xr2, y, dirY); if xr2 >= xr +2 then ffs.Push(xr+2, xr2, y, -dirY); xl := xr2 +2; end; // check right ... while (xl <= xr) and not IsMatch(xl) do inc(xl); while (xl <= xr) do begin xr2 := xl; while (xr2 < maxX) and IsMatch(xr2+1) do inc(xr2); ffs.Push(xl, xr2, y, dirY); if xr2 >= xr +2 then begin ffs.Push(xr+2, xr2, y, -dirY); break; end; inc(xl, 2); while (xl <= xr) and not IsMatch(xl) do inc(xl); end; end; finally ffs.Free; end; end; //------------------------------------------------------------------------------ procedure TFloodFillMask.SetCurrentY(y: Integer); begin colorsRow := PColor32Array(img.PixelRow[y]); maskRow := PColor32Array(mask.PixelRow[y]); end; //------------------------------------------------------------------------------ function TFloodFillMask.IsMatch(x: Integer): Boolean; var b: Byte; begin if (maskRow[x] > 0) then result := false else begin b := compareFunc(initialColor, colorsRow[x]); result := b < tolerance; if Result then maskRow[x] := tolerance - b else maskRow[x] := 1; end; end; //------------------------------------------------------------------------------ function GetFloodFillMask(imgIn, imgMaskOut: TImage32; x, y: Integer; tolerance: Byte; compareFunc: TCompareFunctionEx): Boolean; var ffm: TFloodFillMask; begin if not Assigned(compareFunc) then compareFunc := CompareRGBEx; ffm := TFloodFillMask.Create; try Result := ffm.Execute(imgIn, imgMaskOut, x, y, tolerance, compareFunc); finally ffm.Free; end; end; //------------------------------------------------------------------------------ procedure FloodFill(img: TImage32; x, y: Integer; newColor: TColor32; tolerance: Byte; compareFunc: TCompareFunctionEx); var i: Integer; pc, pm: PColor32; mask: TImage32; begin if not assigned(compareFunc) then begin compareFunc := CompareRGBEx; if tolerance = 0 then tolerance := FloodFillDefaultRGBTolerance; end; mask := TImage32.Create; try if not GetFloodFillMask(img, mask, x, y, tolerance, compareFunc) then Exit; pc := img.PixelBase; pm := mask.PixelBase; for i := 0 to img.Width * img.Height -1 do begin if (pm^ > 1) then pc^ := newColor; inc(pm); inc(pc); end; finally mask.free; end; end; //------------------------------------------------------------------------------ // EMBOSS - AND SUPPORT FUNCTIONS //------------------------------------------------------------------------------ function IncPWeightColor(pwc: PWeightedColor; cnt: Integer): PWeightedColor; begin result := PWeightedColor(PByte(pwc) + cnt * SizeOf(TWeightedColor)); end; //------------------------------------------------------------------------------ function Intensity(color: TColor32): byte; var c: TARGB absolute color; begin Result := (c.R * 61 + c.G * 174 + c.B * 21) shr 8; end; //------------------------------------------------------------------------------ function Gray(color: TColor32): TColor32; var c: TARGB absolute color; res: TARGB absolute Result; begin res.A := c.A; res.R := Intensity(color); res.G := res.R; res.B := res.R; end; //------------------------------------------------------------------------------ procedure Emboss(img: TImage32; radius: Integer; depth: Integer; luminance: Integer; preserveColor: Boolean); var yy,xx, x,y, w,h: Integer; b: byte; kernel: array [0 .. MaxBlur, 0 .. MaxBlur] of Integer; wca: TArrayOfWeightedColor; pc0, pcf, pcb: PColor32; // pointers to pixels (forward & backward in kernel) pw0, pw: PWeightedColor; // pointers to weight customGray: TColor32; pc: PColor32; const maxDepth = 50; begin // grayscale luminance as percent where 0% is black and 100% is white //(luminance is ignored when preserveColor = true) luminance := ClampRange(luminance, 0, 100); b := luminance *255 div 100; customGray := $FF000000 + b shl 16 + b shl 8 + b; ClampRange(radius, 1, 5); inc(depth); ClampRange(depth, 2, maxDepth); kernel[0][0] := 1; for y := 1 to radius do for x := 1 to radius do kernel[y][x] := depth; w := img.Width; h := img.Height; // nb: dynamic arrays are zero-initialized (unless they're a function result) SetLength(wca, w * h); pc0 := IncPColor32(img.PixelBase, radius * w); pw0 := @wca[radius * w]; for y := radius to h -1 - radius do begin for x := radius to w -1 - radius do begin pw := IncPWeightColor(pw0, x); pcb := IncPColor32(pc0, x - 1); if preserveColor then begin pcf := IncPColor32(pc0, x); pw^.Add(pcf^, kernel[0,0]); inc(pcf); end else begin pw^.Add(customGray, kernel[0,0]); pcf := IncPColor32(pc0, x + 1); end; // parse the kernel ... for yy := 1 to radius do begin for xx := 1 to radius do begin pw^.Subtract(Gray(pcf^), kernel[yy,xx]); pw^.Add(Gray(pcb^), kernel[yy,xx]); dec(pcb); inc(pcf); end; dec(pcb, img.Width - radius); inc(pcf, img.Width - radius); end; end; inc(pc0, img.Width); inc(pw0, img.Width); end; pc := @img.Pixels[0]; pw := @wca[0]; for x := 0 to img.width * img.Height - 1 do begin pc^ := pw.Color or $FF000000; inc(pc); inc(pw); end; end; //------------------------------------------------------------------------------ // Structure and functions used by the Vectorize routine //------------------------------------------------------------------------------ type TPt2Container = class; TPt2 = class pt : TPointD; owner : TPt2Container; isStart : Boolean; isHole : Boolean; nextInPath : TPt2; prevInPath : TPt2; nextInRow : TPt2; prevInRow : TPt2; destructor Destroy; override; procedure Update(x, y: double); function GetCount: integer; function GetPoints: TPathD; property IsAscending: Boolean read isStart; end; TPt2Container = class prevRight: integer; leftMostPt, rightMost: TPt2; solution: TPathsD; procedure AddToSolution(const path: TPathD); function StartNewPath(insertBefore: TPt2; xLeft, xRight, y: integer; isHole: Boolean): TPt2; procedure AddRange(var current: TPt2; xLeft, xRight, y: integer); function JoinAscDesc(path1, path2: TPt2): TPt2; function JoinDescAsc(path1, path2: TPt2): TPt2; procedure CheckRowEnds(pt2Left, pt2Right: TPt2); end; //------------------------------------------------------------------------------ destructor TPt2.Destroy; var startPt, endPt, pt: TPt2; begin if not isStart then Exit; startPt := self; endPt := startPt.prevInPath; // remove 'endPt' from double linked list if endPt = owner.rightMost then owner.rightMost := endPt.prevInRow else if assigned(endPt.nextInRow) then endPt.nextInRow.prevInRow := endPt.prevInRow; if endPt = owner.leftMostPt then owner.leftMostPt := endPt.nextInRow else if assigned(endPt.prevInRow) then endPt.prevInRow.nextInRow := endPt.nextInRow; // remove 'startPt' from double linked list if startPt = owner.leftMostPt then owner.leftMostPt := startPt.nextInRow else if assigned(startPt.prevInRow) then startPt.prevInRow.nextInRow := startPt.nextInRow; if assigned(startPt.nextInRow) then startPt.nextInRow.prevInRow := startPt.prevInRow; owner.AddToSolution(GetPoints); // now Free the entire path (except self) pt := startPt.nextInPath; while pt <> startPt do begin endPt := pt; pt := pt.nextInPath; endPt.Free; end; end; //------------------------------------------------------------------------------ function IsColinear(const pt1, pt2, pt3: TPoint): Boolean; overload; begin // cross product = 0 result := (pt1.X - pt2.X)*(pt2.Y - pt3.Y) = (pt2.X - pt3.X)*(pt1.Y - pt2.Y); end; //------------------------------------------------------------------------------ function IsColinear(const pt1, pt2, pt3, pt4: TPoint): Boolean; overload; begin result := (pt1.X - pt2.X)*(pt3.Y - pt4.Y) = (pt3.X - pt4.X)*(pt1.Y - pt2.Y); end; //------------------------------------------------------------------------------ function CreatePt2After(pt: TPt2; const p: TPointD): TPt2; begin Result := TPt2.Create; Result.pt := p; Result.nextInPath := pt.nextInPath; Result.prevInPath := pt; pt.nextInPath.prevInPath := Result; pt.nextInPath := Result; end; //------------------------------------------------------------------------------ procedure TPt2.Update(x, y: double); var newPt2: TPt2; begin if isStart then begin // just update self.pt when colinear if (x = pt.X) and (pt.X = nextInPath.pt.X) then begin pt := PointD(x,y); Exit; end; // self -> 2 -> 1 -> nip CreatePt2After(self, pt); if (x <> pt.X) or (x <> nextInPath.pt.X) then begin // add a pixel either below or beside if IsAscending then CreatePt2After(self, PointD(pt.X, y)) else CreatePt2After(self, PointD(x, pt.Y)); end; pt := PointD(x,y); end else begin // just update self.pt when colinear if (x = pt.X) and (pt.X = prevInPath.pt.X) then begin pt := PointD(x,y); Exit; end; // self <- 2 <- 1 <- pip newPt2 := CreatePt2After(prevInPath, pt); if (x <> pt.X) or (x <> prevInPath.pt.X) then begin // add a pixel either below or beside if IsAscending then CreatePt2After(newPt2, PointD(x, pt.Y)) else CreatePt2After(newPt2, PointD(pt.X, y)); end; pt := PointD(x,y); end; end; //------------------------------------------------------------------------------ function TPt2.GetCount: integer; var pt2: TPt2; begin result := 1; pt2 := nextInPath; while pt2 <> self do begin inc(Result); pt2 := pt2.nextInPath; end; end; //------------------------------------------------------------------------------ function TPt2.GetPoints: TPathD; var i, count: integer; pt2: TPt2; begin Update(pt.X, pt.Y+1); with prevInPath do Update(pt.X, pt.Y+1); // path 'end' count := GetCount; SetLength(Result, count); pt2 := self; for i := 0 to count -1 do begin Result[i] := pt2.pt; pt2 := pt2.nextInPath; end; end; //------------------------------------------------------------------------------ procedure TPt2Container.AddToSolution(const path: TPathD); var len: integer; begin if Length(path) < 2 then Exit; len := Length(solution); SetLength(solution, len + 1); solution[len] := path; end; //------------------------------------------------------------------------------ function TPt2Container.StartNewPath(insertBefore: TPt2; xLeft, xRight, y: integer; isHole: Boolean): TPt2; var pt2Left, pt2Right: TPt2; begin inc(xRight); pt2Left := TPt2.Create; pt2Left.owner := self; pt2Left.isStart := not isHole; pt2Left.isHole := isHole; pt2Left.pt := PointD(xLeft, y); pt2Right := TPt2.Create; pt2Right.owner := self; pt2Right.isStart := isHole; pt2Right.isHole := isHole; pt2Right.pt := PointD(xRight, y); pt2Left.nextInPath := pt2Right; pt2Left.prevInPath := pt2Right; pt2Right.nextInPath := pt2Left; pt2Right.prevInPath := pt2Left; pt2Left.nextInRow := pt2Right; pt2Right.prevInRow := pt2Left; if not Assigned(insertBefore) then begin // must be a new rightMost path pt2Left.prevInRow := rightMost; if Assigned(rightMost) then rightMost.nextInRow := pt2Left; pt2Right.nextInRow := nil; rightMost := pt2Right; if not Assigned(leftMostPt) then leftMostPt := pt2Left; end else begin pt2Right.nextInRow := insertBefore; if leftMostPt = insertBefore then begin // must be a new leftMostPt path leftMostPt := pt2Left; pt2Left.prevInRow := nil; end else begin pt2Left.prevInRow := insertBefore.prevInRow; insertBefore.prevInRow.nextInRow := pt2Left; end; insertBefore.prevInRow := pt2Right; end; result := pt2Right.nextInRow; end; //------------------------------------------------------------------------------ procedure TPt2Container.CheckRowEnds(pt2Left, pt2Right: TPt2); begin if pt2Left = leftMostPt then leftMostPt := pt2Right.nextInRow; if pt2Right = rightMost then rightMost := pt2Left.prevInRow; end; //------------------------------------------------------------------------------ function TPt2Container.JoinAscDesc(path1, path2: TPt2): TPt2; begin result := path2.nextInRow; CheckRowEnds(path1, path2); if path2 = path1.prevInPath then begin path1.Free; Exit; end; with path1 do Update(pt.X, pt.Y+1); with path2 do Update(pt.X, pt.Y+1); path1.isStart := false; // remove path1 from double linked list if assigned(path1.nextInRow) then path1.nextInRow.prevInRow := path1.prevInRow; if assigned(path1.prevInRow) then path1.prevInRow.nextInRow := path1.nextInRow; // remove path2 from double linked list if assigned(path2.nextInRow) then path2.nextInRow.prevInRow := path2.prevInRow; if assigned(path2.prevInRow) then path2.prevInRow.nextInRow := path2.nextInRow; path1.prevInPath.nextInPath := path2.nextInPath; path2.nextInPath.prevInPath := path1.prevInPath; path2.nextInPath := path1; path1.prevInPath := path2; end; //------------------------------------------------------------------------------ function TPt2Container.JoinDescAsc(path1, path2: TPt2): TPt2; begin result := path2.nextInRow; CheckRowEnds(path1, path2); if path1 = path2.prevInPath then begin path2.Free; Exit; end; with path1 do Update(pt.X, pt.Y+1); with path2 do Update(pt.X, pt.Y+1); path2.isStart := false; // remove path1 'end' from double linked list if assigned(path1.nextInRow) then path1.nextInRow.prevInRow := path1.prevInRow; if assigned(path1.prevInRow) then path1.prevInRow.nextInRow := path1.nextInRow; // remove path2 'start' from double linked list if assigned(path2.nextInRow) then path2.nextInRow.prevInRow := path2.prevInRow; if assigned(path2.prevInRow) then path2.prevInRow.nextInRow := path2.nextInRow; path1.nextInPath.prevInPath := path2.prevInPath; path2.prevInPath.nextInPath := path1.nextInPath; path1.nextInPath := path2; path2.prevInPath := path1; end; //------------------------------------------------------------------------------ function IsHeadingLeft(current: TPt2; r: integer): Boolean; {$IFDEF INLINE} inline; {$ENDIF} begin Result := r <= current.pt.X; end; //------------------------------------------------------------------------------ procedure TPt2Container.AddRange(var current: TPt2; xLeft, xRight, y: integer); begin if (prevRight > 0) then begin // nb: prevRight always ends a range (whether a hole or an outer) // check if we're about to start a hole if xLeft < current.pt.X then begin //'current' must be descending and hence prevRight->xLeft a hole current := StartNewPath(current, prevRight, xLeft -1, y, true); prevRight := xRight; Exit; // nb: it's possible for multiple holes end; // check if we're passing under a pending join while assigned(current) and assigned(current.nextInRow) and (prevRight > current.nextInRow.pt.X) do begin // Assert(not current.IsAscending, 'oops!'); // Assert(current.nextInRow.IsAscending, 'oops!'); current := JoinDescAsc(current, current.nextInRow); end; // check again for a new hole if (xLeft < current.pt.X) then begin current := StartNewPath(current, prevRight, xLeft -1, y, true); prevRight := xRight; Exit; end; current.Update(prevRight, y); current := current.nextInRow; prevRight := 0; end; // check if we're passing under a pending join while assigned(current) and assigned(current.nextInRow) and (xLeft > current.nextInRow.pt.X) do current := JoinAscDesc(current, current.nextInRow); if not assigned(current) or (xRight < current.pt.X) then begin StartNewPath(current, xLeft, xRight -1, y, false); // nb: current remains unchanged end else begin //'range' must somewhat overlap one or more paths above if IsHeadingLeft(current, xRight) then begin if current.isHole then begin current.Update(xLeft, y); current := current.nextInRow; end; current.Update(xRight, y); current.Update(xLeft, y); if current.IsAscending then prevRight := xRight else prevRight := 0; current := current.nextInRow; end else begin current.Update(xLeft, y); current := current.nextInRow; prevRight := xRight; end; end end; //------------------------------------------------------------------------------ function VectorizeMask(const mask: TArrayOfByte; maskWidth: integer): TPathsD; var i,j, len, height, blockStart: integer; current: TPt2; ba: PByteArray; pt2Container: TPt2Container; begin Result := nil; len := Length(mask); if (len = 0) or (maskWidth = 0) or (len mod maskWidth <> 0) then Exit; height := len div maskWidth; pt2Container := TPt2Container.Create; try for i := 0 to height -1 do begin ba := @mask[maskWidth * i]; blockStart := -2; current := pt2Container.leftMostPt; for j := 0 to maskWidth -1 do begin if (ba[j] > 0) = (blockStart >= 0) then Continue; if blockStart >= 0 then begin pt2Container.AddRange(current, blockStart, j, i); blockStart := -1; end else blockStart := j; end; if blockStart >= 0 then pt2Container.AddRange(current, blockStart, maskWidth, i); if (pt2Container.prevRight > 0) then begin while Assigned(current.nextInRow) and (pt2Container.prevRight >= current.nextInRow.pt.X) do begin if current.isStart then current := pt2Container.JoinAscDesc(current, current.nextInRow) else current := pt2Container.JoinDescAsc(current, current.nextInRow); end; current.Update(pt2Container.prevRight, i); current := current.nextInRow; pt2Container.prevRight := 0; end; while assigned(current) do begin if current.isStart then current := pt2Container.JoinAscDesc(current, current.nextInRow) else current := pt2Container.JoinDescAsc(current, current.nextInRow); end end; with pt2Container do while Assigned(leftMostPt) do if leftMostPt.isStart then JoinAscDesc(leftMostPt, leftMostPt.nextInRow) else JoinDescAsc(leftMostPt, leftMostPt.nextInRow); Result := pt2Container.solution; finally pt2Container.Free; end; end; //------------------------------------------------------------------------------ function Tidy(const poly: TPathD; tolerance: integer): TPathD; var i,j, highI: integer; prev: TPointD; tolSqrd: double; begin Result := nil; highI := High(poly); while (HighI >= 0) and PointsEqual(poly[highI], poly[0]) do dec(highI); if highI < 1 then Exit; tolSqrd := Sqr(Max(2.02, Min(16.1, tolerance + 0.01))); SetLength(Result, highI +1); prev := poly[highI]; Result[0] := prev; Result[1] := poly[0]; j := 1; for i := 1 to highI -1 do begin if ((DistanceSqrd(prev, Result[j]) > tolSqrd) and (DistanceSqrd(Result[j], poly[i]) > tolSqrd)) or (TurnsRight(prev, result[j], poly[i]) or TurnsLeft(result[j], poly[i], poly[i+1])) then begin prev := result[j]; inc(j); end; result[j] := poly[i]; end; if ((DistanceSqrd(prev, Result[j]) > tolSqrd) and (DistanceSqrd(Result[j], Result[0]) > tolSqrd)) or TurnsRight(prev, result[j], Result[0]) or TurnsLeft(result[j], Result[0], Result[1]) then SetLength(Result, j +1) else SetLength(Result, j); if Abs(Area(Result)) < Length(Result) * tolerance/2 then Result := nil; end; //------------------------------------------------------------------------------ function Vectorize(img: TImage32; compareColor: TColor32; compareFunc: TCompareFunction; colorTolerance: Integer; roundingTolerance: integer): TPathsD; var i,j: integer; mask: TArrayOfByte; begin mask := GetBoolMask(img, compareColor, compareFunc, colorTolerance); Result := VectorizeMask(mask, img.Width); j := 0; for i := 0 to high(Result) do begin Result[j] := Tidy(Result[i], roundingTolerance); if Assigned(Result[j]) then inc(j); end; SetLength(Result, j); end; //------------------------------------------------------------------------------ // RamerDouglasPeucker - and support functions //------------------------------------------------------------------------------ procedure RDP(const path: TPathD; startIdx, endIdx: integer; epsilonSqrd: double; var flags: TArrayOfInteger); var i, idx: integer; d, maxD: double; begin idx := 0; maxD := 0; for i := startIdx +1 to endIdx -1 do begin // PerpendicularDistSqrd - avoids expensive Sqrt() d := PerpendicularDistSqrd(path[i], path[startIdx], path[endIdx]); if d <= maxD then Continue; maxD := d; idx := i; end; if maxD < epsilonSqrd then Exit; flags[idx] := 1; if idx > startIdx + 1 then RDP(path, startIdx, idx, epsilonSqrd, flags); if endIdx > idx + 1 then RDP(path, idx, endIdx, epsilonSqrd, flags); end; //------------------------------------------------------------------------------ function RamerDouglasPeucker(const path: TPathD; epsilon: double): TPathD; var i,j, len: integer; buffer: TArrayOfInteger; begin len := length(path); if len < 5 then begin result := Copy(path, 0, len); Exit; end; SetLength(buffer, len); // buffer is zero initialized buffer[0] := 1; buffer[len -1] := 1; RDP(path, 0, len -1, Sqr(epsilon), buffer); j := 0; SetLength(Result, len); for i := 0 to len -1 do if buffer[i] = 1 then begin Result[j] := path[i]; inc(j); end; SetLength(Result, j); end; //------------------------------------------------------------------------------ function RamerDouglasPeucker(const paths: TPathsD; epsilon: double): TPathsD; var i,j, len: integer; begin j := 0; len := length(paths); setLength(Result, len); for i := 0 to len -1 do begin Result[j] := RamerDouglasPeucker(paths[i], epsilon); if Result[j] <> nil then inc(j); end; setLength(Result, j); end; //------------------------------------------------------------------------------ function DotProdVecs(const vec1, vec2: TPointD): double; {$IFDEF INLINE} inline; {$ENDIF} begin result := (vec1.X * vec2.X + vec1.Y * vec2.Y); end; //--------------------------------------------------------------------------- function SmoothToCubicBezier(const path: TPathD; pathIsClosed: Boolean; maxOffset: integer): TPathD; var i, j, len, prev: integer; vec: TPointD; pl: TArrayOfDouble; unitVecs: TPathD; d, angle, d1,d2: double; begin // SmoothToCubicBezier - returns cubic bezier control points Result := nil; len := Length(path); if len < 3 then Exit; SetLength(Result, len *3 +1); prev := len-1; SetLength(pl, len); SetLength(unitVecs, len); pl[0] := Distance(path[prev], path[0]); unitVecs[0] := GetUnitVector(path[prev], path[0]); for i := 0 to len -1 do begin if i = prev then begin j := 0; end else begin j := i +1; pl[j] := Distance(path[i], path[j]); unitVecs[j] := GetUnitVector(path[i], path[j]); end; vec := GetAvgUnitVector(unitVecs[i], unitVecs[j]); angle := arccos(Max(-1,Min(1,(DotProdVecs(unitVecs[i], unitVecs[j]))))); d := abs(Pi-angle)/TwoPi; d1 := pl[i] * d; d2 := pl[j] * d; if maxOffset > 0 then begin d1 := Min(maxOffset, d1); d2 := Min(maxOffset, d2); end; if i = 0 then Result[len*3-1] := OffsetPoint(path[0], -vec.X * d1, -vec.Y * d1) else Result[i*3-1] := OffsetPoint(path[i], -vec.X * d1, -vec.Y * d1); Result[i*3] := path[i]; Result[i*3+1] := OffsetPoint(path[i], vec.X * d2, vec.Y * d2); end; Result[len*3] := path[0]; if pathIsClosed then Exit; Result[1] := Result[0]; dec(len); Result[len*3-1] := Result[len*3]; SetLength(Result, Len*3 +1); end; //------------------------------------------------------------------------------ function HermiteInterpolation(y1, y2, y3, y4: double; mu, tension: double): double; var m0,m1,mu2,mu3: double; a0,a1,a2,a3: double; begin // http://paulbourke.net/miscellaneous/interpolation/ // nb: optional bias toward left or right has been disabled. mu2 := mu * mu; mu3 := mu2 * mu; m0 := (y2-y1)*(1-tension)/2; m0 := m0 + (y3-y2)*(1-tension)/2; m1 := (y3-y2)*(1-tension)/2; m1 := m1 + (y4-y3)*(1-tension)/2; a0 := 2*mu3 - 3*mu2 + 1; a1 := mu3 - 2*mu2 + mu; a2 := mu3 - mu2; a3 := -2*mu3 + 3*mu2; Result := a0*y2+a1*m0+a2*m1+a3*y3; end; //------------------------------------------------------------------------------ function InterpolateY(const y1,y2,y3,y4: double; dx: integer; tension: double): TArrayOfDouble; var i: integer; begin SetLength(Result, dx); if dx = 0 then Exit; Result[0] := y2; for i := 1 to dx-1 do Result[i] := HermiteInterpolation(y1,y2,y3,y4, i/dx, tension); end; //------------------------------------------------------------------------------ function InterpolatePoints(const points: TPathD; tension: integer): TPathD; var i, j, len, len2: integer; p, p2: TPathD; ys: TArrayOfDouble; begin if tension < -1 then tension := -1 else if tension > 1 then tension := 1; Result := nil; len := Length(points); if len < 2 then Exit; SetLength(p, len +2); p[0] := points[0]; p[len+1] := points[len -1]; Move(points[0],p[1], len * SizeOf(TPointD)); for i := 1 to len-1 do begin ys := InterpolateY(p[i-1].Y,p[i].Y,p[i+1].Y,p[i+2].Y, Trunc(p[i+1].X - p[i].X), tension); len2 := Length(ys); SetLength(p2, len2); for j := 0 to len2 -1 do p2[j] := PointD(p[i].X +j, ys[j]); AppendPath(Result, p2); end; AppendPoint(Result, p[len]); end; //------------------------------------------------------------------------------ // GaussianBlur //------------------------------------------------------------------------------ procedure GaussianBlur(img: TImage32; rec: TRect; radius: Integer); var i, w,h, x,y,yy,z: Integer; gaussTable: array [-MaxBlur .. MaxBlur] of Cardinal; wc: TWeightedColor; wca: TArrayOfWeightedColor; row: PColor32Array; wcRow: PWeightedColorArray; begin Types.IntersectRect(rec, rec, img.Bounds); if IsEmptyRect(rec) or (radius < 1) then Exit else if radius > MaxBlur then radius := MaxBlur; for i := 0 to radius do begin gaussTable[i] := Sqr(Radius - i +1); gaussTable[-i] := gaussTable[i]; end; RectWidthHeight(rec, w, h); setLength(wca, w * h); for y := 0 to h -1 do begin row := PColor32Array(@img.Pixels[(y + rec.Top) * img.Width + rec.Left]); wcRow := PWeightedColorArray(@wca[y * w]); for x := 0 to w -1 do for z := max(0, x - radius) to min(img.Width -1, x + radius) do wcRow[x].Add(row[z], gaussTable[x-z]); end; for x := 0 to w -1 do begin for y := 0 to h -1 do begin wc.Reset; yy := max(0, y - radius) * w; for z := max(0, y - radius) to min(h -1, y + radius) do begin wc.Add(wca[x + yy].Color, gaussTable[y-z]); inc(yy, w); end; img.Pixels[x + rec.Left + (y + rec.Top) * img.Width] := wc.Color; end; end; end; //------------------------------------------------------------------------------ // FastGaussian blur - and support functions //------------------------------------------------------------------------------ //http://blog.ivank.net/fastest-gaussian-blur.html //https://www.peterkovesi.com/papers/FastGaussianSmoothing.pdf function BoxesForGauss(stdDev, boxCnt: integer): TArrayOfInteger; var i, wl, wu, m: integer; wIdeal, mIdeal: double; begin SetLength(Result, boxCnt); wIdeal := Sqrt((12*stdDev*stdDev/boxCnt)+1); // Ideal averaging filter width wl := Floor(wIdeal); if not Odd(wl) then dec(wl); mIdeal := (-3*stdDev*stdDev +0.25*boxCnt*wl*wl +boxCnt*wl +0.75*boxCnt)/(wl+1); m := Floor(mIdeal) div 2; // nb: variation on Ivan Kutskir's code. wl := (wl -1) div 2; // It's better to do this here wu := wl+1; // than later in both BoxBlurH & BoxBlurV for i := 0 to boxCnt -1 do if i < m then Result[i] := wl else Result[i] := wu; end; //------------------------------------------------------------------------------ procedure BoxBlurH(var src, dst: TArrayOfColor32; w,h, stdDev: integer); var i,j, ti, li, ri, re, ovr: integer; fv, lv, val: TWeightedColor; rc: TColor32; begin ovr := Max(0, stdDev - w); for i := 0 to h -1 do begin ti := i * w; li := ti; ri := ti +stdDev; re := ti +w -1; // idx of last pixel in row rc := src[re]; // color of last pixel in row fv.Reset; lv.Reset; val.Reset; fv.Add(src[ti], 1); lv.Add(rc, 1); val.Add(src[ti], stdDev +1); for j := 0 to stdDev -1 - ovr do val.Add(src[ti + j]); if ovr > 0 then val.Add(rc, ovr); for j := 0 to stdDev do begin if ri > re then val.Add(rc) else val.Add(src[ri]); inc(ri); val.Subtract(fv); if ti <= re then dst[ti] := val.Color; inc(ti); end; for j := stdDev +1 to w - stdDev -1 do begin if ri <= re then begin val.Add(src[ri]); inc(ri); val.Subtract(src[li]); inc(li); end; dst[ti] := val.Color; inc(ti); end; while ti <= re do begin if ti > re then Break; val.Add(lv); val.Subtract(src[li]); inc(li); dst[ti] := val.Color; inc(ti); end; end; end; //------------------------------------------------------------------------------ procedure BoxBlurV(var src, dst: TArrayOfColor32; w, h, stdDev: integer); var i,j, ti, li, ri, re, ovr: integer; fv, lv, val: TWeightedColor; rc: TColor32; begin ovr := Max(0, stdDev - h); for i := 0 to w -1 do begin ti := i; li := ti; ri := ti + stdDev * w; fv.Reset; lv.Reset; val.Reset; re := ti +w *(h-1); // idx of last pixel in column rc := src[re]; // color of last pixel in column fv.Add(src[ti]); lv.Add(rc, 1); val.Add(src[ti], stdDev +1); for j := 0 to stdDev -1 -ovr do val.Add(src[ti + j *w]); if ovr > 0 then val.Add(rc, ovr); for j := 0 to stdDev do begin if ri > re then val.Add(rc) else val.Add(src[ri]); inc(ri, w); val.Subtract(fv); if ti <= re then dst[ti] := val.Color; inc(ti, w); end; for j := stdDev +1 to h - stdDev -1 do begin if ri <= re then begin val.Add(src[ri]); inc(ri, w); val.Subtract(src[li]); inc(li, w); end; dst[ti] := val.Color; inc(ti, w); end; while ti <= re do begin val.Add(lv); val.Subtract(src[li]); inc(li, w); dst[ti] := val.Color; inc(ti, w); end; end; end; //------------------------------------------------------------------------------ procedure FastGaussianBlur(img: TImage32; const rec: TRect; stdDev: integer; repeats: integer); begin FastGaussianBlur(img, rec, stdDev, stdDev, repeats); end; //------------------------------------------------------------------------------ procedure FastGaussianBlur(img: TImage32; const rec: TRect; stdDevX, stdDevY: integer; repeats: integer); var i,j,len, w,h: integer; rec2: TRect; boxesH: TArrayOfInteger; boxesV: TArrayOfInteger; src, dst: TArrayOfColor32; blurFullImage: Boolean; pSrc, pDst: PColor32; begin if not Assigned(img) then Exit; Types.IntersectRect(rec2, rec, img.Bounds); if IsEmptyRect(rec2) then Exit; blurFullImage := RectsEqual(rec2, img.Bounds); RectWidthHeight(rec2, w, h); if (Min(w, h) < 2) or ((stdDevX < 1) and (stdDevY < 1)) then Exit; len := w * h; SetLength(src, len); SetLength(dst, len); if blurFullImage then begin // copy the entire image into 'dst' Move(img.PixelBase^, dst[0], len * SizeOf(TColor32)); end else begin // copy a rectangular region into 'dst' pSrc := img.PixelRow[rec2.Top]; inc(pSrc, rec2.Left); pDst := @dst[0]; for i := 0 to h -1 do begin Move(pSrc^, pDst^, w * SizeOf(TColor32)); inc(pSrc, img.Width); inc(pDst, w); end; end; // do the blur inc(repeats); // now represents total iterations boxesH := BoxesForGauss(stdDevX, repeats); if stdDevY = stdDevX then boxesV := boxesH else boxesV := BoxesForGauss(stdDevY, repeats); for j := 0 to repeats -1 do begin BoxBlurH(dst, src, w, h, boxesH[j]); BoxBlurV(src, dst, w, h, boxesV[j]); end; // copy dst array back to image rect img.BeginUpdate; try if blurFullImage then begin Move(dst[0], img.PixelBase^, len * SizeOf(TColor32)); end else begin pDst := img.PixelRow[rec2.Top]; inc(pDst, rec2.Left); pSrc := @dst[0]; for i := 0 to h -1 do begin Move(pSrc^, pDst^, w * SizeOf(TColor32)); inc(pSrc, w); inc(pDst, img.Width); end; end; finally img.EndUpdate; end; end; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // CurveFit() support structures and functions //------------------------------------------------------------------------------ //CurveFit: this function is based on - //"An Algorithm for Automatically Fitting Digitized Curves" //by Philip J. Schneider in "Graphics Gems", Academic Press, 1990 //Smooths out many very closely positioned points //tolerance range: 1..10 where 10 == max tolerance. //This function has been archived as I believe that //RamerDouglasPeuker(), GetSmoothPath() and FlattenCBezier() //will usually achieve a better result function Scale(const vec: TPointD; newLen: double): TPointD; {$IFDEF INLINE} inline; {$ENDIF} begin Result.X := vec.X * newLen; Result.Y := vec.Y * newLen; end; //------------------------------------------------------------------------------ function Mul(const vec: TPointD; val: double): TPointD; {$IFDEF INLINE} inline; {$ENDIF} begin Result.X := vec.X * val; Result.Y := vec.Y * val; end; //------------------------------------------------------------------------------ function AddVecs(const vec1, vec2: TPointD): TPointD; {$IFDEF INLINE} inline; {$ENDIF} begin Result.X := vec1.X + vec2.X; Result.Y := vec1.Y + vec2.Y; end; //------------------------------------------------------------------------------ function SubVecs(const vec1, vec2: TPointD): TPointD; {$IFDEF INLINE} inline; {$ENDIF} begin Result.X := vec1.X - vec2.X; Result.Y := vec1.Y - vec2.Y; end; //------------------------------------------------------------------------------ function NormalizeVec(const vec: TPointD): TPointD; {$IFDEF INLINE} inline; {$ENDIF} var len: double; begin len := Sqrt(vec.X * vec.X + vec.Y * vec.Y); if len <> 0 then begin Result.X := vec.X / len; Result.Y := vec.Y / len; end else result := vec; end; //------------------------------------------------------------------------------ function NormalizeTPt(const pt: PPt): TPointD; {$IFDEF INLINE} inline; {$ENDIF} begin with pt^ do if len <> 0 then begin Result.X := vec.X / len; Result.Y := vec.Y / len; end else result := vec; end; //------------------------------------------------------------------------------ function NegateVec(vec: TPointD): TPointD; {$IFDEF INLINE} inline; {$ENDIF} begin Result.X := -vec.X; Result.Y := -vec.Y; end; //------------------------------------------------------------------------------ function B0(u: double): double; {$IFDEF INLINE} inline; {$ENDIF} var tmp: double; begin tmp := 1.0 - u; result := tmp * tmp * tmp; end; //------------------------------------------------------------------------------ function B1(u: double): double; {$IFDEF INLINE} inline; {$ENDIF} var tmp: double; begin tmp := 1.0 - u; result := 3 * u * tmp * tmp; end; //------------------------------------------------------------------------------ function B2(u: double): double; {$IFDEF INLINE} inline; {$ENDIF} begin result := 3 * u * u * (1.0 - u); end; //------------------------------------------------------------------------------ function B3(u: double): double; {$IFDEF INLINE} inline; {$ENDIF} begin result := u * u * u; end; //------------------------------------------------------------------------------ function TFitCurveContainer.AddPt(const pt: TPointD): PPt; begin new(Result); Result.pt := pt; if not assigned(ppts) then begin Result.prev := Result; Result.next := Result; ppts := Result; end else begin Result.prev := ppts.prev; ppts.prev.next := Result; ppts.prev := Result; Result.next := ppts; end; end; //------------------------------------------------------------------------------ procedure TFitCurveContainer.Clear; var p: PPt; begin solution := nil; ppts.prev.next := nil; //break loop while assigned(ppts) do begin p := ppts; ppts := ppts.next; Dispose(p); end; end; //------------------------------------------------------------------------------ function TFitCurveContainer.Count(first, last: PPt): integer; begin if first = last then result := 0 else result := 1; repeat inc(Result); first := first.next; until (first = last); end; //------------------------------------------------------------------------------ function TFitCurveContainer.ComputeLeftTangent(p: PPt): TPointD; begin Result := NormalizeTPt(p); end; //------------------------------------------------------------------------------ function TFitCurveContainer.ComputeRightTangent(p: PPt): TPointD; begin Result := NegateVec(NormalizeTPt(p.prev)); end; //------------------------------------------------------------------------------ function TFitCurveContainer.ComputeCenterTangent(p: PPt): TPointD; var v1, v2: TPointD; begin v1 := SubVecs(p.pt, p.prev.pt); v2 := SubVecs(p.next.pt, p.pt); Result := AddVecs(v1, v2); Result := NormalizeVec(Result); end; //------------------------------------------------------------------------------ function TFitCurveContainer.ChordLengthParameterize( first: PPt; cnt: integer): TArrayOfDouble; var d: double; i: integer; begin SetLength(Result, cnt); Result[0] := 0; d := 0; for i := 1 to cnt -1 do begin d := d + first.len; Result[i] := d; first := first.next; end; for i := 1 to cnt -1 do Result[i] := Result[i] / d; end; //------------------------------------------------------------------------------ function TFitCurveContainer.GenerateBezier(first, last: PPt; cnt: integer; const u: TArrayOfDouble; const firstTan, lastTan: TPointD): TPathD; var i: integer; p: PPt; dist, epsilon: double; v1,v2, tmp: TPointD; a0, a1: TPathD; c: array [0..1, 0..1] of double; x: array [0..1] of double; det_c0_c1, det_c0_x, det_x_c1, alphaL, alphaR: double; begin SetLength(a0, cnt); SetLength(a1, cnt); dist := Distance(first.pt, last.pt); for i := 0 to cnt -1 do begin v1 := Scale(firstTan, B1(u[i])); v2 := Scale(lastTan, B2(u[i])); a0[i] := v1; a1[i] := v2; end; FillChar(c[0][0], 4 * SizeOf(double), 0); FillChar(x[0], 2 * SizeOf(double), 0); p := first; for i := 0 to cnt -1 do begin c[0][0] := c[0][0] + DotProdVecs(a0[i], (a0[i])); c[0][1] := c[0][1] + DotProdVecs(a0[i], (a1[i])); c[1][0] := c[0][1]; c[1][1] := c[1][1] + DotProdVecs(a1[i], (a1[i])); tmp := SubVecs(p.pt, AddVecs(Mul(first.pt, B0(u[i])), AddVecs(Mul(first.pt, B1(u[i])), AddVecs(Mul(last.pt, B2(u[i])), Mul(last.pt, B3(u[i])))))); x[0] := x[0] + DotProdVecs(a0[i], tmp); x[1] := x[1] + DotProdVecs(a1[i], tmp); p := p.next; end; det_c0_c1 := c[0][0] * c[1][1] - c[1][0] * c[0][1]; det_c0_x := c[0][0] * x[1] - c[1][0] * x[0]; det_x_c1 := x[0] * c[1][1] - x[1] * c[0][1]; if det_c0_c1 = 0 then alphaL := 0 else alphaL := det_x_c1 / det_c0_c1; if det_c0_c1 = 0 then alphaR := 0 else alphaR := det_c0_x / det_c0_c1; //check for unlikely fit if (alphaL > dist * 2) then alphaL := 0 else if (alphaR > dist * 2) then alphaR := 0; epsilon := 1.0e-6 * dist; SetLength(Result, 4); Result[0] := first.pt; Result[3] := last.pt; if (alphaL < epsilon) or (alphaR < epsilon) then begin dist := dist / 3; Result[1] := AddVecs(Result[0], Scale(firstTan, dist)); Result[2] := AddVecs(Result[3], Scale(lastTan, dist)); end else begin Result[1] := AddVecs(Result[0], Scale(firstTan, alphaL)); Result[2] := AddVecs(Result[3], Scale(lastTan, alphaR)); end; end; //------------------------------------------------------------------------------ function TFitCurveContainer.Reparameterize(first: PPt; cnt: integer; const u: TArrayOfDouble; const bezier: TPathD): TArrayOfDouble; var i: integer; begin SetLength(Result, cnt); for i := 0 to cnt -1 do begin Result[i] := NewtonRaphsonRootFind(bezier, first.pt, u[i]); first := first.next; end; end; //------------------------------------------------------------------------------ function BezierII(degree: integer; const v: array of TPointD; t: double): TPointD; var i,j: integer; tmp: array[0..3] of TPointD; begin Move(v[0], tmp[0], degree * sizeOf(TPointD)); for i := 1 to degree do for j := 0 to degree - i do begin tmp[j].x := (1.0 - t) * tmp[j].x + t * tmp[j+1].x; tmp[j].y := (1.0 - t) * tmp[j].y + t * tmp[j+1].y; end; Result := tmp[0]; end; //------------------------------------------------------------------------------ function TFitCurveContainer.ComputeMaxErrorSqrd(first, last: PPt; const bezier: TPathD; const u: TArrayOfDouble; out SplitPoint: PPt): double; var i: integer; distSqrd: double; pt: TPointD; p: PPt; begin Result := 0; i := 1; SplitPoint := first.next; p := first.next; while p <> last do begin pt := BezierII(3, bezier, u[i]); distSqrd := DistanceSqrd(pt, p.pt); if (distSqrd >= Result) then begin Result := distSqrd; SplitPoint := p; end; inc(i); p := p.next; end; end; //------------------------------------------------------------------------------ function TFitCurveContainer.NewtonRaphsonRootFind(const q: TPathD; const pt: TPointD; u: double): double; var numerator, denominator: double; qu, q1u, q2u: TPointD; q1: array[0..2] of TPointD; q2: array[0..1] of TPointD; begin q1[0].x := (q[1].x - q[0].x) * 3.0; q1[0].y := (q[1].y - q[0].y) * 3.0; q1[1].x := (q[2].x - q[1].x) * 3.0; q1[1].y := (q[2].y - q[1].y) * 3.0; q1[2].x := (q[3].x - q[2].x) * 3.0; q1[2].y := (q[3].y - q[2].y) * 3.0; q2[0].x := (q1[1].x - q1[0].x) * 2.0; q2[0].y := (q1[1].y - q1[0].y) * 2.0; q2[1].x := (q1[2].x - q1[1].x) * 2.0; q2[1].y := (q1[2].y - q1[1].y) * 2.0; qu := BezierII(3, q, u); q1u := BezierII(2, q1, u); q2u := BezierII(1, q2, u); numerator := (qu.x - pt.x) * (q1u.x) + (qu.y - pt.y) * (q1u.y); denominator := (q1u.x) * (q1u.x) + (q1u.y) * (q1u.y) + (qu.x - pt.x) * (q2u.x) + (qu.y - pt.y) * (q2u.y); if (denominator = 0) then Result := u else Result := u - (numerator / denominator); end; //------------------------------------------------------------------------------ function TFitCurveContainer.FitCubic(first, last: PPt; firstTan, lastTan: TPointD): Boolean; var i, cnt: integer; splitPoint: PPt; centerTan: TPointD; bezier: TPathD; clps, uPrime: TArrayOfDouble; maxErrorSqrd: double; const maxRetries = 4; begin Result := true; cnt := Count(first, last); if cnt = 2 then begin SetLength(bezier, 4); bezier[0] := first.pt; bezier[3] := last.pt; bezier[1] := bezier[0]; bezier[2] := bezier[3]; AppendSolution(bezier); Exit; end else if cnt = 3 then begin if TurnsLeft(first.prev.pt, first.pt, first.next.pt) = TurnsLeft(first.pt, first.next.pt, last.pt) then firstTan := ComputeCenterTangent(first); if TurnsLeft(last.prev.pt, last.pt, last.next.pt) = TurnsLeft(first.pt, first.next.pt, last.pt) then lastTan := NegateVec(ComputeCenterTangent(last)); end; clps := ChordLengthParameterize(first, cnt); bezier := GenerateBezier(first, last, cnt, clps, firstTan, lastTan); maxErrorSqrd := ComputeMaxErrorSqrd(first, last, bezier, clps, splitPoint); if (maxErrorSqrd < tolSqrd) then begin AppendSolution(bezier); Exit; end; if (maxErrorSqrd < tolSqrd * 4) then //close enough to try again begin for i := 1 to maxRetries do begin uPrime := Reparameterize(first, cnt, clps, bezier); bezier := GenerateBezier(first, last, cnt, uPrime, firstTan, lastTan); maxErrorSqrd := ComputeMaxErrorSqrd(first, last, bezier, uPrime, splitPoint); if (maxErrorSqrd < tolSqrd) then begin AppendSolution(bezier); Exit; end; clps := uPrime; end; end; //We need to break the curve because it's too complex for a single Bezier. //If we're changing direction then make this a 'hard' break (see below). if TurnsLeft(splitPoint.prev.prev.pt, splitPoint.prev.pt, splitPoint.pt) <> TurnsLeft(splitPoint.prev.pt, splitPoint.pt, splitPoint.next.pt) then begin centerTan := ComputeRightTangent(splitPoint); FitCubic(first, splitPoint, firstTan, centerTan); centerTan := ComputeLeftTangent(splitPoint); FitCubic(splitPoint, last, centerTan, lastTan); end else begin centerTan := ComputeCenterTangent(splitPoint); FitCubic(first, splitPoint, firstTan, NegateVec(centerTan)); FitCubic(splitPoint, last, centerTan, lastTan); end; end; //------------------------------------------------------------------------------ function HardBreakCheck(ppt: PPt; compareLen: double): Boolean; var q: double; const longLen = 15; begin //A 'break' means starting a new Bezier. A 'hard' break avoids smoothing //whereas a 'soft' break will still be smoothed. There is as much art as //science in determining where to smooth and where not to. For example, //long edges should generally remain straight but how long does an edge //have to be to be considered a 'long' edge? if (ppt.prev.len * 4 < ppt.len) or (ppt.len * 4 < ppt.prev.len) then begin //We'll hard break whenever there's significant asymmetry between //segment lengths because GenerateBezier() will perform poorly. result := true; end else if ((ppt.prev.len > longLen) and (ppt.len > longLen)) then begin //hard break long segments only when turning by more than ~45 degrees q := (Sqr(ppt.prev.len) + Sqr(ppt.len) - DistanceSqrd(ppt.prev.pt, ppt.next.pt)) / (2 * ppt.prev.len * ppt.len); //Cosine Rule. result := (1 - abs(q)) > 0.3; end else if ((TurnsLeft(ppt.prev.prev.pt, ppt.prev.pt, ppt.pt) = TurnsRight(ppt.prev.pt, ppt.pt, ppt.next.pt)) and (ppt.prev.len > compareLen) and (ppt.len > compareLen)) then begin //we'll also hard break whenever there's a significant inflection point result := true; end else begin //Finally, we'll also force a 'hard' break when there's a significant bend. //Again uses the Cosine Rule. q :=(Sqr(ppt.prev.len) + Sqr(ppt.len) - DistanceSqrd(ppt.prev.pt, ppt.next.pt)) / (2 * ppt.prev.len * ppt.len); Result := (q > -0.2); //ie more than 90% end; end; //------------------------------------------------------------------------------ function TFitCurveContainer.FitCurve(const path: TPathD; closed: Boolean; tolerance: double; minSegLength: double): TPathD; var i, highI: integer; d: double; p, p2, pEnd: PPt; begin //tolerance: specifies the maximum allowed variance between the existing //vertices and the new Bezier curves. More tolerance will produce //fewer Beziers and simpler paths, but at the cost of less precison. tolSqrd := Sqr(Max(1, Min(10, tolerance))); //range 1..10 //minSegLength: Typically when vectorizing raster images, the produced //vector paths will have many series of axis aligned segments that trace //pixel boundaries. These paths will also contain many 1 unit segments at //right angles to adjacent segments. Importantly, these very short segments //will cause artifacts in the solution unless they are trimmed. highI := High(path); if closed then while (highI > 0) and (Distance(path[highI], path[0]) < minSegLength) do dec(highI); p := AddPt(path[0]); for i := 1 to highI do begin d := Distance(p.pt, path[i]); //skip line segments with lengths less than 'minSegLength' if d < minSegLength then Continue; p := AddPt(path[i]); p.prev.len := d; p.prev.vec := SubVecs(p.pt, p.prev.pt); end; p.len := Distance(ppts.pt, p.pt); p.vec := SubVecs(p.next.pt, p.pt); p := ppts; if (p.next = p) or (closed and (p.next = p.prev)) then begin Clear; result := nil; Exit; end; //for closed paths, find a good starting point if closed then begin repeat if HardBreakCheck(p, tolerance) then break; p := p.next; until p = ppts; pEnd := p; end else pEnd := ppts.prev; p2 := p.next; repeat if HardBreakCheck(p2, tolerance) then begin FitCubic(p, p2, ComputeLeftTangent(p), ComputeRightTangent(p2)); p := p2; end; p2 := p2.next; until (p2 = pEnd); FitCubic(p, p2, ComputeLeftTangent(p), ComputeRightTangent(p2)); Result := solution; Clear; end; //------------------------------------------------------------------------------ procedure TFitCurveContainer.AppendSolution(const bezier: TPathD); var i, len: integer; begin len := Length(solution); if len > 0 then begin SetLength(solution, len + 3); for i := 0 to 2 do solution[len +i] := bezier[i +1]; end else solution := bezier; end; //------------------------------------------------------------------------------ function CurveFit(const path: TPathD; closed: Boolean; tolerance: double; minSegLength: double): TPathD; var paths, solution: TPathsD; begin SetLength(paths, 1); paths[0] := path; solution := CurveFit(paths, closed, tolerance, minSegLength); if solution <> nil then Result := solution[0]; end; //------------------------------------------------------------------------------ function CurveFit(const paths: TPathsD; closed: Boolean; tolerance: double; minSegLength: double): TPathsD; var i,j, len: integer; begin j := 0; len := Length(paths); SetLength(Result, len); with TFitCurveContainer.Create do try for i := 0 to len -1 do if (paths[i] <> nil) and (Abs(Area(paths[i])) > Sqr(tolerance)) then begin Result[j] := FitCurve(paths[i], closed, tolerance, minSegLength); inc(j); end; finally Free; end; SetLength(Result, j); end; //------------------------------------------------------------------------------ end. doublecmd-1.1.22/components/Image32/source/Img32.Fmt.SVG.pas0000644000175000001440000003355014743153644022241 0ustar alexxusersunit Img32.Fmt.SVG; (******************************************************************************* * Author : Angus Johnson * * Version : 4.3.1 * * Date : 5 October 2022 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2019-2022 * * Purpose : SVG file format extension for TImage32 * * License : http://www.boost.org/LICENSE_1_0.txt * *******************************************************************************) interface {$I Img32.inc} uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} SysUtils, Classes, Math, {$IFDEF XPLAT_GENERICS} Generics.Collections, Generics.Defaults, {$ENDIF} Img32, Img32.Vector, Img32.SVG.Reader; type TImageFormat_SVG = class(TImageFormat) public class function IsValidImageStream(stream: TStream): Boolean; override; function LoadFromStream(stream: TStream; img32: TImage32): Boolean; override; procedure SaveToStream(stream: TStream; img32: TImage32); override; class function CanCopyToClipboard: Boolean; override; class function CopyToClipboard(img32: TImage32): Boolean; override; class function CanPasteFromClipboard: Boolean; override; class function PasteFromClipboard(img32: TImage32): Boolean; override; end; TSvgListObject = class xml : string; name : string; end; TSvgImageList32 = class(TInterfacedObj, INotifySender) private fReader : TSvgReader; {$IFDEF XPLAT_GENERICS} fList : TList; {$ELSE} fList : TList; {$ENDIF} fDefWidth : integer; fDefHeight : integer; fRecipientList : TRecipients; fUpdateCnt : integer; {$IFDEF MSWINDOWS} fResName : string; procedure SetResName(const resName: string); {$ENDIF} procedure SetDefWidth(value: integer); procedure SetDefHeight(value: integer); protected procedure Changed; virtual; procedure BeginUpdate; procedure EndUpdate; procedure NotifyRecipients(notifyFlag: TImg32Notification); public constructor Create; destructor Destroy; override; procedure Clear; function Count: integer; function Find(const aName: string): integer; procedure AddRecipient(recipient: INotifyRecipient); procedure DeleteRecipient(recipient: INotifyRecipient); function CreateImage(index: integer): TImage32; procedure GetImage(index: integer; image: TImage32); overload; procedure GetImage(index: integer; image: TImage32; out aName: string); overload; procedure Add(const aName, xml: string); procedure AddFromFile(const aName, filename: string); procedure AddFromResource(const aName, resName: string; resType: PChar); procedure Insert(index: integer; const name, xml: string); procedure Move(currentIndex, newIndex: integer); procedure Delete(index: integer); property DefaultWidth: integer read fDefWidth write SetDefWidth; property DefaultHeight: integer read fDefHeight write SetDefHeight; {$IFDEF MSWINDOWS} property ResourceName: string read fResName write SetResName; {$ENDIF} end; var defaultSvgWidth: integer = 800; defaultSvgHeight: integer = 600; implementation //------------------------------------------------------------------------------ // Three routines used to enumerate a resource type //------------------------------------------------------------------------------ function Is_IntResource(lpszType: PChar): Boolean; begin Result := NativeUInt(lpszType) shr 16 = 0; end; //------------------------------------------------------------------------------ function ResourceNameToString(lpszName: PChar): string; begin if Is_IntResource(lpszName) then Result := '#' + IntToStr(NativeUInt(lpszName)) else Result := lpszName; end; //------------------------------------------------------------------------------ function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar; lParam: NativeInt): Boolean; stdcall; var n: string; begin n:= ResourceNameToString(lpszName); TSvgImageList32(lParam).AddFromResource(n, n, lpszType); Result := true; end; //------------------------------------------------------------------------------ // TSvgImageList32 //------------------------------------------------------------------------------ constructor TSvgImageList32.Create; begin fReader := TSvgReader.Create; {$IFDEF XPLAT_GENERICS} fList := TList.Create; {$ELSE} fList := TList.Create; {$ENDIF} end; //------------------------------------------------------------------------------ destructor TSvgImageList32.Destroy; begin NotifyRecipients(inDestroy); Clear; fList.Free; fReader.Free; inherited; end; //------------------------------------------------------------------------------ {$IFDEF MSWINDOWS} procedure TSvgImageList32.SetResName(const resName: string); begin if fResName = resName then Exit; fResName := resName; BeginUpdate; try Clear; EnumResourceNames(HInstance, PChar(resName), @EnumResNameProc, lParam(self)); finally EndUpdate; end; end; //------------------------------------------------------------------------------ {$ENDIF} function TSvgImageList32.Count: integer; begin result := fList.Count; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.Clear; var i: integer; begin for i := 0 to fList.Count -1 do TSvgListObject(fList[i]).Free; fList.Clear; Changed; end; //------------------------------------------------------------------------------ function TSvgImageList32.Find(const aName: string): integer; var i: integer; begin for i := 0 to fList.Count -1 do with TSvgListObject(fList[i]) do if SameText(name, aName) then begin Result := i; Exit; end; Result := -1; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.GetImage(index: integer; image: TImage32; out aName: string); begin if not Assigned(image) or (index < 0) or (index >= count) then Exit; if image.IsEmpty then image.SetSize(fDefWidth, fDefHeight); with TSvgListObject(fList[index]) do begin fReader.LoadFromString(xml); aName := name; end; fReader.DrawImage(image, true); end; //------------------------------------------------------------------------------ function TSvgImageList32.CreateImage(index: integer): TImage32; begin Result := TImage32.Create(DefaultWidth, DefaultHeight); GetImage(index, Result); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.GetImage(index: integer; image: TImage32); var dummy: string; begin GetImage(index, image, dummy); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.Add(const aName, xml: string); begin Insert(count, aName, xml); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.AddFromFile(const aName, filename: string); begin if not FileExists(filename) then Exit; with TStringList.Create do try LoadFromFile(filename); Self.Insert(Self.Count, aName, Text); finally Free; end; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.AddFromResource(const aName, resName: string; resType: PChar); var rs: TResourceStream; ansi: AnsiString; begin rs := TResourceStream.Create(hInstance, resName, resType); try SetLength(ansi, rs.Size); rs.Read(ansi[1], rs.Size); Self.Insert(Self.Count, aName, string(ansi)); finally rs.Free; end; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.Insert(index: integer; const name, xml: string); var lo: TSvgListObject; begin if index < 0 then index := 0 else if index > Count then index := Count; lo := TSvgListObject.Create; lo.name := name; lo.xml := xml; fList.Insert(index, lo); Changed; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.Move(currentIndex, newIndex: integer); begin fList.Move(currentIndex, newIndex); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.Delete(index: integer); begin TSvgListObject(fList[index]).Free; fList.Delete(index); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.BeginUpdate; begin inc(fUpdateCnt); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.EndUpdate; begin dec(fUpdateCnt); if fUpdateCnt = 0 then Changed; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.Changed; begin if (fUpdateCnt = 0) then NotifyRecipients(inStateChange); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.SetDefWidth(value: integer); begin if fDefWidth = value then Exit; fDefWidth := value; Changed; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.SetDefHeight(value: integer); begin if fDefHeight = value then Exit; fDefHeight := value; Changed; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.AddRecipient(recipient: INotifyRecipient); var len: integer; begin len := Length(fRecipientList); SetLength(fRecipientList, len+1); fRecipientList[len] := Recipient; end; //------------------------------------------------------------------------------ procedure TSvgImageList32.DeleteRecipient(recipient: INotifyRecipient); var i, highI: integer; begin highI := High(fRecipientList); i := highI; while (i >= 0) and (fRecipientList[i] <> Recipient) do dec(i); if i < 0 then Exit; if i < highI then System.Move(fRecipientList[i+1], fRecipientList[i], (highI - i) * SizeOf(INotifyRecipient)); SetLength(fRecipientList, highI); end; //------------------------------------------------------------------------------ procedure TSvgImageList32.NotifyRecipients(notifyFlag: TImg32Notification); var i: integer; begin if fUpdateCnt > 0 then Exit; for i := High(fRecipientList) downto 0 do try //when destroying in a finalization section //it's possible for recipients to have been destroyed //without their destructors being called. fRecipientList[i].ReceiveNotification(self, notifyFlag); except end; end; //------------------------------------------------------------------------------ // Loading (reading) SVG images from file ... //------------------------------------------------------------------------------ function TImageFormat_SVG.LoadFromStream(stream: TStream; img32: TImage32): Boolean; var r: TRectWH; w,h, sx,sy: double; begin with TSvgReader.Create do try Result := LoadFromStream(stream); if not Result then Exit; r := GetViewbox(img32.Width, img32.Height); img32.BeginUpdate; try if img32.IsEmpty and not r.IsEmpty then img32.SetSize(Round(r.Width), Round(r.Height)) else if not r.IsEmpty then begin //then scale the SVG to fit image w := r.Width; h := r.Height; sx := img32.Width / w; sy := img32.Height / h; if sy < sx then sx := sy; if not(SameValue(sx, 1, 0.00001)) then begin w := w * sx; h := h * sx; end; img32.SetSize(Round(w), Round(h)); end else img32.SetSize(defaultSvgWidth, defaultSvgHeight); //draw the SVG image to fit inside the canvas DrawImage(img32, True); finally img32.EndUpdate; end; finally Free; end; end; //------------------------------------------------------------------------------ // Saving (writing) SVG images to file (not currently implemented) ... //------------------------------------------------------------------------------ class function TImageFormat_SVG.IsValidImageStream(stream: TStream): Boolean; var i, savedPos, len: integer; buff: array [1..1024] of AnsiChar; begin Result := false; savedPos := stream.Position; len := Min(1024, stream.Size - savedPos); stream.Read(buff[1], len); stream.Position := savedPos; for i := 1 to len -4 do begin if buff[i] < #9 then Exit else if (buff[i] = '<') and (buff[i +1] = 's') and (buff[i +2] = 'v') and (buff[i +3] = 'g') then begin Result := true; break; end; end; end; //------------------------------------------------------------------------------ procedure TImageFormat_SVG.SaveToStream(stream: TStream; img32: TImage32); begin //not enabled end; //------------------------------------------------------------------------------ class function TImageFormat_SVG.CanCopyToClipboard: Boolean; begin Result := false; end; //------------------------------------------------------------------------------ class function TImageFormat_SVG.CopyToClipboard(img32: TImage32): Boolean; begin Result := false; end; //------------------------------------------------------------------------------ class function TImageFormat_SVG.CanPasteFromClipboard: Boolean; begin Result := false; end; //------------------------------------------------------------------------------ class function TImageFormat_SVG.PasteFromClipboard(img32: TImage32): Boolean; begin Result := false; end; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ initialization TImage32.RegisterImageFormatClass('SVG', TImageFormat_SVG, cpLow); end. doublecmd-1.1.22/components/Image32/source/Img32.Resamplers.pas0000644000175000001440000002747414743153644023202 0ustar alexxusersunit Img32.Resamplers; (******************************************************************************* * Author : Angus Johnson * * Version : 4.3 * * Date : 27 September 2022 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2019-2021 * * Purpose : For image transformations (scaling, rotating etc.) * * License : http://www.boost.org/LICENSE_1_0.txt * *******************************************************************************) interface {$I Img32.inc} uses SysUtils, Classes, Img32; //BoxDownSampling: As the name implies, this routine is only intended for //image down-sampling (ie when shrinking images) where it generally performs //better than other resamplers which tend to lose too much detail. However, //because this routine is inferior to other resamplers when performing other //transformations (ie when enlarging, rotating, and skewing images), it's not //intended as a general purpose resampler. procedure BoxDownSampling(Image: TImage32; newWidth, newHeight: Integer); (* The following functions are registered in the initialization section below function NearestResampler(img: TImage32; x256, y256: Integer): TColor32; function BilinearResample(img: TImage32; x256, y256: Integer): TColor32; function BicubicResample(img: TImage32; x256, y256: Integer): TColor32; *) implementation uses Img32.Transform; //------------------------------------------------------------------------------ // NearestNeighbor resampler //------------------------------------------------------------------------------ function NearestResampler(img: TImage32; x256, y256: Integer): TColor32; begin if (x256 < -$7f) then begin Result := clNone32; Exit; end; if (y256 < -$7f) then begin Result := clNone32; Exit; end; if (x256 and $FF > $7F) then inc(x256, $100); x256 := x256 shr 8; if y256 and $FF > $7F then inc(y256, $100); y256 := y256 shr 8; if (x256 < 0) or (x256 >= img.Width) or (y256 < 0) or (y256 >= img.Height) then Result := clNone32 else Result := img.Pixels[y256 * img.Width + x256]; end; //------------------------------------------------------------------------------ // BiLinear resampler //------------------------------------------------------------------------------ function BilinearResample(img: TImage32; x256, y256: Integer): TColor32; var xi,yi, weight: Integer; iw, ih: integer; pixels: TArrayOfColor32; color: TWeightedColor; xf, yf: cardinal; begin iw := img.Width; ih := img.Height; pixels := img.Pixels; if (x256 <= -$100) or (x256 >= iw *$100) or (y256 <= -$100) or (y256 >= ih *$100) then begin result := clNone32; Exit; end; if x256 < 0 then xi := -1 else xi := x256 shr 8; if y256 < 0 then yi := -1 else yi := y256 shr 8; xf := x256 and $FF; yf := y256 and $FF; color.Reset; weight := (($100 - xf) * ($100 - yf)) shr 8; //top-left if (xi < 0) or (yi < 0) then color.AddWeight(weight) else color.Add(pixels[xi + yi * iw], weight); weight := (xf * ($100 - yf)) shr 8; //top-right if ((xi+1) >= iw) or (yi < 0) then color.AddWeight(weight) else color.Add(pixels[(xi+1) + yi * iw], weight); weight := (($100 - xf) * yf) shr 8; //bottom-left if (xi < 0) or ((yi+1) >= ih) then color.AddWeight(weight) else color.Add(pixels[(xi) + (yi+1) * iw], weight); weight := (xf * yf) shr 8; //bottom-right if (xi + 1 >= iw) or (yi + 1 >= ih) then color.AddWeight(weight) else color.Add(pixels[(xi+1) + (yi+1) * iw], weight); Result := color.Color; end; //------------------------------------------------------------------------------ // BiCubic resampler //------------------------------------------------------------------------------ type TBiCubicEdgeAdjust = (eaNone, eaOne, eaTwo, eaThree, eaFour); var byteFrac: array [0..255] of double; byteFracSq: array [0..255] of double; byteFracCubed: array [0..255] of double; //------------------------------------------------------------------------------ function CubicHermite(aclr: PColor32; t: Byte; bce: TBiCubicEdgeAdjust): TColor32; var a,b,c,d: PARGB; q: TARGB; aa, bb, cc: integer; t1, t2, t3: double; res: TARGB absolute Result; const clTrans: TColor32 = clNone32; begin case bce of eaOne: begin a := @clTrans; b := @clTrans; c := PARGB(aclr); Inc(aclr); d := PARGB(aclr); end; eaTwo: begin a := PARGB(aclr); b := a; Inc(aclr); c := PARGB(aclr); Inc(aclr); d := PARGB(aclr); end; eaThree: begin a := PARGB(aclr); Inc(aclr); b := PARGB(aclr); Inc(aclr); c := PARGB(aclr); d := c; end; eaFour: begin a := PARGB(aclr); Inc(aclr); b := PARGB(aclr); c := @clTrans; d := @clTrans; end; else begin a := PARGB(aclr); Inc(aclr); b := PARGB(aclr); Inc(aclr); c := PARGB(aclr); Inc(aclr); d := PARGB(aclr); end; end; if (b.A = 0) and (c.A = 0) then begin result := clNone32; Exit; end else if b.A = 0 then begin q := c^; q.A := 0; b := @q; end; if c.A = 0 then begin q := b^; q.A := 0; c := @q; end; t1 := byteFrac[t]; t2 := byteFracSq[t]; t3 := byteFracCubed[t]; aa := Integer(-a.A + 3*b.A - 3*c.A + d.A) div 2; bb := Integer(2*a.A - 5*b.A + 4*c.A - d.A) div 2; cc := Integer(-a.A + c.A) div 2; Res.A := ClampByte(aa*t3 + bb*t2 + cc*t1 + b.A); aa := Integer(-a.R + 3*b.R - 3*c.R + d.R) div 2; bb := Integer(2*a.R - 5*b.R + 4*c.R - d.R) div 2; cc := Integer(-a.R + c.R) div 2; Res.R := ClampByte(aa*t3 + bb*t2 + cc*t1 + b.R); aa := Integer(-a.G + 3*b.G - 3*c.G + d.G) div 2; bb := Integer(2*a.G - 5*b.G + 4*c.G - d.G) div 2; cc := Integer(-a.G + c.G) div 2; Res.G := ClampByte(aa*t3 + bb*t2 + cc*t1 + b.G); aa := Integer(-a.B + 3*b.B - 3*c.B + d.B) div 2; bb := Integer(2*a.B - 5*b.B + 4*c.B - d.B) div 2; cc := Integer(-a.B + c.B) div 2; Res.B := ClampByte(aa*t3 + bb*t2 + cc*t1 + b.B); end; //------------------------------------------------------------------------------ function BicubicResample(img: TImage32; x256, y256: Integer): TColor32; var i, dx,dy, pi, iw, w,h: Integer; c: array[0..3] of TColor32; x, y: Integer; bceX, bceY: TBiCubicEdgeAdjust; begin Result := clNone32; iw := img.Width; w := iw -1; h := img.Height -1; x := Abs(x256) shr 8; y := Abs(y256) shr 8; if (x256 < -$FF) or (x > w) or (y256 < -$FF) or (y > h) then Exit; if (x256 < 0) then bceX := eaOne else if (x = 0) then bceX := eaTwo else if (x256 > w shl 8) then bceX := eaFour else if (x256 > (w -1) shl 8) then bceX := eaThree else bceX := eaNone; if (bceX = eaOne) or (bceX = eaTwo) then dx := 1 else dx := 0; if (y256 < 0) then bceY := eaOne else if y = 0 then bceY := eaTwo else if y = h -1 then bceY := eaThree else if y = h then bceY := eaFour else bceY := eaNone; if (bceY = eaOne) or (bceY = eaTwo) then dy := 1 else dy := 0; pi := (y -1 +dy) * iw + (x -1 + dx); if bceY = eaFour then dx := 2 else if bceY = eaThree then dx := 1 else dx := 0; for i := dy to 3 -dx do begin c[i] := CubicHermite(@img.Pixels[pi], x256 and $FF, bceX); inc(pi, iw); end; Result := CubicHermite(@c[dy], y256 and $FF, bceY); end; //------------------------------------------------------------------------------ // BoxDownSampling and related functions //------------------------------------------------------------------------------ function GetWeightedColor(const srcBits: TArrayOfColor32; x256, y256, xx256, yy256, maxX: Integer): TColor32; var i, j, xi, yi, xxi, yyi, weight: Integer; xf, yf, xxf, yyf: cardinal; color: TWeightedColor; begin //This function performs 'box sampling' and differs from GetWeightedPixel //(bilinear resampling) in one important aspect - it accommodates weighting //any number of pixels (rather than just adjacent pixels) and this produces //better image quality when significantly downsizing. //Note: there's no range checking here, so the precondition is that the //supplied boundary values are within the bounds of the srcBits array. color.Reset; xi := x256 shr 8; xf := x256 and $FF; yi := y256 shr 8; yf := y256 and $FF; xxi := xx256 shr 8; xxf := xx256 and $FF; yyi := yy256 shr 8; yyf := yy256 and $FF; //1. average the corners ... weight := (($100 - xf) * ($100 - yf)) shr 8; color.Add(srcBits[xi + yi * maxX], weight); weight := (xxf * ($100 - yf)) shr 8; if (weight <> 0) then color.Add(srcBits[xxi + yi * maxX], weight); weight := (($100 - xf) * yyf) shr 8; if (weight <> 0) then color.Add(srcBits[xi + yyi * maxX], weight); weight := (xxf * yyf) shr 8; if (weight <> 0) then color.Add(srcBits[xxi + yyi * maxX], weight); //2. average the edges if (yi +1 < yyi) then begin xf := $100 - xf; for i := yi + 1 to yyi - 1 do color.Add(srcBits[xi + i * maxX], xf); if (xxf <> 0) then for i := yi + 1 to yyi - 1 do color.Add(srcBits[xxi + i * maxX], xxf); end; if (xi + 1 < xxi) then begin yf := $100 - yf; for i := xi + 1 to xxi - 1 do color.Add(srcBits[i + yi * maxX], yf); if (yyf <> 0) then for i := xi + 1 to xxi - 1 do color.Add(srcBits[i + yyi * maxX], yyf); end; //3. average the non-fractional pixel 'internals' ... for i := xi + 1 to xxi - 1 do for j := yi + 1 to yyi - 1 do color.Add(srcBits[i + j * maxX], $100); //4. finally get the weighted color ... if color.AddCount = 0 then Result := srcBits[xi + yi * maxX] else Result := color.Color; end; //------------------------------------------------------------------------------ procedure BoxDownSampling(Image: TImage32; newWidth, newHeight: Integer); var x,y, x256,y256,xx256,yy256: Integer; sx,sy: double; tmp: TArrayOfColor32; pc: PColor32; scaledX: array of Integer; begin sx := Image.Width/newWidth * 256; sy := Image.Height/newHeight * 256; SetLength(tmp, newWidth * newHeight); SetLength(scaledX, newWidth +1); //+1 for fractional overrun for x := 0 to newWidth -1 do scaledX[x] := Round((x+1) * sx); y256 := 0; pc := @tmp[0]; for y := 0 to newHeight - 1 do begin x256 := 0; yy256 := Round((y+1) * sy); for x := 0 to newWidth - 1 do begin xx256 := scaledX[x]; pc^ := GetWeightedColor(Image.Pixels, x256, y256, xx256, yy256, Image.Width); x256 := xx256; inc(pc); end; y256 := yy256; end; Image.BeginUpdate; Image.SetSize(newWidth, newHeight); Move(tmp[0], Image.Pixels[0], newWidth * newHeight * SizeOf(TColor32)); Image.EndUpdate; end; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ procedure InitByteExponents; var i: integer; const inv255 : double = 1/255; inv255sqrd : double = 1/(255*255); inv255cubed: double = 1/(255*255*255); begin for i := 0 to 255 do begin byteFrac[i] := i *inv255; byteFracSq[i] := i*i *inv255sqrd; byteFracCubed[i] := i*i*i *inv255cubed; end; end; //------------------------------------------------------------------------------ initialization InitByteExponents; rNearestResampler := RegisterResampler(NearestResampler, 'NearestNeighbor'); rBilinearResampler := RegisterResampler(BilinearResample, 'Bilinear'); rBicubicResampler := RegisterResampler(BicubicResample, 'HermiteBicubic'); DefaultResampler := rBilinearResampler; end. doublecmd-1.1.22/components/Image32/source/Img32.SVG.Core.pas0000644000175000001440000017221714743153644022407 0ustar alexxusersunit Img32.SVG.Core; (******************************************************************************* * Author : Angus Johnson * * Version : 4.3 * * Date : 27 September 2022 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2019-2022 * * * * Purpose : Essential structures and functions to read SVG files * * * * License : Use, modification & distribution is subject to * * Boost Software License Ver 1 * * http://www.boost.org/LICENSE_1_0.txt * *******************************************************************************) interface {$I Img32.inc} uses SysUtils, Classes, Types, Math, {$IFDEF XPLAT_GENERICS} Generics.Collections, Generics.Defaults,{$ENDIF} Img32, Img32.Vector, Img32.Text, Img32.Transform; {$IFDEF ZEROBASEDSTR} {$ZEROBASEDSTRINGS OFF} {$ENDIF} type TSvgEncoding = (eUnknown, eUtf8, eUnicodeLE, eUnicodeBE); TUnitType = (utUnknown, utNumber, utPercent, utEm, utEx, utPixel, utCm, utMm, utInch, utPt, utPica, utDegree, utRadian); ////////////////////////////////////////////////////////////////////// // TValue - Structure to store numerics with measurement units. // See https://www.w3.org/TR/SVG/types.html#InterfaceSVGLength // and https://www.w3.org/TR/SVG/types.html#InterfaceSVGAngle ////////////////////////////////////////////////////////////////////// //Unfortunately unit-less values can exhibit ambiguity, especially when their //values are small (eg < 1.0). These values can be either absolute values or //relative values (ie relative to the supplied dimension size). //The 'assumeRelValBelow' parameter (see below) attempts to address this //ambiguity, such that unit-less values will be assumed to be 'relative' when //'rawVal' is less than the supplied 'assumeRelValBelow' value. TValue = {$IFDEF RECORD_METHODS} record {$ELSE} object {$ENDIF} rawVal : double; unitType : TUnitType; procedure Init; procedure SetValue(val: double; unitTyp: TUnitType = utNumber); function GetValue(relSize: double; assumeRelValBelow: Double): double; function GetValueXY(const relSize: TRectD; assumeRelValBelow: Double): double; function IsValid: Boolean; function IsRelativeValue(assumeRelValBelow: double): Boolean; {$IFDEF INLINE} inline; {$ENDIF} function HasFontUnits: Boolean; function HasAngleUnits: Boolean; end; TValuePt = {$IFDEF RECORD_METHODS} record {$ELSE} object {$ENDIF} X, Y : TValue; procedure Init; function GetPoint(const relSize: double; assumeRelValBelow: Double): TPointD; overload; function GetPoint(const relSize: TRectD; assumeRelValBelow: Double): TPointD; overload; function IsValid: Boolean; end; TValueRecWH = {$IFDEF RECORD_METHODS} record {$ELSE} object {$ENDIF} left : TValue; top : TValue; width : TValue; height : TValue; procedure Init; function GetRectD(const relSize: TRectD; assumeRelValBelow: Double): TRectD; overload; function GetRectD(relSize: double; assumeRelValBelow: Double): TRectD; overload; function GetRectWH(const relSize: TRectD; assumeRelValBelow: Double): TRectWH; function IsValid: Boolean; function IsEmpty: Boolean; end; {$IFNDEF UNICODE} UTF8Char = Char; PUTF8Char = PChar; {$ELSE} {$IF COMPILERVERSION < 31} UTF8Char = AnsiChar; PUTF8Char = PAnsiChar; {$IFEND} {$ENDIF} TSvgItalicSyle = (sfsUndefined, sfsNone, sfsItalic); TFontDecoration = (fdUndefined, fdNone, fdUnderline, fdStrikeThrough); TSvgTextAlign = (staUndefined, staLeft, staCenter, staRight); TSVGFontInfo = record family : TTtfFontFamily; size : double; spacing : double; textLength : double; italic : TSvgItalicSyle; weight : Integer; align : TSvgTextAlign; decoration : TFontDecoration; baseShift : TValue; end; ////////////////////////////////////////////////////////////////////// // TClassStylesList: custom TStringList that stores ansistring objects ////////////////////////////////////////////////////////////////////// PAnsStringiRec = ^TAnsiStringRec; //used internally by TClassStylesList TAnsiStringRec = record ansi : UTF8String; end; TClassStylesList = class private fList : TStringList; public constructor Create; destructor Destroy; override; function AddAppendStyle(const classname: string; const ansi: UTF8String): integer; function GetStyle(const classname: UTF8String): UTF8String; procedure Clear; end; ////////////////////////////////////////////////////////////////////// // TSvgParser and associated classes - a simple parser for SVG xml ////////////////////////////////////////////////////////////////////// PSvgAttrib = ^TSvgAttrib; //element attribute TSvgAttrib = record hash : Cardinal; //hashed name name : UTF8String; value : UTF8String; end; TSvgParser = class; TXmlEl = class //base element class private {$IFDEF XPLAT_GENERICS} attribs : TList ; {$ELSE} attribs : TList; {$ENDIF} function GetAttrib(index: integer): PSvgAttrib; function GetAttribCount: integer; public {$IFDEF XPLAT_GENERICS} childs : TList; {$ELSE} childs : TList; {$ENDIF} name : UTF8String; owner : TSvgParser; hash : Cardinal; text : UTF8String; selfClosed : Boolean; constructor Create(owner: TSvgParser); virtual; destructor Destroy; override; procedure Clear; virtual; function ParseHeader(var c: PUTF8Char; endC: PUTF8Char): Boolean; virtual; function ParseContent(var c: PUTF8Char; endC: PUTF8Char): Boolean; virtual; function ParseAttribName(var c: PUTF8Char; endC: PUTF8Char; attrib: PSvgAttrib): Boolean; function ParseAttribValue(var c: PUTF8Char; endC: PUTF8Char; attrib: PSvgAttrib): Boolean; function ParseAttributes(var c: PUTF8Char; endC: PUTF8Char): Boolean; virtual; procedure ParseStyleAttribute(const style: UTF8String); property Attrib[index: integer]: PSvgAttrib read GetAttrib; property AttribCount: integer read GetAttribCount; end; TDocTypeEl = class(TXmlEl) private procedure SkipWord(var c, endC: PUTF8Char); function ParseEntities(var c, endC: PUTF8Char): Boolean; public function ParseAttributes(var c: PUTF8Char; endC: PUTF8Char): Boolean; override; end; TSvgTreeEl = class(TXmlEl) public constructor Create(owner: TSvgParser); override; procedure Clear; override; function ParseHeader(var c: PUTF8Char; endC: PUTF8Char): Boolean; override; end; TSvgParser = class private svgStream : TMemoryStream; procedure ParseStream; public classStyles :TClassStylesList; xmlHeader : TXmlEl; docType : TDocTypeEl; svgTree : TSvgTreeEl; constructor Create; destructor Destroy; override; procedure Clear; function FindEntity(hash: Cardinal): PSvgAttrib; function LoadFromFile(const filename: string): Boolean; function LoadFromStream(stream: TStream): Boolean; function LoadFromString(const str: string): Boolean; end; ////////////////////////////////////////////////////////////////////// // Miscellaneous SVG functions ////////////////////////////////////////////////////////////////////// //general parsing functions ////////////////////////////////////////// function ParseNextWord(var c: PUTF8Char; endC: PUTF8Char; out word: UTF8String): Boolean; function ParseNextWordEx(var c: PUTF8Char; endC: PUTF8Char; out word: UTF8String): Boolean; function ParseNextNum(var c: PUTF8Char; endC: PUTF8Char; skipComma: Boolean; out val: double): Boolean; function ParseNextNumEx(var c: PUTF8Char; endC: PUTF8Char; skipComma: Boolean; out val: double; out unitType: TUnitType): Boolean; function GetHash(const name: UTF8String): cardinal; function GetHashCaseSensitive(name: PUTF8Char; nameLen: integer): cardinal; function ExtractRef(const href: UTF8String): UTF8String; function IsNumPending(var c: PUTF8Char; endC: PUTF8Char; ignoreComma: Boolean): Boolean; function UTF8StringToColor32(const value: UTF8String; var color: TColor32): Boolean; function MakeDashArray(const dblArray: TArrayOfDouble; scale: double): TArrayOfInteger; function Match(c: PUTF8Char; const compare: UTF8String): Boolean; overload; function Match(const compare1, compare2: UTF8String): Boolean; overload; function ToUTF8String(var c: PUTF8Char; endC: PUTF8Char): UTF8String; //special parsing functions ////////////////////////////////////////// procedure ParseStyleElementContent(const value: UTF8String; stylesList: TClassStylesList); function ParseTransform(const transform: UTF8String): TMatrixD; procedure GetSvgFontInfo(const value: UTF8String; var fontInfo: TSVGFontInfo); function HtmlDecode(const html: UTF8String): UTF8String; function GetXmlEncoding(memory: Pointer; len: integer): TSvgEncoding; function ClampRange(val, min, max: double): double; function SkipBlanks(var c: PUTF8Char; endC: PUTF8Char): Boolean; function SkipBlanksAndComma(var current: PUTF8Char; currentEnd: PUTF8Char): Boolean; type TSetOfUTF8Char = set of UTF8Char; UTF8Strings = array of UTF8String; function CharInSet(chr: UTF8Char; chrs: TSetOfUTF8Char): Boolean; const clInvalid = $00010001; clCurrent = $00010002; sqrt2 = 1.4142135623731; quote = ''''; dquote = '"'; space = #32; SvgDecimalSeparator = '.'; //do not localize {$I Img32.SVG.HashConsts.inc} var LowerCaseTable : array[#0..#255] of UTF8Char; ColorConstList : TStringList; implementation type TColorConst = record ColorName : string; ColorValue: Cardinal; end; TColorObj = class cc: TColorConst; end; const buffSize = 8; //include hashed html entity constants {$I Img32.SVG.HtmlHashConsts.inc} //------------------------------------------------------------------------------ // Miscellaneous functions ... //------------------------------------------------------------------------------ function ClampRange(val, min, max: double): double; {$IFDEF INLINE} inline; {$ENDIF} begin if val <= min then Result := min else if val >= max then Result := max else Result := val; end; //------------------------------------------------------------------------------ function CharInSet(chr: UTF8Char; chrs: TSetOfUTF8Char): Boolean; begin Result := chr in chrs; end; //------------------------------------------------------------------------------ function Match(c: PUTF8Char; const compare: UTF8String): Boolean; var i: integer; begin Result := false; for i := 1 to Length(compare) do begin if LowerCaseTable[c^] <> compare[i] then Exit; inc(c); end; Result := true; end; //------------------------------------------------------------------------------ function Match(const compare1, compare2: UTF8String): Boolean; var i, len: integer; c1, c2: PUTF8Char; begin Result := false; len := Length(compare1); if len <> Length(compare2) then Exit; c1 := @compare1[1]; c2 := @compare2[1]; for i := 1 to len do begin if LowerCaseTable[c1^] <> LowerCaseTable[c2^] then Exit; inc(c1); inc(c2); end; Result := true; end; //------------------------------------------------------------------------------ function Split(const str: UTF8String): UTF8Strings; var i,j,k, spcCnt, len: integer; begin spcCnt := 0; i := 1; len := Length(str); while (len > 0) and (str[len] <= #32) do dec(len); while (i <= len) and (str[i] <= #32) do inc(i); for j := i + 1 to len do if (str[j] <= #32) and (str[j -1] > #32) then inc(spcCnt); SetLength(Result, spcCnt +1); for k := 0 to spcCnt do begin j := i; while (j <= len) and (str[j] > #32) do inc(j); SetLength(Result[k], j -i); Move(str[i], Result[k][1], j -i); while (j <= len) and (str[j] <= #32) do inc(j); i := j; end; end; //------------------------------------------------------------------------------ function GetXmlEncoding(memory: Pointer; len: integer): TSvgEncoding; var p: PUTF8Char; begin Result := eUnknown; if (len < 4) or not Assigned(memory) then Exit; p := PUTF8Char(memory); case p^ of #$EF: if ((p +1)^ = #$BB) and ((p +2)^ = #$BF) then Result := eUtf8; #$FF: if ((p +1)^ = #$FE) then Result := eUnicodeLE; #$FE: if ((p +1)^ = #$FF) then Result := eUnicodeBE; end; end; //------------------------------------------------------------------------------ function SkipBlanks(var c: PUTF8Char; endC: PUTF8Char): Boolean; begin while (c < endC) and (c^ <= space) do inc(c); Result := (c < endC); end; //------------------------------------------------------------------------------ function SkipBlanksAndComma(var current: PUTF8Char; currentEnd: PUTF8Char): Boolean; begin Result := SkipBlanks(current, currentEnd); if not Result or (current^ <> ',') then Exit; inc(current); Result := SkipBlanks(current, currentEnd); end; //------------------------------------------------------------------------------ function SkipStyleBlanks(var c: PUTF8Char; endC: PUTF8Char): Boolean; var inComment: Boolean; begin //style content may include multi-line comment blocks inComment := false; while (c < endC) do begin if inComment then begin if (c^ = '*') and ((c +1)^ = '/') then begin inComment := false; inc(c); end; end else if (c^ > space) then begin inComment := (c^ = '/') and ((c +1)^ = '*'); if not inComment then break; end; inc(c); end; Result := (c < endC); end; //------------------------------------------------------------------------------ function IsAlpha(c: UTF8Char): Boolean; {$IFDEF INLINE} inline; {$ENDIF} begin Result := CharInSet(c, ['A'..'Z','a'..'z']); end; //------------------------------------------------------------------------------ function ParseStyleNameLen(var c: PUTF8Char; endC: PUTF8Char): integer; var c2: PUTF8Char; const validNonFirstChars = ['0'..'9','A'..'Z','a'..'z','-']; begin Result := 0; //nb: style names may start with a hyphen if (c^ = '-') then begin if not IsAlpha((c+1)^) then Exit; end else if not IsAlpha(c^) then Exit; c2 := c; inc(c); while (c < endC) and CharInSet(c^, validNonFirstChars) do inc(c); Result := c - c2; end; //------------------------------------------------------------------------------ function ParseNextWord(var c: PUTF8Char; endC: PUTF8Char; out word: UTF8String): Boolean; var c2: PUTF8Char; begin Result := SkipBlanksAndComma(c, endC); if not Result then Exit; c2 := c; while (c < endC) and (LowerCaseTable[c^] >= 'a') and (LowerCaseTable[c^] <= 'z') do inc(c); word := ToUTF8String(c2, c); end; //------------------------------------------------------------------------------ function ParseNextWordEx(var c: PUTF8Char; endC: PUTF8Char; out word: UTF8String): Boolean; var isQuoted: Boolean; c2: PUTF8Char; begin Result := SkipBlanksAndComma(c, endC); if not Result then Exit; isQuoted := (c^) = quote; if isQuoted then begin inc(c); c2 := c; while (c < endC) and (c^ <> quote) do inc(c); word := ToUTF8String(c2, c); inc(c); end else begin Result := CharInSet(LowerCaseTable[c^], ['A'..'Z', 'a'..'z']); if not Result then Exit; c2 := c; inc(c); while (c < endC) and CharInSet(LowerCaseTable[c^], ['A'..'Z', 'a'..'z', '-', '_']) do inc(c); word := ToUTF8String(c2, c); end; end; //------------------------------------------------------------------------------ function ParseNameLength(var c: PUTF8Char; endC: PUTF8Char): integer; overload; var c2: PUTF8Char; const validNonFirstChars = ['0'..'9','A'..'Z','a'..'z','_',':','-']; begin c2 := c; inc(c); while (c < endC) and CharInSet(c^, validNonFirstChars) do inc(c); Result := c - c2; end; //------------------------------------------------------------------------------ {$OVERFLOWCHECKS OFF} function GetHash(const name: UTF8String): cardinal; var i: integer; c: PUTF8Char; begin //https://en.wikipedia.org/wiki/Jenkins_hash_function c := PUTF8Char(name); Result := 0; if c = nil then Exit; for i := 1 to Length(name) do begin Result := (Result + Ord(LowerCaseTable[c^])); Result := Result + (Result shl 10); Result := Result xor (Result shr 6); inc(c); end; Result := Result + (Result shl 3); Result := Result xor (Result shr 11); Result := Result + (Result shl 15); end; {$OVERFLOWCHECKS ON} //------------------------------------------------------------------------------ {$OVERFLOWCHECKS OFF} function GetHashCaseSensitive(name: PUTF8Char; nameLen: integer): cardinal; var i: integer; begin Result := 0; for i := 1 to nameLen do begin Result := (Result + Ord(name^)); Result := Result + (Result shl 10); Result := Result xor (Result shr 6); inc(name); end; Result := Result + (Result shl 3); Result := Result xor (Result shr 11); Result := Result + (Result shl 15); end; {$OVERFLOWCHECKS ON} //------------------------------------------------------------------------------ function ParseNextWordHashed(var c: PUTF8Char; endC: PUTF8Char): cardinal; var c2: PUTF8Char; name: UTF8String; begin c2 := c; ParseNameLength(c, endC); name := ToUTF8String(c2, c); if name = '' then Result := 0 else Result := GetHash(name); end; //------------------------------------------------------------------------------ function ParseNextNumEx(var c: PUTF8Char; endC: PUTF8Char; skipComma: Boolean; out val: double; out unitType: TUnitType): Boolean; var decPos,exp: integer; isNeg, expIsNeg: Boolean; start: PUTF8Char; begin Result := false; unitType := utNumber; //skip white space +/- single comma if skipComma then begin while (c < endC) and (c^ <= space) do inc(c); if (c^ = ',') then inc(c); end; while (c < endC) and (c^ <= space) do inc(c); if (c = endC) then Exit; decPos := -1; exp := Invalid; expIsNeg := false; isNeg := c^ = '-'; if isNeg then inc(c); val := 0; start := c; while c < endC do begin if Ord(c^) = Ord(SvgDecimalSeparator) then begin if decPos >= 0 then break; decPos := 0; end else if (LowerCaseTable[c^] = 'e') and (CharInSet((c+1)^, ['-','0'..'9'])) then begin if (c +1)^ = '-' then expIsNeg := true; inc(c); exp := 0; end else if (c^ < '0') or (c^ > '9') then break else if IsValid(exp) then begin exp := exp * 10 + (Ord(c^) - Ord('0')) end else begin val := val *10 + Ord(c^) - Ord('0'); if decPos >= 0 then inc(decPos); end; inc(c); end; Result := c > start; if not Result then Exit; if decPos > 0 then val := val * Power(10, -decPos); if isNeg then val := -val; if IsValid(exp) then begin if expIsNeg then val := val * Power(10, -exp) else val := val * Power(10, exp); end; //https://oreillymedia.github.io/Using_SVG/guide/units.html case c^ of '%': begin inc(c); unitType := utPercent; end; 'c': //convert cm to pixels if ((c+1)^ = 'm') then begin inc(c, 2); unitType := utCm; end; 'd': //ignore deg if ((c+1)^ = 'e') and ((c+2)^ = 'g') then begin inc(c, 3); unitType := utDegree; end; 'e': //convert cm to pixels if ((c+1)^ = 'm') then begin inc(c, 2); unitType := utEm; end else if ((c+1)^ = 'x') then begin inc(c, 2); unitType := utEx; end; 'i': //convert inchs to pixels if ((c+1)^ = 'n') then begin inc(c, 2); unitType := utInch; end; 'm': //convert mm to pixels if ((c+1)^ = 'm') then begin inc(c, 2); unitType := utMm; end; 'p': case (c+1)^ of 'c': begin inc(c, 2); unitType := utPica; end; 't': begin inc(c, 2); unitType := utPt; end; 'x': begin inc(c, 2); unitType := utPixel; end; end; 'r': //convert radian angles to degrees if Match(c, 'rad') then begin inc(c, 3); unitType := utRadian; end; end; end; //------------------------------------------------------------------------------ function ParseNextNum(var c: PUTF8Char; endC: PUTF8Char; skipComma: Boolean; out val: double): Boolean; var tmp: TValue; begin tmp.Init; Result := ParseNextNumEx(c, endC, skipComma, tmp.rawVal, tmp.unitType); val := tmp.GetValue(1, 1); end; //------------------------------------------------------------------------------ function ExtractRef(const href: UTF8String): UTF8String; {$IFDEF INLINE} inline; {$ENDIF} var c, c2, endC: PUTF8Char; begin c := PUTF8Char(href); endC := c + Length(href); if Match(c, 'url(') then begin inc(c, 4); dec(endC); // avoid trailing ')' end; if c^ = '#' then inc(c); c2 := c; while (c < endC) and (c^ <> ')') do inc(c); Result := ToUTF8String(c2, c); end; //------------------------------------------------------------------------------ function ParseNextChar(var c: PUTF8Char; endC: PUTF8Char): UTF8Char; begin Result := #0; if not SkipBlanks(c, endC) then Exit; Result := c^; inc(c); end; //------------------------------------------------------------------------------ function ParseQuoteChar(var c: PUTF8Char; endC: PUTF8Char): UTF8Char; begin if SkipBlanks(c, endC) and (c^ in [quote, dquote]) then begin Result := c^; inc(c); end else Result := #0; end; //------------------------------------------------------------------------------ function AllTrim(var name: UTF8String): Boolean; var i, len: integer; begin len := Length(name); i := 0; while (len > 0) and (name[1] <= space) do begin inc(i); dec(len); end; if i > 0 then Delete(name, 1, i); Result := len > 0; if not Result then Exit; while name[len] <= space do dec(len); SetLength(name, len); end; //------------------------------------------------------------------------------ function ToUTF8String(var c: PUTF8Char; endC: PUTF8Char): UTF8String; var len: integer; begin len := endC - c; SetLength(Result, len); if len = 0 then Exit; Move(c^, Result[1], len * SizeOf(UTF8Char)); c := endC; end; //------------------------------------------------------------------------------ function IsKnownEntity(owner: TSvgParser; var c: PUTF8Char; endC: PUTF8Char; out entity: PSvgAttrib): boolean; var c2, c3: PUTF8Char; entityName: UTF8String; begin inc(c); //skip ampersand. c2 := c; c3 := c; ParseNameLength(c3, endC); entityName := ToUTF8String(c2, c3); entity := owner.FindEntity(GetHash(entityName)); Result := (c3^ = ';') and Assigned(entity); //nb: increments 'c' only if the entity is found. if Result then c := c3 +1 else dec(c); end; //------------------------------------------------------------------------------ function ParseQuotedString(var c: PUTF8Char; endC: PUTF8Char; out quotStr: UTF8String): Boolean; var quote: UTF8Char; c2: PUTF8Char; begin quote := c^; inc(c); c2 := c; while (c < endC) and (c^ <> quote) do inc(c); Result := (c < endC); if not Result then Exit; quotStr := ToUTF8String(c2, c); inc(c); end; //------------------------------------------------------------------------------ function IsNumPending(var c: PUTF8Char; endC: PUTF8Char; ignoreComma: Boolean): Boolean; var c2: PUTF8Char; begin Result := false; //skip white space +/- single comma if ignoreComma then begin while (c < endC) and (c^ <= space) do inc(c); if (c^ = ',') then inc(c); end; while (c < endC) and (c^ <= ' ') do inc(c); if (c = endC) then Exit; c2 := c; if (c2^ = '-') then inc(c2); if (c2^ = SvgDecimalSeparator) then inc(c2); Result := (c2 < endC) and (c2^ >= '0') and (c2^ <= '9'); end; //------------------------------------------------------------------------------ function ParseTransform(const transform: UTF8String): TMatrixD; var i: integer; c, endC: PUTF8Char; c2: UTF8Char; word: UTF8String; values: array[0..5] of double; mat: TMatrixD; begin c := PUTF8Char(transform); endC := c + Length(transform); Result := IdentityMatrix; //in case of invalid or referenced value while ParseNextWord(c, endC, word) do begin if Length(word) < 5 then Exit; if ParseNextChar(c, endC) <> '(' then Exit; //syntax check //reset values variables for i := 0 to High(values) do values[i] := InvalidD; //and since every transform function requires at least one value if not ParseNextNum(c, endC, false, values[0]) then Break; //now get additional variables i := 1; while (i < 6) and IsNumPending(c, endC, true) and ParseNextNum(c, endC, true, values[i]) do inc(i); if ParseNextChar(c, endC) <> ')' then Exit; //syntax check mat := IdentityMatrix; //scal(e), matr(i)x, tran(s)late, rota(t)e, skew(X), skew(Y) case LowerCaseTable[word[5]] of 'e' : //scalE if not IsValid(values[1]) then MatrixScale(mat, values[0]) else MatrixScale(mat, values[0], values[1]); 'i' : //matrIx if IsValid(values[5]) then begin mat[0,0] := values[0]; mat[0,1] := values[1]; mat[1,0] := values[2]; mat[1,1] := values[3]; mat[2,0] := values[4]; mat[2,1] := values[5]; end; 's' : //tranSlateX, tranSlateY & tranSlate if Length(word) =10 then begin c2 := LowerCaseTable[word[10]]; if c2 = 'x' then MatrixTranslate(mat, values[0], 0) else if c2 = 'y' then MatrixTranslate(mat, 0, values[0]); end else if IsValid(values[1]) then MatrixTranslate(mat, values[0], values[1]) else MatrixTranslate(mat, values[0], 0); 't' : //rotaTe if IsValid(values[2]) then MatrixRotate(mat, PointD(values[1],values[2]), DegToRad(values[0])) else MatrixRotate(mat, NullPointD, DegToRad(values[0])); 'x' : //skewX begin MatrixSkew(mat, DegToRad(values[0]), 0); end; 'y' : //skewY begin MatrixSkew(mat, 0, DegToRad(values[0])); end; end; Result := MatrixMultiply(Result, mat); end; end; //------------------------------------------------------------------------------ procedure GetSvgFontInfo(const value: UTF8String; var fontInfo: TSVGFontInfo); var c, endC: PUTF8Char; hash: Cardinal; begin c := PUTF8Char(value); endC := c + Length(value); while (c < endC) and SkipBlanks(c, endC) do begin if c = ';' then break else if IsNumPending(c, endC, true) then ParseNextNum(c, endC, true, fontInfo.size) else begin hash := ParseNextWordHashed(c, endC); case hash of hSans_045_Serif : fontInfo.family := ttfSansSerif; hSerif : fontInfo.family := ttfSerif; hMonospace : fontInfo.family := ttfMonospace; hBold : fontInfo.weight := 600; hItalic : fontInfo.italic := sfsItalic; hNormal : begin fontInfo.weight := 400; fontInfo.italic := sfsNone; end; hStart : fontInfo.align := staLeft; hMiddle : fontInfo.align := staCenter; hEnd : fontInfo.align := staRight; hline_045_through : fontInfo.decoration := fdStrikeThrough; hUnderline : fontInfo.decoration := fdUnderline; end; end; end; end; //------------------------------------------------------------------------------ function HtmlDecode(const html: UTF8String): UTF8String; var val, len: integer; c,ce,endC: PUTF8Char; begin len := Length(html); SetLength(Result, len*3); c := PUTF8Char(html); endC := c + len; ce := c; len := 1; while (ce < endC) and (ce^ <> '&') do inc(ce); while (ce < endC) do begin if ce > c then begin Move(c^, Result[len], ce - c); inc(len, ce - c); end; c := ce; inc(ce); while (ce < endC) and (ce^ <> ';') do inc(ce); if ce = endC then break; val := -1; //assume error if (c +1)^ = '#' then begin val := 0; //decode unicode value if (c +2)^ = 'x' then begin inc(c, 3); while c < ce do begin if (c^ >= 'a') and (c^ <= 'f') then val := val * 16 + Ord(c^) - 87 else if (c^ >= 'A') and (c^ <= 'F') then val := val * 16 + Ord(c^) - 55 else if (c^ >= '0') and (c^ <= '9') then val := val * 16 + Ord(c^) - 48 else begin val := -1; break; end; inc(c); end; end else begin inc(c, 2); while c < ce do begin val := val * 10 + Ord(c^) - 48; inc(c); end; end; end else begin //decode html entity ... case GetHashCaseSensitive(c, ce - c) of {$I Img32.SVG.HtmlValues.inc} end; end; //convert unicode value to utf8 chars //this saves the overhead of multiple UTF8String<-->string conversions. case val of 0 .. $7F: begin result[len] := UTF8Char(val); inc(len); end; $80 .. $7FF: begin Result[len] := UTF8Char($C0 or (val shr 6)); Result[len+1] := UTF8Char($80 or (val and $3f)); inc(len, 2); end; $800 .. $7FFF: begin Result[len] := UTF8Char($E0 or (val shr 12)); Result[len+1] := UTF8Char($80 or ((val shr 6) and $3f)); Result[len+2] := UTF8Char($80 or (val and $3f)); inc(len, 3); end; $10000 .. $10FFFF: begin Result[len] := UTF8Char($F0 or (val shr 18)); Result[len+1] := UTF8Char($80 or ((val shr 12) and $3f)); Result[len+2] := UTF8Char($80 or ((val shr 6) and $3f)); Result[len+3] := UTF8Char($80 or (val and $3f)); inc(len, 4); end; else begin //ie: error Move(c^, Result[len], ce- c +1); inc(len, ce - c +1); end; end; inc(ce); c := ce; while (ce < endC) and (ce^ <> '&') do inc(ce); end; if (c < endC) and (ce > c) then begin Move(c^, Result[len], (ce - c)); inc(len, ce - c); end; setLength(Result, len -1); end; //------------------------------------------------------------------------------ function HexByteToInt(h: UTF8Char): Cardinal; {$IFDEF INLINE} inline; {$ENDIF} begin case h of '0'..'9': Result := Ord(h) - Ord('0'); 'A'..'F': Result := 10 + Ord(h) - Ord('A'); 'a'..'f': Result := 10 + Ord(h) - Ord('a'); else Result := 0; end; end; //------------------------------------------------------------------------------ function IsFraction(val: double): Boolean; {$IFDEF INLINE} inline; {$ENDIF} begin Result := (val <> 0) and (Abs(val) < 1); end; //------------------------------------------------------------------------------ function UTF8StringToColor32(const value: UTF8String; var color: TColor32): Boolean; var i, len : integer; j : Cardinal; clr : TColor32; alpha : Byte; vals : array[0..3] of double; mus : array[0..3] of TUnitType; c, endC : PUTF8Char; begin Result := false; len := Length(value); if len < 3 then Exit; c := PUTF8Char(value); if (color = clInvalid) or (color = clCurrent) or (color = clNone32) then alpha := 255 else alpha := GetAlpha(color); if Match(c, 'rgb') then begin endC := c + len; inc(c, 3); if (c^ = 'a') then inc(c); if (ParseNextChar(c, endC) <> '(') or not ParseNextNumEx(c, endC, false, vals[0], mus[0]) or not ParseNextNumEx(c, endC, true, vals[1], mus[1]) or not ParseNextNumEx(c, endC, true, vals[2], mus[2]) then Exit; for i := 0 to 2 do if mus[i] = utPercent then vals[i] := vals[i] * 255 / 100; if ParseNextNumEx(c, endC, true, vals[3], mus[3]) then alpha := 255 else //stops further alpha adjustment vals[3] := 255; if ParseNextChar(c, endC) <> ')' then Exit; for i := 0 to 3 do if IsFraction(vals[i]) then vals[i] := vals[i] * 255; color := ClampByte(Round(vals[3])) shl 24 + ClampByte(Round(vals[0])) shl 16 + ClampByte(Round(vals[1])) shl 8 + ClampByte(Round(vals[2])); end else if (c^ = '#') then //#RRGGBB or #RGB begin if (len = 9) then begin clr := $0; alpha := $0; for i := 1 to 6 do begin inc(c); clr := clr shl 4 + HexByteToInt(c^); end; for i := 1 to 2 do begin inc(c); alpha := alpha shl 4 + HexByteToInt(c^); end; clr := clr or alpha shl 24; end else if (len = 7) then begin clr := $0; for i := 1 to 6 do begin inc(c); clr := clr shl 4 + HexByteToInt(c^); end; clr := clr or $FF000000; end else if (len = 5) then begin clr := $0; for i := 1 to 3 do begin inc(c); j := HexByteToInt(c^); clr := clr shl 4 + j; clr := clr shl 4 + j; end; inc(c); alpha := HexByteToInt(c^); alpha := alpha + alpha shl 4; clr := clr or alpha shl 24; end else if (len = 4) then begin clr := $0; for i := 1 to 3 do begin inc(c); j := HexByteToInt(c^); clr := clr shl 4 + j; clr := clr shl 4 + j; end; clr := clr or $FF000000; end else Exit; color := clr; end else //color name lookup begin i := ColorConstList.IndexOf(string(value)); if i < 0 then Exit; color := TColorObj(ColorConstList.Objects[i]).cc.ColorValue; end; //and in case the opacity has been set before the color if (alpha < 255) then color := (color and $FFFFFF) or alpha shl 24; {$IF DEFINED(ANDROID)} color := SwapRedBlue(color); {$IFEND} Result := true; end; //------------------------------------------------------------------------------ function MakeDashArray(const dblArray: TArrayOfDouble; scale: double): TArrayOfInteger; var i, len: integer; dist: double; begin dist := 0; len := Length(dblArray); SetLength(Result, len); for i := 0 to len -1 do begin Result[i] := Ceil(dblArray[i] * scale); dist := Result[i] + dist; end; if dist = 0 then begin Result := nil; end else if Odd(len) then begin SetLength(Result, len *2); Move(Result[0], Result[len], len * SizeOf(integer)); end; end; //------------------------------------------------------------------------------ function PeekNextChar(var c: PUTF8Char; endC: PUTF8Char): UTF8Char; begin if not SkipBlanks(c, endC) then Result := #0 else Result := c^; end; //------------------------------------------------------------------------------ procedure ParseStyleElementContent(const value: UTF8String; stylesList: TClassStylesList); var len, cap: integer; names: array of string; procedure AddName(const name: string); begin if len = cap then begin cap := cap + buffSize; SetLength(names, cap); end; names[len] := name; inc(len); end; var i: integer; aclassName: UTF8String; aStyle: UTF8String; c, c2, endC: PUTF8Char; begin //https://oreillymedia.github.io/Using_SVG/guide/style.html stylesList.Clear; if value = '' then Exit; len := 0; cap := 0; c := @value[1]; endC := c + Length(value); SkipBlanks(c, endC); if Match(c, ' '{' then Break; inc(c); c2 := c; while (c < endC) and (c^ <> '}') do inc(c); if (c = endC) then break; aStyle := ToUTF8String(c2, c); //finally, for each class name add (or append) this style for i := 0 to High(names) do stylesList.AddAppendStyle(names[i], aStyle); names := nil; len := 0; cap := 0; inc(c); end; end; //------------------------------------------------------------------------------ // TXmlEl classes //------------------------------------------------------------------------------ constructor TXmlEl.Create(owner: TSvgParser); begin {$IFDEF XPLAT_GENERICS} attribs := TList.Create; childs := TList.Create; {$ELSE} attribs := TList.Create; childs := TList.Create; {$ENDIF} selfClosed := true; Self.owner := owner; end; //------------------------------------------------------------------------------ destructor TXmlEl.Destroy; begin Clear; attribs.Free; childs.Free; inherited; end; //------------------------------------------------------------------------------ procedure TXmlEl.Clear; var i: integer; begin for i := 0 to attribs.Count -1 do Dispose(PSvgAttrib(attribs[i])); attribs.Clear; for i := 0 to childs.Count -1 do TXmlEl(childs[i]).free; childs.Clear; end; //------------------------------------------------------------------------------ function TXmlEl.ParseHeader(var c: PUTF8Char; endC: PUTF8Char): Boolean; var style: UTF8String; c2: PUTF8Char; begin SkipBlanks(c, endC); c2 := c;; ParseNameLength(c, endC); name := ToUTF8String(c2, c); //load the class's style (ie undotted style) if found. style := owner.classStyles.GetStyle(name); if style <> '' then ParseStyleAttribute(style); Result := ParseAttributes(c, endC); end; //------------------------------------------------------------------------------ function TXmlEl.ParseAttribName(var c: PUTF8Char; endC: PUTF8Char; attrib: PSvgAttrib): Boolean; var c2: PUTF8Char; //attribName: UTF8String; begin Result := SkipBlanks(c, endC); if not Result then Exit; c2 := c; ParseNameLength(c, endC); attrib.Name := ToUTF8String(c2, c); attrib.hash := GetHash(attrib.Name); end; //------------------------------------------------------------------------------ function TXmlEl.ParseAttribValue(var c: PUTF8Char; endC: PUTF8Char; attrib: PSvgAttrib): Boolean; var quoteChar : UTF8Char; c2, c3: PUTF8Char; begin Result := ParseNextChar(c, endC) = '='; if not Result then Exit; quoteChar := ParseQuoteChar(c, endC); if quoteChar = #0 then Exit; //trim leading and trailing spaces while (c < endC) and (c^ <= space) do inc(c); c2 := c; while (c < endC) and (c^ <> quoteChar) do inc(c); c3 := c; while (c3 > c2) and ((c3 -1)^ <= space) do dec(c3); attrib.value := ToUTF8String(c2, c3); inc(c); //skip end quote end; //------------------------------------------------------------------------------ function TXmlEl.ParseAttributes(var c: PUTF8Char; endC: PUTF8Char): Boolean; var i: integer; attrib, styleAttrib, classAttrib, idAttrib: PSvgAttrib; classes: UTF8Strings; ansi: UTF8String; begin Result := false; styleAttrib := nil; classAttrib := nil; idAttrib := nil; while SkipBlanks(c, endC) do begin if CharInSet(c^, ['/', '?', '>']) then begin if (c^ <> '>') then begin inc(c); if (c^ <> '>') then Exit; //error selfClosed := true; end; inc(c); Result := true; break; end else if (c^ = 'x') and Match(c, 'xml:') then begin inc(c, 4); //ignore xml: prefixes end; New(attrib); if not ParseAttribName(c, endC, attrib) or not ParseAttribValue(c, endC, attrib) then begin Dispose(attrib); Exit; end; attribs.Add(attrib); case attrib.hash of hId : idAttrib := attrib; hClass : classAttrib := attrib; hStyle : styleAttrib := attrib; end; end; if assigned(classAttrib) then with classAttrib^ do begin //get the 'dotted' classname(s) classes := Split(value); for i := 0 to High(classes) do begin ansi := SvgDecimalSeparator + classes[i]; //get the style definition ansi := owner.classStyles.GetStyle(ansi); if ansi <> '' then ParseStyleAttribute(ansi); end; end; if assigned(styleAttrib) then ParseStyleAttribute(styleAttrib.value); if assigned(idAttrib) then begin //get the 'hashed' classname ansi := '#' + idAttrib.value; //get the style definition ansi := owner.classStyles.GetStyle(ansi); if ansi <> '' then ParseStyleAttribute(ansi); end; end; //------------------------------------------------------------------------------ procedure TXmlEl.ParseStyleAttribute(const style: UTF8String); var styleName, styleVal: UTF8String; c, c2, endC: PUTF8Char; attrib: PSvgAttrib; begin //there are 4 ways to load styles (in ascending precedence) - //1. a class element style (called during element contruction) //2. a non-element class style (called via a class attribute) //3. an inline style (called via a style attribute) //4. an id specific class style c := PUTF8Char(style); endC := c + Length(style); while SkipStyleBlanks(c, endC) do begin c2 := c; ParseStyleNameLen(c, endC); styleName := ToUTF8String(c2, c); if styleName = '' then Break; if (ParseNextChar(c, endC) <> ':') or //syntax check not SkipBlanks(c,endC) then Break; c2 := c; inc(c); while (c < endC) and (c^ <> ';') do inc(c); styleVal := ToUTF8String(c2, c); AllTrim(styleVal); inc(c); new(attrib); attrib.name := styleName; attrib.value := styleVal; attrib.hash := GetHash(attrib.name); attribs.Add(attrib); end; end; //------------------------------------------------------------------------------ function TXmlEl.GetAttribCount: integer; begin Result := attribs.Count; end; //------------------------------------------------------------------------------ function TXmlEl.GetAttrib(index: integer): PSvgAttrib; begin Result := PSvgAttrib(attribs[index]); end; //------------------------------------------------------------------------------ function TXmlEl.ParseContent(var c: PUTF8Char; endC: PUTF8Char): Boolean; var child: TSvgTreeEl; entity: PSvgAttrib; c2, tmpC, tmpEndC: PUTF8Char; begin Result := false; while SkipBlanks(c, endC) do begin if (c^ = '<') then begin inc(c); case c^ of '!': begin if Match(c, '!--') then //start comment begin inc(c, 3); while (c < endC) and ((c^ <> '-') or not Match(c, '-->')) do inc(c); //end comment inc(c, 3); end else begin //it's very likely ']') or not Match(c, ']]>')) do inc(c); text := ToUTF8String(c2, c); inc(c, 3); if (hash = hStyle) then ParseStyleElementContent(text, owner.classStyles); end else begin while (c < endC) and (c^ <> '<') do inc(c); text := ToUTF8String(c2, c); end; end; end; '/', '?': begin //element closing tag inc(c); if Match(c, name) then begin inc(c, Length(name)); //very rarely there's a space before '>' SkipBlanks(c, endC); Result := c^ = '>'; inc(c); end; Exit; end; else begin //starting a new element child := TSvgTreeEl.Create(owner); childs.Add(child); if not child.ParseHeader(c, endC) then break; if not child.selfClosed then child.ParseContent(c, endC); end; end; end else if c^ = '>' then begin break; //oops! something's wrong end else if (c^ = '&') and IsKnownEntity(owner, c, endC, entity) then begin tmpC := PUTF8Char(entity.value); tmpEndC := tmpC + Length(entity.value); ParseContent(tmpC, tmpEndC); end else if (hash = hTSpan) or (hash = hText) or (hash = hTextPath) then begin //text content: and because text can be mixed with one or more // elements we need to create sub-elements for each text block. //And elements can even have sub-elements. tmpC := c; //preserve a leading space if (tmpC -1)^ = space then dec(tmpC); while (c < endC) and (c^ <> '<') do inc(c); if (hash = hTextPath) then begin text := ToUTF8String(tmpC, c); end else begin child := TSvgTreeEl.Create(owner); childs.Add(child); child.text := ToUTF8String(tmpC, c); end; end else begin tmpC := c; while (c < endC) and (c^ <> '<') do inc(c); text := ToUTF8String(tmpC, c); //if doublecmd-1.1.22/pixmaps/dctheme/scalable/actions/view-sort-descending.svg0000644000175000001440000000222014743153644025663 0ustar alexxusers doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/0000755000175000001440000000000014743153644021070 5ustar alexxusersdoublecmd-1.1.22/pixmaps/dctheme/scalable/devices/drive-harddisk.svg0000644000175000001440000005657014743153644024526 0ustar alexxusers image/svg+xml Drive - Hard Disk Jakub Steiner hdd hard drive fixed media solid http://jimmac.musichall.cz doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/drive-optical.svg0000644000175000001440000005673314743153644024371 0ustar alexxusers image/svg+xml Drive - CD-ROM Jakub Steiner cdrom cd-rom optical drive http://jimmac.musichall.cz doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/drive-removable-media-usb.svgz0000644000175000001440000001022714743153644026734 0ustar alexxusers\mo#7:K+Xw.wYjyt%CǞ"jm|dNajurקc.֫!Tb8WlpMVr/Wo.lp'z6x\> ~ZNvZ4zs;~;8;ۏo ڞϦæfͦzYիv mi6vFf6%24XZm?vdK]Q1Z?- EcB{g!TqsYWz7~}器fM<±ɴގS9r (P/n?ZqQ?mt91AX. LVhd=|mwTQvquir{D%#]J2;[Oi4lXm pvWMEFv_]}:.d6MTKv_~u1zOnrHfsdw֜J!] nt_3AKKebŸ捓W{'gKlx3|D^}OVl?LW)[hlxջLV;BhOT`*'| rrRI?W6eX;RD՛ᄏ{|UXr{>?&!|i҂")BhzI+<}Į<_4|X㫟A>bhʞZi{OIcmk8%HSdv U9^#h:< WH4S\_GRg+c?G ӗ"7ep.Sd6 Tl{Bd GS^#{@]bP _GYSu*[;12-2f𧈸Xbw(:P+FrzW?UzO3+&Mp&s5p' 5,5e%;zuNK{M:R1a-:[e Nfe=:(Π*S:嫟[g|~@acmŀ=uqIV?W8bI&ej] H[LoOʅw?ʞaoN7OP@p~3GI%QeN#,P˹&}m&Gr)5(ӗs q#| 5Zsz"{:) 'D/Qgيe}b}뻁[N ȹзl/sWo\Ov G҃ 2G(7rz~@ rBVHuC DQ( zP2{zc cmfd.P8pC83QYج;:` Xi W H*"\3}Qf[FdY<#OV)k+6 _,$'y ̏ryzsN|}.ШZVm^[!9EfoWʰYV'+>_[17TLxaj*dtii1&uTyJ~&;DŽnBν4!pF5K4 q%l*\aTW.aBBDH4uv) 皬$71֯~>+]\t!z4l=6(Y"'yTJt ޷Cwc+/EVBLe~7sҭu# GEXI|0AԌME4m?ꭊ7GoLTDdqU蓤z~f.ˤ@2`9aH/XZ|[%Mppw+n=1cEÍ* iMe >(c>½K h3b|H^!laW/7UsQ.|ua7Þbf:xYtr&KN`4{&->DmX&@#W:\."0,#koq+NKmP,X[+g[@~^_/DD%<^:tWƢ'FS#sNg'O1:?!K.Jf³y"4jXu_]2'-Ϗ'/XV'1".U)R5gJ>I\H0D8/*P66M:Gč81a$&Rǂ4t .oi^kmP\|4 slUzCpBDCxw-fіKϝ̵D[=›[|;pGFt-6BsK|O6"\P1~PkE~5cZkqb\'P[;o.q[В\ߓ[mg(S(sc++PdE~q3?oBn/ηP6]l:uw|Sy,w;z—_]xvcwzPN|yxžwқ8Z牃l+pz)s caG^V2y]F><#h ƙEe>;`v~d퀣΄_׌J[Iobܸ4Řtt5 )OHHgJB:uҋ?"!ݴyòejRжCX9N$cJ,\IN PN 7ml;YM)3 ͦ,M֌ ue{Dƶ%|͘Sh (*FBV8X"-Jȑ6r`!<ӶK~f]xd~$쩖Ff2BK6%7l4-6u|KYr=ÆLD c R<P$b)#FFs h 숆v4;-IÈFR[nA`, ^"03R(هJ+nj`.%KLH' ӄ kIʱ>6*R[+HSτošCAdƲRn:Lm24)~@I[:~9V`pM!K;cc#CaL1T|CG]DL< x=r4{Du6a/*A8 JHc%@+)U”ۀcBiP+cɠ}ՏJP8GՌ̄& AEr+՚ʓمȯd.giJLJ 2H+. [EMMi M*է먑fjd255rC52"S#ƭ1jՈPF25"kHB>]l\GܡL\GlF&S#Q#uFFdjd:j35jEGLF2S#Q#QQ˛Hgjdr52"S#ȊV,dj5C5LdGF2S#fjHwHgj%ڄuF2S#쨑ꨑHej:j$ȈL0S#O'HWs5OYL>]lGlG S#騑eg#l䳳﨑訑է=T#Hgj:j$HwHejwHgjaG0S3!Q#Hej;g#vF@DFQ#8T#;j5LTFF:T#Q#djhVaFQ#Q#Hv﨑25tqLDjorI_.vohPdoublecmd-1.1.22/pixmaps/dctheme/scalable/devices/drive-removable-media.svg0000644000175000001440000004475214743153644025765 0ustar alexxusers image/svg+xml Drive - Removable Jakub Steiner media removable http://jimmac.musichall.cz doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/media-flash.svg0000644000175000001440000006540314743153644023773 0ustar alexxusers image/svg+xml Jakub Steiner http://jimmac.musichall.cz Generic Flash Media flash memory removable photo Novell, Inc., Jakub Steiner doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/media-floppy.svg0000644000175000001440000003367614743153644024216 0ustar alexxusers image/svg+xml Media Floppy Tuomas Kuosmanen http://www.tango-project.org save document store file io floppy media Jakub Steiner doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/media-optical.svg0000644000175000001440000007060314743153644024327 0ustar alexxusers image/svg+xml Media CD-ROM Jakub Steiner http://jimmac.musichall.cz cdrom media removable cd audio doublecmd-1.1.22/pixmaps/dctheme/scalable/devices/network-wired.svg0000644000175000001440000005066414743153644024425 0ustar alexxusers image/svg+xml Jakub Steiner http://jimmac.musichall.cz Network doublecmd-1.1.22/pixmaps/dctheme/scalable/emblems/0000755000175000001440000000000014743153644021072 5ustar alexxusersdoublecmd-1.1.22/pixmaps/dctheme/scalable/emblems/emblem-cloud-offline.svg0000644000175000001440000001244614743153644025607 0ustar alexxusers image/svg+xml doublecmd-1.1.22/pixmaps/dctheme/scalable/emblems/emblem-cloud-online.svg0000644000175000001440000000333614743153644025447 0ustar alexxusers doublecmd-1.1.22/pixmaps/dctheme/scalable/emblems/emblem-cloud-pinned.svg0000644000175000001440000001226414743153644025440 0ustar alexxusers image/svg+xml doublecmd-1.1.22/pixmaps/dctheme/scalable/mimetypes/0000755000175000001440000000000014743153644021462 5ustar alexxusersdoublecmd-1.1.22/pixmaps/dctheme/scalable/mimetypes/application-x-executable.svg0000644000175000001440000002312614743153644027076 0ustar alexxusers image/svg+xml Executable Jakub Steiner http://jimmac.musichall.cz/ executable program binary bin script shell doublecmd-1.1.22/pixmaps/dctheme/scalable/mimetypes/package-x-generic.svg0000644000175000001440000002326614743153644025466 0ustar alexxusers image/svg+xml doublecmd-1.1.22/pixmaps/dctheme/scalable/mimetypes/text-x-hash.svg0000644000175000001440000002171214743153644024360 0ustar alexxusers image/svg+xml doublecmd-1.1.22/pixmaps/dctheme/scalable/mimetypes/unknown.svg0000644000175000001440000001761114743153644023710 0ustar alexxusers image/svg+xml doublecmd-1.1.22/pixmaps/dctheme/scalable/places/0000755000175000001440000000000014743153644020715 5ustar alexxusersdoublecmd-1.1.22/pixmaps/dctheme/scalable/places/folder.svg0000644000175000001440000000432214743153644022712 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/0000755000175000001440000000000014743153644016064 5ustar alexxusersdoublecmd-1.1.22/pixmaps/mainicon/alt/0000755000175000001440000000000014743153644016644 5ustar alexxusersdoublecmd-1.1.22/pixmaps/mainicon/alt/128px-dcfinal.png0000644000175000001440000002277614743153644021650 0ustar alexxusersPNG  IHDR>abKGDtIME5" IDATxy%Uuk3ݡzlD@FA|$/?O38<5!>38D ($34|izC{QU=w;=|νuNڵk^{<1y"d\{ޑˁƹU#ʜ̉ӭ"FFO(j99^Sλ%y!Aۺv1 L_9#SWpsR*(W =*I=%ټ3ג $j}*QwՃ/)-?{~z)תryR ŤJE)KXejG3gk % pƓ5+lyq%=l]dILUŋf嚿hڼY)qelyWFzP=dzu <"r& Ɨ:D.+dAg+;}P4{=;<z%[Ar06ε|!ym!eಗej3]S}1Fyjq~ܹ hM_觗ǩ1?qKYt)F ""BFg =JFc((>U\į{{PǓbK2x'oyUBTVj,]c XH̢i(R9 jω P}X%w Á%/~ǮYNt/@vU(TP]st]p̑0ceX JU+VمXy:E xʕ :s+G/}Ogg.]y:ZyʊNY::ҎJZZ|?/gJLӏ8B0U ;;( gQ!<B䰎5"×uj+: CAC#rJ|"?.7'![2Vy8UʪrĂD/2^2X* TBG( DʂTwBv0o7N YQp1' N)8@pB^`IG` ߣ̈ %@,|[PTk6+}b$!͊`DkI҈$y2iv(.ѴKZ:D흙?H1b@>b9*0t:D06j,KJ' o F3+` aX+W5~$KT<.!CF(, '@$PD0<ީ oFD^Q,)Je9Eh䈢" }{ڡO2{I V`3``D4&4 ?4KDN;%rzB0!Cq r2s]H:1z ÐrT*D䚳:UTUD&`,wtҹtl8qqRfg}ޥ}wނ؏o 1i{<w)1"İvQ@(x1^r?xݑK/w$GXb ,YAchs>}29cKri5dU}*)(łTbks^,]KzØd!"t.YF_S~w_Q ϒy>ZFJEBG9ja3yA]L:0ưp:ʁvݷΛ[Ks%g IFςn!c"G]D-rT^z!{{9)!%@]Kq%W O|ߝY 5<)Q (9yٻc9- Ei"N|e>R,yOL<|&YD! qNa R,YEl{_Q6HvAC'|5rTˆrqܛΆ.Mq.ǟC!BRTKZx]S𮣋s?ds]8t$pZN/pzH5"s클OuCa`}l+H ےBS!Y1XTˆ r1Du[x_Dr/O72kڪ h?t1#Vh;uw0Lc()'}?^!#ϵ~sc ښ`9׽ !XH?^85PcMfiJvŪΒ#q_ԣ u`ez;Ywr<^qҏ4E)cLU\s PG2b b-ss?WJmn8!g!qS*aD%Xu%<‹$+aL$ \6WFaDVe\!P=K9 =RTcl6Z k9tukbW!Ɋ_;(y9+IðYs?97,\?6)Zӎ^}Qm|! ڸJ E<W H͎P/yօΰ1X$LQRюԶ=-8U/WIaKfUCX~T~WWFX1Lfkp;X;Li'*#Ҫһ};onZZ`0FNW*%QrVbgː@ q|x x"JBad/po]5VY|Y#Bi"6Cg/WO ր;+MD(⤿[).X'#QђE=_w؊/O (lUF(/5'm puF[X3T5 B8Q Q߻-kݲx9G=ha剧IS8, HiΩ*'ƪd7>|2]A{/7ǂ$$_4X r6d7aؚa7ŖN<#xI Gt9 9jwxr|';wvҷP kZH}阿9ֿM6氫/'|}g\YđRGZZ|FM Ą`y,(tunҙ/~ baC?SH^%/ʙ~o7nwEw߯Z.ϣó9OLìٲDP=]y i[Z {E@{i$vL+Z)|`P|~C+;{ IR{,߳]A9噬 56_#@7|Q1ڊ pժ:q c&\4 Qv4sDn5ڎĺ 0AOj&hꄵ PPVlGi۷`DDJܿ( rz\l;hK4n\?,R!,q2QFT: ԓAh0}]n9 |[(` XDfp$&j،2,D}D2^mϰ!@X<1IbiqÈ!хWS-ڎJ\nڝdmgnӄ1(_QjyB±Q WSo_؎n&64ʆ3>lyF4+MeW$ߕYXE>T{k[҂`Ǯ"ڜu.viOm6 'Bՙ:FXm LULF@~w>= 7]OM]V)7TW0! sT*#ڶ!d"qTW÷ ,=udKX` E:>d=چLAxIܳ-Hahr=ۧ]E? 0*=[}贻? x)*2j9!ឧ>0DA@.pJ ϛ?Hh,&/l-pH*e=[myh{MCZTyyL=xěFM 7`J:Vs_J]{ΤwpUhJ}f6G"M}5 n=]tI~V<O<{=#r:,)uʳY!u]۩oy 740zb4~N,8 +VM^׷K,D{q3.sZּ - V (9½;o~HهS*-ZW^6#]c*' r24Ȟ;oqY̲ -αQ8#P ڿG'dMm b,Gi@$NI$݇'/fDF^IԌ 62H1½;E%Rr .~tt@wCܕc<6モ3R'\zrʪTS"O}룸 Ozbx&G]2S}u䍐K759#<}38J|Xb* !wMZlpWxWbaZCU5&sL3; x1h_é,~y#Hp}%M taRS_c pνUoz ӵ2&^(fC0'B;6}\V^U)+TabFNNسhӣGOf|J51loz2o~ԫgj >7c8'ǿR/R(R%-e3MqlۈVFFiR%vĂ c tGϪ,|Kf`֟baM3wk/|Nx>CRQ S =LTR۹(atХ/JNuQl S\D}ϧ$r4::Elg`hy+{ɢk:?p30蔡D#4@L nO IUM6(TSJ/Y(ݴ1٘!86;idЅK<Yt΅=W_lh>ڛ7(!!/Jh`pl?87DXgK.M]ͦo}CvSJrM40$(!KڣxulzT#Pb%1 N] \SD^/d/LZ{wi=vFBe"D+O6_;`ۍ?]?VbgBpWjSⴹrCF`5JAVaWDq݆]4}j(Ecșxfar *DNyg| -\4kcXy٬v^9}[=C-s MI՝(&N%s]ڂ"t }߿Bj.O(Yv۬JH'UD?bg7qУr+`KQ *Cu݀#xFMHoE${,EByAyw;~b:\5XV֬t)^_*wtwvMʖ(٫\̄b=H$(I/-Uo6%gb>p3hm O%c!c>f;Ĕ%ѿJ$>]'%yQ_#N)rT^ 4g `zvXŌGF?GICҿK[YOٙԣ舅)H#e_-inq"= xP/Y6[:=k ۹[5V* ;KT F fwM;Hi%B X%1@r]dqNX#'B[[x1<&lOb2(IcxL: SE~L&"8+ 6QQQ+K%-647Tv(bb+=#koU"&0u:/gR@'K/򛣥uP(A]-g&AcTAϫhF%~nO#A+g <(8яo3[]4oa( < B;mbx2^kW?35cXϼa@tY\j2b1= '0܋U@Wc]7c؁s)yW{#%Fmt_]X2U4QτT/[uD7 X5aoD$8QvꄯM]8&F??kÌT3kܰ|2# ׎V7gP=^&M(:_~פ!ixuPDs5 :3~RDԗf?kx7O[i/¥eQػor\SAd)aFr5鏎 Ӽ5q3fd \۸) B?*U_ڍL6.sSjw*Gd+;&?k0Ietg+12~V woD߳|16=lGht*8WWv$J3m_R]]-N;hb9z5}#UĈ3w#i3E-'Gky#oU7$v rO1yc<&#<IENDB`doublecmd-1.1.22/pixmaps/mainicon/alt/128px-doublecmd.png0000644000175000001440000001736514743153644022204 0ustar alexxusersPNG  IHDR>abKGDtIME7KIDATx}y\UwRkoIYl@MD6eQqeMy#AF>*7sA~Q!DYe K$@t:Iw.UVuUuUJ,s~;ι<1y *OG݈1UD#T9s!!BrL8ߋFV#֝8_XD/S(0 F_ Ľ(s/~IX0B~*P>?;/~s.JDWpfzS-B^]EGO[nk*Tb "0:f++A^pŅʙ(D =/|\)_B*(}BBqSDHs(|UX&*~%-#iFڱZ $[~6ꚜ@Xw˘-Psǂ BƅqI\}1nQeY%3D=)_4.J S>*>K/8))3HD[8yQʹ5`J}Upe ("IG"/*2__'ZR ?R[BQ0 -ɣZlq+Hs(t5QEWOUIEN fdlol{){*Ыw0xK+/[NBBi Tܒ0/v:eW7=|x+@E'3t/ϔ اl*N >^"KBqʔOq_0@=--:0ztvI]3!e @vsYFmaЪF"B؟f:ƤKzR\wGc1CBh0 IJQ1P,LhkŎ[sѦvK,65-$3(0 ]L4HiL$ [V x 1hpAZ$r& kt!\y4?,ÚEb=e=BxG,|] )ݎ0:3ӎ;ڽ o@/x+!3rO$%سWy  ^)$0,'ưp͚u^+V>\WǸ,(FA@>kl<$dO^7grz_qyRM\ &]4DZPKQ{)BKbh(xJ[Oi cʙܼ@RwND9 k;sf`i\ػރaSYIs?86M&fmېRN"3޼ڟw Yu0ZOdXP=dKSADD"s-$4D%c927 hkB]KbfW`?@%Fs|W Ήd5FX+"\CCZ)9]Xo֎X,6jJ.w_)UMN Gx<#_xigEGkIFUt\-nC,&-ZI\_E4sV4jJf $p{ `̗ ,&V(>h-c]8Mgiu]DϿ}9ȦSBb_$@u]z\KXus'/"̓xWC.`0;$Ym? |4gjg@ `u/qI^xr"C@_|V9}SJ]wG_:^yR@U1>J M֋OiZ1sᱫZ^*c5E7qv@ ȟًL&Sԗ3@u:Ģ0<>p#}ì~^˫ޝpwous 0䝷2 $hĽYJbO(ZN?(!as>u`xl:*j4eW LGXZ~LvMԼ_  uOsKjV-w sJ`& rQr%+ ]?[|6Pm :(t`q Ȝ{ rq_ 41-O[b *Lpa~e y`SB}o-[h bANj/f滏v79oZ_J2kOl)jP7h RW!0xrrTK{id= MCpz}:#B83QKe5 #7+V;!n/75ּayB^V镔\9R_5?Z MEPu]+K-wOJ ca 5=UjS ܋.ɧk4ar+0 Mݥ̓|BK7, X>ByrP0 t 㯾԰,3.ۛN42h-@DbjޱiHm|,gvj4pߛ-uX_.T&Uw<-m|>(ׅ5:k4Gr2 a--U6'@ VI8SW!#@tiSm#w!⭹RNjQM  h98Pw_"vs[J)E-vZLR##ZBSVRpN;-"8}udzwb9@u&t`KVmO`M;տDήM3$ܑp)= vEk_w\w>x %rm' u!(ARBvA8P AY{S-ew,@ vZAcn^.ܽ:S!۶~@{m9ln`V gp'?bӪ-[SjE|LJm-P b0f3Y\ T6 gW!G+΍>~19 d:`[n~42o@{w]R), (رXWՇΡ*5ӏ}?Rzej=j&[8;ނ;4zw]o币<ѿikrp'3 r ]&kE}9si|`e193tﮟp33$Ģ.¥}"k^Ƚn̬RB_˯bR/њ hn6?|_i{y7{*X5a.wfm\P*MTu _D ~Rhi"3 6OlF`~?,$}.Ghg/fQ]pw#1hg~!+(d2)X ?>kӆ/Ex@n LVt=N=]-^}qgDc.%1@$Xq8$(MG:Hח"CXq۬}̇p*E".JaYlF(ނU_V]u =0i8cc3gϞGzŰH C $D70B`3 {=&SւfT@0z7X&_(opύ#q(3#²,躎ο(A)mDfVNn*w94uwGvNiD8okW)%l.c!@[[R ɟ~'S߱jX+[K|sH̰[`4Mm_. c.{_ )} ICJͼś |S4 kSfWC,6@{_O:q,36(Kt 4D`J}ˡ]s-]?.eufx3HaA+:&6@]ųH@\3 ciP 9zPz"O>̹kESadSH|Kl\4%=lXIд4 mmm{ l<"Ռo?j.~L)  uR;Z#G[[[P (tH[Mwh2o^A_xt:ůAi,@8Fkk+Wl=~\w6]Iξ2ښ)8L؄T0M37bASe>n;]Wp#+%ѾL&B\  #,\ÿucNը4x ]&,z#V B0M*9Js$Oo_]BK?sY#5Bt]d{7w)ϙ^"G_~]EW뺅!3efD]aFaΚ#pYncJ?Ht~|90:us/z O"DY (w(x?",l``)kw6cu;ǟDG -GJYhuJCΜ2J48c~`p'xyO?䎷N*<j'@1bUZCѕ]zk Vhx#' x'}w aC!. 88u% P 0Y*a#Y4HCkwVXbD}&V A\m΅ڙGBeE dIL5P7D `דq&m6ҒY1uesgΣ,@@"f½j,%YAV@C'x\8Xe% p]fQR `I}\؊B2]%Ё<5N@g "|RޗYګtb8ּ%hfH,4RX_IK H0l"q36Xޥϟx,1'_I7p{7+}0)wN*) "'M7}j헭Ͼ|oV"P/f3 GV\eti+@g+R78. XH V&YǏ{?I@?C3ƞ#.,Tהȷ˾KDž,D#xUND DQB JL_\07L+//)Rb6nx $Q !n.}Fo!ߏ(xMc`~חN_|% Y0{V:ەڇ:VpI:%iC/O=zuV;bLPW7 0gl̛7lxAI ~RJ3y;di?Q25&;.]Q@;:hB455E ""flȹZ/ΏXe9IaxVݷZ^]ruBڕW.}.R Gv#Z^f=+YKwSH_F8 ep }\ڹ 3~upJ_Ũ7ξV|B,^.FoADp $@T )RLX/>T@ʹ' fŚsͺ8?`xYw $qɪxٗdr*twD%!. ')R( XAH fu`go/5әYgCEKWo5MMMX|25ɰ㺠TS E>&2,]}(x9u5l@)dr*d3L61lRHQ >8!mr,¶c=( ʺ[*>c";.Y~2@\Ūp3sw)4 8rvqp\g'݁iv`uQ ;Ze/YYuL"0a霖f\bZ}}y]u5gy'GŸ"c%UK;;q)jͼe鎊d,>j['"dL*)R{ً9ft^Y"6ۋsOV`mDxֲ+0Zܷ&o1۳w\iE)FaqX2+8ΠhJ8#ج2?{ A8H1ȱj0dnB X0Ԓ}H4clՉY8̪ )f+'miN+}I0/09ɬL"ܮpڋIb*jY.SG|1ó̙k%GpY2(GdL" v%pZZ&!ؗ%|HFd_Rh$Tr<+]HHKYY%:\i)f_*n>[ cRClkmS#Ě.%8i B|݅餻]&3Q0dc0bl*1äV#ÔŻ,AGpmo> <j#No~%p13ii'q,-}9a @ BODjcg&f81Di%EDг%(Rt8 Ge{{]  .x/+n_= E_V$YZE4AXiFb RE)Z vf6Z\]0؄f7j@fHc)K@@G,Ωs'G@ĞW%=59mNj XkvE &5\lR2H1$ =8TEgX)v̰ &'ah/#`Y5" [0=\Y4egǀO)=ҰD,sR @[ сL%"t"+!{20}|0ȑ􍠇7 ]AmHK)af`QBo! hw,ʽS;A32 >s@R|iY HV vl@JʣL"0Z J'@Ge2؋fz&)L<ɐ҇_(/  {sbx ڊ⡽0`4n%GoBkX3T"κ ?}~KG.o>DQ=Jvjj)C|K3ẍ5l Kcm-N5ǣc̞Cٶ6d[67#85,Dš(<bB!X"袋Jz Vj0n .2&z,FR"?8Cڷ7oDc?hz P :ʂX q5^H2 hw ϡ/Y>!i=ǝ>=]+VRǂhiP6ʵH4wt]Wy1A ߍA~v584րZ 4AHBX0PH|@k1-@aVfsjwʩ4gr4MAp˵h(Ѵ$]}-e( w<'N _ "E"\:>#Y3_CuSv-sd8-XqXzsduJHr-->Ttx*\}p䁻o_ȫXC `] _$05 D|-ƴ Bt-]z;^fy! `\`KҲ$ j`Rk1^J؍Z_UߩuFe8’ϥlsKݞh D"܂Eg_@ :{vbǏ}= >1$$A`Z` "lBmo|p]7^EsAbYI "t-Yw^GC=GΟ;~@de, :d0[[7Q$fbm )>zej敯IW:έM>fh='ʹWa/oD6Hb8,8hm XABc D09 ~<{Pp^y=j4iG8C^Jl|wC>va V Hl EmQI뇑{~}H'%<|qHm]]61c sN˷QWo753\LpY5}aa Иe[f=Zd9tO/xO|?O\=TeMDBP@VCa!)&M~ƪeqh4͝-\{ڌ)X "t?~3mՏyO GB\AqnHĺ4@8_E`dLKV oEMK}[q_E87uWǿQ.١ 8{)Be%.xP&>KQUq>L_)T@{hn| T-IjU[L! yaTo}g ]NӭD#%*B`ŗS\Dž#h @f #tl `BJGsG$~ݼ8\OѬS)= ܏~= |/Q%REKR-LSt H~1OQ}}+_*KHH-Qq]i3y> H3>O P~#tum"ц<UR88_>J>ٟH-1`g9Dz_G*SK?*zR<;w>.{' 6^bK `^>v e.LԔFr/M=)*Xm}ƹxE3uG w!%q Ԅu!+BC+ܔʣ7zT߼SE_Jq#ұ VQJOź~|vu90f +'Kx$-O5jiFG PCYT4 W|Z`S<-Y<`D4t []{hzJ@¶L:7%ĵXJ!KЄ5`:,<8lΫ-8iS'!* c-\^oCJkWdBW|O~?#6`'QJ`񺳒ӫWƤx5׍5(Sv\K{ЯGjR C /fO#Vcً_ϿF*7jՈfXJ X,BJM]]ffLD['+8zpSۓ"ӄEKfXOSP CvEۚh[ PhұAW@:.2B%'#9tz a0i_sd]*5Ihצ8,ղOw*H> \oo,D I@ؿ}vrO';z6JLO ]-0ρ̝{÷7EIytZg>ʒ#]RcBV@/c΃]֠RJp Ԍܼt5{1:O8/T|SwCljq3)q@+0U`UW_V`*iZծ/w{202Dz:HBqb P> eց$=+M:#FSEAWF[N fa66cf Fa%W"^3Φ×3beI MAF+Pb7V5V'%_ ,~SR+_ĞͷG6<mͱT}:X}_=ޤpɪFЃ*RGM82 p'e-4Bu AY[-D}Ҭ+'*y]@l>De_o a_Xc!uy8lx~b5 \HAƭWך.ad@h]FGD:dIM]p58Џa Ab!! k59HEN̚RksSK+o ȝ.`>B^sC0C0J\iFGdF<Ij@~p;~{?o)\(fGoEZ~7ًG `Ah1:=/fq 8"+Dl9~"V'_EbH aǽXR5<:/NlaT_HK`j 0idm\t,\)a/w|mFn~`[nowy&HX @Zdz !@+2.:2ڿ%"QvƩB8`!1C6c W o*/MXqE9ў~΅@RqEDЅ0јV~fXU)&Bk M/B@`\Whz%/ZwSyALSqV1d bϘV ƵmSty#DߪO߷|3|l P V`}9*|:NѤx%lyFhۨoa7RmіP$A>5/{aENմO%|ᕴ?_*R bw8ĵlk}#nzѕA;zx?'oVwj%9~IVB?J`ߵJ PFf`XfWbm%PJ”{ !U"" !KY/k(2\8⤫0e,ahW'RDZ&=fJ1#Iw('؆Ǒ$_X'|~ Ph掼Pcf t:G +oFf'hZu6<?p51<mbx }}ҩh?~mA& IDATX tVۦn=Ϙlb`; %i։kuzID7Ynt?wܻqd.kzqеb P.Ie^h5B1""0͓@S7~k^QblGZEw%8ǻԐa HV>(P`\=ZD]7Fsܱl;oJw1Mհ.b&~ {l]K@g|'F5u1 G7]#hǾӡd-ZjB$Z#IHV~1<'#hO6حٟ o0%v TD5$…4kw7=kH@ \x&JXo4) 9~T&v!extڀ./aʈaK?Sۈ-Sh;K`.7#[=k$G{Urs~um aڳJ֚vJ 'M3ɓ ^m %> y5A[d9o|<`C"P_XA $ 8xO_gB^Nǚl*etI6!>3VVMm|$i'|ۏxo CW FDm~9LZ@În,t##:2:VEK"% s-iǣ]+Gf<Ȟ#F@urtW%hزLL03gfrF>}NUt lڀ?^KZ\if"}> k5m^h a寴K6@,O(3MQac,MJ7׋?))HP[lEjRםKd  @` v#I+3#=}TJ;M^IkZuUڮ@kk@sQ"B&ǟT!OJRbw$e.ı4k#f3բ+ } =7JO:?D&ϼ(0C"`ǮgF0g]Mzc}qD<Cϣa/h䃙# " ~B8b5P?L+"{ˆZ.w~>bvtD`ip?ib4B^-rƓ:ov EEY5 {wH:^rΕkc56iTk/8Cb&Mi'aǝ`'AN=]3M5fWXAasU hH;$+2Yt}F6L4\``iπ.#Ҏ_Οo$`31LPе\Ot3!p[ #u$:LOK;i޻27|=&P0{,f0z'Hֹ#o4u-VAGu)l'?ǎ~MUx`@V􂘩r? Irh3ٹ#RV Krf|4.|)eʌ= +gZ# & [ѦY&hQN9#l&Uaf=rz$ϕ\J"~l*]+%vsv(g3 V4ph WIuŝ`]7a`K>c;z9)*dq+ @8=?I``[Aˌp䞻 ☴yҾjB^.mfF˼f+X@ Ҋ <r8xߟ,"?H @)>~1'yx[\7m2,ڗ 稁7 &.h]2Q.etч\-BBJ5?"CG v4FR[D@<@+u銊2w1dp?icWi % Z{!Byt-˥ PD+*`}$ÜWȓff}jcYcA $L1 el% ~@sXuIRc5[,䵀}{@߳yqrE+w4A IZ=ƃ5 f G(קUc!%r0c+4&;+d4ՊNKKI\-ލ?mM H `0Ub~Pv$\pk Sh֝{sz>PS7`dH `0Z%ρ\f _;^4/RBfq. !Q8`D«־mߠP QZdx^_/@  H< 8]݀S"7Ạ`ijY,:IH `W)~G\45qH/+PPP("/"y<7<`t},%wT8Ll"e45C45f/RX1K#T2Aj=Yz֬?zf!!a#%6A4ijܬ:g57ThH `0m ʙ)侥Œ?7 x27ox2? 0'd>XE$W1rPQNs +2݈x8uJ5H ~n X}]c DTE`V9Cdp[බmoS(RH `M/|G>PaWDKF'/pM#ˊC ( DpZභ!]=$#%Qtd2 a0p4 jrC~mi#n@r@ "wnWфL{܎d;&<AwAo/X$ #o?V:PNxPu ;k2@WKC/<[ 2]&?s kv}jvѠeBܗ8yF;rശiVLP5%"-^XX{^]GeÁP AxܻvBYம1[)A` =>Sqª{k:8hSSo.YNX´X$kd &;z#"Ypgu4%DFa c"Fe[(ij[>l%`F VԿ"A$'6pgF RZ;;P~XDےeo!OZM hi|Q";1y&amU [V0sɠR(;cHyٚR08D"crLʽsN;# j3w! |5C`3G| A@y !žcvoʞ ִr4}YD:'upJIH vA2ɪ[~.]Y,woPZM7Qڤ>{큝['cgm qjH @WB{Ez#s3r{wB>Zwv;E|ZQܾFwN8=~40`6P8|^u 1 &PGI B7`pƐ'!03u5m(8Sh\gAJ{#mr >gg7;3MpJ؎/==7_<2@SmkV@)R s9Fn쁗ׅF}DsfuA `#}sY>Hz{{hWJbҰ袋!ZZ#qCB)f4}܂M(;~ zh?B:N֧!p<|sc0msM;R8-A @s$`aKǎ Ivo?44ׁ@S.aMA"M,XML=w_"2#6Q`߃wx?[6x`7` ];Z3'V1qk9}R@sOFq2oR+ iO\,x`7[6;r ⯚H+j RD,*0з AB`@-K J %zͺj6̻,8Rmg5q {辆/-ֈ`f%)O\)4@j̇V j".Nkc 8COo;}Oa, jAB ىe/{~C3,p1ooGe{EH蜃/ ^}zI1/c_5]aml"K0S1Pؾ_r-z~!G\ګiWq@ ͻ%Gw6,e::pM@Eg+0uڋ¶'KBbIc󉧣ϛ>?8 Z6@ R LRNFN]?(H]'f=TTШ7_jk_*+.](5o,(W+V@y8tj1}$Gy+jL#&9ЇŽM6T o 1D 9 ͋OcLW,@ZC[Xfx-o pӹr V/#`TAj$9<(i;ZX?4McFvXpK޻׾}01g$:Nxۨ;[ͽF_Ѯӝ+'6Cs$a|-/uci3vV|k8 P ]e0ӆ} LcD C~!v<9~ >P@Xt5(`#whm뗐^%Z,iyDA@X;;wxߘHz7fK#e?Wsݳ}Z Z7[ײ/@v`yry=8;&)7âqj⎧F݂l;&G_LucFkLC8m ;E:L6LAM nلCF!p?J@(QK c0ޖdz`RK=Qܵ@\+;xTw[e50_I8[}`f[muq m(?48M87R5A"͇TF!?ݛ I2hCk$ŘӜn,{H4XS_Oo@c~2_ z}̍N)3Id@+n Ԝ`?;Z%2/å`4eX~g) |[&ocPہ@!%j`[۾ssCGK|רeي1$05P3`߇'ĤR_6MpϳPJ3Nk?C9Zow 2I ^`~G;E'1wGE _SNKew*(hډpL=Tv &Xz섷'0"6M~f?X5tϠ?b'ˤLXU0IVʯz}o!in9 -eA@.G c@Ed0aCv>=.rDMk4cUҢzA85,疯CD]A p"j}W?{uiuLϸ::뉛[2D~5XA# @Q(rҒ ?( %4%_Y ֯ AKMALE2gv(ࢯ~ZVl j%#JdPoR3-Q4#]a쪡va8*녁ge.4)(n,=/ Pn-;\8Sl V9_-J^FBҊ QbTѠKb ]IDAT9`fdGqVB!j3~(@A - ;?-H8nТ7D&;WR?CJj?޿H K/<47hVpE8MX7L+We[@T {{0QB\uE~E>1C ( hnL5s-&?bfYgCڳ?G#M 4/TyPMMm߈RDk7-+ t{~;*;L\=<ͯ7<!  -6="'8ͱ_7bŒE&"I&}G~S`1#X /9o#>s_7際 xq)ߟCӟBj$o`JW$@ 0C H`?ɳo>uhA^&,rz+7;~b ˫"l&CpG!.c떥QU_Ueܢ7y2P2@R~ː#o,?^_*7<'ۣ1S"t$w\,Ӭ _@N*L6v}s{r=\A/ pIk ?L! 2/)5Sqh^;F|ȴ<\z9s9nK0!BT:갤R7 ~N|]J+:؁V d+<{0 rf6 %!IZ'f`\U|2oYBK@fqeאMyG=\-.(V5f_d-.vF T HbO1 0Y9cG87_o6O凕BKNbCPja*}X*Zɋ(l(Nn#dw/M3Q,R]iuXlTEk1KgCL]mos{vZuaZڏS]Ү 1iox։ߥ9S[,>:;n9}ana !P^O/(0~M,@Dp !p2T`_=A`{f8nM u @h:z6u|d6P]Klǘ41*`b0gH0\zaç? 7Xikʗ+_ ܷ;s_m:`S0TMq٢SDc'Q~$Bt}=-#A e mQ7dݍ֡330Uz#}6<,\b,9IG1W6.u( `|c[n:Vo Gۢp߂>t=x?-#2pU i5ݗ d[U .[&-Sd)<A@R28쏟ࣨB̠݋]%YMKL?-_==$&j@YW*ZnJC"oҼssL{>_~_~yI܁۹v؎|_ s ;%cT$wi3pT#m 8 tΪmhi }BoZ!7߱ %BY~?c]g6i_|m]TO;in_UUfF `pK;·u6PEQ{?/ Yʵf13ZXI"Rʧ^~0~Ć@L&̒Up.\E& ]ׅS)>]_ÃWU~5x⮀d\̪}Cf08G|gn&qGi%5kaH 8ϾhPSd `)T7R؄hpd?dZ`o?ez %oÁ"so;:@J|?Sgٿ)ƈ#wߎߺ3'4w]]3 j܍& xO2Zrًƛ{]aw?~vw_;vk0dH-Zo3aY,вN9H `qg?[0"doUߠ?Sg>-8 1%~ lR`Ʀ?|_%)LG?^Iϵmn356  2%IXoAy3u)L+b7>˽=`/V~H1&;?5M$X>l:O&r;^opsnzÆ>&.36 E&J`S8;~ORnHǁwq~zd@_Vj?7o4$ SYNP6 S=˃w-)݃׿}JlI*FBamtw>Ցh )z3" ? DH$ ᧿u,=E1Qp ޴2Ic>L>TG ˳fq13c'!j_OMqa~~D%0ր‘2:F[^{wW?ՐZU `}]}v/75MHj,$]M :S Yx}xχ_ۖTBJ˗{#+jN%tA {k8 Z :TӔXp?)z/-S)$sy|@3dMxp.c&+jg`;;.Pɴ#u.&ZuY)XV1凑t FͺTOIfҒKv2ݿ̫pz_@d2uyFDJn*9Dh7&)d0^3u_-`g0(gc-RP;C'袋'13\?~"w,-G_KDME R?U=uᄫN8.(08oГ%zG⳪LBdK;}Y{~+pXtנ!__Ϗ~>\踋Lԟvj3r`0۲}Y$,v7>X +" A Q0սq$J@H?߃٧gO ;]ǟ){&-r[7p~zF9YBGÀ= W`F0 )&)1-P3MG}D@ZdпGг!/i<9}fv[w&֜rz1\n߻Qܳ {k+&P=L;#&A&"og/$ŸPa" blbˀ~"xGoľ @4`։'sjtuZkmHr&̳W?7>} wQ$>r%8q^k{7ag{z~x`TWtUW4n5| ͫ1_Hf=ku$YHHc9V@UЭ^;z | T/l+ՉHECHEu$p JV %:K̠Vۙ_ R(A+,_;tN_lg@zh h# f@]'jEJAވtyHhϒ:^QIؚ^Tpz gyYY+EhE+\@1edfVuiDum2re9p.\ѓ 0=oX^''ˢYmիS{ 7bJGvMq"eq2@:h+O22VY[; # ›Dd0Tb 3o\]g [Dсa bRB#$hftm yټϸsS/N)š] i)ߢw5Gnx[Z[ vJnJDw B00=> t2HIFK`9c/ \ 1i@oXǑj7 UI5ɾ689LgXVe0zk;Bf[o<C(~7! |ۏx M4ip=XEN/9]X{vDaFY*ڶ,e8j_=B*?}@"=S`N fGY̫p fj l+:%ȸ7WӮ[hW _g&9XͧPq,m$@9)$q_Fەlw p[SV|UPFಋ/N(Seddl0$_5Ɠty}niZw2ʳ.X*6bRNFFm`(g0_-Ow`Zzk:h`λeD1de###c=`?3y8kROx:7\|dzU&8w bnAkRC(p+\[L&Y ddl$l0ġ59VkV`'.0֖-J$+ CIk_C Z_Yԁ`ʖ>Y{D.^(\,3GlY2pFF4`3oe@OFzX>vg\P81L'j-H̏32ւ# xi",Ff=x To,"lqE"֖bK+"<:9#n` svGnu[Ps塳O)4btmW_~ue1u{t44C`,JhK oWol6> <Ϸ a$;MR z\9b; tm9 ㉾ӐNRP_o^ONaui6IqEq9%DH$ߴz~ :]o[.1n T+751\S~a_<{/(<m6-b#ք [g-Q>{TXˀ7UkeJCKK@l]ɫ?yjA¢ZH %hΌ!p) ͮ$̋WscoՍ݉{dy8~4^4_EfsΥ-h&I] HQNnSjg`]w Mϯ%ؾ?;|e/)ζU ЅmI[ Y߻6죮%mf{N̘޺cmO JGz䠲C7{pW&ޣx&)>^WGL˟6kWXLˏ\ V0Т⊅\=̋nߵZ]}nMˋK} ?m6GȃkD:Wø};?T2xVeSVY `Y-CwM]zػwx^eL~5QTwZ+saI܀6 0cGBr6Z960_|q8W# Y|ܾKW}l_7k쯺 ۄ:t$*ruW׈zSE,Xk!p]GTAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_a <IENDB`doublecmd-1.1.22/pixmaps/mainicon/alt/256px-doublecmd.png0000644000175000001440000003670514743153644022205 0ustar alexxusersPNG  IHDR\rfsBIT|d pHYsIIEtEXtSoftwarewww.inkscape.org< IDATxw%Unɉ&0 H$I@AQ @_e]װ|W  KNa<=g:\u?n{V|zVթsN;y!DPL3P(C B1QP`(3% F B1QP`(3# sY+r$=;s]:Z1ގQ>Ru]R??>܉o̹'5==whsK+;ҩ;n߹%;: D&k^y7GKXd1H'|dv"DSNi ~ #ZWҁ$\B$+Ⲋv( @Ymf1-n@֤4]:g!r$_h VP\q%綵ݶpEHSsV5k_tvvD1 a`:a e_3 W(Åxx,v98^`!)O4TW(Kvaig'G/^ re[w!D3w{\hW(ÈgID" _,VƂ }N?=b¯P4 I5cVef/8?b]]J# E#7;X Apky p=O~nW(Z@FB qK|V%/5z,ܓ4ΎNU+-]蚯(_D.Bvvv":(֑i,5SV')Op;< z)Ux'7]ZK+rk!ef%Pְ[v7"4Mf~93^dY@b " UMR*M=bޛ.r{N>'*Lk'`=!H$H)d27E4#{oSRV|tz&|Sʹ_mc&lַڱ~.@YbZKKbޓv  0cH#QwRz5P0AY)Fg6tT`bhL&eYat6Dkt,\̢}AOJ~V~e0bl6[z9A<, W5JL|iehF<EYu`5@4F saX8E(nfJwb|H" ϓB4bKWorΠ7#.Z}Ch4jԉeYd2ҎBſ=RM ӬJ]MΓOg?K$33TPM)iTt#1oxsRf9q 2ogyopU51զS0IɤIyyT3&@Q?K.sKy*h]d2!0= Q#"^1RG/z"z-cyUiN2to~1/qe6 -dW˗nxg.Jm% 8!O `zl|KWKRB^kC'ڂ$.. 0WMd"|g> ;kV!/DzQ`/=Ļ>)Dלs~Ø;+aՅ޸ xYI\ !}В,?ct|*ʹwP$"[D⒏ U&BD,ৈ,Zbo]ފJZIK0=SEh:/(k}(3V @IRM7I-X-{e$<_ީYڡދR###vOBܝ7nf_6:N>Od"l7cADSA ,t,-/Y L(ei =%-@7 s&Yܾ)KtJRwۙw y) `"FM[S>"t/FRfFZ h$ n 37L-6|%Gc VB|>?~\Lu0f@8ƛ5ě#7a[c*t]I݈RJLt ӊ^rv\ {eaYoyo0D"V8##vov4S!Uk|kHs[;D)I;N{{{:Cwno޹K@hn{cK_@!h A$]s @Xn)k6O_RJuf3Eb_pMViGQ,˝Z~%ܞ=X4f6`e3 4G?! /;p&WzÕ_`Zdb k8HaTwiόBY #r*[4ʐRs`( r9X} J)3i` L31gRJ"adlXi_[,#gglHvg/AZTKs+=ޡ!־+?m=췾1w>^t( ^-mF[`;Ry d2(HiI7%5 m:1')/hǟBlv.ӄ X)q)šAv3j0=|!䆧xۄ86yR-2OݱB[Eᅧ̦k/Lh$^~ބALu>x~v:̑5ncͦo)r²,FFF&|NJJG"vyy賺*kԽnFx_ᗒݿ;?ӮtQCwbtP622/Y[Z'8VB^))V.}}2Zٷ$vd2}p;/ʼn|ToE8 U=zV =fYzUǖ"CO<:o=;0RmdYwD/FP|WՌ"s\d y=gao #}ToE@zߕ  n=a Mv;܈qRc642^G{=880;> 0_/n|h :ٸV@ ڠ0 :^ZT64Ғnj !@Jx9Vv901gB"|q3'uv;SV< n:B>^xoͿ?ouچ'z~$zs.~y0ϒtz/ZxorS%oSs1;6%ǠfA=MN?A[Nㅇ?:v^z2cHI9_\.אѵ {jh;N<҈̰;m]3+!YHQ@LYȡG":f54cÏlθ+~shW߾lo}=^ ߋ[jѣ_>n8N'el_fޗ— ~Hn)\` J}0M;ǻZN,̀ԉ=h(T ~njԥ5JF1r?zP(~<)\ 6CdADZZ_ȫ50c7 IL̔: LP{Ҩ{ ;004xf0$T>rb܉QEǟֈB(Kk X[Y((zaviU=Arڬn"oUOؚ#ܞzTi99f pĴ{Wʔ-/:hN -Id2rJ;nmNOTAc>m+uy.HQʗLb'I쐗Tv3i>u%`>xD]DIqwqb [JA؋c-NkpTYa}ݍi (>z t)thf7RB1D%Qȫ._%i3 yOCN?gqZU 6d,>B+➸}dsӜO3~/|IڋX5&wG[TW܍iWW+'n_]qTP#溿m@$oZG'Z2mךF|5F,BTTN3-oX}bqB7c5j4Rz/QλGzݳ 鏲ڱɷ=ދZ h7i-X^e 9xgd7X3%u vc[ٶ9MtSiPI^71w/mhu+R߽aC83ffrw ! dzE'B>nF>"/PP'okNMV<C@tjpN^:8 @,K7?zqQ@{$ &Xs|SlZhj^@6{vC @li^flؖX&@Xjrg:^٪ &@ 0':948YZ "ڂ&@,Ko/BB!ta@)%ooZhblFi @f۷ۥI_`aD"D$2;:mE":-f|v~c+e9|3ٿ#vPx` X V& "H$i#Je/ԺXX,V.9ZХS "_ RZf.ˎ^8Z,COԉ=pܘR`G03iLb&A^+HV7}-ٺU|+0oZ4O'z<ZaPP/eN _X V.f:͂,7,{?MYٖAZ$ґHu~ND;8d6#aN oFHI1Nc att`:tt%0^da/-`P6IDATZ/H "DRɔ(P"@@9X$O)!0R)N]]DR4: G|2~@8AAAgaH)) "0&Mt֬}TP'bBtX@:\uAgiX"پ}dH,$a ԉ6*  \M^tVZmߊH`tucE%n{:;EM fZqz pElA@稵 f:CZ"'&g='ŽBӓ=;}i,O+?@+l%+ag6b B6-,:8:J@;P @гeio4gri/ԁ0 ڵ]cK˾Io-43<ᤀs^b9<5k',/!HD5jG @d!GaN#c3KO`w: [_fӘv,nin3 87/<@nFطY, :s |xV)9<<tr&Fs(d>GqO]nJGO9tE(` B6ܶM<`87PJnE{`aq:r=QIgl'`XDX,ͳy_pnڃ)mm]9?nX} / Waʭ0Rӏ<'qQ#IXpnόsoJtN#^dGF2vS гݾ3Zw` 0mzBV\h]sy`Xa B}þ˲\;?i+4)&y wLjɄg)]٧ lV'"4~(=+-c;pnBž^roWUDYDϺh4Bh ~!w4ݎA t1Ƭs^|m6?y`BTC{P9ɏ@ @$.~O //f[ah\ڼEο?-ӟu= ӗ?,(Xf.I~R8͟ghăJ:FƏXb ''Rb#FW7N!Foўl%L5=T`wĄ uϫ# -/؝xZ$O|CX& t_8mܳOPܻ3܌p( ?=%[D [(ni.B#mHk?r_x 6t]]@'Wa׾.2 %恽52co~0^v`mxp$vdk`?pn3p(Jy#؎9g}2G `eog;BsR;/P>9D"7t RuArv R244zzwU0TiRܳ \IOϹ+x_0fbCE= !_: .xSj=-smoU~F?/0"n0rm2#3o4]ТQ|_fOW*9 ;6a["Aoyy-a_ӎ4÷2~5Ty}`ZK/#{-FGg9k Eazd&8p/\-N͖` _{#pdl  M٧1?-+X hl1i7J/=$788ji?|,q'X~0ߍĊӛ>笹4\{(@jo#~ŷHڦ\P|D"ng?d svǠ~XN?cV/ޏYw&0<Ş}'_D ǙdBd2 c~tjwŽr: Mg?}C 5P"2 g|*zX{U"Holߡؿ` CK&Y N?sX$*bf{b>]}W E4#wp[Mf3 HjEur~ФLSܺk5*!f'r'D+-:x Ju.WL+Bj33ZJXO!2Ԩ_Ka ,ψؿRg]7000}u[ 8G#³+l' %߀awqa_:QZsvbx@r4o gzky2L[|ޫϿ^K tsH& МhF"ݤuxq8}?O!p5O!{brX~(ښc8(\T(3i/N _g\{9R)b 3X:&9]/;*LģA;#[6l1# ;vdq. $hnk(MGƒv'$"] eMԩ!¶4w5kO^Z׏SǼW&}5!^SRǝ̪o^ßnhxc!L͌lHfvCG( c Sq>%Gw ok_@%K< zzz8ŶtC2tMeWWz R  !ljAN0(zzzn.lURJ,²,Lt}3h4JGGgHkR|ƪo]Gq'4]M4 ]?g_WVE嚲74.X};L o980CJCk4X̙2 dYV[umGtvvD\4:;;E+K6= tÿZy,WΙ1OXP":::\op1=waD|T*UZ籿06nv|+ v۠vE @I$Zyb>/X !HdW>Sv(&ݗ}_T+c?[vF @b~} @k7̑!6}}wv06<]Px _4з W\3J%$4d2Ybs~vle'.࿯ơxk*sN|}sվd6\Lg෬A @pz9m ripڟ\vb)bX7b("NwW/ipΦ}Kz!ʪD1(Gc?>.e:+fz?~w'`5kVXֶ-J&I,?15d!Ϧ/^ޛ~X}&<08sۻS[ *Wfl`YlWlIJ|JD",:pj{dvcϯBFU`(r? |eqs6sI{uA5&@4ɤ[|O#s.k?Lk̑a6~ {W|-wtZ04xke|v~%w(_ŘsXxE>t6vرW J4 ]!wnZ8ֺ'IN!PPSJj_gtuuItx2/?5Pe~B4, 4}P.y kb̟wihVrNuO`{BxL @Mq(iFOE  Ptʪ];{j2OzYk7`gI!BQP__F׎~:t¿w6&l/怴, ٜj(5 '/F's?epLIξsxٗ`~,E!b /`/? x5ù) ǝCg߹q8ϗSŽFsHIPLFLՅX1Sр8 ,m{ ^heypnhyhXsW%|ԙDQ iQaԠtf=oH lCN=<{)ȿ-I绾 _]=/Ur*N44Xk(_+ˮcߓjϡZcqXg묞o Ҟ<];Iύ+WP!tt9V#U疎W:wSwca9ιP.rcaN$WJ٦~6kY';_JNp! T@ {6EڳlK ڳW-#Ym!$T;\ @m!~~Zߟy]7ZمP`Z@)w^u 3@( ExQP`(3% F B1QP`(3% ӌIENDB`doublecmd-1.1.22/pixmaps/mainicon/alt/dcfinal.svg0000644000175000001440000011261314743153644020771 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/alt/doublecmd.svg0000644000175000001440000006664014743153644021337 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/alt/info.txt0000644000175000001440000000010514743153644020334 0ustar alexxusersAlternative version of the main icon by Ivan Dzikovsky (vanyasmart). doublecmd-1.1.22/pixmaps/mainicon/colored/0000755000175000001440000000000014743153644017513 5ustar alexxusersdoublecmd-1.1.22/pixmaps/mainicon/colored/v4_2.png0000644000175000001440000001467714743153644021012 0ustar alexxusersPNG  IHDR_^EP pHYs  tEXtSoftwareAdobe ImageReadyqe<LIDATx] tչFZdyf'N:!!&!%Pвe+ByJr(=}4%@YZ KHH=!dKp8M,Y}sG3HdY#iՙhن,l+K`tB_؍0NYZ/lKuWhHZa|aovogP`~Q/Moي֬Þvm~|mKj7Ϙf w"C  '+~yI 0 c`x׻^.'@(c_u-];:vEybd1)R?sގIўmcd~& .voLbjn]{g_"饫reӰ۵, ߆kg\'<LJ`μ P%`hI;1{lXƔ,/e A'v ׎MbGTZx5pg =&WAg6\'|9|?MujaAo^i {x,ߘV ?v JZO$@rCxSj]H/|]^uTш cR[y<Hϫeod5nn9ßǻ?倭j?YG`ҘPGA7-1?ǎ 4|pucjajs.](Iȫ5'$=r `1f5MN }NʬcX?a5# HggW+n, [9SNC|P(O3\Cث. < oYF4nrf`R9{_ ,3mppp|y~<FèqVui_.zvGO q=o5~W} NMyg=]= Uv"bN\ms߇Jkʠi䩠[dv"4/2 (<Q6nw.?9BQǤ *B='j\1geٱoVx u bڼnȖnV|+9koa MA7ޟ,LdwNI] +V++[Ǧ[poL%]Oܰ\@>' H=F*r ;Һ1 nN`ҭ]A&I0cU!pZq~Þ?$gT9T![hq<-M] (7S ja3&ԥì9q+;;g~!;DtVuj`?zVԃ~PNi نL"3v|+\{A=CA.\fE$!'!Q BYqJVXILSNڴVFs :8}ѹ$@?yn [ѠLځ a ?;s9# a^F+Lfm $E1pr (_ ?y('$S;H@J)~z쟷%> jmYm¥=L/?743L~α*WHkp `B? iPU9& T†=SUObvt;(G'Sm/z>$'`1fؿ+j< ̖v/Ӛ>X4dpݺOt^AmV;U;HgSӓ)T& 3'nz!@ ~ 4r(ʨ1e^0ѕq%8m ҄qeTOQv/爴}uI`aHd s,"N!ҪBMg|!%v\vmx3l/?op)<>_Si^'6Ք!J$3tNL;0Hp Tɧ!^^8#9z ?O& 6 $$0¨#dFIT;^1w"FSFOCG6_Y|t#Ӊx@T/>EWF@d/IcLvrC:jO`E#u())Q ]Y{~\; lZ`~Hl>(T73 l%HTWE%^%/e:hz&Y  GQ-bP6TR) )騂+!k$8b* "R8 ģ}$nD$^"\|V䇔O_{BxV =&~9IE$ N PRA ~(5  Du1Щ6C ʲ_kC[ڨ/5QL[u5E3Uc( QDb[x~)իQ_ܼ_:FxGloy94. c+hye}ݹB+A= ҷH=уCNӌ%*_8IG4It3 ^P4r1I4 <@NPQUS9nXh6V0 O2Zhj94N72yUN:}O #B ~Ȍ3'Jꅂ)bRDHr )/%Gw[pat#VEk qe] }F!zDF4% )^aQ/D#n=U+;bN I R_1Ák,SP$ol{Q+z^15Q$y`@m`d-{bdj*b3$3&p^:Hl G8 {.]PtũB\=2E^Ζ`oA/=!뤩[mUD}eM&!IBLC*D38? 4(H`<).PQH!Wɕdm*yYʤ~˾ plݷC=rsU?*l!j$[å@r6 t.Ht.*E 6rxl~ѡw&(vO"CoX?a2$$""N 爀G4GXt:}:d3n54*p/#R ܤ R$VIKVˢQ)SQK9XWcJ cT=ͽAZkPi(^c;`PTBWgŚ"?Ο3pٷ.7@fѩjsRLϱŷV뿟6ymհ@Ʃ7^(ćyo',}HPLG:э*(ԏCi8QhxWFۂO'&T˂G=کO6qvKi2Ͱ_{ǝwP#M R)[>z08Ak ÔbzYE'u|~)lU΍ϊL;fT??_İ=Ūz9cymI )3DKi.jGSY+VYu}*'gˎm_]Γl868붽d?5ɺtǒNvcG?LyHx:}663*es(w)W5 ;41+U0r/ -ֈ}ޫI|ѹ.!lUGgOmqyw n{7$>l8) ЕڀOjNaS~ .-/oR-Zh 54Dpa9WKoϓ_g/Т LR kG|/p`On[O;57ۆ7=ZDPc'RO#W= +g.&On^ЌmV=)UWBFyj FZku@BxxS({ӂk.Esrb -cc? yVt_wFݓ1g ~jԫX%4VNI hPJ} *JcGS19r&'c ègǮq zP؏փ`1Ν܈c&CTOU4=5֣a^ y510퍑_V*-.4V @W_q=ۭa3&-2!5{-HL7\ĝ/GS/=\L7;\w~TLU7y@L&@(}9릠\}/yi/A (sQc}Ǝ)ylTLU.1Xf;-ȌI-q^ 4^PlsR+遦ؿ{raߊ siJM穭Q< Fk~H>C0T 8I46]; {Bgi<wy_Jv`J7s>IENDB`doublecmd-1.1.22/pixmaps/mainicon/colored/v4_3.png0000644000175000001440000001550614743153644021003 0ustar alexxusersPNG  IHDRgh, pHYs  tEXtSoftwareAdobe ImageReadyqe<IDATx] třhf$HIdY-6` 8!1`BBM&Yݷ<솗l^ 6vsuY1:f4W_S3YC2vLwW_GU7pbHY/q-U ' =^*v $C(/  i* QEUY 2EJ0r93dݗp-EngMAF<#8/%p`̂Q!ۿWss$!٧dwLq_rJKJa,pTR?;i-@8F kAa-)n{wAFT\iܹs-((ܱhp866ƁANC{eP]xX [\L3@3Ju*A]f@Ic텉d4q ^Za(1K![ˢPPRyCc0s 8 IAnDSq1 a8:N ʂ%E(`LmNu؜ReBv:(^|u8xv5E]SA6SϥmxHQo^#szM4GЅJ5Wr(**#T1gMԳHϻ^pS.V#7'$'+kQnBۡtf0GluaZJV%'7h+.g`H`2t+/Y;Vmʔnt5:no*g0Uup~ x XgN^QQ'j3VQ>rVLq]4VY;E1Qݦ/.9ڎ )V)PXX3vQfYJJJ _^[~֟w±Sܛ ZwE<:"l6v.<_ɒ=g |㭨0;C'sWnillt j߶kYc#^&Yr Y:KWT bĥӓ!=_|zPvdOV\KNW:1AAA v^qd5XIs?u_:FXa`lڴ)To]Y4 gf; 0^5HHtҵW3g[f# ʫ*!Lww7 c02`,l,'a?9y",a$^rAvyA/}͐0xUXǜ)>|=34ӗufgNȺ󎕎Bс]x,lq)G|Rrvj{DժNMEzգy5ˌԬXUUiqo7rJIN[H2ú~:VH u`p \n-YJ3yZkT]ެD*Nʟy)Ɨax,X{m?[XJyyQvR4ԉϢkr V7QJJiX@sOet7>}3gxcrهfק^#K`S7; o{ N!d<,@v``` j^%'q=Ԅa!d)kaWJهnc5 xHozxq+ÙjZ@Э,d64OtVg"Lvck.pwj\Vj S lve-PlLң9NilC;^|ެ+k'0B#-Gsssѕ_;BϪ3IY-GdWYd,:QZ5G$U `]0>' [3tIS0Zfd(p k5_C 7)|p}|f_i*.3\91.p F52™tqܒd-VbΧQk!?#A#(`R䐝=g sɓolSvLv$Jɫ>~6MYͭa`#sB K 99L9r8WH!YPT¥ јDb&@aG#;h4F"x"ɪV0U Q ktm(4ծu !zb$Fւc0 ѢMFLGKrhQ KȨ:Wyge&lBQ7I̸Ycs(N? E!ψ%`K#ƗN:*Nv*'Lni繷SQˠHUah9[A"VAbc,o09ᠰ9qK(vq5G\R<ֆpL"ؤ}q IS.}GZ0B `B%q|dlH/?(h@QT+uMQ=S ,sIS!צ'Qb hDNpdU @(98"JCE_.LJ#ozP<WQ&FUΆ;0ШDF:&)JVrp GG$D ҀoY%xGbcq'2on%glga>W\*Vb''oj,0ўĀJ ;A+yH {={1$~_gF&@i&mq)G@ {J $&KQe-oH:\o wwƪ4HKjC~EzE@MQAQE YH 6쟻 ;COo3~ޮCd38達bAHQYWX+QW0G4P;:^A {HW-$AշW_)l9Qu I kF|_xvF鍗aK_9kSH)o}j4HIC]cW+Stpoy1uoz϶#mi@{+_J$hwgeђqr!Y+aЫlanZތ9N]g*a|>R1 <:GQnZ,c(049n<Q,ZFUC;L{XW|Et9{ix.?C0Ou֕3;T6 !ʮk.Xlv57EY[6/P@R3!]c|X?o6lBw~z9]mpFE˩ۖt'.p]5(EJ|ɏSUJDJRP/,z MUX/ b}HT,,tt'.z̹Q&SyZ6Z^߉CKX3>z#@rzd*Fd*B֓z0Nka{8wg3w Lp>дjc7M;8:@ޣ?e;J ~ vF$(#ić%2Kٳht(z?a{!cfC?NH(f&vi = |ϋ?#RilxdF/> ;L[Q/qØn.d+m~Ӡ{ù70ҪM\%4|}=M7sud"m0 < gP|hB*r<=@=_Bͪ5~s'3E3@] hniVuténq3 ;{r:uB  K. og_~)$X^nV52hs`v,e?S=ş|{;E])E^&dԸ 8Aqx嵫+{a{ .\&!@$( L.fm܄oc[_XB0 &Sk;/BswBZtL嵚-h%|$)Oc]+}vSH_Qi$v{`6k.o[> Ko@=.1X'q$_TyeK+/GU ?GfN@W;818{vO8xUy-uP[¬ B=mAH7b%ă]#]uߋq>Wݕ&׀;y^>kwT7AktaIσYWko[MKq(\p+{+vׇfF LF.-@a^cK!(Q0|$-SM<BUsb~c~aUk}|pl (u#)!+ӤxówPvMF u>3YP0 $IQ`T1]f +P8x`TX{m6ǖkU/Z{VtwyH=¶+N4LdhM gRf9qiC&<DG 罂?~1 kUy>4RdԀdTR,$*>EeJ@Qem7M$:AH%tـ)}8)2jT!ACLW 4<0 j/kƅcp8@o P| @3ZRmoXIENDB`doublecmd-1.1.22/pixmaps/mainicon/colored/v4_4.png0000644000175000001440000001514314743153644021001 0ustar alexxusersPNG  IHDRe]U pHYs  tEXtSoftwareAdobe ImageReadyqe<IDATx]y\G}zcg[ڕVuYucc)\_IA2$e*EP1|#cccK6`Z[,jW{ưwfv8R׾ury:3<jfg>ѹ.{AN*QUØ \"w5v=N?.\TXJ$ҿ|pѠşTֺæ{Vׂ8fqD-6ve~1Ai퇓4|LfՒ;?vd?c=g=Sl^[2cQD$InxN4_"IJ#y:17T-TnB\AifߝRnAq΁=~Ï}a PZ6?ܱկ~;WH3!!!L/rɓDYO9@w}*`=O irF#'75ٚ/+C)”ϕk_FЭIQ1Ux\H ܔhI h%o4y$=!Fc(hQPP5xD6M>Qp(-,!SHvb3,ՁKušP ̭TiAhaת eʒ؃^r8kN4uOJyT34)e.|OGvۤ=1Iz8;FJ'+q_U_C*SOz//I‘0"0$;l6'2S[;"j5OGWH^fΜ~ll?, }UUjjsB011#\$:Xe ] 'ՀdE MY D CV!Fk ?+o9@$fJ١5NtFpYKee%nA0ĥqfΎy[EZl qф֘$wNaJ& 1PJ=>@}kry߳I%E izva?'.cbFքV8&kZjc`.e h8RVSdk[jBE,\.>~:GFƕw4bZM#i J%PH #P$cd3¦:;/P`@)F Nmm-0s B B5ih?|odyQucX*P Qt[cswEXMk;[ݲE vˢV&%ýݏu0b,HEj<]kRQD4=+P]]J+◌SFx^|#Wf1*yuM ,s$ZjIܵ\DtSRo dYaD04Eˍ v.'Zj@r/~nggs+c!&rC= ̅z5hk[`"'|ż ~+(/Y?Y7,zMvԻWUGRcp,P 3[֔yqjj 'f0>x/90ON+.s[Sw^Jг]:=E'؟y"a=$F4>TGzO g[WL?\[d-:; l]\R.LJy8.gmު)e3+s7g?g43e1.2_w.X ̦bTak>$"O l ED2&}9ec[E&RCCC8x1ڴa!sXR)2ziMm,*~qɍCcY|q[[@d1ßl_&/g2/Ϟ:B/GKKgI# ţ82UT/ 8o< I48|nҮn#:=2;yqNd?^W7~kkz0 ?[:&]Nmg,`1__ `0SAƔ:w%eɬg >) *JSs>6?[梼ↆlv/kcY P49D܎+~era3ÜnӀp7^@^lq)1gR29Uac:t9aD r̨.9Os 0 L M%!D`k#[^W jfB+`#Qb9%!zEa:Ƚ!՛ȊK֔3N(q]Bpm|jD^X4ŕk:%&ZQ [ "$Q|;}namfQe9~}&љ&4S+œ| {4"wU\BI(W358jwTy- ]L72\V(~F!E 4RFs %%7pA*:ʀ)@߈AuF0<@wse5 3]քn(Tdr+w)u(*@QKO(҈@z6ԎsȍMIQpAϴ׸e/{<lxRaٲ)E%HK_xH[UYA0 WN1nQcgφEC5VQqcr?- UPCH\a&b9=zvc4a?B D\ FEp8-6K"e ȫxE=~O_ֱRENN[U~LQ-cI"\w"xAPByɁ*S(H3τ=MxhQj`*+ UM"ZulY_+,]sZW\CzcLrn*T[71/Qeups.b0l\B"M{g tYؘ(HH-T9 ^QP25ˉ`r ~5PfU>$ 0%D]x~SKffA(Y,KTK c`04/ V \_+9 tN>l_X^Z<ɩ01/j쳡BKZL|AiuTkf^'f*M~bPQrLnJSO/ys .:,Fjs*GĪjp$^hn̾]1uT[hJjwˣorܱ 4&4/PȂkXTni^}^/1>[|ʍM˙1fۥՆ>ei)MyyfS||΢{&QK-WOZ08{G#|bs`|=3|W Iz*Y):h󢹡J^6ǩZ.;0YϷgirz^pC(|C0b(h>ZN_Ǜz2h^SηUgN#;:n \)IUW吭)N֯%IfA8nzւWzt]2 P %975o\]}0)&$ܿqA?*wgN|뾍9c_Hh+~T/v #<3H^'NOlv bkgOѼ@֙k#zNΛqC{BZ>27{ /Wxqh~;njNZ6(rYʓ"juJt6;[p꾡x4cT$+~wuW߸}YTҔj,2=5+02mlm<5TU:nk*mUiZVSv;>@ASxefzшOC-gyRJIENDB`doublecmd-1.1.22/pixmaps/mainicon/colored/v4_5.png0000644000175000001440000001334314743153644021002 0ustar alexxusersPNG  IHDRe^:ڡ pHYs  tEXtSoftwareAdobe ImageReadyqe<pIDATx t[WOeٲdyQǻ%5{ڐd2PJ,@[Z8sPsf:90 P 4ӆ6]HC$MqR;݉E}idKO4,=w[wqHCrq%E''{\%{XAo\3W_s&CLt=rx=s>":($.AI35a+ryKfMFM1 )1{Xqy*+9jDL99I{}v؇z~ H >ߺtOWrݵPRZ.)15텏}<-ڹ) o3}8^8]8g/?/Gzf9[KXT*5|=p⭿O ~> J?-wZWZ6;y0qBǺF B/}T@l@c})-xaaCvKBoVT61LL2c>0d k4d*6^e ] A!b.isͶ;W^ dO̡?8-Z`{ '쮥'?u&C%˷nݺ _qnӘ|ivY?_vXиC2>v+)`YC{B+/Ϻe:t9`յ otҖ\cNrWj/`ȃŲRP&¤ݻwdje/L; JؤVߵs|WYi. M:, ^T,6}7JvY0(рHQYwU$=v| S{Xز(g"eRK"=Xf{ǩ6{ Ȧ|]5***d ,(DᔖOYpNG=ZV41ȴ$(.%K𥻚P_BޕnkFyyyЛv(je!2I vﹳNJ[TQ!L&D5ۛQTT)^0IQZ Z]%(2g?2]dqۇ*w@U_T@(FGd4,G:96c@rrrX=*AxuN |. :j4~'cdנ€%z=x@P98Wy7Zg |ąq`tC`Ӗl3Ra1硳ow=>o㻾F+eVf <م\F]&`ODa>ۏN r1Bs~oo{4Σ͑3~lX-YL(, }_x3LF7l I ^>؉3z0eWE$uq={8\}[6uf*YSc m>_`r-j:' hd 8QuoD/:JT}$2*+%YfUTM**? ) Hj ,62˟c PUOj$ ySalv(Ӏ0M``Gz'\@u! $.DIIHj. (Wtig!>J",[#}]trLRfOd"T*-B)RCapt @ m-,9KA4+F1dÌ?Q;wގIG&Sa@Da?p;ң c6fyB` OG)[ Ս6aXeݧR#h/a B`טK&IOԄXM:j8E">-A%=]Z\4Zvg\P$s}AXNS DžmˠB@"U[J bH !C%\>,j#c2` RRJt(FS,CM尾U螑j,1L{ ϊjLMJ"2/F$bY.8nB4W8uVZ2ɕnЈ; "L4$NrbzJ %Àa!# @踪Y5(Чos\p A+ΝIi2V8:AdӘ#UfAԜ}1t{<);x:~+gLT0ˍRn"k̋0 <#WԚOdRCҳmcjL:IOk'FŋZ%NzՓ)sK Aw$b7ȰR;R$)rxmd2^u\{M`el7#v>fb5`~FSk 1*)(t+ՓK^,< _C[mKJ*TyOGN09X̌B<~7U^UwR>oVŒ\xt\!N5=9 dE9`#dbcaЋEV҃vdvfOi.TR3x3j+rV\ HHEf oN(} q:wU%H ٓco)'85e |=F9 a(@ J6I[>TUd(vQ/}m>rsMaե6:>q慩I ޻TI{H}Q<)O Yr<߾Yo=콫$]owHwzrD5l[}A"P_hb1E=)_ ѾgعUc j;ml|j gO[ln 1{$[mBP/̝mGFHBEB[?|h9CQ,Dؓ]0%+s߾odctiJЭ aTݻ*7haKb??=T&I̝n#_Uͦ/M T#(4̭>Z7mJx㉧G$)I }'1T$bx7aϏ8'3P(ކ0uPg0~ri=.SxvUm@e;cݍT/a05 j ַԪN-tHƇiҪ:F? |ҋSgqp?ИC}V]P鎎MϸJQRK;7k:27{?:#IsP|-|,RoF{1: :,Y;e6O)1>ŋw*POW")S Ixi 'ֽ9ZåZaN&Rm6<4~J>7e{gjD$M%?s<4 +?b@iE+khI{_v_+%{?9ֳ fAz.|Y=;{끓AIuӟ\A}_|MRY# Q/VHrov6Jd]Rˣ/m׾;./!UvCm#&뒒 Kۻ_ HG3k^<3V{6WϊPg}ϝHĭ_xM?e6L7RU~9uz>1uk+X#8TwS G 3Ӓd8ޓ1Aw|U3* ]Kc^  {xM7^8DG_>4&Q4յګkG5jY\~%șlLA VfxMc4 \wRΏr0s~u%+o=vtۤ<~ f+ P]aƆ\f^cG |ֶ}#۰*lKo;:=9eWGP*V:7H}.ICYM_yb@}Mgp6|QK&xLCRXՓ˖h-yN:gCs_k # p(աyi)99~eSxuvqiAp͞,uܬyp%IkV,O@+M(C\=c^4 _EL&I0@wwPŔ،6W;yqȽ7~" a^0ٵ^ 7us@BP(\iiox9LLz/.90(fv\#{c;oi˷mUkk`^%@EGMV3$&& yYW_2^|)z]}_yKtyokKPl4ot j=Ø@eãQyTKC1]= kt9ZnG&$8u_帢 И*]nQ<\1P@q֚ؿ$Eϣ^l'wA>ߪ~O{Bx.`IENDB`doublecmd-1.1.22/pixmaps/mainicon/colored/v4_6.png0000644000175000001440000001723314743153644021005 0ustar alexxusersPNG  IHDRe^:ڡ pHYs  tEXtSoftwareAdobe ImageReadyqe<(IDATx]yl}f#x߷(uٖhۉlNa$ îhu.?i uAHRmMq⤎8,[m]EEJ<^3-I)p۷;;|k~3$]+7[+IbI["YyRj@+.A4b"EQ/*AF DcwS|hW'EVMkHȤU dk~ P|lV_j^kkCq$>ľ gM*ީ"Nk=slOj7  %b tb"g>R 5BDmAD97Zvٰcl^:ϰ0(+b1V_9WŁuS߶c}A0yc BEDhuKZ/Ɛ{g@cJB Xbh"4:0THeKu9AM"7޹~!n,, /kz"lo:>.c4ow~ns\/QwISf{v/ElmCSnSPJ t|<]IT9XzٴB>^Z\n}N:Hq_Y4۩|/M}&]n:f5!衺3Ise=C:c!ljb2u8hseLWy\g7LvLB}mtq"(SO >ڊd*pv*qc:@_ |L,r5eq,jdP\Bsh+O15ڧhA ڧSBOq`/),ۧI/9ƬQtrtӨ3V u1(ȠXmBV򭾾w67#J)9و$ڄe5dcBD㘒ؓ 3$!H gI\ .  .Ҹܵx1 7a 59 8Ő{ &@ !TX;TU."Kh7MMxYm]@7ޓ*++=>1NOȀ qMOi)E|?RA?6s7/Wze52XpZZZ@COHӄ$vt$1C@H1d(Qb<+2zSسMF0˺mxnՋ{;PIduʢD3 E)iMT TSyݳ eeek3 n͜1Vmʠӵ&wz0TWWs.c )t0,R Gr~ˍޭ&E5cƸKFmv7 ?$.;7g S|-6Ck]ˍDoCœUoQ"YLݡD s{;:ր8K/k|OY؉`YG;эМY^~7מEooێ[p eXsÂ3x` U99tWͲJ VP3hk*s.SJxSߘ6`ao޼AǙ\lB6Q圉|Չ8>Pc{#1zӊv2JWeD(EykS k qlw8c:ouHPVw3ggxbdbbg/cl)x3re F\Jo@ɞ+_`9+ańYZzNNqܽ35ZQv Gcj"J(V]Icw<eM̸x"1I6 [XΣ&-CAd!B];~~ ÃMxyt :\wvNÛ[7xi;J Yvi6#Rҧ (OV~tpYCs-46yͫ90n"8}b\Oe',zڎ!^R =[՘S֙pGW :ZY_ҁ~k1ZhYX%xbs9kqzҪ_{Fk-uBN)"/جćDݫWs!Vʔ)Rβ+%GX  :HȀ9:ق؁wN ؽEd*2 P9 X'%I^y 80=R &g/Y3!?=?g(Y= u6bhh(0؍Q ]4c˽rs`ꉝNbdǎ#`r+<4!0BGr [L26@e 7_kz-20h^%Óry$5P3kc^C#8EٶM 7[ɮHŐ/,z QKRƸX1&Df;#1$gM)wpNmii W)"K@B8J_zrys8Vq Op:]UTT`WˌK,}8YǂOWH*Euޠ\kxKdZT&XfeJ Xe׷p%C\`ٰMs=7 oE\bM$r|{Ǘ*PPG{Ch$`DE,]`_(@cGp%`\CՓ.S3{TemPEQͷ##¤U Gw5FKaDAA"^^b{!>L7ZpӶya㗺% t]l ;`H9^xU1h4L&q.IBMjoH! w:i[D#,R9ǴMѣڔ"na28n8"Ru<r uzgʁPiS`PQ5"Ǻ,7>"%$Hq284ePYF#j &z$kPJh :G#~F W/6RKF;W7ZiXHS/^("Q@fxv ASrB!",8JdMGMJI?əfOF*u "S𵒨k똵P5/:ALS:1#(YeT)Y*$6&TKB&3ӕ]Uz P,|]|9,+)'eb:H$nchr{TKX] H!oRW O=u1&v\:p!r#tCdɭc9dD! q& g"w6zG4B[IH2T0ÇMҴYb-[U,^.|*%; @M1j;H>QF TMZ'+j+r>G (6cPJiEUsŘ'Qkӯsdp|# Q!>C\E9LIm41\`YؽJ?y1"/H`Q]H9 aڂD$7[*ScS<5m8~r A@.dZk6(%Z_ħG"TE}:FexCX3%*^!~$ ;;qKRgI(+P+iΪ i9b8f^Rŗ) Uc\y.T7EjE|ʍ߸ׂSMG`c! nȳQy9γb>|.˦W@.{\UV34ZWȵ> lcI&RGT9KwLD*af}`mG`a[7m?s'ӕR@j̚jRb[ux3 /z@X7{k 2yR4$S1Deα9wL%JvdʝH; y:23)S1 J1yX??E--M, Qdmq\/,?\U2-sxyB ~E1y!q)8I ,$ }A M]E1k-KB Y9)^1ჃחzOλ3;jej1v~²Db''.⌔RQ2ROv~bbj :s }Ѣ|w} )GkߺRY[G$Sv~[ZC\`b'(:I h%{F- }F 뾾ˑ3ͶO$ dV9lQ6{QNJz?iL|z%?0cH: +S DA3{vƭJD_D/&JdKV"^溨vs6@YA霔#3xwZ*s1J(/׻ydpӉLF#7/v֛'c߸i+ Ea '&Mb]i cD/9oVjm"tGK x4Pjc5{#7KE&|nJf +,af|f1ߔ?y ^Xg8H .YaoT3,zuq;ESz'؂uQer86)ĬY+c1ux!YG˾gBGuy2)rWpF ]JFJЭn %00vVai[D)%'K|D#b)YvO5`b)P@2晱ěu08;P[O-`\c]-iM,w|p뽈sxrpŵu ?\D6pػq|z|w)Cb%y%5oGwkڒA7z:H96ۄU=/_?g>P93^{SzŁ c"oMsןC,}ծe=_B˯ /T]H$st36>T9vo9>}  Xt5c},X|Yu=έtY* 1:iE+]Yu-7(d{~XBȐ)|o_} ,V!gi~x`2U +_Fz6)V*col>[}=6Β:!P6)3O-jH ߩb:Gf膺0!Uys]+$vsI)*+7&{BD) qDȽP4\|vlm:vkb;_}3ؙ {+/B4L-z MJ,,wN{脅6ȉs-_"+`,F"@K2|@?\SPzeճLMjq,@Q ѳr2V[e'jm^ܛ~8>'HPR\?j ? <] \͵E7sK⋷(:B) \n|٤䋭)Wrsk- w-a.3h>co^#ҽ"<^Ua w6$ϝ J(XyBM_dg*AOr_^܀O{|Z&݁UpQ/G$Os,|F_2c(G| R2WUK7♳.m>Qz)==qOnƏNB&ʭ#&, ~3ּN|e7<ܩ8.Ϊlzd޽k*֔r`MxW?oU4p*_?Ϙ?]]zJu Qo {{ьNI4}B~g(vtWjEкֳStDHpA&-QWrfr/\^:<[{o20:8kNsyqK (Y{?)&#655z  9O;pP}hItI'[n!gb``caketK~HR@V aJ> r@ε+\Z\W' 2ٺ1]W EG0<Қ`&-֥]<=ʁ܈ZY3@>[e58ѻ wFbjLxa¶` IENDB`doublecmd-1.1.22/pixmaps/mainicon/dc.ai0000644000175000001440000130231014743153644016765 0ustar alexxusers%PDF-1.5 % 1 0 obj <>/OCGs[5 0 R 6 0 R 120 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream application/pdf v4_3 Adobe Illustrator CS4 2009-11-23T23:45:51+03:00 2009-11-26T01:53+02:00 2009-11-26T01:53+02:00 256 256 JPEG /9j/4AAQSkZJRgABAgEB0wHTAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAB0wAAAAEA AQHTAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqhtR1TTN MtWutRu4bK1T7U9xIsSD/ZOQMaSATyYNqX59/llZOyLqT3rqaEWsEsi/Q5VUb6GyQi3DTT7kkm/5 yX8lqf3FneuPF4+H6ueS4B3r+Wn3fchD/wA5OeXqmmlzEdiXYf8AMrD4Y71/LT7vubT/AJyc8uFh z0yZV7kMxP3GIY+GO9fy0+77lUf85NeUajlY3QXuQCTT/gRj4Y71/LT7vuVf+hmPI/8Ayy3v/Isf 1weH5r+Wn3fc7/oZnyN/yy3v/Isf1x8PzX8tPu+53/QzPkb/AJZb3/kWP64+H5r+Wn3fc7/oZryN /wAst7/yLH9cfD81/LT7vua/6Ga8i/8ALLe/8ix/XHw/Nfy0+77nf9DNeRf+Wa9/5Fj+uHw/Nfy0 +77nf9DN+Rf+Wa9/5Fj+uPh+a/lp933O/wChm/In/LNe/wDIsf1x8PzX8tPu+53/AEM55E/5Zr3/ AJFj+uPh+a/lp933Nf8AQznkT/lmvf8AkWP64+H5r+Wn3fc7/oZzyJ/yzXv/ACLH9cfD81/LT7vu d/0M75D/AOWa9/5Fj+uPh+a/lp933O/6Gd8h/wDLPe/8ix/XHwvNfy0+77nf9DPeQv8Alnvf+RY/ rj4Xmv5afd9zX/Qz3kL/AJZ7z/kWP64+F5r+Wn3fcpN/zlB5LDHjZ3JXsSCD93E4+F5r+Wn3fc1/ 0ND5N/5Yrj8f+acfC81/LT7vuVIf+coPIpP762u0FeqJz2+nhj4Xmv5afd9zKfLv51/lxr0iQ22q pb3MhokF2PRY/Sfh/HInGWEsUo8wzhWV1DKQysKqw3BB7jINbeKuxV2KuxV2KvOfzB/NC503UV8s eVoFv/M0wBkZ94LRG25y06t4LjKQgLk5Wm0pyHyYJJ5YsJLr6/5qu5vMutdWM7kW8RPVY0HwgDwA pmsza48h9jvsGiAGwofj8bo1LiKAcbO0trRR0EMKL+JBzClmkXOjp4jvaN/dn9v/AIVf6ZDjLPwo rRqN4Ojj6VU/rGHjKnFFx1a+/nT/AJFx/wDNOS8QsfAj+CVp1e//AJ0/5Fx/804fEK+BH8ErTq9/ /On/ACKj/wCacfEK+BH8ErDrF/8Azp/yKj/5px8Qr4EfwSsOsah/On/IqL/mnD4hR4EfwStOs6h/ On/IqL/mnD4hXwI/glYdZ1D+dP8AkVF/zTh8Qr4EfwStOtaj/On/ACKi/wCacfEK+BH8ErDrWo/z p/yKi/5px4yvgR/BK063qP8AOn/IqL/mnDxlHgR/BK063qP86f8AIqL/AJpw8ZXwI/glYdc1L+dP +RUX/NOPGV8CP4JWnXNS/nT/AJFRf804eMr4EfwSsOu6l/On/IqL/mnDxlfAj+CVp13U/wCdP+RM X/NGPGUeBH8ErG13UiCOafRFEP8AjXDxlfBj+CVFtX1BhvIPoRB+oY8RT4UVM6rf/wC/f+FX+mPE U+HFoavqCnaUfSiH9Yw8RQcUVZPMd+u0kcEynqskKUI/2IXJCZYHTx8/msuG8n6qpj1XRoomb/j4 tgEYE9/h4n8Tl0M5DRLSnob96aaB5r8yfl4Y7qxu5PMHkpmAuLRzyntgTu0ZPSn8p2+WZmPMJ7H5 us1GiB5CpPoPRNa0zW9JtdW0ydbixvEEkEq9wdiCOzKdiOx2yZFOolEg0UbgQ7FXYqx78wPNSeVv KOo6zQNPAnC0jP7U8pCRD5cmBPthAZ44cUgHj3lfTZtJ0p7u7cy67q7G4v7p/t/GdxX57ZpdVqTO V/L3PWabTiIA6D7/ANn3oo5hOcsOFK04oWHCqw4qsOSVacULGxVYcKrThVYcKrDihYcKrTiqxsIQ tOFVhxVYcKrDhQtOFKw4oWHCq04qsOFVhwqr2OoTWcrMoDxSDhPA32XQ9Qf65IGmucBIMw/JTzKf L3nOTyo0hOha8HudJDU/dXSrydK7UEiKQR/MAB1ObHFk4o+YdF2jpq9Q/H4+59BZN07sVQVxrOnW 9w1vLIfWUBmRUdyAeh+FTirz3814bzzGNBsNOgkuLCC9a81B+DJxMMZWFSHClg5kPSvTK83FwER5 udoJ44TuZpKrvSdSaY0gYItFQmg+FRQHc+2aeWjy3y+530O08AH1fYf1IOTT7tOqb+AZT+o5E6XI OjbHtHAf4goS29xGKvGyjxKkDK5Y5DmC5EM8JfTIH4qJyDYsOFVhxVYckq04oWNiqw4VWnCqw4VW HFCw4VWnFVjYQhacKrDiqw4VWHChacKVhxQsOFVpxVaqO7BUUsx6KBUn7skEEgc0bF5d12YVSwnp 1qyMo+9qZMY5Ho48tXiHOQ+aIHkrzM9eNn08ZYh+t8n4E+5q/lHB/O+w/qdL5L85wSafqFlp/LUN KvIbu2HqQkH03V+NedKbGo98uwwlE7uPn1uCYri+w/Hp3Po8eYNLIqJJCP8AjDN/zRmU84jba5hu YVmhblG9eLUI6Gh2ND1GKpNckjV7uhpVYq0/1Tirub/zH78Vb9WT+Y/firjLIRQmoPUGh/Xiqg9n Yyfbtoqn9pVCt/wS0OKpdd+VtFuan0zEx8PiH0k/H/w2VTwQlzDk4tZlh9MikGo+QrlAXspBKB+z 3+7r91cw8mgH8Jdng7aI2mPkxa7sbu1cpPGUINCSNq5g5MMocw7nBqseUek2hTkHIWnFCxsVWHCq 04VWHCqw4oWHCq04qsbCELThVYcVWHCqw4ULThStAJNAKk7ADFBZDovkDXtUYMYjbw92cfEP9jtT /ZEZkQ08jz2dbn7UxQ2HqPl+tm+l/lXo9uA14xuJNiQxJH3Div38syo6eI83VZe1MsuXpHkyez0D SLNOFvbqi+Aov4IFH4ZcIgcnAnklLeRJRiW9ulCsSKR3CrX76YWCrzelORoOmKu5v/MfvxV3NvE4 qjtB/wCOXH/ry/8AJ1sVQF1/x1rv/Vi/4icVdirsVdirsVdirsVUbuztLxOF1EJRSlT9oD54CAdi mMiDY2LDNd8jyRBp9PPqRjcxnqPo/wA/ozAzaIHePyd1pO1yNsm472ISxvG5R1KsOoOa4xINF38Z iQsGwpNgZLDhVacKrDhVYcULDhVacVWNhCFpwqsOKrDhVYcKE00HyxqetThLaMiKvxTEbDxp4/51 y7FhM/c4mq1sMI33l3PU/L3kTSNIVZHUXF3+1Idx9/8AT8cz8eGMeTzmp1uTLzO3cyQUChQAqjZV AoB8gMtcR2KuxV2KuxV2KuxVH6D/AMcuP/Xl/wCTrYql91/x1rv/AFYv+InFXbYq7bFXbYq7bFXb Yq7bFXbYq6uKpD5h8r2upRmSFRHdDcEbBsozYI5BvzczSayeE7bx7nnF9Z3FnO0E6FHXx75qMmMw NF6rBnjljxRQpyDctOFVhwqsOKFhwqtOKrGwhC04VWHFVhwqynyj5IuNXkW4ugYrJaE1qCwP9cy8 Gn4tzydRru0RD0w+r7v2vWLOztLK3W3tYxHGoAoKVNPGmZ4FPOykSbPNW2wodtirtsVdtirtsVdt irtsVdtiqYaD/wAcuP8A15f+TrYql92f9y93/qxf8ROKra4q6uKurirq4q6uKurirq4q6uKuriqT +Y/L8Oq2xIFLpB8DePt8/wDP5VZsQmKLk6XVSwyscuo73l91by20zwyji6GhzTTgYmi9dhyxyREo 8ioHItqw4VWHFCw4VWnFVjYQhacKrDirJ/JflJ9Vuhc3C0s4jU1Gzf19h/DMzT4OLc8nUdpa7g9E Pq+79r1mKKOGJYol4RoKKo/z65sHnF1cVdXFXVxV1cVdXFXVxV1cVdXFXVxVMdB/45cf+tL/AMnW xVbdaMZruS5juXhaUKHULGw+EUB+JTirFfNuo6hod/p1tFP6y3sdw7MyRAqYGhUUonf1jmNqc5xg EOw0GjGfis1SR/4x1bxU+3FP4LmH/KJ7nZHsSP8AOPyVovO92G/ewoy+1a/ryce0R1DVPsSX8Mvs /tTO084aZNQS1hY+O4zJhq8cute9wc3ZuaHSx5b/ALU6hnhnTnC6yL4qa/fmS4CpirsVdirsVdir FvOnl4XcBvbdf38e7gd/9v8Az75janDxixzDseztZ4U6P0H8W85bNQ9WsOFVhxQsOFVpxVY2EIWn CqY+X9Fm1bUEt0FYwR6h9vDb5fdl2DFxnycPXaoYYX/EeT2awsYLG1jtoBREFK0pU+ObUCnkpSJN nmiMKHYq7FXYq2AT0xVKdW81aBpSn63drzHSOMhjkZSA5tuPDOZqItiV/wDnDYIStlZNJ4O5oP4f qyk6mPR2GPsjKeZASeX849YP93ZxJ9Ib9a5D815OQOxh1l9n7VKT849fW3kkEEVU6Ci+BP8AL7Yj UnuZfyPH+cXsWmafd3mm2l2966PcQxysgjioC6BiN17VzLdDIUaTewtBaWqW4cycKku1KksxY9KD qcUK+KvPfzPA/S2hnuIrwV+b22a/tDkPe77sT+P4fpYYc1D0Cw4ULDhSr2WpXllIJIJCpHau2X4t ROHLk4ep0WPL9Q37+rNtC8021+BDcERXPj0U/Pw/V8s22DURye95rV6GeE77x709IIND1zIcJ2Ku xV2KtEKwKsKqRRgehB6jFXl/nHRjp+pM6D9xMeSn3P8AX9dc1WrxcMrHIvT9larjhwn6o/cx45iu 1WHFCw4VWnFVjYQhoKzMFUVZjQAdSThCk1uXrXkjQk07TVmcAzzCvL2PX7z+AGbfDj4I08frNScu Qnp0ZJlriuxV2KuxVD3+oWen2zXN3II4lFanqaeGAmubKMTI0Ny8s80/mXf35e202ttadOY+0w+n +P4Zh5NSeUXe6XsoDfJue5g8skkjl5GLuerMSSfpOY127iMQBQ2CkcWSw4oWT/7xzfL/AI1bJRR1 fWukoU0qzQ9VgiB+YQDNo8Xk+o+9FYsHYq8+/M//AI6uh/8AGK8/4nbZru0OQ97vuxOU/h+lhZzU vQLDhQsOFK04oWq7IwdDxZdwRkgSDYYyiJCjyZz5V8yi7VbK7aky0EUh79gD/DNzptRxij9TyvaG hOE2PoP2MlzKdc7FXYq7FUk826WL/SZKD97F8Sn/AD96fRXKs2PjiQ5Okz+FkEunX3PKGBGx2I6j NK9ksOKrDhVacVWNhCE88naSdQ1ZKj93GRU+BNd/oUE/OmZWlx3K+51naufgx8I5y+7q9gVVVQqi iqAFA6ADoM2bzDeKuxV2KobUtRtdOs5Lu5YLFGK/M+GAmhZZQgZEAcy8U80+ab3XLxnkYraqf3MP ag6E5rsuYzPk9TotFHCO+XekJylzlhwqsOFVhxQsn/3jm+X/ABq2Sijq+uLD/eG2/wCMSf8AERmz DxeT6j71fCwdirz78z/+Orof/GK8/wCJ22a7tDkPe77sTlP4fpYWc1L0Cw4ULDhStOKFhwq6OV4p FkQ0ZemThMxNhry44ziYy5F6b5f1ZdS09ZCazR0WWvU+Dfhv75vcWQTiCHjNRgOKZieiZZY0uxV2 KtOiujI4qjgqw8QRQ4q8g8xWTWmrTxHuxaviakMf+CBzT6mHDMvW9nZuPCO8bfL9iVHKHOWHCq04 qsbCEPTPy500Q2DXLD4nGx93ox/4UJm100Kh73le083HmPdHZmOZDr3Yq7FXYq8j/MTzM2oX5sYH P1S32YDozdf8/wCzMHU5bPCHoeytJwx8Q8zy9zCzmK7hacVWHCqw4VWHFCyf/eOb5f8AGrZKKOr6 4sP94bb/AIxJ/wARGbMPF5PqPvV8LB2KvPvzP/46uh/8Yrz/AInbZru0OQ97vuxOU/h+lhZzUvQL DhQsOFK04oWHCqw4qnvk/U2tdSELH93N8JHap/tofozYaHJR4e90vbGnuIyDmOfuZ9658M2jzjXr nwxV3rnwxV3rnwxVgX5gW4+tR3IFOVOX+yFAP+SZP05ga6OwLvOxcm8o/Fh5zXu/WHCq04q3FE00 yRL9qRgg+bGmSiLNMJy4QSej2PRFW30yFEWisOYHsxqv3LQZuwKeIlIk2Ud658MKHeufDFXeufDF Up806z+j9EuJtuZXio9zt+PT6chklwxJb9Nh8TII97xKR3kdnclnclmY9STuTmpJeyAAFBSOFVpx VYcKrDhVYcULJ/8AeOb5f8atkoo6vriw/wB4bb/jEn/ERmzDxeT6j71fCwdirz78z/8Ajq6H/wAY rz/idtmu7Q5D3u+7E5T+H6WFnNS9AsOFCw4UrTihYcKrDircEpinjkrTiwJp4d8sxy4ZAtOfHxwM e8PTYp/UjRz1ZQT8yN86B4hd6gxV3qDFXeoMVY353jEmnBx1Tf8A4ZQPwJzG1YuBdj2XOs487YAc 1L1Sw4VWnFUXo6c9TgHdSXHzRSw/Vl+nFzDh6+XDhkfL79nrcdI41jHRAFH0Cmbd5Bd6gxV3qDFX eoMVYP8Amben0LS1B2di5/2I3H/DDMTVy2Adz2Njucpdw+954cwXoFhwqtOKrDhVYcKrDihZP/vH N8v+NWyUUdX1xYf7w23/ABiT/iIzZh4vJ9R96vhYOxV59+Z//HV0P/jFef8AE7bNd2hyHvd92Jyn 8P0sLOal6BYcKFhwpWnFCw4VWHFVhySs/wBLnL6bbMepjFfmd832I3AHyeI1MaySH9I/eivUyxpd 6mKu9TFUn80MG0t6jYBiSfZGb+GU6j6C5ehNZo+95y91EO+aW3suEqL3sQx4k8BUW1BBjxJ8NNfK VyLjW4kFOhP3/D/HMrSG8gdb2vGsB94eq+pm2eSd6mKu9TFXepirzL8ztSEetwwntAHof8okf8a5 r9ZL1AeT0vYmO8cj/S/Qw79JR5icTufDd9fiOStjwFv63Ce+G0GJb9aM9GwootcgehrhQtOKFk/+ 8c3y/wCNWyUUdX1xYf7w23/GJP8AiIzZh4vJ9R96vhYOxV59+Z//AB1dD/4xXn/E7bNd2hyHvd92 Jyn8P0sLOal6BYcKFhwpWnFCw4VWHFVNmA6nCrNdJ5fo22PYxqR9IzfYPoHueL1n99P+sUXVvHLX GdVvHFXVbxxVKPNUhTRrgk7COU/8kmynUH93L3OXoBeeH9YPIHvD45z3E+gcCg92fHG08Ci92fHD a8DIPy/uifMsK9SyMB9FG/hmXoT+8Dqe3If4OfeHsdW8c3bxLqt44q6reOKuq3jiryL84i0XmC1k 7SWqr7VVmP8Axtmr131D3PW+z++KQ/pfoDAfrh8cw7d7wO+unxw2jgbF+fHDaDBcNQPjkrYGCoup sO+SEmJxq6aqfHJCTA41dtSVrOYH2H/Ctk4lqMN32NYf7w23/GJP+IjNoHh8n1H3q+Fg7FXn35n/ APHV0P8A4xXn/E7bNd2hyHvd92Jyn8P0sLOal6BYcKFhwpWEgdcUKEk6L74LZCJQkt74HAZNgxoK S7ZmCruSaADxOR4mzgp6paQCG0ghH+641X+n4Z08I0AO588yz4pmXebVOOSa3ccVdxxVjfn+YQ+X bk9+FP8AgnVP+N8xdYaxF2XY8OLUwH45F4w8pznrfQKUmlOG00pNIcbWk48k3Qi802LE/aMiAe7x Mq/icytHKsodb2xj4tNP3fcQXvxAJNOnb5Z0D581xxV3HFXccVeX/nnYt9T0vUFHwxvJA58S4DL9 3DNf2hHYF6X2cyeqcO8A/L+14+ZTmsespaZjhRS0zHxwopr1z45JHC76yfHDbHhXC7PjkrYmKsLw /VpBX9pf1Nk4lrlF912H+8Nt/wAYk/4iM3AfPMn1H3q+Fg7FXn35n/8AHV0P/jFef8Tts13aHIe9 33YnKfw/Sws5qXoFjEDrhVDy3Cr0wGTIQQM92fHIGTbHGgJbk+ORMm0QQkk58cjbYIo7yrZPqGu2 0Q+xGwlc9gFO1f8AZUrmVosfHkHlu6/tbP4Wnkesth8f2PWWIrtsvRR4AdM6R4FrFXYq7FWA/mxe +npkduD8UsiinioqzfiEzXdpTrGB3l6D2cxcWcy/mx+/8F5OzHNI9qpsThVTY4qq6befUtTtLz/l nmjl/wCAYN/DLMcuGQPc06jH4mOUf5wIfSts4e2iYGoKgVHcr8JP3jOnfMCFTFXYq7FWO/mDojaz 5SvbWNeVwi+tbjvzQ1AH+sQBlOox8cCHO7N1Pg54yPLkfcXzQTmhfRVMnChYWwqsLYULS+SRTXqY UUvWX/R5P9df1Nk482Eg+/rD/eG2/wCMSf8AERm6D5tk+o+9XwsHYq8+/M//AI6uh/8AGK8/4nbZ ru0OQ97vuxOU/h+lhEkiqPfNQS9CBaBnueu+RMm6MEBNcHffKzJujBBSze+RJbBFCyS4LZiKGeTG 2VPTPIGhtY6a19OtLi7+yD1VB0/X/nTOh7P0/BCzzk8N25rfFy8Efph9/X9TKKZsHSOpirqYq6mK vG/zP1MXWuJbK1UtlJP+tJQ/8QVDmj7SyXPh7ntvZ3T8OEzP8Z+wftthbHNc9ApMcKqbHCqxsKH0 D+XmqDUvKdnITWWFRFJ41T4N/nw5fTnRaWfFjBfOu1cHhaiQ6E3892R0zIde6mKupirqAggiqkEM PEHYjFXzr+aflN9B8wySxL/oN8WlgYDYMTV126daj7u2aXV4eCVjkXu+xdb42LhP1w2P6CwljmM7 hY2FVNsKFNjhVYThQvVv3D/66fqbJx5sJP0FsP8AeG2/4xJ/xEZuw+aZPqPvV8LB2KvO/wA1H4an oZ8Yrz/idtmt7RPpHveg7CF8fw/S87nnO++aQyeojBATS5AltEUHLJkbbQEK74LZAKDtiypknkry q+qXS3l0tNPhNd/92MOw8R/n45s9Bo+M8UvpH2ug7a7UGGPhwP7w/wCxH6/7e56jQUAAooFFA7AZ 0DxDqYq6mKupiqE1W8istOnuZW4JGpJbw2JJ+hQTkZSEQSejPFjM5CI5k0+e9SvZL6+nu5NnncuR 2AJ2UewG2ctkmZSMj1fTsGEYoCA5RFINsi2qbYVU2wqpthQ9I/JfXlg1G40eZ6R3Q9SCp25gAOB7 7K3yU5s+zstExeY9o9LcY5R02Pu6fjzevlSCQdiOubd5F1MVdTFXUxVJ/Nfley8y6NLptyKOfit5 aCqSD7JFf8+3QnK8uITjRcrR6uWDIJx/tHc+ZvMGg6loWpy6dqERjmjPwn9l1rQOp8D/AGHfNHkx mBovoOm1MM0BOB2Spsi5Cm2FVNsKFjHCrY/uH/10/U2TjzYSfoRYf7w23/GJP+IjN2HzPJ9R96vh YOxV5r+bzcdR0I/5F5/xO2zV9qfTH3vR+z4+v4fpeaTSZoiXrAEHI++RtsAQ0jYGQCgxJNBuTill XlnyFc3zLdakDBZ1qIjs7/0GbXSdmmXqnsO55ztLt6MLhh3l39B+v7no8MEMEKQQII4YxREXYADN 8AAKDx0pGRs7kr6YWLqYq6mKupirzf8ANfzCqxpo8D/E3xXFP5Qen0sKf7H3zV9pZ6HAOvN6b2d0 XFI5jyjsPf8AseXNmlexU2woU2wqpthVTbChW03UbjTdRt763NJrdw6jsadVPsw2OWY5mJBHRqz4 Y5YGEuUg+mNG1S21jSLbU7Zucc6Dl4g+/vtv71zo8cxKII6vmufDLFMwlzCLpk2l1MVdTFXUxVIf OXknSfNmnfVrweldxgm1vB9pGIpv7eI7/cRVmwjIKLm6HXT08+KPLqO986ebvJGveWLxoNQgPoVp FdoCY3r037HbofoqN80+XBKB3e40XaGLUC4nfu6scbK3OU2woU2wq2P7h/8AXT9TZKPNhJ+hNh/v Dbf8Yk/4iM3gfM8n1H3q+Fgoy3lnC/CWeON+vF3VTT5E4q84/Nc/XL7RGs/9JEa3QkMXxheTW/Hk VrSvE9c1vaUJSjGhe70PYOWEOPiIGw5n3vN5bDUK0+rS/wDAN/TNH+XyfzZfIvUDWYP58P8ATBZH oes3BpFZysT0qpH66ZOOizS5RP3Nc+1dNDnMfDf7k0svy91m4YG5KW0fepq33ZmY+yZn6iA63P7S Yo/3cTI+ewZZo3k3R9MKycPrFwP92yb0+QzaYNFjx7gb95ee1naufPtI1HuHL9vxT075lutdTFXU xV1MVdTFUt8xa3baJpUt7M1HoRCv7RbpUe/h7+wOVZsoxxMi5Ok0ss+QQj1+zzeBajfT395Ldzms srVPgB0CivYDYZzGTIZyMjzL6Rp8EcUBCPIINsi3KbYUKbYVU2wqpthQpthV6L+UHnRdM1A6Lesf qV637gn9mU/s/wCy7e/+tmx0GfhPCeRec7f7P44+LH6o8/d+z7vc9sdOJ61B3Vh0IPQjNw8atpir qYq6mKupiqy6tbO9tmtb6BLq2ccWjkAYUPbfAQDzZRmYmwaLzTzL+QOg6g7T6Hdtp0rb/V5Bzir7 AkUr7NT2zDyaKJ5bO90vtBlhtMcY+Recax+SP5gaex4WSXse59S3kFKfKT0z92YstJMebu8Xbumn zJj7x+q2L3Hk3zbDIUfRr3kNjxt5GH0MqkZX4Mx0Lmx1+A8px+YWDyp5p9Fx+hr6vNf+PabsG/yc lHHK+RWWsw/z4/6YPuyx1HT1srdWuYgwjQEF1BBCj3zcB87yfUfejY5I5EDxsHRujKQQfpGFgxXW wv6YuDxBJWPcgHoD44qgwQOir/wK/wBMVbLk+H0AD+GKrSSepOKupirqYq6mKupirqYq6mKqdzcW 1pbSXVy/CCIEsSQK0FaCuAkAWWUIGRAAsl4f50813Gv6izA8bOI0gjFQDTblQ/h/UnOc1mqOWW30 h7/sns0aaG/95Ln+pjTZiO2U2wqpthQpthVTbCqm2FCm2FVhJBBBoRuCMKvdvys/MGLWrNdG1OQJ qcA/cysf7xfH/mr7++270mp4xR+oPDdsdlnBLjgP3Z+zy93cz9kKsVYUI6jM10bVMVdTFXUxV1MV dTFW1d1+yxX5GmKrjK5+0Q3zAP6xiq2o/lT/AIBf6Yq6o/lT/gF/pirJvLgpo8I7cpaf8jWxVJdb /wCOxP8A6sf/ABHFUHTFXUxV1MVdTFXUxV1MVdTFXUxVSu7m1srV7q8kEUCCpZiBWnhXIykIizyZ 48cpyEYiyXjvnfzxca7P9Xt6xabHsidOdD1Pt/tnsBoNZrTkPDH6fve57J7IGnHHPfJ9347/AMGI NmA7tTbCqm2FVNsKFNsKqbYVU2woU2wqpthVdbXVxaXMdzbSGKeFg8ci9Qw6ZKMiDYYZMcZxMZCw Xvn5c/mbZeY4E03U2W31eNaIa/DIAOq1/V1Hyzd6bVDJsfqeF7U7JlpzxR3x/d7/ANbOXjZG4tsc y3TtUxV1MVdTFXUxV1MVdTFXUxV1MVZP5e/45EP+tJ/ycbFUl1of7mJ/9WP/AIjiqDpirqYq6mKu pirqYq6mKthSTQCp8BiqUa/5p0fQoS1zIJLgj93boakn6P8Aa98x8+phiHqPwc3Rdn5dRKoDbv6B 5D5n826pr0/K4b07ZT+7t1Pwjwr4nNBqdXLKd9h3Pc9n9l49MNt59T+ruSBsxXZKbYUKbYVU2wqp thQpthVTbCqm2FCm2FVNsKrGwoWxyywypLE5jljIZHUkMrDcEEdCMINIlEEUeT1/yF+diqkemeZ/ iQfDHfjan+uB0+fTxp1zaafW9J/N5TtHsEi54f8AS/q/U9dge3uoFubOVbi3cBldDXY7jpmxBt5i USDR5uphQ6mKupirqYq6mKupirqYqyby9/xyYf8AWk/5ONiqTax/x17j/Vj/AOI4qhaYq6mKupir gpOw3xVtk4CshEYPQuQv68VSrVfNGg6Wp+tXIMg/3UtQ33UL/wDC098oy6nHj+ouZptBmz/REkd/ T5sC1/8ANG/uVaDS4/q0J2MjAcz/ALGrD7yfozU5+1SdoCvN6bR+zkI75TxHuHL9f3MFuJ5p5Wlm dpJXNWdyWYn3JzVmRJs83pIQjAVEUAoNgZKbYVU2woU2wqpthVTbChTbCqm2FVNsKFNsKqbYVWNh QpNhVY2FU88seevMnlqYPpt0RCDVrWSrRHx2qCv+xIy/FnlDk4Gs7Ow6j6h6u8c3sXln89vLWpBI dbjOnXR2MvWMn/XAp/wQX55ssetjLns8vquwc2PeHrj9vy/U9CtLzTr6JZrG7iuIpPsMrD4vka0P 0HMsEHk6ScDE0RRV2idPtKR8xhYraYq6mKupirqYqyPy/wD8cmH/AFpP+TjYqhtQ0a8nvpLiIwlJ FUUk5ggqKfs4qxvzdqE3li0tbu8hilhurgWq+lzJV2jeRS3Jl2PpkfOmVZ8oxxMiLpy9HpDnnwAg HzY/P+YttA4U2lahWBCmhVhUdZPfMCXasB0LtYezuWQ+qP2/qQU35oUH7uz3/wBgv6xJlR7Yj0i5 EfZmfWY+SV3n5n604IgjWIH+Zmb8E9MfhlM+15nkAHLxezOIfVKR92362PX3mnXruoku3RT1SKkY +nhQn6cw8mtyz5y/Q7TB2TpsXKAvz3+9JWJNSdyeuYzsVNsVUmwqsbCqm2FVNsKFNsKqbYVU2woU 2wqpthVTbChTbCqm2FVjYUKTYVWNhVTbCqm2FCvp+r6rpkpl0+7mtJD9owuyVHg1DuPnk4zMeRas uCGQVMCXvZfpX53efNOCq1xHdoNuMqFdv+eRjqfc1zJjrJjzdVl7B08uQMfcf12yW1/5yRv1UC80 hZW7ukqgf8D6Vf8AhsvGu7w4E/Zofwz+z9qZx/8AOSWimvraRKp7cKH76yrkxro9zjn2cy9JR+1M NN/P7RtQvtPsLbR7h7vUrhLW2jPEVeR1jUn970LN+By3HqRM0A4+fsTJiiZGUaHv/U9i/QepEfZt h785T+FMyHSptpNnLZ6fFbysHlTkXZdgSzFtq/PFUXiqS+cvLieY/LN9pBf0pbhA1tP/AL7niYSQ v8lkVSfEZGURIUeTdp8xxzEh0fP9o81/aTWs8Rt9Z0p3hvbJvtoUJ5r78WqQe6n2zmdTppYzwnpy 8w99ptXGYEx9MvsP7UFIMwnZAodxgZKLDCqk2FVNsVU2wqpthVTbCqm2FCm2FVNsKqbYUKbYVU2w qpthQpthVTbCqxsKFJsKrGwqpthVTbChTbCqm2FVNsKF1tazXUwiiG9CWY7KqjdmY9lA3OEC2MpA Cy9g/wCcbvI7a75ybzRLGTonl+sdizjaW7YEKQCP2Axc06MVzb6bDwRs8z9zyfbWu4h4cfj+PsfV eZDzbsVdirsVeZfml+Vl3rN0vmfyvKLPzRbqFkWvGO7jT7KSeDjoreGx7UhkxRyCpOdo9bLCf6Ly CTzLpxu3sPMlrL5e1uM8ZhJGxgZh34j4lr7VGafUdlyG4ep0vagI7x+Pxuik0/61vY3Vreqehgnj Y/8AAkhvwzWy0s49HaQ12Muby9q/++P+HT/mrIeDLubPzePv+9Rby7rH/LP/AMOn/NWHwZdyfzeP v+9TPl3WP+Wf/h0/5qx8GXcv5rH3/ept5d1j/ln/AOHT/mrD4Mu5fzWPv+9Tby5rP/LP/wAOn/NW HwZdy/msff8Aepny3rX/ACz/APDx/wDNWHwZdyPzWPv+9YfLetf8s3/Dx/8ANWPgy7l/NY+/71M+ Wtb/AOWb/h4/+asPhS7l/NY+/wC9YfLOt/8ALN/w8f8AzVh8KXcv5rH3/ept5Y1z/lm/4eP/AJqw +FLuR+ax9/3qZ8sa5/yzf8PH/wA1YfCl3L+ax9/3rG8r67/yzf8ADx/81YfCl3L+ax9/3qbeVtd/ 5Zf+Hj/5qw+FLuX81j7/AL1jeVte/wCWX/kpH/zVh8KSPzWPv+9Tbyrr3/LL/wAlI/8AmrD4Ul/N Y+/71h8qa/8A8sv/ACUj/wCasPhSX81j7/vUz5T1/wD5Zf8AkpH/AM1Y+FJH5rH3/esbyn5g/wCW X/kpH/zVh8OS/msff96mfKXmD/lk/wCSkf8AzVh8OS/msff96m3lHzD/AMsn/JSL/mrD4ckfmsfe sbyj5h/5ZP8AkpF/zVh8OS/msfesbyjryrzlhjhTu8s8CAfe+SGKR6MTrMY6/ehZ9O0ez31DV7eo /wB0WVbqU+1VpGPpfMiGimfJxsnacB9ItnnkH8n/ADP549MRWcvl7yc5Vrm+uP8Aeu8QUICVAqp7 UHAf5RGbDFpo4/Muh1vapO17vqzy55d0jy5otro2kQC3sLROEUY6nxZj3ZjuTlxNvPykZGymWBi7 FXYq7FXYqlHmHyj5a8x2/oa1p0N6g2VpF+Nf9VxRh9+ESITGRG4ec6j/AM4y+Qbhy9pLd2lTXh6n qKPYA0/XkuIdQ5A1mQdUvH/OLugAUGsXAA7cD/1Uwej+az/P5e93/Qrmgf8AV4uP+AP/AFUxqH81 fz+XvXJ/zi55bDfvNWuWXwVSp+8u2NQ/mr+fy96//oV3yl/1c7z7/wC3BUP5oX8/l73f9CueUv8A q5Xn3/241D+aF/P5e9r/AKFb8o/9XK8+/wDtxqH80L+fy97v+hWvKH/VyvPv/tx9P80L+fy97X/Q rPk//q5Xf3/24fT/ADQv5/L3u/6FY8n/APVxu/v/ALcfT/NC/n8ve1/0Kv5O/wCrjd/f/bj6f5oX 8/l73f8AQq/k7/q43f3/ANuPp/mhfz+Xvd/0Kt5N/wCrhd/f/bj6f5oX8/l72v8AoVXyZ/1cLv7/ AO3H0/zQv5/L3u/6FU8l/wDVwu/v/txuPcF/P5e9r/oVPyX/ANXC7+/+3G49y/n8ve7/AKFS8lf8 t939/wDzdjce5fz+XvWSf84oeTyB6eo3KnvyBb9TrhuP81fz+XvUJP8AnE3y0QPT1aVT35RM36pl xuP81fz+XvUJP+cTdH5fBqvJfFo5FP3CY4eKH81fz+XvWf8AQpmlf9XMf8BL/wBVcPFDuX8/l718 f/OJeiE/vdV4jtxjkb9cy4OKH81fz+XvTKz/AOcT/wAvUcNeXF3cU3Ko/pA/OvqH8ceMdAg63J3s 38tfkz+WflyRZtN0G3NypDLc3INzIGHQqZi/A/6tMiZFqnqJy5lmuRaXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq//9k= xmp.did:1909C3C878D8DE11BA3FC4734EDA5420 uuid:79f4e077-af0a-49b0-8661-3c88af079b47 uuid:4BC73B30D582DE118E9E833D7C53E1E9 proof:pdf xmp.iid:1809C3C878D8DE11BA3FC4734EDA5420 xmp.did:1809C3C878D8DE11BA3FC4734EDA5420 uuid:4BC73B30D582DE118E9E833D7C53E1E9 proof:pdf saved xmp.iid:1709C3C878D8DE11BA3FC4734EDA5420 2009-11-23T23:40:14+02:00 Adobe Illustrator CS4 / saved xmp.iid:1809C3C878D8DE11BA3FC4734EDA5420 2009-11-23T23:44:22+02:00 Adobe Illustrator CS4 / saved xmp.iid:1909C3C878D8DE11BA3FC4734EDA5420 2009-11-23T23:45:49+02:00 Adobe Illustrator CS4 / Adobe PDF library 9.00 1 True False 100.000000 100.000000 Pixels Cyan Magenta Yellow Black Default Swatch Group 0 White RGB PROCESS 255 255 255 Black RGB PROCESS 0 0 0 Charcoal RGB PROCESS 63 63 63 Graphite RGB PROCESS 102 102 102 Ash RGB PROCESS 140 140 140 Smoke RGB PROCESS 178 178 178 Latte RGB PROCESS 228 188 150 Capuccino RGB PROCESS 213 151 88 Mochaccino RGB PROCESS 139 92 41 Chocolate RGB PROCESS 90 61 28 Mars Red RGB PROCESS 143 0 0 Ruby RGB PROCESS 191 0 0 Pure Red RGB PROCESS 255 0 0 Pumpkin RGB PROCESS 255 64 0 Squash RGB PROCESS 255 127 0 Sunshine RGB PROCESS 255 191 0 Yellow RGB PROCESS 255 255 0 Chartreuse Green RGB PROCESS 204 255 0 Fresh Grass Green RGB PROCESS 125 255 0 Pure Green RGB PROCESS 0 255 0 Spearmint RGB PROCESS 0 163 61 Holly Green RGB PROCESS 0 107 51 Sea Green RGB PROCESS 1 83 83 Caribbean Blue RGB PROCESS 4 115 145 Mediterranean Blue RGB PROCESS 0 160 198 Aloha Blue RGB PROCESS 0 96 182 Black Light Blue RGB PROCESS 0 60 255 Pure Blue RGB PROCESS 0 0 255 Sapphire Blue RGB PROCESS 34 16 210 Tanzanite RGB PROCESS 66 16 210 Brilliant Purple RGB PROCESS 93 16 210 Violet RGB PROCESS 130 16 210 Purple Orchid RGB PROCESS 171 16 210 Fuschia RGB PROCESS 208 16 177 Global Pure Red PROCESS 100.000000 RGB 255 0 0 Global Squash PROCESS 100.000000 RGB 255 126 0 Global Yellow PROCESS 100.000000 RGB 255 255 0 Global Pure Green PROCESS 100.000000 RGB 0 255 0 Global Mediterranean Blue PROCESS 100.000000 RGB 0 160 198 Global Pure Blue PROCESS 100.000000 RGB 0 0 255 Document endstream endobj 3 0 obj <> endobj 122 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>/XObject<>>>/Thumb 148 0 R/TrimBox[0.0 0.0 100.0 100.0]/Type/Page>> endobj 123 0 obj <>stream HVMo1 W7wN=}a *$NfUZ3dz>ݟ=kfӿK}>П_K=}C}I.QeJt.L>.@kuāLe*uDS:MW7;Ʋ۪xx&XN!v|TЪxS{긦X { CC\lNz}T7_`}EtR+^s]w:#EJ>ɜ3E/ʐ f}gO*3-.mҋG "c2%%3f&/aNM,rBޡ ܊ė@`3amUH״xɩI`tFKjHL6RTD\ȅmL1|!#vƒ!`wUC.\ĴX4w϶ i xvo#?Ē} 5f("fJlH&< ֣}sTEH!3_s{mJ٭d@=U`BF'vHhn "G k %|AM$N`c8B hB#F"bHLiUs-ő̆eg00;P֡eG v'Ly]h1`A򤌉UlgCc}K/ ?Y9^;)5SKFLҸ;F4$4:ۨiiI6jjч\9L&8v qwPkFfj^&7濻Oku endstream endobj 124 0 obj <> endobj 148 0 obj <>stream 8;TH&Yml4;%(iAMQZNRi0YmpAU7%IPRh*W\fQTk76<7pUNf5GP5e+@-2h3.j-C=c[ X>?7'ff1<=MJ!eeY$4!s/8sW4K8q\C--cHIW\"sBhR',F>s<)t)$&!h:Po~> endstream endobj 150 0 obj [/Indexed/DeviceRGB 255 151 0 R] endobj 151 0 obj <>stream 8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn 6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 136 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream q /GS0 gs 103 0 0 104 -1.2519531 -1.7480469 cm /Im0 Do Q endstream endobj 137 0 obj <>/ExtGState<>/Shading<>>>/Subtype/Form>>stream q 96.212 15.058 m 96.212 8.931 91.243 3.962 85.116 3.962 c 14.845 3.962 l 8.717 3.962 3.75 8.931 3.75 15.058 c 3.75 85.329 l 3.75 91.457 8.717 96.424 14.845 96.424 c 85.116 96.424 l 91.243 96.424 96.212 91.457 96.212 85.329 c h W n q 0 g /GS0 gs 69.5471954 0 0 -33.9607239 63.3984375 19.1269531 cm BX /Sh0 sh EX Q Q endstream endobj 138 0 obj <>/ExtGState<>>>/Subtype/Form>>stream /CS0 cs 1 1 1 scn /GS0 gs q 1 0 0 1 93 13.6084 cm 0 0 m -25.587 0.464 -43.041 26.396 -33.12 50.419 c -28.93 60.568 -19.768 67.936 -9.37 70.94 c -5.22 72.14 -0.952 72.174 3.324 72.174 c 4.029 72.174 6.644 72.262 6.644 72.182 c 6.644 67.061 l 6.644 65.776 6.838 58.987 6.461 58.987 c 2.456 58.987 -1.518 59.179 -5.454 58.312 c -15.31 56.142 -22.082 46.627 -22.181 36.807 c -22.256 29.279 -19.142 22.479 -13.3 17.724 c -9.507 14.636 -4.445 13.187 0.386 13.187 c 5.256 13.187 l 7.01 13.187 6.644 13.519 6.644 11.56 c 6.644 0.959 l 6.644 -0.574 6.697 0 5.212 0 c 0 0 l -0.006 0 -0.006 -0.727 0 -0.727 c 6.647 -0.727 l 6.651 -0.727 6.651 -0.382 6.651 -0.363 c 6.651 13.55 l 6.651 13.568 6.651 13.913 6.647 13.913 c 1.272 13.913 -3.796 13.736 -8.885 15.822 c -16.377 18.895 -20.912 26.35 -22.019 34.097 c -23.294 43.028 -17.92 51.391 -10.417 55.671 c -5.163 58.669 0.841 58.262 6.647 58.262 c 6.651 58.262 6.651 58.605 6.651 58.625 c 6.651 72.537 l 6.651 72.556 6.651 72.899 6.647 72.899 c -3.479 72.899 -12.49 72.064 -21.092 66.079 c -29.982 59.893 -35.861 48.978 -36.065 38.143 c -36.462 17.169 -21.49 -0.336 0 -0.727 c 0.001 -0.727 0.01 -0.001 0 0 c f Q endstream endobj 139 0 obj <>/ExtGState<>>>/Subtype/Form>>stream /CS0 cs 0.584 0.584 0.584 scn /GS0 gs q 1 0 0 1 99.999 86.4976 cm 0 0 m 0 -8.302 l 0 -13.343 l 0 -14.996 -0.466 -14.557 -2.103 -14.557 c -12.256 -14.557 -21.036 -16.68 -26.366 -26.228 c -29.246 -31.387 -29.334 -37.473 -27.891 -43.036 c -25.236 -53.265 -15.646 -59.047 -5.554 -59.047 c -0.591 -59.047 l 0.405 -59.047 0 -60.057 0 -60.909 c 0 -72.331 l 0 -74.685 -4.432 -73.544 -6.389 -73.544 c -11.539 -73.544 -16.433 -72.595 -21.206 -70.663 c -45.354 -60.88 -50.09 -28.242 -32.323 -10.372 c -23.38 -1.377 -11.978 -0.061 0.001 -0.061 c 0.002 -0.061 0.002 0.061 0.001 0.061 c -11.299 0.061 -21.256 -1.08 -30.389 -8.501 c -38.647 -15.212 -43.442 -25.866 -43.442 -36.442 c -43.442 -47.266 -38.896 -57.359 -30.929 -64.642 c -22.124 -72.689 -11.302 -73.666 0.001 -73.666 c 0.002 -73.666 0.002 -73.608 0.002 -73.605 c 0.002 -58.987 l 0.002 -58.984 0.002 -58.926 0.001 -58.926 c -5.466 -58.926 -10.659 -59.158 -15.828 -57.009 c -23.162 -53.962 -27.593 -46.601 -28.671 -39.005 c -30.005 -29.606 -24.512 -20.828 -16.31 -16.705 c -11.27 -14.171 -5.458 -14.678 0.001 -14.678 c 0.002 -14.678 0.002 -14.62 0.002 -14.617 c 0.002 0 l 0.002 0.068 0 0.068 0 0 c f Q endstream endobj 140 0 obj <>/ExtGState<>>>/Subtype/Form>>stream /CS0 cs 1 1 1 scn /GS0 gs q 1 0 0 1 14.8452 5.4121 cm 0 0 m -7.936 0.536 -9.893 6.795 -9.893 13.469 c -9.893 32.113 l -9.893 75.597 l -9.893 81.944 -8.775 87.948 -1.341 89.471 c 1.944 90.144 5.865 89.562 9.176 89.562 c 54.925 89.562 l 64.029 89.562 80.164 92.408 80.164 78.776 c 80.164 39.824 l 80.164 18.135 l 80.164 13.798 80.814 8.887 78.813 4.905 c 76.173 -0.348 70.332 0 65.428 0 c 45.917 0 l 0 0 l -0.004 0 -0.004 -0.5 0 -0.5 c 69.621 -0.5 l 81.847 -0.5 80.169 11.979 80.169 20.255 c 80.169 66.216 l 80.169 74.311 82.756 90.062 70.197 90.062 c 36.13 90.062 l 0.292 90.062 l -12.077 90.062 -9.897 75.947 -9.897 67.797 c -9.897 23.346 l -9.897 14.734 -12.484 0.343 0 -0.5 c -0.007 -0.499 0.015 -0.001 0 0 c f Q endstream endobj 141 0 obj <>/ExtGState<>>>/Subtype/Form>>stream /CS0 cs 0.051 0 0.231 scn /GS0 gs q 1 0 0 1 96.21 15.6602 cm 0 0 m -0.51 -8.207 -6.845 -11.073 -14.005 -11.073 c -31.712 -11.073 l -75.974 -11.073 l -81.106 -11.073 -85.64 -11.367 -89.66 -7.347 c -93.249 -3.757 -92.454 1.974 -92.454 6.579 c -92.454 51.744 l -92.454 61.266 -95.718 80.139 -81.072 80.139 c -45.235 80.139 l -11.168 80.139 l 3.628 80.139 -0.004 59.402 -0.004 49.96 c -0.004 -0.603 l -0.004 -1.31 0.008 -1.31 0.008 -0.603 c 0.008 69.019 l 0.008 75.759 -4.091 80.954 -11.094 81.389 c -14.36 81.592 -17.705 81.389 -20.977 81.389 c -66.85 81.389 l -76.392 81.389 -92.466 83.879 -92.466 69.668 c -92.466 37.513 l -92.466 0.048 l -92.466 -6.693 -88.367 -11.889 -81.365 -12.323 c -78.098 -12.526 -74.753 -12.323 -71.482 -12.323 c -28.145 -12.323 l -18.302 -12.323 -0.883 -15.476 0.004 -1.205 c 0.027 -0.829 -0.018 -0.293 0 0 c f Q endstream endobj 142 0 obj <>/ExtGState<>/Shading<>>>/Subtype/Form>>stream q 0 12.893 m 0 27.511 l 7 27.511 l 19.56 27.511 28.824 37.6 28.824 49.23 c 28.824 61.688 19.354 71.88 6.794 71.88 c 0 71.88 l 0 86.498 l 7 86.498 l 27.178 86.498 43.443 70.131 43.443 49.334 c 43.443 29.467 27.178 12.893 7 12.893 c h W n q 0 g /GS0 gs 0 73.6044922 73.6044922 0 21.7211914 12.8925781 cm BX /Sh0 sh EX Q Q endstream endobj 143 0 obj <>/ExtGState<>/Shading<>>>/Subtype/Form>>stream q 0 12.893 m 0 27.511 l 7 27.511 l 19.56 27.511 28.824 37.6 28.824 49.23 c 28.824 61.688 19.354 71.88 6.794 71.88 c 0 71.88 l 0 86.498 l 7 86.498 l 27.178 86.498 43.443 70.131 43.443 49.334 c 43.443 29.467 27.178 12.893 7 12.893 c h W n q 0 g /GS0 gs 0 -73.6054687 -73.6054687 0 21.7211914 86.4975586 cm BX /Sh0 sh EX Q Q endstream endobj 144 0 obj <>/ExtGState<>>>/Subtype/Form>>stream /CS0 cs 1 1 1 scn /GS0 gs q 1 0 0 1 0.356 13.2451 cm 0 0 m 0 8.438 l 0 13.143 l 0 14.115 2.06 13.55 3.32 13.55 c 13.909 13.55 22.95 17.372 27.326 27.653 c 29.708 33.251 29.104 40.175 26.962 45.689 c 23.033 55.81 13.212 59.351 3.217 59.351 c 2.514 59.351 0 59.261 0 59.342 c 0 63.506 l 0 69.293 l 0 70.263 -0.188 72.537 0.183 72.537 c 9.645 72.537 18.18 71.9 26.43 66.685 c 35.703 60.824 41.198 50.575 42.517 39.882 c 44.149 26.65 37.354 13.875 26.674 6.444 c 18.582 0.813 9.46 0.363 -0.003 0.363 c -0.009 0.363 -0.009 -0.363 -0.003 -0.363 c 11.069 -0.363 20.82 0.816 29.774 8.043 c 38.14 14.795 42.738 25.448 42.738 36.089 c 42.738 46.924 38.443 57.006 30.446 64.339 c 21.808 72.259 11.113 73.263 -0.003 73.263 c -0.008 73.263 -0.007 72.919 -0.007 72.9 c -0.007 58.988 l -0.007 58.969 -0.008 58.625 -0.003 58.625 c 5.372 58.625 10.439 58.802 15.528 56.715 c 23.021 53.643 27.556 46.187 28.662 38.44 c 29.937 29.509 24.564 21.146 17.061 16.866 c 11.807 13.869 5.803 14.276 -0.003 14.276 c -0.008 14.276 -0.007 13.932 -0.007 13.913 c -0.007 0 l -0.007 -0.41 0 -0.41 0 0 c f Q endstream endobj 145 0 obj <>/ExtGState<>>>/Subtype/Form>>stream /CS0 cs 0.584 0.584 0.584 scn /GS0 gs q 1 0 0 1 0.0005 12.8926 cm 0 0 m 0 8.303 l 0 13.344 l 0 14.997 0.466 14.558 2.103 14.558 c 12.256 14.558 21.037 16.681 26.366 26.229 c 29.246 31.387 29.333 37.473 27.89 43.036 c 25.236 53.265 15.647 59.048 5.554 59.048 c 0.592 59.048 l -0.405 59.048 0 60.058 0 60.91 c 0 72.331 l 0 74.685 4.433 73.544 6.39 73.544 c 11.54 73.544 16.434 72.595 21.206 70.662 c 45.356 60.881 50.09 28.243 32.324 10.373 c 23.381 1.378 11.979 0.061 0 0.061 c -0.001 0.061 -0.001 -0.061 0 -0.061 c 11.3 -0.061 21.257 1.08 30.389 8.502 c 38.648 15.213 43.443 25.865 43.443 36.441 c 43.443 47.266 38.897 57.359 30.929 64.642 c 22.125 72.689 11.303 73.666 0 73.666 c -0.001 73.666 -0.001 73.608 -0.001 73.605 c -0.001 58.988 l -0.001 58.985 -0.001 58.927 0 58.927 c 5.466 58.927 10.659 59.158 15.828 57.01 c 23.163 53.963 27.593 46.601 28.67 39.005 c 30.004 29.606 24.512 20.829 16.311 16.706 c 11.27 14.172 5.458 14.679 0 14.679 c -0.001 14.679 -0.001 14.621 -0.001 14.618 c -0.001 0 l -0.001 -0.068 0 -0.068 0 0 c f Q endstream endobj 146 0 obj <>/ExtGState<>/Shading<>>>/Subtype/Form>>stream q 100 86.498 m 100 71.88 l 93 71.88 l 80.441 71.88 71.175 61.791 71.175 50.159 c 71.175 37.702 80.646 27.511 93.205 27.511 c 100 27.511 l 100 12.893 l 93 12.893 l 72.822 12.893 56.558 29.26 56.558 50.056 c 56.558 69.925 72.822 86.498 93 86.498 c h W n q 0 g /GS0 gs 0 73.6044922 73.6044922 0 78.2792969 12.8925781 cm BX /Sh0 sh EX Q Q endstream endobj 147 0 obj <>/ExtGState<>/Shading<>>>/Subtype/Form>>stream q 100 86.498 m 100 71.88 l 93 71.88 l 80.441 71.88 71.175 61.791 71.175 50.159 c 71.175 37.702 80.646 27.511 93.205 27.511 c 100 27.511 l 100 12.893 l 93 12.893 l 72.822 12.893 56.558 29.26 56.558 50.056 c 56.558 69.925 72.822 86.498 93 86.498 c h W n q 0 g /GS0 gs 0 -73.6054687 -73.6054687 0 78.2792969 86.4975586 cm BX /Sh0 sh EX Q Q endstream endobj 171 0 obj <> endobj 167 0 obj <> endobj 126 0 obj [/ICCBased 174 0 R] endobj 173 0 obj <> endobj 175 0 obj <> endobj 176 0 obj <> endobj 177 0 obj <> endobj 178 0 obj <> endobj 174 0 obj <>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 172 0 obj <> endobj 179 0 obj <> endobj 180 0 obj <>/Shading<>>>/Subtype/Form>>stream q 0 g /GS0 gs 0 -73.6054687 -73.6054687 0 78.2792969 86.4975586 cm BX /Sh0 sh EX Q endstream endobj 181 0 obj <> endobj 182 0 obj <> endobj 184 0 obj /DeviceGray endobj 185 0 obj <> endobj 186 0 obj <> endobj 187 0 obj <> endobj 188 0 obj <> endobj 189 0 obj <> endobj 128 0 obj <> endobj 183 0 obj /DeviceGray endobj 170 0 obj <> endobj 164 0 obj <> endobj 190 0 obj <> endobj 191 0 obj <> endobj 192 0 obj <> endobj 169 0 obj <> endobj 168 0 obj <> endobj 165 0 obj <> endobj 166 0 obj <> endobj 193 0 obj <> endobj 194 0 obj <>/Shading<>>>/Subtype/Form>>stream q 0 g /GS0 gs 0 -73.6054687 -73.6054687 0 21.7211914 86.4975586 cm BX /Sh0 sh EX Q endstream endobj 195 0 obj <> endobj 163 0 obj <> endobj 162 0 obj <> endobj 161 0 obj <> endobj 160 0 obj <> endobj 159 0 obj <> endobj 156 0 obj <> endobj 158 0 obj <> endobj 196 0 obj <> endobj 197 0 obj <> endobj 157 0 obj <> endobj 198 0 obj <> endobj 199 0 obj <>/Shading<>>>/Subtype/Form>>stream q 0 g /GS0 gs 69.5471954 0 0 -33.9607239 63.3984375 19.1269531 cm BX /Sh0 sh EX Q endstream endobj 200 0 obj <> endobj 201 0 obj <> endobj 202 0 obj <> endobj 203 0 obj <> endobj 204 0 obj <> endobj 152 0 obj <> endobj 155 0 obj <>stream H1 Om x0) endstream endobj 153 0 obj [/Indexed 206 0 R 0 207 0 R] endobj 205 0 obj <>/Filter/FlateDecode/Height 104/Intent/RelativeColorimetric/Length 973/Name/X/Subtype/Image/Type/XObject/Width 103>>stream HOhfpK#L3]a9a RH ;١)%<ׇQF; g%i^V^}IlFؑ%e R{zby @ЉAC A>ae4eX)Th&lHfBS^; AN3gɴAI&&FdL! ongs\pۙ+s~';ޚl{E8߻~v+=:ޟ$f/fύVoHrl`+(D/ޅ8^4h9|~^\Xfa:z4^9>^U 7kU6Q3q'wJuLM`;dX_M<[1fIL0%ScZHCIN0e5:n3p`I0 `0 `0 `Ť^N'9t`/@+VDd]/McR:cAlݚ9ˑ.9j L&݀Af(X. 7eX|XagG5vNZ߿9ۇX խQBq k d=廴QC6YfEF7 M|zDIeEm_%q1whu^zIZGZ/"7]xE"2M㯎[zRriwMԩ /Iv#~bf/[k?nݺ﹩Nm帶WȘA>ST9Gޛ K/ED/'hr97qCѠu}`9&T`*43sqp~^ IR6FDr1ldUFA^W (F>stream endstream endobj 154 0 obj <> endobj 208 0 obj <> endobj 209 0 obj [0.0 0.0 0.0] endobj 210 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream q /GS0 gs 103 0 0 104 -1.2519531 -1.7480469 cm /Im0 Do Q endstream endobj 211 0 obj <> endobj 213 0 obj <>/Filter/FlateDecode/Height 104/Intent/RelativeColorimetric/Length 973/Name/X/Subtype/Image/Type/XObject/Width 103>>stream HOhfpK#L3]a9a RH ;١)%<ׇQF; g%i^V^}IlFؑ%e R{zby @ЉAC A>ae4eX)Th&lHfBS^; AN3gɴAI&&FdL! ongs\pۙ+s~';ޚl{E8߻~v+=:ޟ$f/fύVoHrl`+(D/ޅ8^4h9|~^\Xfa:z4^9>^U 7kU6Q3q'wJuLM`;dX_M<[1fIL0%ScZHCIN0e5:n3p`I0 `0 `0 `Ť^N'9t`/@+VDd]/McR:cAlݚ9ˑ.9j L&݀Af(X. 7eX|XagG5vNZ߿9ۇX խQBq k d=廴QC6YfEF7 M|zDIeEm_%q1whu^zIZGZ/"7]xE"2M㯎[zRriwMԩ /Iv#~bf/[k?nݺ﹩Nm帶WȘA>ST9Gޛ K/ED/'hr97qCѠu}`9&T`*43sqp~^ IR6FDr1ldUFA^W (F> endobj 134 0 obj <> endobj 135 0 obj <> endobj 215 0 obj <> endobj 216 0 obj <> endobj 217 0 obj <> endobj 218 0 obj <> endobj 219 0 obj <> endobj 214 0 obj <> endobj 220 0 obj <> endobj 221 0 obj <> endobj 120 0 obj <> endobj 222 0 obj [/View/Design] endobj 223 0 obj <>>> endobj 127 0 obj <> endobj 129 0 obj <> endobj 130 0 obj <> endobj 131 0 obj <> endobj 132 0 obj <> endobj 133 0 obj <> endobj 125 0 obj <> endobj 224 0 obj <> endobj 225 0 obj <>stream %!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 14.0 %%AI8_CreatorVersion: 14.0.0 %%For: (Administrator) () %%Title: (v4_3.ai) %%CreationDate: 11/26/2009 1:52 AM %%Canvassize: 16383 %%BoundingBox: -2 -2 102 103 %%HiResBoundingBox: -1.25195 -1.74805 101.748 102.252 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 10.0 %AI12_BuildNumber: 357 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0.627451 0.776471 (Global Mediterranean Blue) %%+ 0 0 1 (Global Pure Blue) %%+ 0 1 0 (Global Pure Green) %%+ 1 0 0 (Global Pure Red) %%+ 1 0.498039 0 (Global Squash) %%+ 1 1 0 (Global Yellow) %%+ 0 0 0 ([Registration]) %AI3_Cropmarks: 0 0 100 100 %AI3_TemplateBox: 50.5 49.5 50.5 49.5 %AI3_TileBox: -247.6001 -370.8701 347.4199 470.9902 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -110 120 4 1252 620 18 0 0 69 109 0 0 0 1 1 0 1 1 0 %AI5_OpenViewLayers: 7 %%PageOrigin:0 0 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 226 0 obj <>stream %%BoundingBox: -2 -2 102 103 %%HiResBoundingBox: -1.25195 -1.74805 101.748 102.252 %AI7_Thumbnail: 128 128 8 %%BeginData: 27134 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFD1EFFCBA2A87D7E7D7D537D537D777D777E %7D7D7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA27D7E %7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA27D7E7DA2 %7D7E7DA27D7E7D7E7D7E7D7E7D7E7DA8A9FD20FFA87D4C4C4B4B214C4B4B %454C4B4B454C4B4B214C454B214B214B214B214B214B214B214B214B214B %214B214B214B214B214B214B214B214B214B214B214B214B214B214B214B %214B214B214B214B214B214B214B214B214B214B214B2145214C4CA2A8FD %1CFF764C6FA1A1C3A1C9C3C3A0C3C3C9A1C9C3C9A1C9A1C9A1C9A1C9A1C9 %A1C9A1C9A1C3A1C9A1C3A1C9A1C3A1C9A1C3A1C9A1C3A1C3A1C3A1C3A1C3 %A1C3A1C3A1C3A1C3A1C3A1C3A1C3A1A1A1C3A1A1A0C3A1A19AA19AA19AA1 %9AA19AFD05A176702152A2FD19FF7D4576A1C9C3C3C2C29AC29AC29AC29A %C29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AA09AC29AA09A %C29A9A9AC29A9A9AA09A9A9AA09A9A9AA0FD0E9A999A9A9A999A999A759A %999A6F9A999A759A9AA1A1C9A1A16F4B52FD16FFA9774BC3C9C9C2C29AC2 %C2C29AC2C2C29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29A9A9AC29A9A9AA0FD069A999A9A9A999A9A9A99 %9A9A9A999A9A9A999A9A9A999A9A9A999A9A9A759A999A6F9A939A75A1A1 %CA9A4B4CFD14FFAF524BC9C3C299C29AC29AC29AC29AC29AC29AC29AC299 %C29AC299C29AA099C29A9A99C29A9A99A09A9A999A9A9A999A999A999A99 %9A999A999A999A999A999A999A999A999A999A999A759A999A6F9A999A6F %9A759A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A76A19A4B4CFD13FF7D %4BC9C9C2BCC3C2C2BCC3C2C29AC2C2C29AC2C2C29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AA09AC29AA0 %9AC29A9A9AC29A9A9AA0FD129A999A9A9A999A9A9A759A9A9A759A9A9A6F %C3A14B7DFD11FFA821A0C3C29AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AA09AC29A9A9AC29A9A99C29A9A99A09A9A999A %9A9A999A9A9A999A9A9A999A999A999A999A999A999A999A999A759A999A %759A999A6F9A759A6F9A759A6F9A6F9A6F9A6F9A6F9A6F9A6FA17645A8FD %10FF5276C3C39AC2C2C29AC2C2C29AC2C2C29AC2BCC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AA09AC29A9A9AC2 %9A9A9AC2FD0A9A999A9A9A999A9A9A999A9A9A999A9A9A999A9A9A999A9A %9A759A9A9A6F9A9A9A6F9A759A6FA14B77FD0FFFA84B9AC39AC29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC299C29AC299C29A9A99C29A9A99C2 %9A9A999A9A9A999A9A9A999A999A999A999A999A999A999A999A999A999A %999A999A759A999A6F9A999A6F9A759A6F9A759A6F9A6F9A6F9A6F9A6F9A %6F9A6F9A6F9A6F9A6F9A6F9A21CAFD0EFFA26FC9C2C2C2C3C2C2C2C3C2C2 %9AC3C2C29AC2C2C29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC29AA09AC29A9A9AC29A9A9AA0FD12 %9A999A9A9A999A9A9A999A9A9A759A9A9A759A9A9A6F9A9A6F7DFD0EFF76 %9AC2C2BCC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29A %C29AA09AC29A9A9AC29A9A99C29A9A99C29A9A999A9A9A999A9A9A999A9A %9A999A9A9A999A999A999A999A999A999A999A999A759A999A6F9A999A6F %9A759A6F9A759A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F76FD0DFFCA76A0C3 %9AC3C2C2A0C2C2C2BCC2C2C29AC2C2C29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29A9A9AC29A9A9AC29A9A %9AA0FD0A9A999A9A9A999A9A9A999A9A9A999A9A9A999A9A9A759A9A9A6F %9A999A6F9A999A759A769A769A4BFD09FFA87DA8A8A87DA8A8A8A7A8A1A8 %A1A7A1A19AC29AC299C29AC29AC29AC299C29AC299C29AA099C29A9A99C2 %9A9A99A09A9A999A9A9A999A999A999A999A999A999A999A999A999A999A %999A999A999A999A759A999A6F9A999A6F9A759A6F9A6F9A6F9A6F9A6F9A %6F9A6F9A76A17DA1A1A87DA8A8A8A1FD06A8FD04FFA8FD0BFFAFFFAFFFA8 %FFA8A8A1C3A0C29AC2C2C29AC29AC29AC29AC29AC29AC29AC29AC29AC29A %C29AC29AC29AC29AC29AC29AC29AC29AA09AC29AA09AC29A9A9AC29A9A9A %A0FD129A999A9A9A939A9AA1A1A8A8FFA8FFAFFFAFFFFFFFAFFFFFFFA8FF %FFA8FD04FFA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8AFA8A8A1A1 %9AC29AC29AC29AC29AC29AC29AC29AA09AC29A9A9AC29A9A99C29A9A99A0 %9A9A999A9A9A999A9A9A999A9A9A999A999A999A999A999A999A999A999A %759A999A759A999A6F9A759A6F9A76A1A1A8A8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FD04FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFFFFFA8FFA8A8A1C3BCC29AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AA09AC29A9A9AC29A9A9AC2FD0A9A999A9A9A999A9A %9A999A9A9A999A9A9A999A9AA1A1FFAFFFA8FFFFFFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FD05FFA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8AFA8A19ABC99C29AC299C29A9A99C29A9A99C29A9A999A %9A9A999A9A9A999A999A999A999A999A999A999A999A999A999A999A999A %759A999A6F9A999A6F9A759A6F9A6F9A76A8A8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD04FFA8FFA8FFFFFFA8FFFFFFA8FF %FFFFA8FFFFFFA8FFFFFFA8FFA8FFA8FFAFA8A1C3BCC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AA09AC29A9A9AC2 %9A9A9AA0FD0E9A999A9AA1A8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFF %FFA8FFFFFFA8FFFFFFA8FD05FFA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A19ABC9AC29AA09AC29A9A9AC29A9A %99C29A9A99C29A9A999A9A9A999A9A9A999A9A9A999A9A9A999A999A999A %999A999A999A999A999A759A999A76A8A8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD04FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFFFFFA8A8A0C29AC29AC2 %9AC29AC29AC29AC29AC29AC29AC29AC29AC29A9A9AC29A9A9AC29A9A9AA0 %FD0A9A999A9A9A999A9A9A93A0A1FFA9FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD04FFA8A8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8A19A99C29A %9A99C29A9A99A09A9A999A9A9A999A999A999A999A999A999A999A999A99 %9A999A999A999A999A999A759A999A6F9A93A0A1FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD04FFA8FFFF %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFFFFFA1C39AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29A %A09AC29AA09AC29A9A9AC29A9A9AA0FD099AA1A8FFFFFFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD04FFA8A8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA1A0999A9AC29A9A9AC29A9A99C29A9A99A09A9A999A9A9A99 %9A9A9A999A9A9A999A999A999A999A999A999A999A999A75A8A8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FD04FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFFFFFA8C39AC29AC29AC29AC29AC29AC29AC29A %C29AA09AC29A9A9AC29A9A9AC2FD0A9A999A9A9A999A9AA8A8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FD05FFA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8A1999A99C29A9A999A9A9A999A9A9A99 %9A999A999A999A999A999A999A999A999A999A999A999A759A999A76A8A8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FD04FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A19AC29AC29AC29A %C29AC29AC29AC29AC29AC29AC29AC29AA09AC29A9A9AC29A9A9AA0FD079A %A8FFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FD05FFA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A099C29A9A %99C29A9A99C29A9A999A9A9A999A9A9A999A9A9A999A9A9A999A999A999A %999A999A9AA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD04FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8A19AC29AC29AC29AC29AC29AC29AC29A9A9AC29A9A9AC29A9A9AA0 %FD0B9AA8AFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD04FFA8A8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA19A99A09A9A999A9A9A999A999A999A999A999A999A999A999A999A %999A999A999A999A99A1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD04FFA8FFA8FF %A8FFAFFFA8FFAFFFA8FFFFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFFFFFA1C29AC29AC29AC29AC29AC29AC29AC29AC29AA0 %9AC29AA09AC29A9A9AC2FD059AA1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFFFFFAFFFFFFFAFFFFFFFA8FFA8A8FD04 %FFFD05A8A1A8A1A7A1A8A7A8A8AFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8A9A0BC9A9A99C29A9A99A09A9A999A9A9A %999A9A9A999A9A9A999A999A999A999A93A1A8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFFD04A87DA8A1A17DA1FD05A8 %FD09FF9AC2C3C2C29AC2A0C3A0C9A8A8A8FFFFFFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFFFA89AC29AC29AC29AC29AC29AA09AC29A9A %9AC29A9A9AC2FD099AA0A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFFFFFA8A87DA1769A759A6F9A759A6FCAFD0DFF9AC29AC29A %C29AC29AC299C29AA1A1AFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8A8999A9A9A999A9A9A999A999A999A999A999A999A999A99 %9A999A999A999A7DAFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8A8769A6F9A6F9A6F9A6F9A6F9A6F6FA2FD0DFFA0C2C3C2C2C2C3 %C2C2C2C3C2C2BCC3A1A8A8FFFFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8A79AC29AC29AC29AC29AC29AC29AC29AC29AA09AC29A9A9AC2 %9A9A9ABCA1AFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFFFFF %A1A19A9A939A9A9A759A9A9A6F9A9A9A6FCBFD0DFF9AC29AC29AC29AC29A %C29AC29AC29AC29AA1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8A0999A99C29A9A999A9A9A999A9A9A999A9A9A999A9A9A999A99 %9A9AA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8769A6F %9A6F9A6F9A6F9A6F9A6F9A6F9A756FA8FD0CFFCBFD07C29AC2C2C29AC2C2 %C29AC2BCC2A1FFFFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA1 %C29AC29AC29AC29AC29A9A9AC29A9A9AC29A9A9AA0FD059AA1A8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A1769A999A759A9A9A6F9A9A %9A6F9A759A6F9A6FCAFD0DFF9AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC2A1A8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD049A99 %9A999A999A999A999A999A999A999A999A999A93A07DFFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8A16F9A6F9A6F9A6F9A6F9A6F9A6F9A6F %9A6F9A6F9AA8FD0DFFC2C2C3C2C3C2C2C2C3C2C2BCC3C2C29AC2C2C29AC2 %A1AFAFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A89AC29AC29AC2 %9AC29AC29AC29AA09AC29AA09AC29A9A9ABCA1FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFCAFFA8A1999A999A9A9A759A9A9A759A9A9A6F9A9A9A %759A6FFD0EFF9AC2A0C29AC29AC29AC29AC29AC29AC29AC29AC29AC2A0A8 %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A0999A99A09A9A999A %9A9A999A9A9A999A9A9A999A999A9AA8A8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA89A6F9A759A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A %A8FD0DFFC2C2C3C2C2BCC2C2C29AC2C2C29AC2C2C29AC2BCC29AC2A1AFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA1C29AC29AC29AA09AC29A %9A9AC29A9A9AC2FD059AA1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8A1999A999A9A9A759A9A9A6F9A9A9A6F9A759A6F9A769A6FFD0EFF9A %C29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC299C2A1A8A8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD049A999A999A999A999A999A999A %999A999A999A7DAFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A16F9A %6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F6FA8FD0DFFC2C2C3C2 %C2C2C3C2C2C2C3C2C29AC3C2C29AC2C2C29AC2BCC2A1FFFFFFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8A19AC29AC29AC29AC29AC29AC29AA09AC29A %9A9ABCA0A8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFAFA1999A9A9A99 %9A9A9A999A9A9A759A9A9A759A9A9A6F9A9A9A6FFD0EFF9AC29AC29AC29A %C29AC29AC29AC29AC29AC29AC29AC29AC29AA07DFFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8AF7DC29A9A999A9A9A999A9A9A999A9A9A999A9A9A99 %A1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8759A6F9A759A6F9A75 %9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F70A8FD0CFFCBFD07C29AC2C2C29A %C2C2C29AC2C2C29AC29AC29AC2BCA1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFAFA89AC29AC29AC29A9A9AC29A9A9AC29A9A9AA09AA07DFFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFFFAF769A9A9A999A9A9A759A9A9A759A9A %9A6F9A9A9A6F9A759A6F9A6FFD0EFF9AC29AC29AC29AC29AC29AC29AC29A %C29AC29AC29AC29AC299C29AA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8A1999A999A999A999A999A999A999A999A999A76A8A8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FF7D9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F %9A6F9A6F9A6F9A6F76A8FD0DFFC2C2C3C2C3C2C2C2C3C2C2BCC3C2C29AC2 %C2C29AC2C2C29AC29AC2A0FFFFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A1C29AC29AC29AC29AC29AA09AC29AA09AC29AA1A8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8A1999A9A9A999A9A9A999A9A9A759A9A9A759A9A9A %6F9A9A9A759A6FFD0EFF9AC2A0C29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC27DFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD04 %9A999A9A9A999A9A9A999A9A9A999A7DA8A8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8A8999A6F9A759A6F9A759A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F %9A6F9AA8FD0DFFC2C2C3C2C2BCC2C2C29AC2C2C29AC2C2C29AC2BCC29AC2 %9AC29AC29AA1A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A19AC29AA0 %9AC29A9A9AC29A9A9AC29A9A9AA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8AFFD049A999A9A9A999A9A9A759A9A9A6F9A9A9A6F9A759A6F9A769A6F %FD0EFF9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC299 %C29AFD13A8A09A999A999A999A999A999A999A999A99A17EFFFD0FA8FFA1 %9A6F9A759A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F6FA8 %FD0DFFC2C2C3C2C2C2C3C2C2C2C3C2C29AC3C2C29AC2C2C29AC29AC29AC2 %9AC2A1FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A19AC29AC29AC29AC2 %9AC29AA09AC29A9AA1AFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A1999A %9A9A999A9A9A999A9A9A999A9A9A759A9A9A759A9A9A6F9A9A9A6FFD0EFF %9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AA1 %A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8AFA19A999A9A9A999A9A9A999A %9A9A999A99A1A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD04A89A9A6F9A999A6F %9A759A6F9A759A6F9A6F9A6F9A6F9A6F9A6F9A6F9A6F70A8FD0CFFCBFD07 %C29AC2C2C29AC2C2C29AC2C2C29AC29AC29AC29AC29AC2A0A8A8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8A89AC29AC29A9A9AC29A9A9AC29A9A9AC2A1 %A8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A0999A999A9A9A999A9A9A75 %9A9A9A759A9A9A6F9A9A9A6F9A759A6F9A6FFD0EFF9AC29AC29AC29AC29A %C29AC29AC29AC29AC29AC29AC29AC299C29AC299C2A1FD11A87DA0999A99 %9A999A999A999A999A999A99FD13A86F9A759A6F9A6F9A6F9A6F9A6F9A6F %9A6F9A6F9A6F9A6F9A6F9A6F9A6F76A8FD0DFFC2C2C3C2C3C2C2C2C3C2C2 %BCC3C2C29AC2C2C29AC2C2C29AC29AC29AC29AA8A8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8A8A0C29AC29AC29AC29AA09AC29AA09AC3A8AFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA1FD079A999A9A9A999A9A9A759A9A9A759A %9A9A6F9A9A9A759A6FFD0EFF9AC2A0C29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29AC29AC2A1FD11A87DA1999A999A9A9A999A999A999A %999A9AFD12A8A16F9A999A6F9A759A6F9A759A6F9A6F9A6F9A6F9A6F9A6F %9A6F9A6F9A6F9AA8FD0DFFC2C2C3C2C2BCC2C2C29AC2C2C29AC2C2C29AC2 %BCC29AC29AC29AC29AC29AC9FD12A8A0C29A9A99BC9A9A999A999A999A99 %9AA8AFFD0FA8AFA1996F9A939A6F9A999A6F9A999A6F9A9A9A759A9A9A6F %9A759A6F9A769A6FFD0EFF9AC29AC29AC29AC29AC29AC29AC29AC29AC29A %C29AC29AC29AC299C29ABCA0FD11A87EA0939A9999939A9399939993996F %9976FD12A8A16E936F936F936F996F936F996F996F9A6F9A6F9A6F9A6F9A %6F9A6F9A6F6FA8FD0DFFC2C2C3C2C2C2C3C2C2C2C3C2C29AC3C2C29AC2C2 %C29AC29AC29AC29AC29AC3FD12A89ABC999A999A9999939A93999399939A %A8AFFD0FA8AF9A936F996F936F996F996F996F996F9A6F996F9A6F9A6F9A %759A6F9A9A9A6FFD0EFF9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC29AC29AC29AC29ABCA0FD11A884A093999399939993936F9993936E93 %99FD12A8A168936E936E936E936F6F6E936F6F6F936F6F6F936F6F6F996F %936F9A6F6FA8FD0CFFCBFD07C29AC2C2C29AC2C2C29AC2C2C29AC29AC29A %C29AC29AC29AA1FD12A89A99939993999399939993999393929AFD11A8AF %76936E936E936F936E936F936E936F936F936F936F936F936F936F936F9A %6FFD0EFF9AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC29AC2 %9AC299BCA0A87DA8A8A87DA8A8A87DA8A8A87DA8A8A87D9A92936E939293 %6E936E936E936E936FA8A8A87DA8A8A87DA8A8A87DA8A8A87DA8A8A16893 %686F6893686F686F686F686F686F686F686F686F6E6F68FD056FA8FD0DFF %C2C2C3C2C3C2C2C2C3C2C2BCC3C2C29AC2C2C29AC2C2C29AC29AC29AC299 %A1FD12A89A939399939993999393929993939299FD11A8A9A1936E936E93 %6E936E936E936E936E936E936E936E936F936E936F936F996FFD0EFF9AC2 %A0C29AC29AC29AC29AC29AC29AC29AC29AC29AC29ABC99BC999A99BCA1FD %11A87D9A92936E9392936E9392936E936E926EFD13A86892686E6893686E %686F686E686F686E686F686F686F686F686F686F6E6FA8FD0DFFC2C2C3C2 %C2BCC2C2C29AC2C2C29AC2C2C29AC2BCC29AC29ABC99BC99BC99FD13A8FD %049392939293929392936E9392937DAFFD11A89968936E93689368936893 %686F6893686F6893686F686F686F686F6E6F68FD0EFF9AC29AC29AC29AC2 %9AC29AC29AC29AC29AC299C299BC99BC999993BB939A7DFD11A87D936E93 %92936E936E936E936E92689368A184FD10A8A97668686E686E686E686E68 %6E6868686E6868686E6868686E6868686F686FA8FD0DFFC2C2C3C2C2C2C3 %C2C2C2C3C2C29AC2C2C29AC29AC299C299BC99BC99BB9AAFFD0FA8FFA8A1 %9299929392939293929392939293929276AFFD11A8A16893689368936893 %689368936893686F6893686F6893686F686F686F68FD0EFF9AC29AC29AC2 %9AC29AC29AC29AC299C299BC99BC99BB99BB999993BB93A1FD12A876926E %9392936E9392936E936E926893689A84FD12A86F6892686E686E686E686E %6868686E6868686E6868686E6868686F6869A8FD0CFFCBFD07C29AC2C2C2 %9AC2BCC299C299BC99BC99BB99BB99BB93BCFD12A884A092939293929392 %939293929392936E9393FD12A8AF768C689368926893686E6893686E686F %686E686F686E686F686E686F68FD0EFF9AC29AC29AC29AC29AC299BC99BC %99BB99BB99BB93BB939992BB93939AFD13A86F9292936E936E9268936E92 %68936E9268937DFD12A8A16868686E6868686E6868686EFD0F6869A8FD0D %FFC2C2C3C2C3C2C2BCC2BCC299C2BBBC99BC99BB99BC99BB93BB99BB93FD %13A87D9992939293929392939293929392936E9392A1A8FFFD0FA8FFA89A %68936893689368926893686E6893686E686F686E686F686E686F68FD0EFF %9AC2A0C29AC29AC299C299BC99BC99BB99BB99BB93BB939992BB929AFD13 %A8A1929392936E9392926E936E9268936E92689275FD12A8AF7D6E686E68 %6E686E6868686E6868686EFD0B6869A8FD0DFFC2C2C3C2C29AC2BCC299C2 %BBBC99BC99BB99BB99BB93BB93BB92BBA7AFFD12A89A9292939293929392 %93929392936E9392936899FD13A8AF75686893686E6893686E686F686E68 %6E686E686E6868686E686E68FD0EFF9AC29AC299C299BC99BB99BB99BB93 %BB93BB92BB939992BB929276A9FD12A87D9392926E936E9268936E926893 %6E926893689268A1FD14A86868686E6868686EFD0E6844686868A8FD0DFF %C2C2C2BCC2BBC2BBC299C2BBBB99BB99BB99BB99BB93BB93BB99AFA8A8A8 %FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8A192939293929392939293929392 %93929392936E929AAFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A168 %9368926893686E6893686E686F686E686F686E686E686F68FD0EFF9AC299 %C299BC99BC99BB99BB99BB93BB93BB92BB939992BB93FD15A86F9292936E %9392926E9392926E936E9268936E926893A1FD14A876686E6868686E6868 %686EFD0E68A8FD0CFFCBC2C2C299C2BBBC99BCBBBB99BB99BB93BB99BB93 %BB93BB92A7FD13A8AFA1939293929392939293929392936E9392936E9392 %9368A1FD13A8FFA8996893686E6893686E686E686E686E6868686E686868 %6F68FD0EFF99C299BC99BB99BB93BB99BB93BB93BB92BB929992BB92A1FD %14A8849A8C926E9392926E936E9268936E9268936892689268926FFD14A8 %AFA86F686EFD0E68446868684468A8FD0DFFC2BCC2BBC2BBBC99BCBBBB99 %BB99BB93BB99BB93BB93A1A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD %04A89393929992939293929392939293929392936E9392936E93A1FFA8FF %A8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8FFA899686E6893686E6893686E %686F686E686E6868686F68FD0EFF99C299BB99BB99BB93BB99BB93BB93BB %92BB92B592A7FD16A876929293929392936E9392926E936E9268936E9268 %936E926899FD15A8AFA89A6868686EFD1068A8FD0DFFBCBBC2BBBB99BBBB %BB99BB99BB93BB99BB92BB99A8A8FFFD13A8FFA199929392939293929392 %939293929392936E9392936E93929368A1FD15A8FFA8A16868686E686E68 %6E6868686E6868686E686E68FD0EFF99BC99BB99BB93BB93BB92BB93BB92 %BB92999AFD17A8849A92936E9392926E936E9268936E9268936E92689368 %92689268926FFD18A8A16FFD0D6844686868A8FD0DFFBCBBC2BBBB99BBBB %BB99BBBBBB92BB99A0A1FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 %FFA8CAA8A8929392999293929392939293929392939293929392936E9392 %936E92A0FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFAFAF76 %936868686F686E686F686E686E686E68FD0EFF99BB99BB99BB93BB93BB92 %BB92999AFD1BA86F929293929392936E9392926E9392926E936E9268936E %92689368926893A1AFFD17A8AFA8A16FFD0D68A8FD0DFFBCFD06BB93BB99 %9A9AA7A8AFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 %AF9A92929392939293929392939293929392936E9392936E9392936E936E %93689AA8FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD05A8FFA8FFA1 %9A6F6FFD0968FD0AFFA8FFA8A89AC3A0A09AA09AA17DFD1EA8A97D939293 %929392926E9392926E936E9268936E9268936892689268926892689268A1 %FD1BA8FFA8A8A1A876766F766F766F76A8FFA8FFA8FD04FFFD05A8FFA8FF %A8FFA8AFA8FFA8FFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FF %A8A8A8FFA8FFA89992939299929392999293929392939293929392939293 %6E9392936E9392936E936EA8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FF %A8A8A8FFA8A8A8FFA8FFA8FFA8FFA9FFA8FFA8FFA8A8A8FFA8A8FD04FFFD %2AA8FFA89A9293929392939293929392936E9392926E936E9268936E9268 %936E926893689268926FFD2CA8FD04FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8 %A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8FFA8A0 %929392999293929392939293929392939293929392936E9392936E939293 %6E936E9368926FA9A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FF %A8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD04A8FD04FFFD28A8AFA8A19293 %9293929392936E9392926E936E9268936E9268936E926893689268926892 %68926892689275FD2AA8FD04FFA8A8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A192BB929992 %99929392999293929392939293929392939293929392936E9392936E936E %936E936E9276FFAFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD05FFFD28A8A192929293929392 %939293929392936E9392926E9392926E936E9268936E9268936892689368 %926892686E76AFFD27A8FD04FFFD05A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8 %A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A192B592939299929392 %9392939293929392939293929392936E9392936E9392936E936E9368936E %936893689275FFAFFFA8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8 %FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8FD04FFFD24A8AFA8A0929292939293 %92939293929392926E9392926E936E9268936E9268936892689268926892 %68926892686E689268686FFD26A8FD04FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A092BB92BB92 %9992BB929392999293929992939293929392939293929392936E9392936E %9392936E936E9368936E9368926FA8AFFFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD04FFFD22A8AFA199 %92939293929392939293929392939293929392936E9392926E936E926893 %6E9268936E9268936892689368926892686E689268A1A8FFFD21A8FD04FF %A8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8 %A8FFA8A89ABB929992BB9293929992939299929392939293929392939293 %9293929392936E9392936E9392936E936E9368936E9368936E926892689A %A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FF %FD04A8FD04FFFD1EA8AFA8A7999292939293929392939293929392939293 %6E9392926E936E9268936E9268936E926893689268926892689268926892 %686E6892686E686E686F7CAFFD1FA8FD04FFA8A8A8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8C292B592BB93BB92BB9399 %92BB92999299929392999293929392939293929392939293929392936E93 %92936E936E936E936E9368936E9368936893689275A8A8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FD05FFFD1AA8AFA8A8 %9A9992BB929392999293929392939293929392939293929392936E939292 %6E9392926E936E9268936E926893689268936892689268926892686E6892 %686E686868767DFFA8FFFD19A8FD04FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8A8A8FFA8FFA8AFA7A093BB92BB92BB939992BB929992BB9293 %92999293929392939293929392939293929392936E9392936E9392936E93 %6E9368936E9368936E9368936892689368926892686F75A8A8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD04FFFD12A8FFA8A9A8 %A9A1A199BB92939299929392939293929392939293929392939293929392 %926E9392926E936E9268936E926893689268926892689268926892686E68 %92686E6892686E686E686E686E6868686F76A8A8FFA8AFFD13A8FD04FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8A7C39ABB92BB93BB92BB93 %BB92BB93BB92BB939992BB929992BB929392999293929992939293929392 %939293929392936E9392936E9392936E936E9368936E9368936E93689368 %936893689368936868689A9AA8A8FFAFFFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8A8FD04FFFD06A8AFA8A8A8AFFD04A8A1A1A0A099BB92BB929992BB92 %9392BB92939299929392939293929392939293929392939293929392936E %9392926E936E9268936E9268936E9268936892689368926892686E689268 %6E6892686E686E6868686EFD05686F6F9A7DA8A1FD04A8AFA8AFA8FFFD04 %A87DFD06FFA8FFAFA19AC3A0C29AC29ABC99BB99BB92BB93BB92BB93BB92 %BB93BB92BB93BB92BB929992BB9293929992939299929392939293929392 %9392939293929392936E9392936E9392936E936E9368936E9368936E9268 %936892689368926893686E6893686E686E6868686E686F6E936F9A6F9A76 %7676FFA8FFA8FD0AFFA19299BB92BB92BB92BB92BB92BB92BB929992BB92 %939299929392999293929392939293929392939293929392936E9392926E %936E9268936E9268936E926893689268926892689268926892686E689268 %6E686E686E686E6868686E6868686EFD0A6844686868446E4477FD0FFF6F %C2C2BB99BBBBBB99BB99BB93BB99BB93BB93BB92BB93BB92BB93BB92BB93 %BB92BB939992BB9299929992939299929392939293929392939293929392 %9392936E9392936E936E936E936E9368936E936893689368936893689368 %926893686E6893686E686F686E686F686E686F6845A8FD0FFF7792C299BB %93BB93BB92BB93BB92BB92BB92BB929992BB929392BB9293929992939293 %92939293929392939293929392936E9392926E9392926E936E9268936E92 %6893689268936892689268926892686E6892686E686E686E686E6868686E %6868686EFD0C684CFD10FFA86FBBC3BBBB99BBBBBB93BB99BB92BB93BB92 %BB93BB92BB93BB92BB939992BB929992BB92939299929392939293929392 %9392939293929392936E9392936E9392936E936E9368936E9368936E9368 %936892689368926893686E6893686E6893686E686E686E686EFD04686E6F %20A8FD11FF776F99C293BB92BB93BB92BB92BB92BB929992BB9293929992 %9392939293929392939293929392939293929392926E9392926E936E9268 %936E926893689268926892689268926892686E6892686E6892686E686E68 %6E686E6868686EFD0F68932077FD13FF526FC2C399BBBBBB99BB99BB93BB %93BB93BB93BB92BB93BB92BB93BB92BB939992BB929992BB929392999293 %929992939293929392939293929392936E9392936E9392936E936E936893 %6E9368936E936893689368936893689368926893686E6893686E686F6868 %6F9A204CFD15FF4C4B9AC399BB92BB92BB92BB92BB929992BB929392BB92 %9392999293929392939293929392939293929392926E9392926E9392926E %936E9268936E926893689268926892689268926892686E6892686E689268 %6E686E6868686E6868686EFD0768936F70204CA8FD16FF524B6FA1C2C2BB %BB99BB99BB93BB99BB93BB93BB93BB93BB92BB93BB92BB939992BB939992 %99939392999293929992939293929392939293929392936E9392936E9392 %936E936E936E936E9368936E9368936E93689368936893686F689368936E %93939A704B2077FD19FF7D4C206F6F9A9AC29AC29AC29AC29AC29AC29AC2 %9AC29AA09AC29AA09AC29A9A99A09A9A99A09A9A999A9A9A999A9A9A999A %9A9A999A999A999A999A999A999A999A999A759A999A759A999A6F9A759A %6F9A759A6F9A759A6F9A6F9A6F9A76764B4C20214BA8FD1CFFA24C4C454B %45704B6F4B6F4B6F4B6F4B6F456F4B4B456F4B4B456F4B4B456F454B454B %454B454B454B454B454B454B454B454B454B454B454B454B454B454B454B %454B454B454B454B454B454B454B454B454B454B454B454B454B2145204B %4B77A8FD20FFA8A87D7D52775377527753775277537D537D777D537D777D %537D777D537D777D537D777D537D777D537D777D537D777D537D777D537D %777D537D777D537D777D537D777D537D5377527752534C534C534C534C53 %4C535253527D7DA8A8FD70FFA9FFAFFFA8FFAFFFA8FDFCFFFDFCFFFDA1FF %FF %%EndData endstream endobj 227 0 obj <>stream %AI12_CompressedDataxkɑ-CFXn#axVՌbhPjĽl/=~n+U̇gd<͎?eX=~|zOz~w~?n×ӷ>~>GϞqwOohl߼~$ OssU5>Կ;|͛o}34wz/Wt_]|xߦ/]W]ۡx/ rm?~Oa7~/̛a~3[_ n~[/޽ꟿOoa4Ǜ/q}|ۯ/~ {c|p??y_ӧ7{oz/wަX鳿~Ʒ'OWvf4}ۿ+fSS΃>}7緿ͯۯyg ٮz~=y>?ZWUW{ <#X9~S<ǻ-/4l۰A7?޿} 񱑎>~=#qz/*޽_73A?Φކo~˺\o~z[ =\RըZo8Ɛ_>˻_ӻY@+<gRޟ? W;sW"||:"x/l>C|  |K8bC/;x7>~o?ׯ?3_gpV@wp]o= oy}3>WO\3߿>cwϼG]5wWlDz!o#zʭ_>f~ۿ>:2{gzϏCť'/o޿Oo?/<tޫ΢?^/}b~? ;} ނ(_/pxɼ2} z_a`=o>8^Ç7_/P}aa^ׯ~UnjXMRnXRork]F7mM4Mׄnnfk׶k};~n]չwc7wk_uzߏ/oW$O~_6TC=Zn0`0˰pNc5#l،ء/ql;~5_vX֢uh=GF5d_me;Ubu^Κ֥#W?6i#^z2+)zXU x^ ~]ݪg>oq]:6wjj/-{(pe3}3eSWwB3}7?tkӃwׯ QH}ɟ_Ԩ'?E'eJx&M'P䣢 ~Jl`ȮFvmj'1izG9cMvF_mC4q#^xŭvW`;~#(3x E* *F++'Wlq2?YTOZ'ޤQrΣO!2W/z+Ywϲ%aːO%z53kbPx#,@pN\.'5̳O^I25bQx;;bW\=z3&i%U5Zn#\Da-sB4[4nr2ӅI"'XcifS .DPnEWpщ \aDsy\naV_p, <.Up(t#/=x 嘊㕘VZm9\qeeWNv5_ `[ٖ wqW[{Wn5Fr: ?uTomC?%XuSdI_խrZe|qڥYgֈk մnM]lwpcF_!I{.UxxF86`q(ʺWR{LB31fi^ 2oZ̐58jUj0Ri) f7N^Mf~ɣ9fFkpΣyOlL(]t6vŴͲmlnN[u`{7moȰVj fL/BHBU1ԇ|l/և:8'źr BuS+1UW_qU")ت*7 _H'{+@cTpꠂh2l~ )Kj qj2ZVIWgWTTQUEFix*euJG.+5YZя=M?ч؍cB/첦0Za^s:D.;w0cW0uk{[8NW4xl¸q#;.m.S8 Rh͗[j-\y2, |G\~23W\F%MpX[%vT oXrzgy<,2[e]Vt|RzDp+h]m=m`B5"~:gOh[6xm',>>d#6$>AHl|tM:a0no9۹ϼy1`_r0⚜\Fs.R1 }sι3Up6cG g熇h' g VHy8:88jLmp-˼LxXtxsۊɷ a:0搂;an4܈d2ANi:iG~x!Ai2 6NXI0&) S_\.G-LlȚ0m19rt҆ G,`} Gc6x5x]&bϐ8I&JpL#1^nG0tEت Ͻ+3/.&D; EȈ ^.'o*&G}7|AG-0Oc_ yFGpf<MzpYaJ7!'MxrmԵ)CBX)O{w_SnhO5Ӟr񔄨B}09~1fYw\h/C8˅Hg}`'Së \cAu?ZE0ߎqK N= [W)zG]6ؿ/h7CK.8d 5wbG1\㮩0t zo9Xsu\r*f\xǃNl9蘽{!L|=娿`5Ec ;q6븼_]/=Lxwhj|}qӀvc_CW)+W:C0?}&?vmiq9Bm{߾}kM$A7mkoĴ[H0 44NXQ-  ܭX{{U iMW_PV&BZ"W uCg&5mgҤYi3Q6HI 3&NI %:,oP/!$:7g7Lo0Df8x );ǭ9Ŭ:m(<avh14S@!s qcI5̌ :ht%%,='FpY]}Jik6љ:, .pyI&&_׬{um{P0Pr1kKbϭ.ǃե j HAҮ/եY_j6Wq+fL$Mr"ZB1)@}Zޫ0)Vg%ݷw[^;dYR|Q=Jc~Dm<̗[E4jr_Ù>cB\љџ,ӒJNŐs.z-+H%+&]`PҥO}`dJПdB0fVX$[ Op* D35lN`\UArI K^s^X0`>m05&[إ ی[GqjpJ`rˉ\]0Jٸeekh$z,|E  ,R/%W%?EWW.G׳V͙MBfSz#hlVѱ#Nh[H"p΂^jFO51DžHr$*_9Ԝ:/# cnBdbpP`!3>3I0MˆTp""[OjJgӄqyk28r_[̪"vS/Y&2Rň/IH 7PT.O$-Y󳣞!=s5rϓOϔOBBE-‰ ڒ'4AŁ m|'_=]Ǩc$.j$Ab,#I Qd?r{DG|rG]Lq9̺d>W~fJF. "4ʡp{Up#x'&az=qqkt`ƿ ?p .#}s\Zy"`b6BJա*Cφ@:ՠ8: vU㏮J87w [ĚXY-lJh>-ݒtW۝wT@ !Rs9C *Zbڲ`2X`Zilnl]3vg`M.|Z*Ҽڍhv*1,m|XhOZxϙv 3올c_a}Ȅc>Խm =ߗl!O$1IFsR'MJdnrᙄ-7=jW L 4~Y~cʴe39h>M'9pO k83 ,厇'˜m AaJ!pyUEUɟKr.$Wעo'|ހ{F7>^0%igJ#Yc V#!IE,x2 $ZA&Gd':FNH<$~ڐTUǬwH}v\mcs1S;뚊1-U4 {wDwS]-n~0!/6|\C>9̞$k)YIOE1`Ky$9XjUMjɮfd%+&D=94?^KGP?I:?Vs}mrek99 Xlۘ-`}*PJt .y)E&KfEϨK%/p( 0TP RHF &_hy͞.o#kCb8t~I@ )1`a%=p{pt*:1m fF5gsQ{IA Vw)s*VY<7NZWUQ g Y2SkZU<1 3'=k,,fiŬz&p9 y5hׁKBEQ)cTT'j5$]Ϟ\c9#8gȲM[C03I\* Te7>s✼9|ěx; ?JU& }ҹoG-pȳW1idfK eSVR>'J`ҫ е-|,.+>K9'Ũ/,dL%J'p r9VXR@zH_𙧁P&r̭>D)#^#VMéwІC3Z?ѲrdہFuhG4.ڮ1PQigw4Heq4 ,iߵyL~ X4~M gf[;_z xZWpA;Ha}pAr K= `Ln༲Į8{ɓ](8uRGڗ fa w]2x} ʗ{b)o#AdZ#>Wr3U:L`XRYy8ٶ0–c蛛A_q'?_C.di\m"ae3qֿmmAZj„Ieq8떯#:C,X[h0 6 ƊAhXg ZWBڭkVB] *ض+fE?ia2m?mڏ"!ʎ\1r3ZYόۂ9pZZҹB׷ɒ4.><|, (5.eRř&XBb- ^"1HAϷ$,}OpRۆ>IPTiFD)"K?0W&)22[|npuԥy1ڔc2/xDOU#=zBd䟁q02 qڽs82?Rbq_9W]MJdzC()݈j7o'D[`{R} XS͜#|s|gaskO3*FwlgPpT=v>yW9c5\t~ 8~@ݺV`e_ gt9$ƪ+6,֯r#SR5@!>lVrb%Sh<ΒOpf௙H58dzq"KА𔐂Pƙ̑Pq'Fy:yru]*4s4#In.'S%Z<1sVr3*&&;Ay3N dd 82J ,Ӝ潾 LT ]*<&-ǩ=1Dpv +]+`ipz@qk-և`2{O祧`:Ά '4q(L>Oz=&'rRG>Rm(>l2Dѐ./s^9BTbŠ}5z^n}#]ǟpvM_3&Hֈ`ʨItޠ!tW/hfh p Im"h HjzXe6Kb%Ṿ#Eۏ,`m4`]t=+n)7 IwClr He-ڥR(3|-.e vS Q>7 D>'.i4% CQGayD 3i܊[zp W2UJ1:,;n.H} 8Cdq?i<5 {Y] C`lO9>%Z+4~55Zí+ud=$Mն8miApwnm1v(,b3 }2/[ 0&b Ls혜!,]'Xzd2Lm?in#Ƃ3S_ Om^lēV'c;^ؒ`Ĝ4<ETw\ЂrrM{W&0o#NnO4}YF (%DpG0Uݍt!ěPc8%XBX*Ske*XIIe&&g"52p> Z馬^j\Lt6I^䀳%ß5غcQo I)åk^\1Z(0B23}윥P ^sh;T#f(qcКy26)#w "DN0͵0jXTCew3/1 \d"N^5gv[AMp]V"&xliΩtfPWPHg `^`9qV I(]C|=2_JkpR,$ FBEDP,Bp ϰ(~M,ڠh8 Ԕ3 %Lu7dU܁AkNgAwW9̍ޏ%@|5KV+q 6EqXη(W\AHJ0D~{Q_B4ߞ;xph<<z 7ehp5ӤNB7V>FYKH@PT՚bCpi!"|4"d!Y֌xփnJ"fDs&XE,}Z-'d*Y)s%*،!㿪*9x/ޝ] ϶90#1w-9i\,4J]'\Y||12}}' L~1;©&Vy3FôGzn/G2֛wOn?(Xǂ}6[Q^<"=hIv:m >?VFS[ή2ٴyTj/).Y[D%hWqj-s˨Aqx* r9wjt$H[B:5?0rmj`Β;c}L#}:=Xҭ>nr;:ǓsC29?P> kN] gV =1er߀tXN7a.&+cEA:1i=蛤GHn | 5kƅlŤp|mxՠzq'|>=Fkx19Ƙ3+!&5nTDsGZ.?yTf|v6*߽Oݿ[2Sc$pSl,|qp s/nڮū Ӫ=+jFk=?>Խ*LmdUb]wkV/W7N{m~ oW{~gpMuoc=:]IߒN+NYdW]6{UgS?|m[^+yuv'߿\6kbeaJypKW67/V_ gaf-#xI7Qvc߱_ӬaWW\} oߠjjqwpNL Is9U~*ӟ1᮳:?TEaC~|]5ZmCc1lkE^A[( ּaC<۵0u`!.#f|~+2Y.?";bUX |H?{I&A\rsR!ACc>d(OBtԪ^ Q:_tjrj0MuDՠaҎI h|FeY96k!@$"fb#e'65- 9Dۦ--F£Ȟ[>Z`,>Y^_&9l㼳ҷܿ=H8 6lޘv φ@$,{^MErRG|^ңzYf/}g:q[ m=g 6n)^|oCKe=NٯJbvoha, x)h!eK`trlG|c smdۍx~a%;b((\Zw%#.؅ 7 FZvmߌ+]0] 2l|-GHVAr M'5Y C _Oyb s# ]8b-) DŽg8'mjۢxWohu_ τaZ{Yh+ƊTP`"grG{WETʗ7\JF+7epX-mMie&?16OՊeGM&Igh̨wv5JW`LL Z I\m횈}<21_2.7JN5[4O%2 <`D&`\L@2eN G,'ĝ Y0\;$B,x 9#f<IW@>}@'4kab/w:yC/SF$y2rVJ8x#o؂pkfUHO}'jT l:`1[}0k$"es-7cHeW[ynfhlffU|̅OBzgw|n~̲<s~VGyar>@16g?3%uoٓN/bN( 'V#&ƿ Y=y+`!Rص^G'w *D^ޣE~BU3poqfs(6p~Q2cV#j6<#e,Od)p5,Hq,$HD=)\6U4,k@q-jJAqa |" [9DzűTq&q})yaFeAZrJl &O,&n]Gc 3H;E(ntC΢!Y'>Ɏx9#>%s|M)^G-kEV[`xͱ,ثgJ/l}2'ʭr&_=Wʙ`~ IK+yx CLɝ5D }d$]JcWp0XYN#+m 5&ur|PHI.?IG2?zpI>yFGhԬ2vkB>bI'܊Z|6D g3v 0Ds&MD Zs~+JʺM Ů. f/݌fgA)m si9蔌c,)7glrRQ& C}-^5:KN{ [{` A]>_O' 얼ܓW!(-uXJѺv`22nԺ!qS8bݘ-@(biMI'7cx;~B0ӄseb\&sʕ͏E#%$t%kVRbפt!C@+兟!.o)0KzXRĒ&6̂g5m,cI7ՓN0/'M(IjbG6} Ŕ]T%0swq7"oP 3JSUO4h@u,^Hc=PĂӆ_QVTQ{i:6󧋃 3apLOO=BZv;<)@ g%D i#LYYZ֚{ik紞amGA)YLM*hi/Ή\Ea`Q=ЊgiČ4r4=zٰ.5%أuL ŠjLκ"ФGA&9[ O<(3DoLIQۊpM'6Ad5_*D'*u,Zd7 }m#u'i3{9d'F^?կ4wZ#CHXA>G@^&@KR~rzʏlz+]Tj捕ɜ31~Nnt2{o;߇'{{ГM6%H2HL1HrE3yr &?xދF:C kP4VZ voZ$豵?ߎJs>xh0bϷ%ќmMPbXPD2{&ϕeupˈA)x8MZʢrhX&!Pa|8d42I] T^ (̚elRo5B6ڍ Unj&f΀\eo#OV Oc+-v0㒉vC7([auR2"MwWL-ZCs˽Љ=8 #v̠d/#>om[O3,65[(6 OҌ+2`;묭@0xAsY3i:U25%UT1$HV8ͪxVDVNn@tGEl#:TQXPzJ ińͶ[V Ǝ,T,o  X"rS0W %S:i#OԌ3 ~3ԌǰYt<74Hi:mt:m _.,xҧT n2z+$Ҝ\%z觌+`HI!:~ggrI)sq'r@S*S;I8VFCl8o0Wj?=Ed0"q(XǐpP؆Y"Xb F I. Tn Jhk34P!g|{Hc|-ZgHOޠNVW]#Tz'L`>jyIT=%??+#nju̐_c{BeB9=4b}t鿿طj+?bRzjmŶpÐ~hCHĔIU/enŖa ⛋ `F"BOQ$e,jg6`D;!9Y,w&e̦ Cާ]= k)T2uϠʼnRޔu~‹Gӄ?8aR1TT)mVkNz峲G5+e dHUjKL`kYsߧ<#`0b ;~M h0}r.xuWnƟ1z(АOr(Й\qP[k(GF ({@i%>!5, jDQg1iض[ F܎WO22tQDO5Q#OI#یl!鸕mVgQg@O#]y4Zn` lp$f a}1+AgzpsmE$%’F, j3hBD‚2,+GP;_ALzu`荕EMJ+q[Q1 _w?2ˈ7[,YjNJRFs!3iYTA#>ƪ{+qˑqF<Kt^0`Ļ"dyer! !d-^cD8g|k?!h&Z-@WEu*Vh`hA>RExSS/m[p@槵]! m75^δ^/[r%C=̓ƌٙv[23 L]ݷ-Io}apCZI? `C3cCVaUGդʩ)|@{ :K f\*ֆN FQHx"l9ia#&"ۇNLIyVߌ;aPZc1a8bQXLBK ؕwc=9SO'E69WOb{G©b-Ss_WVZ^Hj'+6V8;aѓkG_NsWP"xi(<{, SD\/b׀?^Cwp*?uPk=eBTbQN3(v**,-wX.X+Z1|'|GT׎94&˳>؏a4V:ln_␺`mWGoteie)D"P5P˂˟1dJlBzp¤)3ˆi[BJ <sl0"ssss,J,rV!{aR\ t2R"2OCY"'=Ipo&uLJf%\K$j 8¹~tf^{E?{Jq^UP@+{08hk`G2avH4b !0\o΀ H & ,*8A[Gr=P )*5R[PNHۮzoĉ:VE?v!Qv%@?AZ9mkȔ35!F|}4R_? Xs?@6L8$vP/Dà lD K30-Ru&$Y m }gA;IF$8Q[HW@#BN";EOCNx7c"_184>qPaH1+1,O Sڊ~҃Z.>x ܠXBKfKc~0;&!Y b"Ixo}b,,C兕 ~pD oCO±'\;Gh qY]lGVb=GP/!PR^v&KpssDQZe般eyQlg͊Yv)!ňG*(SοiZ2)!qP8\}c eR Xp#]x|hۆ'փ_ɵQ`m.<M>lM.3]z[NyJ$Lgw>bBZ#EՁ+kT-#%+.7!$W 7[_CH-n`>5o,>~#]dQQ. c25B.`co []}!͸9js s3Z]25Y*5^ է3<ZKҿߙO P#u=\@vÓJ:lEbZsQ6qV׌ t 2_3H'Q3 3FpYDq%-<6"SrܳJ5JKEl9vn I":RB[gKs.@_I|rV} ^dc]mC&ܫ^Y<`]dn:>g6$;`U.5˰kʮ\Cڕőn{~`ۺ&DaiWYH PKC; FU^2pֆ!QpINdαi@޺};{K \r7+M#>b/F$1 6-*IL V/r;…f;Eͼ\(i%l)鐋rWӠWkrדm@ҩ6!>p2$iXXٕ]VL-q1$iG0pot3YNӞ@_2ľvN:p%51KSF%(fB<jm Xu@/ΐ KܐP~ݚ٬bE8 ,!:?e6`3.szvd?jUϲLj/#TKQKXhl&V!ʤע_ |,XW$3)θ`2-p9k " ìΈ'CxWؚ`' ժHGqG䠪NˆKD JCNB E_ py}Uc >f.%SX{eħ7(?gTINgJ݅svbKT)WBgN #R{+i*:]$4 9wl5L 5wlLsvO(:ZtX2sF|Q{Q{Q{Qy5oZ/V_j}6V쓦P~D ,ELxNں=,sE^+~S̙0F%+M9'f4+e,&f_ ԨѪcV#djaJ%̂b%\HMFͣc6VnŕY4TEJmbt7̥7[wl0g65xu/ }݋B_ƁjǑS#EQ ]Rx/`=`c3CP\4c#oؕ *k#jj%jש*O?N%a>pq=?B~)ێ4t@1hq`s `yH>> fG!Z]{*Y3aA[4٬B_ʨF) }?vd6Sƻ<вf\㪶qoDc>׎ZGWzZ|H=bwGwphEܗNtKs`1uh9mք1M@'V+&: >W?%cWg"0HF_pKpG\{xLʇ# aȚq' DZz t\dRӟr6r^t'-Ų9=މhA)]Դ]gu)ԍLNe9Z|vJ좖-mF.-Qa%j9]8ƅdDWtn3b#@>rջKэ]qvm􇴖X{ ˸(6)ڳ|"pozIco`⟱pߜeܳjo*]J< PgIhqi\XbZk^x%48p*RQL?jF.Ip"IS;haTttwD">r&Q,cB3il6i]:rb -)nH!v*cGgJ\.G^Jp_shD+˴[T+AuR lkӸtk5p"T-q{R2btܕuSX/^Ki֚#K6Ui:du9Qޥ&HQzF".Dr&[\J6+ґnP+ɘH,EW+]vYPJmt9DvZR.svZi+k(:L0>r \bh8O5^:+LF`בBJU0'"6 l"|T`mi0E' 2(i>+pb&#F?Wٝ(zG&K E= =D0i#f|6h.XbB#6?e c1b3# btf;oz5#j&{m)m'z RD$ztAW#*kNl;f\/ d/7> x[\3+!,j:hVXϊ̝L7s|7X&JIv%bsܜW?Y!9 kGQw8[֛k\0b*A[! o668U>ޱ𝕽kݍ a:1 ĉ5_IE;MDj5#+g-pYyz(هGpFu"B`CF τpNX>z|FsCܲ 6C=ɏr(=y~ڨ,7$9<3Jj- k2vO՟Y/(U`6ٍH`6 r%ț7+EzNIpE(3HP"Rr㏫2y GHd_\<>^U0fw\znܰJ4kFm,&~fC~mNXuF&kr/ MVu*j֪f>x_ȭ6 ɭY{av&{'aNVkLYNK Opg>t ?{pV'p?Xb yA`ØEapz61KVlI6m,/6#㦽ĝōp{s.ĎDV}V0s_D E!;֝|T .d  *;LdpGg&9*K:tL9G5<"ǽ$Z&9͆GLgZDRtV"t<8{aSǢLb< 5}eei7ed!Ec!OJpVƖ3pt=5{h!bMxdxrt3l{sE_Nh@RrKI KR.1}*{5WCIRozZA<$t0I&K]kpqDݎ6U5 2 VY`Aٯ"jl,+U`oI EAkjŅ+z^XE`^xNnwRp :gyއB`|LWv>yyo=?>A -ox]O.ktv۴/4vbAh{>]nPHϲhtU-dDᤑ7az6JdBR2b%9Z6=ޟZmE V2( #|SHպ(QthЈYLaTH:*kQgif"4XD ~b?FeL<7>\~^0 89>p2;mQtlJ9# J$`.aLJo|]Oz& D'3M[dotHK| Qޱ.p=6QFz0iM!wt`((;8*lWJq+&C׿XSK1o(1ã{3ߕ,|^ˎ8 2CC;\6;>tORS3Fo#iZغ63jwc{|Ï3ёgş {3rн=ݢ_cac/,|fs( ˖FZ:N90@#2 . j{?LKmRaʒ4ǹ8ƋMO pk;'9m0m,idIct4G[6Ɍ"tMY pkPGq/${9/d]Ykq='nD,¼>@㞌r@pm<}==Ks! t]enN}c-3^"V͎2WX~Y"aWh!@Z!J:#E܏7c.іa,{'UÞ6/ =hk`^djA5[lE~SV} X7UuO9}8_ΈW鼳\Sqe͊ nWXr؆D٬cCmik&5}O\7[ ȫDz@YRq8dQd9 e]|iMs.\_)fT74GtazkY=pN!"uĭs~ħ>= 5ᎇ>jBߘ .Kỻ[Χ0tI^쓚u0:pqO1Py5@1 \ xê,sXޅB>X]gGo#rw6ZD( 'wt{֬Ti RI:E^=L>ԴfC9*u3O+A'9+^G=޴?v}=س>5*Ē&d&Ǽ%SJ\Yinq^C.iʶ*iҶ2P|cJ"]Qp]quae}m2dI Oq8u֧=6sKS,R1E8Sƌ/3k\q3f]`dA/dY4$KYGv$K$gVB)./'|i"N*Kbo9Nsan#ݭ޶%J{[$ECT7n)'@"}d0bV~XXJXb BJq9lAo F>Y ෭orkˈfMMGdX]#vIaY0?LD31ųj{Arf1!3#zi?#psKgZQ8 X~7pn0b>'4fbG=cqBcSRD]d􎓖&ژ9HoL'z0{UC_n[xtRr)$@h?\~ȴ+v,+ !T}vv4!'l{J[Ψ@2DýIݪEګ/G:m&;(X\i"3m ` M"۷(Q'7ڲd[&8,-K'ŊMJ,MD͌GwbRV?(:JAY4T¸aI͇e'*n@kdE+fwzchZ !^b!f0Rr" ,zHKδ}GD1ϣ>+fO#~o0}7{I;1x .3Aq!`v@0) B~=d- ?ڪ[LW43:d)j@B8OBIߧkqG "%$U^lZ&_K+V"^CH"_,Kw 3Ŕ#@rȍ$jߵzARZh:݌=utsO 85*z J]pm dqC )MPvsôMiNMWS1p2(IŵbhMij' 0lȾ[|_Y %C8<3QntzSXQ;s-;ܷܼ߿oOQ~ڃ[Q;֊x&.UoZŅE\/Qd(z$|HqM: [(:9\;/ZUJowZmE5'6UZQ:j+*T"S7#(%{(Dl6\KJ+K  浯 FAx5kd߿+>bԍ F&Bo<0sD#w6('MSWr!4%չ*V rְUTjEf\\mÃԠx@sYre(T?:Mͨ@³@QMx#tYEq =Aۑ3!.'@@<Da&*PsjU}TbfHo*dz .#rP͹4=)yLufDccƥ]T ?+FȚ-a$c ܤi22I޵b4k1"TtL`0+f\M]sccG41L )[G;^q4jU{Sv8̶cbvfVln);M46+*nl֠ g]TV!K%KѺͨ<+E.dÍڌں 6&Q¡ Q 6ɒݲrR3UI@jFaEV#C,d*A6=1jP6niӮOopO(wWb]iY6Ś&O򊷾e6Ԩ*>{)d3 <m{;_%;5TO_쐃;SO#:!0j\mGL3[q*}W@UPݾ~* ݛRv?{k4k7`-Fgl4c['Sl q(Txf3k'iO:RNj7ѦfEkxq8wyvO]\$-2ou.31Af.|2ouEkҴ6zYLSeM-cr|]>{L7y!هᚏ49GYԪ|y ;2sFN>w{wIyШaj <N;qVz+n#@7x8U'ڑGrc:u#*(3:7,ߘxl/3uSHXif޼fx]Ļ3rxdw4||3|Nlfre]1ÿ__> ?^>h4{׽!zg{=3`L0*N7e-g2QM {S.K֓O]jl훹v/ g;s+˨XHp>Ggg)_se{μg/`1znz@Ս!Fi1V5!جrivOZt.3 a`4,x6 %HiZZs\ՁTA|B7߿ThӸܦDn$I8d.=u_ ̈f P|<78iFN+v0 ͂,4_(7I# b@Yii[h|q5ӭDލ/@VC@)yuEpAG} ;ܛSGl爭T'H.2wEuLnf=Rw/Y۳|Y3 ,srfh /+3xrsɝIAqՌˉ[?;f"l[Ӌ??S欴kgF+b'ǃe3 >_!᳓ɶ3⟚ w7U3ٱ=kb\ *XWB+]xwcl] s/_&|0SKLUcNsRFQ=#I"\A3pW6oWh`$:;c8sU_;|8%ěɏ͛= YȐNyu |PNQa)3FXbD7Mw ټ^g;íqB_:^n*#'g548J˔܅)qq|N/ Hi`fl7LJs'p487Q=)X ^G<7_U7 ZlWV u6coMRsfu(=nc*SblCR\` ZThEZ78&C\3éd2=`og4R%;n|Hg<Ć@<"P3X#UN1#c%^;.~LhԮt^hvU juKy~F#uQ[zzE"cI>O17͕e\G (:MϏX-:cH~zV賁6 ~ ڑQ0W1"C1;!J$(41pvάb_5Q=l>g#H{jXyGƜ%UWN;(T BibŢ>;ΘSfjR)*y<;Ikba;ב㝘x cb8bL:ױdVח+.沐^Z<;h;R.!\Gyuo%NY0-kEV.ɹ|{\zYBRl.t;mUsk7oh_pm(ogpq#mC:]pET 5*5QyRfT78}x=ػs=ŪwܫR3ɰRW:KUNhw3vTk5 7J47DwHt$cpLvGZ8XEF UIֆUDifNKTaQ}g]]xڕRwb&QA^q~_dPGE 2"<2-Umڥh=ZQP{WVPJNڽՆ;Ak(i4Ycx5QC'8{uL[ͨ~Oe$b#wsswOUPD/ɪy%3M}*-=T5.9*G~CCPpKJl咰R_!_!mT{1ѤڀF0c3] {&tG*5(1T'Yg#+~+43@ìAJ:*5-E}\s !s{{h{OJ|Xʛ~&7GVgkx@VucGu*/v4lL1FNvFW2NyZq3gɴHѫǸ$xAǸ֪;z5 OH*+ʻ3_辭e\hvwǔ O_BH..жNW3/uxߤ=sSwܷ_C<]Zw:|~Axҍ6  ;FPwntWZPhY Ӷȴ^ ~>7,#|x3HLΰ1e;6)MdgSnɞ:S2Kl>sr:o)f8YROYdw; !*^bz72J/tr=e3#}q"%6t RV1ת0[X*\s$l*MhvQ=oh_ݖ)2:'S66{oQ޳1v`#?cYg'S%PTK 8_VP |3XsxB[Hĵp)/+p SLyE|/b6=/<>jmbCR9N ("_9t"2TY6 8'4M BZPOMI쓖@~dNgVuN0K<^exS]y]ٟ&'K-4MS&&E3ҧ'.nʔs)}_ "U!ㄶ=Rӓ%RS:WI<9׶{~;`/xjǛ=Vи?ڹ#<,-S3v{G;go.;n6aH҆ZX/6  .$sw{BU|uJ([y!eTø 1n/.;(̤ؑA:# [RQeȟ:7cF؀>-(;v{[%5$df[IgW4WoK,jPVJuq lQ66VTim8>SlkmFGo|TYmh f._Q#.S+99_bF%v>>3z'~9+3z.l$,zwYىFHss6h=-hJ5>@1b0sEZdppdM&k왡atŵ፸0D@`YΠb[׉&$Yuitʸ7 ҞOOy LwN \ uL}~-j7H܅Yb;saݵ;!慯աEe.ܵEhxܣKuhr#yr9vmgMԡU1Ez23LAxݗ=.x-e%Wjbҕ*v9j፤\%k$%6gY4wO E<  H=$Y6 qe*4:K蜤҂iq2 mNX^ &6V63SYe[v~l OUWC\Ԟݫ#V6PGیNZ5N#;1!#bYʄϹX= ھy3OKj5gҊSY 4N]

W@7PɭglDq|=xGtՋr+=SKzײڸobDB 1^Gҟu𥏋v[קw8~I!4cM7oDjs,T`];>I&&n&4Ҏ3$^X|ѾO+bW(o>̬Ҙ~f+SX.w7}GKwŀ25mRR'-vxG|yGw?OaQeYAQ, o"@cgKg%h$[*  W`^9@J0ajp((:f1d0 ,u^¤7H'@-^؟\Ѱ6AxSdgy3组 33SK(HDz)mL[ aDVcïދՃcM+o=i9tV(dM Ldf?k@t#}.i`IOb6rbx;-;n*3`p2ݢ}.`H4 "-$/d’l΅d].Uv&(S{D2B6RE$8}^u]P/>?$KS/Uv 2W|i*5cd&0YX.uc(X =0*W徫[%SI  ++[-$Ue*o$ )fk4:xNqsRQR_8d5QjZKle6$srј}#XA8xs%J\$(15d]6u0 /}F[QL_\"ڝ[B(^9>ߡxwΒHMF@f-g%HAK80]`t7b p@E)*AAKL'A 4@ YM ,N i o E[= x ysęi !y4[4d 3!.eY;7wG{%_'ߓOS9d1QB2nB.%tχΫ˟z_ QYl+{̀c/{ȉ=zlOW-)eedI֤B̊grVMiaZ%*2,M@*h Ӌ̼T2JHW,LߋbG_' D@sw=ܫ ؇_ߵ5}+@QܵŝE7}iȞ^,BW$D})PNhn"ex>\ tR+7_1ƙ r&,fR&,d2&H=t$_;?=~#C]TZK]j$-ku;rR(EGi^r·S#Nm3rJ{UJW'*I{b[{sh]ϵcōPt1ah|s_*ǀqRHOY3#v`lQ3rMX7Wv*q@ yd#KF9z&iՍFgȕ7D"1q[Z!'$vI+#x0e.1 躯݀ד|-p$r &_Sa&kT/`L3.?Mu u.,ڮc->\:8c}jKΏ?qGWG. {s?rV\8}.R/}tC͐@QCNNDio:ڒR A8V\>LzT ﵻ1*ظ0g1:b-QՋ{g5V,{YuW/e*=Lb=[<sK=Ѝm1;D4'5kV_}J3_"'"ODR#y###;jo/㎣3cO wUdZi$c{ G8(x`My^. xÑ "R!FND)>mE5:R<2:QXy B^t]-"Trooܢf2NQL io+lT^ղ-jVj:)A}QU!y=ri'2{,AŃh,r0p3סzFou1oc=뼱~zzP2VoNnesU6ӝ]NH=(Ш8u'cg#|١^/;!zc@A5”,&1L@ǡaH {QF},($͍ݷ;^.uǫ=Fs|'K+ƳFFc* JNfCS .7 .Q'j͢ ɪ) B*)V/)q(*ӿ#;US=t4աm(duIcNZG5d͓R}x7y׽k'N$&#~0(xV)uEj~fεBZr:F6jֈ.b%GZoy}Nq{#w˝JKcJp [հ[k+f0VZb!kCV"FLb_bfz>OM`^ MP 6 Bn`Rr_ |Kr@h'wr[{G!jV~gZQs~$?Bpke(`E6郫QB6cZ޾ӏvK>!A(#]`@eq]>̝|u ho'/4λ Z),Xw9H^iucN%tSn o! !݃'=qߢ#HG<.UBh$RP\zL_Uī/?I(*=Pbo+vĺo"K$O_YwHnun`{}Ryc (L8az *`ox/T<m7KV6MB7*#|"3:l{q w:IXyrrj[ uZaRACVS0䐳8,5ROb c:HP! {Qlᤇj`SR|PNx"cIb5CV#('?*PWO #)ZK)R\"|^Fzq=XI|^{L1>̨[zύn<7&mbκz7SҦ62ô oJeD TB+HP`wc{p׏^@2P3@/'-=6oV_o3pQP_xGIWIJ;tmw+Wy("]Y W?Il8" pp*D{CrI4\F,bYZM`iJW +M]q VGZ3 JL)GP`6A(daR e~:Ҙ Yx"oF||ۀaTa.kU|5mWW3XrM.Um!.N0.5aG(D!^^\ }eK~u 0.]zunv }SfdUPfg6d\2yeL ~eESǍl>9C=R,Wǜ~C;KҰ&m;]\ cg'woǝWH 2_7H)f>QN?SxcOJj qGX1 z2 U,չx7 w3V,ڰ޳% fš(!KTW `ʌ7 _vcMn[$> Jq189͵dGMsRQKՖ2T1.uW:]t#ƍPd=%Bnb͈b>jur)Qx`DQmnFȚ9")c񉎥&@^īO~-(򖱒'Y Vf\@GM|]=.遶W8 8WPr('eX4C*؇g8 Ʃ>!tͦ,Y6A*=xg+=vSӓwN-AcCL?f Ϛex,\5Bf8ny  ӓڃvH+:5Uj>r 1xLVș }O 4,DpaZ')5&$ÆKu%9e+͜suKs`'l.aQ6Lb3e3\,xrNWjԱrV 4ˆ_6,_'r/dqLHV}m*{㼐JaZ'K8>!ꍟоU!ux>(f!>AsBwBE*%Ui!FJth X%G&~(PO8cu- 5//S+Dp"ϜafBlHDMgOz'mi)Os#! |=|}Hfw?qJG_D*,$:d%T!Qٹ9uBu0pB !GH@ߐV#>qWh)EtȫxI-qK[?#j$@@)LČRqR#Y6񬷝]M2܄5,pX1f q,%!u D$KEHH@9PdZ^F*s༡ӃNs.ѕԪ\UOD\=Ra& %UV$)^XB bL"o4QVӮ"d>fJlVQslwZƥEdTg>6٤]JM>Acm}n)Z Yhěj\-TXHDB^¬)ڲl^5LTa25`F<[*Qq˩\@]5sCUX2hCH4Û̀@0`r\TCAZҲ{,EeTKS]9_㱗eQօi0PFNq, R2x&V693 Q047S̮(M*BR*w&=vRy* n5Z > +^.TIXWgxdrd >0ҁN{fJ <`pgQu5b@Q9uţ?}Z̟>e>2Qtf>128jF[SaЖ{\2w9WW+/c!X+ P *B%ت ܯ*'JS]{Oך>e \~'p \~\k w+x;};T*%qB([73FraaF΢Ƞ H\**p sfo-^SBJJ?B4 ;.;fVEP(94FJB-Wl:w..Pz@^3u"nV%ʄq F0_q֕_J鸢I;TV%j_ҮkiR޶[_k& ( mj\dG/<9[#c~}&)|8Umw jƞU 0d稄(x%d`րXnrQux`q %d6p<4)jxf08tƫ&A))_WE ;}ǧ gAB]u׶'h PpO4瓊u=MaBҡS\ Pa;'D._Clnqs=s#Hv0<vs/xmnJ"*Zg =n, irAJSSjP*Fb $-oQ iG$ ;VtstkTJS' N2L[/_NݹK=!zUۅzY6g$C7:kx LJa2#Sքl;gDwnhyա],`^H}uvT3, ~܂9]h=_$Y uoȘIWsw*J:yȭ_e.(ez\2 Oe-3]cY0 O5FQuϮyYMBpNZĮ{F# -rWI2ӸVj֕ByULY.= QV]On;R; j7\e:Tv&w Nz-^Ϯ^kk|<1%<=)1bZ1^XTx:H!ͣDZ4ܝy0 g`bp=$$8 !WHnMeZ5Eb 84N)!Dv d>ziI6XƟD%a_֫ QZ]2i@n?/9x5 .K)H24DRkR W뫻p't34SIXVZu!|ajt᫋ےEgΊC 6do|g>1>k- &u 8_|@x_$ƗiI lw,s!tm Tf"SΆ˽ ^GpLO,l PlsJ#JJ|,4xu@k6*NR=&v(z}`t&t)Z25e}\drOs`B޺bVӉW]WՑHP VpZIv'y.3;\~ӑb䟫jI>%$G2^ Wop,/K²"+[!Y s*+YjqqLi ۥCB@"q3՝TCvD$, >=pP Qnurq??tU|# y)'J(Y&++INu31AsLb#){c_k[w}S/C3H[c1Y $X'P.7H0HM@L)o+52޽!ibdGi(F1Ѭt@)o LQW%8u F"3K1$"=ҾXMy9.TrsO<7sy|/w)S:d)J +fǑ5e" v$kz*yusꧠs1K 0gܵsvҝ!`dVHV\C,$ Upm^Z֟jgRh21O3:g2,chm'%+EZS=b#U]!gW\=ouZq|VʵI}W|}P5?cC;C퀙*L㇝?((%ԃTOԿaYI#9 gta|m&÷h؉EV "5fw'nMuekܠϞUP =et')UƂTl)&aWB[f*jlQb3l#Og>cݿ~2-Il> o-_im?@F&Px(УO@\/AGx:堡G U-kVOO~ 9X)eOPD1R~~Gx6\Yqo)K4!"/fZZ2#3b%Kveq,onO%)HKy'Q2 umJ?qU }ql{&=ag[yRe}÷wo@4 !Њ^0)f6R4 TP  KS* w)g{0}!`-D5fii ,LuuNgtbx@}sRXy;sqTX=WUqg/ :`P;ܑr'{ٵ}^{U#k{t,c/6ઓ;t |tN Zi 馵Tܗ{vJ\nGЂ4 < xgs~8bW=6ơΟ6, -={rgl^ؑDZGRz~Y?v Ÿ؎Pq$IuTooUyp{id._1OBAIJSV5FiZ2HR#e*uSb6(-#yۿQ$o`4w@nu PnlBgP7ʲDY\yNo AWe0b4ɲBv_Ӫ& 54M=@"69;v܊?߰ 6B3[*{ADx#qWAA`ū(?3BV¸&^Kkqz4 ?Kk/Vɀ-*v6.+,ۨ!r[4>ʟڽ:)/Wf{^z<,5KI*gc` hE6]ۓ_ÖّLYQgE Gd<tjV~pf&Np:B|g<b͒J']9,TENxez Wg8D3 uJsp4I *蜷('ɄՐD UY4m42ijkJƘ^D&_7d3U!QRXl!3!=!ɐHPurzmnpuf"t&{຦>l ݊=zxaN~=Gpm$ξoS]@*<(N<M4ΜZLS5U2Q赐{. MRf&$wuqv{B>ZHDqD%ӑ"O~r-$77=(odjU'm$|ˍyVh?*O$؋pIk! }~pUQќ dΌ2*wrrS |Y;,d5A)켧{+'S0^Wo.Y6l&*N7njV閵3o\5SA3)N_a+#DGVC;P'ST LW;LȽU2o&3o ^of,y4sQEj꣐nK"J`2q>guǻC)L`R`)L 0ԀT/2:7ǡZl#0nWøH@O pB+d/)w "V}S3Cp o\":CtG SՉV!1Q\lh;Z-RS㤸]{zslh"zuJTi9B=頲=:Z-1$ɍ"A]dGg&1 A`ĩV@5 rh (fwg2I?1>4cGuS*TԣfToRE4(EP%[A\js`WsF (wYX;0,gm^Qdb'T@C&D*I:I0-%JPNP3"8╶$W\@ QR-QM\oؓtbޱ7sMHe4tȦqQ14xIZ#Wrٙ;d$AZ "a!8Ɖ#2Ӈ{' V tpm4&Ҷf㶕BOjrzζҺwx?FV=_4Y]hKQƊ Z6e|g[֒rcKkoD(_]_wo<;z4z/tsCx!Ǩ*7߅滤$fʧ  #*(l fZ}9mqb[J[6WckcB=Z/Z[r9˔`6Rsz[_i{`LouLu_oG] lX/hȁo@ 1&W!|]%YT%zŒ?-y|>fD-2d,9 Tp0~o2ha0RXu u hoTzIu̍E\ϭ;*^vN2b=HjORG[bJ-6lZ- *bRX.@$Kg,WbCmK?dIAS0h. Z[-xZE*r^: s EV @1` lT%00HԌxL U$H+BJ)pB =|nI'>1X>I['I9G|&MƆm0FГQ]Wޚ/cp5u;]?Zp=ɤm?BpItfRYBn3 [Kn9}u>Ug^;`-bBoo@j$h&f2/XYĚMztE֧wlS*Ld>?#{@<'|PME3u.d>lڎ EN$9D$q҃5 ɋd=Ӈ 5=ХzFg4JZ{)NaS9B| }KvGvfM|z;/d!8QQ\vm{|́l=aqac4 Z5l8FqK8#8&MA+EVwp WŢE6^YSiNmBu+ `)U ˼H&Y3|!nf9{Ya8z|erRSI+ns(;VʧH8wXǂTS}6X\5H[HheU}V}\kvOm%t~VuQ>;6.7Ū.!WɎEFzF̀1dIb^@$x* Ivyw5 <k<&X?wB1f1ıi6-y'whnvFiXR{(!_bwC<}XPv2ġՋ)Sh{K54l!KF`D{Ӟ}A'ub!\㿟HH%) 80H]7";bdHWAH6<d*g|Ů(r$vO x  mWn0WfV(/DIX~24=\(c#\8UtS{.T*C39V͡'P>×X|.K>cdv] P~ 0怦Tf)0SnaU3r `Ŏ4%E7^^:lF_fCvͽw:@~w^zr*^v2@aUȢ3"+"x*q7Oðrxo9c^ O`OB\'@P"Wt.Z{mޗWt5煴Uİj ϤV'ΜXOz2˓ ≀Uz!)9t>-RFn$MjVDNj6qHM:ٱ+mb~3'mqiS4k!mWYWsӟ*[u hOg9  5㔞'f4c5b^'#c~.Ɯ4FIOg(ű &fXEg I S뱩7C<`b;Yy&X9)F1rX*Gv۹BBjZ=qz8ݔSyٕѵpѪ_ ]r•գ'L:cذ"WqՅndr S{2?3.+yJcr߀ns?n?c󗏍0 tx֥SMԤ79UOtR39 @I2Fv(p.u'cd%FU`lIU6`g(RɅ&(RUH0JTBeu! *6 :AHq-_c  _׌d04k 䚍 w6 WY19A7ق[q:RWd8/VrYiT:uJ+ߴOj5xOg7q@rraliW\B[:iw^iGyP7}?=hZ&|1 (Iٜ0*5M,7Ek0ٳ1=WѲ=_QRB^N(^B,+4ū mF0C %dD1udS&dmڕأZ_w?+J4?+J45+k3Fn+w篢ӟ\dž6Wb8VƱJ>7U -DL0kFw ɻhX__rC &|E;SP3zWƒ+9}yމ6$Bg;?! ֒ZK5jX t 0똧«@XJ(p;QY9pjEt|U} ?W(;*wVq_#\~ohាI5UxL{]#5w 0j? l&6ᗓ WK88?}Q3l<]+^[&5?G榡 b(r>DRlEA4/wfd  8gQ@/Hψn53N9zt!l1^"OUxzD1zGM1"5ycd%ԛ@6F8qμ@H@RE<ʕ:qu#Fr\cڿ|՟oίKVw5JZV;Xq ?Ú̦(Ɇ(ءH`(Q1BxdYdF UQ9pJ%Qh#lij]{u"{WIcM 3|~אUd _tbc,`To(r(:iݨ>s6|(w%K#"yc0*Ũw-9_vN Qݳ,tz@7vp:/j8 <;]"ZqlIg򇢃d+qׂܴ6Hf!(w/-J: :qc r8JύF;3fs)#'Z&Jg_r'&9]V ׮NYV{hO^!C:/XBX" Q^KQN(F(89Ej<_qy'X\W-YtݝøR,3;a縖cREQecyHgѓ/WHRX4N&>Խ6unͰ,an&\f{;*|Sf M{5|ײ-_xu7)Dkr;ci<6с+W',t|YsH=lr.Tk=¹o66۾\ݟ}uMdvyvzfANVןA8ۭYL7U, TEOq8>8S1S~ 5nV^hO?<ρY+cw.h^^1dto^o ~f.tjn҇^t'#tsT4.[꽫0w.Ai9_ʙҺW"^mjPkVk%65?GJ{/$q `EnQ-~6uO;ij>yY=/uTuTϫoɞ\ԽU)|{ B;SdDwɂU.䓞+7gOʎy"+e&07t (d !-@`{LX7zesKY R.YBP{Ŧ r~>VY>a#$)%Q%LF5CL﫞ICqsΚ!}8-~n+}txӏlO6UɅǺD~?w`_xW.oCfƸ>6%}thO0_M<[7z!g% !pҙ кx\wrbՆɺ}K2U[^ltMhEc|uaW\];j~Smh!pʍ0˗oqzlaIgHf{};]3K v<ǻe5~3oż7ƳJ#hr_|m_m>M⯸-$MeLɚ{i'{};4N:_rE;bp imq^ІMS7!?cȿא 5C`%2}mDbCs S~qcT@N%a,c9B*`c,7c_&0>韂>xn ->T|#/@T{" 3({ W&&3HF9} xL50lY"x3'Ѳ ۳@fM>Vcqƨzb+6M tN`ӳ-)e߿tiI+<0m ̱G_.hƖkbG:! %67V}fEfֺK&gk9A|ͼّY2^= eVsΤ 8q@if"vI %b8\ݯWIfIm6!6KۄK @.ނNh4%OIޅ E(e${s1R$QJ3#W s¦.j"m&qi o:'C@JLBKA`;$,)VJd^op\7fjV2/Ҧ56fӲͭ'kuuhW^YVcGa`KYq=S[Ny`iy>()kb`|Yt-'϶~dmwm G0^@a Y]벖Oi {E6O VJvʣh-$1M1!a;[y{{vRc΅LVr|8%R&urc$dǴzD:H KNm&ނ,Za 3Sg;e_x$:H"ͼ/D+{Ȓ+.x-qw5W4Weⵛ95yJi 3ٳ'y5I,pk5[ t8?"I (-iΠxUU0w;@֙4 f~u{5=on5AAs':mi~ͦY!@mVDJעYUd F O'TRnsHd2X$pDӕ<͓OCLmiffT0óBzLN-*rz5)=1=+/EeIKE} P&DQ(8(@ܠ!'w'3ȉ:2’uɘ 6m`n+h-_7\fi$6.7XQfx=vGf-ɔ3'ɉq%)iG`|c7o&%{̴A<]Ǽ[4C;,bN6=܀vZoԈHJ{˫CP2B◺0pplB??)+o*qRX7!\_6>n@/azcaˁʼ}ץꛥkR퀿/=ƕ wNp /p`[/ ӸK;e*2{K_#R) .Oxg2ST9[^pp1a` @|d\  T89;f2TF}%ҞBsU>%硫YhɲdUf[Mr +iL*@Xo K $gBY- k%3<ݾך,c:dIut{nn@IsĥoRʎ,tq3.qǕ>!.m`㚻\wC\ӓ&'}-1o͞ MdS/q-kI"gw;mvYY]|CZ8 WI$n,^y>=u]w9)HQGK:Zq&RǟgZ9+z `]0&")ZY_WƑ|"uO$|B8PTLzDRRh:$fFē땹.W"~Ŕ:7W40>TᘯLe6;ZlZ04H|}3$\vwRfDN8qN.RV€ԙiu[8xD֌njZDNw(Fs.ݰ,?)с4q-PO駦&,w{STc/}:oxcY)+O9A\۾ħÎ_M=IMn ujy7!'CHX\fݗJ1\iuQu0U2Hax)rG\ef. 7ٿ-hcR?%r ;Q`i|nwY+̑C!h>C~ύ e "fSDL<֩<+O4ys! ΒbdN>nQOL~%WgO<=dq_@ElG (3eO]>6j#qbv4,$ޑEViܡ6Ғ 92AF6L}إcUr߫lŬ0'nbH=(Q+:yM<+[*',I! JeTJCm%9f.C9s>~$;/s$V ͷ1LHί3 0Bб cdg+-btDޝz{&@4A?ԄXp"ueu>q!Z۫mt͡>dR^}s"<a&Bxaî^"cbG&@&q2RvI"ȸ_P' _ E_1ҍ*c~_T,QR`6]y='|R?P<"=f}َ_K!8@NOdA2SR)޶ŮC0J5kPq^Qɩh>SJƺI.ɐPbX M|c^d"R~C*g,Mn+>؅$Ǯw 9*FVa<2 3G)c|q @yfgbv8gjzi dޘ `˒mɴy\.~l| xsb;% }ٸwAJk&g3,,|%E1&Q4Śt;nJK3#pﳙ+V܀ƚj S6Ҙtn5TLVKnfLq=wm^svEkҴN>93Īo1 l:l}C9b ܛx,Vu@C2H~vXv^gh Æ)|A_d(hhH.X!L)BUr!r'(ٗ,=6m&:06dѱg~F/v@Tw! g%)5?< =>$3OhͰ?z + /Ό!3/̨ǚ'ý[=cbĆbZ0~Qx1!1yeZ q Uvtyҕ }%X`L, 9k  #4 8asb[ ѭf#1Ʊ\i҃bс-g4pÙջx!cJ#8A qԹ`ƶb00qp^-~ZW /v?~7^Qgn?|gt% bA Z!FPH6mHtP ~81i 2%؅(A:F F[qMn>stream ѰWOj`8Ӻ|fQ4A|uP~g4|ZOt–QM,Ƙ5Fa^Hx1G@-1iX@oJ}wc yT# 6 ie[UYzu\U9Ua9 wKr8}ZG H>LԱb,P\.ѭ81ug4+c|5FDg"V(+ī&xeC/B!|7E'\ e@tjMj}c5ρ,jbF%%ňCcxz+~4gn6lq^gΩQv()~IɘXKiRQ/SYt :~]Z!r1n 1'ƪg@tBWL@.qa "C"MB_Qq%!a<`0F㭣a0#B" oDy{F& a؈Wb`F0\@Wb-Ȑ][W$.R֟HkCZ'l,,yoX!-51= 3eU[=3E@u_@CC2A*e"Ʀu|R9nW}K~kQF-ƈ_mJ# co_M ciGtqLq?Fe;A<>$ȶ.+$fR*818tŒ,Dt8t1H}0DrfvfpS'隷$H%:;YrKIھu|d]j9\ǒ z9a!ǮOxkrI SE7#.G*;+RuGuuvB@,! hՆ*fk ̽f`oAr=bWAE| ]Dngqyدr O]܏`Q ZDV7y7WKɠd/X'zg`K'_YX#}! LDF%Ϊ^v?u w,=vر3AÌK#"d Dn*k>L TҪhnI-uM$RI vgOp(shKf-MXPlG5;6,'"5ai5bVRXkXɅ=wwKʘ*P/,#8QYܸ +!aVn7fF3fm8zPEyۙZQ/i;\ \a~P' \P.%t%7Jmwn;ޤY>Q\?$MQ6IzDgcGRmXN_0mV`I* E E eT5 34M8VcUX)Ii?Nr:0逓k, 6x5kB&odQRD)ƌZM-PQ٘X l|QĎ#1hմWcX(wQDs'If)8V[_(j#Dφܑɉfc%bLKHZX[ ȿmu,`Iy9R^Q&MG",a)eT0ҳ=-ָT)RC0$ֆYMS f%%GЃ`by.) $hbemU&",f\D%rQ1KIƼѼFL,+X90Y53is1 sҗ#0b:m.aD46{^ x6geszcSgPЉa"W@S,?E 1͉.kc%lUĖelC)XoʖdÆۂd-(Z*kTWHNNy0,/W_rxE ؠM"Jۦ$;]nV! OD[nt=ʤE#e I\Q d)%qUJĊ<,RqG {S[ؼL%]Եjjh)QYhh`IXE[ FѥR)Sa:-v%:*rtvUUVSasVK.1:hFMtlɎ!~Hs I ^Jcz0m V6 @bB1C;0PѢD!s?ǚNVNawzqudU>!Ư`|~H|,]BC&N27磘[M=6&R:c;]AK@.ȔؾjŦy!AvTKyOWY?o*!+f2e{%D]]ܺӱgc3sR#Hƀ"X!ե ukw0ӳ{6cڳI}<@ jly: E+%rU| H;(reDÌ CaV݈۽9gx{{NZN"֝ßtVz\A(irw''fr+笜gǩ=FhËZ:5@CWpp:3ݡɑGRooĵ+IA kEAv3-kƩB \b$"/$+JV׾G #b)1bZ.#O2E'ڨY!gN/TMB_<- `lH5TP}<|<S̾{8. RH@`x$pwID!>mO|{5˷{FӢ|"ȎL 9 M0U\*@F*AG D3'L<:SsψB9_/:A}(Xk&ʁKd=||wWCyUdsx)])3)N\ *kALf,|+][NWKZુ^qL@ n?D(:l=}|Ƥn iOX%m S{4C**h[-M;!H=wώ[BH>;ޙk v)dώwB;P"P/{(Y\ 85a8kMmŹ͎L $$ >|D-hDT'0c̺/Sj)\c9T>]CPqݛ=8= l1_ 9,O{%L-h: 9`ޱBNϯ)Ԩ(fYrx,c6ߧ݉&X\K*eOr~;e;mKƸvWaE! +oL=X4al`h *Bv;RӮO|%&Kɪ(G4.TvEXf;eʷ#O#J yh*s5IkԕlGIufh#M@"nȵl8FW &_;jUxw8(O.,~எE[!<'$xO.ܿ^q1yd0")k;UFh)iO<۸-)75,=4lhVA8FB&iB5`Q{D38p4BQ,} FvmF; .m3H gPz:&] ]u%k^&t)=r>/]8/=jrZ}@j` )rrJqxtރfS7@fh0u1GLU9e65zvިO AU'Pޭ(-|GYZJ#7ew$־™>hO'&}L; f\K_~AgcOG1YtFK?]EOu*d(E.<2 l6܁IQX,0n3RZ%nشמk>kRX:($!rlW:CL$G`<)"۠JqQ8ֵ]}vBp$v /($1ll2Q)G61@ .E JlۑF%ƕ[6gq>71d ıX^ OFAfBيoEpX3PRb6ۿ`yb&ZvscO$dZ8g 5'Vqb/2imb2 Z6zHA=T&@JB[Cu,!Q k0jJh~FVzx6Hha_yDc%QIT h$̈ϼ [Z=8MDl(OG񵟬^XsI3C>FZ*HeܛW'zȚ WCTФ'-E狈YI q =Q!K낊" ]LWA#5F$jZbg!o(T`flM?݁xO\Vje֫NG uf~vUz>{l0k?_ȔAxǟ4?R'RA}(^ G|ȒE(n!'3:VkZv~p껹{=])X t xP,H$Bˀ Ѡ $APk"@*eODގDE[t>$yԄu8,"3IƘ$oӒɎ]ChtL˜8Za2,+̽S2C9͝: ]E7+GkXK8$*z;zC"N6ڊP/Fp,7Ʒ'<N2R}fƒ9S6XHݭf,(R |g4#sxI3:_?_drÀxj@f_FS;*~7O|gbLvu$3a~5Q}gK3?3c )J1N_OيcC5aVIz~KgPPWIϞ )&=4FLQ>ze`gP6ٹu+|^'}`'h~75B=vK|Ζ";5eyPe˻&r%ti<>܄!jpj w: 4mS%&deGdi('K#Tw]>+c|+i<}K6GS`[H.pIP|lno|,"]+9pi#\ZbHk!afRAq.D*j9 X(J@)ht]ֱ7%.8Ũ ݨ zatT(E'd]>AJ0ubr`bCa26HKtX {XyS >^p)E"._B\n@ X)j}!&=cQޠErUq^Q8Zb8hÙ 6%! z{73;$gn]_~eC-JT$m[Ew];+,}34՟|wFɊqsHn%A'\ȵl#U{R;+QTS@ (%i7 @gȟ#kq+\z? {DNpo1@fNRNT.Hsx "k |m.#|xG3zG I% !ϡW0S17Z-ۦ--IJ{ה fXċ1` baAs8R;p(7j[[;@kAB uRbhvFUfT_*aݩ"IM2.<e1ՁO(y!mpuʸ!oZ;``.gY5)Dkf Τ{ɌםJjR8Jt^zL**vjV6mE"u$}5 J͈}\ ic:UUR&}33ʛq*uәX*#9N M%is 8(<+QƐ0+I!~w\s^"Yup`C@w\B$(HU0Ju°AL Z+k[cxf4/- 7lĥG8ƨdndgLɊo.>ͅWVOSDS祃ϸu*c4+-.΢oMcLo$ C5p[hhtS8ObQ8b8I] 5~gwz?TJd,CH-Qj bIw>NL =USG'UBGp럆rUHP{drlv8&*\)d&.Z:ͦw"+yNRA"7IHgĦZ4>h@%ў"=n-k". XÒ/-S?1QjFU_ԿUYZ u=onTYoOG)kvT&$\$lTxuv<,p(y] 0l71H kM]nktp_8XM +A*~;_:7aF}l T̥8)fcN@S>0wj˚ڱhN + F9v&XVeިa{ԬK/ 1l"n~*b e,({![F*pQ-b&MnqԨِnt[zbӭ4{_O`|x2cf瓍L GQd~u 50#xOͰÄAfc!ME&>5zafhV~c#OuFQ4`%ͺч`7Jo G=DP id@ ņf-Eߕ XEc<0FmDo)z׵*㙅τ6@ q #;24JvLnBGhO9/.*^HKk)s,?BUkU"x(OPCr8\>wB xPۏH`Zv֎<V]@6/; 7C-f{z߇)7tTvA9%!`5a(JH `ȳ͊сD@ V)@^P1}i@Q_ -+ItSqJe^XܠJ}NJ` cާ'RIHyDvVF_m@ڠB qQc22:b= V FxU#KoIz< %B,= :J:2!e8CD6X!x+uǮ"TW-b+0 ZX!  $Bag2s)>y;_6P܌w F8]z\m }'1M x >y $0apw׀&4}+@䁮e{@Q !pKgX 0f>2@ƫ뻕_ީb`qLp1IOR_@G' ٢͉cWc-^x7$ ^{qu!VkFܔhQZ²Lv I0AчrmqDS؈ [wt(vj w5 e-%3aj)5ĨlRARxsDN<@4[mRNFY3#1-)?W Ox^8OdP>( 9|&UNr?07m.͝Kz.C[y1`Ʊ`61enDVUVn'#3m#ClUrrNl #R'Ƨ ^rJp}z,]'p=W9K=|[kћ9'%+Qdadw'u|,`fb˕9pTtHA{Bs~_*| ? : S4@x|p=z"׌/E}b75jf \Ʀ`\4.(Â'Wd$/_*BoDwM(wJ+V-Wf*o?/ ~Sb?s95畳Dj 7Bzh+̙SixbNv9,\ | U,@!k`B2 6(<=j !DFFn0ÄPQ9FcGe.==ҪѿpYœÉ`;"0.]Z+4' Qn_6pvHĺxV90pQ9EEqVgϋrnZӳ# &G^ΚF>B9ֻ\u'zW:kMzG;[|wt7YP-я`F;Ñ@=Bk)"@'xFbT+jQ㻞 WW'PߧSV&J%3ʂܦv=gk\dyN~.E-a@$fIh(1TbNpZI3hH~ܠݨR V$yU j0 _{ᷞog939?^o0m!ꩿ>wjo7"N 0j񖙝XfZT0г *js Kܧ⮔=AO(FSOOIWgp uG^O@υ=djzvK={zUAڥϵVmo^δpδSCv(w ]Ιw=\gsFN5c.&ޟrc["ծF -Ϥ[&㝛-~Z '_ Lm-fUi#^40oi)ǘ~` `Ot@*Q  qcvSk'@'. L*E\Q%㴢:$גKjse5Tc jFٷX\y=cw1hgo|3:k-~Y ,zfR16mkH[ J8Zm|!e}%]f@-#rCX 4ehl^83"> OC9Kq"8}-'o.SF1&=mņѦJKRZa=$ANKTN |>Ѧ:DɪEqpzQ ,stb66#ij`6jL,Xi&7d 5B:t8-dDa&\|Mh4}4g'Ls?` ]`38QyL}nt+C]9_a5`>A26-# Y;44vgO3zsj9M  d ̊NO>ыG:P" hOΠk$YuDBB*^GFo%C@$q^wa- 1-cIifJTR~-hA{eN0N{T&U߹ M5mWWd ♐ʴz]$L;$fƫ@b-# j\!ȓ4!#7v1==Kѹg$ P|:ڣp⠋3fXfӔ9h>ΜVMG '.%nQ˼KQ2ڂo |dSaC3m;8\yG[be~bmp(f͢[׺B,{&{F/WB%Ja%iPI(6;T;oA&C7U~>Vc CD⃻@2-wL'TfCOK]%JDհjazT:m JDU Df$֍ B_lH^XZZpH+q$Ƭ^Z*Yr\{b Q-iת=~J:ԁɰ5;:"un/< x2Bf|G">:fq`p3Sg4=Ĭ"b!XDL!x){$^WܯŞ@4M2-E qةdl?B}dJl.mQĔxF)iB=H⹆X3 6: @cc-AJ?gC$p=s򽆪>F>7YkPGn3=0nFbdh7xɍsxoҞp졶yx>xoS(FQ]0YLc@^.h!5m=æpF:|k Ϛ$XǃDHtoH2W9TV":0D Kd܎:Աʈ8BL#:v_rmˎ;x^>Z X @!/UPf;;Z7:wdXБlp/95iP;27Y^E07 Ĭaޘ,0^:1Ɇi9c*fDq2[j'ICndVʃ뷐K֔M$@757|ìr!ю啭=Ì$?^CtD !OTAzA{|܋ƘlDcePS}1Cq`uC7jZ j@P\*;,%͆JfۑxvLO"Z^a.Ϝ9fcKܷP`1Bݨ-l+RT12>/vjO{ᾬ Č )]a">/Z'8ET%QZ!;z(Y_NK"菟? .Cuжѡ6 .[}}n+ϚJ2E0cErKFRFҸÄg#Kg3"1\QIx@=gՎz;tI'2#!$J &G,F3 oD3+bYi"d]VwEܥ)1o 1Ůb`6zQ^&vˢJKPպ,V%)TJ;&q:\kr>HJ+2fǟ:cӆj Z#X;FbƑM𽘭A0 ZZ)NQuNŠ_ʳ7 慝O8zf^Pr8GJQ/` (`8C u0 かD 6X'|mP ' /lpxAL%݌mFn~n;-C5`btJa#u8[ԷKzr~Vf#8)hqK'2JP&ZP%,[8D͊l>-կ٫dR-aUi N)ŷIxyP9 G CXm|dmGak9ciK_?L|+cf AQ/T]HU1ڨ+['$0b\E=y Ϧ6eʒ9/ SyNrGBnrZEܘ:}OE= qخAz`qJVƩщI7mX`[Bu'г mUݪamjs_ Pd?a3^TK>[yao D!!ZPAÚ |Ngъ`Cu=a{e| kYc{glNi[?J5_I! sՏTw'  ظ{o'=60y_Hv0ȗ㕞ދw :@?*cz'$@1! Ҋww~Qޚ[ӕ9Bi xUa 4ib-l cS|/g _OH KMb#5RB,y#@Fxx_]-uF[QpeCn[*HG*=LN{qJr`ъVkB.imPk5Íw %Jh.f q}xލ!c:,4Q- 3S#ײw>W.)wYY!ERFܳ-@[%AAU+pC@juQp[`HE6;dl A͂ -1Q# d;Z6E>`G|Alk$";gj s&dlli'Gc.)wL0>XOVa?X5}FF7 U<"H&Qܘ3zV`S`=%4ll6Ax*<&8+qU§tϑ)'ŃoקM[_w e[ TA-0gK- '4`{&Fq3L3L؍ toè'xooeh=ޥ<<`:b=0[ZxnV\2?j:AkPN;v/0{y`v08R) z-d O[T_?c&,7,~7:Ȥ}M#~pk|1 .һwz3.­:'vǏ^-bx;v }kq<7^5VAfu^f'z (9xCD*ιrD(lsKpe]|RgǞmep֪ϧ>>>>N݌ q ں%$и {/G8IGV"Ji5"whRUT*;iga!gދtr'ƉHCxTO+/n%',ͳ ;}}IIϝ%:YzW}.?$:?GEjܥ̩sq#`:}WS~WァN=@ow}x/4yp⪧:6|*ɦ@3zq.نϢb-JAqNAD͝!{)͜V\51 |R+Yb&xE.!:V5.9G,gѨԄ o6#[Vf8ļ 2t?zzKT>qP D YVA=Ğ"FXzXN8%(MQErV?'XDk$L4Ů1vhu S=UD9HVChu>0 z:N'Rx`"$^)E 9sWcu#9]k&*M2wg%JF {ّf+ 9~9-'I 73l{ΘU[BbVPOOs \6b@ac-P[-qJV>I3,4 \i"3*G;p4ӕ_QsUjqlrtc^ QUmI>!UZ (ܫw ;@d߆'4!ޭ/ĽLXM!+P !=`E;ʠ7ZOµ$R|ȣ`1wgަOgjЎ#Eu0N,Zf7ʳp|вƲj iIS,'uay]MZ=:J(zxL\jYż^I^fE+'TOVUޙ̢IYdXkJZZs0(^{Ly} 6ߔOޕv ;*?qeuO@q5;*WGJ_'q$Vy}8Vs}κTQ^w|#ԭ{֩MDoߍCl̋ھU>WFw=MKG4::ioVZ5‹*,%-m*ۖ396&0#]j0:۬V5rq96Q*LI$[T (_?&.[޵C)@, 9EʴI[6ೄEBR_N{6b)k?OŒ" yO9|% a vm,(n@<:0`I #o[y rVam6q Zn-ظԢ9M-@N I6V @RB ڒOQd+#^z| H@F5%D.b8h -2Y9ob8ǰ>=KO[`|.rv 1"C!N;—q|X,}o ӭܩlNna{CڑZ3r"~VK u z9?7tI:Jɤyoдt>DP?{`VY *U0 B3@[ 襤B+^0I*S%:<k!SL"IMvO݌鱵#ZZai%a3(w>3&  t^F*!)e$::#7@v0^ހ#D^4hF6Zl4o q9`2>dRofox:rCa0B@R9(!p癚 UmZi}C4|C0MD] wgI':ܛ#{>1 XUeU^:%{ؗ{KgtJVbCLdQ-Wav>`i'&㳑?^k=ä+tuQisF svjvIQJHUbdB2߫Nվ)ԃ^:w`GHBBApK+!<דkyuWtXޤa򆪰Ƀݦb'm=k@Qr2^!b@n)GڬCzDaFR; Th߫qbfo-o"} P_['zq;~ϯ~l9m>MSfzLN5`b!@'~hd304d3 7qߜ/ 4J8yЇqPc j U`;ea6 bn8v}#kXOxp1J;jNu h50 C@jwXJaBRŭ ߅wf3L5\WMwT"x W; -;p_~ftN14*cTwB>m\j繁r,(oP6FҐrFXTpݜS!a;Pz.RM/NNKKdRoLRMWp”4suҟ?>B_$`$#S='{RAǹ{Ah6P_2zE"lMmf<ن9 B")(!CD[JPEQb9:*j5 KtnGSY#MO ŕัD!E-r bZ#VY?9]:m3{tf+N9k{66y%C]g?)c=z%Medwƻf+NIqK^b"?_5.aƃTk)[?CٲktPӏ b QjU#EeF٬â.pOl$z oe[+ǚVf՞U]] ؞vcaׯlW8OQT`Zt{Ԥ:58XLж\8N5%k_007QmziƎ#Jx$zfHR2 uMs ATT؎`g+7.SS"MJTڃm.z}M;Q7,vnj J?j~Q|if :7-hz>0#S(=lHeugPxI<<~%xw@]h@cJ~&YcہP3 B>2FdU?m5OU:C1x"@Inu|U~ks15uSS/kwԗ!pб]7]יʊ*=r!JY$BW6vPS01x~`) iO(yIchB>Ni)X)L ՞: h8? 1\ÌÓ47Œ^'q60w) EHFdըF=FV)[#;cP[a Af@yq[h*"0;\ޖV&$[=Þ{"c*Ks vBf_7/^[ΘH>)B`a 辥>=qy=_yA\=q޳Ǭҥ:L"&3t*B\$VwelA h*~qNC[d?>è6.Ĵ* ,ү+ƿN ke3_}CS~xO;,s;~7F: +:gtzٱFQtO{quqaK]w4&UNs( 6y&#D롶CT"j3 Ɋdj*vx>N_ss9"3&8i_/a-+a 7r.Xm0.(@xF0%wW} Z0|>DZ0V"ތОc YlV 3ܞ(. жj V?Г _"1&c#̈?J[lJdYx#=eMwGs>ŒθQTўR_0|$,˰$$x,'Q/0 # gHjIy" %ޝƾ?x0I&*RR&Xȳ$!, H"z$1Af!!7;FX I"-vtTCbH"  KD&6|cS\\zH#S5&M@:S2d$Sa~>ŒWS÷x_|WNtG]\S8}0<1pWnQ=*{]&q?Y@%nn\>?ފF^V+mۚFPk)-GjT/} g aH uF콛]/gHr?FvPTqj}kJ㒊Aɏf]bWh\e}){{pl /3v NՖr ,2[%ĉsWxb> kQAO%AΜ"hх$a"Ksً/ϝ[t U "ۊMlKNKǯyZPG(ȏN|pjM1|:4]_w4 TjBi>n66k?`d|Utda]>h|Х/ȃ?j/4<'!jjj{3Tn$ le*ؽs$@Q7dT" me4qn| T۱ z"[DphN+hBkb@{s)𦩡hƦ X;)zoR0YЛ1Ɣ1QC.9)}$uFX6ԶوڲӚ)#_E@A#a? gѹzt-:բTMp Z0AUE~!Dկ1oUuTևdQ+mEpDrBJUELhhvf2*j\q?%+q:Cne7XT68ja'*>4$%m"x7\>,qqf 2j"S0fĥDAriN"U`@!X՛d5cFHZ70*]  mP'_ v5xJ @D@iϺSt&^5o4hِ$ʴҐmgw~f9g;Q݇+C U[&퉠#\)k猱s 3=~yƣ@U.B+i{/vm=< xQծ33_z2\䖁3F0RU;.rWq[(]̹ @ii:16]rCV073wV!!zbHqkO:NKX\zEiX"6o_8;!뻱8^a']['$ߕK]ے+Βɭ:"4 eKO Ed;1T ؝!e i҉"{>V$գX`6qʅ=()*Q8֥+k~ʨM;ѓ{yɷ Wv߁>i9W+2Ne9d\Z.n^ij0[Bc00ع 6tq37ra4@̛bi i}xs\wk*c9'/bFJHT||t"v+-lle\ۡk0z XZ\"}V!Bii`求m?LM_\&`]7 -c :v}n|Sk )VW^ױMw芆SwNؗ>3UI1;AN .w/ZrܠzK{ kKВV;t Rz-&S<%kc>9uI*GWj6&$r&Epy {}33JhϳgL0㥞KJxNCX! I\Z#2Fxn,[ϭu3 Tਤ)`*9!S*Djn&8nS;&\1uG;9|.d̜xH,^Q."K,qn:9xȷ3sOe!.2|)ŐrRBjf 髍|}8p9% geA *2wL(mf@+VSql$P$MiU}2U>#JXY;՘1sUO8i^U|"X,%Op~$_ v{yet%|@VҸXh7QJm0ߤUGWPe*Ӛ@ju}}oAVȻu5S֜vOnXXY㼅x(CMi^ϝ[@ "]6)nM?1ewq`R3~`Xƫ U'[q&W\s4Įקf8Np8+q.4;=#=oqL~58Tp jwqoyo*l+x#ZӦ")eS6[ݡ^0np?Z*Ԫ*kuYzECPrPXyq%=D[*^Dϖ߁A3^3>W~ C^mO1q.[\Ϥu7ODϬ DҲCFnn!='\(1/#ѠXeC|!(Ė\0 vjW&Q1>0W]09az$WFzR{>@TG̩E5PÏ" ,>GecFnԄg_[NqR?rIL֫AO 9Rb7>j5g [v#d~]:P[Ɯ3HYZ&f%}{ $0_eG< _O_Q|s+5oQef<W7j7ga5[ǟ:?$Jڼ]` !ыb;cTdwԊNiU\*h=V2GXP_6If`LQ;5dO^O{Ph ḡ(_ uĝ4U yTn쪲L;*i*&We 8DQb<{'Oj/Sg\׹s_i, Y%Q wBA=$yv8 %ZyP;k BD!`<yrfd#<7Eؿ%ɮ ɱ@Lpxc 39.nD\Ltc;nip> c{kׂeO)k鯞ڀnD_w'+Dz-^fbi>Pە!Vp#܃[Y՜a`N =^Md7 <,RlWԎX4ܥNz _%o5>a{r/)) i3'Ou⒇\I^^r:-jI5` #33 F֊7zũ~CxXPN3\ׄ {E9HD~EhJ7_\x낶VwNqgt`Ao)F+7׉^+ d wY7X@͂56ϘҞ;y7!hT;u+W`daV)A| Wc Y>rR3PN W6JjL=WJ6(D_X ?لx٘26[XNp9NЂD٘$cFy\J0wx2xsŻ&=ٺԆm_n?GBټL,`1`E!{M&^ iN`E:Fhnq>(_~WL@$/ů{* '`Q{gC}s?٥laFOuژ t[533nT/\^hjޫ 'Uôv8aHxcQ<-u _ً΋L?yQW3p0>v1F[3_%_N[װwK*GQfFaSR8aPaRo0NP0EйQ8nWQ5c,ct܄t eD؄4&/Q}ܵXKݕ:Y3<#uGhC$D.l"Wj]lGh0*7MEQBJwf./D 6olضE5% ̈́É"3=ɸDɌE#0cu瓯1Y;_&Q^{[r<cc  ` og0F$Ӏa#4iCۛߺq]5Ugoނ\\o%M~BOdѲ@{P(9!A bC1fL6SGa9;${%aFQa׍/0(jQ ":Z<¥{~*%oFЕ9zS`7 6d*zUҫ>I&]2In8GunIri5Φv/&qxKV:?_\I~aw<Cr(~gq'ރ(@& Aq&%ٮY%|'Y%1"Y ?>ڥM9sN/ KI .@$HJ~L:ї9 HLf8d gR3S71!lFY@ψ lBYތ=ћo2h'dFmP0k-ޅ> WlI*܂T3Mh2L0]sՕ 8zKd1_xYKZt䉯}RajL}lQH< a~tד8\TtwssO%G ծ]>c<{캰 fisfz>qq%'3A%Exd fN3g h9@=n#84ja"y9e%\ m,:g`R0@<*VpVb4_inݙ~!WށFpATvs@ü8ci@s5_ߩRbkVNNhIpFXM H"VӌpשO-!"#`y8"(9@V۠VpWӶun YGGplr6;M)p|7͉kPUHNs@l9El9s9%?8NPzdES,\VGbNjcCƢr2>{8@.{צhz޵) yaFm g(ܱS݉kSi&4$vm X8/@|O/ňwUqC/ł6U.RܥNV Y)h淸)+9)ocx-Y O|F^lv/?ﴵ␷v?lg-uG${qTrQt$luJ/!_^@[Ybܷ(hJRV' >udEf7œ`7sVUFmca@+SSVZ%cHD}C8(c*:vVTH)r,*TF b ߙHEtP'AtJj9b88H5?Iy/}K}NEדձlq][ WkD]b^G)^QJ+᪴N|xOe~5hr'O`TÒ~"h޻K @&jC?O,y3seI$ TY>,]Ã),&(G2lt 4_Z$1 |6;/KcI0nEA~,eS%qźhbk9{9vmkzpK>8^jׯsS'ʼn`ur9Zcpﺲ^k_ |:՘>{?]Ƿ_aT*guG\Hv@nN;&Z."6m/GѶ =`8:w] ù8dۜCh4 LV+#TIϮzO`<\ҥZ]@S KKxk|L)1;輕\9ȵNv3vWO"r٫]G_ߥ}J;^nn=X۳}}ܻnNit d}yoϮnu5^Xu ~|zx((>̀| ~@tzT 4Cӟ$]/YR"t- t[ZMXnc8Y -?',^sf\.yFs*/2}zUkO@:^䗩+8gw?| ,{ыfFz?z8[MM_nބD ͹l/ xGfGbw-YN;s~pylp""{]scG:2#U~)Ѹx^sK*)gu?\5W&wp>x݅vU~3HR+]uŋkt{1Mq*'IŬ J KQ:?}T̏O7 XgI6H%%hВH ސ&j-㘱 KEgVNF :o۶:ke+64so& %BIDO.ySK.w8<t w]|7\W|_#ׯ V/i__̓N%z xk:|5Sޏ^ƷZ1xB8? G~~18/βO:N\cs%wA5ƒu̲IyL]euL:K꯳[Q$zv=ZzY%!hm_QCgk tUPl`=FZbY| K pdkWAQ?XVw?j_1G&yBBNY ]&my]j`JkӘ =ߗM]|4 #5{q!Slxpwq{4$:lrFԻt7=XוUX ҝps3~NoӮz ^ gTQ;RMϡcPL`!^ս:ktAX|Pd];)D FNA)@@x!Uҷi‡ki 6FBc|4uO8n,Bౌ%Lh)g,e+d<;cg=_-Ly^3|uӽQ mB<涒tA:Uz,''DLaϒv4jcZĘƋ]R>f97fɻ0 0 `-N/j׫d;#o"S>sNBH0 A_~'(#cK@ȱlj[9пjָExlp]kOqs|7g{9%Zu6fE2+ :|¯~Uw_-誙E|| &nDAR;Mаޔ(!;2KNc\9Qt RI,9]L2R )ȮI?=9n40Y|_%l)e-k yIX:?'~Vx} ;/`^$L~Yyݐ0Юt) O35BQVD{ۓ:w~9ݵܵk"/vv4&K%UɌm=Nnڶ*J緙YZhL$U}s6+=O$ s,> >Y蘺St Nם!qzSPL:Pݷ[iޫNt Ht9zS3e&/QשtKjQsQ,>k~l/s9.re8~rW~5vዸï'b8 $lw]9d@@=TޝN9AĚ`n2H$J8GRӲȋ$%i}s540DGA$* ɢP"x:uY$}}J*&"sp$}AK*@5 TIg2\o5Riʥ,*_;;u!*Ǽ: U$u +|'NF񅀷6?OIU\&rp9 !)b Hp5 A1I0 uԕH8,6:Vz^:VM]ݏǥ&o j./j'AsXMXY&`fOV!X?Y&̼;ULS-#J˽\yKZ"‹]zO.wޮ>*dL$xn ѾX.-BwM5vmUk&ƵS7\勀% W~5Nɿ=,z~K#r5fgj;gri:QH˹Oh0}5>LSޛ.zƻ^]5ZUV )\R PНR `~-PqqޝzJhB;Ƭ۳BX]MZf ѲCbHe=Kg|賝@Pgqfe鳌d1g9gk#bLSڃZXѬ55R03_.g\~}fko 4퉸3Mk@-aHiݛhǕrvM*M hՐ)Qer(=+3z&n?g!-b>y+53TJFquJ^c.GR"3hؔ\6$ %25^Q@r_̗zW~5^-;rŕ|Ӛnd/ZӚ.Em_dxv{Д1<;k^y귙3]rLEE3s3J~ o0GL_خnȉ܅9L&䚣7P<ٿO;4X@]dҳPəTtsoem_e!>:C3mNS',;/Ks?VTn]DAWcs(B$V%D."LrŠܶK_tm$Q˱׬WD PZJ'/{ J+JnpMCY막1'f8L部7ç[ܢNhA{f}8s}[wY<̓y+Vӳ?ʫԮpoM?88A!gH,z -d_Qx夷Od:Z g2W_򕝐HDanfwo7/ƣ|xCT- sM22ijXIc\B_=<K@2^ѫoIQ%m `5WN0:쨾,^Rw*>%\Gd!$W:5T9waq 4Kr`:LbhX!j޴ӨRwZ:nO\}!//0s+SsfGD.HG[,BrNH I8rpѢ$N@]4By4>(WBy|N@>-:$!A ]ͳGd_ourV5JkNUkC_fr.Rss .̋ג*P'Di( (q0&Z;YJjo;fU%:8ױ*Ƌ!DTEwnY}ɥ-fvuZ92uٿlyAmo_G 5 t׿P4̎udd'E֕ONL KSR~錑uf}Y!l#W:eW!=jK;Y,2{*A muUNy^WS`ċkG6A RK /(]g$B㦐vlfI^ ٻHu"p=hd12  zjpo0ցL k8=n @ȆE4 YwtrX6Ӕ 4#N `_{O0 |=OgctbވDn|*ҾF 2\Vp[֣ X_Ⲕ`DK~9*ad(rR;Xt }>_m.4Vw)T-zm!}OP5GAOJr(5{Nhv8H5+KםKÁ!k0%[_n]d%򫷭t.D<s>Ɓ &\䇨^953@ ((ۡthĬ30\`r@T-<t X@LT 2ɻ7taŌ ψtq %q0qސbMpp ߟմdO_]^_o=ݑٱgwTlȈmdOm4mFi,\|.El_}$hbLv?3JRd~^w׽owW;Hc6Coz55ܗѭ]jS Ŀ 5ivV&~Bsx}6Zë=rl,Y崿0,DgH~-dWU};/OdOHm$.T_!@*Qʶy-6P㓰=(%w~-v7˧9T[U/7u_otp ,aUrb5ujw:}bH1|}mw^>6]K}o~l[V;}.}[uߪ@'뭎* bK_vݹYR0P';+mv&Vo$XP|%1'_zѕh%k`]207]u>we#k.tJw9VyVyV?=櫜 jdTއ ʺw ,e$O|q!4d/n&qGyi/ۛP@j&:R}Gj5ߕ;po|^V)ޗӗRGd R{'GɊ:5*! rP@Bh#(1F1{!{I>瓭B:+c纄F`O{ n9/Ty Y KF)aD^qJi u<*>5^VJi\emĝpgyC[k^x_m\ kq<)7k#>&6m:d]v($KƞQQ5: [:4wo,90mxxדw1I߳(=բnJ[hȑ\WbMSv#D!2WiN+sHi6H:acW$Dc &.wc#εNN(fEkx@%Rəd$ 9E܉ &) J3Kɕ8d,dw+}|\:ͺEj_.^o[ϾNAѿ+Yg[=u:oZٞʼnuVڜJ>Zg5~YkN 35f}mܛu<E{IY_sLJ Z;"׵"뉒!Ea1ˈxxGN 92e6 a&1xfFŨM5S A <9~R|^e{%{lyr_ @ |זxxqy]SLxjԲN ),q,,%у xA@1OxQws(VA<Q0 ŗLǝ UwT>'|~貛Fb@; x-ųV |sbFmv_b"YE$F]IJin}<YEve[V(uA{@i Z9Wzhh 5’Mڍ60RDnYWc}ڏ®Z(^.1}` R::ƈtY_ d$5@wݧ;1޴oT89=xitYKVZkL) 7|rO\ss%PE@T/ @2N}fIW~Vˤ2Q WZ Hgj?VZ/)ėW͔}QT}wqrs0!siլLm.d+\ky4EP 3JFKA >j4&߸s64FK9GgǯtI/f..x-QŐnwq)ϮZϼtN#]Φ]$O~m%SdTL02ngd܊+Wh{^sWM2^_O! 4Z|n\ȈRNߺ~>q ywOs"ps;{gi.&'v[d|o}e"C58k]?O;d˟2̋K (;!o72w9;Yq}y}ޜj-ZB%5П3ѷ\¢ew%l}^!7P(4,cz|$I7]S(gyrZkJ_U=R;r`U8ri<4_#7;JÔE6X;>! %a*-O)I%0`AﲡA]AhNx?9U] I~G #voN;Jr<'LJc1.6>ufLf[񬾔S [D<,ϞR4$6 ᳛'lzK9\7GpIT925)[X =v}/irDO(,+ Z Ǻo0 ?F(˵$!~qBey< Z %tw-G4|,u4{F NsHYLښnr b Y^ 5h2 3`7TBxGLF.!*ԅ\aܼ Єm^ rpK >e@ K QA=.b 4&ZjDw,M:r{Fh[B.KtȊ]c&Rr,XgOW1%5+؂A`Y9U/ZhhRj"M~8 ,mWQi '3$ǏE¡89 {1mgP4L4 1;y2jP49ersMDzL% ؄?P[0͡~j&\{7yB8{zB_&.CpXK`^W8 hfJ)y}*^K됒dLxSJQa}Jӥ(iZ~[0Őվ3u = ɉǔ}bbXՇ NZ9H'ynw} \KS-zjl5ibLE(:r0tIpsOL>#jwF$/:0RWOdU.ꃩlEKXRO=Dk-NZ҅?LS$AL]zI+5QA+E' J_;' %QB 8ǁ_ Ѯ_ǭkJ#:dБXXFdzSGHoґtt Fk#߫5N2|ə_o]K"8nUYbCi4KG?po!ܬ޸Fp9ۏB/LÇn䈔("bܨdEp[#圪t-G_c⾲0 ey,kTʼnmH{^3(Zm4j+\WʙI'wIpX|z*|.Zվ3?wDt 7o8po8pzQ"U|ba\Z7U(iَo7A M&}R7A MWôߪ 6 X-O??;/_|_-o?cd~$MJokm{YPnr~ooe/(_0i^{Ue*7~{j(܆fMpWuۺo lk"4$xZOX%*#o|$0Y+~X8oӶ?{ }|>"Yk+ۿ?6[WB4Ulڻ*J%?GŶݷUJ_IePnxpYsi?|%wMkmgmEWmM\o>ҿuh\R8c¡m*;5ԥF C7dغ2j>C-u(uƖ>~ݮ/m=~6MW4ܺD-4YyKhH$*ec˭O5GSWmPc!u.+>'*N_~yΫw@VTW6}ZQTIY7+B}UTia^Q>D{&JVT7'idMuecۭWFu%<_ͯKE;eZn}rT{4=}o7?!oZ{Է3ק/)uТ x}>Ml-JYק֒.nz3cpz^J1>lMO^^ק uD3ӱmPI[ٸO3wGU73e\T-[%Vm *.\dŦhF-ݞ#wi'e>-{fpC'8 YQ,Wv S;lm sz0M<4љܣ#y~e|]QWOskC 8ezKBa-a~t+t3~b^a }1]yeO범N|73{ LYΣm#n}[1}A3]\^̄3HkyӾ2yyzyӮ~b23“3S;Ew>A8젳6E5WwR==_Ν}.?_n 4Q\VA 6nhkUF 5?B]PU|? bJl^7T+=85QmYl$flbcW[GFXc۬ G+HBEs'"P)b(t}`KXeCK 2&ŕ(6+OoڗXH u,%܆u+ZJcԕPڅQT}V\E_-Cl$1eR M}"V"X+nXWjSjEQday"^obYm^c]G euZQo W?m^.6%D%(1St^l{]?LƾoGݺ٪ zz\*'ӝ%kֱߔ:\>nݏzoSuS(Rzg%2j3{A{\RWgVVWvD/񴡂gy 9cVyue=ýnRgȈ$X)r.lCCi %UQn$;!WSq_sK=Jq mNֺԇp[ѵlE+Zj BtƝun{zgX]*OaD; ҍvROttnCRw6Zgj[Kܥ[aBKFX镂v\[\iS(c"&u1[-^y!az>宺hsݞ(-Z=Vqj!`8 UJXLn^_q_mOT.C0걾QTTOoQv#YIJ/ug+ ֩Dj De_ud (UŪ9\%6vkBf}_jtm5fI+G]{"á/9`D!*\ˍLj#Ɉ,e4=cfs=_7 Z6{sebtXT_Ӳ1/u EwMOhX'-q`m8jCqE 7pIvTJF*TrV^D l2%`zk=Snu %kD/KRn%juXY:Ԭ3 25)98̝Ku,=mEeycƉ_kَ^ 4%PW:H⊬=FϦLo/+-^]%pumG}t !Tbv4>=8V]Y/ZL =L݃.z\ۋ!dxViPjT9Jp7F㋡R1h-ںC`%X7Z 07^cw{bfΦ*+{QŢEzHtbDl;|=[K^iu;JyغXHT%n@9\BjϴnԦ#6QZ3Ya76Ur@d9"@Yl׽@<ИpȪ:걲%>,!AwCmR K;@YPɨ-ʬڇ:8ZJ~ MГğ:ɯmL*O?^tF=ā{+xUVI6)0jP&8lЯn\ida!Wq,nNVWmEܑf8FZAUWLJbriv5knl#6)f2]eRDQ *-+0 rJzk xg8AZ@rvӑ0Pk /4&/)8}8G=%`z/B[-t,aU$ƶ06Nr"0 E`J̝>vrq| b@9Q,SΌ;+Pڎ !3߰?'Lj?2i3$A,L1m*L d b#%#6ZRb#*(y7ymLkTnEҦ> 9ᄀP6u]M$ߏBIUra*B:Y hş.*A7X'3Pe"sUJ Fl@)mzH r>-2VT+_-?@<<*[tO * *KAqMTŜ9XRgOP^$ٸ3Ԉ9K:XÇ!C f0OY0褜u o)@|el `_b#ۜF;qtpj6٢2v{x‘ gi[)bBí)E*?hS7s^=]ً*dZ Yn6 i@`Pj|D,Q~z k v*ڔ9gQ\YFP9T6»u wɰ] 3 װBE\ 8V}<.(Y{Od2]+?(/'gd 9#x#pJ<#{Gmf$!=O#tSV$=;%CTYJ޶[2|L=s&\&(gu3Mx6h`Xh:];zn{&*k4K-3ɠNQgi;YN'u)0q .Qg"h{XT}}t褙;[{6QQ-21~PmL-"t:Tu^! FQA#P<H"+ŗZL-p\ 9&r6(*UN5'N^7y|{8fB0Ov$N=@#n-:3p,E !SӱCX)!K іfQ];MBa2)AV#J1E 4a\BX/Z3F ŴzkƤ 80G .zEأBMb#,%t 0+/G{DnbXc eEΤ}USS m]7(AY!k `)-ɌiySY%M|X B:`ȭ~h]am {NQ܃"SW[Ǖ9#Br]qp YJo $QdnU{yj.(B= W+u%f [䅃kOq.i5vZ0$.K gq!gj3ޱljyZ3Սnq _7wOqP Me>\47#>;Hz=@?ޙB)4p3}е9ܓқQ_WΪz%:9AÚ$Gc; n@m*'HX"p6=wh7aj{b]Zi<ͫs8!cy-i B=K͂r HgNu7s\7+o!`'dCQ.d_Y:rtbS6^8\SWNtv*!3v+D<"g=r}.}Cn:VVcQaٵ0y e2FM rU .&9F Ξn.B6?]%UIԣ9.ùª}kwyl QlWIZ;Z2p΁{r[ 2)كkp$~۵^a7w'܍#r z:CйB5DyqvqPL6͊R+pPnG] ͂i-s͚sP%2-f޼UB\y9Q_%9X j=+!kU- tf3g-qk16gJ@!7oG碊q@]MF4RZj-a*HAzm9P5 7B[NE[Np~>6R夆4'rBNN[NTw<.\YW[Np `ʴ-'Cr6B9DɃPI($,r>B*LpՄi  [Mx>V(ɞe2(a)$SHapd$"i|%PJ/`adE4 FxHႝOzZAfIJ@-JH'Hmou?_"5)Eme!oz?٣M pD( ~7$Lvh`^+k40O$#@(M"'7aA}ԀZ | óA'AKI!ifəޛm%^kR9i,1^yQl PlFC f*+x)kp¸XLON;!:M<ڼĶ[V|. 7#qQ;?`hϔeI"(濈i˖ҿ0 4kþp,e`5,,^b\0Ʉ)0hXVys *{~ ;* ;U}I/#B*iUcÔh7|N)XAuo |T "sT=-)X&P! [K暖T.m9҂(0h #Z$o/ !|6Xa@ jTH5%] v>&ԭ`_*F0kkWth25+ѦZW(80HVwaOhF)+AJV_w sAV5HmoM K Q]ZĎ}B`Y079s)̅&-;3a"i@#Akes,Q^jp@P2KE,Jڵ/`P6u`v7``%K-PsKڗ"y(v"Q녠d ҥWa%qu$ƝX- )Fuf~ǃ=T{y}Z=Y8,ĦG:1Z)M)WAN6|G(Tq W a7FvX7q:;?tidJw kaB( d1Írw>I `wj"2m?i:WlGrSvE|aT* h7hg8@%[;2qywSpaKl,a*5ٝr3ZARZ9Տ+ ]$Z?kCb eCh)d' vf DqY0E`J(XZ \ {iLE?kS`E{`(R ʜCcM%B ٦ăn0nQhErP̢VCGt8ȀrЖ_bC݂r73#frPߥfr"3?.F%mJYZ=BC Ɵ"Qk4ͨ9vp6ReHe oh 1@o7/aU4`hA_(d.V&㽖 E5' LNۄ=%.`2~h=ݏ =d̍B/p_Zq` ۋE&%i0M-dW&UD5" ^[@X;zNc68E i, |ؚm OP0:.l°R( 'j\v+b.\k/~]@8O/3ZgHpwIS/H{B z7ט-mI #*'p \2( 8lƚF!_BFvm%zjS\#s\s>.Հ+Sn4,&H?@dL ڪE,}(rg/s52E2X$@վylA)733d%+ m78/)tq d5l'@BP, $yPNj#ߝU.#0E'ijH#b˔*7i ;Ev@6KE ghbc48@ݔՈ=&|ڬa@V̛O, 0sd1K|E f5@!1yu=!2ȋra"<1ɥ|E5ДCN@^3 #?Pʉo醉9LK0у[>Xΐ 'x (>+SmtnQKXuHs 9须]YGj Gt"#&b7DzgЌ"K %D<D7gf$Ly ʹ{--(ߺ13|{T4xN˓Y%tѡY*{R.5dBrCXkJš1AKӢs0`t C *j-8+/9D"mN@PZ PڡE 4>J|_93QI_덻x++vk<8bv4Յ!,g>k?-ĐjՙAnv.űfVcbrJڅE?d*X"XlzΕQJ` [唀r!P8I"j2E+mmn]dz,8"%ZeQ.U11)N#B7C^¾FGcVw/TܫS |^hRĭ*Xjid 6s\ԑkukGMG|PΔic@C SZHuz*e4)+soZ5yh+CrSkIDE`Cy,K[$g1Z(Z+Uv[NUv)#m$=%l};oG·cǹFE -ǻ2%\+(̺'];@ 1T V޷[;+zK_06ФJ5>KoE] ;GxS-][j(ՂkKS!I[ T']! b;FK]J^4T!-mhi-iwM}%ۤ?f_vgBV: 32*&P+Mq$-]BbI}hi-iwM}%iӧ#ZaD\}N%}H VIZJ}K)tcJ1 ?VXąmjCKoIn+&-Qöwk%H δ#r%}H X%޷ћPIIYer^&d!kۄv$n7!0vS*}KkJ%n;4im: _Lr]q>n+Z҇P Y%ah)-qwWNZw^4pE] YA}B>lԷi!-B -ߒvGoچJIK *EL;.h/חҋ)g:YDw۩={J7qehO 9v6VM>LUw ZmqØu%r-8V9.c(q[qVQC_%<W^D+q,9f톻\Yߪ=jŬlSahUg7Ʊ:nS6O]!,i/7%^@zlSwS_ڷq`dZtܺ70il8 e$))Tȍ|Ze"utdx* };c][aVs_[$%(QZY!z~ϕڣVUNUݸ*A WuǠr8:05:=aFm皺A+%m*-EޖO5IMOEBVʝNQA[Irjw&An;ԵhZ)wUu-}Ԕ&-ޏDi"uqVH dCm)-ڃVʝnU[mTS0ՍR0ah-} euk c=Z-YgN(<xd]B7Ht 9{NKɡURמzIs%cpPWHr0aJo*qߣH *9גuG ]wqL5kؼXJY+=(|)*Xm+9."MXEyl/wimCEeҞ pn_Jzj@RNCwxuBTQמ=mc{wKos߄eҞlnEyXRqh_5Gy[T޷hZA򅋜REGgᰎƚʤEųX*4FOFmr[+}{\$#q( q@ ^okJE_TBu\/d{9Te}9T&v\b\oBc"aЭ5[&U3خZgEzi 6ߞu6T4S-V6/h8V)[ؘe"u3R֔-RI-eb;Ö"&Eud )D9vly*o+!.UԺ72iWP(+`, kMu?Cn*C%oj*ICKon+9,2+(dR)Is'7ԷOY!-xӪن-tܖQ˗2 ezwW8k;L={K\* c{ºn*Z'Ow8P_Hp4::5UMe4z#7ԷOY!1VͺmZI[Q(Kl٭^`J,=TUv@v7-Co!ܸ©5jױq~fd+%UmɳVƊJߞ=$nԵr __;;/j)zfgo9\Wߨ=jfS*+Ƒ:*P+%Um6Zհn*Z9+%VQ:--kCwNK7?&䟐; * %}H ٛH*9ï1펻䘴$Jo^n,'cIX`HAJbߒ>ąYB<;mtW&-kOՓ|b&@`%Jbߒ>3CKoI74iWr(I]!utϽt&J}땤6TMT:jCK^aћPI$%RJb~ VZ"_PV>6G܊A6wP#Id`uHDPI[҇PC8i7IKq]!L\)mx`t;d;Mc%gRuhi[H-tN6Fx#{ k^|׽oKBŽhլC[k:$7屖ݖ̿zҺf;p4з  h Z]sFY&lu.セWqֽI W23ʄo{ڮiaqŴ.>}$`WnDiUd8# kUɳ|LBiBvrN0~?d2'Rn]S}Pgw. nPsiWXub}{]sE2~ԓK2 iA H+X!i-Qb $~w0ݠҍ 2{ $p_eL>+]kB_s.\uҺf'eSEL _0]E kݰX&&`8!<3&7-=Kb ̊ɧɕ2Yt[}V53)e-}u{JwQ]|4$JR'gꂱd0W~X6Rm3:FXoCە2?a.,_T7? äDY?alۧ љj6{ϖE2Y\)bVHFʇ2ҳ!LY\/o˟A0q'Df{ψXl#۞4WQkB_s.\',_(.ofR[/ H2]/wR>LR0?*j>tY}4MW^\vҿ /ٟ\)ŎiB|fln\"[brLڱ #ۓ좂zS@J1o]pҕ_L7? W 2|>MhΌ-=oRL7(j>kJ-7\ړ<Ө׽kˌ-g['|_&oFֹtٳYRlԫEN\:Ms-*Atq՘nj\?!A}&[[8X_r?}5, ("eU ?6w&enLeuvFk_֟2=tkiǸ>_CwrtкM'$t GD"ÄY{R/3%^eI𧓩w;cezN n>L>:9􈡟~4MF CW8Y>Я&|b2%e&W^`cODP:CjH=k:JQHא|zCq7'vκS:U-ZgQ:s7 W^{xؑn:)ivtRMA8B?!2#ZzðG?^hQ5FJ7m >gl!=:[T+j~6Y}?ҵoePi˓AG>#}ܤ"(y"9^.G^K"0˅a"3==avnJ%Qi]}!tΦ]0#3ώc3Ӷv4ʂʷۈR |>C]o_^7'ӹXC):UR5]wϴeSZ)e] ?}eL|q6 R·np?C'ۜ3ežE=4Lr X {ɜYrM|PfN&;(=Opkzz #]'}lJ VOw]Ja|I~Jź+/EdggL (qYRN۵2@qGݬM[C^I@XY@J!ZU|MU׻)7qc|C&ٶkц,] pw,)v—8Oq::z{ܿ91}ƭ1sŪ;4ӧh_ˠ:FKn/ tҽ }hͱ.nOlgkMB]i)WM{ NItn~obکMbgOQNiJ; q:ӗ4?_EmO¦_ W7}[bSIj=5}KcMq2D$P^{+lJ8HO[nJ*I  F}&1X5gW^ Xgmv}ueAd;xJc+zɇSbΪ1ʱґ A|UɅw9v봧Tgvon9;ю[W oGgbOO4pŠk)^C3T|fO}1hQ|zQskC#?4Pk~?r.uº]P6xMj Dg'5.(=f~h9oK+j|^[Axq>IwټV4ߴkeht|UI*o~OǏ3@uK;]ڟRq6_*e`ݟB<9݈γ2XF`|+Moq)qB"=::{ bGh"⡯$uxYo{{SJkrwHNgiiiiw|$|C]OXO뗰 %v>rGb>KOKOKNKNKBv;#.<-<-8-8-Anףn'}$֣~?/$w}4=Nr/UOqۧNNrDNr}(InƟO+OKr{cO_(In>In_~Z~ZvZvZ'ϯ$o%%|BNrDNrG}GIzO.wǼ?Ru}׎߫\{q8}ugԚ6G`Bvm}֫ZC$0j';'W6۾&G58Nvʣ?[z4XOO6ghi0'ؐ1#xܶ%cxBoGc?!ȧSc@|40i6ңvtm,}x4z8 _:vah?6^NCcv: ?~soG4|ih:/nKOÏia<ӀǮ|ZrZ#1+y>.[9Бv 暈E:i>6piivZOdpFGb;.<`}"EO˧=~^;~z e4󙥞|v"*N_OIâRQ!=8Mb7βݙ /R/ +EEģyȫ\dF8%T&ۗe*!O׏goiTGO؏slDIe{, ^+գU%5pzyk#wU%mmCq˿,6{ }gK~pF 嫦=9T[3[ +_9okK"7V)\Ś>yUvRI{6zv_wU j*e {褞o[@֔,RyFl=Eʳ|:ɟgGgGG(1ȷ=/aly2gln/XC3mkؾ"W/ 甔&HSnxϞ-W]}"˯Ϟ޴A:*ztZv ?ЉL3a]N M'w\M9X[v,!=6. pq[xmG4G vgw| UÎ)X"S7 `aweu":a \>>?5}x ]<.{m{,v͑1Mǹ?SlIF=]f6g#l=cls8_v%uZs pJոnư 86c=EMξ[j\'ф\ H<]d90Sz \Iw?Dw병kG-]#ggoCbux#5I~R OXm*}w(7姰h|4jZ7I]|4SgGWO Z:~n^h~R3γpptFoۑ+UNR]-bPlTg#Z"ܿp㣋DoվpCm,壚l4Ѧ~Fή|;xPو}ݬO)h|?\g[G} _-3C.m ~)olOYlC,>\gGo}()/5ZDpKI55? fܥYr¯V>y~;'<&w 3H߅)ETM0S9oO _+l 0zۡ)e¿j?Aל/ta˟7COy|Sş+. t \?vgL_OyT. x}o_3a|3`}Opmo=)$|8?+W!???]og?3?/O·?OE,-\fHR5WnW:>W˸w+Ekr~(Sb6J)(%H9yƣL3o>\9l9q{Z =6qE:yrb,9i8;vu{Tõ'{SWBG+m endstream endobj 229 0 obj <>stream o51Ы1QI+'hԱ}th틕;y'$@6d|ؚBO=![Biⶋ b).b~>)t]a~ڽ6]$R3b 1%chɞ2mߎ=xUߥs^̚*_fSFr9JtͧaX.uf޵Bڵd:]dka}'q1;v$_Z:n7w5ǽ&LEiVwYk-`"pm^'q~[t@~h&k\{dW`@ bq_>Ep^XxM 97ۄBԂB,:1bbMlOlY}_0B%V۩gky/ 8@p"NRz X"Ո N;Ҟi;Rk>umO۱Pl7YcuƩFX-s:"DiXi:!:&xdp,rżdpcSE%qEp aHD0EaCmz5.X4e Jlixɘ鯅IosҨBﳋ$S;>ߐJ>C;q4BE|_c2~ &UNB&<#W{ȠFe>Kы"h  A?&8:>[ߎ}KrKCl=uW;.u yIH.èC#DH!hIHUcrڽFv(vg;,4ȃ݋0 :8D@kr/y٨rΫ,v .zXNvS!۫y3J擑K^a$vfr4 ڮk{4Kx"!MqF̙w./K%mȋ*]J/a. ]m V% \ g4#j"D}pf?/ M~9LR֘6d>.UYTW˴nLL2U>ptU |1{н_ g8&jMd5"EhM^u䀑%#3b&Ķ+Z\ P %V)a-r> mc|L|kHzz=Gz5܊wr} lɡm͂cv^i%UGm $[(Z9ςD%:c[YF.lIb6@)٧"]עr4Ѩ.f/5Z ZfnUKvvhNoF՗H[A$IZچ|QP^C,bN Y6#Ν"a9{{56B 8U(l"Z)ri!HJ)f&ȩ{o+vUw#$u"*!vas/eT@bH ;Sv\3@jH Sԍ⒈ZƓ| -Wӈ]aN+I5&30ƑRBZ r9Ќ'nlY%N*'6a4%KN5?kZ\NWgRLEl#sb4IB !OAiw$RI:W0HֵjxUPDф+>)\; 5y_bL~чӒbRRG`;_rQw})-4%qۺDy,J"U9(BmZݬB+GuS ==!yny,+\\Ѯ Dmx\DQ|jơ\ Xߩזfe8D\IUa+ިy#5ʤ1>*y$K笑Aց` .)`s"AyF=L!DDt-M 8Cê^Ҳmm C[iVXZ0{ETzd Rr6k #Y;[Z+tЗ8D75F{s|SψfRhr;5%Y۝)MDDN& m,QMW.BF{FdFZr%cb-ô ]q40ye["؏E E z/b_&y dZ"6e\6t.et1(QΙ6mRf" I#I8p#Q \_8 q\ +Ƶ4^jge,kL\P5e}WCk)znu]ͲocR0)j%2fvWii/ 8g Ȳ!^I/}`b2x;"}>T]xkI˿\ v3j\'TLU.wԶ8\ -״6q0 KGi(҆7:Q|0+n9h,eQrO U㉠zLjPԘמšGlQBߕ/FWՇzBݠԵᨉƢqQ"*-`C :`:(q%c-bM[{1C ΙlmpyUfDMh'Gf1 &q5j>Fɹظyl]DX|GEe&R5ۉ X֎R"BV+^ڂXWDE Ϭ 'mZrP!gG)jߖF·WzNU2Tvb7 ~'U ]R#8 =GX}tWȭRݡ&ﱎgxSb=鄞;9e|65/WE'aI;@Cl\QKBu4ʹuXs|Ft[s{%D5AQt:+9h %k$Q WЈP`)fN87B^&,~n-鿈-Iܚ -k+[tSI"eL~h'_D:"vcbU9ab9 ?GGV07[Rm ʇ0+a]G{vD'ra!4 @⚆ 3"} l WQGFح fFi_\f'8Z!X&jP STLjKeaҦ}LKORTnh渘d)HKkBVF~yqA`uӱ9}T? +BLe1G{])Ћ /d+Bju2"X.1=qR6KG E=&68݀kЙ$ԩUʶ"@Hwr褩]yn 6D CͶt OA+άƤ{i~TZkc".qA@ACO`C0%vI D?VCPe !uY@-Y;2 ?(t>%!>[-&D*Uv08$w&3#=3(Α/u| HJ|,Z6n"1:Bp$00}b+b  =zDa_0Za&Ҹ@g)t~e>?¨2=~)\}?9e40XHW6{5̜S d>=ˈe-t Q?D]bKnz`D6 ۳Q\ݽҞ$ֈ\DK|lBjw\HVŖ(a f@mԈTFWIXb(灡];V TX߅H\1vȜ.s e-+9,W6Ur *ϔ}o!㭣BnGAǪs4nShcb(SA㣨]&0@[u@musf]$l+}r&j&w$J aI. Øp- 29CSՓlt\ 9gdB60"BQGr F; 8 efK=sԊaXޚȈ m F &m }4 E=pJȀo7'P7hDckc&3]mWΡg U׺AóI C1;<“8#V )#vognxC.zb:U w&pSA*>6bE'[儚IE&pv@ +ű 9vAwaq\cxw@hMͳUƁ]. P 9-MPbaX-8 ۽,'Er{҈S/Lh[ZAòDwzhA6sL2)q.v/anon0;G RJI׈Y?ǜ\aMk05`k?7 D L{|e%.nj}͋AM)~hn.e?'J ΅uvcH(i#>?x_MAO3 |tWb"qr=Ψ[F7Kp6QJԫ]LYo e>tRx#t Dfb _?`1qQoӢ,P/U bg@f@oN3 0˒%1 ishU9rmIe)eNnc!ox\W=E Z'źA8QS`5)C}@C,|5FJ fy+v[{q Eo̜O4Ywk< jG i됾C{Y~7DE"ewD KzyJ_]rFKs0k {bnc.Q4lnL[F?R\--o Tb BAKmMڌT&'bG@ع67Mrb WҩVޝ0O6]%=B׉i.vF9vۍxH:I9FwlGu r_.BL]$gj R, ÅY?}P4[dNc @KG|e8x1=3#/3q 0Ac`B3u-S6d= Q~E5ȇ#8G:m l!b|ZTzQ-6`Fqp=DzcXV̆ E"Q[lW ^y9ߙ]1uAn}-֠eBsR?vaqsߧi:Ku%GqRqdtN_2RrZ  >pKD\>zXdIou3Nx6jAcW7L|Of$xx= " lv#JGҗ$8uQkI.چν'i3z4pbF)KREcpw,pB.gOz7pqCo3X[{YaK~ͲuH7qtBZQaɕ$zn-x LP0ؗ!)0Nc]3Vb:#wstF#Lb%܍XO<$[xstb2^C^tG";hSU|^Oo!r?)M}')+Hnc|w}m;_-*oh/0["[hYc_0|?ng@[#U^}GQ18yrŶ+syBm w"jr@0Os'ŝgV f2=`T[XSK i"5+bHc焍yf{$T ʖ!6XP}1#14u-U3 {ܴQ$3-<:弘z]jJ`?WE(K ^YϯKsvJ9adn=臇 ,= I7]J~}5tљI!ݥڦʨ] NvaI" = -3z;ݔm LU5PϨz| K"pr,QmoJ8y|HJtBdǼ@2bv?R21,!SD.!8>`p_oIzI&ʄ r ܶ)yNι5zK< s(6Wp O-R:͉_xrmQH_ Ȗ=XQ0RfGDdG|ZBhX>8QnY_I'$|XƢWM+{v@+35;-1QU'9?N̶2Lf?4"˽²z$O_vKv׶  1 A) &F9{:70DzoNo +Hi1G!70_3>-Dl`U^>q,SRGQNmߟq4bw̡Hcqj;ŻW|t|o3 EfF |32*ĕoImAMS- u[4ѽnW=fA(e.A[ݏL5 K+Jǻ.nz#Xy,iVf|W߰1cVX'F @7`s|#wR8d+yi;[~w2WT0#%fUsW>sEƛN-/[J59NKR$b 0i4X{Ɖ逓JN7@gÓ! ҙ& \=x0s2~N+eb,Qy?=xqkw/H| >P 31|F;|՗ewP dk,8ciw pmVi[MӰ;{> B9Q[O2h,tIwM\2 ;Y$"zdF6G,^$Y(x߃aVl=゜z%}-댞cxx9G/q~?_/&?e>,W_}[*Ze\YIMR_Xz'W}%سYFХuGg Jq&K"NS弗Tt(IMJ`&L+y^ڒϞǰ 8Kw+6/{UrgQCeXEV8b\(\2XUmmJljd.p43X5DEk6[MhIȁH3z'`+G0۩ 읂^-d[JA1HȤR Ӻ0*Q=/dyn(WM؅w; RzISӣ #J>7%քNJѯnozQ[}k g ;@.?!_D6kaw(&y^t9=E'9h'% N#MJhydjlQC+:%n v_Gs ơ7GPk+r(]w6  D+єE%: D(0RiY?[Ո,6DB~ 9mnaBU Qo12B_dB/"tg1;S3)Je@Q9[.rF׋& lu4hT_'Bj&SYbT6)>U`-u'`UTLBh*FA3lC1 ITǭ2QBBɡ.0eZ*ύLrHK ^i<川VD7^* 3O:]+_ Pzx!g<}vdB#/Suُ ?W=ZFbHCЮ զ"bs4)Tۊg eu@899 Uh9m : KP0/NI,dJWimDRUZHy=nd!kk@\EֻVM2I;fQA}%aN'bef$ lָ͆=oJޫ%pv ċDbSkp7Ud{v6c,f'Tdd?r)n/0vuv$OTpW ^dFkoվ~`;MU.tIb'F$/ZA, 1EDq.ݧV8 tS^! \d/,T̟fSh.q-CT5k\rjZ@ꪪ;tz5* PujhruLNKTp旳4hjpS-A54Uؠ*j>!vն #j\s 6-9FhBZM:I<꾈1,/ #*{@l] pqN4VT<Ih'V%[@Zc 'tͨa[BX1Y4km. 0-QDhIQ\,?JN&gEpQL,I 9oRZ ux:aegKD&pX LSmcV5XFk1f@Iך&*49AL%ee֕h`&>NyϨjgI ɷ'UQ^^ Шl dĩ d\˖VJkj_@h[Vsh)8 dž'%Uvj6zoXWЈ٭'!Jj ɋsk@bn&PZv%A^`V +LWl rQf t_IU.ZEQ1$J;[߯VY8A[QEY_K6X݇̚E<BT()]m^0j0 EG1ۈd&6KL? RHUET7Jq?J5d|kkKW-Y WXNWz Xx7Z+ǵ3M =l0h&3\iRңI%a *S.3jN$nYm'@[fJSRYM1m`[ZWXjRQ;^o e #vQd1CJϞ^&7w}JiF8m`*Gt.fٍ8$5^W0"<}=f^f 5mMvJi @#OhWR1uu3W=3Y1E!&g6%Y1S}jgDJ "X1jUB#=)2/GΛ+fU**OV71,oEԼ+lfAde.J}LBoɁ*>!e+DTKD/t-= 4Fۺя>=%Oo -;'W v(ό nI_\>/6Xνy%v5I6*sG] D.V1N>D(}:QTg]7} $}1 xI(5iI܅<}fUQL<9@%~i?ï&?o??۟_ůϿc}[ tHW|`AZ Hm<ӕ'k#{[PNSaY@e0ѴeCIF9YUX{iԫ Ž:*JAQG3oSWq eOky6-\||n|Kx\F0N(3 X\ ʔ=Vu>ve,c$py`U/N%#P_c`D)jfAL!:]k@!.xuߒ#? 2cЗ3cPo'ߖ%s\/3̬i|?ʌV濰{ $$=C2zۦz*Q/l`Z pP`0Bb3n0-d efZd)4~5x(Tu닇4%5J6Ƅ$s5mVq Cْ̺}AJL\ZfrlCt"UȦYK OTt-BC"O~zŌͶn\ +=""Ȉl>|#*^T7"N-k|r<=ګ#y|Yrk1Żc=v1UfG!yh4Fd:0tnP[].C*SGfu6LY;k ΌAq}&3I*DRfqEt;^HsCȼ!>[ -8[?Ccmdžd3ߐumCmK{`v]i ׳o&;XluJi3QpF>/}@p!jģҋVwf2fԏ[8z`LJtkV+/?Mԉ߯]GLSͭUB_5xd]C=eVn{=qk6R/>uO7ч(nXu;޺V!%ΥthZy^:g<;{9{{dz,ّ}5Ґ4 $iSݍG݌tj}>9m7l|ؓVRm,pu a&RÚIO&aZR",0U ;X(O[xeų4C[`f`-Ie y#8G3 Κ EhU<%A֯A_UN֙HZze3`QhPVKec˵ HW9nY,2)ŬOP*d<^W_mٚGUQMia~鈊P$71Ua/9 n" u&昳lk=x{$p L9?WONȈGLSj]^ܵQ7EbdcJ^T^޷n;|yǞȂO"?L AyU&aQ,]W ~Kf^υsAD-"'u̪id*?olj=ƞf$Y`IXăO?R l Yb .m*JD:JcXeYKfn/i_8DtN(PIJsDIB4, ġE(-l<*$FBAdKV`cҒ!-)o_(Ry/D9V$BikY7eU*ͬj lNƄț|[J*Dhi @+]VIސA ڴӤ"ׁGm:BK1XT T"3&Xm^CZp\6bM,<PJΠ#bG6W^ ݲ<@eqE6J$^ sq(O_n^^0qC vF1l.QQ isn:]zo~ 'Ks"[RYm\$8T9JMX]GC!z<]ֻK0,YfjL+fV)P]3U`V3k841vn "5* ڲPc| 5#Khp1a #؞#Hie-ini7@fᶨLf𲥬^XVЫ2[XVj@/72dOl+!~`jBmd/ }W#\&^=N`ĸrlD[ɍ5!񔈝0v۲V{dý kM ob"/9!z/cL8Oؒ+zY-ZBH$*LS/l %ªe%š뱕˜؅,όU" 6$KyX6D`)R۵Ŵ+1 B j#˵ٟiU@91ԮAkL"݊S44su~M'CwdN\imk9 ﻶ̛U^ǎw:٫jt\@nBM u .pYċUޭ1VBēP:qJ1 Iga~y#xziGZݦ ,=f(D쑬E u&DձdQ63mT|SLw|'`Lx=_Ϥ2M3{)vi*Dwh[s1+QBD_a d.# DlSVvБJz)!Bb2ٓP :j]KO=* nM@jdNX*y+.}x&PlB8U>ld~iNv~9e:UG%O-F &НzP1,D}վx)yX.Jvаpɫ[&ˆ:,$h%3gKoǺf&1ho_cͬnIm fu3N/4!tNC"Hn&۴l/x% `'n%`4-V+RG4њ^cچ54ψm1ʸC%Oxfm tAuΓW8`TBonaaaG1V [*2;Z=!w4ku$t#+\"*ޙ^[J ڶ`p9}!OLxmOMl扥U]^תװ, +K^[F`/Kcm- ZF:Grl,ָ.lF;akdeoH+_KP5rx]Β61gw{􊟸5\d%+|J}w>@V6 KUKRki,[>hAVnIcx%/enaYJVcKYxm]('˸J" ila5?EH%Yi?;5Wtg{VNSᝯ\mrV1h I-`**rdλ:V^A3~Wa Lq"#{q,u0YOkj`[W讓unaϠc[ ``47XVyKGF L'}Ri[VN> &`FWӰRa@G61 B΀6B%&N#C9&rX5De(s7- mnt;;-իm s`ӣbwC!(I!qfڭtJ/-׃֪-m\7o 0$V+x/{. MLS.af/p!:b1_oI Z #"! vVu9nD~ q& Iyw /ڜv㱖P̋[Rck& \$8GyHuO$ ag%)^IfR)A2z,맥ޜ6OP.UIBlt>/zɔ67g(i.^%Z5#‰@S1vd6þ@$a|p '[ype{6+)Zj bk83ӛӝdB9gQN )SU3=CQL{PPeh-DֳVێT͓,$]tܶytL,vFhꗽ5Ĭ%C-!6/Ir'R K~ ڵ(Md2N gZ6sH q<鋯[g;" Λr"7Tf/jGܼD'Dh%o]|$S72s:ӣBCN=.5T-S#谵)bZN؇%҃7{ݺ2VT*9dDszYf U94}1Djm90K e3xf3{e+EmN<(δliBro#O7 `[&\ `Q:t z_iu;Rf4 ]HP$iCBiQvK(VY[*HyMFE5M\&s#x igܷI l |ugbUӚm6JaډWtw,+1KR~.Q]~G#\M<5Ԧ5DMhK˛̃p8x1]hV/NaD:qgOlLE<'X@wN v#[K %rB"Io;[օdJj\w'颦d)]'Zׄ^MFK2_l}O}&:\soԁޙٛ'/2&*+Qxƚ/-!"FW-no_n{#xN(N Vz7}34J]B\'GB*L vj"/iK&jcwFr4С u;Kk?:4w3y"-GMۑY^[+:Q-Uɜ-o+0WJ*D {q X`-OEuMezsgF`!ڵ)yO6A܈ } arzC*{qnZb8bq(lsxyإp״u{ѣ:3C?6LQ(6?;8 onށ "|;e+ɂ2Fdmó9HNR sFGb|tHDֱ8ؗ4C8j"(f݀b<ۚJ…鷐oeٓ% fRI)$TO0grX Y)w,6v2ᆰ f\YNpDMu5"R:dmhRgfz 3J$± AՃʰo%Œ"AwaW}:yb8#.պ d)v;BR0u[>Rxgo ŀb' [W/ nۈLm ϻMыxxkzqE~uk ْ=I[=L@8Djo8Hv=tUȴ_wϏ3];*Aا0z\'W>iq@ǽqqZs.>~R8©/3QN$qQ[t`[̍+9ܩեzp>SZY sfv֨Ii[{n"؜ns#L(Ү=,F,dO_ IܙWO8 4食#@9#yoR\OR~%zL^QA} A,6XEo8&QTg*D^ͱmxضhcZ"Lq/*xFZ(LʫC2ΐ{B`i|==kxy>NHY5RS3H1Lz>K낑>@Y4/㛭nI$jT`-ⒿkvX.5E<͒ЂF3X|j1R+c2N_fS:@p-ӈhcT=If91ϝD#3 Y5^:ʧ9]=kZ-zlAߧƾdR雱BQ%c@\jA*u#x.u(3xaF0`)! Lw.,F#7,%=.s H,vDQ)p)b)飮F\UW ߰1:@. X7FJ{]; y T\#iE4QAтtK:,R"[ ΁/ʈHF!{Gq|)1놃&k=+ݭkaT$xw++O#z8vp0 "RYVYIKD[ *ٔ4W+ jrJ;,T(W[(zdSbbt"6.A^E2T0{d"TvݫHh=kKJae/Xhi2Qq=Ũ;p~Tud6X K!׷GGzN, -x:#χEqkM-$kL.mrq1٣cg0DT E *j"['L #XI^M˹6륓:n)#Y=my*MH=afF?sRɥ )q2xS;P@2㦢 EN rr7f"ڤ˄/f)_jKՋߪg2Юc&=Ğ9i`=eGKH8=,Ŋ2+ξf+D~ū$Cn'Gd\9!W-*:#没U^ >'0RvP. )>4ZOݫL" m-`5R_F3ɴRf%$t{ K+xWd?Bɸ۶T<)@hnpH\k{x15I˺\/໴otZ$M +DV¦r6VVa ED yB#yvdۂ2<ٓw'f턹ɷΜ=c~%Rˬ BGBJ9'+4%z6T<}2)YyoZٕY"?އ'*fzYErMG#'r+=vHmx薸:QmE76Mu}U=Vc)0ӁP5#rwA1AV7sEB͋^]Q#߉DdB[J:!{4H錑@o+Tt4K1D%B5  gT56w-c^VsgY(Ak>D P#zG'H{Ƕ,Y$f yw {Jde4x1ZC:S64Τcݥ64 [OH6iR\vfK&w4N$h]iwUBf(N[rDp[_0e58c֮jfr2o7es QdڙdOy=I.O 3Cxӈ{v{Ξ]nBOB~stR0wzᄎ^J=)=ap%* т1ٓGo q4Y_f }6[6 |kbyzs}{.2WFpdHjuޮgː3(LQ@ZD!r/r:,+gr]%@:B`T=Nehq9*XZ& 0p'1CZm^8X b pU 0:I*<ۂ%%"D6rA.+Dtwz< ʨ-ېa a;(vBfHoBeBJgVN!A\z S(-YwC|o K"q#u8 ~;pjMZ"i c}x 㖧7] ߱OBW[rnIp,ci&%v'8Yƻ$BwM/V!2Z^;v]{l,dKnػ[Ț]Nj{Tv ݳPnz$C* ԕd0>8!˚uSPp9u]HͱϽvl^4ѽiWB}c>LZ;}ˠ%3 JT|p@sʆ+M-҈Cְ먲֚^WQ–XF輍(2/"bZzw@ _Bu+[}K)Ԝ öiлŠEBXKK ;ֈwGWbq6dDÚA+V[vgY}e9 :54JI'0q"-}=UxdWty^UCvlնk`Sk1n'N?ʹ䓆TY  #ozN;v uDWdE1`CrpȌm`` [zu!fu&\QL| "vJ+nfq(|;*m»T8:/(Oylp ElUbQ8,>o-J.\71Ӷd m3ywXƼ@MݞB:LF 1{۞a&{1K~㈂G/ޖ&Qѻ9-IėZWܨ+6+Ee"roqyOɍ^X?>6F~uS*Q}[uIrݻ`ClA7y [:ϪulX͸<b::]LmDNN$~/;bҩH`;;Yk=6p|ߝ@5"\bOwCW \bm2Yv4}7Lv0#3Mml"OD2D##s\rBcϯƉHxbd1?N6rjBf ! P_xI$ ;j,s[p oH/\חz f"B}0T#}!"xͪ2İȽ),@Qm҂,ڊqLDV\  q"%6koŷ^騽MѬ#Ҋ 3@؂˓sB_qk0P/ݫ_V՗8@T *Y ?ы牏ԗnσp*I%h2wL@7+z\;LoAN\,abkjoO9_YFԸG:$S)W*8 `yfT%|+ar;#aFB&ʧblsW"-| V_9Q"6+KNIGȳ;Hh:q8œ&2FTtȀ([^)eU(;:+xQ_ AX64|cO*VL4׈UNƜ跶;ΧxɕK J'nw')=' l\wP؋O1:.zCGC}h8@5>TR!]LaUu7prx}0|x&Y| # _$G>]:w\A*[p|^'YDLBN=NxyJ.tbT*L QKH*A:\pPv\8-Ľ17hSfBm[eĠاkA` .2Df.C!;+Otd3㊄=Zp5b?I2@F7>ciI:tAuz^mfĎh~p)CoU;j:W9'{eOXY! 8v?.yYhvQMbאַtu1ԯoS{.`*aD'O"t-DJ! ނ_oxaRw7a$#ǟ݆6-K ZfZq,_X.Iix74QgM:P YLV4kqlu~Dz(1S-&1_IӨ' CU'13>2S& aRR}@vGE@DisI#xr򎆁 8Q.4PBy9+׺ d=z;-6q#1y[6{Q{n0 FmEOw1k 7z 8@:-* a,$FTH}xpn"SZ!Ai#îF9Ն]Wj%AG UD*NX`iڢdG$@K8\*k.0@*?;CטOx~KspɶuV)-bkO1n޸y˛hEoXN[Tͩ#:rJ*98:YtjL9A)IA՜ b``Ŏ_ Bq9lIڨ*vcmZAX PW։[5o &hlmr^8< dN ;$JX#E~hZ9*1o V@0P#"UEWۂJ*F ;BatUXB,)\Jfbi3k8>56 O\P;ƋFe4a0[{B+=Vj-5^s5n$6P0)9,]$wŧ f^hjWdUPL`.*=p2?sȽV{r`cQ)"l;fAJ(9(ͨw`o $\L\uԳ 3N;Jf)A§Fw)VB}Y=j[O@٤+N9dП[T#UiNzcXioPi5ӈ-%~ɸ>t@ `߶'zX~W(eR}rv+x;Ő_ԻT66P;82~ 7OA\PK:NFN)<']Ŗ쓖vKh#?W";"Z0\jtv49:p+<LM.?kiH #vǛH oѿ::+jQbxEk]W~;DȣLdlEqg| ^D,CXbk7T#۹n|mIiL*\}?`ޤ9 &Tzt( 0=:=Rϱ=֏6f}S */``$8 x7Ԇv!INRO-?Mhb{Pd& Fs.^ -me8rRP^9pl?_hz} 9x7U'A&]!N\.[ eW{9rLy[tS|nX؇GKIC*L ezVtdzd /sQնVTb;XX(] ֨#p6hZZn.6/ 켌uK 7e&󲟇~S4W)1?ZlOzmVΰIIqo碒]unboag@B+nPzD:kZ&{=}2R;]o6#.ɓB]º.b>V" flrM֐A"V2}pe ݅K 8YIK*A}ӍteS=[u܇]ٕW[^#=t B1Oۗ\=^/{P_ĒRHS/Rb`]&E%R 7ዬ1g dpd1c;O3g|tUso0{)~Z.d.zO.3dfԒ\ U UQ"1CO\`ŋ4V/Rk|PI$Oh.N)b/ـB%V!.l^6^EirP aa=XC76.2EZr{ Z= U%MnMJpOVWgLAtœ"W,9Lr"R(vDR:fJJJ&'*"ILwiƭ* Vl<LaN몳 tx9v5VXܪ`7y ]V S&́2x7k[qiA;߽v|6,2bX6C$Qn}8c*ʞņCfނԸqURǍVB} UR;XA=-Dܿ3W,,ݕwLeM ް yY9k}TOP?rJ֏w2 pc:):!0C|.T3JIm> "/s+y h hqh0Ȁrp0#撸{7g~)sjK:U{47Y_#ܬ/%>,Qˮ<" ׿+PacF*|/P0IGnFS p\0w'>@\7|[a" :`G΍`d}I&z93xڝ^=Hcc8o+FĖIDA2 FO{{BBN9럕\# g_]O kCL-\ ΖeL/ b;̅{1=,-i"Y/5)k2 5jW:Ox8/+ trU\t+ր )O14\Ŕ2 z0H!= k\LH.AOB{z N&_^ -rjm9ˇ'!4 kOJ$}3x013+Yh "p;۔-KF3"/f5L*F+LDlq1RbgQ<LǗ?x42!G_Ex+ߖ.>ݱ] g[mIƜ2LvuɞC:2fmc+oU9!] -R)!,zٍ{p}x߃%m &[YJ!NzU,?ҟBBKKT !s`7A W HOB$K8FʙidDĞBȊG1Qpۢ7<V(vTEݔ by eB&inxP^KI#t>ZEq#'擖ͩy9'/K2°U6bkS/zhe"s6 om ،X;y`JԾzS de:5p FG҄lG/Į+b7 Is&4t3bݨAq2DQa`ӝq3I;>M>=&y0V³H wC9|mąx"JÉlDe25N{qM=<1U&Y;!=Y{#2mA.6K@} T:p Ik?,"&V!Q8P;ۊxBƈU <ª3.F ;21xW$y!P$ stq$j\K}y?<6a41}Nc:to wS6iv¡Q;3c0#ov˕9}وë[*qxKCi\u" ;wZv\#M:MpA}о wS!{۠Gp׷*2"dY?uJ:z 24Y;WnTۼ4̏&Umi[qcF0 168gc'8H`Wxxk ?kS /v;6`4gJGK#ie2.;'wA-MߢxŎF*Fe݈dq)o)eﵙCm1f DzN P{.[O|gN'쾘9N^ݝ{굆S3 ǰBt=yeKتS|mkM" Z /ЗU38u7I;~f2dpx 0Q2|uw-\ZV>ȈFXpdP Cvr;lxp1S7teּg$?{E{${YG"_O ?^@&^k-NGX,c8 ~^j$j/Y"zF@Q9`-L;HT4M99"?J:[DHԾ(+h*D eKGIa_m2U uC̭?`$SMHhp[ȳL\BDž 4ٶ7' 5M;QPdZیp$J!mDR(N͜_Y@vCUѺ (G1Û@Sw_8{?u!F^D 8n֝ic鎊>4O~-o%}xl ȪFDln"I Ccmh>`4HEqLZp䖧:ޢ/o>Co,[#{|40Q闗[ç9E[%3ebkuhFi &?v๟y3RC'C QDPnz5$ׯ/.M/n*E>OD6/wV9?SO顗.?~5jNUQg;?oyJ‰j`tKJߋ ʺa}'1PgB$$y(arc@exʱQO'%BIFIR s9c!/{`[[^yo&k;RCtDj,5Sn&NM߿i=w'e( vxvTXDiID/SHPs.Pot"q\V{m0oRGks$EVCyM 0wrRPUmօTf]HX#8/@=TY]o55cH&C3QCv(|,anXT]I\#%'3Ͻ'l)hbFl`u ]G'*׾$ f7; r"2ky첡S!Ub1:ƿ ܅t>LGρ>M-fV}(޹x 0S%sĢfwDV^d7?@>Jx*2 )Np8x(˩qᾙjn2$Q#&j:y JbX=:v]YP!U^JCفi!`1"VHPuWH yBC]ӋnIN+Hp,<8y5'#iz8BZ VNph3bWVl#G ~/*Mt r.Ұ]V.Y4.qQCj"YbT 2+RޠDNxy1DZ# 'J()0n.t'JNAӡsPx\."&)p\dhz.v fhu8a w-~uPz=2?RlzQ c (nHX@;׾; j -'v=9W0}S$/x I;Fۀ+j[ʳ9:5Xhb 3p-Nxt9PV;Tw/⸥9߾̥Ui;(z[kfL;rӜp>XO[7ĸlȖvWN&jum-yݘ.VMwoo*>}Z;y=Gk;|VlbBD>hg6 BvHFK]ԛ1wй]E W߈fAJݩbzX ۣ6̍󗠲1Ej!8\c]Ln*-#Ϩ( ,ʠZEwOB%#xOeJ IۉF3D~6Њ˃a]=xR-h̘'* <-I8kT|'a0#NZ z[`sP>S,~ɼ= $ׂڡ7 ycOux0a E&7E|J>$u`fE%ؽ:-D 7r&_5kHoRM) Y/d,^Uw ̑bDV_T`R>rN´VU@Vx͝ OPbIiV .eJyVl^~ҷwdφlP  ?)S f lLڶ2޾yxFBI/?)j b 2q3B0 e߽/#a0#~)Ԧ—xDyb@_-O&߿o츨-m6( H ok|uv їN(\:N\|6_}y wv*^Qsڛ߿n>~AbP[ e(rd(؂

5,;v/ N%9!QP vfCRM" L}"xJlW_ݝnOrW`;ɓes/sKM<#uҗĞ,cc7=ݏxQc[^QͫR4|䬻WcEZ(ZI"Rm</! YG{߯8 LgM<|;1QWߥ{ls@|O]mu8DZ,9#QO8=bdt=U !n4>-wEL{5_DyGɫi>sODa7B_sЌa!o/l :8b˴;f:2tJ*8I<.{c: /rV7l_=siSrǥEVE"CeJtߔhk޴rܛPRﰷ͹^ 9A/FgNՎ:}mnIVqaʊc)lX} Mga% jڷO?nh}l5Mp7qo_'߄fμђɍYX7~vz$>spRh@b0/MQX *q7yb]JU2Ji@bG[geAC["*dyF+$68_ށhVO>>`?D0cP=Տ`s"3W:vSbImGpF+Wq1c[=+v/r&!o۽wJ ,[|U~T)!Rn"P#ς@DIj#)\kqg2/yIOq|{6څn"A .F>ֵ̈́7b)܋4Be۫ x0wxK>$]!@OBoOkO2,Kw=koETJn4V?5}(+bߐopJBr_?K,JAITBO/xZC ] Q4kN`~H:;Wڝ+1J+(锚-( ~#JrBaZ: v!yB笥~bŝsX+D{X vd܅d^P6q:Gq:.| xlXZX; xPG+v8NćC:"r(vK:cAFp:^zCiTiQ]Nᒿ`F}דn_!<3't7Us uV4be||{0-F)870!g8X a˔]mzho|w=sciDg|v]8YZʍ6\) l|™;"y$8"qo? _=U0bg=^.} TۼHZ)V? ͨBp%n1&.\C'!yړ+A\!_\ apJk'oQzEIN!!8/2pkvWyUqP\K\wC;IJi^[P=y ';򛛹˔kQհ$g>rpd{*qɱ"0ʮ bcKkuv-$FQ;Pƙa(օn~ߩvu/ݔ+z|w2mXg/9k+:\psU!g8 k˄HԹLiYU0fY ^ke|H`^P K6cKTj{8xXR~l Woiꔃ'нBO >ZCNZ&]>$sةP})cYQTT0~W5[sT.zhVGif.~nl-~})UJI`S R^ܸ+u] ~ |'Fac=xBPyktX5`@Jg+CA+ jfP@[8FYN>0P><üu>KDֿjv/>6vwr?$k?) 4P@I )>p@ts-mS|^i`47قǾN>ы;[\Uk"hXNs|X`{C*T(YM-Ls8%Un|.l ,[qa<҅:RE*ǖx271S;d19[/Oүk)X.__HAzЏkO>n}-f;k=t,F ԅ!Kj?^&L_m-G5Mb\yY{j;Be4_׫UP/︚^G!S _?Po ,ww#1Zݯ7j1ݣF1x}袊=pp< /܇}vIpfTbtxzF `.{ݡASk/,O%yaW$U;m4oxxxN"Vj]ѝ vNA hURI'V azHUۖf1n~ǘSMO|~1ޔ{,yaDXRQn2ovtӈ~0װ*z`8\y"q(8d:}]zH=*3M<҇i@-S\,?cM&ds/@ᴖ.fP(Uο~o;d*xuwaո 7[ n\ja=6A(L>)ti? f1zrJDWrC^W&lxMڠɢt?<.Ycn_!{2yA"+.`eqv|h(9,bx[>yN )-"A>f}}hJC[DU-p 7t/'A4ԇ̃3г|&]ܢȼJ>CWcI͈ k%"x9H*Lc tC4V ?E.n3f4Ju@0xaῤ.ruKDk"~`GM0tcTYqL%GvDKK.2Ck~,R2 LZ+ Q/Ȅ:^${vtT#T/(1#t̷ٰs*ܯpqsy4g<0w'(?ܰ _mjйIv.X4JL3QHUrsVh4b{ŊccЩ\WJYຍ)"''8s-}q~/m&&N* JMXpoɿp̞fLVgj _ʵtΡX;ACcjFxL@dM_Qwa`ז©`7)E0lS XAUAW-8sl¬۳đ~8:"'T;`q}U 8;dܸ_B*]̬%Q7\Y'# p.CyTV#W2}oTB*7Ox 7Hh]R|L |x@(Qa>[|.+`N6@Ӊ1PDR&ٴ"*z sPhnA:љ kBD5{Nh{ƙهBJ/"WЯ肪Ab1GVmڡg2T"r|&2 Pi cSc.A@o2gGϪTx(a>d'p3[N$9E ,nml"ȟiX?I\5 nmkDhƥ !G4Jna$e3@\pvN N]fJ# DV%1ڪ{Wq"|Z`>J^nX;C}c) ,k6PB~ FRYgO}aҕI>+1VD>qS#)0fǭ^Cf/B X->1Ad\J T Ard R)7j}#N>߬uOBKV1Sc3%6PEohV)[y'3b!T7ǵK:1#J!+2#pdzMX]k؅žc.ao:Q޼"d`?{_@RiRջV?Fhwdul/ɶWI 1/SCMTQc۬JmTz'իk-C=; ?3j8#4–17^!$=gP!Hz d_C"XP.37Xl)A0KtH+I]qODS@~m! )#l/,I& +_|1Z }!{hu;(Tg;g]F;mCgU2(ʧGmUZ\/T* R'KțRI7r]1"P$ /r myi{2Z=!tU ڌ5*9BV tփ "l!wkQބ c>Pn7LtT*Q 7ܱG;s}Ư̎&},3]3Ll}-[P͝sIا@Eb ;j)Wy=FnT@2蝰'\ w[?8' pQh5>N# 0^pK( 5booMlCtq2'rI YY b+^wy]A-`lvX8i5^ ^:u ˪-Ql0E6g1R Yk:/rYi*=`"6@y$=ŇxK:$~tꜴ>#2OܤV==wEdre|-uB87:ˁ^ah=;<Υh!|[yqP2FŰ> e-7H{=1/*ENҸ>xg*q~3J #J|z +M)/T9Nc30c\ bwpAWi%ѵ͞n ǿ2$[GBІ  t w^IpbP.t׾ۖ[+pCx$ίlaİT5:6.Y\ TFH?AyȆ#~K}Kk1oYW9nTv VB\Ď ":c 8Âkb&t"|}S2X E,. 5ZTՀ=\(D6 3f㵱8ø)Dl5ŘjtWT&*5quBiɉ@,j,ast1#\p9FP@G%G_9=_I^D}7i#S.kF u %%dQ~=5LUsNC R*‹]l m!Y 21Irud6wh?!P'Vv`>?`G|@Q4rQZO/#f^jD5WĸՈЁ^~|1FѠ ڇ#5XvDO4q¿B7KyU[.l8E|6}MeH%ɈR^<%BD10~)<`Ii i WCiP4Bd`L^qFq(zfƾI]r^9pbv-zxZ F >l#Wc!m(5X=c{@Qcͬkע׎?n͇t2,dƶP| sov/$([Ǭ0d$+J9E{]qjj?o!\AI`<e](@cw5bbԩحIbI]ť6z􋡏qMݢ^)_. ײSߴq/1a {ŖW7D5 Z:о 5W۟ǿ?on?۳_?ƿ]6_T_aǟO_OzfSIB+Y$e,';NO|gO&'p XE5%f=`I>B9(ǐnDpwIڒuv_|qHi:Z$mJ܍612N^'df8fWVBV1ļh$R*]Ltdub u/82oA vKTI)dᰟHJ\/}Q0TJG^1H8`>d](z}l$4 gKK7 H+" ^OFKޜ\Y0K BV\VCEɠ6P s 'Ι$ט!`+r аJ-%UaBxq0/Q/mrqGg4re#=9#&ўIZ7HAVP,J2&N%ELP/ÌrzAolZ#5E5͚RBhASMk$k? v- <, ڰ'hI 1D1Hc[X2o`"|X5AΌq9B!7Eng<Ī~y˲' I%oM3_ٴ`'pI )VaI 6/ lKBO(0^#X?V]W@VV(t,xɈGuلV(Pwҹ 9jNLʹ nub-;Y]tq2NecDmOV {L^0zTL&:,c8I~T F]s z6'I11 X|}뱊ao^C'A#ϱtk!0pC'*jbXA/`ą\D$Ⱦ%Փ\@Ӎˇ]p~ÜLTڊ 7q1< V;KOBNDha!^(MA sj[-`EWoDj$-Tŭ.XpF6xj߶QMZ JQ@^d<*5 aއHb【Py(Xj'RS+bYIdD.Zwॸ/>vT| >Brr{B{I- m 4&c# d4r Ua_vՉJ_1c%I{p6@/@:< OQdZAn;ZM%l \/<7N(~O@g\;pʨMn>Qx=DP݌U'ߦ+ A@(nMA!Ru9j*bc1y=/B &`AebSz@H>_Es4X etf8&sT|7Ztt֬5edX ?.}3ԇ` fl/jPҀt`zDSK[B{aIlC]؊ Do{\-AȘ MIUš͍\C7Iۋ}zW隃(zrde˃.Ղgi>H?I y%TFRLP/_@JD/L1.=aS>H.q&!Gu╅ J!ga㹬8 xPYMo3u)"R1A8ua$zɝ+UQ  ODQ$M}Od XP'.E2@ + :Ϥvsd}K@r_xP)$iQd5O߰.!".}@t.V4%( }f >OqR2mbl1Xmbfd=,q!ݐJk6g9gb6a%c\w%j@ híъ*Ħ)7Lyܰ{1a$=-򯊛Ca*XHb?Q0o$ yF}kI+ƹ"tQrBwy$~t\:Ë XVЁ\JztdCqN@峴l][,NSB)u72Y=lBEru;Pf1}0_XWVbv$HӺNE˥"Iŋ"Dز)t |e~F~糧@ Ha U@jX^CUW' $ũ+.NSx-BBǚZpؚ޸qpϺ ޒѠrT- 6ӊw_U:Pssu]LQr^SBx_Zƞ7u䇚:u}g^j-5im`Zh?hbi)y{Mu׍RZJ 3; } XJ#9oQ(ܝ|_K: %H5qFwҏ;Wqnl%a ;} R4R?Mc7 Q3.H6zdAyVNK/ͥyǴ y;EmqC #0/Av^j2_GXa'uWC/Y@.~4~#gp H)#bUIRJ:Ĵ9F>OxZmMp\C˂䒇G%x~\&F79qP pӁ'Cna1f٤\{:a"fbPf'FA$Nۇeԟ'zcp*o䌴cсʫ}^xc283SU55.oxC72[}r/!Eª=prX˓\:=Mݳتt{H*//&d }`rn@,WG[{뾛2ˮ+l<"UO1Rv4pX~=prkN.w#~4~&aNlW;U2@WU]4HSR&o׉B,dZx'HDy9׉Q!͉hD;;HD]V9>x2JkhTzX #]$oZޛ`k< k*ZHVttJ;';* ju3yQO?r^rK>H~h(ZhC,\/W}#W粚6*JMrBRon\XNQM,g:6b( &HۙAhU5@Wf#gk19W 6'fL0ezdľH<QY\ɫQ73}-ib:Plr湽`_6_-l*o*۬l7I.8t0Mk%syM'4s| |& p-Jll !i#t6뎭T<~z  oL|&~/V ^ƽAg [ e}9MMzriGA,bik >1KN剖9)5IP 3-Ei-TQRn.`ʝ#4IsBoavGA aB~EM-iBe:Bm6716塸6U|PHPC[җH5R`6+RB$A'`;֜pnjK>g.9h ' Ƹ mW Ҵ.A ŪKҤ' IN*=|/ZYʁ{eU, ͚ҥE@X.!:l]jo$^m W j8Zĸd~Pc#^RviB;-=}<έ "~Z .v8ċU\b'*YF- ΎrD3|$j2SĦdk!kljca |Vq}3,%*5q_nR%6hOHGÈ]ʌшnE`uoȞ/e{=# OwV^i!3H<s&d Hg-o""i_D_C{;aH#-6\~D 8ei+}~ MPв-3m[=dRgv-uΰw 8%@hr2Qi16<)*Hd>8Y?؇6Em`0-uBdTyEVħD2Lbl9-4-XkX$@@J&!!cAxJͿ'+ɜ);Bߴß BpYZɤ9L,DHSJ ]=t]x#]M%~ɺ!u;!B )7ƽȊ}2&jWܬU&0'I|?s?x0<-#}E0x=[jZ֝EPV^F&&^Kb4V)--@GNUg֖cx|u|saNL*IJZ QIl`4> ï& !>1壘K1y.cRRN9\H2ZW՘JU`~h]EꑋqZXy @qqxte|igb,X`Il`բt -<j"ڂ։P)8L3Ǿڱ:K{+t()*uUWg.&ܾe}iħ;v-\Ǎ˫)?x (ղXkFBRj %zQQbjg[V%Gv`@HOu#goF-v@[y"5BNb @ }WhYfDʧcYx2Ԁ9iC)n5W$B%$Hl:±bKЄԝ*}C Y.TS,KH6-#fbҍBG.W_КW2)Vpe0BN7zh a j([ށ&*\u!A@ O;[w]GB>O{:.B7bRHF-u-5m7l*xJf-q4cݒ{ܼf,'{?6cqSr(> 8>H͋d,(79(t:7IJBՅ65[pr.gCHX, I[.l1Rغ?=լt:[xfQ6rQA hih{0n)@?u*`wM\b± F)ı|,Jr2FWG/&+^7ҭ3J ]ƛ䙬GDZ^VVvK_L<E^-c#6c EFWsjAԲm ]*jz-2d|_3/ooIBBx1 y٘oBB&!$/aCLb`csU붺U]ۖ=P˨ Hc%"QYNJt> Q @vcM!xBu-¦xBkbѥVf{I8u\r&Ŵ!/=}5H lydZ`QA 7cW$q߿2%l,:1d-.m"F0:NI6.`"뵢l $PX2:-za^gkBcrЁiW:4TKZ8vL̲&%Ɏ|y^.f*Z X564&)S#" BZ0q qBg# C^%!A3 3669n9gd*;aع 1jח$βr^a>i`ԓ۬uE+)%=6Ai).(g864 Qu5$C롪&\ă ߄g\܉p Jx E[LAt+dJ~҇( ,_A=%KӍQRR))S] #I6RBc3 RAJlagN ;FcS؃Q'x8E -buN7K{iX28E`؜J2̸p %<[pN< B+ÈL.o{0R CAk0 mQO!dp 9y)^)rRǑqJM: W(tHĴ,EYٲ%GxR;/BaHt^&Mb1;JrbR_ʳ4?6ݼf2PVa ٕ=f(iCk^FopεC I=:RW' 0樚J$ l m& uBH΀ڻSՄ٣iFV:CND0t 6DnQG8刯gc6wu$yߩ[OYe7؃um6e (]ف BȜ3]F]RocM-K#ıX/"|R9H{"G5 %~"rtNmṊ\&hvƜiR%&[.eydVdBR9Br=2Y"N@%tҙD&DrI82Efa< h7JHƁb lR2¾T+!)(y@ܷYx]BPI8"'Ƃi+`lۄ}bAUZgvDq>zR[#.K@6 u*m+yؼ_:3H@#a\ePL3A976!W*,m !Φ8ƨ1pLI&qa px cJjD[U)2A'W GM2倓4:\i j%Ú\eIR%q݁o#Feҥtt@)ҘӮ؆,ZJnsi|g]+}הZ~;L# Y |NN8hZ"Q c"QߘƗ̬%XpER30cf)):,)d1=U#$ `.9UPfgFS1Qh9hʌmn$[KNY9vqڒ03e"^XMg 'Y,t<m,7l}=oZ9W rGā ;?1g ϴ pt ǜu9>;4,X9I*b-Xqjڀm0 '.wiaWgc}MX^+-,4oҫ8Q+)+^٤uva&^vٶdsɇ̌}aUH-r1CK<\@Ҟg3jpGg3ydEY(ّiz՟qHo$%'֡y)ߪv0@INũ i4k veӤ e3+Iz zr@6q+1 WDӺZ@!x#u2<{FYspdG/nFZoSLzi,Lb'hӂ|qL[ȩw&<I$ɞjE Z6w`xSqS?}GE@S.ObzG5+|e(/IȬj {Xjy>#[g:9=Լ A3Q6r<7hYAb #9>&Ű]ǂUBZ~,[JN V[~T 4 -YC)p*zAJeTx4=A5zY q66:j Գ^Y;S_L1^"ܺbjc8C:Mys+zhgüh-ȡh1ԎN将;s6ifO&ɤ1w*KT, ڳI`' pR4)Z|4NLT\Nht̅ ȅ]2l{v%F׳h2c'{K u2-gmEH 2fTγ$j2BX){(d.+ExL̩ƾ*-3 %*HPk߫SR(2j6]t }W+]omFa U-0܉DFx-gD(4M&(lP6֎N9.BF>-|496nPG{؆G'D-C.)=`X{ئYi@Q~Ĩ:.s]˹s]/'0eXTijiRmR+w+?e;7&e JH! ͜Ɉ6ǏkCT=!8*'%y mҔ׾M*Iw 8'BU9"(OY= b9~y<ŶU37\* O>sy{ sr,g1XVgWNsT{d[uVڝj:8;p{w]M_Nzg׷(nxhf TzN,1~FndXLiC(ҒYLQ.A3(*).hoU  3> (ƫ)'V)m))u\b&Q`w*["!%.. #dF-⬒|DΠz--aFDeE:Ji/O..qgIKA+؊ %)Њت Y7 J&5#T Y:a+CϺ'En'vj \8;M87UゎZ{i&+9?Lȗzu*,Xv ۳KX!r:n>e땸zR8j+фΗ=r&R@([ Ӹ9TFhYG0Zn_M"-V2NXJYn1B"OYI3bRS-HIc%%"c͔ GR8'XjQ)K1N+ Y0 m %8Ցs1|%' ]mmc6k2Ѡ`=BԴسclg=An8'Uqsm@:uQЪ)Z7,O:'Cyӆri"udBJItgϞx_!m\w :hJEjb +)`6yh"J@Y_J#Y7v<Ä3u;G^8 govmSy7Ԟv> ymݹ}ΏWj[uRJkf˰m3{=?[:+ʩ} KN{vŲ-iίJS[lJ a xl[|B>7!`RGҽOKONw\}n&w𖙃'3j)2xkмѸ=}ٕCPw €vey-=thjveu|3yQɽjlybKWض-)go.nZjkyl\S#ϳpdvyOE>3vV+kPD23=4"45l>ń"q[wdQ+cٰcեKœihgjw&q;kg&]l-5WK,}b7k]nv6i=['j*9tNC+9 ȡ~%r艥&pu˕$:ZDGR Z Z Z wnzۉ4!¨}2S@aP͹dDy Էq|~u :=mB>5fvr9;:y5WM9َit9:6,prOMTW3A9MKmԻGԻ;+ӢxֵuLP״p-r%ٓŠO3)ƕhUƣ9F'.w#nש+15X܌$pw3211P<^9l%N0n.WN.VJʊOX:8]-\׉Jm;:ʑk4Peh&EQ8&CMTudqMuZwn"⊶_\j:`9^->xEWbFs%f4;&Mk7KxL|kwidw{ש32~(Dӄ[ Ab]&ӛOP#Fge'G'?JH dt?*A*AmKٝ*+vĸN }JFn:tZZRڌ'5GX{On//7g[ ʭʼn$j Mnt$Ik^WrG>},}_'Lp: Tp)MRk #ofdC7)ht {bS4nD?nr~j'󥼸'aO,uJ̊ZkVוn ;fkA c'u"P6sqM9o"\*G5qMptbm4Q'ظ<6goΕgĸvFrM,[Mn+3όkK-ҭ>ϹJ2tOU:jv vG"G*1 UTH[W]BM ~H%4ijtnGRtF6ltwR(J2I^$I.,vk>b`YԸx2durrRd}w2oqd׭-q`*vb }699ɕҩR:UJJT1I4P{NҩR:0JT)*٠t-RTi.f HK[iRTj;$lPVa>~aJd0%hBÔфduJO om2L0Tx"*U'ƥFm1msm[zc's{irM"cL(1zJ*腄NA<5WbFk܌t1)8{rkRk? 8N\qf|6 "Z"jt,HE8 Bc]{G>%11T#|o)۞+*65Sbj'[kffۏkrJJ_d*ĩdJ%3A\xT2%fTd*L{OJo*$dPh\iq3D'2Xjή4oK.{X&8URI-6Ҥ^cLRǛ˭ZZmufK=k%uV޹L3b{l2;w4Єm̍>](1/j=y^bh[oN2ِHUWyFg5<_cu<`ԒY'D ޹jDJDJD- UEGf+Qtށp gclYtyVh%n=Rɢ,Zɢ*նFKMiB`ʣe6tsw-5KJ~S.D~m. U^c*ne>jL;1t};]|s5uS7Q//:4mwjB/MxD'#f\b*l 곀%8#; >,zI̶[wV悭AF';w̐lhߌJIr3211G]61txr^K`"\j\hZT㭏'фń3b\O ^_O2-D|Uv2X3A*&gw6uy>}']|Ic)ΞUVKYF&.'}rNKR~hǤś&?֕owtvΊ*$]o|6gJ6L(GprMh)ޱW>[ N *Nn@IfQ"2b~/vM-j<^b'Ikk[Ih\R-{hX~lD5vv#:ېࡱ:)XjvORf އuM7:iT9<3VʜJSGxp~6Vn8GP"ރ(oΜLGA3u;GBT]Nݻn[~|ةyV[z -lsݫwrgzx.vjJ1p 8JE:CU&!A{&Ѻvg;>Rw^`ڭݫn߽+Q Oq7Py84BFv- BWkwA#wk*Z78jk( #(] #n(?IjAC6 S (M OA/u`A!ACE:0zlop0b-F`! 5#kCX4ch%54C@QC Bu,@״iD@7?05S*%nO!̵ &o x`i> mN8 HG.1 "؉$,R>LO! endstream endobj 230 0 obj <>stream pTɠ - ))y. 8݉]>D&`l' 6IE0 1Xhp* 3³w#KFe76л]8¦M6 cYJGn# #1E ң3Ͱ$LjT|a nM i1,f;((Ib4.8|Cbʂ+"TB!1>Bdh!†baghIq'!a"0=.%"I8p;\h/Ŝcj\N~XOJPkmc y_k|@\8`'74)N\˄4 Sgx&p瀸H6 gƀAFa 8*2>tOgb-!Ujc )pA@>#Y2%F1atdiab-c|ք[i!a«'":f&M~h݇qL<$Yt_"O<ViY>ሸZؒ$ P3#i!j,'+U`,@+}NҍS䮲l ܊ef|D|̅Vؠ$e'sbOn/~ y"Nǫ<"o.mXq&#޾ L q>*@["m)/ .D⧍(X^fœ 5N$u*p"AgV:L8'8xx]'< /7BC*}Qo;uae\S kiXT5(ք CdT:E<*xE3hd_ D}34BZ 24nR]j>b_?NŹy2zrṚc5֞%Mߤ XMбDG-mP)58#"TPFD7C2JVWπϘn%!Vdً`88R$&,byteLr4~B$W wMJP| Oe-'Kj9%.4QBz?`v54TK7`o2,ѩ@ɩC=b։Y"D\Q;4@ dFJ˳>ϷK0y+2:_X&@lCĹi،[ ZneVN6kJjl4/nN9bP !eLl;4uJrD^N3PSlv7srI* #aQ E`({PKKT3sdp jѨPkO:/`,qN0c9T&j}fQ+I Ch( şÀ25e7"X {_8{#~I Wҷod5iļP(#RNhPAz$n!3F%g+QtFau·S⮧%| K#dJ<^Hm>&TѠ8j`Q;rWvBv=O9ߤkf(nd*ChK)Df ¸\ٝF@e=y~i(pL)a>BSh# XxpE-TX T1SB:(f5D"Bz\$Cd9I_(ֆ!\BS∄CC rPB'4rE8wQh' @%NȐN,)x9tlЕ$& @EEFвNH,4'IE .ʈ*[nՏ| @HH%YڪP^P( Cȼu .Z;DEԊ%t0*F5a5ۅ:$ tSB1s_-Č,a}&-jXI EF#"2MS|J&0Fbbf5MSag344"͜ɤɤ isfkQΊۀtx@ON j܏,me`aTe^LلabQ熽x" jk#OYؤXkJmX0W~YQ?=aP;L+Jeay`6i(5Ӥzj=6i#j̠_2&r֭\gz}{FCDv!%? i#RfO3ZJ"=&26dePO:dJX3Fut {Hh0uvVe/Fctz$#B2#Ð Q2!I|U%cwd }'% 8T gF eb%U&q>RI +G-;nAbȳ%ŘuU"MEu4 A .hvɴIDl?G*d!GP-!&GVҒ%V%)" /Ҏ8GdcK"d&])/jU@ 5ˑ!)В~b)Jx–Q)QOMŨh7&DzLO06A}`/նbV):@a#VQʸM!"Y;FM>P @Hr5Na!{&*%=~$Sg1Ynquc{ѶEhWaܢ;(+T޳؝Q+𷶙@^^lS+@/-KƇOބk[mM߼D AUhV"g+V;'DeNs"O EDr 35Ȭļ;<@GMl`Y]PJaRʕ>?=+Y)r5`!H$$-$!#S'0e1dS"/$ĥVr#G%p׻bpi%wg@Nvd=ůJSS[˭r3grIP i Ցf!t&p("2{ƔrYFVtF-,l{q*z/

d||k'&ofԡ<ߡhj Zjε[8/u!6z&I*а_X% ` 'Ђ(nxq5Bh``ADBMZsU'㒇)w%?O~k_SW]龷緱==oݗk=k)q]9{?hoKn?}18~ob׶''xΣعƟ ۮQP_-?3BEػVqk5}o=x9{߭-,==}xںA<ѣǶ:J_mG_{Qf˜2gY/sJ2w.)gN/Sz;8u>\]L~mрBڲph0%ѬW9ZxsΡ4v;shS޽ץ)6\t>%٬> gܧ zK׈N՚b+QPSa`X>. N α~ʠ{hWI#hxSshѾ:z% 1D]]|qH9"wnй),1;ϭ(@ut6`[jWW5}wgo%9r|tOkn S3jvPmmݕ[ݥ98󌇟\Mf9w.-B8rj5!t;Di>@dDǐϠ_Ԡb=Eގ&L/9n5|vs1V)%lG)ľRPT/tց{JdLrӐ>zž/[w;__39/~?'8 :a#rv;scCFucRxixKSk;xvN39'e|rxBGܧO=? |/ c?v5^\l ?^bsk hOZ҇6{ςB;o=J|_>?7v|_ݯޜ}4[@R`bz]A;4'N^NϷ6x$}Tp<.F3D >)L2Ÿ1~ƘdžY_833 cÇtب!mH=#}:FY06vH2҆c1~˵sc' Mw{svs?w s=Ͽk{͕}>򫯏_w[o{bυر9{o~__ݿWyNs}m>z nS>0??7yoÏ?ھ;w]|;ʾO/Wvڟse>O=mh~OwƗg8o?}?6[_{mŗ]pN:{O>~}s~]CGw*^yO}5ԟ|?=W:Y?p_~`wB }sO[Mlk7GlOqs7;ysc/2ֽܮ<3%Od)^/>{>]u >o 3O>38W-bc_CB#_ß:dp$w: ~!o z'_ {P?|ox0ԯm^5Ц74 m10\(_w,3᳔ HW\qՔ70`&kRm~kĎ"GY;b`:\Y"jaԐz" }ΜP,@ Ibt8{d e)wtDE${p8DlG}3@K\j9V ޗ6)d=ű芏5Gc?qTKw0ߢrCݹ4%Ktp1CUv|:ʧp,l>7`ic${!aSLЛH?̹WQRknl{qY4@L$;?s.BPxL&b;/:?J蓊˩aI&Il *1_8cn"\ *֛56TӜ rOcYO*`t( @pSZr(oR!1mUnI*E{THҼ/*"< wSI; 3 RAtQ\{('v!Qh9j5,ET)aSnD$s5EUOCH[O`fBc$XHQb G5sܻܷ8wc Zُ>䋛/"<꿽 |OX~+=}c73>7g_7{n˯ /^ώg>gSK7>ē}hxgһ{]ݷދ>F84g~ }xvތv#2y']g#k5>?Ƌ>9WkrÚ|O~~`'3_ jC/ܕ$YϺ?YCt:~N=?V~K#_/D{P3Yx/<` u3Yfq-,3&TiqaDRR9i/^k2*p XP@Uq\52;wcQfǎ>ssP;㣱 /yK^v5{uUJl89+W{ ~Wswοy/~{]کc׀ҋ\r~s_x˯~ ~(hx_>ǎpy]+U QpCG{/<;ً{tnHw+~e{v˔0W6t%^]jhc_\]^{~7^ ?0W] /d׹{&^nj_{v^]- AWv0x#iG{~[*?Jn|_h~bX=nlm/:XYë~4`qu n\Uyzιݥ^D>"8Wyn49ѥА+_I&#sv ^}^LnE]׷V |e/fpŗy/{ \]@]pK.K. 1 ~v: wVfLC(u`+ic8ݘs4εTufʻ"aymF$E CUqG9֕ThXV # ^׋7If `jPohEnrCe \^^Ma}[j'=_>w@~ozz.7 x8u/p'~ji;OG~.}_t#MG^ntk)f<τk5?8ↁ[oBoX!:7}xQCǑxLwnMF {cx)݈%^j"dxciIcO-֫iASAJ5@LP'Fa_HgD00ۋ$h:blz$0!}n,Kj&t&ӵ{ҎNΌ}DS!*3'PQk*H d`\mgv$ Π #YGR8ͬRFe=xQ"ⶾ7w7?ٵ:_ k|u|dªjM[vSO_"D~m3oqr//<G2lƑ< U$~ W#OҩHZeSQ^Rn8z)I+ 9nS };+ >wĠeD8F٫6]Xvj'Bwիsڹ[:\Yi-u̷;KZKgwtNtI˚_3Qzp= u&F `fBiɂB$U@J_呉)1A@Mu~//6 l`*ۯwO`uyt枴}]v̰zfT}ɺ@_i"!LeR x1 -q h a&HTV8tKʔұL~H3Úy,$ 8 \:IA/A,9Lje8P.GChj0 0(6Hi N@0B$ hiR}(=44tlY~_)V*  Сxb8ꘐp71ʧO5\:++^$-l`'{Q`7h"E 0;)#~U4NT¶ F#*,kd Xq6G2~|"& : 6Cy 8waGG!\A"_؈ Ja JA@8Vc6O+ edANclIE3JLP ^9C"K15MF!puA " ;)CE)E\x6cTOw3[@ > >6pWӠdt0cI{xN ރB FL,Ht0ԀcI`3}hAxM$2@gnvVL7wݶHUVOnmvwjG@ނƗ5v9?{d{VﯙJvd4V>M͕Z)B[c+Ođ{GڳYoxo(x}PƱr<\k w׎.o'rl94i- y*ߞd3VEvt`Ħpxd:_ǰ' vxZǠɎ$2tX LpWio}*?uC^u'OH)oO&] f Ԧ;f1i )4<O暰C&;%fq#F"Ccm:c5fc&!Cc&uoM4)8t&R+ǷbNc5!w0p@ G4(6r9hpMљ_sv69 kXvO5?%0qz`S& fwzT"s{ $:-JL'\Kݻ[e%y{jy e5jbt]:lЀqFQH.FMP=Q;P۽/3h5khh3+\R6|itaY[j+T~e$ƲƤwc]V#ʺк:w7-n9277xcwѮA\/f{.#c r_wWFZzl4B:%~uVJ>p4>?pKgYnOާ"/?΅ʌ6\P~i"Nry_8lAxvUuEoY*vԍwLal/QGSEn˫K' L_je뾕%`WNڷtⲝO24=,[-WwuOku-| ۗZti%/7S[C<OD!e+, G4 :G?'s)(vxgW67 T~e8S[z|wyw[c+-yaKO[[ep#O5o^ GQ n//7O\sò^Ks>ԂYu*IG[Kˋ-bq\j.,N{ݜo5@cK{BqQ?w|-wrqvyiwEK fvG'u!u7Óݥw`9*r>>)>l t]QW$iCYxƅPQяԯ?gy3 s'1}ϼ1y{0=2;[6cTP(CI'JAoa^p3:f-)MM0~㤸$Lr"/P6T>gps α$:XR"۝{X}+T^vOY&r:y^fa+P1rTQ~KR͒G@5h#~>O_W诤$ ,>z[_|=U"ֹ̀.\:(#3?LR\"E{_aluHil KY1듣uqT1ÅQi驔53Ir&PP1NtNZ*d6Bf*l96q C}&gS+|;2sc1'p5eh]ۘ! [g-Bb3*gCnFad}YӶ;2M7dQ^*xYCx`Z % SD[֖X sjqni,Zjt΅s %,b*X%lW/p~5؜=9&Jd'b(Á֚9nw,bsNls5gVy ,l;>]lxuث{b-y+oI8Ǧ=8g^{dy{w@)54/XíZ2Tϛ"T':CN9c,)!`730++++qa-US8Cl|79֎m`glj@ݕ*n*nV^^ܟLݟƐRIv}:)[W`Ø+L7VZ_e8;lev+6XL)'ZQeU .H8#M<<1h axF8/9)BdPFɧW>!BO,67p1nS[T'ST@)fl3g s_MekWb@ܗ :c?S{7ث(3Eb"T#u2Dzmɧ7*{f9*fbr鳊Y&YUXw}0 ׮IgdFrpZS ֺ,[fwK(*q:=}5VE?69*48jDv_W,r"o!}-^g .ⴐoiņؑ=*h<؆2TRkL^Xڌ{ʢQ\ފnA[ym/zGΞK*=gX9+=疑EOjGf!"00۔t А6DHuU`e^y}4n#lϸ \LIegkgw:0~~ֺ7":Lp093J Yg{a]$*] 0%5sY)7F1ʍQnrcXGn,2u׼dXWf/du7/i~'_פGx8cS^0ɋ-|tyMVl15kv5?XQ![Q[)1bJwTze+;+QIΥ"Ϙ{rKj-䇙6Ks} @a[#i$ߢv%mOr}m{!$cSW[㬁h;j̨yzH].d'7#ak1 ⪈)83VC'õ&-V5YB0} v(3ɋ_Eg|U/ak'ϸZk?|˸]Dvmfgmf5Ge\ɢ)LJA Œ7$1 ճL\vqEة3 w5ú' f}*![RmWgM%6)!S0RrGBK-~Fj,6ͬ@E TTKhBczda팈dcjڀrzYY z#F.2Pq =ݾ 9:`'TDޔDD),&mQbEtV1K!kkz7^mbp`ڿv?ܨvH[n3/d^ܱ0"%Q@&90A& $xq ݚVhQ|caDiQ+I%pd "Snt[ÇeC;dd|ÒWϾDkah<5HCmfe;nh)nG)%ஶ8Y.)5Ж{wmPS48Z; FɗDdEvӮ\ O%%m1PCEtL7of^H_͖jÜakb̻0aJ/v9es҃ë8(X-ņDupHg$Be~,OgOkðB8Qn NeKc$&֏O!Y(4VGGc?b% w8`ל$[dIIdIp>/߱n[^b.๝=w`W'4 ؞>_ xT oy#^$R [bֈw+BCά4L( eZ"~J +rYS0R*۞Wr5D,֜dPu4Gf6s!)}=#\fHZB~3JES ?I:?xڿx*xS< cw%$NG$YTd; (!Ïx9N9C}4CdJ@Wp"#fdvddا!m%^NͽڈNRybNP@}j^-hEZk[WыxErZ6 g/.kYyϳK1%W}q]AkUX@tޞ R:Nw~]԰u!ZZx$.}8+'1U4,c)d|sF5tBE|ބ/1rF15ܿ;L:]h~ØTڏC~jYAK BWV\.ahu}y^,&l0s"}pIdF6]A]ZL-dqD9igo &lF\q+ Vpߋ'n,#,wǷKUgDě) WK"] ;V2C.S/; 0t)8kn Ac=EEL׽ q_q0^T){I_e,qU$o2W\"X-ZEA[>>A pFquALxM۪aeK ) 6yERtYR[t/(.X,!YIdٟ?\l(ChKN{Wq0lj8Ù>b E8tFÂI)U]dUOƋ*a)5bSO&_|Q|lm a[(b\PQ LCF.>蹭y㡣c X<: Fn~i AJ5m?%ljqZXRs$@~brt SeGF@~zC[b^IUwYz0d˪|![%0X\.{H2eb^&ѐV d,oш_rң@VLzui,G`bY%Qf =HYi<먔5"M)I!h`(A_Z-<Ě@ b~&ԤԸь.wvLwv(Gs>LꍨC12 ')QGUkU2!; ˶SvOC R@l'#вyrPձќq43/R\3U*SKO)ix%RH4O%~*S\"&K_$EMb9FCyB P"O -,/uh6TF_s@K.(H@J?!vPT_d⿩FӒ"bM=-g]1RڕWd362Lj4ZOol-$CndN65?VxHqߏms芄 e$.Z$FVb9I:I˷QPA*PF)o%B2^OUHΡWˈ& LTSӛS?BPtYJ %#U6Gfu "6k6;xKXcG$;#祕Anmd!g(>+C/e I$V@%(q^EѰ[||El=5eE(w2܉7,X*B $$Up(9#rZ~# !wEȊ$ËZ8I1Ĉ,XbȒHWxyXI1 6@:54A+M!j,BsԀaM`Q3,(:`77 EYHqS%*۵rRA$GwTh7FE;*ڍhwG v-M:N 86OUG.cn~Dy_ߩR2͢uPWyXc0LT,b,eAlAp,P+q V0N"p":- 2']{?4n [< Gee iqO闽g_E Jl{q53{./$gZ|b4Tam`<˾y^dHNJAD8!~$dbLcOsTCU1Ӏg=/&I~*q1qb?"V*x*FjmNxkI*D"V"{EVvB VFeʻȐ?'qƟ^d+j%_2d?]ކv^t}ӺV n`Szql2d?r:M>ZfZb,*=7u/홌߈z[9sF@ i :^X;/Y| Xދlq% j.@(TK4\ݩypq;}DRHWgB~i1)i1Zw@/p0,^1bLŘZZVX< Hb(tBS/H%pl"0&NjDII2feQF$ 2,xrvjL:kgiIK׈nax_[x!gh.ٓ-}Fߋ{?kN+8vZe B-5Q1p6(6Gv?)j/ղSԞ -;y<G '0!A8nq, vh!*Hj Jkcox{@ǫ*@FZƲY5]|*NgRo.ǛƔ8PTCQͷQ5L34R - 0S/ѡ{""8  ,SʄdؗL(3}@XpP` 21$ /Jv0,K h%!4Ѐ@4Ѐ7A%^9OJ+3#MUD~JT}'@"㈲ m{d+r|ok[r}p$ =3qwb lYgkq ge36 ڊۯL݃,;ؗvddk2dF1~$[}L98b-WPtX:[i)WuFY%n1 dbƍSe䈔HcP9+K1ÓDBU!+qv~mMMZ3i˄: [Xk3 X 8t`J0JX^?@g24VJP"Bc%y"5c+͵qtg@ht4d 2ϠZ!/2<vE(~xΟ IBl0~XOBOV 1VFo2Ӑ@CxLR*( J!JT'D![Z>cUB?hd*!3Fhp |o?u>:sٵˍёA fJk/gهmlPd8nr<߻Tdk @~kE_4?eO:f Rᔪ{mz3ޜZ }Sh%D NRaN)AaGゝQ# ;SM7yqcwT8cY g/ /$g%ta4B/`DV63#1UI[XN`{ȣ^j:2A SK&wTvFR$Sl]0R`tTUVSY'U8՗M $IX) /ID{ J#U\yJZ[q.g"^mT0GjSՐ`+R~Y^z."ST6P=CUj֨fCR q΁Ph+NS3(YO'M4iԬ-+ 8)~yK\T6@8jRV*5ϓA8JЃԃըZmT0`h$(oҢ>}:ꈜ2~:yӧBeʌLUʜh+DD N.b$U4>%ԵꀨP7`ˌ]{[!c*{M)" [敩Y,bk }1%ETh_A].2RQ_/BT8*iń+M*]=F5i~ ]Q:sz6i!{'(q%]1ǂ_)yoFkRvꛩ ?~8|)O~7cfjCq7qyf \$JgoWR< EȊĨ+NpNHN;'VL3|@SOK{9,_ߩQ-(ٛԚe%#$ GrKT d'Y`(BV[)Y2dR@ARF2SK)#HARFpA_NY eYbd8L!g`eM`֥V) HY@_-9 HP8!ZKD>`f^{ !# X0H2 %dG`#hyTF-4(J-[H2J }{-o}ΡWSfPOmOvMt rftXkNP2rx( Qџj6/msK!|3IԎsZ|ooRF(d`I9r V_ O2dN59e^r]@|!")>@&r=[1;Ի(g7tMuQ;$w|&? P B2.&SSlPQES+>\JET[!^bx/,ZZH)ʐ2=&jQS$"+ X 򵌮rVONz"ӔA艼H>F3S~! :8vJ '0p感S6|%(tG>0+{U׍?TFl "I^"(đ&HI 4nLo #8A$r4^e <Ẍ:VGk%PyrPUz؇ d#**62 /4iL0XMcPD]`U} ˽Hn4JdN iPQRN!pP Yd\%Y%% }?fM?WMҋcsF!S&ߨ"*b<V$D!52˓0D9/D2O//p+0V1ԑ ğH"tB?ޒh;U|.OtNq ^a4q֊eE6Yb ]iX;P"yGF=#^OT3-CA5`8\VS[o,s$\שJjQ)8=5Ed Vl}\ f6|}TeۭPwZVV(\/\~ҰOAݣ5x^7bղ7UpkeVoE}z*/H8'~Q#Ks3ANX :,Y@hދ,$  -6/ÉQ́!BƼd+&KȌuvC4Y5%Ui^$A+8!kC'` /6ʊ0TJU>։=A 6UhV ZR mJW p~HVܓuJ ~9 P?ߩ+O)\W~U*Ca'׫NX Ct'µmV$v_@ȤCxо+bftКLLqaRQ-%PTzTm)]k>٪By&Cc+ߥ?\s_]+fɤkM/:C%SX:_;Vؘj" (ﱡg_a2>$FSHT~,w:>iM[m"=ɭkajn5t؆ څ]o?J3#|;Şs_c_v/v-b׬BBi)% Hڼ||}_-:\ͭn+e5g%[C~s;'Z`]2#(E3ዾё\ WS),*8,_ߙam|xj`y(j!rQ_,FAʺro9h4uMŦRwimMceAs`?XAh@\F5+Zw-ɝ>Ҩ"M5VV 0}E7ViMtb!,]e 56~ZƷ#yxXn-2V#'~XF:((gd5%@zܪTGxԈ冗m؆Z53b7{cZYф.%5j.k]lwx)04ԙ뱅z\"9(,OkY]V˕73K@m˾gODOhRao yQZ #qc!0ZH4JJУbA}vUpC~߭}4*L@FխPNNKB}/gem *2mzju08ތުQ70a޶d0֏ɿ?%?1|藂Z11m=mxtX̷XDPgΌ2\6GtRAKypwzru7}K"jP*hjEHm+Db_ =緪ل>vI7y ckcV̠ ~`&VjXhcA7tߔBSg>6~px4bҌFY{?ޠ |&*=˺4A׉ lEɢ\-C"=zn9&+{,Yz/i:ksx;,e 1pf+禆Dپذ?&V8&`<Dbd5ߞl֒s #'%b*Vpuh[12m[E>=g.1(XW-t(JX+k^ n_Z#GQrRWۺGlP|jЫnmCj*(+VK$ѬJ݅ Tqė/QLZV+JԫJygB= M;]*jj&6~;J'̚g7]4TΫRk2lCS)K -鿨g-`vz=Ұ=q=׷[%Ja_,UkMw`(ŷFv-ΆL> J9͇ƍDұ;B/6݈4ud|%<`zo[7R4v3MinEfD|RHKC'f|a9R嗻ODpbU9:8WWgYÜ؎vۖ|x[+[ӊe?='@ԍ7&Bw7N wIq㼈.]8E5t31tQP EM[5tr--L{}BX/u;YشR ZZ.7XI" biL/ (KZDov}5t!?pϯK ]'gfch`ӊzwV%=@6J]5 VͷB>XEvi5ӫQ{twX ftmTF̗6`O95ަ) lVicoF:H45,DBضfjY+[cJ]#fw=jaFn;@Zd݉KqSvZL,HsXI6Y%Ҭ'zNR" >v⟛FcQK3̨ea)[3׵OҲq]*V)(@ 4F m,v.nZcRVMW,hsPz̢k3Ќ:4K])Ag(Aj$3] %n8~^BW ZCn5qE hg69XݒRrM0#E#[u(ts<[}GԱ}A1妙Ѻ>>7μ殙eh] U$nwJf(v&7k:4D"K)%3[pE5} akaJ}CKwӋ A["VQ1yd߮Ҩjz.A\\EUC2i˼ݑ٨ͼ6/40'T`~A/?Rhca+Q WPnoWkYGXd:ʟVFP=⨵w! V'ױ5{mLf =u=(jUSۊM/9~(9c| e>5Q ~|, Kl.ejd47( ?KXꊙoE w…Gy> hchv`>z\^ȮPVC=N\P3 }+aïs&ڝ׫!~=?BK]<~Axf+>aM"+qOgA ]fv±Yh)ood>pDջ={n؂B#T0ު9雈};={iq5v?\5zؿS1E{G^1epXx F{{g*/u|N7V fyc0s {:օ(\Lռ/%j8fC ES!)fO\4|z|#? YD3w?z#5#~Qt>݇eC^!n.jbޥgm6dH?xWo)ܿYxϮEsj?/[}.[vGr,iW7ՋxM3ąEV\#?\}K{_k3^;;Gݛ7^+Qq[0Ǟ`?Y.,gV#LgNg3̥~Q\3>3Τ h!;] RB:TLҜ]wsZv6fnuV*(٭_ٽAϞgOv`~vyqY.* ŜUߒw 3[f Zmne?7l œ1s\E`q NWo˵mpci&1l>eOss_\oV0 wg'ŧypa%:u3fEnx{y>)g*w/zc>_R6]Xg~a1X.J 8 {Zh oNŅ텇Ԃh›*<.j`vq|X wspqbi1|lbigwV[*-TsYxX89|]v16\/TY7N\*&RtT ,/zd5,,ヤr",Enem K|cu%8+|~倛SW. eP_VRמW**+3/&zWoOUe<~*W+3"fmu6ֶZٵ m`xwVF }@>x Tj4Rzp/Won7'[sA #nk=pyZ2zz~Q^8 b<+(q樒enޢL".a8[^8TSpm,HvC *ct8rޭY"M9/"¯k.!gyn{?ys ïW"ݯw+s^+en,W*|+ȼp~,o"•.'e%~ Ey9nNab4Vr[i$G¼y&i{+qB/ܔXnKΡ/mmh?B_j]mG0sǺGby*|=Zܬ(4+lE޵D.}HO[ه_ہJfyLɥ_o掷KGllGS;g+;vJZia7wwIbWEw͒"ﭟDnq/49G-ܿnnE%^ʿj!|\bKx6\2ӫhHlؓHR9dS7ѹj&*G`6~&c ;Z,,,ǮR/޾99~Jy߿/3<|tcu<`A4arŠvvusZ^~?~LG}hʞGɫQF9^:,o?#FFS,I+$C+'e9‘ӫk=}oVŷYnٳS:n\jg2糥DWXa>_;2cjoqٍS~witϬx=2L9}[c6_+{[k^]GmMQ%vpqūɈo-cdрb4>!>Wa!*'e$Wr;psw} 2G͉rVx| ]E7Gml񼷕?m|5ɢa~!>ߊw *\;k!'{[VGhۋ>-|`?Blњĝat,-\,ErVh[X ¶xD6i%?iI0hjs6LX] OIr/`yo(mpy/TL/VO7Ӷ+nZQ휸" :dpXSú(Xk?ߋndpvG/[7 65L)Σ%Y|,^V0`Mϳuek!_}00Bz!M0Lj'_Vw[ر>e޳՝}۶;̼ӬwaPQm )KJ3_>t*ͮeq. S[םU.] %ҧ+ gKݯjm,uAKޛh6ː-E*˫;)0Wz{7Now)IfBt+kaC~iM*pqWX{]]Guf >YyU ]Ut [ϰkB[UBi9UMsQۛX;Rێ 0W8=| X*%? ǡi<=p#=ma?zr>n6wyt??.nmnF*,ngM{yX6A: vy𠾮Muc2#gԷ'8~5S%E׵AvNC%.0[L쩶#ؚq:K?E M/<. \K+. y2 'زRN׽+qBpp66Up S1w^k"n/Ce\ծp|:<=~\5m) D`wѢ\AXGz^ZԱŌscwiiꀊg wx5la +m/Qxv:dsIhMNpjMk[טs)!dhW=qL5~_N?vه6ߓk>y͑-ge&@j4 ċ[@0P0枳zN}ln?mmS~6\8dŎ*[]V> PpnC۸6xcWD|9Иoy=2KH>lF 1 ?ә~r(\)>GWQ Րzrek33by&tuhҞ"eѩ߮iz,d-OzGyUCR7k3t̘Oė y7:9d}H.Y ,8,ɠuqv;r6(]+[&LꣵC  󡫨ޛH]a- L=վ733 0|00IyaBAh @chAl1(RܔsnmOﭪ{rO]%0\f>qG&6mD3Gy+v 73+ly.Ijaw%7GŅǽit Q--. t[FsoWA> $LZMi w4!O3Ov\뛲=>UEǷ`黗 blK ġjer`%t^RPgV/jŀ^YX#ɏg"eM߇F~oŻ͘|֜.F Ձ4̮2ť&q}+gs#ƪŀlgrn6/=ŅX)[l"aMFI(XR%wG`Nފrt*wOW| O N):?A:i%"NxZsۮmX/&io7B `폈׋+ַ*ǕʉHsJ=\>% quZ_)׮)䝕xRHMc,ŮǓwҶ9<vLYrl+MPv87r[Oo5F#;J>=7?]6s[;\;Ņ=tN*RZv ]>f.JTNJ}b&Q2>, hڀmcE Y|q|ad҄kN_y5(N)@NӥwŅˍb,VFyTz_6@/{E]vnu DK6&k3/Y8/0 GiǶ0Fbvv|v#oFF㵙cnWNJoǟLvܜ&`EZr4smBP *) !PߟoGK'鈵hFp&~8#eƃ猪}UI$SVk4tW,ȩVU>8U%wј mY<>ti'{|ne0ddxrs-R]XS`S7@6^)OT{So jo4]\LDEhTn͙:,yKlJO;I0ɕ}f8a23q9! tx S6^xH"nȺTkB9;sK>./Y:.? h.5a`<`'sHRpY4?j6Z5Jr[12o-˝>ގ3,fnoCȧbv4 ttu*ʘ:=kر;uXᲓnP[ɕ#4`:V8(Clji}#S!tҼpC3>)]rZgk*qf*Uns30d_׽2B;x9vݱq,H<*\:-۠N3rEmPGidAE0dGu}NRT,zA-2+';ԅ*Ȱ֠nMMP[<(l#FTmcPw'5ve0BM<n᥍.VG$ r䓰q~4[XCm6!P#$!rG]|9\v#ٶedS쌟>f=8`w^3ճWϻ@#hax6rq^&RNﴴN^ʭ7<.rs#]qb)Lw)FkN[HO;nU&s֤]G+0G']3-D [/q/+Ԣz0~Mtwi.'gW4o *&fS:u=Qw= H:AvFfEyewH8|;mfnf@FJ׳tFiDi4`)Б;T*w'TF*1\)l % U*-v9>;&us;'TT<^f8jvD7 *#PN,88j uO\Aը$'<A*J6bK_xކϝ?x>ѡ?:6)^اӍ<8D>lRƔצNgƷ{?s&?Om]G:~2ۋf;cfQXyB1OrQ@d̓i2Nu8f٤iƶf>\D0zgsFw֡8$Z[Ӊ35qҳ,ccȤݪ >ݪN$99 dֹ۬02‰#$5$.eq,FNzC[ k菥I;W(mR/ؼ Mz}y^3?}..H#"J-Bdd__{*DF+R:^hlv6rӒ9X,%?w$s}bk{F?B)tWuWkO j/H(І%P۷s?,>/z,U򉭏NT477~Lc"41x!t5t>\R/G_V'X(a(A8pdqI,GЎ#0BI[[0Du FRq똆-/g/;6gYDB$,(UZl &A9z\W^k.+8-AUxʣŋE>mZCFpK]Ø>2We>F+Pk[xTL_Juݰn~F5nȌ@GЈܬX=W.ԝ]T,`ǯyI7Et]hmw8Oqѱ2][@ذr3#y@ FU8Zq3 h[Ť51[^w64?Fp2GKQ!}ȦgAppo@)s&+t;~akx}[H+9HCl4ԍ֊J?Z=Q^g Թ0GtvQ^zhОSPk, =wh3rCS.ܕ`{tϤPX:Ўq`Jw3hA(t?тdփSҩ6NUH{wړMGtk`8{8?>×C{5[lWߏ}mSKS``vhcc5kv Ƕ?E{\[޾aW}H^j8QNS9Jt>\>!HC6t>\>3t>\#ut>\>DER{L0I3=G &/g(}=fL' |퓌>QޤwQSM>U@zm/@)w*Q.B >#1NiwvCW>y[ߩO ]~SUg T -/1䋿4D3\T{aprRrE,1 vbf@iw]Ǘ2b%[QrėYtPT[ %2Gk/M8;{@ ]/wӌ B5y9+ o7gkUx}tWOт&A S1|sƥMtz'txw^݄%\VV/p4V~0& ZhEK Z>ivEv1ii;=)wǐ'T"R:qѓ(wƝ=3}^GtWAwB x ݩ gX.T+:R o Y}{`]PkqAtG~4q۴/U.af[m)K7B[MCpiY/Ai }}kLw ?{pO#/T]we1tu2I(zR} #A~ El3Nzn/F_zo Rh?UͦbYHpBa_~ڂz Zo [ D!^:X E%XkkG?AID<- L5fUjec] {u:M)~?{[ .w0.g"MdV[}-ܴ l~98gi;#Xf^AdE/;zgk̼vNJڀ3}Ltfe=O$@f- ScyۙzSf٩aN]0vz  "!>9uAB/;R-߯ [h-U4;#P)SwHzG6uc07a~@l-zb ߍhm9#C=]xZ'\^ԧICFJ:Xtw:KĦcCޙ0Ħ{?/OZ&/@Yp5@I@s{i^N-I>R 4I>rޗmAHdd1om I@d`h#^  ؏v4fS^cǤѿs+4I~ocmK/ŏ(ּ3fbg3<' ^=$vE0v?+"!ݲҼY{NƣnuNZ_kkΟgK󙗉By{N> gK\U^,(%@ 9:h|]kRg˒j띓v\^pxhs1?:s"O՛>gybo[`fzn(mmz>^/aDWStOk7MN >  jh}nVz=a}nXblHs3iGo? (m ] %װiA'5Օ8Xb[SnRg}ΦJĤH%yal`0}n Ddq~q>a:/sb[Ħ>$eQ>ܲ">gVF{b_{/>^ܠ:݂/k?ӓ}iK}]O?NkwBL:A{I:u9c"֑{ :UnRST:Uuɋؐnu0OPVH!))^Bz8;+>GM ?u s!:}GN}gnOL,*m4ots;`N_Zji)@qS6 n&gRD&5Zx&S1\{.FƈIBS,%zp4`|q/ ւ|o/`$!@"G=m~PD_3k3pV}8ֹpv ;mVl߭~[G:B\)f9gq._dI]PD%Fv eegz)ڲ7Ra|F#por]'uP).r4^1Z ?HH|熼b 7Qh_5gq<wIi+.G_v_{dJ͇Mr_D;ܿHܨ,PG0.ەuns~_WQMٝh 4#fistHv~>GǗ8aS5=.̴v8/ 0bN*:ص|ZCf R.tN/oQMN"nyi.Wh'\JǤ@ݪ]}O-VnSԳO6me'*t.} ͤZtPQ{hefl.Zv9inҖcڲ=F|DM9%Z7SKI kGJL{#`AeJ['ݦ$]#{˔Ġ4A9$&훒)h1EiB'B qXa:0R+tHBWs.g6BBwXOO6 SƲ끇U'wimx[hoO@jEx?$1zUiA{vNð><;yࡿ4o'}ic"tB]x68K8K#އtw琈zo0ya<#VR C#Hq=Y]^<îĴ<O;t{?п7f CgjÈk"fg@vXyqLCzO;tFpaǔ_v假Jq+2.% _f\}ԙ`7bHa6'kvi,֥9V6GknZC2tզ.Mu= lfq8q:doeSTǬѕم4{\= |z<{wnLRs^ϯyi~ï1Q=oϷG.~z)+Y~vg=VƪkŅ⻑ͥcc.\ǚ(Hco#%KRMgwvӉay71OƔKybHkVT:oGf^vb&Kꈑ.l? |jԝPVS55wux;6_^t/20fvaU' Dc={=;̔95zw9|FkIXŀ!9+oo1K[KOa$z߳9HmEk'N*jrd>2`3˩]/0s\U>vvEclVƌ΃&Wq[۫%JU^Kcq̊M]17^4/6Fl0-I g 3IRvԄb!mVF\Vh$ɱr&'kFW nH7}Tn2•ynTϘְ:I΍W+0m5MNd 2Q*xxV6A7~~Hj\YQD$˳!_"]g/p6v/6vHh;9O`3T\<%nM B0S;ߥ&soK [1ӧPkcv4ūi&ڋ8md^|YmTNMrqs'ze2<0mmj9DCQ@1??X]sx_K 4u/A͡d킬ax1Q8!7FwyFvtq2w9;sq1A'{_"/W&~v@KLz8O42ƍ?{6e~E#8?޿0L, tj&8IVfKX&`E 4QEh0%rrF0T) Ј>I̤K)*dٙw%?ܙsva9b՚Ff ]ơ ZFj+ iX/Y&]9\?ԕWML{R7Rȍ/ ZqMX!ѹ%p1aR722;Wa.$-Y)-_e#b&M̶e*w81m KS)~|ꈅi.&}4ݓ!V wqbkG'􃡹 ۇtىɍB8b’c&yDH,!h8 6!Bv<dbQڤ_ؼNH%2.GshSnZ$Eup.Vlj+Gڰ-ߛz%p#"a $f\z~J/Ϊbd dxN\*yb쏲Mf`_,lf&n=S뮇xi&Yd>9i/ŌX;0nLk΢F-&Y:N|t )VL2sJ1NZ)|7M9?3  W"^hʋ)^h3SZд~tz\-1oO-mB'2MӰK b @a/i[c]6uƽ*#ʴJLLwV*OYKĺ1*-#rZcf M-9blLZ9M0'e#k.R[`%g/k24{qxjA9YٺE* U\\ʚs0QJI5z.;&rH inDۙtkOW<I6mM'v쎰O.cs5gjgq[Sibu ^ZeXm/Dz=:%W_ܕ r81-36^7&r2uμ!9C͔g)-D2<왙FsdO ,MaH5N=1]->?|A{^쿤5=&MZŏNꒆݪ7r\f2;4i~@M mnL7U bVq2@mЄZTn FS@ d1!?׻Fsysu0Xvl4xzxxer[E,6./C%I<)YP3Nlj~ZF7gŷ,!% D 2avzx. 'maH4-6Rbeya xw^zY \U̎GUnK^KB"EPհ{_Ƈӫd .ãE%3cpbcdu8q^sé9\ٯO>G.vJNJrʹ?RF')WP\TuSϐ"_BҋNG5etx}1TzZQ ؾE18haƸQM^X7`^kyT7^Tf&:4!(x_''A<&C6Wɒ"P\2$&5 heZI< @# w9ux !NZ1S^=L씧K;N :wPtkO0 ܤYKd|QPJy~]\w>kPm&qZu}F5B_: >ϰ qRiOYu:֯.҆qHCq?~{N-;&g^ԍa!Lly+m@^3Ig ˴ݚNi͝4M8qd}kIQB"$1R]c@g)UcnnQNԅpQ8Lf2 }hVY2r=9Hdbh~e '5) @vL^u`ӏL;-P!b] xbb{J5kr *t5g2܌infak6h,'6gwj%pb8҆CnaydJkZhoFuJoak`hNri9Ījͺ C= ɭg>vyj{\ ZkÆqJZV+ژ;4yZLf~nV>n#B;yDD׍yc`j=%(fK{<yI_ zG3N"_-1Yh4~Ť] FR/DIe,?CaRheJirm 27.X?^4|Rh(Е,gLeA,+ .QKtz}!eI/5M)9IkvAH a[ U4^jZN*G֚`cDMgLjRڙr;Sgky){4nۻ7#y+ZaBΗBxZ&xĵ_]MnP*aJ4T$4N{O9Jo+E}4LZK@Wthnpz ho M ,[+=\V=yDW7/57῜(*r<&FCer͗C,_YY(ekP q'vcf(ybҲbKxg~f2o(ܑ@s@ (&*7b 7J~h#s)6͉* QrCWqd0Z/ϱ/ '>p#Oz~ '~곟O ~3؇GO}?I ۇ'R3G>񙨴T{/}Wt}~O,(n?}t}w,O?~W]?ٟć`>_/w33ӆO¿?G?ƿ룟G?#_ CG|/Wp'p>o~P?3|՟|4~_wÜ?_܉,͗᷾O~׾'G_08?+!L& `B0!L& `B0!L& `B0!+0#nvi`޳CN}7ޗ{tHG>?Yӽ~*v˿p,pwx?//|`窿?8?o/gёz(ON?-clΟ|w?Ŧ|𱿫>wptGД_|ϾM_~W.?{_|KG?o篾Wv;}~_?z;y:l?f_џG]E"[f}G{_Oi󟢃>|Wٯo/iaU3|__/V2t 1Ó/_:*L ޲K_΂:s? G$?#L\f]ż[fhB6~?~茷ÏO~S~ӟ*޲§?1}m@ :< XXGW#or b j6뭗F3f55=E0Ckb_Q4Dz+Q*%$ lxnOCfY*y!UyeVTOˢ$) }9E—I /i-AW `F7dTAF*cTF(uV8w}rYi< <g&5)A)ZwaVT j4ƤU|{5 iIy[soyhwIJ OW/xUH}/DeRZq̢VFbaTq05h=³ieD,ENWDfS YVXЯ(ryҌFU؃|Zd(ˆf+dEf*pBXojQ2l?Y [M"v`U9p o!*oU2F`GDP̲K< j>ÀdJD#0$Qpp*v2L ćɊcXw,# !,)&f(e^08v,Q%iN% ݓ`P15`Xdx(2̸$rVS-eX O\R5l'Ud @bTF2ˀ$35p^E'D)3) x,"B{`3K 2J[h#e"K8p*oVqrQx f,/+w$EIddEE5vI`-r((kA0cQVW8d}0&򸰲((JBb/< %FCBp]آSX1T~7_[CۏwqB(a@x1Ǘ83eϫjȗ%J g恎Ȍ,pШ Iy5_7/7旆X7zi<\ i7.kP?r(6b^7&7UB-|eHUv l|8 b <+, s8Ӫˀt@| 82`5_۔%0Y*gKfdnzm4kaDy \2]IZGImwO;PAC H!"꡼%fN6d@̲|MU74`5%U m dQer*Xd贠hDBuP x*eFīD1@$^< :bD l$EH8Hj(F3*72>W(K(L6PUIUҌ'e ֞c iT UPb2 1#3JSfEF{y{ V8C@e $+2 n8T`CAHPa)}A 9\5QzCTaqV*s+ *bU2< (ļ/l _H #BePiEӯH')1*fŭo@X_Zf b9l dN'm#ȜBHK:hTAu"%v%Q_e؉Wi$DDDIjDbɊ(XyI0A Xˢ+ |)+E.h~<-iki 6wVuw,0{}yL7i#n.ƚy,RK56( `Df~>\56.&~xSo@wHphWWqV /d/d rn+_Yxh.5t_\k\b'oط10$mD'_-P}p"8ԟEd,IUɬ&p Kz "3Di6Kh &x 24D+Y@1(,cAͣj@ V*&( (C_`s-C~vPݽ)N $JT\VֺR =<+IT%£ƒ؂~W8-nC $o5Zz/Qot ~s }0;n㉜VTv@`oJtqdYvѬKce81U'" 2um]a1;Ʀ ^)̥~Mc,2| )jT57 :"#ښbQ~Qҝ-Ewx(J;@-=6/K +/*DN7Dk"zۇѲ"vQɩ6"C6^6Xͨ`8E%[-=>^[we[-` X#]UǨ$8YXͨ ʣ@_?6Z왈Uje:IS J2U!]ĪDX*4Ȳ%Ypz!#K$Kl5'YqdVaSl8( [KMTF`U/ P/ =Kwh-N`RjE(e$e٪@F>:I$ Ɍ01^w_,31b3,$1 rzpA:dh"y:2-RNr$OAȊ2 1]U pD3Өjp@7贷'X*2TTKJɲ! z%i؂2"?vt$f1n7 ^5Q`D4QI@Ҍb.'B֣yQM0hwDleQ45t)a&(DlB46~FU|V<ϣF@E# 8 i(X ? 7d8x=H(;6DxRQOl$(N^ #J >)*8^9^f(ij 1 e"/"J{ *C_Bi=I¤*?IS5%Io* Uq%`eD,Nj((<)DQy0 [\բ`B)ƭjQtb_v쨁fGX# #UI HbJDp HRQ"_.yQ2]zׅP^yb7C՛ks^w<0%_/7*@I0镘ɬH1D7B e[mF-XOjI .J$tȪG 'Ĝ!Y@/a7)ZGOL"+OAު(7悠|WˢUPʄ\TJ29(2,2W;c,3*_$gzMLz ^ f4M**jZbCDҳ!o238ͧ\t:K_s(rY7c(aՈLzEp#RZBj)FBG}0*>$D@-aQt12 $ДA'UB[b 0@$!-+i`U 7ʚ_,;zErGH 'I 6t/Q6frUUΦM)'UL-%V:IH2`RHN`"DIATV&~yFXl"đL9!/KBa  yt˘l.0`+J+)tY0$+FLY6.̠:2;`BrU@kHf))Iւ!I!42"Z|@0m<<4G4$-Jd1*1| B&B3؄@_hq[eUâ2+U%+KWLBu+XPj6}} k]7묉t&"m2+a0+A 5|Z&()0Z+ʊ7aԐ*I+ffLl#jފC/ 2@]1C1S&z"2(+^cD"!Hu,2tG A*yCH4B V̆&|D# 2/fѾ6@=,9-\e 2Ћ iҋFR'@kDW0S I] $" lOy"̊B| R!֨1*I^9])H  (@ } u(a#"*QET$@2^VW%ⳖC,h}$-GY,;241=$aQE"hS]{9 sEuY76jUG0 z;ٖF~:WÖ2:@I[f"@k4P T󦨚~YL6 2 w,P9F-cQW9XqN%ǎB VlcFM6.Bu/YEʒeEIT,(/ BU9I=)˥8lbP6`E(/y~$.Z0#0hP5D|>  ,0$f7_j4S)[_5;UPѣc1Ժ~"K ccr ݇ endstream endobj 149 0 obj [/ICCBased 174 0 R] endobj 5 0 obj <> endobj 6 0 obj <> endobj 110 0 obj [/View/Design] endobj 111 0 obj <>>> endobj 108 0 obj [/View/Design] endobj 109 0 obj <>>> endobj 121 0 obj [120 0 R] endobj 231 0 obj <> endobj xref 0 232 0000000004 65535 f 0000000016 00000 n 0000000174 00000 n 0000042784 00000 n 0000000008 00000 f 0000356296 00000 n 0000356368 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000356558 00000 n 0000356590 00000 n 0000356440 00000 n 0000356472 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000068464 00000 n 0000356676 00000 n 0000042837 00000 n 0000043488 00000 n 0000044387 00000 n 0000069392 00000 n 0000055904 00000 n 0000068656 00000 n 0000060385 00000 n 0000068771 00000 n 0000068896 00000 n 0000069020 00000 n 0000069144 00000 n 0000069268 00000 n 0000067167 00000 n 0000067313 00000 n 0000045286 00000 n 0000045612 00000 n 0000046165 00000 n 0000047533 00000 n 0000048898 00000 n 0000049830 00000 n 0000050885 00000 n 0000051441 00000 n 0000051999 00000 n 0000053292 00000 n 0000054546 00000 n 0000055119 00000 n 0000044451 00000 n 0000356259 00000 n 0000044721 00000 n 0000044771 00000 n 0000063567 00000 n 0000063890 00000 n 0000065250 00000 n 0000063631 00000 n 0000062156 00000 n 0000062590 00000 n 0000062220 00000 n 0000062092 00000 n 0000062028 00000 n 0000061964 00000 n 0000061900 00000 n 0000061836 00000 n 0000060592 00000 n 0000061228 00000 n 0000061292 00000 n 0000055758 00000 n 0000061164 00000 n 0000061100 00000 n 0000060528 00000 n 0000055694 00000 n 0000059153 00000 n 0000055941 00000 n 0000056503 00000 n 0000056112 00000 n 0000056203 00000 n 0000056298 00000 n 0000056393 00000 n 0000059270 00000 n 0000059325 00000 n 0000059622 00000 n 0000059697 00000 n 0000060499 00000 n 0000059843 00000 n 0000059872 00000 n 0000060043 00000 n 0000060128 00000 n 0000060217 00000 n 0000060301 00000 n 0000060738 00000 n 0000060854 00000 n 0000060975 00000 n 0000061409 00000 n 0000061464 00000 n 0000061761 00000 n 0000062374 00000 n 0000062495 00000 n 0000062707 00000 n 0000062762 00000 n 0000063058 00000 n 0000063133 00000 n 0000063287 00000 n 0000063408 00000 n 0000063483 00000 n 0000063936 00000 n 0000065160 00000 n 0000065197 00000 n 0000065366 00000 n 0000065432 00000 n 0000065463 00000 n 0000065755 00000 n 0000067054 00000 n 0000065830 00000 n 0000068114 00000 n 0000067459 00000 n 0000067630 00000 n 0000067751 00000 n 0000067872 00000 n 0000067993 00000 n 0000068235 00000 n 0000068351 00000 n 0000068538 00000 n 0000068570 00000 n 0000069468 00000 n 0000069715 00000 n 0000070958 00000 n 0000098299 00000 n 0000163889 00000 n 0000229479 00000 n 0000295069 00000 n 0000356703 00000 n trailer <<7592BE616E403549899ECDF72B80D9A7>]>> startxref 356872 %%EOF doublecmd-1.1.22/pixmaps/mainicon/dc_128.svg0000644000175000001440000003403114743153644017566 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/dc_192.svg0000644000175000001440000003406714743153644017600 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/dc_256.svg0000644000175000001440000003431014743153644017570 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/dc_48.svg0000644000175000001440000003277214743153644017521 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/dc_96.svg0000644000175000001440000003764214743153644017525 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/info.txt0000644000175000001440000000035014743153644017556 0ustar alexxusersAuthor of the Double Commander icon is Андрей Гудяк (Andryei Gudyak). The source file is dc.ai. SVG files are generated from it. The "colored" directory contains some early versions of the icon with different colors. doublecmd-1.1.22/pixmaps/mainicon/papirus/0000755000175000001440000000000014743153644017547 5ustar alexxusersdoublecmd-1.1.22/pixmaps/mainicon/papirus/doublecmd.ico0000644000175000001440000031611314743153644022206 0ustar alexxusers hv   f00 %@@ (BD (ކ E (  3L3M3M3M3M3M3M3M3M3M3M3M3M3L3M0I0I0I0I1K3M3M1K0I0I0I0I3M3M3M3M3M3M3M3M3M3M3M3ME]3M3ME]3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M0I0IBY3M3MBY0I0I3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M?X>W>W>W>W>W>W>W>W>W>W>W>W@X(0 1+B-D-D-D-D-D-D-D-D-D-D-D-D-D-D-D-D-D-D+C12K{3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2Kz4NӀ3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M4NӀ4NӀ3M)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>*?-D3L3M3M3M3M3M3M3M3M3L-D*?)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M7M3M3M3M3M3M3M3M3M7M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M4N^s3M3M3M3M3M3M3M3M]r4N3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MXm3M3M3M3M3M3M3M3MWl3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M1J3M3M3M3M3M3M3M3M1J3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M1IPb3M3M3M3M3M3M3M3MPb1J3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>)>)>)>)>)>)>)>)>*?Zj3M3M3M3M3M3M3M3MYi*?)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M=U3M3M3M3M3M3M3M3M=U3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M5O3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M5OAX3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MAYVl۪BZ5O3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M5OBZUlۨZiZoݪ\p\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\pYnܩZi( ,233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333332, /3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333/ /KG-B2J3L3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3L2J+BIF/.c2K3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2L/bRA2K3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2LP@-B3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M,C2J3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2K3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>*@.E2L3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2L.E*@)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>*?1J3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M1J*?)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M9L*?2L3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2L*?9L3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MSd.E3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M.ETe3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M:N3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M;O3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M5NTj3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MSi5N3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MG^3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MF^3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2K3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M2K3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M-D3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M-E3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M/G>Q3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M=P/G3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M1J,B)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>,C1J3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>,@Pa3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MO`,@)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>)>3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MBZ3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MC[3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M\q3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M\q3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MC[3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MD\3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M4N3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M4N9R3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M9RE\3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3MD\Vl5O3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M6PVlYmڝRh5O3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M6PRhZnۜUo[qXmE\9R4N3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M4N9RE\XmZpUoUkE[q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\qZpUkEUoYmڝZp[p\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q\q[pZpZnۜUoPNG  IHDR\rf IDATxk\g}߹LMěbP8"bU#jHHmC @"$Hi[x1k}wvg9Ĥ4=c?s~c?3{sfw~KJ=AWx?hvIzIr,V;ϴp7u6Vƍ#^o+޿ȅC~3J?|ݹɖ(*߰k?jԚ 38|o HK4܈z'UTRQRz Z Jm%y'q兮׿7FiV؈/{f$Q41h蘒zsz}ɲZQ}bL^*YCzOScJdQuR .۸[I=R\.]'uSg'pr8_̸F{\`R#^z@Fh}wd #a00F` #a00Frk4VdK+V42OkG4{G>x T*\aWn9$ўt|]vWaEyUy~^MlzkƏek]S вd}?5tURyaNozף4 Zz跟>|WU(8 ˘Rߕq=csgȠuש}Zcuzǻ]9 ÷ c}- j`Jݟr|Zp=dXۛq=BS#V2#xQ[!aGP~Ȱ ;]@57 3=0F` #a00F` #a00FÜ֢ڗЅk߮^^tNZetX7߯#[~*..(:̢鲆=oiGoZ<ף$==65zL 69{5B2̴4aףd Бi7>3z>3i8?pĉTcF'$iIuzDH;ulS'~xs/Wl'=ZXie[A?Mn ?CįVS!?p|Sok^K-z{j˼}WIZRlQok^>iO8Cm@KK8.7.yZԖ \9`Jaּ*#îG126ּJ!\9ʇ*lkWW;8|BR(r\+A*^ W1H0F` #a00F` #a00F` #a00F` #a00F` #a00F` #a00F` #a00F` #a00F` #a00FR;]`^zL#)/s=yŋ/s=Bzy]i`:]Rߕ0ooR5׺#~o1PK\I .}oG~z/|*]ףd8M^>[- 浻"hk;\8y ^5k}{_Hx^hэ755}~Zu=Zr?zg#TG>zSs ɼ #a00F` #a00F` #a0dXǮGh0w *#CGPelHd1#hȰwAC{]@tdCG@  &;_߮C\9"R(֞o}#AkU ?|#[͛\9p32v|󒤶\z34kqp@f= k5}O}JaW\jmCH8S;t@y\&ɓZMOg5!}վlp $qȐ~ l{PO)'Lg.Լ&8I[.Pg>h54jޤ Z7{Zzt6O"uEfߌ]AB_KKxDsS3ܿ3%tS*շ9ΐ\%;g:Tf VrMuJX4^>Rٱ77cS]#uzvѨ"N_$wx,:ph|z#SzCK&qh|z2:xtms)h'v,)}^-Vѩ׾]op78pՊII^#P4hZrhꁷ.j]k,sQfZny|rRRMJ@@".3} *J7 Ⱥ(IGw}h{>K Үݨ[yLRKU`UyC8dL'cQ>;>勻쏌I_5Gy@EZvLKڧٳyDҰfP8%P~f#0 >`QMHټ/rjۑi/k|l$.pIENDB`doublecmd-1.1.22/pixmaps/mainicon/papirus/doublecmd.svg0000644000175000001440000000424514743153644022233 0ustar alexxusers doublecmd-1.1.22/pixmaps/mainicon/papirus/readme.txt0000644000175000001440000000020514743153644021542 0ustar alexxusersPapirus icon theme Version 20171223 License GNU LGPL v3.0 https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/tree/20171223 doublecmd-1.1.22/pixmaps/mainicon/visualelements/0000755000175000001440000000000014743153644021124 5ustar alexxusersdoublecmd-1.1.22/pixmaps/mainicon/visualelements/doublecmd-150x150.png0000644000175000001440000003002714743153644024513 0ustar alexxusersPNG  IHDR<qzTXtRaw profile type exifxY$ Dy ;pt_Y[lZ}LtFT, p;&ؿy?UjMF#?UΈ|XG\x<9Tؖׯ}<}O6@cOOh}?~3윏*u"eŮC_²}+ 'gOK񜒳T"ߥ'P_ e>;9:n餙ngf5[NΛQ$k.t- ג?璞jy'qiN ?woK!8>cżr`3 ϜsI結QQ^C1Ay]}`dR!d-zD  L= HvJ$s-"4qȌLҋ-df+z6Kޥ;)N)04"2De2hc蘚@MUgNF=`ΕWYu5Ϯe{|ʁ?N?r3-Pjͺ Sn+w\3kw)P>Q!I󜑰j")sG5{3|S{n-R0smާT@ 4rNӌ1^Lf=I q&{5 ijm2'܎@;fBA 98̌]}MlRkZ۾g2\V㿖tg@mHQ,յgyq[PT/|v?1j R.jEL3EURFq`9}ıS ڔ51Z, ._<]Ƣaj_I͚pY"b쯤9h%ǧZ$Qт{vӬܖeLe9 BݘWڣ`Hf6dҌT_`G;\~ڦ :/4H)p KV7߫5]{5Env,[:c\v0CP1KZ} mkw txD £k1 vm6M|Eƥ>L`#zL 2yY6ƾb8بD2!dt?YƤ9tN\!@ZFtUI!&65J6\wcL2-&Z#bNhhų#pf[6o+"}ptF;jK!yz3 TxcIQRgpϚ" P)3 GFܲ²pla< dB19[ބnv@=p1͂KESlValv_=<>?kk+:c0J>JQjpv AmeU! tm_J+&}'%+4i:!K0T6|uv- V1fW:kWK(tRBouKYFW]P\xhٲHtg^DzJTvhoL(*>45Q)aK'3y|Cy8dW;IY>w !s  %b`@cs`T䀖lql}Q+7}njc>Uw;:y+);!ya݀cb Oq"kD h7>@]"9۠/bO wD m3&@DӠ0QGDĂ0#OOE@8ThXtDuQ@\ސvf>Ҁa(<Yu>܍XH)aQ#T]')wYfB!W>5 ]T:y{?rq%t#bJEgRACtk^8ӊ{ nUGE5 t*&{5c3BǶ 6~xS:zҎ[ n5NSVH"w mᛁM8yw8LW"'2MzIףH,3ULw &Kh7(pfI4l8^]/a^G9 q*Ƈ7j̈́O4`9},\zo"iCR3#}^|0!2Z^0`bEl$cD{:RqJMFf`"^oqu }ļz@AIG熳83Cidw) M + 9M2-x6u 2P7L'!?^b&_܍ncX~^NS]ٴAg#҃:[{_E Hv"$\oDة<~1xT2p&  AN,pb_LUUuw֪YDx.KnuNu+P-fߒn╟ds„;J9vO0`2bBqb|yAΖ/|ɖ&!Qz8?|0$R MH a xy, [UY&ɤ-⁃cMYHmCtΠuA{w@/n+, iCCPICC profilex}=H@_SR*vqP,8J`Zu0 4$).kŪ "%/)=BTkP5Hcb6*^! ~D1 1SO3_.ʳ9zH @bKGD pHYsctIME 5݄bIDATxyuƿsowuь4  F rbL)\)\$.lS,.*bCRۄWNl%8X d2FH6e7o{O~OohF ZUݷ{                  |h&s  0[FaM` X˵ {0x'k#2QZ&>n;`oѵf04Em5"+9#39׵fҙb03PY, D"T6Htmt lѺv>/:6>։}_ C3[GF 5[ 鏞H+_mtvih(~\0jVmlju߯>XL6/}}­Y1 ͌elc6n%F|?Qu?阳{\y.QC_FdrD8Gս۲?hiHay{E84Ƿ]:W~-seF%nimL3)Ehe8ۉ %Y[-9Mڈ.Ӏ>[*)M03@CNDPL 44(SBdU1Yf &Qa c4$*~,:NZv탉/yfq(6׆H(\RpT$Z&ÌX֢b,*q<4-YsCzN-zDS.wիW :8Wg/u;;J&U 30<7xC !j$K DtBEe[rhP B8{Eyy)JH\j7HVxv\FV^'d Gt\jb"sG}B-:^"D>m\ز M )u|0Q6y?@ poGL[~.ڿ롯E+TT(쎯bx 5#Xj_H0|+BT:#1* "!چew=@31⪖cT|.o|ֶ#cLumDX %Rk>~أW5ˇ! q=K&'XCSD&:Tq3k`X8*'uK_B09BUuԋA|^('$ Ccj:Kf5#}߇ C7рכ3A+ieН== в24JfG>ls9HiEub`0䇸辇=fk"* ckb(ډ|`F ~e#ceHfϱ]$D,#, !21LK.O|2흇pӜnvM|p.()0.LYk' Fwk) B@2~ZHY~#Q ՄNTk,,+Xad<֍x/n꫰cגzR~sj̏<ڝ>j9UqW\vy MeJ] SHsz^X'*?_4r4Z.: 9WJif{P>u@`- p#@4O}~h/y 4&7cBSDJ!j&]፻or!p1]"k]׋4ju Gۢ&M^h1AD 54} 7Ti<|/?iVbW^M Lne @1dӞ A@ $V")d:JJSQQV[ݵc+*}POjXx]^3L\Bq_%RpMZZ#l#:yEBL'?6i@ݟaP@qhǁ4ⳞuMC(WHNYT ؤ S7l]}C YuJ+FAaVCvҩ]EA4]ۧLkEI̳D8; 3>(@!b(ϛ*Įi" }թ@P /)j|ڇʶ7 Sby&uF,~.Eq/!Bni/cAY)`V[aB8lL\ȇޥW"9)G῵MAP~#Sߋ+>YdflaGݦ"Q1#o,JݽMk^|IX8S4sHσ{߇G#0A ߍ;د-0[x`1e1NM+N):dAH*3؄St\p}(6\\,:as#eQ2cX\t :MoOE%C>8<}¿Onz^V>{ όru*ape8S\`1ļ/?@yq#wSҊw ӦԻHcQ`D%FL5bŔvQɱ)W[oY|`1X"{m~'iB|-Q6X}՚h  ,(б/>i1m+Ca?Xh`+Tz\!^TB9,l#l%yD OM+84Qz[["RDP8hEalqq5Q-r ~!dq>c"+Jù\s5W9XcLn(Jgc?}_"q H)BTwތ!^s3&8cìvnBVGƄSJ+Brx?69w͏v k|+ރ&GEMѧp (Brp/^/DXط?JMޛŕ͏;͏|6ffUC~~t8QTl߻ j!ca`X|Zyk(܆{q;Fr&k뢶" [R/`뒥STacQ޴+CCS'QMjߪ[VK;:/Mt] D!:NJ/BGS9JM1 Zp⾃'z+AQgY 7ܚ1;::fq13;~F{O8ćn3=ZsP`(&XLt4iwSVieyMb2Obƨ탣';Q9`t?b9юQV "Z$%}',5Xfa'r.dS >Y4fV-Q:;W,Xu]J*I!Iۤf$m/`ZD̀L#"gY#$}I x$]LdxoO{ddW˕J=`w"B1djZt,# W#*2Ehqʇoe'gc̤"C2DD*aٗZkT.GMq\[Q/"Bh,Q̊{ǝu6uy{3qLyhaLB @'o=y=g;$q0 Bd 8}1gVuN5⼴S De$a)Pu4 `Mۼ"r_90|:Ӧ(@T &&vFxH8>z/ ֽN5+EJ)N}GSZr8NSʭ~ D8TQNTiqwVrZ(%&X"CNiĀdCos49XyWh*~}enSŞiG^Ȳkn/LXg&5˱a5kk3)}2"hO~_]ZyZCU^F-B: [ V G)\MGΣ75> i*l"0滝sj,qg/pUe25Fa:=7ӽVjƾSV]Mi|fxI^Dj Jw FKbjPU]ȶ|Nhw|$` Ѵ{._3H?;*ts֦ ӓ!2Bͱg*-up_3Qt\c Ѵy.9Er&-ө^u%1xܧ?AVFW+K!,Od:j*@gi*$,8#eֲU { T@)EN'3R>tp֑R\qg3"P\z\Ci)GΠhMQ|bwbWLl)[b֜rҲ&VR6]'9bRReWϠ-úĆ1Jo'JdR$'ikKfhĕ2R.;hnֆED2;4fSFY\ai"Dq1JZmDevHb{RXaډt[~ ӐOɧ!9,Gb Qַa$"ʇS|e22j *{y)y YҜAc;2~`5u4 WMJP@饭=\@(`ZxqHLTwH46Lh,e Qa0& 6Q`o0jöxJLjmǎ"Rl{&O1 ^$N%~:OXEo&[$5M#a@4%l P2qєy*Jӓ~TVTEf10b%vl:9GFa޻> Ec#T?7}t)Mk2-% -~3r.DV(a82/{չ*<HDx 7ZANA. 8&s,ML$޷ #.zIFc!TeqyHAD4 G) Zq%*cۯe71J"uT&+hF^VH" V,Baݦ]MW;%_-DZfF__wzNoXwt0&BE JiUO8_c ~*{w1U#F(xl,!^ɒj4K/P~Gi]7YUR}酦[x٬~:ryFDT"+N/ Cz:QP-2YF"Xy*TUWQnI{0FQV6JR aaѥoٺ\goyza>Bk BbHJul&zGn ^Xj*_]xt4$mSp~y_ "JY&"m"ƒRNc|JAy`x:byށ>~~<蘆 ݴClޯ}j]N@^&ݦÛŅKX돩=^[;׮&8<СC_|>:]M ;%+E.vV7awߐ.OSpg\V| _dۗ>4p,r`vf.^r,s{y#7R=<1r=MOAɨ^r:)Z?h kik3ǡ}M̳(`<á\fi `yi_bu ?1z 9T{P&6ae3? z_+S3c(JRyr3^ %lJebW%.KeӃ"aA9TONkfEF[]^(nVW8#A[ &8 8$ wm`-&-e$BĀյgҪ%CUGEb|47! 8m+Q>#F`ɯ+4Gٰh2IENDB`doublecmd-1.1.22/plugins/0000755000175000001440000000000014743153644014267 5ustar alexxusersdoublecmd-1.1.22/plugins/build.bat0000644000175000001440000000171514743153644016062 0ustar alexxusers@echo off rem Build all plugins rem Do not execute this script directly. rem This script is called from ..\build.bat. rem CD to plugins directory pushd plugins rem WCX plugins lazbuild wcx\base64\src\base64wcx.lpi %DC_ARCH% lazbuild wcx\deb\src\deb.lpi %DC_ARCH% lazbuild wcx\rpm\src\rpm.lpi %DC_ARCH% lazbuild wcx\sevenzip\src\sevenzipwcx.lpi %DC_ARCH% lazbuild wcx\unrar\src\unrar.lpi %DC_ARCH% lazbuild wcx\zip\src\zip.lpi %DC_ARCH% rem WDX plugins lazbuild wdx\rpm_wdx\src\rpm_wdx.lpi %DC_ARCH% lazbuild wdx\deb_wdx\src\deb_wdx.lpi %DC_ARCH% lazbuild wdx\audioinfo\src\AudioInfo.lpi %DC_ARCH% rem WFX plugins lazbuild wfx\ftp\src\ftp.lpi %DC_ARCH% rem WLX plugins lazbuild wlx\wmp\src\wmp.lpi %DC_ARCH% lazbuild wlx\preview\src\preview.lpi %DC_ARCH% lazbuild wlx\richview\src\richview.lpi %DC_ARCH% rem Return from plugins directory popd doublecmd-1.1.22/plugins/build.sh0000755000175000001440000000206314743153644015726 0ustar alexxusers#!/bin/sh set -e # Build all plugins # Do not execute this script directly. # This script is called from ../build.sh. # CD to plugins directory basedir=$(pwd) cd plugins # WCX plugins $lazbuild wcx/base64/src/base64wcx.lpi $DC_ARCH $lazbuild wcx/cpio/src/cpio.lpi $DC_ARCH $lazbuild wcx/deb/src/deb.lpi $DC_ARCH $lazbuild wcx/rpm/src/rpm.lpi $DC_ARCH $lazbuild wcx/unrar/src/unrar.lpi $DC_ARCH $lazbuild wcx/zip/src/Zip.lpi $DC_ARCH # WDX plugins $lazbuild wdx/rpm_wdx/src/rpm_wdx.lpi $DC_ARCH $lazbuild wdx/deb_wdx/src/deb_wdx.lpi $DC_ARCH $lazbuild wdx/audioinfo/src/AudioInfo.lpi $DC_ARCH # WFX plugins $lazbuild wfx/ftp/src/ftp.lpi $DC_ARCH # Don't build under OS X if [ -z $(uname | grep Darwin) ]; then $lazbuild wfx/samba/src/samba.lpi $DC_ARCH # WLX plugins $lazbuild wlx/WlxMplayer/src/wlxMplayer.lpi $DC_ARCH else # WLX plugins $lazbuild wlx/MacPreview/src/MacPreview.lpi $DC_ARCH fi # DSX plugins $lazbuild dsx/DSXLocate/src/DSXLocate.lpi $DC_ARCH # Return from plugins directory cd $basedir doublecmd-1.1.22/plugins/dsx/0000755000175000001440000000000014743153644015065 5ustar alexxusersdoublecmd-1.1.22/plugins/dsx/DSXLocate/0000755000175000001440000000000014743153644016653 5ustar alexxusersdoublecmd-1.1.22/plugins/dsx/DSXLocate/src/0000755000175000001440000000000014743153644017442 5ustar alexxusersdoublecmd-1.1.22/plugins/dsx/DSXLocate/src/DSXLocate.lpi0000644000175000001440000000772214743153644021746 0ustar alexxusers <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="DSXLocate plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2012 Koblov Alexander" ProductVersion=""/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../dsxlocate.dsx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <Units Count="2"> <Unit0> <Filename Value="DSXLocate.lpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="un_process.pas"/> <IsPartOfProject Value="True"/> </Unit1> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../dsxlocate.dsx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </CONFIG> ����������������������������������������������doublecmd-1.1.22/plugins/dsx/DSXLocate/src/DSXLocate.lpr��������������������������������������������0000644�0001750�0000144�00000012010�14743153644�021741� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ { DSXLocate ------------------------------------------------------------------------- This is DSX (Search) plugin for Double Commander. Plugin use locate and it's database for searching. Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) The original class of TExProcess used in plugin was written by Anton Rjeshevsky. 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 } library DSXLocate; {$mode objfpc}{$H+} {$include calling.inc} uses Classes, SysUtils, DsxPlugin, un_process; var List: TStringList; LocatePath: String; type { TPlugInfo } TPlugInfo = class private FProcess: TExProcess; FAddProc: TSAddFileProc; FUpdateProc: TSUpdateStatusProc; FSearchRec: TDsxSearchRecord; FilesScanned: Integer; public PluginNr: Integer; //--------------------- constructor Create(Nr: Integer); procedure SetProcs(AddProc: TSAddFileProc; UpdateProc: TSUpdateStatusProc); procedure SetDefs(pSearchRec: PDsxSearchRecord); destructor Destroy; override; //--------------------- procedure Start; procedure Stop; procedure OnReadLn(str: String); end; constructor TPlugInfo.Create(Nr: Integer); begin PluginNr := Nr; FProcess := nil; end; procedure TPlugInfo.SetProcs(AddProc: TSAddFileProc; UpdateProc: TSUpdateStatusProc); begin FAddProc := AddProc; FUpdateProc := UpdateProc; end; procedure TPlugInfo.SetDefs(pSearchRec: PDsxSearchRecord); begin FSearchRec := pSearchRec^; end; destructor TPlugInfo.Destroy; begin if Assigned(FProcess) then FreeAndNil(FProcess); inherited Destroy; end; procedure TPlugInfo.Start; var sSearch: String; begin FilesScanned := 0; if Assigned(FProcess) then FreeAndNil(FProcess); FProcess := TExProcess.Create; FProcess.OnReadLn := @OnReadLn; with FSearchRec do begin // TProcess doesn't support passing parameters other than quoted in "". // Adapt this code when this changes. sSearch := String(StartPath); if sSearch <> '' then begin // Search in given start path and in subdirectories. sSearch := '"' + IncludeTrailingPathDelimiter(sSearch) + String(FileMask) + '" ' + '"' + IncludeTrailingPathDelimiter(sSearch) + '*' + PathDelim + String(FileMask) + '"'; end else sSearch := '"' + String(FileMask) + '"'; end; if LocatePath <> '' then FProcess.SetCmdLine(LocatePath + ' ' + sSearch); FProcess.Execute; end; procedure TPlugInfo.Stop; begin if Assigned(FProcess) then begin FProcess.Stop; FreeAndNil(FProcess); end; end; procedure TPlugInfo.OnReadLn(str: String); begin if str <> '' then Inc(FilesScanned); FAddProc(PluginNr, PChar(str)); FUpdateProc(PluginNr, PChar(str), FilesScanned); end; {Main --------------------------------------------------------------------------------} function Init(dps: PDsxDefaultParamStruct; pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): Integer; dcpcall; var i: Integer; begin if not assigned(List) then List := TStringList.Create; I := List.Count; List.AddObject(IntToStr(I), TPlugInfo.Create(I)); TPlugInfo(List.Objects[I]).SetProcs(pAddFileProc, pUpdateStatus); Result := I; end; procedure StartSearch(FPluginNr: Integer; pSearchRecRec: PDsxSearchRecord); dcpcall; begin TPlugInfo(List.Objects[FPluginNr]).SetDefs(pSearchRecRec); TPlugInfo(List.Objects[FPluginNr]).Start; end; procedure StopSearch(FPluginNr: Integer); dcpcall; begin TPlugInfo(List.Objects[FPluginNr]).Stop; end; procedure Finalize(FPluginNr: Integer); dcpcall; begin if not Assigned(List) then exit; if (FPluginNr > List.Count) or (FPluginNr < 0) or (List.Count = 0) then exit; //Destroy PlugInfo Item № TPlugInfo(List.Objects[FPluginNr]).Free; List.Delete(FPluginNr); if List.Count = 0 then FreeAndNil(List); end; exports Init, StartSearch, StopSearch, Finalize; type Tx = class procedure OnReadLnWhich(str: String); end; procedure Tx.OnReadLnWhich(str: String); begin if str <> '' then begin LocatePath := str; //WriteLn('PLUGIN: locate found in '+str); end; end; var Pr: TExProcess; x: TX; {$R *.res} begin pr := TExProcess.Create('which locate'); x := Tx.Create; pr.OnReadLn := @x.OnReadLnWhich; pr.Execute; pr.Free; x.Free; {$IFDEF UNIX} if LocatePath = '' then Writeln('DSXLocate: Locate utility not found.'); {$ENDIF} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/dsx/DSXLocate/src/un_process.pas�������������������������������������������0000644�0001750�0000144�00000004444�14743153644�022335� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{$mode delphi} {$longstrings on} unit un_process; interface uses process, Math, SysUtils; type TOnReadLn = procedure(str: String) of object; { TExProcess } TExProcess = class protected p: TProcess; s: String; FStop: Boolean; function _GetExitStatus(): Integer; public OnReadLn: TOnReadLn; constructor Create(commandline: String = ''); procedure Execute; procedure Stop; procedure SetCmdLine(commandline: String); destructor Destroy; override; property ExitStatus: Integer read _GetExitStatus; end; implementation const buf_len = 3000; { TExProcess } function TExProcess._GetExitStatus(): Integer; begin Result := p.ExitStatus; end; constructor TExProcess.Create(commandline: String = ''); begin s := ''; p := TProcess.Create(nil); p.CommandLine := commandline; p.Options := [poUsePipes, poNoConsole, poWaitOnExit]; end; procedure TExProcess.Execute; var buf: String; i, j: Integer; begin try p.Execute; repeat if FStop then exit; SetLength(buf, buf_len); SetLength(buf, p.output.Read(buf[1], length(buf))); //waits for the process output // cut the incoming stream to lines: s := s + buf; //add to the accumulator repeat //detect the line breaks and cut. i := Pos(#13, s); j := Pos(#10, s); if i = 0 then i := j; if j = 0 then j := i; if j = 0 then Break; //there are no complete lines yet. if Assigned(OnReadLn) then OnReadLn(Copy(s, 1, min(i, j) - 1)); //return the line without the CR/LF characters s := Copy(s, max(i, j) + 1, length(s) - max(i, j)); //remove the line from accumulator until False; until buf = ''; if s <> '' then if Assigned(OnReadLn) then OnReadLn(s); buf := ''; except {$IFDEF UNIX} on e: Exception do Writeln('DSXLocate error: ', e.Message); {$ENDIF} end; if Assigned(OnReadLn) then OnReadLn(buf); //Empty line to notify DC about search process finish end; procedure TExProcess.Stop; begin FStop := True; end; procedure TExProcess.SetCmdLine(commandline: String); begin p.CommandLine := commandline; end; destructor TExProcess.Destroy; begin FreeAndNil(p); inherited Destroy; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/dsx/everything/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017251� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/dsx/everything/src/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020040� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/dsx/everything/src/EverythingDsx.lpi���������������������������������������0000644�0001750�0000144�00000007773�14743153644�023367� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="EverythingDsx"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <i18n> <EnableI18N LFM="False"/> </i18n> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\everything.dsx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <TrashVariables Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <HostApplicationFilename Value="R:\Temp\doublecmd\doublecmd.exe"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <HostApplicationFilename Value="R:\Temp\doublecmd\doublecmd.exe"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> </RequiredPackages> <Units Count="2"> <Unit0> <Filename Value="EverythingDsx.lpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="everything.pas"/> <IsPartOfProject Value="True"/> </Unit1> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\everything.dsx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> �����doublecmd-1.1.22/plugins/dsx/everything/src/EverythingDsx.lpr���������������������������������������0000644�0001750�0000144�00000001723�14743153644�023365� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library EverythingDsx; {$mode objfpc}{$H+} uses Classes, Everything, DsxPlugin, DCConvertEncoding; threadvar AddFileProc: TSAddFileProc; procedure FoundCallback(FileName: PWideChar); var S: String; begin S:= CeUtf16ToUtf8(UnicodeString(FileName)); AddFileProc(0, PAnsiChar(S)); end; function Init(dps: PDsxDefaultParamStruct; pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): Integer; stdcall; begin AddFileProc:= pAddFileProc; end; procedure StartSearch(FPluginNr: Integer; pSearchRecRec: PDsxSearchRecord); stdcall; var Flags: Integer = 0; begin if pSearchRecRec^.CaseSensitive then Flags:= Flags or EVERYTHING_IPC_MATCHCASE; Start(pSearchRecRec^.FileMask, Flags, @FoundCallback); end; procedure StopSearch(FPluginNr: Integer); stdcall; begin end; procedure Finalize(FPluginNr: Integer); stdcall; begin end; exports Init, StartSearch, StopSearch, Finalize; begin end. ���������������������������������������������doublecmd-1.1.22/plugins/dsx/everything/src/everything.pas������������������������������������������0000644�0001750�0000144�00000021645�14743153644�022741� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Everything search engine interface via IPC Copyright (C) 2017 Alexander Koblov (alexx2000@mail.ru) Based on Everything command line interface source Copyright (C) 2016 David Carpenter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } unit everything; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Windows; const COPYDATA_IPCTEST_QUERYCOMPLETEW = 0; MSGFLT_RESET = 0; MSGFLT_ALLOW = 1; MSGFLT_DISALLOW = 2; EVERYTHING_IPC_COPYDATAQUERYW = 2; EVERYTHING_IPC_SEARCH_WNDCLASS = 'EVERYTHING'; EVERYTHING_IPC_WNDCLASS = 'EVERYTHING_TASKBAR_NOTIFICATION'; EVERYTHING_IPC_ALLRESULTS = $FFFFFFFF; // all results EVERYTHING_IPC_FOLDER = $00000001; // The item is a folder. (its a file if not set) EVERYTHING_IPC_DRIVE = $00000002; // The folder is a drive. Path will be an empty string. // search flags for querys EVERYTHING_IPC_MATCHCASE = $00000001; // match case EVERYTHING_IPC_REGEX = $00000008; // enable regex type PChangeFilterStruct = ^TChangeFilterStruct; TChangeFilterStruct = record cbSize: DWORD; ExtStatus: DWORD; end; {$push}{$packrecords 1} TEVERYTHING_IPC_QUERYW = record // the window that will receive the new results. reply_hwnd: HWND; // the value to set the dwData member in the COPYDATASTRUCT struct // sent by Everything when the query is complete. reply_copydata_message: ULONG_PTR; // search flags (see EVERYTHING_MATCHCASE | EVERYTHING_MATCHWHOLEWORD | EVERYTHING_MATCHPATH) search_flags: DWORD; // only return results after 'offset' results (0 to return the first result) // useful for scrollable lists offset: DWORD; // the number of results to return // zero to return no results // EVERYTHING_IPC_ALLRESULTS to return ALL results max_results: DWORD; // null terminated string. arbitrary sized search_string buffer. search_string: WCHAR; end; PEVERYTHING_IPC_ITEMW = ^TEVERYTHING_IPC_ITEMW; TEVERYTHING_IPC_ITEMW = record // item flags flags: DWORD; // The offset of the filename from the beginning of the list structure. // (wchar_t *)((char *)everything_list + everythinglist->name_offset) filename_offset: DWORD; // The offset of the filename from the beginning of the list structure. // (wchar_t *)((char *)everything_list + everythinglist->path_offset) path_offset: DWORD; end; PEVERYTHING_IPC_LISTW = ^TEVERYTHING_IPC_LISTW; TEVERYTHING_IPC_LISTW = record // the total number of folders found. totfolders: DWORD; // the total number of files found. totfiles: DWORD; // totfolders + totfiles totitems: DWORD; // the number of folders available. numfolders: DWORD; // the number of files available. numfiles: DWORD; // the number of items available. numitems: DWORD; // index offset of the first result in the item list. offset: DWORD; // arbitrary sized item list. // use numitems to determine the actual number of items available. items: TEVERYTHING_IPC_ITEMW; end; {$pop} type TFoundCallback = procedure(FileName: PWideChar); var ChangeWindowMessageFilterEx: function(hWnd: HWND; message: UINT; action: DWORD; filter: PChangeFilterStruct): BOOL; stdcall; procedure Start(FileMask: String; Flags: Integer; pr: TFoundCallback); implementation function SendQuery(hwnd: HWND; num: DWORD; search_string: PWideChar; search_flags: integer): Boolean; var query: ^TEVERYTHING_IPC_QUERYW; len: Int32; size: Int32; everything_hwnd: HWND; cds: COPYDATASTRUCT; begin everything_hwnd:= FindWindow(EVERYTHING_IPC_WNDCLASS, nil); if (everything_hwnd <> 0) then begin len := StrLen(search_string); size := SizeOf(TEVERYTHING_IPC_QUERYW) - SizeOf(WideChar) + len * SizeOf(WideChar) + SizeOf(WideChar); query := GetMem(size); if Assigned(query) then begin query^.offset := 0; query^.max_results := num; query^.reply_copydata_message := COPYDATA_IPCTEST_QUERYCOMPLETEW; query^.search_flags := search_flags; query^.reply_hwnd := hwnd; StrLCopy(@query^.search_string, search_string, len); cds.cbData := size; cds.dwData := EVERYTHING_IPC_COPYDATAQUERYW; cds.lpData := query; if (SendMessage(everything_hwnd, WM_COPYDATA, WPARAM(hwnd), LPARAM(@cds)) <> 0) then begin //HeapFree(GetProcessHeap(),0,query); //return 1; REsult:= True; end else begin //write(L"Everything IPC service not running.\n"); end; FreeMem(query); end; end; Result:= False; end; function EVERYTHING_IPC_ITEMPATHW(list: PEVERYTHING_IPC_LISTW; item: PEVERYTHING_IPC_ITEMW): PWideChar; begin Result:= PWideChar(PByte(list) + item^.path_offset); end; function EVERYTHING_IPC_ITEMFILENAMEW(list: PEVERYTHING_IPC_LISTW; item: PEVERYTHING_IPC_ITEMW): PWideChar; begin Result:= PWideChar(PByte(list) + item^.filename_offset); end; procedure listresultsW(hwnd2: HWND; list: PEVERYTHING_IPC_LISTW); var I: Integer; Item: PEVERYTHING_IPC_ITEMW; CallB: TFoundCallback; Result: PWideChar; Res: UnicodeString; begin CallB:= TFoundCallback(GetWindowLongPtr(hwnd2, GWL_USERDATA)); for i:=0 to list^.numitems - 1 do begin Item:= PEVERYTHING_IPC_ITEMW(@list^.items) + i; if (Item^.flags and EVERYTHING_IPC_DRIVE) <> 0 then begin //WriteLn(WideString(EVERYTHING_IPC_ITEMFILENAMEW(list, Item))); Result:= EVERYTHING_IPC_ITEMFILENAMEW(list, Item); end else begin //WriteLn(WideString(EVERYTHING_IPC_ITEMPATHW(list, Item))); //WriteLn(WideString(EVERYTHING_IPC_ITEMFILENAMEW(list, Item))); Res:= UnicodeString(EVERYTHING_IPC_ITEMPATHW(list, Item)) + PathDelim + UnicodeString(EVERYTHING_IPC_ITEMFILENAMEW(list, Item)); Result:= PWideChar(Res);//EVERYTHING_IPC_ITEMFILENAMEW(list, Item); end; CallB(REsult); end; CallB(nil); PostQuitMessage(0); end; function window_proc(hwnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var cds: PCOPYDATASTRUCT; begin case msg of WM_COPYDATA: begin cds := PCOPYDATASTRUCT(lParam); if cds^.dwData = COPYDATA_IPCTEST_QUERYCOMPLETEW then begin listresultsW(hwnd, PEVERYTHING_IPC_LISTW(cds^.lpData)); Exit(1); end; end; end; Result:= DefWindowProc(hwnd, msg, wParam, lParam); end; procedure Start(FileMask: String; Flags: Integer; pr: TFoundCallback); var wcex: WNDCLASSEX; hwnd2: HWND; HH: HMODULE; lpMsg: TMsg; begin ZeroMemory(@wcex, SizeOf(wcex)); wcex.cbSize := sizeof(wcex); wcex.hInstance := System.HINSTANCE;; wcex.lpfnWndProc := @window_proc; wcex.lpszClassName := 'IPCTEST'; if (RegisterClassEx(@wcex) = 0) then begin WriteLn('failed to register IPCTEST window class'); end; hwnd2 := CreateWindow( 'IPCTEST', '', 0, 0,0,0,0, 0,0,HINSTANCE,nil); HH:= LoadLibrary('user32.dll'); Pointer(ChangeWindowMessageFilterEx) := GetProcAddress(HH, 'ChangeWindowMessageFilterEx'); ChangeWindowMessageFilterEx(hwnd2, WM_COPYDATA, MSGFLT_ALLOW, nil); SetWindowLongPtr(hwnd2, GWL_USERDATA, LONG_PTR(pr)); sendquery(hwnd2,EVERYTHING_IPC_ALLRESULTS,PWideChar(WideString(FileMask)), Flags); while (True) do begin if (PeekMessage(lpmsg, 0,0,0,0)) then begin if not GetMessage(lpmsg,0,0,0) then Exit; // let windows handle it. TranslateMessage(lpmsg); DispatchMessage(lpmsg); end else begin WaitMessage(); end; end; end; end. �������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/�����������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015070� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/base64/����������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016154� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/base64/src/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016743� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/base64/src/base64buf.pas�����������������������������������������������0000644�0001750�0000144�00000004000�14743153644�021223� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Base64Buf; {$mode delphi} interface uses Classes, SysUtils, Base64, BufStream; type { TWriteBufStreamEx } TWriteBufStreamEx = class(TWriteBufStream) private FPosition: Int64; public function Write(const Buffer; Count: Longint): Longint; override; end; { TBase64EncodingStreamEx } TBase64EncodingStreamEx = class(TBase64EncodingStream) private FStream: TStream; public constructor Create(ASource : TStream); reintroduce; destructor Destroy; override; end; { TBase64DecodingStreamEx } TBase64DecodingStreamEx = class(TBase64DecodingStream) private FStream: TStream; public constructor Create(ASource : TStream); reintroduce; overload; constructor Create(ASource: TStream; AMode: TBase64DecodingMode); reintroduce; overload; destructor Destroy; override; end; implementation const BUFFER_SIZE = 32768; { TWriteBufStreamEx } function TWriteBufStreamEx.Write(const Buffer; Count: Longint): Longint; const LINE_LENGTH = 76; EOL = String(LineEnding); begin if (FPosition + Count) > LINE_LENGTH then begin FPosition:= 0; inherited Write(EOL[1], Length(EOL)); end; Inc(FPosition, Count); Result:= inherited Write(Buffer, Count); end; { TBase64DecodingStreamEx } constructor TBase64DecodingStreamEx.Create(ASource: TStream); begin FStream:= TReadBufStream.Create(ASource, BUFFER_SIZE); inherited Create(FStream); end; constructor TBase64DecodingStreamEx.Create(ASource: TStream; AMode: TBase64DecodingMode); begin Create(ASource); Mode:= AMode; end; destructor TBase64DecodingStreamEx.Destroy; begin inherited Destroy; FStream.Free; end; { TBase64EncodingStreamEx } constructor TBase64EncodingStreamEx.Create(ASource: TStream); begin FStream:= TWriteBufStreamEx.Create(ASource, BUFFER_SIZE); inherited Create(FStream); end; destructor TBase64EncodingStreamEx.Destroy; begin inherited Destroy; FStream.Free; end; end. doublecmd-1.1.22/plugins/wcx/base64/src/base64func.pas����������������������������������������������0000644�0001750�0000144�00000024022�14743153644�021410� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Base64 archiver plugin Copyright (C) 2022-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } unit Base64Func; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, WcxPlugin; { Mandatory functions } function OpenArchiveW(var ArchiveData: TOpenArchiveDataW): TArcHandle; dcpcall; export; function ReadHeaderExW(hArcData: TArcHandle; var HeaderData: THeaderDataExW): Integer; dcpcall; export; function ProcessFileW(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PWideChar): Integer; dcpcall; export; function CloseArchive (hArcData: TArcHandle): Integer; dcpcall; export; procedure SetChangeVolProcW(hArcData: TArcHandle; pChangeVolProc: TChangeVolProcW); dcpcall; export; procedure SetProcessDataProcW(hArcData: TArcHandle; pProcessDataProc: TProcessDataProcW); dcpcall; export; { Optional functions } function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer; dcpcall; export; function GetBackgroundFlags: Integer; dcpcall; export; function GetPackerCaps: Integer; dcpcall; export; implementation uses SysUtils, Base64Buf, NullStream, LazFileUtils, DCConvertEncoding, DCOSUtils, DCStrUtils, DCClassesUtf8, MimeInLn; const BUFFER_SIZE = 32768; MIME_VERSION = 'MIME-VERSION:'; CONTENT_TYPE = 'CONTENT-TYPE:'; CONTENT_DISPOSITION = 'CONTENT-DISPOSITION:'; CONTENT_TRANSFER_ENCODING = 'CONTENT-TRANSFER-ENCODING:'; MIME_HEADER = 'MIME-Version: 1.0' + LineEnding + 'Content-Type: application/octet-stream; name="%s"' + LineEnding + 'Content-Transfer-Encoding: base64' + LineEnding + 'Content-Disposition: attachment; filename="%s"' + LineEnding + LineEnding; threadvar gProcessDataProcW : TProcessDataProcW; type TRecord = class Count: Integer; FileName: String; Stream: TFileStreamEx; ProcessDataProcW: TProcessDataProcW; end; function ParseHeader(var AHandle: TRecord): Boolean; var P, ALength: Integer; S, AText, ABuffer: String; begin SetLength(ABuffer, 4096); ALength:= AHandle.Stream.Read(ABuffer[1], Length(ABuffer)); if ALength > 0 then begin SetLength(ABuffer, ALength); AText:= Copy(ABuffer, 1, Length(MIME_VERSION)); // No MIME-header, assume raw Base64 data if CompareStr(MIME_VERSION, UpperCase(AText)) <> 0 then AHandle.Stream.Seek(0, soBeginning) else begin P:= 1; while GetNextLine(ABuffer, AText, P) do begin // Base64 data starts after empty line if (Length(AText) = 0) then begin AHandle.Stream.Seek(P - 1, soBeginning); Break; end; S:= UpperCase(AText); if StrBegins(S, CONTENT_TYPE) then begin S:= SeparateRight(S, ':'); S:= Trim(SeparateLeft(S, ';')); if (S = 'MESSAGE/PARTIAL') then Exit(False); AHandle.FileName:= GetParameter(AText, 'name'); AHandle.FileName:= ExtractFileName(InlineDecodeEx(AHandle.FileName)); end else if StrBegins(S, CONTENT_TRANSFER_ENCODING) then begin S:= Trim(SeparateRight(S, ':')); if (S <> 'BASE64') then Exit(False); end else if StrBegins(S, CONTENT_DISPOSITION) then begin S:= SeparateRight(S, ':'); S:= Trim(SeparateLeft(S, ';')); if (S <> 'ATTACHMENT') then Exit(False); AHandle.FileName:= GetParameter(AText, 'filename'); AHandle.FileName:= ExtractFileName(InlineDecodeEx(AHandle.FileName)); end; end; end; end; Result:= True; end; { Mandatory functions } function OpenArchiveW(var ArchiveData: TOpenArchiveDataW): TArcHandle; dcpcall; export; var AHandle: TRecord absolute Result; begin AHandle:= TRecord.Create; try AHandle.Stream:= TFileStreamEx.Create(CeUtf16ToUtf8(ArchiveData.ArcName), fmOpenRead or fmShareDenyNone); if not ParseHeader(AHandle) then begin AHandle.Stream.Free; FreeAndNil(AHandle); ArchiveData.OpenResult:= E_UNKNOWN_FORMAT; end else if Length(AHandle.FileName) = 0 then begin AHandle.FileName:= ExtractFileNameOnly(AHandle.Stream.FileName); end; except AHandle.Stream.Free; FreeAndNil(AHandle); ArchiveData.OpenResult:= E_EOPEN; end; end; function ReadHeaderExW(hArcData: TArcHandle; var HeaderData: THeaderDataExW): Integer; dcpcall; export; var PackSize: Int64; FileName: UnicodeString; AHandle: TRecord absolute hArcData; begin if AHandle.Count > 0 then Result:= E_END_ARCHIVE else begin Result := E_SUCCESS; FileName:= CeUtf8ToUtf16(AHandle.FileName); FillChar(HeaderData, SizeOf(AHandle.Count), 0); HeaderData.UnpSize:= $FFFFFFFE; HeaderData.UnpSizeHigh:= $FFFFFFFF; PackSize:= AHandle.Stream.Size - AHandle.Stream.Position; HeaderData.PackSize:= Int64Rec(PackSize).Lo; HeaderData.PackSizeHigh:= Int64Rec(PackSize).Hi; StrPLCopy(HeaderData.FileName, FileName, SizeOf(HeaderData.FileName) - 1); end; end; function ProcessFileW(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PWideChar) : Integer; dcpcall; export; var ARead: Integer; ABuffer: TBytes; AFileSize: Int64; fsOutput: TStream; APercent: Integer; ATargetName: String; AStream: TBase64DecodingStreamEx; AHandle: TRecord absolute hArcData; begin case Operation of PK_TEST, PK_EXTRACT: begin try if Operation = PK_TEST then fsOutput:= TNullStream.Create else begin ATargetName:= CeUtf16ToUtf8(DestPath) + CeUtf16ToUtf8(DestName); fsOutput:= TFileStreamEx.Create(ATargetName, fmCreate); end; try AStream:= TBase64DecodingStreamEx.Create(AHandle.Stream); try AFileSize:= AHandle.Stream.Size; SetLength(ABuffer, BUFFER_SIZE); repeat ARead:= AStream.Read(ABuffer[0], BUFFER_SIZE); if ARead > 0 then begin fsOutput.WriteBuffer(ABuffer[0], ARead); APercent:= (AStream.Source.Position * 100) div AFileSize; if (AHandle.ProcessDataProcW(DestName, -APercent) = 0) then begin FreeAndNil(fsOutput); if Operation = PK_EXTRACT then mbDeleteFile(ATargetName); Exit(E_EABORTED); end; end; until ARead < BUFFER_SIZE; finally AStream.Free; end; finally fsOutput.Free; end; except Exit(E_ECREATE); end; end; PK_SKIP: begin end; end; Inc(AHandle.Count); Result:= E_SUCCESS; end; function CloseArchive (hArcData: TArcHandle): Integer; dcpcall; export; var AHandle: TRecord absolute hArcData; begin Result := E_SUCCESS; AHandle.Stream.Free; AHandle.Free; end; procedure SetChangeVolProcW(hArcData: TArcHandle; pChangeVolProc: TChangeVolProcW); dcpcall; export; begin end; procedure SetProcessDataProcW(hArcData: TArcHandle; pProcessDataProc: TProcessDataProcW); dcpcall; export; var AHandle: TRecord absolute hArcData; begin if (hArcData <> wcxInvalidHandle) then AHandle.ProcessDataProcW := pProcessDataProc else begin gProcessDataProcW := pProcessDataProc; end; end; { Optional functions } function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer; dcpcall; export; var ARead: Integer; ABuffer: TBytes; AHeader: String; AFileName: String; ATargetName: String; AStream: TBase64EncodingStreamEx; fsInput, fsOutput: TFileStreamEx; begin if (Flags and PK_PACK_MOVE_FILES) <> 0 then begin Exit(E_NOT_SUPPORTED); end; try AFileName:= CeUtf16ToUtf8(AddList); fsInput:= TFileStreamEx.Create(CeUtf16ToUtf8(SrcPath) + AFileName, fmOpenRead or fmShareDenyNone); try ATargetName:= CeUtf16ToUtf8(PackedFile); try fsOutput:= TFileStreamEx.Create(ATargetName, fmCreate); try AFileName:= InlineEncodeEx(AFileName); AHeader:= Format(MIME_HEADER, [AFileName, AFileName]); try fsOutput.WriteBuffer(AHeader[1], Length(AHeader)); AStream:= TBase64EncodingStreamEx.Create(fsOutput); try SetLength(ABuffer, BUFFER_SIZE); repeat ARead:= fsInput.Read(ABuffer[0], BUFFER_SIZE); if ARead > 0 then begin AStream.WriteBuffer(ABuffer[0], ARead); if (gProcessDataProcW(PackedFile, ARead) = 0) then begin FreeAndNil(AStream); FreeAndNil(fsOutput); mbDeleteFile(ATargetName); Exit(E_EABORTED); end; end; until ARead < BUFFER_SIZE; finally AStream.Free; end; except Exit(E_EWRITE); end; finally fsOutput.Free; end; except Exit(E_ECREATE); end; finally fsInput.Free; end; except Exit(E_EOPEN); end; Result:= E_SUCCESS; end; function GetBackgroundFlags: Integer; dcpcall; export; begin Result:= BACKGROUND_UNPACK or BACKGROUND_PACK; end; function GetPackerCaps: Integer; dcpcall; export; begin Result := PK_CAPS_NEW; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/base64/src/base64wcx.lpi�����������������������������������������������0000644�0001750�0000144�00000010544�14743153644�021263� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="Base64Wcx"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="BASE64 WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2022 Alexander Koblov"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\base64.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"/> </Modes> </RunParams> <RequiredPackages Count="2"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> <Item2> <PackageName Value="LazUtils"/> </Item2> </RequiredPackages> <Units Count="3"> <Unit0> <Filename Value="base64wcx.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="Base64Wcx"/> </Unit0> <Unit1> <Filename Value="base64func.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="Base64Func"/> </Unit1> <Unit2> <Filename Value="base64buf.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="Base64Buf"/> </Unit2> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\base64.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="2"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> </CONFIG> ������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/base64/src/base64wcx.lpr�����������������������������������������������0000644�0001750�0000144�00000000554�14743153644�021274� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library Base64Wcx; uses {$IFDEF UNIX} cthreads, {$ENDIF} FPCAdds, SysUtils, Classes, Base64Func; exports { Mandatory } OpenArchiveW, ReadHeaderExW, ProcessFileW, CloseArchive, SetChangeVolProcW, SetProcessDataProcW, { Optional } PackFilesW, GetPackerCaps, GetBackgroundFlags; {$R *.res} begin end. ����������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/base64/src/mimeinln.pas������������������������������������������������0000644�0001750�0000144�00000035465�14743153644�021275� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.001.011 | |==============================================================================| | Content: Inline MIME support procedures and functions | |==============================================================================| | Copyright (c)1999-2017, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2000-2006. | | All Rights Reserved. | |==============================================================================| | Contributor(s): Copyright (C) 2022 Alexander Koblov (alexx2000@mail.ru) | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@abstract(Utilities for inline MIME) Support for Inline MIME encoding and decoding. Used RFC: RFC-2047, RFC-2231 } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} unit MimeInLn; interface uses SysUtils, Classes; type TSpecials = set of AnsiChar; const SpecialChar: TSpecials = ['=', '(', ')', '[', ']', '<', '>', ':', ';', ',', '@', '/', '?', '\', '"', '_']; NonAsciiChar: TSpecials = [#0..#31, #127..#255]; {:Returns a portion of the "Value" string located to the left of the "Delimiter" string. If a delimiter is not found, results is original string.} function SeparateLeft(const Value, Delimiter: string): string; {:Returns the portion of the "Value" string located to the right of the "Delimiter" string. If a delimiter is not found, results is original string.} function SeparateRight(const Value, Delimiter: string): string; {:Returns parameter value from string in format: parameter1="value1"; parameter2=value2} function GetParameter(const Value, Parameter: string): string; {:Fetch string from left of Value string. This function ignore delimitesr inside quotations.} function FetchEx(var Value: string; const Delimiter, Quotation: string): string; {:Decodes mime inline encoding (i.e. in headers).} function InlineDecode(const Value: string): string; {:Encodes string to MIME inline encoding.} function InlineEncode(const Value: string): string; {:Returns @true, if "Value" contains characters which require inline coding.} function NeedInline(const Value: AnsiString): boolean; {:Decodes mime inline encoding similar to @link(InlineDecode), but it checks first that "Value" encoded by inline coding.} function InlineDecodeEx(const Value: string): string; {:Inline MIME encoding similar to @link(InlineEncode), but it checks first that "Value" contains characters which require inline coding.} function InlineEncodeEx(const Value: string): string; implementation uses Base64, LConvEncoding, DCConvertEncoding; {==============================================================================} function UnquoteStr(const Value: string; Quote: Char): string; var n: integer; inq, dq: Boolean; c, cn: char; begin Result := ''; if Value = '' then Exit; if Value = Quote + Quote then Exit; inq := False; dq := False; for n := 1 to Length(Value) do begin c := Value[n]; if n <> Length(Value) then cn := Value[n + 1] else cn := #0; if c = quote then if dq then dq := False else if not inq then inq := True else if cn = quote then begin Result := Result + Quote; dq := True; end else inq := False else Result := Result + c; end; end; {==============================================================================} function FetchEx(var Value: string; const Delimiter, Quotation: string): string; var b: Boolean; begin Result := ''; b := False; while Length(Value) > 0 do begin if b then begin if Pos(Quotation, Value) = 1 then b := False; Result := Result + Value[1]; Delete(Value, 1, 1); end else begin if Pos(Delimiter, Value) = 1 then begin Delete(Value, 1, Length(delimiter)); break; end; b := Pos(Quotation, Value) = 1; Result := Result + Value[1]; Delete(Value, 1, 1); end; end; end; {==============================================================================} function SeparateLeft(const Value, Delimiter: string): string; var x: Integer; begin x := Pos(Delimiter, Value); if x < 1 then Result := Value else Result := Copy(Value, 1, x - 1); end; {==============================================================================} function SeparateRight(const Value, Delimiter: string): string; var x: Integer; begin x := Pos(Delimiter, Value); if x > 0 then x := x + Length(Delimiter) - 1; Result := Copy(Value, x + 1, Length(Value) - x); end; {==============================================================================} function GetParameter(const Value, Parameter: string): string; var s: string; v: string; begin Result := ''; v := Value; while v <> '' do begin s := Trim(FetchEx(v, ';', '"')); if Pos(Uppercase(parameter), Uppercase(s)) = 1 then begin Delete(s, 1, Length(Parameter)); s := Trim(s); if s = '' then Break; if s[1] = '=' then begin Result := Trim(SeparateRight(s, '=')); Result := UnquoteStr(Result, '"'); break; end; end; end; end; {==============================================================================} function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; var x, l, lv: Integer; c: AnsiChar; b: Byte; bad: Boolean; begin lv := Length(Value); SetLength(Result, lv); x := 1; l := 1; while x <= lv do begin c := Value[x]; Inc(x); if c <> Delimiter then begin Result[l] := c; Inc(l); end else if x < lv then begin Case Value[x] Of #13: if (Value[x + 1] = #10) then Inc(x, 2) else Inc(x); #10: if (Value[x + 1] = #13) then Inc(x, 2) else Inc(x); else begin bad := False; Case Value[x] Of '0'..'9': b := (Byte(Value[x]) - 48) Shl 4; 'a'..'f', 'A'..'F': b := ((Byte(Value[x]) And 7) + 9) shl 4; else begin b := 0; bad := True; end; end; Case Value[x + 1] Of '0'..'9': b := b Or (Byte(Value[x + 1]) - 48); 'a'..'f', 'A'..'F': b := b Or ((Byte(Value[x + 1]) And 7) + 9); else bad := True; end; if bad then begin Result[l] := c; Inc(l); end else begin Inc(x, 2); Result[l] := AnsiChar(b); Inc(l); end; end; end; end else break; end; Dec(l); SetLength(Result, l); end; {==============================================================================} function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; begin Result := DecodeTriplet(Value, '='); end; {==============================================================================} function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; Specials: TSpecials): AnsiString; var n, l: Integer; s: AnsiString; c: AnsiChar; begin SetLength(Result, Length(Value) * 3); l := 1; for n := 1 to Length(Value) do begin c := Value[n]; if c in Specials then begin Result[l] := Delimiter; Inc(l); s := IntToHex(Ord(c), 2); Result[l] := s[1]; Inc(l); Result[l] := s[2]; Inc(l); end else begin Result[l] := c; Inc(l); end; end; Dec(l); SetLength(Result, l); end; {==============================================================================} function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; begin Result := EncodeTriplet(Value, '=', ['='] + NonAsciiChar); end; {==============================================================================} function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; begin Result := EncodeTriplet(Value, '=', SpecialChar + NonAsciiChar); end; {==============================================================================} function InlineDecode(const Value: string): string; var s, su, e, v: string; x, y, z, n: Integer; b: Boolean; c: Char; function SearchEndInline(const Value: string; be: Integer): Integer; var n, q: Integer; begin q := 0; Result := 0; for n := be + 2 to Length(Value) - 1 do if Value[n] = '?' then begin Inc(q); if (q > 2) and (Value[n + 1] = '=') then begin Result := n; Break; end; end; end; begin Result := ''; v := Value; x := Pos('=?', v); y := SearchEndInline(v, x); // fix for broken coding // with begin, but not with end. if (x > 0) and (y <= 0) then y := Length(Result); while (y > x) and (x > 0) do begin s := Copy(v, 1, x - 1); if Trim(s) <> '' then Result := Result + s; s := Copy(v, x, y - x + 2); Delete(v, 1, y + 1); su := Copy(s, 3, Length(s) - 4); z := Pos('?', su); if (Length(su) >= (z + 2)) and (su[z + 2] = '?') then begin e := SeparateLeft(Copy(su, 1, z - 1), '*'); c := UpperCase(su)[z + 1]; su := Copy(su, z + 3, Length(su) - z - 2); if c = 'B' then begin s := DecodeStringBase64(su); s := ConvertEncodingToUTF8(s, e, b); if not b then Exit(EmptyStr); end; if c = 'Q' then begin s := ''; for n := 1 to Length(su) do if su[n] = '_' then s := s + ' ' else s := s + su[n]; s := DecodeQuotedPrintable(s); s := ConvertEncodingToUTF8(s, e, b); if not b then Exit(EmptyStr); end; end; Result := Result + s; x := Pos('=?', v); y := SearchEndInline(v, x); end; Result := Result + v; end; {==============================================================================} function InlineEncode(const Value: string): string; var s, s1, e: string; n: Integer; begin s := Value; e := 'UTF-8'; s := EncodeSafeQuotedPrintable(s); s1 := ''; Result := ''; for n := 1 to Length(s) do if s[n] = ' ' then begin s1 := s1 + '_'; if Length(s1) > 32 then begin if Result <> '' then Result := Result + ' '; Result := Result + '=?' + e + '?Q?' + s1 + '?='; s1 := ''; end; end else s1 := s1 + s[n]; if s1 <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + '=?' + e + '?Q?' + s1 + '?='; end; end; {==============================================================================} function NeedInline(const Value: AnsiString): boolean; var n: Integer; begin Result := False; for n := 1 to Length(Value) do if Value[n] in (SpecialChar + NonAsciiChar - ['_']) then begin Result := True; Break; end; end; {==============================================================================} function InlineDecodeEx(const Value: string): string; begin if Pos('=?', Value) > 0 then Result := InlineDecode(Value) else Result := CeSysToUtf8(Value); end; {==============================================================================} function InlineEncodeEx(const Value: string): string; begin if NeedInline(Value) then Result := InlineEncode(Value) else Result := Value; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016022� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/install.txt�������������������������������������������������������0000644�0001750�0000144�00000001026�14743153644�020230� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������How to install RPM plugin: 1. Unzip the rpm.wcx and cpio.wcx to the Totalcmd directory 2. In Total Commander, choose Configuration - Options 3. Open the 'Packer' page 4. Click 'Configure packer extension WCXs 5. type rpm as the extension 6. Click 'new type', and select the rpm.wcx 5. type cpio as the extension 6. Click 'new type', and select the cpio.wcx 7. Click OK What it does: This plugin allow you to browse rpm archives. Mandryka Yurij Brain group http://braingroup.hotmail.ru/wcplugins/ mailto:braingroup@hotmail.ru����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/license.txt�������������������������������������������������������0000644�0001750�0000144�00000002205�14743153644�020204� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RPM plugin v.1.4 for Windows Commander. Copyright (c) 2000..2002 Mandryka Yurij ( Brain Group ) Add some changes for Lazarus and Linux compability Copyright (C) 2007 Koblov Alexander (Alexx2000@mail.ru) This plugin allow you to browse rpm archives with Windows Commander 4.0 or greater. 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 OR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Any questions about plugin can be made via e-mail : braingroup@hotmail.ru and information about plugin can be found on Brain Group web site : http://braingroup.hotmail.ru/wcplugins/ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/��������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016611� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio.cfg������������������������������������������������������0000644�0001750�0000144�00000000546�14743153644�020231� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-$A- -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I- -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\borland\delphi5\Projects\Bpl" -LN"c:\borland\delphi5\Projects\Bpl" ����������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio.dof������������������������������������������������������0000644�0001750�0000144�00000002433�14743153644�020237� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Compiler] A=0 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=0 J=1 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= SearchPath= Packages=VCL50;VCLX50;VCLSMP50;VCLDB50;VCLADO50;ibevnt50;VCLBDE50;VCLDBX50;QRPT50;TEEUI50;TEEDB50;TEE50;DSS50;TEEQR50;VCLIB50;VCLMID50;VCLIE50;INETDB50;INET50;NMFAST50;WEBMID50;dclocx50;dclaxserver50;dcldtree50 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication=e:\delphi\exedpr\wincmd32.exe [Version Info] IncludeVerInfo=1 AutoIncBuild=1 MajorVer=1 MinorVer=0 Release=0 Build=79 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1049 CodePage=1251 [Version Info Keys] CompanyName=Brain group FileDescription=cpio plugin for rpm plugin for Windows Commander FileVersion=1.0.0.79 InternalName=cpio.wcx LegalCopyright=Mandryka Yurij LegalTrademarks= OriginalFilename=cpio.wcx ProductName=cpio plugin for rpm plugin ProductVersion=1.0.0.0 Comments=any questions on braingroup@hotmail.ru �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio.dpr������������������������������������������������������0000644�0001750�0000144�00000001660�14743153644�020255� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** { Add some changes for Lazarus and Linux compability Copyright (C) 2007 Koblov Alexander (Alexx2000@mail.ru) } //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** library cpio; uses SysUtils, Classes, WcxPlugin, cpio_io in 'cpio_io.pas', cpio_def in 'cpio_def.pas', cpio_archive in 'cpio_archive.pas'; exports CloseArchive, GetPackerCaps, OpenArchive, ProcessFile, ReadHeader, SetChangeVolProc, SetProcessDataProc, GetBackgroundFlags, CanYouHandleThisFile; {$R *.res} begin end. ��������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio.lpi������������������������������������������������������0000644�0001750�0000144�00000012140�14743153644�020247� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="CPIO WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2012 Koblov Alexander"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../cpio.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> <MinVersion Minor="2" Valid="True"/> </Item1> </RequiredPackages> <Units Count="4"> <Unit0> <Filename Value="cpio.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="cpio_io.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="cpio_def.pas"/> <IsPartOfProject Value="True"/> </Unit2> <Unit3> <Filename Value="cpio_archive.pas"/> <IsPartOfProject Value="True"/> </Unit3> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../cpio.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> </CONFIG> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio_archive.pas����������������������������������������������0000644�0001750�0000144�00000024062�14743153644�021755� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** { Add some changes for Lazarus and Linux compability Copyright (C) 2007-2009 Koblov Alexander (Alexx2000@mail.ru) } //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** // History // 2001-02-04 Bug: Error Opening rpm file on CD (readonly) // Fix: Add FileMode = 0 before Reset // Who: Oliver Haeger <haeger@inghb.de> // 2001-02-27 Bug: My or Ghisler I don't know : WC incorrectly // work with names in archive started with // "./" or "/" (normal UNIX filenames form) unit cpio_archive; interface {$mode delphi}{$A-,I-} {$include calling.inc} uses Classes, WcxPlugin, cpio_def, cpio_io; type PArchiveRec = ^TArchiveRec; TArchiveRec = record handle_io : THandle; handle_file : file; fname : AnsiString; fdate : Integer; fgEndArchive : Boolean; process_proc : TProcessDataProc; changevol_proc : TChangeVolProc; last_header : CPIO_Header; end;{ArchiveRec} function GetPackerCaps : Integer; dcpcall; export; function GetBackgroundFlags: Integer; dcpcall; export; function OpenArchive(var ArchiveData : TOpenArchiveData) : TArcHandle; dcpcall; export; function CloseArchive(hArcData : TArcHandle) : Integer; dcpcall; export; function ReadHeader(hArcData : TArcHandle; var HeaderData : THeaderData) : Integer; dcpcall; export; function ProcessFile(hArcData : TArcHandle; Operation : Integer; DestPath : PChar; DestName : PChar) : Integer; dcpcall; export; procedure SetProcessDataProc(hArcData : TArcHandle; ProcessDataProc : TProcessDataProc); dcpcall; export; procedure SetChangeVolProc(hArcData : TArcHandle; ChangeVolProc : TChangeVolProc); dcpcall; export; function CanYouHandleThisFile(FileName: PAnsiChar): Boolean; dcpcall; export; implementation uses SysUtils, DCDateTimeUtils, DCBasicTypes, DCFileAttributes, DCOSUtils; function GetPackerCaps: Integer; begin Result := PK_CAPS_MULTIPLE; end; function GetBackgroundFlags: Integer; begin Result := BACKGROUND_UNPACK; end; function OpenArchive(var ArchiveData : TOpenArchiveData) : TArcHandle; var arch : THandle; filename : String; fgError : Boolean; arec : PArchiveRec absolute Result; begin arec := nil; arch := 0; fgError := False; filename := String(ArchiveData.ArcName); arch := FileOpen(filename, fmOpenRead or fmShareDenyNone); if arch = feInvalidHandle then begin fgError := True; end else begin New(arec); with arec^ do begin handle_io := arch; fname := filename; fdate := FileAge(filename); fgEndArchive := False; process_proc := nil; changevol_proc := nil; if fdate = -1 then fdate := 0; end; AssignFile(arec^.handle_file, filename); FileMode := 0; Reset(arec^.handle_file, 1); if IOResult <> 0 then begin fgError := True; end;{ioresult} end;{arch = -1} if fgError then begin if arec <> nil then begin CloseFile(arec^.handle_file); Dispose(arec); end; FileClose(arch); Result := 0; ArchiveData.OpenResult := E_EOPEN end; end; function CloseArchive(hArcData: TArcHandle): Integer; var arec : PArchiveRec absolute hArcData; begin CloseFile(arec^.handle_file); FileClose(arec^.handle_io); Dispose(arec); Result := E_SUCCESS; end; function ReadHeader(hArcData : TArcHandle; var HeaderData : THeaderData): Integer; var header : CPIO_Header; arec : PArchiveRec absolute hArcData; begin Result := E_EREAD; if arec^.fgEndArchive then Result := E_END_ARCHIVE else begin while True do begin if CPIO_ReadHeader(arec^.handle_file, header) then begin if header.filename = 'TRAILER!!!' then begin Result := E_END_ARCHIVE; Break end else begin if header.filesize <> 0 then begin with HeaderData do begin copy_str2buf(TStrBuf(ArcName), arec^.fname); copy_str2buf(TStrBuf(FileName), header.filename); PackSize := header.filesize; UnpSize := header.filesize; FileAttr := UnixToWcxFileAttr(header.mode); FileTime := UnixFileTimeToWcxTime(TUnixFileTime(header.mtime)); end;{with} Result := 0; Break; end else Continue; end;{not end of file "TRAILER!!!"} end{if header readed} else begin Result := E_EREAD; Break; end; end;{while true} arec^.last_header := header; end;{if not end of archive} end; function ProcessFile(hArcData: TArcHandle; Operation: Integer; DestPath: PChar; DestName: PChar): Integer; var cpio_file : file; cpio_name : String; cpio_dir : String; buf : Pointer; buf_size : LongWord; fsize : LongWord; fgReadError : Boolean; fgWriteError: Boolean; fAborted : Boolean; head : CPIO_Header; arec : PArchiveRec absolute hArcData; begin head := arec^.last_header; case Operation of PK_TEST : begin faborted:=false; fsize := head.filesize; buf_size := 65536; GetMem(buf, buf_size); fgReadError := False; while not faborted do begin if fsize < buf_size then Break; BlockRead(arec^.handle_file, buf^, buf_size); if IOResult <> 0 then begin fgReadError := True; Break; end;{if IO error} Dec(fsize, buf_size); if Assigned(arec^.process_proc) then if arec^.process_proc(nil, buf_size)=0 then faborted:=true; end;{while} if not fgReadError and not faborted then begin if fsize <> 0 then begin BlockRead(arec^.handle_file, buf^, fsize); if IOResult <> 0 then fgReadError := True; if Assigned(arec^.process_proc) then arec^.process_proc(nil, fsize); end; end; if faborted then Result:=E_EABORTED else if fgReadError then Result := E_EREAD else begin Result := 0; if arec^.last_header.IsOldHeader then begin if not AlignFilePointer(arec^.handle_file, 2) then Result := E_EREAD; end else if not AlignFilePointer(arec^.handle_file, 4) then Result := E_EREAD; end; FreeMem(buf, 65536); end;{PK_TEST} PK_SKIP : begin Seek(arec^.handle_file, FilePos(arec^.handle_file) + LongInt(head.filesize)); if IOResult = 0 then begin Result := 0; if arec^.last_header.IsOldHeader then begin if not AlignFilePointer(arec^.handle_file, 2) then Result := E_EREAD; end else if not AlignFilePointer(arec^.handle_file, 4) then Result := E_EREAD; end else Result := E_EREAD; end;{PK_SKIP} PK_EXTRACT : begin cpio_name := String(DestName); cpio_dir := ExtractFileDir(cpio_name); if CreateDirectories(cpio_dir) then begin AssignFile(cpio_file, cpio_name); Rewrite(cpio_file, 1); if IOResult <> 0 then Result := E_ECREATE else begin fsize := head.filesize; buf_size := 65536; GetMem(buf, buf_size); fgReadError := False; fgWriteError :=False; fAborted := False; while not fAborted do begin if fsize < buf_size then Break; BlockRead(arec^.handle_file, buf^, buf_size); if IOResult <> 0 then begin fgReadError := True; Break; end;{if IO error} BlockWrite(cpio_file, buf^, buf_size); if ioresult<>0 then begin fgWriteError:=true; break; end; Dec(fsize, buf_size); if Assigned(arec^.process_proc) then if arec^.process_proc(nil, buf_size)=0 then fAborted:=true; end;{while} if not fgReadError then begin if fsize <> 0 then begin BlockRead(arec^.handle_file, buf^, fsize); if IOResult <> 0 then fgReadError := True; BlockWrite(cpio_file, buf^, fsize); if ioresult<>0 then fgWriteError:=true; if Assigned(arec^.process_proc) then if arec^.process_proc(nil, fsize)=0 then fAborted:=true; end; end; if fAborted then Result:= E_EABORTED else if fgWriteError then Result := E_EWRITE else if fgReadError then Result := E_EREAD else begin Result := 0; if arec^.last_header.IsOldHeader then begin if not AlignFilePointer(arec^.handle_file, 2) then Result := E_EREAD; end else if not AlignFilePointer(arec^.handle_file, 4) then Result := E_EREAD; end; CloseFile(cpio_file); if Result <> 0 then Erase(cpio_file) else begin mbFileSetAttr(cpio_name, UnixToWcxFileAttr(head.mode)); FileSetDate(cpio_name, UnixFileTimeToWcxTime(TUnixFileTime(head.mtime))); end; FreeMem(buf, 65536); end; end else Result := E_ECREATE; end{PK_EXTRACT} else Result := 0; end;{case operation} end; procedure SetProcessDataProc(hArcData: TArcHandle; ProcessDataProc: TProcessDataProc); var arec : PArchiveRec absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin arec^.process_proc := ProcessDataProc; end; end; procedure SetChangeVolProc(hArcData: TArcHandle; ChangeVolProc: TChangeVolProc); var arec : PArchiveRec absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin arec^.changevol_proc := ChangeVolProc; end; end; function CanYouHandleThisFile; begin try Result:= IsCPIOArchive(StrPas(FileName)); except Result := False; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio_def.pas��������������������������������������������������0000644�0001750�0000144�00000006143�14743153644�021072� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** {$A-,I-} unit cpio_def; interface type CPIO_Header = record magic, dev_major, dev_minor, inode, mode, uid, gid, nlink, mtime, filesize, namesize: Longword; filename : String; origname : String; IsOldHeader: Boolean; end;{CPIO_Header} TOldBinaryHeader=packed record c_magic, c_dev, c_ino, c_mode, c_uid, c_gid, c_nlink, c_rdev:word; c_mtime1,c_mtime2:word; c_namesize:word; c_filesize1,c_filesize2:word; (* char c_name[c_namesize rounded to word];*) end; TOldCharHeader=packed record c_magic : array[0..5] of AnsiChar; {070707} c_dev : array[0..5] of AnsiChar; c_ino : array[0..5] of AnsiChar; c_mode : array[0..5] of AnsiChar; c_uid : array[0..5] of AnsiChar; c_gid : array[0..5] of AnsiChar; c_nlink : array[0..5] of AnsiChar; c_rdev : array[0..5] of AnsiChar; c_mtime : array[0..10] of AnsiChar; c_namesize: array[0..5] of AnsiChar; c_filesize: array[0..10] of AnsiChar; end; TNewCharHeader=packed record c_magic : array[0..5] of AnsiChar; {070701} {070702 - CRC format} c_ino : array[0..7] of AnsiChar; c_mode : array[0..7] of AnsiChar; c_uid : array[0..7] of AnsiChar; c_gid : array[0..7] of AnsiChar; c_nlink : array[0..7] of AnsiChar; c_mtime : array[0..7] of AnsiChar; c_filesize : array[0..7] of AnsiChar; //must be 0 for FIFOs and directories c_devmajor : array[0..7] of AnsiChar; c_devminor : array[0..7] of AnsiChar; c_rdevmajor: array[0..7] of AnsiChar; //only valid for chr and blk special files c_rdevminor: array[0..7] of AnsiChar; //only valid for chr and blk special files c_namesize : array[0..7] of AnsiChar; //count includes terminating NUL in pathname c_check : array[0..7] of AnsiChar; //0 for "new" portable format; for CRC format the sum of all the bytes in the file end; implementation end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/cpio/src/cpio_io.pas���������������������������������������������������0000644�0001750�0000144�00000017233�14743153644�020745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** { Add some changes for Lazarus and Linux compability Copyright (C) 2007 Koblov Alexander (Alexx2000@mail.ru) } //*************************************************************** // Part of code (functions DirectoryExists and ForceDirectories) // got from Delphi source code //*************************************************************** //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** {$A-,I-} unit cpio_io; interface uses cpio_def, Classes; type TStrBuf = array[1..260] of Char; function CPIO_ReadHeader(var f : file; var header : CPIO_Header) : Boolean; function IsCPIOArchive(FileName: String): Boolean; function AlignFilePointer(var f : file; align : Integer) : Boolean; procedure copy_str2buf(var buf : TStrBuf; s : AnsiString); function CreateDirectories(Dir : String) : Boolean; function correct_filename(oldname : AnsiString) : AnsiString; implementation uses SysUtils; {$IFNDEF FPC} // for compiling under Delphi Const DirSeparators : set of char = ['/','\']; Procedure DoDirSeparators (Var FileName : String); VAr I : longint; begin For I:=1 to Length(FileName) do If FileName[I] in DirSeparators then FileName[i]:=PathDelim; end; {$ENDIF} procedure copy_str2buf(var buf : TStrBuf; s : AnsiString); var i_char : Integer; begin FillChar(buf, Sizeof(buf), 0); if Length(s) = 0 then Exit; if Length(s) > 259 then SetLength(s, 259); s := s + #0; for i_char := 1 to Length(s) do buf[i_char] := s[i_char]; end; function AlignFilePointer; var start : Integer; mul : LongWord; begin Result := False; start := FilePos(f); case align of 2 : mul := $FFFFFFFE; 4 : mul := $FFFFFFFC; 8 : mul := $FFFFFFF8; else Exit; end;{case} if (start mod align) <> 0 then begin start := start and mul; Inc(start, align); end; Seek(f, start); if IOResult = 0 then Result := True; end; function ExcludeTrailingBackslash(Dir:string):string; begin if (length(dir)>0) and (dir[length(dir)]='\') then result:=copy(dir,1,length(dir)-1) else result:=dir; end; function CreateDirectories(Dir : String) : Boolean; begin Result := True; if Length(Dir) = 0 then Result := False else begin Dir := ExcludeTrailingBackslash(Dir); if (Length(Dir) < 3) or DirectoryExists(Dir) or (ExtractFilePath(Dir) = Dir) then Exit; Result := CreateDirectories(ExtractFilePath(Dir)) and CreateDir(Dir); end; end; function OctalToDec(Octal: String): Longword; var i: Integer; begin Result := 0; for i := 1 to Length(Octal) do begin Result := Result shl 3; case Octal[i] of '0'..'7': Result := Result + Longword(Ord(Octal[i]) - Ord('0')); end; end; end; function HexToDec(Hex: String): Longword; var i: Integer; begin Result := 0; for i := 1 to Length(Hex) do begin Result := Result shl 4; case Hex[i] of '0'..'9': Result := Result + LongWord(Ord(Hex[i]) - Ord('0')); 'A'..'F': Result := Result + LongWord(Ord(Hex[i]) - Ord('A')) + 10; 'a'..'f': Result := Result + LongWord(Ord(Hex[i]) - Ord('a')) + 10; end; end; end; function CPIO_ReadHeader(var f : file; var header : CPIO_Header): Boolean; var Buffer : array [0..259] of AnsiChar; OldHdr : TOldBinaryHeader absolute Buffer; OdcHdr : TOldCharHeader absolute Buffer; NewHdr : TNewCharHeader absolute Buffer; ofs : Integer; begin Result := False; {First, check the type of header} BlockRead(f, Buffer[0], 6); if IOResult <> 0 then Exit; header.IsOldHeader := False; // Old binary format. if PWord(@Buffer[0])^ = $71C7 then begin header.IsOldHeader := True; BlockRead(f, Buffer[6], SizeOf(TOldBinaryHeader) - 6); if IOResult <> 0 then Exit; with header, OldHdr do begin magic := c_magic; dev_major := c_dev; dev_minor := 0; inode := c_ino; mode := c_mode; uid := c_uid; gid := c_gid; nlink := c_nlink; mtime := 65536 * c_mtime1 + c_mtime2; filesize := 65536 * c_filesize1 + c_filesize2; namesize := c_namesize; end; end // Old Ascii format. else if strlcomp(Buffer, '070707', 6) = 0 then begin BlockRead(f, Buffer[6], SizeOf(TOldCharHeader) - 6); if IOResult <> 0 then Exit; with header, OdcHdr do begin magic := OctalToDec(c_magic); dev_major := OctalToDec(c_dev); dev_minor := 0; inode := OctalToDec(c_ino); mode := OctalToDec(c_mode); uid := OctalToDec(c_uid); gid := OctalToDec(c_gid); nlink := OctalToDec(c_nlink); mtime := OctalToDec(c_mtime); filesize := OctalToDec(c_filesize); namesize := OctalToDec(c_namesize); end; end // New Ascii format. else if (strlcomp(Buffer, '070701', 6) = 0) or (strlcomp(Buffer, '070702', 6) = 0) then begin BlockRead(f, Buffer[6], SizeOf(TNewCharHeader) - 6); if IOResult <> 0 then Exit; with header, NewHdr do begin magic := HexToDec(c_magic); dev_major := HexToDec(c_devmajor); dev_minor := HexToDec(c_devminor); inode := HexToDec(c_ino); mode := HexToDec(c_mode); uid := HexToDec(c_uid); gid := HexToDec(c_gid); nlink := HexToDec(c_nlink); mtime := HexToDec(c_mtime); filesize := HexToDec(c_filesize); namesize := HexToDec(c_namesize); end; end else Exit; with header do begin if namesize = 0 then exit; {Error!} {Read name} ofs:=0; if namesize > 259 then begin ofs := namesize - 259; namesize := 259; end; FillChar(Buffer, SizeOf(Buffer), #0); BlockRead(f, Buffer, namesize); if IOResult <> 0 then Exit; SetString(filename, Buffer, namesize); if ofs <> 0 then Seek(f, FilePos(f) + ofs); origname := filename; DoDirSeparators(filename); if IsOldHeader then begin if not AlignFilePointer(f, 2) then Exit; end else if not AlignFilePointer(f, 4) then Exit; //Correct file name started with "./" or "/" filename := correct_filename(filename); end; Result := True; end; function IsCPIOArchive(FileName: String): Boolean; type TAsciiHeader = array[0..5] of AnsiChar; const sOld: TAsciiHeader = ('0', '7', '0', '7', '0', '7'); sNew: TAsciiHeader = ('0', '7', '0', '7', '0', '1'); sCrc: TAsciiHeader = ('0', '7', '0', '7', '0', '2'); var Buf: TAsciiHeader; Stream: TFileStream; begin Result := False; Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); try if (Stream.Size >= 6) and (Stream.Read(Buf[0], 6) = 6) then begin Result := // Binary format (PWord(@Buf[0])^ = $71C7) or // Ascii formats CompareMem(@Buf[0], @sOld[0], 6) or CompareMem(@Buf[0], @sNew[0], 6) or CompareMem(@Buf[0], @sCrc[0], 6); end; finally Stream.Free; end; end; function correct_filename(oldname : AnsiString) : AnsiString; begin Result := oldname; if Length(oldname) > 1 then begin case oldname[1] of '.' : case oldname[2] of '/', '\' : System.Delete(oldname, 1, 2); end;{case} '/', '\' : System.Delete(oldname, 1, 1); end;{case} end; Result := oldname; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015622� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/install.txt��������������������������������������������������������0000644�0001750�0000144�00000000646�14743153644�020037� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������How to install DEB plugin: 1. Unzip the deb.wcx to the Wincmd directory 2. In Windows Commander, choose Configuration - Options 3. Open the 'Packer' page 4. Click 'Configure packer extension WCXs 5. type deb as the extension 6. Click 'new type', and select the deb.wcx 7. Click OK What it does: This plugin allow you to browse debian linux package archives. Alexandre Maximov. Penza. Russia. http://max.reklam.ru ������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/license.txt��������������������������������������������������������0000644�0001750�0000144�00000002037�14743153644�020007� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DEB plugin for Windows Commander. Copyright (c) 2002 Alexandre Maximov Add some changes for Lazarus and Linux compability Copyright (C) 2007 Koblov Alexander (Alexx2000@mail.ru) This plugin allow you to browse debian linux package (*.deb) archives with Windows Commander 4.0 or greater. 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 OR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Any information about plugin can be found on web site : http://max.reklam.ru �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016411� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/deb.dof��������������������������������������������������������0000644�0001750�0000144�00000002417�14743153644�017641� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[FileVersion] Version=6.0 [Compiler] A=8 B=0 C=0 D=0 E=0 F=0 G=1 H=1 I=0 J=0 K=0 L=0 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=1 V=1 W=1 X=1 Y=0 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=65536 ExeDescription= [Directories] OutputDir=bin UnitOutputDir=bin PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\..\.. Packages=vcl;rtl;vclx Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication=X:\Totalcmd\Totalcmd.exe Launcher= UseLauncher=0 DebugCWD= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=1 Locale=1049 CodePage=1251 [Version Info Keys] CompanyName=Alexandre Maximov FileDescription= FileVersion=1.0.0.0 InternalName=deb.wcx LegalCopyright= LegalTrademarks= OriginalFilename=deb.wcx ProductName=WC Plugin for Debian pakages ProductVersion=1.0.0.0 Comments= [Excluded Packages] [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/deb.dpr��������������������������������������������������������0000644�0001750�0000144�00000000435�14743153644�017654� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library deb; uses deb_io in 'deb_io.pas', deb_archive in 'deb_archive.pas', deb_def in 'deb_def.pas'; exports CloseArchive, GetPackerCaps, OpenArchive, ProcessFile, ReadHeader, SetChangeVolProc, SetProcessDataProc, GetBackgroundFlags; {$R *.res} begin end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/deb.lpi��������������������������������������������������������0000644�0001750�0000144�00000012122�14743153644�017647� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="DEB WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2018 Koblov Alexander"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\deb.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <HostApplicationFilename Value="X:\Totalcmd\Totalcmd.exe"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <HostApplicationFilename Value="X:\Totalcmd\Totalcmd.exe"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> <MinVersion Minor="2" Valid="True"/> </Item1> </RequiredPackages> <Units Count="4"> <Unit0> <Filename Value="deb.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="deb_io.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="deb_archive.pas"/> <IsPartOfProject Value="True"/> </Unit2> <Unit3> <Filename Value="deb_def.pas"/> <IsPartOfProject Value="True"/> </Unit3> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\deb.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> </CONFIG> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/deb_archive.pas������������������������������������������������0000644�0001750�0000144�00000022003�14743153644�021346� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit deb_archive; interface {$mode delphi}{$A-,I-} {$include calling.inc} uses Classes, WcxPlugin, deb_def, deb_io; type PArchiveRec = ^TArchiveRec; TArchiveRec = record handle_io : THandle; handle_file : file; fname : AnsiString; fdate : Integer; fgEndArchive : Boolean; process_proc : TProcessDataProc; changevol_proc : TChangeVolProc; last_header : deb_Header; end;{ArchiveRec} function GetPackerCaps : Integer; dcpcall; export; function GetBackgroundFlags: Integer; dcpcall; export; function OpenArchive(var ArchiveData : TOpenArchiveData) : TArcHandle; dcpcall; export; function CloseArchive(hArcData : TArcHandle) : Integer; dcpcall; export; function ReadHeader(hArcData : TArcHandle; var HeaderData : THeaderData) : Integer; dcpcall; export; function ProcessFile(hArcData : TArcHandle; Operation : Integer; DestPath : PChar; DestName : PChar) : Integer; dcpcall; export; procedure SetProcessDataProc(hArcData : TArcHandle; ProcessDataProc : TProcessDataProc); dcpcall; export; procedure SetChangeVolProc(hArcData : TArcHandle; ChangeVolProc : TChangeVolProc); dcpcall; export; implementation uses SysUtils, DCDateTimeUtils, DCBasicTypes, DCFileAttributes; function GetPackerCaps: Integer; begin Result := PK_CAPS_MULTIPLE; end; function GetBackgroundFlags: Integer; begin Result:= BACKGROUND_UNPACK; end; function OpenArchive(var ArchiveData: TOpenArchiveData): TArcHandle; var arch : THandle; filename : String; fgError : Boolean; arec : PArchiveRec absolute Result; function SignatureProbe: integer; //0 Ales Gut; 1 IO error; 2 is not DEBIAN PKG const deb_signature: array [0..20] of Char ='!<arch>'#10'debian-binary'; var tmp_buf : array [0..20] of Char; j : integer; begin Result:=2; BlockRead(arec^.handle_file, tmp_buf, 21); if IOResult <> 0 then begin Result:=1; Exit; end; for j:=0 to 20 do if deb_signature[j] <> tmp_buf[j] then Exit; Result:=0; end; begin ArchiveData.OpenResult := E_EOPEN; arec := nil; arch := 0; fgError := False; filename := String(ArchiveData.ArcName); arch := FileOpen(filename, fmOpenRead or fmShareDenyNone); if arch = THandle(-1) then begin fgError := True; end else begin New(arec); with arec^ do begin handle_io := arch; fname := filename; fdate := FileAge(filename); fgEndArchive := False; process_proc := nil; changevol_proc := nil; if fdate = -1 then fdate := 0; last_header.size:=0; last_header.pos:=size_deb_signature; end; AssignFile(arec^.handle_file, filename); FileMode := 0; Reset(arec^.handle_file, 1); if IOResult <> 0 then begin fgError := True; end else begin case SignatureProbe of 1: begin ArchiveData.OpenResult := E_EREAD; fgError := True; end; 2: begin ArchiveData.OpenResult := E_UNKNOWN_FORMAT; fgError := True; end else begin Seek(arec^.handle_file, size_deb_signature); if IOResult <> 0 then fgError := True; end; end;{case SignatureProbe} end;{ioresult} end;{arch = -1} if fgError then begin if arec <> nil then begin CloseFile(arec^.handle_file); Dispose(arec); end; FileClose(arch); Result := 0; end else begin ArchiveData.OpenResult := E_SUCCESS; end; end; function CloseArchive(hArcData: TArcHandle): Integer; var arec : PArchiveRec absolute hArcData; begin CloseFile(arec^.handle_file); FileClose(arec^.handle_io); Dispose(arec); Result := E_SUCCESS; end; function ReadHeader(hArcData: TArcHandle; var HeaderData: THeaderData): Integer; var header : deb_Header; arec : PArchiveRec absolute hArcData; begin Result := E_EREAD; if arec^.fgEndArchive then Result := E_END_ARCHIVE else begin while True do begin if not deb_ReadHeader(arec^.handle_file, header, arec^.last_header) then begin Result := E_END_ARCHIVE; Break end else begin with HeaderData do begin StrPCopy(ArcName, arec^.fname); StrPCopy(FileName, header.filename); PackSize := header.size; UnpSize := header.size; UnpVer := 2; HostOS := 0; FileCRC := 0; FileAttr := UnixToWcxFileAttr(header.mode); FileTime := UnixFileTimeToWcxTime(TUnixFileTime(header.time)); end;{with} Result := E_SUCCESS; Break; end{if header readed} end;{while true} arec^.last_header := header; end;{if not end of archive} end; function ProcessFile(hArcData: TArcHandle; Operation: Integer; DestPath: PChar; DestName: PChar): Integer; var targz_file : file; targz_name : String; buf : Pointer; buf_size : LongWord; fsize : LongWord; fpos : LongWord; fgReadError : Boolean; fgWriteError: Boolean; fAborted : Boolean; head : deb_Header; arec : PArchiveRec absolute hArcData; begin head := arec^.last_header; case Operation of PK_TEST : begin fAborted:=false; fsize := head.size; fpos := head.pos; buf_size := 65536; GetMem(buf, buf_size); fgReadError := False; Seek(arec^.handle_file, fpos); if IOResult <> 0 then begin fgReadError := True; fAborted:=True; end; while not faborted do begin if fsize < buf_size then Break; BlockRead(arec^.handle_file, buf^, buf_size); if IOResult <> 0 then begin fgReadError := True; Break; end;{if IO error} Dec(fsize, buf_size); if Assigned(arec^.process_proc) then if arec^.process_proc(nil, buf_size)=0 then fAborted:=true; end;{while} if not fgReadError and not faborted then begin if fsize <> 0 then begin BlockRead(arec^.handle_file, buf^, fsize); if IOResult <> 0 then fgReadError := True; if Assigned(arec^.process_proc) then if arec^.process_proc(nil, fsize)=0 then fAborted:=true; end; end; if fAborted then Result:=E_EABORTED else if fgReadError then Result := E_EREAD else Result := 0; Seek(arec^.handle_file, size_deb_signature); FreeMem(buf, 65536); end;{PK_TEST} PK_SKIP : Result := 0; PK_EXTRACT : begin targz_name := String(DestName); AssignFile(targz_file, targz_name); Rewrite(targz_file, 1); if IOResult <> 0 then Result := E_ECREATE else begin fgReadError := False; fgWriteError :=False; fAborted := False; fsize := head.size; fpos := head.pos; buf_size := 65536; GetMem(buf, buf_size); Seek(arec^.handle_file, fpos); if IOResult <> 0 then begin fgReadError := True; fAborted:=True; end; while not fAborted do begin if fsize < buf_size then Break; BlockRead(arec^.handle_file, buf^, buf_size); if IOResult <> 0 then begin fgReadError := True; Break; end;{if IO error} BlockWrite(targz_file, buf^, buf_size); if ioresult<>0 then begin fgWriteError:=true; break; end; Dec(fsize, buf_size); if Assigned(arec^.process_proc) then if arec^.process_proc(nil, buf_size)=0 then fAborted:=true; end;{while} if not fgReadError then begin if fsize <> 0 then begin BlockRead(arec^.handle_file, buf^, fsize); if IOResult <> 0 then fgReadError := True; BlockWrite(targz_file, buf^, fsize); if ioresult<>0 then fgWriteError:=true; if Assigned(arec^.process_proc) then if arec^.process_proc(nil, fsize)=0 then fAborted:=true; end; end; if fAborted then Result:= E_EABORTED else if fgWriteError then Result := E_EWRITE else if fgReadError then Result := E_EREAD else Result := 0; FileSetDate(tfilerec(targz_file).handle, UnixFileTimeToWcxTime(TUnixFileTime(head.time))); CloseFile(targz_file); Seek(arec^.handle_file, size_deb_signature); if result<>0 then Erase(targz_file); FreeMem(buf, 65536); end; end;{PK_EXTRACT} else Result := E_SUCCESS; end;{case operation} end; procedure SetProcessDataProc(hArcData: TArcHandle; ProcessDataProc: TProcessDataProc); var arec : PArchiveRec absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin arec^.process_proc := ProcessDataProc; end; end; procedure SetChangeVolProc(hArcData: TArcHandle; ChangeVolProc: TChangeVolProc); var arec : PArchiveRec absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin arec^.changevol_proc := ChangeVolProc; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/deb_def.pas����������������������������������������������������0000644�0001750�0000144�00000000400�14743153644�020460� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit deb_def; interface type deb_Header = record filename : String; time : longint; size : longint; mode : longint; pos : longint; end; const size_deb_files= 60; size_deb_signature = 72; implementation end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/deb/src/deb_io.pas�����������������������������������������������������0000644�0001750�0000144�00000003420�14743153644�020336� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit deb_io; interface {$A-,I-} uses deb_def; function deb_ReadHeader(var f : file; var header, lastheader : deb_Header) : Boolean; implementation uses SysUtils, DCStrUtils, DCFileAttributes; function deb_ReadHeader(var f : file; var header, lastheader : deb_Header) : Boolean; var tmp_str : String; loadlen : Integer; tmp_buf : array [0..259] of Char; begin Result:= False; loadlen:= size_deb_files; // Skip last header Seek(f, lastheader.pos + lastheader.size); if IOResult <> 0 then Exit; // Read next header header.pos:= FilePos(f) + size_deb_files; BlockRead(f, {%H-}tmp_buf, loadlen); if IOResult <> 0 then Exit; // Other version DPKG - offset 1. if tmp_buf[0] = #10 then begin Seek(f, lastheader.pos + lastheader.size + 1); if IOResult <> 0 then Exit; header.pos:= FilePos(f) + size_deb_files; BlockRead(f, tmp_buf, loadlen); if IOResult <> 0 then Exit; end; // Read file name SetLength(header.filename, 16); Move(tmp_buf[0], header.filename[1], 16); header.filename:= Trim(header.filename); if (Length(header.filename) > 0) then begin loadlen:= Length(header.filename); if header.filename[loadlen] = '/' then SetLength(header.filename, loadlen - 1); end; // Read file time SetLength(tmp_str, 12); Move(tmp_buf[16], tmp_str[1], 12); header.Time:= StrToIntDef(Trim(tmp_str), 0); // Read file mode SetLength(tmp_str, 8); Move(tmp_buf[40], tmp_str[1], 8); tmp_str:= Trim(tmp_str); if Length(tmp_str) > 0 then header.Mode:= OctToDec(tmp_str) else begin header.Mode:= S_IRUSR or S_IWUSR or S_IRGRP or S_IROTH; end; // Read file size SetLength(tmp_str, 10); Move(tmp_buf[48], tmp_str[1], 10); header.size:= StrToIntDef(Trim(tmp_str), 0); Result := True; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015666� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/install.txt��������������������������������������������������������0000644�0001750�0000144�00000001026�14743153644�020074� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������How to install RPM plugin: 1. Unzip the rpm.wcx and cpio.wcx to the Totalcmd directory 2. In Total Commander, choose Configuration - Options 3. Open the 'Packer' page 4. Click 'Configure packer extension WCXs 5. type rpm as the extension 6. Click 'new type', and select the rpm.wcx 5. type cpio as the extension 6. Click 'new type', and select the cpio.wcx 7. Click OK What it does: This plugin allow you to browse rpm archives. Mandryka Yurij Brain group http://braingroup.hotmail.ru/wcplugins/ mailto:braingroup@hotmail.ru����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/license.txt��������������������������������������������������������0000644�0001750�0000144�00000002205�14743153644�020050� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RPM plugin v.1.4 for Windows Commander. Copyright (c) 2000..2002 Mandryka Yurij ( Brain Group ) Add some changes for Lazarus and Linux compability Copyright (C) 2007 Koblov Alexander (Alexx2000@mail.ru) This plugin allow you to browse rpm archives with Windows Commander 4.0 or greater. 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 OR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Any questions about plugin can be made via e-mail : braingroup@hotmail.ru and information about plugin can be found on Brain Group web site : http://braingroup.hotmail.ru/wcplugins/ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016455� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/rpm.cfg��������������������������������������������������������0000644�0001750�0000144�00000000546�14743153644�017741� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-$A- -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I- -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\borland\delphi5\Projects\Bpl" -LN"c:\borland\delphi5\Projects\Bpl" ����������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/rpm.dof��������������������������������������������������������0000644�0001750�0000144�00000002373�14743153644�017752� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Compiler] A=0 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=0 J=1 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= SearchPath= Packages=VCL50;VCLX50;VCLSMP50;VCLDB50;VCLADO50;ibevnt50;VCLBDE50;VCLDBX50;QRPT50;TEEUI50;TEEDB50;TEE50;DSS50;TEEQR50;VCLIB50;VCLMID50;VCLIE50;INETDB50;INET50;NMFAST50;WEBMID50;dclocx50;dclaxserver50;dcldtree50 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication=e:\delphi\exedpr\totalcmd.exe [Version Info] IncludeVerInfo=1 AutoIncBuild=1 MajorVer=1 MinorVer=1 Release=0 Build=188 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1049 CodePage=1251 [Version Info Keys] CompanyName=Brain group FileDescription=rpm plugin for Windows Commander FileVersion=1.1.0.188 InternalName=rpm.wcx LegalCopyright=Mandryka Yurij LegalTrademarks= OriginalFilename=rpm.wcx ProductName=rpm plugin ProductVersion=1.1.0.0 Comments=any questions on braingroup@hotmail.ru ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/rpm.dpr��������������������������������������������������������0000644�0001750�0000144�00000001726�14743153644�017770� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** { Add some changes for Lazarus and Linux compability Copyright (C) 2007-2012 Koblov Alexander (Alexx2000@mail.ru) } //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** library rpm; uses SysUtils, Classes, WcxPlugin, rpm_io in 'rpm_io.pas', rpm_def in 'rpm_def.pas', rpm_archive in 'rpm_archive.pas'; exports CloseArchive, GetPackerCaps, OpenArchive, ProcessFile, ReadHeader, SetChangeVolProc, SetProcessDataProc, GetBackgroundFlags; {$R *.res} begin {$IFNDEF MSWINDOWS} WriteLn('Rpm plugin is loaded'); {$ENDIF} end. ������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/rpm.lpi��������������������������������������������������������0000644�0001750�0000144�00000012111�14743153644�017755� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <LRSInOutputDirectory Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="RPM WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2012 Koblov Alexander"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../rpm.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> <MinVersion Minor="2" Valid="True"/> </Item1> </RequiredPackages> <Units Count="4"> <Unit0> <Filename Value="rpm.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="rpm_io.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="rpm_def.pas"/> <IsPartOfProject Value="True"/> </Unit2> <Unit3> <Filename Value="rpm_archive.pas"/> <IsPartOfProject Value="True"/> </Unit3> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../rpm.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/rpm_archive.pas������������������������������������������������0000644�0001750�0000144�00000025115�14743153644�021465� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** { Add some changes for Lazarus and Linux compability Copyright (C) 2007-2012 Koblov Alexander (Alexx2000@mail.ru) } //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** //*************************************************************** // This code was improved by Sergio Daniel Freue (sfreue@dc.uba.ar) //*************************************************************** // History // 2001-02-04 Bug: Error Opening rpm file on CD (readonly) // Fix: Add FileMode = 0 before Reset // Who: Oliver Haeger <haeger@inghb.de> unit rpm_archive; {$mode delphi}{$A-,I-} {$include calling.inc} interface uses Classes, WcxPlugin, rpm_def, rpm_io; type PArchiveRec = ^TArchiveRec; TArchiveRec = record handle_io : THandle; handle_file : file; fname : AnsiString; fdate : Integer; headers : Integer; header : RPM_Header; arch_len : LongWord; process_proc : TProcessDataProc; changevol_proc : TChangeVolProc; //- RPM tags ------------------------------------------- info : RPM_InfoRec; deps : RPM_DepsRec; datasig : RPM_DataSig; end;{ArchiveRec} function GetPackerCaps : Integer; dcpcall; export; function GetBackgroundFlags: Integer; dcpcall; export; function OpenArchive(var ArchiveData : TOpenArchiveData) : TArcHandle; dcpcall; export; function CloseArchive(hArcData : TArcHandle) : Integer; dcpcall; export; function ReadHeader(hArcData : TArcHandle; var HeaderData : THeaderData) : Integer; dcpcall; export; function ProcessFile(hArcData : TArcHandle; Operation : Integer; DestPath : PChar; DestName : PChar) : Integer; dcpcall; export; procedure SetProcessDataProc(hArcData : TArcHandle; ProcessDataProc : TProcessDataProc); dcpcall; export; procedure SetChangeVolProc(hArcData : TArcHandle; ChangeVolProc : TChangeVolProc); dcpcall; export; implementation uses SysUtils, DCDateTimeUtils, DCBasicTypes, DCFileAttributes; function GetPackerCaps: Integer; begin Result := PK_CAPS_MULTIPLE; end; function GetBackgroundFlags: Integer; begin Result := BACKGROUND_UNPACK; end; function OpenArchive(var ArchiveData : TOpenArchiveData) : TArcHandle; var arch : THandle; filename : String; r_lead : RPM_Lead; signature : RPM_Header; fgError : Boolean; headerend : integer; arec : PArchiveRec absolute Result; begin arec := nil; arch := 0; fgError := False; filename := String(ArchiveData.ArcName); arch := FileOpen(filename, fmOpenRead or fmShareDenyNone); if arch = THandle(-1) then begin fgError := True; end else begin New(arec); with arec^ do begin handle_io := arch; fname := filename; headers := HDR_INFO; arch_len := 0; fdate := FileAge(filename); process_proc := nil; changevol_proc := nil; if fdate = -1 then fdate := 0; end; AssignFile(arec^.handle_file, filename); FileMode := 0; Reset(arec^.handle_file, 1); if IOResult <> 0 then begin fgError := True; end else begin RPM_ReadLead(arec^.handle_file, r_lead); if r_lead.magic <> RPM_MAGIC then fgError := True else begin if not RPM_ReadSignature(arec^.handle_file, r_lead.signature_type, signature) then fgError := True else if not RPM_ReadHeader(arec^.handle_file, False, arec^.header, arec^.info, arec^.deps) then fgError := True else arec^.arch_len := FileSize(arec^.handle_file) - FilePos(arec^.handle_file); if not fgError then begin headerend:=FilePos(arec^.handle_file); BlockRead(arec^.handle_file, arec^.datasig, SizeOf(RPM_DataSig)); Seek(arec^.handle_file, headerend); end; end; end;{ioresult} end;{arch = -1} if fgError then begin if arec <> nil then begin CloseFile(arec^.handle_file); Dispose(arec); end; FileClose(arch); Result := 0; ArchiveData.OpenResult := E_EOPEN end; end; function CloseArchive(hArcData: TArcHandle): Integer; var arec : PArchiveRec absolute hArcData; begin CloseFile(arec^.handle_file); FileClose(arec^.handle_io); Dispose(arec); Result := E_SUCCESS; end; function ReadHeader(hArcData: TArcHandle; var HeaderData: THeaderData): Integer; var arec : PArchiveRec absolute hArcData; begin Result := E_SUCCESS; with HeaderData do begin case arec^.headers of HDR_DATA: begin copy_str2buf(TStrBuf(FileName), get_archivename(arec^.fname,arec^.datasig)); PackSize := arec^.arch_len; UnpSize := arec^.arch_len; end; HDR_INFO: begin copy_str2buf(TStrBuf(FileName), 'INFO.TXT'); PackSize := -1; UnpSize := -1; end; else Result := E_END_ARCHIVE; end; if Result = E_SUCCESS then begin copy_str2buf(TStrBuf(ArcName), arec^.fname); FileAttr := GENERIC_ATTRIBUTE_FILE; FileTime := UnixFileTimeToWcxTime(TUnixFileTime(arec^.info.buildtime)); Inc(arec^.headers); end; end; end; function ProcessFile(hArcData: TArcHandle; Operation: Integer; DestPath: PChar; DestName: PChar): Integer; var rpm_file : file; rpm_name : String; index : Integer; buf : Pointer; buf_size : LongWord; fsize : LongWord; fgReadError : Boolean; fgWriteError: Boolean; faborted : Boolean; testonly : Boolean; arec : PArchiveRec absolute hArcData; // Helper function to output one line of text to rpm_file function Line(S: AnsiString): Integer; begin Result := 0; if not fgReadError and not fgWriteError then if testonly then Result := Length(S) + 2 else begin S := S + #13#10; BlockWrite(rpm_file, S[1], Length(S), Result); if IOResult <> 0 then fgWriteError := True; end; end; begin case Operation of // Because rpm archive doesn't contains length of _alone_ attached // gzipped cpio archive, plugin cann't skip or test rpm archive // correctly without extracting archive. PK_SKIP : Result := E_SUCCESS; PK_TEST, PK_EXTRACT : begin testonly:=Operation=PK_TEST; if not testonly then begin rpm_name := String(DestName); AssignFile(rpm_file, rpm_name); Rewrite(rpm_file, 1); end; if not testonly and (IOResult <> 0) then begin Result := E_EWRITE end else begin fgReadError := False; fgWriteError := False; faborted:=false; case (arec^.headers-1) of HDR_DATA: begin fsize := arec^.arch_len; buf_size := 65536; GetMem(buf, buf_size); while not faborted do begin if fsize < buf_size then Break; BlockRead(arec^.handle_file, buf^, buf_size); if IOResult <> 0 then begin fgReadError := True; Break; end;{if IO error} if not testonly then begin BlockWrite(rpm_file, buf^, buf_size); if IOResult <> 0 then begin fgWriteError := True; Break; end;{if IO error} end; Dec(fsize, buf_size); if Assigned(arec^.process_proc) then if arec^.process_proc(nil, buf_size)=0 then faborted:=true; end;{while} if not fgReadError and not fgWriteError and not faborted then begin if fsize <> 0 then begin BlockRead(arec^.handle_file, buf^, fsize); if IOResult <> 0 then fgReadError := True; if not testonly and not fgReadError then begin BlockWrite(rpm_file, buf^, fsize); if IOResult <> 0 then fgWriteError := True; end; if Assigned(arec^.process_proc) then if arec^.process_proc(nil, fsize)=0 then faborted:=true; end; end; Freemem(buf, buf_size); //Other pseudo-files end; HDR_INFO: with arec^.info do begin Line('NAME: ' + name); Line('VERSION: ' + version); Line('RELEASE: ' + release); Line('SUMMARY: ' + summary); Line('DISTRIBUTION: ' + distribution); Line('VENDOR: ' + vendor); Line('LICENSE: ' + license); Line('PACKAGER: ' + packager); Line('GROUP: ' + group); Line('OS: ' + os); Line('ARCH: ' + arch); Line('SOURCE RPM: ' + sourcerpm); Line('DESCRIPTION: '); Line(description); if Length(arec^.deps.names) > 0 then begin Line(EmptyStr); Line('REQUIRES: '); for index:= 0 to High(arec^.deps.names) do begin Line(' ' + arec^.deps.names[index]); end; end; end; end; if faborted then Result:=E_EABORTED else if fgReadError then Result := E_BAD_DATA else if fgWriteError then Result:= E_EWRITE else Result := E_SUCCESS; if not testonly then begin if result = E_SUCCESS then FileSetDate(tfilerec(rpm_file).handle, UnixFileTimeToWcxTime(TUnixFileTime(arec^.info.buildtime))); CloseFile(rpm_file); if result <> E_SUCCESS then Erase(rpm_file); end; end; end else Result := E_SUCCESS; end;{case operation} end; procedure SetProcessDataProc(hArcData: TArcHandle; ProcessDataProc: TProcessDataProc); var arec : PArchiveRec absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin arec^.process_proc := ProcessDataProc; end; end; procedure SetChangeVolProc(hArcData: TArcHandle; ChangeVolProc: TChangeVolProc); var arec : PArchiveRec absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin arec^.changevol_proc := ChangeVolProc; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/rpm/src/rpm_def.pas����������������������������������������������������0000644�0001750�0000144�00000005773�14743153644�020612� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** {$A-,I-} unit rpm_def; interface uses Classes, SysUtils; {$ifdef ver90} type longword=longint; {$endif} {$ifdef ver100} type longword=longint; {$endif} //values for TArchiveRec.headers (pseudo-files to show) const HDR_INFO = 0; HDR_DATA = 1; const MAX_PHANTOM_FILES = 13; const RPM_MAGIC = $DBEEABED; RPM_TYPE_BINARY = 0; // binary package type RPM_TYPE_SOURCE = 1; // source package type RPMSIG_PGP262_1024 = 1; RPMSIG_MD5 = 3; RPMSIG_MD5_PGP = 4; RPMSIG_HEADERSIG = 5; const RPMTAG_NAME = 1000; RPMTAG_VERSION = 1001; RPMTAG_RELEASE = 1002; RPMTAG_SUMMARY = 1004; RPMTAG_DESCRIPTION = 1005; RPMTAG_BUILDTIME = 1006; RPMTAG_DISTRIBUTION = 1010; RPMTAG_VENDOR = 1011; RPMTAG_LICENSE = 1014; RPMTAG_PACKAGER = 1015; RPMTAG_GROUP = 1016; RPMTAG_OS = 1021; RPMTAG_ARCH = 1022; RPMTAG_FILENAMES = 1027; RPMTAG_FILEMTIMES = 1034; RPMTAG_SOURCERPM = 1044; RPMTAG_ARCHIVESIZE = 1046; RPMTAG_REQUIRENAME = 1049; type RPM_DataSig = array[0..5] of char; type RPM_EntryInfo = record tag : LongWord; etype : LongWord; offset : LongWord; count : LongWord; end;{EntryInfo} type RPM_Lead = record magic : LongWord; major_ver : Byte; minor_ver : Byte; rpmtype : Word; archnum : Word; name : array[1..66] of Char; osnum : Word; signature_type : Word; reserved : array[1..16] of Char; end;{RPM_Lead} RPM_Header =record magic : array [1..3] of byte; header_ver : Byte; reserved : array [1..4] of Byte; count : LongWord; data_size : LongWord; end;{RPM_Header} RPM_InfoRec = record name : AnsiString; // RPMTAG_NAME version : AnsiString; // RPMTAG_VERSION release : AnsiString; // RPMTAG_RELEASE summary : AnsiString; // RPMTAG_SUMMARY description : AnsiString; // RPMTAG_DESCRIPTION distribution : AnsiString; // RPMTAG_DISTRIBUTION buildtime : LongWord; // RPMTAG_BUILDTIME vendor : AnsiString; // RPMTAG_VENDOR license : AnsiString; // RPMTAG_LICENSE packager : AnsiString; // RPMTAG_PACKAGER group : AnsiString; // RPMTAG_GROUP os : AnsiString; // RPMTAG_OS arch : AnsiString; // RPMTAG_ARCH sourcerpm : AnsiString; // RPMTAG_SOURCERPM end;{RPM_Info} RPM_DepsRec = record names: TStringArray; end; implementation end. �����doublecmd-1.1.22/plugins/wcx/rpm/src/rpm_io.pas�����������������������������������������������������0000644�0001750�0000144�00000020237�14743153644�020453� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** //*************************************************************** // This code was improved by Sergio Daniel Freue (sfreue@dc.uba.ar) //*************************************************************** {$A-,I-} unit rpm_io; interface uses SysUtils, rpm_def; type TStrBuf = array[1..260] of Char; function RPM_ReadLead(var f : file; var lead : RPM_Lead) : Boolean; function RPM_ReadSignature(var f : file; sig_type : Word; var signature : RPM_Header) : Boolean; function RPM_ReadHeader(var f : file; align_data : Boolean; var header : RPM_Header; var info : RPM_InfoRec; var deps : RPM_DepsRec) : Boolean; function RPM_ReadEntry(var f : file; data_start : LongInt; var entry : RPM_EntryInfo) : Boolean; function RPM_ProcessEntry(var f : file; data_start : LongInt; var entry : RPM_EntryInfo; var info : RPM_InfoRec; var deps : RPM_DepsRec) : Boolean; procedure swap_value(var value; size : Integer); procedure copy_str2buf(var buf : TStrBuf; s : AnsiString); function get_archivename(var fname : String;datasig:RPM_DataSig) : String; function read_string(var f : file; var s : AnsiString) : Boolean; function read_int32(var f : file; var int32 : LongWord) : Boolean; implementation uses Classes; procedure swap_value(var value; size:Integer); type byte_array = array[1..MaxInt] of Byte; var i : Integer; avalue : Byte; begin for i:=1 to size div 2 do begin avalue := byte_array(value)[i]; byte_array(value)[i] := byte_array(value)[size + 1 - i]; byte_array(value)[size + 1 - i] := avalue; end; end; procedure copy_str2buf(var buf : TStrBuf; s : AnsiString); var i_char : Integer; begin FillChar(buf, Sizeof(buf), 0); if Length(s) = 0 then Exit; if Length(s) > 259 then SetLength(s, 259); s := s + #0; for i_char := 1 to Length(s) do buf[i_char] := s[i_char]; end; function get_archivename(var fname : String;datasig:RPM_DataSig) : String; var tmp_str : String; i_char : Integer; fgFound : Boolean; begin tmp_str := ExtractFileName(fname); fgFound := False; for i_char := Length(tmp_str) downto 1 do if tmp_str[i_char] = '.' then begin fgFound := True; Break; end; if fgFound then SetLength(tmp_str, i_char - 1); if (datasig[0] = #031) and (datasig[1] = #139) then tmp_str := tmp_str + '.cpio.gz' else if (datasig[0]='B') and (datasig[1]='Z') and (datasig[2]='h') then tmp_str := tmp_str + '.cpio.bz2' else if CompareByte(datasig, #253'7zXZ'#000, 6) = 0 then tmp_str := tmp_str + '.cpio.xz' else if CompareByte(datasig, #$28#$B5#$2F#$FD, 4) = 0 then tmp_str := tmp_str + '.cpio.zst' else tmp_str := tmp_str + '.cpio.lzma'; Result := tmp_str; end; function RPM_ReadLead; begin Result := False; BlockRead(f, lead, Sizeof(Lead)); if IOResult = 0 then Result := True; with lead do begin swap_value(rpmtype, 2); swap_value(archnum, 2); swap_value(osnum, 2); swap_value(signature_type, 2); end; end; function RPM_ReadHeader; var i_entry : LongWord; start : Integer; entry : RPM_EntryInfo; begin Result := False; BlockRead(f, header, Sizeof(header)); if IOResult = 0 then begin with header do begin swap_value(count, 4); swap_value(data_size, 4); start := FilePos(f) + LongInt(count) * Sizeof(entry); for i_entry := 0 to count - 1 do begin if not RPM_ReadEntry(f, start, entry) then Exit else if not RPM_ProcessEntry(f, start, entry, info, deps) then Exit; end; end; start := start + LongInt(header.data_size); // Move file pointer on padded to a multiple of 8 bytes position if align_data then if (start mod 8) <> 0 then begin start := start and $FFFFFFF8; Inc(start, 8); end; Seek(f, start); Result := True; end; end; function RPM_ReadEntry; begin Result := False; BlockRead(f, entry, Sizeof(entry)); if IOResult = 0 then Result := True; with entry do begin swap_value(tag, 4); swap_value(etype, 4); swap_value(offset, 4); offset := data_start + LongInt(offset); swap_value(count, 4); end; end; function RPM_ReadSignature; var info : RPM_InfoRec; deps : RPM_DepsRec; begin Result := False; case sig_type of RPMSIG_PGP262_1024 : ; // Old PGP signature RPMSIG_MD5 : ; // RPMSIG_MD5_PGP : ; // RPMSIG_HEADERSIG : // New header signature begin if RPM_ReadHeader(f, True, signature, info, deps) then Result := True; end; end;{case signature type} end; procedure CRtoCRLF(var instr:string); var s:string; i,l:integer; ch,ch2:char; begin s := ''; instr:=instr+' '; {Avoid overflow} l:=length(instr)-1; for i:=1 to l do begin ch:=instr[i]; ch2:=instr[i+1]; if ((ch=#13) and (ch2<>#10)) or ((ch=#10) and (ch2<>#13)) then s:=s+#13#10 else s:=s+ch; end; instr:=s; end; function RPM_ProcessEntry; var save_pos : Integer; fgError : Boolean; i : Integer; s : String; begin result:=true; if entry.tag = RPMTAG_FILENAMES then exit; fgError := False; save_pos := FilePos(f); Seek(f, entry.offset); if IOResult = 0 then begin case entry.tag of RPMTAG_NAME : if entry.etype = 6 then fgError := not read_string(f, info.name); RPMTAG_VERSION : if entry.etype = 6 then fgError := not read_string(f, info.version); RPMTAG_RELEASE : if entry.etype = 6 then fgError := not read_string(f, info.release); RPMTAG_SUMMARY : if entry.etype = 9 then fgError := not read_string(f, info.summary); RPMTAG_DESCRIPTION : if entry.etype = 9 then begin fgError := not read_string(f, info.description); if not fgError then CRtoCRLF(info.description); end; RPMTAG_BUILDTIME : if entry.etype = 4 then fgError := not read_int32(f, info.buildtime); RPMTAG_DISTRIBUTION : if entry.etype = 6 then fgError := not read_string(f, info.distribution); RPMTAG_VENDOR : if entry.etype = 6 then fgError := not read_string(f, info.vendor); RPMTAG_LICENSE : if entry.etype = 6 then fgError := not read_string(f, info.license); RPMTAG_PACKAGER : if entry.etype = 6 then fgError := not read_string(f, info.packager); RPMTAG_GROUP : if entry.etype = 9 then fgError := not read_string(f, info.group); RPMTAG_OS : if entry.etype = 6 then fgError := not read_string(f, info.os); RPMTAG_ARCH : if entry.etype = 6 then fgError := not read_string(f, info.arch); RPMTAG_SOURCERPM : if entry.etype = 6 then fgError := not read_string(f, info.sourcerpm); RPMTAG_REQUIRENAME: if entry.etype = 8 then begin SetLength(deps.names, entry.Count); for i := 0 to entry.Count - 1 do begin read_string(f, s); deps.names[i] := s; end; end; end;{case} end else fgError := True; Result := not fgError; Seek(f, save_pos); end; function read_string(var f : file; var s : AnsiString) : Boolean; var i_char : Char; fgError : Boolean; begin fgError := False; SetLength(s, 0); while not eof(f) do begin BlockRead(f, i_char, 1); if IOResult <> 0 then begin fgError := True; Break; end; if i_char = #0 then Break else s := s + i_char; end; Result := not fgError; end; function read_int32(var f : file; var int32 : LongWord) : Boolean; begin BlockRead(f, int32, Sizeof(LongWord)); swap_value(int32, Sizeof(LongWord)); if IOResult = 0 then Result := True else Result := False; end; procedure RPM_CreateInfoRec(var info : RPM_InfoRec); begin end; procedure RPM_DeleteInfoRec(var info : RPM_InfoRec); begin end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/��������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016733� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/LICENSE.txt���������������������������������������������������0000644�0001750�0000144�00000064505�14743153644�020570� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. (This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.) Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. {signature of Ty Coon}, 1 April 1990 Ty Coon, President of Vice That's all there is to it! �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/README.txt����������������������������������������������������0000644�0001750�0000144�00000001231�14743153644�020426� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SevenZip plugin can store configuration in two places: 1. If sevenzip.ini exists in plugin directory then plugin will use it 2. Otherwise it will store sevenzip.ini in commander configuration directory SevenZip plugin search 7z.dll in next places: 1. Path from sevenzip.ini [Library] i386=<full path to 7z.dll 32 bit> x86_64=<full path to 7z.dll 64 bit> 2. Plugin directory \i386\7z.dll \x86_64\7z.dll \7z.dll 3. Commander directory 4. Windows system directory SevenZip plugin can load external codecs. Plugin searches codecs in subdirectory "Codecs" near 7z.dll. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/build.bat�����������������������������������������������������0000644�0001750�0000144�00000001602�14743153644�020521� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@echo off set VERSION=21.09.18 rem The next two line must be changed before run on your computer set lazpath=D:\Alexx\Prog\FreePascal\Lazarus set PATH=%lazpath%;%PATH% del /Q /S *.wcx* del /Q /S lib\*.* lazbuild.exe --cpu=x86_64 --os=win64 --bm=Release src\SevenZipWcx.lpi ren sevenzip.wcx sevenzip.wcx64 del /Q /S lib\*.* lazbuild.exe --cpu=i386 --os=win32 --bm=Release src\SevenZipWcx.lpi del /Q /S lib\*.* rem Prepare archive del /Q /S release\* copy "C:\Program Files (x86)\7-Zip\7z.dll" release\i386\ copy "C:\Program Files\7-Zip\7z.dll" release\x86_64\ copy LICENSE.txt release\ copy pluginst.inf release\ copy README.txt release\ copy sevenzip.wcx release\ copy sevenzip.wcx64 release\ del /Q sevenzip-*.zip pushd release "C:\Program Files\7-Zip\7z.exe" a ..\sevenzip-%VERSION%.zip .\* popd del /Q /S release\* ������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/pluginst.inf��������������������������������������������������0000644�0001750�0000144�00000000200�14743153644�021266� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[plugininstall] description=SevenZip archiver plugin type=wcx file=SevenZip.wcx defaultextension=7z defaultdir=SevenZip ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017522� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipAdv.pas�������������������������������������������0000644�0001750�0000144�00000040121�14743153644�022423� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin Copyright (C) 2014-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SevenZipAdv; {$mode delphi} interface uses Classes, SysUtils, SevenZip, JclCompression; type TBytes = array of Byte; TCardinalArray = array of Cardinal; TJclCompressionArchiveClassArray = array of TJclCompressionArchiveClass; type { TArchiveFormat } TArchiveFormat = class Name: UnicodeString; Extension: UnicodeString; AddExtension: UnicodeString; Update: WordBool; KeepName: WordBool; ClassID: TGUID; StartSignature: TBytes; end; { TJclXzCompressArchiveEx } TJclXzCompressArchiveEx = class(TJclSevenzipCompressArchive) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; end; { TJclSevenzipUpdateArchiveHelper } TJclSevenzipUpdateArchiveHelper = class helper for TJclSevenzipUpdateArchive procedure RemoveDirectory(const PackedName: WideString); overload; end; { TJclSevenzipDecompressArchiveHelper } TJclSevenzipDecompressArchiveHelper = class helper for TJclSevenzipDecompressArchive procedure ProcessSelected(const SelectedArray: TCardinalArray; Verify: Boolean); end; function FindUpdateFormats(const AFileName: TFileName): TJclUpdateArchiveClassArray; function FindCompressFormats(const AFileName: TFileName): TJclCompressArchiveClassArray; function FindDecompressFormats(const AFileName: TFileName): TJclDecompressArchiveClassArray; function GetNestedArchiveName(const ArchiveName: String; Item: TJclCompressionItem): WideString; function ExpandEnvironmentStrings(const FileName: UnicodeString): UnicodeString; function WideExtractFilePath(const FileName: WideString): WideString; function GetModulePath(out ModulePath: AnsiString): Boolean; implementation uses CTypes, ActiveX, Windows, LazFileUtils, LazUTF8, SevenZipHlp; type TArchiveFormats = array of TArchiveFormat; TJclSevenzipUpdateArchiveClass = class of TJclSevenzipUpdateArchive; TJclSevenzipCompressArchiveClass = class of TJclSevenzipCompressArchive; TJclSevenzipDecompressArchiveClass = class of TJclSevenzipDecompressArchive; TJclArchiveType = (atUpdateArchive, atCompressArchive, atDecompressArchive); type TArchiveFormatCache = record ArchiveName: String; ArchiveClassArray: TJclCompressionArchiveClassArray; end; var Mutex: TRTLCriticalSection; ArchiveFormatsX: TArchiveFormats; var UpdateFormatsCache: TArchiveFormatCache; CompressFormatsCache: TArchiveFormatCache; DecompressFormatsCache: TArchiveFormatCache; function _wcsnicmp(const s1, s2: pwidechar; count: csize_t): cint; cdecl; external 'msvcrt.dll'; function ReadStringProp(FormatIndex: Cardinal; PropID: TPropID; out Value: UnicodeString): LongBool; var PropValue: TPropVariant; begin PropValue.vt:= VT_EMPTY; Result:= Succeeded(GetHandlerProperty2(FormatIndex, PropID, PropValue)); Result:= Result and (PropValue.vt = VT_BSTR); if Result then try Value:= BinaryToUnicode(PropValue.bstrVal); finally VarStringClear(PropValue); end; end; {$OPTIMIZATION OFF} function ReadBooleanProp(FormatIndex: Cardinal; PropID: TPropID; out Value: WordBool): LongBool; var PropValue: TPropVariant; begin PropValue.vt:= VT_EMPTY; Result:= Succeeded(GetHandlerProperty2(FormatIndex, PropID, PropValue)); Result:= Result and (PropValue.vt = VT_BOOL); if Result then Value:= PropValue.boolVal; end; {$OPTIMIZATION DEFAULT} procedure LoadArchiveFormats(var ArchiveFormats: TArchiveFormats); var Idx: Integer = 0; PropSize: Cardinal; PropValue: TPropVariant; ArchiveFormat: TArchiveFormat; Index, NumberOfFormats: Cardinal; begin if (not Is7ZipLoaded) and (not Load7Zip) then Exit; if not Succeeded(GetNumberOfFormats(@NumberOfFormats)) then Exit; SetLength(ArchiveFormats, NumberOfFormats); for Index := Low(ArchiveFormats) to High(ArchiveFormats) do begin PropValue.vt:= VT_EMPTY; // Archive format GUID if Succeeded(GetHandlerProperty2(Index, kClassID, PropValue)) then begin if PropValue.vt = VT_BSTR then try if SysStringByteLen(PropValue.bstrVal) <> SizeOf(TGUID) then Continue else begin ArchiveFormat:= TArchiveFormat.Create; ArchiveFormat.ClassID:= PGUID(PropValue.bstrVal)^; end; finally VarStringClear(PropValue); end; end; PropValue.vt:= VT_EMPTY; // Archive format signature if Succeeded(GetHandlerProperty2(Index, kStartSignature, PropValue)) then begin if PropValue.vt = VT_BSTR then try PropSize:= SysStringByteLen(PropValue.bstrVal); if (PropSize > 0) then begin SetLength(ArchiveFormat.StartSignature, PropSize); CopyMemory(@ArchiveFormat.StartSignature[0], PropValue.bstrVal, PropSize); end; finally VarStringClear(PropValue); end; end; ReadStringProp(Index, kArchiveName, ArchiveFormat.Name); ReadStringProp(Index, kExtension, ArchiveFormat.Extension); ReadStringProp(Index, kAddExtension, ArchiveFormat.AddExtension); ReadBooleanProp(Index, kUpdate, ArchiveFormat.Update); ReadBooleanProp(Index, kKeepName, ArchiveFormat.KeepName); ArchiveFormats[Idx]:= ArchiveFormat; Inc(Idx); end; SetLength(ArchiveFormats, Idx); end; function Contains(const ArrayToSearch: TJclCompressionArchiveClassArray; const ArchiveClass: TJclCompressionArchiveClass): Boolean; var Index: Integer; begin for Index := Low(ArrayToSearch) to High(ArrayToSearch) do if ArrayToSearch[Index] = ArchiveClass then Exit(True); Result := False; end; function FindArchiveFormat(const ClassID: TGUID; ArchiveType: TJclArchiveType): TJclCompressionArchiveClass; var Index: Integer; UpdateClass: TJclSevenzipUpdateArchiveClass; CompressClass: TJclSevenzipCompressArchiveClass; DecompressClass: TJclSevenzipDecompressArchiveClass; begin case ArchiveType of atUpdateArchive: for Index:= 0 to GetArchiveFormats.UpdateFormatCount - 1 do begin UpdateClass:= TJclSevenzipUpdateArchiveClass(GetArchiveFormats.UpdateFormats[Index]); if IsEqualGUID(ClassID, UpdateClass.ArchiveCLSID) then Exit(GetArchiveFormats.UpdateFormats[Index]); end; atCompressArchive: for Index:= 0 to GetArchiveFormats.CompressFormatCount - 1 do begin CompressClass:= TJclSevenzipCompressArchiveClass(GetArchiveFormats.CompressFormats[Index]); if IsEqualGUID(ClassID, CompressClass.ArchiveCLSID) then Exit(GetArchiveFormats.CompressFormats[Index]); end; atDecompressArchive: for Index:= 0 to GetArchiveFormats.DecompressFormatCount - 1 do begin DecompressClass:= TJclSevenzipDecompressArchiveClass(GetArchiveFormats.DecompressFormats[Index]); if IsEqualGUID(ClassID, DecompressClass.ArchiveCLSID) then Exit(GetArchiveFormats.DecompressFormats[Index]); end; end; Result:= nil; end; procedure FindArchiveFormats(const AFileName: TFileName; ArchiveType: TJclArchiveType; var Result: TJclCompressionArchiveClassArray); const BufferSize = 524288; var AFile: THandle; Buffer: TBytes; Idx, Index: Integer; ArchiveFormat: TArchiveFormat; ArchiveClass: TJclCompressionArchiveClass; begin if Length(ArchiveFormatsX) = 0 then LoadArchiveFormats(ArchiveFormatsX); AFile:= FileOpenUTF8(AFileName, fmOpenRead or fmShareDenyNone); if AFile = feInvalidHandle then Exit; try SetLength(Buffer, BufferSize); if FileRead(AFile, Buffer[0], BufferSize) = 0 then Exit; finally FileClose(AFile); end; for Index := Low(ArchiveFormatsX) to High(ArchiveFormatsX) do begin ArchiveFormat:= ArchiveFormatsX[Index]; if (not ArchiveFormat.Update) and (ArchiveType in [atUpdateArchive, atCompressArchive]) then Continue; // Skip container types if IsEqualGUID(ArchiveFormat.ClassID, CLSID_CFormatPe) then Continue; if IsEqualGUID(ArchiveFormat.ClassID, CLSID_CFormatIso) then Continue; if IsEqualGUID(ArchiveFormat.ClassID, CLSID_CFormatUdf) then Continue; if Length(ArchiveFormat.StartSignature) = 0 then Continue; for Idx:= 0 to Pred(BufferSize) - Length(ArchiveFormat.StartSignature) do begin if CompareMem(@Buffer[Idx], @ArchiveFormat.StartSignature[0], Length(ArchiveFormat.StartSignature)) then begin ArchiveClass:= FindArchiveFormat(ArchiveFormat.ClassID, ArchiveType); if Assigned(ArchiveClass) and not Contains(Result, ArchiveClass) then begin SetLength(Result, Length(Result) + 1); Result[High(Result)] := ArchiveClass; end; Break; end; end; end; end; function FindUpdateFormats(const AFileName: TFileName): TJclUpdateArchiveClassArray; var ArchiveClassArray: TJclCompressionArchiveClassArray absolute Result; begin System.EnterCriticalSection(Mutex); try // Try to find archive type in cache if UpdateFormatsCache.ArchiveName = AFileName then Exit(TJclUpdateArchiveClassArray(UpdateFormatsCache.ArchiveClassArray)) else begin UpdateFormatsCache.ArchiveName:= AFileName; SetLength(UpdateFormatsCache.ArchiveClassArray, 0); end; Result:= GetArchiveFormats.FindUpdateFormats(AFileName); FindArchiveFormats(AFileName, atUpdateArchive, ArchiveClassArray); // Save archive type in cache UpdateFormatsCache.ArchiveClassArray:= ArchiveClassArray; finally System.LeaveCriticalSection(Mutex); end; end; function FindCompressFormats(const AFileName: TFileName): TJclCompressArchiveClassArray; var ArchiveClassArray: TJclCompressionArchiveClassArray absolute Result; begin System.EnterCriticalSection(Mutex); try // Try to find archive type in cache if CompressFormatsCache.ArchiveName = AFileName then Exit(TJclCompressArchiveClassArray(CompressFormatsCache.ArchiveClassArray)) else begin CompressFormatsCache.ArchiveName:= AFileName; SetLength(CompressFormatsCache.ArchiveClassArray, 0); end; Result:= GetArchiveFormats.FindCompressFormats(AFileName); FindArchiveFormats(AFileName, atCompressArchive, ArchiveClassArray); // Save archive type in cache CompressFormatsCache.ArchiveClassArray:= ArchiveClassArray; finally System.LeaveCriticalSection(Mutex); end; end; function FindDecompressFormats(const AFileName: TFileName): TJclDecompressArchiveClassArray; var ArchiveClassArray: TJclCompressionArchiveClassArray absolute Result; begin System.EnterCriticalSection(Mutex); try // Try to find archive type in cache if DecompressFormatsCache.ArchiveName = AFileName then Exit(TJclDecompressArchiveClassArray(DecompressFormatsCache.ArchiveClassArray)) else begin DecompressFormatsCache.ArchiveName:= AFileName; SetLength(DecompressFormatsCache.ArchiveClassArray, 0); end; Result:= GetArchiveFormats.FindDecompressFormats(AFileName); FindArchiveFormats(AFileName, atDecompressArchive, ArchiveClassArray); // Save archive type in cache DecompressFormatsCache.ArchiveClassArray:= ArchiveClassArray; finally System.LeaveCriticalSection(Mutex); end; end; { TJclXzCompressArchiveEx } class function TJclXzCompressArchiveEx.ArchiveExtensions: string; begin Result:= TJclXzCompressArchive.ArchiveExtensions; end; class function TJclXzCompressArchiveEx.ArchiveName: string; begin Result:= TJclXzCompressArchive.ArchiveName; end; class function TJclXzCompressArchiveEx.ArchiveSubExtensions: string; begin Result:= TJclXzCompressArchive.ArchiveSubExtensions; end; class function TJclXzCompressArchiveEx.ArchiveCLSID: TGUID; begin Result:= TJclXzCompressArchive.ArchiveCLSID; end; { TJclSevenzipUpdateArchiveHelper } procedure TJclSevenzipUpdateArchiveHelper.RemoveDirectory(const PackedName: WideString); var DirectoryName: WideString; AItem: TJclCompressionItem; Index, PackedNamesIndex: Integer; begin DirectoryName:= Copy(PackedName, 1, Length(PackedName) - 1); // Remove directory for Index := 0 to ItemCount - 1 do begin AItem := Items[Index]; // Can be with or without path delimiter at end if WideSameText(AItem.PackedName, PackedName) or WideSameText(AItem.PackedName, DirectoryName) then begin FItems.Delete(Index); PackedNamesIndex := -1; if (FPackedNames <> nil) and FPackedNames.Find(PackedName, PackedNamesIndex) then FPackedNames.Delete(PackedNamesIndex); Break; end; end; // Remove directory content for Index := ItemCount - 1 downto 0 do begin if (_wcsnicmp(PWideChar(PackedName), PWideChar(Items[Index].PackedName), Length(PackedName)) = 0) then begin if (FPackedNames <> nil) and FPackedNames.Find(Items[Index].PackedName, PackedNamesIndex) then FPackedNames.Delete(PackedNamesIndex); FItems.Delete(Index); end; end; end; { TJclSevenzipDecompressArchiveHelper } procedure TJclSevenzipDecompressArchiveHelper.ProcessSelected(const SelectedArray: TCardinalArray; Verify: Boolean); var AExtractCallback: IArchiveExtractCallback; begin CheckNotDecompressing; FDecompressing := True; AExtractCallback := TJclSevenzipExtractCallback.Create(Self); try OpenArchive; SevenzipCheck(InArchive.Extract(@SelectedArray[0], Length(SelectedArray), Cardinal(Verify), AExtractCallback)); CheckOperationSuccess; finally FDestinationDir := ''; FDecompressing := False; AExtractCallback := nil; end; end; function GetNestedArchiveName(const ArchiveName: String; Item: TJclCompressionItem): WideString; var Extension: String; begin Result:= Item.NestedArchiveName; Extension:= LowerCase(ExtractFileExt(ArchiveName)); if (Extension = '.tbz') or (Extension = '.tgz') or (Extension = '.txz') then begin Result:= Result + '.tar'; end; end; function ExpandEnvironmentStrings(const FileName: UnicodeString): UnicodeString; var dwSize: DWORD; begin SetLength(Result, MAX_PATH + 1); dwSize:= ExpandEnvironmentStringsW(PWideChar(FileName), PWideChar(Result), MAX_PATH); if dwSize > 0 then SetLength(Result, dwSize - 1); end; function WideExtractFilePath(const FileName: WideString): WideString; var Index: Integer; begin for Index:= Length(FileName) downto 1 do case FileName[Index] of PathDelim: Exit(Copy(FileName, 1, Index)); end; Result:= EmptyWideStr; end; function GetModulePath(out ModulePath: AnsiString): Boolean; var lpBuffer: TMemoryBasicInformation; ModuleName: array[0..MAX_PATH] of WideChar; begin Result:= VirtualQuery(@GetModulePath, @lpBuffer, SizeOf(lpBuffer)) = SizeOf(lpBuffer); if Result then begin Result:= GetModuleFileNameW(THandle(lpBuffer.AllocationBase), ModuleName, MAX_PATH) > 0; if Result then begin ModulePath:= ExtractFilePath(Utf16ToUtf8(WideString(ModuleName))); end; end; end; initialization InitCriticalSection(Mutex); finalization DoneCriticalSection(Mutex); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipCodecs.pas����������������������������������������0000644�0001750�0000144�00000026563�14743153644�023127� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin Copyright (C) 2017-2023 Alexander Koblov (alexx2000@mail.ru) Based on Far Manager arclite plugin Copyright © 2000 Far Group All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } unit SevenZipCodecs; {$mode delphi} interface uses Classes, SysUtils, SevenZip, fgl, ActiveX, Windows, JclCompression; const cmMaximum = PtrInt(Ord(High(TJclCompressionMethod))); type { TLibraryInfo } TLibraryInfo = class public Handle: TLibHandle; CreateObject: TCreateObjectFunc; GetHandlerProperty2: TGetHandlerProperty2; GetHandlerProperty: TGetHandlerProperty; GetMethodProperty: TGetMethodProperty; GetNumberOfFormats: TGetNumberOfFormatsFunc; GetNumberOfMethods: TGetNumberOfMethodsFunc; SetLargePageMode: TSetLargePageMode; SetCodecs: function(compressCodecsInfo: ICompressCodecsInfo): HRESULT; stdcall; CreateDecoder: function(Index: Cardinal; IID: PGUID; out Decoder): HRESULT; stdcall; CreateEncoder: function(Index: Cardinal; IID: PGUID; out Coder): HRESULT; stdcall; end; { TCodecInfo } TCodecInfo = class LibraryIndex: Integer; CodecIndex: Integer; EncoderIsAssigned: LongBool; DecoderIsAssigned: LongBool; Encoder: CLSID; Decoder: CLSID; ID: Cardinal; Name: UnicodeString; end; { TCompressCodecsInfo } TCompressCodecsInfo = class(TInterfacedObject, ICompressCodecsInfo, IUnknown) private FCodecs: TFPGObjectList<TCodecInfo>; FLibraries: TFPGObjectList<TLibraryInfo>; public constructor Create(ACodecs: TFPGObjectList<TCodecInfo>; ALibraries: TFPGObjectList<TLibraryInfo>); public function GetNumberOfMethods(NumMethods: PCardinal): HRESULT; stdcall; function GetProperty(Index: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function CreateDecoder(Index: Cardinal; IID: PGUID; out Decoder): HRESULT; stdcall; function CreateEncoder(Index: Cardinal; IID: PGUID; out Coder): HRESULT; stdcall; end; procedure LoadLibraries; function GetCodecName(AMethod: Cardinal): WideString; var ACodecs: TFPGObjectList<TCodecInfo> = nil; implementation uses LazUTF8, FileUtil, SevenZipHlp; { TCompressCodecsInfo } constructor TCompressCodecsInfo.Create(ACodecs: TFPGObjectList<TCodecInfo>; ALibraries: TFPGObjectList<TLibraryInfo>); begin FCodecs:= ACodecs; FLibraries:= ALibraries; end; function TCompressCodecsInfo.GetNumberOfMethods(NumMethods: PCardinal): HRESULT; stdcall; begin NumMethods^:= FCodecs.Count; Result:= S_OK; end; function TCompressCodecsInfo.GetProperty(Index: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; var ACodecInfo: TCodecInfo; begin ACodecInfo:= FCodecs[Index]; if (PropID = kDecoderIsAssigned) then begin Value.vt:= VT_BOOL; Value.bool:= ACodecInfo.DecoderIsAssigned; Exit(S_OK); end else if (PropID = kEncoderIsAssigned) then begin Value.vt:= VT_BOOL; Value.bool:= ACodecInfo.EncoderIsAssigned; Exit(S_OK); end; Result:= FLibraries[ACodecInfo.LibraryIndex].GetMethodProperty(ACodecInfo.CodecIndex, PropID, Value); end; function TCompressCodecsInfo.CreateDecoder(Index: Cardinal; IID: PGUID; out Decoder): HRESULT; stdcall; var ACodecInfo: TCodecInfo; ALibraryInfo: TLibraryInfo; begin Result:= S_OK; ACodecInfo:= FCodecs[Index]; if (ACodecInfo.DecoderIsAssigned) then begin ALibraryInfo:= FLibraries[ACodecInfo.LibraryIndex]; if Assigned(ALibraryInfo.CreateDecoder) then Result:= ALibraryInfo.CreateDecoder(ACodecInfo.CodecIndex, IID, Decoder) else Result:= ALibraryInfo.CreateObject(@ACodecInfo.Decoder, IID, Decoder); end; end; function TCompressCodecsInfo.CreateEncoder(Index: Cardinal; IID: PGUID; out Coder): HRESULT; stdcall; var ACodecInfo: TCodecInfo; ALibraryInfo: TLibraryInfo; begin Result:= S_OK; ACodecInfo:= FCodecs[Index]; if (ACodecInfo.EncoderIsAssigned) then begin ALibraryInfo:= FLibraries[ACodecInfo.LibraryIndex]; if Assigned(ALibraryInfo.CreateEncoder) then Result:= ALibraryInfo.CreateEncoder(ACodecInfo.CodecIndex, IID, Coder) else Result:= ALibraryInfo.CreateObject(@ACodecInfo.Encoder, IID, Coder); end; end; function GetCoderInfo(GetMethodProperty: TGetMethodProperty; Index: UInt32; var AInfo: TCodecInfo): Boolean; var Value: TPropVariant; begin Value.vt:= VT_EMPTY; if (GetMethodProperty(Index, kDecoder, Value) <> S_OK) then Exit(False); if (Value.vt <> VT_EMPTY) then begin if (Value.vt <> VT_BSTR) then Exit(False); try if (SysStringByteLen(Value.bstrVal) < SizeOf(CLSID)) then begin Exit(False); end; AInfo.Decoder:= PGUID(Value.bstrVal)^; AInfo.DecoderIsAssigned:= True; finally VarStringClear(Value); end; end; if (GetMethodProperty(Index, kEncoder, Value) <> S_OK) then Exit(False); if (Value.vt <> VT_EMPTY) then begin if (Value.vt <> VT_BSTR) then Exit(False); try if (SysStringByteLen(Value.bstrVal) < SizeOf(CLSID)) then begin Exit(False); end; AInfo.Encoder:= PGUID(Value.bstrVal)^; AInfo.EncoderIsAssigned:= True; finally VarStringClear(Value); end; end; if (GetMethodProperty(Index, kID, Value) <> S_OK) then Exit(False); if (Value.vt <> VT_UI8) then Exit(False); AInfo.ID:= Value.uhVal.QuadPart; Value.vt:= VT_EMPTY; if (GetMethodProperty(Index, kName, Value) <> S_OK) then Exit(False); if (Value.vt = VT_BSTR) then try AInfo.Name:= BinaryToUnicode(Value.bstrVal); finally VarStringClear(Value); end; Result:= AInfo.DecoderIsAssigned or AInfo.EncoderIsAssigned; end; var ALibraries: TFPGObjectList<TLibraryInfo> = nil; procedure LoadCodecs; var Handle: TLibHandle; Index, J: Integer; AFiles: TStringList; ACodecCount: Integer; NumMethods: UInt32 = 1; ACodecInfo: TCodecInfo; ALibraryInfo: TLibraryInfo; ACompressInfo: ICompressCodecsInfo; begin AFiles:= FindAllFiles(ExtractFilePath(SevenzipLibraryName) + 'Codecs', '*.' + SharedSuffix); for Index:= 0 to AFiles.Count - 1 do begin Handle:= System.LoadLibrary(AFiles[Index]); if Handle <> 0 then begin ALibraryInfo:= TLibraryInfo.Create; ALibraryInfo.Handle:= Handle; ALibraryInfo.CreateObject:= GetProcAddress(Handle, 'CreateObject'); ALibraryInfo.CreateDecoder:= GetProcAddress(Handle, 'CreateDecoder'); ALibraryInfo.CreateEncoder:= GetProcAddress(Handle, 'CreateEncoder'); ALibraryInfo.GetNumberOfMethods:= GetProcAddress(Handle, 'GetNumberOfMethods'); ALibraryInfo.GetMethodProperty:= GetProcAddress(Handle, 'GetMethodProperty'); if (Assigned(ALibraryInfo.CreateObject) or Assigned(ALibraryInfo.CreateDecoder) or Assigned(ALibraryInfo.CreateEncoder)) and Assigned(ALibraryInfo.GetMethodProperty) then begin ACodecCount:= ACodecs.Count; if Assigned(ALibraryInfo.GetNumberOfMethods) then begin if ALibraryInfo.GetNumberOfMethods(@NumMethods) = S_OK then begin for J := 0 to Int32(NumMethods) - 1 do begin ACodecInfo:= TCodecInfo.Create; ACodecInfo.LibraryIndex:= ALibraries.Count; ACodecInfo.CodecIndex:= J; if (GetCoderInfo(ALibraryInfo.GetMethodProperty, J, ACodecInfo)) then ACodecs.Add(ACodecInfo) else ACodecInfo.Free; end; end; end; // GetNumberOfMethods if (ACodecCount < ACodecs.Count) then ALibraries.Add(ALibraryInfo) else begin ALibraryInfo.Free; FreeLibrary(Handle); end; end; end; end; AFiles.Free; if (ACodecs.Count > 0) then begin ACompressInfo:= TCompressCodecsInfo.Create(ACodecs, ALibraries); for Index:= 0 to ALibraries.Count - 1 do begin if Assigned(ALibraries[Index].SetCodecs) then ALibraries[Index].SetCodecs(ACompressInfo); end; end; end; procedure LoadLibraries; var ALibraryInfo: TLibraryInfo; begin ACodecs:= TFPGObjectList<TCodecInfo>.Create; ALibraries:= TFPGObjectList<TLibraryInfo>.Create; // Add default library ALibraryInfo:= TLibraryInfo.Create; ALibraryInfo.Handle:= SevenzipLibraryHandle; ALibraryInfo.CreateObject:= SevenZip.CreateObject; ALibraryInfo.GetHandlerProperty2:= SevenZip.GetHandlerProperty2; ALibraryInfo.GetHandlerProperty:= SevenZip.GetHandlerProperty; ALibraryInfo.GetMethodProperty:= SevenZip.GetMethodProperty; ALibraryInfo.GetNumberOfFormats:= SevenZip.GetNumberOfFormats; ALibraryInfo.GetNumberOfMethods:= SevenZip.GetNumberOfMethods; ALibraryInfo.SetLargePageMode:= SevenZip.SetLargePageMode; ALibraryInfo.SetCodecs:= GetProcAddress(SevenzipLibraryHandle, 'SetCodecs'); ALibraryInfo.CreateDecoder:= GetProcAddress(SevenzipLibraryHandle, 'CreateDecoder'); ALibraryInfo.CreateEncoder:= GetProcAddress(SevenzipLibraryHandle, 'CreateEncoder'); ALibraries.Add(ALibraryInfo); // Load external codecs LoadCodecs; end; function GetCodecName(AMethod: Cardinal): WideString; var Index: Integer; begin if Assigned(ACodecs) then begin for Index:= 0 to ACodecs.Count - 1 do begin if (ACodecs[Index].ID = AMethod) then Exit(ACodecs[Index].Name); end; end; Result:= EmptyWideStr; end; procedure Finish; var Index: Integer; begin if Assigned(ALibraries) then begin for Index:= 0 to ALibraries.Count - 1 do begin if Assigned(ALibraries[Index].SetCodecs) then ALibraries[Index].SetCodecs(nil); FreeLibrary(ALibraries[Index].Handle); end; end; end; finalization Finish; end. ���������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipDlg.pas�������������������������������������������0000644�0001750�0000144�00000062513�14743153644�022430� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin, dialogs unit Copyright (C) 2014-2017 Alexander Koblov (alexx2000@mail.ru) Based on 7-Zip 15.06 (http://7-zip.org) 7-Zip Copyright (C) 1999-2015 Igor Pavlov This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SevenZipDlg; {$mode delphi} interface uses Classes, SysUtils, Windows, Math, SevenZipOpt, SevenZipLng, JclCompression; procedure ShowConfigurationDialog(Parent: HWND); function ShowPasswordQuery(var Encrypt: Boolean; var Password: WideString): Boolean; implementation uses LazUTF8, SevenZipCodecs; {$R *.res} const IDC_PASSWORD = 1001; IDC_SHOW_PASSWORD = 1002; IDC_ENCRYPT_HEADER = 0; const IDC_APPLY_BUTTON = 9; IDC_COMP_FORMAT = 1076; IDC_COMP_METHOD = 1078; IDC_COMP_LEVEL = 1074; IDC_VOLUME_SIZE = 1077; IDC_COMP_DICT = 1079; IDC_COMP_WORD = 1080; IDC_COMP_SOLID = 1081; IDC_COMP_THREAD = 1082; IDC_MAX_THREAD = 1083; IDC_PARAMETERS = 1091; IDC_MEMORY_COMP = 1027; IDC_MEMORY_DECOMP = 1028; function GetComboBox(hwndDlg: HWND; ItemID: Integer): PtrInt; var Index: Integer; begin Index:= SendDlgItemMessage(hwndDlg, ItemID, CB_GETCURSEL, 0, 0); Result:= SendDlgItemMessage(hwndDlg, ItemID, CB_GETITEMDATA, Index, 0); end; procedure SetComboBox(hwndDlg: HWND; ItemID: Integer; ItemData: PtrInt); var Index, Count: Integer; begin Count:= SendDlgItemMessage(hwndDlg, ItemID, CB_GETCOUNT, 0, 0); for Index:= 0 to Count - 1 do begin if SendDlgItemMessage(hwndDlg, ItemID, CB_GETITEMDATA, Index, 0) = ItemData then begin SendDlgItemMessage(hwndDlg, ItemID, CB_SETCURSEL, Index, 0); Exit; end; end; end; procedure SaveArchiver(hwndDlg: HWND); var Format: TArchiveFormat; Parameters: array[0..MAX_PATH] of WideChar; begin Format:= TArchiveFormat(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); PluginConfig[Format].Level:= GetComboBox(hwndDlg, IDC_COMP_LEVEL); PluginConfig[Format].Method:= GetComboBox(hwndDlg, IDC_COMP_METHOD); if PluginConfig[Format].Level <> PtrInt(clStore) then begin PluginConfig[Format].Dictionary:= GetComboBox(hwndDlg, IDC_COMP_DICT); PluginConfig[Format].WordSize:= GetComboBox(hwndDlg, IDC_COMP_WORD); PluginConfig[Format].SolidSize:= GetComboBox(hwndDlg, IDC_COMP_SOLID); PluginConfig[Format].ThreadCount:= GetComboBox(hwndDlg, IDC_COMP_THREAD); end; GetDlgItemTextW(hwndDlg, IDC_PARAMETERS, Parameters, MAX_PATH); PluginConfig[Format].Parameters:= Parameters; SaveConfiguration; end; function ComboBoxAdd(hwndDlg: HWND; ItemID: Integer; ItemText: String; ItemData: PtrInt): Integer; var Text: UnicodeString; begin Text:= UTF8ToUTF16(ItemText); Result:= SendDlgItemMessageW(hwndDlg, ItemID, CB_ADDSTRING, 0, LPARAM(PWideChar(Text))); SendDlgItemMessage(hwndDlg, ItemID, CB_SETITEMDATA, Result, ItemData); end; function GetMemoryUsage(hwndDlg: HWND; out decompressMemory: Int64): Int64; var size: Int64 = 0; Dictionary, hs, numThreads, numThreads1, numBlockThreads: Cardinal; size1, chunkSize: Int64; Level: TCompressionLevel; Method: TJclCompressionMethod; begin Level := TCompressionLevel(GetComboBox(hwndDlg, IDC_COMP_LEVEL)); if (level = clStore) then begin decompressMemory := (1 shl 20); Exit(decompressMemory); end; decompressMemory := -1; Dictionary := Cardinal(GetComboBox(hwndDlg, IDC_COMP_DICT)); Method := TJclCompressionMethod(GetComboBox(hwndDlg, IDC_COMP_METHOD)); if (Method <> cmDeflate) and (Method <> cmDeflate64) and (level >= clUltra) then size += (12 shl 20) * 2 + (5 shl 20); numThreads := GetComboBox(hwndDlg, IDC_COMP_THREAD); case (method) of cmLZMA, cmLZMA2: begin hs := dictionary - 1; hs := hs or (hs shr 1); hs := hs or (hs shr 2); hs := hs or (hs shr 4); hs := hs or (hs shr 8); hs := hs shr 1; hs := hs or $FFFF; if (hs > (1 shl 24)) then hs := hs shr 1; Inc(hs); size1 := Int64(hs) * 4; size1 += Int64(dictionary) * 4; if (level >= clNormal) then size1 += Int64(dictionary) * 4; size1 += (2 shl 20); numThreads1 := 1; if (numThreads > 1) and (level >= clNormal) then begin size1 += (2 shl 20) + (4 shl 20); numThreads1 := 2; end; numBlockThreads := numThreads div numThreads1; if (method = cmLZMA) or (numBlockThreads = 1) then size1 += Int64(dictionary) * 3 div 2 else begin chunkSize := Int64(dictionary) shl 2; chunkSize := Max(chunkSize, Int64(1 shl 20)); chunkSize := Min(chunkSize, Int64(1 shl 28)); chunkSize := Max(chunkSize, Int64(dictionary)); size1 += chunkSize * 2; end; size += size1 * numBlockThreads; decompressMemory := Int64(dictionary) + (2 shl 20); Exit(size); end; cmPPMd: begin decompressMemory := Int64(dictionary) + (2 shl 20); Exit(size + decompressMemory); end; cmDeflate, cmDeflate64: begin if (level >= clMaximum) then size += (1 shl 20); size += 3 shl 20; decompressMemory := (2 shl 20); Exit(size); end; cmBZip2: begin decompressMemory := (7 shl 20); size1 := (10 shl 20); Exit(size + size1 * numThreads); end; end; Result := -1; end; procedure UpdateMemoryUsage(hwndDlg: HWND); var Comp, Decomp: Int64; begin if (GetComboBox(hwndDlg, IDC_COMP_METHOD) > cmMaximum) then begin SetDlgItemText(hwndDlg, IDC_MEMORY_COMP, '?'); SetDlgItemText(hwndDlg, IDC_MEMORY_DECOMP, '?'); end else begin Comp := GetMemoryUsage(hwndDlg, Decomp); SetDlgItemText(hwndDlg, IDC_MEMORY_COMP, PAnsiChar(IntToStr(Comp div cMega) + 'Mb')); SetDlgItemText(hwndDlg, IDC_MEMORY_DECOMP, PAnsiChar(IntToStr(Decomp div cMega) + 'Mb')); end; end; procedure SetDefaultOptions(hwndDlg: HWND); var Value: PtrInt; Level: TCompressionLevel; Method: TJclCompressionMethod; begin Value:= GetComboBox(hwndDlg, IDC_COMP_METHOD); if (Value <= cmMaximum) then begin // Get compression method Method:= TJclCompressionMethod(Value); // Get compression level Level:= TCompressionLevel(GetComboBox(hwndDlg, IDC_COMP_LEVEL)); case Method of cmDeflate, cmDeflate64: begin case Level of clFastest, clFast, clNormal: SetComboBox(hwndDlg, IDC_COMP_WORD, 32); clMaximum: SetComboBox(hwndDlg, IDC_COMP_WORD, 64); clUltra: SetComboBox(hwndDlg, IDC_COMP_WORD, 128); end; SendDlgItemMessage(hwndDlg, IDC_COMP_DICT, CB_SETCURSEL, 0, 0); end; cmBZip2: begin case Level of clFastest: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 100 * cKilo); SetComboBox(hwndDlg, IDC_COMP_SOLID, 8 * cKilo); end; clFast: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 500 * cKilo); SetComboBox(hwndDlg, IDC_COMP_SOLID, 32 * cKilo); end; clNormal, clMaximum, clUltra: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 900 * cKilo); SetComboBox(hwndDlg, IDC_COMP_SOLID, 64 * cKilo); end; end; end; cmLZMA, cmLZMA2: begin case Level of clFastest: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 64 * cKilo); SetComboBox(hwndDlg, IDC_COMP_WORD, 32); SetComboBox(hwndDlg, IDC_COMP_SOLID, 8 * cKilo); end; clFast: begin SetComboBox(hwndDlg, IDC_COMP_DICT, cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 32); SetComboBox(hwndDlg, IDC_COMP_SOLID, 128 * cKilo); end; clNormal: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 16 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 32); SetComboBox(hwndDlg, IDC_COMP_SOLID, 2 * cMega); end; clMaximum: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 32 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 64); SetComboBox(hwndDlg, IDC_COMP_SOLID, 4 * cMega); end; clUltra: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 64 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 64); SetComboBox(hwndDlg, IDC_COMP_SOLID, 4 * cMega); end; end; end; cmPPMd: begin case Level of clFastest, clFast: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 4 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 4); SetComboBox(hwndDlg, IDC_COMP_SOLID, 512 * cKilo); end; clNormal: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 16 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 6); SetComboBox(hwndDlg, IDC_COMP_SOLID, 2 * cMega); end; clMaximum: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 64 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 16); SetComboBox(hwndDlg, IDC_COMP_SOLID, 4 * cMega); end; clUltra: begin SetComboBox(hwndDlg, IDC_COMP_DICT, 192 * cMega); SetComboBox(hwndDlg, IDC_COMP_WORD, 16); SetComboBox(hwndDlg, IDC_COMP_SOLID, 4 * cMega); end; end; end; end; end; UpdateMemoryUsage(hwndDlg); end; procedure UpdateSolid(hwndDlg: HWND); var Index: Integer; Format: TArchiveFormat; Level: TCompressionLevel; begin SendDlgItemMessage(hwndDlg, IDC_COMP_SOLID, CB_RESETCONTENT, 0, 0); // Get compression level Level:= TCompressionLevel(GetComboBox(hwndDlg, IDC_COMP_LEVEL)); Format:= TArchiveFormat(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); if (Format in [afSevenZip]) and (Level <> clStore) then begin ComboBoxAdd(hwndDlg, IDC_COMP_SOLID, rsSolidBlockNonSolid, kNoSolidBlockSize); for Index:= Low(SolidBlock) to High(SolidBlock) do begin ComboBoxAdd(hwndDlg, IDC_COMP_SOLID, FormatFileSize(Int64(SolidBlock[Index]) * cKilo), PtrInt(SolidBlock[Index])); end; ComboBoxAdd(hwndDlg, IDC_COMP_SOLID, rsSolidBlockSolid, kSolidBlockSize); end; end; procedure UpdateThread(hwndDlg: HWND; dwAlgoThreadMax: LongWord); var Index: LongWord; dwMaxThread: LongWord; dwDefaultValue: DWORD; wsMaxThread: WideString; dwHardwareThreads: DWORD; begin SendDlgItemMessage(hwndDlg, IDC_COMP_THREAD, CB_RESETCONTENT, 0, 0); dwHardwareThreads:= GetNumberOfProcessors; dwDefaultValue:= dwHardwareThreads; dwMaxThread:= dwHardwareThreads * 2; if dwMaxThread > dwAlgoThreadMax then dwMaxThread:= dwAlgoThreadMax; if dwAlgoThreadMax < dwDefaultValue then dwDefaultValue:= dwAlgoThreadMax; for Index:= 1 to dwMaxThread do begin ComboBoxAdd(hwndDlg, IDC_COMP_THREAD, IntToStr(Index), Index); end; wsMaxThread:= '/ ' + WideString(IntToStr(dwHardwareThreads)); SendDlgItemMessage(hwndDlg, IDC_COMP_THREAD, CB_SETCURSEL, dwDefaultValue - 1, 0); SendDlgItemMessageW(hwndDlg, IDC_MAX_THREAD, WM_SETTEXT, 0, LPARAM(PWideChar(wsMaxThread))); end; procedure UpdateMethod(hwndDlg: HWND); var Index: PtrInt; Format: TArchiveFormat; dwAlgoThreadMax: LongWord = 1; Method: TJclCompressionMethod; begin // Clear comboboxes SendDlgItemMessage(hwndDlg, IDC_COMP_DICT, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(hwndDlg, IDC_COMP_WORD, CB_RESETCONTENT, 0, 0); Format:= TArchiveFormat(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_DICT), not (Format in [afTar, afWim])); // Get Compression method Index:= GetComboBox(hwndDlg, IDC_COMP_METHOD); if Index > cmMaximum then begin dwAlgoThreadMax:= GetNumberOfProcessors; EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_DICT), False); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_WORD), False); end else begin Method:= TJclCompressionMethod(Index); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_WORD), (Format in [afSevenZip, afGzip, afXz, afZip]) and (Method <> cmBZip2)); case Method of cmDeflate: begin for Index:= Low(DeflateDict) to High(DeflateDict) do begin ComboBoxAdd(hwndDlg, IDC_COMP_DICT, FormatFileSize(DeflateDict[Index]), PtrInt(DeflateDict[Index])); end; for Index:= Low(DeflateWordSize) to High(DeflateWordSize) do begin ComboBoxAdd(hwndDlg, IDC_COMP_WORD, IntToStr(DeflateWordSize[Index]), PtrInt(DeflateWordSize[Index])); end; end; cmDeflate64: begin for Index:= Low(Deflate64Dict) to High(Deflate64Dict) do begin ComboBoxAdd(hwndDlg, IDC_COMP_DICT, FormatFileSize(Deflate64Dict[Index]), PtrInt(Deflate64Dict[Index])); end; for Index:= Low(Deflate64WordSize) to High(Deflate64WordSize) do begin ComboBoxAdd(hwndDlg, IDC_COMP_WORD, IntToStr(Deflate64WordSize[Index]), PtrInt(Deflate64WordSize[Index])); end; end; cmLZMA, cmLZMA2: begin for Index:= Low(LZMADict) to High(LZMADict) do begin ComboBoxAdd(hwndDlg, IDC_COMP_DICT, FormatFileSize(LZMADict[Index], False), PtrInt(LZMADict[Index])); end; for Index:= Low(LZMAWordSize) to High(LZMAWordSize) do begin ComboBoxAdd(hwndDlg, IDC_COMP_WORD, IntToStr(LZMAWordSize[Index]), PtrInt(LZMAWordSize[Index])); end; dwAlgoThreadMax:= IfThen(Method = cmLZMA, 2, 32); end; cmBZip2: begin for Index:= Low(BZip2Dict) to High(BZip2Dict) do begin ComboBoxAdd(hwndDlg, IDC_COMP_DICT, FormatFileSize(BZip2Dict[Index]), PtrInt(BZip2Dict[Index])); end; dwAlgoThreadMax:= 32; end; cmPPMd: begin for Index:= Low(PPMdDict) to High(PPMdDict) do begin ComboBoxAdd(hwndDlg, IDC_COMP_DICT, FormatFileSize(PPMdDict[Index], False), PtrInt(PPMdDict[Index])); end; for Index:= Low(PPMdWordSize) to High(PPMdWordSize) do begin ComboBoxAdd(hwndDlg, IDC_COMP_WORD, IntToStr(PPMdWordSize[Index]), PtrInt(PPMdWordSize[Index])); end; end; end; if Format = afZip then dwAlgoThreadMax:= 128; end; UpdateThread(hwndDlg, dwAlgoThreadMax); end; procedure FillMethod(hwndDlg: HWND); var Index: Integer; Format: TArchiveFormat; begin // Clear combobox SendDlgItemMessage(hwndDlg, IDC_COMP_METHOD, CB_RESETCONTENT, 0, 0); Format:= TArchiveFormat(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); case Format of afSevenZip: begin // Fill compression method ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'LZMA', PtrInt(cmLZMA)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'LZMA2', PtrInt(cmLZMA2)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'PPMd', PtrInt(cmPPMd)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'BZip2', PtrInt(cmBZip2)); if Assigned(ACodecs) then begin for Index:= 0 to ACodecs.Count - 1 do begin ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, ACodecs[Index].Name, PtrInt(ACodecs[Index].ID)); end; end; SetComboBox(hwndDlg, IDC_COMP_METHOD, PluginConfig[Format].Method); end; afBzip2: begin // Fill compression method ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'BZip2', PtrInt(cmBZip2)); SendDlgItemMessage(hwndDlg, IDC_COMP_METHOD, CB_SETCURSEL, 0, 0); end; afGzip: begin // Fill compression method ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'Deflate', PtrInt(cmDeflate)); SendDlgItemMessage(hwndDlg, IDC_COMP_METHOD, CB_SETCURSEL, 0, 0); end; afXz: begin // Fill compression method ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'LZMA2', PtrInt(cmLZMA2)); SendDlgItemMessage(hwndDlg, IDC_COMP_METHOD, CB_SETCURSEL, 0, 0); end; afZip: begin // Fill compression method ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'Deflate', PtrInt(cmDeflate)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'Deflate64', PtrInt(cmDeflate64)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'BZip2', PtrInt(cmBZip2)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'LZMA', PtrInt(cmLZMA)); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, 'PPMd', PtrInt(cmPPMd)); end; end; end; procedure UpdateFormat(hwndDlg: HWND); var Format: TArchiveFormat; begin // Clear comboboxes SendDlgItemMessage(hwndDlg, IDC_COMP_LEVEL, CB_RESETCONTENT, 0, 0); // Get archive format Format:= TArchiveFormat(GetComboBox(hwndDlg, IDC_COMP_FORMAT)); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, LONG_PTR(Format)); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_SOLID), Format = afSevenZip); // 7Zip and Zip if Format in [afSevenZip, afZip] then begin // Fill compression level ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelStore, PtrInt(clStore)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelFastest, PtrInt(clFastest)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelFast, PtrInt(clFast)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelNormal, PtrInt(clNormal)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelMaximum, PtrInt(clMaximum)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelUltra, PtrInt(clUltra)); end else if Format in [afBzip2, afXz] then begin // Fill compression level ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelFastest, PtrInt(clFastest)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelFast, PtrInt(clFast)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelNormal, PtrInt(clNormal)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelMaximum, PtrInt(clMaximum)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelUltra, PtrInt(clUltra)); end else if Format in [afGzip] then begin // Fill compression level ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelFast, PtrInt(clFast)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelNormal, PtrInt(clNormal)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelMaximum, PtrInt(clMaximum)); ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelUltra, PtrInt(clUltra)); end else begin // Fill compression level ComboBoxAdd(hwndDlg, IDC_COMP_LEVEL, rsCompressionLevelStore, PtrInt(clStore)); end; FillMethod(hwndDlg); end; procedure UpdateLevel(hwndDlg: HWND; First: Boolean); var MethodStd: Boolean; Format: TArchiveFormat; Level: TCompressionLevel; begin Format:= TArchiveFormat(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); // Get compression level Level:= TCompressionLevel(GetComboBox(hwndDlg, IDC_COMP_LEVEL)); // Get compression method MethodStd:= (GetComboBox(hwndDlg, IDC_COMP_METHOD) <= cmMaximum); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_DICT), (Level <> clStore) and MethodStd); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_WORD), (Level <> clStore) and MethodStd); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_SOLID), (Format = afSevenZip) and (Level <> clStore)); if Level = clStore then begin SendDlgItemMessage(hwndDlg, IDC_COMP_METHOD, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(hwndDlg, IDC_COMP_DICT, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(hwndDlg, IDC_COMP_WORD, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(hwndDlg, IDC_COMP_SOLID, CB_RESETCONTENT, 0, 0); ComboBoxAdd(hwndDlg, IDC_COMP_METHOD, MethodName[cmCopy], PtrInt(cmCopy)); SendDlgItemMessage(hwndDlg, IDC_COMP_METHOD, CB_SETCURSEL, 0, 0); UpdateThread(hwndDlg, 1); end else if not First then begin FillMethod(hwndDlg); PluginConfig[Format].Method:= DefaultConfig[Format].Method; SetComboBox(hwndDlg, IDC_COMP_METHOD, PluginConfig[Format].Method); UpdateMethod(hwndDlg); UpdateSolid(hwndDlg); EnableWindow(GetDlgItem(hwndDlg, IDC_COMP_SOLID), Format = afSevenZip); end; end; procedure SelectFormat(hwndDlg: HWND); var Format: TArchiveFormat; begin UpdateFormat(hwndDlg); Format:= TArchiveFormat(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); SetComboBox(hwndDlg, IDC_COMP_LEVEL, PluginConfig[Format].Level); SetComboBox(hwndDlg, IDC_COMP_METHOD, PluginConfig[Format].Method); UpdateMethod(hwndDlg); UpdateLevel(hwndDlg, True); UpdateSolid(hwndDlg); SetComboBox(hwndDlg, IDC_COMP_DICT, PluginConfig[Format].Dictionary); SetComboBox(hwndDlg, IDC_COMP_WORD, PluginConfig[Format].WordSize); SetComboBox(hwndDlg, IDC_COMP_SOLID, PluginConfig[Format].SolidSize); SetComboBox(hwndDlg, IDC_COMP_THREAD, PluginConfig[Format].ThreadCount); SetDlgItemTextW(hwndDlg, IDC_PARAMETERS, PWideChar(PluginConfig[Format].Parameters)); UpdateMemoryUsage(hwndDlg); end; function DialogProc(hwndDlg: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): INT_PTR; stdcall; var Index: TArchiveFormat; begin case uMsg of WM_INITDIALOG: begin EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_SIZE), False); for Index:= Low(ArchiveExtension) to High(ArchiveExtension) do ComboBoxAdd(hwndDlg, IDC_COMP_FORMAT, ArchiveExtension[Index], PtrInt(Index)); SendDlgItemMessage(hwndDlg, IDC_COMP_FORMAT, CB_SETCURSEL, 0, 0); SelectFormat(hwndDlg); Result:= 1; end; WM_COMMAND: begin case LOWORD(wParam) of IDC_COMP_FORMAT: begin if (HIWORD(wParam) = CBN_SELCHANGE) then begin SelectFormat(hwndDlg); end; end; IDC_COMP_METHOD: if (HIWORD(wParam) = CBN_SELCHANGE) then begin UpdateMethod(hwndDlg); SetDefaultOptions(hwndDlg); end; IDC_COMP_LEVEL: if (HIWORD(wParam) = CBN_SELCHANGE) then begin UpdateLevel(hwndDlg, False); SetDefaultOptions(hwndDlg); end; IDC_COMP_DICT, IDC_COMP_WORD, IDC_COMP_THREAD: if (HIWORD(wParam) = CBN_SELCHANGE) then begin UpdateMemoryUsage(hwndDlg); end; IDOK: begin SaveArchiver(hwndDlg); EndDialog(hwndDlg, IDOK); end; IDCANCEL: EndDialog(hwndDlg, IDCANCEL); IDC_APPLY_BUTTON: SaveArchiver(hwndDlg); end; end; WM_CLOSE: begin EndDialog(hwndDlg, 0); end else begin Result:= 0; end; end; end; function PasswordDialog(hwndDlg: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): INT_PTR; stdcall; var PasswordData: PPasswordData; begin case uMsg of WM_INITDIALOG: begin PasswordData:= PPasswordData(lParam); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, LONG_PTR(lParam)); SetDlgItemTextW(hwndDlg, IDC_PASSWORD, PasswordData^.Password); SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, MAX_PATH, 0); EnableWindow(GetDlgItem(hwndDlg, IDC_ENCRYPT_HEADER), PasswordData^.EncryptHeader); Exit(1); end; WM_COMMAND: begin case LOWORD(wParam) of IDOK: begin PasswordData:= PPasswordData(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); PasswordData^.EncryptHeader:= IsDlgButtonChecked(hwndDlg, IDC_ENCRYPT_HEADER) <> 0; GetDlgItemTextW(hwndDlg, IDC_PASSWORD, PasswordData^.Password, MAX_PATH); EndDialog(hwndDlg, IDOK); end; IDCANCEL: EndDialog(hwndDlg, IDCANCEL); IDC_SHOW_PASSWORD: begin wParam:= (not IsDlgButtonChecked(hwndDlg, IDC_SHOW_PASSWORD) and $01) * $2A; SendDlgItemMessageW(hwndDlg, IDC_PASSWORD, EM_SETPASSWORDCHAR, wParam, 0); RedrawWindow(hwndDlg, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW); end; end; end; end; Result:= 0; end; function ShowPasswordQuery(var Encrypt: Boolean; var Password: WideString): Boolean; var PasswordData: TPasswordData; begin PasswordData.Password:= Password; PasswordData.EncryptHeader:= Encrypt; Result:= (DialogBoxParam(hInstance, 'DIALOG_PWD', 0, @PasswordDialog, LPARAM(@PasswordData)) = IDOK); if Result then begin Password:= PasswordData.Password; Encrypt:= PasswordData.EncryptHeader; end; end; procedure ShowConfigurationDialog(Parent: HWND); begin DialogBox(hInstance, 'DIALOG_CFG', Parent, @DialogProc); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipDlg.rc��������������������������������������������0000644�0001750�0000144�00000017074�14743153644�022253� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������D�I�A�L�O�G�_�C�F�G� �D�I�A�L�O�G� �M�O�V�E�A�B�L�E� �P�U�R�E� �L�O�A�D�O�N�C�A�L�L� �D�I�S�C�A�R�D�A�B�L�E� �0�,� �0�,� �2�2�1�,� �2�8�9� � �S�T�Y�L�E� �D�S�_�S�E�T�F�O�N�T� �|�D�S�_�M�O�D�A�L�F�R�A�M�E� �|�D�S�_�C�E�N�T�E�R� �|�W�S�_�P�O�P�U�P� �|�W�S�_�S�Y�S�M�E�N�U� �|�W�S�_�C�A�P�T�I�O�N� � � �C�A�P�T�I�O�N� �"�O�p�t�i�o�n�s�"� � �F�O�N�T� �8�,� �"�M�S� �S�h�e�l�l� �D�l�g�"� � �L�A�N�G�U�A�G�E� �L�A�N�G�_�E�N�G�L�I�S�H�,� �1� � �B�E�G�I�N� � � � �C�O�N�T�R�O�L� �"�A�r�c�h�i�v�e� �&�f�o�r�m�a�t�:�"�,�1�0�9�8�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�1�1�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�7�6�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�C�B�S�_�S�O�R�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�9�,�8�8�,�8�0� � � � �C�O�N�T�R�O�L� �"�C�o�m�p�r�e�s�s�i�o�n� �&�l�e�v�e�l�:�"�,�1�0�9�9�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�3�2�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�7�4�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�3�0�,�8�8�,�8�0� � � � �C�O�N�T�R�O�L� �"�C�o�m�p�r�e�s�s�i�o�n� �&�m�e�t�h�o�d�:�"�,�1�1�0�4�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�5�3�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�7�8�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�5�1�,�8�8�,�8�0� � � � �C�O�N�T�R�O�L� �"�&�D�i�c�t�i�o�n�a�r�y� �s�i�z�e�:�"�,�1�1�0�5�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�7�4�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�7�9�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�7�2�,�8�8�,�1�6�7� � � � �C�O�N�T�R�O�L� �"�&�W�o�r�d� �s�i�z�e�:�"�,�1�1�0�6�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�9�5�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�8�0�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�9�3�,�8�8�,�1�4�1� � � � �C�O�N�T�R�O�L� �"�&�S�o�l�i�d� �B�l�o�c�k� �s�i�z�e�:�"�,�1�1�0�7�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�1�1�6�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�8�1�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�1�1�4�,�8�8�,�1�4�0� � � � �C�O�N�T�R�O�L� �"�&�N�u�m�b�e�r� �o�f� �C�P�U� �t�h�r�e�a�d�s�:�"�,�1�1�0�8�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�1�3�7�,�1�0�4�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�8�2�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N�L�I�S�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�1�4�,�1�3�5�,�5�3�,�1�4�0� � � � �C�O�N�T�R�O�L� �"�1�"�,�1�0�8�3�,�"�S�T�A�T�I�C�"�,�S�S�_�R�I�G�H�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�7�7�,�1�3�7�,�2�5�,�8� � � � �C�O�N�T�R�O�L� �"�M�e�m�o�r�y� �u�s�a�g�e� �f�o�r� �C�o�m�p�r�e�s�s�i�n�g�:�"�,�1�0�2�2�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�1�6�0�,�1�5�2�,�8� � � � �C�O�N�T�R�O�L� �"�0�"�,�1�0�2�7�,�"�S�T�A�T�I�C�"�,�S�S�_�R�I�G�H�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�6�2�,�1�6�0�,�4�0�,�8� � � � �C�O�N�T�R�O�L� �"�M�e�m�o�r�y� �u�s�a�g�e� �f�o�r� �D�e�c�o�m�p�r�e�s�s�i�n�g�:�"�,�1�0�2�3�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�1�7�6�,�1�5�2�,�8� � � � �C�O�N�T�R�O�L� �"�0�"�,�1�0�2�8�,�"�S�T�A�T�I�C�"�,�S�S�_�R�I�G�H�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�6�2�,�1�7�6�,�4�0�,�8� � � � �C�O�N�T�R�O�L� �"�S�p�l�i�t� �t�o� �&�v�o�l�u�m�e�s�,� �b�y�t�e�s�:�"�,�1�1�0�3�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�1�9�5�,�1�9�2�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�7�7�,�"�C�O�M�B�O�B�O�X�"�,�C�B�S�_�D�R�O�P�D�O�W�N� �|�C�B�S�_�A�U�T�O�H�S�C�R�O�L�L� �|�W�S�_�C�H�I�L�D� �|�W�S�_�V�S�C�R�O�L�L� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�2�0�7�,�1�9�2�,�7�3� � � � �C�O�N�T�R�O�L� �"�&�P�a�r�a�m�e�t�e�r�s�:�"�,�1�1�0�0�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�2�3�0�,�1�9�2�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�9�1�,�"�E�D�I�T�"�,�E�S�_�A�U�T�O�H�S�C�R�O�L�L� �|�E�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�B�O�R�D�E�R� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�2�,�2�4�0�,�1�9�0�,�1�4� � � � �C�O�N�T�R�O�L� �"�O�K�"�,�1�,�"�B�U�T�T�O�N�"�,�B�S�_�D�E�F�P�U�S�H�B�U�T�T�O�N� �|�B�S�_�V�C�E�N�T�E�R� �|�B�S�_�C�E�N�T�E�R� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�5�,�2�6�5�,�6�4�,�1�6� � � � �C�O�N�T�R�O�L� �"�C�a�n�c�e�l�"�,�2�,�"�B�U�T�T�O�N�"�,�B�S�_�P�U�S�H�B�U�T�T�O�N� �|�B�S�_�V�C�E�N�T�E�R� �|�B�S�_�C�E�N�T�E�R� �|�W�S�_�C�H�I�L�D� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�7�7�,�2�6�5�,�6�4�,�1�6� � � � �C�O�N�T�R�O�L� �"�A�p�p�l�y�"�,�9�,�"�B�U�T�T�O�N�"�,�B�S�_�P�U�S�H�B�U�T�T�O�N� �|�B�S�_�V�C�E�N�T�E�R� �|�B�S�_�C�E�N�T�E�R� �|�W�S�_�C�H�I�L�D� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�4�9�,�2�6�5�,�6�4�,�1�6� � �E�N�D� � � � �D�I�A�L�O�G�_�P�W�D� �D�I�A�L�O�G� �M�O�V�E�A�B�L�E� �P�U�R�E� �L�O�A�D�O�N�C�A�L�L� �D�I�S�C�A�R�D�A�B�L�E� �0�,� �0�,� �1�5�7�,� �1�0�3� � �S�T�Y�L�E� �D�S�_�S�E�T�F�O�N�T� �|�D�S�_�M�O�D�A�L�F�R�A�M�E� �|�D�S�_�C�E�N�T�E�R� �|�W�S�_�P�O�P�U�P� �|�W�S�_�S�Y�S�M�E�N�U� �|�W�S�_�C�A�P�T�I�O�N� � � �C�A�P�T�I�O�N� �"�E�n�t�e�r� �p�a�s�s�w�o�r�d�"� � �F�O�N�T� �8�,� �"�M�S� �S�h�e�l�l� �D�l�g�"� � �L�A�N�G�U�A�G�E� �L�A�N�G�_�E�N�G�L�I�S�H�,� �1� � �B�E�G�I�N� � � � �C�O�N�T�R�O�L� �"�&�E�n�t�e�r� �p�a�s�s�w�o�r�d�:�"�,�1�0�0�0�,�"�S�T�A�T�I�C�"�,�S�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�G�R�O�U�P� �|�W�S�_�V�I�S�I�B�L�E� �,�8�,�8�,�1�4�0�,�8� � � � �C�O�N�T�R�O�L� �"�"�,�1�0�0�1�,�"�E�D�I�T�"�,�E�S�_�P�A�S�S�W�O�R�D� �|�E�S�_�A�U�T�O�H�S�C�R�O�L�L� �|�E�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�B�O�R�D�E�R� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�8�,�2�0�,�1�4�0�,�1�4� � � � �C�O�N�T�R�O�L� �"�&�S�h�o�w� �p�a�s�s�w�o�r�d�"�,�1�0�0�2�,�"�B�U�T�T�O�N�"�,�B�S�_�A�U�T�O�C�H�E�C�K�B�O�X� �|�B�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�4�0�,�1�4�0�,�1�0� � � � �C�O�N�T�R�O�L� �"�O�K�"�,�1�,�"�B�U�T�T�O�N�"�,�B�S�_�D�E�F�P�U�S�H�B�U�T�T�O�N� �|�B�S�_�V�C�E�N�T�E�R� �|�B�S�_�C�E�N�T�E�R� �|�W�S�_�C�H�I�L�D� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�7�5�,�6�4�,�1�6� � � � �C�O�N�T�R�O�L� �"�C�a�n�c�e�l�"�,�2�,�"�B�U�T�T�O�N�"�,�B�S�_�P�U�S�H�B�U�T�T�O�N� �|�B�S�_�V�C�E�N�T�E�R� �|�B�S�_�C�E�N�T�E�R� �|�W�S�_�C�H�I�L�D� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�8�2�,�7�5�,�6�4�,�1�6� � � � �C�O�N�T�R�O�L� �"�E�n�c�r�y�p�t� �f�i�l�e� �&�n�a�m�e�s�"�,�0�,�"�B�U�T�T�O�N�"�,�B�S�_�A�U�T�O�C�H�E�C�K�B�O�X� �|�B�S�_�L�E�F�T� �|�W�S�_�C�H�I�L�D� �|�W�S�_�T�A�B�S�T�O�P� �|�W�S�_�V�I�S�I�B�L�E� �,�1�0�,�5�5�,�1�4�0�,�1�0� � �E�N�D� � ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipDlg.res�������������������������������������������0000644�0001750�0000144�00000003320�14743153644�022425� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������4����D�I�A�L�O�G�_�C�F�G���������0 ��������Ȁ����������!����O�p�t�i�o�n�s����M�S� �S�h�e�l�l� �D�l�g�������P���� � �h��J�A�r�c�h�i�v�e� �&�f�o�r�m�a�t�:�������!P����r� �X�P�4���������P���� � �h��K�C�o�m�p�r�e�s�s�i�o�n� �&�l�e�v�e�l�:������!P����r��X�P�2���������P���� �5�h��P�C�o�m�p�r�e�s�s�i�o�n� �&�m�e�t�h�o�d�:��������!P����r�3�X�P�6���������P���� �J�h��Q�&�D�i�c�t�i�o�n�a�r�y� �s�i�z�e�:������!P����r�H�X��7���������P���� �_�h��R�&�W�o�r�d� �s�i�z�e�:������!P����r�]�X��8���������P���� �t�h��S�&�S�o�l�i�d� �B�l�o�c�k� �s�i�z�e�:��������!P����r�r�X��9���������P���� ��h��T�&�N�u�m�b�e�r� �o�f� �C�P�U� �t�h�r�e�a�d�s�:������!P����r��5��:��������P��������;�1�������P���� �����M�e�m�o�r�y� �u�s�a�g�e� �f�o�r� �C�o�m�p�r�e�s�s�i�n�g�:������P������(���0�������P���� �����M�e�m�o�r�y� �u�s�a�g�e� �f�o�r� �D�e�c�o�m�p�r�e�s�s�i�n�g�:������P������(���0�������P���� ����O�S�p�l�i�t� �t�o� �&�v�o�l�u�m�e�s�,� �b�y�t�e�s�:�����B�!P���� ���I�5���������P���� ����L�&�P�a�r�a�m�e�t�e�r�s�:��������P���� ����C�������P����� @����O�K��������P����M� @����C�a�n�c�e�l��������P����� @�� ��A�p�p�l�y�����h��4����D�I�A�L�O�G�_�P�W�D���������0 ��������Ȁ����������g�����E�n�t�e�r� �p�a�s�s�w�o�r�d����M�S� �S�h�e�l�l� �D�l�g�����P���������&�E�n�t�e�r� �p�a�s�s�w�o�r�d�:��������P���������������P���� �(�� ��&�S�h�o�w� �p�a�s�s�w�o�r�d�������P���� �K�@����O�K��������P����R�K�@����C�a�n�c�e�l�������P���� �7�� ����E�n�c�r�y�p�t� �f�i�l�e� �&�n�a�m�e�s���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipFunc.pas������������������������������������������0000644�0001750�0000144�00000054130�14743153644�022611� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin Copyright (C) 2014-2022 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SevenZipFunc; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} interface uses WcxPlugin; { Mandatory } function OpenArchiveW(var ArchiveData : tOpenArchiveDataW) : TArcHandle;stdcall; function ReadHeaderExW(hArcData : TArcHandle; var HeaderData: THeaderDataExW) : Integer;stdcall; function ProcessFileW(hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PWideChar) : Integer;stdcall; function CloseArchive (hArcData : TArcHandle) : Integer;stdcall; procedure SetChangeVolProcW(hArcData : TArcHandle; pChangeVolProc : TChangeVolProcW);stdcall; procedure SetProcessDataProcW(hArcData : TArcHandle; pProcessDataProc : TProcessDataProcW);stdcall; { Optional } function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer; stdcall; function DeleteFilesW(PackedFile, DeleteList: PWideChar): Integer; stdcall; function CanYouHandleThisFileW(FileName: PWideChar): Boolean; stdcall; procedure PackSetDefaultParams(dps: PPackDefaultParamStruct); stdcall; procedure ConfigurePacker(Parent: HWND; DllInstance: THandle); stdcall; implementation uses JwaWinBase, Windows, SysUtils, Classes, JclCompression, SevenZip, SevenZipAdv, fpTimer, SevenZipDlg, SevenZipLng, SevenZipOpt, LazFileUtils, SyncObjs, LazUTF8, SevenZipCodecs; type { ESevenZipAbort } ESevenZipAbort = class(EJclCompressionError) end; { TSevenZipUpdate } TSevenZipUpdate = class(TThread) FPercent: Int64; FFileName: WideString; FPause: TEventObject; FProgress: TEventObject; FArchive: TJclCompressionArchive; public constructor Create; overload; constructor Create(Archive: TJclCompressionArchive); overload; destructor Destroy; override; public procedure Execute; override; function Update: Integer; virtual; procedure JclCompressionPassword(Sender: TObject; var Password: WideString); procedure JclCompressionProgress(Sender: TObject; const Value, MaxValue: Int64); virtual; end; { TSevenZipHandle } TSevenZipHandle = class(TSevenZipUpdate) Index, Count: LongWord; OpenMode, OperationMode: Integer; ProcessIndex: Cardinal; ArchiveName: String; ProcessArray: TCardinalArray; FileName: array of String; ProcessDataProc: TProcessDataProcW; public procedure Execute; override; function Update: Integer; override; procedure SetArchive(AValue: TJclDecompressArchive); function JclCompressionExtract(Sender: TObject; AIndex: Integer; var AFileName: TFileName; var Stream: TStream; var AOwnsStream: Boolean): Boolean; end; { TPasswordCache } TPasswordCache = class private FTimer: TFPTimer; FArchiveSize: Int64; FArchiveName: String; FArchiveTime: Integer; FMutex: TCriticalSection; FArchivePassword: WideString; const FInterval: Cardinal = 120000; private procedure ResetTimer; procedure ZeroPassword; procedure TimerEvent(Sender: TObject); public constructor Create; destructor Destroy; override; function GetPassword(const Archive: String): WideString; procedure SetPassword(const Archive: String; const Password: WideString); end; var PasswordCache: TPasswordCache; threadvar ProcessDataProcT: TProcessDataProcW; function GetArchiveError(const E: Exception): Integer; begin if E is EFOpenError then Result:= E_EOPEN else if E is EFCreateError then Result:= E_ECREATE else if E is EReadError then Result:= E_EREAD else if E is EWriteError then Result:= E_EWRITE else if E is ESevenZipAbort then Result:= E_EABORTED else if Pos(HexStr(E_OUTOFMEMORY, 8), E.Message) > 0 then Result:= E_NO_MEMORY else begin Result:= E_UNKNOWN_FORMAT; end; end; function WinToDosTime(const WinTime: TFILETIME; var DosTime: Cardinal): LongBool; var lft : Windows.TFILETIME; begin Result:= Windows.FileTimeToLocalFileTime(@Windows.FILETIME(WinTime), @lft) and Windows.FileTimeToDosDateTime(@lft, @LongRec(Dostime).Hi, @LongRec(DosTime).Lo); end; function OpenArchiveW(var ArchiveData : tOpenArchiveDataW) : TArcHandle; stdcall; var I: Integer; ResultHandle: TSevenZipHandle; Archive: TJclDecompressArchive; AFormats: TJclDecompressArchiveClassArray; begin ResultHandle:= TSevenZipHandle.Create; with ResultHandle do begin Index:= 0; ProcessIndex:= 0; OpenMode:= ArchiveData.OpenMode; ArchiveName := Utf16ToUtf8(WideString(ArchiveData.ArcName)); AFormats := FindDecompressFormats(ArchiveName); for I := Low(AFormats) to High(AFormats) do begin Archive := AFormats[I].Create(ArchiveName, 0, False); try SetArchive(Archive); Archive.Password:= PasswordCache.GetPassword(ArchiveName); Archive.ListFiles; PasswordCache.SetPassword(ArchiveName, Archive.Password); Count:= Archive.ItemCount; if OpenMode = PK_OM_EXTRACT then begin SetLength(FileName, Count); SetLength(ProcessArray, Count); end; ArchiveData.OpenResult:= E_SUCCESS; Exit(TArcHandle(ResultHandle)); except on E: Exception do begin ArchiveData.OpenResult:= GetArchiveError(E); FreeAndNil(Archive); Continue; end; end; end; if (Archive = nil) then Free; end; Result:= 0; end; function ReadHeaderExW(hArcData : TArcHandle; var HeaderData: THeaderDataExW) : Integer; stdcall; var FileNameW: UnicodeString; Item: TJclCompressionItem; Handle: TSevenZipHandle absolute hArcData; begin with Handle do begin if Index >= Count then Exit(E_END_ARCHIVE); Item:= FArchive.Items[Index]; FileNameW:= Item.PackedName; HeaderData.UnpSize:= Int64Rec(Item.FileSize).Lo; HeaderData.UnpSizeHigh:= Int64Rec(Item.FileSize).Hi; HeaderData.PackSize:= Int64Rec(Item.PackedSize).Lo; HeaderData.PackSizeHigh:= Int64Rec(Item.PackedSize).Hi; if ipAttributes in Item.ValidProperties then HeaderData.FileAttr:= LongInt(Item.Attributes) else begin HeaderData.FileAttr:= FILE_ATTRIBUTE_ARCHIVE; end; WinToDosTime(Item.LastWriteTime, LongWord(HeaderData.FileTime)); if Item.Encrypted then begin HeaderData.Flags:= RHDF_ENCRYPTED; end; // Special case for absolute file name if (Length(FileNameW) > 0) and (FileNameW[1] = PathDelim) then HeaderData.FileName:= Copy(FileNameW, 2, Length(FileNameW) - 1) else begin HeaderData.FileName:= FileNameW; end; // Special case for BZip2, GZip and Xz archives if (HeaderData.FileName[0] = #0) then begin HeaderData.FileName:= GetNestedArchiveName(ArchiveName, Item); end; end; Result:= E_SUCCESS; end; function ProcessFileW(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PWideChar): Integer; stdcall; var Handle: TSevenZipHandle absolute hArcData; begin try with Handle do case Operation of PK_TEST, PK_EXTRACT: begin if Operation = PK_EXTRACT then begin if Assigned(DestPath) then begin FileName[Index]:= IncludeTrailingPathDelimiter(Utf16ToUtf8(WideString(DestPath))) + Utf16ToUtf8(WideString(DestName)); end else begin FileName[Index]:= Utf16ToUtf8(WideString(DestName)); end; end; Result:= E_SUCCESS; OperationMode:= Operation; ProcessArray[ProcessIndex]:= Index; Inc(ProcessIndex); end; else Result:= E_SUCCESS; end; finally Inc(Handle.Index); end; end; function CloseArchive(hArcData: TArcHandle): Integer; stdcall; var Handle: TSevenZipHandle absolute hArcData; begin Result:= E_SUCCESS; if (hArcData <> wcxInvalidHandle) then with Handle do begin if OpenMode = PK_OM_EXTRACT then begin Start; Update; end; FArchive.Free; Free; end; end; procedure SetChangeVolProcW(hArcData : TArcHandle; pChangeVolProc : TChangeVolProcW); stdcall; begin end; procedure SetProcessDataProcW(hArcData : TArcHandle; pProcessDataProc : TProcessDataProcW); stdcall; var Handle: TSevenZipHandle absolute hArcData; begin if (hArcData = wcxInvalidHandle) then ProcessDataProcT:= pProcessDataProc else begin Handle.ProcessDataProc:= pProcessDataProc; end; end; function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer; stdcall; var I, J: Integer; Encrypt: Boolean; AMessage: String; Password: WideString; FilePath: WideString; FileName: WideString; SfxModule: String = ''; FileNameUTF8: String; AItem: TJclCompressionItem; AProgress: TSevenZipUpdate; Archive: TJclCompressArchive; AFormats: TJclCompressArchiveClassArray; begin FileNameUTF8 := Utf16ToUtf8(WideString(PackedFile)); // If update existing archive if (GetFileAttributesW(PackedFile) <> INVALID_FILE_ATTRIBUTES) then AFormats := TJclCompressArchiveClassArray(FindUpdateFormats(FileNameUTF8)) else begin if not SameText(ExtractFileExt(FileNameUTF8), '.exe') then AFormats := FindCompressFormats(FileNameUTF8) else begin // Only 7-Zip supports self-extract SfxModule := ExtractFilePath(SevenzipLibraryName) + '7z.sfx'; if FileExistsUTF8(SfxModule) then begin SetLength(AFormats, 1); AFormats[0] := TJcl7zCompressArchive; end else begin AMessage := SysErrorMessage(GetLastError) + LineEnding; AMessage += rsSevenZipSfxNotFound + LineEnding + SfxModule; MessageBoxW(0, PWideChar(UTF8ToUTF16(AMessage)), nil, MB_OK or MB_ICONERROR); Exit(E_NO_FILES); end; end; end; for I := Low(AFormats) to High(AFormats) do begin Archive := AFormats[I].Create(FileNameUTF8, 0, False); try AProgress:= TSevenZipUpdate.Create(Archive); if (Flags and PK_PACK_ENCRYPT) <> 0 then begin Encrypt:= Archive is IJclArchiveEncryptHeader; if not ShowPasswordQuery(Encrypt, Password) then Exit(E_EABORTED) else begin Archive.Password:= Password; if Archive is TJcl7zUpdateArchive then TJcl7zUpdateArchive(Archive).SetEncryptHeader(Encrypt); if Archive is TJcl7zCompressArchive then TJcl7zCompressArchive(Archive).SetEncryptHeader(Encrypt); if Archive is TJclZipUpdateArchive then TJclZipUpdateArchive(Archive).SetEncryptionMethod(emAES256); if Archive is TJclZipCompressArchive then TJclZipCompressArchive(Archive).SetEncryptionMethod(emAES256); end; end; if (Archive is TJclUpdateArchive) then try TJclUpdateArchive(Archive).ListFiles; except Continue; end; SetArchiveOptions(Archive); if Archive is TJcl7zCompressArchive then begin TJcl7zCompressArchive(Archive).SfxModule := SfxModule; end; if Assigned(SubPath) then begin FilePath:= WideString(SubPath); if FilePath[Length(FilePath)] <> PathDelim then FilePath := FilePath + PathDelim; end; while True do begin FileName := WideString(AddList); FileNameUTF8:= Utf16ToUtf8(WideString(SrcPath + FileName)); if FileName[Length(FileName)] = PathDelim then Archive.AddDirectory(FilePath + Copy(FileName, 1, Length(FileName) - 1), FileNameUTF8) else Archive.AddFile(FilePath + FileName, FileNameUTF8); if (AddList + Length(FileName) + 1)^ = #0 then Break; Inc(AddList, Length(FileName) + 1); end; AProgress.Start; Result:= AProgress.Update; // If move files requested if (Result = E_SUCCESS) and (Flags and PK_PACK_MOVE_FILES <> 0) then begin // First remove files for J:= 0 to Archive.ItemCount - 1 do begin AItem:= Archive.Items[J]; if AItem.OperationSuccess = osOK then begin if not AItem.Directory then DeleteFileUtf8(AItem.FileName); end; end; // Second remove directories for J:= Archive.ItemCount - 1 downto 0 do begin AItem:= Archive.Items[J]; if AItem.Directory then RemoveDirUtf8(AItem.FileName); end; end; Exit; finally Archive.Free; AProgress.Free; end; end; Result:= E_NOT_SUPPORTED; end; function DeleteFilesW(PackedFile, DeleteList: PWideChar): Integer; stdcall; var I: Integer; PathEnd : WideChar; FileList : PWideChar; FileName : WideString; FileNameUTF8 : String; Archive: TJclUpdateArchive; AProgress: TSevenZipUpdate; AFormats: TJclUpdateArchiveClassArray; begin FileNameUTF8 := Utf16ToUtf8(WideString(PackedFile)); AFormats := FindUpdateFormats(FileNameUTF8); for I := Low(AFormats) to High(AFormats) do begin Archive := AFormats[I].Create(FileNameUTF8, 0, False); try AProgress:= TSevenZipUpdate.Create(Archive); try Archive.ListFiles; except Continue; end; // Parse file list. FileList := DeleteList; while FileList^ <> #0 do begin FileName := FileList; // Convert PWideChar to WideString (up to first #0) PathEnd := (FileList + Length(FileName) - 1)^; // If ends with '.../*.*' or '.../' then delete directory. if (PathEnd = '*') or (PathEnd = PathDelim) then TJclSevenzipUpdateArchive(Archive).RemoveDirectory(WideExtractFilePath(FileName)) else TJclSevenzipUpdateArchive(Archive).RemoveItem(FileName); FileList := FileList + Length(FileName) + 1; // move after filename and ending #0 if FileList^ = #0 then Break; // end of list end; AProgress.Start; Exit(AProgress.Update); finally Archive.Free; AProgress.Free; end; end; Result:= E_NOT_SUPPORTED; end; function CanYouHandleThisFileW(FileName: PWideChar): Boolean; stdcall; begin Result:= FindDecompressFormats(Utf16ToUtf8(WideString(FileName))) <> nil; end; procedure PackSetDefaultParams(dps: PPackDefaultParamStruct); stdcall; var ModulePath: AnsiString; begin // Save configuration file name ConfigFile:= ExtractFilePath(dps^.DefaultIniName); ConfigFile:= WinCPToUTF8(ConfigFile) + DefaultIniName; // Get plugin path if GetModulePath(ModulePath) then begin // Use configuration from plugin path if FileExistsUTF8(ModulePath + DefaultIniName) then ConfigFile:= ModulePath + DefaultIniName; end; // Load plugin configuration LoadConfiguration; // Try to find library path if FileExistsUTF8(LibraryPath) then SevenzipLibraryName:= LibraryPath else if Length(ModulePath) > 0 then begin if FileExistsUTF8(ModulePath + TargetCPU + PathDelim + SevenzipDefaultLibraryName) then SevenzipLibraryName:= ModulePath + TargetCPU + PathDelim + SevenzipDefaultLibraryName else if FileExistsUTF8(ModulePath + SevenzipDefaultLibraryName) then begin SevenzipLibraryName:= ModulePath + SevenzipDefaultLibraryName; end; end; // Process Xz files as archives GetArchiveFormats.RegisterFormat(TJclXzDecompressArchive); // Replace TJclXzCompressArchive by TJclXzCompressArchiveEx GetArchiveFormats.UnregisterFormat(TJclXzCompressArchive); GetArchiveFormats.RegisterFormat(TJclXzCompressArchiveEx); // Don't process PE files as archives GetArchiveFormats.UnregisterFormat(TJclPeDecompressArchive); // Try to load 7z.dll if (Is7ZipLoaded or Load7Zip) then LoadLibraries else begin MessageBoxW(0, PWideChar(UTF8ToUTF16(rsSevenZipLoadError)), 'SevenZip', MB_OK or MB_ICONERROR); end; // Create password cache object PasswordCache:= TPasswordCache.Create; end; procedure ConfigurePacker(Parent: WcxPlugin.HWND; DllInstance: THandle); stdcall; begin ShowConfigurationDialog(Parent); end; { TSevenZipUpdate } constructor TSevenZipUpdate.Create; begin inherited Create(True); FPause:= TEventObject.Create(nil, False, False, ''); FProgress:= TEventObject.Create(nil, False, False, ''); end; constructor TSevenZipUpdate.Create(Archive: TJclCompressionArchive); begin Create; FArchive:= Archive; Archive.OnPassword:= JclCompressionPassword; end; destructor TSevenZipUpdate.Destroy; begin FPause.Free; FProgress.Free; inherited Destroy; end; procedure TSevenZipUpdate.Execute; begin try (FArchive as TJclCompressArchive).Compress; ReturnValue:= E_SUCCESS; except on E: Exception do ReturnValue:= GetArchiveError(E); end; Terminate; FProgress.SetEvent; end; function TSevenZipUpdate.Update: Integer; begin FArchive.OnProgress:= JclCompressionProgress; while not Terminated do begin // Wait progress event FProgress.WaitFor(INFINITE); // If the user has clicked on Cancel, the function returns zero FArchive.CancelCurrentOperation:= (ProcessDataProcT(PWideChar(FFileName), -FPercent) = 0); // Drop pause FPause.SetEvent; end; Result:= ReturnValue; end; procedure TSevenZipUpdate.JclCompressionPassword(Sender: TObject; var Password: WideString); var Encrypt: Boolean = False; begin if not ShowPasswordQuery(Encrypt, Password) then raise ESevenZipAbort.Create(EmptyStr); end; procedure TSevenZipUpdate.JclCompressionProgress(Sender: TObject; const Value, MaxValue: Int64); begin if MaxValue > 0 then begin FPercent:= (Value * 100) div MaxValue; end; if FArchive.ItemCount > 0 then begin FFileName:= FArchive.Items[FArchive.CurrentItemIndex].PackedName; end; // Fire progress event FProgress.SetEvent; // Check pause progress FPause.WaitFor(INFINITE); end; { TSevenZipHandle } procedure TSevenZipHandle.Execute; begin try SetLength(ProcessArray, ProcessIndex); TJclSevenzipDecompressArchive(FArchive).ProcessSelected(ProcessArray, OperationMode = PK_TEST); ReturnValue:= E_SUCCESS; except on E: Exception do begin ReturnValue:= GetArchiveError(E); MessageBoxW(0, PWideChar(UTF8ToUTF16(E.Message)), nil, MB_OK or MB_ICONERROR); end; end; Terminate; FProgress.SetEvent; end; function TSevenZipHandle.Update: Integer; begin FArchive.OnProgress:= JclCompressionProgress; while not Terminated do begin // Wait progress event FProgress.WaitFor(INFINITE); if Assigned(ProcessDataProc) then begin // If the user has clicked on Cancel, the function returns zero FArchive.CancelCurrentOperation:= ProcessDataProc(PWideChar(FFileName), -FPercent) = 0; end; // Drop pause FPause.SetEvent; end; Result:= ReturnValue; end; procedure TSevenZipHandle.SetArchive(AValue: TJclDecompressArchive); begin FArchive:= AValue; AValue.OnPassword := JclCompressionPassword; AValue.OnExtract := JclCompressionExtract; end; function TSevenZipHandle.JclCompressionExtract(Sender: TObject; AIndex: Integer; var AFileName: TFileName; var Stream: TStream; var AOwnsStream: Boolean): Boolean; begin Result:= True; AFileName:= FileName[AIndex]; end; { TPasswordCache } procedure TPasswordCache.ResetTimer; begin if FTimer.Interval > FInterval then FTimer.Interval:= FTimer.Interval - 1 else FTimer.Interval:= FTimer.Interval + 1; end; procedure TPasswordCache.ZeroPassword; begin if (Length(FArchivePassword) > 0) then begin FillWord(FArchivePassword[1], Length(FArchivePassword), 0); SetLength(FArchivePassword, 0); end; end; procedure TPasswordCache.TimerEvent(Sender: TObject); begin FMutex.Acquire; try ZeroPassword; FTimer.Enabled:= False; finally FMutex.Release; end; end; function TPasswordCache.GetPassword(const Archive: String): WideString; begin FMutex.Acquire; try if (SameText(FArchiveName, Archive)) and (FArchiveSize = FileSizeUtf8(Archive)) and (FArchiveTime = FileAgeUtf8(Archive)) then begin ResetTimer; Result:= FArchivePassword end else begin FTimer.Enabled:= False; Result:= EmptyWideStr; ZeroPassword; end; finally FMutex.Release; end; end; procedure TPasswordCache.SetPassword(const Archive: String; const Password: WideString); begin FMutex.Acquire; try if (Length(Password) = 0) then FArchiveName:= EmptyStr else begin FArchiveName:= Archive; FArchivePassword:= Password; FArchiveTime:= FileAgeUtf8(Archive); FArchiveSize:= FileSizeUtf8(Archive); FTimer.Enabled:= True; ResetTimer; end; finally FMutex.Release; end; end; constructor TPasswordCache.Create; begin FTimer:= TFPTimer.Create(nil); FTimer.UseTimerThread:= True; FTimer.OnTimer:= TimerEvent; FTimer.Interval:= FInterval; FMutex:= TCriticalSection.Create; end; destructor TPasswordCache.Destroy; begin FTimer.Free; FMutex.Free; inherited Destroy; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipLng.pas�������������������������������������������0000644�0001750�0000144�00000002763�14743153644�022443� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin, language support Copyright (C) 2014-2015 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SevenZipLng; {$mode delphi} interface uses Classes, SysUtils; resourcestring rsSevenZipLoadError = 'Failed to load 7z.dll'; rsSevenZipSfxNotFound = 'Cannot find specified SFX module'; resourcestring rsCompressionLevelStore = 'Store'; rsCompressionLevelFastest = 'Fastest'; rsCompressionLevelFast = 'Fast'; rsCompressionLevelNormal = 'Normal'; rsCompressionLevelMaximum = 'Maximum'; rsCompressionLevelUltra = 'Ultra'; rsSolidBlockSolid = 'Solid'; rsSolidBlockNonSolid = 'Non-solid'; implementation end. �������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipOpt.pas�������������������������������������������0000644�0001750�0000144�00000037767�14743153644�022501� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin, compression options Copyright (C) 2014-2017 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SevenZipOpt; {$mode delphi} interface uses Classes, SysUtils, Windows, IniFiles, JclCompression, SevenZip; const cKilo = 1024; cMega = cKilo * cKilo; cGiga = cKilo * cKilo * cKilo; const kNoSolidBlockSize = 0; kSolidBlockSize = 64; const DeflateDict: array[0..0] of PtrInt = ( cKilo * 32 ); Deflate64Dict: array[0..0] of PtrInt = ( cKilo * 64 ); Bzip2Dict: array[0..8] of PtrInt = ( cKilo * 100, cKilo * 200, cKilo * 300, cKilo * 400, cKilo * 500, cKilo * 600, cKilo * 700, cKilo * 800, cKilo * 900 ); LZMADict: array[0..21] of PtrInt = ( cKilo * 64, cMega, cMega * 2, cMega * 3, cMega * 4, cMega * 6, cMega * 8, cMega * 12, cMega * 16, cMega * 24, cMega * 32, cMega * 48, cMega * 64, cMega * 96, cMega * 128, cMega * 192, cMega * 256, cMega * 384, cMega * 512, cMega * 768, cMega * 1024, cMega * 1536 ); PPMdDict: array[0..19] of PtrInt = ( cMega, cMega * 2, cMega * 3, cMega * 4, cMega * 6, cMega * 8, cMega * 12, cMega * 16, cMega * 24, cMega * 32, cMega * 48, cMega * 64, cMega * 96, cMega * 128, cMega * 192, cMega * 256, cMega * 384, cMega * 512, cMega * 768, cMega * 1024 ); DeflateWordSize: array[0..11] of PtrInt = (8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 258); Deflate64WordSize: array[0..11] of PtrInt = (8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 257); LZMAWordSize: array[0..11] of PtrInt = (8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 273); PPMdWordSize: array[0..14] of PtrInt = (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); // Stored as block size / 1024 SolidBlock: array[0..16] of PtrInt = ( cKilo, cKilo * 2, cKilo * 4, cKilo * 8, cKilo * 16, cKilo * 32, cKilo * 64, cKilo * 128, cKilo * 256, cKilo * 512, cMega, cMega * 2, cMega * 4, cMega * 8, cMega * 16, cMega * 32, cMega * 64 ); const TargetCPU = {$I %FPCTARGETCPU%}; // Target CPU of FPC type TCompressionLevel = ( clStore = 0, clFastest = 1, clFast = 3, clNormal = 5, clMaximum = 7, clUltra = 9 ); TArchiveFormat = (afSevenZip, afBzip2, afGzip, afTar, afWim, afXz, afZip); PPasswordData = ^TPasswordData; TPasswordData = record EncryptHeader: Boolean; Password: array[0..MAX_PATH] of WideChar; end; TFormatOptions = record Level: PtrInt; Method: PtrInt; Dictionary: PtrInt; WordSize: PtrInt; SolidSize: PtrInt; ThreadCount: PtrInt; ArchiveCLSID: PGUID; Parameters: WideString; end; function GetNumberOfProcessors: LongWord; function FormatFileSize(ASize: Int64; AGiga: Boolean = True): String; procedure SetArchiveOptions(AJclArchive: IInterface); procedure LoadConfiguration; procedure SaveConfiguration; const DefaultIniName = 'sevenzip.ini'; var ConfigFile: AnsiString; LibraryPath: AnsiString; const ArchiveExtension: array[TArchiveFormat] of WideString = ('7z', 'bzip2', 'gzip', 'tar', 'wim', 'xz', 'zip'); const MethodName: array [TJclCompressionMethod] of WideString = (kCopyMethodName, kDeflateMethodName, kDeflate64MethodName, kBZip2MethodName, kLZMAMethodName, kLZMA2MethodName, kPPMdMethodName); const DefaultConfig: array[TArchiveFormat] of TFormatOptions = ( (Level: PtrInt(clNormal); Method: PtrInt(cmLZMA2); Dictionary: cMega * 16; WordSize: 32; SolidSize: cMega * 2; ThreadCount: 2; ArchiveCLSID: @CLSID_CFormat7z; Parameters: '';), (Level: PtrInt(clNormal); Method: PtrInt(cmBZip2); Dictionary: cKilo * 900; WordSize: 0; SolidSize: 0; ThreadCount: 2; ArchiveCLSID: @CLSID_CFormatBZ2; Parameters: '';), (Level: PtrInt(clNormal); Method: PtrInt(cmDeflate); Dictionary: cKilo * 32; WordSize: 32; SolidSize: 0; ThreadCount: 1; ArchiveCLSID: @CLSID_CFormatGZip; Parameters: '';), (Level: PtrInt(clStore); Method: 0; Dictionary: 0; WordSize: 0; SolidSize: 0; ThreadCount: 1; ArchiveCLSID: @CLSID_CFormatTar; Parameters: '';), (Level: PtrInt(clStore); Method: 0; Dictionary: 0; WordSize: 0; SolidSize: 0; ThreadCount: 1; ArchiveCLSID: @CLSID_CFormatWim; Parameters: '';), (Level: PtrInt(clNormal); Method: PtrInt(cmLZMA2); Dictionary: cMega * 16; WordSize: 32; SolidSize: 0; ThreadCount: 2; ArchiveCLSID: @CLSID_CFormatXz; Parameters: '';), (Level: PtrInt(clNormal); Method: PtrInt(cmDeflate); Dictionary: cKilo * 32; WordSize: 32; SolidSize: 0; ThreadCount: 2; ArchiveCLSID: @CLSID_CFormatZip; Parameters: '';) ); var PluginConfig: array[TArchiveFormat] of TFormatOptions; implementation uses ActiveX, LazUTF8, SevenZipAdv, SevenZipCodecs; function GetNumberOfProcessors: LongWord; var SystemInfo: TSYSTEMINFO; begin GetSystemInfo(@SystemInfo); Result:= SystemInfo.dwNumberOfProcessors; end; function FormatFileSize(ASize: Int64; AGiga: Boolean): String; begin if ((ASize div cGiga) > 0) and AGiga then Result:= IntToStr(ASize div cGiga) + ' GB' else if (ASize div cMega) >0 then Result:= IntToStr(ASize div cMega) + ' MB' else if (ASize div cKilo) > 0 then Result:= IntToStr(ASize div cKilo) + ' KB' else Result:= IntToStr(ASize); end; procedure SetArchiveCustom(AJclArchive: IInterface; AFormat: TArchiveFormat); var Index: Integer; Start: Integer = 1; Parameters: WideString; MethodStandard: Boolean; Method: TJclCompressionMethod; JclArchive: TJclCompressionArchive; procedure AddProperty(const Name: WideString; const Value: TPropVariant); begin with JclArchive do begin SetLength(PropNames, Length(PropNames) + 1); PropNames[High(PropNames)] := Name; SetLength(PropValues, Length(PropValues) + 1); PropValues[High(PropValues)] := Value; end; end; procedure AddCardinalProperty(const Name: WideString; Value: Cardinal); var PropValue: TPropVariant; begin PropValue.vt := VT_UI4; PropValue.ulVal := Value; AddProperty(Name, PropValue); end; procedure AddWideStringProperty(const Name: WideString; const Value: WideString); var PropValue: TPropVariant; begin PropValue.vt := VT_BSTR; PropValue.bstrVal := SysAllocString(PWideChar(Value)); AddProperty(Name, PropValue); end; procedure AddOption(Finish: Integer); var C: WideChar; IValue: Int64; PropValue: TPropVariant; Option, Value: WideString; begin Option:= Copy(Parameters, Start, Finish - Start); Start:= Pos('=', Option); if Start = 0 then begin PropValue.vt:= VT_EMPTY; C:= Option[Length(Option)]; if C = '+' then Variant(PropValue):= True else if C = '-' then begin Variant(PropValue):= False; end; if (PropValue.vt <> VT_EMPTY) then begin Delete(Option, Length(Option), 1); end; AddProperty(Option, PropValue); end else begin Value:= Copy(Option, Start + 1, MaxInt); SetLength(Option, Start - 1); if TryStrToInt64(AnsiString(Value), IValue) then AddCardinalProperty(Option, IValue) else AddWideStringProperty(Option, Value); end; end; begin JclArchive:= AJclArchive as TJclCompressionArchive; // Parse additional parameters Parameters:= Trim(PluginConfig[AFormat].Parameters); if Length(Parameters) > 0 then begin for Index:= 1 to Length(Parameters) do begin if Parameters[Index] = #32 then begin AddOption(Index); Start:= Index + 1; end; end; AddOption(MaxInt); end; Parameters:= WideUpperCase(Parameters); MethodStandard:= PluginConfig[AFormat].Method <= cmMaximum; // Set word size parameter if MethodStandard then begin Method:= TJclCompressionMethod(PluginConfig[AFormat].Method); case Method of cmLZMA, cmLZMA2, cmDeflate, cmDeflate64: begin if (Pos('FB=', Parameters) = 0) and (Pos('1=', Parameters) = 0) then AddCardinalProperty('fb', PluginConfig[AFormat].WordSize); end; cmPPMd: begin if Pos('O=', Parameters) = 0 then AddCardinalProperty('o', PluginConfig[AFormat].WordSize); end; end; end; // Set 7-zip compression method if IsEqualGUID(CLSID_CFormat7z, PluginConfig[AFormat].ArchiveCLSID^) then begin if Pos('0=', Parameters) = 0 then begin if MethodStandard then AddWideStringProperty('0', MethodName[Method]) else begin AddWideStringProperty('0', GetCodecName(PluginConfig[AFormat].Method)); end; end; if MethodStandard then begin if (Method > cmCopy) and (Method < cmPPMd) and (Pos('D=', Parameters) = 0) then begin AddWideStringProperty('D', WideString(IntToStr(PluginConfig[AFormat].Dictionary) + 'B')); end else if (Method = cmPPMd) and (Pos('MEM=', Parameters) = 0) then begin AddWideStringProperty('MEM', WideString(IntToStr(PluginConfig[AFormat].Dictionary) + 'B')); end; end; end; end; procedure SetArchiveOptions(AJclArchive: IInterface); var MethodStd: Boolean; ArchiveCLSID: TGUID; SolidBlockSize: Int64; Index: TArchiveFormat; Solid: IJclArchiveSolid; CompressHeader: IJclArchiveCompressHeader; DictionarySize: IJclArchiveDictionarySize; CompressionLevel: IJclArchiveCompressionLevel; MultiThreadStrategy: IJclArchiveNumberOfThreads; CompressionMethod: IJclArchiveCompressionMethod; SaveCreationDateTime: IJclArchiveSaveCreationDateTime; SaveLastAccessDateTime: IJclArchiveSaveLastAccessDateTime; begin if AJclArchive is TJclSevenzipCompressArchive then ArchiveCLSID:= (AJclArchive as TJclSevenzipCompressArchive).ArchiveCLSID else begin ArchiveCLSID:= (AJclArchive as TJclSevenzipUpdateArchive).ArchiveCLSID end; for Index:= Low(PluginConfig) to High(PluginConfig) do begin if IsEqualGUID(ArchiveCLSID, PluginConfig[Index].ArchiveCLSID^) then begin MethodStd:= (PluginConfig[Index].Method <= cmMaximum); if MethodStd and Supports(AJclArchive, IJclArchiveCompressionMethod, CompressionMethod) and Assigned(CompressionMethod) then CompressionMethod.SetCompressionMethod(TJclCompressionMethod(PluginConfig[Index].Method)); if Supports(AJclArchive, IJclArchiveCompressionLevel, CompressionLevel) and Assigned(CompressionLevel) then CompressionLevel.SetCompressionLevel(PluginConfig[Index].Level); if PluginConfig[Index].Level <> PtrInt(clStore) then begin if MethodStd and Supports(AJclArchive, IJclArchiveDictionarySize, DictionarySize) and Assigned(DictionarySize) then DictionarySize.SetDictionarySize(PluginConfig[Index].Dictionary); if Supports(AJclArchive, IJclArchiveSolid, Solid) and Assigned(Solid) then begin SolidBlockSize:= Int64(PluginConfig[Index].SolidSize); if SolidBlockSize <> kSolidBlockSize then SolidBlockSize:= SolidBlockSize * cKilo; Solid.SetSolidBlockSize(SolidBlockSize); end; if Supports(AJclArchive, IJclArchiveNumberOfThreads, MultiThreadStrategy) and Assigned(MultiThreadStrategy) then MultiThreadStrategy.SetNumberOfThreads(PluginConfig[Index].ThreadCount); if Supports(AJclArchive, IJclArchiveSaveCreationDateTime, SaveCreationDateTime) and Assigned(SaveCreationDateTime) then SaveCreationDateTime.SetSaveCreationDateTime(False); if Supports(AJclArchive, IJclArchiveSaveLastAccessDateTime, SaveLastAccessDateTime) and Assigned(SaveLastAccessDateTime) then SaveLastAccessDateTime.SetSaveLastAccessDateTime(False); if Supports(AJclArchive, IJclArchiveCompressHeader, CompressHeader) and Assigned(CompressHeader) then CompressHeader.SetCompressHeader(True); end; try SetArchiveCustom(AJclArchive, Index); except on E: Exception do MessageBoxW(0, PWideChar(UTF8ToUTF16(E.Message)), nil, MB_OK or MB_ICONERROR); end; Exit; end; end; end; procedure LoadConfiguration; var Ini: TIniFile; Section: AnsiString; ArchiveFormat: TArchiveFormat; begin try Ini:= TIniFile.Create(ConfigFile); try LibraryPath:= Ini.ReadString('Library', TargetCPU, EmptyStr); LibraryPath:= Utf16ToUtf8(ExpandEnvironmentStrings(UTF8ToUTF16(LibraryPath))); for ArchiveFormat:= Low(TArchiveFormat) to High(TArchiveFormat) do begin Section:= GUIDToString(PluginConfig[ArchiveFormat].ArchiveCLSID^); PluginConfig[ArchiveFormat].Level:= Ini.ReadInteger(Section, 'Level', DefaultConfig[ArchiveFormat].Level); PluginConfig[ArchiveFormat].Method:= Ini.ReadInteger(Section, 'Method', DefaultConfig[ArchiveFormat].Method); PluginConfig[ArchiveFormat].Dictionary:= Ini.ReadInteger(Section, 'Dictionary', DefaultConfig[ArchiveFormat].Dictionary); PluginConfig[ArchiveFormat].WordSize:= Ini.ReadInteger(Section, 'WordSize', DefaultConfig[ArchiveFormat].WordSize); PluginConfig[ArchiveFormat].SolidSize:= Ini.ReadInteger(Section, 'SolidSize', DefaultConfig[ArchiveFormat].SolidSize); PluginConfig[ArchiveFormat].ThreadCount:= Ini.ReadInteger(Section, 'ThreadCount', DefaultConfig[ArchiveFormat].ThreadCount); PluginConfig[ArchiveFormat].Parameters:= Ini.ReadString(Section, 'Parameters', DefaultConfig[ArchiveFormat].Parameters); end; finally Ini.Free; end; except on E: Exception do MessageBoxW(0, PWideChar(UTF8ToUTF16(E.Message)), nil, MB_OK or MB_ICONERROR); end; end; procedure SaveConfiguration; var Ini: TIniFile; Section: AnsiString; ArchiveFormat: TArchiveFormat; begin try Ini:= TIniFile.Create(ConfigFile); try for ArchiveFormat:= Low(TArchiveFormat) to High(TArchiveFormat) do begin Section:= GUIDToString(PluginConfig[ArchiveFormat].ArchiveCLSID^); Ini.WriteString(Section, 'Format', ArchiveExtension[ArchiveFormat]); Ini.WriteInteger(Section, 'Level', PluginConfig[ArchiveFormat].Level); Ini.WriteInteger(Section, 'Method', PluginConfig[ArchiveFormat].Method); Ini.WriteInteger(Section, 'Dictionary', PluginConfig[ArchiveFormat].Dictionary); Ini.WriteInteger(Section, 'WordSize', PluginConfig[ArchiveFormat].WordSize); Ini.WriteInteger(Section, 'SolidSize', PluginConfig[ArchiveFormat].SolidSize); Ini.WriteInteger(Section, 'ThreadCount', PluginConfig[ArchiveFormat].ThreadCount); Ini.WriteString(Section, 'Parameters', PluginConfig[ArchiveFormat].Parameters); end; finally Ini.Free; end; except on E: Exception do MessageBoxW(0, PWideChar(UTF8ToUTF16(E.Message)), nil, MB_OK or MB_ICONERROR); end; end; initialization CopyMemory(@PluginConfig[Low(PluginConfig)], @DefaultConfig[Low(DefaultConfig)], SizeOf(PluginConfig)); end. ���������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipWcx.dpr�������������������������������������������0000644�0001750�0000144�00000003465�14743153644�022466� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library SevenZipWcx; uses CMem, FPCAdds, SevenZipFunc, SevenZipDlg, WcxPlugin, SevenZipAdv, SevenZipLng, SevenZipCodecs; function OpenArchive(var ArchiveData : tOpenArchiveData) : TArcHandle; stdcall; begin Result:= 0; ArchiveData.OpenResult:= E_NOT_SUPPORTED; end; function ReadHeader(hArcData : TArcHandle; var HeaderData: THeaderData) : Integer; stdcall; begin Result:= E_NOT_SUPPORTED; end; function ProcessFile (hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PAnsiChar) : Integer; stdcall; begin Result:= E_NOT_SUPPORTED; end; procedure SetChangeVolProc (hArcData : TArcHandle; pChangeVolProc : PChangeVolProc); stdcall; begin end; procedure SetProcessDataProc (hArcData : TArcHandle; pProcessDataProc : TProcessDataProc); stdcall; begin end; function PackFiles(PackedFile, SubPath, SrcPath, AddList: PAnsiChar; Flags: Integer): Integer; stdcall; begin Result:= E_NOT_SUPPORTED; end; function DeleteFiles(PackedFile, DeleteList: PAnsiChar): Integer; stdcall; begin Result:= E_NOT_SUPPORTED; end; function GetBackgroundFlags: Integer; stdcall; begin Result:= BACKGROUND_UNPACK or BACKGROUND_PACK; end; function GetPackerCaps : Integer; stdcall; begin Result:= PK_CAPS_NEW or PK_CAPS_DELETE or PK_CAPS_MODIFY or PK_CAPS_MULTIPLE or PK_CAPS_OPTIONS or PK_CAPS_ENCRYPT; end; exports { Mandatory } OpenArchive, OpenArchiveW, ReadHeader, ReadHeaderExW, ProcessFile, ProcessFileW, CloseArchive, SetChangeVolProc, SetChangeVolProcW, SetProcessDataProc, SetProcessDataProcW, { Optional } PackFiles, PackFilesW, DeleteFiles, DeleteFilesW, GetPackerCaps, ConfigurePacker, GetBackgroundFlags, PackSetDefaultParams, CanYouHandleThisFileW ; {$R *.res} begin end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/SevenZipWcx.lpi�������������������������������������������0000644�0001750�0000144�00000012130�14743153644�022452� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="SevenZipWcx"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <i18n> <EnableI18N LFM="False"/> </i18n> <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="24"/> <MinorVersionNr Value="11"/> <RevisionNr Value="4"/> <CharSet Value="04B0"/> <StringTable FileDescription="SevenZip archiver plugin" InternalName="SevenZip" LegalCopyright="Copyright (C) 2014-2024 Alexander Koblov"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\sevenzip.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk;jcl\common;jcl\windows;jcl;platform"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <CustomOptions Value="-dUNICODE_CTRLS"/> </Other> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <HostApplicationFilename Value="D:\doublecmd\doublecmd.exe"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <HostApplicationFilename Value="D:\doublecmd\doublecmd.exe"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="2"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> <Item2> <PackageName Value="LazUtils"/> </Item2> </RequiredPackages> <Units Count="6"> <Unit0> <Filename Value="SevenZipWcx.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="SevenZipFunc.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="SevenZipAdv.pas"/> <IsPartOfProject Value="True"/> </Unit2> <Unit3> <Filename Value="SevenZipDlg.pas"/> <IsPartOfProject Value="True"/> </Unit3> <Unit4> <Filename Value="SevenZipLng.pas"/> <IsPartOfProject Value="True"/> </Unit4> <Unit5> <Filename Value="SevenZipCodecs.pas"/> <IsPartOfProject Value="True"/> </Unit5> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\sevenzip.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk;jcl\common;jcl\windows;jcl;platform"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> <CustomOptions Value="-dUNICODE_CTRLS"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020272� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/DCJclAlternative.pas����������������������������������0000644�0001750�0000144�00000033676�14743153644�024134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin Copyright (C) 2015-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit DCJclAlternative; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fgl, Windows, DCClassesUtf8; // JclBase.pas ----------------------------------------------------------------- type EJclError = class(Exception); TDynByteArray = array of Byte; TDynCardinalArray = array of Cardinal; type JclBase = class type PPInt64 = ^PInt64; end; // JclStreams.pas -------------------------------------------------------------- type TJclStream = TStream; TJclOnVolume = function(Index: Integer): TStream of object; TJclOnVolumeMaxSize = function(Index: Integer): Int64 of object; type { TJclDynamicSplitStream } TJclDynamicSplitStream = class(TJclStream) private FVolume: TStream; FOnVolume: TJclOnVolume; FOnVolumeMaxSize: TJclOnVolumeMaxSize; private function LoadVolume: Boolean; function GetVolume(Index: Integer): TStream; function GetVolumeMaxSize(Index: Integer): Int64; protected function GetSize: Int64; override; procedure SetSize(const NewSize: Int64); override; public constructor Create(ADummy: Boolean = False); function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; function Read(var Buffer; Count: LongInt): LongInt; override; function Write(const Buffer; Count: LongInt): LongInt; override; property OnVolume: TJclOnVolume read FOnVolume write FOnVolume; property OnVolumeMaxSize: TJclOnVolumeMaxSize read FOnVolumeMaxSize write FOnVolumeMaxSize; end; function StreamCopy(Source, Target: TStream): Int64; // JclDateTime.pas ------------------------------------------------------------- function LocalDateTimeToFileTime(DateTime: TDateTime): TFileTime; // JclFileUtils.pas ------------------------------------------------------------ const DirDelimiter = DirectorySeparator; DirSeparator = PathSeparator; type TJclOnAddDirectory = procedure(const Directory: String) of object; TJclOnAddFile = procedure(const Directory: String; const FileInfo: TSearchRec) of object; function PathAddSeparator(const Path: String): String; inline; function PathRemoveSeparator(const Path: String): String; inline; function PathGetRelativePath(const Base, Path: String): String; inline; function PathCanonicalize(const Path: WideString): WideString; function IsFileNameMatch(const FileName, Mask: WideString): Boolean; inline; procedure BuildFileList(const SourceFile: String; FileAttr: Integer; InnerList: TStrings; Dummy: Boolean); procedure EnumFiles(const Path: String; OnAddFile: TJclOnAddFile; ExcludeAttributes: Integer); procedure EnumDirectories(const Path: String; OnAddDirectory: TJclOnAddDirectory; DummyBoolean: Boolean; const DummyString: String; DummyPointer: Pointer); function FileDelete(const FileName: String): Boolean; inline; function FindUnusedFileName(const FileName, FileExt: String): String; function FileMove(const OldName, NewName: String; Replace: Boolean = False): Boolean; // JclSysUtils.pas ------------------------------------------------------------- type TModuleHandle = TLibHandle; const INVALID_MODULEHANDLE_VALUE = NilHandle; type JclSysUtils = class class function LoadModule(var Module: TModuleHandle; FileName: String): Boolean; class procedure UnloadModule(var Module: TModuleHandle); end; function GUIDEquals(const GUID1, GUID2: TGUID): Boolean; inline; function GetModuleSymbol(Module: TModuleHandle; SymbolName: String): Pointer; inline; // JclStrings.pas -------------------------------------------------------------- procedure StrTokenToStrings(const Token: String; Separator: AnsiChar; var Strings: TStrings); // JclWideStrings.pas ---------------------------------------------------------- type TFPWideStrObjMap = specialize TFPGMap<WideString, TObject>; type { TJclWideStringList } TJclWideStringList = class(TFPWideStrObjMap) private FCaseSensitive: Boolean; private procedure SetCaseSensitive(AValue: Boolean); function CompareWideStringProc(Key1, Key2: Pointer): Integer; function CompareTextWideStringProc(Key1, Key2: Pointer): Integer; protected function Get(Index: Integer): WideString; function GetObject(Index: Integer): TObject; procedure Put(Index: Integer; const S: WideString); procedure PutObject(Index: Integer; AObject: TObject); public constructor Create; function AddObject(const S: WideString; AObject: TObject): Integer; property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive; property Objects[Index: Integer]: TObject read GetObject write PutObject; property Strings[Index: Integer]: WideString read Get write Put; default; end; // Classes.pas ----------------------------------------------------------------- type TFileStream = TFileStreamEx; // SysUtils.pas ---------------------------------------------------------------- function FileExists(const FileName: String): Boolean; inline; // Windows.pas ----------------------------------------------------------------- function CreateFile(lpFileName: LPCSTR; dwDesiredAccess: DWORD; dwShareMode: DWORD; lpSecurityAttributes: LPSECURITY_ATTRIBUTES; dwCreationDisposition: DWORD; dwFlagsAndAttributes: DWORD; hTemplateFile: HANDLE): HANDLE; inline; function GetFileAttributesEx(lpFileName: LPCSTR; fInfoLevelId: TGET_FILEEX_INFO_LEVELS; lpFileInformation: Pointer): BOOL; inline; implementation uses LazFileUtils, DCOSUtils, DCWindows; function StreamCopy(Source, Target: TStream): Int64; begin Result:= Target.CopyFrom(Source, Source.Size); end; function LocalDateTimeToFileTime(DateTime: TDateTime): TFileTime; begin Int64(Result) := Round((Extended(DateTime) + 109205.0) * 864000000000.0); Windows.LocalFileTimeToFileTime(@Result, @Result); end; function PathAddSeparator(const Path: String): String; begin Result:= IncludeTrailingPathDelimiter(Path); end; function PathRemoveSeparator(const Path: String): String; begin Result:= ExcludeTrailingPathDelimiter(Path); end; function PathGetRelativePath(const Base, Path: String): String; begin Result:= ExtractRelativePath(Base, Path); end; function PathMatchSpecW(pszFile, pszSpec: LPCWSTR): BOOL; stdcall; external 'shlwapi.dll'; function PathCanonicalizeW(lpszDst, lpszSrc: LPCWSTR): BOOL; stdcall; external 'shlwapi.dll'; function PathCanonicalize(const Path: WideString): WideString; begin SetLength(Result, MAX_PATH); if PathCanonicalizeW(PWideChar(Result), PWideChar(Path)) then Result:= PWideChar(Result) else begin Result:= EmptyWideStr; end; end; function IsFileNameMatch(const FileName, Mask: WideString): Boolean; begin Result:= PathMatchSpecW(PWideChar(FileName), PWideChar(Mask)); end; procedure BuildFileList(const SourceFile: String; FileAttr: Integer; InnerList: TStrings; Dummy: Boolean); begin raise Exception.Create('Not implemented'); end; procedure EnumFiles(const Path: String; OnAddFile: TJclOnAddFile; ExcludeAttributes: Integer); begin raise Exception.Create('Not implemented'); end; procedure EnumDirectories(const Path: String; OnAddDirectory: TJclOnAddDirectory; DummyBoolean: Boolean; const DummyString: String; DummyPointer: Pointer); begin raise Exception.Create('Not implemented'); end; function FileDelete(const FileName: String): Boolean; begin Result:= mbDeleteFile(FileName); end; function FindUnusedFileName(const FileName, FileExt: String): String; var Counter: Int64 = 0; begin Result:= FileName + ExtensionSeparator + FileExt; if FileExists(Result) then repeat Inc(Counter); Result:= FileName + IntToStr(Counter) + ExtensionSeparator + FileExt; until not FileExists(Result); end; function FileMove(const OldName, NewName: String; Replace: Boolean): Boolean; const dwFlags: array[Boolean] of DWORD = (0, MOVEFILE_REPLACE_EXISTING); begin Result:= MoveFileExW(PWideChar(UTF16LongName(OldName)), PWideChar(UTF16LongName(NewName)), dwFlags[Replace] or MOVEFILE_COPY_ALLOWED); end; function GUIDEquals(const GUID1, GUID2: TGUID): Boolean; begin Result:= IsEqualGUID(GUID1, GUID2); end; class function JclSysUtils.LoadModule(var Module: TModuleHandle; FileName: String): Boolean; begin Module:= mbLoadLibrary(FileName); Result:= Module <> INVALID_MODULEHANDLE_VALUE; end; function GetModuleSymbol(Module: TModuleHandle; SymbolName: String): Pointer; begin Result:= GetProcAddress(Module, PAnsiChar(SymbolName)); end; class procedure JclSysUtils.UnloadModule(var Module: TModuleHandle); begin if Module <> INVALID_MODULEHANDLE_VALUE then begin FreeLibrary(Module); Module:= INVALID_MODULEHANDLE_VALUE; end; end; procedure StrTokenToStrings(const Token: String; Separator: AnsiChar; var Strings: TStrings); var Start: Integer = 1; Len, Finish: Integer; begin Len:= Length(Token); Strings.BeginUpdate; try Strings.Clear; for Finish:= 1 to Len - 1 do begin if Token[Finish] = Separator then begin Strings.Add(Copy(Token, Start, Finish - Start)); Start:= Finish + 1; end; end; if Start <= Len then begin Strings.Add(Copy(Token, Start, Len - Start + 1)); end; finally Strings.EndUpdate; end; end; function FileExists(const FileName: String): Boolean; begin Result:= mbFileExists(FileName); end; function CreateFile(lpFileName: LPCSTR; dwDesiredAccess: DWORD; dwShareMode: DWORD; lpSecurityAttributes: LPSECURITY_ATTRIBUTES; dwCreationDisposition: DWORD; dwFlagsAndAttributes: DWORD; hTemplateFile: HANDLE): HANDLE; begin Result:= CreateFileW(PWideChar(UTF16LongName(lpFileName)), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); end; function GetFileAttributesEx(lpFileName: LPCSTR; fInfoLevelId: TGET_FILEEX_INFO_LEVELS; lpFileInformation: Pointer): BOOL; begin Result:= GetFileAttributesExW(PWideChar(UTF16LongName(lpFileName)), fInfoLevelId, lpFileInformation); end; { TJclDynamicSplitStream } function TJclDynamicSplitStream.LoadVolume: Boolean; begin Result:= Assigned(FVolume); if not Result then begin FVolume:= GetVolume(0); GetVolumeMaxSize(0); Result := Assigned(FVolume); if Result then FVolume.Seek(0, soBeginning); end; end; function TJclDynamicSplitStream.GetVolume(Index: Integer): TStream; begin if Assigned(FOnVolume) then Result:= FOnVolume(Index) else begin Result:= nil; end; end; function TJclDynamicSplitStream.GetVolumeMaxSize(Index: Integer): Int64; begin if Assigned(FOnVolumeMaxSize) then Result:= FOnVolumeMaxSize(Index) else begin Result:= 0; end; end; function TJclDynamicSplitStream.GetSize: Int64; begin if not LoadVolume then Result:= 0 else begin Result:= FVolume.Size; end; end; procedure TJclDynamicSplitStream.SetSize(const NewSize: Int64); begin if LoadVolume then FVolume.Size:= NewSize; end; constructor TJclDynamicSplitStream.Create(ADummy: Boolean); begin inherited Create; end; function TJclDynamicSplitStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if not LoadVolume then Result:= 0 else begin Result:= FVolume.Seek(Offset, Origin); end; end; function TJclDynamicSplitStream.Read(var Buffer; Count: LongInt): LongInt; begin if not LoadVolume then Result:= 0 else begin Result:= FVolume.Read(Buffer, Count); end; end; function TJclDynamicSplitStream.Write(const Buffer; Count: LongInt): LongInt; begin if not LoadVolume then Result:= 0 else begin Result:= FVolume.Write(Buffer, Count); end; end; { TJclWideStringList } procedure TJclWideStringList.SetCaseSensitive(AValue: Boolean); begin if FCaseSensitive <> AValue then begin FCaseSensitive:= AValue; if FCaseSensitive then OnKeyPtrCompare := @CompareWideStringProc else begin OnKeyPtrCompare := @CompareTextWideStringProc; end; if Sorted then Sort; end; end; function TJclWideStringList.Get(Index: Integer): WideString; begin Result := Keys[Index]; end; function TJclWideStringList.GetObject(Index: Integer): TObject; begin Result := Data[Index]; end; procedure TJclWideStringList.Put(Index: Integer; const S: WideString); begin Keys[Index] := S; end; procedure TJclWideStringList.PutObject(Index: Integer; AObject: TObject); begin Data[Index] := AObject; end; function TJclWideStringList.CompareWideStringProc(Key1, Key2: Pointer): Integer; begin {$if FPC_FULLVERSION<30002} Result:= WideStringManager.CompareWideStringProc(WideString(Key1^), WideString(Key2^)); {$else} Result:= WideStringManager.CompareWideStringProc(WideString(Key1^), WideString(Key2^), []); {$endif} end; function TJclWideStringList.CompareTextWideStringProc(Key1, Key2: Pointer): Integer; begin {$if FPC_FULLVERSION<30002} Result:= WideStringManager.CompareTextWideStringProc(WideString(Key1^), WideString(Key2^)); {$else} Result:= WideStringManager.CompareWideStringProc(WideString(Key1^), WideString(Key2^), [coIgnoreCase]); {$endif} end; constructor TJclWideStringList.Create; begin inherited Create; OnKeyPtrCompare := @CompareTextWideStringProc; end; function TJclWideStringList.AddObject(const S: WideString; AObject: TObject): Integer; begin Result:= inherited Add(S, AObject); end; end. ������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/DCJclCompression.pas����������������������������������0000644�0001750�0000144�00000007060�14743153644�024143� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit DCJclCompression; {$mode delphi} interface uses Classes, SysUtils, SevenZip; type { TSfxSevenzipOutStream } TSfxSevenzipOutStream = class(TInterfacedObject, ISequentialOutStream, IOutStream, IUnknown) private FStream: TStream; FSfxLength: Int64; FSfxModule: String; public constructor Create(AStream: TStream; const ASfxModule: String); destructor Destroy; override; // ISequentialOutStream function Write(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; stdcall; // IOutStream function Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; stdcall; function SetSize(NewSize: Int64): HRESULT; stdcall; end; implementation uses ActiveX, JwaWinError; { TSfxSevenzipOutStream } constructor TSfxSevenzipOutStream.Create(AStream: TStream; const ASfxModule: String); var SfxModule: TFileStream; begin inherited Create; FStream := AStream; FSfxModule := ASfxModule; SfxModule:= TFileStream.Create(FSfxModule, fmOpenRead or fmShareDenyNone); try FStream.Seek(0, soBeginning); FSfxLength := FStream.CopyFrom(SfxModule, SfxModule.Size); finally SfxModule.Free; end; end; destructor TSfxSevenzipOutStream.Destroy; begin FStream.Free; inherited Destroy; end; function TSfxSevenzipOutStream.Write(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; stdcall; var Processed: Cardinal; begin if Assigned(FStream) then begin Result := S_OK; Processed := FStream.Write(Data^, Size); if Assigned(ProcessedSize) then ProcessedSize^ := Processed; end else Result := S_FALSE; end; function TSfxSevenzipOutStream.Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; stdcall; var NewPos: Int64; NewOffset: Int64; begin if Assigned(FStream) then begin Result := S_OK; if SeekOrigin <> STREAM_SEEK_SET then NewOffset := Offset else begin NewOffset := Offset + FSfxLength; end; // STREAM_SEEK_SET = 0 = soBeginning // STREAM_SEEK_CUR = 1 = soCurrent // STREAM_SEEK_END = 2 = soEnd NewPos := FStream.Seek(NewOffset, TSeekOrigin(SeekOrigin)); if NewPos < FSfxLength then Exit(E_INVALIDARG); if Assigned(NewPosition) then NewPosition^ := NewPos - FSfxLength; end else Result := S_FALSE; end; function TSfxSevenzipOutStream.SetSize(NewSize: Int64): HRESULT; stdcall; begin if Assigned(FStream) then begin Result := S_OK; FStream.Size := NewSize + FSfxLength; end else Result := S_FALSE; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/DCJclResources.pas������������������������������������0000644�0001750�0000144�00000016120�14743153644�023611� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- SevenZip archiver plugin Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit DCJclResources; {$mode delphi} interface resourcestring RsCompressionUnavailableProperty = 'This property is unavailable'; RsCompressionNoNestedArchive = 'Nested archive is not implemented'; RsCompression7zWindows = 'Windows'; RsCompressionDuplicate = 'Archive already contains the file %s'; RsCompressionUnsupportedMethod = 'Unsupported method'; RsCompressionDataError = 'Data error'; RsCompressionCRCError = 'CRC error'; RsCompressionUnknownError = 'Unknown error'; RsCompressionWriteNotSupported = 'Write operation is not supported'; RsCompressionCompressingError = 'This operation is not allowed during compression'; RsCompressionDecompressingError = 'This operation is not allowed during decompression'; RsCompressionReplaceError = 'Some volume could not be replaced while archive update'; RsCompression7zReturnError = '7-Zip: Error code (%.8x) - %s'; RsCompression7zUnknownValueType = '7-Zip: Property (%d) contains unknown value type (%d)'; RsCompression7zLoadError = '7-Zip: Cannot load library 7z.dll'; RsCompression7zOutArchiveError = '7-Zip: Unable to get out archive interface of %s class'; RsCompression7zInArchiveError = '7-Zip: Unable to get in archive interface of %s class'; RsCompressionZipName = 'ZIP format'; RsCompressionZipExtensions = '*.zip'; RsCompressionBZip2Name = 'BZIP2 format'; RsCompressionBZip2Extensions = '*.bz2;*.bzip2;*.tbz2;*.tbz'; RsCompressionBZip2SubExtensions = '.tbz2=.tar;.tbz=.tar'; RsCompressionRarName = 'RAR format'; RsCompressionRarExtensions = '*.rar;*.r00'; RsCompressionArjName = 'ARJ format'; RsCompressionArjExtensions = '*.arj'; RsCompressionZName = 'Z format'; RsCompressionZExtensions = '*.z;*.taz'; RsCompressionZSubExtensions = '.taz=.tar'; RsCompressionLzhName = 'LZH format'; RsCompressionLzhExtensions = '*.lzh;*.lha'; RsCompression7zName = '7z format'; RsCompression7zExtensions = '*.7z'; RsCompressionCabName = 'CAB format'; RsCompressionCabExtensions = '*.cab'; RsCompressionNsisName = 'NSIS format'; RsCompressionNsisExtensions = '*.nsis'; RsCompressionLzmaName = 'LZMA format'; RsCompressionLzmaExtensions = '*.lzma'; RsCompressionLzma86Name = 'LZMA86 format'; RsCompressionLzma86Extensions = '*.lzma86'; RsCompressionXzName = 'XZ format'; RsCompressionXzExtensions = '*.xz;*.txz'; RsCompressionXzSubExtensions = '.txz=.tar'; RsCompressionPpmdName = 'PPMD format'; RsCompressionPpmdExtensions = '*.ppmd'; RsCompressionTEName = 'TE format'; RsCompressionTEExtensions = '*.te'; RsCompressionUEFIcName = 'UEFIc format'; RsCompressionUEFIcExtensions = '*.scap'; RsCompressionUEFIsName = 'UEFIs format'; RsCompressionUEFIsExtensions = '*.uefif'; RsCompressionSquashFSName = 'SquashFS format'; RsCompressionSquashFSExtensions = '*.squashfs'; RsCompressionCramFSName = 'CramFS format'; RsCompressionCramFSExtensions = '*.cramfs'; RsCompressionApmName = 'APM format'; RsCompressionApmExtensions = '*.apm'; RsCompressionMsLZName = 'MsLZ format'; RsCompressionMsLZExtensions = ''; RsCompressionFlvName = 'FLV format'; RsCompressionFlvExtensions = '*.flv'; RsCompressionSwfName = 'SWF format'; RsCompressionSwfExtensions = '*.swf'; RsCompressionSwfcName = 'SWFC format'; RsCompressionSwfcExtensions = '*.swf'; RsCompressionNtfsName = 'NTFS format'; RsCompressionNtfsExtensions = '*.ntfs;*.img'; RsCompressionFatName = 'FAT format'; RsCompressionFatExtensions = '*.fat;*.img'; RsCompressionMbrName = 'MBR format'; RsCompressionMbrExtensions = '*.mbr'; RsCompressionVhdName = 'VHD format'; RsCompressionVhdExtensions = '*.vhd'; RsCompressionVhdSubExtensions = '.vhd=.mbr'; RsCompressionPeName = 'PE format'; RsCompressionPeExtensions = '*.exe;*.dll'; RsCompressionElfName = 'ELF format'; RsCompressionElfExtensions = ''; RsCompressionMachoName = 'MACH-O format'; RsCompressionMachoExtensions = ''; RsCompressionUdfName = 'UDF format'; RsCompressionUdfExtensions = '*.udf;*.iso;*.img'; RsCompressionXarName = 'XAR format'; RsCompressionXarExtensions = '*.xar;*.pkg'; RsCompressionMubName = 'MUB format'; RsCompressionMubExtensions = '*.mub'; RsCompressionHfsName = 'HFS format'; RsCompressionHfsExtensions = '*.hfs;*.hfsx'; RsCompressionDmgName = 'DMG format'; RsCompressionDmgExtensions = '*.dmg'; RsCompressionCompoundName = 'COMPOUND format'; RsCompressionCompoundExtensions = '*.msi;*.msp;*.doc;*.xls;*.ppt'; RsCompressionWimName = 'WIM format'; RsCompressionWimExtensions = '*.wim;*.swm'; RsCompressionIsoName = 'ISO format'; RsCompressionIsoExtensions = '*.iso;*.img'; RsCompressionChmName = 'CHM format'; RsCompressionChmExtensions = '*.chm;*.chw;*.chi;*.chq;*.hxs;*.hxi;*.hxr;*.hxq;*.hxw;*.lit'; RsCompressionSplitName = 'SPLIT format'; RsCompressionSplitExtensions = '*.001'; RsCompressionRpmName = 'RPM format'; RsCompressionRpmExtensions = '*.rpm'; RsCompressionDebName = 'DEB format'; RsCompressionDebExtensions = '*.deb'; RsCompressionCpioName = 'CPIO format'; RsCompressionCpioExtensions = '*.cpio'; RsCompressionTarName = 'TAR format'; RsCompressionTarExtensions = '*.tar'; RsCompressionGZipName = 'GZIP format'; RsCompressionGZipExtensions = '*.gz;*.gzip;*.tgz'; RsCompressionGZipSubExtensions = '.tgz=.tar'; implementation end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/common/�����������������������������������������������0000755�0001750�0000144�00000000000�14743153644�021562� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/common/JclCompression.pas�����������������������������0000644�0001750�0000144�00001124061�14743153644�025226� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{**************************************************************************************************} { } { Project JEDI Code Library (JCL) } { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may obtain a copy of the } { License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } { ANY KIND, either express or implied. See the License for the specific language governing rights } { and limitations under the License. } { } { The Original Code is JclCompression.pas. } { } { The Initial Developer of the Original Code is Matthias Thoma. } { All Rights Reserved. } { } { Contributors: } { Olivier Sannier (obones) } { Florent Ouchet (outchy) } { Jan Goyvaerts (jgsoft) } { Uwe Schuster (uschuster) } { } {**************************************************************************************************} { } { Alternatively, the contents of this file may be used under the terms of the GNU Lesser General } { Public License (the "LGPL License"), in which case the provisions of the LGPL License are } { applicable instead of those above. If you wish to allow use of your version of this file only } { under the terms of the LGPL License and not to allow others to use your version of this file } { under the MPL, indicate your decision by deleting the provisions above and replace them with the } { notice and other provisions required by the LGPL License. If you do not delete the provisions } { above, a recipient may use your version of this file under either the MPL or the LGPL License. } { } { For more information about the LGPL: } { http://www.gnu.org/copyleft/lesser.html } { } {**************************************************************************************************} { } { Last modified: $Date:: $ } { Revision: $Rev:: $ } { Author: $Author:: $ } { } {**************************************************************************************************} unit JclCompression; {$mode delphi} interface uses {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} {$IFDEF HAS_UNIT_LIBC} Libc, {$ENDIF HAS_UNIT_LIBC} {$IFDEF HAS_UNITSCOPE} {$IFDEF MSWINDOWS} Winapi.Windows, Sevenzip, Winapi.ActiveX, {$ENDIF MSWINDOWS} System.Types, System.SysUtils, System.Classes, System.Contnrs, {$IFDEF ZLIB_RTL} System.ZLib, {$ENDIF ZLIB_RTL} {$ELSE ~HAS_UNITSCOPE} {$IFDEF MSWINDOWS} Windows, Sevenzip, ActiveX, {$ENDIF MSWINDOWS} Types, SysUtils, Classes, Contnrs, {$IFDEF ZLIB_RTL} ZLib, {$ENDIF ZLIB_RTL} {$ENDIF ~HAS_UNITSCOPE} {$IFNDEF FPC} zlibh, bzip2, {$ENDIF FPC} DCJclAlternative; // Must be after Classes, SysUtils, Windows {$IFDEF RTL230_UP} {$HPPEMIT '// To avoid ambiguity with System::Zlib::z_stream_s we force using ours'} {$HPPEMIT '#define z_stream_s Zlibh::z_stream_s'} {$ENDIF RTL230_UP} {************************************************************************************************** Class hierarchy TJclCompressionStream | |-- TJclCompressStream | | | |-- TJclZLibCompressStream handled by zlib http://www.zlib.net/ | |-- TJclBZIP2CompressStream handled by bzip2 http://www.bzip.net/ | |-- TJclGZIPCompressStream handled by zlib http://www.zlib.net/ + JCL | |-- TJclDecompressStream | |-- TJclZLibDecompressStream handled by zlib http://www.zlib.net/ |-- TBZIP2DecompressStream handled by bzip2 http://www.bzip.net/ |-- TGZIPDecompressStream handled by zlib http://www.zlib.net/ + JCL TJclCompressionArchive | |-- TJclCompressArchive | | | |-- TJclSevenzipCompressArchive | | | |-- TJclZipCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclBZ2CompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJcl7zCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclTarCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclGZipCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclXzCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclSwfcCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclWimCompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclDecompressArchive | | | |-- TJclSevenZipDecompressArchive | | | |-- TJclZipDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclBZ2DecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclRarDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclArjDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclZDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclLzhDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJcl7zDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclCabDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclNsisDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclLzmaDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclLzma86DecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclPeDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclElfDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclMachoDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclUdfDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclXarDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclMubDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclHfsDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclDmgDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclCompoundDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclWimDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclIsoDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclBkfDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclChmDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclSplitDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclRpmDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclDebDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclCpioDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclTarDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclGZipDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclXzDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclNtfsDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclFatDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclMbrDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclVhdDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclMslzDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclFlvDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclSwfDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclSwfcDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclAPMDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclPpmdDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclTEDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclUEFIcDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclUEFIsDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclSquashFSDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclCramFSDecompressArchive handled by sevenzip http://sevenzip.sourceforge.net/ | |-- TJclUpdateArchive | |-- TJclSevenzipUpdateArchive | |-- TJclZipUpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ |-- TJclBZ2UpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ |-- TJcl7zUpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ |-- TJclTarUpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ |-- TJclGZipUpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ |-- TJclXzUpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ |-- TJclSwfcUpdateArchive handled by sevenzip http://sevenzip.sourceforge.net/ **************************************************************************************************} type {$IFNDEF FPC} TJclCompressionStream = class(TJclStream) private FOnProgress: TNotifyEvent; FBuffer: Pointer; FBufferSize: Cardinal; FStream: TStream; protected function SetBufferSize(Size: Cardinal): Cardinal; virtual; procedure Progress(Sender: TObject); dynamic; property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; public class function StreamExtensions: string; virtual; class function StreamName: string; virtual; class function StreamSubExtensions: string; virtual; constructor Create(AStream: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; procedure Reset; virtual; end; TJclCompressionStreamClass = class of TJclCompressionStream; TJclCompressStream = class(TJclCompressionStream) public function Flush: Integer; dynamic; abstract; constructor Create(Destination: TStream); end; TJclCompressStreamClass = class of TJclCompressStream; TJclDecompressStream = class(TJclCompressionStream) private FOwnsStream: Boolean; public constructor Create(Source: TStream; AOwnsStream: Boolean = False); destructor Destroy; override; end; TJclDecompressStreamClass = class of TJclDecompressStream; TJclCompressionStreamFormats = class private FCompressFormats: TList; FDecompressFormats: TList; protected function GetCompressFormatCount: Integer; function GetCompressFormat(Index: Integer): TJclCompressStreamClass; function GetDecompressFormatCount: Integer; function GetDecompressFormat(Index: Integer): TJclDecompressStreamClass; public constructor Create; destructor Destroy; override; procedure RegisterFormat(AClass: TJclCompressionStreamClass); procedure UnregisterFormat(AClass: TJclCompressionStreamClass); function FindCompressFormat(const AFileName: TFileName): TJclCompressStreamClass; function FindDecompressFormat(const AFileName: TFileName): TJclDecompressStreamClass; property CompressFormatCount: Integer read GetCompressFormatCount; property CompressFormats[Index: Integer]: TJclCompressStreamClass read GetCompressFormat; property DecompressFormatCount: Integer read GetDecompressFormatCount; property DecompressFormats[Index: Integer]: TJclDecompressStreamClass read GetDecompressFormat; end; // retreive a singleton list containing registered stream classes function GetStreamFormats: TJclCompressionStreamFormats; // ZIP Support type TJclCompressionLevel = Integer; TJclZLibCompressStream = class(TJclCompressStream) private FWindowBits: Integer; FMemLevel: Integer; FMethod: Integer; FStrategy: Integer; FDeflateInitialized: Boolean; FCompressionLevel: Integer; protected ZLibRecord: TZStreamRec; procedure SetCompressionLevel(Value: Integer); procedure SetStrategy(Value: Integer); procedure SetMemLevel(Value: Integer); procedure SetMethod(Value: Integer); procedure SetWindowBits(Value: Integer); public // stream description class function StreamExtensions: string; override; class function StreamName: string; override; class function StreamSubExtensions: string; override; constructor Create(Destination: TStream; CompressionLevel: TJclCompressionLevel = -1); destructor Destroy; override; function Flush: Integer; override; procedure Reset; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; function Write(const Buffer; Count: Longint): Longint; override; property WindowBits: Integer read FWindowBits write SetWindowBits; property MemLevel: Integer read FMemLevel write SetMemLevel; property Method: Integer read FMethod write SetMethod; property Strategy: Integer read FStrategy write SetStrategy; property CompressionLevel: Integer read FCompressionLevel write SetCompressionLevel; end; {$IFDEF ZLIB_RTL} const DEF_WBITS = 15; {$EXTERNALSYM DEF_WBITS} DEF_MEM_LEVEL = 8; {$EXTERNALSYM DEF_MEM_LEVEL} type PBytef = PByte; {$EXTERNALSYM PBytef} {$ENDIF ZLIB_RTL} type TJclZLibDecompressStream = class(TJclDecompressStream) private FWindowBits: Integer; FInflateInitialized: Boolean; protected ZLibRecord: TZStreamRec; procedure SetWindowBits(Value: Integer); public // stream description class function StreamExtensions: string; override; class function StreamName: string; override; class function StreamSubExtensions: string; override; constructor Create(Source: TStream; WindowBits: Integer = DEF_WBITS; AOwnsStream: Boolean = False); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property WindowBits: Integer read FWindowBits write SetWindowBits; end; // GZIP Support //=== { GZIP helpers } ======================================================= type TJclGZIPHeader = packed record ID1: Byte; ID2: Byte; CompressionMethod: Byte; Flags: Byte; ModifiedTime: Cardinal; ExtraFlags: Byte; OS: Byte; end; TJclGZIPFooter = packed record DataCRC32: Cardinal; DataSize: Cardinal; end; const // ID1 and ID2 fields JCL_GZIP_ID1 = $1F; // value for the ID1 field JCL_GZIP_ID2 = $8B; // value for the ID2 field // Compression Model field JCL_GZIP_CM_DEFLATE = 8; // Zlib classic // Flags field : extra fields for the header JCL_GZIP_FLAG_TEXT = $01; // file is probably ASCII text JCL_GZIP_FLAG_CRC = $02; // a CRC16 for the header is present JCL_GZIP_FLAG_EXTRA = $04; // extra fields present JCL_GZIP_FLAG_NAME = $08; // original file name is present JCL_GZIP_FLAG_COMMENT = $10; // comment is present // ExtraFlags field : compression level JCL_GZIP_EFLAG_MAX = 2; // compressor used maximum compression JCL_GZIP_EFLAG_FAST = 4; // compressor used fastest compression // OS field : file system JCL_GZIP_OS_FAT = 0; // FAT filesystem (MS-DOS, OS/2, NT/Win32) JCL_GZIP_OS_AMIGA = 1; // Amiga JCL_GZIP_OS_VMS = 2; // VMS (or OpenVMS) JCL_GZIP_OS_UNIX = 3; // Unix JCL_GZIP_OS_VM = 4; // VM/CMS JCL_GZIP_OS_ATARI = 5; // Atari TOS JCL_GZIP_OS_HPFS = 6; // HPFS filesystem (OS/2, NT) JCL_GZIP_OS_MAC = 7; // Macintosh JCL_GZIP_OS_Z = 8; // Z-System JCL_GZIP_OS_CPM = 9; // CP/M JCL_GZIP_OS_TOPS = 10; // TOPS-20 JCL_GZIP_OS_NTFS = 11; // NTFS filesystem (NT) JCL_GZIP_OS_QDOS = 12; // QDOS JCL_GZIP_OS_ACORN = 13; // Acorn RISCOS JCL_GZIP_OS_UNKNOWN = 255; // unknown type TJclGZIPSubFieldHeader = packed record SI1: Byte; SI2: Byte; Len: Word; end; // constants to identify sub fields in the extra field // source: http://www.gzip.org/format.txt const JCL_GZIP_X_AC1 = $41; // AC Acorn RISC OS/BBC MOS file type information JCL_GZIP_X_AC2 = $43; JCL_GZIP_X_Ap1 = $41; // Ap Apollo file type information JCL_GZIP_X_Ap2 = $70; JCL_GZIP_X_cp1 = $63; // cp file compressed by cpio JCL_GZIP_X_cp2 = $70; JCL_GZIP_X_GS1 = $1D; // GS gzsig JCL_GZIP_X_GS2 = $53; JCL_GZIP_X_KN1 = $4B; // KN KeyNote assertion (RFC 2704) JCL_GZIP_X_KN2 = $4E; JCL_GZIP_X_Mc1 = $4D; // Mc Macintosh info (Type and Creator values) JCL_GZIP_X_Mc2 = $63; JCL_GZIP_X_RO1 = $52; // RO Acorn Risc OS file type information JCL_GZIP_X_RO2 = $4F; type TJclGZIPFlag = (gfDataIsText, gfHeaderCRC16, gfExtraField, gfOriginalFileName, gfComment); TJclGZIPFlags = set of TJclGZIPFlag; TJclGZIPFatSystem = (gfsFat, gfsAmiga, gfsVMS, gfsUnix, gfsVM, gfsAtari, gfsHPFS, gfsMac, gfsZ, gfsCPM, gfsTOPS, gfsNTFS, gfsQDOS, gfsAcorn, gfsOther, gfsUnknown); // Format is described in RFC 1952, http://www.faqs.org/rfcs/rfc1952.html TJclGZIPCompressionStream = class(TJclCompressStream) private FFlags: TJclGZIPFlags; FUnixTime: Cardinal; FAutoSetTime: Boolean; FCompressionLevel: TJclCompressionLevel; FFatSystem: TJclGZIPFatSystem; FExtraField: string; FOriginalFileName: TFileName; FComment: string; FZLibStream: TJclZLibCompressStream; FOriginalSize: Cardinal; FDataCRC32: Cardinal; FHeaderWritten: Boolean; FFooterWritten: Boolean; // flag so we only write the footer once! (NEW 2007) procedure WriteHeader; function GetDosTime: TDateTime; function GetUnixTime: Cardinal; procedure SetDosTime(const Value: TDateTime); procedure SetUnixTime(Value: Cardinal); procedure ZLibStreamProgress(Sender: TObject); public // stream description class function StreamExtensions: string; override; class function StreamName: string; override; class function StreamSubExtensions: string; override; constructor Create(Destination: TStream; CompressionLevel: TJclCompressionLevel = -1); destructor Destroy; override; function Write(const Buffer; Count: Longint): Longint; override; procedure Reset; override; // IMPORTANT: In order to get a valid GZip file, Flush MUST be called after // the last call to Write. function Flush: Integer; override; property Flags: TJclGZIPFlags read FFlags write FFlags; property DosTime: TDateTime read GetDosTime write SetDosTime; property UnixTime: Cardinal read GetUnixTime write SetUnixTime; property AutoSetTime: Boolean read FAutoSetTime write FAutoSetTime; property FatSystem: TJclGZIPFatSystem read FFatSystem write FFatSystem; property ExtraField: string read FExtraField write FExtraField; // Note: In order for most decompressors to work, the original file name // must be given or they would display an empty file name in their list. // This does not affect the decompression stream below as it simply reads // the value and does not work with it property OriginalFileName: TFileName read FOriginalFileName write FOriginalFileName; property Comment: string read FComment write FComment; end; TJclGZIPDecompressionStream = class(TJclDecompressStream) private FHeader: TJclGZIPHeader; FFooter: TJclGZIPFooter; FCompressedDataStream: TJclDelegatedStream; FZLibStream: TJclZLibDecompressStream; FOriginalFileName: TFileName; FComment: string; FExtraField: string; FComputedHeaderCRC16: Word; FStoredHeaderCRC16: Word; FComputedDataCRC32: Cardinal; FCompressedDataSize: Int64; FDataSize: Int64; FDataStarted: Boolean; FDataEnded: Boolean; FAutoCheckDataCRC32: Boolean; function GetCompressedDataSize: Int64; function GetComputedDataCRC32: Cardinal; function GetDosTime: TDateTime; function GetFatSystem: TJclGZIPFatSystem; function GetFlags: TJclGZIPFlags; function GetOriginalDataSize: Cardinal; function GetStoredDataCRC32: Cardinal; function ReadCompressedData(Sender: TObject; var Buffer; Count: Longint): Longint; procedure ZLibStreamProgress(Sender: TObject); public // stream description class function StreamExtensions: string; override; class function StreamName: string; override; class function StreamSubExtensions: string; override; constructor Create(Source: TStream; CheckHeaderCRC: Boolean = True; AOwnsStream: Boolean = False); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; property ComputedHeaderCRC16: Word read FComputedHeaderCRC16; property StoredHeaderCRC16: Word read FStoredHeaderCRC16; property ExtraField: string read FExtraField; property OriginalFileName: TFileName read FOriginalFileName; property Comment: string read FComment; property Flags: TJclGZIPFlags read GetFlags; property CompressionLevel: Byte read FHeader.ExtraFlags; property FatSystem: TJclGZIPFatSystem read GetFatSystem; property UnixTime: Cardinal read FHeader.ModifiedTime; property DosTime: TDateTime read GetDosTime; property ComputedDataCRC32: Cardinal read GetComputedDataCRC32; property StoredDataCRC32: Cardinal read GetStoredDataCRC32; property AutoCheckDataCRC32: Boolean read FAutoCheckDataCRC32 write FAutoCheckDataCRC32; property CompressedDataSize: Int64 read GetCompressedDataSize; property OriginalDataSize: Cardinal read GetOriginalDataSize; end; // BZIP2 Support TJclBZIP2CompressionStream = class(TJclCompressStream) private FDeflateInitialized: Boolean; FCompressionLevel: Integer; protected BZLibRecord: bz_stream; procedure SetCompressionLevel(const Value: Integer); public // stream description class function StreamExtensions: string; override; class function StreamName: string; override; class function StreamSubExtensions: string; override; constructor Create(Destination: TStream; ACompressionLevel: TJclCompressionLevel = 9); destructor Destroy; override; function Flush: Integer; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; function Write(const Buffer; Count: Longint): Longint; override; property CompressionLevel: Integer read FCompressionLevel write SetCompressionLevel; end; TJclBZIP2DecompressionStream = class(TJclDecompressStream) private FInflateInitialized: Boolean; protected BZLibRecord: bz_stream; public // stream description class function StreamExtensions: string; override; class function StreamName: string; override; class function StreamSubExtensions: string; override; constructor Create(Source: TStream; AOwnsStream: Boolean = False); overload; destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; {$ENDIF FPC} EJclCompressionError = class(EJclError); {$IFNDEF FPC} // callback type used in helper functions below: TJclCompressStreamProgressCallback = procedure(FileSize, Position: Int64; UserData: Pointer) of object; {helper functions - one liners by wpostma} function GZipFile(SourceFile, DestinationFile: TFileName; CompressionLevel: Integer = Z_DEFAULT_COMPRESSION; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil): Boolean; function UnGZipFile(SourceFile, DestinationFile: TFileName; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil): Boolean; procedure GZipStream(SourceStream, DestinationStream: TStream; CompressionLevel: Integer = Z_DEFAULT_COMPRESSION; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); procedure UnGZipStream(SourceStream, DestinationStream: TStream; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); function BZip2File(SourceFile, DestinationFile: TFileName; CompressionLevel: Integer = 5; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil): Boolean; function UnBZip2File(SourceFile, DestinationFile: TFileName; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil): Boolean; procedure BZip2Stream(SourceStream, DestinationStream: TStream; CompressionLevel: Integer = 5; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); procedure UnBZip2Stream(SourceStream, DestinationStream: TStream; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); {$ENDIF FPC} // archive ancestor classes {$IFDEF MSWINDOWS} type TJclCompressionVolumeEvent = procedure(Sender: TObject; Index: Integer; var AFileName: TFileName; var AStream: TStream; var AOwnsStream: Boolean) of object; TJclCompressionVolumeMaxSizeEvent = procedure(Sender: TObject; Index: Integer; var AVolumeMaxSize: Int64) of object; TJclCompressionProgressEvent = procedure(Sender: TObject; const Value, MaxValue: Int64) of object; TJclCompressionRatioEvent = procedure(Sender: TObject; const InSize, OutSize: Int64) of object; TJclCompressionPasswordEvent = procedure(Sender: TObject; var Password: WideString) of object; TJclCompressionItemProperty = (ipPackedName, ipPackedSize, ipPackedExtension, ipFileSize, ipFileName, ipAttributes, ipCreationTime, ipLastAccessTime, ipLastWriteTime, ipComment, ipHostOS, ipHostFS, ipUser, ipGroup, ipCRC, ipStream, ipMethod, ipEncrypted); TJclCompressionItemProperties = set of TJclCompressionItemProperty; TJclCompressionItemKind = (ikFile, ikDirectory); TJclCompressionOperationSuccess = (osNoOperation, osOK, osUnsupportedMethod, osDataError, osCRCError, osUnknownError); TJclCompressionDuplicateCheck = (dcNone, dcExisting, dcAll); TJclCompressionDuplicateAction = (daOverwrite, daError, daSkip); TJclCompressionArchive = class; TJclCompressionItem = class private FArchive: TJclCompressionArchive; // source or destination FFileName: TFileName; FStream: TStream; FOwnsStream: Boolean; // miscellaneous FValidProperties: TJclCompressionItemProperties; FModifiedProperties: TJclCompressionItemProperties; FPackedIndex: Cardinal; FSelected: Boolean; FOperationSuccess: TJclCompressionOperationSuccess; // file properties FPackedName: WideString; FPackedSize: Int64; FFileSize: Int64; FAttributes: Cardinal; FPackedExtension: WideString; FCreationTime: TFileTime; FLastAccessTime: TFileTime; FLastWriteTime: TFileTime; FComment: WideString; FHostOS: WideString; FHostFS: WideString; FUser: WideString; FGroup: WideString; FCRC: Cardinal; FMethod: WideString; FEncrypted: Boolean; function WideChangeFileExt(const AFileName, AExtension: WideString): WideString; function WideExtractFileExt(const AFileName: WideString): WideString; function WideExtractFileName(const AFileName: WideString): WideString; protected // property checkers procedure CheckGetProperty(AProperty: TJclCompressionItemProperty); virtual; abstract; procedure CheckSetProperty(AProperty: TJclCompressionItemProperty); virtual; abstract; function ValidateExtraction(Index: Integer): Boolean; virtual; function DeleteOutputFile: Boolean; function UpdateFileTimes: Boolean; // property getters function GetAttributes: Cardinal; function GetComment: WideString; function GetCRC: Cardinal; function GetCreationTime: TFileTime; function GetDirectory: Boolean; function GetEncrypted: Boolean; function GetFileName: TFileName; function GetFileSize: Int64; function GetGroup: WideString; function GetHostFS: WideString; function GetHostOS: WideString; function GetItemKind: TJclCompressionItemKind; function GetLastAccessTime: TFileTime; function GetLastWriteTime: TFileTime; function GetMethod: WideString; function GetNestedArchiveName: WideString; virtual; function GetNestedArchiveStream: TStream; virtual; function GetPackedExtension: WideString; function GetPackedName: WideString; function GetPackedSize: Int64; function GetStream: TStream; function GetUser: WideString; // property setters procedure SetAttributes(Value: Cardinal); procedure SetComment(const Value: WideString); procedure SetCRC(Value: Cardinal); procedure SetCreationTime(const Value: TFileTime); procedure SetDirectory(Value: Boolean); procedure SetEncrypted(Value: Boolean); procedure SetFileName(const Value: TFileName); procedure SetFileSize(const Value: Int64); procedure SetGroup(const Value: WideString); procedure SetHostFS(const Value: WideString); procedure SetHostOS(const Value: WideString); procedure SetLastAccessTime(const Value: TFileTime); procedure SetLastWriteTime(const Value: TFileTime); procedure SetMethod(const Value: WideString); procedure SetPackedExtension(const Value: WideString); procedure SetPackedName(const Value: WideString); procedure SetPackedSize(const Value: Int64); procedure SetStream(const Value: TStream); procedure SetUser(const Value: WideString); public constructor Create(AArchive: TJclCompressionArchive); destructor Destroy; override; // release stream if owned and created from file name procedure ReleaseStream; // properties in archive property Attributes: Cardinal read GetAttributes write SetAttributes; property Comment: WideString read GetComment write SetComment; property CRC: Cardinal read GetCRC write SetCRC; property CreationTime: TFileTime read GetCreationTime write SetCreationTime; property Directory: Boolean read GetDirectory write SetDirectory; property Encrypted: Boolean read GetEncrypted write SetEncrypted; property FileSize: Int64 read GetFileSize write SetFileSize; property Group: WideString read GetGroup write SetGroup; property HostOS: WideString read GetHostOS write SetHostOS; property HostFS: WideString read GetHostFS write SetHostFS; property Kind: TJclCompressionItemKind read GetItemKind; property LastAccessTime: TFileTime read GetLastAccessTime write SetLastAccessTime; property LastWriteTime: TFileTime read GetLastWriteTime write SetLastWriteTime; property Method: WideString read GetMethod write SetMethod; property PackedExtension: WideString read GetPackedExtension write SetPackedExtension; property PackedName: WideString read GetPackedName write SetPackedName; property PackedSize: Int64 read GetPackedSize write SetPackedSize; property User: WideString read GetUser write SetUser; // source or destination property FileName: TFileName read GetFileName write SetFileName; property OwnsStream: Boolean read FOwnsStream write FOwnsStream; property Stream: TStream read GetStream write SetStream; property NestedArchiveStream: TStream read GetNestedArchiveStream; property NestedArchiveName: WideString read GetNestedArchiveName; // miscellaneous property Archive: TJclCompressionArchive read FArchive; property OperationSuccess: TJclCompressionOperationSuccess read FOperationSuccess write FOperationSuccess; property ValidProperties: TJclCompressionItemProperties read FValidProperties; property ModifiedProperties: TJclCompressionItemProperties read FModifiedProperties write FModifiedProperties; property PackedIndex: Cardinal read FPackedIndex; property Selected: Boolean read FSelected write FSelected; end; TJclCompressionItemClass = class of TJclCompressionItem; TJclCompressionVolume = class protected FFileName: TFileName; FTmpFileName: TFileName; FStream: TStream; FTmpStream: TStream; FOwnsStream: Boolean; FOwnsTmpStream: Boolean; FVolumeMaxSize: Int64; public constructor Create(AStream, ATmpStream: TStream; AOwnsStream, AOwnsTmpStream: Boolean; AFileName, ATmpFileName: TFileName; AVolumeMaxSize: Int64); destructor Destroy; override; procedure ReleaseStreams; property FileName: TFileName read FFileName; property TmpFileName: TFileName read FTmpFileName; property Stream: TStream read FStream; property TmpStream: TStream read FTmpStream; property OwnsStream: Boolean read FOwnsStream; property OwnsTmpStream: Boolean read FOwnsTmpStream; property VolumeMaxSize: Int64 read FVolumeMaxSize; end; TJclStreamAccess = (saCreate, saReadOnly, saReadOnlyDenyNone, saWriteOnly, saReadWrite); { TJclCompressionArchive is not ref-counted } TJclCompressionArchive = class(TInterfacedObject, IInterface) private FOnProgress: TJclCompressionProgressEvent; FOnRatio: TJclCompressionRatioEvent; FOnVolume: TJclCompressionVolumeEvent; FOnVolumeMaxSize: TJclCompressionVolumeMaxSizeEvent; FOnPassword: TJclCompressionPasswordEvent; FPassword: WideString; FVolumeIndex: Integer; FVolumeIndexOffset: Integer; FVolumeMaxSize: Int64; FVolumeFileNameMask: TFileName; FProgressMax: Int64; FCancelCurrentOperation: Boolean; FCurrentItemIndex: Integer; function GetItemCount: Integer; function GetItem(Index: Integer): TJclCompressionItem; function GetVolumeCount: Integer; function GetVolume(Index: Integer): TJclCompressionVolume; protected FVolumes: TObjectList; FItems: TObjectList; procedure InitializeArchiveProperties; virtual; function InternalOpenStream(const FileName: TFileName): TStream; function TranslateItemPath(const ItemPath, OldBase, NewBase: WideString): WideString; function DoProgress(const Value, MaxValue: Int64): Boolean; function DoRatio(const InSize, OutSize: Int64): Boolean; function NeedStream(Index: Integer): TStream; function NeedStreamMaxSize(Index: Integer): Int64; procedure ReleaseVolumes; function GetItemClass: TJclCompressionItemClass; virtual; abstract; function GetSupportsNestedArchive: Boolean; virtual; public { IInterface } // function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public PropNames: array of WideString; PropValues: array of TPropVariant; public class function MultipleItemContainer: Boolean; virtual; class function VolumeAccess: TJclStreamAccess; virtual; function ItemAccess: TJclStreamAccess; virtual; class function ArchiveExtensions: string; virtual; class function ArchiveName: string; virtual; class function ArchiveSubExtensions: string; virtual; class function ArchiveSignature: TDynByteArray; virtual; constructor Create(Volume0: TStream; AVolumeMaxSize: Int64 = 0; AOwnVolume: Boolean = False); overload; virtual; constructor Create(const VolumeFileName: TFileName; AVolumeMaxSize: Int64 = 0; VolumeMask: Boolean = False); overload; virtual; // if VolumeMask is true then VolumeFileName represents a mask to get volume file names // "myfile%d.zip" "myfile.zip.%.3d" ... destructor Destroy; override; function AddVolume(const VolumeFileName: TFileName; AVolumeMaxSize: Int64 = 0): Integer; overload; virtual; function AddVolume(const VolumeFileName, TmpVolumeFileName: TFileName; AVolumeMaxSize: Int64 = 0): Integer; overload; virtual; function AddVolume(VolumeStream: TStream; AVolumeMaxSize: Int64 = 0; AOwnsStream: Boolean = False): Integer; overload; virtual; function AddVolume(VolumeStream, TmpVolumeStream: TStream; AVolumeMaxSize: Int64 = 0; AOwnsStream: Boolean = False; AOwnsTmpStream: Boolean = False): Integer; overload; virtual; // miscellaneous procedure ClearVolumes; procedure ClearItems; procedure CheckOperationSuccess; procedure ClearOperationSuccess; procedure SelectAll; procedure UnselectAll; property ItemCount: Integer read GetItemCount; property Items[Index: Integer]: TJclCompressionItem read GetItem; property VolumeCount: Integer read GetVolumeCount; property Volumes[Index: Integer]: TJclCompressionVolume read GetVolume; property VolumeMaxSize: Int64 read FVolumeMaxSize; property VolumeFileNameMask: TFileName read FVolumeFileNameMask; property VolumeIndexOffset: Integer read FVolumeIndexOffset write FVolumeIndexOffset; property CurrentItemIndex: Integer read FCurrentItemIndex; // valid during OnProgress property OnProgress: TJclCompressionProgressEvent read FOnProgress write FOnProgress; property OnRatio: TJclCompressionRatioEvent read FOnRatio write FOnRatio; // volume events property OnVolume: TJclCompressionVolumeEvent read FOnVolume write FOnVolume; property OnVolumeMaxSize: TJclCompressionVolumeMaxSizeEvent read FOnVolumeMaxSize write FOnVolumeMaxSize; property OnPassword: TJclCompressionPasswordEvent read FOnPassword write FOnPassword; property Password: WideString read FPassword write FPassword; property SupportsNestedArchive: Boolean read GetSupportsNestedArchive; property CancelCurrentOperation: Boolean read FCancelCurrentOperation write FCancelCurrentOperation; end; TJclCompressionArchiveClass = class of TJclCompressionArchive; IJclArchiveNumberOfThreads = interface ['{9CFAB801-E68E-4A51-AC49-277B297F1141}'] function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); property NumberOfThreads: Cardinal read GetNumberOfThreads write SetNumberOfThreads; end; IJclArchiveCompressionLevel = interface ['{A6A2F55F-2860-4E44-BC20-8C5D3E322AB6}'] function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); property CompressionLevel: Cardinal read GetCompressionLevel write SetCompressionLevel; property CompressionLevelMax: Cardinal read GetCompressionLevelMax; property CompressionLevelMin: Cardinal read GetCompressionLevelMin; end; TJclCompressionMethod = (cmCopy, cmDeflate, cmDeflate64, cmBZip2, cmLZMA, cmLZMA2, cmPPMd); TJclCompressionMethods = set of TJclCompressionMethod; IJclArchiveCompressionMethod = interface ['{2818F8E8-7D5F-4C8C-865E-9BA4512BB766}'] function GetCompressionMethod: TJclCompressionMethod; function GetSupportedCompressionMethods: TJclCompressionMethods; procedure SetCompressionMethod(Value: TJclCompressionMethod); property CompressionMethod: TJclCompressionMethod read GetCompressionMethod write SetCompressionMethod; property SupportedCompressionMethods: TJclCompressionMethods read GetSupportedCompressionMethods; end; TJclEncryptionMethod = (emNone, emAES128, emAES192, emAES256, emZipCrypto); TJclEncryptionMethods = set of TJclEncryptionMethod; IJclArchiveEncryptionMethod = interface ['{643485B6-66A1-41C9-A13B-0A8453E9D0C9}'] function GetEncryptionMethod: TJclEncryptionMethod; function GetSupportedEncryptionMethods: TJclEncryptionMethods; procedure SetEncryptionMethod(Value: TJclEncryptionMethod); property EncryptionMethod: TJclEncryptionMethod read GetEncryptionMethod write SetEncryptionMethod; property SupportedEncryptionMethods: TJclEncryptionMethods read GetSupportedEncryptionMethods; end; IJclArchiveDictionarySize = interface ['{D3949834-9F3B-49BC-8403-FE3CE5FDCF35}'] function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); property DictionarySize: Cardinal read GetDictionarySize write SetDictionarySize; end; IJclArchiveNumberOfPasses = interface ['{C61B2814-50CE-4C3C-84A5-BACF8A57E3BC}'] function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); property NumberOfPasses: Cardinal read GetNumberOfPasses write SetNumberOfPasses; end; IJclArchiveRemoveSfxBlock = interface ['{852D050D-734E-4610-902A-8FB845DB32A9}'] function GetRemoveSfxBlock: Boolean; procedure SetRemoveSfxBlock(Value: Boolean); property RemoveSfxBlock: Boolean read GetRemoveSfxBlock write SetRemoveSfxBlock; end; IJclArchiveCompressHeader = interface ['{22C62A3B-A58E-4F88-9D3F-08586B542639}'] function GetCompressHeader: Boolean; function GetCompressHeaderFull: Boolean; procedure SetCompressHeader(Value: Boolean); procedure SetCompressHeaderFull(Value: Boolean); property CompressHeader: Boolean read GetCompressHeader write SetCompressHeader; property CompressHeaderFull: Boolean read GetCompressHeaderFull write SetCompressHeaderFull; end; IJclArchiveEncryptHeader = interface ['{7DBA20A8-48A1-4CA2-B9AC-41C219A09A4A}'] function GetEncryptHeader: Boolean; procedure SetEncryptHeader(Value: Boolean); property EncryptHeader: Boolean read GetEncryptHeader write SetEncryptHeader; end; IJclArchiveSaveCreationDateTime = interface ['{8B212BF9-C13F-4582-A4FA-A40E538EFF65}'] function GetSaveCreationDateTime: Boolean; procedure SetSaveCreationDateTime(Value: Boolean); property SaveCreationDateTime: Boolean read GetSaveCreationDateTime write SetSaveCreationDateTime; end; IJclArchiveSaveLastAccessDateTime = interface ['{1A4B2906-9DD2-4584-B7A3-3639DA92AFC5}'] function GetSaveLastAccessDateTime: Boolean; procedure SetSaveLastAccessDateTime(Value: Boolean); property SaveLastAccessDateTime: Boolean read GetSaveLastAccessDateTime write SetSaveLastAccessDateTime; end; IJclArchiveSaveLastWriteDateTime = interface ['{0C1729DC-35E8-43D4-8ECA-54F20CDFF87A}'] function GetSaveLastWriteDateTime: Boolean; procedure SetSaveLastWriteDateTime(Value: Boolean); property SaveLastWriteDateTime: Boolean read GetSaveLastWriteDateTime write SetSaveLastWriteDateTime; end; IJclArchiveAlgorithm = interface ['{53965F1F-24CC-4548-B9E8-5AE2EB7F142D}'] function GetAlgorithm: Cardinal; function GetSupportedAlgorithms: TDynCardinalArray; procedure SetAlgorithm(Value: Cardinal); property Algorithm: Cardinal read GetAlgorithm write SetAlgorithm; property SupportedAlgorithms: TDynCardinalArray read GetSupportedAlgorithms; end; IJclArchiveSolid = interface ['{6902C54C-1577-422C-B18B-E27953A28661}'] function GetSolidBlockSize: Int64; function GetSolidExtension: Boolean; procedure SetSolidBlockSize(const Value: Int64); procedure SetSolidExtension(Value: Boolean); property SolidBlockSize: Int64 read GetSolidBlockSize write SetSolidBlockSize; property SolidExtension: Boolean read GetSolidExtension write SetSolidExtension; end; TJclCompressItem = class(TJclCompressionItem) protected procedure CheckGetProperty(AProperty: TJclCompressionItemProperty); override; procedure CheckSetProperty(AProperty: TJclCompressionItemProperty); override; end; TJclCompressArchive = class(TJclCompressionArchive, IInterface) private FBaseRelName: WideString; FBaseDirName: string; FAddFilesInDir: Boolean; FDuplicateAction: TJclCompressionDuplicateAction; FDuplicateCheck: TJclCompressionDuplicateCheck; procedure InternalAddFile(const Directory: string; const FileInfo: TSearchRec); procedure InternalAddDirectory(const Directory: string); protected FCompressing: Boolean; FPackedNames: TJclWideStringList; procedure CheckNotCompressing; function AddFileCheckDuplicate(NewItem: TJclCompressionItem): Integer; public class function VolumeAccess: TJclStreamAccess; override; function ItemAccess: TJclStreamAccess; override; destructor Destroy; override; function AddDirectory(const PackedName: WideString; const DirName: string = ''; RecurseIntoDir: Boolean = False; AddFilesInDir: Boolean = False): Integer; overload; virtual; function AddFile(const PackedName: WideString; const FileName: TFileName): Integer; overload; virtual; function AddFile(const PackedName: WideString; AStream: TStream; AOwnsStream: Boolean = False): Integer; overload; virtual; procedure Compress; virtual; property DuplicateCheck: TJclCompressionDuplicateCheck read FDuplicateCheck write FDuplicateCheck; property DuplicateAction: TJclCompressionDuplicateAction read FDuplicateAction write FDuplicateAction; end; TJclCompressArchiveClass = class of TJclCompressArchive; TJclCompressArchiveClassArray = array of TJclCompressArchiveClass; TJclDecompressItem = class(TJclCompressionItem) protected procedure CheckGetProperty(AProperty: TJclCompressionItemProperty); override; procedure CheckSetProperty(AProperty: TJclCompressionItemProperty); override; function ValidateExtraction(Index: Integer): Boolean; override; end; // return False not to extract this file // assign your own FileName, Stream or AOwnsStream to override default one TJclCompressionExtractEvent = function (Sender: TObject; Index: Integer; var FileName: TFileName; var Stream: TStream; var AOwnsStream: Boolean): Boolean of object; TJclDecompressArchive = class(TJclCompressionArchive, IInterface) private FOnExtract: TJclCompressionExtractEvent; FAutoCreateSubDir: Boolean; protected FDecompressing: Boolean; FListing: Boolean; FDestinationDir: string; FExtractingAllIndex: Integer; procedure CheckNotDecompressing; procedure CheckListing; function ValidateExtraction(Index: Integer; var FileName: TFileName; var AStream: TStream; var AOwnsStream: Boolean): Boolean; virtual; public class function VolumeAccess: TJclStreamAccess; override; function ItemAccess: TJclStreamAccess; override; procedure ListFiles; virtual; abstract; procedure ExtractSelected(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); virtual; procedure ExtractAll(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); virtual; property OnExtract: TJclCompressionExtractEvent read FOnExtract write FOnExtract; property DestinationDir: string read FDestinationDir; property AutoCreateSubDir: Boolean read FAutoCreateSubDir; end; TJclDecompressArchiveClass = class of TJclDecompressArchive; TJclDecompressArchiveClassArray = array of TJclDecompressArchiveClass; TJclUpdateItem = class(TJclCompressionItem) protected procedure CheckGetProperty(AProperty: TJclCompressionItemProperty); override; procedure CheckSetProperty(AProperty: TJclCompressionItemProperty); override; function ValidateExtraction(Index: Integer): Boolean; override; end; TJclUpdateArchive = class(TJclCompressArchive, IInterface) private FOnExtract: TJclCompressionExtractEvent; FAutoCreateSubDir: Boolean; protected FDecompressing: Boolean; FListing: Boolean; FDestinationDir: string; FExtractingAllIndex: Integer; procedure CheckNotDecompressing; procedure CheckListing; procedure InitializeArchiveProperties; override; function ValidateExtraction(Index: Integer; var FileName: TFileName; var AStream: TStream; var AOwnsStream: Boolean): Boolean; virtual; public class function VolumeAccess: TJclStreamAccess; override; function ItemAccess: TJclStreamAccess; override; procedure ListFiles; virtual; abstract; procedure ExtractSelected(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); virtual; procedure ExtractAll(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); virtual; procedure DeleteItem(Index: Integer); virtual; abstract; procedure RemoveItem(const PackedName: WideString); virtual; abstract; property OnExtract: TJclCompressionExtractEvent read FOnExtract write FOnExtract; property DestinationDir: string read FDestinationDir; property AutoCreateSubDir: Boolean read FAutoCreateSubDir; end; // ancestor class for all archives that update files in-place (not creating a copy of the volumes) TJclInPlaceUpdateArchive = class(TJclUpdateArchive, IInterface) end; // called when tmp volumes will replace volumes after out-of-place update TJclCompressionReplaceEvent = function (Sender: TObject; const SrcFileName, DestFileName: TFileName; var SrcStream, DestStream: TStream; var OwnsSrcStream, OwnsDestStream: Boolean): Boolean of object; // ancestor class for all archives that update files out-of-place (by creating a copy of the volumes) TJclOutOfPlaceUpdateArchive = class(TJclUpdateArchive, IInterface) private FReplaceVolumes: Boolean; FTmpVolumeIndex: Integer; FOnReplace: TJclCompressionReplaceEvent; FOnTmpVolume: TJclCompressionVolumeEvent; protected function NeedTmpStream(Index: Integer): TStream; procedure InitializeArchiveProperties; override; function InternalOpenTmpStream(const FileName: TFileName): TStream; public class function TmpVolumeAccess: TJclStreamAccess; virtual; procedure Compress; override; property ReplaceVolumes: Boolean read FReplaceVolumes write FReplaceVolumes; property OnReplace: TJclCompressionReplaceEvent read FOnReplace write FOnReplace; property OnTmpVolume: TJclCompressionVolumeEvent read FOnTmpVolume write FOnTmpVolume; end; TJclUpdateArchiveClass = class of TJclUpdateArchive; TJclUpdateArchiveClassArray = array of TJclUpdateArchiveClass; // registered archive formats type TJclCompressionArchiveFormats = class private FCompressFormats: TList; FDecompressFormats: TList; FUpdateFormats: TList; protected function GetCompressFormatCount: Integer; function GetCompressFormat(Index: Integer): TJclCompressArchiveClass; function GetDecompressFormatCount: Integer; function GetDecompressFormat(Index: Integer): TJclDecompressArchiveClass; function GetUpdateFormatCount: Integer; function GetUpdateFormat(Index: Integer): TJclUpdateArchiveClass; public constructor Create; destructor Destroy; override; procedure RegisterFormat(AClass: TJclCompressionArchiveClass); procedure UnregisterFormat(AClass: TJclCompressionArchiveClass); // archive signatures do not give significant results for ISO/UDF (signature is not located at stream start) // need to find a generic way to match all signature before publishing the code //function SignatureMatches(Format: TJclCompressionArchiveClass; ArchiveStream: TStream; var Buffer: TDynByteArray): Boolean; function FindCompressFormat(const AFileName: TFileName): TJclCompressArchiveClass; //function FindDecompressFormat(const AFileName: TFileName; TestArchiveSignature: Boolean): TJclDecompressArchiveClass; overload; function FindDecompressFormat(const AFileName: TFileName): TJclDecompressArchiveClass; //overload; //function FindUpdateFormat(const AFileName: TFileName; TestArchiveSignature: Boolean): TJclUpdateArchiveClass; overload; function FindUpdateFormat(const AFileName: TFileName): TJclUpdateArchiveClass; //overload; function FindCompressFormats(const AFileName: TFileName): TJclCompressArchiveClassArray; function FindDecompressFormats(const AFileName: TFileName): TJclDecompressArchiveClassArray; function FindUpdateFormats(const AFileName: TFileName): TJclUpdateArchiveClassArray; property CompressFormatCount: Integer read GetCompressFormatCount; property CompressFormats[Index: Integer]: TJclCompressArchiveClass read GetCompressFormat; property DecompressFormatCount: Integer read GetDecompressFormatCount; property DecompressFormats[Index: Integer]: TJclDecompressArchiveClass read GetDecompressFormat; property UpdateFormatCount: Integer read GetUpdateFormatCount; property UpdateFormats[Index: Integer]: TJclUpdateArchiveClass read GetUpdateFormat; end; // retreive a singleton list containing archive formats function GetArchiveFormats: TJclCompressionArchiveFormats; // sevenzip classes for compression type TJclSevenzipCompressArchive = class(TJclCompressArchive, IInterface) private FSfxModule: String; FOutArchive: IOutArchive; protected function GetItemClass: TJclCompressionItemClass; override; function GetOutArchive: IOutArchive; public class function ArchiveCLSID: TGUID; virtual; class function ArchiveSignature: TDynByteArray; override; destructor Destroy; override; procedure Compress; override; property OutArchive: IOutArchive read GetOutArchive; property SfxModule: String read FSfxModule write FSfxModule; end; // file formats TJclZipCompressArchive = class(TJclSevenzipCompressArchive, IJclArchiveCompressionLevel, IJclArchiveCompressionMethod, IJclArchiveEncryptionMethod, IJclArchiveDictionarySize, IJclArchiveNumberOfPasses, IJclArchiveNumberOfThreads, IJclArchiveAlgorithm, IInterface) private FNumberOfThreads: Cardinal; FEncryptionMethod: TJclEncryptionMethod; FDictionarySize: Cardinal; FCompressionLevel: Cardinal; FCompressionMethod: TJclCompressionMethod; FNumberOfPasses: Cardinal; FAlgorithm: Cardinal; protected procedure InitializeArchiveProperties; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); { IJclArchiveEncryptionMethod } function GetEncryptionMethod: TJclEncryptionMethod; function GetSupportedEncryptionMethods: TJclEncryptionMethods; procedure SetEncryptionMethod(Value: TJclEncryptionMethod); { IJclArchiveDictionarySize } function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveCompressionMethod } function GetCompressionMethod: TJclCompressionMethod; function GetSupportedCompressionMethods: TJclCompressionMethods; procedure SetCompressionMethod(Value: TJclCompressionMethod); { IJclArchiveNumberOfPasses } function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); { IJclArchiveAlgoritm } function GetAlgorithm: Cardinal; function GetSupportedAlgorithms: TDynCardinalArray; procedure SetAlgorithm(Value: Cardinal); end; TJclBZ2CompressArchive = class(TJclSevenzipCompressArchive, IJclArchiveCompressionLevel, IJclArchiveDictionarySize, IJclArchiveNumberOfPasses, IJclArchiveNumberOfThreads, IInterface) private FNumberOfThreads: Cardinal; FDictionarySize: Cardinal; FCompressionLevel: Cardinal; FNumberOfPasses: Cardinal; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); { IJclArchiveDictionarySize } function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveNumberOfPasses } function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); end; TJcl7zCompressArchive = class(TJclSevenzipCompressArchive, IJclArchiveCompressionLevel, IJclArchiveDictionarySize, IJclArchiveNumberOfThreads, IJclArchiveRemoveSfxBlock, IJclArchiveCompressHeader, IJclArchiveEncryptHeader, IJclArchiveSaveCreationDateTime, IJclArchiveSaveLastAccessDateTime, IJclArchiveSaveLastWriteDateTime, IJclArchiveSolid, IInterface) private FNumberOfThreads: Cardinal; FEncryptHeader: Boolean; FRemoveSfxBlock: Boolean; FDictionarySize: Cardinal; FCompressionLevel: Cardinal; FCompressHeader: Boolean; FCompressHeaderFull: Boolean; FSaveLastAccessDateTime: Boolean; FSaveCreationDateTime: Boolean; FSaveLastWriteDateTime: Boolean; FSolidBlockSize: Int64; FSolidExtension: Boolean; protected procedure InitializeArchiveProperties; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); { IJclArchiveEncryptHeader } function GetEncryptHeader: Boolean; procedure SetEncryptHeader(Value: Boolean); { IJclArchiveRemoveSfxBlock } function GetRemoveSfxBlock: Boolean; procedure SetRemoveSfxBlock(Value: Boolean); { IJclArchiveDictionarySize } function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveCompressHeader } function GetCompressHeader: Boolean; function GetCompressHeaderFull: Boolean; procedure SetCompressHeader(Value: Boolean); procedure SetCompressHeaderFull(Value: Boolean); { IJclArchiveSaveLastAccessDateTime } function GetSaveLastAccessDateTime: Boolean; procedure SetSaveLastAccessDateTime(Value: Boolean); { IJclArchiveSaveCreationDateTime } function GetSaveCreationDateTime: Boolean; procedure SetSaveCreationDateTime(Value: Boolean); { IJclArchiveSaveLastWriteDateTime } function GetSaveLastWriteDateTime: Boolean; procedure SetSaveLastWriteDateTime(Value: Boolean); { IJclArchiveSolid } function GetSolidBlockSize: Int64; function GetSolidExtension: Boolean; procedure SetSolidBlockSize(const Value: Int64); procedure SetSolidExtension(Value: Boolean); end; TJclTarCompressArchive = class(TJclSevenzipCompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclGZipCompressArchive = class(TJclSevenzipCompressArchive, IJclArchiveCompressionLevel, IJclArchiveNumberOfPasses, IJclArchiveAlgorithm, IInterface) private FCompressionLevel: Cardinal; FNumberOfPasses: Cardinal; FAlgorithm: Cardinal; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveNumberOfPasses } function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); { IJclArchiveAlgorithm } function GetAlgorithm: Cardinal; function GetSupportedAlgorithms: TDynCardinalArray; procedure SetAlgorithm(Value: Cardinal); end; TJclXzCompressArchive = class(TJclSevenzipCompressArchive, IJclArchiveCompressionMethod, IInterface) private FCompressionMethod: TJclCompressionMethod; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveCompressionMethod } function GetCompressionMethod: TJclCompressionMethod; function GetSupportedCompressionMethods: TJclCompressionMethods; procedure SetCompressionMethod(Value: TJclCompressionMethod); end; TJclSwfcCompressArchive = class(TJclSevenzipCompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclWimCompressArchive = class(TJclSevenzipCompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; // sevenzip classes for decompression type TJclSevenzipDecompressItem = class(TJclDecompressItem) protected function GetNestedArchiveStream: TStream; override; end; TJclSevenzipDecompressArchive = class(TJclDecompressArchive, IInterface) private FInArchive: IInArchive; FInArchiveGetStream: IInArchiveGetStream; FOpened: Boolean; protected procedure OpenArchive; function GetInArchive: IInArchive; function GetInArchiveGetStream: IInArchiveGetStream; function GetItemClass: TJclCompressionItemClass; override; function GetSupportsNestedArchive: Boolean; override; public class function ArchiveCLSID: TGUID; virtual; class function ArchiveSignature: TDynByteArray; override; destructor Destroy; override; procedure ListFiles; override; procedure ExtractSelected(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); override; procedure ExtractAll(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); override; property InArchive: IInArchive read GetInArchive; property InArchiveGetStream: IInArchiveGetStream read GetInArchiveGetStream; end; // file formats TJclZipDecompressArchive = class(TJclSevenzipDecompressArchive, IJclArchiveNumberOfThreads, IInterface) private FNumberOfThreads: Cardinal; protected procedure InitializeArchiveProperties; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); end; TJclBZ2DecompressArchive = class(TJclSevenzipDecompressArchive, IJclArchiveNumberOfThreads, IInterface) private FNumberOfThreads: Cardinal; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); end; TJclRarDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclArjDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclZDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; end; TJclLzhDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJcl7zDecompressArchive = class(TJclSevenzipDecompressArchive, IJclArchiveNumberOfThreads, IInterface) private FNumberOfThreads: Cardinal; protected procedure InitializeArchiveProperties; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); end; TJclCabDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclNsisDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclLzmaDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclLzma86DecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclPeDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclElfDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclMachoDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclUdfDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclXarDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclMubDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclHfsDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclDmgDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclCompoundDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclWimDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclIsoDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; // not implemented in 9.04 {TJclBkfDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) protected function GetCLSID: TGUID; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; end;} TJclChmDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclSplitDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclRpmDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclDebDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclCpioDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclTarDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclGZipDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; end; TJclXzDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; end; TJclNtfsDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclFatDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclMbrDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclVhdDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; end; TJclMslzDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclFlvDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclSwfDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclSwfcDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclAPMDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclPpmdDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclTEDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclUEFIcDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclUEFIsDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclSquashFSDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclCramFSDecompressArchive = class(TJclSevenzipDecompressArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; //sevenzip classes for updates (read and write) type TJclSevenzipUpdateArchive = class(TJclOutOfPlaceUpdateArchive, IInterface) private FInArchive: IInArchive; FOutArchive: IOutArchive; FOpened: Boolean; protected procedure OpenArchive; function GetInArchive: IInArchive; function GetItemClass: TJclCompressionItemClass; override; function GetOutArchive: IOutArchive; public class function ArchiveCLSID: TGUID; virtual; class function ArchiveSignature: TDynByteArray; override; destructor Destroy; override; procedure ListFiles; override; procedure ExtractSelected(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); override; procedure ExtractAll(const ADestinationDir: string = ''; AAutoCreateSubDir: Boolean = True); override; procedure Compress; override; procedure DeleteItem(Index: Integer); override; procedure RemoveItem(const PackedName: WideString); override; property InArchive: IInArchive read GetInArchive; property OutArchive: IOutArchive read GetOutArchive; end; TJclZipUpdateArchive = class(TJclSevenzipUpdateArchive, IJclArchiveCompressionLevel, IJclArchiveCompressionMethod, IJclArchiveEncryptionMethod, IJclArchiveDictionarySize, IJclArchiveNumberOfPasses, IJclArchiveNumberOfThreads, IJclArchiveAlgorithm, IInterface) private FNumberOfThreads: Cardinal; FEncryptionMethod: TJclEncryptionMethod; FDictionarySize: Cardinal; FCompressionLevel: Cardinal; FCompressionMethod: TJclCompressionMethod; FNumberOfPasses: Cardinal; FAlgorithm: Cardinal; protected procedure InitializeArchiveProperties; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); { IJclArchiveEncryptionMethod } function GetEncryptionMethod: TJclEncryptionMethod; function GetSupportedEncryptionMethods: TJclEncryptionMethods; procedure SetEncryptionMethod(Value: TJclEncryptionMethod); { IJclArchiveDictionarySize } function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveCompressionMethod } function GetCompressionMethod: TJclCompressionMethod; function GetSupportedCompressionMethods: TJclCompressionMethods; procedure SetCompressionMethod(Value: TJclCompressionMethod); { IJclArchiveNumberOfPasses } function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); { IJclArchiveAlgoritm } function GetAlgorithm: Cardinal; function GetSupportedAlgorithms: TDynCardinalArray; procedure SetAlgorithm(Value: Cardinal); end; TJclBZ2UpdateArchive = class(TJclSevenzipUpdateArchive, IJclArchiveCompressionLevel, IJclArchiveDictionarySize, IJclArchiveNumberOfPasses, IJclArchiveNumberOfThreads, IInterface) private FNumberOfThreads: Cardinal; FDictionarySize: Cardinal; FCompressionLevel: Cardinal; FNumberOfPasses: Cardinal; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); { IJclArchiveDictionarySize } function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveNumberOfPasses } function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); end; TJcl7zUpdateArchive = class(TJclSevenzipUpdateArchive, IJclArchiveCompressionLevel, IJclArchiveDictionarySize, IJclArchiveNumberOfThreads, IJclArchiveRemoveSfxBlock, IJclArchiveCompressHeader, IJclArchiveEncryptHeader, IJclArchiveSaveCreationDateTime, IJclArchiveSaveLastAccessDateTime, IJclArchiveSaveLastWriteDateTime, IInterface) private FNumberOfThreads: Cardinal; FEncryptHeader: Boolean; FRemoveSfxBlock: Boolean; FDictionarySize: Cardinal; FCompressionLevel: Cardinal; FCompressHeader: Boolean; FCompressHeaderFull: Boolean; FSaveLastAccessDateTime: Boolean; FSaveCreationDateTime: Boolean; FSaveLastWriteDateTime: Boolean; protected procedure InitializeArchiveProperties; override; public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveNumberOfThreads } function GetNumberOfThreads: Cardinal; procedure SetNumberOfThreads(Value: Cardinal); { IJclArchiveEncryptHeader } function GetEncryptHeader: Boolean; procedure SetEncryptHeader(Value: Boolean); { IJclArchiveRemoveSfxBlock } function GetRemoveSfxBlock: Boolean; procedure SetRemoveSfxBlock(Value: Boolean); { IJclArchiveDictionarySize } function GetDictionarySize: Cardinal; procedure SetDictionarySize(Value: Cardinal); { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveCompressHeader } function GetCompressHeader: Boolean; function GetCompressHeaderFull: Boolean; procedure SetCompressHeader(Value: Boolean); procedure SetCompressHeaderFull(Value: Boolean); { IJclArchiveSaveLastAccessDateTime } function GetSaveLastAccessDateTime: Boolean; procedure SetSaveLastAccessDateTime(Value: Boolean); { IJclArchiveSaveCreationDateTime } function GetSaveCreationDateTime: Boolean; procedure SetSaveCreationDateTime(Value: Boolean); { IJclArchiveSaveLastWriteDateTime } function GetSaveLastWriteDateTime: Boolean; procedure SetSaveLastWriteDateTime(Value: Boolean); end; TJclTarUpdateArchive = class(TJclSevenzipUpdateArchive, IInterface) public class function MultipleItemContainer: Boolean; override; class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; TJclGZipUpdateArchive = class(TJclSevenzipUpdateArchive, IJclArchiveCompressionLevel, IJclArchiveNumberOfPasses, IJclArchiveAlgorithm, IInterface) private FCompressionLevel: Cardinal; FNumberOfPasses: Cardinal; FAlgorithm: Cardinal; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveCompressionLevel } function GetCompressionLevel: Cardinal; function GetCompressionLevelMax: Cardinal; function GetCompressionLevelMin: Cardinal; procedure SetCompressionLevel(Value: Cardinal); { IJclArchiveNumberOfPasses } function GetNumberOfPasses: Cardinal; procedure SetNumberOfPasses(Value: Cardinal); { IJclArchiveAlgorithm } function GetAlgorithm: Cardinal; function GetSupportedAlgorithms: TDynCardinalArray; procedure SetAlgorithm(Value: Cardinal); end; TJclXzUpdateArchive = class(TJclSevenzipUpdateArchive, IJclArchiveCompressionMethod, IInterface) private FCompressionMethod: TJclCompressionMethod; protected procedure InitializeArchiveProperties; override; public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveSubExtensions: string; override; class function ArchiveCLSID: TGUID; override; { IJclArchiveCompressionMethod } function GetCompressionMethod: TJclCompressionMethod; function GetSupportedCompressionMethods: TJclCompressionMethods; procedure SetCompressionMethod(Value: TJclCompressionMethod); end; TJclSwfcUpdateArchive = class(TJclSevenzipUpdateArchive, IInterface) public class function ArchiveExtensions: string; override; class function ArchiveName: string; override; class function ArchiveCLSID: TGUID; override; end; // internal sevenzip stuff, do not use it directly type TJclSevenzipOutStream = class(TInterfacedObject, ISequentialOutStream, IOutStream, IUnknown) private FArchive: TJclCompressionArchive; FItemIndex: Integer; FStream: TStream; FOwnsStream: Boolean; FTruncateOnRelease: Boolean; FMaximumPosition: Int64; procedure NeedStream; procedure ReleaseStream; public constructor Create(AArchive: TJclCompressionArchive; AItemIndex: Integer); overload; constructor Create(AStream: TStream; AOwnsStream: Boolean; ATruncateOnRelease: Boolean); overload; destructor Destroy; override; // ISequentialOutStream function Write(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; stdcall; // IOutStream function Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; stdcall; function SetSize(NewSize: Int64): HRESULT; stdcall; end; TJclSevenzipNestedInStream = class(TJclStream) private FInStream: IInStream; protected procedure SetSize(const NewSize: Int64); override; public constructor Create(AInStream: IInStream); function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; TJclSevenzipInStream = class(TInterfacedObject, ISequentialInStream, IInStream, IStreamGetSize, IUnknown) private FArchive: TJclCompressionArchive; FItemIndex: Integer; FStream: TStream; FOwnsStream: Boolean; procedure NeedStream; procedure ReleaseStream; public constructor Create(AArchive: TJclCompressionArchive; AItemIndex: Integer); overload; constructor Create(AStream: TStream; AOwnsStream: Boolean); overload; destructor Destroy; override; // ISequentialInStream function Read(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; stdcall; // IInStream function Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; stdcall; // IStreamGetSize function GetSize(Size: PInt64): HRESULT; stdcall; end; TJclSevenzipOpenCallback = class(TInterfacedObject, IArchiveOpenCallback, ICryptoGetTextPassword, IUnknown) private FArchive: TJclCompressionArchive; public constructor Create(AArchive: TJclCompressionArchive); // IArchiveOpenCallback function SetCompleted(Files: PInt64; Bytes: PInt64): HRESULT; stdcall; function SetTotal(Files: PInt64; Bytes: PInt64): HRESULT; stdcall; // ICryptoGetTextPassword function CryptoGetTextPassword(password: PBStr): HRESULT; stdcall; end; TJclSevenzipExtractCallback = class(TInterfacedObject, IUnknown, IProgress, IArchiveExtractCallback, ICryptoGetTextPassword, ICompressProgressInfo) private FArchive: TJclCompressionArchive; FLastStream: Cardinal; public constructor Create(AArchive: TJclCompressionArchive); // IArchiveExtractCallback function GetStream(Index: Cardinal; out OutStream: ISequentialOutStream; askExtractMode: Cardinal): HRESULT; stdcall; function PrepareOperation(askExtractMode: Cardinal): HRESULT; stdcall; function SetOperationResult(resultEOperationResult: Integer): HRESULT; stdcall; // IProgress function SetCompleted(CompleteValue: PInt64): HRESULT; stdcall; function SetTotal(Total: Int64): HRESULT; stdcall; // ICryptoGetTextPassword function CryptoGetTextPassword(password: PBStr): HRESULT; stdcall; // ICompressProgressInfo function SetRatioInfo(InSize: PInt64; OutSize: PInt64): HRESULT; stdcall; end; TJclSevenzipUpdateCallback = class(TInterfacedObject, IUnknown, IProgress, IArchiveUpdateCallback, IArchiveUpdateCallback2, ICryptoGetTextPassword2, ICompressProgressInfo) private FArchive: TJclCompressionArchive; FLastStream: Cardinal; public constructor Create(AArchive: TJclCompressionArchive); // IProgress function SetCompleted(CompleteValue: PInt64): HRESULT; stdcall; function SetTotal(Total: Int64): HRESULT; stdcall; // IArchiveUpdateCallback function GetProperty(Index: Cardinal; PropID: Cardinal; out Value: tagPROPVARIANT): HRESULT; stdcall; function GetStream(Index: Cardinal; out InStream: ISequentialInStream): HRESULT; stdcall; function GetUpdateItemInfo(Index: Cardinal; NewData: PInteger; NewProperties: PInteger; IndexInArchive: PCardinal): HRESULT; stdcall; function SetOperationResult(OperationResult: Integer): HRESULT; stdcall; // IArchiveUpdateCallback2 function GetVolumeSize(Index: Cardinal; Size: PInt64): HRESULT; stdcall; function GetVolumeStream(Index: Cardinal; out VolumeStream: ISequentialOutStream): HRESULT; stdcall; // ICryptoGetTextPassword2 function CryptoGetTextPassword2(PasswordIsDefined: PInteger; Password: PBStr): HRESULT; stdcall; // ICompressProgressInfo function SetRatioInfo(InSize: PInt64; OutSize: PInt64): HRESULT; stdcall; end; type TWideStringSetter = procedure (const Value: WideString) of object; TCardinalSetter = procedure (Value: Cardinal) of object; TInt64Setter = procedure (const Value: Int64) of object; TFileTimeSetter = procedure (const Value: TFileTime) of object; TBoolSetter = procedure (Value: Boolean) of object; procedure SevenzipCheck(Value: HRESULT); function Get7zWideStringProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TWideStringSetter): Boolean; function Get7zCardinalProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TCardinalSetter): Boolean; function Get7zInt64Prop(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TInt64Setter): Boolean; function Get7zFileTimeProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TFileTimeSetter): Boolean; function Get7zBoolProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TBoolSetter): Boolean; procedure Load7zFileAttribute(AInArchive: IInArchive; ItemIndex: Integer; AItem: TJclCompressionItem); procedure GetSevenzipArchiveCompressionProperties(AJclArchive: IInterface; ASevenzipArchive: IInterface); procedure SetSevenzipArchiveCompressionProperties(AJclArchive: IInterface; ASevenzipArchive: IInterface); function Create7zFile(SourceFiles: TStrings; const DestinationFile: TFileName; VolumeSize: Int64 = 0; Password: String = ''; OnArchiveProgress: TJclCompressionProgressEvent = nil; OnArchiveRatio: TJclCompressionRatioEvent = nil): Boolean; overload; function Create7zFile(const SourceFile, DestinationFile: TFileName; VolumeSize: Int64 = 0; Password: String = ''; OnArchiveProgress: TJclCompressionProgressEvent = nil; OnArchiveRatio: TJclCompressionRatioEvent = nil): Boolean; overload; var JclCompressSharedFiles: Boolean = False; {$ENDIF MSWINDOWS} {$IFDEF UNITVERSIONING} const UnitVersioning: TUnitVersionInfo = ( RCSfile: '$URL$'; Revision: '$Revision$'; Date: '$Date$'; LogPath: 'JCL\source\common'; Extra: ''; Data: nil ); {$ENDIF UNITVERSIONING} implementation uses DCJclResources, DCJclCompression; const JclDefaultBufferSize = 131072; // 128k var // using TObject prevents default linking of TJclCompressionStreamFormats // and TJclCompressionArchiveFormats and all classes GlobalStreamFormats: TObject; GlobalArchiveFormats: TObject; {$IFNDEF FPC} //=== { TJclCompressionStream } ============================================== constructor TJclCompressionStream.Create(AStream: TStream); begin inherited Create; FBuffer := nil; SetBufferSize(JclDefaultBufferSize); FStream := AStream; end; destructor TJclCompressionStream.Destroy; begin SetBufferSize(0); inherited Destroy; end; function TJclCompressionStream.Read(var Buffer; Count: Longint): Longint; begin raise EJclCompressionError.CreateRes(@RsCompressionReadNotSupported); end; function TJclCompressionStream.Write(const Buffer; Count: Longint): Longint; begin raise EJclCompressionError.CreateRes(@RsCompressionWriteNotSupported); end; function TJclCompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin raise EJclCompressionError.CreateRes(@RsCompressionSeekNotSupported); end; procedure TJclCompressionStream.Reset; begin raise EJclCompressionError.CreateRes(@RsCompressionResetNotSupported); end; function TJclCompressionStream.SetBufferSize(Size: Cardinal): Cardinal; begin if FBuffer <> nil then FreeMem(FBuffer, FBufferSize); FBufferSize := Size; if FBufferSize > 0 then GetMem(FBuffer, FBufferSize) else FBuffer := nil; Result := FBufferSize; end; class function TJclCompressionStream.StreamExtensions: string; begin Result := ''; end; class function TJclCompressionStream.StreamName: string; begin Result := ''; end; class function TJclCompressionStream.StreamSubExtensions: string; begin Result := ''; end; procedure TJclCompressionStream.Progress(Sender: TObject); begin if Assigned(FOnProgress) then FOnProgress(Sender); end; //=== { TJclCompressStream } ================================================= constructor TJclCompressStream.Create(Destination: TStream); begin inherited Create(Destination); end; //=== { TJclDecompressStream } =============================================== constructor TJclDecompressStream.Create(Source: TStream; AOwnsStream: Boolean); begin inherited Create(Source); FOwnsStream := AOwnsStream; end; destructor TJclDecompressStream.Destroy; begin if FOwnsStream then FStream.Free; inherited Destroy; end; //=== { TJclCompressionStreamFormats } ======================================= constructor TJclCompressionStreamFormats.Create; begin inherited Create; FCompressFormats := TList.Create; FDecompressFormats := TList.Create; RegisterFormat(TJclZLibCompressStream); RegisterFormat(TJclZLibDecompressStream); RegisterFormat(TJclGZIPCompressionStream); RegisterFormat(TJclGZIPDecompressionStream); RegisterFormat(TJclBZIP2CompressionStream); RegisterFormat(TJclBZIP2DecompressionStream); end; destructor TJclCompressionStreamFormats.Destroy; begin FCompressFormats.Free; FDecompressFormats.Free; inherited Destroy; end; function TJclCompressionStreamFormats.FindCompressFormat(const AFileName: TFileName): TJclCompressStreamClass; var IndexFormat, IndexFilter: Integer; Filters: TStrings; AFormat: TJclCompressStreamClass; begin Result := nil; Filters := TStringList.Create; try for IndexFormat := 0 to CompressFormatCount - 1 do begin AFormat := CompressFormats[IndexFormat]; StrTokenToStrings(AFormat.StreamExtensions, DirSeparator, Filters); for IndexFilter := 0 to Filters.Count - 1 do if IsFileNameMatch(AFileName, Filters.Strings[IndexFilter]) then begin Result := AFormat; Break; end; if Result <> nil then Break; end; finally Filters.Free; end; end; function TJclCompressionStreamFormats.FindDecompressFormat(const AFileName: TFileName): TJclDecompressStreamClass; var IndexFormat, IndexFilter: Integer; Filters: TStrings; AFormat: TJclDecompressStreamClass; begin Result := nil; Filters := TStringList.Create; try for IndexFormat := 0 to DecompressFormatCount - 1 do begin AFormat := DecompressFormats[IndexFormat]; StrTokenToStrings(AFormat.StreamExtensions, DirSeparator, Filters); for IndexFilter := 0 to Filters.Count - 1 do if IsFileNameMatch(AFileName, Filters.Strings[IndexFilter]) then begin Result := AFormat; Break; end; if Result <> nil then Break; end; finally Filters.Free; end; end; function TJclCompressionStreamFormats.GetCompressFormat(Index: Integer): TJclCompressStreamClass; begin Result := TJclCompressStreamClass(FCompressFormats.Items[Index]); end; function TJclCompressionStreamFormats.GetCompressFormatCount: Integer; begin Result := FCompressFormats.Count; end; function TJclCompressionStreamFormats.GetDecompressFormat(Index: Integer): TJclDecompressStreamClass; begin Result := TJclDecompressStreamClass(FDecompressFormats.Items[Index]); end; function TJclCompressionStreamFormats.GetDecompressFormatCount: Integer; begin Result := FDecompressFormats.Count; end; procedure TJclCompressionStreamFormats.RegisterFormat(AClass: TJclCompressionStreamClass); begin if AClass.InheritsFrom(TJclCompressStream) then FCompressFormats.Add(AClass) else if AClass.InheritsFrom(TJclDecompressStream) then FDecompressFormats.Add(AClass); end; procedure TJclCompressionStreamFormats.UnregisterFormat(AClass: TJclCompressionStreamClass); begin if AClass.InheritsFrom(TJclCompressStream) then FCompressFormats.Remove(AClass) else if AClass.InheritsFrom(TJclDecompressStream) then FDecompressFormats.Remove(AClass); end; function GetStreamFormats: TJclCompressionStreamFormats; begin if not Assigned(GlobalStreamFormats) then GlobalStreamFormats := TJclCompressionStreamFormats.Create; Result := TJclCompressionStreamFormats(GlobalStreamFormats); end; //=== { TJclZLibCompressionStream } ========================================== { Error checking helper } function ZLibCheck(const ErrCode: Integer): Integer; begin case ErrCode of 0..High(ErrCode): Result := ErrCode; // no error Z_ERRNO: raise EJclCompressionError.CreateRes(@RsCompressionZLibZErrNo); Z_STREAM_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionZLibZStreamError); Z_DATA_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionZLibZDataError); Z_MEM_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionZLibZMemError); Z_BUF_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionZLibZBufError); Z_VERSION_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionZLibZVersionError); else raise EJclCompressionError.CreateResFmt(@RsCompressionZLibError, [ErrCode]); end; end; constructor TJclZLibCompressStream.Create(Destination: TStream; CompressionLevel: TJclCompressionLevel); begin inherited Create(Destination); LoadZLib; Assert(FBuffer <> nil); Assert(FBufferSize > 0); // Initialize ZLib StreamRecord ZLibRecord.zalloc := nil; // Use build-in memory allocation functionality ZLibRecord.zfree := nil; ZLibRecord.next_in := nil; ZLibRecord.avail_in := 0; ZLibRecord.next_out := FBuffer; ZLibRecord.avail_out := FBufferSize; FWindowBits := DEF_WBITS; FMemLevel := DEF_MEM_LEVEL; FMethod := Z_DEFLATED; FStrategy := Z_DEFAULT_STRATEGY; FCompressionLevel := CompressionLevel; FDeflateInitialized := False; end; destructor TJclZLibCompressStream.Destroy; begin Flush; if FDeflateInitialized then begin ZLibRecord.next_in := nil; ZLibRecord.avail_in := 0; ZLibRecord.avail_out := 0; ZLibRecord.next_out := nil; ZLibCheck(deflateEnd(ZLibRecord)); end; inherited Destroy; end; function TJclZLibCompressStream.Write(const Buffer; Count: Longint): Longint; begin if not FDeflateInitialized then begin ZLibCheck(deflateInit2(ZLibRecord, FCompressionLevel, FMethod, FWindowBits, FMemLevel, FStrategy)); FDeflateInitialized := True; end; ZLibRecord.next_in := @Buffer; ZLibRecord.avail_in := Count; while ZLibRecord.avail_in > 0 do begin ZLibCheck(deflate(ZLibRecord, Z_NO_FLUSH)); if ZLibRecord.avail_out = 0 then // Output buffer empty. Write to stream and go on... begin FStream.WriteBuffer(FBuffer^, FBufferSize); Progress(Self); ZLibRecord.next_out := FBuffer; ZLibRecord.avail_out := FBufferSize; end; end; Result := Count; end; function TJclZLibCompressStream.Flush: Integer; begin Result := 0; if FDeflateInitialized then begin ZLibRecord.next_in := nil; ZLibRecord.avail_in := 0; while (ZLibCheck(deflate(ZLibRecord, Z_FINISH)) <> Z_STREAM_END) and (ZLibRecord.avail_out = 0) do begin FStream.WriteBuffer(FBuffer^, FBufferSize); Progress(Self); ZLibRecord.next_out := FBuffer; ZLibRecord.avail_out := FBufferSize; Inc(Result, FBufferSize); end; if ZLibRecord.avail_out < FBufferSize then begin FStream.WriteBuffer(FBuffer^, FBufferSize - ZLibRecord.avail_out); Progress(Self); Inc(Result, FBufferSize - ZLibRecord.avail_out); ZLibRecord.next_out := FBuffer; ZLibRecord.avail_out := FBufferSize; end; end; end; function TJclZLibCompressStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset = 0) and (Origin = soCurrent) then Result := ZLibRecord.total_in else if (Offset = 0) and (Origin = soBeginning) and (ZLibRecord.total_in = 0) then Result := 0 else Result := inherited Seek(Offset, Origin); end; procedure TJclZLibCompressStream.SetWindowBits(Value: Integer); begin FWindowBits := Value; end; class function TJclZLibCompressStream.StreamExtensions: string; begin Result := LoadResString(@RsCompressionZExtensions); end; class function TJclZLibCompressStream.StreamName: string; begin Result := LoadResString(@RsCompressionZName); end; class function TJclZLibCompressStream.StreamSubExtensions: string; begin Result := LoadResString(@RsCompressionZSubExtensions); end; procedure TJclZLibCompressStream.SetMethod(Value: Integer); begin FMethod := Value; end; procedure TJclZLibCompressStream.SetStrategy(Value: Integer); begin FStrategy := Value; if FDeflateInitialized then ZLibCheck(deflateParams(ZLibRecord, FCompressionLevel, FStrategy)); end; procedure TJclZLibCompressStream.SetMemLevel(Value: Integer); begin FMemLevel := Value; end; procedure TJclZLibCompressStream.SetCompressionLevel(Value: Integer); begin FCompressionLevel := Value; if FDeflateInitialized then ZLibCheck(deflateParams(ZLibRecord, FCompressionLevel, FStrategy)); end; procedure TJclZLibCompressStream.Reset; begin if FDeflateInitialized then begin Flush; ZLibCheck(deflateReset(ZLibRecord)); end; end; //=== { TJclZLibDecompressionStream } ======================================= constructor TJclZLibDecompressStream.Create(Source: TStream; WindowBits: Integer; AOwnsStream: Boolean); begin inherited Create(Source, AOwnsStream); LoadZLib; // Initialize ZLib StreamRecord ZLibRecord.zalloc := nil; // Use build-in memory allocation functionality ZLibRecord.zfree := nil; ZLibRecord.next_in := nil; ZLibRecord.avail_in := 0; ZLibRecord.next_out := FBuffer; ZLibRecord.avail_out := FBufferSize; FInflateInitialized := False; FWindowBits := WindowBits; end; destructor TJclZLibDecompressStream.Destroy; begin if FInflateInitialized then begin FStream.Seek(-ZLibRecord.avail_in, soCurrent); ZLibCheck(inflateEnd(ZLibRecord)); end; inherited Destroy; end; function TJclZLibDecompressStream.Read(var Buffer; Count: Longint): Longint; var Res: Integer; begin if not FInflateInitialized then begin ZLibCheck(InflateInit2(ZLibRecord, FWindowBits)); FInflateInitialized := True; end; ZLibRecord.next_out := @Buffer; ZLibRecord.avail_out := Count; while ZLibRecord.avail_out > 0 do // as long as we have data begin if ZLibRecord.avail_in = 0 then begin ZLibRecord.avail_in := FStream.Read(FBuffer^, FBufferSize); if ZLibRecord.avail_in = 0 then begin Result := Count - Longint(ZLibRecord.avail_out); Exit; end; ZLibRecord.next_in := FBuffer; end; if ZLibRecord.avail_in > 0 then begin Res := inflate(ZLibRecord, Z_NO_FLUSH); ZLibCheck(Res); Progress(Self); // Suggestion by ZENsan (mantis 4546) if Res = Z_STREAM_END then begin Result := Count - Longint(ZLibRecord.avail_out); Exit; end; end; end; Result := Count; end; function TJclZLibDecompressStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset = 0) and (Origin = soCurrent) then Result := ZLibRecord.total_out else Result := inherited Seek(Offset, Origin); end; procedure TJclZLibDecompressStream.SetWindowBits(Value: Integer); begin FWindowBits := Value; end; class function TJclZLibDecompressStream.StreamExtensions: string; begin Result := LoadResString(@RsCompressionZExtensions); end; class function TJclZLibDecompressStream.StreamName: string; begin Result := LoadResString(@RsCompressionZName); end; class function TJclZLibDecompressStream.StreamSubExtensions: string; begin Result := LoadResString(@RsCompressionZSubExtensions); end; //=== { TJclGZIPCompressionStream } ========================================== constructor TJclGZIPCompressionStream.Create(Destination: TStream; CompressionLevel: TJclCompressionLevel); begin inherited Create(Destination); LoadZLib; FFlags := [gfHeaderCRC16, gfExtraField, gfOriginalFileName, gfComment]; FAutoSetTime := True; FFatSystem := gfsUnknown; FCompressionLevel := CompressionLevel; FDataCRC32 := crc32(0, nil, 0); end; destructor TJclGZIPCompressionStream.Destroy; begin // BUGFIX: CRC32 and Uncompressed Size missing from GZIP output // unless you called Flush manually. This is not correct Stream behaviour. // Flush should be optional! Flush; FZLibStream.Free; inherited Destroy; end; function TJclGZIPCompressionStream.Flush: Integer; var AFooter: TJclGZIPFooter; begin if Assigned(FZLibStream) then Result := FZLibStream.Flush else Result := 0; if FFooterWritten then Exit; FFooterWritten := True; // Write footer, CRC32 followed by ISIZE AFooter.DataCRC32 := FDataCRC32; AFooter.DataSize := FOriginalSize; Inc(Result, FStream.Write(AFooter, SizeOf(AFooter))); end; function TJclGZIPCompressionStream.GetDosTime: TDateTime; begin if AutoSetTime then Result := Now else Result := UnixTimeToDateTime(FUnixTime); end; function TJclGZIPCompressionStream.GetUnixTime: Cardinal; begin if AutoSetTime then Result := DateTimeToUnixTime(Now) else Result := FUnixTime; end; procedure TJclGZIPCompressionStream.Reset; begin if Assigned(FZLibStream) then FZLibStream.Reset; FDataCRC32 := crc32(0, nil, 0); FOriginalSize := 0; end; procedure TJclGZIPCompressionStream.SetDosTime(const Value: TDateTime); begin AutoSetTime := False; FUnixTime := DateTimeToUnixTime(Value); end; procedure TJclGZIPCompressionStream.SetUnixTime(Value: Cardinal); begin AutoSetTime := False; FUnixTime := Value; end; class function TJclGZIPCompressionStream.StreamExtensions: string; begin Result := LoadResString(@RsCompressionGZipExtensions); end; class function TJclGZIPCompressionStream.StreamName: string; begin Result := LoadResString(@RsCompressionGZipName); end; class function TJclGZIPCompressionStream.StreamSubExtensions: string; begin Result := LoadResString(@RsCompressionGZipSubExtensions); end; function TJclGZIPCompressionStream.Write(const Buffer; Count: Integer): Longint; begin if not FHeaderWritten then begin WriteHeader; FHeaderWritten := True; end; if not Assigned(FZLibStream) then begin FZLibStream := TJclZLibCompressStream.Create(FStream, FCompressionLevel); FZLibStream.WindowBits := -DEF_WBITS; // negative value for raw mode FZLibStream.OnProgress := ZLibStreamProgress; end; Result := FZLibStream.Write(Buffer, Count); FDataCRC32 := crc32(FDataCRC32, PBytef(@Buffer), Result); Inc(FOriginalSize, Result); end; procedure TJclGZIPCompressionStream.WriteHeader; const FatSystemToByte: array [TJclGZIPFatSystem] of Byte = (JCL_GZIP_OS_FAT, JCL_GZIP_OS_AMIGA, JCL_GZIP_OS_VMS, JCL_GZIP_OS_UNIX, JCL_GZIP_OS_VM, JCL_GZIP_OS_ATARI, JCL_GZIP_OS_HPFS, JCL_GZIP_OS_MAC, JCL_GZIP_OS_Z, JCL_GZIP_OS_CPM, JCL_GZIP_OS_TOPS, JCL_GZIP_OS_NTFS, JCL_GZIP_OS_QDOS, JCL_GZIP_OS_ACORN, JCL_GZIP_OS_UNKNOWN, JCL_GZIP_OS_UNKNOWN); var AHeader: TJclGZIPHeader; ExtraFieldLength, HeaderCRC16: Word; HeaderCRC: Cardinal; TmpAnsiString: AnsiString; procedure StreamWriteBuffer(const Buffer; Count: Longint); begin FStream.WriteBuffer(Buffer, Count); if gfHeaderCRC16 in Flags then HeaderCRC := crc32(HeaderCRC, @Byte(Buffer), Count); end; function CheckCString(const Buffer: string): Boolean; var Index: Integer; begin Result := False; for Index := 1 to Length(Buffer) do if Buffer[Index] = #0 then Exit; Result := True; end; begin if gfHeaderCRC16 in Flags then HeaderCRC := crc32(0, nil, 0); AHeader.ID1 := JCL_GZIP_ID1; AHeader.ID2 := JCL_GZIP_ID2; AHeader.CompressionMethod := JCL_GZIP_CM_DEFLATE; AHeader.Flags := 0; if gfDataIsText in Flags then AHeader.Flags := AHeader.Flags or JCL_GZIP_FLAG_TEXT; if gfHeaderCRC16 in Flags then AHeader.Flags := AHeader.Flags or JCL_GZIP_FLAG_CRC; if (gfExtraField in Flags) and (ExtraField <> '') then AHeader.Flags := AHeader.Flags or JCL_GZIP_FLAG_EXTRA; if (gfOriginalFileName in Flags) and (OriginalFileName <> '') then AHeader.Flags := AHeader.Flags or JCL_GZIP_FLAG_NAME; if (gfComment in Flags) and (Comment <> '') then AHeader.Flags := AHeader.Flags or JCL_GZIP_FLAG_COMMENT; if AutoSetTime then AHeader.ModifiedTime := DateTimeToUnixTime(Now) else AHeader.ModifiedTime := FUnixTime; case FCompressionLevel of Z_BEST_COMPRESSION: AHeader.ExtraFlags := JCL_GZIP_EFLAG_MAX; Z_BEST_SPEED: AHeader.ExtraFlags := JCL_GZIP_EFLAG_FAST; else AHeader.ExtraFlags := 0; end; AHeader.OS := FatSystemToByte[FatSystem]; StreamWriteBuffer(AHeader, SizeOf(AHeader)); if (gfExtraField in Flags) and (ExtraField <> '') then begin if Length(ExtraField) > High(Word) then raise EJclCompressionError.CreateRes(@RsCompressionGZIPExtraFieldTooLong); ExtraFieldLength := Length(ExtraField); StreamWriteBuffer(ExtraFieldLength, SizeOf(ExtraFieldLength)); StreamWriteBuffer(ExtraField[1], Length(ExtraField)); end; if (gfOriginalFileName in Flags) and (OriginalFileName <> '') then begin if not CheckCString(OriginalFileName) then raise EJclCompressionError.CreateRes(@RsCompressionGZIPBadString); TmpAnsiString := AnsiString(OriginalFileName); StreamWriteBuffer(TmpAnsiString[1], Length(TmpAnsiString) + 1); end; if (gfComment in Flags) and (Comment <> '') then begin if not CheckCString(Comment) then raise EJclCompressionError.CreateRes(@RsCompressionGZIPBadString); TmpAnsiString := AnsiString(Comment); StreamWriteBuffer(TmpAnsiString[1], Length(TmpAnsiString) + 1); end; if (gfHeaderCRC16 in Flags) then begin HeaderCRC16 := HeaderCRC and $FFFF; FStream.WriteBuffer(HeaderCRC16, SizeOf(HeaderCRC16)); end; end; procedure TJclGZIPCompressionStream.ZLibStreamProgress(Sender: TObject); begin Progress(Self); end; //=== { TJclGZIPDecompressionStream } ======================================== constructor TJclGZIPDecompressionStream.Create(Source: TStream; CheckHeaderCRC: Boolean; AOwnsStream: Boolean); var HeaderCRC: Cardinal; ComputeHeaderCRC: Boolean; ExtraFieldLength: Word; procedure ReadBuffer(var Buffer; SizeOfBuffer: Longint); begin Source.ReadBuffer(Buffer, SizeOfBuffer); if ComputeHeaderCRC then HeaderCRC := crc32(HeaderCRC, @Byte(Buffer), SizeOfBuffer); end; function ReadCString: AnsiString; var Buf: AnsiChar; begin Result := ''; Buf := #0; repeat Source.ReadBuffer(Buf, SizeOf(Buf)); if Buf = #0 then Break; Result := Result + Buf; until False; end; begin inherited Create(Source, AOwnsStream); LoadZLib; FAutoCheckDataCRC32 := True; FComputedDataCRC32 := crc32(0, nil, 0); HeaderCRC := crc32(0, nil, 0); ComputeHeaderCRC := CheckHeaderCRC; ReadBuffer(FHeader, SizeOf(FHeader)); if (FHeader.ID1 <> JCL_GZIP_ID1) or (FHeader.ID2 <> JCL_GZIP_ID2) then raise EJclCompressionError.CreateResFmt(@RsCompressionGZipInvalidID, [FHeader.ID1, FHeader.ID2]); if (FHeader.CompressionMethod <> JCL_GZIP_CM_DEFLATE) then raise EJclCompressionError.CreateResFmt(@RsCompressionGZipUnsupportedCM, [FHeader.CompressionMethod]); if (FHeader.Flags and JCL_GZIP_FLAG_EXTRA) <> 0 then begin ExtraFieldLength := 0; ReadBuffer(ExtraFieldLength, SizeOf(ExtraFieldLength)); SetLength(FExtraField, ExtraFieldLength); ReadBuffer(FExtraField[1], ExtraFieldLength); end; if (FHeader.Flags and JCL_GZIP_FLAG_NAME) <> 0 then FOriginalFileName := TFileName(ReadCString); if (FHeader.Flags and JCL_GZIP_FLAG_COMMENT) <> 0 then FComment := string(ReadCString); if CheckHeaderCRC then begin ComputeHeaderCRC := False; FComputedHeaderCRC16 := HeaderCRC and $FFFF; end; if (FHeader.Flags and JCL_GZIP_FLAG_CRC) <> 0 then begin Source.ReadBuffer(FStoredHeaderCRC16, SizeOf(FStoredHeaderCRC16)); if CheckHeaderCRC and (FComputedHeaderCRC16 <> FStoredHeaderCRC16) then raise EJclCompressionError.CreateRes(@RsCompressionGZipHeaderCRC); end; end; destructor TJclGZIPDecompressionStream.Destroy; begin FZLibStream.Free; FCompressedDataStream.Free; inherited Destroy; end; function TJclGZIPDecompressionStream.GetCompressedDataSize: Int64; begin if not FDataStarted then Result := FStream.Size - FStream.Position - SizeOf(FFooter) else if FDataEnded then Result := FCompressedDataSize else raise EJclCompressionError.CreateRes(@RsCompressionGZipDecompressing); end; function TJclGZIPDecompressionStream.GetComputedDataCRC32: Cardinal; begin if FDataEnded then Result := FComputedDataCRC32 else raise EJclCompressionError.CreateRes(@RsCompressionGZipNotDecompressed); end; function TJclGZIPDecompressionStream.GetDosTime: TDateTime; begin Result := UnixTimeToDateTime(FHeader.ModifiedTime); end; function TJclGZIPDecompressionStream.GetFatSystem: TJclGZIPFatSystem; const ByteToFatSystem: array [JCL_GZIP_OS_FAT..JCL_GZIP_OS_ACORN] of TJclGZIPFatSystem = (gfsFat, gfsAmiga, gfsVMS, gfsUnix, gfsVM, gfsAtari, gfsHPFS, gfsMac, gfsZ, gfsCPM, gfsTOPS, gfsNTFS, gfsQDOS, gfsAcorn); begin case FHeader.OS of JCL_GZIP_OS_FAT..JCL_GZIP_OS_ACORN: Result := ByteToFatSystem[FHeader.OS]; JCL_GZIP_OS_UNKNOWN: Result := gfsUnknown; else Result := gfsOther; end; end; function TJclGZIPDecompressionStream.GetFlags: TJclGZIPFlags; begin Result := []; if (FHeader.Flags and JCL_GZIP_FLAG_TEXT) <> 0 then Result := Result + [gfDataIsText]; if (FHeader.Flags and JCL_GZIP_FLAG_CRC) <> 0 then Result := Result + [gfHeaderCRC16]; if (FHeader.Flags and JCL_GZIP_FLAG_EXTRA) <> 0 then Result := Result + [gfExtraField]; if (FHeader.Flags and JCL_GZIP_FLAG_NAME) <> 0 then Result := Result + [gfOriginalFileName]; if (FHeader.Flags and JCL_GZIP_FLAG_COMMENT) <> 0 then Result := Result + [gfComment]; end; function TJclGZIPDecompressionStream.GetOriginalDataSize: Cardinal; var StartPos: Int64; AFooter: TJclGZIPFooter; begin if not FDataStarted then begin StartPos := FStream.Position; try FStream.Seek(-SizeOf(AFooter), soEnd); AFooter.DataCRC32 := 0; AFooter.DataSize := 0; FStream.ReadBuffer(AFooter, SizeOf(AFooter)); Result := AFooter.DataSize; finally FStream.Seek(StartPos, soBeginning); end; end else if FDataEnded then Result := FFooter.DataSize else raise EJclCompressionError.CreateRes(@RsCompressionGZipDecompressing); end; function TJclGZIPDecompressionStream.GetStoredDataCRC32: Cardinal; var StartPos: Int64; AFooter: TJclGZIPFooter; begin if not FDataStarted then begin StartPos := FStream.Position; try FStream.Seek(-SizeOf(AFooter), soEnd); AFooter.DataSize := 0; AFooter.DataCRC32 := 0; FStream.ReadBuffer(AFooter, SizeOf(AFooter)); Result := AFooter.DataCRC32; finally FStream.Seek(StartPos, soBeginning); end; end else if FDataEnded then Result := FFooter.DataCRC32 else raise EJclCompressionError.CreateRes(@RsCompressionGZipDecompressing); end; function TJclGZIPDecompressionStream.Read(var Buffer; Count: Longint): Longint; begin if not Assigned(FZLibStream) then begin FCompressedDataStream := TJclDelegatedStream.Create; FCompressedDataStream.OnRead := ReadCompressedData; FZLibStream := TJclZLibDecompressStream.Create(FCompressedDataStream, -DEF_WBITS); FZLibStream.OnProgress := ZLibStreamProgress; end; Result := FZLibStream.Read(Buffer, Count); Inc(FDataSize, Result); FComputedDataCRC32 := crc32(FComputedDataCRC32, @Byte(Buffer), Result); if Result < Count then begin if not FDataEnded then // the decompressed stream is stopping before the compressed stream raise EJclCompressionError.CreateRes(@RsCompressionGZipInternalError); if AutoCheckDataCRC32 and (FComputedDataCRC32 <> FFooter.DataCRC32) then raise EJclCompressionError.CreateRes(@RsCompressionGZipDataCRCFailed); end; end; function TJclGZIPDecompressionStream.ReadCompressedData(Sender: TObject; var Buffer; Count: Longint): Longint; var BufferAddr: PAnsiChar; FooterAddr: PAnsiChar; begin if (Count = 0) or FDataEnded then begin Result := 0; Exit; end else if not FDataStarted then begin FDataStarted := True; // prolog if FStream.Read(FFooter, SizeOf(FFooter)) < SizeOf(FFooter) then raise EJclCompressionError.CreateRes(@RsCompressionGZipDataTruncated); end; BufferAddr := @Byte(Buffer); Move(FFooter, Buffer, SizeOf(FFooter)); Result := FStream.Read(BufferAddr[SizeOf(FFooter)], Count - SizeOf(FFooter)) + FStream.Read(FFooter, SizeOf(FFooter)); if Result < Count then begin FDataEnded := True; // epilog FooterAddr := @FFooter; if (Count - Result) < SizeOf(FFooter) then begin // the "real" footer is splitted in the data and the footer // shift the valid bytes of the footer to their place Move(FFooter, FooterAddr[Count - Result], SizeOf(FFooter) - Count + Result); // the missing bytes of the footer are located after the data Move(BufferAddr[Result], FFooter, Count - Result); end else // the "real" footer is located in the data Move(BufferAddr[Result], FFooter, SizeOf(FFooter)); end; Inc(FCompressedDataSize, Result); end; class function TJclGZIPDecompressionStream.StreamExtensions: string; begin Result := LoadResString(@RsCompressionGZipExtensions); end; class function TJclGZIPDecompressionStream.StreamName: string; begin Result := LoadResString(@RsCompressionGZipName); end; class function TJclGZIPDecompressionStream.StreamSubExtensions: string; begin Result := LoadResString(@RsCompressionGZipSubExtensions); end; procedure TJclGZIPDecompressionStream.ZLibStreamProgress(Sender: TObject); begin Progress(Self); end; //=== { TJclBZLibCompressionStream } ========================================= { Error checking helper } function BZIP2LibCheck(const ErrCode: Integer): Integer; begin case ErrCode of 0..High(ErrCode): Result := ErrCode; // no error BZ_SEQUENCE_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2SequenceError); BZ_PARAM_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2ParameterError); BZ_MEM_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2MemoryError); BZ_DATA_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2DataError); BZ_DATA_ERROR_MAGIC: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2HeaderError); BZ_IO_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2IOError); BZ_UNEXPECTED_EOF: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2EOFError); BZ_OUTBUFF_FULL: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2OutBuffError); BZ_CONFIG_ERROR: raise EJclCompressionError.CreateRes(@RsCompressionBZIP2ConfigError); else raise EJclCompressionError.CreateResFmt(@RsCompressionBZIP2Error, [ErrCode]); end; end; constructor TJclBZIP2CompressionStream.Create(Destination: TStream; ACompressionLevel: TJclCompressionLevel); begin inherited Create(Destination); LoadBZip2; Assert(FBuffer <> nil); Assert(FBufferSize > 0); // Initialize ZLib StreamRecord BZLibRecord.bzalloc := nil; // Use build-in memory allocation functionality BZLibRecord.bzfree := nil; BZLibRecord.next_in := nil; BZLibRecord.avail_in := 0; BZLibRecord.next_out := FBuffer; BZLibRecord.avail_out := FBufferSize; FDeflateInitialized := False; FCompressionLevel := ACompressionLevel; end; destructor TJclBZIP2CompressionStream.Destroy; begin Flush; if FDeflateInitialized then BZIP2LibCheck(BZ2_bzCompressEnd(BZLibRecord)); inherited Destroy; end; function TJclBZIP2CompressionStream.Flush: Integer; begin Result := 0; if FDeflateInitialized then begin BZLibRecord.next_in := nil; BZLibRecord.avail_in := 0; while (BZIP2LibCheck(BZ2_bzCompress(BZLibRecord, BZ_FINISH)) <> BZ_STREAM_END) and (BZLibRecord.avail_out = 0) do begin FStream.WriteBuffer(FBuffer^, FBufferSize); Progress(Self); BZLibRecord.next_out := FBuffer; BZLibRecord.avail_out := FBufferSize; Inc(Result, FBufferSize); end; if BZLibRecord.avail_out < FBufferSize then begin FStream.WriteBuffer(FBuffer^, FBufferSize - BZLibRecord.avail_out); Progress(Self); Inc(Result, FBufferSize - BZLibRecord.avail_out); BZLibRecord.next_out := FBuffer; BZLibRecord.avail_out := FBufferSize; end; end; end; function TJclBZIP2CompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset = 0) and (Origin = soCurrent) then Result := (BZLibRecord.total_in_hi32 shl 32) or BZLibRecord.total_in_lo32 else if (Offset = 0) and (Origin = soBeginning) and (BZLibRecord.total_in_lo32 = 0) then Result := 0 else Result := inherited Seek(Offset, Origin); end; procedure TJclBZIP2CompressionStream.SetCompressionLevel(const Value: Integer); begin if not FDeflateInitialized then FCompressionLevel := Value else raise EJclCompressionError.CreateRes(@RsCompressionBZIP2SequenceError); end; class function TJclBZIP2CompressionStream.StreamExtensions: string; begin Result := LoadResString(@RsCompressionBZip2Extensions); end; class function TJclBZIP2CompressionStream.StreamName: string; begin Result := LoadResString(@RsCompressionBZip2Name); end; class function TJclBZIP2CompressionStream.StreamSubExtensions: string; begin Result := LoadResString(@RsCompressionBZip2SubExtensions); end; function TJclBZIP2CompressionStream.Write(const Buffer; Count: Longint): Longint; begin if not FDeflateInitialized then begin BZIP2LibCheck(BZ2_bzCompressInit(BZLibRecord, FCompressionLevel, 0, 0)); FDeflateInitialized := True; end; BZLibRecord.next_in := @Buffer; BZLibRecord.avail_in := Count; while BZLibRecord.avail_in > 0 do begin BZIP2LibCheck(BZ2_bzCompress(BZLibRecord, BZ_RUN)); if BZLibRecord.avail_out = 0 then // Output buffer empty. Write to stream and go on... begin FStream.WriteBuffer(FBuffer^, FBufferSize); Progress(Self); BZLibRecord.next_out := FBuffer; BZLibRecord.avail_out := FBufferSize; end; end; Result := Count; end; //=== { TJclBZip2DecompressionStream } ======================================= constructor TJclBZIP2DecompressionStream.Create(Source: TStream; AOwnsStream: Boolean); begin inherited Create(Source, AOwnsStream); LoadBZip2; // Initialize ZLib StreamRecord BZLibRecord.bzalloc := nil; // Use build-in memory allocation functionality BZLibRecord.bzfree := nil; BZLibRecord.opaque := nil; BZLibRecord.next_in := nil; BZLibRecord.state := nil; BZLibRecord.avail_in := 0; BZLibRecord.next_out := FBuffer; BZLibRecord.avail_out := FBufferSize; FInflateInitialized := False; end; destructor TJclBZIP2DecompressionStream.Destroy; begin if FInflateInitialized then begin FStream.Seek(-BZLibRecord.avail_in, soCurrent); BZIP2LibCheck(BZ2_bzDecompressEnd(BZLibRecord)); end; inherited Destroy; end; function TJclBZIP2DecompressionStream.Read(var Buffer; Count: Longint): Longint; begin if not FInflateInitialized then begin BZIP2LibCheck(BZ2_bzDecompressInit(BZLibRecord, 0, 0)); FInflateInitialized := True; end; BZLibRecord.next_out := @Buffer; BZLibRecord.avail_out := Count; Result := 0; while Result < Count do // as long as we need data begin if BZLibRecord.avail_in = 0 then // no more compressed data begin BZLibRecord.avail_in := FStream.Read(FBuffer^, FBufferSize); if BZLibRecord.avail_in = 0 then Exit; BZLibRecord.next_in := FBuffer; end; if BZLibRecord.avail_in > 0 then begin BZIP2LibCheck(BZ2_bzDecompress(BZLibRecord)); Result := Count; Dec(Result, BZLibRecord.avail_out); end end; Result := Count; end; function TJclBZIP2DecompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset = 0) and (Origin = soCurrent) then Result := (BZLibRecord.total_out_hi32 shl 32) or BZLibRecord.total_out_lo32 else Result := inherited Seek(Offset, Origin); end; class function TJclBZIP2DecompressionStream.StreamExtensions: string; begin Result := LoadResString(@RsCompressionBZip2Extensions); end; class function TJclBZIP2DecompressionStream.StreamName: string; begin Result := LoadResString(@RsCompressionBZip2Name); end; class function TJclBZIP2DecompressionStream.StreamSubExtensions: string; begin Result := LoadResString(@RsCompressionBZip2SubExtensions); end; procedure InternalCompress(SourceStream: TStream; CompressStream: TJclCompressStream; ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer); var SourceStreamSize, SourceStreamPosition: Int64; Buffer: Pointer; ReadBytes: Integer; EofFlag: Boolean; begin SourceStreamSize := SourceStream.Size; // source file size SourceStreamPosition := 0; GetMem(Buffer, JclDefaultBufferSize + 2); try // ZLibStream.CopyFrom(SourceStream, 0 ); // One line way to do it! may not // // be reliable idea to do this! also, // //no progress callbacks! EofFlag := False; while not EofFlag do begin if Assigned(ProgressCallback) then ProgressCallback(SourceStreamSize, SourceStreamPosition, UserData); ReadBytes := SourceStream.Read(Buffer^, JclDefaultBufferSize); SourceStreamPosition := SourceStreamPosition + ReadBytes; CompressStream.WriteBuffer(Buffer^, ReadBytes); // short block indicates end of zlib stream EofFlag := ReadBytes < JclDefaultBufferSize; end; //CompressStream.Flush; (called by the destructor of compression streams finally FreeMem(Buffer); end; if Assigned(ProgressCallback) then ProgressCallback(SourceStreamSize, SourceStreamPosition, UserData); end; procedure InternalDecompress(SourceStream, DestStream: TStream; DecompressStream: TJclDecompressStream; ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer); var SourceStreamSize: Int64; Buffer: Pointer; ReadBytes: Integer; EofFlag: Boolean; begin SourceStreamSize := SourceStream.Size; // source file size GetMem(Buffer, JclDefaultBufferSize + 2); try // ZLibStream.CopyFrom(SourceStream, 0 ); // One line way to do it! may not // // be reliable idea to do this! also, // //no progress callbacks! EofFlag := False; while not EofFlag do begin if Assigned(ProgressCallback) then ProgressCallback(SourceStreamSize, SourceStream.Position, UserData); ReadBytes := DecompressStream.Read(Buffer^, JclDefaultBufferSize); DestStream.WriteBuffer(Buffer^, ReadBytes); // short block indicates end of zlib stream EofFlag := ReadBytes < JclDefaultBufferSize; end; finally FreeMem(Buffer); end; if Assigned(ProgressCallback) then ProgressCallback(SourceStreamSize, SourceStream.Position, UserData); end; { Compress to a .gz file - one liner - NEW MARCH 2007 } function GZipFile(SourceFile, DestinationFile: TFileName; CompressionLevel: Integer; ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer): Boolean; var GZipStream: TJclGZIPCompressionStream; DestStream: TFileStream; SourceStream: TFileStream; GZipStreamDateTime: TDateTime; begin Result := False; if not FileExists(SourceFile) then // can't copy what doesn't exist! Exit; GetFileLastWrite(SourceFile, GZipStreamDateTime); {destination and source streams first and second} SourceStream := TFileStream.Create(SourceFile, fmOpenRead or fmShareDenyWrite); try DestStream := TFileStream.Create(DestinationFile, fmCreate); // see SysUtils try { create compressionstream third, and copy from source, through zlib compress layer, out through file stream} GZipStream := TJclGZIPCompressionStream.Create(DestStream, CompressionLevel); try GZipStream.DosTime := GZipStreamDateTime; InternalCompress(SourceStream, GZipStream, ProgressCallback, UserData); finally GZipStream.Free; end; finally DestStream.Free; end; finally SourceStream.Free; end; Result := FileExists(DestinationFile); end; { Decompress a .gz file } function UnGZipFile(SourceFile, DestinationFile: TFileName; ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer): Boolean; var GZipStream: TJclGZIPDecompressionStream; DestStream: TFileStream; SourceStream: TFileStream; GZipStreamDateTime: TDateTime; begin Result := False; if not FileExists(SourceFile) then // can't copy what doesn't exist! Exit; {destination and source streams first and second} SourceStream := TFileStream.Create(SourceFile, {mode} fmOpenRead or fmShareDenyWrite); try DestStream := TFileStream.Create(DestinationFile, {mode} fmCreate); // see SysUtils try { create decompressionstream third, and copy from source, through zlib decompress layer, out through file stream } GZipStream := TJclGZIPDecompressionStream.Create(SourceStream); try InternalDecompress(SourceStream, DestStream, GZipStream, ProgressCallback, UserData); GZipStreamDateTime := GZipStream.DosTime; finally GZipStream.Free; end; finally DestStream.Free; end; finally SourceStream.Free; end; Result := FileExists(DestinationFile); if Result and (GZipStreamDateTime <> 0) then // preserve datetime when unpacking! (see JclFileUtils) SetFileLastWrite(DestinationFile, GZipStreamDateTime); end; procedure GZipStream(SourceStream, DestinationStream: TStream; CompressionLevel: Integer = Z_DEFAULT_COMPRESSION; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); var GZStream: TJclGZIPCompressionStream; begin GZStream := TJclGZIPCompressionStream.Create(DestinationStream, CompressionLevel); try InternalCompress(SourceStream, GZStream, ProgressCallback, UserData); finally GZStream.Free; end; end; procedure UnGZipStream(SourceStream, DestinationStream: TStream; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); var GZipStream: TJclGZIPDecompressionStream; begin GZipStream := TJclGZIPDecompressionStream.Create(SourceStream); try InternalDecompress(SourceStream, DestinationStream, GZipStream, ProgressCallback, UserData); finally GZipStream.Free; end; end; { Compress to a .bz2 file - one liner } function BZip2File(SourceFile, DestinationFile: TFileName; CompressionLevel: Integer; ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer): Boolean; var BZip2Stream: TJclBZIP2CompressionStream; DestStream: TFileStream; SourceStream: TFileStream; begin Result := False; if not FileExists(SourceFile) then // can't copy what doesn't exist! Exit; {destination and source streams first and second} SourceStream := TFileStream.Create(SourceFile, fmOpenRead or fmShareDenyWrite); try DestStream := TFileStream.Create(DestinationFile, fmCreate); // see SysUtils try { create compressionstream third, and copy from source, through zlib compress layer, out through file stream} BZip2Stream := TJclBZIP2CompressionStream.Create(DestStream, CompressionLevel); try InternalCompress(SourceStream, BZip2Stream, ProgressCallback, UserData); finally BZip2Stream.Free; end; finally DestStream.Free; end; finally SourceStream.Free; end; Result := FileExists(DestinationFile); end; { Decompress a .bzip2 file } function UnBZip2File(SourceFile, DestinationFile: TFileName; ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer): Boolean; var BZip2Stream: TJclBZIP2DecompressionStream; DestStream: TFileStream; SourceStream: TFileStream; begin Result := False; if not FileExists(SourceFile) then // can't copy what doesn't exist! Exit; {destination and source streams first and second} SourceStream := TFileStream.Create(SourceFile, {mode} fmOpenRead or fmShareDenyWrite); try DestStream := TFileStream.Create(DestinationFile, {mode} fmCreate); // see SysUtils try { create decompressionstream third, and copy from source, through zlib decompress layer, out through file stream } BZip2Stream := TJclBZIP2DecompressionStream.Create(SourceStream); try InternalDecompress(SourceStream, DestStream, BZip2Stream, ProgressCallback, UserData); finally BZip2Stream.Free; end; finally DestStream.Free; end; finally SourceStream.Free; end; Result := FileExists(DestinationFile); end; procedure BZip2Stream(SourceStream, DestinationStream: TStream; CompressionLevel: Integer = 5; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); var BZ2Stream: TJclBZIP2CompressionStream; begin BZ2Stream := TJclBZIP2CompressionStream.Create(DestinationStream, CompressionLevel); try InternalCompress(SourceStream, BZ2Stream, ProgressCallback, UserData); finally BZ2Stream.Free; end; end; procedure UnBZip2Stream(SourceStream, DestinationStream: TStream; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); var BZip2Stream: TJclBZIP2DecompressionStream; begin BZip2Stream := TJclBZIP2DecompressionStream.Create(SourceStream); try InternalDecompress(SourceStream, DestinationStream, BZip2Stream, ProgressCallback, UserData); finally BZip2Stream.Free; end; end; {$ENDIF FPC} {$IFDEF MSWINDOWS} function OpenFileStream(const FileName: TFileName; StreamAccess: TJclStreamAccess): TStream; begin Result := nil; case StreamAccess of saCreate: Result := TFileStream.Create(FileName, fmCreate); saReadOnly: if FileExists(FileName) then Result := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); saReadOnlyDenyNone: if FileExists(FileName) then Result := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); saWriteOnly: if FileExists(FileName) then Result := TFileStream.Create(FileName, fmOpenWrite) else if FileName <> '' then Result := TFileStream.Create(FileName, fmCreate); saReadWrite: if FileExists(FileName) then Result := TFileStream.Create(FileName, fmOpenReadWrite) else if FileName <> '' then Result := TFileStream.Create(FileName, fmCreate); end; end; //=== { TJclCompressionItem } ================================================ constructor TJclCompressionItem.Create(AArchive: TJclCompressionArchive); begin inherited Create; FArchive := AArchive; FPackedIndex := $FFFFFFFF; end; function TJclCompressionItem.DeleteOutputFile: Boolean; begin Result := (FFileName <> '') and FileExists(FFileName) and FileDelete(FFileName); end; destructor TJclCompressionItem.Destroy; begin ReleaseStream; inherited Destroy; end; function TJclCompressionItem.GetAttributes: Cardinal; begin CheckGetProperty(ipAttributes); Result := FAttributes; end; function TJclCompressionItem.GetComment: WideString; begin CheckGetProperty(ipComment); Result := FComment; end; function TJclCompressionItem.GetCRC: Cardinal; begin CheckGetProperty(ipCRC); Result := FCRC; end; function TJclCompressionItem.GetCreationTime: TFileTime; begin CheckGetProperty(ipCreationTime); Result := FCreationTime; end; function TJclCompressionItem.GetDirectory: Boolean; begin Result := (Attributes and FILE_ATTRIBUTE_DIRECTORY) <> 0; end; function TJclCompressionItem.GetEncrypted: Boolean; begin CheckGetProperty(ipEncrypted); Result := FEncrypted; end; function TJclCompressionItem.GetFileName: TFileName; begin CheckGetProperty(ipFileName); Result := FFileName; end; function TJclCompressionItem.GetFileSize: Int64; begin CheckGetProperty(ipFileSize); Result := FFileSize; end; function TJclCompressionItem.GetGroup: WideString; begin CheckGetProperty(ipGroup); Result := FGroup; end; function TJclCompressionItem.GetHostFS: WideString; begin CheckGetProperty(ipHostFS); Result := FHostFS; end; function TJclCompressionItem.GetHostOS: WideString; begin CheckGetProperty(ipHostOS); Result := FHostOS; end; function TJclCompressionItem.GetItemKind: TJclCompressionItemKind; begin if (Attributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then Result := ikDirectory else Result := ikFile; end; function TJclCompressionItem.GetLastAccessTime: TFileTime; begin CheckGetProperty(ipLastAccessTime); Result := FLastAccessTime; end; function TJclCompressionItem.GetLastWriteTime: TFileTime; begin CheckGetProperty(ipLastWriteTime); Result := FLastWriteTime; end; function TJclCompressionItem.GetMethod: WideString; begin CheckGetProperty(ipMethod); Result := FMethod; end; function TJclCompressionItem.GetNestedArchiveName: WideString; var ParentArchiveExtension, ArchiveFileName, ArchiveExtension: WideString; ExtensionMap: TStrings; begin if ipPackedName in ValidProperties then Result := PackedName else begin ArchiveFileName := ''; ArchiveExtension := ''; // find archive file name if Archive.VolumeCount > 0 then ArchiveFileName := WideExtractFileName(WideString(Archive.Volumes[0].FileName)); if (ArchiveFileName <> '') and (WideExtractFileExt(ArchiveFileName) = '.001') then ArchiveFileName := WideChangeFileExt(ArchiveFileName, ''); ParentArchiveExtension := WideExtractFileExt(ArchiveFileName); ArchiveFileName := WideChangeFileExt(ArchiveFileName, ''); // find item extension ArchiveExtension := WideExtractFileExt(ArchiveFileName); if ArchiveExtension <> '' then ArchiveFileName := WideChangeFileExt(ArchiveFileName, '') else if ipPackedExtension in ValidProperties then ArchiveExtension := PackedExtension else if ArchiveFileName <> '' then begin ExtensionMap := TStringList.Create; try ExtensionMap.Delimiter := ';'; ExtensionMap.DelimitedText := Archive.ArchiveSubExtensions; ArchiveExtension := ExtensionMap.Values[ParentArchiveExtension]; finally ExtensionMap.Free; end; end; // elaborate result if (ArchiveFileName = '') and (ArchiveExtension = '') then raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty) else if ArchiveFileName = '' then Result := ArchiveExtension else Result := WideChangeFileExt(ArchiveFileName, ArchiveExtension); end; end; function TJclCompressionItem.GetNestedArchiveStream: TStream; begin raise EJclCompressionError.CreateRes(@RsCompressionNoNestedArchive); end; function TJclCompressionItem.GetPackedExtension: WideString; begin CheckGetProperty(ipPackedExtension); if FPackedName = '' then Result := FPackedExtension else Result := WideExtractFileExt(FPackedName); end; function TJclCompressionItem.GetPackedName: WideString; begin CheckGetProperty(ipPackedName); Result := FPackedName; end; function TJclCompressionItem.GetPackedSize: Int64; begin CheckGetProperty(ipPackedSize); Result := FPackedSize; end; function TJclCompressionItem.GetStream: TStream; var AItemAccess: TJclStreamAccess; begin if not Assigned(FStream) and (FileName <> '') then begin AItemAccess:= Archive.ItemAccess; if (AItemAccess = saReadOnly) and JclCompressSharedFiles then AItemAccess:= saReadOnlyDenyNone; FStream := OpenFileStream(FileName, AItemAccess); end; Result := FStream; end; function TJclCompressionItem.GetUser: WideString; begin CheckGetProperty(ipUser); Result := FUser; end; procedure TJclCompressionItem.ReleaseStream; begin if OwnsStream or (FileName <> '') then FreeAndNil(FStream); end; procedure TJclCompressionItem.SetAttributes(Value: Cardinal); begin CheckSetProperty(ipAttributes); FAttributes := Value; Include(FModifiedProperties, ipAttributes); Include(FValidProperties, ipAttributes); end; procedure TJclCompressionItem.SetComment(const Value: WideString); begin CheckSetProperty(ipComment); FComment := Value; Include(FModifiedProperties, ipComment); Include(FValidProperties, ipComment); end; procedure TJclCompressionItem.SetCRC(Value: Cardinal); begin CheckSetProperty(ipCRC); FCRC := Value; Include(FModifiedProperties, ipCRC); Include(FValidProperties, ipCRC); end; procedure TJclCompressionItem.SetCreationTime(const Value: TFileTime); begin CheckSetProperty(ipCreationTime); FCreationTime := Value; Include(FModifiedProperties, ipCreationTime); Include(FValidProperties, ipCreationTime); end; procedure TJclCompressionItem.SetDirectory(Value: Boolean); begin CheckSetProperty(ipAttributes); if Value then FAttributes := FAttributes or FILE_ATTRIBUTE_DIRECTORY else FAttributes := FAttributes and (not FILE_ATTRIBUTE_DIRECTORY); Include(FModifiedProperties, ipAttributes); Include(FValidProperties, ipAttributes); end; procedure TJclCompressionItem.SetEncrypted(Value: Boolean); begin CheckSetProperty(ipEncrypted); FEncrypted := Value; Include(FModifiedProperties, ipEncrypted); Include(FValidProperties, ipEncrypted); end; procedure TJclCompressionItem.SetFileName(const Value: TFileName); var AFindData: TWin32FindData; begin CheckSetProperty(ipFileName); FFileName := Value; if Value <> '' then begin Include(FModifiedProperties, ipFileName); Include(FValidProperties, ipFileName); end else begin Exclude(FModifiedProperties, ipFileName); Exclude(FValidProperties, ipFileName); end; if (Value <> '') and (FArchive is TJclCompressionArchive) and GetFileAttributesEx(PChar(Value), GetFileExInfoStandard, @AFindData) then begin FileSize := (Int64(AFindData.nFileSizeHigh) shl 32) or AFindData.nFileSizeLow; Attributes := AFindData.dwFileAttributes; CreationTime := AFindData.ftCreationTime; LastAccessTime := AFindData.ftLastAccessTime; LastWriteTime := AFindData.ftLastWriteTime; // TODO: user name and group (using file handle and GetSecurityInfo) {$IFDEF MSWINDOWS} HostOS := LoadResString(@RsCompression7zWindows); {$ENDIF MSWINDOWS} {$IFDEF UNIX} HostOS := LoadResString(@RsCompression7zUnix); {$ENDIF UNIX} end; end; procedure TJclCompressionItem.SetFileSize(const Value: Int64); begin CheckSetProperty(ipFileSize); FFileSize := Value; Include(FModifiedProperties, ipFileSize); Include(FValidProperties, ipFileSize); end; procedure TJclCompressionItem.SetGroup(const Value: WideString); begin CheckSetProperty(ipGroup); FGroup := Value; Include(FModifiedProperties, ipGroup); Include(FValidProperties, ipGroup); end; procedure TJclCompressionItem.SetHostFS(const Value: WideString); begin CheckSetProperty(ipHostFS); FHostFS := Value; Include(FModifiedProperties, ipHostFS); Include(FValidProperties, ipHostFS); end; procedure TJclCompressionItem.SetHostOS(const Value: WideString); begin CheckSetProperty(ipHostOS); FHostOS := Value; Include(FModifiedProperties, ipHostOS); Include(FValidProperties, ipHostOS); end; procedure TJclCompressionItem.SetLastAccessTime(const Value: TFileTime); begin CheckSetProperty(ipLastAccessTime); FLastAccessTime := Value; Include(FModifiedProperties, ipLastAccessTime); Include(FValidProperties, ipLastAccessTime); end; procedure TJclCompressionItem.SetLastWriteTime(const Value: TFileTime); begin CheckSetProperty(ipLastWriteTime); FLastWriteTime := Value; Include(FModifiedProperties, ipLastWriteTime); Include(FValidProperties, ipLastWriteTime); end; procedure TJclCompressionItem.SetMethod(const Value: WideString); begin CheckSetProperty(ipMethod); FMethod := Value; Include(FModifiedProperties, ipMethod); Include(FValidProperties, ipMethod); end; procedure TJclCompressionItem.SetPackedExtension(const Value: WideString); begin CheckSetProperty(ipPackedExtension); if (Value <> '') and (Value[1] <> '.') then // force heading '.' FPackedExtension := '.' + Value else FPackedExtension := Value; Include(FModifiedProperties, ipPackedExtension); Include(FValidProperties, ipPackedExtension); end; procedure TJclCompressionItem.SetPackedName(const Value: WideString); var PackedNamesIndex: Integer; begin if FPackedName <> Value then begin CheckSetProperty(ipPackedName); if FArchive is TJclCompressArchive then begin PackedNamesIndex := -1; if (TJclCompressArchive(FArchive).FPackedNames <> nil) and TJclCompressArchive(FArchive).FPackedNames.Find(FPackedName, PackedNamesIndex) then begin TJclCompressArchive(FArchive).FPackedNames.Delete(PackedNamesIndex); try TJclCompressArchive(FArchive).FPackedNames.Add(Value); except raise EJclCompressionError(Format(LoadResString(@RsCompressionDuplicate), [Value])); end; end; end; FPackedName := Value; Include(FModifiedProperties, ipPackedName); Include(FValidProperties, ipPackedName); end; end; procedure TJclCompressionItem.SetPackedSize(const Value: Int64); begin CheckSetProperty(ipPackedSize); FPackedSize := Value; Include(FModifiedProperties, ipPackedSize); Include(FValidProperties, ipPackedSize); end; procedure TJclCompressionItem.SetStream(const Value: TStream); begin CheckSetProperty(ipStream); ReleaseStream; FStream := Value; if Value <> nil then begin Include(FModifiedProperties, ipStream); Include(FValidProperties, ipStream); end else begin Exclude(FModifiedProperties, ipStream); Exclude(FValidProperties, ipStream); end; end; procedure TJclCompressionItem.SetUser(const Value: WideString); begin CheckSetProperty(ipUser); FUser := Value; Include(FModifiedProperties, ipUser); Include(FValidProperties, ipUser); end; function TJclCompressionItem.UpdateFileTimes: Boolean; const FILE_WRITE_ATTRIBUTES = $00000100; var FileHandle: HFILE; ACreationTime, ALastAccessTime, ALastWriteTime: PFileTime; begin ReleaseStream; Result := FFileName <> ''; if Result then begin FileHandle := CreateFile(PChar(FFileName), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nil, OPEN_ALWAYS, 0, 0); try // creation time should be the oldest if ipCreationTime in FValidProperties then ACreationTime := @FCreationTime else if ipLastWriteTime in FValidProperties then ACreationTime := @FLastWriteTime else if ipLastAccessTime in FValidProperties then ACreationTime := @FLastAccessTime else ACreationTime := nil; // last access time may default to now if not set if ipLastAccessTime in FValidProperties then ALastAccessTime := @FLastAccessTime else ALastAccessTime := nil; // last write time may, if not set, be the creation time or last access time if ipLastWriteTime in FValidProperties then ALastWriteTime := @FLastWriteTime else if ipCreationTime in FValidProperties then ALastWriteTime := @FCreationTime else if ipLastAccessTime in FValidProperties then ALastWriteTime := @FLastAccessTime else ALastWriteTime := nil; Result := (FileHandle <> INVALID_HANDLE_VALUE) and SetFileTime(FileHandle, ACreationTime, ALastAccessTime, ALastWriteTime); finally CloseHandle(FileHandle); end; end; end; function TJclCompressionItem.ValidateExtraction(Index: Integer): Boolean; begin Result := False; end; function TJclCompressionItem.WideChangeFileExt(const AFileName, AExtension: WideString): WideString; var Index: Integer; begin Result := AFileName; // Unicode version of ChangeFileExt for Index := Length(Result) downto 1 do begin case Result[Index] of '.': begin Result := Copy(Result, 1, Index - 1) + AExtension; Exit; end; DirSeparator, DirDelimiter: // no extension Break; end; end; Result := Result + AExtension; end; function TJclCompressionItem.WideExtractFileExt( const AFileName: WideString): WideString; var Index: Integer; begin Result := ''; // Unicode version of ExtractFileExt for Index := Length(AFileName) downto 1 do begin case AFileName[Index] of '.': begin Result := Copy(AFileName, Index, Length(AFileName) - Index + 1); Break; end; DirSeparator, DirDelimiter: // no extension Break; end; end; end; function TJclCompressionItem.WideExtractFileName( const AFileName: WideString): WideString; var Index: Integer; begin Result := AFileName; // Unicode version of ExtractFileName for Index := Length(AFileName) downto 1 do begin case AFileName[Index] of DirSeparator, DirDelimiter: begin Result := Copy(AFileName, Index + 1, Length(AFileName) - Index); Break; end; end; end; end; //=== { TJclCompressionArchiveFormats } ====================================== constructor TJclCompressionArchiveFormats.Create; begin inherited Create; FCompressFormats := TList.Create; FDecompressFormats := TList.Create; FUpdateFormats := TList.Create; // register compression archives RegisterFormat(TJclZipCompressArchive); RegisterFormat(TJclBZ2CompressArchive); RegisterFormat(TJcl7zCompressArchive); RegisterFormat(TJclTarCompressArchive); RegisterFormat(TJclGZipCompressArchive); RegisterFormat(TJclXzCompressArchive); RegisterFormat(TJclSwfcCompressArchive); RegisterFormat(TJclWimCompressArchive); // register decompression archives RegisterFormat(TJclZipDecompressArchive); RegisterFormat(TJclBZ2DecompressArchive); RegisterFormat(TJclRarDecompressArchive); RegisterFormat(TJclArjDecompressArchive); RegisterFormat(TJclZDecompressArchive); RegisterFormat(TJclLzhDecompressArchive); RegisterFormat(TJcl7zDecompressArchive); RegisterFormat(TJclCabDecompressArchive); RegisterFormat(TJclNsisDecompressArchive); RegisterFormat(TJclLzmaDecompressArchive); RegisterFormat(TJclLzma86DecompressArchive); RegisterFormat(TJclPeDecompressArchive); RegisterFormat(TJclElfDecompressArchive); RegisterFormat(TJclMachoDecompressArchive); RegisterFormat(TJclUdfDecompressArchive); RegisterFormat(TJclXarDecompressArchive); RegisterFormat(TJclMubDecompressArchive); RegisterFormat(TJclHfsDecompressArchive); RegisterFormat(TJclDmgDecompressArchive); RegisterFormat(TJclCompoundDecompressArchive); RegisterFormat(TJclWimDecompressArchive); RegisterFormat(TJclIsoDecompressArchive); RegisterFormat(TJclChmDecompressArchive); RegisterFormat(TJclSplitDecompressArchive); RegisterFormat(TJclRpmDecompressArchive); RegisterFormat(TJclDebDecompressArchive); RegisterFormat(TJclCpioDecompressArchive); RegisterFormat(TJclTarDecompressArchive); RegisterFormat(TJclGZipDecompressArchive); RegisterFormat(TJclNtfsDecompressArchive); RegisterFormat(TJclFatDecompressArchive); RegisterFormat(TJclMbrDecompressArchive); RegisterFormat(TJclVhdDecompressArchive); RegisterFormat(TJclMslzDecompressArchive); RegisterFormat(TJclFlvDecompressArchive); RegisterFormat(TJclSwfDecompressArchive); RegisterFormat(TJclSwfcDecompressArchive); RegisterFormat(TJclAPMDecompressArchive); RegisterFormat(TJclPpmdDecompressArchive); RegisterFormat(TJclTEDecompressArchive); RegisterFormat(TJclUEFIcDecompressArchive); RegisterFormat(TJclUEFIsDecompressArchive); RegisterFormat(TJclSquashFSDecompressArchive); RegisterFormat(TJclCramFSDecompressArchive); // register update archives RegisterFormat(TJclZipUpdateArchive); RegisterFormat(TJclBZ2UpdateArchive); RegisterFormat(TJcl7zUpdateArchive); RegisterFormat(TJclTarUpdateArchive); RegisterFormat(TJclGZipUpdateArchive); RegisterFormat(TJclSwfcUpdateArchive); end; destructor TJclCompressionArchiveFormats.Destroy; begin FCompressFormats.Free; FDecompressFormats.Free; FUpdateFormats.Free; inherited Destroy; end; function TJclCompressionArchiveFormats.FindCompressFormat(const AFileName: TFileName): TJclCompressArchiveClass; var IndexFormat, IndexFilter: Integer; Filters: TStrings; AFormat: TJclCompressArchiveClass; begin Result := nil; Filters := TStringList.Create; try for IndexFormat := 0 to CompressFormatCount - 1 do begin AFormat := CompressFormats[IndexFormat]; StrTokenToStrings(AFormat.ArchiveExtensions, DirSeparator, Filters); for IndexFilter := 0 to Filters.Count - 1 do if IsFileNameMatch(AFileName, Filters.Strings[IndexFilter]) then begin Result := AFormat; Break; end; if Result <> nil then Break; end; finally Filters.Free; end; end; function TJclCompressionArchiveFormats.FindCompressFormats( const AFileName: TFileName): TJclCompressArchiveClassArray; var IndexFormat, IndexFilter: Integer; Filters: TStrings; AFormat: TJclCompressArchiveClass; begin SetLength(Result, 0); Filters := TStringList.Create; try for IndexFormat := 0 to CompressFormatCount - 1 do begin AFormat := CompressFormats[IndexFormat]; StrTokenToStrings(AFormat.ArchiveExtensions, DirSeparator, Filters); for IndexFilter := 0 to Filters.Count - 1 do if IsFileNameMatch(AFileName, Filters.Strings[IndexFilter]) then begin SetLength(Result, Length(Result) + 1); Result[High(Result)] := AFormat; Break; end; end; finally Filters.Free; end; end; {function TJclCompressionArchiveFormats.FindDecompressFormat(const AFileName: TFileName; TestArchiveSignature: Boolean): TJclDecompressArchiveClass; var MatchingFormats: TJclDecompressArchiveClassArray; Index: Integer; ArchiveStream: TStream; Buffer: TDynByteArray; begin SetLength(Buffer, 0); // enumerate formats based on filename MatchingFormats := FindDecompressFormats(AFileName); if (Length(MatchingFormats) >= 1) and (not TestArchiveSignature) then begin Result := MatchingFormats[0]; Exit; end else Result := nil; // load archive to test signature ArchiveStream := TFileStream.Create(AFileName, fmOpenRead and fmShareDenyNone); try for Index := Low(MatchingFormats) to High(MatchingFormats) do if SignatureMatches(MatchingFormats[Index], ArchiveStream, Buffer) then begin Result := MatchingFormats[Index]; Exit; end; finally ArchiveStream.Free; end; end;} function TJclCompressionArchiveFormats.FindDecompressFormat(const AFileName: TFileName): TJclDecompressArchiveClass; var MatchingFormats: TJclDecompressArchiveClassArray; begin // enumerate formats based on filename MatchingFormats := FindDecompressFormats(AFileName); if Length(MatchingFormats) >= 1 then begin Result := MatchingFormats[0]; Exit; end else Result := nil; end; function TJclCompressionArchiveFormats.FindDecompressFormats( const AFileName: TFileName): TJclDecompressArchiveClassArray; var IndexFormat, IndexFilter: Integer; Filters: TStrings; AFormat: TJclDecompressArchiveClass; begin SetLength(Result, 0); Filters := TStringList.Create; try for IndexFormat := 0 to DecompressFormatCount - 1 do begin AFormat := DecompressFormats[IndexFormat]; StrTokenToStrings(AFormat.ArchiveExtensions, DirSeparator, Filters); for IndexFilter := 0 to Filters.Count - 1 do if IsFileNameMatch(AFileName, Filters.Strings[IndexFilter]) then begin SetLength(Result, Length(Result) + 1); Result[High(Result)] := AFormat; Break; end; end; finally Filters.Free; end; end; {function TJclCompressionArchiveFormats.FindUpdateFormat(const AFileName: TFileName; TestArchiveSignature: Boolean): TJclUpdateArchiveClass; var MatchingFormats: TJclUpdateArchiveClassArray; Index: Integer; ArchiveStream: TStream; Buffer: TDynByteArray; begin SetLength(Buffer, 0); // enumerate formats based on filename MatchingFormats := FindUpdateFormats(AFileName); if (Length(MatchingFormats) >= 1) and (not TestArchiveSignature) then begin Result := MatchingFormats[0]; Exit; end else Result := nil; // load archive to test signature ArchiveStream := TFileStream.Create(AFileName, fmOpenRead and fmShareDenyNone); try for Index := Low(MatchingFormats) to High(MatchingFormats) do if SignatureMatches(MatchingFormats[Index], ArchiveStream, Buffer) then begin Result := MatchingFormats[Index]; Exit; end; finally ArchiveStream.Free; end; end;} function TJclCompressionArchiveFormats.FindUpdateFormat(const AFileName: TFileName): TJclUpdateArchiveClass; var MatchingFormats: TJclUpdateArchiveClassArray; begin // enumerate formats based on filename MatchingFormats := FindUpdateFormats(AFileName); if Length(MatchingFormats) >= 1 then begin Result := MatchingFormats[0]; Exit; end else Result := nil; end; function TJclCompressionArchiveFormats.FindUpdateFormats( const AFileName: TFileName): TJclUpdateArchiveClassArray; var IndexFormat, IndexFilter: Integer; Filters: TStrings; AFormat: TJclUpdateArchiveClass; begin SetLength(Result, 0); Filters := TStringList.Create; try for IndexFormat := 0 to UpdateFormatCount - 1 do begin AFormat := UpdateFormats[IndexFormat]; StrTokenToStrings(AFormat.ArchiveExtensions, DirSeparator, Filters); for IndexFilter := 0 to Filters.Count - 1 do if IsFileNameMatch(AFileName, Filters.Strings[IndexFilter]) then begin SetLength(Result, Length(Result) + 1); Result[High(Result)] := AFormat; Break; end; end; finally Filters.Free; end; end; function TJclCompressionArchiveFormats.GetCompressFormat(Index: Integer): TJclCompressArchiveClass; begin Result := TJclCompressArchiveClass(FCompressFormats.Items[Index]); end; function TJclCompressionArchiveFormats.GetCompressFormatCount: Integer; begin Result := FCompressFormats.Count; end; function TJclCompressionArchiveFormats.GetDecompressFormat(Index: Integer): TJclDecompressArchiveClass; begin Result := TJclDecompressArchiveClass(FDecompressFormats.Items[Index]); end; function TJclCompressionArchiveFormats.GetDecompressFormatCount: Integer; begin Result := FDecompressFormats.Count; end; function TJclCompressionArchiveFormats.GetUpdateFormat(Index: Integer): TJclUpdateArchiveClass; begin Result := TJclUpdateArchiveClass(FUpdateFormats.Items[Index]); end; function TJclCompressionArchiveFormats.GetUpdateFormatCount: Integer; begin Result := FUpdateFormats.Count; end; procedure TJclCompressionArchiveFormats.RegisterFormat(AClass: TJclCompressionArchiveClass); begin if AClass.InheritsFrom(TJclUpdateArchive) then FUpdateFormats.Add(AClass) else if AClass.InheritsFrom(TJclDecompressArchive) then FDecompressFormats.Add(AClass) else if AClass.InheritsFrom(TJclCompressArchive) then FCompressFormats.Add(AClass); end; {function TJclCompressionArchiveFormats.SignatureMatches( Format: TJclCompressionArchiveClass; ArchiveStream: TStream; var Buffer: TDynByteArray): Boolean; var Index, StartPos, EndPos: Integer; Signature: TDynByteArray; begin // must match empty signatures Result := True; Signature := Format.ArchiveSignature; // fill buffer if needed StartPos := Length(Buffer); // High(Buffer) + 1 EndPos := Length(Signature); if StartPos < EndPos then begin SetLength(Buffer, EndPos); for Index := StartPos to EndPos - 1 do ArchiveStream.ReadBuffer(Buffer[Index], SizeOf(Buffer[Index])); end; // compare buffer and signature for Index := 0 to EndPos - 1 do if Buffer[Index] <> Signature[Index] then begin Result := False; Break; end; end;} procedure TJclCompressionArchiveFormats.UnregisterFormat(AClass: TJclCompressionArchiveClass); begin if AClass.InheritsFrom(TJclUpdateArchive) then FUpdateFormats.Remove(AClass) else if AClass.InheritsFrom(TJclDecompressArchive) then FDecompressFormats.Remove(AClass) else if AClass.InheritsFrom(TJclCompressArchive) then FCompressFormats.Remove(AClass); end; function GetArchiveFormats: TJclCompressionArchiveFormats; begin if not Assigned(GlobalArchiveFormats) then GlobalArchiveFormats := TJclCompressionArchiveFormats.Create; Result := TJclCompressionArchiveFormats(GlobalArchiveFormats); end; //=== { TJclCompressionVolume } ============================================== constructor TJclCompressionVolume.Create(AStream, ATmpStream: TStream; AOwnsStream, AOwnsTmpStream: Boolean; AFileName, ATmpFileName: TFileName; AVolumeMaxSize: Int64); begin inherited Create; FStream := AStream; FTmpStream := ATmpStream; FOwnsStream := AOwnsStream; FOwnsTmpStream := AOwnsTmpStream; FFileName := AFileName; FTmpFileName := ATmpFileName; FVolumeMaxSize := AVolumeMaxSize; end; destructor TJclCompressionVolume.Destroy; begin ReleaseStreams; inherited Destroy; end; procedure TJclCompressionVolume.ReleaseStreams; begin if OwnsStream then FreeAndNil(FStream); if OwnsTmpStream then FreeAndNil(FTmpStream); end; //=== { TJclCompressionArchive } ============================================= constructor TJclCompressionArchive.Create(Volume0: TStream; AVolumeMaxSize: Int64 = 0; AOwnVolume: Boolean = False); begin inherited Create; FVolumeIndex := -1; FVolumeIndexOffset := 1; FVolumeMaxSize := AVolumeMaxSize; FItems := TObjectList.Create(True); FVolumes := TObjectList.Create(True); if Assigned(Volume0) then AddVolume(Volume0, AVolumeMaxSize, AOwnVolume); InitializeArchiveProperties; end; constructor TJclCompressionArchive.Create(const VolumeFileName: TFileName; AVolumeMaxSize: Int64 = 0; VolumeMask: Boolean = False); begin inherited Create; FVolumeIndex := -1; FVolumeIndexOffset := 1; FVolumeMaxSize := AVolumeMaxSize; FItems := TObjectList.Create(True); FVolumes := TObjectList.Create(True); if VolumeMask then FVolumeFileNameMask := VolumeFileName else AddVolume(VolumeFileName, AVolumeMaxSize); InitializeArchiveProperties; end; destructor TJclCompressionArchive.Destroy; begin FItems.Free; FVolumes.Free; inherited Destroy; end; function TJclCompressionArchive.AddVolume(VolumeStream: TStream; AVolumeMaxSize: Int64; AOwnsStream: Boolean): Integer; begin Result := FVolumes.Add(TJclCompressionVolume.Create(VolumeStream, nil, AOwnsStream, True, '', '', AVolumeMaxSize)); end; function TJclCompressionArchive.AddVolume(VolumeStream, TmpVolumeStream: TStream; AVolumeMaxSize: Int64; AOwnsStream, AOwnsTmpStream: Boolean): Integer; begin Result := FVolumes.Add(TJclCompressionVolume.Create(VolumeStream, TmpVolumeStream, AOwnsStream, AOwnsTmpStream, '', '', AVolumeMaxSize)); end; function TJclCompressionArchive.AddVolume(const VolumeFileName: TFileName; AVolumeMaxSize: Int64): Integer; begin Result := FVolumes.Add(TJclCompressionVolume.Create(nil, nil, True, True, VolumeFileName, '', AVolumeMaxSize)); end; function TJclCompressionArchive.AddVolume(const VolumeFileName, TmpVolumeFileName: TFileName; AVolumeMaxSize: Int64): Integer; begin Result := FVolumes.Add(TJclCompressionVolume.Create(nil, nil, True, True, VolumeFileName, TmpVolumeFileName, AVolumeMaxSize)); end; class function TJclCompressionArchive.ArchiveExtensions: string; begin Result := ''; end; class function TJclCompressionArchive.ArchiveName: string; begin Result := ''; end; class function TJclCompressionArchive.ArchiveSignature: TDynByteArray; begin SetLength(Result, 0); end; class function TJclCompressionArchive.ArchiveSubExtensions: string; begin Result := ''; end; procedure TJclCompressionArchive.CheckOperationSuccess; var Index: Integer; begin for Index := 0 to FItems.Count - 1 do begin case TJclCompressionItem(FItems.Items[Index]).OperationSuccess of osNoOperation: ; osOK: ; osUnsupportedMethod: raise EJclCompressionError.CreateRes(@RsCompressionUnsupportedMethod); osDataError: raise EJclCompressionError.CreateRes(@RsCompressionDataError); osCRCError: raise EJclCompressionError.CreateRes(@RsCompressionCRCError); else raise EJclCompressionError.CreateRes(@RsCompressionUnknownError); end; end; end; procedure TJclCompressionArchive.ClearItems; begin FItems.Clear; end; procedure TJclCompressionArchive.ClearOperationSuccess; var Index: Integer; begin for Index := 0 to FItems.Count - 1 do TJclCompressionItem(FItems.Items[Index]).OperationSuccess := osNoOperation; end; procedure TJclCompressionArchive.ClearVolumes; begin FVolumes.Clear; end; procedure TJclCompressionArchive.InitializeArchiveProperties; begin // override to customize end; function TJclCompressionArchive.DoProgress(const Value, MaxValue: Int64): Boolean; begin if Assigned(FOnProgress) then FOnProgress(Self, Value, MaxValue); Result := not FCancelCurrentOperation; end; function TJclCompressionArchive.DoRatio(const InSize, OutSize: Int64): Boolean; begin if Assigned(FOnRatio) then FOnRatio(Self, InSize, OutSize); Result := not FCancelCurrentOperation; end; function TJclCompressionArchive.GetItem(Index: Integer): TJclCompressionItem; begin Result := TJclCompressionItem(FItems.Items[Index]); end; function TJclCompressionArchive.GetItemCount: Integer; begin Result := FItems.Count; end; function TJclCompressionArchive.GetSupportsNestedArchive: Boolean; begin Result := False; end; function TJclCompressionArchive.GetVolume(Index: Integer): TJclCompressionVolume; begin Result := TJclCompressionVolume(FVolumes.Items[Index]); end; function TJclCompressionArchive.GetVolumeCount: Integer; begin Result := FVolumes.Count; end; function TJclCompressionArchive.InternalOpenStream( const FileName: TFileName): TStream; begin Result := OpenFileStream(FileName, VolumeAccess); end; function TJclCompressionArchive.ItemAccess: TJclStreamAccess; begin Result := saReadOnly; end; class function TJclCompressionArchive.MultipleItemContainer: Boolean; begin Result := True; end; function TJclCompressionArchive.NeedStream(Index: Integer): TStream; var AVolume: TJclCompressionVolume; AOwnsStream: Boolean; AFileName: TFileName; begin Result := nil; if Index <> FVolumeIndex then begin AOwnsStream := VolumeFileNameMask <> ''; AVolume := nil; AFileName := Format(VolumeFileNameMask, [Index + VolumeIndexOffset]); if (Index >= 0) and (Index < FVolumes.Count) then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); Result := AVolume.Stream; AOwnsStream := AVolume.OwnsStream; AFileName := AVolume.FileName; end; if Assigned(FOnVolume) then FOnVolume(Self, Index, AFileName, Result, AOwnsStream); if Assigned(AVolume) then begin if not Assigned(Result) then Result := InternalOpenStream(AFileName); AVolume.FFileName := AFileName; AVolume.FStream := Result; AVolume.FOwnsStream := AOwnsStream; end else begin while FVolumes.Count < Index do FVolumes.Add(TJclCompressionVolume.Create(nil, nil, True, True, Format(VolumeFileNameMask, [Index + VolumeIndexOffset]), '', FVolumeMaxSize)); if not Assigned(Result) then Result := InternalOpenStream(AFileName); if Assigned(Result) then begin if Index < FVolumes.Count then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); AVolume.FFileName := AFileName; AVolume.FStream := Result; AVolume.FOwnsStream := AOwnsStream; AVolume.FVolumeMaxSize := FVolumeMaxSize; end else FVolumes.Add(TJclCompressionVolume.Create(Result, nil, AOwnsStream, True, AFileName, '', FVolumeMaxSize)); end; end; FVolumeIndex := Index; end else if (Index >= 0) and (Index < FVolumes.Count) then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); Result := AVolume.Stream; if Assigned(Result) then Result.Seek(0, soBeginning); end else FVolumeIndex := Index; end; function TJclCompressionArchive.NeedStreamMaxSize(Index: Integer): Int64; var AVolume: TJclCompressionVolume; begin if (Index <> FVolumeIndex) then begin AVolume := nil; if (Index >= 0) and (Index < FVolumes.Count) then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); FVolumeMaxSize := AVolume.VolumeMaxSize; end; if Assigned(FOnVolumeMaxSize) then FOnVolumeMaxSize(Self, Index, FVolumeMaxSize); if Assigned(AVolume) then AVolume.FVolumeMaxSize := FVolumeMaxSize else begin while FVolumes.Count < Index do FVolumes.Add(TJclCompressionVolume.Create(nil, nil, True, True, Format(VolumeFileNameMask, [Index + VolumeIndexOffset]), '', FVolumeMaxSize)); if Index < FVolumes.Count then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); AVolume.FFileName := Format(VolumeFileNameMask, [Index + VolumeIndexOffset]); AVolume.FStream := nil; AVolume.FOwnsStream := True; AVolume.FVolumeMaxSize := FVolumeMaxSize; end else FVolumes.Add(TJclCompressionVolume.Create(nil, nil, True, True, Format(VolumeFileNameMask, [Index + VolumeIndexOffset]), '', FVolumeMaxSize)); end; end; Result := FVolumeMaxSize; end; procedure TJclCompressionArchive.ReleaseVolumes; var Index: Integer; begin for Index := 0 to FVolumes.Count - 1 do TJclCompressionVolume(FVolumes.Items[Index]).ReleaseStreams; end; procedure TJclCompressionArchive.SelectAll; var Index: Integer; begin for Index := 0 to FItems.Count - 1 do TJclCompressionItem(FItems.Items[Index]).Selected := True; end; function TJclCompressionArchive.TranslateItemPath(const ItemPath, OldBase, NewBase: WideString): WideString; begin Result := PathCanonicalize(PathAddSeparator(NewBase) + PathGetRelativePath(OldBase, ItemPath)); end; procedure TJclCompressionArchive.UnselectAll; var Index: Integer; begin for Index := 0 to FItems.Count - 1 do TJclCompressionItem(FItems.Items[Index]).Selected := False; end; class function TJclCompressionArchive.VolumeAccess: TJclStreamAccess; begin Result := saReadOnly; end; function TJclCompressionArchive._AddRef: Integer; begin Result := -1; end; function TJclCompressionArchive._Release: Integer; begin Result := -1; end; //=== { TJclCompressItem } =================================================== procedure TJclCompressItem.CheckGetProperty( AProperty: TJclCompressionItemProperty); begin // always valid end; procedure TJclCompressItem.CheckSetProperty( AProperty: TJclCompressionItemProperty); begin if AProperty in [ipMethod] then raise EJclCompressionError.CreateRes(@RsCompressionWriteNotSupported); (Archive as TJclCompressArchive).CheckNotCompressing; end; //=== { TJclCompressArchive } ================================================ destructor TJclCompressArchive.Destroy; begin FPackedNames.Free; inherited Destroy; end; function TJclCompressArchive.AddDirectory(const PackedName: WideString; const DirName: string; RecurseIntoDir: Boolean; AddFilesInDir: Boolean): Integer; var AItem: TJclCompressionItem; begin CheckNotCompressing; if DirName <> '' then begin FBaseRelName := PackedName; FBaseDirName := PathRemoveSeparator(DirName); FAddFilesInDir := AddFilesInDir; if RecurseIntoDir then begin Result := FItems.Count; EnumDirectories(DirName, InternalAddDirectory, True, '', nil); Exit; end; end; AItem := GetItemClass.Create(Self); try AItem.PackedName := PackedName; AItem.FileName := DirName; except AItem.Destroy; raise; end; Result := AddFileCheckDuplicate(AItem); if (DirName <> '') and AddFilesInDir then EnumFiles(PathAddSeparator(DirName) + '*', InternalAddFile, faDirectory); end; function TJclCompressArchive.AddFile(const PackedName: WideString; const FileName: TFileName): Integer; var AItem: TJclCompressionItem; begin CheckNotCompressing; AItem := GetItemClass.Create(Self); try AItem.PackedName := PackedName; AItem.FileName := FileName; except AItem.Destroy; raise; end; Result := AddFileCheckDuplicate(AItem); end; function TJclCompressArchive.AddFile(const PackedName: WideString; AStream: TStream; AOwnsStream: Boolean): Integer; var AItem: TJclCompressionItem; NowFileTime: TFileTime; begin CheckNotCompressing; AItem := GetItemClass.Create(Self); try AItem.PackedName := PackedName; AItem.Stream := AStream; AItem.OwnsStream := AOwnsStream; AItem.FileSize := AStream.Size - AStream.Position; NowFileTime := LocalDateTimeToFileTime(Now); AItem.Attributes := faReadOnly and faArchive; AItem.CreationTime := NowFileTime; AItem.LastAccessTime := NowFileTime; AItem.LastWriteTime := NowFileTime; {$IFDEF MSWINDOWS} AItem.HostOS := LoadResString(@RsCompression7zWindows); {$ENDIF MSWINDOWS} {$IFDEF UNIX} AItem.HostOS := LoadResString(@RsCompression7zUnix); {$ENDIF UNIX} except AItem.Destroy; raise; end; Result := AddFileCheckDuplicate(AItem); end; function TJclCompressArchive.AddFileCheckDuplicate(NewItem: TJclCompressionItem): Integer; var I, PackedNamesIndex: Integer; S: string; begin if FDuplicateCheck = dcNone then Result := FItems.Add(NewItem) else begin if FPackedNames = nil then begin FPackedNames := TJclWideStringList.Create; FPackedNames.Sorted := True; {$IFDEF UNIX} FPackedNames.CaseSensitive := True; {$ELSE ~UNIX} FPackedNames.CaseSensitive := False; {$ENDIF ~UNIX} FPackedNames.Duplicates := dupIgnore; for I := ItemCount - 1 downto 0 do FPackedNames.AddObject(Items[I].PackedName, Items[I]); FPackedNames.Duplicates := dupError; end; if DuplicateCheck = dcAll then begin try PackedNamesIndex := -1; FPackedNames.AddObject(NewItem.PackedName, NewItem); Result := FItems.Add(NewItem); except Result := -1; end; end else if FPackedNames.Find(NewItem.PackedName, PackedNamesIndex) then Result := -1 else Result := FItems.Add(NewItem); if Result < 0 then begin case DuplicateAction of daOverwrite: begin if PackedNamesIndex < 0 then PackedNamesIndex := FPackedNames.IndexOf(NewItem.PackedName); FItems.Remove(FPackedNames.Objects[PackedNamesIndex]); Result := FItems.Add(NewItem); if DuplicateCheck = dcAll then FPackedNames.Objects[PackedNamesIndex] := NewItem else FPackedNames.Delete(PackedNamesIndex); end; daError: begin S := Format(LoadResString(@RsCompressionDuplicate), [NewItem.PackedName]); NewItem.Free; raise EJclCompressionError.Create(S); end; daSkip: begin NewItem.Free; Result := -1; end; end end; end; end; procedure TJclCompressArchive.CheckNotCompressing; begin if FCompressing then raise EJclCompressionError.CreateRes(@RsCompressionCompressingError); end; procedure TJclCompressArchive.Compress; begin // Calling ReleaseVolumes here causes subsequent operations on the archive to fail with an "unsupported method" exception // ReleaseVolumes; end; procedure TJclCompressArchive.InternalAddDirectory(const Directory: string); begin AddDirectory(TranslateItemPath(Directory, FBaseDirName, FBaseRelName), Directory, False, FAddFilesInDir); end; procedure TJclCompressArchive.InternalAddFile(const Directory: string; const FileInfo: TSearchRec); var AFileName: TFileName; AItem: TJclCompressionItem; begin AFileName := PathAddSeparator(Directory) + FileInfo.Name; AItem := GetItemClass.Create(Self); try AItem.PackedName := TranslateItemPath(AFileName, FBaseDirName, FBaseRelName); AItem.FileName := AFileName; except AItem.Destroy; raise; end; AddFileCheckDuplicate(AItem); end; function TJclCompressArchive.ItemAccess: TJclStreamAccess; begin Result := saReadOnly; end; class function TJclCompressArchive.VolumeAccess: TJclStreamAccess; begin Result := saWriteOnly; end; //=== { TJclDecompressItem } ================================================= procedure TJclDecompressItem.CheckGetProperty( AProperty: TJclCompressionItemProperty); begin // TODO end; procedure TJclDecompressItem.CheckSetProperty( AProperty: TJclCompressionItemProperty); begin (Archive as TJclDecompressArchive).CheckNotDecompressing; end; function TJclDecompressItem.ValidateExtraction(Index: Integer): Boolean; begin Result := (FArchive as TJclDecompressArchive).ValidateExtraction(Index, FFileName, FStream, FOwnsStream); end; //=== { TJclDecompressArchive } ============================================== procedure TJclDecompressArchive.CheckListing; begin if not FListing then raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclDecompressArchive.CheckNotDecompressing; begin if FDecompressing then raise EJclCompressionError.CreateRes(@RsCompressionDecompressingError); end; procedure TJclDecompressArchive.ExtractAll(const ADestinationDir: string; AAutoCreateSubDir: Boolean); begin // Calling ReleaseVolumes here causes subsequent operations on the archive to fail with an "unsupported method" exception // ReleaseVolumes; end; procedure TJclDecompressArchive.ExtractSelected(const ADestinationDir: string; AAutoCreateSubDir: Boolean); begin // Calling ReleaseVolumes here causes subsequent operations on the archive to fail with an "unsupported method" exception // ReleaseVolumes; end; function TJclDecompressArchive.ItemAccess: TJclStreamAccess; begin Result := saCreate; end; function TJclDecompressArchive.ValidateExtraction(Index: Integer; var FileName: TFileName; var AStream: TStream; var AOwnsStream: Boolean): Boolean; var AItem: TJclCompressionItem; PackedName: TFileName; begin if FExtractingAllIndex <> -1 then // extracting all FExtractingAllIndex := Index; AItem := Items[Index]; if (FileName = '') and not Assigned(AStream) then begin PackedName := AItem.PackedName; if PackedName = '' then PackedName := ChangeFileExt(ExtractFileName(Volumes[0].FileName), AItem.PackedExtension); FileName := PathGetRelativePath(FDestinationDir, PackedName); end; Result := True; if Assigned(FOnExtract) then Result := FOnExtract(Self, Index, FileName, AStream, AOwnsStream); if Result and not Assigned(AStream) and AutoCreateSubDir then begin if (AItem.Attributes and faDirectory) <> 0 then ForceDirectories(FileName) else ForceDirectories(ExtractFilePath(FileName)); end; end; class function TJclDecompressArchive.VolumeAccess: TJclStreamAccess; begin Result := saReadOnly; end; //=== { TJclUpdateItem } ===================================================== procedure TJclUpdateItem.CheckGetProperty( AProperty: TJclCompressionItemProperty); begin // TODO end; procedure TJclUpdateItem.CheckSetProperty( AProperty: TJclCompressionItemProperty); begin (Archive as TJclCompressArchive).CheckNotCompressing; end; function TJclUpdateItem.ValidateExtraction(Index: Integer): Boolean; begin Result := (Archive as TJclUpdateArchive).ValidateExtraction(Index, FFileName, FStream, FOwnsStream); end; //=== { TJclUpdateArchive } ================================================== procedure TJclUpdateArchive.CheckListing; begin if not FListing then raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclUpdateArchive.CheckNotDecompressing; begin if FDecompressing then raise EJclCompressionError.CreateRes(@RsCompressionDecompressingError); end; procedure TJclUpdateArchive.ExtractAll(const ADestinationDir: string; AAutoCreateSubDir: Boolean); begin // Calling ReleaseVolumes here causes subsequent operations on the archive to fail with an "unsupported method" exception // ReleaseVolumes; end; procedure TJclUpdateArchive.ExtractSelected(const ADestinationDir: string; AAutoCreateSubDir: Boolean); begin // Calling ReleaseVolumes here causes subsequent operations on the archive to fail with an "unsupported method" exception // ReleaseVolumes; end; procedure TJclUpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FDuplicateCheck := dcExisting; end; function TJclUpdateArchive.ItemAccess: TJclStreamAccess; begin if FDecompressing then Result := saCreate else Result := saReadOnly; end; function TJclUpdateArchive.ValidateExtraction(Index: Integer; var FileName: TFileName; var AStream: TStream; var AOwnsStream: Boolean): Boolean; var AItem: TJclCompressionItem; PackedName: TFileName; begin if FExtractingAllIndex <> -1 then // extracting all FExtractingAllIndex := Index; AItem := Items[Index]; if (FileName = '') and not Assigned(AStream) then begin PackedName := AItem.PackedName; if PackedName = '' then PackedName := ChangeFileExt(ExtractFileName(Volumes[0].FileName), AItem.PackedExtension); FileName := PathGetRelativePath(FDestinationDir, PackedName); end; Result := True; if Assigned(FOnExtract) then Result := FOnExtract(Self, Index, FileName, AStream, AOwnsStream); if Result and not Assigned(AStream) and AutoCreateSubDir then begin if (AItem.Attributes and faDirectory) <> 0 then ForceDirectories(FileName) else ForceDirectories(ExtractFilePath(FileName)); end; end; class function TJclUpdateArchive.VolumeAccess: TJclStreamAccess; begin Result := saReadOnly; end; //=== { TJclOutOfPlaceUpdateArchive } ======================================== procedure TJclOutOfPlaceUpdateArchive.Compress; var Index: Integer; AVolume: TJclCompressionVolume; SrcFileName, DestFileName: TFileName; SrcStream, DestStream: TStream; OwnsSrcStream, OwnsDestStream, AllHandled, Handled: Boolean; CopiedSize: Int64; begin // release volume streams and other finalization inherited Compress; if ReplaceVolumes then begin AllHandled := True; // replace streams by tmp streams for Index := 0 to FVolumes.Count - 1 do begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); SrcFileName := AVolume.TmpFileName; DestFileName := AVolume.FileName; SrcStream := AVolume.TmpStream; DestStream := AVolume.Stream; OwnsSrcStream := AVolume.OwnsTmpStream; OwnsDestStream := AVolume.OwnsStream; Handled := Assigned(FOnReplace) and FOnReplace(Self, SrcFileName, DestFileName, SrcStream, DestStream, OwnsSrcStream, OwnsDestStream); if not Handled then begin if (SrcFileName <> '') and (DestFileName <> '') and (OwnsSrcStream or not Assigned(SrcStream)) and (OwnsDestStream or not Assigned(DestStream)) then begin // close references before moving files if OwnsSrcStream then FreeAndNil(SrcStream); if OwnsDestStream then FreeAndNil(DestStream); Handled := FileMove(SrcFileName, DestFileName, True); end else if (SrcFileName = '') and (DestFileName = '') and Assigned(SrcStream) and Assigned(DestStream) then begin // in-memory moves SrcStream.Seek(0, soBeginning); DestStream.Seek(0, soBeginning); CopiedSize := StreamCopy(SrcStream, DestStream); // reset size DestStream.Size := CopiedSize; Handled := True; end; // identity // else // Handled := False; end; // update volume information AVolume.FTmpStream := SrcStream; AVolume.FStream := DestStream; AVolume.FOwnsTmpStream := OwnsSrcStream; AVolume.FOwnsStream := OwnsDestStream; AVolume.FTmpFileName := SrcFileName; AVolume.FFileName := DestFileName; AllHandled := AllHandled and Handled; end; if not AllHandled then raise EJclCompressionError.CreateRes(@RsCompressionReplaceError); end else begin // Remove temporary files for Index := 0 to FVolumes.Count - 1 do begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); if AVolume.OwnsTmpStream then begin FreeAndNil(AVolume.FTmpStream); FileDelete(AVolume.TmpFileName); end; end; end; end; procedure TJclOutOfPlaceUpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FReplaceVolumes := True; FTmpVolumeIndex := -1; end; function TJclOutOfPlaceUpdateArchive.InternalOpenTmpStream( const FileName: TFileName): TStream; begin Result := OpenFileStream(FileName, TmpVolumeAccess); end; function TJclOutOfPlaceUpdateArchive.NeedTmpStream(Index: Integer): TStream; var AVolume: TJclCompressionVolume; AOwnsStream: Boolean; AFileName: TFileName; begin Result := nil; if Index <> FTmpVolumeIndex then begin AOwnsStream := VolumeFileNameMask <> ''; AVolume := nil; if VolumeFileNameMask = '' then AFileName := '' else AFileName := FindUnusedFileName(Format(VolumeFileNameMask, [Index + VolumeIndexOffset]), '.tmp'); if (Index >= 0) and (Index < FVolumes.Count) then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); Result := AVolume.TmpStream; AOwnsStream := AVolume.OwnsTmpStream; AFileName := AVolume.TmpFileName; if (AFileName = '') and (AVolume.FileName <> '') then AFileName := FindUnusedFileName(AVolume.FileName, '.tmp'); end; if Assigned(FOnTmpVolume) then FOnTmpVolume(Self, Index, AFileName, Result, AOwnsStream); if Assigned(AVolume) then begin if not Assigned(Result) then Result := InternalOpenTmpStream(AFileName); AVolume.FTmpFileName := AFileName; AVolume.FTmpStream := Result; AVolume.FOwnsTmpStream := AOwnsStream; end else begin while FVolumes.Count < Index do FVolumes.Add(TJclCompressionVolume.Create(nil, nil, True, True, Format(VolumeFileNameMask, [Index + VolumeIndexOffset]), '', FVolumeMaxSize)); if not Assigned(Result) then Result := InternalOpenTmpStream(AFileName); if Assigned(Result) then begin if Index < FVolumes.Count then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); AVolume.FTmpFileName := AFileName; AVolume.FTmpStream := Result; AVolume.FOwnsTmpStream := AOwnsStream; AVolume.FVolumeMaxSize := FVolumeMaxSize; end else FVolumes.Add(TJclCompressionVolume.Create(nil, Result, True, AOwnsStream, '', AFileName, FVolumeMaxSize)); end; end; FTmpVolumeIndex := Index; end else if (Index >= 0) and (Index < FVolumes.Count) then begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); Result := AVolume.TmpStream; if Assigned(Result) then Result.Seek(0, soBeginning); end else FTmpVolumeIndex := Index; end; class function TJclOutOfPlaceUpdateArchive.TmpVolumeAccess: TJclStreamAccess; begin Result := saWriteOnly; end; //=== { TJclSevenzipOutStream } ============================================== constructor TJclSevenzipOutStream.Create(AArchive: TJclCompressionArchive; AItemIndex: Integer); begin inherited Create; FArchive := AArchive; FItemIndex := AItemIndex; FStream := nil; FOwnsStream := False; FMaximumPosition := 0; FTruncateOnRelease := False; NeedStream; end; constructor TJclSevenzipOutStream.Create(AStream: TStream; AOwnsStream: Boolean; ATruncateOnRelease: Boolean); begin inherited Create; FArchive := nil; FItemIndex := -1; FStream := AStream; FOwnsStream := AOwnsStream; FMaximumPosition := 0; FTruncateOnRelease := ATruncateOnRelease; end; destructor TJclSevenzipOutStream.Destroy; begin ReleaseStream; inherited Destroy; end; procedure TJclSevenzipOutStream.NeedStream; begin if Assigned(FArchive) then begin FArchive.FCurrentItemIndex := FItemIndex; if not Assigned(FStream) then FStream := FArchive.Items[FItemIndex].Stream; end; end; procedure TJclSevenzipOutStream.ReleaseStream; begin // truncate to the maximum position that was written if FTruncateOnRelease then FStream.Size := FMaximumPosition; if Assigned(FArchive) then FArchive.Items[FItemIndex].ReleaseStream else if FOwnsStream then FStream.Free; end; function TJclSevenzipOutStream.Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; var NewPos: Int64; begin NeedStream; if Assigned(FStream) then begin Result := S_OK; // STREAM_SEEK_SET = 0 = soBeginning // STREAM_SEEK_CUR = 1 = soCurrent // STREAM_SEEK_END = 2 = soEnd NewPos := FStream.Seek(Offset, TSeekOrigin(SeekOrigin)); if Assigned(NewPosition) then NewPosition^ := NewPos; end else Result := S_FALSE; end; function TJclSevenzipOutStream.SetSize(NewSize: Int64): HRESULT; begin NeedStream; if Assigned(FStream) then begin Result := S_OK; FStream.Size := NewSize; if FTruncateOnRelease and (FMaximumPosition < NewSize) then FMaximumPosition := NewSize; end else Result := S_FALSE; end; function TJclSevenzipOutStream.Write(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; var Processed: Cardinal; APosition: Int64; begin NeedStream; if Assigned(FStream) then begin Result := S_OK; Processed := FStream.Write(Data^, Size); if Assigned(ProcessedSize) then ProcessedSize^ := Processed; if FTruncateOnRelease then begin APosition := FStream.Position; if FMaximumPosition < APosition then FMaximumPosition := APosition; end; end else Result := S_FALSE; end; //=== { TJclSevenzipNestedInStream } ========================================= constructor TJclSevenzipNestedInStream.Create(AInStream: IInStream); begin inherited Create; FInStream := AInStream; end; function TJclSevenzipNestedInStream.Read(var Buffer; Count: Integer): Longint; begin SevenzipCheck(FInStream.Read(@Buffer, Count, @Result)); end; function TJclSevenzipNestedInStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin SevenzipCheck(FInStream.Seek(Offset, Cardinal(Origin), @Result)); end; procedure TJclSevenzipNestedInStream.SetSize(const NewSize: Int64); begin raise EJclCompressionError.CreateRes(@RsCompressionWriteNotSupported); end; function TJclSevenzipNestedInStream.Write(const Buffer; Count: Integer): Longint; begin raise EJclCompressionError.CreateRes(@RsCompressionWriteNotSupported); end; //=== { TJclSevenzipInStream } =============================================== constructor TJclSevenzipInStream.Create(AArchive: TJclCompressionArchive; AItemIndex: Integer); begin inherited Create; FArchive := AArchive; FItemIndex := AItemIndex; FStream := nil; FOwnsStream := False; NeedStream; end; constructor TJclSevenzipInStream.Create(AStream: TStream; AOwnsStream: Boolean); begin inherited Create; FArchive := nil; FItemIndex := -1; FStream := AStream; FOwnsStream := AOwnsStream; end; destructor TJclSevenzipInStream.Destroy; begin ReleaseStream; inherited Destroy; end; function TJclSevenzipInStream.GetSize(Size: PInt64): HRESULT; begin NeedStream; if Assigned(FStream) then begin if Assigned(Size) then Size^ := FStream.Size; Result := S_OK; end else Result := S_FALSE; end; procedure TJclSevenzipInStream.NeedStream; begin if Assigned(FArchive) then begin FArchive.FCurrentItemIndex := FItemIndex; if not Assigned(FStream) then FStream := FArchive.Items[FItemIndex].Stream; end; end; function TJclSevenzipInStream.Read(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; var Processed: Cardinal; begin NeedStream; if Assigned(FStream) then begin Processed := FStream.Read(Data^, Size); if Assigned(ProcessedSize) then ProcessedSize^ := Processed; Result := S_OK; end else Result := S_FALSE; end; procedure TJclSevenzipInStream.ReleaseStream; begin if Assigned(FArchive) then FArchive.Items[FItemIndex].ReleaseStream else if FOwnsStream then FStream.Free; end; function TJclSevenzipInStream.Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; var NewPos: Int64; begin NeedStream; if Assigned(FStream) then begin // STREAM_SEEK_SET = 0 = soBeginning // STREAM_SEEK_CUR = 1 = soCurrent // STREAM_SEEK_END = 2 = soEnd NewPos := FStream.Seek(Offset, TSeekOrigin(SeekOrigin)); if Assigned(NewPosition) then NewPosition^ := NewPos; Result := S_OK; end else Result := S_FALSE; end; // sevenzip helper functions procedure SevenzipCheck(Value: HRESULT); begin if (Value <> S_OK) and (Value <> E_ABORT) then raise EJclCompressionError.CreateResFmt(@RsCompression7zReturnError, [Value, SysErrorMessage(Value)]); end; function Get7zWideStringProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TWideStringSetter): Boolean; var Value: TPropVariant; begin ZeroMemory(@Value, SizeOf(Value)); SevenzipCheck(AArchive.GetProperty(ItemIndex, PropID, Value)); case Value.vt of VT_EMPTY, VT_NULL: Result := False; VT_LPSTR: begin Result := True; Setter(WideString(AnsiString(Value.pszVal))); end; VT_LPWSTR: begin Result := True; Setter(Value.pwszVal); end; VT_BSTR: begin Result := True; Setter(Value.bstrVal); SysFreeString(Value.bstrVal); end; VT_I1: begin Result := True; Setter(IntToStr(Value.iVal)); end; VT_I2: begin Result := True; Setter(IntToStr(Value.iVal)); end; VT_INT, VT_I4: begin Result := True; Setter(IntToStr(Value.lVal)); end; VT_I8: begin Result := True; Setter(IntToStr(Value.hVal.QuadPart)); end; VT_UI1: begin Result := True; Setter(IntToStr(Value.bVal)); end; VT_UI2: begin Result := True; Setter(IntToStr(Value.uiVal)); end; VT_UINT, VT_UI4: begin Result := True; Setter(IntToStr(Value.ulVal)); end; VT_UI8: begin Result := True; Setter(IntToStr(Value.uhVal.QuadPart)); end; else raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [Value.vt, PropID]); end; end; function Get7zCardinalProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TCardinalSetter): Boolean; var Value: TPropVariant; begin ZeroMemory(@Value, SizeOf(Value)); SevenzipCheck(AArchive.GetProperty(ItemIndex, PropID, Value)); case Value.vt of VT_EMPTY, VT_NULL: Result := False; VT_I1, VT_I2, VT_INT, VT_I4, VT_I8, VT_UI1, VT_UI2, VT_UINT, VT_UI4, VT_UI8: begin Result := True; case Value.vt of VT_I1: Setter(Value.iVal); VT_I2: Setter(Value.iVal); VT_INT, VT_I4: Setter(Value.lVal); VT_I8: Setter(Value.hVal.QuadPart); VT_UI1: Setter(Value.bVal); VT_UI2: Setter(Value.uiVal); VT_UINT, VT_UI4: Setter(Value.ulVal); VT_UI8: Setter(Value.uhVal.QuadPart); end; end; else raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [Value.vt, PropID]); end; end; function Get7zInt64Prop(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TInt64Setter): Boolean; var Value: TPropVariant; begin ZeroMemory(@Value, SizeOf(Value)); SevenzipCheck(AArchive.GetProperty(ItemIndex, PropID, Value)); case Value.vt of VT_EMPTY, VT_NULL: Result := False; VT_I1, VT_I2, VT_INT, VT_I4, VT_I8, VT_UI1, VT_UI2, VT_UINT, VT_UI4, VT_UI8: begin Result := True; case Value.vt of VT_I1: Setter(Value.iVal); VT_I2: Setter(Value.iVal); VT_INT, VT_I4: Setter(Value.lVal); VT_I8: Setter(Value.hVal.QuadPart); VT_UI1: Setter(Value.bVal); VT_UI2: Setter(Value.uiVal); VT_UINT, VT_UI4: Setter(Value.ulVal); VT_UI8: Setter(Value.uhVal.QuadPart); end; end; else raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [Value.vt, PropID]); end; end; function Get7zFileTimeProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TFileTimeSetter): Boolean; var Value: TPropVariant; begin ZeroMemory(@Value, SizeOf(Value)); SevenzipCheck(AArchive.GetProperty(ItemIndex, PropID, Value)); case Value.vt of VT_EMPTY, VT_NULL: Result := False; VT_FILETIME: begin Result := True; Setter(Value.filetime); end; else raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [Value.vt, PropID]); end; end; function Get7zBoolProp(const AArchive: IInArchive; ItemIndex: Integer; PropID: Cardinal; const Setter: TBoolSetter): Boolean; var Value: TPropVariant; begin ZeroMemory(@Value, SizeOf(Value)); SevenzipCheck(AArchive.GetProperty(ItemIndex, PropID, Value)); case Value.vt of VT_EMPTY, VT_NULL: Result := False; VT_BOOL: begin Result := True; Setter(Value.bool); end; else raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [Value.vt, PropID]); end; end; // TODO: Are changes for UTF-8 filenames (>= 4.58 beta) necessary? procedure Load7zFileAttribute(AInArchive: IInArchive; ItemIndex: Integer; AItem: TJclCompressionItem); begin AItem.FValidProperties := []; AItem.FPackedIndex := ItemIndex; AItem.FileName := ''; AItem.Stream := nil; AItem.OwnsStream := False; // sometimes, items have neither names nor extension although other properties may succeed Get7zWideStringProp(AInArchive, ItemIndex, kpidPath, AItem.SetPackedName); Get7zWideStringProp(AInArchive, ItemIndex, kpidExtension, AItem.SetPackedExtension); Get7zCardinalProp(AInArchive, ItemIndex, kpidAttrib, AItem.SetAttributes); // SetDirectory must be after SetAttributes Get7zBoolProp(AInArchive, ItemIndex, kpidIsDir, AItem.SetDirectory); Get7zInt64Prop(AInArchive, ItemIndex, kpidSize, AItem.SetFileSize); Get7zInt64Prop(AInArchive, ItemIndex, kpidPackSize, AItem.SetPackedSize); Get7zFileTimeProp(AInArchive, ItemIndex, kpidCTime, AItem.SetCreationTime); Get7zFileTimeProp(AInArchive, ItemIndex, kpidATime, AItem.SetLastAccessTime); Get7zFileTimeProp(AInArchive, ItemIndex, kpidMTime, AItem.SetLastWriteTime); Get7zWideStringProp(AInArchive, ItemIndex, kpidComment, AItem.SetComment); Get7zWideStringProp(AInArchive, ItemIndex, kpidHostOS, AItem.SetHostOS); Get7zWideStringProp(AInArchive, ItemIndex, kpidFileSystem, AItem.SetHostFS); Get7zWideStringProp(AInArchive, ItemIndex, kpidUser, AItem.SetUser); Get7zWideStringProp(AInArchive, ItemIndex, kpidGroup, AItem.SetGroup); Get7zCardinalProp(AInArchive, ItemIndex, kpidCRC, AItem.SetCRC); Get7zWideStringProp(AInArchive, ItemIndex, kpidMethod, AItem.SetMethod); Get7zBoolProp(AInArchive, ItemIndex, kpidEncrypted, AItem.SetEncrypted); // reset modified flags AItem.ModifiedProperties := []; end; procedure GetSevenzipArchiveCompressionProperties(AJclArchive: IInterface; ASevenzipArchive: IInterface); begin // TODO properties from ASevenzipArchive to AJclArchive end; procedure SetSevenzipArchiveCompressionProperties(AJclArchive: IInterface; ASevenzipArchive: IInterface); var Index: Integer; JclArchive: TJclCompressionArchive; PropertySetter: Sevenzip.ISetProperties; InArchive, OutArchive: Boolean; Unused: IInterface; MultiThreadStrategy: IJclArchiveNumberOfThreads; CompressionMethod: IJclArchiveCompressionMethod; CompressionLevel: IJclArchiveCompressionLevel; EncryptionMethod: IJclArchiveEncryptionMethod; DictionarySize: IJclArchiveDictionarySize; NumberOfPasses: IJclArchiveNumberOfPasses; RemoveSfxBlock: IJclArchiveRemoveSfxBlock; CompressHeader: IJclArchiveCompressHeader; EncryptHeader: IJclArchiveEncryptHeader; SaveCreationDateTime: IJclArchiveSaveCreationDateTime; SaveLastAccessDateTime: IJclArchiveSaveLastAccessDateTime; SaveLastWriteDateTime: IJclArchiveSaveLastWriteDateTime; Algorithm: IJclArchiveAlgorithm; Solid: IJclArchiveSolid; PropNames: array of PWideChar; PropValues: array of TPropVariant; procedure AddProperty(const Name: PWideChar; const Value: TPropVariant); begin SetLength(PropNames, Length(PropNames)+1); PropNames[High(PropNames)] := Name; SetLength(PropValues, Length(PropValues)+1); PropValues[High(PropValues)] := Value; end; procedure AddCardinalProperty(const Name: PWideChar; Value: Cardinal); var PropValue: TPropVariant; begin PropValue.vt := VT_UI4; PropValue.ulVal := Value; AddProperty(Name, PropValue); end; procedure AddWideStringProperty(const Name: PWideChar; const Value: WideString); var PropValue: TPropVariant; begin PropValue.vt := VT_BSTR; PropValue.bstrVal := SysAllocString(PWideChar(Value)); AddProperty(Name, PropValue); end; procedure AddBooleanProperty(const Name: PWideChar; Value: Boolean); var PropValue: TPropVariant; const BooleanValues: array [False..True] of WideString = ( 'OFF', 'ON' ); begin PropValue.vt := VT_BSTR; PropValue.bstrVal := SysAllocString(PWideChar(BooleanValues[Value])); AddProperty(Name, PropValue); end; const EncryptionMethodNames: array [TJclEncryptionMethod] of WideString = ( '' {emNone}, kAES128MethodName {emAES128}, kAES192MethodName {emAES192}, kAES256MethodName {emAES256}, kZipCryptoMethodName {emZipCrypto} ); CompressionMethodNames: array [TJclCompressionMethod] of WideString = ( kCopyMethodName {cmCopy}, kDeflateMethodName {cmDeflate}, kDeflate64MethodName {cmDeflate64}, kBZip2MethodName {cmBZip2}, kLZMAMethodName {cmLZMA}, kLZMA2MethodName {cmLZMA2}, kPPMdMethodName {cmPPMd} ); begin if Supports(ASevenzipArchive, Sevenzip.ISetProperties, PropertySetter) and Assigned(PropertySetter) then begin InArchive := Supports(ASevenzipArchive, Sevenzip.IInArchive, Unused); OutArchive := Supports(ASevenzipArchive, Sevenzip.IOutArchive, Unused); if (InArchive or OutArchive) and Supports(AJclArchive, IJclArchiveNumberOfThreads, MultiThreadStrategy) and Assigned(MultiThreadStrategy) and (MultiThreadStrategy.NumberOfThreads > 1) then AddCardinalProperty('MT', MultiThreadStrategy.NumberOfThreads); if OutArchive then begin if Supports(AJclArchive, IJclArchiveCompressionMethod, CompressionMethod) and Assigned(CompressionMethod) then AddWideStringProperty('M', CompressionMethodNames[CompressionMethod.CompressionMethod]); if Supports(AJclArchive, IJclArchiveCompressionLevel, CompressionLevel) and Assigned(CompressionLevel) then AddCardinalProperty('X', CompressionLevel.CompressionLevel); if Supports(AJclArchive, IJclArchiveEncryptionMethod, EncryptionMethod) and Assigned(EncryptionMethod) and (EncryptionMethod.EncryptionMethod <> emNone) then AddWideStringProperty('EM', EncryptionMethodNames[EncryptionMethod.EncryptionMethod]); if Supports(AJclArchive, IJclArchiveDictionarySize, DictionarySize) and Assigned(DictionarySize) and Supports(AJclArchive, IJclArchiveCompressionMethod, CompressionMethod) and Assigned(CompressionMethod) and (CompressionMethod.CompressionMethod in [cmBZip2,cmLZMA,cmLZMA2]) then AddWideStringProperty('D', IntToStr(DictionarySize.DictionarySize) + 'B'); if Supports(AJclArchive, IJclArchiveNumberOfPasses, NumberOfPasses) and Assigned(NumberOfPasses) then AddCardinalProperty('PASS', NumberOfPasses.NumberOfPasses); if Supports(AJclArchive, IJclArchiveRemoveSfxBlock, RemoveSfxBlock) and Assigned(RemoveSfxBlock) then AddBooleanProperty('RSFX', RemoveSfxBlock.RemoveSfxBlock); if Supports(AJclArchive, IJclArchiveCompressHeader, CompressHeader) and Assigned(CompressHeader) then begin AddBooleanProperty('HC', CompressHeader.CompressHeader); if CompressHeader.CompressHeaderFull then AddBooleanProperty('HCF', CompressHeader.CompressHeaderFull); end; if Supports(AJclArchive, IJclArchiveEncryptHeader, EncryptHeader) and Assigned(EncryptHeader) then AddBooleanProperty('HE', EncryptHeader.EncryptHeader); if Supports(AJclArchive, IJclArchiveSaveCreationDateTime, SaveCreationDateTime) and Assigned(SaveCreationDateTime) then AddBooleanProperty('TC', SaveCreationDateTime.SaveCreationDateTime); if Supports(AJclArchive, IJclArchiveSaveLastAccessDateTime, SaveLastAccessDateTime) and Assigned(SaveLastAccessDateTime) then AddBooleanProperty('TA', SaveLastAccessDateTime.SaveLastAccessDateTime); if Supports(AJclArchive, IJclArchiveSaveLastWriteDateTime, SaveLastWriteDateTime) and Assigned(SaveLastWriteDateTime) then AddBooleanProperty('TM', SaveLastWriteDateTime.SaveLastWriteDateTime); if Supports(AJclArchive, IJclArchiveAlgorithm, Algorithm) and Assigned(Algorithm) then AddCardinalProperty('A', Algorithm.Algorithm); if Supports(AJclArchive, IJclArchiveSolid, Solid) and Assigned(Solid) then begin if Solid.SolidExtension then AddWideStringProperty('S', 'E'); if Solid.SolidBlockSize > 0 then AddWideStringProperty('S', IntToStr(Solid.SolidBlockSize) + 'B') else AddWideStringProperty('S', IntToStr(Solid.SolidBlockSize) + 'F'); end; JclArchive := AJclArchive as TJclCompressionArchive; for Index := Low(JclArchive.PropNames) to High(JclArchive.PropNames) do begin AddProperty(PWideChar(JclArchive.PropNames[Index]), JclArchive.PropValues[Index]); end; end; if Length(PropNames) > 0 then try SevenZipCheck(PropertySetter.SetProperties(@PropNames[0], @PropValues[0], Length(PropNames))); finally for Index := 0 to High(PropValues) do begin if (PropValues[Index].vt = VT_BSTR) and (PropValues[Index].bstrVal <> nil) then begin SysFreeString(PropValues[Index].bstrVal); end; SetLength(JclArchive.PropNames, 0); SetLength(JclArchive.PropValues, 0); end end; end; end; function Create7zFile(SourceFiles: TStrings; const DestinationFile: TFileName; VolumeSize: Int64; Password: String; OnArchiveProgress: TJclCompressionProgressEvent; OnArchiveRatio: TJclCompressionRatioEvent): Boolean; var ArchiveFileName: string; SourceFile : String; AFormat: TJclUpdateArchiveClass; Archive : TJclCompressionArchive; i: Integer; InnerList : tStringList; j: Integer; begin Result := False; ArchiveFileName := DestinationFile; AFormat := GetArchiveFormats.FindUpdateFormat(ArchiveFileName); if AFormat <> nil then begin if VolumeSize <> 0 then ArchiveFileName := ArchiveFileName + '.%.3d'; Archive := AFormat.Create(ArchiveFileName, VolumeSize, VolumeSize <> 0); try Archive.Password := Password; Archive.OnProgress := OnArchiveProgress; Archive.OnRatio := OnArchiveRatio; InnerList := tStringList.Create; try for i := 0 to SourceFiles.Count - 1 do begin InnerList.Clear; BuildFileList(SourceFiles[i], faAnyFile, InnerList, True); for j := 0 to InnerList.Count - 1 do begin SourceFile:=InnerList[j]; (Archive as TJclCompressArchive).AddFile(ExtractFileName(SourceFile), SourceFile); Result := True; end; end; finally InnerList.Free; end; (Archive as TJclCompressArchive).Compress; finally Archive.Free; end; end; end; function Create7zFile(const SourceFile, DestinationFile: TFileName; VolumeSize: Int64; Password: String; OnArchiveProgress: TJclCompressionProgressEvent; OnArchiveRatio: TJclCompressionRatioEvent): Boolean; var SourceFiles : TStringList; begin SourceFiles := TStringList.Create; try SourceFiles.Add(SourceFile); Result := Create7zFile(SourceFiles, DestinationFile, VolumeSize, Password, OnArchiveProgress, OnArchiveRatio); finally SourceFiles.Free; end; end; function Get7zArchiveSignature(const ClassID: TGUID): TDynByteArray; var I, NumberOfFormats: Cardinal; J: Integer; PropValue: TPropVariant; Found: Boolean; Data: PAnsiChar; begin Found := False; SetLength(Result, 0); SevenzipCheck(Sevenzip.GetNumberOfFormats(@NumberOfFormats)); for I := 0 to NumberOfFormats - 1 do begin SevenzipCheck(Sevenzip.GetHandlerProperty2(I, kClassID, PropValue)); if PropValue.vt = VT_BSTR then begin try if SysStringByteLen(PropValue.bstrVal) = SizeOf(TGUID) then Found := GUIDEquals(PGUID(PropValue.bstrVal)^, ClassID) else raise EJclCompressionError.CreateRes(@RsCompressionDataError); finally SysFreeString(PropValue.bstrVal); end; end else raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [PropValue.vt, kClassID]); if Found then begin SevenzipCheck(Sevenzip.GetHandlerProperty2(I, kStartSignature, PropValue)); if PropValue.vt = VT_BSTR then begin try SetLength(Result, SysStringByteLen(PropValue.bstrVal)); Data := PAnsiChar(PropValue.bstrVal); for J := Low(Result) to High(Result) do Result[J] := Ord(Data[J]); finally SysFreeString(PropValue.bstrVal); end; end else if PropValue.vt <> VT_EMPTY then raise EJclCompressionError.CreateResFmt(@RsCompression7zUnknownValueType, [PropValue.vt, kClassID]); Break; end; end; end; //=== { TJclSevenzipOutputCallback } ========================================= constructor TJclSevenzipUpdateCallback.Create( AArchive: TJclCompressionArchive); begin inherited Create; FArchive := AArchive; end; function TJclSevenzipUpdateCallback.CryptoGetTextPassword2( PasswordIsDefined: PInteger; Password: PBStr): HRESULT; begin if Assigned(PasswordIsDefined) then begin if FArchive.Password <> '' then PasswordIsDefined^ := Integer($FFFFFFFF) else PasswordIsDefined^ := 0; end; if Assigned(Password) then Password^ := SysAllocString(PWideChar(FArchive.Password)); Result := S_OK; end; function TJclSevenzipUpdateCallback.GetProperty(Index, PropID: Cardinal; out Value: tagPROPVARIANT): HRESULT; var AItem: TJclCompressionItem; begin Result := S_OK; AItem := FArchive.Items[Index]; case PropID of kpidNoProperty: Value.vt := VT_NULL; // kpidMainSubfile: ; // kpidHandlerItemIndex: ; kpidPath: begin Value.vt := VT_BSTR; Value.bstrVal := SysAllocString(PWideChar(AItem.PackedName)); end; //kpidName: (read only) { kpidExtension: begin Value.vt := VT_BSTR; Value.bstrVal := SysAllocString(PWideChar(WideString(ExtractFileExt(FCompressionStream.FileNames[Index])))); end;} kpidIsDir: begin Value.vt := VT_BOOL; Value.bool := AItem.Kind = ikDirectory; end; kpidSize: begin Value.vt := VT_UI8; Value.uhVal.QuadPart := AItem.FileSize; end; // kpidPackSize: ; kpidAttrib: begin Value.vt := VT_UI4; Value.ulVal := AItem.Attributes; end; kpidCTime: begin Value.vt := VT_FILETIME; Value.filetime := AItem.CreationTime; end; kpidATime: begin Value.vt := VT_FILETIME; Value.filetime := AItem.LastAccessTime; end; kpidMTime: begin Value.vt := VT_FILETIME; Value.filetime := AItem.LastWriteTime; end; kpidSolid: begin Value.vt := VT_BOOL; Value.bool := True; end; // kpidCommented: ; // kpidEncrypted: ; // kpidSplitBefore: ; // kpidSplitAfter: ; // kpidDictionarySize: ; // kpidCRC: ; // kpidType: ; kpidIsAnti: begin Value.vt := VT_BOOL; Value.bool := False; end; // kpidMethod: ; // kpidHostOS: ; // kpidFileSystem: ; kpidUser: begin Value.vt := VT_BSTR; Value.bstrVal := SysAllocString(PWideChar(AItem.User)); end; kpidGroup: begin Value.vt := VT_BSTR; Value.bstrVal := SysAllocString(PWideChar(AItem.Group)); end; // kpidBlock: ; kpidComment: begin Value.vt := VT_EMPTY; end; // kpidPosition: ; // kpidPrefix: ; // kpidNumSubDirs: ; // kpidNumSubFiles: ; // kpidUnpackVer: ; // kpidVolume: ; // kpidIsVolume: ; // kpidOffset: ; // kpidLinks: ; // kpidNumBlocks: ; // kpidNumVolumes: ; kpidTimeType: begin Value.vt := VT_UI4; Value.ulVal := kWindows; end; // kpidBit64: ; // kpidBigEndian: ; // kpidCpu: ; // kpidPhySize: ; // kpidHeadersSize: ; // kpidChecksum: ; // kpidCharacts: ; // kpidVa: ; // kpidId: ; kpidShortName: begin Value.vt := VT_EMPTY; end; // kpidCreatorApp: ; // kpidSectorSize: ; kpidPosixAttrib: begin Value.vt := VT_EMPTY; end; // kpidLink: ; // kpidTotalSize: ; // kpidFreeSpace: ; // kpidClusterSize: ; // kpidVolumeName: ; // kpidLocalName: ; // kpidProvider: ; // kpidUserDefined: ; kpidIsAltStream: begin Value.vt := VT_BOOL; Value.bool := False; end; else Value.vt := VT_EMPTY; Result := S_FALSE; end; end; function TJclSevenzipUpdateCallback.GetStream(Index: Cardinal; out InStream: ISequentialInStream): HRESULT; begin Result := E_FAIL; FLastStream := Index; repeat try InStream := TJclSevenzipInStream.Create(FArchive, Index); Result := S_OK; except on E: Exception do begin case MessageBoxW(0, PWideChar(UTF8Decode(E.Message)), nil, MB_ABORTRETRYIGNORE or MB_ICONERROR) of IDABORT: Exit(E_ABORT); IDIGNORE: begin FArchive.Items[Index].OperationSuccess := osNoOperation; FLastStream := MAXDWORD; Exit(S_FALSE); end; end; end; end; until Result = S_OK; end; function TJclSevenzipUpdateCallback.GetUpdateItemInfo(Index: Cardinal; NewData, NewProperties: PInteger; IndexInArchive: PCardinal): HRESULT; var CompressionItem: TJclCompressionItem; begin CompressionItem := FArchive.Items[Index]; if Assigned(NewData) then begin if ([ipFileName, ipStream] * CompressionItem.ModifiedProperties) <> [] then NewData^ := 1 else NewData^ := 0; end; if Assigned(NewProperties) then begin if (CompressionItem.ModifiedProperties - [ipFileName, ipStream]) <> [] then NewProperties^ := 1 else NewProperties^ := 0; end; // TODO if Assigned(IndexInArchive) then IndexInArchive^ := CompressionItem.PackedIndex; Result := S_OK; end; function TJclSevenzipUpdateCallback.GetVolumeSize(Index: Cardinal; Size: PInt64): HRESULT; begin // the JCL has its own spliting engine if Assigned(Size) then Size^ := 0; Result := S_FALSE; end; function TJclSevenzipUpdateCallback.GetVolumeStream(Index: Cardinal; out VolumeStream: ISequentialOutStream): HRESULT; begin VolumeStream := nil; Result := S_FALSE; end; function TJclSevenzipUpdateCallback.SetCompleted( CompleteValue: PInt64): HRESULT; begin Result := S_OK; if Assigned(CompleteValue) and not FArchive.DoProgress(CompleteValue^, FArchive.FProgressMax) then Result := E_ABORT; end; function TJclSevenzipUpdateCallback.SetOperationResult( OperationResult: Integer): HRESULT; begin if FLastStream < MAXDWORD then begin case OperationResult of kOK: FArchive.Items[FLastStream].OperationSuccess := osOK; kUnSupportedMethod: FArchive.Items[FLastStream].OperationSuccess := osUnsupportedMethod; kDataError: FArchive.Items[FLastStream].OperationSuccess := osDataError; kCRCError: FArchive.Items[FLastStream].OperationSuccess := osCRCError; else FArchive.Items[FLastStream].OperationSuccess := osUnknownError; end; end; Result := S_OK; end; function TJclSevenzipUpdateCallback.SetRatioInfo(InSize, OutSize: PInt64): HRESULT; var AInSize, AOutSize: Int64; begin if Assigned(InSize) then AInSize := InSize^ else AInSize := -1; if Assigned(OutSize) then AOutSize := OutSize^ else AOutSize := -1; if FArchive.DoRatio(AInSize, AOutSize) then Result := S_OK else Result := E_ABORT; end; function TJclSevenzipUpdateCallback.SetTotal(Total: Int64): HRESULT; begin FArchive.FProgressMax := Total; if FArchive.CancelCurrentOperation then Result := E_ABORT else Result := S_OK; end; //=== { TJclSevenzipCompressArchive } ======================================== class function TJclSevenzipCompressArchive.ArchiveCLSID: TGUID; begin Result := GUID_NULL; end; class function TJclSevenzipCompressArchive.ArchiveSignature: TDynByteArray; begin Result := Get7zArchiveSignature(ArchiveCLSID); end; destructor TJclSevenzipCompressArchive.Destroy; begin FOutArchive := nil; inherited Destroy; end; function TJclSevenzipCompressArchive.GetItemClass: TJclCompressionItemClass; begin Result := TJclCompressItem; end; function TJclSevenzipCompressArchive.GetOutArchive: IOutArchive; var SevenzipCLSID, InterfaceID: TGUID; begin if not Assigned(FOutArchive) then begin SevenzipCLSID := ArchiveCLSID; InterfaceID := Sevenzip.IOutArchive; if (not Is7ZipLoaded) and (not Load7Zip) then raise EJclCompressionError.CreateRes(@RsCompression7zLoadError); if (Sevenzip.CreateObject(@SevenzipCLSID, @InterfaceID, FOutArchive) <> ERROR_SUCCESS) or not Assigned(FOutArchive) then raise EJclCompressionError.CreateResFmt(@RsCompression7zOutArchiveError, [GUIDToString(SevenzipCLSID)]); end; Result := FOutArchive; end; procedure TJclSevenzipCompressArchive.Compress; var Value: HRESULT; Index: Integer; OutStream: IOutStream; AVolume: TJclCompressionVolume; UpdateCallback: IArchiveUpdateCallback; SplitStream: TJclDynamicSplitStream; begin CheckNotCompressing; FCompressing := True; try SplitStream := TJclDynamicSplitStream.Create(False); SplitStream.OnVolume := NeedStream; SplitStream.OnVolumeMaxSize := NeedStreamMaxSize; if Length(FSfxModule) > 0 then OutStream := TSfxSevenzipOutStream.Create(SplitStream, FSfxModule) else begin OutStream := TJclSevenzipOutStream.Create(SplitStream, True, False); end; UpdateCallback := TJclSevenzipUpdateCallback.Create(Self); SetSevenzipArchiveCompressionProperties(Self, OutArchive); Value:= OutArchive.UpdateItems(OutStream, ItemCount, UpdateCallback); if Value <> S_OK then begin // Remove partial archives for Index := 0 to FVolumes.Count - 1 do begin AVolume := TJclCompressionVolume(FVolumes.Items[Index]); if AVolume.OwnsStream then begin FreeAndNil(AVolume.FStream); FileDelete(AVolume.FileName); end; end; end; SevenzipCheck(Value); finally FCompressing := False; // release volumes and other finalizations inherited Compress; end; end; //=== { TJcl7zCompressArchive } ============================================== class function TJcl7zCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompression7zExtensions); end; class function TJcl7zCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompression7zName); end; class function TJcl7zCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormat7z; end; function TJcl7zCompressArchive.GetCompressHeader: Boolean; begin Result := FCompressHeader; end; function TJcl7zCompressArchive.GetCompressHeaderFull: Boolean; begin Result := FCompressHeaderFull; end; function TJcl7zCompressArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJcl7zCompressArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJcl7zCompressArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJcl7zCompressArchive.GetDictionarySize: Cardinal; begin Result := FDictionarySize; end; function TJcl7zCompressArchive.GetEncryptHeader: Boolean; begin Result := FEncryptHeader; end; function TJcl7zCompressArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; function TJcl7zCompressArchive.GetRemoveSfxBlock: Boolean; begin Result := FRemoveSfxBlock; end; function TJcl7zCompressArchive.GetSaveCreationDateTime: Boolean; begin Result := FSaveCreationDateTime; end; function TJcl7zCompressArchive.GetSaveLastAccessDateTime: Boolean; begin Result := FSaveLastAccessDateTime; end; function TJcl7zCompressArchive.GetSaveLastWriteDateTime: Boolean; begin Result := FSaveLastWriteDateTime; end; function TJcl7zCompressArchive.GetSolidBlockSize: Int64; begin Result := FSolidBlockSize; end; function TJcl7zCompressArchive.GetSolidExtension: Boolean; begin Result := FSolidExtension; end; procedure TJcl7zCompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; FEncryptHeader := False; FRemoveSfxBlock := False; FDictionarySize := kLzmaDicSizeX5; FCompressionLevel := 6; FCompressHeader := False; FCompressHeaderFull := False; FSaveLastAccessDateTime := True; FSaveCreationDateTime := True; FSaveLastWriteDateTime := True; FSolidBlockSize := High(Cardinal); FSolidExtension := False; end; class function TJcl7zCompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; procedure TJcl7zCompressArchive.SetCompressHeader(Value: Boolean); begin CheckNotCompressing; FCompressHeader := Value; end; procedure TJcl7zCompressArchive.SetCompressHeaderFull(Value: Boolean); begin CheckNotCompressing; FCompressHeaderFull := Value; end; procedure TJcl7zCompressArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; if Value <= 9 then begin FCompressionLevel := Value; if Value >= 9 then FDictionarySize := kLzmaDicSizeX9 else if Value >= 7 then FDictionarySize := kLzmaDicSizeX7 else if Value >= 5 then FDictionarySize := kLzmaDicSizeX5 else if Value >= 3 then FDictionarySize := kLzmaDicSizeX3 else FDictionarySize := kLzmaDicSizeX1; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJcl7zCompressArchive.SetDictionarySize(Value: Cardinal); begin CheckNotCompressing; FDictionarySize := Value; end; procedure TJcl7zCompressArchive.SetEncryptHeader(Value: Boolean); begin CheckNotCompressing; FEncryptHeader := Value; end; procedure TJcl7zCompressArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotCompressing; FNumberOfThreads := Value; end; procedure TJcl7zCompressArchive.SetRemoveSfxBlock(Value: Boolean); begin CheckNotCompressing; FRemoveSfxBlock := Value; end; procedure TJcl7zCompressArchive.SetSaveCreationDateTime(Value: Boolean); begin CheckNotCompressing; FSaveCreationDateTime := Value; end; procedure TJcl7zCompressArchive.SetSaveLastAccessDateTime(Value: Boolean); begin CheckNotCompressing; FSaveLastAccessDateTime := Value; end; procedure TJcl7zCompressArchive.SetSaveLastWriteDateTime(Value: Boolean); begin CheckNotCompressing; FSaveLastWriteDateTime := Value; end; procedure TJcl7zCompressArchive.SetSolidBlockSize(const Value: Int64); begin CheckNotCompressing; FSolidBlockSize := Value; end; procedure TJcl7zCompressArchive.SetSolidExtension(Value: Boolean); begin CheckNotCompressing; FSolidExtension := Value; end; //=== { TJclZipCompressArchive } ============================================= class function TJclZipCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionZipExtensions); end; class function TJclZipCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionZipName); end; class function TJclZipCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatZip; end; function TJclZipCompressArchive.GetAlgorithm: Cardinal; begin Result := FAlgorithm; end; function TJclZipCompressArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJclZipCompressArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJclZipCompressArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJclZipCompressArchive.GetCompressionMethod: TJclCompressionMethod; begin Result := FCompressionMethod; end; function TJclZipCompressArchive.GetDictionarySize: Cardinal; begin Result := FDictionarySize; end; function TJclZipCompressArchive.GetEncryptionMethod: TJclEncryptionMethod; begin Result := FEncryptionMethod; end; function TJclZipCompressArchive.GetNumberOfPasses: Cardinal; begin Result := FNumberOfPasses; end; function TJclZipCompressArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; function TJclZipCompressArchive.GetSupportedAlgorithms: TDynCardinalArray; begin SetLength(Result, 2); Result[0] := 0; Result[1] := 1; end; function TJclZipCompressArchive.GetSupportedCompressionMethods: TJclCompressionMethods; begin Result := [cmCopy,cmDeflate,cmDeflate64,cmBZip2,cmLZMA,cmPPMd]; end; function TJclZipCompressArchive.GetSupportedEncryptionMethods: TJclEncryptionMethods; begin Result := [emNone,emAES128,emAES192,emAES256,emZipCrypto]; end; procedure TJclZipCompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; FEncryptionMethod := emZipCrypto; FDictionarySize := kBZip2DicSizeX5; FCompressionLevel := 7; FCompressionMethod := cmDeflate; FNumberOfPasses := kDeflateNumPassesX7; FAlgorithm := kLzAlgoX5; end; class function TJclZipCompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; procedure TJclZipCompressArchive.SetAlgorithm(Value: Cardinal); begin CheckNotCompressing; if (Value = 0) or (Value = 1) then FAlgorithm := Value else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipCompressArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; if Value <= 9 then begin FCompressionLevel := Value; case FCompressionMethod of cmDeflate, cmDeflate64: begin if Value >= 9 then FNumberOfPasses := kDeflateNumPassesX9 else if Value >= 7 then FNumberOfPasses := kDeflateNumPassesX7 else FNumberOfPasses := kDeflateNumPassesX1; if Value >= 5 then FAlgorithm := kLzAlgoX5 else FAlgorithm := kLzAlgoX1; end; cmBZip2: begin if Value >= 9 then FNumberOfPasses := kBZip2NumPassesX9 else if Value >= 7 then FNumberOfPasses := kBZip2NumPassesX7 else FNumberOfPasses := kBZip2NumPassesX1; if Value >= 5 then FDictionarySize := kBZip2DicSizeX5 else if Value >= 3 then FDictionarySize := kBZip2DicSizeX3 else FDictionarySize := kBZip2DicSizeX1; end; cmLZMA: begin if Value >= 9 then FDictionarySize := kLzmaDicSizeX9 else if Value >= 7 then FDictionarySize := kLzmaDicSizeX7 else if Value >= 5 then FDictionarySize := kLzmaDicSizeX5 else if Value >= 3 then FDictionarySize := kLzmaDicSizeX3 else FDictionarySize := kLzmaDicSizeX1; if Value >= 5 then FAlgorithm := kLzAlgoX5 else FAlgorithm := kLzAlgoX1; end; end; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipCompressArchive.SetCompressionMethod(Value: TJclCompressionMethod); begin CheckNotCompressing; if Value in GetSupportedCompressionMethods then FCompressionMethod := Value else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipCompressArchive.SetDictionarySize(Value: Cardinal); begin CheckNotCompressing; FDictionarySize := Value; end; procedure TJclZipCompressArchive.SetEncryptionMethod(Value: TJclEncryptionMethod); begin CheckNotCompressing; if Value in GetSupportedEncryptionMethods then FEncryptionMethod := Value else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipCompressArchive.SetNumberOfPasses(Value: Cardinal); begin CheckNotCompressing; FNumberOfPasses := Value; end; procedure TJclZipCompressArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotCompressing; FNumberOfThreads := Value; end; //=== { TJclBZ2CompressArchive } ============================================= class function TJclBZ2CompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionBZip2Extensions); end; class function TJclBZ2CompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionBZip2Name); end; class function TJclBZ2CompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionBZip2SubExtensions); end; class function TJclBZ2CompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatBZ2; end; function TJclBZ2CompressArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJclBZ2CompressArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJclBZ2CompressArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJclBZ2CompressArchive.GetDictionarySize: Cardinal; begin Result := FDictionarySize; end; function TJclBZ2CompressArchive.GetNumberOfPasses: Cardinal; begin Result := FNumberOfPasses; end; function TJclBZ2CompressArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; procedure TJclBZ2CompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; FDictionarySize := kBZip2DicSizeX5; FCompressionLevel := 7; FNumberOfPasses := kBZip2NumPassesX7; end; procedure TJclBZ2CompressArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; if Value <= 9 then begin FCompressionLevel := Value; if Value >= 9 then FNumberOfPasses := kBZip2NumPassesX9 else if Value >= 7 then FNumberOfPasses := kBZip2NumPassesX7 else FNumberOfPasses := kBZip2NumPassesX1; if Value >= 5 then FDictionarySize := kBZip2DicSizeX5 else if Value >= 3 then FDictionarySize := kBZip2DicSizeX3 else FDictionarySize := kBZip2DicSizeX1; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclBZ2CompressArchive.SetDictionarySize(Value: Cardinal); begin CheckNotCompressing; FDictionarySize := Value; end; procedure TJclBZ2CompressArchive.SetNumberOfPasses(Value: Cardinal); begin CheckNotCompressing; FNumberOfPasses := Value; end; procedure TJclBZ2CompressArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotCompressing; FNumberOfThreads := Value; end; //=== { TJclTarCompressArchive } ============================================= class function TJclTarCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionTarExtensions); end; class function TJclTarCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionTarName); end; class function TJclTarCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatTar; end; class function TJclTarCompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclGZipCompressArchive } ============================================ class function TJclGZipCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionGZipExtensions); end; class function TJclGZipCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionGZipName); end; class function TJclGZipCompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionGZipSubExtensions); end; class function TJclGZipCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatGZip; end; function TJclGZipCompressArchive.GetAlgorithm: Cardinal; begin Result := FAlgorithm; end; function TJclGZipCompressArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJclGZipCompressArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJclGZipCompressArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJclGZipCompressArchive.GetNumberOfPasses: Cardinal; begin Result := FNumberOfPasses; end; function TJclGZipCompressArchive.GetSupportedAlgorithms: TDynCardinalArray; begin SetLength(Result,2); Result[0] := 0; Result[1] := 1; end; procedure TJclGZipCompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FCompressionLevel := 7; FNumberOfPasses := kDeflateNumPassesX7; FAlgorithm := kLzAlgoX5; end; procedure TJclGZipCompressArchive.SetAlgorithm(Value: Cardinal); begin CheckNotCompressing; FAlgorithm := Value; end; procedure TJclGZipCompressArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; if Value <= 9 then begin if Value >= 9 then FNumberOfPasses := kDeflateNumPassesX9 else if Value >= 7 then FNumberOfPasses := kDeflateNumPassesX7 else FNumberOfPasses := kDeflateNumPassesX1; if Value >= 5 then FAlgorithm := kLzAlgoX5 else FAlgorithm := kLzAlgoX1; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclGZipCompressArchive.SetNumberOfPasses(Value: Cardinal); begin CheckNotCompressing; FNumberOfPasses := Value; end; //=== { TJclXzCompressArchive } ============================================== class function TJclXzCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionXzExtensions); end; class function TJclXzCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionXzName); end; class function TJclXzCompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionXzSubExtensions); end; class function TJclXzCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatXz; end; function TJclXzCompressArchive.GetCompressionMethod: TJclCompressionMethod; begin Result := FCompressionMethod; end; function TJclXzCompressArchive.GetSupportedCompressionMethods: TJclCompressionMethods; begin Result := [cmLZMA2]; end; procedure TJclXzCompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FCompressionMethod := cmLZMA2; end; procedure TJclXzCompressArchive.SetCompressionMethod( Value: TJclCompressionMethod); begin CheckNotCompressing; FCompressionMethod := Value; end; //=== { TJclSwfcCompressArchive } ============================================ class function TJclSwfcCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionSwfcExtensions); end; class function TJclSwfcCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionSwfcName); end; class function TJclSwfcCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatSwfc; end; //=== { TJclWimCompressArchive } ============================================= class function TJclWimCompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatWim; end; class function TJclWimCompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionWimExtensions); end; class function TJclWimCompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionWimName); end; //=== { TJclSevenzipOpenCallback } =========================================== constructor TJclSevenzipOpenCallback.Create( AArchive: TJclCompressionArchive); begin inherited Create; FArchive := AArchive; end; function TJclSevenzipOpenCallback.CryptoGetTextPassword( password: PBStr): HRESULT; begin if Assigned(password) then begin if Length(FArchive.FPassword) = 0 then begin if Assigned(FArchive.OnPassword) then FArchive.OnPassword(FArchive, FArchive.FPassword); end; password^ := SysAllocString(PWideChar(FArchive.Password)); end; Result := S_OK; end; function TJclSevenzipOpenCallback.SetCompleted(Files, Bytes: PInt64): HRESULT; begin Result := S_OK; if Assigned(Files) and not FArchive.DoProgress(Files^, FArchive.FProgressMax) then Result := E_ABORT; end; function TJclSevenzipOpenCallback.SetTotal(Files, Bytes: PInt64): HRESULT; begin if Assigned(Files) then FArchive.FProgressMax := Files^; if FArchive.CancelCurrentOperation then Result := E_ABORT else Result := S_OK; end; //=== { TJclSevenzipExtractCallback } ======================================== constructor TJclSevenzipExtractCallback.Create( AArchive: TJclCompressionArchive); begin inherited Create; FArchive := AArchive; end; function TJclSevenzipExtractCallback.CryptoGetTextPassword( password: PBStr): HRESULT; begin if Assigned(password) then begin if Length(FArchive.FPassword) = 0 then begin if Assigned(FArchive.OnPassword) then FArchive.OnPassword(FArchive, FArchive.FPassword); end; password^ := SysAllocString(PWideChar(FArchive.Password)); end; Result := S_OK; end; function TJclSevenzipExtractCallback.GetStream(Index: Cardinal; out OutStream: ISequentialOutStream; askExtractMode: Cardinal): HRESULT; begin FLastStream := Index; Assert(askExtractMode in [kExtract, kTest, kSkip]); if askExtractMode in [kTest, kSkip] then begin OutStream := nil; Result := S_OK; end else if FArchive.Items[Index].ValidateExtraction(Index) then begin OutStream := TJclSevenzipOutStream.Create(FArchive, Index); Result := S_OK; end else begin OutStream := nil; Result := S_FALSE; end; end; function TJclSevenzipExtractCallback.PrepareOperation( askExtractMode: Cardinal): HRESULT; begin Result := S_OK; end; function TJclSevenzipExtractCallback.SetCompleted( CompleteValue: PInt64): HRESULT; begin Result := S_OK; if Assigned(CompleteValue) and not FArchive.DoProgress(CompleteValue^, FArchive.FProgressMax) then Result := E_ABORT; end; function TJclSevenzipExtractCallback.SetOperationResult( resultEOperationResult: Integer): HRESULT; var LastItem: TJclCompressionItem; begin LastItem := FArchive.Items[FLastStream]; case resultEOperationResult of kOK: begin LastItem.OperationSuccess := osOK; LastItem.UpdateFileTimes; end; kUnSupportedMethod: begin LastItem.OperationSuccess := osUnsupportedMethod; LastItem.DeleteOutputFile; end; kDataError: begin LastItem.OperationSuccess := osDataError; LastItem.DeleteOutputFile; end; kCRCError: begin LastItem.OperationSuccess := osCRCError; LastItem.DeleteOutputFile; end else LastItem.OperationSuccess := osUnknownError; LastItem.DeleteOutputFile; end; Result := S_OK; end; function TJclSevenzipExtractCallback.SetRatioInfo(InSize, OutSize: PInt64): HRESULT; var AInSize, AOutSize: Int64; begin if Assigned(InSize) then AInSize := InSize^ else AInSize := -1; if Assigned(OutSize) then AOutSize := OutSize^ else AOutSize := -1; if FArchive.DoRatio(AInSize, AOutSize) then Result := S_OK else Result := E_ABORT; end; function TJclSevenzipExtractCallback.SetTotal(Total: Int64): HRESULT; begin FArchive.FProgressMax := Total; if FArchive.CancelCurrentOperation then Result := E_ABORT else Result := S_OK; end; //=== { TJclSevenzipDecompressItem } ========================================= function TJclSevenzipDecompressItem.GetNestedArchiveStream: TStream; var SequentialInStream: ISequentialInStream; InStream: IInStream; InterfaceID: TGUID; begin if Archive.SupportsNestedArchive and (Archive is TJclSevenzipDecompressArchive) then begin SevenzipCheck(TJclSevenzipDecompressArchive(Archive).InArchiveGetStream.GetStream(PackedIndex, SequentialInStream)); InterfaceID := IInStream; SevenzipCheck(SequentialInStream.QueryInterface(InterfaceID, InStream)); Result := TJclSevenzipNestedInStream.Create(InStream); end else Result := inherited GetNestedArchiveStream; end; //=== { TJclSevenzipDecompressArchive } ====================================== class function TJclSevenzipDecompressArchive.ArchiveCLSID: TGUID; begin Result := GUID_NULL; end; class function TJclSevenzipDecompressArchive.ArchiveSignature: TDynByteArray; begin Result := Get7zArchiveSignature(ArchiveCLSID); end; destructor TJclSevenzipDecompressArchive.Destroy; begin FInArchive := nil; FInArchiveGetStream := nil; inherited Destroy; end; procedure TJclSevenzipDecompressArchive.ExtractAll(const ADestinationDir: string; AAutoCreateSubDir: Boolean); var AExtractCallback: IArchiveExtractCallback; Indices: array of Cardinal; NbIndices: Cardinal; Index: Integer; begin CheckNotDecompressing; FDestinationDir := ADestinationDir; FAutoCreateSubDir := AAutoCreateSubDir; if FDestinationDir <> '' then FDestinationDir := PathAddSeparator(FDestinationDir); FDecompressing := True; FExtractingAllIndex := 0; AExtractCallback := TJclSevenzipExtractCallback.Create(Self); try OpenArchive; // seems buggy: first param "indices" is dereferenced without // liveness checks inside Sevenzip code //SevenzipCheck(InArchive.Extract(nil, $FFFFFFFF, 0, AExtractCallback)); NbIndices := ItemCount; SetLength(Indices, NbIndices); for Index := 0 to NbIndices - 1 do begin Items[Index].Selected := True; Indices[Index] := Index; end; SevenzipCheck(InArchive.Extract(@Indices[0], NbIndices, 0, AExtractCallback)); CheckOperationSuccess; finally FDestinationDir := ''; FDecompressing := False; FExtractingAllIndex := -1; FCurrentItemIndex := -1; AExtractCallback := nil; // release volumes and other finalizations inherited ExtractAll(ADestinationDir, AAutoCreateSubDir); end; end; procedure TJclSevenzipDecompressArchive.ExtractSelected(const ADestinationDir: string; AAutoCreateSubDir: Boolean); var AExtractCallback: IArchiveExtractCallback; Indices: array of Cardinal; NbIndices: Cardinal; Index: Integer; begin CheckNotDecompressing; FDestinationDir := ADestinationDir; FAutoCreateSubDir := AAutoCreateSubDir; if FDestinationDir <> '' then FDestinationDir := PathAddSeparator(FDestinationDir); FDecompressing := True; AExtractCallback := TJclSevenzipExtractCallback.Create(Self); try OpenArchive; NbIndices := 0; for Index := 0 to ItemCount - 1 do if Items[Index].Selected then Inc(NbIndices); SetLength(Indices, NbIndices); NbIndices := 0; for Index := 0 to ItemCount - 1 do if Items[Index].Selected then begin Indices[NbIndices] := Index; Inc(NbIndices); end; SevenzipCheck(InArchive.Extract(@Indices[0], Length(Indices), 0, AExtractCallback)); CheckOperationSuccess; finally FDestinationDir := ''; FDecompressing := False; AExtractCallback := nil; FCurrentItemIndex := -1; // release volumes and other finalizations inherited ExtractSelected(ADestinationDir, AAutoCreateSubDir); end; end; function TJclSevenzipDecompressArchive.GetInArchive: IInArchive; var SevenzipCLSID, InterfaceID: TGUID; begin if not Assigned(FInArchive) then begin SevenzipCLSID := ArchiveCLSID; InterfaceID := Sevenzip.IInArchive; if (not Is7ZipLoaded) and (not Load7Zip) then raise EJclCompressionError.CreateRes(@RsCompression7zLoadError); if (Sevenzip.CreateObject(@SevenzipCLSID, @InterfaceID, FInArchive) <> ERROR_SUCCESS) or not Assigned(FInArchive) then raise EJclCompressionError.CreateResFmt(@RsCompression7zInArchiveError, [GUIDToString(SevenzipCLSID)]); FExtractingAllIndex := -1; end; Result := FInArchive; end; function TJclSevenzipDecompressArchive.GetInArchiveGetStream: IInArchiveGetStream; var InterfaceID: TGUID; begin if not Assigned(FInArchiveGetStream) then begin InterfaceID := Sevenzip.IInArchiveGetStream; SevenzipCheck(InArchive.QueryInterface(InterfaceID, FInArchiveGetStream)); end; Result := FInArchiveGetStream; end; function TJclSevenzipDecompressArchive.GetItemClass: TJclCompressionItemClass; begin Result := TJclSevenzipDecompressItem; end; function TJclSevenzipDecompressArchive.GetSupportsNestedArchive: Boolean; var InterfaceID: TGUID; begin Result := Assigned(FInArchiveGetStream); if not Result then begin InterfaceID := Sevenzip.IInArchiveGetStream; Result := InArchive.QueryInterface(InterfaceID, FInArchiveGetStream) = ERROR_SUCCESS; end; end; procedure TJclSevenzipDecompressArchive.ListFiles; var NumberOfItems: Cardinal; Index: Integer; AItem: TJclCompressionItem; begin CheckNotDecompressing; FListing := True; try ClearItems; OpenArchive; SevenzipCheck(InArchive.GetNumberOfItems(@NumberOfItems)); if NumberOfItems > 0 then begin for Index := 0 to NumberOfItems - 1 do begin AItem := GetItemClass.Create(Self); Load7zFileAttribute(InArchive, Index, AItem); FItems.Add(AItem); end; end; finally FListing := False; end; end; procedure TJclSevenzipDecompressArchive.OpenArchive; var SplitStream: TJclDynamicSplitStream; OpenCallback: IArchiveOpenCallback; MaxCheckStartPosition: Int64; AInStream: IInStream; begin if not FOpened then begin if (VolumeFileNameMask <> '') or (VolumeMaxSize <> 0) or (FVolumes.Count <> 0) then begin SplitStream := TJclDynamicSplitStream.Create(False); SplitStream.OnVolume := NeedStream; SplitStream.OnVolumeMaxSize := NeedStreamMaxSize; AInStream := TJclSevenzipInStream.Create(SplitStream, True); end else AInStream := TJclSevenzipInStream.Create(NeedStream(0), False); OpenCallback := TJclSevenzipOpenCallback.Create(Self); SetSevenzipArchiveCompressionProperties(Self, InArchive); MaxCheckStartPosition := 1 shl 22; SevenzipCheck(InArchive.Open(AInStream, @MaxCheckStartPosition, OpenCallback)); GetSevenzipArchiveCompressionProperties(Self, InArchive); FOpened := True; end; end; //=== { TJclZipDecompressArchive } =========================================== class function TJclZipDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionZipExtensions); end; class function TJclZipDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionZipName); end; class function TJclZipDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatZip; end; function TJclZipDecompressArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; procedure TJclZipDecompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; end; class function TJclZipDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; procedure TJclZipDecompressArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotDecompressing; FNumberOfThreads := Value; end; //=== { TJclBZ2DecompressArchive } =========================================== class function TJclBZ2DecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionBZip2Extensions); end; class function TJclBZ2DecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionBZip2Name); end; class function TJclBZ2DecompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionBZip2SubExtensions); end; class function TJclBZ2DecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatBZ2; end; function TJclBZ2DecompressArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; procedure TJclBZ2DecompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; end; procedure TJclBZ2DecompressArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotDecompressing; FNumberOfThreads := Value; end; //=== { TJclRarDecompressArchive } =========================================== class function TJclRarDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionRarExtensions); end; class function TJclRarDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionRarName); end; class function TJclRarDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatRar; end; class function TJclRarDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclArjDecompressArchive } =========================================== class function TJclArjDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionArjExtensions); end; class function TJclArjDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionArjName); end; class function TJclArjDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatArj; end; class function TJclArjDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclZDecompressArchive } ============================================= class function TJclZDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionZExtensions); end; class function TJclZDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionZName); end; class function TJclZDecompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionZSubExtensions); end; class function TJclZDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatZ; end; class function TJclZDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclLzhDecompressArchive } =========================================== class function TJclLzhDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionLzhExtensions); end; class function TJclLzhDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionLzhName); end; class function TJclLzhDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatLzh; end; class function TJclLzhDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJcl7zDecompressArchive } ============================================ class function TJcl7zDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompression7zExtensions); end; class function TJcl7zDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompression7zName); end; class function TJcl7zDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormat7z; end; function TJcl7zDecompressArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; procedure TJcl7zDecompressArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; end; class function TJcl7zDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; procedure TJcl7zDecompressArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotDecompressing; FNumberOfThreads := Value; end; //=== { TJclCabDecompressArchive } =========================================== class function TJclCabDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionCabExtensions); end; class function TJclCabDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionCabName); end; class function TJclCabDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatCab; end; class function TJclCabDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclNsisDecompressArchive } ========================================== class function TJclNsisDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionNsisExtensions); end; class function TJclNsisDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionNsisName); end; class function TJclNsisDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatNsis; end; class function TJclNsisDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclLzmaDecompressArchive } ========================================== class function TJclLzmaDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionLzmaExtensions); end; class function TJclLzmaDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionLzmaName); end; class function TJclLzmaDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatLzma; end; class function TJclLzmaDecompressArchive.MultipleItemContainer: Boolean; begin Result := False; end; //=== { TJclLzma86DecompressArchive } ======================================== class function TJclLzma86DecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionLzma86Extensions); end; class function TJclLzma86DecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionLzma86Name); end; class function TJclLzma86DecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatLzma86; end; class function TJclLzma86DecompressArchive.MultipleItemContainer: Boolean; begin Result := False; end; //=== { TJclPeDecompressArchive } ============================================ class function TJclPeDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionPeExtensions); end; class function TJclPeDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionPeName); end; class function TJclPeDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatPe; end; class function TJclPeDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclElfDecompressArchive } =========================================== class function TJclElfDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionElfExtensions); end; class function TJclElfDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionElfName); end; class function TJclElfDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatElf; end; class function TJclElfDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclMachoDecompressArchive } ========================================= class function TJclMachoDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionMachoExtensions); end; class function TJclMachoDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionMachoName); end; class function TJclMachoDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatMacho; end; class function TJclMachoDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclUdfDecompressArchive } ========================================== class function TJclUdfDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionUdfExtensions); end; class function TJclUdfDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionUdfName); end; class function TJclUdfDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatUdf; end; class function TJclUdfDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclXarDecompressArchive } =========================================== class function TJclXarDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionXarExtensions); end; class function TJclXarDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionXarName); end; class function TJclXarDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatXar; end; class function TJclXarDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclMubDecompressArchive } =========================================== class function TJclMubDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionMubExtensions); end; class function TJclMubDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionMubName); end; class function TJclMubDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatMub; end; class function TJclMubDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclHfsDecompressArchive } =========================================== class function TJclHfsDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionHfsExtensions); end; class function TJclHfsDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionHfsName); end; class function TJclHfsDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatHfs; end; class function TJclHfsDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclDmgDecompressArchive } =========================================== class function TJclDmgDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionDmgExtensions); end; class function TJclDmgDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionDmgName); end; class function TJclDmgDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatDmg; end; class function TJclDmgDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclCompoundDecompressArchive } ====================================== class function TJclCompoundDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionCompoundExtensions); end; class function TJclCompoundDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionCompoundName); end; class function TJclCompoundDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatCompound; end; class function TJclCompoundDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclWimDecompressArchive } =========================================== class function TJclWimDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionWimExtensions); end; class function TJclWimDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionWimName); end; class function TJclWimDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatWim; end; class function TJclWimDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclIsoDecompressArchive } =========================================== class function TJclIsoDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionIsoExtensions); end; class function TJclIsoDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionIsoName); end; class function TJclIsoDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatIso; end; class function TJclIsoDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclChmDecompressArchive } =========================================== class function TJclChmDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionChmExtensions); end; class function TJclChmDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionChmName); end; class function TJclChmDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatChm; end; class function TJclChmDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclSplitDecompressArchive } ========================================= class function TJclSplitDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionSplitExtensions); end; class function TJclSplitDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionSplitName); end; class function TJclSplitDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatSplit; end; //=== { TJclRpmDecompressArchive } =========================================== class function TJclRpmDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionRpmExtensions); end; class function TJclRpmDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionRpmName); end; class function TJclRpmDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatRpm; end; class function TJclRpmDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclDebDecompressArchive } =========================================== class function TJclDebDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionDebExtensions); end; class function TJclDebDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionDebName); end; class function TJclDebDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatDeb; end; class function TJclDebDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclCpioDecompressArchive } ========================================== class function TJclCpioDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionCpioExtensions); end; class function TJclCpioDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionCpioName); end; class function TJclCpioDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatCpio; end; class function TJclCpioDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclTarDecompressArchive } =========================================== class function TJclTarDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionTarExtensions); end; class function TJclTarDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionTarName); end; class function TJclTarDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatTar; end; class function TJclTarDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclGZipDecompressArchive } ========================================== class function TJclGZipDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionGZipExtensions); end; class function TJclGZipDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionGZipName); end; class function TJclGZipDecompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionGZipSubExtensions); end; class function TJclGZipDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatGZip; end; //=== { TJclXzDecompressArchive } ============================================ class function TJclXzDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionXzExtensions); end; class function TJclXzDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionXzName); end; class function TJclXzDecompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionXzSubExtensions); end; class function TJclXzDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatXz; end; //=== { TJclNtfsDecompressArchive } ========================================== class function TJclNtfsDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionNtfsExtensions); end; class function TJclNtfsDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionNtfsName); end; class function TJclNtfsDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatNtfs; end; class function TJclNtfsDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclFatDecompressArchive } =========================================== class function TJclFatDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionFatExtensions); end; class function TJclFatDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionFatName); end; class function TJclFatDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatFat; end; class function TJclFatDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclMbrDecompressArchive } =========================================== class function TJclMbrDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionMbrExtensions); end; class function TJclMbrDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionMbrName); end; class function TJclMbrDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatMbr; end; class function TJclMbrDecompressArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclVhdDecompressArchive } =========================================== class function TJclVhdDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionVhdExtensions); end; class function TJclVhdDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionVhdName); end; class function TJclVhdDecompressArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionVhdSubExtensions); end; class function TJclVhdDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatVhd; end; //=== { TJclMslzDecompressArchive } ========================================== class function TJclMslzDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionMslzExtensions); end; class function TJclMslzDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionMslzName); end; class function TJclMslzDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatMslz; end; //=== { TJclFlvDecompressArchive } =========================================== class function TJclFlvDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionFlvExtensions); end; class function TJclFlvDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionFlvName); end; class function TJclFlvDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatFlv; end; //=== { TJclSwfDecompressArchive } =========================================== class function TJclSwfDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionSwfExtensions); end; class function TJclSwfDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionSwfName); end; class function TJclSwfDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatSwf; end; //=== { TJclSwfcDecompressArchive } ========================================== class function TJclSwfcDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionSwfcExtensions); end; class function TJclSwfcDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionSwfcName); end; class function TJclSwfcDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatSwfc; end; //=== { TJclAPMDecompressArchive } =========================================== class function TJclAPMDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionApmExtensions); end; class function TJclAPMDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionApmName); end; class function TJclAPMDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatAPM; end; //=== { TJclPpmdDecompressArchive } ========================================== class function TJclPpmdDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionPpmdExtensions); end; class function TJclPpmdDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionPpmdName); end; class function TJclPpmdDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatPpmd; end; //=== { TJclTEDecompressArchive } ============================================ class function TJclTEDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionTEExtensions); end; class function TJclTEDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionTEName); end; class function TJclTEDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatTE; end; //=== { TJclUEFIcDecompressArchive } ========================================= class function TJclUEFIcDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionUEFIcExtensions); end; class function TJclUEFIcDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionUEFIcName); end; class function TJclUEFIcDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatUEFIc; end; //=== { TJclUEFIsDecompressArchive } ========================================= class function TJclUEFIsDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionUEFIsExtensions); end; class function TJclUEFIsDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionUEFIsName); end; class function TJclUEFIsDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatUEFIs; end; //=== { TJclSquashFSDecompressArchive } ====================================== class function TJclSquashFSDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionSquashFSExtensions); end; class function TJclSquashFSDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionSquashFSName); end; class function TJclSquashFSDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatSquashFS; end; //=== { TJclCramFSDecompressArchive } ======================================== class function TJclCramFSDecompressArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionCramFSExtensions); end; class function TJclCramFSDecompressArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionCramFSName); end; class function TJclCramFSDecompressArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatCramFS; end; //=== { TJclSevenzipUpdateArchive } ========================================== class function TJclSevenzipUpdateArchive.ArchiveCLSID: TGUID; begin Result := GUID_NULL; end; destructor TJclSevenzipUpdateArchive.Destroy; begin FInArchive := nil; FOutArchive := nil; inherited Destroy; end; class function TJclSevenzipUpdateArchive.ArchiveSignature: TDynByteArray; begin Result := Get7zArchiveSignature(ArchiveCLSID); end; procedure TJclSevenzipUpdateArchive.Compress; var Value: HRESULT; OutStream: IOutStream; UpdateCallback: IArchiveUpdateCallback; SplitStream: TJclDynamicSplitStream; begin CheckNotCompressing; CheckNotDecompressing; FCompressing := True; try SplitStream := TJclDynamicSplitStream.Create(True); SplitStream.OnVolume := NeedTmpStream; SplitStream.OnVolumeMaxSize := NeedStreamMaxSize; OutStream := TJclSevenzipOutStream.Create(SplitStream, True, True); UpdateCallback := TJclSevenzipUpdateCallback.Create(Self); SetSevenzipArchiveCompressionProperties(Self, OutArchive); Value:= OutArchive.UpdateItems(OutStream, ItemCount, UpdateCallback); if Value <> S_OK then begin FReplaceVolumes:= False; SevenzipCheck(Value); end; finally FCompressing := False; // release reference to volume streams OutStream := nil; // replace streams by tmp streams inherited Compress; end; end; procedure TJclSevenzipUpdateArchive.DeleteItem(Index: Integer); var I, BaseLength: Integer; IsDirectory: Boolean; AItem: TJclCompressionItem; DirectoryName: WideString; begin AItem := Items[Index]; IsDirectory := (AItem.Attributes and faDirectory) <> 0; DirectoryName := AItem.PackedName + DirDelimiter; FItems.Delete(Index); if IsDirectory then begin BaseLength := Length(DirectoryName); for I := ItemCount - 1 downto 0 do if WideSameText(DirectoryName, Copy(Items[I].PackedName, 1, BaseLength)) then FItems.Delete(I); end; end; procedure TJclSevenzipUpdateArchive.ExtractAll(const ADestinationDir: string; AAutoCreateSubDir: Boolean); var AExtractCallback: IArchiveExtractCallback; Indices: array of Cardinal; NbIndices: Cardinal; Index: Integer; begin CheckNotDecompressing; CheckNotCompressing; FDestinationDir := ADestinationDir; FAutoCreateSubDir := AAutoCreateSubDir; if FDestinationDir <> '' then FDestinationDir := PathAddSeparator(FDestinationDir); FDecompressing := True; FExtractingAllIndex := 0; AExtractCallback := TJclSevenzipExtractCallback.Create(Self); try OpenArchive; // seems buggy: first param "indices" is dereferenced without // liveness checks inside Sevenzip code //SevenzipCheck(InArchive.Extract(nil, $FFFFFFFF, 0, AExtractCallback)); NbIndices := ItemCount; SetLength(Indices, NbIndices); for Index := 0 to NbIndices - 1 do begin Items[Index].Selected := True; Indices[Index] := Index; end; SevenzipCheck(InArchive.Extract(@Indices[0], NbIndices, 0, AExtractCallback)); CheckOperationSuccess; finally FDestinationDir := ''; FDecompressing := False; FExtractingAllIndex := -1; FCurrentItemIndex := -1; AExtractCallback := nil; // release volumes and other finalizations inherited ExtractAll(ADestinationDir, AAutoCreateSubDir); end; end; procedure TJclSevenzipUpdateArchive.ExtractSelected( const ADestinationDir: string; AAutoCreateSubDir: Boolean); var AExtractCallback: IArchiveExtractCallback; Indices: array of Cardinal; NbIndices: Cardinal; Index: Integer; begin CheckNotDecompressing; CheckNotCompressing; FDestinationDir := ADestinationDir; FAutoCreateSubDir := AAutoCreateSubDir; if FDestinationDir <> '' then FDestinationDir := PathAddSeparator(FDestinationDir); FDecompressing := True; AExtractCallback := TJclSevenzipExtractCallback.Create(Self); try OpenArchive; NbIndices := 0; for Index := 0 to ItemCount - 1 do if Items[Index].Selected then Inc(NbIndices); SetLength(Indices, NbIndices); NbIndices := 0; for Index := 0 to ItemCount - 1 do if Items[Index].Selected then begin Indices[NbIndices] := Index; Inc(NbIndices); end; SevenzipCheck(InArchive.Extract(@Indices[0], Length(Indices), 0, AExtractCallback)); CheckOperationSuccess; finally FDestinationDir := ''; FDecompressing := False; AExtractCallback := nil; FCurrentItemIndex := -1; // release volumes and other finalizations inherited ExtractSelected(ADestinationDir, AAutoCreateSubDir); end; end; function TJclSevenzipUpdateArchive.GetInArchive: IInArchive; var SevenzipCLSID, InterfaceID: TGUID; begin if not Assigned(FInArchive) then begin SevenzipCLSID := ArchiveCLSID; InterfaceID := Sevenzip.IInArchive; if (not Is7ZipLoaded) and (not Load7Zip) then raise EJclCompressionError.CreateRes(@RsCompression7zLoadError); if (Sevenzip.CreateObject(@SevenzipCLSID, @InterfaceID, FInArchive) <> ERROR_SUCCESS) or not Assigned(FInArchive) then raise EJclCompressionError.CreateResFmt(@RsCompression7zInArchiveError, [GUIDToString(SevenzipCLSID)]); end; Result := FInArchive; end; function TJclSevenzipUpdateArchive.GetItemClass: TJclCompressionItemClass; begin Result := TJclUpdateItem; end; function TJclSevenzipUpdateArchive.GetOutArchive: IOutArchive; var SevenzipCLSID, InterfaceID: TGUID; begin if not Assigned(FOutarchive) then begin SevenzipCLSID := ArchiveCLSID; InterfaceID := Sevenzip.IOutArchive; if not Supports(InArchive, InterfaceID, FOutArchive) or not Assigned(FOutArchive) then raise EJclCompressionError.CreateResFmt(@RsCompression7zOutArchiveError, [GUIDToString(SevenzipCLSID)]); end; Result := FOutArchive; end; procedure TJclSevenzipUpdateArchive.ListFiles; var NumberOfItems: Cardinal; Index: Integer; AItem: TJclCompressionItem; begin CheckNotDecompressing; CheckNotCompressing; FListing := True; try ClearItems; OpenArchive; SevenzipCheck(InArchive.GetNumberOfItems(@NumberOfItems)); if NumberOfItems > 0 then begin for Index := 0 to NumberOfItems - 1 do begin AItem := GetItemClass.Create(Self); Load7zFileAttribute(InArchive, Index, AItem); FItems.Add(AItem); end; end; finally FListing := False; end; end; procedure TJclSevenzipUpdateArchive.OpenArchive; var OpenCallback: IArchiveOpenCallback; MaxCheckStartPosition: Int64; AInStream: IInStream; SplitStream: TJclDynamicSplitStream; begin if not FOpened then begin SplitStream := TJclDynamicSplitStream.Create(True); SplitStream.OnVolume := NeedStream; SplitStream.OnVolumeMaxSize := NeedStreamMaxSize; AInStream := TJclSevenzipInStream.Create(SplitStream, True); OpenCallback := TJclSevenzipOpenCallback.Create(Self); SetSevenzipArchiveCompressionProperties(Self, InArchive); MaxCheckStartPosition := 1 shl 22; SevenzipCheck(InArchive.Open(AInStream, @MaxCheckStartPosition, OpenCallback)); GetSevenzipArchiveCompressionProperties(Self, InArchive); FOpened := True; end; end; procedure TJclSevenzipUpdateArchive.RemoveItem(const PackedName: WideString); var Index, BaseLength, PackedNamesIndex: Integer; IsDirectory: Boolean; AItem: TJclCompressionItem; DirectoryName: WideString; begin IsDirectory := False; for Index := 0 to ItemCount - 1 do begin AItem := Items[Index]; if WideSameText(AItem.PackedName, PackedName) then begin DirectoryName := AItem.PackedName; if (AItem.Attributes and faDirectory) <> 0 then IsDirectory := True; FItems.Delete(Index); PackedNamesIndex := -1; if (FPackedNames <> nil) and FPackedNames.Find(PackedName, PackedNamesIndex) then FPackedNames.Delete(PackedNamesIndex); Break; end; end; if IsDirectory then begin DirectoryName := PackedName + DirDelimiter; BaseLength := Length(DirectoryName); for Index := ItemCount - 1 downto 0 do if WideSameText(DirectoryName, Copy(Items[Index].PackedName, 1, BaseLength)) then begin if (FPackedNames <> nil) and FPackedNames.Find(Items[Index].PackedName, PackedNamesIndex) then FPackedNames.Delete(PackedNamesIndex); FItems.Delete(Index); end; end; end; //=== { TJclZipUpdateArchive } =============================================== class function TJclZipUpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionZipExtensions); end; class function TJclZipUpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionZipName); end; class function TJclZipUpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatZip; end; function TJclZipUpdateArchive.GetAlgorithm: Cardinal; begin Result := FAlgorithm; end; function TJclZipUpdateArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJclZipUpdateArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJclZipUpdateArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJclZipUpdateArchive.GetCompressionMethod: TJclCompressionMethod; begin Result := FCompressionMethod; end; function TJclZipUpdateArchive.GetDictionarySize: Cardinal; begin Result := FDictionarySize; end; function TJclZipUpdateArchive.GetEncryptionMethod: TJclEncryptionMethod; begin Result := FEncryptionMethod; end; function TJclZipUpdateArchive.GetNumberOfPasses: Cardinal; begin Result := FNumberOfPasses; end; function TJclZipUpdateArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; function TJclZipUpdateArchive.GetSupportedAlgorithms: TDynCardinalArray; begin SetLength(Result,2); Result[0] := 0; Result[1] := 1; end; function TJclZipUpdateArchive.GetSupportedCompressionMethods: TJclCompressionMethods; begin Result := [cmCopy,cmDeflate,cmDeflate64,cmBZip2,cmLZMA]; end; function TJclZipUpdateArchive.GetSupportedEncryptionMethods: TJclEncryptionMethods; begin Result := [emNone,emAES128,emAES192,emAES256,emZipCrypto]; end; procedure TJclZipUpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; FEncryptionMethod := emZipCrypto; FDictionarySize := kBZip2DicSizeX5; FCompressionLevel := 7; FCompressionMethod := cmDeflate; FNumberOfPasses := kDeflateNumPassesX7; FAlgorithm := kLzAlgoX5; end; class function TJclZipUpdateArchive.MultipleItemContainer: Boolean; begin Result := True; end; procedure TJclZipUpdateArchive.SetAlgorithm(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; if (Value = 0) or (Value = 1) then FAlgorithm := Value else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipUpdateArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; if Value <= 9 then begin FCompressionLevel := Value; case FCompressionMethod of cmDeflate, cmDeflate64: begin if Value >= 9 then FNumberOfPasses := kDeflateNumPassesX9 else if Value >= 7 then FNumberOfPasses := kDeflateNumPassesX7 else FNumberOfPasses := kDeflateNumPassesX1; if Value >= 5 then FAlgorithm := kLzAlgoX5 else FAlgorithm := kLzAlgoX1; end; cmBZip2: begin if Value >= 9 then FNumberOfPasses := kBZip2NumPassesX9 else if Value >= 7 then FNumberOfPasses := kBZip2NumPassesX7 else FNumberOfPasses := kBZip2NumPassesX1; if Value >= 5 then FDictionarySize := kBZip2DicSizeX5 else if Value >= 3 then FDictionarySize := kBZip2DicSizeX3 else FDictionarySize := kBZip2DicSizeX1; end; cmLZMA: begin if Value >= 9 then FDictionarySize := kLzmaDicSizeX9 else if Value >= 7 then FDictionarySize := kLzmaDicSizeX7 else if Value >= 5 then FDictionarySize := kLzmaDicSizeX5 else if Value >= 3 then FDictionarySize := kLzmaDicSizeX3 else FDictionarySize := kLzmaDicSizeX1; if Value >= 5 then FAlgorithm := kLzAlgoX5 else FAlgorithm := kLzAlgoX1; end; end; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipUpdateArchive.SetCompressionMethod(Value: TJclCompressionMethod); begin CheckNotCompressing; CheckNotDecompressing; if Value in GetSupportedCompressionMethods then FCompressionMethod := Value else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipUpdateArchive.SetDictionarySize(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FDictionarySize := Value; end; procedure TJclZipUpdateArchive.SetEncryptionMethod(Value: TJclEncryptionMethod); begin CheckNotCompressing; CheckNotDecompressing; if Value in GetSupportedEncryptionMethods then FEncryptionMethod := Value else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclZipUpdateArchive.SetNumberOfPasses(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FNumberOfPasses := Value; end; procedure TJclZipUpdateArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FNumberOfThreads := Value; end; //=== { TJclBZ2UpdateArchive } =============================================== class function TJclBZ2UpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionBZip2Extensions); end; class function TJclBZ2UpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionBZip2Name); end; class function TJclBZ2UpdateArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionBZip2SubExtensions); end; class function TJclBZ2UpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatBZ2; end; function TJclBZ2UpdateArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJclBZ2UpdateArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJclBZ2UpdateArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJclBZ2UpdateArchive.GetDictionarySize: Cardinal; begin Result := FDictionarySize; end; function TJclBZ2UpdateArchive.GetNumberOfPasses: Cardinal; begin Result := FNumberOfPasses; end; function TJclBZ2UpdateArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; procedure TJclBZ2UpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; FDictionarySize := kBZip2DicSizeX5; FCompressionLevel := 7; FNumberOfPasses := kBZip2NumPassesX7; end; procedure TJclBZ2UpdateArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; if Value <= 9 then begin FCompressionLevel := Value; if Value >= 9 then FNumberOfPasses := kBZip2NumPassesX9 else if Value >= 7 then FNumberOfPasses := kBZip2NumPassesX7 else FNumberOfPasses := kBZip2NumPassesX1; if Value >= 5 then FDictionarySize := kBZip2DicSizeX5 else if Value >= 3 then FDictionarySize := kBZip2DicSizeX3 else FDictionarySize := kBZip2DicSizeX1; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclBZ2UpdateArchive.SetDictionarySize(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FDictionarySize := Value; end; procedure TJclBZ2UpdateArchive.SetNumberOfPasses(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FNumberOfPasses := Value; end; procedure TJclBZ2UpdateArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FNumberOfThreads := Value; end; //=== { TJcl7zUpdateArchive } ================================================ class function TJcl7zUpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompression7zExtensions); end; class function TJcl7zUpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompression7zName); end; class function TJcl7zUpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormat7z; end; function TJcl7zUpdateArchive.GetCompressHeader: Boolean; begin Result := FCompressHeader; end; function TJcl7zUpdateArchive.GetCompressHeaderFull: Boolean; begin Result := FCompressHeaderFull; end; function TJcl7zUpdateArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJcl7zUpdateArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJcl7zUpdateArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJcl7zUpdateArchive.GetDictionarySize: Cardinal; begin Result := FDictionarySize; end; function TJcl7zUpdateArchive.GetEncryptHeader: Boolean; begin Result := FEncryptHeader; end; function TJcl7zUpdateArchive.GetNumberOfThreads: Cardinal; begin Result := FNumberOfThreads; end; function TJcl7zUpdateArchive.GetRemoveSfxBlock: Boolean; begin Result := FRemoveSfxBlock; end; function TJcl7zUpdateArchive.GetSaveCreationDateTime: Boolean; begin Result := FSaveCreationDateTime; end; function TJcl7zUpdateArchive.GetSaveLastAccessDateTime: Boolean; begin Result := FSaveLastAccessDateTime; end; function TJcl7zUpdateArchive.GetSaveLastWriteDateTime: Boolean; begin Result := FSaveLastWriteDateTime; end; procedure TJcl7zUpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FNumberOfThreads := 1; FEncryptHeader := False; FRemoveSfxBlock := False; FDictionarySize := kLzmaDicSizeX5; FCompressionLevel := 6; FCompressHeader := False; FCompressHeaderFull := False; FSaveLastAccessDateTime := True; FSaveCreationDateTime := True; FSaveLastWriteDateTime := True; end; class function TJcl7zUpdateArchive.MultipleItemContainer: Boolean; begin Result := True; end; procedure TJcl7zUpdateArchive.SetCompressHeader(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FCompressHeader := Value; end; procedure TJcl7zUpdateArchive.SetCompressHeaderFull(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FCompressHeaderFull := Value; end; procedure TJcl7zUpdateArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; if Value <= 9 then begin FCompressionLevel := Value; if Value >= 9 then FDictionarySize := kLzmaDicSizeX9 else if Value >= 7 then FDictionarySize := kLzmaDicSizeX7 else if Value >= 5 then FDictionarySize := kLzmaDicSizeX5 else if Value >= 3 then FDictionarySize := kLzmaDicSizeX3 else FDictionarySize := kLzmaDicSizeX1; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJcl7zUpdateArchive.SetDictionarySize(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FDictionarySize := Value; end; procedure TJcl7zUpdateArchive.SetEncryptHeader(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FEncryptHeader := Value; end; procedure TJcl7zUpdateArchive.SetNumberOfThreads(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FNumberOfThreads := Value; end; procedure TJcl7zUpdateArchive.SetRemoveSfxBlock(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FRemoveSfxBlock := Value; end; procedure TJcl7zUpdateArchive.SetSaveCreationDateTime(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FSaveCreationDateTime := Value; end; procedure TJcl7zUpdateArchive.SetSaveLastAccessDateTime(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FSaveLastAccessDateTime := Value; end; procedure TJcl7zUpdateArchive.SetSaveLastWriteDateTime(Value: Boolean); begin CheckNotCompressing; CheckNotDecompressing; FSaveLastWriteDateTime := Value; end; //=== { TJclTarUpdateArchive } =============================================== class function TJclTarUpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionTarExtensions); end; class function TJclTarUpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionTarName); end; class function TJclTarUpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatTar; end; class function TJclTarUpdateArchive.MultipleItemContainer: Boolean; begin Result := True; end; //=== { TJclGZipUpdateArchive } ============================================== class function TJclGZipUpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionGZipExtensions); end; class function TJclGZipUpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionGZipName); end; class function TJclGZipUpdateArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionGZipSubExtensions); end; class function TJclGZipUpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatGZip; end; function TJclGZipUpdateArchive.GetAlgorithm: Cardinal; begin Result := FAlgorithm; end; function TJclGZipUpdateArchive.GetCompressionLevel: Cardinal; begin Result := FCompressionLevel; end; function TJclGZipUpdateArchive.GetCompressionLevelMax: Cardinal; begin Result := 9; end; function TJclGZipUpdateArchive.GetCompressionLevelMin: Cardinal; begin Result := 0; end; function TJclGZipUpdateArchive.GetNumberOfPasses: Cardinal; begin Result := FNumberOfPasses; end; function TJclGZipUpdateArchive.GetSupportedAlgorithms: TDynCardinalArray; begin SetLength(Result,2); Result[0] := 0; Result[1] := 1; end; procedure TJclGZipUpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FCompressionLevel := 7; FNumberOfPasses := kDeflateNumPassesX7; FAlgorithm := kLzAlgoX5; end; procedure TJclGZipUpdateArchive.SetAlgorithm(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FAlgorithm := Value; end; procedure TJclGZipUpdateArchive.SetCompressionLevel(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; if Value <= 9 then begin if Value >= 9 then FNumberOfPasses := kDeflateNumPassesX9 else if Value >= 7 then FNumberOfPasses := kDeflateNumPassesX7 else FNumberOfPasses := kDeflateNumPassesX1; if Value >= 5 then FAlgorithm := kLzAlgoX5 else FAlgorithm := kLzAlgoX1; end else raise EJclCompressionError.CreateRes(@RsCompressionUnavailableProperty); end; procedure TJclGZipUpdateArchive.SetNumberOfPasses(Value: Cardinal); begin CheckNotCompressing; CheckNotDecompressing; FNumberOfPasses := Value; end; //=== { TJclXzUpdateArchive } ================================================ class function TJclXzUpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionXzExtensions); end; class function TJclXzUpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionXzExtensions); end; class function TJclXzUpdateArchive.ArchiveSubExtensions: string; begin Result := LoadResString(@RsCompressionXzSubExtensions); end; class function TJclXzUpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatXz; end; function TJclXzUpdateArchive.GetCompressionMethod: TJclCompressionMethod; begin Result := FCompressionMethod; end; function TJclXzUpdateArchive.GetSupportedCompressionMethods: TJclCompressionMethods; begin Result := [cmLZMA2]; end; procedure TJclXzUpdateArchive.InitializeArchiveProperties; begin inherited InitializeArchiveProperties; FCompressionMethod := cmLZMA2 end; procedure TJclXzUpdateArchive.SetCompressionMethod( Value: TJclCompressionMethod); begin CheckNotDecompressing; CheckNotCompressing; FCompressionMethod := Value; end; //=== { TJclSwfcUpdateArchive } ============================================== class function TJclSwfcUpdateArchive.ArchiveExtensions: string; begin Result := LoadResString(@RsCompressionSwfcExtensions); end; class function TJclSwfcUpdateArchive.ArchiveName: string; begin Result := LoadResString(@RsCompressionSwfcName); end; class function TJclSwfcUpdateArchive.ArchiveCLSID: TGUID; begin Result := CLSID_CFormatSwfc; end; {$ENDIF MSWINDOWS} initialization {$IFDEF UNITVERSIONING} RegisterUnitVersion(HInstance, UnitVersioning); {$ENDIF UNITVERSIONING} finalization {$IFDEF UNITVERSIONING} UnregisterUnitVersion(HInstance); {$ENDIF UNITVERSIONING} FreeAndNil(GlobalStreamFormats); FreeAndNil(GlobalArchiveFormats); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/doublecmd.diff����������������������������������������0000644�0001750�0000144�00000033335�14743153644�023071� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ jcl/source/common/JclCompression.pas | 180 ++++++++++++++++++++++++++++++----- jcl/source/windows/sevenzip.pas | 10 +- 2 files changed, 161 insertions(+), 29 deletions(-) diff --git a/jcl/source/common/JclCompression.pas b/jcl/source/common/JclCompression.pas index e5e6a2f..80889a3 100644 --- a/jcl/source/common/JclCompression.pas +++ b/jcl/source/common/JclCompression.pas @@ -44,8 +44,7 @@ unit JclCompression; -{$I jcl.inc} -{$I crossplatform.inc} +{$mode delphi} interface @@ -75,7 +74,10 @@ uses ZLib, {$ENDIF ZLIB_RTL} {$ENDIF ~HAS_UNITSCOPE} - zlibh, bzip2, JclWideStrings, JclBase, JclStreams; + {$IFNDEF FPC} + zlibh, bzip2, + {$ENDIF FPC} + DCJclAlternative; // Must be after Classes, SysUtils, Windows {$IFDEF RTL230_UP} {$HPPEMIT '// To avoid ambiguity with System::Zlib::z_stream_s we force using ours'} @@ -180,6 +182,9 @@ uses **************************************************************************************************} type + +{$IFNDEF FPC} + TJclCompressionStream = class(TJclStream) private FOnProgress: TNotifyEvent; @@ -562,8 +567,12 @@ type function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; +{$ENDIF FPC} + EJclCompressionError = class(EJclError); +{$IFNDEF FPC} + // callback type used in helper functions below: TJclCompressStreamProgressCallback = procedure(FileSize, Position: Int64; UserData: Pointer) of object; @@ -586,6 +595,8 @@ procedure BZip2Stream(SourceStream, DestinationStream: TStream; CompressionLevel procedure UnBZip2Stream(SourceStream, DestinationStream: TStream; ProgressCallback: TJclCompressStreamProgressCallback = nil; UserData: Pointer = nil); +{$ENDIF FPC} + // archive ancestor classes {$IFDEF MSWINDOWS} type @@ -595,6 +606,7 @@ type var AVolumeMaxSize: Int64) of object; TJclCompressionProgressEvent = procedure(Sender: TObject; const Value, MaxValue: Int64) of object; TJclCompressionRatioEvent = procedure(Sender: TObject; const InSize, OutSize: Int64) of object; + TJclCompressionPasswordEvent = procedure(Sender: TObject; var Password: WideString) of object; TJclCompressionItemProperty = (ipPackedName, ipPackedSize, ipPackedExtension, ipFileSize, ipFileName, ipAttributes, ipCreationTime, ipLastAccessTime, @@ -770,6 +782,7 @@ type FOnRatio: TJclCompressionRatioEvent; FOnVolume: TJclCompressionVolumeEvent; FOnVolumeMaxSize: TJclCompressionVolumeMaxSizeEvent; + FOnPassword: TJclCompressionPasswordEvent; FPassword: WideString; FVolumeIndex: Integer; FVolumeIndexOffset: Integer; @@ -803,6 +816,9 @@ type // function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; + public + PropNames: array of WideString; + PropValues: array of TPropVariant; public class function MultipleItemContainer: Boolean; virtual; class function VolumeAccess: TJclStreamAccess; virtual; @@ -855,6 +871,7 @@ type property OnVolume: TJclCompressionVolumeEvent read FOnVolume write FOnVolume; property OnVolumeMaxSize: TJclCompressionVolumeMaxSizeEvent read FOnVolumeMaxSize write FOnVolumeMaxSize; + property OnPassword: TJclCompressionPasswordEvent read FOnPassword write FOnPassword; property Password: WideString read FPassword write FPassword; property SupportsNestedArchive: Boolean read GetSupportsNestedArchive; @@ -1193,6 +1210,7 @@ function GetArchiveFormats: TJclCompressionArchiveFormats; type TJclSevenzipCompressArchive = class(TJclCompressArchive, IInterface) private + FSfxModule: String; FOutArchive: IOutArchive; protected function GetItemClass: TJclCompressionItemClass; override; @@ -1203,6 +1221,7 @@ type destructor Destroy; override; procedure Compress; override; property OutArchive: IOutArchive read GetOutArchive; + property SfxModule: String read FSfxModule write FSfxModule; end; // file formats @@ -2189,6 +2208,9 @@ function Create7zFile(const SourceFile, DestinationFile: TFileName; VolumeSize: OnArchiveProgress: TJclCompressionProgressEvent = nil; OnArchiveRatio: TJclCompressionRatioEvent = nil): Boolean; overload; +var + JclCompressSharedFiles: Boolean = False; + {$ENDIF MSWINDOWS} {$IFDEF UNITVERSIONING} @@ -2206,8 +2228,7 @@ const implementation uses - JclUnicode, // WideSameText - JclDateTime, JclFileUtils, JclResources, JclStrings, JclSysUtils; + DCJclResources, DCJclCompression; const JclDefaultBufferSize = 131072; // 128k @@ -2218,6 +2239,8 @@ var GlobalStreamFormats: TObject; GlobalArchiveFormats: TObject; +{$IFNDEF FPC} + //=== { TJclCompressionStream } ============================================== constructor TJclCompressionStream.Create(AStream: TStream); @@ -3743,6 +3766,8 @@ begin end; end; +{$ENDIF FPC} + {$IFDEF MSWINDOWS} function OpenFileStream(const FileName: TFileName; StreamAccess: TJclStreamAccess): TStream; @@ -3887,7 +3912,7 @@ end; function TJclCompressionItem.GetNestedArchiveName: WideString; var ParentArchiveExtension, ArchiveFileName, ArchiveExtension: WideString; - ExtensionMap: TJclWideStrings; + ExtensionMap: TStrings; begin if ipPackedName in ValidProperties then Result := PackedName @@ -3914,7 +3939,7 @@ begin else if ArchiveFileName <> '' then begin - ExtensionMap := TJclWideStringList.Create; + ExtensionMap := TStringList.Create; try ExtensionMap.Delimiter := ';'; ExtensionMap.DelimitedText := Archive.ArchiveSubExtensions; @@ -3962,9 +3987,16 @@ begin end; function TJclCompressionItem.GetStream: TStream; +var + AItemAccess: TJclStreamAccess; begin if not Assigned(FStream) and (FileName <> '') then - FStream := OpenFileStream(FileName, Archive.ItemAccess); + begin + AItemAccess:= Archive.ItemAccess; + if (AItemAccess = saReadOnly) and JclCompressSharedFiles then + AItemAccess:= saReadOnlyDenyNone; + FStream := OpenFileStream(FileName, AItemAccess); + end; Result := FStream; end; @@ -5544,6 +5576,18 @@ begin end; if not AllHandled then raise EJclCompressionError.CreateRes(@RsCompressionReplaceError); + end + else begin + // Remove temporary files + for Index := 0 to FVolumes.Count - 1 do + begin + AVolume := TJclCompressionVolume(FVolumes.Items[Index]); + if AVolume.OwnsTmpStream then + begin + FreeAndNil(AVolume.FTmpStream); + FileDelete(AVolume.TmpFileName); + end; + end; end; end; @@ -5791,6 +5835,8 @@ begin FItemIndex := AItemIndex; FStream := nil; FOwnsStream := False; + + NeedStream; end; constructor TJclSevenzipInStream.Create(AStream: TStream; AOwnsStream: Boolean); @@ -6117,6 +6163,8 @@ end; procedure SetSevenzipArchiveCompressionProperties(AJclArchive: IInterface; ASevenzipArchive: IInterface); var + Index: Integer; + JclArchive: TJclCompressionArchive; PropertySetter: Sevenzip.ISetProperties; InArchive, OutArchive: Boolean; Unused: IInterface; @@ -6254,9 +6302,18 @@ begin else AddWideStringProperty('S', IntToStr(Solid.SolidBlockSize) + 'F'); end; + + JclArchive := AJclArchive as TJclCompressionArchive; + for Index := Low(JclArchive.PropNames) to High(JclArchive.PropNames) do + begin + AddProperty(PWideChar(JclArchive.PropNames[Index]), JclArchive.PropValues[Index]); + end; end; if Length(PropNames) > 0 then + begin SevenZipCheck(PropertySetter.SetProperties(@PropNames[0], @PropValues[0], Length(PropNames))); + SetLength(JclArchive.PropNames, 0); SetLength(JclArchive.PropValues, 0); + end; end; end; @@ -6510,7 +6567,10 @@ begin // kpidCharacts: ; // kpidVa: ; // kpidId: ; - // kpidShortName: ; + kpidShortName: + begin + Value.vt := VT_EMPTY; + end; // kpidCreatorApp: ; // kpidSectorSize: ; kpidPosixAttrib: @@ -6525,6 +6585,11 @@ begin // kpidLocalName: ; // kpidProvider: ; // kpidUserDefined: ; + kpidIsAltStream: + begin + Value.vt := VT_BOOL; + Value.bool := False; + end; else Value.vt := VT_EMPTY; Result := S_FALSE; @@ -6534,9 +6599,27 @@ end; function TJclSevenzipUpdateCallback.GetStream(Index: Cardinal; out InStream: ISequentialInStream): HRESULT; begin + Result := E_FAIL; FLastStream := Index; - InStream := TJclSevenzipInStream.Create(FArchive, Index); - Result := S_OK; + repeat + try + InStream := TJclSevenzipInStream.Create(FArchive, Index); + Result := S_OK; + except + on E: Exception do + begin + case MessageBox(0, PAnsiChar(E.Message), nil, MB_ABORTRETRYIGNORE or MB_ICONERROR) of + IDABORT: Exit(E_ABORT); + IDIGNORE: + begin + FArchive.Items[Index].OperationSuccess := osNoOperation; + FLastStream := MAXDWORD; + Exit(S_FALSE); + end; + end; + end; + end; + until Result = S_OK; end; function TJclSevenzipUpdateCallback.GetUpdateItemInfo(Index: Cardinal; NewData, @@ -6595,17 +6678,20 @@ end; function TJclSevenzipUpdateCallback.SetOperationResult( OperationResult: Integer): HRESULT; begin - case OperationResult of - kOK: - FArchive.Items[FLastStream].OperationSuccess := osOK; - kUnSupportedMethod: - FArchive.Items[FLastStream].OperationSuccess := osUnsupportedMethod; - kDataError: - FArchive.Items[FLastStream].OperationSuccess := osDataError; - kCRCError: - FArchive.Items[FLastStream].OperationSuccess := osCRCError; - else - FArchive.Items[FLastStream].OperationSuccess := osUnknownError; + if FLastStream < MAXDWORD then + begin + case OperationResult of + kOK: + FArchive.Items[FLastStream].OperationSuccess := osOK; + kUnSupportedMethod: + FArchive.Items[FLastStream].OperationSuccess := osUnsupportedMethod; + kDataError: + FArchive.Items[FLastStream].OperationSuccess := osDataError; + kCRCError: + FArchive.Items[FLastStream].OperationSuccess := osCRCError; + else + FArchive.Items[FLastStream].OperationSuccess := osUnknownError; + end; end; Result := S_OK; @@ -6681,7 +6767,10 @@ end; procedure TJclSevenzipCompressArchive.Compress; var + Value: HRESULT; + Index: Integer; OutStream: IOutStream; + AVolume: TJclCompressionVolume; UpdateCallback: IArchiveUpdateCallback; SplitStream: TJclDynamicSplitStream; begin @@ -6692,12 +6781,32 @@ begin SplitStream := TJclDynamicSplitStream.Create(False); SplitStream.OnVolume := NeedStream; SplitStream.OnVolumeMaxSize := NeedStreamMaxSize; - OutStream := TJclSevenzipOutStream.Create(SplitStream, True, False); + if Length(FSfxModule) > 0 then + OutStream := TSfxSevenzipOutStream.Create(SplitStream, FSfxModule) + else begin + OutStream := TJclSevenzipOutStream.Create(SplitStream, True, False); + end; UpdateCallback := TJclSevenzipUpdateCallback.Create(Self); SetSevenzipArchiveCompressionProperties(Self, OutArchive); - SevenzipCheck(OutArchive.UpdateItems(OutStream, ItemCount, UpdateCallback)); + Value:= OutArchive.UpdateItems(OutStream, ItemCount, UpdateCallback); + + if Value <> S_OK then + begin + // Remove partial archives + for Index := 0 to FVolumes.Count - 1 do + begin + AVolume := TJclCompressionVolume(FVolumes.Items[Index]); + if AVolume.OwnsStream then + begin + FreeAndNil(AVolume.FStream); + FileDelete(AVolume.FileName); + end; + end; + end; + + SevenzipCheck(Value); finally FCompressing := False; // release volumes and other finalizations @@ -7422,7 +7531,14 @@ function TJclSevenzipOpenCallback.CryptoGetTextPassword( password: PBStr): HRESULT; begin if Assigned(password) then + begin + if Length(FArchive.FPassword) = 0 then + begin + if Assigned(FArchive.OnPassword) then + FArchive.OnPassword(FArchive, FArchive.FPassword); + end; password^ := SysAllocString(PWideChar(FArchive.Password)); + end; Result := S_OK; end; @@ -7456,7 +7572,14 @@ function TJclSevenzipExtractCallback.CryptoGetTextPassword( password: PBStr): HRESULT; begin if Assigned(password) then + begin + if Length(FArchive.FPassword) = 0 then + begin + if Assigned(FArchive.OnPassword) then + FArchive.OnPassword(FArchive, FArchive.FPassword); + end; password^ := SysAllocString(PWideChar(FArchive.Password)); + end; Result := S_OK; end; @@ -8807,6 +8930,7 @@ end; procedure TJclSevenzipUpdateArchive.Compress; var + Value: HRESULT; OutStream: IOutStream; UpdateCallback: IArchiveUpdateCallback; SplitStream: TJclDynamicSplitStream; @@ -8824,7 +8948,13 @@ begin SetSevenzipArchiveCompressionProperties(Self, OutArchive); - SevenzipCheck(OutArchive.UpdateItems(OutStream, ItemCount, UpdateCallback)); + Value:= OutArchive.UpdateItems(OutStream, ItemCount, UpdateCallback); + + if Value <> S_OK then + begin + FReplaceVolumes:= False; + SevenzipCheck(Value); + end; finally FCompressing := False; // release reference to volume streams diff --git a/jcl/source/windows/sevenzip.pas b/jcl/source/windows/sevenzip.pas index 06fb94f..68f4ae2 100644 --- a/jcl/source/windows/sevenzip.pas +++ b/jcl/source/windows/sevenzip.pas @@ -53,10 +53,11 @@ unit sevenzip; +{$mode delphi} + interface -{$I jcl.inc} -{$I windowsonly.inc} +{$DEFINE 7ZIP_LINKONREQUEST} uses {$IFDEF HAS_UNITSCOPE} @@ -67,8 +68,7 @@ uses {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} - JclBase, - JclSysUtils; + DCJclAlternative; //DOM-IGNORE-BEGIN @@ -251,6 +251,8 @@ const kpidPosixAttrib = 53; kpidLink = 54; + kpidIsAltStream = 63; + kpidTotalSize = $1100; kpidFreeSpace = $1101; kpidClusterSize = $1102; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/windows/����������������������������������������������0000755�0001750�0000144�00000000000�14743153644�021764� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/jcl/windows/sevenzip.pas����������������������������������0000644�0001750�0000144�00000101315�14743153644�024335� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{**************************************************************************************************} { } { Project JEDI Code Library (JCL) } { } { interface of the 'sevenzip' (http://sourceforge.net/projects/sevenzip/) compression library } { version 4.62, December 2th, 2008 } { } { Copyright (C) 1999-2008 Igor Pavlov } { } { GNU LGPL information } { -------------------- } { } { This library is free software; you can redistribute it and/or modify it under the terms of } { the GNU Lesser General Public License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; } { without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. } { See the GNU Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public License along with this } { library; if not, write to } { the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { unRAR restriction } { ----------------- } { } { The decompression engine for RAR archives was developed using source code of unRAR program. } { All copyrights to original unRAR code are owned by Alexander Roshal. } { } { The license for original unRAR code has the following restriction: } { } { The unRAR sources cannot be used to re-create the RAR compression algorithm, } { which is proprietary. Distribution of modified unRAR sources in separate form } { or as a part of other software is permitted, provided that it is clearly } { stated in the documentation and source comments that the code may } { not be used to develop a RAR (WinRAR) compatible archiver. } { } {**************************************************************************************************} { } { Translation 2007-2008 Florent Ouchet for the JEDI Code Library } { Contributors: } { Uwe Schuster (uschuster) } { Jan Goyvaerts (jgsoft) } { } {**************************************************************************************************} { } { Last modified: $Date:: $ } { Revision: $Rev:: $ } { Author: $Author:: $ } { } {**************************************************************************************************} unit sevenzip; {$mode delphi} interface {$DEFINE 7ZIP_LINKONREQUEST} uses {$IFDEF HAS_UNITSCOPE} Winapi.ActiveX, Winapi.Windows, {$ELSE ~HAS_UNITSCOPE} ActiveX, Windows, {$ENDIF ~HAS_UNITSCOPE} {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} DCJclAlternative; //DOM-IGNORE-BEGIN // Guid.txt const CLSID_CCodec : TGUID = '{23170F69-40C1-2790-0000-000000000000}'; CLSID_CCodecBCJ2 : TGUID = '{23170F69-40C1-2790-1B01-030300000000}'; // BCJ2 0303011B CLSID_CCodecBCJ : TGUID = '{23170F69-40C1-2790-0301-030300000000}'; // BCJ 03030103 CLSID_CCodecSWAP2 : TGUID = '{23170F69-40C1-2790-0203-030000000000}'; // swap2 020302 CLSID_CCodecSWAP4 : TGUID = '{23170F69-40C1-2790-0403-020000000000}'; // swap4 020304 CLSID_CCodecBPPC : TGUID = '{23170F69-40C1-2790-0502-030300000000}'; // branch ppc 03030205 CLSID_CCodecBIA64 : TGUID = '{23170F69-40C1-2790-0104-030300000000}'; // branch IA64 03030401 CLSID_CCodecBARM : TGUID = '{23170F69-40C1-2790-0105-030300000000}'; // branch ARM 03030501 CLSID_CCodecBARMT : TGUID = '{23170F69-40C1-2790-0107-030300000000}'; // branch ARM Thumb 03030701 CLSID_CCodecBARMS : TGUID = '{23170F69-40C1-2790-0508-030300000000}'; // branch ARM Sparc 03030805 CLSID_CCodecBZIP : TGUID = '{23170F69-40C1-2790-0202-040000000000}'; // bzip2 040202 CLSID_CCodecCOPY : TGUID = '{23170F69-40C1-2790-0000-000000000000}'; // copy 0 CLSID_CCodecDEF64 : TGUID = '{23170F69-40C1-2790-0901-040000000000}'; // deflate64 040109 CLSID_CCodecDEFNSIS : TGUID = '{23170F69-40C1-2790-0109-040000000000}'; // deflate nsis 040901 CLSID_CCodecDEFREG : TGUID = '{23170F69-40C1-2790-0801-040000000000}'; // deflate register 040108 CLSID_CCodecLZMA : TGUID = '{23170F69-40C1-2790-0101-030000000000}'; // lzma 030101 CLSID_CCodecPPMD : TGUID = '{23170F69-40C1-2790-0104-030000000000}'; // ppmd 030401 CLSID_CCodecRAR1 : TGUID = '{23170F69-40C1-2790-0103-040000000000}'; // rar1 040301 CLSID_CCodecRAR2 : TGUID = '{23170F69-40C1-2790-0203-040000000000}'; // rar2 040302 CLSID_CCodecRAR3 : TGUID = '{23170F69-40C1-2790-0303-040000000000}'; // rar3 040303 CLSID_CAESCodec : TGUID = '{23170F69-40C1-2790-0107-F10600000000}'; // AES 06F10701 CLSID_CArchiveHandler : TGUID = '{23170F69-40C1-278A-1000-000110000000}'; CLSID_CFormatZip : TGUID = '{23170F69-40C1-278A-1000-000110010000}'; CLSID_CFormatBZ2 : TGUID = '{23170F69-40C1-278A-1000-000110020000}'; CLSID_CFormatRar : TGUID = '{23170F69-40C1-278A-1000-000110030000}'; CLSID_CFormatArj : TGUID = '{23170F69-40C1-278A-1000-000110040000}'; CLSID_CFormatZ : TGUID = '{23170F69-40C1-278A-1000-000110050000}'; CLSID_CFormatLzh : TGUID = '{23170F69-40C1-278A-1000-000110060000}'; CLSID_CFormat7z : TGUID = '{23170F69-40C1-278A-1000-000110070000}'; CLSID_CFormatCab : TGUID = '{23170F69-40C1-278A-1000-000110080000}'; CLSID_CFormatNsis : TGUID = '{23170F69-40C1-278A-1000-000110090000}'; CLSID_CFormatLzma : TGUID = '{23170F69-40C1-278A-1000-0001100A0000}'; CLSID_CFormatLzma86 : TGUID = '{23170F69-40C1-278A-1000-0001100B0000}'; CLSID_CFormatXz : TGUID = '{23170F69-40C1-278A-1000-0001100C0000}'; CLSID_CFormatPpmd : TGUID = '{23170F69-40C1-278A-1000-0001100D0000}'; CLSID_CFormatTE : TGUID = '{23170F69-40C1-278A-1000-000110CF0000}'; CLSID_CFormatUEFIc : TGUID = '{23170F69-40C1-278A-1000-000110D00000}'; CLSID_CFormatUEFIs : TGUID = '{23170F69-40C1-278A-1000-000110D10000}'; CLSID_CFormatSquashFS : TGUID = '{23170F69-40C1-278A-1000-000110D20000}'; CLSID_CFormatCramFS : TGUID = '{23170F69-40C1-278A-1000-000110D30000}'; CLSID_CFormatAPM : TGUID = '{23170F69-40C1-278A-1000-000110D40000}'; CLSID_CFormatMslz : TGUID = '{23170F69-40C1-278A-1000-000110D50000}'; CLSID_CFormatFlv : TGUID = '{23170F69-40C1-278A-1000-000110D60000}'; CLSID_CFormatSwf : TGUID = '{23170F69-40C1-278A-1000-000110D70000}'; CLSID_CFormatSwfc : TGUID = '{23170F69-40C1-278A-1000-000110D80000}'; CLSID_CFormatNtfs : TGUID = '{23170F69-40C1-278A-1000-000110D90000}'; CLSID_CFormatFat : TGUID = '{23170F69-40C1-278A-1000-000110DA0000}'; CLSID_CFormatMbr : TGUID = '{23170F69-40C1-278A-1000-000110DB0000}'; CLSID_CFormatVhd : TGUID = '{23170F69-40C1-278A-1000-000110DC0000}'; CLSID_CFormatPe : TGUID = '{23170F69-40C1-278A-1000-000110DD0000}'; CLSID_CFormatElf : TGUID = '{23170F69-40C1-278A-1000-000110DE0000}'; CLSID_CFormatMacho : TGUID = '{23170F69-40C1-278A-1000-000110DF0000}'; CLSID_CFormatUdf : TGUID = '{23170F69-40C1-278A-1000-000110E00000}'; CLSID_CFormatXar : TGUID = '{23170F69-40C1-278A-1000-000110E10000}'; CLSID_CFormatMub : TGUID = '{23170F69-40C1-278A-1000-000110E20000}'; CLSID_CFormatHfs : TGUID = '{23170F69-40C1-278A-1000-000110E30000}'; CLSID_CFormatDmg : TGUID = '{23170F69-40C1-278A-1000-000110E40000}'; CLSID_CFormatCompound : TGUID = '{23170F69-40C1-278A-1000-000110E50000}'; CLSID_CFormatWim : TGUID = '{23170F69-40C1-278A-1000-000110E60000}'; CLSID_CFormatIso : TGUID = '{23170F69-40C1-278A-1000-000110E70000}'; //CLSID_CFormatBkf : TGUID = '{23170F69-40C1-278A-1000-000110E80000}'; not in 4.57 CLSID_CFormatChm : TGUID = '{23170F69-40C1-278A-1000-000110E90000}'; CLSID_CFormatSplit : TGUID = '{23170F69-40C1-278A-1000-000110EA0000}'; CLSID_CFormatRpm : TGUID = '{23170F69-40C1-278A-1000-000110EB0000}'; CLSID_CFormatDeb : TGUID = '{23170F69-40C1-278A-1000-000110EC0000}'; CLSID_CFormatCpio : TGUID = '{23170F69-40C1-278A-1000-000110ED0000}'; CLSID_CFormatTar : TGUID = '{23170F69-40C1-278A-1000-000110EE0000}'; CLSID_CFormatGZip : TGUID = '{23170F69-40C1-278A-1000-000110EF0000}'; // IStream.h type // "23170F69-40C1-278A-0000-000300xx0000" ISequentialInStream = interface(IUnknown) ['{23170F69-40C1-278A-0000-000300010000}'] function Read(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; stdcall; {Out: if size != 0, return_value = S_OK and (*processedSize == 0), then there are no more bytes in stream. if (size > 0) && there are bytes in stream, this function must read at least 1 byte. This function is allowed to read less than number of remaining bytes in stream. You must call Read function in loop, if you need exact amount of data} end; ISequentialOutStream = interface(IUnknown) ['{23170F69-40C1-278A-0000-000300020000}'] function Write(Data: Pointer; Size: Cardinal; ProcessedSize: PCardinal): HRESULT; stdcall; {if (size > 0) this function must write at least 1 byte. This function is allowed to write less than "size". You must call Write function in loop, if you need to write exact amount of data} end; IInStream = interface(ISequentialInStream) ['{23170F69-40C1-278A-0000-000300030000}'] function Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; stdcall; end; IOutStream = interface(ISequentialOutStream) ['{23170F69-40C1-278A-0000-000300040000}'] function Seek(Offset: Int64; SeekOrigin: Cardinal; NewPosition: PInt64): HRESULT; stdcall; function SetSize(NewSize: Int64): HRESULT; stdcall; end; IStreamGetSize = interface(IUnknown) ['{23170F69-40C1-278A-0000-000300060000}'] function GetSize(Size: PInt64): HRESULT; stdcall; end; IOutStreamFlush = interface(IUnknown) ['{23170F69-40C1-278A-0000-000300070000}'] function Flush: HRESULT; stdcall; end; // PropID.h const kpidNoProperty = 0; kpidMainSubfile = 1; kpidHandlerItemIndex = 2; kpidPath = 3; kpidName = 4; kpidExtension = 5; kpidIsFolder = 6 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kpidIsDir' {$ENDIF} {$ENDIF}; kpidIsDir = 6; kpidSize = 7; kpidPackedSize = 8 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kpidPackSize' {$ENDIF} {$ENDIF}; kpidPackSize = 8; kpidAttributes = 9 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kpidAttrib' {$ENDIF} {$ENDIF}; kpidAttrib = 9; kpidCreationTime = 10 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kpidCTime' {$ENDIF} {$ENDIF}; kpidCTime = 10; kpidLastAccessTime = 11 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kpidATime' {$ENDIF} {$ENDIF}; kpidATime = 11; kpidLastWriteTime = 12 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kpidMTime' {$ENDIF} {$ENDIF}; kpidMTime = 12; kpidSolid = 13; kpidCommented = 14; kpidEncrypted = 15; kpidSplitBefore = 16; kpidSplitAfter = 17; kpidDictionarySize = 18; kpidCRC = 19; kpidType = 20; kpidIsAnti = 21; kpidMethod = 22; kpidHostOS = 23; kpidFileSystem = 24; kpidUser = 25; kpidGroup = 26; kpidBlock = 27; kpidComment = 28; kpidPosition = 29; kpidPrefix = 30; kpidNumSubDirs = 31; kpidNumSubFiles = 32; kpidUnpackVer = 33; kpidVolume = 34; kpidIsVolume = 35; kpidOffset = 36; kpidLinks = 37; kpidNumBlocks = 38; kpidNumVolumes = 39; kpidTimeType = 40; kpidBit64 = 41; kpidBigEndian = 42; kpidCpu = 43; kpidPhySize = 44; kpidHeadersSize = 45; kpidChecksum = 46; kpidCharacts = 47; kpidVa = 48; kpidId = 49; kpidShortName = 50; kpidCreatorApp = 51; kpidSectorSize = 52; kpidPosixAttrib = 53; kpidLink = 54; kpidIsAltStream = 63; kpidTotalSize = $1100; kpidFreeSpace = $1101; kpidClusterSize = $1102; kpidVolumeName = $1103; kpidLocalName = $1200; kpidProvider = $1201; kpidUserDefined = $10000; // HandlerOut.cpp kCopyMethodName = WideString('Copy'); kLZMAMethodName = WideString('LZMA'); kLZMA2MethodName = WideString('LZMA2'); kBZip2MethodName = WideString('BZip2'); kPpmdMethodName = WideString('PPMd'); kDeflateMethodName = WideString('Deflate'); kDeflate64MethodName = WideString('Deflate64'); kAES128MethodName = WideString('AES128'); kAES192MethodName = WideString('AES192'); kAES256MethodName = WideString('AES256'); kZipCryptoMethodName = WideString('ZIPCRYPTO'); // ICoder.h type ICompressProgressInfo = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400040000}'] function SetRatioInfo(InSize: PInt64; OutSize: PInt64): HRESULT; stdcall; end; ICompressCoder = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400050000}'] function Code(InStream: ISequentialInStream; OutStream: ISequentialOutStream; InSize, OutSize: PInt64; Progress: ICompressProgressInfo): HRESULT; stdcall; end; PISequentialInStream = ^ISequentialInStream; PISequentialOutStream = ^ISequentialOutStream; ICompressCoder2 = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400180000}'] function Code(InStreams: PISequentialInStream; InSizes: JclBase.PPInt64; NumInStreams: Cardinal; OutStreams: PISequentialOutStream; OutSizes: JclBase.PPInt64; NumOutStreams: Cardinal; Progress: ICompressProgressInfo): HRESULT; stdcall; end; const kDictionarySize = $400; kUsedMemorySize = $401; kOrder = $402; kBlockSize = $403; kPosStateBits = $440; kLitContextBits = $441; kLitPosBits = $442; kNumFastBytes = $450; kMatchFinder = $451; kMatchFinderCycles = $452; kNumPasses = $460; kAlgorithm = $470; kMultiThread = $480; kNumThreads = $481; kEndMarker = $490; type ICompressSetCoderProperties = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400200000}'] function SetCoderProperties(PropIDs: PPropID; Properties: PPropVariant; NumProperties: Cardinal): HRESULT; stdcall; end; ICompressSetDecoderProperties2 = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400220000}'] function SetDecoderProperties2(Data: PByte; Size: Cardinal): HRESULT; stdcall; end; ICompressWriteCoderProperties = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400230000}'] function WriteCoderProperties(OutStream: ISequentialOutStream): HRESULT; stdcall; end; ICompressGetInStreamProcessedSize = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400240000}'] function GetInStreamProcessedSize(Value: PInt64): HRESULT; stdcall; end; ICompressSetCoderMt = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400250000}'] function SetNumberOfThreads(NumThreads: Cardinal): HRESULT; stdcall; end; ICompressGetSubStreamSize = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400300000}'] function GetSubStreamSize(SubStream: Int64; out Value: Int64): HRESULT; stdcall; end; ICompressSetInStream = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400310000}'] function SetInStream(InStream: ISequentialInStream): HRESULT; stdcall; function ReleaseInStream: HRESULT; stdcall; end; ICompressSetOutStream = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400320000}'] function SetOutStream(OutStream: ISequentialOutStream): HRESULT; stdcall; function ReleaseOutStream: HRESULT; stdcall; end; ICompressSetInStreamSize = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400330000}'] function SetInStreamSize(InSize: PInt64): HRESULT; stdcall; end; ICompressSetOutStreamSize = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400340000}'] function SetOutStreamSize(OutSize: PInt64): HRESULT; stdcall; end; ICompressFilter = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400400000}'] function Init: HRESULT; stdcall; function Filter(Data: PByte; Size: Cardinal): Cardinal; stdcall; // Filter return outSize (UInt32) // if (outSize <= size): Filter have converted outSize bytes // if (outSize > size): Filter have not converted anything. // and it needs at least outSize bytes to convert one block // (it's for crypto block algorithms). end; ICompressCodecsInfo = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400600000}'] function GetNumberOfMethods(NumMethods: PCardinal): HRESULT; stdcall; function GetProperty(Index: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function CreateDecoder(Index: Cardinal; IID: PGUID; out Decoder): HRESULT; stdcall; function CreateEncoder(Index: Cardinal; IID: PGUID; out Coder): HRESULT; stdcall; end; ISetCompressCodecsInfo = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400610000}'] function SetCompressCodecsInfo(CompressCodecsInfo: ICompressCodecsInfo): HRESULT; stdcall; end; ICryptoProperties = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400800000}'] function SetKey(Data: PByte; Size: Cardinal): HRESULT; stdcall; function SetInitVector(Data: PByte; Size: Cardinal): HRESULT; stdcall; end; ICryptoSetPassword = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400900000}'] function CryptoSetPassword(Data: PByte; Size: Cardinal): HRESULT; stdcall; end; ICryptoSetCRC = interface(IUnknown) ['{23170F69-40C1-278A-0000-000400A00000}'] function CryptoSetCRC(crc: Cardinal): HRESULT; stdcall; end; const kID = 0; kName = 1; kDecoder = 2; kEncoder = 3; kInStreams = 4; kOutStreams = 5; kDescription = 6; kDecoderIsAssigned = 7; kEncoderIsAssigned = 8; // IProgress.h type IProgress = interface(IUnknown) ['{23170F69-40C1-278A-0000-000000050000}'] function SetTotal(Total: Int64): HRESULT; stdcall; function SetCompleted(CompleteValue: PInt64): HRESULT; stdcall; end; // IArchive.h const // file time type kWindows = 0; kUnix = 1; kDOS = 2; // archive kArchiveName = 0; kClassID = 1; kExtension = 2; kAddExtension = 3; kUpdate = 4; kKeepName = 5; kStartSignature = 6; kFinishSignature = 7; kAssociate = 8; // ask mode kExtract = 0; kTest = 1; kSkip = 2; // operation result kOK = 0; kUnSupportedMethod = 1; kDataError = 2; kCRCError = 3; kError = 1; type // "23170F69-40C1-278A-0000-000600xx0000" IArchiveOpenCallback = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600100000}'] function SetTotal(Files: PInt64; Bytes: PInt64): HRESULT; stdcall; function SetCompleted(Files: PInt64; Bytes: PInt64): HRESULT; stdcall; end; IArchiveExtractCallback = interface(IProgress) ['{23170F69-40C1-278A-0000-000600200000}'] function GetStream(Index: Cardinal; out OutStream: ISequentialOutStream; askExtractMode: Cardinal): HRESULT; stdcall; // GetStream OUT: S_OK - OK, S_FALSE - skeep this file function PrepareOperation(askExtractMode: Cardinal): HRESULT; stdcall; function SetOperationResult(resultEOperationResult: Integer): HRESULT; stdcall; end; IArchiveOpenVolumeCallback = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600300000}'] function GetProperty(PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function GetStream(Name: PWideChar; out InStream: IInStream): HRESULT; stdcall; end; IInArchiveGetStream = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600400000}'] function GetStream(Index: Cardinal; out Stream: ISequentialInStream): HRESULT; stdcall; end; IArchiveOpenSetSubArchiveName = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600500000}'] function SetSubArchiveName(Name: PWideChar): HRESULT; stdcall; end; IInArchive = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600600000}'] function Open(Stream: IInStream; MaxCheckStartPosition: PInt64; OpenArchiveCallback: IArchiveOpenCallback): HRESULT; stdcall; function Close: HRESULT; stdcall; function GetNumberOfItems(NumItems: PCardinal): HRESULT; stdcall; function GetProperty(Index: Cardinal; PropID: TPropID; var Value: TPropVariant): HRESULT; stdcall; function Extract(Indices: PCardinal; NumItems: Cardinal; TestMode: Integer; ExtractCallback: IArchiveExtractCallback): HRESULT; stdcall; // indices must be sorted // numItems = 0xFFFFFFFF means all files // testMode != 0 means "test files operation" function GetArchiveProperty(PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function GetNumberOfProperties(NumProperties: PCardinal): HRESULT; stdcall; function GetPropertyInfo(Index: Cardinal; out Name: TBStr; out PropID: TPropID; out VarType: TVarType): HRESULT; stdcall; function GetNumberOfArchiveProperties(NumProperties: PCardinal): HRESULT; stdcall; function GetArchivePropertyInfo(Index: Cardinal; out Name: TBStr; out PropID: TPropID; out VarType: TVarType): HRESULT; stdcall; end; IArchiveUpdateCallback = interface(IProgress) ['{23170F69-40C1-278A-0000-000600800000}'] function GetUpdateItemInfo(Index: Cardinal; NewData: PInteger; // 1 - new data, 0 - old data NewProperties: PInteger; // 1 - new properties, 0 - old properties IndexInArchive: PCardinal // -1 if there is no in archive, or if doesn't matter ): HRESULT; stdcall; function GetProperty(Index: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function GetStream(Index: Cardinal; out InStream: ISequentialInStream): HRESULT; stdcall; function SetOperationResult(OperationResult: Integer): HRESULT; stdcall; end; IArchiveUpdateCallback2 = interface(IArchiveUpdateCallback) ['{23170F69-40C1-278A-0000-000600820000}'] function GetVolumeSize(Index: Cardinal; Size: PInt64): HRESULT; stdcall; function GetVolumeStream(Index: Cardinal; out VolumeStream: ISequentialOutStream): HRESULT; stdcall; end; IOutArchive = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600A00000}'] function UpdateItems(OutStream: ISequentialOutStream; NumItems: Cardinal; UpdateCallback: IArchiveUpdateCallback): HRESULT; stdcall; function GetFileTimeType(Type_: PCardinal): HRESULT; stdcall; end; ISetProperties = interface(IUnknown) ['{23170F69-40C1-278A-0000-000600030000}'] function SetProperties(Names: PPWideChar; Values: PPropVariant; NumProperties: Integer): HRESULT; stdcall; end; // IPassword.h type ICryptoGetTextPassword = interface(IUnknown) ['{23170F69-40C1-278A-0000-000500100000}'] function CryptoGetTextPassword(password: PBStr): HRESULT; stdcall; end; ICryptoGetTextPassword2 = interface(IUnknown) ['{23170F69-40C1-278A-0000-000500110000}'] function CryptoGetTextPassword2(PasswordIsDefined: PInteger; Password: PBStr): HRESULT; stdcall; end; // ZipHandlerOut.cpp const kDeflateAlgoX1 = 0 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kLzAlgoX1' {$ENDIF} {$ENDIF}; kLzAlgoX1 = 0; kDeflateAlgoX5 = 1 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kLzAlgoX5' {$ENDIF} {$ENDIF}; kLzAlgoX5 = 1; kDeflateNumPassesX1 = 1; kDeflateNumPassesX7 = 3; kDeflateNumPassesX9 = 10; kNumFastBytesX1 = 32 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kDeflateNumFastBytesX1' {$ENDIF} {$ENDIF}; kDeflateNumFastBytesX1 = 32; kNumFastBytesX7 = 64 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kDeflateNumFastBytesX7' {$ENDIF} {$ENDIF}; kDeflateNumFastBytesX7 = 64; kNumFastBytesX9 = 128 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kDeflateNumFastBytesX9' {$ENDIF} {$ENDIF}; kDeflateNumFastBytesX9 = 128; kLzmaNumFastBytesX1 = 32; kLzmaNumFastBytesX7 = 64; kBZip2NumPassesX1 = 1; kBZip2NumPassesX7 = 2; kBZip2NumPassesX9 = 7; kBZip2DicSizeX1 = 100000; kBZip2DicSizeX3 = 500000; kBZip2DicSizeX5 = 900000; // HandlerOut.cpp const kLzmaAlgoX1 = 0; kLzmaAlgoX5 = 1; kLzmaDicSizeX1 = 1 shl 16; kLzmaDicSizeX3 = 1 shl 20; kLzmaDicSizeX5 = 1 shl 24; kLzmaDicSizeX7 = 1 shl 25; kLzmaDicSizeX9 = 1 shl 26; kLzmaFastBytesX1 = 32; kLzmaFastBytesX7 = 64; kPpmdMemSizeX1 = (1 shl 22); kPpmdMemSizeX5 = (1 shl 24); kPpmdMemSizeX7 = (1 shl 26); kPpmdMemSizeX9 = (192 shl 20); kPpmdOrderX1 = 4; kPpmdOrderX5 = 6; kPpmdOrderX7 = 16; kPpmdOrderX9 = 32; kDeflateFastBytesX1 = 32; kDeflateFastBytesX7 = 64; kDeflateFastBytesX9 = 128; {$IFDEF 7ZIP_LINKONREQUEST} type TCreateObjectFunc = function (ClsID: PGUID; IID: PGUID; out Obj): HRESULT; stdcall; TGetHandlerProperty2 = function (FormatIndex: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; TGetHandlerProperty = function (PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; TGetMethodProperty = function (CodecIndex: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; TGetNumberOfFormatsFunc = function (NumFormats: PCardinal): HRESULT; stdcall; TGetNumberOfMethodsFunc = function (NumMethods: PCardinal): HRESULT; stdcall; TSetLargePageMode = function: HRESULT; stdcall; var CreateObject: TCreateObjectFunc = nil; GetHandlerProperty2: TGetHandlerProperty2 = nil; GetHandlerProperty: TGetHandlerProperty = nil; GetMethodProperty: TGetMethodProperty = nil; GetNumberOfFormats: TGetNumberOfFormatsFunc = nil; GetNumberOfMethods: TGetNumberOfMethodsFunc = nil; SetLargePageMode: TSetLargePageMode = nil; {$ELSE ~7ZIP_LINKONREQUEST} function CreateObject(ClsID: PGUID; IID: PGUID; out Obj): HRESULT; stdcall; function GetHandlerProperty2(FormatIndex: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function GetHandlerProperty(PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function GetMethodProperty(CodecIndex: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; stdcall; function GetNumberOfFormats(NumFormats: PCardinal): HRESULT; stdcall; function GetNumberOfMethods(NumMethods: PCardinal): HRESULT; stdcall; function SetLargePageMode: HRESULT; stdcall; {$ENDIF ~7ZIP_LINKONREQUEST} //DOM-IGNORE-END const SevenzipDefaultLibraryName = '7z.dll'; CreateObjectDefaultExportName = 'CreateObject'; GetHandlerProperty2DefaultExportName = 'GetHandlerProperty2'; GetHandlerPropertyDefaultExportName = 'GetHandlerProperty'; GetMethodPropertyDefaultExportName = 'GetMethodProperty'; GetNumberOfFormatsDefaultExportName = 'GetNumberOfFormats'; GetNumberOfMethodsDefaultExportName = 'GetNumberOfMethods'; SetLargePageModeDefaultExportName = 'SetLargePageMode'; {$IFDEF 7ZIP_LINKONREQUEST} var SevenzipLibraryName: string = SevenzipDefaultLibraryName; CreateObjectExportName: string = CreateObjectDefaultExportName; GetHandlerProperty2ExportName: string = GetHandlerProperty2DefaultExportName; GetHandlerPropertyExportName: string = GetHandlerPropertyDefaultExportName; GetMethodPropertyExportName: string = GetMethodPropertyDefaultExportName; GetNumberOfFormatsExportName: string = GetNumberOfFormatsDefaultExportName; GetNumberOfMethodsExportName: string = GetNumberOfMethodsDefaultExportName; SetLargePageModeExportName: string = SetLargePageModeDefaultExportName; SevenzipLibraryHandle: TModuleHandle = INVALID_MODULEHANDLE_VALUE; {$ENDIF 7ZIP_LINKONREQUEST} function Load7Zip: Boolean; function Is7ZipLoaded: Boolean; procedure Unload7Zip; {$IFDEF UNITVERSIONING} const UnitVersioning: TUnitVersionInfo = ( RCSfile: '$URL$'; Revision: '$Revision$'; Date: '$Date$'; LogPath: 'JCL\source\windows'; Extra: ''; Data: nil ); {$ENDIF UNITVERSIONING} implementation {$IFDEF 7ZIP_LINKDLL} function CreateObject; external SevenzipDefaultLibraryName name CreateObjectDefaultExportName; function GetHandlerProperty2; external SevenzipDefaultLibraryName name GetHandlerProperty2DefaultExportName; function GetHandlerProperty; external SevenzipDefaultLibraryName name GetHandlerPropertyDefaultExportName; function GetMethodProperty; external SevenzipDefaultLibraryName name GetMethodPropertyDefaultExportName; function GetNumberOfFormats; external SevenzipDefaultLibraryName name GetNumberOfFormatsDefaultExportName; function GetNumberOfMethods; external SevenzipDefaultLibraryName name GetNumberOfMethodsDefaultExportName; function SetLargePageMode; external SevenzipDefaultLibraryName name SetLargePageModeDefaultExportName; {$ENDIF 7ZIP_LINKDLL} function Load7Zip: Boolean; {$IFDEF 7ZIP_LINKONREQUEST} begin Result := SevenzipLibraryHandle <> INVALID_MODULEHANDLE_VALUE; if Result then Exit; Result := JclSysUtils.LoadModule(SevenzipLibraryHandle, SevenzipLibraryName); if Result then begin @CreateObject := GetModuleSymbol(SevenzipLibraryHandle, CreateObjectExportName); @GetHandlerProperty2 := GetModuleSymbol(SevenzipLibraryHandle, GetHandlerProperty2ExportName); @GetHandlerProperty := GetModuleSymbol(SevenzipLibraryHandle, GetHandlerPropertyExportName); @GetMethodProperty := GetModuleSymbol(SevenzipLibraryHandle, GetMethodPropertyExportName); @GetNumberOfFormats := GetModuleSymbol(SevenzipLibraryHandle, GetNumberOfFormatsExportName); @GetNumberOfMethods := GetModuleSymbol(SevenzipLibraryHandle, GetNumberOfMethodsExportName); @SetLargePageMode := GetModuleSymbol(SevenzipLibraryHandle, SetLargePageModeExportName); Result := Assigned(@CreateObject) and Assigned(@GetHandlerProperty2) and Assigned(@GetHandlerProperty) and Assigned(@GetMethodProperty) and Assigned(@GetNumberOfFormats) and Assigned(@GetNumberOfMethods) and Assigned(@SetLargePageMode); end; end; {$ELSE ~7ZIP_LINKONREQUEST} begin Result := True; end; {$ENDIF ~7ZIP_LINKONREQUEST} function Is7ZipLoaded: Boolean; begin {$IFDEF 7ZIP_LINKONREQUEST} Result := SevenzipLibraryHandle <> INVALID_MODULEHANDLE_VALUE; {$ELSE ~7ZIP_LINKONREQUEST} Result := True; {$ENDIF ~7ZIP_LINKONREQUEST} end; procedure Unload7Zip; begin {$IFDEF 7ZIP_LINKONREQUEST} @CreateObject := nil; @GetHandlerProperty2 := nil; @GetHandlerProperty := nil; @GetMethodProperty := nil; @GetNumberOfFormats := nil; @GetNumberOfMethods := nil; @SetLargePageMode := nil; JclSysUtils.UnloadModule(SevenzipLibraryHandle); {$ENDIF 7ZIP_LINKONREQUEST} end; {$IFDEF UNITVERSIONING} initialization RegisterUnitVersion(HInstance, UnitVersioning); finalization UnregisterUnitVersion(HInstance); {$ENDIF UNITVERSIONING} end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/platform/�������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�021346� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/sevenzip/src/platform/sevenziphlp.pas����������������������������������0000644�0001750�0000144�00000001152�14743153644�024421� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit SevenZipHlp; {$mode delphi} interface uses Classes, SysUtils, ActiveX; procedure VarStringClear(var PropVariant: TPropVariant); function BinaryToUnicode(const bstrVal: TBstr): UnicodeString; implementation uses Windows; procedure VarStringClear(var PropVariant: TPropVariant); begin PropVariant.vt:= VT_EMPTY; SysFreeString(PropVariant.bstrVal); end; function BinaryToUnicode(const bstrVal: TBstr): UnicodeString; var PropSize: Cardinal; begin PropSize:= SysStringByteLen(bstrVal); SetLength(Result, PropSize div SizeOf(WideChar)); Move(bstrVal^, PWideChar(Result)^, PropSize); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016565� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/COPYING.txt����������������������������������������������������0000644�0001750�0000144�00000064505�14743153644�020450� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. (This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.) Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. {signature of Ty Coon}, 1 April 1990 Ty Coon, President of Vice That's all there is to it! �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/src/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017354� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/src/BDecode.pas������������������������������������������������0000644�0001750�0000144�00000007535�14743153644�021360� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit BDecode; {====================================================================== BDecode.pas -- BitTorrent BDecoding Routines Original Coding by Knowbuddy, 2003-03-19 ======================================================================} interface uses SysUtils, Classes, Hashes, Contnrs; type TISType = (tisString = 0, tisInt); TIntString = class(TObject) public StringPart: String; IntPart: Int64; ISType: TISType; end; function bdecodeStream(s: TStream): TObject; function bdecodeInt64(s: TStream): TIntString; function bdecodeHash(s: TStream): TObjectHash; function bdecodeString(s: TStream; i: Integer = 0): TIntString; function bdecodeList(s: TStream): TObjectList; function bin2hex(s: String; m: Integer = 999): String; var hexchars: array[0..15] of Char = '0123456789abcdef'; implementation function bin2hex(s: String; m: Integer = 999): String; var i, j, k, l : Integer; r : array of Char; begin l := Length(s); if(m < l) then l := m; SetLength(r,l * 2); for i := 1 to l do begin j := Ord(s[i]); k := (i - 1) * 2; r[k] := hexchars[j div 16]; r[k+1] := hexchars[j mod 16]; end; bin2hex := String(r); end; function bdecodeStream(s: TStream): TObject; var r: TObject; c: Char; n: Integer; begin n := s.Read(c, 1); if(n > 0) then begin case c of 'd' : r:= bdecodeHash(s); 'l' : r:= bdecodeList(s); 'i' : r:= bdecodeInt64(s); '0'..'9' : r:= bdecodeString(s,StrToInt(c)); else r := nil; end; end else begin r := nil; end; bdecodeStream := r; end; function bdecodeHash(s: TStream): TObjectHash; var r: TObjectHash; o: TObject; n, st: Integer; c: Char; k, l: TIntString; begin r := TObjectHash.Create(); n := s.Read(c, 1); while((n > 0) and (c <> 'e') and (c >= '0') and (c <= '9')) do begin n := StrToInt(c); k := bdecodeString(s, n); if(k <> nil) then begin st := s.Position; o := bdecodeStream(s); if((o <> nil) and (k.StringPart <> '')) then r[k.StringPart] := o; if(k.StringPart = 'pieces') then begin k.StringPart:='pieces'; end; if(k.StringPart = 'info') then begin l := TIntString.Create(); l.IntPart := st; r['_info_start'] := l; l := TIntString.Create(); l.IntPart := s.Position - st; r['_info_length'] := l; end; end; n := s.Read(c, 1); end; if ((c < '0') or (c > '9')) and (c <> 'e') then bdecodeHash:= nil else bdecodeHash := r; end; function bdecodeList(s: TStream): TObjectList; var r: TObjectList; o: TObject; n: Integer; c: Char; begin r := TObjectList.Create(); n := s.Read(c, 1); while((n > 0) and (c <> 'e')) do begin s.Seek(-1, soFromCurrent); o := bdecodeStream(s); if(o <> nil) then r.Add(o); n := s.Read(c, 1); end; bdecodeList := r; end; function bdecodeString(s: TStream; i: Integer = 0): TIntString; var r: TIntString; t: String; c: Char; n: Integer; begin c := '0'; n := s.Read(c, 1); while((n > 0) and (c >= '0') and (c <= '9')) do begin i := (i * 10) + StrToInt(c); n := s.Read(c, 1); end; SetLength(t, i); n:=s.Read(PChar(t)^, i); r := TIntString.Create(); r.StringPart := t; r.ISType := tisString; bdecodeString := r; end; function bdecodeInt64(s: TStream): TIntString; var r: TIntString; i: Int64; c: Char; n: Integer; neg: boolean; begin i := 0; c := '0'; neg:= false; repeat if c='-' then neg:= true else i := (i * 10) + StrToInt(c); n := s.Read(c, 1); until not ((n > 0) and (((c >= '0')and(c <= '9'))or(c = '-'))); if neg then i:=-i; r := TIntString.Create(); r.IntPart := i; r.ISType := tisInt; bdecodeInt64 := r; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/src/Hashes.pas�������������������������������������������������0000644�0001750�0000144�00000043304�14743153644�021300� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Hashes; interface uses SysUtils; const c_HashInitialItemShift = 7; c_HashCompactR = 2; { This many spaces per item. } c_HashCompactM = 100; { Never for less than this number of spaces. } type EHashError = class(Exception); EHashFindError = class(EHashError); EHashIterateError = class(EHashError); EHashInvalidKeyError = class(EHashError); THashRecord = record Hash: Cardinal; ItemIndex: integer; Key: string; end; THashIterator = record ck, cx: integer; end; THash = class protected f_Keys: array of array of THashRecord; f_CurrentItemShift: integer; f_CurrentItemCount: integer; f_CurrentItemMask: integer; f_CurrentItemMaxIdx: integer; f_SpareItems: array of integer; f_NextAllowed: boolean; f_CurrentKey: string; f_AllowCompact: boolean; f_CurrentIterator: THashIterator; procedure FUpdateMasks; procedure FUpdateBuckets; function FFindKey(const Key: string; var k, x: integer): boolean; procedure FSetOrAddKey(const Key: string; ItemIndex: integer); procedure FDeleteIndex(i: integer); virtual; abstract; function FGetItemCount: integer; function FAllocItemIndex: integer; procedure FMoveIndex(oldIndex, newIndex: integer); virtual; abstract; procedure FTrimIndexes(count: integer); virtual; abstract; procedure FClearItems; virtual; abstract; function FIndexMax: integer; virtual; abstract; procedure FAutoCompact; public constructor Create; reintroduce; virtual; function Exists(const Key: string): boolean; procedure Rename(const Key, NewName: string); procedure Delete(const Key: string); procedure Restart; function Next: boolean; function Previous: boolean; function CurrentKey: string; property ItemCount: integer read FGetItemCount; procedure Compact; procedure Clear; property AllowCompact: boolean read f_AllowCompact write f_AllowCompact; property CurrentIterator: THashIterator read f_CurrentIterator write f_CurrentIterator; function NewIterator: THashIterator; end; TStringHash = class(THash) protected f_Items: array of string; procedure FDeleteIndex(i: integer); override; function FGetItem(const Key: string): string; procedure FSetItem(const Key, Value: string); procedure FMoveIndex(oldIndex, newIndex: integer); override; procedure FTrimIndexes(count: integer); override; procedure FClearItems; override; function FIndexMax: integer; override; public property Items[const Key: string]: string read FGetItem write FSetItem; default; end; TIntegerHash = class(THash) protected f_Items: array of integer; procedure FDeleteIndex(i: integer); override; function FGetItem(const Key: string): integer; procedure FSetItem(const Key: string; Value: integer); procedure FMoveIndex(oldIndex, newIndex: integer); override; procedure FTrimIndexes(count: integer); override; procedure FClearItems; override; function FIndexMax: integer; override; public property Items[const Key: string]: integer read FGetItem write FSetItem; default; end; TObjectHash = class(THash) protected f_Items: array of TObject; procedure FDeleteIndex(i: integer); override; function FGetItem(const Key: string): TObject; procedure FSetItem(const Key: string; Value: TObject); procedure FMoveIndex(oldIndex, newIndex: integer); override; procedure FTrimIndexes(count: integer); override; procedure FClearItems; override; function FIndexMax: integer; override; public property Items[const Key: string]: TObject read FGetItem write FSetItem; default; destructor Destroy; override; end; implementation function HashThis(const s: string): cardinal; var h, g, i: cardinal; begin if (s = '') then raise EHashInvalidKeyError.Create('Key cannot be an empty string'); h := $12345670; for i := 1 to Length(s) do begin h := (h shl 4) + ord(s[i]); g := h and $f0000000; if (g > 0) then h := h or (g shr 24) or g; end; result := h; end; constructor THash.Create; begin inherited Create; self.f_CurrentIterator.ck := -1; self.f_CurrentIterator.cx := 0; self.f_CurrentItemShift := c_HashInitialItemShift; self.FUpdateMasks; self.FUpdateBuckets; self.f_AllowCompact := true; end; procedure THash.Delete(const Key: string); var k, x, i: integer; begin { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; if (self.FFindKey(Key, k, x)) then begin { Delete the Index entry. } i := self.f_Keys[k][x].ItemIndex; self.FDeleteIndex(i); { Add the index to the Spares list. } SetLength(self.f_SpareItems, Length(self.f_SpareItems) + 1); self.f_SpareItems[High(self.f_SpareItems)] := i; { Overwrite key with the last in the list. } self.f_Keys[k][x] := self.f_Keys[k][High(self.f_Keys[k])]; { Delete the last in the list. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) - 1); end else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]); self.FAutoCompact; end; function THash.Exists(const Key: string): boolean; var dummy1, dummy2: integer; begin result := FFindKey(Key, dummy1, dummy2); end; procedure THash.FSetOrAddKey(const Key: string; ItemIndex: integer); var k, x, i: integer; begin { Exists already? } if (self.FFindKey(Key, k, x)) then begin { Yep. Delete the old stuff and set the new value. } i := self.f_Keys[k][x].ItemIndex; self.FDeleteIndex(i); self.f_Keys[k][x].ItemIndex := ItemIndex; { Add the index to the spares list. } SetLength(self.f_SpareItems, Length(self.f_SpareItems) + 1); self.f_SpareItems[High(self.f_SpareItems)] := i; end else begin { No, create a new one. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := ItemIndex; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); end; end; function THash.FFindKey(const Key: string; var k, x: integer): boolean; var i: integer; h: cardinal; begin { Which bucket? } h := HashThis(Key); k := h and f_CurrentItemMask; result := false; { Look for it. } for i := 0 to High(self.f_Keys[k]) do if (self.f_Keys[k][i].Hash = h) or true then if (self.f_Keys[k][i].Key = Key) then begin { Found it! } result := true; x := i; break; end; end; procedure THash.Rename(const Key, NewName: string); var k, x, i: integer; begin { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; if (self.FFindKey(Key, k, x)) then begin { Remember the ItemIndex. } i := self.f_Keys[k][x].ItemIndex; { Overwrite key with the last in the list. } self.f_Keys[k][x] := self.f_Keys[k][High(self.f_Keys[k])]; { Delete the last in the list. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) - 1); { Create the new item. } self.FSetOrAddKey(NewName, i); end else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]); self.FAutoCompact; end; function THash.CurrentKey: string; begin if (not (self.f_NextAllowed)) then raise EHashIterateError.Create('Cannot find CurrentKey as the hash has ' + 'been modified since Restart was called') else if (self.f_CurrentKey = '') then raise EHashIterateError.Create('Cannot find CurrentKey as Next has not yet ' + 'been called after Restart') else result := self.f_CurrentKey; end; function THash.Next: boolean; begin if (not (self.f_NextAllowed)) then raise EHashIterateError.Create('Cannot get Next as the hash has ' + 'been modified since Restart was called'); result := false; if (self.f_CurrentIterator.ck = -1) then begin self.f_CurrentIterator.ck := 0; self.f_CurrentIterator.cx := 0; end; while ((not result) and (self.f_CurrentIterator.ck <= f_CurrentItemMaxIdx)) do begin if (self.f_CurrentIterator.cx < Length(self.f_Keys[self.f_CurrentIterator.ck])) then begin result := true; self.f_CurrentKey := self.f_Keys[self.f_CurrentIterator.ck][self.f_CurrentIterator.cx].Key; inc(self.f_CurrentIterator.cx); end else begin inc(self.f_CurrentIterator.ck); self.f_CurrentIterator.cx := 0; end; end; end; procedure THash.Restart; begin self.f_CurrentIterator.ck := -1; self.f_CurrentIterator.cx := 0; self.f_NextAllowed := true; end; function THash.FGetItemCount: integer; var i: integer; begin { Calculate our item count. } result := 0; for i := 0 to f_CurrentItemMaxIdx do inc(result, Length(self.f_Keys[i])); end; function THash.FAllocItemIndex: integer; begin if (Length(self.f_SpareItems) > 0) then begin { Use the top SpareItem. } result := self.f_SpareItems[High(self.f_SpareItems)]; SetLength(self.f_SpareItems, Length(self.f_SpareItems) - 1); end else begin result := self.FIndexMax + 1; end; end; procedure THash.Compact; var aSpaces: array of boolean; aMapping: array of integer; i, j: integer; begin { Find out where the gaps are. We could do this by sorting, but that's at least O(n log n), and sometimes O(n^2), so we'll go for the O(n) method, even though it involves multiple passes. Note that this is a lot faster than it looks. Disabling this saves about 3% in my benchmarks, but uses a lot more memory. } if (self.AllowCompact) then begin SetLength(aSpaces, self.FIndexMax + 1); SetLength(aMapping, self.FIndexMax + 1); for i := 0 to High(aSpaces) do aSpaces[i] := false; for i := 0 to High(aMapping) do aMapping[i] := i; for i := 0 to High(self.f_SpareItems) do aSpaces[self.f_SpareItems[i]] := true; { Starting at the low indexes, fill empty ones from the high indexes. } i := 0; j := self.FIndexMax; while (i < j) do begin if (aSpaces[i]) then begin while ((i < j) and (aSpaces[j])) do dec(j); if (i < j) then begin aSpaces[i] := false; aSpaces[j] := true; self.FMoveIndex(j, i); aMapping[j] := i end; end else inc(i); end; j := self.FIndexMax; while (aSpaces[j]) do dec(j); { Trim the items array down to size. } self.FTrimIndexes(j + 1); { Clear the spaces. } SetLength(self.f_SpareItems, 0); { Update our buckets. } for i := 0 to f_CurrentItemMaxIdx do for j := 0 to High(self.f_Keys[i]) do self.f_Keys[i][j].ItemIndex := aMapping[self.f_Keys[i][j].ItemIndex]; end; end; procedure THash.FAutoCompact; begin if (self.AllowCompact) then if (Length(self.f_SpareItems) >= c_HashCompactM) then if (self.FIndexMax * c_HashCompactR > Length(self.f_SpareItems)) then self.Compact; end; procedure THash.Clear; var i: integer; begin self.FClearItems; SetLength(self.f_SpareItems, 0); for i := 0 to f_CurrentItemMaxIdx do SetLength(self.f_Keys[i], 0); end; procedure THash.FUpdateMasks; begin f_CurrentItemMask := (1 shl f_CurrentItemShift) - 1; f_CurrentItemMaxIdx := (1 shl f_CurrentItemShift) - 1; f_CurrentItemCount := (1 shl f_CurrentItemShift); end; procedure THash.FUpdateBuckets; begin { This is just a temporary thing. } SetLength(self.f_Keys, self.f_CurrentItemCount); end; function THash.NewIterator: THashIterator; begin result.ck := -1; result.cx := 0; end; function THash.Previous: boolean; begin if (not (self.f_NextAllowed)) then raise EHashIterateError.Create('Cannot get Next as the hash has ' + 'been modified since Restart was called'); result := false; if (self.f_CurrentIterator.ck >= 0) then begin while ((not result) and (self.f_CurrentIterator.ck >= 0)) do begin dec(self.f_CurrentIterator.cx); if (self.f_CurrentIterator.cx >= 0) then begin result := true; self.f_CurrentKey := self.f_Keys[self.f_CurrentIterator.ck][self.f_CurrentIterator.cx].Key; end else begin dec(self.f_CurrentIterator.ck); if (self.f_CurrentIterator.ck >= 0) then self.f_CurrentIterator.cx := Length(self.f_Keys[self.f_CurrentIterator.ck]); end; end; end; end; { TStringHash } procedure TStringHash.FDeleteIndex(i: integer); begin self.f_Items[i] := ''; end; function TStringHash.FGetItem(const Key: string): string; var k, x: integer; begin if (self.FFindKey(Key, k, x)) then result := self.f_Items[self.f_Keys[k][x].ItemIndex] else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]); end; procedure TStringHash.FMoveIndex(oldIndex, newIndex: integer); begin self.f_Items[newIndex] := self.f_Items[oldIndex]; end; procedure TStringHash.FSetItem(const Key, Value: string); var k, x, i: integer; begin if (self.FFindKey(Key, k, x)) then self.f_Items[self.f_Keys[k][x].ItemIndex] := Value else begin { New index entry, or recycle an old one. } i := self.FAllocItemIndex; if (i > High(self.f_Items)) then SetLength(self.f_Items, i + 1); self.f_Items[i] := Value; { Add it to the hash. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := i; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; end; end; function TStringHash.FIndexMax: integer; begin result := High(self.f_Items); end; procedure TStringHash.FTrimIndexes(count: integer); begin SetLength(self.f_Items, count); end; procedure TStringHash.FClearItems; begin SetLength(self.f_Items, 0); end; { TIntegerHash } procedure TIntegerHash.FDeleteIndex(i: integer); begin self.f_Items[i] := 0; end; function TIntegerHash.FGetItem(const Key: string): integer; var k, x: integer; begin if (self.FFindKey(Key, k, x)) then result := self.f_Items[self.f_Keys[k][x].ItemIndex] else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]); end; procedure TIntegerHash.FMoveIndex(oldIndex, newIndex: integer); begin self.f_Items[newIndex] := self.f_Items[oldIndex]; end; procedure TIntegerHash.FSetItem(const Key: string; Value: integer); var k, x, i: integer; begin if (self.FFindKey(Key, k, x)) then self.f_Items[self.f_Keys[k][x].ItemIndex] := Value else begin { New index entry, or recycle an old one. } i := self.FAllocItemIndex; if (i > High(self.f_Items)) then SetLength(self.f_Items, i + 1); self.f_Items[i] := Value; { Add it to the hash. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := i; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; end; end; function TIntegerHash.FIndexMax: integer; begin result := High(self.f_Items); end; procedure TIntegerHash.FTrimIndexes(count: integer); begin SetLength(self.f_Items, count); end; procedure TIntegerHash.FClearItems; begin SetLength(self.f_Items, 0); end; { TObjectHash } procedure TObjectHash.FDeleteIndex(i: integer); begin self.f_Items[i].Free; self.f_Items[i] := nil; end; function TObjectHash.FGetItem(const Key: string): TObject; var k, x: integer; begin if (self.FFindKey(Key, k, x)) then result := self.f_Items[self.f_Keys[k][x].ItemIndex] else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]); end; procedure TObjectHash.FMoveIndex(oldIndex, newIndex: integer); begin self.f_Items[newIndex] := self.f_Items[oldIndex]; end; procedure TObjectHash.FSetItem(const Key: string; Value: TObject); var k, x, i: integer; begin if (self.FFindKey(Key, k, x)) then begin self.f_Items[self.f_Keys[k][x].ItemIndex].Free; self.f_Items[self.f_Keys[k][x].ItemIndex] := Value; end else begin { New index entry, or recycle an old one. } i := self.FAllocItemIndex; if (i > High(self.f_Items)) then SetLength(self.f_Items, i + 1); self.f_Items[i] := Value; { Add it to the hash. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := i; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; end; end; function TObjectHash.FIndexMax: integer; begin result := High(self.f_Items); end; procedure TObjectHash.FTrimIndexes(count: integer); begin SetLength(self.f_Items, count); end; procedure TObjectHash.FClearItems; var i: integer; begin for i := 0 to High(self.f_Items) do if (Assigned(self.f_Items[i])) then self.f_Items[i].Free; SetLength(self.f_Items, 0); end; destructor TObjectHash.Destroy; var i: integer; begin for i := 0 to High(self.f_Items) do if (Assigned(self.f_Items[i])) then self.f_Items[i].Free; inherited; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/src/TorrentFile.pas��������������������������������������������0000644�0001750�0000144�00000024711�14743153644�022323� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit TorrentFile; interface uses SysUtils, Contnrs, Hashes, Classes, BDecode; type TBitfield = array of boolean; TTorrentPiece = class(TObject) private _Hash: String; _HashBin: String; _Valid: Boolean; public property Hash: String read _Hash; property HashBin: String read _HashBin; property Valid: Boolean read _Valid write _Valid; constructor Create(Hash: String; HashBin:String; Valid: Boolean); end; TTorrentSubFile = class(TObject) private _Name: String; _Path: String; _Filename: String; _Length: Int64; _Offset: Int64; _Left: Int64; public property Name: String read _Name write _Name; property Path: String read _Path write _Path; property Length: Int64 read _Length; property Offset: Int64 read _Offset; property Left: Int64 read _Left write _Left; property Filename: String read _Filename write _Filename; constructor Create(Name: String; Path: String; Length: Int64; Offset: Int64); end; TTorrentFile = class(TObject) published private _Announce : String; _Name : String; _Comment : String; _Length : Int64; _CreationTime : Int32; _Count : Integer; _Err : TStringList; _Tree : TObjectHash; _SHA1Hash : String; _HashBin : String; _Multifile : Boolean; _Files : TObjectList; public Pieces : array of TTorrentPiece; PieceLength : Integer; BackupTrackers : TStringList; property Announce: String read _Announce write _Announce; property Name: String read _Name write _Name; property CreationTime: Int32 read _CreationTime write _CreationTime; property Length: Int64 read _Length; property Count: Integer read _Count; property Tree: TObjectHash read _Tree; property Errors: TStringList read _Err; property Hash: String read _SHA1Hash; property Comment: String read _Comment write _Comment; property HashBin: String read _HashBin; property Multifile: Boolean read _Multifile; property Files: TObjectList read _Files write _Files; procedure Clear(); function Load(Stream: TStream): Boolean; procedure Save(Stream: TStream; Pieces : array of TTorrentPiece); procedure Init(Announce, Name, Comment, HashBin:String; Length:Int64; Multifile:Boolean); constructor Create(); destructor Destroy(); override; end; implementation uses DCDateTimeUtils, SHA1; { TTorrentSubFile } constructor TTorrentSubFile.Create(Name, Path: String; Length: Int64; Offset: Int64); begin _Name := Name; _Path := Path; _Length := Length; _Offset := Offset; _Left := Length; inherited Create(); end; procedure TTorrentFile.Clear(); var i : Integer; begin _Announce := ''; _Name := ''; _SHA1Hash := ''; _Length := 0; _Count := 0; _Files.Clear(); _Tree.Clear(); _Err.Clear(); for i := Low(Pieces) to High(Pieces) do FreeAndNil(Pieces[i]); SetLength(Pieces,0); _Multifile := False; end; constructor TTorrentFile.Create(); begin _Files := TObjectList.Create(); _Tree := TObjectHash.Create(); _Err := TStringList.Create(); BackupTrackers := TStringList.Create; inherited Create(); end; destructor TTorrentFile.Destroy(); begin Clear(); FreeAndNil(_Files); FreeAndNil(_Tree); FreeAndNil(_Err); FreeAndNil(BackupTrackers); inherited; end; procedure TTorrentFile.Init(Announce, Name, Comment, HashBin:String; Length:Int64; Multifile:Boolean); begin _Announce := Announce; _Name := Name; _Comment := Comment; _HashBin := HashBin; _Length := Length; _Multifile := Multifile; _CreationTime := DateTimeToUnixFileTime(Now); end; function TTorrentFile.Load(Stream: TStream): Boolean; var info, thisfile: TObjectHash; files, path, backup, backup2: TObjectList; fp, fn: String; i, j, pcount: Integer; sz, fs, fo: Int64; digest: TSHA1Digest; r: Boolean; o: TObject; s:string; begin Clear(); r := False; sz := 0; try o := bdecodeStream(Stream); if(Assigned(o)) then begin _Tree := o as TObjectHash; if(_Tree.Exists('announce')) then begin _Announce := (_Tree['announce'] as TIntString).StringPart; end else begin _Err.Add('Corrupt File: Missing "announce" segment'); end; if(_Tree.Exists('announce-list')) then begin backup := _Tree['announce-list'] as TObjectList; for i := 0 to backup.Count - 1 do begin backup2 := (backup[i] as TObjectList); for j:=0 to backup2.Count -1 do BackupTrackers.Add((backup2[j] as TIntString).StringPart); end; end; if(_Tree.Exists('comment')) then begin _Comment := (_Tree['comment'] as TIntString).StringPart; end; if(_Tree.Exists('creation date')) then begin _CreationTime := (_Tree['creation date'] as TIntString).IntPart; end; if(_Tree.Exists('info')) then begin info := _Tree['info'] as TObjectHash; if(info.Exists('name')) then begin _Name := (info['name'] as TIntString).StringPart; if copy(_Name,system.length(_Name)-7,8)='.torrent' then _Name:=copy(_Name,0,system.length(_Name)-8); end else begin _Err.Add('Corrupt File: Missing "info.name" segment'); end; if(info.Exists('piece length')) then begin PieceLength := (info['piece length'] as TIntString).IntPart; end else begin _Err.Add('Corrupt File: Missing "info.piece length" segment'); end; { if(info.Exists('pieces')) then begin fp := (info['pieces'] as TIntString).StringPart; pcount := System.Length(fp) div 20; SetLength(Pieces,pcount); for i := 0 to pcount - 1 do begin s:=copy(fp,(i * 20) + 1,20); Pieces[i] := TTorrentPiece.Create(bin2hex(s), s, False); end; end else begin _Err.Add('Corrupt File: Missing "info.pieces" segment'); end; } if(info.Exists('length')) then begin // single-file archive sz := (info['length'] as TIntString).IntPart; _Count := 1; _Files.Add(TTorrentSubFile.Create(_Name,'',sz,Int64(0))); end else begin if(info.Exists('files')) then begin _Multifile := True; files := info['files'] as TObjectList; for i := 0 to files.Count - 1 do begin thisfile := files[i] as TObjectHash; if(thisfile.Exists('length')) then begin fs := (thisfile['length'] as TIntString).IntPart; end else begin fs := Int64(0); _Err.Add('Corrupt File: files[' + IntToStr(i) + '] is missing a "length" segment'); end; fp := ''; fn := ''; if(thisfile.Exists('path')) then begin path := thisfile['path'] as TObjectList; for j := 0 to path.Count - 2 do fp := fp + (path[j] as TIntString).StringPart + PathDelim; if(path.Count > 0) then fn := (path[path.Count - 1] as TIntString).StringPart; end else begin _Err.Add('Corrupt File: files[' + IntToStr(i) + '] is missing a "path" segment'); end; _Files.Add(TTorrentSubFile.Create(fn,fp,fs,sz)); sz := sz + fs; end; _Count := _Files.Count; end else begin _Err.Add('Corrupt File: Missing both "info.length" and "info.files" segments (should have one or the other)'); end; end; if(_Tree.Exists('_info_start') and _Tree.Exists('_info_length')) then begin fo := Stream.Position; Stream.Seek((_Tree['_info_start'] as TIntString).IntPart,soFromBeginning); fs := (_Tree['_info_length'] as TIntString).IntPart; SetLength(fp,fs); Stream.Read(PChar(fp)^,fs); digest := SHA1String(fp); _SHA1Hash := SHA1Print(digest); SetLength(_HashBin, 20); Move(digest[0], _HashBin[1], 20); Stream.Seek(fo,soFromBeginning); end; end else begin _Err.Add('Corrupt File: Missing "info" segment'); end; _Length := sz; r := True; end else begin _Err.Add('Error parsing file; does not appear to be valid bencoded metainfo'); end; except _Err.Add('Something bad happened while trying to load the file, probably corrupt metainfo'); end; Result := r; end; procedure TTorrentFile.Save(Stream: TStream; Pieces : array of TTorrentPiece); var i:integer; s,s2:string; procedure WStrm(s:string); begin Stream.WriteBuffer(s[1],system.length(s)); end; procedure WStrg(s:string); var t:String; begin t:=inttostr(system.length(s))+':'+s; WStrm(t); end; procedure WInt(i:int64); begin WStrm('i'); WStrm(IntToStr(i)); WStrm('e'); end; begin WStrm('d'); WStrg('announce'); WStrg(Announce); if BackupTrackers.Count > 0 then begin WStrg('announce-list'); WStrm('l'); // Primary Tracker WStrm('l'); WStrg(Announce); WStrm('e'); // Backup Tracker for i:=0 to BackupTrackers.Count-1 do if BackupTrackers[i] <> Announce then begin WStrm('l'); WStrg(BackupTrackers[i]); WStrm('e'); end; WStrm('e'); end; if Comment <> '' then begin WStrg('comment'); WStrg(comment); end; if Date <> 0 then begin WStrg('creation date'); WInt(CreationTime); end; WStrg('info'); WStrm('d'); if Multifile then begin WStrg('files'); WStrm('l'); for i:=0 to Files.Count-1 do with (Files[i] as TTorrentSubFile) do begin WStrm('d'); WStrg('length'); WInt(Length); WStrg('path'); WStrm('l'); if Path <> '' then begin s:=path; repeat if pos('\',s) <> 0 then begin s2:=copy(s,1,pos('\',s)-1); WStrg(s2); Delete(s,1,pos('\',s)); end; if (pos('\',s)=0) and (s <>'') then WStrg(s); until pos('\',s)=0; end; WStrg(Name); WStrm('e'); WStrm('e'); end; WStrm('e'); end else begin WStrg('length'); WInt(Length); end; WStrg('name'); WStrg(Name); WStrg('piece length'); WInt(PieceLength); WStrg('pieces'); WStrm(IntToStr((high(pieces)+1)*20)); WStrm(':'); for i:=0 to high(pieces) do WStrm(pieces[i].HashBin); WStrm('e'); WStrm('e'); end; constructor TTorrentPiece.Create(Hash, HashBin: String; Valid: Boolean); begin _Hash := Hash; _HashBin := HashBin; _Valid := Valid; inherited Create(); end; end. �������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/src/torrent.lpi������������������������������������������������0000644�0001750�0000144�00000010037�14743153644�021560� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="10"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="torrent"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../torrent.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <TrashVariables Value="True"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <HostApplicationFilename Value="/usr/bin/doublecmd"/> </local> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> </RequiredPackages> <Units Count="1"> <Unit0> <Filename Value="torrent.lpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../torrent.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/torrent/src/torrent.lpr������������������������������������������������0000644�0001750�0000144�00000010077�14743153644�021575� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- BitTorrent archiver plugin Copyright (C) 2017 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. } library torrent; {$mode delphi} {$include calling.inc} uses {$IFDEF UNIX} cthreads, {$ENDIF} FPCAdds, Classes, SysUtils, TorrentFile, WcxPlugin, DCDateTimeUtils, DCClassesUtf8, DCConvertEncoding; type PTorrentHandle = ^TTorrentHandle; TTorrentHandle = record Index: Integer; Torrent: TTorrentFile; end; function OpenArchive(var ArchiveData : tOpenArchiveData) : TArcHandle; dcpcall; begin Result := 0; ArchiveData.OpenResult := E_NOT_SUPPORTED; end; function OpenArchiveW(var ArchiveData : tOpenArchiveDataW) : TArcHandle; dcpcall; var AFileName: String; AStream: TFileStreamEx; AHandle: PTorrentHandle = nil; begin Result:= 0; if ArchiveData.OpenMode = PK_OM_EXTRACT then begin ArchiveData.OpenResult:= E_NOT_SUPPORTED; Exit; end; try AFileName := CeUtf16ToUtf8(UnicodeString(ArchiveData.ArcName)); AStream:= TFileStreamEx.Create(AFileName, fmOpenRead or fmShareDenyNone); try New(AHandle); AHandle.Index:= 0; AHandle.Torrent:= TTorrentFile.Create; if not AHandle.Torrent.Load(AStream) then raise Exception.Create(EmptyStr); Result:= TArcHandle(AHandle); finally AStream.Free; end; except ArchiveData.OpenResult:= E_EOPEN; if Assigned(AHandle) then begin AHandle.Torrent.Free; Dispose(AHandle); end; end; end; function ReadHeader(hArcData : TArcHandle; var HeaderData: THeaderData) : Integer; dcpcall; begin Result := E_NOT_SUPPORTED; end; function ReadHeaderExW(hArcData : TArcHandle; var HeaderData: THeaderDataExW) : Integer; dcpcall; var AFile: TTorrentSubFile; AHandle: PTorrentHandle absolute hArcData; begin if AHandle.Index >= AHandle.Torrent.Files.Count then Exit(E_END_ARCHIVE); AFile:= TTorrentSubFile(AHandle.Torrent.Files[AHandle.Index]); HeaderData.FileTime:= UnixFileTimeToWcxTime(AHandle.Torrent.CreationTime); HeaderData.FileName:= CeUtf8ToUtf16(AFile.Path + AFile.Name); HeaderData.UnpSize:= Int64Rec(AFile.Length).Lo; HeaderData.UnpSizeHigh:= Int64Rec(AFile.Length).Hi; HeaderData.PackSize:= HeaderData.UnpSize; HeaderData.PackSizeHigh:= HeaderData.UnpSizeHigh; Result:= E_SUCCESS; end; function ProcessFile(hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PChar) : Integer; dcpcall; begin Result := E_NOT_SUPPORTED; end; function ProcessFileW(hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PWideChar) : Integer; dcpcall; var AHandle: PTorrentHandle absolute hArcData; begin Inc(AHandle.Index); Result:= E_SUCCESS; end; function CloseArchive (hArcData : TArcHandle) : Integer; dcpcall; var AHandle: PTorrentHandle absolute hArcData; begin if hArcData <> wcxInvalidHandle then begin AHandle.Torrent.Free; Dispose(AHandle); end; Result:= E_SUCCESS; end; procedure SetChangeVolProc (hArcData : TArcHandle; pChangeVolProc : TChangeVolProc); dcpcall; begin end; procedure SetProcessDataProc (hArcData : TArcHandle; pProcessDataProc : TProcessDataProc); dcpcall; begin end; function GetPackerCaps : Integer;dcpcall; begin Result := PK_CAPS_MULTIPLE or PK_CAPS_HIDE; end; exports OpenArchive, OpenArchiveW, ReadHeader, ReadHeaderExW, ProcessFile, ProcessFileW, CloseArchive, SetChangeVolProc, SetProcessDataProc, GetPackerCaps; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/�����������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016217� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020002� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.be.po���������������������������������������������0000644�0001750�0000144�00000004450�14743153644�022061� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n%100>=11 && n%100<=14 ? 2 : 3);\n" "X-Crowdin-Project: b5aaebc75354984d7cee90405a1f6642\n" "X-Crowdin-Project-ID: 7\n" "X-Crowdin-Language: be\n" "X-Crowdin-File: /l10n_Translation/plugins/wcx/unrar/language/unrar.po\n" "X-Crowdin-File-ID: 3348\n" "Project-Id-Version: b5aaebc75354984d7cee90405a1f6642\n" "Language-Team: Belarusian\n" "Language: be_BY\n" "PO-Revision-Date: 2022-09-25 05:45\n" #: tdialogbox.caption msgid "Options" msgstr "Параметры" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "Шлях да выканальнага файла Win&RAR" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "Параметры архівацыі" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "Дадаць запіс &аднаўлення" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "Шыфраваць назвы &файлаў" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "Стварыць &суцэльны архіў" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "Метад &сціскання" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "Скасаваць" #: tdialogbox.btnsave.caption msgid "OK" msgstr "ДОБРА" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "Дадатковыя параметры" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack." msgstr "" #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.de.po���������������������������������������������0000644�0001750�0000144�00000004721�14743153644�022064� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Project-Id-Version: Double Commander Plugin 'unrar'\n" "POT-Creation-Date: \n" "PO-Revision-Date: 2024-11-01 18:01+0100\n" "Last-Translator: ㋡ <braass@mail.de>\n" "Language-Team: \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0.1\n" #: tdialogbox.caption msgid "Options" msgstr "Optionen" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "Pfad zur ausführbaren Win&RAR-Datei" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "Optionen für die Archivierung" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "Wiederherstellungs&eintrag hinzufügen" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "Datei&namen verschlüsseln" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "&Solide (progressiv) komprimiertes Archiv erstellen" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "&Komprimierungsmethode" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "Abbrechen" #: tdialogbox.btnsave.caption msgid "OK" msgstr "OK" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "Zusätzliche Parameter" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "" "\"Großes Wörterbuch\"-Warnung (es fallen extrem viele Ersatzsymbole für " "Zeichenfolgen an)" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "" "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to " "unpack." msgstr "" "%u GB \"Wörterbuch\" übersteigt %u GB Grenze und braucht mehr als %u GB " "Speicher zum Entpacken." #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "Abbre&chen" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "&Entpacke einzelne Datei(en)" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "Bitte Passwort eingeben:" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" "Ausführbares RAR-Programm nicht gefunden!\n" "\n" "%s\n" "\n" "Bitte überprüfen Sie die Einstellungen des Plugins." #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "" "Kann Bibliothek %s nicht laden! Bitte überprüfen Sie Ihre Installation." �����������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.hu.po���������������������������������������������0000644�0001750�0000144�00000004371�14743153644�022111� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Project-Id-Version: Double Commander unrar WCX plugin\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Forge Studios Ltd. <kroy <kroysoft@citromail.hu>>\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: hu_HU\n" "X-Generator: Poedit 1.8.8\n" #: tdialogbox.caption msgid "Options" msgstr "Beállítások" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "Win&RAR futtatható állomány helye" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "Archiválási beállítások" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "&Helyreállítási jegyzék hozzáadása" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "Fájl&nevek titkosítása" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "&Tömör archívum létrehozása" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "Tö&mörítési eljárás" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "Mégsem" #: tdialogbox.btnsave.caption msgid "OK" msgstr "OK" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "További paraméterek" #: dropdown list content msgid "Store;Fastest;Fast;Normal;Good;Best" msgstr "Tároló;Leggyorsabb;Gyors;Normál;Jó;Legjobb" msgid "Normal" msgstr "Normál" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack." msgstr "" #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.ko.po���������������������������������������������0000644�0001750�0000144�00000004573�14743153644�022112� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Project-Id-Version: Double Commander Plugin - unrar\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: VenusGirl: https://venusgirls.tistory.com/\n" "Language-Team: 비너스걸: https://venusgirls.tistory.com/\n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Native-Language: 한국어\n" "X-Generator: Poedit 3.4.2\n" #: tdialogbox.caption msgid "Options" msgstr "압축 옵션" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "WinRAR 실행 파일 경로(&R)" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "압축 옵션" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "복구 레코드 추가" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "파일 이름 암호화(&N)" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "솔리드 압축파일 만들기(&S)" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "압축 방법(&C)" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "취소" #: tdialogbox.btnsave.caption msgid "OK" msgstr "확인" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "추가 매개변수" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "큰 사전 경고" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack." msgstr "%u GB 사전이 %u GB 제한을 초과하여 풀려면 %u GB 이상의 메모리가 필요합니다." #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "취소(&C)" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "추출(&E)" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "암호를 입력하십시오:" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" "RAR 실행 파일을 찾을 수 없습니다!\\n\n" "\n" "%s\n" "\n" "플러그인 설정을 확인해 주세요." #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "%s 라이브러리를 로드할 수 없습니다! 설치를 확인하십시오." �������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.pot�����������������������������������������������0000644�0001750�0000144�00000002776�14743153644�021671� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.caption msgid "Options" msgstr "" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "" #: tdialogbox.btnsave.caption msgid "OK" msgstr "" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack." msgstr "" #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "" ��doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.ru.po���������������������������������������������0000644�0001750�0000144�00000004603�14743153644�022121� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.caption msgid "Options" msgstr "Настройки" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "Путь к исполняемому файлу Win&RAR" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "Параметры архивации" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "Добавить запись &восстановления" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "&Шифровать имена файлов" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "Создать &непрерывный архив" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "&Метод сжатия" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "Отмена" #: tdialogbox.btnsave.caption msgid "OK" msgstr "OK" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "Дополнительные параметры" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "Предупреждение о большом словаре" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack." msgstr "Размер словаря %u Гб превышает ограничение в %u Гб, для распаковки требуется более %u Гб памяти." #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "О&тмена" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "&Распаковать" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "Введите пароль:" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" "Исполняемый файл RAR не найден!\n" "\n" "%s\n" "\n" "Проверьте настройки плагина." #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "Не удалось загрузить библиотеку %s! Пожалуйста, проверьте установку." �����������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/language/unrar.zh_CN.po������������������������������������������0000644�0001750�0000144�00000003235�14743153644�022474� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.caption msgid "Options" msgstr "选项" #: tdialogbox.lblpath.caption msgid "Path to Win&RAR executable" msgstr "WinRAR 可执行文件的路径(&R)" #: tdialogbox.gboptions.caption msgid "Archiving options" msgstr "存档选项" #: tdialogbox.gboptions.chkrecovery.caption msgid "Add r&ecovery record" msgstr "添加恢复记录(&E)" #: tdialogbox.gboptions.chkencrypt.caption msgid "Encrypt file &names" msgstr "加密文件名(&N)" #: tdialogbox.gboptions.chksolid.caption msgid "Create &solid archive" msgstr "创建可靠的存档(&S)" #: tdialogbox.lblmethod.caption msgid "&Compression method" msgstr "压缩方式(&C)" #: tdialogbox.brncancel.caption msgid "Cancel" msgstr "取消" #: tdialogbox.btnsave.caption msgid "OK" msgstr "确定" #: tdialogbox.lblargs.caption msgid "Additional parameters" msgstr "附加参数" #: rarlng.rsdictlargewarning msgid "Large dictionary warning" msgstr "" #: rarlng.rsdictnotallowed #, object-pascal-format msgid "%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack." msgstr "" #: rarlng.rsmsgbuttoncancel msgid "&Cancel" msgstr "" #: rarlng.rsmsgbuttonextract msgid "&Extract" msgstr "" #: rarlng.rsmsgpasswordenter msgid "Please enter the password:" msgstr "" #: rarlng.rsmsgexecutablenotfound #, object-pascal-format msgid "" "Cannot find RAR executable!\n" "\n" "%s\n" "\n" "Please check the plugin settings." msgstr "" #: rarlng.rsmsglibrarynotfound #, object-pascal-format msgid "Cannot load library %s! Please check your installation." msgstr "" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/readme.txt�������������������������������������������������������0000644�0001750�0000144�00000001303�14743153644�020212� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������For using this plugin you need unrar library. You can download it from http://www.rarlab.com/rar_add.htm Windows: Download "UnRAR.dll" - Self-extracting archive UnRARDLL.exe, unpack it and copy unrar.dll in Double Commander (or %windir%\system32) directory Linux: Download "UnRAR source" unrarsrc-x.x.x.tar.gz, unpack it: $ tar -xf unrarsrc-x.x.x.tar.gz go to "unrar" directory: $ cd unrar make symlink makefile.unix -> makefile: $ ln -s makefile.unix makefile set CXX environment variable to "g++ -DSILENT" $export CXX="g++ -DSILENT" and build library: $ make lib After compiling, copy "libunrar.so" in "/usr/lib" directory: $ cp libunrar.so /usr/lib/libunrar.so�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/�������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017006� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/fpc-extra.cfg������������������������������������������������0000644�0001750�0000144�00000000157�14743153644�021363� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF CPU64 #IFDEF FPC_CROSSCOMPILING -Fl/usr/lib/gcc/i486-linux-gnu/4.6/64 -Fl/usr/local/lib64 #ENDIF #ENDIF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/rarconfdlg.lfm�����������������������������������������������0000644�0001750�0000144�00000010513�14743153644�021627� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object DialogBox: TDialogBox Left = 373 Height = 282 Top = 194 Width = 320 AutoSize = True BorderStyle = bsDialog Caption = 'Options' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ClientHeight = 282 ClientWidth = 320 OnShow = DialogBoxShow Position = poOwnerFormCenter LCLVersion = '1.4.2.0' object fnePath: TFileNameEdit AnchorSideLeft.Control = lblPath AnchorSideTop.Control = lblPath AnchorSideTop.Side = asrBottom Left = 10 Height = 23 Top = 31 Width = 296 FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 BorderSpacing.Top = 6 MaxLength = 0 TabOrder = 0 end object lblPath: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 10 Height = 15 Top = 10 Width = 143 Caption = 'Path to Win&RAR executable' ParentColor = False end object gbOptions: TGroupBox AnchorSideLeft.Control = cmbMethod AnchorSideTop.Control = edtArgs AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 85 Top = 158 Width = 300 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Archiving options' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 65 ClientWidth = 296 TabOrder = 2 object chkRecovery: TCheckBox Left = 6 Height = 19 Top = 4 Width = 127 Caption = 'Add r&ecovery record' TabOrder = 0 end object chkEncrypt: TCheckBox Left = 6 Height = 19 Top = 23 Width = 127 Caption = 'Encrypt file &names' TabOrder = 1 end object chkSolid: TCheckBox Left = 6 Height = 19 Top = 42 Width = 127 Caption = 'Create &solid archive' TabOrder = 2 end end object lblMethod: TLabel AnchorSideLeft.Control = fnePath AnchorSideTop.Control = fnePath AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 60 Width = 115 BorderSpacing.Top = 6 Caption = '&Compression method' ParentColor = False end object cmbMethod: TComboBox AnchorSideLeft.Control = lblMethod AnchorSideTop.Control = lblMethod AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 79 Width = 300 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 ItemHeight = 15 ItemIndex = 3 Items.Strings = ( 'Store' 'Fastest' 'Fast' 'Normal' 'Good' 'Best' ) Style = csDropDownList TabOrder = 1 Text = 'Normal' end object brnCancel: TButton AnchorSideTop.Control = gbOptions AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 235 Height = 25 Top = 253 Width = 75 Anchors = [akTop, akRight] BorderSpacing.Top = 10 Caption = 'Cancel' Cancel = True ModalResult = 2 OnClick = ButtonClick TabOrder = 4 end object btnSave: TButton AnchorSideTop.Control = brnCancel AnchorSideRight.Control = brnCancel Left = 154 Height = 25 Top = 253 Width = 75 Anchors = [akTop, akRight] BorderSpacing.Right = 6 Caption = 'OK' ModalResult = 1 OnClick = ButtonClick TabOrder = 3 end object lblArgs: TLabel AnchorSideLeft.Control = cmbMethod AnchorSideTop.Control = cmbMethod AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 108 Width = 117 BorderSpacing.Top = 6 Caption = 'Additional parameters' ParentColor = False end object edtArgs: TEdit AnchorSideLeft.Control = lblArgs AnchorSideTop.Control = lblArgs AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 129 Width = 300 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 5 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/rarconfdlg.pas�����������������������������������������������0000644�0001750�0000144�00000007533�14743153644�021644� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit RarConfDlg; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils; procedure LoadConfig; procedure CreateRarConfDlg; var Args: String; Method: Integer; Recovery: Boolean; Encrypt: Boolean; Solid: Boolean; {$IF DEFINED(MSWINDOWS)} WinRar: String = '%ProgramFiles%\WinRAR\WinRAR.exe'; {$ELSEIF DEFINED(DARWIN)} WinRar: String = '/usr/local/bin/rar'; {$ELSE} WinRar: String = '/usr/bin/rar'; {$ENDIF} implementation uses DCClassesUtf8, UnRARFunc, Extension, RarFunc; {$R *.lfm} procedure LoadConfig; var gIni: TIniFileEx; begin try gIni:= TIniFileEx.Create(IniFileName, fmOpenRead); try Args:= gIni.ReadString('unrar', 'Args', EmptyStr); WinRar:= gIni.ReadString('unrar', 'Path', WinRar); Method:= gIni.ReadInteger('unrar', 'Method', 3); Recovery:= gIni.ReadBool('unrar', 'Recovery', False); Encrypt:= gIni.ReadBool('unrar', 'Encrypt', False); Solid:= gIni.ReadBool('unrar', 'Solid', False); finally gIni.Free; end; except end; end; procedure SaveConfig; var gIni: TIniFileEx; begin try gIni:= TIniFileEx.Create(IniFileName, fmOpenReadWrite); try gIni.WriteString('unrar', 'Args', Args); gIni.WriteString('unrar', 'Path', WinRar); gIni.WriteInteger('unrar', 'Method', Method); gIni.WriteBool('unrar', 'Recovery', Recovery); gIni.WriteBool('unrar', 'Encrypt', Encrypt); gIni.WriteBool('unrar', 'Solid', Solid); gIni.UpdateFile; finally gIni.Free; end; except end; end; function DlgProc (pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall; begin Result:= 0; with gStartupInfo do begin case Msg of DN_INITDIALOG: begin SendDlgMsg(pDlg, 'cmbMethod', DM_LISTSETITEMINDEX, Method, 0); SendDlgMsg(pDlg, 'chkRecovery', DM_SETCHECK, PtrInt(Recovery), 0); SendDlgMsg(pDlg, 'chkEncrypt', DM_SETCHECK, PtrInt(Encrypt), 0); SendDlgMsg(pDlg, 'chkSolid', DM_SETCHECK, PtrInt(Solid), 0); SendDlgMsg(pDlg, 'edtArgs', DM_SETTEXT, PtrInt(PAnsiChar(Args)), 0); SendDlgMsg(pDlg, 'fnePath', DM_SETTEXT, PtrInt(PAnsiChar(WinRar)), 0); end; DN_CLICK: if DlgItemName = 'btnSave' then begin Args:= PAnsiChar(SendDlgMsg(pDlg, 'edtArgs', DM_GETTEXT, 0, 0)); WinRar:= PAnsiChar(SendDlgMsg(pDlg, 'fnePath', DM_GETTEXT, 0, 0)); Method:= SendDlgMsg(pDlg, 'cmbMethod', DM_LISTGETITEMINDEX, 0, 0); Recovery:= Boolean(SendDlgMsg(pDlg, 'chkRecovery', DM_GETCHECK, 0, 0)); Encrypt:= Boolean(SendDlgMsg(pDlg, 'chkEncrypt', DM_GETCHECK, 0, 0)); Solid:= Boolean(SendDlgMsg(pDlg, 'chkSolid', DM_GETCHECK, 0, 0)); SaveConfig; SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 1, 0); end else if DlgItemName = 'btnCancel' then SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 2, 0); end;// case end; // with end; procedure CreateRarConfDlg; var ResHandle: TFPResourceHandle = 0; ResGlobal: TFPResourceHGLOBAL = 0; ResData: Pointer = nil; ResSize: LongWord; begin try ResHandle := FindResource(HINSTANCE, PChar('TDIALOGBOX'), MAKEINTRESOURCE(10) {RT_RCDATA}); if ResHandle <> 0 then begin ResGlobal := LoadResource(HINSTANCE, ResHandle); if ResGlobal <> 0 then begin ResData := LockResource(ResGlobal); ResSize := SizeofResource(HINSTANCE, ResHandle); with gStartupInfo do begin DialogBoxLRS(ResData, ResSize, @DlgProc); end; end; end; finally if ResGlobal <> 0 then begin UnlockResource(ResGlobal); FreeResource(ResGlobal); end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/rarfunc.pas��������������������������������������������������0000644�0001750�0000144�00000022057�14743153644�021161� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Wcx plugin for packing RAR archives Copyright (C) 2015-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit RarFunc; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, WcxPlugin; procedure PackSetDefaultParams(dps: PPackDefaultParamStruct); dcpcall; export; procedure ConfigurePacker(Parent: HWND; DllInstance: THandle); dcpcall; export; function DeleteFilesW(PackedFile, DeleteList: PWideChar): Integer; dcpcall; export; function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer; dcpcall; export; var IniFileName: String; implementation uses Process, LazUTF8, DCConvertEncoding, DCProcessUtf8, DCOSUtils, UnRARFunc, RarConfDlg, RarLng, Extension; const UTF16LEBOM: WideChar = #$FEFF; LineEndingW = WideChar(#13) + WideChar(#10); function RarToWcx(Error: Integer): Integer; begin case Error of 0: Result:= E_SUCCESS; // Successful operation 1: Result:= E_SUCCESS; // Warning. Non fatal error(s) occurred 2: Result:= E_BAD_ARCHIVE; // A fatal error occurred 3: Result:= E_BAD_DATA; // Invalid checksum. Data is damaged 4: Result:= E_EOPEN; // Attempt to modify a locked archive 5: Result:= E_EWRITE; // Write error 6: Result:= E_EOPEN; // File open error 7: Result:= E_NOT_SUPPORTED; // Wrong command line option 8: Result:= E_NO_MEMORY; // Not enough memory 9: Result:= E_ECREATE; // File create error 10: Result:= E_BAD_DATA; // No files matching the specified mask and options were found 11: Result:= E_BAD_DATA; // Wrong password 12: Result:= E_EREAD; // Read error 255: Result:= E_EABORTED; // User break else Result:= E_UNKNOWN; // Unknown end; end; function RarExists(const FileName: String): Boolean; var Message: String; begin Result:= mbFileExists(FileName); if not Result then begin Message:= Format(rsMsgExecutableNotFound, [FileName]); gStartupInfo.MessageBox(PAnsiChar(Message), nil, MB_OK or MB_ICONERROR); end; end; function ExecuteRar(Process: TProcessUtf8; FileList : UnicodeString): Integer; var TempFile: THandle; S, FileName: String; Percent: Integer = 0; begin FileName:= GetTempName(''); TempFile:= mbFileCreate(FileName); if (TempFile = feInvalidHandle) then Exit(E_ECREATE); try FileWrite(TempFile, FileList[1], Length(FileList) * SizeOf(WideChar)); FileClose(TempFile); Process.Parameters.Add('@' + FileName); Process.Execute; if poUsePipes in Process.Options then begin S:= EmptyStr; SetLength(FileName, MAX_PATH); while Process.Running do begin if Process.Output.NumBytesAvailable = 0 then Sleep(100) else begin SetLength(FileName, Process.Output.Read(FileName[1], Length(FileName))); S+= FileName; Result:= Pos('%', S); if Result > 0 then begin TempFile:= Result - 1; while S[TempFile] in ['0'..'9'] do Dec(TempFile); if (Result - TempFile) > 1 then begin Percent:= StrToIntDef(Copy(S, TempFile + 1, Result - TempFile - 1), Percent); end; S:= EmptyStr; end; end; if ProcessDataProcW(nil, -(Percent + 1000)) = 0 then begin Process.Terminate(255); Exit(E_EABORTED); end; end; end; Process.WaitOnExit; Result:= RarToWcx(Process.ExitStatus); finally DeleteFile(FileName); end; end; procedure PackSetDefaultParams(dps: PPackDefaultParamStruct); dcpcall; export; begin IniFileName:= CeSysToUtf8(dps^.DefaultIniName); LoadConfig; end; procedure ConfigurePacker(Parent: HWND; DllInstance: THandle); dcpcall; export; begin CreateRarConfDlg; end; function DeleteFilesW(PackedFile, DeleteList: PWideChar): Integer; dcpcall; export; var Rar: String; Process : TProcessUtf8; FileName : UnicodeString; FileList : UnicodeString; FolderName: UnicodeString; begin Rar:= mbExpandEnvironmentStrings(WinRar); if not RarExists(Rar) then Exit(E_HANDLED); Process := TProcessUtf8.Create(nil); try Process.Executable:= Rar; Process.Parameters.Add('d'); Process.Parameters.Add('-c-'); Process.Parameters.Add('-r-'); Process.Parameters.Add(CeUtf16ToUtf8(UnicodeString(PackedFile))); try // Parse file list FileList:= UTF16LEBOM; while DeleteList^ <> #0 do begin FileName := DeleteList; // Convert PWideChar to UnicodeString (up to first #0). FileList += FileName + LineEndingW; // If ends with '*' then delete directory if FileName[Length(FileName)] = '*' then begin FolderName:= FileName; Delete(FolderName, Length(FileName) - 3, 4); FileList += FolderName + LineEndingW; end; DeleteList := DeleteList + Length(FileName) + 1; // move after filename and ending #0 end; Result:= ExecuteRar(Process, FileList); except Result:= E_EOPEN; end; finally Process.Free; end; end; function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer;dcpcall; export; const {$IF DEFINED(MSWINDOWS)} SFXExt = '.exe'; {$ELSE} SFXExt = '.run'; {$ENDIF} var Rar: String; Process : TProcessUtf8; FileList: UnicodeString; FileName: UnicodeString; FolderName: UnicodeString; Password: array[0..MAX_PATH] of AnsiChar; begin Rar:= mbExpandEnvironmentStrings(WinRar); if not RarExists(Rar) then Exit(E_HANDLED); Process := TProcessUtf8.Create(nil); try Process.Executable:= Rar; if FileIsConsoleExe(Process.Executable) then begin Process.Options:= [poUsePipes, poNoConsole, poNewProcessGroup]; end; if (Flags and PK_PACK_MOVE_FILES <> 0) then Process.Parameters.Add('m') else begin Process.Parameters.Add('a'); end; Process.Parameters.Add('-c-'); Process.Parameters.Add('-r-'); // Create solid archive if Solid then Process.Parameters.Add('-s'); // Compression method Process.Parameters.Add('-m' + IntToStr(Method)); if SameStr(ExtractFileExt(CeUtf16ToUtf8(UnicodeString(PackedFile))), SFXExt) then Process.Parameters.Add('-sfx'); // Add user command line parameters if Length(Args) > 0 then CommandToList(Args, Process.Parameters); // Add data recovery record if Recovery and (Pos('-rr', Args) = 0) then Process.Parameters.Add('-rr3p'); // Encrypt archive if (Flags and PK_PACK_ENCRYPT <> 0) then begin FillChar(Password, SizeOf(Password), #0); if gStartupInfo.InputBox('Rar', PAnsiChar(rsMsgPasswordEnter), True, PAnsiChar(Password), MAX_PATH) then begin if Encrypt then Process.Parameters.Add('-hp' + Password) else begin Process.Parameters.Add('-p' + Password); end; end else begin Exit(E_EABORTED); end; end; // Destination path if Assigned(SubPath) then begin Process.Parameters.Add('-ap' + CeUtf16ToUtf8(UnicodeString(SubPath))); end; Process.Parameters.Add(CeUtf16ToUtf8(UnicodeString(PackedFile))); // Source path if Assigned(SrcPath) then begin Process.CurrentDirectory:= CeUtf16ToUtf8(UnicodeString(SrcPath)); end; try // Parse file list FileList:= UTF16LEBOM; while AddList^ <> #0 do begin FileName := UnicodeString(AddList); FileList += FileName + LineEndingW; // If ends with '/' then add directory if FileName[Length(FileName)] = PathDelim then begin FolderName:= FileName; Delete(FolderName, Length(FileName), 1); FileList += FolderName + LineEndingW; end; Inc(AddList, Length(FileName) + 1); end; Result:= ExecuteRar(Process, FileList); except Result:= E_EOPEN; end; finally Process.Free; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/rarlng.pas���������������������������������������������������0000644�0001750�0000144�00000003767�14743153644�021015� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Rar archiver plugin, language support Copyright (C) 2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit RarLng; {$mode delphi} interface uses Classes, SysUtils; resourcestring rsMsgButtonCancel = '&Cancel'; rsMsgButtonExtract = '&Extract'; rsDictLargeWarning = 'Large dictionary warning'; rsMsgPasswordEnter = 'Please enter the password:'; rsDictNotAllowed = '%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack.'; rsMsgLibraryNotFound = 'Cannot load library %s! Please check your installation.'; rsMsgExecutableNotFound = 'Cannot find RAR executable!'#10#10'%s'#10#10'Please check the plugin settings.'; procedure TranslateResourceStrings; implementation uses UnRARFunc; function Translate(Name, Value: AnsiString; Hash: LongInt; Arg: Pointer): AnsiString; var ALen: Integer; begin with gStartupInfo do begin SetLength(Result, MaxSmallint); ALen:= TranslateString(Translation, PAnsiChar(Name), PAnsiChar(Value), PAnsiChar(Result), MaxSmallint); SetLength(Result, ALen); end; end; procedure TranslateResourceStrings; begin if Assigned(gStartupInfo.Translation) then begin SetResourceStrings(@Translate, nil); end; end; end. ���������doublecmd-1.1.22/plugins/wcx/unrar/src/unrar.dpr����������������������������������������������������0000644�0001750�0000144�00000002724�14743153644�020651� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library unrar; uses {$IFDEF UNIX} cthreads, {$ENDIF} FPCAdds, SysUtils, DynLibs, UnRARFunc, RarFunc, RarLng; exports { Mandatory } OpenArchive, OpenArchiveW, ReadHeader, ReadHeaderExW, ProcessFile, ProcessFileW, CloseArchive, SetChangeVolProc, SetChangeVolProcW, SetProcessDataProc, SetProcessDataProcW, { Optional } GetPackerCaps, PackFilesW, DeleteFilesW, ConfigurePacker, GetBackgroundFlags, PackSetDefaultParams, { Extension API } ExtensionInitialize; {$R *.res} begin ModuleHandle := LoadLibrary(_unrar); {$IF DEFINED(LINUX)} if ModuleHandle = NilHandle then ModuleHandle := LoadLibrary(_unrar + '.5'); {$ENDIF} if ModuleHandle = NilHandle then ModuleHandle := LoadLibrary(GetEnvironmentVariable('COMMANDER_PATH') + PathDelim + _unrar); if ModuleHandle <> NilHandle then begin RAROpenArchiveEx := TRAROpenArchiveEx(GetProcAddress(ModuleHandle, 'RAROpenArchiveEx')); RARCloseArchive := TRARCloseArchive(GetProcAddress(ModuleHandle, 'RARCloseArchive')); RARReadHeaderEx := TRARReadHeaderEx(GetProcAddress(ModuleHandle, 'RARReadHeaderEx')); RARProcessFileW := TRARProcessFileW(GetProcAddress(ModuleHandle, 'RARProcessFileW')); RARSetCallback := TRARSetCallback(GetProcAddress(ModuleHandle, 'RARSetCallback')); RARSetPassword := TRARSetPassword(GetProcAddress(ModuleHandle, 'RARSetPassword')); RARGetDllVersion := TRARGetDllVersion(GetProcAddress(ModuleHandle, 'RARGetDllVersion')); end; end. ��������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/unrar.lpi����������������������������������������������������0000644�0001750�0000144�00000010451�14743153644�020644� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <SaveClosedFiles Value="False"/> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="2"/> <StringTable FileDescription="UnRAR WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2020 Alexander Koblov"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\unrar.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <ConfigFile> <CustomConfigFile Value="True"/> <ConfigFilePath Value="fpc-extra.cfg"/> </ConfigFile> </Other> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> <MinVersion Minor="2" Valid="True"/> </Item1> </RequiredPackages> <Units Count="1"> <Unit0> <Filename Value="unrar.dpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\unrar.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> <ConfigFile> <CustomConfigFile Value="True"/> <ConfigFilePath Value="fpc-extra.cfg"/> </ConfigFile> </Other> </CompilerOptions> </CONFIG> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/unrar/src/unrarfunc.pas������������������������������������������������0000644�0001750�0000144�00000043103�14743153644�021517� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WCX plugin for unpacking RAR archives This is simple wrapper for unrar.dll or libunrar.so Copyright (C) 2008-2024 Alexander Koblov (alexx2000@mail.ru) 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 in a file called COPYING along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } unit UnRARFunc; {$mode objfpc}{$H+} {$if FPC_FULLVERSION >= 30300} {$modeswitch arraytodynarray} {$endif} {$include calling.inc} interface uses DynLibs, WcxPlugin, Extension; const {$IF DEFINED(MSWINDOWS)} // libunrar must be built with sizeof(wchar_t) = 2 (default on Windows) _unrar = 'unrar.dll'; {$ELSEIF DEFINED(DARWIN)} // libunrar must be built with sizeof(wchar_t) = 4 (default on Unix) _unrar = 'libunrar.dylib'; {$ELSEIF DEFINED(UNIX)} // libunrar must be built with sizeof(wchar_t) = 4 (default on Unix) _unrar = 'libunrar.so'; {$ENDIF} const // Unrar callback messages. UCM_CHANGEVOLUME = 0; UCM_PROCESSDATA = 1; UCM_NEEDPASSWORD = 2; UCM_CHANGEVOLUMEW = 3; UCM_NEEDPASSWORDW = 4; UCM_LARGEDICT = 5; // Main header flags. MHD_VOLUME = $0001; MHD_COMMENT = $0002; MHD_LOCK = $0004; MHD_SOLID = $0008; MHD_PACK_COMMENT = $0010; MHD_NEWNUMBERING = $0010; MHD_AV = $0020; // (archive signed) MHD_PROTECT = $0040; MHD_PASSWORD = $0080; MHD_FIRSTVOLUME = $0100; MHD_ENCRYPTVER = $0200; type {$IFDEF UNIX} TRarUnicodeChar = UCS4Char; TRarUnicodeString = UCS4String; {$ENDIF} {$IFDEF WINDOWS} TRarUnicodeChar = WideChar; // assuming 2 byte WideChar TRarUnicodeString = UnicodeString; {$ENDIF} PRarUnicodeChar = ^TRarUnicodeChar; TRarUnicodeArray = packed array [0..1023] of TRarUnicodeChar; RARHeaderDataEx = packed record ArcName: packed array [0..1023] of Char; ArcNameW: TRarUnicodeArray; FileName: packed array [0..1023] of Char; FileNameW: TRarUnicodeArray; Flags: LongWord; PackSize: LongWord; PackSizeHigh: LongWord; UnpSize: LongWord; UnpSizeHigh: LongWord; HostOS: LongWord; FileCRC: LongWord; FileTime: LongWord; UnpVer: LongWord; Method: LongWord; FileAttr: LongWord; CmtBuf: PChar; CmtBufSize: LongWord; CmtSize: LongWord; CmtState: LongWord; DictSize: LongWord; HashType: LongWord; Hash: array[0..31] of Byte; RedirType: LongWord; RedirName: PRarUnicodeChar; RedirNameSize: LongWord; DirTarget: LongWord; MtimeLow: LongWord; MtimeHigh: LongWord; CtimeLow: LongWord; CtimeHigh: LongWord; AtimeLow: LongWord; AtimeHigh: LongWord; ArcNameEx: PRarUnicodeChar; ArcNameExSize: LongWord; FileNameEx: PRarUnicodeChar; FileNameExSize: LongWord; Reserved: packed array [0..981] of LongWord; end; {$IFDEF MSWINDOWS}{$CALLING STDCALL}{$ELSE}{$CALLING CDECL}{$ENDIF} TUnrarCallback = function(Msg: LongWord; UserData, P1: Pointer; P2: PtrInt): Integer; RAROpenArchiveDataEx = packed record ArcName: PAnsiChar; ArcNameW: PRarUnicodeChar; OpenMode: LongWord; OpenResult: LongWord; CmtBuf: PChar; CmtBufSize: LongWord; CmtSize: LongWord; CmtState: LongWord; Flags: LongWord; Callback: TUnrarCallback; UserData: PtrInt; Reserved: packed array [0..27] of LongWord; end; TRAROpenArchiveEx = function(var ArchiveData: RAROpenArchiveDataEx) : TArcHandle; TRARCloseArchive = function(hArcData: TArcHandle) : Integer; TRARReadHeaderEx = function (hArcData: TArcHandle; var HeaderData: RARHeaderDataEx) : Integer; TRARProcessFileW = function(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PRarUnicodeChar) : Integer; TRARSetCallback = procedure(hArcData: TArcHandle; UnrarCallback: TUnrarCallback; UserData: PtrInt); TRARSetPassword = procedure(hArcData: TArcHandle; Password: PChar); TRARGetDllVersion = function: Integer; {$CALLING DEFAULT} var RAROpenArchiveEx : TRAROpenArchiveEx = nil; RARCloseArchive : TRARCloseArchive = nil; RARReadHeaderEx : TRARReadHeaderEx = nil; RARProcessFileW : TRARProcessFileW = nil; RARSetCallback : TRARSetCallback = nil; RARSetPassword : TRARSetPassword = nil; RARGetDllVersion : TRARGetDllVersion = nil; ModuleHandle : TLibHandle = NilHandle; { Mandatory } function OpenArchive(var ArchiveData: TOpenArchiveData) : TArcHandle; dcpcall; export; function OpenArchiveW(var ArchiveData: tOpenArchiveDataW) : TArcHandle; dcpcall; export; function ReadHeader(hArcData: TArcHandle; var HeaderData: THeaderData) : Integer; dcpcall; export; function ReadHeaderExW(hArcData: TArcHandle; var HeaderData: THeaderDataExW) : Integer; dcpcall; export; function ProcessFile(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PAnsiChar) : Integer; dcpcall; export; function ProcessFileW(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PWideChar) : Integer; dcpcall; export; function CloseArchive(hArcData: TArcHandle): Integer; dcpcall; export; procedure SetChangeVolProc(hArcData : TArcHandle; pChangeVolProc : TChangeVolProc); dcpcall; export; procedure SetChangeVolProcW(hArcData : TArcHandle; pChangeVolProc : TChangeVolProcW); dcpcall; export; procedure SetProcessDataProc(hArcData : TArcHandle; pProcessDataProc : TProcessDataProc); dcpcall; export; procedure SetProcessDataProcW(hArcData : TArcHandle; pProcessDataProc : TProcessDataProcW); dcpcall; export; { Optional } function GetPackerCaps : Integer; dcpcall; export; function GetBackgroundFlags: Integer; dcpcall; export; { Extension API } procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); dcpcall; export; var gStartupInfo: TExtensionStartupInfo; threadvar ProcessDataProcW : TProcessDataProcW; implementation uses SysUtils, DCBasicTypes, DCDateTimeUtils, DCConvertEncoding, DCFileAttributes, RarLng; type // From libunrar (dll.hpp) RarHostSystem = ( HOST_MSDOS = 0, HOST_OS2 = 1, HOST_WIN32 = 2, HOST_UNIX = 3, HOST_MACOS = 4, HOST_BEOS = 5, HOST_MAX ); TRARHandle = class Handle: TArcHandle; ChangeVolProcW: TChangeVolProcW; ProcessDataProcW: TProcessDataProcW; ProcessFileNameW: array [0..1023] of WideChar; end; function StrLCopy(Dest, Source: PRarUnicodeChar; MaxLen: SizeInt): PRarUnicodeChar; overload; var ACounter: SizeInt; begin ACounter := 0; while (Source[ACounter] <> TRarUnicodeChar(0)) and (ACounter < MaxLen) do begin Dest[ACounter] := TRarUnicodeChar(Source[ACounter]); Inc(ACounter); end; Dest[ACounter] := TRarUnicodeChar(0); StrLCopy := Dest; end; procedure StringToArrayW(src: UnicodeString; pDst: PWideChar; MaxDstLength: Integer); begin if Length(src) < MaxDstLength then MaxDstLength := Length(src) else MaxDstLength := MaxDstLength - 1; // for ending #0 if Length(src) > 0 then Move(src[1], pDst^, SizeOf(WideChar) * MaxDstLength); pDst[MaxDstLength] := WideChar(0); end; function RarUnicodeStringToWideString(src: TRarUnicodeString): UnicodeString; begin {$IFDEF UNIX} Result := UCS4StringToUnicodeString(src); {$ELSE} Result := src; {$ENDIF} end; function WideStringToRarUnicodeString(src: UnicodeString): TRarUnicodeString; begin {$IFDEF UNIX} Result := UnicodeStringToUCS4String(src); {$ELSE} Result := src; {$ENDIF} end; function GetSystemSpecificFileTime(FileTime: LongInt) : LongInt; begin Result := FileTime; {$IFDEF UNIX} Result := LongInt(DateTimeToUnixFileTime(DosFileTimeToDateTime(TDosFileTime(Result)))); {$ENDIF} end; function GetSystemSpecificAttributes(HostOS: RarHostSystem; Attrs: LongInt): LongInt; begin Result := Attrs; {$IFDEF MSWINDOWS} if (HostOS = HOST_UNIX) or // Ugly hack: $1FFFF is max value of attributes on Windows (Result > $1FFFF) then begin Result := LongInt(UnixToWinFileAttr(TFileAttrs(Attrs))); end; {$ENDIF} {$IFDEF UNIX} if HostOS in [HOST_MSDOS, HOST_WIN32] then Result := LongInt(WinToUnixFileAttr(TFileAttrs(Result))); {$ENDIF} end; function UnrarCallback(Msg: LongWord; UserData, P1: Pointer; P2: PtrInt) : Integer; dcpcall; const Giga = 1024 * 1024; var PasswordU: String; Buttons: PPAnsiChar; DictSize: UIntPtr absolute P1; VolumeNameA: TRarUnicodeArray; VolumeNameU: TRarUnicodeString; PasswordA: array[0..511] of AnsiChar; AHandle: TRARHandle absolute UserData; VolumeNameW: array [0..1023] of WideChar; begin Result := 0; case Msg of UCM_CHANGEVOLUMEW: begin if Assigned(AHandle.ChangeVolProcW) then begin Move(PRarUnicodeChar(P1)^, VolumeNameA[0], SizeOf(TRarUnicodeArray)); VolumeNameW := RarUnicodeStringToWideString(VolumeNameA); if AHandle.ChangeVolProcW(VolumeNameW, LongInt(P2)) = 0 then Result := -1 else begin Result := 1; if (P2 = PK_VOL_ASK) then begin VolumeNameU := WideStringToRarUnicodeString(VolumeNameW); Move(PRarUnicodeChar(VolumeNameU)^, P1^, SizeOf(TRarUnicodeArray)); end; end; end else begin Result := -1; end; end; UCM_PROCESSDATA: begin // P1 - pointer to data buffer (first param of ProcessDataProc) // P2 - number of bytes in the buffer (second param of ProcessDataProc) if Assigned(AHandle.ProcessDataProcW) then begin if AHandle.ProcessDataProcW(PWideChar(AHandle.ProcessFileNameW), LongInt(P2)) = 0 then Result := -1; end; end; UCM_NEEDPASSWORDW: begin // DLL needs a password to process archive. This message must be // processed if you wish to be able to handle encrypted archives. // Return zero or a positive value to continue process or -1 // to cancel the archive operation. // P1 - contains the address pointing to the buffer for a password. // You need to copy a password here. // P2 - contains the size of password buffer in characters. StrLCopy(VolumeNameA, PRarUnicodeChar(P1), High(VolumeNameA)); PasswordU := CeUtf16ToUtf8(RarUnicodeStringToWideString(VolumeNameA)); StrLCopy(PasswordA, PAnsiChar(PasswordU), High(PasswordA)); if not gStartupInfo.InputBox('Unrar', 'Please enter the password:', True, PasswordA, High(PasswordA)) then Result := -1 else begin Result := 1; StrPLCopy(VolumeNameW, CeUtf8ToUtf16(PasswordA), High(VolumeNameW)); StrLCopy(PRarUnicodeChar(P1), PRarUnicodeChar(WideStringToRarUnicodeString(VolumeNameW)), P2 - 1); end; end; UCM_LARGEDICT: begin P2:= P2 div Giga; DictSize:= (DictSize div Giga) + Ord((DictSize mod Giga <> 0)); Buttons:= ArrayStringToPPchar([rsMsgButtonExtract, rsMsgButtonCancel], 0); try PasswordU:= Format(rsDictNotAllowed, [DictSize, P2, DictSize]) + LineEnding; if gStartupInfo.MsgChoiceBox(PAnsiChar(PasswordU), PAnsiChar(rsDictLargeWarning), Buttons, 0, 1) = 0 then Result:= 1 else begin Result:= -1; end; finally FreeMem(Buttons); end; end; end; end; function OpenArchive(var ArchiveData: TOpenArchiveData) : TArcHandle; dcpcall; export; begin Result := 0; ArchiveData.OpenResult := E_NOT_SUPPORTED; end; function OpenArchiveW(var ArchiveData: tOpenArchiveDataW): TArcHandle; dcpcall; export; var RarArcName: TRarUnicodeString; AHandle: TRARHandle absolute Result; RarArchiveData: RAROpenArchiveDataEx; begin if (RAROpenArchiveEx = nil) then begin Result := 0; ArchiveData.OpenResult := E_EOPEN; end else begin AHandle:= TRARHandle.Create; RarArcName := WideStringToRarUnicodeString(ArchiveData.ArcName); RarArchiveData := Default(RAROpenArchiveDataEx); RarArchiveData.ArcNameW := PRarUnicodeChar(RarArcName); RarArchiveData.OpenMode := ArchiveData.OpenMode; RarArchiveData.Callback := @UnrarCallback; RarArchiveData.UserData := PtrInt(Result); AHandle.Handle := RAROpenArchiveEx(RarArchiveData); ArchiveData.OpenResult := RarArchiveData.OpenResult; if AHandle.Handle = 0 then FreeAndNil(AHandle) else begin ArchiveData.CmtSize := RarArchiveData.CmtSize; ArchiveData.CmtState := RarArchiveData.CmtState; RARSetCallback(AHandle.Handle, @UnrarCallback, PtrInt(Result)); end; end; end; function ReadHeader(hArcData: TArcHandle; var HeaderData: THeaderData) : Integer; dcpcall; export; begin Result := E_NOT_SUPPORTED; end; function ReadHeaderExW(hArcData: TArcHandle; var HeaderData: THeaderDataExW) : Integer; dcpcall; export; var RarHeader: RARHeaderDataEx; AHandle: TRARHandle absolute hArcData; begin if (RARReadHeaderEx = nil) then Result := E_EREAD else begin RarHeader:= Default(RARHeaderDataEx); RarHeader.CmtBuf := HeaderData.CmtBuf; RarHeader.CmtBufSize := HeaderData.CmtBufSize; Result := RARReadHeaderEx(AHandle.Handle, RarHeader); if Result <> E_SUCCESS then Exit; {$PUSH}{$Q-}{$R-} StringToArrayW( RarUnicodeStringToWideString(TRarUnicodeString(RarHeader.ArcNameW)), @HeaderData.ArcName, SizeOf(HeaderData.ArcName)); StringToArrayW( RarUnicodeStringToWideString(TRarUnicodeString(RarHeader.FileNameW)), @HeaderData.FileName, SizeOf(HeaderData.FileName)); HeaderData.Flags := RarHeader.Flags; HeaderData.PackSize := RarHeader.PackSize; HeaderData.PackSizeHigh := RarHeader.PackSizeHigh; HeaderData.UnpSize := RarHeader.UnpSize; HeaderData.UnpSizeHigh := RarHeader.UnpSizeHigh; HeaderData.HostOS := RarHeader.HostOS; HeaderData.FileCRC := RarHeader.FileCRC; HeaderData.FileTime := RarHeader.FileTime; HeaderData.UnpVer := RarHeader.UnpVer; HeaderData.Method := RarHeader.Method; HeaderData.FileAttr := RarHeader.FileAttr; HeaderData.CmtSize := RarHeader.CmtSize; HeaderData.CmtState := RarHeader.CmtState; HeaderData.FileAttr := GetSystemSpecificAttributes(RarHostSystem(HeaderData.HostOS), HeaderData.FileAttr); HeaderData.FileTime := GetSystemSpecificFileTime(HeaderData.FileTime); Int64Rec(HeaderData.MfileTime).Lo:= RarHeader.MtimeLow; Int64Rec(HeaderData.MfileTime).Hi:= RarHeader.MtimeHigh; {$POP} AHandle.ProcessFileNameW := HeaderData.FileName; end; end; function ProcessFile(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PAnsiChar) : Integer; dcpcall; export; begin Result := E_NOT_SUPPORTED; end; function ProcessFileW(hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PWideChar) : Integer; dcpcall; export; var pwcDestPath: PRarUnicodeChar = nil; pwcDestName: PRarUnicodeChar = nil; AHandle: TRARHandle absolute hArcData; SysSpecDestPath, SysSpecDestName: TRarUnicodeString; begin if (RARProcessFileW = nil) then Result := E_EREAD else begin if DestPath <> nil then begin SysSpecDestPath:= WideStringToRarUnicodeString(DestPath); pwcDestPath := PRarUnicodeChar(SysSpecDestPath); end; if DestName <> nil then begin SysSpecDestName:= WideStringToRarUnicodeString(DestName); pwcDestName := PRarUnicodeChar(SysSpecDestName); end; Result := RARProcessFileW(AHandle.Handle, Operation, pwcDestPath, pwcDestName); end; end; function CloseArchive(hArcData: TArcHandle) : Integer;dcpcall; export; var AHandle: TRARHandle absolute hArcData; begin if (RARCloseArchive = nil) then Result := E_ECLOSE else begin Result := RARCloseArchive(AHandle.Handle); end; AHandle.Free; end; procedure SetChangeVolProc(hArcData: TArcHandle; pChangeVolProc: TChangeVolProc); dcpcall; export; begin end; procedure SetProcessDataProc(hArcData : TArcHandle; pProcessDataProc : TProcessDataProc); dcpcall; export; begin end; procedure SetChangeVolProcW(hArcData: TArcHandle; pChangeVolProc: TChangeVolProcW); dcpcall; export; var AHandle: TRARHandle absolute hArcData; begin if (hArcData <> wcxInvalidHandle) then AHandle.ChangeVolProcW := pChangeVolProc end; procedure SetProcessDataProcW(hArcData : TArcHandle; pProcessDataProc : TProcessDataProcW); dcpcall; export; var AHandle: TRARHandle absolute hArcData; begin if (hArcData <> wcxInvalidHandle) then AHandle.ProcessDataProcW := pProcessDataProc else begin ProcessDataProcW := pProcessDataProc; end; end; function GetPackerCaps: Integer; dcpcall; export; begin Result := PK_CAPS_MULTIPLE or PK_CAPS_BY_CONTENT or PK_CAPS_NEW or PK_CAPS_MODIFY or PK_CAPS_DELETE or PK_CAPS_OPTIONS or PK_CAPS_ENCRYPT; end; function GetBackgroundFlags: Integer; dcpcall; export; begin Result:= BACKGROUND_UNPACK or BACKGROUND_PACK; end; procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); dcpcall; export; begin gStartupInfo := StartupInfo^; TranslateResourceStrings; if ModuleHandle = NilHandle then begin gStartupInfo.MessageBox(PAnsiChar(Format(rsMsgLibraryNotFound, [_unrar])), nil, MB_OK or MB_ICONERROR); end; end; finalization if ModuleHandle <> 0 then UnloadLibrary(ModuleHandle); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015672� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/COPYING.txt��������������������������������������������������������0000644�0001750�0000144�00000043131�14743153644�017545� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 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. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 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. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017455� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.be.po�������������������������������������������������0000644�0001750�0000144�00000003457�14743153644�021215� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n%100>=11 && n%100<=14 ? 2 : 3);\n" "X-Crowdin-Project: b5aaebc75354984d7cee90405a1f6642\n" "X-Crowdin-Project-ID: 7\n" "X-Crowdin-Language: be\n" "X-Crowdin-File: /l10n_Translation/plugins/wcx/zip/language/zip.po\n" "X-Crowdin-File-ID: 3350\n" "Project-Id-Version: b5aaebc75354984d7cee90405a1f6642\n" "Language-Team: Belarusian\n" "Language: be_BY\n" "PO-Revision-Date: 2022-09-25 05:45\n" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "Канфігурацыя Zip-убудовы" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "Zip-убудова сумяшчальная з PKZIP, TAR, XZ, GZip, Zstandard і BZip2, падтрымлівае сцісканне і архівацыю даных." #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "Сцісканне" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "Метад сціскання:" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "Узровень сціскання:" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr "Адкрываць архівы *.tar.xyz за адзін крок (павольна з вялікімі архівамі)" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "Скасаваць" #: tdialogbox.btnOK.caption msgid "OK" msgstr "ДОБРА" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.de.po�������������������������������������������������0000644�0001750�0000144�00000003760�14743153644�021214� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Project-Id-Version: Double Commander Plugin 'zip'\n" "POT-Creation-Date: \n" "PO-Revision-Date: 2024-11-01 18:01+0100\n" "Last-Translator: ㋡ <braass@mail.de>\n" "Language-Team: Deutsch <braass@mail.de>\n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0.1\n" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "Zip-Plugin Konfiguration" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "Zip-Plugin unterstützt PKZIP-kompatible, TAR, XZ, GZip, Zstandard and BZip2 Komprimierung und Archivierung von Daten." #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "Komprimierung" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "Format des Archivs:" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "Komprimierungsmethode:" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "Komprimierungsgrad:" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr "*.tar.xyz Archive in einem Schritt öffnen (langsam bei großen Archiven)" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "Abbrechen" #: tdialogbox.btnOK.caption msgid "OK" msgstr "OK" #: ziplng.rscompressionmethodstore msgid "Store" msgstr "Speichern" #: ziplng.rscompressionmethodoptimal msgid "Optimal (2x slower)" msgstr "Optimal (2x langsamer)" #: ziplng.rscompressionlevelfastest msgid "Fastest" msgstr "Am schnellsten" #: ziplng.rscompressionlevelfast msgid "Fast" msgstr "Schnell" #: ziplng.rscompressionlevelnormal msgid "Normal" msgstr "Normal" #: ziplng.rscompressionlevelmaximum msgid "Maximum" msgstr "Maximum" #: ziplng.rscompressionlevelultra msgid "Ultra" msgstr "Extrem" ����������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.hu.po�������������������������������������������������0000644�0001750�0000144�00000002730�14743153644�021234� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Project-Id-Version: Double Commander Zip WCX plugin\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Forge Studios Ltd. <kroy <kroysoft@citromail.hu>>\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: hu\n" "X-Generator: Poedit 1.8.8\n" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "Zip plugin beállítások" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "A Zip plugin a PKZIP-kompatibilis, TAR, XZ, GZip, Zstandard és BZip2 adattömörítést és archiválást támogatja." #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "Tömörítés" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "Tömörítési módszer:" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "Tömörítési szint:" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr "Nyissa meg a * .tar.xyz archívumokat egy lépésben (nagy archívumokkal lassú)" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "Mégsem" #: tdialogbox.btnOK.caption msgid "OK" msgstr "OK" ����������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.ko.po�������������������������������������������������0000644�0001750�0000144�00000004006�14743153644�021227� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Project-Id-Version: Double Commander Plugin - wcx\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: VenusGirl: https://venusgirls.tistory.com/\n" "Language-Team: 비너스걸: https://venusgirls.tistory.com/\n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Native-Language: 한국어\n" "X-Generator: Poedit 3.4.2\n" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "Zip 플러그인 구성" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "Zip 플러그인은 PKZIP 호환, TAR, XZ, GZip, Zstandard 및 BZip2 데이터 압축 및 보관을 지원합니다." #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "압축" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "압축 형식:" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "압축 방법:" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "압축 수준:" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr ".tar.xyz 압축파일을 한 번에 열기 (대용량 압축파일은 천천히)" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "취소" #: tdialogbox.btnOK.caption msgid "OK" msgstr "확인" #: ziplng.rscompressionmethodstore msgid "Store" msgstr "저장" #: ziplng.rscompressionmethodoptimal msgid "Optimal (2x slower)" msgstr "최적 (2배 느림)" #: ziplng.rscompressionlevelfastest msgid "Fastest" msgstr "가장 빠른" #: ziplng.rscompressionlevelfast msgid "Fast" msgstr "빠른" #: ziplng.rscompressionlevelnormal msgid "Normal" msgstr "일반" #: ziplng.rscompressionlevelmaximum msgid "Maximum" msgstr "최대" #: ziplng.rscompressionlevelultra msgid "Ultra" msgstr "울트라" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.po����������������������������������������������������0000644�0001750�0000144�00000002516�14743153644�020623� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "" #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr "" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "" #: tdialogbox.btnOK.caption msgid "OK" msgstr "" #: ziplng.rscompressionmethodstore msgid "Store" msgstr "" #: ziplng.rscompressionmethodoptimal msgid "Optimal (2x slower)" msgstr "" #: ziplng.rscompressionlevelfastest msgid "Fastest" msgstr "" #: ziplng.rscompressionlevelfast msgid "Fast" msgstr "" #: ziplng.rscompressionlevelnormal msgid "Normal" msgstr "" #: ziplng.rscompressionlevelmaximum msgid "Maximum" msgstr "" #: ziplng.rscompressionlevelultra msgid "Ultra" msgstr "" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.ru.po�������������������������������������������������0000644�0001750�0000144�00000003610�14743153644�021244� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "Настройки Zip-плагина" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "Плагин Zip поддерживает PKZIP-совместимое, TAR, XZ, GZip, Zstandard и BZip2 сжатие и архивирование данных." #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "Cжатие" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "Формат архива:" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "Метод сжатия:" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "Уровень сжатия:" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr "Открывать архивы *.tar.xyz за один шаг (медленно с большими архивами)" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "Отмена" #: tdialogbox.btnOK.caption msgid "OK" msgstr "OK" #: ziplng.rscompressionmethodstore msgid "Store" msgstr "Без сжатия" #: ziplng.rscompressionmethodoptimal msgid "Optimal (2x slower)" msgstr "Оптимальный (медленно)" #: ziplng.rscompressionlevelfastest msgid "Fastest" msgstr "Скоростной" #: ziplng.rscompressionlevelfast msgid "Fast" msgstr "Быстрый" #: ziplng.rscompressionlevelnormal msgid "Normal" msgstr "Нормальный" #: ziplng.rscompressionlevelmaximum msgid "Maximum" msgstr "Максимальный" #: ziplng.rscompressionlevelultra msgid "Ultra" msgstr "Ультра" ������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/language/zip.zh_CN.po����������������������������������������������0000644�0001750�0000144�00000002107�14743153644�021617� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.caption msgid "Zip plugin configuration" msgstr "Zip插件配置" #: tdialogbox.lblAbout.caption msgid "Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving." msgstr "Zip 插件支持 PKZIP 兼容、TAR、XZ、GZip、Zstandard 和 BZip2 数据压缩和归档." #: tdialogbox.gbCompression.caption msgid "Compression" msgstr "压缩" #: tdialogbox.gbCompression.lblArchiveFormat.caption msgid "Archive format:" msgstr "" #: tdialogbox.gbCompression.lblCompressionMethod.caption msgid "Compression method:" msgstr "压缩方式:" #: tdialogbox.gbCompression.lblCompressionLevel.caption msgid "Compression level:" msgstr "压缩级别:" #: tdialogbox.chkTarAutoHandle.caption msgid "Open *.tar.xyz archives at one step (slowly with big archives)" msgstr "一步打开 *.tar.xyz 文件(大文件打开慢)" #: tdialogbox.btnCancel.caption msgid "Cancel" msgstr "取消" #: tdialogbox.btnOK.caption msgid "OK" msgstr "确定" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016461� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/Zip.dpr��������������������������������������������������������0000644�0001750�0000144�00000001104�14743153644�017726� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library Zip; uses {$IFDEF UNIX} cthreads, {$ENDIF} FPCAdds, SysUtils, Classes, ZipFunc, ZipOpt; exports { Mandatory } OpenArchive, OpenArchiveW, ReadHeader, ReadHeaderExW, ProcessFile, ProcessFileW, CloseArchive, SetChangeVolProc, SetChangeVolProcW, SetProcessDataProc, SetProcessDataProcW, { Optional } PackFilesW, DeleteFilesW, GetPackerCaps, ConfigurePacker, GetBackgroundFlags, CanYouHandleThisFileW, { Extension API } ExtensionInitialize; {$R *.res} begin {$IFDEF UNIX} WriteLn('Zip plugin is loaded'); {$ENDIF} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/Zip.lpi��������������������������������������������������������0000644�0001750�0000144�00000012030�14743153644�017725� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="2"/> <StringTable FileDescription="ZIP WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2019 Alexander Koblov"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../zip.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="fparchive;../../../../sdk;lzma/compression/LZ;lzma/compression/LZMA;lzma/compression/RangeCoder"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <ConfigFile> <CustomConfigFile Value="True"/> <ConfigFilePath Value="fpc-extra.cfg"/> </ConfigFile> </Other> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="2"> <Item1> <PackageName Value="kascrypt"/> <MinVersion Major="3" Minor="1" Valid="True"/> </Item1> <Item2> <PackageName Value="doublecmd_common"/> <MinVersion Minor="2" Valid="True"/> </Item2> </RequiredPackages> <Units Count="2"> <Unit0> <Filename Value="Zip.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="ZipFunc.pas"/> <IsPartOfProject Value="True"/> </Unit1> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../zip.wcx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="fparchive;../../../../sdk;lzma/compression/LZ;lzma/compression/LZMA;lzma/compression/RangeCoder"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> <ConfigFile> <CustomConfigFile Value="True"/> <ConfigFilePath Value="fpc-extra.cfg"/> </ConfigFile> </Other> </CompilerOptions> </CONFIG> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipApp.pas�����������������������������������������������������0000644�0001750�0000144�00000013500�14743153644�020370� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ZipApp.pas *} {*********************************************************} {* ABBREVIA: Additional classes and routines *} {*********************************************************} unit ZipApp; {$mode objfpc}{$H+} interface uses Classes, SysUtils, AbArcTyp, AbZipKit, AbUtils; const {$IF DEFINED(MSWINDOWS)} faFolder = faDirectory; {$ELSE} faFolder = AB_FMODE_DIR or AB_FPERMISSION_GENERIC or AB_FPERMISSION_OWNEREXECUTE; {$ENDIF} type { TAbArchiveItemHelper } TAbArchiveItemHelper = class helper for TAbArchiveItem function MatchesPath(const Path : String; Recursive : Boolean = False) : Boolean; function MatchesPathEx(const Paths : String; Recursive : Boolean = False) : Boolean; end; { TAbArchiveAccess } TAbArchiveAccess = class(TAbArchive) end; { TAbZipKit } TAbZipKit = class(TAbCustomZipKit) public {en Delete one file from archive } procedure DeleteFile(const aFileName : String); {en Get the normalized file name } function GetFileName(aFileIndex: Integer): String; {en Delete directory entry and all file and directory entries matching the same path recursively } procedure DeleteDirectoriesRecursively(const Paths : String); {en Test specific item in the archive } procedure TestItemAt(Index : Integer); end; {en See if DirPath matches PathToMatch. If Recursive=True it is allowed for DirPath to point to a subdirectory of PathToMatch, for example: PathToMatch = 'dir/', DirPath = 'dir/subdir' - Result is True. } function AbDirMatch(DirPath : String; PathToMatch : String; Recursive : Boolean) : Boolean; {en From a list of paths separated with AbPathSep (';') extracts a path from the position StartPos (counted from 1) and modifies StartPos to point to next entry. When no more entries are found, returns empty string. } function AbExtractEntry(const Entries : String; var StartPos : Integer) : String; implementation uses AbExcept, DCStrUtils; { TAbArchiveItemHelper } function TAbArchiveItemHelper.MatchesPath(const Path: String; Recursive: Boolean): Boolean; var Value : string; Drive, Dir, Name : string; begin Value := Path; if (Value <> '') and (RightStr(Value, 1) <> AbPathDelim) then Value := Value + AbPathDelim; AbUnfixName(Value); AbParseFileName(Path, Drive, Dir, Name); Value := Dir + Name; Name := FileName; AbUnfixName(Name); Result := AbDirMatch(Name, Value, Recursive); end; function TAbArchiveItemHelper.MatchesPathEx(const Paths: String; Recursive: Boolean): Boolean; var Position: Integer; Path: String; begin Result := True; Position := 1; while True do begin Path := AbExtractEntry(Paths, Position); if Path = '' then Break; if MatchesPath(Path, Recursive) then Exit; end; Result := False; end; { TAbZipKit } procedure TAbZipKit.DeleteFile(const aFileName: String); var I : Integer; begin TAbArchiveAccess(Archive).CheckValid; if Count > 0 then begin for I := Pred(Count) downto 0 do begin with Archive.ItemList[I] do begin if CompareStr(GetFileName(I), aFileName) = 0 then begin DeleteAt(I); Break; end; end; end; end; end; function TAbZipKit.GetFileName(aFileIndex: Integer): String; begin Result := Items[aFileIndex].FileName; if (ArchiveType in [atGzip, atGzippedTar]) and (Result = 'unknown') then begin Result := ExtractOnlyFileName(FileName); if (ArchiveType = atGzippedTar) then begin if (TarAutoHandle = False) and (ExtractOnlyFileExt(Result) <> 'tar') then Result := Result + '.tar'; end; end; DoDirSeparators(Result); Result := ExcludeFrontPathDelimiter(Result); Result := ExcludeTrailingPathDelimiter(Result); end; procedure TAbZipKit.DeleteDirectoriesRecursively(const Paths: String); var I : Integer; begin TAbArchiveAccess(Archive).CheckValid; if Count > 0 then begin for I := Pred(Count) downto 0 do begin with Archive.ItemList[I] do if MatchesPathEx(Paths, True) then DeleteAt(I); end; end; end; procedure TAbZipKit.TestItemAt(Index: Integer); begin if (Archive <> nil) then TAbArchiveAccess(Archive).TestAt(Index) else raise EAbNoArchive.Create; end; function AbDirMatch(DirPath : String; PathToMatch : String; Recursive : Boolean) : Boolean; begin if Recursive then PathToMatch := PathToMatch + '*'; // append wildcard Result := AbPatternMatch(DirPath, 1, PathToMatch, 1); end; function AbExtractEntry(const Entries : String; var StartPos : Integer) : String; var I : Integer; Len: Integer; begin Result := ''; Len := Length(Entries); I := StartPos; if (I >= 1) and (I <= Len) then begin while (I <= Len) and (Entries[I] <> AbPathSep) do Inc(I); Result := Copy(Entries, StartPos, I - StartPos); if (I <= Len) and (Entries[I] = AbPathSep) then Inc(I); StartPos := I; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipCache.pas���������������������������������������������������0000644�0001750�0000144�00000004706�14743153644�020663� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ZipCache; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, SyncObjs, fpTimer; type { TPasswordCache } TPasswordCache = class private FTimer: TFPTimer; FArchiveSize: Int64; FArchiveName: String; FArchiveTime: Integer; FMutex: TCriticalSection; FArchivePassword: String; const FInterval: Cardinal = 120000; private procedure ResetTimer; procedure ZeroPassword; procedure TimerEvent(Sender: TObject); public constructor Create; destructor Destroy; override; function GetPassword(const Archive: String): String; procedure SetPassword(const Archive: String; const Password: String); end; implementation uses LazFileUtils; { TPasswordCache } procedure TPasswordCache.ResetTimer; begin if FTimer.Interval > FInterval then FTimer.Interval:= FTimer.Interval - 1 else FTimer.Interval:= FTimer.Interval + 1; end; procedure TPasswordCache.ZeroPassword; begin if (Length(FArchivePassword) > 0) then begin FillChar(FArchivePassword[1], Length(FArchivePassword), #0); SetLength(FArchivePassword, 0); end; end; procedure TPasswordCache.TimerEvent(Sender: TObject); begin FMutex.Acquire; try ZeroPassword; FTimer.Enabled:= False; finally FMutex.Release; end; end; function TPasswordCache.GetPassword(const Archive: String): String; begin FMutex.Acquire; try if (SameText(FArchiveName, Archive)) and (FArchiveSize = FileSizeUtf8(Archive)) and (FArchiveTime = FileAgeUtf8(Archive)) then begin ResetTimer; Result:= FArchivePassword end else begin FTimer.Enabled:= False; Result:= EmptyStr; ZeroPassword; end; finally FMutex.Release; end; end; procedure TPasswordCache.SetPassword(const Archive: String; const Password: String); begin FMutex.Acquire; try if (Length(Password) = 0) then FArchiveName:= EmptyStr else begin FArchiveName:= Archive; FArchivePassword:= Password; FArchiveTime:= FileAgeUtf8(Archive); FArchiveSize:= FileSizeUtf8(Archive); FTimer.Enabled:= True; ResetTimer; end; finally FMutex.Release; end; end; constructor TPasswordCache.Create; begin FTimer:= TFPTimer.Create(nil); FTimer.UseTimerThread:= True; FTimer.OnTimer:= @TimerEvent; FTimer.Interval:= FInterval; FMutex:= TCriticalSection.Create; end; destructor TPasswordCache.Destroy; begin FTimer.Free; FMutex.Free; inherited Destroy; end; end. ����������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipConfDlg.lfm�������������������������������������������������0000644�0001750�0000144�00000010553�14743153644�021164� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object DialogBox: TDialogBox Left = 693 Height = 353 Top = 345 Width = 438 AutoSize = True BorderStyle = bsDialog Caption = 'Zip plugin configuration' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ClientHeight = 353 ClientWidth = 438 OnShow = DialogBoxShow Position = poOwnerFormCenter LCLVersion = '2.2.4.0' object lblAbout: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = gbCompression AnchorSideRight.Side = asrBottom Left = 10 Height = 57 Top = 10 Width = 417 Alignment = taCenter Anchors = [akTop, akLeft, akRight] Caption = 'Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving.' ParentColor = False WordWrap = True end object gbCompression: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblAbout AnchorSideTop.Side = asrBottom Left = 10 Height = 203 Top = 87 Width = 417 AutoSize = True BorderSpacing.Top = 20 Caption = 'Compression' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ChildSizing.HorizontalSpacing = 25 ChildSizing.VerticalSpacing = 5 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 183 ClientWidth = 415 TabOrder = 0 object lblArchiveFormat: TLabel Left = 10 Height = 35 Top = 10 Width = 204 Caption = 'Archive format:' Layout = tlCenter ParentColor = False end object cbArchiveFormat: TComboBox Left = 239 Height = 35 Top = 10 Width = 166 ItemHeight = 0 OnChange = ComboBoxChange Style = csDropDownList TabOrder = 0 end object lblCompressionMethod: TLabel AnchorSideTop.Side = asrCenter Left = 10 Height = 35 Top = 50 Width = 204 Caption = 'Compression method:' Layout = tlCenter ParentColor = False end object cbCompressionMethod: TComboBox AnchorSideRight.Side = asrBottom Left = 239 Height = 35 Top = 50 Width = 166 ItemHeight = 0 OnChange = ComboBoxChange Style = csDropDownList TabOrder = 1 end object lblCompressionLevel: TLabel AnchorSideTop.Side = asrCenter Left = 10 Height = 35 Top = 90 Width = 204 Caption = 'Compression level:' Layout = tlCenter ParentColor = False end object cbCompressionLevel: TComboBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 239 Height = 35 Top = 90 Width = 166 BorderSpacing.Left = 20 ItemHeight = 0 OnChange = ComboBoxChange Style = csDropDownList TabOrder = 2 end object chkTarAutoHandle: TCheckBox AnchorSideLeft.Control = gbCompression AnchorSideTop.Control = cbCompressionLevel AnchorSideTop.Side = asrBottom Left = 10 Height = 23 Top = 135 Width = 395 BorderSpacing.Top = 10 Caption = 'Open *.tar.xyz archives at one step (slowly with big archives)' TabOrder = 3 end end object btnOK: TBitBtn AnchorSideTop.Control = btnCancel AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCancel Left = 217 Height = 36 Top = 310 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 10 Constraints.MinWidth = 100 Default = True DefaultCaption = True Kind = bkOK ModalResult = 1 OnClick = ButtonClick TabOrder = 1 end object btnCancel: TBitBtn AnchorSideTop.Control = gbCompression AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbCompression AnchorSideRight.Side = asrBottom Left = 327 Height = 36 Top = 310 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 20 Cancel = True Constraints.MinWidth = 100 DefaultCaption = True Kind = bkCancel ModalResult = 2 OnClick = ButtonClick TabOrder = 2 end end �����������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipConfDlg.pas�������������������������������������������������0000644�0001750�0000144�00000021241�14743153644�021165� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WCX plugin for working with *.zip, *.gz, *.bz2, *.tar, *.tgz, *.tbz archives Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) 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 in a file called COPYING along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } unit ZipConfDlg; {$mode objfpc}{$H+} {$include calling.inc} {$R ZipConfDlg.lfm} interface uses SysUtils, Extension; procedure CreateZipConfDlg; implementation uses ZipFunc, ZipOpt, ZipLng, AbZipTyp; function GetComboBox(pDlg: PtrUInt; DlgItemName: PAnsiChar): PtrInt; begin with gStartupInfo do begin Result:= SendDlgMsg(pDlg, DlgItemName, DM_LISTGETITEMINDEX, 0, 0); if Result >= 0 then begin Result:= SendDlgMsg(pDlg, DlgItemName, DM_LISTGETDATA, Result, 0); end; end; end; procedure SetComboBox(pDlg: PtrUInt; DlgItemName: PAnsiChar; ItemData: PtrInt); var Index, Count: Integer; begin with gStartupInfo do begin Count:= SendDlgMsg(pDlg, DlgItemName, DM_LISTGETCOUNT, 0, 0); for Index:= 0 to Count - 1 do begin if SendDlgMsg(pDlg, DlgItemName, DM_LISTGETDATA, Index, 0) = ItemData then begin SendDlgMsg(pDlg, DlgItemName, DM_LISTSETITEMINDEX, Index, 0); Exit; end; end; end; end; function ComboBoxAdd(pDlg: PtrUInt; DlgItemName: PAnsiChar; ItemText: String; ItemData: PtrInt): IntPtr; var P: PAnsiChar; AText: IntPtr absolute P; begin P:= PAnsiChar(ItemText); Result:= gStartupInfo.SendDlgMsg(pDlg, DlgItemName, DM_LISTADD, AText, ItemData); end; function AddCompressionLevel(pDlg: PtrUInt; const AName: String; ALevel: IntPtr): IntPtr; var AText: String; begin AText:= AName + ' (' + IntToStr(ALevel) + ')'; Result:= ComboBoxAdd(pDlg, 'cbCompressionLevel', AText, ALevel); end; procedure UpdateLevel(pDlg: PtrUInt; ALevel: IntPtr); var Index: IntPtr; AFormat: TArchiveFormat; AMethod: TAbZipCompressionMethod; begin with gStartupInfo do begin SendDlgMsg(pDlg, 'cbCompressionLevel', DM_LISTCLEAR, 0, 0); AFormat:= TArchiveFormat(GetComboBox(pDlg, 'cbArchiveFormat')); Index:= SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTGETITEMINDEX, 0, 0); AMethod:= TAbZipCompressionMethod(SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTGETDATA, Index, 0)); if (AMethod = cmStored) then begin SendDlgMsg(pDlg, 'cbCompressionLevel', DM_ENABLE, 0, 0); end else begin SendDlgMsg(pDlg, 'cbCompressionLevel', DM_ENABLE, 1, 0); case AMethod of cmDeflated, cmEnhancedDeflated: begin AddCompressionLevel(pDlg, rsCompressionLevelFastest, 1); AddCompressionLevel(pDlg, rsCompressionLevelFast, 3); Index:= AddCompressionLevel(pDlg, rsCompressionLevelNormal, 6); AddCompressionLevel(pDlg, rsCompressionLevelMaximum, 9); end; cmXz, cmLZMA, cmBzip2: begin AddCompressionLevel(pDlg, rsCompressionLevelFastest, 1); AddCompressionLevel(pDlg, rsCompressionLevelFast, 3); Index:= AddCompressionLevel(pDlg, rsCompressionLevelNormal, 5); AddCompressionLevel(pDlg, rsCompressionLevelMaximum, 7); AddCompressionLevel(pDlg, rsCompressionLevelUltra, 9); end; cmZstd: begin AddCompressionLevel(pDlg, rsCompressionLevelFastest, 3); AddCompressionLevel(pDlg, rsCompressionLevelFast, 5); Index:= AddCompressionLevel(pDlg, rsCompressionLevelNormal, 11); AddCompressionLevel(pDlg, rsCompressionLevelMaximum, 17); AddCompressionLevel(pDlg, rsCompressionLevelUltra, 22); end; end; if ALevel < 0 then SendDlgMsg(pDlg, 'cbCompressionLevel', DM_LISTSETITEMINDEX, Index, 0) else begin SetComboBox(pDlg, 'cbCompressionLevel', PluginConfig[AFormat].Level); end; end; end; end; procedure UpdateMethod(pDlg: PtrUInt); var Index: IntPtr; AFormat: TArchiveFormat; begin with gStartupInfo do begin SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTCLEAR, 0, 0); AFormat:= TArchiveFormat(GetComboBox(pDlg, 'cbArchiveFormat')); case AFormat of afGzip: ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Deflate', PtrInt(cmDeflated)); afXzip: ComboBoxAdd(pDlg, 'cbCompressionMethod', 'LZMA2', PtrInt(cmXz)); afBzip2: ComboBoxAdd(pDlg, 'cbCompressionMethod', 'BZip2', PtrInt(cmBzip2)); afZstd: ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Zstandard', PtrInt(cmZstd)); afZip: begin ComboBoxAdd(pDlg, 'cbCompressionMethod', rsCompressionMethodStore, PtrInt(cmStored)); ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Deflate', PtrInt(cmDeflated)); ComboBoxAdd(pDlg, 'cbCompressionMethod', rsCompressionMethodOptimal, PtrInt(cmEnhancedDeflated)); end; afZipx: begin ComboBoxAdd(pDlg, 'cbCompressionMethod', 'LZMA2', PtrInt(cmXz)); ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Zstandard', PtrInt(cmZstd)); end; end; // case Index:= SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTGETCOUNT, 0, 0); if (Index = 1) then begin SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTSETITEMINDEX, 0, 0); end else begin SetComboBox(pDlg, 'cbCompressionMethod', PluginConfig[AFormat].Method); end; // Randomly crashes under Qt // https://github.com/doublecmd/doublecmd/issues/1233 // SendDlgMsg(pDlg, 'cbCompressionMethod', DM_ENABLE, PtrInt(Index > 1), 0); end; UpdateLevel(pDlg, PluginConfig[AFormat].Level); end; function DlgProc (pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall; var Index: IntPtr; AFormat: TArchiveFormat; begin Result:= 0; with gStartupInfo do begin case Msg of DN_INITDIALOG: begin ComboBoxAdd(pDlg, 'cbArchiveFormat', 'gz', PtrInt(afGzip)); ComboBoxAdd(pDlg, 'cbArchiveFormat', 'xz', PtrInt(afXzip)); ComboBoxAdd(pDlg, 'cbArchiveFormat', 'bz2', PtrInt(afBzip2)); ComboBoxAdd(pDlg, 'cbArchiveFormat', 'zst', PtrInt(afZstd)); Index:= ComboBoxAdd(pDlg, 'cbArchiveFormat', 'zip', PtrInt(afZip)); ComboBoxAdd(pDlg, 'cbArchiveFormat', 'zipx', PtrInt(afZipx)); SendDlgMsg(pDlg, 'cbArchiveFormat', DM_LISTSETITEMINDEX, Index, 0); UpdateMethod(pDlg); SendDlgMsg(pDlg, 'chkTarAutoHandle', DM_SETCHECK, PtrInt(gTarAutoHandle), 0); end; DN_CHANGE: begin if DlgItemName = 'cbArchiveFormat' then begin UpdateMethod(pDlg); end else if DlgItemName = 'cbCompressionMethod' then begin UpdateLevel(pDlg, -1); end; end; DN_CLICK: if DlgItemName = 'btnOK' then begin AFormat:= TArchiveFormat(GetComboBox(pDlg, 'cbArchiveFormat')); PluginConfig[AFormat].Level:= GetComboBox(pDlg, 'cbCompressionLevel'); PluginConfig[AFormat].Method:= GetComboBox(pDlg, 'cbCompressionMethod'); gTarAutoHandle:= Boolean(SendDlgMsg(pDlg, 'chkTarAutoHandle', DM_GETCHECK, 0, 0)); SaveConfiguration; SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 1, 0); end else if DlgItemName = 'btnCancel' then SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 2, 0); end;// case end; // with end; procedure CreateZipConfDlg; var ResHandle: TFPResourceHandle = 0; ResGlobal: TFPResourceHGLOBAL = 0; ResData: Pointer = nil; ResSize: LongWord; begin try ResHandle := FindResource(HINSTANCE, PChar('TDIALOGBOX'), MAKEINTRESOURCE(10) {RT_RCDATA}); if ResHandle <> 0 then begin ResGlobal := LoadResource(HINSTANCE, ResHandle); if ResGlobal <> 0 then begin ResData := LockResource(ResGlobal); ResSize := SizeofResource(HINSTANCE, ResHandle); with gStartupInfo do begin DialogBoxLRS(ResData, ResSize, @DlgProc); end; end; end; finally if ResGlobal <> 0 then begin UnlockResource(ResGlobal); FreeResource(ResGlobal); end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipFunc.pas����������������������������������������������������0000644�0001750�0000144�00000055311�14743153644�020551� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WCX plugin for working with *.zip, *.gz, *.tar, *.tgz archives Copyright (C) 2007-2023 Alexander Koblov (alexx2000@mail.ru) 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 in a file called COPYING along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } unit ZipFunc; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, WcxPlugin, AbArcTyp, AbZipTyp, Extension, AbExcept, AbUtils, AbConst, ZipApp; type { TAbZipKitEx } TAbZipKitEx = class (TAbZipKit) private FItemProgress: Byte; FItem: TAbArchiveItem; FNeedPassword: Boolean; FOperationResult: LongInt; FChangeVolProcW: TChangeVolProcW; FProcessDataProcW : TProcessDataProcW; procedure AbOneItemProgressEvent(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); procedure AbArchiveItemProgressEvent(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); procedure AbArchiveProgressEvent (Sender : TObject; Progress : Byte; var Abort : Boolean); procedure AbNeedPasswordEvent(Sender : TObject; var NewPassword : AnsiString); procedure AbProcessItemFailureEvent(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); procedure AbRequestImageEvent(Sender : TObject; ImageNumber : Integer; var ImageName : String; var Abort : Boolean); public constructor Create(AOwner: TComponent); override; end; {Mandatory functions} function OpenArchive (var ArchiveData : tOpenArchiveData) : TArcHandle;dcpcall; export; function OpenArchiveW(var ArchiveData : tOpenArchiveDataW) : TArcHandle;dcpcall; export; function ReadHeader(hArcData : TArcHandle; var HeaderData: THeaderData) : Integer;dcpcall; export; function ReadHeaderExW(hArcData : TArcHandle; var HeaderData: THeaderDataExW) : Integer;dcpcall; export; function ProcessFile (hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PChar) : Integer;dcpcall; export; function ProcessFileW(hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PWideChar) : Integer;dcpcall; export; function CloseArchive (hArcData : TArcHandle) : Integer;dcpcall; export; procedure SetChangeVolProc (hArcData : TArcHandle; pChangeVolProc : PChangeVolProc);dcpcall; export; procedure SetChangeVolProcW(hArcData : TArcHandle; pChangeVolProc : TChangeVolProcW);dcpcall; export; procedure SetProcessDataProc (hArcData : TArcHandle; pProcessDataProc : TProcessDataProc);dcpcall; export; procedure SetProcessDataProcW(hArcData : TArcHandle; pProcessDataProc : TProcessDataProcW);dcpcall; export; {Optional functions} function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer;dcpcall; export; function DeleteFilesW(PackedFile, DeleteList : PWideChar) : Integer;dcpcall; export; function GetPackerCaps : Integer;dcpcall; export; function GetBackgroundFlags: Integer; dcpcall; export; procedure ConfigurePacker (Parent: HWND; DllInstance: THandle);dcpcall; export; function CanYouHandleThisFileW(FileName: PWideChar): Boolean; dcpcall; export; {Extension API} procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); dcpcall; export; const IniFileName = 'zip.ini'; var gStartupInfo: TExtensionStartupInfo; gTarAutoHandle : Boolean; implementation uses SysUtils, LazUTF8, ZipConfDlg, AbBrowse, DCConvertEncoding, DCOSUtils, ZipOpt, ZipLng, ZipCache, DCDateTimeUtils; var PasswordCache: TPasswordCache; threadvar gProcessDataProcW : TProcessDataProcW; procedure StringToArrayW(src: UnicodeString; pDst: PWideChar; MaxDstLength: Integer); begin if Length(src) < MaxDstLength then MaxDstLength := Length(src) else MaxDstLength := MaxDstLength - 1; // for ending #0 if Length(src) > 0 then Move(src[1], pDst^, SizeOf(WideChar) * MaxDstLength); pDst[MaxDstLength] := WideChar(0); end; function StrEndsWith(S : String; SearchPhrase : String) : Boolean; begin Result := (RightStr(S, Length(SearchPhrase)) = SearchPhrase); end; function GetArchiveError(const E : Exception): Integer; begin if E is EAbUserAbort then Result := E_EABORTED else if E is EAbFileNotFound then Result := E_EOPEN else if E is EAbUnhandledType then Result := E_UNKNOWN_FORMAT else if E is EFCreateError then Result := E_ECREATE else if E is EFOpenError then Result := E_EOPEN else if E is EReadError then Result := E_EREAD else if E is EWriteError then Result := E_EWRITE else Result := E_UNKNOWN; end; procedure CheckError(Arc: TAbZipKitEx; E: Exception; const FileName: String); var AMessage: String; begin if (Arc.FOperationResult = E_UNKNOWN) then begin AMessage:= E.Message + LineEnding + LineEnding + FileName; if gStartupInfo.MessageBox(PAnsiChar(AMessage), nil, MB_OKCANCEL or MB_ICONERROR) = ID_OK then Arc.FOperationResult:= E_HANDLED else begin Arc.FOperationResult:= E_EABORTED; end; end; end; // -- Exported functions ------------------------------------------------------ function OpenArchive (var ArchiveData : tOpenArchiveData) : TArcHandle;dcpcall; export; begin Result := 0; ArchiveData.OpenResult := E_NOT_SUPPORTED; end; function OpenArchiveW(var ArchiveData : tOpenArchiveDataW) : TArcHandle;dcpcall; export; var Arc : TAbZipKitEx; begin Result := 0; Arc := TAbZipKitEx.Create(nil); try Arc.OnArchiveProgress := @Arc.AbArchiveProgressEvent; Arc.OnProcessItemFailure := @Arc.AbProcessItemFailureEvent; Arc.OnNeedPassword:= @Arc.AbNeedPasswordEvent; Arc.OnRequestImage:= @Arc.AbRequestImageEvent; Arc.TarAutoHandle := gTarAutoHandle; Arc.OpenArchive(UTF16ToUTF8(UnicodeString(ArchiveData.ArcName))); if Arc.ArchiveType in [atGzip, atBzip2, atXz, atLzma, atZstd] then Arc.OnArchiveItemProgress := @Arc.AbOneItemProgressEvent else begin Arc.OnArchiveItemProgress := @Arc.AbArchiveItemProgressEvent; end; Arc.Password := PasswordCache.GetPassword(Arc.FileName); Arc.Tag := 0; Result := TArcHandle(Arc); except on E: Exception do begin Arc.Free; ArchiveData.OpenResult := GetArchiveError(E); if (ArchiveData.OpenResult = E_UNKNOWN) then begin ArchiveData.OpenResult := E_HANDLED; gStartupInfo.MessageBox(PAnsiChar(E.Message), nil, MB_OK or MB_ICONERROR); end; end; end; end; function ReadHeader(hArcData : TArcHandle; var HeaderData: THeaderData) : Integer;dcpcall; export; begin Result := E_NOT_SUPPORTED; end; function ReadHeaderExW(hArcData : TArcHandle; var HeaderData: THeaderDataExW) : Integer;dcpcall; export; var sFileName : String; Arc : TAbZipKitEx absolute hArcData; begin if Arc.Tag > Arc.Count - 1 then Exit(E_END_ARCHIVE); sFileName := Arc.GetFileName(Arc.Tag); StringToArrayW(CeUtf8ToUtf16(sFileName), @HeaderData.FileName, SizeOf(HeaderData.FileName)); with Arc.Items[Arc.Tag] do begin HeaderData.PackSize := Lo(CompressedSize); HeaderData.PackSizeHigh := Hi(CompressedSize); HeaderData.UnpSize := Lo(UncompressedSize); HeaderData.UnpSizeHigh := Hi(UncompressedSize); HeaderData.FileCRC := CRC32; HeaderData.FileTime := NativeLastModFileTime; HeaderData.FileAttr := NativeFileAttributes; HeaderData.MfileTime := DateTimeToWinFileTime(LastModTimeAsDateTime); if IsEncrypted then begin HeaderData.Flags := RHDF_ENCRYPTED; end; if IsDirectory then begin HeaderData.FileAttr := HeaderData.FileAttr or faFolder; end; end; Result := E_SUCCESS; end; function ProcessFile (hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PChar) : Integer;dcpcall; export; begin Result := E_NOT_SUPPORTED; end; function ProcessFileW(hArcData : TArcHandle; Operation : Integer; DestPath, DestName : PWideChar) : Integer;dcpcall; export; var Abort: Boolean; DestNameUtf8: String; Arc : TAbZipKitEx absolute hArcData; begin try Arc.FOperationResult := E_SUCCESS; case Operation of PK_TEST: begin Arc.TestItemAt(Arc.Tag); if (Arc.FNeedPassword) and (Arc.FOperationResult = E_SUCCESS) and Arc.Items[Arc.Tag].IsEncrypted then begin Arc.FNeedPassword:= False; PasswordCache.SetPassword(Arc.FileName, Arc.Password); end; // Show progress and ask if aborting. if Assigned(Arc.FProcessDataProcW) then begin Abort := False; Arc.OnArchiveItemProgress(Arc, Arc.Items[Arc.Tag], 100, Abort); if Abort then Arc.FOperationResult := E_EABORTED; end; end; PK_EXTRACT: begin DestNameUtf8 := UTF16ToUTF8(UnicodeString(DestName)); if (DestPath <> nil) and (DestPath[0] <> #0) then Arc.BaseDirectory := DestPath else begin Arc.BaseDirectory := ExtractFilePath(DestNameUtf8); end; repeat Arc.FOperationResult := E_SUCCESS; Arc.ExtractAt(Arc.Tag, DestNameUtf8); until (Arc.FOperationResult <> maxLongint); if (Arc.FNeedPassword) and (Arc.FOperationResult = E_SUCCESS) and Arc.Items[Arc.Tag].IsEncrypted then begin Arc.FNeedPassword:= False; PasswordCache.SetPassword(Arc.FileName, Arc.Password); end; // Show progress and ask if aborting. if Assigned(Arc.FProcessDataProcW) then begin Abort := False; Arc.OnArchiveItemProgress(Arc, Arc.Items[Arc.Tag], 100, Abort); if Abort then Arc.FOperationResult := E_EABORTED; end; end; PK_SKIP: begin end; end; {case} except on E: Exception do begin Arc.FOperationResult := GetArchiveError(E); if (Operation = PK_TEST) then CheckError(Arc, E, Arc.Items[Arc.Tag].FileName); end; end; Result:= Arc.FOperationResult; Arc.Tag := Arc.Tag + 1; end; function CloseArchive (hArcData : TArcHandle) : Integer;dcpcall; export; var Arc : TAbZipKitEx absolute hArcData; begin Arc.CloseArchive; FreeAndNil(Arc); Result := E_SUCCESS; end; procedure SetChangeVolProc (hArcData : TArcHandle; pChangeVolProc : PChangeVolProc);dcpcall; export; begin end; procedure SetChangeVolProcW(hArcData : TArcHandle; pChangeVolProc : TChangeVolProcW);dcpcall; export; var Arc : TAbZipKitEx absolute hArcData; begin if (hArcData <> wcxInvalidHandle) then begin Arc.FChangeVolProcW := pChangeVolProc; end; end; procedure SetProcessDataProc (hArcData : TArcHandle; pProcessDataProc : TProcessDataProc);dcpcall; export; begin end; procedure SetProcessDataProcW(hArcData : TArcHandle; pProcessDataProc : TProcessDataProcW);dcpcall; export; var Arc : TAbZipKitEx absolute hArcData; begin if (hArcData <> wcxInvalidHandle) then // if archive is open Arc.FProcessDataProcW := pProcessDataProc else begin // if archive is close gProcessDataProcW := pProcessDataProc; end; end; {Optional functions} function PackFilesW(PackedFile: PWideChar; SubPath: PWideChar; SrcPath: PWideChar; AddList: PWideChar; Flags: Integer): Integer;dcpcall; export; var FileExt: String; FilePath: String; Arc : TAbZipKitEx; FileName: UnicodeString; sPassword: AnsiString; sPackedFile: String; ArchiveFormat: TArchiveFormat; begin if (Flags and PK_PACK_MOVE_FILES) <> 0 then begin Exit(E_NOT_SUPPORTED); end; Arc := TAbZipKitEx.Create(nil); try Arc.AutoSave := False; Arc.TarAutoHandle:= True; Arc.FProcessDataProcW := gProcessDataProcW; Arc.OnProcessItemFailure := @Arc.AbProcessItemFailureEvent; sPackedFile := UTF16ToUTF8(UnicodeString(PackedFile)); try FileExt:= LowerCase(ExtractFileExt(sPackedFile)); if ((Flags and PK_PACK_ENCRYPT) <> 0) then begin // Only zip/zipx supports encryption if (FileExt = '.zip') or (FileExt = '.zipx') then begin sPassword:= EmptyStr; Arc.AbNeedPasswordEvent(Arc, sPassword); Arc.Password:= sPassword; end; end; Arc.OpenArchive(sPackedFile); ArchiveFormat:= ARCHIVE_FORMAT[Arc.ArchiveType]; if (ArchiveFormat = afZip) then begin if (FileExt = '.zipx') then ArchiveFormat:= afZipx else begin case PluginConfig[ArchiveFormat].Level of 1: Arc.DeflationOption:= doSuperFast; 3: Arc.DeflationOption:= doFast; 6: Arc.DeflationOption:= doNormal; 9: Arc.DeflationOption:= doMaximum; end; case PluginConfig[ArchiveFormat].Method of PtrInt(cmStored): Arc.CompressionMethodToUse:= smStored; PtrInt(cmDeflated): Arc.CompressionMethodToUse:= smDeflated; PtrInt(cmEnhancedDeflated): Arc.CompressionMethodToUse:= smBestMethod; end; end; end; Arc.ZipArchive.CompressionLevel:= PluginConfig[ArchiveFormat].Level; Arc.ZipArchive.CompressionMethod:= PluginConfig[ArchiveFormat].Method; Arc.OnArchiveProgress := @Arc.AbArchiveProgressEvent; Arc.StoreOptions := Arc.StoreOptions + [soReplace]; Arc.BaseDirectory := UTF16ToUTF8(UnicodeString(SrcPath)); FilePath:= UTF16ToUTF8(UnicodeString(SubPath)); while True do begin FileName := UnicodeString(AddList); Arc.Archive.AddEntry(UTF16ToUTF8(FileName), FilePath); if (AddList + Length(FileName) + 1)^ = #0 then Break; Inc(AddList, Length(FileName) + 1); end; if Arc.ArchiveType in [atGzip, atBzip2, atXz, atLzma, atZstd] then begin with Arc.Archive.ItemList[0] do begin UncompressedSize := mbFileSize(DiskFileName); end; Arc.OnArchiveItemProgress := @Arc.AbOneItemProgressEvent end else begin Arc.OnArchiveItemProgress := @Arc.AbArchiveItemProgressEvent; end; Arc.Save; Arc.CloseArchive; except on E: Exception do begin Arc.FOperationResult := GetArchiveError(E); CheckError(Arc, E, sPackedFile); end; end; finally Result := Arc.FOperationResult; FreeAndNil(Arc); end; end; function DeleteFilesW(PackedFile, DeleteList : PWideChar) : Integer;dcpcall; export; var Arc : TAbZipKitEx; FileNameUTF8 : String; pFileName : PWideChar; FileName : UnicodeString; ArchiveFormat: TArchiveFormat; begin Arc := TAbZipKitEx.Create(nil); try Arc.TarAutoHandle:= True; Arc.FProcessDataProcW := gProcessDataProcW; Arc.OnProcessItemFailure := @Arc.AbProcessItemFailureEvent; Arc.OnNeedPassword:= @Arc.AbNeedPasswordEvent; try Arc.OpenArchive(UTF16ToUTF8(UnicodeString(PackedFile))); ArchiveFormat:= ARCHIVE_FORMAT[Arc.ArchiveType]; Arc.ZipArchive.CompressionLevel:= PluginConfig[ArchiveFormat].Level; // Set this after opening archive, to get only progress of deleting. Arc.OnArchiveItemProgress := @Arc.AbArchiveItemProgressEvent; Arc.OnArchiveProgress := @Arc.AbArchiveProgressEvent; // Parse file list. pFileName := DeleteList; while pFileName^ <> #0 do begin FileName := pFileName; // Convert PWideChar to UnicodeString (up to first #0). FileNameUTF8 := UTF16ToUTF8(FileName); // If ends with '.../*.*' or '.../' then delete directory. if StrEndsWith(FileNameUTF8, PathDelim + '*.*') or StrEndsWith(FileNameUTF8, PathDelim) then Arc.DeleteDirectoriesRecursively(ExtractFilePath(FileNameUTF8)) else Arc.DeleteFile(FileNameUTF8); pFileName := pFileName + Length(FileName) + 1; // move after filename and ending #0 if pFileName^ = #0 then Break; // end of list end; Arc.Save; Arc.CloseArchive; except on E: Exception do begin Arc.FOperationResult := GetArchiveError(E); CheckError(Arc, E, Arc.FileName); end; end; finally Result := Arc.FOperationResult; FreeAndNil(Arc); end; end; function GetPackerCaps : Integer;dcpcall; export; begin Result := PK_CAPS_NEW or PK_CAPS_DELETE or PK_CAPS_MODIFY or PK_CAPS_MULTIPLE or PK_CAPS_OPTIONS or PK_CAPS_BY_CONTENT or PK_CAPS_ENCRYPT; end; function GetBackgroundFlags: Integer; dcpcall; export; begin Result:= BACKGROUND_UNPACK or BACKGROUND_PACK; end; procedure ConfigurePacker(Parent: HWND; DllInstance: THandle);dcpcall; export; begin CreateZipConfDlg; end; function CanYouHandleThisFileW(FileName: PWideChar): Boolean; dcpcall; export; begin try Result:= (AbDetermineArcType(UTF16ToUTF8(UnicodeString(FileName)), atUnknown) <> atUnknown); except Result := False; end; end; procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); dcpcall; export; begin gStartupInfo:= StartupInfo^; // Load configuration from ini file LoadConfiguration; TranslateResourceStrings; // Create password cache object PasswordCache:= TPasswordCache.Create; end; { TAbZipKitEx } constructor TAbZipKitEx.Create(AOwner: TComponent); begin inherited Create(AOwner); FOperationResult := E_SUCCESS; FProcessDataProcW := nil; TempDirectory := GetTempDir; end; procedure TAbZipKitEx.AbProcessItemFailureEvent(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); var Message: AnsiString; begin // Unknown error FOperationResult:= E_UNKNOWN; // Check error class if (ErrorClass = ecAbbrevia) then begin case ErrorCode of AbUserAbort: FOperationResult:= E_EABORTED; AbZipBadCRC: FOperationResult:= E_BAD_ARCHIVE; AbFileNotFound: FOperationResult:= E_NO_FILES; AbReadError: FOperationResult:= E_EREAD; end; end // Has exception message? Show it! else if Assigned(ExceptObject) and (ExceptObject is Exception) then begin Message := Exception(ExceptObject).Message; if Assigned(Item) then Message += LineEnding + LineEnding + Item.FileName; if (ProcessType = ptExtract) then begin case gStartupInfo.MessageBox(PAnsiChar(Message), nil, MB_ABORTRETRYIGNORE or MB_ICONERROR) of ID_RETRY: FOperationResult:= maxLongint; ID_IGNORE: FOperationResult:= E_HANDLED; ID_ABORT: raise EAbUserAbort.Create; end; end else begin if gStartupInfo.MessageBox(PAnsiChar(Message), nil, MB_OKCANCEL or MB_ICONERROR) = ID_OK then FOperationResult:= E_HANDLED else begin raise EAbUserAbort.Create; end; end; end // Check error class else case ErrorClass of ecFileOpenError: begin ErrorClass:= ecAbbrevia; ErrorCode:= AbFCIFileOpenError; FOperationResult:= E_EOPEN; end; ecFileCreateError: begin ErrorClass:= ecAbbrevia; ErrorCode:= AbFCICreateError; FOperationResult:= E_ECREATE; end; end; // Show abbrevia specific errors if (ErrorClass = ecAbbrevia) and (ProcessType in [ptAdd, ptFreshen, ptReplace]) then begin Message:= AbStrRes(ErrorCode) + LineEnding + LineEnding + Item.FileName; if gStartupInfo.MessageBox(PAnsiChar(Message), nil, MB_OKCANCEL or MB_ICONERROR) = ID_OK then FOperationResult:= E_HANDLED else begin raise EAbUserAbort.Create; end; end; end; procedure TAbZipKitEx.AbRequestImageEvent(Sender: TObject; ImageNumber: Integer; var ImageName: String; var Abort: Boolean); var AVolume: array[0..MAX_PATH] of WideChar; begin if (not mbFileExists(ImageName)) and Assigned(FChangeVolProcW) then begin StrPCopy(AVolume, CeUtf8ToUtf16(ImageName)); Abort := (FChangeVolProcW(AVolume, PK_VOL_ASK) = 0); if not Abort then ImageName:= CeUtf16ToUtf8(UnicodeString(AVolume)); end; end; procedure TAbZipKitEx.AbOneItemProgressEvent(Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); var ASize: Int64; begin if Assigned(FProcessDataProcW) then begin ASize := Item.UncompressedSize; if ASize = 0 then ASize := -Progress else if FItemProgress = Progress then ASize := 0 else begin ASize := (Int64(Progress) - Int64(FItemProgress)) * ASize div 100; if ASize > High(Int32) then ASize := -Progress; FItemProgress := Progress; end; Abort := (FProcessDataProcW(PWideChar(CeUtf8ToUtf16(Item.FileName)), ASize) = 0); end; end; procedure TAbZipKitEx.AbArchiveItemProgressEvent(Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); var ASize: Int64; begin if Assigned(FProcessDataProcW) then begin if (Item = nil) then Abort := (FProcessDataProcW(nil, -(Progress + 1000)) = 0) else begin if Item.IsDirectory then ASize:= 0 else if Item.UncompressedSize = 0 then ASize:= -(Progress + 1000) else begin if FItem <> Item then begin FItem := Item; FItemProgress := 0; end; if FItemProgress = Progress then ASize := 0 else begin ASize := Item.UncompressedSize; ASize := (Int64(Progress) - Int64(FItemProgress)) * ASize div 100; if ASize > High(Int32) then ASize := -(Progress + 1000); FItemProgress := Progress; end; end; Abort := (FProcessDataProcW(PWideChar(CeUtf8ToUtf16(Item.FileName)), ASize) = 0) end; end; end; procedure TAbZipKitEx.AbArchiveProgressEvent(Sender: TObject; Progress: Byte; var Abort: Boolean); begin try if Assigned(FProcessDataProcW) then Abort := (FProcessDataProcW(nil, -(Progress)) = 0); except Abort := True; end; end; procedure TAbZipKitEx.AbNeedPasswordEvent(Sender: TObject; var NewPassword: AnsiString); var aNewPassword: array[0..MAX_PATH-1] of AnsiChar; Result: Boolean; begin aNewPassword := Copy(NewPassword, 1, MAX_PATH); Result:= gStartupInfo.InputBox('Zip', 'Please enter the password:', True, PAnsiChar(aNewPassword), MAX_PATH); if Result then NewPassword := aNewPassword else begin raise EAbUserAbort.Create; end; FNeedPassword:= True; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipLng.pas�����������������������������������������������������0000644�0001750�0000144�00000003474�14743153644�020401� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Zip archiver plugin, language support Copyright (C) 2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit ZipLng; {$mode delphi} interface uses Classes, SysUtils; resourcestring rsCompressionMethodStore = 'Store'; rsCompressionMethodOptimal = 'Optimal (2x slower)'; rsCompressionLevelFastest = 'Fastest'; rsCompressionLevelFast = 'Fast'; rsCompressionLevelNormal = 'Normal'; rsCompressionLevelMaximum = 'Maximum'; rsCompressionLevelUltra = 'Ultra'; procedure TranslateResourceStrings; implementation uses ZipFunc; function Translate(Name, Value: AnsiString; Hash: LongInt; Arg: Pointer): AnsiString; var ALen: Integer; begin with gStartupInfo do begin SetLength(Result, MaxSmallint); ALen:= TranslateString(Translation, PAnsiChar(Name), PAnsiChar(Value), PAnsiChar(Result), MaxSmallint); SetLength(Result, ALen); end; end; procedure TranslateResourceStrings; begin if Assigned(gStartupInfo.Translation) then begin SetResourceStrings(@Translate, nil); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/ZipOpt.pas�����������������������������������������������������0000644�0001750�0000144�00000007015�14743153644�020416� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ZipOpt; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, AbUtils, AbZipTyp; type TArchiveFormat = ( afNil, afZip, afZipx, afGzip, afBzip2, afXzip, afLzma, afZstd ); TFormatOptions = record Level: PtrInt; Method: PtrInt; end; const ARCHIVE_FORMAT: array[TAbArchiveType] of TArchiveFormat = ( afNil, afZip, afZip, afZip, afNil, afGzip, afGzip, afNil, afBzip2, afBzip2, afXzip, afXzip, afLzma, afLzma, afZstd, afZstd ); const DefaultConfig: array[TArchiveFormat] of TFormatOptions = ( (Level: 0; Method: 0;), (Level: 6; Method: PtrInt(cmDeflated);), (Level: 7; Method: PtrInt(cmXz);), (Level: 6; Method: PtrInt(cmDeflated);), (Level: 9; Method: PtrInt(cmBzip2);), (Level: 7; Method: PtrInt(cmXz);), (Level: 7; Method: PtrInt(cmLZMA);), (Level: 11; Method: PtrInt(cmZstd);) ); var PluginConfig: array[TArchiveFormat] of TFormatOptions; procedure LoadConfiguration; procedure SaveConfiguration; implementation uses TypInfo, DCClassesUtf8, Extension, ZipFunc; procedure LoadConfiguration; var Ini: TIniFileEx; Section: AnsiString; ArchiveFormat: TArchiveFormat; begin try Ini:= TIniFileEx.Create(gStartupInfo.PluginConfDir + IniFileName); try for ArchiveFormat:= Succ(Low(TArchiveFormat)) to High(TArchiveFormat) do begin Section:= Copy(GetEnumName(TypeInfo(TArchiveFormat), PtrInt(ArchiveFormat)), 3, MaxInt); PluginConfig[ArchiveFormat].Level:= Ini.ReadInteger(Section, 'Level', DefaultConfig[ArchiveFormat].Level); PluginConfig[ArchiveFormat].Method:= Ini.ReadInteger(Section, 'Method', DefaultConfig[ArchiveFormat].Method); end; gTarAutoHandle:= Ini.ReadBool('Configuration', 'TarAutoHandle', True); // Backward compatibility case Ini.ReadInteger('Configuration', 'DeflationOption', -1) of IntPtr(doSuperFast): PluginConfig[afZip].Level:= 1; IntPtr(doFast): PluginConfig[afZip].Level:= 3; IntPtr(doNormal): PluginConfig[afZip].Level:= 6; IntPtr(doMaximum): PluginConfig[afZip].Level:= 9; end; case Ini.ReadInteger('Configuration', 'CompressionMethodToUse', -1) of IntPtr(smStored): PluginConfig[afZip].Method:= IntPtr(cmStored); IntPtr(smDeflated): PluginConfig[afZip].Method:= IntPtr(cmDeflated); IntPtr(smBestMethod): PluginConfig[afZip].Method:= IntPtr(cmEnhancedDeflated); end; finally Ini.Free; end; except // Ignore end; end; procedure SaveConfiguration; var Ini: TIniFileEx; Section: AnsiString; ArchiveFormat: TArchiveFormat; begin try Ini:= TIniFileEx.Create(gStartupInfo.PluginConfDir + IniFileName); try for ArchiveFormat:= Succ(Low(TArchiveFormat)) to High(TArchiveFormat) do begin Section:= Copy(GetEnumName(TypeInfo(TArchiveFormat), PtrInt(ArchiveFormat)), 3, MaxInt); Ini.WriteInteger(Section, 'Level', PluginConfig[ArchiveFormat].Level); Ini.WriteInteger(Section, 'Method', PluginConfig[ArchiveFormat].Method); end; Ini.DeleteKey('Configuration', 'DeflationOption'); Ini.DeleteKey('Configuration', 'CompressionMethodToUse'); Ini.WriteBool('Configuration', 'TarAutoHandle', gTarAutoHandle); Ini.UpdateFile; finally Ini.Free; end; except on E: Exception do begin gStartupInfo.MessageBox(PAnsiChar(E.Message), nil, MB_OK or MB_ICONERROR); end; end; end; initialization Move(DefaultConfig[Low(DefaultConfig)], PluginConfig[Low(PluginConfig)], SizeOf(PluginConfig)); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/�����������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020430� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abarctyp.pas�����������������������������������������0000644�0001750�0000144�00000212341�14743153644�022745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbArcTyp.pas *} {*********************************************************} {* ABBREVIA: TABArchive, TABArchiveItem classes *} {*********************************************************} unit AbArcTyp; {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF MSWINDOWS} Classes, Types, AbUtils; { ===== TAbArchiveItem ====================================================== } type TAbArchiveItem = class(TObject) protected {private} NextItem : TAbArchiveItem; FAction : TAbArchiveAction; FCompressedSize : Int64; FCRC32 : Longint; FDiskFileName : string; FExternalFileAttributes : LongWord; FFileName : string; FIsEncrypted : Boolean; FLastModFileTime : Word; FLastModFileDate : Word; FTagged : Boolean; FUncompressedSize : Int64; protected {property methods} function GetCompressedSize : Int64; virtual; function GetCRC32 : Longint; virtual; function GetDiskPath : string; function GetExternalFileAttributes : LongWord; virtual; function GetFileName : string; virtual; function GetIsDirectory: Boolean; virtual; function GetIsEncrypted : Boolean; virtual; function GetLastModFileDate : Word; virtual; function GetLastModFileTime : Word; virtual; { This depends on in what format the attributes are stored in the archive, to which system they refer (MS-DOS, Unix, etc.) and what system we're running on (compile time). } function GetNativeFileAttributes : LongInt; virtual; { This depends on in what format the date/time is stored in the archive (Unix, MS-DOS, ...) and what system we're running on (compile time). Returns MS-DOS local time on Windows, Unix UTC time on Unix. } function GetNativeLastModFileTime : Longint; virtual; function GetStoredPath : string; function GetUncompressedSize : Int64; virtual; procedure SetCompressedSize(const Value : Int64); virtual; procedure SetCRC32(const Value : Longint); virtual; procedure SetExternalFileAttributes( Value : LongWord ); virtual; procedure SetFileName(const Value : string); virtual; procedure SetIsEncrypted(Value : Boolean); virtual; procedure SetLastModFileDate(const Value : Word); virtual; procedure SetLastModFileTime(const Value : Word); virtual; procedure SetUncompressedSize(const Value : Int64); virtual; function GetLastModTimeAsDateTime: TDateTime; virtual; procedure SetLastModTimeAsDateTime(const Value: TDateTime); virtual; public {methods} constructor Create; destructor Destroy; override; function MatchesDiskName(const FileMask : string) : Boolean; function MatchesStoredName(const FileMask : string) : Boolean; function MatchesStoredNameEx(const FileMask : string) : Boolean; public {properties} property Action : TAbArchiveAction read FAction write FAction; property CompressedSize : Int64 read GetCompressedSize write SetCompressedSize; property CRC32 : Longint read GetCRC32 write SetCRC32; property DiskFileName : string read FDiskFileName write FDiskFileName; property DiskPath : string read GetDiskPath; property ExternalFileAttributes : LongWord read GetExternalFileAttributes write SetExternalFileAttributes; property FileName : string read GetFileName write SetFileName; property IsDirectory: Boolean read GetIsDirectory; property IsEncrypted : Boolean read GetIsEncrypted write SetIsEncrypted; property LastModFileDate : Word read GetLastModFileDate write SetLastModFileDate; property LastModFileTime : Word read GetLastModFileTime write SetLastModFileTime; property NativeFileAttributes : LongInt read GetNativeFileAttributes; property NativeLastModFileTime : Longint read GetNativeLastModFileTime; property StoredPath : string read GetStoredPath; property Tagged : Boolean read FTagged write FTagged; property UncompressedSize : Int64 read GetUncompressedSize write SetUncompressedSize; property LastModTimeAsDateTime : TDateTime read GetLastModTimeAsDateTime write SetLastModTimeAsDateTime; end; { ===== TAbArchiveListEnumerator ============================================ } type TAbArchiveList = class; TAbArchiveListEnumerator = class private FIndex: Integer; FList: TAbArchiveList; public constructor Create(aList: TAbArchiveList); function GetCurrent: TAbArchiveItem; function MoveNext: Boolean; property Current: TAbArchiveItem read GetCurrent; end; { ===== TAbArchiveList ====================================================== } TAbArchiveList = class protected {private} FList : TList; FOwnsItems: Boolean; HashTable : array[0..1020] of TAbArchiveItem; protected {methods} function GenerateHash(const S : string) : LongInt; function GetCount : Integer; function Get(Index : Integer) : TAbArchiveItem; procedure Put(Index : Integer; Item : TAbArchiveItem); public {methods} constructor Create(AOwnsItems: Boolean); destructor Destroy; override; function Add(Item : Pointer): Integer; procedure Clear; procedure Delete(Index : Integer); function Find(const FN : string) : Integer; function GetEnumerator: TAbArchiveListEnumerator; function IsActiveDupe(const FN : string) : Boolean; public {properties} property Count : Integer read GetCount; property Items[Index : Integer] : TAbArchiveItem read Get write Put; default; end; { ===== TAbArchive specific types =========================================== } type TAbStoreOption = (soStripDrive, soStripPath, soRemoveDots, soRecurse, soFreshen, soReplace); TAbStoreOptions = set of TAbStoreOption; TAbExtractOption = (eoCreateDirs, eoRestorePath); TAbExtractOptions = set of TAbExtractOption; TAbArchiveStatus = (asInvalid, asIdle, asBusy); TAbArchiveEvent = procedure(Sender : TObject) of object; TAbArchiveConfirmEvent = procedure (Sender : TObject; var Confirm : Boolean) of object; TAbArchiveProgressEvent = procedure(Sender : TObject; Progress : Byte; var Abort : Boolean) of object; TAbArchiveItemEvent = procedure(Sender : TObject; Item : TAbArchiveItem) of object; TAbArchiveItemConfirmEvent = procedure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean) of object; TAbConfirmOverwriteEvent = procedure(var Name : string; var Confirm : Boolean) of object; TAbArchiveItemFailureEvent = procedure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer) of object; TAbArchiveItemExtractEvent = procedure(Sender : TObject; Item : TAbArchiveItem; const NewName : string) of object; TAbArchiveItemExtractToStreamEvent = procedure(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream) of object; TAbArchiveItemTestEvent = procedure(Sender : TObject; Item : TAbArchiveItem) of object; TAbArchiveItemInsertEvent = procedure(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream) of object; TAbArchiveItemInsertFromStreamEvent = procedure(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream) of object; TAbArchiveItemProgressEvent = procedure(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean) of object; TAbProgressEvent = procedure(Progress : Byte; var Abort : Boolean) of object; TAbRequestDiskEvent = procedure(Sender : TObject; var Abort : Boolean) of object; TAbRequestImageEvent = procedure(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean) of object; TAbRequestNthDiskEvent = procedure(Sender : TObject; DiskNumber : Byte; var Abort : Boolean) of object; type TAbArchiveStreamHelper = class protected FStream : TStream; public constructor Create(AStream : TStream); procedure ExtractItemData(AStream : TStream); virtual; abstract; function FindFirstItem : Boolean; virtual; abstract; function FindNextItem : Boolean; virtual; abstract; procedure ReadHeader; virtual; abstract; procedure ReadTail; virtual; abstract; function SeekItem(Index : Integer): Boolean; virtual; abstract; procedure WriteArchiveHeader; virtual; abstract; procedure WriteArchiveItem(AStream : TStream); virtual; abstract; procedure WriteArchiveTail; virtual; abstract; function GetItemCount : Integer; virtual; abstract; end; { ===== TAbArchive ========================================================== } type TAbArchive = class(TObject) public FStream : TStream; FStatus : TAbArchiveStatus; protected {property variables} //These break Encapsulation FArchiveName : string; FAutoSave : Boolean; FBaseDirectory : string; FCurrentItem : TAbArchiveItem; FDOSMode : Boolean; FExtractOptions : TAbExtractOptions; FImageNumber : Word; FInStream : TStream; FIsDirty : Boolean; FSpanningThreshold : Int64; FCompressionLevel : IntPtr; FCompressionMethod : IntPtr; FItemList : TAbArchiveList; FLogFile : string; FLogging : Boolean; FLogStream : TFileStream; FMode : Word; FOwnsStream : Boolean; FSpanned : Boolean; FStoreOptions : TAbStoreOptions; FTempDir : string; protected {event variables} FOnProcessItemFailure : TAbArchiveItemFailureEvent; FOnArchiveProgress : TAbArchiveProgressEvent; FOnArchiveSaveProgress : TAbArchiveProgressEvent; FOnArchiveItemProgress : TAbArchiveItemProgressEvent; FOnConfirmProcessItem : TAbArchiveItemConfirmEvent; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; FOnConfirmSave : TAbArchiveConfirmEvent; FOnLoad : TAbArchiveEvent; FOnProgress : TAbProgressEvent; FOnRequestImage : TAbRequestImageEvent; FOnSave : TAbArchiveEvent; protected {methods} constructor CreateInit; procedure CheckValid; function ConfirmPath(Item : TAbArchiveItem; const NewName : string; out UseName : string) : Boolean; procedure FreshenAt(Index : Integer); function FreshenRequired(Item : TAbArchiveItem) : Boolean; procedure GetFreshenTarget(Item : TAbArchiveItem); function GetItemCount : Integer; procedure MakeLogEntry(const FN: string; LT : TAbLogType); procedure MakeFullNames(const SourceFileName: String; const ArchiveDirectory: String; out FullSourceFileName: String; out FullArchiveFileName: String); procedure ReplaceAt(Index : Integer); procedure SaveIfNeeded(aItem : TAbArchiveItem); procedure SetBaseDirectory(Value : string); procedure SetLogFile(const Value : string); procedure SetLogging(Value : Boolean); protected {abstract methods} function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; {SourceFileName - full or relative path to a file/dir on some file system If full path, BaseDirectory is used to determine relative path} {ArchiveDirectory - path to a directory in the archive the file/dir will be in} {Example: FBaseDirectory = /dir SourceFileName = /dir/subdir/file ArchiveDirectory = files/storage (or files/storage/) -> name in archive = files/storage/subdir/file} virtual; abstract; overload; function CreateItem(const FileSpec : string): TAbArchiveItem; overload; procedure ExtractItemAt(Index : Integer; const UseName : string); virtual; abstract; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); virtual; abstract; procedure LoadArchive; virtual; abstract; procedure SaveArchive; virtual; abstract; procedure TestItemAt(Index : Integer); virtual; abstract; protected {virtual methods} procedure DoProcessItemFailure(Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); virtual; procedure DoArchiveSaveProgress(Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveProgress(Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveItemProgress(Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); virtual; procedure DoConfirmOverwrite(var FileName : string; var Confirm : Boolean); virtual; procedure DoConfirmProcessItem(Item : TAbArchiveItem; const ProcessType : TAbProcessType; var Confirm : Boolean); virtual; procedure DoConfirmSave(var Confirm : Boolean); virtual; procedure DoLoad; virtual; procedure DoProgress(Progress : Byte; var Abort : Boolean); virtual; procedure DoSave; virtual; function FixName(const Value : string) : string; virtual; function GetSpanningThreshold : Int64; virtual; function GetSupportsEmptyFolders : Boolean; virtual; procedure SetSpanningThreshold( Value : Int64 ); virtual; protected {properties and events} property InStream : TStream read FInStream; public {methods} constructor Create(const FileName : string; Mode : Word); virtual; constructor CreateFromStream(aStream : TStream; const aArchiveName : string); virtual; destructor Destroy; override; procedure Add(aItem : TAbArchiveItem); virtual; procedure AddEntry(const Path : String; const ArchiveDirectory : String); procedure AddFiles(const FileMask : string; SearchAttr : Integer); procedure AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); procedure AddFromStream(const NewName : string; aStream : TStream); procedure ClearTags; procedure Delete(aItem : TAbArchiveItem); procedure DeleteAt(Index : Integer); procedure DeleteFiles(const FileMask : string); procedure DeleteFilesEx(const FileMask, ExclusionMask : string); procedure DeleteTaggedItems; procedure Extract(aItem : TAbArchiveItem; const NewName : string); procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); procedure ExtractFilesEx(const FileMask, ExclusionMask : string); procedure ExtractTaggedItems; procedure ExtractToStream(const aFileName : string; aStream : TStream); function FindFile(const aFileName : string): Integer; function FindItem(aItem : TAbArchiveItem): Integer; procedure Freshen(aItem : TAbArchiveItem); procedure FreshenFiles(const FileMask : string); procedure FreshenFilesEx(const FileMask, ExclusionMask : string); procedure FreshenTaggedItems; procedure Load; virtual; procedure Move(aItem : TAbArchiveItem; const NewStoredPath : string); virtual; procedure Replace(aItem : TAbArchiveItem); procedure Save; virtual; procedure TagItems(const FileMask : string); procedure TestTaggedItems; procedure TestAt(Index : Integer); procedure UnTagItems(const FileMask : string); procedure DoDeflateProgress(aPercentDone : integer); virtual; procedure DoInflateProgress(aPercentDone : integer); virtual; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); virtual; public {properties} property OnProgress : TAbProgressEvent read FOnProgress write FOnProgress; property ArchiveName : string read FArchiveName; property AutoSave : Boolean read FAutoSave write FAutoSave; property BaseDirectory : string read FBaseDirectory write SetBaseDirectory; property Count : Integer read GetItemCount; property DOSMode : Boolean read FDOSMode write FDOSMode; property ExtractOptions : TAbExtractOptions read FExtractOptions write FExtractOptions; property IsDirty : Boolean read FIsDirty write FIsDirty; property ItemList : TAbArchiveList read FItemList; property LogFile : string read FLogFile write SetLogFile; property Logging : Boolean read FLogging write SetLogging; property Mode : Word read FMode; property Spanned : Boolean read FSpanned; property SpanningThreshold : Int64 read GetSpanningThreshold write SetSpanningThreshold; property Status : TAbArchiveStatus read FStatus; property StoreOptions : TAbStoreOptions read FStoreOptions write FStoreOptions; property SupportsEmptyFolders : Boolean read GetSupportsEmptyFolders; property TempDirectory : string read FTempDir write FTempDir; property CompressionLevel: IntPtr read FCompressionLevel write FCompressionLevel; property CompressionMethod: IntPtr read FCompressionMethod write FCompressionMethod; public {events} property OnProcessItemFailure : TAbArchiveItemFailureEvent read FOnProcessItemFailure write FOnProcessItemFailure; property OnArchiveProgress : TAbArchiveProgressEvent read FOnArchiveProgress write FOnArchiveProgress; property OnArchiveSaveProgress : TAbArchiveProgressEvent read FOnArchiveSaveProgress write FOnArchiveSaveProgress; property OnArchiveItemProgress : TAbArchiveItemProgressEvent read FOnArchiveItemProgress write FOnArchiveItemProgress; property OnConfirmProcessItem : TAbArchiveItemConfirmEvent read FOnConfirmProcessItem write FOnConfirmProcessItem; property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; property OnConfirmSave : TAbArchiveConfirmEvent read FOnConfirmSave write FOnConfirmSave; property OnLoad : TAbArchiveEvent read FOnLoad write FOnLoad; property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write FOnRequestImage; property OnSave : TAbArchiveEvent read FOnSave write FOnSave; end; { ===== TAbExtraField ======================================================= } type PAbExtraSubField = ^TAbExtraSubField; TAbExtraSubField = packed record ID : Word; Len : Word; Data : record end; end; TAbExtraField = class private {fields} FBuffer : TByteDynArray; private {methods} procedure DeleteField(aSubField : PAbExtraSubField); function FindField(aID : Word; out aSubField : PAbExtraSubField) : Boolean; function FindNext(var aCurField : PAbExtraSubField) : Boolean; function GetCount : Integer; function GetID(aIndex : Integer): Word; procedure SetBuffer(const aValue : TByteDynArray); protected {methods} procedure Changed; virtual; public {methods} procedure Assign(aSource : TAbExtraField); procedure Clear; procedure CloneFrom(aSource : TAbExtraField; aID : Word); procedure Delete(aID : Word); function Get(aID : Word; out aData : Pointer; out aDataSize : Word) : Boolean; function GetStream(aID : Word; out aStream : TStream): Boolean; function Has(aID : Word): Boolean; procedure LoadFromStream(aStream : TStream; aSize : Word); procedure Put(aID : Word; const aData; aDataSize : Word); public {properties} property Count : Integer read GetCount; property Buffer : TByteDynArray read FBuffer write SetBuffer; property IDs[aIndex : Integer]: Word read GetID; end; const AbDefAutoSave = False; AbDefExtractOptions = [eoCreateDirs]; AbDefStoreOptions = [soStripDrive, soRemoveDots]; AbBufferSize = 32768; AbLastDisk = -1; AbLastImage = -1; implementation {.$R ABRES.R32} uses RTLConsts, SysUtils, AbExcept, AbDfBase, AbConst, AbResString, DCOSUtils, DCClassesUtf8; { TAbArchiveItem implementation ============================================ } { TAbArchiveItem } constructor TAbArchiveItem.Create; begin inherited Create; FCompressedSize := 0; FUncompressedSize := 0; FFileName := ''; FAction := aaNone; FLastModFileTime := 0; FLastModFileDate := 0; end; { -------------------------------------------------------------------------- } destructor TAbArchiveItem.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetCompressedSize : Int64; begin Result := FCompressedSize; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetCRC32 : LongInt; begin Result := FCRC32; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetDiskPath : string; begin Result := ExtractFilePath(DiskFileName); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetExternalFileAttributes : LongWord; begin Result := FExternalFileAttributes; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetFileName : string; begin Result := FFileName; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetIsDirectory: Boolean; begin Result := False; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetIsEncrypted : Boolean; begin Result := FIsEncrypted; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetLastModFileTime : Word; begin Result := FLastModFileTime; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetLastModFileDate : Word; begin Result := FLastModFileDate; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetNativeFileAttributes : LongInt; begin {$IFDEF MSWINDOWS} if IsDirectory then Result := faDirectory else Result := 0; {$ENDIF} {$IFDEF UNIX} if IsDirectory then Result := AB_FPERMISSION_GENERIC or AB_FPERMISSION_OWNEREXECUTE else Result := AB_FPERMISSION_GENERIC; {$ENDIF} end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetNativeLastModFileTime : Longint; begin LongRec(Result).Hi := LastModFileDate; LongRec(Result).Lo := LastModFileTime; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetStoredPath : string; begin Result := ExtractFilePath(DiskFileName); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetUnCompressedSize : Int64; begin Result := FUnCompressedSize; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.MatchesDiskName(const FileMask : string) : Boolean; var DiskName, Mask : string; begin DiskName := DiskFileName; AbUnfixName(DiskName); Mask := FileMask; AbUnfixName(Mask); Result := AbFileMatch(DiskName, Mask); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.MatchesStoredName(const FileMask : string) : Boolean; var Value : string; Drive, Dir, Name : string; begin Value := FileMask; AbUnfixName(Value); AbParseFileName(Value, Drive, Dir, Name); Value := Dir + Name; Name := FileName; AbUnfixName(Name); if IsDirectory then Name := ExcludeTrailingPathDelimiter(Name); Result := AbFileMatch(Name, Value); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.MatchesStoredNameEx(const FileMask : string) : Boolean; var I, J: Integer; MaskPart: string; begin Result := True; I := 1; while I <= Length(FileMask) do begin J := I; while (I <= Length(FileMask)) and (FileMask[I] <> PathSep {';'}) do Inc(I); MaskPart := Trim(Copy(FileMask, J, I - J)); if (I <= Length(FileMask)) and (FileMask[I] = PathSep {';'}) then Inc(I); if MatchesStoredName(MaskPart) then Exit; end; Result := False; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetCompressedSize(const Value : Int64); begin FCompressedSize := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetCRC32(const Value : LongInt); begin FCRC32 := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetExternalFileAttributes( Value : LongWord ); begin FExternalFileAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetFileName(const Value : string); begin FFileName := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetIsEncrypted(Value : Boolean); begin FIsEncrypted := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetLastModFileDate(const Value : Word); begin FLastModFileDate := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetLastModFileTime(const Value : Word); begin FLastModFileTime := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetUnCompressedSize(const Value : Int64); begin FUnCompressedSize := Value; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetLastModTimeAsDateTime: TDateTime; begin Result := AbDosFileDateToDateTime(LastModFileDate, LastModFileTime); end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetLastModTimeAsDateTime(const Value: TDateTime); var FileDate : Integer; begin FileDate := AbDateTimeToDosFileDate(Value); LastModFileTime := LongRec(FileDate).Lo; LastModFileDate := LongRec(FileDate).Hi; end; { -------------------------------------------------------------------------- } { TAbArchiveEnumeratorList implementation ================================== } { TAbArchiveEnumeratorList } constructor TAbArchiveListEnumerator.Create(aList: TAbArchiveList); begin inherited Create; FIndex := -1; FList := aList; end; { -------------------------------------------------------------------------- } function TAbArchiveListEnumerator.GetCurrent: TAbArchiveItem; begin Result := FList[FIndex]; end; { -------------------------------------------------------------------------- } function TAbArchiveListEnumerator.MoveNext: Boolean; begin Result := FIndex < FList.Count - 1; if Result then Inc(FIndex); end; { -------------------------------------------------------------------------- } { TAbArchiveList implementation ============================================ } { TAbArchiveList } constructor TAbArchiveList.Create(AOwnsItems: Boolean); begin inherited Create; FList := TList.Create; FOwnsItems := AOwnsItems; end; { -------------------------------------------------------------------------- } destructor TAbArchiveList.Destroy; begin Clear; FList.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbArchiveList.Add(Item : Pointer) : Integer; var H : LongInt; begin if FOwnsItems then begin H := GenerateHash(TAbArchiveItem(Item).FileName); TAbArchiveItem(Item).NextItem := HashTable[H]; HashTable[H] := TAbArchiveItem(Item); end; Result := FList.Add(Item); end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.Clear; var i : Integer; begin if FOwnsItems then for i := 0 to Count - 1 do TObject(FList[i]).Free; FList.Clear; FillChar(HashTable, SizeOf(HashTable), #0); end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.Delete(Index: Integer); var Look : TAbArchiveItem; Last : Pointer; FN : string; begin if FOwnsItems then begin FN := TAbArchiveItem(FList[Index]).FileName; Last := @HashTable[GenerateHash(FN)]; Look := TAbArchiveItem(Last^); while Look <> nil do begin if CompareText(Look.FileName, FN) = 0 then begin Move(Look.NextItem, Last^, SizeOf(Pointer)); Break; end; Last := @Look.NextItem; Look := TAbArchiveItem(Last^); end; TObject(FList[Index]).Free; end; FList.Delete(Index); end; { -------------------------------------------------------------------------- } function TAbArchiveList.Find(const FN : string) : Integer; var Look : TAbArchiveItem; I : Integer; begin if FOwnsItems then begin Look := HashTable[GenerateHash(FN)]; while Look <> nil do begin if CompareText(Look.FileName, FN) = 0 then begin Result := FList.IndexOf(Look); Exit; end; Look := Look.NextItem; end; end else begin for I := 0 to FList.Count - 1 do if CompareText(Items[I].FileName, FN) = 0 then begin Result := I; Exit; end; end; Result := -1; end; { -------------------------------------------------------------------------- } {$IFOPT Q+}{$DEFINE OVERFLOW_CHECKS_ON}{$Q-}{$ENDIF} function TAbArchiveList.GenerateHash(const S : string) : LongInt; var G : LongInt; I : Integer; U : string; begin Result := 0; U := AnsiUpperCase(S); for I := 1 to Length(U) do begin Result := (Result shl 4) + Ord(U[I]); G := LongInt(Result and $F0000000); if (G <> 0) then Result := Result xor (G shr 24); Result := Result and (not G); end; Result := Result mod 1021; end; {$IFDEF OVERFLOW_CHECKS_ON}{$Q+}{$ENDIF} { -------------------------------------------------------------------------- } function TAbArchiveList.Get(Index : Integer): TAbArchiveItem; begin Result := TAbArchiveItem(FList[Index]); end; { -------------------------------------------------------------------------- } function TAbArchiveList.GetCount : Integer; begin Result := FList.Count; end; { -------------------------------------------------------------------------- } function TAbArchiveList.GetEnumerator: TAbArchiveListEnumerator; begin Result := TAbArchiveListEnumerator.Create(Self); end; { -------------------------------------------------------------------------- } function TAbArchiveList.IsActiveDupe(const FN : string) : Boolean; var Look : TAbArchiveItem; I : Integer; begin if FOwnsItems then begin Look := HashTable[GenerateHash(FN)]; while Look <> nil do begin if (CompareText(Look.FileName, FN) = 0) and (Look.Action <> aaDelete) then begin Result := True; Exit; end; Look := Look.NextItem; end; end else begin for I := 0 to Count - 1 do if (CompareText(Items[I].FileName, FN) = 0) and (Items[I].Action <> aaDelete) then begin Result := True; Exit; end; end; Result := False; end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.Put(Index : Integer; Item : TAbArchiveItem); var H : LongInt; Look : TAbArchiveItem; Last : Pointer; FN : string; begin if FOwnsItems then begin FN := TAbArchiveItem(FList[Index]).FileName; Last := @HashTable[GenerateHash(FN)]; Look := TAbArchiveItem(Last^); { Delete old index } while Look <> nil do begin if CompareText(Look.FileName, FN) = 0 then begin Move(Look.NextItem, Last^, SizeOf(Pointer)); Break; end; Last := @Look.NextItem; Look := TAbArchiveItem(Last^); end; { Free old instance } TObject(FList[Index]).Free; { Add new index } H := GenerateHash(TAbArchiveItem(Item).FileName); TAbArchiveItem(Item).NextItem := HashTable[H]; HashTable[H] := TAbArchiveItem(Item); end; { Replace pointer } FList[Index] := Item; end; { TAbArchive implementation ================================================ } { TAbArchive } constructor TAbArchive.CreateInit; begin inherited Create; FIsDirty := False; FAutoSave := False; FItemList := TAbArchiveList.Create(True); StoreOptions := []; ExtractOptions := []; FStatus := asIdle; FOnProgress := DoProgress; // BaseDirectory := ExtractFilePath(ParamStr(0)); end; { -------------------------------------------------------------------------- } constructor TAbArchive.Create(const FileName : string; Mode : Word); {create an archive by opening a filestream on filename with the given mode} begin FOwnsStream := True; CreateFromStream(TFileStreamEx.Create(FileName, Mode), FileName); FMode := Mode; end; { -------------------------------------------------------------------------- } constructor TAbArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); {create an archive based on an existing stream} begin CreateInit; FArchiveName := aArchiveName; FStream := aStream; end; { -------------------------------------------------------------------------- } destructor TAbArchive.Destroy; begin FItemList.Free; if FOwnsStream then FStream.Free; FLogStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Add(aItem : TAbArchiveItem); var Confirm, ItemAdded : Boolean; begin ItemAdded := False; try CheckValid; if FItemList.IsActiveDupe(aItem.FileName) then begin if (soFreshen in StoreOptions) then Freshen(aItem) else if (soReplace in StoreOptions) then Replace(aItem) else DoProcessItemFailure(aItem, ptAdd, ecAbbrevia, AbDuplicateName); Exit; end; DoConfirmProcessItem(aItem, ptAdd, Confirm); if not Confirm then Exit; aItem.Action := aaAdd; FItemList.Add(aItem); ItemAdded := True; FIsDirty := True; if AutoSave then Save; finally if not ItemAdded then aItem.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddEntry(const Path : String; const ArchiveDirectory : String); var Item : TAbArchiveItem; FullSourceFileName, FullArchiveFileName : String; begin MakeFullNames(Path, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); if (FullSourceFileName <> FArchiveName) then begin Item := CreateItem(Path, ArchiveDirectory); Add(Item); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddFiles(const FileMask : string; SearchAttr : Integer); {Add files to the archive where the disk filespec matches} begin AddFilesEx(FileMask, '', SearchAttr); end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); {Add files matching Filemask except those matching ExclusionMask} var PathType : TAbPathType; IsWild : Boolean; SaveDir : string; Mask : string; MaskF : string; procedure CreateItems(Wild, Recursing : Boolean); var i : Integer; Files : TStrings; FilterList : TStringList; Item : TAbArchiveItem; begin FilterList := TStringList.Create; try if (MaskF <> '') then AbFindFilesEx(MaskF, SearchAttr, FilterList, Recursing); Files := TStringList.Create; try AbFindFilesEx(Mask, SearchAttr, Files, Recursing); if (Files.Count > 0) then for i := 0 to pred(Files.Count) do if FilterList.IndexOf(Files[i]) < 0 then if not Wild then begin if (Files[i] <> FArchiveName) then begin Item := CreateItem(Files[i]); Add(Item); end; end else begin if (AbAddBackSlash(FBaseDirectory) + Files[i]) <> FArchiveName then begin Item := CreateItem(Files[i]); Add(Item); end; end; finally Files.Free; end; finally FilterList.Free; end; end; begin if not SupportsEmptyFolders then SearchAttr := SearchAttr and not faDirectory; CheckValid; IsWild := (Pos('*', FileMask) > 0) or (Pos('?', FileMask) > 0); PathType := AbGetPathType(FileMask); Mask := FileMask; AbUnfixName(Mask); MaskF := ExclusionMask; AbUnfixName(MaskF); case PathType of ptNone, ptRelative : begin GetDir(0, SaveDir); if BaseDirectory <> '' then ChDir(BaseDirectory); try CreateItems(IsWild, soRecurse in StoreOptions); finally if BaseDirectory <> '' then ChDir(SaveDir); end; end; ptAbsolute : begin CreateItems(IsWild, soRecurse in StoreOptions); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddFromStream(const NewName : string; aStream : TStream); {Add an item to the archive directly from a TStream descendant} var Confirm : Boolean; Item : TAbArchiveItem; PT : TAbProcessType; begin Item := CreateItem(NewName); CheckValid; PT := ptAdd; if FItemList.IsActiveDupe(NewName) then begin if ((soFreshen in StoreOptions) or (soReplace in StoreOptions)) then begin Item.Free; Item := FItemList[FItemList.Find(NewName)]; PT := ptReplace; end else begin DoProcessItemFailure(Item, ptAdd, ecAbbrevia, AbDuplicateName); Item.Free; Exit; end; end; DoConfirmProcessItem(Item, PT, Confirm); if not Confirm then Exit; FInStream := aStream; Item.Action := aaStreamAdd; if (PT = ptAdd) then FItemList.Add(Item); FIsDirty := True; Save; FInStream := nil; end; { -------------------------------------------------------------------------- } procedure TAbArchive.CheckValid; begin if Status = asInvalid then raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ClearTags; {Clear all tags from the archive} var i : Integer; begin if Count > 0 then for i := 0 to pred(Count) do TAbArchiveItem(FItemList[i]).Tagged := False; end; { -------------------------------------------------------------------------- } function TAbArchive.ConfirmPath(Item : TAbArchiveItem; const NewName : string; out UseName : string) : Boolean; var Path : string; begin if Item.IsDirectory and not (ExtractOptions >= [eoRestorePath, eoCreateDirs]) then begin Result := False; Exit; end; if (NewName = '') then begin UseName := Item.FileName; AbUnfixName(UseName); if Item.IsDirectory then UseName := ExcludeTrailingPathDelimiter(UseName); if (not (eoRestorePath in ExtractOptions)) then UseName := ExtractFileName(UseName); end else UseName := NewName; if (AbGetPathType(UseName) <> ptAbsolute) then UseName := AbAddBackSlash(BaseDirectory) + UseName; Path := ExtractFileDir(UseName); if (Path <> '') and not mbDirectoryExists(Path) then if (eoCreateDirs in ExtractOptions) then AbCreateDirectory(Path) else raise EAbNoSuchDirectory.Create; Result := True; if not Item.IsDirectory and mbFileExists(UseName) then DoConfirmOverwrite(UseName, Result); end; { -------------------------------------------------------------------------- } procedure TAbArchive.Delete(aItem : TAbArchiveItem); {delete an item from the archive} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then DeleteAt(Index); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteAt(Index : Integer); {delete the item at the index from the archive} var Confirm : Boolean; begin CheckValid; SaveIfNeeded(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptDelete, Confirm); if not Confirm then Exit; TAbArchiveItem(FItemList[Index]).Action := aaDelete; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteFiles(const FileMask : string); {delete all files from the archive that match the file mask} begin DeleteFilesEx(FileMask, ''); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteFilesEx(const FileMask, ExclusionMask : string); {Delete files matching Filemask except those matching ExclusionMask} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if MatchesStoredNameEx(FileMask) then if not MatchesStoredNameEx(ExclusionMask) then DeleteAt(i); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteTaggedItems; {delete all tagged items from the archive} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if Tagged then DeleteAt(i); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoProcessItemFailure(Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); begin if Assigned(FOnProcessItemFailure) then FOnProcessItemFailure(Self, Item, ProcessType, ErrorClass, ErrorCode); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoArchiveSaveProgress(Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FOnArchiveSaveProgress) then FOnArchiveSaveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoArchiveProgress(Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FOnArchiveProgress) then FOnArchiveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoArchiveItemProgress(Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FOnArchiveItemProgress) then FOnArchiveItemProgress(Self, Item, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoConfirmOverwrite(var FileName : string; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmOverwrite) then FOnConfirmOverwrite(FileName, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoConfirmProcessItem(Item : TAbArchiveItem; const ProcessType : TAbProcessType; var Confirm : Boolean); const ProcessTypeToLogType : array[TAbProcessType] of TAbLogType = (ltAdd, ltDelete, ltExtract, ltFreshen, ltMove, ltReplace, ltFoundUnhandled); begin Confirm := True; if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(Self, Item, ProcessType, Confirm); if (Confirm and FLogging) then MakeLogEntry(Item.Filename, ProcessTypeToLogType[ProcessType]); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoConfirmSave(var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmSave) then FOnConfirmSave(Self, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoDeflateProgress(aPercentDone: integer); var Abort : Boolean; begin DoProgress(aPercentDone, Abort); if Abort then raise EAbAbortProgress.Create(AbUserAbortS); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoInflateProgress(aPercentDone: integer); var Abort : Boolean; begin DoProgress(aPercentDone, Abort); if Abort then raise EAbAbortProgress.Create(AbUserAbortS); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoLoad; begin if Assigned(FOnLoad) then FOnLoad(Self); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoProgress(Progress : Byte; var Abort : Boolean); begin Abort := False; DoArchiveItemProgress(FCurrentItem, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoSave; begin if Assigned(FOnSave) then FOnSave(Self); end; { -------------------------------------------------------------------------- } procedure TAbArchive.Extract(aItem : TAbArchiveItem; const NewName : string); {extract an item from the archive} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then ExtractAt(Index, NewName); end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractAt(Index : Integer; const NewName : string); {extract an item from the archive at Index} var Confirm : Boolean; ErrorClass : TAbErrorClass; ErrorCode : Integer; UseName : string; begin CheckValid; SaveIfNeeded(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptExtract, Confirm); if not Confirm then Exit; if not ConfirmPath(FItemList[Index], NewName, UseName) then Exit; try FCurrentItem := FItemList[Index]; ExtractItemAt(Index, UseName); except on E : Exception do begin AbConvertException(E, ErrorClass, ErrorCode); DoProcessItemFailure(FItemList[Index], ptExtract, ErrorClass, ErrorCode); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractToStream(const aFileName : string; aStream : TStream); {extract an item from the archive at Index directly to a stream} var Confirm : Boolean; ErrorClass : TAbErrorClass; ErrorCode : Integer; Index : Integer; begin CheckValid; Index := FindFile(aFileName); if (Index = -1) then Exit; SaveIfNeeded(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptExtract, Confirm); if not Confirm then Exit; FCurrentItem := FItemList[Index]; try ExtractItemToStreamAt(Index, aStream); except on E : Exception do begin AbConvertException(E, ErrorClass, ErrorCode); DoProcessItemFailure(FItemList[Index], ptExtract, ErrorClass, ErrorCode); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} begin ExtractFilesEx(FileMask, ''); end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractFilesEx(const FileMask, ExclusionMask : string); {Extract files matching Filemask except those matching ExclusionMask} var i : Integer; Abort : Boolean; begin CheckValid; if Count > 0 then begin for i := 0 to pred(Count) do begin with TAbArchiveItem(FItemList[i]) do if MatchesStoredNameEx(FileMask) and not MatchesStoredNameEx(ExclusionMask) and ((eoCreateDirs in ExtractOptions) or not IsDirectory) then ExtractAt(i, ''); DoArchiveProgress(AbPercentage(succ(i), Count), Abort); if Abort then raise EAbUserAbort.Create; end; DoArchiveProgress(100, Abort); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractTaggedItems; {extract all tagged items from the archive} var i : Integer; Abort : Boolean; begin CheckValid; if Count > 0 then begin for i := 0 to pred(Count) do begin with TAbArchiveItem(FItemList[i]) do if Tagged then ExtractAt(i, ''); DoArchiveProgress(AbPercentage(succ(i), Count), Abort); if Abort then raise EAbUserAbort.Create; end; DoArchiveProgress(100, Abort); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.TestTaggedItems; {test all tagged items in the archive} var i : Integer; Abort : Boolean; begin CheckValid; if Count > 0 then begin for i := 0 to pred(Count) do begin with TAbArchiveItem(FItemList[i]) do if Tagged then begin FCurrentItem := FItemList[i]; TestItemAt(i); end; DoArchiveProgress(AbPercentage(succ(i), Count), Abort); if Abort then raise EAbUserAbort.Create; end; DoArchiveProgress(100, Abort); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.TestAt(Index: Integer); begin FCurrentItem := FItemList[Index]; TestItemAt(Index); end; { -------------------------------------------------------------------------- } function TAbArchive.FindFile(const aFileName : string): Integer; {find the index of the specified file} begin Result := FItemList.Find(aFileName); end; { -------------------------------------------------------------------------- } function TAbArchive.FindItem(aItem : TAbArchiveItem): Integer; {find the index of the specified item} begin Result := FItemList.Find(aItem.FileName); end; { -------------------------------------------------------------------------- } function TAbArchive.FixName(const Value : string) : string; var lValue: string; begin lValue := Value; {$IFDEF MSWINDOWS} if DOSMode then begin {Add the base directory to the filename before converting } {the file spec to the short filespec format. } if BaseDirectory <> '' then begin {Does the filename contain a drive or a leading backslash? } if not ((Pos(':', lValue) = 2) or (Pos(AbPathDelim, lValue) = 1)) then {If not, add the BaseDirectory to the filename.} lValue := AbAddBackSlash(BaseDirectory) + lValue; end; lValue := AbGetShortFileSpec(lValue); end; {$ENDIF} {strip drive stuff} if soStripDrive in StoreOptions then AbStripDrive(lValue); {check for a leading backslash} if lValue[1] = AbPathDelim then System.Delete(lValue, 1, 1); if soStripPath in StoreOptions then begin lValue := ExtractFileName(lValue); end; if soRemoveDots in StoreOptions then AbStripDots(lValue); Result := lValue; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Freshen(aItem : TAbArchiveItem); {freshen the item} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then begin FreshenAt(Index); {point existing item at the new file} if AbGetPathType(aItem.DiskFileName) = ptAbsolute then FItemList[Index].DiskFileName := aItem.DiskFileName; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenAt(Index : Integer); {freshen item at index} var Confirm : Boolean; FR : Boolean; ErrorClass : TAbErrorClass; ErrorCode : Integer; begin CheckValid; SaveIfNeeded(FItemList[Index]); GetFreshenTarget(FItemList[Index]); FR := False; try FR := FreshenRequired(FItemList[Index]); except on E : Exception do begin AbConvertException(E, ErrorClass, ErrorCode); DoProcessItemFailure(FItemList[Index], ptFreshen, ErrorClass, ErrorCode); end; end; if not FR then Exit; DoConfirmProcessItem(FItemList[Index], ptFreshen, Confirm); if not Confirm then Exit; TAbArchiveItem(FItemList[Index]).Action := aaFreshen; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenFiles(const FileMask : string); {freshen all items that match the file mask} begin FreshenFilesEx(FileMask, ''); end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenFilesEx(const FileMask, ExclusionMask : string); {freshen all items that match the file mask} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if MatchesStoredNameEx(FileMask) then if not MatchesStoredNameEx(ExclusionMask) then FreshenAt(i); end; end; end; { -------------------------------------------------------------------------- } function TAbArchive.FreshenRequired(Item : TAbArchiveItem) : Boolean; var FS : TFileStreamEx; DateTime : LongInt; FileTime : Word; FileDate : Word; Matched : Boolean; SaveDir : string; begin GetDir(0, SaveDir); if BaseDirectory <> '' then ChDir(BaseDirectory); try FS := TFileStreamEx.Create(Item.DiskFileName, fmOpenRead or fmShareDenyWrite); try DateTime := FileGetDate(FS.Handle); FileTime := LongRec(DateTime).Lo; FileDate := LongRec(DateTime).Hi; Matched := (Item.LastModFileDate = FileDate) and (Item.LastModFileTime = FileTime) and (Item.UncompressedSize = FS.Size); Result := not Matched; finally FS.Free; end; finally if BaseDirectory <> '' then ChDir(SaveDir); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenTaggedItems; {freshen all tagged items} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if Tagged then FreshenAt(i); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.GetFreshenTarget(Item : TAbArchiveItem); var PathType : TAbPathType; Files : TStrings; SaveDir : string; DName : string; begin PathType := AbGetPathType(Item.DiskFileName); if (soRecurse in StoreOptions) and (PathType = ptNone) then begin GetDir(0, SaveDir); if BaseDirectory <> '' then ChDir(BaseDirectory); try Files := TStringList.Create; try // even if archive supports empty folder we don't have to // freshen it because there is no data, although, the timestamp // can be update since the folder was added AbFindFiles(Item.FileName, faAnyFile and not faDirectory, Files, True); if Files.Count > 0 then begin DName := AbAddBackSlash(BaseDirectory) + Files[0]; AbUnfixName(DName); Item.DiskFileName := DName; end else Item.DiskFileName := ''; finally Files.Free; end; finally if BaseDirectory <> '' then ChDir(SaveDir); end; end else begin if (BaseDirectory <> '') then DName := AbAddBackSlash(BaseDirectory) + Item.FileName else if AbGetPathType(Item.DiskFileName) = ptAbsolute then DName := Item.DiskFileName else DName := Item.FileName; AbUnfixName(DName); Item.DiskFileName := DName; end; end; { -------------------------------------------------------------------------- } function TAbArchive.GetSpanningThreshold : Int64; begin Result := FSpanningThreshold; end; { -------------------------------------------------------------------------- } function TAbArchive.GetSupportsEmptyFolders : Boolean; begin Result := False; end; { -------------------------------------------------------------------------- } function TAbArchive.GetItemCount : Integer; begin if Assigned(FItemList) then Result := FItemList.Count else Result := 0; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Load; {load the archive} begin try LoadArchive; FStatus := asIdle; finally DoLoad; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.MakeLogEntry(const FN: string; LT : TAbLogType); const LogTypeRes : array[TAbLogType] of string = (AbLtAddS, AbLtDeleteS, AbLtExtractS, AbLtFreshenS, AbLtMoveS, AbLtReplaceS, AbLtStartS, AbUnhandledEntityS); var Buf : string; begin if Assigned(FLogStream) then begin Buf := FN + LogTypeRes[LT] + DateTimeToStr(Now) + sLineBreak; FLogStream.Write(Buf[1], Length(Buf) * SizeOf(Char)); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.MakeFullNames(const SourceFileName: String; const ArchiveDirectory: String; out FullSourceFileName: String; out FullArchiveFileName: String); var PathType : TAbPathType; RelativeSourceFileName: String; begin PathType := AbGetPathType(SourceFileName); case PathType of ptNone, ptRelative : begin if FBaseDirectory <> '' then FullSourceFileName := AbAddBackSlash(FBaseDirectory) + SourceFileName else FullSourceFileName := SourceFileName; RelativeSourceFileName := SourceFileName; end; ptAbsolute : begin FullSourceFileName := SourceFileName; if FBaseDirectory <> '' then RelativeSourceFileName := ExtractRelativepath(AbAddBackSlash(FBaseDirectory), SourceFileName) else RelativeSourceFileName := ExtractFileName(SourceFileName); end; end; if ArchiveDirectory <> '' then FullArchiveFileName := AbAddBackSlash(ArchiveDirectory) + RelativeSourceFileName else FullArchiveFileName := RelativeSourceFileName; FullArchiveFileName := FixName(FullArchiveFileName); end; { -------------------------------------------------------------------------- } procedure TAbArchive.Move(aItem : TAbArchiveItem; const NewStoredPath : string); var Confirm : Boolean; Found : Boolean; i : Integer; FixedPath: string; begin CheckValid; FixedPath := FixName(NewStoredPath); Found := False; if Count > 0 then for i := 0 to pred(Count) do if (ItemList[i] <> aItem) and SameText(FixedPath, ItemList[i].FileName) and (ItemList[i].Action <> aaDelete) then begin Found := True; Break; end; if Found then begin DoProcessItemFailure(aItem, ptMove, ecAbbrevia, AbDuplicateName); {even if something gets done in the AddItemFailure, we don't want to continue...} Exit; end; SaveIfNeeded(aItem); DoConfirmProcessItem(aItem, ptMove, Confirm); if not Confirm then Exit; with aItem do begin FileName := FixedPath; Action := aaMove; end; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Replace(aItem : TAbArchiveItem); {replace the item} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then begin ReplaceAt(Index); {point existing item at the new file} if AbGetPathType(aItem.DiskFileName) = ptAbsolute then FItemList[Index].DiskFileName := aItem.DiskFileName; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ReplaceAt(Index : Integer); {replace item at Index} var Confirm : Boolean; begin CheckValid; SaveIfNeeded(FItemList[Index]); GetFreshenTarget(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptReplace, Confirm); if not Confirm then Exit; TAbArchiveItem(FItemList[Index]).Action := aaReplace; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Save; {save the archive} var Confirm : Boolean; begin if Status = asInvalid then Exit; if not FIsDirty then Exit; DoConfirmSave(Confirm); if not Confirm then Exit; SaveArchive; FIsDirty := False; DoSave; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SaveIfNeeded(aItem : TAbArchiveItem); begin if (aItem.Action <> aaNone) then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetBaseDirectory(Value : string); begin if (Value <> '') then if Value[Length(Value)] = AbPathDelim then if (Length(Value) > 1) and (Value[Length(Value) - 1] <> ':') then System.Delete(Value, Length(Value), 1); if (Length(Value) = 0) or mbDirectoryExists(Value) then FBaseDirectory := Value else raise EAbNoSuchDirectory.Create; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetSpanningThreshold( Value : Int64 ); begin FSpanningThreshold := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetLogFile(const Value : string); begin FLogFile := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetLogging(Value : Boolean); begin FLogging := Value; if Assigned(FLogStream) then begin FLogStream.Free; FLogStream := nil; end; if FLogging and (FLogFile <> '') then begin try FLogStream := TFileStream.Create(FLogFile, fmCreate or fmOpenWrite); MakeLogEntry(FArchiveName, ltStart); except raise EAbException.Create(AbLogCreateErrorS); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.TagItems(const FileMask : string); {tag all items that match the mask} var i : Integer; begin if Count > 0 then for i := 0 to pred(Count) do with TAbArchiveItem(FItemList[i]) do begin if MatchesStoredNameEx(FileMask) then Tagged := True; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.UnTagItems(const FileMask : string); {clear tags for all items that match the mask} var i : Integer; begin if Count > 0 then for i := 0 to pred(Count) do with TAbArchiveItem(FItemList[i]) do begin if MatchesStoredNameEx(FileMask) then Tagged := False; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin raise EAbSpanningNotSupported.Create; end; { -------------------------------------------------------------------------- } function TAbArchive.CreateItem(const FileSpec : string): TAbArchiveItem; begin // This function is used by Abbrevia. We don't use it but a dummy // definition is needed for the code to compile successfully. raise Exception.Create(''); end; { -------------------------------------------------------------------------- } { TAbExtraField implementation ============================================= } procedure TAbExtraField.Assign(aSource : TAbExtraField); begin SetBuffer(aSource.Buffer); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Changed; begin // No-op end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Clear; begin FBuffer := nil; Changed; end; { -------------------------------------------------------------------------- } procedure TAbExtraField.CloneFrom(aSource : TAbExtraField; aID : Word); var Data : Pointer; DataSize : Word; begin if aSource.Get(aID, Data, DataSize) then Put(aID, Data, DataSize) else Delete(aID); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Delete(aID : Word); var SubField : PAbExtraSubField; begin if FindField(aID, SubField) then begin DeleteField(SubField); Changed; end; end; { -------------------------------------------------------------------------- } procedure TAbExtraField.DeleteField(aSubField : PAbExtraSubField); var Len, Offset : Integer; begin Len := SizeOf(TAbExtraSubField) + aSubField.Len; Offset := Pointer(aSubField) - Pointer(FBuffer); if Offset + Len < Length(FBuffer) then Move(FBuffer[Offset + Len], aSubField^, Length(FBuffer) - Offset - Len); SetLength(FBuffer, Length(FBuffer) - Len); end; { -------------------------------------------------------------------------- } function TAbExtraField.FindField(aID : Word; out aSubField : PAbExtraSubField) : Boolean; begin Result := False; aSubField := nil; while FindNext(aSubField) do if aSubField.ID = aID then begin Result := True; Break; end; end; { -------------------------------------------------------------------------- } function TAbExtraField.FindNext(var aCurField : PAbExtraSubField) : Boolean; var BytesLeft : Integer; begin if aCurField = nil then begin aCurField := PAbExtraSubField(FBuffer); BytesLeft := Length(FBuffer); end else begin BytesLeft := Length(FBuffer) - (Pointer(aCurField) - Pointer(FBuffer)) - SizeOf(TAbExtraSubField) - aCurField.Len; Inc(Pointer(aCurField), aCurField.Len + SizeOf(TAbExtraSubField)); end; Result := (BytesLeft >= SizeOf(TAbExtraSubField)); if Result and (BytesLeft < SizeOf(TAbExtraSubField) + aCurField.Len) then aCurField.Len := BytesLeft - SizeOf(TAbExtraSubField); end; { -------------------------------------------------------------------------- } function TAbExtraField.Get(aID : Word; out aData : Pointer; out aDataSize : Word) : Boolean; var SubField : PAbExtraSubField; begin Result := FindField(aID, SubField); if Result then begin aData := @SubField.Data; aDataSize := SubField.Len; end else begin aData := nil; aDataSize := 0; end; end; { -------------------------------------------------------------------------- } function TAbExtraField.GetCount : Integer; var SubField : PAbExtraSubField; begin Result := 0; SubField := nil; while FindNext(SubField) do Inc(Result); end; { -------------------------------------------------------------------------- } function TAbExtraField.GetID(aIndex : Integer): Word; var i: Integer; SubField : PAbExtraSubField; begin i := 0; SubField := nil; while FindNext(SubField) do if i = aIndex then begin Result := SubField.ID; Exit; end else Inc(i); raise EListError.CreateFmt(SListIndexError, [aIndex]); end; { -------------------------------------------------------------------------- } function TAbExtraField.GetStream(aID : Word; out aStream : TStream): Boolean; var Data: Pointer; DataSize: Word; begin Result := Get(aID, Data, DataSize); if Result then begin aStream := TMemoryStream.Create; aStream.WriteBuffer(Data^, DataSize); aStream.Position := 0; end; end; { -------------------------------------------------------------------------- } function TAbExtraField.Has(aID : Word): Boolean; var SubField : PAbExtraSubField; begin Result := FindField(aID, SubField); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.LoadFromStream(aStream : TStream; aSize : Word); begin SetLength(FBuffer, aSize); if aSize > 0 then aStream.ReadBuffer( FBuffer[0], aSize); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Put(aID : Word; const aData; aDataSize : Word); var Offset : Cardinal; SubField : PAbExtraSubField; begin if FindField(aID, SubField) then begin if SubField.Len = aDataSize then begin Move(aData, SubField.Data, aDataSize); Changed; Exit; end else DeleteField(SubField); end; Offset := Length(FBuffer); SetLength(FBuffer, Length(FBuffer) + SizeOf(TAbExtraSubField) + aDataSize); SubField := PAbExtraSubField(@FBuffer[Offset]); SubField.ID := aID; SubField.Len := aDataSize; Move(aData, SubField.Data, aDataSize); Changed; end; { -------------------------------------------------------------------------- } procedure TAbExtraField.SetBuffer(const aValue : TByteDynArray); begin SetLength(FBuffer, Length(aValue)); if Length(FBuffer) > 0 then Move(aValue[0], FBuffer[0], Length(FBuffer)); Changed; end; { -------------------------------------------------------------------------- } { ========================================================================== } { TAbArchiveStreamHelper } constructor TAbArchiveStreamHelper.Create(AStream: TStream); begin if Assigned(AStream) then FStream := AStream else raise Exception.Create('nil stream'); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abbase.pas�������������������������������������������0000644�0001750�0000144�00000003470�14743153644�022356� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBase.pas *} {*********************************************************} {* ABBREVIA: Base component class *} {*********************************************************} unit AbBase; {$I AbDefine.inc} interface uses Classes; type TAbBaseComponent = class(TComponent) protected {methods} function GetVersion : string; procedure SetVersion(const Value : string); protected {properties} property Version : string read GetVersion write SetVersion stored False; end; implementation uses AbConst; { -------------------------------------------------------------------------- } function TAbBaseComponent.GetVersion : string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbBaseComponent.SetVersion(const Value : string); begin {NOP} end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abbitbkt.pas�����������������������������������������0000644�0001750�0000144�00000015600�14743153644�022721� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBitBkt.pas *} {*********************************************************} {* ABBREVIA: Bit bucket memory stream class *} {*********************************************************} unit AbBitBkt; {$I AbDefine.inc} interface uses Classes, AbUtils; type TAbBitBucketStream = class(TStream) private FBuffer : {$IFDEF UNICODE}PByte{$ELSE}PAnsiChar{$ENDIF}; FBufSize : longint; FBufPosn : longint; FPosn : Int64; FSize : Int64; FTail : Int64; protected public constructor Create(aBufSize : cardinal); destructor Destroy; override; function Read(var Buffer; Count : Longint) : Longint; override; function Write(const Buffer; Count : Longint) : Longint; override; function Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; override; procedure ForceSize(aSize : Int64); end; implementation uses Math, SysUtils, AbExcept; {Notes: The buffer is a circular queue without a head pointer; FTail is where data is next going to be written and it wraps indescriminately. The buffer can never be empty--it is always full (initially it is full of binary zeros. The class is designed to act as a bit bucket for the test feature of Abbrevia's zip code; it is not intended as a complete class with many possible applications. It is designed to be written to in a steady progression with some reading back in the recently written stream (the buffer size details how far back the Seek method will work). Seeking outside this buffer will result in exceptions being generated. For testing deflated files, the buffer size should be 32KB, for imploded files, either 8KB or 4KB. The Create constructor limits the buffer size to these values.} {===TAbBitBucketStream===============================================} constructor TAbBitBucketStream.Create(aBufSize : cardinal); begin inherited Create; if (aBufSize <> 4096) and (aBufSize <> 8192) and (aBufSize <> 32768) then FBufSize := 32768 else FBufSize := aBufSize; {add a 1KB leeway} inc(FBufSize, 1024); GetMem(FBuffer, FBufSize); end; {--------} destructor TAbBitBucketStream.Destroy; begin if (FBuffer <> nil) then FreeMem(FBuffer, FBufSize); inherited Destroy; end; {--------} procedure TAbBitBucketStream.ForceSize(aSize : Int64); begin FSize := aSize; end; {--------} function TAbBitBucketStream.Read(var Buffer; Count : Longint) : Longint; var Chunk2Size : Int64; Chunk1Size : Int64; OutBuffer : PByte; begin OutBuffer := @Buffer; {we cannot read more bytes than there is buffer} if (Count > FBufSize) then raise EAbBBSReadTooManyBytes.Create(Count); {calculate the size of the chunks} if (FBufPosn <= FTail) then begin Chunk1Size := FTail - FBufPosn; if (Chunk1Size > Count) then Chunk1Size := Count; Chunk2Size := 0; end else begin Chunk1Size := FBufSize - FBufPosn; if (Chunk1Size > Count) then begin Chunk1Size := Count; Chunk2Size := 0; end else begin Chunk2Size := FTail; if (Chunk2Size > (Count - Chunk1Size)) then Chunk2Size := Count - Chunk1Size; end end; {we cannot read more bytes than there are available} if (Count > (Chunk1Size + Chunk2Size)) then raise EAbBBSReadTooManyBytes.Create(Count); {perform the read} if (Chunk1Size > 0) then begin Move(FBuffer[FBufPosn], OutBuffer^, Chunk1Size); inc(FBufPosn, Chunk1Size); inc(FPosn, Chunk1Size); end; if (Chunk2Size > 0) then begin {we've wrapped} Move(FBuffer[0], (OutBuffer + Chunk1Size)^, Chunk2Size); FBufPosn := Chunk2Size; inc(FPosn, Chunk2Size); end; Result := Count; end; {--------} function TAbBitBucketStream.Write(const Buffer; Count : Longint) : Longint; var Chunk2Size : Int64; Chunk1Size : Int64; InBuffer : PByte; Overage : longint; begin Result := Count; InBuffer := @Buffer; {we cannot write more bytes than there is buffer} while Count > FBufSize do begin Overage := Min(FBufSize, Count - FBufSize); Write(InBuffer^, Overage); Inc(PtrInt(InBuffer), Overage); Dec(Count, Overage); end; {calculate the size of the chunks} Chunk1Size := FBufSize - FTail; if (Chunk1Size > Count) then begin Chunk1Size := Count; Chunk2Size := 0; end else begin Chunk2Size := Count - Chunk1Size; end; {write the first chunk} if (Chunk1Size > 0) then begin Move(InBuffer^, FBuffer[FTail], Chunk1Size); inc(FTail, Chunk1Size); end; {if the second chunk size is not zero, write the second chunk; note that we have wrapped} if (Chunk2Size > 0) then begin Move((InBuffer + Chunk1Size)^, FBuffer[0], Chunk2Size); FTail := Chunk2Size; end; {the stream size and position have changed} inc(FSize, Count); FPosn := FSize; FBufPosn := FTail; end; {--------} function TAbBitBucketStream.Seek(const Offset : Int64; Origin : TSeekOrigin): Int64; var Posn : Int64; BytesBack : longint; begin {calculate the new position} case Origin of soBeginning : Posn := Offset; soCurrent : Posn := FPosn + Offset; soEnd : if (Offset = 0) then begin {special case: position at end of stream} FBufPosn := FTail; FPosn := FSize; Result := FSize; Exit; end else begin Posn := FSize + Offset; end; else raise EAbBBSInvalidOrigin.Create; end; {calculate whether the new position is within the buffer; if not, raise exception} if (Posn > FSize) or (Posn <= (FSize - FBufSize)) then raise EAbBBSSeekOutsideBuffer.Create; {set the internal fields for the new position} FPosn := Posn; BytesBack := FSize - Posn; if (BytesBack <= FTail) then FBufPosn := FTail - BytesBack else FBufPosn := longint(FTail) + FBufSize - BytesBack; {return the new position} Result := Posn; end; {====================================================================} end. ��������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abbrowse.pas�����������������������������������������0000644�0001750�0000144�00000051647�14743153644�022756� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBrowse.pas *} {*********************************************************} {* ABBREVIA: Base Browser Component *} {*********************************************************} unit AbBrowse; {$I AbDefine.inc} interface uses Classes, AbBase, AbUtils, AbArcTyp; type IAbProgressMeter = interface ['{4B766704-FD20-40BF-BA40-2EC2DD77B178}'] procedure DoProgress(Progress : Byte); procedure Reset; end; TAbBaseBrowser = class(TAbBaseComponent) public FArchive : TAbArchive; protected {private} FSpanningThreshold : Longint; FItemProgressMeter : IAbProgressMeter; FArchiveProgressMeter : IAbProgressMeter; FBaseDirectory : string; FFileName : string; FLogFile : string; FLogging : Boolean; FOnArchiveProgress : TAbArchiveProgressEvent; FOnArchiveItemProgress : TAbArchiveItemProgressEvent; FOnChange : TNotifyEvent; FOnConfirmProcessItem : TAbArchiveItemConfirmEvent; FOnLoad : TAbArchiveEvent; FOnProcessItemFailure : TAbArchiveItemFailureEvent; FOnRequestImage : TAbRequestImageEvent; FTempDirectory : string; { detected compression type } FArchiveType : TAbArchiveType; FForceType : Boolean; protected {private methods} function GetCount : Integer; function GetItem(Value : Longint) : TAbArchiveItem; function GetSpanned : Boolean; function GetStatus : TAbArchiveStatus; procedure ResetMeters; virtual; procedure SetArchiveProgressMeter(const Value: IAbProgressMeter); procedure SetCompressionType(const Value: TAbArchiveType); procedure SetBaseDirectory(const Value : string); procedure SetItemProgressMeter(const Value: IAbProgressMeter); procedure SetSpanningThreshold(Value : Longint); procedure SetLogFile(const Value : string); procedure SetLogging(Value : Boolean); procedure SetTempDirectory(const Value : string); procedure Loaded; override; procedure Notification(Component: TComponent; Operation: TOperation); override; protected {virtual methods} procedure DoArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); virtual; procedure DoChange; virtual; procedure DoConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); virtual; procedure DoLoad(Sender : TObject); virtual; procedure DoProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); virtual; procedure SetOnRequestImage(Value : TAbRequestImageEvent); virtual; procedure InitArchive; virtual; {This method must be defined in descendent classes} procedure SetFileName(const aFileName : string); virtual; abstract; protected {properties} property Archive : TAbArchive read FArchive; property ArchiveProgressMeter : IAbProgressMeter read FArchiveProgressMeter write SetArchiveProgressMeter; property BaseDirectory : string read FBaseDirectory write SetBaseDirectory; property FileName : string read FFileName write SetFileName; property SpanningThreshold : Longint read FSpanningThreshold write SetSpanningThreshold default 0; property ItemProgressMeter : IAbProgressMeter read FItemProgressMeter write SetItemProgressMeter; property LogFile : string read FLogFile write SetLogFile; property Logging : Boolean read FLogging write SetLogging default False; property Spanned : Boolean read GetSpanned; property TempDirectory : string read FTempDirectory write SetTempDirectory; protected {events} property OnArchiveProgress : TAbArchiveProgressEvent read FOnArchiveProgress write FOnArchiveProgress; property OnArchiveItemProgress : TAbArchiveItemProgressEvent read FOnArchiveItemProgress write FOnArchiveItemProgress; property OnConfirmProcessItem : TAbArchiveItemConfirmEvent read FOnConfirmProcessItem write FOnConfirmProcessItem; property OnProcessItemFailure : TAbArchiveItemFailureEvent read FOnProcessItemFailure write FOnProcessItemFailure; property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write SetOnRequestImage; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure ClearTags; {Clear all tags from the archive} function FindItem(aItem : TAbArchiveItem) : Integer; function FindFile(const aFileName : string) : Integer; procedure TagItems(const FileMask : string); {tag all items that match the mask} procedure UnTagItems(const FileMask : string); {clear tags for all items that match the mask} procedure CloseArchive; {closes the archive by setting FileName to ''} procedure OpenArchive(const aFileName : string); {opens the archive} public {properties} property Count : Integer read GetCount; property Items[Index : Integer] : TAbArchiveItem read GetItem; default; property Status : TAbArchiveStatus read GetStatus; property ArchiveType : TAbArchiveType read FArchiveType write SetCompressionType default atUnknown; property ForceType : Boolean read FForceType write FForceType default False; public {events} property OnChange : TNotifyEvent read FOnChange write FOnChange; property OnLoad : TAbArchiveEvent read FOnLoad write FOnLoad; end; function AbDetermineArcType(const FN : string; AssertType : TAbArchiveType) : TAbArchiveType; overload; function AbDetermineArcType(aStream: TStream) : TAbArchiveType; overload; implementation uses SysUtils, AbExcept, {$IF DEFINED(ExtractCabSupport)} AbCabTyp, {$ENDIF} AbZipTyp, AbTarTyp, AbGzTyp, AbBzip2Typ, AbLzmaTyp, AbXzTyp, AbZstdTyp, DCOSUtils, DCClassesUtf8; { TAbBaseBrowser implementation ======================================= } { -------------------------------------------------------------------------- } constructor TAbBaseBrowser.Create(AOwner : TComponent); begin inherited Create(AOwner); FLogFile := ''; FLogging := False; FSpanningThreshold := 0; FArchiveType := atUnknown; FForceType := False; end; { -------------------------------------------------------------------------- } destructor TAbBaseBrowser.Destroy; begin FArchive.Free; FArchive := nil; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.ClearTags; {Clear all tags from the archive} begin if Assigned(FArchive) then FArchive.ClearTags else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.CloseArchive; {closes the archive by setting FileName to ''} begin if FFileName <> '' then FileName := ''; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FItemProgressMeter) then FItemProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveItemProgress) then FOnArchiveItemProgress(Self, Item, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FArchiveProgressMeter) then FArchiveProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveProgress) then FOnArchiveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoChange; begin if Assigned(FOnChange) then begin FOnChange(Self); end; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); begin Confirm := True; if Assigned(FItemProgressMeter) then FItemProgressMeter.Reset; if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(Self, Item, ProcessType, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoLoad(Sender : TObject); begin if Assigned(FOnLoad) then FOnLoad(Self); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); begin if Assigned(FOnProcessItemFailure) then FOnProcessItemFailure(Self, Item, ProcessType, ErrorClass, ErrorCode); end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.FindItem(aItem : TAbArchiveItem) : Integer; begin if Assigned(FArchive) then Result := FArchive.FindItem(aItem) else Result := -1; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.FindFile(const aFileName : string) : Integer; begin if Assigned(FArchive) then Result := FArchive.FindFile(aFileName) else Result := -1; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetSpanned : Boolean; begin if Assigned(FArchive) then Result := FArchive.Spanned else Result := False; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetStatus : TAbArchiveStatus; begin if Assigned(FArchive) then Result := FArchive.Status else Result := asInvalid; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetCount : Integer; begin if Assigned(FArchive) then Result := FArchive.Count else Result := 0; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetItem(Value : Longint) : TAbArchiveItem; begin if Assigned(FArchive) then Result := FArchive.ItemList[Value] else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.InitArchive; begin ResetMeters; if Assigned(FArchive) then begin {properties} FArchive.SpanningThreshold := FSpanningThreshold; FArchive.LogFile := FLogFile; FArchive.Logging := FLogging; FArchive.TempDirectory := FTempDirectory; SetBaseDirectory(FBaseDirectory); {events} FArchive.OnArchiveProgress := DoArchiveProgress; FArchive.OnArchiveItemProgress := DoArchiveItemProgress; FArchive.OnConfirmProcessItem := DoConfirmProcessItem; FArchive.OnLoad := DoLoad; FArchive.OnProcessItemFailure := DoProcessItemFailure; FArchive.OnRequestImage := FOnRequestImage; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.Loaded; begin inherited Loaded; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.Notification(Component: TComponent; Operation: TOperation); begin inherited Notification(Component, Operation); if (Operation = opRemove) then begin if Assigned(ItemProgressMeter) and Component.IsImplementorOf(ItemProgressMeter) then ItemProgressMeter := nil; if Assigned(ArchiveProgressMeter) and Component.IsImplementorOf(ArchiveProgressMeter) then ArchiveProgressMeter := nil; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.OpenArchive(const aFileName : string); {opens the archive} begin FileName := AFileName; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.ResetMeters; begin if Assigned(FArchiveProgressMeter) then FArchiveProgressMeter.Reset; if Assigned(FItemProgressMeter) then FItemProgressMeter.Reset; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetBaseDirectory(const Value : string); begin if Assigned(FArchive) then begin FArchive.BaseDirectory := Value; FBaseDirectory := FArchive.BaseDirectory; end else FBaseDirectory := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetSpanningThreshold(Value : Longint); begin FSpanningThreshold := Value; if Assigned(FArchive) then FArchive.SpanningThreshold := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetLogFile(const Value : string); begin FLogFile := Value; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then FArchive.LogFile := Value; SetLogging(Value <> ''); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetLogging(Value : Boolean); begin FLogging := Value; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then FArchive.Logging:= Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetOnRequestImage(Value : TAbRequestImageEvent); begin FOnRequestImage := Value; if Assigned(FArchive) then FArchive.OnRequestImage := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetTempDirectory(const Value : string); begin FTempDirectory := Value; if Assigned(FArchive) then FArchive.TempDirectory := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.TagItems(const FileMask : string); {tag all items that match the mask} begin if Assigned(FArchive) then FArchive.TagItems(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.UnTagItems(const FileMask : string); {clear tags for all items that match the mask} begin if Assigned(FArchive) then FArchive.UnTagItems(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetCompressionType(const Value: TAbArchiveType); begin if not Assigned(FArchive) or (Status <> asInvalid) then FArchiveType := Value else raise EAbArchiveBusy.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetArchiveProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FArchiveProgressMeter, opRemove); FArchiveProgressMeter := Value; ReferenceInterface(FArchiveProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetItemProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FItemProgressMeter, opRemove); FItemProgressMeter := Value; ReferenceInterface(FItemProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } function AbDetermineArcType(const FN : string; AssertType : TAbArchiveType) : TAbArchiveType; var Ext : string; FS : TStream; begin Result := AssertType; if Result = atUnknown then begin { Guess archive type based on it's extension } Ext := UpperCase(ExtractFileExt(FN)); if (Ext = '.ZIP') or (Ext = '.JAR') or (Ext = '.ZIPX') then Result := atZip else if (Ext = '.EXE') then Result := atSelfExtZip else if (Ext = '.TAR') then Result := atTar else if (Ext = '.GZ') then Result := atGzip else if (Ext = '.TGZ') then Result := atGzippedTar else if (Ext = '.CAB') then Result := atCab else if (Ext = '.BZ2') then Result := atBzip2 else if (Ext = '.TBZ') then Result := atBzippedTar else if (Ext = '.XZ') then Result := atXz else if (Ext = '.TXZ') then Result := atXzippedTar else if (Ext = '.LZMA') then Result := atLzma else if (Ext = '.TLZ') then Result := atLzmaTar else if (Ext = '.ZST') then Result := atZstd else if (Ext = '.TZST') then Result := atZstdTar; end; {$IF NOT DEFINED(ExtractCabSupport)} if Result = atCab then Result := atUnknown; {$ENDIF} if mbFileExists(FN) and (AbFileGetSize(FN) > 0) then begin { If the file doesn't exist (or is empty) presume to make one, otherwise guess or verify the contents } try FS := TFileStreamEx.Create(FN, fmOpenRead or fmShareDenyNone); try if Result <> atUnknown then begin case Result of atZip : begin Result := VerifyZip(FS); end; atSelfExtZip : begin Result := VerifySelfExtracting(FS); end; atTar : begin Result := VerifyTar(FS); end; atGzip, atGzippedTar: begin Result := VerifyGzip(FS); end; {$IF DEFINED(ExtractCabSupport)} atCab : begin Result := VerifyCab(FS); end; {$ENDIF} atBzip2, atBzippedTar: begin Result := VerifyBzip2(FS); end; atXz, atXzippedTar: begin Result := VerifyXz(FS); end; atLzma, atLzmaTar: begin Result := VerifyLzma(FS); end; atZstd, atZStdTar: begin Result := VerifyZstd(FS); end; end; end; if Result = atUnknown then Result := AbDetermineArcType(FS) finally FS.Free; end; except // Skip end; end; end; { -------------------------------------------------------------------------- } function AbDetermineArcType(aStream: TStream): TAbArchiveType; begin { VerifyZip returns true for self-extracting zips too, so test those first } Result := VerifySelfExtracting(aStream); { VerifyZip returns true for example when ZIP file is stored in a TAR archive, so test it first } if Result = atUnknown then Result := VerifyTar(aStream); if Result = atUnknown then Result := VerifyZip(aStream); if Result = atUnknown then Result := VerifyGzip(aStream); if Result = atUnknown then Result := VerifyBzip2(aStream); {$IF DEFINED(ExtractCabSupport)} if Result = atUnknown then Result := VerifyCab(aStream); {$ENDIF} if Result = atUnknown then Result := VerifyXz(aStream); if Result = atUnknown then Result := VerifyZstd(aStream); end; { -------------------------------------------------------------------------- } end. �����������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abbzip2.pas������������������������������������������0000644�0001750�0000144�00000066040�14743153644�022474� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * This program, "bzip2", the associated library "libbzip2", and all * documentation, are copyright (C) 1996-2007 Julian R Seward. All * rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * * 3. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * * 4. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Julian Seward, jseward@bzip.org * bzip2/libbzip2 version 1.0.5 of 10 December 2007 * * Pascal wrapper created by Edison Mera, version 1.04 * http://edisonlife.homelinux.com/ * * Dynamic and runtime linking and Win64/OS X/Linux support by Craig Peterson * http://tpabbrevia.sourceforge.net/ * ***** END LICENSE BLOCK ***** *) unit AbBzip2; {$I AbDefine.inc} interface uses SysUtils, Classes; type TAlloc = function(opaque: Pointer; Items, Size: Integer): Pointer; cdecl; TFree = procedure(opaque, Block: Pointer); cdecl; // Internal structure. Ignore. TBZStreamRec = record next_in: PByte; // next input byte avail_in: Integer; // number of bytes available at next_in total_in_lo32: Integer; // total nb of input bytes read so far total_in_hi32: Integer; next_out: PByte; // next output byte should be put here avail_out: Integer; // remaining free space at next_out total_out_lo32: Integer; // total nb of bytes output so far total_out_hi32: Integer; state: Pointer; bzalloc: TAlloc; // used to allocate the internal state bzfree: TFree; // used to free the internal state opaque: Pointer; end; // Abstract ancestor class TCustomBZip2Stream = class(TStream) private FStrm: TStream; FStrmPos: Int64; FOnProgress: TNotifyEvent; FBZRec: TBZStreamRec; FBuffer: array[Word] of Byte; protected procedure Progress(Sender: TObject); dynamic; property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; constructor Create(Strm: TStream); end; { TBZCompressionStream compresses data on the fly as data is written to it, and stores the compressed data to another stream. TBZCompressionStream is write-only and strictly sequential. Reading from the stream will raise an exception. Using Seek to move the stream pointer will raise an exception. Output data is cached internally, written to the output stream only when the internal output buffer is full. All pending output data is flushed when the stream is destroyed. The Position property returns the number of uncompressed bytes of data that have been written to the stream so far. CompressionRate returns the on-the-fly percentage by which the original data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 If raw data size = 100 and compressed data size = 25, the CompressionRate is 75% The OnProgress event is called each time the output buffer is filled and written to the output stream. This is useful for updating a progress indicator when you are writing a large chunk of data to the compression stream in a single call.} TBZCompressionStream = class(TCustomBZip2Stream) private function GetCompressionRate: Single; public constructor Create(Level: IntPtr; Dest: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property CompressionRate: Single read GetCompressionRate; property OnProgress; end; { TDecompressionStream decompresses data on the fly as data is read from it. Compressed data comes from a separate source stream. TDecompressionStream is read-only and unidirectional; you can seek forward in the stream, but not backwards. The special case of setting the stream position to zero is allowed. Seeking forward decompresses data until the requested position in the uncompressed data has been reached. Seeking backwards, seeking relative to the end of the stream, requesting the size of the stream, and writing to the stream will raise an exception. The Position property returns the number of bytes of uncompressed data that have been read from the stream so far. The OnProgress event is called each time the internal input buffer of compressed data is exhausted and the next block is read from the input stream. This is useful for updating a progress indicator when you are reading a large chunk of data from the decompression stream in a single call.} TBZDecompressionStream = class(TCustomBZip2Stream) private FReadState: LongInt; public constructor Create(Source: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property OnProgress; end; { CompressBuf compresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf Out: OutBuf = ptr to newly allocated buffer containing decompressed data OutBytes = number of bytes in OutBuf } procedure BZCompressBuf(const InBuf: Pointer; InBytes: Integer; out OutBuf: Pointer; out OutBytes: Integer); { DecompressBuf decompresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf OutEstimate = zero, or est. size of the decompressed data Out: OutBuf = ptr to newly allocated buffer containing decompressed data OutBytes = number of bytes in OutBuf } procedure BZDecompressBuf(const InBuf: Pointer; InBytes: Integer; OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); type EBZip2Error = class(Exception); EBZCompressionError = class(EBZip2Error); EBZDecompressionError = class(EBZip2Error); implementation // Compile for Win64 using MSVC // <Path To MSVC>\bin\x86_amd64\cl.exe -c -nologo -GS- -Z7 -wd4086 -Gs32768 // -DBZ_NO_STDIO blocksort.c huffman.c compress.c decompress.c bzlib.c uses {$IFDEF Bzip2Runtime} {$IF DEFINED(FPC)} dynlibs, {$ELSEIF DEFINED(MSWINDOWS)} Windows, {$IFEND} {$ENDIF} AbUtils; {$IFDEF Bzip2Static} {$IF DEFINED(WIN32)} {$L Win32\blocksort.obj} {$L Win32\huffman.obj} {$L Win32\compress.obj} {$L Win32\decompress.obj} {$L Win32\bzlib.obj} {$ELSEIF DEFINED(WIN64)} {$L Win64\blocksort.obj} {$L Win64\huffman.obj} {$L Win64\compress.obj} {$L Win64\decompress.obj} {$L Win64\bzlib.obj} {$IFEND} procedure BZ2_hbMakeCodeLengths; external; procedure BZ2_blockSort; external; procedure BZ2_hbCreateDecodeTables; external; procedure BZ2_hbAssignCodes; external; procedure BZ2_compressBlock; external; procedure BZ2_decompress; external; {$ENDIF} type TLargeInteger = record case Integer of 0: ( LowPart: LongWord; HighPart: LongWord); 1: ( QuadPart: Int64); end; const BZ_RUN = 0; BZ_FLUSH = 1; BZ_FINISH = 2; BZ_OK = 0; BZ_RUN_OK = 1; BZ_FLUSH_OK = 2; BZ_FINISH_OK = 3; BZ_STREAM_END = 4; BZ_SEQUENCE_ERROR = (-1); BZ_PARAM_ERROR = (-2); BZ_MEM_ERROR = (-3); BZ_DATA_ERROR = (-4); BZ_DATA_ERROR_MAGIC = (-5); BZ_IO_ERROR = (-6); BZ_UNEXPECTED_EOF = (-7); BZ_OUTBUFF_FULL = (-8); BZ_BLOCK_SIZE_100K = 9; {$IFDEF Bzip2Static} BZ2_rNums: array[0..511] of Longint = ( 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 936, 638 ); BZ2_crc32Table: array[0..255] of Longint = ( $00000000, $04C11DB7, $09823B6E, $0D4326D9, $130476DC, $17C56B6B, $1A864DB2, $1E475005, $2608EDB8, $22C9F00F, $2F8AD6D6, $2B4BCB61, $350C9B64, $31CD86D3, $3C8EA00A, $384FBDBD, $4C11DB70, $48D0C6C7, $4593E01E, $4152FDA9, $5F15ADAC, $5BD4B01B, $569796C2, $52568B75, $6A1936C8, $6ED82B7F, $639B0DA6, $675A1011, $791D4014, $7DDC5DA3, $709F7B7A, $745E66CD, -$67DC4920, -$631D54A9, -$6E5E7272, -$6A9F6FC7, -$74D83FC4, -$70192275, -$7D5A04AE, -$799B191B, -$41D4A4A8, -$4515B911, -$48569FCA, -$4C97827F, -$52D0D27C, -$5611CFCD, -$5B52E916, -$5F93F4A3, -$2BCD9270, -$2F0C8FD9, -$224FA902, -$268EB4B7, -$38C9E4B4, -$3C08F905, -$314BDFDE, -$358AC26B, -$0DC57FD8, -$09046261, -$044744BA, -$0086590F, -$1EC1090C, -$1A0014BD, -$17433266, -$13822FD3, $34867077, $30476DC0, $3D044B19, $39C556AE, $278206AB, $23431B1C, $2E003DC5, $2AC12072, $128E9DCF, $164F8078, $1B0CA6A1, $1FCDBB16, $018AEB13, $054BF6A4, $0808D07D, $0CC9CDCA, $7897AB07, $7C56B6B0, $71159069, $75D48DDE, $6B93DDDB, $6F52C06C, $6211E6B5, $66D0FB02, $5E9F46BF, $5A5E5B08, $571D7DD1, $53DC6066, $4D9B3063, $495A2DD4, $44190B0D, $40D816BA, -$535A3969, -$579B24E0, -$5AD80207, -$5E191FB2, -$405E4FB5, -$449F5204, -$49DC74DB, -$4D1D696E, -$7552D4D1, -$7193C968, -$7CD0EFBF, -$7811F20A, -$6656A20D, -$6297BFBC, -$6FD49963, -$6B1584D6, -$1F4BE219, -$1B8AFFB0, -$16C9D977, -$1208C4C2, -$0C4F94C5, -$088E8974, -$05CDAFAB, -$010CB21E, -$39430FA1, -$3D821218, -$30C134CF, -$3400297A, -$2A47797D, -$2E8664CC, -$23C54213, -$27045FA6, $690CE0EE, $6DCDFD59, $608EDB80, $644FC637, $7A089632, $7EC98B85, $738AAD5C, $774BB0EB, $4F040D56, $4BC510E1, $46863638, $42472B8F, $5C007B8A, $58C1663D, $558240E4, $51435D53, $251D3B9E, $21DC2629, $2C9F00F0, $285E1D47, $36194D42, $32D850F5, $3F9B762C, $3B5A6B9B, $0315D626, $07D4CB91, $0A97ED48, $0E56F0FF, $1011A0FA, $14D0BD4D, $19939B94, $1D528623, -$0ED0A9F2, -$0A11B447, -$075292A0, -$03938F29, -$1DD4DF2E, -$1915C29B, -$1456E444, -$1097F9F5, -$28D8444A, -$2C1959FF, -$215A7F28, -$259B6291, -$3BDC3296, -$3F1D2F23, -$325E09FC, -$369F144D, -$42C17282, -$46006F37, -$4B4349F0, -$4F825459, -$51C5045E, -$550419EB, -$58473F34, -$5C862285, -$64C99F3A, -$6008828F, -$6D4BA458, -$698AB9E1, -$77CDE9E6, -$730CF453, -$7E4FD28C, -$7A8ECF3D, $5D8A9099, $594B8D2E, $5408ABF7, $50C9B640, $4E8EE645, $4A4FFBF2, $470CDD2B, $43CDC09C, $7B827D21, $7F436096, $7200464F, $76C15BF8, $68860BFD, $6C47164A, $61043093, $65C52D24, $119B4BE9, $155A565E, $18197087, $1CD86D30, $029F3D35, $065E2082, $0B1D065B, $0FDC1BEC, $3793A651, $3352BBE6, $3E119D3F, $3AD08088, $2497D08D, $2056CD3A, $2D15EBE3, $29D4F654, -$3A56D987, -$3E97C432, -$33D4E2E9, -$3715FF60, -$2952AF5B, -$2D93B2EE, -$20D09435, -$24118984, -$1C5E343F, -$189F298A, -$15DC0F51, -$111D12E8, -$0F5A42E3, -$0B9B5F56, -$06D8798D, -$0219643C, -$764702F7, -$72861F42, -$7FC53999, -$7B042430, -$6543742B, -$6182699E, -$6CC14F45, -$680052F4, -$504FEF4F, -$548EF2FA, -$59CDD421, -$5D0CC998, -$434B9993, -$478A8426, -$4AC9A2FD, -$4E08BF4C ); procedure bz_internal_error(errcode: Integer); cdecl; begin raise EBZip2Error.CreateFmt('Compression Error %d', [errcode]); end; { _bz_internal_error } function malloc(size: Integer): Pointer; cdecl; begin GetMem(Result, Size); end; { _malloc } procedure free(block: Pointer); cdecl; begin FreeMem(block); end; { _free } {$ENDIF} const libbz2 = {$IF DEFINED(MSWINDOWS)}'bz2.dll' {$ELSEIF DEFINED(DARWIN)}'libbz2.dylib' {$ELSE}'libbz2.so.1'{$IFEND}; {$IFDEF Bzip2Runtime} var hBzip2: HMODULE; // deflate compresses data BZ2_bzCompressInit: function(var strm: TBZStreamRec; blockSize100k: Integer; verbosity: Integer; workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzCompress: function(var strm: TBZStreamRec; action: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzCompressEnd: function (var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzBuffToBuffCompress: function(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, blockSize100k, verbosity, workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} // inflate decompresses data BZ2_bzDecompressInit: function(var strm: TBZStreamRec; verbosity: Integer; small: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzDecompress: function(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzDecompressEnd: function(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzBuffToBuffDecompress: function(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, small, verbosity: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} {$ELSE} // deflate compresses data function BZ2_bzCompressInit(var strm: TBZStreamRec; blockSize100k: Integer; verbosity: Integer; workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzCompressInit'{$ENDIF}; function BZ2_bzCompress(var strm: TBZStreamRec; action: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzCompress'{$ENDIF}; function BZ2_bzCompressEnd(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzCompressEnd'{$ENDIF}; function BZ2_bzBuffToBuffCompress(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, blockSize100k, verbosity, workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzBuffToBuffCompress'{$ENDIF}; // inflate decompresses data function BZ2_bzDecompressInit(var strm: TBZStreamRec; verbosity: Integer; small: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzDecompressInit'{$ENDIF}; function BZ2_bzDecompress(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzDecompress'{$ENDIF}; function BZ2_bzDecompressEnd(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzDecompressEnd'{$ENDIF}; function BZ2_bzBuffToBuffDecompress(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, small, verbosity: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzBuffToBuffDecompress'{$ENDIF}; {$ENDIF} procedure LoadBzip2DLL; begin {$IFDEF Bzip2Runtime} if hBzip2 <> 0 then Exit; hBzip2 := LoadLibrary(libbz2); if hBzip2 = 0 then raise EBZip2Error.Create('Bzip2 shared library not found'); @BZ2_bzCompressInit := GetProcAddress(hBzip2, 'BZ2_bzCompressInit'); @BZ2_bzCompress := GetProcAddress(hBzip2, 'BZ2_bzCompress'); @BZ2_bzCompressEnd := GetProcAddress(hBzip2, 'BZ2_bzCompressEnd'); @BZ2_bzBuffToBuffCompress := GetProcAddress(hBzip2, 'BZ2_bzBuffToBuffCompress'); @BZ2_bzDecompressInit := GetProcAddress(hBzip2, 'BZ2_bzDecompressInit'); @BZ2_bzDecompress := GetProcAddress(hBzip2, 'BZ2_bzDecompress'); @BZ2_bzDecompressEnd := GetProcAddress(hBzip2, 'BZ2_bzDecompressEnd'); @BZ2_bzBuffToBuffDecompress := GetProcAddress(hBzip2, 'BZ2_bzBuffToBuffDecompress'); {$ENDIF} end; function bzip2AllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; begin GetMem(Result, Items * Size); end; { bzip2AllocMem } procedure bzip2FreeMem(AppData, Block: Pointer); cdecl; begin FreeMem(Block); end; { bzip2FreeMem } function CCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise EBZCompressionError.CreateFmt('error %d', [code]); //!! end; { CCheck } function DCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise EBZDecompressionError.CreateFmt('error %d', [code]); //!! end; { DCheck } procedure BZCompressBuf(const InBuf: Pointer; InBytes: Integer; out OutBuf: Pointer; out OutBytes: Integer); var strm: TBZStreamRec; P: Pointer; begin LoadBzip2DLL; FillChar(strm, sizeof(strm), 0); strm.bzalloc := bzip2AllocMem; strm.bzfree := bzip2FreeMem; OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; GetMem(OutBuf, OutBytes); try strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := OutBytes; CCheck(BZ2_bzCompressInit(strm, 9, 0, 0)); try while CCheck(BZ2_bzCompress(strm, BZ_FINISH)) <> BZ_STREAM_END do begin P := OutBuf; Inc(OutBytes, 256); ReallocMem(OutBuf, OutBytes); strm.next_out := OutBuf + (strm.next_out - P); strm.avail_out := 256; end; finally CCheck(BZ2_bzCompressEnd(strm)); end; ReallocMem(OutBuf, strm.total_out_lo32); OutBytes := strm.total_out_lo32; except FreeMem(OutBuf); raise end; end; procedure BZDecompressBuf(const InBuf: Pointer; InBytes: Integer; OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); var strm: TBZStreamRec; P: Pointer; BufInc: Integer; begin LoadBzip2DLL; FillChar(strm, sizeof(strm), 0); strm.bzalloc := bzip2AllocMem; strm.bzfree := bzip2FreeMem; BufInc := (InBytes + 255) and not 255; if OutEstimate = 0 then OutBytes := BufInc else OutBytes := OutEstimate; GetMem(OutBuf, OutBytes); try strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := OutBytes; DCheck(BZ2_bzDecompressInit(strm, 0, 0)); try while DCheck(BZ2_bzDecompress(strm)) <> BZ_STREAM_END do begin P := OutBuf; Inc(OutBytes, BufInc); ReallocMem(OutBuf, OutBytes); strm.next_out := OutBuf + (strm.next_out - P); strm.avail_out := BufInc; end; finally DCheck(BZ2_bzDecompressEnd(strm)); end; ReallocMem(OutBuf, strm.total_out_lo32); OutBytes := strm.total_out_lo32; except FreeMem(OutBuf); raise end; end; // TCustomBZip2Stream constructor TCustomBZip2Stream.Create(Strm: TStream); begin inherited Create; FStrm := Strm; FStrmPos := Strm.Position; FBZRec.bzalloc := bzip2AllocMem; FBZRec.bzfree := bzip2FreeMem; end; procedure TCustomBZip2Stream.Progress(Sender: TObject); begin if Assigned(FOnProgress) then FOnProgress(Sender); end; { TCustomBZip2Stream } // TBZCompressionStream constructor TBZCompressionStream.Create(Level: IntPtr; Dest: TStream); begin inherited Create(Dest); LoadBzip2DLL; FBZRec.next_out := @FBuffer[0]; FBZRec.avail_out := sizeof(FBuffer); CCheck(BZ2_bzCompressInit(FBZRec, Level, 0, 0)); end; destructor TBZCompressionStream.Destroy; begin if FBZRec.state <> nil then begin FBZRec.next_in := nil; FBZRec.avail_in := 0; try if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (CCheck(BZ2_bzCompress(FBZRec, BZ_FINISH)) <> BZ_STREAM_END) and (FBZRec.avail_out = 0) do begin FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); FBZRec.next_out := @FBuffer[0]; FBZRec.avail_out := sizeof(FBuffer); end; if FBZRec.avail_out < sizeof(FBuffer) then FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FBZRec.avail_out); finally BZ2_bzCompressEnd(FBZRec); end; end; inherited Destroy; end; function TBZCompressionStream.Read(var Buffer; Count: Longint): Longint; begin raise EBZCompressionError.Create('Invalid stream operation'); end; { TBZCompressionStream } function TBZCompressionStream.Write(const Buffer; Count: Longint): Longint; begin FBZRec.next_in := @Buffer; FBZRec.avail_in := Count; if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (FBZRec.avail_in > 0) do begin CCheck(BZ2_bzCompress(FBZRec, BZ_RUN)); if FBZRec.avail_out = 0 then begin FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); FBZRec.next_out := @FBuffer[0]; FBZRec.avail_out := sizeof(FBuffer); FStrmPos := FStrm.Position; end; Progress(Self); end; Result := Count; end; { TBZCompressionStream } function TBZCompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; var conv64 : TLargeInteger; begin if (Offset = 0) and (Origin = soCurrent) then begin conv64.LowPart := FBZRec.total_in_lo32; conv64.HighPart := FBZRec.total_in_hi32; Result := conv64.QuadPart end else raise EBZCompressionError.Create('Invalid stream operation'); end; { TBZCompressionStream } function TBZCompressionStream.GetCompressionRate: Single; var conv64In : TLargeInteger; conv64Out: TLargeInteger; begin conv64In.LowPart := FBZRec.total_in_lo32; conv64In.HighPart := FBZRec.total_in_hi32; conv64Out.LowPart := FBZRec.total_out_lo32; conv64Out.HighPart := FBZRec.total_out_hi32; if conv64In.QuadPart = 0 then Result := 0 else Result := (1.0 - (conv64Out.QuadPart / conv64In.QuadPart)) * 100.0; end; { TBZCompressionStream } // TDecompressionStream constructor TBZDecompressionStream.Create(Source: TStream); begin inherited Create(Source); LoadBzip2DLL; FBZRec.next_in := @FBuffer[0]; FBZRec.avail_in := 0; DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); end; destructor TBZDecompressionStream.Destroy; begin if FBZRec.state <> nil then BZ2_bzDecompressEnd(FBZRec); inherited Destroy; end; function TBZDecompressionStream.Read(var Buffer; Count: Longint): Longint; begin FBZRec.next_out := @Buffer; FBZRec.avail_out := Count; if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (FBZRec.avail_out > 0) do begin if FReadState = BZ_STREAM_END then begin Result := Count - FBZRec.avail_out; Exit; end else if FBZRec.avail_in = 0 then begin FBZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); if FBZRec.avail_in = 0 then begin Result := Count - FBZRec.avail_out; Exit; end; FBZRec.next_in := @FBuffer[0]; FStrmPos := FStrm.Position; end; FReadState := DCheck(BZ2_bzDecompress(FBZRec)); Progress(Self); end; Result := Count; end; { TBZDecompressionStream } function TBZDecompressionStream.Write(const Buffer; Count: Longint): Longint; begin raise EBZDecompressionError.Create('Invalid stream operation'); end; { TBZDecompressionStream } function TBZDecompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; var I : Integer; Buf : array[0..4095] of Char; conv64: TLargeInteger; NewOff: Int64; begin conv64.LowPart := FBZRec.total_out_lo32; conv64.HighPart := FBZRec.total_out_hi32; if (Offset = 0) and (Origin = soBeginning) then begin DCheck(BZ2_bzDecompressEnd(FBZRec)); DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); FBZRec.next_in := @FBuffer[0]; FBZRec.avail_in := 0; FStrm.Position := 0; FStrmPos := 0; end else if ((Offset >= 0) and (Origin = soCurrent)) or (((Offset - conv64.QuadPart) > 0) and (Origin = soBeginning)) then begin NewOff := Offset; if Origin = soBeginning then Dec(NewOff, conv64.QuadPart); if NewOff > 0 then begin for I := 1 to NewOff div sizeof(Buf) do ReadBuffer(Buf, sizeof(Buf)); ReadBuffer(Buf, NewOff mod sizeof(Buf)); end; end else raise EBZDecompressionError.Create('Invalid stream operation'); Result := conv64.QuadPart; end; { TBZDecompressionStream } end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abbzip2typ.pas���������������������������������������0000644�0001750�0000144�00000036455�14743153644�023240� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Joel Haynie * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBzip2Typ.pas *} {*********************************************************} {* ABBREVIA: TAbBzip2Archive, TAbBzip2Item classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with Bzip2 files *} {*********************************************************} unit AbBzip2Typ; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbTarTyp, AbUtils; const { Default Stream Header for Bzip2s is 'BZhX', where X is the block size setting 1-9 in ASCII } { Each block has the following header: '1AY&SY', and are in units of 100kilobytes NOT 100kibiBytes } AB_BZIP2_FILE_HEADER = 'BZh'; AB_BZIP2_BLOCK_SIZE = ['1','2','3','4','5','6','7','8','9']; AB_BZIP2_BLOCK_HEADER = '1AY&SY'; { Note: $314159265359, BCD for Pi :) } { Note that Blocks are bit aligned, as such the only time you will "for sure" see the block header is on the start of stream/File } AB_BZIP2_FILE_TAIL =#23#114#36#83#133#9#0; { $1772245385090, BCD for sqrt(Pi) :) } { This is odd as the blocks are bit allgned so this is a string that is 13*4 bits = 52 bits } type PAbBzip2Header = ^TAbBzip2Header; { File Header } TAbBzip2Header = packed record { SizeOf(TAbBzip2Header) = 10 } FileHeader : array[0..2] of AnsiChar;{ 'BZh'; $42,5A,68 } BlockSize : AnsiChar; { '1'..'9'; $31-$39 } BlockHeader : array[0..5] of AnsiChar;{ '1AY&SY'; $31,41,59,26,53,59 } end; { The Purpose for this Item is the placeholder for aaAdd and aaDelete Support. } { For all intents and purposes we could just use a TAbArchiveItem } type TAbBzip2Item = class(TabArchiveItem); TAbBzip2ArchiveState = (gsBzip2, gsTar); TAbBzip2Archive = class(TAbTarArchive) private FBzip2Stream : TStream; { stream for Bzip2 file} FBzip2Item : TAbArchiveList; { item in bzip2 (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbBzip2ArchiveState; FIsBzippedTar : Boolean; procedure DecompressToStream(aStream: TStream); procedure SetTarAutoHandle(const Value: Boolean); procedure SwapToBzip2; procedure SwapToTar; protected { Inherited Abstract functions } function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function GetSupportsEmptyFolders : Boolean; override; public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; { Properties } property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsBzippedTar : Boolean read FIsBzippedTar write FIsBzippedTar; end; function VerifyBzip2(Strm : TStream) : TAbArchiveType; implementation uses {$IFDEF MSWINDOWS} Windows, // Fix inline warnings {$ENDIF} StrUtils, SysUtils, BufStream, AbBzip2, AbExcept, AbVMStrm, AbBitBkt, AbProgress, DCOSUtils, DCClassesUtf8; { ****************** Helper functions Not from Classes Above ***************** } function VerifyHeader(const Header : TAbBzip2Header) : Boolean; begin Result := (Header.FileHeader = AB_BZIP2_FILE_HEADER) and (Header.BlockSize in AB_BZIP2_BLOCK_SIZE) and (Header.BlockHeader = AB_BZIP2_BLOCK_HEADER); end; { -------------------------------------------------------------------------- } function VerifyBzip2(Strm : TStream) : TAbArchiveType; var Hdr : TAbBzip2Header; CurPos, DecompSize : Int64; DecompStream, TarStream: TStream; Buffer: array[0..Pred(AB_TAR_RECORDSIZE * 4)] of Byte; begin Result := atUnknown; CurPos := Strm.Position; Strm.Seek(0, soBeginning); try if (Strm.Read(Hdr, SizeOf(Hdr)) = SizeOf(Hdr)) and VerifyHeader(Hdr) then begin Result := atBzip2; { Check for embedded TAR } Strm.Seek(0, soBeginning); DecompStream := TBZDecompressionStream.Create(Strm); try TarStream := TMemoryStream.Create; try DecompSize:= DecompStream.Read(Buffer, SizeOf(Buffer)); TarStream.Write(Buffer, DecompSize); TarStream.Seek(0, soBeginning); if VerifyTar(TarStream) = atTar then Result := atBzippedTar; finally TarStream.Free; end; finally DecompStream.Free; end; end; except on EReadError do Result := atUnknown; end; Strm.Position := CurPos; { Return to original position. } end; { ****************************** TAbBzip2Archive ***************************** } constructor TAbBzip2Archive.CreateFromStream(aStream: TStream; const aArchiveName: string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsBzip2; FBzip2Stream := FStream; FBzip2Item := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SwapToBzip2; begin FStream := FBzip2Stream; FItemList := FBzip2Item; FState := gsBzip2; end; { -------------------------------------------------------------------------- } function TAbBzip2Archive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var Bz2Item : TAbBzip2Item; FullSourceFileName, FullArchiveFileName: String; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(SourceFileName, ArchiveDirectory); end else begin SwapToBzip2; Bz2Item := TAbBzip2Item.Create; try MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); Bz2Item.FileName := FullArchiveFileName; Bz2Item.DiskFileName := FullSourceFileName; Result := Bz2Item; except Result := nil; raise; end; end; end; { -------------------------------------------------------------------------- } destructor TAbBzip2Archive.Destroy; begin SwapToBzip2; FTarList.Free; FTarStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.ExtractItemAt(Index: Integer; const NewName: string); var OutStream : TStream; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, NewName); end else begin SwapToBzip2; OutStream := TFileStreamEx.Create(NewName, fmCreate or fmShareDenyNone); try try ExtractItemToStreamAt(Index, OutStream); finally OutStream.Free; end; { Bz2 doesn't store the last modified time or attributes, so don't set them } except on E : EAbUserAbort do begin FStatus := asInvalid; if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end else begin if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end; end; end; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToBzip2; { Index ignored as there's only one item in a Bz2 } DecompressToStream(aStream); end; end; { -------------------------------------------------------------------------- } function TAbBzip2Archive.GetSupportsEmptyFolders : Boolean; begin Result := IsBzippedTar and TarAutoHandle; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.LoadArchive; var Item: TAbBzip2Item; Abort: Boolean; ItemName: string; begin if FBzip2Stream.Size = 0 then Exit; if IsBzippedTar and TarAutoHandle then begin { Decompress and send to tar LoadArchive } DecompressToStream(FTarStream); SwapToTar; inherited LoadArchive; end else begin SwapToBzip2; Item := TAbBzip2Item.Create; Item.Action := aaNone; { Filename isn't stored, so constuct one based on the archive name } ItemName := ExtractFileName(ArchiveName); if ItemName = '' then Item.FileName := 'unknown' else if AnsiEndsText('.tbz', ItemName) or AnsiEndsText('.tbz2', ItemName) then Item.FileName := ChangeFileExt(ItemName, '.tar') else Item.FileName := ChangeFileExt(ItemName, ''); Item.DiskFileName := Item.FileName; FItemList.Add(Item); end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SaveArchive; var CompStream: TStream; i: Integer; CurItem: TAbBzip2Item; UpdateArchive: Boolean; TempFileName: String; InputFileStream: TStream; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; UpdateArchive := (FBzip2Stream.Size > 0) and (FBzip2Stream is TFileStreamEx); if UpdateArchive then begin FreeAndNil(FBzip2Stream); TempFileName := GetTempName(FArchiveName); { Create new archive with temporary name } FBzip2Stream := TFileStreamEx.Create(TempFileName, fmCreate or fmShareDenyWrite); end; FTarStream.Position := 0; CompStream := TBZCompressionStream.Create(CompressionLevel, FBzip2Stream); try FTargetStream := TWriteBufStream.Create(CompStream, $40000); try inherited SaveArchive; finally FreeAndNil(FTargetStream); end; finally CompStream.Free; end; if UpdateArchive then begin FreeAndNil(FBzip2Stream); { Replace original by new archive } if not (mbDeleteFile(FArchiveName) and mbRenameFile(TempFileName, FArchiveName)) then RaiseLastOSError; { Open new archive } FBzip2Stream := TFileStreamEx.Create(FArchiveName, fmOpenRead or fmShareDenyNone); end; end else begin { Things we know: There is only one file per archive.} { Actions we have to address in SaveArchive: } { aaNone & aaMove do nothing, as the file does not change, only the meta data } { aaDelete could make a zero size file unless there are two files in the list.} { aaAdd, aaStreamAdd, aaFreshen, & aaReplace will be the only ones to take action. } SwapToBzip2; for i := 0 to pred(Count) do begin FCurrentItem := ItemList[i]; CurItem := TAbBzip2Item(ItemList[i]); case CurItem.Action of aaNone, aaMove: Break;{ Do nothing; bz2 doesn't store metadata } aaDelete: ; {doing nothing omits file from new stream} aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin FBzip2Stream.Size := 0; CompStream := TBZCompressionStream.Create(CompressionLevel, FBzip2Stream); try if CurItem.Action = aaStreamAdd then CompStream.CopyFrom(InStream, 0){ Copy/compress entire Instream to FBzip2Stream } else begin InputFileStream := TFileStreamEx.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite); try with TAbProgressWriteStream.Create(CompStream, InputFileStream.Size, OnProgress) do try CopyFrom(InputFileStream, 0);{ Copy/compress entire Instream to FBzip2Stream } finally Free; end; finally InputFileStream.Free; end; end; finally CompStream.Free; end; Break; end; { End aaAdd, aaFreshen, aaReplace, & aaStreamAdd } end; { End of CurItem.Action Case } end; { End Item for loop } end; { End Tar Else } end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToBzip2; FTarAutoHandle := Value; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.DecompressToStream(aStream: TStream); const BufSize = $F000; var DecompStream: TBZDecompressionStream; ProxyStream: TAbProgressReadStream; Buffer: PByte; N: Integer; begin ProxyStream:= TAbProgressReadStream.Create(FBzip2Stream, OnProgress); try DecompStream := TBZDecompressionStream.Create(ProxyStream); try GetMem(Buffer, BufSize); try N := DecompStream.Read(Buffer^, BufSize); while N > 0 do begin aStream.WriteBuffer(Buffer^, N); N := DecompStream.Read(Buffer^, BufSize); end; finally FreeMem(Buffer, BufSize); end; finally DecompStream.Free; end; finally ProxyStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.TestItemAt(Index: Integer); var Bzip2Type: TAbArchiveType; BitBucket: TAbBitBucketStream; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited TestItemAt(Index); end else begin { note Index ignored as there's only one item in a GZip } Bzip2Type := VerifyBzip2(FBzip2Stream); if not (Bzip2Type in [atBzip2, atBzippedTar]) then raise EAbGzipInvalid.Create;// TODO: Add bzip2-specific exceptions } BitBucket := TAbBitBucketStream.Create(1024); try DecompressToStream(BitBucket); finally BitBucket.Free; end; end; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abconst.pas������������������������������������������0000644�0001750�0000144�00000017473�14743153644�022602� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbConst.pas *} {*********************************************************} {* Abbrevia: Constants *} {*********************************************************} unit AbConst; {$I AbDefine.inc} interface const AbVersion = 5.0; AbVersionS = '5.0'; Ab_MessageLen = 255; Ab_CaptionLen = 80; AB_ZIPPATHDELIM = '/'; const AbZipVersionNeeded = 1; AbUnknownCompressionMethod = 2; AbNoExtractionMethod = 3; AbInvalidPassword = 4; AbNoInsertionMethod = 5; AbInvalidFactor = 6; AbDuplicateName = 7; AbUnsupportedCompressionMethod = 8; AbUserAbort = 9; AbArchiveBusy = 10; AbBadSpanStream = 11; AbNoOverwriteSpanStream = 12; AbNoSpannedSelfExtract = 13; AbStreamFull = 14; AbNoSuchDirectory = 15; AbInflateBlockError = 16; AbBadStreamType = 17; AbTruncateError = 18; AbZipBadCRC = 19; AbZipBadStub = 20; AbFileNotFound = 21; AbInvalidLFH = 22; AbNoArchive = 23; AbErrZipInvalid = 24; AbReadError = 25; AbInvalidIndex = 26; AbInvalidThreshold = 27; AbUnhandledFileType = 28; AbSpanningNotSupported = 29; AbBBSReadTooManyBytes = 40; AbBBSSeekOutsideBuffer = 41; AbBBSInvalidOrigin = 42; AbBBSWriteTooManyBytes = 43; AbNoCabinetDllError = 50; AbFCIFileOpenError = 51; AbFCIFileReadError = 52; AbFCIFileWriteError = 53; AbFCIFileCloseError = 54; AbFCIFileSeekError = 55; AbFCIFileDeleteError = 56; AbFCIAddFileError = 57; AbFCICreateError = 58; AbFCIFlushCabinetError = 59; AbFCIFlushFolderError = 60; AbFDICopyError = 61; AbFDICreateError = 62; AbInvalidCabTemplate = 63; AbInvalidCabFile = 64; AbSWSNotEndofStream = 80; AbSWSSeekFailed = 81; AbSWSWriteFailed = 82; AbSWSInvalidOrigin = 83; AbSWSInvalidNewOrigin = 84; AbVMSReadTooManyBytes = 100; AbVMSInvalidOrigin = 101; AbVMSErrorOpenSwap = 102; AbVMSSeekFail = 103; AbVMSReadFail = 104; AbVMSWriteFail = 105; AbVMSWriteTooManyBytes = 106; AbGZipInvalid = 200; AbGzipBadCRC = 201; AbGzipBadFileSize = 202; AbTarInvalid = 220; AbTarBadFileName = 221; AbTarBadLinkName = 222; AbTarBadOp = 223; function AbStrRes(Index : Integer) : string; implementation uses AbResString; type AbStrRec = record ID: Integer; Str: string; end; const AbStrArray : array [0..66] of AbStrRec = ( (ID: AbZipVersionNeeded; Str: AbZipVersionNeededS), (ID: AbUnknownCompressionMethod; Str: AbUnknownCompressionMethodS), (ID: AbNoExtractionMethod; Str: AbNoExtractionMethodS), (ID: AbInvalidPassword; Str: AbInvalidPasswordS), (ID: AbNoInsertionMethod; Str: AbNoInsertionMethodS), (ID: AbInvalidFactor; Str: AbInvalidFactorS), (ID: AbDuplicateName; Str: AbDuplicateNameS), (ID: AbUnsupportedCompressionMethod; Str: AbUnsupportedCompressionMethodS), (ID: AbUserAbort; Str: AbUserAbortS), (ID: AbArchiveBusy; Str: AbArchiveBusyS), (ID: AbBadSpanStream; Str: AbBadSpanStreamS), (ID: AbNoOverwriteSpanStream; Str: AbNoOverwriteSpanStreamS), (ID: AbNoSpannedSelfExtract; Str: AbNoSpannedSelfExtractS), (ID: AbStreamFull; Str: AbStreamFullS), (ID: AbNoSuchDirectory; Str: AbNoSuchDirectoryS), (ID: AbInflateBlockError; Str: AbInflateBlockErrorS), (ID: AbBadStreamType; Str: AbBadStreamTypeS), (ID: AbTruncateError; Str: AbTruncateErrorS), (ID: AbZipBadCRC; Str: AbZipBadCRCS), (ID: AbZipBadStub; Str: AbZipBadStubS), (ID: AbFileNotFound; Str: AbFileNotFoundS), (ID: AbInvalidLFH; Str: AbInvalidLFHS), (ID: AbNoArchive; Str: AbNoArchiveS), (ID: AbErrZipInvalid; Str: AbErrZipInvalidS), (ID: AbReadError; Str: AbReadErrorS), (ID: AbInvalidIndex; Str: AbInvalidIndexS), (ID: AbInvalidThreshold; Str: AbInvalidThresholdS), (ID: AbUnhandledFileType; Str: AbUnhandledFileTypeS), (ID: AbSpanningNotSupported; Str: AbSpanningNotSupportedS), (ID: AbBBSReadTooManyBytes; Str: AbBBSReadTooManyBytesS), (ID: AbBBSSeekOutsideBuffer; Str: AbBBSSeekOutsideBufferS), (ID: AbBBSInvalidOrigin; Str: AbBBSInvalidOriginS), (ID: AbBBSWriteTooManyBytes; Str: AbBBSWriteTooManyBytesS), (ID: AbNoCabinetDllError; Str: AbNoCabinetDllErrorS), (ID: AbFCIFileOpenError; Str: AbFCIFileOpenErrorS), (ID: AbFCIFileReadError; Str: AbFCIFileReadErrorS), (ID: AbFCIFileWriteError; Str: AbFCIFileWriteErrorS), (ID: AbFCIFileCloseError; Str: AbFCIFileCloseErrorS), (ID: AbFCIFileSeekError; Str: AbFCIFileSeekErrorS), (ID: AbFCIFileDeleteError; Str: AbFCIFileDeleteErrorS), (ID: AbFCIAddFileError; Str: AbFCIAddFileErrorS), (ID: AbFCICreateError; Str: AbFCICreateErrorS), (ID: AbFCIFlushCabinetError; Str: AbFCIFlushCabinetErrorS), (ID: AbFCIFlushFolderError; Str: AbFCIFlushFolderErrorS), (ID: AbFDICopyError; Str: AbFDICopyErrorS), (ID: AbFDICreateError; Str: AbFDICreateErrorS), (ID: AbInvalidCabTemplate; Str: AbInvalidCabTemplateS), (ID: AbInvalidCabFile; Str: AbInvalidCabFileS), (ID: AbSWSNotEndofStream; Str: AbSWSNotEndofStreamS), (ID: AbSWSSeekFailed; Str: AbSWSSeekFailedS), (ID: AbSWSWriteFailed; Str: AbSWSWriteFailedS), (ID: AbSWSInvalidOrigin; Str: AbSWSInvalidOriginS), (ID: AbSWSInvalidNewOrigin; Str: AbSWSInvalidNewOriginS), (ID: AbVMSReadTooManyBytes; Str: AbVMSReadTooManyBytesS), (ID: AbVMSInvalidOrigin; Str: AbVMSInvalidOriginS), (ID: AbVMSErrorOpenSwap; Str: AbVMSErrorOpenSwapS), (ID: AbVMSSeekFail; Str: AbVMSSeekFailS), (ID: AbVMSReadFail; Str: AbVMSReadFailS), (ID: AbVMSWriteFail; Str: AbVMSWriteFailS), (ID: AbVMSWriteTooManyBytes; Str: AbVMSWriteTooManyBytesS), (ID: AbGzipInvalid; Str: AbGzipInvalidS), (ID: AbGzipBadCRC; Str: AbGzipBadCRCS), (ID: AbGzipBadFileSize; Str: AbGzipBadFileSizeS), (ID: AbTarInvalid; Str: AbTarInvalidS), (ID: AbTarBadFileName; Str: AbTarBadFileNameS), (ID: AbTarBadLinkName; Str: AbTarBadLinkNameS), (ID: AbTarBadOp; Str: AbTarBadOpS) ); function AbStrRes(Index : Integer) : string; var i : Integer; begin for i := Low(AbStrArray) to High(AbStrArray) do if AbStrArray[i].ID = Index then Result := AbStrArray[i].Str; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdefine.inc�����������������������������������������0000644�0001750�0000144�00000021230�14743153644�022656� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDefine.inc *} {*********************************************************} {* ABBREVIA: Compiler options/directives include file *} {*********************************************************} {NOTE: ABDEFINE.INC is included in all ABBREVIA units; hence you can specify global compiler options here. ABDEFINE.INC is included *before* each unit's own required compiler options, so options specified here could be overridden by hardcoded options in the unit source file.} {====Compiler options that can be changed====} {$A+ Force alignment on word/dword boundaries} {$S- No stack checking} {---Global compiler defines for 32-bit OS's---} {====Global fixed compiler options (do NOT change)====} {$B- Incomplete boolean evaluation} {$H+ Long string support} {$P- No open string parameters} {$Q- Arithmetic overflow checking} {!! - Needs to be turned on!} {$R- Range checking} {!! - Needs to be turned on!} {$T+ No type-checked pointers} {$V- No var string checking} {$X+ Extended syntax} {$Z1 Enumerations are byte sized} {====Platform defines================================================} { map Delphi platform defines to FreePascal's (MSWINDOWS/UNIX/LINUX/DARWIN) } {$IFNDEF FPC} {$IF DEFINED(LINUX) AND (CompilerVersion < 15)} {$DEFINE KYLIX} {$DEFINE UNIX} {$IFEND} {$IFDEF MACOS} {$DEFINE DARWIN} {$ENDIF} {$IFDEF POSIX} {$DEFINE UNIX} {$ENDIF} {$ENDIF} { Unix API (Kylix/Delphi/FreePascal) } {$IFDEF UNIX} {$IF DEFINED(FPC)} {$DEFINE FPCUnixAPI} {$ELSEIF DEFINED(KYLIX)} {$DEFINE LibcAPI} {$ELSE} {$DEFINE PosixAPI} {$IFEND} {$ENDIF} {$IFDEF FPC} {$MODE DELPHI} {$PACKRECORDS C} {$ENDIF} {Activate this define to show CLX/LCL dialogs for spanning media requests. The default behavior will abort the operation instead. This define is only safe when using Abbrevia from the foreground thread. If using it from a background thread override OnRequestLastDisk, OnRequestNthDisk, and OnRequestBlankDisk and synchronize to the foreground yourself. The Windows version always MessageBox so it's thread-safe.} {.$DEFINE UnixDialogs} {====RTL defines=====================================================} {$IFNDEF FPC} {$IF RTLVersion >= 18} // Delphi 2006 {$DEFINE HasAdvancedRecords} {$IFEND} {$IF RTLVersion >= 20} // Delphi 2009 {$DEFINE HasThreadFinished} {$IFEND} {$IF RTLVersion >= 21} // Delphi 2010 {$DEFINE HasThreadStart} {$IFEND} {$IF RTLVersion >= 23} // Delphi XE2 {$DEFINE HasPlatformsAttribute} {$IFEND} {$ENDIF} {====Widgetset defines===============================================} { VCL version specific defines } {$IFNDEF FPC} {$IF RTLVersion >= 17} // Delphi 2005 {$DEFINE HasOnMouseActivate} {$IFEND} {$IF RTLVersion >= 18} // Delphi 2006 {$DEFINE HasOnMouseEnter} {$IFEND} {$IF RTLVersion >= 20} // Delphi 2009 {$DEFINE HasListViewGroups} {$DEFINE HasListViewOnItemChecked} {$DEFINE HasParentDoubleBuffered} {$DEFINE HasTreeViewExpandedImageIndex} {$IFEND} {$IF RTLVersion >= 21} // Delphi 2010 {$DEFINE HasGridDrawingStyle} {$DEFINE HasTouch} {$IFEND} {$ENDIF} {====General defines=================================================} {Activate the following define to include extra code to get rid of all hints and warnings. Parts of ABBREVIA are written in such a way that the hint/warning algorithms of the Delphi compilers are fooled and report things like variables being used before initialisation and so on when in reality the problem does not exist.} {$DEFINE DefeatWarnings} { Disable warnings for explicit string casts } {$IFDEF UNICODE} {$WARN EXPLICIT_STRING_CAST OFF} {$WARN EXPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} { Disable hints on Delphi XE2/Mac to prevent unexpanded inline messages } {$IFDEF POSIX} {$HINTS OFF} {$ENDIF} {====Bzip2 defines===================================================} {Activate this define to statically link bzip2 .obj files into the application. Curerntly only supported by Delphi/Win32.} {.$DEFINE Bzip2Static} {Activate this define to dynamically link to a libbz2.dll/libbbz2.so.1} {.$DEFINE Bzip2Dynamic} {Activate this define to load libbz2.dll/libbz2.so.1 at runtime using LoadLibrary} {.$DEFINE Bzip2Runtime} {Pick an appropriate linking method if none of the above are activate} {$IF NOT DEFINED(Bzip2Static) AND NOT DEFINED(Bzip2Dynamic) AND NOT DEFINED(Bzip2Runtime)} {$IFDEF FPC} {$DEFINE Bzip2Runtime} {$ELSE} {$IFDEF MSWINDOWS} {$DEFINE Bzip2Static} {$ELSE} {$DEFINE Bzip2Dynamic} {$ENDIF} {$ENDIF} {$IFEND} {====Zip defines=====================================================} {Activate the following define when you don't want Visual parts of the VCL library included for a program using a TAbArchive or TAbZipArchive} {.$DEFINE BuildingStub} {Activate the following define to include support for extracting files using PKzip compatible unShrink.} {.$DEFINE UnzipShrinkSupport} {Activate the following define to include support for extracting files using PKZip compatible unReduce.} {.$DEFINE UnzipReduceSupport} {Activate the following define to include support for extracting files using PKZip compatible unImplode.} {.$DEFINE UnzipImplodeSupport} {Activate the following to include support for extracting files using all older PKZip compatible methods (Shrink, Reduce, Implode} {$DEFINE UnzipBackwardSupport} {Activate the following to include support for extracting files using BZIP2 compression. Added in AppNote.txt v4.6. } {.$DEFINE UnzipBzip2Support} {Activate the following to include support for extracting files using 7-zip compatible Lzma compression. Added in AppNote.txt v6.3.} {.$DEFINE UnzipLzmaSupport} {Activate the following to include support for extracting files using zipx PPMd I compression. Added in AppNote.txt v6.3.} {.$DEFINE UnzipPPMdSupport} {Activate the following to include support for extracting .wav files using zipx WavPack compression. Requires copyright notice in your documentation. Check "WavPack License.txt" for details. Added in AppNote.txt v6.3. } {.$DEFINE UnzipWavPackSupport} {Activate the following to include support for extracting files using all newer (zipx) compatible methods (Bzip2, Lzma, PPMd, WavPack)} {$DEFINE UnzipZipxSupport} {Activate the following to include logging support in the deflate/ inflate code. Since this logging support is a by-product of assertion checking, you should only activate it if that is also on: $C+} {$IFOPT C+} //if Assertions are on {.$DEFINE UseLogging} {$ENDIF} { According to http://www.gzip.org/zlib/rfc1952.txt A compliant gzip compressor should calculate and set the CRC32 and ISIZE. However, a compliant decompressor should not check these values. If you want to check the the values of the CRC32 and ISIZE in a GZIP file when decompressing enable the STRICTGZIP define below. } {.$DEFINE STRICTGZIP} { The following define is ONLY used for Abbrevia Unit Tests. It has no effect on the Abbrevia Library. If defined it uses Winzip to create and test archives for compatability. The winzip tests require Systools stSpawn.pas It can be downloaded at http://sf.net/projects/tpsystools } {$IFDEF MSWINDOWS} {.$DEFINE WINZIPTESTS} {$ENDIF} {-------- !! DO NOT CHANGE DEFINES BELOW THIS LINE !! --------} {$IFDEF UnzipBackwardSupport} {$DEFINE UnzipShrinkSupport} {$DEFINE UnzipReduceSupport} {$DEFINE UnzipImplodeSupport} {$ENDIF} {$IFDEF UnzipZipxSupport} {$DEFINE UnzipXzSupport} {$DEFINE UnzipBzip2Support} {$DEFINE UnzipLzmaSupport} {$DEFINE UnzipPPMdSupport} {$DEFINE UnzipZstdSupport} {$DEFINE UnzipWavPackSupport} {$ENDIF} { Linking .obj files isn't currently supported in Kylix or FPC } {$IF DEFINED(FPC) OR NOT DEFINED(MSWINDOWS)} {$UNDEF UnzipPPMdSupport} {$UNDEF UnzipWavPackSupport} {$IFEND} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfbase.pas�����������������������������������������0000644�0001750�0000144�00000056315�14743153644�022676� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfBase.pas *} {*********************************************************} {* Deflate base unit *} {*********************************************************} unit AbDfBase; {$I AbDefine.inc} interface uses SysUtils, Classes; type PAbDfLongintList = ^TAbDfLongintList; TAbDfLongintList = array [0..pred(MaxInt div sizeof(longint))] of longint; const dfc_CodeLenCodeLength = 7; dfc_LitDistCodeLength = 15; dfc_MaxCodeLength = 15; const dfc_MaxMatchLen = 258; {lengths are 3..258 for deflate} dfc_MaxMatchLen64 = 64 * 1024; {lengths are 3..65536 for deflate64} const dfc_LitExtraOffset = 257; dfc_LitExtraBits : array [0..30] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, 99, 99); { note: the last two are required to avoid going beyond the end} { of the array when generating static trees} dfc_DistExtraOffset = 0; dfc_DistExtraBits : array [0..31] of byte = (0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14); { note: the last two are only use for deflate64} dfc_LengthBase : array [0..28] of word = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3); { note: the final 3 is correct for deflate64; for symbol 285,} { lengths are stored as (length - 3)} { for deflate it's very wrong, but there's special code in} { the (de)compression code to cater for this} dfc_DistanceBase : array [0..31] of word = (1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153); dfc_CodeLengthIndex : array [0..18] of byte = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15); const dfc_CanUseStored = $01; dfc_CanUseStatic = $02; dfc_CanUseDynamic = $04; dfc_UseLazyMatch = $08; dfc_UseDeflate64 = $10; dfc_UseAdler32 = $20; dfc_CanUseHuffman = dfc_CanUseStatic or dfc_CanUseDynamic; dfc_TestOnly = $40000000; type TAbProgressStep = procedure (aPercentDone : integer) of object; {-progress metering of deflate/inflate; abort with AbortProgress} TAbDeflateHelper = class private FAmpleLength : longint; FChainLength : longint; FLogFile : string; FMaxLazy : longint; FOnProgressStep : TAbProgressStep; FOptions : longint; FPartSize : Int64; FSizeCompressed : Int64; FSizeNormal : Int64; FStreamSize : Int64; FWindowSize : longint; FZipOption : AnsiChar; protected procedure dhSetAmpleLength(aValue : longint); procedure dhSetChainLength(aValue : longint); procedure dhSetLogFile(const aValue : string); procedure dhSetMaxLazy(aValue : longint); procedure dhSetOnProgressStep(aValue : TAbProgressStep); procedure dhSetOptions(aValue : longint); procedure dhSetWindowSize(aValue : longint); procedure dhSetZipOption(aValue : AnsiChar); public constructor Create; procedure Assign(aHelper : TAbDeflateHelper); property AmpleLength : longint read FAmpleLength write dhSetAmpleLength; property ChainLength : longint read FChainLength write dhSetChainLength; property LogFile : string read FLogFile write dhSetLogFile; property MaxLazyLength : longint read FMaxLazy write dhSetMaxLazy; property Options : longint read FOptions write dhSetOptions; property PartialSize : Int64 read FPartSize write FPartSize; property PKZipOption : AnsiChar read FZipOption write dhSetZipOption; property StreamSize : Int64 read FStreamSize write FStreamSize; property WindowSize : longint read FWindowSize write dhSetWindowSize; property CompressedSize : Int64 read FSizeCompressed write FSizeCompressed; property NormalSize : Int64 read FSizeNormal write FSizeNormal; property OnProgressStep : TAbProgressStep read FOnProgressStep write dhSetOnProgressStep; end; type TAbLineDelimiter = (ldCRLF, ldLF); TAbLogger = class(TStream) private FBuffer : PAnsiChar; FCurPos : PAnsiChar; FLineDelim : TAbLineDelimiter; FStream : TFileStream; protected function logWriteBuffer : boolean; public constructor Create(const aLogName : string); destructor Destroy; override; function Read(var Buffer; Count : longint) : longint; override; function Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; override; function Write(const Buffer; Count : longint) : longint; override; procedure WriteLine(const S : string); procedure WriteStr(const S : string); property LineDelimiter : TAbLineDelimiter read FLineDelim write FLineDelim; end; type TAbNodeManager = class private FFreeList : pointer; FNodeSize : cardinal; FNodesPerPage : cardinal; FPageHead : pointer; FPageSize : cardinal; protected function nmAllocNewPage : pointer; public constructor Create(aNodeSize : cardinal); destructor Destroy; override; function AllocNode : pointer; function AllocNodeClear : pointer; procedure FreeNode(aNode : pointer); end; {---exception classes---} type EAbAbortProgress = class(Exception); EAbPartSizedInflate = class(Exception); EAbInflatePasswordError = class(Exception); EAbInternalInflateError = class(Exception); EAbInflateError = class(Exception) public constructor Create(const aMsg : string); constructor CreateUnknown(const aMsg : string; const aErrorMsg : string); end; EAbInternalDeflateError = class(Exception); EAbDeflateError = class(Exception) public constructor Create(const aMsg : string); constructor CreateUnknown(const aMsg : string; const aErrorMsg : string); end; {---aborting a process---} procedure AbortProgress; {---calculation of checksums---} procedure AbUpdateAdlerBuffer(var aAdler : longint; var aBuffer; aCount : integer); procedure AbUpdateCRCBuffer(var aCRC : longint; var aBuffer; aCount : integer); implementation uses AbUtils; {===TAbDeflateHelper=================================================} constructor TAbDeflateHelper.Create; begin inherited Create; FAmpleLength := 8; FChainLength := 32; {FLogFile := '';} FMaxLazy := 16; {FOnProgressStep := nil;} FOptions := $F; {FStreamSize := 0;} FWindowSize := 32 * 1024; FZipOption := 'n'; end; {--------} procedure TAbDeflateHelper.Assign(aHelper : TAbDeflateHelper); begin FAmpleLength := aHelper.FAmpleLength; FChainLength := aHelper.FChainLength; FLogFile := aHelper.FLogFile; FMaxLazy := aHelper.FMaxLazy; FOnProgressStep := aHelper.FOnProgressStep; FOptions := aHelper.FOptions; FPartSize := aHelper.FPartSize; FStreamSize := aHelper.FStreamSize; FWindowSize := aHelper.FWindowSize; FZipOption := aHelper.FZipOption; end; {--------} procedure TAbDeflateHelper.dhSetAmpleLength(aValue : longint); begin if (aValue <> AmpleLength) then begin if (aValue <> -1) and (aValue < 4) then aValue := 4; FAmpleLength := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetChainLength(aValue : longint); begin if (aValue <> ChainLength) then begin if (aValue <> -1) and (aValue < 4) then aValue := 4; FChainLength := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetLogFile(const aValue : string); begin FLogFile := aValue; end; {--------} procedure TAbDeflateHelper.dhSetMaxLazy(aValue : longint); begin if (aValue <> MaxLazyLength) then begin if (aValue <> -1) and (aValue < 4) then aValue := 4; FMaxLazy := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetOnProgressStep(aValue : TAbProgressStep); begin FOnProgressStep := aValue; end; {--------} procedure TAbDeflateHelper.dhSetOptions(aValue : longint); begin if (aValue <> Options) then begin FOptions := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetWindowSize(aValue : longint); var NewValue : longint; begin if (aValue <> WindowSize) then begin {calculate the window size rounded to nearest 1024 bytes} NewValue := ((aValue + 1023) div 1024) * 1024; {if the new window size is greater than 32KB...} if (NewValue > 32 * 1024) then {if the Deflate64 option is set, force to 64KB} if ((Options and dfc_UseDeflate64) <> 0) then NewValue := 64 * 1024 {otherwise, force to 32KB} else NewValue := 32 * 1024; {set the new window size} FWindowSize := NewValue; end; end; {--------} procedure TAbDeflateHelper.dhSetZipOption(aValue : AnsiChar); begin {notes: The original Abbrevia code used the following table for setting the equivalent values: Good Lazy Chain UseLazy Option 4 4 4 N s ^ 4 5 8 N | 4 6 32 N f faster 4 4 16 Y slower 8 16 32 Y n | 8 16 128 Y | 8 32 256 Y | 32 128 1024 Y | 32 258 4096 Y x V The new Abbrevia 3 code follows these values to a certain extent. } {force to lower case} if ('A' <= aValue) and (aValue <= 'Z') then aValue := AnsiChar(ord(aValue) + ord('a') - ord('A')); {if the value has changed...} if (aValue <> PKZipOption) then begin {switch on the new value...} case aValue of '0' : {no compression} begin FZipOption := aValue; FOptions := (FOptions and (not $0F)) or dfc_CanUseStored; FAmpleLength := 8; { not actually needed} FChainLength := 32; { not actually needed} FMaxLazy := 16; { not actually needed} end; '2' : {hidden option: Abbrevia 2 compatibility} begin FZipOption := aValue; FOptions := FOptions or $0F; FAmpleLength := 8; FChainLength := 32; FMaxLazy := 16; end; 'f' : {fast compression} begin FZipOption := aValue; FOptions := FOptions or $07; { no lazy matching} FAmpleLength := 4; FChainLength := 32; FMaxLazy := 6; end; 'n' : {normal compression} begin FZipOption := aValue; FOptions := FOptions or $0F; FAmpleLength := 16; FChainLength := 32; FMaxLazy := 24; end; 's' : {super fast compression} begin FZipOption := aValue; FOptions := FOptions or $07; { no lazy matching} FAmpleLength := 4; FChainLength := 4; FMaxLazy := 4; end; 'x' : {maximum compression} begin FZipOption := aValue; FOptions := FOptions or $0F; FAmpleLength := 64;{32;} FChainLength := 4096; FMaxLazy := 258; end; end; end; end; {====================================================================} {===TAbLogger========================================================} const LogBufferSize = 4096; {--------} constructor TAbLogger.Create(const aLogName : string); begin Assert(aLogName <> '', 'TAbLogger.Create: a filename must be provided for the logger'); {create the ancestor} inherited Create; {set the default line terminator} {$IFDEF MSWINDOWS} FLineDelim := ldCRLF; {$ENDIF} {$IFDEF UNIX} FLineDelim := ldLF; {$ENDIF} {create and initialize the buffer} GetMem(FBuffer, LogBufferSize); FCurPos := FBuffer; {create the log file} FStream := TFileStream.Create(aLogName, fmCreate); end; {--------} destructor TAbLogger.Destroy; begin {if there is a buffer ensure that it is flushed before freeing it} if (FBuffer <> nil) then begin if (FCurPos <> FBuffer) then logWriteBuffer; FreeMem(FBuffer, LogBufferSize); end; {free the stream} FStream.Free; {destroy the ancestor} inherited Destroy; end; {--------} function TAbLogger.logWriteBuffer : boolean; var BytesToWrite : longint; BytesWritten : longint; begin BytesToWrite := FCurPos - FBuffer; BytesWritten := FStream.Write(FBuffer^, BytesToWrite); if (BytesWritten = BytesToWrite) then begin Result := true; FCurPos := FBuffer; end else begin Result := false; if (BytesWritten <> 0) then begin Move(FBuffer[BytesWritten], FBuffer^, BytesToWrite - BytesWritten); FCurPos := FBuffer + (BytesToWrite - BytesWritten); end; end; end; {--------} function TAbLogger.Read(var Buffer; Count : longint) : longint; begin Assert(false, 'TAbLogger.Read: loggers are write-only, no reading allowed'); Result := 0; end; {--------} function TAbLogger.Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; begin case Origin of soBeginning : begin end; soCurrent : if (Offset = 0) then begin Result := FStream.Position + (FCurPos - FBuffer); Exit; end; soEnd : if (Offset = 0) then begin Result := FStream.Position + (FCurPos - FBuffer); Exit; end; end; Assert(false, 'TAbLogger.Seek: loggers are write-only, no seeking allowed'); Result := 0; end; {--------} function TAbLogger.Write(const Buffer; Count : longint) : longint; var UserBuf : PAnsiChar; BytesToGo : longint; BytesToWrite : longint; begin {reference the user's buffer as a PChar} UserBuf := @Buffer; {start the counter for the number of bytes written} Result := 0; {if needed, empty the internal buffer into the underlying stream} if (LogBufferSize = FCurPos - FBuffer) then if not logWriteBuffer then Exit; {calculate the number of bytes to copy this time from the user's buffer to the internal buffer} BytesToGo := Count; BytesToWrite := LogBufferSize - (FCurPos - FBuffer); if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy the bytes} Move(UserBuf^, FCurPos^, BytesToWrite); {adjust the counters} inc(FCurPos, BytesToWrite); dec(BytesToGo, BytesToWrite); inc(Result, BytesToWrite); {while there are still more bytes to copy, do so} while (BytesToGo <> 0) do begin {advance the user's buffer} inc(UserBuf, BytesToWrite); {empty the internal buffer into the underlying stream} if not logWriteBuffer then Exit; {calculate the number of bytes to copy this time from the user's buffer to the internal buffer} BytesToWrite := LogBufferSize; if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy the bytes} Move(UserBuf^, FCurPos^, BytesToWrite); {adjust the counters} inc(FCurPos, BytesToWrite); dec(BytesToGo, BytesToWrite); inc(Result, BytesToWrite); end; end; {--------} procedure TAbLogger.WriteLine(const S : string); const cLF : AnsiChar = ^J; cCRLF : array [0..1] of AnsiChar = ^M^J; begin if (length(S) > 0) then Write(S[1], length(S)); case FLineDelim of ldLF : Write(cLF, sizeof(cLF)); ldCRLF : Write(cCRLF, sizeof(cCRLF)); end; end; {--------} procedure TAbLogger.WriteStr(const S : string); begin if (length(S) > 0) then Write(S[1], length(S)); end; {====================================================================} {===Calculate checksums==============================================} procedure AbUpdateAdlerBuffer(var aAdler : longint; var aBuffer; aCount : integer); var S1 : LongWord; S2 : LongWord; i : integer; Buffer : PAnsiChar; BytesToUse : integer; begin {Note: this algorithm will *only* work if the buffer is 4KB or less, which is why we go to such lengths to chop up the user buffer into usable chunks of 4KB. However, for Delphi 3 there is no proper 32-bit longword. Although the additions pose no problems in this situation, the mod operations below (especially for S2) will be signed integer divisions, producing an (invalid) signed result. In this case, the buffer is chopped up into 2KB chunks to avoid any signed problems.} {split the current Adler checksum into its halves} S1 := LongWord(aAdler) and $FFFF; S2 := LongWord(aAdler) shr 16; {reference the user buffer as a PChar: it makes it easier} Buffer := @aBuffer; {while there's still data to checksum...} while (aCount <> 0) do begin {calculate the number of bytes to checksum this time} {$IFDEF HasLongWord} BytesToUse := 4096; {$ELSE} BytesToUse := 2048; {$ENDIF} if (BytesToUse > aCount) then BytesToUse := aCount; {checksum the bytes} for i := 0 to pred(BytesToUse) do begin inc(S1, ord(Buffer^)); inc(S2, S1); inc(Buffer); end; {recalibrate the Adler checksum halves} S1 := S1 mod 65521; S2 := S2 mod 65521; {calculate the number of bytes still to go} dec(aCount, BytesToUse); end; {join the halves to produce the complete Adler checksum} aAdler := longint((S2 shl 16) or S1); end; {--------} procedure AbUpdateCRCBuffer(var aCRC : longint; var aBuffer; aCount : integer); var i : integer; CRC : LongWord; Buffer : PAnsiChar; begin {$R-}{$Q-} {reference the user buffer as a PChar: it makes it easier} Buffer := @aBuffer; {get the current CRC as a local variable, it's faster} CRC := aCRC; {checksum the bytes in the buffer} for i := 0 to pred(aCount) do begin CRC := AbCrc32Table[byte(CRC) xor byte(Buffer^)] xor (CRC shr 8); inc(Buffer); end; {return the new CRC} aCRC := CRC; {$R+}{$Q+} end; {====================================================================} {===EAbInflateError==================================================} constructor EAbInflateError.Create(const aMsg : string); begin inherited Create( 'Abbrevia inflate error, possibly a corrupted compressed stream. ' + '(Internal cause: ' + aMsg + ')'); end; {--------} constructor EAbInflateError.CreateUnknown(const aMsg : string; const aErrorMsg : string); begin inherited Create(aMsg + ': ' + aErrorMsg); end; {====================================================================} {===EAbDeflateError==================================================} constructor EAbDeflateError.Create(const aMsg : string); begin inherited Create( 'Abbrevia deflate error. ' + '(Internal cause: ' + aMsg + ')'); end; {--------} constructor EAbDeflateError.CreateUnknown(const aMsg : string; const aErrorMsg : string); begin inherited Create(aMsg + ': ' + aErrorMsg); end; {====================================================================} {===Node manager=====================================================} const PageSize = 8 * 1024; type PGenericNode = ^TGenericNode; TGenericNode = packed record gnNext : PGenericNode; gnData : record end; end; {--------} constructor TAbNodeManager.Create(aNodeSize : cardinal); const Gran = sizeof(pointer); Mask = not (Gran - 1); begin {create the ancestor} inherited Create; {save the node size rounded to nearest 4 bytes} if (aNodeSize <= sizeof(pointer)) then aNodeSize := sizeof(pointer) else aNodeSize := (aNodeSize + Gran - 1) and Mask; FNodeSize := aNodeSize; {calculate the page size (default 1024 bytes) and the number of nodes per page; if the default page size is not large enough for two or more nodes, force a single node per page} FNodesPerPage := (PageSize - sizeof(pointer)) div aNodeSize; if (FNodesPerPage > 1) then FPageSize := PageSize else begin FNodesPerPage := 1; FPagesize := aNodeSize + sizeof(pointer); end; end; {--------} destructor TAbNodeManager.Destroy; var Temp : pointer; begin {dispose of all the pages, if there are any} while (FPageHead <> nil) do begin Temp := PGenericNode(FPageHead)^.gnNext; FreeMem(FPageHead, FPageSize); FPageHead := Temp; end; {destroy the ancestor} inherited Destroy; end; {--------} function TAbNodeManager.AllocNode : pointer; begin Result := FFreeList; if (Result = nil) then Result := nmAllocNewPage else FFreeList := PGenericNode(Result)^.gnNext; end; {--------} function TAbNodeManager.AllocNodeClear : pointer; begin Result := FFreeList; if (Result = nil) then Result := nmAllocNewPage else FFreeList := PGenericNode(Result)^.gnNext; FillChar(Result^, FNodeSize, 0); end; {--------} procedure TAbNodeManager.FreeNode(aNode : pointer); begin {add the node (if non-nil) to the top of the free list} if (aNode <> nil) then begin PGenericNode(aNode)^.gnNext := FFreeList; FFreeList := aNode; end; end; {--------} function TAbNodeManager.nmAllocNewPage : pointer; var NewPage : PAnsiChar; i : integer; FreeList : pointer; NodeSize : integer; begin {allocate a new page and add it to the front of the page list} GetMem(NewPage, FPageSize); PGenericNode(NewPage)^.gnNext := FPageHead; FPageHead := NewPage; {now split up the new page into nodes and push them all onto the free list; note that the first 4 bytes of the page is a pointer to the next page, so remember to skip over it} inc(NewPage, sizeof(pointer)); FreeList := FFreeList; NodeSize := FNodeSize; for i := 0 to pred(FNodesPerPage) do begin PGenericNode(NewPage)^.gnNext := FreeList; FreeList := NewPage; inc(NewPage, NodeSize); end; {return the top of the list} Result := FreeList; FFreeList := PGenericNode(Result)^.gnNext; end; {====================================================================} {====================================================================} procedure AbortProgress; begin raise EAbAbortProgress.Create('Abort'); end; {====================================================================} end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfcrys.pas�����������������������������������������0000644�0001750�0000144�00000045367�14743153644�022751� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfCryS.pas *} {*********************************************************} {* Deflate encryption streams *} {*********************************************************} unit AbDfCryS; {$I AbDefine.inc} interface uses Classes; type TAbZipEncryptHeader = array [0..11] of byte; TAbZipDecryptEngine = class private FReady : boolean; FState : array [0..2] of longint; protected procedure zdeInitState(const aPassphrase : AnsiString); public constructor Create; function Decode(aCh : byte) : byte; {-decodes a byte} procedure DecodeBuffer(var aBuffer; aCount : integer); {-decodes a buffer} function VerifyHeader(const aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint) : boolean; {-validate an encryption header} end; TAbDfDecryptStream = class(TStream) private FCheckValue : longint; FEngine : TAbZipDecryptEngine; FOwnsStream : Boolean; FPassphrase : AnsiString; FReady : boolean; FStream : TStream; protected public constructor Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); destructor Destroy; override; function IsValid : boolean; function Read(var aBuffer; aCount : longint) : longint; override; function Seek(aOffset : longint; aOrigin : word) : longint; override; function Write(const aBuffer; aCount : longint) : longint; override; property OwnsStream : Boolean read FOwnsStream write FOwnsStream; end; TAbZipEncryptEngine = class private FReady : boolean; FState : array [0..2] of longint; protected procedure zeeInitState(const aPassphrase : AnsiString); public constructor Create; function Encode(aCh : byte) : byte; {-encodes a byte} procedure EncodeBuffer(var aBuffer; aCount : integer); {-encodes a buffer} procedure CreateHeader(var aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint); {-generate an encryption header} end; TAbDfEncryptStream = class(TStream) private FBuffer : PAnsiChar; FBufSize : integer; FEngine : TAbZipEncryptEngine; FStream : TStream; protected public constructor Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); destructor Destroy; override; function Read(var aBuffer; aCount : longint) : longint; override; function Seek(aOffset : longint; aOrigin : word) : longint; override; function Write(const aBuffer; aCount : longint) : longint; override; end; implementation {Notes: the ZIP spec defines a couple of primitive routines for performing encryption. For speed Abbrevia inlines them into the respective methods of the encryption/decryption engines char crc32(long,char) return updated CRC from current CRC and next char update_keys(char): Key(0) <- crc32(key(0),char) Key(1) <- Key(1) + (Key(0) & 000000ffH) Key(1) <- Key(1) * 134775813 + 1 Key(2) <- crc32(key(2),key(1) >> 24) end update_keys char decrypt_byte() local unsigned short temp temp <- Key(2) | 2 decrypt_byte <- (temp * (temp ^ 1)) >> 8 end decrypt_byte } uses AbUtils; {---magic numbers from ZIP spec---} const StateInit1 = 305419896; StateInit2 = 591751049; StateInit3 = 878082192; MagicNumber = 134775813; {===internal encryption class========================================} constructor TAbZipDecryptEngine.Create; begin {create the ancestor} inherited Create; {we're not ready for decryption yet since a header hasn't been properly verified with VerifyHeader} FReady := false; end; {--------} function TAbZipDecryptEngine.Decode(aCh : byte) : byte; var Temp : longint; begin {check for programming error} Assert(FReady, 'TAbZipDecryptEngine.Decode: must successfully call VerifyHeader first'); {calculate the decoded byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Result := aCh xor ((Temp * (Temp xor 1)) shr 8); {mix the decoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(Result, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; {--------} procedure TAbZipDecryptEngine.DecodeBuffer(var aBuffer; aCount : integer); var i : integer; Temp : longint; Buffer : PAnsiChar; WorkState : array [0..2] of longint; begin {check for programming error} Assert(FReady, 'TAbZipDecryptEngine.Decode: must successfully call VerifyHeader first'); {move the state to a local variable--for better speed} WorkState[0] := FState[0]; WorkState[1] := FState[1]; WorkState[2] := FState[2]; {reference the buffer as a PChar--easier arithmetic} Buffer := @aBuffer; {for each byte in the buffer...} for i := 0 to pred(aCount) do begin {calculate the next decoded byte (uses inlined decrypt_byte)} Temp := (WorkState[2] and $FFFF) or 2; Buffer^ := AnsiChar( byte(Buffer^) xor ((Temp * (Temp xor 1)) shr 8)); {mix the decoded byte into the state (uses inlined update_keys)} WorkState[0] := AbUpdateCrc32(byte(Buffer^), WorkState[0]); WorkState[1] := WorkState[1] + (WorkState[0] and $FF); WorkState[1] := (WorkState[1] * MagicNumber) + 1; WorkState[2] := AbUpdateCrc32(WorkState[1] shr 24, WorkState[2]); {move onto the next byte} inc(Buffer); end; {save the state} FState[0] := WorkState[0]; FState[1] := WorkState[1]; FState[2] := WorkState[2]; end; {--------} function TAbZipDecryptEngine.VerifyHeader(const aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint) : boolean; type TLongAsBytes = packed record L1, L2, L3, L4 : byte end; var i : integer; Temp : longint; WorkHeader : TAbZipEncryptHeader; begin {check for programming errors} Assert(aPassphrase <> '', 'TAbZipDecryptEngine.VerifyHeader: need a passphrase'); {initialize the decryption state} zdeInitState(aPassphrase); {decrypt the bytes in the header} for i := 0 to 11 do begin {calculate the next decoded byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; WorkHeader[i] := aHeader[i] xor ((Temp * (Temp xor 1)) shr 8); {mix the decoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(WorkHeader[i], FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; {the header is valid if the twelfth byte of the decrypted header equals the fourth byte of the check value} Result := WorkHeader[11] = TLongAsBytes(aCheckValue).L4; {note: zips created with PKZIP prior to version 2.0 also checked that the tenth byte of the decrypted header equals the third byte of the check value} FReady := Result; end; {--------} procedure TAbZipDecryptEngine.zdeInitState(const aPassphrase : AnsiString); var i : integer; begin {initialize the decryption state} FState[0] := StateInit1; FState[1] := StateInit2; FState[2] := StateInit3; {mix in the passphrase to the state (uses inlined update_keys)} for i := 1 to length(aPassphrase) do begin FState[0] := AbUpdateCrc32(byte(aPassphrase[i]), FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; end; {====================================================================} {====================================================================} constructor TAbDfDecryptStream.Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); begin {create the ancestor} inherited Create; {save the parameters} FStream := aStream; FCheckValue := aCheckValue; FPassphrase := aPassphrase; {create the decryption engine} FEngine := TAbZipDecryptEngine.Create; end; {--------} destructor TAbDfDecryptStream.Destroy; {new !!.02} begin FEngine.Free; if FOwnsStream then FStream.Free; inherited Destroy; end; {--------} function TAbDfDecryptStream.IsValid : boolean; var Header : TAbZipEncryptHeader; begin {read the header from the stream} FStream.ReadBuffer(Header, sizeof(Header)); {check to see if the decryption engine agrees it's valid} Result := FEngine.VerifyHeader(Header, FPassphrase, FCheckValue); {if it isn't valid, reposition the stream, ready for the next try} if not Result then begin FStream.Seek(-sizeof(Header), soCurrent); FReady := false; end {otherwise, the stream is ready for decrypting data} else FReady := true; end; {--------} function TAbDfDecryptStream.Read(var aBuffer; aCount : longint) : longint; begin {check for programming error} Assert(FReady, 'TAbDfDecryptStream.Read: the stream header has not been verified'); {read the data from the underlying stream} Result := FStream.Read(aBuffer, aCount); {decrypt the data} FEngine.DecodeBuffer(aBuffer, Result); end; {--------} function TAbDfDecryptStream.Seek(aOffset : longint; aOrigin : word) : longint; begin Result := FStream.Seek(aOffset, aOrigin); end; {--------} function TAbDfDecryptStream.Write(const aBuffer; aCount : longint) : longint; begin {check for programming error} Assert(false, 'TAbDfDecryptStream.Write: the stream is read-only'); Result := 0; end; {====================================================================} {===TAbZipEncryptEngine==============================================} constructor TAbZipEncryptEngine.Create; begin {create the ancestor} inherited Create; {we're not ready for encryption yet since a header hasn't been properly generated with CreateHeader} FReady := false; end; {--------} procedure TAbZipEncryptEngine.CreateHeader( var aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint); type TLongAsBytes = packed record L1, L2, L3, L4 : byte end; var Ch : byte; i : integer; Temp : longint; WorkHeader : TAbZipEncryptHeader; begin {check for programming errors} Assert(aPassphrase <> '', 'TAbZipEncryptEngine.CreateHeader: need a passphrase'); {set the first ten bytes of the header with random values (in fact, we use a random value for each byte and mix it in with the state)} {initialize the decryption state} zeeInitState(aPassphrase); {for the first ten bytes...} for i := 0 to 9 do begin {get a random value} Ch := Random( 256 ); {calculate the XOR encoding byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; {mix the unencoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(Ch, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); {set the current byte of the header} WorkHeader[i] := Ch xor Temp; end; {now encrypt the first ten bytes of the header (this merely sets up the state so that we can encrypt the last two bytes)} {reinitialize the decryption state} zeeInitState(aPassphrase); {for the first ten bytes...} for i := 0 to 9 do begin {calculate the XOR encoding byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; {mix the unencoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(WorkHeader[i], FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); {set the current byte of the header} WorkHeader[i] := WorkHeader[i] xor Temp; end; {now initialize byte 10 of the header, and encrypt it} Ch := TLongAsBytes(aCheckValue).L3; Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; FState[0] := AbUpdateCrc32(Ch, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); WorkHeader[10] := Ch xor Temp; {now initialize byte 11 of the header, and encrypt it} Ch := TLongAsBytes(aCheckValue).L4; Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; FState[0] := AbUpdateCrc32(Ch, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); WorkHeader[11] := Ch xor Temp; {we're now ready to encrypt} FReady := true; {return the header} aHeader := WorkHeader; end; {--------} function TAbZipEncryptEngine.Encode(aCh : byte) : byte; var Temp : longint; begin {check for programming error} Assert(FReady, 'TAbZipEncryptEngine.Encode: must call CreateHeader first'); {calculate the encoded byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Result := aCh xor (Temp * (Temp xor 1)) shr 8; {mix the unencoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(aCh, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; {--------} procedure TAbZipEncryptEngine.EncodeBuffer(var aBuffer; aCount : integer); var Ch : byte; i : integer; Temp : longint; Buffer : PAnsiChar; WorkState : array [0..2] of longint; begin {check for programming error} Assert(FReady, 'TAbZipEncryptEngine.EncodeBuffer: must call CreateHeader first'); {move the state to a local variable--for better speed} WorkState[0] := FState[0]; WorkState[1] := FState[1]; WorkState[2] := FState[2]; {reference the buffer as a PChar--easier arithmetic} Buffer := @aBuffer; {for each byte in the buffer...} for i := 0 to pred(aCount) do begin {calculate the next encoded byte (uses inlined decrypt_byte)} Temp := (WorkState[2] and $FFFF) or 2; Ch := byte(Buffer^); Buffer^ := AnsiChar(Ch xor ((Temp * (Temp xor 1)) shr 8)); {mix the decoded byte into the state (uses inlined update_keys)} WorkState[0] := AbUpdateCrc32(Ch, WorkState[0]); WorkState[1] := WorkState[1] + (WorkState[0] and $FF); WorkState[1] := (WorkState[1] * MagicNumber) + 1; WorkState[2] := AbUpdateCrc32(WorkState[1] shr 24, WorkState[2]); {move onto the next byte} inc(Buffer); end; {save the state} FState[0] := WorkState[0]; FState[1] := WorkState[1]; FState[2] := WorkState[2]; end; {--------} procedure TAbZipEncryptEngine.zeeInitState(const aPassphrase : AnsiString); var i : integer; begin {initialize the decryption state} FState[0] := StateInit1; FState[1] := StateInit2; FState[2] := StateInit3; {mix in the passphrase to the state (uses inlined update_keys)} for i := 1 to length(aPassphrase) do begin FState[0] := AbUpdateCrc32(byte(aPassphrase[i]), FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; end; {====================================================================} {===TAbDfEncryptStream===============================================} constructor TAbDfEncryptStream.Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); var Header : TAbZipEncryptHeader; begin {create the ancestor} inherited Create; {save the stream parameter} FStream := aStream; {create the encryption engine} FEngine := TAbZipEncryptEngine.Create; {generate the encryption header, write it to the stream} FEngine.CreateHeader(Header, aPassphrase, aCheckValue); aStream.WriteBuffer(Header, sizeof(Header)); end; {--------} destructor TAbDfEncryptStream.Destroy; begin {free the internal buffer if used} if (FBuffer <> nil) then FreeMem(FBuffer); {free the engine} FEngine.Free; {destroy the ancestor} inherited Destroy; end; {--------} function TAbDfEncryptStream.Read(var aBuffer; aCount : longint) : longint; begin {check for programming error} Assert(false, 'TAbDfEncryptStream.Read: the stream is write-only'); Result := 0; end; {--------} function TAbDfEncryptStream.Seek(aOffset : longint; aOrigin : word) : longint; begin Result := FStream.Seek(aOffset, aOrigin); end; {--------} function TAbDfEncryptStream.Write(const aBuffer; aCount : longint) : longint; begin {note: since we cannot alter a const parameter, we should copy the data to our own buffer, encrypt it and then write it} {check that our buffer is large enough} if (FBufSize < aCount) then begin if (FBuffer <> nil) then FreeMem(FBuffer); GetMem(FBuffer, aCount); FBufSize := aCount; end; {copy the data to our buffer} Move(aBuffer, FBuffer^, aCount); {encrypt the data in our buffer} FEngine.EncodeBuffer(FBuffer^, aCount); {write the data in our buffer to the underlying stream} Result := FStream.Write(FBuffer^, aCount); end; {====================================================================} end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfdec.pas������������������������������������������0000644�0001750�0000144�00000064352�14743153644�022517� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfDec.pas *} {*********************************************************} {* Deflate decoding unit *} {*********************************************************} unit AbDfDec; {$I AbDefine.inc} interface uses Classes, AbDfBase; function Inflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; implementation uses SysUtils, AbDfStrm, AbDfHufD, AbDfOutW, AbDfCryS; {===Helper routines==================================================} procedure ReadLitDistCodeLengths(aInStrm : TAbDfInBitStream; aCodeLenTree : TAbDfDecodeHuffmanTree; var aCodeLens : array of integer; aCount : integer; var aTotalBits : integer); var i : integer; SymbolCount : integer; LookupValue : integer; EncodedSymbol : longint; Symbol : integer; SymbolCodeLen : integer; RepeatCount : integer; BitBuffer : TAb32bit; BitCount : integer; begin {$IFDEF UseLogging} {we need to calculate the total number of bits in the code lengths for reporting purposes, so zero the count} aTotalBits := 0; {$ENDIF} {clear the code lengths array} FillChar(aCodeLens, sizeof(aCodeLens), 0); {read all the Symbols required in the bit stream} SymbolCount := 0; while (SymbolCount < aCount) do begin {grab the lookup set of bits} BitCount := aCodeLenTree.LookupBitLength + 7; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aCodeLenTree.LookupBitLength]; {get the encoded Symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aCodeLenTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aCodeLenTree.Decodes^[LookupValue]; {$ENDIF} {extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; {$IFDEF UseLogging} {keep count of the total number of bits read} inc(aTotalBits, SymbolCodeLen); {$ENDIF} {check that the symbol is between 0 and 18} if not ((0 <= Symbol) and (Symbol <= 18)) then raise EAbInternalInflateError.Create( 'decoded a symbol not between 0 and 18 {ReadLitDistCodeLengths}'); {check that the codelength is in range} if not ((0 < SymbolCodeLen) and (SymbolCodeLen <= aCodeLenTree.LookupBitLength)) then raise EAbInternalInflateError.Create( 'decoded a code length out of range {ReadLitDistCodeLengths}'); {for a Symbol of 0..15, just save the value} if (Symbol <= 15) then begin aCodeLens[SymbolCount] := Symbol; inc(SymbolCount); {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end {for a Symbol of 16, get two more bits and copy the previous code length that many times + 3} else if (Symbol = 16) then begin RepeatCount := 3 + ((BitBuffer shr SymbolCodeLen) and $3); Symbol := aCodeLens[SymbolCount-1]; for i := 0 to pred(RepeatCount) do aCodeLens[SymbolCount+i] := Symbol; inc(SymbolCount, RepeatCount); BitCount := SymbolCodeLen + 2; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} {$IFDEF UseLogging} inc(aTotalBits, 2); {$ENDIF} end {for a Symbol of 17, get three more bits and copy a zero code length that many times + 3} else if (Symbol = 17) then begin RepeatCount := 3 + ((BitBuffer shr SymbolCodeLen) and $7); {note: the codelengths array was aet to zeros at the start so the following two lines are not needed for i := 0 to pred(RepeatCount) do aCodeLens[SymbolCount+i] := 0;} inc(SymbolCount, RepeatCount); BitCount := SymbolCodeLen + 3; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} {$IFDEF UseLogging} inc(aTotalBits, 3); {$ENDIF} end {for a Symbol of 18, get seven more bits and copy a zero code length that many times + 11} else if (Symbol = 18) then begin RepeatCount := 11 + ((BitBuffer shr SymbolCodeLen) and $7F); {note: the codelengths array was aet to zeros at the start so the following two lines are not needed for i := 0 to pred(RepeatCount) do aCodeLens[SymbolCount+i] := 0;} inc(SymbolCount, RepeatCount); BitCount := SymbolCodeLen + 7; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} {$IFDEF UseLogging} inc(aTotalBits, 7); {$ENDIF} end; end; end; {--------} procedure DecodeData(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLiteralTree : TAbDfDecodeHuffmanTree; aDistanceTree : TAbDfDecodeHuffmanTree; aDeflate64 : boolean); var LookupValue : integer; EncodedSymbol : longint; Symbol : integer; SymbolCodeLen : integer; ExtraBitCount : integer; Length : integer; Distance : integer; BitBuffer : TAb32bit; BitCount : integer; begin {extract the first symbol (it's got to be a literal/length symbol)} {..grab the lookup set of bits} if aDeflate64 then BitCount := aLiteralTree.LookupBitLength + 16 else BitCount := aLiteralTree.LookupBitLength + 5; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aLiteralTree.LookupBitLength]; {..get the encoded symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aLiteralTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aLiteralTree.Decodes^[LookupValue]; {$ENDIF} {..extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; // ExtraBitCount := EncodedSymbol shr 24; {repeat until we get the end-of-block symbol} while ((Symbol <> 256) {and (ExtraBitCount <> 15)}) do begin {for a literal, just output it to the sliding window} if (Symbol < 256) then begin aOutWindow.AddLiteral(AnsiChar(Symbol)); {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end {for a length value, we need to get any extra bits, and then the distance (plus any extra bits for that), and then add the duplicated characters to the sliding window} else begin {check that the length symbol is less than or equal to 285} if (Symbol > 285) then raise EAbInternalInflateError.Create( 'decoded an invalid length symbol: greater than 285 [DecodeData]'); {calculate the length (if need be, by calculating the number of extra bits that encode the length)} if (not aDeflate64) and (Symbol = 285) then begin Length := 258; {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end else begin ExtraBitCount := EncodedSymbol shr 24; if (ExtraBitCount = 0) then begin Length := dfc_LengthBase[Symbol - 257]; {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end else begin Length := dfc_LengthBase[Symbol - 257] + ((BitBuffer shr SymbolCodeLen) and AbExtractMask[ExtraBitCount]); BitCount := SymbolCodeLen + ExtraBitCount; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} end; end; {extract the distance} {..grab the lookup set of bits} BitCount := aDistanceTree.LookupBitLength + 14; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aDistanceTree.LookupBitLength]; {..get the encoded symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aDistanceTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aDistanceTree.Decodes^[LookupValue]; {$ENDIF} {..extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; {check that the distance symbol is less than or equal to 29} if (not aDeflate64) and (Symbol > 29) then raise EAbInternalInflateError.Create( 'decoded an invalid distance symbol: greater than 29 [DecodeData]'); {..calculate the extra bits for the distance} ExtraBitCount := EncodedSymbol shr 24; {..calculate the distance} if (ExtraBitCount = 0) then begin Distance := dfc_DistanceBase[Symbol]; {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end else begin Distance := dfc_DistanceBase[Symbol] + ((BitBuffer shr SymbolCodeLen) and AbExtractMask[ExtraBitCount]); BitCount := SymbolCodeLen + ExtraBitCount; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} end; {duplicate the characters in the sliding window} aOutWindow.AddLenDist(Length, Distance); end; {extract the next symbol} {..grab the lookup set of bits} if aDeflate64 then BitCount := aLiteralTree.LookupBitLength + 16 else BitCount := aLiteralTree.LookupBitLength + 5; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aLiteralTree.LookupBitLength]; {..get the encoded symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aLiteralTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aLiteralTree.Decodes^[LookupValue]; {$ENDIF} {..extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; end; {discard the bits for the end-of-block marker} {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end; {--------} procedure InflateStoredBlock(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLog : TAbLogger); const BufferSize = 16 * 1024; var LenNotLen : packed record Len : word; NotLen : word; end; BytesToGo : integer; BytesToWrite : integer; Buffer : pointer; begin {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine('....a stored block'); {$ENDIF} {align the input bit stream to the nearest byte boundary} aInStrm.AlignToByte; {read the length of the stored data and the notted length} aInStrm.ReadBuffer(LenNotLen, sizeof(LenNotLen)); {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine(Format('..block length: %d (%-4x, NOT %-4x)', [LenNotLen.Len, LenNotLen.Len, LenNotLen.NotLen])); {$ENDIF} {check that NOT of the length equals the notted length} if ((not LenNotLen.Len) <> LenNotLen.NotLen) then raise EAbInternalInflateError.Create( 'invalid stored block (length and NOT length do not match) [InflateStoredBlock]'); {calculate the number of bytes to copy from the stored block} BytesToGo := LenNotLen.Len; {allocate a large buffer} GetMem(Buffer, BufferSize); {copy all the data in the stored block to the output window} try {while there are still some bytes to copy...} while (BytesToGo <> 0) do begin {calculate the number of bytes this time} if (BytesToGo > BufferSize) then BytesToWrite := BufferSize else BytesToWrite := BytesToGo; {read that many bytes and write them to the output window} aInStrm.ReadBuffer(Buffer^, BytesToWrite); aOutWindow.AddBuffer(Buffer^, BytesToWrite); {calculate the number of bytes still to copy} dec(BytesToGo, BytesToWrite); end; finally FreeMem(Buffer); end; end; {--------} procedure InflateStaticBlock(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLog : TAbLogger; aDeflate64 : boolean); begin {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine('....a static huffman tree block'); {$ENDIF} {decode the data with the static trees} DecodeData(aInStrm, aOutWindow, AbStaticLiteralTree, AbStaticDistanceTree, aDeflate64); end; {--------} procedure InflateDynamicBlock(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLog : TAbLogger; aDeflate64 : boolean); var i : integer; LitCount : integer; DistCount : integer; CodeLenCount : integer; CodeLens : array [0..285+32] of integer; CodeLenTree : TAbDfDecodeHuffmanTree; LiteralTree : TAbDfDecodeHuffmanTree; DistanceTree : TAbDfDecodeHuffmanTree; TotalBits : integer; begin {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine('....a dynamic huffman tree block'); {$ENDIF} {prepare for the try..finally} CodeLenTree := nil; LiteralTree := nil; DistanceTree := nil; try {decode the number of literal, distance and codelength codes} LitCount := aInStrm.ReadBits(5) + 257; DistCount := aInStrm.ReadBits(5) + 1; CodeLenCount := aInStrm.ReadBits(4) + 4; {$IFDEF UseLogging} {log it} if (aLog <> nil) then begin aLog.WriteLine(Format('Count of literals: %d', [LitCount])); aLog.WriteLine(Format('Count of distances: %d', [DistCount])); aLog.WriteLine(Format('Count of code lengths: %d', [CodeLenCount])); end; {$ENDIF} {verify that the counts are valid} if (LitCount > 286) then raise EAbInternalInflateError.Create( 'count of literal codes in dynamic block is greater than 286 [InflateDynamicBlock]'); if (not aDeflate64) and (DistCount > 30) then raise EAbInternalInflateError.Create( 'count of distance codes in dynamic block is greater than 30 [InflateDynamicBlock]'); {read the codelengths} FillChar(CodeLens, 19 * sizeof(integer), 0); for i := 0 to pred(CodeLenCount) do CodeLens[dfc_CodeLengthIndex[i]] := aInStrm.ReadBits(3); {$IFDEF UseLogging} {log them} if (aLog <> nil) then begin aLog.WriteLine('CodeLength Huffman tree: code lengths'); for i := 0 to 18 do aLog.WriteStr(Format('%-3d', [CodeLens[i]])); aLog.WriteLine(''); aLog.WriteLine(Format('..total bits: %d', [CodeLenCount * 3])); end; {$ENDIF} {create the codelength huffman tree} CodeLenTree := TAbDfDecodeHuffmanTree.Create(19, 7, huDecoding); CodeLenTree.Build(CodeLens, 0, 19, [0], $FFFF); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Code lengths tree'); CodeLenTree.DebugPrint(aLog); end; {$ENDIF} {read the codelengths for both the literal/length and distance huffman trees} ReadLitDistCodeLengths(aInStrm, CodeLenTree, CodeLens, LitCount + DistCount, TotalBits); {$IFDEF UseLoggingx} {log them} if (aLog <> nil) then begin aLog.WriteLine('Literal/length & Dist Huffman trees: code lengths'); for i := 0 to pred(LitCount + DistCount) do aLog.WriteLine(Format('%3d: %3d', [i, CodeLens[i]])); aLog.WriteLine(''); aLog.WriteLine(Format('..total bits: %d', [TotalBits])); end; {$ENDIF} {create the literal huffman tree} LiteralTree := TAbDfDecodeHuffmanTree.Create(286, 15, huDecoding); LiteralTree.Build(CodeLens, 0, LitCount, dfc_LitExtraBits, dfc_LitExtraOffset); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Literal/length tree'); LiteralTree.DebugPrint(aLog); end; {$ENDIF} {create the distance huffman tree} if aDeflate64 then DistanceTree := TAbDfDecodeHuffmanTree.Create(32, 15, huDecoding) else DistanceTree := TAbDfDecodeHuffmanTree.Create(30, 15, huDecoding); DistanceTree.Build(CodeLens, LitCount, DistCount, dfc_DistExtraBits, dfc_DistExtraOffset); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Distance tree'); DistanceTree.DebugPrint(aLog); end; {$ENDIF} {using the literal and distance trees, decode the bit stream} DecodeData(aInStrm, aOutWindow, LiteralTree, DistanceTree, aDeflate64); finally CodeLenTree.Free; LiteralTree.Free; DistanceTree.Free; end; end; {====================================================================} {===Interfaced routine===============================================} function Inflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; var Helper : TAbDeflateHelper; InBitStrm : TAbDfInBitStream; OutWindow : TAbDfOutputWindow; Log : TAbLogger; UseDeflate64 : boolean; UseCRC32 : boolean; IsFinalBlock : boolean; BlockType : integer; TestOnly : boolean; SourceStartPos : longint; DestStartPos : longint; {$IFDEF UseLogging} StartPosn : longint; {$ENDIF} begin {$IFDEF DefeatWarnings} Result := 0; SourceStartPos := 0; DestStartPos := 0; TestOnly := False; {$ENDIF} {$IFDEF UseLogging} StartPosn := 0; {$ENDIF} {pre-conditions: streams must be allocated of course} Assert(aSource <> nil, 'Deflate: aSource stream cannot be nil'); Assert(aDest <> nil, 'Deflate: aDest stream cannot be nil'); {prepare for the try..finally} Helper := nil; InBitStrm := nil; OutWindow := nil; Log := nil; try {finally} try {except} {create our helper; assign the passed one to it} Helper := TAbDeflateHelper.Create; if (aHelper <> nil) then Helper.Assign(aHelper); {get the initial start positions of both streams} SourceStartPos := aSource.Position; DestStartPos := aDest.Position; {if the helper's stream size is -1, and it has a progress event handler, calculate the stream size from the stream itself} if Assigned(Helper.OnProgressStep) then begin if (Helper.StreamSize = -1) then Helper.StreamSize := aSource.Size; end {otherwise we certainly can't do any progress reporting} else begin Helper.OnProgressStep := nil; Helper.StreamSize := 0; end; {create the logger, if requested} if (Helper.LogFile <> '') then begin Log := TAbLogger.Create(Helper.LogFile); Log.WriteLine('INFLATING STREAM...'); {$IFNDEF UseLogging} Log.WriteLine('Need to recompile the app with UseLogging turned on'); {$ENDIF} end; InBitStrm := TAbDfInBitStream.Create(aSource, Helper.OnProgressStep, Helper.StreamSize); {create the output sliding window} UseDeflate64 := (Helper.Options and dfc_UseDeflate64) <> 0; UseCRC32 := (Helper.Options and dfc_UseAdler32) = 0; TestOnly := (Helper.Options and dfc_TestOnly) <> 0; OutWindow := TAbDfOutputWindow.Create( aDest, UseDeflate64, UseCRC32, Helper.PartialSize, TestOnly, Log); {start decoding the deflated stream} repeat {read the final block flag and the block type} IsFinalBlock := InBitStrm.ReadBit; BlockType := InBitStrm.ReadBits(2); {$IFDEF UseLogging} {log it} if (Log <> nil) then begin Log.WriteLine(''); Log.WriteLine('Starting new block'); Log.WriteLine(Format('..final block? %d', [ord(IsFinalBlock)])); Log.WriteLine(Format('..block type? %d', [BlockType])); StartPosn := OutWindow.Position; end; {$ENDIF} case BlockType of 0 : InflateStoredBlock(InBitStrm, OutWindow, Log); 1 : InflateStaticBlock(InBitStrm, OutWindow, Log, UseDeflate64); 2 : InflateDynamicBlock(InBitStrm, OutWindow, Log, UseDeflate64); else raise EAbInternalInflateError.Create( 'starting new block, but invalid block type [Inflate]'); end; {$IFDEF UseLogging} {log it} if (Log <> nil) then Log.WriteLine(Format('---block end--- (decoded size %d bytes)', [OutWindow.Position - StartPosn])); {$ENDIF} until IsFinalBlock; {get the uncompressed stream's checksum} Result := OutWindow.Checksum; if TestOnly and (aHelper <> nil) then aHelper.NormalSize := OutWindow.Position; {$IFDEF UseLogging} {log it} if (Log <> nil) then Log.WriteLine(Format('End of compressed stream, checksum %-8x', [Result])); {$ENDIF} except on E : EAbPartSizedInflate do begin {nothing, just swallow the exception} Result := 0; end; on E : EAbAbortProgress do begin {nothing, just swallow the exception} Result := 0; end; on E : EAbInternalInflateError do begin if (Log <> nil) then Log.WriteLine(Format('Internal exception raised: %s', [E.Message])); raise EAbInflateError.Create(E.Message); end; end; finally Helper.Free; OutWindow.Free; InBitStrm.Free; Log.Free; end; {if there's a helper return the compressed and uncompressed sizes} if (aHelper <> nil) then begin if not TestOnly then aHelper.NormalSize := aDest.Position - DestStartPos; aHelper.CompressedSize := aSource.Position - SourceStartPos; end; {WARNING NOTE: the compiler will warn that the return value of this function might be undefined. However, it is wrong: it has been fooled by the code. If you don't want to see this warning again, enable the DefeatWarnings compiler define in AbDefine.inc.} end; {====================================================================} end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfhufd.pas�����������������������������������������0000644�0001750�0000144�00000044156�14743153644�022712� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfHufD.pas *} {*********************************************************} {* Deflate Huffman tree for decoder *} {*********************************************************} unit AbDfHufD; {$I AbDefine.inc} {Activate this compiler define and rebuild if you want the complete huffman tree output to print to the current log. The output is voluminous to say the least...} {$IFDEF UseLogging} {.$DEFINE EnableMegaLog} {$ENDIF} {Notes: The object of this class is to build a decoder array, not to build a Huffman tree particularly. We don't want to decode huffman strings bit by bit. moving down the Huffman tree sometimes left, sometimes right. Instead we want to grab a set of bits and look them up in an array. Sometimes we'll grab too many bits, sure, but we can deal with that later. So, the object of the exercise is to calculate the code for a symbol, reverse it ('cos that's how the input bit stream will present it to us) and set that element of the array to the decoded symbol value (plus some extra information: bit lengths). If the alphabet size were 19 (the codelengths huffman tree) and the maximum code length 5, for example, the decoder array would be 2^5 elements long, much larger than the alphabet size. The user of this class will be presenting sets of 5 bits for us to decode. We would like to look up these 5 bits in the array (as an index) and have the symbol returned. Now, since the alphabet size is much less than the number of elements in the decoder array, we must set the other elements in the array as well. Consider a symbol that has a code of 110 in this scenario. The reversed code is 011, or 3, so we'd be setting element 3. However we should also be setting elements 01011, 10011, and 11011 to this symbol information as well, since the lookup will be 5 bits long. Because the code is a huffman code from a prefix tree, we won't get any index clashes between actual codes by this "filling in" process. For the codelength Huffman tree, the maximum code length is at most 7. This equates to a 128 element array. For the literal and distance trees, the max code length is at most 15. This equates to a 32768 element array. For a given lookup value the decoder will return a 32-bit value. The lower 16 bits is the decoded symbol, the next 8 bits is the code length for that symbol, the last 8 bits (the most significant) are the number of extra bits that must be extracted from the input bit stream. } interface uses AbDfBase; type TAbDfHuffmanUsage = ( {usage of a huffman decoder..} huEncoding, {..encoding} huDecoding, {..decoding} huBoth); {..both (used for static trees)} TAbDfDecodeHuffmanTree = class private FAlphaSize : integer; FDecodes : PAbDfLongintList; FDefMaxCodeLen : integer; FEncodes : PAbDfLongintList; {$IFOPT C+} FMask : integer; {$ENDIF} FMaxCodeLen : integer; FUsage : TAbDfHuffmanUsage; protected public constructor Create(aAlphabetSize : integer; aDefMaxCodeLen: integer; aUsage : TAbDfHuffmanUsage); destructor Destroy; override; procedure Build(const aCodeLengths : array of integer; aStartInx : integer; aCount : integer; const aExtraBits : array of byte; aExtraOffset : integer); function Decode(aLookupBits : integer) : longint; function Encode(aSymbol : integer) : longint; {$IFDEF UseLogging} procedure DebugPrint(aLog : TAbLogger); {$ENDIF} property LookupBitLength : integer read FMaxCodeLen; property Decodes : PAbDfLongintList read FDecodes; property Encodes : PAbDfLongintList read FEncodes; end; var AbStaticLiteralTree : TAbDfDecodeHuffmanTree; AbStaticDistanceTree : TAbDfDecodeHuffmanTree; implementation uses SysUtils; const PowerOfTwo : array [0..dfc_MaxCodeLength] of integer = (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768); {===Debug helper routine=============================================} {$IFDEF EnableMegaLog} function CodeToStr(aCode : longint; aLen : integer) : string; var i : integer; begin if (aLen = 0) then Result := 'no code' else begin SetLength(Result, 32); FillChar(Result[1], 32, ' '); for i := 32 downto (33-aLen) do begin if Odd(aCode) then Result[i] := '1' else Result[i] := '0'; aCode := aCode shr 1; end; end; end; {$ENDIF} {====================================================================} {===TAbDfDecodeHuffmanTree===========================================} constructor TAbDfDecodeHuffmanTree.Create( aAlphabetSize : integer; aDefMaxCodeLen: integer; aUsage : TAbDfHuffmanUsage); begin {protect against dumb programming mistakes} Assert(aAlphabetSize >= 2, 'TAbDfDecodeHuffmanTree.Create: a huffman tree must be for at least two symbols'); {let the ancestor initialize} inherited Create; {save the alphabet size, etc} FAlphaSize := aAlphabetSize; FDefMaxCodeLen := aDefMaxCodeLen; FUsage := aUsage; {allocate the encoder array (needs to be initialized to zeros)} if (aUsage <> huDecoding) then FEncodes := AllocMem(FAlphaSize * sizeof(longint)); end; {--------} destructor TAbDfDecodeHuffmanTree.Destroy; begin {destroy the codes arrays} if (FDecodes <> nil) then FreeMem(FDecodes); if (FEncodes <> nil) then FreeMem(FEncodes); {let the ancestor die} inherited Destroy; end; {--------} procedure TAbDfDecodeHuffmanTree.Build( const aCodeLengths : array of integer; aStartInx : integer; aCount : integer; const aExtraBits : array of byte; aExtraOffset : integer); const ByteRevTable : array [0..255] of byte = ( $00, $80, $40, $C0, $20, $A0, $60, $E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88, $48, $C8, $28, $A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8, $04, $84, $44, $C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4, $74, $F4, $0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC, $3C, $BC, $7C, $FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92, $52, $D2, $32, $B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA, $1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6, $66, $E6, $16, $96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE, $2E, $AE, $6E, $EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81, $41, $C1, $21, $A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1, $09, $89, $49, $C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9, $79, $F9, $05, $85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5, $35, $B5, $75, $F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D, $5D, $DD, $3D, $BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3, $13, $93, $53, $D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB, $1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7, $27, $A7, $67, $E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F, $4F, $CF, $2F, $AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF); var i : integer; Symbol : integer; LengthCount : array [0..dfc_MaxCodeLength] of integer; NextCode : array [0..dfc_MaxCodeLength] of integer; Code : longint; CodeLen : integer; CodeData : longint; DecoderLen : integer; CodeIncr : integer; Decodes : PAbDfLongintList; Encodes : PAbDfLongintList; {$IFDEF CPU386} DecodesEnd : pointer; {$ENDIF} TablePtr : pointer; begin {count the number of instances of each code length and calculate the maximum code length at the same time} FillChar(LengthCount, sizeof(LengthCount), 0); FMaxCodeLen := 0; for i := 0 to pred(aCount) do begin CodeLen := aCodeLengths[i + aStartInx]; Assert((CodeLen <= FDefMaxCodeLen), Format('TAbDfDecodeHuffmanTree.Build: a code length is greater than %d', [FDefMaxCodeLen])); if (CodeLen > FMaxCodeLen) then FMaxCodeLen := CodeLen; inc(LengthCount[CodeLen]); end; {now we know the maximum code length we can allocate our decoder array} {$IFNDEF CPU386} DecoderLen := 0; {$ENDIF} if (FUsage <> huEncoding) then begin DecoderLen := PowerOfTwo[FMaxCodeLen]; GetMem(FDecodes, DecoderLen * sizeof(longint)); {$IFDEF CPU386} DecodesEnd := PAnsiChar(FDecodes) + (DecoderLen * sizeof(longint)); {$ENDIF} {$IFOPT C+} FillChar(FDecodes^, DecoderLen * sizeof(longint), $FF); FMask := not (DecoderLen - 1); {$ENDIF} end; {calculate the start codes for each code length} Code := 0; LengthCount[0] := 0; for i := 1 to FDefMaxCodeLen do begin Code := (Code + LengthCount[i-1]) shl 1; NextCode[i] := Code; end; {for speed and convenience} Decodes := FDecodes; Encodes := FEncodes; TablePtr := @ByteRevTable; {for each symbol...} for Symbol := 0 to pred(aCount) do begin {calculate the code length} CodeLen := aCodeLengths[Symbol + aStartInx]; {if the code length were zero, just set the relevant entry in the encoder array; the decoder array doesn't need anything} if (CodeLen = 0) then begin if (FUsage <> huDecoding) then Encodes^[Symbol] := -1 end {otherwise we need to fill elements in both the encoder and decoder arrays} else begin {calculate *reversed* code} Code := NextCode[CodeLen]; {$IFDEF CPU386} asm push esi mov eax, Code mov esi, TablePtr xor ecx, ecx xor edx, edx mov cl, ah mov dl, al mov al, [esi+ecx] mov ah, [esi+edx] mov ecx, 16 pop esi sub ecx, CodeLen shr eax, cl mov Code, eax end; {$ELSE} CodeData:= Code; LongRec(Code).Bytes[1]:= ByteRevTable[LongRec(CodeData).Bytes[0]]; LongRec(Code).Bytes[0]:= ByteRevTable[LongRec(CodeData).Bytes[1]]; Code:= Code shr (16-CodeLen); {$ENDIF} {set the code data (bit count, extra bits required, symbol), everywhere the reversed code would appear in the decoder array; set the code data in the encoder array as well} if (Symbol >= aExtraOffset) then begin if (FUsage <> huEncoding) then CodeData := Symbol + { symbol} (CodeLen shl 16) + { code length} (aExtraBits[Symbol-aExtraOffset] shl 24); { extra bits required} if (FUsage <> huDecoding) then Encodes^[Symbol] := Code + { code} (CodeLen shl 16) + { code length} (aExtraBits[Symbol-aExtraOffset] shl 24) { extra bits required} end else begin if (FUsage <> huEncoding) then CodeData := Symbol + { symbol} (CodeLen shl 16); { code length} if (FUsage <> huDecoding) then Encodes^[Symbol] := Code + { code} (CodeLen shl 16); { code length} end; {OPTIMIZATION NOTE: the following code CodeIncr := PowerOfTwo[CodeLen]; while Code < DecoderLen do begin Decodes^[Code] := CodeData; inc(Code, CodeIncr); end; was replaced by the asm code below to improve the speed. The code in the loop is the big time sink in this routine so it was best to replace it.} if (FUsage <> huEncoding) then begin {$IFDEF CPU386} CodeIncr := PowerOfTwo[CodeLen] * sizeof(longint); asm push edi { save edi} mov eax, Decodes { get the Decodes array} mov edi, DecodesEnd { get the end of the Decodes array} mov edx, Code { get Code and..} shl edx, 1 { ..multiply by 4} shl edx, 1 add eax, edx { eax => first element to be set} mov edx, CodeData { get the CodeData} mov ecx, CodeIncr { get the increment per loop} @@1: mov [eax], edx { set the element} add eax, ecx { move to the next element} cmp eax, edi { if we haven't gone past the end..} jl @@1 { ..go back for the next one} pop edi { retrieve edi} end; {$ELSE} CodeIncr := PowerOfTwo[CodeLen]; while Code < DecoderLen do begin Decodes^[Code] := CodeData; inc(Code, CodeIncr); end; {$ENDIF} end; {we've used this code up for this symbol, so increment for the next symbol at this code length} inc(NextCode[CodeLen]); end; end; end; {--------} {$IFDEF UseLogging} procedure TAbDfDecodeHuffmanTree.DebugPrint(aLog : TAbLogger); {$IFDEF EnableMegaLog} var i : integer; Code : longint; {$ENDIF} begin {to print the huffman tree, we must have a logger...} Assert(aLog <> nil, 'TAbDfDecodeHuffmanTree.DebugPrint needs a logger object to which to print'); if (FUsage <> huEncoding) then begin aLog.WriteLine('Huffman decoder array'); aLog.WriteLine(Format('Alphabet size: %d', [FAlphaSize])); aLog.WriteLine(Format('Max codelength: %d', [FMaxCodeLen])); {$IFDEF EnableMegaLog} aLog.WriteLine('Index Len Xtra Symbol Reversed Code'); for i := 0 to pred(PowerOfTwo[FMaxCodeLen]) do begin Code := FDecodes^[i]; if (Code = -1) then aLog.WriteLine(Format('%5d%49s', [i, 'no code'])) else aLog.WriteLine(Format('%5d%4d%5d%7d%33s', [i, ((Code shr 16) and $FF), ((Code shr 24) and $FF), (Code and $FFFF), CodeToStr(i, ((Code shr 16) and $FF))])); end; aLog.WriteLine('---end decoder array---'); {$ENDIF} end; if (FUsage <> huDecoding) then begin aLog.WriteLine('Huffman encoder array'); aLog.WriteLine(Format('Alphabet size: %d', [FAlphaSize])); {$IFDEF EnableMegaLog} aLog.WriteLine('Symbol Len Xtra Reversed Code'); for i := 0 to pred(FAlphaSize) do begin Code := FEncodes^[i]; if (Code = -1) then aLog.WriteLine(Format('%6d%42s', [i, 'no code'])) else aLog.WriteLine(Format('%6d%4d%5d%33s', [i, ((Code shr 16) and $FF), ((Code shr 24) and $FF), CodeToStr((Code and $FFFF), ((Code shr 16) and $FF))])); end; aLog.WriteLine('---end encoder array---'); {$ENDIF} end; end; {$ENDIF} {--------} function TAbDfDecodeHuffmanTree.Decode(aLookupBits : integer) : longint; begin {protect against dumb programming mistakes (note: FMask only exists if assertions are on)} {$IFOPT C+} Assert((aLookupBits and FMask) = 0, 'TAbDfDecodeHuffmanTree.Decode: trying to decode too many bits, use LookupBitLength property'); {$ENDIF} {return the code data} Result := FDecodes^[aLookupBits]; end; {--------} function TAbDfDecodeHuffmanTree.Encode(aSymbol : integer) : longint; begin {protect against dumb programming mistakes} Assert((0 <= aSymbol) and (aSymbol < FAlphaSize), 'TAbDfDecodeHuffmanTree.Encode: trying to encode a symbol that is not in the alphabet'); {return the code data} Result := FEncodes^[aSymbol]; {if the result is -1, it's another programming mistake: the user is attempting to get a code for a symbol that wasn't being used} Assert(Result <> -1, 'TAbDfDecodeHuffmanTree.Encode: trying to encode a symbol that was not used'); end; {====================================================================} {===BuildStaticTrees=================================================} procedure BuildStaticTrees; var i : integer; CodeLens : array [0..287] of integer; begin {this routine builds the static huffman trees, those whose code lengths are determined by the deflate spec} {the static literal tree first} for i := 0 to 143 do CodeLens[i] := 8; for i := 144 to 255 do CodeLens[i] := 9; for i := 256 to 279 do CodeLens[i] := 7; for i := 280 to 287 do CodeLens[i] := 8; AbStaticLiteralTree := TAbDfDecodeHuffmanTree.Create(288, 15, huBoth); AbStaticLiteralTree.Build(CodeLens, 0, 288, dfc_LitExtraBits, dfc_LitExtraOffset); {the static distance tree afterwards} for i := 0 to 31 do CodeLens[i] := 5; AbStaticDistanceTree := TAbDfDecodeHuffmanTree.Create(32, 15, huBoth); AbStaticDistanceTree.Build(CodeLens, 0, 32, dfc_DistExtraBits, dfc_DistExtraOffset); end; {====================================================================} initialization BuildStaticTrees; finalization AbStaticLiteralTree.Free; AbStaticDistanceTree.Free; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfinw.pas������������������������������������������0000644�0001750�0000144�00000053725�14743153644�022563� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfInW.pas *} {*********************************************************} {* Deflate input sliding window unit *} {*********************************************************} unit AbDfInW; {$I AbDefine.inc} interface uses Classes, AbDfBase; {Notes: TdfInputWindow implements a sliding window on data for the LZ77 dictionary encoding. The stream passed to the class is automatically read when required to keep the internal buffer fully loaded. } type TAbDfMatch = record maLen : integer; maDist : integer; maLit : AnsiChar; end; type PAbPointerList = ^TAbPointerList; TAbPointerList = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer; TAbDfInputWindow = class private FAdvanceStart : boolean; FBuffer : PAnsiChar; FBufferEnd : PAnsiChar; FBytesUsed : longint; FChainLen : integer; FHashChains : PAbPointerList; FHashHeads : PAbPointerList; FHashIndex : integer; FChecksum : longint; FCurrent : PAnsiChar; FLookAheadEnd : PAnsiChar; FMaxMatchLen : integer; FMustSlide : boolean; FOnProgress : TAbProgressStep; FSlidePoint : PAnsiChar; FStart : PAnsiChar; FStartOffset : Int64; FStream : TStream; FStreamSize : Int64; FUseCRC32 : boolean; FUseDeflate64 : boolean; FWinMask : integer; FWinSize : integer; protected function iwGetChecksum : longint; procedure iwReadFromStream; procedure iwSetCapacity(aValue : longint); procedure iwSlide; public constructor Create(aStream : TStream; aStreamSize : Int64; aWinSize : integer; aChainLength : integer; aUseDeflate64 : boolean; aUseCRC32 : boolean); destructor Destroy; override; procedure Advance(aCount : integer; aHashCount : integer); procedure AdvanceByOne; function FindLongestMatch(aAmpleLength : integer; var aMatch : TAbDfMatch; const aPrevMatch : TAbDfMatch) : boolean; function GetNextChar : AnsiChar; function GetNextKeyLength : integer; function Position : Int64; procedure ReadBuffer(var aBuffer; aCount : longint; aOffset : Int64); property ChainLen : integer read FChainLen write FChainLen; property Checksum : longint read iwGetChecksum; property OnProgress : TAbProgressStep read FOnProgress write FOnProgress; end; implementation uses SysUtils; {Notes: Meaning of the internal pointers: |----------+===================+==+--------------------------| | | | | | FBuffer FStart FCurrent FLookAheadEnd FBufferEnd FCurrent is the current match position. The valid data that can be matched is between FStart and FLookAheadEnd, The data between FStart and FCurrent has already been seen; the data between FCurrent and FLookAheadEnd can be used for matching. The buffer size depends on the requested window size (a multiple of 1KB, up to 32KB for deflate, up to 64KB for deflate64) and the lookahead size (up to 258 bytes for deflate and 64KB for deflate64.) The window of data continuously slides to the right, and is slid back to FBuffer whenever FStart reaches a point 16KB away, this point being given by FSlidePoint. The hash table: This is a chained hash table with some peculiarities. First the table itself, FHashHeads. It contains pointers to strings in the window buffer, not to chains. The chains are held is a separate structure, FHashChains. The hash function on the three-character keys is a Rabin-Karp function: ((((Ch1 shl 5) xor Ch2) shl 5) xor Ch3) and $3FFF designed so that a running hash value can be kept and calculated per character. The hash table is $4000 elements long (obviously, given the hash function). On insertion, the previous pointer in the hash table at the calculated index is saved and replaced by the new pointer. The old pointer is saved in the chains array. This has the same number of elements as the sliding window has characters. The pointer is placed at (Ptr and (WindowsSize-1)) overwriting the value that's already there. In this fashion the individual chains in the standard hash table are interwoven with each other in this hash table, like a skein of threads. } const c_HashCount = $4000; {the number of hash entries} c_HashMask = c_HashCount - 1; {a mask for the hash function} c_HashShift = 5; {shift value for the hash function} {===TAbDfInputWindow=================================================} constructor TAbDfInputWindow.Create(aStream : TStream; aStreamSize : Int64; aWinSize : integer; aChainLength : integer; aUseDeflate64 : boolean; aUseCRC32 : boolean); begin {create the ancestor} inherited Create; {save parameters} FStreamSize := aStreamSize; FWinSize := aWinSize; FWinMask := aWinSize - 1; FStream := aStream; FChainLen := aChainLength; FUseDeflate64 := aUseDeflate64; FUseCRC32 := aUseCRC32; if aUseCRC32 then FChecksum := -1 { CRC32 starts off with all bits set } else FCheckSum := 1; { Adler32 starts off with a value of 1 } {set capacity of sliding window} iwSetCapacity(aWinSize); {create the hash table, first the hash table itself (and set all entries to nil)} FHashHeads := AllocMem(c_HashCount * sizeof(pointer)); {..now the chains (there's no need to set the entries to nil, since the chain entries get fed from the head entries before searching)} GetMem(FHashChains, aWinSize * sizeof(pointer)); {read the first chunk of data from the stream} FMustSlide := true; iwReadFromStream; {if there are at least two bytes, prime the hash index} if ((FLookAheadEnd - FBuffer) >= 2) then FHashIndex := ((longint(FBuffer[0]) shl c_HashShift) xor longint(FBuffer[1])) and c_HashMask; end; {--------} destructor TAbDfInputWindow.Destroy; begin {free the hash table} FreeMem(FHashHeads); FreeMem(FHashChains); {free the buffer} FreeMem(FBuffer); {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfInputWindow.Advance(aCount : integer; aHashCount : integer); var i : integer; ByteCount : integer; Percent : integer; HashChains: PAbPointerList; HashHeads : PAbPointerList; HashInx : integer; CurPos : PAnsiChar; begin Assert((FLookAheadEnd - FCurrent) >= aCount, 'TAbDfInputWindow.Advance: seem to be advancing into the unknown'); Assert((aHashCount = aCount) or (aHashCount = pred(aCount)), 'TAbDfInputWindow.Advance: the parameters are plain wrong'); {use local var for speed} CurPos := FCurrent; {advance the current pointer if needed} if (aCount > aHashCount) then inc(CurPos); {make sure we update the hash table; remember that the string[3] at the current position has already been added to the hash table (for notes on updating the hash table, see FindLongestMatch} {use local vars for speed} HashChains := FHashChains; HashHeads := FHashHeads; HashInx := FHashIndex; {update the hash table} for i := 0 to pred(aHashCount) do begin HashInx := ((HashInx shl c_HashShift) xor longint(CurPos[2])) and c_HashMask; HashChains^[PtrUInt(CurPos) and FWinMask] := HashHeads^[HashInx]; HashHeads^[HashInx] := CurPos; inc(CurPos); end; {replace old values} FHashChains := HashChains; FHashHeads := HashHeads; FHashIndex := HashInx; FCurrent := CurPos; {if we've seen at least FWinSize bytes...} if FAdvanceStart then begin {advance the start of the sliding window} inc(FStart, aCount); inc(FStartOffset, aCount); {check to see if we have advanced into the slide zone} if FMustSlide and (FStart >= FSlidePoint) then iwSlide; end {otherwise check to see if we've seen at least FWinSize bytes} else if ((CurPos - FStart) >= FWinSize) then begin FAdvanceStart := true; {note: we can't advance automatically aCount bytes here, we need to calculate the actual count} ByteCount := (CurPos - FWinSize) - FStart; inc(FStart, ByteCount); inc(FStartOffset, ByteCount); end; {show progress} if Assigned(FOnProgress) then begin inc(FBytesUsed, aCount); if ((FBytesUsed and $FFF) = 0) then begin Percent := Round((100.0 * FBytesUsed) / FStreamSize); FOnProgress(Percent); end; end; {check to see if we have advanced into the slide zone} if (FStart >= FSlidePoint) then iwSlide; end; {--------} procedure TAbDfInputWindow.AdvanceByOne; var Percent : integer; begin {advance the current pointer} inc(FCurrent); {if we've seen at least FWinSize bytes...} if FAdvanceStart then begin {advance the start of the sliding window} inc(FStart, 1); inc(FStartOffset, 1); {check to see if we have advanced into the slide zone} if FMustSlide and (FStart >= FSlidePoint) then iwSlide; end {otherwise check to see if we've seen FWinSize bytes} else if ((FCurrent - FStart) = FWinSize) then FAdvanceStart := true; {show progress} if Assigned(FOnProgress) then begin inc(FBytesUsed, 1); if ((FBytesUsed and $FFF) = 0) then begin Percent := Round((100.0 * FBytesUsed) / FStreamSize); FOnProgress(Percent); end; end; end; {--------} function TAbDfInputWindow.FindLongestMatch(aAmpleLength : integer; var aMatch : TAbDfMatch; const aPrevMatch : TAbDfMatch) : boolean; {Note: this routine implements a greedy algorithm and is by far the time sink for compression. There are two versions, one written in Pascal for understanding, one in assembler for speed. Activate one and only one of the following compiler defines.} {$IFDEF CPU386} {$DEFINE UseGreedyAsm} {$ELSE} {$DEFINE UseGreedyPascal} {$ENDIF} {Check to see that all is correct} {$IFDEF UseGreedyAsm} {$IFDEF UseGreedyPascal} !! Compile Error: only one of the greedy compiler defines can be used {$ENDIF} {$ELSE} {$IFNDEF UseGreedyPascal} !! Compile Error: one of the greedy compiler defines must be used {$ENDIF} {$ENDIF} type PWord = ^word; var MaxLen : longint; MaxDist : longint; MaxMatch : integer; ChainLen : integer; PrevStrPos : PAnsiChar; CurPos : PAnsiChar; {$IFDEF UseGreedyAsm} CurWord : word; MaxWord : word; {$ENDIF} {$IFDEF UseGreedyPascal} Len : longint; MatchStr : PAnsiChar; CurrentCh : PAnsiChar; CurCh : AnsiChar; MaxCh : AnsiChar; {$ENDIF} begin {calculate the hash index for the current position; using the Rabin-Karp algorithm this is equal to the previous index less the effect of the character just lost plus the effect of the character just gained} CurPos := FCurrent; FHashIndex := ((FHashIndex shl c_HashShift) xor longint(CurPos[2])) and c_HashMask; {get the head of the hash chain: this is the position in the sliding window of the previous 3-character string with this hash value} PrevStrPos := FHashHeads^[FHashIndex]; {set the head of the hash chain equal to our current position} FHashHeads^[FHashIndex] := CurPos; {update the chain itself: set the entry for this position equal to the previous string position} FHashChains^[PtrUInt(CurPos) and FWinMask] := PrevStrPos; {calculate the maximum match we could do at this position} MaxMatch := (FLookAheadEnd - CurPos); if (MaxMatch > FMaxMatchLen) then MaxMatch := FMaxMatchLen; if (aAmpleLength > MaxMatch) then aAmpleLength := MaxMatch; {calculate the current match length} if (aPrevMatch.maLen = 0) then MaxLen := 2 else begin if (MaxMatch < aPrevMatch.maLen) then begin Result := false; aMatch.maLen := 0; aMatch.maLit := CurPos^; Exit; end; MaxLen := aPrevMatch.maLen; end; {get the bytes at the current position and at the end of the maximum match we have to better} {$IFDEF UseGreedyAsm} CurWord := PWord(CurPos)^; MaxWord := PWord(CurPos + pred(MaxLen))^; {$ENDIF} {$IFDEF UseGreedyPascal} CurCh := CurPos^; MaxCh := (CurPos + pred(MaxLen))^; {$ENDIF} {set the chain length to search based on the current maximum match (basically: if we've already satisfied the ample length requirement, don't search as far)} if (MaxLen >= aAmpleLength) then ChainLen := FChainLen div 4 else ChainLen := FChainLen; {get ready for the loop} {$IFDEF DefeatWarnings} MaxDist := 0; {$ENDIF} {$IFDEF UseGreedyAsm} { slip into assembler for speed...} asm push ebx { save those registers we should} push esi push edi mov ebx, Self { ebx will store the Self pointer} mov edi, PrevStrPos { edi => previous string} mov esi, CurPos { esi => current string} @@TestThisPosition: { check previous string is in range} or edi, edi je @@Exit cmp edi, [ebx].TAbDfInputWindow.FStart jb @@Exit cmp edi, CurPos jae @@Exit mov ax, [edi] { check previous string starts with same} cmp CurWord, ax { two bytes as current} jne @@GetNextPosition { ..nope, they don't match} mov edx, edi { check previous string ends with same} add edi, MaxLen { two bytes as current (by "ends" we} dec edi { mean the last two bytes at the} mov ax, [edi] { current match length)} cmp MaxWord, ax mov edi, edx jne @@GetNextPosition { ..nope, they don't match} push edi { compare the previous string with the} push esi { current string} mov eax, MaxMatch add edi, 2 { (we've already checked that the first} sub eax, 2 { two characters are the same)} add esi, 2 mov ecx, eax @@CmpQuads: cmp ecx, 4 jb @@CmpSingles mov edx, [esi] cmp edx, [edi] jne @@CmpSingles add esi, 4 add edi, 4 sub ecx, 4 jnz @@CmpQuads jmp @@MatchCheck @@CmpSingles: or ecx, ecx jb @@MatchCheck mov dl, [esi] cmp dl, [edi] jne @@MatchCheck inc esi inc edi dec ecx jnz @@CmpSingles @@MatchCheck: sub eax, ecx add eax, 2 pop esi pop edi cmp eax, MaxLen { have we found a longer match?} jbe @@GetNextPosition { ..no} mov MaxLen, eax { ..yes, so save it} mov eax, esi { calculate the dist for this new match} sub eax, edi mov MaxDist, eax cmp eax, aAmpleLength { if this match is ample enough, exit} jae @@Exit mov eax, esi { calculate the two bytes at the end of} add eax, MaxLen { this new match} dec eax mov ax, [eax] mov MaxWord, ax @@GetNextPosition: mov eax, ChainLen { we've visited one more link on the} dec eax { chain, if that's the last one we} je @@Exit { should visit, exit} mov ChainLen, eax { advance along the chain} mov edx, [ebx].TAbDfInputWindow.FHashChains mov eax, [ebx].TAbDfInputWindow.FWinMask and edi, eax shl edi, 2 mov edi, [edx+edi] jmp @@TestThisPosition @@Exit: pop edi pop esi pop ebx end; {$ENDIF} {$IFDEF UseGreedyPascal} {for all possible hash nodes in the chain...} while (FStart <= PrevStrPos) and (PrevStrPos < CurPos) do begin {if the initial and maximal characters match...} if (PrevStrPos[0] = CurCh) and (PrevStrPos[pred(MaxLen)] = MaxCh) then begin {compare more characters} Len := 1; CurrentCh := CurPos + 1; MatchStr := PrevStrPos + 1; {compare away, but don't go above the maximum length} while (Len < MaxMatch) and (MatchStr^ = CurrentCh^) do begin inc(CurrentCh); inc(MatchStr); inc(Len); end; {have we reached another maximum for the length?} if (Len > MaxLen) then begin MaxLen := Len; {calculate the distance} MaxDist := CurPos - PrevStrPos; MaxCh := CurPos[pred(MaxLen)]; {is the new best length ample enough?} if MaxLen >= aAmpleLength then Break; end; end; {have we reached the end of this chain?} dec(ChainLen); if (ChainLen = 0) then Break; {otherwise move onto the next position} PrevStrPos := FHashChains^[PtrUInt(PrevStrPos) and FWinMask]; end; {$ENDIF} {based on the results of our investigation, return the match values} if (MaxLen < 3) or (MaxLen <= aPrevMatch.maLen) then begin Result := false; aMatch.maLen := 0; aMatch.maLit := CurPos^; end else begin Result := true; aMatch.maLen := MaxLen; aMatch.maDist := MaxDist; aMatch.maLit := CurPos^; { just in case...} end; end; {--------} function TAbDfInputWindow.GetNextChar : AnsiChar; begin Result := FCurrent^; inc(FCurrent); end; {--------} function TAbDfInputWindow.GetNextKeyLength : integer; begin Result := FLookAheadEnd - FCurrent; if (Result > 3) then Result := 3; end; {--------} function TAbDfInputWindow.iwGetChecksum : longint; begin {the CRC32 checksum algorithm requires a post-conditioning step after being calculated (the result is NOTted), whereas Adler32 does not} if FUseCRC32 then Result := not FChecksum else Result := FChecksum; end; {--------} procedure TAbDfInputWindow.iwReadFromStream; var BytesRead : longint; BytesToRead : longint; begin {read some more data into the look ahead zone} BytesToRead := FBufferEnd - FLookAheadEnd; BytesRead := FStream.Read(FLookAheadEnd^, BytesToRead); {if nothing was read, we reached the end of the stream; hence there's no more need to slide the window since we have all the data} if (BytesRead = 0) then FMustSlide := false {otherwise something was actually read...} else begin {update the checksum} if FUseCRC32 then AbUpdateCRCBuffer(FChecksum, FLookAheadEnd^, BytesRead) else AbUpdateAdlerBuffer(FChecksum, FLookAheadEnd^, BytesRead); {reposition the pointer for the end of the lookahead area} inc(FLookAheadEnd, BytesRead); end; end; {--------} procedure TAbDfInputWindow.iwSetCapacity(aValue : longint); var ActualSize : integer; begin {calculate the actual size; this will be the value passed in, plus the correct look ahead size, plus 16KB} ActualSize := aValue + (16 * 1024); if FUseDeflate64 then begin inc(ActualSize, dfc_MaxMatchLen64); FMaxMatchLen := dfc_MaxMatchLen64; end else begin inc(ActualSize, dfc_MaxMatchLen); FMaxMatchLen := dfc_MaxMatchLen; end; {get the new buffer} GetMem(FBuffer, ActualSize); {set the other buffer pointers} FStart := FBuffer; FCurrent := FBuffer; FLookAheadEnd := FBuffer; FBufferEnd := FBuffer + ActualSize; FSlidePoint := FBuffer + (16 * 1024); end; {--------} procedure TAbDfInputWindow.iwSlide; var i : integer; ByteCount : PtrInt; Buffer : PAnsiChar; ListItem : PPointer; begin {move current valid data back to the start of the buffer} ByteCount := FLookAheadEnd - FStart; Move(FStart^, FBuffer^, ByteCount); {reset the various pointers} ByteCount := FStart - FBuffer; FStart := FBuffer; dec(FCurrent, ByteCount); dec(FLookAheadEnd, ByteCount); {patch up the hash table: the head pointers} Buffer := FBuffer; ListItem := @FHashHeads^[0]; for i := 0 to pred(c_HashCount) do begin dec(ListItem^, ByteCount); if (ListItem^ < Buffer) then ListItem^ := nil; inc(ListItem); end; {..the chain pointers} ListItem := @FHashChains^[0]; for i := 0 to pred(FWinSize) do begin dec(ListItem^, ByteCount); if (ListItem^ < Buffer) then ListItem^ := nil; inc(ListItem); end; {now read some more data from the stream} iwReadFromStream; end; {--------} function TAbDfInputWindow.Position : Int64; begin Result := (FCurrent - FStart) + FStartOffset; end; {--------} procedure TAbDfInputWindow.ReadBuffer(var aBuffer; aCount : longint; aOffset : Int64); var CurPos : Int64; begin CurPos := FStream.Seek(0, soCurrent); FStream.Seek(aOffSet, soBeginning); FStream.ReadBuffer(aBuffer, aCount); FStream.Seek(CurPos, soBeginning); end; {====================================================================} end. �������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfoutw.pas�����������������������������������������0000644�0001750�0000144�00000026405�14743153644�022757� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfOutW.pas *} {*********************************************************} {* Deflate output sliding window *} {*********************************************************} unit AbDfOutW; {$I AbDefine.inc} interface uses Classes, AbDfBase; {Notes: TAbDfOutputWindow implements a sliding window on previously written data for the LZ77 dictionary decoding. AddLiteral will add a literal character at the current position and advance by one. AddLenDist will copy the required number of characters from the given position to the current position, and advance the stream on by the length. The class will periodically update the stream from the internal buffer. For normal Deflate, the internal buffer is 48K + 512 bytes in size. Once there is 48Kb worth of data, 16KB is written to file, and the buffer is shifted left by 16KB. We need to keep the last decoded 32KB in memory at all times. For Deflate64, the internal buffer is 96K + 512 bytes in size. Once there is 96Kb worth of data, 32KB is written to file, and the buffer is shifted left by 32KB. We need to keep the last decoded 64KB in memory at all times. } type TAbDfOutputWindow = class private FBuffer : PAnsiChar; FChecksum : longint; FCurrent : PAnsiChar; FLog : TAbLogger; FPartSize : longint; FSlideCount : integer; FStream : TStream; FStreamPos : longint; FTestOnly : boolean; FUseCRC32 : boolean; FWritePoint : PAnsiChar; protected function swGetChecksum : longint; procedure swWriteToStream(aFlush : boolean); public constructor Create(aStream : TStream; aUseDeflate64 : boolean; aUseCRC32 : boolean; aPartSize : longint; aTestOnly : boolean; aLog : TAbLogger); destructor Destroy; override; procedure AddBuffer(var aBuffer; aCount : integer); procedure AddLiteral(aCh : AnsiChar); procedure AddLenDist(aLen : integer; aDist : integer); function Position : longint; property Checksum : longint read swGetChecksum; property Log : TAbLogger read FLog; end; implementation uses SysUtils; {Notes: Meaning of the internal pointers: |==============================+------------------------+----| | | | FBuffer FCurrent FWritePoint Once FCurrent reaches or exceeds FWritePoint, FSlideCount bytes of data from FBuffer are written to the stream and the remaining data is moved back FSlideCount bytes, moving FCurrent along with it as well. } {===TAbDfOutputWindow==================================================} constructor TAbDfOutputWindow.Create(aStream : TStream; aUseDeflate64 : boolean; aUseCRC32 : boolean; aPartSize : longint; aTestOnly : boolean; aLog : TAbLogger); var Size : integer; LookAheadSize : integer; begin {allow the ancestor to initialize} inherited Create; {save parameters} FLog := aLog; FStream := aStream; FTestOnly := aTestOnly; if (aPartSize <= 0) then FPartSize := 0 else FPartSize := aPartSize; FUseCRC32 := aUseCRC32; if aUseCRC32 then FChecksum := -1 { CRC32 starts off with all bits set} else FCheckSum := 1; { Adler32 starts off with a value of 1} {set capacity of sliding window} if aUseDeflate64 then begin Size := 96 * 1024; FSlideCount := 32 * 1024; LookAheadSize := 64 * 1024; end else begin Size := 64 * 1024; FSlideCount := 32 * 1024; LookAheadSize := 258; end; GetMem(FBuffer, Size + LookAheadSize); {set the other internal pointers} FCurrent := FBuffer; FWritePoint := FBuffer + Size; if (FPartSize > Size) then FPartSize := Size; end; {--------} destructor TAbDfOutputWindow.Destroy; begin {write remaining data and free the buffer} if (FBuffer <> nil) then begin if (FCurrent <> FBuffer) then swWriteToStream(true); FreeMem(FBuffer); end; {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfOutputWindow.AddBuffer(var aBuffer; aCount : integer); var Buffer : PAnsiChar; BytesToWrite : integer; begin {if we've advanced to the point when we need to write, do so} if (FCurrent >= FWritePoint) then swWriteToStream(false); {cast the user buffer to a PChar, it's easier to use} Buffer := @aBuffer; {calculate the number of bytes to copy} BytesToWrite := FWritePoint - FCurrent; if (BytesToWrite > aCount) then BytesToWrite := aCount; {move this block of bytes} Move(Buffer^, FCurrent^, BytesToWrite); {advance pointers and counters} inc(FCurrent, BytesToWrite); dec(aCount, BytesToWrite); {while there is still data to copy...} while (aCount > 0) do begin {advance the user buffer pointer} inc(Buffer, BytesToWrite); {write the sliding window chunk to the stream} swWriteToStream(false); {calculate the number of bytes to copy} BytesToWrite := FWritePoint - FCurrent; if (BytesToWrite > aCount) then BytesToWrite := aCount; {move this block of bytes} Move(Buffer^, FCurrent^, BytesToWrite); {advance pointers and counters} inc(FCurrent, BytesToWrite); dec(aCount, BytesToWrite); end; end; {--------} procedure AddLenDistToLog(aLog : TAbLogger; aPosn : longint; aLen : integer; aDist : integer; aOverLap : boolean); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if aOverLap then aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d **overlap**', [aPosn, aLen, aDist])) else aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d', [aPosn, aLen, aDist])); end; {--------} procedure TAbDfOutputWindow.AddLenDist(aLen : integer; aDist : integer); var i : integer; ToChar : PAnsiChar; FromChar : PAnsiChar; begin {log it} {$IFDEF UseLogging} if (FLog <> nil) then AddLenDistToLog(FLog, Position, aLen, aDist, (aLen > aDist)); {$ENDIF} {if the length to copy is less than the distance, just do a move} if (aLen <= aDist) then begin Move((FCurrent - aDist)^ , FCurrent^, aLen); end {otherwise we have to use a byte-by-byte copy} else begin FromChar := FCurrent - aDist; ToChar := FCurrent; for i := 1 to aLen do begin ToChar^ := FromChar^; inc(FromChar); inc(ToChar); end; end; {increment the current pointer} inc(FCurrent, aLen); {if we've reached the point requested, abort} if (FPartSize > 0) and ((FCurrent - FBuffer) >= FPartSize) then raise EAbPartSizedInflate.Create(''); {NOTE: This exception is expected during detection of .GZ and .TGZ files. (VerifyGZip)} {if we've advanced to the point when we need to write, do so} if (FCurrent >= FWritePoint) then swWriteToStream(false); end; {--------} procedure AddLiteralToLog(aLog : TAbLogger; aPosn : longint; aCh : AnsiChar); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if (' ' < aCh) and (aCh <= '~') then aLog.WriteLine(Format('%8x Char: %3d $%2x [%s]', [aPosn, ord(aCh), ord(aCh), aCh])) else aLog.WriteLine(Format('%8x Char: %3d $%2x', [aPosn, ord(aCh), ord(aCh)])); end; {--------} procedure TAbDfOutputWindow.AddLiteral(aCh : AnsiChar); begin {log it} {$IFDEF UseLogging} if (FLog <> nil) then AddLiteralToLog(FLog, Position, aCh); {$ENDIF} {add the literal to the buffer} FCurrent^ := aCh; {increment the current pointer} inc(FCurrent); {if we've reached the point requested, abort} if (FPartSize > 0) and ((FCurrent - FBuffer) >= FPartSize) then raise EAbPartSizedInflate.Create(''); {if we've advanced to the point when we need to write, do so} if (FCurrent >= FWritePoint) then swWriteToStream(false); end; {--------} function TAbDfOutputWindow.Position : longint; begin if FTestOnly then Result := FStreamPos + (FCurrent - FBuffer) else Result := FStream.Position + (FCurrent - FBuffer); end; {--------} function TAbDfOutputWindow.swGetChecksum : longint; begin {since the checksum is calculated by the method that flushes to the stream, make sure any buffered data is written out first} if (FCurrent <> FBuffer) then swWriteToStream(true); {the CRC32 checksum algorithm requires a post-conditioning step after being calculated (the result is NOTted), whereas Adler32 does not} if FUseCRC32 then Result := not FChecksum else Result := FChecksum; end; {--------} procedure TAbDfOutputWindow.swWriteToStream(aFlush : boolean); var FromPtr : PAnsiChar; begin {if the request was to flush, write all remaining data after updating the checksum} if aFlush then begin if FUseCRC32 then AbUpdateCRCBuffer(FChecksum, FBuffer^, FCurrent - FBuffer) else AbUpdateAdlerBuffer(FChecksum, FBuffer^, FCurrent - FBuffer); if FTestOnly then inc(FStreamPos, FCurrent - FBuffer) else FStream.WriteBuffer(FBuffer^, FCurrent - FBuffer); FCurrent := FBuffer; end {otherwise, update the checksum with the data in the sliding window chunk, write it out to the stream, and move the rest of the buffer back} else begin if FUseCRC32 then AbUpdateCRCBuffer(FChecksum, FBuffer^, FSlideCount) else AbUpdateAdlerBuffer(FChecksum, FBuffer^, FSlideCount); if FTestOnly then inc(FStreamPos, FSlideCount) else FStream.WriteBuffer(FBuffer^, FSlideCount); FromPtr := FBuffer + FSlideCount; Move(FromPtr^, FBuffer^, FCurrent - FromPtr); FCurrent := FCurrent - FSlideCount; end; end; {====================================================================} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfpkmg.pas�����������������������������������������0000644�0001750�0000144�00000021740�14743153644�022714� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfPkMg.pas *} {*********************************************************} {* Deflate package-merge algorithm *} {*********************************************************} unit AbDfPkMg; {$I AbDefine.inc} interface uses AbDfBase; procedure GenerateCodeLengths(aMaxCodeLen : integer; const aWeights : array of integer; var aCodeLengths : array of integer; aStartInx : integer; aLog : TAbLogger); implementation type PPkgNode = ^TPkgNode; TPkgNode = packed record pnWeight : integer; pnCount : integer; pnLeft : PPkgNode; pnRight : PPkgNode; end; PPkgNodeList = ^TPkgNodeList; TPkgNodeList = array [0..pred(286 * 2)] of PPkgNode; {Note: the "286" is the number of literal/length symbols, the maximum number of weights we'll be calculating the optimal code lengths for} {===helper routines==================================================} function IsCalcFeasible(aCount : integer; aMaxCodeLen : integer) : boolean; begin {works out if length-limited codes can be calculated for a given number of symbols and the maximum code length} {return whether 2^aMaxCodeLen > aCount} Result := (1 shl aMaxCodeLen) > aCount; end; {--------} procedure QSS(aList : PPkgNodeList; aFirst : integer; aLast : integer); var L, R : integer; Pivot : integer; Temp : pointer; begin {while there are at least two items to sort} while (aFirst < aLast) do begin {the pivot is the middle item} Pivot := aList^[(aFirst+aLast) div 2]^.pnWeight; {set indexes and partition} L := pred(aFirst); R := succ(aLast); while true do begin repeat dec(R); until (aList^[R]^.pnWeight <= Pivot); repeat inc(L); until (aList^[L]^.pnWeight >= Pivot); if (L >= R) then Break; Temp := aList^[L]; aList^[L] := aList^[R]; aList^[R] := Temp; end; {quicksort the first subfile} if (aFirst < R) then QSS(aList, aFirst, R); {quicksort the second subfile - recursion removal} aFirst := succ(R); end; end; {--------} procedure SortList(aList : PPkgNodeList; aCount : integer); begin QSS(aList, 0, pred(aCount)); end; {--------} procedure Accumulate(aNode : PPkgNode); begin while (aNode^.pnLeft <> nil) do begin Accumulate(aNode^.pnLeft); aNode := aNode^.pnRight; end; inc(aNode^.pnCount); end; {====================================================================} {===Interfaced routine===============================================} procedure GenerateCodeLengths(aMaxCodeLen : integer; const aWeights : array of integer; var aCodeLengths : array of integer; aStartInx : integer; aLog : TAbLogger); var i : integer; Bit : integer; WeightCount : integer; OrigList : PPkgNodeList; OrigListCount : integer; MergeList : PPkgNodeList; MergeListCount : integer; PkgList : PPkgNodeList; PkgListCount : integer; OrigInx : integer; PkgInx : integer; Node : PPkgNode; NodeMgr : TAbNodeManager; begin {calculate the number of weights} WeightCount := succ(high(aWeights)); {check for dumb programming errors} Assert((0 < aMaxCodeLen) and (aMaxCodeLen <= 15), 'GenerateCodeLengths: the maximum code length should be in the range 1..15'); Assert((1 <= WeightCount) and (WeightCount <= 286), 'GenerateCodeLengths: the weight array must have 1..286 elements'); Assert(IsCalcFeasible(WeightCount, aMaxCodeLen), 'GenerateCodeLengths: the package-merge algorithm should always be feasible'); {clear the code lengths array} FillChar(aCodeLengths[aStartInx], WeightCount * sizeof(integer), 0); {prepare for the try..finally} OrigList := nil; MergeList := nil; PkgList := nil; NodeMgr := nil; try {create the node manager} NodeMgr := TAbNodeManager.Create(sizeof(TPkgNode)); {create the original list of nodes} GetMem(OrigList, WeightCount * sizeof(PPkgNode)); OrigListCount := 0; for i := 0 to pred(WeightCount) do if (aWeights[i] <> 0) then begin Node := NodeMgr.AllocNode; Node^.pnLeft := nil; { this will indicate a leaf} Node^.pnRight := pointer(i); { the index of the weight} Node^.pnWeight := aWeights[i]; { the weight itself} Node^.pnCount := 1; { how many times used} OrigList^[OrigListCount] := Node; inc(OrigListCount); end; {we need at least 2 items, so make anything less a special case} if (OrigListCount <= 1) then begin {if there are no items at all in the original list, we need to pretend that there is one, since we shall eventually need to calculate a Count-1 value that cannot be negative} if (OrigListCount = 0) then begin aCodeLengths[aStartInx] := 1; Exit; end; {otherwise there is only one item: set its code length directly} for i := 0 to pred(WeightCount) do if (aWeights[i] <> 0) then begin aCodeLengths[aStartInx + i] := 1; Exit; end; end; {there are at least 2 items in the list; so sort the list} SortList(OrigList, OrigListCount); {create the merge and package lists} GetMem(MergeList, OrigListCount * 2 * sizeof(PPkgNode)); GetMem(PkgList, OrigListCount * 2 * sizeof(PPkgNode)); {initialize the merge list to have the same items as the original list} Move(OrigList^, MergeList^, OrigListCount * sizeof(PPkgNode)); MergeListCount := OrigListCount; {do aMaxCodeLen - 2 times...} for Bit := 1 to pred(aMaxCodeLen) do begin {generate the package list from the merge list by grouping pairs from the merge list and adding them to the package list} PkgListCount := 0; for i := 0 to pred(MergeListCount div 2) do begin Node := NodeMgr.AllocNode; Node^.pnLeft := MergeList^[i * 2]; Node^.pnRight := MergeList^[i * 2 + 1]; Node^.pnWeight := Node^.pnLeft^.pnWeight + Node^.pnRight^.pnWeight; {$IFOPT C+} Node^.pnCount := 0; {$ENDIF} PkgList^[PkgListCount] := Node; inc(PkgListCount); end; {merge the original list and the package list} MergeListCount := 0; OrigInx := 0; PkgInx := 0; {note the optimization here: the package list will *always* be last to empty in the merge process since it will have at least one item whose accumulated weight is greater than all of the items in the original list} while (OrigInx < OrigListCount) and (PkgInx < PkgListCount) do begin if (OrigList^[OrigInx]^.pnWeight <= PkgList^[PkgInx]^.pnWeight) then begin MergeList^[MergeListCount] := OrigList^[OrigInx]; inc(OrigInx); end else begin MergeList^[MergeListCount] := PkgList^[PkgInx]; inc(PkgInx); end; inc(MergeListCount); end; if (OrigInx < OrigListCount) then begin Move(OrigList^[OrigInx], MergeList^[MergeListCount], (OrigListCount - OrigInx) * sizeof(PPkgNode)); inc(MergeListCount, (OrigListCount - OrigInx)); end else begin Move(PkgList^[PkgInx], MergeList^[MergeListCount], (PkgListCount - PkgInx) * sizeof(PPkgNode)); inc(MergeListCount, (PkgListCount - PkgInx)); end; end; {calculate the code lengths} for i := 0 to (OrigListCount * 2) - 3 do begin Node := MergeList^[i]; if (Node^.pnLeft <> nil) then Accumulate(Node); end; for i := 0 to pred(OrigListCount) do aCodeLengths[aStartInx + integer(OrigList^[i].pnRight)] := OrigList^[i].pnCount; finally FreeMem(OrigList); FreeMem(MergeList); FreeMem(PkgList); NodeMgr.Free; end; end; {====================================================================} end. ��������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfstrm.pas�����������������������������������������0000644�0001750�0000144�00000132314�14743153644�022743� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfStrm.pas *} {*********************************************************} {* Deflate streams unit for various streams *} {*********************************************************} unit AbDfStrm; {$I AbDefine.inc} interface uses Classes, AbDfBase, AbDfInW, AbDfHufD; type TAb32bit = longint; { a 32-bit type} PAbDfLitBuckets = ^TAbDfLitBuckets; TAbDfLitBuckets = array [0..285] of integer; PAbDfDistBuckets = ^TAbDfDistBuckets; TAbDfDistBuckets = array [0..31] of integer; PAbDfCodeLenBuckets = ^TAbDfCodeLenBuckets; TAbDfCodeLenBuckets = array [0..18] of integer; const AbExtractMask : array [1..31] of TAb32bit = ($00000001, $00000003, $00000007, $0000000F, $0000001F, $0000003F, $0000007F, $000000FF, $000001FF, $000003FF, $000007FF, $00000FFF, $00001FFF, $00003FFF, $00007FFF, $0000FFFF, $0001FFFF, $0003FFFF, $0007FFFF, $000FFFFF, $001FFFFF, $003FFFFF, $007FFFFF, $00FFFFFF, $01FFFFFF, $03FFFFFF, $07FFFFFF, $0FFFFFFF, $1FFFFFFF, $3FFFFFFF, $7FFFFFFF); type TAbDfInBitStream = class { input bit stream} private FBitBuffer : TAb32bit; FBitsLeft : integer; FBufEnd : PAnsiChar; FBuffer : PAnsiChar; FBufPos : PAnsiChar; FByteCount : longint; FFakeCount : integer; FOnProgress: TAbProgressStep; {$IFOPT C+} FPeekCount : integer; {$ENDIF} FStream : TStream; FStreamSize: longint; protected function ibsFillBuffer : boolean; public constructor Create(aStream : TStream; aOnProgress : TAbProgressStep; aStreamSize : longint); destructor Destroy; override; procedure AlignToByte; procedure DiscardBits(aCount : integer); procedure DiscardMoreBits(aCount : integer); function PeekBits(aCount : integer) : integer; function PeekMoreBits(aCount : integer) : integer; function ReadBit : boolean; function ReadBits(aCount : integer) : integer; procedure ReadBuffer(var aBuffer; aCount : integer); property BitBuffer : TAb32bit read FBitBuffer write FBitBuffer; property BitsLeft : integer read FBitsLeft write FBitsLeft; end; type TAbDfOutBitStream = class { output bit stream} private FBitBuffer : TAb32bit; FBitsUsed : integer; FBufEnd : PAnsiChar; FBuffer : PAnsiChar; FBufPos : PAnsiChar; FStream : TStream; protected procedure obsEmptyBuffer; public constructor Create(aStream : TStream); destructor Destroy; override; procedure AlignToByte; function Position : longint; procedure WriteBit(aBit : boolean); procedure WriteBits(aBits : integer; aCount : integer); procedure WriteBuffer(var aBuffer; aCount : integer); procedure WriteMoreBits(aBits : integer; aCount : integer); property BitBuffer : TAb32bit read FBitBuffer write FBitBuffer; property BitsUsed : integer read FBitsUsed write FBitsUsed; end; type TAbDfLZStream = class { LZ77 token stream} private FCurPos : PAnsiChar; FDistBuckets : PAbDfDistBuckets; FDistCount : integer; FLitBuckets : PAbDfLitBuckets; FLitCount : integer; FLog : TAbLogger; FSlideWin : TAbDfInputWindow; FStartOfs : Int64; FStoredSize : LongWord; FStream : PAnsiChar; FStrmEnd : PAnsiChar; {$IFDEF UseLogging} FSWPos : longint; {$ENDIF} FUseDeflate64: boolean; protected function lzsGetApproxSize : LongWord; function lzsGetStaticSize : integer; function lzsGetStoredSize : integer; function lzsIsFull : boolean; public constructor Create(aSlideWin : TAbDfInputWindow; aUseDeflate64 : boolean; aLog : TAbLogger); destructor Destroy; override; function AddLenDist(aLen : integer; aDist : integer) : boolean; { returns true if the stream is "full"} function AddLiteral(aCh : AnsiChar) : boolean; { returns true if the stream is "full"} procedure Clear; procedure Encode(aBitStrm : TAbDfOutBitStream; aLitTree : TAbDfDecodeHuffmanTree; aDistTree : TAbDfDecodeHuffmanTree; aUseDeflate64 : boolean); procedure Rewind; procedure ReadStoredBuffer(var aBuffer; aCount : integer); property LenDistCount : integer read FDistCount; property LiteralCount : integer read FLitCount; property DistBuckets : PAbDfDistBuckets read FDistBuckets; property LitBuckets : PAbDfLitBuckets read FLitBuckets; property StaticSize : integer read lzsGetStaticSize;{ in bits} property StoredSize : integer read lzsGetStoredSize;{ in bytes} end; type TAbDfCodeLenStream = class { codelength token stream} private FBuckets : PAbDfCodeLenBuckets; FPosition : PAnsiChar; FStream : PAnsiChar; {array [0..285+32*2] of byte;} FStrmEnd : PAnsiChar; protected public constructor Create(aLog : TAbLogger); destructor Destroy; override; procedure Build(const aCodeLens : array of integer; aCount : integer); procedure Encode(aBitStrm : TAbDfOutBitStream; aTree : TAbDfDecodeHuffmanTree); property Buckets : PAbDfCodeLenBuckets read FBuckets; end; implementation uses SysUtils, AbDfXlat; type PAb32bit = ^TAb32bit; const BitStreamBufferSize = 16*1024; {===TAbDfInBitStream=================================================} constructor TAbDfInBitStream.Create(aStream : TStream; aOnProgress : TAbProgressStep; aStreamSize : longint); begin {protect against dumb programming mistakes} Assert(aStream <> nil, 'TAbDfInBitStream.Create: Cannot create a bit stream wrapping a nil stream'); {create the ancestor} inherited Create; {save the stream instance, allocate the buffer} FStream := aStream; GetMem(FBuffer, BitStreamBufferSize); {save the on progress handler} if Assigned(aOnProgress) and (aStreamSize > 0) then begin FOnProgress := aOnProgress; //FStreamSize := aStreamSize; FStreamSize := aStream.Size - aStream.Position; end; end; {--------} destructor TAbDfInBitStream.Destroy; begin {if we did some work...} if (FBuffer <> nil) then begin {reposition the underlying stream to the point where we stopped; this position is equal to... the position of the underlying stream, PLUS the number of fake bytes we added, LESS the number of bytes in the buffer, PLUS the position in the buffer, PLUS the number of complete bytes in the bit buffer} FStream.Seek(FStream.Position + FFakeCount - (FBufEnd - FBuffer) + (FBufPos - FBuffer) - (FBitsLeft div 8), soBeginning); {free the buffer} FreeMem(FBuffer); end; {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfInBitStream.AlignToByte; begin {get rid of the odd bits by shifting them out of the bit cache} FBitBuffer := FBitBuffer shr (FBitsLeft mod 8); dec(FBitsLeft, FBitsLeft mod 8); end; {--------} procedure TAbDfInBitStream.DiscardBits(aCount : integer); var BitsToGo : integer; begin {aCount comes from a (possibly corrupt) stream, so check that it is the correct range, 1..32} if (aCount <= 0) or (aCount > 32) then raise EAbInternalInflateError.Create( 'count of bits must be between 1 and 32 inclusive [TAbDfInBitStream.DiscardBits]'); {$IFOPT C+} {verify that the count of bits to discard is less than or equal to the recent count from PeekBits--a programming error} Assert((aCount <= FPeekCount), 'TAbDfInBitStream.DiscardBits: discarding more bits than peeked'); {since we're discarding bits already peeked, reset the peek count} FPeekCount := 0; {$ENDIF} {if we have more than enough bits in our bit buffer, update the bitbuffer and the number of bits left} if (aCount <= FBitsLeft) then begin FBitBuffer := FBitBuffer shr aCount; dec(FBitsLeft, aCount); end {otherwise we shall have to read another integer out of the buffer to satisfy the request} else begin {check that there is data in the buffer, if not it's indicates a corrupted stream: PeekBits should have filled it} if (FBufPos = FBufEnd) then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.DiscardBits]'); {refill the bit buffer} BitsToGo := aCount - FBitsLeft; FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := FBitBuffer shr BitsToGo; FBitsLeft := 32 - BitsToGo; end; end; {--------} procedure TAbDfInBitStream.DiscardMoreBits(aCount : integer); var BitsToGo : integer; begin {aCount comes from a (possibly corrupt) stream, so check that it is the correct range, 1..32} if (aCount <= 0) or (aCount > 32) then raise EAbInternalInflateError.Create( 'count of bits must be between 1 and 32 inclusive [TAbDfInBitStream.DiscardMoreBits]'); {$IFOPT C+} {verify that the count of bits to discard is less than or equal to the recent count from PeekBits--a programming error} Assert((aCount <= FPeekCount), 'TAbDfInBitStream.DiscardBits: discarding more bits than peeked'); {since we're discarding bits already peeked, reset the peek count} FPeekCount := 0; {$ENDIF} {check that there is data in the buffer, if not it's indicates a corrupted stream: PeekBits/PeekMoreBits should have filled it} if (FBufPos = FBufEnd) then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.DiscardBits]'); {refill the bit buffer} BitsToGo := aCount - FBitsLeft; FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := FBitBuffer shr BitsToGo; FBitsLeft := 32 - BitsToGo; end; {--------} function TAbDfInBitStream.ibsFillBuffer : boolean; var BytesRead : longint; BytesToRead : longint; i : integer; Percent : integer; Buffer : PAnsiChar; BufferCount : integer; begin {check for dumb programming mistakes: this routine should only be called if there are less than 4 bytes unused in the buffer} Assert((FBufEnd - FBufPos) < sizeof(longint), 'TAbDfInBitStream.ibsFillBuffer: the buffer should be almost empty'); {if there are still 1, 2, or three bytes unused, move them to the front of the buffer} Buffer := FBuffer; while (FBufPos <> FBufEnd) do begin Buffer^ := FBufPos^; inc(FBufPos); inc(Buffer); end; {fill the buffer} BytesToRead := BitStreamBufferSize - (Buffer - FBuffer); BytesRead := FStream.Read(Buffer^, BytesToRead); {reset the internal pointers} FBufPos := FBuffer; FBufEnd := Buffer + BytesRead; BufferCount := FBufEnd - FBuffer; {if, as a result of the read, no data is in the buffer, return false; the caller will decide what to do about the problem} if (BufferCount = 0) then Result := false {otherwise there is data to be processed} else begin Result := true; {if we didn't read anything from the stream, we need to make sure that enough buffer is zeroed out so that reading longint values don't produce (dreadfully) bogus values} if (BytesRead = 0) and ((BufferCount mod 4) <> 0) then begin FFakeCount := 4 - (BufferCount mod 4); for i := 0 to pred(FFakeCount) do begin FBufEnd^ := #0; inc(FBufEnd); end; end; {fire the progress event} if Assigned(FOnProgress) then begin inc(FByteCount, BytesRead); Percent := Round((100.0 * FByteCount) / FStreamSize); FOnProgress(Percent); end; end; end; {--------} function TAbDfInBitStream.PeekBits(aCount : integer) : integer; var BitsToGo : integer; TempBuffer : integer; begin {check that aCount is in the correct range 1..32} Assert((0 <= aCount) and (aCount <= 32), 'TAbDfInBitStream.PeekBits: count of bits must be between 1 and 32 inclusive'); {if we have more than enough bits in our bit buffer, return as many as needed} if (aCount <= FBitsLeft) then Result := FBitBuffer and AbExtractMask[aCount] {otherwise we shall have to read another integer out of the buffer to satisfy the request; note that this will fill the stream buffer if required} else begin BitsToGo := aCount - FBitsLeft; Result := FBitBuffer; if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then TempBuffer := 0 else TempBuffer := PAb32bit(FBufPos)^ else TempBuffer := PAb32bit(FBufPos)^; Result := Result + ((TempBuffer and AbExtractMask[BitsToGo]) shl FBitsLeft); end; {$IFOPT C+} {save the number of bits peeked for an assertion check later} FPeekCount := aCount; {$ENDIF} end; {--------} function TAbDfInBitStream.PeekMoreBits(aCount : integer) : integer; var BitsToGo : integer; TempBuffer : integer; begin BitsToGo := aCount - FBitsLeft; Result := FBitBuffer; if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then TempBuffer := 0 else TempBuffer := PAb32bit(FBufPos)^ else TempBuffer := PAb32bit(FBufPos)^; Result := Result + ((TempBuffer and AbExtractMask[BitsToGo]) shl FBitsLeft); end; {--------} function TAbDfInBitStream.ReadBit : boolean; begin if (FBitsLeft = 0) then begin if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.ReadBit]'); FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); FBitsLeft := 32; end; Result := Odd(FBitBuffer); FBitBuffer := FBitBuffer shr 1; dec(FBitsLeft); end; {--------} function TAbDfInBitStream.ReadBits(aCount : integer) : integer; var BitsToGo : integer; begin {aCount comes from a (possibly corrupt) stream, so check that it is the correct range, 1..16} if (aCount <= 0) or (aCount > 16) then raise EAbInternalInflateError.Create( 'count of bits must be between 1 and 16 inclusive [TAbDfInBitStream.ReadBits]'); {if we have more than enough bits in our bit buffer, return as many as needed, and update the bitbuffer and the number of bits left} if (aCount <= FBitsLeft) then begin Result := FBitBuffer and AbExtractMask[aCount]; FBitBuffer := FBitBuffer shr aCount; dec(FBitsLeft, aCount); end {if we have exactly enough bits in our bit buffer, return them all, and update the bitbuffer and the number of bits left} else if (aCount = FBitsLeft) then begin Result := FBitBuffer; FBitBuffer := 0; FBitsLeft := 0; end {otherwise we shall have to read another integer out of the buffer to satisfy the request} else begin BitsToGo := aCount - FBitsLeft; Result := FBitBuffer; if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.ReadBits]'); FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); Result := Result + ((FBitBuffer and AbExtractMask[BitsToGo]) shl FBitsLeft); FBitBuffer := FBitBuffer shr BitsToGo; FBitsLeft := 32 - BitsToGo; end; end; {--------} procedure TAbDfInBitStream.ReadBuffer(var aBuffer; aCount : integer); var i : integer; Buffer : PAnsiChar; BytesToRead : integer; BytesInBuffer : integer; begin {this method is designed to read a set of bytes and this can only be done if the stream has been byte aligned--if it isn't, it's a programming error} Assert((FBitsLeft mod 8) = 0, 'TAbDfInBitStream.ReadBuffer. cannot read a buffer unless the stream is byte-aligned'); {get the address of the user buffer as a PChar: easier arithmetic} Buffer := @aBuffer; {if we have some bits left in the bit buffer, we need to copy those first} if (FBitsLeft > 0) then begin BytesToRead := FBitsLeft div 8; for i := 0 to pred(BytesToRead) do begin Buffer^ := AnsiChar(FBitBuffer and $FF); inc(Buffer); FBitBuffer := FBitBuffer shr 8; end; {calculate the count of bytes still to read} dec(aCount, BytesToRead); end; {calculate the number of bytes to copy} BytesInBuffer := FBufEnd - FBufPos; if (aCount <= BytesInBuffer) then BytesToRead := aCount else BytesToRead := BytesInBuffer; {copy the data from our buffer to the user buffer} Move(FBufPos^, Buffer^, BytesToRead); {update variables} dec(aCount, BytesToRead); inc(FBufPos, BytesToRead); {while there is still data to copy, keep on filling our internal buffer and copy it to the user buffer} while (aCount <> 0) do begin {increment the user buffer pointer past the data just copied} inc(Buffer, BytesToRead); {fill our buffer} if not ibsFillBuffer then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.ReadBuffer]'); {calculate the number of bytes to copy} BytesInBuffer := FBufEnd - FBufPos; if (aCount <= BytesInBuffer) then BytesToRead := aCount else BytesToRead := BytesInBuffer; {copy the data from our buffer to the user buffer} Move(FBufPos^, Buffer^, BytesToRead); {update variables} dec(aCount, BytesToRead); inc(FBufPos, BytesToRead); end; {now we've copied everything over, reset the bit variables: they're empty and need refilling} FBitBuffer := 0; FBitsLeft := 0; end; {====================================================================} {===TAbDfOutBitStream================================================} constructor TAbDfOutBitStream.Create(aStream : TStream); begin {protect against dumb programming mistakes} Assert(aStream <> nil, 'TAbDfOutBitStream.Create: Cannot create a bit stream wrapping a nil stream'); {create the ancestor} inherited Create; {save the stream instance, allocate the buffer} FStream := aStream; GetMem(FBuffer, BitStreamBufferSize); FBufEnd := FBuffer + BitStreamBufferSize; FBufPos := FBuffer; end; {--------} destructor TAbDfOutBitStream.Destroy; var i : integer; begin {if the buffer was allocated...} if (FBuffer <> nil) then begin {if there are still some bits in the bit buffer...} if (FBitsUsed <> 0) then begin {pad the bit buffer to a byte boundary} AlignToByte; {empty the main buffer if there isn't enough room to copy over the 1 to 4 bytes in the bit buffer} if ((FBufEnd - FBufPos) < FBitsUsed div 8) then obsEmptyBuffer; {flush the bit buffer} for i := 1 to (FBitsUsed div 8) do begin FBufPos^ := AnsiChar(FBitBuffer); FBitBuffer := FBitBuffer shr 8; inc(FBufPos); end; end; {if there is some data in the main buffer, empty it} if (FBufPos <> FBuffer) then obsEmptyBuffer; {free the buffer} FreeMem(FBuffer); end; {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfOutBitStream.AlignToByte; begin {round up the number of bits used to the nearest 8} FBitsUsed := (FBitsUsed + 7) and $F8; {if the bit buffer is now full, flush it to the main buffer} if (FBitsUsed = 32) then begin if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := 0; FBitsUsed := 0; end; end; {--------} procedure TAbDfOutBitStream.obsEmptyBuffer; var ByteCount : integer; BytesWritten : longint; begin {empty the buffer} ByteCount := FBufPos - FBuffer; BytesWritten := FStream.Write(FBuffer^, ByteCount); {if we couldn't write the correct number of bytes, it's an error} if (BytesWritten <> ByteCount) then raise EAbInternalDeflateError.Create( 'could not write to the output stream [TAbDfInBitStream.obsEmptyBuffer]'); {reset the pointers} FBufPos := FBuffer; end; {--------} function TAbDfOutBitStream.Position : longint; begin Assert(false, 'TAbDfOutBitStream.Position: not implemented yet!'); Result := -1; end; {--------} procedure TAbDfOutBitStream.WriteBit(aBit : boolean); begin {only set the corresponding bit in the bit buffer if the passed bit is set (the bit buffer is set to zero when emptied, so we don't actually have to record clear bits)} if aBit then FBitBuffer := FBitBuffer or (1 shl FBitsUsed); {we've now got one more bit} inc(FBitsUsed); {if the bit buffer is now full, flush it to the main buffer} if (FBitsUsed = 32) then begin if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := 0; FBitsUsed := 0; end; end; {--------} procedure TAbDfOutBitStream.WriteBits(aBits : integer; aCount : integer); begin {protect against programming mistakes...} {..the count should be in the range 1 to 16 (BTW, the latter is only used once: Deflate64 with length symbol 258)} Assert((0 < aCount) and (aCount <= 16), 'TAbDfOutBitStream.WriteBits: aCount should be from 1 to 16'); {..there shouldn't be more than aCount bits} Assert((aBits shr aCount) = 0, 'TAbDfOutBitStream.WriteBits: aBits has more than aCount bits'); {copy as many bits as we can to the bit buffer} FBitBuffer := FBitBuffer or (aBits shl FBitsUsed); {increment the number of bits used} inc(FBitsUsed, aCount); {if we've overshot...} if (FBitsUsed >= 32) then begin {the bit buffer is now full, so flush it} if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); {patch up the bit buffer and the number of bits used} dec(FBitsUsed, 32); FBitBuffer := aBits shr (aCount - FBitsUsed); end; end; {--------} procedure TAbDfOutBitStream.WriteBuffer(var aBuffer; aCount : integer); var Buffer : PAnsiChar; BytesToCopy : integer; begin {guard against dumb programming errors: we must be byte aligned} Assert((FBitsUsed and $7) = 0, 'TAbDfOutBitStream.WriteBuffer: must be byte aligned'); {use the user buffer as a PChar} Buffer := @aBuffer; {flush the bit buffer to the underlying stream} while (FBitsUsed <> 0) do begin if (FBufEnd = FBufPos) then obsEmptyBuffer; FBufPos^ := AnsiChar(FBitBuffer and $FF); inc(FBufPos); FBitBuffer := FBitBuffer shr 8; dec(FBitsUsed, 8); end; {copy over the data to the underlying stream} BytesToCopy := FBufEnd - FBufPos; if (BytesToCopy > aCount) then BytesToCopy := aCount; Move(Buffer^, FBufPos^, BytesToCopy); inc(FBufPos, BytesToCopy); dec(aCount, BytesToCopy); while (aCount <> 0) do begin inc(Buffer, BytesToCopy); obsEmptyBuffer; BytesToCopy := FBufEnd - FBufPos; if (BytesToCopy > aCount) then BytesToCopy := aCount; Move(Buffer^, FBufPos^, BytesToCopy); inc(FBufPos, BytesToCopy); dec(aCount, BytesToCopy); end; {finish with a flushed buffer} obsEmptyBuffer; end; {--------} procedure TAbDfOutBitStream.WriteMoreBits(aBits : integer; aCount : integer); begin {the bit buffer is now full, so flush it} if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); {patch up the bit buffer and the number of bits used} dec(FBitsUsed, 32); FBitBuffer := aBits shr (aCount - FBitsUsed); end; {====================================================================} {===TAbDfLZStream====================================================} const {Implementation note: this stream size has been chosen so that if the data must be stored, a block size of about 64K will result} StreamSize = 160 * 1024; type PWord = ^word; {--------} constructor TAbDfLZStream.Create(aSlideWin : TAbDfInputWindow; aUseDeflate64 : boolean; aLog : TAbLogger); begin {create the ancestor} inherited Create; {save the sliding window and the logger} FSlideWin := aSlideWin; FUseDeflate64 := aUseDeflate64; FLog := aLog; {create the buckets} New(FDistBuckets); New(FLitBuckets); {create the memory stream, allocate its buffer, position at start} GetMem(FStream, StreamSize); Clear; end; {--------} destructor TAbDfLZStream.Destroy; begin {free the buckets} if (FDistBuckets <> nil) then Dispose(FDistBuckets); if (FLitBuckets <> nil) then Dispose(FLitBuckets); {free the memory stream} if (FStream <> nil) then FreeMem(FStream); {destroy the ancestor} inherited Destroy; end; {--------} {$IFDEF UseLogging} procedure AddLenDistToLog(aLog : TAbLogger; aPosn : longint; aLen : integer; aDist : integer; aOverLap : boolean); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if aOverLap then aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d **overlap**', [aPosn, aLen, aDist])) else aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d', [aPosn, aLen, aDist])); end; {$ENDIF} {--------} function TAbDfLZStream.AddLenDist(aLen : integer; aDist : integer) : boolean; var LenSymbol : integer; DistSymbol : integer; CurPos : PAnsiChar; begin {$IFDEF UseLogging} {log it} if (FLog <> nil) then begin if (aLen > aDist) then AddLenDistToLog(FLog, FSWPos, aLen, aDist, true) else AddLenDistToLog(FLog, FSWPos, aLen, aDist, false); inc(FSWPos, aLen); end; {$ENDIF} {write a length/distance record to the stream} CurPos := FCurPos; CurPos^ := AnsiChar(false); inc(CurPos); PWord(CurPos)^ := word(aLen - 1); inc(CurPos, sizeof(word)); PWord(CurPos)^ := word(aDist - 1); inc(CurPos, sizeof(word)); FCurPos := CurPos; {increment the various counters} inc(FDistCount); inc(FStoredSize, aLen); {convert the length and distance to their symbols} {$IFOPT C+} {if Assertions are on} LenSymbol := AbSymbolTranslator.TranslateLength(aLen); DistSymbol := AbSymbolTranslator.TranslateDistance(aDist); {$ELSE} if (3 <= aLen) and (aLen <= 258) then LenSymbol := AbSymbolTranslator.LenSymbols[aLen-3] + 257 else LenSymbol := 285; if (aDist <= 256) then DistSymbol := AbSymbolTranslator.ShortDistSymbols[aDist - 1] else if (aDist <= 32768) then DistSymbol := AbSymbolTranslator.MediumDistSymbols[((aDist - 1) div 128) - 2] else DistSymbol := AbSymbolTranslator.LongDistSymbols[((aDist - 1) div 16384) - 2]; {$ENDIF} {increment the buckets} inc(FLitBuckets^[LenSymbol]); inc(FDistBuckets^[DistSymbol]); {return whether the stream is full and needs encoding} Result := lzsIsFull; end; {--------} {$IFDEF UseLogging} procedure AddLiteralToLog(aLog : TAbLogger; aPosn : longint; aCh : AnsiChar); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if (' ' < aCh) and (aCh <= '~') then aLog.WriteLine(Format('%8x Char: %3d $%2x [%s]', [aPosn, ord(aCh), ord(aCh), aCh])) else aLog.WriteLine(Format('%8x Char: %3d $%2x', [aPosn, ord(aCh), ord(aCh)])); end; {$ENDIF} {--------} function TAbDfLZStream.AddLiteral(aCh : AnsiChar) : boolean; var CurPos : PAnsiChar; begin {$IFDEF UseLogging} {log it} if (FLog <> nil) then begin AddLiteralToLog(FLog, FSWPos, aCh); inc(FSWPos); end; {$ENDIF} {write a literal to the internal stream} CurPos := FCurPos; CurPos^ := AnsiChar(true); inc(CurPos); CurPos^ := aCh; inc(CurPos); FCurPos := CurPos; {increment the various counters} inc(FLitCount); inc(FLitBuckets^[byte(aCh)]); inc(FStoredSize); {return whether the stream is full and needs encoding} Result := lzsIsFull; end; {--------} procedure TAbDfLZStream.Clear; begin {position the stream at the start} Rewind; {reset all variables} FStrmEnd := nil; FLitCount := 0; FDistCount := 0; FStartOfs := FSlideWin.Position; FStoredSize := 0; {$IFDEF UseLogging} FSWPos := FStartOfs; {$ENDIF} {reset the buckets} FillChar(FLitBuckets^, sizeof(FLitBuckets^), 0); FLitBuckets^[256] := 1; { end-of-block marker: it's always there...} FillChar(FDistBuckets^, sizeof(FDistBuckets^), 0); end; {--------} procedure TAbDfLZStream.Encode(aBitStrm : TAbDfOutBitStream; aLitTree : TAbDfDecodeHuffmanTree; aDistTree : TAbDfDecodeHuffmanTree; aUseDeflate64 : boolean); var Len : integer; Dist : integer; Symbol : integer; CurPos : PAnsiChar; StrmEnd : PAnsiChar; Code : longint; ExtraBits : longint; begin {rewind the LZ77 stream} Rewind; {for speed use local variables} CurPos := FCurPos; StrmEnd := FStrmEnd; {while there are still items in the stream...} while (CurPos < StrmEnd) do begin {if the next item is a literal...} if boolean(CurPos^) then begin {encode the literal character as a symbol} inc(CurPos); {$IFOPT C+} {if Assertions are on} Code := aLitTree.Encode(byte(CurPos^)); {$ELSE} Code := aLitTree.Encodes^[byte(CurPos^)]; {$ENDIF} inc(CurPos); {write the code out to the bit stream} {$IFOPT C+} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Code and $FFFF) shl BitsUsed); BitsUsed := BitsUsed + ((Code shr 16) and $FF); if (BitsUsed >= 32) then WriteMoreBits(Code and $FFFF, (Code shr 16) and $FF); end; {$ENDIF} end {otherwise it's a length/distance pair} else begin {DO THE LENGTH FIRST-------------------------------------------} {get the length from the stream} inc(CurPos); Len := integer(PWord(CurPos)^) + 1; inc(CurPos, sizeof(word)); {translate it to a symbol and convert that to a code using the literal/length huffman tree} {$IFOPT C+} {if Assertions are on} Symbol := AbSymbolTranslator.TranslateLength(Len); Code := aLitTree.Encode(Symbol); {$ELSE} if (3 <= Len) and (Len <= 258) then Symbol := AbSymbolTranslator.LenSymbols[Len-3] + 257 else Symbol := 285; Code := aLitTree.Encodes^[Symbol]; {$ENDIF} {output the length code} {$IFOPT C+} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Code and $FFFF) shl BitsUsed); BitsUsed := BitsUsed + ((Code shr 16) and $FF); if (BitsUsed >= 32) then WriteMoreBits(Code and $FFFF, (Code shr 16) and $FF); end; {$ENDIF} {if the length symbol were 285, its definition changes from Deflate to Deflate64, so make it a special case: for Deflate there are no extra bits, for Deflate64 output the (length - 3) as 16 bits} if (Symbol = 285) then begin if aUseDeflate64 then begin {$IFOPT C+} aBitStrm.WriteBits(Len - 3, 16); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Len - 3) shl BitsUsed); BitsUsed := BitsUsed + 16; if (BitsUsed >= 32) then WriteMoreBits(Len - 3, 16); end; {$ENDIF} end; end {otherwise if there are extra bits to be output for this length, calculate them and output them} else begin ExtraBits := Code shr 24; if (ExtraBits <> 0) then begin {$IFOPT C+} aBitStrm.WriteBits((Len - dfc_LengthBase[Symbol - 257]), ExtraBits); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Len - dfc_LengthBase[Symbol - 257]) shl BitsUsed); BitsUsed := BitsUsed + ExtraBits; if (BitsUsed >= 32) then WriteMoreBits((Len - dfc_LengthBase[Symbol - 257]), ExtraBits); end; {$ENDIF} end; end; {DO THE DISTANCE NEXT------------------------------------------} {get the distance from the stream} Dist := integer(PWord(CurPos)^) + 1; inc(CurPos, sizeof(word)); {translate it to a symbol and convert that to a code using the distance huffman tree} {$IFOPT C+} {if Assertions are on} Symbol := AbSymbolTranslator.TranslateDistance(Dist); Assert(aUseDeflate64 or (Symbol < 30), 'TAbDfLZStream.Encode: a Deflate64 distance symbol has been generated for Deflate'); Code := aDistTree.Encode(Symbol); {$ELSE} if (Dist <= 256) then Symbol := AbSymbolTranslator.ShortDistSymbols[Dist - 1] else if (Dist <= 32768) then Symbol := AbSymbolTranslator.MediumDistSymbols[((Dist - 1) div 128) - 2] else Symbol := AbSymbolTranslator.LongDistSymbols[((Dist - 1) div 16384) - 2]; Code := aDistTree.Encodes^[Symbol]; {$ENDIF} {output the distance code} {$IFOPT C+} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Code and $FFFF) shl BitsUsed); BitsUsed := BitsUsed + ((Code shr 16) and $FF); if (BitsUsed >= 32) then WriteMoreBits(Code and $FFFF, (Code shr 16) and $FF); end; {$ENDIF} {if there are extra bits to be output for this distance, calculate them and output them} ExtraBits := Code shr 24; if (ExtraBits <> 0) then begin {$IFOPT C+} aBitStrm.WriteBits((Dist - dfc_DistanceBase[Symbol]), ExtraBits); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Dist - dfc_DistanceBase[Symbol]) shl BitsUsed); BitsUsed := BitsUsed + ExtraBits; if (BitsUsed >= 32) then WriteMoreBits((Dist - dfc_DistanceBase[Symbol]), ExtraBits); end; {$ENDIF} end; end; end; {clear the stream; ready for some more items} { Clear;} end; {--------} function TAbDfLZStream.lzsGetApproxSize : LongWord; var i : integer; begin {note: calculates an approximate compressed size without taking too long about it. The average encoded bit length for literals and lengths is assumed to be 8. Distances are assumed to follow the static tree definition (ie, 5 bits per distance, plus any extra bits). There are FLitCount literals, FDistCount lengths, and FDistCount distances} Result := (13 * FDistCount) + (8 * FLitCount); for i := 4 to 31 do inc(Result, FDistBuckets^[i] * dfc_DistExtraBits[i]); Result := Result div 8; end; {--------} function TAbDfLZStream.lzsGetStaticSize : integer; var i : integer; begin Result := 0; for i := 0 to 143 do inc(Result, FLitBuckets^[i] * 8); for i := 144 to 255 do inc(Result, FLitBuckets^[i] * 9); inc(Result, FLitBuckets^[256] * 7); for i := 257 to 279 do inc(Result, FLitBuckets^[i] * (7 + dfc_LitExtraBits[i - dfc_LitExtraOffset])); for i := 280 to 284 do inc(Result, FLitBuckets^[i] * (8 + dfc_LitExtraBits[i - dfc_LitExtraOffset])); if FUseDeflate64 then inc(Result, FLitBuckets^[285] * (8 + 16)) else inc(Result, FLitBuckets^[285] * 8); for i := 0 to 31 do inc(Result, FDistBuckets^[i] * (5 + dfc_DistExtraBits[i])); end; {--------} function TAbDfLZStream.lzsGetStoredSize : integer; begin Result := FStoredSize; {Result := FSlideWin.Position - FStartOfs;} end; {--------} function TAbDfLZStream.lzsIsFull : boolean; begin {if the number of hits on the (eventual) literal tree is a multiple of 8192, the stream is full if the majority were straight literals and we're getting approx 50% compression} if (((FLitCount + FDistCount) and $1FFF) = 0) then begin Result := (FDistCount < FLitCount) and (lzsGetApproxSize < (FStoredSize div 2)); if Result then Exit; end; {otherwise the stream is full if the number of hits on the literal tree or on the distance tree is 32768} { Result := (FCurPos - FStream) > (StreamSIze - 100);} Result := (FDistCount >= 32768) or ((FLitCount + FDistCount) >= 32768); end; {--------} procedure TAbDfLZStream.ReadStoredBuffer(var aBuffer; aCount : integer); begin FSlideWin.ReadBuffer(aBuffer, aCount, FStartOfs); inc(FStartOfs, aCount); end; {--------} procedure TAbDfLZStream.Rewind; begin {position the stream at the beginning} FStrmEnd := FCurPos; FCurPos := FStream; end; {====================================================================} {===TAbDfCodeLenStream===============================================} constructor TAbDfCodeLenStream.Create(aLog : TAbLogger); begin {create the ancestor} inherited Create; {allocate the stream (to contain all literals and distances and possible extra data} GetMem(FStream, (285 + 32) * 2); FPosition := FStream; {allocate the buckets} FBuckets := AllocMem(sizeof(TAbDfCodeLenBuckets)); end; {--------} destructor TAbDfCodeLenStream.Destroy; begin {free the stream} if (FStream <> nil) then FreeMem(FStream); {free the buckets} if (FBuckets <> nil) then Dispose(FBuckets); {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfCodeLenStream.Build(const aCodeLens : array of integer; aCount : integer); var i : integer; State : (ScanStart, ScanNormal, Got2nd, Got3rd); Count : integer; ThisCount : integer; CodeLen : integer; PrevCodeLen : integer; CurPos : PAnsiChar; Buckets : PAbDfCodeLenBuckets; begin {start the automaton} State := ScanStart; CurPos := FStream; Buckets := FBuckets; Count := 0; PrevCodeLen := 0; {for all the codelengths in the array (plus a fake one at the end to ensure all codeslengths are counted)...} for i := 0 to aCount do begin {get the current codelength} if (i = aCount) then CodeLen := -1 else CodeLen := aCodeLens[i]; {switch based on the state...} case State of ScanStart : begin PrevCodeLen := CodeLen; State := ScanNormal; end; ScanNormal : begin {if the current code is the same as the previous, move to the next state} if (CodeLen = PrevCodeLen) then State := Got2nd {otherwise output the previous code} else begin CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen]); PrevCodeLen := CodeLen; end; end; Got2nd : begin {if the current code is the same as the previous, move to the next state; we now have three similar codes in a row} if (CodeLen = PrevCodeLen) then begin State := Got3rd; Count := 3; end {otherwise output the previous two similar codes, move back to the initial state} else begin CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen], 2); PrevCodeLen := CodeLen; State := ScanNormal; end; end; Got3rd: begin {if the current code is the same as the previous, increment the count of similar codes} if (CodeLen = PrevCodeLen) then inc(Count) {otherwise we need to output the repeat values...} else begin {if the previous code were a zero code...} if (PrevCodeLen = 0) then begin {while there are zero codes to be output...} while (Count <> 0) do begin {if there are less than three zero codes, output them individually} if (Count < 3) then begin while (Count <> 0) do begin CurPos^ := #0; inc(CurPos); inc(Buckets^[0]); dec(Count); end; end {if there are less than 11 successive zero codes, output a 17 code and the count of zeros} else if (Count < 11) then begin CurPos^ := #17; inc(CurPos); inc(Buckets^[17]); CurPos^ := AnsiChar(Count - 3); inc(CurPos); Count := 0; end {otherwise output an 18 code and the count of zeros} else begin ThisCount := Count; if (ThisCount > 138) then ThisCount := 138; CurPos^ := #18; inc(CurPos); inc(Buckets^[18]); CurPos^ := AnsiChar(ThisCount - 11); inc(CurPos); dec(Count, ThisCount); end; end; end {otherwise the previous code was a non-zero code...} else begin {output the first code} CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen]); dec(Count); {while there are more codes to be output...} while (Count <> 0) do begin {if there are less than three codes, output them individually} if (Count < 3) then begin while (Count <> 0) do begin CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen]); dec(Count); end; end {otherwise output an 16 code and the count} else begin ThisCount := Count; if (ThisCount > 6) then ThisCount := 6; CurPos^ := #16; inc(CurPos); inc(Buckets^[16]); CurPos^ := AnsiChar(ThisCount - 3); inc(CurPos); dec(Count, ThisCount); end; end; end; {move back to the initial state} PrevCodeLen := CodeLen; State := ScanNormal; end; end; end; end; {set the read position} FStrmEnd := CurPos; FPosition := FStream; end; {--------} procedure TAbDfCodeLenStream.Encode(aBitStrm : TAbDfOutBitStream; aTree : TAbDfDecodeHuffmanTree); var Symbol : integer; ExtraData : integer; Code : longint; CurPos : PAnsiChar; StrmEnd : PAnsiChar; begin {prepare for the loop} CurPos := FPosition; StrmEnd := FStrmEnd; {while there are tokens in the stream...} while (CurPos <> StrmEnd) do begin {get the next symbol} Symbol := ord(CurPos^); inc(CurPos); {if the symbol is 0..15, get the code and output it} if (Symbol <= 15) then begin {$IFOPT C+} {if Assertions are on} Code := aTree.Encode(Symbol); {$ELSE} Code:= aTree.Encodes^[Symbol]; {$ENDIF} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); end {otherwise the symbol is 16, 17, or 18} else begin {get the extra data} ExtraData := ord(CurPos^); inc(CurPos); {get the code and output it} {$IFOPT C+} {if Assertions are on} Code := aTree.Encode(Symbol); {$ELSE} Code:= aTree.Encodes^[Symbol]; {$ENDIF} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); if (Symbol = 16) then aBitStrm.WriteBits(ExtraData, 2) else if (Symbol = 17) then aBitStrm.WriteBits(ExtraData, 3) else {Symbol = 18} aBitStrm.WriteBits(ExtraData, 7); end; end; end; {====================================================================} end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abdfxlat.pas�����������������������������������������0000644�0001750�0000144�00000013032�14743153644�022721� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfXlat.pas *} {*********************************************************} {* Deflate length/dist to symbol translator *} {*********************************************************} unit AbDfXlat; {$I AbDefine.inc} interface uses SysUtils; type TAbDfTranslator = class private FBuffer : PAnsiChar; FLenSymbols : PByteArray; {for lengths 3..258} FLongDistSymbols : PByteArray; {for distances 32769..65536 (deflate64)} FMediumDistSymbols : PByteArray; {for distances 257..32768} FShortDistSymbols : PByteArray; {for distances 1..256} protected procedure trBuild; public constructor Create; destructor Destroy; override; function TranslateLength(aLen : integer): integer; function TranslateDistance(aDist : integer) : integer; property LenSymbols : PByteArray read FLenSymbols; property LongDistSymbols : PByteArray read FLongDistSymbols; property MediumDistSymbols : PByteArray read FMediumDistSymbols; property ShortDistSymbols : PByteArray read FShortDistSymbols; end; var AbSymbolTranslator : TAbDfTranslator; implementation uses AbDfBase; {====================================================================} constructor TAbDfTranslator.Create; begin {create the ancestor} inherited Create; {allocate the translation arrays (the buffer *must* be zeroed)} FBuffer := AllocMem(256 + 2 + 256 + 256); FLenSymbols := PByteArray(FBuffer); FLongDistSymbols := PByteArray(FBuffer + 256); FMediumDistSymbols := PByteArray(FBuffer + 256 + 2); FShortDistSymbols := PByteArray(FBuffer + 256 + 2 + 256); {build the translation arrays} trBuild; end; {--------} destructor TAbDfTranslator.Destroy; begin if (FBuffer <> nil) then FreeMem(FBuffer); inherited Destroy; end; {--------} function TAbDfTranslator.TranslateDistance(aDist : integer) : integer; begin {save against dumb programming mistakes} Assert((1 <= aDist) and (aDist <= 65536), 'TAbDfTranslator.Translate: distance should be 1..65536'); {translate the distance} if (aDist <= 256) then Result := FShortDistSymbols[aDist - 1] else if (aDist <= 32768) then Result := FMediumDistSymbols[((aDist - 1) div 128) - 2] else Result := FLongDistSymbols[((aDist - 1) div 16384) - 2]; end; {--------} function TAbDfTranslator.TranslateLength(aLen : integer): integer; begin {save against dumb programming mistakes} Assert((3 <= aLen) and (aLen <= 65536), 'TAbDfTranslator.Translate: length should be 3..65536'); {translate the length} dec(aLen, 3); if (0 <= aLen) and (aLen <= 255) then Result := FLenSymbols[aLen] + 257 else Result := 285; end; {--------} procedure TAbDfTranslator.trBuild; var i : integer; Len : integer; Dist : integer; Value : integer; begin {initialize the length translation array; elements will contain (Symbol - 257) for a given (length - 3)} for i := low(dfc_LengthBase) to pred(high(dfc_LengthBase)) do begin Len := dfc_LengthBase[i] - 3; FLenSymbols[Len] := i; end; FLenSymbols[255] := 285 - 257; Value := -1; for i := 0 to 255 do begin if (Value < FLenSymbols[i]) then Value := FLenSymbols[i] else FLenSymbols[i] := Value; end; {initialize the short distance translation array: it will contain the Symbol for a given (distance - 1) where distance <= 256} for i := 0 to 15 do begin Dist := dfc_DistanceBase[i] - 1; FShortDistSymbols[Dist] := i; end; Value := -1; for i := 0 to 255 do begin if (Value < FShortDistSymbols[i]) then Value := FShortDistSymbols[i] else FShortDistSymbols[i] := Value; end; {initialize the medium distance translation array: it will contain the Symbol for a given (((distance - 1) div 128) - 2) where distance is in the range 256..32768} for i := 16 to 29 do begin Dist := ((dfc_DistanceBase[i] - 1) div 128) - 2; FMediumDistSymbols[Dist] := i; end; Value := -1; for i := 0 to 255 do begin if (Value < FMediumDistSymbols[i]) then Value := FMediumDistSymbols[i] else FMediumDistSymbols[i] := Value; end; {initialize the long distance translation array: it will contain the Symbol for a given ((distance - 1) div 16384) - 2) for distances over 32768 in deflate64} FLongDistSymbols[0] := 30; FLongDistSymbols[1] := 31; end; {====================================================================} initialization AbSymbolTranslator := TAbDfTranslator.Create; finalization AbSymbolTranslator.Free; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abexcept.pas�����������������������������������������0000644�0001750�0000144�00000042327�14743153644�022740� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbExcept.pas *} {*********************************************************} {* ABBREVIA: Exception classes *} {*********************************************************} unit AbExcept; {$I AbDefine.inc} interface uses SysUtils, AbUtils; type EAbException = class( Exception ) public ErrorCode : Integer; end; EAbArchiveBusy = class( EAbException ) public constructor Create; end; EAbBadStream = class( EAbException ) protected FInnerException : Exception; public constructor Create; constructor CreateInner(aInnerException : Exception); property InnerException : Exception read FInnerException; end; EAbDuplicateName = class( EAbException ) public constructor Create; end; EAbFileNotFound = class( EAbException ) public constructor Create; end; EAbNoArchive = class( EAbException ) public constructor Create; end; EAbUserAbort = class( EAbException ) public constructor Create; end; EAbNoSuchDirectory = class( EAbException ) public constructor Create; end; EAbUnhandledType = class( EAbException ) public constructor Create; end; EAbSpanningNotSupported = class (EAbException) public constructor Create; end; EAbInvalidSpanningThreshold = class ( EAbException ) public constructor Create; end; EAbZipException = class( EAbException ); {Zip exception} EAbCabException = class( EAbException ); {Cab exception} EAbTarException = class( EAbException ); {Tar Exception} EAbGzipException = class( EAbException); {GZip exception} EAbZipBadSpanStream = class( EAbZipException ) public constructor Create; end; EAbZipBadCRC = class( EAbZipException ) public constructor Create; end; EAbZipInflateBlock = class( EAbZipException ) public constructor Create; end; EAbZipInvalid = class( EAbZipException ) public constructor Create; end; EAbInvalidIndex = class( EAbZipException ) public constructor Create; end; EAbZipInvalidFactor = class( EAbZipException ) public constructor Create; end; EAbZipInvalidLFH = class( EAbZipException ) public constructor Create; end; EAbZipInvalidMethod = class( EAbZipException ) public constructor Create; end; EAbZipInvalidPassword = class( EAbZipException ) public constructor Create; end; EAbZipInvalidStub= class( EAbZipException ) public constructor Create; end; EAbZipNoExtraction = class( EAbZipException ) public constructor Create; end; EAbZipNoInsertion = class( EAbZipException ) public constructor Create; end; EAbZipSpanOverwrite= class( EAbZipException ) public constructor Create; end; EAbZipStreamFull = class( EAbZipException ) public constructor Create; end; EAbZipTruncate = class( EAbZipException ) public constructor Create; end; EAbZipUnsupported = class( EAbZipException ) public constructor Create; end; EAbZipVersion = class( EAbZipException ) public constructor Create; end; EAbReadError = class( EAbZipException ) public constructor Create; end; EAbGzipBadCRC = class( EAbGZipException ) public constructor Create; end; EAbGzipBadFileSize = class( EAbGZipException ) public constructor Create; end; EAbGzipInvalid = class( EAbGZipException ) public constructor Create; end; EAbTarInvalid = class( EAbTarException) public constructor Create; end; EAbTarBadFileName = class( EAbTarException) public constructor Create; end; EAbTarBadLinkName = class( EAbTarException) public constructor Create; end; EAbTarBadOp = class( EAbTarException) public constructor Create; end; EAbVMSInvalidOrigin = class( EAbZipException ) public constructor Create( Value : Integer ); end; EAbVMSErrorOpenSwap = class( EAbZipException ) public constructor Create( const Value : string ); end; EAbVMSSeekFail = class( EAbZipException ) public constructor Create( const Value : string ); end; EAbVMSReadFail = class( EAbZipException ) public constructor Create( Count : Integer; const Value : string ); end; EAbVMSWriteFail = class( EAbZipException ) public constructor Create( Count : Integer; const Value : string ); end; EAbVMSWriteTooManyBytes = class( EAbZipException ) public constructor Create( Count : Integer ); end; EAbBBSReadTooManyBytes = class( EAbZipException ) public constructor Create(Count : Integer ); end; EAbBBSSeekOutsideBuffer = class( EAbZipException ) public constructor Create; end; EAbBBSInvalidOrigin = class( EAbZipException ) public constructor Create; end; EAbBBSWriteTooManyBytes = class( EAbZipException ) public constructor Create(Count : Integer ); end; EAbSWSNotEndofStream = class( EAbZipException ) public constructor Create; end; EAbSWSSeekFailed = class( EAbZipException ) public constructor Create; end; EAbSWSWriteFailed = class( EAbZipException ) public constructor Create; end; EAbSWSInvalidOrigin = class( EAbZipException ) public constructor Create; end; EAbSWSInvalidNewOrigin = class( EAbZipException ) public constructor Create; end; EAbNoCabinetDll = class( EAbCabException ) public constructor Create; end; EAbFCIFileOpenError = class( EAbCabException ) public constructor Create; end; EAbFCIFileReadError = class( EAbCabException ) public constructor Create; end; EAbFCIFileWriteError = class( EAbCabException ) public constructor Create; end; EAbFCIFileCloseError = class( EAbCabException ) public constructor Create; end; EAbFCIFileSeekError = class( EAbCabException ) public constructor Create; end; EAbFCIFileDeleteError = class( EAbCabException ) public constructor Create; end; EAbFCIAddFileError = class( EAbCabException ) public constructor Create; end; EAbFCICreateError = class( EAbCabException ) public constructor Create; end; EAbFCIFlushCabinetError = class( EAbCabException ) public constructor Create; end; EAbFCIFlushFolderError = class( EAbCabException ) public constructor Create; end; EAbFDICopyError = class( EAbCabException ) public constructor Create; end; EAbFDICreateError = class( EAbCabException ) public constructor Create; end; EAbInvalidCabTemplate = class( EAbCabException ) public constructor Create; end; EAbInvalidCabFile = class( EAbCabException ) public constructor Create; end; EAbFileTooLarge = class(EAbException) public constructor Create; end; procedure AbConvertException( const E : Exception; var eClass : TAbErrorClass; var eErrorCode : Integer ); implementation uses Classes, AbConst, AbResString; constructor EAbArchiveBusy.Create; begin inherited Create(AbArchiveBusyS); ErrorCode := AbArchiveBusy; end; constructor EAbBadStream.Create; begin inherited Create(AbBadStreamTypeS); FInnerException := nil; ErrorCode := AbBadStreamType; end; constructor EAbBadStream.CreateInner(aInnerException: Exception); begin inherited Create(AbBadStreamTypeS + #13#10 + aInnerException.Message); FInnerException := aInnerException; ErrorCode := AbBadStreamType; end; constructor EAbDuplicateName.Create; begin inherited Create(AbDuplicateNameS); ErrorCode := AbDuplicateName; end; constructor EAbNoSuchDirectory.Create; begin inherited Create(AbNoSuchDirectoryS); ErrorCode := AbNoSuchDirectory; end; constructor EAbInvalidSpanningThreshold.Create; begin inherited Create(AbInvalidThresholdS); ErrorCode := AbInvalidThreshold; end; constructor EAbFileNotFound.Create; begin inherited Create(AbFileNotFoundS); ErrorCode := AbFileNotFound; end; constructor EAbNoArchive.Create; begin inherited Create(AbNoArchiveS); ErrorCode := AbNoArchive; end; constructor EAbUserAbort.Create; begin inherited Create(AbUserAbortS); ErrorCode := AbUserAbort; end; constructor EAbZipBadSpanStream.Create; begin inherited Create(AbBadSpanStreamS); ErrorCode := AbBadSpanStream; end; constructor EAbZipBadCRC.Create; begin inherited Create(AbZipBadCRCS); ErrorCode := AbZipBadCRC; end; constructor EAbZipInflateBlock.Create; begin inherited Create(AbInflateBlockErrorS); ErrorCode := AbInflateBlockError; end; constructor EAbZipInvalid.Create; begin inherited Create(AbErrZipInvalidS); ErrorCode := AbErrZipInvalid; end; constructor EAbInvalidIndex.Create; begin inherited Create(AbInvalidIndexS); ErrorCode := AbInvalidIndex; end; constructor EAbZipInvalidFactor.Create; begin inherited Create(AbInvalidFactorS); ErrorCode := AbInvalidFactor; end; constructor EAbZipInvalidLFH.Create; begin inherited Create(AbInvalidLFHS); ErrorCode := AbInvalidLFH; end; constructor EAbZipInvalidMethod.Create; begin inherited Create(AbUnknownCompressionMethodS); ErrorCode := AbUnknownCompressionMethod; end; constructor EAbZipInvalidPassword.Create; begin inherited Create(AbInvalidPasswordS); ErrorCode := AbInvalidPassword; end; constructor EAbZipInvalidStub.Create; begin inherited Create(AbZipBadStubS); ErrorCode := AbZipBadStub; end; constructor EAbZipNoExtraction.Create; begin inherited Create(AbNoExtractionMethodS); ErrorCode := AbNoExtractionMethod; end; constructor EAbZipNoInsertion.Create; begin inherited Create(AbNoInsertionMethodS); ErrorCode := AbNoInsertionMethod; end; constructor EAbZipSpanOverwrite.Create; begin inherited Create(AbNoOverwriteSpanStreamS); ErrorCode := AbNoOverwriteSpanStream; end; constructor EAbZipStreamFull.Create; begin inherited Create(AbStreamFullS); ErrorCode := AbStreamFull; end; constructor EAbZipTruncate.Create; begin inherited Create(AbTruncateErrorS); ErrorCode := AbTruncateError; end; constructor EAbZipUnsupported.Create; begin inherited Create(AbUnsupportedCompressionMethodS); ErrorCode := AbUnsupportedCompressionMethod; end; constructor EAbZipVersion.Create; begin inherited Create(AbZipVersionNeededS); ErrorCode := AbZipVersionNeeded; end; constructor EAbReadError.Create; begin inherited Create(AbReadErrorS); ErrorCode := AbReadError; end; constructor EAbVMSInvalidOrigin.Create( Value : Integer ); begin inherited Create(Format(AbVMSInvalidOriginS, [Value])); ErrorCode := AbVMSInvalidOrigin; end; constructor EAbBBSReadTooManyBytes.Create(Count : Integer ); begin inherited Create(Format(AbBBSReadTooManyBytesS, [Count])); ErrorCode := AbBBSReadTooManyBytes; end; constructor EAbBBSSeekOutsideBuffer.Create; begin inherited Create(AbBBSSeekOutsideBufferS); ErrorCode := AbBBSSeekOutsideBuffer; end; constructor EAbBBSInvalidOrigin.Create; begin inherited Create(AbBBSInvalidOriginS); ErrorCode := AbBBSInvalidOrigin; end; constructor EAbBBSWriteTooManyBytes.Create(Count : Integer); begin inherited Create(Format(AbBBSWriteTooManyBytesS, [Count])); ErrorCode := AbBBSWriteTooManyBytes; end; constructor EAbVMSErrorOpenSwap.Create( const Value : string ); begin inherited Create(Format(AbVMSErrorOpenSwapS, [Value])); ErrorCode := AbVMSErrorOpenSwap; end; constructor EAbVMSSeekFail.Create( const Value : string ); begin inherited Create(Format(AbVMSSeekFailS, [Value])); ErrorCode := AbVMSSeekFail; end; constructor EAbVMSReadFail.Create( Count : Integer; const Value : string ); begin inherited Create(Format(AbVMSReadFailS, [Count, Value])); ErrorCode := AbVMSReadFail; end; constructor EAbVMSWriteFail.Create( Count : Integer; const Value : string ); begin inherited Create(Format(AbVMSWriteFailS, [Count, Value])); ErrorCode := AbVMSWriteFail; end; constructor EAbVMSWriteTooManyBytes.Create( Count : Integer ); begin inherited Create(Format(AbVMSWriteTooManyBytesS, [Count])); ErrorCode := AbVMSWriteTooManyBytes; end; constructor EAbSWSNotEndofStream.Create; begin inherited Create(AbSWSNotEndofStreamS); ErrorCode := AbSWSNotEndofStream; end; constructor EAbSWSSeekFailed.Create; begin inherited Create(AbSWSSeekFailedS); ErrorCode := AbSWSSeekFailed; end; constructor EAbSWSWriteFailed.Create; begin inherited Create(AbSWSWriteFailedS); ErrorCode := AbSWSWriteFailed; end; constructor EAbSWSInvalidOrigin.Create; begin inherited Create(AbSWSInvalidOriginS); ErrorCode := AbSWSInvalidOrigin; end; constructor EAbSWSInvalidNewOrigin.Create; begin inherited Create(AbSWSInvalidNewOriginS); ErrorCode := AbSWSInvalidNewOrigin; end; constructor EAbFCIFileOpenError.Create; begin inherited Create(AbFCIFileOpenErrorS); ErrorCode := AbFCIFileOpenError; end; constructor EAbNoCabinetDll.Create; begin inherited Create(AbNoCabinetDllErrorS); ErrorCode := AbNoCabinetDllError; end; constructor EAbFCIFileReadError.Create; begin inherited Create(AbFCIFileReadErrorS); ErrorCode := AbFCIFileReadError; end; constructor EAbFCIFileWriteError.Create; begin inherited Create(AbFCIFileWriteErrorS); ErrorCode := AbFCIFileWriteError; end; constructor EAbFCIFileCloseError.Create; begin inherited Create(AbFCIFileCloseErrorS); ErrorCode := AbFCIFileCloseError; end; constructor EAbFCIFileSeekError.Create; begin inherited Create(AbFCIFileSeekErrorS); ErrorCode := AbFCIFileSeekError; end; constructor EAbFCIFileDeleteError.Create; begin inherited Create(AbFCIFileDeleteErrorS); ErrorCode := AbFCIFileDeleteError; end; constructor EAbFCIAddFileError.Create; begin inherited Create(AbFCIAddFileErrorS); ErrorCode := AbFCIAddFileError; end; constructor EAbFCICreateError.Create; begin inherited Create(AbFCICreateErrorS); ErrorCode := AbFCICreateError; end; constructor EAbFCIFlushCabinetError.Create; begin inherited Create(AbFCIFlushCabinetErrorS); ErrorCode := AbFCIFlushCabinetError; end; constructor EAbFCIFlushFolderError.Create; begin inherited Create(AbFCIFlushFolderErrorS); ErrorCode := AbFCIFlushFolderError; end; constructor EAbFDICopyError.Create; begin inherited Create(AbFDICopyErrorS); ErrorCode := AbFDICopyError; end; constructor EAbFDICreateError.Create; begin inherited Create(AbFDICreateErrorS); ErrorCode := AbFDICreateError; end; constructor EAbInvalidCabTemplate.Create; begin inherited Create(AbInvalidCabTemplateS); ErrorCode := AbInvalidCabTemplate; end; constructor EAbInvalidCabFile.Create; begin inherited Create(AbInvalidCabFileS); ErrorCode := AbInvalidCabFile; end; procedure AbConvertException( const E : Exception; var eClass : TAbErrorClass; var eErrorCode : Integer ); begin eClass := ecOther; eErrorCode := 0; if E is EAbException then begin eClass := ecAbbrevia; eErrorCode := (E as EAbException).ErrorCode; end else if E is EInOutError then begin eClass := ecInOutError; eErrorCode := (E as EInOutError).ErrorCode; end else if E is EFilerError then eClass := ecFilerError else if E is EFOpenError then eClass := ecFileOpenError else if E is EFCreateError then eClass := ecFileCreateError; end; { EAbUnhandledType } constructor EAbUnhandledType.Create; begin inherited Create(AbUnhandledFileTypeS); ErrorCode := AbUnhandledFileType; end; { EAbGzipBadCRC } constructor EAbGzipBadCRC.Create; begin inherited Create(AbGzipBadCRCS); ErrorCode := AbGzipBadCRC; end; { EAbGzipBadFileSize } constructor EAbGzipBadFileSize.Create; begin inherited Create(AbGzipBadFileSizeS); ErrorCode := AbGzipBadFileSize; end; { EAbGzipInvalid } constructor EAbGzipInvalid.Create; begin inherited Create(AbSpanningNotSupportedS); ErrorCode := AbSpanningNotSupported; end; { EAbTarInvalid } constructor EAbTarInvalid.Create; begin inherited Create(AbTarInvalidS); ErrorCode := AbTarInvalid; end; { EAbTarBadFileName } constructor EAbTarBadFileName.Create; begin inherited Create(AbTarBadFileNameS); ErrorCode := AbTarBadFileName; end; { EAbTarBadLinkName } constructor EAbTarBadLinkName.Create; begin inherited Create(AbTarBadLinkNameS); ErrorCode := AbTarBadLinkName; end; { EAbTarBadOp } constructor EAbTarBadOp.Create; begin inherited Create(AbTarBadOpS); ErrorCode := AbTarBadOp; end; { EAbSpanningNotSupported } constructor EAbSpanningNotSupported.Create; begin inherited Create(AbSpanningNotSupportedS); ErrorCode := AbSpanningNotSupported; end; { EAbFileTooLarge } constructor EAbFileTooLarge.Create; begin {TODO Create const and fix wording} inherited Create(AbFileSizeTooBigS); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abgztyp.pas������������������������������������������0000644�0001750�0000144�00000116122�14743153644�022620� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbGzTyp.pas *} {*********************************************************} {* ABBREVIA: TAbGzipArchive, TAbGzipItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with GZip files *} {* See: RFC 1952 *} {* "GZIP file format specification version 4.3" *} {* for more information on GZip *} {* See "algorithm.doc" in Gzip source and "format.txt" *} {* on gzip.org for differences from RFC *} {*********************************************************} unit AbGzTyp; {$I AbDefine.inc} interface uses Classes, AbUtils, AbArcTyp, AbTarTyp; type { pre-defined "operating system" (really more FILE system) types for the Gzip header } TAbGzFileSystem = (osFat, osAmiga, osVMS, osUnix, osVM_CMS, osAtariTOS, osHPFS, osMacintosh, osZSystem, osCP_M, osTOPS20, osNTFS, osQDOS, osAcornRISCOS, osVFAT, osMVS, osBeOS, osTandem, osTHEOS, osUnknown, osUndefined); type PAbGzHeader = ^TAbGzHeader; TAbGzHeader = packed record { SizeOf(TGzHeader) = 10} ID1 : Byte; { ID Byte, should always be $1F} ID2 : Byte; { ID Byte, should always be $8B} CompMethod : Byte; { compression method used} { 0..7 reserved, 8 = deflate, others undefined as of this writing (4/27/2001)} Flags : Byte; { misc flags} { Bit 0: FTEXT compressed file contains text, can be used for} { cross platform line termination translation} { Bit 1: FCONTINUATION file is a continuation of a multi-part gzip file} { RFC 1952 says this is the header CRC16 flag, but gzip} { reserves it and won't extract the file if this is set} { header data includes part number after header record} { Bit 2: FEXTRA header data contains Extra Data, starts after part} { number (if any)} { Bit 3: FNAME header data contains FileName, null terminated} { string starting immediately after Extra Data (if any)} { RFC 1952 says this is ISO 8859-1 encoded, but gzip} { always uses the system encoding} { Bit 4: FCOMMENT header data contains Comment, null terminated string} { starting immediately after FileName (if any)} { Bit 5: FENCRYPTED file is encrypted using zip-1.9 encryption } { header data contains a 12-byte encryption header } { starting immediately after Comment. Documented in} { "algorithm.doc", but unsupported in gzip} { Bits 6..7 are undefined and reserved as of this writing (8/25/2009)} ModTime : LongInt; { File Modification (Creation) time,} { UNIX cdate format} XtraFlags : Byte; { additional flags} { XtraFlags = 2 -- Deflate compressor used maximum compression algorithm} { XtraFlags = 4 -- Deflate compressor used fastest algorithm} OS : Byte; { Operating system that created file,} { see GZOsToStr routine for values} end; TAbGzTailRec = packed record CRC32 : LongInt; { crc for uncompressed data } ISize : LongWord; { size of uncompressed data } end; TAbGzExtraFieldSubID = array[0..1] of AnsiChar; type TAbGzipExtraField = class(TAbExtraField) private FGZHeader : PAbGzHeader; function GetID(aIndex : Integer): TAbGzExtraFieldSubID; protected procedure Changed; override; public constructor Create(aGZHeader : PAbGzHeader); procedure Delete(aID : TAbGzExtraFieldSubID); function Get(aID : TAbGzExtraFieldSubID; out aData : Pointer; out aDataSize : Word) : Boolean; procedure Put(aID : TAbGzExtraFieldSubID; const aData; aDataSize : Word); public property IDs[aIndex : Integer]: TAbGzExtraFieldSubID read GetID; end; TAbGzipItem = class(TAbArchiveItem) protected {private} FGZHeader : TAbGzHeader; FExtraField : TAbGzipExtraField; FFileComment : AnsiString; FRawFileName : AnsiString; protected function GetFileSystem: TAbGzFileSystem; function GetHasExtraField: Boolean; function GetHasFileComment: Boolean; function GetHasFileName: Boolean; function GetIsText: Boolean; procedure SetFileComment(const Value : AnsiString); procedure SetFileSystem(const Value: TAbGzFileSystem); procedure SetIsText(const Value: Boolean); function GetExternalFileAttributes : LongWord; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetLastModTimeAsDateTime: TDateTime; override; function GetNativeLastModFileTime: Longint; override; procedure SetExternalFileAttributes( Value : LongWord ); override; procedure SetFileName(const Value : string); override; procedure SetIsEncrypted(Value : Boolean); override; procedure SetLastModFileDate(const Value : Word); override; procedure SetLastModFileTime(const Value : Word); override; procedure SetLastModTimeAsDateTime(const Value: TDateTime); override; procedure SaveGzHeaderToStream(AStream : TStream); procedure LoadGzHeaderFromStream(AStream : TStream); public property CompressionMethod : Byte read FGZHeader.CompMethod; property ExtraFlags : Byte {Default: 2} read FGZHeader.XtraFlags write FGZHeader.XtraFlags; property Flags : Byte read FGZHeader.Flags; property FileComment : AnsiString read FFileComment write SetFileComment; property FileSystem : TAbGzFileSystem {Default: osFat (Windows); osUnix (Linux)} read GetFileSystem write SetFileSystem; property ExtraField : TAbGzipExtraField read FExtraField; property IsEncrypted : Boolean read GetIsEncrypted; property HasExtraField : Boolean read GetHasExtraField; property HasFileName : Boolean read GetHasFileName; property HasFileComment : Boolean read GetHasFileComment; property IsText : Boolean read GetIsText write SetIsText; property GZHeader : TAbGzHeader read FGZHeader; constructor Create; destructor Destroy; override; end; TAbGzipStreamHelper = class(TAbArchiveStreamHelper) private function GetGzCRC: LongInt; function GetFileSize: LongInt; protected {private} FItem : TAbGzipItem; FTail : TAbGzTailRec; FArchive : TAbArchive; public constructor Create(AStream : TStream); overload; constructor Create(Archive : TAbArchive; AStream : TStream); overload; destructor Destroy; override; procedure ExtractItemData(AStream : TStream); override; function FindFirstItem : Boolean; override; function FindNextItem : Boolean; override; function SeekItem(Index : Integer): Boolean; override; procedure SeekToItemData; procedure WriteArchiveHeader; override; procedure WriteArchiveItem(AStream : TStream); override; procedure WriteArchiveTail; override; function GetItemCount : Integer; override; procedure ReadHeader; override; procedure ReadTail; override; property CRC : LongInt read GetGzCRC; property FileSize : LongInt read GetFileSize; property TailCRC : LongInt read FTail.CRC32; property TailSize : LongWord read FTail.ISize; end; TAbGzipArchiveState = (gsGzip, gsTar); TAbGzipArchive = class(TAbTarArchive) private FGZStream : TStream; { stream for GZip file} FGZItem : TAbArchiveList; { item in Gzip (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbGzipArchiveState; FIsGzippedTar : Boolean; procedure SetTarAutoHandle(const Value: Boolean); function GetIsGzippedTar: Boolean; procedure SwapToGzip; procedure SwapToTar; protected function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const UseName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function FixName(const Value : string) : string; override; function GetSupportsEmptyFolders : Boolean; override; function GetItem(Index: Integer): TAbGzipItem; procedure PutItem(Index: Integer; const Value: TAbGzipItem); public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsGzippedTar : Boolean read GetIsGzippedTar write FIsGzippedTar; property Items[Index : Integer] : TAbGzipItem read GetItem write PutItem; default; end; function VerifyGZip(Strm : TStream) : TAbArchiveType; function GZOsToStr(OS: Byte) : string; implementation uses SysUtils, BufStream, AbBitBkt, AbDfBase, AbDfDec, AbZlibPrc, AbExcept, AbResString, AbProgress, AbVMStrm, DCOSUtils, DCClassesUtf8, DCConvertEncoding; const { Header Signature Values} AB_GZ_HDR_ID1 = $1F; AB_GZ_HDR_ID2 = $8B; { Test bits for TGzHeader.Flags field } AB_GZ_FLAG_FTEXT = $01; AB_GZ_FLAG_FCONTINUATION = $02; AB_GZ_FLAG_FEXTRA = $04; AB_GZ_FLAG_FNAME = $08; AB_GZ_FLAG_FCOMMENT = $10; AB_GZ_FLAG_FENCRYPTED = $20; AB_GZ_UNSUPPORTED_FLAGS = $E2; { GZip OS source flags } AB_GZ_OS_ID_FAT = 0; AB_GZ_OS_ID_Amiga = 1; AB_GZ_OS_ID_VMS = 2; AB_GZ_OS_ID_Unix = 3; AB_GZ_OS_ID_VM_CMS = 4; AB_GZ_OS_ID_AtariTOS = 5; AB_GZ_OS_ID_HPFS = 6; AB_GZ_OS_ID_Macintosh = 7; AB_GZ_OS_ID_Z_System = 8; AB_GZ_OS_ID_CP_M = 9; AB_GZ_OS_ID_TOPS20 = 10; AB_GZ_OS_ID_NTFS = 11; AB_GZ_OS_ID_QDOS = 12; AB_GZ_OS_ID_AcornRISCOS = 13; AB_GZ_OS_ID_VFAT = 14; AB_GZ_OS_ID_MVS = 15; AB_GZ_OS_ID_BEOS = 16; AB_GZ_OS_ID_TANDEM = 17; AB_GZ_OS_ID_THEOS = 18; AB_GZ_OS_ID_unknown = 255; function GZOsToStr(OS: Byte) : string; { Return a descriptive string for TGzHeader.OS field } begin case OS of AB_GZ_OS_ID_FAT : Result := AbGzOsFat; AB_GZ_OS_ID_Amiga : Result := AbGzOsAmiga; AB_GZ_OS_ID_VMS : Result := AbGzOsVMS; AB_GZ_OS_ID_Unix : Result := AbGzOsUnix; AB_GZ_OS_ID_VM_CMS : Result := AbGzOsVM_CMS; AB_GZ_OS_ID_AtariTOS : Result := AbGzOsAtari; AB_GZ_OS_ID_HPFS : Result := AbGzOsHPFS; AB_GZ_OS_ID_Macintosh : Result := AbGzOsMacintosh; AB_GZ_OS_ID_Z_System : Result := AbGzOsZ_System; AB_GZ_OS_ID_CP_M : Result := AbGzOsCP_M; AB_GZ_OS_ID_TOPS20 : Result := AbGzOsTOPS_20; AB_GZ_OS_ID_NTFS : Result := AbGzOsNTFS; AB_GZ_OS_ID_QDOS : Result := AbGzOsQDOS; AB_GZ_OS_ID_AcornRISCOS : Result := AbGzOsAcornRISCOS; AB_GZ_OS_ID_VFAT : Result := AbGzOsVFAT; AB_GZ_OS_ID_MVS : Result := AbGzOsMVS; AB_GZ_OS_ID_BEOS : Result := AbGzOsBeOS; AB_GZ_OS_ID_TANDEM : Result := AbGzOsTandem; AB_GZ_OS_ID_THEOS : Result := AbGzOsTHEOS; AB_GZ_OS_ID_unknown : Result := AbGzOsunknown; else Result := AbGzOsUndefined; end; end; function VerifyHeader(const Header : TAbGzHeader) : Boolean; begin { check id fields and if deflated (only handle deflate anyway)} Result := (Header.ID1 = AB_GZ_HDR_ID1) and (Header.ID2 = AB_GZ_HDR_ID2) and (Header.CompMethod = 8 {deflate}); end; function VerifyGZip(Strm : TStream) : TAbArchiveType; var GHlp : TAbGzipStreamHelper; Hlpr : TAbDeflateHelper; PartialTarData : TMemoryStream; CurPos : Int64; begin Result := atUnknown; CurPos := Strm.Position; try Strm.Seek(0, soBeginning); {prepare for the try..finally} Hlpr := nil; PartialTarData := nil; GHlp := TAbGzipStreamHelper.Create(Strm); try {create the stream helper and read the item header} GHlp.ReadHeader; { check id fields and if deflated (only handle deflate anyway)} if VerifyHeader(GHlp.FItem.FGZHeader) then begin Result := atGZip; { provisional } { check if is actually a Gzipped Tar } { partial extract contents, verify vs. Tar } PartialTarData := TMemoryStream.Create; GHlp.SeekToItemData; Hlpr := TAbDeflateHelper.Create; Hlpr.PartialSize := AB_TAR_RECORDSIZE * 4; PartialTarData.SetSize(Hlpr.PartialSize); Inflate(Strm, PartialTarData, Hlpr); {set to beginning of extracted data} PartialTarData.Position := 0; if (VerifyTar(PartialTarData) = atTar) then Result := atGZippedTar; end; finally GHlp.Free; Hlpr.Free; PartialTarData.Free; end; except on EReadError do Result := atUnknown; end; Strm.Position := CurPos; end; { TAbGzipExtraField } constructor TAbGzipExtraField.Create(aGZHeader : PAbGzHeader); begin inherited Create; FGZHeader := aGZHeader; end; procedure TAbGzipExtraField.Changed; begin if Buffer = nil then FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FEXTRA else FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FEXTRA; end; procedure TAbGzipExtraField.Delete(aID : TAbGzExtraFieldSubID); begin inherited Delete(Word(aID)); end; function TAbGzipExtraField.GetID(aIndex : Integer): TAbGzExtraFieldSubID; begin Result := TAbGzExtraFieldSubID(inherited IDs[aIndex]); end; function TAbGzipExtraField.Get(aID : TAbGzExtraFieldSubID; out aData : Pointer; out aDataSize : Word) : Boolean; begin Result := inherited Get(Word(aID), aData, aDataSize); end; procedure TAbGzipExtraField.Put(aID : TAbGzExtraFieldSubID; const aData; aDataSize : Word); begin inherited Put(Word(aID), aData, aDataSize); end; { TAbGzipStreamHelper } constructor TAbGzipStreamHelper.Create(AStream: TStream); begin inherited Create(AStream); FItem := TAbGzipItem.Create; end; constructor TAbGzipStreamHelper.Create(Archive : TAbArchive; AStream: TStream); begin Create(AStream); FArchive := Archive; end; destructor TAbGzipStreamHelper.Destroy; begin FItem.Free; inherited; end; function ReadCStringInStream(AStream: TStream): AnsiString; { locate next instance of a null character in a stream leaves stream positioned just past that, or at end of stream if not found or null is last byte in stream. Result is the entire read string. } const BuffSiz = 1024; var Buff : array [0..BuffSiz-1] of AnsiChar; Len, DataRead : LongInt; begin { basically what this is supposed to do is...} { repeat AStream.Read(C, 1); Result := Result + C; until (AStream.Position = AStream.Size) or (C = #0); } Result := ''; repeat DataRead := AStream.Read(Buff, BuffSiz - 1); Buff[DataRead] := #0; Len := StrLen(Buff); if Len > 0 then begin SetLength(Result, Length(Result) + Len); Move(Buff, Result[Length(Result) - Len + 1], Len); end; if Len < DataRead then begin AStream.Seek(Len - DataRead + 1, soCurrent); Break; end; until DataRead = 0; end; procedure TAbGzipStreamHelper.SeekToItemData; {find end of header data, including FileName etc.} begin {** Seek to Compressed Data **} FStream.Seek(0, soBeginning); FItem.LoadGzHeaderFromStream(FStream); end; procedure TAbGzipStreamHelper.ExtractItemData(AStream: TStream); var Helper : TAbDeflateHelper; begin Helper := TAbDeflateHelper.Create; try if (AStream is TAbBitBucketStream) then Helper.Options := Helper.Options or dfc_TestOnly; FItem.CRC32 := Inflate(FStream, AStream, Helper); FItem.UncompressedSize := Helper.NormalSize; finally Helper.Free; end; end; function TAbGzipStreamHelper.FindFirstItem: Boolean; var GZH : TAbGzHeader; DataRead : Integer; begin Result := False; FStream.Seek(0, soBeginning); DataRead := FStream.Read(GZH, SizeOf(TAbGzHeader)); if (DataRead = SizeOf(TAbGzHeader)) and VerifyHeader(GZH) then begin FItem.FGZHeader := GZH; Result := True; end; FStream.Seek(0, soBeginning); end; function TAbGzipStreamHelper.FindNextItem: Boolean; begin { only one item in a GZip } Result := False; end; function TAbGzipStreamHelper.SeekItem(Index: Integer): Boolean; begin if Index > 0 then Result := False else Result := FindFirstItem; end; procedure TAbGzipStreamHelper.WriteArchiveHeader; begin FItem.SaveGzHeaderToStream(FStream); end; procedure TAbGzipStreamHelper.WriteArchiveItem(AStream: TStream); var Helper : TAbDeflateHelper; begin Helper := TAbDeflateHelper.Create; try case FArchive.CompressionLevel of 1 : Helper.PKZipOption := 's'; 3 : Helper.PKZipOption := 'f'; 6 : Helper.PKZipOption := 'n'; 9 : Helper.PKZipOption := 'x'; end; FItem.CRC32 := Deflate(AStream, FStream, Helper); FItem.UncompressedSize := AStream.Size; finally Helper.Free; end; end; procedure TAbGzipStreamHelper.WriteArchiveTail; var Tail : TAbGzTailRec; begin Tail.CRC32 := FItem.CRC32; Tail.ISize := FItem.UncompressedSize; FStream.Write(Tail, SizeOf(TAbGzTailRec)); end; function TAbGzipStreamHelper.GetItemCount: Integer; begin { only one item in a gzip } Result := 1; end; procedure TAbGzipStreamHelper.ReadHeader; begin FItem.LoadGzHeaderFromStream(FStream); end; procedure TAbGzipStreamHelper.ReadTail; begin FStream.Read(FTail, SizeOf(TAbGzTailRec)); end; function TAbGzipStreamHelper.GetGzCRC: LongInt; begin Result := FItem.CRC32; end; function TAbGzipStreamHelper.GetFileSize: LongInt; begin Result := FItem.UncompressedSize; end; { TAbGzipItem } constructor TAbGzipItem.Create; begin inherited Create; { default ID fields } FGzHeader.ID1 := AB_GZ_HDR_ID1; FGzHeader.ID2 := AB_GZ_HDR_ID2; { compression method } FGzHeader.CompMethod := 8; { deflate } { Maxium Compression } FGzHeader.XtraFlags := 2; FFileName := ''; FFileComment := ''; FExtraField := TAbGzipExtraField.Create(@FGzHeader); { source OS ID } {$IFDEF LINUX } {assume EXT2 system } FGzHeader.OS := AB_GZ_OS_ID_Unix; {$ENDIF LINUX } {$IFDEF MSWINDOWS } {assume FAT system } FGzHeader.OS := AB_GZ_OS_ID_FAT; {$ENDIF MSWINDOWS } end; destructor TAbGzipItem.Destroy; begin FExtraField.Free; inherited; end; function TAbGzipItem.GetExternalFileAttributes: LongWord; begin { GZip has no provision for storing attributes } Result := 0; end; function TAbGzipItem.GetFileSystem: TAbGzFileSystem; begin case FGzHeader.OS of 0..18: Result := TAbGzFileSystem(FGzHeader.OS); 255: Result := osUnknown; else Result := osUndefined; end; { case } end; function TAbGzipItem.GetIsEncrypted: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FENCRYPTED) = AB_GZ_FLAG_FENCRYPTED; end; function TAbGzipItem.GetHasExtraField: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FEXTRA) = AB_GZ_FLAG_FEXTRA; end; function TAbGzipItem.GetHasFileComment: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FCOMMENT) = AB_GZ_FLAG_FCOMMENT; end; function TAbGzipItem.GetHasFileName: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FNAME) = AB_GZ_FLAG_FNAME; end; function TAbGzipItem.GetIsText: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FTEXT) = AB_GZ_FLAG_FTEXT; end; function TAbGzipItem.GetLastModFileDate: Word; begin { convert to local DOS file Date } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Hi; end; function TAbGzipItem.GetLastModFileTime: Word; begin { convert to local DOS file Time } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Lo; end; function TAbGzipItem.GetLastModTimeAsDateTime: TDateTime; begin Result := AbUnixTimeToLocalDateTime(FGZHeader.ModTime); end; function TAbGzipItem.GetNativeLastModFileTime: Longint; {$IFDEF MSWINDOWS} var DateTime: TDateTime; {$ENDIF} begin Result := FGZHeader.ModTime; {$IFDEF MSWINDOWS} DateTime := AbUnixTimeToLocalDateTime(Result); Result := AbDateTimeToDosFileDate(DateTime); {$ENDIF} end; procedure TAbGzipItem.LoadGzHeaderFromStream(AStream: TStream); var LenW : Word; begin FGzHeader.ID1 := 0; AStream.Read(FGzHeader, SizeOf(TAbGzHeader)); if not VerifyHeader(FGzHeader) then Exit; { Skip part number, if any } if (FGzHeader.Flags and AB_GZ_FLAG_FCONTINUATION) = AB_GZ_FLAG_FCONTINUATION then AStream.Seek(SizeOf(Word), soCurrent); if HasExtraField then begin { get length of extra data } AStream.Read(LenW, SizeOf(Word)); FExtraField.LoadFromStream(AStream, LenW); end else FExtraField.Clear; { Get Filename, if any } if HasFileName then begin FRawFileName := ReadCStringInStream(AStream); FFileName := CeRawToUtf8(FRawFileName) end else FFileName := 'unknown'; { any comment present? } if HasFileComment then FFileComment := ReadCStringInStream(AStream) else FFileComment := ''; {Assert: stream should now be located at start of compressed data } {If file was compressed with 3.3 spec this will be invalid so use with care} CompressedSize := AStream.Size - AStream.Position - SizeOf(TAbGzTailRec); FDiskFileName := FileName; AbUnfixName(FDiskFileName); Action := aaNone; Tagged := False; end; procedure TAbGzipItem.SaveGzHeaderToStream(AStream: TStream); var LenW : Word; begin { default ID fields } FGzHeader.ID1 := AB_GZ_HDR_ID1; FGzHeader.ID2 := AB_GZ_HDR_ID2; { compression method } FGzHeader.CompMethod := 8; { deflate } { reset unsupported flags } FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_UNSUPPORTED_FLAGS; { main header data } AStream.Write(FGzHeader, SizeOf(TAbGzHeader)); { add extra field if any } if HasExtraField then begin LenW := Length(FExtraField.Buffer); AStream.Write(LenW, SizeOf(LenW)); if LenW > 0 then AStream.Write(FExtraField.Buffer[0], LenW); end; { add filename if any (and include final #0 from string) } if HasFileName then AStream.Write(FRawFileName[1], Length(FRawFileName) + 1); { add file comment if any (and include final #0 from string) } if HasFileComment then AStream.Write(FFileComment[1], Length(FFileComment) + 1); end; procedure TAbGzipItem.SetExternalFileAttributes(Value: LongWord); begin { do nothing } end; procedure TAbGzipItem.SetFileComment(const Value: AnsiString); begin FFileComment := Value; if FFileComment <> '' then FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FCOMMENT else FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FCOMMENT; end; procedure TAbGzipItem.SetFileName(const Value: string); begin FFileName := Value; FRawFileName := CeUtf8ToSys(Value); if Value <> '' then FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FNAME else FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FNAME; end; procedure TAbGzipItem.SetFileSystem(const Value: TAbGzFileSystem); begin if Value = osUnknown then FGzHeader.OS := 255 else FGzHeader.OS := Ord(Value); end; procedure TAbGzipItem.SetIsEncrypted(Value: Boolean); begin { do nothing } end; procedure TAbGzipItem.SetIsText(const Value: Boolean); begin if Value then FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FTEXT else FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FTEXT; end; procedure TAbGzipItem.SetLastModFileDate(const Value: Word); begin { replace date, keep existing time } LastModTimeAsDateTime := EncodeDate( Value shr 9 + 1980, Value shr 5 and 15, Value and 31) + Frac(LastModTimeAsDateTime); end; procedure TAbGzipItem.SetLastModFileTime(const Value: Word); begin { keep current date, replace time } LastModTimeAsDateTime := Trunc(LastModTimeAsDateTime) + EncodeTime( Value shr 11, Value shr 5 and 63, Value and 31 shl 1, 0); end; procedure TAbGzipItem.SetLastModTimeAsDateTime(const Value: TDateTime); begin FGZHeader.ModTime := AbLocalDateTimeToUnixTime(Value); end; { TAbGzipArchive } constructor TAbGzipArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsGzip; FGZStream := FStream; FGZItem := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; procedure TAbGzipArchive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; procedure TAbGzipArchive.SwapToGzip; begin FStream := FGzStream; FItemList := FGzItem; FState := gsGzip; end; function TAbGzipArchive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var GzItem : TAbGzipItem; FullSourceFileName, FullArchiveFileName: String; begin if IsGZippedTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(SourceFileName, ArchiveDirectory); end else begin SwapToGzip; GzItem := TAbGzipItem.Create; try MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); GzItem.FileName := FullArchiveFileName; GzItem.DiskFileName := FullSourceFileName; Result := GzItem; except Result := nil; raise; end; end; end; destructor TAbGzipArchive.Destroy; begin SwapToGzip; FTarList.Free; FTarStream.Free; inherited Destroy; end; procedure TAbGzipArchive.ExtractItemAt(Index: Integer; const UseName: string); var OutStream : TStream; CurItem : TAbGzipItem; begin if IsGZippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, UseName); end else begin SwapToGzip; if Index > 0 then Index := 0; { only one item in a GZip} CurItem := TAbGzipItem(ItemList[Index]); OutStream := TFileStreamEx.Create(UseName, fmCreate or fmShareDenyNone); try try {OutStream} ExtractItemToStreamAt(Index, OutStream); finally {OutStream} OutStream.Free; end; {OutStream} AbSetFileTime(UseName, CurItem.LastModTimeAsDateTime); AbSetFileAttr(UseName, CurItem.NativeFileAttributes); except on E : EAbUserAbort do begin FStatus := asInvalid; if mbFileExists(UseName) then mbDeleteFile(UseName); raise; end else begin if mbFileExists(UseName) then mbDeleteFile(UseName); raise; end; end; end; end; procedure TAbGzipArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); var GzHelp : TAbGzipStreamHelper; ProxyStream : TAbProgressReadStream; begin if IsGzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToGzip; { note Index ignored as there's only one item in a GZip } ProxyStream := TAbProgressReadStream.Create(FGzStream, FOnProgress); try GZHelp := TAbGzipStreamHelper.Create(ProxyStream); try FGzStream.Seek(0, soBeginning); { read GZip Header } GzHelp.ReadHeader; repeat { extract copy data from GZip} GzHelp.ExtractItemData(aStream); { Get validation data } GzHelp.ReadTail; {$IFDEF STRICTGZIP} { According to http://www.gzip.org/zlib/rfc1952.txt A compliant gzip compressor should calculate and set the CRC32 and ISIZE. However, a compliant decompressor should not check these values. If you want to check the the values of the CRC32 and ISIZE in a GZIP file when decompressing enable the STRICTGZIP define contained in AbDefine.inc } { validate against CRC } if GzHelp.FItem.Crc32 <> GzHelp.TailCRC then raise EAbGzipBadCRC.Create; { validate against file size } if GzHelp.FItem.UncompressedSize <> GZHelp.TailSize then raise EAbGzipBadFileSize.Create; {$ENDIF} { try concatenated streams } GzHelp.ReadHeader; until not VerifyHeader(GZHelp.FItem.FGzHeader); finally GzHelp.Free; end; finally ProxyStream.Free; end; end; end; function TAbGzipArchive.FixName(const Value: string): string; { fix up fileaname for storage } begin if FState = gsTar then Result := inherited FixName( Value ) else begin {GZip files Always strip the file path} StoreOptions := StoreOptions + [soStripDrive, soStripPath]; Result := ''; if Value <> '' then Result := ExtractFileName(Value); end; end; function TAbGzipArchive.GetIsGzippedTar: Boolean; begin Result := FIsGzippedTar; end; function TAbGzipArchive.GetItem(Index: Integer): TAbGzipItem; begin Result := nil; if Index = 0 then Result := TAbGzipItem(FItemList.Items[Index]); end; function TAbGzipArchive.GetSupportsEmptyFolders : Boolean; begin Result := IsGzippedTar and TarAutoHandle; end; procedure TAbGzipArchive.LoadArchive; var GzHelp : TAbGzipStreamHelper; Item : TAbGzipItem; Abort : Boolean; begin SwapToGzip; if FGzStream.Size > 0 then begin GzHelp := TAbGzipStreamHelper.Create(FGzStream); try if GzHelp.FindFirstItem then begin Item := TAbGzipItem.Create; Item.LoadGzHeaderFromStream(FGzStream); FGzStream.Seek(-SizeOf(TAbGzTailRec), soEnd); GZHelp.ReadTail; Item.CRC32 := GZHelp.TailCRC; Item.UncompressedSize := GZHelp.TailSize; Item.Action := aaNone; FGZItem.Add(Item); if IsGzippedTar and TarAutoHandle then begin { extract Tar and set stream up } FGzStream.Seek(0, soBeginning); GzHelp.ReadHeader; repeat GzHelp.ExtractItemData(FTarStream); GzHelp.ReadTail; GzHelp.ReadHeader; until not VerifyHeader(GZHelp.FItem.FGzHeader); SwapToTar; inherited LoadArchive; end; end; DoArchiveProgress(100, Abort); FIsDirty := False; finally { Clean Up } GzHelp.Free; end; end; end; procedure TAbGzipArchive.PutItem(Index: Integer; const Value: TAbGzipItem); begin if Index = 0 then FItemList.Items[Index] := Value; end; procedure TAbGzipArchive.SaveArchive; var InGzHelp, OutGzHelp : TAbGzipStreamHelper; CompStream : TDeflateStream; Abort : Boolean; i : Integer; NewStream : TStream; UncompressedStream : TStream; CurItem : TAbGzipItem; CreateArchive : Boolean; ATempName : String; Tail : TAbGzTailRec; begin {prepare for the try..finally} OutGzHelp := nil; NewStream := nil; try InGzHelp := TAbGzipStreamHelper.Create(Self, FGzStream); try {init new archive stream} CreateArchive:= FOwnsStream and (FGzStream.Size = 0) and (FGzStream is TFileStreamEx); if CreateArchive then NewStream := FGzStream else begin ATempName := GetTempName(FArchiveName); NewStream := TFileStreamEx.Create(ATempName, fmCreate or fmShareDenyWrite); end; OutGzHelp := TAbGzipStreamHelper.Create(Self, NewStream); { save the Tar data } if IsGzippedTar and TarAutoHandle then begin SwapToTar; if FGZItem.Count = 0 then begin CurItem := TAbGzipItem.Create; FGZItem.Add(CurItem); end; CurItem := FGZItem[0] as TAbGzipItem; CurItem.Action := aaNone; CurItem.LastModTimeAsDateTime := Now; CurItem.SaveGzHeaderToStream(NewStream); FTarStream.Position := 0; CompStream := TDeflateStream.Create(CompressionLevel, NewStream); try FTargetStream := TWriteBufStream.Create(CompStream, $40000); try inherited SaveArchive; finally FreeAndNil(FTargetStream); end; CurItem.CRC32 := LongInt(CompStream.Hash); CurItem.UncompressedSize := CompStream.Seek(0, soCurrent); finally CompStream.Free; end; Tail.CRC32 := CurItem.CRC32; Tail.ISize := CurItem.UncompressedSize; NewStream.Write(Tail, SizeOf(TAbGzTailRec)); end else begin SwapToGzip; {build new archive from existing archive} for i := 0 to pred(Count) do begin FCurrentItem := ItemList[i]; CurItem := TAbGzipItem(ItemList[i]); InGzHelp.SeekToItemData; case CurItem.Action of aaNone, aaMove : begin {just copy the file to new stream} CurItem.SaveGzHeaderToStream(NewStream); InGzHelp.SeekToItemData; NewStream.CopyFrom(FGZStream, FGZStream.Size - FGZStream.Position); end; aaDelete: {doing nothing omits file from new stream} ; aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin try if (CurItem.Action = aaStreamAdd) then begin { adding from a stream } CurItem.SaveGzHeaderToStream(NewStream); CurItem.UncompressedSize := InStream.Size; OutGzHelp.WriteArchiveItem(InStream); OutGzHelp.WriteArchiveTail; end else begin CurItem.LastModTimeAsDateTime := AbGetFileTime(CurItem.DiskFileName); UncompressedStream := TFileStreamEx.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite); try CurItem.UncompressedSize := UncompressedStream.Size; CurItem.SaveGzHeaderToStream(NewStream); CompStream := TDeflateStream.Create(CompressionLevel, NewStream); try with TAbProgressWriteStream.Create(CompStream, CurItem.UncompressedSize, OnProgress) do try CopyFrom(UncompressedStream, CurItem.UncompressedSize); finally Free; end; CurItem.CRC32 := LongInt(CompStream.Hash); CurItem.UncompressedSize := CompStream.Seek(0, soCurrent); finally CompStream.Free; end; Tail.CRC32 := CurItem.CRC32; Tail.ISize := CurItem.UncompressedSize; NewStream.Write(Tail, SizeOf(TAbGzTailRec)); finally {UncompressedStream} UncompressedStream.Free; end; {UncompressedStream} end; except ItemList[i].Action := aaDelete; DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0); end; end; end; {case} end; { for } end; finally InGzHelp.Free; end; {copy new stream to FStream} SwapToGzip; NewStream.Position := 0; if (FStream is TMemoryStream) then TMemoryStream(FStream).LoadFromStream(NewStream) else begin { need new stream to write } if CreateArchive then NewStream := nil else begin if FOwnsStream then begin {need new stream to write} if CreateArchive then NewStream := nil else begin FGZStream := nil; FreeAndNil(FStream); FreeAndNil(NewStream); if (mbDeleteFile(FArchiveName) and mbRenameFile(ATempName, FArchiveName)) then FStream := TFileStreamEx.Create(FArchiveName, fmOpenReadWrite or fmShareDenyWrite) else begin RaiseLastOSError; end; FGZStream := FStream; end; end else begin FStream.Size := 0; FStream.Position := 0; FStream.CopyFrom(NewStream, 0) end; end; end; {update Items list} for i := pred( Count ) downto 0 do begin if ItemList[i].Action = aaDelete then FItemList.Delete( i ) else if ItemList[i].Action <> aaFailed then ItemList[i].Action := aaNone; end; if IsGzippedTar and TarAutoHandle then SwapToTar; DoArchiveSaveProgress( 100, Abort ); DoArchiveProgress( 100, Abort ); finally {NewStream} OutGzHelp.Free; if (FStream <> NewStream) then NewStream.Free; end; end; procedure TAbGzipArchive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToGzip; FTarAutoHandle := Value; end; procedure TAbGzipArchive.TestItemAt(Index: Integer); var SavePos : LongInt; GZType : TAbArchiveType; BitBucket : TAbBitBucketStream; GZHelp : TAbGzipStreamHelper; begin if IsGzippedTar and TarAutoHandle then begin inherited TestItemAt(Index); end else begin { note Index ignored as there's only one item in a GZip } SavePos := FGzStream.Position; GZType := VerifyGZip(FGZStream); if not (GZType in [atGZip, atGZippedTar]) then raise EAbGzipInvalid.Create; BitBucket := nil; GZHelp := nil; try BitBucket := TAbBitBucketStream.Create(1024); GZHelp := TAbGzipStreamHelper.Create(FGZStream); Index := 0; FGZStream.Seek(0, soBeginning); GZHelp.ReadHeader; repeat GZHelp.ExtractItemData(BitBucket); GZHelp.ReadTail; { validate against CRC } if GzHelp.FItem.Crc32 <> GZHelp.TailCRC then raise EAbGzipBadCRC.Create; Inc(Index); GzHelp.ReadHeader; until not VerifyHeader(GZHelp.FItem.FGzHeader); if (Index < 2) then begin { validate against file size } if GzHelp.FItem.UncompressedSize <> GZHelp.TailSize then raise EAbGzipBadFileSize.Create; end; finally GZHelp.Free; BitBucket.Free; end; FGzStream.Position := SavePos; end; end; procedure TAbGzipArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/ablzmatyp.pas����������������������������������������0000644�0001750�0000144�00000035243�14743153644�023147� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Joel Haynie * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Alexander Koblov <alexx2000@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbLzmaTyp.pas *} {*********************************************************} {* ABBREVIA: TAbLzmaArchive, TAbLzmaItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with Lzma files *} {*********************************************************} unit AbLzmaTyp; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbTarTyp, AbUtils; type PAbLzmaHeader = ^TAbLzmaHeader; { File Header } TAbLzmaHeader = packed record { SizeOf(TAbLzmaHeader) = 13 } Properties: array[0..4] of Byte; { LZMA properties } UncompressedSize : Int64; { Uncompressed size } end; { The Purpose for this Item is the placeholder for aaAdd and aaDelete Support. } { For all intents and purposes we could just use a TAbArchiveItem } type TAbLzmaItem = class(TabArchiveItem); TAbLzmaArchiveState = (gsLzma, gsTar); { TAbLzmaArchive } TAbLzmaArchive = class(TAbTarArchive) private FLzmaStream : TStream; { stream for Lzma file} FLzmaItem : TAbArchiveList; { item in lzma (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbLzmaArchiveState; FIsLzmaTar : Boolean; procedure CompressFromStream(aStream: TStream); procedure DecompressToStream(aStream: TStream); procedure SetTarAutoHandle(const Value: Boolean); procedure SwapToLzma; procedure SwapToTar; protected { Inherited Abstract functions } function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function GetSupportsEmptyFolders : Boolean; override; public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; { Properties } property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsLzmaTar : Boolean read FIsLzmaTar write FIsLzmaTar; end; function VerifyLzma(Strm : TStream) : TAbArchiveType; implementation uses StrUtils, SysUtils, Math, AbExcept, AbVMStrm, AbBitBkt, ULZMADecoder, ULZMAEncoder, DCOSUtils, DCClassesUtf8; { ****************** Helper functions Not from Classes Above ***************** } function VerifyLzma(Strm : TStream) : TAbArchiveType; var CurPos : Int64; TarStream: TStream; Hdr : TAbLzmaHeader; UncompressedSize: Int64; DecompStream: TLZMADecoder; begin Result := atUnknown; CurPos := Strm.Position; Strm.Seek(0, soBeginning); try if Strm.Read(Hdr, SizeOf(Hdr)) = SizeOf(Hdr) then begin TarStream := TMemoryStream.Create; try DecompStream := TLZMADecoder.Create; try if Hdr.UncompressedSize <> -1 then UncompressedSize:= Min(AB_TAR_RECORDSIZE * 4, Hdr.UncompressedSize) else if Strm.Size < AB_TAR_RECORDSIZE * 8 then UncompressedSize:= -1 else begin UncompressedSize:= AB_TAR_RECORDSIZE * 4; end; if DecompStream.SetDecoderProperties(Hdr.Properties) and DecompStream.Code(Strm, TarStream, UncompressedSize) then begin Result := atLzma; { Check for embedded TAR } TarStream.Seek(0, soBeginning); if VerifyTar(TarStream) = atTar then Result := atLzmaTar; end; finally DecompStream.Free; end; finally TarStream.Free; end; end; except on EReadError do Result := atUnknown; end; Strm.Position := CurPos; { Return to original position. } end; { ****************************** TAbLzmaArchive ***************************** } constructor TAbLzmaArchive.CreateFromStream(aStream: TStream; const aArchiveName: string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsLzma; FLzmaStream := FStream; FLzmaItem := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.SwapToLzma; begin FStream := FLzmaStream; FItemList := FLzmaItem; FState := gsLzma; end; { -------------------------------------------------------------------------- } function TAbLzmaArchive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var LzmaItem : TAbLzmaItem; FullSourceFileName, FullArchiveFileName: String; begin if IsLzmaTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(SourceFileName, ArchiveDirectory); end else begin SwapToLzma; LzmaItem := TAbLzmaItem.Create; try MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); LzmaItem.FileName := FullArchiveFileName; LzmaItem.DiskFileName := FullSourceFileName; Result := LzmaItem; except Result := nil; raise; end; end; end; { -------------------------------------------------------------------------- } destructor TAbLzmaArchive.Destroy; begin SwapToLzma; FTarList.Free; FTarStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.ExtractItemAt(Index: Integer; const NewName: string); var OutStream : TStream; begin if IsLzmaTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, NewName); end else begin SwapToLzma; OutStream := TFileStreamEx.Create(NewName, fmCreate or fmShareDenyNone); try try ExtractItemToStreamAt(Index, OutStream); finally OutStream.Free; end; { Lzma doesn't store the last modified time or attributes, so don't set them } except on E : EAbUserAbort do begin FStatus := asInvalid; if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end else begin if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end; end; end; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); begin if IsLzmaTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToLzma; { Index ignored as there's only one item in a Lzma } DecompressToStream(aStream); end; end; { -------------------------------------------------------------------------- } function TAbLzmaArchive.GetSupportsEmptyFolders : Boolean; begin Result := IsLzmaTar and TarAutoHandle; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.LoadArchive; var Item: TAbLzmaItem; Abort: Boolean; ItemName: string; Header: TAbLzmaHeader; begin if FLzmaStream.Size = 0 then Exit; if IsLzmaTar and TarAutoHandle then begin { Decompress and send to tar LoadArchive } DecompressToStream(FTarStream); SwapToTar; inherited LoadArchive; end else begin SwapToLzma; FStream.Read(Header, SizeOf(Header)); Item := TAbLzmaItem.Create; Item.Action := aaNone; if Header.UncompressedSize <> -1 then Item.UncompressedSize := Header.UncompressedSize; { Filename isn't stored, so constuct one based on the archive name } ItemName := ExtractFileName(ArchiveName); if ItemName = '' then Item.FileName := 'unknown' else if AnsiEndsText('.tlz', ItemName) then Item.FileName := ChangeFileExt(ItemName, '.tar') else Item.FileName := ChangeFileExt(ItemName, ''); Item.DiskFileName := Item.FileName; FItemList.Add(Item); end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.SaveArchive; var I: Integer; CurItem: TAbLzmaItem; UpdateArchive: Boolean; TempFileName: String; InputFileStream: TStream; begin if IsLzmaTar and TarAutoHandle then begin SwapToTar; inherited SaveArchive; UpdateArchive := (FLzmaStream.Size > 0) and (FLzmaStream is TFileStreamEx); if UpdateArchive then begin FreeAndNil(FLzmaStream); TempFileName := GetTempName(FArchiveName); { Create new archive with temporary name } FLzmaStream := TFileStreamEx.Create(TempFileName, fmCreate or fmShareDenyWrite); end; FTarStream.Position := 0; CompressFromStream(FTarStream); if UpdateArchive then begin FreeAndNil(FLzmaStream); { Replace original by new archive } if not (mbDeleteFile(FArchiveName) and mbRenameFile(TempFileName, FArchiveName)) then RaiseLastOSError; { Open new archive } FLzmaStream := TFileStreamEx.Create(FArchiveName, fmOpenRead or fmShareDenyNone); end; end else begin { Things we know: There is only one file per archive.} { Actions we have to address in SaveArchive: } { aaNone & aaMove do nothing, as the file does not change, only the meta data } { aaDelete could make a zero size file unless there are two files in the list.} { aaAdd, aaStreamAdd, aaFreshen, & aaReplace will be the only ones to take action. } SwapToLzma; for I := 0 to Pred(Count) do begin FCurrentItem := ItemList[I]; CurItem := TAbLzmaItem(ItemList[I]); case CurItem.Action of aaNone, aaMove: Break;{ Do nothing; lzma doesn't store metadata } aaDelete: ; {doing nothing omits file from new stream} aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin FLzmaStream.Size := 0; if CurItem.Action = aaStreamAdd then begin CompressFromStream(InStream); { Copy/compress entire Instream to FLzmaStream } end else begin InputFileStream := TFileStreamEx.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite); try CompressFromStream(InputFileStream); { Copy/compress entire Instream to FLzmaStream } finally InputFileStream.Free; end; end; Break; end; { End aaAdd, aaFreshen, aaReplace, & aaStreamAdd } end; { End of CurItem.Action Case } end; { End Item for loop } end; { End Tar Else } end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToLzma; FTarAutoHandle := Value; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.CompressFromStream(aStream: TStream); var Encoder: TLZMAEncoder; begin Encoder := TLZMAEncoder.Create; try Encoder.WriteCoderProperties(FLzmaStream); FLzmaStream.WriteQWord(NToLE(aStream.Size)); Encoder.Code(aStream, FLzmaStream, -1, -1); finally Encoder.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.DecompressToStream(aStream: TStream); var Header: TAbLzmaHeader; Decoder: TLZMADecoder; begin FLzmaStream.Seek(0, soBeginning); if FLzmaStream.Read(Header, SizeOf(Header)) = SizeOf(Header) then begin Decoder := TLZMADecoder.Create; try if Decoder.SetDecoderProperties(Header.Properties) and Decoder.Code(FLzmaStream, aStream, Header.UncompressedSize) then begin Exit; { Success } end; finally Decoder.Free; end; end; raise EAbUnhandledType.Create; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.TestItemAt(Index: Integer); var LzmaType: TAbArchiveType; BitBucket: TAbBitBucketStream; begin if IsLzmaTar and TarAutoHandle then begin SwapToTar; inherited TestItemAt(Index); end else begin { Note Index ignored as there's only one item in a GZip } LzmaType := VerifyLzma(FLzmaStream); if not (LzmaType in [atLzma, atLzmaTar]) then raise EAbGzipInvalid.Create; // TODO: Add lzma-specific exceptions } BitBucket := TAbBitBucketStream.Create(1024); try DecompressToStream(BitBucket); finally BitBucket.Free; end; end; end; { -------------------------------------------------------------------------- } procedure TAbLzmaArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abprogress.pas���������������������������������������0000755�0001750�0000144�00000004713�14743153644�023314� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit AbProgress; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, AbArcTyp; type { TAbProgress } TAbProgress = object DoneSize: Int64; FileSize: Int64; OnProgress: TAbProgressEvent; procedure DoProgress(Result: Integer); end; { TAbProgressReadStream } TAbProgressReadStream = class(TStream) private FSource: TStream; FProgress: TAbProgress; public constructor Create(ASource : TStream; AEvent: TAbProgressEvent); reintroduce; function Read(var Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; { TAbProgressWriteStream } TAbProgressWriteStream = class(TStream) private FTarget: TStream; FProgress: TAbProgress; public constructor Create(ATarget : TStream; ASize: Int64; AEvent: TAbProgressEvent); reintroduce; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; implementation uses AbExcept; { TAbProgress } procedure TAbProgress.DoProgress(Result: Integer); var Percent: Byte; Abort: Boolean = False; begin if (FileSize > 0) then begin DoneSize += Result; Percent:= Byte(DoneSize * 100 div FileSize); OnProgress(Percent, Abort); if Abort then raise EAbUserAbort.Create; end; end; { TAbProgressReadStream } constructor TAbProgressReadStream.Create(ASource: TStream; AEvent: TAbProgressEvent); begin FSource:= ASource; FProgress.OnProgress:= AEvent; FProgress.FileSize:= FSource.Size; end; function TAbProgressReadStream.Read(var Buffer; Count: Longint): Longint; begin Result:= FSource.Read(Buffer, Count); if Assigned(FProgress.OnProgress) then FProgress.DoProgress(Result); end; function TAbProgressReadStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin Result:= FSource.Seek(Offset, Origin); end; { TAbProgressWriteStream } constructor TAbProgressWriteStream.Create(ATarget: TStream; ASize: Int64; AEvent: TAbProgressEvent); begin FTarget:= ATarget; FProgress.FileSize:= ASize; FProgress.OnProgress:= AEvent; end; function TAbProgressWriteStream.Write(const Buffer; Count: Longint): Longint; begin Result:= FTarget.Write(Buffer, Count); if Assigned(FProgress.OnProgress) then FProgress.DoProgress(Result); end; function TAbProgressWriteStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin Result:= FTarget.Seek(Offset, Origin); end; end. �����������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abresstring.pas��������������������������������������0000644�0001750�0000144�00000023301�14743153644�023457� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Roman Kassebaum * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings *} {*********************************************************} unit AbResString; {$I AbDefine.inc} interface resourcestring AbErrZipInvalidS = 'Invalid file - not a PKZip file'; AbZipVersionNeededS = 'Cannot extract file - newer version required'; AbUnknownCompressionMethodS = 'Cannot extract file - unsupported compression method'; AbNoExtractionMethodS = 'Cannot extract file - no extraction support provided'; AbInvalidPasswordS = 'Cannot extract file - invalid password'; AbNoInsertionMethodS = 'Cannot insert file - no insertion support provided'; AbInvalidFactorS = 'Invalid Reduce Factor'; AbDuplicateNameS = 'Cannot insert file - duplicates stored name'; AbUnsupportedCompressionMethodS = 'Cannot insert file - unsupported compression method'; AbUserAbortS = 'Process aborted by user'; AbArchiveBusyS = 'Archive is busy - cannot process new requests'; AbLastDiskRequestS = 'Insert the last disk in the spanned disk set'; AbDiskRequestS = 'Insert floppy'; AbImageRequestS = 'Image file name'; AbBadSpanStreamS = 'Spanned archives must be opened as file streams'; AbDiskNumRequestS = 'Insert disk number %d of the spanned disk set'; AbImageNumRequestS = 'Insert span number %d of the spanned file set'; AbNoOverwriteSpanStreamS = 'Cannot update an existing spanned disk set'; AbNoSpannedSelfExtractS = 'Cannot make a self-extracting spanned disk set'; AbBlankDiskS = 'Insert a blank floppy disk'; AbStreamFullS = 'Stream write error'; AbNoSuchDirectoryS = 'Directory does not exist'; AbInflateBlockErrorS = 'Cannot inflate block'; AbBadStreamTypeS = 'Invalid Stream'; AbTruncateErrorS = 'Error truncating Zip File'; AbZipBadCRCS = 'Failed CRC Check'; AbZipBadStubS = 'Stub must be an executable'; AbFileNotFoundS = 'File not found'; AbInvalidLFHS = 'Invalid Local File Header entry'; AbNoArchiveS = 'Archive does not exist - Filename is blank'; AbReadErrorS = 'Error reading archive'; AbInvalidIndexS = 'Invalid archive item index'; AbInvalidThresholdS = 'Invalid archive size threshold'; AbUnhandledFileTypeS = 'Unhandled Archive Type'; AbSpanningNotSupportedS = 'Spanning not supported by this Archive type'; AbLogCreateErrorS = 'Error creating Log File'; AbMoveFileErrorS = 'Error Moving File %s to %s'; AbFileSizeTooBigS = 'File size is too big for archive type'; AbNoCabinetDllErrorS = 'Cannot load cabinet.dll'; AbFCIFileOpenErrorS = 'FCI cannot open file'; AbFCIFileReadErrorS = 'FCI cannot read file'; AbFCIFileWriteErrorS = 'FCI cannot write file'; AbFCIFileCloseErrorS = 'FCI close file error'; AbFCIFileSeekErrorS = 'FCI file seek error'; AbFCIFileDeleteErrorS = 'FCI file delete error'; AbFCIAddFileErrorS = 'FCI cannot add file'; AbFCICreateErrorS = 'FCI cannot create context'; AbFCIFlushCabinetErrorS = 'FCI cannot flush cabinet'; AbFCIFlushFolderErrorS = 'FCI cannot flush folder'; AbFDICopyErrorS = 'FDI cannot enumerate files'; AbFDICreateErrorS = 'FDI cannot create context'; AbInvalidCabTemplateS = 'Invalid cab file template'; AbInvalidCabFileS = 'Invalid file - not a cabinet file'; AbZipStored = 'Stored'; AbZipShrunk = 'Shrunk'; AbZipReduced = 'Reduced'; AbZipImploded = 'Imploded'; AbZipTokenized = 'Tokenized'; AbZipDeflated = 'Deflated'; AbZipDeflate64 = 'Enhanced Deflation'; AbZipDCLImploded = 'DCL Imploded'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Unknown (%d)'; AbZipBestMethod = 'Best Method'; AbVersionFormatS = 'Version %s'; AbCompressedSizeFormatS = 'Compressed Size: %d'; AbUncompressedSizeFormatS = 'Uncompressed Size: %d'; AbCompressionMethodFormatS = 'Compression Method: %s'; AbCompressionRatioFormatS = 'Compression Ratio: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'External File Attributes: %s'; AbIFAFormatS = 'File Type: %s'; AbTextS = 'Text'; AbBinaryS = 'Binary'; AbEncryptionFormatS = 'Encryption: %s'; AbEncryptedS = 'Encrypted'; AbNotEncryptedS = 'Not Encrypted'; AbUnknownS = 'Unknown'; AbTimeStampFormatS = 'Time Stamp: %s'; AbMadeByFormatS = 'Made by Version: %f'; AbNeededFormatS = 'Version Needed to Extract: %f'; AbCommentFormatS = 'Comment: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZip Archives (*.zip)|*.zip|Self Extracting Archives (*.exe)|*.exe|All Files (*.*)|*.*'; AbFileNameTitleS = 'Select File Name'; AbOKS = 'OK'; AbCancelS = 'Cancel'; AbSelectDirectoryS = 'Select Directory'; AbEnterPasswordS = 'Enter Password'; AbPasswordS = '&Password'; AbVerifyS = '&Verify'; AbCabExtS = '*.cab'; AbCabFilterS = 'Cabinet Archives (*.cab)|*.CAB|All Files (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Text Files (*.txt)|*.TXT|All Files (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Self-Extracting Zip Files (*.exe)|*.EXE|All Files (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: request to read too many bytes [%d]'; AbVMSInvalidOriginS = 'VMS: invalid origin %d, should be 0, 1, 2'; AbVMSErrorOpenSwapS = 'VMS: Cannot open swap file %s'; AbVMSSeekFailS = 'VMS: Failed to seek in swap file %s'; AbVMSReadFailS = 'VMS: Failed to read %d bytes from swap file %s'; AbVMSWriteFailS = 'VMS: Failed to write %d bytes to swap file %s'; AbVMSWriteTooManyBytesS = 'VMS: request to write too many bytes [%d]'; AbBBSReadTooManyBytesS = 'BBS: request to read too many bytes [%d]'; AbBBSSeekOutsideBufferS = 'BBS: New position is outside the buffer'; AbBBSInvalidOriginS = 'BBS: Invalid Origin value'; AbBBSWriteTooManyBytesS = 'BBS: request to write too many bytes [%d]'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Not at end of stream'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: seek failed'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: write failed'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: invalid origin'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: invalid new position'; AbItemNameHeadingS = 'Name'; AbPackedHeadingS = 'Packed'; AbMethodHeadingS = 'Method'; AbRatioHeadingS = 'Ratio (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Attributes'; AbFileFormatHeadingS = 'Format'; AbEncryptionHeadingS = 'Encrypted'; AbTimeStampHeadingS = 'Time Stamp'; AbFileSizeHeadingS = 'Size'; AbVersionMadeHeadingS = 'Version Made'; AbVersionNeededHeadingS = 'Version Needed'; AbPathHeadingS = 'Path'; AbPartialHeadingS = 'Partial'; AbExecutableHeadingS = 'Executable'; AbFileTypeHeadingS = 'Type'; AbLastModifiedHeadingS = 'Modified'; AbCabMethod0S = 'None'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' added '; AbLtDeleteS = ' deleted '; AbLtExtractS = ' extracted '; AbLtFreshenS = ' freshened '; AbLtMoveS = ' moved '; AbLtReplaceS = ' replaced '; AbLtStartS = ' logging '; AbGzipInvalidS = 'Invalid Gzip'; AbGzipBadCRCS = 'Bad CRC'; AbGzipBadFileSizeS = 'Bad File Size'; AbTarInvalidS = 'Invalid Tar'; AbTarBadFileNameS = 'File name too long'; AbTarBadLinkNameS = 'Symbolic link path too long'; AbTarBadOpS = 'Unsupported Operation'; AbUnhandledEntityS = 'Unhandled Entity'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT File System (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (or OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS File System (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS File System (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'VFAT File System (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox or PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'unknown'; AbGzOsUndefined = 'ID undefined by gzip'; { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Index out of bounds'; AbCmpndBusyUpdating = 'Compound file is busy updating'; AbCmpndInvalidFile = 'Invalid compound file'; AbCmpndFileNotFound = 'File/Directory not found'; AbCmpndFolderNotEmpty = 'Folder not empty'; AbCmpndExceedsMaxFileSize = 'File size exceeds maximum allowable'; implementation end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abselfex.pas�����������������������������������������0000644�0001750�0000144�00000007521�14743153644�022733� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbSelfEx.pas *} {*********************************************************} {* ABBREVIA: Component for building self-extracting zips *} {*********************************************************} unit AbSelfEx; {$I AbDefine.inc} interface uses Classes, AbBase; type TAbGetFileEvent = procedure(Sender : TObject; var aFilename : string; var Abort : Boolean) of object; type TAbMakeSelfExe = class(TAbBaseComponent) protected {private} FStubExe : string; FZipFile : string; FSelfExe : string; FStubStream : TStream; FZipStream : TStream; FSelfStream : TStream; FOnGetStubExe : TAbGetFileEvent; FOnGetZipFile : TAbGetFileEvent; procedure DoGetStubExe(var Abort : Boolean); procedure DoGetZipFile(var Abort : Boolean); public function Execute : Boolean; published property SelfExe : string read FSelfExe write FSelfExe; property StubExe : string read FStubExe write FStubExe; property ZipFile : string read FZipFile write FZipFile; property OnGetStubExe : TAbGetFileEvent read FOnGetStubExe write FOnGetStubExe; property OnGetZipFile : TAbGetFileEvent read FOnGetZipFile write FOnGetZipFile; property Version; end; implementation uses SysUtils, {$IFDEF LibcAPI} Libc, {$ENDIF} AbExcept, AbZipTyp, DCOSUtils, DCClassesUtf8; { -------------------------------------------------------------------------- } function TAbMakeSelfExe.Execute : Boolean; var Abort : Boolean; begin Abort := False; if (FStubExe = '') then DoGetStubExe(Abort); if Abort then raise EAbUserAbort.Create; if not mbFileExists(FStubExe) then raise EAbFileNotFound.Create; if (FZipFile = '') then DoGetZipFile(Abort); if Abort then raise EAbUserAbort.Create; if not mbFileExists(FZipFile) then raise EAbFileNotFound.Create; FStubStream := TFileStreamEx.Create(FStubExe, fmOpenRead or fmShareDenyWrite); FZipStream := TFileStreamEx.Create(FZipFile, fmOpenRead or fmShareDenyWrite); if (FSelfExe = '') then FSelfExe := ChangeFileExt(FZipFile, '.exe'); FSelfStream := TFileStreamEx.Create(FSelfExe, fmCreate or fmShareExclusive); try MakeSelfExtracting(FStubStream, FZipStream, FSelfStream); Result := True; finally FStubStream.Free; FZipStream.Free; FSelfStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbMakeSelfExe.DoGetStubExe(var Abort: Boolean); begin if Assigned(FOnGetStubExe) then FOnGetStubExe(Self, FStubExe, Abort); end; { -------------------------------------------------------------------------- } procedure TAbMakeSelfExe.DoGetZipFile(var Abort : Boolean); begin if Assigned(FOnGetZipFile) then FOnGetZipFile(Self, FZipFile, Abort); end; { -------------------------------------------------------------------------- } end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abspanst.pas�����������������������������������������0000644�0001750�0000144�00000030723�14743153644�022755� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbSpanSt.pas *} {*********************************************************} {* ABBREVIA: TAbSpan*Stream Classes *} {*********************************************************} {* Streams to handle splitting ZIP files or spanning *} {* them to diskettes *} {*********************************************************} unit AbSpanSt; {$I AbDefine.inc} interface uses Classes, AbArcTyp; type { TAbSpanBaseStream interface ============================================== } TAbSpanBaseStream = class(TStream) protected {private} FArchiveName: string; FOnRequestImage: TAbRequestImageEvent; protected {methods} function GetImageName( ImageNumber: Integer ): string; public {methods} constructor Create( const ArchiveName: string ); public {events} property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write FOnRequestImage; end; { TAbSpanReadStream interface ============================================== } TAbSpanReadStream = class(TAbSpanBaseStream) protected {private} FCurrentImage: LongWord; FIsSplit: Boolean; FLastImage: LongWord; FStream: TStream; FOnRequestNthDisk : TAbRequestNthDiskEvent; protected {methods} procedure GotoImage( ImageNumber: Integer ); procedure SetOnRequestImage(Value: TAbRequestImageEvent); public {methods} constructor Create( const ArchiveName: string; CurrentImage: LongWord; Stream: TStream ); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; procedure SeekImage( Image: LongWord; const Offset: Int64); public {events} property OnRequestImage write SetOnRequestImage; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write FOnRequestNthDisk; end; { TAbSpanWriteStream interface ============================================= } TAbSpanWriteStream = class(TAbSpanBaseStream) protected {private} FCurrentImage: LongWord; FImageSize: Int64; FStream: TStream; FThreshold: Int64; FOnRequestBlankDisk : TAbRequestDiskEvent; protected {methods} procedure NewImage; public {methods} constructor Create( const ArchiveName: string; Stream: TStream; Threshold: Int64 ); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function WriteUnspanned(const Buffer; Count: Longint; FailOnSpan: Boolean = False): Boolean; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; function ReleaseStream: TStream; public {properties} property CurrentImage : LongWord read FCurrentImage; public {events} property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write FOnRequestBlankDisk; end; implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} Math, RTLConsts, SysUtils, AbUtils, AbExcept, DCOSUtils, DCClassesUtf8; {============================================================================} { TAbSpanBaseStream implementation ========================================= } constructor TAbSpanBaseStream.Create( const ArchiveName: string ); begin inherited Create; FArchiveName := ArchiveName; end; {------------------------------------------------------------------------------} function TAbSpanBaseStream.GetImageName( ImageNumber: Integer ): string; var Abort : Boolean; Ext : string; begin {generate default name} Ext := ExtractFileExt(FArchiveName); if (Length(Ext) < 2) then Ext := '.' + Format('%.2d', [ImageNumber]) else Ext := Ext[1] + Ext[2] + Format('%.2d', [ImageNumber]); Result := ChangeFileExt(FArchiveName, Ext); {call event} if Assigned(FOnRequestImage) then begin Abort := False; FOnRequestImage(Self, ImageNumber, Result, Abort); if Abort then raise EAbUserAbort.Create; end; end; {============================================================================} { TAbSpanReadStream implementation ========================================= } constructor TAbSpanReadStream.Create( const ArchiveName: string; CurrentImage: LongWord; Stream: TStream ); begin inherited Create(ArchiveName); FCurrentImage := CurrentImage; FIsSplit := mbFileExists(GetImageName(1)) or not AbDriveIsRemovable(ArchiveName); FLastImage := CurrentImage; FStream := Stream; end; {------------------------------------------------------------------------------} destructor TAbSpanReadStream.Destroy; begin FreeAndNil(FStream); inherited; end; {------------------------------------------------------------------------------} procedure TAbSpanReadStream.GotoImage( ImageNumber: Integer ); var Abort: Boolean; ImageName: string; begin { switch to the requested image. ImageNumber is passed in as 0-based to match the zip spec, but all of the callbacks receive 1-based values. } FreeAndNil(FStream); FCurrentImage := ImageNumber; Inc(ImageNumber); ImageName := FArchiveName; if FIsSplit then begin { the last image uses the original filename } if FCurrentImage <> FLastImage then ImageName := GetImageName(ImageNumber) end else if Assigned(FOnRequestNthDisk) then begin Abort := False; repeat FOnRequestNthDisk(Self, ImageNumber, Abort); if Abort then raise EAbUserAbort.Create; until AbGetDriveFreeSpace(ImageName) <> -1; end else raise EAbUserAbort.Create; FStream := TFileStreamEx.Create(ImageName, fmOpenRead or fmShareDenyWrite); end; {------------------------------------------------------------------------------} function TAbSpanReadStream.Read(var Buffer; Count: Longint): Longint; var BytesRead, BytesLeft: LongInt; PBuf: PByte; begin { read until the buffer's full, switching images if necessary } Result := 0; if FStream = nil then Exit; PBuf := @Buffer; BytesLeft := Count; while Result < Count do begin BytesRead := FStream.Read(PBuf^, BytesLeft); Inc(Result, BytesRead); Inc(PBuf, BytesRead); Dec(BytesLeft, BytesRead); if BytesRead < BytesLeft then begin if FCurrentImage <> FLastImage then GotoImage(FCurrentImage + 1) else Break; end; end; end; {------------------------------------------------------------------------------} function TAbSpanReadStream.Write(const Buffer; Count: Longint): Longint; begin raise EAbException.Create('TAbSpanReadStream.Write unsupported'); end; {------------------------------------------------------------------------------} function TAbSpanReadStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if FStream = nil then Result := 0 else if (Offset = 0) and (Origin = soCurrent) then Result := FStream.Position else raise EAbException.Create('TAbSpanReadStream.Seek unsupported'); end; {------------------------------------------------------------------------------} procedure TAbSpanReadStream.SeekImage( Image: LongWord; const Offset: Int64); begin if FStream = nil then Exit; if FCurrentImage <> Image then GotoImage(Image); FStream.Position := Offset; end; {------------------------------------------------------------------------------} procedure TAbSpanReadStream.SetOnRequestImage(Value: TAbRequestImageEvent); begin FOnRequestImage := Value; FIsSplit := mbFileExists(GetImageName(1)) or not AbDriveIsRemovable(FArchiveName); end; {============================================================================} { TAbSpanWriteStream implementation ======================================== } constructor TAbSpanWriteStream.Create( const ArchiveName: string; Stream: TStream; Threshold: Int64 ); begin inherited Create(ArchiveName); FCurrentImage := 0; FStream := Stream; FThreshold := Threshold; end; {------------------------------------------------------------------------------} destructor TAbSpanWriteStream.Destroy; begin FStream.Free; inherited; end; {------------------------------------------------------------------------------} procedure TAbSpanWriteStream.NewImage; var Abort: Boolean; begin { start a new span or blank disk. FCurrentImage is 0-based to match the zip spec, but all of the callbacks receive 1-based values. } FreeAndNil(FStream); Inc(FCurrentImage); if FThreshold > 0 then mbRenameFile(FArchiveName, GetImageName(FCurrentImage)) else begin if Assigned(FOnRequestBlankDisk) then begin Abort := False; repeat FOnRequestBlankDisk(Self, Abort); if Abort then raise EAbUserAbort.Create; until AbGetDriveFreeSpace(FArchiveName) <> -1; end else raise EAbUserAbort.Create; AbSetSpanVolumeLabel(AbDrive(FArchiveName), FCurrentImage); end; FStream := TFileStreamEx.Create(FArchiveName, fmCreate or fmShareDenyWrite); FImageSize := 0; end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.Read(var Buffer; Count: Longint): Longint; begin raise EAbException.Create('TAbSpanWriteStream.Read unsupported'); end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.Write(const Buffer; Count: Longint): Longint; var BytesWritten, BytesLeft: LongInt; PBuf: PByte; begin { write until the buffer is done, starting new spans if necessary } Result := 0; if FStream = nil then Exit; PBuf := @Buffer; BytesLeft := Count; while Result < Count do begin if FThreshold > 0 then BytesWritten := FStream.Write(PBuf^, Min(BytesLeft, FThreshold - FImageSize)) else BytesWritten := FStream.Write(PBuf^, BytesLeft); Inc(FImageSize, BytesWritten); Inc(Result, BytesWritten); Inc(PBuf, BytesWritten); Dec(BytesLeft, BytesWritten); if BytesWritten < BytesLeft then NewImage; end; end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.WriteUnspanned(const Buffer; Count: Longint; FailOnSpan: Boolean = False): Boolean; var BytesWritten: LongInt; begin { write as a contiguous block, starting a new span if there isn't room. FailOnSpan (and result = false) can be used to update data before it's written again } if FStream = nil then raise EWriteError.Create(SWriteError); if (FThreshold > 0) and (FThreshold - FImageSize < Count) then BytesWritten := 0 else BytesWritten := FStream.Write(Buffer, Count); if BytesWritten < Count then begin if BytesWritten > 0 then FStream.Size := FStream.Size - BytesWritten; NewImage; if FailOnSpan then BytesWritten := 0 else begin BytesWritten := Count; FStream.WriteBuffer(Buffer, Count); end; end; Inc(FImageSize, BytesWritten); Result := (BytesWritten = Count); end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if FStream = nil then Result := 0 else if (Offset = 0) and (Origin = soCurrent) then Result := FStream.Position else raise EAbException.Create('TAbSpanWriteStream.Seek unsupported'); end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.ReleaseStream: TStream; begin Result := FStream; FStream := nil; end; {------------------------------------------------------------------------------} end. ���������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abswstm.pas������������������������������������������0000644�0001750�0000144�00000033461�14743153644�022624� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbSWStm.pas *} {*********************************************************} {* ABBREVIA: TabSlidingWindowStream class *} {*********************************************************} unit AbSWStm; {$I AbDefine.inc} {Notes: The TabSlidingWindowStream class provides a simple buffered stream for sliding window compression/decompression routines. The sliding window stream is limited when compared with a true buffered stream: - it is assumed that the underlying stream is just going to be written to and is initially empty - the buffer is fixed in size to 40KB - write operations can only occur at the end of the stream - the stream can only be positioned with a certain limited range - we can only read up to 32KB - we can only write up to 32KB The stream is written as a wrapper around another stream (presumably a file stream) which is used for actual reads to the buffer and writes from the buffer. The stream buffer is organized as five 8KB chunks in an array. The last chunk is the only one used for writing, the other four are a 32KB buffer for reading. As the final chunk gets filled, the class will drop off the first chunk (writing it to the underlying stream, and shift the other chunks in the array.} {Define this if you wish to see a trace of the stream usage in a file called C:\SlideWin.LOG} {.$DEFINE DebugTrace} interface uses SysUtils, Classes; const abSWChunkCount = 5; type TabSlidingWindowStream = class(TStream) protected {private} bsChunks : array [0..pred(abSWChunkCount)] of PByteArray; bsBufferStart : longint; bsLastPos : integer; bsCurChunk : integer; bsPosInChunk : integer; bsPosInBuffer : longint; bsSize : Longint; {count of bytes in stream} bsDirty : boolean; {whether the buffer is dirty or not} bsStream : TStream; {actual stream containing data} {$IFDEF DebugTrace} bsF : System.Text; {$ENDIF} protected procedure bsWriteChunk(aIndex : integer); procedure bsSlide; public constructor Create(aStream : TStream); {-create the buffered stream} destructor Destroy; override; {-destroy the buffered stream} procedure Flush; {-ensures that all dirty buffered data is flushed} function Read(var Buffer; Count : Longint) : Longint; override; {-read from the stream into a buffer} function Seek(Offset : Longint; Origin : Word) : Longint; override; {-seek to a particular point in the stream} function Write(const Buffer; Count : Longint) : Longint; override; {-write to the stream from a buffer} end; implementation const ChunkSize = 8192; {cannot be greater than MaxInt} {===Helper routines==================================================} procedure RaiseException(const S : string); begin raise Exception.Create(S); end; {====================================================================} {===TabSlidingWindowStream===========================================} constructor TabSlidingWindowStream.Create(aStream : TStream); var i : integer; begin inherited Create; {save the actual stream} bsStream := aStream; {allocate the chunks-they must be set to binary zeros} for i := 0 to pred(abSWChunkCount) do bsChunks[i] := AllocMem(ChunkSize); {set the page/buffer variables to the start of the stream; remember we only write to the last chunk--the previous chunks are set to binary zeros} aStream.Position := 0; bsSize := 0; bsBufferStart := -ChunkSize * pred(abSWChunkCount); bsPosInBuffer := ChunkSize * pred(abSWChunkCount); bsCurChunk := pred(abSWChunkCount); bsPosInChunk := 0; bsDirty := false; {$IFDEF DebugTrace} System.Assign(bsF, 'c:\SlideWin.LOG'); if FileExists('c:\SlideWin.LOG') then System.Append(bsF) else System.Rewrite(bsF); writeln(bsF, '---NEW LOG---'); {$ENDIF} end; {--------} destructor TabSlidingWindowStream.Destroy; var i : integer; begin {destroy the buffer, after writing it to the actual stream} if bsDirty then Flush; for i := 0 to pred(abSWChunkCount) do if (bsChunks[i] <> nil) then FreeMem(bsChunks[i], ChunkSize); {$IFDEF DebugTrace} System.Close(bsF); {$ENDIF} {let our ancestor clean up} inherited Destroy; end; {--------} procedure TabSlidingWindowStream.bsSlide; var SavePtr : PByteArray; i : integer; begin {write out the first chunk} bsWriteChunk(0); {slide the chunks around} SavePtr := bsChunks[0]; for i := 0 to abSWChunkCount-2 do bsChunks[i] := bsChunks[i+1]; bsChunks[pred(abSWChunkCount)] := SavePtr; {advance the buffer start position} inc(bsBufferStart, ChunkSize); {reset the write position} bsPosInChunk := 0; bsPosInBuffer := ChunkSize * pred(abSWChunkCount); bsLastPos := 0; end; {--------} procedure TabSlidingWindowStream.bsWriteChunk(aIndex : integer); var SeekResult : longint; BytesWrit : longint; Offset : longint; BytesToWrite : integer; begin Offset := bsBufferStart + (longint(aIndex) * ChunkSize); if (Offset >= 0) then begin SeekResult := bsStream.Seek(Offset, 0); if (SeekResult = -1) then RaiseException('TabSlidingWindowStream.bsWriteChunk: seek failed'); if (aIndex <> pred(abSWChunkCount)) then BytesToWrite := ChunkSize else BytesToWrite := bsLastPos; BytesWrit := bsStream.Write(bsChunks[aIndex]^, BytesToWrite); if (BytesWrit <> BytesToWrite) then RaiseException('TabSlidingWindowStream.bsWriteChunk: write failed'); end; end; {--------} procedure TabSlidingWindowStream.Flush; var i : integer; begin if bsDirty then begin for i := 0 to pred(abSWChunkCount) do bsWriteChunk(i); bsDirty := false; end; end; {--------} function TabSlidingWindowStream.Read(var Buffer; Count : Longint) : Longint; var BufPtr : PByte; BytesToGo : Longint; BytesToRead : integer; begin BufPtr := @Buffer; {$IFDEF DebugTrace} System.Writeln(bsF, 'Read: ', Count, ' bytes'); {$ENDIF} {we do not support reads greater than 32KB bytes} if (Count > 32*1024) then Count := 32*1024; {reading is complicated by the fact we can only read in chunks of ChunkSize: we need to partition out the overall read into a read from part of the chunk, zero or more reads from complete chunks and then a possible read from part of a chunk} {calculate the actual number of bytes we can read - this depends on the current position and size of the stream as well as the number of bytes requested} BytesToGo := Count; if (bsSize < (bsBufferStart + bsPosInBuffer + Count)) then BytesToGo := bsSize - (bsBufferStart + bsPosInBuffer); if (BytesToGo <= 0) then begin Result := 0; Exit; end; {remember to return the result of our calculation} Result := BytesToGo; {calculate the number of bytes we can read prior to the loop} BytesToRead := ChunkSize - bsPosInChunk; if (BytesToRead > BytesToGo) then BytesToRead := BytesToGo; {copy from the stream buffer to the caller's buffer} if (BytesToRead = 1) then BufPtr^ := bsChunks[bsCurChunk]^[bsPosInChunk] else Move(bsChunks[bsCurChunk]^[bsPosInChunk], BufPtr^, BytesToRead); {calculate the number of bytes still to read} dec(BytesToGo, BytesToRead); {while we have bytes to read, read them} while (BytesToGo > 0) do begin {advance the pointer for the caller's buffer} inc(BufPtr, BytesToRead); {as we've exhausted this chunk, advance to the next} inc(bsCurChunk); bsPosInChunk := 0; {calculate the number of bytes we can read in this cycle} BytesToRead := ChunkSize; if (BytesToRead > BytesToGo) then BytesToRead := BytesToGo; {copy from the stream buffer to the caller's buffer} Move(bsChunks[bsCurChunk]^, BufPtr^, BytesToRead); {calculate the number of bytes still to read} dec(BytesToGo, BytesToRead); end; {remember our new position} inc(bsPosInChunk, BytesToRead); end; {--------} function TabSlidingWindowStream.Seek(Offset : Longint; Origin : Word) : Longint; {$IFDEF DebugTrace} const OriginStr : array [0..2] of string[7] = ('start', 'current', 'end'); {$ENDIF} var NewPos : Longint; begin {$IFDEF DebugTrace} System.Writeln(bsF, 'Seek: ', Offset, ' bytes from ', OriginStr[Origin]); {$ENDIF} {calculate the new position} case Origin of soFromBeginning : NewPos := Offset; soFromCurrent : NewPos := bsBufferStart + bsPosInBuffer + Offset; soFromEnd : NewPos := bsSize + Offset; else NewPos := 0; RaiseException('TabSlidingWindowStream.Seek: invalid origin'); end; {if the new position is invalid, say so} if (NewPos < bsBufferStart) or (NewPos > bsSize) then RaiseException('TabSlidingWindowStream.Seek: invalid new position'); {calculate the chunk number and the position in buffer & chunk} bsPosInBuffer := NewPos - bsBufferStart; bsCurChunk := bsPosInBuffer div ChunkSize; bsPosInChunk := bsPosInBuffer mod ChunkSize; {return the new position} Result := NewPos; end; {--------} function TabSlidingWindowStream.Write(const Buffer; Count : Longint) : Longint; var BufPtr : PByte; BytesToGo : Longint; BytesToWrite: integer; begin BufPtr := @Buffer; {$IFDEF DebugTrace} System.Writeln(bsF, 'Write: ', Count, ' bytes'); {$ENDIF} {we ONLY write at the end of the stream} if ((bsBufferStart + bsPosInBuffer) <> bsSize) then RaiseException('TabSlidingWindowStream.Write: Not at end of stream'); {we do not support writes greater than 32KB bytes} if (Count > 32*1024) then Count := 32*1024; {writing is complicated by the fact we write in chunks of Chunksize bytes: we need to partition out the overall write into a write to part of the chunk, zero or more writes to complete chunks and then a possible write to part of a chunk; every time we fill a chunk we have toi slide the buffer} {when we write to this stream we always assume that we can write the requested number of bytes: if we can't (eg, the disk is full) we'll get an exception somewhere eventually} BytesToGo := Count; {remember to return the result of our calculation} Result := BytesToGo; {calculate the number of bytes we can write prior to the loop} BytesToWrite := ChunkSize - bsPosInChunk; if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy from the caller's buffer to the stream buffer} if (BytesToWrite = 1) then bsChunks[pred(abSWChunkCount)]^[bsPosInChunk] := BufPtr^ else Move(BufPtr^, bsChunks[pred(abSWChunkCount)]^[bsPosInChunk], BytesToWrite); {mark our buffer as requiring a save to the actual stream} bsDirty := true; {calculate the number of bytes still to write} dec(BytesToGo, BytesToWrite); {while we have bytes to write, write them} while (BytesToGo > 0) do begin {slide the buffer} bsSlide; {advance the pointer for the caller's buffer} inc(BufPtr, BytesToWrite); {calculate the number of bytes we can write in this cycle} BytesToWrite := ChunkSize; if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy from the caller's buffer to our buffer} Move(BufPtr^, bsChunks[pred(abSWChunkCount)]^, BytesToWrite); {calculate the number of bytes still to write} dec(BytesToGo, BytesToWrite); end; {remember our new position} inc(bsPosInChunk, BytesToWrite); bsPosInBuffer := (longint(ChunkSize) * pred(abSWChunkCount)) + bsPosInChunk; bsLastPos := bsPosInChunk; {make sure the stream size is correct} inc(bsSize, Result); {if we're at the end of the chunk, slide the buffer ready for next time we write} if (bsPosInChunk = ChunkSize) then bsSlide; end; {====================================================================} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abtartyp.pas�����������������������������������������0000644�0001750�0000144�00000272614�14743153644�022777� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Joel Haynie * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbTarTyp.pas *} {*********************************************************} {* ABBREVIA: TAbTarArchive, TAbTarItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with Tar files *} {*********************************************************} unit AbTarTyp; {$I AbDefine.inc} interface uses Classes, AbUtils, AbArcTyp; const AB_TAR_RECORDSIZE = 512; {Note: SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE} AB_TAR_NAMESIZE = 100; AB_TAR_V7_EMPTY_SIZE = 167; AB_TAR_USTAR_PREFIX_SIZE = 155; AB_TAR_STAR_PREFIX_SIZE = 131; AB_TAR_OLD_GNU_EMPTY1_SIZE = 5; AB_TAR_OLD_GNU_SPARSE_SIZE = 96; AB_TAR_OLD_GNU_EMPTY2_SIZE = 17; AB_TAR_SIZE_AFTER_STDHDR = 167; AB_TAR_TUSRNAMELEN = 32; AB_TAR_TGRPNAMELEN = 32; { The checksum field is filled with this while the checksum is computed. } AB_TAR_CHKBLANKS = ' '; { 8 blank spaces(#20), no null } AB_TAR_L_HDR_NAME = '././@LongLink'; { As seen in the GNU File Examples} AB_TAR_L_HDR_USR_NAME='root'; { On Cygwin this is #0, Redhat it is 'root' } AB_TAR_L_HDR_GRP_NAME='root'; { Same on all OS's } AB_TAR_L_HDR_ARR8_0 ='0000000'#0; { 7 zeros and one null } AB_TAR_L_HDR_ARR12_0 ='00000000000'#0;{ 11 zeros and one null } AB_TAR_MAGIC_VAL = 'ustar'#0; { 5 chars & a nul } AB_TAR_MAGIC_VER = '00'; { 2 chars } AB_TAR_MAGIC_GNUOLD = 'ustar '#0; { 7 chars & a null } AB_TAR_MAGIC_V7_NONE = #0#0#0#0#0#0#0#0;{ 8, #0 } { The linkflag defines the type of file(FH), and Meta Data about File(MDH) } AB_TAR_LF_OLDNORMAL = #0; { FH, Normal disk file, Unix compatible } { Historically used for V7 } AB_TAR_LF_NORMAL = '0'; { FH, Normal disk file } AB_TAR_LF_LINK = '1'; { FH, Link to previously archived file } AB_TAR_LF_SYMLINK = '2'; { FH, Symbolic(soft) link } AB_TAR_LF_CHR = '3'; { FH, Character special file }{ Used for device nodes, Conditionally compiled into GNUTAR } AB_TAR_LF_BLK = '4'; { FH, Block special file }{ Used for device nodes, Conditionally compiled into GNUTAR } AB_TAR_LF_DIR = '5'; { FH, Directory, Zero size File } AB_TAR_LF_FIFO = '6'; { FH, FIFO special file }{ Used for fifo files(pipe like), Conditionally complied into GNUTAR } AB_TAR_LF_CONTIG = '7'; { FH, Contiguous file } { Normal File, but All blocks should be contiguos on the disk } AB_TAR_LF_XHDR = 'x'; { MDH, POSIX, Next File has Extended Header } AB_TAR_LF_XGL = 'g'; { MDH, POSIX, Global Extended Header } AB_TAR_LF_DUMPDIR = 'D'; { FH, Extra GNU, Dump Directory} { Generated Dump of Files in a directory, has a size } AB_TAR_LF_LONGLINK = 'K'; { MDH, Extra GNU, Next File has Long LinkName} AB_TAR_LF_LONGNAME = 'L'; { MDH, Extra GNU, Next File has Long Name} AB_TAR_LF_MULTIVOL = 'M'; { FH, Extra GNU, MultiVolume File Cont.}{ End of a file that spans multiple TARs } AB_TAR_LF_SPARSE = 'S'; { FH, Extra GNU, Sparse File Cont.} AB_TAR_LF_VOLHDR = 'V'; { FH, Extra GNU, File is Volume Header } AB_TAR_LF_EXHDR = 'X'; { MDH, Extra GNU, Solaris Extended Header } { The only questionable MetaData type is 'V', file or meta-data? will treat as file header } AB_SUPPORTED_F_HEADERS = [AB_TAR_LF_OLDNORMAL, AB_TAR_LF_NORMAL, AB_TAR_LF_LINK, AB_TAR_LF_SYMLINK, AB_TAR_LF_DIR]; AB_UNSUPPORTED_F_HEADERS = [AB_TAR_LF_CHR, AB_TAR_LF_BLK, AB_TAR_LF_FIFO, AB_TAR_LF_CONTIG, AB_TAR_LF_DUMPDIR, AB_TAR_LF_MULTIVOL, AB_TAR_LF_SPARSE, AB_TAR_LF_VOLHDR]; AB_SUPPORTED_MD_HEADERS = [AB_TAR_LF_LONGNAME, AB_TAR_LF_LONGLINK]; AB_UNSUPPORTED_MD_HEADERS= [AB_TAR_LF_XHDR, AB_TAR_LF_XGL, AB_TAR_LF_EXHDR]; AB_GNU_MD_HEADERS = [AB_TAR_LF_LONGLINK, AB_TAR_LF_LONGNAME]; { If present then OLD_/GNU_FORMAT } AB_PAX_MD_HEADERS = [AB_TAR_LF_XHDR, AB_TAR_LF_XGL]; { If present then POSIX_FORMAT } AB_IGNORE_SIZE_HEADERS = [AB_TAR_LF_LINK, AB_TAR_LF_SYMLINK, AB_TAR_LF_CHR, AB_TAR_LF_BLK, AB_TAR_LF_DIR, AB_TAR_LF_FIFO]; { The rest of the Chars are unsupported and unknown types Treat those headers as File types } { Further link types may be defined later. } { Bits used in the mode field - values in octal } AB_TAR_TSUID = $0800; { Set UID on execution } AB_TAR_TSGID = $0400; { Set GID on execution } AB_TAR_TSVTX = $0200; { Save text (sticky bit) } type Arr8 = array [0..7] of AnsiChar; Arr12 = array [0..11] of AnsiChar; Arr12B = array[0..11] of Byte; ArrName = array [0..AB_TAR_NAMESIZE-1] of AnsiChar; TAbTarHeaderFormat = (UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT); TAbTarItemType = (SUPPORTED_ITEM, UNSUPPORTED_ITEM, UNKNOWN_ITEM); TAbTarHeaderType = (FILE_HEADER, META_DATA_HEADER, MD_DATA_HEADER, UNKNOWN_HEADER); TAbTarMagicType = (GNU_OLD, NORMAL); TAbTarMagicRec = packed record case TAbTarMagicType of GNU_OLD: (gnuOld : array[0..7] of AnsiChar); { Old GNU magic: (Magic.gnuOld) } NORMAL : (value : array[0..5] of AnsiChar; { Magic value: (Magic.value)} version: array[0..1] of AnsiChar); { Version: (Magic.version) } end; { Notes from GNU Tar & POSIX Spec.: } {All the first 345 bytes are the same. } { "USTAR_header": Prefix(155): 345-499, empty(12): 500-511 } { "old_gnu_header": atime(12): 345-356, ctime(12): 357-368, offset(12): 369-380, longnames(4): 381-384, empty(1): 385, sparse structs(4x(12+12)=96): 386-481, isextended(1): 482, realsize(12): 483-494, empty(16): 495-511 } { "star_header": Prefix(131): 345-475, atime(12): 476-487, ctime(12): 488-499, empty(12): 500-511 } { "star_in_header": prefix(1): 345, empty(9): 346-354, isextended(1): 355, sparse structs(4x(12+12)=96): 356-451, realsize(12): 452-463, offset(12): 464-475, atime(12): 476-487, ctime(12): 488-499, empty(8): 500-507, xmagic(4): 508-511 } { "sparse_header": These two structs are the same, and they are Meta data about file. } {"star_ext_header": sparse structs(21x(12+12)=504): 0-503, isextended(1): 504 } {POSIX(PAX) extended header: is a buffer packed with content of this form: This if from the POSIX spec. References the C printf command string. "%d %s=%s\n". Then they are simply concatenated. } { PAX Extended Header Keywords: } { 'atime', 'charset', 'comment', 'ctime', 'gid', 'gname', 'linkpath', 'mtime', 'path', 'realtime.', 'security.', 'size', 'uid', 'uname' } { GNU Added PAX Extended Header Keywords: } { 'GNU.sparse.name', 'GNU.sparse.major', 'GNU.sparse.minor', 'GNU.sparse.realsize', 'GNU.sparse.numblocks', 'GNU.sparse.size', 'GNU.sparse.offset', 'GNU.sparse.numbytes', 'GNU.sparse.map', 'GNU.dumpdir', 'GNU.volume.label', 'GNU.volume.filename', 'GNU.volume.size', 'GNU.volume.offset' } { V7 uses AB_TAR_LF_OLDNORMAL linkflag, has no magic field & no Usr/Grp Names } { V7 Format ends Empty(padded with zeros), as does the POSIX record. } TAbTarEnd_Empty_Rec = packed record Empty: array[0..AB_TAR_V7_EMPTY_SIZE-1] of Byte; { 345-511, $159-1FF, Empty Space } end; { UStar End Format } TAbTarEnd_UStar_Rec = packed record Prefix: array[0..AB_TAR_USTAR_PREFIX_SIZE-1] of AnsiChar; { 345-499, $159-1F3, Prefix of file & path name, null terminated ASCII string } Empty : Arr12B;{ 500-512, $1F4-1FF, Empty Space } end; { Old GNU End Format } TAbTarEnd_GNU_old_Rec = packed record Atime : Arr12; { 345-356, $159-164, time of last access (UNIX Date in ASCII coded Octal)} Ctime : Arr12; { 357-368, $165-170, time of last status change (UNIX Date in ASCII coded Octal)} Offset: Arr12; { 369-380, $171-17C, Multirecord specific value } Empty1: array[0..AB_TAR_OLD_GNU_EMPTY1_SIZE-1] of Byte; { 381-385, $17D-181, Empty Space, Once contained longname ref. } Sparse: array[0..AB_TAR_OLD_GNU_SPARSE_SIZE-1] of Byte; { 386-481, $182-1E1, Sparse File specific values } IsExtended: byte;{ 482, $ 1E2, Flag to signify Sparse file headers follow } RealSize: Arr12;{ 483-494, $1E3-1EE, Real size of a Sparse File. } Empty2: array[0..AB_TAR_OLD_GNU_EMPTY2_SIZE-1] of Byte; { 495-511, $1EF-1FF, Empty Space } end; { Star End Format } TAbTarEnd_Star_Rec = packed record Prefix: array[0..AB_TAR_STAR_PREFIX_SIZE-1] of AnsiChar; { 345-499, $159-1F3, prefix of file & path name, null terminated ASCII string } Atime : Arr12; { 476-487, $1DC-1E7, time of last access (UNIX Date in ASCII coded Octal)} Ctime : Arr12; { 488-499, $1E8-1F3, time of last status change (UNIX Date in ASCII coded Octal)} Empty : Arr12B;{ 500-512, $1F4-1FF, Empty Space } end; { When support for sparse files is added, Add another record for sparse in header } { Note: SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE by design } PAbTarHeaderRec = ^TAbTarHeaderRec; { Declare pointer type for use in the list } TAbTarHeaderRec = packed record Name : ArrName; { 0- 99, $ 0- 63, filename, null terminated ASCII string, unless length is 100 } Mode : Arr8; { 100-107, $ 64- 6B, file mode (UNIX style, ASCII coded Octal) } uid : Arr8; { 108-115, $ 6C- 73, usrid # (UNIX style, ASCII coded Octal) } gid : Arr8; { 116-123, $ 74- 7B, grpid # (UNIX style, ASCII coded Octal) } Size : Arr12; { 124-135, $ 7C- 87, size of TARred file (ASCII coded Octal) } ModTime : Arr12; { 136-147, $ 88- 93, time of last modification.(UNIX Date in ASCII coded Octal) UTC time } ChkSum : Arr8; { 148-155, $ 94- 9B, checksum of header (6 bytes ASCII coded Octal, #00, #20) } LinkFlag: AnsiChar; { 156, $ 9C, type of item, one of the Link Flag constants from above } LinkName: ArrName; { 157-256, $ 9D-100, name of link, null terminated ASCII string } Magic : TAbTarMagicRec; { 257-264, $101-108, identifier, usually 'ustar'#00'00' } UsrName : array [0..AB_TAR_TUSRNAMELEN-1] of AnsiChar; { 265-296, $109-128, username, null terminated ASCII string } GrpName : array [0..AB_TAR_TGRPNAMELEN-1] of AnsiChar; { 297-328, $129-148, groupname, null terminated ASCII string } DevMajor: Arr8; { 329-336, $149-150, major device ID (UNIX style, ASCII coded Octal) } DevMinor: Arr8; { 337-344, $151-158, minor device ID (UNIX style, ASCII coded Octal) } case TAbTarHeaderFormat of{ 345-511, $159-1FF See byte Definitions above.} V7_FORMAT : ( v7 : TAbTarEnd_Empty_Rec ); OLDGNU_FORMAT: ( gnuOld: TAbTarEnd_GNU_old_Rec ); GNU_FORMAT : ( gnu : TAbTarEnd_GNU_old_Rec ); USTAR_FORMAT : ( ustar : TAbTarEnd_UStar_Rec ); STAR_FORMAT : ( star : TAbTarEnd_Star_Rec ); POSIX_FORMAT : ( pax : TAbTarEnd_Empty_Rec ); end;{ end TAbTarHeaderRec } { There are three main types of headers we will see in a Tar file } { TAbTarHeaderType = (STANDARD_HDR, SPARSE_HDR, POSIX_EXTENDED_HDR); } { The 1st is defined above, The later two are simply organized data types. } TAbTarItemRec = record { Note: that the actual The name needs to be coherient with the name Inherited from parent type TAbArchiveItem } Name : string; { Path & File name. } Mode : LongWord; { File Permissions } uid : Integer; { User ID } gid : Integer; { Group ID } Size : Int64; { Tared File size } ModTime : Int64; { Last time of Modification, in UnixTime } ChkSumPass : Boolean; { Header Check sum found to be good } LinkFlag : AnsiChar; { Link Flag, Echos the actual File Type of this Item. } ItemType : TAbTarItemType; { Item Type Assigned from LinkFlag Header Types. } LinkName : string; { Link Name } Magic : AnsiString; { Magic value } Version : Integer; { Version Number } UsrName : string; { User Name, for User ID } GrpName : string; { Group Name, for Group ID } DevMajor : Integer; { Major Device ID } DevMinor : Integer; { Minor Device ID } { Additional Types used for holding info. } AccessTime : Int64; { Time of Last Access, in UnixTime } ChangeTime : Int64; { Time of Last Status Change, in UnixTime } ArchiveFormat: TAbTarHeaderFormat; { Type of Archive of this record } StreamPosition: Int64; { Pointer to the top of the item in the file. } Dirty : Boolean; { Indication if this record needs to have its headers CheckSum recalculated } ItemReadOnly: Boolean; { Indication if this record is READ ONLY } FileHeaderCount:Integer;{ Number of Headers in the Orginal TarHeaders in the File Stream } end; type PTAbTarItem = ^TAbTarItem; TAbTarItem = class(TAbArchiveItem) private { The following private members are used for Stuffing FTarItem struct } procedure ParseTarHeaders; { Error in header if } procedure ParsePaxHeaders; { Error in header if } procedure DetectHeaderFormat; { Helper to stuff HeaderFormat } procedure GetFileNameFromHeaders; { Helper to pull name from Headers } procedure GetLinkNameFromHeaders; { Helper to pull name from Headers } function TestCheckSum: Boolean; { Helper to Calculate Checksum of a header. } procedure DoGNUExistingLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); procedure DoGNUNewLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); protected {private} PTarHeader: PAbTarHeaderRec;{ Points to FTarHeaderList.Items[FTarHeaderList.Count-1] } FTarHeaderList: TList; { List of The Headers } FTarHeaderTypeList: TList; { List of the Header Types } FTarItem: TAbTarItemRec; { Data about current TAR Item } protected function GetDevMajor: Integer; function GetDevMinor: Integer; function GetGroupID: Integer; function GetGroupName: string; function GetLinkName: string; function GetUserID: Integer; function GetUserName: string; function GetModTime: Int64; function GetNumHeaders: Integer; function GetMagic: string; { All Sets shall update the headers Or add headers as needed. } procedure SetDevMajor(const Value: Integer); procedure SetDevMinor(const Value: Integer); procedure SetGroupID(const Value: Integer); { Extended Headers } procedure SetGroupName(const Value: string); { Extended Headers } procedure SetLinkFlag(Value: AnsiChar); procedure SetLinkName(const Value: string); { Extended Headers } procedure SetUserID(const Value: Integer); { Extended Headers } procedure SetUserName(const Value: string); { Extended Headers } procedure SetModTime(const Value: Int64); Procedure SetMagic(const Value: string); { TODO: add support for Atime and Ctime here } { Overrides for Inherited Properties from type TAbArchiveItem } function GetCompressedSize : Int64; override; function GetExternalFileAttributes : LongWord; override; function GetFileName : string; override; function GetIsDirectory: Boolean; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetLastModTimeAsDateTime: TDateTime; override; function GetNativeFileAttributes : LongInt; override; function GetNativeLastModFileTime: Longint; override; function GetUncompressedSize : Int64; override; procedure SetCompressedSize(const Value : Int64); override; { Extended Headers } procedure SetExternalFileAttributes( Value : LongWord ); override; procedure SetFileName(const Value : string); override; { Extended Headers } procedure SetIsEncrypted(Value : Boolean); override; procedure SetLastModFileDate(const Value : Word); override; { Extended Headers } procedure SetLastModFileTime(const Value : Word); override; { Extended Headers } procedure SetLastModTimeAsDateTime(const Value: TDateTime); override; procedure SetUncompressedSize(const Value : Int64); override; { Extended Headers } procedure SaveTarHeaderToStream(AStream : TStream); procedure LoadTarHeaderFromStream(AStream : TStream); property Magic : string { Magic value } read GetMagic write SetMagic; public { property Name : STRING; Path & File name. Inherited from parent type TAbArchiveItem } { read GetFileName write SetFileName; overridden above} property Mode : LongWord { File Permissions } read GetExternalFileAttributes write SetExternalFileAttributes; property UserID : Integer { User ID } read GetUserID write SetUserID; property GroupID : Integer { Group ID } read GetGroupID write SetGroupID; property ModTime : Int64 read GetModTime write SetModTime; { property UncompressedSize/CompressedSize(Size): Int64; File size (comp/uncomp) Inherited from parent type TAbArchiveItem } { read GetUncompressedSize, GetCompressedSize; overridden above } { write SetUncompressedSize, SetCompressedSize; overridden above } { property LastModFileTime/LastModFileDate(ModeTime): TDateTime; Last time of Modification Inherited from parent type TAbArchiveItem } { read GetLastModFileTime, GetLastModFileDate; overridden above } { write SetLastModFileTime, SetLastModFileDate; overridden above } property CheckSumGood: Boolean read FTarItem.ChkSumPass; { Header Check sum found to be good } property LinkFlag : AnsiChar { Link Flag of File Header } read FTarItem.LinkFlag write SetLinkFlag; property LinkName : string { Link Name } read GetLinkName write SetLinkName; property UserName : string { User Name, for User ID } read GetUserName write SetUserName; property GroupName : string { Group Name, for Group ID } read GetGroupName write SetGroupName; property DevMajor : Integer { Major Device ID } read GetDevMajor write SetDevMajor; property DevMinor : Integer { Minor Device ID } read GetDevMinor write SetDevMinor; { TODO: Add support ATime and CTime } {AccessTime : TDateTime;} { Time of Last Access } {ChangeTime : TDateTime;} { Time of Last Status Change } { Additional Types used for holding info. } property ExternalFileAttributes; property ArchiveFormat: TAbTarHeaderFormat read FTarItem.ArchiveFormat write FTarItem.ArchiveFormat; property ItemType: TAbTarItemType read FTarItem.ItemType write FTarItem.ItemType; property ItemReadOnly: Boolean read FTarItem.ItemReadOnly write FTarItem.ItemReadOnly; property FileHeaderCount: Integer read FTarItem.FileHeaderCount; property HeaderCount: Integer read GetNumHeaders; property StreamPosition: Int64 read FTarItem.StreamPosition write FTarItem.StreamPosition; constructor Create; destructor Destroy; override; end; { end TAbArchiveItem } TAbTarStreamHelper = class(TAbArchiveStreamHelper) private function FindItem: Boolean; { Tool for FindFirst/NextItem functions } protected FOnProgress : TAbProgressEvent; FTarHeader : TAbTarHeaderRec; { Speed-up Buffer only } FCurrItemSize : Int64; { Current Item size } FCurrItemPreHdrs: Integer; { Number of Meta-data Headers before the Item } public constructor Create(AStream : TStream; AEvent : TAbProgressEvent); overload; destructor Destroy; override; procedure ExtractItemData(AStream : TStream); override; function FindFirstItem : Boolean; override; function FindNextItem : Boolean; override; procedure ReadHeader; override; procedure ReadTail; override; function SeekItem(Index : Integer): Boolean; override; procedure WriteArchiveHeader; override; procedure WriteArchiveItem(AStream : TStream); override; procedure WriteArchiveItemSize(AStream : TStream; ASize: Int64); procedure WriteArchiveTail; override; function GetItemCount : Integer; override; end; TAbTarArchive = class(TAbArchive) private FArchReadOnly : Boolean; FArchFormat: TAbTarHeaderFormat; protected FTargetStream: TStream; protected function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const UseName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function FixName(const Value: string): string; override; function GetSupportsEmptyFolders: Boolean; override; function GetItem(Index: Integer): TAbTarItem; procedure PutItem(Index: Integer; const Value: TAbTarItem); public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; property UnsupportedTypesDetected : Boolean read FArchReadOnly; property Items[Index : Integer] : TAbTarItem read GetItem write PutItem; default; end; procedure UnixAttrsToTarAttrs(const UnixAttrs: LongWord; out Permissions: LongWord; out LinkFlag: AnsiChar); procedure TarAttrsToUnixAttrs(const Permissions: LongWord; const LinkFlag: AnsiChar; out UnixAttrs: LongWord); function VerifyTar(Strm : TStream) : TAbArchiveType; implementation uses Math, RTLConsts, SysUtils, AbVMStrm, AbExcept, AbProgress, DCOSUtils, DCClassesUtf8, DCConvertEncoding, DCStrUtils; { ****************** Helper functions Not from Classes Above ***************** } function OctalToInt(const Oct : PAnsiChar; aLen : integer): Int64; var r : UInt64; i : integer; c, sign : Byte; begin Result := 0; if (aLen = 0 ) then Exit; { detect binary number format } if ((Ord(Oct[0]) and $80) <> 0) then begin c:= Ord(Oct[0]); if (c and $40 <> 0) then begin sign := $FF; r := High(UInt64); end else begin r := 0; sign := 0; c := c and $7F; end; i:= 1; while (aLen > SizeOf(Int64)) do begin if (c <> sign) then begin if (sign <> 0) then Result:= Low(Int64) else begin Result:= High(Int64); end; Exit; end; c := Ord(Oct[i]); Dec(aLen); Inc(i); end; if ((c xor sign) and $80 <> 0) then begin if (sign <> 0) then Result:= Low(Int64) else begin Result:= High(Int64); end; Exit; end; while (aLen > 1) do begin r := (r shl 8) or c; c:= Ord(Oct[i]); Dec(aLen); Inc(i); end; r := (r shl 8) or c; Exit(Int64(r)); end; i := 0; while (i < aLen) and (Oct[i] = ' ') do inc(i); if (i = aLen) then Exit; while (i < aLen) and (Oct[i] in ['0'..'7']) do begin Result := (Result * 8) + (Ord(Oct[i]) - Ord('0')); inc(i); end; end; function IntToOctal(Value : Int64): AnsiString; const OctDigits : array[0..7] of AnsiChar = '01234567'; begin if Value = 0 then Result := '0' else begin Result := ''; while Value > 0 do begin Result := OctDigits[Value and 7] + Result; Value := Value shr 3; end; end; end; function CalcTarHeaderChkSum(const TarH : TAbTarHeaderRec): LongInt; var HdrBuffer : PAnsiChar; HdrChkSum : LongInt; j : Integer; begin { prepare for the checksum calculation } HdrBuffer := PAnsiChar(@TarH); HdrChkSum := 0; {calculate the checksum, a simple sum of the bytes in the header} for j := 0 to Pred(SizeOf(TAbTarHeaderRec)) do HdrChkSum := HdrChkSum + Ord(HdrBuffer[j]); Result := HdrChkSum; end; function VerifyTar(Strm : TStream) : TAbArchiveType; { assumes Tar positioned correctly for test of item } var TarItem : TAbTarItem; StartPos : Int64; begin StartPos := Strm.Position; try { Verifies that the header checksum is valid, and Item type is understood. This does not mean that extraction is supported. } TarItem := TAbTarItem.Create; try { get current Tar Header } TarItem.LoadTarHeaderFromStream(Strm); if TarItem.CheckSumGood then Result := atTar else Result := atUnknown; finally TarItem.Free; end; except on EReadError do Result := atUnknown; end; Strm.Position := StartPos; end; function PadString(const S : AnsiString; Places : Integer) : AnsiString; { Pads a string (S) with one right space and as many left spaces as needed to fill Places If length S greater than Places, just returns S Some TAR utilities evidently expect Octal numeric fields to be in this format } begin if Length(S) >= LongInt(Places) then Result := S else begin Result := S + ' '; Result := StringOfChar(AnsiChar(' '), Places - Length(Result)) + Result; end; end; { Round UP to the nearest Tar Block Boundary. } function RoundToTarBlock(Size: Int64) : Int64; begin Result := (Size + (AB_TAR_RECORDSIZE - 1)) and not (AB_TAR_RECORDSIZE - 1); end; procedure UnixAttrsToTarAttrs(const UnixAttrs: LongWord; out Permissions: LongWord; out LinkFlag: AnsiChar); begin case (UnixAttrs and $F000) of AB_FMODE_SOCKET: ; AB_FMODE_FILELINK: LinkFlag := AB_TAR_LF_SYMLINK; AB_FMODE_FILE2: LinkFlag := AB_TAR_LF_NORMAL; AB_FMODE_BLOCKSPECFILE: LinkFlag := AB_TAR_LF_BLK; AB_FMODE_DIR: LinkFlag := AB_TAR_LF_DIR; AB_FMODE_CHARSPECFILE: LinkFlag := AB_TAR_LF_CHR; AB_FMODE_FIFO: LinkFlag := AB_TAR_LF_FIFO; AB_FMODE_FILE: LinkFlag := AB_TAR_LF_NORMAL; else LinkFlag := AB_TAR_LF_OLDNORMAL; end; Permissions := (UnixAttrs and $0FFF); end; { -------------------------------------------------------------------------- } procedure TarAttrsToUnixAttrs(const Permissions: LongWord; const LinkFlag: AnsiChar; out UnixAttrs: LongWord); begin case LinkFlag of AB_TAR_LF_OLDNORMAL: UnixAttrs := AB_FMODE_FILE; AB_TAR_LF_NORMAL: UnixAttrs := AB_FMODE_FILE2; AB_TAR_LF_SYMLINK: UnixAttrs := AB_FMODE_FILELINK; AB_TAR_LF_BLK: UnixAttrs := AB_FMODE_BLOCKSPECFILE; AB_TAR_LF_DIR: UnixAttrs := AB_FMODE_DIR; AB_TAR_LF_CHR: UnixAttrs := AB_FMODE_CHARSPECFILE; AB_TAR_LF_FIFO: UnixAttrs := AB_FMODE_FIFO; else UnixAttrs := AB_FMODE_FILE; end; UnixAttrs := UnixAttrs or (Permissions and $0FFF); end; { ****************************** TAbTarItem ********************************** } constructor TAbTarItem.Create; begin inherited Create; FTarHeaderList := TList.Create; FTarHeaderTypeList := TList.Create; GetMem(PTarHeader, AB_TAR_RECORDSIZE); { PTarHeader is our new Header } FillChar(PTarHeader^, AB_TAR_RECORDSIZE, #0); FTarHeaderList.Add(PTarHeader); FTarHeaderTypeList.Add(Pointer(FILE_HEADER)); FTarItem.FileHeaderCount := 1; { set defaults } FTarItem.ArchiveFormat := UNKNOWN_FORMAT; FileName := ''; Mode := AB_FPERMISSION_GENERIC; UserID := 0; GroupID := 0; UncompressedSize := 0; { ModTime } LinkFlag := AB_TAR_LF_OLDNORMAL; { Link Name } PTarHeader.Magic.gnuOld := AB_TAR_MAGIC_V7_NONE; { Default to GNU type } UserName := ''; GroupName := ''; DevMajor := 0; DevMinor := 0; { TODO: atime, ctime } FTarItem.ItemType := SUPPORTED_ITEM; FTarItem.Dirty := True; { Checksum needs to be generated } FTarItem.ItemReadOnly := False; end; destructor TAbTarItem.Destroy; var i : Integer; begin if Assigned(FTarHeaderList) then begin for i := 0 to FTarHeaderList.Count - 1 do FreeMem(FTarHeaderList.Items[i]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Free; end; FTarHeaderTypeList.Free; inherited Destroy; end; function TAbTarItem.GetCompressedSize: Int64; { TAR includes no internal compression, returns same value as GetUncompressedSize } begin Result := FTarItem.Size; end; function TAbTarItem.GetDevMajor: Integer; begin Result := FTarItem.DevMajor; end; function TAbTarItem.GetDevMinor: Integer; begin Result := FTarItem.DevMinor; end; function TAbTarItem.GetExternalFileAttributes: LongWord; begin TarAttrsToUnixAttrs(FTarItem.Mode, FTarItem.LinkFlag, Result); end; function TAbTarItem.GetFileName: string; begin Result := FTarItem.Name; { Inherited String from Parent Class } end; function TAbTarItem.GetGroupID: Integer; begin Result := FTarItem.gid; end; function TAbTarItem.GetGroupName: string; begin Result := FTarItem.GrpName; end; function TAbTarItem.GetIsDirectory: Boolean; begin Result := (LinkFlag = AB_TAR_LF_DIR); end; function TAbTarItem.GetIsEncrypted: Boolean; begin { TAR has no native encryption } Result := False; end; function TAbTarItem.GetLastModFileDate: Word; begin { convert to local DOS file Date } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Hi; end; function TAbTarItem.GetLastModFileTime: Word; begin { convert to local DOS file Time } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Lo; end; function TAbTarItem.GetLastModTimeAsDateTime: TDateTime; begin Result := AbUnixTimeToLocalDateTime(FTarItem.ModTime); end; function TAbTarItem.GetNativeLastModFileTime: Longint; {$IFDEF MSWINDOWS} var DateTime: TDateTime; {$ENDIF} begin Result := Self.ModTime; {$IFDEF MSWINDOWS} DateTime := AbUnixTimeToLocalDateTime(Result); Result := AbDateTimeToDosFileDate(DateTime); {$ENDIF} end; function TAbTarItem.GetLinkName: string; begin Result := FTarItem.LinkName; end; function TAbTarItem.GetMagic: string; begin Result := string(FTarItem.Magic); end; function TAbTarItem.GetNativeFileAttributes : LongInt; begin Result := GetExternalFileAttributes; {$IFDEF MSWINDOWS} Result := AbUnix2DosFileAttributes(Result); {$ENDIF} end; function TAbTarItem.GetUncompressedSize: Int64; { TAR includes no internal compression, returns same value as GetCompressedSize } begin Result := FTarItem.Size; end; function TAbTarItem.GetUserID: Integer; begin Result := FTarItem.uid; end; function TAbTarItem.GetUserName: string; begin Result := FTarItem.UsrName; end; function TAbTarItem.GetModTime: Int64; begin Result := FTarItem.ModTime; end; { Get Number of tar headers currently for this item } function TAbTarItem.GetNumHeaders: Integer; begin Result := FTarHeaderList.Count; end; { Takes data from Supported Header types stored in TAbTarItem.FTarHeaderList } { and updates values in the TAbTarItem.FTarItem.X } procedure TAbTarItem.DetectHeaderFormat; begin if FTarItem.ArchiveFormat <> UNKNOWN_FORMAT then Exit;{ We have already set the format. } { In the previous header parsing if pax headers are detected the format is changed } { GNU_FORMAT is detected by the presence of GNU extended headers. } { These detections are similar to GNU tar's. } if CompareByte(PTarHeader.Magic.value, AB_TAR_MAGIC_VAL, SizeOf(AB_TAR_MAGIC_VAL)) = 0 then begin { We have one of three types, STAR_FORMAT, USTAR_FORMAT, POSIX_FORMAT } { Detect STAR format. Leave disabled until explicit STAR support is added. } {if (PTarHeader.star.Prefix[130] = #00) and (PTarHeader.star.Atime[0] in ['0'..'7']) and (PTarHeader.star.Atime[11] = #20) and (PTarHeader.star.Ctime[0]in ['0'..'7']) and (PTarHeader.star.Ctime[11] = #20) then begin FTarItme.ArchiveType := STAR_FORMAT; end } { else if } { POSIX uses the existance of x headers } { This can define false positives, Pax headers/ STAR format could be detected as this } FTarItem.ArchiveFormat := USTAR_FORMAT; end else if CompareByte(PTarHeader.Magic.gnuOld, AB_TAR_MAGIC_GNUOLD, SizeOf(AB_TAR_MAGIC_GNUOLD)) = 0 then begin FTarItem.ArchiveFormat := OLDGNU_FORMAT; end else { V7 uses AB_TAR_LF_OLDNORMAL linkflag, has no magic field & no Usr/Grp Names } begin FTarItem.ArchiveFormat := V7_FORMAT; { Lowest Common Denominator } end; end; { Extract the file name from the headers } procedure TAbTarItem.GetFileNameFromHeaders; var I, J : Integer; PHeader: PAbTarHeaderRec; FoundName: Boolean; NameLength : Int64; NumMHeaders: integer; ExtraName: integer; RawFileName, TempStr: AnsiString; begin { UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT } FoundName := False; I := 0; while (not FoundName) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGNAME then begin FoundName := True; RawFileName := ''; NameLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size)); NumMHeaders := NameLength div AB_TAR_RECORDSIZE; ExtraName := NameLength mod AB_TAR_RECORDSIZE; { Chars in the last Header } { NumMHeaders should never be zero } { It appears that it is not null terminated in the blocks } for J := 1 to NumMHeaders do begin { Copy entire content of Header to String } PHeader := FTarHeaderList.Items[I+J]; SetString(TempStr, PAnsiChar(PHeader), AB_TAR_RECORDSIZE); RawFileName := RawFileName + TempStr; end; if ExtraName <> 0 then begin PHeader := FTarHeaderList.Items[I+NumMHeaders+1]; SetString(TempStr, PAnsiChar(PHeader), ExtraName-1); RawFileName := RawFileName + TempStr; end else { We already copied the entire name, but the string is still null terminated. } begin { Removed the last zero } SetLength(RawFileName, (Length(RawFileName)-1)); end; end { end long filename link flag } else I := I + 1; end; { End While } if not FoundName then begin if (FTarItem.ArchiveFormat = USTAR_FORMAT) and (PTarHeader.ustar.Prefix[0] <> #0) then RawFileName := PTarHeader.ustar.Prefix+'/'+PTarHeader.Name else { V7_FORMAT, OLDGNU_FORMAT } RawFileName := PTarHeader.Name; end; { End not FoundName } FTarItem.Name := CeRawToUtf8(RawFileName); end; { Extract the file name from the headers } procedure TAbTarItem.GetLinkNameFromHeaders; var I, J : Integer; PHeader: PAbTarHeaderRec; FoundName: Boolean; NameLength : Int64; NumMHeaders: integer; ExtraName: integer; RawLinkName, TempStr: AnsiString; begin { UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT } PHeader := nil; FoundName := False; I := 0; { Note that: FTarHeaderList.Count <= 1, always } while (not FoundName) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGLINK then begin FoundName := True; RawLinkName := ''; NameLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size)); NumMHeaders := NameLength div AB_TAR_RECORDSIZE; ExtraName := NameLength mod AB_TAR_RECORDSIZE; { Chars in the last Header } { NumMHeaders should never be zero } { It appears that it is not null terminated in the blocks } for J := 1 to NumMHeaders do begin { Copy entire content of Header to String } PHeader := FTarHeaderList.Items[I+J]; SetString(TempStr, PAnsiChar(PHeader), AB_TAR_RECORDSIZE); RawLinkName := RawLinkName + TempStr; end; if ExtraName <> 0 then begin PHeader := FTarHeaderList.Items[I+NumMHeaders+1]; SetString(TempStr, PAnsiChar(PHeader), ExtraName-1); RawLinkName := RawLinkName + TempStr; end else { We already copied the entire name, but the string is still null terminated. } begin { Removed the last zero } SetLength(RawLinkName, (Length(RawLinkName)-1)); end; end { end long filename link flag } else I := I + 1; end; { End While } if not FoundName then RawLinkName := PHeader.LinkName; FTarItem.LinkName := CeRawToUtf8(RawLinkName); end; { Return True if CheckSum passes out. } function TAbTarItem.TestCheckSum : Boolean; var TarChkSum : LongInt; TarChkSumArr : Arr8; { ChkSum field is Arr8 } PHeader: PAbTarHeaderRec; I: Integer; begin Result := True; { Check sums are in valid headers but NOT in the data headers. } for I := 0 to FTarHeaderList.Count - 1 do begin if TAbTarHeaderType(FTarHeaderTypeList.Items[I]) in [FILE_HEADER, META_DATA_HEADER] then begin PHeader := FTarHeaderList.Items[i]; { Save off old Check sum } Move(PHeader.ChkSum, TarChkSumArr, SizeOf(PHeader.ChkSum)); TarChkSum := OctalToInt(TarChkSumArr, SizeOf(TarChkSumArr)); { Set to Generator Value } PHeader.ChkSum := AB_TAR_CHKBLANKS; if CalcTarHeaderChkSum(PHeader^) <> TarChkSum then Result := False; { Pass unless one miss-compares } { Save back old checksum } Move(TarChkSumArr, PHeader.ChkSum, SizeOf(TarChkSumArr)); end; end; end; procedure TAbTarItem.ParseTarHeaders; begin { The final index is the Item index } DetectHeaderFormat; { Long term this parsing is not correct, as the values in extended headers override the later values in this header } FTarItem.Mode := OctalToInt(PTarHeader.Mode, SizeOf(PTarHeader.Mode)); FTarItem.uid := OctalToInt(PTarHeader.uid, SizeOf(PTarHeader.uid)); { Extended in PAX Headers } FTarItem.gid := OctalToInt(PTarHeader.gid, SizeOf(PTarHeader.gid)); { Extended in PAX Headers } FTarItem.Size := OctalToInt(PTarHeader.Size, SizeOf(PTarHeader.Size)); { Extended in PAX Headers } { ModTime should be an Int64 but no tool support, No issues until Feb 6th, 2106 :) } { ModTime is Extended in PAX Headers } FTarItem.ModTime := OctalToInt(PTarHeader.ModTime, SizeOf(PTarHeader.ModTime)); FTarItem.ChkSumPass := TestCheckSum(); FTarItem.LinkFlag := PTarHeader.LinkFlag; GetLinkNameFromHeaders; { Extended in PAX Headers } FTarItem.Magic := PTarHeader.Magic.value; FTarItem.Version := OctalToInt(PTarHeader.Magic.version, SizeOf(PTarHeader.Magic.version)); FTarItem.UsrName := string(PTarHeader.UsrName); { Extended in PAX Headers } FTarItem.GrpName := string(PTarHeader.GrpName); { Extended in PAX Headers } FTarItem.DevMajor := OctalToInt(PTarHeader.DevMajor, SizeOf(PTarHeader.DevMajor)); FTarItem.DevMinor := OctalToInt(PTarHeader.DevMinor, SizeOf(PTarHeader.DevMinor)); GetFileNameFromHeaders; { FTarItem.ArchiveFormat; Already stuffed } { FTarItem.StreamPosition: Already Stuffed } { FTarItem.Dirty; Stuffed upon creaction } end; procedure TAbTarItem.ParsePaxHeaders; var I, J : Integer; ALength: Integer; RawLength: Int64; RawExtra: Integer; S, P, O: PAnsiChar; NumMHeaders: Integer; PHeader: PAbTarHeaderRec; AName, AValue: AnsiString; RawValue, TempStr: AnsiString; begin RawValue := EmptyStr; for I := 0 to FTarHeaderList.Count - 1 do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_XHDR then begin RawLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size)); // Number of headers NumMHeaders := RawLength div AB_TAR_RECORDSIZE; // Chars in the last header RawExtra := RawLength mod AB_TAR_RECORDSIZE; // Copy data from headers for J := 1 to NumMHeaders do begin PHeader := FTarHeaderList.Items[I + J]; SetString(TempStr, PAnsiChar(PHeader), AB_TAR_RECORDSIZE); RawValue := RawValue + TempStr; end; // Copy data from the last header if RawExtra <> 0 then begin PHeader := FTarHeaderList.Items[I + NumMHeaders + 1]; SetString(TempStr, PAnsiChar(PHeader), RawExtra); RawValue := RawValue + TempStr; end; Break; end; end; // Parse pax headers if (Length(RawValue) > 0) then begin O := nil; ALength:= 0; S:= Pointer(RawValue); P:= S; while (P^ <> #0) do begin case P^ of #10: begin Inc(P); S := P; O := nil; ALength:= 0; end; #32: begin P^:= #0; Inc(P); O:= P; ALength:= StrToIntDef(S, 0); end; '=': begin // Something wrong, exit if (ALength = 0) or (O = nil) then Exit; SetString(AName, O, P - O); ALength:= ALength - (P - S) - 1; if (AName = 'path') then begin SetString(AValue, P + 1, ALength - 1); FTarItem.Name := CeRawToUtf8(AValue); end else if (AName = 'linkpath') then begin SetString(AValue, P + 1, ALength - 1); FTarItem.LinkName := CeRawToUtf8(AValue); end else if (AName = 'size') then begin SetString(AValue, P + 1, ALength - 1); FTarItem.Size := StrToInt64Def(AValue, FTarItem.Size); end else if (AName = 'mtime') then begin SetString(AValue, P + 1, ALength - 1); FTarItem.ModTime := Round(StrToFloatDef(AValue, FTarItem.ModTime)); end; Inc(P, ALength); end; else begin Inc(P); end; end; end; end; end; procedure TAbTarItem.LoadTarHeaderFromStream(AStream: TStream); var NumMHeaders : Integer; I : Integer; FoundItem : Boolean; begin { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } { We should expect FindNext/FirstItem, and next check for bounds. } if FTarHeaderList.Count > 0 then begin { We're Going to stomp over the headers that are already present } { We need to destory the memory we've used } PTarHeader := nil; for i := 0 to FTarHeaderList.Count - 1 do FreeMem(FTarHeaderList.Items[i]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Clear; FTarHeaderTypeList.Clear; FTarItem.FileHeaderCount := 0; { All pointers should now be removed from those headers } end; { Now lets start filling up that list. } FTarItem.ItemType := UNKNOWN_ITEM; { We don't know what we have yet } FoundItem := False; while not FoundItem do begin { Create a Header to be Stored in the Items List } GetMem(PTarHeader, AB_TAR_RECORDSIZE); AStream.ReadBuffer(PTarHeader^, AB_TAR_RECORDSIZE); FTarHeaderList.Add(PTarHeader); { Store the Header to the list } { Parse header based on LinkFlag } if PTarHeader.LinkFlag in (AB_SUPPORTED_MD_HEADERS+AB_UNSUPPORTED_MD_HEADERS) then begin { This Header type is in the Set of un/supported Meta data type headers } if PTarHeader.LinkFlag in AB_UNSUPPORTED_MD_HEADERS then FTarItem.ItemReadOnly := True; { We don't fully support this meta-data type } if (PTarHeader.LinkFlag in AB_PAX_MD_HEADERS) and (CompareByte(PTarHeader.Magic.value, AB_TAR_MAGIC_VAL, SizeOf(AB_TAR_MAGIC_VAL)) = 0) then FTarItem.ArchiveFormat := POSIX_FORMAT; { We have a POSIX_FORMAT, has x headers, and Magic matches } if PTarHeader.LinkFlag in AB_GNU_MD_HEADERS then FTarItem.ArchiveFormat := OLDGNU_FORMAT; { We have a OLDGNU_FORMAT, has L/K headers } { There can be a unknown number of Headers of data } { We are for sure going to read at least one more header, but are we going to read more than that? } FTarHeaderTypeList.Add(Pointer(META_DATA_HEADER)); NumMHeaders := Ceil(OctalToInt(PTarHeader.Size, SizeOf(PTarHeader.Size)) / AB_TAR_RECORDSIZE); { NumMHeasder should never be zero } for I := 1 to NumMHeaders do begin GetMem(PTarHeader, AB_TAR_RECORDSIZE); { Create a new Header } AStream.ReadBuffer(PTarHeader^, AB_TAR_RECORDSIZE); { Get the Meta Data } FTarHeaderList.Add(PTarHeader); { Store the Header to the list } FTarHeaderTypeList.Add(Pointer(MD_DATA_HEADER)); end; { Loop and reparse } end else if PTarHeader.LinkFlag in AB_SUPPORTED_F_HEADERS then begin { This Header type is in the Set of supported File type Headers } FoundItem := True; { Exit Criterion } FTarItem.ItemType := SUPPORTED_ITEM; if FTarItem.ItemReadOnly then { Since some of the Headers are read only. } FTarItem.ItemType := UNSUPPORTED_ITEM; { This Item is unsupported } FTarHeaderTypeList.Add(Pointer(FILE_HEADER)); end else if PTarHeader.LinkFlag in AB_UNSUPPORTED_F_HEADERS then begin { This Header type is in the Set of unsupported File type Headers } FoundItem := True; { Exit Criterion } FTarItem.ItemType := UNSUPPORTED_ITEM; FTarHeaderTypeList.Add(Pointer(FILE_HEADER)); end else { These are unknown header types } begin { Note: Some of these unknown types could have known Meta-data headers } FoundItem := True; FTarItem.ItemType := UNKNOWN_ITEM; FTarHeaderTypeList.Add(Pointer(UNKNOWN_HEADER)); end;{ end LinkFlag parsing } end; { end Found Item While } { PTarHeader points to FTarHeaderList.Items[FTarHeaderList.Count-1]; } { Re-wind the Stream back to the begining of this Item inc. all headers } AStream.Seek(-(FTarHeaderList.Count*AB_TAR_RECORDSIZE), soCurrent); { AStream.Position := FTarItem.StreamPosition; } { This should be equivalent as above } FTarItem.FileHeaderCount := FTarHeaderList.Count; if FTarItem.ItemType <> UNKNOWN_ITEM then begin ParseTarHeaders; { Update FTarItem values } ParsePaxHeaders; { Update FTarItem values } FFileName := FTarItem.Name; {FTarHeader.Name;} // FDiskFileName := FileName; // AbUnfixName(FDiskFileName); end; Action := aaNone; Tagged := False; end; { ****************** BEGIN SET ********************** } procedure TAbTarItem.SaveTarHeaderToStream(AStream: TStream); var i : Integer; j : Integer; PHeader : PAbTarHeaderRec; HdrChkSum : Integer; HdrChkStr : AnsiString; HdrBuffer : PAnsiChar; SkipNextChkSum: Integer; SkipChkSum: Boolean; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } if FTarItem.Dirty then SkipNextChkSum := 0 else SkipNextChkSum := FTarHeaderList.Count; { Don't recalc any chkSums } { The first header in the Item list must have a checksum calculation } for i := 0 to (FTarHeaderList.Count-1) do begin SkipChkSum := False; PHeader := FTarHeaderList.Items[i]; if (SkipNextChkSum = 0) then begin { We need to parse this header } if PHeader.LinkFlag in (AB_SUPPORTED_MD_HEADERS+AB_UNSUPPORTED_MD_HEADERS) then begin { We have a Meta-Data Header, Calculate how many headers to skip. } { These meta-data headers have non-Header buffers after this Header } SkipNextChkSum := Ceil(OctalToInt(PHeader.Size, SizeOf(PHeader.Size)) / AB_TAR_RECORDSIZE); { Ceil will mandate one run through, and will handle 512 correctly } end else if PHeader.LinkFlag in AB_SUPPORTED_F_HEADERS then begin SkipNextChkSum := 0; end else begin { Un-Supported Header type, Copy but do nothing to the data } SkipNextChkSum := 0; SkipChkSum := True; end;{ end LinkFlag parsing } end else begin { Do not calcuate the check sum on this meta Data header buffer } SkipNextChkSum := SkipNextChkSum - 1; SkipChkSum := True; end;{ end SkipNextChkSum } if not SkipChkSum then begin { We are Calculating the Checksum for this Header } {Tar ChkSum is "odd" The check sum field is filled with #20 chars as empty } { ChkSum field itself is #20'd and has an effect on the sum } PHeader.ChkSum := AB_TAR_CHKBLANKS; { Set up the buffers } HdrBuffer := PAnsiChar(PHeader); HdrChkSum := 0; { Calculate the checksum, a simple sum of the bytes in the header } for j := 0 to (AB_TAR_RECORDSIZE-1) do HdrChkSum := HdrChkSum + Ord(HdrBuffer[j]); { set the checksum in the header } HdrChkStr := PadString(IntToOctal(HdrChkSum), SizeOf(PHeader.ChkSum)); Move(HdrChkStr[1], PHeader.ChkSum, Length(HdrChkStr)); end; { end Skip Check Sum } { write header to the file } AStream.Write(PHeader^, AB_TAR_RECORDSIZE); end; { End for the number of headers in the list } { Updated here as the stream is now updated to the latest number of headers } FTarItem.FileHeaderCount := FTarHeaderList.Count; end; procedure TAbTarItem.SetCompressedSize(const Value: Int64); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Size is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.Size := Value; { Store our Vitrual Copy } S := PadString(IntToOctal(Value), SizeOf(Arr12));{ Stuff to header } Move(S[1], PTarHeader.Size, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetDevMajor(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Dev Major and Minor are Only used for AB_TAR_LF_CHR, AB_TAR_LF_BLK } { Otherwise they are stuffed with #00 } FTarItem.DevMajor := Value; { Store to the struct } S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.DevMajor, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetDevMinor(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Dev Major and Minor are Only used for AB_TAR_LF_CHR, AB_TAR_LF_BLK } { Otherwise they are stuffed with #00 } FTarItem.DevMinor := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.DevMinor, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetExternalFileAttributes(Value: LongWord); var S : AnsiString; I: Integer; Permissions: LongWord; ALinkFlag: AnsiChar; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; UnixAttrsToTarAttrs(Value, Permissions, ALinkFlag); FTarItem.Mode := Permissions; S := PadString(IntToOctal(Permissions), SizeOf(Arr8)); for I := 0 to FTarHeaderList.Count - 1 do if TAbTarHeaderType(FTarHeaderTypeList.Items[I]) in [FILE_HEADER, META_DATA_HEADER] then Move(S[1], PAbTarHeaderRec(FTarHeaderList.Items[I]).Mode, Length(S)); Self.LinkFlag := ALinkFlag; // also updates headers FTarItem.Dirty := True; end; { Add/Remove Headers as needed To/From Existing GNU Long (Link/Name) TarItems } procedure TAbTarItem.DoGNUExistingLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); var PHeader: PAbTarHeaderRec; J: Integer; OldNameLength: Integer; TotalOldNumHeaders: Integer; TotalNewNumHeaders: Integer; NumHeaders: Integer; ExtraName: Integer; tempStr: AnsiString; begin PHeader := FTarHeaderList.Items[I]; { Need this data from the old header } OldNameLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size));{ inlcudes Null termination } { Length(FTarItem.Name)+1 = OldNameLength; }{ This should be true, always } { Save off the new Length, so we don't have to change the pointers later. } tempStr := PadString(IntToOctal(Length(Value)+1), SizeOf(PHeader.Size)); Move(tempStr[1], PHeader.Size, Length(tempStr)); TotalOldNumHeaders := Ceil(OldNameLength / AB_TAR_RECORDSIZE); TotalNewNumHeaders := Ceil((Length(Value)+1) / AB_TAR_RECORDSIZE);{ Null terminated } {Length(Value)+1: 1-512 = 1, 513-1024 = 2 ... } J := TotalOldNumHeaders - TotalNewNumHeaders; while J <> 0 do begin if J > 0 then begin { Old > New, Have to many Headers, Remove } FreeMem(FTarHeaderList.Items[I+J]); { Free the Memory for the extra Header } FTarHeaderList.Delete(I+J); { Delete the List index } FTarHeaderTypeList.Delete(I+J); J := J - 1; end else { if J < 0 then } begin { Old < New, Need more Headers, Insert } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(I+1,PHeader);{ Insert: Inserts at index } FTarHeaderTypeList.Insert(I+1,Pointer(MD_DATA_HEADER));{ We are only adding MD Data headers here } J := J + 1; end; end;{ end numHeaders while } { Yes, GNU Tar adds a Nil filled MD data header if Length(Value) mod AB_TAR_RECORDSIZE = 0 } NumHeaders := (Length(Value)+1) div AB_TAR_RECORDSIZE; { Include Null terminator } ExtraName := (Length(Value)+1) mod AB_TAR_RECORDSIZE; { Chars in the last Header } { Now we have the number of headers set up, stuff the name in the Headers } TempStr := AnsiString(Value); for J := 1 to NumHeaders do begin { Copy entire next AB_TAR_RECORDSIZE bytes of tempString to content of Header } { There may only be AB_TAR_RECORDSIZE-1 bytes if this is the last rounded header } PHeader := FTarHeaderList.Items[I+J]; Move(TempStr[1], PHeader^, AB_TAR_RECORDSIZE); if Length(TempStr) >= AB_TAR_RECORDSIZE then Delete(TempStr, 1, AB_TAR_RECORDSIZE);{ Crop string } end; if ExtraName <> 0 then begin { Copy whatever is left in tempStr into the rest of the buffer } PHeader := FTarHeaderList.Items[I+NumHeaders+1]; FillChar(PHeader^, AB_TAR_RECORDSIZE, #0); { Zero the whole block } Move(TempStr[1], PHeader^, ExtraName-1); { The string is null terminated } end else { We already copied the entire name, but it must be null terminated } begin FillChar(Pointer(PtrInt(PHeader)+AB_TAR_RECORDSIZE-1)^, 1, #0); { Zero rest of the block } end; { Finally we need to stuff the file type Header. } { Note: Value.length > AB_TAR_NAMESIZE(100) } if LinkFlag = AB_TAR_LF_LONGNAME then Move(Value[1], PTarHeader.Name, AB_TAR_NAMESIZE) else Move(Value[1], PTarHeader.LinkName, AB_TAR_NAMESIZE); end; { Always inserts the L/K Headers at index 0+ } procedure TAbTarItem.DoGNUNewLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); var PHeader: PAbTarHeaderRec; J: Integer; NumHeaders: Integer; ExtraName: Integer; tempStr: AnsiString; begin { We have a GNU_FORMAT, and no L/K Headers.} { Add a new MD Header and MD Data Headers } { Make an L/K header } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(I, PHeader);{ Insert: Inserts at base index } FTarHeaderTypeList.Insert(I, Pointer( META_DATA_HEADER));{ This is the L/K Header } FillChar(PHeader^, AB_TAR_RECORDSIZE, #0); { Zero the whole block } StrPCopy(PHeader.Name, AB_TAR_L_HDR_NAME); { Stuff L/K String Name } StrPCopy(PHeader.Mode, AB_TAR_L_HDR_ARR8_0); { Stuff zeros } StrPCopy(PHeader.uid, AB_TAR_L_HDR_ARR8_0); { Stuff zeros } StrPCopy(PHeader.gid, AB_TAR_L_HDR_ARR8_0); { Stuff zeros } tempStr := PadString(IntToOctal(Length(Value)+1), SizeOf(PHeader.Size)); { Stuff Size } Move(tempStr[1], PHeader.Size, Length(tempStr)); StrPCopy(PHeader.ModTime, AB_TAR_L_HDR_ARR12_0); { Stuff zeros } { Check sum will be calculated as the Dirty flag is in caller. } PHeader.LinkFlag := LinkFlag; { Stuff Link FlagSize } StrPCopy(PHeader.Magic.gnuOld, AB_TAR_MAGIC_GNUOLD); { Stuff the magic } StrPCopy(PHeader.UsrName, AB_TAR_L_HDR_USR_NAME); StrPCopy(PHeader.GrpName, AB_TAR_L_HDR_GRP_NAME); { All else stays as Zeros. } { Completed with L/K Header } { OK, now we need to add the proper number of MD Data Headers, and intialize to new name } { Yes, GNU Tar adds an extra Nil filled MD data header if Length(Value) mod AB_TAR_RECORDSIZE = 0 } NumHeaders := Ceil((Length(Value)+1) / AB_TAR_RECORDSIZE); { Include Null terminator } ExtraName := (Length(Value)+1) mod AB_TAR_RECORDSIZE; { Chars in the last Header } { Now we have the number of headers set up, stuff the name in the Headers } TempStr := AnsiString(Value); for J := 1 to NumHeaders-1 do begin { Make a buffer, and copy entire next AB_TAR_RECORDSIZE bytes of tempStr to content of Header } { There may only be AB_TAR_RECORDSIZE-1 bytes if this is the last rounded header } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(J+I, PHeader); FTarHeaderTypeList.Insert(J+I, Pointer(MD_DATA_HEADER));{ We are adding MD Data headers here } Move(TempStr[1], PHeader^, AB_TAR_RECORDSIZE); if Length(TempStr) >= AB_TAR_RECORDSIZE then Delete(TempStr, 1, AB_TAR_RECORDSIZE);{ Crop string } end; if ExtraName <> 0 then begin { Copy what ever is left in tempStr into the rest of the buffer } { Create the last MD Data Header } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(I+NumHeaders, PHeader);{ Insert: Inserts at base index } FTarHeaderTypeList.Insert(I+NumHeaders, Pointer(MD_DATA_HEADER));{ We are only adding MD Data headers here } FillChar(PHeader^, AB_TAR_RECORDSIZE, #0); { Zero the whole block } Move(TempStr[1], PHeader^, ExtraName-1); { The string is null terminated in the header } end else { We already copied the entire name, but it must be null terminated } begin FillChar(Pointer(PtrInt(PHeader)+AB_TAR_RECORDSIZE-1)^, 1, #0); { Zero rest of the block } end; { Finally we need to stuff the file type Header. } { Note: Value.length > AB_TAR_NAMESIZE(100) } if LinkFlag = AB_TAR_LF_LONGNAME then Move(Value[1], PTarHeader.Name, AB_TAR_NAMESIZE) else Move(Value[1], PTarHeader.LinkName, AB_TAR_NAMESIZE); end; procedure TAbTarItem.SetFileName(const Value: string); var FoundMetaDataHeader: Boolean; PHeader: PAbTarHeaderRec; I, J: Integer; TotalOldNumHeaders: Integer; RawFileName: AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Assume ItemReadOnly is set for all Unsupported Type. } { Cases: New File Name is short, Length <= 100, All formats: Zero Name field and move new name to field. V7: Work complete, 1 header USTAR: zero prefix field, 1 Header OLD_GNU & GNU: Remove old name headers, 1 header. STAR & PAX: And should not yet get here. New File Name is Long, Length >=101 Note: The Header Parsing sets any V7 to GNU if 'L'/'K" Headers are present V7: Raise an exception, as this can NOT be done, no change to header. USTAR: if new length <= 254 zero fill header, update name fields, 1 updated Header if new Length >= 255 raise an exception, as this can NOT be done, no change to header if old was Short, Add files to match format, OLD_GNU & GNU: Create new Name header, Add N Headers for name, Update name in file header, update name fields, min 3 headers STAR & PAX: And should not yet get here. if old was Long, OLD_GNU & GNU: Add N Headers for name, Update name in MD header, update name field in File Headers, min 3 headers Add headers to length of new Name Length, update name in file header, update name fields } RawFileName := CeUtf8ToSys(Value); { In all cases zero out the name fields in the File Header. } if Length(RawFileName) > AB_TAR_NAMESIZE then begin { Must be null terminated except at 100 char length } { Look for long name meta-data headers already in the archive. } FoundMetaDataHeader := False; I := 0; { FTarHeaderList.Count <= 1 always } while (not FoundMetaDataHeader) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGNAME then begin { We are growing or Shriking the Name MD Data fields. } FoundMetaDataHeader := True; DoGNUExistingLongNameLink(AB_TAR_LF_LONGNAME, I, RawFileName); { Need to copy the Name to the header. } FTarItem.Name := Value; end else I := I + 1; end; { End While } { MD Headers & MD Data Headers have been stuffed if FoundMetaDataHeader } { Still need to stuff the File type header contents. } if not FoundMetaDataHeader then begin case FTarItem.ArchiveFormat of V7_FORMAT: raise EAbTarBadFileName.Create; { File Name to Long } USTAR_FORMAT: begin { Longest file name is AB_TAR_NAMESIZE(100) chars } { Longest Prefix is AB_TAR_USTAR_PREFIX_SIZE(155) chars } { These two fields are delimted by a '/' char } {0123456789012345, Length = 15, NameLength = 5, PrefixLength = 9} { AAAA/BBBB/C.txt, Stored as Name := 'C.txt', Prefix := 'AAAA/BBBB' } { That means Theoretical maximum is 256 for Length(RawFileName) } if Length(RawFileName) > (AB_TAR_NAMESIZE+AB_TAR_USTAR_PREFIX_SIZE+1) then { Check the obvious one. } raise EAbTarBadFileName.Create; { File Name to Long } for I := Length(RawFileName) downto Length(RawFileName)-AB_TAR_NAMESIZE-1 do begin if RawFileName[I] = '/' then begin if (I <= AB_TAR_USTAR_PREFIX_SIZE+1) and (Length(RawFileName)-I <= AB_TAR_NAMESIZE) then begin { We have a successfull parse. } FillChar(PTarHeader.Name, SizeOf(PTarHeader.Name), #0); FillChar(PTarHeader.ustar.Prefix, SizeOf(PTarHeader.ustar.Prefix), #0); Move(RawFileName[I+1], PTarHeader.Name, Length(RawFileName)-I); Move(RawFileName[1], PTarHeader.ustar.Prefix, I); break; end else if (Length(RawFileName)-I > AB_TAR_NAMESIZE) then raise EAbTarBadFileName.Create { File Name not splittable } { else continue; } end; end;{ End for I... } end; { End USTAR Format } OLDGNU_FORMAT: DoGNUNewLongNameLink(AB_TAR_LF_LONGNAME, 0, RawFileName); {GNU_FORMAT} else begin { UNKNOWN_FORMAT, STAR_FORMAT, POSIX_FORMAT } raise EAbTarBadOp.Create; { Unknown Archive Format } end;{ End of Else for case statement } end;{ End of case statement } FTarItem.Name := Value; end; { if no Meta data header found } end { End "name length larger than 100" } else begin { Short new name, Simple Case Just put it in the Name Field & remove any headers } { PTarHeader Points to the File type Header } { Zero the Name field } FillChar(PTarHeader.Name, SizeOf(PTarHeader.Name), #0); if FTarItem.ArchiveFormat in [USTAR_FORMAT] then { Zero the prefix field } FillChar(PTarHeader.ustar.Prefix, SizeOf(PTarHeader.ustar.Prefix), #0); if FTarItem.ArchiveFormat in [GNU_FORMAT, OLDGNU_FORMAT] then begin { We may have AB_TAR_LF_LONGNAME Headers to be removed } { Remove long file names Headers if they exist} FoundMetaDataHeader := False; I := 0; while not FoundMetaDataHeader and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag in [AB_TAR_LF_LONGNAME] then begin { Delete this Header, and the data Headers. } FoundMetaDataHeader := True; TotalOldNumHeaders := Ceil( OctalToInt(PHeader.Size, SizeOf(PHeader.Size)) / AB_TAR_RECORDSIZE); for J := TotalOldNumHeaders downto 0 do begin { Note 0 will delete the Long Link MD Header } FreeMem(FTarHeaderList.Items[I+J]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Delete(I+J); FTarHeaderTypeList.Delete(I+J); end; end else I := I + 1; { Got to next header } end;{ End While not found... } end; { End if GNU... } { Save off the new name and store to the Header } FTarItem.Name := Value; { Must add Null Termination before we store to Header } StrPLCopy(PTarHeader.Name, RawFileName, AB_TAR_NAMESIZE); end;{ End else Short new name,... } { Update the inherited file names. } FFileName := FTarItem.Name; //DiskFileName := FFileName; //AbUnfixName(FDiskFileName); // Don't override DiskFileName FTarItem.Dirty := True; end; procedure TAbTarItem.SetGroupID(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { gid is extendable in PAX Headers, Rember PAX extended Header Over Rule File Headers } FTarItem.gid := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.gid, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetGroupName(const Value: string); begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { GrpName is extendable in PAX Headers, Rember PAX extended Header Over Rule File Headers } FTarItem.GrpName := Value; StrPLCopy(PTarHeader.GrpName, AnsiString(Value), SizeOf(PTarHeader.GrpName)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetIsEncrypted(Value: Boolean); begin { do nothing, TAR has no native encryption } end; procedure TAbTarItem.SetLastModFileDate(const Value: Word); begin { replace date, keep existing time } LastModTimeAsDateTime := EncodeDate( Value shr 9 + 1980, Value shr 5 and 15, Value and 31) + Frac(LastModTimeAsDateTime); end; procedure TAbTarItem.SetLastModFileTime(const Value: Word); begin { keep current date, replace time } LastModTimeAsDateTime := Trunc(LastModTimeAsDateTime) + EncodeTime( Value shr 11, Value shr 5 and 63, Value and 31 shl 1, 0); end; procedure TAbTarItem.SetLastModTimeAsDateTime(const Value: TDateTime); begin // TAR stores always Unix time. SetModTime(AbLocalDateTimeToUnixTime(Value)); // also updates headers end; procedure TAbTarItem.SetLinkFlag(Value: AnsiChar); begin if FTarItem.ItemReadOnly then Exit; FTarItem.LinkFlag := Value; PTarHeader.LinkFlag := Value; FTarItem.Dirty := True; end; procedure TAbTarItem.SetLinkName(const Value: string); var FoundMetaDataHeader: Boolean; PHeader: PAbTarHeaderRec; I, J: Integer; TotalOldNumHeaders: Integer; RawLinkName: AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Cases: New Link Name is short, Length <= 100, All formats: Zero Name field and move new name to field. V7: Work complete, 1 header USTAR: Work complete, 1 Header OLD_GNU & GNU: Remove old link headers, 1 header. STAR & PAX: And should not yet get here. New File Name is Long, Length >=101 Note: The Header Parsing sets any V7 to GNU if 'L'/'K' Headers are present V7: Raise an exception, as this can NOT be done, no change to header. USTAR: Raise an exception, as this can NOT be done, no change to header. if old was Short, Add files to match format, OLD_GNU & GNU: Create new Link header, Add N Headers for name, Update name in file header, update name fields, min 3 headers if old was Long, OLD_GNU & GNU: Add N Headers for name, Update name in MD header, update name field in File Headers, min 3 headers STAR & PAX: And should not yet get here.} RawLinkName := CeUtf8ToSys(Value); if Length(RawLinkName) > AB_TAR_NAMESIZE then { Must be null terminated except at 100 char length } begin { Look for long name meta-data headers already in the archive. } FoundMetaDataHeader := False; I := 0; { FTarHeaderList.Count <= 1 always } while (not FoundMetaDataHeader) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGLINK then begin { We are growing or Shriking the Name MD Data fields. } FoundMetaDataHeader := True; DoGNUExistingLongNameLink(AB_TAR_LF_LONGLINK, I, RawLinkName); { Need to copy the Name to the header. } FTarItem.LinkName := Value; end else I := I + 1; end; { End While } { MD Headers & MD Data Headers have been stuffed if FoundMetaDataHeader } { Still need to stuff the File type header contents. } if not FoundMetaDataHeader then begin case FTarItem.ArchiveFormat of V7_FORMAT: raise EAbTarBadLinkName.Create; { Link Name to Long } USTAR_FORMAT: raise EAbTarBadLinkName.Create; { Link Name to Long } OLDGNU_FORMAT: DoGNUNewLongNameLink(AB_TAR_LF_LONGLINK, 0, RawLinkName); {GNU_FORMAT} else begin { UNKNOWN_FORMAT, STAR_FORMAT, POSIX_FORMAT } raise EAbTarBadOp.Create; { Unknown Archive Format } end;{ End of Else for case statement } end;{ End of case statement } FTarItem.LinkName := Value; end; { if no Meta data header found } end { End "name length larger than 100" } else begin { Short new name, Simple Case Just put it in the Link Field & remove any headers } { PTarHeader Points to the File type Header } { Zero the Link field } FillChar(PTarHeader.LinkName, SizeOf(PTarHeader.LinkName), #0); if FTarItem.ArchiveFormat in [GNU_FORMAT, OLDGNU_FORMAT] then begin { We may have AB_TAR_LF_LONGNAME Headers to be removed } { Remove long file names Headers if they exist} FoundMetaDataHeader := False; I := 0; while not FoundMetaDataHeader and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag in [AB_TAR_LF_LONGLINK] then begin { Delete this Header, and the data Headers. } FoundMetaDataHeader := True; TotalOldNumHeaders := Ceil( OctalToInt(PHeader.Size, SizeOf(PHeader.Size)) / AB_TAR_RECORDSIZE); for J := TotalOldNumHeaders downto 0 do begin { Note 0 will delete the Long Link MD Header } FreeMem(FTarHeaderList.Items[I+J]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Delete(I+J); FTarHeaderTypeList.Delete(I+J); end; end else I := I + 1; { Got to next header } end;{ End While not found... } end; { End if GNU... } { Save off the new name and store to the Header } FTarItem.LinkName := Value; StrPLCopy(PTarHeader.LinkName, RawLinkName, AB_TAR_NAMESIZE); end;{ End else Short new name,... } FTarItem.Dirty := True; end; procedure TAbTarItem.SetMagic(const Value: String); begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; FTarItem.Magic := AnsiString(Value); Move(Value[1], PTarHeader.Magic, SizeOf(TAbTarMagicRec)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetUncompressedSize(const Value: Int64); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Size is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.Size := Value; { Store our Vitrual Copy } S := PadString(IntToOctal(Value), SizeOf(Arr12));{ Stuff to header } Move(S[1], PTarHeader.Size, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetUserID(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { uid is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.uid := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.uid, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetUserName(const Value: string); begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { UsrName is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.UsrName := Value; StrPLCopy(PTarHeader.UsrName, AnsiString(Value), SizeOf(PTarHeader.UsrName)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetModTime(const Value: Int64); var S: AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { ModTime is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.ModTime := Value; { Store our Virtual Copy } S := PadString(IntToOctal(Value), SizeOf(Arr12));{ Stuff to header } Move(S[1], PTarHeader.ModTime, Length(S)); FTarItem.Dirty := True; end; { ************************** TAbTarStreamHelper ****************************** } destructor TAbTarStreamHelper.Destroy; begin inherited Destroy; end; { This is slow, use the archive class instead } procedure TAbTarStreamHelper.ExtractItemData(AStream: TStream); begin { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } if FCurrItemSize <> 0 then begin { copy stored data to output } AStream.CopyFrom(FStream, FCurrItemSize); {reset the stream to the start of the item} FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE+FCurrItemSize), soCurrent); end; { else do nothing } end; { This function Should only be used from LoadArchive, as it is slow. } function TAbTarStreamHelper.FindItem: Boolean; var DataRead : LongInt; FoundItem: Boolean; SkipHdrs : Integer; begin { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } { Note: Standard LBA size of hard disks is 512 bytes = AB_TAR_RECORDSIZE } FoundItem := False; { Getting an new Item reset these numbers } FCurrItemSize := 0; FCurrItemPreHdrs := 0; DataRead := FStream.Read(FTarHeader, AB_TAR_RECORDSIZE); { Read in a header } { DataRead <> AB_TAR_RECORDSIZE means end of stream, and the End Of Archive record is all #0's, which the StrLen(FTarHeader.Name) check will catch } while (DataRead = AB_TAR_RECORDSIZE) and (StrLen(FTarHeader.Name) > 0) and not FoundItem do begin { Either exit when we find a supported file or end of file or an invalid header name. } if FTarHeader.LinkFlag in (AB_SUPPORTED_MD_HEADERS+AB_UNSUPPORTED_MD_HEADERS) then begin { We have a un/supported Meta-Data Header } { FoundItem := False } { Value remains False. } SkipHdrs := Ceil(OctalToInt(FTarHeader.Size, SizeOf(FTarHeader.Size))/AB_TAR_RECORDSIZE); FStream.Seek(SkipHdrs*AB_TAR_RECORDSIZE, soCurrent); { Tally new Headers: Consumed + Current } FCurrItemPreHdrs := FCurrItemPreHdrs + SkipHdrs + 1; { Read our next header, Loop, and re-parse } DataRead := FStream.Read(FTarHeader, AB_TAR_RECORDSIZE); end else if FTarHeader.LinkFlag in (AB_SUPPORTED_F_HEADERS+AB_UNSUPPORTED_F_HEADERS) then begin { We have a un/supported File Header. } FoundItem := True; if not (FTarHeader.LinkFlag in AB_IGNORE_SIZE_HEADERS) then FCurrItemSize := OctalToInt(FTarHeader.Size, SizeOf(FTarHeader.Size)) else FCurrItemSize := 0; { Per The spec these Headers do not have file content } FCurrItemPreHdrs := FCurrItemPreHdrs + 1; { Tally current header } end else begin{ We Have an Unknown header } FoundItem := True; FCurrItemSize := 0; { We could have many un/supported headers before this unknown type } FCurrItemPreHdrs := FCurrItemPreHdrs + 1; { Tally current header } { These Headers should throw exceptions when TAbTarItem.LoadTarHeaderFromStream is called } end; { End of Link Flag parsing } end; { Rewind to the "The Beginning" of this Item } { Really that means to the first supported Header Type before a supported Item Type } if FoundItem then FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE), soCurrent); Result := FoundItem; end; constructor TAbTarStreamHelper.Create(AStream: TStream; AEvent: TAbProgressEvent); begin Create(AStream); FOnProgress:= AEvent; end; { Should only be used from LoadArchive, as it is slow. } function TAbTarStreamHelper.FindFirstItem: Boolean; begin FStream.Seek(0, soBeginning); Result := FindItem; end; { Should only be used from LoadArchive, as it is slow. } function TAbTarStreamHelper.FindNextItem: Boolean; begin { Fast Forward Past the current Item } FStream.Seek((FCurrItemPreHdrs*AB_TAR_RECORDSIZE + RoundToTarBlock(FCurrItemSize)), soCurrent); Result := FindItem; end; { This is slow, use the archive class instead } function TAbTarStreamHelper.GetItemCount : Integer; var Found : Boolean; begin Result := 0; Found := FindFirstItem; while Found do begin Inc(Result); Found := FindNextItem; end; end; procedure TAbTarStreamHelper.ReadHeader; begin { do nothing } { Tar archives have no overall header data } end; procedure TAbTarStreamHelper.ReadTail; begin { do nothing } { Tar archives have no overall tail data } end; { This is slow, use the archive class instead } function TAbTarStreamHelper.SeekItem(Index: Integer): Boolean; var i : Integer; begin Result := FindFirstItem; { see if can get to first item } i := 1; while Result and (i < Index) do begin Result := FindNextItem; Inc(i); end; end; procedure TAbTarStreamHelper.WriteArchiveHeader; begin { do nothing } { Tar archives have no overall header data } end; procedure TAbTarStreamHelper.WriteArchiveItem(AStream: TStream); begin WriteArchiveItemSize(AStream, AStream.Size); end; procedure TAbTarStreamHelper.WriteArchiveItemSize(AStream: TStream; ASize: Int64); var PadBuff : PAnsiChar; PadSize : Integer; begin if ASize = 0 then Exit; { transfer actual item data } with TAbProgressWriteStream.Create(FStream, ASize, FOnProgress) do try CopyFrom(AStream, ASize); finally Free; end; { Pad to Next block } PadSize := RoundToTarBlock(ASize) - ASize; GetMem(PadBuff, PadSize); FillChar(PadBuff^, PadSize, #0); FStream.Write(PadBuff^, PadSize); FreeMem(PadBuff, PadSize); end; procedure TAbTarStreamHelper.WriteArchiveTail; var PadBuff : PAnsiChar; PadSize : Integer; begin { append 2 terminating null blocks } PadSize := AB_TAR_RECORDSIZE; GetMem(PadBuff, PadSize); try FillChar(PadBuff^, PadSize, #0); FStream.Write(PadBuff^, PadSize); FStream.Write(PadBuff^, PadSize); finally FreeMem(PadBuff, PadSize); end; end; { ***************************** TAbTarArchive ******************************** } constructor TAbTarArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); begin inherited; FArchFormat := V7_FORMAT; // Default for new archives end; function TAbTarArchive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var Item : TAbTarItem; I: Integer; FullSourceFileName, FullArchiveFileName: String; begin if FArchReadOnly then raise EAbTarBadOp.Create; { Create Item Unsupported in this Archive } MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); Item := TAbTarItem.Create; try // HeaderFormat = (UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT); if FArchFormat in [OLDGNU_FORMAT, GNU_FORMAT] then begin Item.ArchiveFormat := FArchFormat; Item.LinkFlag := AB_TAR_LF_NORMAL; Item.Magic := AB_TAR_MAGIC_GNUOLD; end else if FArchFormat in [USTAR_FORMAT] then begin Item.ArchiveFormat := USTAR_FORMAT; Item.LinkFlag := AB_TAR_LF_NORMAL; Item.Magic := AB_TAR_MAGIC_VAL+AB_TAR_MAGIC_VER; end else if (FArchFormat = V7_FORMAT) and (Length(FullArchiveFileName) > 100) then begin { Switch the rep over to GNU so it can have long file names. } FArchFormat := OLDGNU_FORMAT; Item.ArchiveFormat := OLDGNU_FORMAT; { Leave the Defaults for LinkFlag, and Magic } { Update all the rest so that it can transistion to GNU_FORMAT } for I := 0 to FItemList.Count - 1 do TAbTarItem(FItemList.Items[i]).ArchiveFormat := OLDGNU_FORMAT; end;{ This should not execute... }{ else if FArchFormat in [STAR_FORMAT, POSIX_FORMAT] then begin Item.ArchiveFormat := FArchFormat; Item.LinkFlag := AB_TAR_LF_NORMAL; Item.Magic := AB_TAR_MAGIC_VAL+AB_TAR_MAGIC_VER; end; }{ else FArchFormat in [ UNKNOWN_FORMAT, V7_FORMAT and Length(S) <= 100 ] } { This is the default. } { Most others are initialized in the .Create } Item.CRC32 := 0; { Note this can raise exceptions for file name lengths. } Item.FileName := FullArchiveFileName; Item.DiskFileName := FullSourceFileName; Item.Action := aaNone; finally Result := Item; end; end; procedure TAbTarArchive.ExtractItemAt(Index: Integer; const UseName: string); var AFileName: String; OutStream : TStream; CurItem : TAbTarItem; begin { Check the index is not out of range. } if(Index >= ItemList.Count) then raise EListError.CreateFmt(SListIndexError, [Index]); CurItem := TAbTarItem(ItemList[Index]); if CurItem.ItemType in [UNKNOWN_ITEM] then raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } { Link to previously archived file } if CurItem.LinkFlag in [AB_TAR_LF_LINK] then begin { Find link target } AFileName := NormalizePathDelimiters(CurItem.FileName); { If link target exists then try to create hard link } if StrEnds(UseName, AFileName) then begin AFileName := StringReplace(UseName, AFileName, CurItem.LinkName, []); if mbFileExists(AFileName) and CreateHardLink(AFileName, UseName) then Exit; end; { Cannot create hard link, extract previously archived file } Index := ItemList.Find(CurItem.LinkName); if (Index >= 0) and (Index < ItemList.Count) then CurItem := TAbTarItem(ItemList[Index]) else raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } end; if CurItem.IsDirectory then AbCreateDirectory(UseName) else begin case (CurItem.Mode and $F000) of AB_FMODE_FILE, AB_FMODE_FILE2: begin OutStream := TFileStreamEx.Create(UseName, fmCreate or fmShareDenyNone); try try {OutStream} ExtractItemToStreamAt(Index, OutStream); finally {OutStream} OutStream.Free; end; {OutStream} except if ExceptObject is EAbUserAbort then FStatus := asInvalid; mbDeleteFile(UseName); raise; end; end; AB_FMODE_FILELINK: begin if not CreateSymLink(CurItem.LinkName, UseName) then raise EOSError.Create(mbSysErrorMessage(GetLastOSError)); end; end; end; if (CurItem.Mode and $F000) <> AB_FMODE_FILELINK then begin AbSetFileTime(UseName, CurItem.LastModTimeAsDateTime); AbSetFileAttr(UseName, CurItem.NativeFileAttributes); end; end; procedure TAbTarArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); var CurItem : TAbTarItem; begin if(Index >= ItemList.Count) then raise EListError.CreateFmt(SListIndexError, [Index]); CurItem := TAbTarItem(ItemList[Index]); if CurItem.ItemType in [UNKNOWN_ITEM] then raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } FStream.Position := CurItem.StreamPosition+CurItem.FileHeaderCount*AB_TAR_RECORDSIZE; if CurItem.UncompressedSize <> 0 then aStream.CopyFrom(FStream, CurItem.UncompressedSize); { Else there is nothing to copy. } end; procedure TAbTarArchive.LoadArchive; var TarHelp : TAbTarStreamHelper; Item : TAbTarItem; ItemFound : Boolean; Abort : Boolean; Confirm : Boolean; Duplicate : Boolean; i : Integer; Progress : Byte; begin { create helper } TarHelp := TAbTarStreamHelper.Create(FStream); try {TarHelp} {build Items list from tar header records} { reset Tar } Duplicate := False; ItemFound := (FStream.Size > 0) and TarHelp.FindFirstItem; if ItemFound then FArchFormat := UNKNOWN_FORMAT else FArchFormat := V7_FORMAT; { while more data in Tar } while (FStream.Position < FStream.Size) and ItemFound do begin {create new Item} Item := TAbTarItem.Create; Item.FTarItem.StreamPosition := FStream.Position; try {Item} Item.LoadTarHeaderFromStream(FStream); if Item.ItemReadOnly then FArchReadOnly := True; { Set Archive as Read Only } if Item.ItemType in [SUPPORTED_ITEM, UNSUPPORTED_ITEM] then begin { List of supported Item/File Types. } { Add the New Supported Item to the List } if FArchFormat < Item.ArchiveFormat then FArchFormat := Item.ArchiveFormat; { Take the max format } Item.Action := aaNone; { TAR archive can contain the same directory multiple times. In this case, use the last found directory. } if Item.IsDirectory then begin I := FItemList.Find(Item.FileName); if (I >= 0) then begin Duplicate := True; FItemList.Items[I] := Item; end; end; if Duplicate then Duplicate := False else begin FItemList.Add(Item); end; end { end if } else begin { unhandled Tar file system entity, notify user, but otherwise ignore } if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(self, Item, ptFoundUnhandled, Confirm); end; { show progress and allow for aborting } Progress := (FStream.Position*100) div FStream.Size; DoArchiveProgress(Progress, Abort); if Abort then begin FStatus := asInvalid; raise EAbUserAbort.Create; end; { get the next item } ItemFound := TarHelp.FindNextItem; except {Item} raise EAbTarBadOp.Create; { Invalid Item } end; {Item} end; {end while } { All the items need to reflect this information. } for i := 0 to FItemList.Count - 1 do begin TAbTarItem(FItemList.Items[i]).ArchiveFormat := FArchFormat; TAbTarItem(FItemList.Items[i]).ItemReadOnly := FArchReadOnly; end; DoArchiveProgress(100, Abort); FIsDirty := False; finally {TarHelp} { Clean Up } TarHelp.Free; end; {TarHelp} end; function TAbTarArchive.FixName(const Value: string): string; { fixup filename for storage } var lValue : string; begin lValue := Value; {$IFDEF MSWINDOWS} if DOSMode then begin {Add the base directory to the filename before converting } {the file spec to the short filespec format. } if BaseDirectory <> '' then begin {Does the filename contain a drive or a leading backslash? } if not ((Pos(':', lValue) = 2) or (Pos(AbPathDelim, lValue) = 1)) then {If not, add the BaseDirectory to the filename.} lValue := BaseDirectory + AbPathDelim + lValue; end; lValue := AbGetShortFileSpec( lValue ); end; {$ENDIF MSWINDOWS} { Should always trip drive info if on a Win/Dos system } StoreOptions := StoreOptions + [soStripDrive]; { strip drive stuff } if soStripDrive in StoreOptions then AbStripDrive( lValue ); { check for a leading slash } if (Length(lValue) > 0) and (lValue[1] = AbPathDelim) then System.Delete( lValue, 1, 1 ); if soStripPath in StoreOptions then lValue := ExtractFileName(lValue); if soRemoveDots in StoreOptions then AbStripDots(lValue); AbFixName(lValue); Result := lValue; end; function TAbTarArchive.GetItem(Index: Integer): TAbTarItem; begin Result := TAbTarItem(FItemList.Items[Index]); end; function TAbTarArchive.GetSupportsEmptyFolders: Boolean; begin Result := True; end; procedure TAbTarArchive.PutItem(Index: Integer; const Value: TAbTarItem); begin //TODO: Remove this from all archives FItemList.Items[Index] := Value; end; procedure TAbTarArchive.SaveArchive; var OutTarHelp : TAbTarStreamHelper; Abort : Boolean; i : Integer; NewStream : TStream; TempStream : TStream; CurItem : TAbTarItem; AttrEx : TAbAttrExRec; ATempName : String; begin if FArchReadOnly then raise EAbTarBadOp.Create; { Archive is read only } {init new archive stream} if Assigned(FTargetStream) then NewStream := FTargetStream else if FOwnsStream and (FStream is TFileStreamEx) then begin if FStream.Size = 0 then NewStream := FStream else begin ATempName := GetTempName(FArchiveName); NewStream := TFileStreamEx.Create(ATempName, fmCreate or fmShareDenyWrite); end; end else begin NewStream := TAbVirtualMemoryStream.Create; TAbVirtualMemoryStream(NewStream).SwapFileDirectory := ExtractFileDir(FArchiveName); end; OutTarHelp := TAbTarStreamHelper.Create(NewStream, OnProgress); try {NewStream/OutTarHelp} {build new archive from existing archive} for i := 0 to pred(Count) do begin FCurrentItem := ItemList[i]; CurItem := TAbTarItem(ItemList[i]); case CurItem.Action of aaNone, aaMove : begin {just copy the file to new stream} { "Seek" to the Item Data } { SaveTarHeaders, Updates FileHeaderCount } FStream.Position := CurItem.StreamPosition+CurItem.FileHeaderCount*AB_TAR_RECORDSIZE; CurItem.StreamPosition := NewStream.Position;{ Reset the Stream Pointer. } { Flush The Headers to the new stream } CurItem.SaveTarHeaderToStream(NewStream); { Copy to new Stream, Round to the AB_TAR_RECORDSIZE boundry, and Pad zeros} outTarhelp.WriteArchiveItemSize(FStream, CurItem.UncompressedSize); end; aaDelete: {doing nothing omits file from new stream} ; aaStreamAdd : begin try { adding from a stream } CurItem.StreamPosition := NewStream.Position;{ Reset the Stream Pointer. } CurItem.UncompressedSize := InStream.Size; CurItem.SaveTarHeaderToStream(NewStream); OutTarHelp.WriteArchiveItemSize(InStream, InStream.Size); except ItemList[i].Action := aaDelete; DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0); end; end; aaAdd, aaFreshen, aaReplace: begin try { update metadata } if not AbFileGetAttrEx(CurItem.DiskFileName, AttrEx, False) then Raise EAbFileNotFound.Create; CurItem.ExternalFileAttributes := AttrEx.Mode; CurItem.LastModTimeAsDateTime := AttrEx.Time; { TODO: uid, gid, uname, gname should be added here } { TODO: Add support for different types of files here } case (AttrEx.Mode and $F000) of AB_FMODE_DIR: begin CurItem.UncompressedSize := 0; CurItem.SaveTarHeaderToStream(NewStream); end; AB_FMODE_FILELINK: begin CurItem.UncompressedSize := 0; CurItem.LinkName := ReadSymlink(CurItem.DiskFileName); CurItem.SaveTarHeaderToStream(NewStream); end; AB_FMODE_FILE, AB_FMODE_FILE2: begin TempStream := TFileStreamEx.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite ); try { TempStream } CurItem.UncompressedSize := TempStream.Size; CurItem.StreamPosition := NewStream.Position;{ Reset the Stream Pointer. } CurItem.SaveTarHeaderToStream(NewStream); OutTarHelp.WriteArchiveItemSize(TempStream, TempStream.Size); finally { TempStream } TempStream.Free; end; { TempStream } end; else begin CurItem.UncompressedSize := AttrEx.Size; CurItem.SaveTarHeaderToStream(NewStream); end; end; except ItemList[i].Action := aaDelete; DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0); end; end; { aaAdd ... } end; { case } end; { for i ... } if NewStream.Position > 0 then OutTarHelp.WriteArchiveTail; { Terminate the TAR } { Size of NewStream is still 0, and max of the stream will also be 0 } if (FTargetStream = nil) then begin {copy new stream to FStream} NewStream.Position := 0; if (FStream is TMemoryStream) then TMemoryStream(FStream).LoadFromStream(NewStream) else if (FStream is TAbVirtualMemoryStream) then begin FStream.Position := 0; FStream.Size := 0; TAbVirtualMemoryStream(FStream).CopyFrom(NewStream, NewStream.Size) end else begin if FOwnsStream then begin {need new stream to write} if NewStream = FStream then NewStream := nil else begin FreeAndNil(FStream); FreeAndNil(NewStream); if (mbDeleteFile(FArchiveName) and mbRenameFile(ATempName, FArchiveName)) then FStream := TFileStreamEx.Create(FArchiveName, fmOpenReadWrite or fmShareDenyWrite) else RaiseLastOSError; end; end else begin FStream.Size := 0; FStream.Position := 0; FStream.CopyFrom(NewStream, 0) end; end; end; {update Items list} for i := pred( Count ) downto 0 do begin if ItemList[i].Action = aaDelete then FItemList.Delete( i ) else if ItemList[i].Action <> aaFailed then ItemList[i].Action := aaNone; end; DoArchiveSaveProgress( 100, Abort ); DoArchiveProgress( 100, Abort ); finally {NewStream/OutTarHelp} OutTarHelp.Free; if (FStream <> NewStream) and (FTargetStream <> NewStream) then NewStream.Free; end; end; { This assumes that LoadArchive has been called. } procedure TAbTarArchive.TestItemAt(Index: Integer); begin FStream.Position := TAbTarItem(FItemList[Index]).StreamPosition; if VerifyTar(FStream) <> atTar then raise EAbTarInvalid.Create; { Invalid Tar } end; end. ��������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abunzoutstm.pas��������������������������������������0000644�0001750�0000144�00000013645�14743153644�023541� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbUnzOutStm.pas *} {*********************************************************} {* ABBREVIA: UnZip output stream; progress and CRC32 *} {*********************************************************} unit AbUnzOutStm; {$I AbDefine.inc} interface uses SysUtils, Classes, AbArcTyp; type // Fixed-length read-only stream, limits reads to the range between // the input stream's starting position and a specified size. Seek/Position // are adjusted to be 0 based. TAbUnzipSubsetStream = class( TStream ) private FStream : TStream; FStartPos: Int64; FCurPos: Int64; FEndPos: Int64; public constructor Create(aStream: TStream; aStreamSize: Int64); function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; // Write-only output stream, computes CRC32 and calls progress event TAbUnzipOutputStream = class( TStream ) private FBytesWritten : Int64; FCRC32 : LongInt; FCurrentProgress : Byte; FStream : TStream; FUncompressedSize : Int64; FOnProgress : TAbProgressEvent; function GetCRC32 : LongInt; public constructor Create(aStream : TStream); function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property CRC32 : LongInt read GetCRC32; property Stream : TStream read FStream write FStream; property UncompressedSize : Int64 read FUncompressedSize write FUncompressedSize; property OnProgress : TAbProgressEvent read FOnProgress write FOnProgress; end; implementation uses Math, AbExcept, AbUtils; { TAbUnzipSubsetStream implementation ====================================== } { -------------------------------------------------------------------------- } constructor TAbUnzipSubsetStream.Create(aStream: TStream; aStreamSize: Int64); begin inherited Create; FStream := aStream; FStartPos := FStream.Position; FCurPos := FStartPos; FEndPos := FStartPos + aStreamSize; end; { -------------------------------------------------------------------------- } function TAbUnzipSubsetStream.Read(var Buffer; Count: Longint): Longint; begin if Count > FEndPos - FCurPos then Count := FEndPos - FCurPos; if Count > 0 then begin Result := FStream.Read(Buffer, Count); Inc(FCurPos, Result); end else Result := 0; end; { -------------------------------------------------------------------------- } function TAbUnzipSubsetStream.Write(const Buffer; Count: Longint): Longint; begin raise EAbException.Create('TAbUnzipSubsetStream.Write not supported'); end; { -------------------------------------------------------------------------- } function TAbUnzipSubsetStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; var OldPos: Int64; begin OldPos := FCurPos; case Origin of soBeginning: FCurPos := FStartPos + Offset; soCurrent: FCurPos := FCurPos + Offset; soEnd: FCurPos := FEndPos + Offset; end; if FCurPos < FStartPos then FCurPos := FStartPos; if FCurPos > FEndPos then FCurPos := FEndPos; if OldPos <> FCurPos then FStream.Position := FCurPos; Result := FCurPos - FStartPos; end; { -------------------------------------------------------------------------- } { TAbUnzipOutputStream implementation ====================================== } { -------------------------------------------------------------------------- } constructor TAbUnzipOutputStream.Create(aStream: TStream); begin inherited Create; FStream := aStream; FCRC32 := -1; end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.Read(var Buffer; Count: Integer): Longint; begin raise EAbException.Create('TAbUnzipOutputStream.Read not supported'); end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.Write(const Buffer; Count: Longint): Longint; var Abort : Boolean; NewProgress : Byte; begin Result := FStream.Write(Buffer, Count); AbUpdateCRC( FCRC32, Buffer, Count ); Inc( FBytesWritten, Result ); if Assigned( FOnProgress ) then begin Abort := False; NewProgress := AbPercentage(FBytesWritten, FUncompressedSize); if (NewProgress <> FCurrentProgress) then begin FOnProgress( NewProgress, Abort ); FCurrentProgress := NewProgress; end; if Abort then raise EAbUserAbort.Create; end; end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin Result := FStream.Seek(Offset, Origin); end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.GetCRC32: LongInt; begin Result := not FCRC32; end; end. �������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abunzprc.pas�����������������������������������������0000644�0001750�0000144�00000116376�14743153644�022777� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbUnzPrc.pas *} {*********************************************************} {* ABBREVIA: UnZip procedures *} {*********************************************************} unit AbUnzPrc; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbZipTyp; type TAbUnzipHelper = class( TObject ) protected {private} {internal variables} FOutWriter : TStream; FOutStream : TStream; FUnCompressedSize : LongInt; FCompressionMethod : TAbZipCompressionMethod; FDictionarySize : TAbZipDictionarySize; FShannonFanoTreeCount : Byte; FOutBuf : PAbByteArray; {output buffer} FOutSent : LongInt; {number of bytes sent to output buffer} FOutPos : Cardinal; {current position in output buffer} FBitSValid : Byte; {Number of valid bits} FInBuf : TAbByteArray4K; FInPos : Integer; {current position in input buffer} FInCnt : Integer; {number of bytes in input buffer} FInEof : Boolean; {set when stream read returns 0} FCurByte : Byte; {current input byte} FBitsLeft : Byte; {bits left to process in FCurByte} FZStream : TStream; protected procedure uzFlushOutBuf; {-Flushes the output buffer} function uzReadBits(Bits : Byte) : Integer; {-Read the specified number of bits} procedure uzReadNextPrim; {-does less likely part of uzReadNext} {$IFDEF UnzipImplodeSupport} procedure uzUnImplode; {-Extract an imploded file} {$ENDIF} {$IFDEF UnzipReduceSupport} procedure uzUnReduce; {-Extract a reduced file} {$ENDIF} {$IFDEF UnzipShrinkSupport} procedure uzUnShrink; {-Extract a shrunk file} {$ENDIF} procedure uzWriteByte(B : Byte); {write to output} public constructor Create( InputStream, OutputStream : TStream ); destructor Destroy; override; procedure Execute; property UnCompressedSize : LongInt read FUncompressedSize write FUncompressedSize; property CompressionMethod : TAbZipCompressionMethod read FCompressionMethod write FCompressionMethod; property DictionarySize : TAbZipDictionarySize read FDictionarySize write FDictionarySize; property ShannonFanoTreeCount : Byte read FShannonFanoTreeCount write FShannonFanoTreeCount; end; procedure AbUnzipToStream( Sender : TObject; Item : TAbZipItem; OutStream : TStream); procedure AbUnzip(Sender : TObject; Item : TAbZipItem; const UseName : string); procedure AbTestZipItem(Sender : TObject; Item : TAbZipItem); procedure InflateStream(CompressedStream, UnCompressedStream : TStream); {-Inflates everything in CompressedStream to UncompressedStream no encryption is tried, no check on CRC is done, uses the whole compressedstream - no Progress events - no Frills!} implementation uses SysUtils, {$IFDEF UnzipBzip2Support} AbBzip2, {$ENDIF} {$IFDEF UnzipLzmaSupport} ULZMADecoder, {$ENDIF} {$IFDEF UnzipPPMdSupport} AbPPMd, {$ENDIF} {$IFDEF UnzipWavPackSupport} AbWavPack, {$ENDIF} {$IFDEF UnzipXzSupport} AbXz, {$ENDIF} {$IFDEF UnzipZstdSupport} AbZstd, {$ENDIF} AbBitBkt, AbConst, AbDfBase, AbDfCryS, AbDfDec, AbExcept, AbSpanSt, AbSWStm, AbUnzOutStm, AbUtils, AbZlibPrc, AbWinZipAes, DCOSUtils, DCClassesUtf8, DCConvertEncoding; { -------------------------------------------------------------------------- } procedure AbReverseBits(var W : Word); {-Reverse the order of the bits in W} register; const RevTable : array[0..255] of Byte = ($00, $80, $40, $C0, $20, $A0, $60, $E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88, $48, $C8, $28, $A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8, $04, $84, $44, $C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4, $74, $F4, $0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC, $3C, $BC, $7C, $FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92, $52, $D2, $32, $B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA, $1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6, $66, $E6, $16, $96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE, $2E, $AE, $6E, $EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81, $41, $C1, $21, $A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1, $09, $89, $49, $C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9, $79, $F9, $05, $85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5, $35, $B5, $75, $F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D, $5D, $DD, $3D, $BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3, $13, $93, $53, $D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB, $1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7, $27, $A7, $67, $E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F, $4F, $CF, $2F, $AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF); begin W := RevTable[Byte(W shr 8)] or Word(RevTable[Byte(W)] shl 8); end; { TAbUnzipHelper implementation ============================================ } { -------------------------------------------------------------------------- } constructor TAbUnzipHelper.Create( InputStream, OutputStream : TStream ); begin inherited Create; FOutBuf := AllocMem( AbBufferSize ); FOutPos := 0; FZStream := InputStream; FOutStream := OutputStream; FUncompressedSize := 0; FDictionarySize := dsInvalid; FShannonFanoTreeCount := 0; FCompressionMethod := cmDeflated; end; { -------------------------------------------------------------------------- } destructor TAbUnzipHelper.Destroy; begin FreeMem( FOutBuf, AbBufferSize ); inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.Execute; begin {parent class handles exceptions via OnExtractFailure} FBitsLeft := 0; FCurByte := 0; FInCnt := 0; FOutSent := 0; FOutPos := 0; FInEof := False; {set the output stream; for Imploded/Reduced files this has to be buffered, for all other types of compression, the code buffers the output data nicely and so the given output stream can be used.} {$IFDEF UnzipImplodeSupport} if (FCompressionMethod = cmImploded) then FOutWriter := TabSlidingWindowStream.Create(FOutStream) else {$ENDIF} {$IFDEF UnzipReduceSupport} if (FCompressionMethod >= cmReduced1) and (FCompressionMethod <= cmReduced4) then FOutWriter := TabSlidingWindowStream.Create(FOutStream) else {$ENDIF} FOutWriter := FOutStream; FInPos := 1+SizeOf(FInBuf); { GetMem( FInBuf, SizeOf(FInBuf^) );} try {uncompress it with the appropriate method} case FCompressionMethod of {$IFDEF UnzipShrinkSupport} cmShrunk : uzUnshrink; {$ENDIF} {$IFDEF UnzipReduceSupport} cmReduced1..cmReduced4 : uzUnReduce; {$ENDIF} {$IFDEF UnzipImplodeSupport} cmImploded : uzUnImplode; {$ENDIF} {cmTokenized} {cmEnhancedDeflated} {cmDCLImploded} else raise EAbZipInvalidMethod.Create; end; finally uzFlushOutBuf; {free any memory} if (FOutWriter <> FOutStream) then FOutWriter.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzReadNextPrim; begin FInCnt := FZStream.Read( FInBuf, sizeof( FInBuf ) ); FInEof := FInCnt = 0; {load first byte in buffer and set position counter} FCurByte := FInBuf[1]; FInPos := 2; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzFlushOutBuf; {-flushes the output buffer} begin if (FOutPos <> 0) then begin FOutWriter.Write( FOutBuf^, FOutPos ); Inc( FOutSent, FOutPos ); FOutPos := 0; end; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzWriteByte(B : Byte); {-Write one byte to the output buffer} begin FOutBuf^[FOutPos] := B; inc(FOutPos); if (FOutPos = AbBufferSize) or (LongInt(FOutPos) + FOutSent = FUncompressedSize) then uzFlushOutBuf; end; { -------------------------------------------------------------------------- } function TAbUnzipHelper.uzReadBits(Bits : Byte) : Integer; {-Read the specified number of bits} var SaveCurByte, Delta, SaveBitsLeft : Byte; begin {read next byte if we're out of bits} if FBitsLeft = 0 then begin {do we still have a byte buffered?} if FInPos <= FInCnt then begin {get next byte out of buffer and advance position counter} FCurByte := FInBuf[FInPos]; Inc(FInPos); end {are there any left to read?} else uzReadNextPrim; FBitsLeft := 8; end; if ( Bits < FBitsLeft ) then begin Dec( FBitsLeft, Bits ); Result := ((1 shl Bits) - 1) and FCurByte; FCurByte := FCurByte shr Bits; end else if ( Bits = FBitsLeft ) then begin Result := FCurByte; FCurByte := 0; FBitsLeft := 0; end else begin SaveCurByte := FCurByte; SaveBitsLeft := FBitsLeft; {number of additional bits that we need} Delta := Bits - FBitsLeft; {do we still have a byte buffered?} if FInPos <= FInCnt then begin {get next byte out of buffer and advance position counter} FCurByte := FInBuf[FInPos]; Inc(FInPos); end {are there any left to read?} else uzReadNextPrim; FBitsLeft := 8; Result := ( uzReadBits( Delta ) shl SaveBitsLeft ) or SaveCurByte; end; end; {$IFDEF UnzipImplodeSupport} { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzUnImplode; {-Extract an imploded file} const szLengthTree = SizeOf(TAbSfTree)-(192*SizeOf(TAbSfEntry)); szDistanceTree = SizeOf(TAbSfTree)-(192*SizeOf(TAbSfEntry)); szLitTree = SizeOf(TAbSfTree); var Length : Integer; DIndex : LongInt; Distance : Integer; SPos : LongInt; MyByte : Byte; DictBits : Integer; {number of bits used in sliding dictionary} MinMatchLength : Integer; {minimum match length} LitTree : PAbSfTree; {Literal tree} LengthTree : PAbSfTree; {Length tree} DistanceTree : PAbSfTree; {Distance tree} procedure uzLoadTree(var T; TreeSize : Integer); {-Load one Shannon-Fano tree} var I : Word; Tree : TAbSfTree absolute T; procedure GenerateTree; {-Generate a Shannon-Fano tree} var C : Word; CodeIncrement : Integer; LastBitLength : Integer; I : Integer; begin C := 0; CodeIncrement := 0; LastBitLength := 0; for I := Tree.Entries-1 downto 0 do with Tree.Entry[I] do begin Inc(C, CodeIncrement); if BitLength <> LastBitLength then begin LastBitLength := BitLength; CodeIncrement := 1 shl (16-LastBitLength); end; Code := C; end; end; procedure SortLengths; {-Sort the bit lengths in ascending order, while retaining the order of the original lengths stored in the file} var XL : Integer; XGL : Integer; TXP : PAbSfEntry; TXGP : PAbSfEntry; X, Gap : Integer; Done : Boolean; LT : LongInt; begin Gap := Tree.Entries shr 1; repeat repeat Done := True; for X := 0 to (Tree.Entries-1)-Gap do begin TXP := @Tree.Entry[X]; TXGP := @Tree.Entry[X+Gap]; XL := TXP^.BitLength; XGL := TXGP^.BitLength; if (XL > XGL) or ((XL = XGL) and (TXP^.Value > TXGP^.Value)) then begin LT := TXP^.L; TXP^.L := TXGP^.L; TXGP^.L := LT; Done := False; end; end; until Done; Gap := Gap shr 1; until (Gap = 0); end; procedure uzReadLengths; {-Read bit lengths for a tree} var TreeBytes : Integer; I, J, K : Integer; Num, Len : Integer; B : Byte; begin {get number of bytes in compressed tree} TreeBytes := uzReadBits(8)+1; I := 0; Tree.MaxLength := 0; {High nibble: Number of values at this bit length + 1. Low nibble: Bits needed to represent value + 1} for J := 1 to TreeBytes do begin B := uzReadBits(8); Len := (B and $0F)+1; Num := (B shr 4)+1; for K := I to I+Num-1 do with Tree, Entry[K] do begin if Len > MaxLength then MaxLength := Len; BitLength := Len; Value := K; end; Inc(I, Num); end; end; begin Tree.Entries := TreeSize; uzReadLengths; SortLengths; GenerateTree; for I := 0 to TreeSize-1 do AbReverseBits(Tree.Entry[I].Code); end; function uzReadTree(var T) : Byte; {-Read next byte using a Shannon-Fano tree} var Bits : Integer; CV : Word; E : Integer; Cur : Integer; var Tree : TAbSfTree absolute T; begin Result := 0; Bits := 0; CV := 0; Cur := 0; E := Tree.Entries; repeat CV := CV or (uzReadBits(1) shl Bits); Inc(Bits); while Tree.Entry[Cur].BitLength < Bits do begin Inc(Cur); if Cur >= E then Exit; end; while Tree.Entry[Cur].BitLength = Bits do begin if Tree.Entry[Cur].Code = CV then begin Result := Tree.Entry[Cur].Value; Exit; end; Inc(Cur); if Cur >= E then Exit; end; until False; end; begin {do we have an 8K dictionary?} if FDictionarySize = ds8K then DictBits := 7 else DictBits := 6; {allocate trees} LengthTree := AllocMem(szLengthTree); DistanceTree := AllocMem(szDistanceTree); LitTree := nil; try {do we have a Literal tree?} MinMatchLength := FShannonFanoTreeCount; if MinMatchLength = 3 then begin LitTree := AllocMem(szLitTree); uzLoadTree(LitTree^, 256); end; {load the other two trees} uzLoadTree(LengthTree^, 64); uzLoadTree(DistanceTree^, 64); while (not FInEof) and (FOutSent + LongInt(FOutPos) < FUncompressedSize) do {is data literal?} if Boolean(uzReadBits(1)) then begin {if MinMatchLength = 3 then we have a Literal tree} if (MinMatchLength = 3) then uzWriteByte( uzReadTree(LitTree^) ) else uzWriteByte( uzReadBits(8) ); end else begin {data is a sliding dictionary} Distance := uzReadBits(DictBits); {using the Distance Shannon-Fano tree, read and decode the upper 6 bits of the Distance value} Distance := Distance or (uzReadTree(DistanceTree^) shl DictBits); {using the Length Shannon-Fano tree, read and decode the Length value} Length := uzReadTree(LengthTree^); if Length = 63 then Inc(Length, uzReadBits(8)); Inc(Length, MinMatchLength); {move backwards Distance+1 bytes in the output stream, and copy Length characters from this position to the output stream. (if this position is before the start of the output stream, then assume that all the data before the start of the output stream is filled with zeros)} DIndex := (FOutSent + LongInt(FOutPos))-(Distance+1); while Length > 0 do begin if DIndex < 0 then uzWriteByte(0) else begin uzFlushOutBuf; SPos := FOutWriter.Position; FOutWriter.Position := DIndex; FOutWriter.Read( MyByte, 1 ); FOutWriter.Position := SPos; uzWriteByte(MyByte); end; Inc(DIndex); Dec(Length); end; end; finally if (LitTree <> nil) then FreeMem(LitTree, szLitTree); FreeMem(LengthTree, szLengthTree); FreeMem(DistanceTree, szDistanceTree); end; end; {$ENDIF UnzipImplodeSupport} { -------------------------------------------------------------------------- } {$IFDEF UnzipReduceSupport} procedure TAbUnzipHelper.uzUnReduce; const FactorMasks : array[1..4] of Byte = ($7F, $3F, $1F, $0F); DLE = 144; var C, Last : Byte; OpI : LongInt; I, J, Sz : Integer; D : Word; SPos : LongInt; MyByte : Byte; Factor : Byte; {reduction Factor} FactorMask : Byte; {bit mask to use based on Factor} Followers : PAbFollowerSets; {array of follower sets} State : Integer; {used while processing reduced files} V : Integer; {"} Len : Integer; {"} function BitsNeeded( i : Byte ) : Word; begin dec( i ); Result := 0; repeat inc( Result ); i := i shr 1; until i = 0; end; begin GetMem(Followers, SizeOf(TAbFollowerSets)); try Factor := Ord( FCompressionMethod ) - 1; FactorMask := FactorMasks[Factor]; State := 0; C := 0; V := 0; Len := 0; D := 0; {load follower sets} for I := 255 downto 0 do begin Sz := uzReadBits(6); Followers^[I].Size := Sz; Dec(Sz); for J := 0 to Sz do Followers^[I].FSet[J] := uzReadBits(8); end; while (not FInEof) and ((FOutSent + LongInt(FOutPos)) < FUncompressedSize) do begin Last := C; with Followers^[Last] do if Size = 0 then C := uzReadBits(8) else begin C := uzReadBits(1); if C <> 0 then C := uzReadBits(8) else C := FSet[uzReadBits(BitsNeeded(Size))]; end; if FInEof then Exit; case State of 0 : if C <> DLE then uzWriteByte(C) else State := 1; 1 : if C <> 0 then begin V := C; Len := V and FactorMask; if Len = FactorMask then State := 2 else State := 3; end else begin uzWriteByte(DLE); State := 0; end; 2 : begin Inc(Len, C); State := 3; end; 3 : begin case Factor of 1 : D := (V shr 7) and $01; 2 : D := (V shr 6) and $03; 3 : D := (V shr 5) and $07; 4 : D := (V shr 4) and $0f; else raise EAbZipInvalidFactor.Create; end; {Delphi raises compiler Hints here, saying D might be undefined... If Factor is not in [1..4], the exception gets raised, and we never execute the following line} OpI := (FOutSent + LongInt(FOutPos))-(Swap(D)+C+1); for I := 0 to Len+2 do begin if OpI < 0 then uzWriteByte(0) else if OpI >= FOutSent then uzWriteByte(FOutBuf[OpI - FOutSent]) else begin SPos := FOutWriter.Position; FOutWriter.Position := OpI; FOutWriter.Read( MyByte, 1 ); FOutWriter.Position := SPos; uzWriteByte(MyByte); end; Inc(OpI); end; State := 0; end; end; end; finally FreeMem(Followers, SizeOf(Followers^)); end; end; {$ENDIF UnzipReduceSupport} { -------------------------------------------------------------------------- } {$IFDEF UnzipShrinkSupport} procedure TAbUnzipHelper.uzUnShrink; {-Extract a file that was shrunk} const MaxBits = 13; InitBits = 9; FirstFree = 257; Clear = 256; MaxCodeMax = 8192; {= 1 shl MaxBits} Unused = -1; var CodeSize : SmallInt; NextFree : SmallInt; BaseChar : SmallInt; NewCode : SmallInt; OldCode : SmallInt; SaveCode : SmallInt; N, R : SmallInt; I : Integer; PrefixTable : PAbIntArray8K; {used while processing shrunk files} SuffixTable : PAbByteArray8K; {"} Stack : PAbByteArray8K; {"} StackIndex : Integer; {"} begin CodeSize := InitBits; { MaxCode := (1 shl InitBits)-1;} NextFree := FirstFree; PrefixTable := nil; SuffixTable := nil; Stack := nil; try GetMem(PrefixTable, SizeOf(PrefixTable^)); SuffixTable := AllocMem(SizeOf(SuffixTable^)); GetMem(Stack, SizeOf(Stack^)); FillChar(PrefixTable^, SizeOf(PrefixTable^), $FF); for NewCode := 255 downto 0 do begin PrefixTable^[NewCode] := 0; SuffixTable^[NewCode] := NewCode; end; OldCode := uzReadBits(CodeSize); if FInEof then Exit; BaseChar := OldCode; uzWriteByte(BaseChar); StackIndex := 0; while (not FInEof) do begin NewCode := uzReadBits(CodeSize); while (NewCode = Clear) and (not FInEof) do begin case uzReadBits(CodeSize) of 1 : begin Inc(CodeSize); end; 2 : begin {mark all nodes as potentially unused} for I := FirstFree to pred( NextFree ) do PrefixTable^[I] := PrefixTable^[I] or LongInt($8000); {unmark those used by other nodes} for N := FirstFree to NextFree-1 do begin {reference to another node?} R := PrefixTable^[N] and $7FFF; {flag node as referenced} if R >= FirstFree then PrefixTable^[R] := PrefixTable^[R] and $7FFF; end; {clear the ones that are still marked} for I := FirstFree to pred( NextFree ) do if PrefixTable^[I] < 0 then PrefixTable^[I] := -1; {recalculate NextFree} NextFree := FirstFree; while (NextFree < MaxCodeMax) and (PrefixTable^[NextFree] <> -1) do Inc(NextFree); end; end; NewCode := uzReadBits(CodeSize); end; if FInEof then Exit; {save current code} SaveCode := NewCode; {special case} if PrefixTable^[NewCode] = Unused then begin Stack^[StackIndex] := BaseChar; Inc(StackIndex); NewCode := OldCode; end; {generate output characters in reverse order} while (NewCode >= FirstFree) do begin if PrefixTable^[NewCode] = Unused then begin Stack^[StackIndex] := BaseChar; Inc(StackIndex); NewCode := OldCode; end else begin Stack^[StackIndex] := SuffixTable^[NewCode]; Inc(StackIndex); NewCode := PrefixTable^[NewCode]; end; end; BaseChar := SuffixTable^[NewCode]; uzWriteByte(BaseChar); {put them out in forward order} while (StackIndex > 0) do begin Dec(StackIndex); uzWriteByte(Stack^[StackIndex]); end; {add new entry to tables} NewCode := NextFree; if NewCode < MaxCodeMax then begin PrefixTable^[NewCode] := OldCode; SuffixTable^[NewCode] := BaseChar; while (NextFree < MaxCodeMax) and (PrefixTable^[NextFree] <> Unused) do Inc(NextFree); end; {remember previous code} OldCode := SaveCode; end; finally FreeMem(PrefixTable, SizeOf(PrefixTable^)); FreeMem(SuffixTable, SizeOf(SuffixTable^)); FreeMem(Stack, SizeOf(Stack^)); end; end; {$ENDIF} { -------------------------------------------------------------------------- } procedure RequestPassword(Archive : TAbZipArchive; var Abort : Boolean); var APassPhrase : AnsiString; begin APassPhrase := Archive.Password; Abort := False; if Assigned(Archive.OnNeedPassword) then begin Archive.OnNeedPassword(Archive, APassPhrase); if APassPhrase = '' then Abort := True else Archive.Password := APassPhrase; end; end; { -------------------------------------------------------------------------- } procedure CheckPassword(Archive : TAbZipArchive; var Tries : Integer; var Abort : Boolean); begin { if current password empty } if Archive.Password = '' then begin { request password } RequestPassword(Archive, Abort); { increment tries } Inc(Tries); end; { if current password still empty } if Archive.Password = '' then begin { abort } raise EAbZipInvalidPassword.Create; end; end; { -------------------------------------------------------------------------- } procedure DoInflate(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Hlpr : TAbDeflateHelper; begin Hlpr := TAbDeflateHelper.Create; try if Item.CompressionMethod = cmEnhancedDeflated then begin Hlpr.Options := Hlpr.Options or dfc_UseDeflate64; Hlpr.StreamSize := Item.CompressedSize; AbDfDec.Inflate(InStream, OutStream, Hlpr) end else begin Hlpr.NormalSize := Item.UncompressedSize; AbZlibPrc.Inflate(InStream, OutStream, Hlpr); end; finally Hlpr.Free; end; end; { -------------------------------------------------------------------------- } procedure DoLegacyUnzip(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Helper : TAbUnzipHelper; begin Helper := TAbUnzipHelper.Create(InStream, OutStream); try {Helper} Helper.DictionarySize := Item.DictionarySize; Helper.UnCompressedSize := Item.UncompressedSize; Helper.CompressionMethod := Item.CompressionMethod; Helper.ShannonFanoTreeCount := Item.ShannonFanoTreeCount; Helper.Execute; finally Helper.Free; end; end; { -------------------------------------------------------------------------- } {$IFDEF UnzipBzip2Support} procedure DoExtractBzip2(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Bzip2Stream: TStream; begin Bzip2Stream := TBZDecompressionStream.Create(InStream); try OutStream.CopyFrom(Bzip2Stream, Item.UncompressedSize); finally Bzip2Stream.Free; end; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFDEF UnzipLzmaSupport} procedure DoExtractLzma(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Header: packed record MajorVer, MinorVer: Byte; PropSize: Word; end; Properties: array of Byte; begin InStream.ReadBuffer(Header, SizeOf(Header)); SetLength(Properties, Header.PropSize); InStream.ReadBuffer(Properties[0], Header.PropSize); with TLZMADecoder.Create do try SetDecoderProperties(Properties); Code(InStream, OutStream, Item.UncompressedSize); finally Free; end; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFDEF UnzipXzSupport} procedure DoExtractXz(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var XzStream: TXzDecompressionStream; begin XzStream := TXzDecompressionStream.Create(InStream); try OutStream.CopyFrom(XzStream, Item.UncompressedSize); finally XzStream.Free; end; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFDEF UnzipZstdSupport} procedure DoExtractZstd(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var ZstdStream: TStream; begin ZstdStream := TZstdDecompressionStream.Create(InStream); try OutStream.CopyFrom(ZstdStream, Item.UncompressedSize); finally ZstdStream.Free; end; end; {$ENDIF} { -------------------------------------------------------------------------- } function ExtractPrep(ZipArchive: TAbZipArchive; Item: TAbZipItem): TStream; var LFH : TAbZipLocalFileHeader; Abort : Boolean; Tries : Integer; CheckValue : LongInt; DecryptStream: TAbDfDecryptStream; FieldSize: Word; WinZipAesField: PWinZipAesRec = nil; AesDecryptStream: TAbWinZipAesDecryptStream; begin { validate } if (Lo(Item.VersionNeededToExtract) > Ab_ZipVersion) then raise EAbZipVersion.Create; { seek to compressed file } if ZipArchive.FStream is TAbSpanReadStream then TAbSpanReadStream(ZipArchive.FStream).SeekImage(Item.DiskNumberStart, Item.RelativeOffset) else ZipArchive.FStream.Position := Item.RelativeOffset; { get local header info for Item} LFH := TAbZipLocalFileHeader.Create; try { select appropriate CRC value based on General Purpose Bit Flag } { also get whether the file is stored, while we've got the local file header } LFH.LoadFromStream(ZipArchive.FStream); if (LFH.GeneralPurposeBitFlag and AbHasDataDescriptorFlag = AbHasDataDescriptorFlag) then { if bit 3 is set, then the data descriptor record is appended to the compressed data } CheckValue := LFH.LastModFileTime shl $10 else CheckValue := Item.CRC32; finally LFH.Free; end; Result := TAbUnzipSubsetStream.Create(ZipArchive.FStream, Item.CompressedSize); { get decrypting stream } if Item.IsEncrypted then begin try { check WinZip AES extra field } if Item.ExtraField.Get(Ab_WinZipAesID, Pointer(WinZipAesField), FieldSize) then begin { get real compression method } Item.CompressionMethod := TAbZipCompressionMethod(WinZipAesField.Method); end; { need to decrypt } Tries := 0; Abort := False; CheckPassword(ZipArchive, Tries, Abort); while True do begin if Abort then raise EAbUserAbort.Create; { check for valid password } if Assigned(WinZipAesField) then begin AesDecryptStream := TAbWinZipAesDecryptStream.Create(Result, WinZipAesField, ZipArchive.Password); if AesDecryptStream.IsValid then begin AesDecryptStream.OwnsStream := True; Result := AesDecryptStream; Break; end; FreeAndNil(AesDecryptStream); end else begin DecryptStream := TAbDfDecryptStream.Create(Result, CheckValue, ZipArchive.Password); if DecryptStream.IsValid then begin DecryptStream.OwnsStream := True; Result := DecryptStream; Break; end; FreeAndNil(DecryptStream); end; { prompt again } Inc(Tries); if (Tries > ZipArchive.PasswordRetries) then raise EAbZipInvalidPassword.Create; RequestPassword(ZipArchive, Abort); end; except Result.Free; raise; end; end; end; { -------------------------------------------------------------------------- } procedure DoExtract(aZipArchive: TAbZipArchive; aItem: TAbZipItem; aInStream, aOutStream: TStream); var Wrong: Boolean; OutStream : TAbUnzipOutputStream; begin if aItem.UncompressedSize = 0 then Exit; OutStream := TAbUnzipOutputStream.Create(aOutStream); try OutStream.UncompressedSize := aItem.UncompressedSize; OutStream.OnProgress := aZipArchive.OnProgress; { determine storage type } case aItem.CompressionMethod of cmStored: begin { unstore aItem } OutStream.CopyFrom(aInStream, aItem.UncompressedSize); end; cmDeflated, cmEnhancedDeflated: begin { inflate aItem } DoInflate(aZipArchive, aItem, aInStream, OutStream); end; {$IFDEF UnzipBzip2Support} cmBzip2: begin DoExtractBzip2(aZipArchive, aItem, aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipLzmaSupport} cmLZMA: begin DoExtractLzma(aZipArchive, aItem, aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipPPMdSupport} cmPPMd: begin DecompressPPMd(aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipWavPackSupport} cmWavPack: begin DecompressWavPack(aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipXzSupport} cmXz: begin DoExtractXz(aZipArchive, aItem, aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipZstdSupport} cmZstd: begin DoExtractZstd(aZipArchive, aItem, aInStream, OutStream); end; {$ENDIF} cmShrunk..cmImploded: begin DoLegacyUnzip(aZipArchive, aItem, aInStream, OutStream); end; else raise EAbZipInvalidMethod.Create; end; { check CRC } if not (aInStream is TAbWinZipAesDecryptStream) then Wrong := (OutStream.CRC32 <> aItem.CRC32) else begin Wrong := not TAbWinZipAesDecryptStream(aInStream).Verify; if TAbWinZipAesDecryptStream(aInStream).ExtraField.Version = 1 then Wrong := Wrong or (OutStream.CRC32 <> aItem.CRC32); end; if Wrong then begin if Assigned(aZipArchive.OnProcessItemFailure) then aZipArchive.OnProcessItemFailure(aZipArchive, aItem, ptExtract, ecAbbrevia, AbZipBadCRC) else raise EAbZipBadCRC.Create; end; finally OutStream.Free; end; end; { -------------------------------------------------------------------------- } procedure AbUnzipToStream( Sender : TObject; Item : TAbZipItem; OutStream : TStream); var ZipArchive : TAbZipArchive; InStream : TStream; begin ZipArchive := Sender as TAbZipArchive; if not Assigned(OutStream) then raise EAbBadStream.Create; InStream := ExtractPrep(ZipArchive, Item); try DoExtract(ZipArchive, Item, InStream, OutStream); finally InStream.Free end; end; { -------------------------------------------------------------------------- } procedure AbUnzip(Sender : TObject; Item : TAbZipItem; const UseName : string); {create the output filestream and pass it to DoExtract} var LinkTarget : String; ZipArchive : TAbZipArchive; InStream, OutStream : TStream; begin ZipArchive := TAbZipArchive(Sender); if Item.IsDirectory then AbCreateDirectory(UseName) else begin InStream := ExtractPrep(ZipArchive, Item); try if FPS_ISLNK(Item.NativeFileAttributes) then begin OutStream := TMemoryStream.Create; try try {OutStream} DoExtract(ZipArchive, Item, InStream, OutStream); SetString(LinkTarget, TMemoryStream(OutStream).Memory, OutStream.Size); LinkTarget := CeRawToUtf8(LinkTarget); finally {OutStream} OutStream.Free; end; {OutStream} if not CreateSymLink(LinkTarget, UseName) then RaiseLastOSError; except if ExceptObject is EAbUserAbort then ZipArchive.FStatus := asInvalid; raise; end; end else begin OutStream := TFileStreamEx.Create(UseName, fmCreate or fmShareDenyWrite); try try {OutStream} DoExtract(ZipArchive, Item, InStream, OutStream); finally {OutStream} OutStream.Free; end; {OutStream} except if ExceptObject is EAbUserAbort then ZipArchive.FStatus := asInvalid; DeleteFile(UseName); raise; end; end; finally InStream.Free end; end; if not FPS_ISLNK(Item.NativeFileAttributes) then begin AbSetFileTime(UseName, Item.LastModTimeAsDateTime); AbSetFileAttr(UseName, Item.NativeFileAttributes); end; end; { -------------------------------------------------------------------------- } procedure AbTestZipItem(Sender : TObject; Item : TAbZipItem); {extract item to bit bucket and verify its local file header} var BitBucket : TAbBitBucketStream; FieldSize : Word; LFH : TAbZipLocalFileHeader; Zip64Field : PZip64LocalHeaderRec; ZipArchive : TAbZipArchive; DD : TAbZipDataDescriptor = nil; begin ZipArchive := TAbZipArchive(Sender); if (Lo(Item.VersionNeededToExtract) > Ab_ZipVersion) then raise EAbZipVersion.Create; { seek to compressed file } if ZipArchive.FStream is TAbSpanReadStream then TAbSpanReadStream(ZipArchive.FStream).SeekImage(Item.DiskNumberStart, Item.RelativeOffset) else ZipArchive.FStream.Position := Item.RelativeOffset; BitBucket := nil; LFH := nil; try BitBucket := TAbBitBucketStream.Create(0); LFH := TAbZipLocalFileHeader.Create; {get the item's local file header} ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning); LFH.LoadFromStream(ZipArchive.FStream); if LFH.HasDataDescriptor then begin DD := TAbZipDataDescriptor.Create; ZipArchive.FStream.Seek(Item.CompressedSize, soCurrent); DD.LoadFromStream(ZipArchive.FStream); end; ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning); {currently a single exception is raised for any LFH error} if (LFH.VersionNeededToExtract <> Item.VersionNeededToExtract) then raise EAbZipInvalidLFH.Create; if (LFH.GeneralPurposeBitFlag <> Item.GeneralPurposeBitFlag) then raise EAbZipInvalidLFH.Create; if (LFH.LastModFileTime <> Item.LastModFileTime) then raise EAbZipInvalidLFH.Create; if (LFH.LastModFileDate <> Item.LastModFileDate) then raise EAbZipInvalidLFH.Create; if Assigned(DD) then begin if (DD.CRC32 <> Item.CRC32) then raise EAbZipInvalidLFH.Create; end else begin if (LFH.CRC32 <> Item.CRC32) then raise EAbZipInvalidLFH.Create; end; if LFH.ExtraField.Get(Ab_Zip64SubfieldID, Pointer(Zip64Field), FieldSize) then begin if (Zip64Field.CompressedSize <> Item.CompressedSize) then raise EAbZipInvalidLFH.Create; if (Zip64Field.UncompressedSize <> Item.UncompressedSize) then raise EAbZipInvalidLFH.Create; end else if Assigned(DD) then begin if (DD.CompressedSize <> Item.CompressedSize) then raise EAbZipInvalidLFH.Create; if (DD.UncompressedSize <> Item.UncompressedSize) then raise EAbZipInvalidLFH.Create; end else begin if (LFH.CompressedSize <> Item.CompressedSize) then raise EAbZipInvalidLFH.Create; if (LFH.UncompressedSize <> Item.UncompressedSize) then raise EAbZipInvalidLFH.Create; end; if (LFH.FileName <> Item.RawFileName) then raise EAbZipInvalidLFH.Create; {any CRC errors will raise exception during extraction} AbUnZipToStream(Sender, Item, BitBucket); finally BitBucket.Free; LFH.Free; DD.Free; end; end; { -------------------------------------------------------------------------- } procedure InflateStream( CompressedStream, UnCompressedStream : TStream ); {-Inflates everything in CompressedStream to UncompressedStream no encryption is tried, no check on CRC is done, uses the whole compressedstream - no Progress events - no Frills!} begin Inflate(CompressedStream, UncompressedStream, nil); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abutils.pas������������������������������������������0000644�0001750�0000144�00000121437�14743153644�022610� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbUtils.pas *} {*********************************************************} {* ABBREVIA: Utility classes and routines *} {*********************************************************} unit AbUtils; {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, DCWindows, DCConvertEncoding, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF FPCUnixAPI} baseunix, {$IFDEF Linux} initc, {$ENDIF} unix, {$ENDIF} {$IFDEF PosixAPI} Posix.SysStatvfs, Posix.SysStat, Posix.Utime, Posix.Base, Posix.Unistd, Posix.Fcntl, Posix.SysTypes, {$ENDIF} {$IFDEF UNIX} DCClassesUtf8, {$ENDIF} DateUtils, SysUtils, Classes; type {describe the pending action for an archive item} TAbArchiveAction = (aaFailed, aaNone, aaAdd, aaDelete, aaFreshen, aaMove, aaReplace, aaStreamAdd); TAbProcessType = (ptAdd, ptDelete, ptExtract, ptFreshen, ptMove, ptReplace, ptFoundUnhandled); TAbLogType = (ltAdd, ltDelete, ltExtract, ltFreshen, ltMove, ltReplace, ltStart, ltFoundUnhandled); TAbErrorClass = (ecAbbrevia, ecInOutError, ecFilerError, ecFileCreateError, ecFileOpenError, ecCabError, ecOther); const AbPathDelim = PathDelim; { Delphi/Linux constant } AbPathSep = PathSep; { Delphi/Linux constant } AbDosPathDelim = '\'; AbUnixPathDelim = '/'; AbDosPathSep = ';'; AbUnixPathSep = ':'; AbDosAnyFile = '*.*'; AbUnixAnyFile = '*'; AbAnyFile = {$IFDEF UNIX} AbUnixAnyFile; {$ELSE} AbDosAnyFile; {$ENDIF} AbThisDir = '.'; AbParentDir = '..'; type TAbArchiveType = (atUnknown, atZip, atSpannedZip, atSelfExtZip, atTar, atGzip, atGzippedTar, atCab, atBzip2, atBzippedTar, atXz, atXzippedTar, atLzma, atLzmaTar, atZstd, atZstdTar); {$IF NOT DECLARED(DWORD)} type DWORD = LongWord; {$IFEND} {$IF NOT DECLARED(PtrInt)} type // Delphi 7-2007 declared NativeInt incorrectly {$IFDEF CPU386} PtrInt = LongInt; PtrUInt = LongWord; {$ELSE} PtrInt = NativeInt; PtrUInt = NativeUInt; {$ENDIF} {$IFEND} { Unicode backwards compatibility types } {$IF NOT DECLARED(RawByteString)} type RawByteString = AnsiString; {$IFEND} { System-encoded SBCS string (formerly AnsiString) } type AbSysString = {$IFDEF Posix}UTF8String{$ELSE}AnsiString{$ENDIF}; const AbCrc32Table : array[0..255] of DWord = ( $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3, $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7, $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b, $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59, $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f, $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d, $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01, $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65, $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9, $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f, $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7, $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5, $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b, $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f, $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713, $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777, $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45, $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9, $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d ); type TAbPathType = ( ptNone, ptRelative, ptAbsolute ); {===Helper functions===} function AbCopyFile(const Source, Destination: string; FailIfExists: Boolean): Boolean; procedure AbCreateDirectory( const Path : string ); {creates the requested directory tree. CreateDir is insufficient, because if you have a path x:\dir, and request x:\dir\sub1\sub2, (/dir and /dir/sub1/sub2 on Unix) it fails.} function AbCreateTempFile(const Dir : string) : string; function AbGetTempDirectory : string; {-Return the system temp directory} function AbGetTempFile(const Dir : string; CreateIt : Boolean) : string; function AbDrive(const ArchiveName : string) : Char; function AbDriveIsRemovable(const ArchiveName : string) : Boolean; function AbFileMatch(FileName : string; FileMask : string ) : Boolean; {see if FileName matches FileMask} procedure AbFindFiles(const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); procedure AbFindFilesEx( const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); function AbAddBackSlash(const DirName : string) : string; function AbFindNthSlash( const Path : string; n : Integer ) : Integer; {return the position of the character just before the nth backslash} function AbGetDriveFreeSpace(const ArchiveName : string) : Int64; {return the available space on the specified drive } function AbGetPathType( const Value : string ) : TAbPathType; {returns path type - none, relative or absolute} {$IFDEF MSWINDOWS} function AbGetShortFileSpec(const LongFileSpec : string ) : string; {$ENDIF} procedure AbIncFilename( var Filename : string; Value : Word ); procedure AbParseFileName( FileSpec : string; out Drive : string; out Path : string; out FileName : string ); procedure AbParsePath( Path : string; SubPaths : TStrings ); {- break abart path into subpaths --- Path : abbrevia/examples -> SubPaths[0] = abbrevia SubPaths[1] = examples} function AbPatternMatch(const Source : string; iSrc : Integer; const Pattern : string; iPat : Integer ) : Boolean; { recursive routine to see if the source string matches the pattern. Both ? and * wildcard characters are allowed.} function AbPercentage(V1, V2 : Int64) : Byte; {-Returns the ratio of V1 to V2 * 100} procedure AbStripDots( var FName : string ); {-strips relative path information} procedure AbStripDrive( var FName : string ); {-strips the drive off a filename} procedure AbFixName( var FName : string ); {-changes backslashes to forward slashes} procedure AbUnfixName( var FName : string ); {-changes forward slashes to backslashes} procedure AbUpdateCRC( var CRC : LongInt; const Buffer; Len : Integer ); function AbUpdateCRC32(CurByte : Byte; CurCrc : LongInt) : LongInt; {-Returns an updated crc32} function AbCRC32Of( const aValue : RawByteString ) : LongInt; function AbWriteVolumeLabel(const VolName : string; Drive : Char) : Cardinal; const AB_SPAN_VOL_LABEL = 'PKBACK# %3.3d'; function AbGetVolumeLabel(Drive : Char) : string; procedure AbSetSpanVolumeLabel(Drive: Char; VolNo : Integer); function AbTestSpanVolumeLabel(Drive: Char; VolNo : Integer): Boolean; procedure AbSetFileAttr(const aFileName : string; aAttr: Integer); {-Sets platform-native file attributes (DOS attr or Unix mode)} function AbFileGetSize(const aFileName : string) : Int64; type TAbAttrExRec = record Time: TDateTime; Size: Int64; Attr: Integer; Mode: {$IFDEF UNIX}mode_t{$ELSE}Cardinal{$ENDIF}; end; function AbFileGetAttrEx(const aFileName: string; out aAttr: TAbAttrExRec; FollowLinks: Boolean = True) : Boolean; function AbSwapLongEndianness(Value : LongInt): LongInt; { date and time stuff } const Date1900 {: LongInt} = $0001AC05; {Julian day count for 01/01/1900 -- TDateTime Start Date} Date1970 {: LongInt} = $00020FE4; {Julian day count for 01/01/1970 -- Unix Start Date} Unix0Date: TDateTime = 25569; {Date1970 - Date1900} SecondsInDay = 86400; {Number of seconds in a day} SecondsInHour = 3600; {Number of seconds in an hour} SecondsInMinute = 60; {Number of seconds in a minute} HoursInDay = 24; {Number of hours in a day} MinutesInHour = 60; {Number of minutes in an hour} MinutesInDay = 1440; {Number of minutes in a day} function AbUnixTimeToLocalDateTime(UnixTime : Int64) : TDateTime; function AbLocalDateTimeToUnixTime(DateTime : TDateTime) : Int64; function AbDosFileDateToDateTime(FileDate, FileTime : Word) : TDateTime; function AbDateTimeToDosFileDate(Value : TDateTime) : LongInt; function AbGetFileTime(const aFileName: string): TDateTime; function AbSetFileTime(const aFileName: string; aValue: TDateTime): Boolean; { file attributes } function AbDOS2UnixFileAttributes(Attr: LongInt): LongInt; function AbUnix2DosFileAttributes(Attr: LongInt): LongInt; { UNIX File Types and Permissions } const AB_FMODE_FILE = $0000; AB_FMODE_FIFO = $1000; AB_FMODE_CHARSPECFILE = $2000; AB_FMODE_DIR = $4000; AB_FMODE_BLOCKSPECFILE = $6000; AB_FMODE_FILE2 = $8000; AB_FMODE_FILELINK = $A000; AB_FMODE_SOCKET = $C000; AB_FPERMISSION_OWNERREAD = $0100; { read by owner } AB_FPERMISSION_OWNERWRITE = $0080; { write by owner } AB_FPERMISSION_OWNEREXECUTE = $0040; { execute/search by owner } AB_FPERMISSION_GROUPREAD = $0020; { read by group } AB_FPERMISSION_GROUPWRITE = $0010; { write by group } AB_FPERMISSION_GROUPEXECUTE = $0008; { execute/search by group } AB_FPERMISSION_OTHERREAD = $0004; { read by other } AB_FPERMISSION_OTHERWRITE = $0002; { write by other } AB_FPERMISSION_OTHEREXECUTE = $0001; { execute/search by other } AB_FPERMISSION_GENERIC = AB_FPERMISSION_OWNERREAD or AB_FPERMISSION_OWNERWRITE or AB_FPERMISSION_GROUPREAD or AB_FPERMISSION_OTHERREAD; { Unicode backwards compatibility functions } {$IFNDEF UNICODE} function CharInSet(C: AnsiChar; CharSet: TSysCharSet): Boolean; {$ENDIF} implementation uses StrUtils, LazUTF8, AbConst, AbExcept, DCOSUtils, DCStrUtils, DCBasicTypes, DCDateTimeUtils; (* {$IF DEFINED(FPCUnixAPI)} function mktemp(template: PAnsiChar): PAnsiChar; cdecl; external clib name 'mktemp'; {$ELSEIF DEFINED(PosixAPI)} function mktemp(template: PAnsiChar): PAnsiChar; cdecl; external libc name _PU + 'mktemp'; {$IFEND} {$IF DEFINED(FPCUnixAPI) AND DEFINED(Linux)} // FreePascal libc definitions type nl_item = cint; const __LC_CTYPE = 0; _NL_CTYPE_CLASS = (__LC_CTYPE shl 16); _NL_CTYPE_CODESET_NAME = (_NL_CTYPE_CLASS)+14; function nl_langinfo(__item: nl_item): PAnsiChar; cdecl; external clib name 'nl_langinfo'; {$IFEND} *) {===platform independent routines for platform dependent stuff=======} function ExtractShortName(const SR : TSearchRec) : string; begin {$IFDEF MSWINDOWS} {$WARN SYMBOL_PLATFORM OFF} if SR.FindData.cAlternateFileName[0] <> #0 then Result := SR.FindData.cAlternateFileName else Result := SR.FindData.cFileName; {$WARN SYMBOL_PLATFORM ON} {$ENDIF} {$IFDEF UNIX} Result := SR.Name; {$ENDIF} end; {====================================================================} { ========================================================================== } function AbCopyFile(const Source, Destination: string; FailIfExists: Boolean): Boolean; {$IFDEF UNIX} var DesStream, SrcStream: TFileStreamEx; {$ENDIF} begin {$IFDEF UNIX} Result := False; if not FailIfExists or not mbFileExists(Destination) then try SrcStream := TFileStreamEx.Create(Source, fmOpenRead or fmShareDenyWrite); try DesStream := TFileStreamEx.Create(Destination, fmCreate); try DesStream.CopyFrom(SrcStream, 0); Result := True; finally DesStream.Free; end; finally SrcStream.Free; end; except // Ignore errors and just return false end; {$ENDIF UNIX} {$IFDEF MSWINDOWS} Result := CopyFileW(PWideChar(CeUtf8ToUtf16(Source)), PWideChar(CeUtf8ToUtf16(Destination)), FailIfExists); {$ENDIF MSWINDOWS} end; { -------------------------------------------------------------------------- } procedure AbCreateDirectory( const Path : string ); {creates the requested directory tree. CreateDir is insufficient, because if you have a path x:\dir, and request x:\dir\sub1\sub2, (/dir and /dir/sub1/sub2 on Unix) it fails.} var iStartSlash : Integer; i : Integer; TempPath : string; begin if mbDirectoryExists( Path ) then Exit; {see how much of the path currently exists} if Pos( '\\', Path ) > 0 then {UNC Path \\computername\sharename\path1..\pathn} iStartSlash := 5 else {standard Path drive:\path1..\pathn} iStartSlash := 2; repeat {find the Slash at iStartSlash} i := AbFindNthSlash( Path, iStartSlash ); {get a temp path to try: drive:\path1} TempPath := Copy( Path, 1, i ); {if it doesn't exist, create it} if not mbDirectoryExists( TempPath ) then if mbCreateDir( TempPath ) = False then Exit; inc( iStartSlash ); until ( Length( TempPath ) = Length( Path ) ); end; { -------------------------------------------------------------------------- } function AbCreateTempFile(const Dir : string) : string; begin Result := AbGetTempFile(Dir, True); end; { -------------------------------------------------------------------------- } function AbGetTempDirectory : string; begin Result:= SysToUTF8(GetTempDir); end; { -------------------------------------------------------------------------- } function AbGetTempFile(const Dir : string; CreateIt : Boolean) : string; var hFile: System.THandle; TempPath : String; begin if mbDirectoryExists(Dir) then TempPath := IncludeTrailingPathDelimiter(Dir) else TempPath := AbGetTempDirectory; Result := GetTempName(TempPath + 'VMS'); if CreateIt then begin hFile := mbFileCreate(Result); if hFile <> feInvalidHandle then FileClose(hFile); end; end; { -------------------------------------------------------------------------- } function AbDrive(const ArchiveName : string) : Char; var iPos: Integer; Path : string; begin Path := ExpandFileName(ArchiveName); iPos := Pos(':', Path); if (iPos <= 0) then Result := 'A' else Result := Path[1]; end; { -------------------------------------------------------------------------- } function AbDriveIsRemovable(const ArchiveName : string) : Boolean; {$IFDEF MSWINDOWS} var Path: string; {$ENDIF} begin {$IFDEF MSWINDOWS} Path := ExpandFileName(ArchiveName); if AnsiStartsText('\\?\UNC\', Path) then Delete(Path, 1, 8) else if AnsiStartsText('\\?\', Path) then Delete(Path, 1, 4); Path := IncludeTrailingPathDelimiter(ExtractFileDrive(Path)); Result := GetDriveType(PChar(Path)) = DRIVE_REMOVABLE; {$ENDIF} {$IFDEF LINUX} {LINUX -- Following may not cover all the bases} Result := AnsiStartsText('/mnt/floppy', ExtractFilePath(ExpandFileName(ArchiveName))); {$ENDIF} {$IFDEF DARWIN} Result := False; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbGetDriveFreeSpace(const ArchiveName : string) : Int64; { attempt to find free space (in bytes) on drive/volume, returns -1 if fails for some reason } {$IFDEF MSWINDOWS} var FreeAvailable, TotalSpace: Int64; begin if GetDiskFreeSpaceExW(PWideChar(CeUtf8ToUtf16(ExtractFilePath(ExpandFileName(ArchiveName)))), FreeAvailable, TotalSpace, nil) then Result := FreeAvailable else Result := -1; {$ENDIF} {$IFDEF UNIX} var FStats : {$IFDEF PosixAPI}_statvfs{$ELSE}TStatFs{$ENDIF}; begin {$IF DEFINED(LibcAPI)} if statfs(PAnsiChar(ExtractFilePath(ArchiveName)), FStats) = 0 then Result := Int64(FStats.f_bAvail) * Int64(FStats.f_bsize) {$ELSEIF DEFINED(FPCUnixAPI)} if fpStatFS(PAnsiChar(UTF8ToSys(ExtractFilePath(ArchiveName))), @FStats) = 0 then Result := Int64(FStats.bAvail) * Int64(FStats.bsize) {$ELSEIF DEFINED(PosixAPI)} if statvfs(PAnsiChar(AbSysString(ExtractFilePath(ArchiveName))), FStats) = 0 then Result := Int64(FStats.f_bavail) * Int64(FStats.f_bsize) {$IFEND} else Result := -1; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbFileMatch(FileName: string; FileMask: string ): Boolean; {see if FileName matches FileMask} var DirMatch : Boolean; MaskDir : string; begin //FileName := UpperCase( FileName ); //FileMask := UpperCase( FileMask ); MaskDir := ExtractFilePath( FileMask ); if MaskDir = '' then DirMatch := True else DirMatch := AbPatternMatch( ExtractFilePath( FileName ), 1, MaskDir, 1 ); Result := DirMatch and AbPatternMatch( ExtractFileName( FileName ), 1, ExtractFileName( FileMask ), 1 ); end; { -------------------------------------------------------------------------- } procedure AbFindFiles( const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); var NewFile : string; SR : TSearchRec; Found : Integer; NameMask: string; begin Found := FindFirst( FileMask, SearchAttr, SR ); if Found = 0 then begin try NameMask := ExtractFileName(FileMask); while Found = 0 do begin NewFile := ExtractFilePath( FileMask ) + SR.Name; if (SR.Name <> AbThisDir) and (SR.Name <> AbParentDir) and AbPatternMatch(SR.Name, 1, NameMask, 1) then if (SR.Attr and faDirectory) <> 0 then FileList.Add( NewFile + PathDelim ) else FileList.Add( NewFile ); Found := FindNext( SR ); end; finally FindClose( SR ); end; end; if not Recurse then Exit; NewFile := ExtractFilePath( FileMask ); if ( NewFile <> '' ) and ( NewFile[Length(NewFile)] <> AbPathDelim) then NewFile := NewFile + AbPathDelim; NewFile := NewFile + AbAnyFile; Found := FindFirst( NewFile, faDirectory or SearchAttr, SR ); if Found = 0 then begin try while ( Found = 0 ) do begin if ( SR.Name <> AbThisDir ) and ( SR.Name <> AbParentDir ) and ((SR.Attr and faDirectory) > 0 ) then AbFindFiles( ExtractFilePath( NewFile ) + SR.Name + AbPathDelim + ExtractFileName( FileMask ), SearchAttr, FileList, True ); Found := FindNext( SR ); end; finally FindClose( SR ); end; end; end; { -------------------------------------------------------------------------- } procedure AbFindFilesEx( const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); var I, J: Integer; MaskPart: string; begin I := 1; while I <= Length(FileMask) do begin J := I; while (I <= Length(FileMask)) and (FileMask[I] <> AbPathSep) do Inc(I); MaskPart := Trim(Copy(FileMask, J, I - J)); if (I <= Length(FileMask)) and (FileMask[I] = AbPathSep) then Inc(I); AbFindFiles(MaskPart, SearchAttr, FileList, Recurse); end; end; { -------------------------------------------------------------------------- } function AbAddBackSlash(const DirName : string) : string; { Add a default slash to a directory name } const AbDelimSet : set of AnsiChar = [AbPathDelim, ':', #0]; begin Result := DirName; if Length(DirName) = 0 then Exit; if not CharInSet(DirName[Length(DirName)], AbDelimSet) then Result := DirName + AbPathDelim; end; { -------------------------------------------------------------------------- } function AbFindNthSlash( const Path : string; n : Integer ) : Integer; { return the position of the character just before the nth slash } var i : Integer; Len : Integer; iSlash : Integer; begin Len := Length( Path ); Result := Len; iSlash := 0; i := 0; while i <= Len do begin if Path[i] = AbPathDelim then begin inc( iSlash ); if iSlash = n then begin Result := pred( i ); break; end; end; inc( i ); end; end; { -------------------------------------------------------------------------- } function AbGetPathType( const Value : string ) : TAbPathType; { returns path type - none, relative or absolute } begin Result := ptNone; {$IFDEF MSWINDOWS} {check for drive/unc info} if ( Pos( '\\', Value ) > 0 ) or ( Pos( ':', Value ) > 0 ) then {$ENDIF MSWINDOWS} {$IFDEF UNIX} { UNIX absolute paths start with a slash } if (Length(Value) > 0) and (Value[1] = AbPathDelim) then {$ENDIF UNIX} Result := ptAbsolute else if ( Pos( AbPathDelim, Value ) > 0 ) or ( Pos( AB_ZIPPATHDELIM, Value ) > 0 ) then Result := ptRelative; end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} {$WARN SYMBOL_PLATFORM OFF} function AbGetShortFileSpec(const LongFileSpec : string ) : string; var SR : TSearchRec; Search : string; Drive : string; Path : string; FileName : string; Found : Integer; SubPaths : TStrings; i : Integer; begin AbParseFileName( LongFileSpec, Drive, Path, FileName ); SubPaths := TStringList.Create; try AbParsePath( Path, SubPaths ); Search := Drive; Result := Search + AbPathDelim; if SubPaths.Count > 0 then for i := 0 to pred( SubPaths.Count ) do begin Search := Search + AbPathDelim + SubPaths[i]; Found := FindFirst( Search, faHidden + faSysFile + faDirectory, SR ); if Found <> 0 then raise EAbException.Create( 'Path not found' ); try Result := Result + ExtractShortName(SR) + AbPathDelim; finally FindClose( SR ); end; end; Search := Search + AbPathDelim + FileName; Found := FindFirst( Search, faReadOnly + faHidden + faSysFile + faArchive, SR ); if Found <> 0 then raise EAbFileNotFound.Create; try Result := Result + ExtractShortName(SR); finally FindClose( SR ); end; finally SubPaths.Free; end; end; {$WARN SYMBOL_PLATFORM ON} {$ENDIF} { -------------------------------------------------------------------------- } procedure AbIncFilename( var Filename : string; Value : Word ); { place value at the end of filename, e.g. Files.C04 } var Ext : string; I : Word; begin I := (Value + 1) mod 100; Ext := ExtractFileExt(Filename); if (Length(Ext) < 2) then Ext := '.' + Format('%.2d', [I]) else Ext := Ext[1] + Ext[2] + Format('%.2d', [I]); Filename := ChangeFileExt(Filename, Ext); end; { -------------------------------------------------------------------------- } procedure AbParseFileName( FileSpec : string; out Drive : string; out Path : string; out FileName : string ); var i : Integer; iColon : Integer; iStartSlash : Integer; begin if Pos( AB_ZIPPATHDELIM, FileSpec ) > 0 then AbUnfixName( FileSpec ); FileName := ExtractFileName( FileSpec ); Path := ExtractFilePath( FileSpec ); {see how much of the path currently exists} iColon := Pos( ':', Path ); if Pos( '\\', Path ) > 0 then begin {UNC Path \\computername\sharename\path1..\pathn} {everything up to the 4th slash is the drive} iStartSlash := 4; i := AbFindNthSlash( Path, iStartSlash ); Drive := Copy( Path, 1, i ); Delete( Path, 1, i + 1 ); end else if iColon > 0 then begin Drive := Copy( Path, 1, iColon ); Delete( Path, 1, iColon ); if Path[1] = AbPathDelim then Delete( Path, 1, 1 ); end; end; { -------------------------------------------------------------------------- } procedure AbParsePath( Path : string; SubPaths : TStrings ); { break abart path into subpaths --- Path : abbrevia/examples > SubPaths[0] = abbrevia SubPaths[1] = examples} var i : Integer; iStart : Integer; iStartSlash : Integer; SubPath : string; begin if Path = '' then Exit; if Path[ Length( Path ) ] = AbPathDelim then Delete( Path, Length( Path ), 1 ); iStart := 1; iStartSlash := 1; repeat {find the Slash at iStartSlash} i := AbFindNthSlash( Path, iStartSlash ); {get the subpath} SubPath := Copy( Path, iStart, i - iStart + 1 ); iStart := i + 2; inc( iStartSlash ); SubPaths.Add( SubPath ); until ( i = Length( Path ) ); end; { -------------------------------------------------------------------------- } function AbPatternMatch(const Source : string; iSrc : Integer; const Pattern : string; iPat : Integer ) : Boolean; { recursive routine to see if the source string matches the pattern. Both ? and * wildcard characters are allowed. Compares Source from iSrc to Length(Source) to Pattern from iPat to Length(Pattern)} var Matched : Boolean; k : Integer; begin if Length( Source ) = 0 then begin Result := Length( Pattern ) = 0; Exit; end; if iPat = 1 then begin if ( CompareStr( Pattern, AbDosAnyFile) = 0 ) or ( CompareStr( Pattern, AbUnixAnyFile ) = 0 ) then begin Result := True; Exit; end; end; if Length( Pattern ) = 0 then begin Result := (Length( Source ) - iSrc + 1 = 0); Exit; end; while True do begin if ( Length( Source ) < iSrc ) and ( Length( Pattern ) < iPat ) then begin Result := True; Exit; end; if Length( Pattern ) < iPat then begin Result := False; Exit; end; if Pattern[iPat] = '*' then begin k := iPat; if ( Length( Pattern ) < iPat + 1 ) then begin Result := True; Exit; end; while True do begin Matched := AbPatternMatch( Source, k, Pattern, iPat + 1 ); if Matched or ( Length( Source ) < k ) then begin Result := Matched; Exit; end; inc( k ); end; end else begin if ( (Pattern[iPat] = '?') and ( Length( Source ) <> iSrc - 1 ) ) or ( Pattern[iPat] = Source[iSrc] ) then begin inc( iPat ); inc( iSrc ); end else begin Result := False; Exit; end; end; end; end; { -------------------------------------------------------------------------- } function AbPercentage(V1, V2 : Int64): Byte; { Returns the ratio of V1 to V2 * 100 } begin if V2 <= 0 then Result := 0 else if V1 >= V2 then Result := 100 else Result := (V1 * 100) div V2; end; { -------------------------------------------------------------------------- } procedure AbStripDots( var FName : string ); { strips relative path information, e.g. ".."} begin while Pos( AbParentDir + AbPathDelim, FName ) = 1 do System.Delete( FName, 1, 3 ); end; { -------------------------------------------------------------------------- } procedure AbStripDrive( var FName : string ); { strips the drive off a filename } var Drive, Path, Name : string; begin AbParseFileName( FName, Drive, Path, Name ); FName := Path + Name; end; { -------------------------------------------------------------------------- } procedure AbFixName( var FName : string ); { changes backslashes to forward slashes } var i : Integer; begin for i := 1 to Length( FName ) do if FName[i] = AbPathDelim then FName[i] := AB_ZIPPATHDELIM; end; { -------------------------------------------------------------------------- } procedure AbUnfixName( var FName : string ); { changes forward slashes to backslashes } var i : Integer; begin for i := 1 to Length( FName ) do if FName[i] = AB_ZIPPATHDELIM then FName[i] := AbPathDelim; end; { -------------------------------------------------------------------------- } procedure AbUpdateCRC( var CRC : LongInt; const Buffer; Len : Integer ); var BufPtr : PByte; i : Integer; CRCTemp : DWORD; begin BufPtr := @Buffer; CRCTemp := CRC; for i := 0 to pred( Len ) do begin CRCTemp := AbCrc32Table[ Byte(CrcTemp) xor (BufPtr^) ] xor ((CrcTemp shr 8) and $00FFFFFF); Inc(BufPtr); end; CRC := CRCTemp; end; { -------------------------------------------------------------------------- } function AbUpdateCRC32(CurByte : Byte; CurCrc : LongInt) : LongInt; { Return the updated 32bit CRC } { Normally a good candidate for basm, but Delphi32's code generation couldn't be beat on this one!} begin Result := DWORD(AbCrc32Table[ Byte(CurCrc xor LongInt( CurByte ) ) ] xor ((CurCrc shr 8) and DWORD($00FFFFFF))); end; { -------------------------------------------------------------------------- } function AbCRC32Of( const aValue : RawByteString ) : LongInt; begin Result := -1; AbUpdateCRC(Result, aValue[1], Length(aValue)); Result := not Result; end; { -------------------------------------------------------------------------- } function AbWriteVolumeLabel(const VolName : string; Drive : Char) : Cardinal; {$IFDEF MSWINDOWS} var Temp : UnicodeString; Vol : array[0..11] of WideChar; Root : array[0..3] of WideChar; {$ENDIF} begin {$IFDEF MSWINDOWS} Temp := CeUtf8ToUtf16(VolName); StrPCopyW(Root, '%:' + AbPathDelim); Root[0] := Drive; if Length(Temp) > 11 then SetLength(Temp, 11); StrPCopyW(Vol, Temp); if Windows.SetVolumeLabelW(Root, Vol) then Result := 0 else Result := GetLastError; {$ENDIF MSWINDOWS} {$IFDEF UNIX} { Volume labels not supported on Unix } Result := 0; {$ENDIF UNIX} end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} function AbOffsetFromUTC: LongInt; { local timezone's offset from UTC in seconds (UTC = local + bias) } var TZI: TTimeZoneInformation; begin case GetTimeZoneInformation(TZI) of TIME_ZONE_ID_UNKNOWN: Result := TZI.Bias; TIME_ZONE_ID_DAYLIGHT: Result := TZI.Bias + TZI.DaylightBias; TIME_ZONE_ID_STANDARD: Result := TZI.Bias + TZI.StandardBias else Result := 0 end; Result := Result * SecondsInMinute; end; {$ENDIF} { -------------------------------------------------------------------------- } function AbUnixTimeToLocalDateTime(UnixTime : Int64) : TDateTime; { convert UTC unix date to Delphi TDateTime in local timezone } {$IFDEF MSWINDOWS} var Hrs, Mins, Secs : Word; TodaysSecs : LongInt; Time: TDateTime; begin UnixTime := UnixTime - AbOffsetFromUTC; TodaysSecs := UnixTime mod SecondsInDay; Hrs := TodaysSecs div SecondsInHour; TodaysSecs := TodaysSecs - (Hrs * SecondsInHour); Mins := TodaysSecs div SecondsInMinute; Secs := TodaysSecs - (Mins * SecondsInMinute); if TryEncodeTime(Hrs, Mins, Secs, 0, Time) then Result := Unix0Date + (UnixTime div SecondsInDay) + Time else Result := 0; {$ENDIF} {$IFDEF UNIX} begin Result := UnixFileTimeToDateTime(TUnixFileTime(UnixTime)); {$ENDIF} end; { -------------------------------------------------------------------------- } function AbLocalDateTimeToUnixTime(DateTime : TDateTime) : Int64; { convert local Delphi TDateTime to UTC unix date } {$IFDEF MSWINDOWS} var Hrs, Mins, Secs, MSecs : Word; Dt, Tm : TDateTime; begin Dt := Trunc(DateTime); Tm := DateTime - Dt; if Dt < Unix0Date then Result := 0 else Result := Trunc(Dt - Unix0Date) * SecondsInDay; DecodeTime(Tm, Hrs, Mins, Secs, MSecs); Result := Result + (Hrs * SecondsInHour) + (Mins * SecondsInMinute) + Secs; Result := Result + AbOffsetFromUTC; {$ENDIF} {$IFDEF UNIX} begin Result := Int64(DateTimeToUnixFileTime(DateTime)); {$ENDIF} end; { -------------------------------------------------------------------------- } function AbDosFileDateToDateTime(FileDate, FileTime : Word) : TDateTime; var Yr, Mo, Dy : Word; Hr, Mn, S : Word; begin Yr := FileDate shr 9 + 1980; Mo := FileDate shr 5 and 15; if Mo < 1 then Mo := 1; if Mo > 12 then Mo := 12; Dy := FileDate and 31; if Dy < 1 then Dy := 1; if Dy > DaysInAMonth(Yr, Mo) then Dy := DaysInAMonth(Yr, Mo); Hr := FileTime shr 11; if Hr > 23 then Hr := 23; Mn := FileTime shr 5 and 63; if Mn > 59 then Mn := 59; S := FileTime and 31 shl 1; if S > 59 then S := 59; Result := EncodeDate(Yr, Mo, Dy) + EncodeTime(Hr, Mn, S, 0); end; function AbDateTimeToDosFileDate(Value : TDateTime) : LongInt; {$IFDEF MSWINDOWS} begin Result := DateTimeToFileDate(Value); {$ENDIF MSWINDOWS} {$IFDEF UNIX} var Yr, Mo, Dy : Word; Hr, Mn, S, MS: Word; begin DecodeDate(Value, Yr, Mo, Dy); if (Yr < 1980) or (Yr > 2107) then { outside DOS file date year range } Yr := 1980; DecodeTime(Value, Hr, Mn, S, MS); LongRec(Result).Lo := (S shr 1) or (Mn shl 5) or (Hr shl 11); LongRec(Result).Hi := Dy or (Mo shl 5) or (Word(Yr - 1980) shl 9); {$ENDIF UNIX} end; { -------------------------------------------------------------------------- } function AbGetFileTime(const aFileName: string): TDateTime; var Attr: TAbAttrExRec; begin AbFileGetAttrEx(aFileName, Attr); Result := Attr.Time; end; function AbSetFileTime(const aFileName: string; aValue: TDateTime): Boolean; begin Result:= mbFileSetTime(aFileName, DateTimeToFileTime(aValue)); end; { -------------------------------------------------------------------------- } function AbSwapLongEndianness(Value : LongInt): LongInt; { convert BigEndian <-> LittleEndian 32-bit value } type TCastArray = array [0..3] of Byte; var i : Integer; begin for i := 3 downto 0 do TCastArray(Result)[3-i] := TCastArray(Value)[i]; end; { -------------------------------------------------------------------------- } function AbDOS2UnixFileAttributes(Attr: LongInt): LongInt; begin {$IFDEF LINUX} {$IF NOT ((FPC_VERSION = 2) and (FPC_RELEASE = 6) and (FPC_PATCH = 0))} {$WARN SYMBOL_PLATFORM OFF} {$ENDIF} {$ELSE} {$WARN SYMBOL_PLATFORM OFF} {$ENDIF} Result := { default permissions } AB_FPERMISSION_OWNERREAD or AB_FPERMISSION_GROUPREAD or AB_FPERMISSION_OTHERREAD; if (Attr and faReadOnly) = 0 then Result := Result or AB_FPERMISSION_OWNERWRITE; if (Attr and faSymLink) <> 0 then Result := Result or AB_FMODE_FILELINK or AB_FPERMISSION_OWNEREXECUTE else if (Attr and faDirectory) <> 0 then Result := Result or AB_FMODE_DIR or AB_FPERMISSION_OWNEREXECUTE else Result := Result or AB_FMODE_FILE; {$IFDEF LINUX} {$IF NOT ((FPC_VERSION = 2) and (FPC_RELEASE = 6) and (FPC_PATCH = 0))} {$WARN SYMBOL_PLATFORM ON} {$ENDIF} {$ELSE} {$WARN SYMBOL_PLATFORM ON} {$ENDIF} end; { -------------------------------------------------------------------------- } function AbUnix2DosFileAttributes(Attr: LongInt): LongInt; begin {$IFDEF LINUX} {$IF NOT ((FPC_VERSION = 2) and (FPC_RELEASE = 6) and (FPC_PATCH = 0))} {$WARN SYMBOL_PLATFORM OFF} {$ENDIF} {$ELSE} {$WARN SYMBOL_PLATFORM OFF} {$ENDIF} Result := 0; case (Attr and $F000) of AB_FMODE_FILE, AB_FMODE_FILE2: { standard file } Result := 0; AB_FMODE_DIR: { directory } Result := Result or faDirectory; AB_FMODE_FILELINK: { symlink} Result := Result or faSymLink; AB_FMODE_FIFO, AB_FMODE_CHARSPECFILE, AB_FMODE_BLOCKSPECFILE, AB_FMODE_SOCKET: Result := Result or faSysFile; end; if (Attr and AB_FPERMISSION_OWNERWRITE) <> AB_FPERMISSION_OWNERWRITE then Result := Result or faReadOnly; {$IFDEF LINUX} {$IF NOT ((FPC_VERSION = 2) and (FPC_RELEASE = 6) and (FPC_PATCH = 0))} {$WARN SYMBOL_PLATFORM ON} {$ENDIF} {$ELSE} {$WARN SYMBOL_PLATFORM ON} {$ENDIF} end; { -------------------------------------------------------------------------- } procedure AbSetFileAttr(const aFileName : string; aAttr: Integer); begin {$IFDEF MSWINDOWS} mbFileSetAttr(aFileName, aAttr); {$ENDIF} {$IF DEFINED(LibcAPI) OR DEFINED(PosixAPI)} chmod(PAnsiChar(AbSysString(aFileName)), aAttr); {$ELSEIF DEFINED(FPCUnixAPI)} mbFileSetAttr(aFileName, aAttr); {$IFEND} end; { -------------------------------------------------------------------------- } function AbFileGetSize(const aFileName : string) : Int64; var SR: TAbAttrExRec; begin if AbFileGetAttrEx(aFileName, SR) then Result := SR.Size else Result := -1; end; { -------------------------------------------------------------------------- } function AbFileGetAttrEx(const aFileName: string; out aAttr: TAbAttrExRec; FollowLinks: Boolean = True) : Boolean; var {$IFDEF MSWINDOWS} FileDate: LongRec; FindData: TWin32FindDataW; LocalFileTime: Windows.TFileTime; {$ENDIF} {$IFDEF FPCUnixAPI} StatBuf: stat; {$ENDIF} {$IFDEF LibcAPI} StatBuf: TStatBuf64; {$ENDIF} {$IFDEF PosixAPI} StatBuf: _stat; {$ENDIF} begin aAttr.Time := 0; aAttr.Size := -1; aAttr.Attr := -1; aAttr.Mode := 0; {$IFDEF MSWINDOWS} Result := GetFileAttributesExW(PWideChar(UTF16LongName(aFileName)), GetFileExInfoStandard, @FindData); if Result then begin aAttr.Time := WinFileTimeToDateTime(FindData.ftLastWriteTime); LARGE_INTEGER(aAttr.Size).LowPart := FindData.nFileSizeLow; LARGE_INTEGER(aAttr.Size).HighPart := FindData.nFileSizeHigh; aAttr.Attr := FindData.dwFileAttributes; aAttr.Mode := AbDOS2UnixFileAttributes(FindData.dwFileAttributes); end; {$ENDIF} {$IFDEF UNIX} {$IFDEF FPCUnixAPI} if FollowLinks then Result := (FpStat(UTF8ToSys(aFileName), StatBuf) = 0) else Result := (FpLStat(UTF8ToSys(aFileName), StatBuf) = 0); {$ENDIF} {$IFDEF LibcAPI} // Work around Kylix QC#2761: Stat64, et al., are defined incorrectly Result := (__lxstat64(_STAT_VER, PAnsiChar(aFileName), StatBuf) = 0); {$ENDIF} {$IFDEF PosixAPI} Result := (stat(PAnsiChar(AbSysString(aFileName)), StatBuf) = 0); {$ENDIF} if Result then begin aAttr.Time := FileDateToDateTime(StatBuf.st_mtime); aAttr.Size := StatBuf.st_size; aAttr.Attr := AbUnix2DosFileAttributes(StatBuf.st_mode); aAttr.Mode := StatBuf.st_mode; end; {$ENDIF UNIX} end; const MAX_VOL_LABEL = 16; function AbGetVolumeLabel(Drive : Char) : string; {-Get the volume label for the specified drive.} {$IFDEF MSWINDOWS} var Root : WideString; Flags, MaxLength : DWORD; NameSize : Integer; VolName : WideString; {$ENDIF} begin {$IFDEF MSWINDOWS} NameSize := 0; Root := Drive + ':\'; SetLength(VolName, MAX_VOL_LABEL); Result := ''; if GetVolumeInformationW(PWideChar(Root), PWideChar(VolName), Length(VolName), nil, MaxLength, Flags, nil, NameSize) then Result := Utf16ToUtf8(VolName); {$ELSE} Result := ''; //Stop Gap, spanning support needs to be rethought for Unix {$ENDIF} end; procedure AbSetSpanVolumeLabel(Drive: Char; VolNo : Integer); begin AbWriteVolumeLabel(Format(AB_SPAN_VOL_LABEL, [VolNo]), Drive); end; function AbTestSpanVolumeLabel(Drive: Char; VolNo : Integer): Boolean; var VolLabel, TestLabel : string; begin TestLabel := Format(AB_SPAN_VOL_LABEL, [VolNo]); VolLabel := UpperCase(AbGetVolumeLabel(Drive)); Result := VolLabel = TestLabel; end; { Unicode backwards compatibility functions } {$IFNDEF UNICODE} function CharInSet(C: AnsiChar; CharSet: TSysCharSet): Boolean; begin Result := C in CharSet; end; {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abvmstrm.pas�����������������������������������������0000644�0001750�0000144�00000041623�14743153644�022776� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbVMStrm.pas *} {*********************************************************} {* ABBREVIA: Virtual Memory Stream *} {*********************************************************} unit AbVMStrm; {$I AbDefine.inc} interface uses Classes; const AB_VMSPageSize = 4096; {must be a power of two} AB_VMSMaxPages = 16384; {makes 64MB with the above value} type PvmsPage = ^TvmsPage; TvmsPage = packed record vpStmOfs : Int64; {value will be multiple of AB_VMSPageSize} vpLRU : integer; {'time' page was last accessed} vpDirty : Boolean; {has the page been changed?} vpData : array [0..pred(AB_VMSPageSize)] of byte; {stream data} end; type TAbVirtualMemoryStream = class(TStream) protected {private} vmsCachePage : PvmsPage; {the latest page used} vmsLRU : Longint; {'tick' value} vmsMaxMemToUse : Longword; {maximum memory to use for data} vmsMaxPages : Integer; {maximum data pages} vmsPageList : TList; {page array, sorted by offset} vmsPosition : Int64; {position of stream} vmsSize : Int64; {size of stream} vmsSwapFileDir : string; {swap file directory} vmsSwapFileName : string; {swap file name} vmsSwapFileSize : Int64; {size of swap file} vmsSwapHandle : System.THandle; {swap file handle} protected procedure vmsSetMaxMemToUse(aNewMem : Longword); function vmsAlterPageList(aNewMem : Longword) : Longword; procedure vmsFindOldestPage(out OldestInx : Longint; out OldestPage: PvmsPage); function vmsGetNextLRU : Longint; function vmsGetPageForOffset(aOffset : Int64) : PvmsPage; procedure vmsSwapFileCreate; procedure vmsSwapFileDestroy; procedure vmsSwapFileRead(aPage : PvmsPage); procedure vmsSwapFileWrite(aPage : PvmsPage); public constructor Create; {-create the virtual memory stream} destructor Destroy; override; {-destroy the virtual memory stream} function Read(var Buffer; Count : Longint) : Longint; override; {-read from the stream into a buffer} function Write(const Buffer; Count : Longint) : Longint; override; {-write to the stream from a buffer} function Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; override; {-seek to a particular point in the stream} procedure SetSize(const NewSize : Int64); override; {-set the stream size} property MaxMemToUse : Longword read vmsMaxMemToUse write vmsSetMaxMemToUse; {-maximum memory to use for data before swapping to disk} property SwapFileDirectory : string read vmsSwapFileDir write vmsSwapFileDir; end; implementation uses {$IFDEF MSWINDOWS} Windows, // Fix warning about unexpanded inline functions {$ENDIF} SysUtils, AbExcept, AbUtils, DCOSUtils; const LastLRUValue = $7FFFFFFF; {===TAbVirtualMemoryStream===========================================} constructor TAbVirtualMemoryStream.Create; var Page : PvmsPage; begin inherited Create; {create the page array} vmsPageList := TList.Create; {create the first page} New(Page); with Page^ do begin vpStmOfs := 0; vpLRU := vmsGetNextLRU; vpDirty := False; FillChar(vpData, AB_VMSPageSize, 0); end; vmsPageList.Insert(0, pointer(Page)); {prime the cache, from now on the cache will never be nil} vmsCachePage := Page; {default to using all allowed pages} MaxMemToUse := AB_VMSMaxPages * AB_VMSPageSize; end; {--------} destructor TAbVirtualMemoryStream.Destroy; var Inx : integer; begin {destroy the swap file} vmsSwapFileDestroy; {throw away all pages in the list} if (vmsPageList <> nil) then begin for Inx := 0 to pred(vmsPageList.Count) do Dispose(PvmsPage(vmsPageList[Inx])); vmsPageList.Destroy; end; {let our ancestor clean up} inherited Destroy; end; {--------} function TAbVirtualMemoryStream.Read(var Buffer; Count : Longint) : Longint; var BufPtr : PByte; Page : PvmsPage; PageDataInx : integer; Posn : int64; BytesToGo : int64; BytesToRead : int64; StartOfs : int64; begin {reading is complicated by the fact we can only read in chunks of AB_VMSPageSize: we need to partition out the overall read into a read from a partial page, zero or more reads from complete pages and then a possible read from a partial page} {initialise some variables, note that the complex calc in the expression for PageDataInx is the offset of the start of the page where Posn is found.} BufPtr := @Buffer; Posn := vmsPosition; PageDataInx := Posn - (Posn and (not pred(AB_VMSPageSize))); BytesToRead := AB_VMSPageSize - PageDataInx; {calculate the actual number of bytes to read - this depends on the current position and size of the stream} BytesToGo := Count; if (vmsSize < (vmsPosition + Count)) then BytesToGo := vmsSize - vmsPosition; if (BytesToGo < 0) then BytesToGo := 0; Result := BytesToGo; {while we have bytes to read, read them} while (BytesToGo <> 0) do begin if (BytesToRead > BytesToGo) then BytesToRead := BytesToGo; StartOfs := Posn and (not pred(AB_VMSPageSize)); if (vmsCachePage^.vpStmOfs = StartOfs) then Page := vmsCachePage else Page := vmsGetPageForOffset(StartOfs); Move(Page^.vpData[PageDataInx], BufPtr^, BytesToRead); dec(BytesToGo, BytesToRead); inc(Posn, BytesToRead); inc(BufPtr, BytesToRead); PageDataInx := 0; BytesToRead := AB_VMSPageSize; end; {remember our new position} vmsPosition := Posn; end; {--------} function TAbVirtualMemoryStream.Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; begin case Origin of soBeginning : vmsPosition := Offset; soCurrent : inc(vmsPosition, Offset); soEnd : vmsPosition := vmsSize + Offset; else raise EAbVMSInvalidOrigin.Create( Integer(Origin)); end; Result := vmsPosition; end; {--------} procedure TAbVirtualMemoryStream.SetSize(const NewSize : Int64); var Page : PvmsPage; Inx : integer; NewFileSize : Int64; begin if (NewSize < vmsSize) then begin {go through the page list discarding pages whose offset is greater than our new size; don't bother saving any data from them since it be beyond the end of the stream anyway} {never delete the last page here} for Inx := pred(vmsPageList.Count) downto 1 do begin Page := PvmsPage(vmsPageList[Inx]); if (Page^.vpStmOfs >= NewSize) then begin Dispose(Page); vmsPageList.Delete(Inx); end else begin Break; end; end; { Reset cache to the first page in case the cached page was deleted. } vmsCachePage := vmsPageList[0]; {force the swap file file size in range, it'll be a multiple of AB_VMSPageSize} NewFileSize := pred(NewSize + AB_VMSPageSize) and (not pred(AB_VMSPageSize)); if (NewFileSize < vmsSwapFileSize) then vmsSwapFileSize := NewFileSize; {ignore the swap file itself} end; vmsSize := NewSize; if (vmsPosition > NewSize) then vmsPosition := NewSize; end; {--------} function TAbVirtualMemoryStream.vmsAlterPageList(aNewMem : Longword) : Longword; var NumPages : Longint; Page : PvmsPage; i : integer; OldestPageNum : Longint; begin {calculate the max number of pages required} if aNewMem = 0 then NumPages := 1 // always have at least one page else NumPages := pred(aNewMem + AB_VMSPageSize) div AB_VMSPageSize; if (NumPages > AB_VMSMaxPages) then NumPages := AB_VMSMaxPages; {if the maximum number of pages means we have to shrink the current list, do so, tossing out the oldest pages first} if (NumPages < vmsPageList.Count) then begin for i := 1 to (vmsPageList.Count - NumPages) do begin {find the oldest page} vmsFindOldestPage(OldestPageNum, Page); {if it is dirty, write it out to the swap file} if Page^.vpDirty then begin vmsSwapFileWrite(Page); end; {remove it from the page list} vmsPageList.Delete(OldestPageNum); {free the page memory} Dispose(Page); end; { Reset cache to the first page in case the cached page was deleted. } vmsCachePage := vmsPageList[0]; end; {remember our new max number of pages} vmsMaxPages := NumPages; Result := NumPages * AB_VMSPageSize; end; {--------} procedure TAbVirtualMemoryStream.vmsFindOldestPage(out OldestInx : Longint; out OldestPage: PvmsPage); var OldestLRU : Longint; Inx : integer; Page : PvmsPage; begin OldestInx := -1; OldestLRU := LastLRUValue; for Inx := 0 to pred(vmsPageList.Count) do begin Page := PvmsPage(vmsPageList[Inx]); if (Page^.vpLRU < OldestLRU) then begin OldestInx := Inx; OldestLRU := Page^.vpLRU; OldestPage := Page; end; end; end; {--------} function TAbVirtualMemoryStream.vmsGetNextLRU : Longint; var Inx : integer; begin if (vmsLRU = LastLRUValue) then begin {reset all LRUs in list} for Inx := 0 to pred(vmsPageList.Count) do PvmsPage(vmsPageList[Inx])^.vpLRU := 0; vmsLRU := 0; end; inc(vmsLRU); Result := vmsLRU; end; {--------} function TAbVirtualMemoryStream.vmsGetPageForOffset(aOffset : Int64) : PvmsPage; var Page : PvmsPage; PageOfs : Int64; L, M, R : integer; OldestPageNum : integer; CreatedNewPage: boolean; begin {using a sequential or a binary search (depending on the number of pages), try to find the page in the cache; we'll do a sequential search if the number of pages is very small, eg less than 4} if (vmsPageList.Count < 4) then begin L := vmsPageList.Count; for M := 0 to pred(vmsPageList.Count) do begin Page := PvmsPage(vmsPageList[M]); PageOfs := Page^.vpStmOfs; if (aOffset < PageOfs) then begin L := M; Break; end; if (aOffset = PageOfs) then begin Page^.vpLRU := vmsGetNextLRU; vmsCachePage := Page; Result := Page; Exit; end; end; end else {we need to do a binary search} begin L := 0; R := pred(vmsPageList.Count); repeat M := (L + R) div 2; Page := PvmsPage(vmsPageList[M]); PageOfs := Page^.vpStmOfs; if (aOffset < PageOfs) then R := pred(M) else if (aOffset > PageOfs) then L := succ(M) else {aOffset = PageOfs} begin Page^.vpLRU := vmsGetNextLRU; vmsCachePage := Page; Result := Page; Exit; end; until (L > R); end; {if we get here the page for the offset is not present in the page list, and once created/loaded, the page should be inserted at L} {enter a try..except block so that if a new page is created and an exception occurs, the page is freed} CreatedNewPage := false; Result := nil; try {if there is room to insert a new page, create one ready} if (vmsPageList.Count < vmsMaxPages) then begin New(Page); CreatedNewPage := true; end {otherwise there is no room for the insertion, so find the oldest page in the list and discard it} else {vmsMaxPages <= vmsPageList.Count} begin {find the oldest page} vmsFindOldestPage(OldestPageNum, Page); {if it is dirty, write it out to the swap file} if Page^.vpDirty then begin vmsSwapFileWrite(Page); end; {remove it from the page list} vmsPageList.Delete(OldestPageNum); {patch up the insertion point, in case the page just deleted was before it} if (OldestPageNum < L) then dec(L); end; {set all the page fields} with Page^ do begin vpStmOfs := aOffset; vpLRU := vmsGetNextLRU; vpDirty := False; vmsSwapFileRead(Page); end; {insert the page into the correct spot} vmsPageList.Insert(L, pointer(Page)); {return the page, remembering to save it in the cache} vmsCachePage := Page; Result := Page; except if CreatedNewPage then Dispose(Page); raise; end;{try..except} end; {--------} procedure TAbVirtualMemoryStream.vmsSetMaxMemToUse(aNewMem : Longword); begin vmsMaxMemToUse := vmsAlterPageList(aNewMem); end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileCreate; begin if (vmsSwapHandle = 0) then begin vmsSwapFileName := AbCreateTempFile(vmsSwapFileDir); vmsSwapHandle := mbFileOpen(vmsSwapFileName, fmOpenReadWrite); if (vmsSwapHandle <= 0) then begin vmsSwapHandle := 0; mbDeleteFile(vmsSwapFileName); raise EAbVMSErrorOpenSwap.Create( vmsSwapFileName ); end; vmsSwapFileSize := 0; end; end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileDestroy; begin if (vmsSwapHandle <> 0) then begin FileClose(vmsSwapHandle); mbDeleteFile(vmsSwapFileName); vmsSwapHandle := 0; end; end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileRead(aPage : PvmsPage); var BytesRead : Longint; SeekResult: Int64; begin if (vmsSwapHandle = 0) or (aPage^.vpStmOfs >= vmsSwapFileSize) then begin {there is nothing to be read from the disk (either the swap file doesn't exist or it's too small) so zero out the page data} FillChar(aPage^.vpData, AB_VMSPageSize, 0) end else {there is something to be read from the swap file} begin SeekResult := FileSeek(vmsSwapHandle, aPage^.vpStmOfs, 0); if (SeekResult = -1) then raise EAbVMSSeekFail.Create( vmsSwapFileName ); BytesRead := FileRead(vmsSwapHandle, aPage^.vpData, AB_VMSPageSize); if (BytesRead <> AB_VMSPageSize) then raise EAbVMSReadFail.Create( AB_VMSPageSize, vmsSwapFileName ); end; end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileWrite(aPage : PvmsPage); var NewPos : Int64; SeekResult: Int64; BytesWritten : Longint; begin if (vmsSwapHandle = 0) then vmsSwapFileCreate; SeekResult := FileSeek(vmsSwapHandle, aPage^.vpStmOfs, 0); if (SeekResult = -1) then raise EAbVMSSeekFail.Create( vmsSwapFileName ); BytesWritten := FileWrite(vmsSwapHandle, aPage^.vpData, AB_VMSPageSize); if BytesWritten <> AB_VMSPageSize then raise EAbVMSWriteFail.Create( AB_VMSPageSize, vmsSwapFileName ); NewPos := aPage^.vpStmOfs + AB_VMSPageSize; if (NewPos > vmsSwapFileSize) then vmsSwapFileSize := NewPos; end; {--------} function TAbVirtualMemoryStream.Write(const Buffer; Count : Longint) : Longint; var BufPtr : PByte; Page : PvmsPage; PageDataInx : integer; Posn : Int64; BytesToGo : Int64; BytesToWrite: Int64; StartOfs : Int64; begin {writing is complicated by the fact we can only write in chunks of AB_VMSPageSize: we need to partition out the overall write into a write to a partial page, zero or more writes to complete pages and then a possible write to a partial page} {initialise some variables, note that the complex calc in the expression for PageDataInx is the offset of the start of the page where Posn is found.} BufPtr := @Buffer; Posn := vmsPosition; PageDataInx := Posn - (Posn and (not pred(AB_VMSPageSize))); BytesToWrite := AB_VMSPageSize - PageDataInx; {calculate the actual number of bytes to write} BytesToGo := Count; Result := BytesToGo; {while we have bytes to write, write them} while (BytesToGo <> 0) do begin if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; StartOfs := Posn and (not pred(AB_VMSPageSize)); if (vmsCachePage^.vpStmOfs = StartOfs) then Page := vmsCachePage else Page := vmsGetPageForOffset(StartOfs); Move(BufPtr^, Page^.vpData[PageDataInx], BytesToWrite); Page^.vpDirty := True; dec(BytesToGo, BytesToWrite); inc(Posn, BytesToWrite); inc(BufPtr, BytesToWrite); PageDataInx := 0; BytesToWrite := AB_VMSPageSize; end; {remember our new position} vmsPosition := Posn; {if we've grown the stream, make a note of it} if (vmsPosition > vmsSize) then vmsSize := vmsPosition; end; {====================================================================} end. �������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abwinzipaes.pas��������������������������������������0000644�0001750�0000144�00000013511�14743153644�023452� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * * WinZip AES decryption stream * * Copyright (C) 2017 Alexander Koblov (alexx2000@mail.ru) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * ***** END LICENSE BLOCK ***** *) unit AbWinZipAes; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCPrijndael, HMAC; const Ab_WinZipAesID : Word = $9901; type { TWinZipAesRec } PWinZipAesRec = ^TWinZipAesRec; TWinZipAesRec = packed record Version: Word; Vendor: Word; Strength: Byte; Method: Word; end; { TAbWinZipAesDecryptStream } TAbWinZipAesDecryptStream = class(TStream) private FKey : TBytes; FOwnsStream : Boolean; FReady : Boolean; FStream : TStream; FDataStream : TStream; FPassword : AnsiString; FContext : THMAC_Context; FDecoder : TDCP_rijndael; FExtraField : TWinZipAesRec; public constructor Create(aStream : TStream; aExtraField: PWinZipAesRec; const aPassword : AnsiString); destructor Destroy; override; function IsValid : Boolean; function Verify : Boolean; function Read(var aBuffer; aCount : Longint) : Longint; override; function Seek(aOffset : Longint; aOrigin : Word) : Longint; override; function Write(const aBuffer; aCount : Longint) : Longint; override; property ExtraField : TWinZipAesRec read FExtraField; property OwnsStream : Boolean read FOwnsStream write FOwnsStream; end; implementation uses AbUnzOutStm, DCPcrypt2, SHA1, Hash, kdf; const CTR : array[0..15] of Byte = (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); const MAC_LENGTH = 10; PWD_VER_LENGTH = 2; KEY_LENGTH: array[1..3] of Byte = (16, 24, 32); SALT_LENGTH: array[1..3] of Byte = (8, 12, 16); { TAbWinZipAesDecryptStream } constructor TAbWinZipAesDecryptStream.Create(aStream: TStream; aExtraField: PWinZipAesRec; const aPassword: AnsiString); begin inherited Create; FStream := aStream; FExtraField := aExtraField^; FPassword := aPassword; FDecoder := TDCP_rijndael.Create(nil); end; destructor TAbWinZipAesDecryptStream.Destroy; begin FDecoder.Free; FDataStream.Free; if FOwnsStream then FStream.Free; inherited Destroy; end; function TAbWinZipAesDecryptStream.IsValid: Boolean; var F: WordRec; Salt: AnsiString; HashDesc: PHashDesc; AKeyLength: Integer; ASaltLength: Integer; AExtraLength: Integer; begin // Integer mode value indicating AES encryption strength if not FExtraField.Strength in [1..3] then Exit(False); AKeyLength := KEY_LENGTH[FExtraField.Strength]; ASaltLength := SALT_LENGTH[FExtraField.Strength]; AExtraLength := AKeyLength * 2 + PWD_VER_LENGTH; SetLength(FKey, AExtraLength); HashDesc:= FindHash_by_ID(_SHA1); // Read salt value SetLength(Salt, ASaltLength); FStream.Read(Salt[1], ASaltLength); // Read password verification value FStream.Read({%H-}F, PWD_VER_LENGTH); pbkdf2(HashDesc, Pointer(FPassword), Length(FPassword), Pointer(Salt), Length(Salt), 1000, FKey[0], AExtraLength); Result := (FKey[AExtraLength - 2] = F.Lo) and (FKey[AExtraLength - 1] = F.Hi); if Result then begin FReady := True; FDecoder.Init(FKey[0], AKeyLength * 8, @CTR[0]); // Initialize for authentication using second key part hmac_init(FContext, HashDesc, @FKey[AKeyLength], AKeyLength); // Create encrypted file data stream AExtraLength := ASaltLength + PWD_VER_LENGTH + MAC_LENGTH; FDataStream := TAbUnzipSubsetStream.Create(FStream, FStream.Size - AExtraLength); end else begin FReady := False; FStream.Seek(-(ASaltLength + PWD_VER_LENGTH), soCurrent); end end; function TAbWinZipAesDecryptStream.Verify: Boolean; var AMac: THashDigest; ABuffer: array[0..MAC_LENGTH - 1] of Byte; begin hmac_final(FContext, {%H-}AMac); FStream.Read({%H-}ABuffer[0], MAC_LENGTH); Result := CompareByte(ABuffer[0], AMac[0], MAC_LENGTH) = 0; end; function TAbWinZipAesDecryptStream.Read(var aBuffer; aCount: Longint): Longint; begin Assert(FReady, 'TAbWinZipAesDecryptStream.Read: the stream header has not been verified'); Result := FDataStream.Read(aBuffer, aCount); if Result > 0 then begin hmac_updateXL(FContext, @aBuffer, Result); FDecoder.DecryptCTR(aBuffer, aBuffer, Result); end; end; function TAbWinZipAesDecryptStream.Seek(aOffset: Longint; aOrigin: Word): Longint; begin Result := FDataStream.Seek(aOffset, aOrigin); end; function TAbWinZipAesDecryptStream.Write(const aBuffer; aCount: Longint): Longint; begin Assert(False, 'TAbWinZipAesDecryptStream.Write: the stream is read-only'); Result := 0; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abxz.pas���������������������������������������������0000644�0001750�0000144�00000025062�14743153644�022106� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Simple interface to lzma library * * Copyright (C) 2014-2023 Alexander Koblov (alexx2000@mail.ru) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * ***** END LICENSE BLOCK ***** *) {********************************************************************} {* ABBREVIA: AbXz.pas *} {********************************************************************} {* ABBREVIA: TXzDecompressionStream, TXzDecompressionStream classes *} {********************************************************************} unit AbXz; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils, CTypes; type TLzmaStreamRec = record next_in: pbyte; (**< Pointer to the next input byte. *) avail_in: csize_t; (**< Number of available input bytes in next_in. *) total_in: cuint64; (**< Total number of bytes read by liblzma. *) next_out: pbyte; (**< Pointer to the next output position. *) avail_out: csize_t; (**< Amount of free space in next_out. *) total_out: cuint64; (**< Total number of bytes written by liblzma. *) (** * \brief Custom memory allocation functions * * In most cases this is NULL which makes liblzma use * the standard malloc() and free(). *) allocator: pointer; (** Internal state is not visible to applications. *) internal: pointer; (* * Reserved space to allow possible future extensions without * breaking the ABI. Excluding the initialization of this structure, * you should not touch these, because the names of these variables * may change. *) reserved_ptr1: pointer; reserved_ptr2: pointer; reserved_ptr3: pointer; reserved_ptr4: pointer; reserved_int1: cuint64; reserved_int2: cuint64; reserved_int3: csize_t; reserved_int4: csize_t; reserved_enum1: cuint32; reserved_enum2: cuint32; end; type { TXzCustomStream } TXzCustomStream = class(TOwnerStream) protected FLzmaRec: TLzmaStreamRec; FBuffer: array[Word] of Byte; public constructor Create(AStream: TStream); destructor Destroy; override; end; { TXzCompressionStream } TXzCompressionStream = class(TXzCustomStream) private procedure FlushBuffer; function Check(Return: cint): cint; public constructor Create(ATarget: TStream; ALevel: Integer); destructor Destroy; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; { TXzDecompressionStream } TXzDecompressionStream = class(TXzCustomStream) private function Check(Return: cint): cint; public constructor Create(ASource: TStream); function Read(var Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; ELzmaError = class(Exception); ELzmaCompressionError = class(ELzmaError); ELzmaDecompressionError = class(ELzmaError); implementation uses DynLibs, RtlConsts; const // Lzma return codes LZMA_OK = 0; LZMA_STREAM_END = 1; LZMA_NO_CHECK = 2; LZMA_UNSUPPORTED_CHECK = 3; LZMA_GET_CHECK = 4; LZMA_MEM_ERROR = 5; LZMA_MEMLIMIT_ERROR = 6; LZMA_FORMAT_ERROR = 7; LZMA_OPTIONS_ERROR = 8; LZMA_DATA_ERROR = 9; LZMA_BUF_ERROR = 10; LZMA_PROG_ERROR = 11; const // Lzma actions LZMA_RUN = 0; LZMA_SYNC_FLUSH = 1; LZMA_FULL_FLUSH = 2; LZMA_FINISH = 3; const // Type of the integrity check (Check ID) LZMA_CHECK_CRC64 = 4; const // Decoding flags LZMA_TELL_UNSUPPORTED_CHECK = $02; LZMA_CONCATENATED = $08; const liblzma = {$IF DEFINED(MSWINDOWS)} 'liblzma.dll' {$ELSEIF DEFINED(DARWIN)} 'liblzma.dylib' {$ELSEIF DEFINED(UNIX)} 'liblzma.so.5' {$IFEND}; var hLzma: TLibHandle = NilHandle; var lzma_stream_decoder: function(var strm: TLzmaStreamRec; memlimit: cuint64; flags: cuint32): cint; cdecl; lzma_easy_encoder: function(var strm: TLzmaStreamRec; preset: cuint32; check: cint): cint; cdecl; lzma_code: function(var strm: TLzmaStreamRec; action: cint): cint; cdecl; lzma_end: procedure(var strm: TLzmaStreamRec); cdecl; procedure LzmaLoadLibrary; begin if hLzma <> NilHandle then Exit; hLzma := LoadLibrary(liblzma); if hLzma = NilHandle then raise ELzmaError.Create('Lzma shared library not found'); @lzma_stream_decoder := GetProcAddress(hLzma, 'lzma_stream_decoder'); @lzma_easy_encoder := GetProcAddress(hLzma, 'lzma_easy_encoder'); @lzma_code := GetProcAddress(hLzma, 'lzma_code'); @lzma_end := GetProcAddress(hLzma, 'lzma_end'); end; constructor TXzCustomStream.Create(AStream: TStream); begin LzmaLoadLibrary; inherited Create(AStream); end; destructor TXzCustomStream.Destroy; begin if (@lzma_end <> nil) then lzma_end(FLzmaRec); inherited Destroy; end; { TXzCompressionStream } function TXzCompressionStream.Check(Return: cint): cint; var Message: String; begin Result:= Return; if not (Return in [LZMA_OK, LZMA_STREAM_END]) then begin case Return of LZMA_MEM_ERROR: Message:= 'Memory allocation failed'; LZMA_OPTIONS_ERROR: Message:= 'Specified preset is not supported'; LZMA_UNSUPPORTED_CHECK: Message:= 'Specified integrity check is not supported'; LZMA_FORMAT_ERROR: Message:= 'The input is not in the .xz format'; LZMA_DATA_ERROR: Message:= 'File size limits exceeded'; else Message:= Format('Unknown error, possibly a bug (error code %d)', [Return]); end; raise ELzmaCompressionError.Create(Message); end; end; constructor TXzCompressionStream.Create(ATarget: TStream; ALevel: Integer); begin inherited Create(ATarget); FLzmaRec.next_out:= FBuffer; FLzmaRec.avail_out:= SizeOf(FBuffer); Check(lzma_easy_encoder(FLzmaRec, ALevel, LZMA_CHECK_CRC64)); end; function TXzCompressionStream.Write(const Buffer; Count: Longint): Longint; begin FLzmaRec.avail_in:= Count; FLzmaRec.next_in:= @Buffer; while FLzmaRec.avail_in > 0 do begin Check(lzma_code(FLzmaRec, LZMA_RUN)); if FLzmaRec.avail_out = 0 then FlushBuffer; end; Result:= Count; end; function TXzCompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset = 0) and (Origin = soCurrent) then Result:= FLzmaRec.total_in else if (Origin = soBeginning) and (FLzmaRec.total_in = Offset) then Result:= Offset else begin raise ELzmaCompressionError.CreateFmt(SStreamInvalidSeek, [ClassName]); end; end; procedure TXzCompressionStream.FlushBuffer; begin FLzmaRec.next_out:= FBuffer; FLzmaRec.avail_out:= SizeOf(FBuffer); FSource.WriteBuffer(FBuffer, SizeOf(FBuffer)); end; destructor TXzCompressionStream.Destroy; var State: cint; begin try repeat if FLzmaRec.avail_out = 0 then FlushBuffer; State:= Check(lzma_code(FLzmaRec, LZMA_FINISH)); until State = LZMA_STREAM_END; if FLzmaRec.avail_out < SizeOf(FBuffer) then begin FSource.WriteBuffer(FBuffer, SizeOf(FBuffer) - FLzmaRec.avail_out); end; finally inherited Destroy; end; end; { TXzDecompressionStream } function TXzDecompressionStream.Check(Return: cint): cint; var Message: String; begin Result:= Return; if not (Return in [LZMA_OK, LZMA_STREAM_END]) then begin case Return of LZMA_MEM_ERROR: Message:= 'Memory allocation failed'; LZMA_OPTIONS_ERROR: Message:= 'Unsupported decompressor flags'; LZMA_FORMAT_ERROR: Message:= 'The input is not in the .xz format'; LZMA_DATA_ERROR: Message:= 'Compressed file is corrupt'; LZMA_BUF_ERROR: Message:= 'Compressed file is truncated or otherwise corrupt'; else Message:= Format('Unknown error, possibly a bug (error code %d)', [Return]); end; raise ELzmaDecompressionError.Create(Message); end; end; constructor TXzDecompressionStream.Create(ASource: TStream); const flags = LZMA_TELL_UNSUPPORTED_CHECK or LZMA_CONCATENATED; var memory_limit: cuint64 = High(cuint64); begin inherited Create(ASource); Check(lzma_stream_decoder(FLzmaRec, memory_limit, flags)); end; function TXzDecompressionStream.Read(var Buffer; Count: Longint): Longint; var State: cint; Action: cint = LZMA_RUN; begin FLzmaRec.avail_out:= Count; FLzmaRec.next_out:= @Buffer; while FLzmaRec.avail_out > 0 do begin if FLzmaRec.avail_in = 0 then begin FLzmaRec.next_in:= FBuffer; FLzmaRec.avail_in:= FSource.Read(FBuffer, SizeOf(FBuffer)); if FLzmaRec.avail_in = 0 then Action:= LZMA_FINISH; end; State:= Check(lzma_code(FLzmaRec, Action)); if State = LZMA_STREAM_END then Break; end; Result:= Count - FLzmaRec.avail_out; end; function TXzDecompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset >= 0) and (Origin = soCurrent) then begin if (Offset > 0) then Discard(Offset); Result:= FLzmaRec.total_out; end else if (Origin = soBeginning) and (FLzmaRec.total_out = Offset) then Result:= Offset else begin raise ELzmaDecompressionError.CreateFmt(SStreamInvalidSeek, [ClassName]); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abxztyp.pas������������������������������������������0000644�0001750�0000144�00000035412�14743153644�022643� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Joel Haynie * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Alexander Koblov <alexx2000@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbXzTyp.pas *} {*********************************************************} {* ABBREVIA: TAbXzArchive, TAbXzItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with Xz files *} {*********************************************************} unit AbXzTyp; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbTarTyp, AbUtils; const { The first six (6) bytes of the Stream are so called Header } { Magic Bytes. They can be used to identify the file type. } AB_XZ_FILE_HEADER = #$FD'7zXZ'#00; type PAbXzHeader = ^TAbXzHeader; { File Header } TAbXzHeader = packed record { SizeOf(TAbXzHeader) = 12 } HeaderMagic : array[0..5] of AnsiChar; { 0xFD, '7', 'z', 'X', 'Z', 0x00 } StreamFlags : Word; { 0x00, 0x00-0x0F } CRC32 : LongWord; { The CRC32 is calculated from the Stream Flags field } end; { The Purpose for this Item is the placeholder for aaAdd and aaDelete Support. } { For all intents and purposes we could just use a TAbArchiveItem } type TAbXzItem = class(TabArchiveItem); TAbXzArchiveState = (gsXz, gsTar); TAbXzArchive = class(TAbTarArchive) private FXzStream : TStream; { stream for Xz file} FXzItem : TAbArchiveList; { item in xz (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbXzArchiveState; FIsXzippedTar : Boolean; procedure DecompressToStream(aStream: TStream); procedure SetTarAutoHandle(const Value: Boolean); procedure SwapToXz; procedure SwapToTar; protected { Inherited Abstract functions } function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function GetSupportsEmptyFolders : Boolean; override; public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; { Properties } property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsXzippedTar : Boolean read FIsXzippedTar write FIsXzippedTar; end; function VerifyXz(Strm : TStream) : TAbArchiveType; implementation uses {$IFDEF MSWINDOWS} Windows, // Fix inline warnings {$ENDIF} StrUtils, SysUtils, BufStream, AbXz, AbExcept, AbVMStrm, AbBitBkt, AbProgress, CRC, DCOSUtils, DCClassesUtf8; { ****************** Helper functions Not from Classes Above ***************** } function VerifyHeader(const Header : TAbXzHeader) : Boolean; begin Result := CompareByte(Header.HeaderMagic, AB_XZ_FILE_HEADER, SizeOf(Header.HeaderMagic)) = 0; Result := Result and (Crc32(0, PByte(@Header.StreamFlags), SizeOf(Header.StreamFlags)) = Header.CRC32); end; { -------------------------------------------------------------------------- } function VerifyXz(Strm : TStream) : TAbArchiveType; var Hdr : TAbXzHeader; CurPos, DecompSize : Int64; DecompStream, TarStream: TStream; Buffer: array[0..Pred(AB_TAR_RECORDSIZE * 4)] of Byte; begin Result := atUnknown; CurPos := Strm.Position; Strm.Seek(0, soBeginning); try if (Strm.Read(Hdr, SizeOf(Hdr)) = SizeOf(Hdr)) and VerifyHeader(Hdr) then begin Result := atXz; { Check for embedded TAR } Strm.Seek(0, soBeginning); DecompStream := TXzDecompressionStream.Create(Strm); try TarStream := TMemoryStream.Create; try DecompSize:= DecompStream.Read(Buffer, SizeOf(Buffer)); TarStream.Write(Buffer, DecompSize); TarStream.Seek(0, soBeginning); if VerifyTar(TarStream) = atTar then Result := atXzippedTar; finally TarStream.Free; end; finally DecompStream.Free; end; end; except Result := atUnknown; end; Strm.Position := CurPos; { Return to original position. } end; { ****************************** TAbXzArchive ***************************** } constructor TAbXzArchive.CreateFromStream(aStream: TStream; const aArchiveName: string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsXz; FXzStream := FStream; FXzItem := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.SwapToXz; begin FStream := FXzStream; FItemList := FXzItem; FState := gsXz; end; { -------------------------------------------------------------------------- } function TAbXzArchive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var XzItem : TAbXzItem; FullSourceFileName, FullArchiveFileName: String; begin if IsXzippedTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(SourceFileName, ArchiveDirectory); end else begin SwapToXz; XzItem := TAbXzItem.Create; try MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); XzItem.FileName := FullArchiveFileName; XzItem.DiskFileName := FullSourceFileName; Result := XzItem; except Result := nil; raise; end; end; end; { -------------------------------------------------------------------------- } destructor TAbXzArchive.Destroy; begin SwapToXz; FTarList.Free; FTarStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.ExtractItemAt(Index: Integer; const NewName: string); var OutStream : TStream; begin if IsXzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, NewName); end else begin SwapToXz; OutStream := TFileStreamEx.Create(NewName, fmCreate or fmShareDenyNone); try try ExtractItemToStreamAt(Index, OutStream); finally OutStream.Free; end; { Xz doesn't store the last modified time or attributes, so don't set them } except on E : EAbUserAbort do begin FStatus := asInvalid; if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end else begin if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end; end; end; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); begin if IsXzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToXz; { Index ignored as there's only one item in a Xz } DecompressToStream(aStream); end; end; { -------------------------------------------------------------------------- } function TAbXzArchive.GetSupportsEmptyFolders : Boolean; begin Result := IsXzippedTar and TarAutoHandle; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.LoadArchive; var Item: TAbXzItem; Abort: Boolean; ItemName: string; begin if FXzStream.Size = 0 then Exit; if IsXzippedTar and TarAutoHandle then begin { Decompress and send to tar LoadArchive } DecompressToStream(FTarStream); SwapToTar; inherited LoadArchive; end else begin SwapToXz; Item := TAbXzItem.Create; Item.Action := aaNone; { Filename isn't stored, so constuct one based on the archive name } ItemName := ExtractFileName(ArchiveName); if ItemName = '' then Item.FileName := 'unknown' else if AnsiEndsText('.txz', ItemName) then Item.FileName := ChangeFileExt(ItemName, '.tar') else Item.FileName := ChangeFileExt(ItemName, ''); Item.DiskFileName := Item.FileName; FItemList.Add(Item); end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.SaveArchive; var I: Integer; CurItem: TAbXzItem; UpdateArchive: Boolean; TempFileName: String; CompStream: TStream; InputFileStream: TStream; begin if IsXzippedTar and TarAutoHandle then begin SwapToTar; UpdateArchive := (FXzStream.Size > 0) and (FXzStream is TFileStreamEx); if UpdateArchive then begin FreeAndNil(FXzStream); TempFileName := GetTempName(FArchiveName); { Create new archive with temporary name } FXzStream := TFileStreamEx.Create(TempFileName, fmCreate or fmShareDenyWrite); end; FTarStream.Position := 0; CompStream := TXzCompressionStream.Create(FXzStream, FCompressionLevel); try FTargetStream := TWriteBufStream.Create(CompStream, $40000); try inherited SaveArchive; finally FreeAndNil(FTargetStream); end; finally CompStream.Free; end; if UpdateArchive then begin FreeAndNil(FXzStream); { Replace original by new archive } if not (mbDeleteFile(FArchiveName) and mbRenameFile(TempFileName, FArchiveName)) then RaiseLastOSError; { Open new archive } FXzStream := TFileStreamEx.Create(FArchiveName, fmOpenRead or fmShareDenyNone); end; end else begin { Things we know: There is only one file per archive.} { Actions we have to address in SaveArchive: } { aaNone & aaMove do nothing, as the file does not change, only the meta data } { aaDelete could make a zero size file unless there are two files in the list.} { aaAdd, aaStreamAdd, aaFreshen, & aaReplace will be the only ones to take action. } SwapToXz; for I := 0 to Pred(Count) do begin FCurrentItem := ItemList[I]; CurItem := TAbXzItem(ItemList[I]); case CurItem.Action of aaNone, aaMove: Break;{ Do nothing; xz doesn't store metadata } aaDelete: ; {doing nothing omits file from new stream} aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin FXzStream.Size := 0; CompStream := TXZCompressionStream.Create(FXzStream, CompressionLevel); try if CurItem.Action = aaStreamAdd then CompStream.CopyFrom(InStream, 0){ Copy/compress entire Instream to FBzip2Stream } else begin InputFileStream := TFileStreamEx.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite); try with TAbProgressWriteStream.Create(CompStream, InputFileStream.Size, OnProgress) do try CopyFrom(InputFileStream, 0);{ Copy/compress entire Instream to FBzip2Stream } finally Free; end; finally InputFileStream.Free; end; end; finally CompStream.Free; end; Break; end; { End aaAdd, aaFreshen, aaReplace, & aaStreamAdd } end; { End of CurItem.Action Case } end; { End Item for loop } end; { End Tar Else } end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToXz; FTarAutoHandle := Value; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.DecompressToStream(aStream: TStream); var ProxyStream: TAbProgressReadStream; DecompStream: TXzDecompressionStream; begin ProxyStream:= TAbProgressReadStream.Create(FXzStream, OnProgress); try DecompStream := TXzDecompressionStream.Create(ProxyStream); try aStream.CopyFrom(DecompStream, 0) finally DecompStream.Free; end; finally ProxyStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.TestItemAt(Index: Integer); var XzType: TAbArchiveType; BitBucket: TAbBitBucketStream; begin if IsXzippedTar and TarAutoHandle then begin SwapToTar; inherited TestItemAt(Index); end else begin { Note Index ignored as there's only one item in a GZip } XzType := VerifyXz(FXzStream); if not (XzType in [atXz, atXzippedTar]) then raise EAbGzipInvalid.Create; // TODO: Add xz-specific exceptions } BitBucket := TAbBitBucketStream.Create(1024); try DecompressToStream(BitBucket); finally BitBucket.Free; end; end; end; { -------------------------------------------------------------------------- } procedure TAbXzArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzbrows.pas�����������������������������������������0000644�0001750�0000144�00000026607�14743153644�023001� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZBrows.pas *} {*********************************************************} {* ABBREVIA: Zip file Browser Component *} {*********************************************************} unit AbZBrows; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbBrowse, AbSpanSt, AbZipTyp; type TAbCustomZipBrowser = class(TAbBaseBrowser) private function GetTarAutoHandle: Boolean; procedure SetTarAutoHandle(const Value: Boolean); protected {private} FPassword : AnsiString; FOnRequestLastDisk : TAbRequestDiskEvent; FOnRequestNthDisk : TAbRequestNthDiskEvent; FOnRequestBlankDisk : TAbRequestDiskEvent; FTarAutoHandle : Boolean; protected {methods} function GetItem(Index : Integer) : TAbZipItem; virtual; function GetStream: TStream; function GetZipfileComment : AnsiString; procedure InitArchive; override; procedure SetFileName(const aFileName : string); override; procedure SetStream(aValue: TStream); procedure SetOnRequestLastDisk(Value : TAbRequestDiskEvent); procedure SetOnRequestNthDisk(Value : TAbRequestNthDiskEvent); procedure SetOnRequestBlankDisk(Value : TAbRequestDiskEvent); procedure SetPassword(const Value : AnsiString); procedure SetZipfileComment(const Value : AnsiString); virtual; protected {properties} property Password : AnsiString read FPassword write SetPassword; protected {events} property OnRequestLastDisk : TAbRequestDiskEvent read FOnRequestLastDisk write SetOnRequestLastDisk; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write SetOnRequestNthDisk; property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write SetOnRequestBlankDisk; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; public {properties} property Items[Index : Integer] : TAbZipItem read GetItem; default; property Stream : TStream // This can be used instead of Filename read GetStream write SetStream; property ZipArchive : {TAbZipArchive} TAbArchive read FArchive; property ZipfileComment : AnsiString read GetZipfileComment write SetZipfileComment; property TarAutoHandle : Boolean read GetTarAutoHandle write SetTarAutoHandle; end; TAbZipBrowser = class(TAbCustomZipBrowser) published property ArchiveProgressMeter; property ItemProgressMeter; property BaseDirectory; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmProcessItem; property OnLoad; property OnProcessItemFailure; property OnRequestLastDisk; property OnRequestNthDisk; property Version; property TarAutoHandle; property FileName; {must be after OnLoad} end; implementation uses SysUtils, AbBzip2Typ, AbExcept, AbGzTyp, AbTarTyp, AbUtils, DCOSUtils; { TAbCustomZipBrowser implementation ======================================= } { -------------------------------------------------------------------------- } constructor TAbCustomZipBrowser.Create(AOwner : TComponent); begin inherited Create(AOwner); end; { -------------------------------------------------------------------------- } destructor TAbCustomZipBrowser.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetItem(Index : Integer) : TAbZipItem; begin Result := TAbZipItem(ZipArchive.ItemList[Index]); end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetStream: TStream; begin if FArchive <> nil then Result := FArchive.FStream else Result := nil end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetTarAutoHandle: Boolean; begin Result := False; if FArchive is TAbGzipArchive then Result := TAbGzipArchive(FArchive).TarAutoHandle else if FArchive is TAbBzip2Archive then Result := TAbBzip2Archive(FArchive).TarAutoHandle; end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetZipfileComment : AnsiString; begin if ZipArchive is TAbZipArchive then Result := TAbZipArchive(ZipArchive).ZipfileComment else Result := ''; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.InitArchive; begin inherited InitArchive; if ZipArchive is TAbZipArchive then begin {properties} TAbZipArchive(ZipArchive).Password := FPassword; {events} TAbZipArchive(ZipArchive).OnRequestLastDisk := FOnRequestLastDisk; TAbZipArchive(ZipArchive).OnRequestNthDisk := FOnRequestNthDisk; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetFileName(const aFileName : string); var ArcType : TAbArchiveType; begin FFileName := aFileName; if csDesigning in ComponentState then Exit; try if Assigned(FArchive) then begin FArchive.Save; end; except end; FArchive.Free; FArchive := nil; if FileName <> '' then begin if mbFileExists(FileName) then begin { open it } ArcType := ArchiveType; if not ForceType then ArcType := AbDetermineArcType(FileName, atUnknown); case ArcType of atZip, atSpannedZip, atSelfExtZip : begin FArchive := TAbZipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); InitArchive; end; atTar : begin FArchive := TAbTarArchive.Create(FileName, fmOpenRead or fmShareDenyNone); inherited InitArchive; end; atGZip : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := False; inherited InitArchive; end; atGZippedTar : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := True; inherited InitArchive; end; atBzip2 : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := False; inherited InitArchive; end; atBzippedTar : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := True; inherited InitArchive; end; else raise EAbUnhandledType.Create; end {case}; FArchive.Load; FArchiveType := ArcType; end; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetStream(aValue: TStream); var ArcType : TAbArchiveType; begin FFileName := ''; try if FArchive <> nil then FArchive.Save; except end; FreeAndNil(FArchive); if aValue <> nil then begin ArcType := ArchiveType; if not ForceType then ArcType := AbDetermineArcType(aValue); case ArcType of atZip, atSpannedZip, atSelfExtZip : begin FArchive := TAbZipArchive.CreateFromStream(aValue, ''); end; atTar : begin FArchive := TAbTarArchive.CreateFromStream(aValue, ''); end; atGZip, atGZippedTar : begin FArchive := TAbGzipArchive.CreateFromStream(aValue, ''); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := (ArcType = atGZippedTar); end; atBzip2, atBzippedTar : begin FArchive := TAbBzip2Archive.CreateFromStream(aValue, ''); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := (ArcType = atBzippedTar); end; else raise EAbUnhandledType.Create; end {case}; InitArchive; FArchive.Load; FArchiveType := ArcType; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetOnRequestBlankDisk(Value : TAbRequestDiskEvent); begin FOnRequestBlankDisk := Value; if ZipArchive is TAbZipArchive then TAbZipArchive(ZipArchive).OnRequestBlankDisk := FOnRequestBlankDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetOnRequestLastDisk(Value : TAbRequestDiskEvent); begin FOnRequestLastDisk := Value; if ZipArchive is TAbZipArchive then TAbZipArchive(ZipArchive).OnRequestLastDisk := FOnRequestLastDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetOnRequestNthDisk(Value : TAbRequestNthDiskEvent); begin FOnRequestNthDisk := Value; if ZipArchive is TAbZipArchive then TAbZipArchive(ZipArchive).OnRequestNthDisk := FOnRequestNthDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetPassword(const Value : AnsiString); begin FPassword := Value; if ZipArchive is TAbZipArchive then TAbZipArchive(ZipArchive).Password := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetTarAutoHandle(const Value: Boolean); begin FTarAutoHandle := Value; if FArchive is TAbGzipArchive then begin if TAbGzipArchive(FArchive).TarAutoHandle <> Value then begin TAbGzipArchive(FArchive).TarAutoHandle := Value; InitArchive; FArchive.Load; DoChange; end; end; if FArchive is TAbBzip2Archive then begin if TAbBzip2Archive(FArchive).TarAutoHandle <> Value then begin TAbBzip2Archive(FArchive).TarAutoHandle := Value; InitArchive; FArchive.Load; DoChange; end; end; end; procedure TAbCustomZipBrowser.SetZipfileComment(const Value : AnsiString); begin {NOP - descendents wishing to set this property should override} end; { -------------------------------------------------------------------------- } end. �������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzipkit.pas�����������������������������������������0000644�0001750�0000144�00000023047�14743153644�022760� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipKit.pas *} {*********************************************************} {* ABBREVIA: TABZipKit component *} {*********************************************************} unit AbZipKit; {$I AbDefine.inc} interface uses Classes, AbZipper, AbArcTyp, AbZipTyp; type TAbCustomZipKit = class(TAbCustomZipper) protected {private} FExtractOptions : TAbExtractOptions; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; FOnNeedPassword : TAbNeedPasswordEvent; FPasswordRetries : Byte; protected {methods} procedure DoConfirmOverwrite(var Name : string; var Confirm : Boolean); virtual; procedure DoNeedPassword(Sender : TObject; var NewPassword : AnsiString); virtual; procedure InitArchive; override; procedure SetExtractOptions(Value : TAbExtractOptions); procedure SetPasswordRetries(Value : Byte); procedure UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string ); procedure UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure TestItemProc(Sender : TObject; Item : TAbArchiveItem); protected {properties} property ExtractOptions : TAbExtractOptions read FExtractOptions write SetExtractOptions default AbDefExtractOptions; property PasswordRetries : Byte read FPasswordRetries write SetPasswordRetries default AbDefPasswordRetries; protected {events} property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; property OnNeedPassword : TAbNeedPasswordEvent read FOnNeedPassword write FOnNeedPassword; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} procedure ExtractFilesEx(const FileMask, ExclusionMask : string); {extract files matching FileMask except those matching ExclusionMask} procedure ExtractTaggedItems; {extract all tagged items from the archive} procedure ExtractToStream(const aFileName : string; ToStream : TStream); {extract the specified item to TStream descendant} procedure TestTaggedItems; {test all tagged items in the archive} public {property} property Spanned; end; TAbZipKit = class(TAbCustomZipKit) published property ArchiveProgressMeter; property ArchiveSaveProgressMeter; property AutoSave; property BaseDirectory; property CompressionMethodToUse; property DeflationOption; {$IFDEF MSWINDOWS} property DOSMode; {$ENDIF} property ExtractOptions; property SpanningThreshold; property ItemProgressMeter; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveSaveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmOverwrite; property OnConfirmProcessItem; property OnConfirmSave; property OnLoad; property OnNeedPassword; property OnProcessItemFailure; property OnRequestBlankDisk; property OnRequestImage; property OnRequestLastDisk; property OnRequestNthDisk; property OnSave; property Password; property PasswordRetries; property StoreOptions; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; implementation uses AbExcept, AbUnzPrc, AbZBrows; { -------------------------------------------------------------------------- } constructor TAbCustomZipKit.Create( AOwner : TComponent ); begin inherited Create( AOwner ); PasswordRetries := AbDefPasswordRetries; end; { -------------------------------------------------------------------------- } destructor TAbCustomZipKit.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.DoConfirmOverwrite( var Name : string; var Confirm : Boolean ); begin Confirm := True; if Assigned( FOnConfirmOverwrite ) then FOnConfirmOverwrite( Name, Confirm ); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.DoNeedPassword( Sender : TObject; var NewPassword : AnsiString ); begin if Assigned( FOnNeedPassword ) then begin FOnNeedPassword( Self, NewPassword ); FPassword := NewPassword; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractAt(Index : Integer; const NewName : string); {extract a file from the archive that match the index} begin if (ZipArchive <> nil) then ZipArchive.ExtractAt( Index, NewName ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} begin if (ZipArchive <> nil) then ZipArchive.ExtractFiles( FileMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractFilesEx(const FileMask, ExclusionMask : string); {extract files matching FileMask except those matching ExclusionMask} begin if (ZipArchive <> nil) then ZipArchive.ExtractFilesEx( FileMask, ExclusionMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractTaggedItems; {extract all tagged items from the archive} begin if (ZipArchive <> nil) then ZipArchive.ExtractTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractToStream(const aFileName : string; ToStream : TStream); begin if (ZipArchive <> nil) then ZipArchive.ExtractToStream(aFileName, ToStream) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.InitArchive; begin inherited InitArchive; if (ZipArchive <> nil) then begin if ZipArchive is TAbZipArchive then begin {properties} ZipArchive.ExtractOptions := FExtractOptions; TAbZipArchive(ZipArchive).PasswordRetries := FPasswordRetries; {events} ZipArchive.OnConfirmOverwrite := DoConfirmOverwrite; TAbZipArchive(ZipArchive).OnNeedPassword := DoNeedPassword; TAbZipArchive(ZipArchive).ExtractHelper := UnzipProc; TAbZipArchive(ZipArchive).ExtractToStreamHelper := UnzipToStreamProc; TAbZipArchive(ZipArchive).TestHelper := TestItemProc; end; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.SetExtractOptions( Value : TAbExtractOptions ); begin FExtractOptions := Value; if (ZipArchive <> nil) then ZipArchive.ExtractOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.SetPasswordRetries( Value : Byte ); begin FPasswordRetries := Value; if (ZipArchive <> nil) then (ZipArchive as TAbZipArchive).PasswordRetries := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.TestTaggedItems; {test all tagged items in the archive} begin if (ZipArchive <> nil) then ZipArchive.TestTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.UnzipProc( Sender : TObject; Item : TAbArchiveItem; const NewName : string ); begin AbUnzip( TAbZipArchive(Sender), TAbZipItem(Item), NewName); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin AbUnzipToStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.TestItemProc(Sender : TObject; Item : TAbArchiveItem); begin AbTestZipItem(TAbZipArchive(Sender), TAbZipItem(Item)); end; { -------------------------------------------------------------------------- } end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzipper.pas�����������������������������������������0000644�0001750�0000144�00000052572�14743153644�022764� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipper.pas *} {*********************************************************} {* ABBREVIA: Non-visual Component with Zip support *} {*********************************************************} unit AbZipper; {$I AbDefine.inc} interface uses Classes, AbBrowse, AbZBrows, AbArcTyp, AbZipTyp; type TAbCustomZipper = class(TAbCustomZipBrowser) protected {private} FAutoSave : Boolean; FCompressionMethodToUse : TAbZipSupportedMethod; FDeflationOption : TAbZipDeflationOption; FDOSMode : Boolean; FOnConfirmSave : TAbArchiveConfirmEvent; FOnSave : TAbArchiveEvent; FOnArchiveSaveProgress : TAbArchiveProgressEvent; FArchiveSaveProgressMeter : IAbProgressMeter; FStoreOptions : TAbStoreOptions; protected {methods} procedure DoConfirmSave(Sender : TObject; var Confirm : Boolean); virtual; procedure DoSave(Sender : TObject); virtual; procedure DoArchiveSaveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); procedure InitArchive; override; procedure SetAutoSave(Value : Boolean); procedure SetCompressionMethodToUse(Value : TAbZipSupportedMethod); procedure SetDeflationOption(Value : TAbZipDeflationOption); procedure SetDOSMode( Value : Boolean ); procedure SetFileName(const aFileName : string); override; procedure SetStoreOptions( Value : TAbStoreOptions ); procedure SetArchiveSaveProgressMeter(const Value: IAbProgressMeter); procedure SetZipfileComment(const Value : AnsiString); override; procedure ZipProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure ZipFromStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream ); procedure Notification(Component: TComponent; Operation: TOperation); override; procedure ResetMeters; override; protected {properties} property AutoSave : Boolean read FAutoSave write SetAutoSave; property CompressionMethodToUse : TAbZipSupportedMethod read FCompressionMethodToUse write SetCompressionMethodToUse default AbDefCompressionMethodToUse; property DeflationOption : TAbZipDeflationOption read FDeflationOption write SetDeflationOption default AbDefDeflationOption; property DOSMode : Boolean read FDOSMode write SetDOSMode; property StoreOptions : TAbStoreOptions read FStoreOptions write SetStoreOptions default AbDefStoreOptions; property ArchiveSaveProgressMeter : IAbProgressMeter read FArchiveSaveProgressMeter write SetArchiveSaveProgressMeter; protected {events} property OnConfirmSave : TAbArchiveConfirmEvent read FOnConfirmSave write FOnConfirmSave; property OnSave : TAbArchiveEvent read FOnSave write FOnSave; property OnArchiveSaveProgress : TAbArchiveProgressEvent read FOnArchiveSaveProgress write FOnArchiveSaveProgress; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure AddFiles(const FileMask : string; SearchAttr : Integer); procedure AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); procedure AddFromStream(const NewName : string; FromStream : TStream); procedure DeleteAt(Index : Integer); procedure DeleteFiles(const FileMask : string); procedure DeleteFilesEx(const FileMask, ExclusionMask : string); procedure DeleteTaggedItems; procedure FreshenFiles(const FileMask : string); procedure FreshenFilesEx(const FileMask, ExclusionMask : string); procedure FreshenTaggedItems; procedure Move(aItem : TAbArchiveItem; const NewStoredPath : string); procedure Save; procedure Replace(aItem : TAbArchiveItem); end; type TAbZipper = class(TAbCustomZipper) published property ArchiveProgressMeter; property ArchiveSaveProgressMeter; property ItemProgressMeter; property AutoSave; property BaseDirectory; property CompressionMethodToUse; property DeflationOption; property DOSMode; property SpanningThreshold; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveSaveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmProcessItem; property OnConfirmSave; property OnLoad; property OnProcessItemFailure; property OnRequestBlankDisk; property OnRequestImage; property OnRequestLastDisk; property OnRequestNthDisk; property OnSave; property Password; property StoreOptions; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; implementation uses SysUtils, AbUtils, AbTarTyp, AbGzTyp, AbBzip2Typ, AbExcept, AbZipPrc, AbXzTyp, AbLzmaTyp, AbZstdTyp, DCOSUtils; { -------------------------------------------------------------------------- } constructor TAbCustomZipper.Create( AOwner : TComponent ); begin inherited Create( AOwner ); CompressionMethodToUse := AbDefCompressionMethodToUse; DeflationOption := AbDefDeflationOption; StoreOptions := AbDefStoreOptions; end; { -------------------------------------------------------------------------- } destructor TAbCustomZipper.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.AddFiles(const FileMask : string; SearchAttr : Integer); {Add files to the archive where the disk filespec matches} begin if (ZipArchive <> nil) then ZipArchive.AddFiles(FileMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); {Add files that match Filemask except those matching ExclusionMask} begin if (ZipArchive <> nil) then ZipArchive.AddFilesEx(FileMask, ExclusionMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.AddFromStream(const NewName : string; FromStream : TStream); {Add stream directly to archive} begin if (ZipArchive <> nil) then begin FromStream.Position := 0; ZipArchive.AddFromStream(NewName, FromStream); end else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteFiles(const FileMask : string); {delete all files from the archive that match the file mask} begin if (ZipArchive <> nil) then ZipArchive.DeleteFiles( FileMask ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteAt(Index : Integer); {delete item at Index} begin if (ZipArchive <> nil) then ZipArchive.DeleteAt( Index ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteFilesEx(const FileMask, ExclusionMask : string); {Delete files that match Filemask except those matching ExclusionMask} begin if (ZipArchive <> nil) then ZipArchive.DeleteFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteTaggedItems; {delete all tagged items from the archive} begin if (ZipArchive <> nil) then ZipArchive.DeleteTaggedItems else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DoConfirmSave(Sender : TObject; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmSave) then FOnConfirmSave(Self, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DoSave(Sender : TObject); begin if Assigned(FOnSave) then FOnSave(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.FreshenFiles(const FileMask : string); {freshen all items that match the file mask} begin if (ZipArchive <> nil) then ZipArchive.FreshenFiles( FileMask ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.FreshenFilesEx(const FileMask, ExclusionMask : string); {freshen all items matching FileMask except those matching ExclusionMask} begin if (ZipArchive <> nil) then ZipArchive.FreshenFilesEx( FileMask, ExclusionMask ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.FreshenTaggedItems; {freshen all tagged items} begin if (ZipArchive <> nil) then ZipArchive.FreshenTaggedItems else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.InitArchive; begin inherited InitArchive; if (ZipArchive is TAbZipArchive) then begin {properties} ZipArchive.AutoSave := FAutoSave; TAbZipArchive(ZipArchive).CompressionMethodToUse := FCompressionMethodToUse; TAbZipArchive(ZipArchive).DeflationOption := FDeflationOption; FArchive.DOSMode := FDOSMode; ZipArchive.StoreOptions := FStoreOptions; {events} ZipArchive.OnArchiveSaveProgress := DoArchiveSaveProgress; ZipArchive.OnConfirmSave := DoConfirmSave; TAbZipArchive(ZipArchive).OnRequestBlankDisk := OnRequestBlankDisk; ZipArchive.OnSave := DoSave; TAbZipArchive(ZipArchive).InsertHelper := ZipProc; TAbZipArchive(ZipArchive).InsertFromStreamHelper := ZipFromStreamProc; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Move(aItem : TAbArchiveItem; const NewStoredPath : string); {renames the item} begin if (ZipArchive <> nil) then ZipArchive.Move(aItem, NewStoredPath) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Replace(aItem : TAbArchiveItem); {replace the item} begin if (ZipArchive <> nil) then ZipArchive.Replace( aItem ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Save; begin if (ZipArchive <> nil) then begin ZipArchive.Save; DoChange; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetAutoSave(Value : Boolean); begin FAutoSave := Value; if (ZipArchive <> nil) then ZipArchive.AutoSave := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetCompressionMethodToUse( Value : TAbZipSupportedMethod); begin FCompressionMethodToUse := Value; if (ZipArchive is TAbZipArchive) then TAbZipArchive(ZipArchive).CompressionMethodToUse := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetDeflationOption(Value : TAbZipDeflationOption); begin FDeflationOption := Value; if (ZipArchive is TAbZipArchive) then TAbZipArchive(ZipArchive).DeflationOption := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetDOSMode(Value : Boolean); begin FDOSMode := Value; if (ZipArchive <> nil) then ZipArchive.DOSMode := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetFileName(const aFileName : string); var ArcType : TAbArchiveType; begin FFileName := aFileName; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then begin FArchive.Save; FreeAndNil(FArchive); end; ArcType := ArchiveType; if (FileName <> '') then if mbFileExists(FileName) then begin { open it } if not ForceType then ArcType := AbDetermineArcType(FileName, atUnknown); case ArcType of atZip, atSpannedZip, atSelfExtZip : begin FArchive := TAbZipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); InitArchive; end; atTar : begin FArchive := TAbTarArchive.Create(FileName, fmOpenRead or fmShareDenyNone); inherited InitArchive; end; atGZip : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := False; inherited InitArchive; end; atGZippedTar : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := True; inherited InitArchive; end; atBzip2 : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := False; inherited InitArchive; end; atBzippedTar : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := True; inherited InitArchive; end; atXz, atXzippedTar : begin FArchive := TAbXzArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbXzArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbXzArchive(FArchive).IsXzippedTar := (ArcType = atXzippedTar); inherited InitArchive; end; atLzma, atLzmaTar : begin FArchive := TAbLzmaArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbLzmaArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbLzmaArchive(FArchive).IsLzmaTar := (ArcType = atLzmaTar); inherited InitArchive; end; atZstd, atZstdTar : begin FArchive := TAbZstdArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbZstdArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbZstdArchive(FArchive).IsZstdTar := (ArcType = atZstdTar); inherited InitArchive; end; else raise EAbUnhandledType.Create; end {case}; FArchive.Load; FArchiveType := ArcType; end else begin { file doesn't exist, so create a new one } if not ForceType then ArcType := AbDetermineArcType(FileName, atUnknown); case ArcType of atZip : begin FArchive := TAbZipArchive.Create(FileName, fmCreate or fmShareDenyWrite); InitArchive; end; atTar : begin FArchive := TAbTarArchive.Create(FileName, fmCreate or fmShareDenyWrite); inherited InitArchive; end; atGZip : begin FArchive := TAbGzipArchive.Create(FileName, fmCreate or fmShareDenyWrite); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := False; inherited InitArchive; end; atGZippedTar : begin FArchive := TAbGzipArchive.Create(FileName, fmCreate or fmShareDenyWrite); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := True; inherited InitArchive; end; atBzip2 : begin FArchive := TAbBzip2Archive.Create(FileName, fmCreate or fmShareDenyWrite); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := False; inherited InitArchive; end; atBzippedTar : begin FArchive := TAbBzip2Archive.Create(FileName, fmCreate or fmShareDenyWrite); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := True; inherited InitArchive; end; atXz, atXzippedTar : begin FArchive := TAbXzArchive.Create(FileName, fmCreate or fmShareDenyWrite); TAbXzArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbXzArchive(FArchive).IsXzippedTar := (ArcType = atXzippedTar); inherited InitArchive; end; atLzma, atLzmaTar : begin FArchive := TAbLzmaArchive.Create(FileName, fmCreate or fmShareDenyWrite); TAbLzmaArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbLzmaArchive(FArchive).IsLzmaTar := (ArcType = atLzmaTar); inherited InitArchive; end; atZstd, atZstdTar : begin FArchive := TAbZstdArchive.Create(FileName, fmCreate or fmShareDenyWrite); TAbZstdArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbZstdArchive(FArchive).IsZstdTar := (ArcType = atZstdTar); inherited InitArchive; end; else raise EAbUnhandledType.Create; end {case}; FArchiveType := ArcType; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetStoreOptions(Value : TAbStoreOptions); begin FStoreOptions := Value; if (ZipArchive <> nil) then ZipArchive.StoreOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetArchiveSaveProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FArchiveSaveProgressMeter, opRemove); FArchiveSaveProgressMeter := Value; ReferenceInterface(FArchiveSaveProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetZipfileComment(const Value : AnsiString); begin if (ZipArchive is TAbZipArchive) then TAbZipArchive(ZipArchive).ZipfileComment := Value else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.ZipProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin AbZip(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.ZipFromStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream); begin if Assigned(InStream) then AbZipFromStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream, InStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DoArchiveSaveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FArchiveSaveProgressMeter) then FArchiveSaveProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveSaveProgress) then FOnArchiveSaveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Notification(Component: TComponent; Operation: TOperation); begin inherited Notification(Component, Operation); if (Operation = opRemove) then if Assigned(ArchiveSaveProgressMeter) and Component.IsImplementorOf(ArchiveSaveProgressMeter) then ArchiveSaveProgressMeter := nil end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.ResetMeters; begin inherited ResetMeters; if Assigned(FArchiveSaveProgressMeter) then FArchiveSaveProgressMeter.Reset; end; { -------------------------------------------------------------------------- } end. ��������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzipprc.pas�����������������������������������������0000644�0001750�0000144�00000023044�14743153644�022752� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipPrc.pas *} {*********************************************************} {* ABBREVIA: TABZipHelper class *} {*********************************************************} unit AbZipPrc; {$I AbDefine.inc} interface uses Classes, AbZipTyp; procedure AbZip( Sender : TAbZipArchive; Item : TAbZipItem; OutStream : TStream ); procedure AbZipFromStream(Sender : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); implementation uses SysUtils, AbArcTyp, AbExcept, AbUtils, AbDfCryS, AbVMStrm, AbDfBase, AbZlibPrc, AbZipxPrc, DCcrc32, DCClassesUtf8; { ========================================================================== } procedure DoDeflate(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); const DEFLATE_NORMAL_MASK = $00; DEFLATE_MAXIMUM_MASK = $02; DEFLATE_FAST_MASK = $04; DEFLATE_SUPERFAST_MASK = $06; var Hlpr : TAbDeflateHelper; begin Item.CompressionMethod := cmDeflated; Hlpr := TAbDeflateHelper.Create; {anything dealing with store options, etc. should already be done.} try {Hlpr} Hlpr.StreamSize := InStream.Size; { set deflation level desired } Hlpr.PKZipOption := '0'; case Archive.DeflationOption of doNormal : begin Hlpr.PKZipOption := 'n'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_NORMAL_MASK; end; doMaximum : begin Hlpr.PKZipOption := 'x'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_MAXIMUM_MASK; end; doFast : begin Hlpr.PKZipOption := 'f'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_FAST_MASK; end; doSuperFast : begin Hlpr.PKZipOption := 's'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_SUPERFAST_MASK; end; end; { attach progress notification method } Hlpr.OnProgressStep := Archive.DoInflateProgress; { provide encryption check value } Item.CRC32 := Deflate(InStream, OutStream, Hlpr); finally {Hlpr} Hlpr.Free; end; {Hlpr} end; { ========================================================================== } procedure DoStore(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var CRC32 : UInt32; Percent : LongInt; LastPercent : LongInt; InSize : Int64; DataRead : Int64; Total : Int64; Abort : Boolean; Buffer : array [0..16383] of byte; begin { setup } Item.CompressionMethod := cmStored; Abort := False; CRC32 := 0; Total := 0; Percent := 0; LastPercent := 0; InSize := InStream.Size; { get first bufferful } DataRead := InStream.Read(Buffer, SizeOf(Buffer)); { while more data has been read and we're not told to bail } while (DataRead <> 0) and not Abort do begin {report the progress} if Assigned(Archive.OnProgress) then begin Total := Total + DataRead; Percent := Round((100.0 * Total) / InSize); if (LastPercent <> Percent) then Archive.OnProgress(Percent, Abort); LastPercent := Percent; end; { update CRC} CRC32 := crc32_16bytes(Buffer, DataRead, CRC32); { write data (encrypting if needed) } OutStream.WriteBuffer(Buffer, DataRead); { get next bufferful } DataRead := InStream.Read(Buffer, SizeOf(Buffer)); end; { finish CRC calculation } Item.CRC32 := LongInt(CRC32); { show final progress increment } if (Percent < 100) and Assigned(Archive.OnProgress) then Archive.OnProgress(100, Abort); { User wants to bail } if Abort then begin raise EAbUserAbort.Create; end; end; { ========================================================================== } procedure DoZipFromStream(Sender : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var ZipArchive : TAbZipArchive; InStartPos : Int64; OutStartPos : Int64; TempOut : TAbVirtualMemoryStream; DestStrm : TStream; begin ZipArchive := TAbZipArchive(Sender); { save starting point } OutStartPos := OutStream.Position; { configure Item } Item.UncompressedSize := InStream.Size; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag and AbLanguageEncodingFlag; if ZipArchive.Password <> '' then { encrypt the stream } DestStrm := TAbDfEncryptStream.Create(OutStream, LongInt(Item.LastModFileTime shl $10), ZipArchive.Password) else DestStrm := OutStream; try if InStream.Size > 0 then begin if SameText(ExtractFileExt(Sender.ArchiveName), '.zipx') then begin case ZipArchive.CompressionMethod of IntPtr(cmXz): DoCompressXz(ZipArchive, Item, DestStrm, InStream); IntPtr(cmZstd): DoCompressZstd(ZipArchive, Item, DestStrm, InStream); else raise Exception.Create(EmptyStr); end; end else { determine how to store Item based on specified CompressionMethodToUse } case ZipArchive.CompressionMethodToUse of smDeflated : begin { Item is to be deflated regarless } { deflate item } DoDeflate(ZipArchive, Item, DestStrm, InStream); end; smStored : begin { Item is to be stored regardless } { store item } DoStore(ZipArchive, Item, DestStrm, InStream); end; smBestMethod : begin { Item is to be archived using method producing best compression } TempOut := TAbVirtualMemoryStream.Create; try TempOut.SwapFileDirectory := Sender.TempDirectory; { save starting points } InStartPos := InStream.Position; { try deflating item } DoDeflate(ZipArchive, Item, TempOut, InStream); { if deflated size > input size then got negative compression } { so storing the item is more efficient } if TempOut.Size > InStream.Size then begin { store item instead } { reset streams to original positions } InStream.Position := InStartPos; TempOut.Free; TempOut := TAbVirtualMemoryStream.Create; TempOut.SwapFileDirectory := Sender.TempDirectory; { store item } DoStore(ZipArchive, Item, TempOut, InStream); end {if}; TempOut.Seek(0, soBeginning); DestStrm.CopyFrom(TempOut, TempOut.Size); finally TempOut.Free; end; end; end; { case } end else begin { InStream is zero length} Item.CRC32 := 0; { ignore any storage indicator and treat as stored } DoStore(ZipArchive, Item, DestStrm, InStream); end; finally if DestStrm <> OutStream then DestStrm.Free; end; { update item } Item.CompressedSize := OutStream.Position - OutStartPos; Item.InternalFileAttributes := 0; { don't care } if (ZipArchive.Password <> '') then Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or AbFileIsEncryptedFlag or AbHasDataDescriptorFlag; end; { -------------------------------------------------------------------------- } procedure AbZipFromStream(Sender : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var FileTimeStamp : LongInt; begin // Set item properties for non-file streams Item.ExternalFileAttributes := 0; FileTimeStamp := DateTimeToFileDate(SysUtils.Now); Item.LastModFileTime := LongRec(FileTimeStamp).Lo; Item.LastModFileDate := LongRec(FileTimeStamp).Hi; DoZipFromStream(Sender, Item, OutStream, InStream); end; { -------------------------------------------------------------------------- } procedure AbZip( Sender : TAbZipArchive; Item : TAbZipItem; OutStream : TStream ); var UncompressedStream : TStream; AttrEx : TAbAttrExRec; begin if not AbFileGetAttrEx(Item.DiskFileName, AttrEx) then Raise EAbFileNotFound.Create; if ((AttrEx.Attr and faDirectory) <> 0) then UncompressedStream := TMemoryStream.Create else UncompressedStream := TFileStreamEx.Create(Item.DiskFileName, fmOpenRead or fmShareDenyWrite); try {UncompressedStream} {$IFDEF UNIX} Item.ExternalFileAttributes := LongWord(AttrEx.Mode) shl 16 + LongWord(AttrEx.Attr); {$ELSE} Item.ExternalFileAttributes := AttrEx.Attr; {$ENDIF} Item.LastModTimeAsDateTime := AttrEx.Time; DoZipFromStream(Sender, Item, OutStream, UncompressedStream); finally {UncompressedStream} UncompressedStream.Free; end; {UncompressedStream} end; { -------------------------------------------------------------------------- } end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abziptyp.pas�����������������������������������������0000644�0001750�0000144�00000264214�14743153644�023010� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson <capeterson@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipTyp.pas *} {*********************************************************} {* ABBREVIA: PKZip types *} {* Based on information from Appnote.txt, shipped with *} {* PKWare's PKZip for Windows 2.5 *} {*********************************************************} unit AbZipTyp; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbUtils, AbSpanSt; const { note #$50 = 'P', #$4B = 'K'} Ab_ZipVersion = 63; Ab_ZipLocalFileHeaderSignature : Longint = $04034B50; Ab_ZipDataDescriptorSignature : Longint = $08074B50; Ab_ZipCentralDirectoryFileHeaderSignature : Longint = $02014B50; Ab_Zip64EndCentralDirectorySignature : Longint = $06064B50; Ab_Zip64EndCentralDirectoryLocatorSignature:Longint = $07064B50; Ab_ZipEndCentralDirectorySignature : Longint = $06054B50; Ab_ZipSpannedSetSignature : Longint = $08074B50; Ab_ZipPossiblySpannedSignature : Longint = $30304B50; Ab_GeneralZipSignature : Word = $4B50; Ab_ArchiveExtraDataRecord : Longint = $08064B50; Ab_DigitalSignature : Longint = $05054B50; Ab_WindowsExeSignature : Word = $5A4D; Ab_LinuxExeSignature : Longint = $464C457F; AbDefZipSpanningThreshold = 0; AbDefPasswordRetries = 3; AbFileIsEncryptedFlag = $0001; AbHasDataDescriptorFlag = $0008; AbLanguageEncodingFlag = $0800; Ab_Zip64SubfieldID : Word = $0001; Ab_NTFSSubfieldID : Word = $000A; Ab_InfoZipTimestampSubfieldID : Word = $5455; Ab_InfoZipUnicodePathSubfieldID : Word = $7075; Ab_XceedUnicodePathSubfieldID : Word = $554E; Ab_XceedUnicodePathSignature : LongWord= $5843554E; type TNtfsTimeField = packed record Reserved : UInt32; Tag : UInt16; Size : UInt16; Mtime : UInt64; Atime : UInt64; Ctime : UInt64; end; PNtfsTimeField = ^TNtfsTimeField; TInfoZipTimeField = packed record Tag : Byte; Mtime : UInt32; end; PInfoZipTimeField = ^TInfoZipTimeField; type PAbByteArray4K = ^TAbByteArray4K; TAbByteArray4K = array[1..4096] of Byte; PAbByteArray8K = ^TAbByteArray8K; TAbByteArray8K = array[0..8192] of Byte; PAbIntArray8K = ^TAbIntArray8K; TAbIntArray8K = array[0..8192] of SmallInt; PAbWordArray = ^TAbWordArray; TAbWordArray = array[0..65535 div SizeOf(Word)-1] of Word; PAbByteArray = ^TAbByteArray; TAbByteArray = array[0..65535-1] of Byte; PAbSmallIntArray = ^TAbSmallIntArray; TAbSmallIntArray = array[0..65535 div SizeOf(SmallInt)-1] of SmallInt; PAbIntegerArray = ^TAbIntegerArray; TAbIntegerArray = array[0..65535 div sizeof(integer)-1] of integer; TAbZip64EndOfCentralDirectoryRecord = packed record Signature : Longint; RecordSize : Int64; VersionMadeBy : Word; VersionNeededToExtract : Word; DiskNumber : LongWord; StartDiskNumber : LongWord; EntriesOnDisk : Int64; TotalEntries : Int64; DirectorySize : Int64; DirectoryOffset : Int64; end; TAbZip64EndOfCentralDirectoryLocator = packed record Signature : Longint; StartDiskNumber : Longint; RelativeOffset : Int64; TotalDisks : Longint; end; TAbZipEndOfCentralDirectoryRecord = packed record Signature : Longint; DiskNumber : Word; StartDiskNumber : Word; EntriesOnDisk : Word; TotalEntries : Word; DirectorySize : LongWord; DirectoryOffset : LongWord; CommentLength : Word; end; TAbFollower = {used to expand reduced files} packed record Size : Byte; {size of follower set} FSet : array[0..31] of Byte; {follower set} end; PAbFollowerSets = ^TAbFollowerSets; TAbFollowerSets = array[0..255] of TAbFollower; PAbSfEntry = ^TAbSfEntry; TAbSfEntry = {entry in a Shannon-Fano tree} packed record case Byte of 0 : (Code : Word; Value, BitLength : Byte); 1 : (L : Longint); end; PAbSfTree = ^TAbSfTree; TAbSfTree = packed record {a Shannon-Fano tree} Entries : SmallInt; MaxLength : SmallInt; Entry : array[0..256] of TAbSfEntry; end; PInfoZipUnicodePathRec = ^TInfoZipUnicodePathRec; TInfoZipUnicodePathRec = packed record Version: Byte; NameCRC32: LongInt; UnicodeName: array[0..0] of AnsiChar; end; PXceedUnicodePathRec = ^TXceedUnicodePathRec; TXceedUnicodePathRec = packed record Signature: LongWord; Length: Integer; UnicodeName: array[0..0] of WideChar; end; PZip64LocalHeaderRec = ^TZip64LocalHeaderRec; TZip64LocalHeaderRec = packed record UncompressedSize: Int64; CompressedSize: Int64; end; type TAbZipCompressionMethod = (cmStored, cmShrunk, cmReduced1, cmReduced2, cmReduced3, cmReduced4, cmImploded, cmTokenized, cmDeflated, cmEnhancedDeflated, cmDCLImploded, cmBzip2 = 12, cmLZMA = 14, cmIBMTerse = 18, cmLZ77, cmZstd = 93, cmXz = 95, cmJPEG = 96, cmWavPack = 97, cmPPMd); TAbZipSupportedMethod = (smStored, smDeflated, smBestMethod); {ExternalFileAttributes compatibility; aliases are Info-ZIP/PKZIP overlaps} TAbZipHostOS = (hosDOS, hosAmiga, hosVAX, hosUnix, hosVMCMS, hosAtari, hosOS2, hosMacintosh, hosZSystem, hosCPM, hosNTFS, hosTOPS20 = hosNTFS, hosMVS, hosWinNT = hosMVS, hosVSE, hosQDOS = hosVSE, hosRISC, hosVFAT, hosAltMVS, hosBeOS, hosTandem, hosOS400, hosTHEOS = hosOS400, hosDarwin, hosAtheOS = 30); {for method 6 - imploding} TAbZipDictionarySize = (dsInvalid, ds4K, ds8K); {for method 8 - deflating} TAbZipDeflationOption = (doInvalid, doNormal, doMaximum, doFast, doSuperFast ); type TAbNeedPasswordEvent = procedure(Sender : TObject; var NewPassword : AnsiString) of object; const AbDefCompressionMethodToUse = smBestMethod; AbDefDeflationOption = doNormal; type TAbZipDataDescriptor = class( TObject ) protected {private} FCRC32 : Longint; FCompressedSize : Int64; FUncompressedSize : Int64; public {methods} procedure LoadFromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream ); public {properties} property CRC32 : Longint read FCRC32 write FCRC32; property CompressedSize : Int64 read FCompressedSize write FCompressedSize; property UncompressedSize : Int64 read FUncompressedSize write FUncompressedSize; end; type { TAbZipFileHeader interface =============================================== } {ancestor class for ZipLocalFileHeader and DirectoryFileHeader} TAbZipFileHeader = class( TObject ) protected {private} FValidSignature : Longint; FSignature : Longint; FVersionNeededToExtract : Word; FGeneralPurposeBitFlag : Word; FCompressionMethod : Word; FLastModFileTime : Word; FLastModFileDate : Word; FCRC32 : Longint; FCompressedSize : LongWord; FUncompressedSize : LongWord; FFileName : AnsiString; FExtraField : TAbExtraField; protected {methods} function GetCompressionMethod : TAbZipCompressionMethod; function GetCompressionRatio : Double; function GetDataDescriptor : Boolean; function GetDeflationOption : TAbZipDeflationOption; function GetDictionarySize : TAbZipDictionarySize; function GetEncrypted : Boolean; function GetIsUTF8 : Boolean; function GetShannonFanoTreeCount : Byte; function GetValid : Boolean; procedure SetCompressionMethod( Value : TAbZipCompressionMethod ); procedure SetIsUTF8( Value : Boolean ); public {methods} constructor Create; destructor Destroy; override; public {properties} property Signature : Longint read FSignature write FSignature; property VersionNeededToExtract : Word read FVersionNeededToExtract write FVersionNeededToExtract; property GeneralPurposeBitFlag : Word read FGeneralPurposeBitFlag write FGeneralPurposeBitFlag; property CompressionMethod : TAbZipCompressionMethod read GetCompressionMethod write SetCompressionMethod; property LastModFileTime : Word read FLastModFileTime write FLastModFileTime; property LastModFileDate : Word read FLastModFileDate write FLastModFileDate; property CRC32 : Longint read FCRC32 write FCRC32; property CompressedSize : LongWord read FCompressedSize write FCompressedSize; property UncompressedSize : LongWord read FUncompressedSize write FUncompressedSize; property FileName : AnsiString read FFileName write FFileName; property ExtraField : TAbExtraField read FExtraField; property CompressionRatio : Double read GetCompressionRatio; property DeflationOption : TAbZipDeflationOption read GetDeflationOption; property DictionarySize : TAbZipDictionarySize read GetDictionarySize; property HasDataDescriptor : Boolean read GetDataDescriptor; property IsValid : Boolean read GetValid; property IsEncrypted : Boolean read GetEncrypted; property IsUTF8 : Boolean read GetIsUTF8 write SetIsUTF8; property ShannonFanoTreeCount : Byte read GetShannonFanoTreeCount; end; { TAbZipLocalFileHeader interface ========================================== } TAbZipLocalFileHeader = class( TAbZipFileHeader ) public {methods} constructor Create; destructor Destroy; override; procedure LoadFromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream ); end; { TAbZipDirectoryFileHeader interface ====================================== } TAbZipDirectoryFileHeader = class( TAbZipFileHeader ) protected {private} FVersionMadeBy : Word; FDiskNumberStart : Word; FInternalFileAttributes : Word; FExternalFileAttributes : LongWord; FRelativeOffset : LongWord; FFileComment : AnsiString; public {methods} constructor Create; destructor Destroy; override; procedure LoadFromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream ); public {properties} property VersionMadeBy : Word read FVersionMadeBy write FVersionMadeBy; property DiskNumberStart : Word read FDiskNumberStart write FDiskNumberStart; property InternalFileAttributes : Word read FInternalFileAttributes write FInternalFileAttributes; property ExternalFileAttributes : LongWord read FExternalFileAttributes write FExternalFileAttributes; property RelativeOffset : LongWord read FRelativeOffset write FRelativeOffset; property FileComment : AnsiString read FFileComment write FFileComment; end; { TAbZipDirectoryFileFooter interface ====================================== } TAbZipDirectoryFileFooter = class( TObject ) protected {private} FDiskNumber : LongWord; FStartDiskNumber : LongWord; FEntriesOnDisk : Int64; FTotalEntries : Int64; FDirectorySize : Int64; FDirectoryOffset : Int64; FZipfileComment : AnsiString; function GetIsZip64: Boolean; public {methods} procedure LoadFromStream( Stream : TStream ); procedure LoadZip64FromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream; aZip64TailOffset : Int64 = -1 ); public {properties} property DiskNumber : LongWord read FDiskNumber write FDiskNumber; property EntriesOnDisk : Int64 read FEntriesOnDisk write FEntriesOnDisk; property TotalEntries : Int64 read FTotalEntries write FTotalEntries; property DirectorySize : Int64 read FDirectorySize write FDirectorySize; property DirectoryOffset : Int64 read FDirectoryOffset write FDirectoryOffset; property StartDiskNumber : LongWord read FStartDiskNumber write FStartDiskNumber; property ZipfileComment : AnsiString read FZipfileComment write FZipfileComment; property IsZip64: Boolean read GetIsZip64; end; { TAbZipItem interface ===================================================== } TAbZipItem = class( TAbArchiveItem ) protected {private} FItemInfo : TAbZipDirectoryFileHeader; FDiskNumberStart : LongWord; FLFHExtraField : TAbExtraField; FRelativeOffset : Int64; FDateTime : TDateTime; protected {methods} function GetCompressionMethod : TAbZipCompressionMethod; function GetCompressionRatio : Double; function GetDeflationOption : TAbZipDeflationOption; function GetDictionarySize : TAbZipDictionarySize; function GetExtraField : TAbExtraField; function GetFileComment : AnsiString; function GetGeneralPurposeBitFlag : Word; function GetHostOS: TAbZipHostOS; function GetInternalFileAttributes : Word; function GetRawFileName : AnsiString; function GetShannonFanoTreeCount : Byte; function GetVersionMadeBy : Word; function GetVersionNeededToExtract : Word; procedure SaveCDHToStream( Stream : TStream ); procedure SaveDDToStream( Stream : TStream ); procedure SaveLFHToStream( Stream : TStream ); procedure SetCompressionMethod( Value : TAbZipCompressionMethod ); procedure SetDiskNumberStart( Value : LongWord ); procedure SetFileComment(const Value : AnsiString ); procedure SetGeneralPurposeBitFlag( Value : Word ); procedure SetHostOS( Value : TAbZipHostOS ); procedure SetInternalFileAttributes( Value : Word ); procedure SetRelativeOffset( Value : Int64 ); procedure SetVersionMadeBy( Value : Word ); procedure SetVersionNeededToExtract( Value : Word ); procedure UpdateVersionNeededToExtract; procedure UpdateZip64ExtraHeader; protected {redefined property methods} function GetCRC32 : Longint; override; function GetExternalFileAttributes : LongWord; override; function GetIsDirectory: Boolean; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetNativeFileAttributes : LongInt; override; function GetNativeLastModFileTime: Longint; override; function GetLastModTimeAsDateTime: TDateTime; override; procedure SetCompressedSize( const Value : Int64 ); override; procedure SetCRC32( const Value : Longint ); override; procedure SetExternalFileAttributes( Value : LongWord ); override; procedure SetFileName(const Value : string ); override; procedure SetLastModFileDate(const Value : Word ); override; procedure SetLastModFileTime(const Value : Word ); override; procedure SetUncompressedSize( const Value : Int64 ); override; procedure SetLastModTimeAsDateTime(const Value: TDateTime); override; public {methods} constructor Create; destructor Destroy; override; procedure LoadFromStream( Stream : TStream ); public {properties} property CompressionMethod : TAbZipCompressionMethod read GetCompressionMethod write SetCompressionMethod; property CompressionRatio : Double read GetCompressionRatio; property DeflationOption : TAbZipDeflationOption read GetDeflationOption; property DictionarySize : TAbZipDictionarySize read GetDictionarySize; property DiskNumberStart : LongWord read FDiskNumberStart write SetDiskNumberStart; property ExtraField : TAbExtraField read GetExtraField; property FileComment : AnsiString read GetFileComment write SetFileComment; property HostOS: TAbZipHostOS read GetHostOS write SetHostOS; property InternalFileAttributes : Word read GetInternalFileAttributes write SetInternalFileAttributes; property GeneralPurposeBitFlag : Word read GetGeneralPurposeBitFlag write SetGeneralPurposeBitFlag; property LFHExtraField : TAbExtraField read FLFHExtraField; property RawFileName : AnsiString read GetRawFileName; property RelativeOffset : Int64 read FRelativeOffset write SetRelativeOffset; property ShannonFanoTreeCount : Byte read GetShannonFanoTreeCount; property VersionMadeBy : Word read GetVersionMadeBy write SetVersionMadeBy; property VersionNeededToExtract : Word read GetVersionNeededToExtract write SetVersionNeededToExtract; end; { TAbZipArchive interface ================================================== } TAbZipArchive = class( TAbArchive ) protected {private} FCompressionMethodToUse : TAbZipSupportedMethod; FDeflationOption : TAbZipDeflationOption; FInfo : TAbZipDirectoryFileFooter; FIsExecutable : Boolean; FPassword : AnsiString; FPasswordRetries : Byte; FStubSize : LongWord; FExtractHelper : TAbArchiveItemExtractEvent; FExtractToStreamHelper : TAbArchiveItemExtractToStreamEvent; FTestHelper : TAbArchiveItemTestEvent; FInsertHelper : TAbArchiveItemInsertEvent; FInsertFromStreamHelper : TAbArchiveItemInsertFromStreamEvent; FOnNeedPassword : TAbNeedPasswordEvent; FOnRequestLastDisk : TAbRequestDiskEvent; FOnRequestNthDisk : TAbRequestNthDiskEvent; FOnRequestBlankDisk : TAbRequestDiskEvent; protected {methods} procedure DoExtractHelper(Index : Integer; const NewName : string); procedure DoExtractToStreamHelper(Index : Integer; aStream : TStream); procedure DoTestHelper(Index : Integer); procedure DoInsertHelper(Index : Integer; OutStream : TStream); procedure DoInsertFromStreamHelper(Index : Integer; OutStream : TStream); function GetItem( Index : Integer ) : TAbZipItem; function GetZipfileComment : AnsiString; procedure PutItem( Index : Integer; Value : TAbZipItem ); procedure DoRequestDisk(const AMessage: string; var Abort : Boolean); procedure DoRequestLastDisk( var Abort : Boolean ); virtual; procedure DoRequestNthDisk(Sender: TObject; DiskNumber : Byte; var Abort : Boolean ); virtual; procedure DoRequestBlankDisk(Sender: TObject; var Abort : Boolean ); virtual; procedure ExtractItemAt(Index : Integer; const UseName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure TestItemAt(Index : Integer); override; function FixName(const Value : string ) : string; override; function GetSupportsEmptyFolders: Boolean; override; procedure LoadArchive; override; procedure SaveArchive; override; procedure SetZipfileComment(const Value : AnsiString ); protected {properties} property IsExecutable : Boolean read FIsExecutable write FIsExecutable; public {protected} procedure DoRequestImage(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); public {methods} constructor CreateFromStream( aStream : TStream; const ArchiveName : string ); override; destructor Destroy; override; function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; public {properties} property CompressionMethodToUse : TAbZipSupportedMethod read FCompressionMethodToUse write FCompressionMethodToUse; property DeflationOption : TAbZipDeflationOption read FDeflationOption write FDeflationOption; property ExtractHelper : TAbArchiveItemExtractEvent read FExtractHelper write FExtractHelper; property ExtractToStreamHelper : TAbArchiveItemExtractToStreamEvent read FExtractToStreamHelper write FExtractToStreamHelper; property TestHelper : TAbArchiveItemTestEvent read FTestHelper write FTestHelper; property InsertHelper : TAbArchiveItemInsertEvent read FInsertHelper write FInsertHelper; property InsertFromStreamHelper : TAbArchiveItemInsertFromStreamEvent read FInsertFromStreamHelper write FInsertFromStreamHelper; property Password : AnsiString read FPassword write FPassword; property PasswordRetries : Byte read FPasswordRetries write FPasswordRetries default AbDefPasswordRetries; property StubSize : LongWord read FStubSize; property ZipfileComment : AnsiString read GetZipfileComment write SetZipfileComment; property Items[Index : Integer] : TAbZipItem read GetItem write PutItem; default; public {events} property OnNeedPassword : TAbNeedPasswordEvent read FOnNeedPassword write FOnNeedPassword; property OnRequestLastDisk : TAbRequestDiskEvent read FOnRequestLastDisk write FOnRequestLastDisk; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write FOnRequestNthDisk; property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write FOnRequestBlankDisk; end; {============================================================================} procedure MakeSelfExtracting( StubStream, ZipStream, SelfExtractingStream : TStream ); {-takes an executable stub, and a .zip format stream, and creates a SelfExtracting stream. The stub should create a TAbZipArchive passing itself as the file, using a read-only open mode. It should then perform operations as needed - like ExtractFiles( '*.*' ). This routine updates the RelativeOffset of each item in the archive} function FindCentralDirectoryTail(aStream : TStream) : Int64; function VerifyZip(Strm : TStream) : TAbArchiveType; function VerifySelfExtracting(Strm : TStream) : TAbArchiveType; function ZipCompressionMethodToString(aMethod: TAbZipCompressionMethod): string; implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF UnixDialogs} {$IFDEF KYLIX} QControls, QDialogs, {$ENDIF} {$IFDEF LCL} Controls, Dialogs, {$ENDIF} {$ENDIF} Math, AbResString, AbExcept, AbVMStrm, SysUtils, LazUTF8, DCOSUtils, DCStrUtils, DCBasicTypes, DCClassesUtf8, DCDateTimeUtils, DCConvertEncoding; function VerifyZip(Strm : TStream) : TAbArchiveType; { determine if stream appears to be in PkZip format } var Empty : TAbZipEndOfCentralDirectoryRecord; Footer : TAbZipEndOfCentralDirectoryRecord; Sig : LongInt; TailPosition : int64; StartPos : int64; begin StartPos := Strm.Position; Result := atUnknown; try Strm.Position := 0; if Strm.Read(Sig, SizeOf(Sig)) = SizeOf(Sig) then begin if (Sig = Ab_ZipSpannedSetSignature) then Result := atSpannedZip else begin { attempt to find Central Directory Tail } TailPosition := FindCentralDirectoryTail( Strm ); if TailPosition <> -1 then begin { check Central Directory Signature } if (Strm.Read(Footer, SizeOf(Footer)) = SizeOf(Footer)) and (Footer.Signature = Ab_ZipEndCentralDirectorySignature) then begin Empty:= Default(TAbZipEndOfCentralDirectoryRecord); Empty.Signature:= Ab_ZipEndCentralDirectorySignature; { check Central Directory Offset } if (Footer.DirectoryOffset = High(LongWord)) or ((Strm.Seek(Footer.DirectoryOffset, soBeginning) = Footer.DirectoryOffset) and (Strm.Read(Sig, SizeOf(Sig)) = SizeOf(Sig)) and (Sig = Ab_ZipCentralDirectoryFileHeaderSignature)) then begin if Footer.DiskNumber = 0 then Result := atZip else Result := atSpannedZip; end { empty archive } else if (Strm.Size = SizeOf(Footer)) and (CompareMem(@Footer, @Empty, SizeOf(Footer))) then begin Result := atZip end; end; end; end; end; except on EReadError do Result := atUnknown; end; Strm.Position := StartPos; end; function VerifySelfExtracting(Strm : TStream) : TAbArchiveType; { determine if stream appears to be an executable with appended PkZip data } var FileSignature : Longint; StartPos : Int64; IsWinExe, IsLinuxExe : Boolean; begin StartPos := Strm.Position; { verify presence of executable stub } {check file type of stub stream} Strm.Position := 0; Strm.Read( FileSignature, sizeof( FileSignature ) ); Result := atSelfExtZip; { detect executable type } IsLinuxExe := FileSignature = Ab_LinuxExeSignature; IsWinExe := LongRec(FileSignature).Lo = Ab_WindowsExeSignature; if not (IsWinExe or IsLinuxExe) then Result := atUnknown; { Check for central directory tail } if VerifyZip(Strm) <> atZip then Result := atUnknown; Strm.Position := StartPos; end; {============================================================================} function ZipCompressionMethodToString(aMethod: TAbZipCompressionMethod): string; begin case aMethod of cmStored: Result := AbZipStored; cmShrunk: Result := AbZipShrunk; cmReduced1..cmReduced4: Result := AbZipReduced; cmImploded: Result := AbZipImploded; cmTokenized: Result := AbZipTokenized; cmDeflated: Result := AbZipDeflated; cmEnhancedDeflated: Result := AbZipDeflate64; cmDCLImploded: Result := AbZipDCLImploded; cmBzip2: Result := AbZipBzip2; cmLZMA: Result := AbZipLZMA; cmIBMTerse: Result := AbZipIBMTerse; cmLZ77: Result := AbZipLZ77; cmJPEG: Result := AbZipJPEG; cmWavPack: Result := AbZipWavPack; cmPPMd: Result := AbZipPPMd; else Result := Format(AbZipUnknown, [Ord(aMethod)]); end; end; {============================================================================} function FindCentralDirectoryTail(aStream : TStream) : Int64; { search end of aStream looking for ZIP Central Directory structure returns position in stream if found (otherwise returns -1), leaves stream positioned at start of structure or at original position if not found } const MaxBufSize = 256 * 1024; var StartPos : Int64; TailRec : TAbZipEndOfCentralDirectoryRecord; Buffer : PAnsiChar; Offset : Int64; TestPos : PAnsiChar; BytesRead : Int64; BufSize : Int64; CommentLen: integer; begin {save the starting position} StartPos := aStream.Seek(0, soCurrent); {start off with the majority case: no zip file comment, so the central directory tail is the last thing in the stream and it's a fixed size and doesn't indicate a zip file comment} Result := aStream.Seek(-sizeof(TailRec), soEnd); if (Result >= 0) then begin aStream.ReadBuffer(TailRec, sizeof(TailRec)); if (TailRec.Signature = Ab_ZipEndCentralDirectorySignature) and (TailRec.CommentLength = 0) then begin aStream.Seek(Result, soBeginning); Exit; end; end; {the zip stream seems to have a comment, or it has null padding bytes from some flaky program, or it's not even a zip formatted stream; we need to search for the tail signature} {get a buffer} BufSize := Min(MaxBufSize, aStream.Size); GetMem(Buffer, BufSize); try {start out searching backwards} Offset := -BufSize; {seek to the search position} Result := aStream.Seek(Offset, soEnd); if (Result < 0) then begin Result := aStream.Seek(0, soBeginning); end; {read a buffer full} BytesRead := aStream.Read(Buffer^, BufSize); if BytesRead < sizeOf(TailRec) then begin Result := -1; Exit; end; {search backwards through the buffer looking for the signature} TestPos := Buffer + BytesRead - sizeof(TailRec); while (TestPos <> Buffer) and (PLongint(TestPos)^ <> Ab_ZipEndCentralDirectorySignature) do dec(TestPos); {if we found the signature...} if (PLongint(TestPos)^ = Ab_ZipEndCentralDirectorySignature) then begin {get the tail record at this position} Move(TestPos^, TailRec, sizeof(TailRec)); {if it's as valid a tail as we can check here...} CommentLen := -Offset - (TestPos - Buffer + sizeof(TailRec)); if (TailRec.CommentLength <= CommentLen) then begin {calculate its position and exit} Result := Result + (TestPos - Buffer); aStream.Seek(Result, soBeginning); Exit; end; end; {if we reach this point, the CD tail is not present} Result := -1; aStream.Seek(StartPos, soBeginning); finally FreeMem(Buffer); end; end; {============================================================================} procedure MakeSelfExtracting( StubStream, ZipStream, SelfExtractingStream : TStream ); {-takes an executable stub, and a .zip format stream, and creates a SelfExtracting stream. The stub should create a TAbZipArchive passing itself as the file, using a read-only open mode. It should then perform operations as needed - like ExtractFiles( '*.*' ). This routine updates the RelativeOffset of each item in the archive} var DirectoryStart : Int64; FileSignature : Longint; StubSize : LongWord; TailPosition : Int64; ZDFF : TAbZipDirectoryFileFooter; ZipItem : TAbZipItem; IsWinExe, IsLinuxExe : Boolean; begin {check file type of stub stream} StubStream.Position := 0; StubStream.Read(FileSignature, SizeOf(FileSignature)); {detect executable type } IsLinuxExe := FileSignature = Ab_LinuxExeSignature; IsWinExe := LongRec(FileSignature).Lo = Ab_WindowsExeSignature; if not (IsWinExe or IsLinuxExe) then raise EAbZipInvalidStub.Create; StubStream.Position := 0; StubSize := StubStream.Size; ZipStream.Position := 0; ZipStream.Read( FileSignature, sizeof( FileSignature ) ); if LongRec(FileSignature).Lo <> Ab_GeneralZipSignature then raise EAbZipInvalid.Create; ZipStream.Position := 0; {copy the stub into the selfex stream} SelfExtractingStream.Position := 0; SelfExtractingStream.CopyFrom( StubStream, 0 ); TailPosition := FindCentralDirectoryTail( ZipStream ); if TailPosition = -1 then raise EAbZipInvalid.Create; {load the ZipDirectoryFileFooter} ZDFF := TAbZipDirectoryFileFooter.Create; try ZDFF.LoadFromStream( ZipStream ); DirectoryStart := ZDFF.DirectoryOffset; finally ZDFF.Free; end; {copy everything up to the CDH into the SelfExtractingStream} ZipStream.Position := 0; SelfExtractingStream.CopyFrom( ZipStream, DirectoryStart ); ZipStream.Position := DirectoryStart; repeat ZipItem := TAbZipItem.Create; try ZipItem.LoadFromStream( ZipStream ); ZipItem.RelativeOffset := ZipItem.RelativeOffset + StubSize; {save the modified entry into the Self Extracting Stream} ZipItem.SaveCDHToStream( SelfExtractingStream ); finally ZipItem.Free; end; until ZipStream.Position = TailPosition; {save the CDH Footer.} ZDFF := TAbZipDirectoryFileFooter.Create; try ZDFF.LoadFromStream( ZipStream ); ZDFF.DirectoryOffset := ZDFF.DirectoryOffset + StubSize; ZDFF.SaveToStream( SelfExtractingStream ); finally ZDFF.Free; end; end; {============================================================================} { TAbZipDataDescriptor implementation ====================================== } procedure TAbZipDataDescriptor.LoadFromStream(Stream: TStream); var Signature: LongInt = 0; begin Stream.Read(Signature, SizeOf(Ab_ZipDataDescriptorSignature)); if (Signature <> Ab_ZipDataDescriptorSignature) then Exit; Stream.Read(FCRC32, SizeOf(FCRC32)); Stream.Read(FCompressedSize, SizeOf(LongWord)); Stream.Read(FUncompressedSize, SizeOf(LongWord)); end; { -------------------------------------------------------------------------- } procedure TAbZipDataDescriptor.SaveToStream( Stream : TStream ); begin Stream.Write( Ab_ZipDataDescriptorSignature, sizeof( Ab_ZipDataDescriptorSignature ) ); Stream.Write( FCRC32, sizeof( FCRC32 ) ); if (FCompressedSize >= $FFFFFFFF) or (FUncompressedSize >= $FFFFFFFF) then begin Stream.Write( FCompressedSize, sizeof( FCompressedSize ) ); Stream.Write( FUncompressedSize, sizeof( FUncompressedSize ) ); end else begin Stream.Write( FCompressedSize, sizeof( LongWord ) ); Stream.Write( FUncompressedSize, sizeof( LongWord ) ); end; end; { -------------------------------------------------------------------------- } { TAbZipFileHeader implementation ========================================== } constructor TAbZipFileHeader.Create; begin inherited Create; FExtraField := TAbExtraField.Create; FValidSignature := $0; end; { -------------------------------------------------------------------------- } destructor TAbZipFileHeader.Destroy; begin FreeAndNil(FExtraField); inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetCompressionMethod : TAbZipCompressionMethod; begin Result := TAbZipCompressionMethod( FCompressionMethod ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetDataDescriptor : Boolean; begin Result := ( CompressionMethod = cmDeflated ) and ( ( FGeneralPurposeBitFlag and AbHasDataDescriptorFlag ) <> 0 ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetCompressionRatio : Double; var CompSize : Int64; begin {adjust for encrypted headers - ensures we never get negative compression ratios for stored, encrypted files - no guarantees about negative compression ratios in other cases} if isEncrypted then CompSize := CompressedSize - 12 else CompSize := CompressedSize; if UncompressedSize > 0 then Result := 100.0 * ( 1 - ( ( 1.0 * CompSize ) / UncompressedSize ) ) else Result := 0.0; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetDeflationOption : TAbZipDeflationOption; begin if CompressionMethod = cmDeflated then if ( ( FGeneralPurposeBitFlag and $02 ) <> 0 ) then if ( ( FGeneralPurposeBitFlag and $04 ) <> 0 ) then Result := doSuperFast else Result := doMaximum else if ( ( FGeneralPurposeBitFlag and $04 ) <> 0 ) then Result := doFast else Result := doNormal else Result := doInvalid; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetDictionarySize : TAbZipDictionarySize; begin if CompressionMethod = cmImploded then if ( ( FGeneralPurposeBitFlag and $02 ) <> 0 ) then Result := ds8K else Result := ds4K else Result := dsInvalid; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetEncrypted : Boolean; begin {bit 0 of the GeneralPurposeBitFlag} Result := ( ( FGeneralPurposeBitFlag and AbFileIsEncryptedFlag ) <> 0 ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetIsUTF8 : Boolean; begin Result := ( ( GeneralPurposeBitFlag and AbLanguageEncodingFlag ) <> 0 ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetShannonFanoTreeCount : Byte; begin if CompressionMethod = cmImploded then if ( ( FGeneralPurposeBitFlag and $04 ) <> 0 ) then Result := 3 else Result := 2 else Result := 0; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetValid : Boolean; begin Result := ( FValidSignature = FSignature ); end; { -------------------------------------------------------------------------- } procedure TAbZipFileHeader.SetCompressionMethod( Value : TAbZipCompressionMethod ); begin FCompressionMethod := Ord( Value ); end; { -------------------------------------------------------------------------- } procedure TAbZipFileHeader.SetIsUTF8( Value : Boolean ); begin if Value then GeneralPurposeBitFlag := GeneralPurposeBitFlag or AbLanguageEncodingFlag else GeneralPurposeBitFlag := GeneralPurposeBitFlag and not AbLanguageEncodingFlag; end; { -------------------------------------------------------------------------- } { TAbZipLocalFileHeader implementation ===================================== } constructor TAbZipLocalFileHeader.Create; begin inherited Create; FValidSignature := Ab_ZipLocalFileHeaderSignature; end; { -------------------------------------------------------------------------- } destructor TAbZipLocalFileHeader.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbZipLocalFileHeader.LoadFromStream( Stream : TStream ); var ExtraFieldLength, FileNameLength : Word; begin with Stream do begin Read( FSignature, sizeof( FSignature ) ); Read( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Read( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Read( FCompressionMethod, sizeof( FCompressionMethod ) ); Read( FLastModFileTime, sizeof( FLastModFileTime ) ); Read( FLastModFileDate, sizeof( FLastModFileDate ) ); Read( FCRC32, sizeof( FCRC32 ) ); Read( FCompressedSize, sizeof( FCompressedSize ) ); Read( FUncompressedSize, sizeof( FUncompressedSize ) ); Read( FileNameLength, sizeof( FileNameLength ) ); Read( ExtraFieldLength, sizeof( ExtraFieldLength ) ); SetLength( FFileName, FileNameLength ); if FileNameLength > 0 then Read( FFileName[1], FileNameLength ); FExtraField.LoadFromStream( Stream, ExtraFieldLength ); end; if not IsValid then raise EAbZipInvalid.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipLocalFileHeader.SaveToStream( Stream : TStream ); var ExtraFieldLength, FileNameLength: Word; begin with Stream do begin {write the valid signature from the constant} Write( FValidSignature, sizeof( FValidSignature ) ); Write( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Write( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Write( FCompressionMethod, sizeof( FCompressionMethod ) ); Write( FLastModFileTime, sizeof( FLastModFileTime ) ); Write( FLastModFileDate, sizeof( FLastModFileDate ) ); Write( FCRC32, sizeof( FCRC32 ) ); Write( FCompressedSize, sizeof( FCompressedSize ) ); Write( FUncompressedSize, sizeof( FUncompressedSize ) ); FileNameLength := Word( Length( FFileName ) ); Write( FileNameLength, sizeof( FileNameLength ) ); ExtraFieldLength := Length(FExtraField.Buffer); Write( ExtraFieldLength, sizeof( ExtraFieldLength ) ); if FileNameLength > 0 then Write( FFileName[1], FileNameLength ); if ExtraFieldLength > 0 then Write(FExtraField.Buffer[0], ExtraFieldLength); end; end; { -------------------------------------------------------------------------- } { TAbZipDirectoryFileHeader implementation ================================= } constructor TAbZipDirectoryFileHeader.Create; begin inherited Create; FValidSignature := Ab_ZipCentralDirectoryFileHeaderSignature; end; { -------------------------------------------------------------------------- } destructor TAbZipDirectoryFileHeader.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileHeader.LoadFromStream( Stream : TStream ); var ExtraFieldLength, FileCommentLength, FileNameLength : Word; begin with Stream do begin Read( FSignature, sizeof( FSignature ) ); Read( FVersionMadeBy, sizeof( FVersionMadeBy ) ); Read( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Read( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Read( FCompressionMethod, sizeof( FCompressionMethod ) ); Read( FLastModFileTime, sizeof( FLastModFileTime ) ); Read( FLastModFileDate, sizeof( FLastModFileDate ) ); Read( FCRC32, sizeof( FCRC32 ) ); Read( FCompressedSize, sizeof( FCompressedSize ) ); Read( FUncompressedSize, sizeof( FUncompressedSize ) ); Read( FileNameLength, sizeof( FileNameLength ) ); Read( ExtraFieldLength, sizeof( ExtraFieldLength ) ); Read( FileCommentLength, sizeof( FileCommentLength ) ); Read( FDiskNumberStart, sizeof( FDiskNumberStart ) ); Read( FInternalFileAttributes, sizeof( FInternalFileAttributes ) ); Read( FExternalFileAttributes, sizeof( FExternalFileAttributes ) ); Read( FRelativeOffset, sizeof( FRelativeOffset ) ); SetLength( FFileName, FileNameLength ); if FileNameLength > 0 then Read( FFileName[1], FileNameLength ); FExtraField.LoadFromStream( Stream, ExtraFieldLength ); SetLength( FFileComment, FileCommentLength ); if FileCommentLength > 0 then Read( FFileComment[1], FileCommentLength ); end; if not IsValid then raise EAbZipInvalid.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileHeader.SaveToStream( Stream : TStream ); var ExtraFieldLength, FileCommentLength, FileNameLength : Word; begin with Stream do begin {write the valid signature from the constant} Write( FValidSignature, sizeof( FValidSignature ) ); Write( FVersionMadeBy, sizeof( FVersionMadeBy ) ); Write( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Write( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Write( FCompressionMethod, sizeof( FCompressionMethod ) ); Write( FLastModFileTime, sizeof( FLastModFileTime ) ); Write( FLastModFileDate, sizeof( FLastModFileDate ) ); Write( FCRC32, sizeof( FCRC32 ) ); Write( FCompressedSize, sizeof( FCompressedSize ) ); Write( FUncompressedSize, sizeof( FUncompressedSize ) ); FileNameLength := Word( Length( FFileName ) ); Write( FileNameLength, sizeof( FileNameLength ) ); ExtraFieldLength := Length(FExtraField.Buffer); Write( ExtraFieldLength, sizeof( ExtraFieldLength ) ); FileCommentLength := Word( Length( FFileComment ) ); Write( FileCommentLength, sizeof( FileCommentLength ) ); Write( FDiskNumberStart, sizeof( FDiskNumberStart ) ); Write( FInternalFileAttributes, sizeof( FInternalFileAttributes ) ); Write( FExternalFileAttributes, sizeof( FExternalFileAttributes ) ); Write( FRelativeOffset, sizeof( FRelativeOffset ) ); if FileNameLength > 0 then Write( FFileName[1], FileNameLength ); if ExtraFieldLength > 0 then Write( FExtraField.Buffer[0], ExtraFieldLength ); if FileCommentLength > 0 then Write( FFileComment[1], FileCommentLength ); end; end; { -------------------------------------------------------------------------- } { TAbZipDirectoryFileFooter implementation ================================= } function TAbZipDirectoryFileFooter.GetIsZip64: Boolean; begin if DiskNumber >= $FFFF then Exit(True); if StartDiskNumber >= $FFFF then Exit(True); if EntriesOnDisk >= $FFFF then Exit(True); if TotalEntries >= $FFFF then Exit(True); if DirectorySize >= $FFFFFFFF then Exit(True); if DirectoryOffset >= $FFFFFFFF then Exit(True); Result := False; end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileFooter.LoadFromStream( Stream : TStream ); var Footer: TAbZipEndOfCentralDirectoryRecord; begin Stream.ReadBuffer( Footer, SizeOf(Footer) ); if Footer.Signature <> Ab_ZipEndCentralDirectorySignature then raise EAbZipInvalid.Create; FDiskNumber := Footer.DiskNumber; FStartDiskNumber := Footer.StartDiskNumber; FEntriesOnDisk := Footer.EntriesOnDisk; FTotalEntries := Footer.TotalEntries; FDirectorySize := Footer.DirectorySize; FDirectoryOffset := Footer.DirectoryOffset; SetLength( FZipfileComment, Footer.CommentLength ); if Footer.CommentLength > 0 then Stream.ReadBuffer( FZipfileComment[1], Footer.CommentLength ); end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileFooter.LoadZip64FromStream( Stream : TStream ); {load the ZIP64 end of central directory record. LoadFromStream() must be called first to load the standard record} var Footer: TAbZip64EndOfCentralDirectoryRecord; begin Stream.ReadBuffer( Footer, SizeOf(Footer) ); if Footer.Signature <> Ab_Zip64EndCentralDirectorySignature then raise EAbZipInvalid.Create; if FDiskNumber = $FFFF then FDiskNumber := Footer.DiskNumber; if FStartDiskNumber = $FFFF then FStartDiskNumber := Footer.StartDiskNumber; if FEntriesOnDisk = $FFFF then FEntriesOnDisk := Footer.EntriesOnDisk; if FTotalEntries = $FFFF then FTotalEntries := Footer.TotalEntries; if FDirectorySize = $FFFFFFFF then FDirectorySize := Footer.DirectorySize; if FDirectoryOffset = $FFFFFFFF then FDirectoryOffset := Footer.DirectoryOffset; {RecordSize, VersionMadeBy, and VersionNeededToExtract are currently ignored} end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileFooter.SaveToStream( Stream : TStream; aZip64TailOffset: Int64 = -1); {write end of central directory record, along with Zip64 records if necessary. aZip64TailOffset is the value to use for the Zip64 locator's directory offset, and is only necessary when writing to an intermediate stream} var Footer: TAbZipEndOfCentralDirectoryRecord; Zip64Footer: TAbZip64EndOfCentralDirectoryRecord; Zip64Locator: TAbZip64EndOfCentralDirectoryLocator; begin if IsZip64 then begin {setup Zip64 end of central directory record} Zip64Footer.Signature := Ab_Zip64EndCentralDirectorySignature; Zip64Footer.RecordSize := SizeOf(Zip64Footer) - SizeOf(Zip64Footer.Signature) - SizeOf(Zip64Footer.RecordSize); Zip64Footer.VersionMadeBy := 45; Zip64Footer.VersionNeededToExtract := 45; Zip64Footer.DiskNumber := DiskNumber; Zip64Footer.StartDiskNumber := StartDiskNumber; Zip64Footer.EntriesOnDisk := EntriesOnDisk; Zip64Footer.TotalEntries := TotalEntries; Zip64Footer.DirectorySize := DirectorySize; Zip64Footer.DirectoryOffset := DirectoryOffset; {setup Zip64 end of central directory locator} Zip64Locator.Signature := Ab_Zip64EndCentralDirectoryLocatorSignature; Zip64Locator.StartDiskNumber := DiskNumber; if aZip64TailOffset = -1 then Zip64Locator.RelativeOffset := Stream.Position else Zip64Locator.RelativeOffset := aZip64TailOffset; Zip64Locator.TotalDisks := DiskNumber + 1; {write Zip64 records} Stream.WriteBuffer(Zip64Footer, SizeOf(Zip64Footer)); Stream.WriteBuffer(Zip64Locator, SizeOf(Zip64Locator)); end; Footer.Signature := Ab_ZipEndCentralDirectorySignature; Footer.DiskNumber := Min(FDiskNumber, $FFFF); Footer.StartDiskNumber := Min(FStartDiskNumber, $FFFF); Footer.EntriesOnDisk := Min(FEntriesOnDisk, $FFFF); Footer.TotalEntries := Min(FTotalEntries, $FFFF); Footer.DirectorySize := Min(FDirectorySize, $FFFFFFFF); Footer.DirectoryOffset := Min(FDirectoryOffset, $FFFFFFFF); Footer.CommentLength := Length( FZipfileComment ); Stream.WriteBuffer( Footer, SizeOf(Footer) ); if FZipfileComment <> '' then Stream.Write( FZipfileComment[1], Length(FZipfileComment) ); end; { -------------------------------------------------------------------------- } { TAbZipItem implementation ================================================ } constructor TAbZipItem.Create; begin inherited Create; FItemInfo := TAbZipDirectoryFileHeader.Create; FLFHExtraField := TAbExtraField.Create; end; { -------------------------------------------------------------------------- } destructor TAbZipItem.Destroy; begin FLFHExtraField.Free; FItemInfo.Free; FItemInfo := nil; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetCompressionMethod : TAbZipCompressionMethod; begin Result := FItemInfo.CompressionMethod; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetCompressionRatio : Double; begin Result := FItemInfo.CompressionRatio; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetCRC32 : Longint; begin Result := FItemInfo.CRC32; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetDeflationOption : TAbZipDeflationOption; begin Result := FItemInfo.DeflationOption; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetDictionarySize : TAbZipDictionarySize; begin Result := FItemInfo.DictionarySize; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetGeneralPurposeBitFlag : Word; begin Result := FItemInfo.GeneralPurposeBitFlag; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetHostOS: TAbZipHostOS; begin Result := TAbZipHostOS(Hi(VersionMadeBy)); end; { -------------------------------------------------------------------------- } function TAbZipItem.GetExternalFileAttributes : LongWord; begin Result := FItemInfo.ExternalFileAttributes; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetExtraField : TAbExtraField; begin Result := FItemInfo.ExtraField; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetFileComment : AnsiString; begin Result := FItemInfo.FileComment; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetInternalFileAttributes : Word; begin Result := FItemInfo.InternalFileAttributes; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetIsDirectory: Boolean; begin Result := ((ExternalFileAttributes and faDirectory) <> 0) or ((FileName <> '') and CharInSet(Filename[Length(FFilename)], ['\','/'])); end; { -------------------------------------------------------------------------- } function TAbZipItem.GetIsEncrypted : Boolean; begin Result := FItemInfo.IsEncrypted; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetLastModFileDate : Word; begin Result := FItemInfo.LastModFileDate; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetLastModFileTime : Word; begin Result := FItemInfo.LastModFileTime; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetNativeFileAttributes : LongInt; begin {$IFDEF MSWINDOWS} if (HostOS = hosUnix) or (ExternalFileAttributes > $1FFFF) then Result := AbUnix2DosFileAttributes(ExternalFileAttributes shr 16) else Result := Byte(ExternalFileAttributes); {$ENDIF} {$IFDEF UNIX} if HostOS in [hosDOS, hosOS2, hosNTFS, hosWinNT, hosVFAT] then Result := AbDOS2UnixFileAttributes(ExternalFileAttributes) else begin Result := ExternalFileAttributes shr 16; if Result = 0 then begin Result:= AB_FPERMISSION_GENERIC; if GetIsDirectory then begin Result := Result or AB_FMODE_DIR or AB_FPERMISSION_OWNEREXECUTE; end; end; end; {$ENDIF} end; { -------------------------------------------------------------------------- } function TAbZipItem.GetRawFileName : AnsiString; begin Result := FItemInfo.FileName; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetNativeLastModFileTime: Longint; {$IFDEF UNIX} var DateTime: TDateTime; {$ENDIF} begin // Zip stores MS-DOS date/time. {$IFDEF UNIX} if (FDateTime <> 0) then DateTime := FDateTime else begin DateTime := AbDosFileDateToDateTime(LastModFileDate, LastModFileTime); end; Result := DateTimeToUnixFileTime(DateTime); {$ELSE} if (FDateTime <> 0) then Result := DateTimeToDosFileTime(FDateTime) else begin LongRec(Result).Hi := LastModFileDate; LongRec(Result).Lo := LastModFileTime; end; {$ENDIF} end; { -------------------------------------------------------------------------- } function TAbZipItem.GetLastModTimeAsDateTime: TDateTime; begin if (FDateTime <> 0) then Result := FDateTime else Result := AbDosFileDateToDateTime(FItemInfo.LastModFileDate, FItemInfo.LastModFileTime); end; { -------------------------------------------------------------------------- } function TAbZipItem.GetShannonFanoTreeCount : Byte; begin Result := FItemInfo.ShannonFanoTreeCount; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetVersionMadeBy : Word; begin Result := FItemInfo.VersionMadeBy; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetVersionNeededToExtract : Word; begin Result := FItemInfo.VersionNeededToExtract; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.LoadFromStream( Stream : TStream ); var Tag, TagSize, FieldSize: Word; FieldStream: TStream; InfoZipField: PInfoZipUnicodePathRec; UnicodeName: UnicodeString; UTF8Name: AnsiString; XceedField: PXceedUnicodePathRec; SystemCode: TAbZipHostOs; begin FItemInfo.LoadFromStream( Stream ); { decode filename (ANSI/OEM/UTF-8) } if FItemInfo.IsUTF8 and (FindInvalidUTF8Codepoint(PAnsiChar(FItemInfo.FileName), Length(FItemInfo.FileName)) < 0) then FFileName := FItemInfo.FileName else if FItemInfo.ExtraField.Get(Ab_InfoZipUnicodePathSubfieldID, Pointer(InfoZipField), FieldSize) and (FieldSize > SizeOf(TInfoZipUnicodePathRec)) and (InfoZipField.Version = 1) and (InfoZipField.NameCRC32 = AbCRC32Of(FItemInfo.FileName)) then begin SetString(UTF8Name, InfoZipField.UnicodeName, FieldSize - SizeOf(TInfoZipUnicodePathRec) + 1); FFileName := UTF8Name; end else if FItemInfo.ExtraField.Get(Ab_XceedUnicodePathSubfieldID, Pointer(XceedField), FieldSize) and (FieldSize > SizeOf(TXceedUnicodePathRec)) and (XceedField.Signature = Ab_XceedUnicodePathSignature) and (XceedField.Length * SizeOf(WideChar) = FieldSize - SizeOf(TXceedUnicodePathRec) + SizeOf(WideChar)) then begin SetString(UnicodeName, XceedField.UnicodeName, XceedField.Length); FFileName := Utf16ToUtf8(UnicodeName); end else begin SystemCode := HostOS; if (SystemCode = hosDOS) then FFileName := CeOemToUtf8(FItemInfo.FileName) else if (SystemCode = hosNTFS) or (SystemCode = hosWinNT) then FFileName := CeAnsiToUtf8(FItemInfo.FileName) else FFileName := CeSysToUtf8(FItemInfo.FileName); end; { read ZIP64 extended header } FUncompressedSize := FItemInfo.UncompressedSize; FCompressedSize := FItemInfo.CompressedSize; FRelativeOffset := FItemInfo.RelativeOffset; FDiskNumberStart := FItemInfo.DiskNumberStart; if FItemInfo.ExtraField.GetStream(Ab_Zip64SubfieldID, FieldStream) then try if FItemInfo.UncompressedSize = $FFFFFFFF then FieldStream.ReadBuffer(FUncompressedSize, SizeOf(Int64)); if FItemInfo.CompressedSize = $FFFFFFFF then FieldStream.ReadBuffer(FCompressedSize, SizeOf(Int64)); if FItemInfo.RelativeOffset = $FFFFFFFF then FieldStream.ReadBuffer(FRelativeOffset, SizeOf(Int64)); if FItemInfo.DiskNumberStart = $FFFF then FieldStream.ReadBuffer(FDiskNumberStart, SizeOf(LongWord)); finally FieldStream.Free; end; LastModFileTime := FItemInfo.LastModFileTime; LastModFileDate := FItemInfo.LastModFileDate; // NTFS Extra Field if FItemInfo.ExtraField.GetStream(Ab_NTFSSubfieldID, FieldStream) then try FieldSize:= FieldStream.Size; if (FieldSize >= 32) then begin // Skip Reserved Dec(FieldSize, 4); FieldStream.Seek(4, soBeginning); while (FieldSize > 4) do begin Dec(FieldSize, 4); Tag:= FieldStream.ReadWord; TagSize:= FieldStream.ReadWord; TagSize:= Min(TagSize, FieldSize); if (Tag = $0001) and (TagSize >= 24) then begin FDateTime:= WinFileTimeToDateTime(TWinFileTime(FieldStream.ReadQWord)); Break; end; Dec(FieldSize, TagSize); end; end; finally FieldStream.Free; end // Extended Timestamp Extra Field else if FItemInfo.ExtraField.GetStream(Ab_InfoZipTimestampSubfieldID, FieldStream) then try FieldSize:= FieldStream.Size; if (FieldSize >= 5) then begin Tag:= FieldStream.ReadByte; if (Tag and $01 <> 0) then FDateTime:= UnixFileTimeToDateTime(TUnixFileTime(FieldStream.ReadDWord)); end; finally FieldStream.Free; end; FDiskFileName := FileName; AbUnfixName( FDiskFileName ); Action := aaNone; Tagged := False; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SaveLFHToStream( Stream : TStream ); var LFH : TAbZipLocalFileHeader; Zip64Field: TZip64LocalHeaderRec; begin LFH := TAbZipLocalFileHeader.Create; try LFH.VersionNeededToExtract := VersionNeededToExtract; LFH.GeneralPurposeBitFlag := GeneralPurposeBitFlag; LFH.CompressionMethod := CompressionMethod; LFH.LastModFileTime := LastModFileTime; LFH.LastModFileDate := LastModFileDate; LFH.CRC32 := CRC32; LFH.FileName := RawFileName; LFH.ExtraField.Assign(LFHExtraField); LFH.ExtraField.CloneFrom(ExtraField, Ab_InfoZipUnicodePathSubfieldID); LFH.ExtraField.CloneFrom(ExtraField, Ab_XceedUnicodePathSubfieldID); { Write ZIP64 local header when file size > 3 GB to speed up archive creation } if (UncompressedSize > $C0000000) then begin { setup sizes; unlike the central directory header, the ZIP64 local header needs to store both compressed and uncompressed sizes if either needs it } if (CompressedSize >= $FFFFFFFF) or (UncompressedSize >= $FFFFFFFF) then begin LFH.UncompressedSize := $FFFFFFFF; LFH.CompressedSize := $FFFFFFFF; end else begin LFH.UncompressedSize := UncompressedSize; LFH.CompressedSize := CompressedSize; end; Zip64Field.UncompressedSize := UncompressedSize; Zip64Field.CompressedSize := CompressedSize; LFH.ExtraField.Put(Ab_Zip64SubfieldID, Zip64Field, SizeOf(Zip64Field)); end else begin LFH.UncompressedSize := UncompressedSize; LFH.CompressedSize := CompressedSize; LFH.ExtraField.Delete(Ab_Zip64SubfieldID); end; LFH.SaveToStream( Stream ); finally LFH.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SaveCDHToStream( Stream : TStream ); {-Save a ZipCentralDirectorHeader entry to Stream} begin FItemInfo.SaveToStream( Stream ); end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SaveDDToStream( Stream : TStream ); var DD : TAbZipDataDescriptor; begin DD := TAbZipDataDescriptor.Create; try DD.CRC32 := CRC32; DD.CompressedSize := CompressedSize; DD.UncompressedSize := UncompressedSize; DD.SaveToStream( Stream ); finally DD.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetCompressedSize( const Value : Int64 ); begin FCompressedSize := Value; FItemInfo.CompressedSize := Min(Value, $FFFFFFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetCompressionMethod( Value : TAbZipCompressionMethod ); begin FItemInfo.CompressionMethod := Value; UpdateVersionNeededToExtract; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetCRC32( const Value : Longint ); begin FItemInfo.CRC32 := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetDiskNumberStart( Value : LongWord ); begin FDiskNumberStart := Value; FItemInfo.DiskNumberStart := Min(Value, $FFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetExternalFileAttributes( Value : LongWord ); begin FItemInfo.ExternalFileAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetFileComment(const Value : AnsiString ); begin FItemInfo.FileComment := Value; end; { -------------------------------------------------------------------------- } {$IFDEF KYLIX}{$IFOPT O+}{$DEFINE OPTIMIZATIONS_ON}{$O-}{$ENDIF}{$ENDIF} procedure TAbZipItem.SetFileName(const Value : string ); var {$IFDEF MSWINDOWS} AnsiName : AnsiString; UnicName : UnicodeString; {$ENDIF} UTF8Name : AnsiString; FieldSize : Word; I : Integer; InfoZipField : PInfoZipUnicodePathRec; UseExtraField: Boolean; begin inherited SetFileName(Value); {$IFDEF MSWINDOWS} FItemInfo.IsUTF8 := False; HostOS := hosDOS; UnicName := CeUtf8ToUtf16(Value); if CeTryEncode(UnicName, CP_OEMCP, False, AnsiName) then {no-op} else if (GetACP <> GetOEMCP) and CeTryEncode(UnicName, CP_ACP, False, AnsiName) then HostOS := hosWinNT else FItemInfo.IsUTF8 := True; if FItemInfo.IsUTF8 then FItemInfo.FileName := Value else FItemInfo.FileName := AnsiName; {$ENDIF} {$IFDEF UNIX} HostOS := hosUnix; FItemInfo.FileName := Value; FItemInfo.IsUTF8 := SystemEncodingUtf8; {$ENDIF} UseExtraField := False; if not FItemInfo.IsUTF8 then for i := 1 to Length(Value) do begin if Ord(Value[i]) > 127 then begin UseExtraField := True; Break; end; end; if UseExtraField then begin UTF8Name := Value; FieldSize := SizeOf(TInfoZipUnicodePathRec) + Length(UTF8Name) - 1; GetMem(InfoZipField, FieldSize); try InfoZipField.Version := 1; InfoZipField.NameCRC32 := AbCRC32Of(FItemInfo.FileName); Move(UTF8Name[1], InfoZipField.UnicodeName, Length(UTF8Name)); FItemInfo.ExtraField.Put(Ab_InfoZipUnicodePathSubfieldID, InfoZipField^, FieldSize); finally FreeMem(InfoZipField); end; end else FItemInfo.ExtraField.Delete(Ab_InfoZipUnicodePathSubfieldID); FItemInfo.ExtraField.Delete(Ab_XceedUnicodePathSubfieldID); end; {$IFDEF OPTIMIZATIONS_ON}{$O+}{$ENDIF} { -------------------------------------------------------------------------- } procedure TAbZipItem.SetGeneralPurposeBitFlag( Value : Word ); begin FItemInfo.GeneralPurposeBitFlag := Value; UpdateVersionNeededToExtract; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetHostOS( Value : TAbZipHostOS ); begin FItemInfo.VersionMadeBy := Low(FItemInfo.VersionMadeBy) or Word(Ord(Value)) shl 8; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetInternalFileAttributes( Value : Word ); begin FItemInfo.InternalFileAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetLastModFileDate( const Value : Word ); begin FItemInfo.LastModFileDate := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetLastModFileTime( const Value : Word ); begin FItemInfo.LastModFileTime := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetRelativeOffset( Value : Int64 ); begin FRelativeOffset := Value; FItemInfo.RelativeOffset := Min(Value, $FFFFFFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetUncompressedSize( const Value : Int64 ); begin FUncompressedSize := Value; FItemInfo.UncompressedSize:= Min(Value, $FFFFFFFF); UpdateZip64ExtraHeader; end; procedure TAbZipItem.SetLastModTimeAsDateTime(const Value: TDateTime); var DataSize: Word; ANtfsTime: PNtfsTimeField; AInfoZipTime: PInfoZipTimeField; begin inherited SetLastModTimeAsDateTime(Value); // Update time extra fields if FItemInfo.ExtraField.Get(Ab_NTFSSubfieldID, ANtfsTime, DataSize) then begin if (DataSize = SizeOf(TNtfsTimeField)) then begin if ANtfsTime^.Tag = $0001 then begin ANtfsTime^.Mtime := DateTimeToWinFileTime(Value); end; end; end else if FItemInfo.ExtraField.Get(Ab_InfoZipTimestampSubfieldID, AInfoZipTime, DataSize) then begin if (DataSize = SizeOf(TInfoZipTimeField)) then begin if (AInfoZipTime^.Tag and $01 <> 0) then begin AInfoZipTime^.Mtime := UInt32(DateTimeToUnixFileTime(Value)); end; end; end; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetVersionMadeBy( Value : Word ); begin FItemInfo.VersionMadeBy := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetVersionNeededToExtract( Value : Word ); begin FItemInfo.VersionNeededToExtract := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.UpdateVersionNeededToExtract; {calculates VersionNeededToExtract and VersionMadeBy based on used features} begin {According to AppNote.txt zipx compression methods should set the Version Needed To Extract to the AppNote version the method was introduced in (e.g., 6.3 for PPMd). Most utilities just set it to 2.0 and rely on the extractor detecting unsupported compression methods, since it's easier to add support for decompression methods without implementing the entire newer spec. } if ExtraField.Has(Ab_Zip64SubfieldID) then VersionNeededToExtract := 45 else if IsDirectory or IsEncrypted or not (CompressionMethod in [cmStored..cmImploded]) then VersionNeededToExtract := 20 else VersionNeededToExtract := 10; VersionMadeBy := (VersionMadeBy and $FF00) + Max(20, VersionNeededToExtract); end; { -------------------------------------------------------------------------- } procedure TAbZipItem.UpdateZip64ExtraHeader; var Changed: Boolean; FieldStream: TMemoryStream; begin FieldStream := TMemoryStream.Create; try if UncompressedSize >= $FFFFFFFF then FieldStream.WriteBuffer(FUncompressedSize, SizeOf(Int64)); if CompressedSize >= $FFFFFFFF then FieldStream.WriteBuffer(FCompressedSize, SizeOf(Int64)); if RelativeOffset >= $FFFFFFFF then FieldStream.WriteBuffer(FRelativeOffset, SizeOf(Int64)); if DiskNumberStart >= $FFFF then FieldStream.WriteBuffer(FDiskNumberStart, SizeOf(LongWord)); Changed := (FieldStream.Size > 0) <> ExtraField.Has(Ab_Zip64SubfieldID); if FieldStream.Size > 0 then ExtraField.Put(Ab_Zip64SubfieldID, FieldStream.Memory^, FieldStream.Size) else ExtraField.Delete(Ab_Zip64SubfieldID); if Changed then UpdateVersionNeededToExtract; finally FieldStream.Free; end; end; { -------------------------------------------------------------------------- } { TAbZipArchive implementation ============================================= } constructor TAbZipArchive.CreateFromStream( aStream : TStream; const ArchiveName : string ); begin inherited CreateFromStream( aStream, ArchiveName ); FCompressionMethodToUse := smBestMethod; FInfo := TAbZipDirectoryFileFooter.Create; StoreOptions := StoreOptions + [soStripDrive]; FDeflationOption := doNormal; FPasswordRetries := AbDefPasswordRetries; FTempDir := ''; SpanningThreshold := AbDefZipSpanningThreshold; end; { -------------------------------------------------------------------------- } destructor TAbZipArchive.Destroy; begin FInfo.Free; FInfo := nil; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbZipArchive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var FullSourceFileName, FullArchiveFileName: string; begin Result := TAbZipItem.Create; with TAbZipItem( Result ) do begin CompressionMethod := cmDeflated; GeneralPurposeBitFlag := 0; CompressedSize := 0; CRC32 := 0; RelativeOffset := 0; MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); if mbDirectoryExists(FullSourceFileName) then begin FullSourceFileName := IncludeTrailingPathDelimiter(FullSourceFileName); end; Result.FileName := FullArchiveFileName; Result.DiskFileName := FullSourceFileName; end; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoExtractHelper(Index : Integer; const NewName : string); begin if Assigned(FExtractHelper) then FExtractHelper(Self, ItemList[Index], NewName) else raise EAbZipNoExtraction.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoExtractToStreamHelper(Index : Integer; aStream : TStream); begin if Assigned(FExtractToStreamHelper) then FExtractToStreamHelper(Self, ItemList[Index], aStream) else raise EAbZipNoExtraction.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoTestHelper(Index : Integer); begin if Assigned(FTestHelper) then FTestHelper(Self, ItemList[Index]) else raise EAbZipNoExtraction.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoInsertHelper(Index : Integer; OutStream : TStream); begin if Assigned(FInsertHelper) then FInsertHelper(Self, ItemList[Index], OutStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoInsertFromStreamHelper(Index : Integer; OutStream : TStream); begin if Assigned(FInsertFromStreamHelper) then FInsertFromStreamHelper(Self, ItemList[Index], OutStream, InStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestDisk(const AMessage: string; var Abort : Boolean); begin {$IFDEF MSWINDOWS} Abort := Windows.MessageBox( 0, PChar(AMessage), PChar(AbDiskRequestS), MB_TASKMODAL or MB_OKCANCEL ) = IDCANCEL; {$ENDIF} {$IFDEF UnixDialogs} {$IFDEF KYLIX} Abort := QDialogs.MessageDlg(AbDiskRequestS, AMessage, mtWarning, mbOKCancel, 0) = mrCancel; {$ENDIF} {$IFDEF LCL} Abort := Dialogs.MessageDlg(AbDiskRequestS, AMessage, mtWarning, mbOKCancel, 0) = mrCancel; {$ENDIF} {$ELSE} Abort := True; {$ENDIF} end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestLastDisk( var Abort : Boolean ); begin Abort := False; if Assigned( FOnRequestLastDisk ) then FOnRequestLastDisk( Self, Abort ) else DoRequestDisk( AbLastDiskRequestS, Abort ); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestNthDisk( Sender: TObject; DiskNumber : Byte; var Abort : Boolean ); begin Abort := False; if Assigned( FOnRequestNthDisk ) then FOnRequestNthDisk( Self, DiskNumber, Abort ) else DoRequestDisk( Format(AbDiskNumRequestS, [DiskNumber]), Abort ); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestBlankDisk(Sender: TObject; var Abort : Boolean ); begin Abort := False; FSpanned := True; if Assigned( FOnRequestBlankDisk ) then FOnRequestBlankDisk( Self, Abort ) else DoRequestDisk( AbBlankDiskS, Abort ); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestImage(Sender: TObject; ImageNumber : Integer; var ImageName : string ; var Abort : Boolean); begin if Assigned(FOnRequestImage) then FOnRequestImage(Self, ImageNumber, ImageName, Abort); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.ExtractItemAt(Index : Integer; const UseName : string); begin DoExtractHelper(Index, UseName); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.ExtractItemToStreamAt(Index : Integer; aStream : TStream); begin DoExtractToStreamHelper(Index, aStream); end; { -------------------------------------------------------------------------- } function TAbZipArchive.FixName(const Value : string ) : string; {-changes backslashes to forward slashes} var i : SmallInt; lValue : string; begin lValue := Value; {$IFDEF MSWINDOWS} if DOSMode then begin {Add the base directory to the filename before converting } {the file spec to the short filespec format. } if BaseDirectory <> '' then begin {Does the filename contain a drive or a leading backslash? } if not ((Pos(':', lValue) = 2) or (Pos(AbPathDelim, lValue) = 1)) then {If not, add the BaseDirectory to the filename.} lValue := AbAddBackSlash(BaseDirectory) + lValue; end; lValue := AbGetShortFileSpec( lValue ); end; {$ENDIF MSWINDOWS} {Zip files Always strip the drive path} StoreOptions := StoreOptions + [soStripDrive]; {strip drive stuff} if soStripDrive in StoreOptions then AbStripDrive( lValue ); {check for a leading backslash} if (Length(lValue) > 1) and (lValue[1] = AbPathDelim) then System.Delete( lValue, 1, 1 ); if soStripPath in StoreOptions then begin lValue := ExtractFileName( lValue ); end; if soRemoveDots in StoreOptions then AbStripDots( lValue ); for i := 1 to Length( lValue ) do if lValue[i] = AbDosPathDelim then lValue[i] := AbUnixPathDelim; Result := lValue; end; { -------------------------------------------------------------------------- } function TAbZipArchive.GetItem( Index : Integer ) : TAbZipItem; begin Result := TAbZipItem(FItemList.Items[Index]); end; { -------------------------------------------------------------------------- } function TAbZipArchive.GetSupportsEmptyFolders: Boolean; begin Result := True; end; { -------------------------------------------------------------------------- } function TAbZipArchive.GetZipfileComment : AnsiString; begin Result := FInfo.ZipfileComment; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.LoadArchive; var Abort : Boolean; TailPosition : int64; Item : TAbZipItem; Progress : Byte; FileSignature : Longint; Zip64Locator : TAbZip64EndOfCentralDirectoryLocator; begin Abort := False; if FStream.Size = 0 then Exit; {Get signature info} FStream.Position := 0; FStream.Read( FileSignature, sizeof( FileSignature ) ); {Get Executable Type; allow non-native stubs} IsExecutable := (LongRec(FileSignature).Lo = Ab_WindowsExeSignature) or (FileSignature = Ab_LinuxExeSignature); { try to locate central directory tail } TailPosition := FindCentralDirectoryTail( FStream ); if (TailPosition = -1) and (FileSignature = Ab_ZipSpannedSetSignature) and FOwnsStream and AbDriveIsRemovable(ArchiveName) then begin while TailPosition = -1 do begin FreeAndNil(FStream); DoRequestLastDisk(Abort); if Abort then begin FStatus := asInvalid; //TODO: Status updates are extremely inconsistent raise EAbUserAbort.Create; end; FStream := TFileStreamEx.Create( ArchiveName, Mode ); TailPosition := FindCentralDirectoryTail( FStream ); end; end; if TailPosition = -1 then begin FStatus := asInvalid; raise EAbZipInvalid.Create; end; { load the ZipDirectoryFileFooter } FInfo.LoadFromStream(FStream); { find Zip64 end of central directory locator; it will usually occur immediately before the standard end of central directory record. the actual Zip64 end of central directory may be on another disk } if FInfo.IsZip64 then begin Dec(TailPosition, SizeOf(Zip64Locator)); repeat if TailPosition < 0 then raise EAbZipInvalid.Create; FStream.Position := TailPosition; FStream.ReadBuffer(Zip64Locator, SizeOf(Zip64Locator)); Dec(TailPosition); until Zip64Locator.Signature = Ab_Zip64EndCentralDirectoryLocatorSignature; { update current image number } FInfo.DiskNumber := Zip64Locator.TotalDisks - 1; end; { setup spanning support and move to the start of the central directory } FSpanned := FInfo.DiskNumber > 0; if FSpanned then begin if FOwnsStream then begin FStream := TAbSpanReadStream.Create( ArchiveName, FInfo.DiskNumber, FStream ); TAbSpanReadStream(FStream).OnRequestImage := DoRequestImage; TAbSpanReadStream(FStream).OnRequestNthDisk := DoRequestNthDisk; if FInfo.IsZip64 then begin TAbSpanReadStream(FStream).SeekImage(Zip64Locator.StartDiskNumber, Zip64Locator.RelativeOffset); FInfo.LoadZip64FromStream(FStream); end; TAbSpanReadStream(FStream).SeekImage(FInfo.StartDiskNumber, FInfo.DirectoryOffset); end else raise EAbZipBadSpanStream.Create; end else begin if FInfo.IsZip64 then begin FStream.Position := Zip64Locator.RelativeOffset; FInfo.LoadZip64FromStream(FStream); end; FStream.Position := FInfo.DirectoryOffset; end; { build Items list from central directory records } FStubSize := High(LongWord); while Count < FInfo.TotalEntries do begin { create new Item } Item := TAbZipItem.Create; try Item.LoadFromStream(FStream); Item.Action := aaNone; FItemList.Add(Item); except Item.Free; raise; end; if IsExecutable and (Item.DiskNumberStart = 0) and (Item.RelativeOffset < FStubSize) then FStubSize := Item.RelativeOffset; Progress := (Count * 100) div FInfo.TotalEntries; DoArchiveProgress( Progress, Abort ); if Abort then begin FStatus := asInvalid; raise EAbUserAbort.Create; end; end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.PutItem( Index : Integer; Value : TAbZipItem ); begin FItemList.Items[Index] := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.SaveArchive; {builds a new archive and copies it to FStream} var APos : Int64; Abort : Boolean; MemStream : TMemoryStream; HasDataDescriptor : Boolean; i : LongWord; LFH : TAbZipLocalFileHeader; NewStream : TStream; WorkingStream : TAbVirtualMemoryStream; CurrItem : TAbZipItem; Progress : Byte; ATempName : String; CreateArchive : Boolean; begin if Count = 0 then Exit; {shouldn't be trying to overwrite an existing spanned archive} if Spanned then begin for i := 0 to Pred(Count) do if ItemList[i].Action <> aaFailed then ItemList[i].Action := aaNone; FIsDirty := False; raise EAbZipSpanOverwrite.Create; end; {init new zip archive stream can span only new archives, if SpanningThreshold > 0 or removable drive spanning writes to original location, rather than writing to a temp stream first} if FOwnsStream and (FStream.Size = 0) and not IsExecutable and ((SpanningThreshold > 0) or AbDriveIsRemovable(ArchiveName)) then begin NewStream := TAbSpanWriteStream.Create(ArchiveName, FStream, SpanningThreshold); FStream := nil; TAbSpanWriteStream(NewStream).OnRequestBlankDisk := DoRequestBlankDisk; TAbSpanWriteStream(NewStream).OnRequestImage := DoRequestImage; end else begin CreateArchive:= FOwnsStream and (FStream.Size = 0) and (FStream is TFileStreamEx); if CreateArchive then NewStream := FStream else begin ATempName := GetTempName(FArchiveName); NewStream := TFileStreamEx.Create(ATempName, fmCreate or fmShareDenyWrite); end; end; try {NewStream} {copy the executable stub over to the output} if IsExecutable then NewStream.CopyFrom( FStream, StubSize ) {assume spanned for spanning stream} else if NewStream is TAbSpanWriteStream then NewStream.Write(Ab_ZipSpannedSetSignature, SizeOf(Ab_ZipSpannedSetSignature)); {build new zip archive from existing archive} for i := 0 to pred( Count ) do begin CurrItem := (ItemList[i] as TAbZipItem); FCurrentItem := ItemList[i]; case CurrItem.Action of aaNone, aaMove: begin {just copy the file to new stream} Assert(not (NewStream is TAbSpanWriteStream)); FStream.Position := CurrItem.RelativeOffset; CurrItem.DiskNumberStart := 0; CurrItem.RelativeOffset := NewStream.Position; {toss old local file header} LFH := TAbZipLocalFileHeader.Create; try {LFH} LFH.LoadFromStream( FStream ); if CurrItem.LFHExtraField.Count = 0 then CurrItem.LFHExtraField.Assign(LFH.ExtraField); finally {LFH} LFH.Free; end; {LFH} {write out new local file header and append compressed data} CurrItem.SaveLFHToStream( NewStream ); if (CurrItem.CompressedSize > 0) then NewStream.CopyFrom(FStream, CurrItem.CompressedSize); end; aaDelete: begin {doing nothing omits file from new stream} end; aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin {compress the file and add it to new stream} try if NewStream is TAbSpanWriteStream then begin WorkingStream := TAbVirtualMemoryStream.Create; try {WorkingStream} WorkingStream.SwapFileDirectory := FTempDir; {compress the file} if (CurrItem.Action = aaStreamAdd) then DoInsertFromStreamHelper(i, WorkingStream) else begin DoInsertHelper(i, WorkingStream); end; {write local header} MemStream := TMemoryStream.Create; try CurrItem.SaveLFHToStream(MemStream); TAbSpanWriteStream(NewStream).WriteUnspanned( MemStream.Memory^, MemStream.Size); {calculate positions after the write in case it triggered a new span} CurrItem.DiskNumberStart := TAbSpanWriteStream(NewStream).CurrentImage; CurrItem.RelativeOffset := NewStream.Position - MemStream.Size; finally MemStream.Free; end; {copy compressed data} NewStream.CopyFrom(WorkingStream, 0); finally WorkingStream.Free; end; end else begin {write local header} CurrItem.DiskNumberStart := 0; CurrItem.RelativeOffset := NewStream.Position; CurrItem.UncompressedSize := mbFileSize(CurrItem.DiskFileName); CurrItem.SaveLFHToStream(NewStream); {compress the file} if (CurrItem.Action = aaStreamAdd) then DoInsertFromStreamHelper(i, NewStream) else begin DoInsertHelper(i, NewStream); end; {update local header} APos:= NewStream.Position; NewStream.Seek(CurrItem.RelativeOffset, soBeginning); CurrItem.SaveLFHToStream(NewStream); NewStream.Seek(APos, soBeginning); end; if CurrItem.IsEncrypted then CurrItem.SaveDDToStream(NewStream); except on E : Exception do begin { Exception was caused by a User Abort and Item Failure should not be called Question: Do we want an New Event when this occurs or should the exception just be re-raised [783614] } if (E is EAbUserAbort) then raise; CurrItem.Action := aaDelete; DoProcessItemFailure(CurrItem, ptAdd, ecFileOpenError, 0); end; end; end; end; { case } { TODO: Check HasDataDescriptior behavior; seems like it's getting written twice for encrypted files } {Now add the data descriptor record to new stream} HasDataDescriptor := (CurrItem.CompressionMethod = cmDeflated) and ((CurrItem.GeneralPurposeBitFlag and AbHasDataDescriptorFlag) <> 0); if (CurrItem.Action <> aaDelete) and HasDataDescriptor then CurrItem.SaveDDToStream(NewStream); Progress := AbPercentage(9 * succ( i ), 10 * Count); DoArchiveSaveProgress(Progress, Abort); DoArchiveProgress(Progress, Abort); if Abort then raise EAbUserAbort.Create; end; {write the central directory} if NewStream is TAbSpanWriteStream then FInfo.DiskNumber := TAbSpanWriteStream(NewStream).CurrentImage else FInfo.DiskNumber := 0; FInfo.StartDiskNumber := FInfo.DiskNumber; FInfo.DirectoryOffset := NewStream.Position; FInfo.DirectorySize := 0; FInfo.EntriesOnDisk := 0; FInfo.TotalEntries := 0; MemStream := TMemoryStream.Create; try {write central directory entries} for i := 0 to Count - 1 do begin if not (FItemList[i].Action in [aaDelete, aaFailed]) then begin (FItemList[i] as TAbZipItem).SaveCDHToStream(MemStream); if NewStream is TAbSpanWriteStream then begin TAbSpanWriteStream(NewStream).WriteUnspanned(MemStream.Memory^, MemStream.Size); {update tail info on span change} if FInfo.DiskNumber <> TAbSpanWriteStream(NewStream).CurrentImage then begin FInfo.DiskNumber := TAbSpanWriteStream(NewStream).CurrentImage; FInfo.EntriesOnDisk := 0; if FInfo.TotalEntries = 0 then begin FInfo.StartDiskNumber := FInfo.DiskNumber; FInfo.DirectoryOffset := NewStream.Position - MemStream.Size; end; end; end else NewStream.WriteBuffer(MemStream.Memory^, MemStream.Size); FInfo.DirectorySize := FInfo.DirectorySize + MemStream.Size; FInfo.EntriesOnDisk := FInfo.EntriesOnDisk + 1; FInfo.TotalEntries := FInfo.TotalEntries + 1; MemStream.Clear; end; end; {append the central directory footer} FInfo.SaveToStream(MemStream, NewStream.Position); if NewStream is TAbSpanWriteStream then begin {update the footer if writing it would trigger a new span} if not TAbSpanWriteStream(NewStream).WriteUnspanned(MemStream.Memory^, MemStream.Size) then begin FInfo.DiskNumber := TAbSpanWriteStream(NewStream).CurrentImage; FInfo.EntriesOnDisk := 0; FInfo.SaveToStream(NewStream); end; end else NewStream.WriteBuffer(MemStream.Memory^, MemStream.Size); finally {MemStream} MemStream.Free; end; {MemStream} FSpanned := (FInfo.DiskNumber > 0); {update output stream} if NewStream is TAbSpanWriteStream then begin {zip has already been written to target location} FStream := TAbSpanWriteStream(NewStream).ReleaseStream; if Spanned then begin {switch to read stream} FStream := TAbSpanReadStream.Create(ArchiveName, FInfo.DiskNumber, FStream); TAbSpanReadStream(FStream).OnRequestImage := DoRequestImage; TAbSpanReadStream(FStream).OnRequestNthDisk := DoRequestNthDisk; end else begin {replace spanned signature} FStream.Position := 0; FStream.Write(Ab_ZipPossiblySpannedSignature, SizeOf(Ab_ZipPossiblySpannedSignature)); end; end else begin {copy new stream to FStream (non-spanned only)} NewStream.Position := 0; if (FStream is TMemoryStream) then TMemoryStream(FStream).LoadFromStream(NewStream) else begin if FOwnsStream then begin {need new stream to write} if CreateArchive then NewStream := nil else begin FreeAndNil(FStream); FreeAndNil(NewStream); if (mbDeleteFile(FArchiveName) and mbRenameFile(ATempName, FArchiveName)) then FStream := TFileStreamEx.Create(FArchiveName, fmOpenReadWrite or fmShareDenyWrite) else RaiseLastOSError; end; end else begin FStream.Size := 0; FStream.Position := 0; FStream.CopyFrom(NewStream, 0) end; end; end; {update Items list} for i := pred( Count ) downto 0 do begin if FItemList[i].Action = aaDelete then FItemList.Delete( i ) else if FItemList[i].Action <> aaFailed then FItemList[i].Action := aaNone; end; DoArchiveSaveProgress( 100, Abort ); DoArchiveProgress( 100, Abort ); finally {NewStream} if (FStream <> NewStream) then NewStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.SetZipfileComment(const Value : AnsiString ); begin FInfo.FZipfileComment := Value; FIsDirty := True; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.TestItemAt(Index : Integer); begin DoTestHelper(Index); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzipxprc.pas����������������������������������������0000644�0001750�0000144�00000010063�14743153644�023137� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Compress item to .zipx archive * * Copyright (C) 2015-2023 Alexander Koblov (alexx2000@mail.ru) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * ***** END LICENSE BLOCK ***** *) {**********************************************************} {* ABBREVIA: AbZipxPrc.pas *} {**********************************************************} {* ABBREVIA: TZipHashStream class *} {**********************************************************} unit AbZipxPrc; {$mode delphi} interface uses Classes, SysUtils, BufStream, AbZipTyp, AbArcTyp; type { TZipHashStream } TZipHashStream = class(TReadBufStream) private FSize: Int64; FHash: UInt32; FOnProgress: TAbProgressEvent; public constructor Create(ASource : TStream); reintroduce; function Read(var ABuffer; ACount : LongInt) : Integer; override; property OnProgress : TAbProgressEvent read FOnProgress write FOnProgress; property Hash: UInt32 read FHash; end; procedure DoCompressXz(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); procedure DoCompressZstd(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); implementation uses AbXz, AbZstd, AbExcept, DCcrc32; procedure DoCompressXz(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var ASource: TZipHashStream; CompStream: TXzCompressionStream; begin Item.CompressionMethod := cmXz; ASource := TZipHashStream.Create(InStream); try ASource.OnProgress := Archive.OnProgress; CompStream := TXzCompressionStream.Create(OutStream, Archive.CompressionLevel); try CompStream.CopyFrom(ASource, Item.UncompressedSize); finally CompStream.Free; end; Item.CRC32 := LongInt(ASource.Hash); finally ASource.Free; end; end; procedure DoCompressZstd(Archive: TAbZipArchive; Item: TAbZipItem; OutStream, InStream: TStream); var ASource: TZipHashStream; CompStream: TZSTDCompressionStream; begin Item.CompressionMethod := cmZstd; ASource := TZipHashStream.Create(InStream); try ASource.OnProgress := Archive.OnProgress; CompStream := TZSTDCompressionStream.Create(OutStream, Archive.CompressionLevel, Item.UncompressedSize); try CompStream.CopyFrom(ASource, Item.UncompressedSize); finally CompStream.Free; end; Item.CRC32 := LongInt(ASource.Hash); finally ASource.Free; end; end; { TZipHashStream } constructor TZipHashStream.Create(ASource: TStream); begin FSize := ASource.Size; inherited Create(ASource); end; function TZipHashStream.Read(var ABuffer; ACount: LongInt): Integer; var Abort: Boolean = False; begin Result := inherited Read(ABuffer, ACount); FHash := crc32_16bytes(@ABuffer, Result, FHash); if Assigned(FOnProgress) then begin FOnProgress(GetPosition * 100 div FSize, Abort); if Abort then raise EAbUserAbort.Create; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzlibprc.pas����������������������������������������0000644�0001750�0000144�00000011216�14743153644�023106� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit AbZlibPrc; {$mode objfpc}{$H+} interface uses Classes, SysUtils, ZStream, AbDfBase; type { TDeflateStream } TDeflateStream = class(TCompressionStream) private FSize: Int64; FHash: UInt32; FOnProgressStep: TAbProgressStep; public constructor Create(ALevel: Integer; ADest: TStream); function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property Hash: UInt32 read FHash; end; { TInflateStream } TInflateStream = class(TDecompressionStream) private FHash: UInt32; public function CopyInto(ATarget: TStream; ACount: Int64): Int64; function Read(var Buffer; Count: LongInt): LongInt; override; end; function Deflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; function Inflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; implementation uses Math, ZDeflate, ZBase, DCcrc32; function Deflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper): longint; var ALevel: Integer; ADeflateStream: TDeflateStream; begin case aHelper.PKZipOption of 'n': ALevel:= 6; 'x': ALevel:= 9; 'f': ALevel:= 3; 's': ALevel:= 1; else ALevel:= Z_DEFAULT_COMPRESSION; end; { if the helper's stream size <= 0, calculate the stream size from the stream itself } if (aHelper.StreamSize <= 0) then aHelper.StreamSize := aSource.Size; ADeflateStream:= TDeflateStream.Create(ALevel, aDest); try ADeflateStream.FSize:= aHelper.StreamSize; { attach progress notification method } ADeflateStream.FOnProgressStep:= aHelper.OnProgressStep; ADeflateStream.CopyFrom(aSource, aHelper.StreamSize); { save the uncompressed and compressed sizes } aHelper.NormalSize:= ADeflateStream.raw_written; aHelper.CompressedSize:= ADeflateStream.compressed_written; { provide encryption check value } Result := LongInt(ADeflateStream.FHash); finally ADeflateStream.Free; end; end; function Inflate(aSource: TStream; aDest: TStream; aHelper: TAbDeflateHelper): longint; var ACount: Int64; AInflateStream: TInflateStream; begin AInflateStream:= TInflateStream.Create(aSource, True); try if aHelper.PartialSize > 0 then begin ACount:= aHelper.PartialSize; aHelper.NormalSize:= AInflateStream.CopyInto(aDest, ACount); end else begin ACount:= aHelper.NormalSize; aHelper.NormalSize:= aDest.CopyFrom(AInflateStream, ACount); end; aHelper.CompressedSize:= AInflateStream.compressed_read; Result:= LongInt(AInflateStream.FHash); finally AInflateStream.Free; end; end; { TInflateStream } function TInflateStream.CopyInto(ATarget: TStream; ACount: Int64): Int64; var ARead, ASize: Integer; ABuffer: array of Byte; begin Result:= 0; ASize:= Min(ACount, $8000); SetLength(ABuffer, ASize); repeat if ACount < ASize then begin ASize:= ACount; end; ARead:= Read(ABuffer[0], ASize); if ARead > 0 then begin Dec(ACount, ARead); Inc(Result, ARead); ATarget.WriteBuffer(ABuffer[0], ARead); end; until (ARead < ASize) or (ACount = 0); end; function TInflateStream.Read(var Buffer; Count: LongInt): LongInt; begin Result:= inherited Read(Buffer, Count); FHash:= crc32_16bytes(@Buffer, Result, FHash); if (Result < Count) and (Fstream.avail_in > 0) then begin FSource.Seek(-Fstream.avail_in, soCurrent); Fstream.avail_in:= 0; end; end; { TDeflateStream } constructor TDeflateStream.Create(ALevel: Integer; ADest: TStream); const BUF_SIZE = 16384; var AError: Integer; begin TOwnerStream(Self).Create(ADest); Fbuffer:= GetMem(BUF_SIZE); Fstream.next_out:= Fbuffer; Fstream.avail_out:= BUF_SIZE; AError:= deflateInit2(Fstream, ALevel, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); if AError <> Z_OK then raise Ecompressionerror.Create(zerror(AError)); end; function TDeflateStream.Write(const Buffer; Count: Longint): Longint; begin FHash:= crc32_16bytes(@Buffer, Count, FHash); Result:= inherited Write(Buffer, Count); if Assigned(FOnProgressStep) then begin FOnProgressStep(raw_written * 100 div FSize); end; end; function TDeflateStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Offset = 0) and (Origin = soCurrent) then Result:= raw_written else begin Result:= inherited Seek(Offset, Origin); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzstd.pas�������������������������������������������0000644�0001750�0000144�00000025474�14743153644�022440� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Simple interface to zstd library * * Copyright (C) 2019-2023 Alexander Koblov (alexx2000@mail.ru) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * ***** END LICENSE BLOCK ***** *) {**********************************************************************} {* ABBREVIA: AbZstd.pas *} {**********************************************************************} {* ABBREVIA: TZstdCompressionStream, TZstdDecompressionStream classes *} {**********************************************************************} unit AbZstd; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils, CTypes; const ZSTD_FRAMEHEADERSIZE_MAX = 18; ZSTD_CONTENTSIZE_UNKNOWN = UInt64(-1); ZSTD_CONTENTSIZE_ERROR = UInt64(-2); type PZSTD_CCtx = ^TZSTD_CCtx; TZSTD_CCtx = record end; PZSTD_DCtx = ^ZSTD_DCtx; ZSTD_DCtx = record end; PZSTD_inBuffer = ^ZSTD_inBuffer; ZSTD_inBuffer = record src: pcuint8; size: csize_t; pos: csize_t; end; PZSTD_outBuffer = ^ZSTD_outBuffer; ZSTD_outBuffer = record dst: pcuint8; size: csize_t; pos: csize_t; end; EZstdError = class(Exception); { TZstdCompressionStream } TZstdCompressionStream = class(TStream) private FStream: TStream; FContext: PZSTD_CCtx; FBufferOut: ZSTD_outBuffer; public constructor Create(OutStream: TStream; ALevel: Integer; InSize: UInt64 = ZSTD_CONTENTSIZE_UNKNOWN); destructor Destroy; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; { TZstdDecompressionStream } TZstdDecompressionStream = class(TStream) private FStream: TStream; FContext: PZSTD_DCtx; FBufferIn: ZSTD_inBuffer; FBufferInSize: UIntPtr; FBufferOut: ZSTD_outBuffer; FBufferOutPos: UIntPtr; public constructor Create(InStream: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; function ZSTD_FileSize(const InStream: TStream): UInt64; implementation uses DynLibs; const libzstd = {$IF DEFINED(MSWINDOWS)} 'libzstd.dll' {$ELSEIF DEFINED(DARWIN)} 'libzstd.dylib' {$ELSEIF DEFINED(UNIX)} 'libzstd.so.1' {$IFEND}; type ZSTD_cParameter = ( ZSTD_c_compressionLevel = 100, ZSTD_c_checksumFlag = 201 ); ZSTD_EndDirective = ( ZSTD_e_continue = 0, ZSTD_e_flush = 1, ZSTD_e_end = 2 ); var ZSTD_CStreamInSize: function(): csize_t; cdecl; ZSTD_CStreamOutSize: function(): csize_t; cdecl; ZSTD_createCCtx: function(): PZSTD_CCtx; cdecl; ZSTD_freeCCtx: function(cctx: PZSTD_CCtx): csize_t; cdecl; ZSTD_CCtx_setParameter: function(cctx: PZSTD_CCtx; param: ZSTD_cParameter; value: cint): csize_t; cdecl; ZSTD_compressStream2: function(cctx: PZSTD_CCtx; output: PZSTD_outBuffer; input: PZSTD_inBuffer; endOp: ZSTD_EndDirective): csize_t; cdecl; ZSTD_DStreamInSize: function(): csize_t; cdecl; ZSTD_DStreamOutSize: function(): csize_t; cdecl; ZSTD_createDCtx: function(): PZSTD_DCtx; cdecl; ZSTD_freeDCtx: function(dctx: PZSTD_DCtx): csize_t; cdecl; ZSTD_DCtx_setMaxWindowSize: function(dctx: PZSTD_DCtx; maxWindowSize: csize_t): csize_t; cdecl; ZSTD_decompressStream: function(zds: PZSTD_DCtx; output: PZSTD_outBuffer; input: PZSTD_inBuffer): csize_t; cdecl; ZSTD_isError: function(code: csize_t): cuint; cdecl; ZSTD_getErrorName: function(code: csize_t): PAnsiChar; cdecl; ZSTD_getFrameContentSize: function(src: pcuint8; srcSize: csize_t): cuint64; cdecl; ZSTD_CCtx_setPledgedSrcSize: function(cctx: PZSTD_CCtx; pledgedSrcSize: cuint64): csize_t; cdecl; var hZstd: TLibHandle = NilHandle; procedure Initialize; begin if hZstd <> NilHandle then Exit; hZstd:= LoadLibrary(libzstd); if hZstd = NilHandle then raise EZstdError.Create('Zstd shared library not found'); @ZSTD_CStreamInSize:= GetProcAddress(hZstd, 'ZSTD_CStreamInSize'); @ZSTD_CStreamOutSize:= GetProcAddress(hZstd, 'ZSTD_CStreamOutSize'); @ZSTD_createCCtx:= GetProcAddress(hZstd, 'ZSTD_createCCtx'); @ZSTD_freeCCtx:= GetProcAddress(hZstd, 'ZSTD_freeCCtx'); @ZSTD_CCtx_setParameter:= GetProcAddress(hZstd, 'ZSTD_CCtx_setParameter'); @ZSTD_compressStream2:= GetProcAddress(hZstd, 'ZSTD_compressStream2'); @ZSTD_DStreamInSize:= GetProcAddress(hZstd, 'ZSTD_DStreamInSize'); @ZSTD_DStreamOutSize:= GetProcAddress(hZstd, 'ZSTD_DStreamOutSize'); @ZSTD_createDCtx:= GetProcAddress(hZstd, 'ZSTD_createDCtx'); @ZSTD_freeDCtx:= GetProcAddress(hZstd, 'ZSTD_freeDCtx'); @ZSTD_DCtx_setMaxWindowSize:= GetProcAddress(hZstd, 'ZSTD_DCtx_setMaxWindowSize'); @ZSTD_decompressStream:= GetProcAddress(hZstd, 'ZSTD_decompressStream'); @ZSTD_isError:= GetProcAddress(hZstd, 'ZSTD_isError'); @ZSTD_getErrorName:= GetProcAddress(hZstd, 'ZSTD_getErrorName'); @ZSTD_getFrameContentSize:= GetProcAddress(hZstd, 'ZSTD_getFrameContentSize'); @ZSTD_CCtx_setPledgedSrcSize:= GetProcAddress(hZstd, 'ZSTD_CCtx_setPledgedSrcSize'); end; function ZSTD_Check(code: csize_t): csize_t; begin Result:= code; if (ZSTD_isError(code) <> 0) then raise EZstdError.Create(ZSTD_getErrorName(code)) end; function ZSTD_FileSize(const InStream: TStream): UInt64; var APosition: Int64; ABuffer: array[1..ZSTD_FRAMEHEADERSIZE_MAX] of Byte; begin Initialize; APosition:= InStream.Position; InStream.Seek(0, soBeginning); InStream.Read(ABuffer[1], ZSTD_FRAMEHEADERSIZE_MAX); InStream.Seek(APosition, soBeginning); Result:= ZSTD_getFrameContentSize(@ABuffer[1], ZSTD_FRAMEHEADERSIZE_MAX); if (Result = ZSTD_CONTENTSIZE_UNKNOWN) or (Result = ZSTD_CONTENTSIZE_ERROR) then Result:= 0; end; { TZstdDecompressionStream } constructor TZstdDecompressionStream.Create(InStream: TStream); const {$IFDEF CPU32} ZSTD_MAXWINDOWSIZE = (1 shl 30); {$ELSE} ZSTD_MAXWINDOWSIZE = (1 shl 31); {$ENDIF} begin Initialize; FStream:= InStream; FContext:= ZSTD_createDCtx(); FBufferInSize:= ZSTD_DStreamInSize(); FBufferIn.size := FBufferInSize; FBufferIn.pos:= FBufferInSize; FBufferIn.src:= GetMem(FBufferIn.size); FBufferOut.pos:= 0; FBufferOut.size := ZSTD_DStreamOutSize(); FBufferOut.dst:= GetMem(FBufferOut.size); ZSTD_Check(ZSTD_DCtx_setMaxWindowSize(FContext, ZSTD_MAXWINDOWSIZE)); end; destructor TZstdDecompressionStream.Destroy; begin if Assigned(FContext) then begin FreeMem(FBufferIn.src); FreeMem(FBufferOut.dst); ZSTD_freeDCtx(FContext); end; inherited Destroy; end; function TZstdDecompressionStream.Read(var Buffer; Count: Longint): Longint; var ABuffer: PByte; Available: Integer; begin Result:= 0; ABuffer:= @Buffer; while (Count > 0) do begin Available:= FBufferOut.pos - FBufferOutPos; if (Available > 0) then begin if Available > Count then Available:= Count; Move(FBufferOut.dst[FBufferOutPos], ABuffer^, Available); Inc(Result, Available); if (Available = Count) then begin Inc(FBufferOutPos, UIntPtr(Available)); Break; end; Inc(ABuffer, Available); Dec(Count, Available); end; if (FBufferIn.size > 0) and (FBufferIn.pos = FBufferIn.size) then begin FBufferIn.pos:= 0; FBufferIn.size:= FStream.Read(FBufferIn.src^, FBufferInSize); end; FBufferOutPos:= 0; FBufferOut.pos:= 0; ZSTD_Check(ZSTD_decompressStream(FContext, @FBufferOut, @FBufferIn)); if (FBufferOut.pos = 0) and (FBufferIn.size = 0) then Break; end; end; function TZstdDecompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin Result:= -1; end; { TZstdCompressionStream } constructor TZstdCompressionStream.Create(OutStream: TStream; ALevel: Integer; InSize: UInt64); begin Initialize; FStream:= OutStream; FContext:= ZSTD_createCCtx(); FBufferOut.size:= ZSTD_CStreamOutSize(); FBufferOut.dst:= GetMem(FBufferOut.size); ZSTD_CCtx_setPledgedSrcSize(FContext, InSize); ZSTD_Check(ZSTD_CCtx_setParameter(FContext, ZSTD_c_checksumFlag, 1)); ZSTD_Check(ZSTD_CCtx_setParameter(FContext, ZSTD_c_compressionLevel, ALevel)); end; destructor TZstdCompressionStream.Destroy; var ARemaining: csize_t; AInput: ZSTD_inBuffer; begin try if Assigned(FContext) then try FillChar({%H-}AInput, SizeOf(ZSTD_inBuffer), 0); repeat FBufferOut.pos:= 0; ARemaining:= ZSTD_Check(ZSTD_compressStream2(FContext, @FBufferOut, @AInput, ZSTD_e_end)); if (FBufferOut.pos > 0) then begin FStream.WriteBuffer(FBufferOut.dst^, FBufferOut.pos); end; until (ARemaining = 0); finally FreeMem(FBufferOut.dst); ZSTD_freeCCtx(FContext); end; finally inherited Destroy; end; end; function TZstdCompressionStream.Write(const Buffer; Count: Longint): Longint; var AInput: ZSTD_inBuffer; begin AInput.pos:= 0; AInput.src:= @Buffer; AInput.size:= Count; while AInput.pos < AInput.size do begin FBufferOut.pos:= 0; ZSTD_Check(ZSTD_compressStream2(FContext, @FBufferOut, @AInput, ZSTD_e_continue)); if (FBufferOut.pos > 0) then FStream.WriteBuffer(FBufferOut.dst^, FBufferOut.pos); end; Result:= AInput.pos; end; function TZstdCompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin Result:= -1; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/abzstdtyp.pas����������������������������������������0000644�0001750�0000144�00000036112�14743153644�023164� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Joel Haynie * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Alexander Koblov <alexx2000@users.sourceforge.net> * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZstdTyp.pas *} {*********************************************************} {* ABBREVIA: TAbZstdArchive, TAbZstdItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with zst files *} {*********************************************************} unit AbZstdTyp; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbTarTyp, AbUtils; const { The first for (4) bytes of the Stream are so called Header } { Magic Bytes. They can be used to identify the file type. } AB_ZSTD_FILE_HEADER = #$28#$B5#$2F#$FD; type PAbZstdHeader = ^TAbZstdHeader; { File Header } TAbZstdHeader = packed record { SizeOf(TAbZstdHeader) = 10 } MagicNumber : array[0..3] of AnsiChar;{ 28 B5 2F FD } end; { The Purpose for this Item is the placeholder for aaAdd and aaDelete Support. } { For all intents and purposes we could just use a TAbArchiveItem } type TAbZstdItem = class(TabArchiveItem); TAbZstdArchiveState = (gsZstd, gsTar); TAbZstdArchive = class(TAbTarArchive) private FZstdStream : TStream; { stream for Zstd file} FZstdItem : TAbArchiveList; { item in zstd (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbZstdArchiveState; FIsZstdTar : Boolean; procedure DecompressToStream(aStream: TStream); procedure SetTarAutoHandle(const Value: Boolean); procedure SwapToZstd; procedure SwapToTar; protected { Inherited Abstract functions } function CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function GetSupportsEmptyFolders : Boolean; override; public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; { Properties } property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsZstdTar : Boolean read FIsZstdTar write FIsZstdTar; end; function VerifyZstd(Strm : TStream) : TAbArchiveType; implementation uses SysUtils, BufStream, AbZstd, AbExcept, AbVMStrm, AbBitBkt, AbProgress, DCOSUtils, DCClassesUtf8; { ****************** Helper functions Not from Classes Above ***************** } function VerifyHeader(const Header : TAbZstdHeader) : Boolean; begin Result := CompareByte(Header.MagicNumber, AB_ZSTD_FILE_HEADER, SizeOf(Header.MagicNumber)) = 0; end; { -------------------------------------------------------------------------- } function VerifyZstd(Strm : TStream) : TAbArchiveType; var Hdr : TAbZstdHeader; CurPos, DecompSize : Int64; DecompStream, TarStream: TStream; Buffer: array[0..Pred(AB_TAR_RECORDSIZE * 4)] of Byte; begin Result := atUnknown; CurPos := Strm.Position; Strm.Seek(0, soBeginning); try if (Strm.Read(Hdr, SizeOf(Hdr)) = SizeOf(Hdr)) and VerifyHeader(Hdr) then begin Result := atZstd; { Check for embedded TAR } Strm.Seek(0, soBeginning); DecompStream := TZSTDDecompressionStream.Create(Strm); try TarStream := TMemoryStream.Create; try DecompSize:= DecompStream.Read(Buffer, SizeOf(Buffer)); TarStream.Write(Buffer, DecompSize); TarStream.Seek(0, soBeginning); if VerifyTar(TarStream) = atTar then Result := atZstdTar; finally TarStream.Free; end; finally DecompStream.Free; end; end; except on EReadError do Result := atUnknown; end; Strm.Position := CurPos; { Return to original position. } end; { ****************************** TAbZstdArchive ***************************** } constructor TAbZstdArchive.CreateFromStream(aStream: TStream; const aArchiveName: string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsZstd; FZstdStream := FStream; FZstdItem := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.SwapToZstd; begin FStream := FZstdStream; FItemList := FZstdItem; FState := gsZstd; end; { -------------------------------------------------------------------------- } function TAbZstdArchive.CreateItem(const SourceFileName : string; const ArchiveDirectory : string): TAbArchiveItem; var ZstdItem : TAbZstdItem; FullSourceFileName, FullArchiveFileName: String; begin if IsZstdTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(SourceFileName, ArchiveDirectory); end else begin SwapToZstd; ZstdItem := TAbZstdItem.Create; try MakeFullNames(SourceFileName, ArchiveDirectory, FullSourceFileName, FullArchiveFileName); ZstdItem.FileName := FullArchiveFileName; ZstdItem.DiskFileName := FullSourceFileName; Result := ZstdItem; except Result := nil; raise; end; end; end; { -------------------------------------------------------------------------- } destructor TAbZstdArchive.Destroy; begin SwapToZstd; FTarList.Free; FTarStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.ExtractItemAt(Index: Integer; const NewName: string); var OutStream : TStream; begin if IsZstdTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, NewName); end else begin SwapToZstd; OutStream := TFileStreamEx.Create(NewName, fmCreate or fmShareDenyNone); try try ExtractItemToStreamAt(Index, OutStream); finally OutStream.Free; end; { Bz2 doesn't store the last modified time or attributes, so don't set them } except on E : EAbUserAbort do begin FStatus := asInvalid; if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end else begin if mbFileExists(NewName) then mbDeleteFile(NewName); raise; end; end; end; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); begin if IsZstdTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToZstd; { Index ignored as there's only one item in a Bz2 } DecompressToStream(aStream); end; end; { -------------------------------------------------------------------------- } function TAbZstdArchive.GetSupportsEmptyFolders : Boolean; begin Result := IsZstdTar and TarAutoHandle; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.LoadArchive; var ItemName: string; Item: TAbZstdItem; Abort: Boolean = False; begin if FZstdStream.Size = 0 then Exit; if IsZstdTar and TarAutoHandle then begin { Decompress and send to tar LoadArchive } DecompressToStream(FTarStream); SwapToTar; inherited LoadArchive; end else begin SwapToZstd; Item := TAbZstdItem.Create; Item.Action := aaNone; Item.UncompressedSize := ZSTD_FileSize(FZstdStream); { Filename isn't stored, so constuct one based on the archive name } ItemName := ExtractFileName(ArchiveName); if ItemName = '' then Item.FileName := 'unknown' else Item.FileName := ChangeFileExt(ItemName, ''); Item.DiskFileName := Item.FileName; FItemList.Add(Item); end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.SaveArchive; var I: Integer; CompStream: TStream; CurItem: TAbZstdItem; TempFileName: String; UpdateArchive: Boolean; InputFileStream: TStream; begin if IsZstdTar and TarAutoHandle then begin SwapToTar; UpdateArchive := (FZstdStream.Size > 0) and (FZstdStream is TFileStreamEx); if UpdateArchive then begin FreeAndNil(FZstdStream); TempFileName := GetTempName(FArchiveName); { Create new archive with temporary name } FZstdStream := TFileStreamEx.Create(TempFileName, fmCreate or fmShareDenyWrite); end; FTarStream.Position := 0; CompStream := TZSTDCompressionStream.Create(FZstdStream, CompressionLevel); try FTargetStream := TWriteBufStream.Create(CompStream, $40000); try inherited SaveArchive; finally FreeAndNil(FTargetStream); end; finally CompStream.Free; end; if UpdateArchive then begin FreeAndNil(FZstdStream); { Replace original by new archive } if not (mbDeleteFile(FArchiveName) and mbRenameFile(TempFileName, FArchiveName)) then RaiseLastOSError; { Open new archive } FZstdStream := TFileStreamEx.Create(FArchiveName, fmOpenRead or fmShareDenyNone); end; end else begin { Things we know: There is only one file per archive.} { Actions we have to address in SaveArchive: } { aaNone & aaMove do nothing, as the file does not change, only the meta data } { aaDelete could make a zero size file unless there are two files in the list.} { aaAdd, aaStreamAdd, aaFreshen, & aaReplace will be the only ones to take action. } SwapToZstd; for I := 0 to pred(Count) do begin FCurrentItem := ItemList[I]; CurItem := TAbZstdItem(ItemList[I]); case CurItem.Action of aaNone, aaMove: Break;{ Do nothing; bz2 doesn't store metadata } aaDelete: ; {doing nothing omits file from new stream} aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin FZstdStream.Size := 0; if CurItem.Action = aaStreamAdd then CurItem.UncompressedSize := InStream.Size else begin CurItem.UncompressedSize := mbFileSize(CurItem.DiskFileName); end; CompStream := TZSTDCompressionStream.Create(FZstdStream, CompressionLevel, CurItem.UncompressedSize); try if CurItem.Action = aaStreamAdd then CompStream.CopyFrom(InStream, 0){ Copy/compress entire Instream to FZstdStream } else begin InputFileStream := TFileStreamEx.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite); try with TAbProgressWriteStream.Create(CompStream, InputFileStream.Size, OnProgress) do try CopyFrom(InputFileStream, 0);{ Copy/compress entire Instream to FZstdStream } finally Free; end; finally InputFileStream.Free; end; end; finally CompStream.Free; end; Break; end; { End aaAdd, aaFreshen, aaReplace, & aaStreamAdd } end; { End of CurItem.Action Case } end; { End Item for loop } end; { End Tar Else } end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToZstd; FTarAutoHandle := Value; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.DecompressToStream(aStream: TStream); const BufSize = $40000; var DecompStream: TZSTDDecompressionStream; ProxyStream: TAbProgressReadStream; Buffer: PByte; N: Integer; begin ProxyStream:= TAbProgressReadStream.Create(FZstdStream, OnProgress); try DecompStream := TZSTDDecompressionStream.Create(ProxyStream); try GetMem(Buffer, BufSize); try N := DecompStream.Read(Buffer^, BufSize); while N > 0 do begin aStream.WriteBuffer(Buffer^, N); N := DecompStream.Read(Buffer^, BufSize); end; finally FreeMem(Buffer, BufSize); end; finally DecompStream.Free; end; finally ProxyStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.TestItemAt(Index: Integer); var ZstdType: TAbArchiveType; BitBucket: TAbBitBucketStream; begin if IsZstdTar and TarAutoHandle then begin SwapToTar; inherited TestItemAt(Index); end else begin { note Index ignored as there's only one item in a GZip } ZstdType := VerifyZstd(FZstdStream); if not (ZstdType in [atZstd, atZstdTar]) then raise EAbGzipInvalid.Create; // TODO: Add zstd-specific exceptions } BitBucket := TAbBitBucketStream.Create(1024); try DecompressToStream(BitBucket); finally BitBucket.Free; end; end; end; { -------------------------------------------------------------------------- } procedure TAbZstdArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/license.txt������������������������������������������0000644�0001750�0000144�00000062233�14743153644�022621� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ MOZILLA PUBLIC LICENSE Version 1.1 --------------- 1. Definitions. 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. "Executable" means Covered Code in any form other than Source Code. 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. "License" means this document. 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. 3.4. Intellectual Property Matters (a) Third Party Claims. If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. (b) Contributor APIs. If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. (c) Representations. Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. 4. Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Application of this License. This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. 6. Versions of the License. 6.1. New Versions. Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. 6.3. Derivative Works. If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) 7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER 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 COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 8. TERMINATION. 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY 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 COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 10. U.S. GOVERNMENT END USERS. The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. 11. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. 12. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. 13. MULTIPLE-LICENSED CODE. Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. The Initial Developer of the Original Code is ________________________. Portions created by ______________________ are Copyright (C) ______ _______________________. All Rights Reserved. Contributor(s): ______________________________________. Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fparchive/readme.txt�������������������������������������������0000644�0001750�0000144�00000002201�14743153644�022421� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Zip plugin compression library It is a Free Pascal compression toolkit which supports ZIP, ZIPX, TAR, XZ, LZMA, GZip, Zstandard and BZip2 data compression and archiving. Based on TurboPower Abbrevia compression toolkit Version: 5.0 Revision: 512 Home Page: http://tpabbrevia.sourceforge.net NOTES: Functions AbDetectCharSet and IsOEM from AbCharset unit fails with some code pages and characters (eg. 936 and 图片) ! Don't use it when merging with Abbrevia. Better to try to convert with MultiByteToWideChar (see DCConvertEncoding CeTryEncode and CeTryDecode). Abbrevia sets current directory before reading files from disk in case paths are relative and uses ExpandFileName (which relies on current directory) to change relative paths to absolute. Since Double Commander uses the toolkit from a non-main thread it cannot rely on current directory not changing while working. Instead, always full paths in archive items are used, both archive file name and disk file name, paths are rebased against TAbArchive.BaseDirectory (which doesn't change during working) and all calls to functions changing current directory have been removed. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/fpc-extra.cfg��������������������������������������������������0000644�0001750�0000144�00000000157�14743153644�021036� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF CPU64 #IFDEF FPC_CROSSCOMPILING -Fl/usr/lib/gcc/i486-linux-gnu/4.6/64 -Fl/usr/local/lib64 #ENDIF #ENDIF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/lzma/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017424� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/lzma/7zC.txt���������������������������������������������������0000644�0001750�0000144�00000015114�14743153644�020632� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7z ANSI-C Decoder 4.23 ---------------------- 7z ANSI-C Decoder 4.23 Copyright (C) 1999-2005 Igor Pavlov 7z ANSI-C provides 7z/LZMA decoding. 7z ANSI-C version is simplified version ported from C++ code. LZMA is default and general compression method of 7z format in 7-Zip compression program (www.7-zip.org). LZMA provides high compression ratio and very fast decompression. LICENSE ------- Read lzma.txt for information about license. Files --------------------- 7zAlloc.* - Allocate and Free 7zBuffer.* - Buffer structure 7zCrc.* - CRC32 code 7zDecode.* - Low level memory->memory decoding 7zExtract.* - High level stream->memory decoding 7zHeader.* - .7z format constants 7zIn.* - .7z archive opening 7zItem.* - .7z structures 7zMain.c - Test application 7zMethodID.* - MethodID structure 7zTypes.h - Base types and constants How To Use ---------- You must download 7-Zip program from www.7-zip.org. You can create .7z archive with 7z.exe or 7za.exe: 7za.exe a archive.7z *.htm -r -mx -m0fb=255 -mf=off If you have big number of files in archive, and you need fast extracting, you can use partly-solid archives: 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K -mf=off In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only 512KB for extracting one file from such archive. Limitations of current version of 7z ANSI-C Decoder --------------------------------------------------- - It reads only "FileName", "Size", and "CRC" information for each file in archive. - It supports only LZMA and Copy (no compression) methods. - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. These limitations will be fixed in future versions. Using 7z ANSI-C Decoder Test application: ----------------------------------------- Usage: 7zDec <command> <archive_name> <Command>: e: Extract files from archive l: List contents of archive t: Test integrity of archive Example: 7zDec l archive.7z lists contents of archive.7z 7zDec e archive.7z extracts files from archive.7z to current folder. How to use .7z Decoder ---------------------- .7z Decoder can be compiled in one of two modes: 1) Default mode. In that mode 7z Decoder will read full compressed block to RAM before decompressing. 2) Mode with defined _LZMA_IN_CB. In that mode 7z Decoder can read compressed block by parts. And you can specify desired buffer size. So memory requirements can be reduced. But decompressing speed will be 5-10% lower and code size is slightly larger. Memory allocation ~~~~~~~~~~~~~~~~~ 7z Decoder uses two memory pools: 1) Temporary pool 2) Main pool Such scheme can allow you to avoid fragmentation of allocated blocks. Steps for using 7z decoder -------------------------- Use code at 7zMain.c as example. 1) Declare variables: inStream /* implements ISzInStream interface */ CArchiveDatabaseEx db; /* 7z archive database structure */ ISzAlloc allocImp; /* memory functions for main pool */ ISzAlloc allocTempImp; /* memory functions for temporary pool */ 2) call InitCrcTable(); function to initialize CRC structures. 3) call SzArDbExInit(&db); function to initialize db structures. 4) call SzArchiveOpen(inStream, &db, &allocMain, &allocTemp) to open archive This function opens archive "inStream" and reads headers to "db". All items in "db" will be allocated with "allocMain" functions. SzArchiveOpen function allocates and frees temporary structures by "allocTemp" functions. 5) List items or Extract items Listing code: ~~~~~~~~~~~~~ { UInt32 i; for (i = 0; i < db.Database.NumFiles; i++) { CFileItem *f = db.Database.Files + i; printf("%10d %s\n", (int)f->Size, f->Name); } } Extracting code: ~~~~~~~~~~~~~~~~ SZ_RESULT SzExtract( ISzInStream *inStream, CArchiveDatabaseEx *db, UInt32 fileIndex, /* index of file */ UInt32 *blockIndex, /* index of solid block */ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ size_t *outBufferSize, /* buffer size for output buffer */ size_t *offset, /* offset of stream for required file in *outBuffer */ size_t *outSizeProcessed, /* size of file in *outBuffer */ ISzAlloc *allocMain, ISzAlloc *allocTemp); If you need to decompress more than one file, you can send these values from previous call: blockIndex, outBuffer, outBufferSize, You can consider "outBuffer" as cache of solid block. If your archive is solid, it will increase decompression speed. After decompressing you must free "outBuffer": allocImp.Free(outBuffer); 6) call SzArDbExFree(&db, allocImp.Free) to free allocated items in "db". Memory requirements for .7z decoding ------------------------------------ Memory usage for Archive opening: - Temporary pool: - Memory for compressed .7z headers (if _LZMA_IN_CB is not defined) - Memory for uncompressed .7z headers - some other temporary blocks - Main pool: - Memory for database: Estimated size of one file structures in solid archive: - Size (4 or 8 Bytes) - CRC32 (4 bytes) - Some file information (4 bytes) - File Name (variable length) + pointer + allocation structures Memory usage for archive Decompressing: - Temporary pool: - Memory for compressed solid block (if _LZMA_IN_CB is not defined) - Memory for LZMA decompressing structures - Main pool: - Memory for decompressed solid block If _LZMA_IN_CB is defined, 7z Decoder will not allocate memory for compressed blocks. Instead of this, you must allocate buffer with desired size before calling 7z Decoder. Use 7zMain.c as example. EXIT codes ----------- 7z Decoder functions can return one of the following codes: #define SZ_OK (0) #define SZE_DATA_ERROR (1) #define SZE_OUTOFMEMORY (2) #define SZE_CRC_ERROR (3) #define SZE_NOTIMPL (4) #define SZE_FAIL (5) #define SZE_ARCHIVE_ERROR (6) LZMA Defines ------------ _LZMA_IN_CB - Use special callback mode for input stream to reduce memory requirements _SZ_FILE_SIZE_64 - define it if you need support for files larger than 4 GB _SZ_NO_INT_64 - define it if your compiler doesn't support long long int _LZMA_PROB32 - it can increase LZMA decompressing speed on some 32-bit CPUs. _SZ_ONE_DIRECTORY - define it if you want to locate all source files to one directory _SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. --- http://www.7-zip.org http://www.7-zip.org/support.html ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/lzma/7zFormat.txt����������������������������������������������0000644�0001750�0000144�00000016172�14743153644�021705� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7z Format description (2.30 Beta 25) ----------------------------------- This file contains description of 7z archive format. 7z archive can contain files compressed with any method. See "Methods.txt" for description for defined compressing methods. Format structure Overview ------------------------- Some fields can be optional. Archive structure ~~~~~~~~~~~~~~~~~ SignatureHeader [PackedStreams] [PackedStreamsForHeaders] [ Header or { Packed Header HeaderInfo } ] Header structure ~~~~~~~~~~~~~~~~ { ArchiveProperties AdditionalStreams { PackInfo { PackPos NumPackStreams Sizes[NumPackStreams] CRCs[NumPackStreams] } CodersInfo { NumFolders Folders[NumFolders] { NumCoders CodersInfo[NumCoders] { ID NumInStreams; NumOutStreams; PropertiesSize Properties[PropertiesSize] } NumBindPairs BindPairsInfo[NumBindPairs] { InIndex; OutIndex; } PackedIndices } UnPackSize[Folders][Folders.NumOutstreams] CRCs[NumFolders] } SubStreamsInfo { NumUnPackStreamsInFolders[NumFolders]; UnPackSizes[] CRCs[] } } MainStreamsInfo { (Same as in AdditionalStreams) } FilesInfo { NumFiles Properties[] { ID Size Data } } } HeaderInfo structure ~~~~~~~~~~~~~~~~~~~~ { (Same as in AdditionalStreams) } Notes about Notation and encoding --------------------------------- 7z uses little endian encoding. 7z archive format has optional headers that are marked as [] Header [] REAL_UINT64 means real UINT64. UINT64 means real UINT64 encoded with the following scheme: Size of encoding sequence depends from first byte: First_Byte Extra_Bytes Value (binary) 0xxxxxxx : ( xxxxxxx ) 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y ... 1111110x BYTE y[6] : ( x << (8 * 6)) + y 11111110 BYTE y[7] : y 11111111 BYTE y[8] : y Property IDs ------------ 0x00 = kEnd, 0x01 = kHeader, 0x02 = kArchiveProperties, 0x03 = kAdditionalStreamsInfo, 0x04 = kMainStreamsInfo, 0x05 = kFilesInfo, 0x06 = kPackInfo, 0x07 = kUnPackInfo, 0x08 = kSubStreamsInfo, 0x09 = kSize, 0x0A = kCRC, 0x0B = kFolder, 0x0C = kCodersUnPackSize, 0x0D = kNumUnPackStream, 0x0E = kEmptyStream, 0x0F = kEmptyFile, 0x10 = kAnti, 0x11 = kName, 0x12 = kCreationTime, 0x13 = kLastAccessTime, 0x14 = kLastWriteTime, 0x15 = kWinAttributes, 0x16 = kComment, 0x17 = kEncodedHeader, 7z format headers ----------------- SignatureHeader ~~~~~~~~~~~~~~~ BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; ArchiveVersion { BYTE Major; // now = 0 BYTE Minor; // now = 2 }; UINT32 StartHeaderCRC; StartHeader { REAL_UINT64 NextHeaderOffset REAL_UINT64 NextHeaderSize UINT32 NextHeaderCRC } ........................... ArchiveProperties ~~~~~~~~~~~~~~~~~ BYTE NID::kArchiveProperties (0x02) while(true) { BYTE PropertyType; if (aType == 0) break; UINT64 PropertySize; BYTE PropertyData[PropertySize]; } Digests (NumStreams) ~~~~~~~~~~~~~~~~~~~~~ BYTE AllAreDefined if (AllAreDefined == 0) { for(NumStreams) BIT Defined } UINT32 CRCs[NumDefined] PackInfo ~~~~~~~~~~~~ BYTE NID::kPackInfo (0x06) UINT64 PackPos UINT64 NumPackStreams [] BYTE NID::kSize (0x09) UINT64 PackSizes[NumPackStreams] [] [] BYTE NID::kCRC (0x0A) PackStreamDigests[NumPackStreams] [] BYTE NID::kEnd Folder ~~~~~~ UINT64 NumCoders; for (NumCoders) { BYTE { 0:3 DecompressionMethod.IDSize 4: 0 - IsSimple 1 - Is not simple 5: 0 - No Attributes 1 - There Are Attributes 7: 0 - Last Method in Alternative_Method_List 1 - There are more alternative methods } BYTE DecompressionMethod.ID[DecompressionMethod.IDSize] if (!IsSimple) { UINT64 NumInStreams; UINT64 NumOutStreams; } if (DecompressionMethod[0] != 0) { UINT64 PropertiesSize BYTE Properties[PropertiesSize] } } NumBindPairs = NumOutStreamsTotal - 1; for (NumBindPairs) { UINT64 InIndex; UINT64 OutIndex; } NumPackedStreams = NumInStreamsTotal - NumBindPairs; if (NumPackedStreams > 1) for(NumPackedStreams) { UINT64 Index; }; Coders Info ~~~~~~~~~~~ BYTE NID::kUnPackInfo (0x07) BYTE NID::kFolder (0x0B) UINT64 NumFolders BYTE External switch(External) { case 0: Folders[NumFolders] case 1: UINT64 DataStreamIndex } BYTE ID::kCodersUnPackSize (0x0C) for(Folders) for(Folder.NumOutStreams) UINT64 UnPackSize; [] BYTE NID::kCRC (0x0A) UnPackDigests[NumFolders] [] BYTE NID::kEnd SubStreams Info ~~~~~~~~~~~~~~ BYTE NID::kSubStreamsInfo; (0x08) [] BYTE NID::kNumUnPackStream; (0x0D) UINT64 NumUnPackStreamsInFolders[NumFolders]; [] [] BYTE NID::kSize (0x09) UINT64 UnPackSizes[] [] [] BYTE NID::kCRC (0x0A) Digests[Number of streams with unknown CRC] [] BYTE NID::kEnd Streams Info ~~~~~~~~~~~~ [] PackInfo [] [] CodersInfo [] [] SubStreamsInfo [] BYTE NID::kEnd FilesInfo ~~~~~~~~~ BYTE NID::kFilesInfo; (0x05) UINT64 NumFiles while(true) { BYTE PropertyType; if (aType == 0) break; UINT64 Size; switch(PropertyType) { kEmptyStream: (0x0E) for(NumFiles) BIT IsEmptyStream kEmptyFile: (0x0F) for(EmptyStreams) BIT IsEmptyFile kAnti: (0x10) for(EmptyStreams) BIT IsAntiFile case kCreationTime: (0x12) case kLastAccessTime: (0x13) case kLastWriteTime: (0x14) BYTE AllAreDefined if (AllAreDefined == 0) { for(NumFiles) BIT TimeDefined } BYTE External; if(External != 0) UINT64 DataIndex [] for(Definded Items) UINT32 Time [] kNames: (0x11) BYTE External; if(External != 0) UINT64 DataIndex [] for(Files) { wchar_t Names[NameSize]; wchar_t 0; } [] kAttributes: (0x15) BYTE AllAreDefined if (AllAreDefined == 0) { for(NumFiles) BIT AttributesAreDefined } BYTE External; if(External != 0) UINT64 DataIndex [] for(Definded Attributes) UINT32 Attributes [] } } Header ~~~~~~ BYTE NID::kHeader (0x01) [] ArchiveProperties [] [] BYTE NID::kAdditionalStreamsInfo; (0x03) StreamsInfo [] [] BYTE NID::kMainStreamsInfo; (0x04) StreamsInfo [] [] FilesInfo [] BYTE NID::kEnd HeaderInfo ~~~~~~~~~~ [] BYTE NID::kEncodedHeader; (0x17) StreamsInfo for Encoded Header [] --- End of document ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wcx/zip/src/lzma/CPL.html��������������������������������������������������0000644�0001750�0000144�00000035531�14743153644�020737� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <HTML><HEAD><TITLE>Common Public License - v 1.0

Common Public License - v 1.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

"Contribution" means:

    a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
    b) in the case of each subsequent Contributor:
    i) changes to the Program, and
    ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.

"Contributor" means any person or entity that distributes the Program.

"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

"Program" means the Contributions distributed in accordance with this Agreement.

"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.

2. GRANT OF RIGHTS

    a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
    b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
    c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
    d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.

3. REQUIREMENTS

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:

    a) it complies with the terms and conditions of this Agreement; and
    b) its license agreement:
    i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
    iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.

When the Program is made available in source code form:

    a) it must be made available under this Agreement; and
    b) a copy of this Agreement must be included with each copy of the Program.

Contributors may not remove or alter any copyright notices contained within the Program.

Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

doublecmd-1.1.22/plugins/wcx/zip/src/lzma/LGPL.txt0000644000175000001440000006351414743153644020734 0ustar alexxusers GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! doublecmd-1.1.22/plugins/wcx/zip/src/lzma/LZMAAlone.cfg0000644000175000001440000000066214743153644021633 0ustar alexxusers-$A8 -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J- -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\program files\borland\delphi7\Projects\Bpl" -LN"c:\program files\borland\delphi7\Projects\Bpl" -w-UNSAFE_TYPE -w-UNSAFE_CODE -w-UNSAFE_CAST doublecmd-1.1.22/plugins/wcx/zip/src/lzma/LZMAAlone.dof0000644000175000001440000001501514743153644021642 0ustar alexxusers[FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= PackageDLLOutputDir= PackageDCPOutputDir= SearchPath= Packages=PFMod;PDirDialog;pamixer;PMedia;DJcl;JvStdCtrlsD7R;JvAppFrmD7R;JvCoreD7R;JvBandsD7R;JvBDED7R;JvDBD7R;JvDlgsD7R;JvCmpD7R;JvCryptD7R;JvCtrlsD7R;JvCustomD7R;JvDockingD7R;JvDotNetCtrlsD7R;JvEDID7R;qrpt;JvGlobusD7R;JvHMID7R;JvInspectorD7R;JvInterpreterD7R;JvJansD7R;JvManagedThreadsD7R;JvMMD7R;JvNetD7R;JvPageCompsD7R;JvPluginD7R;JvPrintPreviewD7R;JvSystemD7R;JvTimeFrameworkD7R;JvUIBD7R;JvValidatorsD7R;JvWizardD7R;JvXPCtrlsD7R;ppsvApplicationHook Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams=e "c:\desktop\badlzma\dgaport.inf" "c:\desktop\test.lz" HostApplication=C:\Program Files\Borland\Delphi7\Projects\lzmabench\Project1.exe Launcher= UseLauncher=0 DebugCWD= [Version Info] IncludeVerInfo=0 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=2057 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.0.0.0 Comments= [Excluded Packages] C:\Program Files\Borland\Delphi7\Bin\dbx70.bpl=Borland SQL Explorer UI Package c:\program files\borland\delphi7\Bin\dclshlctrls70.bpl=Shell Control Property and Component Editors c:\program files\borland\delphi7\bin\dclRave70.bpl=Rave Reports BE 5.0 Package c:\program files\borland\delphi7\Projects\Bpl\L207vd70.bpl=TurboPower LockBox 2.07 Design-time package - VCL60 C:\Program Files\Borland\Delphi7\Bin\dclstd70.bpl=Borland Standard Components c:\program files\borland\delphi7\Bin\dclie70.bpl=Internet Explorer Components c:\program files\borland\delphi7\Bin\dcl31w70.bpl=Delphi 1.0 Compatibility Components c:\program files\borland\delphi7\Bin\dclIntraweb_50_70.bpl=Intraweb 5.0 Design Package for Delphi 7 c:\program files\borland\delphi7\Bin\dclofficexp70.bpl=Microsoft Office XP Sample Automation Server Wrapper Components c:\program files\borland\delphi7\Projects\Bpl\CrossKylix.bpl=CrossKylix IDE Plugin c:\program files\borland\delphi7\Projects\Bpl\VirtualTreesD7D.bpl=Virtual Treeview design time package c:\program files\borland\delphi7\Projects\Bpl\dclIndyCore70.bpl=Indy 10 Core Design Time c:\program files\borland\delphi7\Projects\Bpl\dclIndyProtocols70.bpl=Indy 10 Protocols Design Time c:\program files\borland\delphi7\Projects\Bpl\Png Delphi for Delphi 7.bpl=PNG Delphi (http://pngdelphi.sourceforge.net) c:\program files\borland\delphi7\Projects\Bpl\PDAB.bpl=(untitled) C:\Program Files\Borland\Delphi7\Projects\Bpl\Plinklists.bpl=(untitled) C:\Program Files\Borland\Delphi7\Projects\Bpl\PGIF.bpl=(untitled) c:\program files\borland\delphi7\Bin\idl2paswizardpkg.bpl=Borland IDL2PAS wizard package c:\program files\borland\delphi7\Bin\dclite70.bpl=Borland Integrated Translation Environment c:\program files\borland\delphi7\Bin\dclnet70.bpl=Borland Internet Components c:\program files\borland\delphi7\Bin\dclmcn70.bpl=Borland DataSnap Connection Components C:\Program Files\Borland\Delphi7\Bin\dclmid70.bpl=Borland MyBase DataAccess Components C:\Program Files\Borland\Delphi7\Bin\dcldb70.bpl=Borland Database Components c:\program files\borland\delphi7\Bin\dclsoap70.bpl=Borland SOAP Components c:\program files\borland\delphi7\Bin\dclocx70.bpl=Borland Sample Imported ActiveX Controls c:\program files\borland\delphi7\Bin\dclsmp70.bpl=Borland Sample Components c:\program files\borland\delphi7\Bin\dcldbx70.bpl=Borland dbExpress Components c:\program files\borland\delphi7\Bin\dcldbxcds70.bpl=Borland SimpleDataset Component (DBX) c:\program files\borland\delphi7\Bin\DBWEBXPRT.BPL=Borland Web Wizard Package C:\Program Files\Borland\Delphi7\Bin\dclbde70.bpl=Borland BDE DB Components c:\program files\borland\delphi7\Bin\dclwbm70.bpl=Borland InternetExpress Components c:\program files\borland\delphi7\Bin\dclwebsnap70.bpl=Borland WebSnap Components c:\program files\borland\delphi7\Bin\dclado70.bpl=Borland ADO DB Components c:\program files\borland\delphi7\Bin\DCLIB70.bpl=InterBase Data Access Components c:\program files\borland\delphi7\Bin\dcltee70.bpl=TeeChart Components c:\program files\borland\delphi7\Bin\dcldss70.bpl=Borland Decision Cube Components c:\program files\borland\delphi7\Bin\dclclxdb70.bpl=Borland CLX Database Components C:\Program Files\Borland\Delphi7\Bin\dclclxstd70.bpl=Borland CLX Standard Components c:\program files\borland\delphi7\Bin\dclsmpedit70.bpl=Borland Editor Script Enhancements c:\program files\borland\delphi7\Bin\applet70.bpl=Borland Control Panel Applet Package c:\program files\borland\delphi7\Bin\dclemacsedit70.bpl=Borland Editor Emacs Enhancements c:\program files\borland\delphi7\Bin\dclact70.bpl=Borland ActionBar Components c:\program files\borland\delphi7\Bin\dclmlwiz70.bpl=Borland Markup Language Wizards D:\WINDOWS\system32\ibevnt70.bpl=Borland Interbase Event Alerter Component c:\program files\borland\delphi7\Bin\dclindy70.bpl=Internet Direct (Indy) for D7 Property and Component Editors [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=C:\Program Files\Promixis\Girder\includes doublecmd-1.1.22/plugins/wcx/zip/src/lzma/LZMAAlone.dpr0000644000175000001440000000176014743153644021661 0ustar alexxusersprogram LZMAAlone; {$MODE Delphi} uses UCRC in 'UCRC.pas', ULZBinTree in 'compression\LZ\ULZBinTree.pas', ULZInWindow in 'compression\LZ\ULZInWindow.pas', ULZOutWindow in 'compression\LZ\ULZOutWindow.pas', ULZMABase in 'compression\LZMA\ULZMABase.pas', ULZMACommon in 'compression\LZMA\ULZMACommon.pas', ULZMADecoder in 'compression\LZMA\ULZMADecoder.pas', ULZMAEncoder in 'compression\LZMA\ULZMAEncoder.pas', UBitTreeDecoder in 'compression\RangeCoder\UBitTreeDecoder.pas', UBitTreeEncoder in 'compression\RangeCoder\UBitTreeEncoder.pas', URangeDecoder in 'compression\RangeCoder\URangeDecoder.pas', URangeEncoder in 'compression\RangeCoder\URangeEncoder.pas', UBufferedFS in 'UBufferedFS.pas', ULZMAAlone in 'ULZMAAlone.pas', ULZMABench in 'ULZMABench.pas',SysUtils; var lz:TLZMAAlone; {$IFDEF MSWINDOWS} {$APPTYPE CONSOLE} {$ENDIF} begin try lz:=TLZMAAlone.Create; lz.Main; lz.Free; except on e:exception do writeln(e.message); end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/LZMAAlone.lpi0000644000175000001440000001454114743153644021661 0ustar alexxusers doublecmd-1.1.22/plugins/wcx/zip/src/lzma/LZMAAlone.lpr0000644000175000001440000000176014743153644021671 0ustar alexxusersprogram LZMAAlone; {$MODE Delphi} uses UCRC in 'UCRC.pas', ULZBinTree in 'compression\LZ\ULZBinTree.pas', ULZInWindow in 'compression\LZ\ULZInWindow.pas', ULZOutWindow in 'compression\LZ\ULZOutWindow.pas', ULZMABase in 'compression\LZMA\ULZMABase.pas', ULZMACommon in 'compression\LZMA\ULZMACommon.pas', ULZMADecoder in 'compression\LZMA\ULZMADecoder.pas', ULZMAEncoder in 'compression\LZMA\ULZMAEncoder.pas', UBitTreeDecoder in 'compression\RangeCoder\UBitTreeDecoder.pas', UBitTreeEncoder in 'compression\RangeCoder\UBitTreeEncoder.pas', URangeDecoder in 'compression\RangeCoder\URangeDecoder.pas', URangeEncoder in 'compression\RangeCoder\URangeEncoder.pas', UBufferedFS in 'UBufferedFS.pas', ULZMAAlone in 'ULZMAAlone.pas', ULZMABench in 'ULZMABench.pas',SysUtils; var lz:TLZMAAlone; {$IFDEF MSWINDOWS} {$APPTYPE CONSOLE} {$ENDIF} begin try lz:=TLZMAAlone.Create; lz.Main; lz.Free; except on e:exception do writeln(e.message); end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/Methods.txt0000644000175000001440000000516214743153644021574 0ustar alexxusersCompression method IDs (4.38) ----------------------------- Each compression method in 7z has unique binary value (ID). The length of ID in bytes is arbitrary but it can not exceed 15 bytes. If you want to add some new ID, you have two ways: 1) Write request for allocating IDs to 7-zip developers. 2) Use such random ID: 03 E0 ZZ ... ZZ MM ... MM VV ... VV ZZ != 0, MM != 0, VV != 0 03 E0 - Prefix for random IDs ZZ ... ZZ - Developer ID. (length >= 4). Use real random bytes. You can notify 7-Zip developers about your Developer ID. MM ... MM - Method ID (length >= 1) VV ... VV - Version (length >= 1) Note: Use new ID (MM ... MM VV .. VV) only if old codec can not decode data encoded with new version. List of defined IDs ------------------- 00 - Copy 01 - Reserved 02 - Common 03 Swap - 2 Swap2 - 4 Swap4 04 Delta (subject to change) 03 - 7z 01 - LZMA 01 - Version 03 - Branch 01 - x86 03 - BCJ 1B - BCJ2 02 - PPC 05 - BC_PPC_B (Big Endian) 03 - Alpha 01 - BC_Alpha 04 - IA64 01 - BC_IA64 05 - ARM 01 - BC_ARM 06 - M68 05 - BC_M68_B (Big Endian) 07 - ARM Thumb 01 - BC_ARMThumb 08 - SPARC 05 - BC_SPARC 04 - PPMD 01 - Version 80 - reserved for independent developers E0 - Random IDs 04 - Misc 00 - Reserved 01 - Zip 00 - Copy (not used). Use {00} instead 01 - Shrink 06 - Implode 08 - Deflate 09 - Deflate64 12 - BZip2 (not used). Use {04 02 02} instead 02 - BZip 02 - BZip2 03 - Rar 01 - Rar15 02 - Rar20 03 - Rar29 04 - Arj 01 - Arj (1,2,3) 02 - Arj 4 05 - Z 06 - Lzh 07 - Reserved for 7z 08 - Cab 09 - NSIS 01 - DeflateNSIS 02 - BZip2NSIS 06 - Crypto 00 - 01 - AES 0x - AES-128 4x - AES-192 8x - AES-256 x0 - ECB x1 - CBC x2 - CFB x3 - OFB 07 - Reserved 0F - Reserved F0 - Misc Ciphers (Real Ciphers without hashing algo) F1 - Misc Ciphers (Combine) 01 - Zip 01 - Main Zip crypto algo 03 - RAR 02 - 03 - Rar29 AES-128 + (modified SHA-1) 07 - 7z 01 - AES-256 + SHA-256 07 - Hash (subject to change) 00 - 01 - CRC 02 - SHA-1 03 - SHA-256 04 - SHA-384 05 - SHA-512 F0 - Misc Hash F1 - Misc 03 - RAR 03 - Rar29 Password Hashing (modified SHA1) 07 - 7z 01 - SHA-256 Password Hashing --- End of document doublecmd-1.1.22/plugins/wcx/zip/src/lzma/UBufferedFS.pas0000644000175000001440000001160514743153644022234 0ustar alexxusersunit UBufferedFS; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes,Math; const BufferSize=$10000;//64K type TBFSMode=(BFMRead,BFMWrite); TBufferedFS=class(TFileStream) private membuffer:array [0..BufferSize-1] of byte; bytesinbuffer:integer; bufferpos:integer; bufferdirty:boolean; Mode:TBFSMode; procedure Init; procedure ReadBuffer; public constructor Create(const FileName: string; Mode: Word); overload; constructor Create(const FileName: string; Mode: Word; Rights: Cardinal); overload; destructor Destroy; override; procedure Flush; {$IF (FPC_VERSION <= 2) and (FPC_RELEASE <= 4) and (FPC_PATCH <= 0)} function ReadQWord: QWord; procedure WriteQWord(q: QWord); {$ENDIF} function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; type TByteArray = array of byte; PByteArray = ^TByteArray; implementation function MovePointer(const P: Pointer; const dist: PtrInt): Pointer; begin Result:= Pointer(PtrInt(p) + dist); end; procedure TBufferedFS.Init; begin bytesinbuffer:=0; bufferpos:=0; bufferdirty:=false; mode:=BFMWrite; end; procedure TBufferedFS.Flush; begin if bufferdirty then inherited Write(membuffer[0],bufferpos); bufferdirty:=false; bytesinbuffer:=0; bufferpos:=0; end; constructor TBufferedFS.Create(const FileName: string; Mode: Word); begin inherited Create(FileName, Mode); init; end; constructor TBufferedFS.Create(const FileName: string; Mode: Word; Rights: Cardinal); begin inherited Create(FileName, Mode, Rights); init; end; destructor TBufferedFS.Destroy; begin flush; inherited Destroy; end; procedure TBufferedFS.ReadBuffer; begin flush; bytesinbuffer:=inherited Read(membuffer,buffersize); bufferpos:=0; end; {$IF (FPC_VERSION <= 2) and (FPC_RELEASE <= 4) and (FPC_PATCH <= 0)} function TBufferedFS.ReadQWord: QWord; var q: QWord; begin ReadBuffer(q, SizeOf(QWord)); ReadQWord:= q; end; procedure TBufferedFS.WriteQWord(q: QWord); begin WriteBuffer(q, SizeOf(QWord)); end; {$ENDIF} function TBufferedFS.Read(var Buffer; Count: Longint): Longint; var p:PByteArray; bytestoread:integer; b:PtrInt; begin if Mode=BFMWrite then flush; mode:=BFMRead; result:=0; if count<=bytesinbuffer then begin //all data already in buffer move(membuffer[bufferpos],buffer,count); bytesinbuffer:=bytesinbuffer-count; bufferpos:=bufferpos+count; result:=count; end else begin bytestoread:=count; if (bytestoread<>0)and(bytesinbuffer<>0) then begin //read data remaining in buffer and increment data pointer b:=Read(buffer,bytesinbuffer); p:=PByteArray(@(TByteArray(buffer)[b])); bytestoread:=bytestoread-b; result:=b; end else p:=@buffer; if bytestoread>=BufferSize then begin //data to read is larger than the buffer, read it directly result:=result+inherited Read(p^,bytestoread); end else begin //refill buffer ReadBuffer; //recurse result:=result+Read(p^,math.Min(bytestoread,bytesinbuffer)); end; end; end; function TBufferedFS.Write(const Buffer; Count: Longint): Longint; var p:pointer; bytestowrite:integer; b:PtrInt; begin if mode=BFMRead then begin seek(-BufferSize+bufferpos,soFromCurrent); bytesinbuffer:=0; bufferpos:=0; end; mode:=BFMWrite; result:=0; if count<=BufferSize-bytesinbuffer then begin //all data fits in buffer bufferdirty:=true; move(buffer,membuffer[bufferpos],count); bytesinbuffer:=bytesinbuffer+count; bufferpos:=bufferpos+count; result:=count; end else begin bytestowrite:=count; if (bytestowrite<>0)and(bytesinbuffer<>BufferSize)and(bytesinbuffer<>0) then begin //write data to remaining space in buffer and increment data pointer b:=Write(buffer,BufferSize-bytesinbuffer); p:=MovePointer(@buffer,b); bytestowrite:=bytestowrite-b; result:=b; end else p:=@buffer; if bytestowrite>=BufferSize then begin //empty buffer Flush; //data to write is larger than the buffer, write it directly result:=result+inherited Write(p^,bytestowrite); end else begin //empty buffer Flush; //recurse result:=result+Write(p^,bytestowrite); end; end; end; function TBufferedFS.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Origin=soCurrent)and(Offset=0) then result:=inherited seek(Offset,origin)+bufferpos else begin flush; result:=inherited Seek(offset,origin); end; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/UCRC.pas0000644000175000001440000000266314743153644020674 0ustar alexxusersunit UCRC; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface type TCRC=class public Value:integer; constructor Create; procedure Init; procedure Update(const data: array of byte;const offset,size:integer);overload; procedure Update(const data: array of byte);overload; procedure UpdateByte(const b:integer); function GetDigest:integer; end; implementation var Table: array [0..255] of integer; constructor TCRC.Create; begin Value:=-1; end; procedure TCRC.Init; begin Value:=-1; end; procedure TCRC.Update(const data: array of byte;const offset,size:integer); var i:integer; begin for i := 0 to size-1 do value := Table[(value xor data[offset + i]) and $FF] xor (value shr 8); end; procedure TCRC.Update(const data: array of byte); var size:integer; i:integer; begin size := length(data); for i := 0 to size - 1 do value := Table[(value xor data[i]) and $FF] xor (value shr 8); end; procedure TCRC.UpdateByte(const b:integer); begin value := Table[(value xor b) and $FF] xor (value shr 8); end; function TCRC.GetDigest:integer; begin result:=value xor (-1); end; procedure InitCRC; var i,j,r:integer; begin for i := 0 to 255 do begin r := i; for j := 0 to 7 do begin if ((r and 1) <> 0) then r := (r shr 1) xor integer($EDB88320) else r := r shr 1; end; Table[i] := r; end; end; initialization InitCRC; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/ULZMAAlone.pas0000644000175000001440000002221314743153644022000 0ustar alexxusersunit ULZMAAlone; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses ULZMABench,ULZMAEncoder,ULZMADecoder,UBufferedFS,ULZMACommon,Classes; const kEncode=0; kDecode=1; kBenchmark=2; type TCommandLine=class public command:integer; NumBenchMarkPasses:integer; DictionarySize:integer; DictionarySizeIsDefined:boolean; Lc:integer; Lp:integer; Pb:integer; Fb:integer; FbIsDefined:boolean; Eos:boolean; Algorithm:integer; MatchFinder:integer; InFile:string; OutFile:string; constructor Create; function ParseSwitch(const s:string):boolean; function Parse:boolean; end; TLZMAAlone=class public procedure PrintHelp; procedure Main; end; implementation uses SysUtils; constructor TCommandLine.Create; begin Command:=-1; NumBenchMarkPasses:=10; DictionarySize:=1 shl 23; DictionarySizeIsDefined:= false; Lc:= 3; Lp:= 0; Pb:= 2; Fb:= 128; FbIsDefined:= false; Eos:= false; Algorithm:= 2; MatchFinder:= 1; end; function GetStr(const str:string;const offset:integer):string; var i:integer; begin result:=''; for i:=offset to length(str) do result:=result+str[i]; end; function GetInt(const str:string;const offset:integer):integer; var s:string; begin s:=GetStr(s,offset); result:=strtoint(s); end; function TCommandLine.ParseSwitch(const s:string):boolean; var l:integer; mfs:string; begin result:=false; l:=length(s); if l=0 then exit; case s[1] of 'd': begin DictionarySize := 1 shl GetInt(s,2); DictionarySizeIsDefined := true; result:=true; end; 'f': begin if (l>=2)and(s[2]='b') then begin fb:=GetInt(s,3); FbIsDefined := true; result:=true; end; end; 'a': begin Algorithm := GetInt(s,2); result:=true; end; 'l': begin if (l>=2) then begin if s[2]='c' then begin Lc:=GetInt(s,3); result:=true; end; if s[2]='p' then begin Lp:=GetInt(s,3); result:=true; end; end; end; 'p': begin if (l>=2)and(s[2]='b') then begin Pb:=GetInt(s,3); result:=true; end; end; 'e': begin if (l>=3)and(s[2]='o')and(s[3]='s') then begin eos:=true; result:=true; end; end; 'm': begin if (l>=2)and(s[2]='f') then begin mfs:=GetStr(s,3); if mfs='bt2' then MatchFinder:=0 else if mfs='bt4' then MatchFinder:=1 else if mfs='bt4b' then MatchFinder:=2 else begin result:=false; exit; end; end; end; else result:=false; end; end; function TCommandLine.Parse:boolean; var pos:integer; switchMode:boolean; i,l:integer; s,sw:string; begin pos := 1; switchMode := true; l:=ParamCount; for i := 1 to l do begin s := ParamStr(i); if length(s) = 0 then begin result:=false; exit; end; if switchMode then begin if comparestr(s,'--')= 0 then begin switchMode := false; continue; end; if s[1]='-' then begin sw := AnsiLowerCase(GetStr(s,2)); if length(sw) = 0 then begin result:=false; exit; end; try if not ParseSwitch(sw) then begin result:=false; exit; end; except on e:EConvertError do begin result:=false; exit; end; end; continue; end; end; if pos = 1 then begin if comparetext(s,'e')=0 then Command := kEncode else if comparetext(s,'d')=0 then Command := kDecode else if comparetext(s,'b')=0 then Command := kBenchmark else begin result:=false; exit; end; end else if pos = 2 then begin if Command = kBenchmark then begin try NumBenchmarkPasses := strtoint(s); if NumBenchmarkPasses < 1 then begin result:=false; exit; end; except on e:EConvertError do begin result:=false; exit; end; end; end else InFile := s; end else if pos = 3 then OutFile := s else begin result:=false; exit; end; inc(pos); continue; end; result:=true; exit; end; procedure TLZMAAlone.PrintHelp; begin writeln( #10'Usage: LZMA [...] inputFile outputFile'#10 + ' e: encode file'#10 + ' d: decode file'#10 + ' b: Benchmark'#10 + ''#10 + // ' -a{N}: set compression mode - [0, 1], default: 1 (max)\n' + ' -d{N}: set dictionary - [0,28], default: 23 (8MB)'#10 + ' -fb{N}: set number of fast bytes - [5, 273], default: 128'#10 + ' -lc{N}: set number of literal context bits - [0, 8], default: 3'#10 + ' -lp{N}: set number of literal pos bits - [0, 4], default: 0'#10 + ' -pb{N}: set number of pos bits - [0, 4], default: 2'#10 + ' -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4'#10 + ' -eos: write End Of Stream marker'#10 ); end; procedure TLZMAAlone.Main; var params:TCommandLine; dictionary:integer; lzmaBench:tlzmabench; inStream:TBufferedFS; outStream:TBufferedFS; eos:boolean; encoder:TLZMAEncoder; filesize:int64; i:integer; properties:array[0..4] of byte; decoder:TLZMADecoder; outSize:int64; v:byte; const propertiessize=5; begin writeln(#10'LZMA (Pascal) 4.42 Copyright (c) 1999-2006 Igor Pavlov 2006-05-15'#10); if paramcount<1 then begin PrintHelp; exit; end; params:=TCommandLine.Create; if not params.Parse then begin writeln(#10'Incorrect command'); exit; end; if params.command=kBenchmark then begin dictionary:=1 shl 21; if params.DictionarySizeIsDefined then dictionary:=params.DictionarySize; if params.MatchFinder>1 then raise Exception.Create('Unsupported match finder'); lzmaBench:=TLZMABench.Create; lzmaBench.LzmaBenchmark(params.NumBenchMarkPasses,dictionary); lzmaBench.Free; end else if (params.command=kEncode)or(params.command=kDecode) then begin inStream:=TBufferedFS.Create(params.InFile,fmOpenRead or fmsharedenynone); outStream:=TBufferedFS.Create(params.OutFile,fmcreate); eos := false; if params.Eos then eos := true; if params.Command = kEncode then begin encoder:=TLZMAEncoder.Create; if not encoder.SetAlgorithm(params.Algorithm) then raise Exception.Create('Incorrect compression mode'); if not encoder.SetDictionarySize(params.DictionarySize) then raise Exception.Create('Incorrect dictionary size'); if not encoder.SeNumFastBytes(params.Fb) then raise Exception.Create('Incorrect -fb value'); if not encoder.SetMatchFinder(params.MatchFinder) then raise Exception.Create('Incorrect -mf value'); if not encoder.SetLcLpPb(params.Lc, params.Lp, params.Pb) then raise Exception.Create('Incorrect -lc or -lp or -pb value'); encoder.SetEndMarkerMode(eos); encoder.WriteCoderProperties(outStream); if eos then fileSize := -1 else fileSize := inStream.Size; for i := 0 to 7 do WriteByte(outStream,(fileSize shr (8 * i)) and $FF); encoder.Code(inStream, outStream, -1, -1); encoder.free; end else begin if inStream.read(properties, propertiesSize) <> propertiesSize then raise Exception.Create('input .lzma file is too short'); decoder := TLZMADecoder.Create; if not decoder.SetDecoderProperties(properties) then raise Exception.Create('Incorrect stream properties'); outSize := 0; for i := 0 to 7 do begin v := {shortint}(ReadByte(inStream)); if v < 0 then raise Exception.Create('Can''t read stream size'); outSize := outSize or v shl (8 * i); end; if not decoder.Code(inStream, outStream, outSize) then raise Exception.Create('Error in data stream'); decoder.Free; end; outStream.Free; inStream.Free; end else raise Exception.Create('Incorrect command'); params.Free; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/ULZMABench.pas0000644000175000001440000003332214743153644021764 0ustar alexxusersunit ULZMABench; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes,UCRC,ULZMACommon,windows,ULZMAEncoder,ULZMADecoder; type TLZMABench=class public function GetLogSize(const size:integer):integer; function MyMultDiv64(const value, elapsedTime:int64):int64; function GetCompressRating(const dictionarySize:integer;const elapsedTime,size:int64):int64; function GetDecompressRating(const elapsedTime:int64;const outSize,inSize:int64):int64; function GetTotalRating(const dictionarySize:int64;const elapsedTimeEn, sizeEn, elapsedTimeDe, inSizeDe, outSizeDe:int64):int64; procedure PrintValue(const v:int64); procedure PrintRating(const rating:int64); procedure PrintResults(const dictionarySize:integer;const elapsedTime, size:int64;const decompressMode:boolean;const secondSize:int64); function LzmaBenchmark(const numIterations, dictionarySize:integer):integer; end; TLZMARandomGenerator=class public A1:integer; A2:integer; constructor Create; procedure Init; function GetRnd:integer; end; TLZMABenchBitRandomGenerator=class public RG:TLZMARandomGenerator; Value:integer; NumBits:integer; constructor Create; destructor Destroy;override; procedure Init; function GetRnd(numBits:integer):integer; end; TLZMABenchRandomGenerator=class public RG:TLZMABenchBitRandomGenerator; Pos:integer; Rep0:integer; Buffer:array of byte; BufferSize:integer; constructor Create; destructor Destroy;override; procedure _Set(const bufferSize:integer); function GetRndBit:integer; function GetLogRandBits(const numBits:integer):integer; function GetOffset:integer; function GetLen1:integer; function GetLen2:integer; procedure Generate; end; TCRCStream=class(TStream) public CRC:TCRC; constructor Create; destructor Destroy;override; procedure Init; function GetDigest:integer; function Write(const Buffer; Count: Longint): Longint;override; end; TByteArray=array of byte; PByteArray=^TByteArray; TMyOutputStream=class(TStream) public _buffer:PByteArray; _size:integer; _pos:integer; constructor Create(const buffer:PByteArray); procedure Reset; function Write(const Buffer; Count: Longint): Longint;override; function Size:integer; end; TMyInputStream=class(TStream) public _buffer:PByteArray; _size:integer; _pos:integer; constructor Create(const buffer:PByteArray;const size:integer); procedure Reset; function Read(var Buffer; Count: Longint): Longint;override; end; TLZMAProgressInfo=class public ApprovedStart:int64; InSize:int64; Time:cardinal; procedure Init; procedure OnProgress(const Action:TLZMAProgressAction;const Value:int64); end; implementation uses SysUtils; const kAdditionalSize = (1 shl 21); kCompressedAdditionalSize = (1 shl 10); kSubBits = 8; constructor TLZMARandomGenerator.Create; begin Init; end; procedure TLZMARandomGenerator.Init; begin A1 := 362436069; A2 := 521288629; end; function TLZMARandomGenerator.GetRnd:integer; begin A1 := 36969 * (A1 and $ffff) + (A1 shr 16); A2 := 18000 * (A2 and $ffff) + (A2 shr 16); result:=(A1 shl 16) xor (A2); end; constructor TLZMABenchBitRandomGenerator.Create; begin RG:=TLZMARandomGenerator.Create; end; destructor TLZMABenchBitRandomGenerator.Destroy; begin RG.Free; end; procedure TLZMABenchBitRandomGenerator.Init; begin Value := 0; NumBits := 0; end; function TLZMABenchBitRandomGenerator.GetRnd(numBits:integer):integer; begin if self.NumBits > numBits then begin result := Value and ((1 shl numBits) - 1); Value := Value shr numBits; self.NumBits := self.NumBits - numBits; exit; end; numBits := numBits - self.NumBits; result := (Value shl numBits); Value := RG.GetRnd; result := result or (Value and ((1 shl numBits) - 1)); Value := value shr numBits; self.NumBits := 32 - numBits; end; constructor TLZMABenchRandomGenerator.Create; begin RG:=TLZMABenchBitRandomGenerator.Create; end; destructor TLZMABenchRandomGenerator.Destroy; begin RG.free; end; procedure TLZMABenchRandomGenerator._Set(const bufferSize:integer); begin setlength(Buffer,bufferSize); Pos := 0; self.BufferSize := bufferSize; end; function TLZMABenchRandomGenerator.GetLogRandBits(const numBits:integer):integer; var len:integer; begin len := RG.GetRnd(numBits); result:=RG.GetRnd(len); end; function TLZMABenchRandomGenerator.GetRndBit:integer; begin result:=RG.GetRnd(1); end; function TLZMABenchRandomGenerator.GetOffset:integer; begin if GetRndBit = 0 then result:=GetLogRandBits(4) else result:=(GetLogRandBits(4) shl 10) or RG.GetRnd(10); end; function TLZMABenchRandomGenerator.GetLen1:integer; begin result:=RG.GetRnd(1 + RG.GetRnd(2)); end; function TLZMABenchRandomGenerator.GetLen2:integer; begin result:=RG.GetRnd(2 + RG.GetRnd(2)); end; procedure TLZMABenchRandomGenerator.Generate; var len,i:integer; begin RG.Init; Rep0 := 1; while Pos < BufferSize do begin if (GetRndBit = 0) or (Pos < 1) then begin Buffer[Pos] := RG.GetRnd(8); inc(pos); end else begin if RG.GetRnd(3) = 0 then len := 1 + GetLen1 else begin repeat Rep0 := GetOffset; until not (Rep0 >= Pos); inc(Rep0); len := 2 + GetLen2; end; i:=0; while (i < len) and (Pos < BufferSize) do begin Buffer[Pos] := Buffer[Pos - Rep0]; inc(i); inc(pos); end; end; end; end; constructor TCRCStream.Create; begin CRC:=TCRC.Create; end; destructor TCRCStream.Destroy; begin CRC.Free; end; procedure TCRCStream.Init; begin CRC.Init; end; function TCRCStream.GetDigest:integer; begin result:=CRC.GetDigest; end; function TCRCStream.Write(const Buffer; Count: Longint): Longint; var p:^byte; i:integer; begin p:=@buffer; for i:=0 to count -1 do begin CRC.UpdateByte(p^); inc(p); end; result:=count; end; constructor TMyOutputStream.Create(const buffer:PByteArray); begin _buffer:=buffer; _size:=length(buffer^); end; procedure TMyOutputStream.Reset; begin _pos:=0; end; function TMyOutputStream.Write(const Buffer; Count: Longint): Longint; begin if _pos+count>=_size then raise Exception.Create('Error'); move(buffer,_buffer^[_pos],count); _pos:=_pos+count; result:=count; end; function TMyOutputStream.Size:integer; begin result:=_pos; end; constructor TMyInputStream.Create(const buffer:PByteArray;const size:integer); begin _buffer:=buffer; _size:=size; end; procedure TMyInputStream.Reset; begin _pos:=0; end; function TMyInputStream.Read(var Buffer; Count: Longint): Longint; var b:int64; begin try b:=_size-_pos; if b>count then b:=count; result:=b; move(_buffer^[_pos],buffer,b); _pos:=_pos+b; except writeln('inread error'); end; end; procedure TLZMAProgressInfo.Init; begin InSize:=0; end; procedure TLZMAProgressInfo.OnProgress(const Action:TLZMAProgressAction;const Value:int64); begin if Action=LPAMax then exit; if (value >= ApprovedStart) and (InSize = 0) then begin Time := GetTickCount; InSize := value; end; end; function TLZMABench.GetLogSize(const size:integer):integer; var i,j:integer; begin for i := kSubBits to 31 do for j := 0 to 1 shl kSubBits -1 do if (size <= (1 shl i) + (j shl (i - kSubBits))) then begin result:=(i shl kSubBits) + j; exit; end; result:=32 shl kSubBits; end; function TLZMABench.MyMultDiv64(const value, elapsedTime:int64):int64; var freq,elTime:int64; begin freq := 1000; // ms elTime := elapsedTime; while freq > 1000000 do begin freq := freq shr 1; elTime :=elTime shr 1; end; if elTime = 0 then elTime := 1; result:=value * freq div elTime; end; function TLZMABench.GetCompressRating(const dictionarySize:integer;const elapsedTime,size:int64):int64; var t,numCommandsForOne,numCommands:int64; begin t := GetLogSize(dictionarySize) - (18 shl kSubBits); numCommandsForOne := 1060 + ((t * t * 10) shr (2 * kSubBits)); numCommands := size * numCommandsForOne; result:=MyMultDiv64(numCommands, elapsedTime); end; function TLZMABench.GetDecompressRating(const elapsedTime:int64;const outSize,inSize:int64):int64; var numCommands:int64; begin numCommands := inSize * 220 + outSize * 20; result:=MyMultDiv64(numCommands, elapsedTime); end; function TLZMABench.GetTotalRating(const dictionarySize:int64;const elapsedTimeEn, sizeEn, elapsedTimeDe, inSizeDe, outSizeDe:int64):int64; begin result:=(GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) + GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) div 2; end; procedure TLZMABench.PrintValue(const v:int64); var s:string; i:integer; begin s:=inttostr(v); i:=0; while i+length(s)<6 do begin write(' '); inc(i); end; write(s); end; procedure TLZMABench.PrintRating(const rating:int64); begin PrintValue(rating div 1000000); write(' MIPS'); end; procedure TLZMABench.PrintResults(const dictionarySize:integer;const elapsedTime, size:int64;const decompressMode:boolean;const secondSize:int64); var speed:int64; rating:int64; begin speed := MyMultDiv64(size, elapsedTime); PrintValue(speed div 1024); write(' KB/s '); if decompressMode then rating := GetDecompressRating(elapsedTime, size, secondSize) else rating := GetCompressRating(dictionarySize, elapsedTime, size); PrintRating(rating); end; function TLZMABench.LzmaBenchmark(const numIterations, dictionarySize:integer):integer; var encoder:TLZMAEncoder; decoder:TLZMADecoder; kBufferSize,kCompressedBufferSize:integer; propStream:TMemoryStream; proparray:array of byte; rg:TLZMABenchRandomGenerator; crc:TCRC; progressInfo:TLZMAProgressInfo; totalBenchSize,totalEncodeTime,totalDecodeTime,totalCompressedSize:int64; inStream:TMyInputStream; compressedBuffer:array of byte; compressedStream:TMyOutputStream; CrcOutStream:TCRCStream; inputCompressedStream:TMyInputStream; compressedSize,i,j:integer; encodeTime,decodeTime:cardinal; outSize,startTime,benchSize:int64; begin if numIterations <= 0 then begin result:=0; exit; end; if dictionarySize < (1 shl 18) then begin writeln(#10'Error: dictionary size for benchmark must be >= 18 (256 KB)'); result:=1; exit; end; write(#10' Compressing Decompressing'#10#10); encoder := TLZMAEncoder.Create; decoder := TLZMADecoder.Create; if not encoder.SetDictionarySize(dictionarySize) then raise Exception.Create('Incorrect dictionary size'); kBufferSize := dictionarySize + kAdditionalSize; kCompressedBufferSize := (kBufferSize div 2) + kCompressedAdditionalSize; propstream:=TMemoryStream.Create; encoder.WriteCoderProperties(propStream); setlength(proparray,propstream.size); propstream.Position:=0; propstream.Read(propArray[0],propstream.Size); decoder.SetDecoderProperties(propArray); rg := TLZMABenchRandomGenerator.Create; rg._Set(kBufferSize); rg.Generate; crc := TCRC.Create; crc.Init; crc.Update(rg.Buffer[0], 0, rg.BufferSize); progressInfo := TLZMAProgressInfo.Create; progressInfo.ApprovedStart := dictionarySize; totalBenchSize := 0; totalEncodeTime := 0; totalDecodeTime := 0; totalCompressedSize := 0; inStream := TMyInputStream.Create(@(rg.Buffer), rg.BufferSize); setlength(compressedBuffer,kCompressedBufferSize); compressedStream := TMyOutputStream.Create(@compressedBuffer); crcOutStream :=TCRCStream.Create; inputCompressedStream := nil; compressedSize := 0; for i := 0 to numIterations -1 do begin progressInfo.Init; inStream.reset; compressedStream.reset; encoder.OnProgress:=progressInfo.OnProgress; encoder.Code(inStream, compressedStream, rg.BufferSize, -1); encodeTime := GetTickCount - progressInfo.Time; if i = 0 then begin compressedSize := compressedStream.size; inputCompressedStream := TMyInputStream.Create(@compressedBuffer, compressedSize); end else if compressedSize <> compressedStream.size then raise Exception.Create('Encoding error'); if progressInfo.InSize = 0 then raise Exception.Create('Internal ERROR 1282'); decodeTime := 0; for j := 0 to 1 do begin inputCompressedStream.reset; crcOutStream.Init; outSize := kBufferSize; startTime := GetTickCount; if not decoder.Code(inputCompressedStream, crcOutStream, outSize) then raise Exception.Create('Decoding Error'); decodeTime := GetTickCount - startTime; if crcOutStream.GetDigest <> crc.GetDigest then raise Exception.Create('CRC Error'); end; benchSize := kBufferSize - progressInfo.InSize; PrintResults(dictionarySize, encodeTime, benchSize, false, 0); write(' '); PrintResults(dictionarySize, decodeTime, kBufferSize, true, compressedSize); writeln(''); totalBenchSize := totalBenchSize + benchSize; totalEncodeTime := totalEncodeTime + encodeTime; totalDecodeTime := totalDecodeTime + decodeTime; totalCompressedSize := totalCompressedSize + compressedSize; end; writeln('---------------------------------------------------'); PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0); write(' '); PrintResults(dictionarySize, totalDecodeTime, kBufferSize * numIterations, true, totalCompressedSize); writeln(' Average'); result:=0; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/0000755000175000001440000000000014743153644021765 5ustar alexxusersdoublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZ/0000755000175000001440000000000014743153644022312 5ustar alexxusersdoublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZ/ULZBinTree.pas0000644000175000001440000002661614743153644024755 0ustar alexxusersunit ULZBinTree; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses ULZInWindow,Math; type TLZBinTree=class(TLZInWindow) public cyclicBufferPos:integer; cyclicBufferSize:integer; matchMaxLen:integer; son: array of integer; hash: array of integer; cutValue:integer; hashMask:integer; hashSizeSum:integer; HASH_ARRAY:boolean; kNumHashDirectBytes:integer; kMinMatchCheck:integer; kFixHashSize:integer; constructor Create; procedure SetType(const numHashBytes:integer); procedure Init;override; procedure MovePos;override; function _Create(const historySize,keepAddBufferBefore,matchMaxLen,keepAddBufferAfter:integer):boolean;reintroduce; function GetMatches(var distances:array of integer):integer; procedure Skip(num:integer); procedure NormalizeLinks(var items:array of integer;const numItems,subValue:integer); procedure Normalize; procedure SetCutValue(const cutValue:integer); end; implementation const kHash2Size = 1 shl 10; kHash3Size = 1 shl 16; kBT2HashSize = 1 shl 16; kStartMaxLen = 1; kHash3Offset = kHash2Size; kEmptyHashValue = 0; kMaxValForNormalize = (1 shl 30) - 1; var CRCTable: array [0..255] of integer; constructor TLZBinTree.Create; begin inherited Create; cyclicBufferSize:=0; cutValue:=$FF; hashSizeSum:=0; HASH_ARRAY:=true; kNumHashDirectBytes:=0; kMinMatchCheck:=4; kFixHashsize:=kHash2Size + kHash3Size; end; procedure TLZBinTree.SetType(const numHashBytes:integer); begin HASH_ARRAY := (numHashBytes > 2); if HASH_ARRAY then begin kNumHashDirectBytes := 0; kMinMatchCheck := 4; kFixHashSize := kHash2Size + kHash3Size; end else begin kNumHashDirectBytes := 2; kMinMatchCheck := 2 + 1; kFixHashSize := 0; end; end; procedure TLZBinTree.Init; var i:integer; begin inherited init; for i := 0 to hashSizeSum - 1 do hash[i] := kEmptyHashValue; cyclicBufferPos := 0; ReduceOffsets(-1); end; procedure TLZBinTree.MovePos; begin inc(cyclicBufferPos); if cyclicBufferPos >= cyclicBufferSize then cyclicBufferPos := 0; inherited MovePos; if pos = kMaxValForNormalize then Normalize; end; function TLZBinTree._Create(const historySize,keepAddBufferBefore,matchMaxLen,keepAddBufferAfter:integer):boolean; var windowReservSize:integer; cyclicBufferSize:integer; hs:integer; begin if (historySize > kMaxValForNormalize - 256) then begin result:=false; exit; end; cutValue := 16 + (matchMaxLen shr 1); windowReservSize := (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) div 2 + 256; inherited _Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); self.matchMaxLen := matchMaxLen; cyclicBufferSize := historySize + 1; if self.cyclicBufferSize <> cyclicBufferSize then begin self.cyclicBufferSize:=cyclicBufferSize; setlength(son,cyclicBufferSize * 2); end; hs := kBT2HashSize; if HASH_ARRAY then begin hs := historySize - 1; hs := hs or (hs shr 1); hs := hs or (hs shr 2); hs := hs or (hs shr 4); hs := hs or (hs shr 8); hs := hs shr 1; hs := hs or $FFFF; if (hs > (1 shl 24)) then hs := hs shr 1; hashMask := hs; inc(hs); hs := hs + kFixHashSize; end; if (hs <> hashSizeSum) then begin hashSizeSum := hs; setlength(hash,hashSizeSum); end; result:=true; end; function TLZBinTree.GetMatches(var distances:array of integer):integer; var lenLimit:integer; offset,matchMinPos,cur,maxlen,hashvalue,hash2value,hash3value:integer; temp,curmatch,curmatch2,curmatch3,ptr0,ptr1,len0,len1,count:integer; delta,cyclicpos,pby1,len:integer; begin if pos + matchMaxLen <= streamPos then lenLimit := matchMaxLen else begin lenLimit := streamPos - pos; if lenLimit < kMinMatchCheck then begin MovePos(); result:=0; exit; end; end; offset := 0; if (pos > cyclicBufferSize) then matchMinPos:=(pos - cyclicBufferSize) else matchMinPos:=0; cur := bufferOffset + pos; maxLen := kStartMaxLen; // to avoid items for len < hashSize; hash2Value := 0; hash3Value := 0; if HASH_ARRAY then begin temp := CrcTable[bufferBase[cur] and $FF] xor (bufferBase[cur + 1] and $FF); hash2Value := temp and (kHash2Size - 1); temp := temp xor ((bufferBase[cur + 2] and $FF) shl 8); hash3Value := temp and (kHash3Size - 1); hashValue := (temp xor (CrcTable[bufferBase[cur + 3] and $FF] shl 5)) and hashMask; end else hashValue := ((bufferBase[cur] and $FF) xor ((bufferBase[cur + 1] and $FF) shl 8)); curMatch := hash[kFixHashSize + hashValue]; if HASH_ARRAY then begin curMatch2 := hash[hash2Value]; curMatch3 := hash[kHash3Offset + hash3Value]; hash[hash2Value] := pos; hash[kHash3Offset + hash3Value] := pos; if curMatch2 > matchMinPos then if bufferBase[bufferOffset + curMatch2] = bufferBase[cur] then begin maxLen := 2; distances[offset] := maxLen; inc(offset); distances[offset] := pos - curMatch2 - 1; inc(offset); end; if curMatch3 > matchMinPos then if bufferBase[bufferOffset + curMatch3] = bufferBase[cur] then begin if curMatch3 = curMatch2 then offset := offset - 2; maxLen := 3; distances[offset] := maxlen; inc(offset); distances[offset] := pos - curMatch3 - 1; inc(offset); curMatch2 := curMatch3; end; if (offset <> 0) and (curMatch2 = curMatch) then begin offset := offset - 2; maxLen := kStartMaxLen; end; end; hash[kFixHashSize + hashValue] := pos; ptr0 := (cyclicBufferPos shl 1) + 1; ptr1 := (cyclicBufferPos shl 1); len0 := kNumHashDirectBytes; len1 := len0; if kNumHashDirectBytes <> 0 then begin if (curMatch > matchMinPos) then begin if (bufferBase[bufferOffset + curMatch + kNumHashDirectBytes] <> bufferBase[cur + kNumHashDirectBytes]) then begin maxLen := kNumHashDirectBytes; distances[offset] := maxLen; inc(offset); distances[offset] := pos - curMatch - 1; inc(offset); end; end; end; count := cutValue; while (true) do begin if (curMatch <= matchMinPos) or (count = 0) then begin son[ptr1] := kEmptyHashValue; son[ptr0] := son[ptr1]; break; end; dec(count); delta := pos - curMatch; if delta<=cyclicBufferPos then cyclicpos:=(cyclicBufferPos - delta) shl 1 else cyclicpos:=(cyclicBufferPos - delta + cyclicBufferSize) shl 1; pby1 := bufferOffset + curMatch; len := min(len0, len1); if bufferBase[pby1 + len] = bufferBase[cur + len] then begin inc(len); while (len <> lenLimit) do begin if (bufferBase[pby1 + len] <> bufferBase[cur + len]) then break; inc(len); end; if maxLen < len then begin maxLen := len; distances[offset] := maxlen; inc(offset); distances[offset] := delta - 1; inc(offset); if (len = lenLimit) then begin son[ptr1] := son[cyclicPos]; son[ptr0] := son[cyclicPos + 1]; break; end; end; end; if (bufferBase[pby1 + len] and $FF) < (bufferBase[cur + len] and $FF) then begin son[ptr1] := curMatch; ptr1 := cyclicPos + 1; curMatch := son[ptr1]; len1 := len; end else begin son[ptr0] := curMatch; ptr0 := cyclicPos; curMatch := son[ptr0]; len0 := len; end; end; MovePos; result:=offset; end; procedure TLZBinTree.Skip(num:integer); var lenLimit,matchminpos,cur,hashvalue,temp,hash2value,hash3value,curMatch:integer; ptr0,ptr1,len,len0,len1,count,delta,cyclicpos,pby1:integer; begin repeat if pos + matchMaxLen <= streamPos then lenLimit := matchMaxLen else begin lenLimit := streamPos - pos; if lenLimit < kMinMatchCheck then begin MovePos(); dec(num); continue; end; end; if pos>cyclicBufferSize then matchminpos:=(pos - cyclicBufferSize) else matchminpos:=0; cur := bufferOffset + pos; if HASH_ARRAY then begin temp := CrcTable[bufferBase[cur] and $FF] xor (bufferBase[cur + 1] and $FF); hash2Value := temp and (kHash2Size - 1); hash[hash2Value] := pos; temp := temp xor ((bufferBase[cur + 2] and $FF) shl 8); hash3Value := temp and (kHash3Size - 1); hash[kHash3Offset + hash3Value] := pos; hashValue := (temp xor (CrcTable[bufferBase[cur + 3] and $FF] shl 5)) and hashMask; end else hashValue := ((bufferBase[cur] and $FF) xor ((bufferBase[cur + 1] and $FF) shl 8)); curMatch := hash[kFixHashSize + hashValue]; hash[kFixHashSize + hashValue] := pos; ptr0 := (cyclicBufferPos shl 1) + 1; ptr1 := (cyclicBufferPos shl 1); len0 := kNumHashDirectBytes; len1 := kNumHashDirectBytes; count := cutValue; while true do begin if (curMatch <= matchMinPos) or (count = 0) then begin son[ptr1] := kEmptyHashValue; son[ptr0] := son[ptr1]; break; end else dec(count); delta := pos - curMatch; if (delta <= cyclicBufferPos) then cyclicpos:=(cyclicBufferPos - delta) shl 1 else cyclicpos:=(cyclicBufferPos - delta + cyclicBufferSize) shl 1; pby1 := bufferOffset + curMatch; len := min(len0, len1); if bufferBase[pby1 + len] = bufferBase[cur + len] then begin inc(len); while (len <> lenLimit) do begin if bufferBase[pby1 + len] <> bufferBase[cur + len] then break; inc(len); end; if len = lenLimit then begin son[ptr1] := son[cyclicPos]; son[ptr0] := son[cyclicPos + 1]; break; end; end; if ((bufferBase[pby1 + len] and $FF) < (bufferBase[cur + len] and $FF)) then begin son[ptr1] := curMatch; ptr1 := cyclicPos + 1; curMatch := son[ptr1]; len1 := len; end else begin son[ptr0] := curMatch; ptr0 := cyclicPos; curMatch := son[ptr0]; len0 := len; end; end; MovePos; dec(num); until num=0; end; procedure TLZBinTree.NormalizeLinks(var items:array of integer;const numItems,subValue:integer); var i,value:integer; begin for i:=0 to NumItems-1 do begin value := items[i]; if value <= subValue then value := kEmptyHashValue else value := value - subValue; items[i] := value; end; end; procedure TLZBinTree.Normalize; var subvalue:integer; begin subValue := pos - cyclicBufferSize; NormalizeLinks(son, cyclicBufferSize * 2, subValue); NormalizeLinks(hash, hashSizeSum, subValue); ReduceOffsets(subValue); end; procedure TLZBinTree.SetCutValue(const cutvalue:integer); begin self.cutValue:=cutValue; end; procedure InitCRC; var i,r,j:integer; begin for i := 0 to 255 do begin r := i; for j := 0 to 7 do if ((r and 1) <> 0) then r := (r shr 1) xor integer($EDB88320) else r := r shr 1; CrcTable[i] := r; end; end; initialization InitCRC; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZ/ULZInWindow.pas0000644000175000001440000001116514743153644025154 0ustar alexxusersunit ULZInWindow; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes; type TLZInWindow=class public bufferBase: array of byte;// pointer to buffer with data stream:TStream; posLimit:integer; // offset (from _buffer) of first byte when new block reading must be done streamEndWasReached:boolean; // if (true) then _streamPos shows real end of stream pointerToLastSafePosition:integer; bufferOffset:integer; blockSize:integer; // Size of Allocated memory block pos:integer; // offset (from _buffer) of curent byte keepSizeBefore:integer; // how many BYTEs must be kept in buffer before _pos keepSizeAfter:integer; // how many BYTEs must be kept buffer after _pos streamPos:integer; // offset (from _buffer) of first not read byte from Stream procedure MoveBlock; procedure ReadBlock; procedure _Free; procedure _Create(const keepSizeBefore, keepSizeAfter, keepSizeReserv:integer);virtual; procedure SetStream(const stream:TStream); procedure ReleaseStream; procedure Init;virtual; procedure MovePos;virtual; function GetIndexByte(const index:integer):byte; // index + limit have not to exceed _keepSizeAfter; function GetMatchLen(const index:integer;distance,limit:integer):integer; function GetNumAvailableBytes:integer; procedure ReduceOffsets(const subValue:integer); end; implementation procedure TLZInWindow.MoveBlock; var offset,numbytes,i:integer; begin offset := bufferOffset + pos - keepSizeBefore; // we need one additional byte, since MovePos moves on 1 byte. if (offset > 0) then dec(offset); numBytes := bufferOffset + streamPos - offset; // check negative offset ???? for i := 0 to numBytes -1 do bufferBase[i] := bufferBase[offset + i]; bufferOffset := bufferOffset - offset; end; procedure TLZInWindow.ReadBlock; var size,numreadbytes,pointerToPostion:integer; begin if streamEndWasReached then exit; while (true) do begin size := (0 - bufferOffset) + blockSize - streamPos; if size = 0 then exit; numReadBytes := stream.Read(bufferBase[bufferOffset + streamPos], size); if (numReadBytes = 0) then begin posLimit := streamPos; pointerToPostion := bufferOffset + posLimit; if (pointerToPostion > pointerToLastSafePosition) then posLimit := pointerToLastSafePosition - bufferOffset; streamEndWasReached := true; exit; end; streamPos := streamPos + numReadBytes; if (streamPos >= pos + keepSizeAfter) then posLimit := streamPos - keepSizeAfter; end; end; procedure TLZInWindow._Free; begin setlength(bufferBase,0); end; procedure TLZInWindow._Create(const keepSizeBefore, keepSizeAfter, keepSizeReserv:integer); var blocksize:integer; begin self.keepSizeBefore := keepSizeBefore; self.keepSizeAfter := keepSizeAfter; blockSize := keepSizeBefore + keepSizeAfter + keepSizeReserv; if (length(bufferBase) = 0) or (self.blockSize <> blockSize) then begin _Free; self.blockSize := blockSize; setlength(bufferBase,self.blockSize); end; pointerToLastSafePosition := self.blockSize - keepSizeAfter; end; procedure TLZInWindow.SetStream(const stream:TStream); begin self.stream:=stream; end; procedure TLZInWindow.ReleaseStream; begin stream:=nil; end; procedure TLZInWindow.Init; begin bufferOffset := 0; pos := 0; streamPos := 0; streamEndWasReached := false; ReadBlock; end; procedure TLZInWindow.MovePos; var pointerToPostion:integer; begin inc(pos); if pos > posLimit then begin pointerToPostion := bufferOffset + pos; if pointerToPostion > pointerToLastSafePosition then MoveBlock; ReadBlock; end; end; function TLZInWindow.GetIndexByte(const index:integer):byte; begin result:=bufferBase[bufferOffset + pos + index]; end; function TLZInWindow.GetMatchLen(const index:integer;distance,limit:integer):integer; var pby,i:integer; begin if streamEndWasReached then if (pos + index) + limit > streamPos then limit := streamPos - (pos + index); inc(distance); // Byte *pby = _buffer + (size_t)_pos + index; pby := bufferOffset + pos + index; i:=0; while (i windowSize) then setlength(buffer,windowSize); self.windowSize := windowSize; pos := 0; streamPos := 0; end; procedure TLZOutWindow.SetStream(const stream:TStream); begin ReleaseStream; self.stream:=stream; end; procedure TLZOutWindow.ReleaseStream; begin flush; self.stream:=nil; end; procedure TLZOutWindow.Init(const solid:boolean); begin if not solid then begin streamPos:=0; Pos:=0; end; end; procedure TLZOutWindow.Flush; var size:integer; begin size := pos - streamPos; if (size = 0) then exit; stream.write(buffer[streamPos], size); if (pos >= windowSize) then pos := 0; streamPos := pos; end; procedure TLZOutWindow.CopyBlock(const distance:integer;len:integer); var pos:integer; begin pos := self.pos - distance - 1; if pos < 0 then pos := pos + windowSize; while len<>0 do begin if pos >= windowSize then pos := 0; buffer[self.pos] := buffer[pos]; inc(self.pos); inc(pos); if self.pos >= windowSize then Flush(); dec(len); end; end; procedure TLZOutWindow.PutByte(const b:byte); begin buffer[pos] := b; inc(pos); if (pos >= windowSize) then Flush(); end; function TLZOutWindow.GetByte(const distance:integer):byte; var pos:integer; begin pos := self.pos - distance - 1; if (pos < 0) then pos := pos + windowSize; result:=buffer[pos]; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZMA/0000755000175000001440000000000014743153644022530 5ustar alexxusersdoublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZMA/ULZMABase.pas0000644000175000001440000000470614743153644024727 0ustar alexxusersunit ULZMABase; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface function StateInit:integer; function StateUpdateChar(const index:integer):integer; function StateUpdateMatch(const index:integer):integer; function StateUpdateRep(const index:integer):integer; function StateUpdateShortRep(const index:integer):integer; function StateIsCharState(const index:integer):boolean; function GetLenToPosState(len:integer):integer; const kNumRepDistances = 4; kNumStates = 12; kNumPosSlotBits = 6; kDicLogSizeMin = 0; // kDicLogSizeMax = 28; // kDistTableSizeMax = kDicLogSizeMax * 2; kNumLenToPosStatesBits = 2; // it's for speed optimization kNumLenToPosStates = 1 shl kNumLenToPosStatesBits; kMatchMinLen = 2; kNumAlignBits = 4; kAlignTableSize = 1 shl kNumAlignBits; kAlignMask = (kAlignTableSize - 1); kStartPosModelIndex = 4; kEndPosModelIndex = 14; kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; kNumFullDistances = 1 shl (kEndPosModelIndex div 2); kNumLitPosStatesBitsEncodingMax = 4; kNumLitContextBitsMax = 8; kNumPosStatesBitsMax = 4; kNumPosStatesMax = (1 shl kNumPosStatesBitsMax); kNumPosStatesBitsEncodingMax = 4; kNumPosStatesEncodingMax = (1 shl kNumPosStatesBitsEncodingMax); kNumLowLenBits = 3; kNumMidLenBits = 3; kNumHighLenBits = 8; kNumLowLenSymbols = 1 shl kNumLowLenBits; kNumMidLenSymbols = 1 shl kNumMidLenBits; kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + (1 shl kNumHighLenBits); kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1; implementation function StateInit:integer; begin result:=0; end; function StateUpdateChar(const index:integer):integer; begin if (index < 4) then result:=0 else if (index < 10) then result:=index - 3 else result:=index - 6; end; function StateUpdateMatch(const index:integer):integer; begin if index<7 then result:=7 else result:=10; end; function StateUpdateRep(const index:integer):integer; begin if index<7 then result:=8 else result:=11; end; function StateUpdateShortRep(const index:integer):integer; begin if index<7 then result:=9 else result:=11; end; function StateIsCharState(const index:integer):boolean; begin result:=index<7; end; function GetLenToPosState(len:integer):integer; begin len := len - kMatchMinLen; if (len < kNumLenToPosStates) then result:=len else result:=(kNumLenToPosStates - 1); end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZMA/ULZMACommon.pas0000644000175000001440000000115214743153644025275 0ustar alexxusersunit ULZMACommon; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes; type TLZMAProgressAction=(LPAMax,LPAPos); TLZMAProgress=procedure (const Action:TLZMAProgressAction;const Value:int64) of object; function ReadByte(const stream:TStream):byte; procedure WriteByte(const stream:TStream;const b:byte); const CodeProgressInterval = 50;//approx. number of times an OnProgress event will be fired during coding implementation function ReadByte(const stream:TStream):byte; begin stream.Read(result,1); end; procedure WriteByte(const stream:TStream;const b:byte); begin stream.Write(b,1); end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZMA/ULZMADecoder.pas0000644000175000001440000003414014743153644025415 0ustar alexxusersunit ULZMADecoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses ULZMABase,UBitTreeDecoder,ULZOutWindow,URangeDecoder,Math,Classes,ULZMACommon; type TLZMALenDecoder = class; TLZMALiteralDecoder = class; TLZMADecoder = class private FOnProgress:TLZMAProgress; procedure DoProgress(const Action:TLZMAProgressAction;const Value:integer); public m_OutWindow:TLZOutWindow; m_RangeDecoder:TRangeDecoder; m_IsMatchDecoders: array [0..ULZMABase.kNumStates shl ULZMABase.kNumPosStatesBitsMax-1] of smallint; m_IsRepDecoders: array [0..ULZMABase.kNumStates-1] of smallint; m_IsRepG0Decoders: array [0..ULZMABase.kNumStates-1] of smallint; m_IsRepG1Decoders: array [0..ULZMABase.kNumStates-1] of smallint; m_IsRepG2Decoders: array [0..ULZMABase.kNumStates-1] of smallint; m_IsRep0LongDecoders: array [0..ULZMABase.kNumStates shl ULZMABase.kNumPosStatesBitsMax-1] of smallint; m_PosSlotDecoder: array [0..ULZMABase.kNumLenToPosStates-1] of TBitTreeDecoder; m_PosDecoders: array [0..ULZMABase.kNumFullDistances - ULZMABase.kEndPosModelIndex-1] of smallint; m_PosAlignDecoder:TBitTreeDecoder; m_LenDecoder:TLZMALenDecoder; m_RepLenDecoder:TLZMALenDecoder; m_LiteralDecoder:TLZMALiteralDecoder; m_DictionarySize:integer; m_DictionarySizeCheck:integer; m_PosStateMask:integer; constructor Create; destructor Destroy;override; function SetDictionarySize(const dictionarySize:integer):boolean; function SetLcLpPb(const lc,lp,pb:integer):boolean; procedure Init; function Code(const inStream,outStream:TStream;outSize:int64):boolean; function SetDecoderProperties(const properties:array of byte):boolean; property OnProgress:TLZMAProgress read FOnProgress write FOnProgress; end; TLZMALenDecoder = class public m_Choice:array [0..1] of smallint; m_LowCoder: array[0..ULZMABase.kNumPosStatesMax-1] of TBitTreeDecoder; m_MidCoder: array[0..ULZMABase.kNumPosStatesMax-1] of TBitTreeDecoder; m_HighCoder: TBitTreeDecoder; m_NumPosStates:integer; constructor Create; destructor Destroy;override; procedure _Create(const numPosStates:integer); procedure Init; function Decode(const rangeDecoder:TRangeDecoder;const posState:integer):integer; end; TLZMADecoder2 = class public m_Decoders: array [0..$300-1] of smallint; procedure Init; function DecodeNormal(const rangeDecoder:TRangeDecoder):byte; function DecodeWithMatchByte(const rangeDecoder:TRangeDecoder;matchByte:byte):byte; end; TLZMALiteralDecoder = class public m_Coders: array of TLZMADecoder2; m_NumPrevBits:integer; m_NumPosBits:integer; m_PosMask:integer; procedure _Create(const numPosBits, numPrevBits:integer); procedure Init; function GetDecoder(const pos:integer;const prevByte:byte):TLZMADecoder2; destructor Destroy;override; end; implementation constructor TLZMALenDecoder.Create; begin m_HighCoder:=TBitTreeDecoder.Create(ULZMABase.kNumHighLenBits); m_NumPosStates:=0; end; destructor TLZMALenDecoder.Destroy; var i:integer; begin m_HighCoder.free; for i:=low(m_LowCoder) to high(m_LowCoder) do begin if m_LowCoder[i]<>nil then m_LowCoder[i].free; if m_MidCoder[i]<>nil then m_MidCoder[i].free; end; inherited; end; procedure TLZMALenDecoder._Create(const numPosStates:integer); begin while m_NumPosStates < numPosStates do begin m_LowCoder[m_NumPosStates] := TBitTreeDecoder.Create(ULZMABase.kNumLowLenBits); m_MidCoder[m_NumPosStates] := TBitTreeDecoder.Create(ULZMABase.kNumMidLenBits); inc(m_NumPosStates); end; end; procedure TLZMALenDecoder.Init; var posState:integer; begin URangeDecoder.InitBitModels(m_Choice); for posState := 0 to m_NumPosStates-1 do begin m_LowCoder[posState].Init; m_MidCoder[posState].Init; end; m_HighCoder.Init; end; function TLZMALenDecoder.Decode(const rangeDecoder:TRangeDecoder;const posState:integer):integer; var symbol:integer; begin if (rangeDecoder.DecodeBit(m_Choice, 0) = 0) then begin result:=m_LowCoder[posState].Decode(rangeDecoder); exit; end; symbol := ULZMABase.kNumLowLenSymbols; if (rangeDecoder.DecodeBit(m_Choice, 1) = 0) then symbol := symbol + m_MidCoder[posState].Decode(rangeDecoder) else symbol := symbol + ULZMABase.kNumMidLenSymbols + m_HighCoder.Decode(rangeDecoder); result:=symbol; end; procedure TLZMADecoder2.Init; begin URangeDecoder.InitBitModels(m_Decoders); end; function TLZMADecoder2.DecodeNormal(const rangeDecoder:TRangeDecoder):byte; var symbol:integer; begin symbol := 1; repeat symbol := (symbol shl 1) or rangeDecoder.DecodeBit(m_Decoders, symbol); until not (symbol < $100); result:= byte(symbol); end; function TLZMADecoder2.DecodeWithMatchByte(const rangeDecoder:TRangeDecoder;matchByte:byte):byte; var symbol:integer; matchbit:integer; bit:integer; begin symbol := 1; repeat matchBit := (matchByte shr 7) and 1; matchByte := byte(matchByte shl 1); bit := rangeDecoder.DecodeBit(m_Decoders, ((1 + matchBit) shl 8) + symbol); symbol := (symbol shl 1) or bit; if (matchBit <> bit) then begin while (symbol < $100) do begin symbol := (symbol shl 1) or rangeDecoder.DecodeBit(m_Decoders, symbol); end; break; end; until not (symbol < $100); result:= byte(symbol); end; procedure TLZMALiteralDecoder._Create(const numPosBits, numPrevBits:integer); var numStates,i:integer; begin if (length(m_Coders) <> 0) and (m_NumPrevBits = numPrevBits) and (m_NumPosBits = numPosBits) then exit; m_NumPosBits := numPosBits; m_PosMask := (1 shl numPosBits) - 1; m_NumPrevBits := numPrevBits; numStates := 1 shl (m_NumPrevBits + m_NumPosBits); setlength(m_Coders,numStates); for i :=0 to numStates-1 do m_Coders[i] := TLZMADecoder2.Create; end; destructor TLZMALiteralDecoder.Destroy; var i:integer; begin for i :=low(m_Coders) to high(m_Coders) do if m_Coders[i]<>nil then m_Coders[i].Free; inherited; end; procedure TLZMALiteralDecoder.Init; var numStates,i:integer; begin numStates := 1 shl (m_NumPrevBits + m_NumPosBits); for i := 0 to numStates -1 do m_Coders[i].Init; end; function TLZMALiteralDecoder.GetDecoder(const pos:integer;const prevByte:byte):TLZMADecoder2; begin result:=m_Coders[((pos and m_PosMask) shl m_NumPrevBits) + ((prevByte and $FF) shr (8 - m_NumPrevBits))]; end; constructor TLZMADecoder.Create; var i:integer; begin FOnProgress:=nil; m_OutWindow:=TLZOutWindow.Create; m_RangeDecoder:=TRangeDecoder.Create; m_PosAlignDecoder:=TBitTreeDecoder.Create(ULZMABase.kNumAlignBits); m_LenDecoder:=TLZMALenDecoder.Create; m_RepLenDecoder:=TLZMALenDecoder.Create; m_LiteralDecoder:=TLZMALiteralDecoder.Create; m_DictionarySize:= -1; m_DictionarySizeCheck:= -1; for i := 0 to ULZMABase.kNumLenToPosStates -1 do m_PosSlotDecoder[i] :=TBitTreeDecoder.Create(ULZMABase.kNumPosSlotBits); end; destructor TLZMADecoder.Destroy; var i:integer; begin m_OutWindow.Free; m_RangeDecoder.Free; m_PosAlignDecoder.Free; m_LenDecoder.Free; m_RepLenDecoder.Free; m_LiteralDecoder.Free; for i := 0 to ULZMABase.kNumLenToPosStates -1 do m_PosSlotDecoder[i].Free; end; function TLZMADecoder.SetDictionarySize(const dictionarySize:integer):boolean; begin if dictionarySize < 0 then result:=false else begin if m_DictionarySize <> dictionarySize then begin m_DictionarySize := dictionarySize; m_DictionarySizeCheck := max(m_DictionarySize, 1); m_OutWindow._Create(max(m_DictionarySizeCheck, (1 shl 12))); end; result:=true; end; end; function TLZMADecoder.SetLcLpPb(const lc,lp,pb:integer):boolean; var numPosStates:integer; begin if (lc > ULZMABase.kNumLitContextBitsMax) or (lp > 4) or (pb > ULZMABase.kNumPosStatesBitsMax) then begin result:=false; exit; end; m_LiteralDecoder._Create(lp, lc); numPosStates := 1 shl pb; m_LenDecoder._Create(numPosStates); m_RepLenDecoder._Create(numPosStates); m_PosStateMask := numPosStates - 1; result:=true; end; procedure TLZMADecoder.Init; var i:integer; begin m_OutWindow.Init(false); URangeDecoder.InitBitModels(m_IsMatchDecoders); URangeDecoder.InitBitModels(m_IsRep0LongDecoders); URangeDecoder.InitBitModels(m_IsRepDecoders); URangeDecoder.InitBitModels(m_IsRepG0Decoders); URangeDecoder.InitBitModels(m_IsRepG1Decoders); URangeDecoder.InitBitModels(m_IsRepG2Decoders); URangeDecoder.InitBitModels(m_PosDecoders); m_LiteralDecoder.Init(); for i := 0 to ULZMABase.kNumLenToPosStates -1 do m_PosSlotDecoder[i].Init; m_LenDecoder.Init; m_RepLenDecoder.Init; m_PosAlignDecoder.Init; m_RangeDecoder.Init; end; function TLZMADecoder.Code(const inStream,outStream:TStream;outSize:int64):boolean; var state,rep0,rep1,rep2,rep3:integer; nowPos64:int64; prevByte:byte; posState:integer; decoder2:TLZMADecoder2; len,distance,posSlot,numDirectBits:integer; lpos:int64; progint:int64; begin DoProgress(LPAMax,outSize); m_RangeDecoder.SetStream(inStream); m_OutWindow.SetStream(outStream); Init; state := ULZMABase.StateInit; rep0 := 0; rep1 := 0; rep2 := 0; rep3 := 0; nowPos64 := 0; prevByte := 0; progint:=outsize div CodeProgressInterval; lpos:=progint; while (outSize < 0) or (nowPos64 < outSize) do begin if (nowPos64 >=lpos) then begin DoProgress(LPAPos,nowPos64); lpos:=lpos+progint; end; posState := nowPos64 and m_PosStateMask; if (m_RangeDecoder.DecodeBit(m_IsMatchDecoders, (state shl ULZMABase.kNumPosStatesBitsMax) + posState) = 0) then begin decoder2 := m_LiteralDecoder.GetDecoder(nowPos64, prevByte); if not ULZMABase.StateIsCharState(state) then prevByte := decoder2.DecodeWithMatchByte(m_RangeDecoder, m_OutWindow.GetByte(rep0)) else prevByte := decoder2.DecodeNormal(m_RangeDecoder); m_OutWindow.PutByte(prevByte); state := ULZMABase.StateUpdateChar(state); inc(nowPos64); end else begin if (m_RangeDecoder.DecodeBit(m_IsRepDecoders, state) = 1) then begin len := 0; if (m_RangeDecoder.DecodeBit(m_IsRepG0Decoders, state) = 0) then begin if (m_RangeDecoder.DecodeBit(m_IsRep0LongDecoders, (state shl ULZMABase.kNumPosStatesBitsMax) + posState) = 0) then begin state := ULZMABase.StateUpdateShortRep(state); len := 1; end; end else begin if m_RangeDecoder.DecodeBit(m_IsRepG1Decoders, state) = 0 then distance := rep1 else begin if (m_RangeDecoder.DecodeBit(m_IsRepG2Decoders, state) = 0) then distance := rep2 else begin distance := rep3; rep3 := rep2; end; rep2 := rep1; end; rep1 := rep0; rep0 := distance; end; if len = 0 then begin len := m_RepLenDecoder.Decode(m_RangeDecoder, posState) + ULZMABase.kMatchMinLen; state := ULZMABase.StateUpdateRep(state); end; end else begin rep3 := rep2; rep2 := rep1; rep1 := rep0; len := ULZMABase.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState); state := ULZMABase.StateUpdateMatch(state); posSlot := m_PosSlotDecoder[ULZMABase.GetLenToPosState(len)].Decode(m_RangeDecoder); if posSlot >= ULZMABase.kStartPosModelIndex then begin numDirectBits := (posSlot shr 1) - 1; rep0 := ((2 or (posSlot and 1)) shl numDirectBits); if posSlot < ULZMABase.kEndPosModelIndex then rep0 := rep0 + UBitTreeDecoder.ReverseDecode(m_PosDecoders, rep0 - posSlot - 1, m_RangeDecoder, numDirectBits) else begin rep0 := rep0 + (m_RangeDecoder.DecodeDirectBits( numDirectBits - ULZMABase.kNumAlignBits) shl ULZMABase.kNumAlignBits); rep0 := rep0 + m_PosAlignDecoder.ReverseDecode(m_RangeDecoder); if rep0 < 0 then begin if rep0 = -1 then break; result:=false; exit; end; end; end else rep0 := posSlot; end; if (rep0 >= nowPos64) or (rep0 >= m_DictionarySizeCheck) then begin m_OutWindow.Flush(); result:=false; exit; end; m_OutWindow.CopyBlock(rep0, len); nowPos64 := nowPos64 + len; prevByte := m_OutWindow.GetByte(0); end; end; m_OutWindow.Flush(); m_OutWindow.ReleaseStream(); m_RangeDecoder.ReleaseStream(); DoProgress(LPAPos,nowPos64); result:=true; end; function TLZMADecoder.SetDecoderProperties(const properties:array of byte):boolean; var val,lc,remainder,lp,pb,dictionarysize,i:integer; begin if length(properties) < 5 then begin result:=false; exit; end; val := properties[0] and $FF; lc := val mod 9; remainder := val div 9; lp := remainder mod 5; pb := remainder div 5; dictionarySize := 0; for i := 0 to 3 do dictionarySize := dictionarysize + ((properties[1 + i]) and $FF) shl (i * 8); if (not SetLcLpPb(lc, lp, pb)) then begin result:=false; exit; end; result:=SetDictionarySize(dictionarySize); end; procedure TLZMADecoder.DoProgress(const Action:TLZMAProgressAction;const Value:integer); begin if assigned(fonprogress) then fonprogress(action,value); end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/LZMA/ULZMAEncoder.pas0000644000175000001440000015275214743153644025441 0ustar alexxusersunit ULZMAEncoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses UBitTreeEncoder,ULZMABase,ULZBinTree,URangeEncoder,Classes,Math,ULZMACommon; const EMatchFinderTypeBT2 = 0; EMatchFinderTypeBT4 = 1; kIfinityPrice:integer = $FFFFFFF; kDefaultDictionaryLogSize = 22; kNumFastBytesDefault = $20; kNumLenSpecSymbols = ULZMABase.kNumLowLenSymbols + ULZMABase.kNumMidLenSymbols; kNumOpts = 1 shl 12; kPropSize = 5; type TLZMAEncoder2=class; TLZMALiteralEncoder=class; TLZMAOptimal=class; TLZMALenPriceTableEncoder=class; TLZMAEncoder=class private FOnProgress:TLZMAProgress; procedure DoProgress(const Action:TLZMAProgressAction;const Value:integer); public g_FastPos:array [0..1 shl 11-1] of byte; _state:integer; _previousByte:byte; _repDistances:array [0..ULZMABase.kNumRepDistances-1] of integer; _optimum: array [0..kNumOpts-1] of TLZMAOptimal; _matchFinder:TLZBinTree; _rangeEncoder:TRangeEncoder; _isMatch:array [0..ULZMABase.kNumStates shl ULZMABase.kNumPosStatesBitsMax-1]of smallint; _isRep:array [0..ULZMABase.kNumStates-1] of smallint; _isRepG0:array [0..ULZMABase.kNumStates-1] of smallint; _isRepG1:array [0..ULZMABase.kNumStates-1] of smallint; _isRepG2:array [0..ULZMABase.kNumStates-1] of smallint; _isRep0Long:array [0..ULZMABase.kNumStates shl ULZMABase.kNumPosStatesBitsMax-1]of smallint; _posSlotEncoder:array [0..ULZMABase.kNumLenToPosStates-1] of TBitTreeEncoder; // kNumPosSlotBits _posEncoders:array [0..ULZMABase.kNumFullDistances-ULZMABase.kEndPosModelIndex-1]of smallint; _posAlignEncoder:TBitTreeEncoder; _lenEncoder:TLZMALenPriceTableEncoder; _repMatchLenEncoder:TLZMALenPriceTableEncoder; _literalEncoder:TLZMALiteralEncoder; _matchDistances:array [0..ULZMABase.kMatchMaxLen*2+1] of integer; _numFastBytes:integer; _longestMatchLength:integer; _numDistancePairs:integer; _additionalOffset:integer; _optimumEndIndex:integer; _optimumCurrentIndex:integer; _longestMatchWasFound:boolean; _posSlotPrices:array [0..1 shl (ULZMABase.kNumPosSlotBits+ULZMABase.kNumLenToPosStatesBits)-1] of integer; _distancesPrices:array [0..ULZMABase.kNumFullDistances shl ULZMABase.kNumLenToPosStatesBits-1] of integer; _alignPrices:array [0..ULZMABase.kAlignTableSize-1] of integer; _alignPriceCount:integer; _distTableSize:integer; _posStateBits:integer; _posStateMask:integer; _numLiteralPosStateBits:integer; _numLiteralContextBits:integer; _dictionarySize:integer; _dictionarySizePrev:integer; _numFastBytesPrev:integer; nowPos64:int64; _finished:boolean; _inStream:TStream; _matchFinderType:integer; _writeEndMark:boolean; _needReleaseMFStream:boolean; reps:array [0..ULZMABase.kNumRepDistances-1]of integer; repLens:array [0..ULZMABase.kNumRepDistances-1] of integer; backRes:integer; processedInSize:int64; processedOutSize:int64; finished:boolean; properties:array [0..kPropSize] of byte; tempPrices:array [0..ULZMABase.kNumFullDistances-1]of integer; _matchPriceCount:integer; constructor Create; destructor Destroy;override; function GetPosSlot(const pos:integer):integer; function GetPosSlot2(const pos:integer):integer; procedure BaseInit; procedure _Create; procedure SetWriteEndMarkerMode(const writeEndMarker:boolean); procedure Init; function ReadMatchDistances:integer; procedure MovePos(const num:integer); function GetRepLen1Price(const state,posState:integer):integer; function GetPureRepPrice(const repIndex, state, posState:integer):integer; function GetRepPrice(const repIndex, len, state, posState:integer):integer; function GetPosLenPrice(const pos, len, posState:integer):integer; function Backward(cur:integer):integer; function GetOptimum(position:integer):integer; function ChangePair(const smallDist, bigDist:integer):boolean; procedure WriteEndMarker(const posState:integer); procedure Flush(const nowPos:integer); procedure ReleaseMFStream; procedure CodeOneBlock(var inSize,outSize:int64;var finished:boolean); procedure FillDistancesPrices; procedure FillAlignPrices; procedure SetOutStream(const outStream:TStream); procedure ReleaseOutStream; procedure ReleaseStreams; procedure SetStreams(const inStream, outStream:TStream;const inSize, outSize:int64); procedure Code(const inStream, outStream:TStream;const inSize, outSize:int64); procedure WriteCoderProperties(const outStream:TStream); function SetAlgorithm(const algorithm:integer):boolean; function SetDictionarySize(dictionarySize:integer):boolean; function SeNumFastBytes(const numFastBytes:integer):boolean; function SetMatchFinder(const matchFinderIndex:integer):boolean; function SetLcLpPb(const lc,lp,pb:integer):boolean; procedure SetEndMarkerMode(const endMarkerMode:boolean); property OnProgress:TLZMAProgress read FOnProgress write FOnProgress; end; TLZMALiteralEncoder=class public m_Coders: array of TLZMAEncoder2; m_NumPrevBits:integer; m_NumPosBits:integer; m_PosMask:integer; procedure _Create(const numPosBits,numPrevBits:integer); destructor Destroy;override; procedure Init; function GetSubCoder(const pos:integer;const prevByte:byte):TLZMAEncoder2; end; TLZMAEncoder2=class public m_Encoders: array[0..$300-1] of smallint; procedure Init; procedure Encode(const rangeEncoder:TRangeEncoder;const symbol:byte); procedure EncodeMatched(const rangeEncoder:TRangeEncoder;const matchByte,symbol:byte); function GetPrice(const matchMode:boolean;const matchByte,symbol:byte):integer; end; TLZMALenEncoder=class public _choice:array[0..1] of smallint; _lowCoder: array [0..ULZMABase.kNumPosStatesEncodingMax-1] of TBitTreeEncoder; _midCoder: array [0..ULZMABase.kNumPosStatesEncodingMax-1] of TBitTreeEncoder; _highCoder:TBitTreeEncoder; constructor Create; destructor Destroy;override; procedure Init(const numPosStates:integer); procedure Encode(const rangeEncoder:TRangeEncoder;symbol:integer;const posState:integer);virtual; procedure SetPrices(const posState,numSymbols:integer;var prices:array of integer;const st:integer); end; TLZMALenPriceTableEncoder=class(TLZMALenEncoder) public _prices: array [0..ULZMABase.kNumLenSymbols shl ULZMABase.kNumPosStatesBitsEncodingMax-1] of integer; _tableSize:integer; _counters: array [0..ULZMABase.kNumPosStatesEncodingMax-1] of integer; procedure SetTableSize(const tableSize:integer); function GetPrice(const symbol,posState:integer):integer; procedure UpdateTable(const posState:integer); procedure UpdateTables(const numPosStates:integer); procedure Encode(const rangeEncoder:TRangeEncoder;symbol:integer;const posState:integer);override; end; TLZMAOptimal=class public State:integer; Prev1IsChar:boolean; Prev2:boolean; PosPrev2:integer; BackPrev2:integer; Price:integer; PosPrev:integer; BackPrev:integer; Backs0:integer; Backs1:integer; Backs2:integer; Backs3:integer; procedure MakeAsChar; procedure MakeAsShortRep; function IsShortRep:boolean; end; implementation constructor TLZMAEncoder.Create; var kFastSlots,c,slotFast,j,k:integer; begin kFastSlots := 22; c := 2; g_FastPos[0] := 0; g_FastPos[1] := 1; for slotFast := 2 to kFastSlots -1 do begin k := (1 shl ((slotFast shr 1) - 1)); for j := 0 to k -1 do begin g_FastPos[c] := slotFast; inc(c); end; end; _state := ULZMABase.StateInit(); _matchFinder:=nil; _rangeEncoder:=TRangeEncoder.Create; _posAlignEncoder:=TBitTreeEncoder.Create(ULZMABase.kNumAlignBits); _lenEncoder:=TLZMALenPriceTableEncoder.Create; _repMatchLenEncoder:=TLZMALenPriceTableEncoder.Create; _literalEncoder:=TLZMALiteralEncoder.Create; _numFastBytes:= kNumFastBytesDefault; _distTableSize:= (kDefaultDictionaryLogSize * 2); _posStateBits:= 2; _posStateMask:= (4 - 1); _numLiteralPosStateBits:= 0; _numLiteralContextBits:= 3; _dictionarySize:= (1 shl kDefaultDictionaryLogSize); _dictionarySizePrev:= -1; _numFastBytesPrev:= -1; _matchFinderType:= EMatchFinderTypeBT4; _writeEndMark:= false; _needReleaseMFStream:= false; end; destructor TLZMAEncoder.Destroy; var i:integer; begin _rangeEncoder.Free; _posAlignEncoder.Free; _lenEncoder.Free; _repMatchLenEncoder.Free; _literalEncoder.Free; if _matchFinder<>nil then _matchFinder.Free; for i := 0 to kNumOpts -1 do _optimum[i].Free; for i := 0 to ULZMABase.kNumLenToPosStates -1 do _posSlotEncoder[i].Free; end; procedure TLZMAEncoder._Create; var bt:TLZBinTree; numHashBytes,i:integer; begin if _matchFinder = nil then begin bt := TLZBinTree.Create; numHashBytes:= 4; if _matchFinderType = EMatchFinderTypeBT2 then numHashBytes := 2; bt.SetType(numHashBytes); _matchFinder := bt; end; _literalEncoder._Create(_numLiteralPosStateBits, _numLiteralContextBits); if (_dictionarySize = _dictionarySizePrev) and (_numFastBytesPrev = _numFastBytes) then exit; _matchFinder._Create(_dictionarySize, kNumOpts, _numFastBytes, ULZMABase.kMatchMaxLen + 1); _dictionarySizePrev := _dictionarySize; _numFastBytesPrev := _numFastBytes; for i := 0 to kNumOpts -1 do _optimum[i]:=TLZMAOptimal.Create; for i := 0 to ULZMABase.kNumLenToPosStates -1 do _posSlotEncoder[i] :=TBitTreeEncoder.Create(ULZMABase.kNumPosSlotBits); end; function TLZMAEncoder.GetPosSlot(const pos:integer):integer; begin if (pos < (1 shl 11)) then result:=g_FastPos[pos] else if (pos < (1 shl 21)) then result:=(g_FastPos[pos shr 10] + 20) else result:=(g_FastPos[pos shr 20] + 40); end; function TLZMAEncoder.GetPosSlot2(const pos:integer):integer; begin if (pos < (1 shl 17)) then result:=(g_FastPos[pos shr 6] + 12) else if (pos < (1 shl 27)) then result:=(g_FastPos[pos shr 16] + 32) else result:=(g_FastPos[pos shr 26] + 52); end; procedure TLZMAEncoder.BaseInit; var i:integer; begin _state := ulzmaBase.StateInit; _previousByte := 0; for i := 0 to ULZMABase.kNumRepDistances -1 do _repDistances[i] := 0; end; procedure TLZMAEncoder.SetWriteEndMarkerMode(const writeEndMarker:boolean); begin _writeEndMark := writeEndMarker; end; procedure TLZMAEncoder.Init; var i:integer; begin BaseInit; _rangeEncoder.Init; URangeEncoder.InitBitModels(_isMatch); URangeEncoder.InitBitModels(_isRep0Long); URangeEncoder.InitBitModels(_isRep); URangeEncoder.InitBitModels(_isRepG0); URangeEncoder.InitBitModels(_isRepG1); URangeEncoder.InitBitModels(_isRepG2); URangeEncoder.InitBitModels(_posEncoders); _literalEncoder.Init(); for i := 0 to ULZMABase.kNumLenToPosStates -1 do _posSlotEncoder[i].Init; _lenEncoder.Init(1 shl _posStateBits); _repMatchLenEncoder.Init(1 shl _posStateBits); _posAlignEncoder.Init; _longestMatchWasFound := false; _optimumEndIndex := 0; _optimumCurrentIndex := 0; _additionalOffset := 0; end; function TLZMAEncoder.ReadMatchDistances:integer; var lenRes:integer; begin lenRes := 0; _numDistancePairs := _matchFinder.GetMatches(_matchDistances); if _numDistancePairs > 0 then begin lenRes := _matchDistances[_numDistancePairs - 2]; if lenRes = _numFastBytes then lenRes := lenRes + _matchFinder.GetMatchLen(lenRes - 1, _matchDistances[_numDistancePairs - 1], ULZMABase.kMatchMaxLen - lenRes); end; inc(_additionalOffset); result:=lenRes; end; procedure TLZMAEncoder.MovePos(const num:integer); begin if num > 0 then begin _matchFinder.Skip(num); _additionalOffset := _additionalOffset + num; end; end; function TLZMAEncoder.GetRepLen1Price(const state,posState:integer):integer; begin result:=RangeEncoder.GetPrice0(_isRepG0[state]) + RangeEncoder.GetPrice0(_isRep0Long[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]); end; function TLZMAEncoder.GetPureRepPrice(const repIndex, state, posState:integer):integer; var price:integer; begin if repIndex = 0 then begin price := RangeEncoder.GetPrice0(_isRepG0[state]); price := price + RangeEncoder.GetPrice1(_isRep0Long[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]); end else begin price := RangeEncoder.GetPrice1(_isRepG0[state]); if repIndex = 1 then price := price + RangeEncoder.GetPrice0(_isRepG1[state]) else begin price := price + RangeEncoder.GetPrice1(_isRepG1[state]); price := price + RangeEncoder.GetPrice(_isRepG2[state], repIndex - 2); end; end; result:=price; end; function TLZMAEncoder.GetRepPrice(const repIndex, len, state, posState:integer):integer; var price:integer; begin price := _repMatchLenEncoder.GetPrice(len - ULZMABase.kMatchMinLen, posState); result := price + GetPureRepPrice(repIndex, state, posState); end; function TLZMAEncoder.GetPosLenPrice(const pos, len, posState:integer):integer; var price,lenToPosState:integer; begin lenToPosState := ULZMABase.GetLenToPosState(len); if pos < ULZMABase.kNumFullDistances then price := _distancesPrices[(lenToPosState * ULZMABase.kNumFullDistances) + pos] else price := _posSlotPrices[(lenToPosState shl ULZMABase.kNumPosSlotBits) + GetPosSlot2(pos)] + _alignPrices[pos and ULZMABase.kAlignMask]; result := price + _lenEncoder.GetPrice(len - ULZMABase.kMatchMinLen, posState); end; function TLZMAEncoder.Backward(cur:integer):integer; var posMem,backMem,posPrev,backCur:integer; begin _optimumEndIndex := cur; posMem := _optimum[cur].PosPrev; backMem := _optimum[cur].BackPrev; repeat if _optimum[cur].Prev1IsChar then begin _optimum[posMem].MakeAsChar; _optimum[posMem].PosPrev := posMem - 1; if _optimum[cur].Prev2 then begin _optimum[posMem - 1].Prev1IsChar := false; _optimum[posMem - 1].PosPrev := _optimum[cur].PosPrev2; _optimum[posMem - 1].BackPrev := _optimum[cur].BackPrev2; end; end; posPrev := posMem; backCur := backMem; backMem := _optimum[posPrev].BackPrev; posMem := _optimum[posPrev].PosPrev; _optimum[posPrev].BackPrev := backCur; _optimum[posPrev].PosPrev := cur; cur := posPrev; until not (cur > 0); backRes := _optimum[0].BackPrev; _optimumCurrentIndex := _optimum[0].PosPrev; result:=_optimumCurrentIndex; end; function TLZMAEncoder.GetOptimum(position:integer):integer; var lenRes,lenMain,numDistancePairs,numAvailableBytes,repMaxIndex,i:integer; matchPrice,repMatchPrice,shortRepPrice,lenEnd,len,repLen,price:integer; curAndLenPrice,normalMatchPrice,Offs,distance,cur,newLen:integer; posPrev,state,pos,curPrice,curAnd1Price,numAvailableBytesFull:integer; lenTest2,t,state2,posStateNext,nextRepMatchPrice,offset:integer; startLen,repIndex,lenTest,lenTestTemp,curAndLenCharPrice:integer; nextMatchPrice,curBack:integer; optimum,opt,nextOptimum:TLZMAOptimal; currentByte,matchByte,posState:byte; nextIsChar:boolean; begin if (_optimumEndIndex <> _optimumCurrentIndex) then begin lenRes := _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex; backRes := _optimum[_optimumCurrentIndex].BackPrev; _optimumCurrentIndex := _optimum[_optimumCurrentIndex].PosPrev; result:=lenRes; exit; end;//if optimumendindex _optimumCurrentIndex := 0; _optimumEndIndex := 0; if not _longestMatchWasFound then begin lenMain := ReadMatchDistances(); end else begin //if not longest lenMain := _longestMatchLength; _longestMatchWasFound := false; end;//if not longest else numDistancePairs := _numDistancePairs; numAvailableBytes := _matchFinder.GetNumAvailableBytes + 1; if numAvailableBytes < 2 then begin backRes := -1; result:=1; exit; end;//if numavailable {if numAvailableBytes > ULZMABase.kMatchMaxLen then numAvailableBytes := ULZMABase.kMatchMaxLen;} repMaxIndex := 0; for i := 0 to ULZMABase.kNumRepDistances-1 do begin reps[i] := _repDistances[i]; repLens[i] := _matchFinder.GetMatchLen(0 - 1, reps[i], ULZMABase.kMatchMaxLen); if repLens[i] > repLens[repMaxIndex] then repMaxIndex := i; end;//for i if repLens[repMaxIndex] >= _numFastBytes then begin backRes := repMaxIndex; lenRes := repLens[repMaxIndex]; MovePos(lenRes - 1); result:=lenRes; exit; end;//if replens[] if lenMain >= _numFastBytes then begin backRes := _matchDistances[numDistancePairs - 1] + ULZMABase.kNumRepDistances; MovePos(lenMain - 1); result:=lenMain; exit; end;//if lenMain currentByte := _matchFinder.GetIndexByte(0 - 1); matchByte := _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1); if (lenMain < 2) and (currentByte <> matchByte) and (repLens[repMaxIndex] < 2) then begin backRes := -1; result:=1; exit; end;//if lenmain<2 _optimum[0].State := _state; posState := (position and _posStateMask); _optimum[1].Price := RangeEncoder.GetPrice0(_isMatch[(_state shl ULZMABase.kNumPosStatesBitsMax) + posState]) + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(not ULZMABase.StateIsCharState(_state), matchByte, currentByte); _optimum[1].MakeAsChar(); matchPrice := RangeEncoder.GetPrice1(_isMatch[(_state shl ULZMABase.kNumPosStatesBitsMax) + posState]); repMatchPrice := matchPrice + RangeEncoder.GetPrice1(_isRep[_state]); if matchByte = currentByte then begin shortRepPrice := repMatchPrice + GetRepLen1Price(_state, posState); if shortRepPrice < _optimum[1].Price then begin _optimum[1].Price := shortRepPrice; _optimum[1].MakeAsShortRep; end;//if shortrepprice end;//if matchbyte if lenMain >= repLens[repMaxIndex] then lenEnd:=lenMain else lenEnd:=repLens[repMaxIndex]; if lenEnd < 2 then begin backRes := _optimum[1].BackPrev; result:=1; exit; end;//if lenend<2 _optimum[1].PosPrev := 0; _optimum[0].Backs0 := reps[0]; _optimum[0].Backs1 := reps[1]; _optimum[0].Backs2 := reps[2]; _optimum[0].Backs3 := reps[3]; len := lenEnd; repeat _optimum[len].Price := kIfinityPrice; dec(len); until not (len >= 2); for i := 0 to ULZMABase.kNumRepDistances -1 do begin repLen := repLens[i]; if repLen < 2 then continue; price := repMatchPrice + GetPureRepPrice(i, _state, posState); repeat curAndLenPrice := price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); optimum := _optimum[repLen]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := 0; optimum.BackPrev := i; optimum.Prev1IsChar := false; end;//if curandlenprice dec(replen); until not (repLen >= 2); end;//for i normalMatchPrice := matchPrice + RangeEncoder.GetPrice0(_isRep[_state]); if repLens[0] >= 2 then len:=repLens[0] + 1 else len:=2; if len <= lenMain then begin offs := 0; while len > _matchDistances[offs] do offs := offs + 2; while (true) do begin distance := _matchDistances[offs + 1]; curAndLenPrice := normalMatchPrice + GetPosLenPrice(distance, len, posState); optimum := _optimum[len]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := 0; optimum.BackPrev := distance + ULZMABase.kNumRepDistances; optimum.Prev1IsChar := false; end;//if curlenandprice if len = _matchDistances[offs] then begin offs := offs + 2; if offs = numDistancePairs then break; end;//if len=_match inc(len); end;//while (true) end;//if len<=lenmain cur := 0; while (true) do begin inc(cur); if cur = lenEnd then begin result:=Backward(cur); exit; end;//if cur=lenEnd newLen := ReadMatchDistances; numDistancePairs := _numDistancePairs; if newLen >= _numFastBytes then begin _longestMatchLength := newLen; _longestMatchWasFound := true; result:=Backward(cur); exit; end;//if newlen=_numfast inc(position); posPrev := _optimum[cur].PosPrev; if _optimum[cur].Prev1IsChar then begin dec(posPrev); if _optimum[cur].Prev2 then begin state := _optimum[_optimum[cur].PosPrev2].State; if _optimum[cur].BackPrev2 < ULZMABase.kNumRepDistances then state := ULZMABase.StateUpdateRep(state) else state := ULZMABase.StateUpdateMatch(state); end//if _optimum[cur].Prev2 else state := _optimum[posPrev].State; state := ULZMABase.StateUpdateChar(state); end//if _optimum[cur].Prev1IsChar else state := _optimum[posPrev].State; if posPrev = cur - 1 then begin if _optimum[cur].IsShortRep then state := ULZMABase.StateUpdateShortRep(state) else state := ULZMABase.StateUpdateChar(state); end //if posPrev = cur - 1 else begin if _optimum[cur].Prev1IsChar and _optimum[cur].Prev2 then begin posPrev := _optimum[cur].PosPrev2; pos := _optimum[cur].BackPrev2; state := ULZMABase.StateUpdateRep(state); end//if _optimum[cur].Prev1IsChar else begin pos := _optimum[cur].BackPrev; if pos < ULZMABase.kNumRepDistances then state := ULZMABase.StateUpdateRep(state) else state := ULZMABase.StateUpdateMatch(state); end;//if else _optimum[cur].Prev1IsChar opt := _optimum[posPrev]; if pos < ULZMABase.kNumRepDistances then begin if pos = 0 then begin reps[0] := opt.Backs0; reps[1] := opt.Backs1; reps[2] := opt.Backs2; reps[3] := opt.Backs3; end//if pos=0 else if pos = 1 then begin reps[0] := opt.Backs1; reps[1] := opt.Backs0; reps[2] := opt.Backs2; reps[3] := opt.Backs3; end //if pos=1 else if pos = 2 then begin reps[0] := opt.Backs2; reps[1] := opt.Backs0; reps[2] := opt.Backs1; reps[3] := opt.Backs3; end//if pos=2 else begin reps[0] := opt.Backs3; reps[1] := opt.Backs0; reps[2] := opt.Backs1; reps[3] := opt.Backs2; end;//else if pos= end// if pos < ULZMABase.kNumRepDistances else begin reps[0] := (pos - ULZMABase.kNumRepDistances); reps[1] := opt.Backs0; reps[2] := opt.Backs1; reps[3] := opt.Backs2; end;//if else pos < ULZMABase.kNumRepDistances end;//if else posPrev = cur - 1 _optimum[cur].State := state; _optimum[cur].Backs0 := reps[0]; _optimum[cur].Backs1 := reps[1]; _optimum[cur].Backs2 := reps[2]; _optimum[cur].Backs3 := reps[3]; curPrice := _optimum[cur].Price; currentByte := _matchFinder.GetIndexByte(0 - 1); matchByte := _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1); posState := (position and _posStateMask); curAnd1Price := curPrice + RangeEncoder.GetPrice0(_isMatch[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]) + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)). GetPrice(not ULZMABase.StateIsCharState(state), matchByte, currentByte); nextOptimum := _optimum[cur + 1]; nextIsChar := false; if curAnd1Price < nextOptimum.Price then begin nextOptimum.Price := curAnd1Price; nextOptimum.PosPrev := cur; nextOptimum.MakeAsChar; nextIsChar := true; end;//if curand1price matchPrice := curPrice + RangeEncoder.GetPrice1(_isMatch[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]); repMatchPrice := matchPrice + RangeEncoder.GetPrice1(_isRep[state]); if (matchByte = currentByte) and (not ((nextOptimum.PosPrev < cur) and (nextOptimum.BackPrev = 0))) then begin shortRepPrice := repMatchPrice + GetRepLen1Price(state, posState); if shortRepPrice <= nextOptimum.Price then begin nextOptimum.Price := shortRepPrice; nextOptimum.PosPrev := cur; nextOptimum.MakeAsShortRep; nextIsChar := true; end;//if shortRepPrice <= nextOptimum.Price end;//if (matchByte = currentByte) and numAvailableBytesFull := _matchFinder.GetNumAvailableBytes + 1; numAvailableBytesFull := min(kNumOpts - 1 - cur, numAvailableBytesFull); numAvailableBytes := numAvailableBytesFull; if numAvailableBytes < 2 then continue; if numAvailableBytes > _numFastBytes then numAvailableBytes := _numFastBytes; if (not nextIsChar) and (matchByte <> currentByte) then begin // try Literal + rep0 t := min(numAvailableBytesFull - 1, _numFastBytes); lenTest2 := _matchFinder.GetMatchLen(0, reps[0], t); if lenTest2 >= 2 then begin state2 := ULZMABase.StateUpdateChar(state); posStateNext := (position + 1) and _posStateMask; nextRepMatchPrice := curAnd1Price + RangeEncoder.GetPrice1(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]) + RangeEncoder.GetPrice1(_isRep[state2]); begin offset := cur + 1 + lenTest2; while lenEnd < offset do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenend curAndLenPrice := nextRepMatchPrice + GetRepPrice( 0, lenTest2, state2, posStateNext); optimum := _optimum[offset]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur + 1; optimum.BackPrev := 0; optimum.Prev1IsChar := true; optimum.Prev2 := false; end;//if curandlenprice end;//none end;//if lentest end;//if not nextischar and ... startLen := 2; // speed optimization for repIndex := 0 to ULZMABase.kNumRepDistances -1 do begin lenTest := _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes); if lenTest < 2 then continue; lenTestTemp := lenTest; repeat while lenEnd < cur + lenTest do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd curAndLenPrice := repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); optimum := _optimum[cur + lenTest]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur; optimum.BackPrev := repIndex; optimum.Prev1IsChar := false; end;//if curandlen dec(lenTest); until not (lenTest >= 2); lenTest := lenTestTemp; if repIndex = 0 then startLen := lenTest + 1; // if (_maxMode) if lenTest < numAvailableBytesFull then begin t := min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); lenTest2 := _matchFinder.GetMatchLen(lenTest, reps[repIndex], t); if lenTest2 >= 2 then begin state2 := ULZMABase.StateUpdateRep(state); posStateNext := (position + lenTest) and _posStateMask; curAndLenCharPrice := repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + RangeEncoder.GetPrice0(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]) + _literalEncoder.GetSubCoder(position + lenTest, _matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true, _matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)), _matchFinder.GetIndexByte(lenTest - 1)); state2 := ULZMABase.StateUpdateChar(state2); posStateNext := (position + lenTest + 1) and _posStateMask; nextMatchPrice := curAndLenCharPrice + RangeEncoder.GetPrice1(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]); nextRepMatchPrice := nextMatchPrice + RangeEncoder.GetPrice1(_isRep[state2]); // for(; lenTest2 >= 2; lenTest2--) begin offset := lenTest + 1 + lenTest2; while lenEnd < cur + offset do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd curAndLenPrice := nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); optimum := _optimum[cur + offset]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur + lenTest + 1; optimum.BackPrev := 0; optimum.Prev1IsChar := true; optimum.Prev2 := true; optimum.PosPrev2 := cur; optimum.BackPrev2 := repIndex; end;//if curAndLenPrice < optimum.Price end;//none end;//if lenTest2 >= 2 end;//if lenTest < numAvailableBytesFull end;//for repIndex if newLen > numAvailableBytes then begin newLen := numAvailableBytes; numDistancePairs := 0; while newLen > _matchDistances[numDistancePairs] do numDistancePairs := numDistancePairs + 2; _matchDistances[numDistancePairs] := newLen; numDistancePairs := numDistancePairs + 2; end;//if newLen > numAvailableBytes if newLen >= startLen then begin normalMatchPrice := matchPrice + RangeEncoder.GetPrice0(_isRep[state]); while lenEnd < cur + newLen do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd offs := 0; while startLen > _matchDistances[offs] do offs := offs + 2; lenTest := startLen; while (true) do begin curBack := _matchDistances[offs + 1]; curAndLenPrice := normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); optimum := _optimum[cur + lenTest]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur; optimum.BackPrev := curBack + ULZMABase.kNumRepDistances; optimum.Prev1IsChar := false; end;//if curAndLenPrice < optimum.Price if lenTest = _matchDistances[offs] then begin if lenTest < numAvailableBytesFull then begin t := min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); lenTest2 := _matchFinder.GetMatchLen(lenTest, curBack, t); if lenTest2 >= 2 then begin state2 := ULZMABase.StateUpdateMatch(state); posStateNext := (position + lenTest) and _posStateMask; curAndLenCharPrice := curAndLenPrice + RangeEncoder.GetPrice0(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]) + _literalEncoder.GetSubCoder(position + lenTest, _matchFinder.GetIndexByte(lenTest - 1 - 1)). GetPrice(true, _matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1), _matchFinder.GetIndexByte(lenTest - 1)); state2 := ULZMABase.StateUpdateChar(state2); posStateNext := (position + lenTest + 1) and _posStateMask; nextMatchPrice := curAndLenCharPrice + RangeEncoder.GetPrice1(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]); nextRepMatchPrice := nextMatchPrice + RangeEncoder.GetPrice1(_isRep[state2]); offset := lenTest + 1 + lenTest2; while lenEnd < cur + offset do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd curAndLenPrice := nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); optimum := _optimum[cur + offset]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur + lenTest + 1; optimum.BackPrev := 0; optimum.Prev1IsChar := true; optimum.Prev2 := true; optimum.PosPrev2 := cur; optimum.BackPrev2 := curBack + ULZMABase.kNumRepDistances; end;//if curAndLenPrice < optimum.Price end;//if lenTest2 >= 2 end;//lenTest < numAvailableBytesFull offs :=offs + 2; if offs = numDistancePairs then break; end;//if lenTest = _matchDistances[offs] inc(lenTest); end;//while(true) end;//if newLen >= startLen end;//while (true) end; function TLZMAEncoder.ChangePair(const smallDist, bigDist:integer):boolean; var kDif:integer; begin kDif := 7; result:= (smallDist < (1 shl (32 - kDif))) and (bigDist >= (smallDist shl kDif)); end; procedure TLZMAEncoder.WriteEndMarker(const posState:integer); var len,posSlot,lenToPosState,footerBits,posReduced:integer; begin if not _writeEndMark then exit; _rangeEncoder.Encode(_isMatch, (_state shl ULZMABase.kNumPosStatesBitsMax) + posState, 1); _rangeEncoder.Encode(_isRep, _state, 0); _state := ULZMABase.StateUpdateMatch(_state); len := ULZMABase.kMatchMinLen; _lenEncoder.Encode(_rangeEncoder, len - ULZMABase.kMatchMinLen, posState); posSlot := (1 shl ULZMABase.kNumPosSlotBits) - 1; lenToPosState := ULZMABase.GetLenToPosState(len); _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); footerBits := 30; posReduced := (1 shl footerBits) - 1; _rangeEncoder.EncodeDirectBits(posReduced shr ULZMABase.kNumAlignBits, footerBits - ULZMABase.kNumAlignBits); _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced and ULZMABase.kAlignMask); end; procedure TLZMAEncoder.Flush(const nowPos:integer); begin ReleaseMFStream; WriteEndMarker(nowPos and _posStateMask); _rangeEncoder.FlushData(); _rangeEncoder.FlushStream(); end; procedure TLZMAEncoder.CodeOneBlock(var inSize,outSize:int64;var finished:boolean); var progressPosValuePrev:int64; posState,len,pos,complexState,distance,i,posSlot,lenToPosState:integer; footerBits,baseVal,posReduced:integer; curByte,matchByte:byte; subcoder:TLZMAEncoder2; begin inSize := 0; outSize := 0; finished := true; if _inStream <>nil then begin _matchFinder.SetStream(_inStream); _matchFinder.Init; _needReleaseMFStream := true; _inStream := nil; end; if _finished then exit; _finished := true; progressPosValuePrev := nowPos64; if nowPos64 = 0 then begin if _matchFinder.GetNumAvailableBytes = 0 then begin Flush(nowPos64); exit; end; ReadMatchDistances; posState := integer(nowPos64) and _posStateMask; _rangeEncoder.Encode(_isMatch, (_state shl ULZMABase.kNumPosStatesBitsMax) + posState, 0); _state := ULZMABase.StateUpdateChar(_state); curByte := _matchFinder.GetIndexByte(0 - _additionalOffset); _literalEncoder.GetSubCoder(integer(nowPos64), _previousByte).Encode(_rangeEncoder, curByte); _previousByte := curByte; dec(_additionalOffset); inc(nowPos64); end; if _matchFinder.GetNumAvailableBytes = 0 then begin Flush(integer(nowPos64)); exit; end; while true do begin len := GetOptimum(integer(nowPos64)); pos := backRes; posState := integer(nowPos64) and _posStateMask; complexState := (_state shl ULZMABase.kNumPosStatesBitsMax) + posState; if (len = 1) and (pos = -1) then begin _rangeEncoder.Encode(_isMatch, complexState, 0); curByte := _matchFinder.GetIndexByte(0 - _additionalOffset); subCoder := _literalEncoder.GetSubCoder(integer(nowPos64), _previousByte); if not ULZMABase.StateIsCharState(_state) then begin matchByte := _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset); subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); end else subCoder.Encode(_rangeEncoder, curByte); _previousByte := curByte; _state := ULZMABase.StateUpdateChar(_state); end else begin _rangeEncoder.Encode(_isMatch, complexState, 1); if pos < ULZMABase.kNumRepDistances then begin _rangeEncoder.Encode(_isRep, _state, 1); if pos = 0 then begin _rangeEncoder.Encode(_isRepG0, _state, 0); if len = 1 then _rangeEncoder.Encode(_isRep0Long, complexState, 0) else _rangeEncoder.Encode(_isRep0Long, complexState, 1); end else begin _rangeEncoder.Encode(_isRepG0, _state, 1); if pos = 1 then _rangeEncoder.Encode(_isRepG1, _state, 0) else begin _rangeEncoder.Encode(_isRepG1, _state, 1); _rangeEncoder.Encode(_isRepG2, _state, pos - 2); end; end; if len = 1 then _state := ULZMABase.StateUpdateShortRep(_state) else begin _repMatchLenEncoder.Encode(_rangeEncoder, len - ULZMABase.kMatchMinLen, posState); _state := ULZMABase.StateUpdateRep(_state); end; distance := _repDistances[pos]; if pos <> 0 then begin for i := pos downto 1 do _repDistances[i] := _repDistances[i - 1]; _repDistances[0] := distance; end; end else begin _rangeEncoder.Encode(_isRep, _state, 0); _state := ULZMABase.StateUpdateMatch(_state); _lenEncoder.Encode(_rangeEncoder, len - ULZMABase.kMatchMinLen, posState); pos := pos - ULZMABase.kNumRepDistances; posSlot := GetPosSlot(pos); lenToPosState := ULZMABase.GetLenToPosState(len); _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); if posSlot >= ULZMABase.kStartPosModelIndex then begin footerBits := integer((posSlot shr 1) - 1); baseVal := ((2 or (posSlot and 1)) shl footerBits); posReduced := pos - baseVal; if posSlot < ULZMABase.kEndPosModelIndex then UBitTreeEncoder.ReverseEncode(_posEncoders, baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced) else begin _rangeEncoder.EncodeDirectBits(posReduced shr ULZMABase.kNumAlignBits, footerBits - ULZMABase.kNumAlignBits); _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced and ULZMABase.kAlignMask); inc(_alignPriceCount); end; end; distance := pos; for i := ULZMABase.kNumRepDistances - 1 downto 1 do _repDistances[i] := _repDistances[i - 1]; _repDistances[0] := distance; inc(_matchPriceCount); end; _previousByte := _matchFinder.GetIndexByte(len - 1 - _additionalOffset); end; _additionalOffset := _additionalOffset - len; nowPos64 := nowPos64 + len; if _additionalOffset = 0 then begin // if (!_fastMode) if _matchPriceCount >= (1 shl 7) then FillDistancesPrices; if _alignPriceCount >= ULZMABase.kAlignTableSize then FillAlignPrices; inSize := nowPos64; outSize := _rangeEncoder.GetProcessedSizeAdd; if _matchFinder.GetNumAvailableBytes = 0 then begin Flush(integer(nowPos64)); exit; end; if (nowPos64 - progressPosValuePrev >= (1 shl 12)) then begin _finished := false; finished := false; exit; end; end; end; end; procedure TLZMAEncoder.ReleaseMFStream; begin if (_matchFinder <>nil) and _needReleaseMFStream then begin _matchFinder.ReleaseStream; _needReleaseMFStream := false; end; end; procedure TLZMAEncoder.SetOutStream(const outStream:TStream); begin _rangeEncoder.SetStream(outStream); end; procedure TLZMAEncoder.ReleaseOutStream; begin _rangeEncoder.ReleaseStream; end; procedure TLZMAEncoder.ReleaseStreams; begin ReleaseMFStream; ReleaseOutStream; end; procedure TLZMAEncoder.SetStreams(const inStream, outStream:TStream;const inSize, outSize:int64); begin _inStream := inStream; _finished := false; _Create(); SetOutStream(outStream); Init(); // if (!_fastMode) FillDistancesPrices; FillAlignPrices; _lenEncoder.SetTableSize(_numFastBytes + 1 - ULZMABase.kMatchMinLen); _lenEncoder.UpdateTables(1 shl _posStateBits); _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - ULZMABase.kMatchMinLen); _repMatchLenEncoder.UpdateTables(1 shl _posStateBits); nowPos64 := 0; end; procedure TLZMAEncoder.Code(const inStream, outStream:TStream;const inSize, outSize:int64); var lpos:int64; progint:int64; inputsize:int64; begin if insize=-1 then inputsize:=instream.Size-instream.Position else inputsize:=insize; progint:=inputsize div CodeProgressInterval; lpos:=progint; _needReleaseMFStream := false; DoProgress(LPAMax,inputsize); try SetStreams(inStream, outStream, inSize, outSize); while true do begin CodeOneBlock(processedInSize, processedOutSize, finished); if finished then begin DoProgress(LPAPos,inputsize); exit; end; if (processedInSize>=lpos) then begin DoProgress(LPAPos,processedInSize); lpos:=lpos+progint; end; end; finally ReleaseStreams(); end; end; procedure TLZMAEncoder.WriteCoderProperties(const outStream:TStream); var i:integer; begin properties[0] := (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits; for i := 0 to 3 do properties[1 + i] := byte(_dictionarySize shr (8 * i)); outStream.write(properties, kPropSize); end; procedure TLZMAEncoder.FillDistancesPrices; var i,posSlot,footerBits,baseVal,lenToPosState,st,st2:integer; encoder:TBitTreeEncoder; begin for i := ULZMABase.kStartPosModelIndex to ULZMABase.kNumFullDistances -1 do begin posSlot := GetPosSlot(i); footerBits := integer((posSlot shr 1) - 1); baseVal := (2 or (posSlot and 1)) shl footerBits; tempPrices[i] := ReverseGetPrice(_posEncoders, baseVal - posSlot - 1, footerBits, i - baseVal); end; for lenToPosState := 0 to ULZMABase.kNumLenToPosStates -1 do begin encoder := _posSlotEncoder[lenToPosState]; st := (lenToPosState shl ULZMABase.kNumPosSlotBits); for posSlot := 0 to _distTableSize -1 do _posSlotPrices[st + posSlot] := encoder.GetPrice(posSlot); for posSlot := ULZMABase.kEndPosModelIndex to _distTableSize -1 do _posSlotPrices[st + posSlot] := _posSlotPrices[st + posSlot] + ((((posSlot shr 1) - 1) - ULZMABase.kNumAlignBits) shl kNumBitPriceShiftBits); st2 := lenToPosState * ULZMABase.kNumFullDistances; for i := 0 to ULZMABase.kStartPosModelIndex -1 do _distancesPrices[st2 + i] := _posSlotPrices[st + i]; for i := ULZMABase.kStartPosModelIndex to ULZMABase.kNumFullDistances-1 do _distancesPrices[st2 + i] := _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i]; end; _matchPriceCount := 0; end; procedure TLZMAEncoder.FillAlignPrices; var i:integer; begin for i := 0 to ULZMABase.kAlignTableSize -1 do _alignPrices[i] := _posAlignEncoder.ReverseGetPrice(i); _alignPriceCount := 0; end; function TLZMAEncoder.SetAlgorithm(const algorithm:integer):boolean; begin { _fastMode = (algorithm == 0); _maxMode = (algorithm >= 2); } result:=true; end; function TLZMAEncoder.SetDictionarySize(dictionarySize:integer):boolean; var kDicLogSizeMaxCompress,dicLogSize:integer; begin kDicLogSizeMaxCompress := 29; if (dictionarySize < (1 shl ULZMABase.kDicLogSizeMin)) or (dictionarySize > (1 shl kDicLogSizeMaxCompress)) then begin result:=false; exit; end; _dictionarySize := dictionarySize; dicLogSize := 0; while dictionarySize > (1 shl dicLogSize) do inc(dicLogSize); _distTableSize := dicLogSize * 2; result:=true; end; function TLZMAEncoder.SeNumFastBytes(const numFastBytes:integer):boolean; begin if (numFastBytes < 5) or (numFastBytes > ULZMABase.kMatchMaxLen) then begin result:=false; exit; end; _numFastBytes := numFastBytes; result:=true; end; function TLZMAEncoder.SetMatchFinder(const matchFinderIndex:integer):boolean; var matchFinderIndexPrev:integer; begin if (matchFinderIndex < 0) or (matchFinderIndex > 2) then begin result:=false; exit; end; matchFinderIndexPrev := _matchFinderType; _matchFinderType := matchFinderIndex; if (_matchFinder <> nil) and (matchFinderIndexPrev <> _matchFinderType) then begin _dictionarySizePrev := -1; _matchFinder := nil; end; result:=true; end; function TLZMAEncoder.SetLcLpPb(const lc,lp,pb:integer):boolean; begin if (lp < 0) or (lp > ULZMABase.kNumLitPosStatesBitsEncodingMax) or (lc < 0) or (lc > ULZMABase.kNumLitContextBitsMax) or (pb < 0) or (pb > ULZMABase.kNumPosStatesBitsEncodingMax) then begin result:=false; exit; end; _numLiteralPosStateBits := lp; _numLiteralContextBits := lc; _posStateBits := pb; _posStateMask := ((1) shl _posStateBits) - 1; result:=true; end; procedure TLZMAEncoder.SetEndMarkerMode(const endMarkerMode:boolean); begin _writeEndMark := endMarkerMode; end; procedure TLZMAEncoder2.Init; begin URangeEncoder.InitBitModels(m_Encoders); end; procedure TLZMAEncoder2.Encode(const rangeEncoder:TRangeEncoder;const symbol:byte); var context:integer; bit,i:integer; begin context := 1; for i := 7 downto 0 do begin bit := ((symbol shr i) and 1); rangeEncoder.Encode(m_Encoders, context, bit); context := (context shl 1) or bit; end; end; procedure TLZMAEncoder2.EncodeMatched(const rangeEncoder:TRangeEncoder;const matchByte,symbol:byte); var context,i,bit,state,matchbit:integer; same:boolean; begin context := 1; same := true; for i := 7 downto 0 do begin bit := ((symbol shr i) and 1); state := context; if same then begin matchBit := ((matchByte shr i) and 1); state :=state + ((1 + matchBit) shl 8); same := (matchBit = bit); end; rangeEncoder.Encode(m_Encoders, state, bit); context := (context shl 1) or bit; end; end; function TLZMAEncoder2.GetPrice(const matchMode:boolean;const matchByte,symbol:byte):integer; var price,context,i,matchbit,bit:integer; begin price := 0; context := 1; i := 7; if matchMode then while i>=0 do begin matchBit := (matchByte shr i) and 1; bit := (symbol shr i) and 1; price := price + RangeEncoder.GetPrice(m_Encoders[((1 + matchBit) shl 8) + context], bit); context := (context shl 1) or bit; if (matchBit <> bit) then begin dec(i); break; end; dec(i); end; while i>=0 do begin bit := (symbol shr i) and 1; price := price + RangeEncoder.GetPrice(m_Encoders[context], bit); context := (context shl 1) or bit; dec(i); end; result:=price; end; procedure TLZMALiteralEncoder._Create(const numPosBits,numPrevBits:integer); var numstates:integer; i:integer; begin if (length(m_Coders)<>0) and (m_NumPrevBits = numPrevBits) and (m_NumPosBits = numPosBits) then exit; m_NumPosBits := numPosBits; m_PosMask := (1 shl numPosBits) - 1; m_NumPrevBits := numPrevBits; numStates := 1 shl (m_NumPrevBits + m_NumPosBits); setlength(m_coders,numStates); for i := 0 to numStates-1 do m_Coders[i] := TLZMAEncoder2.Create; end; destructor TLZMALiteralEncoder.Destroy; var i:integer; begin for i:=low(m_Coders) to high(m_Coders) do if m_Coders[i]<>nil then m_Coders[i].Free; inherited; end; procedure TLZMALiteralEncoder.Init; var numstates,i:integer; begin numStates := 1 shl (m_NumPrevBits + m_NumPosBits); for i := 0 to numStates-1 do m_Coders[i].Init; end; function TLZMALiteralEncoder.GetSubCoder(const pos:integer;const prevByte:byte):TLZMAEncoder2; begin result:=m_Coders[((pos and m_PosMask) shl m_NumPrevBits) + ((prevByte and $FF) shr (8 - m_NumPrevBits))]; end; constructor TLZMALenEncoder.Create; var posState:integer; begin _highCoder := TBitTreeEncoder.Create(ULZMABase.kNumHighLenBits); for posState := 0 to ULZMABase.kNumPosStatesEncodingMax-1 do begin _lowCoder[posState] := TBitTreeEncoder.Create(ULZMABase.kNumLowLenBits); _midCoder[posState] := TBitTreeEncoder.Create(ULZMABase.kNumMidLenBits); end; end; destructor TLZMALenEncoder.Destroy; var posState:integer; begin _highCoder.Free; for posState := 0 to ULZMABase.kNumPosStatesEncodingMax-1 do begin _lowCoder[posState].Free; _midCoder[posState].Free; end; inherited; end; procedure TLZMALenEncoder.Init(const numPosStates:integer); var posState:integer; begin URangeEncoder.InitBitModels(_choice); for posState := 0 to numPosStates -1 do begin _lowCoder[posState].Init; _midCoder[posState].Init; end; _highCoder.Init; end; procedure TLZMALenEncoder.Encode(const rangeEncoder:TRangeEncoder;symbol:integer;const posState:integer); begin if (symbol < ULZMABase.kNumLowLenSymbols) then begin rangeEncoder.Encode(_choice, 0, 0); _lowCoder[posState].Encode(rangeEncoder, symbol); end else begin symbol := symbol - ULZMABase.kNumLowLenSymbols; rangeEncoder.Encode(_choice, 0, 1); if symbol < ULZMABase.kNumMidLenSymbols then begin rangeEncoder.Encode(_choice, 1, 0); _midCoder[posState].Encode(rangeEncoder, symbol); end else begin rangeEncoder.Encode(_choice, 1, 1); _highCoder.Encode(rangeEncoder, symbol - ULZMABase.kNumMidLenSymbols); end; end; end; procedure TLZMALenEncoder.SetPrices(const posState,numSymbols:integer;var prices:array of integer;const st:integer); var a0,a1,b0,b1,i:integer; begin a0 := RangeEncoder.GetPrice0(_choice[0]); a1 := RangeEncoder.GetPrice1(_choice[0]); b0 := a1 + RangeEncoder.GetPrice0(_choice[1]); b1 := a1 + RangeEncoder.GetPrice1(_choice[1]); i:=0; while i= numSymbols then exit; prices[st + i] := a0 + _lowCoder[posState].GetPrice(i); inc(i); end; while i < ULZMABase.kNumLowLenSymbols + ULZMABase.kNumMidLenSymbols do begin if i >= numSymbols then exit; prices[st + i] := b0 + _midCoder[posState].GetPrice(i - ULZMABase.kNumLowLenSymbols); inc(i); end; while i < numSymbols do begin prices[st + i] := b1 + _highCoder.GetPrice(i - ULZMABase.kNumLowLenSymbols - ULZMABase.kNumMidLenSymbols); inc(i); end; end; procedure TLZMALenPriceTableEncoder.SetTableSize(const tableSize:integer); begin _tableSize := tableSize; end; function TLZMALenPriceTableEncoder.GetPrice(const symbol,posState:integer):integer; begin result:=_prices[posState * ULZMABase.kNumLenSymbols + symbol] end; procedure TLZMALenPriceTableEncoder.UpdateTable(const posState:integer); begin SetPrices(posState, _tableSize, _prices, posState * ULZMABase.kNumLenSymbols); _counters[posState] := _tableSize; end; procedure TLZMALenPriceTableEncoder.UpdateTables(const numPosStates:integer); var posState:integer; begin for posState := 0 to numPosStates -1 do UpdateTable(posState); end; procedure TLZMALenPriceTableEncoder.Encode(const rangeEncoder:TRangeEncoder;symbol:integer;const posState:integer); begin inherited Encode(rangeEncoder, symbol, posState); dec(_counters[posState]); if (_counters[posState] = 0) then UpdateTable(posState); end; procedure TLZMAOptimal.MakeAsChar; begin BackPrev := -1; Prev1IsChar := false; end; procedure TLZMAOptimal.MakeAsShortRep; begin BackPrev := 0; Prev1IsChar := false; end; function TLZMAOptimal.IsShortRep:boolean; begin result:=BackPrev = 0; end; procedure TLZMAEncoder.DoProgress(const Action:TLZMAProgressAction;const Value:integer); begin if assigned(fonprogress) then fonprogress(action,value); end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/RangeCoder/0000755000175000001440000000000014743153644023776 5ustar alexxusersdoublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/RangeCoder/UBitTreeDecoder.pas0000644000175000001440000000350714743153644027461 0ustar alexxusersunit UBitTreeDecoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses URangeDecoder; type TBitTreeDecoder=class public Models: array of smallint; NumBitLevels:integer; constructor Create(const numBitLevels:integer); procedure Init; function Decode(const rangeDecoder:TRangeDecoder):integer; function ReverseDecode(const rangeDecoder:TRangeDecoder):integer;overload; end; function ReverseDecode(var Models: array of smallint; const startIndex:integer;const rangeDecoder:TRangeDecoder; const NumBitLevels:integer):integer;overload; implementation constructor TBitTreeDecoder.Create(const numBitLevels:integer); begin self.NumBitLevels := numBitLevels; setlength(Models,1 shl numBitLevels); end; procedure TBitTreeDecoder.Init; begin urangedecoder.InitBitModels(Models); end; function TBitTreeDecoder.Decode(const rangeDecoder:TRangeDecoder):integer; var m,bitIndex:integer; begin m:=1; for bitIndex := NumBitLevels downto 1 do begin m:=m shl 1 + rangeDecoder.DecodeBit(Models, m); end; result:=m - (1 shl NumBitLevels); end; function TBitTreeDecoder.ReverseDecode(const rangeDecoder:TRangeDecoder):integer; var m,symbol,bitindex,bit:integer; begin m:=1; symbol:=0; for bitindex:=0 to numbitlevels-1 do begin bit:=rangeDecoder.DecodeBit(Models, m); m:=(m shl 1) + bit; symbol:=symbol or (bit shl bitIndex); end; result:=symbol; end; function ReverseDecode(var Models: array of smallint;const startIndex:integer; const rangeDecoder:TRangeDecoder;const NumBitLevels:integer):integer; var m,symbol,bitindex,bit:integer; begin m:=1; symbol:=0; for bitindex:=0 to numbitlevels -1 do begin bit := rangeDecoder.DecodeBit(Models, startIndex + m); m := (m shl 1) + bit; symbol := symbol or bit shl bitindex; end; result:=symbol; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/RangeCoder/UBitTreeEncoder.pas0000644000175000001440000000612214743153644027467 0ustar alexxusersunit UBitTreeEncoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses URangeDecoder,URangeEncoder; type TBitTreeEncoder=class public Models: array of smallint; NumBitLevels:integer; constructor Create(const numBitLevels:integer); procedure Init; procedure Encode(const rangeEncoder:TRangeEncoder;const symbol:integer); procedure ReverseEncode(const rangeEncoder:TRangeEncoder;symbol:integer); function GetPrice(const symbol:integer):integer; function ReverseGetPrice(symbol:integer):integer;overload; end; procedure ReverseEncode(var Models:array of smallint;const startIndex:integer;const rangeEncoder:TRangeEncoder;const NumBitLevels:integer; symbol:integer); function ReverseGetPrice(var Models:array of smallint;const startIndex,NumBitLevels:integer; symbol:integer):integer; implementation constructor TBitTreeEncoder.Create(const numBitLevels:integer); begin self.NumBitLevels:=numBitLevels; setlength(Models,1 shl numBitLevels); end; procedure TBitTreeEncoder.Init; begin URangeDecoder.InitBitModels(Models); end; procedure TBitTreeEncoder.Encode(const rangeEncoder:TRangeEncoder;const symbol:integer); var m,bitindex,bit:integer; begin m := 1; for bitIndex := NumBitLevels -1 downto 0 do begin bit := (symbol shr bitIndex) and 1; rangeEncoder.Encode(Models, m, bit); m := (m shl 1) or bit; end; end; procedure TBitTreeEncoder.ReverseEncode(const rangeEncoder:TRangeEncoder;symbol:integer); var m,i,bit:integer; begin m:=1; for i:= 0 to NumBitLevels -1 do begin bit := symbol and 1; rangeEncoder.Encode(Models, m, bit); m := (m shl 1) or bit; symbol := symbol shr 1; end; end; function TBitTreeEncoder.GetPrice(const symbol:integer):integer; var price,m,bitindex,bit:integer; begin price := 0; m := 1; for bitIndex := NumBitLevels - 1 downto 0 do begin bit := (symbol shr bitIndex) and 1; price := price + RangeEncoder.GetPrice(Models[m], bit); m := (m shl 1) + bit; end; result:=price; end; function TBitTreeEncoder.ReverseGetPrice(symbol:integer):integer; var price,m,i,bit:integer; begin price := 0; m := 1; for i:= NumBitLevels downto 1 do begin bit := symbol and 1; symbol := symbol shr 1; price :=price + RangeEncoder.GetPrice(Models[m], bit); m := (m shl 1) or bit; end; result:=price; end; function ReverseGetPrice(var Models:array of smallint;const startIndex,NumBitLevels:integer;symbol:integer):integer; var price,m,i,bit:integer; begin price := 0; m := 1; for i := NumBitLevels downto 1 do begin bit := symbol and 1; symbol := symbol shr 1; price := price + RangeEncoder.GetPrice(Models[startIndex + m], bit); m := (m shl 1) or bit; end; result:=price; end; procedure ReverseEncode(var Models:array of smallint;const startIndex:integer;const rangeEncoder:TRangeEncoder;const NumBitLevels:integer;symbol:integer); var m,i,bit:integer; begin m:=1; for i := 0 to NumBitLevels -1 do begin bit := symbol and 1; rangeEncoder.Encode(Models, startIndex + m, bit); m := (m shl 1) or bit; symbol := symbol shr 1; end; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/RangeCoder/URangeDecoder.pas0000644000175000001440000000474214743153644027161 0ustar alexxusersunit URangeDecoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes,ULZMACommon; type TRangeDecoder=class public Range,Code:integer; Stream:TStream; procedure SetStream(const Stream:TStream); procedure ReleaseStream; procedure Init; function DecodeDirectBits(const numTotalBits:integer):integer; function DecodeBit(var probs: array of smallint;const index:integer):integer; end; procedure InitBitModels(var probs: array of smallint); implementation const kTopMask = not ((1 shl 24) - 1); kNumBitModelTotalBits = 11; kBitModelTotal = (1 shl kNumBitModelTotalBits); kNumMoveBits = 5; procedure TRangeDecoder.SetStream(const Stream:TStream); begin self.Stream:=Stream; end; procedure TRangeDecoder.ReleaseStream; begin stream:=nil; end; procedure TRangeDecoder.Init; var i:integer; begin code:=0; Range:=-1; for i:=0 to 4 do begin code:=(code shl 8) or byte(ReadByte(stream)); end; end; function TRangeDecoder.DecodeDirectBits(const numTotalBits:integer):integer; var i,t:integer; begin result:=0; for i := numTotalBits downto 1 do begin range:=range shr 1; t := (cardinal(Code - Range) shr 31); Code := integer(Code - Range and (t - 1)); result := (result shl 1) or (1 - t); if ((Range and kTopMask) = 0) then begin Code := (Code shl 8) or ReadByte(stream); Range := Range shl 8; end; end; end; function TRangeDecoder.DecodeBit(var probs: array of smallint;const index:integer):integer; var prob,newbound:integer; begin prob:=probs[index]; newbound:= integer((Range shr kNumBitModelTotalBits) * prob); if (integer((integer(Code) xor integer($80000000))) < integer((integer(newBound) xor integer($80000000)))) then begin Range := newBound; probs[index] := (prob + ((kBitModelTotal - prob) shr kNumMoveBits)); if ((Range and kTopMask) = 0) then begin Code := (Code shl 8) or ReadByte(stream); Range := Range shl 8; end; result:=0; end else begin Range := integer(Range - newBound); Code := integer(Code - newBound); probs[index] := (prob - ((prob) shr kNumMoveBits)); if ((Range and kTopMask) = 0) then begin Code := (Code shl 8) or ReadByte(stream); Range := Range shl 8; end; result:=1; end; end; procedure InitBitModels(var probs: array of smallint); var i:integer; begin for i:=0 to length(probs)-1 do probs[i] := kBitModelTotal shr 1; end; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/compression/RangeCoder/URangeEncoder.pas0000644000175000001440000001032314743153644027163 0ustar alexxusersunit URangeEncoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes,ULZMACommon; const kNumBitPriceShiftBits = 6; kTopMask = not ((1 shl 24) - 1); kNumBitModelTotalBits = 11; kBitModelTotal = (1 shl kNumBitModelTotalBits); kNumMoveBits = 5; kNumMoveReducingBits = 2; type TRangeEncoder=class private ProbPrices: array [0..kBitModelTotal shr kNumMoveReducingBits-1] of integer; public Stream:TStream; Low,Position:int64; Range,cacheSize,cache:integer; procedure SetStream(const stream:TStream); procedure ReleaseStream; procedure Init; procedure FlushData; procedure FlushStream; procedure ShiftLow; procedure EncodeDirectBits(const v,numTotalBits:integer); function GetProcessedSizeAdd:int64; procedure Encode(var probs: array of smallint;const index,symbol:integer); constructor Create; function GetPrice(const Prob,symbol:integer):integer; function GetPrice0(const Prob:integer):integer; function GetPrice1(const Prob:integer):integer; end; var RangeEncoder:TRangeEncoder; procedure InitBitModels(var probs:array of smallint); implementation procedure TRangeEncoder.SetStream(const stream:TStream); begin self.Stream:=Stream; end; procedure TRangeEncoder.ReleaseStream; begin stream:=nil; end; procedure TRangeEncoder.Init; begin position := 0; Low := 0; Range := -1; cacheSize := 1; cache := 0; end; procedure TRangeEncoder.FlushData; var i:integer; begin for i:=0 to 4 do ShiftLow(); end; procedure TRangeEncoder.FlushStream; begin //stream.flush; end; procedure TRangeEncoder.ShiftLow; var LowHi:integer; temp:integer; begin LowHi := (Low shr 32); if (LowHi <> 0) or (Low < int64($FF000000)) then begin position := position + cacheSize; temp := cache; repeat WriteByte(stream,byte(temp + LowHi)); temp := $FF; dec(cacheSize); until(cacheSize = 0); cache := (Low shr 24); end; inc(cacheSize); Low := (Low and integer($FFFFFF)) shl 8; end; procedure TRangeEncoder.EncodeDirectBits(const v,numTotalBits:integer); var i:integer; begin for i := numTotalBits - 1 downto 0 do begin Range := Range shr 1; if (((v shr i) and 1) = 1) then Low := Low + Range; if ((Range and kTopMask) = 0) then begin Range := range shl 8; ShiftLow; end; end; end; function TRangeEncoder.GetProcessedSizeAdd:int64; begin result:=cacheSize + position + 4; end; procedure InitBitModels(var probs:array of smallint); var i:integer; begin for i := 0 to length(probs) -1 do probs[i] := kBitModelTotal shr 1; end; procedure TRangeEncoder.Encode(var probs: array of smallint;const index,symbol:integer); var prob,newbound:integer; begin prob := probs[index]; newBound := integer((Range shr kNumBitModelTotalBits) * prob); if (symbol = 0) then begin Range := newBound; probs[index] := (prob + ((kBitModelTotal - prob) shr kNumMoveBits)); end else begin Low := Low + (newBound and int64($FFFFFFFF)); Range := integer(Range - newBound); probs[index] := (prob - ((prob) shr kNumMoveBits)); end; if ((Range and kTopMask) = 0) then begin Range := Range shl 8; ShiftLow; end; end; constructor TRangeEncoder.Create; var kNumBits:integer; i,j,start,_end:integer; begin kNumBits := (kNumBitModelTotalBits - kNumMoveReducingBits); for i := kNumBits - 1 downto 0 do begin start := 1 shl (kNumBits - i - 1); _end := 1 shl (kNumBits - i); for j := start to _end -1 do ProbPrices[j] := (i shl kNumBitPriceShiftBits) + (((_end - j) shl kNumBitPriceShiftBits) shr (kNumBits - i - 1)); end; end; function TRangeEncoder.GetPrice(const Prob,symbol:integer):integer; begin result:=ProbPrices[(((Prob - symbol) xor ((-symbol))) and (kBitModelTotal - 1)) shr kNumMoveReducingBits]; end; function TRangeEncoder.GetPrice0(const Prob:integer):integer; begin result:= ProbPrices[Prob shr kNumMoveReducingBits]; end; function TRangeEncoder.GetPrice1(const Prob:integer):integer; begin result:= ProbPrices[(kBitModelTotal - Prob) shr kNumMoveReducingBits]; end; initialization RangeEncoder:=TRangeEncoder.Create; finalization RangeEncoder.Free; end. doublecmd-1.1.22/plugins/wcx/zip/src/lzma/history.txt0000644000175000001440000000171014743153644021665 0ustar alexxusersHISTORY of the LZMA SDK ----------------------- Version 4.42b 2006-06-13 -------------------------------------- - Fixed bug in ULZBinTree which caused an infinite loop on some files - Fixed bug in ULZMAEncoder which caused encoding to fail on some files - Fixed code layout problems caused by a mixture of tabs and spaces Version 4.42a 2006-06-05 -------------------------------------- - Added port of LZMA benchmark Version 4.42 2006-06-01 -------------------------------------- - First version of Pascal SDK ported from Java SDK HISTORY of the LZMA ------------------- 2001-2004: Improvements to LZMA compressing/decompressing code, keeping compatibility with original LZMA format 1996-2001: Development of LZMA compression format Some milestones: 2001-08-30: LZMA compression was added to 7-Zip 1999-01-02: First version of 7-Zip was released End of document doublecmd-1.1.22/plugins/wcx/zip/src/lzma/lzma.txt0000644000175000001440000005121214743153644021131 0ustar alexxusersLZMA SDK 4.42 ------------- LZMA SDK Copyright (C) 1999-2006 Igor Pavlov LZMA SDK provides the documentation, samples, header files, libraries, and tools you need to develop applications that use LZMA compression. LZMA is default and general compression method of 7z format in 7-Zip compression program (www.7-zip.org). LZMA provides high compression ratio and very fast decompression. LZMA is an improved version of famous LZ77 compression algorithm. It was improved in way of maximum increasing of compression ratio, keeping high decompression speed and low memory requirements for decompressing. LICENSE ------- LZMA SDK is available under any of the following licenses: 1) GNU Lesser General Public License (GNU LGPL) 2) Common Public License (CPL) 3) Simplified license for unmodified code (read SPECIAL EXCEPTION) 4) Proprietary license It means that you can select one of these four options and follow rules of that license. 1,2) GNU LGPL and CPL licenses are pretty similar and both these licenses are classified as - "Free software licenses" at http://www.gnu.org/ - "OSI-approved" at http://www.opensource.org/ 3) SPECIAL EXCEPTION Igor Pavlov, as the author of this code, expressly permits you to statically or dynamically link your code (or bind by name) to the files from LZMA SDK without subjecting your linked code to the terms of the CPL or GNU LGPL. Any modifications or additions to files from LZMA SDK, however, are subject to the GNU LGPL or CPL terms. SPECIAL EXCEPTION allows you to use LZMA SDK in applications with closed code, while you keep LZMA SDK code unmodified. SPECIAL EXCEPTION #2: Igor Pavlov, as the author of this code, expressly permits you to use this code under the same terms and conditions contained in the License Agreement you have for any previous version of LZMA SDK developed by Igor Pavlov. SPECIAL EXCEPTION #2 allows owners of proprietary licenses to use latest version of LZMA SDK as update for previous versions. SPECIAL EXCEPTION #3: Igor Pavlov, as the author of this code, expressly permits you to use code of the following files: BranchTypes.h, LzmaTypes.h, LzmaTest.c, LzmaStateTest.c, LzmaAlone.cpp, LzmaAlone.cs, LzmaAlone.java as public domain code. 4) Proprietary license LZMA SDK also can be available under a proprietary license which can include: 1) Right to modify code without subjecting modified code to the terms of the CPL or GNU LGPL 2) Technical support for code To request such proprietary license or any additional consultations, send email message from that page: http://www.7-zip.org/support.html You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA You should have received a copy of the Common Public License along with this library. LZMA SDK Contents ----------------- LZMA SDK includes: - C++ source code of LZMA compressing and decompressing - ANSI-C compatible source code for LZMA decompressing - C# source code for LZMA compressing and decompressing - Java source code for LZMA compressing and decompressing - Compiled file->file LZMA compressing/decompressing program for Windows system ANSI-C LZMA decompression code was ported from original C++ sources to C. Also it was simplified and optimized for code size. But it is fully compatible with LZMA from 7-Zip. UNIX/Linux version ------------------ To compile C++ version of file->file LZMA, go to directory C/7zip/Compress/LZMA_Alone and type "make" or "make clean all" to recompile all. In some UNIX/Linux versions you must compile LZMA with static libraries. To compile with static libraries, change string in makefile LIB = -lm to string LIB = -lm -static Files --------------------- C - C / CPP source code CS - C# source code Java - Java source code lzma.txt - LZMA SDK description (this file) 7zFormat.txt - 7z Format description 7zC.txt - 7z ANSI-C Decoder description (this file) methods.txt - Compression method IDs for .7z LGPL.txt - GNU Lesser General Public License CPL.html - Common Public License lzma.exe - Compiled file->file LZMA encoder/decoder for Windows history.txt - history of the LZMA SDK Source code structure --------------------- C - C / CPP files Common - common files for C++ projects Windows - common files for Windows related code 7zip - files related to 7-Zip Project Common - common files for 7-Zip Compress - files related to compression/decompression LZ - files related to LZ (Lempel-Ziv) compression algorithm BinTree - Binary Tree Match Finder for LZ algorithm HashChain - Hash Chain Match Finder for LZ algorithm Patricia - Patricia Match Finder for LZ algorithm RangeCoder - Range Coder (special code of compression/decompression) LZMA - LZMA compression/decompression on C++ LZMA_Alone - file->file LZMA compression/decompression LZMA_C - ANSI-C compatible LZMA decompressor LzmaDecode.h - interface for LZMA decoding on ANSI-C LzmaDecode.c - LZMA decoding on ANSI-C (new fastest version) LzmaDecodeSize.c - LZMA decoding on ANSI-C (old size-optimized version) LzmaTest.c - test application that decodes LZMA encoded file LzmaTypes.h - basic types for LZMA Decoder LzmaStateDecode.h - interface for LZMA decoding (State version) LzmaStateDecode.c - LZMA decoding on ANSI-C (State version) LzmaStateTest.c - test application (State version) Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code Archive - files related to archiving 7z_C - 7z ANSI-C Decoder CS - C# files 7zip Common - some common files for 7-Zip Compress - files related to compression/decompression LZ - files related to LZ (Lempel-Ziv) compression algorithm LZMA - LZMA compression/decompression LzmaAlone - file->file LZMA compression/decompression RangeCoder - Range Coder (special code of compression/decompression) Java - Java files SevenZip Compression - files related to compression/decompression LZ - files related to LZ (Lempel-Ziv) compression algorithm LZMA - LZMA compression/decompression RangeCoder - Range Coder (special code of compression/decompression) C/C++ source code of LZMA SDK is part of 7-Zip project. You can find ANSI-C LZMA decompressing code at folder C/7zip/Compress/LZMA_C 7-Zip doesn't use that ANSI-C LZMA code and that code was developed specially for this SDK. And files from LZMA_C do not need files from other directories of SDK for compiling. 7-Zip source code can be downloaded from 7-Zip's SourceForge page: http://sourceforge.net/projects/sevenzip/ LZMA features ------------- - Variable dictionary size (up to 1 GB) - Estimated compressing speed: about 1 MB/s on 1 GHz CPU - Estimated decompressing speed: - 8-12 MB/s on 1 GHz Intel Pentium 3 or AMD Athlon - 500-1000 KB/s on 100 MHz ARM, MIPS, PowerPC or other simple RISC - Small memory requirements for decompressing (8-32 KB + DictionarySize) - Small code size for decompressing: 2-8 KB (depending from speed optimizations) LZMA decoder uses only integer operations and can be implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). Some critical operations that affect to speed of LZMA decompression: 1) 32*16 bit integer multiply 2) Misspredicted branches (penalty mostly depends from pipeline length) 3) 32-bit shift and arithmetic operations Speed of LZMA decompressing mostly depends from CPU speed. Memory speed has no big meaning. But if your CPU has small data cache, overall weight of memory speed will slightly increase. How To Use ---------- Using LZMA encoder/decoder executable -------------------------------------- Usage: LZMA inputFile outputFile [...] e: encode file d: decode file b: Benchmark. There are two tests: compressing and decompressing with LZMA method. Benchmark shows rating in MIPS (million instructions per second). Rating value is calculated from measured speed and it is normalized with AMD Athlon 64 X2 CPU results. Also Benchmark checks possible hardware errors (RAM errors in most cases). Benchmark uses these settings: (-a1, -d21, -fb32, -mfbt4). You can change only -d. Also you can change number of iterations. Example for 30 iterations: LZMA b 30 Default number of iterations is 10. -a{N}: set compression mode 0 = fast, 1 = normal default: 1 (normal) d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB) The maximum value for dictionary size is 1 GB = 2^30 bytes. Dictionary size is calculated as DictionarySize = 2^N bytes. For decompressing file compressed by LZMA method with dictionary size D = 2^N you need about D bytes of memory (RAM). -fb{N}: set number of fast bytes - [5, 273], default: 128 Usually big number gives a little bit better compression ratio and slower compression process. -lc{N}: set number of literal context bits - [0, 8], default: 3 Sometimes lc=4 gives gain for big files. -lp{N}: set number of literal pos bits - [0, 4], default: 0 lp switch is intended for periodical data when period is equal 2^N. For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's better to set lc0, if you change lp switch. -pb{N}: set number of pos bits - [0, 4], default: 2 pb switch is intended for periodical data when period is equal 2^N. -mf{MF_ID}: set Match Finder. Default: bt4. Algorithms from hc* group doesn't provide good compression ratio, but they often works pretty fast in combination with fast mode (-a0). Memory requirements depend from dictionary size (parameter "d" in table below). MF_ID Memory Description bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing. bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing. bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing. hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing. -eos: write End Of Stream marker. By default LZMA doesn't write eos marker, since LZMA decoder knows uncompressed size stored in .lzma file header. -si: Read data from stdin (it will write End Of Stream marker). -so: Write data to stdout Examples: 1) LZMA e file.bin file.lzma -d16 -lc0 compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K) and 0 literal context bits. -lc0 allows to reduce memory requirements for decompression. 2) LZMA e file.bin file.lzma -lc0 -lp2 compresses file.bin to file.lzma with settings suitable for 32-bit periodical data (for example, ARM or MIPS code). 3) LZMA d file.lzma file.bin decompresses file.lzma to file.bin. Compression ratio hints ----------------------- Recommendations --------------- To increase compression ratio for LZMA compressing it's desirable to have aligned data (if it's possible) and also it's desirable to locate data in such order, where code is grouped in one place and data is grouped in other place (it's better than such mixing: code, data, code, data, ...). Using Filters ------------- You can increase compression ratio for some data types, using special filters before compressing. For example, it's possible to increase compression ratio on 5-10% for code for those CPU ISAs: x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC. You can find C/C++ source code of such filters in folder "7zip/Compress/Branch" You can check compression ratio gain of these filters with such 7-Zip commands (example for ARM code): No filter: 7z a a1.7z a.bin -m0=lzma With filter for little-endian ARM code: 7z a a2.7z a.bin -m0=bc_arm -m1=lzma With filter for big-endian ARM code (using additional Swap4 filter): 7z a a3.7z a.bin -m0=swap4 -m1=bc_arm -m2=lzma It works in such manner: Compressing = Filter_encoding + LZMA_encoding Decompressing = LZMA_decoding + Filter_decoding Compressing and decompressing speed of such filters is very high, so it will not increase decompressing time too much. Moreover, it reduces decompression time for LZMA_decoding, since compression ratio with filtering is higher. These filters convert CALL (calling procedure) instructions from relative offsets to absolute addresses, so such data becomes more compressible. Source code of these CALL filters is pretty simple (about 20 lines of C++), so you can convert it from C++ version yourself. For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. LZMA compressed file format --------------------------- Offset Size Description 0 1 Special LZMA properties for compressed data 1 4 Dictionary size (little endian) 5 8 Uncompressed size (little endian). -1 means unknown size 13 Compressed data ANSI-C LZMA Decoder ~~~~~~~~~~~~~~~~~~~ To compile ANSI-C LZMA Decoder you can use one of the following files sets: 1) LzmaDecode.h + LzmaDecode.c + LzmaTest.c (fastest version) 2) LzmaDecode.h + LzmaDecodeSize.c + LzmaTest.c (old size-optimized version) 3) LzmaStateDecode.h + LzmaStateDecode.c + LzmaStateTest.c (zlib-like interface) Memory requirements for LZMA decoding ------------------------------------- LZMA decoder doesn't allocate memory itself, so you must allocate memory and send it to LZMA. Stack usage of LZMA decoding function for local variables is not larger than 200 bytes. How To decompress data ---------------------- LZMA Decoder (ANSI-C version) now supports 5 interfaces: 1) Single-call Decompressing 2) Single-call Decompressing with input stream callback 3) Multi-call Decompressing with output buffer 4) Multi-call Decompressing with input callback and output buffer 5) Multi-call State Decompressing (zlib-like interface) Variant-5 is similar to Variant-4, but Variant-5 doesn't use callback functions. Decompressing steps ------------------- 1) read LZMA properties (5 bytes): unsigned char properties[LZMA_PROPERTIES_SIZE]; 2) read uncompressed size (8 bytes, little-endian) 3) Decode properties: CLzmaDecoderState state; /* it's 24-140 bytes structure, if int is 32-bit */ if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) return PrintError(rs, "Incorrect stream properties"); 4) Allocate memory block for internal Structures: state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); if (state.Probs == 0) return PrintError(rs, kCantAllocateMessage); LZMA decoder uses array of CProb variables as internal structure. By default, CProb is unsigned_short. But you can define _LZMA_PROB32 to make it unsigned_int. It can increase speed on some 32-bit CPUs, but memory usage will be doubled in that case. 5) Main Decompressing You must use one of the following interfaces: 5.1 Single-call Decompressing ----------------------------- When to use: RAM->RAM decompressing Compile files: LzmaDecode.h, LzmaDecode.c Compile defines: no defines Memory Requirements: - Input buffer: compressed size - Output buffer: uncompressed size - LZMA Internal Structures (~16 KB for default settings) Interface: int res = LzmaDecode(&state, inStream, compressedSize, &inProcessed, outStream, outSize, &outProcessed); 5.2 Single-call Decompressing with input stream callback -------------------------------------------------------- When to use: File->RAM or Flash->RAM decompressing. Compile files: LzmaDecode.h, LzmaDecode.c Compile defines: _LZMA_IN_CB Memory Requirements: - Buffer for input stream: any size (for example, 16 KB) - Output buffer: uncompressed size - LZMA Internal Structures (~16 KB for default settings) Interface: typedef struct _CBuffer { ILzmaInCallback InCallback; FILE *File; unsigned char Buffer[kInBufferSize]; } CBuffer; int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size) { CBuffer *bo = (CBuffer *)object; *buffer = bo->Buffer; *size = MyReadFile(bo->File, bo->Buffer, kInBufferSize); return LZMA_RESULT_OK; } CBuffer g_InBuffer; g_InBuffer.File = inFile; g_InBuffer.InCallback.Read = LzmaReadCompressed; int res = LzmaDecode(&state, &g_InBuffer.InCallback, outStream, outSize, &outProcessed); 5.3 Multi-call decompressing with output buffer ----------------------------------------------- When to use: RAM->File decompressing Compile files: LzmaDecode.h, LzmaDecode.c Compile defines: _LZMA_OUT_READ Memory Requirements: - Input buffer: compressed size - Buffer for output stream: any size (for example, 16 KB) - LZMA Internal Structures (~16 KB for default settings) - LZMA dictionary (dictionary size is encoded in stream properties) Interface: state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); LzmaDecoderInit(&state); do { LzmaDecode(&state, inBuffer, inAvail, &inProcessed, g_OutBuffer, outAvail, &outProcessed); inAvail -= inProcessed; inBuffer += inProcessed; } while you need more bytes see LzmaTest.c for more details. 5.4 Multi-call decompressing with input callback and output buffer ------------------------------------------------------------------ When to use: File->File decompressing Compile files: LzmaDecode.h, LzmaDecode.c Compile defines: _LZMA_IN_CB, _LZMA_OUT_READ Memory Requirements: - Buffer for input stream: any size (for example, 16 KB) - Buffer for output stream: any size (for example, 16 KB) - LZMA Internal Structures (~16 KB for default settings) - LZMA dictionary (dictionary size is encoded in stream properties) Interface: state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); LzmaDecoderInit(&state); do { LzmaDecode(&state, &bo.InCallback, g_OutBuffer, outAvail, &outProcessed); } while you need more bytes see LzmaTest.c for more details: 5.5 Multi-call State Decompressing (zlib-like interface) ------------------------------------------------------------------ When to use: file->file decompressing Compile files: LzmaStateDecode.h, LzmaStateDecode.c Compile defines: Memory Requirements: - Buffer for input stream: any size (for example, 16 KB) - Buffer for output stream: any size (for example, 16 KB) - LZMA Internal Structures (~16 KB for default settings) - LZMA dictionary (dictionary size is encoded in stream properties) Interface: state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); LzmaDecoderInit(&state); do { res = LzmaDecode(&state, inBuffer, inAvail, &inProcessed, g_OutBuffer, outAvail, &outProcessed, finishDecoding); inAvail -= inProcessed; inBuffer += inProcessed; } while you need more bytes see LzmaStateTest.c for more details: 6) Free all allocated blocks Note ---- LzmaDecodeSize.c is size-optimized version of LzmaDecode.c. But compiled code of LzmaDecodeSize.c can be larger than compiled code of LzmaDecode.c. So it's better to use LzmaDecode.c in most cases. EXIT codes ----------- LZMA decoder can return one of the following codes: #define LZMA_RESULT_OK 0 #define LZMA_RESULT_DATA_ERROR 1 If you use callback function for input data and you return some error code, LZMA Decoder also returns that code. LZMA Defines ------------ _LZMA_IN_CB - Use callback for input data _LZMA_OUT_READ - Use read function for output data _LZMA_LOC_OPT - Enable local speed optimizations inside code. _LZMA_LOC_OPT is only for LzmaDecodeSize.c (size-optimized version). _LZMA_LOC_OPT doesn't affect LzmaDecode.c (speed-optimized version) and LzmaStateDecode.c _LZMA_PROB32 - It can increase speed on some 32-bit CPUs, but memory usage will be doubled in that case _LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit. _LZMA_SYSTEM_SIZE_T - Define it if you want to use system's size_t. You can use it to enable 64-bit sizes supporting C++ LZMA Encoder/Decoder ~~~~~~~~~~~~~~~~~~~~~~~~ C++ LZMA code use COM-like interfaces. So if you want to use it, you can study basics of COM/OLE. By default, LZMA Encoder contains all Match Finders. But for compressing it's enough to have just one of them. So for reducing size of compressing code you can define: #define COMPRESS_MF_BT #define COMPRESS_MF_BT4 and it will use only bt4 match finder. --- http://www.7-zip.org http://www.7-zip.org/support.html doublecmd-1.1.22/plugins/wdx/0000755000175000001440000000000014743153644015071 5ustar alexxusersdoublecmd-1.1.22/plugins/wdx/audioinfo/0000755000175000001440000000000014743153644017046 5ustar alexxusersdoublecmd-1.1.22/plugins/wdx/audioinfo/audioinfo.lng0000644000175000001440000000476114743153644021535 0ustar alexxusers[KOR] Channels=채널 Duration (seconds)=지속 시간 (초) Duration (H:M:S)=지속 시간 (시:분:초) Sample rate=샘플 속도 Bitrate=비트레이트 Bitrate type=비트레이트 유형 Title=제목 Artist=아티스트 Album=앨범 Track=트랙 Track (zero-filled)=트랙 (0으로 채워짐) Date=날짜 Genre=장르 Comment=주석 Composer=작곡가 Copyright=저작권 Link=링크 Encoder=인코더 Tags=태그 Bit depth=비트 깊이 Full text=전체 텍스트 Unknown|Mono|Stereo|Joint Stereo|Dual Channel=알 수 없음|모노|스테레오|조인트 스테레오|듀얼 채널 Hz|kHz=Hz|kHz CBR|VBR|Unknown=CBR|VBR|알 수 없음 [RUS] Channels=Каналы Duration (seconds)=Время (секунды) Duration (H:M:S)=Время (Ч:М:С) Sample rate=Частота Bitrate=Битрейт Bitrate type=Тип битрейта Title=Название Artist=Исполнитель Album=Альбом Track=Трек Track (zero-filled)=Трек (ведущий ноль) Date=Дата Genre=Жанр Comment=Комментарий Composer=Композитор Copyright=Авторское право Link=Ссылка Encoder=Кодировщик Tags=Теги Bit depth=Разрядность Full text=Весь текст Unknown|Mono|Stereo|Joint Stereo|Dual Channel=Неизвестно|Моно|Стерео|Joint Стерео|Dual Channel Hz|kHz=Гц|КГц CBR|VBR|Unknown=CBR|VBR|Неизвестно [FRA] Channels=Canaux Duration (seconds)=Duree (secondes) Duration (H:M:S)=Duree (H:M:S) Sample rate=Échantillonnage Bitrate=Débit Bitrate type=Type de débit Title=Titre Artist=Artiste Album=Album Track=Piste Track (zero-filled)=Piste (zero-filled) Date=Date Genre=Genre Comment=Commentaire Composer=Compositeur Copyright=Copyright Link=Lien Encoder=Encodeur Tags=Tags Full text=Texte Inconnu|Mono|Stereo|Joint Stereo|Deux cannaux=Inconnu|Mono|Stereo|Joint Stereo|Deux canaux Hz|KHz=Hz|kHz [HUN] Channels=Csatornák Duration (seconds)=Hossz (másodperc) Duration (H:M:S)=Hossz (Ó:P:MP) Sample rate=Mintavételi ráta Bitrate=Bitráta Bitrate type=Bitráta típus Title=Cím Artist=Előadó Album=Album Track=Szám Track (zero-filled)=Szám (üres) Date=Dátum Genre=Műfaj Comment=Megjegyzés Composer=Szerző Copyright=Jogtulajdonos Link=Link Encoder=Enkóder Tags=Címkék Full text=Teljes szöveg Unknown|Mono|Stereo|Joint Stereo|Dual Channel=Ismeretlen|Monó|Sztereó|Joint Sztereó|Kétcsatornás Hz|KHz=Hz|kHz doublecmd-1.1.22/plugins/wdx/audioinfo/src/0000755000175000001440000000000014743153644017635 5ustar alexxusersdoublecmd-1.1.22/plugins/wdx/audioinfo/src/AudioInfo.lpi0000644000175000001440000000761014743153644022224 0ustar alexxusers <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <i18n> <EnableI18N LFM="False"/> </i18n> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../audioinfo.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk;$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk;atl"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"/> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> </RequiredPackages> <Units Count="1"> <Unit0> <Filename Value="AudioInfo.lpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../audioinfo.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk;$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk;atl"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> ������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/AudioInfo.lpr��������������������������������������������0000644�0001750�0000144�00000012477�14743153644�022244� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library AudioInfo; {$mode objfpc}{$H+} {$include calling.inc} uses FPCAdds, SysUtils, Classes, LazUTF8, WdxPlugin, AudioData, DCOSUtils; const DETECT_STRING: String = '(EXT="MP3") | (EXT="MP2") | (EXT="MP1") | (EXT="OGG") | (EXT="WMA") | ' + '(EXT="WAV") | (EXT="VQF") | (EXT="AAC") | (EXT="APE") | (EXT="MPC") | ' + '(EXT="FLAC") | (EXT="CDA") | (EXT="TTA") | (EXT="AC3") | (EXT="DTS") | ' + '(EXT="WV") | (EXT="WVC") | (EXT="OFR") | (EXT="OFS") | (EXT="M4A") | ' + '(EXT="MP4") | (EXT="OPUS")'; const FIELD_COUNT = 21; FIELD_NAME: array[0..Pred(FIELD_COUNT)] of String = ( 'Channels', 'Duration (seconds)', 'Duration (H:M:S)', 'Sample rate', 'Bitrate', 'Bitrate type', 'Title', 'Artist', 'Album', 'Track', 'Track (zero-filled)', 'Date', 'Genre', 'Comment', 'Composer', 'Copyright', 'Link', 'Encoder', 'Tags', 'Bit depth', 'Full text' ); FIELD_TYPE: array[0..Pred(FIELD_COUNT)] of Integer = ( ft_multiplechoice, ft_numeric_32, ft_string, ft_numeric_32, ft_numeric_32, ft_multiplechoice, ft_stringw, ft_stringw, ft_stringw, ft_numeric_32, ft_stringw, ft_stringw, ft_stringw, ft_stringw, ft_stringw, ft_stringw, ft_stringw, ft_stringw, ft_stringw, ft_numeric_32, ft_fulltextw ); FIELD_UNIT: array[0..Pred(FIELD_COUNT)] of String = ( 'Unknown|Mono|Stereo|Joint Stereo|Dual Channel', '', '', 'Hz|kHz', '', 'CBR|VBR|Unknown', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''); var DataAudio: TAudioData; CurrentFileName: String; function ContentGetSupportedField(FieldIndex: Integer; FieldName, Units: PAnsiChar; MaxLen: Integer): Integer; dcpcall; begin if (FieldIndex < 0) or (FieldIndex >= FIELD_COUNT) then begin Result := FT_NOMOREFIELDS; Exit; end; Result := FIELD_TYPE[FieldIndex]; StrPLCopy(Units, FIELD_UNIT[FieldIndex], MaxLen - 1); StrPLCopy(FieldName, FIELD_NAME[FieldIndex], MaxLen - 1); end; function ContentGetValue(FileName: PAnsiChar; FieldIndex, UnitIndex: Integer; FieldValue: PByte; MaxLen, Flags: Integer): Integer; dcpcall; begin Result:= ft_nosuchfield; end; function ContentGetValueW(FileName: PWideChar; FieldIndex, UnitIndex: Integer; FieldValue: PByte; MaxLen, Flags: Integer): Integer; dcpcall; var Value: String; FileNameU: String; FullText: UnicodeString; ValueI: PInteger absolute FieldValue; begin if (FieldIndex < 0) or (FieldIndex >= FIELD_COUNT) then begin Result:= ft_nosuchfield; Exit; end; FileNameU:= UTF16ToUTF8(UnicodeString(FileName)); if not mbFileExists(FileNameU) then begin Result:= ft_fileerror; Exit; end; if CurrentFileName <> FileNameU then try CurrentFileName:= FileNameU; DataAudio.LoadFromFile(FileNameU); except Exit(ft_fileerror); end; Result:= FIELD_TYPE[FieldIndex]; case FieldIndex of 0: Value:= DataAudio.Channels; 1: ValueI^:= DataAudio.Duration; 2: Value:= DataAudio.DurationHMS; 3: case UnitIndex of 0: ValueI^:= DataAudio.SampleRate; 1: ValueI^:= DataAudio.SampleRate div 1000; end; 4: ValueI^:= DataAudio.BitRate; 5: Value:= DataAudio.BitRateType; 6: Value:= DataAudio.Title; 7: Value:= DataAudio.Artist; 8: Value:= DataAudio.Album; 9: ValueI^:= DataAudio.Track; 10: if DataAudio.Track = 0 then Value:= EmptyStr else begin Value:= Format('%.2d', [DataAudio.Track]); end; 11: Value:= DataAudio.Date; 12: Value:= DataAudio.Genre; 13: Value:= DataAudio.Comment; 14: Value:= DataAudio.Composer; 15: Value:= DataAudio.Copyright; 16: Value:= DataAudio.URL; 17: Value:= DataAudio.Encoder; 18: Value:= DataAudio.Tags; 19: ValueI^:= DataAudio.Bits; 20: begin if UnitIndex = -1 then Result:= ft_fieldempty else begin MaxLen:= MaxLen div SizeOf(WideChar) - 1; FullText:= Copy(DataAudio.FullText, UnitIndex + 1, MaxLen); if Length(FullText) = 0 then Result:= ft_fieldempty else begin StrPLCopy(PWideChar(FieldValue), FullText, MaxLen); end; end; end; end; case Result of ft_string, ft_stringw, ft_multiplechoice: begin if Length(Value) = 0 then PWideChar(FieldValue)^:= #0 else begin if Result <> ft_stringw then StrPLCopy(PAnsiChar(FieldValue), Value, MaxLen - 1) else begin MaxLen:= MaxLen div SizeOf(WideChar) - 1; StrPLCopy(PWideChar(FieldValue), UTF8ToUTF16(Value), MaxLen); end; end; end; ft_numeric_32: if ValueI^ = 0 then Result:= ft_fieldempty; end; end; procedure ContentSetDefaultParams(dps: PContentDefaultParamStruct); dcpcall; begin DataAudio:= TAudioData.Create; end; procedure ContentPluginUnloading; dcpcall; begin FreeAndNil(DataAudio); end; procedure ContentGetDetectString(DetectString: PAnsiChar; MaxLen: Integer); dcpcall; begin StrPLCopy(DetectString, DETECT_STRING, MaxLen - 1); end; exports ContentGetSupportedField, ContentGetValue, ContentGetValueW, ContentGetDetectString, ContentSetDefaultParams, ContentPluginUnloading; begin end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/�����������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020415� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/AACfile.pas������������������������������������������0000644�0001750�0000144�00000036035�14743153644�022355� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TAACfile - for manipulating with AAC file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.2 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.1 (April 2004) by Gambit } { - Added Ratio and TotalFrames property } { } { Version 1.01 (September 2003) by Gambit } { - fixed the bitrate/duration bug (scans the whole file) } { } { Version 1.0 (2 October 2002) } { - Support for AAC files with ADIF or ADTS header } { - File info: file size, type, channels, sample rate, bit rate, duration } { - Class TID3v1: reading & writing support for ID3v1 tags } { - Class TID3v2: reading & writing support for ID3v2 tags } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit AACfile; interface uses Classes, SysUtils, ID3v1, ID3v2, APEtag, DCClassesUtf8; const { Header type codes } AAC_HEADER_TYPE_UNKNOWN = 0; { Unknown } AAC_HEADER_TYPE_ADIF = 1; { ADIF } AAC_HEADER_TYPE_ADTS = 2; { ADTS } { Header type names } AAC_HEADER_TYPE: array [0..2] of string = ('Unknown', 'ADIF', 'ADTS'); { MPEG version codes } AAC_MPEG_VERSION_UNKNOWN = 0; { Unknown } AAC_MPEG_VERSION_2 = 1; { MPEG-2 } AAC_MPEG_VERSION_4 = 2; { MPEG-4 } { MPEG version names } AAC_MPEG_VERSION: array [0..2] of string = ('Unknown', 'MPEG-2', 'MPEG-4'); { Profile codes } AAC_PROFILE_UNKNOWN = 0; { Unknown } AAC_PROFILE_MAIN = 1; { Main } AAC_PROFILE_LC = 2; { LC } AAC_PROFILE_SSR = 3; { SSR } AAC_PROFILE_LTP = 4; { LTP } { Profile names } AAC_PROFILE: array [0..4] of string = ('Unknown', 'AAC Main', 'AAC LC', 'AAC SSR', 'AAC LTP'); { Bit rate type codes } AAC_BITRATE_TYPE_UNKNOWN = 0; { Unknown } AAC_BITRATE_TYPE_CBR = 1; { CBR } AAC_BITRATE_TYPE_VBR = 2; { VBR } { Bit rate type names } AAC_BITRATE_TYPE: array [0..2] of string = ('Unknown', 'CBR', 'VBR'); type { Class TAACfile } TAACfile = class(TObject) private { Private declarations } FFileSize: Integer; FHeaderTypeID: Byte; FMPEGVersionID: Byte; FProfileID: Byte; FChannels: Byte; FSampleRate: Integer; FBitRate: Integer; FBitRateTypeID: Byte; FID3v1: TID3v1; FID3v2: TID3v2; FAPEtag: TAPEtag; FTotalFrames: Integer; procedure FResetData; function FGetHeaderType: string; function FGetMPEGVersion: string; function FGetProfile: string; function FGetBitRateType: string; function FGetDuration: Double; function FIsValid: Boolean; function FRecognizeHeaderType(const Source: TFileStreamEx): Byte; procedure FReadADIF(const Source: TFileStreamEx); procedure FReadADTS(const Source: TFileStreamEx); function FGetRatio: Double; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean;{ Load header } property FileSize: Integer read FFileSize; { File size (bytes) } property HeaderTypeID: Byte read FHeaderTypeID; { Header type code } property HeaderType: string read FGetHeaderType; { Header type name } property MPEGVersionID: Byte read FMPEGVersionID; { MPEG version code } property MPEGVersion: string read FGetMPEGVersion; { MPEG version name } property ProfileID: Byte read FProfileID; { Profile code } property Profile: string read FGetProfile; { Profile name } property Channels: Byte read FChannels; { Number of channels } property SampleRate: Integer read FSampleRate; { Sample rate (hz) } property BitRate: Integer read FBitRate; { Bit rate (bit/s) } property BitRateTypeID: Byte read FBitRateTypeID; { Bit rate type code } property BitRateType: string read FGetBitRateType; { Bit rate type name } property Duration: Double read FGetDuration; { Duration (seconds) } property Valid: Boolean read FIsValid; { True if data valid } property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data } property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data } property APEtag: TAPEtag read FAPEtag; { APE tag data } property Ratio: Double read FGetRatio; { Compression ratio (%) } property TotalFrames: Integer read FTotalFrames;{ Total number of frames } end; implementation const { Sample rate values } SAMPLE_RATE: array [0..15] of Integer = (96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 0, 0, 0, 0); { ********************* Auxiliary functions & procedures ******************** } function ReadBits(Source: TFileStreamEx; Position, Count: Integer): Integer; var Buffer: array [1..4] of Byte; begin { Read a number of bits from file at the given position } Source.Seek(Position div 8, soFromBeginning); Source.Read(Buffer, SizeOf(Buffer)); Result := Buffer[1] * $1000000 + Buffer[2] * $10000 + Buffer[3] * $100 + Buffer[4]; Result := (Result shl (Position mod 8)) shr (32 - Count); end; { ********************** Private functions & procedures ********************* } procedure TAACfile.FResetData; begin { Reset all variables } FFileSize := 0; FHeaderTypeID := AAC_HEADER_TYPE_UNKNOWN; FMPEGVersionID := AAC_MPEG_VERSION_UNKNOWN; FProfileID := AAC_PROFILE_UNKNOWN; FChannels := 0; FSampleRate := 0; FBitRate := 0; FBitRateTypeID := AAC_BITRATE_TYPE_UNKNOWN; FID3v1.ResetData; FID3v2.ResetData; FAPEtag.ResetData; FTotalFrames := 0; end; { --------------------------------------------------------------------------- } function TAACfile.FGetHeaderType: string; begin { Get header type name } Result := AAC_HEADER_TYPE[FHeaderTypeID]; end; { --------------------------------------------------------------------------- } function TAACfile.FGetMPEGVersion: string; begin { Get MPEG version name } Result := AAC_MPEG_VERSION[FMPEGVersionID]; end; { --------------------------------------------------------------------------- } function TAACfile.FGetProfile: string; begin { Get profile name } Result := AAC_PROFILE[FProfileID]; end; { --------------------------------------------------------------------------- } function TAACfile.FGetBitRateType: string; begin { Get bit rate type name } Result := AAC_BITRATE_TYPE[FBitRateTypeID]; end; { --------------------------------------------------------------------------- } function TAACfile.FGetDuration: Double; begin { Calculate duration time } if FBitRate = 0 then Result := 0 else Result := 8 * (FFileSize - ID3v2.Size) / FBitRate; end; { --------------------------------------------------------------------------- } function TAACfile.FIsValid: Boolean; begin { Check for file correctness } Result := (FHeaderTypeID <> AAC_HEADER_TYPE_UNKNOWN) and (FChannels > 0) and (FSampleRate > 0) and (FBitRate > 0); end; { --------------------------------------------------------------------------- } function TAACfile.FRecognizeHeaderType(const Source: TFileStreamEx): Byte; var Header: array [1..4] of Char; begin { Get header type of the file } Result := AAC_HEADER_TYPE_UNKNOWN; Source.Seek(FID3v2.Size, soFromBeginning); Source.Read(Header, SizeOf(Header)); if Header[1] + Header[2] + Header[3] + Header[4] = 'ADIF' then Result := AAC_HEADER_TYPE_ADIF else if (Byte(Header[1]) = $FF) and (Byte(Header[1]) and $F0 = $F0) then Result := AAC_HEADER_TYPE_ADTS; end; { --------------------------------------------------------------------------- } procedure TAACfile.FReadADIF(const Source: TFileStreamEx); var Position: Integer; begin { Read ADIF header data } Position := FID3v2.Size * 8 + 32; if ReadBits(Source, Position, 1) = 0 then Inc(Position, 3) else Inc(Position, 75); if ReadBits(Source, Position, 1) = 0 then FBitRateTypeID := AAC_BITRATE_TYPE_CBR else FBitRateTypeID := AAC_BITRATE_TYPE_VBR; Inc(Position, 1); FBitRate := ReadBits(Source, Position, 23); if FBitRateTypeID = AAC_BITRATE_TYPE_CBR then Inc(Position, 51) else Inc(Position, 31); FMPEGVersionID := AAC_MPEG_VERSION_4; FProfileID := ReadBits(Source, Position, 2) + 1; Inc(Position, 2); FSampleRate := SAMPLE_RATE[ReadBits(Source, Position, 4)]; Inc(Position, 4); Inc(FChannels, ReadBits(Source, Position, 4)); Inc(Position, 4); Inc(FChannels, ReadBits(Source, Position, 4)); Inc(Position, 4); Inc(FChannels, ReadBits(Source, Position, 4)); Inc(Position, 4); Inc(FChannels, ReadBits(Source, Position, 2)); end; { --------------------------------------------------------------------------- } procedure TAACfile.FReadADTS(const Source: TFileStreamEx); var Frames, TotalSize, Position: Integer; begin { Read ADTS header data } Frames := 0; TotalSize := 0; repeat Inc(Frames); Position := (FID3v2.Size + TotalSize) * 8; if ReadBits(Source, Position, 12) <> $FFF then break; Inc(Position, 12); if ReadBits(Source, Position, 1) = 0 then FMPEGVersionID := AAC_MPEG_VERSION_4 else FMPEGVersionID := AAC_MPEG_VERSION_2; Inc(Position, 4); FProfileID := ReadBits(Source, Position, 2) + 1; Inc(Position, 2); FSampleRate := SAMPLE_RATE[ReadBits(Source, Position, 4)]; Inc(Position, 5); FChannels := ReadBits(Source, Position, 3); if FMPEGVersionID = AAC_MPEG_VERSION_4 then Inc(Position, 9) else Inc(Position, 7); Inc(TotalSize, ReadBits(Source, Position, 13)); Inc(Position, 13); if ReadBits(Source, Position, 11) = $7FF then FBitRateTypeID := AAC_BITRATE_TYPE_VBR else FBitRateTypeID := AAC_BITRATE_TYPE_CBR; if FBitRateTypeID = AAC_BITRATE_TYPE_CBR then break; // more accurate //until (Frames = 1000) or (Source.Size <= FID3v2.Size + TotalSize); until (Source.Size <= FID3v2.Size + TotalSize); FTotalFrames := Frames; FBitRate := Round(8 * TotalSize / 1024 / Frames * FSampleRate); end; { ********************** Public functions & procedures ********************** } constructor TAACfile.Create; begin { Create object } FID3v1 := TID3v1.Create; FID3v2 := TID3v2.Create; FAPEtag := TAPEtag.Create; FResetData; inherited; end; { --------------------------------------------------------------------------- } destructor TAACfile.Destroy; begin { Destroy object } FID3v1.Free; FID3v2.Free; FAPEtag.Free; inherited; end; { --------------------------------------------------------------------------- } function TAACfile.ReadFromFile(const FileName: String): Boolean; var SourceFile: TFileStreamEx; begin { Read data from file } Result := false; FResetData; { At first search for tags, then try to recognize header type } if (FID3v2.ReadFromFile(FileName)) and (FID3v1.ReadFromFile(FileName)) and (FAPEtag.ReadFromFile(FileName)) then try SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); FFileSize := SourceFile.Size; FHeaderTypeID := FRecognizeHeaderType(SourceFile); { Read header data } if FHeaderTypeID = AAC_HEADER_TYPE_ADIF then FReadADIF(SourceFile); if FHeaderTypeID = AAC_HEADER_TYPE_ADTS then FReadADTS(SourceFile); SourceFile.Free; Result := true; except end; end; { --------------------------------------------------------------------------- } function TAACfile.FGetRatio: Double; begin { Get compression ratio } if FIsValid then Result := FFileSize / ((FTotalFrames * 1024) * (FChannels * 16 / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/AC3.pas����������������������������������������������0000644�0001750�0000144�00000014215�14743153644�021473� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TAC3 - for manipulating with AC3 Files } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2005 by Gambit } { } { Version 1.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.0 (05 January 2005) } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit AC3; interface uses Classes, SysUtils, DCClassesUtf8; const BIRATES: array[0..18] of Integer = (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640); type { Class TAC3 } TAC3 = class(TObject) private { Private declarations } FFileSize: Int64; FValid: Boolean; FChannels: Cardinal; FBits: Cardinal; FSampleRate: Cardinal; FBitrate: Word; FDuration: Double; function FGetRatio: Double; procedure FResetData; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load header } property FileSize: Int64 read FFileSize; property Valid: Boolean read FValid; property Channels: Cardinal read FChannels; property Bits: Cardinal read FBits; property SampleRate: Cardinal read FSampleRate; property Bitrate: Word read FBitrate; property Duration: Double read FDuration; property Ratio: Double read FGetRatio; { Compression ratio (%) } end; implementation { ********************** Private functions & procedures ********************* } procedure TAC3.FResetData; begin { Reset all data } FFileSize := 0; FValid := False; FChannels := 0; FBits := 0; FSampleRate := 0; FBitrate := 0; FDuration := 0; end; { ********************** Public functions & procedures ********************** } constructor TAC3.Create; begin { Create object } inherited; FResetData; end; (* -------------------------------------------------------------------------- *) destructor TAC3.Destroy; begin inherited; end; (* -------------------------------------------------------------------------- *) function TAC3.ReadFromFile(const FileName: String): Boolean; var f: TFileStreamEx; SignatureChunk: Word; tehByte: Byte; begin Result := False; FResetData; f:=nil; try f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite); //0x0B77 if (f.Read(SignatureChunk, SizeOf(SignatureChunk)) = SizeOf(SignatureChunk)) and (SignatureChunk = 30475) then begin FillChar(tehByte, SizeOf(tehByte),0); f.Seek(2, soFromCurrent); f.Read(tehByte, SizeOf(tehByte)); FFileSize := f.Size; FValid := TRUE; case (tehByte and $C0) of 0: FSampleRate := 48000; $40: FSampleRate := 44100; $80: FSampleRate := 32000; else FSampleRate := 0; end; FBitrate := BIRATES[(tehByte and $3F) shr 1]; FillChar(tehByte, SizeOf(tehByte),0); f.Seek(1, soFromCurrent); f.Read(tehByte, SizeOf(tehByte)); case (tehByte and $E0) of 0: FChannels := 2; $20: FChannels := 1; $40: FChannels := 2; $60: FChannels := 3; $80: FChannels := 3; $A0: FChannels := 4; $C0: FChannels := 4; $E0: FChannels := 5; else FChannels := 0; end; FBits := 16; FDuration := FFileSize * 8 / 1000 / FBitrate; Result := True; end; finally f.free; end; end; (* -------------------------------------------------------------------------- *) function TAC3.FGetRatio: Double; begin { Get compression ratio } if FValid then Result := FFileSize / ((FDuration * FSampleRate) * (FChannels * FBits / 8) + 44) * 100 else Result := 0; end; (* -------------------------------------------------------------------------- *) end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/APEtag.pas�������������������������������������������0000644�0001750�0000144�00000044035�14743153644�022231� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TAPEtag - for manipulating with APE tags } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 2.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 2.0 (30 May 2003) by Jean-Marie Prat } { - Writing support for APE 2.0 tags } { - Removed UTF8 decoding since calling application is supposed to provide } { or handle UTF8 strings. } { - Removed direct tag infos. All fields are now stored into an array. A } { specific field can be requested using SeekField function. } { - Introduced procedures to add/remove/order fields. } { } { Version 1.0 (21 April 2002) } { - Reading & writing support for APE 1.0 tags } { - Reading support for APE 2.0 tags (UTF-8 decoding) } { - Tag info: title, artist, album, track, year, genre, comment, copyright } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit APEtag; interface uses Classes, SysUtils, DCClassesUtf8; const { Tag ID } ID3V1_ID = 'TAG'; { ID3v1 } APE_ID = 'APETAGEX'; { APE } { Size constants } ID3V1_TAG_SIZE = 128; { ID3v1 tag } APE_TAG_FOOTER_SIZE = 32; { APE tag footer } APE_TAG_HEADER_SIZE = 32; { APE tag header } { Version of APE tag } APE_VERSION_1_0 = 1000; APE_VERSION_2_0 = 1000; type { APE tag header/footer - for internal use } RTagHeader = record { Real structure of APE footer } ID: array [0..7] of Char; { Always "APETAGEX" } Version: Integer; { Tag version } Size: Integer; { Tag size including footer } Fields: Integer; { Number of fields } Flags: Integer; { Tag flags } Reserved: array [0..7] of Char; { Reserved for later use } { Extended data } DataShift: Byte; { Used if ID3v1 tag found } FileSize: Integer; { File size (bytes) } end; RField = record Name: string; Value: String; end; AField = array of RField; { TAPETag } TAPETag = class private pField: Afield; pExists: Boolean; pVersion: Integer; pSize: Integer; function ReadFooter(sFile: String; var footer: RTagHeader): boolean; procedure ReadFields(sFile: String; footer: RTagHeader); private function GetTrack: Word; function GetYear: String; function GetGenre: String; function GetTitle: String; function GetAlbum: String; function GetArtist: String; function GetComment: String; function GetComposer: String; function GetCopyright: String; public property Exists: Boolean read pExists; { True if tag found } property Version: Integer read pVersion; { Tag version } property Fields: AField read pField; property Size: Integer read pSize; constructor Create(); function ReadFromFile(sFile: String): Boolean; function RemoveTagFromFile(sFile: String): Boolean; function WriteTagInFile(sFile: String): Boolean; procedure InsertField(pos: integer ; name: string ; value: String); { Insert field so that it has position pos} procedure RemoveField(pos: integer); procedure AppendField(name: string ; value: String); procedure SwapFields(pos1, pos2: integer); function SeekField(Field: string): String; procedure ResetData; property Title: String read GetTitle; { Song title } property Artist: String read GetArtist; { Artist name } property Album: String read GetAlbum; { Album title } property Track: Word read GetTrack; { Track number } property Year: String read GetYear; { Release year } property Genre: String read GetGenre; { Genre name } property Comment: String read GetComment; { Comment } property Composer: String read GetComposer; { Composer } property Copyright: String read GetCopyright; { Copyright } end; implementation //----------------------------------------------------------------------------// // Private stuff // //----------------------------------------------------------------------------// procedure TAPETag.ResetData(); begin SetLength(pField,0); pExists := False; pVersion := 0; pSize := 0; end; // ---------------------------------------------------------------------------- function TAPETag.ReadFooter(sFile: String; var footer: RTagHeader): boolean; var SourceFile: TFileStreamEx; TagID: array [1..3] of Char; Transferred: Integer; begin FillChar(Footer, SizeOf(Footer), 0); try Result := true; { Set read-access and open file } SourceFile := TFileStreamEx.Create(sFile, fmOpenRead or fmShareDenyWrite); Footer.FileSize := SourceFile.Size; if (IOResult <> 0) then begin SourceFile.Free; Result := False; Exit; end; { Check for existing ID3v1 tag } if (Footer.FileSize - ID3V1_TAG_SIZE > 0) then begin SourceFile.Seek(Footer.FileSize - ID3V1_TAG_SIZE, soFromBeginning); SourceFile.Read(TagID, SizeOf(TagID)); if TagID = ID3V1_ID then Footer.DataShift := ID3V1_TAG_SIZE else Footer.DataShift := 0; end; { Read footer data } Transferred := 0; if (Footer.FileSize - Footer.DataShift - APE_TAG_FOOTER_SIZE) > 0 then begin SourceFile.Seek(Footer.FileSize - Footer.DataShift - APE_TAG_FOOTER_SIZE, soFromBeginning); //BlockRead(SourceFile, Footer, APE_TAG_FOOTER_SIZE, Transferred); Transferred := SourceFile.Read(Footer, APE_TAG_FOOTER_SIZE); end; SourceFile.Free; { if transfer is not complete } if Transferred < APE_TAG_FOOTER_SIZE then Result := false; except { Error } Result := false; end; end; function TAPETag.GetAlbum: String; begin Result := SeekField('Album'); end; function TAPETag.GetArtist: String; begin Result := SeekField('Artist'); end; function TAPETag.GetComment: String; begin Result := SeekField('Comment'); end; function TAPETag.GetComposer: String; begin Result := SeekField('Composer'); end; function TAPETag.GetCopyright: String; begin Result := SeekField('Copyright'); end; function TAPETag.GetYear: String; begin Result := SeekField('Year'); end; function TAPETag.GetGenre: String; begin Result := SeekField('Genre'); end; function TAPETag.GetTitle: String; begin Result := SeekField('Title'); end; function TAPETag.GetTrack: Word; var TrackString: String; Index, Value, Code: Integer; begin { Extract track from string } TrackString := SeekField('Track'); Index := Pos('/', TrackString); if Index = 0 then Val(TrackString, Value, Code) else Val(Copy(TrackString, 1, Index - 1), Value, Code); if Code = 0 then Result := Value else Result := 0; end; // ---------------------------------------------------------------------------- procedure TAPETag.ReadFields(sFile: String; footer: RTagHeader); var SourceFile: TFileStreamEx; FieldName: String; FieldValue: array [1..250] of Char; NextChar: Char; Iterator, ValueSize, ValuePosition, FieldFlags: Integer; begin try { Set read-access, open file } SourceFile := TFileStreamEx.Create(sFile, fmOpenRead or fmShareDenyWrite); SourceFile.Seek(footer.FileSize - footer.DataShift - footer.Size, soFromBeginning); { Read all stored fields } SetLength(pField,footer.Fields); for Iterator := 0 to footer.Fields-1 do begin FillChar(FieldValue, SizeOf(FieldValue), 0); SourceFile.Read(ValueSize, SizeOf(ValueSize)); SourceFile.Read(FieldFlags, SizeOf(FieldFlags)); FieldName := ''; repeat SourceFile.Read(NextChar, SizeOf(NextChar)); FieldName := FieldName + NextChar; until Ord(NextChar) = 0; ValuePosition := SourceFile.Position; SourceFile.Read(FieldValue, ValueSize mod SizeOf(FieldValue)); pField[Iterator].Name := Trim(FieldName); pField[Iterator].Value := Trim(FieldValue); SourceFile.Seek(ValuePosition + ValueSize, soFromBeginning); end; SourceFile.Free; except end; end; //----------------------------------------------------------------------------// // Public stuff // //----------------------------------------------------------------------------// constructor TAPETag.Create(); begin inherited; ResetData; end; // ---------------------------------------------------------------------------- function TAPETag.ReadFromFile(sFile: String): Boolean; var Footer: RTagHeader; begin ResetData; Result := ReadFooter(sFile, Footer); { Process data if loaded and footer valid } if (Result) and (Footer.ID = APE_ID) then begin pExists := True; pVersion := Footer.Version; pSize := Footer.Size; ReadFields(sFile, Footer); end; end; // ---------------------------------------------------------------------------- function TAPETag.RemoveTagFromFile(sFile: String): Boolean; var SourceFile: TFileStreamEx; Footer: RTagHeader; ID3: pointer; begin Result := ReadFooter(sFile, Footer); { Process data if loaded and footer valid } if (Result) and (Footer.ID = APE_ID) then begin SourceFile := TFileStreamEx.Create(sFile, fmOpenReadWrite or fmShareDenyWrite); { If there is an ID3v1 tag roaming around behind the APE tag, we have to buffer it } if Footer.DataShift = ID3V1_TAG_SIZE then begin GetMem(ID3,ID3V1_TAG_SIZE); SourceFile.Seek(footer.FileSize - footer.DataShift, soFromBeginning); SourceFile.Read(ID3^, ID3V1_TAG_SIZE); end; { If this is an APEv2, header size must be added } if (Footer.Flags shr 31) > 0 then Inc(Footer.Size, APE_TAG_HEADER_SIZE); SourceFile.Seek(Footer.FileSize - footer.Size-Footer.DataShift, soFromBeginning); { If there is an ID3v1 tag roaming around, we copy it } if Footer.DataShift = ID3V1_TAG_SIZE then begin SourceFile.Write(ID3^, ID3V1_TAG_SIZE); FreeMem(ID3,128); end; SourceFile.Seek(Footer.FileSize-Footer.Size, soFromBeginning); //truncate SourceFile.Size := SourceFile.Position; SourceFile.Free; end; end; // ---------------------------------------------------------------------------- function TAPETag.WriteTagInFile(sFile: String): Boolean; const APEPreample: array [0..7] of char = ('A','P','E','T','A','G','E','X'); var SourceFile: TFileStreamEx; Header, Footer, RefFooter: RTagHeader; ID3: PChar; i, len, TagSize, Flags: integer; TagData: TStringStream; begin ID3 := nil; // method : first, save any eventual ID3v1 tag lying around // then we truncate the file after the audio data // then write the APE tag (and possibly the ID3) Result := ReadFooter(sFile, RefFooter); { Process data if loaded and footer valid } if (Result) and (RefFooter.ID = APE_ID) then begin SourceFile := TFileStreamEx.Create(sFile, fmOpenReadWrite or fmShareDenyWrite); { If there is an ID3v1 tag roaming around behind the APE tag, we have to buffer it } if RefFooter.DataShift = ID3V1_TAG_SIZE then begin GetMem(ID3,ID3V1_TAG_SIZE); SourceFile.Seek(Reffooter.FileSize - Reffooter.DataShift, soFromBeginning); SourceFile.Read(ID3^, ID3V1_TAG_SIZE); end; { If this is an APEv2, header size must be added } //if (RefFooter.Flags shr 31) > 0 then Inc(RefFooter.Size, APE_TAG_HEADER_SIZE); SourceFile.Seek(RefFooter.FileSize - RefFooter.Size-RefFooter.DataShift, soFromBeginning); //truncate SourceFile.Size := SourceFile.Position; SourceFile.Free; end; TagData := TStringStream.Create(''); TagSize := APE_TAG_FOOTER_SIZE; for i:=0 to high(pField) do begin TagSize := TagSize + 9 + Length(pField[i].Name) + Length(pField[i].Value); end; Header.ID[0] := 'A'; Header.ID[1] := 'P'; Header.ID[2] := 'E'; Header.ID[3] := 'T'; Header.ID[4] := 'A'; Header.ID[5] := 'G'; Header.ID[6] := 'E'; Header.ID[7] := 'X'; Header.Version := 2000; Header.Size := TagSize; Header.Fields := Length(pField); Header.Flags := Integer(0 or (1 shl 29) or (1 shl 31)); // tag contains a header and this is the header //ShowMessage(IntToSTr(Header.Flags)); TagData.Write(Header,APE_TAG_HEADER_SIZE); for i:=0 to high(pField) do begin len := Length(pField[i].Value); Flags := 0; TagData.Write(len, SizeOf(len)); TagData.Write(Flags, SizeOf(Flags)); TagData.WriteString(pField[i].Name + #0); TagData.WriteString(pField[i].Value); end; Footer.ID[0] := 'A'; Footer.ID[1] := 'P'; Footer.ID[2] := 'E'; Footer.ID[3] := 'T'; Footer.ID[4] := 'A'; Footer.ID[5] := 'G'; Footer.ID[6] := 'E'; Footer.ID[7] := 'X'; Footer.Version := 2000; Footer.Size := TagSize; Footer.Fields := Length(pField); Footer.Flags := Integer(0 or (1 shl 31)); // tag contains a header and this is the footer TagData.Write(Footer,APE_TAG_FOOTER_SIZE); if (RefFooter.DataShift = ID3V1_TAG_SIZE) and Assigned(ID3)then begin TagData.Write(ID3^,ID3V1_TAG_SIZE); FreeMem(ID3); end; SourceFile := TFileStreamEx.Create(sFile, fmOpenReadWrite or fmShareDenyWrite); SourceFile.Seek(0, soFromEnd); TagData.Seek(0, soFromBeginning); SourceFile.CopyFrom(TagData, TagData.Size); SourceFile.Free; TagData.Free; end; // ---------------------------------------------------------------------------- procedure TAPETag.InsertField (pos: integer ; name: string ; value: String); var dummy: AField; i: integer; begin if pos>=Length(pField) then exit; SetLength(dummy,Length(pField)-pos); dummy := copy(pField,pos,Length(dummy)); pField[pos].Name := name; pField[pos].Value := value; SetLength(pField,Length(pField)+1); for i:= pos+1 to high(pField) do pField[i] := dummy[i-pos-1]; end; // ---------------------------------------------------------------------------- procedure TAPETag.RemoveField (pos: integer); var i: integer; begin if pos>Length(pField) then exit; for i:=pos+1 to high(pField) do pField[i-1]:=pField[i]; SetLength(pField,Length(pField)-1); end; // ---------------------------------------------------------------------------- procedure TAPETag.AppendField(name: string ; value: String); begin SetLength(pField,Length(pField)+1); pField[high(pField)].Name := name; pField[high(pField)].Value := value; end; // ---------------------------------------------------------------------------- procedure TAPETag.SwapFields (pos1, pos2: integer); var dummy: RField; begin dummy.Name := pField[pos1].Name; dummy.Value := pField[pos1].Value; pField[pos1].Name := pField[pos2].Name; pField[pos1].Value := pField[pos2].Value; pField[pos2].Name := dummy.Name; pField[pos2].Value := dummy.Value; end; // ---------------------------------------------------------------------------- function TAPETag.SeekField(Field: string): String; var i: integer; begin Result := ''; for i:=0 to high(pField) do begin if UpperCase(Field)=UpperCase(pField[i].Name) then begin Result := pField[i].Value; Break; end; end; end; // ---------------------------------------------------------------------------- end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/CDAtrack.pas�����������������������������������������0000644�0001750�0000144�00000016300�14743153644�022536� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TCDAtrack - for getting information for CDDA track } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.0 (4 November 2002) } { - Using cdplayer.ini } { - Track info: title, artist, album, duration, track number, position } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit CDAtrack; interface uses Classes, SysUtils, IniFiles, DCClassesUtf8; type { Class TCDAtrack } TCDAtrack = class(TObject) private { Private declarations } FValid: Boolean; FTitle: String; FArtist: String; FAlbum: String; FDuration: Double; FTrack: Word; FPosition: Double; procedure FResetData; public { Public declarations } constructor Create; { Create object } function ReadFromFile(const FileName: String): Boolean; { Load data } property Valid: Boolean read FValid; { True if valid format } property Title: String read FTitle; { Song title } property Artist: String read FArtist; { Artist name } property Album: String read FAlbum; { Album name } property Duration: Double read FDuration; { Duration (seconds) } property Track: Word read FTrack; { Track number } property Position: Double read FPosition; { Track position (seconds) } end; implementation type { CDA track data } TrackData = packed record RIFFHeader: array [1..4] of Char; { Always "RIFF" } FileSize: Integer; { Always "RealFileSize - 8" } CDDAHeader: array [1..8] of Char; { Always "CDDAfmt " } FormatSize: Integer; { Always 24 } FormatID: Word; { Always 1 } TrackNumber: Word; { Track number } Serial: Integer; { CD serial number (stored in cdplayer.ini) } PositionHSG: Integer; { Track position in HSG format } DurationHSG: Integer; { Track duration in HSG format } PositionRB: Integer; { Track position in Red-Book format } DurationRB: Integer; { Track duration in Red-Book format } Title: string; { Song title } Artist: string; { Artist name } Album: string; { Album name } end; { ********************* Auxiliary functions & procedures ******************** } function ReadData(const FileName: String; var Data: TrackData): Boolean; var SourceFile: TFileStreamEx; CDData: TIniFile; begin { Read track data } Result := false; try SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); SourceFile.Read(Data, 44); SourceFile.Free; Result := true; { Try to get song info } CDData := TIniFile.Create('cdplayer.ini'); Data.Title := CDData.ReadString(IntToHex(Data.Serial, 2), IntToStr(Data.TrackNumber), ''); Data.Artist := CDData.ReadString(IntToHex(Data.Serial, 2), 'artist', ''); Data.Album := CDData.ReadString(IntToHex(Data.Serial, 2), 'title', ''); CDData.Free; except end; end; { --------------------------------------------------------------------------- } function IsValid(const Data: TrackData): Boolean; begin { Check for format correctness } Result := (Data.RIFFHeader = 'RIFF') and (Data.CDDAHeader = 'CDDAfmt '); end; { ********************** Private functions & procedures ********************* } procedure TCDAtrack.FResetData; begin { Reset variables } FValid := false; FTitle := ''; FArtist := ''; FAlbum := ''; FDuration := 0; FTrack := 0; FPosition := 0; end; { ********************** Public functions & procedures ********************** } constructor TCDAtrack.Create; begin { Create object } inherited; FResetData; end; { --------------------------------------------------------------------------- } function TCDAtrack.ReadFromFile(const FileName: String): Boolean; var Data: TrackData; begin { Reset variables and load file data } FResetData; FillChar(Data, SizeOf(Data), 0); Result := ReadData(FileName, Data); { Process data if loaded and valid } if Result and IsValid(Data) then begin FValid := true; { Fill properties with loaded data } FTitle := Data.Title; FArtist := Data.Artist; FAlbum := Data.Album; FDuration := Data.DurationHSG / 75; FTrack := Data.TrackNumber; FPosition := Data.PositionHSG / 75; end; end; { --------------------------------------------------------------------------- } end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/COPYING.txt������������������������������������������0000644�0001750�0000144�00000064500�14743153644�022273� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/DTS.pas����������������������������������������������0000644�0001750�0000144�00000015623�14743153644�021563� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TDTS - for manipulating with DTS Files } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2005 by Gambit } { } { Version 1.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.0 (10 January 2005) } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit DTS; interface uses Classes, SysUtils, DCClassesUtf8; const BIRATES: array[0..31] of Integer = (32, 56, 64, 96, 112, 128, 192, 224, 256, 320, 384, 448, 512, 576, 640, 768, 960, 1024, 1152, 1280, 1344, 1408, 1411, 1472, 1536, 1920, 2048, 3072, 3840, 0, -1, 1); //open, variable, lossless type { Class TDTS } TDTS = class(TObject) private { Private declarations } FFileSize: Int64; FValid: Boolean; FChannels: Cardinal; FBits: Cardinal; FSampleRate: Cardinal; FBitrate: Word; FDuration: Double; function FGetRatio: Double; procedure FResetData; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load header } property FileSize: Int64 read FFileSize; property Valid: Boolean read FValid; property Channels: Cardinal read FChannels; property Bits: Cardinal read FBits; property SampleRate: Cardinal read FSampleRate; property Bitrate: Word read FBitrate; property Duration: Double read FDuration; property Ratio: Double read FGetRatio; { Compression ratio (%) } end; implementation { ********************** Private functions & procedures ********************* } procedure TDTS.FResetData; begin { Reset all data } FFileSize := 0; FValid := False; FChannels := 0; FBits := 0; FSampleRate := 0; FBitrate := 0; FDuration := 0; end; { ********************** Public functions & procedures ********************** } constructor TDTS.Create; begin { Create object } inherited; FResetData; end; (* -------------------------------------------------------------------------- *) destructor TDTS.Destroy; begin inherited; end; (* -------------------------------------------------------------------------- *) function TDTS.ReadFromFile(const FileName: String): Boolean; var f: TFileStreamEx; SignatureChunk: Cardinal; tehWord: Word; gayDTS: array[0..7] of Byte; begin Result := False; FResetData; f:=nil; try f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite); //0x7FFE8001 if (f.Read(SignatureChunk, SizeOf(SignatureChunk)) = SizeOf(SignatureChunk)) and (SignatureChunk = 25230975) then begin FillChar(gayDTS, SizeOf(gayDTS),0); f.Seek(3, soFromCurrent); f.Read(gayDTS, SizeOf(gayDTS)); FFileSize := f.Size; FValid := TRUE; tehWord := gayDTS[1] or (gayDTS[0] shl 8); case ((tehWord and $0FC0) shr 6) of 0: FChannels := 1; 1..4: FChannels := 2; 5..6: FChannels := 3; 7..8: FChannels := 4; 9: FChannels := 5; 10..12: FChannels := 6; 13: FChannels := 7; 14..15: FChannels := 8; else FChannels := 0; end; case ((tehWord and $3C) shr 2) of 1: FSampleRate := 8000; 2: FSampleRate := 16000; 3: FSampleRate := 32000; 6: FSampleRate := 11025; 7: FSampleRate := 22050; 8: FSampleRate := 44100; 11: FSampleRate := 12000; 12: FSampleRate := 24000; 13: FSampleRate := 48000; else FSampleRate := 0; end; tehWord := 0; tehWord := gayDTS[2] or (gayDTS[1] shl 8); FBitrate := BIRATES[(tehWord and $03E0) shr 5]; tehWord := 0; tehWord := gayDTS[7] or (gayDTS[6] shl 8); case ((tehWord and $01C0) shr 6) of 0..1: FBits := 16; 2..3: FBits := 20; 4..5: FBits := 24; else FBits := 16; end; FDuration := FFileSize * 8 / 1000 / FBitrate; Result := True; end; finally f.free; end; end; (* -------------------------------------------------------------------------- *) function TDTS.FGetRatio: Double; begin { Get compression ratio } if FValid then Result := FFileSize / ((FDuration * FSampleRate) * (FChannels * FBits / 8) + 44) * 100 else Result := 0; end; (* -------------------------------------------------------------------------- *) end. �������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/FLACfile.pas�����������������������������������������0000644�0001750�0000144�00000071733�14743153644�022502� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TFLACfile - for manipulating with FLAC file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.4 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.3 (13 August 2004) by jtclipper } { - unit rewritten, VorbisComment is obsolete now } { } { Version 1.2 (23 June 2004) by sundance } { - Check for ID3 tags (although not supported) } { - Don't parse for other FLAC metablocks if FLAC header is missing } { } { Version 1.1 (6 July 2003) by Erik } { - Class: Vorbis comments (native comment to FLAC files) added } { } { Version 1.0 (13 August 2002) } { - Info: channels, sample rate, bits/sample, file size, duration, ratio } { - Class TID3v1: reading & writing support for ID3v1 tags } { - Class TID3v2: reading & writing support for ID3v2 tags } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit FLACfile; interface uses Classes, SysUtils, StrUtils, ID3v2, DCClassesUtf8, DCBasicTypes, DCOSUtils; const META_STREAMINFO = 0; META_PADDING = 1; META_APPLICATION = 2; META_SEEKTABLE = 3; META_VORBIS_COMMENT = 4; META_CUESHEET = 5; META_PICTURE = 6; type TFlacHeader = record StreamMarker: array[1..4] of Char; //should always be 'fLaC' MetaDataBlockHeader: array[1..4] of Byte; Info: array[1..18] of Byte; MD5Sum: array[1..16] of Byte; end; TMetaData = record MetaDataBlockHeader: array[1..4] of Byte; Data: TMemoryStream; end; { TFLACfile } TFLACfile = class(TObject) private FHeader: TFlacHeader; FFileName: String; FPaddingIndex: integer; FPaddingLast: boolean; FPaddingFragments: boolean; FVorbisIndex: integer; FPadding: integer; FVCOffset: integer; FAudioOffset: integer; FChannels: byte; FSampleRate: integer; FBitsPerSample: byte; FBitrate: integer; FFileLength: integer; FSamples: Int64; aMetaBlockOther: array of TMetaData; // tag data FVendor: string; FTagSize: integer; FExists: boolean; FID3v2: TID3v2; function FGetHasLyrics: boolean; procedure FResetData( const bHeaderInfo, bTagFields :boolean ); function FIsValid: Boolean; function FGetDuration: Double; function FGetTrack: Word; function FGetRatio: Double; function FGetChannelMode: string; function GetInfo( sFile: String; bSetTags: boolean ): boolean; procedure AddMetaDataOther( aMetaHeader: array of Byte; stream: TFileStreamEx; const iBlocklength,iIndex: integer ); procedure ReadTag( Source: TFileStreamEx; bSetTagFields: boolean ); function RebuildFile( const sFile: String; VorbisBlock: TStringStream ): Boolean; public TrackString: string; Title: string; Artist: string; Album: string; Year: string; Genre: string; Comment: string; //extra xTones: string; xStyles: string; xMood: string; xSituation: string; xRating: string; xQuality: string; xTempo: string; xType: string; // Composer: string; Language: string; Copyright: string; Link: string; Encoder: string; Lyrics: string; Performer: string; License: string; Organization: string; Description: string; Location: string; Contact: string; ISRC: string; aExtraFields: array of array of string; constructor Create; destructor Destroy; override; function ReadFromFile( const sFile: String ): boolean; function SaveToFile( const sFile: String; const bBasicOnly: boolean = false ): boolean; function RemoveFromFile( const sFile: String ):boolean; procedure AddExtraField(const sID, sValue: string); property Channels: Byte read FChannels; // Number of channels property SampleRate: Integer read FSampleRate; // Sample rate (hz) property BitsPerSample: Byte read FBitsPerSample; // Bits per sample property FileLength: integer read FFileLength; // File length (bytes) property Samples: Int64 read FSamples; // Number of samples property Valid: Boolean read FIsValid; // True if header valid property Duration: Double read FGetDuration; // Duration (seconds) property Ratio: Double read FGetRatio; // Compression ratio (%) property Track: Word read FGetTrack; // Track number property Bitrate: integer read FBitrate; property ChannelMode: string read FGetChannelMode; property Exists: boolean read FExists; property Vendor: string read FVendor; property FileName: String read FFileName; property AudioOffset: integer read FAudioOffset; //offset of audio data property HasLyrics: boolean read FGetHasLyrics; end; var bTAG_PreserveDate: boolean; implementation (* -------------------------------------------------------------------------- *) procedure TFLACfile.FResetData( const bHeaderInfo, bTagFields :boolean ); var i: integer; begin if bHeaderInfo then begin FFileName := ''; FPadding := 0; FPaddingLast := false; FPaddingFragments := false; FChannels := 0; FSampleRate := 0; FBitsPerSample := 0; FFileLength := 0; FSamples := 0; FVorbisIndex := 0; FPaddingIndex := 0; FVCOffset := 0; FAudioOffset := 0; for i := 0 to Length( aMetaBlockOther ) - 1 do aMetaBlockOther[ i ].Data.Free; SetLength( aMetaBlockOther, 0 ); end; //tag data if bTagFields then begin FVendor := ''; FTagSize := 0; FExists := false; Title := ''; Artist := ''; Album := ''; TrackString := ''; Year := ''; Genre := ''; Comment := ''; //extra xTones := ''; xStyles := ''; xMood := ''; xSituation := ''; xRating := ''; xQuality := ''; xTempo := ''; xType := ''; // Composer := ''; Language := ''; Copyright := ''; Link := ''; Encoder := ''; Lyrics := ''; Performer := ''; License := ''; Organization := ''; Description := ''; Location := ''; Contact := ''; ISRC := ''; SetLength( aExtraFields, 0 ); end; end; (* -------------------------------------------------------------------------- *) // Check for right FLAC file data function TFLACfile.FIsValid: Boolean; begin result := (FHeader.StreamMarker = 'fLaC') and (FChannels > 0) and (FSampleRate > 0) and (FBitsPerSample > 0) and (FSamples > 0); end; (* -------------------------------------------------------------------------- *) function TFLACfile.FGetDuration: Double; begin if (FIsValid) and (FSampleRate > 0) then begin result := FSamples / FSampleRate end else begin result := 0; end; end; (* -------------------------------------------------------------------------- *) function TFLACfile.FGetTrack: Word; var Index, Value, Code: Integer; begin { Extract track from string } Index := Pos('/', TrackString); if Index = 0 then Val(TrackString, Value, Code) else Val(Copy(TrackString, 1, Index - 1), Value, Code); if Code = 0 then Result := Value else Result := 0; end; (* -------------------------------------------------------------------------- *) // Get compression ratio function TFLACfile.FGetRatio: Double; begin if FIsValid then begin result := FFileLength / (FSamples * FChannels * FBitsPerSample / 8) * 100 end else begin result := 0; end; end; (* -------------------------------------------------------------------------- *) // Get channel mode function TFLACfile.FGetChannelMode: string; begin if FIsValid then begin case FChannels of 1 : result := 'Mono'; 2 : result := 'Stereo'; else result := 'Multi Channel'; end; end else begin result := ''; end; end; (* -------------------------------------------------------------------------- *) function TFLACfile.FGetHasLyrics: boolean; begin result := ( Trim( Lyrics ) <> '' ); end; (* -------------------------------------------------------------------------- *) constructor TFLACfile.Create; begin inherited; FID3v2 := TID3v2.Create; FResetData( true, true ); end; destructor TFLACfile.Destroy; begin FResetData( true, true ); FID3v2.Free; inherited; end; (* -------------------------------------------------------------------------- *) function TFLACfile.ReadFromFile( const sFile: String ): boolean; begin FResetData( false, true ); result := GetInfo( sFile, true ); end; (* -------------------------------------------------------------------------- *) function TFLACfile.GetInfo( sFile: String; bSetTags: boolean ): boolean; var SourceFile: TFileStreamEx; aMetaDataBlockHeader: array[1..4] of byte; iBlockLength, iMetaType, iIndex: integer; bPaddingFound: boolean; begin result := true; bPaddingFound := false; FResetData( true, false ); try { Read data from ID3 tags } FID3v2.ReadFromFile(sFile); // Set read-access and open file SourceFile := TFileStreamEx.Create(sFile, fmOpenRead or fmShareDenyWrite); FFileLength := SourceFile.Size; FFileName := sFile; { Seek past the ID3v2 tag, if there is one } if FID3v2.Exists then begin SourceFile.Seek(FID3v2.Size, soFromBeginning) end; // Read header data FillChar( FHeader, SizeOf(FHeader), 0 ); SourceFile.Read( FHeader, SizeOf(FHeader) ); // Process data if loaded and header valid if FHeader.StreamMarker = 'fLaC' then begin with FHeader do begin FChannels := ( Info[13] shr 1 and $7 + 1 ); FSampleRate := ( Info[11] shl 12 or Info[12] shl 4 or Info[13] shr 4 ); FBitsPerSample := ( Info[13] and 1 shl 4 or Info[14] shr 4 + 1 ); FSamples := ( Info[15] shl 24 or Info[16] shl 16 or Info[17] shl 8 or Info[18] ); end; if (FHeader.MetaDataBlockHeader[1] and $80) <> 0 then exit; //no metadata blocks exist iIndex := 0; repeat // read more metadata blocks if available SourceFile.Read( aMetaDataBlockHeader, 4 ); iIndex := iIndex + 1; // metadatablock index iBlockLength := (aMetaDataBlockHeader[2] shl 16 or aMetaDataBlockHeader[3] shl 8 or aMetaDataBlockHeader[4]); //decode length if iBlockLength <= 0 then exit; // can it be 0 ? iMetaType := (aMetaDataBlockHeader[1] and $7F); // decode metablock type if iMetaType = META_VORBIS_COMMENT then begin // read vorbis block FVCOffset := SourceFile.Position; FTagSize := iBlockLength; FVorbisIndex := iIndex; ReadTag(SourceFile, bSetTags); // set up fields end else if (iMetaType = META_PADDING) and not bPaddingFound then begin // we have padding block FPadding := iBlockLength; // if we find more skip & put them in metablock array FPaddingLast := ((aMetaDataBlockHeader[1] and $80) <> 0); FPaddingIndex := iIndex; bPaddingFound := true; SourceFile.Seek(FPadding, soCurrent); // advance into file till next block or audio data start end else begin // all other if iMetaType <= META_PICTURE then begin // is it a valid metablock ? if (iMetaType = META_PADDING) then begin // set flag for fragmented padding blocks FPaddingFragments := true; end; AddMetaDataOther(aMetaDataBlockHeader, SourceFile, iBlocklength, iIndex); end else begin FSamples := 0; // ops... Exit; end; end; until ((aMetaDataBlockHeader[1] and $80) <> 0); // until is last flag ( first bit = 1 ) end; finally if FIsValid then begin FAudioOffset := SourceFile.Position; // we need that to rebuild the file if nedeed FBitrate := Round( ( ( FFileLength - FAudioOffset ) / 1000 ) * 8 / FGetDuration ); //time to calculate average bitrate end else begin result := false; end; FreeAndNil(SourceFile); end; end; (* -------------------------------------------------------------------------- *) procedure TFLACfile.AddMetaDataOther( aMetaHeader: array of Byte; stream: TFileStreamEx; const iBlocklength,iIndex: integer ); var iMetaLen: integer; begin // enlarge array iMetaLen := Length( aMetaBlockOther ) + 1; SetLength( aMetaBlockOther, iMetaLen ); // save header aMetaBlockOther[ iMetaLen - 1 ].MetaDataBlockHeader[1] := aMetaHeader[0]; aMetaBlockOther[ iMetaLen - 1 ].MetaDataBlockHeader[2] := aMetaHeader[1]; aMetaBlockOther[ iMetaLen - 1 ].MetaDataBlockHeader[3] := aMetaHeader[2]; aMetaBlockOther[ iMetaLen - 1 ].MetaDataBlockHeader[4] := aMetaHeader[3]; // save content in a stream aMetaBlockOther[ iMetaLen - 1 ].Data := TMemoryStream.Create; aMetaBlockOther[ iMetaLen - 1 ].Data.Position := 0; aMetaBlockOther[ iMetaLen - 1 ].Data.CopyFrom( stream, iBlocklength ); end; (* -------------------------------------------------------------------------- *) procedure TFLACfile.ReadTag( Source: TFileStreamEx; bSetTagFields: boolean ); var i, iCount, iSize, iSepPos: Integer; Data, sFieldID, sFieldData: String; begin Source.Read( iSize, SizeOf( iSize ) ); // vendor SetLength( Data, iSize ); Source.Read( Data[ 1 ], iSize ); FVendor := String( Data ); Source.Read( iCount, SizeOf( iCount ) ); //fieldcount FExists := ( iCount > 0 ); for i := 0 to iCount - 1 do begin Source.Read( iSize, SizeOf( iSize ) ); SetLength( Data , iSize ); Source.Read( Data[ 1 ], iSize ); if not bSetTagFields then Continue; // if we don't want to re asign fields we skip iSepPos := Pos( '=', String( Data ) ); if iSepPos > 0 then begin sFieldID := UpperCase( Copy( String( Data ), 1, iSepPos - 1) ); sFieldData := Copy( String( Data ), iSepPos + 1, MaxInt ); if (sFieldID = 'TRACKNUMBER') and (TrackString = '') then begin TrackString := sFieldData; end else if (sFieldID = 'ARTIST') and (Artist = '') then begin Artist := sFieldData; end else if (sFieldID = 'ALBUM') and (Album = '') then begin Album := sFieldData; end else if (sFieldID = 'TITLE') and (Title = '') then begin Title := sFieldData; end else if (sFieldID = 'DATE') and (Year = '') then begin Year := sFieldData; end else if (sFieldID = 'GENRE') and (Genre = '') then begin Genre := sFieldData; end else if (sFieldID = 'COMMENT') and (Comment = '') then begin Comment := sFieldData; end else if (sFieldID = 'COMPOSER') and (Composer = '') then begin Composer := sFieldData; end else if (sFieldID = 'LANGUAGE') and (Language = '') then begin Language := sFieldData; end else if (sFieldID = 'COPYRIGHT') and (Copyright = '') then begin Copyright := sFieldData; end else if (sFieldID = 'URL') and (Link = '') then begin Link := sFieldData; end else if (sFieldID = 'ENCODER') and (Encoder = '') then begin Encoder := sFieldData; end else if (sFieldID = 'TONES') and (xTones = '') then begin xTones := sFieldData; end else if (sFieldID = 'STYLES') and (xStyles = '') then begin xStyles := sFieldData; end else if (sFieldID = 'MOOD') and (xMood = '') then begin xMood := sFieldData; end else if (sFieldID = 'SITUATION') and (xSituation = '') then begin xSituation := sFieldData; end else if (sFieldID = 'RATING') and (xRating = '') then begin xRating := sFieldData; end else if (sFieldID = 'QUALITY') and (xQuality = '') then begin xQuality := sFieldData; end else if (sFieldID = 'TEMPO') and (xTempo = '') then begin xTempo := sFieldData; end else if (sFieldID = 'TYPE') and (xType = '') then begin xType := sFieldData; end else if (sFieldID = 'LYRICS') and (Lyrics = '') then begin Lyrics := sFieldData; end else if (sFieldID = 'PERFORMER') and (Performer = '') then begin Performer := sFieldData; end else if (sFieldID = 'LICENSE') and (License = '') then begin License := sFieldData; end else if (sFieldID = 'ORGANIZATION') and (Organization = '') then begin Organization := sFieldData; end else if (sFieldID = 'DESCRIPTION') and (Description = '') then begin Description := sFieldData; end else if (sFieldID = 'LOCATION') and (Location = '') then begin Location := sFieldData; end else if (sFieldID = 'CONTACT') and (Contact = '') then begin Contact := sFieldData; end else if (sFieldID = 'ISRC') and (ISRC = '') then begin ISRC := sFieldData; end else begin // more fields AddExtraField( sFieldID, sFieldData ); end; end; end; end; (* -------------------------------------------------------------------------- *) procedure TFLACfile.AddExtraField(const sID, sValue: string); var iExtraLen: integer; begin iExtraLen := Length( aExtraFields ) + 1; SetLength( aExtraFields, iExtraLen ); SetLength( aExtraFields[ iExtraLen - 1 ], 2 ); aExtraFields[ iExtraLen - 1, 0 ] := sID; aExtraFields[ iExtraLen - 1, 1 ] := sValue; end; (* -------------------------------------------------------------------------- *) function TFLACfile.SaveToFile( const sFile: String; const bBasicOnly: boolean = false ): boolean; var i, iFieldCount, iSize: Integer; VorbisBlock, Tag: TStringStream; procedure _WriteTagBuff( sID, sData: string ); var sTmp: string; iTmp: integer; begin if sData <> '' then begin sTmp := sID + '=' + sData; iTmp := Length( sTmp ); Tag.Write( iTmp, SizeOf( iTmp ) ); Tag.WriteString( sTmp ); iFieldCount := iFieldCount + 1; end; end; begin try result := false; Tag := TStringStream.Create(''); VorbisBlock := TStringStream.Create(''); if not GetInfo( sFile, false ) then exit; //reload all except tag fields iFieldCount := 0; _WriteTagBuff( 'TRACKNUMBER', TrackString ); _WriteTagBuff( 'ARTIST', Artist ); _WriteTagBuff( 'ALBUM', Album ); _WriteTagBuff( 'TITLE', Title ); _WriteTagBuff( 'DATE', Year ); _WriteTagBuff( 'GENRE', Genre ); _WriteTagBuff( 'COMMENT', Comment ); _WriteTagBuff( 'COMPOSER', Composer ); _WriteTagBuff( 'LANGUAGE', Language ); _WriteTagBuff( 'COPYRIGHT', Copyright ); _WriteTagBuff( 'URL', Link ); _WriteTagBuff( 'ENCODER', Encoder ); _WriteTagBuff( 'TONES', xTones ); _WriteTagBuff( 'STYLES', xStyles ); _WriteTagBuff( 'MOOD', xMood ); _WriteTagBuff( 'SITUATION', xSituation ); _WriteTagBuff( 'RATING', xRating ); _WriteTagBuff( 'QUALITY', xQuality ); _WriteTagBuff( 'TEMPO', xTempo ); _WriteTagBuff( 'TYPE', xType ); if not bBasicOnly then begin _WriteTagBuff( 'PERFORMER', Performer ); _WriteTagBuff( 'LICENSE', License ); _WriteTagBuff( 'ORGANIZATION', Organization ); _WriteTagBuff( 'DESCRIPTION', Description ); _WriteTagBuff( 'LOCATION', Location ); _WriteTagBuff( 'CONTACT', Contact ); _WriteTagBuff( 'ISRC', ISRC ); _WriteTagBuff( 'LYRICS', Lyrics ); for i := 0 to Length( aExtraFields ) - 1 do begin if Trim( aExtraFields[ i, 0 ] ) <> '' then _WriteTagBuff( aExtraFields[ i, 0 ], aExtraFields[ i, 1 ] ); end; end; // Write vendor info and number of fields with VorbisBlock do begin if FVendor = '' then FVendor := 'reference libFLAC 1.1.0 20030126'; // guess it iSize := Length( FVendor ); Write( iSize, SizeOf( iSize ) ); WriteString( FVendor ); Write( iFieldCount, SizeOf( iFieldCount ) ); end; VorbisBlock.CopyFrom( Tag, 0 ); // All tag data is here now VorbisBlock.Position := 0; result := RebuildFile( sFile, VorbisBlock ); FExists := result and (Tag.Size > 0 ); finally FreeAndNil( Tag ); FreeAndNil( VorbisBlock ); end; end; (* -------------------------------------------------------------------------- *) function TFLACfile.RemoveFromFile( const sFile: String ):boolean; begin FResetData( false, true ); result := SaveToFile( sFile ); if FExists then FExists := not result; end; (* -------------------------------------------------------------------------- *) // saves metablocks back to the file // always tries to rebuild header so padding exists after comment block and no more than 1 padding block exists function TFLACfile.RebuildFile( const sFile: String; VorbisBlock: TStringStream ): Boolean; var iFileAge: TFileTime; Source, Destination: TFileStreamEx; i, iNewPadding, iMetaCount, iExtraPadding: Integer; BufferName, sTmp: string; MetaDataBlockHeader: array[1..4] of Byte; oldHeader: TFlacHeader; MetaBlocks: TMemoryStream; bRebuild, bRearange: boolean; begin result := false; bRearange := false; iExtraPadding := 0; if (not mbFileExists(FileName)) or (not mbFileSetReadOnly(FileName, False)) then exit; try iFileAge := 0; if bTAG_PreserveDate then iFileAge := mbFileAge( FileName ); // re arrange other metadata in case of // 1. padding block is not aligned after vorbis comment // 2. insufficient padding - rearange upon file rebuild // 3. fragmented padding blocks iMetaCount := Length( aMetaBlockOther ); if (FPaddingIndex <> FVorbisIndex + 1) or (FPadding <= VorbisBlock.Size - FTagSize ) or FPaddingFragments then begin MetaBlocks := TMemoryStream.Create; for i := 0 to iMetaCount - 1 do begin aMetaBlockOther[ i ].MetaDataBlockHeader[ 1 ] := ( aMetaBlockOther[ i ].MetaDataBlockHeader[ 1 ] and $7f ); // not last if aMetaBlockOther[ i ].MetaDataBlockHeader[ 1 ] = META_PADDING then begin iExtraPadding := iExtraPadding + aMetaBlockOther[ i ].Data.Size + 4; // add padding size plus 4 bytes of header block end else begin aMetaBlockOther[ i ].Data.Position := 0; MetaBlocks.Write( aMetaBlockOther[ i ].MetaDataBlockHeader[ 1 ], 4 ); MetaBlocks.CopyFrom( aMetaBlockOther[ i ].Data, 0 ); end; end; MetaBlocks.Position := 0; bRearange := true; end; // set up file if (FPadding <= VorbisBlock.Size - FTagSize ) then begin // no room rebuild the file from scratch bRebuild := true; BufferName := FileName + '~'; Source := TFileStreamEx.Create( FileName, fmOpenRead ); // Set read-only and open old file, and create new Destination := TFileStreamEx.Create( BufferName, fmCreate ); Source.Read( oldHeader, sizeof( oldHeader ) ); oldHeader.MetaDataBlockHeader[ 1 ] := (oldHeader.MetaDataBlockHeader[ 1 ] and $7f ); //just in case no metadata existed Destination.Write( oldHeader, Sizeof( oldHeader ) ); Destination.CopyFrom( MetaBlocks, 0 ); end else begin bRebuild := false; Source := nil; Destination := TFileStreamEx.Create( FileName, fmOpenWrite); // Set write-access and open file if bRearange then begin Destination.Seek( SizeOf( FHeader ), soFromBeginning ); Destination.CopyFrom( MetaBlocks, 0 ); end else begin Destination.Seek( FVCOffset - 4, soFromBeginning ); end; end; // finally write vorbis block MetaDataBlockHeader[1] := META_VORBIS_COMMENT; MetaDataBlockHeader[2] := Byte(( VorbisBlock.Size shr 16 ) and 255 ); MetaDataBlockHeader[3] := Byte(( VorbisBlock.Size shr 8 ) and 255 ); MetaDataBlockHeader[4] := Byte( VorbisBlock.Size and 255 ); Destination.Write( MetaDataBlockHeader[ 1 ], SizeOf( MetaDataBlockHeader ) ); Destination.CopyFrom( VorbisBlock, VorbisBlock.Size ); // and add padding if FPaddingLast or bRearange then begin MetaDataBlockHeader[1] := META_PADDING or $80; end else begin MetaDataBlockHeader[1] := META_PADDING; end; if bRebuild then begin iNewPadding := 4096; // why not... end else begin if FTagSize > VorbisBlock.Size then begin // tag got smaller increase padding iNewPadding := (FPadding + FTagSize - VorbisBlock.Size) + iExtraPadding; end else begin // tag got bigger shrink padding iNewPadding := (FPadding - VorbisBlock.Size + FTagSize ) + iExtraPadding; end; end; MetaDataBlockHeader[2] := Byte(( iNewPadding shr 16 ) and 255 ); MetaDataBlockHeader[3] := Byte(( iNewPadding shr 8 ) and 255 ); MetaDataBlockHeader[4] := Byte( iNewPadding and 255 ); Destination.Write(MetaDataBlockHeader[ 1 ], 4); if (FPadding <> iNewPadding) or bRearange then begin // fill the block with zeros sTmp := DupeString( #0, iNewPadding ); Destination.Write( sTmp[1], iNewPadding ); end; // finish if bRebuild then begin // time to put back the audio data... Source.Seek( FAudioOffset, soFromBeginning ); Destination.CopyFrom( Source, Source.Size - FAudioOffset ); Source.Free; Destination.Free; if ( mbDeleteFile( FileName ) ) and ( mbRenameFile( BufferName, FileName ) ) then begin //Replace old file and delete temporary file result := true end else begin raise Exception.Create(''); end; end else begin result := true; Destination.Free; end; // post save tasks if bTAG_PreserveDate then mbFileSetTime( FileName, iFileAge ); if bRearange then FreeAndNil( MetaBlocks ); except // Access error if mbFileExists( BufferName ) then mbDeleteFile( BufferName ); end; end; (* -------------------------------------------------------------------------- *) end. �������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/ID3v1.pas��������������������������������������������0000644�0001750�0000144�00000071327�14743153644�021762� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TID3v1 - for manipulating with ID3v1 tags } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.2 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.1 (16 June 2004) by jtclipper } { - added support for Lyrics3 v2.00 Tags } { } { Version 1.0 (25 July 2001) } { - Reading & writing support for ID3v1.x tags } { - Tag info: title, artist, album, track, year, genre, comment } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit ID3v1; interface uses Classes, SysUtils, StrUtils, DCClassesUtf8, DCOSUtils; const MAX_MUSIC_GENRES = 148; // Max. number of music genres DEFAULT_GENRE = 255; { Index for default genre } { Used with VersionID property } TAG_VERSION_1_0 = 1; { Index for ID3v1.0 tag } TAG_VERSION_1_1 = 2; { Index for ID3v1.1 tag } var aTAG_MusicGenre: array [0..MAX_MUSIC_GENRES - 1] of string; // Genre names bTAG_PreserveDate: boolean; bTAG_ID3v2PreserveALL: boolean; bTAG_UseLYRICS3: boolean; bTAG_GenreOther: boolean; type String04 = string[4]; { String with max. 4 symbols } { Real structure of ID3v1 tag } TagRecord = record Header: array [1..3] of Char; //Tag header - must be "TAG" Title: array [1..30] of Char; // Title data Artist: array [1..30] of Char; // Artist data Album: array [1..30] of Char; // Album data Year: array [1..4] of Char; // Year data Comment: array [1..30] of Char; // Comment data Genre: Byte; // Genre data end; Lyr2Mark = record Size: array [1..6] of Char; Mark: array [1..9] of Char; end; Lyr2Field = record ID: array [1..3] of Char; Size: array [1..5] of Char; end; { Class TID3v1 } TID3v1 = class(TObject) private FExists: Boolean; FVersionID: Byte; FTitle: string; FArtist: string; FAlbum: string; FYear: String04; FComment: string; FTrack: Byte; //FTrackString: string; FGenreID: byte; //lyrics 2 FExists2: boolean; FLyrics2Size: integer; FArtist2: string; FAlbum2: string; FTitle2: string; FComment2: string; FIMG: string; function FGetLyrics2Size: integer; function FGetTagSize: integer; function ReadTag(const FileName: String; bSetFields: boolean=true): Boolean; function SaveTag(const FileName: String; bUseLYR2: boolean = true): Boolean; procedure FSetTitle(const NewTitle: string); procedure FSetArtist(const NewArtist: string); procedure FSetAlbum(const NewAlbum: string); procedure FSetYear(const NewYear: String04); procedure FSetComment(const NewComment: string); procedure FSetTrack(const NewTrack: Byte); procedure FSetGenreID(const NewGenreID: Byte); procedure FSetGenre(const NewGenre: string); function FGetTrackString: string; function FGetTitle: string; function FGetArtist: string; function FGetAlbum: string; function FGetComment: string; function FGetGenre: string; function FGetHasLyrics: boolean; public //lyrics 2 Writer: string; Lyrics: string; constructor Create; procedure ResetData; function ReadFromFile(const FileName: String): Boolean; function RemoveFromFile(const FileName: String; bLyr2Only: boolean = false): Boolean; function SaveToFile(const FileName: String ): Boolean; property Exists: Boolean read FExists; // True if tag found property ExistsLyrics2: Boolean read FExists2; // True if Lyrics 2 tag found property VersionID: Byte read FVersionID; // Version code property Track: Byte read FTrack write FSetTrack; // Track number property TrackString: string read FGetTrackString; property Title: string read FGetTitle write FSetTitle; property Artist: string read FGetArtist write FSetArtist; property Album: string read FGetAlbum write FSetAlbum; property Year: String04 read FYear write FSetYear; property Comment: string read FGetComment write FSetComment; property GenreID: Byte read FGenreID write FSetGenreID; // Genre code property Genre: string read FGetGenre write FSetGenre; // Genre name property HasLyrics: boolean read FGetHasLyrics; property Lyrics2Size: integer read FGetLyrics2Size; // full LYRICS2 tag size property TagSize: integer read FGetTagSize; // full tag size end; implementation uses DCConvertEncoding; //----------------------------------------------------------------------------------------------------------------------------------- // Private functions & procedures //----------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetTitle(const NewTitle: String); begin FTitle := CeUtf8ToAnsi(TrimRight(NewTitle)); if Length( FTitle ) > 30 then begin FTitle2 := FTitle; end else begin FTitle2 := ''; end; end; //----------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetArtist(const NewArtist: String); begin FArtist := CeUtf8ToAnsi(TrimRight(NewArtist)); if Length( FArtist ) > 30 then begin FArtist2 := FArtist; end else begin FArtist2 := ''; end; end; //----------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetAlbum(const NewAlbum: string); begin FAlbum := CeUtf8ToAnsi(TrimRight(NewAlbum)); if Length( FAlbum ) > 30 then begin FAlbum2 := FAlbum; end else begin FAlbum2 := ''; end; end; //----------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetYear(const NewYear: String04); begin FYear := TrimRight(NewYear); end; //----------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetComment(const NewComment: string); begin FComment := CeUtf8ToAnsi(TrimRight(NewComment)); if Length( FComment ) > 30 then begin FComment2 := FComment; end else begin FComment2 := ''; end; end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetTrack(const NewTrack: Byte); begin FTrack := NewTrack; end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetGenreID(const NewGenreID: Byte); begin FGenreID := NewGenreID; end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.FSetGenre(const NewGenre: string); var i: integer; begin FGenreID := 255; for i := 0 to MAX_MUSIC_GENRES - 1 do begin if UpperCase( aTAG_MusicGenre[ i ] ) = UpperCase( NewGenre ) then begin FGenreID := i; break; end end; if bTAG_GenreOther and ((FGenreID = 255) and (NewGenre <> '')) then FGenreID := 12; // _OTHER_GENRE_ID = 12; end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetTrackString: string; begin if FTrack = 0 then begin result := ''; end else begin result := IntToStr( FTrack ); end; end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetTitle: string; begin if FTitle2 <> '' then begin result := FTitle2; end else begin result := FTitle; end; Result:= CeAnsiToUtf8(Result); end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetArtist: string; begin if FArtist2 <> '' then begin result := FArtist2; end else begin result := FArtist; end; Result:= CeAnsiToUtf8(Result); end; //---------------------------------------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetAlbum: string; begin if FAlbum2 <> '' then begin result := FAlbum2; end else begin result := FAlbum; end; Result:= CeAnsiToUtf8(Result); end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetComment: string; begin if FComment2 <> '' then begin result := FComment2; end else begin result := FComment; end; Result:= CeAnsiToUtf8(Result); end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetGenre: string; begin Result := ''; // Return an empty string if the current GenreID is not valid if FGenreID in [0..MAX_MUSIC_GENRES - 1] then Result := aTAG_MusicGenre[ FGenreID ]; end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetLyrics2Size: integer; begin if FLyrics2Size > 0 then begin result := FLyrics2Size + 15; end else begin result := 0; end; end; function TID3v1.FGetTagSize: integer; begin result := Lyrics2Size; if FExists then result := result + 128; end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.FGetHasLyrics: boolean; begin result := ( Trim( Lyrics ) <> '' ); end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.ReadTag(const FileName: String; bSetFields: boolean=true): Boolean; var TagData: TagRecord; SourceFile: TFileStreamEx; Mark: Lyr2Mark; Field: Lyr2Field; iOffSet, iFieldSize: integer; aBuff: array of char; begin try Result := true; // Set read-access and open file SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); // Read id3v1 tag SourceFile.Seek(SourceFile.Size - 128, soFromBeginning); SourceFile.Read(TagData, 128); if TagData.Header = 'TAG' then begin FExists := true; if bSetFields then begin // set version if ((TagData.Comment[29] = #0) and (TagData.Comment[30] <> #0)) or ((TagData.Comment[29] = #32) and (TagData.Comment[30] <> #32)) then begin // Terms for ID3v1.1 FVersionID := TAG_VERSION_1_1; end else begin FVersionID := TAG_VERSION_1_0; end; FTitle := TrimRight( TagData.Title ); FArtist := TrimRight( TagData.Artist ); FAlbum := TrimRight( TagData.Album ); FYear := TrimRight( TagData.Year ); if FVersionID = TAG_VERSION_1_0 then begin FComment := TrimRight( TagData.Comment ) end else begin FComment := TrimRight( Copy( TagData.Comment, 1, 28 ) ); FTrack := Ord( TagData.Comment[30] ); end; FGenreID := TagData.Genre; end; end; // try to read LYRICS2 tag iOffSet := 15; if FExists then iOffSet := iOffSet + 128; SourceFile.Seek(SourceFile.Size - iOffSet, soFromBeginning); SourceFile.Read(Mark, 15); if Mark.Mark = 'LYRICS200' then begin FLyrics2Size := StrToIntDef( Mark.Size, 0 ); if FLyrics2Size > 0 then begin SourceFile.Seek(SourceFile.Size - (FLyrics2Size + iOffSet), soFromBeginning); SetLength( aBuff, 11 ); // LYRICSBEGIN SourceFile.Read(aBuff[0], 11); if String( aBuff ) = 'LYRICSBEGIN' then begin // is it ok ? FExists2 := true; if bSetFields then begin while true do begin // read all fields SourceFile.Read(Field, SizeOf(Field)); iFieldSize := StrToIntDef( Field.Size, -1 ); if iFieldSize < 0 then break; SetLength( aBuff, iFieldSize ); SourceFile.Read(aBuff[0], iFieldSize); if Field.ID = 'IND' then begin end else if Field.ID = 'LYR' then begin Lyrics := Trim( String( aBuff ) ); Lyrics := StringReplace( Lyrics, #13, #13#10, [rfReplaceAll] ); Lyrics := StringReplace( Lyrics, #13#10#10, #13#10, [rfReplaceAll] ); end else if Field.ID = 'INF' then begin FComment2 := Trim( String( aBuff ) ); end else if Field.ID = 'AUT' then begin Writer := Trim( String( aBuff ) ); end else if Field.ID = 'EAL' then begin FAlbum2 := Trim( String( aBuff ) ); end else if Field.ID = 'EAR' then begin FArtist2 := Trim( String( aBuff ) ); end else if Field.ID = 'ETT' then begin FTitle2 := Trim( String( aBuff ) ); end else if Field.ID = 'IMG' then begin FIMG := String( aBuff ); end else begin break; end; end; //while end; end else begin FExists2 := false; FLyrics2Size := 0; end; end; end; // end SetLength( aBuff, 0 ); SourceFile.Free; except Result := false; // Error end; end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.SaveTag(const FileName: String; bUseLYR2: boolean = true): Boolean; var Tag: TagRecord; iFileAge: integer; SourceFile: TFileStreamEx; iFilePos: integer; sTmp: string; sTmp30: string[30]; procedure WriteField( sID, sValue: string ); var iLen: integer; begin if Trim( sValue ) <> '' then begin iLen := Length( sValue ); sTmp := sID + DupeString( '0', 5 - Length( IntToStr( iLen ) ) ) + IntToStr( iLen ) + sValue; SourceFile.Write(sTmp[1], Length(sTmp)); end; end; begin result := true; iFileAge := 0; try if bTAG_PreserveDate then iFileAge := mbFileAge(FileName); // Allow write-access and open file mbFileSetReadOnly(FileName, False); SourceFile := TFileStreamEx.Create(FileName, fmOpenReadWrite or fmShareDenyWrite); // Write lyrics2 if bUseLYR2 and ( bTAG_UseLYRICS3 or ( (Lyrics <> '') or (Writer <> '') or ( FIMG <> '' ) ) ) then begin if (Lyrics <> '') or (Writer <> '') or (FArtist2 <> '') or (FAlbum2 <> '' ) or (FComment2 <> '') or (FTitle2 <> '') then begin SourceFile.Seek(SourceFile.Size, soFromBeginning); iFilePos := SourceFile.Position; SourceFile.Write('LYRICSBEGIN', 11); if Lyrics <> '' then begin SourceFile.Write('IND0000210', 10); end else begin SourceFile.Write('IND0000200', 10); end; WriteField( 'EAL', FAlbum2 ); WriteField( 'EAR', FArtist2 ); WriteField( 'ETT', FTitle2 ); WriteField( 'INF', FComment2 ); WriteField( 'AUT', Writer ); WriteField( 'LYR', Lyrics ); WriteField( 'IMG', FIMG ); iFilepos := SourceFile.Position - iFilePos; sTmp := DupeString( '0', 6 - Length( IntToStr( iFilepos ) ) ) + IntToStr( iFilepos ) + 'LYRICS200'; SourceFile.Write(sTmp[1], Length(sTmp)); FExists2 := true; end; end; // Write id3v1 SourceFile.Seek(SourceFile.Size, soFromBeginning); FillChar( Tag, SizeOf( Tag ), 0); Tag.Header := 'TAG'; sTmp30 := TrimRight( Title ); Move( sTmp30[1], Tag.Title , Length( sTmp30 ) ); sTmp30 := TrimRight( Artist ); Move( sTmp30[1], Tag.Artist , Length( sTmp30 ) ); sTmp30 := TrimRight( Album ); Move( sTmp30[1], Tag.Album , Length( sTmp30 ) ); Move( Year[1], Tag.Year , Length( Year ) ); sTmp30 := TrimRight( Comment ); Move( sTmp30[1], Tag.Comment, Length( sTmp30 ) ); if FTrack > 0 then begin Tag.Comment[29] := #0; Tag.Comment[30] := Chr( FTrack ); end; Tag.Genre := FGenreID; SourceFile.Write(Tag, SizeOf(Tag)); SourceFile.Free; if bTAG_PreserveDate then mbFileSetTime(FileName, iFileAge); except result := false; // Error end; end; //----------------------------------------------------------------------------------------------------------------------------------- procedure TID3v1.ResetData; begin FExists := false; FVersionID := TAG_VERSION_1_0; FTitle := ''; FArtist := ''; FAlbum := ''; FYear := ''; FComment := ''; FTrack := 0; FGenreID := DEFAULT_GENRE; // lyrics 2 FExists2 := false; FLyrics2Size := 0; Lyrics := ''; Writer := ''; FArtist2 := ''; FAlbum2 := ''; FTitle2 := ''; FComment2 := ''; FIMG := ''; end; //----------------------------------------------------------------------------------------------------------------------------------- // Public functions & procedures //----------------------------------------------------------------------------------------------------------------------------------- constructor TID3v1.Create; begin inherited; ResetData; end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.ReadFromFile(const FileName: String): Boolean; begin // Reset and load tag data from file to variable ResetData; Result := ReadTag(FileName); end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.SaveToFile(const FileName: String): Boolean; begin // Delete old tag and write new tag result := (RemoveFromFile(FileName)) and (SaveTag(FileName)); if (result) and ( not FExists ) then FExists := true; // NOTE end; //----------------------------------------------------------------------------------------------------------------------------------- function TID3v1.RemoveFromFile(const FileName: String; bLyr2Only: boolean = false): Boolean; var iFileAge: integer; SourceFile: TFileStreamEx; begin result := true; try ReadTag(FileName, false); if FExists or FExists2 then begin iFileAge := 0; if bTAG_PreserveDate then iFileAge := mbFileAge(FileName); Result := true; // Allow write-access and open file mbFileSetReadOnly(FileName, False); SourceFile := TFileStreamEx.Create(FileName, fmOpenReadWrite or fmShareDenyWrite); // Delete id3v1 if FExists then begin SourceFile.Seek(SourceFile.Size - 128, soFromBeginning); //truncate SourceFile.Size := SourceFile.Position; FExists := false; end; // Delete lyrics2 if FExists2 then begin SourceFile.Seek(SourceFile.Size - Lyrics2Size, soFromBeginning); //truncate SourceFile.Size := SourceFile.Position; FExists2 := false; end; if bLyr2Only then begin if SaveTag(FileName, false) then begin FExists := true; end; end; SourceFile.Free; if bTAG_PreserveDate then mbFileSetTime(FileName, iFileAge); end; except result := false; // Error end; end; { ************************** Initialize music genres ************************ } initialization begin //-- Initialize music genres { Standard genres } aTAG_MusicGenre[0] := 'Blues'; aTAG_MusicGenre[1] := 'Classic Rock'; aTAG_MusicGenre[2] := 'Country'; aTAG_MusicGenre[3] := 'Dance'; aTAG_MusicGenre[4] := 'Disco'; aTAG_MusicGenre[5] := 'Funk'; aTAG_MusicGenre[6] := 'Grunge'; aTAG_MusicGenre[7] := 'Hip-Hop'; aTAG_MusicGenre[8] := 'Jazz'; aTAG_MusicGenre[9] := 'Metal'; aTAG_MusicGenre[10] := 'New Age'; aTAG_MusicGenre[11] := 'Oldies'; aTAG_MusicGenre[12] := 'Other'; aTAG_MusicGenre[13] := 'Pop'; aTAG_MusicGenre[14] := 'R&B'; aTAG_MusicGenre[15] := 'Rap'; aTAG_MusicGenre[16] := 'Reggae'; aTAG_MusicGenre[17] := 'Rock'; aTAG_MusicGenre[18] := 'Techno'; aTAG_MusicGenre[19] := 'Industrial'; aTAG_MusicGenre[20] := 'Alternative'; aTAG_MusicGenre[21] := 'Ska'; aTAG_MusicGenre[22] := 'Death Metal'; aTAG_MusicGenre[23] := 'Pranks'; aTAG_MusicGenre[24] := 'Soundtrack'; aTAG_MusicGenre[25] := 'Euro-Techno'; aTAG_MusicGenre[26] := 'Ambient'; aTAG_MusicGenre[27] := 'Trip-Hop'; aTAG_MusicGenre[28] := 'Vocal'; aTAG_MusicGenre[29] := 'Jazz+Funk'; aTAG_MusicGenre[30] := 'Fusion'; aTAG_MusicGenre[31] := 'Trance'; aTAG_MusicGenre[32] := 'Classical'; aTAG_MusicGenre[33] := 'Instrumental'; aTAG_MusicGenre[34] := 'Acid'; aTAG_MusicGenre[35] := 'House'; aTAG_MusicGenre[36] := 'Game'; aTAG_MusicGenre[37] := 'Sound Clip'; aTAG_MusicGenre[38] := 'Gospel'; aTAG_MusicGenre[39] := 'Noise'; aTAG_MusicGenre[40] := 'AlternRock'; aTAG_MusicGenre[41] := 'Bass'; aTAG_MusicGenre[42] := 'Soul'; aTAG_MusicGenre[43] := 'Punk'; aTAG_MusicGenre[44] := 'Space'; aTAG_MusicGenre[45] := 'Meditative'; aTAG_MusicGenre[46] := 'Instrumental Pop'; aTAG_MusicGenre[47] := 'Instrumental Rock'; aTAG_MusicGenre[48] := 'Ethnic'; aTAG_MusicGenre[49] := 'Gothic'; aTAG_MusicGenre[50] := 'Darkwave'; aTAG_MusicGenre[51] := 'Techno-Industrial'; aTAG_MusicGenre[52] := 'Electronic'; aTAG_MusicGenre[53] := 'Pop-Folk'; aTAG_MusicGenre[54] := 'Eurodance'; aTAG_MusicGenre[55] := 'Dream'; aTAG_MusicGenre[56] := 'Southern Rock'; aTAG_MusicGenre[57] := 'Comedy'; aTAG_MusicGenre[58] := 'Cult'; aTAG_MusicGenre[59] := 'Gangsta'; aTAG_MusicGenre[60] := 'Top 40'; aTAG_MusicGenre[61] := 'Christian Rap'; aTAG_MusicGenre[62] := 'Pop/Funk'; aTAG_MusicGenre[63] := 'Jungle'; aTAG_MusicGenre[64] := 'Native American'; aTAG_MusicGenre[65] := 'Cabaret'; aTAG_MusicGenre[66] := 'New Wave'; aTAG_MusicGenre[67] := 'Psychadelic'; aTAG_MusicGenre[68] := 'Rave'; aTAG_MusicGenre[69] := 'Showtunes'; aTAG_MusicGenre[70] := 'Trailer'; aTAG_MusicGenre[71] := 'Lo-Fi'; aTAG_MusicGenre[72] := 'Tribal'; aTAG_MusicGenre[73] := 'Acid Punk'; aTAG_MusicGenre[74] := 'Acid Jazz'; aTAG_MusicGenre[75] := 'Polka'; aTAG_MusicGenre[76] := 'Retro'; aTAG_MusicGenre[77] := 'Musical'; aTAG_MusicGenre[78] := 'Rock & Roll'; aTAG_MusicGenre[79] := 'Hard Rock'; { Extended genres } aTAG_MusicGenre[80] := 'Folk'; aTAG_MusicGenre[81] := 'Folk-Rock'; aTAG_MusicGenre[82] := 'National Folk'; aTAG_MusicGenre[83] := 'Swing'; aTAG_MusicGenre[84] := 'Fast Fusion'; aTAG_MusicGenre[85] := 'Bebob'; aTAG_MusicGenre[86] := 'Latin'; aTAG_MusicGenre[87] := 'Revival'; aTAG_MusicGenre[88] := 'Celtic'; aTAG_MusicGenre[89] := 'Bluegrass'; aTAG_MusicGenre[90] := 'Avantgarde'; aTAG_MusicGenre[91] := 'Gothic Rock'; aTAG_MusicGenre[92] := 'Progressive Rock'; aTAG_MusicGenre[93] := 'Psychedelic Rock'; aTAG_MusicGenre[94] := 'Symphonic Rock'; aTAG_MusicGenre[95] := 'Slow Rock'; aTAG_MusicGenre[96] := 'Big Band'; aTAG_MusicGenre[97] := 'Chorus'; aTAG_MusicGenre[98] := 'Easy Listening'; aTAG_MusicGenre[99] := 'Acoustic'; aTAG_MusicGenre[100]:= 'Humour'; aTAG_MusicGenre[101]:= 'Speech'; aTAG_MusicGenre[102]:= 'Chanson'; aTAG_MusicGenre[103]:= 'Opera'; aTAG_MusicGenre[104]:= 'Chamber Music'; aTAG_MusicGenre[105]:= 'Sonata'; aTAG_MusicGenre[106]:= 'Symphony'; aTAG_MusicGenre[107]:= 'Booty Bass'; aTAG_MusicGenre[108]:= 'Primus'; aTAG_MusicGenre[109]:= 'Porn Groove'; aTAG_MusicGenre[110]:= 'Satire'; aTAG_MusicGenre[111]:= 'Slow Jam'; aTAG_MusicGenre[112]:= 'Club'; aTAG_MusicGenre[113]:= 'Tango'; aTAG_MusicGenre[114]:= 'Samba'; aTAG_MusicGenre[115]:= 'Folklore'; aTAG_MusicGenre[116]:= 'Ballad'; aTAG_MusicGenre[117]:= 'Power Ballad'; aTAG_MusicGenre[118]:= 'Rhythmic Soul'; aTAG_MusicGenre[119]:= 'Freestyle'; aTAG_MusicGenre[120]:= 'Duet'; aTAG_MusicGenre[121]:= 'Punk Rock'; aTAG_MusicGenre[122]:= 'Drum Solo'; aTAG_MusicGenre[123]:= 'A capella'; aTAG_MusicGenre[124]:= 'Euro-House'; aTAG_MusicGenre[125]:= 'Dance Hall'; aTAG_MusicGenre[126]:= 'Goa'; aTAG_MusicGenre[127]:= 'Drum & Bass'; aTAG_MusicGenre[128]:= 'Club-House'; aTAG_MusicGenre[129]:= 'Hardcore'; aTAG_MusicGenre[130]:= 'Terror'; aTAG_MusicGenre[131]:= 'Indie'; aTAG_MusicGenre[132]:= 'BritPop'; aTAG_MusicGenre[133]:= 'Negerpunk'; aTAG_MusicGenre[134]:= 'Polsk Punk'; aTAG_MusicGenre[135]:= 'Beat'; aTAG_MusicGenre[136]:= 'Christian Gangsta Rap'; aTAG_MusicGenre[137]:= 'Heavy Metal'; aTAG_MusicGenre[138]:= 'Black Metal'; aTAG_MusicGenre[139]:= 'Crossover'; aTAG_MusicGenre[140]:= 'Contemporary Christian'; aTAG_MusicGenre[141]:= 'Christian Rock'; aTAG_MusicGenre[142]:= 'Merengue'; aTAG_MusicGenre[143]:= 'Salsa'; aTAG_MusicGenre[144]:= 'Thrash Metal'; aTAG_MusicGenre[145]:= 'Anime'; aTAG_MusicGenre[146]:= 'JPop'; aTAG_MusicGenre[147]:= 'Synthpop'; //--- bTAG_PreserveDate := false; bTAG_ID3v2PreserveALL := false; bTAG_UseLYRICS3 := false; bTAG_GenreOther := false; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/ID3v2.pas��������������������������������������������0000644�0001750�0000144�00000066634�14743153644�021770� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TID3v2 - for manipulating with ID3v2 tags } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.8 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.7 (2 October 2002) } { - Added property TrackString } { } { Version 1.6 (29 July 2002) } { - Reading support for Unicode } { - Removed limitation for the track number } { } { Version 1.5 (23 May 2002) } { - Support for padding } { } { Version 1.4 (24 March 2002) } { - Reading support for ID3v2.2.x & ID3v2.4.x tags } { } { Version 1.3 (16 February 2002) } { - Fixed bug with property Comment } { - Added info: composer, encoder, copyright, language, link } { } { Version 1.2 (17 October 2001) } { - Writing support for ID3v2.3.x tags } { - Fixed bug with track number detection } { - Fixed bug with tag reading } { } { Version 1.1 (31 August 2001) } { - Added public procedure ResetData } { } { Version 1.0 (14 August 2001) } { - Reading support for ID3v2.3.x tags } { - Tag info: title, artist, album, track, year, genre, comment } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit ID3v2; interface uses Classes, SysUtils, DCClassesUtf8, DCOSUtils; const TAG_VERSION_2_2 = 2; { Code for ID3v2.2.x tag } TAG_VERSION_2_3 = 3; { Code for ID3v2.3.x tag } TAG_VERSION_2_4 = 4; { Code for ID3v2.4.x tag } type { Class TID3v2 } TID3v2 = class(TObject) private { Private declarations } FExists: Boolean; FVersionID: Byte; FSize: Integer; FTitle: string; FArtist: string; FAlbum: string; FTrack: Word; FTrackString: string; FYear: string; FGenre: string; FComment: string; FComposer: string; FEncoder: string; FCopyright: string; FLanguage: string; FLink: string; FTSIZ: string; procedure FSetTitle(const NewTitle: string); procedure FSetArtist(const NewArtist: string); procedure FSetAlbum(const NewAlbum: string); procedure FSetTrack(const NewTrack: Word); procedure FSetYear(const NewYear: string); procedure FSetGenre(const NewGenre: string); procedure FSetComment(const NewComment: string); procedure FSetComposer(const NewComposer: string); procedure FSetEncoder(const NewEncoder: string); procedure FSetCopyright(const NewCopyright: string); procedure FSetLanguage(const NewLanguage: string); procedure FSetLink(const NewLink: string); public { Public declarations } constructor Create; { Create object } procedure ResetData; { Reset all data } function ReadFromFile(const FileName: String): Boolean; { Load tag } function SaveToFile(const FileName: String): Boolean; { Save tag } function RemoveFromFile(const FileName: String): Boolean;{ Delete tag } property Exists: Boolean read FExists; { True if tag found } property VersionID: Byte read FVersionID; { Version code } property Size: Integer read FSize; { Total tag size } property Title: string read FTitle write FSetTitle; { Song title } property Artist: string read FArtist write FSetArtist; { Artist name } property Album: string read FAlbum write FSetAlbum; { Album title } property Track: Word read FTrack write FSetTrack; { Track number } property TrackString: string read FTrackString; { Track number (string) } property Year: string read FYear write FSetYear; { Release year } property Genre: string read FGenre write FSetGenre; { Genre name } property Comment: string read FComment write FSetComment; { Comment } property Composer: string read FComposer write FSetComposer; { Composer } property Encoder: string read FEncoder write FSetEncoder; { Encoder } property Copyright: string read FCopyright write FSetCopyright; { (c) } property Language: string read FLanguage write FSetLanguage; { Language } property Link: string read FLink write FSetLink; { URL link } property TSIZ: string read FTSIZ; end; implementation uses LazUTF8, DCConvertEncoding, DCUnicodeUtils; const { ID3v2 tag ID } ID3V2_ID = 'ID3'; { Max. number of supported tag frames } ID3V2_FRAME_COUNT = 17; { Names of supported tag frames (ID3v2.3.x & ID3v2.4.x) } ID3V2_FRAME_NEW: array [1..ID3V2_FRAME_COUNT] of string = ('TIT2', 'TPE1', 'TALB', 'TRCK', 'TYER', 'TCON', 'COMM', 'TCOM', 'TENC', 'TCOP', 'TLAN', 'WXXX', 'TDRC', 'TOPE', 'TIT1', 'TOAL', 'TSIZ'); { Names of supported tag frames (ID3v2.2.x) } ID3V2_FRAME_OLD: array [1..ID3V2_FRAME_COUNT] of string = ('TT2', 'TP1', 'TAL', 'TRK', 'TYE', 'TCO', 'COM', 'TCM', 'TEN', 'TCR', 'TLA', 'WXX', 'TOR', 'TOA', 'TT1', 'TOT', 'TSI'); { Max. tag size for saving } ID3V2_MAX_SIZE = 4096; { Unicode ID } UTF16_ID = #01; UTF16BE_ID = #02; UTF8_ID = #03; type { Frame header (ID3v2.3.x & ID3v2.4.x) } FrameHeaderNew = record ID: array [1..4] of Char; { Frame ID } Size: Integer; { Size excluding header } Flags: Word; { Flags } end; { Frame header (ID3v2.2.x) } FrameHeaderOld = record ID: array [1..3] of Char; { Frame ID } Size: array [1..3] of Byte; { Size excluding header } end; { ID3v2 header data - for internal use } TagInfo = record { Real structure of ID3v2 header } ID: array [1..3] of Char; { Always "ID3" } Version: Byte; { Version number } Revision: Byte; { Revision number } Flags: Byte; { Flags of tag } Size: array [1..4] of Byte; { Tag size excluding header } { Extended data } FileSize: Integer; { File size (bytes) } Frame: array [1..ID3V2_FRAME_COUNT] of string; { Information from frames } NeedRewrite: Boolean; { Tag should be rewritten } PaddingSize: Integer; { Padding size (bytes) } end; { ********************* Auxiliary functions & procedures ******************** } function ReadHeader(const FileName: String; var Tag: TagInfo): Boolean; var SourceFile: TFileStreamEx; Transferred: Integer; begin try Result := true; { Set read-access and open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); { Read header and get file size } Transferred := SourceFile.Read(Tag, 10); Tag.FileSize := SourceFile.Size; SourceFile.Free; { if transfer is not complete } if Transferred < 10 then Result := false; except { Error } Result := false; end; end; { --------------------------------------------------------------------------- } function GetTagSize(const Tag: TagInfo): Integer; begin { Get total tag size } Result := Tag.Size[1] * $200000 + Tag.Size[2] * $4000 + Tag.Size[3] * $80 + Tag.Size[4] + 10; if Tag.Flags and $10 = $10 then Inc(Result, 10); if Result > Tag.FileSize then Result := 0; end; { --------------------------------------------------------------------------- } procedure SetTagItem(const ID, Data: string; var Tag: TagInfo); var Iterator: Byte; FrameID: string; begin { Set tag item if supported frame found } for Iterator := 1 to ID3V2_FRAME_COUNT do begin if Tag.Version > TAG_VERSION_2_2 then FrameID := ID3V2_FRAME_NEW[Iterator] else FrameID := ID3V2_FRAME_OLD[Iterator]; if (FrameID = ID) and (Data[1] <= UTF8_ID) then Tag.Frame[Iterator] := Data; end; end; { --------------------------------------------------------------------------- } function Swap32(const Figure: Integer): Integer; var ByteArray: array [1..4] of Byte absolute Figure; begin { Swap 4 bytes } Result := ByteArray[1] * $1000000 + ByteArray[2] * $10000 + ByteArray[3] * $100 + ByteArray[4]; end; { --------------------------------------------------------------------------- } procedure ReadFramesNew(const FileName: String; var Tag: TagInfo); var ASize: Cardinal; SourceFile: TFileStreamEx; Frame: FrameHeaderNew; Data: array [1..500] of Char; DataPosition, DataSize: Integer; begin { Get information from frames (ID3v2.3.x & ID3v2.4.x) } try { Set read-access, open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); SourceFile.Seek(10, soFromBeginning); // ID3v2 extended header if Tag.Flags and $40 = $40 then begin ASize:= BEToN(SourceFile.ReadDWord); SourceFile.Seek(ASize - 4, soFromCurrent); end; while (SourceFile.Position < GetTagSize(Tag)) and (SourceFile.Position < SourceFile.Size) do begin FillChar(Data, SizeOf(Data), 0); { Read frame header and check frame ID } SourceFile.Read(Frame, 10); if not (Frame.ID[1] in ['A'..'Z']) then break; { Note data position and determine significant data size } DataPosition := SourceFile.Position; if Swap32(Frame.Size) > SizeOf(Data) then DataSize := SizeOf(Data) else DataSize := Swap32(Frame.Size); { Read frame data and set tag item if frame supported } SourceFile.Read(Data, DataSize); if Frame.Flags and $8000 <> $8000 then SetTagItem(Frame.ID, Data, Tag); SourceFile.Seek(DataPosition + Swap32(Frame.Size), soFromBeginning); end; SourceFile.Free; except end; end; { --------------------------------------------------------------------------- } procedure ReadFramesOld(const FileName: String; var Tag: TagInfo); var SourceFile: TFileStreamEx; Frame: FrameHeaderOld; Data: array [1..500] of Char; DataPosition, FrameSize, DataSize: Integer; begin { Get information from frames (ID3v2.2.x) } try { Set read-access, open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); SourceFile.Seek(10, soFromBeginning); while (SourceFile.Position < GetTagSize(Tag)) and (SourceFile.Position < SourceFile.Size) do begin FillChar(Data, SizeOf(Data), 0); { Read frame header and check frame ID } SourceFile.Read(Frame, 6); if not (Frame.ID[1] in ['A'..'Z']) then break; { Note data position and determine significant data size } DataPosition := SourceFile.Position; FrameSize := Frame.Size[1] shl 16 + Frame.Size[2] shl 8 + Frame.Size[3]; if FrameSize > SizeOf(Data) then DataSize := SizeOf(Data) else DataSize := FrameSize; { Read frame data and set tag item if frame supported } SourceFile.Read(Data, DataSize); SetTagItem(Frame.ID, Data, Tag); SourceFile.Seek(DataPosition + FrameSize, soFromBeginning); end; SourceFile.Free; except end; end; { --------------------------------------------------------------------------- } function GetStringUtf8(const Source: string): string; const UTF16BEBOM = #$FE#$FF; UTF16LEBOM = #$FF#$FE; begin { Convert string from unicode if needed and trim spaces } if (Length(Source) > 0) and (Source[1] = UTF16_ID) then begin if (Length(Source) < 3) then Result := EmptyStr else if (CompareWord(Source[2], UTF16BEBOM, 1) = 0) then Result := Trim(Utf16BEToUtf8(Copy(Source, 4, MaxInt))) else if (CompareWord(Source[2], UTF16LEBOM, 1) = 0) then Result := Trim(Utf16LEToUtf8(Copy(Source, 4, MaxInt))) else Result := EmptyStr end else if (Length(Source) > 0) and (Source[1] = UTF16BE_ID) then Result := Trim(Utf16BEToUtf8(Copy(Source, 2, MaxInt))) else if (Length(Source) > 0) and (Source[1] = UTF8_ID) then Result := Trim(Copy(Source, 2, MaxInt)) else Result := CeAnsiToUtf8(Trim(Source)); end; { --------------------------------------------------------------------------- } function GetContent(const Content1, Content2: string): string; begin { Get content preferring the first content } Result := GetStringUtf8(Content1); if Result = '' then Result := GetStringUtf8(Content2); end; { --------------------------------------------------------------------------- } function ExtractTrack(const TrackString: string): Word; var Track: string; Index, Value, Code: Integer; begin { Extract track from string } Track := GetStringUtf8(TrackString); Index := Pos('/', Track); if Index = 0 then Val(Track, Value, Code) else Val(Copy(Track, 1, Index - 1), Value, Code); if Code = 0 then Result := Value else Result := 0; end; { --------------------------------------------------------------------------- } function ExtractYear(const YearString, DateString: string): string; begin { Extract year from strings } Result := GetStringUtf8(YearString); if Result = '' then Result := Copy(GetStringUtf8(DateString), 1, 4); end; { --------------------------------------------------------------------------- } function ExtractGenre(const GenreString: string): string; begin { Extract genre from string } Result := GetStringUtf8(GenreString); if Pos(')', Result) > 0 then Delete(Result, 1, LastDelimiter(')', Result)); end; { --------------------------------------------------------------------------- } function ExtractText(const SourceString: string; LanguageID: Boolean): string; var Source, Separator: string; EncodingID: Char; begin { Extract significant text data from a complex field } Source := SourceString; Result := ''; if Length(Source) > 0 then begin EncodingID := Source[1]; if EncodingID in [UTF16_ID, UTF16BE_ID] then Separator := #0#0 else begin Separator := #0; end; if LanguageID then Delete(Source, 1, 4) else begin Delete(Source, 1, 1); end; Delete(Source, 1, Pos(Separator, Source) + Length(Separator) - 1); Result := GetStringUtf8(EncodingID + Source); end; end; { --------------------------------------------------------------------------- } procedure BuildHeader(var Tag: TagInfo); var Iterator, TagSize: Integer; begin { Calculate new tag size (without padding) } TagSize := 10; for Iterator := 1 to ID3V2_FRAME_COUNT do if Tag.Frame[Iterator] <> '' then Inc(TagSize, Length(Tag.Frame[Iterator]) + 11); { Check for ability to change existing tag } Tag.NeedRewrite := (Tag.ID <> ID3V2_ID) or (GetTagSize(Tag) < TagSize) or (GetTagSize(Tag) > ID3V2_MAX_SIZE); { Calculate padding size and set padded tag size } if Tag.NeedRewrite then Tag.PaddingSize := ID3V2_MAX_SIZE - TagSize else Tag.PaddingSize := GetTagSize(Tag) - TagSize; if Tag.PaddingSize > 0 then Inc(TagSize, Tag.PaddingSize); { Build tag header } Tag.ID := ID3V2_ID; Tag.Version := TAG_VERSION_2_3; Tag.Revision := 0; Tag.Flags := 0; { Convert tag size } for Iterator := 1 to 4 do Tag.Size[Iterator] := ((TagSize - 10) shr ((4 - Iterator) * 7)) and $7F; end; { --------------------------------------------------------------------------- } function ReplaceTag(const FileName: String; TagData: TStream): Boolean; var Destination: TFileStreamEx; begin { Replace old tag with new tag data } Result := false; if (not mbFileExists(FileName)) or (not mbFileSetReadOnly(FileName, False)) then exit; try TagData.Position := 0; Destination := TFileStreamEx.Create(FileName, fmOpenReadWrite); Destination.CopyFrom(TagData, TagData.Size); Destination.Free; Result := true; except { Access error } end; end; { --------------------------------------------------------------------------- } function RebuildFile(const FileName: String; TagData: TStream): Boolean; var Tag: TagInfo; Source, Destination: TFileStreamEx; BufferName: string; begin { Rebuild file with old file data and new tag data (optional) } Result := false; if (not mbFileExists(FileName)) or (not mbFileSetReadOnly(FileName, False)) then exit; if not ReadHeader(FileName, Tag) then exit; if (TagData = nil) and (Tag.ID <> ID3V2_ID) then exit; try { Create file streams } BufferName := FileName + '~'; Source := TFileStreamEx.Create(FileName, fmOpenRead); Destination := TFileStreamEx.Create(BufferName, fmCreate); { Copy data blocks } if Tag.ID = ID3V2_ID then Source.Seek(GetTagSize(Tag), soFromBeginning); if TagData <> nil then Destination.CopyFrom(TagData, 0); Destination.CopyFrom(Source, Source.Size - Source.Position); { Free resources } Source.Free; Destination.Free; { Replace old file and delete temporary file } if (mbDeleteFile(FileName)) and (mbRenameFile(BufferName, FileName)) then Result := true else raise Exception.Create(''); except { Access error } if mbFileExists(BufferName) then mbDeleteFile(BufferName); end; end; { --------------------------------------------------------------------------- } function SaveTag(const FileName: String; Tag: TagInfo): Boolean; var TagData: TStringStream; Iterator, FrameSize: Integer; Padding: array [1..ID3V2_MAX_SIZE] of Byte; begin { Build and write tag header and frames to stream } TagData := TStringStream.Create(''); BuildHeader(Tag); TagData.Write(Tag, 10); for Iterator := 1 to ID3V2_FRAME_COUNT do if Tag.Frame[Iterator] <> '' then begin TagData.WriteString(ID3V2_FRAME_NEW[Iterator]); FrameSize := Swap32(Length(Tag.Frame[Iterator]) + 1); TagData.Write(FrameSize, SizeOf(FrameSize)); TagData.WriteString(#0#0#0 + Tag.Frame[Iterator]); end; { Add padding } FillChar(Padding, SizeOf(Padding), 0); if Tag.PaddingSize > 0 then TagData.Write(Padding, Tag.PaddingSize); { Rebuild file or replace tag with new tag data } if Tag.NeedRewrite then Result := RebuildFile(FileName, TagData) else Result := ReplaceTag(FileName, TagData); TagData.Free; end; { ********************** Private functions & procedures ********************* } procedure TID3v2.FSetTitle(const NewTitle: string); begin { Set song title } FTitle := Trim(NewTitle); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetArtist(const NewArtist: string); begin { Set artist name } FArtist := Trim(NewArtist); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetAlbum(const NewAlbum: string); begin { Set album title } FAlbum := Trim(NewAlbum); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetTrack(const NewTrack: Word); begin { Set track number } FTrack := NewTrack; end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetYear(const NewYear: string); begin { Set release year } FYear := Trim(NewYear); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetGenre(const NewGenre: string); begin { Set genre name } FGenre := Trim(NewGenre); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetComment(const NewComment: string); begin { Set comment } FComment := Trim(NewComment); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetComposer(const NewComposer: string); begin { Set composer name } FComposer := Trim(NewComposer); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetEncoder(const NewEncoder: string); begin { Set encoder name } FEncoder := Trim(NewEncoder); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetCopyright(const NewCopyright: string); begin { Set copyright information } FCopyright := Trim(NewCopyright); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetLanguage(const NewLanguage: string); begin { Set language } FLanguage := Trim(NewLanguage); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetLink(const NewLink: string); begin { Set URL link } FLink := Trim(NewLink); end; { ********************** Public functions & procedures ********************** } constructor TID3v2.Create; begin { Create object } inherited; ResetData; end; { --------------------------------------------------------------------------- } procedure TID3v2.ResetData; begin { Reset all variables } FExists := false; FVersionID := 0; FSize := 0; FTitle := ''; FArtist := ''; FAlbum := ''; FTrack := 0; FTrackString := ''; FYear := ''; FGenre := ''; FComment := ''; FComposer := ''; FEncoder := ''; FCopyright := ''; FLanguage := ''; FLink := ''; FTSIZ := ''; end; { --------------------------------------------------------------------------- } function TID3v2.ReadFromFile(const FileName: String): Boolean; var Tag: TagInfo; begin { Reset data and load header from file to variable } ResetData; Result := ReadHeader(FileName, Tag); { Process data if loaded and header valid } if (Result) and (Tag.ID = ID3V2_ID) then begin FExists := true; { Fill properties with header data } FVersionID := Tag.Version; FSize := GetTagSize(Tag); { Get information from frames if version supported } if (FVersionID in [TAG_VERSION_2_2..TAG_VERSION_2_4]) and (FSize > 0) then begin if FVersionID > TAG_VERSION_2_2 then ReadFramesNew(FileName, Tag) else ReadFramesOld(FileName, Tag); FTitle := GetContent(Tag.Frame[1], Tag.Frame[15]); FArtist := GetContent(Tag.Frame[2], Tag.Frame[14]); FAlbum := GetContent(Tag.Frame[3], Tag.Frame[16]); FTrack := ExtractTrack(Tag.Frame[4]); FTrackString := GetStringUtf8(Tag.Frame[4]); FYear := ExtractYear(Tag.Frame[5], Tag.Frame[13]); FGenre := ExtractGenre(Tag.Frame[6]); FComment := ExtractText(Tag.Frame[7], true); FComposer := GetStringUtf8(Tag.Frame[8]); FEncoder := GetStringUtf8(Tag.Frame[9]); FCopyright := GetStringUtf8(Tag.Frame[10]); FLanguage := GetStringUtf8(Tag.Frame[11]); FLink := ExtractText(Tag.Frame[12], false); FTSIZ := GetStringUtf8(Tag.Frame[17]); end; end; end; { --------------------------------------------------------------------------- } function TID3v2.SaveToFile(const FileName: String): Boolean; var Tag: TagInfo; begin { Check for existing tag } FillChar(Tag, SizeOf(Tag), 0); ReadHeader(FileName, Tag); { Prepare tag data and save to file } Tag.Frame[1] := FTitle; Tag.Frame[2] := FArtist; Tag.Frame[3] := FAlbum; if FTrack > 0 then Tag.Frame[4] := IntToStr(FTrack); Tag.Frame[5] := FYear; Tag.Frame[6] := FGenre; if FComment <> '' then Tag.Frame[7] := 'eng' + #0 + FComment; Tag.Frame[8] := FComposer; Tag.Frame[9] := FEncoder; Tag.Frame[10] := FCopyright; Tag.Frame[11] := FLanguage; if FLink <> '' then Tag.Frame[12] := #0 + FLink; Result := SaveTag(FileName, Tag); end; { --------------------------------------------------------------------------- } function TID3v2.RemoveFromFile(const FileName: String): Boolean; begin { Remove tag from file } Result := RebuildFile(FileName, nil); end; { --------------------------------------------------------------------------- } end. ����������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/MP4file.pas������������������������������������������0000644�0001750�0000144�00000023070�14743153644�022364� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Class TMP4file - for manipulating with M4A audio file information Copyright (C) 2016 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit MP4file; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCClassesUtf8; type TAtomName = array [0..3] of AnsiChar; { TMP4file } TMP4file = class private FFileSize: Int64; FStream: TStream; function GetValid: Boolean; private FChannels: Word; FBitRate: Double; FDuration: Double; FSampleSize: Word; FSampleRate: LongWord; private FYear, FGenre, FTitle, FAlbum, FArtist, FEncoder, FComment, FComposer, FCopyright: String; FTrack: LongWord; protected procedure ResetData; procedure ReadMovieHeader; procedure ReadMetaDataItemList; procedure ReadSampleDescription; function ReadAtomData: String; function ReadGenreData: String; function ReadTrackData: LongWord; function FindAtomHeader(const AName: TAtomName; ASize: PInt64 = nil): Boolean; function LoadAtomHeader(out AtomName: TAtomName; out AtomSize: Int64): Boolean; public constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load header } property FileSize: Int64 read FFileSize; { File size (bytes) } property Channels: Word read FChannels; { Number of channels } property SampleRate: LongWord read FSampleRate; { Sample rate (hz) } property BitRate: Double read FBitRate; { Bit rate (bit/s) } property Duration: Double read FDuration; { Duration (seconds) } property Year: String read FYear; { Release year } property Genre: String read FGenre; { Genre name } property Track: LongWord read FTrack; { Track number } property Title: String read FTitle; { Song title } property Album: String read FAlbum; { Album title } property Artist: String read FArtist; { Artist name } property Comment: String read FComment; { Comment } property Encoder: String read FEncoder; { Encoder } property Composer: String read FComposer; { Composer } property Copyright: String read FCopyright; { Copyright } property Valid: Boolean read GetValid; { True if data valid } end; implementation uses ID3v1; { TMP4file } function TMP4file.FindAtomHeader(const AName: TAtomName; ASize: PInt64): Boolean; var AtomSize: Int64; APosition: Int64; AtomName: TAtomName; begin repeat if not LoadAtomHeader(AtomName, AtomSize) then Break; if SameText(AtomName, AName) then begin if Assigned(ASize) then ASize^:= AtomSize; Exit(True); end else begin APosition:= FStream.Seek(AtomSize, soCurrent); end; until (APosition >= FFileSize); Result:= False; end; function TMP4file.GetValid: Boolean; begin Result:= (FDuration > 0.0) and (FBitRate > 0.0); end; function TMP4file.LoadAtomHeader(out AtomName: TAtomName; out AtomSize: Int64): Boolean; begin AtomSize:= SwapEndian(FStream.ReadDWord); FillChar({%H-}AtomName, SizeOf(TAtomName), #0); FStream.Read(AtomName, SizeOf(TAtomName)); if AtomSize <> 1 then AtomSize:= AtomSize - 8 else begin AtomSize:= Int64(SwapEndian(FStream.ReadQWord)) - 16; end; Result:= not ((AtomSize < 0) or (AtomSize > FFileSize)); end; procedure TMP4file.ResetData; begin FTrack:= 0; FBitRate:= 0; FChannels:= 0; FDuration:= 0.0; FSampleSize:= 0; FSampleRate:= 0; FYear:= EmptyStr; FGenre:= EmptyStr; FTitle:= EmptyStr; FAlbum:= EmptyStr; FArtist:= EmptyStr; FEncoder:= EmptyStr; FComment:= EmptyStr; FComposer:= EmptyStr; FCopyright:= EmptyStr; end; procedure TMP4file.ReadMovieHeader; var AVersion: Byte; MediaSize: Int64; ADuration: QWord = 0; TimeScale: LongWord = 0; begin FStream.Seek(0, soBeginning); if FindAtomHeader('moov') and FindAtomHeader('mvhd') then begin AVersion:= FStream.ReadByte; FStream.Seek(3, soCurrent); if AVersion = 0 then begin FStream.Seek(8, soCurrent); TimeScale:= SwapEndian(FStream.ReadDWord); ADuration:= SwapEndian(FStream.ReadDWord); end else if AVersion = 1 then begin FStream.Seek(16, soCurrent); TimeScale:= SwapEndian(FStream.ReadDWord); ADuration:= SwapEndian(FStream.ReadQWord); end; if TimeScale > 0 then FDuration:= ADuration / TimeScale; end; FStream.Seek(0, soBeginning); if (FDuration > 0) and FindAtomHeader('mdat', @MediaSize) then begin FBitRate:= MediaSize * 8 / FDuration / 1000; end; end; function TMP4file.ReadAtomData: String; var AtomSize: Int64; DataType: LongWord; Buffer: array[Byte] of AnsiChar; begin Result:= EmptyStr; if FindAtomHeader('data', @AtomSize) then begin if AtomSize - 8 > High(Byte) then Exit; DataType:= SwapEndian(FStream.ReadDWord); if DataType = 1 then begin FStream.Seek(4, soCurrent); FStream.Read({%H-}Buffer, AtomSize - 8); SetString(Result, Buffer, AtomSize - 8); end; end; end; function TMP4file.ReadGenreData: String; var AtomSize: Int64; AGenre: Word = 0; begin Result:= EmptyStr; if FindAtomHeader('data', @AtomSize) then begin FStream.Seek(8, soCurrent); AGenre:= SwapEndian(FStream.ReadWord); FStream.Seek(AtomSize - 10, soCurrent); end; if (AGenre > 0) and (AGenre < MAX_MUSIC_GENRES) then begin Result:= aTAG_MusicGenre[AGenre - 1]; end; end; function TMP4file.ReadTrackData: LongWord; var AtomSize: Int64; begin Result:= 0; if FindAtomHeader('data', @AtomSize) then begin FStream.Seek(8, soCurrent); Result:= SwapEndian(FStream.ReadDWord); FStream.Seek(AtomSize - 12, soCurrent); end; end; procedure TMP4file.ReadMetaDataItemList; var AtomSize: Int64; AtomFinish: Int64; AtomName: TAtomName; begin FStream.Seek(0, soBeginning); if not FindAtomHeader('moov') then Exit; if not FindAtomHeader('udta') then Exit; if FindAtomHeader('meta') then begin FStream.Seek(4, soCurrent); if FindAtomHeader('ilst', @AtomSize) then begin AtomFinish := FStream.Position + AtomSize; while FStream.Position < AtomFinish do begin LoadAtomHeader(AtomName, AtomSize); if SameText('trkn', AtomName) then FTrack:= ReadTrackData else if SameText('gnre', AtomName) then FGenre:= ReadGenreData else if SameText('cprt', AtomName) then FCopyright:= ReadAtomData else if SameText(#169'art', AtomName) then FArtist:= ReadAtomData else if SameText(#169'alb', AtomName) then FAlbum:= ReadAtomData else if SameText(#169'cmt', AtomName) then FComment:= ReadAtomData else if SameText(#169'day', AtomName) then FYear:= ReadAtomData else if SameText(#169'nam', AtomName) then FTitle:= ReadAtomData else if SameText(#169'too', AtomName) then FEncoder:= ReadAtomData else if SameText(#169'wrt', AtomName) then FComposer:= ReadAtomData else if SameText(#169'gen', AtomName) then FGenre:= ReadAtomData else FStream.Seek(AtomSize, soCurrent); end; end; end; end; procedure TMP4file.ReadSampleDescription; var Number: LongWord; begin if not FindAtomHeader('moov') then Exit; if not FindAtomHeader('trak') then Exit; if not FindAtomHeader('mdia') then Exit; if not FindAtomHeader('minf') then Exit; if not FindAtomHeader('stbl') then Exit; if FindAtomHeader('stsd') then begin FStream.Seek(4, soCurrent); Number:= SwapEndian(FStream.ReadDWord); if Number = 1 then begin if FindAtomHeader('mp4a') then begin FStream.Seek(16, soCurrent); FChannels:= SwapEndian(FStream.ReadWord); FSampleSize:= SwapEndian(FStream.ReadWord); FStream.Seek(2, soCurrent); FSampleRate:= SwapEndian(FStream.ReadDWord); end; end; end; end; constructor TMP4file.Create; begin end; destructor TMP4file.Destroy; begin inherited Destroy; end; function TMP4file.ReadFromFile(const FileName: String): Boolean; var AtomSize: Int64; AtomName: TAtomName; begin ResetData; FStream:= TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try FFileSize:= FStream.Size; Result:= LoadAtomHeader(AtomName, AtomSize) and SameText(AtomName, 'ftyp'); if Result then begin FStream.Seek(AtomSize, soCurrent); ReadSampleDescription; ReadMovieHeader; ReadMetaDataItemList; end; finally FreeAndNil(FStream); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/MPEGaudio.pas����������������������������������������0000644�0001750�0000144�00000106606�14743153644�022705� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TMPEGaudio - for manipulating with MPEG audio file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 2.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 2.00 (December 2004) by e-w@re } { - returns the correct MPEG data position in file } { - added property MPEGstart -> returns start of MPEG data in file } { - added property MPEGend -> returns end of MPEG data in file } { } { Version 1.99 (April 2004) by Gambit } { - Improved LAME detection } { (checks for the LAME string in the padding) } { } { Version 1.91 (April 2004) by Gambit } { - Added Ratio property } { } { Version 1.9 (22 February 2004) by Gambit } { - Added Samples property } { } { Version 1.8 (29 June 2003) by Gambit } { - Reads ape tags in mp3 files } { } { Version 1.7 (4 November 2002) } { - Ability to recognize QDesign MPEG audio encoder } { - Fixed bug with MPEG Layer II } { - Fixed bug with very big files } { } { Version 1.6 (23 May 2002) } { - Improved reading performance (up to 50% faster) } { } { Version 1.1 (11 September 2001) } { - Improved encoder guessing for CBR files } { } { Version 1.0 (31 August 2001) } { - Support for MPEG audio (versions 1, 2, 2.5, layers I, II, III) } { - Support for Xing & FhG VBR } { - Ability to guess audio encoder (Xing, FhG, LAME, Blade, GoGo, Shine) } { - Class TID3v1: reading & writing support for ID3v1 tags } { - Class TID3v2: reading & writing support for ID3v2 tags } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit MPEGaudio; interface uses Classes, SysUtils, ID3v1, ID3v2, APEtag; const { Table for bit rates } MPEG_BIT_RATE: array [0..3, 0..3, 0..15] of Word = ( { For MPEG 2.5 } ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), (0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0)), { Reserved } ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), { For MPEG 2 } ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), (0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0)), { For MPEG 1 } ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0), (0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0), (0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0)) ); { Sample rate codes } MPEG_SAMPLE_RATE_LEVEL_3 = 0; { Level 3 } MPEG_SAMPLE_RATE_LEVEL_2 = 1; { Level 2 } MPEG_SAMPLE_RATE_LEVEL_1 = 2; { Level 1 } MPEG_SAMPLE_RATE_UNKNOWN = 3; { Unknown value } { Table for sample rates } MPEG_SAMPLE_RATE: array [0..3, 0..3] of Word = ( (11025, 12000, 8000, 0), { For MPEG 2.5 } (0, 0, 0, 0), { Reserved } (22050, 24000, 16000, 0), { For MPEG 2 } (44100, 48000, 32000, 0) { For MPEG 1 } ); { VBR header ID for Xing/FhG } VBR_ID_XING = 'Xing'; { Xing VBR ID } VBR_ID_FHG = 'VBRI'; { FhG VBR ID } { MPEG version codes } MPEG_VERSION_2_5 = 0; { MPEG 2.5 } MPEG_VERSION_UNKNOWN = 1; { Unknown version } MPEG_VERSION_2 = 2; { MPEG 2 } MPEG_VERSION_1 = 3; { MPEG 1 } { MPEG version names } MPEG_VERSION: array [0..3] of string = ('MPEG 2.5', 'MPEG ?', 'MPEG 2', 'MPEG 1'); { MPEG layer codes } MPEG_LAYER_UNKNOWN = 0; { Unknown layer } MPEG_LAYER_III = 1; { Layer III } MPEG_LAYER_II = 2; { Layer II } MPEG_LAYER_I = 3; { Layer I } { MPEG layer names } MPEG_LAYER: array [0..3] of string = ('Layer ?', 'Layer III', 'Layer II', 'Layer I'); { Channel mode codes } MPEG_CM_STEREO = 0; { Stereo } MPEG_CM_JOINT_STEREO = 1; { Joint Stereo } MPEG_CM_DUAL_CHANNEL = 2; { Dual Channel } MPEG_CM_MONO = 3; { Mono } MPEG_CM_UNKNOWN = 4; { Unknown mode } { Channel mode names } MPEG_CM_MODE: array [0..4] of string = ('Stereo', 'Joint Stereo', 'Dual Channel', 'Mono', 'Unknown'); { Extension mode codes (for Joint Stereo) } MPEG_CM_EXTENSION_OFF = 0; { IS and MS modes set off } MPEG_CM_EXTENSION_IS = 1; { Only IS mode set on } MPEG_CM_EXTENSION_MS = 2; { Only MS mode set on } MPEG_CM_EXTENSION_ON = 3; { IS and MS modes set on } MPEG_CM_EXTENSION_UNKNOWN = 4; { Unknown extension mode } { Emphasis mode codes } MPEG_EMPHASIS_NONE = 0; { None } MPEG_EMPHASIS_5015 = 1; { 50/15 ms } MPEG_EMPHASIS_UNKNOWN = 2; { Unknown emphasis } MPEG_EMPHASIS_CCIT = 3; { CCIT J.17 } { Emphasis names } MPEG_EMPHASIS: array [0..3] of string = ('None', '50/15 ms', 'Unknown', 'CCIT J.17'); { Encoder codes } MPEG_ENCODER_UNKNOWN = 0; { Unknown encoder } MPEG_ENCODER_XING = 1; { Xing } MPEG_ENCODER_FHG = 2; { FhG } MPEG_ENCODER_LAME = 3; { LAME } MPEG_ENCODER_BLADE = 4; { Blade } MPEG_ENCODER_GOGO = 5; { GoGo } MPEG_ENCODER_SHINE = 6; { Shine } MPEG_ENCODER_QDESIGN = 7; { QDesign } { Encoder names } MPEG_ENCODER: array [0..7] of string = ('Unknown', 'Xing', 'FhG', 'LAME', 'Blade', 'GoGo', 'Shine', 'QDesign'); type hFileInt = Integer; { Xing/FhG VBR header data } VBRData = record Found: Boolean; { True if VBR header found } ID: array [1..4] of Char; { Header ID: "Xing" or "VBRI" } Frames: Integer; { Total number of frames } Bytes: Integer; { Total number of bytes } Scale: Byte; { VBR scale (1..100) } VendorID: string; { Vendor ID (if present) } end; { MPEG frame header data} FrameData = record Found: Boolean; { True if frame found } Position: Integer; { Frame position in the file } Size: Word; { Frame size (bytes) } Xing: Boolean; { True if Xing encoder } Data: array [1..4] of Byte; { The whole frame header data } VersionID: Byte; { MPEG version ID } LayerID: Byte; { MPEG layer ID } ProtectionBit: Boolean; { True if protected by CRC } BitRateID: Word; { Bit rate ID } SampleRateID: Word; { Sample rate ID } PaddingBit: Boolean; { True if frame padded } PrivateBit: Boolean; { Extra information } ModeID: Byte; { Channel mode ID } ModeExtensionID: Byte; { Mode extension ID (for Joint Stereo) } CopyrightBit: Boolean; { True if audio copyrighted } OriginalBit: Boolean; { True if original media } EmphasisID: Byte; { Emphasis ID } end; { Class TMPEGaudio } TMPEGaudio = class(TObject) private { Private declarations } FFileLength: Integer; FVendorID: string; FVBR: VBRData; FFrame: FrameData; FMPEGStart: Int64; FMPEGEnd: Int64; FAudioSizeTag: Int64; FID3v1: TID3v1; FID3v2: TID3v2; FAPEtag: TAPEtag; procedure FResetData; function FGetVersion: string; function FGetLayer: string; function FGetBitRate: Word; function FGetSampleRate: Word; function FGetChannelMode: string; function FGetEmphasis: string; function FGetFrames: Integer; function FGetDuration: Double; function FGetVBREncoderID: Byte; function FGetCBREncoderID: Byte; function FGetEncoderID: Byte; function FGetEncoder: string; function FGetValid: Boolean; function FGetSamples: Cardinal; function FGetRatio: Double; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load data } property FileLength: Integer read FFileLength; { File length (bytes) } property VBR: VBRData read FVBR; { VBR header data } property Frame: FrameData read FFrame; { Frame header data } property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data } property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data } property APEtag: TAPEtag read FAPEtag; { APE tag data } property Version: string read FGetVersion; { MPEG version name } property Layer: string read FGetLayer; { MPEG layer name } property BitRate: Word read FGetBitRate; { Bit rate (kbit/s) } property SampleRate: Word read FGetSampleRate; { Sample rate (hz) } property ChannelMode: string read FGetChannelMode; { Channel mode name } property Emphasis: string read FGetEmphasis; { Emphasis name } property Frames: Integer read FGetFrames; { Total number of frames } property Duration: Double read FGetDuration; { Song duration (sec) } property EncoderID: Byte read FGetEncoderID; { Guessed encoder ID } property Encoder: string read FGetEncoder; { Guessed encoder name } property Valid: Boolean read FGetValid; { True if MPEG file valid } property Samples: Cardinal read FGetSamples; property Ratio: Double read FGetRatio; { Compression ratio (%) } property MPEGStart: Int64 read FMPEGStart;{Returns start pos of MPEG data} property MPEGEnd: Int64 read FMPEGEnd; { Returns end pos of MPEG data } property AudioSizeTag: Int64 read FAudioSizeTag; { Returns ID3v2 TSIZ value or 0 } end; implementation uses DCOSUtils; const { Limitation constants } MAX_MPEG_FRAME_LENGTH = 1729; { Max. MPEG frame length } MIN_MPEG_BIT_RATE = 8; { Min. bit rate value } MAX_MPEG_BIT_RATE = 448; { Max. bit rate value } MIN_ALLOWED_DURATION = 0.1; { Min. song duration value } { VBR Vendor ID strings } VENDOR_ID_LAME = 'LAME'; { For LAME } VENDOR_ID_GOGO_NEW = 'GOGO'; { For GoGo (New) } VENDOR_ID_GOGO_OLD = 'MPGE'; { For GoGo (Old) } hINVALID_HANDLE_VALUE = hFileInt(-1); { ********************* Auxiliary functions & procedures ******************** } function IsFrameHeader(const HeaderData: array of Byte): Boolean; begin { Check for valid frame header } if ((HeaderData[0] and $FF) <> $FF) or ((HeaderData[1] and $E0) <> $E0) or (((HeaderData[1] shr 3) and 3) = 1) or (((HeaderData[1] shr 1) and 3) = 0) or ((HeaderData[2] and $F0) = $F0) or ((HeaderData[2] and $F0) = 0) or (((HeaderData[2] shr 2) and 3) = 3) or ((HeaderData[3] and 3) = 2) then Result := false else Result := true; end; { --------------------------------------------------------------------------- } procedure DecodeHeader(const HeaderData: array of Byte; var Frame: FrameData); begin { Decode frame header data } Move(HeaderData, Frame.Data, SizeOf(Frame.Data)); Frame.VersionID := (HeaderData[1] shr 3) and 3; Frame.LayerID := (HeaderData[1] shr 1) and 3; Frame.ProtectionBit := (HeaderData[1] and 1) <> 1; Frame.BitRateID := HeaderData[2] shr 4; Frame.SampleRateID := (HeaderData[2] shr 2) and 3; Frame.PaddingBit := ((HeaderData[2] shr 1) and 1) = 1; Frame.PrivateBit := (HeaderData[2] and 1) = 1; Frame.ModeID := (HeaderData[3] shr 6) and 3; Frame.ModeExtensionID := (HeaderData[3] shr 4) and 3; Frame.CopyrightBit := ((HeaderData[3] shr 3) and 1) = 1; Frame.OriginalBit := ((HeaderData[3] shr 2) and 1) = 1; Frame.EmphasisID := HeaderData[3] and 3; end; { --------------------------------------------------------------------------- } function ValidFrameAt(const Index: Word; Data: array of Byte): Boolean; var HeaderData: array [1..4] of Byte; begin { Check for frame at given position } HeaderData[1] := Data[Index]; HeaderData[2] := Data[Index + 1]; HeaderData[3] := Data[Index + 2]; HeaderData[4] := Data[Index + 3]; if IsFrameHeader(HeaderData) then Result := true else Result := false; end; { --------------------------------------------------------------------------- } function GetCoefficient(const Frame: FrameData): Byte; begin { Get frame size coefficient } if Frame.VersionID = MPEG_VERSION_1 then if Frame.LayerID = MPEG_LAYER_I then Result := 48 else Result := 144 else if Frame.LayerID = MPEG_LAYER_I then Result := 24 else if Frame.LayerID = MPEG_LAYER_II then Result := 144 else Result := 72; end; { --------------------------------------------------------------------------- } function GetBitRate(const Frame: FrameData): Word; begin { Get bit rate } Result := MPEG_BIT_RATE[Frame.VersionID, Frame.LayerID, Frame.BitRateID]; end; { --------------------------------------------------------------------------- } function GetSampleRate(const Frame: FrameData): Word; begin { Get sample rate } Result := MPEG_SAMPLE_RATE[Frame.VersionID, Frame.SampleRateID]; end; { --------------------------------------------------------------------------- } function GetPadding(const Frame: FrameData): Byte; begin { Get frame padding } if Frame.PaddingBit then if Frame.LayerID = MPEG_LAYER_I then Result := 4 else Result := 1 else Result := 0; end; { --------------------------------------------------------------------------- } function GetFrameLength(const Frame: FrameData): Word; var Coefficient, BitRate, SampleRate, Padding: Word; begin { Calculate MPEG frame length } Coefficient := GetCoefficient(Frame); BitRate := GetBitRate(Frame); SampleRate := GetSampleRate(Frame); Padding := GetPadding(Frame); Result := Trunc(Coefficient * BitRate * 1000 / SampleRate) + Padding; end; { --------------------------------------------------------------------------- } function IsXing(const Index: Word; Data: array of Byte): Boolean; begin { Get true if Xing encoder } Result := (Data[Index] = 0) and (Data[Index + 1] = 0) and (Data[Index + 2] = 0) and (Data[Index + 3] = 0) and (Data[Index + 4] = 0) and (Data[Index + 5] = 0); end; { --------------------------------------------------------------------------- } function GetXingInfo(const Index: Word; Data: array of Byte): VBRData; begin { Extract Xing VBR info at given position } FillChar(Result, SizeOf(Result), 0); Result.Found := true; Result.ID := VBR_ID_XING; Result.Frames := Data[Index + 8] * $1000000 + Data[Index + 9] * $10000 + Data[Index + 10] * $100 + Data[Index + 11]; Result.Bytes := Data[Index + 12] * $1000000 + Data[Index + 13] * $10000 + Data[Index + 14] * $100 + Data[Index + 15]; Result.Scale := Data[Index + 119]; { Vendor ID can be not present } Result.VendorID := Chr(Data[Index + 120]) + Chr(Data[Index + 121]) + Chr(Data[Index + 122]) + Chr(Data[Index + 123]) + Chr(Data[Index + 124]) + Chr(Data[Index + 125]) + Chr(Data[Index + 126]) + Chr(Data[Index + 127]); end; { --------------------------------------------------------------------------- } function GetFhGInfo(const Index: Word; Data: array of Byte): VBRData; begin { Extract FhG VBR info at given position } FillChar(Result, SizeOf(Result), 0); Result.Found := true; Result.ID := VBR_ID_FHG; Result.Scale := Data[Index + 9]; Result.Bytes := Data[Index + 10] * $1000000 + Data[Index + 11] * $10000 + Data[Index + 12] * $100 + Data[Index + 13]; Result.Frames := Data[Index + 14] * $1000000 + Data[Index + 15] * $10000 + Data[Index + 16] * $100 + Data[Index + 17]; end; { --------------------------------------------------------------------------- } function FindVBR(const Index: Word; Data: array of Byte): VBRData; begin { Check for VBR header at given position } FillChar(Result, SizeOf(Result), 0); if Chr(Data[Index]) + Chr(Data[Index + 1]) + Chr(Data[Index + 2]) + Chr(Data[Index + 3]) = VBR_ID_XING then Result := GetXingInfo(Index, Data); if Chr(Data[Index]) + Chr(Data[Index + 1]) + Chr(Data[Index + 2]) + Chr(Data[Index + 3]) = VBR_ID_FHG then Result := GetFhGInfo(Index, Data); end; { --------------------------------------------------------------------------- } function GetVBRDeviation(const Frame: FrameData): Byte; begin { Calculate VBR deviation } if Frame.VersionID = MPEG_VERSION_1 then if Frame.ModeID <> MPEG_CM_MONO then Result := 36 else Result := 21 else if Frame.ModeID <> MPEG_CM_MONO then Result := 21 else Result := 13; end; { --------------------------------------------------------------------------- } function FindFrame(const Data: array of Byte; var VBR: VBRData): FrameData; var HeaderData: array [1..4] of Byte; Iterator, VBRIdx: Integer; begin { Search for valid frame } FillChar(Result, SizeOf(Result), 0); Move(Data, HeaderData, SizeOf(HeaderData)); for Iterator := 0 to SizeOf(Data) - MAX_MPEG_FRAME_LENGTH do begin { Decode data if frame header found } if IsFrameHeader(HeaderData) then begin DecodeHeader(HeaderData, Result); { Check for next frame and try to find VBR header } VBRIdx := Iterator + GetFrameLength(Result); if (VBRIdx < SizeOf(Data)) and ValidFrameAt(VBRIdx, Data) then begin Result.Found := true; Result.Position := Iterator; Result.Size := GetFrameLength(Result); Result.Xing := IsXing(Iterator + SizeOf(HeaderData), Data); VBR := FindVBR(Iterator + GetVBRDeviation(Result), Data); break; end; end; { Prepare next data block } HeaderData[1] := HeaderData[2]; HeaderData[2] := HeaderData[3]; HeaderData[3] := HeaderData[4]; HeaderData[4] := Data[Iterator + SizeOf(HeaderData)]; end; end; { --------------------------------------------------------------------------- } function FindVendorID(const Data: array of Byte; Size: Word): string; var Iterator: Integer; VendorID: string; begin { Search for vendor ID } Result := ''; if (SizeOf(Data) - Size - 8) < 0 then Size := SizeOf(Data) - 8; for Iterator := 0 to Size do begin VendorID := Chr(Data[SizeOf(Data) - Iterator - 8]) + Chr(Data[SizeOf(Data) - Iterator - 7]) + Chr(Data[SizeOf(Data) - Iterator - 6]) + Chr(Data[SizeOf(Data) - Iterator - 5]); if VendorID = VENDOR_ID_LAME then begin Result := VendorID + Chr(Data[SizeOf(Data) - Iterator - 4]) + Chr(Data[SizeOf(Data) - Iterator - 3]) + Chr(Data[SizeOf(Data) - Iterator - 2]) + Chr(Data[SizeOf(Data) - Iterator - 1]); break; end; if VendorID = VENDOR_ID_GOGO_NEW then begin Result := VendorID; break; end; end; end; { ********************** Private functions & procedures ********************* } procedure TMPEGaudio.FResetData; begin { Reset all variables } FFileLength := 0; FMPEGStart := 0; FMPEGEnd := 0; FAudioSizeTag := 0; FVendorID := ''; FillChar(FVBR, SizeOf(FVBR), 0); FillChar(FFrame, SizeOf(FFrame), 0); FFrame.VersionID := MPEG_VERSION_UNKNOWN; FFrame.SampleRateID := MPEG_SAMPLE_RATE_UNKNOWN; FFrame.ModeID := MPEG_CM_UNKNOWN; FFrame.ModeExtensionID := MPEG_CM_EXTENSION_UNKNOWN; FFrame.EmphasisID := MPEG_EMPHASIS_UNKNOWN; FID3v1.ResetData; FID3v2.ResetData; FAPEtag.ResetData; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetVersion: string; begin { Get MPEG version name } Result := MPEG_VERSION[FFrame.VersionID]; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetLayer: string; begin { Get MPEG layer name } Result := MPEG_LAYER[FFrame.LayerID]; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetBitRate: Word; begin { Get bit rate, calculate average bit rate if VBR header found } if (FVBR.Found) and (FVBR.Frames > 0) then Result := Round((FVBR.Bytes / FVBR.Frames - GetPadding(FFrame)) * GetSampleRate(FFrame) / GetCoefficient(FFrame) / 1000) else Result := GetBitRate(FFrame); end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetSampleRate: Word; begin { Get sample rate } Result := GetSampleRate(FFrame); end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetChannelMode: string; begin { Get channel mode name } Result := MPEG_CM_MODE[FFrame.ModeID]; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetEmphasis: string; begin { Get emphasis name } Result := MPEG_EMPHASIS[FFrame.EmphasisID]; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetFrames: Integer; var MPEGSize: Integer; begin { Get total number of frames, calculate if VBR header not found } if FVBR.Found then Result := FVBR.Frames else begin MPEGSize := FMPEGEnd - FMPEGStart; Result := (MPEGSize - FFrame.Position) div GetFrameLength(FFrame); end; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetDuration: Double; var MPEGSize: Int64; begin { Calculate song duration } if FFrame.Found then if (FVBR.Found) and (FVBR.Frames > 0) then Result := FVBR.Frames * GetCoefficient(FFrame) * 8 / GetSampleRate(FFrame) else begin MPEGSize := FMPEGEnd - FMPEGStart; Result := (MPEGSize - FFrame.Position) / GetBitRate(FFrame) / 1000 * 8; end else Result := 0; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetVBREncoderID: Byte; begin { Guess VBR encoder and get ID } Result := 0; if Copy(FVBR.VendorID, 1, 4) = VENDOR_ID_LAME then Result := MPEG_ENCODER_LAME; if Copy(FVBR.VendorID, 1, 4) = VENDOR_ID_GOGO_NEW then Result := MPEG_ENCODER_GOGO; if Copy(FVBR.VendorID, 1, 4) = VENDOR_ID_GOGO_OLD then Result := MPEG_ENCODER_GOGO; if (FVBR.ID = VBR_ID_XING) and (Copy(FVBR.VendorID, 1, 4) <> VENDOR_ID_LAME) and (Copy(FVBR.VendorID, 1, 4) <> VENDOR_ID_GOGO_NEW) and (Copy(FVBR.VendorID, 1, 4) <> VENDOR_ID_GOGO_OLD) then Result := MPEG_ENCODER_XING; if FVBR.ID = VBR_ID_FHG then Result := MPEG_ENCODER_FHG; if (Copy(FVendorID, 1, 4) = VENDOR_ID_LAME) then Result := MPEG_ENCODER_LAME; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetCBREncoderID: Byte; begin { Guess CBR encoder and get ID } Result := MPEG_ENCODER_FHG; if (FFrame.OriginalBit) and (FFrame.ProtectionBit) then Result := MPEG_ENCODER_LAME; if (GetBitRate(FFrame) <= 160) and (FFrame.ModeID = MPEG_CM_STEREO) then Result := MPEG_ENCODER_BLADE; if (FFrame.CopyrightBit) and (FFrame.OriginalBit) and (not FFrame.ProtectionBit) then Result := MPEG_ENCODER_XING; if (FFrame.Xing) and (FFrame.OriginalBit) then Result := MPEG_ENCODER_XING; if FFrame.LayerID = MPEG_LAYER_II then Result := MPEG_ENCODER_QDESIGN; if (FFrame.ModeID = MPEG_CM_DUAL_CHANNEL) and (FFrame.ProtectionBit) then Result := MPEG_ENCODER_SHINE; if Copy(FVendorID, 1, 4) = VENDOR_ID_LAME then Result := MPEG_ENCODER_LAME; if Copy(FVendorID, 1, 4) = VENDOR_ID_GOGO_NEW then Result := MPEG_ENCODER_GOGO; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetEncoderID: Byte; begin { Get guessed encoder ID } if FFrame.Found then if FVBR.Found then Result := FGetVBREncoderID else Result := FGetCBREncoderID else Result := 0; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetEncoder: string; var VendorID: string; begin { Get guessed encoder name and encoder version for LAME } Result := MPEG_ENCODER[FGetEncoderID]; if FVBR.VendorID <> '' then VendorID := FVBR.VendorID; if FVendorID <> '' then VendorID := FVendorID; if (FGetEncoderID = MPEG_ENCODER_LAME) and (Length(VendorID) >= 8) and (VendorID[5] in ['0'..'9']) and (VendorID[6] = '.') and (VendorID[7] in ['0'..'9']) and (VendorID[8] in ['0'..'9']) then Result := Result + #32 + VendorID[5] + VendorID[6] + VendorID[7] + VendorID[8]; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetValid: Boolean; begin { Check for right MPEG file data } Result := (FFrame.Found) and (FGetBitRate >= MIN_MPEG_BIT_RATE) and (FGetBitRate <= MAX_MPEG_BIT_RATE) and (FGetDuration >= MIN_ALLOWED_DURATION); end; { ********************** Public functions & procedures ********************** } constructor TMPEGaudio.Create; begin { Object constructor } inherited; FID3v1 := TID3v1.Create; FID3v2 := TID3v2.Create; FAPEtag := TAPEtag.Create; FResetData; end; { --------------------------------------------------------------------------- } destructor TMPEGaudio.Destroy; begin { Object destructor } FID3v1.Free; FID3v2.Free; FAPEtag.Free; inherited; end; { --------------------------------------------------------------------------- } function TMPEGaudio.ReadFromFile(const FileName: String): Boolean; var SourceFile: hFileInt; Data: array [1..MAX_MPEG_FRAME_LENGTH * 2] of Byte; Transferred: DWORD; Position : Int64; tmp : Integer; str: string; Value: Int64; Code: Integer; begin FResetData; SourceFile := hINVALID_HANDLE_VALUE; try SourceFile := mbFileOpen(FileName, fmOpenRead or fmShareDenyWrite); if (SourceFile = hINVALID_HANDLE_VALUE) then begin Result := false; Exit; end; { At first search for tags & Lyrics3 then search for a MPEG frame and VBR data } if (FID3v2.ReadFromFile(FileName)) and (FID3v1.ReadFromFile(FileName)) then begin FFileLength := mbFileSize(FileName); Position := FID3v2.Size; FileSeek(SourceFile, Position, soFromBeginning); Transferred:= FileRead(SourceFile, Data, SizeOf(Data)); FFrame := FindFrame(Data, FVBR); // Search for vendor ID at the beginning FVendorID := FindVendorID(Data, FFrame.Size * 5); { patched by e-w@re } { Try to find the first frame if no frame at the beginning found ]} if (not FFrame.Found) and (Transferred = SizeOf(Data)) then repeat Transferred:= FileRead(SourceFile, Data, SizeOf(Data)); Inc(Position, Transferred); FFrame := FindFrame(Data, FVBR); until (FFrame.Found) or (Transferred < SizeOf(Data)); if FFrame.Found then begin FFrame.Position := Position + FFrame.Position; FMPEGStart := FFrame.Position; tmp := FID3v1.TagSize; FMPEGEnd := FFileLength - tmp; end; if FID3v2.Exists then begin str := FID3v2.TSIZ; if Length(str) > 0 then try Val(str, Value, Code); if (Code = 0) then FAudioSizeTag := Value; except // ignore end; end; { Search for vendor ID at the end if CBR encoded } if (FFrame.Found) and (FVendorID = '') then begin if not FID3v1.Exists then Position := FFileLength - SizeOf(Data) else Position := FFileLength - SizeOf(Data) - 128; FileSeek(SourceFile, Position, soFromBeginning); Transferred:= FileRead(SourceFile, Data, SizeOf(Data)); FVendorID := FindVendorID(Data, FFrame.Size * 5); end; end; FileClose(SourceFile); Result := true; except if (SourceFile <> hINVALID_HANDLE_VALUE) then FileClose(SourceFile); Result := false; end; if not FFrame.Found then FResetData; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetSamples: Cardinal; begin Result := 0; if FFrame.Found then // rework, it's the same if (FVBR.Found) and (FVBR.Frames > 0) then Result := FVBR.Frames * GetCoefficient(FFrame) * 8 else Result := FGetFrames * GetCoefficient(FFrame) * 8; end; { --------------------------------------------------------------------------- } function TMPEGaudio.FGetRatio: Double; begin { Get compression ratio } if FGetValid then begin //Result := FFileSize / (FGetSamples * FChannels * FBits / 8 + 44) * 100 if ChannelMode = 'Mono' then Result := FFileLength / (FGetSamples * (1 * 16 / 8) + 44) * 100 else Result := FFileLength / (FGetSamples * (2 * 16 / 8) + 44) * 100; end else Result := 0; end; { --------------------------------------------------------------------------- } end. ��������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/Monkey.pas�������������������������������������������0000644�0001750�0000144�00000044217�14743153644�022374� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TMonkey - for manipulating with Monkey's Audio file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.7 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.6 (11 April 2004) by Gambit } { - Added Ratio property again } { } { Version 1.5 (22 August 2003) by MaDah } { - Added support for Monkey's Audio 3.98 } { - Added/changed/removed some stuff } { } { Version 1.4 (29 July 2002) } { - Correction for calculating of duration } { } { Version 1.1 (11 September 2001) } { - Added property Samples } { - Removed WAV header information } { } { Version 1.0 (7 September 2001) } { - Support for Monkey's Audio files } { - Class TID3v1: reading & writing support for ID3v1 tags } { - Class TID3v2: reading & writing support for ID3v2 tags } { - Class TAPEtag: reading & writing support for APE tags } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit Monkey; interface uses Classes, SysUtils, ID3v1, ID3v2, APEtag, DCClassesUtf8; const { Compression level codes } MONKEY_COMPRESSION_FAST = 1000; { Fast (poor) } MONKEY_COMPRESSION_NORMAL = 2000; { Normal (good) } MONKEY_COMPRESSION_HIGH = 3000; { High (very good) } MONKEY_COMPRESSION_EXTRA_HIGH = 4000; { Extra high (best) } MONKEY_COMPRESSION_INSANE = 5000; { Insane } MONKEY_COMPRESSION_BRAINDEAD = 6000; { BrainDead } { Compression level names } MONKEY_COMPRESSION: array [0..6] of string = ('Unknown', 'Fast', 'Normal', 'High', 'Extra High', 'Insane', 'BrainDead'); { Format flags, only for Monkey's Audio <= 3.97 } MONKEY_FLAG_8_BIT = 1; // Audio 8-bit MONKEY_FLAG_CRC = 2; // New CRC32 error detection MONKEY_FLAG_PEAK_LEVEL = 4; // Peak level stored MONKEY_FLAG_24_BIT = 8; // Audio 24-bit MONKEY_FLAG_SEEK_ELEMENTS = 16; // Number of seek elements stored MONKEY_FLAG_WAV_NOT_STORED = 32; // WAV header not stored { Channel mode names } MONKEY_MODE: array [0..2] of string = ('Unknown', 'Mono', 'Stereo'); type { Class TMonkey } TMonkey = class(TObject) private { Private declarations } FValid : boolean; // Stuff loaded from the header: FVersion : integer; FVersionStr : string; FChannels : integer; FSampleRate : integer; FBits : integer; FPeakLevel : longword; FPeakLevelRatio : double; FTotalSamples : int64; FBitrate : double; FDuration : double; FCompressionMode : integer; FCompressionModeStr : string; // FormatFlags, only used with Monkey's <= 3.97 FFormatFlags : integer; FHasPeakLevel : boolean; FHasSeekElements : boolean; FWavNotStored : boolean; // Tagging FID3v1 : TID3v1; FID3v2 : TID3v2; FAPEtag : TAPEtag; // FFileSize : int64; procedure FResetData; function FGetRatio: Double; function FGetChannelMode: string; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load header } property FileSize : int64 read FFileSize; property Valid : boolean read FValid; property Version : integer read FVersion; property VersionStr : string read FVersionStr; property Channels : integer read FChannels; property SampleRate : integer read FSamplerate; property Bits : integer read FBits; property Bitrate : double read FBitrate; property Duration : double read FDuration; property PeakLevel : longword read FPeakLevel; property PeakLevelRatio : double read FPeakLevelRatio; property TotalSamples : int64 read FTotalSamples; property CompressionMode : integer read FCompressionMode; property CompressionModeStr: string read FCompressionModeStr; property ChannelMode: string read FGetChannelMode; { Channel mode name } // FormatFlags, only used with Monkey's <= 3.97 property FormatFlags : integer read FFormatFlags; property HasPeakLevel : boolean read FHasPeakLevel; property HasSeekElements : boolean read FHasSeekElements; property WavNotStored : boolean read FWavNotStored; // Tagging property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data } property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data } property APEtag: TAPEtag read FAPEtag; { APE tag data } property Ratio: Double read FGetRatio; { Compression ratio (%) } end; implementation type { Real structure of Monkey's Audio header } // common header for all versions APE_HEADER = packed record cID: array[0..3] of byte; // should equal 'MAC ' nVersion : WORD; // version number * 1000 (3.81 = 3810) end; // old header for <= 3.97 APE_HEADER_OLD = packed record nCompressionLevel, // the compression level nFormatFlags, // any format flags (for future use) nChannels: word; // the number of channels (1 or 2) nSampleRate, // the sample rate (typically 44100) nHeaderBytes, // the bytes after the MAC header that compose the WAV header nTerminatingBytes, // the bytes after that raw data (for extended info) nTotalFrames, // the number of frames in the file nFinalFrameBlocks: longword; // the number of samples in the final frame nInt : integer; end; // new header for >= 3.98 APE_HEADER_NEW = packed record nCompressionLevel : word; // the compression level (see defines I.E. COMPRESSION_LEVEL_FAST) nFormatFlags : word; // any format flags (for future use) Note: NOT the same flags as the old header! nBlocksPerFrame : longword; // the number of audio blocks in one frame nFinalFrameBlocks : longword; // the number of audio blocks in the final frame nTotalFrames : longword; // the total number of frames nBitsPerSample : word; // the bits per sample (typically 16) nChannels : word; // the number of channels (1 or 2) nSampleRate : longword; // the sample rate (typically 44100) end; // data descriptor for >= 3.98 APE_DESCRIPTOR = packed record padded : Word; // padding/reserved (always empty) nDescriptorBytes, // the number of descriptor bytes (allows later expansion of this header) nHeaderBytes, // the number of header APE_HEADER bytes nSeekTableBytes, // the number of bytes of the seek table nHeaderDataBytes, // the number of header data bytes (from original file) nAPEFrameDataBytes, // the number of bytes of APE frame data nAPEFrameDataBytesHigh, // the high order number of APE frame data bytes nTerminatingDataBytes : longword;// the terminating data of the file (not including tag data) cFileMD5 : array[0..15] of Byte; // the MD5 hash of the file (see notes for usage... it's a littly tricky) end; { ********************** Private functions & procedures ********************* } procedure TMonkey.FResetData; begin { Reset data } FValid := false; FVersion := 0; FVersionStr := ''; FChannels := 0; FSampleRate := 0; FBits := 0; FPeakLevel := 0; FPeakLevelRatio := 0.0; FTotalSamples := 0; FBitrate := 0.0; FDuration := 0.0; FCompressionMode := 0; FCompressionModeStr := ''; FFormatFlags := 0; FHasPeakLevel := false; FHasSeekElements := false; FWavNotStored := false; FFileSize := 0; FID3v1.ResetData; FID3v2.ResetData; FAPEtag.ResetData; end; { ********************** Public functions & procedures ********************** } constructor TMonkey.Create; begin { Create object } inherited; FID3v1 := TID3v1.Create; FID3v2 := TID3v2.Create; FAPEtag := TAPEtag.Create; FResetData; end; { --------------------------------------------------------------------------- } destructor TMonkey.Destroy; begin { Destroy object } FID3v1.Free; FID3v2.Free; FAPEtag.Free; inherited; end; { --------------------------------------------------------------------------- } function TMonkey.ReadFromFile(const FileName: String): Boolean; var f : TFileStreamEx; APE : APE_HEADER; // common header APE_OLD : APE_HEADER_OLD; // old header <= 3.97 APE_NEW : APE_HEADER_NEW; // new header >= 3.98 APE_DESC : APE_DESCRIPTOR; // extra header >= 3.98 BlocksPerFrame : integer; LoadSuccess : boolean; TagSize : integer; begin Result := FALSE; FResetData; // load tags first FID3v2.ReadFromFile(FileName); FID3v1.ReadFromFile(FileName); FAPEtag.ReadFromFile(FileName); // calculate total tag size TagSize := 0; if FID3v1.Exists then inc(TagSize, 128); if FID3v2.Exists then inc(TagSize, FID3v2.Size); if FAPEtag.Exists then inc(TagSize, FAPETag.Size); // begin reading data from file LoadSuccess := FALSE; f:=nil; try try f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite); FFileSize := f.Size; // seek past id3v2-tag if FID3v2.Exists then begin f.Seek(FID3v2.Size, soFromBeginning); end; // Read APE Format Header fillchar(APE, sizeof(APE), 0); if (f.Read(APE, sizeof(APE)) = sizeof(APE)) and ( StrLComp(@APE.cID[0],'MAC ',4)=0) then begin FVersion := APE.nVersion; Str(FVersion / 1000 : 4 : 2, FVersionStr); // Load New Monkey's Audio Header for version >= 3.98 if APE.nVersion >= 3980 then begin fillchar(APE_DESC, sizeof(APE_DESC), 0); if (f.Read(APE_DESC, sizeof(APE_DESC)) = sizeof(APE_DESC)) then begin // seek past description header if APE_DESC.nDescriptorBytes <> 52 then f.Seek(APE_DESC.nDescriptorBytes - 52, soFromCurrent); // load new ape_header if APE_DESC.nHeaderBytes > sizeof(APE_NEW) then APE_DESC.nHeaderBytes := sizeof(APE_NEW); fillchar(APE_NEW, sizeof(APE_NEW), 0); if (longword(f.Read(APE_NEW, APE_DESC.nHeaderBytes)) = APE_DESC.nHeaderBytes ) then begin // based on MAC SDK 3.98a1 (APEinfo.h) FSampleRate := APE_NEW.nSampleRate; FChannels := APE_NEW.nChannels; FFormatFlags := APE_NEW.nFormatFlags; FBits := APE_NEW.nBitsPerSample; FCompressionMode := APE_NEW.nCompressionLevel; // calculate total uncompressed samples if APE_NEW.nTotalFrames>0 then begin FTotalSamples := Int64(APE_NEW.nBlocksPerFrame) * Int64(APE_NEW.nTotalFrames-1) + Int64(APE_NEW.nFinalFrameBlocks); end; LoadSuccess := TRUE; end; end; end else begin // Old Monkey <= 3.97 fillchar(APE_OLD, sizeof(APE_OLD), 0); if (f.Read(APE_OLD, sizeof(APE_OLD)) = sizeof(APE_OLD) ) then begin FCompressionMode := APE_OLD.nCompressionLevel; FSampleRate := APE_OLD.nSampleRate; FChannels := APE_OLD.nChannels; FFormatFlags := APE_OLD.nFormatFlags; FBits := 16; if APE_OLD.nFormatFlags and MONKEY_FLAG_8_BIT <>0 then FBits := 8; if APE_OLD.nFormatFlags and MONKEY_FLAG_24_BIT <>0 then FBits := 24; FHasSeekElements := APE_OLD.nFormatFlags and MONKEY_FLAG_PEAK_LEVEL <>0; FWavNotStored := APE_OLD.nFormatFlags and MONKEY_FLAG_SEEK_ELEMENTS <>0; FHasPeakLevel := APE_OLD.nFormatFlags and MONKEY_FLAG_WAV_NOT_STORED<>0; if FHasPeakLevel then begin FPeakLevel := APE_OLD.nInt; FPeakLevelRatio := (FPeakLevel / (1 shl FBits) / 2.0) * 100.0; end; // based on MAC_SDK_397 (APEinfo.cpp) if (FVersion >= 3950) then BlocksPerFrame := 73728 * 4 else if (FVersion >= 3900) or ((FVersion >= 3800) and (APE_OLD.nCompressionLevel = MONKEY_COMPRESSION_EXTRA_HIGH)) then BlocksPerFrame := 73728 else BlocksPerFrame := 9216; // calculate total uncompressed samples if APE_OLD.nTotalFrames>0 then begin FTotalSamples := Int64(APE_OLD.nTotalFrames-1) * Int64(BlocksPerFrame) + Int64(APE_OLD.nFinalFrameBlocks); end; LoadSuccess := TRUE; end; end; if LoadSuccess then begin // compression profile name if ((FCompressionMode mod 1000) = 0) and (FCompressionMode<=6000) then begin FCompressionModeStr := MONKEY_COMPRESSION[FCompressionMode div 1000]; end else begin FCompressionModeStr := IntToStr(FCompressionMode); end; // length if FSampleRate>0 then FDuration := FTotalSamples / FSampleRate; // average bitrate if FDuration>0 then FBitrate := (FFileSize - Int64(TagSize))*8.0 / (FDuration/1000.0); // some extra sanity checks FValid := (FBits>0) and (FSampleRate>0) and (FTotalSamples>0) and (FChannels>0); Result := FValid; end; end; finally f.free; end; except end; end; { --------------------------------------------------------------------------- } function TMonkey.FGetRatio: Double; begin { Get compression ratio } if FValid then Result := FFileSize / (FTotalSamples * (FChannels * FBits / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } function TMonkey.FGetChannelMode: string; begin if FChannels < Length(MONKEY_MODE) then Result:= MONKEY_MODE[FChannels] else begin Result:= EmptyStr; end; end; { --------------------------------------------------------------------------- } end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/Musepack.pas�����������������������������������������0000644�0001750�0000144�00000044027�14743153644�022701� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TMPEGplus - for manipulating with Musepack file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 2.0 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.9 (13 April 2004) by Gambit } { - Added Ratio property } { } { Version 1.81 (27 September 2003) } { - changed minimal allowed bitrate to '3' (e.g. encoded digital silence) } { } { Version 1.8 (20 August 2003) by Madah } { - Will now read files with different samplerates correctly } { - Also changed GetProfileID() for this to work } { - Added the ability to determine encoder used } { } { Version 1.7 (7 June 2003) by Gambit } { - --quality 0 to 10 detection (all profiles) } { - Stream Version 7.1 detected and supported } { } { Version 1.6 (8 February 2002) } { - Fixed bug with property Corrupted } { } { Version 1.2 (2 August 2001) } { - Some class properties added/changed } { } { Version 1.1 (26 July 2001) } { - Fixed reading problem with "read only" files } { } { Version 1.0 (23 May 2001) } { - Support for MPEGplus files (stream versions 4-7) } { - Class TID3v1: reading & writing support for ID3v1 tags } { - Class TID3v2: reading & writing support for ID3v2 tags } { - Class TAPEtag: reading & writing support for APE tags } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit Musepack; interface uses Classes, SysUtils, ID3v1, ID3v2, APEtag, DCClassesUtf8; const { Used with ChannelModeID property } MPP_CM_STEREO = 1; { Index for stereo mode } MPP_CM_JOINT_STEREO = 2; { Index for joint-stereo mode } { Channel mode names } MPP_MODE: array [0..2] of string = ('Unknown', 'Stereo', 'Joint Stereo'); { Used with ProfileID property } MPP_PROFILE_QUALITY0 = 9; { '--quality 0' profile } MPP_PROFILE_QUALITY1 = 10; { '--quality 1' profile } MPP_PROFILE_TELEPHONE = 11; { 'Telephone' profile } MPP_PROFILE_THUMB = 1; { 'Thumb' (poor) quality } MPP_PROFILE_RADIO = 2; { 'Radio' (normal) quality } MPP_PROFILE_STANDARD = 3; { 'Standard' (good) quality } MPP_PROFILE_XTREME = 4; { 'Xtreme' (very good) quality } MPP_PROFILE_INSANE = 5; { 'Insane' (excellent) quality } MPP_PROFILE_BRAINDEAD = 6; { 'BrainDead' (excellent) quality } MPP_PROFILE_QUALITY9 = 7; { '--quality 9' (excellent) quality } MPP_PROFILE_QUALITY10 = 8; { '--quality 10' (excellent) quality } MPP_PROFILE_UNKNOWN = 0; { Unknown profile } MPP_PROFILE_EXPERIMENTAL = 12; { Profile names } MPP_PROFILE: array [0..12] of string = ('Unknown', 'Thumb', 'Radio', 'Standard', 'Xtreme', 'Insane', 'BrainDead', '--quality 9', '--quality 10', '--quality 0', '--quality 1', 'Telephone', 'Experimental'); type { Class TMPEGplus } TMPEGplus = class(TObject) private { Private declarations } FValid: Boolean; FChannelModeID: Byte; FFileSize: Integer; FFrameCount: Integer; FSampleRate: Integer; FBitRate: Word; FStreamVersion: Byte; FProfileID: Byte; FID3v1: TID3v1; FID3v2: TID3v2; FAPEtag: TAPEtag; FEncoder : string; procedure FResetData; function FGetChannelMode: string; function FGetBitRate: Word; function FGetProfile: string; function FGetDuration: Double; function FIsCorrupted: Boolean; function FGetRatio: Double; function FGetStreamStreamVersionString: String; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean;{ Load header } property Valid: Boolean read FValid; { True if header valid } property ChannelModeID: Byte read FChannelModeID; { Channel mode code } property ChannelMode: string read FGetChannelMode; { Channel mode name } property FileSize: Integer read FFileSize; { File size (bytes) } property FrameCount: Integer read FFrameCount; { Number of frames } property BitRate: Word read FGetBitRate; { Bit rate } property StreamVersion: Byte read FStreamVersion; { Stream version } property StreamStreamVersionString: String read FGetStreamStreamVersionString; property SampleRate: Integer read FSampleRate; property ProfileID: Byte read FProfileID; { Profile code } property Profile: string read FGetProfile; { Profile name } property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data } property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data } property APEtag: TAPEtag read FAPEtag; { APE tag data } property Duration: Double read FGetDuration; { Duration (seconds) } property Corrupted: Boolean read FIsCorrupted; { True if file corrupted } property Encoder: string read FEncoder; { Encoder used } property Ratio: Double read FGetRatio; { Compression ratio (%) } end; implementation const { ID code for stream version 7 and 7.1 } STREAM_VERSION_7_ID = 120279117; { 120279117 = 'MP+' + #7 } STREAM_VERSION_71_ID = 388714573; { 388714573 = 'MP+' + #23 } type { File header data - for internal use } HeaderRecord = record ByteArray: array [1..32] of Byte; { Data as byte array } IntegerArray: array [1..8] of Integer; { Data as integer array } FileSize: Integer; { File size } ID3v2Size: Integer; { ID3v2 tag size (bytes) } end; { ********************* Auxiliary functions & procedures ******************** } function ReadHeader(const FileName: String; var Header: HeaderRecord): Boolean; var SourceFile: TFileStreamEx; Transferred: Integer; begin try Result := true; { Set read-access and open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); SourceFile.Seek(Header.ID3v2Size, soFromBeginning); { Read header and get file size } Transferred := SourceFile.Read(Header, 32); Header.FileSize := SourceFile.Size; SourceFile.Free; { if transfer is not complete } if Transferred < 32 then Result := false else Move(Header.ByteArray, Header.IntegerArray, SizeOf(Header.ByteArray)); except { Error } Result := false; end; end; { --------------------------------------------------------------------------- } function GetStreamVersion(const Header: HeaderRecord): Byte; begin { Get MPEGplus stream version } if Header.IntegerArray[1] = STREAM_VERSION_7_ID then Result := 7 else if Header.IntegerArray[1] = STREAM_VERSION_71_ID then Result := 71 else case (Header.ByteArray[2] mod 32) div 2 of 3: Result := 4; 7: Result := 5; 11: Result := 6 else Result := 0; end; end; { --------------------------------------------------------------------------- } function GetSampleRate(const Header: HeaderRecord): Integer; const mpp_samplerates : array[0..3] of integer = ( 44100, 48000, 37800, 32000 ); begin (* get samplerate from header note: this is the same byte where profile is stored *) Result := mpp_samplerates[Header.ByteArray[11] and 3]; end; { --------------------------------------------------------------------------- } function GetEncoder(const Header: HeaderRecord): string; var EncoderID : integer; begin EncoderID := Header.ByteArray[11+2+15]; Result := ''; if EncoderID = 0 then begin //FEncoder := 'Buschmann 1.7.0...9, Klemm 0.90...1.05'; end else begin case ( EncoderID mod 10 ) of 0: Result := format('%u.%u Release', [EncoderID div 100, (EncoderID div 10) mod 10]); 2,4,6,8 : Result := format('%u.%.2u Beta', [EncoderID div 100, EncoderID mod 100] ); else Result := format('%u.%.2u --Alpha--', [EncoderID div 100, EncoderID mod 100] ); end; end; end; { --------------------------------------------------------------------------- } function GetChannelModeID(const Header: HeaderRecord): Byte; begin if (GetStreamVersion(Header) = 7) or (GetStreamVersion(Header) = 71) then { Get channel mode for stream version 7 } if (Header.ByteArray[12] mod 128) < 64 then Result := MPP_CM_STEREO else Result := MPP_CM_JOINT_STEREO else { Get channel mode for stream version 4-6 } if (Header.ByteArray[3] mod 128) = 0 then Result := MPP_CM_STEREO else Result := MPP_CM_JOINT_STEREO; end; { --------------------------------------------------------------------------- } function GetFrameCount(const Header: HeaderRecord): Integer; begin { Get frame count } case GetStreamVersion(Header) of 4: Result := Header.IntegerArray[2] shr 16; 5..71: Result := Header.IntegerArray[2]; else Result := 0; end; end; { --------------------------------------------------------------------------- } function GetBitRate(const Header: HeaderRecord): Word; begin { Try to get bit rate } case GetStreamVersion(Header) of 4, 5: Result := Header.IntegerArray[1] shr 23; else Result := 0; end; end; { --------------------------------------------------------------------------- } function GetProfileID(const Header: HeaderRecord): Byte; begin Result := MPP_PROFILE_UNKNOWN; { Get MPEGplus profile (exists for stream version 7 only) } if (GetStreamVersion(Header) = 7) or (GetStreamVersion(Header) = 71) then // ((and $F0) shr 4) is needed because samplerate is stored in the same byte! case ((Header.ByteArray[11] and $F0) shr 4) of 1: Result := MPP_PROFILE_EXPERIMENTAL; 5: Result := MPP_PROFILE_QUALITY0; 6: Result := MPP_PROFILE_QUALITY1; 7: Result := MPP_PROFILE_TELEPHONE; 8: Result := MPP_PROFILE_THUMB; 9: Result := MPP_PROFILE_RADIO; 10: Result := MPP_PROFILE_STANDARD; 11: Result := MPP_PROFILE_XTREME; 12: Result := MPP_PROFILE_INSANE; 13: Result := MPP_PROFILE_BRAINDEAD; 14: Result := MPP_PROFILE_QUALITY9; 15: Result := MPP_PROFILE_QUALITY10; end; end; { ********************** Private functions & procedures ********************* } procedure TMPEGplus.FResetData; begin FValid := false; FChannelModeID := 0; FFileSize := 0; FFrameCount := 0; FBitRate := 0; FStreamVersion := 0; FSampleRate := 0; FEncoder := ''; FProfileID := MPP_PROFILE_UNKNOWN; FID3v1.ResetData; FID3v2.ResetData; FAPEtag.ResetData; end; { --------------------------------------------------------------------------- } function TMPEGplus.FGetChannelMode: string; begin Result := MPP_MODE[FChannelModeID]; end; { --------------------------------------------------------------------------- } function TMPEGplus.FGetBitRate: Word; var CompressedSize: Integer; begin Result := FBitRate; { Calculate bit rate if not given } CompressedSize := FFileSize - FID3v2.Size - FAPEtag.Size; if FID3v1.Exists then Dec(FFileSize, 128); if (Result = 0) and (FFrameCount > 0) then Result := Round(CompressedSize * 8 * (FSampleRate/1000) / FFRameCount / 1152); end; { --------------------------------------------------------------------------- } function TMPEGplus.FGetProfile: string; begin Result := MPP_PROFILE[FProfileID]; end; { --------------------------------------------------------------------------- } function TMPEGplus.FGetDuration: Double; begin { Calculate duration time } if FSampleRate > 0 then Result := FFRameCount * 1152 / FSampleRate else Result := 0; end; { --------------------------------------------------------------------------- } function TMPEGplus.FIsCorrupted: Boolean; begin { Check for file corruption } Result := (FValid) and ((FGetBitRate < 3) or (FGetBitRate > 480)); end; { ********************** Public functions & procedures ********************** } constructor TMPEGplus.Create; begin inherited; FID3v1 := TID3v1.Create; FID3v2 := TID3v2.Create; FAPEtag := TAPEtag.Create; FResetData; end; { --------------------------------------------------------------------------- } destructor TMPEGplus.Destroy; begin FID3v1.Free; FID3v2.Free; FAPEtag.Free; inherited; end; { --------------------------------------------------------------------------- } function TMPEGplus.ReadFromFile(const FileName: String): Boolean; var Header: HeaderRecord; begin { Reset data and load header from file to variable } FResetData; FillChar(Header, SizeOf(Header), 0); { At first try to load ID3v2 tag data, then header } if FID3v2.ReadFromFile(FileName) then Header.ID3v2Size := FID3v2.Size; Result := ReadHeader(FileName, Header); { Process data if loaded and file valid } if (Result) and (Header.FileSize > 0) and (GetStreamVersion(Header) > 0) then begin FValid := true; { Fill properties with header data } FSampleRate := GetSampleRate(Header); FChannelModeID := GetChannelModeID(Header); FFileSize := Header.FileSize; FFrameCount := GetFrameCount(Header); FBitRate := GetBitRate(Header); FStreamVersion := GetStreamVersion(Header); FProfileID := GetProfileID(Header); FEncoder := GetEncoder(Header); FID3v1.ReadFromFile(FileName); FAPEtag.ReadFromFile(FileName); end; end; { --------------------------------------------------------------------------- } function TMPEGplus.FGetRatio: Double; begin { Get compression ratio } if (FValid) and ((FChannelModeID = MPP_CM_STEREO) or (FChannelModeID = MPP_CM_JOINT_STEREO)) then Result := FFileSize / ((FFrameCount * 1152) * (2 * 16 / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } function TMPEGplus.FGetStreamStreamVersionString: String; begin case FStreamVersion of 4: Result := '4.0'; 5: Result := '5.0'; 6: Result := '6.0'; 7: Result := '7.0'; 71: Result := '7.1'; else Result := IntToStr(FStreamVersion); end; end; { --------------------------------------------------------------------------- } end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/OggVorbis.pas����������������������������������������0000644�0001750�0000144�00000104414�14743153644�023027� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TOggVorbis - for manipulating with Ogg Vorbis file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.9 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.83 (26 march 2005) by Kurtnoise } { - Added multichannel support } { } { Version 1.82 (23 March 2005) by Gambit } { - fixed nominal bitrate info (eg 192 was 193 sometimes) } { } { Version 1.81 (21 June 2004) by Gambit } { - Added Encoder property } { } { Version 1.8 (13 April 2004) by Gambit } { - Added Ratio property } { } { Version 1.7 (20 August 2003) by Madah } { - Minor fix: changed FSampleRate into Integer } { ... so that samplerates>65535 works. } { } { Version 1.6 (2 October 2002) } { - Writing support for Vorbis tag } { - Changed several properties } { - Fixed bug with long Vorbis tag fields } { } { Version 1.2 (18 February 2002) } { - Added property BitRateNominal } { - Fixed bug with Vorbis tag fields } { } { Version 1.1 (21 October 2001) } { - Support for UTF-8 } { - Fixed bug with vendor info detection } { } { Version 1.0 (15 August 2001) } { - File info: file size, channel mode, sample rate, duration, bit rate } { - Vorbis tag: title, artist, album, track, date, genre, comment, vendor } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit OggVorbis; interface uses Classes, SysUtils, DCClassesUtf8, DCOSUtils; const { Used with ChannelModeID property } VORBIS_CM_MONO = 1; { Code for mono mode } VORBIS_CM_STEREO = 2; { Code for stereo mode } VORBIS_CM_MULTICHANNEL = 6; { Code for Multichannel Mode } { Channel mode names } VORBIS_MODE: array [0..3] of string = ('Unknown', 'Mono', 'Stereo', 'Multichannel'); type TOggCodecType = (octVorbis, octOpus, octSpeex); { Class TOggVorbis } TOggVorbis = class(TObject) private { Private declarations } FFileSize: Integer; FChannelModeID: Byte; FSampleRate: integer; FBitRateNominal: Word; FSamples: Integer; FID3v2Size: Integer; FTitle: string; FArtist: string; FAlbum: string; FTrack: Word; FDate: string; FGenre: string; FComment: string; FVendor: string; FCodec: String; procedure FResetData; function FGetChannelMode: string; function FGetDuration: Double; function FGetBitRate: Word; function FHasID3v2: Boolean; function FIsValid: Boolean; function FGetRatio: Double; function FGetEncoder: String; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load data } function SaveTag(const FileName: String): Boolean; { Save tag data } function ClearTag(const FileName: String): Boolean; { Clear tag data } property FileSize: Integer read FFileSize; { File size (bytes) } property ChannelModeID: Byte read FChannelModeID; { Channel mode code } property ChannelMode: string read FGetChannelMode; { Channel mode name } property SampleRate: integer read FSampleRate; { Sample rate (hz) } property BitRateNominal: Word read FBitRateNominal; { Nominal bit rate } property Title: string read FTitle write FTitle; { Song title } property Artist: string read FArtist write FArtist; { Artist name } property Album: string read FAlbum write FAlbum; { Album name } property Track: Word read FTrack write FTrack; { Track number } property Date: string read FDate write FDate; { Year } property Genre: string read FGenre write FGenre; { Genre name } property Comment: string read FComment write FComment; { Comment } property Vendor: string read FVendor; { Vendor string } property Duration: Double read FGetDuration; { Duration (seconds) } property BitRate: Word read FGetBitRate; { Average bit rate } property ID3v2: Boolean read FHasID3v2; { True if ID3v2 tag exists } property Valid: Boolean read FIsValid; { True if file valid } property Ratio: Double read FGetRatio; { Compression ratio (%) } property Encoder: String read FGetEncoder; { Encoder string } property Codec: String read FCodec; { Codec string } end; implementation const { Ogg page header ID } OGG_PAGE_ID = 'OggS'; { Vorbis parameter frame ID } VORBIS_PARAMETERS_ID = #1 + 'vorbis'; OPUS_PARAMETERS_ID = 'OpusHead'; SPEEX_PARAMETERS_ID = 'Speex '; { Vorbis tag frame ID } VORBIS_TAG_ID = #3 + 'vorbis'; OPUS_TAG_ID = 'OpusTags'; { Max. number of supported comment fields } VORBIS_FIELD_COUNT = 9; { Names of supported comment fields } VORBIS_FIELD: array [1..VORBIS_FIELD_COUNT] of string = ('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'DATE', 'GENRE', 'COMMENT', 'PERFORMER', 'DESCRIPTION'); { CRC table for checksum calculating } CRC_TABLE: array [0..$FF] of Cardinal = ( $00000000, $04C11DB7, $09823B6E, $0D4326D9, $130476DC, $17C56B6B, $1A864DB2, $1E475005, $2608EDB8, $22C9F00F, $2F8AD6D6, $2B4BCB61, $350C9B64, $31CD86D3, $3C8EA00A, $384FBDBD, $4C11DB70, $48D0C6C7, $4593E01E, $4152FDA9, $5F15ADAC, $5BD4B01B, $569796C2, $52568B75, $6A1936C8, $6ED82B7F, $639B0DA6, $675A1011, $791D4014, $7DDC5DA3, $709F7B7A, $745E66CD, $9823B6E0, $9CE2AB57, $91A18D8E, $95609039, $8B27C03C, $8FE6DD8B, $82A5FB52, $8664E6E5, $BE2B5B58, $BAEA46EF, $B7A96036, $B3687D81, $AD2F2D84, $A9EE3033, $A4AD16EA, $A06C0B5D, $D4326D90, $D0F37027, $DDB056FE, $D9714B49, $C7361B4C, $C3F706FB, $CEB42022, $CA753D95, $F23A8028, $F6FB9D9F, $FBB8BB46, $FF79A6F1, $E13EF6F4, $E5FFEB43, $E8BCCD9A, $EC7DD02D, $34867077, $30476DC0, $3D044B19, $39C556AE, $278206AB, $23431B1C, $2E003DC5, $2AC12072, $128E9DCF, $164F8078, $1B0CA6A1, $1FCDBB16, $018AEB13, $054BF6A4, $0808D07D, $0CC9CDCA, $7897AB07, $7C56B6B0, $71159069, $75D48DDE, $6B93DDDB, $6F52C06C, $6211E6B5, $66D0FB02, $5E9F46BF, $5A5E5B08, $571D7DD1, $53DC6066, $4D9B3063, $495A2DD4, $44190B0D, $40D816BA, $ACA5C697, $A864DB20, $A527FDF9, $A1E6E04E, $BFA1B04B, $BB60ADFC, $B6238B25, $B2E29692, $8AAD2B2F, $8E6C3698, $832F1041, $87EE0DF6, $99A95DF3, $9D684044, $902B669D, $94EA7B2A, $E0B41DE7, $E4750050, $E9362689, $EDF73B3E, $F3B06B3B, $F771768C, $FA325055, $FEF34DE2, $C6BCF05F, $C27DEDE8, $CF3ECB31, $CBFFD686, $D5B88683, $D1799B34, $DC3ABDED, $D8FBA05A, $690CE0EE, $6DCDFD59, $608EDB80, $644FC637, $7A089632, $7EC98B85, $738AAD5C, $774BB0EB, $4F040D56, $4BC510E1, $46863638, $42472B8F, $5C007B8A, $58C1663D, $558240E4, $51435D53, $251D3B9E, $21DC2629, $2C9F00F0, $285E1D47, $36194D42, $32D850F5, $3F9B762C, $3B5A6B9B, $0315D626, $07D4CB91, $0A97ED48, $0E56F0FF, $1011A0FA, $14D0BD4D, $19939B94, $1D528623, $F12F560E, $F5EE4BB9, $F8AD6D60, $FC6C70D7, $E22B20D2, $E6EA3D65, $EBA91BBC, $EF68060B, $D727BBB6, $D3E6A601, $DEA580D8, $DA649D6F, $C423CD6A, $C0E2D0DD, $CDA1F604, $C960EBB3, $BD3E8D7E, $B9FF90C9, $B4BCB610, $B07DABA7, $AE3AFBA2, $AAFBE615, $A7B8C0CC, $A379DD7B, $9B3660C6, $9FF77D71, $92B45BA8, $9675461F, $8832161A, $8CF30BAD, $81B02D74, $857130C3, $5D8A9099, $594B8D2E, $5408ABF7, $50C9B640, $4E8EE645, $4A4FFBF2, $470CDD2B, $43CDC09C, $7B827D21, $7F436096, $7200464F, $76C15BF8, $68860BFD, $6C47164A, $61043093, $65C52D24, $119B4BE9, $155A565E, $18197087, $1CD86D30, $029F3D35, $065E2082, $0B1D065B, $0FDC1BEC, $3793A651, $3352BBE6, $3E119D3F, $3AD08088, $2497D08D, $2056CD3A, $2D15EBE3, $29D4F654, $C5A92679, $C1683BCE, $CC2B1D17, $C8EA00A0, $D6AD50A5, $D26C4D12, $DF2F6BCB, $DBEE767C, $E3A1CBC1, $E760D676, $EA23F0AF, $EEE2ED18, $F0A5BD1D, $F464A0AA, $F9278673, $FDE69BC4, $89B8FD09, $8D79E0BE, $803AC667, $84FBDBD0, $9ABC8BD5, $9E7D9662, $933EB0BB, $97FFAD0C, $AFB010B1, $AB710D06, $A6322BDF, $A2F33668, $BCB4666D, $B8757BDA, $B5365D03, $B1F740B4); type { Ogg page header } OggHeader = packed record ID: array [1..4] of AnsiChar; { Always "OggS" } StreamVersion: Byte; { Stream structure version } TypeFlag: Byte; { Header type flag } AbsolutePosition: Int64; { Absolute granule position } Serial: Integer; { Stream serial number } PageNumber: Integer; { Page sequence number } Checksum: Integer; { Page checksum } Segments: Byte; { Number of page segments } LacingValues: array [1..$FF] of Byte; { Lacing values - segment sizes } end; { Vorbis parameter header } VorbisHeader = packed record ID: array [1..7] of AnsiChar; { Always #1 + "vorbis" } BitstreamVersion: array [1..4] of Byte; { Bitstream version number } ChannelMode: Byte; { Number of channels } SampleRate: Integer; { Sample rate (hz) } BitRateMaximal: Integer; { Bit rate upper limit } BitRateNominal: Integer; { Nominal bit rate } BitRateMinimal: Integer; { Bit rate lower limit } BlockSize: Byte; { Coded size for small and long blocks } StopFlag: Byte; { Always 1 } end; // Opus parameter header TOpusHeader = packed record ID: array [1..8] of AnsiChar; { Always "OpusHead" } BitstreamVersion: Byte; { Bitstream version number } ChannelCount: Byte; { Number of channels } PreSkip: Word; SampleRate: LongWord; { Sample rate (hz) } OutputGain: Word; MappingFamily: Byte; { 0,1,255 } end; // Speex parameter header TSpeexHeader = packed record ID: array [1..8] of AnsiChar; speex_version: array [1..20] of AnsiChar; speex_version_id: Integer; header_size: Integer; rate: Integer; mode: Integer; mode_bitstream_version: Integer; nb_channels: Integer; bitrate: Integer; frame_size: Integer; vbr: Integer; frames_per_packet: Integer; extra_headers: Integer; reserved1: Integer; reserved2: Integer; end; { Vorbis tag data } VorbisTag = record ID: array [1..7] of AnsiChar; { Always #3 + "vorbis" } Fields: Integer; { Number of tag fields } FieldData: array [0..VORBIS_FIELD_COUNT] of string; { Tag field data } end; // Opus tag data TOpusTags = record ID: array [1..8] of AnsiChar; { Always "OpusTags" } Fields: Integer; { Number of tag fields } FieldData: array [0..VORBIS_FIELD_COUNT] of string; { Tag field data } end; { File data } FileInfo = record FPage, SPage, LPage: OggHeader; { First, second and last page } CodecType: TOggCodecType; Parameters: VorbisHeader; { Vorbis parameter header } Tag: VorbisTag; { Vorbis tag data } OpusHeader: TOpusHeader; SpeexHeader: TSpeexHeader; FileSize: Integer; { File size (bytes) } Samples: Integer; { Total number of samples } ID3v2Size: Integer; { ID3v2 tag size (bytes) } SPagePos: Integer; { Position of second Ogg page } TagEndPos: Integer; { Tag end position } end; { ********************* Auxiliary functions & procedures ******************** } function GetID3v2Size(const Source: TFileStreamEx): Integer; type ID3v2Header = record ID: array [1..3] of AnsiChar; Version: Byte; Revision: Byte; Flags: Byte; Size: array [1..4] of Byte; end; var Header: ID3v2Header; begin { Get ID3v2 tag size (if exists) } Result := 0; Source.Seek(0, soFromBeginning); Source.Read(Header, SizeOf(Header)); if Header.ID = 'ID3' then begin Result := Header.Size[1] * $200000 + Header.Size[2] * $4000 + Header.Size[3] * $80 + Header.Size[4] + 10; if Header.Flags and $10 = $10 then Inc(Result, 10); if Result > Source.Size then Result := 0; end; end; { --------------------------------------------------------------------------- } procedure SetTagItem(const Data: string; var Info: FileInfo); var Separator, Index: Integer; FieldID, FieldData: string; begin { Set Vorbis tag item if supported comment field found } Separator := Pos('=', Data); if Separator > 0 then begin FieldID := UpperCase(Copy(Data, 1, Separator - 1)); FieldData := Copy(Data, Separator + 1, Length(Data) - Length(FieldID)); for Index := 1 to VORBIS_FIELD_COUNT do if VORBIS_FIELD[Index] = FieldID then Info.Tag.FieldData[Index] := Trim(FieldData); end else if Info.Tag.FieldData[0] = '' then Info.Tag.FieldData[0] := Data; end; { --------------------------------------------------------------------------- } procedure ReadTag(const Source: TFileStreamEx; var Info: FileInfo); var Index, Size, Position: Integer; Data: array [1..250] of AnsiChar; begin { Read Vorbis tag } Index := 0; repeat FillChar(Data, SizeOf(Data), 0); Source.Read(Size, SizeOf(Size)); Position := Source.Position; if Size > SizeOf(Data) then Source.Read(Data, SizeOf(Data)) else Source.Read(Data, Size); { Set Vorbis tag item } SetTagItem(Trim(Data), Info); Source.Seek(Position + Size, soFromBeginning); if Index = 0 then Source.Read(Info.Tag.Fields, SizeOf(Info.Tag.Fields)); Inc(Index); until Index > Info.Tag.Fields; Info.TagEndPos := Source.Position; end; { --------------------------------------------------------------------------- } function GetSamples(const Source: TFileStreamEx): Integer; var Index, DataIndex, Iterator: Integer; Data: array [0..250] of AnsiChar; Header: OggHeader; begin { Get total number of samples } Result := 0; for Index := 1 to 50 do begin DataIndex := Source.Size - (SizeOf(Data) - 10) * Index - 10; Source.Seek(DataIndex, soFromBeginning); Source.Read(Data, SizeOf(Data)); { Get number of PCM samples from last Ogg packet header } for Iterator := SizeOf(Data) - 10 downto 0 do if Data[Iterator] + Data[Iterator + 1] + Data[Iterator + 2] + Data[Iterator + 3] = OGG_PAGE_ID then begin Source.Seek(DataIndex + Iterator, soFromBeginning); Source.Read(Header, SizeOf(Header)); Result := Header.AbsolutePosition; exit; end; end; end; { --------------------------------------------------------------------------- } function GetInfo(const FileName: String; var Info: FileInfo): Boolean; var SourceFile: TFileStreamEx; OpusTags: TOpusTags; CodecID: array [1..8] of AnsiChar; TagsID: array [1..8] of AnsiChar; begin { Get info from file } Result := false; SourceFile := nil; try SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); Info.FileSize := SourceFile.Size; Info.ID3v2Size := GetID3v2Size(SourceFile); SourceFile.Seek(Info.ID3v2Size, soFromBeginning); SourceFile.Read(Info.FPage, SizeOf(Info.FPage)); if Info.FPage.ID <> OGG_PAGE_ID then exit; // Read the codec ID signature SourceFile.Seek(Info.ID3v2Size + Info.FPage.Segments + 27, soFromBeginning); SourceFile.Read(CodecID, SizeOf(CodecID)); // Check codec if Copy(CodecID, 1, 7) = VORBIS_PARAMETERS_ID then Info.CodecType:= octVorbis else if CodecID = OPUS_PARAMETERS_ID then Info.CodecType:= octOpus else if CodecID = SPEEX_PARAMETERS_ID then Info.CodecType:= octSpeex else Exit; // Back to header start position SourceFile.Seek(Info.ID3v2Size + Info.FPage.Segments + 27, soFromBeginning); case Info.CodecType of octVorbis: { Read Vorbis parameter header } SourceFile.Read(Info.Parameters, SizeOf(Info.Parameters)); octOpus: SourceFile.Read(Info.OpusHeader, SizeOf(TOpusHeader)); octSpeex: SourceFile.Read(Info.SpeexHeader, SizeOf(TSpeexHeader)); end; Info.SPagePos := SourceFile.Position; SourceFile.Read(Info.SPage, SizeOf(Info.SPage)); SourceFile.Seek(Info.SPagePos + Info.SPage.Segments + 27, soFromBeginning); SourceFile.Read(TagsID, SizeOf(TagsID)); if not (((Info.CodecType = octVorbis) and (Copy(TagsID, 1, 7) = VORBIS_TAG_ID)) or ((Info.CodecType = octOpus) and (TagsID = OPUS_TAG_ID)) or (Info.CodecType = octSpeex)) then Exit; // Back to tags start position SourceFile.Seek(Info.SPagePos + Info.SPage.Segments + 27, soFromBeginning); // Speex tags block has no header, so in case of it we not read anything case Info.CodecType of octVorbis: { Read Vorbis parameter header } SourceFile.Read(Info.Tag.ID, SizeOf(Info.Tag.ID)); octOpus: SourceFile.Read(OpusTags.ID, SizeOf(OpusTags.ID)); end; { Read Vorbis, Opus or Speex tags } ReadTag(SourceFile, Info); { Get total number of samples } Info.Samples := GetSamples(SourceFile); Result := true; finally SourceFile.Free; end; end; { --------------------------------------------------------------------------- } function GetTrack(const TrackString: string): Byte; var Index, Value, Code: Integer; begin { Extract track from string } Index := Pos('/', TrackString); if Index = 0 then Val(TrackString, Value, Code) else Val(Copy(TrackString, 1, Index), Value, Code); if Code = 0 then Result := Value else Result := 0; end; { --------------------------------------------------------------------------- } function BuildTag(const Info: FileInfo): TStringStream; var Index, Fields, Size: Integer; FieldData: string; begin { Build Vorbis tag } Result := TStringStream.Create(''); Fields := 0; for Index := 1 to VORBIS_FIELD_COUNT do if Info.Tag.FieldData[Index] <> '' then Inc(Fields); { Write frame ID, vendor info and number of fields } Result.Write(Info.Tag.ID, SizeOf(Info.Tag.ID)); Size := Length(Info.Tag.FieldData[0]); Result.Write(Size, SizeOf(Size)); Result.WriteString(Info.Tag.FieldData[0]); Result.Write(Fields, SizeOf(Fields)); { Write tag fields } for Index := 1 to VORBIS_FIELD_COUNT do if Info.Tag.FieldData[Index] <> '' then begin FieldData := VORBIS_FIELD[Index] + '=' + Info.Tag.FieldData[Index]; Size := Length(FieldData); Result.Write(Size, SizeOf(Size)); Result.WriteString(FieldData); end; end; { --------------------------------------------------------------------------- } procedure SetLacingValues(var Info: FileInfo; const NewTagSize: Integer); var Index, Position, Value: Integer; Buffer: array [1..$FF] of Byte; begin { Set new lacing values for the second Ogg page } Position := 1; Value := 0; for Index := Info.SPage.Segments downto 1 do begin if Info.SPage.LacingValues[Index] < $FF then begin Position := Index; Value := 0; end; Inc(Value, Info.SPage.LacingValues[Index]); end; Value := Value + NewTagSize - (Info.TagEndPos - Info.SPagePos - Info.SPage.Segments - 27); { Change lacing values at the beginning } for Index := 1 to Value div $FF do Buffer[Index] := $FF; Buffer[(Value div $FF) + 1] := Value mod $FF; if Position < Info.SPage.Segments then for Index := Position + 1 to Info.SPage.Segments do Buffer[Index - Position + (Value div $FF) + 1] := Info.SPage.LacingValues[Index]; Info.SPage.Segments := Info.SPage.Segments - Position + (Value div $FF) + 1; for Index := 1 to Info.SPage.Segments do Info.SPage.LacingValues[Index] := Buffer[Index]; end; { --------------------------------------------------------------------------- } procedure CalculateCRC(var CRC: Cardinal; const Data; Size: Cardinal); var Buffer: ^Byte; Index: Cardinal; begin { Calculate CRC through data } Buffer := Addr(Data); for Index := 1 to Size do begin CRC := (CRC shl 8) xor CRC_TABLE[((CRC shr 24) and $FF) xor Buffer^]; Inc(Buffer); end; end; { --------------------------------------------------------------------------- } procedure SetCRC(const Destination: TFileStreamEx; Info: FileInfo); var Index: Integer; Value: Cardinal; Data: array [1..$FF] of Byte; begin { Calculate and set checksum for Vorbis tag } Value := 0; CalculateCRC(Value, Info.SPage, Info.SPage.Segments + 27); Destination.Seek(Info.SPagePos + Info.SPage.Segments + 27, soFromBeginning); for Index := 1 to Info.SPage.Segments do if Info.SPage.LacingValues[Index] > 0 then begin Destination.Read(Data, Info.SPage.LacingValues[Index]); CalculateCRC(Value, Data, Info.SPage.LacingValues[Index]); end; Destination.Seek(Info.SPagePos + 22, soFromBeginning); Destination.Write(Value, SizeOf(Value)); end; { --------------------------------------------------------------------------- } function RebuildFile(FileName: String; Tag: TStream; Info: FileInfo): Boolean; var Source, Destination: TFileStreamEx; BufferName: String; begin { Rebuild the file with the new Vorbis tag } Result := false; if (not mbFileExists(FileName)) or (mbFileSetReadOnly(FileName, False) <> True) then exit; try { Create file streams } BufferName := FileName + '~'; Source := TFileStreamEx.Create(FileName, fmOpenRead); Destination := TFileStreamEx.Create(BufferName, fmCreate); { Copy data blocks } Destination.CopyFrom(Source, Info.SPagePos); Destination.Write(Info.SPage, Info.SPage.Segments + 27); Destination.CopyFrom(Tag, 0); Source.Seek(Info.TagEndPos, soFromBeginning); Destination.CopyFrom(Source, Source.Size - Info.TagEndPos); SetCRC(Destination, Info); Source.Free; Destination.Free; { Replace old file and delete temporary file } if (mbDeleteFile(FileName)) and (mbRenameFile(BufferName, FileName)) then Result := true else raise Exception.Create(''); except { Access error } if mbFileExists(BufferName) then mbDeleteFile(BufferName); end; end; { ********************** Private functions & procedures ********************* } procedure TOggVorbis.FResetData; begin { Reset variables } FFileSize := 0; FChannelModeID := 0; FSampleRate := 0; FBitRateNominal := 0; FSamples := 0; FID3v2Size := 0; FTitle := ''; FArtist := ''; FAlbum := ''; FTrack := 0; FDate := ''; FGenre := ''; FComment := ''; FVendor := ''; FCodec := ''; end; { --------------------------------------------------------------------------- } function TOggVorbis.FGetChannelMode: string; begin if FChannelModeID > 2 then Result := VORBIS_MODE[3] else Result := VORBIS_MODE[FChannelModeID]; end; { --------------------------------------------------------------------------- } function TOggVorbis.FGetDuration: Double; begin { Calculate duration time } if FSamples > 0 then if FSampleRate > 0 then Result := FSamples / FSampleRate else Result := 0 else if (FBitRateNominal > 0) and (FChannelModeID > 0) then Result := (FFileSize - FID3v2Size) / FBitRateNominal / FChannelModeID / 125 * 2 else Result := 0; end; { --------------------------------------------------------------------------- } function TOggVorbis.FGetBitRate: Word; begin { Calculate average bit rate } Result := 0; if FGetDuration > 0 then Result := Round((FFileSize - FID3v2Size) / FGetDuration / 125); end; { --------------------------------------------------------------------------- } function TOggVorbis.FHasID3v2: Boolean; begin { Check for ID3v2 tag } Result := FID3v2Size > 0; end; { --------------------------------------------------------------------------- } function TOggVorbis.FIsValid: Boolean; begin { Check for file correctness } Result := (FChannelModeID in [VORBIS_CM_MONO, VORBIS_CM_STEREO, VORBIS_CM_MULTICHANNEL]) and (FSampleRate > 0) and (FGetDuration > 0.1) and (FGetBitRate > 0); end; { ********************** Public functions & procedures ********************** } constructor TOggVorbis.Create; begin { Object constructor } FResetData; inherited; end; { --------------------------------------------------------------------------- } destructor TOggVorbis.Destroy; begin { Object destructor } inherited; end; { --------------------------------------------------------------------------- } function TOggVorbis.ReadFromFile(const FileName: String): Boolean; var Info: FileInfo; begin { Read data from file } Result := false; FResetData; FillChar(Info, SizeOf(Info), 0); if GetInfo(FileName, Info) then begin { Fill variables } FFileSize := Info.FileSize; case Info.CodecType of octVorbis: begin FChannelModeID := Info.Parameters.ChannelMode; FSampleRate := Info.Parameters.SampleRate; FBitRateNominal := Info.Parameters.BitRateNominal div 1000; FCodec:='Vorbis'; end; octOpus: begin FChannelModeID := Info.OpusHeader.ChannelCount; FSampleRate := Info.OpusHeader.SampleRate; FCodec:='Opus'; end; octSpeex: begin FChannelModeID := Info.SpeexHeader.nb_channels; FSampleRate := Info.SpeexHeader.rate; FCodec:='Speex'; end; end; FSamples := Info.Samples; FID3v2Size := Info.ID3v2Size; FTitle := Info.Tag.FieldData[1]; if Info.Tag.FieldData[2] <> '' then FArtist := Info.Tag.FieldData[2] else FArtist := Info.Tag.FieldData[8]; FAlbum := Info.Tag.FieldData[3]; FTrack := GetTrack(Info.Tag.FieldData[4]); FDate := Info.Tag.FieldData[5]; FGenre := Info.Tag.FieldData[6]; if Info.Tag.FieldData[7] <> '' then FComment := Info.Tag.FieldData[7] else FComment := Info.Tag.FieldData[9]; FVendor := Info.Tag.FieldData[0]; Result := true; end; end; { --------------------------------------------------------------------------- } function TOggVorbis.SaveTag(const FileName: String): Boolean; var Info: FileInfo; Tag: TStringStream; begin { Save Vorbis tag } Result := false; FillChar(Info, SizeOf(Info), 0); if GetInfo(FileName, Info) then begin { Prepare tag data and save to file } Info.Tag.FieldData[1] := Trim(FTitle); Info.Tag.FieldData[2] := Trim(FArtist); Info.Tag.FieldData[3] := Trim(FAlbum); if FTrack > 0 then Info.Tag.FieldData[4] := IntToStr(FTrack) else Info.Tag.FieldData[4] := ''; Info.Tag.FieldData[5] := Trim(FDate); Info.Tag.FieldData[6] := Trim(FGenre); Info.Tag.FieldData[7] := Trim(FComment); Info.Tag.FieldData[8] := ''; Info.Tag.FieldData[9] := ''; Tag := BuildTag(Info); Info.SPage.Checksum := 0; SetLacingValues(Info, Tag.Size); Result := RebuildFile(FileName, Tag, Info); Tag.Free; end; end; { --------------------------------------------------------------------------- } function TOggVorbis.ClearTag(const FileName: String): Boolean; begin { Clear Vorbis tag } FTitle := ''; FArtist := ''; FAlbum := ''; FTrack := 0; FDate := ''; FGenre := ''; FComment := ''; Result := SaveTag(FileName); end; { --------------------------------------------------------------------------- } function TOggVorbis.FGetRatio: Double; begin { Get compression ratio } if FIsValid then //Result := FFileSize / (FSamples * FChannelModeID * FBitsPerSample / 8 + 44) * 100 Result := FFileSize / (FSamples * (FChannelModeID * 16 / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } function TOggVorbis.FGetEncoder: String; begin if FVendor = 'Xiphophorus libVorbis I 20000508' then Result := '1.0 beta 1 or beta 2' else if FVendor = 'Xiphophorus libVorbis I 20001031' then Result := '1.0 beta 3' else if FVendor = 'Xiphophorus libVorbis I 20010225' then Result := '1.0 beta 4' else if FVendor = 'Xiphophorus libVorbis I 20010615' then Result := '1.0 rc1' else if FVendor = 'Xiphophorus libVorbis I 20010813' then Result := '1.0 rc2' else if FVendor = 'Xiphophorus libVorbis I 20010816 (gtune 1)' then Result := '1.0 RC2 GT1' else if FVendor = 'Xiphophorus libVorbis I 20011014 (GTune 2)' then Result := '1.0 RC2 GT2' else if FVendor = 'Xiphophorus libVorbis I 20011217' then Result := '1.0 rc3' else if FVendor = 'Xiphophorus libVorbis I 20011231' then Result := '1.0 rc3' //prolly an earlier build of 1.0 //else if FVendor = 'Xiph.Org libVorbis I 20020711' then Result := '1.0' else if FVendor = 'Xiph.Org libVorbis I 20020717' then Result := '1.0' else if FVendor = 'Xiph.Org/Sjeng.Org libVorbis I 20020717 (GTune 3, beta 1)' then Result := '1.0 GT3b1' else if FVendor = 'Xiph.Org libVorbis I 20030308' then Result := 'Post 1.0 CVS' else if FVendor = 'Xiph.Org libVorbis I 20030909 (1.0.1)' then Result := '1.0.1' else if FVendor = 'Xiph.Org libVorbis I 20030909' then Result := '1.0.1' else if FVendor = 'Xiph.Org/Sjeng.Org libVorbis I 20030909 (GTune 3, beta 2) EXPERIMENTAL' then Result := 'Experimental GT3b2' else if FVendor = 'Xiph.Org libVorbis I 20031230 (1.0.1)' then Result := 'Post 1.0.1 CVS' else if FVendor = 'Xiph.Org/Sjeng.Org libVorbis I 20031230 (GTune 3, beta 2)' then Result := 'GT3b2' else if FVendor = 'AO; aoTuV b2 [20040420] (based on Xiph.Org''s 1.0.1)' then Result := '1.0.1 aoTuV beta 2' else if FVendor = 'Xiph.Org libVorbis I 20040629' then Result := '1.1' else if FVendor = 'Xiph.Org libVorbis I 20040920' then Result := '1.1 with impulse_trigger_profile' else if FVendor = 'AO; aoTuV b3 [20041120] (based on Xiph.Org''s libVorbis)' then Result := '1.1 aoTuV beta 3' else Result := FVendor; end; { --------------------------------------------------------------------------- } end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/OptimFROG.pas����������������������������������������0000644�0001750�0000144�00000023741�14743153644�022677� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TOptimFROG - for manipulating with OptimFROG file information } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2003-2005 by Erik Stenborg } { } { Version 1.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.0 (10 July 2003) } { - Support for OptimFROG files via modification of TMonkey class by Jurgen } { - Class TID3v1: reading & writing support for ID3v1 tags } { - Class TID3v2: reading & writing support for ID3v2 tags } { - Class TAPEtag: reading & writing support for APE tags } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit OptimFROG; interface uses Classes, SysUtils, ID3v1, ID3v2, APEtag, DCClassesUtf8; const OFR_COMPRESSION: array [0..9] of String = ('fast', 'normal', 'high', 'extra', 'best', 'ultra', 'insane', 'highnew', 'extranew', 'bestnew'); OFR_BITS: array [0..10] of ShortInt = (8, 8, 16, 16, 24, 24, 32, 32, -32, -32, -32); //negative value corresponds to floating point type. OFR_CHANNELMODE: array [0..1] of String = ('Mono', 'Stereo'); type { Real structure of OptimFROG header } TOfrHeader = packed record ID: array [1..4] of Char; { Always 'OFR ' } Size: Cardinal; Length: Cardinal; HiLength: Word; SampleType, ChannelMode: Byte; SampleRate: Integer; EncoderID: Word; CompressionID: Byte; end; { Class TOptimFrog } TOptimFrog = class(TObject) private { Private declarations } FFileLength: Int64; FHeader: TOfrHeader; FID3v1: TID3v1; FID3v2: TID3v2; FAPEtag: TAPEtag; procedure FResetData; function FGetValid: Boolean; function FGetVersion: string; function FGetCompression: string; function FGetBits: ShortInt; function FGetChannelMode: string; function FGetSamples: Int64; function FGetDuration: Double; function FGetRatio: Double; function FGetSampleRate: Integer; function FGetChannels: Byte; function FGetBitrate: Integer; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; {Load header } property FileLength: Int64 read FFileLength; { File length (bytes) } property Header: TOfrHeader read FHeader; { OptimFROG header } property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data } property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data } property APEtag: TAPEtag read FAPEtag; { APE tag data } property Valid: Boolean read FGetValid; { True if header valid } property Version: string read FGetVersion; { Encoder version } property Compression: string read FGetCompression; { Compression level } property Bits: ShortInt read FGetBits; { Bits per sample } property ChannelMode: string read FGetChannelMode; { Channel mode } property Samples: Int64 read FGetSamples; { Number of samples } property Duration: Double read FGetDuration; { Duration (seconds) } property SampleRate: Integer read FGetSampleRate; { Sample rate (Hz) } property Ratio: Double read FGetRatio; { Compression ratio (%) } property Channels: Byte read FGetChannels; property Bitrate: Integer read FGetBitrate; end; implementation { ********************** Private functions & procedures ********************* } procedure TOptimFrog.FResetData; begin { Reset data } FFileLength := 0; FillChar(FHeader, SizeOf(FHeader), 0); FID3v1.ResetData; FID3v2.ResetData; FAPEtag.ResetData; end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetValid: Boolean; begin Result := (FHeader.ID = 'OFR ') and (FHeader.SampleRate > 0) and (FHeader.SampleType in [0..10]) and (FHeader.ChannelMode in [0..1]) and (FHeader.CompressionID shr 3 in [0..9]); end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetVersion: string; begin { Get encoder version } Result := Format('%5.3f', [((FHeader.EncoderID shr 4) + 4500) / 1000]); end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetCompression: string; begin { Get compression level } Result := OFR_COMPRESSION[FHeader.CompressionID shr 3] end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetBits: ShortInt; begin { Get number of bits per sample } Result := OFR_BITS[FHeader.SampleType] end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetChannelMode: string; begin { Get channel mode } Result := OFR_CHANNELMODE[FHeader.ChannelMode] end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetSamples: Int64; var Res: array [0..1] of Cardinal absolute Result; begin { Get number of samples } Res[0] := Header.Length shr Header.ChannelMode; Res[1] := Header.HiLength shr Header.ChannelMode; end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetDuration: Double; begin { Get song duration } if FHeader.SampleRate > 0 then Result := FGetSamples / FHeader.SampleRate else Result := 0; end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetSampleRate: Integer; begin Result := Header.SampleRate; end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetRatio: Double; begin { Get compression ratio } if FGetValid then Result := FFileLength / (FGetSamples * ((FHeader.ChannelMode+1) * Abs(FGetBits) / 8) + 44) * 100 else Result := 0; end; { ********************** Public functions & procedures ********************** } constructor TOptimFrog.Create; begin { Create object } inherited; FID3v1 := TID3v1.Create; FID3v2 := TID3v2.Create; FAPEtag := TAPEtag.Create; FResetData; end; { --------------------------------------------------------------------------- } destructor TOptimFrog.Destroy; begin { Destroy object } FID3v1.Free; FID3v2.Free; FAPEtag.Free; inherited; end; { --------------------------------------------------------------------------- } function TOptimFrog.ReadFromFile(const FileName: String): Boolean; var SourceFile: TFileStreamEx; begin Result := False; SourceFile := nil; try { Reset data and search for file tag } FResetData; FID3v1.ReadFromFile(FileName); FID3v2.ReadFromFile(FileName); FAPEtag.ReadFromFile(FileName); { Set read-access, open file and get file length } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); FFileLength := SourceFile.Size; { Read header data } SourceFile.Seek(ID3v2.Size, soFromBeginning); SourceFile.Read(FHeader, SizeOf(FHeader)); if FHeader.ID = 'OFR ' then Result := True; finally SourceFile.Free; end; end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetChannels: Byte; begin Result := Header.ChannelMode + 1; end; { --------------------------------------------------------------------------- } function TOptimFrog.FGetBitrate: Integer; begin Result := Round(FFileLength * 8.0 / (FGetSamples / FHeader.SampleRate * 1000)); end; { --------------------------------------------------------------------------- } end. �������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/README.txt�������������������������������������������0000644�0001750�0000144�00000035330�14743153644�022117� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Programming tools for Borland Delphi 3, 4, 5, 6, 7, 2005 } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 2.3 (27 May 2005) } { } { The pack includes several components described below: } { } { AAC - for manipulating with AAC file information } { AC3 - for manipulating with AC3 file information } { APE Tag - for manipulating with APE Tags } { CDDA Track - for getting information for CDDA track } { DTS - for manipulating with DTS file information } { FLAC - for manipulating with FLAC file information } { fpl - reads foobar2000 playlist files (*.fpl) } { ID3v1 - for manipulating with ID3v1 tags } { ID3v2 - for manipulating with ID3v2 tags } { Monkey - for manipulating with Monkey's Audio file information } { MPEG Audio - for manipulating with MPEG audio file information } { Musepack - for manipulating with Musepack file information } { Ogg Vorbis - for manipulating with Ogg Vorbis file information } { OptimFROG - for manipulating with OptimFROG file information } { Speex - for manipulating with Speex file information } { TTA - for manipulating with TTA file information } { TwinVQ - for extracting information from TwinVQ file header } { Vorbis Comment - for manipulating with Vorbis Comments } { WAV - for manipulating with WAV files } { WavPack - for manipulating with WAVPack Files } { WMA - for extracting information from WMA file header } { } { To compile, you need to have these components installed: } { - JEDI VCL 3.00 } { http://jvcl.sourceforge.net } { - TntWare Delphi Unicode Controls } { http://www.tntware.com/delphicontrols/unicode/ } { } { You are welcome to send bug reports, comments and suggestions. } { Spoken languages: English, German. } { } { 27.05.2005 - version 2.3 } { - unicode file access support } { } { 13.01.2005 - version 2.2 } { - added AC3 component } { - added DTS component } { - updated APE Tag unit (writing support for APE 2.0 tags) } { } { 31.12.2004 - version 2.1 } { - added TTA component } { - added Speex component } { - updated WavPack component } { - added support for Lyrics3 v2.00 Tags to the ID3v1 component } { - updated FLAC component } { - updated WAV component } { - updated MPEG Audio component } { - some other updates/fixes to some components } { } { 14.06.2004 - version 2.0 } { - added OptimFROG component } { - added WavPack component } { - added Vorbis Comment component } { - added fpl component } { - many changes/updates/fixes } { - ATL is now released under the GNU LGPL license } { } { 04.11.2002 } { - TCDAtrack: first release } { - TMPEGaudio: ability to recognize QDesign MPEG audio encoder } { - TMPEGaudio: fixed bug with MPEG Layer II } { - TMPEGaudio: fixed bug with very big files } { } { 02.10.2002 } { - TAACfile: first release } { - TID3v2: added property TrackString } { - TOggVorbis: writing support for Vorbis tag } { - TOggVorbis: changed several properties } { - TOggVorbis: fixed bug with long Vorbis tag fields } { } { 13.08.2002 } { - TFLACfile: first release } { - TTwinVQ: Added property Album } { - TTwinVQ: Support for Twin VQ 2.0 } { } { 29.07.2002 } { - TMonkey: correction for calculating of duration } { - TID3v2: reading support for Unicode } { - TID3v2: removed limitation for the track number } { } { 23.05.2002 } { - TMPEGaudio: improved reading performance (up to 50% faster) } { - TID3v2: support for padding } { } { 29.04.2002 } { - TWMAfile: first release } { } { 21.04.2002 } { - TAPEtag: first release } { } { 24.03.2002 } { - TID3v2: reading support for ID3v2.2.x & ID3v2.4.x tags } { } { 18.02.2002 } { - TOggVorbis: added property BitRateNominal } { - TOggVorbis: fixed bug with tag fields } { } { 16.02.2002 } { - TID3v2: fixed bug with property Comment } { - TID3v2: added info: composer, encoder, copyright, language, link } { } { 08.02.2002 } { - TMPEGplus: fixed bug with property Corrupted } { } { 14.01.2002 } { - TWAVfile: fixed bug with calculating of duration } { - TWAVfile: some class properties added/changed } { } { 21.10.2001 } { - TOggVorbis: support for UTF-8 } { - TOggVorbis: fixed bug with vendor info detection } { } { 17.10.2001 } { - TID3v2: writing support for ID3v2.3.x tags } { - TID3v2: fixed bug with track number detection } { - TID3v2: fixed bug with tag reading } { } { 09.10.2001 } { - TWAVfile: fixed bug with WAV header detection } { } { 11.09.2001 } { - TMPEGaudio: improved encoder guessing for CBR files } { - TMonkey: added property Samples } { - TMonkey: removed WAV header information } { } { 07.09.2001 } { - TMonkey: first release } { } { 31.08.2001 } { - TMPEGaudio: first release } { - TID3v2: added public procedure ResetData } { } { 15.08.2001 } { - TOggVorbis: first release } { } { 14.08.2001 } { - TID3v2: first release } { } { 06.08.2001 } { - TTwinVQ: first release } { } { 02.08.2001 } { - TMPEGplus: some class properties added/changed } { } { 31.07.2001 } { - TWAVfile: first release } { } { 26.07.2001 } { - TMPEGplus: fixed reading problem with "read only" files } { } { 25.07.2001 } { - TID3v1: first release } { } { 23.05.2001 } { - TMPEGplus: first release } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** }��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/TTA.pas����������������������������������������������0000644�0001750�0000144�00000016112�14743153644�021553� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TTTA - for manipulating with TTA Files } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2004-2005 by Gambit } { } { Version 1.1 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.0 (12 August 2004) } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit TTA; interface uses Classes, SysUtils, ID3v1, ID3v2, APEtag, DCClassesUtf8; type tta_header = packed record //TTAid: array[0..3] of Char; AudioFormat: Word; NumChannels: Word; BitsPerSample: Word; SampleRate: Longword; DataLength: Longword; CRC32: Longword; end; { Class TTTA } TTTA = class(TObject) private { Private declarations } FFileSize: Int64; FValid: Boolean; FAudioFormat: Cardinal; FChannels: Cardinal; FBits: Cardinal; FSampleRate: Cardinal; FSamples: Cardinal; FCRC32: Cardinal; FBitrate: Double; FDuration: Double; FID3v1: TID3v1; FID3v2: TID3v2; FAPEtag: TAPEtag; function FGetRatio: Double; procedure FResetData; public { Public declarations } constructor Create; { Create object } destructor Destroy; override; { Destroy object } function ReadFromFile(const FileName: String): Boolean; { Load header } property FileSize: Int64 read FFileSize; property Valid: Boolean read FValid; property AudioFormat: Cardinal read FAudioFormat; property Channels: Cardinal read FChannels; property Bits: Cardinal read FBits; property SampleRate: Cardinal read FSampleRate; property Samples: Cardinal read FSamples; { Number of samples } property CRC32: Cardinal read FCRC32; property Bitrate: Double read FBitrate; property Duration: Double read FDuration; property Ratio: Double read FGetRatio; { Compression ratio (%) } property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data } property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data } property APEtag: TAPEtag read FAPEtag; { APE tag data } end; implementation { ********************** Private functions & procedures ********************* } procedure TTTA.FResetData; begin { Reset all data } FFileSize := 0; FValid := False; FAudioFormat := 0; FChannels := 0; FBits := 0; FSampleRate := 0; FSamples := 0; FCRC32 := 0; FBitrate := 0; FDuration := 0; FID3v1.ResetData; FID3v2.ResetData; FAPEtag.ResetData; end; { ********************** Public functions & procedures ********************** } constructor TTTA.Create; begin { Create object } inherited; FID3v1 := TID3v1.Create; FID3v2 := TID3v2.Create; FAPEtag := TAPEtag.Create; FResetData; end; (* -------------------------------------------------------------------------- *) destructor TTTA.Destroy; begin FID3v1.Free; FID3v2.Free; FAPEtag.Free; inherited; end; (* -------------------------------------------------------------------------- *) function TTTA.ReadFromFile(const FileName: String): Boolean; var f: TFileStreamEx; SignatureChunk: array[0..3] of Char; ttaheader: tta_header; TagSize: Int64; begin Result := False; FResetData; // load tags first FID3v2.ReadFromFile(FileName); FID3v1.ReadFromFile(FileName); FAPEtag.ReadFromFile(FileName); // calulate total tag size TagSize := 0; if FID3v1.Exists then inc(TagSize,128); if FID3v2.Exists then inc(TagSize, FID3v2.Size); if FAPEtag.Exists then inc(TagSize, FAPETag.Size); // begin reading data from file f:=nil; try f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite); // seek past id3v2-tag if FID3v2.Exists then begin f.Seek(FID3v2.Size, soFromBeginning); end; if (f.Read(SignatureChunk, SizeOf(SignatureChunk)) = SizeOf(SignatureChunk)) and (StrLComp(SignatureChunk,'TTA1',4) = 0) then begin // start looking for chunks FillChar(ttaheader, SizeOf(ttaheader),0); f.Read(ttaheader, SizeOf(ttaheader)); FFileSize := f.Size; FValid := TRUE; FAudioFormat := ttaheader.AudioFormat; FChannels := ttaheader.NumChannels; FBits := ttaheader.BitsPerSample; FSampleRate := ttaheader.SampleRate; FSamples := ttaheader.DataLength; FCRC32 := ttaheader.CRC32; FBitrate := FFileSize * 8 / (FSamples / FSampleRate) / 1000; FDuration := ttaheader.DataLength / ttaheader.SampleRate; Result := True; end; finally f.free; end; end; (* -------------------------------------------------------------------------- *) function TTTA.FGetRatio: Double; begin { Get compression ratio } if FValid then Result := FFileSize / (FSamples * (FChannels * FBits / 8) + 44) * 100 else Result := 0; end; (* -------------------------------------------------------------------------- *) end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/TwinVQ.pas�������������������������������������������0000644�0001750�0000144�00000031362�14743153644�022317� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TTwinVQ - for extracting information from TwinVQ file header } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.3 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.2 (April 2004) by Gambit } { - Added Ratio property } { } { Version 1.1 (13 August 2002) } { - Added property Album } { - Support for Twin VQ 2.0 } { } { Version 1.0 (6 August 2001) } { - File info: channel mode, bit rate, sample rate, file size, duration } { - Tag info: title, comment, author, copyright, compressed file name } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit TwinVQ; interface uses Classes, SysUtils, DCClassesUtf8; const { Used with ChannelModeID property } TWIN_CM_MONO = 1; { Index for mono mode } TWIN_CM_STEREO = 2; { Index for stereo mode } { Channel mode names } TWIN_MODE: array [0..2] of string = ('Unknown', 'Mono', 'Stereo'); type { Class TTwinVQ } TTwinVQ = class(TObject) private { Private declarations } FValid: Boolean; FChannelModeID: Byte; FBitRate: Byte; FSampleRate: Word; FFileSize: Cardinal; FDuration: Double; FTitle: string; FComment: string; FAuthor: string; FCopyright: string; FOriginalFile: string; FAlbum: string; procedure FResetData; function FGetChannelMode: string; function FIsCorrupted: Boolean; function FGetRatio: Double; public { Public declarations } constructor Create; { Create object } function ReadFromFile(const FileName: String): Boolean; { Load header } property Valid: Boolean read FValid; { True if header valid } property ChannelModeID: Byte read FChannelModeID; { Channel mode code } property ChannelMode: string read FGetChannelMode; { Channel mode name } property BitRate: Byte read FBitRate; { Total bit rate } property SampleRate: Word read FSampleRate; { Sample rate (hz) } property FileSize: Cardinal read FFileSize; { File size (bytes) } property Duration: Double read FDuration; { Duration (seconds) } property Title: string read FTitle; { Title name } property Comment: string read FComment; { Comment } property Author: string read FAuthor; { Author name } property Copyright: string read FCopyright; { Copyright } property OriginalFile: string read FOriginalFile; { Original file name } property Album: string read FAlbum; { Album title } property Corrupted: Boolean read FIsCorrupted; { True if file corrupted } property Ratio: Double read FGetRatio; { Compression ratio (%) } end; implementation const { Twin VQ header ID } TWIN_ID = 'TWIN'; { Max. number of supported tag-chunks } TWIN_CHUNK_COUNT = 6; { Names of supported tag-chunks } TWIN_CHUNK: array [1..TWIN_CHUNK_COUNT] of string = ('NAME', 'COMT', 'AUTH', '(c) ', 'FILE', 'ALBM'); type { TwinVQ chunk header } ChunkHeader = record ID: array [1..4] of Char; { Chunk ID } Size: Cardinal; { Chunk size } end; { File header data - for internal use } HeaderInfo = record { Real structure of TwinVQ file header } ID: array [1..4] of Char; { Always "TWIN" } Version: array [1..8] of Char; { Version ID } Size: Cardinal; { Header size } Common: ChunkHeader; { Common chunk header } ChannelMode: Cardinal; { Channel mode: 0 - mono, 1 - stereo } BitRate: Cardinal; { Total bit rate } SampleRate: Cardinal; { Sample rate (khz) } SecurityLevel: Cardinal; { Always 0 } { Extended data } FileSize: Cardinal; { File size (bytes) } Tag: array [1..TWIN_CHUNK_COUNT] of string; { Tag information } end; { ********************* Auxiliary functions & procedures ******************** } function ReadHeader(const FileName: String; var Header: HeaderInfo): Boolean; var SourceFile: TFileStreamEx; Transferred: Integer; begin try Result := true; { Set read-access and open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); { Read header and get file size } Transferred := SourceFile.Read(Header, 40); Header.FileSize := SourceFile.Size; SourceFile.Free; { if transfer is not complete } if Transferred < 40 then Result := false; except { Error } Result := false; end; end; { --------------------------------------------------------------------------- } function GetChannelModeID(const Header: HeaderInfo): Byte; begin { Get channel mode from header } case Swap(Header.ChannelMode shr 16) of 0: Result := TWIN_CM_MONO; 1: Result := TWIN_CM_STEREO else Result := 0; end; end; { --------------------------------------------------------------------------- } function GetBitRate(const Header: HeaderInfo): Byte; begin { Get bit rate from header } Result := Swap(Header.BitRate shr 16); end; { --------------------------------------------------------------------------- } function GetSampleRate(const Header: HeaderInfo): Word; begin { Get real sample rate from header } Result := Swap(Header.SampleRate shr 16); case Result of 11: Result := 11025; 22: Result := 22050; 44: Result := 44100; else Result := Result * 1000; end; end; { --------------------------------------------------------------------------- } function GetDuration(const Header: HeaderInfo): Double; begin { Get duration from header } Result := Abs((Header.FileSize - Swap(Header.Size shr 16) - 20)) / 125 / Swap(Header.BitRate shr 16); end; { --------------------------------------------------------------------------- } function HeaderEndReached(const Chunk: ChunkHeader): Boolean; begin { Check for header end } Result := (Ord(Chunk.ID[1]) < 32) or (Ord(Chunk.ID[2]) < 32) or (Ord(Chunk.ID[3]) < 32) or (Ord(Chunk.ID[4]) < 32) or (Chunk.ID = 'DATA'); end; { --------------------------------------------------------------------------- } procedure SetTagItem(const ID, Data: string; var Header: HeaderInfo); var Iterator: Byte; begin { Set tag item if supported tag-chunk found } for Iterator := 1 to TWIN_CHUNK_COUNT do if TWIN_CHUNK[Iterator] = ID then Header.Tag[Iterator] := Data; end; { --------------------------------------------------------------------------- } procedure ReadTag(const FileName: String; var Header: HeaderInfo); var SourceFile: TFileStreamEx; Chunk: ChunkHeader; Data: array [1..250] of Char; begin try { Set read-access, open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); SourceFile.Seek(16, soFromBeginning); repeat begin FillChar(Data, SizeOf(Data), 0); { Read chunk header } SourceFile.Read(Chunk, 8); { Read chunk data and set tag item if chunk header valid } if HeaderEndReached(Chunk) then break; SourceFile.Read(Data, Swap(Chunk.Size shr 16) mod SizeOf(Data)); SetTagItem(Chunk.ID, Data, Header); end; until SourceFile.Position >= SourceFile.Size; SourceFile.Free; except end; end; { ********************** Private functions & procedures ********************* } procedure TTwinVQ.FResetData; begin FValid := false; FChannelModeID := 0; FBitRate := 0; FSampleRate := 0; FFileSize := 0; FDuration := 0; FTitle := ''; FComment := ''; FAuthor := ''; FCopyright := ''; FOriginalFile := ''; FAlbum := ''; end; { --------------------------------------------------------------------------- } function TTwinVQ.FGetChannelMode: string; begin Result := TWIN_MODE[FChannelModeID]; end; { --------------------------------------------------------------------------- } function TTwinVQ.FIsCorrupted: Boolean; begin { Check for file corruption } Result := (FValid) and ((FChannelModeID = 0) or (FBitRate < 8) or (FBitRate > 192) or (FSampleRate < 8000) or (FSampleRate > 44100) or (FDuration < 0.1) or (FDuration > 10000)); end; { ********************** Public functions & procedures ********************** } constructor TTwinVQ.Create; begin inherited; FResetData; end; { --------------------------------------------------------------------------- } function TTwinVQ.ReadFromFile(const FileName: String): Boolean; var Header: HeaderInfo; begin { Reset data and load header from file to variable } FResetData; Result := ReadHeader(FileName, Header); { Process data if loaded and header valid } if (Result) and (Header.ID = TWIN_ID) then begin FValid := true; { Fill properties with header data } FChannelModeID := GetChannelModeID(Header); FBitRate := GetBitRate(Header); FSampleRate := GetSampleRate(Header); FFileSize := Header.FileSize; FDuration := GetDuration(Header); { Get tag information and fill properties } ReadTag(FileName, Header); FTitle := Trim(Header.Tag[1]); FComment := Trim(Header.Tag[2]); FAuthor := Trim(Header.Tag[3]); FCopyright := Trim(Header.Tag[4]); FOriginalFile := Trim(Header.Tag[5]); FAlbum := Trim(Header.Tag[6]); end; end; { --------------------------------------------------------------------------- } function TTwinVQ.FGetRatio: Double; begin { Get compression ratio } if FValid then Result := FFileSize / ((FDuration * FSampleRate) * (FChannelModeID * 16 / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/WAVPackfile.pas��������������������������������������0000644�0001750�0000144�00000033734�14743153644�023230� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TWAVPackFile - for manipulating with WAVPack Files } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2003-2005 by Mattias Dahlberg } { } { Version 1.2 (09 August 2004) by jtclipper } { - updated to support WavPack version 4 files } { - added encoder detection } { } { Version 1.1 (April 2004) by Gambit } { - Added Ratio and Samples property } { } { Version 1.0 (August 2003) } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit WAVPackfile; interface uses Classes, SysUtils, APEtag, DCClassesUtf8; type TWAVPackfile = class(TObject) private FFileSize: int64; FValid: boolean; FFormatTag: integer; FVersion: integer; FChannels: integer; FSampleRate: integer; FBits: integer; FBitrate: double; FDuration: double; FEncoder: string; FAPEtag : TAPEtag; FTagSize: integer; FSamples: Int64; FBSamples: Int64; procedure FResetData; function FGetRatio: Double; function FGetChannelMode: string; public constructor Create; destructor Destroy; override; function ReadFromFile(const FileName: String): Boolean; function _ReadV3( f: TFileStreamEx ): boolean; function _ReadV4( f: TFileStreamEx ): boolean; property FileSize: int64 read FFileSize; property Valid: boolean read FValid; property FormatTag: integer read FFormatTag; property Version: integer read FVersion; property Channels: integer read FChannels; property ChannelMode: string read FGetChannelMode; property SampleRate: integer read FSamplerate; property Bits: integer read FBits; property Bitrate: double read FBitrate; property Duration: double read FDuration; property Samples: Int64 read FSamples; property BSamples: Int64 read FBSamples; property Ratio: Double read FGetRatio; property Encoder: string read FEncoder; property APEtag: TAPEtag read FAPEtag; end; implementation type wavpack_header3 = record ckID: array[0..3] of char; ckSize: longword; version: word; bits: word ; flags: word; shift: word; total_samples: longword; crc: longword; crc2: longword; extension: array[0..3] of char; extra_bc: byte; extras: array[0..2] of char; end; wavpack_header4 = record ckID: array[0..3] of char; ckSize: longword; version: word; track_no: byte; index_no: byte; total_samples: longword; block_index: longword; block_samples: longword; flags: longword; crc: longword; end; fmt_chunk = record wformattag: word; wchannels: word; dwsamplespersec: longword; dwavgbytespersec: longword; wblockalign: word; wbitspersample: word; end; riff_chunk = record id: array[0..3] of char; size: longword; end; const //version 3 flags MONO_FLAG_v3 = 1; // not stereo FAST_FLAG_v3 = 2; // non-adaptive predictor and stereo mode // RAW_FLAG_v3 = 4; // raw mode (no .wav header) // CALC_NOISE_v3 = 8; // calc noise in lossy mode (no longer stored) HIGH_FLAG_v3 = $10; // high quality mode (all modes) // BYTES_3_v3 = $20; // files have 3-byte samples // OVER_20_v3 = $40; // samples are over 20 bits WVC_FLAG_v3 = $80; // create/use .wvc (no longer stored) // LOSSY_SHAPE_v3 = $100; // noise shape (lossy mode only) // VERY_FAST_FLAG_v3 = $200; // double fast (no longer stored) NEW_HIGH_FLAG_v3 = $400; // new high quality mode (lossless only) // CANCEL_EXTREME_v3 = $800; // cancel EXTREME_DECORR // CROSS_DECORR_v3 = $1000; // decorrelate chans (with EXTREME_DECORR flag) // NEW_DECORR_FLAG_v3 = $2000; // new high-mode decorrelator // JOINT_STEREO_v3 = $4000; // joint stereo (lossy and high lossless) EXTREME_DECORR_v3 = $8000; // extra decorrelation (+ enables other flags) sample_rates: array[0..14] of integer = ( 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 ); { --------------------------------------------------------------------------- } procedure TWAVPackfile.FResetData; begin FFileSize := 0; FTagSize := 0; FValid := false; FFormatTag := 0; FChannels := 0; FSampleRate := 0; FBits := 0; FBitrate := 0; FDuration := 0; FVersion := 0; FEncoder := ''; FSamples := 0; FBSamples := 0; FAPEtag.ResetData; end; { --------------------------------------------------------------------------- } constructor TWAVPackfile.Create; begin inherited; FAPEtag := TAPEtag.Create; FResetData; end; destructor TWAVPackfile.Destroy; begin FAPEtag.Free; inherited; end; { --------------------------------------------------------------------------- } function TWAVPackfile.FGetChannelMode: string; begin case FChannels of 1: result := 'Mono'; 2: result := 'Stereo'; else result := 'Surround'; end; end; { --------------------------------------------------------------------------- } function TWAVPackfile.ReadFromFile(const FileName: String): Boolean; var f: TFileStreamEx; marker: array[0..3] of char; begin FResetData; FAPEtag.ReadFromFile(FileName); FTagSize := FAPEtag.Size; try f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite); FFileSize := f.Size; //read first bytes FillChar( marker, SizeOf( marker ), 0 ); f.Read( marker, SizeOf( marker) ); f.Seek( 0, soFromBeginning ); if marker = 'RIFF' then begin result := _ReadV3( f ); end else if marker = 'wvpk' then begin result := _ReadV4( f ); end else begin result := False; end; finally FreeAndNil( f ); end; end; { --------------------------------------------------------------------------- } function TWAVPackfile._ReadV4( f: TFileStreamEx ): boolean; var wvh4: wavpack_header4; EncBuf : array[1..4096] of Byte; tempo : Integer; encoderbyte: Byte; begin result := false; FillChar( wvh4, SizeOf(wvh4) ,0); f.Read( wvh4, SizeOf(wvh4) ); if wvh4.ckID = 'wvpk' then // wavpack header found begin Result := true; FValid := true; FVersion := wvh4.version shr 8; FChannels := 2 - (wvh4.flags and 4); // mono flag FBits := ((wvh4.flags and 3) * 16); // bytes stored flag FSamples := wvh4.total_samples; FBSamples := wvh4.block_samples; FSampleRate := (wvh4.flags and ($1F shl 23)) shr 23; if (FSampleRate > 14) or (FSampleRate < 0) then begin FSampleRate := 44100; end else begin FSampleRate := sample_rates[ FSampleRate ]; end; if ((wvh4.flags and 8) = 8) then // hybrid flag begin FEncoder := 'hybrid lossy'; end else begin //if ((wvh4.flags and 2) = 2) then begin // lossless flag FEncoder := 'lossless'; end; { if ((wvh4.flags and $20) > 0) then // MODE_HIGH begin FEncoder := FEncoder + ' (high)'; end else if ((wvh4.flags and $40) > 0) then // MODE_FAST begin FEncoder := FEncoder + ' (fast)'; end; } FDuration := wvh4.total_samples / FSampleRate; if FDuration > 0 then FBitrate := (FFileSize - int64( FTagSize ) ) * 8 / (FSamples / FSampleRate) / 1000; FillChar(EncBuf, SizeOf(EncBuf), 0); f.Read(EncBuf, SizeOf(EncBuf)); for tempo := 1 to 4094 do begin If EncBuf[tempo] = $65 then if EncBuf[tempo + 1] = $02 then begin encoderbyte := EncBuf[tempo + 2]; if encoderbyte = 8 then FEncoder := FEncoder + ' (high)' else if encoderbyte = 0 then FEncoder := FEncoder + ' (normal)' else if encoderbyte = 2 then FEncoder := FEncoder + ' (fast)' else if encoderbyte = 6 then FEncoder := FEncoder + ' (very fast)'; Break; end; end; end; end; { --------------------------------------------------------------------------- } function TWAVPackfile._ReadV3( f: TFileStreamEx ): boolean; var chunk: riff_chunk; wavchunk: array[0..3] of char; fmt: fmt_chunk; hasfmt: boolean; fpos: int64; wvh3: wavpack_header3; begin result := false; hasfmt := false; // read and evaluate header FillChar( chunk, sizeof(chunk), 0 ); if (f.Read(chunk, sizeof(chunk)) <> SizeOf( chunk )) or (f.Read(wavchunk, sizeof(wavchunk)) <> SizeOf(wavchunk)) or (wavchunk <> 'WAVE') then exit; // start looking for chunks FillChar( chunk, SizeOf(chunk), 0 ); while (f.Position < f.Size) do begin if (f.read(chunk, sizeof(chunk)) < sizeof(chunk)) or (chunk.size <= 0) then break; fpos := f.Position; if chunk.id = 'fmt ' then begin // Format chunk found read it if (chunk.size >= sizeof(fmt)) and (f.Read(fmt, sizeof(fmt)) = sizeof(fmt)) then begin hasfmt := true; result := True; FValid := true; FFormatTag := fmt.wformattag; FChannels := fmt.wchannels; FSampleRate := fmt.dwsamplespersec; FBits := fmt.wbitspersample; FBitrate := fmt.dwavgbytespersec / 125.0; // 125 = 1/8*1000 end else begin break; end; end else if (chunk.id = 'data') and hasfmt then begin FillChar( wvh3, SizeOf(wvh3) ,0); f.Read( wvh3, SizeOf(wvh3) ); if wvh3.ckID = 'wvpk' then begin // wavpack header found result := true; FValid := true; FVersion := wvh3.version; FChannels := 2 - (wvh3.flags and 1); // mono flag FSamples := wvh3.total_samples; // Encoder guess if wvh3.bits > 0 then begin if (wvh3.flags and NEW_HIGH_FLAG_v3) > 0 then begin FEncoder := 'hybrid'; if (wvh3.flags and WVC_FLAG_v3) > 0 then begin FEncoder := FEncoder + ' lossless'; end else begin FEncoder := FEncoder + ' lossy'; end; if (wvh3.flags and EXTREME_DECORR_v3) > 0 then FEncoder := FEncoder + ' (high)'; end else if (wvh3.flags and (HIGH_FLAG_v3 or FAST_FLAG_v3)) = 0 then begin FEncoder := IntToStr( wvh3.bits + 3 ) + '-bit lossy'; end else begin FEncoder := IntToStr( wvh3.bits + 3 ) + '-bit lossy'; if (wvh3.flags and HIGH_FLAG_v3) > 0 then begin FEncoder := FEncoder + ' high'; end else begin FEncoder := FEncoder + ' fast'; end end; end else begin if (wvh3.flags and HIGH_FLAG_v3) = 0 then begin FEncoder := 'lossless (fast mode)'; end else if (wvh3.flags and EXTREME_DECORR_v3) > 0 then begin FEncoder := 'lossless (high mode)'; end else begin FEncoder := 'lossless'; end; end; if FSampleRate <= 0 then FSampleRate := 44100; FDuration := wvh3.total_samples / FSampleRate; if FDuration > 0 then FBitrate := 8.0*(FFileSize - int64( FTagSize ) - int64(wvh3.ckSize))/(FDuration*1000.0); end; break; end else begin // not a wv file break; end; f.seek( fpos + chunk.size, soFromBeginning ); end; // while end; { --------------------------------------------------------------------------- } function TWAVPackfile.FGetRatio: Double; begin { Get compression ratio } if FValid then Result := FFileSize / (FSamples * (FChannels * FBits / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } end. ������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/WAVfile.pas������������������������������������������0000644�0001750�0000144�00000041173�14743153644�022425� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TWAVfile - for manipulating with WAV files } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.5 (April 2005) by Gambit } { - updated to unicode file access } { } { Version 1.44 (23 March 2005) by Gambit } { - multichannel support } { } { Version 1.43 (27 August 2004) by Gambit } { - added procedures: TrimFromEnd, TrimFromBeginning and FindSilence } { - removed WriteNewLength procedure (replaced with TrimFromEnd) } { - fixed some FormatSize/HeaderSize/SampleNumber related bugs } { } { Version 1.32 (05 June 2004) by Gambit } { - WriteNewLength now properly truncates the file } { } { Version 1.31 (April 2004) by Gambit } { - Added Ratio property } { } { Version 1.3 (22 February 2004) by Gambit } { - SampleNumber is now read correctly } { - added procedure to change the duration (SampleNumber and FileSize) } { of the wav file (can be used for example to trim off the encoder } { padding from decoded mp3 files) } { } { Version 1.2 (14 January 2002) } { - Fixed bug with calculating of duration } { - Some class properties added/changed } { } { Version 1.1 (9 October 2001) } { - Fixed bug with WAV header detection } { } { Version 1.0 (31 July 2001) } { - Info: channel mode, sample rate, bits per sample, file size, duration } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit WAVfile; interface uses Classes, SysUtils, DCClassesUtf8; const { Format type names } WAV_FORMAT_UNKNOWN = 'Unknown'; WAV_FORMAT_PCM = 'Windows PCM'; WAV_FORMAT_ADPCM = 'Microsoft ADPCM'; WAV_FORMAT_ALAW = 'A-LAW'; WAV_FORMAT_MULAW = 'MU-LAW'; WAV_FORMAT_DVI_IMA_ADPCM = 'DVI/IMA ADPCM'; WAV_FORMAT_MP3 = 'MPEG Layer III'; { Channel mode names } WAV_MODE: array [0..3] of string = ('Unknown', 'Mono', 'Stereo', 'Multichannel'); type { Class TWAVfile } TWAVfile = class(TObject) private { Private declarations } FValid: Boolean; FFormatSize: Cardinal; FFormatID: Word; FChannelNumber: Byte; FSampleRate: Cardinal; FBytesPerSecond: Cardinal; FBlockAlign: Word; FBitsPerSample: Byte; FSampleNumber: Cardinal; FHeaderSize: Cardinal; FFileSize: Cardinal; FFileName: String; FAmountTrimBegin: Cardinal; FAmountTrimEnd: Cardinal; FBitrate: Double; procedure FResetData; function FGetFormat: string; function FGetChannelMode: string; function FGetDuration: Double; function FGetRatio: Double; public { Public declarations } constructor Create; { Create object } function ReadFromFile(const FileName: String): Boolean; { Load header } property Valid: Boolean read FValid; { True if header valid } property FormatSize: Cardinal read FFormatSize; property FormatID: Word read FFormatID; { Format type code } property Format: string read FGetFormat; { Format type name } property ChannelNumber: Byte read FChannelNumber; { Number of channels } property ChannelMode: string read FGetChannelMode; { Channel mode name } property SampleRate: Cardinal read FSampleRate; { Sample rate (hz) } property BytesPerSecond: Cardinal read FBytesPerSecond; { Bytes/second } property BlockAlign: Word read FBlockAlign; { Block alignment } property BitsPerSample: Byte read FBitsPerSample; { Bits/sample } property HeaderSize: Cardinal read FHeaderSize; { Header size (bytes) } property FileSize: Cardinal read FFileSize; { File size (bytes) } property Duration: Double read FGetDuration; { Duration (seconds) } property SampleNumber: Cardinal read FSampleNumber; procedure TrimFromBeginning(const Samples: Cardinal); procedure TrimFromEnd(const Samples: Cardinal); procedure FindSilence(const FromBeginning, FromEnd: Boolean); property Ratio: Double read FGetRatio; { Compression ratio (%) } property AmountTrimBegin: Cardinal read FAmountTrimBegin; property AmountTrimEnd: Cardinal read FAmountTrimEnd; property Bitrate: Double read FBitrate; end; implementation const DATA_CHUNK = 'data'; { Data chunk ID } type { WAV file header data } WAVRecord = record { RIFF file header } RIFFHeader: array [1..4] of Char; { Must be "RIFF" } FileSize: Integer; { Must be "RealFileSize - 8" } WAVEHeader: array [1..4] of Char; { Must be "WAVE" } { Format information } FormatHeader: array [1..4] of Char; { Must be "fmt " } FormatSize: Cardinal; { Format size } FormatID: Word; { Format type code } ChannelNumber: Word; { Number of channels } SampleRate: Integer; { Sample rate (hz) } BytesPerSecond: Integer; { Bytes/second } BlockAlign: Word; { Block alignment } BitsPerSample: Word; { Bits/sample } DataHeader: array [1..4] of Char; { Can be "data" } SampleNumber: Cardinal; { Number of samples (optional) } end; { ********************* Auxiliary functions & procedures ******************** } function ReadWAV(const FileName: String; var WAVData: WAVRecord): Boolean; var SourceFile: TFileStreamEx; begin try Result := true; { Set read-access and open file } SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); { Read header } SourceFile.Read(WAVData, 36); { Read number of samples } if SourceFile.Size > (WAVData.FormatSize + 24) then begin SourceFile.Seek(WAVData.FormatSize + 24, soFromBeginning); SourceFile.Read(WAVData.SampleNumber, 4); end; SourceFile.Free; except { Error } Result := false; end; end; { --------------------------------------------------------------------------- } function HeaderIsValid(const WAVData: WAVRecord): Boolean; begin Result := True; { Header validation } if WAVData.RIFFHeader <> 'RIFF' then Result := False; if WAVData.WAVEHeader <> 'WAVE' then Result := False; if WAVData.FormatHeader <> 'fmt ' then Result := False; if WAVData.ChannelNumber = 0 then Result := False; end; { ********************** Private functions & procedures ********************* } procedure TWAVfile.FResetData; begin { Reset all data } FValid := false; FFormatSize := 0; FFormatID := 0; FChannelNumber := 0; FSampleRate := 0; FBytesPerSecond := 0; FBlockAlign := 0; FBitsPerSample := 0; FSampleNumber := 0; FHeaderSize := 0; FFileSize := 0; FFileName := ''; FAmountTrimBegin := 0; FAmountTrimEnd := 0; FBitrate := 0; end; { --------------------------------------------------------------------------- } function TWAVfile.FGetFormat: string; begin { Get format type name } case FFormatID of 1: Result := WAV_FORMAT_PCM; 2: Result := WAV_FORMAT_ADPCM; 6: Result := WAV_FORMAT_ALAW; 7: Result := WAV_FORMAT_MULAW; 17: Result := WAV_FORMAT_DVI_IMA_ADPCM; 85: Result := WAV_FORMAT_MP3; else Result := ''; end; end; { --------------------------------------------------------------------------- } function TWAVfile.FGetChannelMode: string; begin { Get channel mode name } //multichannel if FChannelNumber > 2 then Result := WAV_MODE[3] else Result := WAV_MODE[FChannelNumber]; end; { --------------------------------------------------------------------------- } function TWAVfile.FGetDuration: Double; begin { Get duration } Result := 0; if FValid then begin if (FSampleNumber = 0) and (FBytesPerSecond > 0) then Result := (FFileSize - FHeaderSize) / FBytesPerSecond; if (FSampleNumber > 0) and (FSampleRate > 0) then Result := FSampleNumber / FSampleRate; end; end; { ********************** Public functions & procedures ********************** } constructor TWAVfile.Create; begin { Create object } inherited; FResetData; end; { --------------------------------------------------------------------------- } function TWAVfile.ReadFromFile(const FileName: String): Boolean; var WAVData: WAVRecord; begin { Reset and load header data from file to variable } FResetData; FillChar(WAVData, SizeOf(WAVData), 0); Result := ReadWAV(FileName, WAVData); { Process data if loaded and header valid } if (Result) and (HeaderIsValid(WAVData)) then begin FValid := true; { Fill properties with header data } FFormatSize := WAVData.FormatSize; FFormatID := WAVData.FormatID; FChannelNumber := WAVData.ChannelNumber; FSampleRate := WAVData.SampleRate; FBytesPerSecond := WAVData.BytesPerSecond; FBlockAlign := WAVData.BlockAlign; FBitsPerSample := WAVData.BitsPerSample; FSampleNumber := WAVData.SampleNumber div FBlockAlign; if WAVData.DataHeader = DATA_CHUNK then FHeaderSize := 44 else FHeaderSize := WAVData.FormatSize + 28; FFileSize := WAVData.FileSize + 8; if FHeaderSize > FFileSize then FHeaderSize := FFileSize; FFileName := FileName; FBitrate := FBytesPerSecond * 8 / 1000; end; end; { --------------------------------------------------------------------------- } function TWAVfile.FGetRatio: Double; begin { Get compression ratio } if FValid then if FSampleNumber = 0 then Result := FFileSize / ((FFileSize - FHeaderSize) / FBytesPerSecond * FSampleRate * (FChannelNumber * FBitsPerSample / 8) + 44) * 100 else Result := FFileSize / (FSampleNumber * (FChannelNumber * FBitsPerSample / 8) + 44) * 100 else Result := 0; end; { --------------------------------------------------------------------------- } procedure TWAVfile.TrimFromBeginning(const Samples: Cardinal); var SourceFile: TFileStreamEx; NewData, NewSamples, EraseOldData, NewFormatSize : Cardinal; begin try // blah, blah... should be self explanatory what happens here... SourceFile := TFileStreamEx.Create(FFileName, fmOpenReadWrite or fmShareDenyWrite); SourceFile.Seek(16, soFromBeginning); NewFormatSize := (Samples * FBlockAlign) + FFormatSize; SourceFile.Write(NewFormatSize, SizeOf(NewFormatSize)); SourceFile.Seek(FHeaderSize - 8, soFromBeginning); EraseOldData := 0; SourceFile.Write(EraseOldData, SizeOf(EraseOldData)); SourceFile.Seek(FHeaderSize + (Samples * FBlockAlign) - 8, soFromBeginning); NewData := 1635017060; // 'data' SourceFile.Write(NewData, SizeOf(NewData)); NewSamples := (FSampleNumber - Samples) * FBlockAlign; SourceFile.Write(NewSamples, SizeOf(NewSamples)); FFormatSize := NewFormatSize; FSampleNumber := FSampleNumber - Samples; FHeaderSize := FFormatSize + 28; SourceFile.Free; except { Error } end; end; { --------------------------------------------------------------------------- } procedure TWAVfile.TrimFromEnd(const Samples: Cardinal); var SourceFile: TFileStreamEx; NewSamples, NewSize : Cardinal; begin try SourceFile := TFileStreamEx.Create(FFileName, fmOpenReadWrite or fmShareDenyWrite); SourceFile.Seek(4, soFromBeginning); NewSamples := (FSampleNumber - Samples) * FBlockAlign; NewSize := NewSamples + FHeaderSize - 8; SourceFile.Write(NewSize, SizeOf(NewSize)); SourceFile.Seek(FHeaderSize - 4, soFromBeginning); SourceFile.Write(NewSamples, SizeOf(NewSamples)); SourceFile.Size := NewSamples + FHeaderSize; FSampleNumber := FSampleNumber - Samples; FFileSize := NewSamples + FHeaderSize; SourceFile.Free; except { Error } end; end; { --------------------------------------------------------------------------- } procedure TWAVfile.FindSilence(const FromBeginning, FromEnd: Boolean); var SourceFile: TFileStreamEx; ReadSample : Integer; AmountBegin, AmountEnd : Cardinal; begin try SourceFile := TFileStreamEx.Create(FFileName, fmOpenRead or fmShareDenyWrite); if FromBeginning then begin AmountBegin := 0; ReadSample := 0; SourceFile.Seek(FHeaderSize, soFromBeginning); // this assumes 16bit stereo repeat SourceFile.Read(ReadSample, SizeOf(ReadSample)); if ReadSample = 0 then Inc(AmountBegin); until (ReadSample <> 0) or (SourceFile.Position >= SourceFile.Size); FAmountTrimBegin := AmountBegin; end; if FromEnd then begin AmountEnd := 0; ReadSample := 0; repeat // this assumes 16bit stereo SourceFile.Seek(FFileSize - ((AmountEnd + 1) * 4), soFromBeginning); SourceFile.Read(ReadSample, SizeOf(ReadSample)); if ReadSample = 0 then Inc(AmountEnd); until ReadSample <> 0; FAmountTrimEnd := AmountEnd; end; SourceFile.Free; except { Error } end; end; { --------------------------------------------------------------------------- } end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/atl/WMAfile.pas������������������������������������������0000644�0001750�0000144�00000032557�14743153644�022422� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ *************************************************************************** } { } { Audio Tools Library } { Class TWMAfile - for extracting information from WMA file header } { } { http://mac.sourceforge.net/atl/ } { e-mail: macteam@users.sourceforge.net } { } { Copyright (c) 2000-2002 by Jurgen Faul } { Copyright (c) 2003-2005 by The MAC Team } { } { Version 1.0 (29 April 2002) } { - Support for Windows Media Audio (versions 7, 8) } { - File info: file size, channel mode, sample rate, duration, bit rate } { - WMA tag info: title, artist, album, track, year, genre, comment } { } { This library is free software; you can redistribute it and/or } { modify it under the terms of the GNU Lesser General Public } { License as published by the Free Software Foundation; either } { version 2.1 of the License, or (at your option) any later version. } { } { This library is distributed in the hope that it will be useful, } { but WITHOUT ANY WARRANTY; without even the implied warranty of } { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU } { Lesser General Public License for more details. } { } { You should have received a copy of the GNU Lesser General Public } { License along with this library; if not, write to the Free Software } { Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { } { *************************************************************************** } unit WMAfile; interface uses Classes, SysUtils, LazUTF8, DCClassesUtf8; const { Channel modes } WMA_CM_UNKNOWN = 0; { Unknown } WMA_CM_MONO = 1; { Mono } WMA_CM_STEREO = 2; { Stereo } { Channel mode names } WMA_MODE: array [0..2] of string = ('Unknown', 'Mono', 'Stereo'); type { Class TWMAfile } TWMAfile = class(TObject) private { Private declarations } FValid: Boolean; FFileSize: Integer; FChannelModeID: Byte; FSampleRate: Integer; FDuration: Double; FBitRate: Integer; FTitle: String; FArtist: String; FAlbum: String; FTrack: Integer; FYear: String; FGenre: String; FComment: String; procedure FResetData; function FGetChannelMode: string; public { Public declarations } constructor Create; { Create object } function ReadFromFile(const FileName: String): Boolean; { Load data } property Valid: Boolean read FValid; { True if valid data } property FileSize: Integer read FFileSize; { File size (bytes) } property ChannelModeID: Byte read FChannelModeID; { Channel mode code } property ChannelMode: string read FGetChannelMode; { Channel mode name } property SampleRate: Integer read FSampleRate; { Sample rate (hz) } property Duration: Double read FDuration; { Duration (seconds) } property BitRate: Integer read FBitRate; { Bit rate (kbit) } property Title: String read FTitle; { Song title } property Artist: String read FArtist; { Artist name } property Album: String read FAlbum; { Album name } property Track: Integer read FTrack; { Track number } property Year: String read FYear; { Year } property Genre: String read FGenre; { Genre name } property Comment: String read FComment; { Comment } end; implementation const { Object IDs } WMA_HEADER_ID = #48#38#178#117#142#102#207#17#166#217#0#170#0#98#206#108; WMA_FILE_PROPERTIES_ID = #161#220#171#140#71#169#207#17#142#228#0#192#12#32#83#101; WMA_STREAM_PROPERTIES_ID = #145#7#220#183#183#169#207#17#142#230#0#192#12#32#83#101; WMA_CONTENT_DESCRIPTION_ID = #51#38#178#117#142#102#207#17#166#217#0#170#0#98#206#108; WMA_EXTENDED_CONTENT_DESCRIPTION_ID = #64#164#208#210#7#227#210#17#151#240#0#160#201#94#168#80; { Max. number of supported comment fields } WMA_FIELD_COUNT = 7; { Names of supported comment fields } WMA_FIELD_NAME: array [1..WMA_FIELD_COUNT] of UnicodeString = ('WM/TITLE', 'WM/AUTHOR', 'WM/ALBUMTITLE', 'WM/TRACK', 'WM/YEAR', 'WM/GENRE', 'WM/DESCRIPTION'); { Max. number of characters in tag field } WMA_MAX_STRING_SIZE = 250; type { Object ID } ObjectID = array [1..16] of Char; { Tag data } TagData = array [1..WMA_FIELD_COUNT] of UnicodeString; { File data - for internal use } FileData = record FileSize: Integer; { File size (bytes) } MaxBitRate: Integer; { Max. bit rate (bps) } Channels: Word; { Number of channels } SampleRate: Integer; { Sample rate (hz) } ByteRate: Integer; { Byte rate } Tag: TagData; { WMA tag information } end; { ********************* Auxiliary functions & procedures ******************** } function ReadFieldString(const Source: TStream; DataSize: Word): UnicodeString; var Iterator, StringSize: Integer; FieldData: array [1..WMA_MAX_STRING_SIZE * 2] of Byte; begin { Read field data and convert to Unicode string } Result := ''; StringSize := DataSize div 2; if StringSize > WMA_MAX_STRING_SIZE then StringSize := WMA_MAX_STRING_SIZE; Source.ReadBuffer(FieldData, StringSize * 2); Source.Seek(DataSize - StringSize * 2, soFromCurrent); for Iterator := 1 to StringSize do Result := Result + WideChar(FieldData[Iterator * 2 - 1] + (FieldData[Iterator * 2] shl 8)); end; { --------------------------------------------------------------------------- } procedure ReadTagStandard(const Source: TStream; var Tag: TagData); var Iterator: Integer; FieldSize: array [1..5] of Word; FieldValue: UnicodeString; begin { Read standard tag data } Source.ReadBuffer(FieldSize, SizeOf(FieldSize)); for Iterator := 1 to 5 do if FieldSize[Iterator] > 0 then begin { Read field value } FieldValue := ReadFieldString(Source, FieldSize[Iterator]); { Set corresponding tag field if supported } case Iterator of 1: Tag[1] := FieldValue; 2: Tag[2] := FieldValue; 4: Tag[7] := FieldValue; end; end; end; { --------------------------------------------------------------------------- } procedure ReadTagExtended(const Source: TStream; var Tag: TagData); var Iterator1, Iterator2, FieldCount, DataSize, DataType: Word; FieldName, FieldValue: UnicodeString; begin { Read extended tag data } Source.ReadBuffer(FieldCount, SizeOf(FieldCount)); for Iterator1 := 1 to FieldCount do begin { Read field name } Source.ReadBuffer(DataSize, SizeOf(DataSize)); FieldName := ReadFieldString(Source, DataSize); { Read value data type } Source.ReadBuffer(DataType, SizeOf(DataType)); { Read field value only if string } if DataType = 0 then begin Source.ReadBuffer(DataSize, SizeOf(DataSize)); FieldValue := ReadFieldString(Source, DataSize); end else Source.Seek(DataSize, soFromCurrent); { Set corresponding tag field if supported } for Iterator2 := 1 to WMA_FIELD_COUNT do if UpperCase(Trim(FieldName)) = WMA_FIELD_NAME[Iterator2] then Tag[Iterator2] := FieldValue; end; end; { --------------------------------------------------------------------------- } procedure ReadObject(const ID: ObjectID; Source: TStream; var Data: FileData); begin { Read data from header object if supported } if ID = WMA_FILE_PROPERTIES_ID then begin { Read file properties } Source.Seek(80, soFromCurrent); Source.ReadBuffer(Data.MaxBitRate, SizeOf(Data.MaxBitRate)); end; if ID = WMA_STREAM_PROPERTIES_ID then begin { Read stream properties } Source.Seek(60, soFromCurrent); Source.ReadBuffer(Data.Channels, SizeOf(Data.Channels)); Source.ReadBuffer(Data.SampleRate, SizeOf(Data.SampleRate)); Source.ReadBuffer(Data.ByteRate, SizeOf(Data.ByteRate)); end; if ID = WMA_CONTENT_DESCRIPTION_ID then begin { Read standard tag data } Source.Seek(4, soFromCurrent); ReadTagStandard(Source, Data.Tag); end; if ID = WMA_EXTENDED_CONTENT_DESCRIPTION_ID then begin { Read extended tag data } Source.Seek(4, soFromCurrent); ReadTagExtended(Source, Data.Tag); end; end; { --------------------------------------------------------------------------- } function ReadData(const FileName: String; var Data: FileData): Boolean; var Source: TFileStreamEx; ID: ObjectID; Iterator, ObjectCount, ObjectSize, Position: Integer; begin { Read file data } try Source := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); Data.FileSize := Source.Size; { Check for existing header } Source.ReadBuffer(ID, SizeOf(ID)); if ID = WMA_HEADER_ID then begin Source.Seek(8, soFromCurrent); Source.ReadBuffer(ObjectCount, SizeOf(ObjectCount)); Source.Seek(2, soFromCurrent); { Read all objects in header and get needed data } for Iterator := 1 to ObjectCount do begin Position := Source.Position; Source.ReadBuffer(ID, SizeOf(ID)); Source.ReadBuffer(ObjectSize, SizeOf(ObjectSize)); ReadObject(ID, Source, Data); Source.Seek(Position + ObjectSize, soFromBeginning); end; end; Source.Free; Result := true; except Result := false; end; end; { --------------------------------------------------------------------------- } function IsValid(const Data: FileData): Boolean; begin { Check for data validity } Result := (Data.MaxBitRate > 0) and (Data.MaxBitRate < 320000) and ((Data.Channels = WMA_CM_MONO) or (Data.Channels = WMA_CM_STEREO)) and (Data.SampleRate >= 8000) and (Data.SampleRate <= 96000) and (Data.ByteRate > 0) and (Data.ByteRate < 40000); end; { --------------------------------------------------------------------------- } function ExtractTrack(const TrackString: UnicodeString): Integer; var Value, Code: Integer; begin { Extract track from string } Result := 0; Val(TrackString, Value, Code); if Code = 0 then Result := Value; end; { ********************** Private functions & procedures ********************* } procedure TWMAfile.FResetData; begin { Reset variables } FValid := false; FFileSize := 0; FChannelModeID := WMA_CM_UNKNOWN; FSampleRate := 0; FDuration := 0; FBitRate := 0; FTitle := ''; FArtist := ''; FAlbum := ''; FTrack := 0; FYear := ''; FGenre := ''; FComment := ''; end; { --------------------------------------------------------------------------- } function TWMAfile.FGetChannelMode: string; begin { Get channel mode name } Result := WMA_MODE[FChannelModeID]; end; { ********************** Public functions & procedures ********************** } constructor TWMAfile.Create; begin { Create object } inherited; FResetData; end; { --------------------------------------------------------------------------- } function TWMAfile.ReadFromFile(const FileName: String): Boolean; var Data: FileData; begin { Reset variables and load file data } FResetData; FillChar(Data, SizeOf(Data), 0); Result := ReadData(FileName, Data); { Process data if loaded and valid } if Result and IsValid(Data) then begin FValid := true; { Fill properties with loaded data } FFileSize := Data.FileSize; FChannelModeID := Data.Channels; FSampleRate := Data.SampleRate; FDuration := Data.FileSize * 8 / Data.MaxBitRate; FBitRate := Data.ByteRate * 8 div 1000; FTitle := UTF16ToUTF8(Trim(Data.Tag[1])); FArtist := UTF16ToUTF8(Trim(Data.Tag[2])); FAlbum := UTF16ToUTF8(Trim(Data.Tag[3])); FTrack := ExtractTrack(Trim(Data.Tag[4])); FYear := UTF16ToUTF8(Trim(Data.Tag[5])); FGenre := UTF16ToUTF8(Trim(Data.Tag[6])); FComment := UTF16ToUTF8(Trim(Data.Tag[7])); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/audioinfo/src/audiodata.pas��������������������������������������������0000644�0001750�0000144�00000041654�14743153644�022307� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- This content plugin can show information about audio files Copyright (C) 2016-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit AudioData; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCStrUtils, MPEGaudio, Musepack, OggVorbis, ID3v1, ID3v2, APEtag, FLACfile, Monkey, AACfile, CDAtrack, WMAfile, WAVfile, TTA, TwinVQ, AC3, DTS, WAVPackfile, OptimFROG, MP4file; type { TAudioData } TAudioData = class private FDTS: TDTS; FAC3: TAC3; FTTA: TTTA; FTwinVQ: TTwinVQ; FMonkey: TMonkey; FMP4file: TMP4file; FAACfile: TAACfile; FWMAfile: TWMAfile; FWAVfile: TWAVfile; FFLACfile: TFLACfile; FMPEGplus: TMPEGplus; FCDAtrack: TCDAtrack; FMPEGaudio: TMPEGaudio; FOggVorbis: TOggVorbis; FOptimFrog: TOptimFrog; FWAVPackfile: TWAVPackfile; private procedure Clear; procedure ReadID3v1(ID3v1: TID3v1); procedure ReadID3v2(ID3v2: TID3v2); procedure ReadAPEtag(APEtag: TAPEtag); procedure AppendTag(const ATag: String); function FormatChannels(AChannels: Integer): String; function FormatDuration(ADuration: Integer): String; procedure UpdateValue(var AValue: Integer; AData: Integer); procedure UpdateValue(var AValue: String; const AData: String); protected FFileName: String; function ReadDTS: Boolean; function ReadAC3: Boolean; function ReadTTA: Boolean; function ReadTwinVQ: Boolean; function ReadMonkey: Boolean; function ReadMP4file: Boolean; function ReadAACfile: Boolean; function ReadWMAfile: Boolean; function ReadWAVfile: Boolean; function ReadFLACfile: Boolean; function ReadMPEGplus: Boolean; function ReadCDAtrack: Boolean; function ReadMPEGaudio: Boolean; function ReadOggVorbis: Boolean; function ReadOptimFrog: Boolean; function ReadWAVPackfile: Boolean; public Album, Artist, Title: String; Bits, Track, Duration, SampleRate, BitRate: Integer; DurationHMS, BitRateType, Channels, Date, Genre, Comment, Tags, Encoder, Composer, Copyright, URL: String; FullText: UnicodeString; public constructor Create; destructor Destroy; override; function LoadFromFile(const FileName: String): Boolean; end; implementation uses LazUTF8; { TAudioData } procedure TAudioData.Clear; begin Bits:= 0; Track:= 0; BitRate:= 0; Duration:= 0; SampleRate:= 0; URL:= EmptyStr; Tags:= EmptyStr; Date:= EmptyStr; Genre:= EmptyStr; Title:= EmptyStr; Album:= EmptyStr; Artist:= EmptyStr; Comment:= EmptyStr; Encoder:= EmptyStr; Channels:= EmptyStr; Composer:= EmptyStr; Copyright:= EmptyStr; DurationHMS:= EmptyStr; FullText:= EmptyWideStr; BitRateType:= 'Unknown'; end; procedure TAudioData.ReadID3v1(ID3v1: TID3v1); begin if ID3v1.Exists then begin UpdateValue(Date, ID3v1.Year); UpdateValue(Track, ID3v1.Track); UpdateValue(Album, ID3v1.Album); UpdateValue(Title, ID3v1.Title); UpdateValue(Genre, ID3v1.Genre); UpdateValue(Artist, ID3v1.Artist); UpdateValue(Comment, ID3v1.Comment); case ID3v1.VersionID of TAG_VERSION_1_0: AppendTag('ID3v1.0'); TAG_VERSION_1_1: AppendTag('ID3v1.1'); else AppendTag('ID3v1'); end; end; end; procedure TAudioData.ReadID3v2(ID3v2: TID3v2); begin if ID3v2.Exists then begin UpdateValue(URL, ID3v2.Link); UpdateValue(Date, ID3v2.Year); UpdateValue(Track, ID3v2.Track); UpdateValue(Album, ID3v2.Album); UpdateValue(Title, ID3v2.Title); UpdateValue(Genre, ID3v2.Genre); UpdateValue(Artist, ID3v2.Artist); UpdateValue(Comment, ID3v2.Comment); UpdateValue(Encoder, ID3v2.Encoder); UpdateValue(Composer, ID3v2.Composer); UpdateValue(Copyright, ID3v2.Copyright); case ID3v2.VersionID of TAG_VERSION_2_2: AppendTag('ID3v2.2'); TAG_VERSION_2_3: AppendTag('ID3v2.3'); TAG_VERSION_2_4: AppendTag('ID3v2.4'); else AppendTag('ID3v2'); end; end; end; procedure TAudioData.ReadAPEtag(APEtag: TAPEtag); begin if APEtag.Exists then begin UpdateValue(Date, APEtag.Year); UpdateValue(Track, APEtag.Track); UpdateValue(Album, APEtag.Album); UpdateValue(Title, APEtag.Title); UpdateValue(Genre, APEtag.Genre); UpdateValue(Artist, APEtag.Artist); UpdateValue(Comment, APEtag.Comment); UpdateValue(Composer, APEtag.Composer); UpdateValue(Copyright, APEtag.Copyright); AppendTag('APEv' + IntToStr(APEtag.Version div 1000)); end; end; procedure TAudioData.AppendTag(const ATag: String); begin if Length(Tags) = 0 then Tags:= ATag else begin Tags:= Tags + ' ' + ATag; end; end; function TAudioData.FormatChannels(AChannels: Integer): String; begin case AChannels of 0: Result:= 'Unknown'; 1: Result:= 'Mono'; 2: Result:= 'Stereo' else Result:= IntToStr(AChannels) + ' ch'; end; end; function TAudioData.FormatDuration(ADuration: Integer): String; var AHour, AMinute, ASecond: Integer; begin AHour:= ADuration div 3600; AMinute:= ADuration mod 3600 div 60; ASecond:= ADuration mod 60; Result:= Format('%.2d:%.2d:%.2d', [AHour, AMinute, ASecond]); end; procedure TAudioData.UpdateValue(var AValue: Integer; AData: Integer); begin if AValue = 0 then AValue:= AData; end; procedure TAudioData.UpdateValue(var AValue: String; const AData: String); begin if Length(AValue) = 0 then AValue:= AData; end; function TAudioData.ReadDTS: Boolean; begin Result:= FDTS.ReadFromFile(FFileName) and FDTS.Valid; if Result then begin BitRate:= FDTS.BitRate; Bits:= Integer(FDTS.Bits); Duration:= Round(FDTS.Duration); DurationHMS:= FormatDuration(Duration); Channels:= FormatChannels(FDTS.Channels); SampleRate:= FDTS.SampleRate; end; end; function TAudioData.ReadAC3: Boolean; begin Result:= FAC3.ReadFromFile(FFileName) and FAC3.Valid; if Result then begin BitRate:= FAC3.BitRate; Duration:= Round(FAC3.Duration); DurationHMS:= FormatDuration(Duration); Channels:= FormatChannels(FAC3.Channels); SampleRate:= FAC3.SampleRate; end; end; function TAudioData.ReadTTA: Boolean; begin Result:= FTTA.ReadFromFile(FFileName) and FTTA.Valid; if Result then begin Bits:= Integer(FTTA.Bits); BitRate:= Round(FTTA.BitRate); Duration:= Round(FTTA.Duration); DurationHMS:= FormatDuration(Duration); Channels:= FormatChannels(FTTA.Channels); SampleRate:= FTTA.SampleRate; ReadAPEtag(FTTA.APEtag); ReadID3v2(FTTA.ID3v2); ReadID3v1(FTTA.ID3v1); end; end; function TAudioData.ReadTwinVQ: Boolean; begin Result:= FTwinVQ.ReadFromFile(FFileName) and FTwinVQ.Valid; if Result then begin BitRate:= FTwinVQ.BitRate; Channels:= FTwinVQ.ChannelMode; Duration:= Round(FTwinVQ.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FTwinVQ.SampleRate; Album:= FTwinVQ.Album; Title:= FTwinVQ.Title; Artist:= FTwinVQ.Author; Comment:= FTwinVQ.Comment; end; end; function TAudioData.ReadMonkey: Boolean; begin Result:= FMonkey.ReadFromFile(FFileName) and FMonkey.Valid; if Result then begin Bits:= FMonkey.Bits; Channels:= FMonkey.ChannelMode; BitRate:= Round(FMonkey.BitRate) div 1000000; Duration:= Round(FMonkey.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FMonkey.SampleRate; ReadAPEtag(FMonkey.APEtag); ReadID3v2(FMonkey.ID3v2); ReadID3v1(FMonkey.ID3v1); end; end; function TAudioData.ReadMP4file: Boolean; begin Result:= FMP4file.ReadFromFile(FFileName) and FMP4file.Valid; if Result then begin SampleRate:= FMP4file.SampleRate; BitRate:= Round(FMP4file.BitRate); Duration:= Round(FMP4file.Duration); DurationHMS:= FormatDuration(Duration); Channels:= FormatChannels(FMP4file.Channels); Date:= FMP4file.Year; Track:= FMP4file.Track; Genre:= FMP4file.Genre; Title:= FMP4file.Title; Album:= FMP4file.Album; Artist:= FMP4file.Artist; Comment:= FMP4file.Comment; Encoder:= FMP4file.Encoder; Composer:= FMP4file.Composer; Copyright:= FMP4file.Copyright; end; end; function TAudioData.ReadAACfile: Boolean; begin Result:= FAACfile.ReadFromFile(FFileName) and FAACfile.Valid; if Result then begin BitRate:= FAACfile.BitRate; BitRateType:= FAACfile.BitRateType; Duration:= Round(FAACfile.Duration); DurationHMS:= FormatDuration(Duration); Channels:= FormatChannels(FAACfile.Channels); SampleRate:= FAACfile.SampleRate; ReadID3v2(FAACfile.ID3v2); ReadID3v1(FAACfile.ID3v1); ReadAPEtag(FAACfile.APEtag); end; end; function TAudioData.ReadWMAfile: Boolean; begin Result:= FWMAfile.ReadFromFile(FFileName) and FWMAfile.Valid; if Result then begin BitRate:= FWMAfile.BitRate; Channels:= FWMAfile.ChannelMode; Duration:= Round(FWMAfile.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FWMAfile.SampleRate; Date:= FWMAfile.Year; Track:= FWMAfile.Track; Album:= FWMAfile.Album; Title:= FWMAfile.Title; Genre:= FWMAfile.Genre; Artist:= FWMAfile.Artist; Comment:= FWMAfile.Comment; end; end; function TAudioData.ReadWAVfile: Boolean; begin Result:= FWAVfile.ReadFromFile(FFileName) and FWAVfile.Valid; if Result then begin Bits:= FWAVfile.BitsPerSample; BitRate:= Round(FWAVfile.BitRate); Channels:= FWAVfile.ChannelMode; Duration:= Round(FWAVfile.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FWAVfile.SampleRate; end; end; function TAudioData.ReadFLACfile: Boolean; begin Result:= FFLACfile.ReadFromFile(FFileName) and FFLACfile.Valid; if Result then begin BitRate:= FFLACfile.BitRate; Bits:= FFLACfile.BitsPerSample; Channels:= FFLACfile.ChannelMode; Duration:= Round(FFLACfile.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FFLACfile.SampleRate; URL:= FFLACfile.Link; Date:= FFLACfile.Year; Track:= FFLACfile.Track; Album:= FFLACfile.Album; Title:= FFLACfile.Title; Genre:= FFLACfile.Genre; Artist:= FFLACfile.Artist; Comment:= FFLACfile.Comment; Encoder:= FFLACfile.Encoder; Composer:= FFLACfile.Composer; Copyright:= FFLACfile.Copyright; end; end; function TAudioData.ReadMPEGplus: Boolean; begin Result:= FMPEGplus.ReadFromFile(FFileName) and FMPEGplus.Valid; if Result then begin BitRate:= FMPEGplus.BitRate; Channels:= FMPEGplus.ChannelMode; Duration:= Round(FMPEGplus.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FMPEGplus.SampleRate; ReadID3v2(FMPEGplus.ID3v2); ReadID3v1(FMPEGplus.ID3v1); ReadAPEtag(FMPEGplus.APEtag); end; end; function TAudioData.ReadCDAtrack: Boolean; begin Result:= FCDAtrack.ReadFromFile(FFileName) and FCDAtrack.Valid; if Result then begin Duration:= Round(FCDAtrack.Duration); DurationHMS:= FormatDuration(Duration); Track:= FCDAtrack.Track; Album:= FCDAtrack.Album; Title:= FCDAtrack.Title; Artist:= FCDAtrack.Artist; end; end; function TAudioData.ReadMPEGaudio: Boolean; begin Result:= FMPEGaudio.ReadFromFile(FFileName) and FMPEGaudio.Valid; if Result then begin if FMPEGaudio.VBR.Found then BitRateType:= 'VBR' else begin BitRateType:= 'CBR'; end; BitRate:= FMPEGaudio.BitRate; Channels:= FMPEGaudio.ChannelMode; Duration:= Round(FMPEGaudio.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FMPEGaudio.SampleRate; ReadID3v2(FMPEGaudio.ID3v2); ReadID3v1(FMPEGaudio.ID3v1); end; end; function TAudioData.ReadOggVorbis: Boolean; begin Result:= FOggVorbis.ReadFromFile(FFileName) and FOggVorbis.Valid; if Result then begin BitRate:= FOggVorbis.BitRate; Channels:= FOggVorbis.ChannelMode; Duration:= Round(FOggVorbis.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FOggVorbis.SampleRate; Date:= FOggVorbis.Date; Track:= FOggVorbis.Track; Album:= FOggVorbis.Album; Title:= FOggVorbis.Title; Genre:= FOggVorbis.Genre; Artist:= FOggVorbis.Artist; Comment:= FOggVorbis.Comment; Encoder:= FOggVorbis.Encoder; end; end; function TAudioData.ReadOptimFrog: Boolean; begin Result:= FOptimFrog.ReadFromFile(FFileName) and FOptimFrog.Valid; if Result then begin Bits:= FOptimFrog.Bits; BitRate:= FOptimFrog.BitRate; Channels:= FOptimFrog.ChannelMode; Duration:= Round(FOptimFrog.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FOptimFrog.SampleRate; ReadID3v2(FOptimFrog.ID3v2); ReadID3v1(FOptimFrog.ID3v1); ReadAPEtag(FOptimFrog.APEtag); end; end; function TAudioData.ReadWAVPackfile: Boolean; begin Result:= FWAVPackfile.ReadFromFile(FFileName) and FWAVPackfile.Valid; if Result then begin Bits:= FWAVPackfile.Bits; Encoder:= FWAVPackfile.Encoder; Channels:= FWAVPackfile.ChannelMode; BitRate:= Round(FWAVPackfile.BitRate); Duration:= Round(FWAVPackfile.Duration); DurationHMS:= FormatDuration(Duration); SampleRate:= FWAVPackfile.SampleRate; ReadAPEtag(FWAVPackfile.APEtag); end; end; constructor TAudioData.Create; begin FDTS:= TDTS.Create; FAC3:= TAC3.Create; FTTA:= TTTA.Create; FTwinVQ:= TTwinVQ.Create; FMonkey:= TMonkey.Create; FMP4file:= TMP4file.Create; FAACfile:= TAACfile.Create; FWMAfile:= TWMAfile.Create; FWAVfile:= TWAVfile.Create; FCDAtrack:= TCDAtrack.Create; FMPEGplus:= TMPEGplus.Create; FFLACfile:= TFLACfile.Create; FMPEGaudio:= TMPEGaudio.Create; FOggVorbis:= TOggVorbis.Create; FOptimFrog:= TOptimFrog.Create; FWAVPackfile:= TWAVPackfile.Create; end; destructor TAudioData.Destroy; begin FDTS.Free; FAC3.Free; FTTA.Free; FTwinVQ.Free; FMonkey.Free; FMP4file.Free; FAACfile.Free; FWMAfile.Free; FWAVfile.Free; FCDAtrack.Free; FMPEGplus.Free; FFLACfile.Free; FMPEGaudio.Free; FOggVorbis.Free; FOptimFrog.Free; FWAVPackfile.Free; inherited Destroy; end; function TAudioData.LoadFromFile(const FileName: String): Boolean; var FileExt: String; begin Clear; FFileName:= FileName; FileExt:= LowerCase(ExtractOnlyFileExt(FileName)); if (FileExt = 'mp3') or (FileExt = 'mp2') or (FileExt = 'mp1') then begin Result:= ReadMPEGaudio; end else if (FileExt = 'mpc') then begin Result:= ReadMPEGplus; end else if (FileExt = 'ogg') or (FileExt = 'opus') then begin Result:= ReadOggVorbis; end else if (FileExt = 'flac') then begin Result:= ReadFLACfile; end else if (FileExt = 'ape') then begin Result:= ReadMonkey; end else if (FileExt = 'aac') then begin Result:= ReadAACfile; end else if (FileExt = 'cda') then begin Result:= ReadCDAtrack; end else if (FileExt = 'wma') then begin Result:= ReadWMAfile; end else if (FileExt = 'wav') then begin Result:= ReadWAVfile; end else if (FileExt = 'tta') then begin Result:= ReadTTA; end else if (FileExt = 'vqf') then begin Result:= ReadTwinVQ; end else if (FileExt = 'ac3') then begin Result:= ReadAC3; end else if (FileExt = 'dts') then begin Result:= ReadDTS; end else if (FileExt = 'wv') or (FileExt = 'wvc') then begin Result:= ReadWAVPackfile; end else if (FileExt = 'ofr') or (FileExt = 'ofs') then begin Result:= ReadOptimFrog; end else if (FileExt = 'mp4') or (FileExt = 'm4a') then begin Result:= ReadMP4file; end else Result:= False; if Result then begin FullText:= UTF8ToUTF16(Title + LineEnding + Artist + LineEnding + Album + LineEnding + Comment + LineEnding + Composer + LineEnding + Copyright + LineEnding + URL + LineEnding + Encoder + LineEnding); end; end; end. ������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016505� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/src/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017274� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/src/deb_wdx.dpr������������������������������������������������0000644�0001750�0000144�00000001260�14743153644�021416� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of DEBWDX, a content plugin for // Total Commander handling Debian Linux package. // // Copyright (C) 2005 Ralgh Young (yang.guilong@gmail.com) //*************************************************************** // Add some changes for Lazarus and Linux compatibility // // Copyright (C) 2009 Koblov Alexander (Alexx2000@mail.ru) //*************************************************************** library deb_wdx; uses SysUtils, Classes, WdxPlugin, deb_wdx_intf in 'deb_wdx_intf.pas'; exports ContentGetDetectString, ContentGetSupportedField, ContentGetValue; {$R *.res} begin end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/src/deb_wdx.lpi������������������������������������������������0000644�0001750�0000144�00000010500�14743153644�021412� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="2"/> <StringTable FileDescription="DEB WDX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2021 Alexander Koblov"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\deb_wdx.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk;..\..\..\wcx\zip\src\fparchive"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <CStyleOperator Value="False"/> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <Units Count="2"> <Unit0> <Filename Value="deb_wdx.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="deb_wdx_intf.pas"/> <IsPartOfProject Value="True"/> </Unit1> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\deb_wdx.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk;..\..\..\wcx\zip\src\fparchive"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <CStyleOperator Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/src/deb_wdx_intf.pas�������������������������������������������0000644�0001750�0000144�00000013214�14743153644�022436� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of DEBWDX, a content plugin for // Total Commander handling Debian Linux package. // // Copyright (C) 2005 Ralgh Young (yang.guilong@gmail.com) //*************************************************************** // This program is free software; you can redistribute it and/or modify it // under the GPL. // // Only version 2.0 package is supported, and I would not to add support for // old format since I haven't old packages. But if you have some package of old format, // and you're interested in, you're welcomed to modify the source by yourself. // FYI: refer to dpkg-deb/extract.c in dpkg-deb's source, // and search '0.93' in function extracthalf, you're find something useful. {$A-,I-} //no alignment, no I/O error autochecking unit deb_wdx_intf; {$mode delphi}{$H+} {$include calling.inc} interface uses Classes, WdxPlugin; procedure ContentGetDetectString(DetectString:pchar; maxlen:integer); dcpcall; export; function ContentGetSupportedField(FieldIndex:integer;FieldName:pchar; Units:pchar;maxlen:integer):integer; dcpcall; export; function ContentGetValue(FileName:pchar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer; dcpcall; export; implementation uses SysUtils, debunpak; var IDX_PACKAGE, IDX_VERSION, IDX_SECTION, IDX_PRIORITY, IDX_ARCH, IDX_DEPENDS, IDX_RECOMMENDS, IDX_SUGGESTS, IDX_CONFLICTS, IDX_INSTALLED_SIZE, IDX_MAINTAINER, IDX_SOURCE, IDX_SUMMARY, IDX_DESCRIPTION : integer; CurrentPackageFile: String; FieldList : TStrings; FileInfo : TStrings; procedure ContentGetDetectString(DetectString:pchar; maxlen:integer); begin StrPCopy(DetectString, 'EXT="DEB"'); end; function ContentGetSupportedField(FieldIndex:integer; FieldName:pchar; Units:pchar;maxlen:integer):integer; begin StrPCopy(Units, ''); if FieldIndex =IDX_INSTALLED_SIZE then begin StrPCopy(FieldName, FieldList.Strings[FieldIndex]); StrPCopy(Units, 'bytes|kbytes|Mbytes|Gbytes'+#0); Result := FT_NUMERIC_64; end else if FieldIndex < FieldList.Count then begin StrPCopy(FieldName, FieldList.Strings[FieldIndex]); Result := FT_STRING; end else Result := FT_NOMOREFIELDS; end; {$WRITEABLECONST ON} function ContentGetValue(FileName:pchar; FieldIndex,UnitIndex:integer; FieldValue:pbyte; maxlen,flags:integer):integer; function EnsureLength(S: string; nMaxlen: integer): string; begin Result := S; if length(Result)>=nMaxlen then begin Result := Copy(Result, 1, nMaxlen-4); Result := Result + '...'; end; end; const DescTmpFile: String = ''; var Field, Value : String; i, where_start_desc : integer; size : int64; begin Result := FT_FILEERROR; if not FileExists(FileName) then exit; if CurrentPackageFile<>FileName then begin if not Deb_ExtractCtrlInfoFile(FileName, DescTmpFile) then exit; FileInfo.Text := DescTmpFile; CurrentPackageFile := FileName; end {$IFDEF GDEBUG} else WriteLn('Cached info reused for '+FileName); {$ENDIF}; if (FieldIndex>=FieldList.Count) then begin Result := FT_NOSUCHFIELD; exit; end; if FieldIndex<>IDX_DESCRIPTION then begin if FieldIndex=IDX_SUMMARY then //for 'Summary', return the value of Description Field := 'Description' else Field := FieldList.Strings[FieldIndex]; Value := ''; Value := Trim(FileInfo.Values[Field]); if Value='' then begin Result := FT_FIELDEMPTY; exit; end; if FieldIndex=IDX_INSTALLED_SIZE then begin size := StrToInt64Def(Value, -1); case UnitIndex of 0: //bytes size := size * 1024; // 1: //kbytes // pass 2: //mbytes size := size div 1024; 3: //gbytes size := size div (1024 * 1024); end; Move(size, FieldValue^, sizeof(size)); Result := FT_NUMERIC_64; end else //other fields, just string begin StrPCopy(PChar(FieldValue), EnsureLength(Value, maxlen)); Result := FT_STRING; end; end else //IDX_DESCRIPTION, begin Value := ''; where_start_desc := -1; for i:=0 to FileInfo.Count-1 do begin if FileInfo.Names[i]='Description' then begin where_start_desc := i; break; end; end; if where_start_desc>=0 then begin for i:=where_start_desc+1 to FileInfo.Count-1 do begin Value := Value + FileInfo.Strings[i]; end; StrPCopy(PChar(FieldValue), EnsureLength(Value, maxlen)); //Result := FT_FULLTEXT; Result := FT_STRING; end; end end; initialization CurrentPackageFile := ''; FileInfo := TStringList.Create; FileInfo.NameValueSeparator := ':'; FieldList := TStringList.Create; IDX_PACKAGE := FieldList.Add('Package'); IDX_VERSION := FieldList.Add('Version'); IDX_SECTION := FieldList.Add('Section'); IDX_PRIORITY := FieldList.Add('Priority'); IDX_ARCH := FieldList.Add('Architecture'); IDX_DEPENDS := FieldList.Add('Depends'); IDX_RECOMMENDS:= FieldList.Add('Recommends'); IDX_SUGGESTS := FieldList.Add('Suggests'); IDX_CONFLICTS := FieldList.Add('Conflicts'); IDX_INSTALLED_SIZE := FieldList.Add('Installed-Size'); IDX_MAINTAINER := FieldList.Add('Maintainer'); IDX_SOURCE := FieldList.Add('Source'); IDX_SUMMARY := FieldList.Add('Summary'); IDX_DESCRIPTION := FieldList.Add('Description'); finalization FileInfo.Free; FieldList.Free; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/src/debunpak.pas�����������������������������������������������0000644�0001750�0000144�00000010674�14743153644�021602� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit debunpak; {$mode delphi}{$H+} interface uses SysUtils, Classes; // Extract 'control' from control.tar.* function Deb_ExtractCtrlInfoFile(const DebFile: String; var DescFile: String): Boolean; implementation uses dpkg_deb, libtar, AbXz, ZStream, AbZstd; var DebPkg: TDebianPackage; const HEAD_CRC = $02; { bit 1 set: header CRC present } EXTRA_FIELD = $04; { bit 2 set: extra field present } ORIG_NAME = $08; { bit 3 set: original file name present } COMMENT = $10; { bit 4 set: file comment present } type TGzHeader = packed record ID1 : Byte; ID2 : Byte; Method : Byte; Flags : Byte; ModTime : UInt32; XtraFlags : Byte; OS : Byte; end; function ExtractGzip(InStream, OutStream: TStream): Boolean; var ALength: Integer; AHeader: TGzHeader; ABuffer: array[Word] of Byte; begin Result:= False; InStream.ReadBuffer(AHeader, SizeOf(TGzHeader)); if (AHeader.ID1 = $1F) and (AHeader.ID2 = $8B) and (AHeader.Method = 8) then begin // Skip the extra field if (AHeader.Flags and EXTRA_FIELD <> 0) then begin ALength:= InStream.ReadWord; while ALength > 0 do begin InStream.ReadByte; Dec(ALength); end; end; // Skip the original file name if (AHeader.Flags and ORIG_NAME <> 0) then begin while (InStream.ReadByte > 0) do; end; // Skip the .gz file comment if (AHeader.Flags and COMMENT <> 0) then begin while (InStream.ReadByte > 0) do; end; // Skip the header crc if (AHeader.Flags and HEAD_CRC <> 0) then begin InStream.ReadWord; end; with TDecompressionStream.Create(InStream, True) do try while True do begin ALength:= Read(ABuffer[0], SizeOf(ABuffer)); if (ALength = 0) then Break; OutStream.Write(ABuffer[0], ALength); end; Result:= True; finally Free; end; end; end; function ExtractXz(InStream, OutStream: TStream): Boolean; var AStream: TStream; begin Result:= False; AStream:= TXzDecompressionStream.Create(InStream); try OutStream.CopyFrom(AStream, 0); Result:= True; finally AStream.Free; end; end; function ExtractZstd(InStream, OutStream: TStream): Boolean; var AStream: TStream; begin Result:= False; AStream:= TZstdDecompressionStream.Create(InStream); try OutStream.CopyFrom(AStream, 0); Result:= True; finally AStream.Free; end; end; function UnpackDebFile(const DebFile: String; MemberIdx: Integer; OutStream: TStream): Boolean; var Index: Integer; FileExt: String; TempStream: TMemoryStream; begin Result:= False; if (MemberIdx in [MEMBER_CONTROL, MEMBER_DATA]) then try // a debian package must have control.tar.* and data.tar.* if DebPkg.ReadFromFile(DebFile) < 2 then Exit; // Check file type FileExt:= TrimRight(DebPkg.FMemberList[MemberIdx].ar_name); Index:= Pos(ExtensionSeparator, FileExt); if Index = 0 then Exit; FileExt:= Copy(FileExt, Index, MaxInt); if (FileExt = '.tar.xz') or (FileExt = '.tar.gz') or (FileExt = '.tar.zst') then begin TempStream:= TMemoryStream.Create; try if DebPkg.ExtractMemberToStream(MemberIdx, TempStream) then begin TempStream.Position:= 0; case FileExt[6] of 'x': Result:= ExtractXz(TempStream, OutStream); 'g': Result:= ExtractGzip(TempStream, OutStream); 'z': Result:= ExtractZstd(TempStream, OutStream); end; end; finally TempStream.Free; end; end; except Result:= False; end; end; function Deb_ExtractCtrlInfoFile(const DebFile: String; var DescFile: String): Boolean; var TA: TTarArchive; DirRec: TTarDirRec; OutStream: TMemoryStream; begin Result:= False; OutStream:= TMemoryStream.Create; try Result:= UnpackDebFile(DebFile, MEMBER_CONTROL, OutStream); if Result then try TA := TTarArchive.Create(OutStream); try while TA.FindNext(DirRec) do begin if (DirRec.Name = './control') or (DirRec.Name = '.\control') or (DirRec.Name = 'control') then begin DescFile:= TA.ReadFile; Result:= True; Break; end; end; finally TA.Free; end; except // Ignore end; finally OutStream.Free; end; end; initialization DebPkg := TDebianPackage.Create; finalization DebPkg.Free; end. ��������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/deb_wdx/src/dpkg_deb.pas�����������������������������������������������0000644�0001750�0000144�00000024763�14743153644�021554� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit dpkg_deb; //Debian Linux package unpacker implemented as TFileStream //v1.0.1 add option ReadAfterDataMember, to avoid unnecessary read after data.tar.gz interface uses Classes; const MEMBER_CONTROL = 1; MEMBER_DATA = 2; type ar_hdr = record //converted from /usr/include/ar.h ar_name: array [0..Pred(16)] of char; (* name *) ar_date: array [0..Pred(12)] of char; (* modification time *) ar_uid: array [0..Pred(6)] of char; (* user id *) ar_gid: array [0..Pred(6)] of char; (* group id *) ar_mode: array [0..Pred(8)] of char; (* octal file permissions *) ar_size: array [0..Pred(10)] of char; (* size in bytes *) ar_fmag: array [0..Pred(2)] of char; (* consistency check *) end; TDebianPackage = class private //FMemberList: array of ar_hdr; FPkgVersion: string; //FDebStrm: TFileStream; FCheckHeader : boolean; //constructor Create; override; //destructor Destory; override; FFileName : string; function DoCheckHeader(arh: ar_hdr; infobuf: PChar; memberlen: integer): boolean; //function GetFileList: TStrings; function ParseHeaderLength(inh: PChar; Len: integer): integer; function SkipMember(Strm: TStream; memberlen: integer): boolean; public FMemberList: array of ar_hdr; ReadAfterDataMember: boolean; constructor Create; function ReadFromFile(DebPkgFile: string): integer; function ExtractMemberToStream(MemberIdx: integer; OutputStrm: TStream): boolean; function ExtractMemberToFile(idx: integer; OutputFile: string): boolean; published property PkgVersion: string read FPkgVersion; property CheckHeader: boolean read FCheckHeader write FCheckHeader default false; //property MemberList: array of ar_hdr read FMemberList; default; //property FileList: TStrings read GetFileList; //property GetControlFile: //need tar+gzip to implement this end; implementation uses SysUtils{$IFDEF GDEBUG}, dbugintf {$ENDIF}; const (* Pre-4BSD archives had these magic numbers in them. *) OARMAG1 = $FF6D; OARMAG2 = $FF65; ARMAG = '!<arch>'#10; (* ar "magic number" *) SARMAG = 8; (* strlen(ARMAG); *) AR_EFMT1 = '#1/'; (* extended format #1 *) ARFMAG = '`'#10''; (* static void skipmember(FILE *ar, const char *fn, long memberlen) { int c; memberlen += (memberlen&1); while (memberlen > 0) { if ((c= getc(ar)) == EOF) readfail(ar,fn,"skipped member data"); memberlen--; } } *) function TDebianPackage.SkipMember(Strm: TStream; memberlen: integer): boolean; begin Result := false; Inc(memberlen, (memberlen and 1)); if Strm.Position + memberlen > Strm.Size then exit; Strm.Seek(memberlen, soFromCurrent); Result := true; end; //return the number of members found function TDebianPackage.ReadFromFile(DebPkgFile: string): integer; var debStrm: TFileStream; MagicHeaderBuf: array[0..10] of char; //memberbuf: PChar; verinfobuf : array [0..100] of char; arh: ar_hdr; memberlen, memberidx: integer; n: integer; begin Result := 0; SetLength(FMemberList, 0); //if not Assigned(DebStrm) then raise Exception.Create('Stream not assigned'); if not FileExists(DebPkgFile) then raise Exception.Create('File not exists!'); FFileName := DebPkgFile; debStrm := TFileStream.Create(DebPkgFile, fmOpenRead or fmShareDenyWrite); try //debStrm.LoadFromFile(DebPkgFile); if DebStrm.Size < sizeof(ARMAG) + 2*sizeof(ar_hdr) then raise Exception.Create('Size of file is too small. maybe its not a debian package'); DebStrm.Seek(0, soFromBeginning); //rewind DebStrm.Read(MagicHeaderBuf, SARMAG); if StrLComp(MagicHeaderBuf, ARMAG, SARMAG)=0 then //if MagicHeaderBuf='!<arch>\n' begin memberidx:=0; repeat n := DebStrm.Read(arh, sizeof(arh)); if n=0 then break else if n<sizeof(ar_hdr) then raise Exception.Create('corrputed package'); (* if (memcmp(arh.ar_fmag,ARFMAG,sizeof(arh.ar_fmag))) ohshit("file `%.250s' is corrupt - bad magic at end of first header",debar); *) if StrLComp(arh.ar_fmag, ARFMAG, sizeof(arh.ar_fmag))<>0 then raise Exception.Create('bad magic at end of first header'); memberlen := ParseHeaderLength(arh.ar_size, sizeof(arh.ar_size)); if memberlen<0 then raise Exception.Create('corrputed package'); //ohshit("file `%.250s' is corrupt - negative member length %ld",debar,memberlen); //save header (member info) into list SetLength(FMemberList, memberidx+1); FMemberList[memberidx] := arh; Inc(memberidx); if (memberidx=0) and FCheckHeader then //package header begin //GetMem(memberbuf, memberlen + 1); try //if DebStrm.Read(memberbuf, memberlen + (memberlen and 1))<memberlen then exit; //failed to read header info member if DebStrm.Read(verinfobuf, memberlen + (memberlen and 1))<memberlen then exit; {$IFDEF GDEBUG} SendDebug(StrPas(verinfobuf)); {$ENDIF} //if CheckHeader(arh, memberbuf, memberlen) then exit; if not DoCheckHeader(arh, verinfobuf, memberlen) then exit; finally //FreeMem(memberbuf, memberlen + 1); end; end else if (Trim(arh.ar_name)='data.tar.gz') and (not ReadAfterDataMember) then break else SkipMember(DebStrm, memberlen) until (DebStrm.Position>=DebStrm.Size); Result := memberidx + 1; end else if StrLComp(MagicHeaderBuf,'!<arch>',7)=0 then raise Exception.Create('Bad magic header. maybe it''s not a debian package') //"file looks like it might be an archive which has been\n" //"corrupted by being downloaded in ASCII mode.\n" else if StrLComp(MagicHeaderBuf,'0.93',4)=0 then raise Exception.Create('Old format debian package not supported') else raise Exception.Create('Bad magic header. maybe it''s not a debian package'); finally DebStrm.Free; end; end; function TDebianPackage.ExtractMemberToStream(MemberIdx: integer; OutputStrm: TStream): boolean; var idx, memberlen: integer; DebStrm : TFileStream; arh: ar_hdr; begin Result := false; if not Assigned(OutputStrm) then exit; if MemberIdx > High(FMemberList) then exit; DebStrm := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite); try DebStrm.Seek(SARMAG, soFromBeginning); //rewind to the first member idx := 0; while(idx<=memberidx) do begin arh := FMemberList[idx]; if DebStrm.Read(arh, sizeof(arh))<sizeof(ar_hdr) then raise Exception.Create('corrputed package'); memberlen := ParseHeaderLength(arh.ar_size, sizeof(arh.ar_size)); if memberlen<0 then raise Exception.Create('corrputed package'); //ohshit("file `%.250s' is corrupt - negative member length %ld",debar,memberlen); //if (idx=1) then //header // if ReadControlFile(DebStrm, arh, memberlen)<0 then raise.... if (idx=MemberIdx) then begin if OutputStrm.CopyFrom(DebStrm, memberlen)<memberlen then exit; Result := True; break; end else SkipMember(DebStrm, memberlen); Inc(idx); end; finally DebStrm.Free; end; end; function TDebianPackage.ExtractMemberToFile(idx: integer; OutputFile: string): boolean; var AFileStrm: TFileStream; begin Result := false; if idx>High(FMemberList) then exit; AFileStrm := TFileStream.Create(OutputFile, fmCreate or fmOpenWrite or fmShareDenyWrite); try Result := ExtractMemberToStream(idx, AFileStrm); finally AFileStrm.Free; end; end; function TDebianPackage.ParseHeaderLength(inh: PChar; Len: integer): integer; (*static unsigned long parseheaderlength(const char *inh, size_t len, const char *fn, const char *what) { char lintbuf[15]; unsigned long r; char *endp; if (memchr(inh,0,len)) ohshit("file `%.250s' is corrupt - %.250s length contains nulls",fn,what); assert(sizeof(lintbuf) > len); memcpy(lintbuf,inh,len); lintbuf[len]= ' '; *strchr(lintbuf,' ')= 0; r= strtoul(lintbuf,&endp,10); if ( *endp ) ohshit("file `%.250s' is corrupt - bad digit (code %d) in %s",fn,*endp,what); return r; *) var lintbuf: array[0..14] of char; begin if len> sizeof(lintbuf) then raise Exception.Create('ParseMemberLength'); StrLCopy(lintbuf, inh, len); lintbuf[len] := #0; StrScan(lintbuf, ' ')^ := #0; Result := StrToInt(StrPas(lintbuf)); end; //return the length of control.tar.gz (*function TDebianPackage.CheckControlFile(DebStrm: TMemoryStream; arh: ar_hdr; memberlen: integer; OutputFile: String): integer; begin end; *) //if any error encounted, return false function TDebianPackage.DoCheckHeader(arh: ar_hdr; infobuf: PChar; memberlen: integer): boolean; const DebianSign = 'debian-binary '; var verinfobuf: array[0..20] of char; cur: PChar; begin Result := false; if StrLComp(arh.ar_name, DebianSign, sizeof(arh.ar_name))<>0 then exit; //ohshit("file `%.250s' is not a debian binary archive (try dpkg-split?)",debar); //memberlen = ParseArchiveLength(arh.ar_size,sizeof(arh.ar_size)); infobuf[memberlen] := #0; cur := StrScan(infobuf, #10); if (cur=nil) then exit; //ohshit("archive has no newlines in header"); cur^ := #0; cur := StrScan(infobuf,'.'); if (cur=nil) then exit; //ohshit("archive has no dot in version number"); cur^ := #0; if (StrComp(infobuf,'2')<>0) then exit; //ohshit("archive version %.250s not understood, get newer " BACKEND, infobuf); cur^ := '.'; //restore version delimiter //StrLCopy(verinfobuf, infobuf, min(sizeof(verinfobuf)-1, memberlen); //got the package version info StrLCopy(verinfobuf, infobuf, sizeof(verinfobuf)-1); verinfobuf[sizeof(verinfobuf)-1] := #0; FPkgVersion := StrPas(verinfobuf); Result := true; end; constructor TDebianPackage.Create; begin CheckHeader := True; ReadAfterDataMember := false; end; end.�������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016551� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/src/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017340� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/src/rpm_def.pas������������������������������������������������0000644�0001750�0000144�00000005724�14743153644�021471� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** {$A-,I-} unit rpm_def; {$MODE Delphi} interface uses Classes; {$ifdef ver90} type longword=longint; {$endif} {$ifdef ver100} type longword=longint; {$endif} //values for TArchiveRec.headers (pseudo-files to show) const HDR_INFO = 0; HDR_DATA = 1; const MAX_PHANTOM_FILES = 13; const RPM_MAGIC = $DBEEABED; RPM_TYPE_BINARY = 0; // binary package type RPM_TYPE_SOURCE = 1; // source package type RPMSIG_PGP262_1024 = 1; RPMSIG_MD5 = 3; RPMSIG_MD5_PGP = 4; RPMSIG_HEADERSIG = 5; const RPMTAG_NAME = 1000; RPMTAG_VERSION = 1001; RPMTAG_RELEASE = 1002; RPMTAG_SUMMARY = 1004; RPMTAG_DESCRIPTION = 1005; RPMTAG_BUILDTIME = 1006; RPMTAG_DISTRIBUTION = 1010; RPMTAG_VENDOR = 1011; RPMTAG_LICENSE = 1014; RPMTAG_PACKAGER = 1015; RPMTAG_GROUP = 1016; RPMTAG_OS = 1021; RPMTAG_ARCH = 1022; RPMTAG_FILENAMES = 1027; RPMTAG_FILEMTIMES = 1034; RPMTAG_SOURCERPM = 1044; RPMTAG_ARCHIVESIZE = 1046; type RPM_EntryInfo = record tag : LongWord; etype : LongWord; offset : LongWord; count : LongWord; end;{EntryInfo} type RPM_Lead = record magic : LongWord; major_ver : Byte; minor_ver : Byte; rpmtype : Word; archnum : Word; name : array[1..66] of Char; osnum : Word; signature_type : Word; reserved : array[1..16] of Char; end;{RPM_Lead} RPM_Header =record magic : array [1..3] of byte; header_ver : Byte; reserved : array [1..4] of Byte; count : LongWord; data_size : LongWord; end;{RPM_Header} RPM_InfoRec = record name : AnsiString; // RPMTAG_NAME version : AnsiString; // RPMTAG_VERSION release : AnsiString; // RPMTAG_RELEASE summary : AnsiString; // RPMTAG_SUMMARY description : AnsiString; // RPMTAG_DESCRIPTION distribution : AnsiString; // RPMTAG_DISTRIBUTION buildtime : LongWord; // RPMTAG_BUILDTIME vendor : AnsiString; // RPMTAG_VENDOR license : AnsiString; // RPMTAG_LICENSE packager : AnsiString; // RPMTAG_PACKAGER group : AnsiString; // RPMTAG_GROUP os : AnsiString; // RPMTAG_OS arch : AnsiString; // RPMTAG_ARCH sourcerpm : AnsiString; // RPMTAG_SOURCERPM end;{RPM_Info} implementation end. ��������������������������������������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/src/rpm_io.pas�������������������������������������������������0000644�0001750�0000144�00000017247�14743153644�021345� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//*************************************************************** // This file is part of RPMWCX, a archiver plugin for // Windows Commander. // Copyright (C) 2000 Mandryka Yurij e-mail:braingroup@hotmail.ru //*************************************************************** //*************************************************************** // This code based on Christian Ghisler (support@ghisler.com) sources //*************************************************************** //*************************************************************** // This code was improved by Sergio Daniel Freue (sfreue@dc.uba.ar) //*************************************************************** {$A-,I-} unit rpm_io; {$MODE Delphi} interface uses SysUtils, rpm_def; type TStrBuf = array[1..260] of Char; function RPM_ReadLead(var f : file; var lead : RPM_Lead) : Boolean; function RPM_ReadSignature(var f : file; sig_type : Word; var signature : RPM_Header) : Boolean; function RPM_ReadHeader(var f : file; align_data : Boolean; var header : RPM_Header; var info : RPM_InfoRec) : Boolean; function RPM_ReadEntry(var f : file; data_start : LongInt; var entry : RPM_EntryInfo) : Boolean; function RPM_ProcessEntry(var f : file; data_start : LongInt; var entry : RPM_EntryInfo; var info : RPM_InfoRec) : Boolean; procedure swap_value(var value; size : Integer); procedure copy_str2buf(var buf : TStrBuf; s : AnsiString); function get_archivename(var fname : String;is_bz2file:boolean) : String; function read_string(var f : file; var s : AnsiString) : Boolean; function read_int32(var f : file; var int32 : LongWord) : Boolean; implementation uses Classes; procedure swap_value(var value; size:Integer); type byte_array = array[1..MaxInt] of Byte; var i : Integer; avalue : Byte; begin for i:=1 to size div 2 do begin avalue := byte_array(value)[i]; byte_array(value)[i] := byte_array(value)[size + 1 - i]; byte_array(value)[size + 1 - i] := avalue; end; end; procedure copy_str2buf(var buf : TStrBuf; s : AnsiString); var i_char : Integer; begin FillChar(buf, Sizeof(buf), 0); if Length(s) = 0 then Exit; if Length(s) > 259 then SetLength(s, 259); s := s + #0; for i_char := 1 to Length(s) do buf[i_char] := s[i_char]; end; function get_archivename(var fname : String;is_bz2file:boolean) : String; var tmp_str : String; i_char : Integer; fgFound : Boolean; begin tmp_str := ExtractFileName(fname); fgFound := False; for i_char := Length(tmp_str) downto 1 do if tmp_str[i_char] = '.' then begin fgFound := True; Break; end; if fgFound then SetLength(tmp_str, i_char - 1); if is_bz2file then tmp_str := tmp_str + '.cpio.bz2' else tmp_str := tmp_str + '.cpio.gz'; Result := tmp_str; end; function RPM_ReadLead; begin Result := False; BlockRead(f, lead, Sizeof(Lead)); if IOResult = 0 then Result := True; with lead do begin swap_value(rpmtype, 2); swap_value(archnum, 2); swap_value(osnum, 2); swap_value(signature_type, 2); end; end; function RPM_ReadHeader; var i_entry : LongWord; start : Integer; entry : RPM_EntryInfo; begin Result := False; BlockRead(f, header, Sizeof(header)); if IOResult = 0 then begin with header do begin swap_value(count, 4); swap_value(data_size, 4); start := FilePos(f) + LongInt(count) * Sizeof(entry); for i_entry := 0 to count - 1 do begin if not RPM_ReadEntry(f, start, entry) then Exit else if not RPM_ProcessEntry(f, start, entry, info) then Exit; end; end; start := start + LongInt(header.data_size); // Move file pointer on padded to a multiple of 8 bytes position if align_data then if (start mod 8) <> 0 then begin start := start and $FFFFFFF8; Inc(start, 8); end; Seek(f, start); Result := True; end; end; function RPM_ReadEntry; begin Result := False; BlockRead(f, entry, Sizeof(entry)); if IOResult = 0 then Result := True; with entry do begin swap_value(tag, 4); swap_value(etype, 4); swap_value(offset, 4); offset := data_start + LongInt(offset); swap_value(count, 4); end; end; function RPM_ReadSignature; var info : RPM_InfoRec; begin Result := False; case sig_type of RPMSIG_PGP262_1024 : ; // Old PGP signature RPMSIG_MD5 : ; // RPMSIG_MD5_PGP : ; // RPMSIG_HEADERSIG : // New header signature begin if RPM_ReadHeader(f, True, signature, info) then Result := True; end; end;{case signature type} end; procedure CRtoCRLF(var instr:string); var s:string; i,l:integer; ch,ch2:char; begin instr:=instr+' '; {Avoid overflow} l:=length(instr)-1; for i:=1 to l do begin ch:=instr[i]; ch2:=instr[i+1]; if ((ch=#13) and (ch2<>#10)) or ((ch=#10) and (ch2<>#13)) then s:=s+#13#10 else s:=s+ch; end; instr:=s; end; function RPM_ProcessEntry; var save_pos : Integer; fgError : Boolean; begin result:=true; if entry.tag = RPMTAG_FILENAMES then exit; fgError := False; save_pos := FilePos(f); Seek(f, entry.offset); if IOResult = 0 then begin case entry.tag of RPMTAG_NAME : if entry.etype = 6 then fgError := not read_string(f, info.name); RPMTAG_VERSION : if entry.etype = 6 then fgError := not read_string(f, info.version); RPMTAG_RELEASE : if entry.etype = 6 then fgError := not read_string(f, info.release); RPMTAG_SUMMARY : if entry.etype = 9 then fgError := not read_string(f, info.summary); RPMTAG_DESCRIPTION : if entry.etype = 9 then begin fgError := not read_string(f, info.description); if not fgError then CRtoCRLF(info.description); end; RPMTAG_BUILDTIME : if entry.etype = 4 then fgError := not read_int32(f, info.buildtime); RPMTAG_DISTRIBUTION : if entry.etype = 6 then fgError := not read_string(f, info.distribution); RPMTAG_VENDOR : if entry.etype = 6 then fgError := not read_string(f, info.vendor); RPMTAG_LICENSE : if entry.etype = 6 then fgError := not read_string(f, info.license); RPMTAG_PACKAGER : if entry.etype = 6 then fgError := not read_string(f, info.packager); RPMTAG_GROUP : if entry.etype = 9 then fgError := not read_string(f, info.group); RPMTAG_OS : if entry.etype = 6 then fgError := not read_string(f, info.os); RPMTAG_ARCH : if entry.etype = 6 then fgError := not read_string(f, info.arch); RPMTAG_SOURCERPM : if entry.etype = 6 then fgError := not read_string(f, info.sourcerpm); end;{case} end else fgError := True; Result := not fgError; Seek(f, save_pos); end; function read_string(var f : file; var s : AnsiString) : Boolean; var i_char : Char; fgError : Boolean; begin fgError := False; SetLength(s, 0); while not eof(f) do begin BlockRead(f, i_char, 1); if IOResult <> 0 then begin fgError := True; Break; end; if i_char = #0 then Break else s := s + i_char; end; Result := not fgError; end; function read_int32(var f : file; var int32 : LongWord) : Boolean; begin BlockRead(f, int32, Sizeof(LongWord)); swap_value(int32, Sizeof(LongWord)); if IOResult = 0 then Result := True else Result := False; end; procedure RPM_CreateInfoRec(var info : RPM_InfoRec); begin end; procedure RPM_DeleteInfoRec(var info : RPM_InfoRec); begin end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/src/rpm_wdx.dpr������������������������������������������������0000644�0001750�0000144�00000001556�14743153644�021536� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library rpm_wdx; {$MODE Delphi} { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. } uses SysUtils, Classes, rpm_io in 'rpm_io.pas', rpm_wdx_intf in 'rpm_wdx_intf.pas', rpm_def in 'rpm_def.pas'; {$E wdx} exports ContentGetDetectString, ContentGetSupportedField, ContentGetValue; {$R *.res} begin end. ��������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/src/rpm_wdx.lpi������������������������������������������������0000644�0001750�0000144�00000011567�14743153644�021540� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="RPM WDX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2012 Koblov Alexander"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\rpm_wdx.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="LCL"/> </Item1> </RequiredPackages> <Units Count="4"> <Unit0> <Filename Value="rpm_wdx.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="rpm_io.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="rpm_wdx_intf.pas"/> <IsPartOfProject Value="True"/> </Unit2> <Unit3> <Filename Value="rpm_def.pas"/> <IsPartOfProject Value="True"/> </Unit3> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\rpm_wdx.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> </CONFIG> �����������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/rpm_wdx/src/rpm_wdx_intf.pas�������������������������������������������0000644�0001750�0000144�00000012617�14743153644�022554� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit rpm_wdx_intf; {$mode delphi} {$include calling.inc} interface procedure ContentGetDetectString(DetectString:pchar; maxlen:integer); dcpcall; export; function ContentGetSupportedField(FieldIndex:integer; FieldName:pchar; Units:pchar;maxlen:integer):integer; dcpcall; export; function ContentGetValue(FileName:pchar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer; dcpcall; export; implementation uses SysUtils, WdxPlugin, rpm_io, rpm_def; const IDX_PACKAGE = 0; IDX_VERSION = 1; IDX_RELEASE = 2; IDX_DISTRIBUTION = 3; IDX_VENDER = 4; IDX_LICENSE = 5; IDX_PACKAGER = 6; IDX_GROUP = 7; IDX_OS = 8; IDX_ARCH = 9; IDX_SOURCE_RPM = 10; IDX_SUMMARY = 11; IDX_DESCRIPTION = 12; FIELDS_COUNT = 13; // IDX_BUILDTIME , // IDX_ARCHIVE_SIZE var CurrentPackageFile: String; FileInfoCache : RPM_InfoRec; //cache procedure ContentGetDetectString(DetectString:pchar; maxlen:integer); begin StrPCopy(DetectString, 'EXT="RPM"'); end; function ContentGetSupportedField(FieldIndex:integer; FieldName:pchar; Units:pchar;maxlen:integer):integer; var Field: String; begin StrPCopy(Units, ''); // if FieldIndex =IDX_ARCHIVE_SIZE then // begin // StrPCopy(FieldName, FieldList.Strings[FieldIndex]); // StrPCopy(Units, 'bytes|kbytes|Mbytes|Gbytes'+#0); // Result := FT_NUMERIC_64; // exit; // end // else if FieldIndex >= FIELDS_COUNT then begin Result := FT_NOMOREFIELDS; exit; end; Result := FT_STRING; case FieldIndex of IDX_PACKAGE: Field := 'Package'; IDX_VERSION: Field := 'Version'; IDX_RELEASE: Field := 'Release'; IDX_DISTRIBUTION:Field := 'Distribution'; IDX_VENDER: Field := 'Vender'; IDX_LICENSE: Field := 'License'; IDX_PACKAGER: Field := 'Packager'; IDX_GROUP: Field := 'Group'; IDX_OS: Field := 'OS'; IDX_ARCH: Field := 'Arch'; IDX_SOURCE_RPM: Field := 'Source-RPM'; IDX_SUMMARY: Field := 'Summary'; IDX_DESCRIPTION: Field := 'Description'; // IDX_BUILD_TIME: Field := 'Build-Time'; // IDX_ARCHIVE_SIZE: // begin // Field := 'Archive-Size'; // StrPCopy(FieldName, Field); // StrPCopy(Units, 'bytes|kbytes|Mbytes|Gbytes'+#0); // Result := FT_NUMERIC_64; // exit; end; StrPCopy(FieldName, Field); end; function ContentGetValue(FileName:pchar; FieldIndex,UnitIndex:integer; FieldValue:pbyte; maxlen,flags:integer):integer; function ReadRPMInfo(filename: String): integer; var fh: integer; fh_file: file; r_lead: RPM_Lead; signature, r_header: RPM_Header; //r_info: RPM_InfoRec; begin Result := -1; fh := FileOpen(filename, fmOpenRead or fmShareDenyNone); if fh=-1 then exit; AssignFile(fh_file, filename); try FileMode := 0; Reset(fh_file, 1); if IOResult <> 0 then exit; RPM_ReadLead(fh_file, r_lead); if r_lead.magic <> RPM_MAGIC then exit; if not RPM_ReadSignature(fh_file, r_lead.signature_type, signature) then exit; if not RPM_ReadHeader(fh_file, false, r_header, FileInfoCache) then exit; Result := 0; finally CloseFile(fh_file); FileClose(fh); //oppsition to FileOpen end; end; function EnsureLength(S: string; nMaxlen: integer): string; begin Result := S; if length(Result)>=nMaxlen then begin Result := Copy(Result, 1, nMaxlen-4); Result := Result + '...'; end; end; var Value : String; begin Result := FT_FILEERROR; if not FileExists(FileName) then exit; if CurrentPackageFile<>FileName then begin if ReadRPMInfo(FileName) <0 then exit; CurrentPackageFile := FileName; end {$IFDEF GDEBUG} else SendDebug('Cached info reused for '+FileName); {$ENDIF}; if (FieldIndex>=FIELDS_COUNT) then begin Result := FT_NOSUCHFIELD; exit; end; Result := FT_STRING; case FieldIndex of IDX_PACKAGE: Value := FileInfoCache.name; IDX_VERSION: Value := FileInfoCache.version; IDX_RELEASE: Value := FileInfoCache.release; IDX_DISTRIBUTION: Value := FileInfoCache.distribution; IDX_VENDER: Value := FileInfoCache.version; IDX_LICENSE: Value := FileInfoCache.license; IDX_PACKAGER: Value := FileInfoCache.packager; IDX_GROUP: Value := FileInfoCache.group; IDX_OS: Value := FileInfoCache.os; IDX_ARCH: Value := FileInfoCache.arch; IDX_SOURCE_RPM: Value := FileInfoCache.sourcerpm; IDX_SUMMARY: Value := FileInfoCache.summary; IDX_DESCRIPTION: Value := FileINfoCache.description; // IDX_BUILD_TIME: // //??? // IDX_ARCHIVE_SIZE: // Result := FT_NUMERIC_64; // size := FileInfoCache.archive_size; // case UnitIndex of // 0: //bytes // size := size * 1024; // // 1: //kbytes // // pass // 2: //mbytes // size := size div 1024; // 3: //gbytes // size := size div (1024 * 1024); // end; // exit; else Result := FT_FIELDEMPTY; exit; end; StrPCopy(PChar(FieldValue), EnsureLength(Value, maxlen)); end; initialization CurrentPackageFile := ''; end. �����������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/scripts/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016560� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/scripts/descriptionwdx.lua���������������������������������������������0000644�0001750�0000144�00000002126�14743153644�022332� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- This script reads file descriptions from descript.ion function ContentGetSupportedField(Index) if (Index > 0) then return '','', 0; -- ft_nomorefields end return 'Description','', 8; -- FieldName,Units,ft_string end function ContentGetDefaultSortOrder(FieldIndex) return 1; --or -1 end function ContentGetDetectString() return 'EXT="*"'; -- return detect string end function ContentGetValue(FileName, FieldIndex, UnitIndex, flags) if FieldIndex==0 then --Linux paths only local pat="/.*/" i,j=string.find(FileName,pat); if i~=nil then local path=string.sub(FileName,i,j); fn=string.sub(FileName,string.len(path)+1,-1); if fn~=".." then return GetDesc(path,fn); else return ""; end end end return nil; end function GetDesc(Path,Name) local f=io.open(Path..'descript.ion',"r"); if not f then return nil; end for line in f:lines() do if string.find(line,Name..' ') then f:close(); return string.sub(line,string.len(Name..' ')+1,-1); end end f:close(); return nil; end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/scripts/fulltextodtwdx.lua���������������������������������������������0000644�0001750�0000144�00000001213�14743153644�022361� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- Finds text in OpenDocument Text (.odt) -- Requires: odt2txt tool function ContentGetSupportedField(Index) if (Index == 0) then return 'Text','', 9; -- FieldName,Units,ft_fulltext end return '','', 0; -- ft_nomorefields end function ContentGetDetectString() return '(EXT="ODT")'; -- return detect string end function ContentGetValue(FileName, FieldIndex, UnitIndex, flags) if (FieldIndex > 0) then return nil; end if (UnitIndex == 0) then local f = io.popen ("odt2txt " .. FileName, 'r') if not f then return nil; end local ss = f:read("*a") f:close() return ss; end; return nil; end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/scripts/simplewdx.lua��������������������������������������������������0000644�0001750�0000144�00000002022�14743153644�021273� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- Simple example of how to write wdx-scripts function ContentSetDefaultParams(IniFileName,PlugApiVerHi,PlugApiVerLow) --Initialization code here end function ContentGetSupportedField(Index) if (Index == 0) then return 'FieldName0','', 8; -- FieldName,Units,ft_string elseif (Index == 1) then return 'FieldName1','', 8; elseif (Index == 2) then return 'FieldName2','', 8; end return '','', 0; -- ft_nomorefields end function ContentGetDefaultSortOrder(FieldIndex) return 1; --or -1 end function ContentGetDetectString() return '(EXT="TXT") | (EXT="INI")'; -- return detect string end function ContentGetValue(FileName, FieldIndex, UnitIndex, flags) if (FieldIndex == 0) then return "FieldValue0"; -- return string elseif (FieldIndex == 1) then return "FieldValue1"; elseif (FieldIndex == 2) then return "FieldValue2"; end return nil; -- invalid end --function ContentGetSupportedFieldFlags(FieldIndex) --return 0; -- return flags --end --function ContentStopGetValue(Filename) --end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/scripts/textlinewdx.lua������������������������������������������������0000644�0001750�0000144�00000001532�14743153644�021643� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ function ContentGetSupportedField(Index) if (Index == 0) then return 'Line1','', 8; -- FieldName,Units,ft_string elseif (Index == 1) then return 'Line2','', 8; elseif (Index == 2) then return 'Line3','', 8; elseif (Index == 3) then return 'Line4','', 8; elseif (Index == 4) then return 'Line5','', 8; end return '','', 0; -- ft_nomorefields end function ContentGetDetectString() return '(EXT="TXT") | (EXT="INI")'; -- return detect string end function ContentGetValue(FileName, FieldIndex, UnitIndex, flags) if (FieldIndex > 4) then return nil; end local f=io.open(FileName,"r"); if not f then return nil; end local ii = 0; for line in f:lines() do if (ii == FieldIndex) then f:close(); return line; end ii = ii + 1; end f:close(); return nil; end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/��������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016725� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/COPYING.GPL.txt�����������������������������������������������0000644�0001750�0000144�00000043254�14743153644�021227� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/COPYING.LESSER.txt��������������������������������������������0000644�0001750�0000144�00000063642�14743153644�021605� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! ����������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/README.txt����������������������������������������������������0000644�0001750�0000144�00000001130�14743153644�020416� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Text Line Content plugin for Double Commander Description ----------- Plugin is intended to show one line of a text file. You can select line number and text encoding, you can replace one substring by another. Settings are stored in textline.ini. Without settings file plugin don't skip empty lines and doesn't replace anything. textline.ini example: [Options] ;skip empty lines SkipEmpty=0 ;a list of substitutions in the format S<n>=<original_text>=<new_text> [Replaces] ;replace "hello" by nothing ;S1=hello= ;replace "test" by "hello" ;S2=test=hello S1= S2= S3= S4= S5= S6= S7= S8= S9= S10= ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/src/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017514� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/src/TextLine.lpi����������������������������������������������0000644�0001750�0000144�00000010164�14743153644�021760� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="TextLine"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <i18n> <EnableI18N LFM="False"/> </i18n> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../textline.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk;$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"/> </Modes> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> </RequiredPackages> <Units Count="1"> <Unit0> <Filename Value="TextLine.lpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../textline.wdx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk;$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wdx/textline/src/TextLine.lpr����������������������������������������������0000644�0001750�0000144�00000010425�14743153644�021771� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Wdx plugin is intended to show one line of a text file Copyright (C) 2016-2017 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } library TextLine; {$mode objfpc}{$H+} {$include calling.inc} uses SysUtils, Classes, StreamEx, LazUTF8, WdxPlugin, DCClassesUtf8, DCConvertEncoding, DCOSUtils; const DETECT_STRING = '(EXT="TXT") | (EXT="LOG") | (EXT="INI") | (EXT="XML")'; var FReplace: Boolean = False; FSkipEmpty: Boolean = False; FReplaces: array[1..10, 1..2] of String; function ContentGetSupportedField(FieldIndex: Integer; FieldName, Units: PAnsiChar; MaxLen: Integer): Integer; dcpcall; begin if (FieldIndex < 0) or (FieldIndex > 9) then begin Result := FT_NOMOREFIELDS; Exit; end; StrLCopy(FieldName, PAnsiChar(IntToStr(FieldIndex + 1)), MaxLen - 1); StrLCopy(Units, 'ANSI|OEM|UTF-8', MaxLen - 1); Result := FT_STRINGW; end; function ContentGetValueW(FileName: PWideChar; FieldIndex, UnitIndex: Integer; FieldValue: PWideChar; MaxLen, Flags: Integer): Integer; dcpcall; var Value: String; Index: Integer; FileNameU: String; Stream: TFileStreamEx; Reader: TStreamReader; begin if (FieldIndex < 0) or (FieldIndex > 9) then begin Result:= ft_nosuchfield; Exit; end; FileNameU:= UTF16ToUTF8(UnicodeString(FileName)); if not mbFileExists(FileNameU) then begin Result:= ft_fileerror; Exit; end; Result:= ft_fieldempty; try Stream:= TFileStreamEx.Create(FileNameU, fmOpenRead or fmShareDenyNone); try Index:= -1; Reader:= TStreamReader.Create(Stream, BUFFER_SIZE, True); repeat Value:= EmptyStr; if Reader.Eof then Break; Value:= Trim(Reader.ReadLine); if (Length(Value) = 0) and FSkipEmpty then Continue; Inc(Index); until Index = FieldIndex; finally Reader.Free; end; except Exit(ft_fileerror); end; if Value = EmptyStr then Exit; case UnitIndex of 0: Value:= CeAnsiToUtf8(Value); 1: Value:= CeOemToUtf8(Value); end; if FReplace and (Length(Value) > 0) then begin for Flags:= Low(FReplaces) to High(FReplaces) do begin if Length(FReplaces[Flags, 1]) > 0 then Value:= StringReplace(Value, FReplaces[Flags, 1], FReplaces[Flags, 2], [rfReplaceAll]); end; end; if Length(Value) > 0 then begin MaxLen:= MaxLen div SizeOf(WideChar) - 1; StrPLCopy(FieldValue, UTF8ToUTF16(Value), MaxLen); Result:= ft_stringw; end; end; procedure ContentSetDefaultParams(dps: PContentDefaultParamStruct); dcpcall; var S: String; Index: Integer; Ini: TIniFileEx; FileName: String; begin FileName:= CeSysToUtf8(dps^.DefaultIniName); FileName:= ExtractFilePath(FileName) + 'textline.ini'; try Ini:= TIniFileEx.Create(FileName, fmOpenRead); try FSkipEmpty:= Ini.ReadBool('Options', 'SkipEmpty', FSkipEmpty); for Index:= Low(FReplaces) to High(FReplaces) do begin S:= Ini.ReadString('Replaces', 'S' + IntToStr(Index), '='); FReplaces[Index, 1]:= Copy(S, 1, Pos('=', S) - 1); FReplaces[Index, 2]:= Copy(S, Pos('=', S) + 1, MaxInt); if (FReplace = False) then FReplace:= (S <> '='); end; finally Ini.Free; end; except // Ignore end; end; procedure ContentGetDetectString(DetectString: PAnsiChar; MaxLen: Integer); dcpcall; begin StrPLCopy(DetectString, DETECT_STRING, MaxLen - 1); end; exports ContentGetSupportedField, ContentGetValueW, ContentGetDetectString, ContentSetDefaultParams; begin end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/�����������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015073� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015664� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/COPYING.GPL.txt����������������������������������������������������0000644�0001750�0000144�00000043254�14743153644�020166� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/COPYING.LESSER.txt�������������������������������������������������0000644�0001750�0000144�00000063642�14743153644�020544� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! ����������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017447� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.be.po�������������������������������������������������0000644�0001750�0000144�00000010420�14743153644�021162� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n%100>=11 && n%100<=14 ? 2 : 3);\n" "X-Crowdin-Project: b5aaebc75354984d7cee90405a1f6642\n" "X-Crowdin-Project-ID: 7\n" "X-Crowdin-Language: be\n" "X-Crowdin-File: /l10n_Translation/plugins/wfx/ftp/language/ftp.po\n" "X-Crowdin-File-ID: 3352\n" "Project-Id-Version: b5aaebc75354984d7cee90405a1f6642\n" "Language-Team: Belarusian\n" "Language: be_BY\n" "PO-Revision-Date: 2022-09-25 05:45\n" #: tdialogbox.btnadd.caption msgid "+" msgstr "+" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "Ананімна" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "Скасаваць" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "Змяніць пароль..." #: tdialogbox.btndelete.caption msgid "-" msgstr "-" #: tdialogbox.btnok.caption msgid "&OK" msgstr "&Добра" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "Капіяваць з дапамогай пратакола SCP (хутчэй)" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "Падтрымліваць злучэнне падчас перадачы" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "Выкарыcтоўваць &галоўны пароль для абароны пароля" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "Пасіўны рэжым &перадачы (як вэб-браўзер)" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "Выкарыcтоўваць 'LIST -la' для схаваных элементаў" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "Аўтаматычна" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "Аўтэнтыфікацыя па кліенцкім сертыфікаце:" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "Злучэнне праз проксі" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "SSH" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "Кадаванне:" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "Сервер [:Порт]:" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "Адправіць &загады:" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "&Назва злучэння:" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "&Пароль:" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "Файл прыватнага ключа (*.pem):" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "Пратакол:" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "&Выкарыcтоўваць проксі-сервер" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "&Назва хоста:" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "&Пароль:" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "&Імя карыстальніка:" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "Файл публічнага ключа (*.pub):" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "A&длеглы каталог:" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "&Імя карыстальніка:" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "Спосаб злучэння" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "Дадатковыя" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "Асноўныя" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "Проксі" #: tfrmfileproperties.caption msgid "Properties" msgstr "" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.de.po�������������������������������������������������0000644�0001750�0000144�00000007544�14743153644�021201� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Project-Id-Version: Double Commander Plugin 'ftp'\n" "POT-Creation-Date: \n" "PO-Revision-Date: 2024-11-01 18:01+0100\n" "Last-Translator: ㋡ <braass@mail.de>\n" "Language-Team: \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0.1\n" #: tdialogbox.btnadd.caption msgid "+" msgstr "+" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "Anonym" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "Abbrechen" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "Passwort ändern ..." #: tdialogbox.btndelete.caption msgid "-" msgstr "-" #: tdialogbox.btnok.caption msgid "&OK" msgstr "&OK" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "SSH-Agent-Authentifizierung verwenden" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "Kopieren mit SCP (Secure Copy Protocol) -> schneller" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "'Keepalive'-Pakete senden aktivieren" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "Master-Passwort zum Schutz des Passworts verwenden" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "Passiven Modus für Übertragungen verwenden (wie ein Web-Browser)" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "'LIST -la' verwenden um verborgene Elemente anzuzeigen" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "Auto" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "Client-Zertifikat für die Authentifizierung:" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "Firewall-Anmeldung" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "SSH" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "Kodierung:" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "Host[:Port]:" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "Startbefehle:" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "Verbindungsname:" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "Passwort:" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "Datei mit privatem Schlüssel (*.pem):" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "Protokoll:" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "Firewall aktivieren (Proxy-Server)" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "Rechnername:" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "&Passwort:" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "Ben&utzername:" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "Datei mit öffentlichem Schlüssel (*.pub):" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "Remote-Verzeichnis:" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "Benutzername:" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "Verbindungsmethode" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "Weiterführend" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "Allgemein" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "Proxy" #: tfrmfileproperties.caption msgid "Properties" msgstr "Eigenschaften" ������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.hu.po�������������������������������������������������0000644�0001750�0000144�00000007360�14743153644�021221� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Project-Id-Version: Double Commander FTP WFX plugin\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Forge Studios Ltd. < kroy <kroysoft@citromail.hu>>\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: hu\n" "X-Generator: Poedit 1.8.8\n" #: tdialogbox.btnadd.caption msgid "+" msgstr "+" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "Vendég" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "Mégsem" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "Jelszó módosítása..." #: tdialogbox.btndelete.caption msgid "-" msgstr "-" #: tdialogbox.btnok.caption msgid "&OK" msgstr "&OK" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "SCP protokoll a másoláshoz (gyorsabb)" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "Életjel küldése az átvitel alatt" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "Mesterjelszóval védett jelszó használata" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "Passzív módú átvitel használata (mint egy WWW böngésző)" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "A 'LIST -la' parancs mutassa a rejtett elemeket" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "Automatikus" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "Ügyfél hitelesítő tanúsítványa:" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "Tűzfal belépés" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "SSH" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "Kódolás:" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "Kiszolgáló[:port]:" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "Kezdőparancsok:" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "Kapcsolat neve:" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "Jelszó:" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "Privát kulcs fájl (*.pub):" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "Protokoll:" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "Tűzfal használata (proxy kiszolgáló)" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "&Kiszolgálónév:" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "&Jelszó:" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "&Felhasználónév:" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "Publikus kulcs fájl (*.pub):" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "Távoli könyvtár:" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "Felhasználónév:" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "Csatlakozás módja" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "Haladó" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "Általános" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "Proxy" #: tfrmfileproperties.caption msgid "Properties" msgstr "" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.ko.po�������������������������������������������������0000644�0001750�0000144�00000007231�14743153644�021213� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: VenusGirl: https://venusgirls.tistory.com/\n" "Language-Team: 비너스걸: https://venusgirls.tistory.com/\n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Native-Language: 한국어\n" "X-Generator: Poedit 3.4.2\n" #: tdialogbox.btnadd.caption msgid "+" msgstr "+" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "익명" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "취소" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "암호 변경..." #: tdialogbox.btndelete.caption msgid "-" msgstr "-" #: tdialogbox.btnok.caption msgid "&OK" msgstr "확인(&O)" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "SSH 에이전트 인증 사용" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "SCP 프로토콜을 사용한 복사 (더 빠름)" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "전송 중 킵얼라이브 전송" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "마스터 암호를 사용하여 암호 보호" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "전송 시 패시브 모드 사용 (예: WWW 브라우저)" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "'LIST -la' 명령을 사용하여 숨겨진 항목 표시" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "자동" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "인증을 위한 클라이언트 인증서:" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "방화벽 로그온" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "SSH" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "인코딩:" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "호스트[:포트]:" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "초기화 명령:" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "연결 이름:" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "암호:" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "개인 키 파일 (*.pem):" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "프로토콜:" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "방화벽 (프록시 서버) 사용" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "호스트 이름(&H):" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "암호(&P):" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "사용자 이름(&U):" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "개인 키 파일 (*.pub):" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "원격 디렉터리:" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "사용자 이름:" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "연결 방법" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "고급" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "일반" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "프록시" #: tfrmfileproperties.caption msgid "Properties" msgstr "속성" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.pot���������������������������������������������������0000644�0001750�0000144�00000005452�14743153644�020772� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.btnadd.caption msgid "+" msgstr "" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "" #: tdialogbox.btndelete.caption msgid "-" msgstr "" #: tdialogbox.btnok.caption msgid "&OK" msgstr "" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "" #: tfrmfileproperties.caption msgid "Properties" msgstr "" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.ru.po�������������������������������������������������0000644�0001750�0000144�00000007644�14743153644�021240� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.btnadd.caption msgid "+" msgstr "+" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "Анонимно" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "Отмена" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "Изменить пароль..." #: tdialogbox.btndelete.caption msgid "-" msgstr "-" #: tdialogbox.btnok.caption msgid "&OK" msgstr "&ОК" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "Использовать SSH-агент" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "Копировать используя протокол SCP (быстрее)" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "Поддерживать соединение во время передачи" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "Использовать &главный пароль для защиты пароля" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "Пассивный режим о&бмена (как Web-браузер)" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "Использовать 'LIST -la' для скрытых элементов" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "Аутентификация по клиентскому сертификату:" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "FTP" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "Соединение через прокси" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "SSH" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "Кодировка:" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "Сервер [:Порт]:" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "Послать &команды:" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "Им&я соединения:" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "&Пароль:" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "Файл приватного ключа (*.pem):" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "Протокол:" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "&Использовать прокси-сервер" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "Сервер [:Порт]:" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "&Пароль:" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "&Имя пользователя:" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "Файл публичного ключа (*.pub):" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "Уд&алённый каталог:" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "&Имя пользователя:" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "Способ соединения" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "Расширенные" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "Общие" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "Прокси" #: tfrmfileproperties.caption msgid "Properties" msgstr "Свойства" ��������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/language/ftp.zh_CN.po����������������������������������������������0000644�0001750�0000144�00000006454�14743153644�021611� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: tdialogbox.btnadd.caption msgid "+" msgstr "" #: tdialogbox.btnanonymous.caption msgid "Anonymous" msgstr "匿名" #: tdialogbox.btncancel.caption msgid "Cancel" msgstr "取消" #: tdialogbox.btnchangepassword.caption msgid "Change password..." msgstr "更改密码..." #: tdialogbox.btndelete.caption msgid "-" msgstr "" #: tdialogbox.btnok.caption msgid "&OK" msgstr "确定(&O)" #: tdialogbox.caption msgctxt "tdialogbox.caption" msgid "FTP" msgstr "" #: tdialogbox.chkagentssh.caption msgid "Use SSH-agent authentication" msgstr "" #: tdialogbox.chkcopyscp.caption msgid "Copy using SCP protocol (faster)" msgstr "使用 SCP 协议复制(更快)" #: tdialogbox.chkkeepalivetransfer.caption msgid "Send keepalive during a transfer" msgstr "在传输期间发送 keepalive" #: tdialogbox.chkmasterpassword.caption msgid "Use master password to protect the password" msgstr "使用主密码保护密码" #: tdialogbox.chkpassivemode.caption msgid "Use passive mode for transfers (like a WWW browser)" msgstr "使用被动模式进行传输(像 WWW浏览器)" #: tdialogbox.chkshowhidden.caption msgid "Use 'LIST -la' command to reveal hidden items" msgstr "使用'LIST -la'命令来显示隐藏的项目" #: tdialogbox.cmbencoding.text msgid "Auto" msgstr "自动" #: tdialogbox.dividerbevel.caption msgid "Client certificate for authentication:" msgstr "用于身份验证的客户端证书:" #: tdialogbox.gbftp.caption msgctxt "tdialogbox.gbftp.caption" msgid "FTP" msgstr "" #: tdialogbox.gblogon.caption msgid "Firewall logon" msgstr "防火墙登录" #: tdialogbox.gbssh.caption msgctxt "tdialogbox.gbssh.caption" msgid "SSH" msgstr "" #: tdialogbox.lblencoding.caption msgid "Encoding:" msgstr "编码:" #: tdialogbox.lblhost.caption msgid "Host[:Port]:" msgstr "主机[:端口]:" #: tdialogbox.lblinitcommands.caption msgid "Init commands:" msgstr "初始化命令:" #: tdialogbox.lblname.caption msgid "Connection name:" msgstr "连接名称:" #: tdialogbox.lblpassword.caption msgid "Password:" msgstr "密码:" #: tdialogbox.lblprivatekey.caption msgid "Private key file (*.pem):" msgstr "私钥文件(*.pem):" #: tdialogbox.lblprotocol.caption msgid "Protocol:" msgstr "协议:" #: tdialogbox.lblproxy.caption msgid "Use firewall (proxy server)" msgstr "使用防火墙(代理服务器)" #: tdialogbox.lblproxyhost.caption msgid "&Host name:" msgstr "主机名(&H):" #: tdialogbox.lblproxypassword.caption msgid "&Password:" msgstr "密码(&P):" #: tdialogbox.lblproxyuser.caption msgid "&User name:" msgstr "用户名(&U):" #: tdialogbox.lblpublickey.caption msgid "Public key file (*.pub):" msgstr "公钥文件(*.pub):" #: tdialogbox.lblremotedir.caption msgid "Remote dir:" msgstr "远程目录:" #: tdialogbox.lblusername.caption msgid "User name:" msgstr "用户名:" #: tdialogbox.rgproxytype.caption msgid "Connect method" msgstr "连接方式" #: tdialogbox.tsadvanced.caption msgid "Advanced" msgstr "高级" #: tdialogbox.tsgeneral.caption msgid "General" msgstr "常规" #: tdialogbox.tsproxy.caption msgid "Proxy" msgstr "代理" #: tfrmfileproperties.caption msgid "Properties" msgstr "" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016453� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/FtpConfDlg.lfm�������������������������������������������������0000644�0001750�0000144�00000050731�14743153644�021147� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object DialogBox: TDialogBox Left = 431 Height = 482 Top = 141 Width = 440 AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'FTP' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ClientHeight = 482 ClientWidth = 440 OnShow = DialogBoxShow Position = poScreenCenter LCLVersion = '3.3.0.0' object btnCancel: TButton AnchorSideTop.Control = PageControl AnchorSideTop.Side = asrBottom AnchorSideRight.Control = PageControl AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 355 Height = 25 Top = 438 Width = 75 Anchors = [akTop, akRight] BorderSpacing.Top = 12 Cancel = True Caption = 'Cancel' ModalResult = 2 TabOrder = 2 OnClick = ButtonClick end object btnOK: TButton AnchorSideTop.Control = btnCancel AnchorSideRight.Control = btnCancel AnchorSideBottom.Side = asrBottom Left = 268 Height = 25 Top = 438 Width = 75 Anchors = [akTop, akRight] BorderSpacing.Right = 12 Caption = '&OK' TabOrder = 1 OnClick = ButtonClick end object PageControl: TPageControl AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 10 Height = 416 Top = 10 Width = 420 ActivePage = tsGeneral TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' ClientHeight = 381 ClientWidth = 416 object lblName: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = edtName AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 16 Width = 112 BorderSpacing.Left = 12 Caption = 'Connection name:' ParentColor = False end object edtName: TEdit AnchorSideLeft.Control = lblName AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = tsGeneral AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 12 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 18 BorderSpacing.Top = 12 BorderSpacing.Right = 12 TabOrder = 0 end object lblHost: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = edtHost AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 48 Width = 70 BorderSpacing.Left = 12 Caption = 'Host[:Port]:' ParentColor = False end object edtHost: TEdit AnchorSideLeft.Control = edtName AnchorSideTop.Control = edtName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtName AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 44 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 1 end object lblProtocol: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = cmbProtocol AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 74 Width = 48 BorderSpacing.Left = 12 Caption = 'Protocol:' end object cmbProtocol: TComboBox AnchorSideLeft.Control = edtHost AnchorSideTop.Control = edtHost AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtHost AnchorSideRight.Side = asrBottom Left = 128 Height = 23 Top = 70 Width = 274 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ItemHeight = 15 Items.Strings = ( 'FTP' 'FTPS' 'FTPES' 'SSH+SCP' 'SFTP' ) Style = csDropDownList TabOrder = 2 OnChange = ComboBoxChange end object lblUserName: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 111 Width = 71 BorderSpacing.Left = 12 Caption = 'User name:' ParentColor = False end object edtUserName: TEdit AnchorSideLeft.Control = btnAnonymous AnchorSideTop.Control = btnAnonymous AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnAnonymous AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 107 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 4 end object btnAnonymous: TButton AnchorSideLeft.Control = edtHost AnchorSideTop.Control = cmbProtocol AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtHost AnchorSideRight.Side = asrBottom Left = 142 Height = 25 Top = 76 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = 'Anonymous' TabOrder = 3 OnClick = ButtonClick end object edtRemoteDir: TEdit AnchorSideLeft.Control = edtPassword AnchorSideTop.Control = cmbEncoding AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtPassword AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 235 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 9 end object lblRemoteDir: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = edtRemoteDir AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 239 Width = 71 BorderSpacing.Left = 12 Caption = 'Remote dir:' ParentColor = False end object edtPassword: TEdit AnchorSideLeft.Control = edtUserName AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtUserName AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 139 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 EchoMode = emPassword PasswordChar = '*' TabOrder = 5 end object lblPassword: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = edtPassword AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 143 Width = 63 BorderSpacing.Left = 12 Caption = 'Password:' ParentColor = False end object chkMasterPassword: TCheckBox AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = lblPassword AnchorSideTop.Side = asrBottom Left = 12 Height = 24 Top = 173 Width = 306 BorderSpacing.Left = 12 BorderSpacing.Top = 12 Caption = 'Use master password to protect the password' TabOrder = 7 OnChange = CheckBoxChange end object btnChangePassword: TButton AnchorSideLeft.Control = edtUserName AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtUserName AnchorSideRight.Side = asrBottom Left = 142 Height = 25 Top = 139 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = 'Change password...' TabOrder = 6 Visible = False OnClick = ButtonClick end object edtInitCommands: TEdit AnchorSideLeft.Control = edtRemoteDir AnchorSideTop.Control = edtRemoteDir AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtRemoteDir AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 267 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 10 end object lblInitCommands: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = edtInitCommands AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 271 Width = 96 BorderSpacing.Left = 12 Caption = 'Init commands:' ParentColor = False end object cmbEncoding: TComboBox AnchorSideLeft.Control = edtPassword AnchorSideTop.Control = chkMasterPassword AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtPassword AnchorSideRight.Side = asrBottom Left = 142 Height = 26 Top = 203 Width = 264 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ItemHeight = 18 ItemIndex = 0 Items.Strings = ( 'Auto' 'UTF-8' 'CP1250' 'CP1251' 'CP1252' 'CP1253' 'CP1254' 'CP1255' 'CP1256' 'CP1257' 'CP1258' 'CP437' 'CP850' 'CP852' 'CP866' 'CP874' 'CP932' 'CP936' 'CP949' 'CP950' 'KOI8-R' 'ISO-8859-1' 'ISO-8859-2' 'ISO-8859-15' ) Style = csDropDownList TabOrder = 8 Text = 'Auto' end object lblEncoding: TLabel AnchorSideLeft.Control = tsGeneral AnchorSideTop.Control = cmbEncoding AnchorSideTop.Side = asrCenter Left = 12 Height = 18 Top = 207 Width = 61 BorderSpacing.Left = 12 Caption = 'Encoding:' ParentColor = False end end object tsAdvanced: TTabSheet Caption = 'Advanced' ClientHeight = 388 ClientWidth = 412 object gbFTP: TGroupBox AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = tsAdvanced AnchorSideRight.Control = tsAdvanced AnchorSideRight.Side = asrBottom Left = 6 Height = 89 Top = 6 Width = 400 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = 'FTP' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 62 ClientWidth = 394 TabOrder = 0 object chkPassiveMode: TCheckBox AnchorSideLeft.Control = gbFTP AnchorSideTop.Control = gbFTP Left = 6 Height = 19 Top = 6 Width = 299 Caption = 'Use passive mode for transfers (like a WWW browser)' Checked = True State = cbChecked TabOrder = 0 end object chkShowHidden: TCheckBox AnchorSideLeft.Control = chkPassiveMode AnchorSideTop.Control = chkPassiveMode AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 25 Width = 265 Caption = 'Use ''LIST -la'' command to reveal hidden items' TabOrder = 1 end object chkKeepAliveTransfer: TCheckBox AnchorSideLeft.Control = chkPassiveMode AnchorSideTop.Control = chkShowHidden AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 44 Width = 188 Caption = 'Send keepalive during a transfer' TabOrder = 2 end end object gbSSH: TGroupBox AnchorSideLeft.Control = gbFTP AnchorSideTop.Control = gbFTP AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFTP AnchorSideRight.Side = asrBottom Left = 6 Height = 204 Top = 101 Width = 400 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'SSH' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 184 ClientWidth = 396 TabOrder = 1 object chkAgentSSH: TCheckBox AnchorSideLeft.Control = gbSSH AnchorSideTop.Control = gbSSH Left = 6 Height = 19 Top = 6 Width = 178 Caption = 'Use SSH-agent authentication' TabOrder = 0 end object chkCopySCP: TCheckBox AnchorSideLeft.Control = gbSSH AnchorSideTop.Control = chkAgentSSH AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 25 Width = 192 Caption = 'Copy using SCP protocol (faster)' TabOrder = 1 end object DividerBevel: TDividerBevel AnchorSideTop.Control = chkCopySCP AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbSSH AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 50 Width = 384 Caption = 'Client certificate for authentication:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ParentFont = False end object lblPublicKey: TLabel AnchorSideLeft.Control = gbSSH AnchorSideTop.Control = DividerBevel AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 71 Width = 116 BorderSpacing.Top = 6 Caption = 'Public key file (*.pub):' ParentColor = False end object fnePublicKey: TFileNameEdit AnchorSideLeft.Control = gbSSH AnchorSideTop.Control = lblPublicKey AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbSSH AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 90 Width = 384 FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 MaxLength = 0 TabOrder = 2 end object lblPrivateKey: TLabel AnchorSideLeft.Control = gbSSH AnchorSideTop.Control = fnePublicKey AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 117 Width = 122 BorderSpacing.Top = 4 Caption = 'Private key file (*.pem):' ParentColor = False end object fnePrivateKey: TFileNameEdit AnchorSideLeft.Control = gbSSH AnchorSideTop.Control = lblPrivateKey AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbSSH AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 136 Width = 384 FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 MaxLength = 0 TabOrder = 3 end end end object tsProxy: TTabSheet Caption = 'Proxy' ClientHeight = 388 ClientWidth = 412 object pnlProxy: TPanel Left = 0 Height = 56 Top = 0 Width = 412 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ClientHeight = 56 ClientWidth = 412 TabOrder = 0 object lblProxy: TLabel AnchorSideLeft.Control = pnlProxy AnchorSideTop.Control = pnlProxy Left = 4 Height = 15 Top = 4 Width = 134 Caption = 'Use firewall (proxy server)' ParentColor = False end object cmbProxy: TComboBox AnchorSideLeft.Control = pnlProxy AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnAdd Left = 4 Height = 23 Top = 28 Width = 339 Anchors = [akTop, akLeft, akRight] ItemHeight = 26 Style = csDropDownList TabOrder = 0 OnChange = ComboBoxChange end object btnAdd: TBitBtn AnchorSideTop.Control = cmbProxy AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnDelete Left = 343 Height = 25 Top = 27 Width = 34 Anchors = [akTop, akRight] AutoSize = True Caption = '+' Font.Style = [fsBold] OnClick = ButtonClick ParentFont = False TabOrder = 1 end object btnDelete: TBitBtn AnchorSideTop.Control = cmbProxy AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlProxy AnchorSideRight.Side = asrBottom Left = 377 Height = 25 Top = 27 Width = 31 Anchors = [akTop, akRight] AutoSize = True Caption = '-' Font.Style = [fsBold] OnClick = ButtonClick ParentFont = False TabOrder = 2 end end object rgProxyType: TRadioGroup AnchorSideLeft.Control = tsProxy AnchorSideTop.Control = pnlProxy AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsProxy AnchorSideRight.Side = asrBottom Left = 0 Height = 77 Top = 56 Width = 412 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'Connect method' ChildSizing.LeftRightSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 50 ClientWidth = 406 Items.Strings = ( 'SOCKS4' 'SOCKS5' 'HTTP CONNECT' ) TabOrder = 1 end object gbLogon: TGroupBox AnchorSideLeft.Control = tsProxy AnchorSideTop.Control = rgProxyType AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsProxy AnchorSideRight.Side = asrBottom Left = 0 Height = 101 Top = 133 Width = 412 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Firewall logon' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 74 ClientWidth = 406 TabOrder = 2 object lblProxyHost: TLabel Left = 6 Height = 23 Top = 6 Width = 189 Caption = '&Host name:' ParentColor = False end object edtProxyHost: TEdit Left = 195 Height = 23 Top = 6 Width = 207 TabOrder = 0 end object lblProxyUser: TLabel Left = 6 Height = 23 Top = 29 Width = 189 Caption = '&User name:' ParentColor = False end object edtProxyUser: TEdit Left = 195 Height = 23 Top = 29 Width = 207 TabOrder = 1 end object lblProxyPassword: TLabel Left = 6 Height = 23 Top = 52 Width = 189 Caption = '&Password:' ParentColor = False end object edtProxyPassword: TEdit Left = 195 Height = 23 Top = 52 Width = 207 TabOrder = 2 end end end end end ���������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/FtpConfDlg.pas�������������������������������������������������0000644�0001750�0000144�00000045015�14743153644�021153� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Wfx plugin for working with File Transfer Protocol Copyright (C) 2009-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit FtpConfDlg; {$mode objfpc}{$H+} {$include calling.inc} {$R FtpConfDlg.lfm} interface uses SysUtils, Extension, FtpFunc; function ShowFtpConfDlg(Connection: TConnection): Boolean; implementation uses LazUTF8, DynLibs, FtpUtils, blcksock, synaip, ssl_openssl_lib, libssh, FtpProxy, TypInfo; var Protocol: PtrInt; ProxyIndex: Integer; gConnection: TConnection; procedure ShowWarningSSL; begin with gStartupInfo do begin MessageBox(PAnsiChar('OpenSSL library not found!' + LineEnding + 'To use SSL connections, please install the OpenSSL ' + 'libraries (' + DLLSSLName + ' and ' + DLLUtilName + ')!'), 'OpenSSL', MB_OK or MB_ICONERROR ); end; end; procedure ShowWarningSSH; begin with gStartupInfo do begin MessageBox(PAnsiChar('LibSSH2 library not found!' + LineEnding + 'To use SSH2 connections, please install the LibSSH2 ' + 'library (' + LibSSHName + ')!'), 'LibSSH2', MB_OK or MB_ICONERROR ); end; end; procedure EnableControls(pDlg: PtrUInt); begin with gStartupInfo do begin SendDlgMsg(pDlg, 'gbSSH', DM_ENABLE, PtrInt(gConnection.OpenSSH), 0); SendDlgMsg(pDlg, 'gbFTP', DM_ENABLE, PtrInt(not gConnection.OpenSSH), 0); if not gConnection.OpenSSH then begin SendDlgMsg(pDlg, 'chkCopySCP', DM_SETCHECK, 0, 0); SendDlgMsg(pDlg, 'chkAgentSSH', DM_SETCHECK, 0, 0); end else begin SendDlgMsg(pDlg, 'chkShowHidden', DM_SETCHECK, 0, 0); SendDlgMsg(pDlg, 'chkPassiveMode', DM_SETCHECK, 0, 0); SendDlgMsg(pDlg, 'chkKeepAliveTransfer', DM_SETCHECK, 0, 0); SendDlgMsg(pDlg, 'chkCopySCP', DM_ENABLE, PtrInt(not gConnection.OnlySCP), 0); end; end; end; function CreateProxyID: String; var Guid: TGuid; begin if CreateGUID(Guid) = 0 then Result := GUIDToString(Guid) else Result := IntToStr(Random(MaxInt)); end; function GetProxyName(Proxy: TFtpProxy): String; begin Result:= Proxy.Host; if Proxy.Port <> '' then Result+= ':' + Proxy.Port; Result+= ' (' + GetEnumName(TypeInfo(TProxyType), Integer(Proxy.ProxyType)) + ')'; end; procedure LoadProxy(pDlg: PtrUInt); var Data: PtrInt; Text: String; Proxy: TFtpProxy; begin with gStartupInfo do begin if (ProxyIndex > 0) then begin Proxy:= TFtpProxy(SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETDATA, ProxyIndex, 0)); SendDlgMsg(pDlg, 'rgProxyType', DM_LISTSETITEMINDEX, PtrInt(Proxy.ProxyType) - 1, 0); Text:= Proxy.Host; if Proxy.Port <> EmptyStr then Text+= ':' + Proxy.Port; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtProxyHost', DM_SETTEXT, Data, 0); Data:= PtrInt(PAnsiChar(Proxy.User)); SendDlgMsg(pDlg, 'edtProxyUser', DM_SETTEXT, Data, 0); Data:= PtrInt(PAnsiChar(Proxy.Password)); SendDlgMsg(pDlg, 'edtProxyPassword', DM_SETTEXT, Data, 0); end else begin SendDlgMsg(pDlg, 'rgProxyType', DM_LISTSETITEMINDEX, 0, 0); SendDlgMsg(pDlg, 'edtProxyHost', DM_SETTEXT, 0, 0); SendDlgMsg(pDlg, 'edtProxyUser', DM_SETTEXT, 0, 0); SendDlgMsg(pDlg, 'edtProxyPassword', DM_SETTEXT, 0, 0); end; SendDlgMsg(pDlg, 'gbLogon', DM_ENABLE, ProxyIndex, 0); SendDlgMsg(pDlg, 'rgProxyType', DM_ENABLE, ProxyIndex, 0); SendDlgMsg(pDlg, 'btnDelete', DM_ENABLE, ProxyIndex, 0); end; end; procedure UpdateProxy(pDlg: PtrUInt); var Data: PtrInt; Text: String; Proxy: TFtpProxy; begin if (ProxyIndex > 0) then begin with gStartupInfo do begin Proxy:= TFtpProxy(SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETDATA, ProxyIndex, 0)); Data:= SendDlgMsg(pDlg, 'rgProxyType', DM_LISTGETITEMINDEX, 0, 0); Proxy.ProxyType:= TProxyType(Data + 1); Text:= PAnsiChar(SendDlgMsg(pDlg, 'edtProxyHost', DM_GETTEXT, 0, 0)); Proxy.Host:= ExtractConnectionHost(Text); Proxy.Port:= ExtractConnectionPort(Text); if Length(Text) > 0 then begin Text:= GetProxyName(Proxy); Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'cmbProxy', DM_LISTUPDATE, ProxyIndex, Data); end; Data:= SendDlgMsg(pDlg, 'edtProxyUser', DM_GETTEXT, 0, 0); Proxy.User:= PAnsiChar(Data); Data:= SendDlgMsg(pDlg, 'edtProxyPassword', DM_GETTEXT, 0, 0); Proxy.Password:= PAnsiChar(Data); end; end; end; procedure LoadProxyList(pDlg: PtrUInt); var Data: PtrInt; Text: String; Index: Integer; Proxy: TFtpProxy; begin ProxyIndex:= ProxyList.IndexOf(gConnection.Proxy) + 1; with gStartupInfo do begin Data:= PtrInt(PAnsiChar('(None)')); SendDlgMsg(pDlg, 'cmbProxy', DM_LISTADDSTR, Data, 0); for Index:= 0 to ProxyList.Count - 1 do begin Proxy:= TFtpProxy(ProxyList.Objects[Index]).Clone; Text:= GetProxyName(Proxy); Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'cmbProxy', DM_LISTADD, Data, PtrInt(Proxy)); end; SendDlgMsg(pDlg, 'cmbProxy', DM_LISTSETITEMINDEX, ProxyIndex, 0); end; LoadProxy(pDlg); end; procedure SaveProxyList(pDlg: PtrUInt); var Count: Integer; Index: Integer; Proxy: TFtpProxy; begin with gStartupInfo do begin ProxyList.Clear; UpdateProxy(pDlg); Count:= SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETCOUNT, 0, 0); for Index:= 1 to Count - 1 do begin Proxy:= TFtpProxy(SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETDATA, Index, 0)); ProxyList.AddObject(Proxy.ID, Proxy); end; end; if ProxyIndex > 0 then gConnection.Proxy:= TFtpProxy(ProxyList.Objects[ProxyIndex - 1]).ID else gConnection.Proxy:= EmptyStr; end; procedure FreeProxyList(pDlg: PtrUInt); var Count: Integer; Index: Integer; begin with gStartupInfo do begin Count:= SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETCOUNT, 0, 0); for Index:= 1 to Count - 1 do begin TFtpProxy(SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETDATA, Index, 0)).Free; end; end; end; function DlgProc (pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall; var Data: PtrInt; Text: String; Proxy: TFtpProxy; begin Result:= 0; with gStartupInfo do begin case Msg of DN_INITDIALOG: begin Text:= gConnection.Encoding; Data:= PtrInt(PAnsiChar(Text)); Data:= SendDlgMsg(pDlg, 'cmbEncoding', DM_LISTINDEXOF, 0, Data); if Data >= 0 then SendDlgMsg(pDlg, 'cmbEncoding', DM_LISTSETITEMINDEX, Data, 0); Text:= gConnection.ConnectionName; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtName', DM_SETTEXT, Data, 0); Text:= gConnection.Host; if gConnection.Port <> EmptyStr then begin if IsIP6(Text) then Text := '[' + Text + ']'; Text += ':' + gConnection.Port; end; if gConnection.FullSSL then Protocol:= 1 else if gConnection.AutoTLS then Protocol:= 2 else if gConnection.OpenSSH then begin if gConnection.OnlySCP then Protocol:= 3 else Protocol:= 4; end else begin Protocol:= 0; end; SendDlgMsg(pDlg, 'cmbProtocol', DM_LISTSETITEMINDEX, Protocol, 0); Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtHost', DM_SETTEXT, Data, 0); Text:= gConnection.UserName; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtUserName', DM_SETTEXT, Data, 0); if gConnection.MasterPassword then begin SendDlgMsg(pDlg, 'chkMasterPassword', DM_SETCHECK, 1, 0); SendDlgMsg(pDlg, 'chkMasterPassword', DM_ENABLE, 0, 0); //SendDlgMsg(pDlg, 'edtPassword', DM_SHOWITEM, 0, 0); SendDlgMsg(pDlg, 'btnChangePassword', DM_SHOWITEM, 1, 0); end else begin Text:= gConnection.Password; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtPassword', DM_SETTEXT, Data, 0); end; Text:= SysToUTF8(gConnection.Path); Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtRemoteDir', DM_SETTEXT, Data, 0); Text:= gConnection.InitCommands; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtInitCommands', DM_SETTEXT, Data, 0); Data:= PtrInt(gConnection.PassiveMode); SendDlgMsg(pDlg, 'chkPassiveMode', DM_SETCHECK, Data, 0); Data:= PtrInt(gConnection.AgentSSH); SendDlgMsg(pDlg, 'chkAgentSSH', DM_SETCHECK, Data, 0); Data:= PtrInt(gConnection.CopySCP); SendDlgMsg(pDlg, 'chkCopySCP', DM_SETCHECK, Data, 0); Data:= PtrInt(gConnection.ShowHiddenItems); SendDlgMsg(pDlg, 'chkShowHidden', DM_SETCHECK, Data, 0); Data:= PtrInt(gConnection.KeepAliveTransfer); SendDlgMsg(pDlg, 'chkKeepAliveTransfer', DM_SETCHECK, Data, 0); Data:= PtrInt(PAnsiChar(gConnection.PublicKey)); SendDlgMsg(pDlg, 'fnePublicKey', DM_SETTEXT, Data, 0); Data:= PtrInt(PAnsiChar(gConnection.PrivateKey)); SendDlgMsg(pDlg, 'fnePrivateKey', DM_SETTEXT, Data, 0); if SameText(gConnection.ConnectionName, cQuickConnection) then begin SendDlgMsg(pDlg, 'edtName', DM_ENABLE, 0, 0); SendDlgMsg(pDlg, 'chkMasterPassword', DM_SHOWITEM, 0, 0); end; EnableControls(pDlg); LoadProxyList(pDlg); end; DN_CHANGE: begin if DlgItemName = 'chkMasterPassword' then begin Data:= SendDlgMsg(pDlg, 'chkMasterPassword', DM_GETCHECK, 0, 0); gConnection.MasterPassword:= Boolean(Data); gConnection.PasswordChanged:= True; end else if DlgItemName = 'cmbProtocol' then begin Data:= SendDlgMsg(pDlg, 'cmbProtocol', DM_LISTGETITEMINDEX, 0, 0); case Data of 0: // FTP begin Protocol:= Data; gConnection.OpenSSH:= False; gConnection.OnlySCP:= False; gConnection.FullSSL:= False; gConnection.AutoTLS:= False; end; 1, 2: // FTPS, FTPES begin if (SSLImplementation = TSSLNone) then begin ShowWarningSSL; SendDlgMsg(pDlg, 'cmbProtocol', DM_LISTSETITEMINDEX, Protocol, 0); end else begin Protocol:= Data; gConnection.OpenSSH:= False; gConnection.OnlySCP:= False; gConnection.FullSSL:= (Data = 1); gConnection.AutoTLS:= (Data = 2); end; end; 3, 4: // SSH+SCP, SFTP begin if libssh2 = NilHandle then begin ShowWarningSSH; SendDlgMsg(pDlg, 'cmbProtocol', DM_LISTSETITEMINDEX, Protocol, 0); end else begin Protocol:= Data; gConnection.OpenSSH:= True; gConnection.FullSSL:= False; gConnection.AutoTLS:= False; gConnection.OnlySCP:= (Data = 3); SendDlgMsg(pDlg, 'chkCopySCP', DM_SETCHECK, PtrInt(Data = 3), 0); end; end; end; EnableControls(pDlg); end else if DlgItemName = 'cmbProxy' then begin UpdateProxy(pDlg); ProxyIndex:= SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETITEMINDEX, 0, 0); // Load current proxy settings LoadProxy(pDlg); end; end; DN_CLICK: if DlgItemName = 'btnAnonymous' then begin Text:= 'anonymous'; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtUserName', DM_SETTEXT, Data, 0); Text:= 'anonymous@example.org'; Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtPassword', DM_SETTEXT, Data, 0); end else if DlgItemName = 'btnChangePassword' then begin if ReadPassword(gConnection.ConnectionName, Text) then begin Data:= PtrInt(PAnsiChar(Text)); SendDlgMsg(pDlg, 'edtPassword', DM_SETTEXT, Data, 0); SendDlgMsg(pDlg, 'edtPassword', DM_SHOWITEM, 1, 0); SendDlgMsg(pDlg, 'btnChangePassword', DM_SHOWITEM, 0, 0); SendDlgMsg(pDlg, 'chkMasterPassword', DM_ENABLE, 1, 0); gConnection.PasswordChanged:= True; end; end else if DlgItemName = 'btnAdd' then begin UpdateProxy(pDlg); Proxy:= TFtpProxy.Create; Proxy.ID:= CreateProxyID; Data:= PtrInt(PAnsiChar(Proxy.ID)); ProxyIndex:= SendDlgMsg(pDlg, 'cmbProxy', DM_LISTADD, Data, PtrInt(Proxy)); SendDlgMsg(pDlg, 'cmbProxy', DM_LISTSETITEMINDEX, ProxyIndex, 0); LoadProxy(pDlg); end else if DlgItemName = 'btnDelete' then begin Data:= SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETITEMINDEX, 0, 0); TFtpProxy(SendDlgMsg(pDlg, 'cmbProxy', DM_LISTGETDATA, Data, 0)).Free; SendDlgMsg(pDlg, 'cmbProxy', DM_LISTDELETE, Data, 0); ProxyIndex:= 0; SendDlgMsg(pDlg, 'cmbProxy', DM_LISTSETITEMINDEX, 0, 0); LoadProxy(pDlg); end else if DlgItemName = 'btnOK' then begin Data:= SendDlgMsg(pDlg, 'cmbEncoding', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); gConnection.Encoding:= Text; Data:= SendDlgMsg(pDlg, 'edtName', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); gConnection.ConnectionName:= RepairConnectionName(Text); Data:= SendDlgMsg(pDlg, 'edtHost', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); if (Length(Text) = 0) or (Length(gConnection.ConnectionName) = 0) then begin gStartupInfo.MessageBox('You MUST at least specify a connection and host name!', nil, MB_OK or MB_ICONERROR); Exit; end; gConnection.Host:= ExtractConnectionHost(Text); gConnection.Port:= ExtractConnectionPort(Text); gConnection.FullSSL:= ExtractConnectionProt(Text) = 'ftps'; Data:= SendDlgMsg(pDlg, 'edtUserName', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); gConnection.UserName:= Text; Data:= SendDlgMsg(pDlg, 'edtPassword', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); gConnection.Password:= Text; Data:= SendDlgMsg(pDlg, 'chkMasterPassword', DM_GETCHECK, 0, 0); gConnection.MasterPassword:= Boolean(Data); Data:= SendDlgMsg(pDlg, 'edtRemoteDir', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); gConnection.Path:= UTF8ToSys(Text); Data:= SendDlgMsg(pDlg, 'edtInitCommands', DM_GETTEXT, 0, 0); Text:= PAnsiChar(Data); gConnection.InitCommands:= Text; Data:= SendDlgMsg(pDlg, 'chkPassiveMode', DM_GETCHECK, 0, 0); gConnection.PassiveMode:= Boolean(Data); Data:= SendDlgMsg(pDlg, 'chkAgentSSH', DM_GETCHECK, 0, 0); gConnection.AgentSSH:= Boolean(Data); Data:= SendDlgMsg(pDlg, 'chkCopySCP', DM_GETCHECK, 0, 0); gConnection.CopySCP:= Boolean(Data); Data:= SendDlgMsg(pDlg, 'chkShowHidden', DM_GETCHECK, 0, 0); gConnection.ShowHiddenItems:= Boolean(Data); Data:= SendDlgMsg(pDlg, 'chkKeepAliveTransfer', DM_GETCHECK, 0, 0); gConnection.KeepAliveTransfer:= Boolean(Data); Data:= SendDlgMsg(pDlg, 'fnePublicKey', DM_GETTEXT, 0, 0); gConnection.PublicKey:= PAnsiChar(Data); Data:= SendDlgMsg(pDlg, 'fnePrivateKey', DM_GETTEXT, 0, 0); gConnection.PrivateKey:= PAnsiChar(Data); if gConnection.OpenSSH then begin if (Length(gConnection.PublicKey) > 0) and (Length(gConnection.PrivateKey) = 0) or (Length(gConnection.PublicKey) = 0) and (Length(gConnection.PrivateKey) > 0) then begin gStartupInfo.MessageBox('You must enter the location of the public/private key pair!', nil, MB_OK or MB_ICONERROR); Exit; end; end; if gConnection.FullSSL and (InitSSLInterface = False) then begin; ShowWarningSSL; end; SaveProxyList(pDlg); // close dialog SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 1, 0); end else if DlgItemName = 'btnCancel' then begin FreeProxyList(pDlg); // close dialog SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 2, 0); end; end;// case end; // with end; function ShowFtpConfDlg(Connection: TConnection): Boolean; var ResHandle: TFPResourceHandle = 0; ResGlobal: TFPResourceHGLOBAL = 0; ResData: Pointer = nil; ResSize: LongWord; begin Result := False; try ResHandle := FindResource(HINSTANCE, PChar('TDIALOGBOX'), MAKEINTRESOURCE(10) {RT_RCDATA}); if ResHandle <> 0 then begin ResGlobal := LoadResource(HINSTANCE, ResHandle); if ResGlobal <> 0 then begin ResData := LockResource(ResGlobal); ResSize := SizeofResource(HINSTANCE, ResHandle); with gStartupInfo do begin gConnection := Connection; Result := DialogBoxLRS(ResData, ResSize, @DlgProc); end; end; end; finally if ResGlobal <> 0 then begin UnlockResource(ResGlobal); FreeResource(ResGlobal); end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftp.dpr��������������������������������������������������������0000644�0001750�0000144�00000001407�14743153644�017755� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library ftp; {$IFDEF FPC} {$mode delphi}{$H+} {$ENDIF} uses {$IFDEF UNIX} cthreads, {$ENDIF} DCConvertEncoding, FPCAdds, Classes, FtpFunc, FtpUtils, FtpConfDlg {$IF DEFINED(UNIX)} , ssl_openssl_ver {$ENDIF} , ssl_openssl {$IF DEFINED(LINUX)} , ssl_gnutls {$ENDIF} ; exports FsInitW, FsFindFirstW, FsFindNextW, FsFindClose, FsExecuteFileW, FsRenMovFileW, FsGetFileW, FsPutFileW, FsDeleteFileW, FsMkDirW, FsRemoveDirW, FsSetTimeW, FsDisconnectW, FsSetCryptCallbackW, FsGetDefRootName, FsSetDefaultParams, FsStatusInfoW, FsGetBackgroundFlags, { FsNetworkGetSupportedProtocols, FsNetworkGetConnection, FsNetworkManageConnection, FsNetworkOpenConnection, } ExtensionInitialize; {$R *.res} begin Randomize; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftp.ico��������������������������������������������������������0000644�0001750�0000144�00000474106�14743153644�017754� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �(����``��� ����HH��� �T��V�@@��� �(B���00��� �%��4� ��� ���Y���� � ��Vj���� �h��s�(���������� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���'���'���&���&���%���%���$���#���#���"���"���!���!��� ��� ��������������������������������������������������������������������������������������������������� ��� ��� ��� ��� ��� ��� ��� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������hدد֮ծӭҮѭЭϭάͭˬʪɪɫǪƫũĩé|zxutro|||mwwwkyyyisssfssscnnn_dddVOOOJ000= 2���.���.���.���-���)���&���"����������������������������������������������������������������������������������������������������������������������������������������������������������������欬ͣ|||m���2���2���2���2���)����������������������������������������������������������������������������������������������������������������������������������������������΄w���2���2���2���2���)����������������������������������������������������������������������������������������������������������������������������������� 4���2���2���2�������������������������������������������������������������������������������������������������������������������������������ggg]���2���2���2���������������������������������������������������������������������������������������������������������������������������rrrd���2���2���-�����������������������������������������������������������������������������������������������������������������������~!!!<���2���2�����������������������������������������������������������������������������������������������������������������������|���2���2���-�������������������������������������������������������������������������������������������������������������������z!!!<���2���2�������������������������������������������������������������������������������������������������������������������u���2���2�������������������������������������������������������������������������������������������������������������������s!!!<���2��� ����������������������������������������������������������������������������������������������������������������p���2���'����������������������������������������������������������������������������������������������������������������l���2���.����������������������������������������������������������������������������������������������������������������i���2���2���������������������������������������������������������������������������������������������������������������e���2���2����������������������������������������������������������������������������������������������������������������b^^^W���1����������������������������������������������������������������������������������������������������������������^||otcmY|fPx`GsX;tY:w^CzcK}iTn[vgt���0����������������������������������������������������������������������������������������������������������������\ugu^DmO0|_CqUgnv{}ysgmSw]BzhTx���/����������������������������������������������������������������������������������������������������������������Wo^rX<qQ1jM|csxyzwtqqrsuz{~eeKvbLym���.����������������������������������������������������������������������������������������������������������������SwbLmM+xZ:tWqrrqok}ijkmmnoqqu{sYpW9uh���-����������������������������������������������������������������������������������������������������������������Q{iVmN-{]<|_lkheybxbyczd{e}f}ghijllnyzbv]C|q���-����������������������������������������������������������������������������������������������������������������Oq`nP/sR0tQfxau`v`v`v`v_w`w_y`yazc}d}e~f~fhit|}}}~{qWs\E|���,����������������������������������������������������������������������������������������������������������������}}}IpT7pO-bAdv^s]t]t]u]u]v]w^w]w]w]y^y_{`{`}b~cftz{{||}}~}~~~}~~oz`DzjX���+����������������������������������������������������������������������������������������������������������������}}}EzoP0rQ.lLix]r[rZs[u[u[u[u[v[v[w[wZwZxZy]y]{^gvxyyzzzz{||||{||||xqWzeO���*����������������������������������������������������������������������������������������������������������������|||CxinN,tS/nNhgpYqXrYrXtYuXuYuXvYvXvXwYwXwXwXyZiuuwwxwxzzzzzzzzzzzzzww]{cK���)����������������������������������������������������������������������������������������������������������������xxxAkWpO-vT/pPfhcqWpVrVsVsVtVuVvWvVvVvUvUuTvTwTfœoœqÜqÝrÞtÞtßvğvßwwxxxxxxxvlwwxux_}dJ���(����������������������������������������������������������������������������������������������������������������ttt;yaHpP-wT0lJefgiiiiigfcba`^`behÚjÚkÛkÛmĜnĜoĝpĝqĝrĞtÞtÞužwwvwwvk{brvvtrv\gM���(����������������������������������������������������������������������������������������������������������������jjj7oZpP-wU0a<adfgiiklmllk™kÚjÚjějĚiśiĚhĚhĚhĚhęhŚhěiějěkĝmŝnŝoĝqÝqÝsÝsvuutshptssqktZjP���'����������������������������������������������������������������������������������������������������������������hhh4wpP-wU0[4{Ybcefhikjji™iÙhÙhĚhŚgŚgśfƛeƚeƛeŚdŚdŚdŚcƚeŚfƛgśhśiŜjĜlělěoĜpœpœrssrrrrpppo}csYlS���'����������������������������������������������������������������������������������������������������������������ccc2oO,wT0Z3oK_acefhhhhfØfØeęeŚeŚdƚcǛcǚbǚbǛbǛbǛbǚaǚaǚ`ǚ`řařaZU`ƛgŜiśiěkěmÛnšoib`gnonnllw[sXs^���&����������������������������������������������������������������������������������������������������������������```.qR3vS/}Y2`6~[_`cefeee—d—cØcŘbřbƚbǚaȚaț`ț_ɛ_ɛ_ɚ^ɚ^Ț]Ț]Ț\Ț\ř[KmCmDoFMZĚeŚgÚhdYsRsStTtUZikkkj}auYqWn���%����������������������������������������������������������������������������������������������������������������III)y]AtR.|X2^5nE\_`bcccb•a–aė`Ř_Ƙ_Ǚ_Ț_Ț]ɛ]ʚ\ʛ\˛\˛\ʛ[ʛ[ʛ[ʛZʛZʙYPi<j>j?kAlBmDuFMPpJpKpLrOqOrQqQXjihgevXsWoU���%����������������������������������������������������������������������������������������������������������������LLL'qP-zV1]5c8{S[^_a``__–_Ė]Ƙ]Ƙ\ș\ɚ[ɚ[ʚZ˛Z̜Z̛Y̜Z˜Z̜Z̛Y̛Y̛X̛X˚WEh9g9h;i<j=j>k@kAkBlCmGmGnInJoLpNnO_gfedz\tWqWfM���$����������������������������������������������������������������������������������������������������������������999"qR2wT0[3a7j>Y[]_^]]]•[Ė[ŖZǘYȘYʙYʚY˚X˛Y̛X̜Y̜Y̜Y̜X̝Y̜Y͜Y̜X̛W̛Wn9g7e6e5e6f8f9g:h;i>i?j@jBkDlFkGlHmJrMddba~]vWsVoU|���$����������������������������������������������������������������������������������������������������������������/// vsR.}Y2_6f:qDX[\\ZZZ“YĕXƕXǗWȘVʙVʙV˚W̚W̛X͜X͜X̜X͝Y͝Y͝X͝X͜W͜W͜W͜Wu9d5c3c3c2c3d4e6e7f8f:f;g=g>h@iBiDiDiF`a`^]xWtVpTjR���#����������������������������������������������������������������������������������������������������������������nN-yV0]5c8j<xIWZYXXW“WēVƕUǕTɗTʘS˙T˚ƯV̛W͜W͜WΝXΞYΝXΝXΞXΞXΝWΝWΜVΜVAb2b2a0a0`/a0`1a2c3c5c6d7f:e;e=e>fAgA[_]\[zWvVrUnSp���#�������������������������������������������������������������������������������������������������������������������zctR.~Y3a7h;o?|LXWWUUTÓTœRǕRɖQʗR˙S̚T̛ƯU͜VΝWΝWϞXϞXϟXϟXϞWϞWϞWϞWϞWΝVJa0`/_._.],],^+_-_/`.a1a2b3b5c7b9c;i@[]\ZY{WwUsUoS|cH���"�������������������������������������������������������������������������������������������������������������������nN,yV0]5e9l=sAOUTSRQ‘QœPǔPȕOɗQʗQ˙S̚S͜U͜UΝVΞWϞWϞWПXПXПWѠXПWПWПWϞVϞUϞUA`-],],\+\*\*[)\*],x3=~8`0_1_3`6r=XZ[ZX}VxUtToRlQqZ���"�������������������������������������������������������������������������������������������������������������������zsQ.~Y3a7i;p?wDMRPPOOđNƓMȕNɕNʗP˙Q̙R͛SΜTΝTΝUϞVПWРXѠWѡXѠWѠWѠWѠWПVПVПVОTϞTěOEG:\)Y&Y&X%w1ȓJǒIǒJH;_1_3z?VXZZXVzTvSqRlPtY>���!�������������������������������������������������������������������������������������������������������������������x\>wU0]5e9m=tB{FKNNLLÐKőKǓKɕMɖNʗO̙Q͛RΜSϜSϞUПVѠWПVѠWѡWҡWҢXҢWҢWҡWҡWҡVҠUѠUџTОSОSϝRΜQCa*Z'Y&9ɔJȓIǒIǒJJt5_1?TUXZXV{UwSrQmPgK���!�������������������������������������������������������������������������������������������������������������������pO-|X2`6h;p?xD}FHKJIHďHƒIȔKɕL˗N̙O͚P͛QΜRϞTПUѠVҠVҡWӢWӢWӣXԣXԣXԣXԣXԣXԣXӣXӢWӡVҡVҠUџTОSϝRIl.Z':ʕJɔJȔJǒIǒJGc0@RTVXXV|TxSsQnNhMt_��� �������������������������������������������������������������������������������������������������������������������tR.[3c8l=tB|FFEHGFÍEŏEǒHȔJʖL˗M͙OΛPϜQОSџTҠUӡVӢWԣXԤYեZեZ֦[֦[֦[֦[֦[֦[եZեZԤYԣXӢWӡVҠUџTОSǚN<J˗LʖKɕKȓIǒIƑIEGORTVXV~TyRsOnNiLlQ4��� �������������������������������������������������������������������������������������������������������������������eIwU0^5f:o?wD}FFEED‹CŎCǐEȓHʕJ˗L͙NΛPϝRџTҠUӡVӣXԤYեZ֦[֧\ק\ר]ר]ب]ب]ب]ר]ר]ק\ק\֦[֦[եZԤYӢWҡVҠUОSϝRΛP͙N̗LʖKɔJȓIǒIőIKNORTVVTzRtPoMiKpT8����������������������������������������������������������������������������������������������������������������������nN,{W1`6k5cu,Ty&^|*5CDCčCƐEȒGʕJ˗L͙NΛPНRџTҡVӢWԤYեZ֦[ק\ب]ة^٪_٪_٪_٫`٫`٫`٫`٪_٪_ة^ة^ר]ק\֦[եZԤYӢWҡVџTНRΛP͙N̗LʕJȓIǒHƑHĐIKMPRTVSzQtNoMiJvZ=l����������������������������������������������������������������������������������������������������������������������qP-~Y3tf0Fs!Iw"Nz$P|$Q}$z/DŒCŏDǑFɔI˗L͙NΛPОSџTӡVԣXեZ֦[ק\ة^٪_٫`ڬaڬaۭbۭbۭbѫ_Fj3g3c1|;ש^٪_ة^ب]ק\֦[դYԣXҡVџTОSΛP͙N˗LʕJȒHƑGŏGÏILMOSTS|PvMoKiIz^AmS9����������������������������������������������������������������������������������������������������������������������sR.\3Fo Fu!Kx#N{$P|$R}$T#8čCǐEɓHʖK̙NΛPНRџTӢWԤYեZק\ة^٪_ګ`ڬaۭbܮcܯdܯdܯdMh4a1a1a0`0`0Mۭbڬa٫`ة^ר]֧\եZԣXӡVџTНRΛP͙N˖KɔIǑGŐFĎGHLNOSR|OvMoKiH{^?aE(����������������������������������������������������������������������������������������������������������������������yvS/u_0BrGv"Ly$O{$Q}$R~#T#e'ŽBȒGʕJ̘MΚOϝRџTӢWԤY֦[ר]ة^٫`ڬaۮcܯdݰeݱfޱfڱeDa2a2a2a2a2e3Eʫ\ܯdܮcۭbڬa٪_ة^ק\եZԣXӡVџTϝRΛP̘MʖKȓHƐFĎEGILNPR}OvLoIiF|^?cF'����������������������������������������������������������������������������������������������������������������������{ewU0}a3Cr Hv"Nz$P|$Q}$S#U#V#7ɔI˗L͙NϜQџTҡVԤY֦[ר]٪_ڬaۭbܯdݰeޱf޲g߳hֱe?b3b3d4COYرe߳h߲g޲gݱfܯdۮcڬa٫`ة^ק\եZԣXҡVџTϜQ͚O˗LɔIǒGŏDEHILOP}NvKpIhF{]<dG(����������������������������������������������������������������������������������������������������������������������kPyV1`5Ds Iw"Nz$P|$R}$T#V#W#1ʕJ̘MΛPОSҡVԣX֦[ר]٪_ڬaۮcݯdޱf߲gߴijаcv<c4c4r:Ҳdlllkkji߳h޲gݰeܯdۭbګ`ة^ק\եZԣXҡVОSΛP̙NʖKȓHƐEčCEGJMN~NvJoFhC|\;eH(û����������������������������������������������������������������������������������������������������������������������vZ<zW1b6Dt Jx#N{$P}$R~#T#V#W$3˗L͚OϝRѠUӢWեZר]٪_ڬaܮcݰe޲g߳hjkǯ`o9c4c4c5Tooonnmlkji߲gޱfܯdۭbګ`ة^ק\եZӢWѠUϝR͚O˗LɔIǑFŎCCFHJM}LuHoFhCz[9fH)����������������������������������������������������������������������������������������������������������������������kL,{W1c7Et!Kx#O{$Q}$S~#U#V#X$7̘MΛPОSӡVդYק\ت_ڬaܮcݰe߲giklմgl8c5d5d6d6Orqqqpoonlkj߳hޱfܯdۭb٫`ة^֦[ԤYҡVОSΜQ̙NʖKȒGƏDŒCDFHK~KuHnCf@yX6fH)����������������������������������������������������������������������������������������������������������������������kL+|X2c7Ft!Ly$O{$Q}$S#U#W#X$C͙NϝRҠUԣX֦[ة^ڬaܮcݰe߲gikmmEd6d6e6e7e7Iuuutsrqpomlj߳hޱfܯdۭb٪_ר]եZӣXѠUϝR͚O˗LɓHƐEÍCDDGC|=u?mCe?vV3fH)}����������������������������������������������������������������������������������������������������������������������mO/{W1c7Fu!Ly$P|$R}$T#V#W#h*˗LΛPОSӡVեZר]٫`ۭbݰe߲gjlnoWd6e7e8e8e8e9yCyyyxwvtrqonlj߳hޱfܯdڬaت_ק\ԤYҡVОSΛP̘MɔIǑFčCCD4Q|&P{(Lx(qp5c<tR.eH(����������������������������������������������������������������������������������������������������������������������z_BzW1d6Fu!My$P|$R}$T#V#W$6̘MϜQџTԣX֦[ة^ڬaܯd޲gilnprDe8e8e9e:f:f:i=}~}|{zxvtrpnlj߳hݰeۮc٫`ب]եZӢWџTϜQ̙NʕJǒGŎCC>S}$P|$N{%Ix%Gu%zc6sR.eG(����������������������������������������������������������������������������������������������������������������������oWzV1c6Fu!My$P|$R}$T#V#X$C͙NϝRҡVԤYר]٫`ۮcޱfiknprtk<e9f:f;f<f<f=f=yƂŁŀ~|zwurpnli޲gܯdۭbت_֧\ԤYҠUϝR͙NʖKȒGŎCC5Q}$P|$Mz$Hv#Cs"^g*rQ.cF'����������������������������������������������������������������������������������������������������������������������jxU0b5Et!Ly$P|$R}$T#V#i*ʖK͚OОSӢWեZة^ڬaݯd߲gkmpruӹne:f;f<f=f=f>f>f>ùpȆȆDžƃƂŀ~{xurpnkߴiݱfۮc٫`ר]եZҡVОS͚O˖KȓHƏD‹C;R}$P|$Mz$Gu!Br Qh%pP-aE'����������������������������������������������������������������������������������������������������������������������}vS/`4Et!Ly$P|$R}$T#V#b'ʕJΚOџTӢW֦[٪_ۮcޱfiloruyef;f=f=f>f?f?g@g@ZʊʊɉɇȆDŽŁ|yuromj޲gܯdڬaة^֦[ӢWОSΛP˗LɓHƏD‹CCU}%P|$Ly$Fu!@pMg#nN,_C&����������������������������������������������������������������������������������������������������������������������sQ.^5Hs"Kx#P|$R}$T#V#X$EΛPџTԣXק\ګ`ܯd߲gknqty|_f=f>f?g@gAgAgAgBkDȉ̎ˍˌʊɈDžƃ|xtqnkߴiݰeۭb٪_֦[ӣXџTΛP˗LɓHƏD‹CDR|$O{$Ly$Et!?p\a(kL+_D)����������������������������������������������������������������������������������������������������������������������nN,\4Pq$Jx#O{$R}$T#V#X$:ΛPѠUԤYר]ڬaݰeߴilorw|ŀĹnf?f@gAgBgBgCgChChCfΒΑ͐̎ˌɉȆƃ{wspmjޱfܮc٫`ק\ԣXџTΜQ̗LɓHƏD‹CBQ}$O{$Kx#Dt >omX,hJ)oYC����������������������������������������������������������������������������������������������������������������������kM,}Y2Xn'Iw"O{$Q}$T#V#X$u0ΜQҠUեZة^ۭbޱfjmquzƃŃhAgAgBgChDhEhEhEhEhEnЕϓΒ͏ˍʊȆƂ~zuqnk߲gܯdګ`ר]ԤYѠUϜQ̘MɓHƏDC<Q}$O{$Jx#Cs Hk!tS/dG(}����������������������������������������������������������������������������������������������������������������������r[xU0`j*Gv"Nz$Q}$T#V#X$['ǛNҠUեZة^ۮc޲gkorx}ƂȆʋdgChDhEhFhFhGhGhGhGhGnΕЖϓ͐ˍɉDžŁ|wrol߳hݰeڬaר]ԤYѠUϜQ̗LȓHŏDC}1P}$Nz$Iv"Brgb+pP-_C&ý����������������������������������������������������������������������������������������������������������������������sQ.pd/Eu!Mz$P|$S$V#X$Y&CҠUեZت_ܮc߲glptzĀDžʊ̎͑\hFhGhHhHhIhIhIhIhIhHyR̐Зϓ͐ˌɈƃytpliݰeڬaר]ԤYѠUΜQ˗LȓHŎC@Z~&P|$Nz$Gu"[l(|X2kL+dL2����������������������������������������������������������������������������������������������������������������������kL+[3Jr#Ly$P|$R~$U#W$Y&8ѠUեZ٪_ܮc߳hlpv|ƂɇˍΑЕΓuOhIhIiJiKiKiKiKiJiIhI_Қїϓ͏ʋȆŁ{vqmiݰeڬaר]ԤYѠUΛP˗LȒGAh)R~$P|$Ly$Qs%`4wT0eH(|l����������������������������������������������������������������������������������������������������������������������~fMyV0bl*Iw"O|$R~$U#W$Y&f,ϞSդYت_ܯd߳hmqw~DŽʊ͐ϔҙԝÃiJiKiLiLiMiMiLiLiKiJhI̒ҚЖΒ̍Ɉƃ}wqnjݱfڬaר]ԤYџT̙NB6j)T$Q}$O{$Uw'j6\4pP-^C%����������������������������������������������������������������������������������������������������������������������pP-xb1Fu!N{$Q}$T$W#Y%Z(DԤYة^ܮc߳hmrxĀȆˌΒїӜ֠ЙiLiMjNjNjNjNjNjNiMiLiKwԝҙϔ͏ʊDŽ~xrnjݰeڬaק\ԣXОSĘLY&W$U#S~$P}$f{-q=d8{W1iJ*YA&����������������������������������������������������������������������������������������������������������������������jM.|X2Zo(Kx$P|$S~$W$]+_-s6Ԥ[٪a۰gߵlpu|Ƃʊ͐ϖқՠץԠlPlPkQkRkRkRkQkPkOkOiLZ֠ӜЗΑˌȆyrniݰeڬa֧\ӢWНR̘Mr-W#U#U~%}~3yCl=_5sQ.aD&}n����������������������������������������������������������������������������������������������������������������������rQ.{c2Hu"N{$R~$Y(a1c3e6S٬eݱkotyĀȇˏϕҜ֡ئګتqWpWpXqYqYpXpXoWoVoUoTnRњաӜЖ̐ɉƃ|uqlܰg٬c֧^ҢYϝT˘NƒH::A~FsAf9}Y2jK*\C*����������������������������������������������������������������������������������������������������������������������oS6}Y2gn,Ly$P|$[/f7h9i<{CӬgݳosx}ƄʋΓҚԠإ۫ݰМu]v^v_v_v`u`u_u^t]s[sZsXÇץԠҚϔˎȇxupݲk٭fרaӣ\ϟW̙RȕMÐKLFzEm=_6sQ.`D&����������������������������������������������������������������������������������������������������������������������pP-`5]t*O{$`6j>l?mBnCRݴrw|ÀLJˏЗӝפڪݰۭuzdzezfzgzfzfzfzeycybxax_t٪פԞИ̑ɊŃ}xt޴oگj֪eӥ`Р[̛VȕQÑRS~FsAe9{W1hJ)aJ2����������������������������������������������������������������������������������������������������������������������rZ@yV1g7\x*`8mFqErGtHtKczĄȊ̒Кՠبԣŋpijlmnmm~m~l~j~i~g}e}dНبբҚΔˍƆ|w޴rڰm׫iӦcС_̜YǗWXYyDk<]5pO-\A$���������������������������������������������������������������������������������������������������������������������� jK*\4m=EsMuLvLwNUiߺ|㿁ćɌ͓ќ̕yiknopsttttsrqomlhrة֤ҞϖːLjÃzݵuڰp֬kӦfϢb̝]Ƙ^_[p?b7vT/bF'dO:���������������������������������������������������������������������������������������������������������������������� ubpP-a7{Mke_e֯t۵zߺ㿄ĉɎ͔xilnqsvwyz{{{zywutqnl†اӟϙ̑ȋÆ㿁}ݵwٰs֬nӧiϢdʞcřeeWf:|X2hJ)W>%Ŀ���������������������������������������������������������������������������������������������������������������������� v_GvS/h<pƠsͥrөqׯwڵ|޺⿆Ëɐʼnjmqsvy|}~}{yvtpnuÇÅż|vpjc^[WWaÙkjvL[4mM+X>#���������������������������������������������������������������������������������������������������������������������� kQ5zV1\ßyʤxЩwծxڳ}ݹᾈÍȑɐorux{~~{xvsoligdca_\[Y~W{W`qg_6pO-[@$s���������������������������������������������������������������������������������������������������������������������� ĿfH+`;xǥͩ~Ӯ}سܸ߽Žǒ̗{vx|ŒÎŒ}zxspnljhfdb`^_bsquPrQ.]B%scR���������������������������������������������������������������������������������������������������������������������� dF(|^ʩЭղڶݼœʘɕz|ŒďőƓƔƓŒÏ~{xusqomkigefk{xluU2^B%_L9���������������������������������������������������������������������������������������������������������������������� dH*p̬ұ׵ܺ߾ÓȘ̝ČŒďŒǕȘɚəǕƒĐÍ{ywvsqpolmuƧ}v{]<\A%[H5��� ������������������������������������������������������������������������������������������������������������������� jQ5}̮ӴظݼŘɜ͞ÎĐƔȖɚʛʚȘǕŒÏŒ~{zxwtsuɩ}gJY?#l\L��� ������������������������������������������������������������������������������������������������������������������� t`JʯӶغݾ—ƛʟɚŒÎőƓǕȘəȘȗǕƓĐΌ~}{zͱɬmRS:!vj��� ������������������������������������������������������������������������������������������������������������������� udRyǯӸؼÚǞˢɛĐŒƓǕǗȗǖǖǕƔőďɶѴƭu]DL7 ��� ������������������������������������������������������������������������������������������������������������������� xk|j®η׽ÞǠʤˢțƕŔƔǕǖǖǖǕǕƔœĒѐ̻պͳ¬}bK3Q?-��� ������������������������������������������������������������������������������������������������������������������� wjǴһĥǤɤ˧ΩΨ̠ͤʝȚǘǘƘƗŖĕĔԔ—œ׾йDzkUP=)��� ������������������������������������������������������������������������������������������������������������������� xjȶѽëŪǩʩ̩̪άϭЭΪ̦ͧˤʤɢȡǠǥŧçлȵyfO<(yp��� ������������������������������������������������������������������������������������������������������������������� reWyŷͼůǯɯʯ˯ˮˮ̮ˮʭʭɮȮƭìӿͻƵ{iWI7%pg^��� ������������������������������������������������������������������������������������������������������������������� ~zm{Źɼ;ñıŲŲŲı°ξʻŸtdZI8j`V��� ������������������������������������������������������������������������������������������������������������������� dYN`RB}o`o|swgn^MO>-A3$qjb���������������������������������������������������������������������������������������������������������������������� }xohbf_Xxsm����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ww^v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]v]w^w^w^w^w^w^w^w^w^w^u\yfLvbFtbErbEl[>-�������������������������������������������������������������������������������������������������������y`}Z_dddddddddddddddddddddddddddddddddddddddb\~jKubE@@�����������������������������������������������������������������������������������������������rWdgffeeddddddddddddddddddddddddddddddddddddddd{VucE�����������������������������������������������������������������������������������������������}edjiihhggffeedddddddddddddddddddddddddddddddddddoOsbBI�������������������������������������������������������������������������������������������ƿ~\llkkjjiihhgggffeeddddddddddddddddddddddddddddddcucF�������������������������������������������������������������������������������������������bonnmmǰɲȲªjjiihhggffeedddddd|dddddddddddddxeH������������������������������������������������������������������������������������������tmqqppomllkkjjiihhgeddddddddddddddddddlMp`@ ���������������������������������������������������������������������������������������oqĤtäs£s¢rroonnmmllkkjjggffeedddddddddddddoOlY@(���������������������������������������������������������������������������������������oätȨvǧvƧuƦuťtrqqppoonnmmljiihhgeddddddddddddoOlY@(���������������������������������������������������������������������������������������oǧu̫y˫x˪xʩwɩwťtĤtäs£srrqqppoollkkjjggffeedddddddoOlY@(���������������������������������������������������������������������������������������o˫xЯ{Ю{ϭzέzͬyɩwȨvǧvƦuŦuťtĤtäs£srrqonnmmlϽνͻɵ|ggffeeddoOlY@(���������������������������������������������������������������������������������������pϮzղ~Բ}ӱ}Ұ|Ѱ|ƣţŢĢáѶȨvǧvƦuŦuťtĤtqqppooihhggfpOlY@(���������������������������������������������������������������������������������������pұ|ٶص״ִճ~׾̫y˫xʪxʩwɨwȨvĤtäs£srrqkjjiirPlY@(���������������������������������������������������������������������������������������pұ|ٶٶٶٶٶؿЯ{Ϯzϭzέyͬy̫xȨvǧvƦuŦuĥtĤt͵ʹкmmllksQlY@(���������������������������������������������������������������������������������������pұ|ٶٶٶٶٶַַշԷԶěԲ}ӱ}ӱ|Ұ|ѯ{Я{̫x˪xʪwɩwɨvȨvĤtãs£s¤vpoonntRlY@(���������������������������������������������������������������������������������������pұ|ٶٶٶٶٶٶٶٶٶٶٶضص״ֳ~ճ~Բ}Я{Ϯzέzάyͬy̫xȨvǧuƦuťtrqqppuTlY@(���������������������������������������������������������������������������������������pұ|ٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶضԲ}ӱ}ӱ|Ұ|ѯ{Я{̫x˪xʪwȨťtĥtäsãs£rvTlY@(���������������������������������������������������������������������������������������pҰ{ٶٶٶٶٶٶҰؽԲ}ƤɩwȨvȧvǧuƦuwUo\A'���������������������������������������������������������������������������������������rٶٶٶٶٶٶҲصֽέzͬyͬy̫x˪xʪwmMqU9 ���������������������������������������������������������������������������������������|þfٶٶٶٶٶٶ̧Ҳٶڿٿھӱ}Ұ|Ѱ|ѯ{Ю{ϮzέzzgI�������������������������������������������������������������������������������������������zx[ճ~ٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶص׵ֳִ~ճ~Բ}ӱ}fzfG��������������������������������������������������������������������������������������������y¼bٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶصʪwygHـ@@��������������������������������������������������������������������������������������������wbѯ{ٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶk|hIj\@$������������������������������������������������������������������������������������������������ukz^deeeeeeeeeeeeeeeeeeeeefffffffffffffedZ[rP}jJweHff3����������������������������������������������������������������������������������������������������rA5%Qo^C.jU@ ����������������������������������������������������������������������������������������������������������������~~~o���)������������������������������������������������������������������������������������������������������������������������mmm`���(���������������������������������������������������������������������������������������������������������������������������1[[[Ittuuvvvwwxxyyzzzz{{||}}~~~~~~~~~~}}||{{zzzzyyxxwwvvvuuttssrrr_���(������������������������������������������������������������������������������������������������������������������������������������������������������������ ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?������������?������������?������������?������������?������������?������������������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?������������?�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���`������� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]]]^^^^^^^^^______```bbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaa ``` ``` ``` ``` ``` ``` ``` ``` ``` ___ ___ __________________^^^^^^__^`__aaabaacbb~}}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������*~~~~~~~~~~~~~~~~~~|||{{{||||||{{{zzzzzzzzzxxxyyyxxxwwwvvv~uuu}uuuzuuuyssswrrruqqqspppqnnnoooolmmmjlllhxxxfda`][XVTQOMICsss9PPP+666$111"000"/// ---***(((%%%������������������������������������������������������������������������������������������������������������F㭭ttt,,,^###H���0���&���```iii��������������������������������������������������������������������������������������������E񥥥ZZZ+++R2���*iii����������������������������������������������������������������������������������������C]]]o���2���.����������������������������������������������������������������������������������������@eeet3���/fff������������������������������������������������������������������������������������>111U���1������������������������������������������������������������������������������������=fff3'NNN��������������������������������������������������������������������������������:000Y���,BBB ��������������������������������������������������������������������������������8qqq���.GGG��������������������������������������������������������������������������������6���0MMM��������������������������������������������������������������������������������4���2SSS��������������������������������������������������������������������������������1###?WWW��������������������������������������������������������������������������������/y}oudo[lUq^vf|mziiiu[[[��������������������������������������������������������������������������������-}pkV{`CnS~dovz|}|{t~fnUuc|___��������������������������������������������������������������������������������*{n}hReJpTepsqponoqty|mzdvduaaa��������������������������������������������������������������������������������(}ycL}bDxXdige~e|e}f~hijlmuuinZccc��������������������������������������������������������������������������������&ycKwY8tN~bu_u_u_v_v_w^x_ya|c}d~ehpz||}~~|u\p^ddd��������������������������������������������������������������������������������#ttY<cBZx]r[s[t\u[u\v\v[w[x\y^z_cpwyzz{||||||{ioY~eee��������������������������������������������������������������������������������!xitV7a@b`qYrYsYtXtYuYvXvXvXwXwY`nuwxwyzzzzzzzzyqrZxfff��������������������������������������������������������������������������������p]tR/gEag`[ZZZYYXWWX\j›oÜpÝqÝsÞtÞužvwwwwwtlvwprY|lgff��������������������������������������������������������������������������������s^sS1a=}]eghijjifeeddfhÙiÚiÚjÛkěmĜoĝpÝrstuvuphrtsjqWvgff��������������������������������������������������������������������������������stU3{X2xUbdfhjjji˜hÙhĚhĚgŚfŚeŚeędęeŚdŚfŚgěiějĜlÛmÛpœqssrpqqpo}drZgff��������������������������������������������������������������������������������rQ-|X2mH_adfggf—eØdędŚcƚbǚbǚaǛaǚaǚ`ǚ`ǚ_ƙ_\SU^fĚiĚkkf_^elmlkw[sZgff��������������������������������������������������������������������������������|`BzW1a8yT_acdcc–b×aŘ`ƙ`Ǚ_Ț_Ț]ɚ]ʛ]ɚ\ɚ\ɚ[ȚZWHk@lBtFPW[UxPrPrQuT]jih}`sWv^gff��������������������������������������������������������������������������������zcwT0]5lCX^```__Ö]ŗ]ǘ\ș[ə[ʚZ˛Z˛Z˛Z˛Z˚Y˛X˚XOs=g:h<j>k?oBqEmEmHnIoKoMrPcfebvXqVygff��������������������������������������������������������������������������������uS0Z2d9vLZ]]\\”[ĕZƖYȘXəXʚX˚X̛X̜X̜X̜X̜X̜X̜X̛WHh7d5d4e6e8f9h;h>i?iBkDjFkHQcb_zZtVt\gff��������������������������������������������������������������������������������xxxfHzW1_6k=|OYZYXXÓVƕVȗUɘTʙU˚V̚W͛W͜X͜X͝X͝W͜W͜W͛VIj5b2a1a1b2b3d5d7d9f;f>f@gByJ^^\|YuVoTyggf��������������������������������������������������������������������������������iii uR.\4e9qAQWWUUÒTœRȕRɗR˙S˚T̛U͜V͜WΝXΞXΞXΝWΝWΝWΝVNs6`/_.^-^,^-_/a0a2b4c7c9c;{F\\Z|XwUqTlR¸ggg��������������������������������������������������������������������������������fff iM|X2b7k<wEQSRPPœOǔOɖPʗQ˙R͛T͜UΝVϞWϞWПWПWПWПWПVϞUϞUIv4q2k/[)Z(Z(m0<=s5c3_4DXZYWyUsSmQkRhgg��������������������������������������������������������������������������������fff z[:]5f9p?{FMOMMĐLƓLȕMɖO˙Q̚RΛSΝTϞUПVРWѠWѡWѠVѠVѠVПUПTОTƛOLGz2['X%:ǒIǒIG:a2DUXYV{TuRnP}cGhgg��������������������������������������������������������������������������������eee xV1a7k<uB}FJKIŽHőIȔKɕM˘N̚P͛QϝSПUџVѠVҡWҢWӢXӢWӢWӢWӢWҡVҠUѠUџTНRK6](=ɔIȓIƒIFr4DSUXW}TvRpOiMhgg��������������������������������������������������������������������������������ddd oS}Y2f9p?zEEFFEĎDƑGȔJʖL̙NΛPϝRџTҠUӢWԣXԤYեZ֦[֦[֦[֦[֦[եZԤYԣXӢWҠUџT̜QDƗKʖKɕKȓIƑHFIORVVTwQpNjLt]hhg��������������������������������������������������������������������������������ddd ¹wW5\4j7~t5{7?DCÌCƏDȓHʖK̘MΛPОSѠUӢWԤYեZ֦[ר]ר]ة^ة^ة^ة^ר]ר]ק\֦[եZԣXҢWѠUОSΛP̘M˖KɔIǒHőHJMPSUTxPqMjKgNƿhhh��������������������������������������������������������������������������������ddd vT/za1Sr%Ox$R{%h~+<CŏDǒGʕJ̙NΛPОSҡVԣXեZ֧\ب]٪_٫`ګ`ڬaج`UA=@ƥWة^ר]צ[եZԣXҡVОSΛP͙NʖKȓHƑGďHJMPSSzOrLjIx]Ahhh��������������������������������������������������������������������������������ddd qxW0Sj$Gv!Ly#O{#R}#r+>ǑFɔI̘MΛPОSҡVԤY֦[ة^٪_ڬaۭbܮcۯd̫^Ac2a1a0f3Iۭb٫`ت_ר]զ[ԣXҡVОSΛP̘MʕJǒGŏFGJMPRzNrKjHtW9hhh��������������������������������������������������������������������������������ccc w_wY0Pm#Hv"Nz#P|#S~#X#6ɓH˗LΚOОSҡVԤY֧\ة^٫`ۭbܯdݰeܱfê[Aa2k6}?GQͬ^ܰeۮcڭb٪_ר]֦[ԣXҠUОSΚO˗LȔIƐFÍEGKNP{MrJjFuW8}hhh��������������������������������������������������������������������������������ccc hL~[2Sn%Jw"O{$Q|$T#V#y.ʕJ̙NϜQҡVԤY֧\ت_ڬaܮcݰe޲gߴi¬\|>d4@\бdڴgߵii߳hޱfݰeۭbګ`ة^֦[ԣXҡVϝQ̙NʖKǒGĎDEHLN{MrHiDvW6phhh ��������������������������������������������������������������������������������ccc uV6\3Uo%Kx#O{#Q}#T#V#|0˘MΛPџTӣX֦[ت_ڬaܯd޲gߴiߵj[i7c4c5Zoonmmki߳hݰeۮcګ`ة^֦[ӣXПTΛP˘MȓHƏD‹CFHK{JqFiBtU4u`hhh ��������������������������������������������������������������������������������ccc oN-]4Vo&Ly#O{#R~#U#W#6͙NϝRӡVեZة^ڬaܯdޱfilǰay>c5d5d6Ussrppnlk߳hݰeۮc٫`ר]ԥZҡVϝR̚OʕJǐEÍCDFG{CqCg@sS1lVhgg ��������������������������������������������������������������������������������ccc pP.]4Vp&My$P|$S~#V#]%AΛPџTԣXר]٫`ܯc޲gjlٶjKf7d7e7e8Qxxvusqomk߳hݱfۮbت_֧\ӣXПTΛP˖KȒGĎCC>p}0^z-ks3f;pP-oYggg ��������������������������������������������������������������������������������ccc |`A]3Vp&My$P|#S~#V#x.HϝRҡVեZت_ۭbޱfjmp˵fp=e8e9e:f:L}~|{yvsqmk߳hܰeڬaة^ԤYҠUϜQ˘MȓHŎCAy/P|#Lz$Gu$gh/oO,|hggg ��������������������������������������������������������������������������������ccc nT[2Uo&My$P|#S~#X$7ɘLОSӢW֧\ڬaݯdilorcf:e:e<e<f=K|ƃłĀ~{wtpmj޲gۮc٫`֦[ӢWОS̘MɔIƏD@t-P|#Kx#Ds!Rj%mM+uggg ��������������������������������������������������������������������������������ccc}f|Z1To%My$Q|$S~#Y$9̘MџTԣXب]ۮc޲gkorw\e;f<f=f>f?uGƻtɉȇȅǃ|xspmߴiܰeڬaר]ԣXПS͙NʔIƐEB2Q|$Jx#Cr Ji"jK*ggg ��������������������������������������������������������������������������������ccc}zV1Xm'Ly#P|#S~#V#3ŘLѠUեZ٪_ܰeimrw|Ye=f?f@fAgAgBbʋˍʋɉDžŁ}wsok޲gۭbة^ԤYџT͚OʔIƏDC3O{#Jw#AqWb&hJ+ggg ��������������������������������������������������������������������������������cccuS/^j(Jx"P{#S~#V#n,IҡVզ[٫`ݱfjotzŀjf@fAgBgCgDgCvLuΒ͐̎ɊdžŁ{vql߳hܯd٪_եZѠUΚOʕJƏDB~1O{#Hv"Cpe[*mR6ggg ��������������������������������������������������������������������������������ccc}_?de+Iw"O{$S~#V#\&EӡV֧\ڬa޲glqx~DŽ}~NgCgDhEhFhFhFtN~ϔϒ̎ɊDžysniݰe٫_զ[ѡVΛOʕJƐE?k+N{$Gu!Pk#lU,w`Hggg ��������������������������������������������������������������������������������cccjs]/Gu"Nz#R~#V#X$9ҡV֧\ۭb߳hms{łɉ̏}yPgGhHhIhIhIhIkJi͒Γ̎ɉł|uojݰe٫`եZѠU͚OɔIĎC5S|$Nz#Pq$p_.mM,~lggg ��������������������������������������������������������������������������������ccczX4Sq%Ly#Q}#U#W$o.ѠU֧\ۭbߴinu~DžˍϓЗthIhJiKhKhKiKhIqNąЗΒˍDž~wpkݱf٫`եZѠUɘMB7Z%P|#Px%qj/{W1eH(fff ��������������������������������������������������������������������������������cccƾ|`Agh+Jx"P|$U#X$\(L֦[ۭbiovŁɈ͐їԝϖiKiMiMiMiMiMiLhKqӛЕ͏Ɉŀyplݱf٫_եZџTDj*]%R~$X|'}t4b6sQ.^D'fff ��������������������������������������������������������������������������������bbb~is[/Vq&Nz#S~$Z(_.>Ҧ]ۮfms{Džˎϖӝ֣գmQlRlSlSlSlRkPkOwUԞҚϓʋƃ{qlݱfت`ԤYОSFw.f(r~.z=m=~Z2hI)pfff ��������������������������������������������������������������������������������bbbsU2ig,Ow$S~%^/d5s=X۰krxĀɊΔҜפڪեrZrZs[s\r[rZqYpWpU̕Ԡљ̐ȈupݲjثcԤ\ϟVʗNFBDuBe9sQ.pX>fff��������������������������������������������������������������������������������bbb~hxZ0bp+S~(c8j=mAMίjw}ń̐љաڪܮŊxbycydydxdxcwaw_v]„ץԞΕʌŃzu޴o٭gԧaС[˙SŒPQ|Em>\4hK+}fff��������������������������������������������������������������������������������bbb|aD_4jy1lAqFsHvK^{lj͔ћќȐyklnonnm~k~i~gpН֤љ̑Ljz޵sٮlԨfТ`ʛYÕYYs@a7qP-t_Ifff��������������������������������������������������������������������������������bbbxX5m=RYV_n߻~NjˑulortvwwvusqokԢќ͓ȋƒ}ݶwدpԩiϣdɜ`–a[g:xU0aE'fff��������������������������������������������������������������������������������bbbva\4WoŤmЫrٳz߻ǎlnrvy{}~}zxuqq~ƌćĹxqib]ZciUZ3fH(vffff��������������������������������������������������������������������������������bbb~fLfAo˥yҫyز|ݺƐĉruy}|xuqlifca^[Y~Ygif?hK,r`eee��������������������������������������������������������������������������������bbbľ}cI|\ãΫձ۸߾đȓy~ďĐό~zvqoljgdbclszWoP/q]Ieee��������������������������������������������������������������������������������aaaw^DwƧѰضݼ‘ɘƑÎŒǖȘǕŒÎ{wuronklv|jtW8]F.eee��������������������������������������������������������������������������������aaat^{ĨҴٹ޾ŘʝЍđǔȘɚȘǕđ~{ywvzvrX=wfSeee��������������������������������������������������������������������������������aaa||ĬѵټƜɞÐÎőƓǖȗǖǕŒÏƯsr\Czleee��������������������������������������������������������������������������������aaa{ζپǟɠǚŔœƔǖǖƕǕœđÐ˷ȰrgR<ueee��������������������������������������������������������������������������������aaa~~~ÿñѻƥɦ̨̤ͧˡɞȜțǚŘŗ×—šսͷtatgfff��������������������������������������������������������������������������������aaa|||нªƫɬˬ̭̫ͭ˪ʨɨȧƦèտ͹o_zn~~~ggg��������������������������������������������������������������������������������bbb|||~ƸοİŰưƱůîͼŶ{kvhZ}{{{~hhh��������������������������������������������������������������������������������ccc{{{{o~ysfocWxzzzzhhg��������������������������������������������������������������������������������dddzzzv��������������������������������������������������������������������������������eeezzzs��������������������������������������������������������������������������������n��������������������������������������������������������������������������������i��������������������������������������������������������������������������������~e��������������������������������������������������������������������������������{c|^|^|^|^|^|^|^|^|^|^|^|^|^|^|^|^|^|^|_|_|_|_|_|_|_|_{^oPlL}jK{jLMr��������������������������������������������������������������������zaadddcdccdccdccdccdccdccdccdccdc`xUtTe����������������������������������������������������������������xľhhhggfeedddccdccdccdccdccdccdccdccczV~kK`����������������������������������������������������������������uilkkrrphggffedddkmlddddglmhddddddddcmM����������������������������������������������������������������svmonnӿ˵kjjihhgffDZμdccdͻðcdccdccdcqPwS ������������������������������������������������������������rprrqqnmmlkkjiifeedŲŰcdccdccdcvSyeG������������������������������������������������������������oqȧvǨvǧuƦu¢rqqpoonmmjiihȵDZeddddddddvTydH������������������������������������������������������������mr̬yͬy̫x˪xƦuťtĤtãs¢rrqppmllk̸whedddcvTzeI������������������������������������������������������������ktҰ|Ұ|ѯ{Я{׾ֽռӹʬ}ƦuĥtäsãspoonϻyggfewTzfI������������������������������������������������������������iv׵ص״ִ~̫x˪xʩwɨvťtäs£srԿ~kji{V{fI������������������������������������������������������������gu״صصصڿѯ{ЮzϭzέyɩwȨvǧuƦuտȫ̳nml}X|gJ������������������������������������������������������������du״صصصݾܼܽܽطִ~ճ~Բ}ӱ|έzͬy̫x˪xĢҹƦtĥṯʰppoZ|gJ������������������������������������������������������������cu״ٶٶٶǟǞǞǞݾۻǟǞǞĜÜÛշȥּà¡ťtĤsãs[}hJ����������������������������������������������������������������`yղ}صصصշʤЮ˧ϱʪwɨvȨvZgH����������������������������������������������������������������^έzصصصѯą̈̄ɡӴַЯ{ϮzέzͬyyU禋f����������������������������������������������������������������[uٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶص׵ִ~ֳ~Բ}mxV��������������������������������������������������������������������Ztִ~صٶصصٶصصٶصصٶصصٶصصٶصصٶصصٶصصٶصصٶصصpuQl!��������������������������������������������������������������������Xjikkkkkkkkkkkkkkklllllllllllkc`~XzYr!u��������������������������������������������������������������������UE:*=mT{��������������������������������������������������������������������������������M.)"����������������������������������������������������������������������������������������HHH-w,( ����������������������������������������������������������������������������������������222222333333222222111111111111111111111111111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 100 00/ 00/ 0/. /.- /.,/-+.,*.,)-+(-+'-*&-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%-*%,)$+(#+'"+'"*'!*& JB7 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?���������?���������?������������������������������������������������������������������������������������������������������������?���������?���������?��������������������������������(���H������� �����`T����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IIIGNNNYNNNWNNNVNNNUNNNTNNNSNNNQMMMPMMMOMMMNMMMMMMMLMMMJLLLIKKKHLLLFKKKEKKKDKKKBJJJAJJJ@III>III=III;HHH:HHH8GGG7FFF5FFF3FFF2FFF0EEE.-+)(&$"!~~~ vvv kkkwww��������������������������������������������������������������������������������忿侾㽽⽼⼻໺๹߸޷ݴܲ۲ڲٲر֨њ̕ʑ†aaax K."""222eee��������������������������������������������������������������������񏏏HHHo5%SSS����������������������������������������������������������������9���(����������������������������������������������������������������hhh���1;;;������������������������������������������������������������C "mmm��������������������������������������������������������ccc���)ttt�������������������������������������������������������� ���.�������������������������������������������������������� ���2�������������������������������������������������������� 999P�������������������������������������������������������� xgoX{djllorrk|j^^^|�������������������������������������������������������� q^gLtWhqonnnqut~hvdhhh�������������������������������������������������������� uex_@~Wedxaw`yb{d}fgjs}~~~fxhooo�������������������������������������������������������� x^BkJ}]s\t\u\v\v\w\y]z_coyz{|}}}|vt^{qqq��������������������������������������������������������{x[<nOcqXrXtXuXuXvWvWwW]mtvwxyyyyyxv{dusss��������������������������������������������������������wvV5nLdfccb`_]]`fšlÛnÜpÝqÞstvvwrkusy`ssss��������������������������������������������������������vW5d?`egjkj˜iÙiĚhŚgŚfĚeęeŚeĚgějŜkÜnÜpœrsrorqmtZttt��������������������������������������������������������{]=[4|Xadffe×dĘcřcǚaǚ`ǚ`ǚ`Ǚ_Ǚ^\QR^Úgšje\\flkdsYuuu��������������������������������������������������������jN|X2jB]`bbaÖ_Ř^Ǚ^Ț]ɚ\ʛ[ʛ[ʛZʚZʚYIj=j?qC~IMsKpLpNvRchevYybuuu��������������������������������������������������������zW3`7wM\^]\Õ[ŖYȘYʙYʚX̛X̛Y̜X̜X̛X̛W|=e6e6f8g;h=i@jCkFlIRcazZqUuuu��������������������������������������������������������www|]=\4i<QZYXÓWƕUȗTʙT˚V̛W͜W͝X͝X͝W͜W͜V=b2a0a0b2c4d7e:f=f@tG^]}YuUt[uuu��������������������������������������������������������jjjzW1d8qASUSRœQȕPʗR˚S̛U͝VΝWϞWϞWϞWϞVΝUIf0],\+\*],i1t6`3`6xBZZ~WwUoRpuuu��������������������������������������������������������kkkeG]5k<xDOOMđMǔMɖO˙Q͛SΝTϞVПWѠWѠWѠWѠVПUϞTNH:](c)BÑHDj4@VYWzTrQeIttt��������������������������������������������������������kkkƾwU1c8q@|EIIHƑIɕK˗N͚PΜRПTѠVҡWӢWԣXԣXԣXӣXӢWҠUџT̜Q?z2FȔJƒI@ASVW|TsPjMttt��������������������������������������������������������jjj}Y2i:w@CEDŎDȒHʖK͙OϝRџTӢWԤYեZ֧[ק\ק\ק\֧\֦[եZԣXҡVОSÚM˘MʖKȓIđHIOSV~StOkLnttt��������������������������������������������������������jjjsX|^2[r(Ry%k~,?ŒCǑFʖK͙NНRҠUԤX֦[ר]ت_٫`ګ`Ҫ^KEOר]ק\եZӢWѠUϜQ̘MʕJǒHďHKOSRvNkJz`Fttt��������������������������������������������������������jjjhI\g'Hv"N{#Q}#w,ŏDɔI̙NϝRҡVեZר]٪_ڬaۮcܯdSn7`1a1@ҫ^ڬaة^֧\ԣXҠUϜQ̘MɔIŐFŒGKOQwMkHpS4ttt��������������������������������������������������������jjja?]j(Jw"P|$S~#Z$?˗LϜQҡVեZة^ڬaܯdݱfܲfPl7?Qì\ֱdݲfܰeڭb٪_ק\ԣXѠUΛPʖKǒGÍDGLOwKkFqS3ƿsss��������������������������������������������������������kkkzY5ak)Ky#P|#T#Y$?͚OџTԤYة^ڬaݰe߳hܴhNh6p:ʲcnmlkiޱfۮc٪_֧\ӣXОS̙NɔIŎDDHLwIjCqR1sss��������������������������������������������������������jjjļxU0bl*My#Q}#T#]%FϝRӢWק\ڬaݰe߳hkYe6d6o;˵gsrqoljޱfۮc٪_եZѡVΜQʖKƐECECvAh@oP/rrr��������������������������������������������������������jjjyX4bm*Mz#R}#U#r-̙NџTեZ٪_ܯdߴimֶiw?d7e8h;µh{ywtqmjޱfڭbר]ӣXНR̘MǒG‹B9U|&Nx'pi3mM+rrr��������������������������������������������������������jjj`?al*Nz#R}#W#:ΛPҢWר]ۭb߳hlqʶgg:e;f<f=eƂŁ~{vqniܰe٫`զZџT͙NȓHÌC1O{$Hv"Pl%jK*ļqqq��������������������������������������������������������iiigH`k)Mz#R}#W#<ϜQԣX٪_ݰejpvbe<f=f?f?WɉɈDžŁ}wql޲gڭbק\ҡV͚OɔIÌC6O{$Gu!Ij"gI)ppp��������������������������������������������������������iiipTeh*Ly#R}#U#4ϝRեZڬa޲gms|hf?f@gBgBqH~̏ˌɈƃ|uojܯdة^ӢWΛPɔIÌC6Nz#Et!Vc%kP4ooo��������������������������������������������������������iiivib,Jx"Q}#U#g*͝R֦[ۭbipxŁ}tIgChEhFhFxPLjΓ̎ɈŁyqlݰeت_ӣXϜQɔIŒCy/Mz#Gr!gZ*q\nnn��������������������������������������������������������iiiǿsX.Iv"P|#U#\&I֦[ܮckr}Ȇ̎|jHhHhIhIhIlJ~ϔ̎Ȇ}tmޱfت_ӣXΛPȓH;W}%Mx#dh*oO,mmm��������������������������������������������������������hhh~aBXo'N{#T#Y%=ԥZܮcktŀʋϔҙfiKiLiMiLhJ_ϕϓʊŁvn޲gت_ӢW˜K4a'S|%ks.~]2dH(lll��������������������������������������������������������hhhzlb-Nx$S~$Z(m3̤ZܯfoxDž͑Қ֢xkPkRkRkQkOsSʎј̎Ƅxoޱgة_ҡVIl*b({6k:vT/{fPkkk��������������������������������������������������������gggwY5\p(Q}%`2g8R۲muʍљ֣ګ|t\t]s]s\rZqWԠϕɊ}t޳kتbҢZ˙QGDvB`6nQ2jjj��������������������������������������������������������gggy`2^y,g=nCwHh|Ņ͓Ԡդɒj|h|j|i{h{ezcs֤Ҝ̐ńz޵rحiҤ`̛XÓTMj<tR.taiii~��������������������������������������������������������eeegJi:QSYİo⾁Ɗʑpoquvvtqnlƌԡ͔lj俀޷wخnҥf˝``zKZ2lS8hhh{��������������������������������������������������������eee|úa@YápϪrڴ|ὅƍnsx||xssxpg_Zagf=kN0gggw��������������������������������������������������������dddzdByϪ|س޼ĐÉvz‹Œ|wplhea^_k\lM,}fffu��������������������������������������������������������cccwx[Ŧӱ۹ɘőǕǖő}xtqnjkwqtX9}m\dddr��������������������������������������������������������aaatrĩԶݽřșÏƔȘəǖđŒ|zw|©{y`Fxcccn��������������������������������������������������������```q}ҸƞǛēđƓǖǖǕŒÏĭzvbMbbbj��������������������������������������������������������___nʵƤɤˣˠʞțǚƘŖÕ•ʽʷq|n```g��������������������������������������������������������]]]kȷӿǬɭˮ̭˫ɩȩŨ̸swj^^^c��������������������������������������������������������\\\iyĵ|uf{\\\_��������������������������������������������������������[[[f{{z[������������������������������������������������������������[[[eW����������������������������������������������������������������bR����������������������������������������������������������������`N����������������������������������������������������������������^~b```````````````````_vUrQ}jLm����������������������������������������������������\gffedddddcdddcddddcdddcdc_tR^ ������������������������������������������������Ykkkongffeddejjdddgkhddcddd^sRZ������������������������������������������������WrpoŬkjjihgzddd¯ddcdddbkK}[��������������������������������������������UqťtĤsзponmlk«hgfϾdcccccbwcG\��������������������������������������������Ss̬y˪xּťtĤs£srqpɰlkk¨|wieddbwcG_��������������������������������������������PvԲ}Ӱ|αͱɫ̯ƦuťtϵqpoƫigexdGa��������������������������������������������Nwصصś׼άyͫxԺƦuťtäsɭʰukizeHc��������������������������������������������LwصصŜØØطղ}ӱ|ڿͬy̫x˪wͯťtʮŪom{fId��������������������������������������������JwصٶƜԵԵԴ˥ԵҴѳвʪʬ~ťtq}hJe��������������������������������������������G~صٶŚΪپѱ›έz̫xƦukLv������������������������������������������������EҰ|ٶڹ×ĘĘĘĘۻݿĘĘĘĘĘĘݽܼĘĘʕںֳ~ղ}ӱ|lbC������������������������������������������������C}Ϯ|ղ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ճ~ղ}ӱ|ptR����������������������������������������������������@wcFpSwlC��������������������������������������������������������;QI<����������������������������������������������������������������`pqrrsttuuvvwxxxyzz{{{{|||||||||{{{{zzzzyyyxxxwwwvvuu}}}nME8����������������������������������������������������������������{}x{t~xp|vm{ti{sg{sg{sg{sg{sf{sf{sf{sf{sf{sf{sf{sf{sfzrfvnaul_tk]siZ|i��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?������������������������������������(���@������� ������B��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PPPaWWWWWW}VVV{VVVyVVVxVVVvUUUtUUUsUUUqTTToTTTnTTTkSSSiRRRhRRRfQQQdQQQbPPP`PPP^OOO\OOOYNNNWNNNULLLRKKKPJJJNIIIKHHHH{{{FCA>;9630(uuuddd```\\\UUUKKK ������������������������������������������������������������������������{{{LLLj���/���$???����������������������������������������������������������������JJJn���2������������������������������������������������������������SSSs���0]]]��������������������������������������������������������4 ��������������������������������������������������������```���'�����������������������������������������������������������.�����������������������������������������������������������2��������������������������������������������������������zqx>>>U��������������������������������������������������������wp\mR|bquxz|x~g~ktWWW{��������������������������������������������������������xj|bD{Zlih}gikns}exi```��������������������������������������������������������}w\?wPy`u^u^v^w^y`|b}djy|}~~}ybzmddd��������������������������������������������������������{lxX6arZrYtYuYvYvYwYx[hvxxzz{z{{pvcfff��������������������������������������������������������q\zX5`f__^\[Z[c›mÜoÝqÞsžuwwwsmvns]ggg��������������������������������������������������������mwU0xVdgjkj™iÚhĚhŚfĚfęfŚfĚhĜkĜmÜoœrssorqeydggg��������������������������������������������������������vS/iC_dffeØdřcƚbǚaȚ`Ț`ǚ_ǚ^ZMVdĚif\\hlkw[xhhh��������������������������������������������������������vU3]5{S_aa`Ė^Ƙ]ș]ɚ[˛Z˛[˛Z˛YʚXBh<j?mBxHnGoJpMtQff}_qVhhh��������������������������������������������������������yyyk~Y2h<Y][[ĕYƗXɘW˚W̛X̜X̜X̜X̜W̛Wk7d4d4e7g:g=h@jCjFUa^uVu]hhh��������������������������������������������������������cccvS/b7sDXWVÓTǕSʗS˚T̛V͜WΝXΞXΞWΝWΜV;`/_._.`0a2c5c9d<M]ZxVpThhh��������������������������������������������������������___}e[3j<{HRQOƓNɖO˘Q͛S͜UϞVПWПWПWПVϞUO;6[(Z'6B9_3JYY{UrRhNhhh��������������������������������������������������������___vV3b7r@~GLJĐIȔKʗN̚QΜSПUѠVҡWҢWӢWӢWҡVҠUџTϝRB^(AȓIőI{7IUX~UuRjMggg��������������������������������������������������������___Ĺ{X1i;yDEFŒDƑFɕK̙NϜQџTӢWԤYեZ֦[ק\֧\֦[եZԤYӡVџTKɘMʖKȓIHKQVUvPkLggg��������������������������������������������������������^^^s}]2]r)Tz&2CŏDɔI̙NϝRҡVԤY֦[ة^٪_ګ`׫`NHUר]֦[ԤYҡVϝR͙NɕJƑGÏIMRTxOlJ{bHggg��������������������������������������������������������^^^sX_g(Iw"O{$S~#9ȒG̘MϝRҡVեZة^ګ`ۮcܯdǪ\s9a1a1Gۭb٫`ר]եZҡVϝR̘MȓHďFIMQyMlHnQ3ggg��������������������������������������������������������^^^dEbi*Kx#P|$T#p+ʖKΛPҡVզ[ت_ۭbݰe޳h[i6AZֲeߴi޲gܯdڬaة^եZҡVΛPʖKƑFEINyLkFpR1fff��������������������������������������������������������___uU2fk+Ly#Q}#U#q,̙NПTդYت_ۮc޲gjZf5c5ñapomkiݱfۭbة^ԤYПT̙NȓHÍCFJyIjCoP0fff��������������������������������������������������������^^^sR/gk,Mz$R~#V#7ΛPӢWר]ۭb޲gkյhl:d7e7^wuspmjݱfڬa֧\ҢWΜQʕJŎDC9my3i<mN,üeee��������������������������������������������������������^^^}^>fl+Nz$S~#V#EОSեZ٫`ޱfkpYe8e:f;\}{vrniܯd٪_ԤYОS˗LƐE>Q|$Kx$Xl)kL*eee��������������������������������������������������������^^^mQdj*Nz$S~#]%˗LѠUק\ܮciouRf<f=f>RɈdžƃ~xrm޳hڭb֧\џT̘MǑFAQ|$Iw"Hl!gI)ddd��������������������������������������������������������^^^|egg+My#S~#W#GҡVة^ݱfms|Rf?gAgBhCŃ̎ʋDžwpjܯdר]ҡV̙NǑFCP{$Hv"Qf$hL0ccc��������������������������������������������������������]]]}ka,Kx#R~#W#=ӢW٫`߳hoyƂlgBgDhEhFxPȊΒˍDž}smݱfة^ҢW͙NǑF<O{$Ft!d\*vbbbb��������������������������������������������������������]]]{sW.Jv#Q}$V#x1ӢWڬair~Ɉ͑ahHhIhJhIlKƈϓʋłwn޲gت_ҢW̙NďDr,Nz$]m(pP-aaa|��������������������������������������������������������]]]ziMZn'P|$U#\'ǟRڬajtł̎јϖiKiMiMiMiKgҙ͐Ȇzo޲gة^ҡV@j)R}$hw-`4dG(```y��������������������������������������������������������\\\xp^.Ly#U%`/FڭfozȈϕՠצnSmUmUmTmRqSӝЖʊ}q޲hש_џUDx.7o>wU/we___v��������������������������������������������������������\\\ugJen+V+i;oAǬfwĂ̑Ԟڪϛwaxbwcwbv_u\ʒԟ͒Ƅx޵oثeѡ[ʗQO{Db7gJ+^^^s��������������������������������������������������������ZZZs{Y1v}9qItJ[}ƈΖ̕mnppoliv֥ИȊ߷vحlѣbɚZZm=rQ.w]]]p��������������������������������������������������������ZZZqne;liزx༂ƌlrw{}~|yuoʑĆλ{pf^e\~Y2pYB\\\m��������������������������������������������������������YYYnkRb˦{ְ|޻ŏu{~yslhd`\[mlFfM2[[[j��������������������������������������������������������XXXk~fL~ЯڸɘÏƔǖŒ{vrnjkyebH,YYYg��������������������������������������������������������WWWhoҴܽřǗŒŒȗəǖđŒ~{x}©tlU>ĿXXXc��������������������������������������������������������VVVeζǟȜœœǕǖǕœÏƶĬoraPWWW_��������������������������������������������������������SSSbӾƧʨ̧̥ˢɟȝƛĚÞԿ˶o^UUU\��������������������������������������������������������SSS_ɹ®ƯǯȰƮĮѿxsRRRX��������������������������������������������������������QQQ]z~QQQS��������������������������������������������������������QQQ[O��������������������������������������������������������YJ��������������������������������������������������������VF��������������������������������������������������������Tf`````````````aaaa`yVtRւpRgo��������������������������������������������R|ggfedddddddddddddddddd`oOx��������������������������������������������Oflk{yhhgfedtvdddswddddddxU��������������������������������������������Mpqpmlkjiheeddddddd}YpO����������������������������������������KǧvȨvǧu£rqponmjiheedddd~YpQ����������������������������������������IϮzѯ{Ϯzҷеͱťtäs£ronmưofeZrR����������������������������������������Fճ~ص״ͬy̫xʩwťtäsrkj]tS����������������������������������������Dճ~ٶٶƛśճ~Բ}Ұ|ͬy˫xʩwťtätpoauT����������������������������������������Bճ}ٶٶٽٽ׺ܽٽٽֻּ׺αƦuťtdvU����������������������������������������?ǧvٶٶ–Ɯֹϭzͬya`����������������������������������������={ٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶٶص׵״Ұ|~\��������������������������������������������;prrrrrrrrrrrssssssrmf`l ��������������������������������������������8ZO=*v����������������������������������������������������$ĴŵŶƶǷƸǸȹȹȺɻʻʻʼʼʽ˾˾˾˾˾̾̾˾˾˾˾˽ʽʽʼʼɻȻȺȹǹǹƸƸŷŷĶŶĵôZQB��������������������������������������������������������dddfffeeecccccccccccccccccccccccccccccccccccccccccccccccccccbbbaaa``^ _^[ ^\X ]ZU \XR [VO ZUL ZTK ZTK ZTJ ZTJ ZTJ ZTJ ZTJ ZTJ ZTJ ZTJ ZTJ ZTJ XRH VOE UND TMA~r_������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?������������(���0���`���� �����%�������������������������������������� ��������������������������������������������������������������������������������������������zԱӰѯЮϭά̫˪ɩȨƧŦå¤}}}www^^^a'''2EEEUUU������������������������������������������������}}}?'''�������������������������������������������� :\\\����������������������������������������WWW&&&����������������������������������������%%%!����������������������������������������333(����������������������������������������xnniovyiiiP����������������������������������������~oW{[hlklp|{osxxxf����������������������������������������{kS~xOv^u]v]w]z_~cpz|}~}~h~}}}n����������������������������������������w}bE{Z]yYzYzX{XYjsuwyyxumwn����������������������������������������sz]=vTfijhfefęgĚhěkĜnÜqtroren����������������������������������������phLhA`de—cĘbƚaȚ_Ț_Ț^ř\NO]aYZhjv[m����������������������������������������l\4zP^^]ŗ[șZʚY˛Y˜Y˛XQj9g9i=kAkDmISd|]y`m����������������������������������������i|[7h;TXVŔTɘT˚ƯWΝXΝWΝWQh3`/`0b3c6d;oC]ZsUl����������������������������������������zzzg_6sAPOĒNȕO˙R͜TϞVПWѠWПVОUH=c*n.C:u;XXwSjOk����������������������������������������yyyflNh;{DHGǒI˗MΛQПTҡWӣXԤYԤYԤYӢWџTI=ɕJ‘HBSWzSmMĻj����������������������������������������yyyezZ2jr-x}1AŏDʖKΛPҠUԤYק\ة_ت_UNҧ[եZӢWОS̙NȓIĐHMS}QnK{i����������������������������������������yyydĹdb*Jx"Q}#1ɔIΛPҡV֧\٫`ۮc֮bDk6?ɪ\ڬaר]ԣXОS̘MƑGGMOnIu^h����������������������������������������yyycje,Ly#S~#h)̘MѠU֦[ڬaޱfֱeA@ִgkj޲gۮcة^ԣXΜQɕJÍDHLmEiNg����������������������������������������yyyblf-Nz#T#{0ϜQդYڬa޲g߶kHd6Euspm߳hۮc֧\ѠU̘MŏEC}:l<z_Ce����������������������������������������xxxakf,O{#U#>ѠUר]ݰemոkh:e;tD~~ztn޲g٬aԣX͛PǑF7Nz$Qo&hMd����������������������������������������xxx_Ƽic+Nz#U#AӢWڬajrŶjf=f?jBͿzɉDŽ}slܯd֦[ϜQȒG;My#Il"qZ~~~a����������������������������������������www^m`0Ly#T#8ԣXܯdmy{lDgDgEUʍ̎Džzoޱfר]ϝRȒG7Kx"Yc&}}}}_����������������������������������������www\uWMv#S#k,ԤYݰeqŀ̎vhIhJhJyS̐̎Łs߳hר]ΝRAc(Xs'oS-ü|||\����������������������������������������wwwZ^k)Q}#[(QݱguȇЖӞkOkPjPjMϕDžuߴiק]ÙLi)m|-g6rX;{{{Y����������������������������������������vvvXye=Vy'd6Iڴo~֣͒Ԣu^v`u_t\sԟˎ|߶o֩b͜UJwB{W1zzzV����������������������������������������uuuV}h6MRɳqćʑqqsrnlΙϖąx֫k͟_[d8|eMxxxT����������������������������������������tttSp]̨t۶Ì{t{~wuzpf]_YtW:wwwP����������������������������������������sssQzcִŏ~ΜĐzsnijqvZ;vvvM����������������������������������������qqqNغƚÑŒȘǖĐ|oXtttI����������������������������������������pppKӻƢȟɜȚǘŖÓŵvsssF����������������������������������������oooHʸŭɮɭǫéɷrrrB����������������������������������������oooE>����������������������������������������yyyC9����������������������������������������A5����������������������������������������>baaaaaaaaaaaaa}YuSf-��������������������������������<jkkfeddfhcdfgddccxT��������������������������������:qplkjhɶedƱddcd[xU ����������������������������8tʩwϴäsrpoĨkjsjdd\vT����������������������������5æyԲ}ԸͰǧvɬrpŰh^yV����������������������������3Ũzٶ׹ԴѰֶҰ|ϰ˪xɩvǪ~oc{X����������������������������1Ũzص׹ƜѳҸǧug|X ����������������������������.ٶØԴԵԴԴԵԵԴʤȠԴӴɣճҰ|d��������������������������������,uåuåuåuåuåuåuåuåvĥvĥvåvĥvåuph٠i>��������������������������������(j]J���������������������������������������� EMtttMvvvNuuuOuuuPuuuPvvvQvvvRwwwRwwwSwwwSwwwTxxxUxxxUxxxUxxxVxxxVxwwVwwvVwvuVvutVutrVutrVusqVtspVtrpUsroUsqoUsqoUrqoUrpnTqpmTqomTpnlTkifPthV ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(��� ���@���� �����������������������������������?=;986420.,*'%"  mmm������������������������������������bBBBk444����������������������������^HHHqVVV������������������������[DDD������������������������Xddd!������������������������TlahpuxxA������������������������QpzRu\u\w\bt{||nI������������������������M}jvTfdbagělÝpttqhI������������������������Je>ac×aǙ_ɛ]ɚ\T}GVUXi{bI������������������������FdAzLYÔWɘƯW͝X͝WHb1c3e9g@X|YH������������������������Df:KMȕN̚RϞUѠWѠW͟TFn.@;PWnPG������������������������C~a{s3@ƐF̙NѠUեZר]̦Y£TեZ͟S̙NƒHMTqMF������������������������Csj<My#n*˗LҡVة^ܯdTAQۮcר]ҡV˗LÎFMrJE������������������������Am_.O{#k*ϝRة^޲gYd6Ѷiqlݱfר]ϝRƑFCq?wD������������������������@th9P|#6ӢWݰepHe<mĀwmۮcӢWɔI1Mr$B������������������������?zUO{#3֦[jzPgCWˍDžv߳hեZʕJ1Qk$@������������������������=Qw$`(ӦZnDžLjhJiKaΒ~kեZ?^|(mY,=������������������������;ik1].UxΓգr[r[rXЙȈpԥ]Dr<{d:������������������������9Ja†uuvqɎոxĦe]~\87������������������������6vʨ~߾ŒÎzoggtQ4������������������������3˱śÐƔǖÏn0������������������������0͹Ȫɨƥǽ-������������������������.¾(������������������������+$������������������������)qcbbbbbbbb\}\w��������������������'n̶jhgDzddd]}X����������������%ű̫xɬåvpl§ðg_{W ����������������"ʶصÚϭzȨvʭèf[ ���������������� ˸ٶұֺ׾l_����������������Ʃ}ʪyʪyʪyʪyʪyʪy˫y˫yʪyťti��������������������׃t]����������������������������w|s|r|r|r|r|r}vlyqev��������������?��������������������������������������������������������������(������0���� �����` �������������������������� nmkigfca_]ZXURJ:[[[\\\��������������������H???YYYY����������������ENNN����������������Axxx����������������>r~[cfu}w5����������������:tZaa_dÜotvq7����������������7q}TaŘ^ɚ]ʛ[MHPWa6����������������4e:SœR˚SΝWϞWHm2x6s=Z~c6����������������3u7EʗLѠUեZЦZʣV̠TJGRtO5����������������2gO{#<ҡVڬaª[I«\ۭbԣXʖLHvJ4����������������0aQ}#E٪_ݶjp=_wmڭbϝRAjt02����������������/xQ}#J޲g۽thAVʊ|iӢW@Op#¹0����������������-ƽTw%?lʋkiMlʊnϡV|0pa1-����������������+|N}Gܻy˒x|ijϗzҤ`~H*����������������)m޻wkfz^'����������������&®›ƗȘÑ$����������������#Ƚķ ����������������!����������������fcbdbdb]ꖀ\>������������solgid|X������������ͭ|׽ϯ~ťtǰ\������������ͯϬԶԷcw������������ª©ªªªêi{m������������$''())**+++++****y)q��������������������������������������������������������(������ ���� �����@����������������������͍̐ňrSSS ������������.JJJ��������+��������'_`asxv$��������$zY]ș[˛ZEzFV$��������"Ĺx>ǓKПVѤYğRDHyR#��������!]'џTҭ`Mӱdר]ɕK{Fú"��������k,٫``QƂlΜQhx+ ��������]{+ѯȇmSyxO|p=��������γ|}w^��������ĸƼǟ¹����������������~fwln^؏xU����ξԸֽγ̳ҿuzV����Ğͯġ̮xߝ]����lnopqqqqqqpom�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftp.lpi��������������������������������������������������������0000644�0001750�0000144�00000012701�14743153644�017753� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <SaveOnlyProjectUnits Value="True"/> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <UseAppBundle Value="False"/> <Icon Value="0"/> </General> <i18n> <EnableI18N Value="True"/> <OutDir Value="..\language"/> </i18n> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="3"/> <RevisionNr Value="5"/> <StringTable FileDescription="FTP WFX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2024 Alexander Koblov"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\ftp.wfx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk;..\synapse"/> <OtherUnitFiles Value="..\synapse;..\..\..\..\sdk;sftp"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'darwin') and (TargetCPU = 'aarch64') then begin LinkerOptions += ' -rpath /opt/homebrew/lib'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <RequiredPackages Count="2"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> <Item2> <PackageName Value="LazUtils"/> </Item2> </RequiredPackages> <Units Count="6"> <Unit0> <Filename Value="ftp.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="ftputils.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="FtpUtils"/> </Unit1> <Unit2> <Filename Value="FtpConfDlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="DialogBox"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit2> <Unit3> <Filename Value="ftpfunc.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="FtpFunc"/> </Unit3> <Unit4> <Filename Value="ftpadv.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="FtpAdv"/> </Unit4> <Unit5> <Filename Value="sftp\sftpsend.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="SftpSend"/> </Unit5> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\ftp.wfx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\..\..\..\sdk;..\synapse"/> <OtherUnitFiles Value="..\synapse;..\..\..\..\sdk;sftp"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end; if (TargetOS = 'darwin') and (TargetCPU = 'aarch64') then begin LinkerOptions += ' -rpath /opt/homebrew/lib'; end;"/> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> </Other> </CompilerOptions> </CONFIG> ���������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftpadv.pas�����������������������������������������������������0000644�0001750�0000144�00000064365�14743153644�020462� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WFX plugin for working with File Transfer Protocol Copyright (C) 2009-2021 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit FtpAdv; {$mode delphi} {$macro on} interface uses Classes, SysUtils, WfxPlugin, FtpSend, DCClassesUtf8, LConvEncoding, DCConvertEncoding, DCFileAttributes, DCBasicTypes, blcksock, LazVersion; type TConvertUTF8ToEncodingFunc = function(const S: String {$IFDEF FPC_HAS_CPSTRING}; SetTargetCodePage: Boolean = False{$ENDIF}): RawByteString; type { EUserAbort } EUserAbort = class(Exception); { TFTPListRecEx } TFTPListRecEx = class(TFTPListRec) private FMode: TFileAttrs; public procedure Assign(Value: TFTPListRec); override; property Mode: TFileAttrs read FMode write FMode; end; { TFTPListEx } TFTPListEx = class(TFTPList) private FIndex: Integer; protected procedure FillRecord(const Value: TFTPListRec); override; public procedure Clear; override; procedure ParseLines; override; procedure Assign(Value: TFTPList); override; end; { TProgressStream } TProgressStream = class(TFileStreamEx) public DoneSize: Int64; FileSize: Int64; PluginNumber: Integer; ProgressProc: TProgressProcW; SourceName, TargetName: PWideChar; private FTime: QWord; FtpSend: TFTPSend; procedure DoProgress(Result: Integer); public function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; end; { TFTPSendEx } TFTPSendEx = class(TFTPSend) private FUnicode: Boolean; FSetTime: Boolean; FMachine: Boolean; FShowHidden: Boolean; FShowHiddenText: String; FUseAllocate: Boolean; FTcpKeepAlive: Boolean; FKeepAliveTransfer: Boolean; procedure SetEncoding(AValue: String); protected ConvertToUtf8: TConvertEncodingFunction; ConvertFromUtf8: TConvertUTF8ToEncodingFunc; protected FAuto: Boolean; FEncoding: String; FPublicKey, FPrivateKey: String; function Connect: Boolean; override; function DataSocket: Boolean; override; function ListMachine(Directory: String): Boolean; procedure DoStatus(Response: Boolean; const Value: string); override; procedure OnSocketStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); public function ServerToClient(const Value: AnsiString): UnicodeString; function ClientToServer(const Value: AnsiString): AnsiString; overload; function ClientToServer(const Value: UnicodeString): AnsiString; overload; public function FsFindFirstW(const Path: String; var FindData: TWin32FindDataW): Pointer; virtual; function FsFindNextW(Handle: Pointer; var FindData: TWin32FindDataW): BOOL; virtual; function FsFindClose(Handle: Pointer): Integer; virtual; function FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PWfxFileTime): BOOL; virtual; public constructor Create(const Encoding: String); virtual; reintroduce; function Login: Boolean; override; function Clone: TFTPSendEx; virtual; procedure CloneTo(AValue: TFTPSendEx); virtual; procedure ParseRemote(Value: string); override; function FileExists(const FileName: String): Boolean; virtual; function CreateDir(const Directory: string): Boolean; override; function FileProperties(const FileName: String): Boolean; virtual; function CopyFile(const OldName, NewName: String): Boolean; virtual; function ChangeMode(const FileName, Mode: String): Boolean; virtual; function List(Directory: String; NameList: Boolean): Boolean; override; function StoreFile(const FileName: string; Restore: Boolean): Boolean; override; function ExecuteCommand(const Command: String; const Directory: String = ''): Boolean; virtual; function RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; virtual; overload; function NetworkError(): Boolean; virtual; public property Encoding: String write SetEncoding; property UseAllocate: Boolean write FUseAllocate; property TcpKeepAlive: Boolean write FTcpKeepAlive; property PublicKey: String read FPublicKey write FPublicKey; property PrivateKey: String read FPrivateKey write FPrivateKey; property ShowHidden: Boolean read FShowHidden write FShowHidden; property KeepAliveTransfer: Boolean read FKeepAliveTransfer write FKeepAliveTransfer; end; { TFTPSendExClass } TFTPSendExClass = class of TFTPSendEx; implementation uses LazUTF8, DCOSUtils, FtpFunc, FtpUtils, synautil, synsock, DCStrUtils, DCDateTimeUtils {$IF (FPC_FULLVERSION < 30000)} , LazUTF8SysUtils {$ENDIF} ; {$IF NOT DECLARED(EncodingCP1250)} const EncodingCP1250 = 'cp1250'; EncodingCP1251 = 'cp1251'; EncodingCP1252 = 'cp1252'; EncodingCP1253 = 'cp1253'; EncodingCP1254 = 'cp1254'; EncodingCP1255 = 'cp1255'; EncodingCP1256 = 'cp1256'; EncodingCP1257 = 'cp1257'; EncodingCP1258 = 'cp1258'; EncodingCP437 = 'cp437'; EncodingCP850 = 'cp850'; EncodingCP852 = 'cp852'; EncodingCP866 = 'cp866'; EncodingCP874 = 'cp874'; EncodingCP932 = 'cp932'; EncodingCP936 = 'cp936'; EncodingCP949 = 'cp949'; EncodingCP950 = 'cp950'; EncodingCPKOI8 = 'koi8'; EncodingCPIso1 = 'iso88591'; EncodingCPIso2 = 'iso88592'; EncodingCPIso15 = 'iso885915'; {$ENDIF} {$IF NOT DECLARED(EncodingCPKOI8R)} const EncodingCPKOI8R = 'koi8r'; {$define KOI8RToUTF8:= KOI8ToUTF8} {$define UTF8ToKOI8R:= UTF8ToKOI8} {$ENDIF} function Dummy(const S: String): String; begin Result:= S; end; function Ymmud(const S: String {$IFDEF FPC_HAS_CPSTRING}; SetTargetCodePage: Boolean = False{$ENDIF}): RawByteString; begin Result:= S; end; function Utf8ToSys(const S: String {$IFDEF FPC_HAS_CPSTRING}; SetTargetCodePage: Boolean = False{$ENDIF}): RawByteString; begin Result:= CeUtf8ToSys(S); end; { TFTPListRecEx } procedure TFTPListRecEx.Assign(Value: TFTPListRec); begin inherited Assign(Value); Permission:= Value.Permission; if Value is TFTPListRecEx then Mode:= TFTPListRecEx(Value).Mode else Mode:= UnixStrToFileAttr(Permission); end; { TFTPListEx } procedure TFTPListEx.Clear; begin FIndex := 0; inherited Clear; end; procedure TFTPListEx.ParseLines; var ATotal: Int64; begin if FLines.Count > 0 then begin if Pos('total', FLines[0]) = 1 then begin if TryStrToInt64(Trim(Copy(FLines[0], 6, MaxInt)), ATotal) then FLines.Delete(0); end; end; inherited ParseLines; end; procedure TFTPListEx.FillRecord(const Value: TFTPListRec); var flr: TFTPListRecEx; begin inherited FillRecord(Value); if Value.Directory and (Value.FileName = '..') then begin flr := TFTPListRecEx.Create; flr.Assign(Value); FList.Add(flr); end; end; procedure TFTPListEx.Assign(Value: TFTPList); var flr: TFTPListRecEx; n: integer; begin Clear; for n := 0 to Value.Count - 1 do begin flr := TFTPListRecEx.Create; flr.Assign(Value[n]); Flist.Add(flr); end; Lines.Assign(Value.Lines); Masks.Assign(Value.Masks); UnparsedLines.Assign(Value.UnparsedLines); end; { TProgressStream } procedure TProgressStream.DoProgress(Result: Integer); var Percent: Int64; begin DoneSize += Result; Percent:= DoneSize * 100 div FileSize; if ProgressProc(PluginNumber, SourceName, TargetName, Percent) = 1 then raise EUserAbort.Create(EmptyStr); // Send keepalive also during a transfer if TFTPSendEx(FtpSend).KeepAliveTransfer then begin Percent:= GetTickCount64; if (Percent - FTime) > 30000 then begin FTime:= Percent; FtpSend.Sock.SendString(CRLF); end; end; end; function TProgressStream.Read(var Buffer; Count: Longint): Longint; begin Result:= inherited Read(Buffer, Count); if FileSize > 0 then DoProgress(Result); end; function TProgressStream.Write(const Buffer; Count: Longint): Longint; begin Result:= inherited Write(Buffer, Count); if FileSize > 0 then DoProgress(Result); end; { TFTPSendEx } procedure TFTPSendEx.SetEncoding(AValue: String); begin FEncoding:= AValue; if FEncoding = EncodingUTF8 then begin ConvertToUtf8:= @Dummy; ConvertFromUtf8:= @Ymmud; end else if FEncoding = EncodingCPIso1 then begin ConvertToUtf8:= @ISO_8859_1ToUTF8; ConvertFromUtf8:= @UTF8ToISO_8859_1; end else if FEncoding = EncodingCPIso2 then begin ConvertToUtf8:= @ISO_8859_2ToUTF8; ConvertFromUtf8:= @UTF8ToISO_8859_2; end else if FEncoding = EncodingCPIso15 then begin ConvertToUtf8:= @ISO_8859_15ToUTF8; ConvertFromUtf8:= @UTF8ToISO_8859_15; end else if FEncoding = EncodingCP1250 then begin ConvertToUtf8:= @CP1250ToUTF8; ConvertFromUtf8:= @UTF8ToCP1250; end else if FEncoding = EncodingCP1251 then begin ConvertToUtf8:= @CP1251ToUTF8; ConvertFromUtf8:= @UTF8ToCP1251; end else if FEncoding = EncodingCP1252 then begin ConvertToUtf8:= @CP1252ToUTF8; ConvertFromUtf8:= @UTF8ToCP1252; end else if FEncoding = EncodingCP1253 then begin ConvertToUtf8:= @CP1253ToUTF8; ConvertFromUtf8:= @UTF8ToCP1253; end else if FEncoding = EncodingCP1254 then begin ConvertToUtf8:= @CP1254ToUTF8; ConvertFromUtf8:= @UTF8ToCP1254; end else if FEncoding = EncodingCP1255 then begin ConvertToUtf8:= @CP1255ToUTF8; ConvertFromUtf8:= @UTF8ToCP1255; end else if FEncoding = EncodingCP1256 then begin ConvertToUtf8:= @CP1256ToUTF8; ConvertFromUtf8:= @UTF8ToCP1256; end else if FEncoding = EncodingCP1257 then begin ConvertToUtf8:= @CP1257ToUTF8; ConvertFromUtf8:= @UTF8ToCP1257; end else if FEncoding = EncodingCP1258 then begin ConvertToUtf8:= @CP1258ToUTF8; ConvertFromUtf8:= @UTF8ToCP1258; end else if FEncoding = EncodingCP437 then begin ConvertToUtf8:= @CP437ToUTF8; ConvertFromUtf8:= @UTF8ToCP437; end else if FEncoding = EncodingCP850 then begin ConvertToUtf8:= @CP850ToUTF8; ConvertFromUtf8:= @UTF8ToCP850; end else if FEncoding = EncodingCP852 then begin ConvertToUtf8:= @CP852ToUTF8; ConvertFromUtf8:= @UTF8ToCP852; end else if FEncoding = EncodingCP866 then begin ConvertToUtf8:= @CP866ToUTF8; ConvertFromUtf8:= @UTF8ToCP866; end else if FEncoding = EncodingCP874 then begin ConvertToUtf8:= @CP874ToUTF8; ConvertFromUtf8:= @UTF8ToCP874; end else if FEncoding = EncodingCP932 then begin ConvertToUtf8:= @CP932ToUTF8; ConvertFromUtf8:= @UTF8ToCP932; end else if FEncoding = EncodingCP936 then begin ConvertToUtf8:= @CP936ToUTF8; ConvertFromUtf8:= @UTF8ToCP936; end else if FEncoding = EncodingCP949 then begin ConvertToUtf8:= @CP949ToUTF8; ConvertFromUtf8:= @UTF8ToCP949; end else if FEncoding = EncodingCP950 then begin ConvertToUtf8:= @CP950ToUTF8; ConvertFromUtf8:= @UTF8ToCP950; end else if FEncoding = EncodingCPKOI8R then begin ConvertToUtf8:= @KOI8RToUTF8; ConvertFromUtf8:= @UTF8ToKOI8R; end; end; function TFTPSendEx.Connect: Boolean; var Option: Cardinal = 1; Message: UnicodeString; begin Result:= inherited Connect; if Result then LogProc(PluginNumber, MSGTYPE_CONNECT, nil); // Apply TcpKeepAlive option if FTcpKeepAlive and Result then begin if SetSockOpt(FSock.Socket, SOL_SOCKET, SO_KEEPALIVE, @Option, SizeOf(Option)) <> 0 then begin Message := UTF8ToUTF16(FSock.GetErrorDesc(synsock.WSAGetLastError)); LogProc(PluginNumber, msgtype_importanterror, PWideChar('CSOCK ERROR ' + Message)); end; end; end; function TFTPSendEx.DataSocket: Boolean; var Message: UnicodeString; begin Result:= inherited DataSocket; if FDSock.LastError <> 0 then begin Message:= UTF8ToUTF16(CeSysToUtf8(FDSock.LastErrorDesc)); LogProc(PluginNumber, msgtype_importanterror, PWideChar('DSOCK ERROR ' + Message)); end; end; function TFTPSendEx.ListMachine(Directory: String): Boolean; var v: String; start: Boolean; s, x, y: Integer; flr: TFTPListRecEx; pdir, pcdir: Boolean; option, value: String; begin FFTPList.Clear; Result := False; FDataStream.Clear; if Directory <> '' then Directory := ' ' + Directory; FTPCommand('TYPE A'); if not DataSocket then Exit; x := FTPCommand('MLSD' + Directory); if (x div 100) <> 1 then Exit; Result := DataRead(FDataStream); if Result then begin pdir := False; FDataStream.Position := 0; FFTPList.Lines.LoadFromStream(FDataStream); for x:= 0 to FFTPList.Lines.Count - 1 do begin s:= 1; start := False; flr := TFTPListRecEx.Create; v:= FFTPList.Lines[x]; flr.OriginalLine:= v; // DoStatus(True, v); for y:= 1 to Length(v) do begin if (not start) and (v[y] = '=') then begin option:= LowerCase(Copy(v, s, y - s)); start := True; s:= y + 1; end else if v[y] = ';' then begin value:= LowerCase(Copy(v, s, y - s)); if (option = 'type') then begin // Skip 'cdir' entry if (value = 'cdir') then begin FreeAndNil(flr); Break; end; // Parent directory entry pcdir := (value = 'pdir'); if pcdir then begin // Skip duplicate 'pdir' entry if pdir then begin FreeAndNil(flr); Break; end; pdir := True; end; flr.Directory:= (value = 'os.unix=symlink'); if flr.Directory then flr.Mode := flr.Mode or S_IFLNK else begin flr.Directory := pcdir or (value = 'dir'); end; end else if (option = 'modify') then begin flr.FileTime:= DecodeMachineTime(value); end else if (option = 'size') then begin flr.FileSize:= StrToInt64Def(value, 0); end else if (option = 'unix.mode') then begin flr.Mode:= flr.Mode or OctToDec(value); end; if (y < Length(v)) and (v[y + 1] = ' ') then begin if (flr.Directory and pcdir) then flr.FileName:= '..' else flr.FileName:= SeparateLeft(Copy(v, y + 2, MaxInt), ' -> '); Break; end; start := False; s:= y + 1; end; end; if Assigned(flr) then FFTPList.List.Add(flr); end; end; FDataStream.Position := 0; end; procedure TFTPSendEx.DoStatus(Response: Boolean; const Value: string); var Index: Integer; Message: UnicodeString; begin Index:= Pos('PASS ', Value); if Index = 0 then Message:= ServerToClient(Value) else begin Message:= ServerToClient(Copy(Value, 1, Index + 4)) + '********'; end; LogProc(PluginNumber, msgtype_details, PWideChar(Message)); if FSock.LastError <> 0 then begin Message:= UTF8ToUTF16(CeSysToUtf8(FSock.LastErrorDesc)); LogProc(PluginNumber, msgtype_importanterror, PWideChar('CSOCK ERROR ' + Message)); end; end; procedure TFTPSendEx.OnSocketStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); var MsgType: Integer; begin if (Reason in [HR_ResolvingBegin, HR_ResolvingEnd, HR_Error]) then begin if (Length(Value) > 0) then begin if Reason = HR_Error then MsgType:= msgtype_importanterror else begin MsgType:= msgtype_details; end; LogProc(PluginNumber, MsgType, PWideChar(ServerToClient(Value))); end; end; end; function TFTPSendEx.ClientToServer(const Value: AnsiString): AnsiString; begin Result:= ConvertFromUtf8(Value); end; function TFTPSendEx.ClientToServer(const Value: UnicodeString): AnsiString; begin Result:= ConvertFromUtf8(UTF16ToUTF8(Value)); end; function TFTPSendEx.ServerToClient(const Value: AnsiString): UnicodeString; begin Result:= UTF8ToUTF16(ConvertToUtf8(Value)); end; function TFTPSendEx.FsFindFirstW(const Path: String; var FindData: TWin32FindDataW): Pointer; begin Result:= nil; // Get directory listing if List(Path, False) then begin if FtpList.Count > 0 then begin // Save file list Result:= TFTPListEx.Create; TFTPListEx(Result).Assign(FtpList); FsFindNextW(Result, FindData); end; end; end; function TFTPSendEx.FsFindNextW(Handle: Pointer; var FindData: TWin32FindDataW): BOOL; var I: Integer; FtpList: TFTPListEx absolute Handle; begin Result := False; if Assigned(FtpList) then begin I := FtpList.FIndex; if I < FtpList.Count then begin FillChar(FindData, SizeOf(FindData), 0); StrPCopy(FindData.cFileName, ServerToClient(FtpList.Items[I].FileName)); FindData.dwFileAttributes := FindData.dwFileAttributes or FILE_ATTRIBUTE_UNIX_MODE; if TFTPListEx(FtpList).Items[I].Directory then FindData.dwFileAttributes := FindData.dwFileAttributes or FILE_ATTRIBUTE_DIRECTORY else begin FindData.nFileSizeLow := (FtpList.Items[I].FileSize and MAXDWORD); FindData.nFileSizeHigh := (FtpList.Items[I].FileSize shr $20); end; // set Unix permissions FindData.dwReserved0 := TFTPListRecEx(FtpList.Items[I]).Mode; FindData.ftLastWriteTime := TWfxFileTime(DateTimeToWinFileTime(FtpList.Items[I].FileTime)); Inc(FtpList.FIndex); Result := True; end; end; end; function TFTPSendEx.FsFindClose(Handle: Pointer): Integer; begin Result:= 0; FreeAndNil(TFTPListEx(Handle)); end; constructor TFTPSendEx.Create(const Encoding: String); begin inherited Create; FTimeout:= 15000; FDirectFile:= True; ConvertToUtf8:= @CeSysToUtf8; ConvertFromUtf8:= @Utf8ToSys; Sock.OnStatus:= OnSocketStatus; FEncoding:= NormalizeEncoding(Encoding); FAuto:= (FEncoding = '') or (FEncoding = 'auto'); if not FAuto then SetEncoding(FEncoding); FFtpList.Free; FFtpList:= TFTPListEx.Create; // Move mostly used UNIX format to first FFtpList.Masks.Exchange(0, 2); // Windows CE 5.1 (insert before BullGCOS7) FFtpList.Masks.Insert(35, 'MM DD YY hh mm !S* n*'); FFtpList.Masks.Insert(36, 'MM DD YY hh mm $ d!n*'); end; function TFTPSendEx.Login: Boolean; var Index: Integer; begin Result:= inherited Login; if Result then begin if IsTLS and Sock.SSL.SSLEnabled then begin LogProc(PluginNumber, msgtype_details, PWideChar('TLS Library ' + UTF8ToUTF16(FSock.SSL.LibVersion))); LogProc(PluginNumber, msgtype_details, PWideChar('TLS Protocol ' + UTF8ToUTF16(FSock.SSL.GetSSLVersion))); LogProc(PluginNumber, msgtype_details, PWideChar('TLS Cipher ' + UTF8ToUTF16(FSock.SSL.GetCipherName))); end; if (FTPCommand('FEAT') div 100) = 2 then begin for Index:= 0 to FFullResult.Count - 1 do begin if not FMachine then FMachine:= Pos('MLST', FFullResult[Index]) > 0; if not FMachine then FMachine:= Pos('MLSD', FFullResult[Index]) > 0; if not FUnicode then FUnicode:= Pos('UTF8', FFullResult[Index]) > 0; if not FSetTime then FSetTime:= Pos('MFMT', FFullResult[Index]) > 0; end; if FUnicode and FAuto then begin ConvertToUtf8:= @Dummy; ConvertFromUtf8:= @Ymmud; FTPCommand('OPTS UTF8 ON'); end; end; if (not FMachine) and FShowHidden then begin if inherited List('-la', False) then FShowHiddenText:= '-la' else begin DoStatus(False, 'Server does not seem to support LIST -a'); end; end; end; end; function TFTPSendEx.Clone: TFTPSendEx; begin Result:= TFTPSendExClass(ClassType).Create(FEncoding); CloneTo(Result); end; procedure TFTPSendEx.CloneTo(AValue: TFTPSendEx); begin AValue.TargetHost := TargetHost; AValue.TargetPort:= TargetPort; AValue.PassiveMode:= PassiveMode; AValue.AutoTLS:= AutoTLS; AValue.FullSSL:= FullSSL; AValue.UseAllocate:= FUseAllocate; AValue.UserName:= UserName; AValue.Password:= Password; AValue.KeepAliveTransfer:= KeepAliveTransfer; AValue.PublicKey:= FPublicKey; AValue.PrivateKey:= FPrivateKey; AValue.ShowHidden:= FShowHidden; AValue.TcpKeepAlive:= FTcpKeepAlive; AValue.Sock.HTTPTunnelIP:= Sock.HTTPTunnelIP; AValue.Sock.HTTPTunnelPort:= Sock.HTTPTunnelPort; AValue.Sock.HTTPTunnelUser:= Sock.HTTPTunnelUser; AValue.Sock.HTTPTunnelPass:= Sock.HTTPTunnelPass; AValue.Sock.SocksIP:= Sock.SocksIP; AValue.Sock.SocksType:= Sock.SocksType; AValue.Sock.SocksPort:= Sock.SocksPort; AValue.Sock.SocksUsername:= Sock.SocksUsername; AValue.Sock.SocksPassword:= Sock.SocksPassword; AValue.DSock.HTTPTunnelIP:= DSock.HTTPTunnelIP; AValue.DSock.HTTPTunnelPort:= DSock.HTTPTunnelPort; AValue.DSock.HTTPTunnelUser:= DSock.HTTPTunnelUser; AValue.DSock.HTTPTunnelPass:= DSock.HTTPTunnelPass; AValue.DSock.SocksIP:= DSock.SocksIP; AValue.DSock.SocksType:= DSock.SocksType; AValue.DSock.SocksPort:= DSock.SocksPort; AValue.DSock.SocksUsername:= DSock.SocksUsername; AValue.DSock.SocksPassword:= DSock.SocksPassword; end; procedure TFTPSendEx.ParseRemote(Value: string); var RemoteIP: String; begin inherited ParseRemote(Value); RemoteIP:= FSock.GetRemoteSinIP; if FDataIP = '0.0.0.0' then FDataIP:= RemoteIP else if IsIpPrivate(FDataIP) and (IsIpPrivate(RemoteIP) = False) then begin FDataIP:= RemoteIP; DoStatus(False, 'Server reports local IP -> Redirect to: ' + FDataIP); end; end; function TFTPSendEx.FileExists(const FileName: String): Boolean; begin Result:= (Self.FileSize(FileName) >= 0); end; function TFTPSendEx.CreateDir(const Directory: string): Boolean; var sOldPath: AnsiString; begin sOldPath := GetCurrentDir; if ChangeWorkingDir(Directory) then Result := ChangeWorkingDir(sOldPath) else begin Result := inherited CreateDir(Directory); end; end; function TFTPSendEx.ExecuteCommand(const Command, Directory: String): Boolean; begin Result:= (FTPCommand(Command) div 100) = 2; end; function TFTPSendEx.FileProperties(const FileName: String): Boolean; begin Result:= (FTPCommand('STAT' + #32 + FileName) div 100) = 2; end; function TFTPSendEx.CopyFile(const OldName, NewName: String): Boolean; begin Result:= False; end; function TFTPSendEx.ChangeMode(const FileName, Mode: String): Boolean; begin Result:= (FTPCommand('SITE CHMOD' + #32 + Mode + #32 + FileName) div 100) = 2; end; function TFTPSendEx.List(Directory: String; NameList: Boolean): Boolean; var Message: UnicodeString; begin Result:= ChangeWorkingDir(Directory); if Result then begin if FMachine then Result:= ListMachine(EmptyStr) else begin Result:= inherited List(FShowHiddenText, NameList); end; if (Result = False) and (FSock.WaitingData > 0) then begin Message:= UnicodeString(FSock.RecvPacket(1000)); LogProc(PluginNumber, msgtype_importanterror, PWideChar(Message)); end; end; end; function TFTPSendEx.FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PWfxFileTime): BOOL; var Time: String; begin if not FSetTime then Exit(False); if (LastWriteTime = nil) then Exit(False); Time:= FormatMachineTime(LastWriteTime^); Result:= FTPCommand('MFMT ' + Time + ' ' + FileName) = 213; end; function TFTPSendEx.StoreFile(const FileName: string; Restore: Boolean): Boolean; var StorSize: Int64; RestoreAt: Int64 = 0; SendStream: TProgressStream; begin Result := False; Restore := Restore and FCanResume; if Restore then begin RestoreAt := Self.FileSize(FileName); if RestoreAt < 0 then RestoreAt := 0; end; SendStream := TProgressStream.Create(FDirectFileName, fmOpenRead or fmShareDenyWrite); SendStream.FtpSend:= Self; SendStream.PluginNumber:= PluginNumber; SendStream.ProgressProc:= ProgressProc; SendStream.TargetName:= PWideChar(ServerToClient(FileName)); SendStream.SourceName:= PWideChar(CeUtf8ToUtf16(FDirectFileName)); try if not DataSocket then Exit; FTPCommand('TYPE I'); StorSize := SendStream.Size; if not FCanResume then RestoreAt := 0; if RestoreAt > StorSize then RestoreAt := 0; if (StorSize > 0) and (RestoreAt = StorSize) then begin Result := True; Exit; end; SendStream.FileSize := StorSize; SendStream.DoneSize := RestoreAt; if FUseAllocate then FTPCommand('ALLO ' + IntToStr(StorSize - RestoreAt)); if FCanResume then begin if (FTPCommand('REST ' + IntToStr(RestoreAt)) div 100) <> 3 then Exit; end; SendStream.Position := RestoreAt; if (FTPCommand('STOR ' + FileName) div 100) <> 1 then Exit; Result := DataWrite(SendStream); finally SendStream.Free; end; end; function TFTPSendEx.RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; var RetrStream: TProgressStream; begin Result := False; if not DataSocket then Exit; Restore := Restore and FCanResume; if Restore and mbFileExists(FDirectFileName) then RetrStream := TProgressStream.Create(FDirectFileName, fmOpenWrite or fmShareExclusive) else begin RetrStream := TProgressStream.Create(FDirectFileName, fmCreate or fmShareDenyWrite) end; RetrStream.FtpSend := Self; RetrStream.FileSize := FileSize; RetrStream.PluginNumber := PluginNumber; RetrStream.ProgressProc := ProgressProc; RetrStream.SourceName := PWideChar(ServerToClient(FileName)); RetrStream.TargetName := PWideChar(CeUtf8ToUtf16(FDirectFileName)); try FTPCommand('TYPE I'); if Restore then begin RetrStream.DoneSize := RetrStream.Size; RetrStream.Position := RetrStream.DoneSize; if (FTPCommand('REST ' + IntToStr(RetrStream.DoneSize)) div 100) <> 3 then Exit; end; if (FTPCommand('RETR ' + FileName) div 100) <> 1 then Exit; Result := DataRead(RetrStream); finally RetrStream.Free; end; end; function TFTPSendEx.NetworkError(): Boolean; begin Result := FSock.CanRead(0); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftpfunc.pas����������������������������������������������������0000644�0001750�0000144�00000117730�14743153644�020636� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Wfx plugin for working with File Transfer Protocol Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit FtpFunc; {$mode delphi}{$H+} {$include calling.inc} interface uses SysUtils, Classes, WfxPlugin, Extension; const cAddConnection = '<Add connection>'; cQuickConnection = '<Quick connection>'; type { TConnection } TConnection = class public ConnectionName, Path, Host: AnsiString; Port: AnsiString; UserName: AnsiString; Password: AnsiString; MasterPassword: Boolean; CachedPassword: AnsiString; Proxy: String; PassiveMode: Boolean; CopySCP: Boolean; OnlySCP: Boolean; AutoTLS: Boolean; FullSSL: Boolean; OpenSSH: Boolean; AgentSSH: Boolean; UseAllocate: Boolean; Encoding: AnsiString; Fingerprint: AnsiString; InitCommands: AnsiString; ShowHiddenItems: Boolean; PasswordChanged: Boolean; KeepAliveTransfer: Boolean; PublicKey, PrivateKey: String; public procedure Assign(Connection: TConnection); end; function FsInitW(PluginNr: Integer; pProgressProc: TProgressProcW; pLogProc: TLogProcW; pRequestProc: TRequestProcW): Integer; dcpcall; export; function FsFindFirstW(Path: PWideChar; var FindData: TWin32FindDataW): THandle; dcpcall; export; function FsFindNextW(Hdl: THandle; var FindData: TWin32FindDataW): BOOL; dcpcall; export; function FsFindClose(Hdl: THandle): Integer; dcpcall; export; function FsExecuteFileW(MainWin: THandle; RemoteName, Verb: PWideChar): Integer; dcpcall; export; function FsRenMovFileW(OldName, NewName: PWideChar; Move, OverWrite: BOOL; RemoteInfo: pRemoteInfo): Integer; dcpcall; export; function FsGetFileW(RemoteName, LocalName: PWideChar; CopyFlags: Integer; RemoteInfo: pRemoteInfo): Integer; dcpcall; export; function FsPutFileW(LocalName, RemoteName: PWideChar; CopyFlags: Integer) : Integer; dcpcall; export; function FsDeleteFileW(RemoteName: PWideChar): BOOL; dcpcall; export; function FsMkDirW(RemoteDir: PWideChar): BOOL; dcpcall; export; function FsRemoveDirW(RemoteName: PWideChar): BOOL; dcpcall; export; function FsSetTimeW(RemoteName: PWideChar; CreationTime, LastAccessTime, LastWriteTime: PFileTime): BOOL; dcpcall; export; function FsDisconnectW(DisconnectRoot: PWideChar): BOOL; dcpcall; export; procedure FsSetCryptCallbackW(pCryptProc: TCryptProcW; CryptoNr, Flags: Integer); dcpcall; export; procedure FsGetDefRootName(DefRootName: PAnsiChar; MaxLen: Integer); dcpcall; export; procedure FsSetDefaultParams(dps: pFsDefaultParamStruct); dcpcall; export; procedure FsStatusInfoW(RemoteDir: PWideChar; InfoStartEnd, InfoOperation: Integer); dcpcall; export; function FsGetBackgroundFlags: Integer; dcpcall; export; { Network API } { procedure FsNetworkGetSupportedProtocols(Protocols: PAnsiChar; MaxLen: LongInt); dcpcall; export; function FsNetworkGetConnection(Index: LongInt; Connection: PAnsiChar; MaxLen: LongInt): LongBool; dcpcall; export; function FsNetworkManageConnection(MainWin: HWND; Connection: PAnsiChar; Action: LongInt; MaxLen: LongInt): LongBool; dcpcall; export; function FsNetworkOpenConnection(Connection: PAnsiChar; RootDir, RemotePath: PAnsiChar; MaxLen: LongInt): LongBool; dcpcall; export; } { Extension API } procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); dcpcall; export; function ReadPassword(ConnectionName: AnsiString; out Password: AnsiString): Boolean; function DeletePassword(ConnectionName: AnsiString): Boolean; var gStartupInfo: TExtensionStartupInfo; var LogProc: TLogProcW; CryptProc: TCryptProcW; PluginNumber: Integer; CryptoNumber: Integer; RequestProc: TRequestProcW; ProgressProc: TProgressProcW; implementation uses IniFiles, StrUtils, FtpAdv, FtpUtils, FtpConfDlg, syncobjs, LazFileUtils, LazUTF8, DCClassesUtf8, DCConvertEncoding, SftpSend, ScpSend, FtpProxy, FtpPropDlg, DCFileAttributes; var DefaultIniName: String; TcpKeepAlive: Boolean = True; ActiveConnectionList, ConnectionList: TStringList; IniFile: TIniFile; ListLock: TCriticalSection; threadvar ThreadCon: TFtpSendEx; const FS_COPYFLAGS_FORCE = FS_COPYFLAGS_OVERWRITE or FS_COPYFLAGS_RESUME; RootList: array [0 .. 1] of AnsiString = (cAddConnection, cQuickConnection); type TListRec = record Path: AnsiString; Index: Integer; FtpSend: TFTPSendEx; FtpList: TFTPListEx; end; PListRec = ^TListRec; procedure ReadConnectionList; var I, Count: Integer; sIndex: AnsiString; Connection: TConnection; begin Count := IniFile.ReadInteger('FTP', 'ConnectionCount', 0); for I := 1 to Count do begin sIndex := IntToStr(I); Connection := TConnection.Create; Connection.ConnectionName := IniFile.ReadString('FTP', 'Connection' + sIndex + 'Name', EmptyStr); Connection.Path := IniFile.ReadString('FTP', 'Connection' + sIndex + 'Path', EmptyStr); Connection.Host := IniFile.ReadString('FTP', 'Connection' + sIndex + 'Host', EmptyStr); Connection.Port := IniFile.ReadString('FTP', 'Connection' + sIndex + 'Port', EmptyStr); Connection.UserName := IniFile.ReadString('FTP', 'Connection' + sIndex + 'UserName', EmptyStr); Connection.MasterPassword := IniFile.ReadBool('FTP', 'Connection' + sIndex + 'MasterPassword', False); if Connection.MasterPassword then Connection.Password := EmptyStr else Connection.Password := DecodeBase64(IniFile.ReadString('FTP', 'Connection' + sIndex + 'Password', EmptyStr)); Connection.Proxy := IniFile.ReadString('FTP', 'Connection' + sIndex + 'Proxy', EmptyStr); Connection.Encoding := IniFile.ReadString('FTP', 'Connection' + sIndex + 'Encoding', EmptyStr); Connection.PassiveMode:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'PassiveMode', True); Connection.AutoTLS:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'AutoTLS', False); Connection.FullSSL:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'FullSSL', False); Connection.OpenSSH:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'OpenSSH', False); Connection.OnlySCP:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'OnlySCP', False); Connection.CopySCP:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'CopySCP', False); Connection.AgentSSH:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'AgentSSH', False); Connection.UseAllocate:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'UseAllocate', False); Connection.PublicKey := IniFile.ReadString('FTP', 'Connection' + sIndex + 'PublicKey', EmptyStr); Connection.PrivateKey := IniFile.ReadString('FTP', 'Connection' + sIndex + 'PrivateKey', EmptyStr); Connection.Fingerprint:= IniFile.ReadString('FTP', 'Connection' + sIndex + 'Fingerprint', EmptyStr); Connection.InitCommands := IniFile.ReadString('FTP', 'Connection' + sIndex + 'InitCommands', EmptyStr); Connection.ShowHiddenItems := IniFile.ReadBool('FTP', 'Connection' + sIndex + 'ShowHiddenItems', True); Connection.KeepAliveTransfer := IniFile.ReadBool('FTP', 'Connection' + sIndex + 'KeepAliveTransfer', False); // add connection to connection list ConnectionList.AddObject(Connection.ConnectionName, Connection); end; LoadProxyList(IniFile); end; procedure WriteConnectionList; var I, Count: Integer; sIndex: AnsiString; Connection: TConnection; begin IniFile.EraseSection('FTP'); Count := ConnectionList.Count; IniFile.WriteInteger('FTP', 'ConnectionCount', Count); for I := 0 to Count - 1 do begin sIndex := IntToStr(I + 1); Connection := TConnection(ConnectionList.Objects[I]); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Name', Connection.ConnectionName); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Path', Connection.Path); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Host', Connection.Host); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Port', Connection.Port); IniFile.WriteString('FTP', 'Connection' + sIndex + 'UserName', Connection.UserName); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'MasterPassword', Connection.MasterPassword); if Connection.MasterPassword then IniFile.DeleteKey('FTP', 'Connection' + sIndex + 'Password') else IniFile.WriteString('FTP', 'Connection' + sIndex + 'Password', EncodeBase64(Connection.Password)); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Proxy', Connection.Proxy); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Encoding', Connection.Encoding); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'PassiveMode', Connection.PassiveMode); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'AutoTLS', Connection.AutoTLS); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'FullSSL', Connection.FullSSL); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'OpenSSH', Connection.OpenSSH); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'OnlySCP', Connection.OnlySCP); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'CopySCP', Connection.CopySCP); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'AgentSSH', Connection.AgentSSH); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'UseAllocate', Connection.UseAllocate); IniFile.WriteString('FTP', 'Connection' + sIndex + 'PublicKey', Connection.PublicKey); IniFile.WriteString('FTP', 'Connection' + sIndex + 'PrivateKey', Connection.PrivateKey); IniFile.WriteString('FTP', 'Connection' + sIndex + 'Fingerprint', Connection.Fingerprint); IniFile.WriteString('FTP', 'Connection' + sIndex + 'InitCommands', Connection.InitCommands); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'ShowHiddenItems', Connection.ShowHiddenItems); IniFile.WriteBool('FTP', 'Connection' + sIndex + 'KeepAliveTransfer', Connection.KeepAliveTransfer); end; SaveProxyList(IniFile); IniFile.UpdateFile; end; procedure FreeConnectionList; var I, Count: Integer; Connection: TConnection; begin Count := ConnectionList.Count; for I := Count - 1 downto 0 do begin Connection := TConnection(ConnectionList.Objects[I]); Connection.Free; ConnectionList.Delete(I); end; end; procedure ZeroPassword(var APassword: String); begin if (Length(APassword) > 0) then begin FillChar(APassword[1], Length(APassword), 0); SetLength(APassword, 0); end; end; function CryptFunc(Mode: LongInt; ConnectionName: String; var Password: String): LongInt; var APassword: UnicodeString; AConnection: UnicodeString; begin APassword:= CeUtf8ToUtf16(Password); AConnection:= CeUtf8ToUtf16(ConnectionName); if (Mode = FS_CRYPT_LOAD_PASSWORD) or (Mode = FS_CRYPT_LOAD_PASSWORD_NO_UI) then begin SetLength(APassword, MAX_PATH); FillChar(APassword[1], MAX_PATH * SizeOf(WideChar), #0); end; Result:= CryptProc(PluginNumber, CryptoNumber, Mode, PWideChar(AConnection), PWideChar(APassword), MAX_PATH); if (Mode = FS_CRYPT_LOAD_PASSWORD) or (Mode = FS_CRYPT_LOAD_PASSWORD_NO_UI) then begin Password:= UTF16ToUTF8(PWideChar(APassword)); // truncate to #0 end; end; function ShowPasswordDialog(out Password: String): Boolean; var APassword: UnicodeString; begin SetLength(APassword, MAX_PATH); APassword[1] := #0; Result := RequestProc(PluginNumber, RT_Password, nil, nil, PWideChar(APassword), MAX_PATH); if Result then Password := UTF16ToUTF8(PWideChar(APassword)) // truncate to #0 else Password := EmptyStr; end; function FtpLogin(const Connection: TConnection; const FtpSend: TFTPSendEx): Boolean; var sTemp: AnsiString; begin Result := False; if FtpSend.Login then begin sTemp:= Connection.InitCommands; while sTemp <> EmptyStr do FtpSend.ExecuteCommand(Copy2SymbDel(sTemp, ';')); if Length(Connection.Path) > 0 then FtpSend.ChangeWorkingDir(FtpSend.ClientToServer(CeUtf8ToUtf16(Connection.Path))); Result := True; end; end; function FtpConnect(const ConnectionName: AnsiString; out FtpSend: TFTPSendEx): Boolean; var I: Integer; APassword: String; Connection: TConnection; begin Result:= False; I:= ActiveConnectionList.IndexOf(ConnectionName); // If find active connection then use it if I >= 0 then begin FtpSend:= TFTPSendEx(ActiveConnectionList.Objects[I]); if FtpSend.NetworkError then //Server closed the connection, or network error occurred, or whatever else. //Attempt to reconnect and execute login sequence begin LogProc(PluginNumber, msgtype_details, PWideChar('Network error detected, attempting to reconnect...')); I:= ConnectionList.IndexOf(ConnectionName); if I >= 0 then begin Connection := TConnection(ConnectionList.Objects[I]); if not FtpLogin(Connection, FtpSend) then begin RequestProc(PluginNumber, RT_MsgOK, nil, 'Connection lost, unable to reconnect!', nil, MAX_PATH); Exit; end; end; end; Result:= True; end else begin // find in exists connection list I:= ConnectionList.IndexOf(ConnectionName); if I >= 0 then begin Connection := TConnection(ConnectionList.Objects[I]); if Connection.OpenSSH then begin if Connection.OnlySCP then FtpSend := TScpSend.Create(Connection.Encoding) else begin FtpSend := TSftpSend.Create(Connection.Encoding); TSftpSend(FtpSend).CopySCP := Connection.CopySCP; end; FtpSend.PublicKey:= Connection.PublicKey; FtpSend.PrivateKey:= Connection.PrivateKey; TScpSend(FtpSend).Agent:= Connection.AgentSSH; TScpSend(FtpSend).Fingerprint:= Connection.Fingerprint; end else begin FtpSend := TFTPSendEx.Create(Connection.Encoding); FtpSend.ShowHidden := Connection.ShowHiddenItems; FtpSend.KeepAliveTransfer := Connection.KeepAliveTransfer; end; FtpSend.TcpKeepAlive := TcpKeepAlive; FtpSend.TargetHost := Connection.Host; FtpSend.PassiveMode:= Connection.PassiveMode; FtpSend.AutoTLS:= Connection.AutoTLS; FtpSend.FullSSL:= Connection.FullSSL; FtpSend.UseAllocate:= Connection.UseAllocate; if Connection.Port <> EmptyStr then FtpSend.TargetPort := Connection.Port else if Connection.FullSSL then FtpSend.TargetPort := cFtpsPort; if Connection.UserName <> EmptyStr then FtpSend.UserName := Connection.UserName; if Connection.MasterPassword then begin if CryptFunc(FS_CRYPT_LOAD_PASSWORD, Connection.ConnectionName, Connection.Password) <> FS_FILE_OK then ZeroPassword(Connection.Password); end; // if no saved password then ask it if Connection.OpenSSH and (Connection.AgentSSH or ((Connection.PrivateKey <> '') and (Connection.PublicKey <> ''))) then APassword:= EmptyStr else if Length(Connection.Password) > 0 then APassword:= Connection.Password else if Length(Connection.CachedPassword) > 0 then APassword:= Connection.CachedPassword else if not ShowPasswordDialog(APassword) then begin FreeAndNil(FtpSend); Exit; end; FtpSend.Password := FtpSend.ClientToServer(APassword); SetProxy(FtpSend, Connection.Proxy); // try to connect if not FtpLogin(Connection, FtpSend) then begin RequestProc(PluginNumber, RT_MsgOK, nil, 'Can not connect to the server!', nil, MAX_PATH); FreeAndNil(FtpSend); end else begin Connection.CachedPassword:= APassword; LogProc(PluginNumber, MSGTYPE_CONNECT, PWideChar('CONNECT ' + PathDelim + CeUtf8ToUtf16(ConnectionName))); ActiveConnectionList.AddObject(ConnectionName, FtpSend); if Connection.OpenSSH and (ConnectionName <> cQuickConnection) then begin // Save connection server fingerprint if Connection.Fingerprint <> TScpSend(FtpSend).Fingerprint then begin Connection.Fingerprint:= TScpSend(FtpSend).Fingerprint; WriteConnectionList; end; end; Result:= True; end; end; end; end; function QuickConnection(out FtpSend: TFTPSendEx): Boolean; var Index: Integer; Connection: TConnection; begin Index:= ActiveConnectionList.IndexOf(cQuickConnection); Result:= (Index >= 0); if Result then FtpSend:= TFTPSendEx(ActiveConnectionList.Objects[Index]) else begin Connection := TConnection.Create; Connection.ConnectionName:= cQuickConnection; if ShowFtpConfDlg(Connection) then begin Connection.ConnectionName:= cQuickConnection; Index:= ConnectionList.AddObject(Connection.ConnectionName, Connection); Result:= FtpConnect(Connection.ConnectionName, FtpSend); ConnectionList.Delete(Index); end; Connection.Free; end; end; function AddConnection: Integer; var Connection: TConnection; begin Result := -1; Connection := TConnection.Create; Connection.PassiveMode := True; if ShowFtpConfDlg(Connection) then begin with Connection do begin if ConnectionList.IndexOf(ConnectionName) >= 0 then begin ConnectionName += '+' + IntToStr(Random(MaxInt)); end; if MasterPassword then begin if Length(Password) = 0 then MasterPassword:= False else if CryptFunc(FS_CRYPT_SAVE_PASSWORD, ConnectionName, Password) = FS_FILE_OK then Password:= EmptyStr else MasterPassword:= False; end; Result:= ConnectionList.AddObject(ConnectionName, Connection); end; end; if Result < 0 then FreeAndNil(Connection) else WriteConnectionList; end; function EditConnection(ConnectionName: AnsiString): Boolean; var I: Integer; ATemp: TConnection; Connection: TConnection; begin Result:= False; I := ConnectionList.IndexOf(ConnectionName); if I >= 0 then begin ATemp:= TConnection.Create; Connection:= TConnection(ConnectionList.Objects[I]); ATemp.Assign(Connection); if ShowFtpConfDlg(ATemp) then begin with ATemp do begin if ConnectionName <> Connection.ConnectionName then begin if Connection.MasterPassword then begin if CryptFunc(FS_CRYPT_MOVE_PASSWORD, Connection.ConnectionName, ConnectionName) <> FS_FILE_OK then begin gStartupInfo.MessageBox('Cannot save connection!', 'FTP', MB_OK or MB_ICONERROR); Exit(False); end; end; ConnectionList[I]:= ConnectionName end; if PasswordChanged then begin // Master password enabled if MasterPassword then begin if Length(Password) = 0 then MasterPassword:= False else if CryptFunc(FS_CRYPT_SAVE_PASSWORD, ConnectionName, Password) = FS_FILE_OK then Password:= EmptyStr else MasterPassword:= False; end; // Master password disabled if (MasterPassword = False) and (Connection.MasterPassword <> MasterPassword) then begin DeletePassword(ConnectionName); end; end end; Connection.Assign(ATemp); WriteConnectionList; Result:= True; end; FreeAndNil(ATemp); end; end; function DeleteConnection(ConnectionName: AnsiString): Boolean; var I: Integer; Connection: TConnection; begin Result:= False; I:= ConnectionList.IndexOf(ConnectionName); if I >= 0 then begin Connection:= TConnection(ConnectionList.Objects[I]); Connection.Free; ConnectionList.Delete(I); WriteConnectionList; Result:= True; end; end; function ExtractConnectionName(const sPath: AnsiString): AnsiString; var Index: Integer; begin Result:= sPath; if sPath[1] = PathDelim then Result := Copy(sPath, 2, Length(sPath)); Index := Pos(PathDelim, Result); if Index = 0 then Index := MaxInt; Result := Copy(Result, 1, Index - 1); end; function ExtractRemoteFileName(const FileName: AnsiString): AnsiString; var I: Integer; begin Result := FileName; System.Delete(Result, 1, 1); I := Pos(PathDelim, Result); if I = 0 then Result := '/' else begin System.Delete(Result, 1, I - 1); Result := StringReplace(Result, '\', '/', [rfReplaceAll]); end; end; function GetConnectionByPath(const sPath: UnicodeString; out FtpSend: TFTPSendEx; out RemotePath: AnsiString): Boolean; var sConnName: AnsiString; begin Result := False; if (ExtractFileDir(sPath) = PathDelim) then Exit; sConnName := ExtractConnectionName(UTF16ToUTF8(sPath)); if Assigned(ThreadCon) then begin Result:= True; FtpSend:= ThreadCon; end else begin Result:= FtpConnect(sConnName, FtpSend); end; if Result then begin RemotePath:= FtpSend.ClientToServer(sPath); RemotePath:= ExtractRemoteFileName(RemotePath); end; end; function LocalFindNext(Hdl: THandle; var FindData: TWin32FindDataW): Boolean; var ListRec: PListRec absolute Hdl; I, RootCount: Integer; Connection: TConnection; begin Result := False; I := ListRec^.Index; RootCount := High(RootList) + 1; FillChar(FindData, SizeOf(FindData), 0); if I < RootCount then begin StrPCopy(FindData.cFileName, CeUtf8ToUtf16(RootList[I])); FindData.dwFileAttributes := 0; Inc(ListRec^.Index); Result := True; end else if I - RootCount < ConnectionList.Count then begin Connection := TConnection(ConnectionList.Objects[I - RootCount]); StrPCopy(FindData.cFileName, CeUtf8ToUtf16(Connection.ConnectionName)); FindData.dwFileAttributes := FILE_ATTRIBUTE_VOLUME; Inc(ListRec^.Index); Result := True; end; if Result then begin FindData.nFileSizeLow := $FFFFFFFE; FindData.nFileSizeHigh := $FFFFFFFF; FindData.ftLastWriteTime.dwLowDateTime := $FFFFFFFE; FindData.ftLastWriteTime.dwHighDateTime := $FFFFFFFF; end; end; function FsInitW(PluginNr: Integer; pProgressProc: TProgressProcW; pLogProc: TLogProcW; pRequestProc: TRequestProcW): Integer; dcpcall; export; begin ProgressProc := pProgressProc; LogProc := pLogProc; RequestProc := pRequestProc; PluginNumber := PluginNr; Result := 0; end; function FsFindFirstW(Path: PWideChar; var FindData: TWin32FindDataW): THandle; dcpcall; export; var ListRec: PListRec; sPath: AnsiString; FtpSend: TFTPSendEx; Directory: UnicodeString; begin New(ListRec); ListRec.Index := 0; ListRec.Path := Path; ListRec.FtpSend := nil; ListRec.FtpList := nil; Result := wfxInvalidHandle; if Path = PathDelim then begin Result := THandle(ListRec); LocalFindNext(Result, FindData); end else begin ListLock.Acquire; try Directory:= Path; if Directory[Length(Directory)] <> PathDelim then Directory:= Directory + PathDelim; if GetConnectionByPath(Directory, FtpSend, sPath) then begin ListRec.FtpSend := FtpSend; ListRec.FtpList := FtpSend.FsFindFirstW(sPath, FindData); if Assigned(ListRec.FtpList) then Result:= THandle(ListRec); end; finally ListLock.Release; if Result = wfxInvalidHandle then Dispose(ListRec); end; end; end; function FsFindNextW(Hdl: THandle; var FindData: TWin32FindDataW): BOOL; dcpcall; export; var ListRec: PListRec absolute Hdl; begin if ListRec.Path = PathDelim then Result := LocalFindNext(Hdl, FindData) else Result := ListRec^.FtpSend.FsFindNextW(ListRec.FtpList, FindData); end; function FsFindClose(Hdl: THandle): Integer; dcpcall; export; var ListRec: PListRec absolute Hdl; begin Result:= 0; if Assigned(ListRec) then begin if Assigned(ListRec^.FtpSend) then begin Result:= ListRec^.FtpSend.FsFindClose(ListRec.FtpList); end; Dispose(ListRec); end; end; function FsExecuteFileW(MainWin: THandle; RemoteName, Verb: PWideChar): Integer; dcpcall; export; var FtpSend: TFTPSendEx; RemoteDir: AnsiString; asFileName: AnsiString; wsFileName: UnicodeString; begin Result:= FS_EXEC_YOURSELF; if (RemoteName = '') then Exit; if Verb = 'open' then begin if (ExtractFileDir(RemoteName) = PathDelim) then // root path begin asFileName:= UTF16ToUTF8(RemoteName + 1); if RemoteName[1] <> '<' then // connection begin if not FtpConnect(asFileName, FtpSend) then Result := FS_EXEC_OK else begin Result := FS_EXEC_SYMLINK; end; end else // special item begin if asFileName = cAddConnection then begin AddConnection; Result:= FS_EXEC_OK; end else if asFileName = cQuickConnection then begin if not QuickConnection(FtpSend) then Result := FS_EXEC_OK else begin Result := FS_EXEC_SYMLINK; end; end; end; if (Result = FS_EXEC_SYMLINK) then begin wsFileName := FtpSend.ServerToClient(FtpSend.GetCurrentDir); wsFileName := SetDirSeparators(RemoteName + wsFileName); StrPLCopy(RemoteName, wsFileName, MAX_PATH); end; end; // root path end // Verb = open else if Pos('chmod', UnicodeString(Verb)) = 1 then begin if GetConnectionByPath(RemoteName, FtpSend, asFileName) then begin if FtpSend.ChangeMode(asFileName, AnsiString(Copy(Verb, 7, MaxInt))) then Result:= FS_EXEC_OK else Result := FS_EXEC_ERROR; end; end else if Pos('quote', UnicodeString(Verb)) = 1 then begin if GetConnectionByPath(RemoteName, FtpSend, RemoteDir) then begin asFileName:= FtpSend.ClientToServer(Verb); if FtpSend.ExecuteCommand(Copy(asFileName, 7, MaxInt), RemoteDir) then Result := FS_EXEC_OK else Result := FS_EXEC_ERROR; end; end else if Verb = 'properties' then begin if (ExtractFileDir(RemoteName) = PathDelim) and not (RemoteName[1] in [#0, '<']) then // connection begin EditConnection(UTF16ToUTF8(RemoteName + 1)); end else if (ExtractFileDir(RemoteName) <> PathDelim) then begin if GetConnectionByPath(RemoteName, FtpSend, asFileName) then begin if FtpSend.FileProperties(asFileName) then begin wsFileName:= FtpSend.ServerToClient(FtpSend.FullResult.Text); ShowPropertiesDlg(PAnsiChar(UTF8Encode(wsFileName))); end end; end; Result:= FS_EXEC_OK; end; end; function FsRenMovFileW(OldName, NewName: PWideChar; Move, OverWrite: BOOL; RemoteInfo: pRemoteInfo): Integer; dcpcall; export; var O, N: Integer; FtpSend: TFTPSendEx; sOldName: AnsiString; sNewName: AnsiString; Connection: TConnection; begin Result := FS_FILE_NOTSUPPORTED; if not Move then begin if (ExtractFileDir(OldName) = PathDelim) and (WideChar(OldName[1]) <> '<') and (ExtractFileDir(NewName) = PathDelim) and (WideChar(NewName[1]) <> '<') then begin O:= ConnectionList.IndexOf(OldName + 1); if O < 0 then Result:= FS_FILE_NOTFOUND else begin sNewName:= RepairConnectionName(UTF16ToUTF8(UnicodeString(NewName + 1))); N:= ConnectionList.IndexOf(sNewName); if (N >= 0) then begin if not OverWrite then Exit(FS_FILE_EXISTS); Connection:= TConnection(ConnectionList.Objects[N]); end else begin Connection:= TConnection.Create; ConnectionList.AddObject(sNewName, Connection); end; Connection.Assign(TConnection(ConnectionList.Objects[O])); Connection.ConnectionName:= sNewName; WriteConnectionList; Result:= FS_FILE_OK; end; end else if GetConnectionByPath(OldName, FtpSend, sOldName) then begin if FtpSend is TScpSend then begin sNewName := FtpSend.ClientToServer(NewName); sNewName := ExtractRemoteFileName(sNewName); ProgressProc(PluginNumber, OldName, NewName, 0); if (not OverWrite) and (FtpSend.FileExists(sNewName)) then begin Exit(FS_FILE_EXISTS); end; if FtpSend.CopyFile(sOldName, sNewName) then begin ProgressProc(PluginNumber, OldName, NewName, 100); Result := FS_FILE_OK; end; end; end; Exit; end; if (ExtractFileDir(OldName) = PathDelim) and (WideChar(OldName[1]) <> '<') then begin O:= ConnectionList.IndexOf(OldName + 1); if O < 0 then Result:= FS_FILE_NOTFOUND else begin ConnectionList[O]:= RepairConnectionName(UTF16ToUTF8(UnicodeString(NewName + 1))); TConnection(ConnectionList.Objects[O]).ConnectionName:= ConnectionList[O]; WriteConnectionList; Result:= FS_FILE_OK; end; end else if GetConnectionByPath(OldName, FtpSend, sOldName) then begin sNewName := FtpSend.ClientToServer(NewName); sNewName := ExtractRemoteFileName(sNewName); ProgressProc(PluginNumber, OldName, NewName, 0); if FtpSend.RenameFile(sOldName, sNewName) then begin ProgressProc(PluginNumber, OldName, NewName, 100); Result := FS_FILE_OK; end; end; end; function FsGetFileW(RemoteName, LocalName: PWideChar; CopyFlags: Integer; RemoteInfo: pRemoteInfo): Integer; dcpcall; export; var FileSize: Int64; FtpSend: TFTPSendEx; sFileName: AnsiString; FileName: AnsiString; begin Result := FS_FILE_READERROR; if GetConnectionByPath(RemoteName, FtpSend, sFileName) then try FileName:= UTF16ToUTF8(UnicodeString(LocalName)); if FileExistsUTF8(FileName) and (CopyFlags and FS_COPYFLAGS_FORCE = 0) then begin if not FtpSend.CanResume then Exit(FS_FILE_EXISTS); Exit(FS_FILE_EXISTSRESUMEALLOWED); end; FtpSend.DataStream.Clear; FtpSend.DirectFileName := FileName; Int64Rec(FileSize).Lo := RemoteInfo^.SizeLow; Int64Rec(FileSize).Hi := RemoteInfo^.SizeHigh; ProgressProc(PluginNumber, RemoteName, LocalName, 0); if FtpSend.RetrieveFile(sFileName, FileSize, (CopyFlags and FS_COPYFLAGS_RESUME) <> 0) then begin ProgressProc(PluginNumber, RemoteName, LocalName, 100); Result := FS_FILE_OK; end; except on EUserAbort do Result := FS_FILE_USERABORT; on EFOpenError do Result := FS_FILE_READERROR; else Result := FS_FILE_WRITEERROR; end; end; function FsPutFileW(LocalName, RemoteName: PWideChar; CopyFlags: Integer): Integer; dcpcall; export; var FtpSend: TFTPSendEx; sFileName: AnsiString; FileName: AnsiString; begin Result := FS_FILE_WRITEERROR; if GetConnectionByPath(RemoteName, FtpSend, sFileName) then try FileName:= UTF16ToUTF8(UnicodeString(LocalName)); if (CopyFlags and FS_COPYFLAGS_FORCE = 0) and (FtpSend.FileExists(sFileName)) then begin if not FtpSend.CanResume then Exit(FS_FILE_EXISTS); Exit(FS_FILE_EXISTSRESUMEALLOWED); end; FtpSend.DataStream.Clear; FtpSend.DirectFileName := FileName; ProgressProc(PluginNumber, LocalName, RemoteName, 0); if FtpSend.StoreFile(sFileName, (CopyFlags and FS_COPYFLAGS_RESUME) <> 0) then begin ProgressProc(PluginNumber, LocalName, RemoteName, 100); Result := FS_FILE_OK; end; except on EReadError do Result := FS_FILE_READERROR; on EUserAbort do Result := FS_FILE_USERABORT; else Result := FS_FILE_WRITEERROR; end; end; function FsDeleteFileW(RemoteName: PWideChar): BOOL; dcpcall; export; var FtpSend: TFTPSendEx; sFileName: AnsiString; begin Result := False; // if root path then delete connection if (ExtractFileDir(RemoteName) = PathDelim) and (RemoteName[1] <> '<') then Result:= DeleteConnection(ExtractConnectionName(UTF16ToUTF8(RemoteName))) else if GetConnectionByPath(RemoteName, FtpSend, sFileName) then Result := FtpSend.DeleteFile(sFileName); end; function FsMkDirW(RemoteDir: PWideChar): BOOL; dcpcall; export; var sPath: AnsiString; FtpSend: TFTPSendEx; begin Result := False; if GetConnectionByPath(RemoteDir, FtpSend, sPath) then Result := FtpSend.CreateDir(sPath); end; function FsRemoveDirW(RemoteName: PWideChar): BOOL; dcpcall; export; var sPath: AnsiString; FtpSend: TFTPSendEx; begin Result := False; if GetConnectionByPath(RemoteName, FtpSend, sPath) then Result := FtpSend.DeleteDir(sPath); end; function FsSetTimeW(RemoteName: PWideChar; CreationTime, LastAccessTime, LastWriteTime: PFileTime): BOOL; dcpcall; export; var sPath: AnsiString; FtpSend: TFTPSendEx; begin if (LastAccessTime = nil) and (LastWriteTime = nil) then Result := False else if GetConnectionByPath(RemoteName, FtpSend, sPath) then Result := FtpSend.FsSetTime(sPath, LastAccessTime, LastWriteTime) else begin Result := False; end; end; function FsDisconnectW(DisconnectRoot: PWideChar): BOOL; dcpcall; export; var Index: Integer; asTemp: AnsiString; FtpSend: TFTPSendEx; wsTemp: UnicodeString; begin wsTemp := ExcludeLeadingPathDelimiter(DisconnectRoot); asTemp := ExtractConnectionName(UTF16ToUTF8(wsTemp)); Index := ActiveConnectionList.IndexOf(asTemp); Result := (Index >= 0); if Result then begin FtpSend:= TFTPSendEx(ActiveConnectionList.Objects[Index]); if not FtpSend.NetworkError then begin FtpSend.Logout; end; ActiveConnectionList.Delete(Index); Index:= ConnectionList.IndexOf(asTemp); if Index >= 0 then begin ZeroPassword(TConnection(ConnectionList.Objects[Index]).CachedPassword); end; LogProc(PluginNumber, MSGTYPE_DISCONNECT, PWideChar('DISCONNECT ' + DisconnectRoot)); FreeAndNil(FtpSend); end; end; procedure FsSetCryptCallbackW(pCryptProc: TCryptProcW; CryptoNr, Flags: Integer); dcpcall; export; begin CryptProc:= pCryptProc; CryptoNumber:= CryptoNr; end; procedure FsGetDefRootName(DefRootName: PAnsiChar; MaxLen: Integer); dcpcall; export; begin StrPLCopy(DefRootName, 'FTP', MaxLen); end; procedure FsSetDefaultParams(dps: pFsDefaultParamStruct); dcpcall; export; begin ConnectionList := TStringList.Create; ActiveConnectionList := TStringList.Create; DefaultIniName:= ExtractFileName(dps.DefaultIniName); end; procedure FsStatusInfoW(RemoteDir: PWideChar; InfoStartEnd, InfoOperation: Integer); dcpcall; export; var FtpSend: TFtpSendEx; RemotePath: AnsiString; begin if (InfoOperation in [FS_STATUS_OP_GET_MULTI_THREAD, FS_STATUS_OP_PUT_MULTI_THREAD]) then begin if InfoStartEnd = FS_STATUS_START then begin if GetConnectionByPath(RemoteDir, FtpSend, RemotePath) then begin LogProc(PluginNumber, msgtype_details, 'Create background connection'); ThreadCon:= FtpSend.Clone; if not ThreadCon.Login then begin FreeAndNil(ThreadCon); LogProc(PluginNumber, msgtype_importanterror, 'Cannot create background connection, use foreground'); end; end; end else if Assigned(ThreadCon) then begin LogProc(PluginNumber, msgtype_details, 'Destroy background connection'); ThreadCon.Logout; FreeAndNil(ThreadCon); end; end; end; function FsGetBackgroundFlags: Integer; dcpcall; export; begin Result:= BG_DOWNLOAD or BG_UPLOAD or BG_ASK_USER; end; { procedure FsNetworkGetSupportedProtocols(Protocols: PAnsiChar; MaxLen: LongInt); dcpcall; export; begin StrPLCopy(Protocols, ftpProtocol, MaxLen); end; function FsNetworkGetConnection(Index: LongInt; Connection: PAnsiChar; MaxLen: LongInt): LongBool; dcpcall; export; begin Result:= False; if Index >= ConnectionList.Count then Exit; StrPLCopy(Connection, TConnection(ConnectionList.Objects[Index]).ConnectionName, MaxLen); Result:= True; end; function FsNetworkManageConnection(MainWin: HWND; Connection: PAnsiChar; Action: LongInt; MaxLen: LongInt): LongBool; dcpcall; export; var I: Integer; begin Result:= False; case Action of FS_NM_ACTION_ADD: begin I:= AddConnection; if I >= 0 then begin StrPLCopy(Connection, ConnectionList[I], MaxLen); Result:= True; end; end; FS_NM_ACTION_EDIT: begin I:= ConnectionList.IndexOf(Connection); if I >= 0 then begin if EditConnection(Connection) then begin StrPLCopy(Connection, ConnectionList[I], MaxLen); Result:= True; end; end; end; FS_NM_ACTION_DELETE: Result:= DeleteConnection(Connection); end; end; function FsNetworkOpenConnection(Connection: PAnsiChar; RootDir, RemotePath: PAnsiChar; MaxLen: LongInt): LongBool; dcpcall; export; var I: Integer; FtpSend: TFTPSendEx; Con: TConnection; begin Result:= False; if Connection = #0 then begin if QuickConnection then begin I:= ActiveConnectionList.IndexOf(cQuickConnection); if I >= 0 then begin Con:= TConnection(ActiveConnectionList.Objects[I]); StrPLCopy(Connection, ftpProtocol + Con.Host, MaxLen); StrPLCopy(RootDir, PathDelim + Con.ConnectionName, MaxLen); StrPLCopy(RemotePath, Con.Path, MaxLen); Result:= True; end; end; end else if FtpConnect(Connection, FtpSend) then begin I:= ConnectionList.IndexOf(Connection); if I >= 0 then begin Con:= TConnection(ConnectionList.Objects[I]); StrPLCopy(Connection, ftpProtocol + Con.Host, MaxLen); StrPLCopy(RootDir, PathDelim + Con.ConnectionName, MaxLen); StrPLCopy(RemotePath, Con.Path, MaxLen); Result:= True; end; end; end; } procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); begin gStartupInfo:= StartupInfo^; DefaultIniName:= gStartupInfo.PluginConfDir + DefaultIniName; IniFile := TIniFileEx.Create(DefaultIniName, fmOpenReadWrite); // Use TCP keep alive for all connections: Useful for certain // firewalls/router if the connection breaks very often. TcpKeepAlive := IniFile.ReadBool('General', 'TcpKeepAlive', TcpKeepAlive); ReadConnectionList; end; function ReadPassword(ConnectionName: AnsiString; out Password: AnsiString): Boolean; begin Password:= EmptyStr; case CryptFunc(FS_CRYPT_LOAD_PASSWORD, ConnectionName, Password) of FS_FILE_OK, FS_FILE_READERROR: Result:= True else Result:= False; end; end; function DeletePassword(ConnectionName: AnsiString): Boolean; var Password: String = ''; begin Result:= CryptFunc(FS_CRYPT_DELETE_PASSWORD, ConnectionName, Password) = FS_FILE_OK; end; { TConnection } procedure TConnection.Assign(Connection: TConnection); begin Path:= Connection.Path; Host:= Connection.Host; Port:= Connection.Port; Proxy:= Connection.Proxy; AutoTLS:= Connection.AutoTLS; FullSSL:= Connection.FullSSL; OpenSSH:= Connection.OpenSSH; CopySCP:= Connection.CopySCP; OnlySCP:= Connection.OnlySCP; AgentSSH:= Connection.AgentSSH; UserName:= Connection.UserName; Password:= Connection.Password; Encoding:= Connection.Encoding; PublicKey:= Connection.PublicKey; PrivateKey:= Connection.PrivateKey; Fingerprint:= Connection.Fingerprint; PassiveMode:= Connection.PassiveMode; UseAllocate:= Connection.UseAllocate; InitCommands:= Connection.InitCommands; MasterPassword:= Connection.MasterPassword; ConnectionName:= Connection.ConnectionName; PasswordChanged:= Connection.PasswordChanged; ShowHiddenItems:= Connection.ShowHiddenItems; KeepAliveTransfer:= Connection.KeepAliveTransfer; end; initialization ListLock := syncobjs.TCriticalSection.Create; finalization FreeAndNil(ListLock); end. ����������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftppropdlg.lfm�������������������������������������������������0000644�0001750�0000144�00000004772�14743153644�021346� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFileProperties: TfrmFileProperties Left = 290 Height = 400 Top = 175 Width = 640 Caption = 'Properties' ClientHeight = 400 ClientWidth = 640 Constraints.MinHeight = 223 Constraints.MinWidth = 334 DesignTimePPI = 107 OnShow = DialogBoxShow Position = poOwnerFormCenter LCLVersion = '2.2.6.0' inline seProperties: TSynEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnClose Left = 11 Height = 334 Top = 11 Width = 618 BorderSpacing.Left = 11 BorderSpacing.Top = 11 BorderSpacing.Right = 11 BorderSpacing.Bottom = 11 Anchors = [akTop, akLeft, akRight, akBottom] Color = clWindow Font.Color = clWindowText Font.Pitch = fpFixed Font.Quality = fqDefault ParentColor = False ParentFont = False TabOrder = 1 Gutter.Visible = False Gutter.Width = 0 Gutter.MouseActions = <> RightGutter.Width = 0 RightGutter.MouseActions = <> Keystrokes = <> MouseActions = <> MouseTextActions = <> MouseSelActions = <> Options = [eoAutoIndent, eoBracketHighlight, eoHideRightMargin, eoNoCaret, eoScrollPastEol, eoSmartTabs, eoTabsToSpaces, eoTrimTrailingSpaces] VisibleSpecialChars = [vscSpace, vscTabAtLast] ReadOnly = True ScrollBars = ssNone SelectedColor.BackPriority = 50 SelectedColor.ForePriority = 50 SelectedColor.FramePriority = 50 SelectedColor.BoldPriority = 50 SelectedColor.ItalicPriority = 50 SelectedColor.UnderlinePriority = 50 SelectedColor.StrikeOutPriority = 50 BracketHighlightStyle = sbhsBoth BracketMatchColor.Background = clNone BracketMatchColor.Foreground = clNone BracketMatchColor.Style = [fsBold] FoldedCodeColor.Background = clNone FoldedCodeColor.Foreground = clGray FoldedCodeColor.FrameColor = clGray MouseLinkColor.Background = clNone MouseLinkColor.Foreground = clBlue LineHighlightColor.Background = clNone LineHighlightColor.Foreground = clNone inline SynLeftGutterPartList1: TSynGutterPartList end end object btnClose: TBitBtn AnchorSideLeft.Side = asrCenter AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 265 Height = 33 Top = 356 Width = 111 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 11 Cancel = True DefaultCaption = True ModalResult = 2 Kind = bkClose TabOrder = 0 end end ������doublecmd-1.1.22/plugins/wfx/ftp/src/ftppropdlg.pas�������������������������������������������������0000644�0001750�0000144�00000002757�14743153644�021354� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit FtpPropDlg; {$mode delphi} {$include calling.inc} interface uses SysUtils, Extension, FtpFunc; function ShowPropertiesDlg(const AText: String): Boolean; implementation {$R ftppropdlg.lfm} function DlgProc(pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall; var Data: PtrInt; Text: PString absolute Data; begin Result:= 0; with gStartupInfo do begin case Msg of DN_INITDIALOG: begin Data:= SendDlgMsg(pDlg, nil, DM_GETDLGDATA, 0, 0); Data:= PtrInt(PAnsiChar(Text^)); SendDlgMsg(pDlg, 'seProperties', DM_SETTEXT, Data, 0); end; end; end; // with end; function ShowPropertiesDlg(const AText: String): Boolean; var ResHandle: TFPResourceHandle = 0; ResGlobal: TFPResourceHGLOBAL = 0; ResData: Pointer = nil; ResSize: LongWord; begin Result := False; try ResHandle := FindResource(HINSTANCE, PChar('TfrmFileProperties'), MAKEINTRESOURCE(10) {RT_RCDATA}); if ResHandle <> 0 then begin ResGlobal := LoadResource(HINSTANCE, ResHandle); if ResGlobal <> 0 then begin ResData := LockResource(ResGlobal); ResSize := SizeofResource(HINSTANCE, ResHandle); with gStartupInfo do begin Result := (DialogBoxParam(ResData, ResSize, @DlgProc, DB_LRS, @AText, nil) > 0); end; end; end; finally if ResGlobal <> 0 then begin UnlockResource(ResGlobal); FreeResource(ResGlobal); end; end; end; end. �����������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftpproxy.pas���������������������������������������������������0000644�0001750�0000144�00000013727�14743153644�021065� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WFX plugin for working with File Transfer Protocol Copyright (C) 2018 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit FtpProxy; {$mode delphi} interface uses Classes, SysUtils, IniFiles, ftpsend; type TProxyType = ( PROXY_NONE = 0, PROXY_SOCKS4 = 1, PROXY_SOCKS5 = 2, PROXY_HTTP_CONNECT = 3 ); { TFtpProxy } TFtpProxy = class public ID: String; Host: String; Port: String; User: String; Password: String; ProxyType: TProxyType; function Clone: TFtpProxy; end; var ProxyList: TStringList; procedure LoadProxyList(IniFile: TIniFile); procedure SaveProxyList(IniFile: TIniFile); procedure SetProxy(FtpSend: TFTPSend; ProxyID: String); implementation uses FtpUtils, blcksock; procedure LoadProxyList(IniFile: TIniFile); var Proxy: TFtpProxy; I, Count: Integer; sIndex: AnsiString; begin ProxyList.Clear; Count := IniFile.ReadInteger('FTP', 'ProxyCount', 0); for I := 1 to Count do begin sIndex := IntToStr(I); Proxy := TFtpProxy.Create; Proxy.ID := IniFile.ReadString('FTP', 'Proxy' + sIndex + 'ID', EmptyStr); Proxy.Host := IniFile.ReadString('FTP', 'Proxy' + sIndex + 'Host', EmptyStr); Proxy.Port := IniFile.ReadString('FTP', 'Proxy' + sIndex + 'Port', EmptyStr); Proxy.User := IniFile.ReadString('FTP', 'Proxy' + sIndex + 'User', EmptyStr); Proxy.Password := DecodeBase64(IniFile.ReadString('FTP', 'Proxy' + sIndex + 'Password', EmptyStr)); Proxy.ProxyType := TProxyType(IniFile.ReadInteger('FTP', 'Proxy' + sIndex + 'Type', Integer(PROXY_NONE))); // Add proxy to proxy list ProxyList.AddObject(Proxy.ID, Proxy); end; end; procedure SaveProxyList(IniFile: TIniFile); var Proxy: TFtpProxy; I, Count: Integer; sIndex: AnsiString; begin Count:= ProxyList.Count; IniFile.WriteInteger('FTP', 'ProxyCount', Count); for I := 0 to Count - 1 do begin sIndex := IntToStr(I + 1); Proxy := TFtpProxy(ProxyList.Objects[I]); IniFile.WriteString('FTP', 'Proxy' + sIndex + 'ID', Proxy.ID); IniFile.WriteString('FTP', 'Proxy' + sIndex + 'Host', Proxy.Host); IniFile.WriteString('FTP', 'Proxy' + sIndex + 'Port', Proxy.Port); IniFile.WriteString('FTP', 'Proxy' + sIndex + 'User', Proxy.User); IniFile.WriteString('FTP', 'Proxy' + sIndex + 'Password', EncodeBase64(Proxy.Password)); IniFile.WriteInteger('FTP', 'Proxy' + sIndex + 'Type', Integer(Proxy.ProxyType)); end; end; procedure SetProxy(FtpSend: TFTPSend; ProxyID: String); var Index: Integer; Proxy: TFtpProxy; begin Index:= ProxyList.IndexOf(ProxyID); if (Index < 0) then begin FtpSend.Sock.HTTPTunnelIP:= EmptyStr; FtpSend.Sock.HTTPTunnelUser:= EmptyStr; FtpSend.Sock.HTTPTunnelPass:= EmptyStr; FtpSend.DSock.HTTPTunnelIP:= EmptyStr; FtpSend.DSock.HTTPTunnelUser:= EmptyStr; FtpSend.DSock.HTTPTunnelPass:= EmptyStr; FtpSend.Sock.SocksIP:= EmptyStr; FtpSend.Sock.SocksUsername:= EmptyStr; FtpSend.Sock.SocksPassword:= EmptyStr; FtpSend.DSock.SocksIP:= EmptyStr; FtpSend.DSock.SocksUsername:= EmptyStr; FtpSend.DSock.SocksPassword:= EmptyStr; end else begin Proxy:= TFtpProxy(ProxyList.Objects[Index]); case Proxy.ProxyType of PROXY_HTTP_CONNECT: begin FtpSend.Sock.HTTPTunnelIP:= Proxy.Host; FtpSend.Sock.HTTPTunnelUser:= Proxy.User; FtpSend.Sock.HTTPTunnelPass:= Proxy.Password; FtpSend.DSock.HTTPTunnelIP:= Proxy.Host; FtpSend.DSock.HTTPTunnelUser:= Proxy.User; FtpSend.DSock.HTTPTunnelPass:= Proxy.Password; if Length(Proxy.Port) > 0 then begin FtpSend.Sock.HTTPTunnelPort:= Proxy.Port; FtpSend.DSock.HTTPTunnelPort:= Proxy.Port; end; end; PROXY_SOCKS4, PROXY_SOCKS5: begin if Proxy.ProxyType = PROXY_SOCKS4 then begin FtpSend.Sock.SocksType:= ST_Socks4; FtpSend.DSock.SocksType:= ST_Socks4; end else begin FtpSend.Sock.SocksType:= ST_Socks5; FtpSend.DSock.SocksType:= ST_Socks5; end; FtpSend.Sock.SocksIP:= Proxy.Host; FtpSend.Sock.SocksResolver:= False; FtpSend.Sock.SocksUsername:= Proxy.User; FtpSend.Sock.SocksPassword:= Proxy.Password; FtpSend.DSock.SocksIP:= Proxy.Host; FtpSend.DSock.SocksResolver:= False; FtpSend.DSock.SocksUsername:= Proxy.User; FtpSend.DSock.SocksPassword:= Proxy.Password; if Length(Proxy.Port) > 0 then begin FtpSend.Sock.SocksPort:= Proxy.Port; FtpSend.DSock.SocksPort:= Proxy.Port; end; end; end; end; end; { TFtpProxy } function TFtpProxy.Clone: TFtpProxy; begin Result:= TFtpProxy.Create; Result.ID:= ID; Result.Host:= Host; Result.Port:= Port; Result.User:= User; Result.Password:= Password; Result.ProxyType:= ProxyType; end; initialization ProxyList:= TStringList.Create; ProxyList.OwnsObjects:= True; finalization ProxyList.Free; end. �����������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/ftputils.pas���������������������������������������������������0000644�0001750�0000144�00000015615�14743153644�021042� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WFX plugin for working with File Transfer Protocol Copyright (C) 2009-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit FtpUtils; {$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF} interface uses Classes, SysUtils, WfxPlugin; const cFtpsPort = '990'; function IsIpPrivate(Value: String): Boolean; function EncodeBase64(Data: AnsiString): AnsiString; function DecodeBase64(Data: AnsiString): AnsiString; function RepairConnectionName(Connection: AnsiString): AnsiString; function ExtractConnectionHost(Connection: AnsiString): AnsiString; function ExtractConnectionPort(Connection: AnsiString): AnsiString; function ExtractConnectionProt(Connection: AnsiString): AnsiString; function FormatMachineTime(const Time: TFileTime): String; function DecodeMachineTime(const Time: String): TDateTime; implementation uses Base64, DateUtils, synautil, synaip {$IFDEF MSWINDOWS} , Windows {$ELSE} , UnixUtil {$ENDIF} ; function IsIPv6(Value: String): Boolean; var Index: Integer; begin Index:= Pos('[', Value); if Index = 1 then begin Index:= Pos(']', Value, Index + 1); if Index > 0 then begin Value:= Copy(Value, 2, Index - 2); end; end; Result:= IsIP6(Value); end; function StrToIp(Value: String): LongWord; var S: String; I, X: LongWord; begin Result := 0; for X := 0 to 3 do begin S := Fetch(Value, '.'); I := StrToIntDef(S, 0); Result := (256 * Result) + I; end; end; function IsIpPrivate(Value: String): Boolean; var Index: Integer; Binary: LongWord; const PrivAddr: array [0..4, 0..1] of LongWord = ( // 10.0.0.0 - 10.255.255.255 (167772160, 184549375), // Single Class A network // 172.16.0.0 - 172.31.255.255 (2886729728, 2887778303), // Contiguous range of 16 Class B blocks // 192.168.0.0 - 192.168.255.255 (3232235520, 3232301055), // Contiguous range of 256 Class C blocks // 169.254.0.0 - 169.254.255.255 (2851995648, 2852061183), // Link-local address // 127.0.0.0 - 127.255.255.255 (2130706432, 2147483647) // Loopback (localhost) ); begin Binary:= StrToIp(Value); for Index:= 0 to 4 do begin if (Binary >= PrivAddr[Index][0]) and (Binary <= PrivAddr[Index][1]) then Exit(True) end; Result:= False; end; function EncodeBase64(Data: AnsiString): AnsiString; var StringStream1, StringStream2: TStringStream; begin Result:= EmptyStr; if Data = EmptyStr then Exit; StringStream1:= TStringStream.Create(Data); try StringStream1.Position:= 0; StringStream2:= TStringStream.Create(EmptyStr); try with TBase64EncodingStream.Create(StringStream2) do try CopyFrom(StringStream1, StringStream1.Size); finally Free; end; Result:= StringStream2.DataString; finally StringStream2.Free; end; finally StringStream1.Free; end; end; function DecodeBase64(Data: AnsiString): AnsiString; var StringStream1, StringStream2: TStringStream; Base64DecodingStream: TBase64DecodingStream; begin Result:= EmptyStr; if Data = EmptyStr then Exit; StringStream1:= TStringStream.Create(Data); try StringStream1.Position:= 0; StringStream2:= TStringStream.Create(EmptyStr); try Base64DecodingStream:= TBase64DecodingStream.Create(StringStream1); with StringStream2 do try CopyFrom(Base64DecodingStream, Base64DecodingStream.Size); finally Base64DecodingStream.Free; end; Result:= StringStream2.DataString; finally StringStream2.Free; end; finally StringStream1.Free; end; end; function RepairConnectionName(Connection: AnsiString): AnsiString; var Index: Integer; DenySym: set of AnsiChar; begin Result:= Connection; DenySym:= AllowDirectorySeparators + AllowDriveSeparators + ['<']; for Index:= 1 to Length(Result) do begin if Result[Index] in DenySym then begin Result[Index]:= '_'; end; end; end; function ExtractConnectionHost(Connection: AnsiString): AnsiString; var Index: Integer; begin Index:= Pos('://', Connection); if Index > 0 then Delete(Connection, 1, Index + 2); if IsIPv6(Connection) then begin Index:= Pos('[', Connection); if Index = 1 then begin Index:= Pos(']', Connection, Index + 1); if Index > 0 then begin Connection:= Copy(Connection, 2, Index - 2); end; end; end else begin Index:= Pos(':', Connection); if Index > 0 then Connection:= Copy(Connection, 1, Index - 1) end; Result:= Connection; end; function ExtractConnectionPort(Connection: AnsiString): AnsiString; var I, J: Integer; begin I:= Pos('://', Connection); if I > 0 then Delete(Connection, 1, I + 2); if IsIPv6(Connection) then begin I:= Pos(']:', Connection); if I > 0 then Delete(Connection, 1, I + 1); end else begin I:= Pos(':', Connection); if I > 0 then Delete(Connection, 1, I); end; if I = 0 then Result:= EmptyStr else begin J:= Pos('/', Connection); if J = 0 then J:= MaxInt; Result:= Trim(Copy(Connection, 1, J - 1)); end; end; function ExtractConnectionProt(Connection: AnsiString): AnsiString; var I: Integer; begin Result:= LowerCase(Connection); I:= Pos('://', Result); if I = 0 then Result:= EmptyStr else begin Result:= Copy(Result, 1, I - 1); end; end; function FormatMachineTime(const Time: TFileTime): String; var FileTime: TDateTime; begin FileTime:= (Int64(Time) / 864000000000.0) - 109205.0; Result:= FormatDateTime('yyyymmddhhnnss', FileTime); end; function DecodeMachineTime(const Time: String): TDateTime; var Year, Month, Day: Word; Hour, Minute, Second: Word; begin try Year:= StrToIntDef(Copy(Time, 1, 4), 1970); Month:= StrToIntDef(Copy(Time, 5, 2), 1); Day:= StrToIntDef(Copy(Time, 7, 2), 1); Hour:= StrToIntDef(Copy(Time, 9, 2), 0); Minute:= StrToIntDef(Copy(Time, 11, 2), 0); Second:= StrToIntDef(Copy(Time, 13, 2), 0); Result:= EncodeDate(Year, Month, Day) + EncodeTime(Hour, Minute, Second, 0); Result:= UniversalTimeToLocal(Result, TimeZoneBias); except Result:= MinDateTime; end; end; end. �������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/sftp/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017427� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/sftp/libssh.pas������������������������������������������������0000644�0001750�0000144�00000074207�14743153644�021432� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit libssh; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils, CTypes, DynLibs; const //* Hash Types */ LIBSSH2_HOSTKEY_HASH_MD5 = 1; LIBSSH2_HOSTKEY_HASH_SHA1 = 2; LIBSSH2_HOSTKEY_HASH_SHA256 = 3; //* Method constants */ LIBSSH2_METHOD_KEX = 0; LIBSSH2_METHOD_HOSTKEY = 1; LIBSSH2_METHOD_CRYPT_CS = 2; LIBSSH2_METHOD_CRYPT_SC = 3; //* Disconnect Codes (defined by SSH protocol) */ SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1; SSH_DISCONNECT_PROTOCOL_ERROR = 2; SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3; SSH_DISCONNECT_RESERVED = 4; SSH_DISCONNECT_MAC_ERROR = 5; SSH_DISCONNECT_COMPRESSION_ERROR = 6; SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7; SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8; SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9; SSH_DISCONNECT_CONNECTION_LOST = 10; SSH_DISCONNECT_BY_APPLICATION = 11; SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12; SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13; SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14; SSH_DISCONNECT_ILLEGAL_USER_NAME = 15; { Error Codes (defined by libssh2) } LIBSSH2_ERROR_NONE = 0; LIBSSH2_ERROR_SOCKET_NONE = -(1); LIBSSH2_ERROR_BANNER_RECV = -(2); LIBSSH2_ERROR_BANNER_SEND = -(3); LIBSSH2_ERROR_INVALID_MAC = -(4); LIBSSH2_ERROR_KEX_FAILURE = -(5); LIBSSH2_ERROR_ALLOC = -(6); LIBSSH2_ERROR_SOCKET_SEND = -(7); LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE = -(8); LIBSSH2_ERROR_TIMEOUT = -(9); LIBSSH2_ERROR_HOSTKEY_INIT = -(10); LIBSSH2_ERROR_HOSTKEY_SIGN = -(11); LIBSSH2_ERROR_DECRYPT = -(12); LIBSSH2_ERROR_SOCKET_DISCONNECT = -(13); LIBSSH2_ERROR_PROTO = -(14); LIBSSH2_ERROR_PASSWORD_EXPIRED = -(15); LIBSSH2_ERROR_FILE = -(16); LIBSSH2_ERROR_METHOD_NONE = -(17); LIBSSH2_ERROR_AUTHENTICATION_FAILED = -(18); LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED = LIBSSH2_ERROR_AUTHENTICATION_FAILED; LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED = -(19); LIBSSH2_ERROR_CHANNEL_OUTOFORDER = -(20); LIBSSH2_ERROR_CHANNEL_FAILURE = -(21); LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED = -(22); LIBSSH2_ERROR_CHANNEL_UNKNOWN = -(23); LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED = -(24); LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED = -(25); LIBSSH2_ERROR_CHANNEL_CLOSED = -(26); LIBSSH2_ERROR_CHANNEL_EOF_SENT = -(27); LIBSSH2_ERROR_SCP_PROTOCOL = -(28); LIBSSH2_ERROR_ZLIB = -(29); LIBSSH2_ERROR_SOCKET_TIMEOUT = -(30); LIBSSH2_ERROR_SFTP_PROTOCOL = -(31); LIBSSH2_ERROR_REQUEST_DENIED = -(32); LIBSSH2_ERROR_METHOD_NOT_SUPPORTED = -(33); LIBSSH2_ERROR_INVAL = -(34); LIBSSH2_ERROR_INVALID_POLL_TYPE = -(35); LIBSSH2_ERROR_PUBLICKEY_PROTOCOL = -(36); LIBSSH2_ERROR_EAGAIN = -(37); LIBSSH2_ERROR_BUFFER_TOO_SMALL = -(38); LIBSSH2_ERROR_BAD_USE = -(39); LIBSSH2_ERROR_COMPRESS = -(40); LIBSSH2_ERROR_OUT_OF_BOUNDARY = -(41); LIBSSH2_ERROR_AGENT_PROTOCOL = -(42); LIBSSH2_ERROR_SOCKET_RECV = -(43); LIBSSH2_ERROR_ENCRYPT = -(44); LIBSSH2_ERROR_BAD_SOCKET = -(45); LIBSSH2_ERROR_KNOWN_HOSTS = -(46); //* Channel API */ LIBSSH2_CHANNEL_WINDOW_DEFAULT = (2*1024*1024); LIBSSH2_CHANNEL_PACKET_DEFAULT = 32768; //* Flags for open_ex() */ _LIBSSH2_SFTP_OPENFILE = 0; _LIBSSH2_SFTP_OPENDIR = 1; //* Flags for rename_ex() */ LIBSSH2_SFTP_RENAME_OVERWRITE = $00000001; LIBSSH2_SFTP_RENAME_ATOMIC = $00000002; LIBSSH2_SFTP_RENAME_NATIVE = $00000004; //* Flags for stat_ex() */ _LIBSSH2_SFTP_STAT = 0; _LIBSSH2_SFTP_LSTAT = 1; _LIBSSH2_SFTP_SETSTAT = 2; //* Flags for symlink_ex() */ _LIBSSH2_SFTP_SYMLINK = 0; _LIBSSH2_SFTP_READLINK = 1; _LIBSSH2_SFTP_REALPATH = 2; //* SFTP attribute flag bits */ LIBSSH2_SFTP_ATTR_SIZE = $00000001; LIBSSH2_SFTP_ATTR_UIDGID = $00000002; LIBSSH2_SFTP_ATTR_PERMISSIONS = $00000004; LIBSSH2_SFTP_ATTR_ACMODTIME = $00000008; LIBSSH2_SFTP_ATTR_EXTENDED = $80000000; //* File mode */ //* Read, write, execute/search by owner */ LIBSSH2_SFTP_S_IRWXU = 448; //* RWX mask for owner */ LIBSSH2_SFTP_S_IRUSR = 256; //* R for owner */ LIBSSH2_SFTP_S_IWUSR = 128; //* W for owner */ LIBSSH2_SFTP_S_IXUSR = 64; //* X for owner */ //* Read, write, execute/search by group */ LIBSSH2_SFTP_S_IRWXG = 56; //* RWX mask for group */ LIBSSH2_SFTP_S_IRGRP = 32; //* R for group */ LIBSSH2_SFTP_S_IWGRP = 16; //* W for group */ LIBSSH2_SFTP_S_IXGRP = 8; //* X for group */ //* Read, write, execute/search by others */ LIBSSH2_SFTP_S_IRWXO = 7; //* RWX mask for other */ LIBSSH2_SFTP_S_IROTH = 4; //* R for other */ LIBSSH2_SFTP_S_IWOTH = 2; //* W for other */ LIBSSH2_SFTP_S_IXOTH = 1; //* X for other */ //* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) */ LIBSSH2_FXF_READ = $00000001; LIBSSH2_FXF_WRITE = $00000002; LIBSSH2_FXF_APPEND = $00000004; LIBSSH2_FXF_CREAT = $00000008; LIBSSH2_FXF_TRUNC = $00000010; LIBSSH2_FXF_EXCL = $00000020; type //* Session API */ PLIBSSH2_SESSION = type Pointer; //* Agent API */ PLIBSSH2_AGENT = type Pointer; libssh2_agent_publickey = record magic: cuint; node: Pointer; blob: PByte; blob_len: csize_t; comment: PAnsiChar; end; Plibssh2_agent_publickey = ^libssh2_agent_publickey; PPlibssh2_agent_publickey = ^Plibssh2_agent_publickey; //* Channel API */ PLIBSSH2_CHANNEL = type Pointer; //* SFTP API */ PLIBSSH2_SFTP = type Pointer; PLIBSSH2_SFTP_HANDLE = type Pointer; PLIBSSH2_SFTP_ATTRIBUTES = ^LIBSSH2_SFTP_ATTRIBUTES; LIBSSH2_SFTP_ATTRIBUTES = record flags: culong; filesize: cuint64; uid, gid: culong; permissions: culong; atime, mtime: culong; end; PLIBSSH2_SFTP_STATVFS = ^_LIBSSH2_SFTP_STATVFS; _LIBSSH2_SFTP_STATVFS = record f_bsize: cuint64; //* file system block size */ f_frsize: cuint64; //* fragment size */ f_blocks: cuint64; //* size of fs in f_frsize units */ f_bfree: cuint64; //* # free blocks */ f_bavail: cuint64; //* # free blocks for non-root */ f_files: cuint64; //* # inodes */ f_ffree: cuint64; //* # free inodes */ f_favail: cuint64; //* # free inodes for non-root */ f_fsid: cuint64; //* file system ID */ f_flag: cuint64; //* mount flags */ f_namemax: cuint64; //* maximum filename length */ end; PLIBSSH2_USERAUTH_KBDINT_PROMPT = ^LIBSSH2_USERAUTH_KBDINT_PROMPT; LIBSSH2_USERAUTH_KBDINT_PROMPT = record text: PAnsiChar; length: cuint; echo: cuchar; end; PLIBSSH2_USERAUTH_KBDINT_RESPONSE = ^LIBSSH2_USERAUTH_KBDINT_RESPONSE; LIBSSH2_USERAUTH_KBDINT_RESPONSE = record text: PAnsiChar; length: cuint; end; Plibssh2_struct_stat = type Pointer; //* Malloc callbacks */ LIBSSH2_ALLOC_FUNC = function(count: csize_t; abstract: Pointer): Pointer; cdecl; LIBSSH2_REALLOC_FUNC = function(ptr: Pointer; count: csize_t; abstract: Pointer): Pointer; cdecl; LIBSSH2_FREE_FUNC = procedure(ptr: Pointer; abstract: Pointer); cdecl; //* Callbacks for special SSH packets */ LIBSSH2_PASSWD_CHANGEREQ_FUNC = procedure(session: PLIBSSH2_SESSION; var newpw: PAnsiChar; var newpw_len: cint; abstract: Pointer); cdecl; //* 'keyboard-interactive' authentication callback */ LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC = procedure(const name: PAnsiChar; name_len: cint; const instruction: PAnsiChar; instruction_len: cint; num_prompts: cint; const prompts: PLIBSSH2_USERAUTH_KBDINT_PROMPT; responses: PLIBSSH2_USERAUTH_KBDINT_RESPONSE; abstract: PPointer); cdecl; var //* Global API */ libssh2_init: function(flags: cint): cint; cdecl; libssh2_exit: procedure(); cdecl; libssh2_version: function(required_version: cint): PAnsiChar; cdecl; //* Session API */ libssh2_session_init_ex: function(my_alloc: LIBSSH2_ALLOC_FUNC; my_free: LIBSSH2_FREE_FUNC; my_realloc: LIBSSH2_REALLOC_FUNC; abstract: Pointer): PLIBSSH2_SESSION; cdecl; libssh2_session_handshake: function(session: PLIBSSH2_SESSION; sock: cint): cint; cdecl; libssh2_hostkey_hash: function(session: PLIBSSH2_SESSION; hash_type: cint): PAnsiChar; cdecl; libssh2_session_methods: function(session: PLIBSSH2_SESSION; method_type: cint): PAnsiChar; cdecl; libssh2_session_disconnect_ex: function(session: PLIBSSH2_SESSION; reason: cint; const description: PAnsiChar; const lang: PAnsiChar): cint; cdecl; libssh2_session_free: function(session: PLIBSSH2_SESSION): cint; cdecl; libssh2_session_set_blocking: procedure(session: PLIBSSH2_SESSION; blocking: cint); cdecl; libssh2_session_last_errno: function(session: PLIBSSH2_SESSION): cint; cdecl; libssh2_session_set_timeout: procedure(session: PLIBSSH2_SESSION; timeout: clong); cdecl; libssh2_session_last_error: function(session: PLIBSSH2_SESSION; errmsg: PPAnsiChar; errmsg_len: pcint; want_buf: cint): cint; cdecl; //* Userauth API */ libssh2_userauth_authenticated: function(session: PLIBSSH2_SESSION): cint; cdecl; libssh2_userauth_list: function(session: PLIBSSH2_SESSION; const username: PAnsiChar; username_len: cuint): PAnsiChar; cdecl; libssh2_userauth_password_ex: function(session: PLIBSSH2_SESSION; const username: PAnsiChar; username_len: cuint; const password: PAnsiChar; password_len: cuint; passwd_change_cb: LIBSSH2_PASSWD_CHANGEREQ_FUNC): cint; cdecl; libssh2_userauth_keyboard_interactive_ex: function(session: PLIBSSH2_SESSION; const username: PAnsiChar; username_len: cuint; response_callback: LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC): cint; cdecl; libssh2_userauth_publickey_fromfile_ex: function(session: PLIBSSH2_SESSION; const username: PAnsiChar; username_len: cuint; const publickey, privatekey, passphrase: PAnsiChar): cint; cdecl; //* Agent API */ libssh2_agent_init: function(session: PLIBSSH2_SESSION): PLIBSSH2_AGENT; cdecl; libssh2_agent_connect: function(agent: PLIBSSH2_AGENT): cint; cdecl; libssh2_agent_list_identities: function(agent: PLIBSSH2_AGENT): cint; cdecl; libssh2_agent_get_identity: function(agent: PLIBSSH2_AGENT; store: PPlibssh2_agent_publickey; prev: Plibssh2_agent_publickey): cint; cdecl; libssh2_agent_userauth: function(agent: PLIBSSH2_AGENT; const username: PAnsiChar; identity: Plibssh2_agent_publickey): cint; cdecl; libssh2_agent_disconnect: function(agent: PLIBSSH2_AGENT): cint; cdecl; libssh2_agent_free: procedure(agent: PLIBSSH2_AGENT); cdecl; //* Channel API */ libssh2_channel_open_ex: function(session: PLIBSSH2_SESSION; const channel_type: PAnsiChar; channel_type_len, window_size, packet_size: cuint; const message: PAnsiChar; message_len: cuint): PLIBSSH2_CHANNEL; cdecl; libssh2_channel_free: function(channel: PLIBSSH2_CHANNEL): cint; cdecl; libssh2_channel_set_blocking: procedure (channel: PLIBSSH2_CHANNEL; blocking: cint); cdecl; libssh2_channel_process_startup: function(channel: PLIBSSH2_CHANNEL; const request: PAnsiChar; request_len: cuint; const message: PAnsiChar; message_len: cuint): cint; cdecl; libssh2_channel_flush_ex: function(channel: PLIBSSH2_CHANNEL; streamid: cint): cint; cdecl; libssh2_channel_send_eof: function(channel: PLIBSSH2_CHANNEL): cint; cdecl; libssh2_channel_eof: function(channel: PLIBSSH2_CHANNEL): cint; cdecl; libssh2_channel_read_ex: function(channel: PLIBSSH2_CHANNEL; stream_id: cint; buf: PAnsiChar; buflen: csize_t): ptrint; cdecl; libssh2_channel_write_ex: function(channel: PLIBSSH2_CHANNEL; stream_id: cint; const buf: PAnsiChar; buflen: csize_t): ptrint; cdecl; libssh2_channel_get_exit_status: function(channel: PLIBSSH2_CHANNEL): cint; cdecl; libssh2_scp_send64: function(session: PLIBSSH2_SESSION; const path: PAnsiChar; mode: cint; size: cuint64; mtime, atime: ptrint): PLIBSSH2_CHANNEL; cdecl; libssh2_scp_recv2: function(session: PLIBSSH2_SESSION; const path: PAnsiChar; sb: Plibssh2_struct_stat): PLIBSSH2_CHANNEL; cdecl; //* SFTP API */ libssh2_sftp_init: function(session: PLIBSSH2_SESSION): PLIBSSH2_SFTP; cdecl; libssh2_sftp_shutdown: function(sftp: PLIBSSH2_SFTP): cint; cdecl; libssh2_sftp_last_error: function(sftp: PLIBSSH2_SFTP): culong; cdecl; //* File / Directory Ops */ libssh2_sftp_open_ex: function(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar; filename_len: cint; flags: culong; mode: clong; open_type: cint): PLIBSSH2_SFTP_HANDLE; cdecl; libssh2_sftp_read: function(handle: PLIBSSH2_SFTP_HANDLE; buffer: PAnsiChar; buffer_maxlen: csize_t): ptrint; cdecl; libssh2_sftp_write: function(handle: PLIBSSH2_SFTP_HANDLE; buffer: PByte; count: csize_t): ptrint; cdecl; libssh2_sftp_readdir_ex: function(handle: PLIBSSH2_SFTP_HANDLE; buffer: PAnsiChar; buffer_maxlen: csize_t; longentry: PAnsiChar; longentry_maxlen: csize_t; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; cdecl; libssh2_sftp_close_handle: function(handle: PLIBSSH2_SFTP_HANDLE): cint; cdecl; libssh2_sftp_seek64: procedure(handle: PLIBSSH2_SFTP_HANDLE; offset: cuint64); cdecl; //* Miscellaneous Ops */ libssh2_sftp_rename_ex: function(sftp: PLIBSSH2_SFTP; const source_filename: PAnsiChar; srouce_filename_len: cuint; const dest_filename: PAnsiChar; dest_filename_len: cuint; flags: clong): cint; cdecl; libssh2_sftp_unlink_ex: function(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar; filename_len: cuint): cint; cdecl; libssh2_sftp_statvfs: function(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; path_len: csize_t; st: PLIBSSH2_SFTP_STATVFS): cint; cdecl; libssh2_sftp_mkdir_ex: function(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; path_len: cuint; mode: clong): cint; cdecl; libssh2_sftp_rmdir_ex: function(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; path_len: cuint): cint; cdecl; libssh2_sftp_stat_ex: function(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; path_len: cuint; stat_type: cint; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; cdecl; libssh2_sftp_symlink_ex: function(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; path_len: cuint; target: PAnsiChar; target_len: cuint; link_type: cint): cint; cdecl; //* Inline functions */ function libssh2_session_init(abstract: Pointer): PLIBSSH2_SESSION; inline; function libssh2_session_disconnect(session: PLIBSSH2_SESSION; const description: PAnsiChar): cint; inline; function libssh2_userauth_password(session: PLIBSSH2_SESSION; const username: PAnsiChar; const password: PAnsiChar): cint; inline; function libssh2_userauth_keyboard_interactive(session: PLIBSSH2_SESSION; const username: PAnsiChar; response_callback: LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC): cint; inline; function libssh2_userauth_publickey_fromfile(session: PLIBSSH2_SESSION; const username, publickey, privatekey, passphrase: PAnsiChar): cint; inline; function libssh2_channel_open_session(session: PLIBSSH2_SESSION): PLIBSSH2_CHANNEL; inline; function libssh2_channel_exec(channel: PLIBSSH2_CHANNEL; command: PAnsiChar): cint; inline; function libssh2_channel_flush(channel: PLIBSSH2_CHANNEL): cint; inline; function libssh2_channel_read(channel: PLIBSSH2_CHANNEL; buf: PAnsiChar; buflen: csize_t): ptrint; inline; function libssh2_channel_read_stderr(channel: PLIBSSH2_CHANNEL; buf: PAnsiChar; buflen: csize_t): ptrint; inline; function libssh2_channel_write(channel: PLIBSSH2_CHANNEL; const buf: PAnsiChar; buflen: csize_t): ptrint; inline; function libssh2_sftp_open(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar; flags: culong; mode: clong): PLIBSSH2_SFTP_HANDLE; inline; function libssh2_sftp_opendir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): PLIBSSH2_SFTP_HANDLE; inline; function libssh2_sftp_close(handle: PLIBSSH2_SFTP_HANDLE): cint; inline; function libssh2_sftp_closedir(handle: PLIBSSH2_SFTP_HANDLE): cint; inline; function libssh2_sftp_rename(sftp: PLIBSSH2_SFTP; const sourcefile: PAnsiChar; const destfile: PAnsiChar): cint; inline; function libssh2_sftp_unlink(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar): cint; inline; function libssh2_sftp_mkdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; mode: clong): cint; inline; function libssh2_sftp_rmdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): cint; inline; function libssh2_sftp_stat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; inline; function libssh2_sftp_lstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; inline; function libssh2_sftp_setstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; inline; function libssh2_sftp_symlink(sftp: PLIBSSH2_SFTP; const orig: PAnsiChar; linkpath: PAnsiChar): cint; inline; function libssh2_sftp_readlink(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: cuint): cint; inline; function libssh2_sftp_realpath(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: cuint): cint; inline; const LibSSHName = {$IF DEFINED(MSWINDOWS)} 'libssh2.dll' {$ELSEIF DEFINED(DARWIN)} 'libssh2.dylib' {$ELSEIF DEFINED(UNIX)} 'libssh2.so.1' {$ENDIF} ; var libssh2: TLibHandle = NilHandle; implementation uses DCOSUtils; function libssh2_alloc(count: csize_t; abstract: Pointer): Pointer; cdecl; begin Result:= GetMem(count); end; function libssh2_realloc(ptr: Pointer; count: csize_t; abstract: Pointer): Pointer; cdecl; begin Result:= ReAllocMem(ptr, count); end; procedure libssh2_free(ptr: Pointer; abstract: Pointer); cdecl; begin FreeMem(ptr); end; function libssh2_session_init(abstract: Pointer): PLIBSSH2_SESSION; begin Result:= libssh2_session_init_ex(libssh2_alloc, libssh2_free, libssh2_realloc, abstract); end; function libssh2_session_disconnect(session: PLIBSSH2_SESSION; const description: PAnsiChar): cint; begin Result:= libssh2_session_disconnect_ex(session, SSH_DISCONNECT_BY_APPLICATION, description, ''); end; function libssh2_userauth_password(session: PLIBSSH2_SESSION; const username: PAnsiChar; const password: PAnsiChar): cint; begin Result:= libssh2_userauth_password_ex(session, username, strlen(username), password, strlen(password), nil); end; function libssh2_userauth_keyboard_interactive(session: PLIBSSH2_SESSION; const username: PAnsiChar; response_callback: LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC): cint; begin Result:= libssh2_userauth_keyboard_interactive_ex(session, username, strlen(username), response_callback); end; function libssh2_userauth_publickey_fromfile(session: PLIBSSH2_SESSION; const username, publickey, privatekey, passphrase: PAnsiChar): cint; begin Result:= libssh2_userauth_publickey_fromfile_ex(session, username, strlen(username), publickey, privatekey, passphrase); end; function libssh2_channel_open_session(session: PLIBSSH2_SESSION): PLIBSSH2_CHANNEL; begin Result:= libssh2_channel_open_ex(session, 'session', Length('session'), LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, nil, 0); end; function libssh2_channel_exec(channel: PLIBSSH2_CHANNEL; command: PAnsiChar): cint; begin REsult:= libssh2_channel_process_startup(channel, 'exec', Length('exec'), command, strlen(command)); end; function libssh2_channel_flush(channel: PLIBSSH2_CHANNEL): cint; begin Result:= libssh2_channel_flush_ex(channel, 0); end; function libssh2_channel_read(channel: PLIBSSH2_CHANNEL; buf: PAnsiChar; buflen: csize_t): ptrint; cdecl; begin Result:= libssh2_channel_read_ex(channel, 0, buf, buflen); end; function libssh2_channel_read_stderr(channel: PLIBSSH2_CHANNEL; buf: PAnsiChar; buflen: csize_t): ptrint; cdecl; begin Result:= libssh2_channel_read_ex(channel, 1, buf, buflen); end; function libssh2_channel_write(channel: PLIBSSH2_CHANNEL; const buf: PAnsiChar; buflen: csize_t): ptrint; begin Result:= libssh2_channel_write_ex(channel, 0, buf, buflen); end; function libssh2_sftp_open(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar; flags: culong; mode: clong): PLIBSSH2_SFTP_HANDLE; begin Result:= libssh2_sftp_open_ex(sftp, filename, strlen(filename), flags, mode, _LIBSSH2_SFTP_OPENFILE); end; function libssh2_sftp_opendir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): PLIBSSH2_SFTP_HANDLE; begin Result:= libssh2_sftp_open_ex(sftp, path, strlen(path), 0, 0, _LIBSSH2_SFTP_OPENDIR); end; function libssh2_sftp_close(handle: PLIBSSH2_SFTP_HANDLE): cint; begin Result:= libssh2_sftp_close_handle(handle); end; function libssh2_sftp_closedir(handle: PLIBSSH2_SFTP_HANDLE): cint; begin Result:= libssh2_sftp_close_handle(handle); end; function libssh2_sftp_rename(sftp: PLIBSSH2_SFTP; const sourcefile: PAnsiChar; const destfile: PAnsiChar): cint; begin Result:= libssh2_sftp_rename_ex(sftp, sourcefile, strlen(sourcefile), destfile, strlen(destfile), LIBSSH2_SFTP_RENAME_OVERWRITE or LIBSSH2_SFTP_RENAME_ATOMIC or LIBSSH2_SFTP_RENAME_NATIVE); end; function libssh2_sftp_unlink(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar): cint; begin Result:= libssh2_sftp_unlink_ex(sftp, filename, strlen(filename)); end; function libssh2_sftp_mkdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; mode: clong): cint; begin Result:= libssh2_sftp_mkdir_ex(sftp, path, strlen(path), mode); end; function libssh2_sftp_rmdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): cint; begin Result:= libssh2_sftp_rmdir_ex(sftp, path, strlen(path)); end; function libssh2_sftp_stat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; begin Result:= libssh2_sftp_stat_ex(sftp, path, strlen(path), _LIBSSH2_SFTP_STAT, attrs); end; function libssh2_sftp_lstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; begin Result:= libssh2_sftp_stat_ex(sftp, path, strlen(path), _LIBSSH2_SFTP_LSTAT, attrs); end; function libssh2_sftp_setstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; begin repeat Result:= libssh2_sftp_stat_ex(sftp, path, strlen(path), _LIBSSH2_SFTP_SETSTAT, attrs); Sleep(1); until Result <> LIBSSH2_ERROR_EAGAIN; end; function libssh2_sftp_symlink(sftp: PLIBSSH2_SFTP; const orig: PAnsiChar; linkpath: PAnsiChar): cint; begin Result:= libssh2_sftp_symlink_ex(sftp, orig, strlen(orig), linkpath, strlen(linkpath), _LIBSSH2_SFTP_SYMLINK); end; function libssh2_sftp_readlink(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: cuint): cint; begin Result:= libssh2_sftp_symlink_ex(sftp, path, strlen(path), target, maxlen, _LIBSSH2_SFTP_READLINK) end; function libssh2_sftp_realpath(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: cuint): cint; begin Result:= libssh2_sftp_symlink_ex(sftp, path, strlen(path), target, maxlen, _LIBSSH2_SFTP_REALPATH); end; procedure Initialize; begin libssh2:= LoadLibrary(LibSSHName); if (libssh2 <> NilHandle) then try //* Global API */ libssh2_init:= SafeGetProcAddress(libssh2, 'libssh2_init'); libssh2_exit:= SafeGetProcAddress(libssh2, 'libssh2_exit'); libssh2_version:= SafeGetProcAddress(libssh2, 'libssh2_version'); //* Session API */ libssh2_session_init_ex:= SafeGetProcAddress(libssh2, 'libssh2_session_init_ex'); libssh2_session_handshake:= SafeGetProcAddress(libssh2, 'libssh2_session_handshake'); libssh2_hostkey_hash:= SafeGetProcAddress(libssh2, 'libssh2_hostkey_hash'); libssh2_session_methods:= SafeGetProcAddress(libssh2, 'libssh2_session_methods'); libssh2_session_disconnect_ex:= SafeGetProcAddress(libssh2, 'libssh2_session_disconnect_ex'); libssh2_session_free:= SafeGetProcAddress(libssh2, 'libssh2_session_free'); libssh2_session_set_blocking:= SafeGetProcAddress(libssh2, 'libssh2_session_set_blocking'); libssh2_session_last_errno:= SafeGetProcAddress(libssh2, 'libssh2_session_last_errno'); libssh2_session_last_error:= SafeGetProcAddress(libssh2, 'libssh2_session_last_error'); libssh2_session_set_timeout:= SafeGetProcAddress(libssh2, 'libssh2_session_set_timeout'); //* Userauth API */ libssh2_userauth_list:= SafeGetProcAddress(libssh2, 'libssh2_userauth_list'); libssh2_userauth_password_ex:= SafeGetProcAddress(libssh2, 'libssh2_userauth_password_ex'); libssh2_userauth_authenticated:= SafeGetProcAddress(libssh2, 'libssh2_userauth_authenticated'); libssh2_userauth_keyboard_interactive_ex:= SafeGetProcAddress(libssh2, 'libssh2_userauth_keyboard_interactive_ex'); libssh2_userauth_publickey_fromfile_ex:= SafeGetProcAddress(libssh2, 'libssh2_userauth_publickey_fromfile_ex'); //* Agent API */ libssh2_agent_init:= SafeGetProcAddress(libssh2, 'libssh2_agent_init'); libssh2_agent_connect:= SafeGetProcAddress(libssh2, 'libssh2_agent_connect'); libssh2_agent_list_identities:= SafeGetProcAddress(libssh2, 'libssh2_agent_list_identities'); libssh2_agent_get_identity:= SafeGetProcAddress(libssh2, 'libssh2_agent_get_identity'); libssh2_agent_userauth:= SafeGetProcAddress(libssh2, 'libssh2_agent_userauth'); libssh2_agent_disconnect:= SafeGetProcAddress(libssh2, 'libssh2_agent_disconnect'); libssh2_agent_free:= SafeGetProcAddress(libssh2, 'libssh2_agent_free'); //* Channel API */ libssh2_channel_open_ex:= SafeGetProcAddress(libssh2, 'libssh2_channel_open_ex'); libssh2_channel_free:= SafeGetProcAddress(libssh2, 'libssh2_channel_free'); libssh2_channel_set_blocking:= SafeGetProcAddress(libssh2, 'libssh2_channel_set_blocking'); libssh2_channel_process_startup:= SafeGetProcAddress(libssh2, 'libssh2_channel_process_startup'); libssh2_channel_flush_ex:= SafeGetProcAddress(libssh2, 'libssh2_channel_flush_ex'); libssh2_channel_send_eof:= SafeGetProcAddress(libssh2, 'libssh2_channel_send_eof'); libssh2_channel_eof:= SafeGetProcAddress(libssh2, 'libssh2_channel_eof'); libssh2_channel_read_ex:= SafeGetProcAddress(libssh2, 'libssh2_channel_read_ex'); libssh2_channel_write_ex:= SafeGetProcAddress(libssh2, 'libssh2_channel_write_ex'); libssh2_channel_get_exit_status:= SafeGetProcAddress(libssh2, 'libssh2_channel_get_exit_status'); libssh2_scp_send64:= SafeGetProcAddress(libssh2, 'libssh2_scp_send64'); libssh2_scp_recv2:= SafeGetProcAddress(libssh2, 'libssh2_scp_recv2'); //* SFTP API */ libssh2_sftp_init:= SafeGetProcAddress(libssh2, 'libssh2_sftp_init'); libssh2_sftp_shutdown:= SafeGetProcAddress(libssh2, 'libssh2_sftp_shutdown'); libssh2_sftp_last_error:= SafeGetProcAddress(libssh2, 'libssh2_sftp_last_error'); //* File / Directory Ops */ libssh2_sftp_open_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_open_ex'); libssh2_sftp_read:= SafeGetProcAddress(libssh2, 'libssh2_sftp_read'); libssh2_sftp_write:= SafeGetProcAddress(libssh2, 'libssh2_sftp_write'); libssh2_sftp_readdir_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_readdir_ex'); libssh2_sftp_close_handle:= SafeGetProcAddress(libssh2, 'libssh2_sftp_close_handle'); libssh2_sftp_seek64:= SafeGetProcAddress(libssh2, 'libssh2_sftp_seek64'); //* Miscellaneous Ops */ libssh2_sftp_rename_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_rename_ex'); libssh2_sftp_unlink_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_unlink_ex'); libssh2_sftp_statvfs:= SafeGetProcAddress(libssh2, 'libssh2_sftp_statvfs'); libssh2_sftp_mkdir_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_mkdir_ex'); libssh2_sftp_rmdir_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_rmdir_ex'); libssh2_sftp_stat_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_stat_ex'); libssh2_sftp_symlink_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_symlink_ex'); // Initialize the libssh2 functions if (libssh2_init(0) <> 0) then raise Exception.Create(EmptyStr); except FreeLibrary(libssh2); libssh2:= NilHandle; end; end; initialization Initialize; finalization if (libssh2 <> NilHandle) then begin libssh2_exit(); FreeLibrary(libssh2); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/sftp/scpsend.pas�����������������������������������������������0000644�0001750�0000144�00000074266�14743153644�021612� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Wfx plugin for working with File Transfer Protocol Copyright (C) 2013-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit ScpSend; {$mode delphi} {$pointermath on} interface uses Classes, SysUtils, WfxPlugin, FtpAdv, libssh; type { TScpSend } TScpSend = class(TFTPSendEx) private FAutoDetect: Boolean; FListCommand: String; FPassphrase: AnsiString; FChannel: PLIBSSH2_CHANNEL; FErrorStream: TStringBuilder; private function OpenChannel: Boolean; procedure PrintErrors(const E: String); function CloseChannel(Channel: PLIBSSH2_CHANNEL): Boolean; function SendCommand(const Command: String): Boolean; overload; function SendCommand(const Command: String; out Answer: String; Err: Boolean = True): Boolean; overload; private FAnswer: String; protected FAgent: Boolean; FCurrentDir: String; FLastError: Integer; FSavedPassword: Boolean; FFingerprint: AnsiString; FSession: PLIBSSH2_SESSION; SourceName, TargetName: PWideChar; procedure DoProgress(Percent: Int64); protected procedure PrintLastError; procedure DetectEncoding; function AuthKey: Integer; function AuthAgent: Integer; function Connect: Boolean; override; public constructor Create(const Encoding: String); override; destructor Destroy; override; function Login: Boolean; override; function Logout: Boolean; override; function GetCurrentDir: String; override; function NetworkError: Boolean; override; procedure CloneTo(AValue: TFTPSendEx); override; function FileSize(const FileName: String): Int64; override; function FileExists(const FileName: String): Boolean; override; function CreateDir(const Directory: string): Boolean; override; function DeleteDir(const Directory: string): Boolean; override; function DeleteFile(const FileName: string): Boolean; override; function FileProperties(const FileName: String): Boolean; override; function CopyFile(const OldName, NewName: String): Boolean; override; function ChangeWorkingDir(const Directory: string): Boolean; override; function RenameFile(const OldName, NewName: string): Boolean; override; function ChangeMode(const FileName, Mode: String): Boolean; override; function ExecuteCommand(const Command, Directory: String): Boolean; override; function StoreFile(const FileName: string; Restore: Boolean): Boolean; override; function RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; override; public function DataRead(const DestStream: TStream): Boolean; override; public function List(Directory: String; NameList: Boolean): Boolean; override; function FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PWfxFileTime): BOOL; override; public property Agent: Boolean read FAgent write FAgent; property Fingerprint: AnsiString read FFingerprint write FFingerprint; end; implementation uses CTypes, LazUTF8, FtpFunc, DCStrUtils, DCClassesUtf8, DCOSUtils, DCDateTimeUtils, DCBasicTypes, DCConvertEncoding, FileUtil, Base64, LConvEncoding, SynaCode, StrUtils; const TXT_BUFFER_SIZE = 4096; SMB_BUFFER_SIZE = 131072; LIST_TIME_STYLE = ' --time-style=+%Y.%m.%d-%H:%M:%S'; LIST_LOCALE_C = 'export LC_TIME=C' + #10 + 'export LC_MESSAGES=C' + #10; procedure userauth_kbdint(const name: PAnsiChar; name_len: cint; const instruction: PAnsiChar; instruction_len: cint; num_prompts: cint; const prompts: PLIBSSH2_USERAUTH_KBDINT_PROMPT; responses: PLIBSSH2_USERAUTH_KBDINT_RESPONSE; abstract: PPointer); cdecl; var S: String; I: Integer; Sender: TScpSend; Title, Message, Password: UnicodeString; begin Sender:= TScpSend(abstract^); for I:= 0 to num_prompts - 1 do begin if (I = 0) and (Length(Sender.FPassword) > 0) and (not Sender.FSavedPassword) then begin Sender.FSavedPassword:= True; responses^.text:= GetMem(Length(Sender.FPassword) + 1); StrCopy(responses^.text, PAnsiChar(Sender.FPassword)); responses^.length:= Length(Sender.FPassword); end else begin Title:= EmptyWideStr; Message:= EmptyWideStr; if Assigned(instruction) and (instruction_len > 0) then begin SetString(S, instruction, instruction_len); Message:= Sender.ServerToClient(S) + LineEnding; end; if Assigned(prompts[I].text) and (prompts[I].length > 0) then begin SetString(S, prompts[I].text, prompts[I].length); Message+= Sender.ServerToClient(S); end; if Assigned(name) and (name_len > 0) then begin SetString(S, name, name_len); Title:= Sender.ServerToClient(S) + #32; end; SetLength(Password, MAX_PATH + 1); Title+= 'ssh://' + UTF8ToUTF16(Sender.UserName + '@' + Sender.TargetHost); if not RequestProc(PluginNumber, RT_Password, PWideChar(Title), PWideChar(Message), PWideChar(Password), MAX_PATH) then begin responses[I].text:= nil; responses[I].length:= 0; end else begin Sender.FPassword:= Sender.ClientToServer(Password); responses[I].text:= GetMem(Length(Sender.FPassword) + 1); StrCopy(responses[I].text, PAnsiChar(Sender.FPassword)); responses[I].length:= Length(Sender.FPassword); end; end; end; end; { TScpSend } function TScpSend.OpenChannel: Boolean; begin repeat FChannel := libssh2_channel_open_session(FSession); if not Assigned(FChannel) then begin FLastError:= libssh2_session_last_errno(FSession); if (FLastError <> LIBSSH2_ERROR_EAGAIN) then begin PrintLastError; Exit(False); end; end; until not ((FChannel = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN)); Result:= Assigned(FChannel); end; function TScpSend.CloseChannel(Channel: PLIBSSH2_CHANNEL): Boolean; begin repeat FLastError:= libssh2_channel_free(Channel); until (FLastError <> LIBSSH2_ERROR_EAGAIN); Result:= (FLastError = 0); end; procedure TScpSend.PrintErrors(const E: String); var S: String = ''; Index: Integer = 1; begin while GetNextLine(E, S, Index) do begin LogProc(PluginNumber, msgtype_importanterror, PWideChar(ServerToClient(S))); end; end; function TScpSend.SendCommand(const Command: String): Boolean; begin repeat FLastError := libssh2_channel_exec(FChannel, PAnsiChar(Command)); until (FLastError <> LIBSSH2_ERROR_EAGAIN); while (libssh2_channel_flush(FChannel) = LIBSSH2_ERROR_EAGAIN) do; while (libssh2_channel_send_eof(FChannel) = LIBSSH2_ERROR_EAGAIN) do; Result:= (FLastError >= 0); end; function TScpSend.SendCommand(const Command: String; out Answer: String; Err: Boolean): Boolean; var Ret: cint; E, Buffer: String; begin Result:= OpenChannel; if Result then begin Result:= SendCommand(Command); if Result then begin E:= EmptyStr; Answer:= EmptyStr; SetLength(Buffer, TXT_BUFFER_SIZE + 1); while libssh2_channel_eof(FChannel) = 0 do begin repeat Ret:= libssh2_channel_read_stderr(FChannel, Pointer(Buffer), TXT_BUFFER_SIZE); until Ret <> LIBSSH2_ERROR_EAGAIN; if Ret > 0 then E+= Copy(Buffer, 1, Ret); repeat Ret:= libssh2_channel_read(FChannel, Pointer(Buffer), TXT_BUFFER_SIZE); until Ret <> LIBSSH2_ERROR_EAGAIN; if (Ret > 0) then Answer+= Copy(Buffer, 1, Ret); end; Result:= (libssh2_channel_get_exit_status(FChannel) = 0) and (Length(E) = 0); if Err and (Length(E) > 0) then PrintErrors(E); end; CloseChannel(FChannel); end; end; procedure TScpSend.DoProgress(Percent: Int64); begin if ProgressProc(PluginNumber, SourceName, TargetName, Percent) = 1 then raise EUserAbort.Create(EmptyStr); end; procedure TScpSend.PrintLastError; var Message: String; errmsg_len: cint; errmsg: PAnsiChar; begin FLastError:= libssh2_session_last_error(FSession, @errmsg, @errmsg_len, 0); SetString(Message, errmsg, errmsg_len); LogProc(PluginNumber, msgtype_importanterror, PWideChar(UnicodeString('SSH ERROR ' + Message))); end; procedure TScpSend.DetectEncoding; begin if SendCommand('echo $LANG $LC_CTYPE $LC_ALL', FAnswer) then begin FAuto:= False; if Pos('UTF-8', FAnswer) > 0 then begin Encoding:= EncodingUTF8; end; end; end; function TScpSend.AuthKey: Integer; const Alphabet = ['a'..'z','A'..'Z','0'..'9','+','/','=', #10, #13]; var Key: String; Index: Integer; Memory: PAnsiChar; PrivateStream: String; Encrypted: Boolean = False; Passphrase: AnsiString = ''; Title, Message, Password: UnicodeString; begin PrivateStream:= ReadFileToString(FPrivateKey); // Check private key format Index:= Pos(#10, PrivateStream); if Index = 0 then Index:= Pos(#13, PrivateStream); if Index > 0 then begin // Skip first line and empty lines Memory:= Pointer(@PrivateStream[Index]) + 1; while Memory^ in [#10, #13] do Inc(Memory); // Check old private key format for Index:= 0 to 31 do begin if (not (Memory[Index] in Alphabet)) then begin Encrypted:= True; Break; end; end; // Check new OpenSSH private key format if not Encrypted then begin if Pos('-----BEGIN OPENSSH PRIVATE KEY-----', PrivateStream) > 0 then begin Key:= DecodeStringBase64(Memory); Index:= Pos('bcrypt', Key); Encrypted:= (Index > 0) and (Index <= 64); end; end; end; // Private key encrypted, request passphrase if Encrypted then begin if (Length(FPassphrase) > 0) then Passphrase:= FPassphrase else begin SetLength(Password, MAX_PATH + 1); Message:= 'Private key passphrase:'; Title:= 'ssh://' + UTF8ToUTF16(FUserName + '@' + FTargetHost); if RequestProc(PluginNumber, RT_Password, PWideChar(Title), PWideChar(Message), PWideChar(Password), MAX_PATH) then begin Passphrase:= ClientToServer(Password); FillWord(Password[1], Length(Password), 0); end; end; end; repeat FLastError:= libssh2_userauth_publickey_fromfile(FSession, PAnsiChar(FUserName), PAnsiChar(CeUtf8ToSys(FPublicKey)), PAnsiChar(CeUtf8ToSys(FPrivateKey)), PAnsiChar(Passphrase)); until (FLastError <> LIBSSH2_ERROR_EAGAIN); // Save passphrase to cache if (FLastError = 0) and (Length(Passphrase) > 0) then begin FPassphrase:= Passphrase; end; Result:= FLastError; end; function TScpSend.AuthAgent: Integer; var agent: PLIBSSH2_AGENT; identity, prev_identity: Plibssh2_agent_publickey; begin agent:= libssh2_agent_init(FSession); if (agent = nil) then Exit(-1); try Result:= libssh2_agent_connect(agent); if (Result = LIBSSH2_ERROR_NONE) then try Result:= libssh2_agent_list_identities(agent); if Result < 0 then Exit; prev_identity:= nil; while True do begin Result:= libssh2_agent_get_identity(agent, @identity, prev_identity); if (Result < 0) then Exit; if (Result = 1) then Exit(-1); repeat FLastError:= libssh2_agent_userauth(agent, PAnsiChar(FUserName), identity); until (FLastError <> LIBSSH2_ERROR_EAGAIN); if (FLastError <> 0) then begin DoStatus(False, Format('Authentication with username %s and public key %s failed', [username, identity^.comment])); end else begin DoStatus(False, Format('Authentication with username %s and public key %s succeeded', [username, identity^.comment])); Break; end; prev_identity:= identity; end; finally libssh2_agent_disconnect(agent); end; finally libssh2_agent_free(agent); end; end; function TScpSend.Connect: Boolean; const HASH_SIZE: array[1..3] of Byte = (16, 20, 32); HASH_NAME: array[1..3] of String = ('(MD5) ', '(SHA1) ', '(SHA256) '); var S: String; F: String = ''; SS: String = ''; CS, SC: PAnsiChar; I, J, Finish: Integer; Message: UnicodeString; FingerPrint: PAnsiChar; userauthlist: PAnsiChar; begin FSock.CloseSocket; DoStatus(False, 'Connecting to: ' + FTargetHost); FSock.Connect(FTargetHost, FTargetPort); Result:= (FSock.LastError = 0); if Result then begin FSession := libssh2_session_init(Self); if not Assigned(FSession) then Exit(False); try libssh2_session_set_timeout(FSession, FTimeout); //* Since we have not set non-blocking, tell libssh2 we are blocking */ libssh2_session_set_blocking(FSession, 1); FLastError:= libssh2_session_handshake(FSession, FSock.Socket); if FLastError <> 0 then begin DoStatus(False, 'Cannot perform the SSH handshake ' + IntToStr(FLastError)); Exit(False); end; LogProc(PluginNumber, MSGTYPE_CONNECT, nil); DoStatus(False, 'Connection established'); DoStatus(False, 'Key exchange method: ' + libssh2_session_methods(FSession, LIBSSH2_METHOD_KEX)); CS:= libssh2_session_methods(FSession, LIBSSH2_METHOD_CRYPT_CS); SC:= libssh2_session_methods(FSession, LIBSSH2_METHOD_CRYPT_SC); if Assigned(CS) and Assigned(SC) and (StrComp(SC, SC) = 0) then DoStatus(False, 'Encryption method: ' + CS) else begin DoStatus(False, 'Encryption method (client to server): ' + CS); DoStatus(False, 'Encryption method (server to client): ' + SC); end; DoStatus(False, 'Host key method: ' + libssh2_session_methods(FSession, LIBSSH2_METHOD_HOSTKEY)); if libssh2_version($010900) = nil then Finish:= LIBSSH2_HOSTKEY_HASH_SHA1 else begin Finish:= LIBSSH2_HOSTKEY_HASH_SHA256; end; for J:= LIBSSH2_HOSTKEY_HASH_MD5 to Finish do begin FingerPrint := libssh2_hostkey_hash(FSession, J); if Assigned(FingerPrint) then begin if (J >= LIBSSH2_HOSTKEY_HASH_SHA256) then begin SetString(S, FingerPrint, HASH_SIZE[J]); S := TrimRightSet(EncodeBase64(S), ['=']); end else begin S:= EmptyStr; for I:= 0 to HASH_SIZE[J] - 1 do begin S+= IntToHex(Ord(FingerPrint[I]), 2) + #32; end; SetLength(S, Length(S) - 1); // Remove space end; SS += HASH_NAME[J] + S + LineEnding; DoStatus(False, 'Server fingerprint: ' + HASH_NAME[J] + S); if (J > LIBSSH2_HOSTKEY_HASH_MD5) and (Length(F) = 0) then F:= S; end; end; // Verify server fingerprint if FFingerPrint <> F then begin if FFingerprint = EmptyStr then Message:= 'You are using this connection for the first time.' + LineEnding + 'Please verify that the following host fingerprint matches the fingerprint of your server:' else begin Message:= 'WARNING!' + LineEnding + 'The fingerprint of the host has changed!' + LineEnding + 'Please make sure that the new fingerprint matches your server:'; end; Message += UnicodeString(LineEnding + LineEnding + SS); if not RequestProc(PluginNumber, RT_MsgYesNo, nil, PWideChar(Message), nil, 0) then begin LogProc(PluginNumber, msgtype_importanterror, 'Wrong server fingerprint!'); Exit(False); end; FFingerprint:= F; end; //* check what authentication methods are available */ userauthlist := libssh2_userauth_list(FSession, PAnsiChar(FUserName), Length(FUserName)); DoStatus(False, 'Authentication methods: ' + userauthlist); if (libssh2_userauth_authenticated(FSession) <> 0) then begin DoStatus(False, 'Username authentication'); end else if (strpos(userauthlist, 'publickey') <> nil) and (FAgent or ((FPublicKey <> '') and (FPrivateKey <> ''))) then begin if FAgent then begin DoStatus(False, 'SSH-agent authentication'); FLastError:= AuthAgent; end else begin DoStatus(False, 'Public key authentication'); FLastError:= AuthKey; end; if (FLastError < 0) then begin PrintLastError; Exit(False); end; end else if (strpos(userauthlist, 'password') <> nil) then begin DoStatus(False, 'Password authentication'); repeat FLastError := libssh2_userauth_password(FSession, PAnsiChar(FUserName), PAnsiChar(FPassword)); until (FLastError <> LIBSSH2_ERROR_EAGAIN); if FLastError < 0 then begin PrintLastError; Exit(False); end; end else if (strpos(userauthlist, 'keyboard-interactive') <> nil) then begin FSavedPassword:= False; libssh2_session_set_timeout(FSession, 0); DoStatus(False, 'Keyboard interactive authentication'); repeat FLastError := libssh2_userauth_keyboard_interactive(FSession, PAnsiChar(FUserName), @userauth_kbdint); until (FLastError <> LIBSSH2_ERROR_EAGAIN); if FLastError < 0 then begin PrintLastError; Exit(False); end; libssh2_session_set_timeout(FSession, FTimeout); end else begin LogProc(PluginNumber, msgtype_importanterror, 'Authentication failed'); Exit(False); end; DoStatus(False, 'Authentication succeeded'); finally if not Result then begin libssh2_session_free(FSession); FSock.CloseSocket; end; end; end; end; constructor TScpSend.Create(const Encoding: String); begin inherited Create(Encoding); FTargetPort:= '22'; FListCommand:= 'ls -la'; FErrorStream:= TStringBuilder.Create; end; destructor TScpSend.Destroy; begin if (Length(FPassphrase) > 0) then begin if (StringRefCount(FPassphrase) = 1) then begin FillChar(FPassphrase[1], Length(FPassphrase), 0); SetLength(FPassphrase, 0); end; end; inherited Destroy; FErrorStream.Free end; function TScpSend.Login: Boolean; var ACommand: String; begin Result:= Connect; if Result then begin if FAuto then DetectEncoding; if (Length(FCurrentDir) = 0) then begin if not SendCommand('pwd', FAnswer) then FCurrentDir:= '/' else begin FCurrentDir:= TrimRightLineEnding(FAnswer, tlbsLF); FCurrentDir:= CeUtf16ToUtf8(ServerToClient(FCurrentDir)); end; DoStatus(False, 'Remote directory: ' + FCurrentDir); end; if not FAutoDetect then begin FAutoDetect:= True; // Try to use custom time style ACommand:= LIST_LOCALE_C + FListCommand + LIST_TIME_STYLE; if SendCommand(ACommand + ' > /dev/null', FAnswer, False) then begin FListCommand:= ACommand; FFtpList.Masks.Insert(0, 'pppppppppp $!!!S* YYYY MM DD hh mm ss $n*'); end else begin // Try to use 'C' locale ACommand:= LIST_LOCALE_C + FListCommand; if SendCommand(ACommand + ' > /dev/null', FAnswer, False) then begin FListCommand:= ACommand end; end; end; end; end; function TScpSend.Logout: Boolean; begin Result:= libssh2_session_disconnect(FSession, 'Logout') = 0; libssh2_session_free(FSession); FSock.CloseSocket; end; function TScpSend.GetCurrentDir: String; begin Result:= FCurrentDir; end; function TScpSend.NetworkError: Boolean; begin Result:= FSock.CanRead(0) and (libssh2_session_last_errno(FSession) <> 0); end; procedure TScpSend.CloneTo(AValue: TFTPSendEx); begin inherited CloneTo(AValue); TScpSend(AValue).FAgent:= FAgent; TScpSend(AValue).FPassphrase:= FPassphrase; TScpSend(AValue).FFingerprint:= FFingerprint; end; function TScpSend.FileSize(const FileName: String): Int64; begin Result:= -1; end; function TScpSend.FileExists(const FileName: String): Boolean; begin Result:= SendCommand('stat ' + EscapeNoQuotes(FileName), FAnswer, False); end; function TScpSend.CreateDir(const Directory: string): Boolean; begin Result:= SendCommand('mkdir ' + EscapeNoQuotes(Directory), FAnswer); end; function TScpSend.DeleteDir(const Directory: string): Boolean; begin Result:= SendCommand('rmdir ' + EscapeNoQuotes(Directory), FAnswer); end; function TScpSend.DeleteFile(const FileName: string): Boolean; begin Result:= SendCommand('rm -f ' + EscapeNoQuotes(FileName), FAnswer); end; function TScpSend.ExecuteCommand(const Command, Directory: String): Boolean; var Index: Integer; ADirectory: String; Answer: TStringList; begin FDataStream.Clear; Result:= OpenChannel; if Result then begin if Directory = EmptyStr then ADirectory:= FCurrentDir else begin ADirectory:= Directory; end; DoStatus(False, Command); Result:= SendCommand('cd ' + EscapeNoQuotes(ADirectory) + ' && ' + Command); if Result then begin if DataRead(FDataStream) then begin FDataStream.Position:= 0; Answer:= TStringList.Create; try Answer.LoadFromStream(FDataStream); for Index:= 0 to Answer.Count - 1 do DoStatus(True, Answer.Strings[Index]); finally Answer.Free; end; end; FDataStream.Clear; end; CloseChannel(FChannel); end; end; function TScpSend.FileProperties(const FileName: String): Boolean; begin Result:= SendCommand('stat ' + EscapeNoQuotes(FileName), FAnswer); if Result then FFullResult.Text:= FAnswer; end; function TScpSend.CopyFile(const OldName, NewName: String): Boolean; begin Result:= SendCommand('cp -p ' + EscapeNoQuotes(OldName) + ' ' + EscapeNoQuotes(NewName), FAnswer); end; function TScpSend.ChangeWorkingDir(const Directory: string): Boolean; begin Result:= SendCommand('cd ' + EscapeNoQuotes(Directory), FAnswer); if Result then FCurrentDir:= Directory; end; function TScpSend.RenameFile(const OldName, NewName: string): Boolean; begin Result:= SendCommand('mv ' + EscapeNoQuotes(OldName) + ' ' + EscapeNoQuotes(NewName), FAnswer); end; function TScpSend.ChangeMode(const FileName, Mode: String): Boolean; begin Result:= SendCommand('chmod ' + Mode + ' ' + EscapeNoQuotes(FileName), FAnswer); end; function TScpSend.StoreFile(const FileName: string; Restore: Boolean): Boolean; var Index: PtrInt; FBuffer: PByte; FileSize: Int64; BytesRead: Integer; BytesToRead: Integer; BytesWritten: PtrInt; BytesToWrite: Integer; SendStream: TFileStreamEx; TotalBytesToWrite: Int64 = 0; TargetHandle: PLIBSSH2_CHANNEL = nil; begin SendStream := TFileStreamEx.Create(FDirectFileName, fmOpenRead or fmShareDenyWrite); TargetName:= PWideChar(ServerToClient(FileName)); SourceName:= PWideChar(CeUtf8ToUtf16(FDirectFileName)); FileSize:= SendStream.Size; FBuffer:= GetMem(SMB_BUFFER_SIZE); libssh2_session_set_blocking(FSession, 0); try TotalBytesToWrite:= FileSize; // Open remote file repeat TargetHandle:= libssh2_scp_send64(FSession, PAnsiChar(FileName), $1A0, FileSize, 0, 0); if (TargetHandle = nil) then begin FLastError:= libssh2_session_last_errno(FSession); if (FLastError <> LIBSSH2_ERROR_EAGAIN) then Exit(False); if (FileSize > 0) then DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize); FSock.CanRead(10); end; until not ((TargetHandle = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN)); BytesToRead:= SMB_BUFFER_SIZE; while (TotalBytesToWrite > 0) do begin if (BytesToRead > TotalBytesToWrite) then begin BytesToRead:= TotalBytesToWrite; end; BytesRead:= SendStream.Read(FBuffer^, BytesToRead); if (BytesRead = 0) then Exit(False); // Start write operation Index:= 0; BytesToWrite:= BytesRead; while (BytesToWrite > 0) do begin repeat BytesWritten:= libssh2_channel_write(TargetHandle, PAnsiChar(FBuffer + Index), BytesToWrite); if BytesWritten = LIBSSH2_ERROR_EAGAIN then begin DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize); FSock.CanRead(10); end; until BytesWritten <> LIBSSH2_ERROR_EAGAIN; if (BytesWritten < 0) then Exit(False); Dec(TotalBytesToWrite, BytesWritten); Dec(BytesToWrite, BytesWritten); Inc(Index, BytesWritten); end; DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize); end; // Close remote file repeat FLastError:= libssh2_channel_send_eof(TargetHandle); DoProgress(100); FSock.CanRead(10); until FLastError <> LIBSSH2_ERROR_EAGAIN; Result:= (FLastError = 0); finally SendStream.Free; FreeMem(FBuffer); Result:= CloseChannel(TargetHandle) and Result; libssh2_session_set_blocking(FSession, 1); end; end; function TScpSend.RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; var FBuffer: PByte; BytesRead: PtrInt; BytesToRead: Integer; RetrStream: TFileStreamEx; TotalBytesToRead: Int64 = 0; SourceHandle: PLIBSSH2_CHANNEL; begin RetrStream := TFileStreamEx.Create(FDirectFileName, fmCreate or fmShareDenyWrite); SourceName := PWideChar(ServerToClient(FileName)); TargetName := PWideChar(CeUtf8ToUtf16(FDirectFileName)); libssh2_session_set_blocking(FSession, 0); try repeat SourceHandle:= libssh2_scp_recv2(FSession, PAnsiChar(FileName), nil); if (SourceHandle = nil) then begin FLastError:= libssh2_session_last_errno(FSession); if (FLastError <> LIBSSH2_ERROR_EAGAIN) then Exit(False); if (FileSize > 0) then DoProgress(TotalBytesToRead * 100 div FileSize); FSock.CanRead(10); end; until not ((SourceHandle = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN)); FBuffer:= GetMem(SMB_BUFFER_SIZE); TotalBytesToRead:= FileSize - TotalBytesToRead; try BytesToRead:= SMB_BUFFER_SIZE; while TotalBytesToRead > 0 do begin if (BytesToRead > TotalBytesToRead) then begin BytesToRead := TotalBytesToRead; end; repeat BytesRead := libssh2_channel_read(SourceHandle, PAnsiChar(FBuffer), BytesToRead); if BytesRead = LIBSSH2_ERROR_EAGAIN then begin DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize); FSock.CanRead(10); end; until BytesRead <> LIBSSH2_ERROR_EAGAIN; if (BytesRead < 0) then Exit(False); if RetrStream.Write(FBuffer^, BytesRead) <> BytesRead then Exit(False); Dec(TotalBytesToRead, BytesRead); DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize); end; Result:= True; finally FreeMem(FBuffer); Result:= CloseChannel(SourceHandle) and Result; end; finally RetrStream.Free; libssh2_session_set_blocking(FSession, 1); end; end; function TScpSend.DataRead(const DestStream: TStream): Boolean; var Ret: cint; Buffer: String; begin FErrorStream.Clear; SetLength(Buffer, TXT_BUFFER_SIZE + 1); while libssh2_channel_eof(FChannel) = 0 do begin repeat Ret:= libssh2_channel_read_stderr(FChannel, Pointer(Buffer), TXT_BUFFER_SIZE); until Ret <> LIBSSH2_ERROR_EAGAIN; if Ret > 0 then FErrorStream.Append(Copy(Buffer, 1, Ret)); repeat Ret:= libssh2_channel_read(FChannel, Pointer(Buffer), TXT_BUFFER_SIZE); until Ret <> LIBSSH2_ERROR_EAGAIN; if Ret > 0 then DestStream.Write(Buffer[1], Ret); end; if (FErrorStream.Length > 0) then begin PrintErrors(FErrorStream.ToString); end; Result:= DestStream.Position > 0; end; function TScpSend.List(Directory: String; NameList: Boolean): Boolean; begin FFTPList.Clear; FDataStream.Clear; Result:= OpenChannel; if Result then begin if Directory <> '' then begin Directory := ' ' + EscapeNoQuotes(Directory); end; Result:= SendCommand(FListCommand + Directory); if Result then begin Result:= DataRead(FDataStream); if Result then begin FDataStream.Position := 0; FFTPList.Lines.LoadFromStream(FDataStream); FFTPList.ParseLines; end; FDataStream.Position := 0; end; CloseChannel(FChannel); end; end; function TScpSend.FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PWfxFileTime): BOOL; var DateTime: String; FileTime: TDateTime; begin if (LastWriteTime = nil) then Exit(False); FileTime:= WinFileTimeToDateTime(TWinFileTime(LastWriteTime^)); DateTime:= FormatDateTime('yyyymmddhhnn.ss', FileTime); Result:= SendCommand('touch -ct ' + DateTime + ' ' + EscapeNoQuotes(FileName), FAnswer); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/src/sftp/sftpsend.pas����������������������������������������������0000644�0001750�0000144�00000035655�14743153644�022000� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Wfx plugin for working with File Transfer Protocol Copyright (C) 2013-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SftpSend; {$mode delphi} {$pointermath on} interface uses Classes, SysUtils, WfxPlugin, ftpsend, ScpSend, libssh, FtpAdv; type { TSftpSend } TSftpSend = class(TScpSend) private function FileClose(Handle: Pointer): Boolean; protected FCopySCP: Boolean; FSFTPSession: PLIBSSH2_SFTP; protected function Connect: Boolean; override; public constructor Create(const Encoding: String); override; function Login: Boolean; override; function Logout: Boolean; override; function GetCurrentDir: String; override; function FileSize(const FileName: String): Int64; override; function CreateDir(const Directory: string): Boolean; override; function DeleteDir(const Directory: string): Boolean; override; function DeleteFile(const FileName: string): Boolean; override; function ChangeWorkingDir(const Directory: string): Boolean; override; function RenameFile(const OldName, NewName: string): Boolean; override; function ChangeMode(const FileName, Mode: String): Boolean; override; function StoreFile(const FileName: string; Restore: Boolean): Boolean; override; function RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; override; public function FsFindFirstW(const Path: String; var FindData: TWin32FindDataW): Pointer; override; function FsFindNextW(Handle: Pointer; var FindData: TWin32FindDataW): BOOL; override; function FsFindClose(Handle: Pointer): Integer; override; function FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PFileTime): BOOL; override; public property CopySCP: Boolean read FCopySCP write FCopySCP; end; implementation uses LazUTF8, DCBasicTypes, DCDateTimeUtils, DCStrUtils, DCOSUtils, FtpFunc, CTypes, DCClassesUtf8, DCFileAttributes, DCConvertEncoding; const SMB_BUFFER_SIZE = 131072; type PFindRec = ^TFindRec; TFindRec = record Path: String; Handle: PLIBSSH2_SFTP_HANDLE; end; { TSftpSend } function TSftpSend.FileClose(Handle: Pointer): Boolean; begin FLastError:= 0; if Assigned(Handle) then repeat FLastError:= libssh2_sftp_close(Handle); DoProgress(100); FSock.CanRead(10); until FLastError <> LIBSSH2_ERROR_EAGAIN; Result:= (FLastError = 0); end; function TSftpSend.Connect: Boolean; begin Result:= inherited Connect; if Result then begin FSFTPSession := libssh2_sftp_init(FSession); Result:= Assigned(FSFTPSession); if not Result then begin libssh2_session_free(FSession); FSock.CloseSocket; end; end; end; constructor TSftpSend.Create(const Encoding: String); begin inherited Create(Encoding); FCanResume := True; end; function TSftpSend.Login: Boolean; var Return: Integer; begin Result:= Connect; if Result then begin if FAuto then DetectEncoding; if (Length(FCurrentDir) = 0) then begin SetLength(FCurrentDir, MAX_PATH + 1); Return:= libssh2_sftp_realpath(FSFTPSession, '.', PAnsiChar(FCurrentDir), MAX_PATH); if Return < 1 then FCurrentDir:= '/' else begin SetLength(FCurrentDir, Return); FCurrentDir:= CeUtf16ToUtf8(ServerToClient(FCurrentDir)); end; DoStatus(False, 'Remote directory: ' + FCurrentDir); end; end; end; function TSftpSend.Logout: Boolean; begin Result:= libssh2_sftp_shutdown(FSFTPSession) = 0; Result:= Result and inherited Logout; end; function TSftpSend.GetCurrentDir: String; begin Result:= FCurrentDir; end; function TSftpSend.FileSize(const FileName: String): Int64; var Attributes: LIBSSH2_SFTP_ATTRIBUTES; begin repeat FLastError:= libssh2_sftp_stat(FSFTPSession, PAnsiChar(FileName), @Attributes); if (FLastError = 0) then Exit(Attributes.filesize); FSock.CanRead(10); DoProgress(0); until FLastError <> LIBSSH2_ERROR_EAGAIN; Result:= -1; end; function TSftpSend.CreateDir(const Directory: string): Boolean; var Return: Integer; Attributes: LIBSSH2_SFTP_ATTRIBUTES; begin Return:= libssh2_sftp_mkdir(FSFTPSession, PAnsiChar(Directory), LIBSSH2_SFTP_S_IRWXU or LIBSSH2_SFTP_S_IRGRP or LIBSSH2_SFTP_S_IXGRP or LIBSSH2_SFTP_S_IROTH or LIBSSH2_SFTP_S_IXOTH); if (Return <> 0) then begin Return:= libssh2_sftp_stat(FSFTPSession, PAnsiChar(Directory), @Attributes); end; Result:= (Return = 0); end; function TSftpSend.DeleteDir(const Directory: string): Boolean; begin Result:= libssh2_sftp_rmdir(FSFTPSession, PAnsiChar(Directory)) = 0; end; function TSftpSend.DeleteFile(const FileName: string): Boolean; begin Result:= libssh2_sftp_unlink(FSFTPSession, PAnsiChar(FileName)) = 0; end; function TSftpSend.ChangeWorkingDir(const Directory: string): Boolean; var Attributes: LIBSSH2_SFTP_ATTRIBUTES; begin Result:= libssh2_sftp_stat(FSFTPSession, PAnsiChar(Directory), @Attributes) = 0; if Result then FCurrentDir:= Directory; end; function TSftpSend.RenameFile(const OldName, NewName: string): Boolean; begin Result:= libssh2_sftp_rename(FSFTPSession, PAnsiChar(OldName), PAnsiChar(NewName)) = 0; end; function TSftpSend.ChangeMode(const FileName, Mode: String): Boolean; var Attributes: LIBSSH2_SFTP_ATTRIBUTES; begin Attributes.permissions:= OctToDec(Mode); Attributes.flags:= LIBSSH2_SFTP_ATTR_PERMISSIONS; Result:= libssh2_sftp_setstat(FSFTPSession, PAnsiChar(FileName), @Attributes) = 0; end; function TSftpSend.StoreFile(const FileName: string; Restore: Boolean): Boolean; var Index: PtrInt; FBuffer: PByte; FileSize: Int64; BytesRead: Integer; BytesToRead: Integer; BytesWritten: PtrInt; BytesToWrite: Integer; SendStream: TFileStreamEx; TotalBytesToWrite: Int64 = 0; TargetHandle: PLIBSSH2_SFTP_HANDLE = nil; Flags: cint = LIBSSH2_FXF_CREAT or LIBSSH2_FXF_WRITE; begin if FCopySCP then begin Result:= inherited StoreFile(FileName, Restore); Exit; end; SendStream := TFileStreamEx.Create(FDirectFileName, fmOpenRead or fmShareDenyWrite); TargetName:= PWideChar(ServerToClient(FileName)); SourceName:= PWideChar(CeUtf8ToUtf16(FDirectFileName)); FileSize:= SendStream.Size; FBuffer:= GetMem(SMB_BUFFER_SIZE); libssh2_session_set_blocking(FSession, 0); try if not Restore then begin TotalBytesToWrite:= FileSize; Flags:= Flags or LIBSSH2_FXF_TRUNC end else begin TotalBytesToWrite:= Self.FileSize(FileName); if (FileSize = TotalBytesToWrite) then Exit(True); if TotalBytesToWrite < 0 then TotalBytesToWrite:= 0; SendStream.Seek(TotalBytesToWrite, soBeginning); TotalBytesToWrite := FileSize - TotalBytesToWrite; Flags:= Flags or LIBSSH2_FXF_APPEND; end; // Open remote file repeat TargetHandle:= libssh2_sftp_open(FSFTPSession, PAnsiChar(FileName), Flags, $1A0); if (TargetHandle = nil) then begin FLastError:= libssh2_session_last_errno(FSession); if (FLastError <> LIBSSH2_ERROR_EAGAIN) then Exit(False); if (FileSize > 0) then DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize); FSock.CanRead(10); end; until not ((TargetHandle = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN)); BytesToRead:= SMB_BUFFER_SIZE; while (TotalBytesToWrite > 0) do begin if (BytesToRead > TotalBytesToWrite) then begin BytesToRead:= TotalBytesToWrite; end; BytesRead:= SendStream.Read(FBuffer^, BytesToRead); if (BytesRead = 0) then Exit(False); // Start write operation Index:= 0; BytesToWrite:= BytesRead; while (BytesToWrite > 0) do begin repeat BytesWritten:= libssh2_sftp_write(TargetHandle, FBuffer + Index, BytesToWrite); if BytesWritten = LIBSSH2_ERROR_EAGAIN then begin DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize); FSock.CanRead(10); end; until BytesWritten <> LIBSSH2_ERROR_EAGAIN; if (BytesWritten < 0) then Exit(False); Dec(TotalBytesToWrite, BytesWritten); Dec(BytesToWrite, BytesWritten); Inc(Index, BytesWritten); end; DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize); end; Result:= True; finally SendStream.Free; FreeMem(FBuffer); Result:= FileClose(TargetHandle) and Result; libssh2_session_set_blocking(FSession, 1); end; end; function TSftpSend.RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; var FBuffer: PByte; BytesRead: PtrInt; RetrStream: TFileStreamEx; TotalBytesToRead: Int64 = 0; SourceHandle: PLIBSSH2_SFTP_HANDLE; begin if FCopySCP then begin Result:= inherited RetrieveFile(FileName, FileSize, Restore); Exit; end; if Restore and mbFileExists(FDirectFileName) then RetrStream := TFileStreamEx.Create(FDirectFileName, fmOpenWrite or fmShareExclusive) else begin RetrStream := TFileStreamEx.Create(FDirectFileName, fmCreate or fmShareDenyWrite) end; SourceName := PWideChar(ServerToClient(FileName)); TargetName := PWideChar(CeUtf8ToUtf16(FDirectFileName)); if Restore then TotalBytesToRead:= RetrStream.Seek(0, soEnd); libssh2_session_set_blocking(FSession, 0); try repeat SourceHandle:= libssh2_sftp_open(FSFTPSession, PAnsiChar(FileName), LIBSSH2_FXF_READ, 0); if (SourceHandle = nil) then begin FLastError:= libssh2_session_last_errno(FSession); if (FLastError <> LIBSSH2_ERROR_EAGAIN) then Exit(False); if (FileSize > 0) then DoProgress(TotalBytesToRead * 100 div FileSize); FSock.CanRead(10); end; until not ((SourceHandle = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN)); if Restore then begin libssh2_sftp_seek64(SourceHandle, TotalBytesToRead); end; FBuffer:= GetMem(SMB_BUFFER_SIZE); TotalBytesToRead:= FileSize - TotalBytesToRead; try while TotalBytesToRead > 0 do begin repeat BytesRead := libssh2_sftp_read(SourceHandle, PAnsiChar(FBuffer), SMB_BUFFER_SIZE); if BytesRead = LIBSSH2_ERROR_EAGAIN then begin DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize); FSock.CanRead(10); end; until BytesRead <> LIBSSH2_ERROR_EAGAIN; if (BytesRead < 0) then Exit(False); if RetrStream.Write(FBuffer^, BytesRead) <> BytesRead then Exit(False); Dec(TotalBytesToRead, BytesRead); DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize); end; Result:= True; finally FreeMem(FBuffer); Result:= FileClose(SourceHandle) and Result; end; finally RetrStream.Free; libssh2_session_set_blocking(FSession, 1); end; end; function TSftpSend.FsFindFirstW(const Path: String; var FindData: TWin32FindDataW): Pointer; var FindRec: PFindRec; begin Result := libssh2_sftp_opendir(FSFTPSession, PAnsiChar(Path)); if (Result = nil) then PrintLastError else begin New(FindRec); FindRec.Path:= Path; FindRec.Handle:= Result; FsFindNextW(FindRec, FindData); Result:= FindRec; end; end; function TSftpSend.FsFindNextW(Handle: Pointer; var FindData: TWin32FindDataW): BOOL; var Return: Integer; FindRec: PFindRec absolute Handle; Attributes: LIBSSH2_SFTP_ATTRIBUTES; AFileName: array[0..1023] of AnsiChar; AFullData: array[0..2047] of AnsiChar; begin Return:= libssh2_sftp_readdir_ex(FindRec.Handle, AFileName, SizeOf(AFileName), AFullData, SizeOf(AFullData), @Attributes); Result:= (Return > 0); if Result then begin FillChar(FindData, SizeOf(FindData), 0); FindData.dwReserved0:= Attributes.permissions; FindData.dwFileAttributes:= FILE_ATTRIBUTE_UNIX_MODE; if (Attributes.permissions and S_IFMT) <> S_IFDIR then begin FindData.nFileSizeLow:= Int64Rec(Attributes.filesize).Lo; FindData.nFileSizeHigh:= Int64Rec(Attributes.filesize).Hi; end; StrPLCopy(FindData.cFileName, ServerToClient(AFileName), MAX_PATH - 1); FindData.ftLastWriteTime:= TWfxFileTime(UnixFileTimeToWinTime(Attributes.mtime)); FindData.ftLastAccessTime:= TWfxFileTime(UnixFileTimeToWinTime(Attributes.atime)); if (Attributes.permissions and S_IFMT) = S_IFLNK then begin if libssh2_sftp_stat(FSFTPSession, PAnsiChar(FindRec.Path + AFileName), @Attributes) = 0 then begin if (Attributes.permissions and S_IFMT) = S_IFDIR then begin FindData.nFileSizeLow:= 0; FindData.nFileSizeHigh:= 0; FindData.dwFileAttributes:= FindData.dwFileAttributes or FILE_ATTRIBUTE_REPARSE_POINT; end; end; end; end; end; function TSftpSend.FsFindClose(Handle: Pointer): Integer; var FindRec: PFindRec absolute Handle; begin Result:= libssh2_sftp_closedir(FindRec.Handle); Dispose(FindRec); end; function TSftpSend.FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: WfxPlugin.PFileTime): BOOL; var Attributes: LIBSSH2_SFTP_ATTRIBUTES; begin if (LastAccessTime = nil) or (LastWriteTime = nil) then begin if libssh2_sftp_stat(FSFTPSession, PAnsiChar(FileName), @Attributes) <> 0 then Exit(False); end; if Assigned(LastAccessTime) then begin Attributes.atime:= WinFileTimeToUnixTime(TWinFileTime(LastAccessTime^)); end; if Assigned(LastWriteTime) then begin Attributes.mtime:= WinFileTimeToUnixTime(TWinFileTime(LastWriteTime^)); end; Attributes.flags:= LIBSSH2_SFTP_ATTR_ACMODTIME; Result:= libssh2_sftp_setstat(FSFTPSession, PAnsiChar(FileName), @Attributes) = 0; end; end. �����������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017346� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/blcksock.pas�����������������������������������������������0000644�0001750�0000144�00000400461�14743153644�021653� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 009.010.002 | |==============================================================================| | Content: Library base | |==============================================================================| | Copyright (c)1999-2021, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)1999-2021. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} { Special thanks to Gregor Ibic <gregor.ibic@intelicom.si> (Intelicom d.o.o., http://www.intelicom.si) for good inspiration about SSL programming. } {$DEFINE ONCEWINSOCK} {Note about define ONCEWINSOCK: If you remove this compiler directive, then socket interface is loaded and initialized on constructor of TBlockSocket class for each socket separately. Socket interface is used only if your need it. If you leave this directive here, then socket interface is loaded and initialized only once at start of your program! It boost performace on high count of created and destroyed sockets. It eliminate possible small resource leak on Windows systems too. } //{$DEFINE RAISEEXCEPT} {When you enable this define, then is Raiseexcept property is on by default } {:@abstract(Synapse's library core) Core with implementation basic socket classes. } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$IFDEF VER125} {$DEFINE BCB} {$ENDIF} {$IFDEF BCB} {$ObjExportAll On} {$ENDIF} {$Q-} {$H+} {$M+} {$TYPEDADDRESS OFF} //old Delphi does not have MSWINDOWS define. {$IFDEF WIN32} {$IFNDEF MSWINDOWS} {$DEFINE MSWINDOWS} {$ENDIF} {$ENDIF} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} {$IFDEF NEXTGEN} {$ZEROBASEDSTRINGS OFF} {$ENDIF} unit blcksock; interface uses SysUtils, Classes, synafpc, synsock, synautil, synacode, synaip {$IFDEF POSIX} ,System.Generics.Collections, System.Generics.Defaults {$ENDIF} {$IfDef CIL} ,System.Net ,System.Net.Sockets ,System.Text {$EndIf} ; const SynapseRelease = '40'; cLocalhost = '127.0.0.1'; cAnyHost = '0.0.0.0'; cBroadcast = '255.255.255.255'; c6Localhost = '::1'; c6AnyHost = '::0'; c6Broadcast = 'ffff::1'; cAnyPort = '0'; CR = #$0d; LF = #$0a; CRLF = CR + LF; c64k = 65536; type {:@abstract(Exception clas used by Synapse) When you enable generating of exceptions, this exception is raised by Synapse's units.} ESynapseError = class(Exception) private FErrorCode: Integer; FErrorMessage: string; published {:Code of error. Value depending on used operating system} property ErrorCode: Integer read FErrorCode Write FErrorCode; {:Human readable description of error.} property ErrorMessage: string read FErrorMessage Write FErrorMessage; end; {:Types of OnStatus events} THookSocketReason = ( {:Resolving is begin. Resolved IP and port is in parameter in format like: 'localhost.somewhere.com:25'.} HR_ResolvingBegin, {:Resolving is done. Resolved IP and port is in parameter in format like: 'localhost.somewhere.com:25'. It is always same as in HR_ResolvingBegin!} HR_ResolvingEnd, {:Socket created by CreateSocket method. It reporting Family of created socket too!} HR_SocketCreate, {:Socket closed by CloseSocket method.} HR_SocketClose, {:Socket binded to IP and Port. Binded IP and Port is in parameter in format like: 'localhost.somewhere.com:25'.} HR_Bind, {:Socket connected to IP and Port. Connected IP and Port is in parameter in format like: 'localhost.somewhere.com:25'.} HR_Connect, {:Called when CanRead method is used with @True result.} HR_CanRead, {:Called when CanWrite method is used with @True result.} HR_CanWrite, {:Socket is swithed to Listen mode. (TCP socket only)} HR_Listen, {:Socket Accepting client connection. (TCP socket only)} HR_Accept, {:report count of bytes readed from socket. Number is in parameter string. If you need is in integer, you must use StrToInt function!} HR_ReadCount, {:report count of bytes writed to socket. Number is in parameter string. If you need is in integer, you must use StrToInt function!} HR_WriteCount, {:If is limiting of bandwidth on, then this reason is called when sending or receiving is stopped for satisfy bandwidth limit. Parameter is count of waiting milliseconds.} HR_Wait, {:report situation where communication error occured. When raiseexcept is @true, then exception is called after this Hook reason.} HR_Error ); {:Procedural type for OnStatus event. Sender is calling TBlockSocket object, Reason is one of set Status events and value is optional data.} THookSocketStatus = procedure(Sender: TObject; Reason: THookSocketReason; const Value: String) of object; {:This procedural type is used for DataFilter hooks.} THookDataFilter = procedure(Sender: TObject; var Value: AnsiString) of object; {:This procedural type is used for hook OnCreateSocket. By this hook you can insert your code after initialisation of socket. (you can set special socket options, etc.)} THookCreateSocket = procedure(Sender: TObject) of object; {:This procedural type is used for monitoring of communication.} THookMonitor = procedure(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer) of object; {:This procedural type is used for hook OnAfterConnect. By this hook you can insert your code after TCP socket has been sucessfully connected.} THookAfterConnect = procedure(Sender: TObject) of object; {:This procedural type is used for hook OnVerifyCert. By this hook you can insert your additional certificate verification code. Usefull to verify server CN against URL. } THookVerifyCert = function(Sender: TObject):boolean of object; {:This procedural type is used for hook OnHeartbeat. By this hook you can call your code repeately during long socket operations. You must enable heartbeats by @Link(HeartbeatRate) property!} THookHeartbeat = procedure(Sender: TObject) of object; {:Specify family of socket.} TSocketFamily = ( {:Default mode. Socket family is defined by target address for connection. It allows instant access to IPv4 and IPv6 nodes. When you need IPv6 address as destination, then is used IPv6 mode. othervise is used IPv4 mode. However this mode not working properly with preliminary IPv6 supports!} SF_Any, {:Turn this class to pure IPv4 mode. This mode is totally compatible with previous Synapse releases.} SF_IP4, {:Turn to only IPv6 mode.} SF_IP6 ); {:specify possible values of SOCKS modes.} TSocksType = ( ST_Socks5, ST_Socks4 ); {:Specify requested SSL/TLS version for secure connection.} TSSLType = ( LT_all, LT_SSLv2, LT_SSLv3, LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2, LT_TLSv1_3, LT_SSHv2 ); {:Specify type of socket delayed option.} TSynaOptionType = ( SOT_Linger, SOT_RecvBuff, SOT_SendBuff, SOT_NonBlock, SOT_RecvTimeout, SOT_SendTimeout, SOT_Reuse, SOT_TTL, SOT_Broadcast, SOT_MulticastTTL, SOT_MulticastLoop ); {:@abstract(this object is used for remember delayed socket option set.)} TSynaOption = class(TObject) public Option: TSynaOptionType; Enabled: Boolean; Value: Integer; end; TCustomSSL = class; TSSLClass = class of TCustomSSL; TBlockSocket = class; {$IFDEF POSIX} TOptionList = TList<TSynaOption>; TSocketList = TList<TBlockSocket>; {$ELSE} TOptionList = TList; TSocketList = TList; {$ENDIF} {:@abstract(Basic IP object.) This is parent class for other class with protocol implementations. Do not use this class directly! Use @link(TICMPBlockSocket), @link(TRAWBlockSocket), @link(TTCPBlockSocket) or @link(TUDPBlockSocket) instead.} TBlockSocket = class(TObject) private FOnStatus: THookSocketStatus; FOnReadFilter: THookDataFilter; FOnCreateSocket: THookCreateSocket; FOnMonitor: THookMonitor; FOnHeartbeat: THookHeartbeat; FLocalSin: TVarSin; FRemoteSin: TVarSin; FTag: integer; FBuffer: AnsiString; FRaiseExcept: Boolean; FNonBlockMode: Boolean; FMaxLineLength: Integer; FMaxSendBandwidth: Integer; FNextSend: LongWord; FMaxRecvBandwidth: Integer; FNextRecv: LongWord; FConvertLineEnd: Boolean; FLastCR: Boolean; FLastLF: Boolean; FBinded: Boolean; FFamily: TSocketFamily; FFamilySave: TSocketFamily; FIP6used: Boolean; FPreferIP4: Boolean; FDelayedOptions: TOptionList; FInterPacketTimeout: Boolean; {$IFNDEF CIL} FFDSet: TFDSet; {$ENDIF} FRecvCounter: int64; FSendCounter: int64; FSendMaxChunk: Integer; FStopFlag: Boolean; FNonblockSendTimeout: Integer; FHeartbeatRate: integer; FConnectionTimeout: integer; {$IFNDEF ONCEWINSOCK} FWsaDataOnce: TWSADATA; {$ENDIF} function GetSizeRecvBuffer: Integer; procedure SetSizeRecvBuffer(Size: Integer); function GetSizeSendBuffer: Integer; procedure SetSizeSendBuffer(Size: Integer); procedure SetNonBlockMode(Value: Boolean); procedure SetTTL(TTL: integer); function GetTTL:integer; procedure SetFamily(Value: TSocketFamily); virtual; procedure SetSocket(Value: TSocket); virtual; function GetWsaData: TWSAData; function FamilyToAF(f: TSocketFamily): TAddrFamily; protected FSocket: TSocket; FLastError: Integer; FLastErrorDesc: string; FOwner: TObject; procedure SetDelayedOption(const Value: TSynaOption); procedure DelayedOption(const Value: TSynaOption); procedure ProcessDelayedOptions; procedure InternalCreateSocket(Sin: TVarSin); procedure SetSin(var Sin: TVarSin; IP, Port: string); function GetSinIP(Sin: TVarSin): string; function GetSinPort(Sin: TVarSin): Integer; procedure DoStatus(Reason: THookSocketReason; const Value: string); procedure DoReadFilter(Buffer: TMemory; var Len: Integer); procedure DoMonitor(Writing: Boolean; const Buffer: TMemory; Len: Integer); procedure DoCreateSocket; procedure DoHeartbeat; procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); procedure SetBandwidth(Value: Integer); function TestStopFlag: Boolean; procedure InternalSendStream(const Stream: TStream; WithSize, Indy: boolean); virtual; function InternalCanRead(Timeout: Integer): Boolean; virtual; function InternalCanWrite(Timeout: Integer): Boolean; virtual; public constructor Create; {:Create object and load all necessary socket library. What library is loaded is described by STUB parameter. If STUB is empty string, then is loaded default libraries.} constructor CreateAlternate(Stub: string); destructor Destroy; override; {:If @link(family) is not SF_Any, then create socket with type defined in @link(Family) property. If family is SF_Any, then do nothing! (socket is created automaticly when you know what type of socket you need to create. (i.e. inside @link(Connect) or @link(Bind) call.) When socket is created, then is aplyed all stored delayed socket options.} procedure CreateSocket; {:It create socket. Address resolving of Value tells what type of socket is created. If Value is resolved as IPv4 IP, then is created IPv4 socket. If value is resolved as IPv6 address, then is created IPv6 socket.} procedure CreateSocketByName(const Value: String); {:Destroy socket in use. This method is also automatically called from object destructor.} procedure CloseSocket; virtual; {:Abort any work on Socket and destroy them.} procedure AbortSocket; virtual; {:Connects socket to local IP address and PORT. IP address may be numeric or symbolic ('192.168.74.50', 'cosi.nekde.cz', 'ff08::1'). The same for PORT - it may be number or mnemonic port ('23', 'telnet'). If port value is '0', system chooses itself and conects unused port in the range 1024 to 4096 (this depending by operating system!). Structure LocalSin is filled after calling this method. Note: If you call this on non-created socket, then socket is created automaticly. Warning: when you call : Bind('0.0.0.0','0'); then is nothing done! In this case is used implicit system bind instead.} procedure Bind(const IP, Port: string); {:Connects socket to remote IP address and PORT. The same rules as with @link(BIND) method are valid. The only exception is that PORT with 0 value will not be connected! Structures LocalSin and RemoteSin will be filled with valid values. When you call this on non-created socket, then socket is created automaticly. Type of created socket is by @link(Family) property. If is used SF_IP4, then is created socket for IPv4. If is used SF_IP6, then is created socket for IPv6. When you have family on SF_Any (default!), then type of created socket is determined by address resolving of destination address. (Not work properly on prilimitary winsock IPv6 support!)} procedure Connect(IP, Port: string); virtual; {:Sets socket to receive mode for new incoming connections. It is necessary to use @link(TBlockSocket.BIND) function call before this method to select receiving port!} procedure Listen; virtual; {:Waits until new incoming connection comes. After it comes a new socket is automatically created (socket handler is returned by this function as result).} function Accept: TSocket; virtual; {:Sends data of LENGTH from BUFFER address via connected socket. System automatically splits data to packets.} function SendBuffer(const Buffer: Tmemory; Length: Integer): Integer; virtual; {:One data BYTE is sent via connected socket.} procedure SendByte(Data: Byte); virtual; {:Send data string via connected socket. Any terminator is not added! If you need send true string with CR-LF termination, you must add CR-LF characters to sended string! Because any termination is not added automaticly, you can use this function for sending any binary data in binary string.} procedure SendString(Data: AnsiString); virtual; {:Send integer as four bytes to socket.} procedure SendInteger(Data: integer); virtual; {:Send data as one block to socket. Each block begin with 4 bytes with length of data in block. This 4 bytes is added automaticly by this function.} procedure SendBlock(const Data: AnsiString); virtual; {:Send data from stream to socket.} procedure SendStreamRaw(const Stream: TStream); virtual; {:Send content of stream to socket. It using @link(SendBlock) method} procedure SendStream(const Stream: TStream); virtual; {:Send content of stream to socket. It using @link(SendBlock) method and this is compatible with streams in Indy library.} procedure SendStreamIndy(const Stream: TStream); virtual; {:Note: This is low-level receive function. You must be sure if data is waiting for read before call this function for avoid deadlock! Waits until allocated buffer is filled by received data. Returns number of data received, which equals to LENGTH value under normal operation. If it is not equal the communication channel is possibly broken. On stream oriented sockets if is received 0 bytes, it mean 'socket is closed!" On datagram socket is readed first waiting datagram.} function RecvBuffer(Buffer: TMemory; Length: Integer): Integer; virtual; {:Note: This is high-level receive function. It using internal @link(LineBuffer) and you can combine this function freely with other high-level functions! Method waits until data is received. If no data is received within TIMEOUT (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT. Methods serves for reading any size of data (i.e. one megabyte...). This method is preffered for reading from stream sockets (like TCP).} function RecvBufferEx(Buffer: Tmemory; Len: Integer; Timeout: Integer): Integer; virtual; {:Similar to @link(RecvBufferEx), but readed data is stored in binary string, not in memory buffer.} function RecvBufferStr(Len: Integer; Timeout: Integer): AnsiString; virtual; {:Note: This is high-level receive function. It using internal @link(LineBuffer) and you can combine this function freely with other high-level functions. Waits until one data byte is received which is also returned as function result. If no data is received within TIMEOUT (in milliseconds)period, @link(LastError) is set to WSAETIMEDOUT and result have value 0.} function RecvByte(Timeout: Integer): Byte; virtual; {:Note: This is high-level receive function. It using internal @link(LineBuffer) and you can combine this function freely with other high-level functions. Waits until one four bytes are received and return it as one Ineger Value. If no data is received within TIMEOUT (in milliseconds)period, @link(LastError) is set to WSAETIMEDOUT and result have value 0.} function RecvInteger(Timeout: Integer): Integer; virtual; {:Note: This is high-level receive function. It using internal @link(LineBuffer) and you can combine this function freely with other high-level functions. Method waits until data string is received. This string is terminated by CR-LF characters. The resulting string is returned without this termination (CR-LF)! If @link(ConvertLineEnd) is used, then CR-LF sequence may not be exactly CR-LF. See @link(ConvertLineEnd) description. If no data is received within TIMEOUT (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT. You may also specify maximum length of reading data by @link(MaxLineLength) property.} function RecvString(Timeout: Integer): AnsiString; virtual; {:Note: This is high-level receive function. It using internal @link(LineBuffer) and you can combine this function freely with other high-level functions. Method waits until data string is received. This string is terminated by Terminator string. The resulting string is returned without this termination. If no data is received within TIMEOUT (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT. You may also specify maximum length of reading data by @link(MaxLineLength) property.} function RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; virtual; {:Note: This is high-level receive function. It using internal @link(LineBuffer) and you can combine this function freely with other high-level functions. Method reads all data waiting for read. If no data is received within TIMEOUT (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT. Methods serves for reading unknown size of data. Because before call this function you don't know size of received data, returned data is stored in dynamic size binary string. This method is preffered for reading from stream sockets (like TCP). It is very goot for receiving datagrams too! (UDP protocol)} function RecvPacket(Timeout: Integer): AnsiString; virtual; {:Read one block of data from socket. Each block begin with 4 bytes with length of data in block. This function read first 4 bytes for get lenght, then it wait for reported count of bytes.} function RecvBlock(Timeout: Integer): AnsiString; virtual; {:Read all data from socket to stream until socket is closed (or any error occured.)} procedure RecvStreamRaw(const Stream: TStream; Timeout: Integer); virtual; {:Read requested count of bytes from socket to stream.} procedure RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: int64); {:Receive data to stream. It using @link(RecvBlock) method.} procedure RecvStream(const Stream: TStream; Timeout: Integer); virtual; {:Receive data to stream. This function is compatible with similar function in Indy library. It using @link(RecvBlock) method.} procedure RecvStreamIndy(const Stream: TStream; Timeout: Integer); virtual; {:Same as @link(RecvBuffer), but readed data stays in system input buffer. Warning: this function not respect data in @link(LineBuffer)! Is not recommended to use this function!} function PeekBuffer(Buffer: TMemory; Length: Integer): Integer; virtual; {:Same as @link(RecvByte), but readed data stays in input system buffer. Warning: this function not respect data in @link(LineBuffer)! Is not recommended to use this function!} function PeekByte(Timeout: Integer): Byte; virtual; {:On stream sockets it returns number of received bytes waiting for picking. 0 is returned when there is no such data. On datagram socket it returns length of the first waiting datagram. Returns 0 if no datagram is waiting.} function WaitingData: Integer; virtual; {:Same as @link(WaitingData), but if exists some of data in @link(Linebuffer), return their length instead.} function WaitingDataEx: Integer; {:Clear all waiting data for read from buffers.} procedure Purge; {:Sets linger. Enabled linger means that the system waits another LINGER (in milliseconds) time for delivery of sent data. This function is only for stream type of socket! (TCP)} procedure SetLinger(Enable: Boolean; Linger: Integer); {:Actualize values in @link(LocalSin).} procedure GetSinLocal; {:Actualize values in @link(RemoteSin).} procedure GetSinRemote; {:Actualize values in @link(LocalSin) and @link(RemoteSin).} procedure GetSins; {:Reset @link(LastError) and @link(LastErrorDesc) to non-error state.} procedure ResetLastError; {:If you "manually" call Socket API functions, forward their return code as parameter to this function, which evaluates it, eventually calls GetLastError and found error code returns and stores to @link(LastError).} function SockCheck(SockResult: Integer): Integer; virtual; {:If @link(LastError) contains some error code and @link(RaiseExcept) property is @true, raise adequate exception.} procedure ExceptCheck; {:Returns local computer name as numerical or symbolic value. It try get fully qualified domain name. Name is returned in the format acceptable by functions demanding IP as input parameter.} function LocalName: string; {:Try resolve name to all possible IP address. i.e. If you pass as name result of @link(LocalName) method, you get all IP addresses used by local system.} procedure ResolveNameToIP(Name: string; const IPList: TStrings); {:Try resolve name to primary IP address. i.e. If you pass as name result of @link(LocalName) method, you get primary IP addresses used by local system.} function ResolveName(Name: string): string; {:Try resolve IP to their primary domain name. If IP not have domain name, then is returned original IP.} function ResolveIPToName(IP: string): string; {:Try resolve symbolic port name to port number. (i.e. 'Echo' to 8)} function ResolvePort(Port: string): Word; {:Set information about remote side socket. It is good for seting remote side for sending UDP packet, etc.} procedure SetRemoteSin(IP, Port: string); {:Picks IP socket address from @link(LocalSin).} function GetLocalSinIP: string; virtual; {:Picks IP socket address from @link(RemoteSin).} function GetRemoteSinIP: string; virtual; {:Picks socket PORT number from @link(LocalSin).} function GetLocalSinPort: Integer; virtual; {:Picks socket PORT number from @link(RemoteSin).} function GetRemoteSinPort: Integer; virtual; {:Return @TRUE, if you can read any data from socket or is incoming connection on TCP based socket. Status is tested for time Timeout (in milliseconds). If value in Timeout is 0, status is only tested and continue. If value in Timeout is -1, run is breaked and waiting for read data maybe forever. This function is need only on special cases, when you need use @link(RecvBuffer) function directly! read functioms what have timeout as calling parameter, calling this function internally.} function CanRead(Timeout: Integer): Boolean; virtual; {:Same as @link(CanRead), but additionally return @TRUE if is some data in @link(LineBuffer).} function CanReadEx(Timeout: Integer): Boolean; virtual; {:Return @TRUE, if you can to socket write any data (not full sending buffer). Status is tested for time Timeout (in milliseconds). If value in Timeout is 0, status is only tested and continue. If value in Timeout is -1, run is breaked and waiting for write data maybe forever. This function is need only on special cases!} function CanWrite(Timeout: Integer): Boolean; virtual; {:Same as @link(SendBuffer), but send datagram to address from @link(RemoteSin). Usefull for sending reply to datagram received by function @link(RecvBufferFrom).} function SendBufferTo(const Buffer: TMemory; Length: Integer): Integer; virtual; {:Note: This is low-lever receive function. You must be sure if data is waiting for read before call this function for avoid deadlock! Receives first waiting datagram to allocated buffer. If there is no waiting one, then waits until one comes. Returns length of datagram stored in BUFFER. If length exceeds buffer datagram is truncated. After this @link(RemoteSin) structure contains information about sender of UDP packet.} function RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; virtual; {$IFNDEF CIL} {:This function is for check for incoming data on set of sockets. Whitch sockets is checked is decribed by SocketList Tlist with TBlockSocket objects. TList may have maximal number of objects defined by FD_SETSIZE constant. Return @TRUE, if you can from some socket read any data or is incoming connection on TCP based socket. Status is tested for time Timeout (in milliseconds). If value in Timeout is 0, status is only tested and continue. If value in Timeout is -1, run is breaked and waiting for read data maybe forever. If is returned @TRUE, CanReadList TList is filled by all TBlockSocket objects what waiting for read.} function GroupCanRead(const SocketList: TSocketList; Timeout: Integer; const CanReadList: TSocketList): Boolean; {$ENDIF} {:By this method you may turn address reuse mode for local @link(bind). It is good specially for UDP protocol. Using this with TCP protocol is hazardous!} procedure EnableReuse(Value: Boolean); {:Try set timeout for all sending and receiving operations, if socket provider can do it. (It not supported by all socket providers!)} procedure SetTimeout(Timeout: Integer); {:Try set timeout for all sending operations, if socket provider can do it. (It not supported by all socket providers!)} procedure SetSendTimeout(Timeout: Integer); {:Try set timeout for all receiving operations, if socket provider can do it. (It not supported by all socket providers!)} procedure SetRecvTimeout(Timeout: Integer); {:Return value of socket type.} function GetSocketType: integer; Virtual; {:Return value of protocol type for socket creation.} function GetSocketProtocol: integer; Virtual; {:WSA structure with information about socket provider. On non-windows platforms this structure is simulated!} property WSAData: TWSADATA read GetWsaData; {:FDset structure prepared for usage with this socket.} property FDset: TFDSet read FFDset; {:Structure describing local socket side.} property LocalSin: TVarSin read FLocalSin write FLocalSin; {:Structure describing remote socket side.} property RemoteSin: TVarSin read FRemoteSin write FRemoteSin; {:Socket handler. Suitable for "manual" calls to socket API or manual connection of socket to a previously created socket (i.e by Accept method on TCP socket)} property Socket: TSocket read FSocket write SetSocket; {:Last socket operation error code. Error codes are described in socket documentation. Human readable error description is stored in @link(LastErrorDesc) property.} property LastError: Integer read FLastError; {:Human readable error description of @link(LastError) code.} property LastErrorDesc: string read FLastErrorDesc; {:Buffer used by all high-level receiving functions. This buffer is used for optimized reading of data from socket. In normal cases you not need access to this buffer directly!} property LineBuffer: AnsiString read FBuffer write FBuffer; {:Size of Winsock receive buffer. If it is not supported by socket provider, it return as size one kilobyte.} property SizeRecvBuffer: Integer read GetSizeRecvBuffer write SetSizeRecvBuffer; {:Size of Winsock send buffer. If it is not supported by socket provider, it return as size one kilobyte.} property SizeSendBuffer: Integer read GetSizeSendBuffer write SetSizeSendBuffer; {:If @True, turn class to non-blocking mode. Not all functions are working properly in this mode, you must know exactly what you are doing! However when you have big experience with non-blocking programming, then you can optimise your program by non-block mode!} property NonBlockMode: Boolean read FNonBlockMode Write SetNonBlockMode; {:Set Time-to-live value. (if system supporting it!)} property TTL: Integer read GetTTL Write SetTTL; {:If is @true, then class in in IPv6 mode.} property IP6used: Boolean read FIP6used; {:Return count of received bytes on this socket from begin of current connection.} property RecvCounter: int64 read FRecvCounter; {:Return count of sended bytes on this socket from begin of current connection.} property SendCounter: int64 read FSendCounter; published {:Return descriptive string for given error code. This is class function. You may call it without created object!} class function GetErrorDesc(ErrorCode: Integer): string; {:Return descriptive string for @link(LastError).} function GetErrorDescEx: string; virtual; {:this value is for free use.} property Tag: Integer read FTag write FTag; {:If @true, winsock errors raises exception. Otherwise is setted @link(LastError) value only and you must check it from your program! Default value is @false.} property RaiseExcept: Boolean read FRaiseExcept write FRaiseExcept; {:Define maximum length in bytes of @link(LineBuffer) for high-level receiving functions. If this functions try to read more data then this limit, error is returned! If value is 0 (default), no limitation is used. This is very good protection for stupid attacks to your server by sending lot of data without proper terminator... until all your memory is allocated by LineBuffer! Note: This maximum length is checked only in functions, what read unknown number of bytes! (like @link(RecvString) or @link(RecvTerminated))} property MaxLineLength: Integer read FMaxLineLength Write FMaxLineLength; {:Define maximal bandwidth for all sending operations in bytes per second. If value is 0 (default), bandwidth limitation is not used.} property MaxSendBandwidth: Integer read FMaxSendBandwidth Write FMaxSendBandwidth; {:Define maximal bandwidth for all receiving operations in bytes per second. If value is 0 (default), bandwidth limitation is not used.} property MaxRecvBandwidth: Integer read FMaxRecvBandwidth Write FMaxRecvBandwidth; {:Define maximal bandwidth for all sending and receiving operations in bytes per second. If value is 0 (default), bandwidth limitation is not used.} property MaxBandwidth: Integer Write SetBandwidth; {:Do a conversion of non-standard line terminators to CRLF. (Off by default) If @True, then terminators like sigle CR, single LF or LFCR are converted to CRLF internally. This have effect only in @link(RecvString) method!} property ConvertLineEnd: Boolean read FConvertLineEnd Write FConvertLineEnd; {:Specified Family of this socket. When you are using Windows preliminary support for IPv6, then I recommend to set this property!} property Family: TSocketFamily read FFamily Write SetFamily; {:When resolving of domain name return both IPv4 and IPv6 addresses, then specify if is used IPv4 (dafault - @true) or IPv6.} property PreferIP4: Boolean read FPreferIP4 Write FPreferIP4; {:By default (@true) is all timeouts used as timeout between two packets in reading operations. If you set this to @false, then Timeouts is for overall reading operation!} property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout; {:All sended datas was splitted by this value.} property SendMaxChunk: Integer read FSendMaxChunk Write FSendMaxChunk; {:By setting this property to @true you can stop any communication. You can use this property for soft abort of communication.} property StopFlag: Boolean read FStopFlag Write FStopFlag; {:Timeout for data sending by non-blocking socket mode.} property NonblockSendTimeout: Integer read FNonblockSendTimeout Write FNonblockSendTimeout; {:Timeout for @link(Connect) call. Default value 0 means default system timeout. Non-zero value means timeout in millisecond.} property ConnectionTimeout: Integer read FConnectionTimeout write FConnectionTimeout; {:This event is called by various reasons. It is good for monitoring socket, create gauges for data transfers, etc.} property OnStatus: THookSocketStatus read FOnStatus write FOnStatus; {:this event is good for some internal thinks about filtering readed datas. It is used by telnet client by example.} property OnReadFilter: THookDataFilter read FOnReadFilter write FOnReadFilter; {:This event is called after real socket creation for setting special socket options, because you not know when socket is created. (it is depended on Ipv4, IPv6 or automatic mode)} property OnCreateSocket: THookCreateSocket read FOnCreateSocket write FOnCreateSocket; {:This event is good for monitoring content of readed or writed datas.} property OnMonitor: THookMonitor read FOnMonitor write FOnMonitor; {:This event is good for calling your code during long socket operations. (Example, for refresing UI if class in not called within the thread.) Rate of heartbeats can be modified by @link(HeartbeatRate) property.} property OnHeartbeat: THookHeartbeat read FOnHeartbeat write FOnHeartbeat; {:Specify typical rate of @link(OnHeartbeat) event and @link(StopFlag) testing. Default value 0 disabling heartbeats! Value is in milliseconds. Real rate can be higher or smaller then this value, because it depending on real socket operations too! Note: Each heartbeat slowing socket processing.} property HeartbeatRate: integer read FHeartbeatRate Write FHeartbeatRate; {:What class own this socket? Used by protocol implementation classes.} property Owner: TObject read FOwner Write FOwner; end; {:@abstract(Support for SOCKS4 and SOCKS5 proxy) Layer with definition all necessary properties and functions for implementation SOCKS proxy client. Do not use this class directly.} TSocksBlockSocket = class(TBlockSocket) protected FSocksIP: string; FSocksPort: string; FSocksTimeout: integer; FSocksUsername: string; FSocksPassword: string; FUsingSocks: Boolean; FSocksResolver: Boolean; FSocksLastError: integer; FSocksResponseIP: string; FSocksResponsePort: string; FSocksLocalIP: string; FSocksLocalPort: string; FSocksRemoteIP: string; FSocksRemotePort: string; FBypassFlag: Boolean; FSocksType: TSocksType; function SocksCode(IP, Port: string): Ansistring; function SocksDecode(Value: Ansistring): integer; public constructor Create; {:Open connection to SOCKS proxy and if @link(SocksUsername) is set, do authorisation to proxy. This is needed only in special cases! (it is called internally!)} function SocksOpen: Boolean; {:Send specified request to SOCKS proxy. This is needed only in special cases! (it is called internally!)} function SocksRequest(Cmd: Byte; const IP, Port: string): Boolean; {:Receive response to previosly sended request. This is needed only in special cases! (it is called internally!)} function SocksResponse: Boolean; {:Is @True when class is using SOCKS proxy.} property UsingSocks: Boolean read FUsingSocks; {:If SOCKS proxy failed, here is error code returned from SOCKS proxy.} property SocksLastError: integer read FSocksLastError; published {:Address of SOCKS server. If value is empty string, SOCKS support is disabled. Assingning any value to this property enable SOCKS mode. Warning: You cannot combine this mode with HTTP-tunneling mode!} property SocksIP: string read FSocksIP write FSocksIP; {:Port of SOCKS server. Default value is '1080'.} property SocksPort: string read FSocksPort write FSocksPort; {:If you need authorisation on SOCKS server, set username here.} property SocksUsername: string read FSocksUsername write FSocksUsername; {:If you need authorisation on SOCKS server, set password here.} property SocksPassword: string read FSocksPassword write FSocksPassword; {:Specify timeout for communicatin with SOCKS server. Default is one minute.} property SocksTimeout: integer read FSocksTimeout write FSocksTimeout; {:If @True, all symbolic names of target hosts is not translated to IP's locally, but resolving is by SOCKS proxy. Default is @True.} property SocksResolver: Boolean read FSocksResolver write FSocksResolver; {:Specify SOCKS type. By default is used SOCKS5, but you can use SOCKS4 too. When you select SOCKS4, then if @link(SOCKSResolver) is enabled, then is used SOCKS4a. Othervise is used pure SOCKS4.} property SocksType: TSocksType read FSocksType write FSocksType; end; {:@abstract(Implementation of TCP socket.) Supported features: IPv4, IPv6, SSL/TLS or SSH (depending on used plugin), SOCKS5 proxy (outgoing connections and limited incomming), SOCKS4/4a proxy (outgoing connections and limited incomming), TCP through HTTP proxy tunnel.} TTCPBlockSocket = class(TSocksBlockSocket) protected FOnAfterConnect: THookAfterConnect; FSSL: TCustomSSL; FHTTPTunnelIP: string; FHTTPTunnelPort: string; FHTTPTunnel: Boolean; FHTTPTunnelRemoteIP: string; FHTTPTunnelRemotePort: string; FHTTPTunnelUser: string; FHTTPTunnelPass: string; FHTTPTunnelTimeout: integer; procedure SocksDoConnect(IP, Port: string); procedure HTTPTunnelDoConnect(IP, Port: string); procedure DoAfterConnect; public {:Create TCP socket class with default plugin for SSL/TSL/SSH implementation (see @link(SSLImplementation))} constructor Create; {:Create TCP socket class with desired plugin for SSL/TSL/SSH implementation} constructor CreateWithSSL(SSLPlugin: TSSLClass); destructor Destroy; override; {:See @link(TBlockSocket.CloseSocket)} procedure CloseSocket; override; {:See @link(TBlockSocket.WaitingData)} function WaitingData: Integer; override; {:Sets socket to receive mode for new incoming connections. It is necessary to use @link(TBlockSocket.BIND) function call before this method to select receiving port! If you use SOCKS, activate incoming TCP connection by this proxy. (By BIND method of SOCKS.)} procedure Listen; override; {:Waits until new incoming connection comes. After it comes a new socket is automatically created (socket handler is returned by this function as result). If you use SOCKS, new socket is not created! In this case is used same socket as socket for listening! So, you can accept only one connection in SOCKS mode.} function Accept: TSocket; override; {:Connects socket to remote IP address and PORT. The same rules as with @link(TBlockSocket.BIND) method are valid. The only exception is that PORT with 0 value will not be connected. After call to this method a communication channel between local and remote socket is created. Local socket is assigned automatically if not controlled by previous call to @link(TBlockSocket.BIND) method. Structures @link(TBlockSocket.LocalSin) and @link(TBlockSocket.RemoteSin) will be filled with valid values. If you use SOCKS, activate outgoing TCP connection by SOCKS proxy specified in @link(TSocksBlockSocket.SocksIP). (By CONNECT method of SOCKS.) If you use HTTP-tunnel mode, activate outgoing TCP connection by HTTP tunnel specified in @link(HTTPTunnelIP). (By CONNECT method of HTTP protocol.) Note: If you call this on non-created socket, then socket is created automaticly.} procedure Connect(IP, Port: string); override; {:If you need upgrade existing TCP connection to SSL/TLS (or SSH2, if plugin allows it) mode, then call this method. This method switch this class to SSL mode and do SSL/TSL handshake.} procedure SSLDoConnect; {:By this method you can downgrade existing SSL/TLS connection to normal TCP connection.} procedure SSLDoShutdown; {:If you need use this component as SSL/TLS TCP server, then after accepting of inbound connection you need start SSL/TLS session by this method. Before call this function, you must have assigned all neeeded certificates and keys!} function SSLAcceptConnection: Boolean; {:See @link(TBlockSocket.GetLocalSinIP)} function GetLocalSinIP: string; override; {:See @link(TBlockSocket.GetRemoteSinIP)} function GetRemoteSinIP: string; override; {:See @link(TBlockSocket.GetLocalSinPort)} function GetLocalSinPort: Integer; override; {:See @link(TBlockSocket.GetRemoteSinPort)} function GetRemoteSinPort: Integer; override; {:See @link(TBlockSocket.SendBuffer)} function SendBuffer(const Buffer: TMemory; Length: Integer): Integer; override; {:See @link(TBlockSocket.RecvBuffer)} function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; {:Return value of socket type. For TCP return SOCK_STREAM.} function GetSocketType: integer; override; {:Return value of protocol type for socket creation. For TCP return IPPROTO_TCP.} function GetSocketProtocol: integer; override; {:Class implementing SSL/TLS support. It is allways some descendant of @link(TCustomSSL) class. When programmer not select some SSL plugin class, then is used @link(TSSLNone)} property SSL: TCustomSSL read FSSL; {:@True if is used HTTP tunnel mode.} property HTTPTunnel: Boolean read FHTTPTunnel; published {:Return descriptive string for @link(LastError). On case of error in SSL/TLS subsystem, it returns right error description.} function GetErrorDescEx: string; override; {:Specify IP address of HTTP proxy. Assingning non-empty value to this property enable HTTP-tunnel mode. This mode is for tunnelling any outgoing TCP connection through HTTP proxy server. (If policy on HTTP proxy server allow this!) Warning: You cannot combine this mode with SOCK5 mode!} property HTTPTunnelIP: string read FHTTPTunnelIP Write FHTTPTunnelIP; {:Specify port of HTTP proxy for HTTP-tunneling.} property HTTPTunnelPort: string read FHTTPTunnelPort Write FHTTPTunnelPort; {:Specify authorisation username for access to HTTP proxy in HTTP-tunnel mode. If you not need authorisation, then let this property empty.} property HTTPTunnelUser: string read FHTTPTunnelUser Write FHTTPTunnelUser; {:Specify authorisation password for access to HTTP proxy in HTTP-tunnel mode.} property HTTPTunnelPass: string read FHTTPTunnelPass Write FHTTPTunnelPass; {:Specify timeout for communication with HTTP proxy in HTTPtunnel mode.} property HTTPTunnelTimeout: integer read FHTTPTunnelTimeout Write FHTTPTunnelTimeout; {:This event is called after sucessful TCP socket connection.} property OnAfterConnect: THookAfterConnect read FOnAfterConnect write FOnAfterConnect; end; {:@abstract(Datagram based communication) This class implementing datagram based communication instead default stream based communication style.} TDgramBlockSocket = class(TSocksBlockSocket) public {:Fill @link(TBlockSocket.RemoteSin) structure. This address is used for sending data.} procedure Connect(IP, Port: string); override; {:Silently redirected to @link(TBlockSocket.SendBufferTo).} function SendBuffer(const Buffer: TMemory; Length: Integer): Integer; override; {:Silently redirected to @link(TBlockSocket.RecvBufferFrom).} function RecvBuffer(Buffer: TMemory; Length: Integer): Integer; override; end; {:@abstract(Implementation of UDP socket.) NOTE: in this class is all receiving redirected to RecvBufferFrom. You can use for reading any receive function. Preffered is RecvPacket! Similary all sending is redirected to SendbufferTo. You can use for sending UDP packet any sending function, like SendString. Supported features: IPv4, IPv6, unicasts, broadcasts, multicasts, SOCKS5 proxy (only unicasts! Outgoing and incomming.)} TUDPBlockSocket = class(TDgramBlockSocket) protected FSocksControlSock: TTCPBlockSocket; function UdpAssociation: Boolean; procedure SetMulticastTTL(TTL: integer); function GetMulticastTTL:integer; public destructor Destroy; override; {:Enable or disable sending of broadcasts. If seting OK, result is @true. This method is not supported in SOCKS5 mode! IPv6 does not support broadcasts! In this case you must use Multicasts instead.} procedure EnableBroadcast(Value: Boolean); {:See @link(TBlockSocket.SendBufferTo)} function SendBufferTo(const Buffer: TMemory; Length: Integer): Integer; override; {:See @link(TBlockSocket.RecvBufferFrom)} function RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; override; {$IFNDEF CIL} {:Add this socket to given multicast group. You cannot use Multicasts in SOCKS mode!} procedure AddMulticast(MCastIP:string); {:Remove this socket from given multicast group.} procedure DropMulticast(MCastIP:string); {$ENDIF} {:All sended multicast datagrams is loopbacked to your interface too. (you can read your sended datas.) You can disable this feature by this function. This function not working on some Windows systems!} procedure EnableMulticastLoop(Value: Boolean); {:Return value of socket type. For UDP return SOCK_DGRAM.} function GetSocketType: integer; override; {:Return value of protocol type for socket creation. For UDP return IPPROTO_UDP.} function GetSocketProtocol: integer; override; {:Set Time-to-live value for multicasts packets. It define number of routers for transfer of datas. If you set this to 1 (dafault system value), then multicasts packet goes only to you local network. If you need transport multicast packet to worldwide, then increase this value, but be carefull, lot of routers on internet does not transport multicasts packets!} property MulticastTTL: Integer read GetMulticastTTL Write SetMulticastTTL; end; {:@abstract(Implementation of RAW ICMP socket.) For this object you must have rights for creating RAW sockets!} TICMPBlockSocket = class(TDgramBlockSocket) public {:Return value of socket type. For RAW and ICMP return SOCK_RAW.} function GetSocketType: integer; override; {:Return value of protocol type for socket creation. For ICMP returns IPPROTO_ICMP or IPPROTO_ICMPV6} function GetSocketProtocol: integer; override; end; {:@abstract(Implementation of RAW socket.) For this object you must have rights for creating RAW sockets!} TRAWBlockSocket = class(TBlockSocket) public {:Return value of socket type. For RAW and ICMP return SOCK_RAW.} function GetSocketType: integer; override; {:Return value of protocol type for socket creation. For RAW returns IPPROTO_RAW.} function GetSocketProtocol: integer; override; end; {:@abstract(Implementation of PGM-message socket.) Not all systems supports this protocol!} TPGMMessageBlockSocket = class(TBlockSocket) public {:Return value of socket type. For PGM-message return SOCK_RDM.} function GetSocketType: integer; override; {:Return value of protocol type for socket creation. For PGM-message returns IPPROTO_RM.} function GetSocketProtocol: integer; override; end; {:@abstract(Implementation of PGM-stream socket.) Not all systems supports this protocol!} TPGMStreamBlockSocket = class(TBlockSocket) public {:Return value of socket type. For PGM-stream return SOCK_STREAM.} function GetSocketType: integer; override; {:Return value of protocol type for socket creation. For PGM-stream returns IPPROTO_RM.} function GetSocketProtocol: integer; override; end; {:@abstract(Parent class for all SSL plugins.) This is abstract class defining interface for other SSL plugins. Instance of this class will be created for each @link(TTCPBlockSocket). Warning: not all methods and propertis can work in all existing SSL plugins! Please, read documentation of used SSL plugin.} TCustomSSL = class(TObject) private protected FSessionOld: Pointer; FSessionNew: Pointer; FOnVerifyCert: THookVerifyCert; FSocket: TTCPBlockSocket; FSSLEnabled: Boolean; FLastError: integer; FLastErrorDesc: string; FSSLType: TSSLType; FKeyPassword: string; FCiphers: string; FCertificateFile: string; FPrivateKeyFile: string; FCertificate: Ansistring; FPrivateKey: Ansistring; FPFX: Ansistring; FPFXfile: string; FCertCA: Ansistring; FCertCAFile: string; FTrustCertificate: Ansistring; FTrustCertificateFile: string; FVerifyCert: Boolean; FUsername: string; FPassword: string; FSSHChannelType: string; FSSHChannelArg1: string; FSSHChannelArg2: string; FCertComplianceLevel: integer; FSNIHost: string; procedure ReturnError; procedure SetCertCAFile(const Value: string); virtual; function DoVerifyCert:boolean; function CreateSelfSignedCert(Host: string): Boolean; virtual; public {: Create plugin class. it is called internally from @link(TTCPBlockSocket)} constructor Create(const Value: TTCPBlockSocket); virtual; {: Assign settings (certificates and configuration) from another SSL plugin class.} procedure Assign(const Value: TCustomSSL); virtual; {: return description of used plugin. It usually return name and version of used SSL library.} function LibVersion: String; virtual; {: return name of used plugin.} function LibName: String; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for start SSL connection.} function Connect: boolean; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for acept new SSL connection.} function Accept: boolean; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for hard shutdown of SSL connection. (for example, before socket is closed)} function Shutdown: boolean; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for soft shutdown of SSL connection. (for example, when you need to continue with unprotected connection.)} function BiShutdown: boolean; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for sending some datas by SSL connection.} function SendBuffer(Buffer: TMemory; Len: Integer): Integer; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for receiving some datas by SSL connection.} function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; virtual; {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! Here is needed code for getting count of datas what waiting for read. If SSL plugin not allows this, then it should return 0.} function WaitingData: Integer; virtual; {:Return string with identificator of SSL/TLS version of existing connection.} function GetSSLVersion: string; virtual; {:Return subject of remote SSL peer.} function GetPeerSubject: string; virtual; {:Return Serial number if remote X509 certificate.} function GetPeerSerialNo: integer; virtual; {:Return issuer certificate of remote SSL peer.} function GetPeerIssuer: string; virtual; {:Return peer name from remote side certificate. This is good for verify, if certificate is generated for remote side IP name.} function GetPeerName: string; virtual; {:Returns has of peer name from remote side certificate. This is good for fast remote side authentication.} function GetPeerNameHash: cardinal; virtual; {:Return fingerprint of remote SSL peer. (As binary nonprintable string!)} function GetPeerFingerprint: AnsiString; virtual; {:Return all detailed information about certificate from remote side of SSL/TLS connection. Result string can be multilined! Each plugin can return this informations in different format!} function GetCertInfo: string; virtual; {:Return currently used Cipher.} function GetCipherName: string; virtual; {:Return currently used number of bits in current Cipher algorythm.} function GetCipherBits: integer; virtual; {:Return number of bits in current Cipher algorythm.} function GetCipherAlgBits: integer; virtual; {:Return result value of verify remote side certificate. Look to OpenSSL documentation for possible values. For example 0 is successfuly verified certificate, or 18 is self-signed certificate.} function GetVerifyCert: integer; virtual; {: Resurn @true if SSL mode is enabled on existing cvonnection.} property SSLEnabled: Boolean read FSSLEnabled; {:Return error code of last SSL operation. 0 is OK.} property LastError: integer read FLastError; {:Return error description of last SSL operation.} property LastErrorDesc: string read FLastErrorDesc; {:Used for session resumption } property Session: Pointer read FSessionNew write FSessionOld; published {:Here you can specify requested SSL/TLS mode. Default is autodetection, but on some servers autodetection not working properly. In this case you must specify requested SSL/TLS mode by your hand!} property SSLType: TSSLType read FSSLType write FSSLType; {:Password for decrypting of encoded certificate or key.} property KeyPassword: string read FKeyPassword write FKeyPassword; {:Username for possible credentials.} property Username: string read FUsername write FUsername; {:password for possible credentials.} property Password: string read FPassword write FPassword; {:By this property you can modify default set of SSL/TLS ciphers.} property Ciphers: string read FCiphers write FCiphers; {:Used for loading certificate from disk file. See to plugin documentation if this method is supported and how!} property CertificateFile: string read FCertificateFile write FCertificateFile; {:Used for loading private key from disk file. See to plugin documentation if this method is supported and how!} property PrivateKeyFile: string read FPrivateKeyFile write FPrivateKeyFile; {:Used for loading certificate from binary string. See to plugin documentation if this method is supported and how!} property Certificate: Ansistring read FCertificate write FCertificate; {:Used for loading private key from binary string. See to plugin documentation if this method is supported and how!} property PrivateKey: Ansistring read FPrivateKey write FPrivateKey; {:Used for loading PFX from binary string. See to plugin documentation if this method is supported and how!} property PFX: Ansistring read FPFX write FPFX; {:Used for loading PFX from disk file. See to plugin documentation if this method is supported and how!} property PFXfile: string read FPFXfile write FPFXfile; {:Used for loading trusted certificates from disk file. See to plugin documentation if this method is supported and how!} property TrustCertificateFile: string read FTrustCertificateFile write FTrustCertificateFile; {:Used for loading trusted certificates from binary string. See to plugin documentation if this method is supported and how!} property TrustCertificate: Ansistring read FTrustCertificate write FTrustCertificate; {:Used for loading CA certificates from binary string. See to plugin documentation if this method is supported and how!} property CertCA: Ansistring read FCertCA write FCertCA; {:Used for loading CA certificates from disk file. See to plugin documentation if this method is supported and how!} property CertCAFile: string read FCertCAFile write SetCertCAFile; {:If @true, then is verified client certificate. (it is good for writing SSL/TLS servers.) When you are not server, but you are client, then if this property is @true, verify servers certificate.} property VerifyCert: Boolean read FVerifyCert write FVerifyCert; {:channel type for possible SSH connections} property SSHChannelType: string read FSSHChannelType write FSSHChannelType; {:First argument of channel type for possible SSH connections} property SSHChannelArg1: string read FSSHChannelArg1 write FSSHChannelArg1; {:Second argument of channel type for possible SSH connections} property SSHChannelArg2: string read FSSHChannelArg2 write FSSHChannelArg2; {: Level of standards compliance level (CryptLib: values in cryptlib.pas, -1: use default value ) } property CertComplianceLevel:integer read FCertComplianceLevel write FCertComplianceLevel; {:This event is called when verifying the server certificate immediatally after a successfull verification in the ssl library.} property OnVerifyCert: THookVerifyCert read FOnVerifyCert write FOnVerifyCert; {: Server Name Identification. Host name to send to server. If empty the host name found in URL will be used, which should be the normal use (http Header Host = SNI Host). The value is cleared after the connection is established. (SNI support requires OpenSSL 0.9.8k or later. Cryptlib not supported, yet ) } property SNIHost:string read FSNIHost write FSNIHost; end; {:@abstract(Default SSL plugin with no SSL support.) Dummy SSL plugin implementation for applications without SSL/TLS support.} TSSLNone = class (TCustomSSL) public {:See @inherited} function LibVersion: String; override; {:See @inherited} function LibName: String; override; end; {:@abstract(Record with definition of IP packet header.) For reading data from ICMP or RAW sockets.} TIPHeader = record VerLen: Byte; TOS: Byte; TotalLen: Word; Identifer: Word; FragOffsets: Word; TTL: Byte; Protocol: Byte; CheckSum: Word; SourceIp: LongWord; DestIp: LongWord; Options: LongWord; end; {:@abstract(Parent class of application protocol implementations.) By this class is defined common properties.} TSynaClient = Class(TObject) protected FTargetHost: string; FTargetPort: string; FIPInterface: string; FTimeout: integer; FUserName: string; FPassword: string; public constructor Create; published {:Specify terget server IP (or symbolic name). Default is 'localhost'.} property TargetHost: string read FTargetHost Write FTargetHost; {:Specify terget server port (or symbolic name).} property TargetPort: string read FTargetPort Write FTargetPort; {:Defined local socket address. (outgoing IP address). By default is used '0.0.0.0' as wildcard for default IP.} property IPInterface: string read FIPInterface Write FIPInterface; {:Specify default timeout for socket operations.} property Timeout: integer read FTimeout Write FTimeout; {:If protocol need user authorization, then fill here username.} property UserName: string read FUserName Write FUserName; {:If protocol need user authorization, then fill here password.} property Password: string read FPassword Write FPassword; end; var {:Selected SSL plugin. Default is @link(TSSLNone). Do not change this value directly!!! Just add your plugin unit to your project uses instead. Each plugin unit have initialization code what modify this variable.} SSLImplementation: TSSLClass = TSSLNone; implementation {$IFDEF ONCEWINSOCK} var WsaDataOnce: TWSADATA; e: ESynapseError; {$ENDIF} constructor TBlockSocket.Create; begin CreateAlternate(''); end; constructor TBlockSocket.CreateAlternate(Stub: string); {$IFNDEF ONCEWINSOCK} var e: ESynapseError; {$ENDIF} begin inherited Create; FDelayedOptions := TOptionList.Create; FRaiseExcept := False; {$IFDEF RAISEEXCEPT} FRaiseExcept := True; {$ENDIF} FSocket := INVALID_SOCKET; FBuffer := ''; FLastCR := False; FLastLF := False; FBinded := False; FNonBlockMode := False; FMaxLineLength := 0; FMaxSendBandwidth := 0; FNextSend := 0; FMaxRecvBandwidth := 0; FNextRecv := 0; FConvertLineEnd := False; FFamily := SF_Any; FFamilySave := SF_Any; FIP6used := False; FPreferIP4 := True; FInterPacketTimeout := True; FRecvCounter := 0; FSendCounter := 0; FSendMaxChunk := c64k; FStopFlag := False; FNonblockSendTimeout := 15000; FHeartbeatRate := 0; FConnectionTimeout := 0; FOwner := nil; {$IFNDEF ONCEWINSOCK} if Stub = '' then Stub := DLLStackName; if not InitSocketInterface(Stub) then begin e := ESynapseError.Create('Error loading Socket interface (' + Stub + ')!'); e.ErrorCode := 0; e.ErrorMessage := 'Error loading Socket interface (' + Stub + ')!'; raise e; end; SockCheck(synsock.WSAStartup(WinsockLevel, FWsaDataOnce)); ExceptCheck; {$ENDIF} end; destructor TBlockSocket.Destroy; var n: integer; p: TSynaOption; begin CloseSocket; {$IFNDEF ONCEWINSOCK} synsock.WSACleanup; DestroySocketInterface; {$ENDIF} for n := FDelayedOptions.Count - 1 downto 0 do begin p := TSynaOption(FDelayedOptions[n]); p.Free; end; FDelayedOptions.Free; inherited Destroy; end; function TBlockSocket.FamilyToAF(f: TSocketFamily): TAddrFamily; begin case f of SF_ip4: Result := AF_INET; SF_ip6: Result := AF_INET6; else Result := AF_UNSPEC; end; end; procedure TBlockSocket.SetDelayedOption(const Value: TSynaOption); var li: TLinger; x: integer; buf: TMemory; {$IFNDEF MSWINDOWS} timeval: TTimeval; {$ENDIF} begin case value.Option of SOT_Linger: begin {$IFDEF CIL} li := TLinger.Create(Value.Enabled, Value.Value div 1000); synsock.SetSockOptObj(FSocket, integer(SOL_SOCKET), integer(SO_LINGER), li); {$ELSE} li.l_onoff := Ord(Value.Enabled); li.l_linger := Value.Value div 1000; buf := @li; synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_LINGER), buf, SizeOf(li)); {$ENDIF} end; SOT_RecvBuff: begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(value.Value); {$ELSE} buf := @Value.Value; {$ENDIF} synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVBUF), buf, SizeOf(Value.Value)); end; SOT_SendBuff: begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(value.Value); {$ELSE} buf := @Value.Value; {$ENDIF} synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDBUF), buf, SizeOf(Value.Value)); end; SOT_NonBlock: begin FNonBlockMode := Value.Enabled; x := Ord(FNonBlockMode); synsock.IoctlSocket(FSocket, FIONBIO, x); end; SOT_RecvTimeout: begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(value.Value); synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVTIMEO), buf, SizeOf(Value.Value)); {$ELSE} {$IFDEF MSWINDOWS} buf := @Value.Value; synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVTIMEO), buf, SizeOf(Value.Value)); {$ELSE} timeval.tv_sec:=Value.Value div 1000; timeval.tv_usec:=(Value.Value mod 1000) * 1000; synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVTIMEO), @timeval, SizeOf(timeval)); {$ENDIF} {$ENDIF} end; SOT_SendTimeout: begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(value.Value); {$ELSE} {$IFDEF MSWINDOWS} buf := @Value.Value; synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDTIMEO), buf, SizeOf(Value.Value)); {$ELSE} timeval.tv_sec:=Value.Value div 1000; timeval.tv_usec:=(Value.Value mod 1000) * 1000; synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDTIMEO), @timeval, SizeOf(timeval)); {$ENDIF} {$ENDIF} end; SOT_Reuse: begin x := Ord(Value.Enabled); {$IFDEF CIL} buf := System.BitConverter.GetBytes(x); {$ELSE} buf := @x; {$ENDIF} synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_REUSEADDR), buf, SizeOf(x)); end; SOT_TTL: begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(value.Value); {$ELSE} buf := @Value.Value; {$ENDIF} if FIP6Used then synsock.SetSockOpt(FSocket, integer(IPPROTO_IPV6), integer(IPV6_UNICAST_HOPS), buf, SizeOf(Value.Value)) else synsock.SetSockOpt(FSocket, integer(IPPROTO_IP), integer(IP_TTL), buf, SizeOf(Value.Value)); end; SOT_Broadcast: begin //#todo1 broadcasty na IP6 x := Ord(Value.Enabled); {$IFDEF CIL} buf := System.BitConverter.GetBytes(x); {$ELSE} buf := @x; {$ENDIF} synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_BROADCAST), buf, SizeOf(x)); end; SOT_MulticastTTL: begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(value.Value); {$ELSE} buf := @Value.Value; {$ENDIF} if FIP6Used then synsock.SetSockOpt(FSocket, integer(IPPROTO_IPV6), integer(IPV6_MULTICAST_HOPS), buf, SizeOf(Value.Value)) else synsock.SetSockOpt(FSocket, integer(IPPROTO_IP), integer(IP_MULTICAST_TTL), buf, SizeOf(Value.Value)); end; SOT_MulticastLoop: begin x := Ord(Value.Enabled); {$IFDEF CIL} buf := System.BitConverter.GetBytes(x); {$ELSE} buf := @x; {$ENDIF} if FIP6Used then synsock.SetSockOpt(FSocket, integer(IPPROTO_IPV6), integer(IPV6_MULTICAST_LOOP), buf, SizeOf(x)) else synsock.SetSockOpt(FSocket, integer(IPPROTO_IP), integer(IP_MULTICAST_LOOP), buf, SizeOf(x)); end; end; Value.Free; end; procedure TBlockSocket.DelayedOption(const Value: TSynaOption); begin if FSocket = INVALID_SOCKET then begin FDelayedOptions.Insert(0, Value); end else SetDelayedOption(Value); end; procedure TBlockSocket.ProcessDelayedOptions; var n: integer; d: TSynaOption; begin for n := FDelayedOptions.Count - 1 downto 0 do begin d := TSynaOption(FDelayedOptions[n]); SetDelayedOption(d); end; FDelayedOptions.Clear; end; procedure TBlockSocket.SetSin(var Sin: TVarSin; IP, Port: string); var f: TSocketFamily; begin DoStatus(HR_ResolvingBegin, IP + ':' + Port); ResetLastError; //if socket exists, then use their type, else use users selection f := SF_Any; if (FSocket = INVALID_SOCKET) and (FFamily = SF_any) then begin if IsIP(IP) then f := SF_IP4 else if IsIP6(IP) then f := SF_IP6; end else f := FFamily; FLastError := synsock.SetVarSin(sin, ip, port, FamilyToAF(f), GetSocketprotocol, GetSocketType, FPreferIP4); DoStatus(HR_ResolvingEnd, GetSinIP(sin) + ':' + IntTostr(GetSinPort(sin))); end; function TBlockSocket.GetSinIP(Sin: TVarSin): string; begin Result := synsock.GetSinIP(sin); end; function TBlockSocket.GetSinPort(Sin: TVarSin): Integer; begin Result := synsock.GetSinPort(sin); end; procedure TBlockSocket.CreateSocket; var sin: TVarSin; begin //dummy for SF_Any Family mode ResetLastError; if (FFamily <> SF_Any) and (FSocket = INVALID_SOCKET) then begin {$IFDEF CIL} if FFamily = SF_IP6 then sin := TVarSin.Create(IPAddress.Parse('::0'), 0) else sin := TVarSin.Create(IPAddress.Parse('0.0.0.0'), 0); {$ELSE} FillChar(Sin, Sizeof(Sin), 0); if FFamily = SF_IP6 then sin.sin_family := AF_INET6 else sin.sin_family := AF_INET; {$ENDIF} InternalCreateSocket(Sin); end; end; procedure TBlockSocket.CreateSocketByName(const Value: String); var sin: TVarSin; begin ResetLastError; if FSocket = INVALID_SOCKET then begin SetSin(sin, value, '0'); if FLastError = 0 then InternalCreateSocket(Sin); end; end; procedure TBlockSocket.InternalCreateSocket(Sin: TVarSin); begin FStopFlag := False; FRecvCounter := 0; FSendCounter := 0; ResetLastError; if FSocket = INVALID_SOCKET then begin FBuffer := ''; FBinded := False; FIP6Used := Sin.AddressFamily = AF_INET6; FSocket := synsock.Socket(integer(Sin.AddressFamily), GetSocketType, GetSocketProtocol); if FSocket = INVALID_SOCKET then FLastError := synsock.WSAGetLastError; {$IFNDEF CIL} FD_ZERO(FFDSet); FD_SET(FSocket, FFDSet); {$ENDIF} ExceptCheck; if FIP6used then DoStatus(HR_SocketCreate, 'IPv6') else DoStatus(HR_SocketCreate, 'IPv4'); ProcessDelayedOptions; DoCreateSocket; end; end; procedure TBlockSocket.CloseSocket; begin AbortSocket; end; procedure TBlockSocket.AbortSocket; var n: integer; p: TSynaOption; begin if FSocket <> INVALID_SOCKET then synsock.CloseSocket(FSocket); FSocket := INVALID_SOCKET; for n := FDelayedOptions.Count - 1 downto 0 do begin p := TSynaOption(FDelayedOptions[n]); p.Free; end; FDelayedOptions.Clear; FFamily := FFamilySave; DoStatus(HR_SocketClose, ''); end; procedure TBlockSocket.Bind(const IP, Port: string); var Sin: TVarSin; begin ResetLastError; if (FSocket <> INVALID_SOCKET) or not((FFamily = SF_ANY) and (IP = cAnyHost) and (Port = cAnyPort)) then begin SetSin(Sin, IP, Port); if FLastError = 0 then begin if FSocket = INVALID_SOCKET then InternalCreateSocket(Sin); SockCheck(synsock.Bind(FSocket, Sin)); GetSinLocal; FBuffer := ''; FBinded := True; end; ExceptCheck; DoStatus(HR_Bind, IP + ':' + Port); end; end; procedure TBlockSocket.Connect(IP, Port: string); var Sin: TVarSin; b: boolean; begin SetSin(Sin, IP, Port); if FLastError = 0 then begin if FSocket = INVALID_SOCKET then InternalCreateSocket(Sin); if FConnectionTimeout > 0 then begin // connect in non-blocking mode b := NonBlockMode; NonBlockMode := true; SockCheck(synsock.Connect(FSocket, Sin)); if (FLastError = WSAEINPROGRESS) OR (FLastError = WSAEWOULDBLOCK) then if not CanWrite(FConnectionTimeout) then FLastError := WSAETIMEDOUT; NonBlockMode := b; end else SockCheck(synsock.Connect(FSocket, Sin)); if FLastError = 0 then GetSins; FBuffer := ''; FLastCR := False; FLastLF := False; end; ExceptCheck; DoStatus(HR_Connect, IP + ':' + Port); end; procedure TBlockSocket.Listen; begin SockCheck(synsock.Listen(FSocket, SOMAXCONN)); GetSins; ExceptCheck; DoStatus(HR_Listen, ''); end; function TBlockSocket.Accept: TSocket; begin Result := synsock.Accept(FSocket, FRemoteSin); /// SockCheck(Result); ExceptCheck; DoStatus(HR_Accept, ''); end; procedure TBlockSocket.GetSinLocal; begin synsock.GetSockName(FSocket, FLocalSin); end; procedure TBlockSocket.GetSinRemote; begin synsock.GetPeerName(FSocket, FRemoteSin); end; procedure TBlockSocket.GetSins; begin GetSinLocal; GetSinRemote; end; procedure TBlockSocket.SetBandwidth(Value: Integer); begin MaxSendBandwidth := Value; MaxRecvBandwidth := Value; end; procedure TBlockSocket.LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); var x: LongWord; y: LongWord; n: integer; begin if FStopFlag then exit; if MaxB > 0 then begin y := GetTick; if Next > y then begin x := Next - y; if x > 0 then begin DoStatus(HR_Wait, IntToStr(x)); sleep(x mod 250); for n := 1 to x div 250 do if FStopFlag then Break else sleep(250); end; end; Next := GetTick + LongWord(Trunc((Length / MaxB) * 1000)); end; end; function TBlockSocket.TestStopFlag: Boolean; begin DoHeartbeat; Result := FStopFlag; if Result then begin FStopFlag := False; FLastError := WSAECONNABORTED; ExceptCheck; end; end; function TBlockSocket.SendBuffer(const Buffer: TMemory; Length: Integer): Integer; {$IFNDEF CIL} var x, y: integer; l, r: integer; p: Pointer; {$ENDIF} begin Result := 0; if TestStopFlag then Exit; DoMonitor(True, Buffer, Length); {$IFDEF CIL} Result := synsock.Send(FSocket, Buffer, Length, 0); {$ELSE} l := Length; x := 0; while x < l do begin y := l - x; if y > FSendMaxChunk then y := FSendMaxChunk; if y > 0 then begin LimitBandwidth(y, FMaxSendBandwidth, FNextsend); p := IncPoint(Buffer, x); r := synsock.Send(FSocket, p, y, MSG_NOSIGNAL); SockCheck(r); if FLastError = WSAEWOULDBLOCK then begin if CanWrite(FNonblockSendTimeout) then begin r := synsock.Send(FSocket, p, y, MSG_NOSIGNAL); SockCheck(r); end else FLastError := WSAETIMEDOUT; end; if FLastError <> 0 then Break; Inc(x, r); Inc(Result, r); Inc(FSendCounter, r); DoStatus(HR_WriteCount, IntToStr(r)); end else break; end; {$ENDIF} ExceptCheck; end; procedure TBlockSocket.SendByte(Data: Byte); {$IFDEF CIL} var buf: TMemory; {$ENDIF} begin {$IFDEF CIL} setlength(buf, 1); buf[0] := Data; SendBuffer(buf, 1); {$ELSE} SendBuffer(@Data, 1); {$ENDIF} end; procedure TBlockSocket.SendString(Data: AnsiString); var buf: TMemory; begin {$IFDEF CIL} buf := BytesOf(Data); {$ELSE} buf := Pointer(data); {$ENDIF} SendBuffer(buf, Length(Data)); end; procedure TBlockSocket.SendInteger(Data: integer); var buf: TMemory; begin {$IFDEF CIL} buf := System.BitConverter.GetBytes(Data); {$ELSE} buf := @Data; {$ENDIF} SendBuffer(buf, SizeOf(Data)); end; procedure TBlockSocket.SendBlock(const Data: AnsiString); var i: integer; begin i := SwapBytes(Length(data)); SendString(Codelongint(i) + Data); end; procedure TBlockSocket.InternalSendStream(const Stream: TStream; WithSize, Indy: boolean); var l: integer; yr: integer; s: AnsiString; b: boolean; {$IFDEF CIL} buf: TMemory; {$ENDIF} begin b := true; l := 0; if WithSize then begin l := Stream.Size - Stream.Position;; if not Indy then l := synsock.HToNL(l); end; repeat {$IFDEF CIL} Setlength(buf, FSendMaxChunk); yr := Stream.read(buf, FSendMaxChunk); if yr > 0 then begin if WithSize and b then begin b := false; SendString(CodeLongInt(l)); end; SendBuffer(buf, yr); if FLastError <> 0 then break; end {$ELSE} Setlength(s, FSendMaxChunk); yr := Stream.read(Pointer(s)^, FSendMaxChunk); if yr > 0 then begin SetLength(s, yr); if WithSize and b then begin b := false; SendString(CodeLongInt(l) + s); end else SendString(s); if FLastError <> 0 then break; end {$ENDIF} until yr <= 0; end; procedure TBlockSocket.SendStreamRaw(const Stream: TStream); begin InternalSendStream(Stream, false, false); end; procedure TBlockSocket.SendStreamIndy(const Stream: TStream); begin InternalSendStream(Stream, true, true); end; procedure TBlockSocket.SendStream(const Stream: TStream); begin InternalSendStream(Stream, true, false); end; function TBlockSocket.RecvBuffer(Buffer: TMemory; Length: Integer): Integer; begin Result := 0; if TestStopFlag then Exit; LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); // Result := synsock.Recv(FSocket, Buffer^, Length, MSG_NOSIGNAL); Result := synsock.Recv(FSocket, Buffer, Length, MSG_NOSIGNAL); if Result = 0 then FLastError := WSAECONNRESET else SockCheck(Result); ExceptCheck; if Result > 0 then begin Inc(FRecvCounter, Result); DoStatus(HR_ReadCount, IntToStr(Result)); DoMonitor(False, Buffer, Result); DoReadFilter(Buffer, Result); end; end; function TBlockSocket.RecvBufferEx(Buffer: TMemory; Len: Integer; Timeout: Integer): Integer; var s: AnsiString; rl, l: integer; ti: LongWord; {$IFDEF CIL} n: integer; b: TMemory; {$ENDIF} begin ResetLastError; Result := 0; if Len > 0 then begin rl := 0; repeat ti := GetTick; s := RecvPacket(Timeout); l := Length(s); if (rl + l) > Len then l := Len - rl; {$IFDEF CIL} b := BytesOf(s); for n := 0 to l do Buffer[rl + n] := b[n]; {$ELSE} Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); {$ENDIF} rl := rl + l; if FLastError <> 0 then Break; if rl >= Len then Break; if not FInterPacketTimeout then begin Timeout := Timeout - integer(TickDelta(ti, GetTick)); if Timeout <= 0 then begin FLastError := WSAETIMEDOUT; Break; end; end; until False; delete(s, 1, l); FBuffer := s; Result := rl; end; end; function TBlockSocket.RecvBufferStr(Len: Integer; Timeout: Integer): AnsiString; var x: integer; {$IFDEF CIL} buf: Tmemory; {$ENDIF} begin Result := ''; if Len > 0 then begin {$IFDEF CIL} Setlength(Buf, Len); x := RecvBufferEx(buf, Len , Timeout); if FLastError = 0 then begin SetLength(Buf, x); Result := StringOf(buf); end else Result := ''; {$ELSE} Setlength(Result, Len); x := RecvBufferEx(Pointer(Result), Len , Timeout); if FLastError = 0 then SetLength(Result, x) else Result := ''; {$ENDIF} end; end; function TBlockSocket.RecvPacket(Timeout: Integer): AnsiString; var x: integer; {$IFDEF CIL} buf: TMemory; {$ENDIF} begin Result := ''; ResetLastError; if FBuffer <> '' then begin Result := FBuffer; FBuffer := ''; end else begin {$IFDEF MSWINDOWS} //not drain CPU on large downloads... Sleep(0); {$ENDIF} x := WaitingData; if x > 0 then begin {$IFDEF CIL} SetLength(Buf, x); x := RecvBuffer(Buf, x); if x >= 0 then begin SetLength(Buf, x); Result := StringOf(Buf); end; {$ELSE} SetLength(Result, x); x := RecvBuffer(Pointer(Result), x); if x >= 0 then SetLength(Result, x); {$ENDIF} end else begin if CanRead(Timeout) then begin x := WaitingData; if x = 0 then FLastError := WSAECONNRESET; if x > 0 then begin {$IFDEF CIL} SetLength(Buf, x); x := RecvBuffer(Buf, x); if x >= 0 then begin SetLength(Buf, x); result := StringOf(Buf); end; {$ELSE} SetLength(Result, x); x := RecvBuffer(Pointer(Result), x); if x >= 0 then SetLength(Result, x); {$ENDIF} end; end else FLastError := WSAETIMEDOUT; end; end; if FConvertLineEnd and (Result <> '') then begin if FLastCR and (Result[1] = LF) then Delete(Result, 1, 1); if FLastLF and (Result[1] = CR) then Delete(Result, 1, 1); FLastCR := False; FLastLF := False; end; ExceptCheck; end; function TBlockSocket.RecvByte(Timeout: Integer): Byte; begin Result := 0; ResetLastError; if FBuffer = '' then FBuffer := RecvPacket(Timeout); if (FLastError = 0) and (FBuffer <> '') then begin Result := Ord(FBuffer[1]); Delete(FBuffer, 1, 1); end; ExceptCheck; end; function TBlockSocket.RecvInteger(Timeout: Integer): Integer; var s: AnsiString; begin Result := 0; s := RecvBufferStr(4, Timeout); if FLastError = 0 then Result := (ord(s[1]) + ord(s[2]) * 256) + (ord(s[3]) + ord(s[4]) * 256) * 65536; end; function TBlockSocket.RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; var x: Integer; s: AnsiString; l: Integer; CorCRLF: Boolean; t: AnsiString; tl: integer; ti: LongWord; begin ResetLastError; Result := ''; l := Length(Terminator); if l = 0 then Exit; tl := l; CorCRLF := FConvertLineEnd and (Terminator = CRLF); s := ''; x := 0; repeat //get rest of FBuffer or incomming new data... ti := GetTick; s := s + RecvPacket(Timeout); if FLastError <> 0 then Break; x := 0; if Length(s) > 0 then if CorCRLF then begin t := ''; x := PosCRLF(s, t); tl := Length(t); if t = CR then FLastCR := True; if t = LF then FLastLF := True; end else begin x := pos(Terminator, s); tl := l; end; if (FMaxLineLength <> 0) and (Length(s) > FMaxLineLength) then begin FLastError := WSAENOBUFS; Break; end; if x > 0 then Break; if not FInterPacketTimeout then begin Timeout := Timeout - integer(TickDelta(ti, GetTick)); if Timeout <= 0 then begin FLastError := WSAETIMEDOUT; Break; end; end; until False; if x > 0 then begin Result := Copy(s, 1, x - 1); Delete(s, 1, x + tl - 1); end; FBuffer := s; ExceptCheck; end; function TBlockSocket.RecvString(Timeout: Integer): AnsiString; var s: AnsiString; begin Result := ''; s := RecvTerminated(Timeout, CRLF); if FLastError = 0 then Result := s; end; function TBlockSocket.RecvBlock(Timeout: Integer): AnsiString; var x: integer; begin Result := ''; x := RecvInteger(Timeout); if FLastError = 0 then Result := RecvBufferStr(x, Timeout); end; procedure TBlockSocket.RecvStreamRaw(const Stream: TStream; Timeout: Integer); var s: AnsiString; begin repeat s := RecvPacket(Timeout); if (Length(s) = 0) then Break; if FLastError = 0 then WriteStrToStream(Stream, s); until FLastError <> 0; end; procedure TBlockSocket.RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: int64); var s: AnsiString; n: int64; {$IFDEF CIL} buf: TMemory; {$ENDIF} begin n := Size div int64(FSendMaxChunk); while n > 0 do begin {$IFDEF CIL} SetLength(buf, FSendMaxChunk); RecvBufferEx(buf, FSendMaxChunk, Timeout); if FLastError <> 0 then Exit; Stream.Write(buf, FSendMaxChunk); {$ELSE} s := RecvBufferStr(FSendMaxChunk, Timeout); if FLastError <> 0 then Exit; WriteStrToStream(Stream, s); {$ENDIF} dec(n); end; n := Size mod int64(FSendMaxChunk); if n > 0 then begin {$IFDEF CIL} SetLength(buf, n); RecvBufferEx(buf, n, Timeout); if FLastError <> 0 then Exit; Stream.Write(buf, n); {$ELSE} s := RecvBufferStr(n, Timeout); if FLastError <> 0 then Exit; WriteStrToStream(Stream, s); {$ENDIF} end; end; procedure TBlockSocket.RecvStreamIndy(const Stream: TStream; Timeout: Integer); var x: integer; begin x := RecvInteger(Timeout); x := synsock.NToHL(x); if FLastError = 0 then RecvStreamSize(Stream, Timeout, x); end; procedure TBlockSocket.RecvStream(const Stream: TStream; Timeout: Integer); var x: integer; begin x := RecvInteger(Timeout); if FLastError = 0 then RecvStreamSize(Stream, Timeout, x); end; function TBlockSocket.PeekBuffer(Buffer: TMemory; Length: Integer): Integer; begin {$IFNDEF CIL} // Result := synsock.Recv(FSocket, Buffer^, Length, MSG_PEEK + MSG_NOSIGNAL); Result := synsock.Recv(FSocket, Buffer, Length, MSG_PEEK + MSG_NOSIGNAL); SockCheck(Result); ExceptCheck; {$ENDIF} end; function TBlockSocket.PeekByte(Timeout: Integer): Byte; var s: string; begin {$IFNDEF CIL} Result := 0; if CanRead(Timeout) then begin SetLength(s, 1); PeekBuffer(Pointer(s), 1); if s <> '' then Result := Ord(s[1]); end else FLastError := WSAETIMEDOUT; ExceptCheck; {$ENDIF} end; procedure TBlockSocket.ResetLastError; begin FLastError := 0; FLastErrorDesc := ''; end; function TBlockSocket.SockCheck(SockResult: Integer): Integer; begin ResetLastError; if SockResult = integer(SOCKET_ERROR) then begin FLastError := synsock.WSAGetLastError; FLastErrorDesc := GetErrorDescEx; end; Result := FLastError; end; procedure TBlockSocket.ExceptCheck; var e: ESynapseError; begin FLastErrorDesc := GetErrorDescEx; if (LastError <> 0) and (LastError <> WSAEINPROGRESS) and (LastError <> WSAEWOULDBLOCK) then begin DoStatus(HR_Error, IntToStr(FLastError) + ',' + FLastErrorDesc); if FRaiseExcept then begin e := ESynapseError.Create(Format('Synapse TCP/IP Socket error %d: %s', [FLastError, FLastErrorDesc])); e.ErrorCode := FLastError; e.ErrorMessage := FLastErrorDesc; raise e; end; end; end; function TBlockSocket.WaitingData: Integer; var x: Integer; begin Result := 0; if synsock.IoctlSocket(FSocket, FIONREAD, x) = 0 then Result := x; if Result > c64k then Result := c64k; end; function TBlockSocket.WaitingDataEx: Integer; begin if FBuffer <> '' then Result := Length(FBuffer) else Result := WaitingData; end; procedure TBlockSocket.Purge; begin Sleep(1); try while (Length(FBuffer) > 0) or (WaitingData > 0) do begin RecvPacket(0); if FLastError <> 0 then break; end; except on exception do; end; ResetLastError; end; procedure TBlockSocket.SetLinger(Enable: Boolean; Linger: Integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_Linger; d.Enabled := Enable; d.Value := Linger; DelayedOption(d); end; function TBlockSocket.LocalName: string; begin Result := synsock.GetHostName; if Result = '' then Result := '127.0.0.1'; end; procedure TBlockSocket.ResolveNameToIP(Name: string; const IPList: TStrings); begin IPList.Clear; synsock.ResolveNameToIP(Name, FamilyToAF(FFamily), GetSocketprotocol, GetSocketType, IPList); if IPList.Count = 0 then IPList.Add(cAnyHost); end; function TBlockSocket.ResolveName(Name: string): string; var l: TStringList; begin l := TStringList.Create; try ResolveNameToIP(Name, l); Result := l[0]; finally l.Free; end; end; function TBlockSocket.ResolvePort(Port: string): Word; begin Result := synsock.ResolvePort(Port, FamilyToAF(FFamily), GetSocketProtocol, GetSocketType); end; function TBlockSocket.ResolveIPToName(IP: string): string; begin if not IsIP(IP) and not IsIp6(IP) then IP := ResolveName(IP); Result := synsock.ResolveIPToName(IP, FamilyToAF(FFamily), GetSocketProtocol, GetSocketType); end; procedure TBlockSocket.SetRemoteSin(IP, Port: string); begin SetSin(FRemoteSin, IP, Port); end; function TBlockSocket.GetLocalSinIP: string; begin Result := GetSinIP(FLocalSin); end; function TBlockSocket.GetRemoteSinIP: string; begin Result := GetSinIP(FRemoteSin); end; function TBlockSocket.GetLocalSinPort: Integer; begin Result := GetSinPort(FLocalSin); end; function TBlockSocket.GetRemoteSinPort: Integer; begin Result := GetSinPort(FRemoteSin); end; function TBlockSocket.InternalCanRead(Timeout: Integer): Boolean; {$IFDEF CIL} begin Result := FSocket.Poll(Timeout * 1000, SelectMode.SelectRead); {$ELSE} var TimeVal: PTimeVal; TimeV: TTimeVal; x: Integer; FDSet: TFDSet; begin TimeV.tv_usec := (Timeout mod 1000) * 1000; TimeV.tv_sec := Timeout div 1000; TimeVal := @TimeV; if Timeout = -1 then TimeVal := nil; FDSet := FFdSet; x := synsock.Select(FSocket + 1, @FDSet, nil, nil, TimeVal); SockCheck(x); if FLastError <> 0 then x := 0; Result := x > 0; {$ENDIF} end; function TBlockSocket.CanRead(Timeout: Integer): Boolean; var ti, tr: Integer; n: integer; begin if (FHeartbeatRate <> 0) and (Timeout <> -1) then begin ti := Timeout div FHeartbeatRate; tr := Timeout mod FHeartbeatRate; end else begin ti := 0; tr := Timeout; end; Result := InternalCanRead(tr); if not Result then for n := 0 to ti do begin DoHeartbeat; if FStopFlag then begin Result := False; FStopFlag := False; Break; end; Result := InternalCanRead(FHeartbeatRate); if Result then break; end; ExceptCheck; if Result then DoStatus(HR_CanRead, ''); end; function TBlockSocket.InternalCanWrite(Timeout: Integer): Boolean; {$IFDEF CIL} begin Result := FSocket.Poll(Timeout * 1000, SelectMode.SelectWrite); {$ELSE} var TimeVal: PTimeVal; TimeV: TTimeVal; x: Integer; FDSet: TFDSet; begin TimeV.tv_usec := (Timeout mod 1000) * 1000; TimeV.tv_sec := Timeout div 1000; TimeVal := @TimeV; if Timeout = -1 then TimeVal := nil; FDSet := FFdSet; x := synsock.Select(FSocket + 1, nil, @FDSet, nil, TimeVal); SockCheck(x); if FLastError <> 0 then x := 0; Result := x > 0; {$ENDIF} end; function TBlockSocket.CanWrite(Timeout: Integer): Boolean; var ti, tr: Integer; n: integer; begin if (FHeartbeatRate <> 0) and (Timeout <> -1) then begin ti := Timeout div FHeartbeatRate; tr := Timeout mod FHeartbeatRate; end else begin ti := 0; tr := Timeout; end; Result := InternalCanWrite(tr); if not Result then for n := 0 to ti do begin DoHeartbeat; if FStopFlag then begin Result := False; FStopFlag := False; Break; end; Result := InternalCanWrite(FHeartbeatRate); if Result then break; end; ExceptCheck; if Result then DoStatus(HR_CanWrite, ''); end; function TBlockSocket.CanReadEx(Timeout: Integer): Boolean; begin if FBuffer <> '' then Result := True else Result := CanRead(Timeout); end; function TBlockSocket.SendBufferTo(const Buffer: TMemory; Length: Integer): Integer; begin Result := 0; if TestStopFlag then Exit; DoMonitor(True, Buffer, Length); LimitBandwidth(Length, FMaxSendBandwidth, FNextsend); Result := synsock.SendTo(FSocket, Buffer, Length, MSG_NOSIGNAL, FRemoteSin); SockCheck(Result); ExceptCheck; Inc(FSendCounter, Result); DoStatus(HR_WriteCount, IntToStr(Result)); end; function TBlockSocket.RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; begin Result := 0; if TestStopFlag then Exit; LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); Result := synsock.RecvFrom(FSocket, Buffer, Length, MSG_NOSIGNAL, FRemoteSin); SockCheck(Result); ExceptCheck; Inc(FRecvCounter, Result); DoStatus(HR_ReadCount, IntToStr(Result)); DoMonitor(False, Buffer, Result); end; function TBlockSocket.GetSizeRecvBuffer: Integer; var l: Integer; {$IFDEF CIL} buf: TMemory; {$ENDIF} begin {$IFDEF CIL} setlength(buf, 4); SockCheck(synsock.GetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVBUF), buf, l)); Result := System.BitConverter.ToInt32(buf,0); {$ELSE} l := SizeOf(Result); SockCheck(synsock.GetSockOpt(FSocket, SOL_SOCKET, SO_RCVBUF, @Result, l)); if FLastError <> 0 then Result := 1024; ExceptCheck; {$ENDIF} end; procedure TBlockSocket.SetSizeRecvBuffer(Size: Integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_RecvBuff; d.Value := Size; DelayedOption(d); end; function TBlockSocket.GetSizeSendBuffer: Integer; var l: Integer; {$IFDEF CIL} buf: TMemory; {$ENDIF} begin {$IFDEF CIL} setlength(buf, 4); SockCheck(synsock.GetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDBUF), buf, l)); Result := System.BitConverter.ToInt32(buf,0); {$ELSE} l := SizeOf(Result); SockCheck(synsock.GetSockOpt(FSocket, SOL_SOCKET, SO_SNDBUF, @Result, l)); if FLastError <> 0 then Result := 1024; ExceptCheck; {$ENDIF} end; procedure TBlockSocket.SetSizeSendBuffer(Size: Integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_SendBuff; d.Value := Size; DelayedOption(d); end; procedure TBlockSocket.SetNonBlockMode(Value: Boolean); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_nonblock; d.Enabled := Value; DelayedOption(d); end; procedure TBlockSocket.SetTimeout(Timeout: Integer); begin SetSendTimeout(Timeout); SetRecvTimeout(Timeout); end; procedure TBlockSocket.SetSendTimeout(Timeout: Integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_sendtimeout; d.Value := Timeout; DelayedOption(d); end; procedure TBlockSocket.SetRecvTimeout(Timeout: Integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_recvtimeout; d.Value := Timeout; DelayedOption(d); end; {$IFNDEF CIL} function TBlockSocket.GroupCanRead(const SocketList: TSocketList; Timeout: Integer; const CanReadList: TSocketList): boolean; var FDSet: TFDSet; TimeVal: PTimeVal; TimeV: TTimeVal; x, n: Integer; Max: Integer; begin TimeV.tv_usec := (Timeout mod 1000) * 1000; TimeV.tv_sec := Timeout div 1000; TimeVal := @TimeV; if Timeout = -1 then TimeVal := nil; FD_ZERO(FDSet); Max := 0; for n := 0 to SocketList.Count - 1 do if TObject(SocketList.Items[n]) is TBlockSocket then begin if TBlockSocket(SocketList.Items[n]).Socket > Max then Max := TBlockSocket(SocketList.Items[n]).Socket; FD_SET(TBlockSocket(SocketList.Items[n]).Socket, FDSet); end; x := synsock.Select(Max + 1, @FDSet, nil, nil, TimeVal); SockCheck(x); ExceptCheck; if FLastError <> 0 then x := 0; Result := x > 0; CanReadList.Clear; if Result then for n := 0 to SocketList.Count - 1 do if TObject(SocketList.Items[n]) is TBlockSocket then if FD_ISSET(TBlockSocket(SocketList.Items[n]).Socket, FDSet) then CanReadList.Add(TBlockSocket(SocketList.Items[n])); end; {$ENDIF} procedure TBlockSocket.EnableReuse(Value: Boolean); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_reuse; d.Enabled := Value; DelayedOption(d); end; procedure TBlockSocket.SetTTL(TTL: integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_TTL; d.Value := TTL; DelayedOption(d); end; function TBlockSocket.GetTTL:integer; var l: Integer; begin {$IFNDEF CIL} l := SizeOf(Result); if FIP6Used then synsock.GetSockOpt(FSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, @Result, l) else synsock.GetSockOpt(FSocket, IPPROTO_IP, IP_TTL, @Result, l); {$ENDIF} end; procedure TBlockSocket.SetFamily(Value: TSocketFamily); begin FFamily := Value; FFamilySave := Value; end; procedure TBlockSocket.SetSocket(Value: TSocket); begin FRecvCounter := 0; FSendCounter := 0; FSocket := Value; {$IFNDEF CIL} FD_ZERO(FFDSet); FD_SET(FSocket, FFDSet); {$ENDIF} GetSins; FIP6Used := FRemoteSin.AddressFamily = AF_INET6; end; function TBlockSocket.GetWsaData: TWSAData; begin {$IFDEF ONCEWINSOCK} Result := WsaDataOnce; {$ELSE} Result := FWsaDataOnce; {$ENDIF} end; function TBlockSocket.GetSocketType: integer; begin Result := 0; end; function TBlockSocket.GetSocketProtocol: integer; begin Result := integer(IPPROTO_IP); end; procedure TBlockSocket.DoStatus(Reason: THookSocketReason; const Value: string); begin if assigned(OnStatus) then OnStatus(Self, Reason, Value); end; procedure TBlockSocket.DoReadFilter(Buffer: TMemory; var Len: Integer); var s: AnsiString; begin if assigned(OnReadFilter) then if Len > 0 then begin {$IFDEF CIL} s := StringOf(Buffer); {$ELSE} SetLength(s, Len); Move(Buffer^, Pointer(s)^, Len); {$ENDIF} OnReadFilter(Self, s); if Length(s) > Len then SetLength(s, Len); Len := Length(s); {$IFDEF CIL} Buffer := BytesOf(s); {$ELSE} Move(Pointer(s)^, Buffer^, Len); {$ENDIF} end; end; procedure TBlockSocket.DoCreateSocket; begin if assigned(OnCreateSocket) then OnCreateSocket(Self); end; procedure TBlockSocket.DoMonitor(Writing: Boolean; const Buffer: TMemory; Len: Integer); begin if assigned(OnMonitor) then begin OnMonitor(Self, Writing, Buffer, Len); end; end; procedure TBlockSocket.DoHeartbeat; begin if assigned(OnHeartbeat) and (FHeartbeatRate <> 0) then begin OnHeartbeat(Self); end; end; function TBlockSocket.GetErrorDescEx: string; begin Result := GetErrorDesc(FLastError); end; class function TBlockSocket.GetErrorDesc(ErrorCode: Integer): string; begin {$IFDEF CIL} if ErrorCode = 0 then Result := '' else begin Result := WSAGetLastErrorDesc; if Result = '' then Result := 'Other Winsock error (' + IntToStr(ErrorCode) + ')'; end; {$ELSE} case ErrorCode of 0: Result := ''; WSAEINTR: {10004} Result := 'Interrupted system call'; WSAEBADF: {10009} Result := 'Bad file number'; WSAEACCES: {10013} Result := 'Permission denied'; WSAEFAULT: {10014} Result := 'Bad address'; WSAEINVAL: {10022} Result := 'Invalid argument'; WSAEMFILE: {10024} Result := 'Too many open files'; WSAEWOULDBLOCK: {10035} Result := 'Operation would block'; WSAEINPROGRESS: {10036} Result := 'Operation now in progress'; WSAEALREADY: {10037} Result := 'Operation already in progress'; WSAENOTSOCK: {10038} Result := 'Socket operation on nonsocket'; WSAEDESTADDRREQ: {10039} Result := 'Destination address required'; WSAEMSGSIZE: {10040} Result := 'Message too long'; WSAEPROTOTYPE: {10041} Result := 'Protocol wrong type for Socket'; WSAENOPROTOOPT: {10042} Result := 'Protocol not available'; WSAEPROTONOSUPPORT: {10043} Result := 'Protocol not supported'; WSAESOCKTNOSUPPORT: {10044} Result := 'Socket not supported'; WSAEOPNOTSUPP: {10045} Result := 'Operation not supported on Socket'; WSAEPFNOSUPPORT: {10046} Result := 'Protocol family not supported'; WSAEAFNOSUPPORT: {10047} Result := 'Address family not supported'; WSAEADDRINUSE: {10048} Result := 'Address already in use'; WSAEADDRNOTAVAIL: {10049} Result := 'Can''t assign requested address'; WSAENETDOWN: {10050} Result := 'Network is down'; WSAENETUNREACH: {10051} Result := 'Network is unreachable'; WSAENETRESET: {10052} Result := 'Network dropped connection on reset'; WSAECONNABORTED: {10053} Result := 'Software caused connection abort'; WSAECONNRESET: {10054} Result := 'Connection reset by peer'; WSAENOBUFS: {10055} Result := 'No Buffer space available'; WSAEISCONN: {10056} Result := 'Socket is already connected'; WSAENOTCONN: {10057} Result := 'Socket is not connected'; WSAESHUTDOWN: {10058} Result := 'Can''t send after Socket shutdown'; WSAETOOMANYREFS: {10059} Result := 'Too many references:can''t splice'; WSAETIMEDOUT: {10060} Result := 'Connection timed out'; WSAECONNREFUSED: {10061} Result := 'Connection refused'; WSAELOOP: {10062} Result := 'Too many levels of symbolic links'; WSAENAMETOOLONG: {10063} Result := 'File name is too long'; WSAEHOSTDOWN: {10064} Result := 'Host is down'; WSAEHOSTUNREACH: {10065} Result := 'No route to host'; WSAENOTEMPTY: {10066} Result := 'Directory is not empty'; WSAEPROCLIM: {10067} Result := 'Too many processes'; WSAEUSERS: {10068} Result := 'Too many users'; WSAEDQUOT: {10069} Result := 'Disk quota exceeded'; WSAESTALE: {10070} Result := 'Stale NFS file handle'; WSAEREMOTE: {10071} Result := 'Too many levels of remote in path'; WSASYSNOTREADY: {10091} Result := 'Network subsystem is unusable'; WSAVERNOTSUPPORTED: {10092} Result := 'Winsock DLL cannot support this application'; WSANOTINITIALISED: {10093} Result := 'Winsock not initialized'; WSAEDISCON: {10101} Result := 'Disconnect'; WSAHOST_NOT_FOUND: {11001} Result := 'Host not found'; WSATRY_AGAIN: {11002} Result := 'Non authoritative - host not found'; WSANO_RECOVERY: {11003} Result := 'Non recoverable error'; WSANO_DATA: {11004} Result := 'Valid name, no data record of requested type' else Result := 'Other Winsock error (' + IntToStr(ErrorCode) + ')'; end; {$ENDIF} end; {======================================================================} constructor TSocksBlockSocket.Create; begin inherited Create; FSocksIP:= ''; FSocksPort:= '1080'; FSocksTimeout:= 60000; FSocksUsername:= ''; FSocksPassword:= ''; FUsingSocks := False; FSocksResolver := True; FSocksLastError := 0; FSocksResponseIP := ''; FSocksResponsePort := ''; FSocksLocalIP := ''; FSocksLocalPort := ''; FSocksRemoteIP := ''; FSocksRemotePort := ''; FBypassFlag := False; FSocksType := ST_Socks5; end; function TSocksBlockSocket.SocksOpen: boolean; var Buf: AnsiString; n: integer; begin Result := False; FUsingSocks := False; if FSocksType <> ST_Socks5 then begin FUsingSocks := True; Result := True; end else begin FBypassFlag := True; try if FSocksUsername = '' then Buf := #5 + #1 + #0 else Buf := #5 + #2 + #2 +#0; SendString(Buf); Buf := RecvBufferStr(2, FSocksTimeout); if Length(Buf) < 2 then Exit; if Buf[1] <> #5 then Exit; n := Ord(Buf[2]); case n of 0: //not need authorisation ; 2: begin Buf := #1 + AnsiChar(Length(FSocksUsername)) + FSocksUsername + AnsiChar(Length(FSocksPassword)) + FSocksPassword; SendString(Buf); Buf := RecvBufferStr(2, FSocksTimeout); if Length(Buf) < 2 then Exit; if Buf[2] <> #0 then Exit; end; else //other authorisation is not supported! Exit; end; FUsingSocks := True; Result := True; finally FBypassFlag := False; end; end; end; function TSocksBlockSocket.SocksRequest(Cmd: Byte; const IP, Port: string): Boolean; var Buf: AnsiString; begin FBypassFlag := True; try if FSocksType <> ST_Socks5 then Buf := #4 + AnsiChar(Cmd) + SocksCode(IP, Port) else Buf := #5 + AnsiChar(Cmd) + #0 + SocksCode(IP, Port); SendString(Buf); Result := FLastError = 0; finally FBypassFlag := False; end; end; function TSocksBlockSocket.SocksResponse: Boolean; var Buf, s: AnsiString; x: integer; begin Result := False; FBypassFlag := True; try FSocksResponseIP := ''; FSocksResponsePort := ''; FSocksLastError := -1; if FSocksType <> ST_Socks5 then begin Buf := RecvBufferStr(8, FSocksTimeout); if FLastError <> 0 then Exit; if Buf[1] <> #0 then Exit; FSocksLastError := Ord(Buf[2]); end else begin Buf := RecvBufferStr(4, FSocksTimeout); if FLastError <> 0 then Exit; if Buf[1] <> #5 then Exit; case Ord(Buf[4]) of 1: s := RecvBufferStr(4, FSocksTimeout); 3: begin x := RecvByte(FSocksTimeout); if FLastError <> 0 then Exit; s := AnsiChar(x) + RecvBufferStr(x, FSocksTimeout); end; 4: s := RecvBufferStr(16, FSocksTimeout); else Exit; end; Buf := Buf + s + RecvBufferStr(2, FSocksTimeout); if FLastError <> 0 then Exit; FSocksLastError := Ord(Buf[2]); end; if ((FSocksLastError <> 0) and (FSocksLastError <> 90)) then Exit; SocksDecode(Buf); Result := True; finally FBypassFlag := False; end; end; function TSocksBlockSocket.SocksCode(IP, Port: string): Ansistring; var ip6: TIp6Bytes; n: integer; begin if FSocksType <> ST_Socks5 then begin Result := CodeInt(ResolvePort(Port)); if not FSocksResolver then IP := ResolveName(IP); if IsIP(IP) then begin Result := Result + IPToID(IP); Result := Result + FSocksUsername + #0; end else begin Result := Result + IPToID('0.0.0.1'); Result := Result + FSocksUsername + #0; Result := Result + IP + #0; end; end else begin if not FSocksResolver then IP := ResolveName(IP); if IsIP(IP) then Result := #1 + IPToID(IP) else if IsIP6(IP) then begin ip6 := StrToIP6(IP); Result := #4; for n := 0 to 15 do Result := Result + AnsiChar(ip6[n]); end else Result := #3 + AnsiChar(Length(IP)) + IP; Result := Result + CodeInt(ResolvePort(Port)); end; end; function TSocksBlockSocket.SocksDecode(Value: Ansistring): integer; var Atyp: Byte; y, n: integer; w: Word; ip6: TIp6Bytes; begin FSocksResponsePort := '0'; Result := 0; if FSocksType <> ST_Socks5 then begin if Length(Value) < 8 then Exit; Result := 3; w := DecodeInt(Value, Result); FSocksResponsePort := IntToStr(w); FSocksResponseIP := Format('%d.%d.%d.%d', [Ord(Value[5]), Ord(Value[6]), Ord(Value[7]), Ord(Value[8])]); Result := 9; end else begin if Length(Value) < 4 then Exit; Atyp := Ord(Value[4]); Result := 5; case Atyp of 1: begin if Length(Value) < 10 then Exit; FSocksResponseIP := Format('%d.%d.%d.%d', [Ord(Value[5]), Ord(Value[6]), Ord(Value[7]), Ord(Value[8])]); Result := 9; end; 3: begin y := Ord(Value[5]); if Length(Value) < (5 + y + 2) then Exit; for n := 6 to 6 + y - 1 do FSocksResponseIP := FSocksResponseIP + Value[n]; Result := 5 + y + 1; end; 4: begin if Length(Value) < 22 then Exit; for n := 0 to 15 do ip6[n] := ord(Value[n + 5]); FSocksResponseIP := IP6ToStr(ip6); Result := 21; end; else Exit; end; w := DecodeInt(Value, Result); FSocksResponsePort := IntToStr(w); Result := Result + 2; end; end; {======================================================================} procedure TDgramBlockSocket.Connect(IP, Port: string); begin SetRemoteSin(IP, Port); InternalCreateSocket(FRemoteSin); FBuffer := ''; DoStatus(HR_Connect, IP + ':' + Port); end; function TDgramBlockSocket.RecvBuffer(Buffer: TMemory; Length: Integer): Integer; begin Result := RecvBufferFrom(Buffer, Length); end; function TDgramBlockSocket.SendBuffer(const Buffer: TMemory; Length: Integer): Integer; begin Result := SendBufferTo(Buffer, Length); end; {======================================================================} destructor TUDPBlockSocket.Destroy; begin if Assigned(FSocksControlSock) then FSocksControlSock.Free; inherited; end; procedure TUDPBlockSocket.EnableBroadcast(Value: Boolean); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_Broadcast; d.Enabled := Value; DelayedOption(d); end; function TUDPBlockSocket.UdpAssociation: Boolean; var b: Boolean; begin Result := True; FUsingSocks := False; if FSocksIP <> '' then begin Result := False; if not Assigned(FSocksControlSock) then FSocksControlSock := TTCPBlockSocket.Create; FSocksControlSock.CloseSocket; FSocksControlSock.CreateSocketByName(FSocksIP); FSocksControlSock.Connect(FSocksIP, FSocksPort); if FSocksControlSock.LastError <> 0 then Exit; // if not assigned local port, assign it! if not FBinded then Bind(cAnyHost, cAnyPort); //open control TCP connection to SOCKS FSocksControlSock.FSocksUsername := FSocksUsername; FSocksControlSock.FSocksPassword := FSocksPassword; b := FSocksControlSock.SocksOpen; if b then b := FSocksControlSock.SocksRequest(3, GetLocalSinIP, IntToStr(GetLocalSinPort)); if b then b := FSocksControlSock.SocksResponse; if not b and (FLastError = 0) then FLastError := WSANO_RECOVERY; FUsingSocks :=FSocksControlSock.UsingSocks; FSocksRemoteIP := FSocksControlSock.FSocksResponseIP; FSocksRemotePort := FSocksControlSock.FSocksResponsePort; Result := b and (FLastError = 0); end; end; function TUDPBlockSocket.SendBufferTo(const Buffer: TMemory; Length: Integer): Integer; var SIp: string; SPort: integer; Buf: Ansistring; begin Result := 0; FUsingSocks := False; if (FSocksIP <> '') and (not UdpAssociation) then FLastError := WSANO_RECOVERY else begin if FUsingSocks then begin {$IFNDEF CIL} Sip := GetRemoteSinIp; SPort := GetRemoteSinPort; SetRemoteSin(FSocksRemoteIP, FSocksRemotePort); SetLength(Buf,Length); Move(Buffer^, Pointer(Buf)^, Length); Buf := #0 + #0 + #0 + SocksCode(Sip, IntToStr(SPort)) + Buf; Result := inherited SendBufferTo(Pointer(Buf), System.Length(buf)); SetRemoteSin(Sip, IntToStr(SPort)); {$ENDIF} end else Result := inherited SendBufferTo(Buffer, Length); end; end; function TUDPBlockSocket.RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; var Buf: Ansistring; x: integer; begin Result := inherited RecvBufferFrom(Buffer, Length); if FUsingSocks then begin {$IFNDEF CIL} SetLength(Buf, Result); Move(Buffer^, Pointer(Buf)^, Result); x := SocksDecode(Buf); Result := Result - x + 1; Buf := Copy(Buf, x, Result); Move(Pointer(Buf)^, Buffer^, Result); SetRemoteSin(FSocksResponseIP, FSocksResponsePort); {$ENDIF} end; end; {$IFNDEF CIL} procedure TUDPBlockSocket.AddMulticast(MCastIP: string); var Multicast: TIP_mreq; Multicast6: TIPv6_mreq; n: integer; ip6: Tip6bytes; begin if FIP6Used then begin ip6 := StrToIp6(MCastIP); for n := 0 to 15 do Multicast6.ipv6mr_multiaddr.{$IFDEF POSIX}s6_addr{$ELSE}u6_addr8{$ENDIF}[n] := Ip6[n]; Multicast6.ipv6mr_interface := 0; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, PAnsiChar(@Multicast6), SizeOf(Multicast6))); end else begin Multicast.imr_multiaddr.S_addr := swapbytes(strtoip(MCastIP)); // Multicast.imr_interface.S_addr := INADDR_ANY; Multicast.imr_interface.S_addr := FLocalSin.sin_addr.S_addr; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, PAnsiChar(@Multicast), SizeOf(Multicast))); end; ExceptCheck; end; procedure TUDPBlockSocket.DropMulticast(MCastIP: string); var Multicast: TIP_mreq; Multicast6: TIPv6_mreq; n: integer; ip6: Tip6bytes; begin if FIP6Used then begin ip6 := StrToIp6(MCastIP); for n := 0 to 15 do Multicast6.ipv6mr_multiaddr.{$IFDEF POSIX}s6_addr{$ELSE}u6_addr8{$ENDIF}[n] := Ip6[n]; Multicast6.ipv6mr_interface := 0; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, PAnsiChar(@Multicast6), SizeOf(Multicast6))); end else begin Multicast.imr_multiaddr.S_addr := swapbytes(strtoip(MCastIP)); // Multicast.imr_interface.S_addr := INADDR_ANY; Multicast.imr_interface.S_addr := FLocalSin.sin_addr.S_addr; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, PAnsiChar(@Multicast), SizeOf(Multicast))); end; ExceptCheck; end; {$ENDIF} procedure TUDPBlockSocket.SetMulticastTTL(TTL: integer); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_MulticastTTL; d.Value := TTL; DelayedOption(d); end; function TUDPBlockSocket.GetMulticastTTL:integer; var l: Integer; begin {$IFNDEF CIL} l := SizeOf(Result); if FIP6Used then synsock.GetSockOpt(FSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, @Result, l) else synsock.GetSockOpt(FSocket, IPPROTO_IP, IP_MULTICAST_TTL, @Result, l); {$ENDIF} end; procedure TUDPBlockSocket.EnableMulticastLoop(Value: Boolean); var d: TSynaOption; begin d := TSynaOption.Create; d.Option := SOT_MulticastLoop; d.Enabled := Value; DelayedOption(d); end; function TUDPBlockSocket.GetSocketType: integer; begin Result := integer(SOCK_DGRAM); end; function TUDPBlockSocket.GetSocketProtocol: integer; begin Result := integer(IPPROTO_UDP); end; {======================================================================} constructor TTCPBlockSocket.CreateWithSSL(SSLPlugin: TSSLClass); begin inherited Create; FSSL := SSLPlugin.Create(self); FHTTPTunnelIP := ''; FHTTPTunnelPort := ''; FHTTPTunnel := False; FHTTPTunnelRemoteIP := ''; FHTTPTunnelRemotePort := ''; FHTTPTunnelUser := ''; FHTTPTunnelPass := ''; FHTTPTunnelTimeout := 30000; end; constructor TTCPBlockSocket.Create; begin CreateWithSSL(SSLImplementation); end; destructor TTCPBlockSocket.Destroy; begin inherited Destroy; FSSL.Free; end; function TTCPBlockSocket.GetErrorDescEx: string; begin Result := inherited GetErrorDescEx; if (FLastError = WSASYSNOTREADY) and (self.SSL.LastError <> 0) then begin Result := self.SSL.LastErrorDesc; end; end; procedure TTCPBlockSocket.CloseSocket; begin if FSSL.SSLEnabled then FSSL.Shutdown; if (FSocket <> INVALID_SOCKET) and (FLastError = 0) then begin Synsock.Shutdown(FSocket, 1); Purge; end; inherited CloseSocket; end; procedure TTCPBlockSocket.DoAfterConnect; begin if assigned(OnAfterConnect) then begin OnAfterConnect(Self); end; end; function TTCPBlockSocket.WaitingData: Integer; begin Result := 0; if FSSL.SSLEnabled and (FSocket <> INVALID_SOCKET) then Result := FSSL.WaitingData; if Result = 0 then Result := inherited WaitingData; end; procedure TTCPBlockSocket.Listen; var b: Boolean; Sip,SPort: string; begin if FSocksIP = '' then begin inherited Listen; end else begin Sip := GetLocalSinIP; if Sip = cAnyHost then Sip := LocalName; SPort := IntToStr(GetLocalSinPort); inherited Connect(FSocksIP, FSocksPort); b := SocksOpen; if b then b := SocksRequest(2, Sip, SPort); if b then b := SocksResponse; if not b and (FLastError = 0) then FLastError := WSANO_RECOVERY; FSocksLocalIP := FSocksResponseIP; if FSocksLocalIP = cAnyHost then FSocksLocalIP := FSocksIP; FSocksLocalPort := FSocksResponsePort; FSocksRemoteIP := ''; FSocksRemotePort := ''; ExceptCheck; DoStatus(HR_Listen, ''); end; end; function TTCPBlockSocket.Accept: TSocket; begin if FUsingSocks then begin if not SocksResponse and (FLastError = 0) then FLastError := WSANO_RECOVERY; FSocksRemoteIP := FSocksResponseIP; FSocksRemotePort := FSocksResponsePort; Result := FSocket; ExceptCheck; DoStatus(HR_Accept, ''); end else begin result := inherited Accept; end; end; procedure TTCPBlockSocket.Connect(IP, Port: string); begin if FSocksIP <> '' then SocksDoConnect(IP, Port) else if FHTTPTunnelIP <> '' then HTTPTunnelDoConnect(IP, Port) else inherited Connect(IP, Port); if FLasterror = 0 then DoAfterConnect; end; procedure TTCPBlockSocket.SocksDoConnect(IP, Port: string); var b: Boolean; begin inherited Connect(FSocksIP, FSocksPort); if FLastError = 0 then begin b := SocksOpen; if b then b := SocksRequest(1, IP, Port); if b then b := SocksResponse; if not b and (FLastError = 0) then FLastError := WSASYSNOTREADY; FSocksLocalIP := FSocksResponseIP; FSocksLocalPort := FSocksResponsePort; FSocksRemoteIP := IP; FSocksRemotePort := Port; end; ExceptCheck; DoStatus(HR_Connect, IP + ':' + Port); end; procedure TTCPBlockSocket.HTTPTunnelDoConnect(IP, Port: string); //bugfixed by Mike Green (mgreen@emixode.com) var s: string; begin Port := IntToStr(ResolvePort(Port)); inherited Connect(FHTTPTunnelIP, FHTTPTunnelPort); if FLastError <> 0 then Exit; FHTTPTunnel := False; if IsIP6(IP) then IP := '[' + IP + ']'; SendString('CONNECT ' + IP + ':' + Port + ' HTTP/1.0' + CRLF); if FHTTPTunnelUser <> '' then Sendstring('Proxy-Authorization: Basic ' + EncodeBase64(FHTTPTunnelUser + ':' + FHTTPTunnelPass) + CRLF); SendString(CRLF); repeat s := RecvTerminated(FHTTPTunnelTimeout, #$0a); if FLastError <> 0 then Break; if (Pos('HTTP/', s) = 1) and (Length(s) > 11) then FHTTPTunnel := s[10] = '2'; until (s = '') or (s = #$0d); if (FLasterror = 0) and not FHTTPTunnel then FLastError := WSAECONNREFUSED; FHTTPTunnelRemoteIP := IP; FHTTPTunnelRemotePort := Port; ExceptCheck; end; procedure TTCPBlockSocket.SSLDoConnect; begin ResetLastError; if not FSSL.Connect then FLastError := WSASYSNOTREADY; ExceptCheck; end; procedure TTCPBlockSocket.SSLDoShutdown; begin ResetLastError; FSSL.BiShutdown; end; function TTCPBlockSocket.GetLocalSinIP: string; begin if FUsingSocks then Result := FSocksLocalIP else Result := inherited GetLocalSinIP; end; function TTCPBlockSocket.GetRemoteSinIP: string; begin if FUsingSocks then Result := FSocksRemoteIP else if FHTTPTunnel then Result := FHTTPTunnelRemoteIP else Result := inherited GetRemoteSinIP; end; function TTCPBlockSocket.GetLocalSinPort: Integer; begin if FUsingSocks then Result := StrToIntDef(FSocksLocalPort, 0) else Result := inherited GetLocalSinPort; end; function TTCPBlockSocket.GetRemoteSinPort: Integer; begin if FUsingSocks then Result := ResolvePort(FSocksRemotePort) else if FHTTPTunnel then Result := StrToIntDef(FHTTPTunnelRemotePort, 0) else Result := inherited GetRemoteSinPort; end; function TTCPBlockSocket.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; begin if FSSL.SSLEnabled then begin Result := 0; if TestStopFlag then Exit; ResetLastError; LimitBandwidth(Len, FMaxRecvBandwidth, FNextRecv); Result := FSSL.RecvBuffer(Buffer, Len); if FSSL.LastError <> 0 then FLastError := WSASYSNOTREADY; ExceptCheck; Inc(FRecvCounter, Result); DoStatus(HR_ReadCount, IntToStr(Result)); DoMonitor(False, Buffer, Result); DoReadFilter(Buffer, Result); end else Result := inherited RecvBuffer(Buffer, Len); end; function TTCPBlockSocket.SendBuffer(const Buffer: TMemory; Length: Integer): Integer; var x, y: integer; l, r: integer; {$IFNDEF CIL} p: Pointer; {$ENDIF} begin if FSSL.SSLEnabled then begin Result := 0; if TestStopFlag then Exit; ResetLastError; DoMonitor(True, Buffer, Length); {$IFDEF CIL} Result := FSSL.SendBuffer(Buffer, Length); if FSSL.LastError <> 0 then FLastError := WSASYSNOTREADY; Inc(FSendCounter, Result); DoStatus(HR_WriteCount, IntToStr(Result)); {$ELSE} l := Length; x := 0; while x < l do begin y := l - x; if y > FSendMaxChunk then y := FSendMaxChunk; if y > 0 then begin LimitBandwidth(y, FMaxSendBandwidth, FNextsend); p := IncPoint(Buffer, x); r := FSSL.SendBuffer(p, y); if FSSL.LastError <> 0 then FLastError := WSASYSNOTREADY; if Flasterror <> 0 then Break; Inc(x, r); Inc(Result, r); Inc(FSendCounter, r); DoStatus(HR_WriteCount, IntToStr(r)); end else break; end; {$ENDIF} ExceptCheck; end else Result := inherited SendBuffer(Buffer, Length); end; function TTCPBlockSocket.SSLAcceptConnection: Boolean; begin ResetLastError; if not FSSL.Accept then FLastError := WSASYSNOTREADY; ExceptCheck; Result := FLastError = 0; end; function TTCPBlockSocket.GetSocketType: integer; begin Result := integer(SOCK_STREAM); end; function TTCPBlockSocket.GetSocketProtocol: integer; begin Result := integer(IPPROTO_TCP); end; {======================================================================} function TICMPBlockSocket.GetSocketType: integer; begin Result := integer(SOCK_RAW); end; function TICMPBlockSocket.GetSocketProtocol: integer; begin if FIP6Used then Result := integer(IPPROTO_ICMPV6) else Result := integer(IPPROTO_ICMP); end; {======================================================================} function TRAWBlockSocket.GetSocketType: integer; begin Result := integer(SOCK_RAW); end; function TRAWBlockSocket.GetSocketProtocol: integer; begin Result := integer(IPPROTO_RAW); end; {======================================================================} function TPGMmessageBlockSocket.GetSocketType: integer; begin Result := integer(SOCK_RDM); end; function TPGMmessageBlockSocket.GetSocketProtocol: integer; begin Result := integer(IPPROTO_RM); end; {======================================================================} function TPGMstreamBlockSocket.GetSocketType: integer; begin Result := integer(SOCK_STREAM); end; function TPGMstreamBlockSocket.GetSocketProtocol: integer; begin Result := integer(IPPROTO_RM); end; {======================================================================} constructor TSynaClient.Create; begin inherited Create; FIPInterface := cAnyHost; FTargetHost := cLocalhost; FTargetPort := cAnyPort; FTimeout := 5000; FUsername := ''; FPassword := ''; end; {======================================================================} constructor TCustomSSL.Create(const Value: TTCPBlockSocket); begin inherited Create; FSocket := Value; FSSLEnabled := False; FUsername := ''; FPassword := ''; FLastError := 0; FLastErrorDesc := ''; FVerifyCert := False; FSSLType := LT_all; FKeyPassword := ''; FCiphers := ''; FCertificateFile := ''; FPrivateKeyFile := ''; FCertCAFile := ''; FCertCA := ''; FTrustCertificate := ''; FTrustCertificateFile := ''; FCertificate := ''; FPrivateKey := ''; FPFX := ''; FPFXfile := ''; FSSHChannelType := ''; FSSHChannelArg1 := ''; FSSHChannelArg2 := ''; FCertComplianceLevel := -1; //default FSNIHost := ''; end; procedure TCustomSSL.Assign(const Value: TCustomSSL); begin FUsername := Value.Username; FPassword := Value.Password; FVerifyCert := Value.VerifyCert; FSSLType := Value.SSLType; FKeyPassword := Value.KeyPassword; FCiphers := Value.Ciphers; FCertificateFile := Value.CertificateFile; FPrivateKeyFile := Value.PrivateKeyFile; FCertCAFile := Value.CertCAFile; FCertCA := Value.CertCA; FTrustCertificate := Value.TrustCertificate; FTrustCertificateFile := Value.TrustCertificateFile; FCertificate := Value.Certificate; FPrivateKey := Value.PrivateKey; FPFX := Value.PFX; FPFXfile := Value.PFXfile; FCertComplianceLevel := Value.CertComplianceLevel; FSNIHost := Value.FSNIHost; end; procedure TCustomSSL.ReturnError; begin FLastError := -1; FLastErrorDesc := 'SSL/TLS support is not compiled!'; end; function TCustomSSL.LibVersion: String; begin Result := ''; end; function TCustomSSL.LibName: String; begin Result := ''; end; function TCustomSSL.CreateSelfSignedCert(Host: string): Boolean; begin Result := False; end; function TCustomSSL.Connect: boolean; begin ReturnError; Result := False; end; function TCustomSSL.Accept: boolean; begin ReturnError; Result := False; end; function TCustomSSL.Shutdown: boolean; begin ReturnError; Result := False; end; function TCustomSSL.BiShutdown: boolean; begin ReturnError; Result := False; end; function TCustomSSL.SendBuffer(Buffer: TMemory; Len: Integer): Integer; begin ReturnError; Result := integer(SOCKET_ERROR); end; procedure TCustomSSL.SetCertCAFile(const Value: string); begin FCertCAFile := Value; end; function TCustomSSL.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; begin ReturnError; Result := integer(SOCKET_ERROR); end; function TCustomSSL.WaitingData: Integer; begin ReturnError; Result := 0; end; function TCustomSSL.GetSSLVersion: string; begin Result := ''; end; function TCustomSSL.GetPeerSubject: string; begin Result := ''; end; function TCustomSSL.GetPeerSerialNo: integer; begin Result := -1; end; function TCustomSSL.GetPeerName: string; begin Result := ''; end; function TCustomSSL.GetPeerNameHash: cardinal; begin Result := 0; end; function TCustomSSL.GetPeerIssuer: string; begin Result := ''; end; function TCustomSSL.GetPeerFingerprint: AnsiString; begin Result := ''; end; function TCustomSSL.GetCertInfo: string; begin Result := ''; end; function TCustomSSL.GetCipherName: string; begin Result := ''; end; function TCustomSSL.GetCipherBits: integer; begin Result := 0; end; function TCustomSSL.GetCipherAlgBits: integer; begin Result := 0; end; function TCustomSSL.GetVerifyCert: integer; begin Result := 1; end; function TCustomSSL.DoVerifyCert:boolean; begin if assigned(OnVerifyCert) then begin result:=OnVerifyCert(Self); end else result:=true; end; {======================================================================} function TSSLNone.LibVersion: String; begin Result := 'Without SSL support'; end; function TSSLNone.LibName: String; begin Result := 'ssl_none'; end; {======================================================================} initialization begin {$IFDEF ONCEWINSOCK} if not InitSocketInterface(DLLStackName) then begin e := ESynapseError.Create('Error loading Socket interface (' + DLLStackName + ')!'); e.ErrorCode := 0; e.ErrorMessage := 'Error loading Socket interface (' + DLLStackName + ')!'; raise e; end; synsock.WSAStartup(WinsockLevel, WsaDataOnce); {$ENDIF} end; finalization begin {$IFDEF ONCEWINSOCK} synsock.WSACleanup; DestroySocketInterface; {$ENDIF} end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/doublecmd.diff���������������������������������������������0000644�0001750�0000144�00000023050�14743153644�022136� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Index: ssfpc.inc =================================================================== --- ssfpc.inc (revision 209) +++ ssfpc.inc (working copy) @@ -67,6 +67,9 @@ {$ifdef darwin} {$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr {$endif} +{$ifdef haiku} +{$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr +{$endif} interface @@ -103,7 +106,9 @@ const FIONREAD = termio.FIONREAD; FIONBIO = termio.FIONBIO; +{$IFNDEF HAIKU} FIOASYNC = termio.FIOASYNC; +{$ENDIF} const IPPROTO_IP = 0; { Dummy } @@ -212,12 +217,21 @@ SOMAXCONN = 1024; +{$IFDEF HAIKU} + IPV6_UNICAST_HOPS = 27; +{$ELSE} IPV6_UNICAST_HOPS = sockets.IPV6_UNICAST_HOPS; +{$ENDIF} IPV6_MULTICAST_IF = sockets.IPV6_MULTICAST_IF; IPV6_MULTICAST_HOPS = sockets.IPV6_MULTICAST_HOPS; IPV6_MULTICAST_LOOP = sockets.IPV6_MULTICAST_LOOP; +{$IFDEF HAIKU} + IPV6_JOIN_GROUP = 28; + IPV6_LEAVE_GROUP = 29; +{$ELSE} IPV6_JOIN_GROUP = sockets.IPV6_JOIN_GROUP; IPV6_LEAVE_GROUP = sockets.IPV6_LEAVE_GROUP; +{$ENDIF} const SOCK_STREAM = 1; { stream socket } @@ -231,9 +245,9 @@ { Address families. } - AF_UNSPEC = 0; { unspecified } - AF_INET = 2; { internetwork: UDP, TCP, etc. } - AF_INET6 = 10; { Internetwork Version 6 } + AF_UNSPEC = 0; { unspecified } + AF_INET = sockets.AF_INET; { internetwork: UDP, TCP, etc. } + AF_INET6 = sockets.AF_INET6; { Internetwork Version 6 } AF_MAX = 24; { Protocol families, same as address families for now. } @@ -254,15 +268,31 @@ MSG_OOB = sockets.MSG_OOB; // Process out-of-band data. MSG_PEEK = sockets.MSG_PEEK; // Peek at incoming messages. - {$ifdef DARWIN} + {$if defined(DARWIN)} MSG_NOSIGNAL = $20000; // Do not generate SIGPIPE. // Works under MAC OS X, but is undocumented, // So FPC doesn't include it + {$elseif defined(HAIKU)} + MSG_NOSIGNAL = $0800; {$else} - MSG_NOSIGNAL = sockets.MSG_NOSIGNAL; // Do not generate SIGPIPE. + MSG_NOSIGNAL = sockets.MSG_NOSIGNAL; // Do not generate SIGPIPE. {$endif} +{$IF DEFINED(HAIKU)} const + ESysESTALE = (B_POSIX_ERROR_BASE + 40); + ESysENOTSOCK = (B_POSIX_ERROR_BASE + 44); + ESysEHOSTDOWN = (B_POSIX_ERROR_BASE + 45); + ESysEDESTADDRREQ = (B_POSIX_ERROR_BASE + 48); + ESysEDQUOT = (B_POSIX_ERROR_BASE + 49); + // Fake error codes + ESysEUSERS = (B_POSIX_ERROR_BASE + 128); + ESysEREMOTE = (B_POSIX_ERROR_BASE + 129); + ESysETOOMANYREFS = (B_POSIX_ERROR_BASE + 130); + ESysESOCKTNOSUPPORT = (B_POSIX_ERROR_BASE + 131); +{$ENDIF} + +const WSAEINTR = ESysEINTR; WSAEBADF = ESysEBADF; WSAEACCES = ESysEACCES; @@ -755,7 +785,7 @@ begin Result := 0; FillChar(Sin, Sizeof(Sin), 0); - Sin.sin_port := Resolveport(port, family, SockProtocol, SockType); + Sin.sin_port := htons(Resolveport(port, family, SockProtocol, SockType)); TwoPass := False; if Family = AF_UNSPEC then begin @@ -858,7 +888,7 @@ ProtoEnt: TProtocolEntry; ServEnt: TServiceEntry; begin - Result := synsock.htons(StrToIntDef(Port, 0)); + Result := StrToIntDef(Port, 0); if Result = 0 then begin ProtoEnt.Name := ''; @@ -865,7 +895,7 @@ GetProtocolByNumber(SockProtocol, ProtoEnt); ServEnt.port := 0; GetServiceByName(Port, ProtoEnt.Name, ServEnt); - Result := ServEnt.port; + Result := ntohs(ServEnt.port); end; end; Index: blcksock.pas =================================================================== --- blcksock.pas (revision 278) +++ blcksock.pas (working copy) @@ -1234,6 +1234,8 @@ TCustomSSL = class(TObject) private protected + FSessionOld: Pointer; + FSessionNew: Pointer; FOnVerifyCert: THookVerifyCert; FSocket: TTCPBlockSocket; FSSLEnabled: Boolean; @@ -1368,6 +1370,9 @@ {:Return error description of last SSL operation.} property LastErrorDesc: string read FLastErrorDesc; + + {:Used for session resumption } + property Session: Pointer read FSessionNew write FSessionOld; published {:Here you can specify requested SSL/TLS mode. Default is autodetection, but on some servers autodetection not working properly. In this case you must @@ -2518,6 +2523,8 @@ begin repeat s := RecvPacket(Timeout); + if (Length(s) = 0) then + Break; if FLastError = 0 then WriteStrToStream(Stream, s); until FLastError <> 0; Index: ftpsend.pas =================================================================== --- ftpsend.pas (revision 209) +++ ftpsend.pas (working copy) @@ -870,6 +870,11 @@ end; FDSock.CloseSocket; FDSock.Bind(FIPInterface, cAnyPort); + + if FIsDataTLS then begin + FDSock.SSL.Session := FSock.SSL.Session; + end; + FDSock.Connect(FDataIP, FDataPort); Result := FDSock.LastError = 0; end Index: ssl_openssl.pas =================================================================== --- ssl_openssl.pas (revision 278) +++ ssl_openssl.pas (working copy) @@ -77,8 +77,9 @@ accepting of new connections! } -{$INCLUDE 'jedi.inc'} - +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} {$H+} {$IFDEF UNICODE} @@ -86,7 +87,7 @@ {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} -unit ssl_openssl{$IFDEF SUPPORTS_DEPRECATED} deprecated{$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use ssl_openssl3 with OpenSSL 3.0 instead'{$ENDIF}{$ENDIF}; +unit ssl_openssl; interface @@ -495,6 +496,11 @@ function TSSLOpenSSL.DeInit: Boolean; begin Result := True; + if Assigned(FSessionNew) then + begin + SslSessionFree(FSessionNew); + FSessionNew := nil; + end; if assigned (Fssl) then sslfree(Fssl); Fssl := nil; @@ -538,6 +544,10 @@ SSLCheck; Exit; end; + // Reuse session + if Assigned(FSessionOld) then begin + SslSetSession(Fssl, FSessionOld); + end; if SNIHost<>'' then begin SSLCtrl(Fssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, PAnsiChar(AnsiString(SNIHost))); @@ -579,6 +589,9 @@ FSSLEnabled := True; Result := True; end; + if Result and (FSessionOld = nil) then begin + FSessionNew := SslGet1Session(Fssl); + end; end; function TSSLOpenSSL.Accept: boolean; Index: ssl_openssl_lib.pas =================================================================== --- ssl_openssl_lib.pas (revision 278) +++ ssl_openssl_lib.pas (working copy) @@ -813,6 +813,9 @@ function SSLGetVerifyResult(ssl: PSSL):Integer; function SSLCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; function SslSet1Host(ssl: PSSL; hostname: PAnsiChar):Integer; + procedure SslSessionFree(session: PSslPtr); + function SslGet1Session(ssl: PSSL):PSslPtr; + function SslSetSession(ssl: PSSL; session: PSslPtr): Integer; // libeay.dll function X509New: PX509; @@ -940,6 +943,9 @@ TSSLGetVerifyResult = function(ssl: PSSL):Integer; cdecl; TSSLCtrl = function(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; cdecl; TSslSet1Host = function(ssl: PSSL; hostname: PAnsiChar):Integer; cdecl; + TSslSessionFree = procedure(session: PSslPtr); cdecl; + TSslGet1Session = function(ssl: PSSL):PSslPtr; cdecl; + TSslSetSession = function(ssl: PSSL; session: PSslPtr): Integer; cdecl; TSSLSetTlsextHostName = function(ssl: PSSL; buf: PAnsiChar):Integer; cdecl; @@ -1049,6 +1055,9 @@ _SSLGetVerifyResult: TSSLGetVerifyResult = nil; _SSLCtrl: TSSLCtrl = nil; _SslSet1Host: TSslSet1Host = nil; + _SslSessionFree: TSslSessionFree = nil; + _SslGet1Session: TSslGet1Session = nil; + _SslSetSession: TSslSetSession = nil; // libeay.dll _X509New: TX509New = nil; @@ -1474,6 +1483,28 @@ Result := 0; end; +procedure SslSessionFree(session: PSslPtr); +begin + if InitSSLInterface and Assigned(_SslSessionFree) then + _SslSessionFree(session); +end; + +function SslGet1Session(ssl: PSSL): PSslPtr; +begin + if InitSSLInterface and Assigned(_SslGet1Session) then + Result := _SslGet1Session(ssl) + else + Result := nil; +end; + +function SslSetSession(ssl: PSSL; session: PSslPtr): Integer; +begin + if InitSSLInterface and Assigned(_SslSetSession) then + Result := _SslSetSession(ssl, session) + else + Result := 0; +end; + // libeay.dll function X509New: PX509; begin @@ -1924,7 +1955,7 @@ {$ENDIF} end; -function GetLibFileName(Handle: THandle): string; +function GetLibFileName(Handle: TLibHandle): string; var n: integer; begin @@ -2022,6 +2053,9 @@ _SslGetVerifyResult := GetProcAddr(SSLLibHandle, 'SSL_get_verify_result'); _SslCtrl := GetProcAddr(SSLLibHandle, 'SSL_ctrl'); _SslSet1Host := GetProcAddr(SSLLibHandle, 'SSL_set1_host'); + _SslSessionFree := GetProcAddr(SSLLibHandle, 'SSL_SESSION_free'); + _SslGet1Session := GetProcAddr(SSLLibHandle, 'SSL_get1_session'); + _SslSetSession := GetProcAddr(SSLLibHandle, 'SSL_set_session'); _X509New := GetProcAddr(SSLUtilHandle, 'X509_new'); _X509Free := GetProcAddr(SSLUtilHandle, 'X509_free'); @@ -2213,6 +2247,9 @@ _SslGetVerifyResult := nil; _SslCtrl := nil; _SslSet1Host := nil; + _SslSessionFree := nil; + _SslGet1Session := nil; + _SslSetSession := nil; _X509New := nil; _X509Free := nil; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ftpsend.pas������������������������������������������������0000644�0001750�0000144�00000154142�14743153644�021525� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 004.000.000 | |==============================================================================| | Content: FTP client | |==============================================================================| | Copyright (c)1999-2011, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c) 1999-2010. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | | Petr Esner <petr.esner@atlas.cz> | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {: @abstract(FTP client protocol) Used RFC: RFC-959, RFC-2228, RFC-2428 } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} {$TYPEINFO ON}// Borland changed defualt Visibility from Public to Published // and it requires RTTI to be generated $M+ {$M+} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} unit ftpsend; interface uses SysUtils, Classes, blcksock, synautil, synaip, synsock; const cFtpProtocol = '21'; cFtpDataProtocol = '20'; {:Terminating value for TLogonActions} FTP_OK = 255; {:Terminating value for TLogonActions} FTP_ERR = 254; type {:Array for holding definition of logon sequence.} TLogonActions = array [0..17] of byte; {:Procedural type for OnStatus event. Sender is calling @link(TFTPSend) object. Value is FTP command or reply to this comand. (if it is reply, Response is @True).} TFTPStatus = procedure(Sender: TObject; Response: Boolean; const Value: string) of object; {: @abstract(Object for holding file information) parsed from directory listing of FTP server.} TFTPListRec = class(TObject) private FFileName: String; FDirectory: Boolean; FReadable: Boolean; FFileSize: int64; FFileTime: TDateTime; FOriginalLine: string; FMask: string; FPermission: String; public {: You can assign another TFTPListRec to this object.} procedure Assign(Value: TFTPListRec); virtual; {:name of file} property FileName: string read FFileName write FFileName; {:if name is subdirectory not file.} property Directory: Boolean read FDirectory write FDirectory; {:if you have rights to read} property Readable: Boolean read FReadable write FReadable; {:size of file in bytes} property FileSize: int64 read FFileSize write FFileSize; {:date and time of file. Local server timezone is used. Any timezone conversions was not done!} property FileTime: TDateTime read FFileTime write FFileTime; {:original unparsed line} property OriginalLine: string read FOriginalLine write FOriginalLine; {:mask what was used for parsing} property Mask: string read FMask write FMask; {:permission string (depending on used mask!)} property Permission: string read FPermission write FPermission; end; {:@abstract(This is TList of TFTPListRec objects.) This object is used for holding lististing of all files information in listed directory on FTP server.} TFTPList = class(TObject) protected FList: TList; FLines: TStringList; FMasks: TStringList; FUnparsedLines: TStringList; Monthnames: string; BlockSize: string; DirFlagValue: string; FileName: string; VMSFileName: string; Day: string; Month: string; ThreeMonth: string; YearTime: string; Year: string; Hours: string; HoursModif: Ansistring; Minutes: string; Seconds: string; Size: Ansistring; Permissions: Ansistring; DirFlag: string; function GetListItem(Index: integer): TFTPListRec; virtual; function ParseEPLF(Value: string): Boolean; virtual; procedure ClearStore; virtual; function ParseByMask(Value, NextValue, Mask: ansistring): Integer; virtual; function CheckValues: Boolean; virtual; procedure FillRecord(const Value: TFTPListRec); virtual; public {:Constructor. You not need create this object, it is created by TFTPSend class as their property.} constructor Create; destructor Destroy; override; {:Clear list.} procedure Clear; virtual; {:count of holded @link(TFTPListRec) objects} function Count: integer; virtual; {:Assigns one list to another} procedure Assign(Value: TFTPList); virtual; {:try to parse raw directory listing in @link(lines) to list of @link(TFTPListRec).} procedure ParseLines; virtual; {:By this property you have access to list of @link(TFTPListRec). This is for compatibility only. Please, use @link(Items) instead.} property List: TList read FList; {:By this property you have access to list of @link(TFTPListRec).} property Items[Index: Integer]: TFTPListRec read GetListItem; default; {:Set of lines with RAW directory listing for @link(parseLines)} property Lines: TStringList read FLines; {:Set of masks for directory listing parser. It is predefined by default, however you can modify it as you need. (for example, you can add your own definition mask.) Mask is same as mask used in TotalCommander.} property Masks: TStringList read FMasks; {:After @link(ParseLines) it holding lines what was not sucessfully parsed.} property UnparsedLines: TStringList read FUnparsedLines; end; {:@abstract(Implementation of FTP protocol.) Note: Are you missing properties for setting Username and Password? Look to parent @link(TSynaClient) object! (Username and Password have default values for "anonymous" FTP login) Are you missing properties for specify server address and port? Look to parent @link(TSynaClient) too!} TFTPSend = class(TSynaClient) protected FOnStatus: TFTPStatus; FSock: TTCPBlockSocket; FDSock: TTCPBlockSocket; FResultCode: Integer; FResultString: string; FFullResult: TStringList; FAccount: string; FFWHost: string; FFWPort: string; FFWUsername: string; FFWPassword: string; FFWMode: integer; FDataStream: TMemoryStream; FDataIP: string; FDataPort: string; FDirectFile: Boolean; FDirectFileName: string; FCanResume: Boolean; FPassiveMode: Boolean; FForceDefaultPort: Boolean; FForceOldPort: Boolean; FFtpList: TFTPList; FBinaryMode: Boolean; FAutoTLS: Boolean; FIsTLS: Boolean; FIsDataTLS: Boolean; FTLSonData: Boolean; FFullSSL: Boolean; function Auth(Mode: integer): Boolean; virtual; function Connect: Boolean; virtual; function InternalStor(const Command: string; RestoreAt: int64): Boolean; virtual; function DataSocket: Boolean; virtual; function AcceptDataSocket: Boolean; virtual; procedure DoStatus(Response: Boolean; const Value: string); virtual; public {:Custom definition of login sequence. You can use this when you set @link(FWMode) to value -1.} CustomLogon: TLogonActions; constructor Create; destructor Destroy; override; {:Waits and read FTP server response. You need this only in special cases!} function ReadResult: Integer; virtual; {:Parse remote side information of data channel from value string (returned by PASV command). This function you need only in special cases!} procedure ParseRemote(Value: string); virtual; {:Parse remote side information of data channel from value string (returned by EPSV command). This function you need only in special cases!} procedure ParseRemoteEPSV(Value: string); virtual; {:Send Value as FTP command to FTP server. Returned result code is result of this function. This command is good for sending site specific command, or non-standard commands.} function FTPCommand(const Value: string): integer; virtual; {:Connect and logon to FTP server. If you specify any FireWall, connect to firewall and throw them connect to FTP server. Login sequence depending on @link(FWMode).} function Login: Boolean; virtual; {:Logoff and disconnect from FTP server.} function Logout: Boolean; virtual; {:Break current transmission of data. (You can call this method from Sock.OnStatus event, or from another thread.)} procedure Abort; virtual; {:Break current transmission of data. It is same as Abort, but it send abort telnet commands prior ABOR FTP command. Some servers need it. (You can call this method from Sock.OnStatus event, or from another thread.)} procedure TelnetAbort; virtual; {:Download directory listing of Directory on FTP server. If Directory is empty string, download listing of current working directory. If NameList is @true, download only names of files in directory. (internally use NLST command instead LIST command) If NameList is @false, returned list is also parsed to @link(FTPList) property.} function List(Directory: string; NameList: Boolean): Boolean; virtual; {:Read data from FileName on FTP server. If Restore is @true and server supports resume dowloads, download is resumed. (received is only rest of file)} function RetrieveFile(const FileName: string; Restore: Boolean): Boolean; virtual; {:Send data to FileName on FTP server. If Restore is @true and server supports resume upload, upload is resumed. (send only rest of file) In this case if remote file is same length as local file, nothing will be done. If remote file is larger then local, resume is disabled and file is transfered from begin!} function StoreFile(const FileName: string; Restore: Boolean): Boolean; virtual; {:Send data to FTP server and assing unique name for this file.} function StoreUniqueFile: Boolean; virtual; {:Append data to FileName on FTP server.} function AppendFile(const FileName: string): Boolean; virtual; {:Rename on FTP server file with OldName to NewName.} function RenameFile(const OldName, NewName: string): Boolean; virtual; {:Delete file FileName on FTP server.} function DeleteFile(const FileName: string): Boolean; virtual; {:Return size of Filename file on FTP server. If command failed (i.e. not implemented), return -1.} function FileSize(const FileName: string): int64; virtual; {:Send NOOP command to FTP server for preserve of disconnect by inactivity timeout.} function NoOp: Boolean; virtual; {:Change currect working directory to Directory on FTP server.} function ChangeWorkingDir(const Directory: string): Boolean; virtual; {:walk to upper directory on FTP server.} function ChangeToParentDir: Boolean; virtual; {:walk to root directory on FTP server. (May not work with all servers properly!)} function ChangeToRootDir: Boolean; virtual; {:Delete Directory on FTP server.} function DeleteDir(const Directory: string): Boolean; virtual; {:Create Directory on FTP server.} function CreateDir(const Directory: string): Boolean; virtual; {:Return current working directory on FTP server.} function GetCurrentDir: String; virtual; {:Establish data channel to FTP server and retrieve data. This function you need only in special cases, i.e. when you need to implement some special unsupported FTP command!} function DataRead(const DestStream: TStream): Boolean; virtual; {:Establish data channel to FTP server and send data. This function you need only in special cases, i.e. when you need to implement some special unsupported FTP command.} function DataWrite(const SourceStream: TStream): Boolean; virtual; published {:After FTP command contains result number of this operation.} property ResultCode: Integer read FResultCode; {:After FTP command contains main line of result.} property ResultString: string read FResultString; {:After any FTP command it contains all lines of FTP server reply.} property FullResult: TStringList read FFullResult; {:Account information used in some cases inside login sequence.} property Account: string read FAccount Write FAccount; {:Address of firewall. If empty string (default), firewall not used.} property FWHost: string read FFWHost Write FFWHost; {:port of firewall. standard value is same port as ftp server used. (21)} property FWPort: string read FFWPort Write FFWPort; {:Username for login to firewall. (if needed)} property FWUsername: string read FFWUsername Write FFWUsername; {:password for login to firewall. (if needed)} property FWPassword: string read FFWPassword Write FFWPassword; {:Type of Firewall. Used only if you set some firewall address. Supported predefined firewall login sequences are described by comments in source file where you can see pseudocode decribing each sequence.} property FWMode: integer read FFWMode Write FFWMode; {:Socket object used for TCP/IP operation on control channel. Good for seting OnStatus hook, etc.} property Sock: TTCPBlockSocket read FSock; {:Socket object used for TCP/IP operation on data channel. Good for seting OnStatus hook, etc.} property DSock: TTCPBlockSocket read FDSock; {:If you not use @link(DirectFile) mode, all data transfers is made to or from this stream.} property DataStream: TMemoryStream read FDataStream; {:After data connection is established, contains remote side IP of this connection.} property DataIP: string read FDataIP; {:After data connection is established, contains remote side port of this connection.} property DataPort: string read FDataPort; {:Mode of data handling by data connection. If @False, all data operations are made to or from @link(DataStream) TMemoryStream. If @true, data operations is made directly to file in your disk. (filename is specified by @link(DirectFileName) property.) Dafault is @False!} property DirectFile: Boolean read FDirectFile Write FDirectFile; {:Filename for direct disk data operations.} property DirectFileName: string read FDirectFileName Write FDirectFileName; {:Indicate after @link(Login) if remote server support resume downloads and uploads.} property CanResume: Boolean read FCanResume; {:If true (default value), all transfers is made by passive method. It is safer method for various firewalls.} property PassiveMode: Boolean read FPassiveMode Write FPassiveMode; {:Force to listen for dataconnection on standard port (20). Default is @false, dataconnections will be made to any non-standard port reported by PORT FTP command. This setting is not used, if you use passive mode.} property ForceDefaultPort: Boolean read FForceDefaultPort Write FForceDefaultPort; {:When is @true, then is disabled EPSV and EPRT support. However without this commands you cannot use IPv6! (Disabling of this commands is needed only when you are behind some crap firewall/NAT.} property ForceOldPort: Boolean read FForceOldPort Write FForceOldPort; {:You may set this hook for monitoring FTP commands and replies.} property OnStatus: TFTPStatus read FOnStatus write FOnStatus; {:After LIST command is here parsed list of files in given directory.} property FtpList: TFTPList read FFtpList; {:if @true (default), then data transfers is in binary mode. If this is set to @false, then ASCII mode is used.} property BinaryMode: Boolean read FBinaryMode Write FBinaryMode; {:if is true, then if server support upgrade to SSL/TLS mode, then use them.} property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; {:if server listen on SSL/TLS port, then you set this to true.} property FullSSL: Boolean read FFullSSL Write FFullSSL; {:Signalise, if control channel is in SSL/TLS mode.} property IsTLS: Boolean read FIsTLS; {:Signalise, if data transfers is in SSL/TLS mode.} property IsDataTLS: Boolean read FIsDataTLS; {:If @true (default), then try to use SSL/TLS on data transfers too. If @false, then SSL/TLS is used only for control connection.} property TLSonData: Boolean read FTLSonData write FTLSonData; end; {:A very useful function, and example of use can be found in the TFtpSend object. Dowload specified file from FTP server to LocalFile.} function FtpGetFile(const IP, Port, FileName, LocalFile, User, Pass: string): Boolean; {:A very useful function, and example of use can be found in the TFtpSend object. Upload specified LocalFile to FTP server.} function FtpPutFile(const IP, Port, FileName, LocalFile, User, Pass: string): Boolean; {:A very useful function, and example of use can be found in the TFtpSend object. Initiate transfer of file between two FTP servers.} function FtpInterServerTransfer( const FromIP, FromPort, FromFile, FromUser, FromPass: string; const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean; implementation constructor TFTPSend.Create; begin inherited Create; FFullResult := TStringList.Create; FDataStream := TMemoryStream.Create; FSock := TTCPBlockSocket.Create; FSock.Owner := self; FSock.ConvertLineEnd := True; FDSock := TTCPBlockSocket.Create; FDSock.Owner := self; FFtpList := TFTPList.Create; FTimeout := 300000; FTargetPort := cFtpProtocol; FUsername := 'anonymous'; FPassword := 'anonymous@' + FSock.LocalName; FDirectFile := False; FPassiveMode := True; FForceDefaultPort := False; FForceOldPort := false; FAccount := ''; FFWHost := ''; FFWPort := cFtpProtocol; FFWUsername := ''; FFWPassword := ''; FFWMode := 0; FBinaryMode := True; FAutoTLS := False; FFullSSL := False; FIsTLS := False; FIsDataTLS := False; FTLSonData := True; end; destructor TFTPSend.Destroy; begin FDSock.Free; FSock.Free; FFTPList.Free; FDataStream.Free; FFullResult.Free; inherited Destroy; end; procedure TFTPSend.DoStatus(Response: Boolean; const Value: string); begin if assigned(OnStatus) then OnStatus(Self, Response, Value); end; function TFTPSend.ReadResult: Integer; var s, c: AnsiString; begin FFullResult.Clear; c := ''; repeat s := FSock.RecvString(FTimeout); if c = '' then if length(s) > 3 then if s[4] in [' ', '-'] then c :=Copy(s, 1, 3); FResultString := s; FFullResult.Add(s); DoStatus(True, s); if FSock.LastError <> 0 then Break; until (c <> '') and (Pos(c + ' ', s) = 1); Result := StrToIntDef(c, 0); FResultCode := Result; end; function TFTPSend.FTPCommand(const Value: string): integer; begin FSock.Purge; FSock.SendString(Value + CRLF); DoStatus(False, Value); Result := ReadResult; end; // based on idea by Petr Esner <petr.esner@atlas.cz> function TFTPSend.Auth(Mode: integer): Boolean; const //if not USER <username> then // if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action0: TLogonActions = (0, FTP_OK, 3, 1, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0); //if not USER <FWusername> then // if not PASS <FWPassword> then ERROR! //if SITE <FTPServer> then ERROR! //if not USER <username> then // if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action1: TLogonActions = (3, 6, 3, 4, 6, FTP_ERR, 5, FTP_ERR, 9, 0, FTP_OK, 12, 1, FTP_OK, 15, 2, FTP_OK, FTP_ERR); //if not USER <FWusername> then // if not PASS <FWPassword> then ERROR! //if USER <UserName>'@'<FTPServer> then OK! //if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action2: TLogonActions = (3, 6, 3, 4, 6, FTP_ERR, 6, FTP_OK, 9, 1, FTP_OK, 12, 2, FTP_OK, FTP_ERR, 0, 0, 0); //if not USER <FWusername> then // if not PASS <FWPassword> then ERROR! //if not USER <username> then // if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action3: TLogonActions = (3, 6, 3, 4, 6, FTP_ERR, 0, FTP_OK, 9, 1, FTP_OK, 12, 2, FTP_OK, FTP_ERR, 0, 0, 0); //OPEN <FTPserver> //if not USER <username> then // if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action4: TLogonActions = (7, 3, 3, 0, FTP_OK, 6, 1, FTP_OK, 9, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0); //if USER <UserName>'@'<FTPServer> then OK! //if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action5: TLogonActions = (6, FTP_OK, 3, 1, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0); //if not USER <FWUserName>@<FTPServer> then // if not PASS <FWPassword> then ERROR! //if not USER <username> then // if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action6: TLogonActions = (8, 6, 3, 4, 6, FTP_ERR, 0, FTP_OK, 9, 1, FTP_OK, 12, 2, FTP_OK, FTP_ERR, 0, 0, 0); //if USER <UserName>@<FTPServer> <FWUserName> then ERROR! //if not PASS <password> then // if not ACCT <account> then ERROR! //OK! Action7: TLogonActions = (9, FTP_ERR, 3, 1, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0); //if not USER <UserName>@<FWUserName>@<FTPServer> then // if not PASS <Password>@<FWPassword> then // if not ACCT <account> then ERROR! //OK! Action8: TLogonActions = (10, FTP_OK, 3, 11, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0); var FTPServer: string; LogonActions: TLogonActions; i: integer; s: string; x: integer; begin Result := False; if FFWHost = '' then Mode := 0; if (FTargetPort = cFtpProtocol) or (FTargetPort = '21') then FTPServer := FTargetHost else FTPServer := FTargetHost + ':' + FTargetPort; case Mode of -1: LogonActions := CustomLogon; 1: LogonActions := Action1; 2: LogonActions := Action2; 3: LogonActions := Action3; 4: LogonActions := Action4; 5: LogonActions := Action5; 6: LogonActions := Action6; 7: LogonActions := Action7; 8: LogonActions := Action8; else LogonActions := Action0; end; i := 0; repeat case LogonActions[i] of 0: s := 'USER ' + FUserName; 1: s := 'PASS ' + FPassword; 2: s := 'ACCT ' + FAccount; 3: s := 'USER ' + FFWUserName; 4: s := 'PASS ' + FFWPassword; 5: s := 'SITE ' + FTPServer; 6: s := 'USER ' + FUserName + '@' + FTPServer; 7: s := 'OPEN ' + FTPServer; 8: s := 'USER ' + FFWUserName + '@' + FTPServer; 9: s := 'USER ' + FUserName + '@' + FTPServer + ' ' + FFWUserName; 10: s := 'USER ' + FUserName + '@' + FFWUserName + '@' + FTPServer; 11: s := 'PASS ' + FPassword + '@' + FFWPassword; end; x := FTPCommand(s); x := x div 100; if (x <> 2) and (x <> 3) then Exit; i := LogonActions[i + x - 1]; case i of FTP_ERR: Exit; FTP_OK: begin Result := True; Exit; end; end; until False; end; function TFTPSend.Connect: Boolean; begin FSock.CloseSocket; FSock.Bind(FIPInterface, cAnyPort); if FSock.LastError = 0 then if FFWHost = '' then FSock.Connect(FTargetHost, FTargetPort) else FSock.Connect(FFWHost, FFWPort); if FSock.LastError = 0 then if FFullSSL then FSock.SSLDoConnect; Result := FSock.LastError = 0; end; function TFTPSend.Login: Boolean; var x: integer; begin Result := False; FCanResume := False; if not Connect then Exit; FIsTLS := FFullSSL; FIsDataTLS := False; repeat x := ReadResult div 100; until x <> 1; if x <> 2 then Exit; if FAutoTLS and not(FIsTLS) then if (FTPCommand('AUTH TLS') div 100) = 2 then begin FSock.SSLDoConnect; FIsTLS := FSock.LastError = 0; if not FIsTLS then begin Result := False; Exit; end; end; if not Auth(FFWMode) then Exit; if FIsTLS then begin FTPCommand('PBSZ 0'); if FTLSonData then FIsDataTLS := (FTPCommand('PROT P') div 100) = 2; if not FIsDataTLS then FTPCommand('PROT C'); end; FTPCommand('TYPE I'); FTPCommand('STRU F'); FTPCommand('MODE S'); if FTPCommand('REST 0') = 350 then if FTPCommand('REST 1') = 350 then begin FTPCommand('REST 0'); FCanResume := True; end; Result := True; end; function TFTPSend.Logout: Boolean; begin Result := (FTPCommand('QUIT') div 100) = 2; FSock.CloseSocket; end; procedure TFTPSend.ParseRemote(Value: string); var n: integer; nb, ne: integer; s: string; x: integer; begin Value := trim(Value); nb := Pos('(',Value); ne := Pos(')',Value); if (nb = 0) or (ne = 0) then begin nb:=RPos(' ',Value); s:=Copy(Value, nb + 1, Length(Value) - nb); end else begin s:=Copy(Value,nb+1,ne-nb-1); end; for n := 1 to 4 do if n = 1 then FDataIP := Fetch(s, ',') else FDataIP := FDataIP + '.' + Fetch(s, ','); x := StrToIntDef(Fetch(s, ','), 0) * 256; x := x + StrToIntDef(Fetch(s, ','), 0); FDataPort := IntToStr(x); end; procedure TFTPSend.ParseRemoteEPSV(Value: string); var n: integer; s, v: AnsiString; begin s := SeparateRight(Value, '('); s := Trim(SeparateLeft(s, ')')); Delete(s, Length(s), 1); v := ''; for n := Length(s) downto 1 do if s[n] in ['0'..'9'] then v := s[n] + v else Break; FDataPort := v; FDataIP := FTargetHost; end; function TFTPSend.DataSocket: boolean; var s: string; begin Result := False; if FIsDataTLS then FPassiveMode := True; if FPassiveMode then begin if FSock.IP6used then s := '2' else s := '1'; if FSock.IP6used and not(FForceOldPort) and ((FTPCommand('EPSV ' + s) div 100) = 2) then begin ParseRemoteEPSV(FResultString); end else if FSock.IP6used then Exit else begin if (FTPCommand('PASV') div 100) <> 2 then Exit; ParseRemote(FResultString); end; FDSock.CloseSocket; FDSock.Bind(FIPInterface, cAnyPort); if FIsDataTLS then begin FDSock.SSL.Session := FSock.SSL.Session; end; FDSock.Connect(FDataIP, FDataPort); Result := FDSock.LastError = 0; end else begin FDSock.CloseSocket; if FForceDefaultPort then s := cFtpDataProtocol else s := '0'; //data conection from same interface as command connection FDSock.Bind(FSock.GetLocalSinIP, s); if FDSock.LastError <> 0 then Exit; FDSock.SetLinger(True, 10000); FDSock.Listen; FDSock.GetSins; FDataIP := FDSock.GetLocalSinIP; FDataIP := FDSock.ResolveName(FDataIP); FDataPort := IntToStr(FDSock.GetLocalSinPort); if FSock.IP6used and (not FForceOldPort) then begin if IsIp6(FDataIP) then s := '2' else s := '1'; s := 'EPRT |' + s +'|' + FDataIP + '|' + FDataPort + '|'; Result := (FTPCommand(s) div 100) = 2; end; if not Result and IsIP(FDataIP) then begin s := ReplaceString(FDataIP, '.', ','); s := 'PORT ' + s + ',' + IntToStr(FDSock.GetLocalSinPort div 256) + ',' + IntToStr(FDSock.GetLocalSinPort mod 256); Result := (FTPCommand(s) div 100) = 2; end; end; end; function TFTPSend.AcceptDataSocket: Boolean; var x: TSocket; begin if FPassiveMode then Result := True else begin Result := False; if FDSock.CanRead(FTimeout) then begin x := FDSock.Accept; if not FDSock.UsingSocks then FDSock.CloseSocket; FDSock.Socket := x; Result := True; end; end; if Result and FIsDataTLS then begin FDSock.SSL.Assign(FSock.SSL); FDSock.SSLDoConnect; Result := FDSock.LastError = 0; end; end; function TFTPSend.DataRead(const DestStream: TStream): Boolean; var x: integer; begin Result := False; try if not AcceptDataSocket then Exit; FDSock.RecvStreamRaw(DestStream, FTimeout); FDSock.CloseSocket; x := ReadResult; Result := (x div 100) = 2; finally FDSock.CloseSocket; end; end; function TFTPSend.DataWrite(const SourceStream: TStream): Boolean; var x: integer; b: Boolean; begin Result := False; try if not AcceptDataSocket then Exit; FDSock.SendStreamRaw(SourceStream); b := FDSock.LastError = 0; FDSock.CloseSocket; x := ReadResult; Result := b and ((x div 100) = 2); finally FDSock.CloseSocket; end; end; function TFTPSend.List(Directory: string; NameList: Boolean): Boolean; var x: integer; begin Result := False; FDataStream.Clear; FFTPList.Clear; if Directory <> '' then Directory := ' ' + Directory; FTPCommand('TYPE A'); if not DataSocket then Exit; if NameList then x := FTPCommand('NLST' + Directory) else x := FTPCommand('LIST' + Directory); if (x div 100) <> 1 then Exit; Result := DataRead(FDataStream); if (not NameList) and Result then begin FDataStream.Position := 0; FFTPList.Lines.LoadFromStream(FDataStream); FFTPList.ParseLines; end; FDataStream.Position := 0; end; function TFTPSend.RetrieveFile(const FileName: string; Restore: Boolean): Boolean; var RetrStream: TStream; begin Result := False; if FileName = '' then Exit; if not DataSocket then Exit; Restore := Restore and FCanResume; if FDirectFile then if Restore and FileExists(FDirectFileName) then RetrStream := TFileStream.Create(FDirectFileName, fmOpenReadWrite or fmShareExclusive) else RetrStream := TFileStream.Create(FDirectFileName, fmCreate or fmShareDenyWrite) else RetrStream := FDataStream; try if FBinaryMode then FTPCommand('TYPE I') else FTPCommand('TYPE A'); if Restore then begin RetrStream.Position := RetrStream.Size; if (FTPCommand('REST ' + IntToStr(RetrStream.Size)) div 100) <> 3 then Exit; end else if RetrStream is TMemoryStream then TMemoryStream(RetrStream).Clear; if (FTPCommand('RETR ' + FileName) div 100) <> 1 then Exit; Result := DataRead(RetrStream); if not FDirectFile then RetrStream.Position := 0; finally if FDirectFile then RetrStream.Free; end; end; function TFTPSend.InternalStor(const Command: string; RestoreAt: int64): Boolean; var SendStream: TStream; StorSize: int64; begin Result := False; if FDirectFile then if not FileExists(FDirectFileName) then Exit else SendStream := TFileStream.Create(FDirectFileName, fmOpenRead or fmShareDenyWrite) else SendStream := FDataStream; try if not DataSocket then Exit; if FBinaryMode then FTPCommand('TYPE I') else FTPCommand('TYPE A'); StorSize := SendStream.Size; if not FCanResume then RestoreAt := 0; if (StorSize > 0) and (RestoreAt = StorSize) then begin Result := True; Exit; end; if RestoreAt > StorSize then RestoreAt := 0; FTPCommand('ALLO ' + IntToStr(StorSize - RestoreAt)); if FCanResume then if (FTPCommand('REST ' + IntToStr(RestoreAt)) div 100) <> 3 then Exit; SendStream.Position := RestoreAt; if (FTPCommand(Command) div 100) <> 1 then Exit; Result := DataWrite(SendStream); finally if FDirectFile then SendStream.Free; end; end; function TFTPSend.StoreFile(const FileName: string; Restore: Boolean): Boolean; var RestoreAt: int64; begin Result := False; if FileName = '' then Exit; RestoreAt := 0; Restore := Restore and FCanResume; if Restore then begin RestoreAt := Self.FileSize(FileName); if RestoreAt < 0 then RestoreAt := 0; end; Result := InternalStor('STOR ' + FileName, RestoreAt); end; function TFTPSend.StoreUniqueFile: Boolean; begin Result := InternalStor('STOU', 0); end; function TFTPSend.AppendFile(const FileName: string): Boolean; begin Result := False; if FileName = '' then Exit; Result := InternalStor('APPE ' + FileName, 0); end; function TFTPSend.NoOp: Boolean; begin Result := (FTPCommand('NOOP') div 100) = 2; end; function TFTPSend.RenameFile(const OldName, NewName: string): Boolean; begin Result := False; if (FTPCommand('RNFR ' + OldName) div 100) <> 3 then Exit; Result := (FTPCommand('RNTO ' + NewName) div 100) = 2; end; function TFTPSend.DeleteFile(const FileName: string): Boolean; begin Result := (FTPCommand('DELE ' + FileName) div 100) = 2; end; function TFTPSend.FileSize(const FileName: string): int64; var s: string; begin Result := -1; if (FTPCommand('SIZE ' + FileName) div 100) = 2 then begin s := Trim(SeparateRight(ResultString, ' ')); s := Trim(SeparateLeft(s, ' ')); {$IFDEF VER100} Result := StrToIntDef(s, -1); {$ELSE} Result := StrToInt64Def(s, -1); {$ENDIF} end; end; function TFTPSend.ChangeWorkingDir(const Directory: string): Boolean; begin Result := (FTPCommand('CWD ' + Directory) div 100) = 2; end; function TFTPSend.ChangeToParentDir: Boolean; begin Result := (FTPCommand('CDUP') div 100) = 2; end; function TFTPSend.ChangeToRootDir: Boolean; begin Result := ChangeWorkingDir('/'); end; function TFTPSend.DeleteDir(const Directory: string): Boolean; begin Result := (FTPCommand('RMD ' + Directory) div 100) = 2; end; function TFTPSend.CreateDir(const Directory: string): Boolean; begin Result := (FTPCommand('MKD ' + Directory) div 100) = 2; end; function TFTPSend.GetCurrentDir: String; begin Result := ''; if (FTPCommand('PWD') div 100) = 2 then begin Result := SeparateRight(FResultString, '"'); Result := Trim(Separateleft(Result, '"')); end; end; procedure TFTPSend.Abort; begin FSock.SendString('ABOR' + CRLF); FDSock.StopFlag := True; end; procedure TFTPSend.TelnetAbort; begin FSock.SendString(#$FF + #$F4 + #$FF + #$F2); Abort; end; {==============================================================================} procedure TFTPListRec.Assign(Value: TFTPListRec); begin FFileName := Value.FileName; FDirectory := Value.Directory; FReadable := Value.Readable; FFileSize := Value.FileSize; FFileTime := Value.FileTime; FOriginalLine := Value.OriginalLine; FMask := Value.Mask; end; constructor TFTPList.Create; begin inherited Create; FList := TList.Create; FLines := TStringList.Create; FMasks := TStringList.Create; FUnparsedLines := TStringList.Create; //various UNIX FMasks.add('pppppppppp $!!!S*$TTT$DD$hh mm ss$YYYY$n*'); FMasks.add('pppppppppp $!!!S*$DD$TTT$hh mm ss$YYYY$n*'); FMasks.add('pppppppppp $!!!S*$TTT$DD$UUUUU$n*'); //mostly used UNIX format FMasks.add('pppppppppp $!!!S*$DD$TTT$UUUUU$n*'); //MacOS FMasks.add('pppppppppp $!!S*$TTT$DD$UUUUU$n*'); FMasks.add('pppppppppp $!S*$TTT$DD$UUUUU$n*'); //Novell FMasks.add('d $!S*$TTT$DD$UUUUU$n*'); //Windows FMasks.add('MM DD YY hh mmH !S* n*'); FMasks.add('MM DD YY hh mmH $ d!n*'); FMasks.add('MM DD YYYY hh mmH !S* n*'); FMasks.add('MM DD YYYY hh mmH $ d!n*'); FMasks.add('DD MM YYYY hh mmH !S* n*'); FMasks.add('DD MM YYYY hh mmH $ d!n*'); //VMS FMasks.add('v*$ DD TTT YYYY hh mm'); FMasks.add('v*$!DD TTT YYYY hh mm'); FMasks.add('n*$ YYYY MM DD hh mm$S*'); //AS400 FMasks.add('!S*$MM DD YY hh mm ss !n*'); FMasks.add('!S*$DD MM YY hh mm ss !n*'); FMasks.add('n*!S*$MM DD YY hh mm ss d'); FMasks.add('n*!S*$DD MM YY hh mm ss d'); //VxWorks FMasks.add('$S* TTT DD YYYY hh mm ss $n* $ d'); FMasks.add('$S* TTT DD YYYY hh mm ss $n*'); //Distinct FMasks.add('d $S*$TTT DD YYYY hh mm$n*'); FMasks.add('d $S*$TTT DD$hh mm$n*'); //PC-NFSD FMasks.add('nnnnnnnn.nnn dSSSSSSSSSSS MM DD YY hh mmH'); //VOS FMasks.add('- SSSSS YY MM DD hh mm ss n*'); FMasks.add('- d= SSSSS YY MM DD hh mm ss n*'); //Unissys ClearPath FMasks.add('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn SSSSSSSSS MM DD YYYY hh mm'); FMasks.add('n*\x SSSSSSSSS MM DD YYYY hh mm'); //IBM FMasks.add('- SSSSSSSSSSSS d MM DD YYYY hh mm n*'); //OS9 FMasks.add('- YY MM DD hhmm d SSSSSSSSS n*'); //tandem FMasks.add('nnnnnnnn SSSSSSS DD TTT YY hh mm ss'); //MVS FMasks.add('- YYYY MM DD SSSSS d=O n*'); //BullGCOS8 FMasks.add(' $S* MM DD YY hh mm ss !n*'); FMasks.add('d $S* MM DD YY !n*'); //BullGCOS7 FMasks.add(' TTT DD YYYY n*'); FMasks.add(' d n*'); end; destructor TFTPList.Destroy; begin Clear; FList.Free; FLines.Free; FMasks.Free; FUnparsedLines.Free; inherited Destroy; end; procedure TFTPList.Clear; var n:integer; begin for n := 0 to FList.Count - 1 do if Assigned(FList[n]) then TFTPListRec(FList[n]).Free; FList.Clear; FLines.Clear; FUnparsedLines.Clear; end; function TFTPList.Count: integer; begin Result := FList.Count; end; function TFTPList.GetListItem(Index: integer): TFTPListRec; begin Result := nil; if Index < Count then Result := TFTPListRec(FList[Index]); end; procedure TFTPList.Assign(Value: TFTPList); var flr: TFTPListRec; n: integer; begin Clear; for n := 0 to Value.Count - 1 do begin flr := TFTPListRec.Create; flr.Assign(Value[n]); Flist.Add(flr); end; Lines.Assign(Value.Lines); Masks.Assign(Value.Masks); UnparsedLines.Assign(Value.UnparsedLines); end; procedure TFTPList.ClearStore; begin Monthnames := ''; BlockSize := ''; DirFlagValue := ''; FileName := ''; VMSFileName := ''; Day := ''; Month := ''; ThreeMonth := ''; YearTime := ''; Year := ''; Hours := ''; HoursModif := ''; Minutes := ''; Seconds := ''; Size := ''; Permissions := ''; DirFlag := ''; end; function TFTPList.ParseByMask(Value, NextValue, Mask: AnsiString): Integer; var Ivalue, IMask: integer; MaskC, LastMaskC: AnsiChar; c: AnsiChar; s: string; begin ClearStore; Result := 0; if Value = '' then Exit; if Mask = '' then Exit; Ivalue := 1; IMask := 1; Result := 1; LastMaskC := ' '; while Imask <= Length(mask) do begin if (Mask[Imask] <> '*') and (Ivalue > Length(Value)) then begin Result := 0; Exit; end; MaskC := Mask[Imask]; if Ivalue > Length(Value) then Exit; c := Value[Ivalue]; case MaskC of 'n': FileName := FileName + c; 'v': VMSFileName := VMSFileName + c; '.': begin if c in ['.', ' '] then FileName := TrimSP(FileName) + '.' else begin Result := 0; Exit; end; end; 'D': Day := Day + c; 'M': Month := Month + c; 'T': ThreeMonth := ThreeMonth + c; 'U': YearTime := YearTime + c; 'Y': Year := Year + c; 'h': Hours := Hours + c; 'H': HoursModif := HoursModif + c; 'm': Minutes := Minutes + c; 's': Seconds := Seconds + c; 'S': Size := Size + c; 'p': Permissions := Permissions + c; 'd': DirFlag := DirFlag + c; 'x': if c <> ' ' then begin Result := 0; Exit; end; '*': begin s := ''; if LastMaskC in ['n', 'v'] then begin if Imask = Length(Mask) then s := Copy(Value, IValue, Maxint) else while IValue <= Length(Value) do begin if Value[Ivalue] = ' ' then break; s := s + Value[Ivalue]; Inc(Ivalue); end; if LastMaskC = 'n' then FileName := FileName + s else VMSFileName := VMSFileName + s; end else begin while IValue <= Length(Value) do begin if not(Value[Ivalue] in ['0'..'9']) then break; s := s + Value[Ivalue]; Inc(Ivalue); end; case LastMaskC of 'S': Size := Size + s; end; end; Dec(IValue); end; '!': begin while IValue <= Length(Value) do begin if Value[Ivalue] = ' ' then break; Inc(Ivalue); end; while IValue <= Length(Value) do begin if Value[Ivalue] <> ' ' then break; Inc(Ivalue); end; Dec(IValue); end; '$': begin while IValue <= Length(Value) do begin if not(Value[Ivalue] in [' ', #9]) then break; Inc(Ivalue); end; Dec(IValue); end; '=': begin s := ''; case LastmaskC of 'S': begin while Imask <= Length(Mask) do begin if not(Mask[Imask] in ['0'..'9']) then break; s := s + Mask[Imask]; Inc(Imask); end; Dec(Imask); BlockSize := s; end; 'T': begin Monthnames := Copy(Mask, IMask, 12 * 3); Inc(IMask, 12 * 3); end; 'd': begin Inc(Imask); DirFlagValue := Mask[Imask]; end; end; end; '\': begin Value := NextValue; IValue := 0; Result := 2; end; end; Inc(Ivalue); Inc(Imask); LastMaskC := MaskC; end; end; function TFTPList.CheckValues: Boolean; var x, n: integer; begin Result := false; if FileName <> '' then begin if pos('?', VMSFilename) > 0 then Exit; if pos('*', VMSFilename) > 0 then Exit; end; if VMSFileName <> '' then if pos(';', VMSFilename) <= 0 then Exit; if (FileName = '') and (VMSFileName = '') then Exit; if Permissions <> '' then begin if length(Permissions) <> 10 then Exit; for n := 1 to 10 do if not(Permissions[n] in ['a', 'b', 'c', 'd', 'h', 'l', 'p', 'r', 's', 't', 'w', 'x', 'y', '-']) then Exit; end; if Day <> '' then begin Day := TrimSP(Day); x := StrToIntDef(day, -1); if (x < 1) or (x > 31) then Exit; end; if Month <> '' then begin Month := TrimSP(Month); x := StrToIntDef(Month, -1); if (x < 1) or (x > 12) then Exit; end; if Hours <> '' then begin Hours := TrimSP(Hours); x := StrToIntDef(Hours, -1); if (x < 0) or (x > 24) then Exit; end; if HoursModif <> '' then begin if not (HoursModif[1] in ['a', 'A', 'p', 'P']) then Exit; end; if Minutes <> '' then begin Minutes := TrimSP(Minutes); x := StrToIntDef(Minutes, -1); if (x < 0) or (x > 59) then Exit; end; if Seconds <> '' then begin Seconds := TrimSP(Seconds); x := StrToIntDef(Seconds, -1); if (x < 0) or (x > 59) then Exit; end; if Size <> '' then begin Size := TrimSP(Size); for n := 1 to Length(Size) do if not (Size[n] in ['0'..'9']) then Exit; end; if length(Monthnames) = (12 * 3) then for n := 1 to 12 do CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3); if ThreeMonth <> '' then begin x := GetMonthNumber(ThreeMonth); if (x = 0) then Exit; end; if YearTime <> '' then begin YearTime := ReplaceString(YearTime, '-', ':'); if pos(':', YearTime) > 0 then begin if (GetTimeFromstr(YearTime) = -1) then Exit; end else begin YearTime := TrimSP(YearTime); x := StrToIntDef(YearTime, -1); if (x = -1) then Exit; if (x < 1900) or (x > 2100) then Exit; end; end; if Year <> '' then begin Year := TrimSP(Year); x := StrToIntDef(Year, -1); if (x = -1) then Exit; if Length(Year) = 4 then begin if not((x > 1900) and (x < 2100)) then Exit; end else if Length(Year) = 2 then begin if not((x >= 0) and (x <= 99)) then Exit; end else if Length(Year) = 3 then begin if not((x >= 100) and (x <= 110)) then Exit; end else Exit; end; Result := True; end; procedure TFTPList.FillRecord(const Value: TFTPListRec); var s: string; x: integer; myear: Word; mmonth: Word; mday: Word; mhours, mminutes, mseconds: word; n: integer; begin s := DirFlagValue; if s = '' then s := 'D'; s := Uppercase(s); Value.Directory := s = Uppercase(DirFlag); if FileName <> '' then Value.FileName := SeparateLeft(Filename, ' -> '); if VMSFileName <> '' then begin Value.FileName := VMSFilename; Value.Directory := Pos('.DIR;',VMSFilename) > 0; end; Value.FileName := TrimSPRight(Value.FileName); Value.Readable := not Value.Directory; if BlockSize <> '' then x := StrToIntDef(BlockSize, 1) else x := 1; {$IFDEF VER100} Value.FileSize := x * StrToIntDef(Size, 0); {$ELSE} Value.FileSize := x * StrToInt64Def(Size, 0); {$ENDIF} DecodeDate(Date,myear,mmonth,mday); mhours := 0; mminutes := 0; mseconds := 0; if Day <> '' then mday := StrToIntDef(day, 1); if Month <> '' then mmonth := StrToIntDef(Month, 1); if length(Monthnames) = (12 * 3) then for n := 1 to 12 do CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3); if ThreeMonth <> '' then mmonth := GetMonthNumber(ThreeMonth); if Year <> '' then begin myear := StrToIntDef(Year, 0); if (myear <= 99) and (myear > 50) then myear := myear + 1900; if myear <= 50 then myear := myear + 2000; end; if YearTime <> '' then begin if pos(':', YearTime) > 0 then begin YearTime := TrimSP(YearTime); mhours := StrToIntDef(Separateleft(YearTime, ':'), 0); mminutes := StrToIntDef(SeparateRight(YearTime, ':'), 0); if (Encodedate(myear, mmonth, mday) + EncodeTime(mHours, mminutes, 0, 0)) > now then Dec(mYear); end else myear := StrToIntDef(YearTime, 0); end; if Minutes <> '' then mminutes := StrToIntDef(Minutes, 0); if Seconds <> '' then mseconds := StrToIntDef(Seconds, 0); if Hours <> '' then begin mHours := StrToIntDef(Hours, 0); if HoursModif <> '' then if Uppercase(HoursModif[1]) = 'P' then if mHours <> 12 then mHours := MHours + 12; end; Value.FileTime := Encodedate(myear, mmonth, mday) + EncodeTime(mHours, mminutes, mseconds, 0); if Permissions <> '' then begin Value.Permission := Permissions; Value.Readable := Uppercase(permissions)[2] = 'R'; if Uppercase(permissions)[1] = 'D' then begin Value.Directory := True; Value.Readable := false; end else if Uppercase(permissions)[1] = 'L' then Value.Directory := True; end; end; function TFTPList.ParseEPLF(Value: string): Boolean; var s, os: string; flr: TFTPListRec; begin Result := False; if Value <> '' then if Value[1] = '+' then begin os := Value; Delete(Value, 1, 1); flr := TFTPListRec.create; flr.FileName := SeparateRight(Value, #9); s := Fetch(Value, ','); while s <> '' do begin if s[1] = #9 then Break; case s[1] of '/': flr.Directory := true; 'r': flr.Readable := true; 's': {$IFDEF VER100} flr.FileSize := StrToIntDef(Copy(s, 2, Length(s) - 1), 0); {$ELSE} flr.FileSize := StrToInt64Def(Copy(s, 2, Length(s) - 1), 0); {$ENDIF} 'm': flr.FileTime := (StrToIntDef(Copy(s, 2, Length(s) - 1), 0) / 86400) + 25569; end; s := Fetch(Value, ','); end; if flr.FileName <> '' then if (flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..'))) or (flr.FileName = '') then flr.free else begin flr.OriginalLine := os; flr.Mask := 'EPLF'; Flist.Add(flr); Result := True; end; end; end; procedure TFTPList.ParseLines; var flr: TFTPListRec; n, m: Integer; S: string; x: integer; b: Boolean; begin n := 0; while n < Lines.Count do begin if n = Lines.Count - 1 then s := '' else s := Lines[n + 1]; b := False; x := 0; if ParseEPLF(Lines[n]) then begin b := True; x := 1; end else for m := 0 to Masks.Count - 1 do begin x := ParseByMask(Lines[n], s, Masks[m]); if x > 0 then if CheckValues then begin flr := TFTPListRec.create; FillRecord(flr); flr.OriginalLine := Lines[n]; flr.Mask := Masks[m]; if flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')) then flr.free else Flist.Add(flr); b := True; Break; end; end; if not b then FUnparsedLines.Add(Lines[n]); Inc(n); if x > 1 then Inc(n, x - 1); end; end; {==============================================================================} function FtpGetFile(const IP, Port, FileName, LocalFile, User, Pass: string): Boolean; begin Result := False; with TFTPSend.Create do try if User <> '' then begin Username := User; Password := Pass; end; TargetHost := IP; TargetPort := Port; if not Login then Exit; DirectFileName := LocalFile; DirectFile:=True; Result := RetrieveFile(FileName, False); Logout; finally Free; end; end; function FtpPutFile(const IP, Port, FileName, LocalFile, User, Pass: string): Boolean; begin Result := False; with TFTPSend.Create do try if User <> '' then begin Username := User; Password := Pass; end; TargetHost := IP; TargetPort := Port; if not Login then Exit; DirectFileName := LocalFile; DirectFile:=True; Result := StoreFile(FileName, False); Logout; finally Free; end; end; function FtpInterServerTransfer( const FromIP, FromPort, FromFile, FromUser, FromPass: string; const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean; var FromFTP, ToFTP: TFTPSend; s: string; x: integer; begin Result := False; FromFTP := TFTPSend.Create; toFTP := TFTPSend.Create; try if FromUser <> '' then begin FromFTP.Username := FromUser; FromFTP.Password := FromPass; end; if ToUser <> '' then begin ToFTP.Username := ToUser; ToFTP.Password := ToPass; end; FromFTP.TargetHost := FromIP; FromFTP.TargetPort := FromPort; ToFTP.TargetHost := ToIP; ToFTP.TargetPort := ToPort; if not FromFTP.Login then Exit; if not ToFTP.Login then Exit; if (FromFTP.FTPCommand('PASV') div 100) <> 2 then Exit; FromFTP.ParseRemote(FromFTP.ResultString); s := ReplaceString(FromFTP.DataIP, '.', ','); s := 'PORT ' + s + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) div 256) + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) mod 256); if (ToFTP.FTPCommand(s) div 100) <> 2 then Exit; x := ToFTP.FTPCommand('RETR ' + FromFile); if (x div 100) <> 1 then Exit; x := FromFTP.FTPCommand('STOR ' + ToFile); if (x div 100) <> 1 then Exit; FromFTP.Timeout := 21600000; x := FromFTP.ReadResult; if (x div 100) <> 2 then Exit; ToFTP.Timeout := 21600000; x := ToFTP.ReadResult; if (x div 100) <> 2 then Exit; Result := True; finally ToFTP.Free; FromFTP.Free; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/license.txt������������������������������������������������0000644�0001750�0000144�00000004154�14743153644�021535� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Copyright (c)1999-2002, Lukas Gebauer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Lukas Gebauer nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssfpc.inc��������������������������������������������������0000644�0001750�0000144�00000075655�14743153644�021201� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.001.005 | |==============================================================================| | Content: Socket Independent Platform Layer - FreePascal definition include | |==============================================================================| | Copyright (c)2006-2013, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2006-2013. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@exclude} {$IFDEF FPC} {For FreePascal 2.x.x} //{$DEFINE FORCEOLDAPI} {Note about define FORCEOLDAPI: If you activate this compiler directive, then is allways used old socket API for name resolution. If you leave this directive inactive, then the new API is used, when running system allows it. For IPv6 support you must have new API! } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} {$ifdef FreeBSD} {$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr {$endif} {$ifdef darwin} {$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr {$endif} {$ifdef haiku} {$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr {$endif} interface uses SyncObjs, SysUtils, Classes, synafpc, BaseUnix, Unix, termio, sockets, netdb; function InitSocketInterface(stack: string): Boolean; function DestroySocketInterface: Boolean; const DLLStackName = ''; WinsockLevel = $0202; cLocalHost = '127.0.0.1'; cAnyHost = '0.0.0.0'; c6AnyHost = '::0'; c6Localhost = '::1'; cLocalHostStr = 'localhost'; type TSocket = longint; TAddrFamily = integer; TMemory = pointer; type TFDSet = Baseunix.TFDSet; PFDSet = ^TFDSet; Ptimeval = Baseunix.ptimeval; Ttimeval = Baseunix.ttimeval; const FIONREAD = termio.FIONREAD; FIONBIO = termio.FIONBIO; {$IFNDEF HAIKU} FIOASYNC = termio.FIOASYNC; {$ENDIF} const IPPROTO_IP = 0; { Dummy } IPPROTO_ICMP = 1; { Internet Control Message Protocol } IPPROTO_IGMP = 2; { Internet Group Management Protocol} IPPROTO_TCP = 6; { TCP } IPPROTO_UDP = 17; { User Datagram Protocol } IPPROTO_IPV6 = 41; IPPROTO_ICMPV6 = 58; IPPROTO_RM = 113; IPPROTO_RAW = 255; IPPROTO_MAX = 256; type PInAddr = ^TInAddr; TInAddr = sockets.in_addr; PSockAddrIn = ^TSockAddrIn; TSockAddrIn = sockets.TInetSockAddr; TIP_mreq = record imr_multiaddr: TInAddr; // IP multicast address of group imr_interface: TInAddr; // local IP address of interface end; PInAddr6 = ^TInAddr6; TInAddr6 = sockets.Tin6_addr; PSockAddrIn6 = ^TSockAddrIn6; TSockAddrIn6 = sockets.TInetSockAddr6; TIPv6_mreq = record ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. ipv6mr_interface: integer; // Interface index. end; const INADDR_ANY = $00000000; INADDR_LOOPBACK = $7F000001; INADDR_BROADCAST = $FFFFFFFF; INADDR_NONE = $FFFFFFFF; ADDR_ANY = INADDR_ANY; INVALID_SOCKET = TSocket(NOT(0)); SOCKET_ERROR = -1; Const IP_TOS = sockets.IP_TOS; { int; IP type of service and precedence. } IP_TTL = sockets.IP_TTL; { int; IP time to live. } IP_HDRINCL = sockets.IP_HDRINCL; { int; Header is included with data. } IP_OPTIONS = sockets.IP_OPTIONS; { ip_opts; IP per-packet options. } // IP_ROUTER_ALERT = sockets.IP_ROUTER_ALERT; { bool } IP_RECVOPTS = sockets.IP_RECVOPTS; { bool } IP_RETOPTS = sockets.IP_RETOPTS; { bool } // IP_PKTINFO = sockets.IP_PKTINFO; { bool } // IP_PKTOPTIONS = sockets.IP_PKTOPTIONS; // IP_PMTUDISC = sockets.IP_PMTUDISC; { obsolete name? } // IP_MTU_DISCOVER = sockets.IP_MTU_DISCOVER; { int; see below } // IP_RECVERR = sockets.IP_RECVERR; { bool } // IP_RECVTTL = sockets.IP_RECVTTL; { bool } // IP_RECVTOS = sockets.IP_RECVTOS; { bool } IP_MULTICAST_IF = sockets.IP_MULTICAST_IF; { in_addr; set/get IP multicast i/f } IP_MULTICAST_TTL = sockets.IP_MULTICAST_TTL; { u_char; set/get IP multicast ttl } IP_MULTICAST_LOOP = sockets.IP_MULTICAST_LOOP; { i_char; set/get IP multicast loopback } IP_ADD_MEMBERSHIP = sockets.IP_ADD_MEMBERSHIP; { ip_mreq; add an IP group membership } IP_DROP_MEMBERSHIP = sockets.IP_DROP_MEMBERSHIP; { ip_mreq; drop an IP group membership } SOL_SOCKET = sockets.SOL_SOCKET; SO_DEBUG = sockets.SO_DEBUG; SO_REUSEADDR = sockets.SO_REUSEADDR; SO_TYPE = sockets.SO_TYPE; SO_ERROR = sockets.SO_ERROR; SO_DONTROUTE = sockets.SO_DONTROUTE; SO_BROADCAST = sockets.SO_BROADCAST; SO_SNDBUF = sockets.SO_SNDBUF; SO_RCVBUF = sockets.SO_RCVBUF; SO_KEEPALIVE = sockets.SO_KEEPALIVE; SO_OOBINLINE = sockets.SO_OOBINLINE; // SO_NO_CHECK = sockets.SO_NO_CHECK; // SO_PRIORITY = sockets.SO_PRIORITY; SO_LINGER = sockets.SO_LINGER; // SO_BSDCOMPAT = sockets.SO_BSDCOMPAT; // SO_REUSEPORT = sockets.SO_REUSEPORT; // SO_PASSCRED = sockets.SO_PASSCRED; // SO_PEERCRED = sockets.SO_PEERCRED; SO_RCVLOWAT = sockets.SO_RCVLOWAT; SO_SNDLOWAT = sockets.SO_SNDLOWAT; SO_RCVTIMEO = sockets.SO_RCVTIMEO; SO_SNDTIMEO = sockets.SO_SNDTIMEO; { Security levels - as per NRL IPv6 - don't actually do anything } // SO_SECURITY_AUTHENTICATION = sockets.SO_SECURITY_AUTHENTICATION; // SO_SECURITY_ENCRYPTION_TRANSPORT = sockets.SO_SECURITY_ENCRYPTION_TRANSPORT; // SO_SECURITY_ENCRYPTION_NETWORK = sockets.SO_SECURITY_ENCRYPTION_NETWORK; // SO_BINDTODEVICE = sockets.SO_BINDTODEVICE; { Socket filtering } // SO_ATTACH_FILTER = sockets.SO_ATTACH_FILTER; // SO_DETACH_FILTER = sockets.SO_DETACH_FILTER; {$IFDEF DARWIN} SO_NOSIGPIPE = $1022; {$ENDIF} SOMAXCONN = 1024; {$IFDEF HAIKU} IPV6_UNICAST_HOPS = 27; {$ELSE} IPV6_UNICAST_HOPS = sockets.IPV6_UNICAST_HOPS; {$ENDIF} IPV6_MULTICAST_IF = sockets.IPV6_MULTICAST_IF; IPV6_MULTICAST_HOPS = sockets.IPV6_MULTICAST_HOPS; IPV6_MULTICAST_LOOP = sockets.IPV6_MULTICAST_LOOP; {$IFDEF HAIKU} IPV6_JOIN_GROUP = 28; IPV6_LEAVE_GROUP = 29; {$ELSE} IPV6_JOIN_GROUP = sockets.IPV6_JOIN_GROUP; IPV6_LEAVE_GROUP = sockets.IPV6_LEAVE_GROUP; {$ENDIF} const SOCK_STREAM = 1; { stream socket } SOCK_DGRAM = 2; { datagram socket } SOCK_RAW = 3; { raw-protocol interface } SOCK_RDM = 4; { reliably-delivered message } SOCK_SEQPACKET = 5; { sequenced packet stream } { TCP options. } TCP_NODELAY = $0001; { Address families. } AF_UNSPEC = 0; { unspecified } AF_INET = sockets.AF_INET; { internetwork: UDP, TCP, etc. } AF_INET6 = sockets.AF_INET6; { Internetwork Version 6 } AF_MAX = 24; { Protocol families, same as address families for now. } PF_UNSPEC = AF_UNSPEC; PF_INET = AF_INET; PF_INET6 = AF_INET6; PF_MAX = AF_MAX; type { Structure used for manipulating linger option. } PLinger = ^TLinger; TLinger = packed record l_onoff: integer; l_linger: integer; end; const MSG_OOB = sockets.MSG_OOB; // Process out-of-band data. MSG_PEEK = sockets.MSG_PEEK; // Peek at incoming messages. {$if defined(DARWIN)} MSG_NOSIGNAL = $20000; // Do not generate SIGPIPE. // Works under MAC OS X, but is undocumented, // So FPC doesn't include it {$elseif defined(HAIKU)} MSG_NOSIGNAL = $0800; {$else} MSG_NOSIGNAL = sockets.MSG_NOSIGNAL; // Do not generate SIGPIPE. {$endif} {$IF DEFINED(HAIKU)} const ESysESTALE = (B_POSIX_ERROR_BASE + 40); ESysENOTSOCK = (B_POSIX_ERROR_BASE + 44); ESysEHOSTDOWN = (B_POSIX_ERROR_BASE + 45); ESysEDESTADDRREQ = (B_POSIX_ERROR_BASE + 48); ESysEDQUOT = (B_POSIX_ERROR_BASE + 49); // Fake error codes ESysEUSERS = (B_POSIX_ERROR_BASE + 128); ESysEREMOTE = (B_POSIX_ERROR_BASE + 129); ESysETOOMANYREFS = (B_POSIX_ERROR_BASE + 130); ESysESOCKTNOSUPPORT = (B_POSIX_ERROR_BASE + 131); {$ENDIF} const WSAEINTR = ESysEINTR; WSAEBADF = ESysEBADF; WSAEACCES = ESysEACCES; WSAEFAULT = ESysEFAULT; WSAEINVAL = ESysEINVAL; WSAEMFILE = ESysEMFILE; WSAEWOULDBLOCK = ESysEWOULDBLOCK; WSAEINPROGRESS = ESysEINPROGRESS; WSAEALREADY = ESysEALREADY; WSAENOTSOCK = ESysENOTSOCK; WSAEDESTADDRREQ = ESysEDESTADDRREQ; WSAEMSGSIZE = ESysEMSGSIZE; WSAEPROTOTYPE = ESysEPROTOTYPE; WSAENOPROTOOPT = ESysENOPROTOOPT; WSAEPROTONOSUPPORT = ESysEPROTONOSUPPORT; WSAESOCKTNOSUPPORT = ESysESOCKTNOSUPPORT; WSAEOPNOTSUPP = ESysEOPNOTSUPP; WSAEPFNOSUPPORT = ESysEPFNOSUPPORT; WSAEAFNOSUPPORT = ESysEAFNOSUPPORT; WSAEADDRINUSE = ESysEADDRINUSE; WSAEADDRNOTAVAIL = ESysEADDRNOTAVAIL; WSAENETDOWN = ESysENETDOWN; WSAENETUNREACH = ESysENETUNREACH; WSAENETRESET = ESysENETRESET; WSAECONNABORTED = ESysECONNABORTED; WSAECONNRESET = ESysECONNRESET; WSAENOBUFS = ESysENOBUFS; WSAEISCONN = ESysEISCONN; WSAENOTCONN = ESysENOTCONN; WSAESHUTDOWN = ESysESHUTDOWN; WSAETOOMANYREFS = ESysETOOMANYREFS; WSAETIMEDOUT = ESysETIMEDOUT; WSAECONNREFUSED = ESysECONNREFUSED; WSAELOOP = ESysELOOP; WSAENAMETOOLONG = ESysENAMETOOLONG; WSAEHOSTDOWN = ESysEHOSTDOWN; WSAEHOSTUNREACH = ESysEHOSTUNREACH; WSAENOTEMPTY = ESysENOTEMPTY; WSAEPROCLIM = -1; WSAEUSERS = ESysEUSERS; WSAEDQUOT = ESysEDQUOT; WSAESTALE = ESysESTALE; WSAEREMOTE = ESysEREMOTE; WSASYSNOTREADY = -2; WSAVERNOTSUPPORTED = -3; WSANOTINITIALISED = -4; WSAEDISCON = -5; WSAHOST_NOT_FOUND = 1; WSATRY_AGAIN = 2; WSANO_RECOVERY = 3; WSANO_DATA = -6; const WSADESCRIPTION_LEN = 256; WSASYS_STATUS_LEN = 128; type PWSAData = ^TWSAData; TWSAData = packed record wVersion: Word; wHighVersion: Word; szDescription: array[0..WSADESCRIPTION_LEN] of Char; szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; iMaxSockets: Word; iMaxUdpDg: Word; lpVendorInfo: PChar; end; function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); var in6addr_any, in6addr_loopback : TInAddr6; procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); procedure FD_ZERO(var FDSet: TFDSet); {=============================================================================} var SynSockCS: SyncObjs.TCriticalSection; SockEnhancedApi: Boolean; SockWship6Api: Boolean; type TVarSin = packed record {$ifdef SOCK_HAS_SINLEN} sin_len : cuchar; {$endif} case integer of 0: (AddressFamily: sa_family_t); 1: ( case sin_family: sa_family_t of AF_INET: (sin_port: word; sin_addr: TInAddr; sin_zero: array[0..7] of Char); AF_INET6: (sin6_port: word; sin6_flowinfo: longword; sin6_addr: TInAddr6; sin6_scope_id: longword); ); end; function SizeOfVarSin(sin: TVarSin): integer; function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; function WSACleanup: Integer; function WSAGetLastError: Integer; function GetHostName: string; function Shutdown(s: TSocket; how: Integer): Integer; function SetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; optlen: Integer): Integer; function GetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; var optlen: Integer): Integer; function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; function ntohs(netshort: word): word; function ntohl(netlong: longword): longword; function Listen(s: TSocket; backlog: Integer): Integer; function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; function htons(hostshort: word): word; function htonl(hostlong: longword): longword; function GetSockName(s: TSocket; var name: TVarSin): Integer; function GetPeerName(s: TSocket; var name: TVarSin): Integer; function Connect(s: TSocket; const name: TVarSin): Integer; function CloseSocket(s: TSocket): Integer; function Bind(s: TSocket; const addr: TVarSin): Integer; function Accept(s: TSocket; var addr: TVarSin): TSocket; function Socket(af, Struc, Protocol: Integer): TSocket; function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): Longint; function IsNewApi(Family: integer): Boolean; function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; function GetSinIP(Sin: TVarSin): string; function GetSinPort(Sin: TVarSin): Integer; procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; {==============================================================================} implementation uses InitC; {$if defined(LINUX) or defined(OPENBSD)} {$define FIRST_ADDR_THEN_CANONNAME} {$elseif defined(FREEBSD) or defined(NETBSD) or defined(DRAGONFLY) or defined(SOLARIS) or defined(ANDROID) or defined(DARWIN) or defined(HAIKU)} {$define FIRST_CANONNAME_THEN_ADDR} {$else} {$error fatal 'Please consult the netdb.h file for your system to determine the order of ai_addr and ai_canonname'} {$endif} {$push}{$packrecords c} type PAddrInfo = ^addrinfo; addrinfo = record ai_flags: cint; {* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST *} ai_family: cint; {* PF_xxx *} ai_socktype: cint; {* SOCK_xxx *} ai_protocol: cint; {* 0 or IPPROTO_xxx for IPv4 and IPv6 *} ai_addrlen: TSockLen; {* length of ai_addr *} {$ifdef FIRST_CANONNAME_THEN_ADDR} ai_canonname: PAnsiChar; {* canonical name for hostname *} ai_addr: psockaddr; {* binary address *} {$endif} {$ifdef FIRST_ADDR_THEN_CANONNAME} ai_addr: psockaddr; {* binary address *} ai_canonname: PAnsiChar; {* canonical name for hostname *} {$endif} ai_next: PAddrInfo; {* next structure in linked list *} end; TAddrInfo = addrinfo; PPAddrInfo = ^PAddrInfo; {$pop} function getaddrinfo(name, service: PAnsiChar; hints: PAddrInfo; res: PPAddrInfo): cint; cdecl; external clib; procedure freeaddrinfo(ai: PAddrInfo); cdecl; external clib; function ResolveName(const HostName: String; Addresses: Pointer; MaxAddresses, Family: Integer): Integer; overload; var hints: TAddrInfo; res, ai: PAddrInfo; begin Result:= -1; if MaxAddresses = 0 then Exit; res:= nil; hints:= Default(TAddrInfo); hints.ai_family:= Family; hints.ai_socktype:= SOCK_STREAM; if (getaddrinfo(PAnsiChar(HostName), nil, @hints, @res) <> 0) or (res = nil) then Exit; ai:= res; Result:= 0; repeat if ai^.ai_family = Family then begin if Family = AF_INET then begin Move(PInetSockAddr(ai^.ai_addr)^.sin_addr, Addresses^, SizeOf(TInAddr)); Inc(PInAddr(Addresses)); end else begin Move(PInetSockAddr6(ai^.ai_addr)^.sin6_addr, Addresses^, SizeOf(TIn6Addr)); Inc(PIn6Addr(Addresses)); end; Inc(Result); end; ai:= ai^.ai_next; until (ai = nil) or (Result >= MaxAddresses); freeaddrinfo(res); end; function ResolveName(HostName: String; var Addresses: array of THostAddr): Integer; overload; begin Result:= ResolveName(HostName, @Addresses, Length(Addresses), AF_INET); end; function ResolveName6(HostName: String; var Addresses: array of THostAddr6): Integer; begin Result:= ResolveName(HostName, @Addresses, Length(Addresses), AF_INET6); end; function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); end; function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and (a^.u6_addr32[2] = 0) and (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); end; function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); end; function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); end; function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; begin Result := (a^.u6_addr8[0] = $FF); end; function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; begin Result := (CompareMem( a, b, sizeof(TInAddr6))); end; procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); begin FillChar(a^, sizeof(TInAddr6), 0); end; procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); begin FillChar(a^, sizeof(TInAddr6), 0); a^.u6_addr8[15] := 1; end; {=============================================================================} function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; begin with WSData do begin wVersion := wVersionRequired; wHighVersion := $202; szDescription := 'Synsock - Synapse Platform Independent Socket Layer'; szSystemStatus := 'Running on Unix/Linux by FreePascal'; iMaxSockets := 32768; iMaxUdpDg := 8192; end; Result := 0; end; function WSACleanup: Integer; begin Result := 0; end; function WSAGetLastError: Integer; begin Result := fpGetErrno; end; function FD_ISSET(Socket: TSocket; var fdset: TFDSet): Boolean; begin Result := fpFD_ISSET(socket, fdset) <> 0; end; procedure FD_SET(Socket: TSocket; var fdset: TFDSet); begin fpFD_SET(Socket, fdset); end; procedure FD_CLR(Socket: TSocket; var fdset: TFDSet); begin fpFD_CLR(Socket, fdset); end; procedure FD_ZERO(var fdset: TFDSet); begin fpFD_ZERO(fdset); end; {=============================================================================} function SizeOfVarSin(sin: TVarSin): integer; begin case sin.sin_family of AF_INET: Result := SizeOf(TSockAddrIn); AF_INET6: Result := SizeOf(TSockAddrIn6); else Result := 0; end; end; {=============================================================================} function Bind(s: TSocket; const addr: TVarSin): Integer; begin if fpBind(s, @addr, SizeOfVarSin(addr)) = 0 then Result := 0 else Result := SOCKET_ERROR; end; function Connect(s: TSocket; const name: TVarSin): Integer; begin if fpConnect(s, @name, SizeOfVarSin(name)) = 0 then Result := 0 else Result := SOCKET_ERROR; end; function GetSockName(s: TSocket; var name: TVarSin): Integer; var len: integer; begin len := SizeOf(name); FillChar(name, len, 0); Result := fpGetSockName(s, @name, @Len); end; function GetPeerName(s: TSocket; var name: TVarSin): Integer; var len: integer; begin len := SizeOf(name); FillChar(name, len, 0); Result := fpGetPeerName(s, @name, @Len); end; function GetHostName: string; begin Result := unix.GetHostName; end; function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; begin Result := fpSend(s, pointer(Buf), len, flags); end; function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; begin Result := fpRecv(s, pointer(Buf), len, flags); end; function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; begin Result := fpSendTo(s, pointer(Buf), len, flags, @addrto, SizeOfVarSin(addrto)); end; function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; var x: integer; begin x := SizeOf(from); Result := fpRecvFrom(s, pointer(Buf), len, flags, @from, @x); end; function Accept(s: TSocket; var addr: TVarSin): TSocket; var x: integer; begin x := SizeOf(addr); Result := fpAccept(s, @addr, @x); end; function Shutdown(s: TSocket; how: Integer): Integer; begin Result := fpShutdown(s, how); end; function SetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; optlen: Integer): Integer; begin Result := fpsetsockopt(s, level, optname, pointer(optval), optlen); end; function GetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; var optlen: Integer): Integer; begin Result := fpgetsockopt(s, level, optname, pointer(optval), @optlen); end; function ntohs(netshort: word): word; begin Result := sockets.ntohs(NetShort); end; function ntohl(netlong: longword): longword; begin Result := sockets.ntohl(NetLong); end; function Listen(s: TSocket; backlog: Integer): Integer; begin if fpListen(s, backlog) = 0 then Result := 0 else Result := SOCKET_ERROR; end; function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; begin Result := fpIoctl(s, cmd, @arg); end; function htons(hostshort: word): word; begin Result := sockets.htons(Hostshort); end; function htonl(hostlong: longword): longword; begin Result := sockets.htonl(HostLong); end; function CloseSocket(s: TSocket): Integer; begin Result := sockets.CloseSocket(s); end; function Socket(af, Struc, Protocol: Integer): TSocket; {$IFDEF DARWIN} var on_off: integer; {$ENDIF} begin Result := fpSocket(af, struc, protocol); // ##### Patch for Mac OS to avoid "Project XXX raised exception class 'External: SIGPIPE'" error. {$IFDEF DARWIN} if Result <> INVALID_SOCKET then begin on_off := 1; synsock.SetSockOpt(Result, integer(SOL_SOCKET), integer(SO_NOSIGPIPE), @on_off, SizeOf(integer)); end; {$ENDIF} end; function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): Longint; begin Result := fpSelect(nfds, readfds, writefds, exceptfds, timeout); end; {=============================================================================} function IsNewApi(Family: integer): Boolean; begin Result := SockEnhancedApi; if not Result then Result := (Family = AF_INET6) and SockWship6Api; end; function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; var TwoPass: boolean; f1, f2: integer; function GetAddr(f:integer): integer; var a4: array [1..1] of in_addr; a6: array [1..1] of Tin6_addr; he: THostEntry; begin Result := WSAEPROTONOSUPPORT; case f of AF_INET: begin if IP = cAnyHost then begin Sin.sin_family := AF_INET; Result := 0; end else begin if lowercase(IP) = cLocalHostStr then a4[1].s_addr := htonl(INADDR_LOOPBACK) else begin a4[1].s_addr := 0; Result := WSAHOST_NOT_FOUND; a4[1] := StrTonetAddr(IP); if a4[1].s_addr = INADDR_ANY then if GetHostByName(ip, he) then a4[1]:=HostToNet(he.Addr) else Resolvename(ip, a4); end; if a4[1].s_addr <> INADDR_ANY then begin Sin.sin_family := AF_INET; sin.sin_addr := a4[1]; Result := 0; end; end; end; AF_INET6: begin if IP = c6AnyHost then begin Sin.sin_family := AF_INET6; Result := 0; end else begin if lowercase(IP) = cLocalHostStr then SET_LOOPBACK_ADDR6(@a6[1]) else begin Result := WSAHOST_NOT_FOUND; SET_IN6_IF_ADDR_ANY(@a6[1]); a6[1] := StrTonetAddr6(IP); if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then Resolvename6(ip, a6); end; if not IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then begin Sin.sin_family := AF_INET6; sin.sin6_addr := a6[1]; Result := 0; end; end; end; end; end; begin Result := 0; FillChar(Sin, Sizeof(Sin), 0); Sin.sin_port := htons(Resolveport(port, family, SockProtocol, SockType)); TwoPass := False; if Family = AF_UNSPEC then begin if PreferIP4 then begin f1 := AF_INET; f2 := AF_INET6; TwoPass := True; end else begin f2 := AF_INET; f1 := AF_INET6; TwoPass := True; end; end else f1 := Family; Result := GetAddr(f1); if Result <> 0 then if TwoPass then Result := GetAddr(f2); end; function GetSinIP(Sin: TVarSin): string; begin Result := ''; case sin.AddressFamily of AF_INET: begin result := NetAddrToStr(sin.sin_addr); end; AF_INET6: begin result := NetAddrToStr6(sin.sin6_addr); end; end; end; function GetSinPort(Sin: TVarSin): Integer; begin if (Sin.sin_family = AF_INET6) then Result := synsock.ntohs(Sin.sin6_port) else Result := synsock.ntohs(Sin.sin_port); end; procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); var x, n: integer; a4: array [1..255] of in_addr; a6: array [1..255] of Tin6_addr; he: THostEntry; begin IPList.Clear; if (family = AF_INET) or (family = AF_UNSPEC) then begin if lowercase(name) = cLocalHostStr then IpList.Add(cLocalHost) else begin a4[1] := StrTonetAddr(name); if a4[1].s_addr = INADDR_ANY then if GetHostByName(name, he) then begin a4[1]:=HostToNet(he.Addr); x := 1; end else x := Resolvename(name, a4) else x := 1; for n := 1 to x do IpList.Add(netaddrToStr(a4[n])); end; end; if (family = AF_INET6) or (family = AF_UNSPEC) then begin if lowercase(name) = cLocalHostStr then IpList.Add(c6LocalHost) else begin a6[1] := StrTonetAddr6(name); if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then x := Resolvename6(name, a6) else x := 1; for n := 1 to x do IpList.Add(netaddrToStr6(a6[n])); end; end; if IPList.Count = 0 then IPList.Add(cLocalHost); end; function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; var ProtoEnt: TProtocolEntry; ServEnt: TServiceEntry; begin Result := StrToIntDef(Port, 0); if Result = 0 then begin ProtoEnt.Name := ''; GetProtocolByNumber(SockProtocol, ProtoEnt); ServEnt.port := 0; GetServiceByName(Port, ProtoEnt.Name, ServEnt); Result := ntohs(ServEnt.port); end; end; function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; var n: integer; a4: array [1..1] of in_addr; a6: array [1..1] of Tin6_addr; a: array [1..1] of string; begin Result := IP; a4[1] := StrToNetAddr(IP); if a4[1].s_addr <> INADDR_ANY then begin //why ResolveAddress need address in HOST order? :-O n := ResolveAddress(nettohost(a4[1]), a); if n > 0 then Result := a[1]; end else begin a6[1] := StrToNetAddr6(IP); n := ResolveAddress6(a6[1], a); if n > 0 then Result := a[1]; end; end; {=============================================================================} function InitSocketInterface(stack: string): Boolean; begin SockEnhancedApi := False; SockWship6Api := False; // Libc.Signal(Libc.SIGPIPE, TSignalHandler(Libc.SIG_IGN)); Result := True; end; function DestroySocketInterface: Boolean; begin Result := True; end; initialization begin SynSockCS := SyncObjs.TCriticalSection.Create; SET_IN6_IF_ADDR_ANY (@in6addr_any); SET_LOOPBACK_ADDR6 (@in6addr_loopback); end; finalization begin SynSockCS.Free; end; {$ENDIF} �����������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_gnutls.pas���������������������������������������������0000644�0001750�0000144�00000027164�14743153644�022262� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.000.000 | |==============================================================================| | Content: SSL support by GnuTLS | |==============================================================================| | Copyright (C) 2013-2023 Alexander Koblov <alexx2000@mail.ru> | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (C) 2005-2023. | | Portions created by Petr Fejfar are Copyright (C) 2011-2012. | | All Rights Reserved. | |==============================================================================} {:@abstract(SSL plugin for GnuTLS) Compatibility with GnuTLS versions: 3.0.0+ GnuTLS libraries are loaded dynamicly - you not need GnuTLS librares even you compile your application with this unit. SSL just not working when you not have GnuTLS libraries. } {$MODE DELPHI} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} unit ssl_gnutls; interface uses SysUtils, Classes, blcksock, synsock, synautil, ssl_gnutls_lib; type {:@abstract(class implementing GnuTLS SSL plugin.) Instance of this class will be created for each @link(TTCPBlockSocket). You not need to create instance of this class, all is done by Synapse itself!} { TSSLGnuTLS } TSSLGnuTLS = class(TCustomSSL) private FShutdown: Integer; FDatum: gnutls_datum_t; FSession: gnutls_session_t; FPriorities: array[Byte] of AnsiChar; FCredentials: gnutls_certificate_credentials_t; protected function Init: Boolean; function DeInit: Boolean; function Prepare: Boolean; function SSLCheck: Boolean; public {:See @inherited} constructor Create(const Value: TTCPBlockSocket); override; destructor Destroy; override; {:See @inherited} function LibVersion: String; override; {:See @inherited} function LibName: String; override; {:See @inherited} function Connect: boolean; override; {:See @inherited} function Shutdown: boolean; override; {:See @inherited} function BiShutdown: boolean; override; {:See @inherited} function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; {:See @inherited} function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; {:See @inherited} function WaitingData: Integer; override; {:See @inherited} function GetSSLVersion: string; override; {:See @inherited} function GetCipherName: string; override; {:See @inherited} function GetCipherBits: integer; override; {:See @inherited} function GetCipherAlgBits: integer; override; end; implementation {==============================================================================} constructor TSSLGnuTLS.Create(const Value: TTCPBlockSocket); begin inherited Create(Value); end; destructor TSSLGnuTLS.Destroy; begin DeInit; inherited Destroy; end; function TSSLGnuTLS.LibVersion: String; begin Result := 'GnuTLS ' + gnutls_check_version('3.0.0'); end; function TSSLGnuTLS.LibName: String; begin Result := 'ssl_gnutls'; end; function TSSLGnuTLS.Init: Boolean; begin Result := False; FLastError := 0; FLastErrorDesc := EmptyStr; case FSSLType of LT_SSLv3: FPriorities := 'NONE:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL'; LT_TLSv1: FPriorities := 'NONE:+VERS-TLS1.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL'; LT_TLSv1_1: FPriorities := 'NONE:+VERS-TLS1.1:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL'; LT_TLSv1_2: FPriorities := 'NONE:+VERS-TLS1.2:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL'; LT_TLSv1_3: FPriorities := 'NONE:+VERS-TLS1.3:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL'; LT_all: FPriorities := 'NONE:+VERS-TLS-ALL:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL'; else Exit; end; FLastError := gnutls_certificate_allocate_credentials(FCredentials); if not SSLCheck then Exit; FLastError := gnutls_init(@FSession, GNUTLS_CLIENT); if not SSLCheck then Exit; FLastError := gnutls_priority_set_direct(FSession, FPriorities, nil); if not SSLCheck then Exit; FLastError := gnutls_credentials_set(FSession, GNUTLS_CRD_CERTIFICATE, FCredentials); if not SSLCheck then Exit; if Length(FCertificateFile) > 0 then begin gnutls_certificate_set_x509_trust_file(FCredentials, PAnsiChar(FCertificateFile), GNUTLS_X509_FMT_PEM); end; if Length(FPrivateKeyFile) > 0 then begin gnutls_certificate_set_x509_key_file(FCredentials, PAnsiChar(FCertificateFile), PAnsiChar(FPrivateKeyFile), GNUTLS_X509_FMT_PEM); end; Result := True; end; function TSSLGnuTLS.DeInit: Boolean; begin Result := True; if Assigned(FSessionNew) then begin gnutls_free(FDatum.data); FSessionNew := nil; FDatum.data := nil; FDatum.size := 0 end; if Assigned(FCredentials) then begin gnutls_certificate_free_credentials(FCredentials); FCredentials := nil; end; if Assigned(FSession) then begin gnutls_deinit(FSession); FSession := nil end; FSSLEnabled := False; end; function TSSLGnuTLS.Prepare: Boolean; begin DeInit; if Init then Result := True else begin DeInit; Result := False; end; end; function TSSLGnuTLS.SSLCheck: Boolean; var P : PAnsiChar; begin if FLastError = GNUTLS_E_SUCCESS then begin Result := True; FLastErrorDesc := EmptyStr; end else begin Result := False; P := gnutls_strerror(FLastError); FLastErrorDesc := StrPas(P); end; end; function TSSLGnuTLS.Connect: boolean; var B: Boolean; begin Result := False; if FSocket.Socket = INVALID_SOCKET then Exit; if Prepare then begin gnutls_transport_set_ptr(FSession, gnutls_transport_ptr_t(FSocket.Socket)); // Reuse session if Assigned(FSessionOld) then begin gnutls_session_set_data(FSession, gnutls_datum_ptr_t(FSessionOld)^.data, gnutls_datum_ptr_t(FSessionOld)^.size); end; // do blocking call of SSL_Connect if FSocket.ConnectionTimeout <= 0 then begin repeat FLastError := gnutls_handshake(FSession); until (FLastError <> GNUTLS_E_AGAIN) and (FLastError <> GNUTLS_E_INTERRUPTED); end // do non-blocking call of SSL_Connect else begin B := FSocket.NonBlockMode; FSocket.NonBlockMode := True; repeat FLastError := gnutls_handshake(FSession); until (FLastError <> GNUTLS_E_AGAIN) and (FLastError <> GNUTLS_E_INTERRUPTED); FSocket.NonBlockMode := B; end; if SSLCheck then begin if (FSessionOld = nil) then begin if (gnutls_session_get_data2(FSession, @FDatum) = GNUTLS_E_SUCCESS) then begin FSessionNew := @FDatum; end; end; FSSLEnabled := True; FShutdown := 0; Result := True; end; end; end; function TSSLGnuTLS.Shutdown: boolean; begin Result := BiShutdown; end; function TSSLGnuTLS.BiShutdown: boolean; begin if (FShutdown > 0) then gnutls_bye(FSession, GNUTLS_SHUT_WR) else begin gnutls_bye(FSession, GNUTLS_SHUT_RDWR); end; Inc(FShutdown); DeInit; Result := True; end; function TSSLGnuTLS.SendBuffer(Buffer: TMemory; Len: Integer): Integer; begin FLastError := 0; FLastErrorDesc := EmptyStr; repeat Result := gnutls_record_send(FSession, Buffer , Len); until (Result <> GNUTLS_E_AGAIN) and (Result <> GNUTLS_E_INTERRUPTED); if (Result < 0) then begin FLastError := Result; Result := 0; end; end; function TSSLGnuTLS.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; begin FLastError := 0; FLastErrorDesc := EmptyStr; repeat Result := gnutls_record_recv(FSession, Buffer , Len); until (Result <> GNUTLS_E_AGAIN) and (Result <> GNUTLS_E_INTERRUPTED); if (Result < 0) then begin FLastError := Result; Result := 0; end; end; function TSSLGnuTLS.WaitingData: Integer; begin Result := gnutls_record_check_pending(FSession); end; function TSSLGnuTLS.GetSSLVersion: string; begin if (FSession = nil) then Result := EmptyStr else Result := gnutls_protocol_get_name(gnutls_protocol_get_version(FSession)); end; function TSSLGnuTLS.GetCipherName: string; var kx: gnutls_kx_algorithm_t; mac: gnutls_mac_algorithm_t; cipher: gnutls_cipher_algorithm_t; begin if (FSession = nil) then Result := EmptyStr else begin kx := gnutls_kx_get(FSession); mac := gnutls_mac_get(FSession); cipher := gnutls_cipher_get(FSession); Result := gnutls_cipher_suite_get_name(kx, cipher, mac); end; end; function TSSLGnuTLS.GetCipherBits: integer; begin Result := GetCipherAlgBits; end; function TSSLGnuTLS.GetCipherAlgBits: integer; begin if (FSession = nil) then Result := 0 else Result := (gnutls_cipher_get_key_size(gnutls_cipher_get(FSession)) * 8); end; {==============================================================================} initialization if (SSLImplementation = TSSLNone) and InitSSLInterface then SSLImplementation := TSSLGnuTLS; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_gnutls_lib.pas�����������������������������������������0000644�0001750�0000144�00000024311�14743153644�023077� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.000.000 | |==============================================================================| | Content: SSL support by GnuTLS | |==============================================================================| | Copyright (C) 2013-2023 Alexander Koblov <alexx2000@mail.ru> | | | | The GnuTLS is free software; you can redistribute it and/or | | modify it under the terms of the GNU Lesser General Public License | | as published by the Free Software Foundation; either version 2.1 of | | the License, or (at your option) any later version. | | | | This library is distributed in the hope that it will be useful, but | | WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | | Lesser General Public License for more details. | | | | You should have received a copy of the GNU Lesser General Public License | | along with this program. If not, see <https://www.gnu.org/licenses/> | |==============================================================================} unit ssl_gnutls_lib; {$mode delphi} {$packrecords c} interface uses CTypes; const GNUTLS_E_SUCCESS = 0; GNUTLS_E_AGAIN = -28; GNUTLS_E_INTERRUPTED = -52; type gnutls_protocol_t = ( GNUTLS_SSL3 = 1, GNUTLS_TLS1_0, GNUTLS_TLS1_1, GNUTLS_TLS1_2, GNUTLS_TLS1_3, GNUTLS_VERSION_UNKNOWN = $ff ) ; gnutls_cipher_algorithm_t = ( GNUTLS_CIPHER_NULL = 1, GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_ARCFOUR_40, GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_CIPHER_RC2_40_CBC = 90, GNUTLS_CIPHER_DES_CBC ); gnutls_kx_algorithm_t = ( GNUTLS_KX_RSA = 1, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, GNUTLS_KX_ANON_DH, GNUTLS_KX_SRP, GNUTLS_KX_RSA_EXPORT, GNUTLS_KX_SRP_RSA, GNUTLS_KX_SRP_DSS, GNUTLS_KX_PSK, GNUTLS_KX_DHE_PSK ); gnutls_mac_algorithm_t = ( GNUTLS_MAC_UNKNOWN = 0, GNUTLS_MAC_NULL = 1, GNUTLS_MAC_MD5, GNUTLS_MAC_SHA1, GNUTLS_MAC_RMD160, GNUTLS_MAC_MD2, GNUTLS_MAC_SHA256, GNUTLS_MAC_SHA384, GNUTLS_MAC_SHA512 ); gnutls_compression_method_t = ( GNUTLS_COMP_NULL = 1, GNUTLS_COMP_DEFLATE, GNUTLS_COMP_LZO ); gnutls_certificate_type_t = ( GNUTLS_CRT_X509 = 1, GNUTLS_CRT_OPENPGP ); gnutls_init_flags_t = ( GNUTLS_SERVER = 1, GNUTLS_CLIENT ); gnutls_credentials_type_t = ( GNUTLS_CRD_CERTIFICATE = 1, GNUTLS_CRD_ANON, GNUTLS_CRD_SRP, GNUTLS_CRD_PSK, GNUTLS_CRD_IA ); gnutls_x509_crt_fmt_t = ( GNUTLS_X509_FMT_DER = 0, GNUTLS_X509_FMT_PEM = 1 ); gnutls_close_request_t = ( GNUTLS_SHUT_RDWR = 0, GNUTLS_SHUT_WR = 1 ); type gnutls_datum_t = record data: pcuchar; size: cuint; end; gnutls_datum_ptr_t = ^gnutls_datum_t; type gnutls_session_st = record end; gnutls_session_t = ^gnutls_session_st; gnutls_transport_ptr_t = type UIntPtr; gnutls_session_ptr_t = ^gnutls_session_t; gnutls_certificate_credentials_st = record end; gnutls_certificate_credentials_t = ^gnutls_certificate_credentials_st; var gnutls_global_init: function(): cint; cdecl; gnutls_init: function(session: gnutls_session_ptr_t; flags: gnutls_init_flags_t): cint; cdecl; gnutls_deinit: procedure(session: gnutls_session_t); cdecl; gnutls_priority_set_direct: function(session: gnutls_session_t; const priorities: PAnsiChar; const err_pos: PPAnsiChar): cint; cdecl; gnutls_credentials_set: function(session: gnutls_session_t; cred_type: gnutls_credentials_type_t; cred: Pointer): cint; cdecl; gnutls_certificate_set_x509_trust_file: function(res: gnutls_certificate_credentials_t; const CAFILE: PAnsiChar; crt_type: gnutls_x509_crt_fmt_t): cint; cdecl; gnutls_certificate_set_x509_key_file: function(res: gnutls_certificate_credentials_t; const CERTFILE: PAnsiChar; const KEYFILE: PAnsiChar; crt_type: gnutls_x509_crt_fmt_t): cint; cdecl; gnutls_certificate_allocate_credentials: function(out res: gnutls_certificate_credentials_t): cint; cdecl; gnutls_certificate_free_credentials: procedure(sc: gnutls_certificate_credentials_t); cdecl; gnutls_free: procedure(ptr: Pointer); cdecl; gnutls_session_get_data2: function(session: gnutls_session_t; data: gnutls_datum_ptr_t): cint; cdecl; gnutls_session_set_data: function(session: gnutls_session_t; session_data: Pointer; session_data_size: csize_t): cint; cdecl; gnutls_transport_set_ptr: procedure(session: gnutls_session_t; ptr: gnutls_transport_ptr_t); cdecl; gnutls_record_check_pending: function(session: gnutls_session_t): csize_t; cdecl; gnutls_handshake: function(session: gnutls_session_t): cint; cdecl; gnutls_bye: function(session: gnutls_session_t; how: gnutls_close_request_t): cint; cdecl; gnutls_record_send: function(session: gnutls_session_t; const data: Pointer; sizeofdata: csize_t): PtrInt; cdecl; gnutls_record_recv: function(session: gnutls_session_t; data: Pointer; sizeofdata: csize_t): PtrInt; cdecl; gnutls_protocol_get_name: function(version: gnutls_protocol_t): PAnsiChar; cdecl; gnutls_protocol_get_version: function(session: gnutls_session_t): gnutls_protocol_t; cdecl; gnutls_cipher_get: function(session: gnutls_session_t): gnutls_cipher_algorithm_t; cdecl; gnutls_kx_get: function(session: gnutls_session_t): gnutls_kx_algorithm_t; cdecl; gnutls_mac_get: function(session: gnutls_session_t): gnutls_mac_algorithm_t; cdecl; gnutls_compression_get: function(session: gnutls_session_t): gnutls_compression_method_t; cdecl; gnutls_certificate_type_get: function(session: gnutls_session_t): gnutls_certificate_type_t; cdecl; gnutls_cipher_suite_get_name: function(kx_algorithm: gnutls_kx_algorithm_t; cipher_algorithm: gnutls_cipher_algorithm_t; mac_algorithm: gnutls_mac_algorithm_t): PAnsiChar; cdecl; gnutls_cipher_get_key_size: function(algorithm: gnutls_cipher_algorithm_t): csize_t; cdecl; gnutls_strerror: function(error: cint): PAnsiChar; cdecl; gnutls_check_version: function(const req_version: PAnsiChar): PAnsiChar; cdecl; function InitSSLInterface: Boolean; implementation uses SysUtils, DynLibs; function SafeGetProcAddress(Lib : TlibHandle; const ProcName : AnsiString) : Pointer; begin Result:= GetProcedureAddress(Lib, ProcName); if (Result = nil) then raise Exception.Create(EmptyStr); end; function InitSSLInterface: Boolean; const libgnutls: array[0..2] of String = ('30', '28', '26'); var index: Integer; gnutls: TLibHandle; begin for index:= Low(libgnutls) to High(libgnutls) do begin gnutls:= LoadLibrary('libgnutls.so.' + libgnutls[index]); if gnutls <> NilHandle then Break; end; Result:= (gnutls <> NilHandle); if Result then try @gnutls_check_version:= SafeGetProcAddress(gnutls, 'gnutls_check_version'); if (gnutls_check_version('3.0.0') = nil) then raise Exception.Create(EmptyStr); @gnutls_global_init:= SafeGetProcAddress(gnutls, 'gnutls_global_init'); @gnutls_init:= SafeGetProcAddress(gnutls, 'gnutls_init'); @gnutls_deinit:= SafeGetProcAddress(gnutls, 'gnutls_deinit'); @gnutls_priority_set_direct:= SafeGetProcAddress(gnutls, 'gnutls_priority_set_direct'); @gnutls_credentials_set:= SafeGetProcAddress(gnutls, 'gnutls_credentials_set'); @gnutls_certificate_set_x509_trust_file:= SafeGetProcAddress(gnutls, 'gnutls_certificate_set_x509_trust_file'); @gnutls_certificate_set_x509_key_file:= SafeGetProcAddress(gnutls, 'gnutls_certificate_set_x509_key_file'); @gnutls_certificate_allocate_credentials:= SafeGetProcAddress(gnutls, 'gnutls_certificate_allocate_credentials'); @gnutls_certificate_free_credentials:= SafeGetProcAddress(gnutls, 'gnutls_certificate_free_credentials'); @gnutls_free:= SafeGetProcAddress(gnutls, 'gnutls_free'); @gnutls_session_get_data2:= SafeGetProcAddress(gnutls, 'gnutls_session_get_data2'); @gnutls_session_set_data:= SafeGetProcAddress(gnutls, 'gnutls_session_set_data'); @gnutls_transport_set_ptr:= SafeGetProcAddress(gnutls, 'gnutls_transport_set_ptr'); @gnutls_record_check_pending:= SafeGetProcAddress(gnutls, 'gnutls_record_check_pending'); @gnutls_handshake:= SafeGetProcAddress(gnutls, 'gnutls_handshake'); @gnutls_bye:= SafeGetProcAddress(gnutls, 'gnutls_bye'); @gnutls_record_send:= SafeGetProcAddress(gnutls, 'gnutls_record_send'); @gnutls_record_recv:= SafeGetProcAddress(gnutls, 'gnutls_record_recv'); @gnutls_protocol_get_name:= SafeGetProcAddress(gnutls, 'gnutls_protocol_get_name'); @gnutls_protocol_get_version:= SafeGetProcAddress(gnutls, 'gnutls_protocol_get_version'); @gnutls_cipher_get:= SafeGetProcAddress(gnutls, 'gnutls_cipher_get'); @gnutls_kx_get:= SafeGetProcAddress(gnutls, 'gnutls_kx_get'); @gnutls_mac_get:= SafeGetProcAddress(gnutls, 'gnutls_mac_get'); @gnutls_compression_get:= SafeGetProcAddress(gnutls, 'gnutls_compression_get'); @gnutls_certificate_type_get:= SafeGetProcAddress(gnutls, 'gnutls_certificate_type_get'); @gnutls_cipher_suite_get_name:= SafeGetProcAddress(gnutls, 'gnutls_cipher_suite_get_name'); @gnutls_cipher_get_key_size:= SafeGetProcAddress(gnutls, 'gnutls_cipher_get_key_size'); @gnutls_strerror:= SafeGetProcAddress(gnutls, 'gnutls_strerror'); if (gnutls_global_init() <> GNUTLS_E_SUCCESS) then raise Exception.Create(EmptyStr); except Result:= False; FreeLibrary(gnutls); end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_openssl.pas��������������������������������������������0000644�0001750�0000144�00000060122�14743153644�022420� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.004.001 | |==============================================================================| | Content: SSL support by OpenSSL | |==============================================================================| | Copyright (c)1999-2017, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2005-2017. | | Portions created by Petr Fejfar are Copyright (c)2011-2012. | | Portions created by Pepak are Copyright (c)2018. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} //requires OpenSSL libraries! {:@abstract(SSL plugin for OpenSSL) Compatibility with OpenSSL versions: 0.9.6 should work, known mysterious crashing on FreePascal and Linux platform. 0.9.7 - 1.0.0 working fine. 1.1.0 should work, under testing. OpenSSL libraries are loaded dynamicly - you not need OpenSSL librares even you compile your application with this unit. SSL just not working when you not have OpenSSL libraries. This plugin have limited support for .NET too! Because is not possible to use callbacks with CDECL calling convention under .NET, is not supported key/certificate passwords and multithread locking. :-( For handling keys and certificates you can use this properties: @link(TCustomSSL.CertificateFile) for PEM or ASN1 DER (cer) format. @br @link(TCustomSSL.Certificate) for ASN1 DER format only. @br @link(TCustomSSL.PrivateKeyFile) for PEM or ASN1 DER (key) format. @br @link(TCustomSSL.PrivateKey) for ASN1 DER format only. @br @link(TCustomSSL.CertCAFile) for PEM CA certificate bundle. @br @link(TCustomSSL.PFXFile) for PFX format. @br @link(TCustomSSL.PFX) for PFX format from binary string. @br This plugin is capable to create Ad-Hoc certificates. When you start SSL/TLS server without explicitly assigned key and certificate, then this plugin create Ad-Hoc key and certificate for each incomming connection by self. It slowdown accepting of new connections! } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} unit ssl_openssl; interface uses SysUtils, Classes, blcksock, synsock, synautil, {$IFDEF CIL} System.Text, {$ENDIF} {$IFDEF DELPHI23_UP} AnsiStrings, {$ENDIF} ssl_openssl_lib; type {:@abstract(class implementing OpenSSL SSL plugin.) Instance of this class will be created for each @link(TTCPBlockSocket). You not need to create instance of this class, all is done by Synapse itself!} TSSLOpenSSL = class(TCustomSSL) private FServer: boolean; protected FSsl: PSSL; Fctx: PSSL_CTX; function NeedSigningCertificate: boolean; virtual; function SSLCheck: Boolean; function SetSslKeys: boolean; virtual; function Init: Boolean; function DeInit: Boolean; function Prepare: Boolean; function LoadPFX(pfxdata: ansistring): Boolean; function CreateSelfSignedCert(Host: string): Boolean; override; property Server: boolean read FServer; public {:See @inherited} constructor Create(const Value: TTCPBlockSocket); override; destructor Destroy; override; {:See @inherited} function LibVersion: String; override; {:See @inherited} function LibName: String; override; {:See @inherited and @link(ssl_cryptlib) for more details.} function Connect: boolean; override; {:See @inherited and @link(ssl_cryptlib) for more details.} function Accept: boolean; override; {:See @inherited} function Shutdown: boolean; override; {:See @inherited} function BiShutdown: boolean; override; {:See @inherited} function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; {:See @inherited} function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; {:See @inherited} function WaitingData: Integer; override; {:See @inherited} function GetSSLVersion: string; override; {:See @inherited} function GetPeerSubject: string; override; {:See @inherited} function GetPeerSerialNo: integer; override; {pf} {:See @inherited} function GetPeerIssuer: string; override; {:See @inherited} function GetPeerName: string; override; {:See @inherited} function GetPeerNameHash: cardinal; override; {pf} {:See @inherited} function GetPeerFingerprint: ansistring; override; {:See @inherited} function GetCertInfo: string; override; {:See @inherited} function GetCipherName: string; override; {:See @inherited} function GetCipherBits: integer; override; {:See @inherited} function GetCipherAlgBits: integer; override; {:See @inherited} function GetVerifyCert: integer; override; end; implementation {==============================================================================} {$IFNDEF CIL} function PasswordCallback(buf:PAnsiChar; size:Integer; rwflag:Integer; userdata: Pointer):Integer; cdecl; var Password: AnsiString; begin Password := ''; if TCustomSSL(userdata) is TCustomSSL then Password := TCustomSSL(userdata).KeyPassword; if Length(Password) > (Size - 1) then SetLength(Password, Size - 1); Result := Length(Password); {$IFDEF DELPHI23_UP}AnsiStrings.{$ENDIF}StrLCopy(buf, PAnsiChar(Password + #0), Result + 1); end; {$ENDIF} {==============================================================================} constructor TSSLOpenSSL.Create(const Value: TTCPBlockSocket); begin inherited Create(Value); FCiphers := 'DEFAULT'; FSsl := nil; Fctx := nil; end; destructor TSSLOpenSSL.Destroy; begin DeInit; inherited Destroy; end; function TSSLOpenSSL.LibVersion: String; begin Result := SSLeayversion(0); end; function TSSLOpenSSL.LibName: String; begin Result := 'ssl_openssl'; end; function TSSLOpenSSL.SSLCheck: Boolean; var {$IFDEF CIL} sb: StringBuilder; {$ENDIF} s : AnsiString; begin Result := true; FLastErrorDesc := ''; FLastError := ErrGetError; ErrClearError; if FLastError <> 0 then begin Result := False; {$IFDEF CIL} sb := StringBuilder.Create(256); ErrErrorString(FLastError, sb, 256); FLastErrorDesc := Trim(sb.ToString); {$ELSE} s := StringOfChar(#0, 256); ErrErrorString(FLastError, s, Length(s)); FLastErrorDesc := s; {$ENDIF} end; end; function TSSLOpenSSL.CreateSelfSignedCert(Host: string): Boolean; var pk: EVP_PKEY; x: PX509; rsa: PRSA; t: PASN1_UTCTIME; name: PX509_NAME; b: PBIO; xn, y: integer; s: AnsiString; {$IFDEF CIL} sb: StringBuilder; {$ENDIF} begin Result := True; pk := EvpPkeynew; x := X509New; try rsa := RsaGenerateKey(2048, $10001, nil, nil); EvpPkeyAssign(pk, EVP_PKEY_RSA, rsa); X509SetVersion(x, 2); Asn1IntegerSet(X509getSerialNumber(x), 0); t := Asn1UtctimeNew; try X509GmtimeAdj(t, -60 * 60 *24); X509SetNotBefore(x, t); X509GmtimeAdj(t, 60 * 60 * 60 *24); X509SetNotAfter(x, t); finally Asn1UtctimeFree(t); end; X509SetPubkey(x, pk); Name := X509GetSubjectName(x); X509NameAddEntryByTxt(Name, 'C', $1001, 'CZ', -1, -1, 0); X509NameAddEntryByTxt(Name, 'CN', $1001, host, -1, -1, 0); x509SetIssuerName(x, Name); x509Sign(x, pk, EvpGetDigestByName('SHA1')); b := BioNew(BioSMem); try i2dX509Bio(b, x); xn := bioctrlpending(b); {$IFDEF CIL} sb := StringBuilder.Create(xn); y := bioread(b, sb, xn); if y > 0 then begin sb.Length := y; s := sb.ToString; end; {$ELSE} setlength(s, xn); y := bioread(b, s, xn); if y > 0 then setlength(s, y); {$ENDIF} finally BioFreeAll(b); end; FCertificate := s; b := BioNew(BioSMem); try i2dPrivatekeyBio(b, pk); xn := bioctrlpending(b); {$IFDEF CIL} sb := StringBuilder.Create(xn); y := bioread(b, sb, xn); if y > 0 then begin sb.Length := y; s := sb.ToString; end; {$ELSE} setlength(s, xn); y := bioread(b, s, xn); if y > 0 then setlength(s, y); {$ENDIF} finally BioFreeAll(b); end; FPrivatekey := s; finally X509free(x); EvpPkeyFree(pk); end; end; function TSSLOpenSSL.LoadPFX(pfxdata: Ansistring): Boolean; var cert, pkey, ca: SslPtr; b: PBIO; p12: SslPtr; begin Result := False; b := BioNew(BioSMem); try BioWrite(b, pfxdata, Length(PfxData)); p12 := d2iPKCS12bio(b, nil); if not Assigned(p12) then Exit; try cert := nil; pkey := nil; ca := nil; try {pf} if PKCS12parse(p12, FKeyPassword, pkey, cert, ca) > 0 then if SSLCTXusecertificate(Fctx, cert) > 0 then if SSLCTXusePrivateKey(Fctx, pkey) > 0 then Result := True; {pf} finally EvpPkeyFree(pkey); X509free(cert); SkX509PopFree(ca,_X509Free); // for ca=nil a new STACK was allocated... end; {/pf} finally PKCS12free(p12); end; finally BioFreeAll(b); end; end; function TSSLOpenSSL.SetSslKeys: boolean; var st: TFileStream; s: string; begin Result := False; if not assigned(FCtx) then Exit; try if FCertificateFile <> '' then if SslCtxUseCertificateChainFile(FCtx, FCertificateFile) <> 1 then if SslCtxUseCertificateFile(FCtx, FCertificateFile, SSL_FILETYPE_PEM) <> 1 then if SslCtxUseCertificateFile(FCtx, FCertificateFile, SSL_FILETYPE_ASN1) <> 1 then Exit; if FCertificate <> '' then if SslCtxUseCertificateASN1(FCtx, length(FCertificate), FCertificate) <> 1 then Exit; SSLCheck; if FPrivateKeyFile <> '' then if SslCtxUsePrivateKeyFile(FCtx, FPrivateKeyFile, SSL_FILETYPE_PEM) <> 1 then if SslCtxUsePrivateKeyFile(FCtx, FPrivateKeyFile, SSL_FILETYPE_ASN1) <> 1 then Exit; if FPrivateKey <> '' then if SslCtxUsePrivateKeyASN1(EVP_PKEY_RSA, FCtx, FPrivateKey, length(FPrivateKey)) <> 1 then Exit; SSLCheck; if FCertCAFile <> '' then if SslCtxLoadVerifyLocations(FCtx, FCertCAFile, '') <> 1 then Exit; if FPFXfile <> '' then begin try st := TFileStream.Create(FPFXfile, fmOpenRead or fmShareDenyNone); try s := ReadStrFromStream(st, st.Size); finally st.Free; end; if not LoadPFX(s) then Exit; except on Exception do Exit; end; end; if FPFX <> '' then if not LoadPFX(FPfx) then Exit; SSLCheck; Result := True; finally SSLCheck; end; end; function TSSLOpenSSL.NeedSigningCertificate: boolean; begin Result := (FCertificateFile = '') and (FCertificate = '') and (FPFXfile = '') and (FPFX = ''); end; function TSSLOpenSSL.Init: Boolean; var s: AnsiString; begin Result := False; FLastErrorDesc := ''; FLastError := 0; Fctx := nil; case FSSLType of LT_SSLv2: Fctx := SslCtxNew(SslMethodV2); LT_SSLv3: Fctx := SslCtxNew(SslMethodV3); LT_TLSv1: Fctx := SslCtxNew(SslMethodTLSV1); LT_TLSv1_1: Fctx := SslCtxNew(SslMethodTLSV11); LT_TLSv1_2: Fctx := SslCtxNew(SslMethodTLSV12); LT_all: begin //try new call for OpenSSL 1.1.0 first Fctx := SslCtxNew(SslMethodTLS); if Fctx=nil then //callback to previous versions Fctx := SslCtxNew(SslMethodV23); end; else Exit; end; if Fctx = nil then begin SSLCheck; Exit; end else begin s := FCiphers; SslCtxSetCipherList(Fctx, s); if FVerifyCert then SslCtxSetVerify(FCtx, SSL_VERIFY_PEER, nil) else SslCtxSetVerify(FCtx, SSL_VERIFY_NONE, nil); {$IFNDEF CIL} SslCtxSetDefaultPasswdCb(FCtx, @PasswordCallback); SslCtxSetDefaultPasswdCbUserdata(FCtx, self); {$ENDIF} if server and NeedSigningCertificate then begin CreateSelfSignedcert(FSocket.ResolveIPToName(FSocket.GetRemoteSinIP)); end; if not SetSSLKeys then Exit else begin Fssl := nil; Fssl := SslNew(Fctx); if Fssl = nil then begin SSLCheck; exit; end; end; end; Result := true; end; function TSSLOpenSSL.DeInit: Boolean; begin Result := True; if Assigned(FSessionNew) then begin SslSessionFree(FSessionNew); FSessionNew := nil; end; if assigned (Fssl) then sslfree(Fssl); Fssl := nil; if assigned (Fctx) then begin SslCtxFree(Fctx); Fctx := nil; ErrRemoveState(0); end; FSSLEnabled := False; end; function TSSLOpenSSL.Prepare: Boolean; begin Result := false; DeInit; if Init then Result := true else DeInit; end; function TSSLOpenSSL.Connect: boolean; var x: integer; b: boolean; err: integer; begin Result := False; if FSocket.Socket = INVALID_SOCKET then Exit; FServer := False; if Prepare then begin {$IFDEF CIL} if sslsetfd(FSsl, FSocket.Socket.Handle.ToInt32) < 1 then {$ELSE} if sslsetfd(FSsl, FSocket.Socket) < 1 then {$ENDIF} begin SSLCheck; Exit; end; // Reuse session if Assigned(FSessionOld) then begin SslSetSession(Fssl, FSessionOld); end; if SNIHost<>'' then begin SSLCtrl(Fssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, PAnsiChar(AnsiString(SNIHost))); SslSet1Host(Fssl, PAnsiChar(AnsiString(SNIHost))); end; if FSocket.ConnectionTimeout <= 0 then //do blocking call of SSL_Connect begin x := sslconnect(FSsl); if x < 1 then begin SSLcheck; Exit; end; end else //do non-blocking call of SSL_Connect begin b := Fsocket.NonBlockMode; Fsocket.NonBlockMode := true; repeat x := sslconnect(FSsl); err := SslGetError(FSsl, x); if err = SSL_ERROR_WANT_READ then if not FSocket.CanRead(FSocket.ConnectionTimeout) then break; if err = SSL_ERROR_WANT_WRITE then if not FSocket.CanWrite(FSocket.ConnectionTimeout) then break; until (err <> SSL_ERROR_WANT_READ) and (err <> SSL_ERROR_WANT_WRITE); Fsocket.NonBlockMode := b; if err <> SSL_ERROR_NONE then begin SSLcheck; Exit; end; end; if FverifyCert then if (GetVerifyCert <> 0) or (not DoVerifyCert) then Exit; FSSLEnabled := True; Result := True; end; if Result and (FSessionOld = nil) then begin FSessionNew := SslGet1Session(Fssl); end; end; function TSSLOpenSSL.Accept: boolean; var x: integer; begin Result := False; if FSocket.Socket = INVALID_SOCKET then Exit; FServer := True; if Prepare then begin {$IFDEF CIL} if sslsetfd(FSsl, FSocket.Socket.Handle.ToInt32) < 1 then {$ELSE} if sslsetfd(FSsl, FSocket.Socket) < 1 then {$ENDIF} begin SSLCheck; Exit; end; x := sslAccept(FSsl); if x < 1 then begin SSLcheck; Exit; end; FSSLEnabled := True; Result := True; end; end; function TSSLOpenSSL.Shutdown: boolean; begin if assigned(FSsl) then sslshutdown(FSsl); DeInit; Result := True; end; function TSSLOpenSSL.BiShutdown: boolean; var x: integer; begin if assigned(FSsl) then begin x := sslshutdown(FSsl); if x = 0 then begin Synsock.Shutdown(FSocket.Socket, 1); sslshutdown(FSsl); end; end; DeInit; Result := True; end; function TSSLOpenSSL.SendBuffer(Buffer: TMemory; Len: Integer): Integer; var err: integer; {$IFDEF CIL} s: ansistring; {$ENDIF} begin FLastError := 0; FLastErrorDesc := ''; repeat {$IFDEF CIL} s := StringOf(Buffer); Result := SslWrite(FSsl, s, Len); {$ELSE} Result := SslWrite(FSsl, Buffer , Len); {$ENDIF} err := SslGetError(FSsl, Result); until (err <> SSL_ERROR_WANT_READ) and (err <> SSL_ERROR_WANT_WRITE); if err = SSL_ERROR_ZERO_RETURN then Result := 0 else if (err <> 0) then FLastError := err; end; function TSSLOpenSSL.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; var err: integer; {$IFDEF CIL} sb: stringbuilder; s: ansistring; {$ENDIF} begin FLastError := 0; FLastErrorDesc := ''; repeat {$IFDEF CIL} sb := StringBuilder.Create(Len); Result := SslRead(FSsl, sb, Len); if Result > 0 then begin sb.Length := Result; s := sb.ToString; System.Array.Copy(BytesOf(s), Buffer, length(s)); end; {$ELSE} Result := SslRead(FSsl, Buffer , Len); {$ENDIF} err := SslGetError(FSsl, Result); until (err <> SSL_ERROR_WANT_READ) and (err <> SSL_ERROR_WANT_WRITE); if err = SSL_ERROR_ZERO_RETURN then Result := 0 {pf}// Verze 1.1.0 byla s else tak jak to ted mam, // ve verzi 1.1.1 bylo ELSE zruseno, ale pak je SSL_ERROR_ZERO_RETURN // propagovano jako Chyba. {pf} else {/pf} if (err <> 0) then FLastError := err; end; function TSSLOpenSSL.WaitingData: Integer; begin Result := sslpending(Fssl); end; function TSSLOpenSSL.GetSSLVersion: string; begin if not assigned(FSsl) then Result := '' else Result := SSlGetVersion(FSsl); end; function TSSLOpenSSL.GetPeerSubject: string; var cert: PX509; s: ansistring; {$IFDEF CIL} sb: StringBuilder; {$ENDIF} begin if not assigned(FSsl) then begin Result := ''; Exit; end; cert := SSLGetPeerCertificate(Fssl); if not assigned(cert) then begin Result := ''; Exit; end; {$IFDEF CIL} sb := StringBuilder.Create(4096); Result := X509NameOneline(X509GetSubjectName(cert), sb, 4096); {$ELSE} setlength(s, 4096); Result := X509NameOneline(X509GetSubjectName(cert), s, Length(s)); {$ENDIF} X509Free(cert); end; function TSSLOpenSSL.GetPeerSerialNo: integer; {pf} var cert: PX509; SN: PASN1_INTEGER; begin if not assigned(FSsl) then begin Result := -1; Exit; end; cert := SSLGetPeerCertificate(Fssl); try if not assigned(cert) then begin Result := -1; Exit; end; SN := X509GetSerialNumber(cert); Result := Asn1IntegerGet(SN); finally X509Free(cert); end; end; function TSSLOpenSSL.GetPeerName: string; var s: ansistring; begin s := GetPeerSubject; s := SeparateRight(s, '/CN='); Result := Trim(SeparateLeft(s, '/')); end; function TSSLOpenSSL.GetPeerNameHash: cardinal; {pf} var cert: PX509; begin if not assigned(FSsl) then begin Result := 0; Exit; end; cert := SSLGetPeerCertificate(Fssl); try if not assigned(cert) then begin Result := 0; Exit; end; Result := X509NameHash(X509GetSubjectName(cert)); finally X509Free(cert); end; end; function TSSLOpenSSL.GetPeerIssuer: string; var cert: PX509; s: ansistring; {$IFDEF CIL} sb: StringBuilder; {$ENDIF} begin if not assigned(FSsl) then begin Result := ''; Exit; end; cert := SSLGetPeerCertificate(Fssl); if not assigned(cert) then begin Result := ''; Exit; end; {$IFDEF CIL} sb := StringBuilder.Create(4096); Result := X509NameOneline(X509GetIssuerName(cert), sb, 4096); {$ELSE} setlength(s, 4096); Result := X509NameOneline(X509GetIssuerName(cert), s, Length(s)); {$ENDIF} X509Free(cert); end; function TSSLOpenSSL.GetPeerFingerprint: ansistring; var cert: PX509; x: integer; {$IFDEF CIL} sb: StringBuilder; {$ENDIF} begin if not assigned(FSsl) then begin Result := ''; Exit; end; cert := SSLGetPeerCertificate(Fssl); if not assigned(cert) then begin Result := ''; Exit; end; {$IFDEF CIL} sb := StringBuilder.Create(EVP_MAX_MD_SIZE); X509Digest(cert, EvpGetDigestByName('MD5'), sb, x); sb.Length := x; Result := sb.ToString; {$ELSE} setlength(Result, EVP_MAX_MD_SIZE); X509Digest(cert, EvpGetDigestByName('MD5'), Result, x); SetLength(Result, x); {$ENDIF} X509Free(cert); end; function TSSLOpenSSL.GetCertInfo: string; var cert: PX509; x, y: integer; b: PBIO; s: AnsiString; {$IFDEF CIL} sb: stringbuilder; {$ENDIF} begin if not assigned(FSsl) then begin Result := ''; Exit; end; cert := SSLGetPeerCertificate(Fssl); if not assigned(cert) then begin Result := ''; Exit; end; try {pf} b := BioNew(BioSMem); try X509Print(b, cert); x := bioctrlpending(b); {$IFDEF CIL} sb := StringBuilder.Create(x); y := bioread(b, sb, x); if y > 0 then begin sb.Length := y; s := sb.ToString; end; {$ELSE} setlength(s,x); y := bioread(b,s,x); if y > 0 then setlength(s, y); {$ENDIF} Result := ReplaceString(s, LF, CRLF); finally BioFreeAll(b); end; {pf} finally X509Free(cert); end; {/pf} end; function TSSLOpenSSL.GetCipherName: string; begin if not assigned(FSsl) then Result := '' else Result := SslCipherGetName(SslGetCurrentCipher(FSsl)); end; function TSSLOpenSSL.GetCipherBits: integer; var x: integer; begin if not assigned(FSsl) then Result := 0 else Result := SSLCipherGetBits(SslGetCurrentCipher(FSsl), x); end; function TSSLOpenSSL.GetCipherAlgBits: integer; begin if not assigned(FSsl) then Result := 0 else SSLCipherGetBits(SslGetCurrentCipher(FSsl), Result); end; function TSSLOpenSSL.GetVerifyCert: integer; begin if not assigned(FSsl) then Result := 1 else Result := SslGetVerifyResult(FSsl); end; {==============================================================================} initialization if InitSSLInterface then SSLImplementation := TSSLOpenSSL; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_openssl_lib.pas����������������������������������������0000644�0001750�0000144�00000243573�14743153644�023263� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 003.009.001 | |==============================================================================| | Content: SSL support by OpenSSL | |==============================================================================| | Copyright (c)1999-2017, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2002-2017. | | Portions created by Petr Fejfar are Copyright (c)2011-2012. | | Portions created by Pepak are Copyright (c)2018. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | | Tomas Hajny (OS2 support) | | Pepak (multiversion support) | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} { Special thanks to Gregor Ibic <gregor.ibic@intelicom.si> (Intelicom d.o.o., http://www.intelicom.si) for good inspiration about begin with SSL programming. } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} {$IFDEF VER125} {$DEFINE BCB} {$ENDIF} {$IFDEF BCB} {$ObjExportAll On} (*$HPPEMIT 'namespace ssl_openssl_lib { using System::Shortint; }' *) {$ENDIF} //old Delphi does not have MSWINDOWS define. {$IFDEF WIN32} {$IFNDEF MSWINDOWS} {$DEFINE MSWINDOWS} {$ENDIF} {$ENDIF} {:@abstract(OpenSSL support) This unit is Pascal interface to OpenSSL library (used by @link(ssl_openssl) unit). OpenSSL is loaded dynamicly on-demand. If this library is not found in system, requested OpenSSL function just return errorcode. } unit ssl_openssl_lib; interface uses {$IFDEF CIL} System.Runtime.InteropServices, System.Text, {$ENDIF} Classes, synafpc, {$IFNDEF MSWINDOWS} {$IFDEF FPC} {$IFDEF UNIX} BaseUnix, {$ENDIF UNIX} {$ELSE} Libc, {$ENDIF} SysUtils; {$ELSE} SysUtils, Windows; {$ENDIF} {$IFDEF CIL} const {$IFDEF LINUX} DLLSSLName = 'libssl.so'; DLLUtilName = 'libcrypto.so'; {$ELSE} DLLSSLName = 'ssleay32.dll'; DLLUtilName = 'libeay32.dll'; {$ENDIF} {$ELSE} var {$IFNDEF MSWINDOWS} {$IFDEF DARWIN} DLLSSLName: string = 'libssl.dylib'; DLLUtilName: string = 'libcrypto.dylib'; {$ELSE} {$IFDEF OS2} {$IFDEF OS2GCC} DLLSSLName: string = 'kssl.dll'; DLLUtilName: string = 'kcrypto.dll'; {$ELSE OS2GCC} DLLSSLName: string = 'ssl.dll'; DLLUtilName: string = 'crypto.dll'; {$ENDIF OS2GCC} {$ELSE OS2} DLLSSLName: string = 'libssl.so'; DLLUtilName: string = 'libcrypto.so'; {$ENDIF OS2} {$ENDIF} {$ELSE} DLLSSLName: string = 'ssleay32.dll'; DLLSSLName2: string = 'libssl32.dll'; DLLUtilName: string = 'libeay32.dll'; {$ENDIF} {$IFDEF MSWINDOWS} const LibCount = 5; SSLLibNames: array[0..LibCount-1] of string = ( // OpenSSL v3.0 {$IFDEF WIN64} 'libssl-3-x64.dll', {$ELSE} 'libssl-3.dll', {$ENDIF} // OpenSSL v1.1.x {$IFDEF WIN64} 'libssl-1_1-x64.dll', {$ELSE} 'libssl-1_1.dll', {$ENDIF} // OpenSSL v1.0.2 distinct names for x64 and x86 {$IFDEF WIN64} 'ssleay32-x64.dll', {$ELSE} 'ssleay32-x86.dll', {$ENDIF} // OpenSSL v1.0.2 'ssleay32.dll', // OpenSSL (ancient) 'libssl32.dll' ); CryptoLibNames: array[0..LibCount-1] of string = ( // OpenSSL v3.0 {$IFDEF WIN64} 'libcrypto-3-x64.dll', {$ELSE} 'libcrypto-3.dll', {$ENDIF} // OpenSSL v1.1.x {$IFDEF WIN64} 'libcrypto-1_1-x64.dll', {$ELSE} 'libcrypto-1_1.dll', {$ENDIF} // OpenSSL v1.0.2 distinct names for x64 and x86 {$IFDEF WIN64} 'libeay32-x64.dll', {$ELSE} 'libeay32-x86.dll', {$ENDIF} // OpenSSL v1.0.2 'libeay32.dll', // OpenSSL (ancient) 'libeay32.dll' ); {$ENDIF} {$ENDIF} type {$IFDEF CIL} SslPtr = IntPtr; {$ELSE} SslPtr = Pointer; {$ENDIF} PSslPtr = ^SslPtr; PSSL_CTX = SslPtr; PSSL = SslPtr; PSSL_METHOD = SslPtr; PX509 = SslPtr; PX509_NAME = SslPtr; PEVP_MD = SslPtr; PInteger = ^Integer; PBIO_METHOD = SslPtr; PBIO = SslPtr; EVP_PKEY = SslPtr; PRSA = SslPtr; PASN1_UTCTIME = SslPtr; PASN1_INTEGER = SslPtr; PPasswdCb = SslPtr; PFunction = procedure; PSTACK = SslPtr; {pf} TSkPopFreeFunc = procedure(p:SslPtr); cdecl; {pf} TX509Free = procedure(x: PX509); cdecl; {pf} DES_cblock = array[0..7] of Byte; PDES_cblock = ^DES_cblock; des_ks_struct = packed record ks: DES_cblock; weak_key: Integer; end; des_key_schedule = array[1..16] of des_ks_struct; const EVP_MAX_MD_SIZE = 16 + 20; SSL_ERROR_NONE = 0; SSL_ERROR_SSL = 1; SSL_ERROR_WANT_READ = 2; SSL_ERROR_WANT_WRITE = 3; SSL_ERROR_WANT_X509_LOOKUP = 4; SSL_ERROR_SYSCALL = 5; //look at error stack/return value/errno SSL_ERROR_ZERO_RETURN = 6; SSL_ERROR_WANT_CONNECT = 7; SSL_ERROR_WANT_ACCEPT = 8; SSL_OP_NO_SSLv2 = $01000000; SSL_OP_NO_SSLv3 = $02000000; SSL_OP_NO_TLSv1 = $04000000; SSL_OP_ALL = $000FFFFF; SSL_VERIFY_NONE = $00; SSL_VERIFY_PEER = $01; OPENSSL_DES_DECRYPT = 0; OPENSSL_DES_ENCRYPT = 1; X509_V_OK = 0; X509_V_ILLEGAL = 1; X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2; X509_V_ERR_UNABLE_TO_GET_CRL = 3; X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4; X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5; X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6; X509_V_ERR_CERT_SIGNATURE_FAILURE = 7; X509_V_ERR_CRL_SIGNATURE_FAILURE = 8; X509_V_ERR_CERT_NOT_YET_VALID = 9; X509_V_ERR_CERT_HAS_EXPIRED = 10; X509_V_ERR_CRL_NOT_YET_VALID = 11; X509_V_ERR_CRL_HAS_EXPIRED = 12; X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13; X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14; X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15; X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16; X509_V_ERR_OUT_OF_MEM = 17; X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18; X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19; X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20; X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21; X509_V_ERR_CERT_CHAIN_TOO_LONG = 22; X509_V_ERR_CERT_REVOKED = 23; X509_V_ERR_INVALID_CA = 24; X509_V_ERR_PATH_LENGTH_EXCEEDED = 25; X509_V_ERR_INVALID_PURPOSE = 26; X509_V_ERR_CERT_UNTRUSTED = 27; X509_V_ERR_CERT_REJECTED = 28; //These are 'informational' when looking for issuer cert X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29; X509_V_ERR_AKID_SKID_MISMATCH = 30; X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31; X509_V_ERR_KEYUSAGE_NO_CERTSIGN = 32; X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = 33; X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = 34; //The application is not happy X509_V_ERR_APPLICATION_VERIFICATION = 50; SSL_FILETYPE_ASN1 = 2; SSL_FILETYPE_PEM = 1; EVP_PKEY_RSA = 6; SSL_CTRL_SET_TLSEXT_HOSTNAME = 55; TLSEXT_NAMETYPE_host_name = 0; var SSLLibHandle: TLibHandle = 0; SSLUtilHandle: TLibHandle = 0; SSLLibFile: string = ''; SSLUtilFile: string = ''; {$IFDEF CIL} [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_get_error')] function SslGetError(s: PSSL; ret_code: Integer): Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_library_init')] function SslLibraryInit: Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_load_error_strings')] procedure SslLoadErrorStrings; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_set_cipher_list')] function SslCtxSetCipherList(arg0: PSSL_CTX; var str: String): Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_new')] function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_free')] procedure SslCtxFree (arg0: PSSL_CTX); external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_set_fd')] function SslSetFd(s: PSSL; fd: Integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSLv2_method')] function SslMethodV2 : PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSLv3_method')] function SslMethodV3 : PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'TLSv1_method')] function SslMethodTLSV1:PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'TLSv1_1_method')] function SslMethodTLSV11:PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'TLSv1_2_method')] function SslMethodTLSV12:PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSLv23_method')] function SslMethodV23 : PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'TLS_method')] function SslMethodTLS : PSSL_METHOD; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_PrivateKey')] function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_PrivateKey_ASN1')] function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: String; len: integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_RSAPrivateKey_file')] function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_certificate')] function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_certificate_ASN1')] function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: String):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_certificate_file')] function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer;external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_use_certificate_chain_file')] function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: String):Integer;external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_check_private_key')] function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_set_default_passwd_cb')] procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb); external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_set_default_passwd_cb_userdata')] procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: IntPtr); external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_load_verify_locations')] function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; CAfile: string; CApath: String):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_ctrl')] function SslCtxCtrl(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: IntPtr): integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_new')] function SslNew(ctx: PSSL_CTX):PSSL; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_free')] procedure SslFree(ssl: PSSL); external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_accept')] function SslAccept(ssl: PSSL):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_connect')] function SslConnect(ssl: PSSL):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_shutdown')] function SslShutdown(s: PSSL):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_read')] function SslRead(ssl: PSSL; buf: StringBuilder; num: Integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_peek')] function SslPeek(ssl: PSSL; buf: StringBuilder; num: Integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_write')] function SslWrite(ssl: PSSL; buf: String; num: Integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_pending')] function SslPending(ssl: PSSL):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_get_version')] function SslGetVersion(ssl: PSSL):String; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_get_peer_certificate')] function SslGetPeerCertificate(s: PSSL):PX509; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CTX_set_verify')] procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction); external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_get_current_cipher')] function SSLGetCurrentCipher(s: PSSL): SslPtr; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CIPHER_get_name')] function SSLCipherGetName(c: SslPtr):String; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_CIPHER_get_bits')] function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer; external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_get_verify_result')] function SSLGetVerifyResult(ssl: PSSL):Integer;external; [DllImport(DLLSSLName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSL_ctrl')] function SslCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: IntPtr): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_new')] function X509New: PX509; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_free')] procedure X509Free(x: PX509); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_NAME_oneline')] function X509NameOneline(a: PX509_NAME; buf: StringBuilder; size: Integer): String; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_get_subject_name')] function X509GetSubjectName(a: PX509):PX509_NAME; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_get_issuer_name')] function X509GetIssuerName(a: PX509):PX509_NAME; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_NAME_hash')] function X509NameHash(x: PX509_NAME):Cardinal; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_digest')] function X509Digest (data: PX509; _type: PEVP_MD; md: StringBuilder; var len: Integer):Integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_set_version')] function X509SetVersion(x: PX509; version: integer): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_set_pubkey')] function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_set_issuer_name')] function X509SetIssuerName(x: PX509; name: PX509_NAME): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_NAME_add_entry_by_txt')] function X509NameAddEntryByTxt(name: PX509_NAME; field: string; _type: integer; bytes: string; len, loc, _set: integer): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_sign')] function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_print')] function X509print(b: PBIO; a: PX509): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_gmtime_adj')] function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_set_notBefore')] function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_set_notAfter')] function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'X509_get_serialNumber')] function X509GetSerialNumber(x: PX509): PASN1_INTEGER; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'EVP_PKEY_new')] function EvpPkeyNew: EVP_PKEY; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'EVP_PKEY_free')] procedure EvpPkeyFree(pk: EVP_PKEY); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'EVP_PKEY_assign')] function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'EVP_get_digestbyname')] function EvpGetDigestByName(Name: String): PEVP_MD; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'EVP_cleanup')] procedure EVPcleanup; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'SSLeay_version')] function SSLeayversion(t: integer): String; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ERR_error_string_n')] procedure ErrErrorString(e: integer; buf: StringBuilder; len: integer); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ERR_get_error')] function ErrGetError: integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ERR_clear_error')] procedure ErrClearError; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ERR_free_strings')] procedure ErrFreeStrings; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ERR_remove_state')] procedure ErrRemoveState(pid: integer); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'OPENSSL_add_all_algorithms_noconf')] procedure OPENSSLaddallalgorithms; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'CRYPTO_cleanup_all_ex_data')] procedure CRYPTOcleanupAllExData; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'RAND_screen')] procedure RandScreen; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'BIO_new')] function BioNew(b: PBIO_METHOD): PBIO; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'BIO_free_all')] procedure BioFreeAll(b: PBIO); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'BIO_s_mem')] function BioSMem: PBIO_METHOD; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'BIO_ctrl_pending')] function BioCtrlPending(b: PBIO): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'BIO_read')] function BioRead(b: PBIO; Buf: StringBuilder; Len: integer): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'BIO_write')] function BioWrite(b: PBIO; var Buf: String; Len: integer): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'd2i_PKCS12_bio')] function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'PKCS12_parse')] function PKCS12parse(p12: SslPtr; pass: string; var pkey, cert, ca: SslPtr): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'PKCS12_free')] procedure PKCS12free(p12: SslPtr); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'RSA_generate_key')] function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ASN1_UTCTIME_new')] function Asn1UtctimeNew: PASN1_UTCTIME; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ASN1_UTCTIME_free')] procedure Asn1UtctimeFree(a: PASN1_UTCTIME); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'ASN1_INTEGER_set')] function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'i2d_X509_bio')] function i2dX509bio(b: PBIO; x: PX509): integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'i2d_PrivateKey_bio')] function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer; external; // 3DES functions [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'DES_set_odd_parity')] procedure DESsetoddparity(Key: des_cblock); external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'DES_set_key_checked')] function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer; external; [DllImport(DLLUtilName, CharSet = CharSet.Ansi, SetLastError = False, CallingConvention= CallingConvention.cdecl, EntryPoint = 'DES_ecb_encrypt')] procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); external; {$ELSE} // libssl.dll function SslGetError(s: PSSL; ret_code: Integer):Integer; function SslLibraryInit:Integer; procedure SslLoadErrorStrings; // function SslCtxSetCipherList(arg0: PSSL_CTX; str: PChar):Integer; function SslCtxSetCipherList(arg0: PSSL_CTX; var str: AnsiString):Integer; function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX; procedure SslCtxFree(arg0: PSSL_CTX); function SslSetFd(s: PSSL; fd: Integer):Integer; function SslMethodV2:PSSL_METHOD; function SslMethodV3:PSSL_METHOD; function SslMethodTLSV1:PSSL_METHOD; function SslMethodTLSV11:PSSL_METHOD; function SslMethodTLSV12:PSSL_METHOD; function SslMethodV23:PSSL_METHOD; function SslMethodTLS:PSSL_METHOD; function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer; function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: AnsiString; len: integer):Integer; // function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer; function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer; function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: AnsiString):Integer; function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; // function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: PChar):Integer; function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: AnsiString):Integer; function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer; procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb); procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: SslPtr); // function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer; function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: AnsiString; const CApath: AnsiString):Integer; function SslCtxCtrl(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: SslPtr): integer; function SslNew(ctx: PSSL_CTX):PSSL; procedure SslFree(ssl: PSSL); function SslAccept(ssl: PSSL):Integer; function SslConnect(ssl: PSSL):Integer; function SslShutdown(ssl: PSSL):Integer; function SslRead(ssl: PSSL; buf: SslPtr; num: Integer):Integer; function SslPeek(ssl: PSSL; buf: SslPtr; num: Integer):Integer; function SslWrite(ssl: PSSL; buf: SslPtr; num: Integer):Integer; function SslPending(ssl: PSSL):Integer; function SslGetVersion(ssl: PSSL):AnsiString; function SslGetPeerCertificate(ssl: PSSL):PX509; procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction); function SSLGetCurrentCipher(s: PSSL):SslPtr; function SSLCipherGetName(c: SslPtr): AnsiString; function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer; function SSLGetVerifyResult(ssl: PSSL):Integer; function SSLCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; function SslSet1Host(ssl: PSSL; hostname: PAnsiChar):Integer; procedure SslSessionFree(session: PSslPtr); function SslGet1Session(ssl: PSSL):PSslPtr; function SslSetSession(ssl: PSSL; session: PSslPtr): Integer; // libeay.dll function X509New: PX509; procedure X509Free(x: PX509); function X509NameOneline(a: PX509_NAME; var buf: AnsiString; size: Integer):AnsiString; function X509GetSubjectName(a: PX509):PX509_NAME; function X509GetIssuerName(a: PX509):PX509_NAME; function X509NameHash(x: PX509_NAME):Cardinal; // function SslX509Digest(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer; function X509Digest(data: PX509; _type: PEVP_MD; md: AnsiString; var len: Integer):Integer; function X509print(b: PBIO; a: PX509): integer; function X509SetVersion(x: PX509; version: integer): integer; function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer; function X509SetIssuerName(x: PX509; name: PX509_NAME): integer; function X509NameAddEntryByTxt(name: PX509_NAME; field: Ansistring; _type: integer; bytes: Ansistring; len, loc, _set: integer): integer; function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer; function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer; function X509GetSerialNumber(x: PX509): PASN1_INTEGER; function EvpPkeyNew: EVP_PKEY; procedure EvpPkeyFree(pk: EVP_PKEY); function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; function EvpGetDigestByName(Name: AnsiString): PEVP_MD; procedure EVPcleanup; // function ErrErrorString(e: integer; buf: PChar): PChar; function SSLeayversion(t: integer): Ansistring; procedure ErrErrorString(e: integer; var buf: Ansistring; len: integer); function ErrGetError: integer; procedure ErrClearError; procedure ErrFreeStrings; procedure ErrRemoveState(pid: integer); procedure OPENSSLaddallalgorithms; procedure CRYPTOcleanupAllExData; procedure RandScreen; function BioNew(b: PBIO_METHOD): PBIO; procedure BioFreeAll(b: PBIO); function BioSMem: PBIO_METHOD; function BioCtrlPending(b: PBIO): integer; function BioRead(b: PBIO; var Buf: AnsiString; Len: integer): integer; function BioWrite(b: PBIO; Buf: AnsiString; Len: integer): integer; function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr; function PKCS12parse(p12: SslPtr; pass: Ansistring; var pkey, cert, ca: SslPtr): integer; procedure PKCS12free(p12: SslPtr); function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; function Asn1UtctimeNew: PASN1_UTCTIME; procedure Asn1UtctimeFree(a: PASN1_UTCTIME); function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer; function Asn1IntegerGet(a: PASN1_INTEGER): integer; {pf} function i2dX509bio(b: PBIO; x: PX509): integer; function d2iX509bio(b:PBIO; x:PX509): PX509; {pf} function PEMReadBioX509(b:PBIO; {var x:PX509;}x:PSslPtr; callback:PFunction; cb_arg: SslPtr): PX509; {pf} procedure SkX509PopFree(st: PSTACK; func: TSkPopFreeFunc); {pf} function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer; // 3DES functions procedure DESsetoddparity(Key: des_cblock); function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer; procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); {$ENDIF} function IsSSLloaded: Boolean; function InitSSLInterface: Boolean; function DestroySSLInterface: Boolean; var _X509Free: TX509Free = nil; {pf} implementation uses {$IFDEF OS2} Sockets, {$ENDIF OS2} SyncObjs; {$IFNDEF CIL} type // libssl.dll TSslGetError = function(s: PSSL; ret_code: Integer):Integer; cdecl; TSslLibraryInit = function:Integer; cdecl; TSslLoadErrorStrings = procedure; cdecl; TSslCtxSetCipherList = function(arg0: PSSL_CTX; str: PAnsiChar):Integer; cdecl; TSslCtxNew = function(meth: PSSL_METHOD):PSSL_CTX; cdecl; TSslCtxFree = procedure(arg0: PSSL_CTX); cdecl; TSslSetFd = function(s: PSSL; fd: Integer):Integer; cdecl; TSslMethodV2 = function:PSSL_METHOD; cdecl; TSslMethodV3 = function:PSSL_METHOD; cdecl; TSslMethodTLSV1 = function:PSSL_METHOD; cdecl; TSslMethodTLSV11 = function:PSSL_METHOD; cdecl; TSslMethodTLSV12 = function:PSSL_METHOD; cdecl; TSslMethodV23 = function:PSSL_METHOD; cdecl; TSslMethodTLS = function:PSSL_METHOD; cdecl; TSslCtxUsePrivateKey = function(ctx: PSSL_CTX; pkey: sslptr):Integer; cdecl; TSslCtxUsePrivateKeyASN1 = function(pk: integer; ctx: PSSL_CTX; d: sslptr; len: integer):Integer; cdecl; TSslCtxUsePrivateKeyFile = function(ctx: PSSL_CTX; const _file: PAnsiChar; _type: Integer):Integer; cdecl; TSslCtxUseCertificate = function(ctx: PSSL_CTX; x: SslPtr):Integer; cdecl; TSslCtxUseCertificateASN1 = function(ctx: PSSL_CTX; len: Integer; d: SslPtr):Integer; cdecl; TSslCtxUseCertificateFile = function(ctx: PSSL_CTX; const _file: PAnsiChar; _type: Integer):Integer; cdecl; TSslCtxUseCertificateChainFile = function(ctx: PSSL_CTX; const _file: PAnsiChar):Integer; cdecl; TSslCtxCheckPrivateKeyFile = function(ctx: PSSL_CTX):Integer; cdecl; TSslCtxSetDefaultPasswdCb = procedure(ctx: PSSL_CTX; cb: SslPtr); cdecl; TSslCtxSetDefaultPasswdCbUserdata = procedure(ctx: PSSL_CTX; u: SslPtr); cdecl; TSslCtxLoadVerifyLocations = function(ctx: PSSL_CTX; const CAfile: PAnsiChar; const CApath: PAnsiChar):Integer; cdecl; TSslCtxCtrl = function(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: SslPtr): integer; cdecl; TSslNew = function(ctx: PSSL_CTX):PSSL; cdecl; TSslFree = procedure(ssl: PSSL); cdecl; TSslAccept = function(ssl: PSSL):Integer; cdecl; TSslConnect = function(ssl: PSSL):Integer; cdecl; TSslShutdown = function(ssl: PSSL):Integer; cdecl; TSslRead = function(ssl: PSSL; buf: PAnsiChar; num: Integer):Integer; cdecl; TSslPeek = function(ssl: PSSL; buf: PAnsiChar; num: Integer):Integer; cdecl; TSslWrite = function(ssl: PSSL; const buf: PAnsiChar; num: Integer):Integer; cdecl; TSslPending = function(ssl: PSSL):Integer; cdecl; TSslGetVersion = function(ssl: PSSL):PAnsiChar; cdecl; TSslGetPeerCertificate = function(ssl: PSSL):PX509; cdecl; TSslCtxSetVerify = procedure(ctx: PSSL_CTX; mode: Integer; arg2: SslPtr); cdecl; TSSLGetCurrentCipher = function(s: PSSL):SslPtr; cdecl; TSSLCipherGetName = function(c: Sslptr):PAnsiChar; cdecl; TSSLCipherGetBits = function(c: SslPtr; alg_bits: PInteger):Integer; cdecl; TSSLGetVerifyResult = function(ssl: PSSL):Integer; cdecl; TSSLCtrl = function(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; cdecl; TSslSet1Host = function(ssl: PSSL; hostname: PAnsiChar):Integer; cdecl; TSslSessionFree = procedure(session: PSslPtr); cdecl; TSslGet1Session = function(ssl: PSSL):PSslPtr; cdecl; TSslSetSession = function(ssl: PSSL; session: PSslPtr): Integer; cdecl; TSSLSetTlsextHostName = function(ssl: PSSL; buf: PAnsiChar):Integer; cdecl; // libeay.dll TX509New = function: PX509; cdecl; TX509NameOneline = function(a: PX509_NAME; buf: PAnsiChar; size: Integer):PAnsiChar; cdecl; TX509GetSubjectName = function(a: PX509):PX509_NAME; cdecl; TX509GetIssuerName = function(a: PX509):PX509_NAME; cdecl; TX509NameHash = function(x: PX509_NAME):Cardinal; cdecl; TX509Digest = function(data: PX509; _type: PEVP_MD; md: PAnsiChar; len: PInteger):Integer; cdecl; TX509print = function(b: PBIO; a: PX509): integer; cdecl; TX509SetVersion = function(x: PX509; version: integer): integer; cdecl; TX509SetPubkey = function(x: PX509; pkey: EVP_PKEY): integer; cdecl; TX509SetIssuerName = function(x: PX509; name: PX509_NAME): integer; cdecl; TX509NameAddEntryByTxt = function(name: PX509_NAME; field: PAnsiChar; _type: integer; bytes: PAnsiChar; len, loc, _set: integer): integer; cdecl; TX509Sign = function(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; cdecl; TX509GmtimeAdj = function(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; cdecl; TX509SetNotBefore = function(x: PX509; tm: PASN1_UTCTIME): integer; cdecl; TX509SetNotAfter = function(x: PX509; tm: PASN1_UTCTIME): integer; cdecl; TX509GetSerialNumber = function(x: PX509): PASN1_INTEGER; cdecl; TEvpPkeyNew = function: EVP_PKEY; cdecl; TEvpPkeyFree = procedure(pk: EVP_PKEY); cdecl; TEvpPkeyAssign = function(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; cdecl; TEvpGetDigestByName = function(Name: PAnsiChar): PEVP_MD; cdecl; TEVPcleanup = procedure; cdecl; TSSLeayversion = function(t: integer): PAnsiChar; cdecl; TErrErrorString = procedure(e: integer; buf: PAnsiChar; len: integer); cdecl; TErrGetError = function: integer; cdecl; TErrClearError = procedure; cdecl; TErrFreeStrings = procedure; cdecl; TErrRemoveState = procedure(pid: integer); cdecl; TOPENSSLaddallalgorithms = procedure; cdecl; TCRYPTOcleanupAllExData = procedure; cdecl; TRandScreen = procedure; cdecl; TBioNew = function(b: PBIO_METHOD): PBIO; cdecl; TBioFreeAll = procedure(b: PBIO); cdecl; TBioSMem = function: PBIO_METHOD; cdecl; TBioCtrlPending = function(b: PBIO): integer; cdecl; TBioRead = function(b: PBIO; Buf: PAnsiChar; Len: integer): integer; cdecl; TBioWrite = function(b: PBIO; Buf: PAnsiChar; Len: integer): integer; cdecl; Td2iPKCS12bio = function(b:PBIO; Pkcs12: SslPtr): SslPtr; cdecl; TPKCS12parse = function(p12: SslPtr; pass: PAnsiChar; var pkey, cert, ca: SslPtr): integer; cdecl; TPKCS12free = procedure(p12: SslPtr); cdecl; TRsaGenerateKey = function(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; cdecl; TAsn1UtctimeNew = function: PASN1_UTCTIME; cdecl; TAsn1UtctimeFree = procedure(a: PASN1_UTCTIME); cdecl; TAsn1IntegerSet = function(a: PASN1_INTEGER; v: integer): integer; cdecl; TAsn1IntegerGet = function(a: PASN1_INTEGER): integer; cdecl; {pf} Ti2dX509bio = function(b: PBIO; x: PX509): integer; cdecl; Td2iX509bio = function(b:PBIO; x:PX509): PX509; cdecl; {pf} TPEMReadBioX509 = function(b:PBIO; {var x:PX509;}x:PSslPtr; callback:PFunction; cb_arg:SslPtr): PX509; cdecl; {pf} TSkX509PopFree = procedure(st: PSTACK; func: TSkPopFreeFunc); cdecl; {pf} Ti2dPrivateKeyBio= function(b: PBIO; pkey: EVP_PKEY): integer; cdecl; // 3DES functions TDESsetoddparity = procedure(Key: des_cblock); cdecl; TDESsetkeychecked = function(key: des_cblock; schedule: des_key_schedule): Integer; cdecl; TDESecbencrypt = procedure(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); cdecl; //thread lock functions TCRYPTOnumlocks = function: integer; cdecl; TCRYPTOSetLockingCallback = procedure(cb: Sslptr); cdecl; var // libssl.dll _SslGetError: TSslGetError = nil; _SslLibraryInit: TSslLibraryInit = nil; _SslLoadErrorStrings: TSslLoadErrorStrings = nil; _SslCtxSetCipherList: TSslCtxSetCipherList = nil; _SslCtxNew: TSslCtxNew = nil; _SslCtxFree: TSslCtxFree = nil; _SslSetFd: TSslSetFd = nil; _SslMethodV2: TSslMethodV2 = nil; _SslMethodV3: TSslMethodV3 = nil; _SslMethodTLSV1: TSslMethodTLSV1 = nil; _SslMethodTLSV11: TSslMethodTLSV11 = nil; _SslMethodTLSV12: TSslMethodTLSV12 = nil; _SslMethodV23: TSslMethodV23 = nil; _SslMethodTLS: TSslMethodTLS = nil; _SslCtxUsePrivateKey: TSslCtxUsePrivateKey = nil; _SslCtxUsePrivateKeyASN1: TSslCtxUsePrivateKeyASN1 = nil; _SslCtxUsePrivateKeyFile: TSslCtxUsePrivateKeyFile = nil; _SslCtxUseCertificate: TSslCtxUseCertificate = nil; _SslCtxUseCertificateASN1: TSslCtxUseCertificateASN1 = nil; _SslCtxUseCertificateFile: TSslCtxUseCertificateFile = nil; _SslCtxUseCertificateChainFile: TSslCtxUseCertificateChainFile = nil; _SslCtxCheckPrivateKeyFile: TSslCtxCheckPrivateKeyFile = nil; _SslCtxSetDefaultPasswdCb: TSslCtxSetDefaultPasswdCb = nil; _SslCtxSetDefaultPasswdCbUserdata: TSslCtxSetDefaultPasswdCbUserdata = nil; _SslCtxLoadVerifyLocations: TSslCtxLoadVerifyLocations = nil; _SslCtxCtrl: TSslCtxCtrl = nil; _SslNew: TSslNew = nil; _SslFree: TSslFree = nil; _SslAccept: TSslAccept = nil; _SslConnect: TSslConnect = nil; _SslShutdown: TSslShutdown = nil; _SslRead: TSslRead = nil; _SslPeek: TSslPeek = nil; _SslWrite: TSslWrite = nil; _SslPending: TSslPending = nil; _SslGetVersion: TSslGetVersion = nil; _SslGetPeerCertificate: TSslGetPeerCertificate = nil; _SslCtxSetVerify: TSslCtxSetVerify = nil; _SSLGetCurrentCipher: TSSLGetCurrentCipher = nil; _SSLCipherGetName: TSSLCipherGetName = nil; _SSLCipherGetBits: TSSLCipherGetBits = nil; _SSLGetVerifyResult: TSSLGetVerifyResult = nil; _SSLCtrl: TSSLCtrl = nil; _SslSet1Host: TSslSet1Host = nil; _SslSessionFree: TSslSessionFree = nil; _SslGet1Session: TSslGet1Session = nil; _SslSetSession: TSslSetSession = nil; // libeay.dll _X509New: TX509New = nil; _X509NameOneline: TX509NameOneline = nil; _X509GetSubjectName: TX509GetSubjectName = nil; _X509GetIssuerName: TX509GetIssuerName = nil; _X509NameHash: TX509NameHash = nil; _X509Digest: TX509Digest = nil; _X509print: TX509print = nil; _X509SetVersion: TX509SetVersion = nil; _X509SetPubkey: TX509SetPubkey = nil; _X509SetIssuerName: TX509SetIssuerName = nil; _X509NameAddEntryByTxt: TX509NameAddEntryByTxt = nil; _X509Sign: TX509Sign = nil; _X509GmtimeAdj: TX509GmtimeAdj = nil; _X509SetNotBefore: TX509SetNotBefore = nil; _X509SetNotAfter: TX509SetNotAfter = nil; _X509GetSerialNumber: TX509GetSerialNumber = nil; _EvpPkeyNew: TEvpPkeyNew = nil; _EvpPkeyFree: TEvpPkeyFree = nil; _EvpPkeyAssign: TEvpPkeyAssign = nil; _EvpGetDigestByName: TEvpGetDigestByName = nil; _EVPcleanup: TEVPcleanup = nil; _SSLeayversion: TSSLeayversion = nil; _ErrErrorString: TErrErrorString = nil; _ErrGetError: TErrGetError = nil; _ErrClearError: TErrClearError = nil; _ErrFreeStrings: TErrFreeStrings = nil; _ErrRemoveState: TErrRemoveState = nil; _OPENSSLaddallalgorithms: TOPENSSLaddallalgorithms = nil; _CRYPTOcleanupAllExData: TCRYPTOcleanupAllExData = nil; _RandScreen: TRandScreen = nil; _BioNew: TBioNew = nil; _BioFreeAll: TBioFreeAll = nil; _BioSMem: TBioSMem = nil; _BioCtrlPending: TBioCtrlPending = nil; _BioRead: TBioRead = nil; _BioWrite: TBioWrite = nil; _d2iPKCS12bio: Td2iPKCS12bio = nil; _PKCS12parse: TPKCS12parse = nil; _PKCS12free: TPKCS12free = nil; _RsaGenerateKey: TRsaGenerateKey = nil; _Asn1UtctimeNew: TAsn1UtctimeNew = nil; _Asn1UtctimeFree: TAsn1UtctimeFree = nil; _Asn1IntegerSet: TAsn1IntegerSet = nil; _Asn1IntegerGet: TAsn1IntegerGet = nil; {pf} _i2dX509bio: Ti2dX509bio = nil; _d2iX509bio: Td2iX509bio = nil; {pf} _PEMReadBioX509: TPEMReadBioX509 = nil; {pf} _SkX509PopFree: TSkX509PopFree = nil; {pf} _i2dPrivateKeyBio: Ti2dPrivateKeyBio = nil; // 3DES functions _DESsetoddparity: TDESsetoddparity = nil; _DESsetkeychecked: TDESsetkeychecked = nil; _DESecbencrypt: TDESecbencrypt = nil; //thread lock functions _CRYPTOnumlocks: TCRYPTOnumlocks = nil; _CRYPTOSetLockingCallback: TCRYPTOSetLockingCallback = nil; {$ENDIF} var SSLCS: TCriticalSection; SSLloaded: boolean = false; {$IFNDEF CIL} Locks: TList; {$ENDIF} {$IFNDEF CIL} // libssl.dll function SslGetError(s: PSSL; ret_code: Integer):Integer; begin if InitSSLInterface and Assigned(_SslGetError) then Result := _SslGetError(s, ret_code) else Result := SSL_ERROR_SSL; end; function SslLibraryInit:Integer; begin if InitSSLInterface and Assigned(_SslLibraryInit) then Result := _SslLibraryInit else Result := 1; end; procedure SslLoadErrorStrings; begin if InitSSLInterface and Assigned(_SslLoadErrorStrings) then _SslLoadErrorStrings; end; //function SslCtxSetCipherList(arg0: PSSL_CTX; str: PChar):Integer; function SslCtxSetCipherList(arg0: PSSL_CTX; var str: AnsiString):Integer; begin if InitSSLInterface and Assigned(_SslCtxSetCipherList) then Result := _SslCtxSetCipherList(arg0, PAnsiChar(str)) else Result := 0; end; function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX; begin if InitSSLInterface and Assigned(_SslCtxNew) then Result := _SslCtxNew(meth) else Result := nil; end; procedure SslCtxFree(arg0: PSSL_CTX); begin if InitSSLInterface and Assigned(_SslCtxFree) then _SslCtxFree(arg0); end; function SslSetFd(s: PSSL; fd: Integer):Integer; begin if InitSSLInterface and Assigned(_SslSetFd) then Result := _SslSetFd(s, fd) else Result := 0; end; function SslMethodV2:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodV2) then Result := _SslMethodV2 else Result := nil; end; function SslMethodV3:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodV3) then Result := _SslMethodV3 else Result := nil; end; function SslMethodTLSV1:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodTLSV1) then Result := _SslMethodTLSV1 else Result := nil; end; function SslMethodTLSV11:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodTLSV11) then Result := _SslMethodTLSV11 else Result := nil; end; function SslMethodTLSV12:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodTLSV12) then Result := _SslMethodTLSV12 else Result := nil; end; function SslMethodV23:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodV23) then Result := _SslMethodV23 else Result := nil; end; function SslMethodTLS:PSSL_METHOD; begin if InitSSLInterface and Assigned(_SslMethodTLS) then Result := _SslMethodTLS else Result := nil; end; function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer; begin if InitSSLInterface and Assigned(_SslCtxUsePrivateKey) then Result := _SslCtxUsePrivateKey(ctx, pkey) else Result := 0; end; function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: AnsiString; len: integer):Integer; begin if InitSSLInterface and Assigned(_SslCtxUsePrivateKeyASN1) then Result := _SslCtxUsePrivateKeyASN1(pk, ctx, Sslptr(d), len) else Result := 0; end; //function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer; function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; begin if InitSSLInterface and Assigned(_SslCtxUsePrivateKeyFile) then Result := _SslCtxUsePrivateKeyFile(ctx, PAnsiChar(_file), _type) else Result := 0; end; function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer; begin if InitSSLInterface and Assigned(_SslCtxUseCertificate) then Result := _SslCtxUseCertificate(ctx, x) else Result := 0; end; function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: AnsiString):Integer; begin if InitSSLInterface and Assigned(_SslCtxUseCertificateASN1) then Result := _SslCtxUseCertificateASN1(ctx, len, SslPtr(d)) else Result := 0; end; function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; begin if InitSSLInterface and Assigned(_SslCtxUseCertificateFile) then Result := _SslCtxUseCertificateFile(ctx, PAnsiChar(_file), _type) else Result := 0; end; //function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: PChar):Integer; function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: AnsiString):Integer; begin if InitSSLInterface and Assigned(_SslCtxUseCertificateChainFile) then Result := _SslCtxUseCertificateChainFile(ctx, PAnsiChar(_file)) else Result := 0; end; function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer; begin if InitSSLInterface and Assigned(_SslCtxCheckPrivateKeyFile) then Result := _SslCtxCheckPrivateKeyFile(ctx) else Result := 0; end; procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb); begin if InitSSLInterface and Assigned(_SslCtxSetDefaultPasswdCb) then _SslCtxSetDefaultPasswdCb(ctx, cb); end; procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: SslPtr); begin if InitSSLInterface and Assigned(_SslCtxSetDefaultPasswdCbUserdata) then _SslCtxSetDefaultPasswdCbUserdata(ctx, u); end; //function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer; function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: AnsiString; const CApath: AnsiString):Integer; begin if InitSSLInterface and Assigned(_SslCtxLoadVerifyLocations) then Result := _SslCtxLoadVerifyLocations(ctx, SslPtr(CAfile), SslPtr(CApath)) else Result := 0; end; function SslCtxCtrl(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: SslPtr): integer; begin if InitSSLInterface and Assigned(_SslCtxCtrl) then Result := _SslCtxCtrl(ctx, cmd, larg, parg) else Result := 0; end; function SslNew(ctx: PSSL_CTX):PSSL; begin if InitSSLInterface and Assigned(_SslNew) then Result := _SslNew(ctx) else Result := nil; end; procedure SslFree(ssl: PSSL); begin if InitSSLInterface and Assigned(_SslFree) then _SslFree(ssl); end; function SslAccept(ssl: PSSL):Integer; begin if InitSSLInterface and Assigned(_SslAccept) then Result := _SslAccept(ssl) else Result := -1; end; function SslConnect(ssl: PSSL):Integer; begin if InitSSLInterface and Assigned(_SslConnect) then Result := _SslConnect(ssl) else Result := -1; end; function SslShutdown(ssl: PSSL):Integer; begin if InitSSLInterface and Assigned(_SslShutdown) then Result := _SslShutdown(ssl) else Result := -1; end; //function SslRead(ssl: PSSL; buf: PChar; num: Integer):Integer; function SslRead(ssl: PSSL; buf: SslPtr; num: Integer):Integer; begin if InitSSLInterface and Assigned(_SslRead) then Result := _SslRead(ssl, PAnsiChar(buf), num) else Result := -1; end; //function SslPeek(ssl: PSSL; buf: PChar; num: Integer):Integer; function SslPeek(ssl: PSSL; buf: SslPtr; num: Integer):Integer; begin if InitSSLInterface and Assigned(_SslPeek) then Result := _SslPeek(ssl, PAnsiChar(buf), num) else Result := -1; end; //function SslWrite(ssl: PSSL; const buf: PChar; num: Integer):Integer; function SslWrite(ssl: PSSL; buf: SslPtr; num: Integer):Integer; begin if InitSSLInterface and Assigned(_SslWrite) then Result := _SslWrite(ssl, PAnsiChar(buf), num) else Result := -1; end; function SslPending(ssl: PSSL):Integer; begin if InitSSLInterface and Assigned(_SslPending) then Result := _SslPending(ssl) else Result := 0; end; //function SslGetVersion(ssl: PSSL):PChar; function SslGetVersion(ssl: PSSL):AnsiString; begin if InitSSLInterface and Assigned(_SslGetVersion) then Result := _SslGetVersion(ssl) else Result := ''; end; function SslGetPeerCertificate(ssl: PSSL):PX509; begin if InitSSLInterface and Assigned(_SslGetPeerCertificate) then Result := _SslGetPeerCertificate(ssl) else Result := nil; end; //procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: SslPtr); procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction); begin if InitSSLInterface and Assigned(_SslCtxSetVerify) then _SslCtxSetVerify(ctx, mode, @arg2); end; function SSLGetCurrentCipher(s: PSSL):SslPtr; begin if InitSSLInterface and Assigned(_SSLGetCurrentCipher) then {$IFDEF CIL} {$ELSE} Result := _SSLGetCurrentCipher(s) {$ENDIF} else Result := nil; end; //function SSLCipherGetName(c: SslPtr):PChar; function SSLCipherGetName(c: SslPtr):AnsiString; begin if InitSSLInterface and Assigned(_SSLCipherGetName) then Result := _SSLCipherGetName(c) else Result := ''; end; //function SSLCipherGetBits(c: SslPtr; alg_bits: PInteger):Integer; function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer; begin if InitSSLInterface and Assigned(_SSLCipherGetBits) then Result := _SSLCipherGetBits(c, @alg_bits) else Result := 0; end; function SSLGetVerifyResult(ssl: PSSL):Integer; begin if InitSSLInterface and Assigned(_SSLGetVerifyResult) then Result := _SSLGetVerifyResult(ssl) else Result := X509_V_ERR_APPLICATION_VERIFICATION; end; function SSLCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; begin if InitSSLInterface and Assigned(_SSLCtrl) then Result := _SSLCtrl(ssl, cmd, larg, parg) else Result := X509_V_ERR_APPLICATION_VERIFICATION; end; function SslSet1Host(ssl: PSSL; hostname: PAnsiChar):Integer; begin if InitSSLInterface and Assigned(_SslSet1Host) then Result := _SslSet1Host(ssl, hostname) else Result := 0; end; procedure SslSessionFree(session: PSslPtr); begin if InitSSLInterface and Assigned(_SslSessionFree) then _SslSessionFree(session); end; function SslGet1Session(ssl: PSSL): PSslPtr; begin if InitSSLInterface and Assigned(_SslGet1Session) then Result := _SslGet1Session(ssl) else Result := nil; end; function SslSetSession(ssl: PSSL; session: PSslPtr): Integer; begin if InitSSLInterface and Assigned(_SslSetSession) then Result := _SslSetSession(ssl, session) else Result := 0; end; // libeay.dll function X509New: PX509; begin if InitSSLInterface and Assigned(_X509New) then Result := _X509New else Result := nil; end; procedure X509Free(x: PX509); begin if InitSSLInterface and Assigned(_X509Free) then _X509Free(x); end; //function SslX509NameOneline(a: PX509_NAME; buf: PChar; size: Integer):PChar; function X509NameOneline(a: PX509_NAME; var buf: AnsiString; size: Integer):AnsiString; begin if InitSSLInterface and Assigned(_X509NameOneline) then Result := _X509NameOneline(a, PAnsiChar(buf),size) else Result := ''; end; function X509GetSubjectName(a: PX509):PX509_NAME; begin if InitSSLInterface and Assigned(_X509GetSubjectName) then Result := _X509GetSubjectName(a) else Result := nil; end; function X509GetIssuerName(a: PX509):PX509_NAME; begin if InitSSLInterface and Assigned(_X509GetIssuerName) then Result := _X509GetIssuerName(a) else Result := nil; end; function X509NameHash(x: PX509_NAME):Cardinal; begin if InitSSLInterface and Assigned(_X509NameHash) then Result := _X509NameHash(x) else Result := 0; end; //function SslX509Digest(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer; function X509Digest(data: PX509; _type: PEVP_MD; md: AnsiString; var len: Integer):Integer; begin if InitSSLInterface and Assigned(_X509Digest) then Result := _X509Digest(data, _type, PAnsiChar(md), @len) else Result := 0; end; function EvpPkeyNew: EVP_PKEY; begin if InitSSLInterface and Assigned(_EvpPkeyNew) then Result := _EvpPkeyNew else Result := nil; end; procedure EvpPkeyFree(pk: EVP_PKEY); begin if InitSSLInterface and Assigned(_EvpPkeyFree) then _EvpPkeyFree(pk); end; function SSLeayversion(t: integer): Ansistring; begin if InitSSLInterface and Assigned(_SSLeayversion) then Result := PAnsiChar(_SSLeayversion(t)) else Result := ''; end; procedure ErrErrorString(e: integer; var buf: Ansistring; len: integer); begin if InitSSLInterface and Assigned(_ErrErrorString) then _ErrErrorString(e, Pointer(buf), len); buf := PAnsiChar(Buf); end; function ErrGetError: integer; begin if InitSSLInterface and Assigned(_ErrGetError) then Result := _ErrGetError else Result := SSL_ERROR_SSL; end; procedure ErrClearError; begin if InitSSLInterface and Assigned(_ErrClearError) then _ErrClearError; end; procedure ErrFreeStrings; begin if InitSSLInterface and Assigned(_ErrFreeStrings) then _ErrFreeStrings; end; procedure ErrRemoveState(pid: integer); begin if InitSSLInterface and Assigned(_ErrRemoveState) then _ErrRemoveState(pid); end; procedure OPENSSLaddallalgorithms; begin if InitSSLInterface and Assigned(_OPENSSLaddallalgorithms) then _OPENSSLaddallalgorithms; end; procedure EVPcleanup; begin if InitSSLInterface and Assigned(_EVPcleanup) then _EVPcleanup; end; procedure CRYPTOcleanupAllExData; begin if InitSSLInterface and Assigned(_CRYPTOcleanupAllExData) then _CRYPTOcleanupAllExData; end; procedure RandScreen; begin if InitSSLInterface and Assigned(_RandScreen) then _RandScreen; end; function BioNew(b: PBIO_METHOD): PBIO; begin if InitSSLInterface and Assigned(_BioNew) then Result := _BioNew(b) else Result := nil; end; procedure BioFreeAll(b: PBIO); begin if InitSSLInterface and Assigned(_BioFreeAll) then _BioFreeAll(b); end; function BioSMem: PBIO_METHOD; begin if InitSSLInterface and Assigned(_BioSMem) then Result := _BioSMem else Result := nil; end; function BioCtrlPending(b: PBIO): integer; begin if InitSSLInterface and Assigned(_BioCtrlPending) then Result := _BioCtrlPending(b) else Result := 0; end; //function BioRead(b: PBIO; Buf: PChar; Len: integer): integer; function BioRead(b: PBIO; var Buf: AnsiString; Len: integer): integer; begin if InitSSLInterface and Assigned(_BioRead) then Result := _BioRead(b, PAnsiChar(Buf), Len) else Result := -2; end; //function BioWrite(b: PBIO; Buf: PChar; Len: integer): integer; function BioWrite(b: PBIO; Buf: AnsiString; Len: integer): integer; begin if InitSSLInterface and Assigned(_BioWrite) then Result := _BioWrite(b, PAnsiChar(Buf), Len) else Result := -2; end; function X509print(b: PBIO; a: PX509): integer; begin if InitSSLInterface and Assigned(_X509print) then Result := _X509print(b, a) else Result := 0; end; function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr; begin if InitSSLInterface and Assigned(_d2iPKCS12bio) then Result := _d2iPKCS12bio(b, Pkcs12) else Result := nil; end; function PKCS12parse(p12: SslPtr; pass: Ansistring; var pkey, cert, ca: SslPtr): integer; begin if InitSSLInterface and Assigned(_PKCS12parse) then Result := _PKCS12parse(p12, SslPtr(pass), pkey, cert, ca) else Result := 0; end; procedure PKCS12free(p12: SslPtr); begin if InitSSLInterface and Assigned(_PKCS12free) then _PKCS12free(p12); end; function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; begin if InitSSLInterface and Assigned(_RsaGenerateKey) then Result := _RsaGenerateKey(bits, e, callback, cb_arg) else Result := nil; end; function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; begin if InitSSLInterface and Assigned(_EvpPkeyAssign) then Result := _EvpPkeyAssign(pkey, _type, key) else Result := 0; end; function X509SetVersion(x: PX509; version: integer): integer; begin if InitSSLInterface and Assigned(_X509SetVersion) then Result := _X509SetVersion(x, version) else Result := 0; end; function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer; begin if InitSSLInterface and Assigned(_X509SetPubkey) then Result := _X509SetPubkey(x, pkey) else Result := 0; end; function X509SetIssuerName(x: PX509; name: PX509_NAME): integer; begin if InitSSLInterface and Assigned(_X509SetIssuerName) then Result := _X509SetIssuerName(x, name) else Result := 0; end; function X509NameAddEntryByTxt(name: PX509_NAME; field: Ansistring; _type: integer; bytes: Ansistring; len, loc, _set: integer): integer; begin if InitSSLInterface and Assigned(_X509NameAddEntryByTxt) then Result := _X509NameAddEntryByTxt(name, PAnsiChar(field), _type, PAnsiChar(Bytes), len, loc, _set) else Result := 0; end; function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; begin if InitSSLInterface and Assigned(_X509Sign) then Result := _X509Sign(x, pkey, md) else Result := 0; end; function Asn1UtctimeNew: PASN1_UTCTIME; begin if InitSSLInterface and Assigned(_Asn1UtctimeNew) then Result := _Asn1UtctimeNew else Result := nil; end; procedure Asn1UtctimeFree(a: PASN1_UTCTIME); begin if InitSSLInterface and Assigned(_Asn1UtctimeFree) then _Asn1UtctimeFree(a); end; function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; begin if InitSSLInterface and Assigned(_X509GmtimeAdj) then Result := _X509GmtimeAdj(s, adj) else Result := nil; end; function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer; begin if InitSSLInterface and Assigned(_X509SetNotBefore) then Result := _X509SetNotBefore(x, tm) else Result := 0; end; function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer; begin if InitSSLInterface and Assigned(_X509SetNotAfter) then Result := _X509SetNotAfter(x, tm) else Result := 0; end; function i2dX509bio(b: PBIO; x: PX509): integer; begin if InitSSLInterface and Assigned(_i2dX509bio) then Result := _i2dX509bio(b, x) else Result := 0; end; function d2iX509bio(b: PBIO; x: PX509): PX509; {pf} begin if InitSSLInterface and Assigned(_d2iX509bio) then Result := _d2iX509bio(b, x) else Result := nil; end; function PEMReadBioX509(b:PBIO; {var x:PX509;}x:PSslPtr; callback:PFunction; cb_arg: SslPtr): PX509; {pf} begin if InitSSLInterface and Assigned(_PEMReadBioX509) then Result := _PEMReadBioX509(b,x,callback,cb_arg) else Result := nil; end; procedure SkX509PopFree(st: PSTACK; func:TSkPopFreeFunc); {pf} begin if InitSSLInterface and Assigned(_SkX509PopFree) then _SkX509PopFree(st,func); end; function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer; begin if InitSSLInterface and Assigned(_i2dPrivateKeyBio) then Result := _i2dPrivateKeyBio(b, pkey) else Result := 0; end; function EvpGetDigestByName(Name: AnsiString): PEVP_MD; begin if InitSSLInterface and Assigned(_EvpGetDigestByName) then Result := _EvpGetDigestByName(PAnsiChar(Name)) else Result := nil; end; function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer; begin if InitSSLInterface and Assigned(_Asn1IntegerSet) then Result := _Asn1IntegerSet(a, v) else Result := 0; end; function Asn1IntegerGet(a: PASN1_INTEGER): integer; {pf} begin if InitSSLInterface and Assigned(_Asn1IntegerGet) then Result := _Asn1IntegerGet(a) else Result := 0; end; function X509GetSerialNumber(x: PX509): PASN1_INTEGER; begin if InitSSLInterface and Assigned(_X509GetSerialNumber) then Result := _X509GetSerialNumber(x) else Result := nil; end; // 3DES functions procedure DESsetoddparity(Key: des_cblock); begin if InitSSLInterface and Assigned(_DESsetoddparity) then _DESsetoddparity(Key); end; function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer; begin if InitSSLInterface and Assigned(_DESsetkeychecked) then Result := _DESsetkeychecked(key, schedule) else Result := -1; end; procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); begin if InitSSLInterface and Assigned(_DESecbencrypt) then _DESecbencrypt(Input, output, ks, enc); end; procedure locking_callback(mode, ltype: integer; lfile: PChar; line: integer); cdecl; begin if (mode and 1) > 0 then TCriticalSection(Locks[ltype]).Enter else TCriticalSection(Locks[ltype]).Leave; end; procedure InitLocks; var n: integer; max: integer; begin Locks := TList.Create; max := _CRYPTOnumlocks; for n := 1 to max do Locks.Add(TCriticalSection.Create); _CRYPTOsetlockingcallback(@locking_callback); end; procedure FreeLocks; var n: integer; begin _CRYPTOsetlockingcallback(nil); for n := 0 to Locks.Count - 1 do TCriticalSection(Locks[n]).Free; Locks.Free; end; {$ENDIF} function LoadLib(const Value: String): HModule; begin {$IFDEF CIL} Result := LoadLibrary(Value); {$ELSE} Result := LoadLibrary(PChar(Value)); {$ENDIF} end; function GetProcAddr(module: HModule; const ProcName: string): SslPtr; begin {$IFDEF CIL} Result := GetProcAddress(module, ProcName); {$ELSE} Result := GetProcAddress(module, PChar(ProcName)); {$ENDIF} end; function GetLibFileName(Handle: TLibHandle): string; var n: integer; begin n := MAX_PATH + 1024; SetLength(Result, n); n := GetModuleFilename(Handle, PChar(Result), n); SetLength(Result, n); end; function InitSSLInterface: Boolean; var s: string; i: integer; begin {pf} if SSLLoaded then begin Result := TRUE; exit; end; {/pf} SSLCS.Enter; try if not IsSSLloaded then begin {$IFDEF CIL} SSLLibHandle := 1; SSLUtilHandle := 1; {$ELSE} // Note: It's important to ensure that the libraries both come from the // same directory, preferably the one of the executable. Otherwise a // version mismatch could easily occur. {$IFDEF MSWINDOWS} for i := 0 to Pred(LibCount) do begin SSLUtilHandle := LoadLib(CryptoLibNames[i]); if SSLUtilHandle <> 0 then begin s := ExtractFilePath(GetLibFileName(SSLUtilHandle)); SSLLibHandle := LoadLib(s + SSLLibNames[i]); Break; end; end; {$ELSE} SSLUtilHandle := LoadLib(DLLUtilName); SSLLibHandle := LoadLib(DLLSSLName); {$ENDIF} {$ENDIF} if (SSLLibHandle <> 0) and (SSLUtilHandle <> 0) then begin {$IFNDEF CIL} _SslGetError := GetProcAddr(SSLLibHandle, 'SSL_get_error'); _SslLibraryInit := GetProcAddr(SSLLibHandle, 'SSL_library_init'); _SslLoadErrorStrings := GetProcAddr(SSLLibHandle, 'SSL_load_error_strings'); _SslCtxSetCipherList := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_cipher_list'); _SslCtxNew := GetProcAddr(SSLLibHandle, 'SSL_CTX_new'); _SslCtxFree := GetProcAddr(SSLLibHandle, 'SSL_CTX_free'); _SslSetFd := GetProcAddr(SSLLibHandle, 'SSL_set_fd'); _SslMethodV2 := GetProcAddr(SSLLibHandle, 'SSLv2_method'); _SslMethodV3 := GetProcAddr(SSLLibHandle, 'SSLv3_method'); _SslMethodTLSV1 := GetProcAddr(SSLLibHandle, 'TLSv1_method'); _SslMethodTLSV11 := GetProcAddr(SSLLibHandle, 'TLSv1_1_method'); _SslMethodTLSV12 := GetProcAddr(SSLLibHandle, 'TLSv1_2_method'); _SslMethodV23 := GetProcAddr(SSLLibHandle, 'SSLv23_method'); _SslMethodTLS := GetProcAddr(SSLLibHandle, 'TLS_method'); _SslCtxUsePrivateKey := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_PrivateKey'); _SslCtxUsePrivateKeyASN1 := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_PrivateKey_ASN1'); //use SSL_CTX_use_RSAPrivateKey_file instead SSL_CTX_use_PrivateKey_file, //because SSL_CTX_use_PrivateKey_file not support DER format. :-O _SslCtxUsePrivateKeyFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_RSAPrivateKey_file'); _SslCtxUseCertificate := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate'); _SslCtxUseCertificateASN1 := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_ASN1'); _SslCtxUseCertificateFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_file'); _SslCtxUseCertificateChainFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_chain_file'); _SslCtxCheckPrivateKeyFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_check_private_key'); _SslCtxSetDefaultPasswdCb := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_default_passwd_cb'); _SslCtxSetDefaultPasswdCbUserdata := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_default_passwd_cb_userdata'); _SslCtxLoadVerifyLocations := GetProcAddr(SSLLibHandle, 'SSL_CTX_load_verify_locations'); _SslCtxCtrl := GetProcAddr(SSLLibHandle, 'SSL_CTX_ctrl'); _SslNew := GetProcAddr(SSLLibHandle, 'SSL_new'); _SslFree := GetProcAddr(SSLLibHandle, 'SSL_free'); _SslAccept := GetProcAddr(SSLLibHandle, 'SSL_accept'); _SslConnect := GetProcAddr(SSLLibHandle, 'SSL_connect'); _SslShutdown := GetProcAddr(SSLLibHandle, 'SSL_shutdown'); _SslRead := GetProcAddr(SSLLibHandle, 'SSL_read'); _SslPeek := GetProcAddr(SSLLibHandle, 'SSL_peek'); _SslWrite := GetProcAddr(SSLLibHandle, 'SSL_write'); _SslPending := GetProcAddr(SSLLibHandle, 'SSL_pending'); _SslGetPeerCertificate := GetProcAddr(SSLLibHandle, 'SSL_get_peer_certificate'); _SslGetVersion := GetProcAddr(SSLLibHandle, 'SSL_get_version'); _SslCtxSetVerify := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_verify'); _SslGetCurrentCipher := GetProcAddr(SSLLibHandle, 'SSL_get_current_cipher'); _SslCipherGetName := GetProcAddr(SSLLibHandle, 'SSL_CIPHER_get_name'); _SslCipherGetBits := GetProcAddr(SSLLibHandle, 'SSL_CIPHER_get_bits'); _SslGetVerifyResult := GetProcAddr(SSLLibHandle, 'SSL_get_verify_result'); _SslCtrl := GetProcAddr(SSLLibHandle, 'SSL_ctrl'); _SslSet1Host := GetProcAddr(SSLLibHandle, 'SSL_set1_host'); _SslSessionFree := GetProcAddr(SSLLibHandle, 'SSL_SESSION_free'); _SslGet1Session := GetProcAddr(SSLLibHandle, 'SSL_get1_session'); _SslSetSession := GetProcAddr(SSLLibHandle, 'SSL_set_session'); _X509New := GetProcAddr(SSLUtilHandle, 'X509_new'); _X509Free := GetProcAddr(SSLUtilHandle, 'X509_free'); _X509NameOneline := GetProcAddr(SSLUtilHandle, 'X509_NAME_oneline'); _X509GetSubjectName := GetProcAddr(SSLUtilHandle, 'X509_get_subject_name'); _X509GetIssuerName := GetProcAddr(SSLUtilHandle, 'X509_get_issuer_name'); _X509NameHash := GetProcAddr(SSLUtilHandle, 'X509_NAME_hash'); _X509Digest := GetProcAddr(SSLUtilHandle, 'X509_digest'); _X509print := GetProcAddr(SSLUtilHandle, 'X509_print'); _X509SetVersion := GetProcAddr(SSLUtilHandle, 'X509_set_version'); _X509SetPubkey := GetProcAddr(SSLUtilHandle, 'X509_set_pubkey'); _X509SetIssuerName := GetProcAddr(SSLUtilHandle, 'X509_set_issuer_name'); _X509NameAddEntryByTxt := GetProcAddr(SSLUtilHandle, 'X509_NAME_add_entry_by_txt'); _X509Sign := GetProcAddr(SSLUtilHandle, 'X509_sign'); _X509GmtimeAdj := GetProcAddr(SSLUtilHandle, 'X509_gmtime_adj'); _X509SetNotBefore := GetProcAddr(SSLUtilHandle, 'X509_set_notBefore'); _X509SetNotAfter := GetProcAddr(SSLUtilHandle, 'X509_set_notAfter'); _X509GetSerialNumber := GetProcAddr(SSLUtilHandle, 'X509_get_serialNumber'); _EvpPkeyNew := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_new'); _EvpPkeyFree := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_free'); _EvpPkeyAssign := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_assign'); _EVPCleanup := GetProcAddr(SSLUtilHandle, 'EVP_cleanup'); _EvpGetDigestByName := GetProcAddr(SSLUtilHandle, 'EVP_get_digestbyname'); _SSLeayversion := GetProcAddr(SSLUtilHandle, 'SSLeay_version'); _ErrErrorString := GetProcAddr(SSLUtilHandle, 'ERR_error_string_n'); _ErrGetError := GetProcAddr(SSLUtilHandle, 'ERR_get_error'); _ErrClearError := GetProcAddr(SSLUtilHandle, 'ERR_clear_error'); _ErrFreeStrings := GetProcAddr(SSLUtilHandle, 'ERR_free_strings'); _ErrRemoveState := GetProcAddr(SSLUtilHandle, 'ERR_remove_state'); _OPENSSLaddallalgorithms := GetProcAddr(SSLUtilHandle, 'OPENSSL_add_all_algorithms_noconf'); _CRYPTOcleanupAllExData := GetProcAddr(SSLUtilHandle, 'CRYPTO_cleanup_all_ex_data'); _RandScreen := GetProcAddr(SSLUtilHandle, 'RAND_screen'); _BioNew := GetProcAddr(SSLUtilHandle, 'BIO_new'); _BioFreeAll := GetProcAddr(SSLUtilHandle, 'BIO_free_all'); _BioSMem := GetProcAddr(SSLUtilHandle, 'BIO_s_mem'); _BioCtrlPending := GetProcAddr(SSLUtilHandle, 'BIO_ctrl_pending'); _BioRead := GetProcAddr(SSLUtilHandle, 'BIO_read'); _BioWrite := GetProcAddr(SSLUtilHandle, 'BIO_write'); _d2iPKCS12bio := GetProcAddr(SSLUtilHandle, 'd2i_PKCS12_bio'); _PKCS12parse := GetProcAddr(SSLUtilHandle, 'PKCS12_parse'); _PKCS12free := GetProcAddr(SSLUtilHandle, 'PKCS12_free'); _RsaGenerateKey := GetProcAddr(SSLUtilHandle, 'RSA_generate_key'); _Asn1UtctimeNew := GetProcAddr(SSLUtilHandle, 'ASN1_UTCTIME_new'); _Asn1UtctimeFree := GetProcAddr(SSLUtilHandle, 'ASN1_UTCTIME_free'); _Asn1IntegerSet := GetProcAddr(SSLUtilHandle, 'ASN1_INTEGER_set'); _Asn1IntegerGet := GetProcAddr(SSLUtilHandle, 'ASN1_INTEGER_get'); {pf} _i2dX509bio := GetProcAddr(SSLUtilHandle, 'i2d_X509_bio'); _d2iX509bio := GetProcAddr(SSLUtilHandle, 'd2i_X509_bio'); {pf} _PEMReadBioX509 := GetProcAddr(SSLUtilHandle, 'PEM_read_bio_X509'); {pf} _SkX509PopFree := GetProcAddr(SSLUtilHandle, 'SK_X509_POP_FREE'); {pf} _i2dPrivateKeyBio := GetProcAddr(SSLUtilHandle, 'i2d_PrivateKey_bio'); // 3DES functions _DESsetoddparity := GetProcAddr(SSLUtilHandle, 'DES_set_odd_parity'); _DESsetkeychecked := GetProcAddr(SSLUtilHandle, 'DES_set_key_checked'); _DESecbencrypt := GetProcAddr(SSLUtilHandle, 'DES_ecb_encrypt'); // _CRYPTOnumlocks := GetProcAddr(SSLUtilHandle, 'CRYPTO_num_locks'); _CRYPTOsetlockingcallback := GetProcAddr(SSLUtilHandle, 'CRYPTO_set_locking_callback'); {$ENDIF} {$IFDEF CIL} SslLibraryInit; SslLoadErrorStrings; OPENSSLaddallalgorithms; RandScreen; {$ELSE} SSLLibFile := GetLibFileName(SSLLibHandle); SSLUtilFile := GetLibFileName(SSLUtilHandle); //init library if assigned(_SslLibraryInit) then _SslLibraryInit; if assigned(_SslLoadErrorStrings) then _SslLoadErrorStrings; if assigned(_OPENSSLaddallalgorithms) then _OPENSSLaddallalgorithms; if assigned(_RandScreen) then _RandScreen; if assigned(_CRYPTOnumlocks) and assigned(_CRYPTOsetlockingcallback) then InitLocks; {$ENDIF} SSLloaded := True; {$IFDEF OS2} Result := InitEMXHandles; {$ELSE OS2} Result := True; {$ENDIF OS2} end else begin //load failed! if SSLLibHandle <> 0 then begin {$IFNDEF CIL} FreeLibrary(SSLLibHandle); {$ENDIF} SSLLibHandle := 0; end; if SSLUtilHandle <> 0 then begin {$IFNDEF CIL} FreeLibrary(SSLUtilHandle); {$ENDIF} SSLLibHandle := 0; end; Result := False; end; end else //loaded before... Result := true; finally SSLCS.Leave; end; end; function DestroySSLInterface: Boolean; begin SSLCS.Enter; try if IsSSLLoaded then begin //deinit library {$IFNDEF CIL} if assigned(_CRYPTOnumlocks) and assigned(_CRYPTOsetlockingcallback) then FreeLocks; {$ENDIF} EVPCleanup; CRYPTOcleanupAllExData; ErrRemoveState(0); end; SSLloaded := false; if SSLLibHandle <> 0 then begin {$IFNDEF CIL} FreeLibrary(SSLLibHandle); {$ENDIF} SSLLibHandle := 0; end; if SSLUtilHandle <> 0 then begin {$IFNDEF CIL} FreeLibrary(SSLUtilHandle); {$ENDIF} SSLLibHandle := 0; end; {$IFNDEF CIL} _SslGetError := nil; _SslLibraryInit := nil; _SslLoadErrorStrings := nil; _SslCtxSetCipherList := nil; _SslCtxNew := nil; _SslCtxFree := nil; _SslSetFd := nil; _SslMethodV2 := nil; _SslMethodV3 := nil; _SslMethodTLSV1 := nil; _SslMethodTLSV11 := nil; _SslMethodTLSV12 := nil; _SslMethodV23 := nil; _SslMethodTLS := nil; _SslCtxUsePrivateKey := nil; _SslCtxUsePrivateKeyASN1 := nil; _SslCtxUsePrivateKeyFile := nil; _SslCtxUseCertificate := nil; _SslCtxUseCertificateASN1 := nil; _SslCtxUseCertificateFile := nil; _SslCtxUseCertificateChainFile := nil; _SslCtxCheckPrivateKeyFile := nil; _SslCtxSetDefaultPasswdCb := nil; _SslCtxSetDefaultPasswdCbUserdata := nil; _SslCtxLoadVerifyLocations := nil; _SslCtxCtrl := nil; _SslNew := nil; _SslFree := nil; _SslAccept := nil; _SslConnect := nil; _SslShutdown := nil; _SslRead := nil; _SslPeek := nil; _SslWrite := nil; _SslPending := nil; _SslGetPeerCertificate := nil; _SslGetVersion := nil; _SslCtxSetVerify := nil; _SslGetCurrentCipher := nil; _SslCipherGetName := nil; _SslCipherGetBits := nil; _SslGetVerifyResult := nil; _SslCtrl := nil; _SslSet1Host := nil; _SslSessionFree := nil; _SslGet1Session := nil; _SslSetSession := nil; _X509New := nil; _X509Free := nil; _X509NameOneline := nil; _X509GetSubjectName := nil; _X509GetIssuerName := nil; _X509NameHash := nil; _X509Digest := nil; _X509print := nil; _X509SetVersion := nil; _X509SetPubkey := nil; _X509SetIssuerName := nil; _X509NameAddEntryByTxt := nil; _X509Sign := nil; _X509GmtimeAdj := nil; _X509SetNotBefore := nil; _X509SetNotAfter := nil; _X509GetSerialNumber := nil; _EvpPkeyNew := nil; _EvpPkeyFree := nil; _EvpPkeyAssign := nil; _EVPCleanup := nil; _EvpGetDigestByName := nil; _SSLeayversion := nil; _ErrErrorString := nil; _ErrGetError := nil; _ErrClearError := nil; _ErrFreeStrings := nil; _ErrRemoveState := nil; _OPENSSLaddallalgorithms := nil; _CRYPTOcleanupAllExData := nil; _RandScreen := nil; _BioNew := nil; _BioFreeAll := nil; _BioSMem := nil; _BioCtrlPending := nil; _BioRead := nil; _BioWrite := nil; _d2iPKCS12bio := nil; _PKCS12parse := nil; _PKCS12free := nil; _RsaGenerateKey := nil; _Asn1UtctimeNew := nil; _Asn1UtctimeFree := nil; _Asn1IntegerSet := nil; _Asn1IntegerGet := nil; {pf} _SkX509PopFree := nil; {pf} _i2dX509bio := nil; _i2dPrivateKeyBio := nil; // 3DES functions _DESsetoddparity := nil; _DESsetkeychecked := nil; _DESecbencrypt := nil; // _CRYPTOnumlocks := nil; _CRYPTOsetlockingcallback := nil; {$ENDIF} finally SSLCS.Leave; end; Result := True; end; function IsSSLloaded: Boolean; begin Result := SSLLoaded; end; initialization begin SSLCS:= TCriticalSection.Create; end; finalization begin {$IFNDEF CIL} DestroySSLInterface; {$ENDIF} SSLCS.Free; end; end. �������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_openssl_ver.pas����������������������������������������0000755�0001750�0000144�00000012142�14743153644�023276� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 003.004.001 | |==============================================================================| | Content: SSL support by OpenSSL | |==============================================================================| | Copyright (c)1999-2005, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2002-2005. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | | Alexander Koblov | | Ales Katona (Try to load all library versions until you find or run out) | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} unit ssl_openssl_ver; {$mode delphi} interface implementation uses blcksock, ssl_openssl_lib; const LibSSLName = 'libssl'; LibUtilName = 'libcrypto'; { ADD NEW ONES WHEN THEY APPEAR! Always make .so/dylib last (Darwin won't load unversioned), then versions, in descending order! Add "." .before the version} {$IFDEF DARWIN} LibVersions: array[1..10] of String = ('.48', '.47', '.46', '.45', '.44', '.43', '.42', '.41', '.39', '.35' ); {Always make .so/dylib first, then versions, in descending order! Add "." .before the version, first is always just "" } {$ELSE} LibVersions: array[1..10] of String = ('', '.3', '.111', '.1.1.1', '.11', '.1.1', '.1.1.0', '.10', '.1.0.2', '.1.0.1' ); {$ENDIF} function GetLibraryName(const Value: String; Index: Integer): String; begin {$IFDEF DARWIN} Result := Value + LibVersions[Index] + '.dylib'; {$ELSE} Result := Value + '.so' + LibVersions[Index]; {$ENDIF} end; var Index: Integer; begin if not IsSSLloaded then begin for Index := Low(LibVersions) to High(LibVersions) do begin DLLSSLName := GetLibraryName(LibSSLName, Index); DLLUtilName := GetLibraryName(LibUtilName, Index); if InitSSLInterface then Break; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_winssl_lib.inc�����������������������������������������0000644�0001750�0000144�00000000505�14743153644�023067� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exports SSL_library_init, SSL_set_fd, SSL_CTX_new, SSL_CTX_free, SSL_new, SSL_free, SSL_connect, SSL_shutdown, SSL_read, SSL_write, SSL_pending, SSLv23_method, SSLv2_method, SSLv3_method, TLSv1_method, TLSv1_1_method, TLSv1_2_method, SSL_CTX_set_verify, SSL_get_error;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/ssl_winssl_lib.pas�����������������������������������������0000644�0001750�0000144�00000064156�14743153644�023115� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ SChannel to OpenSSL wrapper Copyright (c) 2008 Boris Krasnovskiy Copyright (c) 2013-2015 Alexander Koblov (pascal port) 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. 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, see <http://www.gnu.org/licenses/>. } unit ssl_winssl_lib; {$mode delphi} interface uses Windows, SynSock, JwaSspi, CTypes; type PSSL_CTX = ^SSL_CTX; SSL_CTX = record dwProtocol: DWORD; bVerify: BOOL; end; PSSL_METHOD = ^SSL_METHOD; SSL_METHOD = record dummy: DWORD; end; PSSL = ^SSL; SSL = record s: TSocket; ctx: PSSL_CTX; hContext: CtxtHandle; hCreds: CredHandle; pbRecDataBuf: PByte; cbRecDataBuf: LONG; sbRecDataBuf: LONG; pbIoBuffer: PByte; cbIoBuffer: LONG; sbIoBuffer: LONG; exIoBuffer: BOOL; rmshtdn: BOOL; end; function SSL_library_init(): cint; cdecl; function SSL_set_fd(ssl: PSSL; fd: cint): cint; cdecl; function SSL_CTX_new(method: PSSL_METHOD): PSSL_CTX; cdecl; procedure SSL_CTX_free(ctx: PSSL_CTX); cdecl; function SSL_new(ctx: PSSL_CTX): PSSL; cdecl; procedure SSL_free(ssl: PSSL); cdecl; function SSL_connect(ssl: PSSL): cint; cdecl; function SSL_shutdown(ssl: PSSL): cint; cdecl; function SSL_read(ssl: PSSL; buf: PByte; num: cint): cint; cdecl; function SSL_write(ssl: PSSL; const buf: PByte; num: cint): cint; cdecl; function SSL_pending(ssl: PSSL): cint; cdecl; function SSLv23_method(): PSSL_METHOD; cdecl; function SSLv2_method(): PSSL_METHOD; cdecl; function SSLv3_method(): PSSL_METHOD; cdecl; function TLSv1_method(): PSSL_METHOD; cdecl; function TLSv1_1_method(): PSSL_METHOD; cdecl; function TLSv1_2_method(): PSSL_METHOD; cdecl; procedure SSL_CTX_set_verify(ctx: PSSL_CTX; mode: cint; func: Pointer); cdecl; function SSL_get_error (ssl: PSSL; ret: cint): cint; cdecl; implementation uses JwaWinError, ssl_openssl_lib, blcksock, ssl_openssl; const SCHANNEL_CRED_VERSION = $00000004; const SCH_CRED_MANUAL_CRED_VALIDATION = $00000008; SCH_CRED_NO_DEFAULT_CREDS = $00000010; const SCHANNEL_SHUTDOWN = 1; // gracefully close down a connection const SP_PROT_SSL2_SERVER = $00000004; SP_PROT_SSL2_CLIENT = $00000008; SP_PROT_SSL2 = (SP_PROT_SSL2_SERVER or SP_PROT_SSL2_CLIENT); SP_PROT_SSL3_SERVER = $00000010; SP_PROT_SSL3_CLIENT = $00000020; SP_PROT_SSL3 = (SP_PROT_SSL3_SERVER or SP_PROT_SSL3_CLIENT); SP_PROT_TLS1_SERVER = $00000040; SP_PROT_TLS1_CLIENT = $00000080; SP_PROT_TLS1 = (SP_PROT_TLS1_SERVER or SP_PROT_TLS1_CLIENT); SP_PROT_TLS1_1_SERVER = $00000100; SP_PROT_TLS1_1_CLIENT = $00000200; SP_PROT_TLS1_1 = (SP_PROT_TLS1_1_SERVER or SP_PROT_TLS1_1_CLIENT); SP_PROT_TLS1_2_SERVER = $00000400; SP_PROT_TLS1_2_CLIENT = $00000800; SP_PROT_TLS1_2 = (SP_PROT_TLS1_2_SERVER or SP_PROT_TLS1_2_CLIENT); const UNISP_NAME_A = AnsiString('Microsoft Unified Security Protocol Provider'); UNISP_NAME_W = WideString('Microsoft Unified Security Protocol Provider'); type ALG_ID = type cuint; HCERTSTORE = type HANDLE; PCCERT_CONTEXT = type Pointer; type SCHANNEL_CRED = record dwVersion: DWORD; cCreds: DWORD; paCred: PCCERT_CONTEXT; hRootStore: HCERTSTORE; cMappers: DWORD; aphMappers: Pointer; cSupportedAlgs: DWORD; palgSupportedAlgs: ^ALG_ID; grbitEnabledProtocols: DWORD; dwMinimumCipherStrength: DWORD; dwMaximumCipherStrength: DWORD; dwSessionLifespan: DWORD; dwFlags: DWORD; dwCredFormat: DWORD; end; var g_hSecurity: HMODULE; g_pSSPI: PSecurityFunctionTableA; function SSL_library_init(): cint; cdecl; var pInitSecurityInterface: INIT_SECURITY_INTERFACE_A; begin if (g_hSecurity <> 0) then Exit(1); g_hSecurity:= LoadLibraryA('schannel.dll'); if (g_hSecurity = 0) then Exit(0); pInitSecurityInterface := INIT_SECURITY_INTERFACE_A(GetProcAddress(g_hSecurity, SECURITY_ENTRYPOINT_ANSIA)); if (pInitSecurityInterface <> nil) then g_pSSPI := pInitSecurityInterface(); if (g_pSSPI = nil) then begin FreeLibrary(g_hSecurity); g_hSecurity := 0; Exit(0); end; Result := 1; end; function SSL_set_fd(ssl: PSSL; fd: cint): cint; cdecl; begin if (ssl = nil) then Exit(0); ssl^.s := TSocket(fd); Result := 1; end; function SSL_CTX_new(method: PSSL_METHOD): PSSL_CTX; cdecl; begin if (g_hSecurity = 0) then Exit(nil); Result := GetMem(SizeOf(SSL_CTX)); Result^.dwProtocol := DWORD(method); end; procedure SSL_CTX_free(ctx: PSSL_CTX); cdecl; begin FreeMem(ctx); end; function SSL_new(ctx: PSSL_CTX): PSSL; cdecl; var SchannelCred: SCHANNEL_CRED; tsExpiry: TimeStamp; scRet: SECURITY_STATUS; begin if (ctx = nil) then Exit(nil); Result := GetMem(SizeOf(SSL)); ZeroMemory(Result, SizeOf(SSL)); Result^.ctx := ctx; ZeroMemory(@SchannelCred, SizeOf(SchannelCred)); SchannelCred.dwVersion := SCHANNEL_CRED_VERSION; SchannelCred.grbitEnabledProtocols := ctx^.dwProtocol; SchannelCred.dwFlags := SchannelCred.dwFlags or SCH_CRED_NO_DEFAULT_CREDS; if (not ctx^.bVerify) then SchannelCred.dwFlags := SchannelCred.dwFlags or SCH_CRED_MANUAL_CRED_VALIDATION; // Create an SSPI credential. scRet := g_pSSPI^.AcquireCredentialsHandleA( nil, // Name of principal UNISP_NAME_A, // Name of package SECPKG_CRED_OUTBOUND, // Flags indicating use nil, // Pointer to logon ID @SchannelCred, // Package specific data nil, // Pointer to GetKey() func nil, // Value to pass to GetKey() @Result^.hCreds, // (out) Cred Handle @tsExpiry); // (out) Lifetime (optional) if (scRet <> SEC_E_OK) then begin FreeMem(Result); Result := nil; end; end; procedure SSL_free(ssl: PSSL); cdecl; begin if (ssl = nil) then Exit; g_pSSPI^.FreeCredentialHandle(@ssl^.hCreds); g_pSSPI^.DeleteSecurityContext(@ssl^.hContext); FreeMem(ssl^.pbRecDataBuf); FreeMem(ssl^.pbIoBuffer); FreeMem(ssl); end; function ClientHandshakeLoop(ssl: PSSL; fDoInitialRead: BOOL): SECURITY_STATUS; var InBuffer: SecBufferDesc; InBuffers: array [0..1] of SecBuffer; OutBuffer: SecBufferDesc; OutBuffers: array [0..0] of SecBuffer; dwSSPIFlags: DWORD; dwSSPIOutFlags: DWORD = 0; tsExpiry: TimeStamp; scRet: SECURITY_STATUS; cbData: LONG; fDoRead: BOOL; tv: TTimeVal = (tv_sec: 10; tv_usec: 0); fd: TFDSet; begin dwSSPIFlags := ISC_REQ_SEQUENCE_DETECT or ISC_REQ_REPLAY_DETECT or ISC_REQ_CONFIDENTIALITY or ISC_RET_EXTENDED_ERROR or ISC_REQ_ALLOCATE_MEMORY or ISC_REQ_STREAM; ssl^.cbIoBuffer := 0; fDoRead := fDoInitialRead; scRet := SEC_I_CONTINUE_NEEDED; // Loop until the handshake is finished or an error occurs. while (scRet = SEC_I_CONTINUE_NEEDED) or (scRet = SEC_E_INCOMPLETE_MESSAGE) or (scRet = SEC_I_INCOMPLETE_CREDENTIALS) do begin // Read server data if (0 = ssl^.cbIoBuffer) or (scRet = SEC_E_INCOMPLETE_MESSAGE) then begin if (fDoRead) then begin // If buffer not large enough reallocate buffer if (ssl^.sbIoBuffer <= ssl^.cbIoBuffer) then begin ssl^.sbIoBuffer += 2048; ssl^.pbIoBuffer := PUCHAR(ReAllocMem(ssl^.pbIoBuffer, ssl^.sbIoBuffer)); end; FD_ZERO(fd); FD_SET(ssl^.s, fd); if (select(1, @fd, nil, nil, @tv) <> 1) then begin scRet := SEC_E_INTERNAL_ERROR; break; end; cbData := recv(ssl^.s, ssl^.pbIoBuffer + ssl^.cbIoBuffer, ssl^.sbIoBuffer - ssl^.cbIoBuffer, 0); if (cbData = SOCKET_ERROR) then begin scRet := SEC_E_INTERNAL_ERROR; break; end else if (cbData = 0) then begin scRet := SEC_E_INTERNAL_ERROR; break; end; ssl^.cbIoBuffer += cbData; end else begin fDoRead := TRUE; end; end; // Set up the input buffers. Buffer 0 is used to pass in data // received from the server. Schannel will consume some or all // of this. Leftover data (if any) will be placed in buffer 1 and // given a buffer type of SECBUFFER_EXTRA. InBuffers[0].pvBuffer := ssl^.pbIoBuffer; InBuffers[0].cbBuffer := ssl^.cbIoBuffer; InBuffers[0].BufferType := SECBUFFER_TOKEN; InBuffers[1].pvBuffer := nil; InBuffers[1].cbBuffer := 0; InBuffers[1].BufferType := SECBUFFER_EMPTY; InBuffer.cBuffers := 2; InBuffer.pBuffers := InBuffers; InBuffer.ulVersion := SECBUFFER_VERSION; // Set up the output buffers. These are initialized to NULL // so as to make it less likely we'll attempt to free random // garbage later. OutBuffers[0].pvBuffer := nil; OutBuffers[0].BufferType:= SECBUFFER_TOKEN; OutBuffers[0].cbBuffer := 0; OutBuffer.cBuffers := 1; OutBuffer.pBuffers := OutBuffers; OutBuffer.ulVersion := SECBUFFER_VERSION; scRet := g_pSSPI^.InitializeSecurityContextA(@ssl^.hCreds, @ssl^.hContext, nil, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, @InBuffer, 0, nil, @OutBuffer, dwSSPIOutFlags, @tsExpiry); // If success (or if the error was one of the special extended ones), // send the contents of the output buffer to the server. if (scRet = SEC_E_OK) or (scRet = SEC_I_CONTINUE_NEEDED) or (FAILED(scRet) and (dwSSPIOutFlags and ISC_RET_EXTENDED_ERROR <> 0)) then begin if (OutBuffers[0].cbBuffer <> 0) and (OutBuffers[0].pvBuffer <> nil) then begin cbData := send(ssl^.s, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0); if (cbData = SOCKET_ERROR) or (cbData = 0) then begin g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer); g_pSSPI^.DeleteSecurityContext(@ssl^.hContext); Exit(SEC_E_INTERNAL_ERROR); end; // Free output buffer. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer); OutBuffers[0].pvBuffer := nil; end; end; // we need to read more data from the server and try again. if (scRet = SEC_E_INCOMPLETE_MESSAGE) then continue; // handshake completed successfully. if (scRet = SEC_E_OK) then begin // Store remaining data for further use if (InBuffers[1].BufferType = SECBUFFER_EXTRA) then begin ssl^.exIoBuffer := True; MoveMemory(ssl^.pbIoBuffer, ssl^.pbIoBuffer + (ssl^.cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer); ssl^.cbIoBuffer := InBuffers[1].cbBuffer; end else ssl^.cbIoBuffer := 0; break; end; // Check for fatal error. if (FAILED(scRet)) then break; // server just requested client authentication. if (scRet = SEC_I_INCOMPLETE_CREDENTIALS) then begin // Server has requested client authentication and // GetNewClientCredentials(ssl); // Go around again. fDoRead := FALSE; scRet := SEC_I_CONTINUE_NEEDED; continue; end; // Copy any leftover data from the buffer, and go around again. if ( InBuffers[1].BufferType = SECBUFFER_EXTRA ) then begin ssl^.exIoBuffer := True; MoveMemory(ssl^.pbIoBuffer, ssl^.pbIoBuffer + (ssl^.cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer); ssl^.cbIoBuffer := InBuffers[1].cbBuffer; end else ssl^.cbIoBuffer := 0; end; // Delete the security context in the case of a fatal error. if (FAILED(scRet)) then begin g_pSSPI^.DeleteSecurityContext(@ssl^.hContext); end; if (ssl^.cbIoBuffer = 0) then begin FreeMem(ssl^.pbIoBuffer); ssl^.pbIoBuffer := nil; ssl^.sbIoBuffer := 0; end; Result := scRet; end; function SSL_connect(ssl: PSSL): cint; cdecl; var OutBuffer: SecBufferDesc; OutBuffers: array[0..0] of SecBuffer; dwSSPIFlags: DWORD; dwSSPIOutFlags: DWORD = 0; tsExpiry: TimeStamp; scRet: SECURITY_STATUS; cbData: LONG; sock: TVarSin; begin if (ssl = nil) then Exit(0); dwSSPIFlags := ISC_REQ_SEQUENCE_DETECT or ISC_REQ_REPLAY_DETECT or ISC_REQ_CONFIDENTIALITY or ISC_RET_EXTENDED_ERROR or ISC_REQ_ALLOCATE_MEMORY or ISC_REQ_STREAM; // Initiate a ClientHello message and generate a token. OutBuffers[0].pvBuffer := nil; OutBuffers[0].BufferType := SECBUFFER_TOKEN; OutBuffers[0].cbBuffer := 0; OutBuffer.cBuffers := 1; OutBuffer.pBuffers := OutBuffers; OutBuffer.ulVersion := SECBUFFER_VERSION; GetPeerName(ssl^.s, sock); scRet := g_pSSPI^.InitializeSecurityContextA( @ssl^.hCreds, nil, inet_ntoa(sock.sin_addr), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, nil, 0, @ssl^.hContext, @OutBuffer, dwSSPIOutFlags, @tsExpiry); if (scRet <> SEC_I_CONTINUE_NEEDED) then begin Exit(0); end; // Send response to server if there is one. if (OutBuffers[0].cbBuffer <> 0) and (OutBuffers[0].pvBuffer <> nil) then begin cbData := send(ssl^.s, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0); if (cbData = SOCKET_ERROR) or (cbData = 0) then begin g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer); g_pSSPI^.DeleteSecurityContext(@ssl^.hContext); Exit(0); end; // Free output buffer. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer); OutBuffers[0].pvBuffer := nil; end; Result := cint(ClientHandshakeLoop(ssl, TRUE) = SEC_E_OK); end; function SSL_shutdown(ssl: PSSL): cint; cdecl; var dwType: DWORD; OutBuffer: SecBufferDesc; OutBuffers: array[0..0] of SecBuffer; dwSSPIFlags: DWORD; dwSSPIOutFlags: DWORD = 0; tsExpiry: TimeStamp; Status: DWORD; begin if (ssl = nil) then Exit(SOCKET_ERROR); dwType := SCHANNEL_SHUTDOWN; OutBuffers[0].pvBuffer := @dwType; OutBuffers[0].BufferType := SECBUFFER_TOKEN; OutBuffers[0].cbBuffer := SizeOf(dwType); OutBuffer.cBuffers := 1; OutBuffer.pBuffers := OutBuffers; OutBuffer.ulVersion := SECBUFFER_VERSION; Status := g_pSSPI^.ApplyControlToken(@ssl^.hContext, @OutBuffer); if (FAILED(Status)) then Exit(cint(ssl^.rmshtdn)); // // Build an SSL close notify message. // dwSSPIFlags := ISC_REQ_SEQUENCE_DETECT or ISC_REQ_REPLAY_DETECT or ISC_REQ_CONFIDENTIALITY or ISC_RET_EXTENDED_ERROR or ISC_REQ_ALLOCATE_MEMORY or ISC_REQ_STREAM; OutBuffers[0].pvBuffer := nil; OutBuffers[0].BufferType := SECBUFFER_TOKEN; OutBuffers[0].cbBuffer := 0; OutBuffer.cBuffers := 1; OutBuffer.pBuffers := OutBuffers; OutBuffer.ulVersion := SECBUFFER_VERSION; Status := g_pSSPI^.InitializeSecurityContextA( @ssl^.hCreds, @ssl^.hContext, nil, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, nil, 0, @ssl^.hContext, @OutBuffer, dwSSPIOutFlags, @tsExpiry); if (FAILED(Status)) then Exit(cint(ssl^.rmshtdn)); // Send the close notify message to the server. if (OutBuffers[0].pvBuffer <> nil) and (OutBuffers[0].cbBuffer <> 0) then begin send(ssl^.s, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0); g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer); end; // Free the security context. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext); Result := cint(ssl^.rmshtdn); end; function SSL_read(ssl: PSSL; buf: PByte; num: cint): cint; cdecl; var scRet: SECURITY_STATUS; cbData: LONG; i: cint; Message: SecBufferDesc; Buffers: array [0..3] of SecBuffer; pDataBuffer: PSecBuffer; pExtraBuffer: PSecBuffer; bytes, rbytes: LONG; fQOP: ULONG = 0; begin if (ssl = nil) then Exit(SOCKET_ERROR); if (num = 0) then Exit(0); if (ssl^.cbRecDataBuf <> 0) then begin bytes := Min(num, ssl^.cbRecDataBuf); CopyMemory(buf, ssl^.pbRecDataBuf, bytes); rbytes := ssl^.cbRecDataBuf - bytes; MoveMemory(ssl^.pbRecDataBuf, ssl^.pbRecDataBuf + bytes, rbytes); ssl^.cbRecDataBuf := rbytes; Exit(bytes); end; scRet := SEC_E_OK; while (True) do begin if (0 = ssl^.cbIoBuffer) or (scRet = SEC_E_INCOMPLETE_MESSAGE) then begin if (ssl^.sbIoBuffer <= ssl^.cbIoBuffer) then begin ssl^.sbIoBuffer += 2048; ssl^.pbIoBuffer := PUCHAR(ReAllocMem(ssl^.pbIoBuffer, ssl^.sbIoBuffer)); end; cbData := recv(ssl^.s, ssl^.pbIoBuffer + ssl^.cbIoBuffer, ssl^.sbIoBuffer - ssl^.cbIoBuffer, 0); if (cbData = SOCKET_ERROR) then begin Exit(SOCKET_ERROR); end else if (cbData = 0) then begin // Server disconnected. if (ssl^.cbIoBuffer <> 0) then begin scRet := SEC_E_INTERNAL_ERROR; Exit(SOCKET_ERROR); end else Exit(0); end else ssl^.cbIoBuffer += cbData; end; // Attempt to decrypt the received data. Buffers[0].pvBuffer := ssl^.pbIoBuffer; Buffers[0].cbBuffer := ssl^.cbIoBuffer; Buffers[0].BufferType := SECBUFFER_DATA; Buffers[1].BufferType := SECBUFFER_EMPTY; Buffers[2].BufferType := SECBUFFER_EMPTY; Buffers[3].BufferType := SECBUFFER_EMPTY; Message.ulVersion := SECBUFFER_VERSION; Message.cBuffers := 4; Message.pBuffers := Buffers; if (@g_pSSPI^.DecryptMessage <> nil) then scRet := g_pSSPI^.DecryptMessage(@ssl^.hContext, @Message, 0, fQOP) else scRet := DECRYPT_MESSAGE_FN(g_pSSPI^.Reserved4)(@ssl^.hContext, @Message, 0, fQOP); if (scRet = SEC_E_INCOMPLETE_MESSAGE) then begin // The input buffer contains only a fragment of an // encrypted record. Loop around and read some more // data. continue; end; // Server signaled end of session if (scRet = SEC_I_CONTEXT_EXPIRED) then begin ssl^.rmshtdn := TRUE; SSL_shutdown(ssl); Exit(0); end; if (scRet <> SEC_E_OK) and (scRet <> SEC_I_RENEGOTIATE) and (scRet <> SEC_I_CONTEXT_EXPIRED) then begin Exit(SOCKET_ERROR); end; // Locate data and (optional) extra buffers. pDataBuffer := nil; pExtraBuffer := nil; for i := 1 to 3 do begin if (pDataBuffer = nil) and (Buffers[i].BufferType = SECBUFFER_DATA) then begin pDataBuffer := @Buffers[i]; end; if (pExtraBuffer = nil) and (Buffers[i].BufferType = SECBUFFER_EXTRA) then begin pExtraBuffer := @Buffers[i]; end; end; // Return decrypted data. if Assigned(pDataBuffer) then begin bytes := Min(num, pDataBuffer^.cbBuffer); CopyMemory(buf, pDataBuffer^.pvBuffer, bytes); rbytes := pDataBuffer^.cbBuffer - bytes; if (rbytes > 0) then begin if (ssl^.sbRecDataBuf < rbytes) then begin ssl^.sbRecDataBuf := rbytes; ssl^.pbRecDataBuf := PUCHAR(ReAllocMem(ssl^.pbRecDataBuf, rbytes)); end; CopyMemory(ssl^.pbRecDataBuf, pDataBuffer^.pvBuffer + bytes, rbytes); ssl^.cbRecDataBuf := rbytes; end; end; // Move any "extra" data to the input buffer. if Assigned(pExtraBuffer) then begin MoveMemory(ssl^.pbIoBuffer, pExtraBuffer^.pvBuffer, pExtraBuffer^.cbBuffer); ssl^.cbIoBuffer := pExtraBuffer^.cbBuffer; end else ssl^.cbIoBuffer := 0; if (pDataBuffer <> nil) and (bytes <> 0) then Exit(bytes); if (scRet = SEC_I_RENEGOTIATE) then begin // The server wants to perform another handshake // sequence. scRet := ClientHandshakeLoop(ssl, FALSE); if (scRet <> SEC_E_OK) then Exit(SOCKET_ERROR); end; end; end; function SSL_write(ssl: PSSL; const buf: PByte; num: cint): cint; cdecl; var Sizes: SecPkgContext_StreamSizes; scRet: SECURITY_STATUS; cbData: LONG; Message: SecBufferDesc; Buffers: array[0..3] of SecBuffer; pbDataBuffer: PUCHAR; pbMessage: PUCHAR; cbMessage: DWORD; sendOff: DWORD = 0; begin if (ssl = nil) then Exit(SOCKET_ERROR); FillChar(Buffers, SizeOf(Buffers), 0); scRet := g_pSSPI^.QueryContextAttributesA(@ssl^.hContext, SECPKG_ATTR_STREAM_SIZES, @Sizes); if (scRet <> SEC_E_OK) then Exit(scRet); pbDataBuffer := PUCHAR(GetMem(Sizes.cbMaximumMessage + Sizes.cbHeader + Sizes.cbTrailer)); pbMessage := pbDataBuffer + Sizes.cbHeader; while (sendOff < DWORD(num)) do begin cbMessage := Min(Sizes.cbMaximumMessage, DWORD(num) - sendOff); CopyMemory(pbMessage, buf + sendOff, cbMessage); Buffers[0].pvBuffer := pbDataBuffer; Buffers[0].cbBuffer := Sizes.cbHeader; Buffers[0].BufferType := SECBUFFER_STREAM_HEADER; Buffers[1].pvBuffer := pbMessage; Buffers[1].cbBuffer := cbMessage; Buffers[1].BufferType := SECBUFFER_DATA; Buffers[2].pvBuffer := pbMessage + cbMessage; Buffers[2].cbBuffer := Sizes.cbTrailer; Buffers[2].BufferType := SECBUFFER_STREAM_TRAILER; Buffers[3].BufferType := SECBUFFER_EMPTY; Message.ulVersion := SECBUFFER_VERSION; Message.cBuffers := 4; Message.pBuffers := Buffers; if (@g_pSSPI^.EncryptMessage <> nil) then scRet := g_pSSPI^.EncryptMessage(@ssl^.hContext, 0, @Message, 0) else scRet := ENCRYPT_MESSAGE_FN(g_pSSPI^.Reserved3)(@ssl^.hContext, 0, @Message, 0); if (FAILED(scRet)) then break; // Calculate encrypted packet size cbData := Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer; // Send the encrypted data to the server. cbData := send(ssl^.s, pbDataBuffer, cbData, 0); if (cbData = SOCKET_ERROR) or (cbData = 0) then begin g_pSSPI^.DeleteSecurityContext(@ssl^.hContext); scRet := SEC_E_INTERNAL_ERROR; break; end; sendOff += cbMessage; end; FreeMem(pbDataBuffer); if scRet = SEC_E_OK then Result := num else Result := SOCKET_ERROR; end; function SSL_pending(ssl: PSSL): cint; cdecl; begin if (ssl = nil) then Exit(0); if ssl^.cbRecDataBuf > 0 then Result := ssl^.cbRecDataBuf else if ssl^.exIoBuffer then begin ssl^.exIoBuffer := False; Result := ssl^.cbIoBuffer end else Result := 0; end; function SSLv23_method(): PSSL_METHOD; cdecl; begin Result:= PSSL_METHOD(SP_PROT_SSL3 or SP_PROT_TLS1 or SP_PROT_TLS1_1); end; function SSLv2_method(): PSSL_METHOD; cdecl; begin Result := PSSL_METHOD(SP_PROT_SSL2); end; function SSLv3_method(): PSSL_METHOD; cdecl; begin Result := PSSL_METHOD(SP_PROT_SSL3); end; function TLSv1_method(): PSSL_METHOD; cdecl; begin Result := PSSL_METHOD(SP_PROT_TLS1); end; function TLSv1_1_method(): PSSL_METHOD; cdecl; begin Result := PSSL_METHOD(SP_PROT_TLS1_1); end; function TLSv1_2_method(): PSSL_METHOD; cdecl; begin Result := PSSL_METHOD(SP_PROT_TLS1_2); end; procedure SSL_CTX_set_verify(ctx: PSSL_CTX; mode: cint; func: Pointer); cdecl; begin if (ctx <> nil) then ctx^.bVerify := mode <> 0; end; function SSL_get_error (ssl: PSSL; ret: cint): cint; cdecl; begin if (ret > 0) then Result := SSL_ERROR_NONE else Result := SSL_ERROR_ZERO_RETURN; end; var lpBuffer: TMemoryBasicInformation; begin if (IsSSLloaded = False) then begin if VirtualQuery(@lpBuffer, @lpBuffer, SizeOf(lpBuffer)) = SizeOf(lpBuffer) then begin SetLength(DLLSSLName, MAX_PATH); SetLength(DLLSSLName, GetModuleFileName(THandle(lpBuffer.AllocationBase), PAnsiChar(DLLSSLName), MAX_PATH)); DLLUtilName := DLLSSLName; if InitSSLInterface then SSLImplementation := TSSLOpenSSL; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/sswin32.inc������������������������������������������������0000644�0001750�0000144�00000154707�14743153644�021367� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 002.003.001 | |==============================================================================| | Content: Socket Independent Platform Layer - Win32/64 definition include | |==============================================================================| | Copyright (c)1999-2012, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2003-2012. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@exclude} //{$DEFINE WINSOCK1} {Note about define WINSOCK1: If you activate this compiler directive, then socket interface level 1.1 is used instead default level 2.2. Level 2.2 is not available on old W95, however you can install update. } //{$DEFINE FORCEOLDAPI} {Note about define FORCEOLDAPI: If you activate this compiler directive, then is allways used old socket API for name resolution. If you leave this directive inactive, then the new API is used, when running system allows it. For IPv6 support you must have new API! } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} {$IFDEF VER125} {$DEFINE BCB} {$ENDIF} {$IFDEF BCB} {$ObjExportAll On} (*$HPPEMIT '/* EDE 2003-02-19 */' *) (*$HPPEMIT 'namespace Synsock { using System::Shortint; }' *) (*$HPPEMIT '#undef h_addr' *) (*$HPPEMIT '#undef IOCPARM_MASK' *) (*$HPPEMIT '#undef FD_SETSIZE' *) (*$HPPEMIT '#undef IOC_VOID' *) (*$HPPEMIT '#undef IOC_OUT' *) (*$HPPEMIT '#undef IOC_IN' *) (*$HPPEMIT '#undef IOC_INOUT' *) (*$HPPEMIT '#undef FIONREAD' *) (*$HPPEMIT '#undef FIONBIO' *) (*$HPPEMIT '#undef FIOASYNC' *) (*$HPPEMIT '#undef IPPROTO_IP' *) (*$HPPEMIT '#undef IPPROTO_ICMP' *) (*$HPPEMIT '#undef IPPROTO_IGMP' *) (*$HPPEMIT '#undef IPPROTO_TCP' *) (*$HPPEMIT '#undef IPPROTO_UDP' *) (*$HPPEMIT '#undef IPPROTO_RAW' *) (*$HPPEMIT '#undef IPPROTO_MAX' *) (*$HPPEMIT '#undef INADDR_ANY' *) (*$HPPEMIT '#undef INADDR_LOOPBACK' *) (*$HPPEMIT '#undef INADDR_BROADCAST' *) (*$HPPEMIT '#undef INADDR_NONE' *) (*$HPPEMIT '#undef INVALID_SOCKET' *) (*$HPPEMIT '#undef SOCKET_ERROR' *) (*$HPPEMIT '#undef WSADESCRIPTION_LEN' *) (*$HPPEMIT '#undef WSASYS_STATUS_LEN' *) (*$HPPEMIT '#undef IP_OPTIONS' *) (*$HPPEMIT '#undef IP_TOS' *) (*$HPPEMIT '#undef IP_TTL' *) (*$HPPEMIT '#undef IP_MULTICAST_IF' *) (*$HPPEMIT '#undef IP_MULTICAST_TTL' *) (*$HPPEMIT '#undef IP_MULTICAST_LOOP' *) (*$HPPEMIT '#undef IP_ADD_MEMBERSHIP' *) (*$HPPEMIT '#undef IP_DROP_MEMBERSHIP' *) (*$HPPEMIT '#undef IP_DONTFRAGMENT' *) (*$HPPEMIT '#undef IP_DEFAULT_MULTICAST_TTL' *) (*$HPPEMIT '#undef IP_DEFAULT_MULTICAST_LOOP' *) (*$HPPEMIT '#undef IP_MAX_MEMBERSHIPS' *) (*$HPPEMIT '#undef SOL_SOCKET' *) (*$HPPEMIT '#undef SO_DEBUG' *) (*$HPPEMIT '#undef SO_ACCEPTCONN' *) (*$HPPEMIT '#undef SO_REUSEADDR' *) (*$HPPEMIT '#undef SO_KEEPALIVE' *) (*$HPPEMIT '#undef SO_DONTROUTE' *) (*$HPPEMIT '#undef SO_BROADCAST' *) (*$HPPEMIT '#undef SO_USELOOPBACK' *) (*$HPPEMIT '#undef SO_LINGER' *) (*$HPPEMIT '#undef SO_OOBINLINE' *) (*$HPPEMIT '#undef SO_DONTLINGER' *) (*$HPPEMIT '#undef SO_SNDBUF' *) (*$HPPEMIT '#undef SO_RCVBUF' *) (*$HPPEMIT '#undef SO_SNDLOWAT' *) (*$HPPEMIT '#undef SO_RCVLOWAT' *) (*$HPPEMIT '#undef SO_SNDTIMEO' *) (*$HPPEMIT '#undef SO_RCVTIMEO' *) (*$HPPEMIT '#undef SO_ERROR' *) (*$HPPEMIT '#undef SO_OPENTYPE' *) (*$HPPEMIT '#undef SO_SYNCHRONOUS_ALERT' *) (*$HPPEMIT '#undef SO_SYNCHRONOUS_NONALERT' *) (*$HPPEMIT '#undef SO_MAXDG' *) (*$HPPEMIT '#undef SO_MAXPATHDG' *) (*$HPPEMIT '#undef SO_UPDATE_ACCEPT_CONTEXT' *) (*$HPPEMIT '#undef SO_CONNECT_TIME' *) (*$HPPEMIT '#undef SO_TYPE' *) (*$HPPEMIT '#undef SOCK_STREAM' *) (*$HPPEMIT '#undef SOCK_DGRAM' *) (*$HPPEMIT '#undef SOCK_RAW' *) (*$HPPEMIT '#undef SOCK_RDM' *) (*$HPPEMIT '#undef SOCK_SEQPACKET' *) (*$HPPEMIT '#undef TCP_NODELAY' *) (*$HPPEMIT '#undef AF_UNSPEC' *) (*$HPPEMIT '#undef SOMAXCONN' *) (*$HPPEMIT '#undef AF_INET' *) (*$HPPEMIT '#undef AF_MAX' *) (*$HPPEMIT '#undef PF_UNSPEC' *) (*$HPPEMIT '#undef PF_INET' *) (*$HPPEMIT '#undef PF_MAX' *) (*$HPPEMIT '#undef MSG_OOB' *) (*$HPPEMIT '#undef MSG_PEEK' *) (*$HPPEMIT '#undef WSABASEERR' *) (*$HPPEMIT '#undef WSAEINTR' *) (*$HPPEMIT '#undef WSAEBADF' *) (*$HPPEMIT '#undef WSAEACCES' *) (*$HPPEMIT '#undef WSAEFAULT' *) (*$HPPEMIT '#undef WSAEINVAL' *) (*$HPPEMIT '#undef WSAEMFILE' *) (*$HPPEMIT '#undef WSAEWOULDBLOCK' *) (*$HPPEMIT '#undef WSAEINPROGRESS' *) (*$HPPEMIT '#undef WSAEALREADY' *) (*$HPPEMIT '#undef WSAENOTSOCK' *) (*$HPPEMIT '#undef WSAEDESTADDRREQ' *) (*$HPPEMIT '#undef WSAEMSGSIZE' *) (*$HPPEMIT '#undef WSAEPROTOTYPE' *) (*$HPPEMIT '#undef WSAENOPROTOOPT' *) (*$HPPEMIT '#undef WSAEPROTONOSUPPORT' *) (*$HPPEMIT '#undef WSAESOCKTNOSUPPORT' *) (*$HPPEMIT '#undef WSAEOPNOTSUPP' *) (*$HPPEMIT '#undef WSAEPFNOSUPPORT' *) (*$HPPEMIT '#undef WSAEAFNOSUPPORT' *) (*$HPPEMIT '#undef WSAEADDRINUSE' *) (*$HPPEMIT '#undef WSAEADDRNOTAVAIL' *) (*$HPPEMIT '#undef WSAENETDOWN' *) (*$HPPEMIT '#undef WSAENETUNREACH' *) (*$HPPEMIT '#undef WSAENETRESET' *) (*$HPPEMIT '#undef WSAECONNABORTED' *) (*$HPPEMIT '#undef WSAECONNRESET' *) (*$HPPEMIT '#undef WSAENOBUFS' *) (*$HPPEMIT '#undef WSAEISCONN' *) (*$HPPEMIT '#undef WSAENOTCONN' *) (*$HPPEMIT '#undef WSAESHUTDOWN' *) (*$HPPEMIT '#undef WSAETOOMANYREFS' *) (*$HPPEMIT '#undef WSAETIMEDOUT' *) (*$HPPEMIT '#undef WSAECONNREFUSED' *) (*$HPPEMIT '#undef WSAELOOP' *) (*$HPPEMIT '#undef WSAENAMETOOLONG' *) (*$HPPEMIT '#undef WSAEHOSTDOWN' *) (*$HPPEMIT '#undef WSAEHOSTUNREACH' *) (*$HPPEMIT '#undef WSAENOTEMPTY' *) (*$HPPEMIT '#undef WSAEPROCLIM' *) (*$HPPEMIT '#undef WSAEUSERS' *) (*$HPPEMIT '#undef WSAEDQUOT' *) (*$HPPEMIT '#undef WSAESTALE' *) (*$HPPEMIT '#undef WSAEREMOTE' *) (*$HPPEMIT '#undef WSASYSNOTREADY' *) (*$HPPEMIT '#undef WSAVERNOTSUPPORTED' *) (*$HPPEMIT '#undef WSANOTINITIALISED' *) (*$HPPEMIT '#undef WSAEDISCON' *) (*$HPPEMIT '#undef WSAENOMORE' *) (*$HPPEMIT '#undef WSAECANCELLED' *) (*$HPPEMIT '#undef WSAEEINVALIDPROCTABLE' *) (*$HPPEMIT '#undef WSAEINVALIDPROVIDER' *) (*$HPPEMIT '#undef WSAEPROVIDERFAILEDINIT' *) (*$HPPEMIT '#undef WSASYSCALLFAILURE' *) (*$HPPEMIT '#undef WSASERVICE_NOT_FOUND' *) (*$HPPEMIT '#undef WSATYPE_NOT_FOUND' *) (*$HPPEMIT '#undef WSA_E_NO_MORE' *) (*$HPPEMIT '#undef WSA_E_CANCELLED' *) (*$HPPEMIT '#undef WSAEREFUSED' *) (*$HPPEMIT '#undef WSAHOST_NOT_FOUND' *) (*$HPPEMIT '#undef HOST_NOT_FOUND' *) (*$HPPEMIT '#undef WSATRY_AGAIN' *) (*$HPPEMIT '#undef TRY_AGAIN' *) (*$HPPEMIT '#undef WSANO_RECOVERY' *) (*$HPPEMIT '#undef NO_RECOVERY' *) (*$HPPEMIT '#undef WSANO_DATA' *) (*$HPPEMIT '#undef NO_DATA' *) (*$HPPEMIT '#undef WSANO_ADDRESS' *) (*$HPPEMIT '#undef ENAMETOOLONG' *) (*$HPPEMIT '#undef ENOTEMPTY' *) (*$HPPEMIT '#undef FD_CLR' *) (*$HPPEMIT '#undef FD_ISSET' *) (*$HPPEMIT '#undef FD_SET' *) (*$HPPEMIT '#undef FD_ZERO' *) (*$HPPEMIT '#undef NO_ADDRESS' *) (*$HPPEMIT '#undef ADDR_ANY' *) (*$HPPEMIT '#undef SO_GROUP_ID' *) (*$HPPEMIT '#undef SO_GROUP_PRIORITY' *) (*$HPPEMIT '#undef SO_MAX_MSG_SIZE' *) (*$HPPEMIT '#undef SO_PROTOCOL_INFOA' *) (*$HPPEMIT '#undef SO_PROTOCOL_INFOW' *) (*$HPPEMIT '#undef SO_PROTOCOL_INFO' *) (*$HPPEMIT '#undef PVD_CONFIG' *) (*$HPPEMIT '#undef AF_INET6' *) (*$HPPEMIT '#undef PF_INET6' *) (*$HPPEMIT '#undef NI_MAXHOST' *) (*$HPPEMIT '#undef NI_MAXSERV' *) (*$HPPEMIT '#undef NI_NOFQDN' *) (*$HPPEMIT '#undef NI_NUMERICHOST' *) (*$HPPEMIT '#undef NI_NAMEREQD' *) (*$HPPEMIT '#undef NI_NUMERICSERV' *) (*$HPPEMIT '#undef NI_DGRAM' *) (*$HPPEMIT '#undef AI_PASSIVE' *) (*$HPPEMIT '#undef AI_CANONNAME' *) (*$HPPEMIT '#undef AI_NUMERICHOST' *) (*$HPPEMIT '#undef EWOULDBLOCK' *) (*$HPPEMIT '#undef EINPROGRESS' *) (*$HPPEMIT '#undef EALREADY' *) (*$HPPEMIT '#undef ENOTSOCK' *) (*$HPPEMIT '#undef EDESTADDRREQ' *) (*$HPPEMIT '#undef EMSGSIZE' *) (*$HPPEMIT '#undef EPROTOTYPE' *) (*$HPPEMIT '#undef ENOPROTOOPT' *) (*$HPPEMIT '#undef EPROTONOSUPPORT' *) (*$HPPEMIT '#undef EOPNOTSUPP' *) (*$HPPEMIT '#undef EAFNOSUPPORT' *) (*$HPPEMIT '#undef EADDRINUSE' *) (*$HPPEMIT '#undef EADDRNOTAVAIL' *) (*$HPPEMIT '#undef ENETDOWN' *) (*$HPPEMIT '#undef ENETUNREACH' *) (*$HPPEMIT '#undef ENETRESET' *) (*$HPPEMIT '#undef ECONNABORTED' *) (*$HPPEMIT '#undef ECONNRESET' *) (*$HPPEMIT '#undef ENOBUFS' *) (*$HPPEMIT '#undef EISCONN' *) (*$HPPEMIT '#undef ENOTCONN' *) (*$HPPEMIT '#undef ETIMEDOUT' *) (*$HPPEMIT '#undef ECONNREFUSED' *) (*$HPPEMIT '#undef ELOOP' *) (*$HPPEMIT '#undef EHOSTUNREACH' *) {$ENDIF} {$IFDEF FPC} {$IFDEF WIN32} {$ALIGN OFF} {$ELSE} {$PACKRECORDS C} {$ENDIF} {$ELSE} {$IFDEF WIN64} {$ALIGN ON} {$MINENUMSIZE 4} {$ELSE} {$MINENUMSIZE 4} {$ALIGN OFF} {$ENDIF} {$ENDIF} interface uses SyncObjs, SysUtils, Classes, Windows; function InitSocketInterface(stack: String): Boolean; function DestroySocketInterface: Boolean; const {$IFDEF WINSOCK1} WinsockLevel = $0101; {$ELSE} WinsockLevel = $0202; {$ENDIF} type u_short = Word; u_int = Integer; u_long = Longint; pu_long = ^u_long; pu_short = ^u_short; {$IFDEF FPC} TSocket = ptruint; {$ELSE} {$IFDEF WIN64} TSocket = UINT_PTR; {$ELSE} TSocket = u_int; {$ENDIF} {$ENDIF} TAddrFamily = integer; TMemory = pointer; const {$IFDEF WINCE} DLLStackName = 'ws2.dll'; {$ELSE} {$IFDEF WINSOCK1} DLLStackName = 'wsock32.dll'; {$ELSE} DLLStackName = 'ws2_32.dll'; {$ENDIF} {$ENDIF} DLLwship6 = 'wship6.dll'; cLocalhost = '127.0.0.1'; cAnyHost = '0.0.0.0'; cBroadcast = '255.255.255.255'; c6Localhost = '::1'; c6AnyHost = '::0'; c6Broadcast = 'ffff::1'; cAnyPort = '0'; const FD_SETSIZE = 64; type PFDSet = ^TFDSet; TFDSet = record fd_count: u_int; fd_array: array[0..FD_SETSIZE-1] of TSocket; end; const FIONREAD = $4004667f; FIONBIO = $8004667e; FIOASYNC = $8004667d; type PTimeVal = ^TTimeVal; TTimeVal = record tv_sec: Longint; tv_usec: Longint; end; const IPPROTO_IP = 0; { Dummy } IPPROTO_ICMP = 1; { Internet Control Message Protocol } IPPROTO_IGMP = 2; { Internet Group Management Protocol} IPPROTO_TCP = 6; { TCP } IPPROTO_UDP = 17; { User Datagram Protocol } IPPROTO_IPV6 = 41; IPPROTO_ICMPV6 = 58; IPPROTO_RM = 113; IPPROTO_RAW = 255; IPPROTO_MAX = 256; type PInAddr = ^TInAddr; TInAddr = record case integer of 0: (S_bytes: packed array [0..3] of byte); 1: (S_addr: u_long); end; PSockAddrIn = ^TSockAddrIn; TSockAddrIn = record case Integer of 0: (sin_family: u_short; sin_port: u_short; sin_addr: TInAddr; sin_zero: array[0..7] of byte); 1: (sa_family: u_short; sa_data: array[0..13] of byte) end; TIP_mreq = record imr_multiaddr: TInAddr; { IP multicast address of group } imr_interface: TInAddr; { local IP address of interface } end; PInAddr6 = ^TInAddr6; TInAddr6 = record case integer of 0: (S6_addr: packed array [0..15] of byte); 1: (u6_addr8: packed array [0..15] of byte); 2: (u6_addr16: packed array [0..7] of word); 3: (u6_addr32: packed array [0..3] of integer); end; PSockAddrIn6 = ^TSockAddrIn6; TSockAddrIn6 = record sin6_family: u_short; // AF_INET6 sin6_port: u_short; // Transport level port number sin6_flowinfo: u_long; // IPv6 flow information sin6_addr: TInAddr6; // IPv6 address sin6_scope_id: u_long; // Scope Id: IF number for link-local // SITE id for site-local end; TIPv6_mreq = record ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. ipv6mr_interface: integer; // Interface index. padding: integer; end; PHostEnt = ^THostEnt; THostEnt = record h_name: PAnsiChar; h_aliases: ^PAnsiChar; h_addrtype: Smallint; h_length: Smallint; case integer of 0: (h_addr_list: ^PAnsiChar); 1: (h_addr: ^PInAddr); end; PNetEnt = ^TNetEnt; TNetEnt = record n_name: PAnsiChar; n_aliases: ^PAnsiChar; n_addrtype: Smallint; n_net: u_long; end; PServEnt = ^TServEnt; TServEnt = record s_name: PAnsiChar; s_aliases: ^PAnsiChar; {$ifdef WIN64} s_proto: PAnsiChar; s_port: Smallint; {$else} s_port: Smallint; s_proto: PAnsiChar; {$endif} end; PProtoEnt = ^TProtoEnt; TProtoEnt = record p_name: PAnsiChar; p_aliases: ^PAnsichar; p_proto: Smallint; end; const INADDR_ANY = $00000000; INADDR_LOOPBACK = $7F000001; INADDR_BROADCAST = $FFFFFFFF; INADDR_NONE = $FFFFFFFF; ADDR_ANY = INADDR_ANY; INVALID_SOCKET = TSocket(NOT(0)); SOCKET_ERROR = -1; Const {$IFDEF WINSOCK1} IP_OPTIONS = 1; IP_MULTICAST_IF = 2; { set/get IP multicast interface } IP_MULTICAST_TTL = 3; { set/get IP multicast timetolive } IP_MULTICAST_LOOP = 4; { set/get IP multicast loopback } IP_ADD_MEMBERSHIP = 5; { add an IP group membership } IP_DROP_MEMBERSHIP = 6; { drop an IP group membership } IP_TTL = 7; { set/get IP Time To Live } IP_TOS = 8; { set/get IP Type Of Service } IP_DONTFRAGMENT = 9; { set/get IP Don't Fragment flag } {$ELSE} IP_OPTIONS = 1; IP_HDRINCL = 2; IP_TOS = 3; { set/get IP Type Of Service } IP_TTL = 4; { set/get IP Time To Live } IP_MULTICAST_IF = 9; { set/get IP multicast interface } IP_MULTICAST_TTL = 10; { set/get IP multicast timetolive } IP_MULTICAST_LOOP = 11; { set/get IP multicast loopback } IP_ADD_MEMBERSHIP = 12; { add an IP group membership } IP_DROP_MEMBERSHIP = 13; { drop an IP group membership } IP_DONTFRAGMENT = 14; { set/get IP Don't Fragment flag } {$ENDIF} IP_DEFAULT_MULTICAST_TTL = 1; { normally limit m'casts to 1 hop } IP_DEFAULT_MULTICAST_LOOP = 1; { normally hear sends if a member } IP_MAX_MEMBERSHIPS = 20; { per socket; must fit in one mbuf } SOL_SOCKET = $ffff; {options for socket level } { Option flags per-socket. } SO_DEBUG = $0001; { turn on debugging info recording } SO_ACCEPTCONN = $0002; { socket has had listen() } SO_REUSEADDR = $0004; { allow local address reuse } SO_KEEPALIVE = $0008; { keep connections alive } SO_DONTROUTE = $0010; { just use interface addresses } SO_BROADCAST = $0020; { permit sending of broadcast msgs } SO_USELOOPBACK = $0040; { bypass hardware when possible } SO_LINGER = $0080; { linger on close if data present } SO_OOBINLINE = $0100; { leave received OOB data in line } SO_DONTLINGER = $ff7f; { Additional options. } SO_SNDBUF = $1001; { send buffer size } SO_RCVBUF = $1002; { receive buffer size } SO_SNDLOWAT = $1003; { send low-water mark } SO_RCVLOWAT = $1004; { receive low-water mark } SO_SNDTIMEO = $1005; { send timeout } SO_RCVTIMEO = $1006; { receive timeout } SO_ERROR = $1007; { get error status and clear } SO_TYPE = $1008; { get socket type } { WinSock 2 extension -- new options } SO_GROUP_ID = $2001; { ID of a socket group} SO_GROUP_PRIORITY = $2002; { the relative priority within a group} SO_MAX_MSG_SIZE = $2003; { maximum message size } SO_PROTOCOL_INFOA = $2004; { WSAPROTOCOL_INFOA structure } SO_PROTOCOL_INFOW = $2005; { WSAPROTOCOL_INFOW structure } SO_PROTOCOL_INFO = SO_PROTOCOL_INFOA; PVD_CONFIG = $3001; {configuration info for service provider } { Option for opening sockets for synchronous access. } SO_OPENTYPE = $7008; SO_SYNCHRONOUS_ALERT = $10; SO_SYNCHRONOUS_NONALERT = $20; { Other NT-specific options. } SO_MAXDG = $7009; SO_MAXPATHDG = $700A; SO_UPDATE_ACCEPT_CONTEXT = $700B; SO_CONNECT_TIME = $700C; SOMAXCONN = $7fffffff; IPV6_UNICAST_HOPS = 8; // ??? IPV6_MULTICAST_IF = 9; // set/get IP multicast i/f IPV6_MULTICAST_HOPS = 10; // set/get IP multicast ttl IPV6_MULTICAST_LOOP = 11; // set/get IP multicast loopback IPV6_JOIN_GROUP = 12; // add an IP group membership IPV6_LEAVE_GROUP = 13; // drop an IP group membership MSG_NOSIGNAL = 0; // getnameinfo constants NI_MAXHOST = 1025; NI_MAXSERV = 32; NI_NOFQDN = $1; NI_NUMERICHOST = $2; NI_NAMEREQD = $4; NI_NUMERICSERV = $8; NI_DGRAM = $10; const SOCK_STREAM = 1; { stream socket } SOCK_DGRAM = 2; { datagram socket } SOCK_RAW = 3; { raw-protocol interface } SOCK_RDM = 4; { reliably-delivered message } SOCK_SEQPACKET = 5; { sequenced packet stream } { TCP options. } TCP_NODELAY = $0001; { Address families. } AF_UNSPEC = 0; { unspecified } AF_INET = 2; { internetwork: UDP, TCP, etc. } AF_INET6 = 23; { Internetwork Version 6 } AF_MAX = 24; { Protocol families, same as address families for now. } PF_UNSPEC = AF_UNSPEC; PF_INET = AF_INET; PF_INET6 = AF_INET6; PF_MAX = AF_MAX; type { Structure used by kernel to store most addresses. } PSockAddr = ^TSockAddr; TSockAddr = TSockAddrIn; { Structure used by kernel to pass protocol information in raw sockets. } PSockProto = ^TSockProto; TSockProto = record sp_family: u_short; sp_protocol: u_short; end; type PAddrInfo = ^TAddrInfo; TAddrInfo = record ai_flags: integer; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST. ai_family: integer; // PF_xxx. ai_socktype: integer; // SOCK_xxx. ai_protocol: integer; // 0 or IPPROTO_xxx for IPv4 and IPv6. ai_addrlen: u_int; // Length of ai_addr. ai_canonname: PAnsiChar; // Canonical name for nodename. ai_addr: PSockAddr; // Binary address. ai_next: PAddrInfo; // Next structure in linked list. end; const // Flags used in "hints" argument to getaddrinfo(). AI_PASSIVE = $1; // Socket address will be used in bind() call. AI_CANONNAME = $2; // Return canonical name in first ai_canonname. AI_NUMERICHOST = $4; // Nodename must be a numeric address string. type { Structure used for manipulating linger option. } PLinger = ^TLinger; TLinger = record l_onoff: u_short; l_linger: u_short; end; const MSG_OOB = $01; // Process out-of-band data. MSG_PEEK = $02; // Peek at incoming messages. const { All Windows Sockets error constants are biased by WSABASEERR from the "normal" } WSABASEERR = 10000; { Windows Sockets definitions of regular Microsoft C error constants } WSAEINTR = (WSABASEERR+4); WSAEBADF = (WSABASEERR+9); WSAEACCES = (WSABASEERR+13); WSAEFAULT = (WSABASEERR+14); WSAEINVAL = (WSABASEERR+22); WSAEMFILE = (WSABASEERR+24); { Windows Sockets definitions of regular Berkeley error constants } WSAEWOULDBLOCK = (WSABASEERR+35); WSAEINPROGRESS = (WSABASEERR+36); WSAEALREADY = (WSABASEERR+37); WSAENOTSOCK = (WSABASEERR+38); WSAEDESTADDRREQ = (WSABASEERR+39); WSAEMSGSIZE = (WSABASEERR+40); WSAEPROTOTYPE = (WSABASEERR+41); WSAENOPROTOOPT = (WSABASEERR+42); WSAEPROTONOSUPPORT = (WSABASEERR+43); WSAESOCKTNOSUPPORT = (WSABASEERR+44); WSAEOPNOTSUPP = (WSABASEERR+45); WSAEPFNOSUPPORT = (WSABASEERR+46); WSAEAFNOSUPPORT = (WSABASEERR+47); WSAEADDRINUSE = (WSABASEERR+48); WSAEADDRNOTAVAIL = (WSABASEERR+49); WSAENETDOWN = (WSABASEERR+50); WSAENETUNREACH = (WSABASEERR+51); WSAENETRESET = (WSABASEERR+52); WSAECONNABORTED = (WSABASEERR+53); WSAECONNRESET = (WSABASEERR+54); WSAENOBUFS = (WSABASEERR+55); WSAEISCONN = (WSABASEERR+56); WSAENOTCONN = (WSABASEERR+57); WSAESHUTDOWN = (WSABASEERR+58); WSAETOOMANYREFS = (WSABASEERR+59); WSAETIMEDOUT = (WSABASEERR+60); WSAECONNREFUSED = (WSABASEERR+61); WSAELOOP = (WSABASEERR+62); WSAENAMETOOLONG = (WSABASEERR+63); WSAEHOSTDOWN = (WSABASEERR+64); WSAEHOSTUNREACH = (WSABASEERR+65); WSAENOTEMPTY = (WSABASEERR+66); WSAEPROCLIM = (WSABASEERR+67); WSAEUSERS = (WSABASEERR+68); WSAEDQUOT = (WSABASEERR+69); WSAESTALE = (WSABASEERR+70); WSAEREMOTE = (WSABASEERR+71); { Extended Windows Sockets error constant definitions } WSASYSNOTREADY = (WSABASEERR+91); WSAVERNOTSUPPORTED = (WSABASEERR+92); WSANOTINITIALISED = (WSABASEERR+93); WSAEDISCON = (WSABASEERR+101); WSAENOMORE = (WSABASEERR+102); WSAECANCELLED = (WSABASEERR+103); WSAEEINVALIDPROCTABLE = (WSABASEERR+104); WSAEINVALIDPROVIDER = (WSABASEERR+105); WSAEPROVIDERFAILEDINIT = (WSABASEERR+106); WSASYSCALLFAILURE = (WSABASEERR+107); WSASERVICE_NOT_FOUND = (WSABASEERR+108); WSATYPE_NOT_FOUND = (WSABASEERR+109); WSA_E_NO_MORE = (WSABASEERR+110); WSA_E_CANCELLED = (WSABASEERR+111); WSAEREFUSED = (WSABASEERR+112); { Error return codes from gethostbyname() and gethostbyaddr() (when using the resolver). Note that these errors are retrieved via WSAGetLastError() and must therefore follow the rules for avoiding clashes with error numbers from specific implementations or language run-time systems. For this reason the codes are based at WSABASEERR+1001. Note also that [WSA]NO_ADDRESS is defined only for compatibility purposes. } { Authoritative Answer: Host not found } WSAHOST_NOT_FOUND = (WSABASEERR+1001); HOST_NOT_FOUND = WSAHOST_NOT_FOUND; { Non-Authoritative: Host not found, or SERVERFAIL } WSATRY_AGAIN = (WSABASEERR+1002); TRY_AGAIN = WSATRY_AGAIN; { Non recoverable errors, FORMERR, REFUSED, NOTIMP } WSANO_RECOVERY = (WSABASEERR+1003); NO_RECOVERY = WSANO_RECOVERY; { Valid name, no data record of requested type } WSANO_DATA = (WSABASEERR+1004); NO_DATA = WSANO_DATA; { no address, look for MX record } WSANO_ADDRESS = WSANO_DATA; NO_ADDRESS = WSANO_ADDRESS; EWOULDBLOCK = WSAEWOULDBLOCK; EINPROGRESS = WSAEINPROGRESS; EALREADY = WSAEALREADY; ENOTSOCK = WSAENOTSOCK; EDESTADDRREQ = WSAEDESTADDRREQ; EMSGSIZE = WSAEMSGSIZE; EPROTOTYPE = WSAEPROTOTYPE; ENOPROTOOPT = WSAENOPROTOOPT; EPROTONOSUPPORT = WSAEPROTONOSUPPORT; ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT; EOPNOTSUPP = WSAEOPNOTSUPP; EPFNOSUPPORT = WSAEPFNOSUPPORT; EAFNOSUPPORT = WSAEAFNOSUPPORT; EADDRINUSE = WSAEADDRINUSE; EADDRNOTAVAIL = WSAEADDRNOTAVAIL; ENETDOWN = WSAENETDOWN; ENETUNREACH = WSAENETUNREACH; ENETRESET = WSAENETRESET; ECONNABORTED = WSAECONNABORTED; ECONNRESET = WSAECONNRESET; ENOBUFS = WSAENOBUFS; EISCONN = WSAEISCONN; ENOTCONN = WSAENOTCONN; ESHUTDOWN = WSAESHUTDOWN; ETOOMANYREFS = WSAETOOMANYREFS; ETIMEDOUT = WSAETIMEDOUT; ECONNREFUSED = WSAECONNREFUSED; ELOOP = WSAELOOP; ENAMETOOLONG = WSAENAMETOOLONG; EHOSTDOWN = WSAEHOSTDOWN; EHOSTUNREACH = WSAEHOSTUNREACH; ENOTEMPTY = WSAENOTEMPTY; EPROCLIM = WSAEPROCLIM; EUSERS = WSAEUSERS; EDQUOT = WSAEDQUOT; ESTALE = WSAESTALE; EREMOTE = WSAEREMOTE; EAI_ADDRFAMILY = 1; // Address family for nodename not supported. EAI_AGAIN = 2; // Temporary failure in name resolution. EAI_BADFLAGS = 3; // Invalid value for ai_flags. EAI_FAIL = 4; // Non-recoverable failure in name resolution. EAI_FAMILY = 5; // Address family ai_family not supported. EAI_MEMORY = 6; // Memory allocation failure. EAI_NODATA = 7; // No address associated with nodename. EAI_NONAME = 8; // Nodename nor servname provided, or not known. EAI_SERVICE = 9; // Servname not supported for ai_socktype. EAI_SOCKTYPE = 10; // Socket type ai_socktype not supported. EAI_SYSTEM = 11; // System error returned in errno. const WSADESCRIPTION_LEN = 256; WSASYS_STATUS_LEN = 128; type PWSAData = ^TWSAData; TWSAData = record wVersion: Word; wHighVersion: Word; {$ifdef win64} iMaxSockets : Word; iMaxUdpDg : Word; lpVendorInfo : PAnsiChar; szDescription : array[0..WSADESCRIPTION_LEN] of AnsiChar; szSystemStatus : array[0..WSASYS_STATUS_LEN] of AnsiChar; {$else} szDescription: array[0..WSADESCRIPTION_LEN] of AnsiChar; szSystemStatus: array[0..WSASYS_STATUS_LEN] of AnsiChar; iMaxSockets: Word; iMaxUdpDg: Word; lpVendorInfo: PAnsiChar; {$endif} end; function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); var in6addr_any, in6addr_loopback : TInAddr6; procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); procedure FD_ZERO(var FDSet: TFDSet); {=============================================================================} type TWSAStartup = function(wVersionRequired: Word; var WSData: TWSAData): Integer; stdcall; TWSACleanup = function: Integer; stdcall; TWSAGetLastError = function: Integer; stdcall; TGetServByName = function(name, proto: PAnsiChar): PServEnt; stdcall; TGetServByPort = function(port: Integer; proto: PAnsiChar): PServEnt; stdcall; TGetProtoByName = function(name: PAnsiChar): PProtoEnt; stdcall; TGetProtoByNumber = function(proto: Integer): PProtoEnt; stdcall; TGetHostByName = function(name: PAnsiChar): PHostEnt; stdcall; TGetHostByAddr = function(addr: Pointer; len, Struc: Integer): PHostEnt; stdcall; TGetHostName = function(name: PAnsiChar; len: Integer): Integer; stdcall; TShutdown = function(s: TSocket; how: Integer): Integer; stdcall; TSetSockOpt = function(s: TSocket; level, optname: Integer; optval: PAnsiChar; optlen: Integer): Integer; stdcall; TGetSockOpt = function(s: TSocket; level, optname: Integer; optval: PAnsiChar; var optlen: Integer): Integer; stdcall; TSendTo = function(s: TSocket; const Buf; len, flags: Integer; addrto: PSockAddr; tolen: Integer): Integer; stdcall; TSend = function(s: TSocket; const Buf; len, flags: Integer): Integer; stdcall; TRecv = function(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall; TRecvFrom = function(s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; var fromlen: Integer): Integer; stdcall; Tntohs = function(netshort: u_short): u_short; stdcall; Tntohl = function(netlong: u_long): u_long; stdcall; TListen = function(s: TSocket; backlog: Integer): Integer; stdcall; TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: Integer): Integer; stdcall; TInet_ntoa = function(inaddr: TInAddr): PAnsiChar; stdcall; TInet_addr = function(cp: PAnsiChar): u_long; stdcall; Thtons = function(hostshort: u_short): u_short; stdcall; Thtonl = function(hostlong: u_long): u_long; stdcall; TGetSockName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; stdcall; TGetPeerName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; stdcall; TConnect = function(s: TSocket; name: PSockAddr; namelen: Integer): Integer; stdcall; TCloseSocket = function(s: TSocket): Integer; stdcall; TBind = function(s: TSocket; addr: PSockAddr; namelen: Integer): Integer; stdcall; TAccept = function(s: TSocket; addr: PSockAddr; var addrlen: Integer): TSocket; stdcall; TTSocket = function(af, Struc, Protocol: Integer): TSocket; stdcall; TSelect = function(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): Longint; stdcall; TGetAddrInfo = function(NodeName: PAnsiChar; ServName: PAnsiChar; Hints: PAddrInfo; var Addrinfo: PAddrInfo): integer; stdcall; TFreeAddrInfo = procedure(ai: PAddrInfo); stdcall; TGetNameInfo = function( addr: PSockAddr; namelen: Integer; host: PAnsiChar; hostlen: DWORD; serv: PAnsiChar; servlen: DWORD; flags: integer): integer; stdcall; T__WSAFDIsSet = function (s: TSocket; var FDSet: TFDSet): Bool; stdcall; TWSAIoctl = function (s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD; lpcbBytesReturned: PDWORD; lpOverlapped: Pointer; lpCompletionRoutine: pointer): u_int; stdcall; var WSAStartup: TWSAStartup = nil; WSACleanup: TWSACleanup = nil; WSAGetLastError: TWSAGetLastError = nil; GetServByName: TGetServByName = nil; GetServByPort: TGetServByPort = nil; GetProtoByName: TGetProtoByName = nil; GetProtoByNumber: TGetProtoByNumber = nil; GetHostByName: TGetHostByName = nil; GetHostByAddr: TGetHostByAddr = nil; ssGetHostName: TGetHostName = nil; Shutdown: TShutdown = nil; SetSockOpt: TSetSockOpt = nil; GetSockOpt: TGetSockOpt = nil; ssSendTo: TSendTo = nil; ssSend: TSend = nil; ssRecv: TRecv = nil; ssRecvFrom: TRecvFrom = nil; ntohs: Tntohs = nil; ntohl: Tntohl = nil; Listen: TListen = nil; IoctlSocket: TIoctlSocket = nil; Inet_ntoa: TInet_ntoa = nil; Inet_addr: TInet_addr = nil; htons: Thtons = nil; htonl: Thtonl = nil; ssGetSockName: TGetSockName = nil; ssGetPeerName: TGetPeerName = nil; ssConnect: TConnect = nil; CloseSocket: TCloseSocket = nil; ssBind: TBind = nil; ssAccept: TAccept = nil; Socket: TTSocket = nil; Select: TSelect = nil; GetAddrInfo: TGetAddrInfo = nil; FreeAddrInfo: TFreeAddrInfo = nil; GetNameInfo: TGetNameInfo = nil; __WSAFDIsSet: T__WSAFDIsSet = nil; WSAIoctl: TWSAIoctl = nil; var SynSockCS: SyncObjs.TCriticalSection; SockEnhancedApi: Boolean; SockWship6Api: Boolean; type TVarSin = packed record case integer of 0: (AddressFamily: u_short); 1: ( case sin_family: u_short of AF_INET: (sin_port: u_short; sin_addr: TInAddr; sin_zero: array[0..7] of byte); AF_INET6: (sin6_port: u_short; sin6_flowinfo: u_long; sin6_addr: TInAddr6; sin6_scope_id: u_long); ); end; function SizeOfVarSin(sin: TVarSin): integer; function Bind(s: TSocket; const addr: TVarSin): Integer; function Connect(s: TSocket; const name: TVarSin): Integer; function GetSockName(s: TSocket; var name: TVarSin): Integer; function GetPeerName(s: TSocket; var name: TVarSin): Integer; function GetHostName: AnsiString; function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; function Accept(s: TSocket; var addr: TVarSin): TSocket; function IsNewApi(Family: integer): Boolean; function SetVarSin(var Sin: TVarSin; IP, Port: AnsiString; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; function GetSinIP(Sin: TVarSin): AnsiString; function GetSinPort(Sin: TVarSin): Integer; procedure ResolveNameToIP(Name: AnsiString; Family, SockProtocol, SockType: integer; const IPList: TStrings); function ResolveIPToName(IP: AnsiString; Family, SockProtocol, SockType: integer): AnsiString; function ResolvePort(Port: AnsiString; Family, SockProtocol, SockType: integer): Word; {==============================================================================} implementation var SynSockCount: Integer = 0; LibHandle: THandle = 0; Libwship6Handle: THandle = 0; function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); end; function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and (a^.u6_addr32[2] = 0) and (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); end; function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); end; function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; begin Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); end; function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; begin Result := (a^.u6_addr8[0] = $FF); end; function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; begin Result := (CompareMem( a, b, sizeof(TInAddr6))); end; procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); begin FillChar(a^, sizeof(TInAddr6), 0); end; procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); begin FillChar(a^, sizeof(TInAddr6), 0); a^.u6_addr8[15] := 1; end; {=============================================================================} procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); var I: Integer; begin I := 0; while I < FDSet.fd_count do begin if FDSet.fd_array[I] = Socket then begin while I < FDSet.fd_count - 1 do begin FDSet.fd_array[I] := FDSet.fd_array[I + 1]; Inc(I); end; Dec(FDSet.fd_count); Break; end; Inc(I); end; end; function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; begin Result := __WSAFDIsSet(Socket, FDSet); end; procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); begin if FDSet.fd_count < FD_SETSIZE then begin FDSet.fd_array[FDSet.fd_count] := Socket; Inc(FDSet.fd_count); end; end; procedure FD_ZERO(var FDSet: TFDSet); begin FDSet.fd_count := 0; end; {=============================================================================} function SizeOfVarSin(sin: TVarSin): integer; begin case sin.sin_family of AF_INET: Result := SizeOf(TSockAddrIn); AF_INET6: Result := SizeOf(TSockAddrIn6); else Result := 0; end; end; {=============================================================================} function Bind(s: TSocket; const addr: TVarSin): Integer; begin Result := ssBind(s, @addr, SizeOfVarSin(addr)); end; function Connect(s: TSocket; const name: TVarSin): Integer; begin Result := ssConnect(s, @name, SizeOfVarSin(name)); end; function GetSockName(s: TSocket; var name: TVarSin): Integer; var len: integer; begin len := SizeOf(name); FillChar(name, len, 0); Result := ssGetSockName(s, @name, Len); end; function GetPeerName(s: TSocket; var name: TVarSin): Integer; var len: integer; begin len := SizeOf(name); FillChar(name, len, 0); Result := ssGetPeerName(s, @name, Len); end; function GetHostName: AnsiString; var s: AnsiString; begin Result := ''; setlength(s, 255); ssGetHostName(pAnsichar(s), Length(s) - 1); Result := PAnsichar(s); end; function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; begin Result := ssSend(s, Buf^, len, flags); end; function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; begin Result := ssRecv(s, Buf^, len, flags); end; function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; begin Result := ssSendTo(s, Buf^, len, flags, @addrto, SizeOfVarSin(addrto)); end; function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; var x: integer; begin x := SizeOf(from); Result := ssRecvFrom(s, Buf^, len, flags, @from, x); end; function Accept(s: TSocket; var addr: TVarSin): TSocket; var x: integer; begin x := SizeOf(addr); Result := ssAccept(s, @addr, x); end; {=============================================================================} function IsNewApi(Family: integer): Boolean; begin Result := SockEnhancedApi; if not Result then Result := (Family = AF_INET6) and SockWship6Api; end; function SetVarSin(var Sin: TVarSin; IP, Port: AnsiString; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; type pu_long = ^u_long; var ProtoEnt: PProtoEnt; ServEnt: PServEnt; HostEnt: PHostEnt; r: integer; Hints1, Hints2: TAddrInfo; Sin1, Sin2: TVarSin; TwoPass: boolean; function GetAddr(const IP, port: AnsiString; Hints: TAddrInfo; var Sin: TVarSin): integer; var Addr: PAddrInfo; begin Addr := nil; try FillChar(Sin, Sizeof(Sin), 0); if Hints.ai_socktype = SOCK_RAW then begin Hints.ai_socktype := 0; Hints.ai_protocol := 0; Result := synsock.GetAddrInfo(PAnsiChar(IP), nil, @Hints, Addr); end else begin if (IP = cAnyHost) or (IP = c6AnyHost) then begin Hints.ai_flags := AI_PASSIVE; Result := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); end else if (IP = cLocalhost) or (IP = c6Localhost) then begin Result := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); end else begin Result := synsock.GetAddrInfo(PAnsiChar(IP), PAnsiChar(Port), @Hints, Addr); end; end; if Result = 0 then if (Addr <> nil) then Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); finally if Assigned(Addr) then synsock.FreeAddrInfo(Addr); end; end; begin Result := 0; FillChar(Sin, Sizeof(Sin), 0); if not IsNewApi(family) then begin SynSockCS.Enter; try Sin.sin_family := AF_INET; ProtoEnt := synsock.GetProtoByNumber(SockProtocol); ServEnt := nil; if (ProtoEnt <> nil) and (StrToIntDef(string(Port),-1) =-1) then ServEnt := synsock.GetServByName(PAnsiChar(Port), ProtoEnt^.p_name); if ServEnt = nil then Sin.sin_port := synsock.htons(StrToIntDef(string(Port), 0)) else Sin.sin_port := ServEnt^.s_port; if IP = cBroadcast then Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) else begin Sin.sin_addr.s_addr := synsock.inet_addr(PAnsiChar(IP)); if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then begin HostEnt := synsock.GetHostByName(PAnsiChar(IP)); Result := synsock.WSAGetLastError; if HostEnt <> nil then Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); end; end; finally SynSockCS.Leave; end; end else begin FillChar(Hints1, Sizeof(Hints1), 0); FillChar(Hints2, Sizeof(Hints2), 0); TwoPass := False; if Family = AF_UNSPEC then begin if PreferIP4 then begin Hints1.ai_family := AF_INET; Hints2.ai_family := AF_INET6; TwoPass := True; end else begin Hints2.ai_family := AF_INET; Hints1.ai_family := AF_INET6; TwoPass := True; end; end else Hints1.ai_family := Family; Hints1.ai_socktype := SockType; Hints1.ai_protocol := SockProtocol; Hints2.ai_socktype := Hints1.ai_socktype; Hints2.ai_protocol := Hints1.ai_protocol; r := GetAddr(IP, Port, Hints1, Sin1); Result := r; sin := sin1; if r <> 0 then if TwoPass then begin r := GetAddr(IP, Port, Hints2, Sin2); Result := r; if r = 0 then sin := sin2; end; end; end; function GetSinIP(Sin: TVarSin): AnsiString; var p: PAnsiChar; host, serv: AnsiString; hostlen, servlen: integer; r: integer; begin Result := ''; if not IsNewApi(Sin.AddressFamily) then begin p := synsock.inet_ntoa(Sin.sin_addr); if p <> nil then Result := p; end else begin hostlen := NI_MAXHOST; servlen := NI_MAXSERV; setlength(host, hostlen); setlength(serv, servlen); r := getnameinfo(@sin, SizeOfVarSin(sin), PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); if r = 0 then Result := PAnsiChar(host); end; end; function GetSinPort(Sin: TVarSin): Integer; begin if (Sin.sin_family = AF_INET6) then Result := synsock.ntohs(Sin.sin6_port) else Result := synsock.ntohs(Sin.sin_port); end; procedure ResolveNameToIP(Name: AnsiString; Family, SockProtocol, SockType: integer; const IPList: TStrings); type TaPInAddr = array[0..250] of PInAddr; PaPInAddr = ^TaPInAddr; var Hints: TAddrInfo; Addr: PAddrInfo; AddrNext: PAddrInfo; r: integer; host, serv: AnsiString; hostlen, servlen: integer; RemoteHost: PHostEnt; IP: u_long; PAdrPtr: PaPInAddr; i: Integer; s: String; InAddr: TInAddr; begin IPList.Clear; if not IsNewApi(Family) then begin IP := synsock.inet_addr(PAnsiChar(Name)); if IP = u_long(INADDR_NONE) then begin SynSockCS.Enter; try RemoteHost := synsock.GetHostByName(PAnsiChar(Name)); if RemoteHost <> nil then begin PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); i := 0; while PAdrPtr^[i] <> nil do begin InAddr := PAdrPtr^[i]^; s := Format('%d.%d.%d.%d', [InAddr.S_bytes[0], InAddr.S_bytes[1], InAddr.S_bytes[2], InAddr.S_bytes[3]]); IPList.Add(s); Inc(i); end; end; finally SynSockCS.Leave; end; end else IPList.Add(string(Name)); end else begin Addr := nil; try FillChar(Hints, Sizeof(Hints), 0); Hints.ai_family := AF_UNSPEC; Hints.ai_socktype := SockType; Hints.ai_protocol := SockProtocol; Hints.ai_flags := 0; r := synsock.GetAddrInfo(PAnsiChar(Name), nil, @Hints, Addr); if r = 0 then begin AddrNext := Addr; while not(AddrNext = nil) do begin if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then begin hostlen := NI_MAXHOST; servlen := NI_MAXSERV; setlength(host, hostlen); setlength(serv, servlen); r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); if r = 0 then begin host := PAnsiChar(host); IPList.Add(string(host)); end; end; AddrNext := AddrNext^.ai_next; end; end; finally if Assigned(Addr) then synsock.FreeAddrInfo(Addr); end; end; if IPList.Count = 0 then IPList.Add(cAnyHost); end; function ResolvePort(Port: AnsiString; Family, SockProtocol, SockType: integer): Word; var ProtoEnt: PProtoEnt; ServEnt: PServEnt; Hints: TAddrInfo; Addr: PAddrInfo; r: integer; begin Result := 0; if not IsNewApi(Family) then begin SynSockCS.Enter; try ProtoEnt := synsock.GetProtoByNumber(SockProtocol); ServEnt := nil; if ProtoEnt <> nil then ServEnt := synsock.GetServByName(PAnsiChar(Port), ProtoEnt^.p_name); if ServEnt = nil then Result := StrToIntDef(string(Port), 0) else Result := synsock.htons(ServEnt^.s_port); finally SynSockCS.Leave; end; end else begin Addr := nil; try FillChar(Hints, Sizeof(Hints), 0); Hints.ai_family := AF_UNSPEC; Hints.ai_socktype := SockType; Hints.ai_protocol := Sockprotocol; Hints.ai_flags := AI_PASSIVE; r := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); if (r = 0) and Assigned(Addr) then begin if Addr^.ai_family = AF_INET then Result := synsock.htons(Addr^.ai_addr^.sin_port); if Addr^.ai_family = AF_INET6 then Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); end; finally if Assigned(Addr) then synsock.FreeAddrInfo(Addr); end; end; end; function ResolveIPToName(IP: AnsiString; Family, SockProtocol, SockType: integer): AnsiString; var Hints: TAddrInfo; Addr: PAddrInfo; r: integer; host, serv: AnsiString; hostlen, servlen: integer; RemoteHost: PHostEnt; IPn: u_long; begin Result := IP; if not IsNewApi(Family) then begin IPn := synsock.inet_addr(PAnsiChar(IP)); if IPn <> u_long(INADDR_NONE) then begin SynSockCS.Enter; try RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); if RemoteHost <> nil then Result := RemoteHost^.h_name; finally SynSockCS.Leave; end; end; end else begin Addr := nil; try FillChar(Hints, Sizeof(Hints), 0); Hints.ai_family := AF_UNSPEC; Hints.ai_socktype := SockType; Hints.ai_protocol := SockProtocol; Hints.ai_flags := 0; r := synsock.GetAddrInfo(PAnsiChar(IP), nil, @Hints, Addr); if (r = 0) and Assigned(Addr)then begin hostlen := NI_MAXHOST; servlen := NI_MAXSERV; setlength(host, hostlen); setlength(serv, servlen); r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, NI_NUMERICSERV); if r = 0 then Result := PAnsiChar(host); end; finally if Assigned(Addr) then synsock.FreeAddrInfo(Addr); end; end; end; {=============================================================================} function InitSocketInterface(stack: String): Boolean; begin Result := False; if stack = '' then stack := DLLStackName; SynSockCS.Enter; try if SynSockCount = 0 then begin SockEnhancedApi := False; SockWship6Api := False; LibHandle := LoadLibrary(PChar(Stack)); if LibHandle <> 0 then begin WSAIoctl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAIoctl'))); __WSAFDIsSet := GetProcAddress(LibHandle, PAnsiChar(AnsiString('__WSAFDIsSet'))); CloseSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('closesocket'))); IoctlSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ioctlsocket'))); WSAGetLastError := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAGetLastError'))); WSAStartup := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAStartup'))); WSACleanup := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSACleanup'))); ssAccept := GetProcAddress(LibHandle, PAnsiChar(AnsiString('accept'))); ssBind := GetProcAddress(LibHandle, PAnsiChar(AnsiString('bind'))); ssConnect := GetProcAddress(LibHandle, PAnsiChar(AnsiString('connect'))); ssGetPeerName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getpeername'))); ssGetSockName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockname'))); GetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockopt'))); Htonl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('htonl'))); Htons := GetProcAddress(LibHandle, PAnsiChar(AnsiString('htons'))); Inet_Addr := GetProcAddress(LibHandle, PAnsiChar(AnsiString('inet_addr'))); Inet_Ntoa := GetProcAddress(LibHandle, PAnsiChar(AnsiString('inet_ntoa'))); Listen := GetProcAddress(LibHandle, PAnsiChar(AnsiString('listen'))); Ntohl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ntohl'))); Ntohs := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ntohs'))); ssRecv := GetProcAddress(LibHandle, PAnsiChar(AnsiString('recv'))); ssRecvFrom := GetProcAddress(LibHandle, PAnsiChar(AnsiString('recvfrom'))); Select := GetProcAddress(LibHandle, PAnsiChar(AnsiString('select'))); ssSend := GetProcAddress(LibHandle, PAnsiChar(AnsiString('send'))); ssSendTo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('sendto'))); SetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('setsockopt'))); ShutDown := GetProcAddress(LibHandle, PAnsiChar(AnsiString('shutdown'))); Socket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('socket'))); GetHostByAddr := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostbyaddr'))); GetHostByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostbyname'))); GetProtoByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getprotobyname'))); GetProtoByNumber := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getprotobynumber'))); GetServByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getservbyname'))); GetServByPort := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getservbyport'))); ssGetHostName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostname'))); {$IFNDEF FORCEOLDAPI} GetAddrInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getaddrinfo'))); FreeAddrInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('freeaddrinfo'))); GetNameInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getnameinfo'))); SockEnhancedApi := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) and Assigned(GetNameInfo); if not SockEnhancedApi then begin LibWship6Handle := LoadLibrary(PChar(DLLWship6)); if LibWship6Handle <> 0 then begin GetAddrInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('getaddrinfo'))); FreeAddrInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('freeaddrinfo'))); GetNameInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('getnameinfo'))); SockWship6Api := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) and Assigned(GetNameInfo); end; end; {$ENDIF} Result := True; end; end else Result := True; if Result then Inc(SynSockCount); finally SynSockCS.Leave; end; end; function DestroySocketInterface: Boolean; begin SynSockCS.Enter; try Dec(SynSockCount); if SynSockCount < 0 then SynSockCount := 0; if SynSockCount = 0 then begin if LibHandle <> 0 then begin FreeLibrary(libHandle); LibHandle := 0; end; if LibWship6Handle <> 0 then begin FreeLibrary(LibWship6Handle); LibWship6Handle := 0; end; end; finally SynSockCS.Leave; end; Result := True; end; initialization begin SynSockCS := SyncObjs.TCriticalSection.Create; SET_IN6_IF_ADDR_ANY (@in6addr_any); SET_LOOPBACK_ADDR6 (@in6addr_loopback); end; finalization begin SynSockCS.Free; end;���������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/synacode.pas�����������������������������������������������0000644�0001750�0000144�00000143160�14743153644�021665� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 002.002.003 | |==============================================================================| | Content: Coding and decoding support | |==============================================================================| | Copyright (c)1999-2013, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2000-2013. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@abstract(Various encoding and decoding support)} {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$Q-} {$R-} {$H+} {$TYPEDADDRESS OFF} {$IFDEF CIL} {$DEFINE SYNACODE_NATIVE} {$ENDIF} {$IFDEF FPC_BIG_ENDIAN} {$DEFINE SYNACODE_NATIVE} {$ENDIF} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$WARN SUSPICIOUS_TYPECAST OFF} {$ENDIF} unit synacode; interface uses SysUtils; type TSpecials = set of AnsiChar; const SpecialChar: TSpecials = ['=', '(', ')', '[', ']', '<', '>', ':', ';', ',', '@', '/', '?', '\', '"', '_']; NonAsciiChar: TSpecials = [#0..#31, #127..#255]; URLFullSpecialChar: TSpecials = [';', '/', '?', ':', '@', '=', '&', '#', '+']; URLSpecialChar: TSpecials = [#$00..#$20, '<', '>', '"', '%', '{', '}', '|', '\', '^', '[', ']', '`', #$7F..#$FF]; TableBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; TableBase64mod = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,='; TableUU = '`!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'; TableXX = '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; ReTablebase64 = #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$3E +#$40 +#$40 +#$40 +#$3F +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C +#$3D +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$01 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C +#$0D +#$0E +#$0F +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; ReTableUU = #$01 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C +#$0D +#$0E +#$0F +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C +#$3D +#$3E +#$3F +#$00 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; ReTableXX = #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$40 +#$01 +#$40 +#$40 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$0C +#$0D +#$0E +#$0F +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 +#$25 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C +#$3D +#$3E +#$3F +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; {:Decodes triplet encoding with a given character delimiter. It is used for decoding quoted-printable or URL encoding.} function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; {:Decodes a string from quoted printable form. (also decodes triplet sequences like '=7F')} function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; {:Decodes a string of URL encoding. (also decodes triplet sequences like '%7F')} function DecodeURL(const Value: AnsiString): AnsiString; {:Performs triplet encoding with a given character delimiter. Used for encoding quoted-printable or URL encoding.} function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; Specials: TSpecials): AnsiString; {:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) are encoded.} function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; {:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) and @link(SpecialChar) are encoded.} function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; {:Encodes a string to URL format. Used for encoding data from a form field in HTTP, etc. (Encodes all critical characters including characters used as URL delimiters ('/',':', etc.)} function EncodeURLElement(const Value: AnsiString): AnsiString; {:Encodes a string to URL format. Used to encode critical characters in all URLs.} function EncodeURL(const Value: AnsiString): AnsiString; {:Decode 4to3 encoding with given table. If some element is not found in table, first item from table is used. This is good for buggy coded items by Microsoft Outlook. This software sometimes using wrong table for UUcode, where is used ' ' instead '`'.} function Decode4to3(const Value, Table: AnsiString): AnsiString; {:Decode 4to3 encoding with given REVERSE table. Using this function with reverse table is much faster then @link(Decode4to3). This function is used internally for Base64, UU or XX decoding.} function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; {:Encode by system 3to4 (used by Base64, UU coding, etc) by given table.} function Encode3to4(const Value, Table: AnsiString): AnsiString; {:Decode string from base64 format.} function DecodeBase64(const Value: AnsiString): AnsiString; {:Encodes a string to base64 format.} function EncodeBase64(const Value: AnsiString): AnsiString; {:Decode string from modified base64 format. (used in IMAP, for example.)} function DecodeBase64mod(const Value: AnsiString): AnsiString; {:Encodes a string to modified base64 format. (used in IMAP, for example.)} function EncodeBase64mod(const Value: AnsiString): AnsiString; {:Decodes a string from UUcode format.} function DecodeUU(const Value: AnsiString): AnsiString; {:encode UUcode. it encode only datas, you must also add header and footer for proper encode.} function EncodeUU(const Value: AnsiString): AnsiString; {:Decodes a string from XXcode format.} function DecodeXX(const Value: AnsiString): AnsiString; {:decode line with Yenc code. This code is sometimes used in newsgroups.} function DecodeYEnc(const Value: AnsiString): AnsiString; {:Returns a new CRC32 value after adding a new byte of data.} function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; {:return CRC32 from a value string.} function Crc32(const Value: AnsiString): Integer; {:Returns a new CRC16 value after adding a new byte of data.} function UpdateCrc16(Value: Byte; Crc16: Word): Word; {:return CRC16 from a value string.} function Crc16(const Value: AnsiString): Word; {:Returns a binary string with a RSA-MD5 hashing of "Value" string.} function MD5(const Value: AnsiString): AnsiString; {:Returns a binary string with HMAC-MD5 hash.} function HMAC_MD5(Text, Key: AnsiString): AnsiString; {:Returns a binary string with a RSA-MD5 hashing of string what is constructed by repeating "value" until length is "Len".} function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; {:Returns a binary string with a SHA-1 hashing of "Value" string.} function SHA1(const Value: AnsiString): AnsiString; {:Returns a binary string with HMAC-SHA1 hash.} function HMAC_SHA1(Text, Key: AnsiString): AnsiString; {:Returns a binary string with a SHA-1 hashing of string what is constructed by repeating "value" until length is "Len".} function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; {:Returns a binary string with a RSA-MD4 hashing of "Value" string.} function MD4(const Value: AnsiString): AnsiString; implementation const Crc32Tab: array[0..255] of Integer = ( Integer($00000000), Integer($77073096), Integer($EE0E612C), Integer($990951BA), Integer($076DC419), Integer($706AF48F), Integer($E963A535), Integer($9E6495A3), Integer($0EDB8832), Integer($79DCB8A4), Integer($E0D5E91E), Integer($97D2D988), Integer($09B64C2B), Integer($7EB17CBD), Integer($E7B82D07), Integer($90BF1D91), Integer($1DB71064), Integer($6AB020F2), Integer($F3B97148), Integer($84BE41DE), Integer($1ADAD47D), Integer($6DDDE4EB), Integer($F4D4B551), Integer($83D385C7), Integer($136C9856), Integer($646BA8C0), Integer($FD62F97A), Integer($8A65C9EC), Integer($14015C4F), Integer($63066CD9), Integer($FA0F3D63), Integer($8D080DF5), Integer($3B6E20C8), Integer($4C69105E), Integer($D56041E4), Integer($A2677172), Integer($3C03E4D1), Integer($4B04D447), Integer($D20D85FD), Integer($A50AB56B), Integer($35B5A8FA), Integer($42B2986C), Integer($DBBBC9D6), Integer($ACBCF940), Integer($32D86CE3), Integer($45DF5C75), Integer($DCD60DCF), Integer($ABD13D59), Integer($26D930AC), Integer($51DE003A), Integer($C8D75180), Integer($BFD06116), Integer($21B4F4B5), Integer($56B3C423), Integer($CFBA9599), Integer($B8BDA50F), Integer($2802B89E), Integer($5F058808), Integer($C60CD9B2), Integer($B10BE924), Integer($2F6F7C87), Integer($58684C11), Integer($C1611DAB), Integer($B6662D3D), Integer($76DC4190), Integer($01DB7106), Integer($98D220BC), Integer($EFD5102A), Integer($71B18589), Integer($06B6B51F), Integer($9FBFE4A5), Integer($E8B8D433), Integer($7807C9A2), Integer($0F00F934), Integer($9609A88E), Integer($E10E9818), Integer($7F6A0DBB), Integer($086D3D2D), Integer($91646C97), Integer($E6635C01), Integer($6B6B51F4), Integer($1C6C6162), Integer($856530D8), Integer($F262004E), Integer($6C0695ED), Integer($1B01A57B), Integer($8208F4C1), Integer($F50FC457), Integer($65B0D9C6), Integer($12B7E950), Integer($8BBEB8EA), Integer($FCB9887C), Integer($62DD1DDF), Integer($15DA2D49), Integer($8CD37CF3), Integer($FBD44C65), Integer($4DB26158), Integer($3AB551CE), Integer($A3BC0074), Integer($D4BB30E2), Integer($4ADFA541), Integer($3DD895D7), Integer($A4D1C46D), Integer($D3D6F4FB), Integer($4369E96A), Integer($346ED9FC), Integer($AD678846), Integer($DA60B8D0), Integer($44042D73), Integer($33031DE5), Integer($AA0A4C5F), Integer($DD0D7CC9), Integer($5005713C), Integer($270241AA), Integer($BE0B1010), Integer($C90C2086), Integer($5768B525), Integer($206F85B3), Integer($B966D409), Integer($CE61E49F), Integer($5EDEF90E), Integer($29D9C998), Integer($B0D09822), Integer($C7D7A8B4), Integer($59B33D17), Integer($2EB40D81), Integer($B7BD5C3B), Integer($C0BA6CAD), Integer($EDB88320), Integer($9ABFB3B6), Integer($03B6E20C), Integer($74B1D29A), Integer($EAD54739), Integer($9DD277AF), Integer($04DB2615), Integer($73DC1683), Integer($E3630B12), Integer($94643B84), Integer($0D6D6A3E), Integer($7A6A5AA8), Integer($E40ECF0B), Integer($9309FF9D), Integer($0A00AE27), Integer($7D079EB1), Integer($F00F9344), Integer($8708A3D2), Integer($1E01F268), Integer($6906C2FE), Integer($F762575D), Integer($806567CB), Integer($196C3671), Integer($6E6B06E7), Integer($FED41B76), Integer($89D32BE0), Integer($10DA7A5A), Integer($67DD4ACC), Integer($F9B9DF6F), Integer($8EBEEFF9), Integer($17B7BE43), Integer($60B08ED5), Integer($D6D6A3E8), Integer($A1D1937E), Integer($38D8C2C4), Integer($4FDFF252), Integer($D1BB67F1), Integer($A6BC5767), Integer($3FB506DD), Integer($48B2364B), Integer($D80D2BDA), Integer($AF0A1B4C), Integer($36034AF6), Integer($41047A60), Integer($DF60EFC3), Integer($A867DF55), Integer($316E8EEF), Integer($4669BE79), Integer($CB61B38C), Integer($BC66831A), Integer($256FD2A0), Integer($5268E236), Integer($CC0C7795), Integer($BB0B4703), Integer($220216B9), Integer($5505262F), Integer($C5BA3BBE), Integer($B2BD0B28), Integer($2BB45A92), Integer($5CB36A04), Integer($C2D7FFA7), Integer($B5D0CF31), Integer($2CD99E8B), Integer($5BDEAE1D), Integer($9B64C2B0), Integer($EC63F226), Integer($756AA39C), Integer($026D930A), Integer($9C0906A9), Integer($EB0E363F), Integer($72076785), Integer($05005713), Integer($95BF4A82), Integer($E2B87A14), Integer($7BB12BAE), Integer($0CB61B38), Integer($92D28E9B), Integer($E5D5BE0D), Integer($7CDCEFB7), Integer($0BDBDF21), Integer($86D3D2D4), Integer($F1D4E242), Integer($68DDB3F8), Integer($1FDA836E), Integer($81BE16CD), Integer($F6B9265B), Integer($6FB077E1), Integer($18B74777), Integer($88085AE6), Integer($FF0F6A70), Integer($66063BCA), Integer($11010B5C), Integer($8F659EFF), Integer($F862AE69), Integer($616BFFD3), Integer($166CCF45), Integer($A00AE278), Integer($D70DD2EE), Integer($4E048354), Integer($3903B3C2), Integer($A7672661), Integer($D06016F7), Integer($4969474D), Integer($3E6E77DB), Integer($AED16A4A), Integer($D9D65ADC), Integer($40DF0B66), Integer($37D83BF0), Integer($A9BCAE53), Integer($DEBB9EC5), Integer($47B2CF7F), Integer($30B5FFE9), Integer($BDBDF21C), Integer($CABAC28A), Integer($53B39330), Integer($24B4A3A6), Integer($BAD03605), Integer($CDD70693), Integer($54DE5729), Integer($23D967BF), Integer($B3667A2E), Integer($C4614AB8), Integer($5D681B02), Integer($2A6F2B94), Integer($B40BBE37), Integer($C30C8EA1), Integer($5A05DF1B), Integer($2D02EF8D) ); Crc16Tab: array[0..255] of Word = ( $0000, $1189, $2312, $329B, $4624, $57AD, $6536, $74BF, $8C48, $9DC1, $AF5A, $BED3, $CA6C, $DBE5, $E97E, $F8F7, $1081, $0108, $3393, $221A, $56A5, $472C, $75B7, $643E, $9CC9, $8D40, $BFDB, $AE52, $DAED, $CB64, $F9FF, $E876, $2102, $308B, $0210, $1399, $6726, $76AF, $4434, $55BD, $AD4A, $BCC3, $8E58, $9FD1, $EB6E, $FAE7, $C87C, $D9F5, $3183, $200A, $1291, $0318, $77A7, $662E, $54B5, $453C, $BDCB, $AC42, $9ED9, $8F50, $FBEF, $EA66, $D8FD, $C974, $4204, $538D, $6116, $709F, $0420, $15A9, $2732, $36BB, $CE4C, $DFC5, $ED5E, $FCD7, $8868, $99E1, $AB7A, $BAF3, $5285, $430C, $7197, $601E, $14A1, $0528, $37B3, $263A, $DECD, $CF44, $FDDF, $EC56, $98E9, $8960, $BBFB, $AA72, $6306, $728F, $4014, $519D, $2522, $34AB, $0630, $17B9, $EF4E, $FEC7, $CC5C, $DDD5, $A96A, $B8E3, $8A78, $9BF1, $7387, $620E, $5095, $411C, $35A3, $242A, $16B1, $0738, $FFCF, $EE46, $DCDD, $CD54, $B9EB, $A862, $9AF9, $8B70, $8408, $9581, $A71A, $B693, $C22C, $D3A5, $E13E, $F0B7, $0840, $19C9, $2B52, $3ADB, $4E64, $5FED, $6D76, $7CFF, $9489, $8500, $B79B, $A612, $D2AD, $C324, $F1BF, $E036, $18C1, $0948, $3BD3, $2A5A, $5EE5, $4F6C, $7DF7, $6C7E, $A50A, $B483, $8618, $9791, $E32E, $F2A7, $C03C, $D1B5, $2942, $38CB, $0A50, $1BD9, $6F66, $7EEF, $4C74, $5DFD, $B58B, $A402, $9699, $8710, $F3AF, $E226, $D0BD, $C134, $39C3, $284A, $1AD1, $0B58, $7FE7, $6E6E, $5CF5, $4D7C, $C60C, $D785, $E51E, $F497, $8028, $91A1, $A33A, $B2B3, $4A44, $5BCD, $6956, $78DF, $0C60, $1DE9, $2F72, $3EFB, $D68D, $C704, $F59F, $E416, $90A9, $8120, $B3BB, $A232, $5AC5, $4B4C, $79D7, $685E, $1CE1, $0D68, $3FF3, $2E7A, $E70E, $F687, $C41C, $D595, $A12A, $B0A3, $8238, $93B1, $6B46, $7ACF, $4854, $59DD, $2D62, $3CEB, $0E70, $1FF9, $F78F, $E606, $D49D, $C514, $B1AB, $A022, $92B9, $8330, $7BC7, $6A4E, $58D5, $495C, $3DE3, $2C6A, $1EF1, $0F78 ); procedure ArrByteToLong(var ArByte: Array of byte; var ArLong: Array of Integer); {$IFDEF SYNACODE_NATIVE} var n: integer; {$ENDIF} begin if (High(ArByte) + 1) > ((High(ArLong) + 1) * 4) then Exit; {$IFDEF SYNACODE_NATIVE} for n := 0 to ((high(ArByte) + 1) div 4) - 1 do ArLong[n] := ArByte[n * 4 + 0] + (ArByte[n * 4 + 1] shl 8) + (ArByte[n * 4 + 2] shl 16) + (ArByte[n * 4 + 3] shl 24); {$ELSE} Move(ArByte[0], ArLong[0], High(ArByte) + 1); {$ENDIF} end; procedure ArrLongToByte(var ArLong: Array of Integer; var ArByte: Array of byte); {$IFDEF SYNACODE_NATIVE} var n: integer; {$ENDIF} begin if (High(ArByte) + 1) < ((High(ArLong) + 1) * 4) then Exit; {$IFDEF SYNACODE_NATIVE} for n := 0 to high(ArLong) do begin ArByte[n * 4 + 0] := ArLong[n] and $000000FF; ArByte[n * 4 + 1] := (ArLong[n] shr 8) and $000000FF; ArByte[n * 4 + 2] := (ArLong[n] shr 16) and $000000FF; ArByte[n * 4 + 3] := (ArLong[n] shr 24) and $000000FF; end; {$ELSE} Move(ArLong[0], ArByte[0], High(ArByte) + 1); {$ENDIF} end; type TMDCtx = record State: array[0..3] of Integer; Count: array[0..1] of Integer; BufAnsiChar: array[0..63] of Byte; BufLong: array[0..15] of Integer; end; TSHA1Ctx= record Hi, Lo: integer; Buffer: array[0..63] of byte; Index: integer; Hash: array[0..4] of Integer; HashByte: array[0..19] of byte; end; TMDTransform = procedure(var Buf: array of LongInt; const Data: array of LongInt); {==============================================================================} function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; var x, l, lv: Integer; c: AnsiChar; b: Byte; bad: Boolean; begin lv := Length(Value); SetLength(Result, lv); x := 1; l := 1; while x <= lv do begin c := Value[x]; Inc(x); if c <> Delimiter then begin Result[l] := c; Inc(l); end else if x < lv then begin Case Value[x] Of #13: if (Value[x + 1] = #10) then Inc(x, 2) else Inc(x); #10: if (Value[x + 1] = #13) then Inc(x, 2) else Inc(x); else begin bad := False; Case Value[x] Of '0'..'9': b := (Byte(Value[x]) - 48) Shl 4; 'a'..'f', 'A'..'F': b := ((Byte(Value[x]) And 7) + 9) shl 4; else begin b := 0; bad := True; end; end; Case Value[x + 1] Of '0'..'9': b := b Or (Byte(Value[x + 1]) - 48); 'a'..'f', 'A'..'F': b := b Or ((Byte(Value[x + 1]) And 7) + 9); else bad := True; end; if bad then begin Result[l] := c; Inc(l); end else begin Inc(x, 2); Result[l] := AnsiChar(b); Inc(l); end; end; end; end else break; end; Dec(l); SetLength(Result, l); end; {==============================================================================} function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; begin Result := DecodeTriplet(Value, '='); end; {==============================================================================} function DecodeURL(const Value: AnsiString): AnsiString; begin Result := DecodeTriplet(Value, '%'); end; {==============================================================================} function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; Specials: TSpecials): AnsiString; var n, l: Integer; s: AnsiString; c: AnsiChar; begin SetLength(Result, Length(Value) * 3); l := 1; for n := 1 to Length(Value) do begin c := Value[n]; if c in Specials then begin Result[l] := Delimiter; Inc(l); s := IntToHex(Ord(c), 2); Result[l] := s[1]; Inc(l); Result[l] := s[2]; Inc(l); end else begin Result[l] := c; Inc(l); end; end; Dec(l); SetLength(Result, l); end; {==============================================================================} function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; begin Result := EncodeTriplet(Value, '=', ['='] + NonAsciiChar); end; {==============================================================================} function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; begin Result := EncodeTriplet(Value, '=', SpecialChar + NonAsciiChar); end; {==============================================================================} function EncodeURLElement(const Value: AnsiString): AnsiString; begin Result := EncodeTriplet(Value, '%', URLSpecialChar + URLFullSpecialChar); end; {==============================================================================} function EncodeURL(const Value: AnsiString): AnsiString; begin Result := EncodeTriplet(Value, '%', URLSpecialChar); end; {==============================================================================} function Decode4to3(const Value, Table: AnsiString): AnsiString; var x, y, n, l: Integer; d: array[0..3] of Byte; begin SetLength(Result, Length(Value)); x := 1; l := 1; while x <= Length(Value) do begin for n := 0 to 3 do begin if x > Length(Value) then d[n] := 64 else begin y := Pos(Value[x], Table); if y < 1 then y := 1; d[n] := y - 1; end; Inc(x); end; Result[l] := AnsiChar((D[0] and $3F) shl 2 + (D[1] and $30) shr 4); Inc(l); if d[2] <> 64 then begin Result[l] := AnsiChar((D[1] and $0F) shl 4 + (D[2] and $3C) shr 2); Inc(l); if d[3] <> 64 then begin Result[l] := AnsiChar((D[2] and $03) shl 6 + (D[3] and $3F)); Inc(l); end; end; end; Dec(l); SetLength(Result, l); end; {==============================================================================} function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; var x, y, lv: Integer; d: integer; dl: integer; c: byte; p: integer; begin lv := Length(Value); SetLength(Result, lv); x := 1; dl := 4; d := 0; p := 1; while x <= lv do begin y := Ord(Value[x]); if y in [33..127] then c := Ord(Table[y - 32]) else c := 64; Inc(x); if c > 63 then continue; d := (d shl 6) or c; dec(dl); if dl <> 0 then continue; Result[p] := AnsiChar((d shr 16) and $ff); inc(p); Result[p] := AnsiChar((d shr 8) and $ff); inc(p); Result[p] := AnsiChar(d and $ff); inc(p); d := 0; dl := 4; end; case dl of 1: begin d := d shr 2; Result[p] := AnsiChar((d shr 8) and $ff); inc(p); Result[p] := AnsiChar(d and $ff); inc(p); end; 2: begin d := d shr 4; Result[p] := AnsiChar(d and $ff); inc(p); end; end; SetLength(Result, p - 1); end; {==============================================================================} function Encode3to4(const Value, Table: AnsiString): AnsiString; var c: Byte; n, l: Integer; Count: Integer; DOut: array[0..3] of Byte; begin setlength(Result, ((Length(Value) + 2) div 3) * 4); l := 1; Count := 1; while Count <= Length(Value) do begin c := Ord(Value[Count]); Inc(Count); DOut[0] := (c and $FC) shr 2; DOut[1] := (c and $03) shl 4; if Count <= Length(Value) then begin c := Ord(Value[Count]); Inc(Count); DOut[1] := DOut[1] + (c and $F0) shr 4; DOut[2] := (c and $0F) shl 2; if Count <= Length(Value) then begin c := Ord(Value[Count]); Inc(Count); DOut[2] := DOut[2] + (c and $C0) shr 6; DOut[3] := (c and $3F); end else begin DOut[3] := $40; end; end else begin DOut[2] := $40; DOut[3] := $40; end; for n := 0 to 3 do begin if (DOut[n] + 1) <= Length(Table) then begin Result[l] := Table[DOut[n] + 1]; Inc(l); end; end; end; SetLength(Result, l - 1); end; {==============================================================================} function DecodeBase64(const Value: AnsiString): AnsiString; begin Result := Decode4to3Ex(Value, ReTableBase64); end; {==============================================================================} function EncodeBase64(const Value: AnsiString): AnsiString; begin Result := Encode3to4(Value, TableBase64); end; {==============================================================================} function DecodeBase64mod(const Value: AnsiString): AnsiString; begin Result := Decode4to3(Value, TableBase64mod); end; {==============================================================================} function EncodeBase64mod(const Value: AnsiString): AnsiString; begin Result := Encode3to4(Value, TableBase64mod); end; {==============================================================================} function DecodeUU(const Value: AnsiString): AnsiString; var s: AnsiString; uut: AnsiString; x: Integer; begin Result := ''; uut := TableUU; s := trim(UpperCase(Value)); if s = '' then Exit; if Pos('BEGIN', s) = 1 then Exit; if Pos('END', s) = 1 then Exit; if Pos('TABLE', s) = 1 then Exit; //ignore Table yet (set custom UUT) //begin decoding x := Pos(Value[1], uut) - 1; case (x mod 3) of 0: x :=(x div 3)* 4; 1: x :=((x div 3) * 4) + 2; 2: x :=((x div 3) * 4) + 3; end; //x - lenght UU line s := Copy(Value, 2, x); if s = '' then Exit; s := s + StringOfChar(' ', x - length(s)); Result := Decode4to3(s, uut); end; {==============================================================================} function EncodeUU(const Value: AnsiString): AnsiString; begin Result := ''; if Length(Value) < Length(TableUU) then Result := TableUU[Length(Value) + 1] + Encode3to4(Value, TableUU); end; {==============================================================================} function DecodeXX(const Value: AnsiString): AnsiString; var s: AnsiString; x: Integer; begin Result := ''; s := trim(UpperCase(Value)); if s = '' then Exit; if Pos('BEGIN', s) = 1 then Exit; if Pos('END', s) = 1 then Exit; //begin decoding x := Pos(Value[1], TableXX) - 1; case (x mod 3) of 0: x :=(x div 3)* 4; 1: x :=((x div 3) * 4) + 2; 2: x :=((x div 3) * 4) + 3; end; //x - lenght XX line s := Copy(Value, 2, x); if s = '' then Exit; s := s + StringOfChar(' ', x - length(s)); Result := Decode4to3(s, TableXX); end; {==============================================================================} function DecodeYEnc(const Value: AnsiString): AnsiString; var C : Byte; i: integer; begin Result := ''; i := 1; while i <= Length(Value) do begin c := Ord(Value[i]); Inc(i); if c = Ord('=') then begin c := Ord(Value[i]); Inc(i); Dec(c, 64); end; Dec(C, 42); Result := Result + AnsiChar(C); end; end; {==============================================================================} function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; begin Result := (Crc32 shr 8) xor crc32tab[Byte(Value xor (Crc32 and Integer($000000FF)))]; end; {==============================================================================} function Crc32(const Value: AnsiString): Integer; var n: Integer; begin Result := Integer($FFFFFFFF); for n := 1 to Length(Value) do Result := UpdateCrc32(Ord(Value[n]), Result); Result := not Result; end; {==============================================================================} function UpdateCrc16(Value: Byte; Crc16: Word): Word; begin Result := ((Crc16 shr 8) and $00FF) xor crc16tab[Byte(Crc16 xor (Word(Value)) and $00FF)]; end; {==============================================================================} function Crc16(const Value: AnsiString): Word; var n: Integer; begin Result := $FFFF; for n := 1 to Length(Value) do Result := UpdateCrc16(Ord(Value[n]), Result); end; {==============================================================================} procedure MDInit(var MDContext: TMDCtx); var n: integer; begin MDContext.Count[0] := 0; MDContext.Count[1] := 0; for n := 0 to high(MDContext.BufAnsiChar) do MDContext.BufAnsiChar[n] := 0; for n := 0 to high(MDContext.BufLong) do MDContext.BufLong[n] := 0; MDContext.State[0] := Integer($67452301); MDContext.State[1] := Integer($EFCDAB89); MDContext.State[2] := Integer($98BADCFE); MDContext.State[3] := Integer($10325476); end; procedure MD5Transform(var Buf: array of LongInt; const Data: array of LongInt); var A, B, C, D: LongInt; procedure Round1(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); begin Inc(W, (Z xor (X and (Y xor Z))) + Data); W := (W shl S) or (W shr (32 - S)); Inc(W, X); end; procedure Round2(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); begin Inc(W, (Y xor (Z and (X xor Y))) + Data); W := (W shl S) or (W shr (32 - S)); Inc(W, X); end; procedure Round3(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); begin Inc(W, (X xor Y xor Z) + Data); W := (W shl S) or (W shr (32 - S)); Inc(W, X); end; procedure Round4(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); begin Inc(W, (Y xor (X or not Z)) + Data); W := (W shl S) or (W shr (32 - S)); Inc(W, X); end; begin A := Buf[0]; B := Buf[1]; C := Buf[2]; D := Buf[3]; Round1(A, B, C, D, Data[0] + Longint($D76AA478), 7); Round1(D, A, B, C, Data[1] + Longint($E8C7B756), 12); Round1(C, D, A, B, Data[2] + Longint($242070DB), 17); Round1(B, C, D, A, Data[3] + Longint($C1BDCEEE), 22); Round1(A, B, C, D, Data[4] + Longint($F57C0FAF), 7); Round1(D, A, B, C, Data[5] + Longint($4787C62A), 12); Round1(C, D, A, B, Data[6] + Longint($A8304613), 17); Round1(B, C, D, A, Data[7] + Longint($FD469501), 22); Round1(A, B, C, D, Data[8] + Longint($698098D8), 7); Round1(D, A, B, C, Data[9] + Longint($8B44F7AF), 12); Round1(C, D, A, B, Data[10] + Longint($FFFF5BB1), 17); Round1(B, C, D, A, Data[11] + Longint($895CD7BE), 22); Round1(A, B, C, D, Data[12] + Longint($6B901122), 7); Round1(D, A, B, C, Data[13] + Longint($FD987193), 12); Round1(C, D, A, B, Data[14] + Longint($A679438E), 17); Round1(B, C, D, A, Data[15] + Longint($49B40821), 22); Round2(A, B, C, D, Data[1] + Longint($F61E2562), 5); Round2(D, A, B, C, Data[6] + Longint($C040B340), 9); Round2(C, D, A, B, Data[11] + Longint($265E5A51), 14); Round2(B, C, D, A, Data[0] + Longint($E9B6C7AA), 20); Round2(A, B, C, D, Data[5] + Longint($D62F105D), 5); Round2(D, A, B, C, Data[10] + Longint($02441453), 9); Round2(C, D, A, B, Data[15] + Longint($D8A1E681), 14); Round2(B, C, D, A, Data[4] + Longint($E7D3FBC8), 20); Round2(A, B, C, D, Data[9] + Longint($21E1CDE6), 5); Round2(D, A, B, C, Data[14] + Longint($C33707D6), 9); Round2(C, D, A, B, Data[3] + Longint($F4D50D87), 14); Round2(B, C, D, A, Data[8] + Longint($455A14ED), 20); Round2(A, B, C, D, Data[13] + Longint($A9E3E905), 5); Round2(D, A, B, C, Data[2] + Longint($FCEFA3F8), 9); Round2(C, D, A, B, Data[7] + Longint($676F02D9), 14); Round2(B, C, D, A, Data[12] + Longint($8D2A4C8A), 20); Round3(A, B, C, D, Data[5] + Longint($FFFA3942), 4); Round3(D, A, B, C, Data[8] + Longint($8771F681), 11); Round3(C, D, A, B, Data[11] + Longint($6D9D6122), 16); Round3(B, C, D, A, Data[14] + Longint($FDE5380C), 23); Round3(A, B, C, D, Data[1] + Longint($A4BEEA44), 4); Round3(D, A, B, C, Data[4] + Longint($4BDECFA9), 11); Round3(C, D, A, B, Data[7] + Longint($F6BB4B60), 16); Round3(B, C, D, A, Data[10] + Longint($BEBFBC70), 23); Round3(A, B, C, D, Data[13] + Longint($289B7EC6), 4); Round3(D, A, B, C, Data[0] + Longint($EAA127FA), 11); Round3(C, D, A, B, Data[3] + Longint($D4EF3085), 16); Round3(B, C, D, A, Data[6] + Longint($04881D05), 23); Round3(A, B, C, D, Data[9] + Longint($D9D4D039), 4); Round3(D, A, B, C, Data[12] + Longint($E6DB99E5), 11); Round3(C, D, A, B, Data[15] + Longint($1FA27CF8), 16); Round3(B, C, D, A, Data[2] + Longint($C4AC5665), 23); Round4(A, B, C, D, Data[0] + Longint($F4292244), 6); Round4(D, A, B, C, Data[7] + Longint($432AFF97), 10); Round4(C, D, A, B, Data[14] + Longint($AB9423A7), 15); Round4(B, C, D, A, Data[5] + Longint($FC93A039), 21); Round4(A, B, C, D, Data[12] + Longint($655B59C3), 6); Round4(D, A, B, C, Data[3] + Longint($8F0CCC92), 10); Round4(C, D, A, B, Data[10] + Longint($FFEFF47D), 15); Round4(B, C, D, A, Data[1] + Longint($85845DD1), 21); Round4(A, B, C, D, Data[8] + Longint($6FA87E4F), 6); Round4(D, A, B, C, Data[15] + Longint($FE2CE6E0), 10); Round4(C, D, A, B, Data[6] + Longint($A3014314), 15); Round4(B, C, D, A, Data[13] + Longint($4E0811A1), 21); Round4(A, B, C, D, Data[4] + Longint($F7537E82), 6); Round4(D, A, B, C, Data[11] + Longint($BD3AF235), 10); Round4(C, D, A, B, Data[2] + Longint($2AD7D2BB), 15); Round4(B, C, D, A, Data[9] + Longint($EB86D391), 21); Inc(Buf[0], A); Inc(Buf[1], B); Inc(Buf[2], C); Inc(Buf[3], D); end; //fixed by James McAdams procedure MDUpdate(var MDContext: TMDCtx; const Data: AnsiString; transform: TMDTransform); var Index, partLen, InputLen, I: integer; {$IFDEF SYNACODE_NATIVE} n: integer; {$ENDIF} begin InputLen := Length(Data); with MDContext do begin Index := (Count[0] shr 3) and $3F; Inc(Count[0], InputLen shl 3); if Count[0] < (InputLen shl 3) then Inc(Count[1]); Inc(Count[1], InputLen shr 29); partLen := 64 - Index; if InputLen >= partLen then begin ArrLongToByte(BufLong, BufAnsiChar); {$IFDEF SYNACODE_NATIVE} for n := 1 to partLen do BufAnsiChar[index - 1 + n] := Ord(Data[n]); {$ELSE} Move(Data[1], BufAnsiChar[Index], partLen); {$ENDIF} ArrByteToLong(BufAnsiChar, BufLong); Transform(State, Buflong); I := partLen; while I + 63 < InputLen do begin ArrLongToByte(BufLong, BufAnsiChar); {$IFDEF SYNACODE_NATIVE} for n := 1 to 64 do BufAnsiChar[n - 1] := Ord(Data[i + n]); {$ELSE} Move(Data[I+1], BufAnsiChar, 64); {$ENDIF} ArrByteToLong(BufAnsiChar, BufLong); Transform(State, Buflong); inc(I, 64); end; Index := 0; end else I := 0; ArrLongToByte(BufLong, BufAnsiChar); {$IFDEF SYNACODE_NATIVE} for n := 1 to InputLen-I do BufAnsiChar[Index + n - 1] := Ord(Data[i + n]); {$ELSE} Move(Data[I+1], BufAnsiChar[Index], InputLen-I); {$ENDIF} ArrByteToLong(BufAnsiChar, BufLong); end end; function MDFinal(var MDContext: TMDCtx; transform: TMDTransform): AnsiString; var Cnt: Word; P: Byte; digest: array[0..15] of Byte; i: Integer; n: integer; begin for I := 0 to 15 do Digest[I] := I + 1; with MDContext do begin Cnt := (Count[0] shr 3) and $3F; P := Cnt; BufAnsiChar[P] := $80; Inc(P); Cnt := 64 - 1 - Cnt; if Cnt < 8 then begin for n := 0 to cnt - 1 do BufAnsiChar[P + n] := 0; ArrByteToLong(BufAnsiChar, BufLong); // FillChar(BufAnsiChar[P], Cnt, #0); Transform(State, BufLong); ArrLongToByte(BufLong, BufAnsiChar); for n := 0 to 55 do BufAnsiChar[n] := 0; ArrByteToLong(BufAnsiChar, BufLong); // FillChar(BufAnsiChar, 56, #0); end else begin for n := 0 to Cnt - 8 - 1 do BufAnsiChar[p + n] := 0; ArrByteToLong(BufAnsiChar, BufLong); // FillChar(BufAnsiChar[P], Cnt - 8, #0); end; BufLong[14] := Count[0]; BufLong[15] := Count[1]; Transform(State, BufLong); ArrLongToByte(State, Digest); // Move(State, Digest, 16); Result := ''; for i := 0 to 15 do Result := Result + AnsiChar(digest[i]); end; // FillChar(MD5Context, SizeOf(TMD5Ctx), #0) end; {==============================================================================} function MD5(const Value: AnsiString): AnsiString; var MDContext: TMDCtx; begin MDInit(MDContext); MDUpdate(MDContext, Value, @MD5Transform); Result := MDFinal(MDContext, @MD5Transform); end; {==============================================================================} function HMAC_MD5(Text, Key: AnsiString): AnsiString; var ipad, opad, s: AnsiString; n: Integer; MDContext: TMDCtx; begin if Length(Key) > 64 then Key := md5(Key); ipad := StringOfChar(#$36, 64); opad := StringOfChar(#$5C, 64); for n := 1 to Length(Key) do begin ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); end; MDInit(MDContext); MDUpdate(MDContext, ipad, @MD5Transform); MDUpdate(MDContext, Text, @MD5Transform); s := MDFinal(MDContext, @MD5Transform); MDInit(MDContext); MDUpdate(MDContext, opad, @MD5Transform); MDUpdate(MDContext, s, @MD5Transform); Result := MDFinal(MDContext, @MD5Transform); end; {==============================================================================} function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; var cnt, rest: integer; l: integer; n: integer; MDContext: TMDCtx; begin l := length(Value); cnt := Len div l; rest := Len mod l; MDInit(MDContext); for n := 1 to cnt do MDUpdate(MDContext, Value, @MD5Transform); if rest > 0 then MDUpdate(MDContext, Copy(Value, 1, rest), @MD5Transform); Result := MDFinal(MDContext, @MD5Transform); end; {==============================================================================} // SHA1 is based on sources by Dave Barton (davebarton@bigfoot.com) procedure SHA1init( var SHA1Context: TSHA1Ctx ); var n: integer; begin SHA1Context.Hi := 0; SHA1Context.Lo := 0; SHA1Context.Index := 0; for n := 0 to High(SHA1Context.Buffer) do SHA1Context.Buffer[n] := 0; for n := 0 to High(SHA1Context.HashByte) do SHA1Context.HashByte[n] := 0; // FillChar(SHA1Context, SizeOf(TSHA1Ctx), #0); SHA1Context.Hash[0] := integer($67452301); SHA1Context.Hash[1] := integer($EFCDAB89); SHA1Context.Hash[2] := integer($98BADCFE); SHA1Context.Hash[3] := integer($10325476); SHA1Context.Hash[4] := integer($C3D2E1F0); end; //****************************************************************************** function RB(A: integer): integer; begin Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); end; procedure SHA1Compress(var Data: TSHA1Ctx); var A, B, C, D, E, T: integer; W: array[0..79] of integer; i: integer; n: integer; function F1(x, y, z: integer): integer; begin Result := z xor (x and (y xor z)); end; function F2(x, y, z: integer): integer; begin Result := x xor y xor z; end; function F3(x, y, z: integer): integer; begin Result := (x and y) or (z and (x or y)); end; function LRot32(X: integer; c: integer): integer; begin result := (x shl c) or (x shr (32 - c)); end; begin ArrByteToLong(Data.Buffer, W); // Move(Data.Buffer, W, Sizeof(Data.Buffer)); for i := 0 to 15 do W[i] := RB(W[i]); for i := 16 to 79 do W[i] := LRot32(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16], 1); A := Data.Hash[0]; B := Data.Hash[1]; C := Data.Hash[2]; D := Data.Hash[3]; E := Data.Hash[4]; for i := 0 to 19 do begin T := LRot32(A, 5) + F1(B, C, D) + E + W[i] + integer($5A827999); E := D; D := C; C := LRot32(B, 30); B := A; A := T; end; for i := 20 to 39 do begin T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($6ED9EBA1); E := D; D := C; C := LRot32(B, 30); B := A; A := T; end; for i := 40 to 59 do begin T := LRot32(A, 5) + F3(B, C, D) + E + W[i] + integer($8F1BBCDC); E := D; D := C; C := LRot32(B, 30); B := A; A := T; end; for i := 60 to 79 do begin T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($CA62C1D6); E := D; D := C; C := LRot32(B, 30); B := A; A := T; end; Data.Hash[0] := Data.Hash[0] + A; Data.Hash[1] := Data.Hash[1] + B; Data.Hash[2] := Data.Hash[2] + C; Data.Hash[3] := Data.Hash[3] + D; Data.Hash[4] := Data.Hash[4] + E; for n := 0 to high(w) do w[n] := 0; // FillChar(W, Sizeof(W), 0); for n := 0 to high(Data.Buffer) do Data.Buffer[n] := 0; // FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); end; //****************************************************************************** procedure SHA1Update(var Context: TSHA1Ctx; const Data: AnsiString); var Len: integer; n: integer; i, k: integer; begin Len := Length(data); for k := 0 to 7 do begin i := Context.Lo; Inc(Context.Lo, Len); if Context.Lo < i then Inc(Context.Hi); end; for n := 1 to len do begin Context.Buffer[Context.Index] := byte(Data[n]); Inc(Context.Index); if Context.Index = 64 then begin Context.Index := 0; SHA1Compress(Context); end; end; end; //****************************************************************************** function SHA1Final(var Context: TSHA1Ctx): AnsiString; type Pinteger = ^integer; var i: integer; procedure ItoArr(var Ar: Array of byte; I, value: Integer); begin Ar[i + 0] := Value and $000000FF; Ar[i + 1] := (Value shr 8) and $000000FF; Ar[i + 2] := (Value shr 16) and $000000FF; Ar[i + 3] := (Value shr 24) and $000000FF; end; begin Context.Buffer[Context.Index] := $80; if Context.Index >= 56 then SHA1Compress(Context); ItoArr(Context.Buffer, 56, RB(Context.Hi)); ItoArr(Context.Buffer, 60, RB(Context.Lo)); // Pinteger(@Context.Buffer[56])^ := RB(Context.Hi); // Pinteger(@Context.Buffer[60])^ := RB(Context.Lo); SHA1Compress(Context); Context.Hash[0] := RB(Context.Hash[0]); Context.Hash[1] := RB(Context.Hash[1]); Context.Hash[2] := RB(Context.Hash[2]); Context.Hash[3] := RB(Context.Hash[3]); Context.Hash[4] := RB(Context.Hash[4]); ArrLongToByte(Context.Hash, Context.HashByte); Result := ''; for i := 0 to 19 do Result := Result + AnsiChar(Context.HashByte[i]); end; function SHA1(const Value: AnsiString): AnsiString; var SHA1Context: TSHA1Ctx; begin SHA1Init(SHA1Context); SHA1Update(SHA1Context, Value); Result := SHA1Final(SHA1Context); end; {==============================================================================} function HMAC_SHA1(Text, Key: AnsiString): AnsiString; var ipad, opad, s: AnsiString; n: Integer; SHA1Context: TSHA1Ctx; begin if Length(Key) > 64 then Key := SHA1(Key); ipad := StringOfChar(#$36, 64); opad := StringOfChar(#$5C, 64); for n := 1 to Length(Key) do begin ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); end; SHA1Init(SHA1Context); SHA1Update(SHA1Context, ipad); SHA1Update(SHA1Context, Text); s := SHA1Final(SHA1Context); SHA1Init(SHA1Context); SHA1Update(SHA1Context, opad); SHA1Update(SHA1Context, s); Result := SHA1Final(SHA1Context); end; {==============================================================================} function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; var cnt, rest: integer; l: integer; n: integer; SHA1Context: TSHA1Ctx; begin l := length(Value); cnt := Len div l; rest := Len mod l; SHA1Init(SHA1Context); for n := 1 to cnt do SHA1Update(SHA1Context, Value); if rest > 0 then SHA1Update(SHA1Context, Copy(Value, 1, rest)); Result := SHA1Final(SHA1Context); end; {==============================================================================} procedure MD4Transform(var Buf: array of LongInt; const Data: array of LongInt); var A, B, C, D: LongInt; function LRot32(a, b: longint): longint; begin Result:= (a shl b) or (a shr (32 - b)); end; begin A := Buf[0]; B := Buf[1]; C := Buf[2]; D := Buf[3]; A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 0], 3); D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 1], 7); C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 2], 11); B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 3], 19); A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 4], 3); D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 5], 7); C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 6], 11); B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 7], 19); A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 8], 3); D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 9], 7); C:= LRot32(C + (B xor (D and (A xor B))) + Data[10], 11); B:= LRot32(B + (A xor (C and (D xor A))) + Data[11], 19); A:= LRot32(A + (D xor (B and (C xor D))) + Data[12], 3); D:= LRot32(D + (C xor (A and (B xor C))) + Data[13], 7); C:= LRot32(C + (B xor (D and (A xor B))) + Data[14], 11); B:= LRot32(B + (A xor (C and (D xor A))) + Data[15], 19); A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 0] + longint($5a827999), 3); D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 4] + longint($5a827999), 5); C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 8] + longint($5a827999), 9); B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[12] + longint($5a827999), 13); A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 1] + longint($5a827999), 3); D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 5] + longint($5a827999), 5); C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 9] + longint($5a827999), 9); B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[13] + longint($5a827999), 13); A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 2] + longint($5a827999), 3); D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 6] + longint($5a827999), 5); C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[10] + longint($5a827999), 9); B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[14] + longint($5a827999), 13); A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 3] + longint($5a827999), 3); D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 7] + longint($5a827999), 5); C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[11] + longint($5a827999), 9); B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[15] + longint($5a827999), 13); A:= LRot32(A + (B xor C xor D) + Data[ 0] + longint($6ed9eba1), 3); D:= LRot32(D + (A xor B xor C) + Data[ 8] + longint($6ed9eba1), 9); C:= LRot32(C + (D xor A xor B) + Data[ 4] + longint($6ed9eba1), 11); B:= LRot32(B + (C xor D xor A) + Data[12] + longint($6ed9eba1), 15); A:= LRot32(A + (B xor C xor D) + Data[ 2] + longint($6ed9eba1), 3); D:= LRot32(D + (A xor B xor C) + Data[10] + longint($6ed9eba1), 9); C:= LRot32(C + (D xor A xor B) + Data[ 6] + longint($6ed9eba1), 11); B:= LRot32(B + (C xor D xor A) + Data[14] + longint($6ed9eba1), 15); A:= LRot32(A + (B xor C xor D) + Data[ 1] + longint($6ed9eba1), 3); D:= LRot32(D + (A xor B xor C) + Data[ 9] + longint($6ed9eba1), 9); C:= LRot32(C + (D xor A xor B) + Data[ 5] + longint($6ed9eba1), 11); B:= LRot32(B + (C xor D xor A) + Data[13] + longint($6ed9eba1), 15); A:= LRot32(A + (B xor C xor D) + Data[ 3] + longint($6ed9eba1), 3); D:= LRot32(D + (A xor B xor C) + Data[11] + longint($6ed9eba1), 9); C:= LRot32(C + (D xor A xor B) + Data[ 7] + longint($6ed9eba1), 11); B:= LRot32(B + (C xor D xor A) + Data[15] + longint($6ed9eba1), 15); Inc(Buf[0], A); Inc(Buf[1], B); Inc(Buf[2], C); Inc(Buf[3], D); end; {==============================================================================} function MD4(const Value: AnsiString): AnsiString; var MDContext: TMDCtx; begin MDInit(MDContext); MDUpdate(MDContext, Value, @MD4Transform); Result := MDFinal(MDContext, @MD4Transform); end; {==============================================================================} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/synafpc.pas������������������������������������������������0000644�0001750�0000144�00000012523�14743153644�021521� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.003.001 | |==============================================================================| | Content: Utils for FreePascal compatibility | |==============================================================================| | Copyright (c)1999-2013, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2003-2013. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | | Tomas Hajny (OS2 support) | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@exclude} {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$H+} //old Delphi does not have MSWINDOWS define. {$IFDEF WIN32} {$IFNDEF MSWINDOWS} {$DEFINE MSWINDOWS} {$ENDIF} {$ENDIF} unit synafpc; interface uses {$IFDEF FPC} dynlibs, sysutils; {$ELSE} {$IFDEF MSWINDOWS} Windows; {$ELSE} SysUtils; {$ENDIF} {$ENDIF} {$IFDEF FPC} type TLibHandle = dynlibs.TLibHandle; function LoadLibrary(ModuleName: PChar): TLibHandle; function FreeLibrary(Module: TLibHandle): LongBool; function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; {$ELSE} //not FPC type {$IFDEF CIL} TLibHandle = Integer; PtrInt = Integer; {$ELSE} TLibHandle = HModule; {$IFDEF WIN64} PtrInt = NativeInt; {$ELSE} PtrInt = Integer; {$ENDIF} {$ENDIF} {$IFDEF VER100} LongWord = DWord; {$ENDIF} {$ENDIF} procedure Sleep(milliseconds: Cardinal); implementation {==============================================================================} {$IFDEF FPC} function LoadLibrary(ModuleName: PChar): TLibHandle; begin Result := dynlibs.LoadLibrary(Modulename); end; function FreeLibrary(Module: TLibHandle): LongBool; begin Result := dynlibs.UnloadLibrary(Module); end; function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; begin {$IFDEF OS2GCC} Result := dynlibs.GetProcedureAddress(Module, '_' + Proc); {$ELSE OS2GCC} Result := dynlibs.GetProcedureAddress(Module, Proc); {$ENDIF OS2GCC} end; function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; begin Result := 0; end; {$ELSE} {$ENDIF} procedure Sleep(milliseconds: Cardinal); begin {$IFDEF MSWINDOWS} {$IFDEF FPC} sysutils.sleep(milliseconds); {$ELSE} windows.sleep(milliseconds); {$ENDIF} {$ELSE} sysutils.sleep(milliseconds); {$ENDIF} end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/synaip.pas�������������������������������������������������0000644�0001750�0000144�00000027177�14743153644�021374� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 001.002.001 | |==============================================================================| | Content: IP address support procedures and functions | |==============================================================================| | Copyright (c)2006-2010, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c) 2006-2010. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@abstract(IP adress support procedures and functions)} {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$Q-} {$R-} {$H+} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$WARN SUSPICIOUS_TYPECAST OFF} {$ENDIF} unit synaip; interface uses SysUtils, SynaUtil; type {:binary form of IPv6 adress (for string conversion routines)} TIp6Bytes = array [0..15] of Byte; {:binary form of IPv6 adress (for string conversion routines)} TIp6Words = array [0..7] of Word; {:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!} function IsIP(const Value: string): Boolean; {:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!} function IsIP6(const Value: string): Boolean; {:Returns a string with the "Host" ip address converted to binary form.} function IPToID(Host: string): Ansistring; {:Convert IPv6 address from their string form to binary byte array.} function StrToIp6(value: string): TIp6Bytes; {:Convert IPv6 address from binary byte array to string form.} function Ip6ToStr(value: TIp6Bytes): string; {:Convert IPv4 address from their string form to binary.} function StrToIp(value: string): integer; {:Convert IPv4 address from binary to string form.} function IpToStr(value: integer): string; {:Convert IPv4 address to reverse form.} function ReverseIP(Value: AnsiString): AnsiString; {:Convert IPv6 address to reverse form.} function ReverseIP6(Value: AnsiString): AnsiString; {:Expand short form of IPv6 address to long form.} function ExpandIP6(Value: AnsiString): AnsiString; implementation {==============================================================================} function IsIP(const Value: string): Boolean; var TempIP: string; function ByteIsOk(const Value: string): Boolean; var x, n: integer; begin x := StrToIntDef(Value, -1); Result := (x >= 0) and (x < 256); // X may be in correct range, but value still may not be correct value! // i.e. "$80" if Result then for n := 1 to length(Value) do if not (AnsiChar(Value[n]) in ['0'..'9']) then begin Result := False; Break; end; end; begin TempIP := Value; Result := False; if not ByteIsOk(Fetch(TempIP, '.')) then Exit; if not ByteIsOk(Fetch(TempIP, '.')) then Exit; if not ByteIsOk(Fetch(TempIP, '.')) then Exit; if ByteIsOk(TempIP) then Result := True; end; {==============================================================================} function IsIP6(const Value: string): Boolean; var TempIP: string; s,t: string; x: integer; partcount: integer; zerocount: integer; First: Boolean; begin TempIP := Value; Result := False; if Value = '::' then begin Result := True; Exit; end; partcount := 0; zerocount := 0; First := True; while tempIP <> '' do begin s := fetch(TempIP, ':'); if not(First) and (s = '') then Inc(zerocount); First := False; if zerocount > 1 then break; Inc(partCount); if s = '' then Continue; if partCount > 8 then break; if tempIP = '' then begin t := SeparateRight(s, '%'); s := SeparateLeft(s, '%'); x := StrToIntDef('$' + t, -1); if (x < 0) or (x > $ffff) then break; end; x := StrToIntDef('$' + s, -1); if (x < 0) or (x > $ffff) then break; if tempIP = '' then if not((PartCount = 1) and (ZeroCount = 0)) then Result := True; end; end; {==============================================================================} function IPToID(Host: string): Ansistring; var s: string; i, x: Integer; begin Result := ''; for x := 0 to 3 do begin s := Fetch(Host, '.'); i := StrToIntDef(s, 0); Result := Result + AnsiChar(i); end; end; {==============================================================================} function StrToIp(value: string): integer; var s: string; i, x: Integer; begin Result := 0; for x := 0 to 3 do begin s := Fetch(value, '.'); i := StrToIntDef(s, 0); Result := (256 * Result) + i; end; end; {==============================================================================} function IpToStr(value: integer): string; var x1, x2: word; y1, y2: byte; begin Result := ''; x1 := value shr 16; x2 := value and $FFFF; y1 := x1 div $100; y2 := x1 mod $100; Result := inttostr(y1) + '.' + inttostr(y2) + '.'; y1 := x2 div $100; y2 := x2 mod $100; Result := Result + inttostr(y1) + '.' + inttostr(y2); end; {==============================================================================} function ExpandIP6(Value: AnsiString): AnsiString; var n: integer; s: ansistring; x: integer; begin Result := ''; if value = '' then exit; x := countofchar(value, ':'); if x > 7 then exit; if value[1] = ':' then value := '0' + value; if value[length(value)] = ':' then value := value + '0'; x := 8 - x; s := ''; for n := 1 to x do s := s + ':0'; s := s + ':'; Result := replacestring(value, '::', s); end; {==============================================================================} function StrToIp6(Value: string): TIp6Bytes; var IPv6: TIp6Words; Index: Integer; n: integer; b1, b2: byte; s: string; x: integer; begin for n := 0 to 15 do Result[n] := 0; for n := 0 to 7 do Ipv6[n] := 0; Index := 0; Value := ExpandIP6(value); if value = '' then exit; while Value <> '' do begin if Index > 7 then Exit; s := fetch(value, ':'); if s = '@' then break; if s = '' then begin IPv6[Index] := 0; end else begin x := StrToIntDef('$' + s, -1); if (x > 65535) or (x < 0) then Exit; IPv6[Index] := x; end; Inc(Index); end; for n := 0 to 7 do begin b1 := ipv6[n] div 256; b2 := ipv6[n] mod 256; Result[n * 2] := b1; Result[(n * 2) + 1] := b2; end; end; {==============================================================================} //based on routine by the Free Pascal development team function Ip6ToStr(value: TIp6Bytes): string; var i, x: byte; zr1,zr2: set of byte; zc1,zc2: byte; have_skipped: boolean; ip6w: TIp6words; begin zr1 := []; zr2 := []; zc1 := 0; zc2 := 0; for i := 0 to 7 do begin x := i * 2; ip6w[i] := value[x] * 256 + value[x + 1]; if ip6w[i] = 0 then begin include(zr2, i); inc(zc2); end else begin if zc1 < zc2 then begin zc1 := zc2; zr1 := zr2; zc2 := 0; zr2 := []; end; end; end; if zc1 < zc2 then begin zr1 := zr2; end; SetLength(Result, 8*5-1); SetLength(Result, 0); have_skipped := false; for i := 0 to 7 do begin if not(i in zr1) then begin if have_skipped then begin if Result = '' then Result := '::' else Result := Result + ':'; have_skipped := false; end; Result := Result + IntToHex(Ip6w[i], 1) + ':'; end else begin have_skipped := true; end; end; if have_skipped then if Result = '' then Result := '::0' else Result := Result + ':'; if Result = '' then Result := '::0'; if not (7 in zr1) then SetLength(Result, Length(Result)-1); Result := LowerCase(result); end; {==============================================================================} function ReverseIP(Value: AnsiString): AnsiString; var x: Integer; begin Result := ''; repeat x := LastDelimiter('.', Value); Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x); Delete(Value, x, Length(Value) - x + 1); until x < 1; if Length(Result) > 0 then if Result[1] = '.' then Delete(Result, 1, 1); end; {==============================================================================} function ReverseIP6(Value: AnsiString): AnsiString; var ip6: TIp6bytes; n: integer; x, y: integer; begin ip6 := StrToIP6(Value); x := ip6[15] div 16; y := ip6[15] mod 16; Result := IntToHex(y, 1) + '.' + IntToHex(x, 1); for n := 14 downto 0 do begin x := ip6[n] div 16; y := ip6[n] mod 16; Result := Result + '.' + IntToHex(y, 1) + '.' + IntToHex(x, 1); end; end; {==============================================================================} end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/ftp/synapse/synautil.pas�����������������������������������������������0000644�0001750�0000144�00000154000�14743153644�021723� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 004.015.000 | |==============================================================================| | Content: support procedures and functions | |==============================================================================| | Copyright (c)1999-2012, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c) 1999-2012. | | Portions created by Hernan Sanchez are Copyright (c) 2000. | | Portions created by Petr Fejfar are Copyright (c)2011-2012. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | | Hernan Sanchez (hernan.sanchez@iname.com) | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@abstract(Support procedures and functions)} {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$Q-} {$R-} {$H+} //old Delphi does not have MSWINDOWS define. {$IFDEF WIN32} {$IFNDEF MSWINDOWS} {$DEFINE MSWINDOWS} {$ENDIF} {$ENDIF} {$IFDEF UNICODE} {$WARN IMPLICIT_STRING_CAST OFF} {$WARN IMPLICIT_STRING_CAST_LOSS OFF} {$WARN SUSPICIOUS_TYPECAST OFF} {$ENDIF} unit synautil; interface uses {$IFDEF MSWINDOWS} Windows, {$ELSE} {$IFDEF FPC} UnixUtil, Unix, BaseUnix, {$ELSE} Libc, {$ENDIF} {$ENDIF} {$IFDEF CIL} System.IO, {$ENDIF} SysUtils, Classes, SynaFpc; {$IFDEF VER100} type int64 = integer; {$ENDIF} {:Return your timezone bias from UTC time in minutes.} function TimeZoneBias: integer; {:Return your timezone bias from UTC time in string representation like "+0200".} function TimeZone: string; {:Returns current time in format defined in RFC-822. Useful for SMTP messages, but other protocols use this time format as well. Results contains the timezone specification. Four digit year is used to break any Y2K concerns. (Example 'Fri, 15 Oct 1999 21:14:56 +0200')} function Rfc822DateTime(t: TDateTime): string; {:Returns date and time in format defined in C compilers in format "mmm dd hh:nn:ss"} function CDateTime(t: TDateTime): string; {:Returns date and time in format defined in format 'yymmdd hhnnss'} function SimpleDateTime(t: TDateTime): string; {:Returns date and time in format defined in ANSI C compilers in format "ddd mmm d hh:nn:ss yyyy" } function AnsiCDateTime(t: TDateTime): string; {:Decode three-letter string with name of month to their month number. If string not match any month name, then is returned 0. For parsing are used predefined names for English, French and German and names from system locale too.} function GetMonthNumber(Value: String): integer; {:Return decoded time from given string. Time must be witch separator ':'. You can use "hh:mm" or "hh:mm:ss".} function GetTimeFromStr(Value: string): TDateTime; {:Decode string in format "m-d-y" to TDateTime type.} function GetDateMDYFromStr(Value: string): TDateTime; {:Decode various string representations of date and time to Tdatetime type. This function do all timezone corrections too! This function can decode lot of formats like: @longcode(# ddd, d mmm yyyy hh:mm:ss ddd, d mmm yy hh:mm:ss ddd, mmm d yyyy hh:mm:ss ddd mmm dd hh:mm:ss yyyy #) and more with lot of modifications, include: @longcode(# Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format #) Timezone corrections known lot of symbolic timezone names (like CEST, EDT, etc.) or numeric representation (like +0200). By convention defined in RFC timezone +0000 is GMT and -0000 is current your system timezone.} function DecodeRfcDateTime(Value: string): TDateTime; {:Return current system date and time in UTC timezone.} function GetUTTime: TDateTime; {:Set Newdt as current system date and time in UTC timezone. This function work only if you have administrator rights!} function SetUTTime(Newdt: TDateTime): Boolean; {:Return current value of system timer with precizion 1 millisecond. Good for measure time difference.} function GetTick: LongWord; {:Return difference between two timestamps. It working fine only for differences smaller then maxint. (difference must be smaller then 24 days.)} function TickDelta(TickOld, TickNew: LongWord): LongWord; {:Return two characters, which ordinal values represents the value in byte format. (High-endian)} function CodeInt(Value: Word): Ansistring; {:Decodes two characters located at "Index" offset position of the "Value" string to Word values.} function DecodeInt(const Value: Ansistring; Index: Integer): Word; {:Return four characters, which ordinal values represents the value in byte format. (High-endian)} function CodeLongInt(Value: LongInt): Ansistring; {:Decodes four characters located at "Index" offset position of the "Value" string to LongInt values.} function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; {:Dump binary buffer stored in a string to a result string.} function DumpStr(const Buffer: Ansistring): string; {:Dump binary buffer stored in a string to a result string. All bytes with code of character is written as character, not as hexadecimal value.} function DumpExStr(const Buffer: Ansistring): string; {:Dump binary buffer stored in a string to a file with DumpFile filename.} procedure Dump(const Buffer: AnsiString; DumpFile: string); {:Dump binary buffer stored in a string to a file with DumpFile filename. All bytes with code of character is written as character, not as hexadecimal value.} procedure DumpEx(const Buffer: AnsiString; DumpFile: string); {:Like TrimLeft, but remove only spaces, not control characters!} function TrimSPLeft(const S: string): string; {:Like TrimRight, but remove only spaces, not control characters!} function TrimSPRight(const S: string): string; {:Like Trim, but remove only spaces, not control characters!} function TrimSP(const S: string): string; {:Returns a portion of the "Value" string located to the left of the "Delimiter" string. If a delimiter is not found, results is original string.} function SeparateLeft(const Value, Delimiter: string): string; {:Returns the portion of the "Value" string located to the right of the "Delimiter" string. If a delimiter is not found, results is original string.} function SeparateRight(const Value, Delimiter: string): string; {:Returns parameter value from string in format: parameter1="value1"; parameter2=value2} function GetParameter(const Value, Parameter: string): string; {:parse value string with elements differed by Delimiter into stringlist.} procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); {:parse value string with elements differed by ';' into stringlist.} procedure ParseParameters(Value: string; const Parameters: TStrings); {:Index of string in stringlist with same beginning as Value is returned.} function IndexByBegin(Value: string; const List: TStrings): integer; {:Returns only the e-mail portion of an address from the full address format. i.e. returns 'nobody@@somewhere.com' from '"someone" <nobody@@somewhere.com>'} function GetEmailAddr(const Value: string): string; {:Returns only the description part from a full address format. i.e. returns 'someone' from '"someone" <nobody@@somewhere.com>'} function GetEmailDesc(Value: string): string; {:Returns a string with hexadecimal digits representing the corresponding values of the bytes found in "Value" string.} function StrToHex(const Value: Ansistring): string; {:Returns a string of binary "Digits" representing "Value".} function IntToBin(Value: Integer; Digits: Byte): string; {:Returns an integer equivalent of the binary string in "Value". (i.e. ('10001010') returns 138)} function BinToInt(const Value: string): Integer; {:Parses a URL to its various components.} function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, Para: string): string; {:Replaces all "Search" string values found within "Value" string, with the "Replace" string value.} function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; {:It is like RPos, but search is from specified possition.} function RPosEx(const Sub, Value: string; From: integer): Integer; {:It is like POS function, but from right side of Value string.} function RPos(const Sub, Value: String): Integer; {:Like @link(fetch), but working with binary strings, not with text.} function FetchBin(var Value: string; const Delimiter: string): string; {:Fetch string from left of Value string.} function Fetch(var Value: string; const Delimiter: string): string; {:Fetch string from left of Value string. This function ignore delimitesr inside quotations.} function FetchEx(var Value: string; const Delimiter, Quotation: string): string; {:If string is binary string (contains non-printable characters), then is returned true.} function IsBinaryString(const Value: AnsiString): Boolean; {:return position of string terminator in string. If terminator found, then is returned in terminator parameter. Possible line terminators are: CRLF, LFCR, CR, LF} function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; {:Delete empty strings from end of stringlist.} Procedure StringsTrim(const value: TStrings); {:Like Pos function, buf from given string possition.} function PosFrom(const SubStr, Value: String; From: integer): integer; {$IFNDEF CIL} {:Increase pointer by value.} function IncPoint(const p: pointer; Value: integer): pointer; {$ENDIF} {:Get string between PairBegin and PairEnd. This function respect nesting. For example: @longcode(# Value is: 'Hi! (hello(yes!))' pairbegin is: '(' pairend is: ')' In this case result is: 'hello(yes!)'#)} function GetBetween(const PairBegin, PairEnd, Value: string): string; {:Return count of Chr in Value string.} function CountOfChar(const Value: string; Chr: char): integer; {:Remove quotation from Value string. If Value is not quoted, then return same string without any modification. } function UnquoteStr(const Value: string; Quote: Char): string; {:Quote Value string. If Value contains some Quote chars, then it is doubled.} function QuoteStr(const Value: string; Quote: Char): string; {:Convert lines in stringlist from 'name: value' form to 'name=value' form.} procedure HeadersToList(const Value: TStrings); {:Convert lines in stringlist from 'name=value' form to 'name: value' form.} procedure ListToHeaders(const Value: TStrings); {:swap bytes in integer.} function SwapBytes(Value: integer): integer; {:read string with requested length form stream.} function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; {:write string to stream.} procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); {:Return filename of new temporary file in Dir (if empty, then default temporary directory is used) and with optional filename prefix.} function GetTempFile(const Dir, prefix: AnsiString): AnsiString; {:Return padded string. If length is greater, string is truncated. If length is smaller, string is padded by Pad character.} function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; {:XOR each byte in the strings} function XorString(Indata1, Indata2: AnsiString): AnsiString; {:Read header from "Value" stringlist beginning at "Index" position. If header is Splitted into multiple lines, then this procedure de-split it into one line.} function NormalizeHeader(Value: TStrings; var Index: Integer): string; {pf} {:Search for one of line terminators CR, LF or NUL. Return position of the line beginning and length of text.} procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); {:Skip both line terminators CR LF (if any). Move APtr position forward.} procedure SkipLineBreak(var APtr:PANSIChar; AEtx:PANSIChar); {:Skip all blank lines in a buffer starting at APtr and move APtr position forward.} procedure SkipNullLines (var APtr:PANSIChar; AEtx:PANSIChar); {:Copy all lines from a buffer starting at APtr to ALines until empty line or end of the buffer is reached. Move APtr position forward).} procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); {:Copy all lines from a buffer starting at APtr to ALines until ABoundary or end of the buffer is reached. Move APtr position forward).} procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); {:Search ABoundary in a buffer starting at APtr. Return beginning of the ABoundary. Move APtr forward behind a trailing CRLF if any).} function SearchForBoundary (var APtr:PANSIChar; AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; {:Compare a text at position ABOL with ABoundary and return position behind the match (including a trailing CRLF if any).} function MatchBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; {:Compare a text at position ABOL with ABoundary + the last boundary suffix and return position behind the match (including a trailing CRLF if any).} function MatchLastBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; {:Copy data from a buffer starting at position APtr and delimited by AEtx position into ANSIString.} function BuildStringFromBuffer (AStx,AEtx:PANSIChar): ANSIString; {/pf} var {:can be used for your own months strings for @link(getmonthnumber)} CustomMonthNames: array[1..12] of string; implementation {==============================================================================} const MyDayNames: array[1..7] of AnsiString = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); var MyMonthNames: array[0..6, 1..12] of String = ( ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //rewrited by system locales 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //English 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), ('jan', 'fv', 'mar', 'avr', 'mai', 'jun', //French 'jul', 'ao', 'sep', 'oct', 'nov', 'dc'), ('jan', 'fev', 'mar', 'avr', 'mai', 'jun', //French#2 'jul', 'aou', 'sep', 'oct', 'nov', 'dec'), ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', //German 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), ('Jan', 'Feb', 'Mr', 'Apr', 'Mai', 'Jun', //German#2 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), ('Led', 'no', 'Be', 'Dub', 'Kv', 'en', //Czech 'ec', 'Srp', 'Z', 'j', 'Lis', 'Pro') ); {==============================================================================} function TimeZoneBias: integer; {$IFNDEF MSWINDOWS} {$IFNDEF FPC} var t: TTime_T; UT: TUnixTime; begin __time(@T); localtime_r(@T, UT); Result := ut.__tm_gmtoff div 60; {$ELSE} begin Result := TZSeconds div 60; {$ENDIF} {$ELSE} var zoneinfo: TTimeZoneInformation; bias: Integer; begin case GetTimeZoneInformation(Zoneinfo) of 2: bias := zoneinfo.Bias + zoneinfo.DaylightBias; 1: bias := zoneinfo.Bias + zoneinfo.StandardBias; else bias := zoneinfo.Bias; end; Result := bias * (-1); {$ENDIF} end; {==============================================================================} function TimeZone: string; var bias: Integer; h, m: Integer; begin bias := TimeZoneBias; if bias >= 0 then Result := '+' else Result := '-'; bias := Abs(bias); h := bias div 60; m := bias mod 60; Result := Result + Format('%.2d%.2d', [h, m]); end; {==============================================================================} function Rfc822DateTime(t: TDateTime): string; var wYear, wMonth, wDay: word; begin DecodeDate(t, wYear, wMonth, wDay); Result := Format('%s, %d %s %s %s', [MyDayNames[DayOfWeek(t)], wDay, MyMonthNames[1, wMonth], FormatDateTime('yyyy hh":"nn":"ss', t), TimeZone]); end; {==============================================================================} function CDateTime(t: TDateTime): string; var wYear, wMonth, wDay: word; begin DecodeDate(t, wYear, wMonth, wDay); Result:= Format('%s %2d %s', [MyMonthNames[1, wMonth], wDay, FormatDateTime('hh":"nn":"ss', t)]); end; {==============================================================================} function SimpleDateTime(t: TDateTime): string; begin Result := FormatDateTime('yymmdd hhnnss', t); end; {==============================================================================} function AnsiCDateTime(t: TDateTime): string; var wYear, wMonth, wDay: word; begin DecodeDate(t, wYear, wMonth, wDay); Result := Format('%s %s %d %s', [MyDayNames[DayOfWeek(t)], MyMonthNames[1, wMonth], wDay, FormatDateTime('hh":"nn":"ss yyyy ', t)]); end; {==============================================================================} function DecodeTimeZone(Value: string; var Zone: integer): Boolean; var x: integer; zh, zm: integer; s: string; begin Result := false; s := Value; if (Pos('+', s) = 1) or (Pos('-',s) = 1) then begin if s = '-0000' then Zone := TimeZoneBias else if Length(s) > 4 then begin zh := StrToIntdef(s[2] + s[3], 0); zm := StrToIntdef(s[4] + s[5], 0); zone := zh * 60 + zm; if s[1] = '-' then zone := zone * (-1); end; Result := True; end else begin x := 32767; if s = 'NZDT' then x := 13; if s = 'IDLE' then x := 12; if s = 'NZST' then x := 12; if s = 'NZT' then x := 12; if s = 'EADT' then x := 11; if s = 'GST' then x := 10; if s = 'JST' then x := 9; if s = 'CCT' then x := 8; if s = 'WADT' then x := 8; if s = 'WAST' then x := 7; if s = 'ZP6' then x := 6; if s = 'ZP5' then x := 5; if s = 'ZP4' then x := 4; if s = 'BT' then x := 3; if s = 'EET' then x := 2; if s = 'MEST' then x := 2; if s = 'MESZ' then x := 2; if s = 'SST' then x := 2; if s = 'FST' then x := 2; if s = 'CEST' then x := 2; if s = 'CET' then x := 1; if s = 'FWT' then x := 1; if s = 'MET' then x := 1; if s = 'MEWT' then x := 1; if s = 'SWT' then x := 1; if s = 'UT' then x := 0; if s = 'UTC' then x := 0; if s = 'GMT' then x := 0; if s = 'WET' then x := 0; if s = 'WAT' then x := -1; if s = 'BST' then x := -1; if s = 'AT' then x := -2; if s = 'ADT' then x := -3; if s = 'AST' then x := -4; if s = 'EDT' then x := -4; if s = 'EST' then x := -5; if s = 'CDT' then x := -5; if s = 'CST' then x := -6; if s = 'MDT' then x := -6; if s = 'MST' then x := -7; if s = 'PDT' then x := -7; if s = 'PST' then x := -8; if s = 'YDT' then x := -8; if s = 'YST' then x := -9; if s = 'HDT' then x := -9; if s = 'AHST' then x := -10; if s = 'CAT' then x := -10; if s = 'HST' then x := -10; if s = 'EAST' then x := -10; if s = 'NT' then x := -11; if s = 'IDLW' then x := -12; if x <> 32767 then begin zone := x * 60; Result := True; end; end; end; {==============================================================================} function GetMonthNumber(Value: String): integer; var n: integer; function TestMonth(Value: String; Index: Integer): Boolean; var n: integer; begin Result := False; for n := 0 to 6 do if Value = AnsiUppercase(MyMonthNames[n, Index]) then begin Result := True; Break; end; end; begin Result := 0; Value := AnsiUppercase(Value); for n := 1 to 12 do if TestMonth(Value, n) or (Value = AnsiUppercase(CustomMonthNames[n])) then begin Result := n; Break; end; end; {==============================================================================} function GetTimeFromStr(Value: string): TDateTime; var x: integer; begin x := rpos(':', Value); if (x > 0) and ((Length(Value) - x) > 2) then Value := Copy(Value, 1, x + 2); Value := ReplaceString(Value, ':', TimeSeparator); Result := -1; try Result := StrToTime(Value); except on Exception do ; end; end; {==============================================================================} function GetDateMDYFromStr(Value: string): TDateTime; var wYear, wMonth, wDay: word; s: string; begin Result := 0; s := Fetch(Value, '-'); wMonth := StrToIntDef(s, 12); s := Fetch(Value, '-'); wDay := StrToIntDef(s, 30); wYear := StrToIntDef(Value, 1899); if wYear < 1000 then if (wYear > 99) then wYear := wYear + 1900 else if wYear > 50 then wYear := wYear + 1900 else wYear := wYear + 2000; try Result := EncodeDate(wYear, wMonth, wDay); except on Exception do ; end; end; {==============================================================================} function DecodeRfcDateTime(Value: string): TDateTime; var day, month, year: Word; zone: integer; x, y: integer; s: string; t: TDateTime; begin // ddd, d mmm yyyy hh:mm:ss // ddd, d mmm yy hh:mm:ss // ddd, mmm d yyyy hh:mm:ss // ddd mmm dd hh:mm:ss yyyy // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format Result := 0; if Value = '' then Exit; day := 0; month := 0; year := 0; zone := 0; Value := ReplaceString(Value, ' -', ' #'); Value := ReplaceString(Value, '-', ' '); Value := ReplaceString(Value, ' #', ' -'); while Value <> '' do begin s := Fetch(Value, ' '); s := uppercase(s); // timezone if DecodetimeZone(s, x) then begin zone := x; continue; end; x := StrToIntDef(s, 0); // day or year if x > 0 then if (x < 32) and (day = 0) then begin day := x; continue; end else begin if (year = 0) and ((month > 0) or (x > 12)) then begin year := x; if year < 32 then year := year + 2000; if year < 1000 then year := year + 1900; continue; end; end; // time if rpos(':', s) > Pos(':', s) then begin t := GetTimeFromStr(s); if t <> -1 then Result := t; continue; end; //timezone daylight saving time if s = 'DST' then begin zone := zone + 60; continue; end; // month y := GetMonthNumber(s); if (y > 0) and (month = 0) then month := y; end; if year = 0 then year := 1980; if month < 1 then month := 1; if month > 12 then month := 12; if day < 1 then day := 1; x := MonthDays[IsLeapYear(year), month]; if day > x then day := x; Result := Result + Encodedate(year, month, day); zone := zone - TimeZoneBias; x := zone div 1440; Result := Result - x; zone := zone mod 1440; t := EncodeTime(Abs(zone) div 60, Abs(zone) mod 60, 0, 0); if zone < 0 then t := 0 - t; Result := Result - t; end; {==============================================================================} function GetUTTime: TDateTime; {$IFDEF MSWINDOWS} {$IFNDEF FPC} var st: TSystemTime; begin GetSystemTime(st); result := SystemTimeToDateTime(st); {$ELSE} var st: SysUtils.TSystemTime; stw: Windows.TSystemTime; begin GetSystemTime(stw); st.Year := stw.wYear; st.Month := stw.wMonth; st.Day := stw.wDay; st.Hour := stw.wHour; st.Minute := stw.wMinute; st.Second := stw.wSecond; st.Millisecond := stw.wMilliseconds; result := SystemTimeToDateTime(st); {$ENDIF} {$ELSE} {$IFNDEF FPC} var TV: TTimeVal; begin gettimeofday(TV, nil); Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; {$ELSE} var TV: TimeVal; begin fpgettimeofday(@TV, nil); Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; {$ENDIF} {$ENDIF} end; {==============================================================================} function SetUTTime(Newdt: TDateTime): Boolean; {$IFDEF MSWINDOWS} {$IFNDEF FPC} var st: TSystemTime; begin DateTimeToSystemTime(newdt,st); Result := SetSystemTime(st); {$ELSE} var st: SysUtils.TSystemTime; stw: Windows.TSystemTime; begin DateTimeToSystemTime(newdt,st); stw.wYear := st.Year; stw.wMonth := st.Month; stw.wDay := st.Day; stw.wHour := st.Hour; stw.wMinute := st.Minute; stw.wSecond := st.Second; stw.wMilliseconds := st.Millisecond; Result := SetSystemTime(stw); {$ENDIF} {$ELSE} {$IFNDEF FPC} var TV: TTimeVal; d: double; TZ: Ttimezone; PZ: PTimeZone; begin TZ.tz_minuteswest := 0; TZ.tz_dsttime := 0; PZ := @TZ; gettimeofday(TV, PZ); d := (newdt - UnixDateDelta) * 86400; TV.tv_sec := trunc(d); TV.tv_usec := trunc(frac(d) * 1000000); Result := settimeofday(TV, TZ) <> -1; {$ELSE} var TV: TimeVal; d: double; begin d := (newdt - UnixDateDelta) * 86400; TV.tv_sec := trunc(d); TV.tv_usec := trunc(frac(d) * 1000000); Result := fpsettimeofday(@TV, nil) <> -1; {$ENDIF} {$ENDIF} end; {==============================================================================} {$IFNDEF MSWINDOWS} function GetTick: LongWord; var Stamp: TTimeStamp; begin Stamp := DateTimeToTimeStamp(Now); Result := Stamp.Time; end; {$ELSE} function GetTick: LongWord; var tick, freq: TLargeInteger; {$IFDEF VER100} x: TLargeInteger; {$ENDIF} begin if Windows.QueryPerformanceFrequency(freq) then begin Windows.QueryPerformanceCounter(tick); {$IFDEF VER100} x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000; Result := x.LowPart; {$ELSE} Result := Trunc((tick / freq) * 1000) and High(LongWord) {$ENDIF} end else Result := Windows.GetTickCount; end; {$ENDIF} {==============================================================================} function TickDelta(TickOld, TickNew: LongWord): LongWord; begin //if DWord is signed type (older Deplhi), // then it not work properly on differencies larger then maxint! Result := 0; if TickOld <> TickNew then begin if TickNew < TickOld then begin TickNew := TickNew + LongWord(MaxInt) + 1; TickOld := TickOld + LongWord(MaxInt) + 1; end; Result := TickNew - TickOld; if TickNew < TickOld then if Result > 0 then Result := 0 - Result; end; end; {==============================================================================} function CodeInt(Value: Word): Ansistring; begin setlength(result, 2); result[1] := AnsiChar(Value div 256); result[2] := AnsiChar(Value mod 256); // Result := AnsiChar(Value div 256) + AnsiChar(Value mod 256) end; {==============================================================================} function DecodeInt(const Value: Ansistring; Index: Integer): Word; var x, y: Byte; begin if Length(Value) > Index then x := Ord(Value[Index]) else x := 0; if Length(Value) >= (Index + 1) then y := Ord(Value[Index + 1]) else y := 0; Result := x * 256 + y; end; {==============================================================================} function CodeLongInt(Value: Longint): Ansistring; var x, y: word; begin // this is fix for negative numbers on systems where longint = integer x := (Value shr 16) and integer($ffff); y := Value and integer($ffff); setlength(result, 4); result[1] := AnsiChar(x div 256); result[2] := AnsiChar(x mod 256); result[3] := AnsiChar(y div 256); result[4] := AnsiChar(y mod 256); end; {==============================================================================} function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; var x, y: Byte; xl, yl: Byte; begin if Length(Value) > Index then x := Ord(Value[Index]) else x := 0; if Length(Value) >= (Index + 1) then y := Ord(Value[Index + 1]) else y := 0; if Length(Value) >= (Index + 2) then xl := Ord(Value[Index + 2]) else xl := 0; if Length(Value) >= (Index + 3) then yl := Ord(Value[Index + 3]) else yl := 0; Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); end; {==============================================================================} function DumpStr(const Buffer: Ansistring): string; var n: Integer; begin Result := ''; for n := 1 to Length(Buffer) do Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); end; {==============================================================================} function DumpExStr(const Buffer: Ansistring): string; var n: Integer; x: Byte; begin Result := ''; for n := 1 to Length(Buffer) do begin x := Ord(Buffer[n]); if x in [65..90, 97..122] then Result := Result + ' +''' + char(x) + '''' else Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); end; end; {==============================================================================} procedure Dump(const Buffer: AnsiString; DumpFile: string); var f: Text; begin AssignFile(f, DumpFile); if FileExists(DumpFile) then DeleteFile(DumpFile); Rewrite(f); try Writeln(f, DumpStr(Buffer)); finally CloseFile(f); end; end; {==============================================================================} procedure DumpEx(const Buffer: AnsiString; DumpFile: string); var f: Text; begin AssignFile(f, DumpFile); if FileExists(DumpFile) then DeleteFile(DumpFile); Rewrite(f); try Writeln(f, DumpExStr(Buffer)); finally CloseFile(f); end; end; {==============================================================================} function TrimSPLeft(const S: string): string; var I, L: Integer; begin Result := ''; if S = '' then Exit; L := Length(S); I := 1; while (I <= L) and (S[I] = ' ') do Inc(I); Result := Copy(S, I, Maxint); end; {==============================================================================} function TrimSPRight(const S: string): string; var I: Integer; begin Result := ''; if S = '' then Exit; I := Length(S); while (I > 0) and (S[I] = ' ') do Dec(I); Result := Copy(S, 1, I); end; {==============================================================================} function TrimSP(const S: string): string; begin Result := TrimSPLeft(s); Result := TrimSPRight(Result); end; {==============================================================================} function SeparateLeft(const Value, Delimiter: string): string; var x: Integer; begin x := Pos(Delimiter, Value); if x < 1 then Result := Value else Result := Copy(Value, 1, x - 1); end; {==============================================================================} function SeparateRight(const Value, Delimiter: string): string; var x: Integer; begin x := Pos(Delimiter, Value); if x > 0 then x := x + Length(Delimiter) - 1; Result := Copy(Value, x + 1, Length(Value) - x); end; {==============================================================================} function GetParameter(const Value, Parameter: string): string; var s: string; v: string; begin Result := ''; v := Value; while v <> '' do begin s := Trim(FetchEx(v, ';', '"')); if Pos(Uppercase(parameter), Uppercase(s)) = 1 then begin Delete(s, 1, Length(Parameter)); s := Trim(s); if s = '' then Break; if s[1] = '=' then begin Result := Trim(SeparateRight(s, '=')); Result := UnquoteStr(Result, '"'); break; end; end; end; end; {==============================================================================} procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); var s: string; begin Parameters.Clear; while Value <> '' do begin s := Trim(FetchEx(Value, Delimiter, '"')); Parameters.Add(s); end; end; {==============================================================================} procedure ParseParameters(Value: string; const Parameters: TStrings); begin ParseParametersEx(Value, ';', Parameters); end; {==============================================================================} function IndexByBegin(Value: string; const List: TStrings): integer; var n: integer; s: string; begin Result := -1; Value := uppercase(Value); for n := 0 to List.Count -1 do begin s := UpperCase(List[n]); if Pos(Value, s) = 1 then begin Result := n; Break; end; end; end; {==============================================================================} function GetEmailAddr(const Value: string): string; var s: string; begin s := SeparateRight(Value, '<'); s := SeparateLeft(s, '>'); Result := Trim(s); end; {==============================================================================} function GetEmailDesc(Value: string): string; var s: string; begin Value := Trim(Value); s := SeparateRight(Value, '"'); if s <> Value then s := SeparateLeft(s, '"') else begin s := SeparateLeft(Value, '<'); if s = Value then begin s := SeparateRight(Value, '('); if s <> Value then s := SeparateLeft(s, ')') else s := ''; end; end; Result := Trim(s); end; {==============================================================================} function StrToHex(const Value: Ansistring): string; var n: Integer; begin Result := ''; for n := 1 to Length(Value) do Result := Result + IntToHex(Byte(Value[n]), 2); Result := LowerCase(Result); end; {==============================================================================} function IntToBin(Value: Integer; Digits: Byte): string; var x, y, n: Integer; begin Result := ''; x := Value; repeat y := x mod 2; x := x div 2; if y > 0 then Result := '1' + Result else Result := '0' + Result; until x = 0; x := Length(Result); for n := x to Digits - 1 do Result := '0' + Result; end; {==============================================================================} function BinToInt(const Value: string): Integer; var n: Integer; begin Result := 0; for n := 1 to Length(Value) do begin if Value[n] = '0' then Result := Result * 2 else if Value[n] = '1' then Result := Result * 2 + 1 else Break; end; end; {==============================================================================} function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, Para: string): string; var x, y: Integer; sURL: string; s: string; s1, s2: string; begin Prot := 'http'; User := ''; Pass := ''; Port := '80'; Para := ''; x := Pos('://', URL); if x > 0 then begin Prot := SeparateLeft(URL, '://'); sURL := SeparateRight(URL, '://'); end else sURL := URL; if UpperCase(Prot) = 'HTTPS' then Port := '443'; if UpperCase(Prot) = 'FTP' then Port := '21'; x := Pos('@', sURL); y := Pos('/', sURL); if (x > 0) and ((x < y) or (y < 1))then begin s := SeparateLeft(sURL, '@'); sURL := SeparateRight(sURL, '@'); x := Pos(':', s); if x > 0 then begin User := SeparateLeft(s, ':'); Pass := SeparateRight(s, ':'); end else User := s; end; x := Pos('/', sURL); if x > 0 then begin s1 := SeparateLeft(sURL, '/'); s2 := SeparateRight(sURL, '/'); end else begin s1 := sURL; s2 := ''; end; if Pos('[', s1) = 1 then begin Host := Separateleft(s1, ']'); Delete(Host, 1, 1); s1 := SeparateRight(s1, ']'); if Pos(':', s1) = 1 then Port := SeparateRight(s1, ':'); end else begin x := Pos(':', s1); if x > 0 then begin Host := SeparateLeft(s1, ':'); Port := SeparateRight(s1, ':'); end else Host := s1; end; Result := '/' + s2; x := Pos('?', s2); if x > 0 then begin Path := '/' + SeparateLeft(s2, '?'); Para := SeparateRight(s2, '?'); end else Path := '/' + s2; if Host = '' then Host := 'localhost'; end; {==============================================================================} function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; var x, l, ls, lr: Integer; begin if (Value = '') or (Search = '') then begin Result := Value; Exit; end; ls := Length(Search); lr := Length(Replace); Result := ''; x := Pos(Search, Value); while x > 0 do begin {$IFNDEF CIL} l := Length(Result); SetLength(Result, l + x - 1); Move(Pointer(Value)^, Pointer(@Result[l + 1])^, x - 1); {$ELSE} Result:=Result+Copy(Value,1,x-1); {$ENDIF} {$IFNDEF CIL} l := Length(Result); SetLength(Result, l + lr); Move(Pointer(Replace)^, Pointer(@Result[l + 1])^, lr); {$ELSE} Result:=Result+Replace; {$ENDIF} Delete(Value, 1, x - 1 + ls); x := Pos(Search, Value); end; Result := Result + Value; end; {==============================================================================} function RPosEx(const Sub, Value: string; From: integer): Integer; var n: Integer; l: Integer; begin result := 0; l := Length(Sub); for n := From - l + 1 downto 1 do begin if Copy(Value, n, l) = Sub then begin result := n; break; end; end; end; {==============================================================================} function RPos(const Sub, Value: String): Integer; begin Result := RPosEx(Sub, Value, Length(Value)); end; {==============================================================================} function FetchBin(var Value: string; const Delimiter: string): string; var s: string; begin Result := SeparateLeft(Value, Delimiter); s := SeparateRight(Value, Delimiter); if s = Value then Value := '' else Value := s; end; {==============================================================================} function Fetch(var Value: string; const Delimiter: string): string; begin Result := FetchBin(Value, Delimiter); Result := TrimSP(Result); Value := TrimSP(Value); end; {==============================================================================} function FetchEx(var Value: string; const Delimiter, Quotation: string): string; var b: Boolean; begin Result := ''; b := False; while Length(Value) > 0 do begin if b then begin if Pos(Quotation, Value) = 1 then b := False; Result := Result + Value[1]; Delete(Value, 1, 1); end else begin if Pos(Delimiter, Value) = 1 then begin Delete(Value, 1, Length(delimiter)); break; end; b := Pos(Quotation, Value) = 1; Result := Result + Value[1]; Delete(Value, 1, 1); end; end; end; {==============================================================================} function IsBinaryString(const Value: AnsiString): Boolean; var n: integer; begin Result := False; for n := 1 to Length(Value) do if Value[n] in [#0..#8, #10..#31] then //ignore null-terminated strings if not ((n = Length(value)) and (Value[n] = AnsiChar(#0))) then begin Result := True; Break; end; end; {==============================================================================} function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; var n, l: integer; begin Result := -1; Terminator := ''; l := length(value); for n := 1 to l do if value[n] in [#$0d, #$0a] then begin Result := n; Terminator := Value[n]; if n <> l then case value[n] of #$0d: if value[n + 1] = #$0a then Terminator := #$0d + #$0a; #$0a: if value[n + 1] = #$0d then Terminator := #$0a + #$0d; end; Break; end; end; {==============================================================================} Procedure StringsTrim(const Value: TStrings); var n: integer; begin for n := Value.Count - 1 downto 0 do if Value[n] = '' then Value.Delete(n) else Break; end; {==============================================================================} function PosFrom(const SubStr, Value: String; From: integer): integer; var ls,lv: integer; begin Result := 0; ls := Length(SubStr); lv := Length(Value); if (ls = 0) or (lv = 0) then Exit; if From < 1 then From := 1; while (ls + from - 1) <= (lv) do begin {$IFNDEF CIL} if CompareMem(@SubStr[1],@Value[from],ls) then {$ELSE} if SubStr = copy(Value, from, ls) then {$ENDIF} begin result := from; break; end else inc(from); end; end; {==============================================================================} {$IFNDEF CIL} function IncPoint(const p: pointer; Value: integer): pointer; begin Result := PAnsiChar(p) + Value; end; {$ENDIF} {==============================================================================} //improved by 'DoggyDawg' function GetBetween(const PairBegin, PairEnd, Value: string): string; var n: integer; x: integer; s: string; lenBegin: integer; lenEnd: integer; str: string; max: integer; begin lenBegin := Length(PairBegin); lenEnd := Length(PairEnd); n := Length(Value); if (Value = PairBegin + PairEnd) then begin Result := '';//nothing between exit; end; if (n < lenBegin + lenEnd) then begin Result := Value; exit; end; s := SeparateRight(Value, PairBegin); if (s = Value) then begin Result := Value; exit; end; n := Pos(PairEnd, s); if (n = 0) then begin Result := Value; exit; end; Result := ''; x := 1; max := Length(s) - lenEnd + 1; for n := 1 to max do begin str := copy(s, n, lenEnd); if (str = PairEnd) then begin Dec(x); if (x <= 0) then Break; end; str := copy(s, n, lenBegin); if (str = PairBegin) then Inc(x); Result := Result + s[n]; end; end; {==============================================================================} function CountOfChar(const Value: string; Chr: char): integer; var n: integer; begin Result := 0; for n := 1 to Length(Value) do if Value[n] = chr then Inc(Result); end; {==============================================================================} // ! do not use AnsiExtractQuotedStr, it's very buggy and can crash application! function UnquoteStr(const Value: string; Quote: Char): string; var n: integer; inq, dq: Boolean; c, cn: char; begin Result := ''; if Value = '' then Exit; if Value = Quote + Quote then Exit; inq := False; dq := False; for n := 1 to Length(Value) do begin c := Value[n]; if n <> Length(Value) then cn := Value[n + 1] else cn := #0; if c = quote then if dq then dq := False else if not inq then inq := True else if cn = quote then begin Result := Result + Quote; dq := True; end else inq := False else Result := Result + c; end; end; {==============================================================================} function QuoteStr(const Value: string; Quote: Char): string; var n: integer; begin Result := ''; for n := 1 to length(value) do begin Result := result + Value[n]; if value[n] = Quote then Result := Result + Quote; end; Result := Quote + Result + Quote; end; {==============================================================================} procedure HeadersToList(const Value: TStrings); var n, x, y: integer; s: string; begin for n := 0 to Value.Count -1 do begin s := Value[n]; x := Pos(':', s); if x > 0 then begin y:= Pos('=',s); if not ((y > 0) and (y < x)) then begin s[x] := '='; Value[n] := s; end; end; end; end; {==============================================================================} procedure ListToHeaders(const Value: TStrings); var n, x: integer; s: string; begin for n := 0 to Value.Count -1 do begin s := Value[n]; x := Pos('=', s); if x > 0 then begin s[x] := ':'; Value[n] := s; end; end; end; {==============================================================================} function SwapBytes(Value: integer): integer; var s: AnsiString; x, y, xl, yl: Byte; begin s := CodeLongInt(Value); x := Ord(s[4]); y := Ord(s[3]); xl := Ord(s[2]); yl := Ord(s[1]); Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); end; {==============================================================================} function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; var x: integer; {$IFDEF CIL} buf: Array of Byte; {$ENDIF} begin {$IFDEF CIL} Setlength(buf, Len); x := Stream.read(buf, Len); SetLength(buf, x); Result := StringOf(Buf); {$ELSE} Setlength(Result, Len); x := Stream.read(PAnsiChar(Result)^, Len); SetLength(Result, x); {$ENDIF} end; {==============================================================================} procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); {$IFDEF CIL} var buf: Array of Byte; {$ENDIF} begin {$IFDEF CIL} buf := BytesOf(Value); Stream.Write(buf,length(Value)); {$ELSE} Stream.Write(PAnsiChar(Value)^, Length(Value)); {$ENDIF} end; {==============================================================================} function GetTempFile(const Dir, prefix: AnsiString): AnsiString; {$IFNDEF FPC} {$IFDEF MSWINDOWS} var Path: AnsiString; x: integer; {$ENDIF} {$ENDIF} begin {$IFDEF FPC} Result := GetTempFileName(Dir, Prefix); {$ELSE} {$IFNDEF MSWINDOWS} Result := tempnam(Pointer(Dir), Pointer(prefix)); {$ELSE} {$IFDEF CIL} Result := System.IO.Path.GetTempFileName; {$ELSE} if Dir = '' then begin SetLength(Path, MAX_PATH); x := GetTempPath(Length(Path), PChar(Path)); SetLength(Path, x); end else Path := Dir; x := Length(Path); if Path[x] <> '\' then Path := Path + '\'; SetLength(Result, MAX_PATH + 1); GetTempFileName(PChar(Path), PChar(Prefix), 0, PChar(Result)); Result := PChar(Result); SetFileattributes(PChar(Result), GetFileAttributes(PChar(Result)) or FILE_ATTRIBUTE_TEMPORARY); {$ENDIF} {$ENDIF} {$ENDIF} end; {==============================================================================} function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; begin if length(value) >= len then Result := Copy(value, 1, len) else Result := Value + StringOfChar(Pad, len - length(value)); end; {==============================================================================} function XorString(Indata1, Indata2: AnsiString): AnsiString; var i: integer; begin Indata2 := PadString(Indata2, length(Indata1), #0); Result := ''; for i := 1 to length(Indata1) do Result := Result + AnsiChar(ord(Indata1[i]) xor ord(Indata2[i])); end; {==============================================================================} function NormalizeHeader(Value: TStrings; var Index: Integer): string; var s, t: string; n: Integer; begin s := Value[Index]; Inc(Index); if s <> '' then while (Value.Count - 1) > Index do begin t := Value[Index]; if t = '' then Break; for n := 1 to Length(t) do if t[n] = #9 then t[n] := ' '; if not(AnsiChar(t[1]) in [' ', '"', ':', '=']) then Break else begin s := s + ' ' + Trim(t); Inc(Index); end; end; Result := TrimRight(s); end; {==============================================================================} {pf} procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); begin ABol := APtr; while (APtr<AEtx) and not (APtr^ in [#0,#10,#13]) do inc(APtr); ALength := APtr-ABol; end; {/pf} {pf} procedure SkipLineBreak(var APtr:PANSIChar; AEtx:PANSIChar); begin if (APtr<AEtx) and (APtr^=#13) then inc(APtr); if (APtr<AEtx) and (APtr^=#10) then inc(APtr); end; {/pf} {pf} procedure SkipNullLines(var APtr:PANSIChar; AEtx:PANSIChar); var bol: PANSIChar; lng: integer; begin while (APtr<AEtx) do begin SearchForLineBreak(APtr,AEtx,bol,lng); SkipLineBreak(APtr,AEtx); if lng>0 then begin APtr := bol; Break; end; end; end; {/pf} {pf} procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); var bol: PANSIChar; lng: integer; s: ANSIString; begin // Copying until body separator will be reached while (APtr<AEtx) and (APtr^<>#0) do begin SearchForLineBreak(APtr,AEtx,bol,lng); SkipLineBreak(APtr,AEtx); if lng=0 then Break; SetString(s,bol,lng); ALines.Add(s); end; end; {/pf} {pf} procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); var bol: PANSIChar; lng: integer; s: ANSIString; BackStop: ANSIString; eob1: PANSIChar; eob2: PANSIChar; begin BackStop := '--'+ABoundary; eob2 := nil; // Copying until Boundary will be reached while (APtr<AEtx) do begin SearchForLineBreak(APtr,AEtx,bol,lng); SkipLineBreak(APtr,AEtx); eob1 := MatchBoundary(bol,APtr,ABoundary); if Assigned(eob1) then eob2 := MatchLastBoundary(bol,AEtx,ABoundary); if Assigned(eob2) then begin APtr := eob2; Break; end else if Assigned(eob1) then begin APtr := eob1; Break; end else begin SetString(s,bol,lng); ALines.Add(s); end; end; end; {/pf} {pf} function SearchForBoundary(var APtr:PANSIChar; AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; var eob: PANSIChar; Step: integer; begin Result := nil; // Moving Aptr position forward until boundary will be reached while (APtr<AEtx) do begin if strlcomp(APtr,#13#10'--',4)=0 then begin eob := MatchBoundary(APtr,AEtx,ABoundary); Step := 4; end else if strlcomp(APtr,'--',2)=0 then begin eob := MatchBoundary(APtr,AEtx,ABoundary); Step := 2; end else begin eob := nil; Step := 1; end; if Assigned(eob) then begin Result := APtr; // boundary beginning APtr := eob; // boundary end exit; end else inc(APtr,Step); end; end; {/pf} {pf} function MatchBoundary(ABol,AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; var MatchPos: PANSIChar; Lng: integer; begin Result := nil; MatchPos := ABol; Lng := length(ABoundary); if (MatchPos+2+Lng)>AETX then exit; if strlcomp(MatchPos,#13#10,2)=0 then inc(MatchPos,2); if (MatchPos+2+Lng)>AETX then exit; if strlcomp(MatchPos,'--',2)<>0 then exit; inc(MatchPos,2); if strlcomp(MatchPos,PANSIChar(ABoundary),Lng)<>0 then exit; inc(MatchPos,Lng); if ((MatchPos+2)<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then inc(MatchPos,2); Result := MatchPos; end; {/pf} {pf} function MatchLastBoundary(ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; var MatchPos: PANSIChar; begin Result := nil; MatchPos := MatchBoundary(ABOL,AETX,ABoundary); if not Assigned(MatchPos) then exit; if strlcomp(MatchPos,'--',2)<>0 then exit; inc(MatchPos,2); if (MatchPos+2<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then inc(MatchPos,2); Result := MatchPos; end; {/pf} {pf} function BuildStringFromBuffer(AStx,AEtx:PANSIChar): ANSIString; var lng: integer; begin Lng := 0; if Assigned(AStx) and Assigned(AEtx) then begin Lng := AEtx-AStx; if Lng<0 then Lng := 0; end; SetString(Result,AStx,lng); end; {/pf} {==============================================================================} var n: integer; begin for n := 1 to 12 do begin CustomMonthNames[n] := ShortMonthNames[n]; MyMonthNames[0, n] := ShortMonthNames[n]; end; end. doublecmd-1.1.22/plugins/wfx/ftp/synapse/synsock.pas������������������������������������������������0000644�0001750�0000144�00000010156�14743153644�021547� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{==============================================================================| | Project : Ararat Synapse | 005.002.003 | |==============================================================================| | Content: Socket Independent Platform Layer | |==============================================================================| | Copyright (c)1999-2013, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions are met: | | | | Redistributions of source code must retain the above copyright notice, this | | list of conditions and the following disclaimer. | | | | Redistributions in binary form must reproduce the above copyright notice, | | this list of conditions and the following disclaimer in the documentation | | and/or other materials provided with the distribution. | | | | Neither the name of Lukas Gebauer nor the names of its contributors may | | be used to endorse or promote products derived from this software without | | specific prior written permission. | | | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| | Portions created by Lukas Gebauer are Copyright (c)2001-2013. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | | Tomas Hajny (OS2 support) | |==============================================================================| | History: see HISTORY.HTM from distribution package | | (Found at URL: http://www.ararat.cz/synapse/) | |==============================================================================} {:@exclude} unit synsock; {$MINENUMSIZE 4} //old Delphi does not have MSWINDOWS define. {$IFDEF WIN32} {$IFNDEF MSWINDOWS} {$DEFINE MSWINDOWS} {$ENDIF} {$ENDIF} {$IFDEF CIL} {$I ssdotnet.inc} {$ELSE} {$IFDEF MSWINDOWS} {$I sswin32.inc} {$ELSE} {$IFDEF WINCE} {$I sswin32.inc} //not complete yet! {$ELSE} {$IFDEF FPC} {$IFDEF OS2} {$I ssos2ws1.inc} {$ELSE OS2} {$I ssfpc.inc} {$ENDIF OS2} {$ELSE} {$I sslinux.inc} {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} {$IFDEF POSIX} //Posix.SysSocket {$I ssposix.inc} //experimental! {$ENDIF} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/�����������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016156� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/COPYING.GPL.txt��������������������������������������������������0000644�0001750�0000144�00000043254�14743153644�020460� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/COPYING.LESSER.txt�����������������������������������������������0000644�0001750�0000144�00000063642�14743153644�021036� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! ����������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/src/�������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016745� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/src/libsmbclient.pas���������������������������������������������0000644�0001750�0000144�00000011511�14743153644�022120� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit libsmbclient; {$mode delphi} interface uses Classes, SysUtils, Unix, BaseUnix, UnixType; const SMBC_WORKGROUP = 1; SMBC_SERVER = 2; SMBC_FILE_SHARE = 3; SMBC_PRINTER_SHARE = 4; SMBC_COMMS_SHARE = 5; SMBC_IPC_SHARE = 6; SMBC_DIR = 7; SMBC_FILE = 8; SMBC_LINK = 9; const SMBC_DOS_MODE_READONLY = $01; SMBC_DOS_MODE_HIDDEN = $02; SMBC_DOS_MODE_SYSTEM = $04; SMBC_DOS_MODE_VOLUME_ID = $08; SMBC_DOS_MODE_DIRECTORY = $10; SMBC_DOS_MODE_ARCHIVE = $20; type (**@ingroup structure * Structure that represents a directory entry. * *) psmbc_dirent = ^smbc_dirent; smbc_dirent = record (** Type of entity. SMBC_WORKGROUP=1, SMBC_SERVER=2, SMBC_FILE_SHARE=3, SMBC_PRINTER_SHARE=4, SMBC_COMMS_SHARE=5, SMBC_IPC_SHARE=6, SMBC_DIR=7, SMBC_FILE=8, SMBC_LINK=9,*) smbc_type: LongWord; (** Length of this smbc_dirent in bytes *) dirlen: LongWord; (** The length of the comment string in bytes (does not include * null terminator) *) commentlen: LongWord; (** Points to the null terminated comment string *) comment: PAnsiChar; (** The length of the name string in bytes (does not include * null terminator) *) namelen: LongWord; (** Points to the null terminated name string *) name: array[0..0] of AnsiChar; end; smbc_get_auth_data_fn = procedure(server, share: PAnsiChar; wg: PAnsiChar; wglen: LongInt; un: PAnsiChar; unlen: LongInt; pw: PAnsiChar; pwlen: LongInt); cdecl; smbc_init_fn = function (fn: smbc_get_auth_data_fn; debug: LongInt): LongInt; cdecl; smbc_open_fn = function(furl: PAnsiChar; flags: LongInt; mode: mode_t): LongInt; cdecl; smbc_read_fn = function(fd: LongInt; buf: Pointer; bufsize: size_t): ssize_t; cdecl; smbc_write_fn = function(fd: LongInt; buf: Pointer; bufsize: size_t): ssize_t; cdecl; smbc_lseek_fn = function(fd: LongInt; offset: off_t; whence: LongInt): off_t; cdecl; smbc_close_fn = function(fd: LongInt): LongInt; cdecl; smbc_unlink_fn = function(furl: PAnsiChar): LongInt; cdecl; smbc_rename_fn = function(ourl: PAnsiChar; nurl: PAnsiChar): LongInt; cdecl; smbc_opendir_fn = function(durl: PAnsiChar): LongInt; cdecl; smbc_closedir_fn = function(dh: LongInt): LongInt; cdecl; smbc_readdir_fn = function(dh: LongInt): psmbc_dirent; cdecl; smbc_mkdir_fn = function(durl: PAnsiChar; mode: mode_t): LongInt; cdecl; smbc_rmdir_fn = function(durl: PAnsiChar): LongInt; cdecl; smbc_stat_fn = function(url: PAnsiChar; st: PStat): LongInt; cdecl; smbc_getxattr_fn = function(url, name: PAnsiChar; value: Pointer; size: size_t): LongInt; cdecl; smbc_setxattr_fn = function(url, name: PAnsiChar; value: Pointer; size: size_t; flags: LongInt): LongInt; cdecl; smbc_utimes_fn = function(url: PAnsiChar; tbuf: ptimeval): LongInt; cdecl; var smbc_init: smbc_init_fn; smbc_open: smbc_open_fn; smbc_read: smbc_read_fn; smbc_write: smbc_write_fn; smbc_lseek: smbc_lseek_fn; smbc_close: smbc_close_fn; smbc_unlink: smbc_unlink_fn; smbc_rename: smbc_rename_fn; smbc_opendir: smbc_opendir_fn; smbc_closedir: smbc_closedir_fn; smbc_readdir: smbc_readdir_fn; smbc_mkdir: smbc_mkdir_fn; smbc_rmdir: smbc_rmdir_fn; smbc_stat: smbc_stat_fn; smbc_getxattr: smbc_getxattr_fn; smbc_setxattr: smbc_setxattr_fn; smbc_utimes: smbc_utimes_fn; function LoadSambaLibrary: Boolean; implementation uses dynlibs; var hSamba: TLibHandle = 0; function LoadSambaLibrary: Boolean; begin if (hSamba = 0) then begin hSamba:= LoadLibrary('libsmbclient.so.0'); if (hSamba <> 0) then begin @smbc_init:= GetProcAddress(hSamba, 'smbc_init'); @smbc_opendir:= GetProcAddress(hSamba, 'smbc_opendir'); @smbc_readdir:= GetProcAddress(hSamba, 'smbc_readdir'); @smbc_closedir:= GetProcAddress(hSamba, 'smbc_closedir'); @smbc_mkdir:= GetProcAddress(hSamba, 'smbc_mkdir'); @smbc_rmdir:= GetProcAddress(hSamba, 'smbc_rmdir'); @smbc_open:= GetProcAddress(hSamba, 'smbc_open'); @smbc_read:= GetProcAddress(hSamba, 'smbc_read'); @smbc_write:= GetProcAddress(hSamba, 'smbc_write'); @smbc_lseek:= GetProcAddress(hSamba, 'smbc_lseek'); @smbc_close:= GetProcAddress(hSamba, 'smbc_close'); @smbc_unlink:= GetProcAddress(hSamba, 'smbc_unlink'); @smbc_rename:= GetProcAddress(hSamba, 'smbc_rename'); @smbc_stat:= GetProcAddress(hSamba, 'smbc_stat'); @smbc_getxattr:= GetProcAddress(hSamba, 'smbc_getxattr'); @smbc_setxattr:= GetProcAddress(hSamba, 'smbc_setxattr'); @smbc_utimes:= GetProcAddress(hSamba, 'smbc_utimes'); end; end; Result:= (hSamba <> 0); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/src/samba.lpi����������������������������������������������������0000644�0001750�0000144�00000010067�14743153644�020542� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="samba"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <i18n> <EnableI18N LFM="False"/> </i18n> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="2"/> <StringTable FileDescription="Samba WFX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2015 Alexander Koblov" ProductVersion=""/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../samba.wfx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <HostApplicationFilename Value="/usr/bin/doublecmd"/> </local> </RunParams> <Units Count="2"> <Unit0> <Filename Value="samba.lpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="smbauthdlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="DialogBox"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="SmbAuthDlg"/> </Unit1> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../samba.wfx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/src/samba.lpr����������������������������������������������������0000644�0001750�0000144�00000000536�14743153644�020553� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library samba; {$mode objfpc}{$H+} uses Classes, SmbFunc, SmbAuthDlg { you can add units after this }; exports FsInit, FsFindFirst, FsFindNext, FsFindClose, FsRenMovFile, FsGetFile, FsPutFile, FsDeleteFile, FsMkDir, FsRemoveDir, FsSetAttr, FsSetTime, FsGetDefRootName, ExtensionInitialize; {$R *.res} begin end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/samba/src/smbauthdlg.lfm�����������������������������������������������0000755�0001750�0000144�00000024744�14743153644�021615� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object DialogBox: TDialogBox Left = 369 Height = 185 Top = 214 Width = 354 AutoSize = True BorderStyle = bsDialog Caption = 'Authentication' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 185 ClientWidth = 354 OnShow = DialogBoxShow Position = poScreenCenter LCLVersion = '0.9.30' object lblUserName: TLabel AnchorSideLeft.Control = lblMessage AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrCenter Left = 66 Height = 18 Top = 54 Width = 69 Caption = 'User name:' ParentColor = False end object edtUserName: TEdit AnchorSideLeft.Control = lblUserName AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblMessage AnchorSideTop.Side = asrBottom Left = 153 Height = 27 Top = 50 Width = 200 BorderSpacing.Left = 18 BorderSpacing.Top = 24 TabOrder = 0 end object lblPassword: TLabel AnchorSideLeft.Control = lblMessage AnchorSideTop.Control = edtPassword AnchorSideTop.Side = asrCenter Left = 66 Height = 18 Top = 120 Width = 63 Caption = 'Password:' ParentColor = False end object edtPassword: TEdit AnchorSideLeft.Control = edtUserName AnchorSideTop.Control = edtDomain AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtUserName AnchorSideRight.Side = asrBottom Left = 153 Height = 27 Top = 116 Width = 200 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 EchoMode = emPassword PasswordChar = '*' TabOrder = 2 end object btnCancel: TBitBtn AnchorSideTop.Control = edtPassword AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtPassword AnchorSideRight.Side = asrBottom Left = 263 Height = 30 Top = 155 Width = 90 Anchors = [akTop, akRight] BorderSpacing.Top = 12 Cancel = True Caption = 'Cancel' Kind = bkCancel ModalResult = 2 OnClick = ButtonClick TabOrder = 4 end object btnOK: TBitBtn AnchorSideTop.Control = btnCancel AnchorSideRight.Control = btnCancel Left = 167 Height = 30 Top = 155 Width = 90 Anchors = [akTop, akRight] BorderSpacing.Right = 6 Caption = '&OK' Default = True Kind = bkOK ModalResult = 1 OnClick = ButtonClick TabOrder = 3 end object lblMessage: TLabel AnchorSideLeft.Control = imgAuth AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = imgAuth Left = 66 Height = 18 Top = 8 Width = 153 BorderSpacing.Left = 10 Caption = 'Password required for %s' ParentColor = False end object edtDomain: TEdit AnchorSideLeft.Control = edtUserName AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtPassword AnchorSideRight.Side = asrBottom Left = 153 Height = 27 Top = 83 Width = 200 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 1 end object lblDomain: TLabel AnchorSideLeft.Control = lblMessage AnchorSideTop.Control = edtDomain AnchorSideTop.Side = asrCenter Left = 66 Height = 18 Top = 87 Width = 52 Caption = 'Domain:' ParentColor = False end object imgAuth: TImage AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 8 Height = 48 Top = 8 Width = 48 AutoSize = True Picture.Data = { 1754506F727461626C654E6574776F726B477261706869639E0C000089504E47 0D0A1A0A0000000D49484452000000300000003008060000005702F987000000 017352474200AECE1CE900000006624B474400FF00FF00FFA0BDA79300000009 7048597300000DD700000DD70142289B780000000774494D4507DB080F071810 46DD836300000C1E4944415468DEED99696C5CD775C7FFF7BE75567286FB4E4A 946451FB92C892BA08B12CD5B69C1510827C285023C856A4881D470E69B4982F 7165C9551314719AB641F3A51FE43A4E1D25B2C5489614CB5A182D96646DDCB7 216786E4BCD9E76DF7DE7E9811CB2869E02816ED02BDC0C50CDE9CF3707FE79C 7BCEB97780FFE383FC6F3F9C3C79D2AF7AA4373CBAE7615DD36555D50A9515A1 F16231F72BCBB2DF4CA5B2C7366FDE5CF8C8029C38D57BA3BEB6BEABA9B119B2 A2429115A8AA0AC77190CEA45028E4529665FFB8E09A3F58BF727DFF470EA0F7 ADA37CD3BA8F93A9E94930E62210A8444B730B2CCB86AA2A2084229FCFC148CD 8942A1D06B99C57D9B363D7C6DB101E8EF2163966DC1B48A30D2C6778D64AA66 70F0CEA3F178F4603C3E356EA4E62049148D0DCDA4AEB661B7C7E7BBDC77F9C2 BF9EEC3B59FF9100101CE763F1289A1A9B0190AF1AC6CCEAAEAEB5C73B3B1FDA D7D27271492697FED4ECDCEC9BF1C4342714686FED901A6AEBBFE8A7DAC0E9B7 4FFEF5871E42478F1E0DCA3A195CD1B9A2C6A37B71EBF60DC7B2EDAFEFDAF9D8 0F17CADD18B8B18A30719052F258385405894A181D1F412693FE0FDBE45FDEBD 7B77FE43010080DEDE23CBA8A2FCAA6BC5AA7A55D5717BE0268AF9DCCB3E6FFE D96DDBF61617CABE7BFDE22EEEF2433E5F60556D4D2DA663D3181E1932870747 662DCBC901483026AE13224E158B9EDE48E46F320F1C00008E1D3BD64264F67A 5B6BFB86CA8A10C627C661A4674708A4AF3FFA89BFF8C55DB9175E7AA14B97E4 7FEA5CD6F9677575F5726B4B3B72B90C46C68621530D54926099261289193B11 9F7518633F1682753FF7DC73D9070A0000478E1CF16A5EF9DF7D5EEFDEF6B60E 388E83F1C93198A6F95330F6DCBBEFBEB79DCAF4E5952BBBB4D87482FA033ED4 D5D56049C712148B266289692C695F0ADBB2E03206C7B171FBCE803D32343AE3 38D8D5D3F3ECCD070A00004208F2CB136F7E89CAE4859AAADAF0D28E6548A753 38DF775644A7A6F8C73FB645BA72F92AEAEBEBB17EFD5A080023A3837868D94A 4CC7A730376BA0ABAB0B9665C2765CC812453C9E1017CE5F4A3A8EB5B9BBBB7B F403CD42BF454A88D8B5F3B11FC29597C713B17FBE72EDD73C9E886162224AB6 6DDD2E0DF40FA1A6BA06EBD7AF43201044DA48636C64323B363186C6FA26B8CC 16972F5D81AAE9A004B01D1BB575B564C3C6B52145D17E1E8944E80305B83B76 EEDC39B7EB91C7BF5AB48A5BCEF59D8B3FF4D00AE40B7918C934D66F5C8B5C3E 034A292E5EBC84C6E6FA002040A90C5991AD3B7706012E402905A5121CC7466B 6B330D87431D5EAFFF8B8B02309F757E7D63B2982F56B4B4B462B07F18EBD6AD 06E70C9C7364B319D8B68BBAEA3A04FD15181A1940A150B846482962A9248152 0A42081CD7C5EAB52BBD94D26F2D2A0083B3A7B5A58D73C66024D3686E6982EB B890CA96ED58D28E4B97DF15935313666236716AF0CEE8FAA6A606C88A0C4208 2452F282E00C55E12AA8AADA78E0C081A57FE83AE4FB059065795B5575D89B4E 67E1F379A1280A6CDB02A5148EEB60E5CAE5B06D8B5CBF7A471742EC686F6FC3 B6ED5B21B88044244002280400094270545787D9D858612380A14501A0200DAA AA2197CB4255D5D2334A21840000D8B68575EBD660C38675E09CC3EBF54140C0 751C104A4041200909800040E0F3F9144250BD681E0050E442409452ECFCC604 0444F9B96599701C079C73A4520602C10AE89A064A693935030214945230CE04 40DC45DB035CB09BB94C96852A2A90C96421D1D24238E7C8E5F2309249CCCECE 219BCBC1B26D702150C8E5C05C0610024A4AF2129520491272D9BC0DB0F14503 70B97B2A3A1D2D042B2B000264B279082E70EBD66DC46271E4727970CE41CAD5 92828250A050CC838094C2A8EC3521041289844708D1B768004BDB569C4C1B29 DB344D842A2B30D03F009FDF875028044A040821A5C513024228082D7D7221E0 D81608290148928CA9A99820845CE8EEEE36160D60EFDEBDCCE5ACE7CAE5CB85 CE651DB8736700F97C014B3ADA21ABDA6F742B64BE6B21902885CBDCB2F54B21 77E9E295A265B9DD8B5A0700C02A38FF964A1B971389B8D3D45C8F13C7DF02A5 0A562C5F01BFCF575AB3004048C9E28494810884E02020E8EBBB683A8EFD9F3D 3DFBDE5974804824C2298A4F0E8F8E4E575404A0A80A7E71F40D70C6D0D1B114 ADAD6D08852AA1EB1EE89A024DD7A1697A290B09829B376FB1B1D1F16B994CFA 2B1FF891F2FD8EA79F8EA408A0D4D7376069673B344DC14F7EF23AAE5DBB0E89 4AA8AAAA4175751582C14A783C1EC89204C761E04240D3344A08FA23918879DF 05F58F053874E890C7E5569522CBA80A57419224787D31F40F0CE0EAD5EBF0FB FDF8DCE73E09084040802A145CE4C05C070D0D0D8473EC7E2087FAF73B9E79E6 992221F8FB2BD7AF145455452010404B4B33EA1BAAB17CC51214CD8298994942 966548B4D4C4C9928CA269A2A232084D537DF7D3037D6000A5AAC65F8B4E44F5 4C26035996C1184355388C254B97A0582C3867CF9E2B663219288A024996A069 2A0AF90220085A5A9AC19878F44301884422F41FBF77E0652AAB7D1B366C2415 C10A101098A6054551C0980BCBCE8B4462F61BAFBEFA5FC69933E74C4A283C1E 0F2CCB826D5B686B6BF1EABAFE990F05C0EB55D6CBB2FA977B9E7852EBECEC24 5C7030C6619945783C5E1849033E9FFF4277F7BE7F9124F967B222498CB1524D 20402A9D467D431D1CC7FD93575E79455A74004678D0716C52340BF3876BD32C 82730E8FD783583C6672CE7FBA7FFFFE559462EFDA35AB15D775C13883A66A30 92B3D0351DC1A09F0D0D8D6F5C7480EE6FFDED29DB743E7BE2C4F1ECCCCCAC90 6505D96C0E9AAA419664C462319711F4027447737353B95B2D75AF5EAF8E39C3 80E338686D6D5125E9FEB2D11FBD89BFFDEDE78FB9AEFD77232343454A095269 03814000C54211B66DBB3DCFF6DCE49C9E181E1EC1E1C3AFE64F9D7E3B373D15 13FE4010AEE3209D4EA1A1A1419365F9338B5A07BE73F03BAB3DB2FA82107CB3 00426D6DEDBA6DDB706C1BA1501813D14948941C07809E9E676F0B217CFBF7EF 5F3A3A52FC6C3693ED79FCF1DD153E9F17B3C939B4B6B4C175DDD59148C41B89 440A8BE201954A7FD5D6DEF6C49E3D9F6CF8C2E7BFA037373523954E43D33CF0 FA7C88C5A6338ECD7EB6F05A261C0E8FC9B2FC312A490AE70CC1400552460A12 95100E878BBAAEFFE9A28510A5D4234BB253110CE2EEC92C9BC92014AA84E01C B1585C755571FCAEFC8B2FBE18C8E70B6FD737D4EDD9B163BBD7652EFC8100F2 851C6CDB465373634051D43D8B06609BECF9FE8101DB4819A52B1200D96C06D5 55D5481A491082D8F34F3F3FBDC0033ED7659BB66CD9A40380EB32E8BA064228 32D934EAEA6A28409F583400429C660891E8EFEF679450148A45702E50595981 582CCE39134717CAEFDBB72F46A974A6B7F7547E2E999A3F3BFBFD3E18461295 9595E09C351E3C78B0F68103BC74E8408FAAEBE7B73EBCB5EDE12D5B25102093 CE201008824A0AA2D1C92C13EED17BF5BEF9CD6F7C229FCB7CEDD45B6F174647 26C08580DFE7472A950221404D4D95EDBAE291070E40089EFED4939FF6AE5CB9 4AA612052514D95C06E1AA305CC7C15C72CE63E69DD3BFEB7E9531761610B4AA 3A0CC65CF87DFEF9B6A2A1A12EA069CAA71F14000120B7B7B7EB103C1E9D8ABA 840094500801E47239842B4388CF24204BF2ED728F7FEFED379165E507CB972F 95155502671CB22243D554188681503804D7658F00D0CA299E7C1075800290CA B2D2E8E8A8D477E1CAE705C8D9DA9ADA406D6D1DF2F92C0821F0FB03B8FEDE7B 762E9FFB39001D0003E0960F9614800C821ADDA3CB9CF3BB775A08F883300C03 9AEA018028004F59F7AEBE0B80DF8F074879F14A79AA00B4C3870F272727A3DD BDC77F59304D1373C924828120F2F93C868787D87474EA4C59765EA7FC5D9E9D 99FBFEB5AB37F217CE5D2CCC2593E09C83CA14F1C40C060606AD6432F94A595E 2D1B4DFE7DDE90DE07C05D0FD085F3FCB90B835BB76E69BC71EB46576226614A 9244CEF79DB70C23F5BD7F78E9BBAF952DC6CBD69F37D83BEF9CE99F9818FF51 5D5D5D3A39975E3D31314526C6A2C865F3C9542AF3C6E9D3277F343E3E9E5FA0 BF70DED73F34BF1142F74CB266CD1AFF23BB766C095586FE3C9F2D5C3870E0A5 D717B8FFB7436881BECFE7939F7AEAA9EDA3A3D1D123475E8B2E58287BBF2144 FEC04D7CAF27EED517F7588CDDE301B20080CE5F16FDCF058C58F00EF63BF4FF 7F7CE4C67F0326A2B675DDA7D6BA0000000049454E44AE426082 } end end ����������������������������doublecmd-1.1.22/plugins/wfx/samba/src/smbauthdlg.pas�����������������������������������������������0000755�0001750�0000144�00000004746�14743153644�021622� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit SmbAuthDlg; {$mode objfpc}{$H+} {$R smbauthdlg.lfm} interface uses SysUtils, Extension; function ShowSmbAuthDlg: Boolean; implementation uses SmbFunc; function DlgProc (pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; cdecl; var Data: PtrInt; Text: String; begin Result:= 0; with ExtensionStartupInfo do begin case Msg of DN_INITDIALOG: begin Text:= PAnsiChar(SendDlgMsg(pDlg, 'lblMessage', DM_GETTEXT, 0, 0)); Data:= PtrInt(PAnsiChar(Format(Text, [Message]))); SendDlgMsg(pDlg, 'lblMessage', DM_SETTEXT, Data, 0); Data:= PtrInt(PAnsiChar(UserName)); SendDlgMsg(pDlg, 'edtUserName', DM_SETTEXT, Data, 0); Data:= PtrInt(PAnsiChar(WorkGroup)); SendDlgMsg(pDlg, 'edtDomain', DM_SETTEXT, Data, 0); Data:= PtrInt(PAnsiChar(Password)); SendDlgMsg(pDlg, 'edtPassword', DM_SETTEXT, Data, 0); end; DN_CLICK: if DlgItemName = 'btnOK' then begin Data:= SendDlgMsg(pDlg, 'edtUserName', DM_GETTEXT, 0, 0); StrLCopy(UserName, PAnsiChar(Data), MAX_PATH); Data:= SendDlgMsg(pDlg, 'edtDomain', DM_GETTEXT, 0, 0); StrLCopy(WorkGroup, PAnsiChar(Data), MAX_PATH); Data:= SendDlgMsg(pDlg, 'edtPassword', DM_GETTEXT, 0, 0); StrLCopy(Password, PAnsiChar(Data), MAX_PATH); // close dialog SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, ID_OK, 0); end else if DlgItemName = 'btnCancel' then begin // close dialog SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, ID_CANCEL, 0); end; end;// case end; // with end; function ShowSmbAuthDlg: Boolean; var ResHandle: TFPResourceHandle = 0; ResGlobal: TFPResourceHGLOBAL = 0; ResData: Pointer = nil; ResSize: LongWord; begin Result := False; try ResHandle := FindResource(HINSTANCE, PChar('TDIALOGBOX'), MAKEINTRESOURCE(10) {RT_RCDATA}); if ResHandle <> 0 then begin ResGlobal := LoadResource(HINSTANCE, ResHandle); if ResGlobal <> 0 then begin ResData := LockResource(ResGlobal); ResSize := SizeofResource(HINSTANCE, ResHandle); with ExtensionStartupInfo do begin Result := DialogBoxLRS(ResData, ResSize, @DlgProc); end; end; end; finally if ResGlobal <> 0 then begin UnlockResource(ResGlobal); FreeResource(ResGlobal); end; end; end; end. ��������������������������doublecmd-1.1.22/plugins/wfx/samba/src/smbfunc.pas��������������������������������������������������0000644�0001750�0000144�00000042172�14743153644�021115� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- WFX plugin for working with Common Internet File System (CIFS) Copyright (C) 2011-2015 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit SmbFunc; {$mode objfpc}{$H+} interface uses InitC, Classes, SysUtils, WfxPlugin, Extension; function FsInit(PluginNr: Integer; pProgressProc: TProgressProc; pLogProc: TLogProc; pRequestProc: TRequestProc): Integer; cdecl; function FsFindFirst(Path: PAnsiChar; var FindData: TWin32FindData): THandle; cdecl; function FsFindNext(Hdl: THandle; var FindData: TWin32FindData): BOOL; cdecl; function FsFindClose(Hdl: THandle): Integer; cdecl; function FsRenMovFile(OldName, NewName: PAnsiChar; Move, OverWrite: BOOL; RemoteInfo: pRemoteInfo): Integer; cdecl; function FsGetFile(RemoteName, LocalName: PAnsiChar; CopyFlags: Integer; RemoteInfo: pRemoteInfo): Integer; cdecl; function FsPutFile(LocalName, RemoteName: PAnsiChar; CopyFlags: Integer): Integer; cdecl; function FsDeleteFile(RemoteName: PAnsiChar): BOOL; cdecl; function FsMkDir(RemoteDir: PAnsiChar): BOOL; cdecl; function FsRemoveDir(RemoteName: PAnsiChar): BOOL; cdecl; function FsSetAttr(RemoteName: PAnsiChar; NewAttr: Integer): BOOL; cdecl; function FsSetTime(RemoteName: PAnsiChar; CreationTime, LastAccessTime, LastWriteTime: PFileTime): BOOL; cdecl; procedure FsGetDefRootName(DefRootName: PAnsiChar; MaxLen: Integer); cdecl; { Extension API } procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); cdecl; var Message: AnsiString; WorkGroup: array[0..MAX_PATH-1] of AnsiChar; UserName: array[0..MAX_PATH-1] of AnsiChar; Password: array[0..MAX_PATH-1] of AnsiChar; ExtensionStartupInfo: TExtensionStartupInfo; implementation uses Math, Unix, BaseUnix, UnixType, StrUtils, URIParser, SmbAuthDlg, libsmbclient; const SMB_BUFFER_SIZE = 524288; type PSambaHandle = ^TSambaHandle; TSambaHandle = record Path: String; Handle: LongInt; end; var ProgressProc: TProgressProc; LogProc: TLogProc; RequestProc: TRequestProc; PluginNumber: Integer; Auth: Boolean = False; Abort: Boolean = False; NeedAuth: Boolean = False; function FileTimeToUnixTime(ft: TFileTime): time_t; var UnixTime: Int64; begin UnixTime:= ft.dwHighDateTime; UnixTime:= (UnixTime shl 32) or ft.dwLowDateTime; UnixTime:= (UnixTime - 116444736000000000) div 10000000; Result:= time_t(UnixTime); end; function UnixTimeToFileTime(mtime: time_t): TFileTime; var FileTime: Int64; begin FileTime:= Int64(mtime) * 10000000 + 116444736000000000; Result.dwLowDateTime:= (FileTime and $FFFF); Result.dwHighDateTime:= (FileTime shr $20); end; function URIEncode(Path: String): String; begin Result:= FileNameToURI(Path); Result:= 'smb:/' + Copy(Result, 8, MaxInt); end; procedure WriteError(const FuncName: String); begin WriteLn(FuncName + ': ', SysErrorMessage(fpgetCerrno)); end; procedure smbc_get_auth_data(server, share: PAnsiChar; wg: PAnsiChar; wglen: LongInt; un: PAnsiChar; unlen: LongInt; pw: PAnsiChar; pwlen: LongInt); cdecl; begin Auth:= True; if NeedAuth then begin Abort:= True; // Set query resource if (server = nil) then Message:= StrPas(share) else Message:= StrPas(server) + PathDelim + StrPas(share); // Set authentication data StrLCopy(WorkGroup, wg, wglen); StrLCopy(UserName, un, unlen); StrLCopy(Password, pw, pwlen); // Query authentication data if ShowSmbAuthDlg then begin Abort:= False; // Get authentication data StrLCopy(wg, WorkGroup, wglen); StrLCopy(un, UserName, unlen); StrLCopy(pw, Password, pwlen); end; end else begin // If has saved workgroup then use it if StrLen(WorkGroup) <> 0 then StrLCopy(wg, WorkGroup, wglen); // If has saved user name then use it if StrLen(UserName) <> 0 then StrLCopy(un, UserName, unlen); // If has saved password then use it if StrLen(Password) <> 0 then StrLCopy(pw, Password, pwlen); end; end; function BuildNetworkPath(const Path: String): String; var I, C: Integer; begin C:= 0; if Path = PathDelim then Exit('smb://'); Result := Path; // Don't check last symbol for I := 1 to Length(Result) - 1 do begin if (Result[I] = PathDelim) then Inc(C); end; if (C < 2) then Result:= URIEncode(Result) else begin I:= PosEx(PathDelim, Result, 2); Result:= URIEncode(Copy(Result, I, MaxInt)); end; end; function ForceAuth(Path: PAnsiChar): String; var un: array[0..MAX_PATH-1] of AnsiChar; pw: array[0..MAX_PATH-1] of AnsiChar; begin Result:= BuildNetworkPath(Path); // Use by default saved user name and password StrLCopy(un, UserName, MAX_PATH); StrLCopy(pw, Password, MAX_PATH); // Query auth data smbc_get_auth_data(nil, PAnsiChar(Result), WorkGroup, MAX_PATH, un, MAX_PATH, pw, MAX_PATH); if (Abort = False) and (un <> '') then begin if StrLen(WorkGroup) = 0 then Result:= 'smb://' + un + ':' + pw + '@' + Copy(Result, 7, MAX_PATH) else Result:= 'smb://' + WorkGroup + ';' + un + ':' + pw + '@' + Copy(Result, 7, MAX_PATH); end; end; function FsInit(PluginNr: Integer; pProgressProc: tProgressProc; pLogProc: tLogProc; pRequestProc: tRequestProc): Integer; cdecl; begin if not LoadSambaLibrary then begin pRequestProc(PluginNr, RT_MsgOK, nil, 'Can not load "libsmbclient" library!', nil, 0); Exit(-1); end; ProgressProc := pProgressProc; LogProc := pLogProc; RequestProc := pRequestProc; PluginNumber := PluginNr; FillChar(WorkGroup, SizeOf(WorkGroup), #0); FillChar(UserName, SizeOf(UserName), #0); FillChar(Password, SizeOf(Password), #0); Result := smbc_init(@smbc_get_auth_data, 0); if Result < 0 then WriteError('smbc_init'); end; function FsFindFirst(Path: PAnsiChar; var FindData: TWin32FindData): THandle; cdecl; var NetworkPath: String; SambaHandle: PSambaHandle; Handle: LongInt; begin Abort:= False; NetworkPath:= BuildNetworkPath(Path); repeat Auth:= False; Handle:= smbc_opendir(PChar(NetworkPath)); NeedAuth:= (Handle = -1); // Sometimes smbc_get_auth_data don't called automatically // so we call it manually if NeedAuth and (Auth = False) then begin NetworkPath:= ForceAuth(Path); end; until not NeedAuth or Abort; if Handle < 0 then begin WriteError('smbc_opendir'); Result:= wfxInvalidHandle; end else begin New(SambaHandle); SambaHandle^.Path:= IncludeTrailingPathDelimiter(NetworkPath); SambaHandle^.Handle:= Handle; Result:= THandle(SambaHandle); FsFindNext(Result, FindData); end; end; function FsFindNext(Hdl: THandle; var FindData: TWin32FindData): BOOL; cdecl; var dirent: psmbc_dirent; FileInfo: BaseUnix.Stat; Mode: array[0..10] of AnsiChar; SambaHandle: PSambaHandle absolute Hdl; begin Result:= True; dirent := smbc_readdir(SambaHandle^.Handle); if (dirent = nil) then Exit(False); FillByte(FindData, SizeOf(TWin32FindData), 0); StrLCopy(FindData.cFileName, dirent^.name, dirent^.namelen); if dirent^.smbc_type in [SMBC_WORKGROUP, SMBC_SERVER, SMBC_FILE_SHARE] then FindData.dwFileAttributes:= FILE_ATTRIBUTE_DIRECTORY; if dirent^.smbc_type in [SMBC_DIR, SMBC_FILE, SMBC_LINK] then begin if smbc_stat(PChar(SambaHandle^.Path + FindData.cFileName), @FileInfo) = 0 then begin FindData.nFileSizeLow := (FileInfo.st_size and MAXDWORD); FindData.nFileSizeHigh := (FileInfo.st_size shr $20); FindData.ftLastAccessTime:= UnixTimeToFileTime(FileInfo.st_atime); FindData.ftCreationTime:= UnixTimeToFileTime(FileInfo.st_ctime); FindData.ftLastWriteTime:= UnixTimeToFileTime(FileInfo.st_mtime); FindData.dwFileAttributes:= IfThen(fpS_ISDIR(FileInfo.st_mode), FILE_ATTRIBUTE_DIRECTORY, 0); end; if smbc_getxattr(PChar(SambaHandle^.Path + FindData.cFileName), 'system.dos_attr.mode', @Mode, SizeOf(Mode)) >= 0 then begin // smbc_getxattr returns attributes as hex string (like 0x00000000) FindData.dwFileAttributes:= StrToIntDef(Mode, FindData.dwFileAttributes); end; end; end; function FsFindClose(Hdl: THandle): Integer; cdecl; var SambaHandle: PSambaHandle absolute Hdl; begin Result:= smbc_closedir(SambaHandle^.Handle); if Result < 0 then WriteError('smbc_closedir'); Dispose(SambaHandle); end; function FsRenMovFile(OldName, NewName: PAnsiChar; Move, OverWrite: BOOL; RemoteInfo: pRemoteInfo): Integer; cdecl; var OldFileName, NewFileName: String; Buffer: Pointer = nil; BufferSize: LongWord; fdOldFile: LongInt; fdNewFile: LongInt; dwRead: ssize_t; Written: Int64; FileSize: Int64; Percent: LongInt; Flags: cint = O_CREAT or O_RDWR or O_TRUNC; begin OldFileName:= BuildNetworkPath(OldName); NewFileName:= BuildNetworkPath(NewName); if Move then begin if smbc_rename(PChar(OldFileName), PChar(NewFileName)) < 0 then Exit(-1); end else begin if OverWrite = False then begin Flags:= Flags or O_EXCL; end; BufferSize:= SMB_BUFFER_SIZE; Buffer:= GetMem(BufferSize); try // Open source file fdOldFile:= smbc_open(PChar(OldFileName), O_RDONLY, 0); if (fdOldFile < 0) then Exit(FS_FILE_READERROR); // Open target file fdNewFile:= smbc_open(PChar(NewFileName), Flags, RemoteInfo^.Attr); if (fdNewFile < 0) then begin if cerrno = ESysEEXIST then Exit(FS_FILE_EXISTS) else Exit(FS_FILE_WRITEERROR); end; // Get source file size FileSize:= smbc_lseek(fdOldFile, 0, SEEK_END); smbc_lseek(fdOldFile, 0, SEEK_SET); Written:= 0; // Copy data repeat dwRead:= smbc_read(fdOldFile, Buffer, BufferSize); if (dwRead < 0) then Exit(FS_FILE_READERROR); if (dwRead > 0) then begin if smbc_write(fdNewFile, Buffer, dwRead) <> dwRead then Exit(FS_FILE_WRITEERROR); Written:= Written + dwRead; // Calculate percent Percent:= (Written * 100) div FileSize; // Update statistics if ProgressProc(PluginNumber, PChar(OldFileName), PChar(NewFileName), Percent) = 1 then Exit(FS_FILE_USERABORT); end; until (dwRead = 0); finally if Assigned(Buffer) then FreeMem(Buffer); if not (fdOldFile < 0) then smbc_close(fdOldFile); if not (fdNewFile < 0) then smbc_close(fdNewFile); end; end; Result:= FS_FILE_OK; end; function FsGetFile(RemoteName, LocalName: PAnsiChar; CopyFlags: Integer; RemoteInfo: pRemoteInfo): Integer; cdecl; var OldFileName: String; Buffer: Pointer = nil; BufferSize: LongWord; fdOldFile: LongInt; fdNewFile: LongInt; dwRead: ssize_t; Written: Int64; FileSize: Int64; Percent: LongInt; Flags: cint = O_CREAT or O_RDWR or O_TRUNC; begin OldFileName:= BuildNetworkPath(RemoteName); if (CopyFlags and FS_COPYFLAGS_OVERWRITE) = 0 then begin Flags:= Flags or O_EXCL; end; BufferSize:= SMB_BUFFER_SIZE; Buffer:= GetMem(BufferSize); try // Open source file fdOldFile:= smbc_open(PChar(OldFileName), O_RDONLY, 0); if (fdOldFile < 0) then Exit(FS_FILE_READERROR); // Open target file fdNewFile:= fpOpen(PChar(LocalName), Flags, $1A4); // $1A4 = &644 if (fdNewFile < 0) then begin if errno = ESysEEXIST then Exit(FS_FILE_EXISTS) else Exit(FS_FILE_WRITEERROR); end; // Get source file size FileSize:= smbc_lseek(fdOldFile, 0, SEEK_END); smbc_lseek(fdOldFile, 0, SEEK_SET); Written:= 0; // Copy data repeat dwRead:= smbc_read(fdOldFile, Buffer, BufferSize); if (dwRead < 0) then Exit(FS_FILE_READERROR); if (dwRead > 0) then begin if fpWrite(fdNewFile, Buffer^, dwRead) <> dwRead then Exit(FS_FILE_WRITEERROR); Written:= Written + dwRead; // Calculate percent Percent:= (Written * 100) div FileSize; // Update statistics if ProgressProc(PluginNumber, PChar(OldFileName), LocalName, Percent) = 1 then Exit(FS_FILE_USERABORT); end; until (dwRead = 0); finally if Assigned(Buffer) then FreeMem(Buffer); if not (fdOldFile < 0) then smbc_close(fdOldFile); if not (fdNewFile < 0) then fpClose(fdNewFile); end; Result:= FS_FILE_OK; end; function FsPutFile(LocalName, RemoteName: PAnsiChar; CopyFlags: Integer): Integer; cdecl; var NewFileName: String; Buffer: Pointer = nil; BufferSize: LongWord; fdOldFile: LongInt; fdNewFile: LongInt; dwRead: TSsize; Written: Int64; FileSize: Int64; Percent: LongInt; Flags: cint = O_CREAT or O_RDWR or O_TRUNC; begin NewFileName:= BuildNetworkPath(RemoteName); if (CopyFlags and FS_COPYFLAGS_OVERWRITE) = 0 then begin Flags:= Flags or O_EXCL; end; BufferSize:= SMB_BUFFER_SIZE; Buffer:= GetMem(BufferSize); try // Open source file fdOldFile:= fpOpen(LocalName, O_RDONLY, 0); if (fdOldFile < 0) then Exit(FS_FILE_READERROR); // Open target file fdNewFile:= smbc_open(PChar(NewFileName), Flags, 0); if (fdNewFile < 0) then begin if cerrno = ESysEEXIST then Exit(FS_FILE_EXISTS) else Exit(FS_FILE_WRITEERROR); end; // Get source file size FileSize:= fpLseek(fdOldFile, 0, SEEK_END); fpLseek(fdOldFile, 0, SEEK_SET); Written:= 0; // Copy data repeat dwRead:= fpRead(fdOldFile, Buffer^, BufferSize); if (dwRead < 0) then Exit(FS_FILE_READERROR); if (dwRead > 0) then begin if smbc_write(fdNewFile, Buffer, dwRead) <> dwRead then Exit(FS_FILE_WRITEERROR); Written:= Written + dwRead; // Calculate percent Percent:= (Written * 100) div FileSize; // Update statistics if ProgressProc(PluginNumber, LocalName, PChar(NewFileName), Percent) = 1 then Exit(FS_FILE_USERABORT); end; until (dwRead = 0); finally if Assigned(Buffer) then FreeMem(Buffer); if not (fdOldFile < 0) then fpClose(fdOldFile); if not (fdNewFile < 0) then smbc_close(fdNewFile); end; Result:= FS_FILE_OK; end; function FsDeleteFile(RemoteName: PAnsiChar): BOOL; cdecl; var FileName: String; begin FileName:= BuildNetworkPath(RemoteName); Result:= smbc_unlink(PChar(FileName)) = 0; end; function FsMkDir(RemoteDir: PAnsiChar): BOOL; cdecl; var NewDir: String; begin NewDir:= BuildNetworkPath(RemoteDir); Result:= smbc_mkdir(PChar(NewDir), $1FF) = 0; // $1FF = &0777 end; function FsRemoveDir(RemoteName: PAnsiChar): BOOL; cdecl; var RemDir: String; begin RemDir:= BuildNetworkPath(RemoteName); Result:= smbc_rmdir(PChar(RemDir)) = 0; end; function FsSetAttr(RemoteName: PAnsiChar; NewAttr: Integer): BOOL; cdecl; var FileName: String; Mode: array[0..10] of AnsiChar; begin Mode:= '0x' + HexStr(NewAttr, 8) + #0; FileName:= BuildNetworkPath(RemoteName); // smbc_setxattr takes attributes as hex string (like 0x00000000) Result:= (smbc_setxattr(PChar(FileName), 'system.dos_attr.mode', @Mode, SizeOf(Mode), 0) >= 0); end; function FsSetTime(RemoteName: PAnsiChar; CreationTime, LastAccessTime, LastWriteTime: PFileTime): BOOL; cdecl; var FileName: String; tbuf: array[0..1] of timeval; FileInfo: BaseUnix.Stat; begin FileName:= BuildNetworkPath(RemoteName); if (LastAccessTime = nil) or (LastWriteTime = nil) then begin if smbc_stat(PChar(FileName), @FileInfo) < 0 then Exit(False); if (LastAccessTime = nil) then tbuf[0].tv_sec:= FileInfo.st_atime else tbuf[0].tv_sec:= FileTimeToUnixTime(LastAccessTime^); if (LastWriteTime = nil) then tbuf[1].tv_sec:= FileInfo.st_mtime else tbuf[1].tv_sec:= FileTimeToUnixTime(LastWriteTime^); end else begin tbuf[0].tv_sec:= FileTimeToUnixTime(LastAccessTime^); tbuf[1].tv_sec:= FileTimeToUnixTime(LastWriteTime^); end; Result:= (smbc_utimes(PChar(FileName), @tbuf) = 0); end; procedure FsGetDefRootName(DefRootName: PAnsiChar; MaxLen: Integer); cdecl; begin StrPLCopy(DefRootName, 'Windows Network', MaxLen); end; procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); cdecl; begin ExtensionStartupInfo:= StartupInfo^; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/sample/����������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016354� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/sample/src/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017143� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/sample/src/sample.lpi��������������������������������������������������0000644�0001750�0000144�00000004155�14743153644�021137� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <General> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="Example of WFX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2012 Koblov Alexander" ProductVersion=""/> </VersionInfo> <BuildModes Count="1"> <Item1 Name="default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <Units Count="1"> <Unit0> <Filename Value="sample.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="Sample"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../sample.wfx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../../../sdk"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <Linking> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wfx/sample/src/sample.lpr��������������������������������������������������0000644�0001750�0000144�00000003354�14743153644�021150� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library Sample; {$mode objfpc}{$H+} {$include calling.inc} uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF unix} baseunix, {$ENDIF} Classes, WfxPlugin, SysUtils; {$E wfx} {$R *.res} var gPluginNr: integer; gProgressProc: tProgressProc; gLogProc: tLogProc; gRequestProc: tRequestProc; function FsInit(PluginNr:integer;pProgressProc:tProgressProc;pLogProc:tLogProc; pRequestProc:tRequestProc):integer; dcpcall; begin gPluginNr:= PluginNr; gProgressProc:= pProgressProc; gLogProc:= pLogProc; gRequestProc:= pRequestProc; Result:= 0; end; function FsFindFirst(path :pchar;var FindData:tWIN32FINDDATA):thandle; dcpcall; begin FillChar(FindData, SizeOf(FindData), 0); FindData.dwFileAttributes :=0; //0 - обычный файл без каких-либо атрибутов StrPCopy(FindData.cFileName,'Hello, world.txt'); //имя файла Result:= 1985; //функция нормально отработала} end; function FsFindNext(Hdl:thandle;var FindData:tWIN32FINDDATA): BOOL; dcpcall; begin // gRequestProc(gPluginNr, RT_URL, nil, nil, nil, 0); Result:= False; end; function FsFindClose(Hdl:thandle):integer; dcpcall; begin Result:= 0; end; function FsRenMovFile(OldName,NewName:pchar;Move,OverWrite:bool; RemoteInfo:pRemoteInfo):integer; dcpcall; begin gRequestProc(gPluginNr, RT_MsgOK, OldName, NewName, nil, 0); Result:= FS_FILE_OK; end; function FsExecuteFile(MainWin:thandle;RemoteName,Verb:pchar):integer; dcpcall; begin gRequestProc(gPluginNr, RT_MsgOK, RemoteName, Verb, nil, 0); Result:= FS_EXEC_OK; end; exports // mandatory FsInit, FsFindFirst, FsFindNext, FsFindClose, // optional FsRenMovFile, FsExecuteFile; begin end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/�����������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015101� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/MacPreview/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017143� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/MacPreview/src/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017732� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/MacPreview/src/MacPreview.lpi������������������������������������������0000644�0001750�0000144�00000003741�14743153644�022507� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="MacPreview"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes> <Item Name="Default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <Units> <Unit> <Filename Value="MacPreview.lpr"/> <IsPartOfProject Value="True"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../MacPreview.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <LinkerOptions Value="-weak_framework UniformTypeIdentifiers"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> �������������������������������doublecmd-1.1.22/plugins/wlx/MacPreview/src/MacPreview.lpr������������������������������������������0000644�0001750�0000144�00000021504�14743153644�022515� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- MacOS preview plugin Copyright (C) 2022-2024 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2022-2024 Rich Chang (rich2014.git@outlook.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } library MacPreview; {$mode objfpc}{$H+} {$modeswitch objectivec1} uses SysUtils, WlxPlugin, QuickLookUI, CFPropertyList, MacOSAll, CocoaAll, UniformTypeIdentifiers; const NSAppKitVersionNumber11_0 = 2022; type TQLPItem = objcclass(NSObject, QLPreviewItemProtocol) function previewItemURL: NSURL; private url: NSURL; public ext: ShortString; procedure initPath( path: pchar); message 'initPath:'; end; DCQLPreview = objcclass(QLPreviewView) function acceptsFirstResponder: ObjCBOOL; override; end; var QLContentTypes: NSMutableArray; QLContentUTTypes: NSMutableArray; const ExcludeList: array[0..2] of PAnsiChar = ( 'public.plain-text', 'public.json', 'public.xml' ); // copy from uMyDarwin function StringToNSString(const S: String): NSString; begin Result:= NSString(NSString.stringWithUTF8String(PAnsiChar(S))); end; // copy from DCStrUtils function ExtractOnlyFileExt(const FileName: string): string; var I : LongInt; SOF : Boolean; EndSep : Set of Char; begin Result := EmptyStr; I := Length(FileName); EndSep:= AllowDirectorySeparators + AllowDriveSeparators + [ExtensionSeparator]; while (I > 0) and not (FileName[I] in EndSep) do Dec(I); if (I > 0) and (FileName[I] = ExtensionSeparator) then begin SOF:= (I = 1) or (FileName[I - 1] in AllowDirectorySeparators); if (not SOF) or FirstDotAtFileNameStartIsExtension then Result := Copy(FileName, I + 1, MaxInt) end; end; procedure AddContentType(AType: NSString); var anObject: id; begin QLContentTypes.addObject(AType); if NSAppKitVersionNumber >= NSAppKitVersionNumber11_0 then begin anObject:= UTType.typeWithIdentifier(AType); if Assigned(anObject) then QLContentUTTypes.addObject(anObject); end; end; function CheckContentType(const Name: String; FileType: NSString): Boolean; var Index: Integer; begin // Special case if (Name = 'Text.qlgenerator') then begin for Index:= 0 to High(ExcludeList) do begin if StrComp(FileType.UTF8String, ExcludeList[Index]) = 0 then Exit(False) end; end; Result:= True; end; procedure ParseFile(const Path, Name: String); var Data: NSData; I, J: Integer; Dict: NSDictionary; FileType: NSString; DocumentTypes, ContentTypes: NSArray; begin Data:= NSData.dataWithContentsOfFile(StringToNSString(Path + Name + '/Contents/Info.plist')); if Assigned(Data) then begin Dict:= NSDictionary(NSPropertyListSerialization.propertyListWithData_options_format_error(Data, NSPropertyListImmutable, nil, nil)); if Assigned(Dict) then begin DocumentTypes:= NSArray(Dict.valueForKey(StringToNSString('CFBundleDocumentTypes'))); if Assigned(DocumentTypes) then begin for I:= 0 to Integer(DocumentTypes.count) - 1 do begin Dict:= NSDictionary(DocumentTypes.objectAtIndex(I)); ContentTypes:= NSArray(Dict.valueForKey(StringToNSString('LSItemContentTypes'))); if Assigned(ContentTypes) then begin for J:= 0 to Integer(ContentTypes.count - 1) do begin FileType:= NSString(ContentTypes.objectAtIndex(J)); if CheckContentType(Name, FileType) then AddContentType(FileType); end; end; end; end; end; end; end; procedure ParseFolder(const Path: String); var FindData: TSearchRec; begin if FindFirst(Path + '*.qlgenerator', faDirectory, FindData) = 0 then begin repeat ParseFile(Path, FindData.Name); until FindNext(FindData) <> 0; FindClose(FindData); end; end; function CheckFile_oldMacOS(const FileName: String): Boolean; var Index: Integer; QLType: NSString; FileType: NSString; begin FileType:= NSWorkspace.sharedWorkspace.typeOfFile_error(StringToNSString(FileName), nil); if (FileType = nil) then begin Result:= False; end else begin for Index:= 0 to QLContentTypes.Count - 1 do begin QLType:= NSString(QLContentTypes.objectAtIndex(Index)); // Direct comparison if (FileType.compare(QLType) = NSOrderedSame) then Exit(True); // Conforms checking if UTTypeConformsTo(CFStringRef(FileType), CFStringRef(QLType)) then Exit(True); end; Result:= False; end; end; function CheckFile_newMacOS(const FileName: String): Boolean; var Index: Integer; FileExt: String; QLUTType: UTType; QLType: NSString; FileType: NSString; FileUTType: UTType; begin FileExt:= ExtractOnlyFileExt(FileName); FileUTType:= UTType.typeWithFilenameExtension(StringToNSString(FileExt)); if (FileUTType = nil) then begin Result:= False; end else begin FileType:= FileUTType.identifier; // Direct comparison for Index:= 0 to QLContentTypes.Count - 1 do begin QLType:= NSString(QLContentTypes.objectAtIndex(Index)); if (FileType.compare(QLType) = NSOrderedSame) then Exit(True); end; // Conforms checking for Index:= 0 to QLContentUTTypes.Count - 1 do begin QLUTType:= UTType(QLContentUTTypes.objectAtIndex(Index)); if FileUTType.conformsToType(QLUTType) then Exit(True); end; Result:= False; end; end; function CheckFile(const FileName: String): Boolean; begin if NSAppKitVersionNumber >= NSAppKitVersionNumber11_0 then Result:= CheckFile_newMacOS( FileName ) else Result:= CheckFile_oldMacOS( FileName ); end; function TQLPItem.previewItemURL: NSURL; begin Result:= url; end; procedure TQLPItem.initPath( path: pchar ); begin url:= NSURL.fileURLWithPath( StringToNSString(path) ); ext:= UpperCase( ExtractOnlyFileExt(path) ); end; function DCQLPreview.acceptsFirstResponder: ObjCBOOL; begin Result:= false; end; procedure setFilepath( view:QLPreviewView; filepath:String ); var item: TQLPItem; begin if filepath=EmptyStr then begin item:= nil; end else begin item:= TQLPItem.alloc.init; item.initPath( pchar(filepath) ); end; view.setPreviewItem( item ); item.release; end; function ListLoad( ParentWin:THandle; FileToLoad:pchar; {%H-}ShowFlags:integer):THandle; cdecl; var view: QLPreviewView; begin if not CheckFile(FileToLoad) then Exit(wlxInvalidHandle); view:= DCQLPreview.alloc.init; view.setAutostarts( true ); view.setShouldCloseWithWindow( false ); NSView(ParentWin).addSubview( view ); setFilepath( view, FileToLoad ); Result:= THandle( view ); end; function isExtChanged( view: QLPreviewView; FileToLoad:pchar ): boolean; var item: TQLPItem; newExt: ShortString; begin item:= {%H-}TQLPItem( view.previewItem ); newExt:= upperCase( ExtractOnlyFileExt( FileToLoad ) ); Result:= item.ext<>newExt; end; function ListLoadNext( {%H-}ParentWin,PluginWin:THandle; FileToLoad:pchar; {%H-}ShowFlags:integer):integer; cdecl; var view: QLPreviewView; begin if not CheckFile(FileToLoad) then Exit(LISTPLUGIN_ERROR); view:= QLPreviewView(PluginWin); // workaround for the bug of MacOS Quick Look: // when previewing different types of files continuously, occasionally exceptions occur. // such as previewing a large .pas file immediately after previewing a pdf file. // empty the original preview file first can solve such problems. if isExtChanged(view,FileToLoad) then setFilepath(view,EmptyStr); setFilepath( view, FileToLoad ); Result:= LISTPLUGIN_OK; end; procedure ListCloseWindow(ListWin:THandle); cdecl; begin QLPreviewView(ListWin).close; QLPreviewView(ListWin).removeFromSuperview; end; procedure ListSetDefaultParams(dps: PListDefaultParamStruct); cdecl; begin QLContentTypes:= NSMutableArray.alloc.init; QLContentUTTypes:= NSMutableArray.alloc.init; ParseFolder('/Library/QuickLook/'); ParseFolder('/System/Library/QuickLook/'); ParseFolder(IncludeTrailingBackslash(GetUserDir) + 'Library/QuickLook/'); end; procedure ListGetDetectString(DetectString:pchar;maxlen:integer); cdecl; begin StrLCopy(DetectString, '(EXT!="")', MaxLen); end; exports ListLoad, ListLoadNext, ListCloseWindow, ListGetDetectString, ListSetDefaultParams; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/MacPreview/src/UniformTypeIdentifiers.pas������������������������������0000644�0001750�0000144�00000001722�14743153644�025110� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit UniformTypeIdentifiers; {$mode delphi} {$modeswitch objectivec1} interface uses SysUtils, CocoaAll; type UTType = objcclass external(NSObject, NSCopyingProtocol, NSSecureCodingProtocol) public class function typeWithIdentifier(identifier: NSString): id; message 'typeWithIdentifier:'; class function typeWithFilenameExtension(filenameExtension: NSString): id; message 'typeWithFilenameExtension:'; function identifier: NSString; message 'identifier'; function conformsToType(type_: UTType): ObjCBOOL; message 'conformsToType:'; // NSCopyingProtocol function copyWithZone(zone: NSZonePtr): id; message 'copyWithZone:'; // NSCodingProtocol procedure encodeWithCoder(aCoder: NSCoder); message 'encodeWithCoder:'; function initWithCoder(aDecoder: NSCoder): id; message 'initWithCoder:'; // NSSecureCodingProtocol class function supportsSecureCoding: ObjCBOOL; message 'supportsSecureCoding'; end; implementation end. ����������������������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017205� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/COPYING.txt�������������������������������������������������0000644�0001750�0000144�00000020735�14743153644�021065� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ This is the file COPYING.TXT, it applies to the Free Pascal Qt4 Binding. The source code of the Free Pascal Qt4 binding is distributed under the GNU Lesser General Public License (see http://www.gnu.org/licenses/lgpl.txt and below) with the following modification: As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. http://www.gnu.org/licenses/lgpl.txt: GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. �����������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/README.txt��������������������������������������������������0000644�0001750�0000144�00000002542�14743153644�020706� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ WlxMplayer ------------------------------------------------------------------------- This is WLX (Lister) plugin for Double Commander. Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Class TExProcess used in plugin was written by Anton Rjeshevsky. Gtk2 and Qt support were added by Koblov Alexander (Alexx2000@mail.ru) 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 While the gui interface for wlx isn't developed to use this plugin add to doublecmd.ini these lines and edit them. [Lister Plugins] PluginCount=1 Plugin1Name=WlxMplayer Plugin1Detect=(EXT="MPG")|(EXT="AVI")|(EXT="MPEG")|(EXT="FLV") Plugin1Path=*Here you must write path to compiled plugin* ��������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/src/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017774� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/src/fpc-extra.cfg�������������������������������������������0000644�0001750�0000144�00000000157�14743153644�022351� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF CPU64 #IFDEF FPC_CROSSCOMPILING -Fl/usr/lib/gcc/i486-linux-gnu/4.6/64 -Fl/usr/local/lib64 #ENDIF #ENDIF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/src/wlxMplayer.lpi������������������������������������������0000644�0001750�0000144�00000011536�14743153644�022654� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="10"/> <PathDelim Value="\"/> <General> <Flags> <LRSInOutputDirectory Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="1"/> <StringTable FileDescription="MPlayer WLX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2012 Koblov Alexander"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\wlxmplayer.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="..\..\..\..\sdk"/> <OtherUnitFiles Value="$(LazarusDir)\lcl\units\$(TargetCPU)-$(TargetOS)\$(LCLWidgetType);..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <Optimizations> <VariablesInRegisters Value="True"/> <UncertainOptimizations Value="True"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <ConfigFile> <CustomConfigFile Value="True"/> <ConfigFilePath Value="fpc-extra.cfg"/> </ConfigFile> <CustomOptions Value="-dLCL$(LCLWidgetType)"/> </Other> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="LCL"/> </Item1> </RequiredPackages> <Units Count="1"> <Unit0> <Filename Value="wlxMplayer.lpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\wlxmplayer.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="..\..\..\..\sdk"/> <OtherUnitFiles Value="$(LazarusDir)\lcl\units\$(TargetCPU)-$(TargetOS)\$(LCLWidgetType);..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> <VariablesInRegisters Value="True"/> <UncertainOptimizations Value="True"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> <Other> <ConfigFile> <CustomConfigFile Value="True"/> <ConfigFilePath Value="fpc-extra.cfg"/> </ConfigFile> <CustomOptions Value="-dLCL$(LCLWidgetType)"/> </Other> </CompilerOptions> </CONFIG> ������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/WlxMplayer/src/wlxMplayer.lpr������������������������������������������0000644�0001750�0000144�00000017371�14743153644�022670� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ WlxMplayer ------------------------------------------------------------------------- This is WLX (Lister) plugin for Double Commander. Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Class TExProcess used in plugin was written by Anton Rjeshevsky. Gtk2 and Qt support were added by Koblov Alexander (Alexx2000@mail.ru) 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 } library wlxMplayer; {$mode objfpc}{$H+} {$include calling.inc} {$IF NOT (DEFINED(LCLGTK) or DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6))} {$DEFINE LCLGTK2} {$ENDIF} uses {$IFDEF UNIX} cthreads, {$IFNDEF HEAPTRC} cmem, {$ENDIF} {$ENDIF} Classes, sysutils, x, {$IFDEF LCLGTK} gtk, gdk, glib, {$ENDIF} {$IFDEF LCLGTK2} gtk2, gdk2, glib2, gdk2x, {$ENDIF} {$IFDEF LCLQT} qt4, {$ENDIF} {$IFDEF LCLQT5} qt5, {$ENDIF} {$IFDEF LCLQT6} qt6, {$ENDIF} process, math, WLXPlugin; type { TExProcess } TExProcess = class protected p: TProcess; s: string; function _GetExitStatus(): integer; public RezList:TStringList; constructor Create(commandline: string); procedure Execute; destructor Destroy; procedure OnReadLn(str: string); property ExitStatus: integer read _GetExitStatus; end; const buf_len = 3000; { TExProcess } function TExProcess._GetExitStatus(): integer; begin Result:=p.ExitStatus; end; constructor TExProcess.Create(commandline: string); begin RezList:=TStringList.Create; s:=''; p:=TProcess.Create(nil); p.CommandLine:=commandline; p.Options:=[poUsePipes,poNoConsole]; end; procedure TExProcess.Execute; var buf: string; i, j, c, n: integer; begin p.Execute; repeat SetLength(buf, buf_len); SetLength(buf, p.output.Read(buf[1], length(buf))); //waits for the process output // cut the incoming stream to lines: s:=s + buf; //add to the accumulator repeat //detect the line breaks and cut. i:=Pos(#13, s); j:=Pos(#10, s); if i=0 then i:=j; if j=0 then j:=i; if j = 0 then Break; //there are no complete lines yet. OnReadLn(Copy(s, 1, min(i, j) - 1)); //return the line without the CR/LF characters s:=Copy(s, max(i, j) + 1, length(s) - max(i, j)); //remove the line from accumulator until false; until buf = ''; if s <> '' then OnReadLn(s); end; destructor TExProcess.Destroy; begin RezList.Free; p.Free; end; procedure TExProcess.OnReadLn(str: string); begin RezList.Add(str); end; type //Class implementing mplayer control { TMPlayer } TMPlayer=class(TThread) public //--------------------- hWidget:THandle; //the integrable widget fileName:string; //filename xid:TWindow; //X window handle pr:TProcess; //mplayer's process pmplayer:string; //path to mplayer //--------------------- constructor Create(APlayerPath, AFilename: String); destructor destroy; override; procedure SetParentWidget(AWidget:thandle); protected procedure Execute; override; private end; { TMPlayer } constructor TMPlayer.Create(APlayerPath, AFilename: String); begin inherited Create(True); filename:= '"' + AFilename + '"'; pmplayer:= APlayerPath + ' '; WriteLn('wlxMPlayer: found mplayer in - ' + pmplayer); end; destructor TMPlayer.destroy; begin if pr.Running then pr.Terminate(0); pr.Free; {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} QWidget_Destroy(QWidgetH(hWidget)); {$ELSE} gtk_widget_destroy(PGtkWidget(hWidget)); {$ENDIF} inherited destroy; end; procedure TMPlayer.SetParentWidget(AWidget: THandle); {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} begin hWidget:= THandle(QWidget_create(QWidgetH(AWidget))); QWidget_show(QWidgetH(hWidget)); xid:= QWidget_winId(QWidgetH(hWidget)); end; {$ELSE} var widget, mySocket: PGtkWidget; //the socket begin widget := PGtkWidget(AWidget); mySocket := gtk_socket_new; gtk_container_add(GTK_CONTAINER(widget), mySocket); gtk_widget_show(mySocket); gtk_widget_show(widget); gtk_widget_realize(mySocket); {$IFDEF LCLGTK} xid:= (PGdkWindowPrivate(mySocket^.window))^.xwindow; {$ENDIF} {$IFDEF LCLGTK2} xid:= GDK_WINDOW_XID(mySocket^.window); {$ENDIF} hWidget:= THandle(mySocket); end; {$ENDIF} procedure TMPlayer.Execute; begin pr:=TProcess.Create(nil); pr.Options := Pr.Options + [poWaitOnExit,poNoConsole{,poUsePipes}]; //mplayer stops if poUsePipes used. pr.CommandLine:=pmplayer+fileName+' -wid '+IntToStr(xid); WriteLn(pr.CommandLine); pr.Execute; end; //Custom class contains info for plugin windows type { TPlugInfo } TPlugInfo = class private fControls:TStringList; public fFileToLoad:string; fShowFlags:integer; //etc constructor Create; destructor Destroy; override; function AddControl(AItem: TMPlayer):integer; end; { TPlugInfo } constructor TPlugInfo.Create; begin fControls:=TStringlist.Create; end; destructor TPlugInfo.Destroy; begin while fControls.Count>0 do begin TMPlayer(fControls.Objects[0]).Free; fControls.Delete(0); end; inherited Destroy; end; function TPlugInfo.AddControl(AItem: TMPlayer): integer; begin fControls.AddObject(inttostr(PtrUInt(AItem)),TObject(AItem)); end; {Plugin main part} var List:TStringList; function ListLoad(ParentWin: THandle; FileToLoad: PChar; ShowFlags: Integer): THandle; dcpcall; var pf: TExProcess; sPlayerPath: String; p: TMPlayer; begin pf:= TExProcess.Create('which mplayer'); try pf.Execute; if (pf.RezList.Count <> 0) then sPlayerPath:= pf.RezList[0] else WriteLn('wlxMPlayer: mplayer not found!'); finally pf.Free; end; if sPlayerPath = EmptyStr then Exit(wlxInvalidHandle); p:= TMPlayer.Create(sPlayerPath, string(FileToLoad)); p.SetParentWidget(ParentWin); // Create list if none if not Assigned(List) then List:= TStringList.Create; // Add to list new plugin window and it's info List.AddObject(IntToStr(PtrInt(p.hWidget)), TPlugInfo.Create); with TPlugInfo(List.Objects[List.Count-1]) do begin fFileToLoad:= FileToLoad; fShowFlags:= ShowFlags; AddControl(p); end; Result:= p.hWidget; p.Resume; end; procedure ListCloseWindow(ListWin:thandle); dcpcall; var Index:integer; s:string; begin if assigned(List) then begin writeln('ListCloseWindow quit, List Item count: '+inttostr(List.Count)); s:=IntToStr(ListWin); Index:=List.IndexOf(s); if Index>-1 then begin TPlugInfo(List.Objects[index]).Free; List.Delete(Index); writeln('List item n: '+inttostr(Index)+' Deleted'); end; //Free list if it has zero items If List.Count=0 then FreeAndNil(List); end; end; procedure ListGetDetectString(DetectString:pchar;maxlen:integer); dcpcall; begin StrLCopy(DetectString, '(EXT="AVI")|(EXT="MKV")|(EXT="FLV")|(EXT="MPG")|(EXT="MPEG")|(EXT="MP4")|(EXT="VOB")', maxlen); end; exports ListLoad, ListCloseWindow, ListGetDetectString; {$R *.res} begin end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/preview/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016562� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/preview/src/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017351� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/preview/src/preview.lpi������������������������������������������������0000644�0001750�0000144�00000007314�14743153644�021545� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="11"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="PreviewHandler"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\preview.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <TrashVariables Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> <Modes Count="0"/> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="doublecmd_common"/> </Item1> </RequiredPackages> <Units Count="1"> <Unit0> <Filename Value="preview.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="Preview"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\preview.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> </Exceptions> </Debugging> </CONFIG> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/preview/src/preview.lpr������������������������������������������������0000644�0001750�0000144�00000012314�14743153644�021552� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Explorer preview plugin Copyright (C) 2021 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } library Preview; {$mode objfpc}{$H+} uses SysUtils, JwaWinUser, Windows, Messages, WlxPlugin, uPreviewHandler; const WH_KEYBOARD_LL = 13; PREVIEW_HANDLER = UnicodeString('IPreviewHandler'); type TPreviewData = class Handler: IPreviewHandler; end; var hhk: HHOOK; Count: Integer = 0; ProcessIdWide: PWideChar; ProcessIdAtom: ATOM absolute ProcessIdWide; procedure DLL_Entry_Hook(lpReserved : PtrInt); begin GlobalDeleteAtom(ProcessIdAtom); end; function LowLevelKeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var ParentWin: HWND; ProcessId: HANDLE; Msg: PKbDllHookStruct absolute lParam; function IsKeyUp(Key: Integer): Boolean; inline; begin Result := (GetKeyState(Key) and $8000) = 0; end; begin if (nCode = HC_ACTION) then begin if (wParam = WM_KEYDOWN) and (Msg^.vkCode = VK_ESCAPE) then begin ParentWin:= Windows.GetAncestor(GetForegroundWindow, GA_ROOT); ProcessId:= Windows.GetPropW(ParentWin, ProcessIdWide); if (ProcessId <> 0) and (ProcessId = GetProcessID) then begin if IsKeyUp(VK_MENU) and IsKeyUp(VK_CONTROL) and IsKeyUp(VK_MENU) then begin PostMessage(ParentWin, WM_SYSCOMMAND, SC_CLOSE, 0); end; end; end; end; Result:= CallNextHookEx(hhk, nCode, wParam, lParam); end; function WindowProc(hWnd: HWND; uiMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var ARect: TRect; AData: TPreviewData; AHandle: THandle absolute AData; begin if (uiMsg = WM_SETFOCUS) then begin AHandle:= GetWindowLongPtr(hWnd, GWLP_USERDATA); if (AHandle <> 0) then AData.Handler.SetFocus(); end else if (uiMsg = WM_SIZE) then begin AHandle:= GetWindowLongPtr(hWnd, GWLP_USERDATA); if (AHandle <> 0) then begin ARect.Top:= 0; ARect.Left:= 0; ARect.Width:= LOWORD(lParam); ARect.Height:= HIWORD(lParam); AData.Handler.SetRect(@ARect); end; end; Result := DefWindowProc(hWnd, uiMsg, wParam, lParam); end; function ListLoadW(ParentWin: HWND; FileToLoad: PWideChar; ShowFlags: Integer): HWND; stdcall; var ARect: TRect; AData: TPreviewData; WindowClassW: TWndClassW; AHandler: IPreviewHandler; AHandle: THandle absolute AData; begin AHandler:= GetPreviewHandler(FileToLoad); if (AHandler = nil) then Exit(wlxInvalidHandle); ZeroMemory(@WindowClassW, SizeOf(WndClassW)); with WindowClassW do begin Style := CS_DBLCLKS; lpfnWndProc := @WindowProc; cbWndExtra := SizeOf(Pointer); hCursor := LoadCursor(0, IDC_ARROW); lpszClassName := PREVIEW_HANDLER; hInstance := GetModuleHandleW(nil); end; Windows.RegisterClassW(WindowClassW); if not GetClientRect(ParentWin, ARect) then ARect:= TRect.Create(0, 0, 640, 480); Result:= CreateWindowW(PREVIEW_HANDLER, 'PreviewHandler', WS_CHILD or WS_VISIBLE, ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, ParentWin, 0, WindowClassW.hInstance, nil); if (Result <> wlxInvalidHandle) then begin AData:= TPreviewData.Create; AData.Handler:= AHandler; SetPropW(ParentWin, ProcessIdWide, GetProcessID); SetWindowLongPtr(Result, GWLP_USERDATA, AHandle); AHandler.SetWindow(Result, ARect); AData.Handler.DoPreview(); Inc(Count); if (Count = 1) then begin hhk:= SetWindowsHookExW(WH_KEYBOARD_LL, @LowLevelKeyboardProc, WindowClassW.hInstance, 0); end; end; end; procedure ListCloseWindow(ListWin: HWND); stdcall; var AData: TPreviewData; AHandle: THandle absolute AData; begin AHandle:= GetWindowLongPtr(ListWin, GWLP_USERDATA); DestroyWindow(ListWin); if Assigned(AData) then begin AData.Handler.Unload(); AData.Free; Dec(Count); if Count = 0 then begin UnhookWindowsHookEx(hhk); end; end; end; procedure ListGetDetectString(DetectString: PAnsiChar; MaxLen: Integer); stdcall; begin StrLCopy(DetectString, '(EXT="HTM")|(EXT="HTML")|(EXT="MHT")|(EXT="MHTML")', MaxLen); end; procedure ListSetDefaultParams(dps: PListDefaultParamStruct); stdcall; begin Dll_Process_Detach_Hook:= @DLL_Entry_Hook; ProcessIdAtom := GlobalAddAtomW(PREVIEW_HANDLER); end; exports ListLoadW, ListCloseWindow, ListGetDetectString, ListSetDefaultParams; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/preview/src/upreviewhandler.pas����������������������������������������0000644�0001750�0000144�00000012360�14743153644�023264� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Explorer preview handler Copyright (C) 2021 Alexander Koblov (alexx2000@mail.ru) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } unit uPreviewHandler; {$mode delphi} interface uses Classes, SysUtils, Windows, ShlObj, ActiveX; type IPreviewHandler = interface(IUnknown) ['{8895B1C6-B41F-4C1C-A562-0D564250836F}'] function SetWindow(hwnd: HWND; const prc: RECT): HRESULT; stdcall; function SetRect(const prc: PRECT): HRESULT; stdcall; function DoPreview(): HRESULT; stdcall; function Unload(): HRESULT; stdcall; function SetFocus(): HRESULT; stdcall; function QueryFocus(out phwnd: HWND): HRESULT; stdcall; function TranslateAccelerator(pmsg: PMSG): HRESULT; stdcall; end; function GetPreviewHandler(const FileName: UnicodeString): IPreviewHandler; implementation uses ComObj, DCConvertEncoding, DCClassesUtf8; type IInitializeWithFile = interface(IUnknown) ['{B7D14566-0509-4CCE-A71F-0A554233BD9B}'] function Initialize(pszFilePath: LPCWSTR; grfMode: DWORD): HRESULT; stdcall; end; IInitializeWithStream = interface(IUnknown) ['{B824B49D-22AC-4161-AC8A-9916E8FA3F7F}'] function Initialize(const pstream: IStream; grfMode: DWORD): HRESULT; stdcall; end; IInitializeWithItem = interface(IUnknown) ['{7F73BE3F-FB79-493C-A6C7-7EE14E245841}'] function Initialize(const psi: IShellItem; grfMode: DWORD): HRESULT; stdcall; end; var SHCreateItemFromParsingName: function(pszPath: LPCWSTR; const pbc: IBindCtx; const riid: TIID; out ppv): HRESULT; stdcall; function AssocQueryStringW(flags: DWORD; str: DWORD; pszAssoc: LPCWSTR; pszExtra: LPCWSTR; pszOut: LPWSTR; pcchOut: PDWORD): HRESULT; stdcall; external 'shlwapi.dll'; function GetShellClass(const FileExt: UnicodeString; interfaceID: TGUID): TGUID; const ASSOCSTR_SHELLEXTENSION = 16; ASSOCF_INIT_DEFAULTTOSTAR = $00000004; var Res: HRESULT; cchOut: DWORD = MAX_PATH; ABuffer: array[0..MAX_PATH] of WideChar; begin Res := AssocQueryStringW(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_SHELLEXTENSION, PWideChar(FileExt), PWideChar(CeUtf8ToUtf16(GuidToString(interfaceID))), ABuffer, @cchOut); if (Res <> S_OK) then Exit(Default(TGUID)); Res := CLSIDFromString(ABuffer, @Result); if (Res <> NOERROR) then Exit(Default(TGUID)); end; function GetPreviewHandler(const FileName: UnicodeString): IPreviewHandler; var Res: HRESULT; ClassID: TGUID; AStream: IStream; AFile: TFileStreamEx; AShellItem: IShellItem; AInitializeWithFile: IInitializeWithFile; AInitializeWithItem: IInitializeWithItem; AInitializeWithStream: IInitializeWithStream; begin ClassID:= GetShellClass(ExtractFileExt(FileName), IPreviewHandler); if IsEqualGUID(ClassID, Default(TGUID)) then Exit(nil); Result:= CreateComObject(ClassID) as IPreviewHandler; if Assigned(Result) then begin if Supports(Result, IInitializeWithFile, AInitializeWithFile) then Res:= AInitializeWithFile.Initialize(PWideChar(FileName), STGM_READ) else if Supports(Result, IInitializeWithStream, AInitializeWithStream) then try AFile:= TFileStreamEx.Create(CeUtf16ToUtf8(FileName), fmOpenRead or fmShareDenyNone); AStream:= TStreamAdapter.Create(AFile, soOwned) as IStream; Res:= AInitializeWithStream.Initialize(AStream, STGM_READ); except Res:= E_FAIL; end else if (Win32MajorVersion > 5) and Supports(Result, IInitializeWithItem, AInitializeWithItem) then begin Res:= SHCreateItemFromParsingName(PWideChar(FileName), nil, IShellItem, AShellItem); if Succeeded(Res) then Res:= AInitializeWithItem.Initialize(AShellItem, STGM_READ); end else begin Res:= E_FAIL; end; if not Succeeded(Res) then begin Result:= nil; AStream:= nil; end; end; end; initialization if (Win32MajorVersion > 5) then SHCreateItemFromParsingName:= GetProcAddress(GetModuleHandle('shell32.dll'), 'SHCreateItemFromParsingName'); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/richview/��������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016721� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/richview/src/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017510� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/richview/src/richview.lpi����������������������������������������������0000644�0001750�0000144�00000006257�14743153644�022050� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> <CompatibilityMode Value="True"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="RichView"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes Count="2"> <Item1 Name="Release" Default="True"/> <Item2 Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\richview.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <Units Count="1"> <Unit0> <Filename Value="richview.lpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\richview.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/richview/src/richview.lpr����������������������������������������������0000644�0001750�0000144�00000014164�14743153644�022055� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Rich Text Format plugin Copyright (C) 2022 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } library richview; {$mode objfpc}{$H+} uses RichEdit, Windows, Messages, WlxPlugin; type {$push}{$packrecords 4} TEditStream = record dwCookie : DWORD_PTR; dwError : DWORD; pfnCallback : EDITSTREAMCALLBACK; end; {$pop} var RichEditClass: PWideChar; function LoadLibraryX(const AName: PWideChar): HMODULE; begin Result:= LoadLibraryExW(AName, 0, LOAD_LIBRARY_SEARCH_SYSTEM32); end; function RichEditWndProc(hWnd: HWND; uiMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var AWndProc: Windows.WNDPROC; AHandle: LONG_PTR absolute AWndProc; begin if (uiMsg = WM_KEYDOWN) then begin if (wParam = VK_ESCAPE) then begin PostMessage(GetParent(hWnd), WM_SYSCOMMAND, SC_CLOSE, 0); end; end; AHandle := GetWindowLongPtr(hWnd, GWLP_USERDATA); if Assigned(AWndProc) then Result := CallWindowProc(AWndProc, hWnd, uiMsg, wParam, lParam) else begin Result := DefWindowProc(hWnd, uiMsg, wParam, lParam); end; end; function EditStreamCallback(dwCookie: DWORD_PTR; lpBuff: LPBYTE; cb: LONG; pcb: PLONG): DWORD; stdcall; var AFile: THandle absolute dwCookie; begin if (ReadFile(AFile, lpBuff^, cb, PDWORD(pcb)^, nil)) then Exit(0); Result:= DWORD(-1); end; function ListLoadW(ParentWin: HWND; FileToLoad: PWideChar; ShowFlags: Integer): HWND; stdcall; var ARect: TRect; AFile: THandle; AResult: Boolean; hInstance: HMODULE; AWndProc: LONG_PTR; AStream: TEditStream; begin if (RichEditClass = nil) then Exit(wlxInvalidHandle); AFile:= CreateFileW(FileToLoad, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); if (AFile = INVALID_HANDLE_VALUE) then Exit(wlxInvalidHandle); hInstance := GetModuleHandleW(nil); if not GetClientRect(ParentWin, @ARect) then ARect:= TRect.Create(0, 0, 640, 480); Result:= CreateWindowW(RichEditClass, nil, WS_CHILD or WS_HSCROLL or WS_VSCROLL or ES_READONLY or ES_MULTILINE or ES_AUTOHSCROLL or ES_AUTOVSCROLL or WS_TABSTOP, ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, ParentWin, hInstance, 0, nil); if (Result <> wlxInvalidHandle) then begin AStream.dwError := 0; AStream.dwCookie := DWORD_PTR(AFile); AStream.pfnCallback := @EditStreamCallback; AResult := (SendMessage(Result, EM_STREAMIN, SF_RTF, LPARAM(@AStream)) <> 0) and (AStream.dwError = 0); if AResult then begin AWndProc:= SetWindowLongPtr(Result, GWLP_WNDPROC, LONG_PTR(@RichEditWndProc)); SetWindowLongPtr(Result, GWLP_USERDATA, AWndProc); ShowWindow(Result, SW_SHOW); end else begin DestroyWindow(Result); Result:= wlxInvalidHandle; end; end; CloseHandle(AFile); end; function ListSearchTextW(ListWin: HWND; SearchString: PWideChar; SearchParameter: Integer): Integer; stdcall; var AMode: TFindTextExW; wParam: Windows.WPARAM; ARange: RichEdit.TCharRange; begin AMode:= Default(TFindTextExW); AMode.lpstrText:= SearchString; SendMessageW(ListWin, EM_EXGETSEL, 0, LPARAM(@ARange)); if (SearchParameter and lcs_findfirst <> 0) then begin if SearchParameter and lcs_backwards <> 0 then ARange.cpMin:= High(LONG) else ARange.cpMax:= 0; end; if SearchParameter and lcs_backwards <> 0 then begin wParam:= 0; AMode.chrg.cpMax:= 0; AMode.chrg.cpMin:= ARange.cpMin; end else begin wParam:= FR_DOWN; AMode.chrg.cpMax:= -1; AMode.chrg.cpMin:= ARange.cpMax; end; if (SearchParameter and lcs_matchcase <> 0) then wParam:= wParam or FR_MATCHCASE; if (SearchParameter and lcs_wholewords <> 0) then wParam:= wParam or FR_WHOLEWORD; if SendMessageW(ListWin, EM_FINDTEXTEXW, wParam, LPARAM(@AMode)) >= 0 then begin Result:= LISTPLUGIN_OK; SendMessageW(ListWin, EM_EXSETSEL, 0, LPARAM(@AMode.chrgText)); end else begin Result:= LISTPLUGIN_ERROR; end; end; function ListSendCommand(ListWin: HWND; Command, Parameter: Integer): Integer; stdcall; var ARange: TCharRange; begin case Command of lc_selectall: begin ARange.cpMin:= 0; ARange.cpMax:= -1; if SendMessageW(ListWin, EM_EXSETSEL, 0, LPARAM(@ARange)) >= 0 then Result:= LISTPLUGIN_OK else begin Result:= LISTPLUGIN_ERROR; end; end; lc_copy: begin if SendMessageW(ListWin, WM_COPY, 0, 0) <> 0 then Result:= LISTPLUGIN_OK else begin Result:= LISTPLUGIN_ERROR; end; end; else begin Result:= LISTPLUGIN_ERROR; end; end; end; procedure ListGetDetectString(DetectString: PAnsiChar; MaxLen: Integer); stdcall; begin lstrcpynA(DetectString, 'EXT="RTF"', MaxLen); end; procedure ListSetDefaultParams(dps: PListDefaultParamStruct); stdcall; begin // Rich Edit Version 4.1 if (LoadLibraryX('Msftedit.dll') <> NilHandle) then RichEditClass := 'RichEdit50W' // Rich Edit Version 2.0/3.0 else if (LoadLibraryX('riched20.dll') <> NilHandle) then RichEditClass := 'RichEdit20W' else begin RichEditClass := nil; end; end; exports ListLoadW, ListSearchTextW, ListSendCommand, ListGetDetectString, ListSetDefaultParams; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/simplewlx/�������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017125� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/simplewlx/src/���������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017714� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/simplewlx/src/simplewlx.lpi��������������������������������������������0000644�0001750�0000144�00000004105�14743153644�022446� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <General> <Flags> <LRSInOutputDirectory Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> </General> <VersionInfo> <Language Value=""/> <CharSet Value=""/> <StringTable ProductVersion=""/> </VersionInfo> <BuildModes Count="1"> <Item1 Name="default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <Units Count="1"> <Unit0> <Filename Value="simplewlx.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="SimpleWlx"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../simplewlx.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="../../../../sdk"/> <UnitOutputDirectory Value="../lib"/> </SearchPaths> <Conditionals Value="if (TargetCPU <> 'arm') then begin CustomOptions += '-fPIC'; end; if (TargetOS = 'darwin') then begin LinkerOptions += ' -no_order_inits'; end; if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end;"/> <Parsing> <SyntaxOptions> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <Linking> <LinkSmart Value="True"/> <Options> <PassLinkerOptions Value="True"/> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </CONFIG> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/simplewlx/src/simplewlx.lpr��������������������������������������������0000644�0001750�0000144�00000005325�14743153644�022464� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library SimpleWlx; {$mode objfpc}{$H+} {$include calling.inc} {$DEFINE GTK2} uses Classes, sysutils, {$IFDEF GTK} gtk,gdk,glib, {$ENDIF} {$IFDEF GTK2} gtk2,gdk2,glib2, {$ENDIF} WLXPlugin; var List:TStringList; //Custom class contains info for plugin windows type { TPlugInfo } TPlugInfo = class private fControls:TStringList; public fFileToLoad:string; fShowFlags:integer; //etc constructor Create; destructor Destroy; override; function AddControl(AItem:PGtkWidget):integer; end; { TPlugInfo } constructor TPlugInfo.Create; begin fControls:=TStringlist.Create; end; destructor TPlugInfo.Destroy; begin while fControls.Count>0 do begin gtk_widget_destroy(PGtkWidget(fControls.Objects[0])); fControls.Delete(0); end; inherited Destroy; end; function TPlugInfo.AddControl(AItem: PGtkWidget): integer; begin fControls.AddObject(inttostr(Integer(AItem)),TObject(AItem)); end; function ListLoad(ParentWin:thandle;FileToLoad:pchar;ShowFlags:integer):thandle; dcpcall; var GFix, GButton1, Gbutton2: PGtkWidget; begin // gFix:=gtk_fixed_new; gFix:=gtk_vbox_new(true,5); gtk_container_add(GTK_CONTAINER(PGtkWidget(ParentWin)),gFix); gtk_widget_show(gFix); GButton1:=gtk_button_new_with_label('Yehoo1'); gtk_container_add(GTK_CONTAINER(GFix),GButton1); gtk_widget_set_usize(GButton1,10,10); // gtk_widget_set_uposition(GButton1,30,10); gtk_widget_show(GButton1); Gbutton2:=gtk_button_new_with_label('Yehoo2'); gtk_container_add(GTK_CONTAINER(GFix),Gbutton2 ); gtk_widget_set_usize(GButton2,20,20); // gtk_widget_set_uposition(GButton2,50,50); gtk_widget_show(Gbutton2); //Create list if none if not assigned(List) then List:=TStringList.Create; //add to list new plugin window and it's info List.AddObject(IntToStr(integer(GFix)),TPlugInfo.Create); with TPlugInfo(List.Objects[List.Count-1]) do begin fFileToLoad:=FileToLoad; fShowFlags:=ShowFlags; AddControl(GFix); end; Result:= thandle(GFix); end; procedure ListCloseWindow(ListWin:thandle); dcpcall; var Index:integer; s:string; begin if assigned(List) then begin writeln('ListCloseWindow quit, List Item count: '+inttostr(List.Count)); s:=IntToStr(ListWin); Index:=List.IndexOf(s); if Index>-1 then begin TPlugInfo(List.Objects[index]).Free; List.Delete(Index); writeln('List item n: '+inttostr(Index)+' Deleted'); end; //Free list if it has zero items If List.Count=0 then FreeAndNil(List); end; end; exports ListLoad, ListCloseWindow; begin end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/simplewlx/src/wlxplugin.pas��������������������������������������������0000644�0001750�0000144�00000004443�14743153644�022457� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Lister API definitions. // This unit is written by Christian Ghisler, it's from Total Commander // Lister API Guide, which can be found at http://ghisler.com. // Version: 1.8. unit WLXPlugin; interface {$IFDEF MSWINDOWS} uses Windows;{$ENDIF} const lc_copy=1; lc_newparams=2; lc_selectall=3; lc_setpercent=4; lcp_wraptext=1; lcp_fittowindow=2; lcp_ansi=4; lcp_ascii=8; lcp_variable=12; lcp_forceshow=16; lcp_fitlargeronly=32; lcp_center=64; lcs_findfirst=1; lcs_matchcase=2; lcs_wholewords=4; lcs_backwards=8; itm_percent=$FFFE; itm_fontstyle=$FFFD; itm_wrap=$FFFC; itm_fit=$FFFB; itm_next=$FFFA; itm_center=$FFF9; LISTPLUGIN_OK=0; LISTPLUGIN_ERROR=1; const MAX_PATH=32000; type tListDefaultParamStruct=record size, PluginInterfaceVersionLow, PluginInterfaceVersionHi:longint; DefaultIniName:array[0..MAX_PATH-1] of char; end; pListDefaultParamStruct=^tListDefaultParamStruct; type tdateformat=record wYear,wMonth,wDay:word; end; pdateformat=^tdateformat; type ttimeformat=record wHour,wMinute,wSecond:word; end; ptimeformat=^ttimeformat; type HBITMAP = type LongWord; { Function prototypes: Functions need to be defined exactly like this!} { function ListLoad(ParentWin:thandle;FileToLoad:pchar;ShowFlags:integer):thandle; stdcall; function ListLoadNext(ParentWin,PluginWin:thandle;FileToLoad:pchar;ShowFlags:integer):integer; stdcall; procedure ListCloseWindow(ListWin:thandle); stdcall; procedure ListGetDetectString(DetectString:pchar;maxlen:integer); stdcall; function ListSearchText(ListWin:thandle;SearchString:pchar; SearchParameter:integer):integer; stdcall; function ListSearchDialog(ListWin:thandle;FindNext:integer):integer; stdcall; function ListSendCommand(ListWin:thandle;Command,Parameter:integer):integer; stdcall; function ListPrint(ListWin:thandle;FileToPrint,DefPrinter:pchar; PrintFlags:integer;var Margins:trect):integer; stdcall; function ListNotificationReceived(ListWin:thandle;Message,wParam,lParam:integer):integer; stdcall; procedure ListSetDefaultParams(dps:pListDefaultParamStruct); stdcall; function ListGetPreviewBitmap(FileToLoad:pchar;width,height:integer; contentbuf:pchar;contentbuflen:integer):hbitmap; stdcall; } implementation end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/wmp/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015704� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/wmp/src/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016473� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/wmp/src/activexcontainer.pas�������������������������������������������0000644�0001750�0000144�00000047554�14743153644�022565� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit activexcontainer; {$mode delphi}{$H+} { Visual ActiveX container. Copyright (C) 2011 Ludo Brands This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version with the following modification: As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules,and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. } interface uses Classes, SysUtils, Windows, ActiveX, ComObj; type //from OCIDL.h PPointF = ^TPointF; tagPOINTF = record x: Single; y: Single; end; TPointF = tagPOINTF; POINTF = TPointF; IOleControlSite = interface ['{B196B289-BAB4-101A-B69C-00AA00341D07}'] function OnControlInfoChanged: HResult; stdcall; function LockInPlaceActive(fLock: BOOL): HResult; stdcall; function GetExtendedControl(out disp: IDispatch): HResult; stdcall; function TransformCoords(var ptlHimetric: TPoint; var ptfContainer: TPointF; flags: Longint): HResult; stdcall; function TranslateAccelerator(msg: PMsg; grfModifiers: Longint): HResult; stdcall; function OnFocus(fGotFocus: BOOL): HResult; stdcall; function ShowPropertyFrame: HResult; stdcall; end; IPropertyNotifySink = interface ['{9BFBBC02-EFF1-101A-84ED-00AA00341D07}'] function OnChanged(dispid: TDispID): HResult; stdcall; function OnRequestEdit(dispid: TDispID): HResult; stdcall; end; ISimpleFrameSite = interface ['{742B0E01-14E6-101B-914E-00AA00300CAB}'] function PreMessageFilter(wnd: HWnd; msg, wp, lp: Integer; out res: Integer; out Cookie: Longint): HResult; stdcall; function PostMessageFilter(wnd: HWnd; msg, wp, lp: Integer; out res: Integer; Cookie: Longint): HResult; stdcall; end; TStatusTextEvent = procedure(Sender: TObject; Status:string) of object; { TActiveXContainer } TActiveXContainer = class(TComponent, IUnknown, IOleClientSite, IOleControlSite, IOleInPlaceSite, IOleInPlaceFrame, IDispatch) private FHandle: HWND; FPixelsPerInchX, FPixelsPerInchY: Integer; FActive: boolean; FAttached: boolean; FClassName: string; FOleObject: IDispatch; FOnStatusText: TStatusTextEvent; FPrevWndProc:windows.WNDPROC; Function GetvObject:variant; //IOleClientSite Function SaveObject: HResult;StdCall; Function GetMoniker(dwAssign: Longint; dwWhichMoniker: Longint;OUT mk: IMoniker):HResult;StdCall; Function GetContainer(OUT container: IOleContainer):HResult;StdCall; procedure SetActive(AValue: boolean); procedure SetClassName(AValue: string); procedure SetHandle(AValue: HWND); procedure SetOleObject(AValue: IDispatch); Function ShowObject:HResult;StdCall; Function OnShowWindow(fShow: BOOL):HResult;StdCall; Function RequestNewObjectLayout:HResult;StdCall; //IOleControlSite function OnControlInfoChanged: HResult; stdcall; function LockInPlaceActive(fLock: BOOL): HResult; stdcall; function GetExtendedControl(out disp: IDispatch): HResult; stdcall; function TransformCoords(var ptlHimetric: TPoint; var ptfContainer: TPointF; flags: Longint): HResult; stdcall; function TranslateAccelerator(msg: PMsg; grfModifiers: Longint): HResult;overload; stdcall; function OnFocus(fGotFocus: BOOL): HResult; stdcall; function ShowPropertyFrame: HResult; stdcall; //IOleInPlaceSite function CanInPlaceActivate : HResult;stdcall; function OnInPlaceActivate : HResult;stdcall; function OnUIActivate : HResult;stdcall; function GetWindowContext(out ppframe:IOleInPlaceFrame;out ppdoc:IOleInPlaceUIWindow;lprcposrect:LPRECT;lprccliprect:LPRECT;lpframeinfo:LPOLEINPLACEFRAMEINFO):hresult; stdcall; function Scroll(scrollExtant:TSIZE):hresult; stdcall; function OnUIDeactivate(fUndoable:BOOL):hresult; stdcall; function OnInPlaceDeactivate :hresult; stdcall; function DiscardUndoState :hresult; stdcall; function DeactivateAndUndo :hresult; stdcall; function OnPosRectChange(lprcPosRect:LPRect):hresult; stdcall; //IOleWindow function GetWindow(out wnd: HWnd): HResult; stdcall; function ContextSensitiveHelp(fEnterMode: BOOL): HResult; stdcall; //IOleInPlaceFrame function InsertMenus(hmenuShared: HMenu; var menuWidths: TOleMenuGroupWidths): HResult;StdCall; function SetMenu(hmenuShared: HMenu; holemenu: HMenu; hwndActiveObject: HWnd): HResult;StdCall; function RemoveMenus(hmenuShared: HMenu): HResult;StdCall; function SetStatusText(pszStatusText: POleStr): HResult;StdCall; function EnableModeless(fEnable: BOOL): HResult;StdCall; function TranslateAccelerator(var msg: TMsg; wID: Word): HResult;StdCall;overload; //IOleInPlaceUIWindow function GetBorder(out rectBorder: TRect):HResult;StdCall; function RequestBorderSpace(const borderwidths: TRect):HResult;StdCall; function SetBorderSpace(const borderwidths: TRect):HResult;StdCall; function SetActiveObject(const activeObject: IOleInPlaceActiveObject;pszObjName: POleStr):HResult;StdCall; //IDispatch function GetTypeInfoCount(out count : longint) : HResult;stdcall; function GetTypeInfo(Index,LocaleID : longint; out TypeInfo): HResult;stdcall; function GetIDsOfNames(const iid: TGUID; names: Pointer; NameCount, LocaleID: LongInt; DispIDs: Pointer) : HResult;stdcall; function Invoke(DispID: LongInt;const iid : TGUID; LocaleID : longint; Flags: Word;var params; VarResult,ExcepInfo,ArgErr : pointer) : HResult;stdcall; //internal procedure Attach; procedure Detach; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; //VT_DISPATCH variant used for late binding property vObject:Variant read GetvObject; published //ActiveX object is automatically created from classname and destroyed when set property OleClassName:string read FClassName write SetClassName; {IDispatch interface for ActiveX object. Overrides classname. Set ComServer when you create and destroy the object yourself, fe. using CoClass. When Active, returns the IDispatch for the object. } property ComServer:IDispatch read FOleObject write SetOleObject; {When set, binds ActiveX component to control. When cleared, detaches the component from the control If Classname is provided the ActiveX component will also be created and destroyed automatically.} property Active:boolean read FActive write SetActive; property Handle: HWND read FHandle write SetHandle; end; implementation {$ifdef wince} const GWLP_USERDATA=GWL_USERDATA; function GetWindowLongPtrW(hWnd:HWND; nIndex:longint):LONG; begin result:=GetWindowLongW(hWnd, nIndex); end; function SetWindowLongPtrW(hWnd:HWND; nIndex:longint; dwNewLong:LONG):LONG; begin result:=SetWindowLongW(hWnd, nIndex, dwNewLong); end; function SetWindowLongPtr(hWnd:HWND; nIndex:longint; dwNewLong:LONG):LONG; begin result:=SetWindowLongW(hWnd, nIndex, dwNewLong); end; {$endif wince} function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall; var bounds:TRect; DC: HDC; size:TPOINT; AXC:TActiveXContainer; begin AXC:=TActiveXContainer(GetWindowLongPtrW( Ahwnd, GWLP_USERDATA)); case uMsg of WM_DESTROY:AXC.Detach; WM_SIZE: begin size.x:=(LOWORD(lparam)*2540) div AXC.FPixelsPerInchX; size.y:=(HIWORD(lparam)*2540) div AXC.FPixelsPerInchY; MoveWindow(AXC.FHandle, 0, 0, LOWORD(lparam), HIWORD(lparam), True); olecheck((AXC.ComServer as IOleObject).SetExtent(DVASPECT_CONTENT,size)); GetClientRect(AXC.FHandle, @bounds); olecheck((AXC.ComServer as IOleInPlaceObject).SetObjectRects(@bounds,@bounds)); end; WM_PAINT: begin DC:=GetDC(AXC.handle); GetClientRect(AXC.FHandle, @bounds); olecheck((AXC.ComServer as IViewObject).Draw(DVASPECT_CONTENT,0,nil,nil,0,DC,@bounds,@bounds,nil,0)); ReleaseDC(AXC.handle,DC); end; end; result:=CallWindowProc(AXC.FPrevWndProc,Ahwnd, uMsg, WParam, LParam); end; { TActiveXContainer } function TActiveXContainer.GetvObject: variant; begin result:=FOleObject; end; function TActiveXContainer.SaveObject: HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.GetMoniker(dwAssign: Longint; dwWhichMoniker: Longint; out mk: IMoniker): HResult; StdCall; begin mk := nil; Result := E_NOTIMPL; end; function TActiveXContainer.GetContainer(out container: IOleContainer): HResult; StdCall; begin container := nil; Result := E_NOINTERFACE; end; procedure TActiveXContainer.SetActive(AValue: boolean); begin if FActive=AValue then Exit; if AValue then begin if (FClassName='') and not assigned(ComServer) then raise exception.Create('OleClassName and ComServer not assigned.'); if not assigned(FOleObject) then FOleObject:=CreateOleObject(FClassName); Attach; end else begin Detach; if FClassName<>'' then //destroy com object FOleObject:=nil; end; FActive:=AValue; end; procedure TActiveXContainer.SetClassName(AValue: string); begin if (FClassName=AValue) or FActive then Exit; FClassName:=AValue; end; procedure TActiveXContainer.SetHandle(AValue: HWND); var DC: HDC; begin if FHandle=AValue then Exit; FHandle:=AValue; DC:= GetDC(FHandle); FPixelsPerInchX := GetDeviceCaps(DC, LOGPIXELSX); FPixelsPerInchY := GetDeviceCaps(DC, LOGPIXELSY); ReleaseDC(FHandle, DC); end; procedure TActiveXContainer.SetOleObject(AValue: IDispatch); begin if (FOleObject=AValue) or FActive then Exit; FOleObject:=AValue; end; function TActiveXContainer.ShowObject: HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.OnShowWindow(fShow: BOOL): HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.RequestNewObjectLayout: HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.OnControlInfoChanged: HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.LockInPlaceActive(fLock: BOOL): HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.GetExtendedControl(out disp: IDispatch): HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.TransformCoords(var ptlHimetric: TPoint; var ptfContainer: TPointF; flags: Longint): HResult; stdcall; begin if flags and 4 <> 0 then //XFORMCOORDS_HIMETRICTOCONTAINER=4 begin ptfContainer.X := (ptlHimetric.X * FPixelsPerInchX) div 2540; ptfContainer.Y := (ptlHimetric.Y * FPixelsPerInchY) div 2540; end else if assigned(@ptlHimetric) and (flags and 8 <> 0) then //XFORMCOORDS_CONTAINERTOHIMETRIC = 8 begin ptlHimetric.X := Integer(Round(ptfContainer.X * 2540 / FPixelsPerInchX)); ptlHimetric.Y := Integer(Round(ptfContainer.Y * 2540 / FPixelsPerInchY)); end; Result := S_OK; end; function TActiveXContainer.TranslateAccelerator(msg: PMsg; grfModifiers: Longint ): HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.OnFocus(fGotFocus: BOOL): HResult; stdcall; begin Result := S_OK; end; function TActiveXContainer.ShowPropertyFrame: HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.CanInPlaceActivate: HResult;stdcall; begin Result := S_OK; end; function TActiveXContainer.OnInPlaceActivate: HResult;stdcall; begin Result := S_OK; end; function TActiveXContainer.OnUIActivate: HResult; stdcall; begin Result := S_OK; end; function TActiveXContainer.GetWindowContext(out ppframe: IOleInPlaceFrame; out ppdoc: IOleInPlaceUIWindow; lprcposrect: LPRECT; lprccliprect: LPRECT; lpframeinfo: LPOLEINPLACEFRAMEINFO): hresult; stdcall; begin if assigned (ppframe) then ppframe := Self as IOleInPlaceFrame; if assigned(ppdoc) then ppdoc:= nil; if assigned(lpframeinfo) then begin lpframeinfo.fMDIApp := False; lpframeinfo.cAccelEntries := 0; lpframeinfo.haccel := 0; lpframeinfo.hwndFrame := Handle; end; if assigned (lprcPosRect) then GetClientRect(FHandle, lprcPosRect); if assigned (lprcClipRect) then GetClientRect(FHandle, lprcClipRect); Result := S_OK; end; function TActiveXContainer.Scroll(scrollExtant: TSIZE): hresult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.OnUIDeactivate(fUndoable: BOOL): hresult; stdcall; begin Result := S_OK; end; function TActiveXContainer.OnInPlaceDeactivate: hresult; stdcall; begin Result := S_OK; end; function TActiveXContainer.DiscardUndoState: hresult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.DeactivateAndUndo: hresult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.OnPosRectChange(lprcPosRect: LPRect): hresult; stdcall; begin Result := S_OK; end; function TActiveXContainer.GetWindow(out wnd: HWnd): HResult; stdcall; begin wnd:=Handle; Result := S_OK; end; function TActiveXContainer.ContextSensitiveHelp(fEnterMode: BOOL): HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.InsertMenus(hmenuShared: HMenu; var menuWidths: TOleMenuGroupWidths): HResult; StdCall; begin Result := E_NOTIMPL; end; function TActiveXContainer.SetMenu(hmenuShared: HMenu; holemenu: HMenu; hwndActiveObject: HWnd): HResult; StdCall; begin Result := E_NOTIMPL; end; function TActiveXContainer.RemoveMenus(hmenuShared: HMenu): HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.SetStatusText(pszStatusText: POleStr): HResult; StdCall; begin if assigned(FOnStatusText) then FOnStatusText(Self,utf8encode(WideString(pszStatusText))); Result := S_OK; end; function TActiveXContainer.EnableModeless(fEnable: BOOL): HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.TranslateAccelerator(var msg: TMsg; wID: Word): HResult; StdCall; begin Result := E_NOTIMPL; end; function TActiveXContainer.GetBorder(out rectBorder: TRect): HResult; StdCall; begin Result := INPLACE_E_NOTOOLSPACE; end; function TActiveXContainer.RequestBorderSpace(const borderwidths: TRect): HResult; StdCall; begin Result := INPLACE_E_NOTOOLSPACE; end; function TActiveXContainer.SetBorderSpace(const borderwidths: TRect): HResult; StdCall; begin Result := E_NOTIMPL; end; function TActiveXContainer.SetActiveObject( const activeObject: IOleInPlaceActiveObject; pszObjName: POleStr): HResult; StdCall; begin Result := S_OK; end; function TActiveXContainer.GetTypeInfoCount(out count: longint): HResult; stdcall; begin Count := 0; Result := S_OK; end; function TActiveXContainer.GetTypeInfo(Index, LocaleID: longint; out TypeInfo ): HResult; stdcall; begin Pointer(TypeInfo) := nil; Result := E_NOTIMPL; end; function TActiveXContainer.GetIDsOfNames(const iid: TGUID; names: Pointer; NameCount, LocaleID: LongInt; DispIDs: Pointer): HResult; stdcall; begin Result := E_NOTIMPL; end; function TActiveXContainer.Invoke(DispID: LongInt; const iid: TGUID; LocaleID: longint; Flags: Word; var params; VarResult, ExcepInfo, ArgErr: pointer): HResult; stdcall; const DISPID_AMBIENT_BACKCOLOR = -701; DISPID_AMBIENT_DISPLAYNAME = -702; DISPID_AMBIENT_FONT = -703; DISPID_AMBIENT_FORECOLOR = -704; DISPID_AMBIENT_LOCALEID = -705; DISPID_AMBIENT_MESSAGEREFLECT = -706; DISPID_AMBIENT_USERMODE = -709; DISPID_AMBIENT_UIDEAD = -710; DISPID_AMBIENT_SHOWGRABHANDLES = -711; DISPID_AMBIENT_SHOWHATCHING = -712; DISPID_AMBIENT_SUPPORTSMNEMONICS = -714; DISPID_AMBIENT_AUTOCLIP = -715; begin if (Flags and DISPATCH_PROPERTYGET <> 0) and (VarResult <> nil) then begin Result := S_OK; case DispID of // DISPID_AMBIENT_BACKCOLOR: // PVariant(VarResult)^ := Color; DISPID_AMBIENT_DISPLAYNAME: PVariant(VarResult)^ := OleVariant(Name); DISPID_AMBIENT_FONT: PVariant(VarResult)^ :=nil; // DISPID_AMBIENT_FORECOLOR: // PVariant(VarResult)^ := Font.Color; DISPID_AMBIENT_LOCALEID: PVariant(VarResult)^ := Integer(GetUserDefaultLCID); DISPID_AMBIENT_MESSAGEREFLECT: PVariant(VarResult)^ := False; DISPID_AMBIENT_USERMODE: PVariant(VarResult)^ := not (csDesigning in ComponentState); DISPID_AMBIENT_UIDEAD: PVariant(VarResult)^ := csDesigning in ComponentState; DISPID_AMBIENT_SHOWGRABHANDLES: PVariant(VarResult)^ := False; DISPID_AMBIENT_SHOWHATCHING: PVariant(VarResult)^ := False; DISPID_AMBIENT_SUPPORTSMNEMONICS: PVariant(VarResult)^ := True; DISPID_AMBIENT_AUTOCLIP: PVariant(VarResult)^ := True; else Result := DISP_E_MEMBERNOTFOUND; end; end else Result := DISP_E_MEMBERNOTFOUND; end; procedure TActiveXContainer.Attach; var size:TPOINT; ARect: TRect; begin SetWindowLongPtr(Handle,GWLP_USERDATA, PtrInt(Self)); FPrevWndProc:=Windows.WNDPROC(SetWindowLongPtr(Handle,GWL_WNDPROC,PtrInt(@WndCallback))); FAttached:=true; olecheck((FOleObject as IOleObject).SetClientSite(Self as IOleClientSite)); olecheck((FOleObject as IOleObject).SetHostNames(PWideChar(name),PWideChar(name))); GetClientRect(FHandle, ARect); size.x:=(ARect.Width*2540) div FPixelsPerInchX; size.y:=(ARect.Height*2540) div FPixelsPerInchY; olecheck((FOleObject as IOleObject).SetExtent(DVASPECT_CONTENT,size)); olecheck((FOleObject as IOleObject).DoVerb(OLEIVERB_INPLACEACTIVATE,nil,Self as IOleClientSite,0,Handle,ARect)); end; procedure TActiveXContainer.Detach; const OLECLOSE_NOSAVE = 1; begin if FAttached then begin SetWindowLongPtr(Handle,GWL_WNDPROC,PtrInt(@FPrevWndProc)); SetWindowLongPtr(Handle,GWLP_USERDATA, 0); end; if assigned(FOleObject) then begin olecheck((FOleObject as IOleObject).SetClientSite(nil)); olecheck((FOleObject as IOleObject).Close(OLECLOSE_NOSAVE)); end; end; constructor TActiveXContainer.Create(TheOwner: TComponent); begin inherited Create(TheOwner); end; destructor TActiveXContainer.Destroy; begin Active:=false; //destroys com object if created by Self inherited Destroy; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/wmp/src/wmp.lpi��������������������������������������������������������0000644�0001750�0000144�00000006573�14743153644�020017� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> <MainUnitHasScaledStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="wmp"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes> <Item Name="Release" Default="True"/> <Item Name="Debug"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\wmp.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <TrashVariables Value="True"/> </Debugging> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> </Item> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <Units> <Unit> <Filename Value="wmp.lpr"/> <IsPartOfProject Value="True"/> </Unit> <Unit> <Filename Value="wmplib_1_0_tlb.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="WMPLib_1_0_TLB"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\wmp.wlx" ApplyConventions="False"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\..\..\sdk"/> <UnitOutputDirectory Value="..\lib"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <RelocatableUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <ExecutableType Value="Library"/> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/wmp/src/wmp.lpr��������������������������������������������������������0000644�0001750�0000144�00000010612�14743153644�020015� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Windows Media Player plugin Copyright (C) 2021-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } library wmp; {$mode objfpc}{$H+} uses Classes, WMPLib_1_0_TLB, ActiveXContainer, SysUtils, Windows, WlxPlugin, IniFiles; const CLASS_NAME = UnicodeString('IWMPPlayer4'); var Volume: Integer = 50; ConfigFile: AnsiString; procedure LoadConfiguration; begin try with TIniFile.Create(ConfigFile) do try Volume:= ReadInteger('WMP', 'Volume', Volume); finally Free; end; except // Ignore end; end; procedure SaveConfiguration; begin try with TIniFile.Create(ConfigFile) do try WriteInteger('WMP', 'Volume', Volume); finally Free; end; except // Ignore end; end; function ListLoadW(ParentWin: HWND; FileToLoad: PWideChar; ShowFlags: Integer): HWND; stdcall; var ARect: TRect; APlayer: IWMPPlayer4; AData: TActiveXContainer; WindowClassW: TWndClassW; begin try APlayer:= CoWindowsMediaPlayer.Create; except Exit(wlxInvalidHandle); end; ZeroMemory(@WindowClassW, SizeOf(WndClassW)); with WindowClassW do begin Style := CS_DBLCLKS; lpfnWndProc := @DefWindowProc; cbWndExtra := SizeOf(Pointer); hCursor := LoadCursor(0, IDC_ARROW); lpszClassName := CLASS_NAME; hInstance := GetModuleHandleW(nil); end; Windows.RegisterClassW(WindowClassW); if not GetClientRect(ParentWin, ARect) then ARect:= TRect.Create(0, 0, 640, 480); Result:= CreateWindowW(CLASS_NAME, 'PreviewHandler', WS_CHILD or WS_VISIBLE, ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, ParentWin, 0, WindowClassW.hInstance, nil); if (Result <> wlxInvalidHandle) then begin AData:= TActiveXContainer.Create(nil); AData.Handle:= Result; AData.ComServer:= APlayer; try AData.Active:= True; APlayer.settings.volume:= Volume; APlayer.URL:= WideString(FileToLoad); APlayer.Controls.Play; except AData.Free; DestroyWindow(Result); Result:= wlxInvalidHandle; end; end; end; procedure ListCloseWindow(ListWin: HWND); stdcall; var AVolume: Integer; AData: TActiveXContainer; AHandle: THandle absolute AData; begin AHandle:= GetWindowLongPtr(ListWin, GWLP_USERDATA); if Assigned(AData) then begin AVolume:= (AData.ComServer as IWMPPlayer4).settings.volume; if AVolume <> Volume then begin Volume:= AVolume; SaveConfiguration; end; AData.Free; end; DestroyWindow(ListWin); end; function ListLoadNextW(ParentWin, PluginWin: HWND; FileToLoad: PWideChar; ShowFlags: Integer): Integer; stdcall; var APlayer: IWMPPlayer4; AData: TActiveXContainer; AHandle: THandle absolute AData; begin AHandle:= GetWindowLongPtr(PluginWin, GWLP_USERDATA); if Assigned(AData) then begin APlayer:= AData.ComServer as IWMPPlayer4; try APlayer.Controls.Stop; APlayer.URL:= WideString(FileToLoad); APlayer.Controls.Play; except Exit(LISTPLUGIN_ERROR); end; end; Result:= LISTPLUGIN_OK; end; procedure ListSetDefaultParams(dps: PListDefaultParamStruct); stdcall; begin // Save configuration file name ConfigFile:= dps^.DefaultIniName; LoadConfiguration; end; procedure ListGetDetectString(DetectString: PAnsiChar; MaxLen: Integer); stdcall; begin StrLCopy(DetectString, '(EXT="WAV")|(EXT="MP3")|(EXT="WMA")|(EXT="MP4")|(EXT="AVI")|(EXT="WMV")', MaxLen); end; exports ListLoadW, ListLoadNextW, ListCloseWindow, ListGetDetectString, ListSetDefaultParams; end. ����������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/plugins/wlx/wmp/src/wmplib_1_0_tlb.pas���������������������������������������������0000644�0001750�0000144�00002240503�14743153644�022000� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit WMPLib_1_0_TLB; // Imported WMPLib on 29.08.2021 15:27:47 from C:\WINDOWS\system32\wmp.dll {$mode delphi}{$H+} interface Uses Windows,ActiveX,Classes,Variants,stdole2,EventSink; Const WMPLibMajorVersion = 1; WMPLibMinorVersion = 0; WMPLibLCID = 0; LIBID_WMPLib : TGUID = '{6BF52A50-394A-11D3-B153-00C04F79FAA6}'; IID_IWMPEvents : TGUID = '{19A6627B-DA9E-47C1-BB23-00B5E668236A}'; IID_IWMPEvents2 : TGUID = '{1E7601FA-47EA-4107-9EA9-9004ED9684FF}'; IID_IWMPSyncDevice : TGUID = '{82A2986C-0293-4FD0-B279-B21B86C058BE}'; IID_IWMPEvents3 : TGUID = '{1F504270-A66B-4223-8E96-26A06C63D69F}'; IID_IWMPCdromRip : TGUID = '{56E2294F-69ED-4629-A869-AEA72C0DCC2C}'; IID_IWMPCdromBurn : TGUID = '{BD94DBEB-417F-4928-AA06-087D56ED9B59}'; IID_IWMPPlaylist : TGUID = '{D5F0F4F1-130C-11D3-B14E-00C04F79FAA6}'; IID_IWMPMedia : TGUID = '{94D55E95-3FAC-11D3-B155-00C04F79FAA6}'; IID_IWMPLibrary : TGUID = '{3DF47861-7DF1-4C1F-A81B-4C26F0F7A7C6}'; IID_IWMPMediaCollection : TGUID = '{8363BC22-B4B4-4B19-989D-1CD765749DD1}'; IID_IWMPStringCollection : TGUID = '{4A976298-8C0D-11D3-B389-00C04F68574B}'; IID_IWMPEvents4 : TGUID = '{26DABCFA-306B-404D-9A6F-630A8405048D}'; IID__WMPOCXEvents : TGUID = '{6BF52A51-394A-11D3-B153-00C04F79FAA6}'; CLASS_WindowsMediaPlayer : TGUID = '{6BF52A52-394A-11D3-B153-00C04F79FAA6}'; IID_IWMPPlayer4 : TGUID = '{6C497D62-8919-413C-82DB-E935FB3EC584}'; IID_IWMPCore3 : TGUID = '{7587C667-628F-499F-88E7-6A6F4E888464}'; IID_IWMPCore2 : TGUID = '{BC17E5B7-7561-4C18-BB90-17D485775659}'; IID_IWMPCore : TGUID = '{D84CCA99-CCE2-11D2-9ECC-0000F8085981}'; IID_IWMPControls : TGUID = '{74C09E02-F828-11D2-A74B-00A0C905F36E}'; IID_IWMPSettings : TGUID = '{9104D1AB-80C9-4FED-ABF0-2E6417A6DF14}'; IID_IWMPPlaylistCollection : TGUID = '{10A13217-23A7-439B-B1C0-D847C79B7774}'; IID_IWMPPlaylistArray : TGUID = '{679409C0-99F7-11D3-9FB7-00105AA620BB}'; IID_IWMPNetwork : TGUID = '{EC21B779-EDEF-462D-BBA4-AD9DDE2B29A7}'; IID_IWMPCdromCollection : TGUID = '{EE4C8FE2-34B2-11D3-A3BF-006097C9B344}'; IID_IWMPCdrom : TGUID = '{CFAB6E98-8730-11D3-B388-00C04F68574B}'; IID_IWMPClosedCaption : TGUID = '{4F2DF574-C588-11D3-9ED0-00C04FB6E937}'; IID_IWMPError : TGUID = '{A12DCF7D-14AB-4C1B-A8CD-63909F06025B}'; IID_IWMPErrorItem : TGUID = '{3614C646-3B3B-4DE7-A81E-930E3F2127B3}'; IID_IWMPDVD : TGUID = '{8DA61686-4668-4A5C-AE5D-803193293DBE}'; IID_IWMPPlayerApplication : TGUID = '{40897764-CEAB-47BE-AD4A-8E28537F9BBF}'; IID_IWMPPlayer3 : TGUID = '{54062B68-052A-4C25-A39F-8B63346511D4}'; IID_IWMPPlayer2 : TGUID = '{0E6B01D1-D407-4C85-BF5F-1C01F6150280}'; IID_IWMPPlayer : TGUID = '{6BF52A4F-394A-11D3-B153-00C04F79FAA6}'; IID_IWMPErrorItem2 : TGUID = '{F75CCEC0-C67C-475C-931E-8719870BEE7D}'; IID_IWMPControls2 : TGUID = '{6F030D25-0890-480F-9775-1F7E40AB5B8E}'; IID_IWMPMedia2 : TGUID = '{AB7C88BB-143E-4EA4-ACC3-E4350B2106C3}'; IID_IWMPMedia3 : TGUID = '{F118EFC7-F03A-4FB4-99C9-1C02A5C1065B}'; IID_IWMPMetadataPicture : TGUID = '{5C29BBE0-F87D-4C45-AA28-A70F0230FFA9}'; IID_IWMPMetadataText : TGUID = '{769A72DB-13D2-45E2-9C48-53CA9D5B7450}'; IID_IWMPSettings2 : TGUID = '{FDA937A4-EECE-4DA5-A0B6-39BF89ADE2C2}'; IID_IWMPControls3 : TGUID = '{A1D1110E-D545-476A-9A78-AC3E4CB1E6BD}'; IID_IWMPClosedCaption2 : TGUID = '{350BA78B-6BC8-4113-A5F5-312056934EB6}'; IID_IWMPMediaCollection2 : TGUID = '{8BA957F5-FD8C-4791-B82D-F840401EE474}'; IID_IWMPQuery : TGUID = '{A00918F3-A6B0-4BFB-9189-FD834C7BC5A5}'; IID_IWMPStringCollection2 : TGUID = '{46AD648D-53F1-4A74-92E2-2A1B68D63FD4}'; IID_IWMPPlayerServices : TGUID = '{1D01FBDB-ADE2-4C8D-9842-C190B95C3306}'; IID_IWMPPlayerServices2 : TGUID = '{1BB1592F-F040-418A-9F71-17C7512B4D70}'; IID_IWMPRemoteMediaServices : TGUID = '{CBB92747-741F-44FE-AB5B-F1A48F3B2A59}'; IID_IWMPSyncServices : TGUID = '{8B5050FF-E0A4-4808-B3A8-893A9E1ED894}'; IID_IWMPLibraryServices : TGUID = '{39C2F8D5-1CF2-4D5E-AE09-D73492CF9EAA}'; IID_IWMPLibrarySharingServices : TGUID = '{82CBA86B-9F04-474B-A365-D6DD1466E541}'; IID_IWMPLibrary2 : TGUID = '{DD578A4E-79B1-426C-BF8F-3ADD9072500B}'; IID_IWMPFolderMonitorServices : TGUID = '{788C8743-E57F-439D-A468-5BC77F2E59C6}'; IID_IWMPSyncDevice2 : TGUID = '{88AFB4B2-140A-44D2-91E6-4543DA467CD1}'; IID_IWMPSyncDevice3 : TGUID = '{B22C85F9-263C-4372-A0DA-B518DB9B4098}'; IID_IWMPPlaylistCtrl : TGUID = '{5F9CFD92-8CAD-11D3-9A7E-00C04F8EFB70}'; IID_IAppDispatch : TGUID = '{E41C88DD-2364-4FF7-A0F5-CA9859AF783F}'; IID_IWMPSafeBrowser : TGUID = '{EF870383-83AB-4EA9-BE48-56FA4251AF10}'; IID_IWMPObjectExtendedProps : TGUID = '{21D077C1-4BAA-11D3-BD45-00C04F6EA5AE}'; IID_IWMPLayoutSubView : TGUID = '{72F486B1-0D43-11D3-BD3F-00C04F6EA5AE}'; IID_IWMPLayoutView : TGUID = '{172E905D-80D9-4C2F-B7CE-2CCB771787A2}'; IID_IWMPEventObject : TGUID = '{5AF0BEC1-46AA-11D3-BD45-00C04F6EA5AE}'; IID_IWMPTheme : TGUID = '{6FCAE13D-E492-4584-9C21-D2C052A2A33A}'; IID_IWMPLayoutSettingsDispatch : TGUID = '{B2C2D18E-97AF-4B6A-A56B-2FFFF470FB81}'; IID_IWMPWindow : TGUID = '{43D5AE92-4332-477C-8883-E0B3B063C5D2}'; IID_IWMPBrandDispatch : TGUID = '{98BB02D4-ED74-43CC-AD6A-45888F2E0DCC}'; IID_IWMPNowPlayingHelperDispatch : TGUID = '{504F112E-77CC-4E3C-A073-5371B31D9B36}'; IID_IWMPNowDoingDispatch : TGUID = '{2A2E0DA3-19FA-4F82-BE18-CD7D7A3B977F}'; IID_IWMPHoverPreviewDispatch : TGUID = '{946B023E-044C-4473-8018-74954F09DC7E}'; IID_IWMPButtonCtrlEvents : TGUID = '{BB17FFF7-1692-4555-918A-6AF7BFACEDD2}'; CLASS_WMPButtonCtrl : TGUID = '{87291B51-0C8E-11D3-BB2A-00A0C93CA73A}'; IID_IWMPButtonCtrl : TGUID = '{87291B50-0C8E-11D3-BB2A-00A0C93CA73A}'; CLASS_WMPListBoxCtrl : TGUID = '{FC1880CF-83B9-43A7-A066-C44CE8C82583}'; IID_IWMPListBoxCtrl : TGUID = '{FC1880CE-83B9-43A7-A066-C44CE8C82583}'; IID_IWMPListBoxItem : TGUID = '{D255DFB8-C22A-42CF-B8B7-F15D7BCF65D6}'; IID_IWMPPlaylistCtrlColumn : TGUID = '{63D9D30F-AE4C-4678-8CA8-5720F4FE4419}'; IID_IWMPSliderCtrlEvents : TGUID = '{CDAC14D2-8BE4-11D3-BB48-00A0C93CA73A}'; CLASS_WMPSliderCtrl : TGUID = '{F2BF2C90-405F-11D3-BB39-00A0C93CA73A}'; IID_IWMPSliderCtrl : TGUID = '{F2BF2C8F-405F-11D3-BB39-00A0C93CA73A}'; IID_IWMPVideoCtrlEvents : TGUID = '{A85C0477-714C-4A06-B9F6-7C8CA38B45DC}'; CLASS_WMPVideoCtrl : TGUID = '{61CECF11-FC3A-11D2-A1CD-005004602752}'; IID_IWMPVideoCtrl : TGUID = '{61CECF10-FC3A-11D2-A1CD-005004602752}'; CLASS_WMPEffects : TGUID = '{47DEA830-D619-4154-B8D8-6B74845D6A2D}'; IID_IWMPEffectsCtrl : TGUID = '{A9EFAB80-0A60-4C3F-BBD1-4558DD2A9769}'; CLASS_WMPEqualizerSettingsCtrl : TGUID = '{93EB32F5-87B1-45AD-ACC6-0F2483DB83BB}'; IID_IWMPEqualizerSettingsCtrl : TGUID = '{2BD3716F-A914-49FB-8655-996D5F495498}'; CLASS_WMPVideoSettingsCtrl : TGUID = '{AE7BFAFE-DCC8-4A73-92C8-CC300CA88859}'; IID_IWMPVideoSettingsCtrl : TGUID = '{07EC23DA-EF73-4BDE-A40F-F269E0B7AFD6}'; CLASS_WMPLibraryTreeCtrl : TGUID = '{D9DE732A-AEE9-4503-9D11-5605589977A8}'; IID_IWMPLibraryTreeCtrl : TGUID = '{B738FCAE-F089-45DF-AED6-034B9E7DB632}'; CLASS_WMPEditCtrl : TGUID = '{6342FCED-25EA-4033-BDDB-D049A14382D3}'; IID_IWMPEditCtrl : TGUID = '{70E1217C-C617-4CFD-BD8A-69CA2043E70B}'; CLASS_WMPSkinList : TGUID = '{A8A55FAC-82EA-4BD7-BD7B-11586A4D99E4}'; IID_IWMPSkinList : TGUID = '{8CEA03A2-D0C5-4E97-9C38-A676A639A51D}'; IID_IWMPPluginUIHost : TGUID = '{5D0AD945-289E-45C5-A9C6-F301F0152108}'; CLASS_WMPMenuCtrl : TGUID = '{BAB3768B-8883-4AEC-9F9B-E14C947913EF}'; IID_IWMPMenuCtrl : TGUID = '{158A7ADC-33DA-4039-A553-BDDBBE389F5C}'; CLASS_WMPAutoMenuCtrl : TGUID = '{6B28F900-8D64-4B80-9963-CC52DDD1FBB4}'; IID_IWMPAutoMenuCtrl : TGUID = '{1AD13E0B-4F3A-41DF-9BE2-F9E6FE0A7875}'; CLASS_WMPRegionalButtonCtrl : TGUID = '{AE3B6831-25A9-11D3-BD41-00C04F6EA5AE}'; IID_IWMPRegionalButtonCtrl : TGUID = '{58D507B1-2354-11D3-BD41-00C04F6EA5AE}'; IID_IWMPRegionalButtonEvents : TGUID = '{50FC8D31-67AC-11D3-BD4C-00C04F6EA5AE}'; CLASS_WMPRegionalButton : TGUID = '{09AEFF11-69EF-11D3-BD4D-00C04F6EA5AE}'; IID_IWMPRegionalButton : TGUID = '{58D507B2-2354-11D3-BD41-00C04F6EA5AE}'; IID_IWMPCustomSliderCtrlEvents : TGUID = '{95F45AA4-ED0A-11D2-BA67-0000F80855E6}'; CLASS_WMPCustomSliderCtrl : TGUID = '{95F45AA3-ED0A-11D2-BA67-0000F80855E6}'; IID_IWMPCustomSlider : TGUID = '{95F45AA2-ED0A-11D2-BA67-0000F80855E6}'; CLASS_WMPTextCtrl : TGUID = '{DDDA102E-0E17-11D3-A2E2-00C04F79F88E}'; IID_IWMPTextCtrl : TGUID = '{237DAC8E-0E32-11D3-A2E2-00C04F79F88E}'; CLASS_WMPPlaylistCtrl : TGUID = '{5F9CFD93-8CAD-11D3-9A7E-00C04F8EFB70}'; IID_ITaskCntrCtrl : TGUID = '{891EADB1-1C45-48B0-B704-49A888DA98C4}'; IID__WMPCoreEvents : TGUID = '{D84CCA96-CCE2-11D2-9ECC-0000F8085981}'; CLASS_WMPCore : TGUID = '{09428D37-E0B9-11D2-B147-00C04F79FAA6}'; IID_IWMPGraphEventHandler : TGUID = '{6B550945-018F-11D3-B14A-00C04F79FAA6}'; IID_IBattery : TGUID = '{F8578BFA-CD8F-4CE1-A684-5B7E85FCA7DC}'; IID_IBatteryPreset : TGUID = '{40C6BDE7-9C90-49D4-AD20-BEF81A6C5F22}'; IID_IBatteryRandomPreset : TGUID = '{F85E2D65-207D-48DB-84B1-915E1735DB17}'; IID_IBatterySavedPreset : TGUID = '{876E7208-0172-4EBB-B08B-2E1D30DFE44C}'; IID_IBarsEffect : TGUID = '{33E9291A-F6A9-11D2-9435-00A0C92A2F2D}'; IID_IWMPExternal : TGUID = '{E2CC638C-FD2C-409B-A1EA-5DDB72DC8E84}'; IID_IWMPExternalColors : TGUID = '{D10CCDFF-472D-498C-B5FE-3630E5405E0A}'; IID_IWMPSubscriptionServiceLimited : TGUID = '{54DF358E-CF38-4010-99F1-F44B0E9000E5}'; IID_IWMPSubscriptionServiceExternal : TGUID = '{2E922378-EE70-4CEB-BBAB-CE7CE4A04816}'; IID_IWMPDownloadManager : TGUID = '{E15E9AD1-8F20-4CC4-9EC7-1A328CA86A0D}'; IID_IWMPDownloadCollection : TGUID = '{0A319C7F-85F9-436C-B88E-82FD88000E1C}'; IID_IWMPDownloadItem2 : TGUID = '{9FBB3336-6DA3-479D-B8FF-67D46E20A987}'; IID_IWMPDownloadItem : TGUID = '{C9470E8E-3F6B-46A9-A0A9-452815C34297}'; IID_IWMPSubscriptionServicePlayMedia : TGUID = '{5F0248C1-62B3-42D7-B927-029119E6AD14}'; IID_IWMPDiscoExternal : TGUID = '{A915CEA2-72DF-41E1-A576-EF0BAE5E5169}'; IID_IWMPCDDVDWizardExternal : TGUID = '{2D7EF888-1D3C-484A-A906-9F49D99BB344}'; IID_IWMPBaseExternal : TGUID = '{F81B2A59-02BC-4003-8B2F-C124AF66FC66}'; IID_IWMPOfflineExternal : TGUID = '{3148E685-B243-423D-8341-8480D6EFF674}'; IID_IWMPDMRAVTransportService : TGUID = '{4E195DB1-9E29-47FC-9CE1-DE9937D32925}'; IID_IWMPDMRConnectionManagerService : TGUID = '{FB61CD38-8DE7-4479-8B76-A8D097C20C70}'; IID_IWMPDMRRenderingControlService : TGUID = '{FF4B1BDA-19F0-42CF-8DDA-19162950C543}'; //Enums Type WMPPlaylistChangeEventType =LongWord; Const wmplcUnknown = $0000000000000000; wmplcClear = $0000000000000001; wmplcInfoChange = $0000000000000002; wmplcMove = $0000000000000003; wmplcDelete = $0000000000000004; wmplcInsert = $0000000000000005; wmplcAppend = $0000000000000006; wmplcPrivate = $0000000000000007; wmplcNameChange = $0000000000000008; wmplcMorph = $0000000000000009; wmplcSort = $000000000000000A; wmplcLast = $000000000000000B; Type WMPDeviceStatus =LongWord; Const wmpdsUnknown = $0000000000000000; wmpdsPartnershipExists = $0000000000000001; wmpdsPartnershipDeclined = $0000000000000002; wmpdsPartnershipAnother = $0000000000000003; wmpdsManualDevice = $0000000000000004; wmpdsNewDevice = $0000000000000005; wmpdsLast = $0000000000000006; Type WMPSyncState =LongWord; Const wmpssUnknown = $0000000000000000; wmpssSynchronizing = $0000000000000001; wmpssStopped = $0000000000000002; wmpssEstimating = $0000000000000003; wmpssLast = $0000000000000004; Type WMPRipState =LongWord; Const wmprsUnknown = $0000000000000000; wmprsRipping = $0000000000000001; wmprsStopped = $0000000000000002; Type WMPBurnFormat =LongWord; Const wmpbfAudioCD = $0000000000000000; wmpbfDataCD = $0000000000000001; Type WMPBurnState =LongWord; Const wmpbsUnknown = $0000000000000000; wmpbsBusy = $0000000000000001; wmpbsReady = $0000000000000002; wmpbsWaitingForDisc = $0000000000000003; wmpbsRefreshStatusPending = $0000000000000004; wmpbsPreparingToBurn = $0000000000000005; wmpbsBurning = $0000000000000006; wmpbsStopped = $0000000000000007; wmpbsErasing = $0000000000000008; wmpbsDownloading = $0000000000000009; Type WMPLibraryType =LongWord; Const wmpltUnknown = $0000000000000000; wmpltAll = $0000000000000001; wmpltLocal = $0000000000000002; wmpltRemote = $0000000000000003; wmpltDisc = $0000000000000004; wmpltPortableDevice = $0000000000000005; Type WMPFolderScanState =LongWord; Const wmpfssUnknown = $0000000000000000; wmpfssScanning = $0000000000000001; wmpfssUpdating = $0000000000000002; wmpfssStopped = $0000000000000003; Type WMPStringCollectionChangeEventType =LongWord; Const wmpsccetUnknown = $0000000000000000; wmpsccetInsert = $0000000000000001; wmpsccetChange = $0000000000000002; wmpsccetDelete = $0000000000000003; wmpsccetClear = $0000000000000004; wmpsccetBeginUpdates = $0000000000000005; wmpsccetEndUpdates = $0000000000000006; Type WMPOpenState =LongWord; Const wmposUndefined = $0000000000000000; wmposPlaylistChanging = $0000000000000001; wmposPlaylistLocating = $0000000000000002; wmposPlaylistConnecting = $0000000000000003; wmposPlaylistLoading = $0000000000000004; wmposPlaylistOpening = $0000000000000005; wmposPlaylistOpenNoMedia = $0000000000000006; wmposPlaylistChanged = $0000000000000007; wmposMediaChanging = $0000000000000008; wmposMediaLocating = $0000000000000009; wmposMediaConnecting = $000000000000000A; wmposMediaLoading = $000000000000000B; wmposMediaOpening = $000000000000000C; wmposMediaOpen = $000000000000000D; wmposBeginCodecAcquisition = $000000000000000E; wmposEndCodecAcquisition = $000000000000000F; wmposBeginLicenseAcquisition = $0000000000000010; wmposEndLicenseAcquisition = $0000000000000011; wmposBeginIndividualization = $0000000000000012; wmposEndIndividualization = $0000000000000013; wmposMediaWaiting = $0000000000000014; wmposOpeningUnknownURL = $0000000000000015; Type WMPPlayState =LongWord; Const wmppsUndefined = $0000000000000000; wmppsStopped = $0000000000000001; wmppsPaused = $0000000000000002; wmppsPlaying = $0000000000000003; wmppsScanForward = $0000000000000004; wmppsScanReverse = $0000000000000005; wmppsBuffering = $0000000000000006; wmppsWaiting = $0000000000000007; wmppsMediaEnded = $0000000000000008; wmppsTransitioning = $0000000000000009; wmppsReady = $000000000000000A; wmppsReconnecting = $000000000000000B; wmppsLast = $000000000000000C; Type WMPSubscriptionDownloadState =LongWord; Const wmpsdlsDownloading = $0000000000000000; wmpsdlsPaused = $0000000000000001; wmpsdlsProcessing = $0000000000000002; wmpsdlsCompleted = $0000000000000003; wmpsdlsCancelled = $0000000000000004; Type WMP_WRITENAMESEX_TYPE =LongWord; Const WMP_WRITENAMES_TYPE_CD_BY_TOC = $0000000000000000; WMP_WRITENAMES_TYPE_CD_BY_CONTENT_ID = $0000000000000001; WMP_WRITENAMES_TYPE_CD_BY_MDQCD = $0000000000000002; WMP_WRITENAMES_TYPE_DVD_BY_DVDID = $0000000000000003; //Forward declarations Type IWMPEvents = interface; IWMPEvents2 = interface; IWMPSyncDevice = interface; IWMPEvents3 = interface; IWMPCdromRip = interface; IWMPCdromBurn = interface; IWMPPlaylist = interface; IWMPPlaylistDisp = dispinterface; IWMPMedia = interface; IWMPMediaDisp = dispinterface; IWMPLibrary = interface; IWMPMediaCollection = interface; IWMPMediaCollectionDisp = dispinterface; IWMPStringCollection = interface; IWMPStringCollectionDisp = dispinterface; IWMPEvents4 = interface; _WMPOCXEvents = dispinterface; IWMPPlayer4 = interface; IWMPPlayer4Disp = dispinterface; IWMPCore3 = interface; IWMPCore3Disp = dispinterface; IWMPCore2 = interface; IWMPCore2Disp = dispinterface; IWMPCore = interface; IWMPCoreDisp = dispinterface; IWMPControls = interface; IWMPControlsDisp = dispinterface; IWMPSettings = interface; IWMPSettingsDisp = dispinterface; IWMPPlaylistCollection = interface; IWMPPlaylistCollectionDisp = dispinterface; IWMPPlaylistArray = interface; IWMPPlaylistArrayDisp = dispinterface; IWMPNetwork = interface; IWMPNetworkDisp = dispinterface; IWMPCdromCollection = interface; IWMPCdromCollectionDisp = dispinterface; IWMPCdrom = interface; IWMPCdromDisp = dispinterface; IWMPClosedCaption = interface; IWMPClosedCaptionDisp = dispinterface; IWMPError = interface; IWMPErrorDisp = dispinterface; IWMPErrorItem = interface; IWMPErrorItemDisp = dispinterface; IWMPDVD = interface; IWMPDVDDisp = dispinterface; IWMPPlayerApplication = interface; IWMPPlayerApplicationDisp = dispinterface; IWMPPlayer3 = interface; IWMPPlayer3Disp = dispinterface; IWMPPlayer2 = interface; IWMPPlayer2Disp = dispinterface; IWMPPlayer = interface; IWMPPlayerDisp = dispinterface; IWMPErrorItem2 = interface; IWMPErrorItem2Disp = dispinterface; IWMPControls2 = interface; IWMPControls2Disp = dispinterface; IWMPMedia2 = interface; IWMPMedia2Disp = dispinterface; IWMPMedia3 = interface; IWMPMedia3Disp = dispinterface; IWMPMetadataPicture = interface; IWMPMetadataPictureDisp = dispinterface; IWMPMetadataText = interface; IWMPMetadataTextDisp = dispinterface; IWMPSettings2 = interface; IWMPSettings2Disp = dispinterface; IWMPControls3 = interface; IWMPControls3Disp = dispinterface; IWMPClosedCaption2 = interface; IWMPClosedCaption2Disp = dispinterface; IWMPMediaCollection2 = interface; IWMPMediaCollection2Disp = dispinterface; IWMPQuery = interface; IWMPQueryDisp = dispinterface; IWMPStringCollection2 = interface; IWMPStringCollection2Disp = dispinterface; IWMPPlayerServices = interface; IWMPPlayerServices2 = interface; IWMPRemoteMediaServices = interface; IWMPSyncServices = interface; IWMPLibraryServices = interface; IWMPLibrarySharingServices = interface; IWMPLibrary2 = interface; IWMPFolderMonitorServices = interface; IWMPSyncDevice2 = interface; IWMPSyncDevice3 = interface; IWMPPlaylistCtrl = interface; IWMPPlaylistCtrlDisp = dispinterface; IAppDispatch = interface; IAppDispatchDisp = dispinterface; IWMPSafeBrowser = interface; IWMPSafeBrowserDisp = dispinterface; IWMPObjectExtendedProps = interface; IWMPObjectExtendedPropsDisp = dispinterface; IWMPLayoutSubView = interface; IWMPLayoutSubViewDisp = dispinterface; IWMPLayoutView = interface; IWMPLayoutViewDisp = dispinterface; IWMPEventObject = interface; IWMPEventObjectDisp = dispinterface; IWMPTheme = interface; IWMPThemeDisp = dispinterface; IWMPLayoutSettingsDispatch = interface; IWMPLayoutSettingsDispatchDisp = dispinterface; IWMPWindow = interface; IWMPWindowDisp = dispinterface; IWMPBrandDispatch = interface; IWMPBrandDispatchDisp = dispinterface; IWMPNowPlayingHelperDispatch = interface; IWMPNowPlayingHelperDispatchDisp = dispinterface; IWMPNowDoingDispatch = interface; IWMPNowDoingDispatchDisp = dispinterface; IWMPHoverPreviewDispatch = interface; IWMPHoverPreviewDispatchDisp = dispinterface; IWMPButtonCtrlEvents = dispinterface; IWMPButtonCtrl = interface; IWMPButtonCtrlDisp = dispinterface; IWMPListBoxCtrl = interface; IWMPListBoxCtrlDisp = dispinterface; IWMPListBoxItem = interface; IWMPListBoxItemDisp = dispinterface; IWMPPlaylistCtrlColumn = interface; IWMPPlaylistCtrlColumnDisp = dispinterface; IWMPSliderCtrlEvents = dispinterface; IWMPSliderCtrl = interface; IWMPSliderCtrlDisp = dispinterface; IWMPVideoCtrlEvents = dispinterface; IWMPVideoCtrl = interface; IWMPVideoCtrlDisp = dispinterface; IWMPEffectsCtrl = interface; IWMPEffectsCtrlDisp = dispinterface; IWMPEqualizerSettingsCtrl = interface; IWMPEqualizerSettingsCtrlDisp = dispinterface; IWMPVideoSettingsCtrl = interface; IWMPVideoSettingsCtrlDisp = dispinterface; IWMPLibraryTreeCtrl = interface; IWMPLibraryTreeCtrlDisp = dispinterface; IWMPEditCtrl = interface; IWMPEditCtrlDisp = dispinterface; IWMPSkinList = interface; IWMPSkinListDisp = dispinterface; IWMPPluginUIHost = interface; IWMPPluginUIHostDisp = dispinterface; IWMPMenuCtrl = interface; IWMPMenuCtrlDisp = dispinterface; IWMPAutoMenuCtrl = interface; IWMPAutoMenuCtrlDisp = dispinterface; IWMPRegionalButtonCtrl = interface; IWMPRegionalButtonCtrlDisp = dispinterface; IWMPRegionalButtonEvents = dispinterface; IWMPRegionalButton = interface; IWMPRegionalButtonDisp = dispinterface; IWMPCustomSliderCtrlEvents = dispinterface; IWMPCustomSlider = interface; IWMPCustomSliderDisp = dispinterface; IWMPTextCtrl = interface; IWMPTextCtrlDisp = dispinterface; ITaskCntrCtrl = interface; ITaskCntrCtrlDisp = dispinterface; _WMPCoreEvents = dispinterface; IWMPGraphEventHandler = interface; IWMPGraphEventHandlerDisp = dispinterface; IBattery = interface; IBatteryDisp = dispinterface; IBatteryPreset = interface; IBatteryPresetDisp = dispinterface; IBatteryRandomPreset = interface; IBatteryRandomPresetDisp = dispinterface; IBatterySavedPreset = interface; IBatterySavedPresetDisp = dispinterface; IBarsEffect = interface; IBarsEffectDisp = dispinterface; IWMPExternal = interface; IWMPExternalDisp = dispinterface; IWMPExternalColors = interface; IWMPExternalColorsDisp = dispinterface; IWMPSubscriptionServiceLimited = interface; IWMPSubscriptionServiceLimitedDisp = dispinterface; IWMPSubscriptionServiceExternal = interface; IWMPSubscriptionServiceExternalDisp = dispinterface; IWMPDownloadManager = interface; IWMPDownloadManagerDisp = dispinterface; IWMPDownloadCollection = interface; IWMPDownloadCollectionDisp = dispinterface; IWMPDownloadItem2 = interface; IWMPDownloadItem2Disp = dispinterface; IWMPDownloadItem = interface; IWMPDownloadItemDisp = dispinterface; IWMPSubscriptionServicePlayMedia = interface; IWMPSubscriptionServicePlayMediaDisp = dispinterface; IWMPDiscoExternal = interface; IWMPDiscoExternalDisp = dispinterface; IWMPCDDVDWizardExternal = interface; IWMPCDDVDWizardExternalDisp = dispinterface; IWMPBaseExternal = interface; IWMPBaseExternalDisp = dispinterface; IWMPOfflineExternal = interface; IWMPOfflineExternalDisp = dispinterface; IWMPDMRAVTransportService = interface; IWMPDMRAVTransportServiceDisp = dispinterface; IWMPDMRConnectionManagerService = interface; IWMPDMRConnectionManagerServiceDisp = dispinterface; IWMPDMRRenderingControlService = interface; IWMPDMRRenderingControlServiceDisp = dispinterface; //Map CoClass to its default interface WindowsMediaPlayer = IWMPPlayer4; WMPButtonCtrl = IWMPButtonCtrl; WMPListBoxCtrl = IWMPListBoxCtrl; WMPSliderCtrl = IWMPSliderCtrl; WMPVideoCtrl = IWMPVideoCtrl; WMPEffects = IWMPEffectsCtrl; WMPEqualizerSettingsCtrl = IWMPEqualizerSettingsCtrl; WMPVideoSettingsCtrl = IWMPVideoSettingsCtrl; WMPLibraryTreeCtrl = IWMPLibraryTreeCtrl; WMPEditCtrl = IWMPEditCtrl; WMPSkinList = IWMPSkinList; WMPMenuCtrl = IWMPMenuCtrl; WMPAutoMenuCtrl = IWMPAutoMenuCtrl; WMPRegionalButtonCtrl = IWMPRegionalButtonCtrl; WMPRegionalButton = IWMPRegionalButton; WMPCustomSliderCtrl = IWMPCustomSlider; WMPTextCtrl = IWMPTextCtrl; WMPPlaylistCtrl = IWMPPlaylistCtrl; WMPCore = IWMPCore3; //records, unions, aliases ULONG_PTR = LongWord; //interface declarations // IWMPEvents : IWMPEvents: Public interface. IWMPEvents = interface(IUnknown) ['{19A6627B-DA9E-47C1-BB23-00B5E668236A}'] // OpenStateChange : Sent when the control changes OpenState function OpenStateChange(NewState:Integer):HRESULT;stdcall; // PlayStateChange : Sent when the control changes PlayState function PlayStateChange(NewState:Integer):HRESULT;stdcall; // AudioLanguageChange : Sent when the current audio language has changed function AudioLanguageChange(LangID:Integer):HRESULT;stdcall; // StatusChange : Sent when the status string changes function StatusChange:HRESULT;stdcall; // ScriptCommand : Sent when a synchronized command or URL is received function ScriptCommand(scType:WideString;Param:WideString):HRESULT;stdcall; // NewStream : Sent when a new stream is started in a channel function NewStream:HRESULT;stdcall; // Disconnect : Sent when the control is disconnected from the server function Disconnect(Result:Integer):HRESULT;stdcall; // Buffering : Sent when the control begins or ends buffering function Buffering(Start:WordBool):HRESULT;stdcall; // Error : Sent when the control has an error condition function Error:HRESULT;stdcall; // Warning : Sent when the control encounters a problem function Warning(WarningType:Integer;Param:Integer;Description:WideString):HRESULT;stdcall; // EndOfStream : Sent when the end of file is reached function EndOfStream(Result:Integer):HRESULT;stdcall; // PositionChange : Indicates that the current position of the movie has changed function PositionChange(oldPosition:Double;newPosition:Double):HRESULT;stdcall; // MarkerHit : Sent when a marker is reached function MarkerHit(MarkerNum:Integer):HRESULT;stdcall; // DurationUnitChange : Indicates that the unit used to express duration and position has changed function DurationUnitChange(NewDurationUnit:Integer):HRESULT;stdcall; // CdromMediaChange : Indicates that the CD ROM media has changed function CdromMediaChange(CdromNum:Integer):HRESULT;stdcall; // PlaylistChange : Sent when a playlist changes function PlaylistChange(Playlist:IDispatch;change:WMPPlaylistChangeEventType):HRESULT;stdcall; // CurrentPlaylistChange : Sent when the current playlist changes function CurrentPlaylistChange(change:WMPPlaylistChangeEventType):HRESULT;stdcall; // CurrentPlaylistItemAvailable : Sent when a current playlist item becomes available function CurrentPlaylistItemAvailable(bstrItemName:WideString):HRESULT;stdcall; // MediaChange : Sent when a media object changes function MediaChange(Item:IDispatch):HRESULT;stdcall; // CurrentMediaItemAvailable : Sent when a current media item becomes available function CurrentMediaItemAvailable(bstrItemName:WideString):HRESULT;stdcall; // CurrentItemChange : Sent when the item selection on the current playlist changes function CurrentItemChange(pdispMedia:IDispatch):HRESULT;stdcall; // MediaCollectionChange : Sent when the media collection needs to be requeried function MediaCollectionChange:HRESULT;stdcall; // MediaCollectionAttributeStringAdded : Sent when an attribute string is added in the media collection function MediaCollectionAttributeStringAdded(bstrAttribName:WideString;bstrAttribVal:WideString):HRESULT;stdcall; // MediaCollectionAttributeStringRemoved : Sent when an attribute string is removed from the media collection function MediaCollectionAttributeStringRemoved(bstrAttribName:WideString;bstrAttribVal:WideString):HRESULT;stdcall; // MediaCollectionAttributeStringChanged : Sent when an attribute string is changed in the media collection function MediaCollectionAttributeStringChanged(bstrAttribName:WideString;bstrOldAttribVal:WideString;bstrNewAttribVal:WideString):HRESULT;stdcall; // PlaylistCollectionChange : Sent when playlist collection needs to be requeried function PlaylistCollectionChange:HRESULT;stdcall; // PlaylistCollectionPlaylistAdded : Sent when a playlist is added to the playlist collection function PlaylistCollectionPlaylistAdded(bstrPlaylistName:WideString):HRESULT;stdcall; // PlaylistCollectionPlaylistRemoved : Sent when a playlist is removed from the playlist collection function PlaylistCollectionPlaylistRemoved(bstrPlaylistName:WideString):HRESULT;stdcall; // PlaylistCollectionPlaylistSetAsDeleted : Sent when a playlist has been set or reset as deleted function PlaylistCollectionPlaylistSetAsDeleted(bstrPlaylistName:WideString;varfIsDeleted:WordBool):HRESULT;stdcall; // ModeChange : Playlist playback mode has changed function ModeChange(ModeName:WideString;NewValue:WordBool):HRESULT;stdcall; // MediaError : Sent when the media object has an error condition function MediaError(pMediaObject:IDispatch):HRESULT;stdcall; // OpenPlaylistSwitch : Current playlist switch with no open state change function OpenPlaylistSwitch(pItem:IDispatch):HRESULT;stdcall; // DomainChange : Send a current domain function DomainChange(strDomain:WideString):HRESULT;stdcall; // SwitchedToPlayerApplication : Sent when display switches to player application function SwitchedToPlayerApplication:HRESULT;stdcall; // SwitchedToControl : Sent when display switches to control function SwitchedToControl:HRESULT;stdcall; // PlayerDockedStateChange : Sent when the player docks or undocks function PlayerDockedStateChange:HRESULT;stdcall; // PlayerReconnect : Sent when the OCX reconnects to the player function PlayerReconnect:HRESULT;stdcall; // Click : Occurs when a user clicks the mouse function Click(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer):HRESULT;stdcall; // DoubleClick : Occurs when a user double-clicks the mouse function DoubleClick(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer):HRESULT;stdcall; // KeyDown : Occurs when a key is pressed function KeyDown(nKeyCode:Smallint;nShiftState:Smallint):HRESULT;stdcall; // KeyPress : Occurs when a key is pressed and released function KeyPress(nKeyAscii:Smallint):HRESULT;stdcall; // KeyUp : Occurs when a key is released function KeyUp(nKeyCode:Smallint;nShiftState:Smallint):HRESULT;stdcall; // MouseDown : Occurs when a mouse button is pressed function MouseDown(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer):HRESULT;stdcall; // MouseMove : Occurs when a mouse pointer is moved function MouseMove(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer):HRESULT;stdcall; // MouseUp : Occurs when a mouse button is released function MouseUp(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer):HRESULT;stdcall; end; // IWMPEvents2 : IWMPEvents2: Public interface. IWMPEvents2 = interface(IWMPEvents) ['{1E7601FA-47EA-4107-9EA9-9004ED9684FF}'] // DeviceConnect : Occurs when a device is connected function DeviceConnect(pDevice:IWMPSyncDevice):HRESULT;stdcall; // DeviceDisconnect : Occurs when a device is disconnected function DeviceDisconnect(pDevice:IWMPSyncDevice):HRESULT;stdcall; // DeviceStatusChange : Occurs when a device status changes function DeviceStatusChange(pDevice:IWMPSyncDevice;NewStatus:WMPDeviceStatus):HRESULT;stdcall; // DeviceSyncStateChange : Occurs when a device sync state changes function DeviceSyncStateChange(pDevice:IWMPSyncDevice;NewState:WMPSyncState):HRESULT;stdcall; // DeviceSyncError : Occurs when a device's media has an error function DeviceSyncError(pDevice:IWMPSyncDevice;pMedia:IDispatch):HRESULT;stdcall; // CreatePartnershipComplete : Occurs when createPartnership call completes function CreatePartnershipComplete(pDevice:IWMPSyncDevice;hrResult:HResult):HRESULT;stdcall; end; // IWMPSyncDevice : IWMPSyncDevice: Public interface for Windows Media Player SDK. IWMPSyncDevice = interface(IUnknown) ['{82A2986C-0293-4FD0-B279-B21B86C058BE}'] function Get_friendlyName : WideString; stdcall; procedure Set_friendlyName(const pbstrName:WideString); stdcall; function Get_deviceName : WideString; stdcall; function Get_deviceId : WideString; stdcall; function Get_partnershipIndex : Integer; stdcall; function Get_connected : WordBool; stdcall; function Get_status : WMPDeviceStatus; stdcall; function Get_syncState : WMPSyncState; stdcall; function Get_progress : Integer; stdcall; // getItemInfo : function getItemInfo(bstrItemName:WideString):HRESULT;stdcall; // createPartnership : function createPartnership(vbShowUI:WordBool):HRESULT;stdcall; // deletePartnership : function deletePartnership:HRESULT;stdcall; // Start : function Start:HRESULT;stdcall; // stop : function stop:HRESULT;stdcall; // showSettings : function showSettings:HRESULT;stdcall; // isIdentical : function isIdentical(pDevice:IWMPSyncDevice):HRESULT;stdcall; // friendlyName : property friendlyName:WideString read Get_friendlyName write Set_friendlyName; // deviceName : property deviceName:WideString read Get_deviceName; // deviceId : property deviceId:WideString read Get_deviceId; // partnershipIndex : property partnershipIndex:Integer read Get_partnershipIndex; // connected : property connected:WordBool read Get_connected; // status : property status:WMPDeviceStatus read Get_status; // syncState : property syncState:WMPSyncState read Get_syncState; // progress : property progress:Integer read Get_progress; end; // IWMPEvents3 : IWMPEvents3: Public interface. IWMPEvents3 = interface(IWMPEvents2) ['{1F504270-A66B-4223-8E96-26A06C63D69F}'] // CdromRipStateChange : Occurs when ripping state changes function CdromRipStateChange(pCdromRip:IWMPCdromRip;wmprs:WMPRipState):HRESULT;stdcall; // CdromRipMediaError : Occurs when an error happens while ripping a media function CdromRipMediaError(pCdromRip:IWMPCdromRip;pMedia:IDispatch):HRESULT;stdcall; // CdromBurnStateChange : Occurs when burning state changes function CdromBurnStateChange(pCdromBurn:IWMPCdromBurn;wmpbs:WMPBurnState):HRESULT;stdcall; // CdromBurnMediaError : Occurs when an error happens while burning a media function CdromBurnMediaError(pCdromBurn:IWMPCdromBurn;pMedia:IDispatch):HRESULT;stdcall; // CdromBurnError : Occurs when a generic error happens while burning function CdromBurnError(pCdromBurn:IWMPCdromBurn;hrError:HResult):HRESULT;stdcall; // LibraryConnect : Occurs when a library is connected function LibraryConnect(pLibrary:IWMPLibrary):HRESULT;stdcall; // LibraryDisconnect : Occurs when a library is disconnected function LibraryDisconnect(pLibrary:IWMPLibrary):HRESULT;stdcall; // FolderScanStateChange : Occurs when a folder scan state changes function FolderScanStateChange(wmpfss:WMPFolderScanState):HRESULT;stdcall; // StringCollectionChange : Sent when a string collection changes function StringCollectionChange(pdispStringCollection:IDispatch;change:WMPStringCollectionChangeEventType;lCollectionIndex:Integer):HRESULT;stdcall; // MediaCollectionMediaAdded : Sent when a media is added to the local library function MediaCollectionMediaAdded(pdispMedia:IDispatch):HRESULT;stdcall; // MediaCollectionMediaRemoved : Sent when a media is removed from the local library function MediaCollectionMediaRemoved(pdispMedia:IDispatch):HRESULT;stdcall; end; // IWMPCdromRip : IWMPCdromRip: Public interface for Windows Media Player SDK. IWMPCdromRip = interface(IUnknown) ['{56E2294F-69ED-4629-A869-AEA72C0DCC2C}'] function Get_ripState : WMPRipState; stdcall; function Get_ripProgress : Integer; stdcall; // startRip : function startRip:HRESULT;stdcall; // stopRip : function stopRip:HRESULT;stdcall; // ripState : property ripState:WMPRipState read Get_ripState; // ripProgress : property ripProgress:Integer read Get_ripProgress; end; // IWMPCdromBurn : IWMPCdromBurn: Public interface for Windows Media Player SDK. IWMPCdromBurn = interface(IUnknown) ['{BD94DBEB-417F-4928-AA06-087D56ED9B59}'] // isAvailable : function isAvailable(bstrItem:WideString):HRESULT;stdcall; // getItemInfo : function getItemInfo(bstrItem:WideString):HRESULT;stdcall; function Get_label_ : WideString; stdcall; procedure Set_label_(const pbstrLabel:WideString); stdcall; function Get_burnFormat : WMPBurnFormat; stdcall; procedure Set_burnFormat(const pwmpbf:WMPBurnFormat); stdcall; function Get_burnPlaylist : IWMPPlaylist; stdcall; procedure Set_burnPlaylist(const ppPlaylist:IWMPPlaylist); stdcall; // refreshStatus : function refreshStatus:HRESULT;stdcall; function Get_burnState : WMPBurnState; stdcall; function Get_burnProgress : Integer; stdcall; // startBurn : function startBurn:HRESULT;stdcall; // stopBurn : function stopBurn:HRESULT;stdcall; // erase : function erase:HRESULT;stdcall; // label : property label_:WideString read Get_label_ write Set_label_; // burnFormat : property burnFormat:WMPBurnFormat read Get_burnFormat write Set_burnFormat; // burnPlaylist : property burnPlaylist:IWMPPlaylist read Get_burnPlaylist write Set_burnPlaylist; // burnState : property burnState:WMPBurnState read Get_burnState; // burnProgress : property burnProgress:Integer read Get_burnProgress; end; // IWMPPlaylist : IWMPPlaylist: Public interface. IWMPPlaylist = interface(IDispatch) ['{D5F0F4F1-130C-11D3-B14E-00C04F79FAA6}'] function Get_count : Integer; safecall; function Get_name : WideString; safecall; procedure Set_name(const pbstrName:WideString); safecall; function Get_attributeCount : Integer; safecall; function Get_attributeName(lIndex:Integer) : WideString; safecall; function Get_Item : IWMPMedia; safecall; // getItemInfo : Returns the value of a playlist attribute function getItemInfo(bstrName:WideString):WideString;safecall; // setItemInfo : Sets the value of a playlist attribute procedure setItemInfo(bstrName:WideString;bstrValue:WideString);safecall; function Get_isIdentical(pIWMPPlaylist:IWMPPlaylist) : WordBool; safecall; // clear : Removes all items from the playlist procedure clear;safecall; // insertItem : Inserts an item into the playlist at the specified location procedure insertItem(lIndex:Integer;pIWMPMedia:IWMPMedia);safecall; // appendItem : Adds an item to the end of the playlist procedure appendItem(pIWMPMedia:IWMPMedia);safecall; // removeItem : Removes the specified item from the playlist procedure removeItem(pIWMPMedia:IWMPMedia);safecall; // moveItem : Changes the location of an item in the playlist procedure moveItem(lIndexOld:Integer;lIndexNew:Integer);safecall; // count : Returns the number of items in the playlist property count:Integer read Get_count; // name : Returns the name of the playlist property name:WideString read Get_name write Set_name; // attributeCount : Returns the number of attributes associated with the playlist property attributeCount:Integer read Get_attributeCount; // attributeName : Returns the name of an attribute specified by an index property attributeName[lIndex:Integer]:WideString read Get_attributeName; // Item : Returns the item at the specified index property Item:IWMPMedia read Get_Item; // isIdentical : Determines if the supplied object is the same as the this one property isIdentical[pIWMPPlaylist:IWMPPlaylist]:WordBool read Get_isIdentical; end; // IWMPPlaylist : IWMPPlaylist: Public interface. IWMPPlaylistDisp = dispinterface ['{D5F0F4F1-130C-11D3-B14E-00C04F79FAA6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getItemInfo : Returns the value of a playlist attribute function getItemInfo(bstrName:WideString):WideString;dispid 203; // setItemInfo : Sets the value of a playlist attribute procedure setItemInfo(bstrName:WideString;bstrValue:WideString);dispid 204; // clear : Removes all items from the playlist procedure clear;dispid 205; // insertItem : Inserts an item into the playlist at the specified location procedure insertItem(lIndex:Integer;pIWMPMedia:IWMPMedia);dispid 206; // appendItem : Adds an item to the end of the playlist procedure appendItem(pIWMPMedia:IWMPMedia);dispid 207; // removeItem : Removes the specified item from the playlist procedure removeItem(pIWMPMedia:IWMPMedia);dispid 208; // moveItem : Changes the location of an item in the playlist procedure moveItem(lIndexOld:Integer;lIndexNew:Integer);dispid 209; // count : Returns the number of items in the playlist property count:Integer readonly dispid 201; // name : Returns the name of the playlist property name:WideString dispid 202; // attributeCount : Returns the number of attributes associated with the playlist property attributeCount:Integer readonly dispid 210; // attributeName : Returns the name of an attribute specified by an index property attributeName[lIndex:Integer]:WideString readonly dispid 211; // Item : Returns the item at the specified index property Item:IWMPMedia readonly dispid 212; // isIdentical : Determines if the supplied object is the same as the this one property isIdentical[pIWMPPlaylist:IWMPPlaylist]:WordBool readonly dispid 213; end; // IWMPMedia : IWMPMedia: Public interface. IWMPMedia = interface(IDispatch) ['{94D55E95-3FAC-11D3-B155-00C04F79FAA6}'] function Get_isIdentical(pIWMPMedia:IWMPMedia) : WordBool; safecall; function Get_sourceURL : WideString; safecall; function Get_name : WideString; safecall; procedure Set_name(const pbstrName:WideString); safecall; function Get_imageSourceWidth : Integer; safecall; function Get_imageSourceHeight : Integer; safecall; function Get_markerCount : Integer; safecall; // getMarkerTime : Returns the time of a marker function getMarkerTime(MarkerNum:Integer):Double;safecall; // getMarkerName : Returns the name of a marker function getMarkerName(MarkerNum:Integer):WideString;safecall; function Get_duration : Double; safecall; function Get_durationString : WideString; safecall; function Get_attributeCount : Integer; safecall; // getAttributeName : Returns the name of the attribute whose index has been specified function getAttributeName(lIndex:Integer):WideString;safecall; // getItemInfo : Returns the value of specified attribute for this media function getItemInfo(bstrItemName:WideString):WideString;safecall; // setItemInfo : Sets the value of specified attribute for this media procedure setItemInfo(bstrItemName:WideString;bstrVal:WideString);safecall; // getItemInfoByAtom : Gets an item info by atom function getItemInfoByAtom(lAtom:Integer):WideString;safecall; // isMemberOf : Is the media a member of the given playlist function isMemberOf(pPlaylist:IWMPPlaylist):WordBool;safecall; // isReadOnlyItem : Is the attribute read only function isReadOnlyItem(bstrItemName:WideString):WordBool;safecall; // isIdentical : Determines if the supplied object is the same as the this one property isIdentical[pIWMPMedia:IWMPMedia]:WordBool read Get_isIdentical; // sourceURL : Returns the media URL property sourceURL:WideString read Get_sourceURL; // name : Returns the name of the media property name:WideString read Get_name write Set_name; // imageSourceWidth : Returns the original width of the source images property imageSourceWidth:Integer read Get_imageSourceWidth; // imageSourceHeight : Returns the original height of the source images property imageSourceHeight:Integer read Get_imageSourceHeight; // markerCount : Returns the number of markers in the file property markerCount:Integer read Get_markerCount; // duration : Returns duration of current media property duration:Double read Get_duration; // durationString : Returns duration of current media as a string property durationString:WideString read Get_durationString; // attributeCount : Returns the count of the attributes associated with this media property attributeCount:Integer read Get_attributeCount; end; // IWMPMedia : IWMPMedia: Public interface. IWMPMediaDisp = dispinterface ['{94D55E95-3FAC-11D3-B155-00C04F79FAA6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getMarkerTime : Returns the time of a marker function getMarkerTime(MarkerNum:Integer):Double;dispid 755; // getMarkerName : Returns the name of a marker function getMarkerName(MarkerNum:Integer):WideString;dispid 756; // getAttributeName : Returns the name of the attribute whose index has been specified function getAttributeName(lIndex:Integer):WideString;dispid 760; // getItemInfo : Returns the value of specified attribute for this media function getItemInfo(bstrItemName:WideString):WideString;dispid 761; // setItemInfo : Sets the value of specified attribute for this media procedure setItemInfo(bstrItemName:WideString;bstrVal:WideString);dispid 762; // getItemInfoByAtom : Gets an item info by atom function getItemInfoByAtom(lAtom:Integer):WideString;dispid 765; // isMemberOf : Is the media a member of the given playlist function isMemberOf(pPlaylist:IWMPPlaylist):WordBool;dispid 766; // isReadOnlyItem : Is the attribute read only function isReadOnlyItem(bstrItemName:WideString):WordBool;dispid 767; // isIdentical : Determines if the supplied object is the same as the this one property isIdentical[pIWMPMedia:IWMPMedia]:WordBool readonly dispid 763; // sourceURL : Returns the media URL property sourceURL:WideString readonly dispid 751; // name : Returns the name of the media property name:WideString dispid 764; // imageSourceWidth : Returns the original width of the source images property imageSourceWidth:Integer readonly dispid 752; // imageSourceHeight : Returns the original height of the source images property imageSourceHeight:Integer readonly dispid 753; // markerCount : Returns the number of markers in the file property markerCount:Integer readonly dispid 754; // duration : Returns duration of current media property duration:Double readonly dispid 757; // durationString : Returns duration of current media as a string property durationString:WideString readonly dispid 758; // attributeCount : Returns the count of the attributes associated with this media property attributeCount:Integer readonly dispid 759; end; // IWMPLibrary : IWMPLibrary: Public interface for Windows Media Player SDK. IWMPLibrary = interface(IUnknown) ['{3DF47861-7DF1-4C1F-A81B-4C26F0F7A7C6}'] function Get_name : WideString; stdcall; function Get_type_ : WMPLibraryType; stdcall; function Get_mediaCollection : IWMPMediaCollection; stdcall; // isIdentical : function isIdentical(pIWMPLibrary:IWMPLibrary):HRESULT;stdcall; // name : property name:WideString read Get_name; // type : property type_:WMPLibraryType read Get_type_; // mediaCollection : property mediaCollection:IWMPMediaCollection read Get_mediaCollection; end; // IWMPMediaCollection : IWMPMediaCollection: Public interface. IWMPMediaCollection = interface(IDispatch) ['{8363BC22-B4B4-4B19-989D-1CD765749DD1}'] // add : Creates a new media object function add(bstrURL:WideString):IWMPMedia;safecall; // getAll : Returns a collection of all the items function getAll:IWMPPlaylist;safecall; // getByName : Returns a collection of items with the given name function getByName(bstrName:WideString):IWMPPlaylist;safecall; // getByGenre : Returns a collection of items with the given genre function getByGenre(bstrGenre:WideString):IWMPPlaylist;safecall; // getByAuthor : Returns a collection of items by a given author function getByAuthor(bstrAuthor:WideString):IWMPPlaylist;safecall; // getByAlbum : Returns a collection of items from the given album function getByAlbum(bstrAlbum:WideString):IWMPPlaylist;safecall; // getByAttribute : Returns a collection of items with the given attribute function getByAttribute(bstrAttribute:WideString;bstrValue:WideString):IWMPPlaylist;safecall; // remove : Removes an item from the media collection procedure remove(pItem:IWMPMedia;varfDeleteFile:WordBool);safecall; // getAttributeStringCollection : Returns the string collection associated with an attribute function getAttributeStringCollection(bstrAttribute:WideString;bstrMediaType:WideString):IWMPStringCollection;safecall; // getMediaAtom : Gets an atom associated with an item name which can be requested from an IWMPMedia out of this collection via getItemInfoByAtom function getMediaAtom(bstrItemName:WideString):Integer;safecall; // setDeleted : Sets the deleted flag on a media object procedure setDeleted(pItem:IWMPMedia;varfIsDeleted:WordBool);safecall; // isDeleted : Gets the deleted flag on a media object function isDeleted(pItem:IWMPMedia):WordBool;safecall; end; // IWMPMediaCollection : IWMPMediaCollection: Public interface. IWMPMediaCollectionDisp = dispinterface ['{8363BC22-B4B4-4B19-989D-1CD765749DD1}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // add : Creates a new media object function add(bstrURL:WideString):IWMPMedia;dispid 452; // getAll : Returns a collection of all the items function getAll:IWMPPlaylist;dispid 453; // getByName : Returns a collection of items with the given name function getByName(bstrName:WideString):IWMPPlaylist;dispid 454; // getByGenre : Returns a collection of items with the given genre function getByGenre(bstrGenre:WideString):IWMPPlaylist;dispid 455; // getByAuthor : Returns a collection of items by a given author function getByAuthor(bstrAuthor:WideString):IWMPPlaylist;dispid 456; // getByAlbum : Returns a collection of items from the given album function getByAlbum(bstrAlbum:WideString):IWMPPlaylist;dispid 457; // getByAttribute : Returns a collection of items with the given attribute function getByAttribute(bstrAttribute:WideString;bstrValue:WideString):IWMPPlaylist;dispid 458; // remove : Removes an item from the media collection procedure remove(pItem:IWMPMedia;varfDeleteFile:WordBool);dispid 459; // getAttributeStringCollection : Returns the string collection associated with an attribute function getAttributeStringCollection(bstrAttribute:WideString;bstrMediaType:WideString):IWMPStringCollection;dispid 461; // getMediaAtom : Gets an atom associated with an item name which can be requested from an IWMPMedia out of this collection via getItemInfoByAtom function getMediaAtom(bstrItemName:WideString):Integer;dispid 470; // setDeleted : Sets the deleted flag on a media object procedure setDeleted(pItem:IWMPMedia;varfIsDeleted:WordBool);dispid 471; // isDeleted : Gets the deleted flag on a media object function isDeleted(pItem:IWMPMedia):WordBool;dispid 472; end; // IWMPStringCollection : IWMPStringCollection: Public interface. IWMPStringCollection = interface(IDispatch) ['{4A976298-8C0D-11D3-B389-00C04F68574B}'] function Get_count : Integer; safecall; // Item : Returns the string at the given index function Item(lIndex:Integer):WideString;safecall; // count : Returns the number of items in the string collection property count:Integer read Get_count; end; // IWMPStringCollection : IWMPStringCollection: Public interface. IWMPStringCollectionDisp = dispinterface ['{4A976298-8C0D-11D3-B389-00C04F68574B}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Item : Returns the string at the given index function Item(lIndex:Integer):WideString;dispid 402; // count : Returns the number of items in the string collection property count:Integer readonly dispid 401; end; // IWMPEvents4 : IWMPEvents4: Public interface. IWMPEvents4 = interface(IWMPEvents3) ['{26DABCFA-306B-404D-9A6F-630A8405048D}'] // DeviceEstimation : Occurs when the sync estimation completed function DeviceEstimation(pDevice:IWMPSyncDevice;hrResult:HResult;qwEstimatedUsedSpace:Int64;qwEstimatedSpace:Int64):HRESULT;stdcall; end; // _WMPOCXEvents : _WMPOCXEvents: Public interface. _WMPOCXEvents = dispinterface ['{6BF52A51-394A-11D3-B153-00C04F79FAA6}'] // OpenStateChange : Sent when the control changes OpenState procedure OpenStateChange(NewState:Integer);dispid 5001; // PlayStateChange : Sent when the control changes PlayState procedure PlayStateChange(NewState:Integer);dispid 5101; // AudioLanguageChange : Sent when the current audio language has changed procedure AudioLanguageChange(LangID:Integer);dispid 5102; // StatusChange : Sent when the status string changes procedure StatusChange;dispid 5002; // ScriptCommand : Sent when a synchronized command or URL is received procedure ScriptCommand(scType:WideString;Param:WideString);dispid 5301; // NewStream : Sent when a new stream is started in a channel procedure NewStream;dispid 5403; // Disconnect : Sent when the control is disconnected from the server procedure Disconnect(Result:Integer);dispid 5401; // Buffering : Sent when the control begins or ends buffering procedure Buffering(Start:WordBool);dispid 5402; // Error : Sent when the control has an error condition procedure Error;dispid 5501; // Warning : Sent when the control encounters a problem procedure Warning(WarningType:Integer;Param:Integer;Description:WideString);dispid 5601; // EndOfStream : Sent when the end of file is reached procedure EndOfStream(Result:Integer);dispid 5201; // PositionChange : Indicates that the current position of the movie has changed procedure PositionChange(oldPosition:Double;newPosition:Double);dispid 5202; // MarkerHit : Sent when a marker is reached procedure MarkerHit(MarkerNum:Integer);dispid 5203; // DurationUnitChange : Indicates that the unit used to express duration and position has changed procedure DurationUnitChange(NewDurationUnit:Integer);dispid 5204; // CdromMediaChange : Indicates that the CD ROM media has changed procedure CdromMediaChange(CdromNum:Integer);dispid 5701; // PlaylistChange : Sent when a playlist changes procedure PlaylistChange(Playlist:IDispatch;change:WMPPlaylistChangeEventType);dispid 5801; // CurrentPlaylistChange : Sent when the current playlist changes procedure CurrentPlaylistChange(change:WMPPlaylistChangeEventType);dispid 5804; // CurrentPlaylistItemAvailable : Sent when a current playlist item becomes available procedure CurrentPlaylistItemAvailable(bstrItemName:WideString);dispid 5805; // MediaChange : Sent when a media object changes procedure MediaChange(Item:IDispatch);dispid 5802; // CurrentMediaItemAvailable : Sent when a current media item becomes available procedure CurrentMediaItemAvailable(bstrItemName:WideString);dispid 5803; // CurrentItemChange : Sent when the item selection on the current playlist changes procedure CurrentItemChange(pdispMedia:IDispatch);dispid 5806; // MediaCollectionChange : Sent when the media collection needs to be requeried procedure MediaCollectionChange;dispid 5807; // MediaCollectionAttributeStringAdded : Sent when an attribute string is added in the media collection procedure MediaCollectionAttributeStringAdded(bstrAttribName:WideString;bstrAttribVal:WideString);dispid 5808; // MediaCollectionAttributeStringRemoved : Sent when an attribute string is removed from the media collection procedure MediaCollectionAttributeStringRemoved(bstrAttribName:WideString;bstrAttribVal:WideString);dispid 5809; // MediaCollectionAttributeStringChanged : Sent when an attribute string is changed in the media collection procedure MediaCollectionAttributeStringChanged(bstrAttribName:WideString;bstrOldAttribVal:WideString;bstrNewAttribVal:WideString);dispid 5820; // PlaylistCollectionChange : Sent when playlist collection needs to be requeried procedure PlaylistCollectionChange;dispid 5810; // PlaylistCollectionPlaylistAdded : Sent when a playlist is added to the playlist collection procedure PlaylistCollectionPlaylistAdded(bstrPlaylistName:WideString);dispid 5811; // PlaylistCollectionPlaylistRemoved : Sent when a playlist is removed from the playlist collection procedure PlaylistCollectionPlaylistRemoved(bstrPlaylistName:WideString);dispid 5812; // PlaylistCollectionPlaylistSetAsDeleted : Sent when a playlist has been set or reset as deleted procedure PlaylistCollectionPlaylistSetAsDeleted(bstrPlaylistName:WideString;varfIsDeleted:WordBool);dispid 5818; // ModeChange : Playlist playback mode has changed procedure ModeChange(ModeName:WideString;NewValue:WordBool);dispid 5819; // MediaError : Sent when the media object has an error condition procedure MediaError(pMediaObject:IDispatch);dispid 5821; // OpenPlaylistSwitch : Current playlist switch with no open state change procedure OpenPlaylistSwitch(pItem:IDispatch);dispid 5823; // DomainChange : Send a current domain procedure DomainChange(strDomain:WideString);dispid 5822; // SwitchedToPlayerApplication : Sent when display switches to player application procedure SwitchedToPlayerApplication;dispid 6501; // SwitchedToControl : Sent when display switches to control procedure SwitchedToControl;dispid 6502; // PlayerDockedStateChange : Sent when the player docks or undocks procedure PlayerDockedStateChange;dispid 6503; // PlayerReconnect : Sent when the OCX reconnects to the player procedure PlayerReconnect;dispid 6504; // Click : Occurs when a user clicks the mouse procedure Click(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer);dispid 6505; // DoubleClick : Occurs when a user double-clicks the mouse procedure DoubleClick(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer);dispid 6506; // KeyDown : Occurs when a key is pressed procedure KeyDown(nKeyCode:Smallint;nShiftState:Smallint);dispid 6507; // KeyPress : Occurs when a key is pressed and released procedure KeyPress(nKeyAscii:Smallint);dispid 6508; // KeyUp : Occurs when a key is released procedure KeyUp(nKeyCode:Smallint;nShiftState:Smallint);dispid 6509; // MouseDown : Occurs when a mouse button is pressed procedure MouseDown(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer);dispid 6510; // MouseMove : Occurs when a mouse pointer is moved procedure MouseMove(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer);dispid 6511; // MouseUp : Occurs when a mouse button is released procedure MouseUp(nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer);dispid 6512; // DeviceConnect : Occurs when a device is connected procedure DeviceConnect(pDevice:IWMPSyncDevice);dispid 6513; // DeviceDisconnect : Occurs when a device is disconnected procedure DeviceDisconnect(pDevice:IWMPSyncDevice);dispid 6514; // DeviceStatusChange : Occurs when a device status changes procedure DeviceStatusChange(pDevice:IWMPSyncDevice;NewStatus:WMPDeviceStatus);dispid 6515; // DeviceSyncStateChange : Occurs when a device sync state changes procedure DeviceSyncStateChange(pDevice:IWMPSyncDevice;NewState:WMPSyncState);dispid 6516; // DeviceSyncError : Occurs when a device's media has an error procedure DeviceSyncError(pDevice:IWMPSyncDevice;pMedia:IDispatch);dispid 6517; // CreatePartnershipComplete : Occurs when createPartnership call completes procedure CreatePartnershipComplete(pDevice:IWMPSyncDevice;hrResult:HResult);dispid 6518; // DeviceEstimation : Occurs when the sync estimation completed procedure DeviceEstimation(pDevice:IWMPSyncDevice;hrResult:HResult;qwEstimatedUsedSpace:Int64;qwEstimatedSpace:Int64);dispid 6527; // CdromRipStateChange : Occurs when ripping state changes procedure CdromRipStateChange(pCdromRip:IWMPCdromRip;wmprs:WMPRipState);dispid 6519; // CdromRipMediaError : Occurs when an error happens while ripping a media procedure CdromRipMediaError(pCdromRip:IWMPCdromRip;pMedia:IDispatch);dispid 6520; // CdromBurnStateChange : Occurs when burning state changes procedure CdromBurnStateChange(pCdromBurn:IWMPCdromBurn;wmpbs:WMPBurnState);dispid 6521; // CdromBurnMediaError : Occurs when an error happens while burning a media procedure CdromBurnMediaError(pCdromBurn:IWMPCdromBurn;pMedia:IDispatch);dispid 6522; // CdromBurnError : Occurs when a generic error happens while burning procedure CdromBurnError(pCdromBurn:IWMPCdromBurn;hrError:HResult);dispid 6523; // LibraryConnect : Occurs when a library is connected procedure LibraryConnect(pLibrary:IWMPLibrary);dispid 6524; // LibraryDisconnect : Occurs when a library is disconnected procedure LibraryDisconnect(pLibrary:IWMPLibrary);dispid 6525; // FolderScanStateChange : Occurs when a folder scan state changes procedure FolderScanStateChange(wmpfss:WMPFolderScanState);dispid 6526; // StringCollectionChange : Sent when a string collection changes procedure StringCollectionChange(pdispStringCollection:IDispatch;change:WMPStringCollectionChangeEventType;lCollectionIndex:Integer);dispid 5824; // MediaCollectionMediaAdded : Sent when a media is added to the local library procedure MediaCollectionMediaAdded(pdispMedia:IDispatch);dispid 5825; // MediaCollectionMediaRemoved : Sent when a media is removed from the local library procedure MediaCollectionMediaRemoved(pdispMedia:IDispatch);dispid 5826; end; // IWMPCore : IWMPCore: Public interface. IWMPCore = interface(IDispatch) ['{D84CCA99-CCE2-11D2-9ECC-0000F8085981}'] // close : Closes the media procedure close;safecall; function Get_URL : WideString; safecall; procedure Set_URL(const pbstrURL:WideString); safecall; function Get_openState : WMPOpenState; safecall; function Get_playState : WMPPlayState; safecall; function Get_controls : IWMPControls; safecall; function Get_settings : IWMPSettings; safecall; function Get_currentMedia : IWMPMedia; safecall; procedure Set_currentMedia(const ppMedia:IWMPMedia); safecall; function Get_mediaCollection : IWMPMediaCollection; safecall; function Get_playlistCollection : IWMPPlaylistCollection; safecall; function Get_versionInfo : WideString; safecall; // launchURL : procedure launchURL(bstrURL:WideString);safecall; function Get_network : IWMPNetwork; safecall; function Get_currentPlaylist : IWMPPlaylist; safecall; procedure Set_currentPlaylist(const ppPL:IWMPPlaylist); safecall; function Get_cdromCollection : IWMPCdromCollection; safecall; function Get_closedCaption : IWMPClosedCaption; safecall; function Get_isOnline : WordBool; safecall; function Get_Error : IWMPError; safecall; function Get_status : WideString; safecall; // URL : Returns or sets the URL property URL:WideString read Get_URL write Set_URL; // openState : Returns the open state of the player property openState:WMPOpenState read Get_openState; // playState : Returns the play state of the player property playState:WMPPlayState read Get_playState; // controls : Returns the control handler property controls:IWMPControls read Get_controls; // settings : Returns the settings handler property settings:IWMPSettings read Get_settings; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia read Get_currentMedia write Set_currentMedia; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection read Get_mediaCollection; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection read Get_playlistCollection; // versionInfo : Returns the version information for the player property versionInfo:WideString read Get_versionInfo; // network : Returns the network information handler property network:IWMPNetwork read Get_network; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist read Get_currentPlaylist write Set_currentPlaylist; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection read Get_cdromCollection; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption read Get_closedCaption; // isOnline : Returns whether the machine is online. property isOnline:WordBool read Get_isOnline; // Error : Returns the error object property Error:IWMPError read Get_Error; // status : Returns status string property status:WideString read Get_status; end; // IWMPCore : IWMPCore: Public interface. IWMPCoreDisp = dispinterface ['{D84CCA99-CCE2-11D2-9ECC-0000F8085981}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; end; // IWMPCore2 : IWMPCore2: Public interface. IWMPCore2 = interface(IWMPCore) ['{BC17E5B7-7561-4C18-BB90-17D485775659}'] function Get_dvd : IWMPDVD; safecall; // dvd : Returns the DVD handler property dvd:IWMPDVD read Get_dvd; end; // IWMPCore2 : IWMPCore2: Public interface. IWMPCore2Disp = dispinterface ['{BC17E5B7-7561-4C18-BB90-17D485775659}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; // dvd : Returns the DVD handler property dvd:IWMPDVD readonly dispid 40; end; // IWMPCore3 : IWMPCore3: Public interface. IWMPCore3 = interface(IWMPCore2) ['{7587C667-628F-499F-88E7-6A6F4E888464}'] // newPlaylist : Creates a new playlist object function newPlaylist(bstrName:WideString;bstrURL:WideString):IWMPPlaylist;safecall; // newMedia : Creates a new media object function newMedia(bstrURL:WideString):IWMPMedia;safecall; end; // IWMPCore3 : IWMPCore3: Public interface. IWMPCore3Disp = dispinterface ['{7587C667-628F-499F-88E7-6A6F4E888464}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // newPlaylist : Creates a new playlist object function newPlaylist(bstrName:WideString;bstrURL:WideString):IWMPPlaylist;dispid 41; // newMedia : Creates a new media object function newMedia(bstrURL:WideString):IWMPMedia;dispid 42; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; // dvd : Returns the DVD handler property dvd:IWMPDVD readonly dispid 40; end; // IWMPPlayer4 : IWMPPlayer4: Public interface. IWMPPlayer4 = interface(IWMPCore3) ['{6C497D62-8919-413C-82DB-E935FB3EC584}'] function Get_enabled : WordBool; safecall; procedure Set_enabled(const pbEnabled:WordBool); safecall; function Get_fullScreen : WordBool; safecall; procedure Set_fullScreen(const pbFullScreen:WordBool); safecall; function Get_enableContextMenu : WordBool; safecall; procedure Set_enableContextMenu(const pbEnableContextMenu:WordBool); safecall; procedure Set_uiMode(const pbstrMode:WideString); safecall; function Get_uiMode : WideString; safecall; function Get_stretchToFit : WordBool; safecall; procedure Set_stretchToFit(const pbEnabled:WordBool); safecall; function Get_windowlessVideo : WordBool; safecall; procedure Set_windowlessVideo(const pbEnabled:WordBool); safecall; function Get_isRemote : WordBool; safecall; function Get_playerApplication : IWMPPlayerApplication; safecall; // openPlayer : Opens the player with the specified URL procedure openPlayer(bstrURL:WideString);safecall; // enabled : Returns a boolean value specifying whether or not the control is enabled property enabled:WordBool read Get_enabled write Set_enabled; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool read Get_fullScreen write Set_fullScreen; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool read Get_enableContextMenu write Set_enableContextMenu; // uiMode : Specifies the ui mode to select property uiMode:WideString read Get_uiMode write Set_uiMode; // stretchToFit : Returns a boolean value specifying whether or not video is stretched property stretchToFit:WordBool read Get_stretchToFit write Set_stretchToFit; // windowlessVideo : Returns a boolean value specifying whether or not video is windowless property windowlessVideo:WordBool read Get_windowlessVideo write Set_windowlessVideo; // isRemote : Indicates whether the player is running remotely property isRemote:WordBool read Get_isRemote; // playerApplication : Returns the player application handler property playerApplication:IWMPPlayerApplication read Get_playerApplication; end; // IWMPPlayer4 : IWMPPlayer4: Public interface. IWMPPlayer4Disp = dispinterface ['{6C497D62-8919-413C-82DB-E935FB3EC584}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // newPlaylist : Creates a new playlist object function newPlaylist(bstrName:WideString;bstrURL:WideString):IWMPPlaylist;dispid 41; // newMedia : Creates a new media object function newMedia(bstrURL:WideString):IWMPMedia;dispid 42; // openPlayer : Opens the player with the specified URL procedure openPlayer(bstrURL:WideString);dispid 28; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; // dvd : Returns the DVD handler property dvd:IWMPDVD readonly dispid 40; // enabled : Returns a boolean value specifying whether or not the control is enabled property enabled:WordBool dispid 19; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool dispid 21; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool dispid 22; // uiMode : Specifies the ui mode to select property uiMode:WideString dispid 23; // stretchToFit : Returns a boolean value specifying whether or not video is stretched property stretchToFit:WordBool dispid 24; // windowlessVideo : Returns a boolean value specifying whether or not video is windowless property windowlessVideo:WordBool dispid 25; // isRemote : Indicates whether the player is running remotely property isRemote:WordBool readonly dispid 26; // playerApplication : Returns the player application handler property playerApplication:IWMPPlayerApplication readonly dispid 27; end; // IWMPControls : IWMPControls: Public interface. IWMPControls = interface(IDispatch) ['{74C09E02-F828-11D2-A74B-00A0C905F36E}'] function Get_isAvailable(bstrItem:WideString) : WordBool; safecall; // play : Begins playing media procedure play;safecall; // stop : Stops play of media procedure stop;safecall; // pause : Pauses play of media procedure pause;safecall; // fastForward : Fast play of media in forward direction procedure fastForward;safecall; // fastReverse : Fast play of media in reverse direction procedure fastReverse;safecall; function Get_currentPosition : Double; safecall; procedure Set_currentPosition(const pdCurrentPosition:Double); safecall; function Get_currentPositionString : WideString; safecall; // next : Sets the current item to the next item in the playlist procedure next;safecall; // previous : Sets the current item to the previous item in the playlist procedure previous;safecall; function Get_currentItem : IWMPMedia; safecall; procedure Set_currentItem(const ppIWMPMedia:IWMPMedia); safecall; function Get_currentMarker : Integer; safecall; procedure Set_currentMarker(const plMarker:Integer); safecall; // playItem : Sets the current item and plays it procedure playItem(pIWMPMedia:IWMPMedia);safecall; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool read Get_isAvailable; // currentPosition : Returns the current position in media property currentPosition:Double read Get_currentPosition write Set_currentPosition; // currentPositionString : Returns the current position in media as a string property currentPositionString:WideString read Get_currentPositionString; // currentItem : Returns/Sets the play item property currentItem:IWMPMedia read Get_currentItem write Set_currentItem; // currentMarker : Returns the current marker property currentMarker:Integer read Get_currentMarker write Set_currentMarker; end; // IWMPControls : IWMPControls: Public interface. IWMPControlsDisp = dispinterface ['{74C09E02-F828-11D2-A74B-00A0C905F36E}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // play : Begins playing media procedure play;dispid 51; // stop : Stops play of media procedure stop;dispid 52; // pause : Pauses play of media procedure pause;dispid 53; // fastForward : Fast play of media in forward direction procedure fastForward;dispid 54; // fastReverse : Fast play of media in reverse direction procedure fastReverse;dispid 55; // next : Sets the current item to the next item in the playlist procedure next;dispid 58; // previous : Sets the current item to the previous item in the playlist procedure previous;dispid 59; // playItem : Sets the current item and plays it procedure playItem(pIWMPMedia:IWMPMedia);dispid 63; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool readonly dispid 62; // currentPosition : Returns the current position in media property currentPosition:Double dispid 56; // currentPositionString : Returns the current position in media as a string property currentPositionString:WideString readonly dispid 57; // currentItem : Returns/Sets the play item property currentItem:IWMPMedia dispid 60; // currentMarker : Returns the current marker property currentMarker:Integer dispid 61; end; // IWMPSettings : IWMPSettings: Public interface. IWMPSettings = interface(IDispatch) ['{9104D1AB-80C9-4FED-ABF0-2E6417A6DF14}'] function Get_isAvailable(bstrItem:WideString) : WordBool; safecall; function Get_autoStart : WordBool; safecall; procedure Set_autoStart(const pfAutoStart:WordBool); safecall; function Get_baseURL : WideString; safecall; procedure Set_baseURL(const pbstrBaseURL:WideString); safecall; function Get_defaultFrame : WideString; safecall; procedure Set_defaultFrame(const pbstrDefaultFrame:WideString); safecall; function Get_invokeURLs : WordBool; safecall; procedure Set_invokeURLs(const pfInvokeURLs:WordBool); safecall; function Get_mute : WordBool; safecall; procedure Set_mute(const pfMute:WordBool); safecall; function Get_playCount : Integer; safecall; procedure Set_playCount(const plCount:Integer); safecall; function Get_rate : Double; safecall; procedure Set_rate(const pdRate:Double); safecall; function Get_balance : Integer; safecall; procedure Set_balance(const plBalance:Integer); safecall; function Get_volume : Integer; safecall; procedure Set_volume(const plVolume:Integer); safecall; // getMode : Returns the mode of the playlist function getMode(bstrMode:WideString):WordBool;safecall; // setMode : Sets the mode of the playlist procedure setMode(bstrMode:WideString;varfMode:WordBool);safecall; function Get_enableErrorDialogs : WordBool; safecall; procedure Set_enableErrorDialogs(const pfEnableErrorDialogs:WordBool); safecall; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool read Get_isAvailable; // autoStart : Returns whether media should automatically begin playing property autoStart:WordBool read Get_autoStart write Set_autoStart; // baseURL : Returns the base URL used for relative path resolution property baseURL:WideString read Get_baseURL write Set_baseURL; // defaultFrame : Returns the frame location that changes when a URL flip occurs property defaultFrame:WideString read Get_defaultFrame write Set_defaultFrame; // invokeURLs : Returns whether URL events should spawn a browser. property invokeURLs:WordBool read Get_invokeURLs write Set_invokeURLs; // mute : Returns whether audio should be muted. property mute:WordBool read Get_mute write Set_mute; // playCount : Returns how many times media should play property playCount:Integer read Get_playCount write Set_playCount; // rate : Returns current playback rate property rate:Double read Get_rate write Set_rate; // balance : Returns current audio Balance property balance:Integer read Get_balance write Set_balance; // volume : Returns current audio volume property volume:Integer read Get_volume write Set_volume; // enableErrorDialogs : Returns whether error dialogs are shown by default when embedded property enableErrorDialogs:WordBool read Get_enableErrorDialogs write Set_enableErrorDialogs; end; // IWMPSettings : IWMPSettings: Public interface. IWMPSettingsDisp = dispinterface ['{9104D1AB-80C9-4FED-ABF0-2E6417A6DF14}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getMode : Returns the mode of the playlist function getMode(bstrMode:WideString):WordBool;dispid 110; // setMode : Sets the mode of the playlist procedure setMode(bstrMode:WideString;varfMode:WordBool);dispid 111; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool readonly dispid 113; // autoStart : Returns whether media should automatically begin playing property autoStart:WordBool dispid 101; // baseURL : Returns the base URL used for relative path resolution property baseURL:WideString dispid 108; // defaultFrame : Returns the frame location that changes when a URL flip occurs property defaultFrame:WideString dispid 109; // invokeURLs : Returns whether URL events should spawn a browser. property invokeURLs:WordBool dispid 103; // mute : Returns whether audio should be muted. property mute:WordBool dispid 104; // playCount : Returns how many times media should play property playCount:Integer dispid 105; // rate : Returns current playback rate property rate:Double dispid 106; // balance : Returns current audio Balance property balance:Integer dispid 102; // volume : Returns current audio volume property volume:Integer dispid 107; // enableErrorDialogs : Returns whether error dialogs are shown by default when embedded property enableErrorDialogs:WordBool dispid 112; end; // IWMPPlaylistCollection : IWMPPlaylistCollection: Public interface. IWMPPlaylistCollection = interface(IDispatch) ['{10A13217-23A7-439B-B1C0-D847C79B7774}'] // newPlaylist : Creates a new playlist object function newPlaylist(bstrName:WideString):IWMPPlaylist;safecall; // getAll : Returns a playlist array with all the playlists function getAll:IWMPPlaylistArray;safecall; // getByName : Returns a playlist array with playlists matching the given name function getByName(bstrName:WideString):IWMPPlaylistArray;safecall; // remove : Removes an item from the playlist collection procedure remove(pItem:IWMPPlaylist);safecall; // setDeleted : Sets the deleted flag on a playlist object procedure setDeleted(pItem:IWMPPlaylist;varfIsDeleted:WordBool);safecall; // isDeleted : Gets the deleted flag on a playlist object function isDeleted(pItem:IWMPPlaylist):WordBool;safecall; // importPlaylist : Imports a playlist object into the library function importPlaylist(pItem:IWMPPlaylist):IWMPPlaylist;safecall; end; // IWMPPlaylistCollection : IWMPPlaylistCollection: Public interface. IWMPPlaylistCollectionDisp = dispinterface ['{10A13217-23A7-439B-B1C0-D847C79B7774}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // newPlaylist : Creates a new playlist object function newPlaylist(bstrName:WideString):IWMPPlaylist;dispid 552; // getAll : Returns a playlist array with all the playlists function getAll:IWMPPlaylistArray;dispid 553; // getByName : Returns a playlist array with playlists matching the given name function getByName(bstrName:WideString):IWMPPlaylistArray;dispid 554; // remove : Removes an item from the playlist collection procedure remove(pItem:IWMPPlaylist);dispid 556; // setDeleted : Sets the deleted flag on a playlist object procedure setDeleted(pItem:IWMPPlaylist;varfIsDeleted:WordBool);dispid 560; // isDeleted : Gets the deleted flag on a playlist object function isDeleted(pItem:IWMPPlaylist):WordBool;dispid 561; // importPlaylist : Imports a playlist object into the library function importPlaylist(pItem:IWMPPlaylist):IWMPPlaylist;dispid 562; end; // IWMPPlaylistArray : IWMPPlaylistArray: Public interface. IWMPPlaylistArray = interface(IDispatch) ['{679409C0-99F7-11D3-9FB7-00105AA620BB}'] function Get_count : Integer; safecall; // Item : Returns the playlist object at the given index function Item(lIndex:Integer):IWMPPlaylist;safecall; // count : Returns the number of items in the playlist array property count:Integer read Get_count; end; // IWMPPlaylistArray : IWMPPlaylistArray: Public interface. IWMPPlaylistArrayDisp = dispinterface ['{679409C0-99F7-11D3-9FB7-00105AA620BB}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Item : Returns the playlist object at the given index function Item(lIndex:Integer):IWMPPlaylist;dispid 502; // count : Returns the number of items in the playlist array property count:Integer readonly dispid 501; end; // IWMPNetwork : IWMPNetwork: Public interface. IWMPNetwork = interface(IDispatch) ['{EC21B779-EDEF-462D-BBA4-AD9DDE2B29A7}'] function Get_bandWidth : Integer; safecall; function Get_recoveredPackets : Integer; safecall; function Get_sourceProtocol : WideString; safecall; function Get_receivedPackets : Integer; safecall; function Get_lostPackets : Integer; safecall; function Get_receptionQuality : Integer; safecall; function Get_bufferingCount : Integer; safecall; function Get_bufferingProgress : Integer; safecall; function Get_bufferingTime : Integer; safecall; procedure Set_bufferingTime(const plBufferingTime:Integer); safecall; function Get_frameRate : Integer; safecall; function Get_maxBitRate : Integer; safecall; function Get_bitRate : Integer; safecall; // getProxySettings : Returns the proxy settings for the specified protocol function getProxySettings(bstrProtocol:WideString):Integer;safecall; // setProxySettings : Sets the proxy settings for the specified protocol procedure setProxySettings(bstrProtocol:WideString;lProxySetting:Integer);safecall; // getProxyName : Returns the proxy name for the specified protocol function getProxyName(bstrProtocol:WideString):WideString;safecall; // setProxyName : Sets the proxy name for the specified protocol procedure setProxyName(bstrProtocol:WideString;bstrProxyName:WideString);safecall; // getProxyPort : Returns the proxy port for the specified protocol function getProxyPort(bstrProtocol:WideString):Integer;safecall; // setProxyPort : Sets the proxy port for the specified protocol procedure setProxyPort(bstrProtocol:WideString;lProxyPort:Integer);safecall; // getProxyExceptionList : Returns the proxy exception list for the specified protocol function getProxyExceptionList(bstrProtocol:WideString):WideString;safecall; // setProxyExceptionList : Sets the proxy exception list for the specified protocol procedure setProxyExceptionList(bstrProtocol:WideString;pbstrExceptionList:WideString);safecall; // getProxyBypassForLocal : Returns whether or not to bypass the proxy for local addresses function getProxyBypassForLocal(bstrProtocol:WideString):WordBool;safecall; // setProxyBypassForLocal : Sets whether or not to by pass the proxy for local addresses procedure setProxyBypassForLocal(bstrProtocol:WideString;fBypassForLocal:WordBool);safecall; function Get_maxBandwidth : Integer; safecall; procedure Set_maxBandwidth(const lMaxBandwidth:Integer); safecall; function Get_downloadProgress : Integer; safecall; function Get_encodedFrameRate : Integer; safecall; function Get_framesSkipped : Integer; safecall; // bandWidth : Returns the current bandwidth of the clip. property bandWidth:Integer read Get_bandWidth; // recoveredPackets : Returns the number of recovered packets property recoveredPackets:Integer read Get_recoveredPackets; // sourceProtocol : Returns the source protocol used to receive data. property sourceProtocol:WideString read Get_sourceProtocol; // receivedPackets : Returns the number of packets received. property receivedPackets:Integer read Get_receivedPackets; // lostPackets : Returns the number of packets lost. property lostPackets:Integer read Get_lostPackets; // receptionQuality : Returns the percentage of packets received in the last 15 seconds. property receptionQuality:Integer read Get_receptionQuality; // bufferingCount : Returns the number of times buffering occurred during clip playback. property bufferingCount:Integer read Get_bufferingCount; // bufferingProgress : Returns the percentage of buffering completed. property bufferingProgress:Integer read Get_bufferingProgress; // bufferingTime : Returns the number of seconds allocated for buffering for this media type. property bufferingTime:Integer read Get_bufferingTime write Set_bufferingTime; // frameRate : Current video frame rate in frames/second property frameRate:Integer read Get_frameRate; // maxBitRate : Maximum possible video bit rate property maxBitRate:Integer read Get_maxBitRate; // bitRate : Current video bit rate property bitRate:Integer read Get_bitRate; // maxBandwidth : Returns or sets maximum allowed bandwidth property maxBandwidth:Integer read Get_maxBandwidth write Set_maxBandwidth; // downloadProgress : Returns the percentage of download completed. property downloadProgress:Integer read Get_downloadProgress; // encodedFrameRate : Returns the video frame rate, in frames/second, that the file was encoded in property encodedFrameRate:Integer read Get_encodedFrameRate; // framesSkipped : Returns the number of skipped frames property framesSkipped:Integer read Get_framesSkipped; end; // IWMPNetwork : IWMPNetwork: Public interface. IWMPNetworkDisp = dispinterface ['{EC21B779-EDEF-462D-BBA4-AD9DDE2B29A7}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getProxySettings : Returns the proxy settings for the specified protocol function getProxySettings(bstrProtocol:WideString):Integer;dispid 813; // setProxySettings : Sets the proxy settings for the specified protocol procedure setProxySettings(bstrProtocol:WideString;lProxySetting:Integer);dispid 814; // getProxyName : Returns the proxy name for the specified protocol function getProxyName(bstrProtocol:WideString):WideString;dispid 815; // setProxyName : Sets the proxy name for the specified protocol procedure setProxyName(bstrProtocol:WideString;bstrProxyName:WideString);dispid 816; // getProxyPort : Returns the proxy port for the specified protocol function getProxyPort(bstrProtocol:WideString):Integer;dispid 817; // setProxyPort : Sets the proxy port for the specified protocol procedure setProxyPort(bstrProtocol:WideString;lProxyPort:Integer);dispid 818; // getProxyExceptionList : Returns the proxy exception list for the specified protocol function getProxyExceptionList(bstrProtocol:WideString):WideString;dispid 819; // setProxyExceptionList : Sets the proxy exception list for the specified protocol procedure setProxyExceptionList(bstrProtocol:WideString;pbstrExceptionList:WideString);dispid 820; // getProxyBypassForLocal : Returns whether or not to bypass the proxy for local addresses function getProxyBypassForLocal(bstrProtocol:WideString):WordBool;dispid 821; // setProxyBypassForLocal : Sets whether or not to by pass the proxy for local addresses procedure setProxyBypassForLocal(bstrProtocol:WideString;fBypassForLocal:WordBool);dispid 822; // bandWidth : Returns the current bandwidth of the clip. property bandWidth:Integer readonly dispid 801; // recoveredPackets : Returns the number of recovered packets property recoveredPackets:Integer readonly dispid 802; // sourceProtocol : Returns the source protocol used to receive data. property sourceProtocol:WideString readonly dispid 803; // receivedPackets : Returns the number of packets received. property receivedPackets:Integer readonly dispid 804; // lostPackets : Returns the number of packets lost. property lostPackets:Integer readonly dispid 805; // receptionQuality : Returns the percentage of packets received in the last 15 seconds. property receptionQuality:Integer readonly dispid 806; // bufferingCount : Returns the number of times buffering occurred during clip playback. property bufferingCount:Integer readonly dispid 807; // bufferingProgress : Returns the percentage of buffering completed. property bufferingProgress:Integer readonly dispid 808; // bufferingTime : Returns the number of seconds allocated for buffering for this media type. property bufferingTime:Integer dispid 809; // frameRate : Current video frame rate in frames/second property frameRate:Integer readonly dispid 810; // maxBitRate : Maximum possible video bit rate property maxBitRate:Integer readonly dispid 811; // bitRate : Current video bit rate property bitRate:Integer readonly dispid 812; // maxBandwidth : Returns or sets maximum allowed bandwidth property maxBandwidth:Integer dispid 823; // downloadProgress : Returns the percentage of download completed. property downloadProgress:Integer readonly dispid 824; // encodedFrameRate : Returns the video frame rate, in frames/second, that the file was encoded in property encodedFrameRate:Integer readonly dispid 825; // framesSkipped : Returns the number of skipped frames property framesSkipped:Integer readonly dispid 826; end; // IWMPCdromCollection : IWMPCdromCollection: Public interface. IWMPCdromCollection = interface(IDispatch) ['{EE4C8FE2-34B2-11D3-A3BF-006097C9B344}'] function Get_count : Integer; safecall; // Item : Returns the CDROM object at the given index function Item(lIndex:Integer):IWMPCdrom;safecall; // getByDriveSpecifier : Returns the CDROM object associated with a particular drive specifier, e.g. F: function getByDriveSpecifier(bstrDriveSpecifier:WideString):IWMPCdrom;safecall; // count : Returns the number of items in the cdrom collection property count:Integer read Get_count; end; // IWMPCdromCollection : IWMPCdromCollection: Public interface. IWMPCdromCollectionDisp = dispinterface ['{EE4C8FE2-34B2-11D3-A3BF-006097C9B344}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Item : Returns the CDROM object at the given index function Item(lIndex:Integer):IWMPCdrom;dispid 302; // getByDriveSpecifier : Returns the CDROM object associated with a particular drive specifier, e.g. F: function getByDriveSpecifier(bstrDriveSpecifier:WideString):IWMPCdrom;dispid 303; // count : Returns the number of items in the cdrom collection property count:Integer readonly dispid 301; end; // IWMPCdrom : IWMPCdrom: Public interface. IWMPCdrom = interface(IDispatch) ['{CFAB6E98-8730-11D3-B388-00C04F68574B}'] function Get_driveSpecifier : WideString; safecall; function Get_Playlist : IWMPPlaylist; safecall; // eject : Eject the CD in the CDROM drive procedure eject;safecall; // driveSpecifier : Returns the CDROM drive specifier property driveSpecifier:WideString read Get_driveSpecifier; // Playlist : Returns the playlist of tracks currently in the CDROM drive property Playlist:IWMPPlaylist read Get_Playlist; end; // IWMPCdrom : IWMPCdrom: Public interface. IWMPCdromDisp = dispinterface ['{CFAB6E98-8730-11D3-B388-00C04F68574B}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // eject : Eject the CD in the CDROM drive procedure eject;dispid 253; // driveSpecifier : Returns the CDROM drive specifier property driveSpecifier:WideString readonly dispid 251; // Playlist : Returns the playlist of tracks currently in the CDROM drive property Playlist:IWMPPlaylist readonly dispid 252; end; // IWMPClosedCaption : IWMPClosedCaption: Public interface. IWMPClosedCaption = interface(IDispatch) ['{4F2DF574-C588-11D3-9ED0-00C04FB6E937}'] function Get_SAMIStyle : WideString; safecall; procedure Set_SAMIStyle(const pbstrSAMIStyle:WideString); safecall; function Get_SAMILang : WideString; safecall; procedure Set_SAMILang(const pbstrSAMILang:WideString); safecall; function Get_SAMIFileName : WideString; safecall; procedure Set_SAMIFileName(const pbstrSAMIFileName:WideString); safecall; function Get_captioningId : WideString; safecall; procedure Set_captioningId(const pbstrCaptioningID:WideString); safecall; // SAMIStyle : Returns the previously set SAMI style property SAMIStyle:WideString read Get_SAMIStyle write Set_SAMIStyle; // SAMILang : Returns the previously set SAMI language property SAMILang:WideString read Get_SAMILang write Set_SAMILang; // SAMIFileName : Returns the previously set SAMI file name property SAMIFileName:WideString read Get_SAMIFileName write Set_SAMIFileName; // captioningId : Returns the previously set Captioning ID property captioningId:WideString read Get_captioningId write Set_captioningId; end; // IWMPClosedCaption : IWMPClosedCaption: Public interface. IWMPClosedCaptionDisp = dispinterface ['{4F2DF574-C588-11D3-9ED0-00C04FB6E937}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // SAMIStyle : Returns the previously set SAMI style property SAMIStyle:WideString dispid 951; // SAMILang : Returns the previously set SAMI language property SAMILang:WideString dispid 952; // SAMIFileName : Returns the previously set SAMI file name property SAMIFileName:WideString dispid 953; // captioningId : Returns the previously set Captioning ID property captioningId:WideString dispid 954; end; // IWMPError : IWMPError: Public interface. IWMPError = interface(IDispatch) ['{A12DCF7D-14AB-4C1B-A8CD-63909F06025B}'] // clearErrorQueue : Clears the error queue procedure clearErrorQueue;safecall; function Get_errorCount : Integer; safecall; function Get_Item(dwIndex:Integer) : IWMPErrorItem; safecall; // webHelp : Launches WebHelp procedure webHelp;safecall; // errorCount : Returns the number of error items property errorCount:Integer read Get_errorCount; // Item : Returns an error item object property Item[dwIndex:Integer]:IWMPErrorItem read Get_Item; end; // IWMPError : IWMPError: Public interface. IWMPErrorDisp = dispinterface ['{A12DCF7D-14AB-4C1B-A8CD-63909F06025B}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // clearErrorQueue : Clears the error queue procedure clearErrorQueue;dispid 851; // webHelp : Launches WebHelp procedure webHelp;dispid 854; // errorCount : Returns the number of error items property errorCount:Integer readonly dispid 852; // Item : Returns an error item object property Item[dwIndex:Integer]:IWMPErrorItem readonly dispid 853; end; // IWMPErrorItem : IWMPErrorItem: Public interface. IWMPErrorItem = interface(IDispatch) ['{3614C646-3B3B-4DE7-A81E-930E3F2127B3}'] function Get_errorCode : Integer; safecall; function Get_errorDescription : WideString; safecall; function Get_errorContext : OleVariant; safecall; function Get_remedy : Integer; safecall; function Get_customUrl : WideString; safecall; // errorCode : Returns the error code property errorCode:Integer read Get_errorCode; // errorDescription : Returns a description of the error property errorDescription:WideString read Get_errorDescription; // errorContext : Returns context information for the error property errorContext:OleVariant read Get_errorContext; // remedy : Returns remedy code for the error property remedy:Integer read Get_remedy; // customUrl : Returns a custom url for this error (if avail) property customUrl:WideString read Get_customUrl; end; // IWMPErrorItem : IWMPErrorItem: Public interface. IWMPErrorItemDisp = dispinterface ['{3614C646-3B3B-4DE7-A81E-930E3F2127B3}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // errorCode : Returns the error code property errorCode:Integer readonly dispid 901; // errorDescription : Returns a description of the error property errorDescription:WideString readonly dispid 902; // errorContext : Returns context information for the error property errorContext:OleVariant readonly dispid 903; // remedy : Returns remedy code for the error property remedy:Integer readonly dispid 904; // customUrl : Returns a custom url for this error (if avail) property customUrl:WideString readonly dispid 905; end; // IWMPDVD : IWMPDVD: Public interface. IWMPDVD = interface(IDispatch) ['{8DA61686-4668-4A5C-AE5D-803193293DBE}'] function Get_isAvailable(bstrItem:WideString) : WordBool; safecall; function Get_domain : WideString; safecall; // topMenu : Displays the top menu of the DVD procedure topMenu;safecall; // titleMenu : Displays the title menu of the current DVD title procedure titleMenu;safecall; // back : Navigates back one menu procedure back;safecall; // resume : Removes the menu from the screen and returns to playing the DVD procedure resume;safecall; // isAvailable : Returns whether or not the specified DVD functionality is available property isAvailable[bstrItem:WideString]:WordBool read Get_isAvailable; // domain : Returns the current DVD domain property domain:WideString read Get_domain; end; // IWMPDVD : IWMPDVD: Public interface. IWMPDVDDisp = dispinterface ['{8DA61686-4668-4A5C-AE5D-803193293DBE}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // topMenu : Displays the top menu of the DVD procedure topMenu;dispid 1003; // titleMenu : Displays the title menu of the current DVD title procedure titleMenu;dispid 1004; // back : Navigates back one menu procedure back;dispid 1005; // resume : Removes the menu from the screen and returns to playing the DVD procedure resume;dispid 1006; // isAvailable : Returns whether or not the specified DVD functionality is available property isAvailable[bstrItem:WideString]:WordBool readonly dispid 1001; // domain : Returns the current DVD domain property domain:WideString readonly dispid 1002; end; // IWMPPlayerApplication : IWMPPlayerApplication: Public interface. IWMPPlayerApplication = interface(IDispatch) ['{40897764-CEAB-47BE-AD4A-8E28537F9BBF}'] // switchToPlayerApplication : Switches the display to player application procedure switchToPlayerApplication;safecall; // switchToControl : Switches the display to control procedure switchToControl;safecall; function Get_playerDocked : WordBool; safecall; function Get_hasDisplay : WordBool; safecall; // playerDocked : Returns a boolean value specifying whether or not the player is docked property playerDocked:WordBool read Get_playerDocked; // hasDisplay : Returns a boolean value specifying whether or not the control has display property hasDisplay:WordBool read Get_hasDisplay; end; // IWMPPlayerApplication : IWMPPlayerApplication: Public interface. IWMPPlayerApplicationDisp = dispinterface ['{40897764-CEAB-47BE-AD4A-8E28537F9BBF}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // switchToPlayerApplication : Switches the display to player application procedure switchToPlayerApplication;dispid 1101; // switchToControl : Switches the display to control procedure switchToControl;dispid 1102; // playerDocked : Returns a boolean value specifying whether or not the player is docked property playerDocked:WordBool readonly dispid 1103; // hasDisplay : Returns a boolean value specifying whether or not the control has display property hasDisplay:WordBool readonly dispid 1104; end; // IWMPPlayer3 : IWMPPlayer3: Public interface. IWMPPlayer3 = interface(IWMPCore2) ['{54062B68-052A-4C25-A39F-8B63346511D4}'] function Get_enabled : WordBool; safecall; procedure Set_enabled(const pbEnabled:WordBool); safecall; function Get_fullScreen : WordBool; safecall; procedure Set_fullScreen(const pbFullScreen:WordBool); safecall; function Get_enableContextMenu : WordBool; safecall; procedure Set_enableContextMenu(const pbEnableContextMenu:WordBool); safecall; procedure Set_uiMode(const pbstrMode:WideString); safecall; function Get_uiMode : WideString; safecall; function Get_stretchToFit : WordBool; safecall; procedure Set_stretchToFit(const pbEnabled:WordBool); safecall; function Get_windowlessVideo : WordBool; safecall; procedure Set_windowlessVideo(const pbEnabled:WordBool); safecall; // enabled : Returns a boolen value specifying whether or not the control is enabled property enabled:WordBool read Get_enabled write Set_enabled; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool read Get_fullScreen write Set_fullScreen; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool read Get_enableContextMenu write Set_enableContextMenu; // uiMode : Specifies the ui mode to select property uiMode:WideString read Get_uiMode write Set_uiMode; // stretchToFit : Returns a boolen value specifying whether or not video is stretched property stretchToFit:WordBool read Get_stretchToFit write Set_stretchToFit; // windowlessVideo : Returns a boolen value specifying whether or not video is windowless property windowlessVideo:WordBool read Get_windowlessVideo write Set_windowlessVideo; end; // IWMPPlayer3 : IWMPPlayer3: Public interface. IWMPPlayer3Disp = dispinterface ['{54062B68-052A-4C25-A39F-8B63346511D4}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; // dvd : Returns the DVD handler property dvd:IWMPDVD readonly dispid 40; // enabled : Returns a boolen value specifying whether or not the control is enabled property enabled:WordBool dispid 19; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool dispid 21; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool dispid 22; // uiMode : Specifies the ui mode to select property uiMode:WideString dispid 23; // stretchToFit : Returns a boolen value specifying whether or not video is stretched property stretchToFit:WordBool dispid 24; // windowlessVideo : Returns a boolen value specifying whether or not video is windowless property windowlessVideo:WordBool dispid 25; end; // IWMPPlayer2 : IWMPPlayer2: Public interface. IWMPPlayer2 = interface(IWMPCore) ['{0E6B01D1-D407-4C85-BF5F-1C01F6150280}'] function Get_enabled : WordBool; safecall; procedure Set_enabled(const pbEnabled:WordBool); safecall; function Get_fullScreen : WordBool; safecall; procedure Set_fullScreen(const pbFullScreen:WordBool); safecall; function Get_enableContextMenu : WordBool; safecall; procedure Set_enableContextMenu(const pbEnableContextMenu:WordBool); safecall; procedure Set_uiMode(const pbstrMode:WideString); safecall; function Get_uiMode : WideString; safecall; function Get_stretchToFit : WordBool; safecall; procedure Set_stretchToFit(const pbEnabled:WordBool); safecall; function Get_windowlessVideo : WordBool; safecall; procedure Set_windowlessVideo(const pbEnabled:WordBool); safecall; // enabled : Returns a boolen value specifying whether or not the control is enabled property enabled:WordBool read Get_enabled write Set_enabled; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool read Get_fullScreen write Set_fullScreen; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool read Get_enableContextMenu write Set_enableContextMenu; // uiMode : Specifies the ui mode to select property uiMode:WideString read Get_uiMode write Set_uiMode; // stretchToFit : Returns a boolen value specifying whether or not video is stretched property stretchToFit:WordBool read Get_stretchToFit write Set_stretchToFit; // windowlessVideo : Returns a boolen value specifying whether or not video is windowless property windowlessVideo:WordBool read Get_windowlessVideo write Set_windowlessVideo; end; // IWMPPlayer2 : IWMPPlayer2: Public interface. IWMPPlayer2Disp = dispinterface ['{0E6B01D1-D407-4C85-BF5F-1C01F6150280}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; // enabled : Returns a boolen value specifying whether or not the control is enabled property enabled:WordBool dispid 19; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool dispid 21; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool dispid 22; // uiMode : Specifies the ui mode to select property uiMode:WideString dispid 23; // stretchToFit : Returns a boolen value specifying whether or not video is stretched property stretchToFit:WordBool dispid 24; // windowlessVideo : Returns a boolen value specifying whether or not video is windowless property windowlessVideo:WordBool dispid 25; end; // IWMPPlayer : IWMPPlayer: Public interface. IWMPPlayer = interface(IWMPCore) ['{6BF52A4F-394A-11D3-B153-00C04F79FAA6}'] function Get_enabled : WordBool; safecall; procedure Set_enabled(const pbEnabled:WordBool); safecall; function Get_fullScreen : WordBool; safecall; procedure Set_fullScreen(const pbFullScreen:WordBool); safecall; function Get_enableContextMenu : WordBool; safecall; procedure Set_enableContextMenu(const pbEnableContextMenu:WordBool); safecall; procedure Set_uiMode(const pbstrMode:WideString); safecall; function Get_uiMode : WideString; safecall; // enabled : Returns a boolen value specifying whether or not the control is enabled property enabled:WordBool read Get_enabled write Set_enabled; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool read Get_fullScreen write Set_fullScreen; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool read Get_enableContextMenu write Set_enableContextMenu; // uiMode : Specifies the ui mode to select property uiMode:WideString read Get_uiMode write Set_uiMode; end; // IWMPPlayer : IWMPPlayer: Public interface. IWMPPlayerDisp = dispinterface ['{6BF52A4F-394A-11D3-B153-00C04F79FAA6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // close : Closes the media procedure close;dispid 3; // launchURL : procedure launchURL(bstrURL:WideString);dispid 12; // URL : Returns or sets the URL property URL:WideString dispid 1; // openState : Returns the open state of the player property openState:WMPOpenState readonly dispid 2; // playState : Returns the play state of the player property playState:WMPPlayState readonly dispid 10; // controls : Returns the control handler property controls:IWMPControls readonly dispid 4; // settings : Returns the settings handler property settings:IWMPSettings readonly dispid 5; // currentMedia : Returns or sets the current media object property currentMedia:IWMPMedia dispid 6; // mediaCollection : Returns the media collection handler property mediaCollection:IWMPMediaCollection readonly dispid 8; // playlistCollection : Returns the playlist collection handler property playlistCollection:IWMPPlaylistCollection readonly dispid 9; // versionInfo : Returns the version information for the player property versionInfo:WideString readonly dispid 11; // network : Returns the network information handler property network:IWMPNetwork readonly dispid 7; // currentPlaylist : Returns/sets the current playlist property currentPlaylist:IWMPPlaylist dispid 13; // cdromCollection : Get the CDROM drive collection property cdromCollection:IWMPCdromCollection readonly dispid 14; // closedCaption : Returns the closed caption handler property closedCaption:IWMPClosedCaption readonly dispid 15; // isOnline : Returns whether the machine is online. property isOnline:WordBool readonly dispid 16; // Error : Returns the error object property Error:IWMPError readonly dispid 17; // status : Returns status string property status:WideString readonly dispid 18; // enabled : Returns a boolen value specifying whether or not the control is enabled property enabled:WordBool dispid 19; // fullScreen : Returns a boolean value specifying whether or not the control is in full screen mode property fullScreen:WordBool dispid 21; // enableContextMenu : Returns a boolean value specifying whether or not the context menu is enabled on the control property enableContextMenu:WordBool dispid 22; // uiMode : Specifies the ui mode to select property uiMode:WideString dispid 23; end; // IWMPErrorItem2 : IWMPErrorItem2: Public interface. IWMPErrorItem2 = interface(IWMPErrorItem) ['{F75CCEC0-C67C-475C-931E-8719870BEE7D}'] function Get_condition : Integer; safecall; // condition : Returns condition for the error property condition:Integer read Get_condition; end; // IWMPErrorItem2 : IWMPErrorItem2: Public interface. IWMPErrorItem2Disp = dispinterface ['{F75CCEC0-C67C-475C-931E-8719870BEE7D}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // errorCode : Returns the error code property errorCode:Integer readonly dispid 901; // errorDescription : Returns a description of the error property errorDescription:WideString readonly dispid 902; // errorContext : Returns context information for the error property errorContext:OleVariant readonly dispid 903; // remedy : Returns remedy code for the error property remedy:Integer readonly dispid 904; // customUrl : Returns a custom url for this error (if avail) property customUrl:WideString readonly dispid 905; // condition : Returns condition for the error property condition:Integer readonly dispid 906; end; // IWMPControls2 : IWMPControls2: Public interface. IWMPControls2 = interface(IWMPControls) ['{6F030D25-0890-480F-9775-1F7E40AB5B8E}'] // step : Advances the video one frame procedure step(lStep:Integer);safecall; end; // IWMPControls2 : IWMPControls2: Public interface. IWMPControls2Disp = dispinterface ['{6F030D25-0890-480F-9775-1F7E40AB5B8E}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // play : Begins playing media procedure play;dispid 51; // stop : Stops play of media procedure stop;dispid 52; // pause : Pauses play of media procedure pause;dispid 53; // fastForward : Fast play of media in forward direction procedure fastForward;dispid 54; // fastReverse : Fast play of media in reverse direction procedure fastReverse;dispid 55; // next : Sets the current item to the next item in the playlist procedure next;dispid 58; // previous : Sets the current item to the previous item in the playlist procedure previous;dispid 59; // playItem : Sets the current item and plays it procedure playItem(pIWMPMedia:IWMPMedia);dispid 63; // step : Advances the video one frame procedure step(lStep:Integer);dispid 64; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool readonly dispid 62; // currentPosition : Returns the current position in media property currentPosition:Double dispid 56; // currentPositionString : Returns the current position in media as a string property currentPositionString:WideString readonly dispid 57; // currentItem : Returns/Sets the play item property currentItem:IWMPMedia dispid 60; // currentMarker : Returns the current marker property currentMarker:Integer dispid 61; end; // IWMPMedia2 : IWMPMedia2: Public interface. IWMPMedia2 = interface(IWMPMedia) ['{AB7C88BB-143E-4EA4-ACC3-E4350B2106C3}'] function Get_Error : IWMPErrorItem; safecall; // Error : Returns an error item pointer for a media specific error property Error:IWMPErrorItem read Get_Error; end; // IWMPMedia2 : IWMPMedia2: Public interface. IWMPMedia2Disp = dispinterface ['{AB7C88BB-143E-4EA4-ACC3-E4350B2106C3}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getMarkerTime : Returns the time of a marker function getMarkerTime(MarkerNum:Integer):Double;dispid 755; // getMarkerName : Returns the name of a marker function getMarkerName(MarkerNum:Integer):WideString;dispid 756; // getAttributeName : Returns the name of the attribute whose index has been specified function getAttributeName(lIndex:Integer):WideString;dispid 760; // getItemInfo : Returns the value of specified attribute for this media function getItemInfo(bstrItemName:WideString):WideString;dispid 761; // setItemInfo : Sets the value of specified attribute for this media procedure setItemInfo(bstrItemName:WideString;bstrVal:WideString);dispid 762; // getItemInfoByAtom : Gets an item info by atom function getItemInfoByAtom(lAtom:Integer):WideString;dispid 765; // isMemberOf : Is the media a member of the given playlist function isMemberOf(pPlaylist:IWMPPlaylist):WordBool;dispid 766; // isReadOnlyItem : Is the attribute read only function isReadOnlyItem(bstrItemName:WideString):WordBool;dispid 767; // isIdentical : Determines if the supplied object is the same as the this one property isIdentical[pIWMPMedia:IWMPMedia]:WordBool readonly dispid 763; // sourceURL : Returns the media URL property sourceURL:WideString readonly dispid 751; // name : Returns the name of the media property name:WideString dispid 764; // imageSourceWidth : Returns the original width of the source images property imageSourceWidth:Integer readonly dispid 752; // imageSourceHeight : Returns the original height of the source images property imageSourceHeight:Integer readonly dispid 753; // markerCount : Returns the number of markers in the file property markerCount:Integer readonly dispid 754; // duration : Returns duration of current media property duration:Double readonly dispid 757; // durationString : Returns duration of current media as a string property durationString:WideString readonly dispid 758; // attributeCount : Returns the count of the attributes associated with this media property attributeCount:Integer readonly dispid 759; // Error : Returns an error item pointer for a media specific error property Error:IWMPErrorItem readonly dispid 768; end; // IWMPMedia3 : IWMPMedia3: Public interface. IWMPMedia3 = interface(IWMPMedia2) ['{F118EFC7-F03A-4FB4-99C9-1C02A5C1065B}'] // getAttributeCountByType : function getAttributeCountByType(bstrType:WideString;bstrLanguage:WideString):Integer;safecall; // getItemInfoByType : function getItemInfoByType(bstrType:WideString;bstrLanguage:WideString;lIndex:Integer):OleVariant;safecall; end; // IWMPMedia3 : IWMPMedia3: Public interface. IWMPMedia3Disp = dispinterface ['{F118EFC7-F03A-4FB4-99C9-1C02A5C1065B}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getMarkerTime : Returns the time of a marker function getMarkerTime(MarkerNum:Integer):Double;dispid 755; // getMarkerName : Returns the name of a marker function getMarkerName(MarkerNum:Integer):WideString;dispid 756; // getAttributeName : Returns the name of the attribute whose index has been specified function getAttributeName(lIndex:Integer):WideString;dispid 760; // getItemInfo : Returns the value of specified attribute for this media function getItemInfo(bstrItemName:WideString):WideString;dispid 761; // setItemInfo : Sets the value of specified attribute for this media procedure setItemInfo(bstrItemName:WideString;bstrVal:WideString);dispid 762; // getItemInfoByAtom : Gets an item info by atom function getItemInfoByAtom(lAtom:Integer):WideString;dispid 765; // isMemberOf : Is the media a member of the given playlist function isMemberOf(pPlaylist:IWMPPlaylist):WordBool;dispid 766; // isReadOnlyItem : Is the attribute read only function isReadOnlyItem(bstrItemName:WideString):WordBool;dispid 767; // getAttributeCountByType : function getAttributeCountByType(bstrType:WideString;bstrLanguage:WideString):Integer;dispid 769; // getItemInfoByType : function getItemInfoByType(bstrType:WideString;bstrLanguage:WideString;lIndex:Integer):OleVariant;dispid 770; // isIdentical : Determines if the supplied object is the same as the this one property isIdentical[pIWMPMedia:IWMPMedia]:WordBool readonly dispid 763; // sourceURL : Returns the media URL property sourceURL:WideString readonly dispid 751; // name : Returns the name of the media property name:WideString dispid 764; // imageSourceWidth : Returns the original width of the source images property imageSourceWidth:Integer readonly dispid 752; // imageSourceHeight : Returns the original height of the source images property imageSourceHeight:Integer readonly dispid 753; // markerCount : Returns the number of markers in the file property markerCount:Integer readonly dispid 754; // duration : Returns duration of current media property duration:Double readonly dispid 757; // durationString : Returns duration of current media as a string property durationString:WideString readonly dispid 758; // attributeCount : Returns the count of the attributes associated with this media property attributeCount:Integer readonly dispid 759; // Error : Returns an error item pointer for a media specific error property Error:IWMPErrorItem readonly dispid 768; end; // IWMPMetadataPicture : IWMPMetadataPicture: Not Public. Internal interface used by Windows Media Player. IWMPMetadataPicture = interface(IDispatch) ['{5C29BBE0-F87D-4C45-AA28-A70F0230FFA9}'] function Get_mimeType : WideString; safecall; function Get_pictureType : WideString; safecall; function Get_Description : WideString; safecall; function Get_URL : WideString; safecall; // mimeType : property mimeType:WideString read Get_mimeType; // pictureType : property pictureType:WideString read Get_pictureType; // Description : property Description:WideString read Get_Description; // URL : property URL:WideString read Get_URL; end; // IWMPMetadataPicture : IWMPMetadataPicture: Not Public. Internal interface used by Windows Media Player. IWMPMetadataPictureDisp = dispinterface ['{5C29BBE0-F87D-4C45-AA28-A70F0230FFA9}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // mimeType : property mimeType:WideString readonly dispid 1051; // pictureType : property pictureType:WideString readonly dispid 1052; // Description : property Description:WideString readonly dispid 1053; // URL : property URL:WideString readonly dispid 1054; end; // IWMPMetadataText : IWMPMetadataText: Not Public. Internal interface used by Windows Media Player. IWMPMetadataText = interface(IDispatch) ['{769A72DB-13D2-45E2-9C48-53CA9D5B7450}'] function Get_Description : WideString; safecall; function Get_text_ : WideString; safecall; // Description : property Description:WideString read Get_Description; // text : property text_:WideString read Get_text_; end; // IWMPMetadataText : IWMPMetadataText: Not Public. Internal interface used by Windows Media Player. IWMPMetadataTextDisp = dispinterface ['{769A72DB-13D2-45E2-9C48-53CA9D5B7450}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Description : property Description:WideString readonly dispid 1056; // text : property text_:WideString readonly dispid 1055; end; // IWMPSettings2 : IWMPSettings2: Public interface. IWMPSettings2 = interface(IWMPSettings) ['{FDA937A4-EECE-4DA5-A0B6-39BF89ADE2C2}'] function Get_defaultAudioLanguage : Integer; safecall; function Get_mediaAccessRights : WideString; safecall; // requestMediaAccessRights : function requestMediaAccessRights(bstrDesiredAccess:WideString):WordBool;safecall; // defaultAudioLanguage : Returns the LCID of default audio language property defaultAudioLanguage:Integer read Get_defaultAudioLanguage; // mediaAccessRights : property mediaAccessRights:WideString read Get_mediaAccessRights; end; // IWMPSettings2 : IWMPSettings2: Public interface. IWMPSettings2Disp = dispinterface ['{FDA937A4-EECE-4DA5-A0B6-39BF89ADE2C2}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getMode : Returns the mode of the playlist function getMode(bstrMode:WideString):WordBool;dispid 110; // setMode : Sets the mode of the playlist procedure setMode(bstrMode:WideString;varfMode:WordBool);dispid 111; // requestMediaAccessRights : function requestMediaAccessRights(bstrDesiredAccess:WideString):WordBool;dispid 116; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool readonly dispid 113; // autoStart : Returns whether media should automatically begin playing property autoStart:WordBool dispid 101; // baseURL : Returns the base URL used for relative path resolution property baseURL:WideString dispid 108; // defaultFrame : Returns the frame location that changes when a URL flip occurs property defaultFrame:WideString dispid 109; // invokeURLs : Returns whether URL events should spawn a browser. property invokeURLs:WordBool dispid 103; // mute : Returns whether audio should be muted. property mute:WordBool dispid 104; // playCount : Returns how many times media should play property playCount:Integer dispid 105; // rate : Returns current playback rate property rate:Double dispid 106; // balance : Returns current audio Balance property balance:Integer dispid 102; // volume : Returns current audio volume property volume:Integer dispid 107; // enableErrorDialogs : Returns whether error dialogs are shown by default when embedded property enableErrorDialogs:WordBool dispid 112; // defaultAudioLanguage : Returns the LCID of default audio language property defaultAudioLanguage:Integer readonly dispid 114; // mediaAccessRights : property mediaAccessRights:WideString readonly dispid 115; end; // IWMPControls3 : IWMPControls3: Public interface. IWMPControls3 = interface(IWMPControls2) ['{A1D1110E-D545-476A-9A78-AC3E4CB1E6BD}'] function Get_audioLanguageCount : Integer; safecall; // getAudioLanguageID : Returns the LCID corresponding to the index function getAudioLanguageID(lIndex:Integer):Integer;safecall; // getAudioLanguageDescription : Returns the desription corresponding to the index function getAudioLanguageDescription(lIndex:Integer):WideString;safecall; function Get_currentAudioLanguage : Integer; safecall; procedure Set_currentAudioLanguage(const plLangID:Integer); safecall; function Get_currentAudioLanguageIndex : Integer; safecall; procedure Set_currentAudioLanguageIndex(const plIndex:Integer); safecall; // getLanguageName : Returns the human-readable name of language specified by LCID function getLanguageName(lLangID:Integer):WideString;safecall; function Get_currentPositionTimecode : WideString; safecall; procedure Set_currentPositionTimecode(const bstrTimecode:WideString); safecall; // audioLanguageCount : Returns the count of supported audio languages property audioLanguageCount:Integer read Get_audioLanguageCount; // currentAudioLanguage : Gets the current audio language setting for playback property currentAudioLanguage:Integer read Get_currentAudioLanguage write Set_currentAudioLanguage; // currentAudioLanguageIndex : Gets the current audio language index setting for playback property currentAudioLanguageIndex:Integer read Get_currentAudioLanguageIndex write Set_currentAudioLanguageIndex; // currentPositionTimecode : Returns the current timecode position in media property currentPositionTimecode:WideString read Get_currentPositionTimecode write Set_currentPositionTimecode; end; // IWMPControls3 : IWMPControls3: Public interface. IWMPControls3Disp = dispinterface ['{A1D1110E-D545-476A-9A78-AC3E4CB1E6BD}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // play : Begins playing media procedure play;dispid 51; // stop : Stops play of media procedure stop;dispid 52; // pause : Pauses play of media procedure pause;dispid 53; // fastForward : Fast play of media in forward direction procedure fastForward;dispid 54; // fastReverse : Fast play of media in reverse direction procedure fastReverse;dispid 55; // next : Sets the current item to the next item in the playlist procedure next;dispid 58; // previous : Sets the current item to the previous item in the playlist procedure previous;dispid 59; // playItem : Sets the current item and plays it procedure playItem(pIWMPMedia:IWMPMedia);dispid 63; // step : Advances the video one frame procedure step(lStep:Integer);dispid 64; // getAudioLanguageID : Returns the LCID corresponding to the index function getAudioLanguageID(lIndex:Integer):Integer;dispid 66; // getAudioLanguageDescription : Returns the desription corresponding to the index function getAudioLanguageDescription(lIndex:Integer):WideString;dispid 67; // getLanguageName : Returns the human-readable name of language specified by LCID function getLanguageName(lLangID:Integer):WideString;dispid 70; // isAvailable : Returns whether or not the specified media functionality is available property isAvailable[bstrItem:WideString]:WordBool readonly dispid 62; // currentPosition : Returns the current position in media property currentPosition:Double dispid 56; // currentPositionString : Returns the current position in media as a string property currentPositionString:WideString readonly dispid 57; // currentItem : Returns/Sets the play item property currentItem:IWMPMedia dispid 60; // currentMarker : Returns the current marker property currentMarker:Integer dispid 61; // audioLanguageCount : Returns the count of supported audio languages property audioLanguageCount:Integer readonly dispid 65; // currentAudioLanguage : Gets the current audio language setting for playback property currentAudioLanguage:Integer dispid 68; // currentAudioLanguageIndex : Gets the current audio language index setting for playback property currentAudioLanguageIndex:Integer dispid 69; // currentPositionTimecode : Returns the current timecode position in media property currentPositionTimecode:WideString dispid 71; end; // IWMPClosedCaption2 : IWMPClosedCaption2: Public interface. IWMPClosedCaption2 = interface(IWMPClosedCaption) ['{350BA78B-6BC8-4113-A5F5-312056934EB6}'] function Get_SAMILangCount : Integer; safecall; // getSAMILangName : Returns the name of a SAMI language by index function getSAMILangName(nIndex:Integer):WideString;safecall; // getSAMILangID : Returns the ID of a SAMI language by index function getSAMILangID(nIndex:Integer):Integer;safecall; function Get_SAMIStyleCount : Integer; safecall; // getSAMIStyleName : Returns the name of a SAMI style by index function getSAMIStyleName(nIndex:Integer):WideString;safecall; // SAMILangCount : Returns the count of SAMI languages property SAMILangCount:Integer read Get_SAMILangCount; // SAMIStyleCount : Returns the count of SAMI styles property SAMIStyleCount:Integer read Get_SAMIStyleCount; end; // IWMPClosedCaption2 : IWMPClosedCaption2: Public interface. IWMPClosedCaption2Disp = dispinterface ['{350BA78B-6BC8-4113-A5F5-312056934EB6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getSAMILangName : Returns the name of a SAMI language by index function getSAMILangName(nIndex:Integer):WideString;dispid 956; // getSAMILangID : Returns the ID of a SAMI language by index function getSAMILangID(nIndex:Integer):Integer;dispid 957; // getSAMIStyleName : Returns the name of a SAMI style by index function getSAMIStyleName(nIndex:Integer):WideString;dispid 959; // SAMIStyle : Returns the previously set SAMI style property SAMIStyle:WideString dispid 951; // SAMILang : Returns the previously set SAMI language property SAMILang:WideString dispid 952; // SAMIFileName : Returns the previously set SAMI file name property SAMIFileName:WideString dispid 953; // captioningId : Returns the previously set Captioning ID property captioningId:WideString dispid 954; // SAMILangCount : Returns the count of SAMI languages property SAMILangCount:Integer readonly dispid 955; // SAMIStyleCount : Returns the count of SAMI styles property SAMIStyleCount:Integer readonly dispid 958; end; // IWMPMediaCollection2 : IWMPMediaCollection2: Public interface for Windows Media Player SDK. IWMPMediaCollection2 = interface(IWMPMediaCollection) ['{8BA957F5-FD8C-4791-B82D-F840401EE474}'] // createQuery : Creates an empty query object function createQuery:IWMPQuery;safecall; // getPlaylistByQuery : Creates a playlist from a query function getPlaylistByQuery(pQuery:IWMPQuery;bstrMediaType:WideString;bstrSortAttribute:WideString;fSortAscending:WordBool):IWMPPlaylist;safecall; // getStringCollectionByQuery : Creates a string collection from a query function getStringCollectionByQuery(bstrAttribute:WideString;pQuery:IWMPQuery;bstrMediaType:WideString;bstrSortAttribute:WideString;fSortAscending:WordBool):IWMPStringCollection;safecall; // getByAttributeAndMediaType : Returns a collection of items with the given attribute and media type function getByAttributeAndMediaType(bstrAttribute:WideString;bstrValue:WideString;bstrMediaType:WideString):IWMPPlaylist;safecall; end; // IWMPMediaCollection2 : IWMPMediaCollection2: Public interface for Windows Media Player SDK. IWMPMediaCollection2Disp = dispinterface ['{8BA957F5-FD8C-4791-B82D-F840401EE474}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // add : Creates a new media object function add(bstrURL:WideString):IWMPMedia;dispid 452; // getAll : Returns a collection of all the items function getAll:IWMPPlaylist;dispid 453; // getByName : Returns a collection of items with the given name function getByName(bstrName:WideString):IWMPPlaylist;dispid 454; // getByGenre : Returns a collection of items with the given genre function getByGenre(bstrGenre:WideString):IWMPPlaylist;dispid 455; // getByAuthor : Returns a collection of items by a given author function getByAuthor(bstrAuthor:WideString):IWMPPlaylist;dispid 456; // getByAlbum : Returns a collection of items from the given album function getByAlbum(bstrAlbum:WideString):IWMPPlaylist;dispid 457; // getByAttribute : Returns a collection of items with the given attribute function getByAttribute(bstrAttribute:WideString;bstrValue:WideString):IWMPPlaylist;dispid 458; // remove : Removes an item from the media collection procedure remove(pItem:IWMPMedia;varfDeleteFile:WordBool);dispid 459; // getAttributeStringCollection : Returns the string collection associated with an attribute function getAttributeStringCollection(bstrAttribute:WideString;bstrMediaType:WideString):IWMPStringCollection;dispid 461; // getMediaAtom : Gets an atom associated with an item name which can be requested from an IWMPMedia out of this collection via getItemInfoByAtom function getMediaAtom(bstrItemName:WideString):Integer;dispid 470; // setDeleted : Sets the deleted flag on a media object procedure setDeleted(pItem:IWMPMedia;varfIsDeleted:WordBool);dispid 471; // isDeleted : Gets the deleted flag on a media object function isDeleted(pItem:IWMPMedia):WordBool;dispid 472; // createQuery : Creates an empty query object function createQuery:IWMPQuery;dispid 1401; // getPlaylistByQuery : Creates a playlist from a query function getPlaylistByQuery(pQuery:IWMPQuery;bstrMediaType:WideString;bstrSortAttribute:WideString;fSortAscending:WordBool):IWMPPlaylist;dispid 1402; // getStringCollectionByQuery : Creates a string collection from a query function getStringCollectionByQuery(bstrAttribute:WideString;pQuery:IWMPQuery;bstrMediaType:WideString;bstrSortAttribute:WideString;fSortAscending:WordBool):IWMPStringCollection;dispid 1403; // getByAttributeAndMediaType : Returns a collection of items with the given attribute and media type function getByAttributeAndMediaType(bstrAttribute:WideString;bstrValue:WideString;bstrMediaType:WideString):IWMPPlaylist;dispid 1404; end; // IWMPQuery : IWMPQuery: Public interface for Windows Media Player SDK. IWMPQuery = interface(IDispatch) ['{A00918F3-A6B0-4BFB-9189-FD834C7BC5A5}'] // addCondition : Adds a single AND query parameter to existing group procedure addCondition(bstrAttribute:WideString;bstrOperator:WideString;bstrValue:WideString);safecall; // beginNextGroup : Starts a new OR query group procedure beginNextGroup;safecall; end; // IWMPQuery : IWMPQuery: Public interface for Windows Media Player SDK. IWMPQueryDisp = dispinterface ['{A00918F3-A6B0-4BFB-9189-FD834C7BC5A5}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // addCondition : Adds a single AND query parameter to existing group procedure addCondition(bstrAttribute:WideString;bstrOperator:WideString;bstrValue:WideString);dispid 1351; // beginNextGroup : Starts a new OR query group procedure beginNextGroup;dispid 1352; end; // IWMPStringCollection2 : IWMPStringCollection2: Public interface for Windows Media Player SDK. IWMPStringCollection2 = interface(IWMPStringCollection) ['{46AD648D-53F1-4A74-92E2-2A1B68D63FD4}'] // isIdentical : Determines if the supplied object is the same as this one function isIdentical(pIWMPStringCollection2:IWMPStringCollection2):WordBool;safecall; // getItemInfo : Gets an attribute from a string collection backing object function getItemInfo(lCollectionIndex:Integer;bstrItemName:WideString):WideString;safecall; // getAttributeCountByType : Gets count of values for a particular attribute function getAttributeCountByType(lCollectionIndex:Integer;bstrType:WideString;bstrLanguage:WideString):Integer;safecall; // getItemInfoByType : Gets one value of an attribute from a string collection backing object function getItemInfoByType(lCollectionIndex:Integer;bstrType:WideString;bstrLanguage:WideString;lAttributeIndex:Integer):OleVariant;safecall; end; // IWMPStringCollection2 : IWMPStringCollection2: Public interface for Windows Media Player SDK. IWMPStringCollection2Disp = dispinterface ['{46AD648D-53F1-4A74-92E2-2A1B68D63FD4}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Item : Returns the string at the given index function Item(lIndex:Integer):WideString;dispid 402; // isIdentical : Determines if the supplied object is the same as this one function isIdentical(pIWMPStringCollection2:IWMPStringCollection2):WordBool;dispid 1451; // getItemInfo : Gets an attribute from a string collection backing object function getItemInfo(lCollectionIndex:Integer;bstrItemName:WideString):WideString;dispid 1452; // getAttributeCountByType : Gets count of values for a particular attribute function getAttributeCountByType(lCollectionIndex:Integer;bstrType:WideString;bstrLanguage:WideString):Integer;dispid 1453; // getItemInfoByType : Gets one value of an attribute from a string collection backing object function getItemInfoByType(lCollectionIndex:Integer;bstrType:WideString;bstrLanguage:WideString;lAttributeIndex:Integer):OleVariant;dispid 1454; // count : Returns the number of items in the string collection property count:Integer readonly dispid 401; end; // IWMPPlayerServices : IWMPPlayerServices: Public interface for Windows Media Player SDK. IWMPPlayerServices = interface(IUnknown) ['{1D01FBDB-ADE2-4C8D-9842-C190B95C3306}'] // activateUIPlugin : function activateUIPlugin(bstrPlugin:WideString):HRESULT;stdcall; // setTaskPane : function setTaskPane(bstrTaskPane:WideString):HRESULT;stdcall; // setTaskPaneURL : function setTaskPaneURL(bstrTaskPane:WideString;bstrURL:WideString;bstrFriendlyName:WideString):HRESULT;stdcall; end; // IWMPPlayerServices2 : IWMPPlayerServices2: Public interface for Windows Media Player SDK. IWMPPlayerServices2 = interface(IWMPPlayerServices) ['{1BB1592F-F040-418A-9F71-17C7512B4D70}'] // setBackgroundProcessingPriority : function setBackgroundProcessingPriority(bstrPriority:WideString):HRESULT;stdcall; end; // IWMPRemoteMediaServices : IWMPRemoteMediaServices: Public interface for Windows Media Player SDK. IWMPRemoteMediaServices = interface(IUnknown) ['{CBB92747-741F-44FE-AB5B-F1A48F3B2A59}'] // GetServiceType : function GetServiceType(out pbstrType:WideString):HRESULT;stdcall; // GetApplicationName : function GetApplicationName(out pbstrName:WideString):HRESULT;stdcall; // GetScriptableObject : function GetScriptableObject(out pbstrName:WideString;out ppDispatch:IDispatch):HRESULT;stdcall; // GetCustomUIMode : function GetCustomUIMode(out pbstrFile:WideString):HRESULT;stdcall; end; // IWMPSyncServices : IWMPSyncServices: Public interface for Windows Media Player SDK. IWMPSyncServices = interface(IUnknown) ['{8B5050FF-E0A4-4808-B3A8-893A9E1ED894}'] function Get_deviceCount : Integer; stdcall; // getDevice : function getDevice(lIndex:Integer):HRESULT;stdcall; // deviceCount : property deviceCount:Integer read Get_deviceCount; end; // IWMPLibraryServices : IWMPLibraryServices: Public interface for Windows Media Player SDK. IWMPLibraryServices = interface(IUnknown) ['{39C2F8D5-1CF2-4D5E-AE09-D73492CF9EAA}'] // getCountByType : function getCountByType(wmplt:WMPLibraryType):HRESULT;stdcall; // getLibraryByType : function getLibraryByType(wmplt:WMPLibraryType;lIndex:Integer):HRESULT;stdcall; end; // IWMPLibrarySharingServices : IWMPLibrarySharingServices: Public interface for Windows Media Player SDK. IWMPLibrarySharingServices = interface(IUnknown) ['{82CBA86B-9F04-474B-A365-D6DD1466E541}'] // isLibraryShared : function isLibraryShared:HRESULT;stdcall; // isLibrarySharingEnabled : function isLibrarySharingEnabled:HRESULT;stdcall; // showLibrarySharing : function showLibrarySharing:HRESULT;stdcall; end; // IWMPLibrary2 : IWMPLibrary2: Public interface for Windows Media Player SDK. IWMPLibrary2 = interface(IWMPLibrary) ['{DD578A4E-79B1-426C-BF8F-3ADD9072500B}'] // getItemInfo : function getItemInfo(bstrItemName:WideString):HRESULT;stdcall; end; // IWMPFolderMonitorServices : IWMPFolderMonitorServices: Public interface for Windows Media Player SDK. IWMPFolderMonitorServices = interface(IUnknown) ['{788C8743-E57F-439D-A468-5BC77F2E59C6}'] function Get_count : Integer; stdcall; // Item : function Item(lIndex:Integer):HRESULT;stdcall; // add : function add(bstrFolder:WideString):HRESULT;stdcall; // remove : function remove(lIndex:Integer):HRESULT;stdcall; function Get_scanState : WMPFolderScanState; stdcall; function Get_currentFolder : WideString; stdcall; function Get_scannedFilesCount : Integer; stdcall; function Get_addedFilesCount : Integer; stdcall; function Get_updateProgress : Integer; stdcall; // startScan : function startScan:HRESULT;stdcall; // stopScan : function stopScan:HRESULT;stdcall; // count : property count:Integer read Get_count; // scanState : property scanState:WMPFolderScanState read Get_scanState; // currentFolder : property currentFolder:WideString read Get_currentFolder; // scannedFilesCount : property scannedFilesCount:Integer read Get_scannedFilesCount; // addedFilesCount : property addedFilesCount:Integer read Get_addedFilesCount; // updateProgress : property updateProgress:Integer read Get_updateProgress; end; // IWMPSyncDevice2 : IWMPSyncDevice2: Public interface for Windows Media Player SDK. IWMPSyncDevice2 = interface(IWMPSyncDevice) ['{88AFB4B2-140A-44D2-91E6-4543DA467CD1}'] // setItemInfo : function setItemInfo(bstrItemName:WideString;bstrVal:WideString):HRESULT;stdcall; end; // IWMPSyncDevice3 : IWMPSyncDevice3: Public interface for Windows Media Player SDK. IWMPSyncDevice3 = interface(IWMPSyncDevice2) ['{B22C85F9-263C-4372-A0DA-B518DB9B4098}'] // estimateSyncSize : function estimateSyncSize(pNonRulePlaylist:IWMPPlaylist;pRulesPlaylist:IWMPPlaylist):HRESULT;stdcall; // cancelEstimation : function cancelEstimation:HRESULT;stdcall; end; // IWMPPlaylistCtrl : IWMPPlaylistCtrl: Public interface for skin object model. IWMPPlaylistCtrl = interface(IDispatch) ['{5F9CFD92-8CAD-11D3-9A7E-00C04F8EFB70}'] function Get_Playlist : IWMPPlaylist; safecall; procedure Set_Playlist(const ppdispPlaylist:IWMPPlaylist); safecall; function Get_columns : WideString; safecall; procedure Set_columns(const pbstrColumns:WideString); safecall; function Get_columnCount : Integer; safecall; function Get_columnOrder : WideString; safecall; procedure Set_columnOrder(const pbstrColumnOrder:WideString); safecall; function Get_columnsVisible : WordBool; safecall; procedure Set_columnsVisible(const pVal:WordBool); safecall; function Get_dropDownVisible : WordBool; safecall; procedure Set_dropDownVisible(const pVal:WordBool); safecall; function Get_playlistItemsVisible : WordBool; safecall; procedure Set_playlistItemsVisible(const pVal:WordBool); safecall; function Get_checkboxesVisible : WordBool; safecall; procedure Set_checkboxesVisible(const pVal:WordBool); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pbstrColor:WideString); safecall; function Get_foregroundColor : WideString; safecall; procedure Set_foregroundColor(const pbstrColor:WideString); safecall; function Get_disabledItemColor : WideString; safecall; procedure Set_disabledItemColor(const pbstrColor:WideString); safecall; function Get_itemPlayingColor : WideString; safecall; procedure Set_itemPlayingColor(const pbstrColor:WideString); safecall; function Get_itemPlayingBackgroundColor : WideString; safecall; procedure Set_itemPlayingBackgroundColor(const pbstrBackgroundColor:WideString); safecall; function Get_backgroundImage : WideString; safecall; procedure Set_backgroundImage(const pbstrImage:WideString); safecall; function Get_allowItemEditing : WordBool; safecall; procedure Set_allowItemEditing(const pVal:WordBool); safecall; function Get_allowColumnSorting : WordBool; safecall; procedure Set_allowColumnSorting(const pVal:WordBool); safecall; function Get_dropDownList : WideString; safecall; procedure Set_dropDownList(const pbstrList:WideString); safecall; function Get_dropDownToolTip : WideString; safecall; procedure Set_dropDownToolTip(const pbstrToolTip:WideString); safecall; function Get_copying : WordBool; safecall; procedure Set_copying(const pVal:WordBool); safecall; // copy : method copy procedure copy;safecall; // abortCopy : method abortCopy procedure abortCopy;safecall; // deleteSelected : method deleteSelected procedure deleteSelected;safecall; // deleteSelectedFromLibrary : method deleteSelectedFromLibrary procedure deleteSelectedFromLibrary;safecall; // moveSelectedUp : method moveSelectedUp procedure moveSelectedUp;safecall; // moveSelectedDown : method moveSelectedDown procedure moveSelectedDown;safecall; // addSelectedToPlaylist : method addSelectedToPlaylist procedure addSelectedToPlaylist(pdispPlaylist:IWMPPlaylist);safecall; // getNextSelectedItem : method getNextSelectedItem function getNextSelectedItem(nStartIndex:Integer):Integer;safecall; // getNextCheckedItem : method getNextCheckedItem function getNextCheckedItem(nStartIndex:Integer):Integer;safecall; // setSelectedState : method setSelectedState procedure setSelectedState(nIndex:Integer;vbSelected:WordBool);safecall; // setCheckedState : method setCheckedState procedure setCheckedState(nIndex:Integer;vbChecked:WordBool);safecall; // sortColumn : method sortColumn procedure sortColumn(nIndex:Integer);safecall; // setColumnResizeMode : method setColumnResizeMode procedure setColumnResizeMode(nIndex:Integer;newMode:WideString);safecall; // setColumnWidth : method setColumnWidth procedure setColumnWidth(nIndex:Integer;nWidth:Integer);safecall; function Get_itemErrorColor : WideString; safecall; procedure Set_itemErrorColor(const pbstrColor:WideString); safecall; function Get_itemCount : Integer; safecall; function Get_itemMedia(nIndex:Integer) : IWMPMedia; safecall; function Get_itemPlaylist(nIndex:Integer) : IWMPPlaylist; safecall; // getNextSelectedItem2 : method getNextSelectedItem2 function getNextSelectedItem2(nStartIndex:Integer):Integer;safecall; // getNextCheckedItem2 : method getNextCheckedItem2 function getNextCheckedItem2(nStartIndex:Integer):Integer;safecall; // setSelectedState2 : method setSelectedState2 procedure setSelectedState2(nIndex:Integer;vbSelected:WordBool);safecall; // setCheckedState2 : method setCheckedState2 procedure setCheckedState2(nIndex:Integer;vbChecked:WordBool);safecall; function Get_leftStatus : WideString; safecall; procedure Set_leftStatus(const pbstrStatus:WideString); safecall; function Get_rightStatus : WideString; safecall; procedure Set_rightStatus(const pbstrStatus:WideString); safecall; function Get_editButtonVisible : WordBool; safecall; procedure Set_editButtonVisible(const pVal:WordBool); safecall; function Get_dropDownImage : WideString; safecall; procedure Set_dropDownImage(const pbstrImage:WideString); safecall; function Get_dropDownBackgroundImage : WideString; safecall; procedure Set_dropDownBackgroundImage(const pbstrImage:WideString); safecall; function Get_hueShift : Single; safecall; procedure Set_hueShift(const pVal:Single); safecall; function Get_saturation : Single; safecall; procedure Set_saturation(const pVal:Single); safecall; function Get_statusColor : WideString; safecall; procedure Set_statusColor(const pbstrColor:WideString); safecall; function Get_toolbarVisible : WordBool; safecall; procedure Set_toolbarVisible(const pVal:WordBool); safecall; function Get_itemSelectedColor : WideString; safecall; procedure Set_itemSelectedColor(const pbstrColor:WideString); safecall; function Get_itemSelectedFocusLostColor : WideString; safecall; procedure Set_itemSelectedFocusLostColor(const pbstrFocusLostColor:WideString); safecall; function Get_itemSelectedBackgroundColor : WideString; safecall; procedure Set_itemSelectedBackgroundColor(const pbstrColor:WideString); safecall; function Get_itemSelectedBackgroundFocusLostColor : WideString; safecall; procedure Set_itemSelectedBackgroundFocusLostColor(const pbstrFocusLostColor:WideString); safecall; function Get_backgroundSplitColor : WideString; safecall; procedure Set_backgroundSplitColor(const pbstrColor:WideString); safecall; function Get_statusTextColor : WideString; safecall; procedure Set_statusTextColor(const pbstrColor:WideString); safecall; // Playlist : property playlist property Playlist:IWMPPlaylist read Get_Playlist write Set_Playlist; // columns : property columns property columns:WideString read Get_columns write Set_columns; // columnCount : property columnCount property columnCount:Integer read Get_columnCount; // columnOrder : property columnOrder property columnOrder:WideString read Get_columnOrder write Set_columnOrder; // columnsVisible : property columnsVisible property columnsVisible:WordBool read Get_columnsVisible write Set_columnsVisible; // dropDownVisible : property dropDownVisible property dropDownVisible:WordBool read Get_dropDownVisible write Set_dropDownVisible; // playlistItemsVisible : property playlistItemsVisible property playlistItemsVisible:WordBool read Get_playlistItemsVisible write Set_playlistItemsVisible; // checkboxesVisible : property checkboxesVisible property checkboxesVisible:WordBool read Get_checkboxesVisible write Set_checkboxesVisible; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // foregroundColor : property foregroundColor property foregroundColor:WideString read Get_foregroundColor write Set_foregroundColor; // disabledItemColor : property disabledItemColor property disabledItemColor:WideString read Get_disabledItemColor write Set_disabledItemColor; // itemPlayingColor : property itemPlayingColor property itemPlayingColor:WideString read Get_itemPlayingColor write Set_itemPlayingColor; // itemPlayingBackgroundColor : property itemPlayingBackgroundColor property itemPlayingBackgroundColor:WideString read Get_itemPlayingBackgroundColor write Set_itemPlayingBackgroundColor; // backgroundImage : property backgroundImage property backgroundImage:WideString read Get_backgroundImage write Set_backgroundImage; // allowItemEditing : property allowItemEditing property allowItemEditing:WordBool read Get_allowItemEditing write Set_allowItemEditing; // allowColumnSorting : property allowColumnSorting property allowColumnSorting:WordBool read Get_allowColumnSorting write Set_allowColumnSorting; // dropDownList : property dropDownList property dropDownList:WideString read Get_dropDownList write Set_dropDownList; // dropDownToolTip : property dropDownToolTip property dropDownToolTip:WideString read Get_dropDownToolTip write Set_dropDownToolTip; // copying : property copying property copying:WordBool read Get_copying write Set_copying; // itemErrorColor : property itemErrorColor property itemErrorColor:WideString read Get_itemErrorColor write Set_itemErrorColor; // itemCount : property itemCount property itemCount:Integer read Get_itemCount; // itemMedia : property itemMedia property itemMedia[nIndex:Integer]:IWMPMedia read Get_itemMedia; // itemPlaylist : property itemPlaylist property itemPlaylist[nIndex:Integer]:IWMPPlaylist read Get_itemPlaylist; // leftStatus : property leftStatus property leftStatus:WideString read Get_leftStatus write Set_leftStatus; // rightStatus : property rightStatus property rightStatus:WideString read Get_rightStatus write Set_rightStatus; // editButtonVisible : property editButtonVisible property editButtonVisible:WordBool read Get_editButtonVisible write Set_editButtonVisible; // dropDownImage : property dropDownImage property dropDownImage:WideString read Get_dropDownImage write Set_dropDownImage; // dropDownBackgroundImage : property dropDownBackgroundImage property dropDownBackgroundImage:WideString read Get_dropDownBackgroundImage write Set_dropDownBackgroundImage; // hueShift : property hueShift property hueShift:Single read Get_hueShift write Set_hueShift; // saturation : property saturation property saturation:Single read Get_saturation write Set_saturation; // statusColor : property statusColor property statusColor:WideString read Get_statusColor write Set_statusColor; // toolbarVisible : property toolbarVisible property toolbarVisible:WordBool read Get_toolbarVisible write Set_toolbarVisible; // itemSelectedColor : property itemSelectedColor property itemSelectedColor:WideString read Get_itemSelectedColor write Set_itemSelectedColor; // itemSelectedFocusLostColor : property itemSelectedFocusLostColor property itemSelectedFocusLostColor:WideString read Get_itemSelectedFocusLostColor write Set_itemSelectedFocusLostColor; // itemSelectedBackgroundColor : property itemSelectedBackgroundColor property itemSelectedBackgroundColor:WideString read Get_itemSelectedBackgroundColor write Set_itemSelectedBackgroundColor; // itemSelectedBackgroundFocusLostColor : property itemSelectedBackgroundFocusLostColor property itemSelectedBackgroundFocusLostColor:WideString read Get_itemSelectedBackgroundFocusLostColor write Set_itemSelectedBackgroundFocusLostColor; // backgroundSplitColor : property backgroundSplitColor property backgroundSplitColor:WideString read Get_backgroundSplitColor write Set_backgroundSplitColor; // statusTextColor : property statusTextColor property statusTextColor:WideString read Get_statusTextColor write Set_statusTextColor; end; // IWMPPlaylistCtrl : IWMPPlaylistCtrl: Public interface for skin object model. IWMPPlaylistCtrlDisp = dispinterface ['{5F9CFD92-8CAD-11D3-9A7E-00C04F8EFB70}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // copy : method copy procedure copy;dispid 5623; // abortCopy : method abortCopy procedure abortCopy;dispid 5624; // deleteSelected : method deleteSelected procedure deleteSelected;dispid 5625; // deleteSelectedFromLibrary : method deleteSelectedFromLibrary procedure deleteSelectedFromLibrary;dispid 5626; // moveSelectedUp : method moveSelectedUp procedure moveSelectedUp;dispid 5628; // moveSelectedDown : method moveSelectedDown procedure moveSelectedDown;dispid 5629; // addSelectedToPlaylist : method addSelectedToPlaylist procedure addSelectedToPlaylist(pdispPlaylist:IWMPPlaylist);dispid 5630; // getNextSelectedItem : method getNextSelectedItem function getNextSelectedItem(nStartIndex:Integer):Integer;dispid 5631; // getNextCheckedItem : method getNextCheckedItem function getNextCheckedItem(nStartIndex:Integer):Integer;dispid 5632; // setSelectedState : method setSelectedState procedure setSelectedState(nIndex:Integer;vbSelected:WordBool);dispid 5633; // setCheckedState : method setCheckedState procedure setCheckedState(nIndex:Integer;vbChecked:WordBool);dispid 5634; // sortColumn : method sortColumn procedure sortColumn(nIndex:Integer);dispid 5635; // setColumnResizeMode : method setColumnResizeMode procedure setColumnResizeMode(nIndex:Integer;newMode:WideString);dispid 5636; // setColumnWidth : method setColumnWidth procedure setColumnWidth(nIndex:Integer;nWidth:Integer);dispid 5637; // getNextSelectedItem2 : method getNextSelectedItem2 function getNextSelectedItem2(nStartIndex:Integer):Integer;dispid 5646; // getNextCheckedItem2 : method getNextCheckedItem2 function getNextCheckedItem2(nStartIndex:Integer):Integer;dispid 5647; // setSelectedState2 : method setSelectedState2 procedure setSelectedState2(nIndex:Integer;vbSelected:WordBool);dispid 5648; // setCheckedState2 : method setCheckedState2 procedure setCheckedState2(nIndex:Integer;vbChecked:WordBool);dispid 5649; // Playlist : property playlist property Playlist:IWMPPlaylist dispid 5601; // columns : property columns property columns:WideString dispid 5602; // columnCount : property columnCount property columnCount:Integer readonly dispid 5603; // columnOrder : property columnOrder property columnOrder:WideString dispid 5604; // columnsVisible : property columnsVisible property columnsVisible:WordBool dispid 5605; // dropDownVisible : property dropDownVisible property dropDownVisible:WordBool dispid 5607; // playlistItemsVisible : property playlistItemsVisible property playlistItemsVisible:WordBool dispid 5608; // checkboxesVisible : property checkboxesVisible property checkboxesVisible:WordBool dispid 5609; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 5612; // foregroundColor : property foregroundColor property foregroundColor:WideString dispid 5613; // disabledItemColor : property disabledItemColor property disabledItemColor:WideString dispid 5614; // itemPlayingColor : property itemPlayingColor property itemPlayingColor:WideString dispid 5615; // itemPlayingBackgroundColor : property itemPlayingBackgroundColor property itemPlayingBackgroundColor:WideString dispid 5616; // backgroundImage : property backgroundImage property backgroundImage:WideString dispid 5617; // allowItemEditing : property allowItemEditing property allowItemEditing:WordBool dispid 5618; // allowColumnSorting : property allowColumnSorting property allowColumnSorting:WordBool dispid 5619; // dropDownList : property dropDownList property dropDownList:WideString dispid 5620; // dropDownToolTip : property dropDownToolTip property dropDownToolTip:WideString dispid 5621; // copying : property copying property copying:WordBool dispid 5622; // itemErrorColor : property itemErrorColor property itemErrorColor:WideString dispid 5642; // itemCount : property itemCount property itemCount:Integer readonly dispid 5643; // itemMedia : property itemMedia property itemMedia[nIndex:Integer]:IWMPMedia readonly dispid 5644; // itemPlaylist : property itemPlaylist property itemPlaylist[nIndex:Integer]:IWMPPlaylist readonly dispid 5645; // leftStatus : property leftStatus property leftStatus:WideString dispid 5650; // rightStatus : property rightStatus property rightStatus:WideString dispid 5651; // editButtonVisible : property editButtonVisible property editButtonVisible:WordBool dispid 5652; // dropDownImage : property dropDownImage property dropDownImage:WideString dispid 5653; // dropDownBackgroundImage : property dropDownBackgroundImage property dropDownBackgroundImage:WideString dispid 5654; // hueShift : property hueShift property hueShift:Single dispid 5655; // saturation : property saturation property saturation:Single dispid 5656; // statusColor : property statusColor property statusColor:WideString dispid 5658; // toolbarVisible : property toolbarVisible property toolbarVisible:WordBool dispid 5660; // itemSelectedColor : property itemSelectedColor property itemSelectedColor:WideString dispid 5662; // itemSelectedFocusLostColor : property itemSelectedFocusLostColor property itemSelectedFocusLostColor:WideString dispid 5663; // itemSelectedBackgroundColor : property itemSelectedBackgroundColor property itemSelectedBackgroundColor:WideString dispid 5664; // itemSelectedBackgroundFocusLostColor : property itemSelectedBackgroundFocusLostColor property itemSelectedBackgroundFocusLostColor:WideString dispid 5665; // backgroundSplitColor : property backgroundSplitColor property backgroundSplitColor:WideString dispid 5666; // statusTextColor : property statusTextColor property statusTextColor:WideString dispid 5667; end; // IAppDispatch : IAppDispatch: Not Public. Internal interface used by Windows Media Player. IAppDispatch = interface(IDispatch) ['{E41C88DD-2364-4FF7-A0F5-CA9859AF783F}'] function Get_titlebarVisible : WordBool; safecall; procedure Set_titlebarVisible(const pVal:WordBool); safecall; function Get_titlebarAutoHide : WordBool; safecall; procedure Set_titlebarAutoHide(const pVal:WordBool); safecall; function Get_currentTask : WideString; safecall; procedure Set_currentTask(const pVal:WideString); safecall; function Get_libraryBasketMode : Integer; safecall; procedure Set_libraryBasketMode(const pVal:Integer); safecall; function Get_libraryBasketWidth : Integer; safecall; function Get_breadcrumbItemCount : Integer; safecall; function Get_breadcrumbItemName(lIndex:Integer) : WideString; safecall; function Get_breadcrumbItemHasMenu(lIndex:Integer) : WordBool; safecall; // breadcrumbItemClick : procedure breadcrumbItemClick(lIndex:Integer);safecall; function Get_settingsVisible : WordBool; safecall; procedure Set_settingsVisible(const pVal:WordBool); safecall; function Get_playlistVisible : WordBool; safecall; procedure Set_playlistVisible(const pVal:WordBool); safecall; // gotoSkinMode : procedure gotoSkinMode;safecall; // gotoPlayerMode : procedure gotoPlayerMode;safecall; // gotoLibraryMode : procedure gotoLibraryMode(lButton:Integer);safecall; // navigatePrevious : procedure navigatePrevious;safecall; // navigateNext : procedure navigateNext;safecall; // goFullScreen : procedure goFullScreen;safecall; function Get_fullScreenEnabled : WordBool; safecall; function Get_serviceLoginVisible : WordBool; safecall; function Get_serviceLoginSignedIn : WordBool; safecall; // serviceLogin : procedure serviceLogin;safecall; // serviceLogout : procedure serviceLogout;safecall; function Get_serviceGetInfo(bstrItem:WideString) : OleVariant; safecall; function Get_navigatePreviousEnabled : WordBool; safecall; function Get_navigateNextEnabled : WordBool; safecall; // navigateToAddress : procedure navigateToAddress(address:WideString);safecall; function Get_glassEnabled : WordBool; safecall; function Get_inVistaPlus : WordBool; safecall; // adjustLeft : procedure adjustLeft(nDistance:Integer);safecall; function Get_taskbarVisible : WordBool; safecall; procedure Set_taskbarVisible(const pVal:WordBool); safecall; function Get_DPI : Integer; safecall; function Get_previousEnabled : WordBool; safecall; function Get_playLibraryItemEnabled : WordBool; safecall; // previous : procedure previous;safecall; function Get_titlebarCurrentlyVisible : WordBool; safecall; function Get_menubarCurrentlyVisible : WordBool; safecall; function Get_bgPluginRunning : WordBool; safecall; // configurePlugins : procedure configurePlugins(nType:Integer);safecall; // getTimeString : method getTimeString function getTimeString(dTime:Double):WideString;safecall; function Get_maximized : WordBool; safecall; function Get_top : Integer; safecall; procedure Set_top(const pVal:Integer); safecall; function Get_left : Integer; safecall; procedure Set_left(const pVal:Integer); safecall; function Get_width : Integer; safecall; procedure Set_width(const pVal:Integer); safecall; function Get_height : Integer; safecall; procedure Set_height(const pVal:Integer); safecall; // setWindowPos : procedure setWindowPos(lTop:Integer;lLeft:Integer;lWidth:Integer;lHeight:Integer);safecall; // logData : procedure logData(ID:WideString;data:WideString);safecall; function Get_powerPersonality : WideString; safecall; // navigateNamespace : procedure navigateNamespace(address:WideString);safecall; function Get_exclusiveService : WideString; safecall; procedure Set_windowText(const Param1:WideString); safecall; function Get_resourceIdForDpi(iResourceId:SYSINT) : SYSINT; safecall; // titlebarVisible : property titlebarVisible:WordBool read Get_titlebarVisible write Set_titlebarVisible; // titlebarAutoHide : property titlebarAutoHide:WordBool read Get_titlebarAutoHide write Set_titlebarAutoHide; // currentTask : property currentTask:WideString read Get_currentTask write Set_currentTask; // libraryBasketMode : property libraryBasketMode:Integer read Get_libraryBasketMode write Set_libraryBasketMode; // libraryBasketWidth : property libraryBasketWidth:Integer read Get_libraryBasketWidth; // breadcrumbItemCount : property breadcrumbItemCount:Integer read Get_breadcrumbItemCount; // breadcrumbItemName : property breadcrumbItemName[lIndex:Integer]:WideString read Get_breadcrumbItemName; // breadcrumbItemHasMenu : property breadcrumbItemHasMenu[lIndex:Integer]:WordBool read Get_breadcrumbItemHasMenu; // settingsVisible : property settingsVisible:WordBool read Get_settingsVisible write Set_settingsVisible; // playlistVisible : property playlistVisible:WordBool read Get_playlistVisible write Set_playlistVisible; // fullScreenEnabled : property fullScreenEnabled:WordBool read Get_fullScreenEnabled; // serviceLoginVisible : property serviceLoginVisible:WordBool read Get_serviceLoginVisible; // serviceLoginSignedIn : property serviceLoginSignedIn:WordBool read Get_serviceLoginSignedIn; // serviceGetInfo : property serviceGetInfo[bstrItem:WideString]:OleVariant read Get_serviceGetInfo; // navigatePreviousEnabled : property navigatePreviousEnabled:WordBool read Get_navigatePreviousEnabled; // navigateNextEnabled : property navigateNextEnabled:WordBool read Get_navigateNextEnabled; // glassEnabled : property glassEnabled:WordBool read Get_glassEnabled; // inVistaPlus : property inVistaPlus:WordBool read Get_inVistaPlus; // taskbarVisible : property taskbarVisible:WordBool read Get_taskbarVisible write Set_taskbarVisible; // DPI : property DPI:Integer read Get_DPI; // previousEnabled : property previousEnabled:WordBool read Get_previousEnabled; // playLibraryItemEnabled : property playLibraryItemEnabled:WordBool read Get_playLibraryItemEnabled; // titlebarCurrentlyVisible : property titlebarCurrentlyVisible:WordBool read Get_titlebarCurrentlyVisible; // menubarCurrentlyVisible : property menubarCurrentlyVisible:WordBool read Get_menubarCurrentlyVisible; // bgPluginRunning : property bgPluginRunning:WordBool read Get_bgPluginRunning; // maximized : property maximized:WordBool read Get_maximized; // top : property top:Integer read Get_top write Set_top; // left : property left:Integer read Get_left write Set_left; // width : property width:Integer read Get_width write Set_width; // height : property height:Integer read Get_height write Set_height; // powerPersonality : property powerPersonality:WideString read Get_powerPersonality; // exclusiveService : property exclusiveService:WideString read Get_exclusiveService; // windowText : property windowText:WideString write Set_windowText; // resourceIdForDpi : property resourceIdForDpi[iResourceId:SYSINT]:SYSINT read Get_resourceIdForDpi; end; // IAppDispatch : IAppDispatch: Not Public. Internal interface used by Windows Media Player. IAppDispatchDisp = dispinterface ['{E41C88DD-2364-4FF7-A0F5-CA9859AF783F}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // breadcrumbItemClick : procedure breadcrumbItemClick(lIndex:Integer);dispid 150; // gotoSkinMode : procedure gotoSkinMode;dispid 105; // gotoPlayerMode : procedure gotoPlayerMode;dispid 143; // gotoLibraryMode : procedure gotoLibraryMode(lButton:Integer);dispid 144; // navigatePrevious : procedure navigatePrevious;dispid 125; // navigateNext : procedure navigateNext;dispid 126; // goFullScreen : procedure goFullScreen;dispid 142; // serviceLogin : procedure serviceLogin;dispid 134; // serviceLogout : procedure serviceLogout;dispid 135; // navigateToAddress : procedure navigateToAddress(address:WideString);dispid 130; // adjustLeft : procedure adjustLeft(nDistance:Integer);dispid 106; // previous : procedure previous;dispid 115; // configurePlugins : procedure configurePlugins(nType:Integer);dispid 110; // getTimeString : method getTimeString function getTimeString(dTime:Double):WideString;dispid 111; // setWindowPos : procedure setWindowPos(lTop:Integer;lLeft:Integer;lWidth:Integer;lHeight:Integer);dispid 121; // logData : procedure logData(ID:WideString;data:WideString);dispid 122; // navigateNamespace : procedure navigateNamespace(address:WideString);dispid 128; // titlebarVisible : property titlebarVisible:WordBool dispid 100; // titlebarAutoHide : property titlebarAutoHide:WordBool dispid 101; // currentTask : property currentTask:WideString dispid 102; // libraryBasketMode : property libraryBasketMode:Integer dispid 145; // libraryBasketWidth : property libraryBasketWidth:Integer readonly dispid 146; // breadcrumbItemCount : property breadcrumbItemCount:Integer readonly dispid 147; // breadcrumbItemName : property breadcrumbItemName[lIndex:Integer]:WideString readonly dispid 148; // breadcrumbItemHasMenu : property breadcrumbItemHasMenu[lIndex:Integer]:WordBool readonly dispid 149; // settingsVisible : property settingsVisible:WordBool dispid 103; // playlistVisible : property playlistVisible:WordBool dispid 104; // fullScreenEnabled : property fullScreenEnabled:WordBool readonly dispid 141; // serviceLoginVisible : property serviceLoginVisible:WordBool readonly dispid 132; // serviceLoginSignedIn : property serviceLoginSignedIn:WordBool readonly dispid 133; // serviceGetInfo : property serviceGetInfo[bstrItem:WideString]:OleVariant readonly dispid 140; // navigatePreviousEnabled : property navigatePreviousEnabled:WordBool readonly dispid 123; // navigateNextEnabled : property navigateNextEnabled:WordBool readonly dispid 124; // glassEnabled : property glassEnabled:WordBool readonly dispid 131; // inVistaPlus : property inVistaPlus:WordBool readonly dispid 136; // taskbarVisible : property taskbarVisible:WordBool dispid 107; // DPI : property DPI:Integer readonly dispid 116; // previousEnabled : property previousEnabled:WordBool readonly dispid 114; // playLibraryItemEnabled : property playLibraryItemEnabled:WordBool readonly dispid 139; // titlebarCurrentlyVisible : property titlebarCurrentlyVisible:WordBool readonly dispid 108; // menubarCurrentlyVisible : property menubarCurrentlyVisible:WordBool readonly dispid 137; // bgPluginRunning : property bgPluginRunning:WordBool readonly dispid 109; // maximized : property maximized:WordBool readonly dispid 113; // top : property top:Integer dispid 117; // left : property left:Integer dispid 118; // width : property width:Integer dispid 119; // height : property height:Integer dispid 120; // powerPersonality : property powerPersonality:WideString readonly dispid 127; // exclusiveService : property exclusiveService:WideString readonly dispid 129; // windowText : property windowText:WideString writeonly dispid 138; // resourceIdForDpi : property resourceIdForDpi[iResourceId:SYSINT]:SYSINT readonly dispid 151; end; // IWMPSafeBrowser : IWMPSafeBrowser: Not Public. Internal interface used by Windows Media Player. IWMPSafeBrowser = interface(IDispatch) ['{EF870383-83AB-4EA9-BE48-56FA4251AF10}'] function Get_URL : WideString; safecall; procedure Set_URL(const pVal:WideString); safecall; function Get_status : Integer; safecall; function Get_pendingDownloads : Integer; safecall; // showSAMIText : method showSAMIText procedure showSAMIText(samiText:WideString);safecall; // showLyrics : method showLyrics procedure showLyrics(lyrics:WideString);safecall; // loadSpecialPage : loads one of our special pages by name procedure loadSpecialPage(pageName:WideString);safecall; // goBack : go back to the previous page procedure goBack;safecall; // goForward : go forward through the current MRU procedure goForward;safecall; // stop : stop loading page procedure stop;safecall; // refresh : refresh the page procedure refresh;safecall; function Get_baseURL : WideString; safecall; function Get_fullURL : WideString; safecall; function Get_secureLock : Integer; safecall; function Get_busy : WordBool; safecall; // showCert : show security certificate dialog procedure showCert;safecall; // URL : property URL:WideString read Get_URL write Set_URL; // status : property status:Integer read Get_status; // pendingDownloads : property pendingDownloads:Integer read Get_pendingDownloads; // baseURL : property baseURL:WideString read Get_baseURL; // fullURL : property fullURL:WideString read Get_fullURL; // secureLock : property secureLock:Integer read Get_secureLock; // busy : property busy:WordBool read Get_busy; end; // IWMPSafeBrowser : IWMPSafeBrowser: Not Public. Internal interface used by Windows Media Player. IWMPSafeBrowserDisp = dispinterface ['{EF870383-83AB-4EA9-BE48-56FA4251AF10}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // showSAMIText : method showSAMIText procedure showSAMIText(samiText:WideString);dispid 8403; // showLyrics : method showLyrics procedure showLyrics(lyrics:WideString);dispid 8404; // loadSpecialPage : loads one of our special pages by name procedure loadSpecialPage(pageName:WideString);dispid 8405; // goBack : go back to the previous page procedure goBack;dispid 8406; // goForward : go forward through the current MRU procedure goForward;dispid 8407; // stop : stop loading page procedure stop;dispid 8408; // refresh : refresh the page procedure refresh;dispid 8409; // showCert : show security certificate dialog procedure showCert;dispid 8413; // URL : property URL:WideString dispid 8400; // status : property status:Integer readonly dispid 8401; // pendingDownloads : property pendingDownloads:Integer readonly dispid 8402; // baseURL : property baseURL:WideString readonly dispid 8410; // fullURL : property fullURL:WideString readonly dispid 8414; // secureLock : property secureLock:Integer readonly dispid 8411; // busy : property busy:WordBool readonly dispid 8412; end; // IWMPObjectExtendedProps : IWMPObjectExtendedProps: Public interface for skin object model. IWMPObjectExtendedProps = interface(IDispatch) ['{21D077C1-4BAA-11D3-BD45-00C04F6EA5AE}'] function Get_ID : WideString; safecall; function Get_elementType : WideString; safecall; function Get_left : Integer; safecall; procedure Set_left(const pVal:Integer); safecall; function Get_top : Integer; safecall; procedure Set_top(const pVal:Integer); safecall; function Get_right : Integer; safecall; procedure Set_right(const pVal:Integer); safecall; function Get_bottom : Integer; safecall; procedure Set_bottom(const pVal:Integer); safecall; function Get_width : Integer; safecall; procedure Set_width(const pVal:Integer); safecall; function Get_height : Integer; safecall; procedure Set_height(const pVal:Integer); safecall; function Get_zIndex : Integer; safecall; procedure Set_zIndex(const pVal:Integer); safecall; function Get_clippingImage : WideString; safecall; procedure Set_clippingImage(const pVal:WideString); safecall; function Get_clippingColor : WideString; safecall; procedure Set_clippingColor(const pVal:WideString); safecall; function Get_visible : WordBool; safecall; procedure Set_visible(const pVal:WordBool); safecall; function Get_enabled : WordBool; safecall; procedure Set_enabled(const pVal:WordBool); safecall; function Get_tabStop : WordBool; safecall; procedure Set_tabStop(const pVal:WordBool); safecall; function Get_passThrough : WordBool; safecall; procedure Set_passThrough(const pVal:WordBool); safecall; function Get_horizontalAlignment : WideString; safecall; procedure Set_horizontalAlignment(const pVal:WideString); safecall; function Get_verticalAlignment : WideString; safecall; procedure Set_verticalAlignment(const pVal:WideString); safecall; // moveTo : method moveTo procedure moveTo(newX:Integer;newY:Integer;moveTime:Integer);safecall; // slideTo : method slideTo procedure slideTo(newX:Integer;newY:Integer;moveTime:Integer);safecall; // moveSizeTo : method moveSizeTo procedure moveSizeTo(newX:Integer;newY:Integer;newWidth:Integer;newHeight:Integer;moveTime:Integer;fSlide:WordBool);safecall; function Get_alphaBlend : Integer; safecall; procedure Set_alphaBlend(const pVal:Integer); safecall; // alphaBlendTo : method alphaBlendTo procedure alphaBlendTo(newVal:Integer;alphaTime:Integer);safecall; function Get_accName : WideString; safecall; procedure Set_accName(const pszName:WideString); safecall; function Get_accDescription : WideString; safecall; procedure Set_accDescription(const pszDesc:WideString); safecall; function Get_accKeyboardShortcut : WideString; safecall; procedure Set_accKeyboardShortcut(const pszShortcut:WideString); safecall; function Get_resizeImages : WordBool; safecall; procedure Set_resizeImages(const pVal:WordBool); safecall; function Get_nineGridMargins : WideString; safecall; procedure Set_nineGridMargins(const pszMargins:WideString); safecall; function Get_resizeOptimize : WideString; safecall; procedure Set_resizeOptimize(const ppszResizeOptimize:WideString); safecall; function Get_rotation : Single; safecall; procedure Set_rotation(const pfVal:Single); safecall; // ID : property id property ID:WideString read Get_ID; // elementType : property elementType property elementType:WideString read Get_elementType; // left : property left property left:Integer read Get_left write Set_left; // top : property top property top:Integer read Get_top write Set_top; // right : property right property right:Integer read Get_right write Set_right; // bottom : property bottom property bottom:Integer read Get_bottom write Set_bottom; // width : property width property width:Integer read Get_width write Set_width; // height : property height property height:Integer read Get_height write Set_height; // zIndex : property zIndex property zIndex:Integer read Get_zIndex write Set_zIndex; // clippingImage : property clippingImage property clippingImage:WideString read Get_clippingImage write Set_clippingImage; // clippingColor : property clippingColor property clippingColor:WideString read Get_clippingColor write Set_clippingColor; // visible : property visible property visible:WordBool read Get_visible write Set_visible; // enabled : property enabled property enabled:WordBool read Get_enabled write Set_enabled; // tabStop : property tabStop property tabStop:WordBool read Get_tabStop write Set_tabStop; // passThrough : property passThrough property passThrough:WordBool read Get_passThrough write Set_passThrough; // horizontalAlignment : property horizontalAlignment property horizontalAlignment:WideString read Get_horizontalAlignment write Set_horizontalAlignment; // verticalAlignment : property verticalAlignment property verticalAlignment:WideString read Get_verticalAlignment write Set_verticalAlignment; // alphaBlend : property alphaBlend property alphaBlend:Integer read Get_alphaBlend write Set_alphaBlend; // accName : property accName property accName:WideString read Get_accName write Set_accName; // accDescription : property accDescription property accDescription:WideString read Get_accDescription write Set_accDescription; // accKeyboardShortcut : property accKeyboardShortcut property accKeyboardShortcut:WideString read Get_accKeyboardShortcut write Set_accKeyboardShortcut; // resizeImages : property resizeImages property resizeImages:WordBool read Get_resizeImages write Set_resizeImages; // nineGridMargins : property nineGridMargins property nineGridMargins:WideString read Get_nineGridMargins write Set_nineGridMargins; // resizeOptimize : property resizeOptimize property resizeOptimize:WideString read Get_resizeOptimize write Set_resizeOptimize; // rotation : property rotation property rotation:Single read Get_rotation write Set_rotation; end; // IWMPObjectExtendedProps : IWMPObjectExtendedProps: Public interface for skin object model. IWMPObjectExtendedPropsDisp = dispinterface ['{21D077C1-4BAA-11D3-BD45-00C04F6EA5AE}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // moveTo : method moveTo procedure moveTo(newX:Integer;newY:Integer;moveTime:Integer);dispid 2015; // slideTo : method slideTo procedure slideTo(newX:Integer;newY:Integer;moveTime:Integer);dispid 2021; // moveSizeTo : method moveSizeTo procedure moveSizeTo(newX:Integer;newY:Integer;newWidth:Integer;newHeight:Integer;moveTime:Integer;fSlide:WordBool);dispid 2026; // alphaBlendTo : method alphaBlendTo procedure alphaBlendTo(newVal:Integer;alphaTime:Integer);dispid 2017; // ID : property id property ID:WideString readonly dispid 2000; // elementType : property elementType property elementType:WideString readonly dispid 2001; // left : property left property left:Integer dispid 2002; // top : property top property top:Integer dispid 2003; // right : property right property right:Integer dispid 2022; // bottom : property bottom property bottom:Integer dispid 2023; // width : property width property width:Integer dispid 2004; // height : property height property height:Integer dispid 2005; // zIndex : property zIndex property zIndex:Integer dispid 2006; // clippingImage : property clippingImage property clippingImage:WideString dispid 2007; // clippingColor : property clippingColor property clippingColor:WideString dispid 2008; // visible : property visible property visible:WordBool dispid 2009; // enabled : property enabled property enabled:WordBool dispid 2010; // tabStop : property tabStop property tabStop:WordBool dispid 2011; // passThrough : property passThrough property passThrough:WordBool dispid 2012; // horizontalAlignment : property horizontalAlignment property horizontalAlignment:WideString dispid 2013; // verticalAlignment : property verticalAlignment property verticalAlignment:WideString dispid 2014; // alphaBlend : property alphaBlend property alphaBlend:Integer dispid 2016; // accName : property accName property accName:WideString dispid 2018; // accDescription : property accDescription property accDescription:WideString dispid 2019; // accKeyboardShortcut : property accKeyboardShortcut property accKeyboardShortcut:WideString dispid 2020; // resizeImages : property resizeImages property resizeImages:WordBool dispid 2024; // nineGridMargins : property nineGridMargins property nineGridMargins:WideString dispid 2025; // resizeOptimize : property resizeOptimize property resizeOptimize:WideString dispid 2027; // rotation : property rotation property rotation:Single dispid 2028; end; // IWMPLayoutSubView : IWMPLayoutSubView: Public interface for skin object model. IWMPLayoutSubView = interface(IWMPObjectExtendedProps) ['{72F486B1-0D43-11D3-BD3F-00C04F6EA5AE}'] function Get_transparencyColor : WideString; safecall; procedure Set_transparencyColor(const pVal:WideString); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_backgroundImage : WideString; safecall; procedure Set_backgroundImage(const pVal:WideString); safecall; function Get_backgroundTiled : WordBool; safecall; procedure Set_backgroundTiled(const pVal:WordBool); safecall; function Get_backgroundImageHueShift : Single; safecall; procedure Set_backgroundImageHueShift(const pVal:Single); safecall; function Get_backgroundImageSaturation : Single; safecall; procedure Set_backgroundImageSaturation(const pVal:Single); safecall; function Get_resizeBackgroundImage : WordBool; safecall; procedure Set_resizeBackgroundImage(const pVal:WordBool); safecall; // transparencyColor : property transparencyColor property transparencyColor:WideString read Get_transparencyColor write Set_transparencyColor; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // backgroundImage : property backgroundImage property backgroundImage:WideString read Get_backgroundImage write Set_backgroundImage; // backgroundTiled : property backgroundTiled property backgroundTiled:WordBool read Get_backgroundTiled write Set_backgroundTiled; // backgroundImageHueShift : property hueShift property backgroundImageHueShift:Single read Get_backgroundImageHueShift write Set_backgroundImageHueShift; // backgroundImageSaturation : property saturation property backgroundImageSaturation:Single read Get_backgroundImageSaturation write Set_backgroundImageSaturation; // resizeBackgroundImage : property resizeBackgroundImage property resizeBackgroundImage:WordBool read Get_resizeBackgroundImage write Set_resizeBackgroundImage; end; // IWMPLayoutSubView : IWMPLayoutSubView: Public interface for skin object model. IWMPLayoutSubViewDisp = dispinterface ['{72F486B1-0D43-11D3-BD3F-00C04F6EA5AE}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // moveTo : method moveTo procedure moveTo(newX:Integer;newY:Integer;moveTime:Integer);dispid 2015; // slideTo : method slideTo procedure slideTo(newX:Integer;newY:Integer;moveTime:Integer);dispid 2021; // moveSizeTo : method moveSizeTo procedure moveSizeTo(newX:Integer;newY:Integer;newWidth:Integer;newHeight:Integer;moveTime:Integer;fSlide:WordBool);dispid 2026; // alphaBlendTo : method alphaBlendTo procedure alphaBlendTo(newVal:Integer;alphaTime:Integer);dispid 2017; // ID : property id property ID:WideString readonly dispid 2000; // elementType : property elementType property elementType:WideString readonly dispid 2001; // left : property left property left:Integer dispid 2002; // top : property top property top:Integer dispid 2003; // right : property right property right:Integer dispid 2022; // bottom : property bottom property bottom:Integer dispid 2023; // width : property width property width:Integer dispid 2004; // height : property height property height:Integer dispid 2005; // zIndex : property zIndex property zIndex:Integer dispid 2006; // clippingImage : property clippingImage property clippingImage:WideString dispid 2007; // clippingColor : property clippingColor property clippingColor:WideString dispid 2008; // visible : property visible property visible:WordBool dispid 2009; // enabled : property enabled property enabled:WordBool dispid 2010; // tabStop : property tabStop property tabStop:WordBool dispid 2011; // passThrough : property passThrough property passThrough:WordBool dispid 2012; // horizontalAlignment : property horizontalAlignment property horizontalAlignment:WideString dispid 2013; // verticalAlignment : property verticalAlignment property verticalAlignment:WideString dispid 2014; // alphaBlend : property alphaBlend property alphaBlend:Integer dispid 2016; // accName : property accName property accName:WideString dispid 2018; // accDescription : property accDescription property accDescription:WideString dispid 2019; // accKeyboardShortcut : property accKeyboardShortcut property accKeyboardShortcut:WideString dispid 2020; // resizeImages : property resizeImages property resizeImages:WordBool dispid 2024; // nineGridMargins : property nineGridMargins property nineGridMargins:WideString dispid 2025; // resizeOptimize : property resizeOptimize property resizeOptimize:WideString dispid 2027; // rotation : property rotation property rotation:Single dispid 2028; // transparencyColor : property transparencyColor property transparencyColor:WideString dispid 2300; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 2301; // backgroundImage : property backgroundImage property backgroundImage:WideString dispid 2302; // backgroundTiled : property backgroundTiled property backgroundTiled:WordBool dispid 2303; // backgroundImageHueShift : property hueShift property backgroundImageHueShift:Single dispid 2304; // backgroundImageSaturation : property saturation property backgroundImageSaturation:Single dispid 2305; // resizeBackgroundImage : property resizeBackgroundImage property resizeBackgroundImage:WordBool dispid 2306; end; // IWMPLayoutView : IWMPLayoutView: Public interface for skin object model. IWMPLayoutView = interface(IWMPLayoutSubView) ['{172E905D-80D9-4C2F-B7CE-2CCB771787A2}'] function Get_title : WideString; safecall; procedure Set_title(const pVal:WideString); safecall; function Get_category : WideString; safecall; procedure Set_category(const pVal:WideString); safecall; function Get_focusObjectID : WideString; safecall; procedure Set_focusObjectID(const pVal:WideString); safecall; function Get_titleBar : WordBool; safecall; function Get_resizable : WordBool; safecall; function Get_timerInterval : Integer; safecall; procedure Set_timerInterval(const pVal:Integer); safecall; function Get_minWidth : Integer; safecall; procedure Set_minWidth(const pVal:Integer); safecall; function Get_maxWidth : Integer; safecall; procedure Set_maxWidth(const pVal:Integer); safecall; function Get_minHeight : Integer; safecall; procedure Set_minHeight(const pVal:Integer); safecall; function Get_maxHeight : Integer; safecall; procedure Set_maxHeight(const pVal:Integer); safecall; // close : method close procedure close;safecall; // minimize : method minimize procedure minimize;safecall; // maximize : method maximize procedure maximize;safecall; // restore : method restore procedure restore;safecall; // size : method size procedure size(bstrDirection:WideString);safecall; // returnToMediaCenter : method returnToMediaCenter procedure returnToMediaCenter;safecall; // updateWindow : method updateWindow procedure updateWindow;safecall; function Get_maximized : WordBool; safecall; function Get_minimized : WordBool; safecall; // title : property title property title:WideString read Get_title write Set_title; // category : property category property category:WideString read Get_category write Set_category; // focusObjectID : property focusObjectID property focusObjectID:WideString read Get_focusObjectID write Set_focusObjectID; // titleBar : property titleBar property titleBar:WordBool read Get_titleBar; // resizable : property resizable property resizable:WordBool read Get_resizable; // timerInterval : property timerInterval property timerInterval:Integer read Get_timerInterval write Set_timerInterval; // minWidth : property minWidth property minWidth:Integer read Get_minWidth write Set_minWidth; // maxWidth : property maxWidth property maxWidth:Integer read Get_maxWidth write Set_maxWidth; // minHeight : property minHeight property minHeight:Integer read Get_minHeight write Set_minHeight; // maxHeight : property maxHeight property maxHeight:Integer read Get_maxHeight write Set_maxHeight; // maximized : property maximized:WordBool read Get_maximized; // minimized : property minimized:WordBool read Get_minimized; end; // IWMPLayoutView : IWMPLayoutView: Public interface for skin object model. IWMPLayoutViewDisp = dispinterface ['{172E905D-80D9-4C2F-B7CE-2CCB771787A2}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // moveTo : method moveTo procedure moveTo(newX:Integer;newY:Integer;moveTime:Integer);dispid 2015; // slideTo : method slideTo procedure slideTo(newX:Integer;newY:Integer;moveTime:Integer);dispid 2021; // moveSizeTo : method moveSizeTo procedure moveSizeTo(newX:Integer;newY:Integer;newWidth:Integer;newHeight:Integer;moveTime:Integer;fSlide:WordBool);dispid 2026; // alphaBlendTo : method alphaBlendTo procedure alphaBlendTo(newVal:Integer;alphaTime:Integer);dispid 2017; // close : method close procedure close;dispid 2318; // minimize : method minimize procedure minimize;dispid 2319; // maximize : method maximize procedure maximize;dispid 2320; // restore : method restore procedure restore;dispid 2321; // size : method size procedure size(bstrDirection:WideString);dispid 2322; // returnToMediaCenter : method returnToMediaCenter procedure returnToMediaCenter;dispid 2323; // updateWindow : method updateWindow procedure updateWindow;dispid 2324; // ID : property id property ID:WideString readonly dispid 2000; // elementType : property elementType property elementType:WideString readonly dispid 2001; // left : property left property left:Integer dispid 2002; // top : property top property top:Integer dispid 2003; // right : property right property right:Integer dispid 2022; // bottom : property bottom property bottom:Integer dispid 2023; // width : property width property width:Integer dispid 2004; // height : property height property height:Integer dispid 2005; // zIndex : property zIndex property zIndex:Integer dispid 2006; // clippingImage : property clippingImage property clippingImage:WideString dispid 2007; // clippingColor : property clippingColor property clippingColor:WideString dispid 2008; // visible : property visible property visible:WordBool dispid 2009; // enabled : property enabled property enabled:WordBool dispid 2010; // tabStop : property tabStop property tabStop:WordBool dispid 2011; // passThrough : property passThrough property passThrough:WordBool dispid 2012; // horizontalAlignment : property horizontalAlignment property horizontalAlignment:WideString dispid 2013; // verticalAlignment : property verticalAlignment property verticalAlignment:WideString dispid 2014; // alphaBlend : property alphaBlend property alphaBlend:Integer dispid 2016; // accName : property accName property accName:WideString dispid 2018; // accDescription : property accDescription property accDescription:WideString dispid 2019; // accKeyboardShortcut : property accKeyboardShortcut property accKeyboardShortcut:WideString dispid 2020; // resizeImages : property resizeImages property resizeImages:WordBool dispid 2024; // nineGridMargins : property nineGridMargins property nineGridMargins:WideString dispid 2025; // resizeOptimize : property resizeOptimize property resizeOptimize:WideString dispid 2027; // rotation : property rotation property rotation:Single dispid 2028; // transparencyColor : property transparencyColor property transparencyColor:WideString dispid 2300; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 2301; // backgroundImage : property backgroundImage property backgroundImage:WideString dispid 2302; // backgroundTiled : property backgroundTiled property backgroundTiled:WordBool dispid 2303; // backgroundImageHueShift : property hueShift property backgroundImageHueShift:Single dispid 2304; // backgroundImageSaturation : property saturation property backgroundImageSaturation:Single dispid 2305; // resizeBackgroundImage : property resizeBackgroundImage property resizeBackgroundImage:WordBool dispid 2306; // title : property title property title:WideString dispid 2307; // category : property category property category:WideString dispid 2308; // focusObjectID : property focusObjectID property focusObjectID:WideString dispid 2309; // titleBar : property titleBar property titleBar:WordBool readonly dispid 2311; // resizable : property resizable property resizable:WordBool readonly dispid 2312; // timerInterval : property timerInterval property timerInterval:Integer dispid 2313; // minWidth : property minWidth property minWidth:Integer dispid 2314; // maxWidth : property maxWidth property maxWidth:Integer dispid 2315; // minHeight : property minHeight property minHeight:Integer dispid 2316; // maxHeight : property maxHeight property maxHeight:Integer dispid 2317; // maximized : property maximized:WordBool readonly dispid 2326; // minimized : property minimized:WordBool readonly dispid 2327; end; // IWMPEventObject : IWMPEventObject: Not Public. Internal interface used by Windows Media Player. IWMPEventObject = interface(IDispatch) ['{5AF0BEC1-46AA-11D3-BD45-00C04F6EA5AE}'] function Get_srcElement : IDispatch; safecall; function Get_altKey : WordBool; safecall; function Get_ctrlKey : WordBool; safecall; function Get_shiftKey : WordBool; safecall; function Get_fromElement : IDispatch; safecall; function Get_toElement : IDispatch; safecall; procedure Set_keyCode(const p:Integer); safecall; function Get_keyCode : Integer; safecall; function Get_button : Integer; safecall; function Get_x : Integer; safecall; function Get_y : Integer; safecall; function Get_clientX : Integer; safecall; function Get_clientY : Integer; safecall; function Get_offsetX : Integer; safecall; function Get_offsetY : Integer; safecall; function Get_screenX : Integer; safecall; function Get_screenY : Integer; safecall; function Get_screenWidth : Integer; safecall; function Get_screenHeight : Integer; safecall; function Get_penOrTouch : WordBool; safecall; // srcElement : property srcElement:IDispatch read Get_srcElement; // altKey : property altKey:WordBool read Get_altKey; // ctrlKey : property ctrlKey:WordBool read Get_ctrlKey; // shiftKey : property shiftKey:WordBool read Get_shiftKey; // fromElement : property fromElement:IDispatch read Get_fromElement; // toElement : property toElement:IDispatch read Get_toElement; // keyCode : property keyCode:Integer read Get_keyCode write Set_keyCode; // button : property button:Integer read Get_button; // x : property x:Integer read Get_x; // y : property y:Integer read Get_y; // clientX : property clientX:Integer read Get_clientX; // clientY : property clientY:Integer read Get_clientY; // offsetX : property offsetX:Integer read Get_offsetX; // offsetY : property offsetY:Integer read Get_offsetY; // screenX : property screenX:Integer read Get_screenX; // screenY : property screenY:Integer read Get_screenY; // screenWidth : property screenWidth:Integer read Get_screenWidth; // screenHeight : property screenHeight:Integer read Get_screenHeight; // penOrTouch : property penOrTouch:WordBool read Get_penOrTouch; end; // IWMPEventObject : IWMPEventObject: Not Public. Internal interface used by Windows Media Player. IWMPEventObjectDisp = dispinterface ['{5AF0BEC1-46AA-11D3-BD45-00C04F6EA5AE}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // srcElement : property srcElement:IDispatch readonly dispid 2200; // altKey : property altKey:WordBool readonly dispid 2201; // ctrlKey : property ctrlKey:WordBool readonly dispid 2202; // shiftKey : property shiftKey:WordBool readonly dispid 2203; // fromElement : property fromElement:IDispatch readonly dispid 2204; // toElement : property toElement:IDispatch readonly dispid 2205; // keyCode : property keyCode:Integer dispid 2206; // button : property button:Integer readonly dispid 2207; // x : property x:Integer readonly dispid 2208; // y : property y:Integer readonly dispid 2209; // clientX : property clientX:Integer readonly dispid 2210; // clientY : property clientY:Integer readonly dispid 2211; // offsetX : property offsetX:Integer readonly dispid 2212; // offsetY : property offsetY:Integer readonly dispid 2213; // screenX : property screenX:Integer readonly dispid 2214; // screenY : property screenY:Integer readonly dispid 2215; // screenWidth : property screenWidth:Integer readonly dispid 2216; // screenHeight : property screenHeight:Integer readonly dispid 2217; // penOrTouch : property penOrTouch:WordBool readonly dispid 2218; end; // IWMPTheme : IWMPTheme: Public interface for skin object model. IWMPTheme = interface(IDispatch) ['{6FCAE13D-E492-4584-9C21-D2C052A2A33A}'] function Get_title : WideString; safecall; function Get_version : Single; safecall; function Get_authorVersion : WideString; safecall; function Get_author : WideString; safecall; function Get_copyright : WideString; safecall; function Get_currentViewID : WideString; safecall; procedure Set_currentViewID(const pVal:WideString); safecall; // showErrorDialog : method showErrorDialog procedure showErrorDialog;safecall; // logString : method logString procedure logString(stringVal:WideString);safecall; // openView : method openView procedure openView(viewID:WideString);safecall; // openViewRelative : method openView function openViewRelative(viewID:WideString;x:Integer;y:Integer):IDispatch;safecall; // closeView : method closeView procedure closeView(viewID:WideString);safecall; // openDialog : method openDialog function openDialog(dialogType:WideString;parameters:WideString):WideString;safecall; // loadString : method loadString function loadString(bstrString:WideString):WideString;safecall; // loadPreference : method loadPreference function loadPreference(bstrName:WideString):WideString;safecall; // savePreference : method savePreference procedure savePreference(bstrName:WideString;bstrValue:WideString);safecall; // playSound : method playSound procedure playSound(bstrFilename:WideString);safecall; // openViewRelativeInternal : Microsoft internal use only function openViewRelativeInternal(viewID:WideString;nIndex:Integer;x:Integer;y:Integer;nWidth:Integer;nHeight:Integer;bstrHorizontalAlignment:WideString;bstrVerticalAlignment:WideString):IDispatch;safecall; // setViewPosition : Microsoft internal use only procedure setViewPosition(viewID:WideString;nIndex:Integer;x:Integer;y:Integer;nWidth:Integer;nHeight:Integer;bstrHorizontalAlignment:WideString;bstrVerticalAlignment:WideString);safecall; // title : property title property title:WideString read Get_title; // version : property version property version:Single read Get_version; // authorVersion : property authorVersion property authorVersion:WideString read Get_authorVersion; // author : property author property author:WideString read Get_author; // copyright : property copyright property copyright:WideString read Get_copyright; // currentViewID : property title property currentViewID:WideString read Get_currentViewID write Set_currentViewID; end; // IWMPTheme : IWMPTheme: Public interface for skin object model. IWMPThemeDisp = dispinterface ['{6FCAE13D-E492-4584-9C21-D2C052A2A33A}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // showErrorDialog : method showErrorDialog procedure showErrorDialog;dispid 2506; // logString : method logString procedure logString(stringVal:WideString);dispid 2507; // openView : method openView procedure openView(viewID:WideString);dispid 2508; // openViewRelative : method openView function openViewRelative(viewID:WideString;x:Integer;y:Integer):IDispatch;dispid 2515; // closeView : method closeView procedure closeView(viewID:WideString);dispid 2509; // openDialog : method openDialog function openDialog(dialogType:WideString;parameters:WideString):WideString;dispid 2510; // loadString : method loadString function loadString(bstrString:WideString):WideString;dispid 2511; // loadPreference : method loadPreference function loadPreference(bstrName:WideString):WideString;dispid 2512; // savePreference : method savePreference procedure savePreference(bstrName:WideString;bstrValue:WideString);dispid 2513; // playSound : method playSound procedure playSound(bstrFilename:WideString);dispid 2514; // openViewRelativeInternal : Microsoft internal use only function openViewRelativeInternal(viewID:WideString;nIndex:Integer;x:Integer;y:Integer;nWidth:Integer;nHeight:Integer;bstrHorizontalAlignment:WideString;bstrVerticalAlignment:WideString):IDispatch;dispid 2516; // setViewPosition : Microsoft internal use only procedure setViewPosition(viewID:WideString;nIndex:Integer;x:Integer;y:Integer;nWidth:Integer;nHeight:Integer;bstrHorizontalAlignment:WideString;bstrVerticalAlignment:WideString);dispid 2518; // title : property title property title:WideString readonly dispid 2500; // version : property version property version:Single readonly dispid 2501; // authorVersion : property authorVersion property authorVersion:WideString readonly dispid 2502; // author : property author property author:WideString readonly dispid 2503; // copyright : property copyright property copyright:WideString readonly dispid 2504; // currentViewID : property title property currentViewID:WideString dispid 2505; end; // IWMPLayoutSettingsDispatch : IWMPLayoutSettingsDispatch: Not Public. Internal interface used by Windows Media Player. IWMPLayoutSettingsDispatch = interface(IDispatch) ['{B2C2D18E-97AF-4B6A-A56B-2FFFF470FB81}'] function Get_effectType : WideString; safecall; procedure Set_effectType(const pVal:WideString); safecall; function Get_effectPreset : Integer; safecall; procedure Set_effectPreset(const pVal:Integer); safecall; function Get_settingsView : WideString; safecall; procedure Set_settingsView(const pVal:WideString); safecall; function Get_videoZoom : Integer; safecall; procedure Set_videoZoom(const pVal:Integer); safecall; function Get_videoShrinkToFit : WordBool; safecall; procedure Set_videoShrinkToFit(const pVal:WordBool); safecall; function Get_videoStretchToFit : WordBool; safecall; procedure Set_videoStretchToFit(const pVal:WordBool); safecall; function Get_userVideoStretchToFit : WordBool; safecall; procedure Set_userVideoStretchToFit(const pVal:WordBool); safecall; function Get_showCaptions : WordBool; safecall; procedure Set_showCaptions(const pVal:WordBool); safecall; function Get_showTitles : WordBool; safecall; procedure Set_showTitles(const pVal:WordBool); safecall; function Get_showEffects : WordBool; safecall; procedure Set_showEffects(const pVal:WordBool); safecall; function Get_showFullScreenPlaylist : WordBool; safecall; procedure Set_showFullScreenPlaylist(const pVal:WordBool); safecall; function Get_contrastMode : WideString; safecall; // getNamedString : method getNamedString function getNamedString(bstrName:WideString):WideString;safecall; // getDurationStringFromSeconds : method getDurationStringFromSeconds function getDurationStringFromSeconds(lDurationVal:Integer):WideString;safecall; function Get_displayView : WideString; safecall; procedure Set_displayView(const pVal:WideString); safecall; function Get_metadataView : WideString; safecall; procedure Set_metadataView(const pVal:WideString); safecall; function Get_showSettings : WordBool; safecall; procedure Set_showSettings(const pVal:WordBool); safecall; function Get_showResizeBars : WordBool; safecall; procedure Set_showResizeBars(const pVal:WordBool); safecall; function Get_showPlaylist : WordBool; safecall; procedure Set_showPlaylist(const pVal:WordBool); safecall; function Get_showMetadata : WordBool; safecall; procedure Set_showMetadata(const pVal:WordBool); safecall; function Get_settingsWidth : Integer; safecall; procedure Set_settingsWidth(const pVal:Integer); safecall; function Get_settingsHeight : Integer; safecall; procedure Set_settingsHeight(const pVal:Integer); safecall; function Get_playlistWidth : Integer; safecall; procedure Set_playlistWidth(const pVal:Integer); safecall; function Get_playlistHeight : Integer; safecall; procedure Set_playlistHeight(const pVal:Integer); safecall; function Get_metadataWidth : Integer; safecall; procedure Set_metadataWidth(const pVal:Integer); safecall; function Get_metadataHeight : Integer; safecall; procedure Set_metadataHeight(const pVal:Integer); safecall; function Get_fullScreenAvailable : WordBool; safecall; procedure Set_fullScreenAvailable(const pVal:WordBool); safecall; function Get_fullScreenRequest : WordBool; safecall; procedure Set_fullScreenRequest(const pVal:WordBool); safecall; function Get_quickHide : WordBool; safecall; procedure Set_quickHide(const pVal:WordBool); safecall; function Get_displayPreset : Integer; safecall; procedure Set_displayPreset(const pVal:Integer); safecall; function Get_settingsPreset : Integer; safecall; procedure Set_settingsPreset(const pVal:Integer); safecall; function Get_metadataPreset : Integer; safecall; procedure Set_metadataPreset(const pVal:Integer); safecall; function Get_userDisplayView : WideString; safecall; function Get_userWMPDisplayView : WideString; safecall; function Get_userDisplayPreset : Integer; safecall; function Get_userWMPDisplayPreset : Integer; safecall; function Get_dynamicRangeControl : Integer; safecall; procedure Set_dynamicRangeControl(const pVal:Integer); safecall; function Get_slowRate : Single; safecall; procedure Set_slowRate(const pVal:Single); safecall; function Get_fastRate : Single; safecall; procedure Set_fastRate(const pVal:Single); safecall; function Get_buttonHueShift : Single; safecall; procedure Set_buttonHueShift(const pVal:Single); safecall; function Get_buttonSaturation : Single; safecall; procedure Set_buttonSaturation(const pVal:Single); safecall; function Get_backHueShift : Single; safecall; procedure Set_backHueShift(const pVal:Single); safecall; function Get_backSaturation : Single; safecall; procedure Set_backSaturation(const pVal:Single); safecall; function Get_vizRequest : Integer; safecall; procedure Set_vizRequest(const pVal:Integer); safecall; function Get_appColorLight : WideString; safecall; function Get_appColorMedium : WideString; safecall; function Get_appColorDark : WideString; safecall; function Get_toolbarButtonHighlight : WideString; safecall; function Get_toolbarButtonShadow : WideString; safecall; function Get_toolbarButtonFace : WideString; safecall; function Get_itemPlayingColor : WideString; safecall; function Get_itemPlayingBackgroundColor : WideString; safecall; function Get_itemErrorColor : WideString; safecall; function Get_appColorLimited : WordBool; safecall; function Get_appColorBlackBackground : WordBool; safecall; procedure Set_appColorBlackBackground(const pVal:WordBool); safecall; function Get_appColorVideoBorder : WideString; safecall; procedure Set_appColorVideoBorder(const pVal:WideString); safecall; function Get_appColorAux1 : WideString; safecall; function Get_appColorAux2 : WideString; safecall; function Get_appColorAux3 : WideString; safecall; function Get_appColorAux4 : WideString; safecall; function Get_appColorAux5 : WideString; safecall; function Get_appColorAux6 : WideString; safecall; function Get_appColorAux7 : WideString; safecall; function Get_appColorAux8 : WideString; safecall; function Get_appColorAux9 : WideString; safecall; function Get_appColorAux10 : WideString; safecall; function Get_appColorAux11 : WideString; safecall; function Get_appColorAux12 : WideString; safecall; function Get_appColorAux13 : WideString; safecall; function Get_appColorAux14 : WideString; safecall; function Get_appColorAux15 : WideString; safecall; function Get_status : WideString; safecall; procedure Set_status(const pVal:WideString); safecall; function Get_userWMPSettingsView : WideString; safecall; function Get_userWMPSettingsPreset : Integer; safecall; function Get_userWMPShowSettings : WordBool; safecall; function Get_userWMPMetadataView : WideString; safecall; function Get_userWMPMetadataPreset : Integer; safecall; function Get_userWMPShowMetadata : WordBool; safecall; function Get_captionsHeight : Integer; safecall; procedure Set_captionsHeight(const pVal:Integer); safecall; function Get_snapToVideo : WordBool; safecall; procedure Set_snapToVideo(const pVal:WordBool); safecall; function Get_pinFullScreenControls : WordBool; safecall; procedure Set_pinFullScreenControls(const pVal:WordBool); safecall; function Get_isMultiMon : WordBool; safecall; function Get_exclusiveHueShift : Single; safecall; procedure Set_exclusiveHueShift(const pVal:Single); safecall; function Get_exclusiveSaturation : Single; safecall; procedure Set_exclusiveSaturation(const pVal:Single); safecall; function Get_themeBkgColorIsActive : WordBool; safecall; procedure Set_themeBkgColorIsActive(const pVal:WordBool); safecall; function Get_themeBkgColorActive : WideString; safecall; function Get_themeBkgColorInactive : WideString; safecall; // effectType : property effectType property effectType:WideString read Get_effectType write Set_effectType; // effectPreset : property effectPreset property effectPreset:Integer read Get_effectPreset write Set_effectPreset; // settingsView : property settingsView property settingsView:WideString read Get_settingsView write Set_settingsView; // videoZoom : property videoZoom property videoZoom:Integer read Get_videoZoom write Set_videoZoom; // videoShrinkToFit : property videoShrinkToFit property videoShrinkToFit:WordBool read Get_videoShrinkToFit write Set_videoShrinkToFit; // videoStretchToFit : property videoStretchToFit property videoStretchToFit:WordBool read Get_videoStretchToFit write Set_videoStretchToFit; // userVideoStretchToFit : property userVideoStretchToFit property userVideoStretchToFit:WordBool read Get_userVideoStretchToFit write Set_userVideoStretchToFit; // showCaptions : property showCaptions property showCaptions:WordBool read Get_showCaptions write Set_showCaptions; // showTitles : property showTitles property showTitles:WordBool read Get_showTitles write Set_showTitles; // showEffects : property showEffects property showEffects:WordBool read Get_showEffects write Set_showEffects; // showFullScreenPlaylist : property showFullScreenPlaylist property showFullScreenPlaylist:WordBool read Get_showFullScreenPlaylist write Set_showFullScreenPlaylist; // contrastMode : property contrastMode property contrastMode:WideString read Get_contrastMode; // displayView : property displayView property displayView:WideString read Get_displayView write Set_displayView; // metadataView : property metadataView property metadataView:WideString read Get_metadataView write Set_metadataView; // showSettings : property showSettings property showSettings:WordBool read Get_showSettings write Set_showSettings; // showResizeBars : property showResizeBars property showResizeBars:WordBool read Get_showResizeBars write Set_showResizeBars; // showPlaylist : property showPlaylist property showPlaylist:WordBool read Get_showPlaylist write Set_showPlaylist; // showMetadata : property showMetadata property showMetadata:WordBool read Get_showMetadata write Set_showMetadata; // settingsWidth : property settingsWidth property settingsWidth:Integer read Get_settingsWidth write Set_settingsWidth; // settingsHeight : property settingsHeight property settingsHeight:Integer read Get_settingsHeight write Set_settingsHeight; // playlistWidth : property playlistWidth property playlistWidth:Integer read Get_playlistWidth write Set_playlistWidth; // playlistHeight : property playlistHeight property playlistHeight:Integer read Get_playlistHeight write Set_playlistHeight; // metadataWidth : property metadataWidth property metadataWidth:Integer read Get_metadataWidth write Set_metadataWidth; // metadataHeight : property metadataHeight property metadataHeight:Integer read Get_metadataHeight write Set_metadataHeight; // fullScreenAvailable : property fullScreenAvailable property fullScreenAvailable:WordBool read Get_fullScreenAvailable write Set_fullScreenAvailable; // fullScreenRequest : property fullScreenRequest property fullScreenRequest:WordBool read Get_fullScreenRequest write Set_fullScreenRequest; // quickHide : property quickHide property quickHide:WordBool read Get_quickHide write Set_quickHide; // displayPreset : property displayPreset property displayPreset:Integer read Get_displayPreset write Set_displayPreset; // settingsPreset : property settingsPreset property settingsPreset:Integer read Get_settingsPreset write Set_settingsPreset; // metadataPreset : property metadataPreset property metadataPreset:Integer read Get_metadataPreset write Set_metadataPreset; // userDisplayView : property userDisplayView property userDisplayView:WideString read Get_userDisplayView; // userWMPDisplayView : property userWMPDisplayView property userWMPDisplayView:WideString read Get_userWMPDisplayView; // userDisplayPreset : property userDisplayPreset property userDisplayPreset:Integer read Get_userDisplayPreset; // userWMPDisplayPreset : property userWMPDisplayPreset property userWMPDisplayPreset:Integer read Get_userWMPDisplayPreset; // dynamicRangeControl : property dynamicRangeControl property dynamicRangeControl:Integer read Get_dynamicRangeControl write Set_dynamicRangeControl; // slowRate : property slowRate property slowRate:Single read Get_slowRate write Set_slowRate; // fastRate : property fastRate property fastRate:Single read Get_fastRate write Set_fastRate; // buttonHueShift : property buttonHueShift property buttonHueShift:Single read Get_buttonHueShift write Set_buttonHueShift; // buttonSaturation : property buttonSaturation property buttonSaturation:Single read Get_buttonSaturation write Set_buttonSaturation; // backHueShift : property backHueShift property backHueShift:Single read Get_backHueShift write Set_backHueShift; // backSaturation : property backSaturation property backSaturation:Single read Get_backSaturation write Set_backSaturation; // vizRequest : property vizRequest property vizRequest:Integer read Get_vizRequest write Set_vizRequest; // appColorLight : property appColorLight property appColorLight:WideString read Get_appColorLight; // appColorMedium : property appColorMedium property appColorMedium:WideString read Get_appColorMedium; // appColorDark : property appColorDark property appColorDark:WideString read Get_appColorDark; // toolbarButtonHighlight : property toolbarButtonHighlight property toolbarButtonHighlight:WideString read Get_toolbarButtonHighlight; // toolbarButtonShadow : property toolbarButtonShadow property toolbarButtonShadow:WideString read Get_toolbarButtonShadow; // toolbarButtonFace : property toolbarButtonFace property toolbarButtonFace:WideString read Get_toolbarButtonFace; // itemPlayingColor : property itemPlayingColor property itemPlayingColor:WideString read Get_itemPlayingColor; // itemPlayingBackgroundColor : property itemPlayingBackgroundColor property itemPlayingBackgroundColor:WideString read Get_itemPlayingBackgroundColor; // itemErrorColor : property itemErrorColor property itemErrorColor:WideString read Get_itemErrorColor; // appColorLimited : property AppColorLimited property appColorLimited:WordBool read Get_appColorLimited; // appColorBlackBackground : property AppColorBlackBackground property appColorBlackBackground:WordBool read Get_appColorBlackBackground write Set_appColorBlackBackground; // appColorVideoBorder : property appColorVideoBorder property appColorVideoBorder:WideString read Get_appColorVideoBorder write Set_appColorVideoBorder; // appColorAux1 : auxiliary color property appColorAux1:WideString read Get_appColorAux1; // appColorAux2 : auxiliary color property appColorAux2:WideString read Get_appColorAux2; // appColorAux3 : auxiliary color property appColorAux3:WideString read Get_appColorAux3; // appColorAux4 : auxiliary color property appColorAux4:WideString read Get_appColorAux4; // appColorAux5 : auxiliary color property appColorAux5:WideString read Get_appColorAux5; // appColorAux6 : auxiliary color property appColorAux6:WideString read Get_appColorAux6; // appColorAux7 : auxiliary color property appColorAux7:WideString read Get_appColorAux7; // appColorAux8 : auxiliary color property appColorAux8:WideString read Get_appColorAux8; // appColorAux9 : auxiliary color property appColorAux9:WideString read Get_appColorAux9; // appColorAux10 : auxiliary color property appColorAux10:WideString read Get_appColorAux10; // appColorAux11 : auxiliary color property appColorAux11:WideString read Get_appColorAux11; // appColorAux12 : auxiliary color property appColorAux12:WideString read Get_appColorAux12; // appColorAux13 : auxiliary color property appColorAux13:WideString read Get_appColorAux13; // appColorAux14 : auxiliary color property appColorAux14:WideString read Get_appColorAux14; // appColorAux15 : auxiliary color property appColorAux15:WideString read Get_appColorAux15; // status : status string for remote player (taskbar player) property status:WideString read Get_status write Set_status; // userWMPSettingsView : property userWMPSettingsView property userWMPSettingsView:WideString read Get_userWMPSettingsView; // userWMPSettingsPreset : property userWMPSettingsPreset property userWMPSettingsPreset:Integer read Get_userWMPSettingsPreset; // userWMPShowSettings : property userWMPShowSettings property userWMPShowSettings:WordBool read Get_userWMPShowSettings; // userWMPMetadataView : property userWMPMetadataView property userWMPMetadataView:WideString read Get_userWMPMetadataView; // userWMPMetadataPreset : property userWMPMetadataPreset property userWMPMetadataPreset:Integer read Get_userWMPMetadataPreset; // userWMPShowMetadata : property userWMPShowMetadata property userWMPShowMetadata:WordBool read Get_userWMPShowMetadata; // captionsHeight : property captionsHeight property captionsHeight:Integer read Get_captionsHeight write Set_captionsHeight; // snapToVideo : property snapToVideo property snapToVideo:WordBool read Get_snapToVideo write Set_snapToVideo; // pinFullScreenControls : property pinFullScreenControls property pinFullScreenControls:WordBool read Get_pinFullScreenControls write Set_pinFullScreenControls; // isMultiMon : property isMultiMon property isMultiMon:WordBool read Get_isMultiMon; // exclusiveHueShift : property exclusiveHueShift property exclusiveHueShift:Single read Get_exclusiveHueShift write Set_exclusiveHueShift; // exclusiveSaturation : property exclusiveSaturation property exclusiveSaturation:Single read Get_exclusiveSaturation write Set_exclusiveSaturation; // themeBkgColorIsActive : themeBkgColorIsActive property themeBkgColorIsActive:WordBool read Get_themeBkgColorIsActive write Set_themeBkgColorIsActive; // themeBkgColorActive : themeBkgColorActive property themeBkgColorActive:WideString read Get_themeBkgColorActive; // themeBkgColorInactive : themeBkgColorInactive property themeBkgColorInactive:WideString read Get_themeBkgColorInactive; end; // IWMPLayoutSettingsDispatch : IWMPLayoutSettingsDispatch: Not Public. Internal interface used by Windows Media Player. IWMPLayoutSettingsDispatchDisp = dispinterface ['{B2C2D18E-97AF-4B6A-A56B-2FFFF470FB81}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getNamedString : method getNamedString function getNamedString(bstrName:WideString):WideString;dispid 2810; // getDurationStringFromSeconds : method getDurationStringFromSeconds function getDurationStringFromSeconds(lDurationVal:Integer):WideString;dispid 2815; // effectType : property effectType property effectType:WideString dispid 2800; // effectPreset : property effectPreset property effectPreset:Integer dispid 2801; // settingsView : property settingsView property settingsView:WideString dispid 2802; // videoZoom : property videoZoom property videoZoom:Integer dispid 2803; // videoShrinkToFit : property videoShrinkToFit property videoShrinkToFit:WordBool dispid 2804; // videoStretchToFit : property videoStretchToFit property videoStretchToFit:WordBool dispid 2805; // userVideoStretchToFit : property userVideoStretchToFit property userVideoStretchToFit:WordBool dispid 2868; // showCaptions : property showCaptions property showCaptions:WordBool dispid 2807; // showTitles : property showTitles property showTitles:WordBool dispid 2808; // showEffects : property showEffects property showEffects:WordBool dispid 2809; // showFullScreenPlaylist : property showFullScreenPlaylist property showFullScreenPlaylist:WordBool dispid 2811; // contrastMode : property contrastMode property contrastMode:WideString readonly dispid 2813; // displayView : property displayView property displayView:WideString dispid 2816; // metadataView : property metadataView property metadataView:WideString dispid 2817; // showSettings : property showSettings property showSettings:WordBool dispid 2818; // showResizeBars : property showResizeBars property showResizeBars:WordBool dispid 2819; // showPlaylist : property showPlaylist property showPlaylist:WordBool dispid 2820; // showMetadata : property showMetadata property showMetadata:WordBool dispid 2821; // settingsWidth : property settingsWidth property settingsWidth:Integer dispid 2822; // settingsHeight : property settingsHeight property settingsHeight:Integer dispid 2823; // playlistWidth : property playlistWidth property playlistWidth:Integer dispid 2824; // playlistHeight : property playlistHeight property playlistHeight:Integer dispid 2825; // metadataWidth : property metadataWidth property metadataWidth:Integer dispid 2826; // metadataHeight : property metadataHeight property metadataHeight:Integer dispid 2827; // fullScreenAvailable : property fullScreenAvailable property fullScreenAvailable:WordBool dispid 2828; // fullScreenRequest : property fullScreenRequest property fullScreenRequest:WordBool dispid 2829; // quickHide : property quickHide property quickHide:WordBool dispid 2830; // displayPreset : property displayPreset property displayPreset:Integer dispid 2831; // settingsPreset : property settingsPreset property settingsPreset:Integer dispid 2832; // metadataPreset : property metadataPreset property metadataPreset:Integer dispid 2833; // userDisplayView : property userDisplayView property userDisplayView:WideString readonly dispid 2834; // userWMPDisplayView : property userWMPDisplayView property userWMPDisplayView:WideString readonly dispid 2835; // userDisplayPreset : property userDisplayPreset property userDisplayPreset:Integer readonly dispid 2836; // userWMPDisplayPreset : property userWMPDisplayPreset property userWMPDisplayPreset:Integer readonly dispid 2837; // dynamicRangeControl : property dynamicRangeControl property dynamicRangeControl:Integer dispid 2838; // slowRate : property slowRate property slowRate:Single dispid 2839; // fastRate : property fastRate property fastRate:Single dispid 2840; // buttonHueShift : property buttonHueShift property buttonHueShift:Single dispid 2841; // buttonSaturation : property buttonSaturation property buttonSaturation:Single dispid 2842; // backHueShift : property backHueShift property backHueShift:Single dispid 2843; // backSaturation : property backSaturation property backSaturation:Single dispid 2844; // vizRequest : property vizRequest property vizRequest:Integer dispid 2845; // appColorLight : property appColorLight property appColorLight:WideString readonly dispid 2847; // appColorMedium : property appColorMedium property appColorMedium:WideString readonly dispid 2848; // appColorDark : property appColorDark property appColorDark:WideString readonly dispid 2849; // toolbarButtonHighlight : property toolbarButtonHighlight property toolbarButtonHighlight:WideString readonly dispid 2856; // toolbarButtonShadow : property toolbarButtonShadow property toolbarButtonShadow:WideString readonly dispid 2857; // toolbarButtonFace : property toolbarButtonFace property toolbarButtonFace:WideString readonly dispid 2858; // itemPlayingColor : property itemPlayingColor property itemPlayingColor:WideString readonly dispid 2850; // itemPlayingBackgroundColor : property itemPlayingBackgroundColor property itemPlayingBackgroundColor:WideString readonly dispid 2851; // itemErrorColor : property itemErrorColor property itemErrorColor:WideString readonly dispid 2852; // appColorLimited : property AppColorLimited property appColorLimited:WordBool readonly dispid 2853; // appColorBlackBackground : property AppColorBlackBackground property appColorBlackBackground:WordBool dispid 2854; // appColorVideoBorder : property appColorVideoBorder property appColorVideoBorder:WideString dispid 2855; // appColorAux1 : auxiliary color property appColorAux1:WideString readonly dispid 2869; // appColorAux2 : auxiliary color property appColorAux2:WideString readonly dispid 2870; // appColorAux3 : auxiliary color property appColorAux3:WideString readonly dispid 2871; // appColorAux4 : auxiliary color property appColorAux4:WideString readonly dispid 2872; // appColorAux5 : auxiliary color property appColorAux5:WideString readonly dispid 2873; // appColorAux6 : auxiliary color property appColorAux6:WideString readonly dispid 2874; // appColorAux7 : auxiliary color property appColorAux7:WideString readonly dispid 2875; // appColorAux8 : auxiliary color property appColorAux8:WideString readonly dispid 2876; // appColorAux9 : auxiliary color property appColorAux9:WideString readonly dispid 2877; // appColorAux10 : auxiliary color property appColorAux10:WideString readonly dispid 2878; // appColorAux11 : auxiliary color property appColorAux11:WideString readonly dispid 2879; // appColorAux12 : auxiliary color property appColorAux12:WideString readonly dispid 2880; // appColorAux13 : auxiliary color property appColorAux13:WideString readonly dispid 2881; // appColorAux14 : auxiliary color property appColorAux14:WideString readonly dispid 2882; // appColorAux15 : auxiliary color property appColorAux15:WideString readonly dispid 2883; // status : status string for remote player (taskbar player) property status:WideString dispid 2884; // userWMPSettingsView : property userWMPSettingsView property userWMPSettingsView:WideString readonly dispid 2859; // userWMPSettingsPreset : property userWMPSettingsPreset property userWMPSettingsPreset:Integer readonly dispid 2860; // userWMPShowSettings : property userWMPShowSettings property userWMPShowSettings:WordBool readonly dispid 2861; // userWMPMetadataView : property userWMPMetadataView property userWMPMetadataView:WideString readonly dispid 2862; // userWMPMetadataPreset : property userWMPMetadataPreset property userWMPMetadataPreset:Integer readonly dispid 2863; // userWMPShowMetadata : property userWMPShowMetadata property userWMPShowMetadata:WordBool readonly dispid 2864; // captionsHeight : property captionsHeight property captionsHeight:Integer dispid 2865; // snapToVideo : property snapToVideo property snapToVideo:WordBool dispid 2866; // pinFullScreenControls : property pinFullScreenControls property pinFullScreenControls:WordBool dispid 2867; // isMultiMon : property isMultiMon property isMultiMon:WordBool readonly dispid 2887; // exclusiveHueShift : property exclusiveHueShift property exclusiveHueShift:Single dispid 2888; // exclusiveSaturation : property exclusiveSaturation property exclusiveSaturation:Single dispid 2889; // themeBkgColorIsActive : themeBkgColorIsActive property themeBkgColorIsActive:WordBool dispid 2892; // themeBkgColorActive : themeBkgColorActive property themeBkgColorActive:WideString readonly dispid 2890; // themeBkgColorInactive : themeBkgColorInactive property themeBkgColorInactive:WideString readonly dispid 2891; end; // IWMPWindow : IWMPWindow: Not Public. Internal interface used by Windows Media Player. IWMPWindow = interface(IDispatch) ['{43D5AE92-4332-477C-8883-E0B3B063C5D2}'] // setWindowPos : method setWindowPos procedure setWindowPos(x:Integer;y:Integer;height:Integer;width:Integer);safecall; function Get_frameRate : Integer; safecall; procedure Set_frameRate(const pVal:Integer); safecall; function Get_mouseX : Integer; safecall; function Get_mouseY : Integer; safecall; procedure Set_onsizing(const Param1:IDispatch); safecall; // openViewAlwaysOnTop : procedure openViewAlwaysOnTop(bstrViewID:WideString);safecall; // frameRate : property frameRate:Integer read Get_frameRate write Set_frameRate; // mouseX : property mouseX:Integer read Get_mouseX; // mouseY : property mouseY:Integer read Get_mouseY; // onsizing : property onsizing:IDispatch write Set_onsizing; end; // IWMPWindow : IWMPWindow: Not Public. Internal interface used by Windows Media Player. IWMPWindowDisp = dispinterface ['{43D5AE92-4332-477C-8883-E0B3B063C5D2}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // setWindowPos : method setWindowPos procedure setWindowPos(x:Integer;y:Integer;height:Integer;width:Integer);dispid 3300; // openViewAlwaysOnTop : procedure openViewAlwaysOnTop(bstrViewID:WideString);dispid 3305; // frameRate : property frameRate:Integer dispid 3301; // mouseX : property mouseX:Integer readonly dispid 3302; // mouseY : property mouseY:Integer readonly dispid 3303; // onsizing : property onsizing:IDispatch writeonly dispid 3304; end; // IWMPBrandDispatch : IWMPBrandDispatch: Not Public. Internal interface used by Windows Media Player. IWMPBrandDispatch = interface(IDispatch) ['{98BB02D4-ED74-43CC-AD6A-45888F2E0DCC}'] function Get_fullServiceName : WideString; safecall; function Get_friendlyName : WideString; safecall; function Get_guideButtonText : WideString; safecall; function Get_guideButtonTip : WideString; safecall; function Get_guideMenuText : WideString; safecall; function Get_guideAccText : WideString; safecall; function Get_task1ButtonText : WideString; safecall; function Get_task1ButtonTip : WideString; safecall; function Get_task1MenuText : WideString; safecall; function Get_task1AccText : WideString; safecall; function Get_guideUrl : WideString; safecall; function Get_task1Url : WideString; safecall; function Get_imageLargeUrl : WideString; safecall; function Get_imageSmallUrl : WideString; safecall; function Get_imageMenuUrl : WideString; safecall; function Get_infoCenterUrl : WideString; safecall; function Get_albumInfoUrl : WideString; safecall; function Get_buyCDUrl : WideString; safecall; function Get_htmlViewUrl : WideString; safecall; function Get_navigateUrl : WideString; safecall; function Get_cookieUrl : WideString; safecall; function Get_downloadStatusUrl : WideString; safecall; function Get_colorPlayer : WideString; safecall; function Get_colorPlayerText : WideString; safecall; function Get_navigateDispid : Integer; safecall; function Get_navigateParams : WideString; safecall; function Get_navigatePane : WideString; safecall; function Get_selectedPane : WideString; safecall; procedure Set_selectedPane(const pVal:WideString); safecall; // setNavigateProps : method setNavigateProps procedure setNavigateProps(bstrPane:WideString;lDispid:Integer;bstrParams:WideString);safecall; // getMediaParams : method getMediaParams function getMediaParams(pObject:IUnknown;bstrURL:WideString):WideString;safecall; procedure Set_selectedTask(const Param1:Integer); safecall; function Get_contentPartnerSelected : WordBool; safecall; // fullServiceName : property fullServiceName property fullServiceName:WideString read Get_fullServiceName; // friendlyName : property friendlyName property friendlyName:WideString read Get_friendlyName; // guideButtonText : property guideButtonText property guideButtonText:WideString read Get_guideButtonText; // guideButtonTip : property guideButtonTip property guideButtonTip:WideString read Get_guideButtonTip; // guideMenuText : property guideMenuText property guideMenuText:WideString read Get_guideMenuText; // guideAccText : property guideAccText property guideAccText:WideString read Get_guideAccText; // task1ButtonText : property task1ButtonText property task1ButtonText:WideString read Get_task1ButtonText; // task1ButtonTip : property task1ButtonTip property task1ButtonTip:WideString read Get_task1ButtonTip; // task1MenuText : property task1MenuText property task1MenuText:WideString read Get_task1MenuText; // task1AccText : property task1AccText property task1AccText:WideString read Get_task1AccText; // guideUrl : property guideUrl property guideUrl:WideString read Get_guideUrl; // task1Url : property task1Url property task1Url:WideString read Get_task1Url; // imageLargeUrl : property imageLargeUrl property imageLargeUrl:WideString read Get_imageLargeUrl; // imageSmallUrl : property imageSmallUrl property imageSmallUrl:WideString read Get_imageSmallUrl; // imageMenuUrl : property imageMenuUrl property imageMenuUrl:WideString read Get_imageMenuUrl; // infoCenterUrl : property infoCenterUrl property infoCenterUrl:WideString read Get_infoCenterUrl; // albumInfoUrl : property albumInfoUrl property albumInfoUrl:WideString read Get_albumInfoUrl; // buyCDUrl : property buyCDUrl property buyCDUrl:WideString read Get_buyCDUrl; // htmlViewUrl : property htmlViewUrl property htmlViewUrl:WideString read Get_htmlViewUrl; // navigateUrl : property navigateUrl property navigateUrl:WideString read Get_navigateUrl; // cookieUrl : property cookieUrl property cookieUrl:WideString read Get_cookieUrl; // downloadStatusUrl : property downloadStatusUrl property downloadStatusUrl:WideString read Get_downloadStatusUrl; // colorPlayer : property colorPlayer property colorPlayer:WideString read Get_colorPlayer; // colorPlayerText : property colorPlayerText property colorPlayerText:WideString read Get_colorPlayerText; // navigateDispid : property navigateDispid property navigateDispid:Integer read Get_navigateDispid; // navigateParams : property navigateParams property navigateParams:WideString read Get_navigateParams; // navigatePane : property navigatePane property navigatePane:WideString read Get_navigatePane; // selectedPane : property selectedPane property selectedPane:WideString read Get_selectedPane write Set_selectedPane; // selectedTask : property selectedTask property selectedTask:Integer write Set_selectedTask; // contentPartnerSelected : property contentPartnerSelected property contentPartnerSelected:WordBool read Get_contentPartnerSelected; end; // IWMPBrandDispatch : IWMPBrandDispatch: Not Public. Internal interface used by Windows Media Player. IWMPBrandDispatchDisp = dispinterface ['{98BB02D4-ED74-43CC-AD6A-45888F2E0DCC}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // setNavigateProps : method setNavigateProps procedure setNavigateProps(bstrPane:WideString;lDispid:Integer;bstrParams:WideString);dispid 3041; // getMediaParams : method getMediaParams function getMediaParams(pObject:IUnknown;bstrURL:WideString):WideString;dispid 3042; // fullServiceName : property fullServiceName property fullServiceName:WideString readonly dispid 3040; // friendlyName : property friendlyName property friendlyName:WideString readonly dispid 3000; // guideButtonText : property guideButtonText property guideButtonText:WideString readonly dispid 3001; // guideButtonTip : property guideButtonTip property guideButtonTip:WideString readonly dispid 3002; // guideMenuText : property guideMenuText property guideMenuText:WideString readonly dispid 3003; // guideAccText : property guideAccText property guideAccText:WideString readonly dispid 3004; // task1ButtonText : property task1ButtonText property task1ButtonText:WideString readonly dispid 3005; // task1ButtonTip : property task1ButtonTip property task1ButtonTip:WideString readonly dispid 3006; // task1MenuText : property task1MenuText property task1MenuText:WideString readonly dispid 3007; // task1AccText : property task1AccText property task1AccText:WideString readonly dispid 3008; // guideUrl : property guideUrl property guideUrl:WideString readonly dispid 3017; // task1Url : property task1Url property task1Url:WideString readonly dispid 3018; // imageLargeUrl : property imageLargeUrl property imageLargeUrl:WideString readonly dispid 3021; // imageSmallUrl : property imageSmallUrl property imageSmallUrl:WideString readonly dispid 3022; // imageMenuUrl : property imageMenuUrl property imageMenuUrl:WideString readonly dispid 3023; // infoCenterUrl : property infoCenterUrl property infoCenterUrl:WideString readonly dispid 3024; // albumInfoUrl : property albumInfoUrl property albumInfoUrl:WideString readonly dispid 3025; // buyCDUrl : property buyCDUrl property buyCDUrl:WideString readonly dispid 3026; // htmlViewUrl : property htmlViewUrl property htmlViewUrl:WideString readonly dispid 3027; // navigateUrl : property navigateUrl property navigateUrl:WideString readonly dispid 3028; // cookieUrl : property cookieUrl property cookieUrl:WideString readonly dispid 3029; // downloadStatusUrl : property downloadStatusUrl property downloadStatusUrl:WideString readonly dispid 3030; // colorPlayer : property colorPlayer property colorPlayer:WideString readonly dispid 3031; // colorPlayerText : property colorPlayerText property colorPlayerText:WideString readonly dispid 3032; // navigateDispid : property navigateDispid property navigateDispid:Integer readonly dispid 3035; // navigateParams : property navigateParams property navigateParams:WideString readonly dispid 3036; // navigatePane : property navigatePane property navigatePane:WideString readonly dispid 3037; // selectedPane : property selectedPane property selectedPane:WideString dispid 3038; // selectedTask : property selectedTask property selectedTask:Integer writeonly dispid 3039; // contentPartnerSelected : property contentPartnerSelected property contentPartnerSelected:WordBool readonly dispid 3043; end; // IWMPNowPlayingHelperDispatch : IWMPNowPlayingHelperDispatch: Not Public. Internal interface used by Windows Media Player. IWMPNowPlayingHelperDispatch = interface(IDispatch) ['{504F112E-77CC-4E3C-A073-5371B31D9B36}'] function Get_viewFriendlyName(bstrView:WideString) : WideString; safecall; function Get_viewPresetCount(bstrView:WideString) : Integer; safecall; function Get_viewPresetName(bstrView:WideString) : WideString; safecall; function Get_effectFriendlyName(bstrEffect:WideString) : WideString; safecall; function Get_effectPresetName(bstrEffect:WideString) : WideString; safecall; // resolveDisplayView : method resolveDisplayView function resolveDisplayView(fSafe:WordBool):WideString;safecall; // isValidDisplayView : method isValidDisplayView function isValidDisplayView(bstrView:WideString):WordBool;safecall; // getSkinFile : method getSkinFile function getSkinFile:WideString;safecall; function Get_captionsAvailable : WordBool; safecall; function Get_linkAvailable : Integer; safecall; function Get_linkRequest : Integer; safecall; procedure Set_linkRequest(const pVal:Integer); safecall; function Get_linkRequestParams : WideString; safecall; procedure Set_linkRequestParams(const pVal:WideString); safecall; // getCurrentArtID : method getCurrentArtID function getCurrentArtID(fLargeArt:WordBool):Integer;safecall; // getTimeString : method getTimeString function getTimeString(dTime:Double):WideString;safecall; // getCurrentScriptCommand : method getCurrentScriptCommand function getCurrentScriptCommand(bstrType:WideString):WideString;safecall; // calcLayout : method calcLayout procedure calcLayout(lWidth:Integer;lHeight:Integer;vbCaptions:WordBool;vbBanner:WordBool);safecall; // getLayoutSize : method getLayoutSize function getLayoutSize(nProp:Integer):Integer;safecall; // getRootPlaylist : method getRootPlaylist function getRootPlaylist(pPlaylist:IDispatch):IDispatch;safecall; // getHTMLViewURL : method getHTMLViewURL function getHTMLViewURL:WideString;safecall; function Get_editObj : IUnknown; safecall; procedure Set_editObj(const ppVal:IUnknown); safecall; // getStatusString : method getStatusString function getStatusString(bstrStatusId:WideString):WideString;safecall; // getStatusPct : method getStatusPct function getStatusPct(bstrStatusId:WideString):Integer;safecall; // getStatusResult : method getStatusResult function getStatusResult(bstrStatusId:WideString):Integer;safecall; // getStatusIcon : method getStatusIcon function getStatusIcon(bstrStatusId:WideString):Integer;safecall; // getStatusIdList : method getStatusIdList function getStatusIdList:WideString;safecall; function Get_notificationString : WideString; safecall; function Get_htmlViewBaseURL : WideString; safecall; procedure Set_htmlViewBaseURL(const pVal:WideString); safecall; function Get_htmlViewFullURL : WideString; safecall; procedure Set_htmlViewFullURL(const pVal:WideString); safecall; function Get_htmlViewSecureLock : Integer; safecall; procedure Set_htmlViewSecureLock(const pVal:Integer); safecall; function Get_htmlViewBusy : WordBool; safecall; procedure Set_htmlViewBusy(const pVal:WordBool); safecall; function Get_htmlViewShowCert : WordBool; safecall; procedure Set_htmlViewShowCert(const pVal:WordBool); safecall; function Get_previousEnabled : WordBool; safecall; procedure Set_previousEnabled(const pVal:WordBool); safecall; function Get_doPreviousNow : WordBool; safecall; procedure Set_doPreviousNow(const pVal:WordBool); safecall; function Get_DPI : Integer; safecall; // clearColors : clear all user color info procedure clearColors;safecall; function Get_lastMessage : WideString; safecall; procedure Set_lastMessage(const pVal:WideString); safecall; function Get_inVistaPlus : WordBool; safecall; function Get_isBidi : WordBool; safecall; function Get_isOCX : WordBool; safecall; function Get_hoverTransportsEnabled : WordBool; safecall; // initRipHelper : procedure initRipHelper;safecall; function Get_isAudioCD : WordBool; safecall; procedure Set_isAudioCD(const pVal:WordBool); safecall; function Get_canRip : WordBool; safecall; procedure Set_canRip(const pVal:WordBool); safecall; function Get_isRipping : WordBool; safecall; procedure Set_isRipping(const pVal:WordBool); safecall; function Get_currentDrive : WideString; safecall; procedure Set_currentDrive(const pVal:WideString); safecall; // startRip : procedure startRip;safecall; // stopRip : procedure stopRip;safecall; function Get_showMMO : WordBool; safecall; procedure Set_showMMO(const pVal:WordBool); safecall; function Get_MMOVisible : WordBool; safecall; function Get_suggestionsVisible : WordBool; safecall; function Get_suggestionsTextColor : WideString; safecall; function Get_fontFace : WideString; safecall; function Get_fontSize : Integer; safecall; function Get_backgroundColor : WideString; safecall; function Get_doubleClickTime : Integer; safecall; function Get_playAgain : WordBool; safecall; function Get_previousPlaylistAvailable : WordBool; safecall; function Get_nextPlaylistAvailable : WordBool; safecall; // nextPlaylist : procedure nextPlaylist;safecall; // previousPlaylist : procedure previousPlaylist;safecall; // playOffsetMedia : procedure playOffsetMedia(iOffset:Integer);safecall; function Get_basketVisible : WordBool; safecall; procedure Set_basketVisible(const pVal:WordBool); safecall; function Get_mmoTextColor : WideString; safecall; function Get_backgroundVisible : WordBool; safecall; procedure Set_backgroundEnabled(const pVal:WordBool); safecall; function Get_backgroundEnabled : WordBool; safecall; procedure Set_backgroundIndex(const pVal:Integer); safecall; function Get_backgroundIndex : Integer; safecall; function Get_upNext : WideString; safecall; function Get_playbackOverlayVisible : WordBool; safecall; function Get_remoted : WordBool; safecall; function Get_glassEnabled : WordBool; safecall; function Get_highContrast : WordBool; safecall; procedure Set_testHighContrast(const Param1:WideString); safecall; function Get_sessionPlaylistCount : Integer; safecall; // setGestureStatus : procedure setGestureStatus(pObject:IDispatch;newVal:Integer);safecall; function Get_metadataString : WideString; safecall; procedure Set_metadataString(const pVal:WideString); safecall; function Get_albumArtAlpha : Integer; safecall; function Get_playerModeAlbumArtSelected : WordBool; safecall; function Get_inFullScreen : WordBool; safecall; // syncToAlbumArt : procedure syncToAlbumArt(pObject:IDispatch;iOffsetFromCurrentMedia:Integer;bstrFallbackImage:WideString);safecall; function Get_resourceIdForDpi(iResourceId:SYSINT) : SYSINT; safecall; // viewFriendlyName : property viewFriendlyName property viewFriendlyName[bstrView:WideString]:WideString read Get_viewFriendlyName; // viewPresetCount : property viewPresetCount property viewPresetCount[bstrView:WideString]:Integer read Get_viewPresetCount; // viewPresetName : method viewPresetName property viewPresetName[bstrView:WideString]:WideString read Get_viewPresetName; // effectFriendlyName : property effectFriendlyName property effectFriendlyName[bstrEffect:WideString]:WideString read Get_effectFriendlyName; // effectPresetName : method effectPresetName property effectPresetName[bstrEffect:WideString]:WideString read Get_effectPresetName; // captionsAvailable : method captionsAvailable property captionsAvailable:WordBool read Get_captionsAvailable; // linkAvailable : property linkAvailable property linkAvailable:Integer read Get_linkAvailable; // linkRequest : property linkRequest property linkRequest:Integer read Get_linkRequest write Set_linkRequest; // linkRequestParams : property linkRequestParams property linkRequestParams:WideString read Get_linkRequestParams write Set_linkRequestParams; // editObj : property editObj:IUnknown read Get_editObj write Set_editObj; // notificationString : property notificationString:WideString read Get_notificationString; // htmlViewBaseURL : property htmlViewBaseURL:WideString read Get_htmlViewBaseURL write Set_htmlViewBaseURL; // htmlViewFullURL : property htmlViewFullURL:WideString read Get_htmlViewFullURL write Set_htmlViewFullURL; // htmlViewSecureLock : property htmlViewSecureLock:Integer read Get_htmlViewSecureLock write Set_htmlViewSecureLock; // htmlViewBusy : property htmlViewBusy:WordBool read Get_htmlViewBusy write Set_htmlViewBusy; // htmlViewShowCert : property htmlViewShowCert:WordBool read Get_htmlViewShowCert write Set_htmlViewShowCert; // previousEnabled : property previousEnabled:WordBool read Get_previousEnabled write Set_previousEnabled; // doPreviousNow : property doPreviousNow:WordBool read Get_doPreviousNow write Set_doPreviousNow; // DPI : property DPI:Integer read Get_DPI; // lastMessage : property lastMessage:WideString read Get_lastMessage write Set_lastMessage; // inVistaPlus : property inVistaPlus:WordBool read Get_inVistaPlus; // isBidi : property isBidi:WordBool read Get_isBidi; // isOCX : property isOCX:WordBool read Get_isOCX; // hoverTransportsEnabled : property hoverTransportsEnabled:WordBool read Get_hoverTransportsEnabled; // isAudioCD : property isAudioCD:WordBool read Get_isAudioCD write Set_isAudioCD; // canRip : property canRip:WordBool read Get_canRip write Set_canRip; // isRipping : property isRipping:WordBool read Get_isRipping write Set_isRipping; // currentDrive : property currentDrive:WideString read Get_currentDrive write Set_currentDrive; // showMMO : property showMMO:WordBool read Get_showMMO write Set_showMMO; // MMOVisible : property MMOVisible:WordBool read Get_MMOVisible; // suggestionsVisible : property suggestionsVisible:WordBool read Get_suggestionsVisible; // suggestionsTextColor : property suggestionsTextColor:WideString read Get_suggestionsTextColor; // fontFace : property fontFace:WideString read Get_fontFace; // fontSize : property fontSize:Integer read Get_fontSize; // backgroundColor : property backgroundColor:WideString read Get_backgroundColor; // doubleClickTime : property doubleClickTime:Integer read Get_doubleClickTime; // playAgain : property playAgain:WordBool read Get_playAgain; // previousPlaylistAvailable : property previousPlaylistAvailable:WordBool read Get_previousPlaylistAvailable; // nextPlaylistAvailable : property nextPlaylistAvailable:WordBool read Get_nextPlaylistAvailable; // basketVisible : property basketVisible:WordBool read Get_basketVisible write Set_basketVisible; // mmoTextColor : property mmoTextColor:WideString read Get_mmoTextColor; // backgroundVisible : property backgroundVisible:WordBool read Get_backgroundVisible; // backgroundEnabled : property backgroundEnabled:WordBool read Get_backgroundEnabled write Set_backgroundEnabled; // backgroundIndex : property backgroundIndex:Integer read Get_backgroundIndex write Set_backgroundIndex; // upNext : property upNext:WideString read Get_upNext; // playbackOverlayVisible : property playbackOverlayVisible:WordBool read Get_playbackOverlayVisible; // remoted : property remoted:WordBool read Get_remoted; // glassEnabled : property glassEnabled:WordBool read Get_glassEnabled; // highContrast : property highContrast:WordBool read Get_highContrast; // testHighContrast : property testHighContrast:WideString write Set_testHighContrast; // sessionPlaylistCount : property sessionPlaylistCount:Integer read Get_sessionPlaylistCount; // metadataString : property metadataString:WideString read Get_metadataString write Set_metadataString; // albumArtAlpha : property albumArtAlpha:Integer read Get_albumArtAlpha; // playerModeAlbumArtSelected : property playerModeAlbumArtSelected:WordBool read Get_playerModeAlbumArtSelected; // inFullScreen : property inFullScreen:WordBool read Get_inFullScreen; // resourceIdForDpi : property resourceIdForDpi[iResourceId:SYSINT]:SYSINT read Get_resourceIdForDpi; end; // IWMPNowPlayingHelperDispatch : IWMPNowPlayingHelperDispatch: Not Public. Internal interface used by Windows Media Player. IWMPNowPlayingHelperDispatchDisp = dispinterface ['{504F112E-77CC-4E3C-A073-5371B31D9B36}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // resolveDisplayView : method resolveDisplayView function resolveDisplayView(fSafe:WordBool):WideString;dispid 2909; // isValidDisplayView : method isValidDisplayView function isValidDisplayView(bstrView:WideString):WordBool;dispid 2910; // getSkinFile : method getSkinFile function getSkinFile:WideString;dispid 2911; // getCurrentArtID : method getCurrentArtID function getCurrentArtID(fLargeArt:WordBool):Integer;dispid 2917; // getTimeString : method getTimeString function getTimeString(dTime:Double):WideString;dispid 2918; // getCurrentScriptCommand : method getCurrentScriptCommand function getCurrentScriptCommand(bstrType:WideString):WideString;dispid 2919; // calcLayout : method calcLayout procedure calcLayout(lWidth:Integer;lHeight:Integer;vbCaptions:WordBool;vbBanner:WordBool);dispid 2920; // getLayoutSize : method getLayoutSize function getLayoutSize(nProp:Integer):Integer;dispid 2921; // getRootPlaylist : method getRootPlaylist function getRootPlaylist(pPlaylist:IDispatch):IDispatch;dispid 2922; // getHTMLViewURL : method getHTMLViewURL function getHTMLViewURL:WideString;dispid 2923; // getStatusString : method getStatusString function getStatusString(bstrStatusId:WideString):WideString;dispid 2927; // getStatusPct : method getStatusPct function getStatusPct(bstrStatusId:WideString):Integer;dispid 2939; // getStatusResult : method getStatusResult function getStatusResult(bstrStatusId:WideString):Integer;dispid 2940; // getStatusIcon : method getStatusIcon function getStatusIcon(bstrStatusId:WideString):Integer;dispid 2941; // getStatusIdList : method getStatusIdList function getStatusIdList:WideString;dispid 2942; // clearColors : clear all user color info procedure clearColors;dispid 2937; // initRipHelper : procedure initRipHelper;dispid 2947; // startRip : procedure startRip;dispid 2952; // stopRip : procedure stopRip;dispid 2953; // nextPlaylist : procedure nextPlaylist;dispid 2961; // previousPlaylist : procedure previousPlaylist;dispid 2962; // playOffsetMedia : procedure playOffsetMedia(iOffset:Integer);dispid 2972; // setGestureStatus : procedure setGestureStatus(pObject:IDispatch;newVal:Integer);dispid 2980; // syncToAlbumArt : procedure syncToAlbumArt(pObject:IDispatch;iOffsetFromCurrentMedia:Integer;bstrFallbackImage:WideString);dispid 2985; // viewFriendlyName : property viewFriendlyName property viewFriendlyName[bstrView:WideString]:WideString readonly dispid 2901; // viewPresetCount : property viewPresetCount property viewPresetCount[bstrView:WideString]:Integer readonly dispid 2902; // viewPresetName : method viewPresetName property viewPresetName[bstrView:WideString]:WideString readonly dispid 2903; // effectFriendlyName : property effectFriendlyName property effectFriendlyName[bstrEffect:WideString]:WideString readonly dispid 2904; // effectPresetName : method effectPresetName property effectPresetName[bstrEffect:WideString]:WideString readonly dispid 2905; // captionsAvailable : method captionsAvailable property captionsAvailable:WordBool readonly dispid 2912; // linkAvailable : property linkAvailable property linkAvailable:Integer readonly dispid 2913; // linkRequest : property linkRequest property linkRequest:Integer dispid 2914; // linkRequestParams : property linkRequestParams property linkRequestParams:WideString dispid 2915; // editObj : property editObj:IUnknown dispid 2926; // notificationString : property notificationString:WideString readonly dispid 2928; // htmlViewBaseURL : property htmlViewBaseURL:WideString dispid 2930; // htmlViewFullURL : property htmlViewFullURL:WideString dispid 2933; // htmlViewSecureLock : property htmlViewSecureLock:Integer dispid 2929; // htmlViewBusy : property htmlViewBusy:WordBool dispid 2931; // htmlViewShowCert : property htmlViewShowCert:WordBool dispid 2932; // previousEnabled : property previousEnabled:WordBool dispid 2934; // doPreviousNow : property doPreviousNow:WordBool dispid 2935; // DPI : property DPI:Integer readonly dispid 2936; // lastMessage : property lastMessage:WideString dispid 2938; // inVistaPlus : property inVistaPlus:WordBool readonly dispid 2943; // isBidi : property isBidi:WordBool readonly dispid 2944; // isOCX : property isOCX:WordBool readonly dispid 2945; // hoverTransportsEnabled : property hoverTransportsEnabled:WordBool readonly dispid 2946; // isAudioCD : property isAudioCD:WordBool dispid 2948; // canRip : property canRip:WordBool dispid 2949; // isRipping : property isRipping:WordBool dispid 2950; // currentDrive : property currentDrive:WideString dispid 2951; // showMMO : property showMMO:WordBool dispid 2954; // MMOVisible : property MMOVisible:WordBool readonly dispid 2971; // suggestionsVisible : property suggestionsVisible:WordBool readonly dispid 2955; // suggestionsTextColor : property suggestionsTextColor:WideString readonly dispid 2956; // fontFace : property fontFace:WideString readonly dispid 2964; // fontSize : property fontSize:Integer readonly dispid 2965; // backgroundColor : property backgroundColor:WideString readonly dispid 2966; // doubleClickTime : property doubleClickTime:Integer readonly dispid 2957; // playAgain : property playAgain:WordBool readonly dispid 2958; // previousPlaylistAvailable : property previousPlaylistAvailable:WordBool readonly dispid 2959; // nextPlaylistAvailable : property nextPlaylistAvailable:WordBool readonly dispid 2960; // basketVisible : property basketVisible:WordBool dispid 2963; // mmoTextColor : property mmoTextColor:WideString readonly dispid 2967; // backgroundVisible : property backgroundVisible:WordBool readonly dispid 2968; // backgroundEnabled : property backgroundEnabled:WordBool dispid 2969; // backgroundIndex : property backgroundIndex:Integer dispid 2970; // upNext : property upNext:WideString readonly dispid 2973; // playbackOverlayVisible : property playbackOverlayVisible:WordBool readonly dispid 2974; // remoted : property remoted:WordBool readonly dispid 2975; // glassEnabled : property glassEnabled:WordBool readonly dispid 2976; // highContrast : property highContrast:WordBool readonly dispid 2977; // testHighContrast : property testHighContrast:WideString writeonly dispid 2978; // sessionPlaylistCount : property sessionPlaylistCount:{!! pointer !!} OleVariant readonly dispid 2979; // metadataString : property metadataString:WideString dispid 2981; // albumArtAlpha : property albumArtAlpha:Integer readonly dispid 2982; // playerModeAlbumArtSelected : property playerModeAlbumArtSelected:WordBool readonly dispid 2983; // inFullScreen : property inFullScreen:WordBool readonly dispid 2984; // resourceIdForDpi : property resourceIdForDpi[iResourceId:SYSINT]:SYSINT readonly dispid 2986; end; // IWMPNowDoingDispatch : IWMPNowDoingDispatch: Not Public. Internal interface used by Windows Media Player. IWMPNowDoingDispatch = interface(IDispatch) ['{2A2E0DA3-19FA-4F82-BE18-CD7D7A3B977F}'] // hideBasket : method hideBasket procedure hideBasket;safecall; // burnNavigateToStatus : method burnNavigateToStatus procedure burnNavigateToStatus;safecall; // syncNavigateToStatus : method syncNavigateToStatus procedure syncNavigateToStatus;safecall; function Get_DPI : Integer; safecall; function Get_mode : WideString; safecall; procedure Set_burn_selectedDrive(const pVal:Integer); safecall; function Get_burn_selectedDrive : Integer; safecall; function Get_sync_selectedDevice : Integer; safecall; procedure Set_sync_selectedDevice(const pVal:Integer); safecall; function Get_burn_numDiscsSpanned : Integer; safecall; function Get_editPlaylist : IDispatch; safecall; function Get_basketPlaylistName : WideString; safecall; function Get_isHighContrastMode : WordBool; safecall; function Get_allowRating : WordBool; safecall; function Get_burn_mediaType : WideString; safecall; function Get_burn_contentType : WideString; safecall; function Get_burn_freeSpace : Integer; safecall; function Get_burn_totalSpace : Integer; safecall; function Get_burn_driveName : WideString; safecall; function Get_burn_numDevices : Integer; safecall; function Get_burn_spaceToUse : Integer; safecall; function Get_burn_percentComplete : Integer; safecall; function Get_sync_spaceToUse : Integer; safecall; function Get_sync_spaceUsed : Integer; safecall; function Get_sync_totalSpace : Integer; safecall; function Get_sync_deviceName : WideString; safecall; function Get_sync_numDevices : Integer; safecall; function Get_sync_oemName : WideString; safecall; function Get_sync_percentComplete : Integer; safecall; // logData : method logData procedure logData(ID:WideString;data:WideString);safecall; // formatTime : method formatTime function formatTime(value:Integer):WideString;safecall; // DPI : property DPI:Integer read Get_DPI; // mode : property mode property mode:WideString read Get_mode; // burn_selectedDrive : property burn_selectedDrive property burn_selectedDrive:Integer read Get_burn_selectedDrive write Set_burn_selectedDrive; // sync_selectedDevice : property sync_selectedDevice property sync_selectedDevice:Integer read Get_sync_selectedDevice write Set_sync_selectedDevice; // burn_numDiscsSpanned : property burn_numDiscsSpanned property burn_numDiscsSpanned:Integer read Get_burn_numDiscsSpanned; // editPlaylist : method editPlaylist property editPlaylist:IDispatch read Get_editPlaylist; // basketPlaylistName : property basketPlaylistName property basketPlaylistName:WideString read Get_basketPlaylistName; // isHighContrastMode : property isHighContrastMode property isHighContrastMode:WordBool read Get_isHighContrastMode; // allowRating : property allowRating property allowRating:WordBool read Get_allowRating; // burn_mediaType : property burn_mediaType property burn_mediaType:WideString read Get_burn_mediaType; // burn_contentType : property burn_contentType property burn_contentType:WideString read Get_burn_contentType; // burn_freeSpace : property burn_freeSpace property burn_freeSpace:Integer read Get_burn_freeSpace; // burn_totalSpace : property burn_totalSpace property burn_totalSpace:Integer read Get_burn_totalSpace; // burn_driveName : property burn_driveName property burn_driveName:WideString read Get_burn_driveName; // burn_numDevices : property burn_numDevices property burn_numDevices:Integer read Get_burn_numDevices; // burn_spaceToUse : property burn_spaceToUse property burn_spaceToUse:Integer read Get_burn_spaceToUse; // burn_percentComplete : property burn_percentComplete property burn_percentComplete:Integer read Get_burn_percentComplete; // sync_spaceToUse : property sync_spaceToUse property sync_spaceToUse:Integer read Get_sync_spaceToUse; // sync_spaceUsed : property sync_spaceUsed property sync_spaceUsed:Integer read Get_sync_spaceUsed; // sync_totalSpace : property sync_totalSpace property sync_totalSpace:Integer read Get_sync_totalSpace; // sync_deviceName : property sync_deviceName property sync_deviceName:WideString read Get_sync_deviceName; // sync_numDevices : property sync_numDevices property sync_numDevices:Integer read Get_sync_numDevices; // sync_oemName : property sync_oemName property sync_oemName:WideString read Get_sync_oemName; // sync_percentComplete : property sync_percentComplete property sync_percentComplete:Integer read Get_sync_percentComplete; end; // IWMPNowDoingDispatch : IWMPNowDoingDispatch: Not Public. Internal interface used by Windows Media Player. IWMPNowDoingDispatchDisp = dispinterface ['{2A2E0DA3-19FA-4F82-BE18-CD7D7A3B977F}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // hideBasket : method hideBasket procedure hideBasket;dispid 3222; // burnNavigateToStatus : method burnNavigateToStatus procedure burnNavigateToStatus;dispid 3211; // syncNavigateToStatus : method syncNavigateToStatus procedure syncNavigateToStatus;dispid 3220; // logData : method logData procedure logData(ID:WideString;data:WideString);dispid 3224; // formatTime : method formatTime function formatTime(value:Integer):WideString;dispid 3226; // DPI : property DPI:Integer readonly dispid 3223; // mode : property mode property mode:WideString readonly dispid 3200; // burn_selectedDrive : property burn_selectedDrive property burn_selectedDrive:Integer dispid 3206; // sync_selectedDevice : property sync_selectedDevice property sync_selectedDevice:Integer dispid 3216; // burn_numDiscsSpanned : property burn_numDiscsSpanned property burn_numDiscsSpanned:Integer readonly dispid 3208; // editPlaylist : method editPlaylist property editPlaylist:IDispatch readonly dispid 3225; // basketPlaylistName : property basketPlaylistName property basketPlaylistName:WideString readonly dispid 3227; // isHighContrastMode : property isHighContrastMode property isHighContrastMode:WordBool readonly dispid 3228; // allowRating : property allowRating property allowRating:WordBool readonly dispid 3229; // burn_mediaType : property burn_mediaType property burn_mediaType:WideString readonly dispid 3201; // burn_contentType : property burn_contentType property burn_contentType:WideString readonly dispid 3202; // burn_freeSpace : property burn_freeSpace property burn_freeSpace:Integer readonly dispid 3203; // burn_totalSpace : property burn_totalSpace property burn_totalSpace:Integer readonly dispid 3204; // burn_driveName : property burn_driveName property burn_driveName:WideString readonly dispid 3205; // burn_numDevices : property burn_numDevices property burn_numDevices:Integer readonly dispid 3207; // burn_spaceToUse : property burn_spaceToUse property burn_spaceToUse:Integer readonly dispid 3209; // burn_percentComplete : property burn_percentComplete property burn_percentComplete:Integer readonly dispid 3210; // sync_spaceToUse : property sync_spaceToUse property sync_spaceToUse:Integer readonly dispid 3212; // sync_spaceUsed : property sync_spaceUsed property sync_spaceUsed:Integer readonly dispid 3213; // sync_totalSpace : property sync_totalSpace property sync_totalSpace:Integer readonly dispid 3214; // sync_deviceName : property sync_deviceName property sync_deviceName:WideString readonly dispid 3215; // sync_numDevices : property sync_numDevices property sync_numDevices:Integer readonly dispid 3217; // sync_oemName : property sync_oemName property sync_oemName:WideString readonly dispid 3218; // sync_percentComplete : property sync_percentComplete property sync_percentComplete:Integer readonly dispid 3219; end; // IWMPHoverPreviewDispatch : IWMPHoverPreviewDispatch: Not Public. Internal interface used by Windows Media Player. IWMPHoverPreviewDispatch = interface(IDispatch) ['{946B023E-044C-4473-8018-74954F09DC7E}'] function Get_title : WideString; safecall; function Get_album : WideString; safecall; function Get_URL : WideString; safecall; procedure Set_image(const Param1:IDispatch); safecall; procedure Set_autoClick(const Param1:WordBool); safecall; procedure Set_previewClick(const Param1:WordBool); safecall; // dismiss : procedure dismiss;safecall; // title : property title:WideString read Get_title; // album : property album:WideString read Get_album; // URL : property URL:WideString read Get_URL; // image : property image:IDispatch write Set_image; // autoClick : property autoClick:WordBool write Set_autoClick; // previewClick : property previewClick:WordBool write Set_previewClick; end; // IWMPHoverPreviewDispatch : IWMPHoverPreviewDispatch: Not Public. Internal interface used by Windows Media Player. IWMPHoverPreviewDispatchDisp = dispinterface ['{946B023E-044C-4473-8018-74954F09DC7E}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // dismiss : procedure dismiss;dispid 3156; // title : property title:WideString readonly dispid 3150; // album : property album:WideString readonly dispid 3151; // URL : property URL:WideString readonly dispid 3153; // image : property image:IDispatch writeonly dispid 3152; // autoClick : property autoClick:WordBool writeonly dispid 3155; // previewClick : property previewClick:WordBool writeonly dispid 3154; end; // IWMPButtonCtrlEvents : IWMPButtonCtrlEvents: Public interface for skin object model. IWMPButtonCtrlEvents = dispinterface ['{BB17FFF7-1692-4555-918A-6AF7BFACEDD2}'] // onclick : event ondragbegin function onclick:HResult;dispid 5120; end; // IWMPButtonCtrl : IWMPButtonCtrl: Public interface for skin object model. IWMPButtonCtrl = interface(IDispatch) ['{87291B50-0C8E-11D3-BB2A-00A0C93CA73A}'] function Get_image : WideString; safecall; procedure Set_image(const pVal:WideString); safecall; function Get_hoverImage : WideString; safecall; procedure Set_hoverImage(const pVal:WideString); safecall; function Get_downImage : WideString; safecall; procedure Set_downImage(const pVal:WideString); safecall; function Get_disabledImage : WideString; safecall; procedure Set_disabledImage(const pVal:WideString); safecall; function Get_hoverDownImage : WideString; safecall; procedure Set_hoverDownImage(const pVal:WideString); safecall; function Get_tiled : WordBool; safecall; procedure Set_tiled(const pVal:WordBool); safecall; function Get_transparencyColor : WideString; safecall; procedure Set_transparencyColor(const pVal:WideString); safecall; function Get_down : WordBool; safecall; procedure Set_down(const pVal:WordBool); safecall; function Get_sticky : WordBool; safecall; procedure Set_sticky(const pVal:WordBool); safecall; function Get_upToolTip : WideString; safecall; procedure Set_upToolTip(const pVal:WideString); safecall; function Get_downToolTip : WideString; safecall; procedure Set_downToolTip(const pVal:WideString); safecall; function Get_cursor : WideString; safecall; procedure Set_cursor(const pVal:WideString); safecall; // image : property image:WideString read Get_image write Set_image; // hoverImage : property hoverImage:WideString read Get_hoverImage write Set_hoverImage; // downImage : property downImage:WideString read Get_downImage write Set_downImage; // disabledImage : property disabledImage:WideString read Get_disabledImage write Set_disabledImage; // hoverDownImage : property hoverDownImage:WideString read Get_hoverDownImage write Set_hoverDownImage; // tiled : property tiled:WordBool read Get_tiled write Set_tiled; // transparencyColor : property transparencyColor:WideString read Get_transparencyColor write Set_transparencyColor; // down : property down:WordBool read Get_down write Set_down; // sticky : property sticky:WordBool read Get_sticky write Set_sticky; // upToolTip : property upToolTip:WideString read Get_upToolTip write Set_upToolTip; // downToolTip : property downToolTip:WideString read Get_downToolTip write Set_downToolTip; // cursor : property cursor:WideString read Get_cursor write Set_cursor; end; // IWMPButtonCtrl : IWMPButtonCtrl: Public interface for skin object model. IWMPButtonCtrlDisp = dispinterface ['{87291B50-0C8E-11D3-BB2A-00A0C93CA73A}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // image : property image:WideString dispid 5102; // hoverImage : property hoverImage:WideString dispid 5103; // downImage : property downImage:WideString dispid 5104; // disabledImage : property disabledImage:WideString dispid 5105; // hoverDownImage : property hoverDownImage:WideString dispid 5106; // tiled : property tiled:WordBool dispid 5107; // transparencyColor : property transparencyColor:WideString dispid 5108; // down : property down:WordBool dispid 5109; // sticky : property sticky:WordBool dispid 5110; // upToolTip : property upToolTip:WideString dispid 5112; // downToolTip : property downToolTip:WideString dispid 5113; // cursor : property cursor:WideString dispid 5114; end; // IWMPListBoxCtrl : IWMPListBoxCtrl: Public interface for skin object model. IWMPListBoxCtrl = interface(IDispatch) ['{FC1880CE-83B9-43A7-A066-C44CE8C82583}'] function Get_selectedItem : Integer; safecall; procedure Set_selectedItem(const pnPos:Integer); safecall; function Get_sorted : WordBool; safecall; procedure Set_sorted(const pVal:WordBool); safecall; function Get_multiselect : WordBool; safecall; procedure Set_multiselect(const pVal:WordBool); safecall; function Get_readOnly : WordBool; safecall; procedure Set_readOnly(const pVal:WordBool); safecall; function Get_foregroundColor : WideString; safecall; procedure Set_foregroundColor(const pVal:WideString); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_fontSize : Integer; safecall; procedure Set_fontSize(const pVal:Integer); safecall; function Get_fontStyle : WideString; safecall; procedure Set_fontStyle(const pVal:WideString); safecall; function Get_fontFace : WideString; safecall; procedure Set_fontFace(const pVal:WideString); safecall; function Get_itemCount : Integer; safecall; function Get_firstVisibleItem : Integer; safecall; procedure Set_firstVisibleItem(const pVal:Integer); safecall; procedure Set_popUp(const Param1:WordBool); safecall; function Get_focusItem : Integer; safecall; procedure Set_focusItem(const pVal:Integer); safecall; function Get_border : WordBool; safecall; procedure Set_border(const pVal:WordBool); safecall; // getItem : method getItem function getItem(nPos:Integer):WideString;safecall; // insertItem : method insertItem procedure insertItem(nPos:Integer;newVal:WideString);safecall; // appendItem : method appendItem procedure appendItem(newVal:WideString);safecall; // replaceItem : method replaceItem procedure replaceItem(nPos:Integer;newVal:WideString);safecall; // deleteItem : method deleteItem procedure deleteItem(nPos:Integer);safecall; // deleteAll : method deleteAll procedure deleteAll;safecall; // findItem : method findItem function findItem(nStartIndex:Integer;newVal:WideString):Integer;safecall; // getNextSelectedItem : method getNextSelectedItem function getNextSelectedItem(nStartIndex:Integer):Integer;safecall; // setSelectedState : method setSelectedState procedure setSelectedState(nPos:Integer;vbSelected:WordBool);safecall; // show : method show procedure show;safecall; // dismiss : method dismiss procedure dismiss;safecall; // selectedItem : property selectedItem:Integer read Get_selectedItem write Set_selectedItem; // sorted : property sorted:WordBool read Get_sorted write Set_sorted; // multiselect : property multiselect:WordBool read Get_multiselect write Set_multiselect; // readOnly : property readOnly:WordBool read Get_readOnly write Set_readOnly; // foregroundColor : property foregroundColor:WideString read Get_foregroundColor write Set_foregroundColor; // backgroundColor : property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // fontSize : property fontSize:Integer read Get_fontSize write Set_fontSize; // fontStyle : property fontStyle:WideString read Get_fontStyle write Set_fontStyle; // fontFace : property fontFace:WideString read Get_fontFace write Set_fontFace; // itemCount : property itemCount:Integer read Get_itemCount; // firstVisibleItem : property firstVisibleItem:Integer read Get_firstVisibleItem write Set_firstVisibleItem; // popUp : property popUp:WordBool write Set_popUp; // focusItem : property focusItem:Integer read Get_focusItem write Set_focusItem; // border : property border:WordBool read Get_border write Set_border; end; // IWMPListBoxCtrl : IWMPListBoxCtrl: Public interface for skin object model. IWMPListBoxCtrlDisp = dispinterface ['{FC1880CE-83B9-43A7-A066-C44CE8C82583}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getItem : method getItem function getItem(nPos:Integer):WideString;dispid 6111; // insertItem : method insertItem procedure insertItem(nPos:Integer;newVal:WideString);dispid 6112; // appendItem : method appendItem procedure appendItem(newVal:WideString);dispid 6113; // replaceItem : method replaceItem procedure replaceItem(nPos:Integer;newVal:WideString);dispid 6114; // deleteItem : method deleteItem procedure deleteItem(nPos:Integer);dispid 6115; // deleteAll : method deleteAll procedure deleteAll;dispid 6116; // findItem : method findItem function findItem(nStartIndex:Integer;newVal:WideString):Integer;dispid 6117; // getNextSelectedItem : method getNextSelectedItem function getNextSelectedItem(nStartIndex:Integer):Integer;dispid 6118; // setSelectedState : method setSelectedState procedure setSelectedState(nPos:Integer;vbSelected:WordBool);dispid 6122; // show : method show procedure show;dispid 6123; // dismiss : method dismiss procedure dismiss;dispid 6124; // selectedItem : property selectedItem:Integer dispid 6108; // sorted : property sorted:WordBool dispid 6100; // multiselect : property multiselect:WordBool dispid 6101; // readOnly : property readOnly:WordBool dispid 6102; // foregroundColor : property foregroundColor:WideString dispid 6103; // backgroundColor : property backgroundColor:WideString dispid 6104; // fontSize : property fontSize:Integer dispid 6105; // fontStyle : property fontStyle:WideString dispid 6106; // fontFace : property fontFace:WideString dispid 6107; // itemCount : property itemCount:Integer readonly dispid 6109; // firstVisibleItem : property firstVisibleItem:Integer dispid 6110; // popUp : property popUp:WordBool writeonly dispid 6120; // focusItem : property focusItem:Integer dispid 6121; // border : property border:WordBool dispid 6125; end; // IWMPListBoxItem : IWMPListBoxItem: Public interface for skin object model. IWMPListBoxItem = interface(IDispatch) ['{D255DFB8-C22A-42CF-B8B7-F15D7BCF65D6}'] procedure Set_value(const Param1:WideString); safecall; // value : property value property value:WideString write Set_value; end; // IWMPListBoxItem : IWMPListBoxItem: Public interface for skin object model. IWMPListBoxItemDisp = dispinterface ['{D255DFB8-C22A-42CF-B8B7-F15D7BCF65D6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // value : property value property value:WideString writeonly dispid 6119; end; // IWMPPlaylistCtrlColumn : IWMPPlaylistCtrlColumn: Public interface for skin object model. IWMPPlaylistCtrlColumn = interface(IDispatch) ['{63D9D30F-AE4C-4678-8CA8-5720F4FE4419}'] function Get_columnName : WideString; safecall; procedure Set_columnName(const pVal:WideString); safecall; function Get_columnID : WideString; safecall; procedure Set_columnID(const pVal:WideString); safecall; function Get_columnResizeMode : WideString; safecall; procedure Set_columnResizeMode(const pVal:WideString); safecall; function Get_columnWidth : Integer; safecall; procedure Set_columnWidth(const pVal:Integer); safecall; // columnName : property columnName property columnName:WideString read Get_columnName write Set_columnName; // columnID : property columnID property columnID:WideString read Get_columnID write Set_columnID; // columnResizeMode : property columnResizeMode property columnResizeMode:WideString read Get_columnResizeMode write Set_columnResizeMode; // columnWidth : property columnWidth property columnWidth:Integer read Get_columnWidth write Set_columnWidth; end; // IWMPPlaylistCtrlColumn : IWMPPlaylistCtrlColumn: Public interface for skin object model. IWMPPlaylistCtrlColumnDisp = dispinterface ['{63D9D30F-AE4C-4678-8CA8-5720F4FE4419}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // columnName : property columnName property columnName:WideString dispid 5670; // columnID : property columnID property columnID:WideString dispid 5671; // columnResizeMode : property columnResizeMode property columnResizeMode:WideString dispid 5672; // columnWidth : property columnWidth property columnWidth:Integer dispid 5673; end; // IWMPSliderCtrlEvents : IWMPSliderCtrlEvents: Public interface for skin object model. IWMPSliderCtrlEvents = dispinterface ['{CDAC14D2-8BE4-11D3-BB48-00A0C93CA73A}'] // ondragbegin : event ondragbegin function ondragbegin:HResult;dispid 5430; // ondragend : event ondragend function ondragend:HResult;dispid 5431; // onpositionchange : event onpositionchange function onpositionchange:HResult;dispid 5432; end; // IWMPSliderCtrl : IWMPSliderCtrl: Public interface for skin object model. IWMPSliderCtrl = interface(IDispatch) ['{F2BF2C8F-405F-11D3-BB39-00A0C93CA73A}'] function Get_direction : WideString; safecall; procedure Set_direction(const pVal:WideString); safecall; function Get_slide : WordBool; safecall; procedure Set_slide(const pVal:WordBool); safecall; function Get_tiled : WordBool; safecall; procedure Set_tiled(const pVal:WordBool); safecall; function Get_foregroundColor : WideString; safecall; procedure Set_foregroundColor(const pVal:WideString); safecall; function Get_foregroundEndColor : WideString; safecall; procedure Set_foregroundEndColor(const pVal:WideString); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_backgroundEndColor : WideString; safecall; procedure Set_backgroundEndColor(const pVal:WideString); safecall; function Get_disabledColor : WideString; safecall; procedure Set_disabledColor(const pVal:WideString); safecall; function Get_transparencyColor : WideString; safecall; procedure Set_transparencyColor(const pVal:WideString); safecall; function Get_foregroundImage : WideString; safecall; procedure Set_foregroundImage(const pVal:WideString); safecall; function Get_backgroundImage : WideString; safecall; procedure Set_backgroundImage(const pVal:WideString); safecall; function Get_backgroundHoverImage : WideString; safecall; procedure Set_backgroundHoverImage(const pVal:WideString); safecall; function Get_disabledImage : WideString; safecall; procedure Set_disabledImage(const pVal:WideString); safecall; function Get_thumbImage : WideString; safecall; procedure Set_thumbImage(const pVal:WideString); safecall; function Get_thumbHoverImage : WideString; safecall; procedure Set_thumbHoverImage(const pVal:WideString); safecall; function Get_thumbDownImage : WideString; safecall; procedure Set_thumbDownImage(const pVal:WideString); safecall; function Get_thumbDisabledImage : WideString; safecall; procedure Set_thumbDisabledImage(const pVal:WideString); safecall; function Get_min : Single; safecall; procedure Set_min(const pVal:Single); safecall; function Get_max : Single; safecall; procedure Set_max(const pVal:Single); safecall; function Get_value : Single; safecall; procedure Set_value(const pVal:Single); safecall; function Get_toolTip : WideString; safecall; procedure Set_toolTip(const pVal:WideString); safecall; function Get_cursor : WideString; safecall; procedure Set_cursor(const pVal:WideString); safecall; function Get_borderSize : SYSINT; safecall; procedure Set_borderSize(const pVal:SYSINT); safecall; function Get_foregroundHoverImage : WideString; safecall; procedure Set_foregroundHoverImage(const pVal:WideString); safecall; function Get_foregroundProgress : Single; safecall; procedure Set_foregroundProgress(const pVal:Single); safecall; function Get_useForegroundProgress : WordBool; safecall; procedure Set_useForegroundProgress(const pVal:WordBool); safecall; // direction : property direction property direction:WideString read Get_direction write Set_direction; // slide : property slide property slide:WordBool read Get_slide write Set_slide; // tiled : property tiled property tiled:WordBool read Get_tiled write Set_tiled; // foregroundColor : property foregroundColor property foregroundColor:WideString read Get_foregroundColor write Set_foregroundColor; // foregroundEndColor : property foregroundEndColor property foregroundEndColor:WideString read Get_foregroundEndColor write Set_foregroundEndColor; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // backgroundEndColor : property backgroundEndColor property backgroundEndColor:WideString read Get_backgroundEndColor write Set_backgroundEndColor; // disabledColor : property disabledColor property disabledColor:WideString read Get_disabledColor write Set_disabledColor; // transparencyColor : property transparencyColor property transparencyColor:WideString read Get_transparencyColor write Set_transparencyColor; // foregroundImage : property foregroundImage property foregroundImage:WideString read Get_foregroundImage write Set_foregroundImage; // backgroundImage : property backgroundImage property backgroundImage:WideString read Get_backgroundImage write Set_backgroundImage; // backgroundHoverImage : property backgroundHoverImage property backgroundHoverImage:WideString read Get_backgroundHoverImage write Set_backgroundHoverImage; // disabledImage : property disabledImage property disabledImage:WideString read Get_disabledImage write Set_disabledImage; // thumbImage : property thumbImage property thumbImage:WideString read Get_thumbImage write Set_thumbImage; // thumbHoverImage : property thumbHoverImage property thumbHoverImage:WideString read Get_thumbHoverImage write Set_thumbHoverImage; // thumbDownImage : property thumbDownImage property thumbDownImage:WideString read Get_thumbDownImage write Set_thumbDownImage; // thumbDisabledImage : property thumbDisabledImage property thumbDisabledImage:WideString read Get_thumbDisabledImage write Set_thumbDisabledImage; // min : property min property min:Single read Get_min write Set_min; // max : property max property max:Single read Get_max write Set_max; // value : property value property value:Single read Get_value write Set_value; // toolTip : property toolTip property toolTip:WideString read Get_toolTip write Set_toolTip; // cursor : property cursor property cursor:WideString read Get_cursor write Set_cursor; // borderSize : property borderSize property borderSize:SYSINT read Get_borderSize write Set_borderSize; // foregroundHoverImage : property foregroundHoverImage property foregroundHoverImage:WideString read Get_foregroundHoverImage write Set_foregroundHoverImage; // foregroundProgress : property foregroundValue property foregroundProgress:Single read Get_foregroundProgress write Set_foregroundProgress; // useForegroundProgress : property useForegroundValue property useForegroundProgress:WordBool read Get_useForegroundProgress write Set_useForegroundProgress; end; // IWMPSliderCtrl : IWMPSliderCtrl: Public interface for skin object model. IWMPSliderCtrlDisp = dispinterface ['{F2BF2C8F-405F-11D3-BB39-00A0C93CA73A}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // direction : property direction property direction:WideString dispid 5400; // slide : property slide property slide:WordBool dispid 5402; // tiled : property tiled property tiled:WordBool dispid 5403; // foregroundColor : property foregroundColor property foregroundColor:WideString dispid 5404; // foregroundEndColor : property foregroundEndColor property foregroundEndColor:WideString dispid 5405; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 5406; // backgroundEndColor : property backgroundEndColor property backgroundEndColor:WideString dispid 5407; // disabledColor : property disabledColor property disabledColor:WideString dispid 5408; // transparencyColor : property transparencyColor property transparencyColor:WideString dispid 5409; // foregroundImage : property foregroundImage property foregroundImage:WideString dispid 5410; // backgroundImage : property backgroundImage property backgroundImage:WideString dispid 5411; // backgroundHoverImage : property backgroundHoverImage property backgroundHoverImage:WideString dispid 5412; // disabledImage : property disabledImage property disabledImage:WideString dispid 5413; // thumbImage : property thumbImage property thumbImage:WideString dispid 5414; // thumbHoverImage : property thumbHoverImage property thumbHoverImage:WideString dispid 5415; // thumbDownImage : property thumbDownImage property thumbDownImage:WideString dispid 5416; // thumbDisabledImage : property thumbDisabledImage property thumbDisabledImage:WideString dispid 5417; // min : property min property min:Single dispid 5418; // max : property max property max:Single dispid 5419; // value : property value property value:Single dispid 5420; // toolTip : property toolTip property toolTip:WideString dispid 5421; // cursor : property cursor property cursor:WideString dispid 5422; // borderSize : property borderSize property borderSize:SYSINT dispid 5423; // foregroundHoverImage : property foregroundHoverImage property foregroundHoverImage:WideString dispid 5424; // foregroundProgress : property foregroundValue property foregroundProgress:Single dispid 5425; // useForegroundProgress : property useForegroundValue property useForegroundProgress:WordBool dispid 5426; end; // IWMPVideoCtrlEvents : IWMPVideoCtrlEvents: Public interface for skin object model. IWMPVideoCtrlEvents = dispinterface ['{A85C0477-714C-4A06-B9F6-7C8CA38B45DC}'] // onvideostart : event onvideostart function onvideostart:HResult;dispid 5720; // onvideoend : event onvideostart function onvideoend:HResult;dispid 5721; end; // IWMPVideoCtrl : IWMPVideoCtrl: Public interface for skin object model. IWMPVideoCtrl = interface(IDispatch) ['{61CECF10-FC3A-11D2-A1CD-005004602752}'] procedure Set_windowless(const pbClipped:WordBool); safecall; function Get_windowless : WordBool; safecall; procedure Set_cursor(const pbstrCursor:WideString); safecall; function Get_cursor : WideString; safecall; procedure Set_backgroundColor(const pbstrColor:WideString); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_maintainAspectRatio(const pbMaintainAspectRatio:WordBool); safecall; function Get_maintainAspectRatio : WordBool; safecall; procedure Set_toolTip(const bstrToolTip:WideString); safecall; function Get_toolTip : WideString; safecall; function Get_fullScreen : WordBool; safecall; procedure Set_fullScreen(const pbFullScreen:WordBool); safecall; procedure Set_shrinkToFit(const pbShrinkToFit:WordBool); safecall; function Get_shrinkToFit : WordBool; safecall; procedure Set_stretchToFit(const pbStretchToFit:WordBool); safecall; function Get_stretchToFit : WordBool; safecall; procedure Set_zoom(const pzoom:Integer); safecall; function Get_zoom : Integer; safecall; // windowless : property windowless:WordBool read Get_windowless write Set_windowless; // cursor : property cursor:WideString read Get_cursor write Set_cursor; // backgroundColor : property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // maintainAspectRatio : property maintainAspectRatio:WordBool read Get_maintainAspectRatio write Set_maintainAspectRatio; // toolTip : property toolTip:WideString read Get_toolTip write Set_toolTip; // fullScreen : property fullScreen:WordBool read Get_fullScreen write Set_fullScreen; // shrinkToFit : property shrinkToFit:WordBool read Get_shrinkToFit write Set_shrinkToFit; // stretchToFit : property stretchToFit:WordBool read Get_stretchToFit write Set_stretchToFit; // zoom : property zoom:Integer read Get_zoom write Set_zoom; end; // IWMPVideoCtrl : IWMPVideoCtrl: Public interface for skin object model. IWMPVideoCtrlDisp = dispinterface ['{61CECF10-FC3A-11D2-A1CD-005004602752}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // windowless : property windowless:WordBool dispid 5700; // cursor : property cursor:WideString dispid 5701; // backgroundColor : property backgroundColor:WideString dispid 5702; // maintainAspectRatio : property maintainAspectRatio:WordBool dispid 5704; // toolTip : property toolTip:WideString dispid 5706; // fullScreen : property fullScreen:WordBool dispid 5707; // shrinkToFit : property shrinkToFit:WordBool dispid 5703; // stretchToFit : property stretchToFit:WordBool dispid 5708; // zoom : property zoom:Integer dispid 5709; end; // IWMPEffectsCtrl : IWMPEffectsCtrl: Public interface for skin object model. IWMPEffectsCtrl = interface(IDispatch) ['{A9EFAB80-0A60-4C3F-BBD1-4558DD2A9769}'] function Get_windowed : WordBool; safecall; procedure Set_windowed(const pVal:WordBool); safecall; function Get_allowAll : WordBool; safecall; procedure Set_allowAll(const pVal:WordBool); safecall; procedure Set_currentEffectType(const pVal:WideString); safecall; function Get_currentEffectType : WideString; safecall; function Get_currentEffectTitle : WideString; safecall; // next : method next procedure next;safecall; // previous : method previous procedure previous;safecall; // settings : method settings procedure settings;safecall; function Get_currentEffect : IDispatch; safecall; procedure Set_currentEffect(const p:IDispatch); safecall; // nextEffect : method nextEffect procedure nextEffect;safecall; // previousEffect : method previousEffect procedure previousEffect;safecall; // nextPreset : method nextPreset procedure nextPreset;safecall; // previousPreset : method previousPreset procedure previousPreset;safecall; function Get_currentPreset : Integer; safecall; procedure Set_currentPreset(const pVal:Integer); safecall; function Get_currentPresetTitle : WideString; safecall; function Get_currentEffectPresetCount : Integer; safecall; function Get_fullScreen : WordBool; safecall; procedure Set_fullScreen(const pbFullScreen:WordBool); safecall; function Get_effectCanGoFullScreen : WordBool; safecall; function Get_effectHasPropertyPage : WordBool; safecall; function Get_effectCount : Integer; safecall; function Get_effectTitle(index:Integer) : WideString; safecall; function Get_effectType(index:Integer) : WideString; safecall; // windowed : property windowed property windowed:WordBool read Get_windowed write Set_windowed; // allowAll : property allowAll property allowAll:WordBool read Get_allowAll write Set_allowAll; // currentEffectType : property currentEffectType property currentEffectType:WideString read Get_currentEffectType write Set_currentEffectType; // currentEffectTitle : property currentEffectTitle property currentEffectTitle:WideString read Get_currentEffectTitle; // currentEffect : property currentEffect property currentEffect:IDispatch read Get_currentEffect write Set_currentEffect; // currentPreset : property currentPreset property currentPreset:Integer read Get_currentPreset write Set_currentPreset; // currentPresetTitle : property currentPresetTitle property currentPresetTitle:WideString read Get_currentPresetTitle; // currentEffectPresetCount : property currentEffectPresetCount property currentEffectPresetCount:Integer read Get_currentEffectPresetCount; // fullScreen : property fullScreen property fullScreen:WordBool read Get_fullScreen write Set_fullScreen; // effectCanGoFullScreen : property canGoFullScreen property effectCanGoFullScreen:WordBool read Get_effectCanGoFullScreen; // effectHasPropertyPage : property canGoFullScreen property effectHasPropertyPage:WordBool read Get_effectHasPropertyPage; // effectCount : property effectCount property effectCount:Integer read Get_effectCount; // effectTitle : property effectTitle(index) property effectTitle[index:Integer]:WideString read Get_effectTitle; // effectType : property effectType(index) property effectType[index:Integer]:WideString read Get_effectType; end; // IWMPEffectsCtrl : IWMPEffectsCtrl: Public interface for skin object model. IWMPEffectsCtrlDisp = dispinterface ['{A9EFAB80-0A60-4C3F-BBD1-4558DD2A9769}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // next : method next procedure next;dispid 5502; // previous : method previous procedure previous;dispid 5503; // settings : method settings procedure settings;dispid 5504; // nextEffect : method nextEffect procedure nextEffect;dispid 5509; // previousEffect : method previousEffect procedure previousEffect;dispid 5510; // nextPreset : method nextPreset procedure nextPreset;dispid 5511; // previousPreset : method previousPreset procedure previousPreset;dispid 5512; // windowed : property windowed property windowed:WordBool dispid 5500; // allowAll : property allowAll property allowAll:WordBool dispid 5501; // currentEffectType : property currentEffectType property currentEffectType:WideString dispid 5507; // currentEffectTitle : property currentEffectTitle property currentEffectTitle:WideString readonly dispid 5506; // currentEffect : property currentEffect property currentEffect:IDispatch dispid 5505; // currentPreset : property currentPreset property currentPreset:Integer dispid 5513; // currentPresetTitle : property currentPresetTitle property currentPresetTitle:WideString readonly dispid 5514; // currentEffectPresetCount : property currentEffectPresetCount property currentEffectPresetCount:Integer readonly dispid 5515; // fullScreen : property fullScreen property fullScreen:WordBool dispid 5516; // effectCanGoFullScreen : property canGoFullScreen property effectCanGoFullScreen:WordBool readonly dispid 5517; // effectHasPropertyPage : property canGoFullScreen property effectHasPropertyPage:WordBool readonly dispid 5518; // effectCount : property effectCount property effectCount:Integer readonly dispid 5520; // effectTitle : property effectTitle(index) property effectTitle[index:Integer]:WideString readonly dispid 5521; // effectType : property effectType(index) property effectType[index:Integer]:WideString readonly dispid 5522; end; // IWMPEqualizerSettingsCtrl : IWMPEqualizerSettingsCtrl: Public interface for skin object model. IWMPEqualizerSettingsCtrl = interface(IDispatch) ['{2BD3716F-A914-49FB-8655-996D5F495498}'] function Get_bypass : WordBool; safecall; procedure Set_bypass(const pVal:WordBool); safecall; function Get_gainLevel1 : Single; safecall; procedure Set_gainLevel1(const pflLevel:Single); safecall; function Get_gainLevel2 : Single; safecall; procedure Set_gainLevel2(const pflLevel:Single); safecall; function Get_gainLevel3 : Single; safecall; procedure Set_gainLevel3(const pflLevel:Single); safecall; function Get_gainLevel4 : Single; safecall; procedure Set_gainLevel4(const pflLevel:Single); safecall; function Get_gainLevel5 : Single; safecall; procedure Set_gainLevel5(const pflLevel:Single); safecall; function Get_gainLevel6 : Single; safecall; procedure Set_gainLevel6(const pflLevel:Single); safecall; function Get_gainLevel7 : Single; safecall; procedure Set_gainLevel7(const pflLevel:Single); safecall; function Get_gainLevel8 : Single; safecall; procedure Set_gainLevel8(const pflLevel:Single); safecall; function Get_gainLevel9 : Single; safecall; procedure Set_gainLevel9(const pflLevel:Single); safecall; function Get_gainLevel10 : Single; safecall; procedure Set_gainLevel10(const pflLevel:Single); safecall; function Get_gainLevels(iIndex:Integer) : Single; safecall; procedure Set_gainLevels(const iIndex:Integer; const pargainLevels:Single); safecall; // reset_ : method reset procedure reset_;safecall; function Get_bands : Integer; safecall; // nextPreset : method nextPreset procedure nextPreset;safecall; // previousPreset : method previousPreset procedure previousPreset;safecall; function Get_currentPreset : Integer; safecall; procedure Set_currentPreset(const pVal:Integer); safecall; function Get_currentPresetTitle : WideString; safecall; function Get_presetCount : Integer; safecall; function Get_enhancedAudio : WordBool; safecall; procedure Set_enhancedAudio(const pfVal:WordBool); safecall; function Get_speakerSize : Integer; safecall; procedure Set_speakerSize(const plVal:Integer); safecall; function Get_currentSpeakerName : WideString; safecall; function Get_truBassLevel : Integer; safecall; procedure Set_truBassLevel(const plTruBassLevel:Integer); safecall; function Get_wowLevel : Integer; safecall; procedure Set_wowLevel(const plWowLevel:Integer); safecall; function Get_splineTension : Single; safecall; procedure Set_splineTension(const pflSplineTension:Single); safecall; function Get_enableSplineTension : WordBool; safecall; procedure Set_enableSplineTension(const pfEnableSplineTension:WordBool); safecall; function Get_presetTitle(iIndex:Integer) : WideString; safecall; function Get_normalization : WordBool; safecall; procedure Set_normalization(const pfVal:WordBool); safecall; function Get_normalizationAverage : Single; safecall; function Get_normalizationPeak : Single; safecall; function Get_crossFade : WordBool; safecall; procedure Set_crossFade(const pfVal:WordBool); safecall; function Get_crossFadeWindow : Integer; safecall; procedure Set_crossFadeWindow(const plWindow:Integer); safecall; // bypass : property bypass property bypass:WordBool read Get_bypass write Set_bypass; // gainLevel1 : property gainLevel1 property gainLevel1:Single read Get_gainLevel1 write Set_gainLevel1; // gainLevel2 : property gainLevel2 property gainLevel2:Single read Get_gainLevel2 write Set_gainLevel2; // gainLevel3 : property gainLevel3 property gainLevel3:Single read Get_gainLevel3 write Set_gainLevel3; // gainLevel4 : property gainLevel4 property gainLevel4:Single read Get_gainLevel4 write Set_gainLevel4; // gainLevel5 : property gainLevel5 property gainLevel5:Single read Get_gainLevel5 write Set_gainLevel5; // gainLevel6 : property gainLevel6 property gainLevel6:Single read Get_gainLevel6 write Set_gainLevel6; // gainLevel7 : property gainLevel7 property gainLevel7:Single read Get_gainLevel7 write Set_gainLevel7; // gainLevel8 : property gainLevel8 property gainLevel8:Single read Get_gainLevel8 write Set_gainLevel8; // gainLevel9 : property gainLevel9 property gainLevel9:Single read Get_gainLevel9 write Set_gainLevel9; // gainLevel10 : property gainLevel10 property gainLevel10:Single read Get_gainLevel10 write Set_gainLevel10; // gainLevels : property gainLevels property gainLevels[iIndex:Integer]:Single read Get_gainLevels write Set_gainLevels; // bands : property bands:Integer read Get_bands; // currentPreset : property currentPreset property currentPreset:Integer read Get_currentPreset write Set_currentPreset; // currentPresetTitle : property currentPresetTitle property currentPresetTitle:WideString read Get_currentPresetTitle; // presetCount : property presetCount property presetCount:Integer read Get_presetCount; // enhancedAudio : property enhancedAudio property enhancedAudio:WordBool read Get_enhancedAudio write Set_enhancedAudio; // speakerSize : property speakerSize property speakerSize:Integer read Get_speakerSize write Set_speakerSize; // currentSpeakerName : property currentSpeakerName property currentSpeakerName:WideString read Get_currentSpeakerName; // truBassLevel : property truBassLevel property truBassLevel:Integer read Get_truBassLevel write Set_truBassLevel; // wowLevel : property wowLevel property wowLevel:Integer read Get_wowLevel write Set_wowLevel; // splineTension : property splineTension property splineTension:Single read Get_splineTension write Set_splineTension; // enableSplineTension : property enableSplineTension property enableSplineTension:WordBool read Get_enableSplineTension write Set_enableSplineTension; // presetTitle : property presetTitle property presetTitle[iIndex:Integer]:WideString read Get_presetTitle; // normalization : property normalization property normalization:WordBool read Get_normalization write Set_normalization; // normalizationAverage : property normalizationAverage property normalizationAverage:Single read Get_normalizationAverage; // normalizationPeak : property normalizationPeak property normalizationPeak:Single read Get_normalizationPeak; // crossFade : property crossFade property crossFade:WordBool read Get_crossFade write Set_crossFade; // crossFadeWindow : property crossFadeWindow property crossFadeWindow:Integer read Get_crossFadeWindow write Set_crossFadeWindow; end; // IWMPEqualizerSettingsCtrl : IWMPEqualizerSettingsCtrl: Public interface for skin object model. IWMPEqualizerSettingsCtrlDisp = dispinterface ['{2BD3716F-A914-49FB-8655-996D5F495498}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // reset_ : method reset procedure reset_;dispid 5814; // nextPreset : method nextPreset procedure nextPreset;dispid 5816; // previousPreset : method previousPreset procedure previousPreset;dispid 5817; // bypass : property bypass property bypass:WordBool dispid 5800; // gainLevel1 : property gainLevel1 property gainLevel1:Single dispid 5804; // gainLevel2 : property gainLevel2 property gainLevel2:Single dispid 5805; // gainLevel3 : property gainLevel3 property gainLevel3:Single dispid 5806; // gainLevel4 : property gainLevel4 property gainLevel4:Single dispid 5807; // gainLevel5 : property gainLevel5 property gainLevel5:Single dispid 5808; // gainLevel6 : property gainLevel6 property gainLevel6:Single dispid 5809; // gainLevel7 : property gainLevel7 property gainLevel7:Single dispid 5810; // gainLevel8 : property gainLevel8 property gainLevel8:Single dispid 5811; // gainLevel9 : property gainLevel9 property gainLevel9:Single dispid 5812; // gainLevel10 : property gainLevel10 property gainLevel10:Single dispid 5813; // gainLevels : property gainLevels property gainLevels[iIndex:Integer]:Single dispid 5815; // bands : property bands:Integer readonly dispid 5801; // currentPreset : property currentPreset property currentPreset:Integer dispid 5818; // currentPresetTitle : property currentPresetTitle property currentPresetTitle:WideString readonly dispid 5819; // presetCount : property presetCount property presetCount:Integer readonly dispid 5820; // enhancedAudio : property enhancedAudio property enhancedAudio:WordBool dispid 5821; // speakerSize : property speakerSize property speakerSize:Integer dispid 5822; // currentSpeakerName : property currentSpeakerName property currentSpeakerName:WideString readonly dispid 5823; // truBassLevel : property truBassLevel property truBassLevel:Integer dispid 5824; // wowLevel : property wowLevel property wowLevel:Integer dispid 5825; // splineTension : property splineTension property splineTension:Single dispid 5827; // enableSplineTension : property enableSplineTension property enableSplineTension:WordBool dispid 5826; // presetTitle : property presetTitle property presetTitle[iIndex:Integer]:WideString readonly dispid 5828; // normalization : property normalization property normalization:WordBool dispid 5829; // normalizationAverage : property normalizationAverage property normalizationAverage:Single readonly dispid 5830; // normalizationPeak : property normalizationPeak property normalizationPeak:Single readonly dispid 5831; // crossFade : property crossFade property crossFade:WordBool dispid 5832; // crossFadeWindow : property crossFadeWindow property crossFadeWindow:Integer dispid 5833; end; // IWMPVideoSettingsCtrl : IWMPVideoSettingsCtrl: Public interface for skin object model. IWMPVideoSettingsCtrl = interface(IDispatch) ['{07EC23DA-EF73-4BDE-A40F-F269E0B7AFD6}'] function Get_brightness : Integer; safecall; procedure Set_brightness(const pVal:Integer); safecall; function Get_contrast : Integer; safecall; procedure Set_contrast(const pVal:Integer); safecall; function Get_hue : Integer; safecall; procedure Set_hue(const pVal:Integer); safecall; function Get_saturation : Integer; safecall; procedure Set_saturation(const pVal:Integer); safecall; // reset_ : method reset procedure reset_;safecall; // brightness : property brightness property brightness:Integer read Get_brightness write Set_brightness; // contrast : property contrast property contrast:Integer read Get_contrast write Set_contrast; // hue : property hue property hue:Integer read Get_hue write Set_hue; // saturation : property saturation property saturation:Integer read Get_saturation write Set_saturation; end; // IWMPVideoSettingsCtrl : IWMPVideoSettingsCtrl: Public interface for skin object model. IWMPVideoSettingsCtrlDisp = dispinterface ['{07EC23DA-EF73-4BDE-A40F-F269E0B7AFD6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // reset_ : method reset procedure reset_;dispid 5904; // brightness : property brightness property brightness:Integer dispid 5900; // contrast : property contrast property contrast:Integer dispid 5901; // hue : property hue property hue:Integer dispid 5902; // saturation : property saturation property saturation:Integer dispid 5903; end; // IWMPLibraryTreeCtrl : IWMPLibraryTreeCtrl: Not Public. Internal interface used by Windows Media Player. IWMPLibraryTreeCtrl = interface(IDispatch) ['{B738FCAE-F089-45DF-AED6-034B9E7DB632}'] function Get_dropDownVisible : WordBool; safecall; procedure Set_dropDownVisible(const pVal:WordBool); safecall; function Get_foregroundColor : WideString; safecall; procedure Set_foregroundColor(const pVal:WideString); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_fontSize : Integer; safecall; procedure Set_fontSize(const pVal:Integer); safecall; function Get_fontStyle : WideString; safecall; procedure Set_fontStyle(const pVal:WideString); safecall; function Get_fontFace : WideString; safecall; procedure Set_fontFace(const pVal:WideString); safecall; function Get_filter : WideString; safecall; procedure Set_filter(const pVal:WideString); safecall; function Get_expandState : WideString; safecall; procedure Set_expandState(const pVal:WideString); safecall; function Get_Playlist : IWMPPlaylist; safecall; procedure Set_Playlist(const ppPlaylist:IWMPPlaylist); safecall; function Get_selectedPlaylist : IWMPPlaylist; safecall; function Get_selectedMedia : IWMPMedia; safecall; // dropDownVisible : property dropDownVisible property dropDownVisible:WordBool read Get_dropDownVisible write Set_dropDownVisible; // foregroundColor : property foregroundColor property foregroundColor:WideString read Get_foregroundColor write Set_foregroundColor; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // fontSize : property fontSize property fontSize:Integer read Get_fontSize write Set_fontSize; // fontStyle : property fontStyle property fontStyle:WideString read Get_fontStyle write Set_fontStyle; // fontFace : property fontFace property fontFace:WideString read Get_fontFace write Set_fontFace; // filter : property filter property filter:WideString read Get_filter write Set_filter; // expandState : property expandState property expandState:WideString read Get_expandState write Set_expandState; // Playlist : property playlist property Playlist:IWMPPlaylist read Get_Playlist write Set_Playlist; // selectedPlaylist : property selectedPlaylist property selectedPlaylist:IWMPPlaylist read Get_selectedPlaylist; // selectedMedia : property selectedMedia property selectedMedia:IWMPMedia read Get_selectedMedia; end; // IWMPLibraryTreeCtrl : IWMPLibraryTreeCtrl: Not Public. Internal interface used by Windows Media Player. IWMPLibraryTreeCtrlDisp = dispinterface ['{B738FCAE-F089-45DF-AED6-034B9E7DB632}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // dropDownVisible : property dropDownVisible property dropDownVisible:WordBool dispid 6401; // foregroundColor : property foregroundColor property foregroundColor:WideString dispid 6402; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 6403; // fontSize : property fontSize property fontSize:Integer dispid 6404; // fontStyle : property fontStyle property fontStyle:WideString dispid 6405; // fontFace : property fontFace property fontFace:WideString dispid 6406; // filter : property filter property filter:WideString dispid 6407; // expandState : property expandState property expandState:WideString dispid 6408; // Playlist : property playlist property Playlist:IWMPPlaylist dispid 6409; // selectedPlaylist : property selectedPlaylist property selectedPlaylist:IWMPPlaylist readonly dispid 6410; // selectedMedia : property selectedMedia property selectedMedia:IWMPMedia readonly dispid 6411; end; // IWMPEditCtrl : IWMPEditCtrl: Public interface for skin object model. IWMPEditCtrl = interface(IDispatch) ['{70E1217C-C617-4CFD-BD8A-69CA2043E70B}'] function Get_value : WideString; safecall; procedure Set_value(const pVal:WideString); safecall; function Get_border : WordBool; safecall; procedure Set_border(const pVal:WordBool); safecall; function Get_justification : WideString; safecall; procedure Set_justification(const pVal:WideString); safecall; function Get_editStyle : WideString; safecall; procedure Set_editStyle(const pVal:WideString); safecall; function Get_wordWrap : WordBool; safecall; procedure Set_wordWrap(const pVal:WordBool); safecall; function Get_readOnly : WordBool; safecall; procedure Set_readOnly(const pVal:WordBool); safecall; function Get_foregroundColor : WideString; safecall; procedure Set_foregroundColor(const pVal:WideString); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_fontSize : Integer; safecall; procedure Set_fontSize(const pVal:Integer); safecall; function Get_fontStyle : WideString; safecall; procedure Set_fontStyle(const pVal:WideString); safecall; function Get_fontFace : WideString; safecall; procedure Set_fontFace(const pVal:WideString); safecall; function Get_textLimit : Integer; safecall; procedure Set_textLimit(const pVal:Integer); safecall; function Get_lineCount : Integer; safecall; // getLine : method getLine function getLine(nIndex:Integer):WideString;safecall; // getSelectionStart : method getSelectionStart function getSelectionStart:Integer;safecall; // getSelectionEnd : method getSelectionEnd function getSelectionEnd:Integer;safecall; // setSelection : method setSelection procedure setSelection(nStart:Integer;nEnd:Integer);safecall; // replaceSelection : method replaceSelection procedure replaceSelection(newVal:WideString);safecall; // getLineIndex : method getLineIndex function getLineIndex(nIndex:Integer):Integer;safecall; // getLineFromChar : method getLineFromChar function getLineFromChar(nPosition:Integer):Integer;safecall; // value : property value property value:WideString read Get_value write Set_value; // border : property border property border:WordBool read Get_border write Set_border; // justification : property justification property justification:WideString read Get_justification write Set_justification; // editStyle : property editStyle property editStyle:WideString read Get_editStyle write Set_editStyle; // wordWrap : property wordWrap property wordWrap:WordBool read Get_wordWrap write Set_wordWrap; // readOnly : property readOnly property readOnly:WordBool read Get_readOnly write Set_readOnly; // foregroundColor : property foregroundColor property foregroundColor:WideString read Get_foregroundColor write Set_foregroundColor; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // fontSize : property fontSize property fontSize:Integer read Get_fontSize write Set_fontSize; // fontStyle : property fontStyle property fontStyle:WideString read Get_fontStyle write Set_fontStyle; // fontFace : property fontFace property fontFace:WideString read Get_fontFace write Set_fontFace; // textLimit : property textLimit property textLimit:Integer read Get_textLimit write Set_textLimit; // lineCount : property lineCount property lineCount:Integer read Get_lineCount; end; // IWMPEditCtrl : IWMPEditCtrl: Public interface for skin object model. IWMPEditCtrlDisp = dispinterface ['{70E1217C-C617-4CFD-BD8A-69CA2043E70B}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getLine : method getLine function getLine(nIndex:Integer):WideString;dispid 6012; // getSelectionStart : method getSelectionStart function getSelectionStart:Integer;dispid 6013; // getSelectionEnd : method getSelectionEnd function getSelectionEnd:Integer;dispid 6014; // setSelection : method setSelection procedure setSelection(nStart:Integer;nEnd:Integer);dispid 6015; // replaceSelection : method replaceSelection procedure replaceSelection(newVal:WideString);dispid 6016; // getLineIndex : method getLineIndex function getLineIndex(nIndex:Integer):Integer;dispid 6017; // getLineFromChar : method getLineFromChar function getLineFromChar(nPosition:Integer):Integer;dispid 6018; // value : property value property value:WideString dispid 0; // border : property border property border:WordBool dispid 6000; // justification : property justification property justification:WideString dispid 6001; // editStyle : property editStyle property editStyle:WideString dispid 6002; // wordWrap : property wordWrap property wordWrap:WordBool dispid 6003; // readOnly : property readOnly property readOnly:WordBool dispid 6004; // foregroundColor : property foregroundColor property foregroundColor:WideString dispid 6005; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 6006; // fontSize : property fontSize property fontSize:Integer dispid 6007; // fontStyle : property fontStyle property fontStyle:WideString dispid 6008; // fontFace : property fontFace property fontFace:WideString dispid 6009; // textLimit : property textLimit property textLimit:Integer dispid 6010; // lineCount : property lineCount property lineCount:Integer readonly dispid 6011; end; // IWMPSkinList : IWMPSkinlist: interface for skin object model. IWMPSkinList = interface(IDispatch) ['{8CEA03A2-D0C5-4E97-9C38-A676A639A51D}'] // updateBasketColumns : property basketVisible procedure updateBasketColumns;safecall; // highContrastChange : property highContrastChange procedure highContrastChange;safecall; end; // IWMPSkinList : IWMPSkinlist: interface for skin object model. IWMPSkinListDisp = dispinterface ['{8CEA03A2-D0C5-4E97-9C38-A676A639A51D}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // updateBasketColumns : property basketVisible procedure updateBasketColumns;dispid 6050; // highContrastChange : property highContrastChange procedure highContrastChange;dispid 6051; end; // IWMPPluginUIHost : IWMPPluginUIHost: Not Public. Internal interface used by Windows Media Player. IWMPPluginUIHost = interface(IDispatch) ['{5D0AD945-289E-45C5-A9C6-F301F0152108}'] function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_objectID : WideString; safecall; procedure Set_objectID(const pVal:WideString); safecall; // getProperty : method getProperty function getProperty(bstrName:WideString):OleVariant;safecall; // setProperty : method setProperty procedure setProperty(bstrName:WideString;newVal:OleVariant);safecall; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // objectID : property objectID property objectID:WideString read Get_objectID write Set_objectID; end; // IWMPPluginUIHost : IWMPPluginUIHost: Not Public. Internal interface used by Windows Media Player. IWMPPluginUIHostDisp = dispinterface ['{5D0AD945-289E-45C5-A9C6-F301F0152108}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getProperty : method getProperty function getProperty(bstrName:WideString):OleVariant;dispid 6203; // setProperty : method setProperty procedure setProperty(bstrName:WideString;newVal:OleVariant);dispid 6204; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 6201; // objectID : property objectID property objectID:WideString dispid 6202; end; // IWMPMenuCtrl : IWMPMenuCtrl: Not Public. Internal interface used by Windows Media Player. IWMPMenuCtrl = interface(IDispatch) ['{158A7ADC-33DA-4039-A553-BDDBBE389F5C}'] // deleteAllItems : method deleteAllItems procedure deleteAllItems;safecall; // appendItem : method appendItem procedure appendItem(nID:Integer;bstrItem:WideString);safecall; // appendSeparator : method appendSeparator procedure appendSeparator;safecall; // enableItem : property enableItem procedure enableItem(nID:Integer;newVal:WordBool);safecall; // checkItem : property checkItem procedure checkItem(nID:Integer;newVal:WordBool);safecall; // checkRadioItem : property checkRadioItem procedure checkRadioItem(nID:Integer;newVal:WordBool);safecall; function Get_showFlags : Integer; safecall; procedure Set_showFlags(const pVal:Integer); safecall; // show : method show function show:Integer;safecall; // showEx : method showEx procedure showEx(nID:Integer);safecall; // showFlags : property showFlags property showFlags:Integer read Get_showFlags write Set_showFlags; end; // IWMPMenuCtrl : IWMPMenuCtrl: Not Public. Internal interface used by Windows Media Player. IWMPMenuCtrlDisp = dispinterface ['{158A7ADC-33DA-4039-A553-BDDBBE389F5C}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // deleteAllItems : method deleteAllItems procedure deleteAllItems;dispid 6301; // appendItem : method appendItem procedure appendItem(nID:Integer;bstrItem:WideString);dispid 6302; // appendSeparator : method appendSeparator procedure appendSeparator;dispid 6303; // enableItem : property enableItem procedure enableItem(nID:Integer;newVal:WordBool);dispid 6304; // checkItem : property checkItem procedure checkItem(nID:Integer;newVal:WordBool);dispid 6305; // checkRadioItem : property checkRadioItem procedure checkRadioItem(nID:Integer;newVal:WordBool);dispid 6306; // show : method show function show:Integer;dispid 6308; // showEx : method showEx procedure showEx(nID:Integer);dispid 6309; // showFlags : property showFlags property showFlags:Integer dispid 6307; end; // IWMPAutoMenuCtrl : IWMPAutoMenuCtrl: Not Public. Internal interface used by Windows Media Player. IWMPAutoMenuCtrl = interface(IDispatch) ['{1AD13E0B-4F3A-41DF-9BE2-F9E6FE0A7875}'] // show : method show procedure show(newVal:WideString);safecall; end; // IWMPAutoMenuCtrl : IWMPAutoMenuCtrl: Not Public. Internal interface used by Windows Media Player. IWMPAutoMenuCtrlDisp = dispinterface ['{1AD13E0B-4F3A-41DF-9BE2-F9E6FE0A7875}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // show : method show procedure show(newVal:WideString);dispid 6501; end; // IWMPRegionalButtonCtrl : IWMPRegionalButtonCtrl: Public interface for skin object model. IWMPRegionalButtonCtrl = interface(IDispatch) ['{58D507B1-2354-11D3-BD41-00C04F6EA5AE}'] function Get_image : WideString; safecall; procedure Set_image(const pVal:WideString); safecall; function Get_hoverImage : WideString; safecall; procedure Set_hoverImage(const pVal:WideString); safecall; function Get_downImage : WideString; safecall; procedure Set_downImage(const pVal:WideString); safecall; function Get_hoverDownImage : WideString; safecall; procedure Set_hoverDownImage(const pVal:WideString); safecall; function Get_hoverHoverImage : WideString; safecall; procedure Set_hoverHoverImage(const pVal:WideString); safecall; function Get_disabledImage : WideString; safecall; procedure Set_disabledImage(const pVal:WideString); safecall; function Get_mappingImage : WideString; safecall; procedure Set_mappingImage(const pVal:WideString); safecall; function Get_transparencyColor : WideString; safecall; procedure Set_transparencyColor(const pVal:WideString); safecall; function Get_cursor : WideString; safecall; procedure Set_cursor(const pVal:WideString); safecall; function Get_showBackground : WordBool; safecall; procedure Set_showBackground(const pVal:WordBool); safecall; function Get_radio : WordBool; safecall; procedure Set_radio(const pVal:WordBool); safecall; function Get_buttonCount : Integer; safecall; // createButton : method CreateButton function createButton:IDispatch;safecall; // getButton : method GetButton function getButton(nButton:Integer):IDispatch;safecall; // Click : method Click procedure Click(nButton:Integer);safecall; function Get_hueShift : Single; safecall; procedure Set_hueShift(const pVal:Single); safecall; function Get_saturation : Single; safecall; procedure Set_saturation(const pVal:Single); safecall; // image : property Image property image:WideString read Get_image write Set_image; // hoverImage : property HoverImage property hoverImage:WideString read Get_hoverImage write Set_hoverImage; // downImage : property DownImage property downImage:WideString read Get_downImage write Set_downImage; // hoverDownImage : property HoverDownImage property hoverDownImage:WideString read Get_hoverDownImage write Set_hoverDownImage; // hoverHoverImage : property hoverHoverImage property hoverHoverImage:WideString read Get_hoverHoverImage write Set_hoverHoverImage; // disabledImage : property DisabledImage property disabledImage:WideString read Get_disabledImage write Set_disabledImage; // mappingImage : property MappingImage property mappingImage:WideString read Get_mappingImage write Set_mappingImage; // transparencyColor : property TransparencyColor property transparencyColor:WideString read Get_transparencyColor write Set_transparencyColor; // cursor : property Cursor property cursor:WideString read Get_cursor write Set_cursor; // showBackground : property ShowBackground property showBackground:WordBool read Get_showBackground write Set_showBackground; // radio : property Radio property radio:WordBool read Get_radio write Set_radio; // buttonCount : property ButtonCount property buttonCount:Integer read Get_buttonCount; // hueShift : property hueShift property hueShift:Single read Get_hueShift write Set_hueShift; // saturation : property saturation property saturation:Single read Get_saturation write Set_saturation; end; // IWMPRegionalButtonCtrl : IWMPRegionalButtonCtrl: Public interface for skin object model. IWMPRegionalButtonCtrlDisp = dispinterface ['{58D507B1-2354-11D3-BD41-00C04F6EA5AE}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // createButton : method CreateButton function createButton:IDispatch;dispid 5312; // getButton : method GetButton function getButton(nButton:Integer):IDispatch;dispid 5313; // Click : method Click procedure Click(nButton:Integer);dispid 5314; // image : property Image property image:WideString dispid 5300; // hoverImage : property HoverImage property hoverImage:WideString dispid 5301; // downImage : property DownImage property downImage:WideString dispid 5302; // hoverDownImage : property HoverDownImage property hoverDownImage:WideString dispid 5303; // hoverHoverImage : property hoverHoverImage property hoverHoverImage:WideString dispid 5317; // disabledImage : property DisabledImage property disabledImage:WideString dispid 5304; // mappingImage : property MappingImage property mappingImage:WideString dispid 5305; // transparencyColor : property TransparencyColor property transparencyColor:WideString dispid 5306; // cursor : property Cursor property cursor:WideString dispid 5308; // showBackground : property ShowBackground property showBackground:WordBool dispid 5309; // radio : property Radio property radio:WordBool dispid 5310; // buttonCount : property ButtonCount property buttonCount:Integer readonly dispid 5311; // hueShift : property hueShift property hueShift:Single dispid 5315; // saturation : property saturation property saturation:Single dispid 5316; end; // IWMPRegionalButtonEvents : IWMPRegionalButtonEvents: Public interface for skin object model. IWMPRegionalButtonEvents = dispinterface ['{50FC8D31-67AC-11D3-BD4C-00C04F6EA5AE}'] // onblur : event onblur function onblur:HResult;dispid 5360; // onfocus : event onfocus function onfocus:HResult;dispid 5361; // onclick : event onclick function onclick:HResult;dispid 5362; // ondblclick : event ondblclick function ondblclick:HResult;dispid 5363; // onmousedown : event onmousedown function onmousedown:HResult;dispid 5364; // onmouseup : event onmouseup function onmouseup:HResult;dispid 5365; // onmousemove : event onmousemove function onmousemove:HResult;dispid 5366; // onmouseover : event onmouseover function onmouseover:HResult;dispid 5367; // onmouseout : event onmouseout function onmouseout:HResult;dispid 5368; // onkeypress : event onkeypress function onkeypress:HResult;dispid 5369; // onkeydown : event onkeydown function onkeydown:HResult;dispid 5370; // onkeyup : event onkeyup function onkeyup:HResult;dispid 5371; end; // IWMPRegionalButton : IWMPRegionalButton: Public interface for skin object model. IWMPRegionalButton = interface(IDispatch) ['{58D507B2-2354-11D3-BD41-00C04F6EA5AE}'] function Get_upToolTip : WideString; safecall; procedure Set_upToolTip(const pVal:WideString); safecall; function Get_downToolTip : WideString; safecall; procedure Set_downToolTip(const pVal:WideString); safecall; function Get_mappingColor : WideString; safecall; procedure Set_mappingColor(const pVal:WideString); safecall; function Get_enabled : WordBool; safecall; procedure Set_enabled(const pVal:WordBool); safecall; function Get_sticky : WordBool; safecall; procedure Set_sticky(const pVal:WordBool); safecall; function Get_down : WordBool; safecall; procedure Set_down(const pVal:WordBool); safecall; function Get_index : Integer; safecall; function Get_tabStop : WordBool; safecall; procedure Set_tabStop(const pVal:WordBool); safecall; function Get_cursor : WideString; safecall; procedure Set_cursor(const pVal:WideString); safecall; // Click : method Click procedure Click;safecall; function Get_accName : WideString; safecall; procedure Set_accName(const pszName:WideString); safecall; function Get_accDescription : WideString; safecall; procedure Set_accDescription(const pszDescription:WideString); safecall; function Get_accKeyboardShortcut : WideString; safecall; procedure Set_accKeyboardShortcut(const pszShortcut:WideString); safecall; // upToolTip : property UpToolTip property upToolTip:WideString read Get_upToolTip write Set_upToolTip; // downToolTip : property DownToolTip property downToolTip:WideString read Get_downToolTip write Set_downToolTip; // mappingColor : property MappingColor property mappingColor:WideString read Get_mappingColor write Set_mappingColor; // enabled : property Enabled property enabled:WordBool read Get_enabled write Set_enabled; // sticky : property Sticky property sticky:WordBool read Get_sticky write Set_sticky; // down : property Down property down:WordBool read Get_down write Set_down; // index : property Index property index:Integer read Get_index; // tabStop : property TabStop property tabStop:WordBool read Get_tabStop write Set_tabStop; // cursor : property Cursor property cursor:WideString read Get_cursor write Set_cursor; // accName : property AccName property accName:WideString read Get_accName write Set_accName; // accDescription : property AccDescription property accDescription:WideString read Get_accDescription write Set_accDescription; // accKeyboardShortcut : property accKeyboardShortcut property accKeyboardShortcut:WideString read Get_accKeyboardShortcut write Set_accKeyboardShortcut; end; // IWMPRegionalButton : IWMPRegionalButton: Public interface for skin object model. IWMPRegionalButtonDisp = dispinterface ['{58D507B2-2354-11D3-BD41-00C04F6EA5AE}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Click : method Click procedure Click;dispid 5344; // upToolTip : property UpToolTip property upToolTip:WideString dispid 5330; // downToolTip : property DownToolTip property downToolTip:WideString dispid 5331; // mappingColor : property MappingColor property mappingColor:WideString dispid 5332; // enabled : property Enabled property enabled:WordBool dispid 5333; // sticky : property Sticky property sticky:WordBool dispid 5339; // down : property Down property down:WordBool dispid 5340; // index : property Index property index:Integer readonly dispid 5341; // tabStop : property TabStop property tabStop:WordBool dispid 5342; // cursor : property Cursor property cursor:WideString dispid 5343; // accName : property AccName property accName:WideString dispid 5345; // accDescription : property AccDescription property accDescription:WideString dispid 5346; // accKeyboardShortcut : property accKeyboardShortcut property accKeyboardShortcut:WideString dispid 5347; end; // IWMPCustomSliderCtrlEvents : IWMPCustomSliderCtrlEvents: Public interface for skin object model. IWMPCustomSliderCtrlEvents = dispinterface ['{95F45AA4-ED0A-11D2-BA67-0000F80855E6}'] // ondragbegin : event ondragbegin function ondragbegin:HResult;dispid 5020; // ondragend : event ondragend function ondragend:HResult;dispid 5021; // onpositionchange : event onpositionchange function onpositionchange:HResult;dispid 5022; end; // IWMPCustomSlider : IWMPCustomSlider: Public interface for skin object model. IWMPCustomSlider = interface(IDispatch) ['{95F45AA2-ED0A-11D2-BA67-0000F80855E6}'] function Get_cursor : WideString; safecall; procedure Set_cursor(const pVal:WideString); safecall; function Get_min : Single; safecall; procedure Set_min(const pVal:Single); safecall; function Get_max : Single; safecall; procedure Set_max(const pVal:Single); safecall; function Get_value : Single; safecall; procedure Set_value(const pVal:Single); safecall; function Get_toolTip : WideString; safecall; procedure Set_toolTip(const pVal:WideString); safecall; function Get_positionImage : WideString; safecall; procedure Set_positionImage(const pVal:WideString); safecall; function Get_image : WideString; safecall; procedure Set_image(const pVal:WideString); safecall; function Get_hoverImage : WideString; safecall; procedure Set_hoverImage(const pVal:WideString); safecall; function Get_disabledImage : WideString; safecall; procedure Set_disabledImage(const pVal:WideString); safecall; function Get_downImage : WideString; safecall; procedure Set_downImage(const pVal:WideString); safecall; function Get_transparencyColor : WideString; safecall; procedure Set_transparencyColor(const pVal:WideString); safecall; // cursor : property cursor property cursor:WideString read Get_cursor write Set_cursor; // min : property min property min:Single read Get_min write Set_min; // max : property max property max:Single read Get_max write Set_max; // value : property value property value:Single read Get_value write Set_value; // toolTip : property toolTip property toolTip:WideString read Get_toolTip write Set_toolTip; // positionImage : property positionImage property positionImage:WideString read Get_positionImage write Set_positionImage; // image : property image property image:WideString read Get_image write Set_image; // hoverImage : property hoverImage property hoverImage:WideString read Get_hoverImage write Set_hoverImage; // disabledImage : property disabledImage property disabledImage:WideString read Get_disabledImage write Set_disabledImage; // downImage : property downImage property downImage:WideString read Get_downImage write Set_downImage; // transparencyColor : property transparancyColor property transparencyColor:WideString read Get_transparencyColor write Set_transparencyColor; end; // IWMPCustomSlider : IWMPCustomSlider: Public interface for skin object model. IWMPCustomSliderDisp = dispinterface ['{95F45AA2-ED0A-11D2-BA67-0000F80855E6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // cursor : property cursor property cursor:WideString dispid 5009; // min : property min property min:Single dispid 5005; // max : property max property max:Single dispid 5006; // value : property value property value:Single dispid 5010; // toolTip : property toolTip property toolTip:WideString dispid 5011; // positionImage : property positionImage property positionImage:WideString dispid 5002; // image : property image property image:WideString dispid 5001; // hoverImage : property hoverImage property hoverImage:WideString dispid 5003; // disabledImage : property disabledImage property disabledImage:WideString dispid 5004; // downImage : property downImage property downImage:WideString dispid 5012; // transparencyColor : property transparancyColor property transparencyColor:WideString dispid 5008; end; // IWMPTextCtrl : IWMPTextCtrl: Public interface for skin object model. IWMPTextCtrl = interface(IDispatch) ['{237DAC8E-0E32-11D3-A2E2-00C04F79F88E}'] function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_fontFace : WideString; safecall; procedure Set_fontFace(const pVal:WideString); safecall; function Get_fontStyle : WideString; safecall; procedure Set_fontStyle(const pVal:WideString); safecall; function Get_fontSize : Integer; safecall; procedure Set_fontSize(const pVal:Integer); safecall; function Get_foregroundColor : WideString; safecall; procedure Set_foregroundColor(const pVal:WideString); safecall; function Get_hoverBackgroundColor : WideString; safecall; procedure Set_hoverBackgroundColor(const pVal:WideString); safecall; function Get_hoverForegroundColor : WideString; safecall; procedure Set_hoverForegroundColor(const pVal:WideString); safecall; function Get_hoverFontStyle : WideString; safecall; procedure Set_hoverFontStyle(const pVal:WideString); safecall; function Get_value : WideString; safecall; procedure Set_value(const pVal:WideString); safecall; function Get_toolTip : WideString; safecall; procedure Set_toolTip(const pVal:WideString); safecall; function Get_disabledFontStyle : WideString; safecall; procedure Set_disabledFontStyle(const pVal:WideString); safecall; function Get_disabledForegroundColor : WideString; safecall; procedure Set_disabledForegroundColor(const pVal:WideString); safecall; function Get_disabledBackgroundColor : WideString; safecall; procedure Set_disabledBackgroundColor(const pVal:WideString); safecall; function Get_fontSmoothing : WordBool; safecall; procedure Set_fontSmoothing(const pVal:WordBool); safecall; function Get_justification : WideString; safecall; procedure Set_justification(const pVal:WideString); safecall; function Get_wordWrap : WordBool; safecall; procedure Set_wordWrap(const pVal:WordBool); safecall; function Get_cursor : WideString; safecall; procedure Set_cursor(const pVal:WideString); safecall; function Get_scrolling : WordBool; safecall; procedure Set_scrolling(const pVal:WordBool); safecall; function Get_scrollingDirection : WideString; safecall; procedure Set_scrollingDirection(const pVal:WideString); safecall; function Get_scrollingDelay : SYSINT; safecall; procedure Set_scrollingDelay(const pVal:SYSINT); safecall; function Get_scrollingAmount : SYSINT; safecall; procedure Set_scrollingAmount(const pVal:SYSINT); safecall; function Get_textWidth : SYSINT; safecall; function Get_onGlass : WordBool; safecall; procedure Set_onGlass(const pVal:WordBool); safecall; function Get_disableGlassBlurBackground : WordBool; safecall; procedure Set_disableGlassBlurBackground(const pVal:WordBool); safecall; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // fontFace : property fontFace property fontFace:WideString read Get_fontFace write Set_fontFace; // fontStyle : property fontStyle property fontStyle:WideString read Get_fontStyle write Set_fontStyle; // fontSize : property fontSize property fontSize:Integer read Get_fontSize write Set_fontSize; // foregroundColor : property foregroundColor property foregroundColor:WideString read Get_foregroundColor write Set_foregroundColor; // hoverBackgroundColor : property hoverBackgroundColor property hoverBackgroundColor:WideString read Get_hoverBackgroundColor write Set_hoverBackgroundColor; // hoverForegroundColor : property hoverForegroundColor property hoverForegroundColor:WideString read Get_hoverForegroundColor write Set_hoverForegroundColor; // hoverFontStyle : property hoverFontStyle property hoverFontStyle:WideString read Get_hoverFontStyle write Set_hoverFontStyle; // value : property value property value:WideString read Get_value write Set_value; // toolTip : property toolTip property toolTip:WideString read Get_toolTip write Set_toolTip; // disabledFontStyle : property disabledFontStyle property disabledFontStyle:WideString read Get_disabledFontStyle write Set_disabledFontStyle; // disabledForegroundColor : property disabledForegroundColor property disabledForegroundColor:WideString read Get_disabledForegroundColor write Set_disabledForegroundColor; // disabledBackgroundColor : property disabledBackgroundColor property disabledBackgroundColor:WideString read Get_disabledBackgroundColor write Set_disabledBackgroundColor; // fontSmoothing : property fontSmoothing property fontSmoothing:WordBool read Get_fontSmoothing write Set_fontSmoothing; // justification : property justification property justification:WideString read Get_justification write Set_justification; // wordWrap : property wordWrap property wordWrap:WordBool read Get_wordWrap write Set_wordWrap; // cursor : property cursor property cursor:WideString read Get_cursor write Set_cursor; // scrolling : property scrolling property scrolling:WordBool read Get_scrolling write Set_scrolling; // scrollingDirection : property scrollingDirection property scrollingDirection:WideString read Get_scrollingDirection write Set_scrollingDirection; // scrollingDelay : property scrollingDelay property scrollingDelay:SYSINT read Get_scrollingDelay write Set_scrollingDelay; // scrollingAmount : property scrollingAmount property scrollingAmount:SYSINT read Get_scrollingAmount write Set_scrollingAmount; // textWidth : property textWidth property textWidth:SYSINT read Get_textWidth; // onGlass : property onGlass property onGlass:WordBool read Get_onGlass write Set_onGlass; // disableGlassBlurBackground : property disableGlassBlurBackground property disableGlassBlurBackground:WordBool read Get_disableGlassBlurBackground write Set_disableGlassBlurBackground; end; // IWMPTextCtrl : IWMPTextCtrl: Public interface for skin object model. IWMPTextCtrlDisp = dispinterface ['{237DAC8E-0E32-11D3-A2E2-00C04F79F88E}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 5201; // fontFace : property fontFace property fontFace:WideString dispid 5206; // fontStyle : property fontStyle property fontStyle:WideString dispid 5207; // fontSize : property fontSize property fontSize:Integer dispid 5208; // foregroundColor : property foregroundColor property foregroundColor:WideString dispid 5209; // hoverBackgroundColor : property hoverBackgroundColor property hoverBackgroundColor:WideString dispid 5210; // hoverForegroundColor : property hoverForegroundColor property hoverForegroundColor:WideString dispid 5211; // hoverFontStyle : property hoverFontStyle property hoverFontStyle:WideString dispid 5212; // value : property value property value:WideString dispid 5213; // toolTip : property toolTip property toolTip:WideString dispid 5214; // disabledFontStyle : property disabledFontStyle property disabledFontStyle:WideString dispid 5215; // disabledForegroundColor : property disabledForegroundColor property disabledForegroundColor:WideString dispid 5216; // disabledBackgroundColor : property disabledBackgroundColor property disabledBackgroundColor:WideString dispid 5217; // fontSmoothing : property fontSmoothing property fontSmoothing:WordBool dispid 5221; // justification : property justification property justification:WideString dispid 5222; // wordWrap : property wordWrap property wordWrap:WordBool dispid 5223; // cursor : property cursor property cursor:WideString dispid 5224; // scrolling : property scrolling property scrolling:WordBool dispid 5225; // scrollingDirection : property scrollingDirection property scrollingDirection:WideString dispid 5226; // scrollingDelay : property scrollingDelay property scrollingDelay:SYSINT dispid 5227; // scrollingAmount : property scrollingAmount property scrollingAmount:SYSINT dispid 5228; // textWidth : property textWidth property textWidth:SYSINT readonly dispid 5229; // onGlass : property onGlass property onGlass:WordBool dispid 5230; // disableGlassBlurBackground : property disableGlassBlurBackground property disableGlassBlurBackground:WordBool dispid 5231; end; // ITaskCntrCtrl : ITaskCntrCtrl: Not Public. Internal interface used by Windows Media Player. ITaskCntrCtrl = interface(IDispatch) ['{891EADB1-1C45-48B0-B704-49A888DA98C4}'] function Get_CurrentContainer : IUnknown; safecall; procedure Set_CurrentContainer(const ppUnk:IUnknown); safecall; // Activate : procedure Activate;safecall; // CurrentContainer : property CurrentContainer:IUnknown read Get_CurrentContainer write Set_CurrentContainer; end; // ITaskCntrCtrl : ITaskCntrCtrl: Not Public. Internal interface used by Windows Media Player. ITaskCntrCtrlDisp = dispinterface ['{891EADB1-1C45-48B0-B704-49A888DA98C4}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Activate : procedure Activate;dispid 1610743810; // CurrentContainer : property CurrentContainer:IUnknown dispid 1610743808; end; // _WMPCoreEvents : _WMPCoreEvents: Public interface. _WMPCoreEvents = dispinterface ['{D84CCA96-CCE2-11D2-9ECC-0000F8085981}'] // OpenStateChange : Sent when the control changes OpenState procedure OpenStateChange(NewState:Integer);dispid 5001; // PlayStateChange : Sent when the control changes PlayState procedure PlayStateChange(NewState:Integer);dispid 5101; // AudioLanguageChange : Sent when the current audio language has changed procedure AudioLanguageChange(LangID:Integer);dispid 5102; // StatusChange : Sent when the status string changes procedure StatusChange;dispid 5002; // ScriptCommand : Sent when a synchronized command or URL is received procedure ScriptCommand(scType:WideString;Param:WideString);dispid 5301; // NewStream : Sent when a new stream is started in a channel procedure NewStream;dispid 5403; // Disconnect : Sent when the control is disconnected from the server procedure Disconnect(Result:Integer);dispid 5401; // Buffering : Sent when the control begins or ends buffering procedure Buffering(Start:WordBool);dispid 5402; // Error : Sent when the control has an error condition procedure Error;dispid 5501; // Warning : Sent when the control encounters a problem procedure Warning(WarningType:Integer;Param:Integer;Description:WideString);dispid 5601; // EndOfStream : Sent when the end of file is reached procedure EndOfStream(Result:Integer);dispid 5201; // PositionChange : Indicates that the current position of the movie has changed procedure PositionChange(oldPosition:Double;newPosition:Double);dispid 5202; // MarkerHit : Sent when a marker is reached procedure MarkerHit(MarkerNum:Integer);dispid 5203; // DurationUnitChange : Indicates that the unit used to express duration and position has changed procedure DurationUnitChange(NewDurationUnit:Integer);dispid 5204; // CdromMediaChange : Indicates that the CD ROM media has changed procedure CdromMediaChange(CdromNum:Integer);dispid 5701; // PlaylistChange : Sent when a playlist changes procedure PlaylistChange(Playlist:IDispatch;change:WMPPlaylistChangeEventType);dispid 5801; // CurrentPlaylistChange : Sent when the current playlist changes procedure CurrentPlaylistChange(change:WMPPlaylistChangeEventType);dispid 5804; // CurrentPlaylistItemAvailable : Sent when a current playlist item becomes available procedure CurrentPlaylistItemAvailable(bstrItemName:WideString);dispid 5805; // MediaChange : Sent when a media object changes procedure MediaChange(Item:IDispatch);dispid 5802; // CurrentMediaItemAvailable : Sent when a current media item becomes available procedure CurrentMediaItemAvailable(bstrItemName:WideString);dispid 5803; // CurrentItemChange : Sent when the item selection on the current playlist changes procedure CurrentItemChange(pdispMedia:IDispatch);dispid 5806; // MediaCollectionChange : Sent when the media collection needs to be requeried procedure MediaCollectionChange;dispid 5807; // MediaCollectionAttributeStringAdded : Sent when an attribute string is added in the media collection procedure MediaCollectionAttributeStringAdded(bstrAttribName:WideString;bstrAttribVal:WideString);dispid 5808; // MediaCollectionAttributeStringRemoved : Sent when an attribute string is removed from the media collection procedure MediaCollectionAttributeStringRemoved(bstrAttribName:WideString;bstrAttribVal:WideString);dispid 5809; // MediaCollectionAttributeStringChanged : Sent when an attribute string is changed in the media collection procedure MediaCollectionAttributeStringChanged(bstrAttribName:WideString;bstrOldAttribVal:WideString;bstrNewAttribVal:WideString);dispid 5820; // PlaylistCollectionChange : Sent when playlist collection needs to be requeried procedure PlaylistCollectionChange;dispid 5810; // PlaylistCollectionPlaylistAdded : Sent when a playlist is added to the playlist collection procedure PlaylistCollectionPlaylistAdded(bstrPlaylistName:WideString);dispid 5811; // PlaylistCollectionPlaylistRemoved : Sent when a playlist is removed from the playlist collection procedure PlaylistCollectionPlaylistRemoved(bstrPlaylistName:WideString);dispid 5812; // PlaylistCollectionPlaylistSetAsDeleted : Sent when a playlist has been set or reset as deleted procedure PlaylistCollectionPlaylistSetAsDeleted(bstrPlaylistName:WideString;varfIsDeleted:WordBool);dispid 5818; // ModeChange : Playlist playback mode has changed procedure ModeChange(ModeName:WideString;NewValue:WordBool);dispid 5819; // MediaError : Sent when the media object has an error condition procedure MediaError(pMediaObject:IDispatch);dispid 5821; // OpenPlaylistSwitch : Current playlist switch with no open state change procedure OpenPlaylistSwitch(pItem:IDispatch);dispid 5823; // DomainChange : Send a current domain procedure DomainChange(strDomain:WideString);dispid 5822; // StringCollectionChange : Sent when a string collection changes procedure StringCollectionChange(pdispStringCollection:IDispatch;change:WMPStringCollectionChangeEventType;lCollectionIndex:Integer);dispid 5824; // MediaCollectionMediaAdded : Sent when a media is added to the local library procedure MediaCollectionMediaAdded(pdispMedia:IDispatch);dispid 5825; // MediaCollectionMediaRemoved : Sent when a media is removed from the local library procedure MediaCollectionMediaRemoved(pdispMedia:IDispatch);dispid 5826; end; // IWMPGraphEventHandler : IWMPGraphEventHandler: Not Public. Internal interface used by Windows Media Player. IWMPGraphEventHandler = interface(IDispatch) ['{6B550945-018F-11D3-B14A-00C04F79FAA6}'] // NotifyGraphStateChange : Notifies graph state changes procedure NotifyGraphStateChange(punkGraph:ULONG_PTR;lGraphState:Integer);safecall; // AsyncNotifyGraphStateChange : Notifies graph state changes asynchronously procedure AsyncNotifyGraphStateChange(punkGraph:ULONG_PTR;lGraphState:Integer);safecall; // NotifyRateChange : Notifies changes in playback rate procedure NotifyRateChange(punkGraph:ULONG_PTR;dRate:Double);safecall; // NotifyPlaybackEnd : Notifies the end of playback procedure NotifyPlaybackEnd(punkGraph:ULONG_PTR;bstrQueuedUrl:WideString;dwCurrentContext:ULONG_PTR);safecall; // NotifyStreamEnd : Notifies the end of a stream procedure NotifyStreamEnd(punkGraph:ULONG_PTR);safecall; // NotifyScriptCommand : Notifies that a script command was encountered procedure NotifyScriptCommand(punkGraph:ULONG_PTR;bstrCommand:WideString;bstrParam:WideString);safecall; // NotifyEarlyScriptCommand : Notifies that a script command was encountered procedure NotifyEarlyScriptCommand(punkGraph:ULONG_PTR;bstrCommand:WideString;bstrParam:WideString;dTime:Double);safecall; // NotifyMarkerHit : Notifies that a marker was encountered procedure NotifyMarkerHit(punkGraph:ULONG_PTR;lMarker:Integer);safecall; // NotifyGraphError : Notifies that an error has occurred procedure NotifyGraphError(punkGraph:ULONG_PTR;lErrMajor:Integer;lErrMinor:Integer;lCondition:Integer;bstrInfo:WideString;punkGraphData:IUnknown);safecall; // NotifyAcquireCredentials : Spawns the Acquire Credentials dialog procedure NotifyAcquireCredentials(punkGraph:ULONG_PTR;bstrRealm:WideString;bstrSite:WideString;bstrUser:WideString;bstrPassword:WideString;var pdwFlags:LongWord;out pfCancel:WordBool);safecall; // NotifyUntrustedLicense : Spawns the untrusted license dialog procedure NotifyUntrustedLicense(punkGraph:ULONG_PTR;bstrURL:WideString;out pfCancel:WordBool);safecall; // NotifyLicenseDialog : Notifies a communication with the license dialog procedure NotifyLicenseDialog(punkGraph:ULONG_PTR;bstrURL:WideString;bstrContent:WideString;var pPostData:Byte;dwPostDataSize:LongWord;lResult:Integer);safecall; // NotifyNeedsIndividualization : Notifies a communication with the Individualization dialog procedure NotifyNeedsIndividualization(punkGraph:ULONG_PTR;out pfResult:WordBool);safecall; // NotifyNewMetadata : Notifies that new metadata is avail procedure NotifyNewMetadata(punkGraph:ULONG_PTR);safecall; // NotifyNewMediaCaps : Notifies that new capabilities are avail procedure NotifyNewMediaCaps(punkGraph:ULONG_PTR);safecall; // NotifyDisconnect : Notifies that the graph's connection to the media has been lost. procedure NotifyDisconnect(punkGraph:ULONG_PTR;lResult:Integer);safecall; // NotifySave : Notifies that the graph save operation started/stopped. procedure NotifySave(punkGraph:ULONG_PTR;fStarted:Integer;lResult:Integer);safecall; // NotifyDelayClose : Notifies if the close call needs to be delayed. procedure NotifyDelayClose(punkGraph:ULONG_PTR;fDelay:WordBool);safecall; // NotifyDVD : Notifies when domain changes, parental control and region needs to be handled. procedure NotifyDVD(punkGraph:ULONG_PTR;lEventCode:Integer;lParam1:Integer;lParam2:Integer);safecall; // NotifyRequestAppThreadAction : Requests a callback into the graph on the apps thread procedure NotifyRequestAppThreadAction(punkGraph:ULONG_PTR;dwAction:LongWord);safecall; // NotifyPrerollReady : Notifies that a prerolled graph is ready to play with no more buffering procedure NotifyPrerollReady(punkGraph:ULONG_PTR);safecall; // NotifyNewIcons : Notifies core that our DirectShow filters have new icons to display procedure NotifyNewIcons(punkGraph:ULONG_PTR);safecall; // NotifyStepComplete : Notifies core that our step operation has completed procedure NotifyStepComplete(punkGraph:ULONG_PTR);safecall; // NotifyNewBitrate : Notifies core that our bitrate has changed procedure NotifyNewBitrate(punkGraph:ULONG_PTR;dwBitrate:LongWord);safecall; // NotifyGraphCreationPreRender : procedure NotifyGraphCreationPreRender(punkGraph:ULONG_PTR;punkFilterGraph:ULONG_PTR;punkCardeaEncConfig:ULONG_PTR;phrContinue:ULONG_PTR;hEventToSet:ULONG_PTR);safecall; // NotifyGraphCreationPostRender : procedure NotifyGraphCreationPostRender(punkGraph:ULONG_PTR;punkFilterGraph:ULONG_PTR;phrContinue:ULONG_PTR;hEventToSet:ULONG_PTR);safecall; // NotifyGraphUserEvent : Signals a user event from the renderer procedure NotifyGraphUserEvent(punkGraph:ULONG_PTR;EventCode:Integer);safecall; // NotifyRevocation : Notifies a communication with the Revocation dialog procedure NotifyRevocation(punkGraph:ULONG_PTR;out pfResult:WordBool);safecall; // NotifyNeedsWMGraphIndividualization : Notifies a communication with the Individualization dialog procedure NotifyNeedsWMGraphIndividualization(punkGraph:ULONG_PTR;phWnd:ULONG_PTR;hIndivEvent:ULONG_PTR;out pfCancel:WordBool;out pfResult:WordBool);safecall; // NotifyNeedsFullscreen : Notifies core that the content requires fullscreen mode procedure NotifyNeedsFullscreen(punkGraph:ULONG_PTR);safecall; end; // IWMPGraphEventHandler : IWMPGraphEventHandler: Not Public. Internal interface used by Windows Media Player. IWMPGraphEventHandlerDisp = dispinterface ['{6B550945-018F-11D3-B14A-00C04F79FAA6}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // NotifyGraphStateChange : Notifies graph state changes procedure NotifyGraphStateChange(punkGraph:ULONG_PTR;lGraphState:Integer);dispid 8151; // AsyncNotifyGraphStateChange : Notifies graph state changes asynchronously procedure AsyncNotifyGraphStateChange(punkGraph:ULONG_PTR;lGraphState:Integer);dispid 8173; // NotifyRateChange : Notifies changes in playback rate procedure NotifyRateChange(punkGraph:ULONG_PTR;dRate:Double);dispid 8153; // NotifyPlaybackEnd : Notifies the end of playback procedure NotifyPlaybackEnd(punkGraph:ULONG_PTR;bstrQueuedUrl:WideString;dwCurrentContext:ULONG_PTR);dispid 8157; // NotifyStreamEnd : Notifies the end of a stream procedure NotifyStreamEnd(punkGraph:ULONG_PTR);dispid 8156; // NotifyScriptCommand : Notifies that a script command was encountered procedure NotifyScriptCommand(punkGraph:ULONG_PTR;bstrCommand:WideString;bstrParam:WideString);dispid 8158; // NotifyEarlyScriptCommand : Notifies that a script command was encountered procedure NotifyEarlyScriptCommand(punkGraph:ULONG_PTR;bstrCommand:WideString;bstrParam:WideString;dTime:Double);dispid 8172; // NotifyMarkerHit : Notifies that a marker was encountered procedure NotifyMarkerHit(punkGraph:ULONG_PTR;lMarker:Integer);dispid 8159; // NotifyGraphError : Notifies that an error has occurred procedure NotifyGraphError(punkGraph:ULONG_PTR;lErrMajor:Integer;lErrMinor:Integer;lCondition:Integer;bstrInfo:WideString;punkGraphData:IUnknown);dispid 8160; // NotifyAcquireCredentials : Spawns the Acquire Credentials dialog procedure NotifyAcquireCredentials(punkGraph:ULONG_PTR;bstrRealm:WideString;bstrSite:WideString;bstrUser:WideString;bstrPassword:WideString;var pdwFlags:LongWord;out pfCancel:WordBool);dispid 8161; // NotifyUntrustedLicense : Spawns the untrusted license dialog procedure NotifyUntrustedLicense(punkGraph:ULONG_PTR;bstrURL:WideString;out pfCancel:WordBool);dispid 8178; // NotifyLicenseDialog : Notifies a communication with the license dialog procedure NotifyLicenseDialog(punkGraph:ULONG_PTR;bstrURL:WideString;bstrContent:WideString;var pPostData:Byte;dwPostDataSize:LongWord;lResult:Integer);dispid 8162; // NotifyNeedsIndividualization : Notifies a communication with the Individualization dialog procedure NotifyNeedsIndividualization(punkGraph:ULONG_PTR;out pfResult:WordBool);dispid 8163; // NotifyNewMetadata : Notifies that new metadata is avail procedure NotifyNewMetadata(punkGraph:ULONG_PTR);dispid 8165; // NotifyNewMediaCaps : Notifies that new capabilities are avail procedure NotifyNewMediaCaps(punkGraph:ULONG_PTR);dispid 8166; // NotifyDisconnect : Notifies that the graph's connection to the media has been lost. procedure NotifyDisconnect(punkGraph:ULONG_PTR;lResult:Integer);dispid 8167; // NotifySave : Notifies that the graph save operation started/stopped. procedure NotifySave(punkGraph:ULONG_PTR;fStarted:Integer;lResult:Integer);dispid 8168; // NotifyDelayClose : Notifies if the close call needs to be delayed. procedure NotifyDelayClose(punkGraph:ULONG_PTR;fDelay:WordBool);dispid 8169; // NotifyDVD : Notifies when domain changes, parental control and region needs to be handled. procedure NotifyDVD(punkGraph:ULONG_PTR;lEventCode:Integer;lParam1:Integer;lParam2:Integer);dispid 8170; // NotifyRequestAppThreadAction : Requests a callback into the graph on the apps thread procedure NotifyRequestAppThreadAction(punkGraph:ULONG_PTR;dwAction:LongWord);dispid 8171; // NotifyPrerollReady : Notifies that a prerolled graph is ready to play with no more buffering procedure NotifyPrerollReady(punkGraph:ULONG_PTR);dispid 8174; // NotifyNewIcons : Notifies core that our DirectShow filters have new icons to display procedure NotifyNewIcons(punkGraph:ULONG_PTR);dispid 8177; // NotifyStepComplete : Notifies core that our step operation has completed procedure NotifyStepComplete(punkGraph:ULONG_PTR);dispid 8179; // NotifyNewBitrate : Notifies core that our bitrate has changed procedure NotifyNewBitrate(punkGraph:ULONG_PTR;dwBitrate:LongWord);dispid 8180; // NotifyGraphCreationPreRender : procedure NotifyGraphCreationPreRender(punkGraph:ULONG_PTR;punkFilterGraph:ULONG_PTR;punkCardeaEncConfig:ULONG_PTR;phrContinue:ULONG_PTR;hEventToSet:ULONG_PTR);dispid 8181; // NotifyGraphCreationPostRender : procedure NotifyGraphCreationPostRender(punkGraph:ULONG_PTR;punkFilterGraph:ULONG_PTR;phrContinue:ULONG_PTR;hEventToSet:ULONG_PTR);dispid 8182; // NotifyGraphUserEvent : Signals a user event from the renderer procedure NotifyGraphUserEvent(punkGraph:ULONG_PTR;EventCode:Integer);dispid 8186; // NotifyRevocation : Notifies a communication with the Revocation dialog procedure NotifyRevocation(punkGraph:ULONG_PTR;out pfResult:WordBool);dispid 8183; // NotifyNeedsWMGraphIndividualization : Notifies a communication with the Individualization dialog procedure NotifyNeedsWMGraphIndividualization(punkGraph:ULONG_PTR;phWnd:ULONG_PTR;hIndivEvent:ULONG_PTR;out pfCancel:WordBool;out pfResult:WordBool);dispid 8184; // NotifyNeedsFullscreen : Notifies core that the content requires fullscreen mode procedure NotifyNeedsFullscreen(punkGraph:ULONG_PTR);dispid 8185; end; // IBattery : IBattery: Not Public. Internal interface used by Windows Media Player. IBattery = interface(IDispatch) ['{F8578BFA-CD8F-4CE1-A684-5B7E85FCA7DC}'] function Get_presetCount : Integer; safecall; function Get_preset(nIndex:Integer) : IDispatch; safecall; // presetCount : property presetCount:Integer read Get_presetCount; // preset : property preset[nIndex:Integer]:IDispatch read Get_preset; end; // IBattery : IBattery: Not Public. Internal interface used by Windows Media Player. IBatteryDisp = dispinterface ['{F8578BFA-CD8F-4CE1-A684-5B7E85FCA7DC}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // presetCount : property presetCount:Integer readonly dispid 1; // preset : property preset[nIndex:Integer]:IDispatch readonly dispid 2; end; // IBatteryPreset : IBatteryPreset: Not Public. Internal interface used by Windows Media Player. IBatteryPreset = interface(IDispatch) ['{40C6BDE7-9C90-49D4-AD20-BEF81A6C5F22}'] function Get_title : WideString; safecall; procedure Set_title(const pVal:WideString); safecall; // title : property title:WideString read Get_title write Set_title; end; // IBatteryPreset : IBatteryPreset: Not Public. Internal interface used by Windows Media Player. IBatteryPresetDisp = dispinterface ['{40C6BDE7-9C90-49D4-AD20-BEF81A6C5F22}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // title : property title:WideString dispid 1; end; // IBatteryRandomPreset : IBatteryRandomPreset: Not Public. Internal interface used by Windows Media Player. IBatteryRandomPreset = interface(IBatteryPreset) ['{F85E2D65-207D-48DB-84B1-915E1735DB17}'] end; // IBatteryRandomPreset : IBatteryRandomPreset: Not Public. Internal interface used by Windows Media Player. IBatteryRandomPresetDisp = dispinterface ['{F85E2D65-207D-48DB-84B1-915E1735DB17}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // title : property title:WideString dispid 1; end; // IBatterySavedPreset : IBatterySavedPreset: Not Public. Internal interface used by Windows Media Player. IBatterySavedPreset = interface(IBatteryPreset) ['{876E7208-0172-4EBB-B08B-2E1D30DFE44C}'] end; // IBatterySavedPreset : IBatterySavedPreset: Not Public. Internal interface used by Windows Media Player. IBatterySavedPresetDisp = dispinterface ['{876E7208-0172-4EBB-B08B-2E1D30DFE44C}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // title : property title:WideString dispid 1; end; // IBarsEffect : IBarsEffect: Not Public. Internal interface used by Windows Media Player. IBarsEffect = interface(IDispatch) ['{33E9291A-F6A9-11D2-9435-00A0C92A2F2D}'] function Get_displayMode : Integer; safecall; procedure Set_displayMode(const pVal:Integer); safecall; function Get_showPeaks : WordBool; safecall; procedure Set_showPeaks(const pVal:WordBool); safecall; function Get_peakHangTime : Integer; safecall; procedure Set_peakHangTime(const pVal:Integer); safecall; function Get_peakFallbackAcceleration : Single; safecall; procedure Set_peakFallbackAcceleration(const pVal:Single); safecall; function Get_peakFallbackSpeed : Single; safecall; procedure Set_peakFallbackSpeed(const pVal:Single); safecall; function Get_levelFallbackAcceleration : Single; safecall; procedure Set_levelFallbackAcceleration(const pVal:Single); safecall; function Get_levelFallbackSpeed : Single; safecall; procedure Set_levelFallbackSpeed(const pVal:Single); safecall; function Get_backgroundColor : WideString; safecall; procedure Set_backgroundColor(const pVal:WideString); safecall; function Get_levelColor : WideString; safecall; procedure Set_levelColor(const pVal:WideString); safecall; function Get_peakColor : WideString; safecall; procedure Set_peakColor(const pVal:WideString); safecall; function Get_horizontalSpacing : Integer; safecall; procedure Set_horizontalSpacing(const pVal:Integer); safecall; function Get_levelWidth : Integer; safecall; procedure Set_levelWidth(const pVal:Integer); safecall; function Get_levelScale : Single; safecall; procedure Set_levelScale(const pVal:Single); safecall; function Get_fadeRate : Integer; safecall; procedure Set_fadeRate(const pVal:Integer); safecall; function Get_fadeMode : Integer; safecall; procedure Set_fadeMode(const pVal:Integer); safecall; function Get_transparent : WordBool; safecall; procedure Set_transparent(const pVal:WordBool); safecall; // displayMode : property displayMode property displayMode:Integer read Get_displayMode write Set_displayMode; // showPeaks : property showPeaks property showPeaks:WordBool read Get_showPeaks write Set_showPeaks; // peakHangTime : property peakHangTime property peakHangTime:Integer read Get_peakHangTime write Set_peakHangTime; // peakFallbackAcceleration : property peakFallbackAcceleration property peakFallbackAcceleration:Single read Get_peakFallbackAcceleration write Set_peakFallbackAcceleration; // peakFallbackSpeed : property peakFallbackSpeed property peakFallbackSpeed:Single read Get_peakFallbackSpeed write Set_peakFallbackSpeed; // levelFallbackAcceleration : property levelFallbackAcceleration property levelFallbackAcceleration:Single read Get_levelFallbackAcceleration write Set_levelFallbackAcceleration; // levelFallbackSpeed : property levelFallbackSpeed property levelFallbackSpeed:Single read Get_levelFallbackSpeed write Set_levelFallbackSpeed; // backgroundColor : property backgroundColor property backgroundColor:WideString read Get_backgroundColor write Set_backgroundColor; // levelColor : property levelColor property levelColor:WideString read Get_levelColor write Set_levelColor; // peakColor : property peakColor property peakColor:WideString read Get_peakColor write Set_peakColor; // horizontalSpacing : property horizontalSpacing property horizontalSpacing:Integer read Get_horizontalSpacing write Set_horizontalSpacing; // levelWidth : property levelWidth property levelWidth:Integer read Get_levelWidth write Set_levelWidth; // levelScale : property levelScale property levelScale:Single read Get_levelScale write Set_levelScale; // fadeRate : property fadeRate property fadeRate:Integer read Get_fadeRate write Set_fadeRate; // fadeMode : property fadeMode property fadeMode:Integer read Get_fadeMode write Set_fadeMode; // transparent : property transparent property transparent:WordBool read Get_transparent write Set_transparent; end; // IBarsEffect : IBarsEffect: Not Public. Internal interface used by Windows Media Player. IBarsEffectDisp = dispinterface ['{33E9291A-F6A9-11D2-9435-00A0C92A2F2D}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // displayMode : property displayMode property displayMode:Integer dispid 8000; // showPeaks : property showPeaks property showPeaks:WordBool dispid 8001; // peakHangTime : property peakHangTime property peakHangTime:Integer dispid 8002; // peakFallbackAcceleration : property peakFallbackAcceleration property peakFallbackAcceleration:Single dispid 8003; // peakFallbackSpeed : property peakFallbackSpeed property peakFallbackSpeed:Single dispid 8004; // levelFallbackAcceleration : property levelFallbackAcceleration property levelFallbackAcceleration:Single dispid 8005; // levelFallbackSpeed : property levelFallbackSpeed property levelFallbackSpeed:Single dispid 8006; // backgroundColor : property backgroundColor property backgroundColor:WideString dispid 8007; // levelColor : property levelColor property levelColor:WideString dispid 8008; // peakColor : property peakColor property peakColor:WideString dispid 8009; // horizontalSpacing : property horizontalSpacing property horizontalSpacing:Integer dispid 8010; // levelWidth : property levelWidth property levelWidth:Integer dispid 8012; // levelScale : property levelScale property levelScale:Single dispid 8013; // fadeRate : property fadeRate property fadeRate:Integer dispid 8014; // fadeMode : property fadeMode property fadeMode:Integer dispid 8015; // transparent : property transparent property transparent:WordBool dispid 8016; end; // IWMPExternal : IWMPExternal: Public interface for scripting object model. IWMPExternal = interface(IDispatch) ['{E2CC638C-FD2C-409B-A1EA-5DDB72DC8E84}'] function Get_version : WideString; safecall; function Get_appColorLight : WideString; safecall; procedure Set_OnColorChange(const Param1:IDispatch); safecall; // version : property version:WideString read Get_version; // appColorLight : property appColorLight:WideString read Get_appColorLight; // OnColorChange : property OnColorChange:IDispatch write Set_OnColorChange; end; // IWMPExternal : IWMPExternal: Public interface for scripting object model. IWMPExternalDisp = dispinterface ['{E2CC638C-FD2C-409B-A1EA-5DDB72DC8E84}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; end; // IWMPExternalColors : IWMPExternalColors: Public interface for scripting object model. IWMPExternalColors = interface(IWMPExternal) ['{D10CCDFF-472D-498C-B5FE-3630E5405E0A}'] function Get_appColorMedium : WideString; safecall; function Get_appColorDark : WideString; safecall; function Get_appColorButtonHighlight : WideString; safecall; function Get_appColorButtonShadow : WideString; safecall; function Get_appColorButtonHoverFace : WideString; safecall; // appColorMedium : property appColorMedium:WideString read Get_appColorMedium; // appColorDark : property appColorDark:WideString read Get_appColorDark; // appColorButtonHighlight : property appColorButtonHighlight:WideString read Get_appColorButtonHighlight; // appColorButtonShadow : property appColorButtonShadow:WideString read Get_appColorButtonShadow; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString read Get_appColorButtonHoverFace; end; // IWMPExternalColors : IWMPExternalColors: Public interface for scripting object model. IWMPExternalColorsDisp = dispinterface ['{D10CCDFF-472D-498C-B5FE-3630E5405E0A}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; // appColorMedium : property appColorMedium:WideString readonly dispid 10013; // appColorDark : property appColorDark:WideString readonly dispid 10014; // appColorButtonHighlight : property appColorButtonHighlight:WideString readonly dispid 10015; // appColorButtonShadow : property appColorButtonShadow:WideString readonly dispid 10016; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString readonly dispid 10017; end; // IWMPSubscriptionServiceLimited : IWMPSubscriptionServiceLimited: Public interface for scripting object model. IWMPSubscriptionServiceLimited = interface(IWMPExternalColors) ['{54DF358E-CF38-4010-99F1-F44B0E9000E5}'] // NavigateTaskPaneURL : procedure NavigateTaskPaneURL(bstrKeyName:WideString;bstrTaskPane:WideString;bstrParams:WideString);safecall; procedure Set_SelectedTaskPane(const bstrTaskPane:WideString); safecall; function Get_SelectedTaskPane : WideString; safecall; // SelectedTaskPane : property SelectedTaskPane:WideString read Get_SelectedTaskPane write Set_SelectedTaskPane; end; // IWMPSubscriptionServiceLimited : IWMPSubscriptionServiceLimited: Public interface for scripting object model. IWMPSubscriptionServiceLimitedDisp = dispinterface ['{54DF358E-CF38-4010-99F1-F44B0E9000E5}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // NavigateTaskPaneURL : procedure NavigateTaskPaneURL(bstrKeyName:WideString;bstrTaskPane:WideString;bstrParams:WideString);dispid 10026; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; // appColorMedium : property appColorMedium:WideString readonly dispid 10013; // appColorDark : property appColorDark:WideString readonly dispid 10014; // appColorButtonHighlight : property appColorButtonHighlight:WideString readonly dispid 10015; // appColorButtonShadow : property appColorButtonShadow:WideString readonly dispid 10016; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString readonly dispid 10017; // SelectedTaskPane : property SelectedTaskPane:WideString dispid 10027; end; // IWMPSubscriptionServiceExternal : IWMPSubscriptionServiceExternal: Public interface for scripting object model. IWMPSubscriptionServiceExternal = interface(IWMPSubscriptionServiceLimited) ['{2E922378-EE70-4CEB-BBAB-CE7CE4A04816}'] function Get_DownloadManager : IWMPDownloadManager; safecall; // DownloadManager : property DownloadManager:IWMPDownloadManager read Get_DownloadManager; end; // IWMPSubscriptionServiceExternal : IWMPSubscriptionServiceExternal: Public interface for scripting object model. IWMPSubscriptionServiceExternalDisp = dispinterface ['{2E922378-EE70-4CEB-BBAB-CE7CE4A04816}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // NavigateTaskPaneURL : procedure NavigateTaskPaneURL(bstrKeyName:WideString;bstrTaskPane:WideString;bstrParams:WideString);dispid 10026; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; // appColorMedium : property appColorMedium:WideString readonly dispid 10013; // appColorDark : property appColorDark:WideString readonly dispid 10014; // appColorButtonHighlight : property appColorButtonHighlight:WideString readonly dispid 10015; // appColorButtonShadow : property appColorButtonShadow:WideString readonly dispid 10016; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString readonly dispid 10017; // SelectedTaskPane : property SelectedTaskPane:WideString dispid 10027; // DownloadManager : property DownloadManager:IWMPDownloadManager readonly dispid 10009; end; // IWMPDownloadManager : IWMPDownloadManager: Public interface. IWMPDownloadManager = interface(IDispatch) ['{E15E9AD1-8F20-4CC4-9EC7-1A328CA86A0D}'] // getDownloadCollection : Returns a specific download collection function getDownloadCollection(lCollectionId:Integer):IWMPDownloadCollection;safecall; // createDownloadCollection : Creates a download collection function createDownloadCollection:IWMPDownloadCollection;safecall; end; // IWMPDownloadManager : IWMPDownloadManager: Public interface. IWMPDownloadManagerDisp = dispinterface ['{E15E9AD1-8F20-4CC4-9EC7-1A328CA86A0D}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // getDownloadCollection : Returns a specific download collection function getDownloadCollection(lCollectionId:Integer):IWMPDownloadCollection;dispid 1151; // createDownloadCollection : Creates a download collection function createDownloadCollection:IWMPDownloadCollection;dispid 1152; end; // IWMPDownloadCollection : IWMPDownloadCollection: Public interface. IWMPDownloadCollection = interface(IDispatch) ['{0A319C7F-85F9-436C-B88E-82FD88000E1C}'] function Get_ID : Integer; safecall; function Get_count : Integer; safecall; // Item : Returns a pending download object function Item(lItem:Integer):IWMPDownloadItem2;safecall; // startDownload : Queues a download function startDownload(bstrSourceURL:WideString;bstrType:WideString):IWMPDownloadItem2;safecall; // removeItem : Remove a download from the collection. Cancel if in progress. procedure removeItem(lItem:Integer);safecall; // clear : Clear the download collection procedure clear;safecall; // ID : Returns the unique identifier of the collection property ID:Integer read Get_ID; // count : Returns the number of pending downloads property count:Integer read Get_count; end; // IWMPDownloadCollection : IWMPDownloadCollection: Public interface. IWMPDownloadCollectionDisp = dispinterface ['{0A319C7F-85F9-436C-B88E-82FD88000E1C}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // Item : Returns a pending download object function Item(lItem:Integer):IWMPDownloadItem2;dispid 1203; // startDownload : Queues a download function startDownload(bstrSourceURL:WideString;bstrType:WideString):IWMPDownloadItem2;dispid 1204; // removeItem : Remove a download from the collection. Cancel if in progress. procedure removeItem(lItem:Integer);dispid 1205; // clear : Clear the download collection procedure clear;dispid 1206; // ID : Returns the unique identifier of the collection property ID:Integer readonly dispid 1201; // count : Returns the number of pending downloads property count:Integer readonly dispid 1202; end; // IWMPDownloadItem : IWMPDownloadItem: Public interface. IWMPDownloadItem = interface(IDispatch) ['{C9470E8E-3F6B-46A9-A0A9-452815C34297}'] function Get_sourceURL : WideString; safecall; function Get_size : Integer; safecall; function Get_type_ : WideString; safecall; function Get_progress : Integer; safecall; function Get_downloadState : WMPSubscriptionDownloadState; safecall; // pause : Pauses the download procedure pause;safecall; // resume : Resumes the download procedure resume;safecall; // cancel : Cancels the download procedure cancel;safecall; // sourceURL : Returns the source URL of the download property sourceURL:WideString read Get_sourceURL; // size : Returns the size of the download property size:Integer read Get_size; // type : Returns the type of the download property type_:WideString read Get_type_; // progress : Returns the progress (in bytes) of the download property progress:Integer read Get_progress; // downloadState : Returns the state of the download property downloadState:WMPSubscriptionDownloadState read Get_downloadState; end; // IWMPDownloadItem : IWMPDownloadItem: Public interface. IWMPDownloadItemDisp = dispinterface ['{C9470E8E-3F6B-46A9-A0A9-452815C34297}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // pause : Pauses the download procedure pause;dispid 1256; // resume : Resumes the download procedure resume;dispid 1257; // cancel : Cancels the download procedure cancel;dispid 1258; // sourceURL : Returns the source URL of the download property sourceURL:WideString readonly dispid 1251; // size : Returns the size of the download property size:Integer readonly dispid 1252; // type : Returns the type of the download property type_:WideString readonly dispid 1253; // progress : Returns the progress (in bytes) of the download property progress:Integer readonly dispid 1254; // downloadState : Returns the state of the download property downloadState:WMPSubscriptionDownloadState readonly dispid 1255; end; // IWMPDownloadItem2 : IWMPDownloadItem2: Public interface. IWMPDownloadItem2 = interface(IWMPDownloadItem) ['{9FBB3336-6DA3-479D-B8FF-67D46E20A987}'] // getItemInfo : Returns the value of specified attribute for this download item function getItemInfo(bstrItemName:WideString):WideString;safecall; end; // IWMPDownloadItem2 : IWMPDownloadItem2: Public interface. IWMPDownloadItem2Disp = dispinterface ['{9FBB3336-6DA3-479D-B8FF-67D46E20A987}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // pause : Pauses the download procedure pause;dispid 1256; // resume : Resumes the download procedure resume;dispid 1257; // cancel : Cancels the download procedure cancel;dispid 1258; // getItemInfo : Returns the value of specified attribute for this download item function getItemInfo(bstrItemName:WideString):WideString;dispid 1301; // sourceURL : Returns the source URL of the download property sourceURL:WideString readonly dispid 1251; // size : Returns the size of the download property size:Integer readonly dispid 1252; // type : Returns the type of the download property type_:WideString readonly dispid 1253; // progress : Returns the progress (in bytes) of the download property progress:Integer readonly dispid 1254; // downloadState : Returns the state of the download property downloadState:WMPSubscriptionDownloadState readonly dispid 1255; end; // IWMPSubscriptionServicePlayMedia : IWMPSubscriptionServicePlayMedia: Public interface for scripting object model. IWMPSubscriptionServicePlayMedia = interface(IWMPSubscriptionServiceLimited) ['{5F0248C1-62B3-42D7-B927-029119E6AD14}'] // playMedia : method playMedia procedure playMedia(bstrURL:WideString);safecall; end; // IWMPSubscriptionServicePlayMedia : IWMPSubscriptionServicePlayMedia: Public interface for scripting object model. IWMPSubscriptionServicePlayMediaDisp = dispinterface ['{5F0248C1-62B3-42D7-B927-029119E6AD14}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // NavigateTaskPaneURL : procedure NavigateTaskPaneURL(bstrKeyName:WideString;bstrTaskPane:WideString;bstrParams:WideString);dispid 10026; // playMedia : method playMedia procedure playMedia(bstrURL:WideString);dispid 10004; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; // appColorMedium : property appColorMedium:WideString readonly dispid 10013; // appColorDark : property appColorDark:WideString readonly dispid 10014; // appColorButtonHighlight : property appColorButtonHighlight:WideString readonly dispid 10015; // appColorButtonShadow : property appColorButtonShadow:WideString readonly dispid 10016; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString readonly dispid 10017; // SelectedTaskPane : property SelectedTaskPane:WideString dispid 10027; end; // IWMPDiscoExternal : IWMPDiscoExternal: Public interface for scripting object model. IWMPDiscoExternal = interface(IWMPSubscriptionServiceExternal) ['{A915CEA2-72DF-41E1-A576-EF0BAE5E5169}'] procedure Set_OnLoginChange(const Param1:IDispatch); safecall; function Get_userLoggedIn : WordBool; safecall; // attemptLogin : procedure attemptLogin;safecall; function Get_accountType : WideString; safecall; procedure Set_OnViewChange(const Param1:IDispatch); safecall; // changeView : procedure changeView(bstrLibraryLocationType:WideString;bstrLibraryLocationID:WideString;bstrFilter:WideString;bstrViewParams:WideString);safecall; // changeViewOnlineList : procedure changeViewOnlineList(bstrLibraryLocationType:WideString;bstrLibraryLocationID:WideString;bstrParams:WideString;bstrFriendlyName:WideString;bstrListType:WideString;bstrViewMode:WideString);safecall; function Get_libraryLocationType : WideString; safecall; function Get_libraryLocationID : WideString; safecall; function Get_selectedItemType : WideString; safecall; function Get_selectedItemID : WideString; safecall; function Get_filter : WideString; safecall; function Get_task : WideString; safecall; function Get_viewParameters : WideString; safecall; // cancelNavigate : procedure cancelNavigate;safecall; // showPopup : procedure showPopup(lPopupIndex:Integer;bstrParameters:WideString);safecall; // addToBasket : procedure addToBasket(bstrViewType:WideString;bstrViewIDs:WideString);safecall; function Get_basketTitle : WideString; safecall; // play : procedure play(bstrLibraryLocationType:WideString;bstrLibraryLocationIDs:WideString);safecall; // download : procedure download(bstrViewType:WideString;bstrViewIDs:WideString);safecall; // buy : procedure buy(bstrViewType:WideString;bstrViewIDs:WideString);safecall; // saveCurrentViewToLibrary : procedure saveCurrentViewToLibrary(bstrFriendlyListType:WideString;fDynamic:WordBool);safecall; // authenticate : procedure authenticate(lAuthenticationIndex:Integer);safecall; // sendMessage : procedure sendMessage(bstrMsg:WideString;bstrParam:WideString);safecall; procedure Set_OnSendMessageComplete(const Param1:IDispatch); safecall; procedure Set_ignoreIEHistory(const Param1:WordBool); safecall; function Get_pluginRunning : WordBool; safecall; function Get_templateBeingDisplayedInLocalLibrary : WordBool; safecall; procedure Set_OnChangeViewError(const Param1:IDispatch); safecall; procedure Set_OnChangeViewOnlineListError(const Param1:IDispatch); safecall; // OnLoginChange : property OnLoginChange:IDispatch write Set_OnLoginChange; // userLoggedIn : property userLoggedIn:WordBool read Get_userLoggedIn; // accountType : property accountType:WideString read Get_accountType; // OnViewChange : property OnViewChange:IDispatch write Set_OnViewChange; // libraryLocationType : property libraryLocationType:WideString read Get_libraryLocationType; // libraryLocationID : property libraryLocationID:WideString read Get_libraryLocationID; // selectedItemType : property selectedItemType:WideString read Get_selectedItemType; // selectedItemID : property selectedItemID:WideString read Get_selectedItemID; // filter : property filter:WideString read Get_filter; // task : property task:WideString read Get_task; // viewParameters : property viewParameters:WideString read Get_viewParameters; // basketTitle : property basketTitle:WideString read Get_basketTitle; // OnSendMessageComplete : property OnSendMessageComplete:IDispatch write Set_OnSendMessageComplete; // ignoreIEHistory : property ignoreIEHistory:WordBool write Set_ignoreIEHistory; // pluginRunning : property pluginRunning:WordBool read Get_pluginRunning; // templateBeingDisplayedInLocalLibrary : property templateBeingDisplayedInLocalLibrary:WordBool read Get_templateBeingDisplayedInLocalLibrary; // OnChangeViewError : property OnChangeViewError:IDispatch write Set_OnChangeViewError; // OnChangeViewOnlineListError : property OnChangeViewOnlineListError:IDispatch write Set_OnChangeViewOnlineListError; end; // IWMPDiscoExternal : IWMPDiscoExternal: Public interface for scripting object model. IWMPDiscoExternalDisp = dispinterface ['{A915CEA2-72DF-41E1-A576-EF0BAE5E5169}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // NavigateTaskPaneURL : procedure NavigateTaskPaneURL(bstrKeyName:WideString;bstrTaskPane:WideString;bstrParams:WideString);dispid 10026; // attemptLogin : procedure attemptLogin;dispid 10030; // changeView : procedure changeView(bstrLibraryLocationType:WideString;bstrLibraryLocationID:WideString;bstrFilter:WideString;bstrViewParams:WideString);dispid 10033; // changeViewOnlineList : procedure changeViewOnlineList(bstrLibraryLocationType:WideString;bstrLibraryLocationID:WideString;bstrParams:WideString;bstrFriendlyName:WideString;bstrListType:WideString;bstrViewMode:WideString);dispid 10034; // cancelNavigate : procedure cancelNavigate;dispid 10042; // showPopup : procedure showPopup(lPopupIndex:Integer;bstrParameters:WideString);dispid 10043; // addToBasket : procedure addToBasket(bstrViewType:WideString;bstrViewIDs:WideString);dispid 10044; // play : procedure play(bstrLibraryLocationType:WideString;bstrLibraryLocationIDs:WideString);dispid 10046; // download : procedure download(bstrViewType:WideString;bstrViewIDs:WideString);dispid 10047; // buy : procedure buy(bstrViewType:WideString;bstrViewIDs:WideString);dispid 10048; // saveCurrentViewToLibrary : procedure saveCurrentViewToLibrary(bstrFriendlyListType:WideString;fDynamic:WordBool);dispid 10049; // authenticate : procedure authenticate(lAuthenticationIndex:Integer);dispid 10050; // sendMessage : procedure sendMessage(bstrMsg:WideString;bstrParam:WideString);dispid 10051; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; // appColorMedium : property appColorMedium:WideString readonly dispid 10013; // appColorDark : property appColorDark:WideString readonly dispid 10014; // appColorButtonHighlight : property appColorButtonHighlight:WideString readonly dispid 10015; // appColorButtonShadow : property appColorButtonShadow:WideString readonly dispid 10016; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString readonly dispid 10017; // SelectedTaskPane : property SelectedTaskPane:WideString dispid 10027; // DownloadManager : property DownloadManager:IWMPDownloadManager readonly dispid 10009; // OnLoginChange : property OnLoginChange:IDispatch writeonly dispid 10028; // userLoggedIn : property userLoggedIn:WordBool readonly dispid 10029; // accountType : property accountType:WideString readonly dispid 10031; // OnViewChange : property OnViewChange:IDispatch writeonly dispid 10032; // libraryLocationType : property libraryLocationType:WideString readonly dispid 10035; // libraryLocationID : property libraryLocationID:WideString readonly dispid 10036; // selectedItemType : property selectedItemType:WideString readonly dispid 10037; // selectedItemID : property selectedItemID:WideString readonly dispid 10038; // filter : property filter:WideString readonly dispid 10039; // task : property task:WideString readonly dispid 10040; // viewParameters : property viewParameters:WideString readonly dispid 10041; // basketTitle : property basketTitle:WideString readonly dispid 10045; // OnSendMessageComplete : property OnSendMessageComplete:IDispatch writeonly dispid 10052; // ignoreIEHistory : property ignoreIEHistory:WordBool writeonly dispid 10053; // pluginRunning : property pluginRunning:WordBool readonly dispid 10054; // templateBeingDisplayedInLocalLibrary : property templateBeingDisplayedInLocalLibrary:WordBool readonly dispid 10055; // OnChangeViewError : property OnChangeViewError:IDispatch writeonly dispid 10056; // OnChangeViewOnlineListError : property OnChangeViewOnlineListError:IDispatch writeonly dispid 10057; end; // IWMPCDDVDWizardExternal : IWMPCDDVDWizardExternal: Not Public. Internal interface used by Windows Media Player. IWMPCDDVDWizardExternal = interface(IWMPExternalColors) ['{2D7EF888-1D3C-484A-A906-9F49D99BB344}'] // WriteNames : procedure WriteNames(bstrTOC:WideString;bstrMetadata:WideString);safecall; // ReturnToMainTask : procedure ReturnToMainTask;safecall; // WriteNamesEx : procedure WriteNamesEx(type_:WMP_WRITENAMESEX_TYPE;bstrTypeId:WideString;bstrMetadata:WideString;fRenameRegroupFiles:WordBool);safecall; // GetMDQByRequestID : function GetMDQByRequestID(bstrRequestID:WideString):WideString;safecall; // EditMetadata : procedure EditMetadata;safecall; // IsMetadataAvailableForEdit : function IsMetadataAvailableForEdit:WordBool;safecall; // BuyCD : procedure BuyCD(bstrTitle:WideString;bstrArtist:WideString;bstrAlbum:WideString;bstrUFID:WideString;bstrWMID:WideString);safecall; end; // IWMPCDDVDWizardExternal : IWMPCDDVDWizardExternal: Not Public. Internal interface used by Windows Media Player. IWMPCDDVDWizardExternalDisp = dispinterface ['{2D7EF888-1D3C-484A-A906-9F49D99BB344}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // WriteNames : procedure WriteNames(bstrTOC:WideString;bstrMetadata:WideString);dispid 10001; // ReturnToMainTask : procedure ReturnToMainTask;dispid 10002; // WriteNamesEx : procedure WriteNamesEx(type_:WMP_WRITENAMESEX_TYPE;bstrTypeId:WideString;bstrMetadata:WideString;fRenameRegroupFiles:WordBool);dispid 10007; // GetMDQByRequestID : function GetMDQByRequestID(bstrRequestID:WideString):WideString;dispid 10008; // EditMetadata : procedure EditMetadata;dispid 10011; // IsMetadataAvailableForEdit : function IsMetadataAvailableForEdit:WordBool;dispid 10010; // BuyCD : procedure BuyCD(bstrTitle:WideString;bstrArtist:WideString;bstrAlbum:WideString;bstrUFID:WideString;bstrWMID:WideString);dispid 10023; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; // appColorMedium : property appColorMedium:WideString readonly dispid 10013; // appColorDark : property appColorDark:WideString readonly dispid 10014; // appColorButtonHighlight : property appColorButtonHighlight:WideString readonly dispid 10015; // appColorButtonShadow : property appColorButtonShadow:WideString readonly dispid 10016; // appColorButtonHoverFace : property appColorButtonHoverFace:WideString readonly dispid 10017; end; // IWMPBaseExternal : IWMPBaseExternal: Public interface for scripting object model. IWMPBaseExternal = interface(IWMPExternal) ['{F81B2A59-02BC-4003-8B2F-C124AF66FC66}'] end; // IWMPBaseExternal : IWMPBaseExternal: Public interface for scripting object model. IWMPBaseExternalDisp = dispinterface ['{F81B2A59-02BC-4003-8B2F-C124AF66FC66}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; end; // IWMPOfflineExternal : IWMPOfflineExternal: Not Public. Internal interface used by Windows Media Player.. IWMPOfflineExternal = interface(IWMPExternal) ['{3148E685-B243-423D-8341-8480D6EFF674}'] // forceOnline : procedure forceOnline;safecall; end; // IWMPOfflineExternal : IWMPOfflineExternal: Not Public. Internal interface used by Windows Media Player.. IWMPOfflineExternalDisp = dispinterface ['{3148E685-B243-423D-8341-8480D6EFF674}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // forceOnline : procedure forceOnline;dispid 10025; // version : property version:WideString readonly dispid 10005; // appColorLight : property appColorLight:WideString readonly dispid 10012; // OnColorChange : property OnColorChange:IDispatch writeonly dispid 10018; end; // IWMPDMRAVTransportService : IWMPDMRAVTransportService Interface IWMPDMRAVTransportService = interface(IDispatch) ['{4E195DB1-9E29-47FC-9CE1-DE9937D32925}'] function Get_TransportState : WideString; safecall; function Get_TransportStatus : WideString; safecall; function Get_PlaybackStorageMedium : WideString; safecall; function Get_RecordStorageMedium : WideString; safecall; function Get_PossiblePlaybackStorageMedia : WideString; safecall; function Get_PossibleRecordStorageMedia : WideString; safecall; function Get_CurrentPlayMode : WideString; safecall; function Get_TransportPlaySpeed : WideString; safecall; function Get_RecordMediumWriteStatus : WideString; safecall; function Get_CurrentRecordQualityMode : WideString; safecall; function Get_PossibleRecordQualityModes : WideString; safecall; function Get_NumberOfTracks : LongWord; safecall; function Get_CurrentTrack : LongWord; safecall; function Get_CurrentTrackDuration : WideString; safecall; function Get_CurrentMediaDuration : WideString; safecall; function Get_CurrentTrackMetaData : WideString; safecall; function Get_CurrentTrackURI : WideString; safecall; function Get_AVTransportURI : WideString; safecall; function Get_AVTransportURIMetaData : WideString; safecall; function Get_NextAVTransportURI : WideString; safecall; function Get_NextAVTransportURIMetaData : WideString; safecall; function Get_RelativeTimePosition : WideString; safecall; function Get_AbsoluteTimePosition : WideString; safecall; function Get_RelativeCounterPosition : Integer; safecall; function Get_AbsoluteCounterPosition : Integer; safecall; function Get_CurrentTransportActions : WideString; safecall; function Get_LastChange : WideString; safecall; function Get_A_ARG_TYPE_SeekMode : WideString; safecall; function Get_A_ARG_TYPE_SeekTarget : WideString; safecall; function Get_A_ARG_TYPE_InstanceID : LongWord; safecall; function Get_CurrentProtocolInfo : WideString; safecall; // SetAVTransportURI : Method SetAVTransportURI procedure SetAVTransportURI(punkRemoteEndpointInfo:IUnknown;ulInstanceID:LongWord;bstrCurrentURI:WideString;bstrCurrentURIMetaData:WideString);safecall; // GetMediaInfo : Method GetMediaInfo procedure GetMediaInfo(ulInstanceID:LongWord;out pulNumTracks:LongWord;out pbstrMediaDuration:WideString;out pbstrCurrentURI:WideString;out pbstrCurrentURIMetaData:WideString;out pbstrNextURI:WideString;out pNextURIMetaData:WideString;out pbstrPlayMedium:WideString;out pbstrRecordMedium:WideString;out pbstrWriteStatus:WideString);safecall; // GetTransportInfo : Method GetTransportInfo procedure GetTransportInfo(ulInstanceID:LongWord;out pbstrCurrentTransportState:WideString;out pbstrCurrentTransportStatus:WideString;out pbstrCurrentSpeed:WideString);safecall; // GetPositionInfo : Method GetPositionInfo procedure GetPositionInfo(ulInstanceID:LongWord;out pTrack:LongWord;out pbstrTrackDuration:WideString;out pbstrTrackMetaData:WideString;out pbstrTrackURI:WideString;out pbstrRelTime:WideString;out pbstrAbsTime:WideString;out plRelCount:Integer;out plAbsCount:Integer);safecall; // GetDeviceCapabilities : Method GetDeviceCapabilities procedure GetDeviceCapabilities(ulInstanceID:LongWord;out pbstrPlayMedia:WideString;out pbstrRecMedia:WideString;out pbstrRecQualityModes:WideString);safecall; // GetTransportSettings : Method GetTransportSettings procedure GetTransportSettings(ulInstanceID:LongWord;out pbstrPlayMode:WideString;out pbstrRecQualityMode:WideString);safecall; // stop : Method Stop procedure stop(ulInstanceID:LongWord);safecall; // play : Method Play procedure play(ulInstanceID:LongWord;bstrSpeed:WideString);safecall; // pause : Method Pause procedure pause(ulInstanceID:LongWord);safecall; // Seek : Method Seek procedure Seek(ulInstanceID:LongWord;bstrUnit:WideString;bstrTarget:WideString);safecall; // next : Method Next procedure next(ulInstanceID:LongWord);safecall; // previous : Method Previous procedure previous(ulInstanceID:LongWord);safecall; // GetCurrentTransportActions : Method GetCurrentTransportActions procedure GetCurrentTransportActions(ulInstanceID:LongWord;var pbstrActions:WideString);safecall; // SetNextAVTransportURI : Method SetNextAVTransportURI procedure SetNextAVTransportURI(punkRemoteEndpointInfo:IUnknown;ulInstanceID:LongWord;bstrNextURI:WideString;bstrNextURIMetaData:WideString);safecall; // TransportState : Property TransportState property TransportState:WideString read Get_TransportState; // TransportStatus : Property TransportStatus property TransportStatus:WideString read Get_TransportStatus; // PlaybackStorageMedium : Property PlaybackStorageMedium property PlaybackStorageMedium:WideString read Get_PlaybackStorageMedium; // RecordStorageMedium : Property RecordStorageMedium property RecordStorageMedium:WideString read Get_RecordStorageMedium; // PossiblePlaybackStorageMedia : Property PossiblePlaybackStorageMedia property PossiblePlaybackStorageMedia:WideString read Get_PossiblePlaybackStorageMedia; // PossibleRecordStorageMedia : Property PossibleRecordStorageMedia property PossibleRecordStorageMedia:WideString read Get_PossibleRecordStorageMedia; // CurrentPlayMode : Property CurrentPlayMode property CurrentPlayMode:WideString read Get_CurrentPlayMode; // TransportPlaySpeed : Property TransportPlaySpeed property TransportPlaySpeed:WideString read Get_TransportPlaySpeed; // RecordMediumWriteStatus : Property RecordMediumWriteStatus property RecordMediumWriteStatus:WideString read Get_RecordMediumWriteStatus; // CurrentRecordQualityMode : Property CurrentRecordQualityMode property CurrentRecordQualityMode:WideString read Get_CurrentRecordQualityMode; // PossibleRecordQualityModes : Property PossibleRecordQualityModes property PossibleRecordQualityModes:WideString read Get_PossibleRecordQualityModes; // NumberOfTracks : Property NumberOfTracks property NumberOfTracks:LongWord read Get_NumberOfTracks; // CurrentTrack : Property CurrentTrack property CurrentTrack:LongWord read Get_CurrentTrack; // CurrentTrackDuration : Property CurrentTrackDuration property CurrentTrackDuration:WideString read Get_CurrentTrackDuration; // CurrentMediaDuration : Property CurrentMediaDuration property CurrentMediaDuration:WideString read Get_CurrentMediaDuration; // CurrentTrackMetaData : Property CurrentTrackMetaData property CurrentTrackMetaData:WideString read Get_CurrentTrackMetaData; // CurrentTrackURI : Property CurrentTrackURI property CurrentTrackURI:WideString read Get_CurrentTrackURI; // AVTransportURI : Property AVTransportURI property AVTransportURI:WideString read Get_AVTransportURI; // AVTransportURIMetaData : Property AVTransportURIMetaData property AVTransportURIMetaData:WideString read Get_AVTransportURIMetaData; // NextAVTransportURI : Property NextAVTransportURI property NextAVTransportURI:WideString read Get_NextAVTransportURI; // NextAVTransportURIMetaData : Property NextAVTransportURIMetaData property NextAVTransportURIMetaData:WideString read Get_NextAVTransportURIMetaData; // RelativeTimePosition : Property RelativeTimePosition property RelativeTimePosition:WideString read Get_RelativeTimePosition; // AbsoluteTimePosition : Property AbsoluteTimePosition property AbsoluteTimePosition:WideString read Get_AbsoluteTimePosition; // RelativeCounterPosition : Property RelativeCounterPosition property RelativeCounterPosition:Integer read Get_RelativeCounterPosition; // AbsoluteCounterPosition : Property AbsoluteCounterPosition property AbsoluteCounterPosition:Integer read Get_AbsoluteCounterPosition; // CurrentTransportActions : Property CurrentTransportActions property CurrentTransportActions:WideString read Get_CurrentTransportActions; // LastChange : Property LastChange property LastChange:WideString read Get_LastChange; // A_ARG_TYPE_SeekMode : Property A_ARG_TYPE_SeekMode property A_ARG_TYPE_SeekMode:WideString read Get_A_ARG_TYPE_SeekMode; // A_ARG_TYPE_SeekTarget : Property A_ARG_TYPE_SeekTarget property A_ARG_TYPE_SeekTarget:WideString read Get_A_ARG_TYPE_SeekTarget; // A_ARG_TYPE_InstanceID : Property A_ARG_TYPE_InstanceID property A_ARG_TYPE_InstanceID:LongWord read Get_A_ARG_TYPE_InstanceID; // CurrentProtocolInfo : Property CurrentProtocolInfo property CurrentProtocolInfo:WideString read Get_CurrentProtocolInfo; end; // IWMPDMRAVTransportService : IWMPDMRAVTransportService Interface IWMPDMRAVTransportServiceDisp = dispinterface ['{4E195DB1-9E29-47FC-9CE1-DE9937D32925}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // SetAVTransportURI : Method SetAVTransportURI procedure SetAVTransportURI(punkRemoteEndpointInfo:IUnknown;ulInstanceID:LongWord;bstrCurrentURI:WideString;bstrCurrentURIMetaData:WideString);dispid 31; // GetMediaInfo : Method GetMediaInfo procedure GetMediaInfo(ulInstanceID:LongWord;out pulNumTracks:LongWord;out pbstrMediaDuration:WideString;out pbstrCurrentURI:WideString;out pbstrCurrentURIMetaData:WideString;out pbstrNextURI:WideString;out pNextURIMetaData:WideString;out pbstrPlayMedium:WideString;out pbstrRecordMedium:WideString;out pbstrWriteStatus:WideString);dispid 33; // GetTransportInfo : Method GetTransportInfo procedure GetTransportInfo(ulInstanceID:LongWord;out pbstrCurrentTransportState:WideString;out pbstrCurrentTransportStatus:WideString;out pbstrCurrentSpeed:WideString);dispid 34; // GetPositionInfo : Method GetPositionInfo procedure GetPositionInfo(ulInstanceID:LongWord;out pTrack:LongWord;out pbstrTrackDuration:WideString;out pbstrTrackMetaData:WideString;out pbstrTrackURI:WideString;out pbstrRelTime:WideString;out pbstrAbsTime:WideString;out plRelCount:Integer;out plAbsCount:Integer);dispid 35; // GetDeviceCapabilities : Method GetDeviceCapabilities procedure GetDeviceCapabilities(ulInstanceID:LongWord;out pbstrPlayMedia:WideString;out pbstrRecMedia:WideString;out pbstrRecQualityModes:WideString);dispid 36; // GetTransportSettings : Method GetTransportSettings procedure GetTransportSettings(ulInstanceID:LongWord;out pbstrPlayMode:WideString;out pbstrRecQualityMode:WideString);dispid 37; // stop : Method Stop procedure stop(ulInstanceID:LongWord);dispid 38; // play : Method Play procedure play(ulInstanceID:LongWord;bstrSpeed:WideString);dispid 39; // pause : Method Pause procedure pause(ulInstanceID:LongWord);dispid 40; // Seek : Method Seek procedure Seek(ulInstanceID:LongWord;bstrUnit:WideString;bstrTarget:WideString);dispid 41; // next : Method Next procedure next(ulInstanceID:LongWord);dispid 42; // previous : Method Previous procedure previous(ulInstanceID:LongWord);dispid 43; // GetCurrentTransportActions : Method GetCurrentTransportActions procedure GetCurrentTransportActions(ulInstanceID:LongWord;var pbstrActions:WideString);dispid 44; // SetNextAVTransportURI : Method SetNextAVTransportURI procedure SetNextAVTransportURI(punkRemoteEndpointInfo:IUnknown;ulInstanceID:LongWord;bstrNextURI:WideString;bstrNextURIMetaData:WideString);dispid 32; // TransportState : Property TransportState property TransportState:WideString readonly dispid 1; // TransportStatus : Property TransportStatus property TransportStatus:WideString readonly dispid 2; // PlaybackStorageMedium : Property PlaybackStorageMedium property PlaybackStorageMedium:WideString readonly dispid 3; // RecordStorageMedium : Property RecordStorageMedium property RecordStorageMedium:WideString readonly dispid 4; // PossiblePlaybackStorageMedia : Property PossiblePlaybackStorageMedia property PossiblePlaybackStorageMedia:WideString readonly dispid 5; // PossibleRecordStorageMedia : Property PossibleRecordStorageMedia property PossibleRecordStorageMedia:WideString readonly dispid 6; // CurrentPlayMode : Property CurrentPlayMode property CurrentPlayMode:WideString readonly dispid 7; // TransportPlaySpeed : Property TransportPlaySpeed property TransportPlaySpeed:WideString readonly dispid 8; // RecordMediumWriteStatus : Property RecordMediumWriteStatus property RecordMediumWriteStatus:WideString readonly dispid 9; // CurrentRecordQualityMode : Property CurrentRecordQualityMode property CurrentRecordQualityMode:WideString readonly dispid 10; // PossibleRecordQualityModes : Property PossibleRecordQualityModes property PossibleRecordQualityModes:WideString readonly dispid 11; // NumberOfTracks : Property NumberOfTracks property NumberOfTracks:LongWord readonly dispid 12; // CurrentTrack : Property CurrentTrack property CurrentTrack:LongWord readonly dispid 13; // CurrentTrackDuration : Property CurrentTrackDuration property CurrentTrackDuration:WideString readonly dispid 14; // CurrentMediaDuration : Property CurrentMediaDuration property CurrentMediaDuration:WideString readonly dispid 15; // CurrentTrackMetaData : Property CurrentTrackMetaData property CurrentTrackMetaData:WideString readonly dispid 16; // CurrentTrackURI : Property CurrentTrackURI property CurrentTrackURI:WideString readonly dispid 17; // AVTransportURI : Property AVTransportURI property AVTransportURI:WideString readonly dispid 18; // AVTransportURIMetaData : Property AVTransportURIMetaData property AVTransportURIMetaData:WideString readonly dispid 19; // NextAVTransportURI : Property NextAVTransportURI property NextAVTransportURI:WideString readonly dispid 20; // NextAVTransportURIMetaData : Property NextAVTransportURIMetaData property NextAVTransportURIMetaData:WideString readonly dispid 21; // RelativeTimePosition : Property RelativeTimePosition property RelativeTimePosition:WideString readonly dispid 22; // AbsoluteTimePosition : Property AbsoluteTimePosition property AbsoluteTimePosition:WideString readonly dispid 23; // RelativeCounterPosition : Property RelativeCounterPosition property RelativeCounterPosition:Integer readonly dispid 24; // AbsoluteCounterPosition : Property AbsoluteCounterPosition property AbsoluteCounterPosition:Integer readonly dispid 25; // CurrentTransportActions : Property CurrentTransportActions property CurrentTransportActions:WideString readonly dispid 26; // LastChange : Property LastChange property LastChange:WideString readonly dispid 27; // A_ARG_TYPE_SeekMode : Property A_ARG_TYPE_SeekMode property A_ARG_TYPE_SeekMode:WideString readonly dispid 28; // A_ARG_TYPE_SeekTarget : Property A_ARG_TYPE_SeekTarget property A_ARG_TYPE_SeekTarget:WideString readonly dispid 29; // A_ARG_TYPE_InstanceID : Property A_ARG_TYPE_InstanceID property A_ARG_TYPE_InstanceID:LongWord readonly dispid 30; // CurrentProtocolInfo : Property CurrentProtocolInfo property CurrentProtocolInfo:WideString readonly dispid 45; end; // IWMPDMRConnectionManagerService : IWMPDMRConnectionManagerService = interface(IDispatch) ['{FB61CD38-8DE7-4479-8B76-A8D097C20C70}'] function Get_SourceProtocolInfo : WideString; safecall; function Get_SinkProtocolInfo : WideString; safecall; function Get_CurrentConnectionIDs : WideString; safecall; function Get_A_ARG_TYPE_ConnectionStatus : WideString; safecall; function Get_A_ARG_TYPE_ConnectionManager : WideString; safecall; function Get_A_ARG_TYPE_Direction : WideString; safecall; function Get_A_ARG_TYPE_ProtocolInfo : WideString; safecall; function Get_A_ARG_TYPE_ConnectionID : Integer; safecall; function Get_A_ARG_TYPE_AVTransportID : Integer; safecall; function Get_A_ARG_TYPE_RcsID : Integer; safecall; // GetProtocolInfo : Method GetProtocolInfo procedure GetProtocolInfo(var pbstrSource:WideString;var pbstrSink:WideString);safecall; // GetCurrentConnectionIDs : Method GetCurrentConnectionIDs procedure GetCurrentConnectionIDs(var pbstrConnectionIDs:WideString);safecall; // GetCurrentConnectionInfo : Method GetCurrentConnectionInfo procedure GetCurrentConnectionInfo(lConnectionID:Integer;var plResID:Integer;var plAVTransportID:Integer;var pbstrProtocolInfo:WideString;var pbstrPeerConnectionManager:WideString;var plPeerConnectionID:Integer;var pbstrDirection:WideString;var pbstrStatus:WideString);safecall; // SourceProtocolInfo : Property SourceProtocolInfo property SourceProtocolInfo:WideString read Get_SourceProtocolInfo; // SinkProtocolInfo : Property SinkProtocolInfo property SinkProtocolInfo:WideString read Get_SinkProtocolInfo; // CurrentConnectionIDs : Property CurrentConnectionIDs property CurrentConnectionIDs:WideString read Get_CurrentConnectionIDs; // A_ARG_TYPE_ConnectionStatus : Property A_ARG_TYPE_ConnectionStatus property A_ARG_TYPE_ConnectionStatus:WideString read Get_A_ARG_TYPE_ConnectionStatus; // A_ARG_TYPE_ConnectionManager : Property A_ARG_TYPE_ConnectionManager property A_ARG_TYPE_ConnectionManager:WideString read Get_A_ARG_TYPE_ConnectionManager; // A_ARG_TYPE_Direction : Property A_ARG_TYPE_Direction property A_ARG_TYPE_Direction:WideString read Get_A_ARG_TYPE_Direction; // A_ARG_TYPE_ProtocolInfo : Property A_ARG_TYPE_ProtocolInfo property A_ARG_TYPE_ProtocolInfo:WideString read Get_A_ARG_TYPE_ProtocolInfo; // A_ARG_TYPE_ConnectionID : Property A_ARG_TYPE_ConnectionID property A_ARG_TYPE_ConnectionID:Integer read Get_A_ARG_TYPE_ConnectionID; // A_ARG_TYPE_AVTransportID : Property A_ARG_TYPE_AVTransportID property A_ARG_TYPE_AVTransportID:Integer read Get_A_ARG_TYPE_AVTransportID; // A_ARG_TYPE_RcsID : Property A_ARG_TYPE_RcsID property A_ARG_TYPE_RcsID:Integer read Get_A_ARG_TYPE_RcsID; end; // IWMPDMRConnectionManagerService : IWMPDMRConnectionManagerServiceDisp = dispinterface ['{FB61CD38-8DE7-4479-8B76-A8D097C20C70}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // GetProtocolInfo : Method GetProtocolInfo procedure GetProtocolInfo(var pbstrSource:WideString;var pbstrSink:WideString);dispid 11; // GetCurrentConnectionIDs : Method GetCurrentConnectionIDs procedure GetCurrentConnectionIDs(var pbstrConnectionIDs:WideString);dispid 12; // GetCurrentConnectionInfo : Method GetCurrentConnectionInfo procedure GetCurrentConnectionInfo(lConnectionID:Integer;var plResID:Integer;var plAVTransportID:Integer;var pbstrProtocolInfo:WideString;var pbstrPeerConnectionManager:WideString;var plPeerConnectionID:Integer;var pbstrDirection:WideString;var pbstrStatus:WideString);dispid 13; // SourceProtocolInfo : Property SourceProtocolInfo property SourceProtocolInfo:WideString readonly dispid 1; // SinkProtocolInfo : Property SinkProtocolInfo property SinkProtocolInfo:WideString readonly dispid 2; // CurrentConnectionIDs : Property CurrentConnectionIDs property CurrentConnectionIDs:WideString readonly dispid 3; // A_ARG_TYPE_ConnectionStatus : Property A_ARG_TYPE_ConnectionStatus property A_ARG_TYPE_ConnectionStatus:WideString readonly dispid 4; // A_ARG_TYPE_ConnectionManager : Property A_ARG_TYPE_ConnectionManager property A_ARG_TYPE_ConnectionManager:WideString readonly dispid 5; // A_ARG_TYPE_Direction : Property A_ARG_TYPE_Direction property A_ARG_TYPE_Direction:WideString readonly dispid 6; // A_ARG_TYPE_ProtocolInfo : Property A_ARG_TYPE_ProtocolInfo property A_ARG_TYPE_ProtocolInfo:WideString readonly dispid 7; // A_ARG_TYPE_ConnectionID : Property A_ARG_TYPE_ConnectionID property A_ARG_TYPE_ConnectionID:Integer readonly dispid 8; // A_ARG_TYPE_AVTransportID : Property A_ARG_TYPE_AVTransportID property A_ARG_TYPE_AVTransportID:Integer readonly dispid 9; // A_ARG_TYPE_RcsID : Property A_ARG_TYPE_RcsID property A_ARG_TYPE_RcsID:Integer readonly dispid 10; end; // IWMPDMRRenderingControlService : IWMPDMRRenderingControlService Interface IWMPDMRRenderingControlService = interface(IDispatch) ['{FF4B1BDA-19F0-42CF-8DDA-19162950C543}'] function Get_LastChange : WideString; safecall; function Get_PresetNameList : WideString; safecall; function Get_mute : WordBool; safecall; function Get_volume : Word; safecall; function Get_A_ARG_TYPE_Channel : WideString; safecall; function Get_A_ARG_TYPE_InstanceID : LongWord; safecall; function Get_A_ARG_TYPE_PresetName : WideString; safecall; // ListPresets : Method ListPresets procedure ListPresets(ulInstanceID:LongWord;var pbstrCurrentPresetList:WideString);safecall; // SelectPreset : Method SelectPreset procedure SelectPreset(ulInstanceID:LongWord;bstrPresetName:WideString);safecall; // GetMute : Method GetMute procedure GetMute(ulInstanceID:LongWord;bstrChannel:WideString;var pbCurrentMute:WordBool);safecall; // SetMute : Method SetMute procedure SetMute(ulInstanceID:LongWord;bstrChannel:WideString;bDesiredMute:WordBool);safecall; // GetVolume : Method GetVolume procedure GetVolume(ulInstanceID:LongWord;bstrChannel:WideString;var puiCurrentVolume:Word);safecall; // SetVolume : Method SetVolume procedure SetVolume(ulInstanceID:LongWord;bstrChannel:WideString;uiDesiredVolume:Word);safecall; // LastChange : Property LastChange property LastChange:WideString read Get_LastChange; // PresetNameList : Property PresetNameList property PresetNameList:WideString read Get_PresetNameList; // mute : Property Mute property mute:WordBool read Get_mute; // volume : Property Volume property volume:Word read Get_volume; // A_ARG_TYPE_Channel : Property A_ARG_TYPE_Channel property A_ARG_TYPE_Channel:WideString read Get_A_ARG_TYPE_Channel; // A_ARG_TYPE_InstanceID : Property A_ARG_TYPE_InstanceID property A_ARG_TYPE_InstanceID:LongWord read Get_A_ARG_TYPE_InstanceID; // A_ARG_TYPE_PresetName : Property A_ARG_TYPE_PresetName property A_ARG_TYPE_PresetName:WideString read Get_A_ARG_TYPE_PresetName; end; // IWMPDMRRenderingControlService : IWMPDMRRenderingControlService Interface IWMPDMRRenderingControlServiceDisp = dispinterface ['{FF4B1BDA-19F0-42CF-8DDA-19162950C543}'] // QueryInterface : procedure QueryInterface(var riid:{!! GUID !!} OleVariant;out ppvObj:{!! Ppointer !!} OleVariant);dispid 1610612736; // AddRef : function AddRef:LongWord;dispid 1610612737; // Release : function Release:LongWord;dispid 1610612738; // GetTypeInfoCount : procedure GetTypeInfoCount(out pctinfo:UInt);dispid 1610678272; // GetTypeInfo : procedure GetTypeInfo(itinfo:UInt;lcid:LongWord;out pptinfo:{!! Ppointer !!} OleVariant);dispid 1610678273; // GetIDsOfNames : procedure GetIDsOfNames(var riid:{!! GUID !!} OleVariant;var rgszNames:{!! PShortInt !!} OleVariant;cNames:UInt;lcid:LongWord;out rgdispid:Integer);dispid 1610678274; // Invoke : procedure Invoke(dispidMember:Integer;var riid:{!! GUID !!} OleVariant;lcid:LongWord;wFlags:Word;var pdispparams:{!! DISPPARAMS !!} OleVariant;out pvarResult:OleVariant;out pexcepinfo:{!! EXCEPINFO !!} OleVariant;out puArgErr:UInt);dispid 1610678275; // ListPresets : Method ListPresets procedure ListPresets(ulInstanceID:LongWord;var pbstrCurrentPresetList:WideString);dispid 8; // SelectPreset : Method SelectPreset procedure SelectPreset(ulInstanceID:LongWord;bstrPresetName:WideString);dispid 9; // GetMute : Method GetMute procedure GetMute(ulInstanceID:LongWord;bstrChannel:WideString;var pbCurrentMute:WordBool);dispid 10; // SetMute : Method SetMute procedure SetMute(ulInstanceID:LongWord;bstrChannel:WideString;bDesiredMute:WordBool);dispid 11; // GetVolume : Method GetVolume procedure GetVolume(ulInstanceID:LongWord;bstrChannel:WideString;var puiCurrentVolume:Word);dispid 12; // SetVolume : Method SetVolume procedure SetVolume(ulInstanceID:LongWord;bstrChannel:WideString;uiDesiredVolume:Word);dispid 13; // LastChange : Property LastChange property LastChange:WideString readonly dispid 1; // PresetNameList : Property PresetNameList property PresetNameList:WideString readonly dispid 2; // mute : Property Mute property mute:WordBool readonly dispid 3; // volume : Property Volume property volume:Word readonly dispid 4; // A_ARG_TYPE_Channel : Property A_ARG_TYPE_Channel property A_ARG_TYPE_Channel:WideString readonly dispid 5; // A_ARG_TYPE_InstanceID : Property A_ARG_TYPE_InstanceID property A_ARG_TYPE_InstanceID:LongWord readonly dispid 6; // A_ARG_TYPE_PresetName : Property A_ARG_TYPE_PresetName property A_ARG_TYPE_PresetName:WideString readonly dispid 7; end; //CoClasses T_WMPOCXEventsOpenStateChange = procedure(Sender: TObject;NewState:Integer) of object; T_WMPOCXEventsPlayStateChange = procedure(Sender: TObject;NewState:Integer) of object; T_WMPOCXEventsAudioLanguageChange = procedure(Sender: TObject;LangID:Integer) of object; T_WMPOCXEventsStatusChange = procedure(Sender: TObject) of object; T_WMPOCXEventsScriptCommand = procedure(Sender: TObject;scType:WideString;Param:WideString) of object; T_WMPOCXEventsNewStream = procedure(Sender: TObject) of object; T_WMPOCXEventsDisconnect = procedure(Sender: TObject;Result:Integer) of object; T_WMPOCXEventsBuffering = procedure(Sender: TObject;Start:WordBool) of object; T_WMPOCXEventsError = procedure(Sender: TObject) of object; T_WMPOCXEventsWarning = procedure(Sender: TObject;WarningType:Integer;Param:Integer;Description:WideString) of object; T_WMPOCXEventsEndOfStream = procedure(Sender: TObject;Result:Integer) of object; T_WMPOCXEventsPositionChange = procedure(Sender: TObject;oldPosition:Double;newPosition:Double) of object; T_WMPOCXEventsMarkerHit = procedure(Sender: TObject;MarkerNum:Integer) of object; T_WMPOCXEventsDurationUnitChange = procedure(Sender: TObject;NewDurationUnit:Integer) of object; T_WMPOCXEventsCdromMediaChange = procedure(Sender: TObject;CdromNum:Integer) of object; T_WMPOCXEventsPlaylistChange = procedure(Sender: TObject;Playlist:IDispatch;change:WMPPlaylistChangeEventType) of object; T_WMPOCXEventsCurrentPlaylistChange = procedure(Sender: TObject;change:WMPPlaylistChangeEventType) of object; T_WMPOCXEventsCurrentPlaylistItemAvailable = procedure(Sender: TObject;bstrItemName:WideString) of object; T_WMPOCXEventsMediaChange = procedure(Sender: TObject;Item:IDispatch) of object; T_WMPOCXEventsCurrentMediaItemAvailable = procedure(Sender: TObject;bstrItemName:WideString) of object; T_WMPOCXEventsCurrentItemChange = procedure(Sender: TObject;pdispMedia:IDispatch) of object; T_WMPOCXEventsMediaCollectionChange = procedure(Sender: TObject) of object; T_WMPOCXEventsMediaCollectionAttributeStringAdded = procedure(Sender: TObject;bstrAttribName:WideString;bstrAttribVal:WideString) of object; T_WMPOCXEventsMediaCollectionAttributeStringRemoved = procedure(Sender: TObject;bstrAttribName:WideString;bstrAttribVal:WideString) of object; T_WMPOCXEventsMediaCollectionAttributeStringChanged = procedure(Sender: TObject;bstrAttribName:WideString;bstrOldAttribVal:WideString;bstrNewAttribVal:WideString) of object; T_WMPOCXEventsPlaylistCollectionChange = procedure(Sender: TObject) of object; T_WMPOCXEventsPlaylistCollectionPlaylistAdded = procedure(Sender: TObject;bstrPlaylistName:WideString) of object; T_WMPOCXEventsPlaylistCollectionPlaylistRemoved = procedure(Sender: TObject;bstrPlaylistName:WideString) of object; T_WMPOCXEventsPlaylistCollectionPlaylistSetAsDeleted = procedure(Sender: TObject;bstrPlaylistName:WideString;varfIsDeleted:WordBool) of object; T_WMPOCXEventsModeChange = procedure(Sender: TObject;ModeName:WideString;NewValue:WordBool) of object; T_WMPOCXEventsMediaError = procedure(Sender: TObject;pMediaObject:IDispatch) of object; T_WMPOCXEventsOpenPlaylistSwitch = procedure(Sender: TObject;pItem:IDispatch) of object; T_WMPOCXEventsDomainChange = procedure(Sender: TObject;strDomain:WideString) of object; T_WMPOCXEventsSwitchedToPlayerApplication = procedure(Sender: TObject) of object; T_WMPOCXEventsSwitchedToControl = procedure(Sender: TObject) of object; T_WMPOCXEventsPlayerDockedStateChange = procedure(Sender: TObject) of object; T_WMPOCXEventsPlayerReconnect = procedure(Sender: TObject) of object; T_WMPOCXEventsClick = procedure(Sender: TObject;nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer) of object; T_WMPOCXEventsDoubleClick = procedure(Sender: TObject;nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer) of object; T_WMPOCXEventsKeyDown = procedure(Sender: TObject;nKeyCode:Smallint;nShiftState:Smallint) of object; T_WMPOCXEventsKeyPress = procedure(Sender: TObject;nKeyAscii:Smallint) of object; T_WMPOCXEventsKeyUp = procedure(Sender: TObject;nKeyCode:Smallint;nShiftState:Smallint) of object; T_WMPOCXEventsMouseDown = procedure(Sender: TObject;nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer) of object; T_WMPOCXEventsMouseMove = procedure(Sender: TObject;nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer) of object; T_WMPOCXEventsMouseUp = procedure(Sender: TObject;nButton:Smallint;nShiftState:Smallint;fX:Integer;fY:Integer) of object; T_WMPOCXEventsDeviceConnect = procedure(Sender: TObject;pDevice:IWMPSyncDevice) of object; T_WMPOCXEventsDeviceDisconnect = procedure(Sender: TObject;pDevice:IWMPSyncDevice) of object; T_WMPOCXEventsDeviceStatusChange = procedure(Sender: TObject;pDevice:IWMPSyncDevice;NewStatus:WMPDeviceStatus) of object; T_WMPOCXEventsDeviceSyncStateChange = procedure(Sender: TObject;pDevice:IWMPSyncDevice;NewState:WMPSyncState) of object; T_WMPOCXEventsDeviceSyncError = procedure(Sender: TObject;pDevice:IWMPSyncDevice;pMedia:IDispatch) of object; T_WMPOCXEventsCreatePartnershipComplete = procedure(Sender: TObject;pDevice:IWMPSyncDevice;hrResult:HResult) of object; T_WMPOCXEventsDeviceEstimation = procedure(Sender: TObject;pDevice:IWMPSyncDevice;hrResult:HResult;qwEstimatedUsedSpace:Int64;qwEstimatedSpace:Int64) of object; T_WMPOCXEventsCdromRipStateChange = procedure(Sender: TObject;pCdromRip:IWMPCdromRip;wmprs:WMPRipState) of object; T_WMPOCXEventsCdromRipMediaError = procedure(Sender: TObject;pCdromRip:IWMPCdromRip;pMedia:IDispatch) of object; T_WMPOCXEventsCdromBurnStateChange = procedure(Sender: TObject;pCdromBurn:IWMPCdromBurn;wmpbs:WMPBurnState) of object; T_WMPOCXEventsCdromBurnMediaError = procedure(Sender: TObject;pCdromBurn:IWMPCdromBurn;pMedia:IDispatch) of object; T_WMPOCXEventsCdromBurnError = procedure(Sender: TObject;pCdromBurn:IWMPCdromBurn;hrError:HResult) of object; T_WMPOCXEventsLibraryConnect = procedure(Sender: TObject;pLibrary:IWMPLibrary) of object; T_WMPOCXEventsLibraryDisconnect = procedure(Sender: TObject;pLibrary:IWMPLibrary) of object; T_WMPOCXEventsFolderScanStateChange = procedure(Sender: TObject;wmpfss:WMPFolderScanState) of object; T_WMPOCXEventsStringCollectionChange = procedure(Sender: TObject;pdispStringCollection:IDispatch;change:WMPStringCollectionChangeEventType;lCollectionIndex:Integer) of object; T_WMPOCXEventsMediaCollectionMediaAdded = procedure(Sender: TObject;pdispMedia:IDispatch) of object; T_WMPOCXEventsMediaCollectionMediaRemoved = procedure(Sender: TObject;pdispMedia:IDispatch) of object; CoWindowsMediaPlayer = Class Public Class Function Create: IWMPPlayer4; Class Function CreateRemote(const MachineName: string): IWMPPlayer4; end; TEvsWindowsMediaPlayer = Class(TEventSink) Private FOnOpenStateChange:T_WMPOCXEventsOpenStateChange; FOnPlayStateChange:T_WMPOCXEventsPlayStateChange; FOnAudioLanguageChange:T_WMPOCXEventsAudioLanguageChange; FOnStatusChange:T_WMPOCXEventsStatusChange; FOnScriptCommand:T_WMPOCXEventsScriptCommand; FOnNewStream:T_WMPOCXEventsNewStream; FOnDisconnect:T_WMPOCXEventsDisconnect; FOnBuffering:T_WMPOCXEventsBuffering; FOnError:T_WMPOCXEventsError; FOnWarning:T_WMPOCXEventsWarning; FOnEndOfStream:T_WMPOCXEventsEndOfStream; FOnPositionChange:T_WMPOCXEventsPositionChange; FOnMarkerHit:T_WMPOCXEventsMarkerHit; FOnDurationUnitChange:T_WMPOCXEventsDurationUnitChange; FOnCdromMediaChange:T_WMPOCXEventsCdromMediaChange; FOnPlaylistChange:T_WMPOCXEventsPlaylistChange; FOnCurrentPlaylistChange:T_WMPOCXEventsCurrentPlaylistChange; FOnCurrentPlaylistItemAvailable:T_WMPOCXEventsCurrentPlaylistItemAvailable; FOnMediaChange:T_WMPOCXEventsMediaChange; FOnCurrentMediaItemAvailable:T_WMPOCXEventsCurrentMediaItemAvailable; FOnCurrentItemChange:T_WMPOCXEventsCurrentItemChange; FOnMediaCollectionChange:T_WMPOCXEventsMediaCollectionChange; FOnMediaCollectionAttributeStringAdded:T_WMPOCXEventsMediaCollectionAttributeStringAdded; FOnMediaCollectionAttributeStringRemoved:T_WMPOCXEventsMediaCollectionAttributeStringRemoved; FOnMediaCollectionAttributeStringChanged:T_WMPOCXEventsMediaCollectionAttributeStringChanged; FOnPlaylistCollectionChange:T_WMPOCXEventsPlaylistCollectionChange; FOnPlaylistCollectionPlaylistAdded:T_WMPOCXEventsPlaylistCollectionPlaylistAdded; FOnPlaylistCollectionPlaylistRemoved:T_WMPOCXEventsPlaylistCollectionPlaylistRemoved; FOnPlaylistCollectionPlaylistSetAsDeleted:T_WMPOCXEventsPlaylistCollectionPlaylistSetAsDeleted; FOnModeChange:T_WMPOCXEventsModeChange; FOnMediaError:T_WMPOCXEventsMediaError; FOnOpenPlaylistSwitch:T_WMPOCXEventsOpenPlaylistSwitch; FOnDomainChange:T_WMPOCXEventsDomainChange; FOnSwitchedToPlayerApplication:T_WMPOCXEventsSwitchedToPlayerApplication; FOnSwitchedToControl:T_WMPOCXEventsSwitchedToControl; FOnPlayerDockedStateChange:T_WMPOCXEventsPlayerDockedStateChange; FOnPlayerReconnect:T_WMPOCXEventsPlayerReconnect; FOnClick:T_WMPOCXEventsClick; FOnDoubleClick:T_WMPOCXEventsDoubleClick; FOnKeyDown:T_WMPOCXEventsKeyDown; FOnKeyPress:T_WMPOCXEventsKeyPress; FOnKeyUp:T_WMPOCXEventsKeyUp; FOnMouseDown:T_WMPOCXEventsMouseDown; FOnMouseMove:T_WMPOCXEventsMouseMove; FOnMouseUp:T_WMPOCXEventsMouseUp; FOnDeviceConnect:T_WMPOCXEventsDeviceConnect; FOnDeviceDisconnect:T_WMPOCXEventsDeviceDisconnect; FOnDeviceStatusChange:T_WMPOCXEventsDeviceStatusChange; FOnDeviceSyncStateChange:T_WMPOCXEventsDeviceSyncStateChange; FOnDeviceSyncError:T_WMPOCXEventsDeviceSyncError; FOnCreatePartnershipComplete:T_WMPOCXEventsCreatePartnershipComplete; FOnDeviceEstimation:T_WMPOCXEventsDeviceEstimation; FOnCdromRipStateChange:T_WMPOCXEventsCdromRipStateChange; FOnCdromRipMediaError:T_WMPOCXEventsCdromRipMediaError; FOnCdromBurnStateChange:T_WMPOCXEventsCdromBurnStateChange; FOnCdromBurnMediaError:T_WMPOCXEventsCdromBurnMediaError; FOnCdromBurnError:T_WMPOCXEventsCdromBurnError; FOnLibraryConnect:T_WMPOCXEventsLibraryConnect; FOnLibraryDisconnect:T_WMPOCXEventsLibraryDisconnect; FOnFolderScanStateChange:T_WMPOCXEventsFolderScanStateChange; FOnStringCollectionChange:T_WMPOCXEventsStringCollectionChange; FOnMediaCollectionMediaAdded:T_WMPOCXEventsMediaCollectionMediaAdded; FOnMediaCollectionMediaRemoved:T_WMPOCXEventsMediaCollectionMediaRemoved; fServer:IWMPPlayer4; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPPlayer4 read fServer; property OnOpenStateChange : T_WMPOCXEventsOpenStateChange read FOnOpenStateChange write FOnOpenStateChange; property OnPlayStateChange : T_WMPOCXEventsPlayStateChange read FOnPlayStateChange write FOnPlayStateChange; property OnAudioLanguageChange : T_WMPOCXEventsAudioLanguageChange read FOnAudioLanguageChange write FOnAudioLanguageChange; property OnStatusChange : T_WMPOCXEventsStatusChange read FOnStatusChange write FOnStatusChange; property OnScriptCommand : T_WMPOCXEventsScriptCommand read FOnScriptCommand write FOnScriptCommand; property OnNewStream : T_WMPOCXEventsNewStream read FOnNewStream write FOnNewStream; property OnDisconnect : T_WMPOCXEventsDisconnect read FOnDisconnect write FOnDisconnect; property OnBuffering : T_WMPOCXEventsBuffering read FOnBuffering write FOnBuffering; property OnError : T_WMPOCXEventsError read FOnError write FOnError; property OnWarning : T_WMPOCXEventsWarning read FOnWarning write FOnWarning; property OnEndOfStream : T_WMPOCXEventsEndOfStream read FOnEndOfStream write FOnEndOfStream; property OnPositionChange : T_WMPOCXEventsPositionChange read FOnPositionChange write FOnPositionChange; property OnMarkerHit : T_WMPOCXEventsMarkerHit read FOnMarkerHit write FOnMarkerHit; property OnDurationUnitChange : T_WMPOCXEventsDurationUnitChange read FOnDurationUnitChange write FOnDurationUnitChange; property OnCdromMediaChange : T_WMPOCXEventsCdromMediaChange read FOnCdromMediaChange write FOnCdromMediaChange; property OnPlaylistChange : T_WMPOCXEventsPlaylistChange read FOnPlaylistChange write FOnPlaylistChange; property OnCurrentPlaylistChange : T_WMPOCXEventsCurrentPlaylistChange read FOnCurrentPlaylistChange write FOnCurrentPlaylistChange; property OnCurrentPlaylistItemAvailable : T_WMPOCXEventsCurrentPlaylistItemAvailable read FOnCurrentPlaylistItemAvailable write FOnCurrentPlaylistItemAvailable; property OnMediaChange : T_WMPOCXEventsMediaChange read FOnMediaChange write FOnMediaChange; property OnCurrentMediaItemAvailable : T_WMPOCXEventsCurrentMediaItemAvailable read FOnCurrentMediaItemAvailable write FOnCurrentMediaItemAvailable; property OnCurrentItemChange : T_WMPOCXEventsCurrentItemChange read FOnCurrentItemChange write FOnCurrentItemChange; property OnMediaCollectionChange : T_WMPOCXEventsMediaCollectionChange read FOnMediaCollectionChange write FOnMediaCollectionChange; property OnMediaCollectionAttributeStringAdded : T_WMPOCXEventsMediaCollectionAttributeStringAdded read FOnMediaCollectionAttributeStringAdded write FOnMediaCollectionAttributeStringAdded; property OnMediaCollectionAttributeStringRemoved : T_WMPOCXEventsMediaCollectionAttributeStringRemoved read FOnMediaCollectionAttributeStringRemoved write FOnMediaCollectionAttributeStringRemoved; property OnMediaCollectionAttributeStringChanged : T_WMPOCXEventsMediaCollectionAttributeStringChanged read FOnMediaCollectionAttributeStringChanged write FOnMediaCollectionAttributeStringChanged; property OnPlaylistCollectionChange : T_WMPOCXEventsPlaylistCollectionChange read FOnPlaylistCollectionChange write FOnPlaylistCollectionChange; property OnPlaylistCollectionPlaylistAdded : T_WMPOCXEventsPlaylistCollectionPlaylistAdded read FOnPlaylistCollectionPlaylistAdded write FOnPlaylistCollectionPlaylistAdded; property OnPlaylistCollectionPlaylistRemoved : T_WMPOCXEventsPlaylistCollectionPlaylistRemoved read FOnPlaylistCollectionPlaylistRemoved write FOnPlaylistCollectionPlaylistRemoved; property OnPlaylistCollectionPlaylistSetAsDeleted : T_WMPOCXEventsPlaylistCollectionPlaylistSetAsDeleted read FOnPlaylistCollectionPlaylistSetAsDeleted write FOnPlaylistCollectionPlaylistSetAsDeleted; property OnModeChange : T_WMPOCXEventsModeChange read FOnModeChange write FOnModeChange; property OnMediaError : T_WMPOCXEventsMediaError read FOnMediaError write FOnMediaError; property OnOpenPlaylistSwitch : T_WMPOCXEventsOpenPlaylistSwitch read FOnOpenPlaylistSwitch write FOnOpenPlaylistSwitch; property OnDomainChange : T_WMPOCXEventsDomainChange read FOnDomainChange write FOnDomainChange; property OnSwitchedToPlayerApplication : T_WMPOCXEventsSwitchedToPlayerApplication read FOnSwitchedToPlayerApplication write FOnSwitchedToPlayerApplication; property OnSwitchedToControl : T_WMPOCXEventsSwitchedToControl read FOnSwitchedToControl write FOnSwitchedToControl; property OnPlayerDockedStateChange : T_WMPOCXEventsPlayerDockedStateChange read FOnPlayerDockedStateChange write FOnPlayerDockedStateChange; property OnPlayerReconnect : T_WMPOCXEventsPlayerReconnect read FOnPlayerReconnect write FOnPlayerReconnect; property OnClick : T_WMPOCXEventsClick read FOnClick write FOnClick; property OnDoubleClick : T_WMPOCXEventsDoubleClick read FOnDoubleClick write FOnDoubleClick; property OnKeyDown : T_WMPOCXEventsKeyDown read FOnKeyDown write FOnKeyDown; property OnKeyPress : T_WMPOCXEventsKeyPress read FOnKeyPress write FOnKeyPress; property OnKeyUp : T_WMPOCXEventsKeyUp read FOnKeyUp write FOnKeyUp; property OnMouseDown : T_WMPOCXEventsMouseDown read FOnMouseDown write FOnMouseDown; property OnMouseMove : T_WMPOCXEventsMouseMove read FOnMouseMove write FOnMouseMove; property OnMouseUp : T_WMPOCXEventsMouseUp read FOnMouseUp write FOnMouseUp; property OnDeviceConnect : T_WMPOCXEventsDeviceConnect read FOnDeviceConnect write FOnDeviceConnect; property OnDeviceDisconnect : T_WMPOCXEventsDeviceDisconnect read FOnDeviceDisconnect write FOnDeviceDisconnect; property OnDeviceStatusChange : T_WMPOCXEventsDeviceStatusChange read FOnDeviceStatusChange write FOnDeviceStatusChange; property OnDeviceSyncStateChange : T_WMPOCXEventsDeviceSyncStateChange read FOnDeviceSyncStateChange write FOnDeviceSyncStateChange; property OnDeviceSyncError : T_WMPOCXEventsDeviceSyncError read FOnDeviceSyncError write FOnDeviceSyncError; property OnCreatePartnershipComplete : T_WMPOCXEventsCreatePartnershipComplete read FOnCreatePartnershipComplete write FOnCreatePartnershipComplete; property OnDeviceEstimation : T_WMPOCXEventsDeviceEstimation read FOnDeviceEstimation write FOnDeviceEstimation; property OnCdromRipStateChange : T_WMPOCXEventsCdromRipStateChange read FOnCdromRipStateChange write FOnCdromRipStateChange; property OnCdromRipMediaError : T_WMPOCXEventsCdromRipMediaError read FOnCdromRipMediaError write FOnCdromRipMediaError; property OnCdromBurnStateChange : T_WMPOCXEventsCdromBurnStateChange read FOnCdromBurnStateChange write FOnCdromBurnStateChange; property OnCdromBurnMediaError : T_WMPOCXEventsCdromBurnMediaError read FOnCdromBurnMediaError write FOnCdromBurnMediaError; property OnCdromBurnError : T_WMPOCXEventsCdromBurnError read FOnCdromBurnError write FOnCdromBurnError; property OnLibraryConnect : T_WMPOCXEventsLibraryConnect read FOnLibraryConnect write FOnLibraryConnect; property OnLibraryDisconnect : T_WMPOCXEventsLibraryDisconnect read FOnLibraryDisconnect write FOnLibraryDisconnect; property OnFolderScanStateChange : T_WMPOCXEventsFolderScanStateChange read FOnFolderScanStateChange write FOnFolderScanStateChange; property OnStringCollectionChange : T_WMPOCXEventsStringCollectionChange read FOnStringCollectionChange write FOnStringCollectionChange; property OnMediaCollectionMediaAdded : T_WMPOCXEventsMediaCollectionMediaAdded read FOnMediaCollectionMediaAdded write FOnMediaCollectionMediaAdded; property OnMediaCollectionMediaRemoved : T_WMPOCXEventsMediaCollectionMediaRemoved read FOnMediaCollectionMediaRemoved write FOnMediaCollectionMediaRemoved; end; TIWMPButtonCtrlEventsonclick = procedure(Sender: TObject) of object; CoWMPButtonCtrl = Class Public Class Function Create: IWMPButtonCtrl; Class Function CreateRemote(const MachineName: string): IWMPButtonCtrl; end; TEvsWMPButtonCtrl = Class(TEventSink) Private FOnonclick:TIWMPButtonCtrlEventsonclick; fServer:IWMPButtonCtrl; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPButtonCtrl read fServer; property Ononclick : TIWMPButtonCtrlEventsonclick read FOnonclick write FOnonclick; end; CoWMPListBoxCtrl = Class Public Class Function Create: IWMPListBoxCtrl; Class Function CreateRemote(const MachineName: string): IWMPListBoxCtrl; end; TIWMPSliderCtrlEventsondragbegin = procedure(Sender: TObject) of object; TIWMPSliderCtrlEventsondragend = procedure(Sender: TObject) of object; TIWMPSliderCtrlEventsonpositionchange = procedure(Sender: TObject) of object; CoWMPSliderCtrl = Class Public Class Function Create: IWMPSliderCtrl; Class Function CreateRemote(const MachineName: string): IWMPSliderCtrl; end; TEvsWMPSliderCtrl = Class(TEventSink) Private FOnondragbegin:TIWMPSliderCtrlEventsondragbegin; FOnondragend:TIWMPSliderCtrlEventsondragend; FOnonpositionchange:TIWMPSliderCtrlEventsonpositionchange; fServer:IWMPSliderCtrl; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPSliderCtrl read fServer; property Onondragbegin : TIWMPSliderCtrlEventsondragbegin read FOnondragbegin write FOnondragbegin; property Onondragend : TIWMPSliderCtrlEventsondragend read FOnondragend write FOnondragend; property Ononpositionchange : TIWMPSliderCtrlEventsonpositionchange read FOnonpositionchange write FOnonpositionchange; end; TIWMPVideoCtrlEventsonvideostart = procedure(Sender: TObject) of object; TIWMPVideoCtrlEventsonvideoend = procedure(Sender: TObject) of object; CoWMPVideoCtrl = Class Public Class Function Create: IWMPVideoCtrl; Class Function CreateRemote(const MachineName: string): IWMPVideoCtrl; end; TEvsWMPVideoCtrl = Class(TEventSink) Private FOnonvideostart:TIWMPVideoCtrlEventsonvideostart; FOnonvideoend:TIWMPVideoCtrlEventsonvideoend; fServer:IWMPVideoCtrl; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPVideoCtrl read fServer; property Ononvideostart : TIWMPVideoCtrlEventsonvideostart read FOnonvideostart write FOnonvideostart; property Ononvideoend : TIWMPVideoCtrlEventsonvideoend read FOnonvideoend write FOnonvideoend; end; CoWMPEffects = Class Public Class Function Create: IWMPEffectsCtrl; Class Function CreateRemote(const MachineName: string): IWMPEffectsCtrl; end; CoWMPEqualizerSettingsCtrl = Class Public Class Function Create: IWMPEqualizerSettingsCtrl; Class Function CreateRemote(const MachineName: string): IWMPEqualizerSettingsCtrl; end; CoWMPVideoSettingsCtrl = Class Public Class Function Create: IWMPVideoSettingsCtrl; Class Function CreateRemote(const MachineName: string): IWMPVideoSettingsCtrl; end; CoWMPLibraryTreeCtrl = Class Public Class Function Create: IWMPLibraryTreeCtrl; Class Function CreateRemote(const MachineName: string): IWMPLibraryTreeCtrl; end; CoWMPEditCtrl = Class Public Class Function Create: IWMPEditCtrl; Class Function CreateRemote(const MachineName: string): IWMPEditCtrl; end; CoWMPSkinList = Class Public Class Function Create: IWMPSkinList; Class Function CreateRemote(const MachineName: string): IWMPSkinList; end; CoWMPMenuCtrl = Class Public Class Function Create: IWMPMenuCtrl; Class Function CreateRemote(const MachineName: string): IWMPMenuCtrl; end; CoWMPAutoMenuCtrl = Class Public Class Function Create: IWMPAutoMenuCtrl; Class Function CreateRemote(const MachineName: string): IWMPAutoMenuCtrl; end; CoWMPRegionalButtonCtrl = Class Public Class Function Create: IWMPRegionalButtonCtrl; Class Function CreateRemote(const MachineName: string): IWMPRegionalButtonCtrl; end; TIWMPRegionalButtonEventsonblur = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonfocus = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonclick = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsondblclick = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonmousedown = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonmouseup = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonmousemove = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonmouseover = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonmouseout = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonkeypress = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonkeydown = procedure(Sender: TObject) of object; TIWMPRegionalButtonEventsonkeyup = procedure(Sender: TObject) of object; CoWMPRegionalButton = Class Public Class Function Create: IWMPRegionalButton; Class Function CreateRemote(const MachineName: string): IWMPRegionalButton; end; TEvsWMPRegionalButton = Class(TEventSink) Private FOnonblur:TIWMPRegionalButtonEventsonblur; FOnonfocus:TIWMPRegionalButtonEventsonfocus; FOnonclick:TIWMPRegionalButtonEventsonclick; FOnondblclick:TIWMPRegionalButtonEventsondblclick; FOnonmousedown:TIWMPRegionalButtonEventsonmousedown; FOnonmouseup:TIWMPRegionalButtonEventsonmouseup; FOnonmousemove:TIWMPRegionalButtonEventsonmousemove; FOnonmouseover:TIWMPRegionalButtonEventsonmouseover; FOnonmouseout:TIWMPRegionalButtonEventsonmouseout; FOnonkeypress:TIWMPRegionalButtonEventsonkeypress; FOnonkeydown:TIWMPRegionalButtonEventsonkeydown; FOnonkeyup:TIWMPRegionalButtonEventsonkeyup; fServer:IWMPRegionalButton; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPRegionalButton read fServer; property Ononblur : TIWMPRegionalButtonEventsonblur read FOnonblur write FOnonblur; property Ononfocus : TIWMPRegionalButtonEventsonfocus read FOnonfocus write FOnonfocus; property Ononclick : TIWMPRegionalButtonEventsonclick read FOnonclick write FOnonclick; property Onondblclick : TIWMPRegionalButtonEventsondblclick read FOnondblclick write FOnondblclick; property Ononmousedown : TIWMPRegionalButtonEventsonmousedown read FOnonmousedown write FOnonmousedown; property Ononmouseup : TIWMPRegionalButtonEventsonmouseup read FOnonmouseup write FOnonmouseup; property Ononmousemove : TIWMPRegionalButtonEventsonmousemove read FOnonmousemove write FOnonmousemove; property Ononmouseover : TIWMPRegionalButtonEventsonmouseover read FOnonmouseover write FOnonmouseover; property Ononmouseout : TIWMPRegionalButtonEventsonmouseout read FOnonmouseout write FOnonmouseout; property Ononkeypress : TIWMPRegionalButtonEventsonkeypress read FOnonkeypress write FOnonkeypress; property Ononkeydown : TIWMPRegionalButtonEventsonkeydown read FOnonkeydown write FOnonkeydown; property Ononkeyup : TIWMPRegionalButtonEventsonkeyup read FOnonkeyup write FOnonkeyup; end; TIWMPCustomSliderCtrlEventsondragbegin = procedure(Sender: TObject) of object; TIWMPCustomSliderCtrlEventsondragend = procedure(Sender: TObject) of object; TIWMPCustomSliderCtrlEventsonpositionchange = procedure(Sender: TObject) of object; CoWMPCustomSliderCtrl = Class Public Class Function Create: IWMPCustomSlider; Class Function CreateRemote(const MachineName: string): IWMPCustomSlider; end; TEvsWMPCustomSliderCtrl = Class(TEventSink) Private FOnondragbegin:TIWMPCustomSliderCtrlEventsondragbegin; FOnondragend:TIWMPCustomSliderCtrlEventsondragend; FOnonpositionchange:TIWMPCustomSliderCtrlEventsonpositionchange; fServer:IWMPCustomSlider; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPCustomSlider read fServer; property Onondragbegin : TIWMPCustomSliderCtrlEventsondragbegin read FOnondragbegin write FOnondragbegin; property Onondragend : TIWMPCustomSliderCtrlEventsondragend read FOnondragend write FOnondragend; property Ononpositionchange : TIWMPCustomSliderCtrlEventsonpositionchange read FOnonpositionchange write FOnonpositionchange; end; CoWMPTextCtrl = Class Public Class Function Create: IWMPTextCtrl; Class Function CreateRemote(const MachineName: string): IWMPTextCtrl; end; CoWMPPlaylistCtrl = Class Public Class Function Create: IWMPPlaylistCtrl; Class Function CreateRemote(const MachineName: string): IWMPPlaylistCtrl; end; T_WMPCoreEventsOpenStateChange = procedure(Sender: TObject;NewState:Integer) of object; T_WMPCoreEventsPlayStateChange = procedure(Sender: TObject;NewState:Integer) of object; T_WMPCoreEventsAudioLanguageChange = procedure(Sender: TObject;LangID:Integer) of object; T_WMPCoreEventsStatusChange = procedure(Sender: TObject) of object; T_WMPCoreEventsScriptCommand = procedure(Sender: TObject;scType:WideString;Param:WideString) of object; T_WMPCoreEventsNewStream = procedure(Sender: TObject) of object; T_WMPCoreEventsDisconnect = procedure(Sender: TObject;Result:Integer) of object; T_WMPCoreEventsBuffering = procedure(Sender: TObject;Start:WordBool) of object; T_WMPCoreEventsError = procedure(Sender: TObject) of object; T_WMPCoreEventsWarning = procedure(Sender: TObject;WarningType:Integer;Param:Integer;Description:WideString) of object; T_WMPCoreEventsEndOfStream = procedure(Sender: TObject;Result:Integer) of object; T_WMPCoreEventsPositionChange = procedure(Sender: TObject;oldPosition:Double;newPosition:Double) of object; T_WMPCoreEventsMarkerHit = procedure(Sender: TObject;MarkerNum:Integer) of object; T_WMPCoreEventsDurationUnitChange = procedure(Sender: TObject;NewDurationUnit:Integer) of object; T_WMPCoreEventsCdromMediaChange = procedure(Sender: TObject;CdromNum:Integer) of object; T_WMPCoreEventsPlaylistChange = procedure(Sender: TObject;Playlist:IDispatch;change:WMPPlaylistChangeEventType) of object; T_WMPCoreEventsCurrentPlaylistChange = procedure(Sender: TObject;change:WMPPlaylistChangeEventType) of object; T_WMPCoreEventsCurrentPlaylistItemAvailable = procedure(Sender: TObject;bstrItemName:WideString) of object; T_WMPCoreEventsMediaChange = procedure(Sender: TObject;Item:IDispatch) of object; T_WMPCoreEventsCurrentMediaItemAvailable = procedure(Sender: TObject;bstrItemName:WideString) of object; T_WMPCoreEventsCurrentItemChange = procedure(Sender: TObject;pdispMedia:IDispatch) of object; T_WMPCoreEventsMediaCollectionChange = procedure(Sender: TObject) of object; T_WMPCoreEventsMediaCollectionAttributeStringAdded = procedure(Sender: TObject;bstrAttribName:WideString;bstrAttribVal:WideString) of object; T_WMPCoreEventsMediaCollectionAttributeStringRemoved = procedure(Sender: TObject;bstrAttribName:WideString;bstrAttribVal:WideString) of object; T_WMPCoreEventsMediaCollectionAttributeStringChanged = procedure(Sender: TObject;bstrAttribName:WideString;bstrOldAttribVal:WideString;bstrNewAttribVal:WideString) of object; T_WMPCoreEventsPlaylistCollectionChange = procedure(Sender: TObject) of object; T_WMPCoreEventsPlaylistCollectionPlaylistAdded = procedure(Sender: TObject;bstrPlaylistName:WideString) of object; T_WMPCoreEventsPlaylistCollectionPlaylistRemoved = procedure(Sender: TObject;bstrPlaylistName:WideString) of object; T_WMPCoreEventsPlaylistCollectionPlaylistSetAsDeleted = procedure(Sender: TObject;bstrPlaylistName:WideString;varfIsDeleted:WordBool) of object; T_WMPCoreEventsModeChange = procedure(Sender: TObject;ModeName:WideString;NewValue:WordBool) of object; T_WMPCoreEventsMediaError = procedure(Sender: TObject;pMediaObject:IDispatch) of object; T_WMPCoreEventsOpenPlaylistSwitch = procedure(Sender: TObject;pItem:IDispatch) of object; T_WMPCoreEventsDomainChange = procedure(Sender: TObject;strDomain:WideString) of object; T_WMPCoreEventsStringCollectionChange = procedure(Sender: TObject;pdispStringCollection:IDispatch;change:WMPStringCollectionChangeEventType;lCollectionIndex:Integer) of object; T_WMPCoreEventsMediaCollectionMediaAdded = procedure(Sender: TObject;pdispMedia:IDispatch) of object; T_WMPCoreEventsMediaCollectionMediaRemoved = procedure(Sender: TObject;pdispMedia:IDispatch) of object; CoWMPCore = Class Public Class Function Create: IWMPCore3; Class Function CreateRemote(const MachineName: string): IWMPCore3; end; TEvsWMPCore = Class(TEventSink) Private FOnOpenStateChange:T_WMPCoreEventsOpenStateChange; FOnPlayStateChange:T_WMPCoreEventsPlayStateChange; FOnAudioLanguageChange:T_WMPCoreEventsAudioLanguageChange; FOnStatusChange:T_WMPCoreEventsStatusChange; FOnScriptCommand:T_WMPCoreEventsScriptCommand; FOnNewStream:T_WMPCoreEventsNewStream; FOnDisconnect:T_WMPCoreEventsDisconnect; FOnBuffering:T_WMPCoreEventsBuffering; FOnError:T_WMPCoreEventsError; FOnWarning:T_WMPCoreEventsWarning; FOnEndOfStream:T_WMPCoreEventsEndOfStream; FOnPositionChange:T_WMPCoreEventsPositionChange; FOnMarkerHit:T_WMPCoreEventsMarkerHit; FOnDurationUnitChange:T_WMPCoreEventsDurationUnitChange; FOnCdromMediaChange:T_WMPCoreEventsCdromMediaChange; FOnPlaylistChange:T_WMPCoreEventsPlaylistChange; FOnCurrentPlaylistChange:T_WMPCoreEventsCurrentPlaylistChange; FOnCurrentPlaylistItemAvailable:T_WMPCoreEventsCurrentPlaylistItemAvailable; FOnMediaChange:T_WMPCoreEventsMediaChange; FOnCurrentMediaItemAvailable:T_WMPCoreEventsCurrentMediaItemAvailable; FOnCurrentItemChange:T_WMPCoreEventsCurrentItemChange; FOnMediaCollectionChange:T_WMPCoreEventsMediaCollectionChange; FOnMediaCollectionAttributeStringAdded:T_WMPCoreEventsMediaCollectionAttributeStringAdded; FOnMediaCollectionAttributeStringRemoved:T_WMPCoreEventsMediaCollectionAttributeStringRemoved; FOnMediaCollectionAttributeStringChanged:T_WMPCoreEventsMediaCollectionAttributeStringChanged; FOnPlaylistCollectionChange:T_WMPCoreEventsPlaylistCollectionChange; FOnPlaylistCollectionPlaylistAdded:T_WMPCoreEventsPlaylistCollectionPlaylistAdded; FOnPlaylistCollectionPlaylistRemoved:T_WMPCoreEventsPlaylistCollectionPlaylistRemoved; FOnPlaylistCollectionPlaylistSetAsDeleted:T_WMPCoreEventsPlaylistCollectionPlaylistSetAsDeleted; FOnModeChange:T_WMPCoreEventsModeChange; FOnMediaError:T_WMPCoreEventsMediaError; FOnOpenPlaylistSwitch:T_WMPCoreEventsOpenPlaylistSwitch; FOnDomainChange:T_WMPCoreEventsDomainChange; FOnStringCollectionChange:T_WMPCoreEventsStringCollectionChange; FOnMediaCollectionMediaAdded:T_WMPCoreEventsMediaCollectionMediaAdded; FOnMediaCollectionMediaRemoved:T_WMPCoreEventsMediaCollectionMediaRemoved; fServer:IWMPCore3; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:IWMPCore3 read fServer; property OnOpenStateChange : T_WMPCoreEventsOpenStateChange read FOnOpenStateChange write FOnOpenStateChange; property OnPlayStateChange : T_WMPCoreEventsPlayStateChange read FOnPlayStateChange write FOnPlayStateChange; property OnAudioLanguageChange : T_WMPCoreEventsAudioLanguageChange read FOnAudioLanguageChange write FOnAudioLanguageChange; property OnStatusChange : T_WMPCoreEventsStatusChange read FOnStatusChange write FOnStatusChange; property OnScriptCommand : T_WMPCoreEventsScriptCommand read FOnScriptCommand write FOnScriptCommand; property OnNewStream : T_WMPCoreEventsNewStream read FOnNewStream write FOnNewStream; property OnDisconnect : T_WMPCoreEventsDisconnect read FOnDisconnect write FOnDisconnect; property OnBuffering : T_WMPCoreEventsBuffering read FOnBuffering write FOnBuffering; property OnError : T_WMPCoreEventsError read FOnError write FOnError; property OnWarning : T_WMPCoreEventsWarning read FOnWarning write FOnWarning; property OnEndOfStream : T_WMPCoreEventsEndOfStream read FOnEndOfStream write FOnEndOfStream; property OnPositionChange : T_WMPCoreEventsPositionChange read FOnPositionChange write FOnPositionChange; property OnMarkerHit : T_WMPCoreEventsMarkerHit read FOnMarkerHit write FOnMarkerHit; property OnDurationUnitChange : T_WMPCoreEventsDurationUnitChange read FOnDurationUnitChange write FOnDurationUnitChange; property OnCdromMediaChange : T_WMPCoreEventsCdromMediaChange read FOnCdromMediaChange write FOnCdromMediaChange; property OnPlaylistChange : T_WMPCoreEventsPlaylistChange read FOnPlaylistChange write FOnPlaylistChange; property OnCurrentPlaylistChange : T_WMPCoreEventsCurrentPlaylistChange read FOnCurrentPlaylistChange write FOnCurrentPlaylistChange; property OnCurrentPlaylistItemAvailable : T_WMPCoreEventsCurrentPlaylistItemAvailable read FOnCurrentPlaylistItemAvailable write FOnCurrentPlaylistItemAvailable; property OnMediaChange : T_WMPCoreEventsMediaChange read FOnMediaChange write FOnMediaChange; property OnCurrentMediaItemAvailable : T_WMPCoreEventsCurrentMediaItemAvailable read FOnCurrentMediaItemAvailable write FOnCurrentMediaItemAvailable; property OnCurrentItemChange : T_WMPCoreEventsCurrentItemChange read FOnCurrentItemChange write FOnCurrentItemChange; property OnMediaCollectionChange : T_WMPCoreEventsMediaCollectionChange read FOnMediaCollectionChange write FOnMediaCollectionChange; property OnMediaCollectionAttributeStringAdded : T_WMPCoreEventsMediaCollectionAttributeStringAdded read FOnMediaCollectionAttributeStringAdded write FOnMediaCollectionAttributeStringAdded; property OnMediaCollectionAttributeStringRemoved : T_WMPCoreEventsMediaCollectionAttributeStringRemoved read FOnMediaCollectionAttributeStringRemoved write FOnMediaCollectionAttributeStringRemoved; property OnMediaCollectionAttributeStringChanged : T_WMPCoreEventsMediaCollectionAttributeStringChanged read FOnMediaCollectionAttributeStringChanged write FOnMediaCollectionAttributeStringChanged; property OnPlaylistCollectionChange : T_WMPCoreEventsPlaylistCollectionChange read FOnPlaylistCollectionChange write FOnPlaylistCollectionChange; property OnPlaylistCollectionPlaylistAdded : T_WMPCoreEventsPlaylistCollectionPlaylistAdded read FOnPlaylistCollectionPlaylistAdded write FOnPlaylistCollectionPlaylistAdded; property OnPlaylistCollectionPlaylistRemoved : T_WMPCoreEventsPlaylistCollectionPlaylistRemoved read FOnPlaylistCollectionPlaylistRemoved write FOnPlaylistCollectionPlaylistRemoved; property OnPlaylistCollectionPlaylistSetAsDeleted : T_WMPCoreEventsPlaylistCollectionPlaylistSetAsDeleted read FOnPlaylistCollectionPlaylistSetAsDeleted write FOnPlaylistCollectionPlaylistSetAsDeleted; property OnModeChange : T_WMPCoreEventsModeChange read FOnModeChange write FOnModeChange; property OnMediaError : T_WMPCoreEventsMediaError read FOnMediaError write FOnMediaError; property OnOpenPlaylistSwitch : T_WMPCoreEventsOpenPlaylistSwitch read FOnOpenPlaylistSwitch write FOnOpenPlaylistSwitch; property OnDomainChange : T_WMPCoreEventsDomainChange read FOnDomainChange write FOnDomainChange; property OnStringCollectionChange : T_WMPCoreEventsStringCollectionChange read FOnStringCollectionChange write FOnStringCollectionChange; property OnMediaCollectionMediaAdded : T_WMPCoreEventsMediaCollectionMediaAdded read FOnMediaCollectionMediaAdded write FOnMediaCollectionMediaAdded; property OnMediaCollectionMediaRemoved : T_WMPCoreEventsMediaCollectionMediaRemoved read FOnMediaCollectionMediaRemoved write FOnMediaCollectionMediaRemoved; end; implementation uses comobj; Class Function CoWindowsMediaPlayer.Create: IWMPPlayer4; begin Result := CreateComObject(CLASS_WindowsMediaPlayer) as IWMPPlayer4; end; Class Function CoWindowsMediaPlayer.CreateRemote(const MachineName: string): IWMPPlayer4; begin Result := CreateRemoteComObject(MachineName,CLASS_WindowsMediaPlayer) as IWMPPlayer4; end; constructor TEvsWindowsMediaPlayer.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWindowsMediaPlayer.Create; Connect(fServer,_WMPOCXEvents); end; procedure TEvsWindowsMediaPlayer.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5001: if assigned(OnOpenStateChange) then OnOpenStateChange(Self, OleVariant(Params.rgvarg[0])); 5101: if assigned(OnPlayStateChange) then OnPlayStateChange(Self, OleVariant(Params.rgvarg[0])); 5102: if assigned(OnAudioLanguageChange) then OnAudioLanguageChange(Self, OleVariant(Params.rgvarg[0])); 5002: if assigned(OnStatusChange) then OnStatusChange(Self); 5301: if assigned(OnScriptCommand) then OnScriptCommand(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5403: if assigned(OnNewStream) then OnNewStream(Self); 5401: if assigned(OnDisconnect) then OnDisconnect(Self, OleVariant(Params.rgvarg[0])); 5402: if assigned(OnBuffering) then OnBuffering(Self, OleVariant(Params.rgvarg[0])); 5501: if assigned(OnError) then OnError(Self); 5601: if assigned(OnWarning) then OnWarning(Self, OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5201: if assigned(OnEndOfStream) then OnEndOfStream(Self, OleVariant(Params.rgvarg[0])); 5202: if assigned(OnPositionChange) then OnPositionChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5203: if assigned(OnMarkerHit) then OnMarkerHit(Self, OleVariant(Params.rgvarg[0])); 5204: if assigned(OnDurationUnitChange) then OnDurationUnitChange(Self, OleVariant(Params.rgvarg[0])); 5701: if assigned(OnCdromMediaChange) then OnCdromMediaChange(Self, OleVariant(Params.rgvarg[0])); 5801: if assigned(OnPlaylistChange) then OnPlaylistChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5804: if assigned(OnCurrentPlaylistChange) then OnCurrentPlaylistChange(Self, OleVariant(Params.rgvarg[0])); 5805: if assigned(OnCurrentPlaylistItemAvailable) then OnCurrentPlaylistItemAvailable(Self, OleVariant(Params.rgvarg[0])); 5802: if assigned(OnMediaChange) then OnMediaChange(Self, OleVariant(Params.rgvarg[0])); 5803: if assigned(OnCurrentMediaItemAvailable) then OnCurrentMediaItemAvailable(Self, OleVariant(Params.rgvarg[0])); 5806: if assigned(OnCurrentItemChange) then OnCurrentItemChange(Self, OleVariant(Params.rgvarg[0])); 5807: if assigned(OnMediaCollectionChange) then OnMediaCollectionChange(Self); 5808: if assigned(OnMediaCollectionAttributeStringAdded) then OnMediaCollectionAttributeStringAdded(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5809: if assigned(OnMediaCollectionAttributeStringRemoved) then OnMediaCollectionAttributeStringRemoved(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5820: if assigned(OnMediaCollectionAttributeStringChanged) then OnMediaCollectionAttributeStringChanged(Self, OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5810: if assigned(OnPlaylistCollectionChange) then OnPlaylistCollectionChange(Self); 5811: if assigned(OnPlaylistCollectionPlaylistAdded) then OnPlaylistCollectionPlaylistAdded(Self, OleVariant(Params.rgvarg[0])); 5812: if assigned(OnPlaylistCollectionPlaylistRemoved) then OnPlaylistCollectionPlaylistRemoved(Self, OleVariant(Params.rgvarg[0])); 5818: if assigned(OnPlaylistCollectionPlaylistSetAsDeleted) then OnPlaylistCollectionPlaylistSetAsDeleted(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5819: if assigned(OnModeChange) then OnModeChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5821: if assigned(OnMediaError) then OnMediaError(Self, OleVariant(Params.rgvarg[0])); 5823: if assigned(OnOpenPlaylistSwitch) then OnOpenPlaylistSwitch(Self, OleVariant(Params.rgvarg[0])); 5822: if assigned(OnDomainChange) then OnDomainChange(Self, OleVariant(Params.rgvarg[0])); 6501: if assigned(OnSwitchedToPlayerApplication) then OnSwitchedToPlayerApplication(Self); 6502: if assigned(OnSwitchedToControl) then OnSwitchedToControl(Self); 6503: if assigned(OnPlayerDockedStateChange) then OnPlayerDockedStateChange(Self); 6504: if assigned(OnPlayerReconnect) then OnPlayerReconnect(Self); 6505: if assigned(OnClick) then OnClick(Self, OleVariant(Params.rgvarg[3]), OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6506: if assigned(OnDoubleClick) then OnDoubleClick(Self, OleVariant(Params.rgvarg[3]), OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6507: if assigned(OnKeyDown) then OnKeyDown(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6508: if assigned(OnKeyPress) then OnKeyPress(Self, OleVariant(Params.rgvarg[0])); 6509: if assigned(OnKeyUp) then OnKeyUp(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6510: if assigned(OnMouseDown) then OnMouseDown(Self, OleVariant(Params.rgvarg[3]), OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6511: if assigned(OnMouseMove) then OnMouseMove(Self, OleVariant(Params.rgvarg[3]), OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6512: if assigned(OnMouseUp) then OnMouseUp(Self, OleVariant(Params.rgvarg[3]), OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6513: if assigned(OnDeviceConnect) then OnDeviceConnect(Self, OleVariant(Params.rgvarg[0])); 6514: if assigned(OnDeviceDisconnect) then OnDeviceDisconnect(Self, OleVariant(Params.rgvarg[0])); 6515: if assigned(OnDeviceStatusChange) then OnDeviceStatusChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6516: if assigned(OnDeviceSyncStateChange) then OnDeviceSyncStateChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6517: if assigned(OnDeviceSyncError) then OnDeviceSyncError(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); // 6518: if assigned(OnCreatePartnershipComplete) then // OnCreatePartnershipComplete(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); // 6527: if assigned(OnDeviceEstimation) then // OnDeviceEstimation(Self, OleVariant(Params.rgvarg[3]), OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6519: if assigned(OnCdromRipStateChange) then OnCdromRipStateChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6520: if assigned(OnCdromRipMediaError) then OnCdromRipMediaError(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6521: if assigned(OnCdromBurnStateChange) then OnCdromBurnStateChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6522: if assigned(OnCdromBurnMediaError) then OnCdromBurnMediaError(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); // 6523: if assigned(OnCdromBurnError) then // OnCdromBurnError(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 6524: if assigned(OnLibraryConnect) then OnLibraryConnect(Self, OleVariant(Params.rgvarg[0])); 6525: if assigned(OnLibraryDisconnect) then OnLibraryDisconnect(Self, OleVariant(Params.rgvarg[0])); 6526: if assigned(OnFolderScanStateChange) then OnFolderScanStateChange(Self, OleVariant(Params.rgvarg[0])); 5824: if assigned(OnStringCollectionChange) then OnStringCollectionChange(Self, OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5825: if assigned(OnMediaCollectionMediaAdded) then OnMediaCollectionMediaAdded(Self, OleVariant(Params.rgvarg[0])); 5826: if assigned(OnMediaCollectionMediaRemoved) then OnMediaCollectionMediaRemoved(Self, OleVariant(Params.rgvarg[0])); end; end; Class Function CoWMPButtonCtrl.Create: IWMPButtonCtrl; begin Result := CreateComObject(CLASS_WMPButtonCtrl) as IWMPButtonCtrl; end; Class Function CoWMPButtonCtrl.CreateRemote(const MachineName: string): IWMPButtonCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPButtonCtrl) as IWMPButtonCtrl; end; constructor TEvsWMPButtonCtrl.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWMPButtonCtrl.Create; Connect(fServer,IWMPButtonCtrlEvents); end; procedure TEvsWMPButtonCtrl.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5120: if assigned(Ononclick) then Ononclick(Self); end; end; Class Function CoWMPListBoxCtrl.Create: IWMPListBoxCtrl; begin Result := CreateComObject(CLASS_WMPListBoxCtrl) as IWMPListBoxCtrl; end; Class Function CoWMPListBoxCtrl.CreateRemote(const MachineName: string): IWMPListBoxCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPListBoxCtrl) as IWMPListBoxCtrl; end; Class Function CoWMPSliderCtrl.Create: IWMPSliderCtrl; begin Result := CreateComObject(CLASS_WMPSliderCtrl) as IWMPSliderCtrl; end; Class Function CoWMPSliderCtrl.CreateRemote(const MachineName: string): IWMPSliderCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPSliderCtrl) as IWMPSliderCtrl; end; constructor TEvsWMPSliderCtrl.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWMPSliderCtrl.Create; Connect(fServer,IWMPSliderCtrlEvents); end; procedure TEvsWMPSliderCtrl.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5430: if assigned(Onondragbegin) then Onondragbegin(Self); 5431: if assigned(Onondragend) then Onondragend(Self); 5432: if assigned(Ononpositionchange) then Ononpositionchange(Self); end; end; Class Function CoWMPVideoCtrl.Create: IWMPVideoCtrl; begin Result := CreateComObject(CLASS_WMPVideoCtrl) as IWMPVideoCtrl; end; Class Function CoWMPVideoCtrl.CreateRemote(const MachineName: string): IWMPVideoCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPVideoCtrl) as IWMPVideoCtrl; end; constructor TEvsWMPVideoCtrl.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWMPVideoCtrl.Create; Connect(fServer,IWMPVideoCtrlEvents); end; procedure TEvsWMPVideoCtrl.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5720: if assigned(Ononvideostart) then Ononvideostart(Self); 5721: if assigned(Ononvideoend) then Ononvideoend(Self); end; end; Class Function CoWMPEffects.Create: IWMPEffectsCtrl; begin Result := CreateComObject(CLASS_WMPEffects) as IWMPEffectsCtrl; end; Class Function CoWMPEffects.CreateRemote(const MachineName: string): IWMPEffectsCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPEffects) as IWMPEffectsCtrl; end; Class Function CoWMPEqualizerSettingsCtrl.Create: IWMPEqualizerSettingsCtrl; begin Result := CreateComObject(CLASS_WMPEqualizerSettingsCtrl) as IWMPEqualizerSettingsCtrl; end; Class Function CoWMPEqualizerSettingsCtrl.CreateRemote(const MachineName: string): IWMPEqualizerSettingsCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPEqualizerSettingsCtrl) as IWMPEqualizerSettingsCtrl; end; Class Function CoWMPVideoSettingsCtrl.Create: IWMPVideoSettingsCtrl; begin Result := CreateComObject(CLASS_WMPVideoSettingsCtrl) as IWMPVideoSettingsCtrl; end; Class Function CoWMPVideoSettingsCtrl.CreateRemote(const MachineName: string): IWMPVideoSettingsCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPVideoSettingsCtrl) as IWMPVideoSettingsCtrl; end; Class Function CoWMPLibraryTreeCtrl.Create: IWMPLibraryTreeCtrl; begin Result := CreateComObject(CLASS_WMPLibraryTreeCtrl) as IWMPLibraryTreeCtrl; end; Class Function CoWMPLibraryTreeCtrl.CreateRemote(const MachineName: string): IWMPLibraryTreeCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPLibraryTreeCtrl) as IWMPLibraryTreeCtrl; end; Class Function CoWMPEditCtrl.Create: IWMPEditCtrl; begin Result := CreateComObject(CLASS_WMPEditCtrl) as IWMPEditCtrl; end; Class Function CoWMPEditCtrl.CreateRemote(const MachineName: string): IWMPEditCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPEditCtrl) as IWMPEditCtrl; end; Class Function CoWMPSkinList.Create: IWMPSkinList; begin Result := CreateComObject(CLASS_WMPSkinList) as IWMPSkinList; end; Class Function CoWMPSkinList.CreateRemote(const MachineName: string): IWMPSkinList; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPSkinList) as IWMPSkinList; end; Class Function CoWMPMenuCtrl.Create: IWMPMenuCtrl; begin Result := CreateComObject(CLASS_WMPMenuCtrl) as IWMPMenuCtrl; end; Class Function CoWMPMenuCtrl.CreateRemote(const MachineName: string): IWMPMenuCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPMenuCtrl) as IWMPMenuCtrl; end; Class Function CoWMPAutoMenuCtrl.Create: IWMPAutoMenuCtrl; begin Result := CreateComObject(CLASS_WMPAutoMenuCtrl) as IWMPAutoMenuCtrl; end; Class Function CoWMPAutoMenuCtrl.CreateRemote(const MachineName: string): IWMPAutoMenuCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPAutoMenuCtrl) as IWMPAutoMenuCtrl; end; Class Function CoWMPRegionalButtonCtrl.Create: IWMPRegionalButtonCtrl; begin Result := CreateComObject(CLASS_WMPRegionalButtonCtrl) as IWMPRegionalButtonCtrl; end; Class Function CoWMPRegionalButtonCtrl.CreateRemote(const MachineName: string): IWMPRegionalButtonCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPRegionalButtonCtrl) as IWMPRegionalButtonCtrl; end; Class Function CoWMPRegionalButton.Create: IWMPRegionalButton; begin Result := CreateComObject(CLASS_WMPRegionalButton) as IWMPRegionalButton; end; Class Function CoWMPRegionalButton.CreateRemote(const MachineName: string): IWMPRegionalButton; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPRegionalButton) as IWMPRegionalButton; end; constructor TEvsWMPRegionalButton.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWMPRegionalButton.Create; Connect(fServer,IWMPRegionalButtonEvents); end; procedure TEvsWMPRegionalButton.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5360: if assigned(Ononblur) then Ononblur(Self); 5361: if assigned(Ononfocus) then Ononfocus(Self); 5362: if assigned(Ononclick) then Ononclick(Self); 5363: if assigned(Onondblclick) then Onondblclick(Self); 5364: if assigned(Ononmousedown) then Ononmousedown(Self); 5365: if assigned(Ononmouseup) then Ononmouseup(Self); 5366: if assigned(Ononmousemove) then Ononmousemove(Self); 5367: if assigned(Ononmouseover) then Ononmouseover(Self); 5368: if assigned(Ononmouseout) then Ononmouseout(Self); 5369: if assigned(Ononkeypress) then Ononkeypress(Self); 5370: if assigned(Ononkeydown) then Ononkeydown(Self); 5371: if assigned(Ononkeyup) then Ononkeyup(Self); end; end; Class Function CoWMPCustomSliderCtrl.Create: IWMPCustomSlider; begin Result := CreateComObject(CLASS_WMPCustomSliderCtrl) as IWMPCustomSlider; end; Class Function CoWMPCustomSliderCtrl.CreateRemote(const MachineName: string): IWMPCustomSlider; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPCustomSliderCtrl) as IWMPCustomSlider; end; constructor TEvsWMPCustomSliderCtrl.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWMPCustomSliderCtrl.Create; Connect(fServer,IWMPCustomSliderCtrlEvents); end; procedure TEvsWMPCustomSliderCtrl.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5020: if assigned(Onondragbegin) then Onondragbegin(Self); 5021: if assigned(Onondragend) then Onondragend(Self); 5022: if assigned(Ononpositionchange) then Ononpositionchange(Self); end; end; Class Function CoWMPTextCtrl.Create: IWMPTextCtrl; begin Result := CreateComObject(CLASS_WMPTextCtrl) as IWMPTextCtrl; end; Class Function CoWMPTextCtrl.CreateRemote(const MachineName: string): IWMPTextCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPTextCtrl) as IWMPTextCtrl; end; Class Function CoWMPPlaylistCtrl.Create: IWMPPlaylistCtrl; begin Result := CreateComObject(CLASS_WMPPlaylistCtrl) as IWMPPlaylistCtrl; end; Class Function CoWMPPlaylistCtrl.CreateRemote(const MachineName: string): IWMPPlaylistCtrl; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPPlaylistCtrl) as IWMPPlaylistCtrl; end; Class Function CoWMPCore.Create: IWMPCore3; begin Result := CreateComObject(CLASS_WMPCore) as IWMPCore3; end; Class Function CoWMPCore.CreateRemote(const MachineName: string): IWMPCore3; begin Result := CreateRemoteComObject(MachineName,CLASS_WMPCore) as IWMPCore3; end; constructor TEvsWMPCore.Create(TheOwner: TComponent); begin inherited Create(TheOwner); OnInvoke:=EventSinkInvoke; fServer:=CoWMPCore.Create; Connect(fServer,_WMPCoreEvents); end; procedure TEvsWMPCore.EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); begin case DispID of 5001: if assigned(OnOpenStateChange) then OnOpenStateChange(Self, OleVariant(Params.rgvarg[0])); 5101: if assigned(OnPlayStateChange) then OnPlayStateChange(Self, OleVariant(Params.rgvarg[0])); 5102: if assigned(OnAudioLanguageChange) then OnAudioLanguageChange(Self, OleVariant(Params.rgvarg[0])); 5002: if assigned(OnStatusChange) then OnStatusChange(Self); 5301: if assigned(OnScriptCommand) then OnScriptCommand(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5403: if assigned(OnNewStream) then OnNewStream(Self); 5401: if assigned(OnDisconnect) then OnDisconnect(Self, OleVariant(Params.rgvarg[0])); 5402: if assigned(OnBuffering) then OnBuffering(Self, OleVariant(Params.rgvarg[0])); 5501: if assigned(OnError) then OnError(Self); 5601: if assigned(OnWarning) then OnWarning(Self, OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5201: if assigned(OnEndOfStream) then OnEndOfStream(Self, OleVariant(Params.rgvarg[0])); 5202: if assigned(OnPositionChange) then OnPositionChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5203: if assigned(OnMarkerHit) then OnMarkerHit(Self, OleVariant(Params.rgvarg[0])); 5204: if assigned(OnDurationUnitChange) then OnDurationUnitChange(Self, OleVariant(Params.rgvarg[0])); 5701: if assigned(OnCdromMediaChange) then OnCdromMediaChange(Self, OleVariant(Params.rgvarg[0])); 5801: if assigned(OnPlaylistChange) then OnPlaylistChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5804: if assigned(OnCurrentPlaylistChange) then OnCurrentPlaylistChange(Self, OleVariant(Params.rgvarg[0])); 5805: if assigned(OnCurrentPlaylistItemAvailable) then OnCurrentPlaylistItemAvailable(Self, OleVariant(Params.rgvarg[0])); 5802: if assigned(OnMediaChange) then OnMediaChange(Self, OleVariant(Params.rgvarg[0])); 5803: if assigned(OnCurrentMediaItemAvailable) then OnCurrentMediaItemAvailable(Self, OleVariant(Params.rgvarg[0])); 5806: if assigned(OnCurrentItemChange) then OnCurrentItemChange(Self, OleVariant(Params.rgvarg[0])); 5807: if assigned(OnMediaCollectionChange) then OnMediaCollectionChange(Self); 5808: if assigned(OnMediaCollectionAttributeStringAdded) then OnMediaCollectionAttributeStringAdded(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5809: if assigned(OnMediaCollectionAttributeStringRemoved) then OnMediaCollectionAttributeStringRemoved(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5820: if assigned(OnMediaCollectionAttributeStringChanged) then OnMediaCollectionAttributeStringChanged(Self, OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5810: if assigned(OnPlaylistCollectionChange) then OnPlaylistCollectionChange(Self); 5811: if assigned(OnPlaylistCollectionPlaylistAdded) then OnPlaylistCollectionPlaylistAdded(Self, OleVariant(Params.rgvarg[0])); 5812: if assigned(OnPlaylistCollectionPlaylistRemoved) then OnPlaylistCollectionPlaylistRemoved(Self, OleVariant(Params.rgvarg[0])); 5818: if assigned(OnPlaylistCollectionPlaylistSetAsDeleted) then OnPlaylistCollectionPlaylistSetAsDeleted(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5819: if assigned(OnModeChange) then OnModeChange(Self, OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5821: if assigned(OnMediaError) then OnMediaError(Self, OleVariant(Params.rgvarg[0])); 5823: if assigned(OnOpenPlaylistSwitch) then OnOpenPlaylistSwitch(Self, OleVariant(Params.rgvarg[0])); 5822: if assigned(OnDomainChange) then OnDomainChange(Self, OleVariant(Params.rgvarg[0])); 5824: if assigned(OnStringCollectionChange) then OnStringCollectionChange(Self, OleVariant(Params.rgvarg[2]), OleVariant(Params.rgvarg[1]), OleVariant(Params.rgvarg[0])); 5825: if assigned(OnMediaCollectionMediaAdded) then OnMediaCollectionMediaAdded(Self, OleVariant(Params.rgvarg[0])); 5826: if assigned(OnMediaCollectionMediaRemoved) then OnMediaCollectionMediaRemoved(Self, OleVariant(Params.rgvarg[0])); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/scripts/���������������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�014275� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/scripts/rabbit-vcs.py��������������������������������������������������������������0000644�0001750�0000144�00000005503�14743153644�016706� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # This is an extension to the Double Commander to allow # integration with the version control systems. # # Copyright (C) 2009 Jason Heeris <jason.heeris@gmail.com> # Copyright (C) 2009 Bruce van der Kooij <brucevdkooij@gmail.com> # Copyright (C) 2009 Adam Plumb <adamplumb@gmail.com> # Copyright (C) 2014-2021 Alexander Koblov <alexx2000@mail.ru> # # RabbitVCS 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. # # RabbitVCS 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 RabbitVCS; If not, see <http://www.gnu.org/licenses/>. # import os, os.path import sys try: from rabbitvcs.util.contextmenuitems import MenuItem, MenuSeparator from rabbitvcs.util.contextmenu import MenuBuilder, MainContextMenu, MainContextMenuCallbacks import rabbitvcs.services.checkerservice except Exception as e: print("RabbitVCS: {}".format(e)) exit(1) class DCSender: """Double Commander sender class""" def rescan_after_process_exit(self, proc, paths): print("rescan_after_process_exit") return class DCMenuItem: """Double Commander menu item class""" identifier = None label = None icon = None menu = [] def connect(self, signal, *callback): return class DCContextMenu(MenuBuilder): """Double Commander context menu class""" signal = "activate" def make_menu_item(self, item, id_magic): menuitem = DCMenuItem() if type(item) is MenuSeparator: menuitem.label = "-" else: menuitem.icon = item.icon menuitem.label = item.make_label() menuitem.identifier = item.callback_name return menuitem def attach_submenu(self, menu_node, submenu_list): menu_node.menu = [] menu_node.identifier = "" for item in submenu_list: menu_node.menu.append(item) def top_level_menu(self, items): return items class DCMainContextMenu(MainContextMenu): """Double Commander main context menu class""" def Execute(self, identifier): # Try to find and execute callback function if hasattr(self.callbacks, identifier): function = getattr(self.callbacks, identifier) if callable(function): function(self, None) def GetMenu(self): return DCContextMenu(self.structure, self.conditions, self.callbacks).menu def GetContextMenu(paths): sender = DCSender() base_dir = os.path.dirname(paths[0]) return DCMainContextMenu(sender, base_dir, paths, None) def StartService(): rabbitvcs.services.checkerservice.start() ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/scripts/terminal.sh����������������������������������������������������������������0000755�0001750�0000144�00000001132�14743153644�016444� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env bash # Execute command in terminal emulator Mac OS X # Path to temporary script file SCRIPT_FILE=$(mktemp /var/tmp/doublecmd-XXXX) # Add shebang echo "#!/usr/bin/env bash" > $SCRIPT_FILE # Remove temporary script file at exit echo "trap 'rm -f $SCRIPT_FILE' INT TERM EXIT" >> $SCRIPT_FILE # Clear screen echo "clear" >> $SCRIPT_FILE # Change to directory printf -v DIR "%q" "$(pwd)" echo "cd $DIR" >> $SCRIPT_FILE # Copy over target command line echo "$@" >> $SCRIPT_FILE # Make executable chmod +x "$SCRIPT_FILE" # Execute in terminal open -b com.apple.terminal "$SCRIPT_FILE" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/sdk/�������������������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�013367� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/sdk/calling.inc��������������������������������������������������������������������0000644�0001750�0000144�00000000144�14743153644�015472� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{$MACRO ON} {$IFDEF MSWINDOWS} {$DEFINE dcpcall:=stdcall} {$ELSE} {$DEFINE dcpcall:=cdecl} {$ENDIF} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/sdk/common.h�����������������������������������������������������������������������0000644�0001750�0000144�00000003000�14743153644�015021� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _COMMON_H #define _COMMON_H #ifdef __GNUC__ #include <stdint.h> #if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64) #define DCPCALL __attribute__((stdcall)) #else #define DCPCALL #endif #define MAX_PATH 260 typedef int32_t LONG; typedef uint32_t DWORD; typedef uint16_t WORD; typedef void *HANDLE; typedef HANDLE HICON; typedef HANDLE HBITMAP; typedef HANDLE HWND; typedef int BOOL; typedef char CHAR; typedef uint16_t WCHAR; typedef intptr_t LPARAM; typedef uintptr_t WPARAM; #pragma pack(push, 1) typedef struct _RECT { LONG left; LONG top; LONG right; LONG bottom; } RECT, *PRECT; typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME,*PFILETIME,*LPFILETIME; typedef struct _WIN32_FIND_DATAA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; CHAR cFileName[MAX_PATH]; CHAR cAlternateFileName[14]; } WIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; typedef struct _WIN32_FIND_DATAW { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; WCHAR cFileName[MAX_PATH]; WCHAR cAlternateFileName[14]; } WIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; #pragma pack(pop) #else #if defined(_WIN32) || defined(_WIN64) #define DCPCALL __stdcall #else #define DCPCALL __cdecl #endif #endif #endif // _COMMON_H doublecmd-1.1.22/sdk/dsxplugin.pas������������������������������������������������������������������0000644�0001750�0000144�00000003321�14743153644�016110� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit DsxPlugin; {$include calling.inc} interface uses SysUtils; type PDsxSearchRecord = ^TDsxSearchRecord; TDsxSearchRecord = record StartPath: array[0..1023] of AnsiChar; FileMask: array[0..1023] of AnsiChar; Attributes: Cardinal; AttribStr: array[0..127] of AnsiChar; CaseSensitive: Boolean; { Date/time search } IsDateFrom, IsDateTo, IsTimeFrom, IsTimeTo: Boolean; DateTimeFrom, DateTimeTo: TDateTime; { File size search } IsFileSizeFrom, IsFileSizeTo: Boolean; FileSizeFrom, FileSizeTo: Int64; { Find/replace text } IsFindText: Boolean; FindText: array[0..1023] of AnsiChar; IsReplaceText: Boolean; ReplaceText: array[0..1023] of AnsiChar; NotContainingText: Boolean; end; TDsxDefaultParamStruct = record Size, PluginInterfaceVersionLow, PluginInterfaceVersionHi: Longint; DefaultIniName: array[0..MAX_PATH - 1] of Char; end; PDsxDefaultParamStruct = ^TDsxDefaultParamStruct; { For compatibility with Delphi use $IFDEF's to set calling convention } {Prototypes} {Callbacks procs} TSAddFileProc = procedure(PluginNr: Integer; FoundFile: PChar); dcpcall; //if FoundFile='' then searching is finished TSUpdateStatusProc = procedure(PluginNr: Integer; CurrentFile: PChar; FilesScaned: Integer); dcpcall; {Mandatory (must be implemented)} TSInit = function(dps: PDsxDefaultParamStruct; pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): Integer; dcpcall; TSStartSearch = procedure(PluginNr: Integer; pSearchRec: PDsxSearchRecord); dcpcall; TSStopSearch = procedure(PluginNr: Integer); dcpcall; TSFinalize = procedure(PluginNr: Integer); dcpcall; implementation end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/sdk/extension.h��������������������������������������������������������������������0000644�0001750�0000144�00000014131�14743153644�015554� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "common.h" /* dialog messages */ #define DM_FIRST 0 #define DM_CLOSE DM_FIRST+1 /* A signal that the dialog is about to close */ #define DM_ENABLE DM_FIRST+2 #define DM_GETDLGDATA DM_FIRST+3 #define DM_GETDLGBOUNDS DM_FIRST+4 #define DM_GETITEMBOUNDS DM_FIRST+5 #define DM_GETTEXT DM_FIRST+6 /* Retrieve the text of an edit string or the caption of an item */ #define DM_KEYDOWN DM_FIRST+7 #define DM_KEYUP DM_FIRST+8 #define DM_SETDLGDATA DM_FIRST+9 #define DM_SETFOCUS DM_FIRST+10 /* Set the keyboard focus to the given dialog item */ #define DM_REDRAW DM_FIRST+11 /* Redraw the whole dialog */ #define DM_SETTEXT DM_FIRST+12 /* Set a new string value for an edit line or a new caption for an item */ #define DM_SETMAXTEXTLENGTH DM_FIRST+13 /* Set the maximum length of an edit string */ #define DM_SHOWDIALOG DM_FIRST+14 /* Show/hide the dialog window */ #define DM_SHOWITEM DM_FIRST+15 /* Show/hide a dialog item */ #define DM_GETCHECK DM_FIRST+16 /* Retrieve the state of TCheckBox or TRadioButton items */ #define DM_SETCHECK DM_FIRST+17 /* Change the state of TCheckBox and TRadioButton items */ #define DM_LISTGETITEM DM_FIRST+18 /* Retrieve a list item */ #define DM_LISTGETITEMINDEX DM_FIRST+19 /* Get current item index in a list */ #define DM_LISTSETITEMINDEX DM_FIRST+20 /* Set current item index in a list */ #define DM_LISTDELETE DM_FIRST+21 #define DM_LISTADD DM_FIRST+22 #define DM_LISTADDSTR DM_FIRST+23 #define DM_LISTUPDATE DM_FIRST+24 #define DM_LISTINSERT DM_FIRST+25 #define DM_LISTINDEXOF DM_FIRST+26 #define DM_LISTGETCOUNT DM_FIRST+27 #define DM_LISTGETDATA DM_FIRST+28 #define DM_LISTSETDATA DM_FIRST+29 #define DM_SETDLGBOUNDS DM_FIRST+30 #define DM_SETITEMBOUNDS DM_FIRST+31 #define DM_GETDROPPEDDOWN DM_FIRST+32 #define DM_SETDROPPEDDOWN DM_FIRST+33 #define DM_GETITEMDATA DM_FIRST+34 #define DM_SETITEMDATA DM_FIRST+35 #define DM_LISTSET DM_FIRST+36 #define DM_SETPROGRESSVALUE DM_FIRST+37 #define DM_SETPROGRESSSTYLE DM_FIRST+38 #define DM_SETPASSWORDCHAR DM_FIRST+39 #define DM_LISTCLEAR DM_FIRST+40 #define DM_TIMERSETINTERVAL DM_FIRST+41 /* events messages */ #define DN_FIRST 0x1000 #define DN_CLICK DN_FIRST+1 /* Sent after mouse click */ #define DN_DBLCLICK DN_FIRST+2 /* Sent after mouse double click */ #define DN_CHANGE DN_FIRST+3 /* Sent after the dialog item is changed */ #define DN_GOTFOCUS DN_FIRST+4 /* Sent when the dialog item gets input focus */ #define DN_INITDIALOG DN_FIRST+5 /* Sent before showing the dialog */ #define DN_KILLFOCUS DN_FIRST+6 /* Sent before a dialog item loses the input focus */ #define DN_TIMER DN_FIRST+7 /* Sent when a timer expires */ #define DN_KEYDOWN DM_KEYDOWN #define DN_KEYUP DM_KEYUP #define DN_CLOSE DM_CLOSE /* Sent before the dialog is closed */ #define DM_USER 0x4000 /* Starting value for user defined messages */ // MessageBox: To indicate the buttons displayed in the message box, // specify one of the following values. #define MB_OK 0x00000000 #define MB_OKCANCEL 0x00000001 #define MB_ABORTRETRYIGNORE 0x00000002 #define MB_YESNOCANCEL 0x00000003 #define MB_YESNO 0x00000004 #define MB_RETRYCANCEL 0x00000005 #define MB_ICONHAND 0x00000010 #define MB_ICONQUESTION 0x00000020 #define MB_ICONEXCLAMATION 0x00000030 #define MB_ICONASTERICK 0x00000040 #define MB_ICONWARNING MB_ICONEXCLAMATION #define MB_ICONERROR MB_ICONHAND #define MB_ICONSTOP MB_ICONHAND #define MB_ICONINFORMATION MB_ICONASTERICK // MessageBox: To indicate the default button, specify one of the following values. #define MB_DEFBUTTON1 0x00000000 #define MB_DEFBUTTON2 0x00000100 #define MB_DEFBUTTON3 0x00000200 #define MB_DEFBUTTON4 0x00000300 // MessageBox: Return values #define ID_OK 1 #define ID_CANCEL 2 #define ID_ABORT 3 #define ID_RETRY 4 #define ID_IGNORE 5 #define ID_YES 6 #define ID_NO 7 #define ID_CLOSE 8 #define ID_HELP 9 // DialogBoxParam: Flags #define DB_LFM 0 // Data contains a form in the LFM format #define DB_LRS 1 // Data contains a form in the LRS format #define DB_FILENAME 2 // Data contains a form file name (*.lfm) /* other */ #define EXT_MAX_PATH 16384 /* 16 Kb */ /* Dialog window callback function */ typedef intptr_t (DCPCALL *tDlgProc)(uintptr_t pDlg, char* DlgItemName, intptr_t Msg, intptr_t wParam, intptr_t lParam); /* Definition of callback functions called by the DLL */ typedef BOOL (DCPCALL *tInputBoxProc)(char* Caption, char* Prompt, BOOL MaskInput, char* Value, int ValueMaxLen); typedef int (DCPCALL *tMessageBoxProc)(char* Text, char* Caption, long Flags); typedef int (DCPCALL *tMsgChoiceBoxProc)(char* Text, char* Caption, char** Buttons, int BtnDef, int BtnEsc); typedef BOOL (DCPCALL *tDialogBoxLFMProc)(intptr_t LFMData, unsigned long DataSize, tDlgProc DlgProc); typedef BOOL (DCPCALL *tDialogBoxLRSProc)(intptr_t LRSData, unsigned long DataSize, tDlgProc DlgProc); typedef BOOL (DCPCALL *tDialogBoxLFMFileProc)(char* LFMFileName, tDlgProc DlgProc); typedef uintptr_t (DCPCALL *tDialogBoxParamProc)(void* Data, uint32_t DataSize, tDlgProc DlgProc, uint32_t Flags, void *UserData, void* Reserved); typedef int (DCPCALL *tTranslateStringProc)(void *Translation, const char *Identifier, const char *Original, char *Output, int OutLen); #pragma pack(push) #pragma pack(1) typedef struct { uint32_t StructSize; char PluginDir[EXT_MAX_PATH]; char PluginConfDir[EXT_MAX_PATH]; tInputBoxProc InputBox; tMessageBoxProc MessageBox; tDialogBoxLFMProc DialogBoxLFM; tDialogBoxLRSProc DialogBoxLRS; tDialogBoxLFMFileProc DialogBoxLFMFile; tDlgProc SendDlgMsg; void *Translation; tTranslateStringProc TranslateString; uintptr_t VersionAPI; tMsgChoiceBoxProc MsgChoiceBox; tDialogBoxParamProc DialogBoxParam; unsigned char Reserved[4091 * sizeof(void *)]; } tExtensionStartupInfo; #pragma pack(pop) typedef void (DCPCALL tExtensionInitializeProc)(tExtensionStartupInfo* StartupInfo); typedef void (DCPCALL tExtensionFinalizeProc)(void* Reserved); /* Plugin must implement this function for working with Extension API void DCPCALL ExtensionInitialize(tExtensionStartupInfo* StartupInfo); void DCPCALL ExtensionFinalize(void* Reserved); */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/sdk/extension.pas������������������������������������������������������������������0000644�0001750�0000144�00000016731�14743153644�016120� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Extension; interface const // dialog messages DM_FIRST = 0; DM_CLOSE = DM_FIRST+1; // A signal that the dialog is about to close DM_ENABLE = DM_FIRST+2; DM_GETDLGDATA = DM_FIRST+3; DM_GETDLGBOUNDS = DM_FIRST+4; DM_GETITEMBOUNDS = DM_FIRST+5; DM_GETTEXT = DM_FIRST+6; // Retrieve the text of an edit string or the caption of an item DM_KEYDOWN = DM_FIRST+7; DM_KEYUP = DM_FIRST+8; DM_SETDLGDATA = DM_FIRST+9; DM_SETFOCUS = DM_FIRST+10; // Set the keyboard focus to the given dialog item DM_REDRAW = DM_FIRST+11; // Redraw the whole dialog DM_SETTEXT = DM_FIRST+12; // Set a new string value for an edit line or a new caption for an item DM_SETMAXTEXTLENGTH = DM_FIRST+13; // Set the maximum length of an edit string DM_SHOWDIALOG = DM_FIRST+14; // Show/hide the dialog window DM_SHOWITEM = DM_FIRST+15; // Show/hide a dialog item DM_GETCHECK = DM_FIRST+16; // Retrieve the state of TCheckBox or TRadioButton items DM_SETCHECK = DM_FIRST+17; // Change the state of TCheckBox and TRadioButton items DM_LISTGETITEM = DM_FIRST+18; // Retrieve a list item DM_LISTGETITEMINDEX = DM_FIRST+19; // Get current item index in a list DM_LISTSETITEMINDEX = DM_FIRST+20; // Set current item index in a list DM_LISTDELETE = DM_FIRST+21; DM_LISTADD = DM_FIRST+22; DM_LISTADDSTR = DM_FIRST+23; DM_LISTUPDATE = DM_FIRST+24; DM_LISTINSERT = DM_FIRST+25; DM_LISTINDEXOF = DM_FIRST+26; DM_LISTGETCOUNT = DM_FIRST+27; DM_LISTGETDATA = DM_FIRST+28; DM_LISTSETDATA = DM_FIRST+29; DM_SETDLGBOUNDS = DM_FIRST+30; DM_SETITEMBOUNDS = DM_FIRST+31; DM_GETDROPPEDDOWN = DM_FIRST+32; DM_SETDROPPEDDOWN = DM_FIRST+33; DM_GETITEMDATA = DM_FIRST+34; DM_SETITEMDATA = DM_FIRST+35; DM_LISTSET = DM_FIRST+36; DM_SETPROGRESSVALUE = DM_FIRST+37; DM_SETPROGRESSSTYLE = DM_FIRST+38; DM_SETPASSWORDCHAR = DM_FIRST+39; DM_LISTCLEAR = DM_FIRST+40; DM_TIMERSETINTERVAL = DM_FIRST+41; // events messages DN_FIRST = $1000; DN_CLICK = DN_FIRST+1; // Sent after mouse click DN_DBLCLICK = DN_FIRST+2; // Sent after mouse double click DN_CHANGE = DN_FIRST+3; // Sent after the dialog item is changed DN_GOTFOCUS = DN_FIRST+4; // Sent when the dialog item gets input focus DN_INITDIALOG = DN_FIRST+5; // Sent before showing the dialog DN_KILLFOCUS = DN_FIRST+6; // Sent before a dialog item loses the input focus DN_TIMER = DN_FIRST+7; // Sent when a timer expires DN_KEYDOWN = DM_KEYDOWN; DN_KEYUP = DM_KEYUP; DN_CLOSE = DM_CLOSE; // Sent before the dialog is closed DM_USER = $4000; // Starting value for user defined messages const // MessageBox: To indicate the buttons displayed in the message box, // specify one of the following values. MB_OK = $00000000; MB_OKCANCEL = $00000001; MB_ABORTRETRYIGNORE = $00000002; MB_YESNOCANCEL = $00000003; MB_YESNO = $00000004; MB_RETRYCANCEL = $00000005; MB_ICONHAND = $00000010; MB_ICONQUESTION = $00000020; MB_ICONEXCLAMATION = $00000030; MB_ICONASTERICK = $00000040; MB_ICONWARNING = MB_ICONEXCLAMATION; MB_ICONERROR = MB_ICONHAND; MB_ICONSTOP = MB_ICONHAND; MB_ICONINFORMATION = MB_ICONASTERICK; // MessageBox: To indicate the default button, specify one of the following values. MB_DEFBUTTON1 = $00000000; MB_DEFBUTTON2 = $00000100; MB_DEFBUTTON3 = $00000200; MB_DEFBUTTON4 = $00000300; // MessageBox: Return values ID_OK = 1; ID_CANCEL = 2; ID_ABORT = 3; ID_RETRY = 4; ID_IGNORE = 5; ID_YES = 6; ID_NO = 7; ID_CLOSE = 8; ID_HELP = 9; // DialogBoxParam: Flags DB_LFM = 0; // Data contains a form in the LFM format DB_LRS = 1; // Data contains a form in the LRS format DB_FILENAME = 2; // Data contains a form file name (*.lfm) const EXT_MAX_PATH = 16384; // 16 Kb { For compatibility with Delphi use $IFDEF's to set calling convention } type { Dialog window callback function } TDlgProc = function(pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; { Definition of callback functions called by the DLL } TInputBoxProc = function(Caption, Prompt: PAnsiChar; MaskInput: LongBool; Value: PAnsiChar; ValueMaxLen: Integer): LongBool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TMessageBoxProc = function(Text, Caption: PAnsiChar; Flags: Longint): Integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TMsgChoiceBoxProc = function(Text, Caption: PAnsiChar; Buttons: PPAnsiChar; BtnDef, BtnEsc: Integer): Integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TDialogBoxLFMProc = function(LFMData: Pointer; DataSize: LongWord; DlgProc: TDlgProc): LongBool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TDialogBoxLRSProc = function(LRSData: Pointer; DataSize: LongWord; DlgProc: TDlgProc): LongBool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TDialogBoxLFMFileProc = function(lfmFileName: PAnsiChar; DlgProc: TDlgProc): LongBool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TDialogBoxParamProc = function(Data: Pointer; DataSize: LongWord; DlgProc: TDlgProc; Flags: LongWord; UserData, Reserved: Pointer): UIntPtr; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TTranslateStringProc = function(Translation: Pointer; Identifier, Original: PAnsiChar; Output: PAnsiChar; OutLen: Integer): Integer {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; type PExtensionStartupInfo = ^TExtensionStartupInfo; TExtensionStartupInfo = packed record // The size of the structure, in bytes StructSize: LongWord; // Directory where plugin is located (UTF-8 encoded) PluginDir: packed array [0..Pred(EXT_MAX_PATH)] of AnsiChar; // Directory where plugin configuration file must be located (UTF-8 encoded) PluginConfDir: packed array [0..Pred(EXT_MAX_PATH)] of AnsiChar; // Dialog API InputBox: TInputBoxProc; MessageBox: TMessageBoxProc; DialogBoxLFM: TDialogBoxLFMProc; DialogBoxLRS: TDialogBoxLRSProc; DialogBoxLFMFile: TDialogBoxLFMFileProc; SendDlgMsg: TDlgProc; Translation: Pointer; TranslateString: TTranslateStringProc; VersionAPI: UIntPtr; MsgChoiceBox: TMsgChoiceBoxProc; DialogBoxParam: TDialogBoxParamProc; // Reserved for future API extension Reserved: packed array [0..Pred(4091 * SizeOf(Pointer))] of Byte; end; type TExtensionInitializeProc = procedure(StartupInfo: PExtensionStartupInfo); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TExtensionFinalizeProc = procedure(Reserved: Pointer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; implementation (* Plugin must implement this function for working with Extension API procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ExtensionFinalize(Reserved: Pointer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; *) end. ���������������������������������������doublecmd-1.1.22/sdk/help/��������������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�014317� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/sdk/help/dfxplugin.html������������������������������������������������������������0000644�0001750�0000144�00000075033�14743153644�017215� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"> <html lang="en-us"> <head> <meta name="GENERATOR" content="PasDoc 0.11.0"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Writing file system plugins for Double Commander

Writing file system plugins for Double Commander

Description Structures Functions and Procedures Types Constants

Description

This help file is about writing file system plugins for Double Commander.

Functions and Procedures

HANDLE __stdcall VfsOpen(char* Path);
void __stdcall VfsClose(HANDLE hInstance);
BOOL __stdcall VfsFindFirst(HANDLE hInstance, char* Path, VFS_FIND_DATA* FindData);
BOOL __stdcall VfsFindNext(HANDLE hInstance, VFS_FIND_DATA* FindData);
void __stdcall VfsFindClose(HANDLE hInstance, VFS_FIND_DATA* FindData);
int __stdcall VfsMoveFile(HANDLE hInstance, char* OldName, char* NewName, int CopyFlags);
int __stdcall VfsDeleteFile(HANDLE hInstance, char* RemotePath);
int __stdcall VfsGetFile(HANDLE hInstance, char* RemoteName, char* LocalName, int CopyFlags);
int __stdcall VfsPutFile(HANDLE hInstance, char* LocalName, char* RemoteName, int CopyFlags);
int __stdcall VfsExecuteFile(HANDLE hInstance, HWND MainWin, char* RemoteName, char* Verb);
int __stdcall VfsCreateFolder(HANDLE hInstance, char* RemotePath);
int __stdcall VfsRemoveFolder(HANDLE hInstance, char* RemotePath);
void __stdcall VfsNetworkGetSupportedProtocols(char* Protocols, int MaxLen);
int __stdcall VfsNetworkGetConnection(HANDLE hInstance, int Index, char* Connection, int MaxLen);
int __stdcall VfsNetworkManageConnection(HANDLE hInstance, HWND MainWin, char* Connection, int Action, int MaxLen);
int __stdcall VfsNetworkOpenConnection(HANDLE hInstance, char* Connection, char* RootDir, char* RemotePath, int MaxLen);
int __stdcall VfsNetworkCloseConnection(HANDLE hInstance, char* Connection);

Constants

VFS_NM_ACTION_ADD     = 0;
VFS_NM_ACTION_EDIT    = 1;
VFS_NM_ACTION_DELETE  = 2;
VFS_RET_OK    = 0;
VFS_RET_FAILED  = 1;
VFS_RET_ABORTED  = 2;
VFS_RET_NOT_SUPPORTED    = 3;
VFS_RET_FILE_NOT_FOUND  = 4;
VFS_RET_FILE_EXISTS  = 5;
VFS_RET_READ_ERROR    = 6;
VFS_RET_WRITE_ERROR  = 7;
VFS_EXEC_OK    = 0;
VFS_EXEC_ERROR  = 1;
VFS_EXEC_YOURSELF    = 2;
VFS_EXEC_SYMLINK  = 3;

Description

Functions and Procedures

HANDLE __stdcall VfsOpen(char* Path);

Initialize and open plugin file system.

Parameters
Path
Path that must be opened by plugin
Returns

The function returns plugin instance handle if successful, NULL otherwise

void __stdcall VfsClose(HANDLE hInstance);

Finalize and close plugin file system.

Parameters
Handle
Plugin file system instance handle that have been returned by FsOpen
BOOL __stdcall VfsMoveFile(HANDLE hInstance, char* OldName, char* NewName, int CopyFlags);

VfsMoveFile is called to transfer (copy or move) a file within the plugin's file system.

Parameters
hInstance
Plugin file system instance handle
OldName
Name of the remote source file, with full path
NewName
Name of the remote destination file, with full path
CopyFlags
Can be a combination of the VFS_COPYFLAGS_XXX flags
Returns

The function returns True if successful, False otherwise

BOOL __stdcall VfsGetFile(HANDLE hInstance, char* RemoteName,char* LocalName,int CopyFlags);

VfsGetFile is called to transfer a file from the plugin's file system to the normal file system.

Parameters
hInstance
Plugin file system instance handle
RemoteName
Name of the file to be retrieved, with full path
LocalName
Local file name with full path
CopyFlags
Can be a combination of the VFS_COPYFLAGS_XXX flags
Returns

The function returns True if successful, False otherwise

BOOL __stdcall VfsPutFile(HANDLE hInstance, char* LocalName, char* RemoteName, int CopyFlags);

VfsPutFile is called to transfer a file from the normal file system to the plugin's file system.

Parameters
hInstance
Plugin file system instance handle
LocalName
Local file name with full path
RemoteName
Name of the remote file, with full path
CopyFlags
Can be a combination of the VFS_COPYFLAGS_XXX flags
Returns

The function returns True if successful, False otherwise

BOOL __stdcall VfsDeleteFile(HANDLE hInstance, char* RemotePath);

VfsDeleteFile is called to delete a file from the plugin's file system.

Parameters
hInstance
Plugin file system instance handle
RemotePath
Name of the file to be deleted, with full path
Returns

The function returns True if successful, False otherwise

int __stdcall VfsExecuteFile(HANDLE hInstance, HWND MainWin, char* RemoteName, char* Verb);

VfsExecuteFile is called to execute a file on the plugin's file system, or show its property sheet.

Parameters
hInstance
Plugin file system instance handle
MainWin
Parent window which can be used for showing a property sheet
RemoteName
Name of the file to be executed, with full path
Verb
Plugin file system instance handle that have been returned by VfsOpen
Returns

The function returns True if successful, False otherwise

int __stdcall VfsCreateFolder(HANDLE hInstance, char* RemoteName);

VfsCreateFolder is called to create a directory on the plugin's file system.

Parameters
hInstance
Plugin file system instance handle
RemoteName
Name of the directory to be created, with full path
Returns

The function returns True if successful, False otherwise

int __stdcall VfsRemoveFolder(HANDLE hInstance, char* RemoteName);

VfsRemoveFolder is called to remove a directory from the plugin's file system.

Parameters
hInstance
Plugin file system instance handle
RemoteName
Name of the directory to be removed, with full path
Returns

The function returns True if successful, False otherwise

void __stdcall VfsNetworkGetSupportedProtocols(char* Protocols, int MaxLen);

VfsNetworkGetSupportedProtocols is called to retrieve protocols that supported by plugin.

Parameters
Protocols
Pointer to a buffer (allocated by the calling program) which can receive the semicolon separated protocol list, e.g. "http://;ftp://"
MaxLen
Maximum number of characters (including the final 0) which fit in the buffer.
BOOL __stdcall VfsNetworkGetConnection(int Index, char* Connection, int MaxLen);

VfsNetworkGetConnection is called to enumerate all connections that plugin has. Index is increased by 1 starting from 0 until the plugin returns False.

Parameters
Index
The index of the connection for which DC requests information. Starting with 0, the Index is increased until the plugin returns False.
Connection
Here the plugin has to return the name of the connection with index Index. You may return a maximum of maxlen characters, including the trailing 0.
MaxLen
The maximum number of characters, including the trailing 0, which may be returned in each of the connections.
Returns

The function returns True if successful, False otherwise

BOOL __stdcall VfsNetworkManageConnection(HWND MainWin, char* Connection, int Action, int MaxLen);

VfsNetworkManageConnection is called from "Connection manager" dialog when user wants to add/edit/delete connection.

Parameters
MainWin
Parent window which can be used for showing a connection configuration dialog.
Connection
In: Connection name for edit/delete action
Out: Connection name of new connection for add action
Action
Action type: FS_NM_ACTION_ADD or FS_NM_ACTION_EDIT or FS_NM_ACTION_DELETE
MaxLen
Maximum number of characters that you can return in Connection, including the final 0.
Returns

The function returns True if successful, False otherwise

BOOL __stdcall VfsNetworkOpenConnection(char* Connection, char* RootDir, char* RemotePath, int MaxLen);

VfsNetworkOpenConnection is called when the user wants to open a connection to the network.

Parameters
Connection
In: Connection name
Out: Server address, e.g. "ftp://ftp.chg.ru"
RootDir
Here the plugin has to return the root directory of the opening connection, e.g. "/"
RemotePath
Here the plugin has to return the remote path of the opening connection, e.g. "/pub/Linux"
MaxLen
Maximum number of characters that you can return in Connection, RootDir and RemotePath, including the final 0.
Returns

The function returns True if successful, False otherwise

BOOL __stdcall VfsNetworkCloseConnection(char* Connection);

VfsNetworkOpenConnection is called when the user wants to close a connection to the network.

Parameters
Connection
Connection name
Returns

The function returns True if successful, False otherwise

Constants

VFS_NM_ACTION_ADD     = 0;

Add connection action.

VFS_NM_ACTION_EDIT    = 1;

Edit connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_RET_OK  = 0;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.

VFS_NM_ACTION_DELETE  = 2;

Delete connection action.


Double Commander DFX plugin API doublecmd-1.1.22/sdk/help/pasdoc.css0000644000175000001440000001210314743153644016277 0ustar alexxusersbody { font-family: Verdana,Arial; color: black; background-color: white; font-size: 12px; } body.navigationframe { font-family: Verdana,Arial; color: white; background-color: #787878; font-size: 12px; } img { border:0px; } a:link {color:#C91E0C; text-decoration: none; } a:visited {color:#7E5C31; text-decoration: none; } a:hover {text-decoration: underline; } a:active {text-decoration: underline; } a.navigation:link { color: white; text-decoration: none; font-size: 12px;} a.navigation:visited { color: white; text-decoration: none; font-size: 12px;} a.navigation:hover { color: white; font-weight: bold; text-decoration: none; font-size: 12px; } a.navigation:active { color: white; text-decoration: none; font-size: 12px;} a.bold:link {color:#C91E0C; text-decoration: none; font-weight:bold; } a.bold:visited {color:#7E5C31; text-decoration: none; font-weight:bold; } a.bold:hover {text-decoration: underline; font-weight:bold; } a.bold:active {text-decoration: underline; font-weight:bold; } a.section {color: green; text-decoration: none; font-weight: bold; } a.section:hover {color: green; text-decoration: underline; font-weight: bold; } ul.useslist a:link {color:#C91E0C; text-decoration: none; font-weight:bold; } ul.useslist a:visited {color:#7E5C31; text-decoration: none; font-weight:bold; } ul.useslist a:hover {text-decoration: underline; font-weight:bold; } ul.useslist a:active {text-decoration: underline; font-weight:bold; } ul.hierarchy { list-style-type:none; } ul.hierarchylevel { list-style-type:none; } p.unitlink a:link {color:#C91E0C; text-decoration: none; font-weight:bold; } p.unitlink a:visited {color:#7E5C31; text-decoration: none; font-weight:bold; } p.unitlink a:hover {text-decoration: underline; font-weight:bold; } p.unitlink a:active {text-decoration: underline; font-weight:bold; } tr.list { background: #FFBF44; } tr.list2 { background: #FFC982; } tr.listheader { background: #C91E0C; color: white; } table.wide_list { border-spacing:2px; width:100%; } table.wide_list td { vertical-align:top; padding:4px; } table.markerlegend { width:auto; } table.markerlegend td.legendmarker { text-align:center; } table.sections { background:white; } table.sections td {background:lightgray; } table.summary td.itemcode { width:100%; } table.detail td.itemcode { width:100%; } td.itemname {white-space:nowrap; } td.itemunit {white-space:nowrap; } td.itemdesc { width:100%; } div.nodescription { color:red; } dl.parameters dt { color:blue; } /* Various browsers have various default styles for
, sometimes ugly for our purposes, so it's best to set things like font-size and font-weight in out pasdoc.css explicitly. */ h6.description_section { /* font-size 100% means that it has the same font size as the parent element, i.e. normal description text */ font-size: 100%; font-weight: bold; /* By default browsers usually have some large margin-bottom and margin-top for tags. In our case, margin-bottom is unnecessary, we want to visually show that description_section is closely related to content below. In this situation (where the font size is just as a normal text), smaller bottom margin seems to look good. */ margin-bottom: 0em; } /* Style applied to Pascal code in documentation (e.g. produced by @longcode tag) } */ span.pascal_string { color: #000080; } span.pascal_keyword { font-weight: bolder; } span.pascal_comment { color: #000080; font-style: italic; } span.pascal_compiler_comment { color: #008000; } span.pascal_numeric { } span.pascal_hex { } p.hint_directive { color: red; } input#search_text { } input#search_submit_button { } acronym.mispelling { background-color: #ffa; } /* Actually this reduces vertical space between *every* paragraph inside list with @itemSpacing(compact). While we would like to reduce this space only for the top of 1st and bottom of last paragraph within each list item. But, well, user probably will not do any paragraph breaks within a list with @itemSpacing(compact) anyway, so it's acceptable solution. */ ul.compact_spacing p { margin-top: 0em; margin-bottom: 0em; } ol.compact_spacing p { margin-top: 0em; margin-bottom: 0em; } dl.compact_spacing p { margin-top: 0em; margin-bottom: 0em; } /* Style for table created by @table tags: just some thin border. This way we have some borders around the cells (so cells are visibly separated), but the border "blends with the background" so it doesn't look too ugly. Hopefully it looks satisfactory in most cases and for most people. We add padding for cells, otherwise they look too close. This is normal thing to do when border-collapse is set to collapse (because this eliminates spacing between cells). */ table.table_tag { border-collapse: collapse; } table.table_tag td { border: 1pt solid gray; padding: 0.3em; } table.table_tag th { border: 1pt solid gray; padding: 0.3em; } table.detail { border: 1pt solid gray; margin-top: 0.3em; margin-bottom: 0.3em; } doublecmd-1.1.22/sdk/wcxplugin.h0000644000175000001440000001410614743153644015562 0ustar alexxusers#include "common.h" /* Contents of file wcxhead.h */ /* It contains definitions of error codes, flags and callbacks */ /* Error codes returned to calling application */ #define E_SUCCESS 0 /* Success */ #define E_END_ARCHIVE 10 /* No more files in archive */ #define E_NO_MEMORY 11 /* Not enough memory */ #define E_BAD_DATA 12 /* Data is bad */ #define E_BAD_ARCHIVE 13 /* CRC error in archive data */ #define E_UNKNOWN_FORMAT 14 /* Archive format unknown */ #define E_EOPEN 15 /* Cannot open existing file */ #define E_ECREATE 16 /* Cannot create file */ #define E_ECLOSE 17 /* Error closing file */ #define E_EREAD 18 /* Error reading from file */ #define E_EWRITE 19 /* Error writing to file */ #define E_SMALL_BUF 20 /* Buffer too small */ #define E_EABORTED 21 /* Function aborted by user */ #define E_NO_FILES 22 /* No files found */ #define E_TOO_MANY_FILES 23 /* Too many files to pack */ #define E_NOT_SUPPORTED 24 /* Function not supported */ /* flags for unpacking */ #define PK_OM_LIST 0 #define PK_OM_EXTRACT 1 /* flags for ProcessFile */ #define PK_SKIP 0 /* Skip this file */ #define PK_TEST 1 /* Test file integrity */ #define PK_EXTRACT 2 /* Extract to disk */ /* Flags passed through ChangeVolProc */ #define PK_VOL_ASK 0 /* Ask user for location of next volume */ #define PK_VOL_NOTIFY 1 /* Notify app that next volume will be unpacked */ /* Flags for packing */ /* For PackFiles */ #define PK_PACK_MOVE_FILES 1 /* Delete original after packing */ #define PK_PACK_SAVE_PATHS 2 /* Save path names of files */ #define PK_PACK_ENCRYPT 4 /* Ask user for password, then encrypt */ /* Returned by GetPackCaps */ #define PK_CAPS_NEW 1 /* Can create new archives */ #define PK_CAPS_MODIFY 2 /* Can modify exisiting archives */ #define PK_CAPS_MULTIPLE 4 /* Archive can contain multiple files */ #define PK_CAPS_DELETE 8 /* Can delete files */ #define PK_CAPS_OPTIONS 16 /* Has options dialog */ #define PK_CAPS_MEMPACK 32 /* Supports packing in memory */ #define PK_CAPS_BY_CONTENT 64 /* Detect archive type by content */ #define PK_CAPS_SEARCHTEXT 128 /* Allow searching for text in archives */ /* created with this plugin} */ #define PK_CAPS_HIDE 256 /* Show as normal files (hide packer */ /* icon), open with Ctrl+PgDn, not Enter*/ #define PK_CAPS_ENCRYPT 512 /* Plugin supports PK_PACK_ENCRYPT option*/ /* Flags for packing in memory */ #define MEM_OPTIONS_WANTHEADERS 1 /* Return archive headers with packed data */ /* Errors returned by PackToMem */ #define MEMPACK_OK 0 /* Function call finished OK, but there is more data */ #define MEMPACK_DONE 1 /* Function call finished OK, there is no more data */ #define PK_CRYPT_SAVE_PASSWORD 1 #define PK_CRYPT_LOAD_PASSWORD 2 #define PK_CRYPT_LOAD_PASSWORD_NO_UI 3 // Load password only if master password has already been entered! #define PK_CRYPT_COPY_PASSWORD 4 // Copy encrypted password to new archive name #define PK_CRYPT_MOVE_PASSWORD 5 // Move password when renaming an archive #define PK_CRYPT_DELETE_PASSWORD 6 // Delete password #define PK_CRYPTOPT_MASTERPASS_SET 1 // The user already has a master password defined /* tHeaderData Flags */ #define RHDF_ENCRYPTED 0x04 // File encrypted with password typedef struct { char ArcName[260]; char FileName[260]; int Flags; int PackSize; int UnpSize; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tHeaderData; typedef struct { char ArcName[1024]; char FileName[1024]; int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; char Reserved[1024]; } tHeaderDataEx; typedef struct { WCHAR ArcName[1024]; WCHAR FileName[1024]; int Flags; unsigned int PackSize; unsigned int PackSizeHigh; unsigned int UnpSize; unsigned int UnpSizeHigh; int HostOS; int FileCRC; int FileTime; int UnpVer; int Method; int FileAttr; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; char Reserved[1024]; uint64_t MfileTime; } tHeaderDataExW; typedef struct { char* ArcName; int OpenMode; int OpenResult; char* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tOpenArchiveData; typedef struct { WCHAR* ArcName; int OpenMode; int OpenResult; WCHAR* CmtBuf; int CmtBufSize; int CmtSize; int CmtState; } tOpenArchiveDataW; typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } PackDefaultParamStruct; /* Definition of callback functions called by the DLL Ask to swap disk for multi-volume archive */ typedef int (DCPCALL *tChangeVolProc)(char *ArcName,int Mode); typedef int (DCPCALL *tChangeVolProcW)(WCHAR *ArcName,int Mode); /* Notify that data is processed - used for progress dialog */ typedef int (DCPCALL *tProcessDataProc)(char *FileName,int Size); typedef int (DCPCALL *tProcessDataProcW)(WCHAR *FileName,int Size); typedef int (DCPCALL *tPkCryptProc)(int CryptoNr,int Mode, char* ArchiveName,char* Password,int maxlen); typedef int (DCPCALL *tPkCryptProcW)(int CryptoNr,int Mode, WCHAR* ArchiveName,WCHAR* Password,int maxlen); doublecmd-1.1.22/sdk/wcxplugin.pas0000644000175000001440000001554514743153644016126 0ustar alexxusers{ Contents of file wcxhead.pas } { It contains definitions of error codes, flags and callbacks } { Ver. 2.20 with Unicode support } unit WcxPlugin; interface const {Error codes returned to calling application} E_SUCCESS= 0; {Success} E_END_ARCHIVE= 10; {No more files in archive} E_NO_MEMORY= 11; {Not enough memory} E_BAD_DATA= 12; {Data is bad} E_BAD_ARCHIVE= 13; {CRC error in archive data} E_UNKNOWN_FORMAT= 14; {Archive format unknown} E_EOPEN= 15; {Cannot open existing file} E_ECREATE= 16; {Cannot create file} E_ECLOSE= 17; {Error closing file} E_EREAD= 18; {Error reading from file} E_EWRITE= 19; {Error writing to file} E_SMALL_BUF= 20; {Buffer too small} E_EABORTED= 21; {Function aborted by user} E_NO_FILES= 22; {No files found} E_TOO_MANY_FILES= 23; {Too many files to pack} E_NOT_SUPPORTED= 24; {Function not supported} E_HANDLED= -32769; {Handled error} E_UNKNOWN= +32768; {Unknown error} {Unpacking flags} PK_OM_LIST= 0; PK_OM_EXTRACT= 1; {Flags for ProcessFile} PK_SKIP= 0; {Skip file (no unpacking)} PK_TEST= 1; {Test file integrity} PK_EXTRACT= 2; {Extract file to disk} {Flags passed through ChangeVolProc} PK_VOL_ASK= 0; {Ask user for location of next volume} PK_VOL_NOTIFY= 1; {Notify app that next volume will be unpacked} {Packing flags} {For PackFiles} PK_PACK_MOVE_FILES= 1; {Delete original after packing} PK_PACK_SAVE_PATHS= 2; {Save path names of files} PK_PACK_ENCRYPT= 4; {Ask user for password, then encrypt} {Returned by GetPackCaps} PK_CAPS_NEW= 1; {Can create new archives} PK_CAPS_MODIFY= 2; {Can modify exisiting archives} PK_CAPS_MULTIPLE= 4; {Archive can contain multiple files} PK_CAPS_DELETE= 8; {Can delete files} PK_CAPS_OPTIONS= 16; {Supports the options dialogbox} PK_CAPS_MEMPACK= 32; {Supports packing in memory} PK_CAPS_BY_CONTENT= 64; {Detect archive type by content} PK_CAPS_SEARCHTEXT= 128; {Allow searching for text in archives} { created with this plugin} PK_CAPS_HIDE= 256; { Show as normal files (hide packer icon) } { open with Ctrl+PgDn, not Enter } PK_CAPS_ENCRYPT= 512; { Plugin supports PK_PACK_ENCRYPT option } BACKGROUND_UNPACK=1; { Which operations are thread-safe? } BACKGROUND_PACK=2; BACKGROUND_MEMPACK=4; { For tar.pluginext in background } {Flags for packing in memory} MEM_OPTIONS_WANTHEADERS=1; {Return archive headers with packed data} {Errors returned by PackToMem} MEMPACK_OK= 0; {Function call finished OK, but there is more data} MEMPACK_DONE= 1; {Function call finished OK, there is no more data} {Flags for PkCryptProc callback} PK_CRYPT_SAVE_PASSWORD=1; PK_CRYPT_LOAD_PASSWORD=2; PK_CRYPT_LOAD_PASSWORD_NO_UI=3; { Load password only if master password has already been entered!} PK_CRYPT_COPY_PASSWORD=4; { Copy encrypted password to new archive name} PK_CRYPT_MOVE_PASSWORD=5; { Move password when renaming an archive} PK_CRYPT_DELETE_PASSWORD=6; { Delete password} PK_CRYPTOPT_MASTERPASS_SET = 1; // The user already has a master password defined { THeaderData Flags } RHDF_ENCRYPTED = $04; { File encrypted with password } type { Unsigned integer with pointer size } TArcHandle = {$IFDEF CPU64}QWord{$ELSE}LongWord{$ENDIF}; {$IFNDEF LCL} HWND = type PtrUInt; // Defined as in LCL {$ENDIF} const wcxInvalidHandle = TArcHandle(-1); { For compatibility with Delphi use $IFDEF's to set calling convention } type {Definition of callback functions called by the DLL} {Ask to swap disk for multi-volume archive} PChangeVolProc=^TChangeVolProc; TChangeVolProc=function(ArcName:pchar;Mode:longint):longint; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; PChangeVolProcW=^TChangeVolProcW; TChangeVolProcW=function(ArcName:pwidechar;Mode:longint):longint; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; {Notify that data is processed - used for progress dialog} PProcessDataProc=^TProcessDataProc; TProcessDataProc=function(FileName:pchar;Size:longint):longint; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; PProcessDataProcW=^TProcessDataProcW; TProcessDataProcW=function(FileName:pwidechar;Size:longint):longint; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; PPkCryptProc = ^TPkCryptProc; TPkCryptProc = function(CryptoNr: Integer; Mode: Integer; ArchiveName, Password: PAnsiChar; MaxLen: Integer): Integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; PPkCryptProcW = ^TPkCryptProcW; TPkCryptProcW = function(CryptoNr: Integer; Mode: Integer; ArchiveName, Password: PWideChar; MaxLen: Integer): Integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; type PHeaderData = ^THeaderData; THeaderData=packed record ArcName:array [0..259] of char; FileName:array [0..259] of char; Flags, PackSize, UnpSize, HostOS, FileCRC, FileTime, UnpVer, Method, FileAttr:longint; CmtBuf:pchar; CmtBufSize, CmtSize, CmtState:longint; end; PHeaderDataEx = ^THeaderDataEx; THeaderDataEx=packed record ArcName:array [0..1023] of char; FileName:array [0..1023] of char; Flags:longint; PackSize, PackSizeHigh, UnpSize, UnpSizeHigh:longword; HostOS, FileCRC, FileTime, UnpVer, Method, FileAttr:longint; CmtBuf:pchar; CmtBufSize, CmtSize, CmtState:longint; Reserved:array[0..1023] of char; end; PHeaderDataExW=^THeaderDataExW; THeaderDataExW=packed record ArcName:array [0..1023] of widechar; FileName:array [0..1023] of widechar; Flags:longint; PackSize, PackSizeHigh, UnpSize, UnpSizeHigh:longword; HostOS, FileCRC, FileTime, UnpVer, Method, FileAttr:longint; CmtBuf:pchar; CmtBufSize, CmtSize, CmtState:longint; Reserved:array[0..1023] of char; MfileTime: UInt64; end; tOpenArchiveData=packed record ArcName:pchar; OpenMode, OpenResult:longint; CmtBuf:pchar; CmtBufSize, CmtSize, CmtState:longint; end; tOpenArchiveDataW=packed record ArcName:pwidechar; OpenMode, OpenResult:longint; CmtBuf:pwidechar; CmtBufSize, CmtSize, CmtState:longint; end; tPackDefaultParamStruct=record size, PluginInterfaceVersionLow, PluginInterfaceVersionHi:longint; DefaultIniName:array[0..259] of char; end; pPackDefaultParamStruct=^tPackDefaultParamStruct; implementation end. doublecmd-1.1.22/sdk/wdxplugin.h0000644000175000001440000000740414743153644015566 0ustar alexxusers#ifndef _WDX_H #define _WDX_H #include "common.h" // Contents of file contplug.h version 2.0 #define ft_nomorefields 0 #define ft_numeric_32 1 #define ft_numeric_64 2 #define ft_numeric_floating 3 #define ft_date 4 #define ft_time 5 #define ft_boolean 6 #define ft_multiplechoice 7 #define ft_string 8 #define ft_fulltext 9 #define ft_datetime 10 #define ft_stringw 11 #define ft_fulltextw 12 // for ContentGetValue #define ft_nosuchfield -1 // error, invalid field number given #define ft_fileerror -2 // file i/o error #define ft_fieldempty -3 // field valid, but empty #define ft_ondemand -4 // field will be retrieved only when user presses #define ft_notsupported -5 // function not supported #define ft_setcancel -6 // user clicked cancel in field editor #define ft_delayed 0 // field takes a long time to extract -> try again in background // for ContentSetValue #define ft_setsuccess 0 // setting of the attribute succeeded // for ContentGetSupportedFieldFlags #define contflags_edit 1 #define contflags_substsize 2 #define contflags_substdatetime 4 #define contflags_substdate 6 #define contflags_substtime 8 #define contflags_substattributes 10 #define contflags_substattributestr 12 #define contflags_passthrough_size_float 14 #define contflags_substmask 14 #define contflags_fieldedit 16 #define contst_readnewdir 1 #define contst_refreshpressed 2 #define contst_showhint 4 #define setflags_first_attribute 1 // First attribute of this file #define setflags_last_attribute 2 // Last attribute of this file #define setflags_only_date 4 // Only set the date of the datetime value! #define editflags_initialize 1 // The data passed to the plugin may be used to // initialize the edit dialog #define CONTENT_DELAYIFSLOW 1 // ContentGetValue called in foreground #define CONTENT_PASSTHROUGH 2 // If requested via contflags_passthrough_size_float: The size // is passed in as floating value, TC expects correct value // from the given units value, and optionally a text string typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } ContentDefaultParamStruct; typedef struct { WORD wYear; WORD wMonth; WORD wDay; } tdateformat,*pdateformat; typedef struct { WORD wHour; WORD wMinute; WORD wSecond; } ttimeformat,*ptimeformat; #ifdef __cplusplus extern "C" { #endif int DCPCALL ContentGetDetectString(char* DetectString,int maxlen); int DCPCALL ContentGetSupportedField(int FieldIndex,char* FieldName,char* Units,int maxlen); int DCPCALL ContentGetValue(char* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags); int DCPCALL ContentGetValueW(WCHAR* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags); void DCPCALL ContentSetDefaultParams(ContentDefaultParamStruct* dps); void DCPCALL ContentPluginUnloading(void); void DCPCALL ContentStopGetValue(char* FileName); void DCPCALL ContentStopGetValueW(WCHAR* FileName); int DCPCALL ContentGetDefaultSortOrder(int FieldIndex); int DCPCALL ContentGetSupportedFieldFlags(int FieldIndex); int DCPCALL ContentSetValue(char* FileName,int FieldIndex,int UnitIndex,int FieldType,void* FieldValue,int flags); int DCPCALL ContentSetValueW(WCHAR* FileName,int FieldIndex,int UnitIndex,int FieldType,void* FieldValue,int flags); int DCPCALL ContentEditValue(HWND ParentWin,int FieldIndex,int UnitIndex,int FieldType, void* FieldValue,int maxlen,int flags,char* langidentifier); void DCPCALL ContentSendStateInformation(int state,char* path); void DCPCALL ContentSendStateInformationW(int state,WCHAR* path); #ifdef __cplusplus } #endif #endif // _WDX_H doublecmd-1.1.22/sdk/wdxplugin.pas0000644000175000001440000001017414743153644016120 0ustar alexxusersunit WdxPlugin; { Content plugins } interface uses SysUtils; const ft_nomorefields=0; ft_numeric_32=1; ft_numeric_64=2; ft_numeric_floating=3; ft_date=4; ft_time=5; ft_boolean=6; ft_multiplechoice=7; ft_string=8; ft_fulltext=9; ft_datetime=10; ft_stringw=11; ft_fulltextw=12; // for ContentGetValue ft_nosuchfield=-1; ft_fileerror=-2; ft_fieldempty=-3; ft_ondemand=-4; ft_notsupported=-5; ft_setcancel=-6; ft_delayed=0; // for ContentSetValue ft_setsuccess=0; // setting of the attribute succeeded // for ContentGetSupportedFieldFlags contflags_edit=1; contflags_substsize=2; contflags_substdatetime=4; contflags_substdate=6; contflags_substtime=8; contflags_substattributes=10; contflags_substattributestr=12; contflags_passthrough_size_float=14; contflags_substmask=14; contflags_fieldedit=16; // for ContentSendStateInformation contst_readnewdir=1; contst_refreshpressed=2; contst_showhint=4; setflags_first_attribute=1; // First attribute of this file setflags_last_attribute=2; // Last attribute of this file setflags_only_date=4; // Only set the date of the datetime value! CONTENT_DELAYIFSLOW=1; // ContentGetValue called in foreground CONTENT_PASSTHROUGH=2; // If requested via contflags_passthrough_size_float: The size // is passed in as floating value, TC expects correct value // from the given units value, and optionally a text string type tContentDefaultParamStruct=record size, PluginInterfaceVersionLow, PluginInterfaceVersionHi:longint; DefaultIniName:array[0..MAX_PATH-1] of char; end; pContentDefaultParamStruct=^tContentDefaultParamStruct; type tdateformat=record wYear,wMonth,wDay:word; end; pdateformat=^tdateformat; type ttimeformat=record wHour,wMinute,wSecond:word; end; ptimeformat=^ttimeformat; { Function prototypes: } (* procedure ContentGetDetectString(DetectString:pchar;maxlen:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentGetSupportedField(FieldIndex:integer;FieldName:pchar; Units:pchar;maxlen:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentGetValue(FileName:pchar;FieldIndex,UnitIndex:integer; FieldValue:pbyte; maxlen,flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentGetValueW(FileName:pwidechar;FieldIndex,UnitIndex:integer; FieldValue:pbyte; maxlen,flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ContentSetDefaultParams(dps:pContentDefaultParamStruct); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ContentPluginUnloading; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ContentStopGetValue(FileName:pchar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ContentStopGetValueW(FileName:pwidechar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentGetDefaultSortOrder(FieldIndex:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentGetSupportedFieldFlags(FieldIndex:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentSetValue(FileName:pchar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentSetValueW(FileName:pwidechar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ContentSendStateInformation(state:integer;path:pchar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ContentSendStateInformationW(state:integer;path:pwidechar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ContentEditValue(handle:thandle;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pchar;maxlen:integer;flags:integer;langidentifier:pchar):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; *) implementation end. doublecmd-1.1.22/sdk/wfxplugin.h0000644000175000001440000002425414743153644015572 0ustar alexxusers#include "common.h" // contents of fsplugin.h version 2.1 (27.April.2010) // ids for FsGetFile #define FS_FILE_OK 0 #define FS_FILE_EXISTS 1 #define FS_FILE_NOTFOUND 2 #define FS_FILE_READERROR 3 #define FS_FILE_WRITEERROR 4 #define FS_FILE_USERABORT 5 #define FS_FILE_NOTSUPPORTED 6 #define FS_FILE_EXISTSRESUMEALLOWED 7 #define FS_EXEC_OK 0 #define FS_EXEC_ERROR 1 #define FS_EXEC_YOURSELF -1 #define FS_EXEC_SYMLINK -2 #define FS_COPYFLAGS_OVERWRITE 1 #define FS_COPYFLAGS_RESUME 2 #define FS_COPYFLAGS_MOVE 4 #define FS_COPYFLAGS_EXISTS_SAMECASE 8 #define FS_COPYFLAGS_EXISTS_DIFFERENTCASE 16 // flags for tRequestProc #define RT_Other 0 #define RT_UserName 1 #define RT_Password 2 #define RT_Account 3 #define RT_UserNameFirewall 4 #define RT_PasswordFirewall 5 #define RT_TargetDir 6 #define RT_URL 7 #define RT_MsgOK 8 #define RT_MsgYesNo 9 #define RT_MsgOKCancel 10 // flags for tLogProc #define MSGTYPE_CONNECT 1 #define MSGTYPE_DISCONNECT 2 #define MSGTYPE_DETAILS 3 #define MSGTYPE_TRANSFERCOMPLETE 4 #define MSGTYPE_CONNECTCOMPLETE 5 #define MSGTYPE_IMPORTANTERROR 6 #define MSGTYPE_OPERATIONCOMPLETE 7 // flags for FsStatusInfo #define FS_STATUS_START 0 #define FS_STATUS_END 1 #define FS_STATUS_OP_LIST 1 #define FS_STATUS_OP_GET_SINGLE 2 #define FS_STATUS_OP_GET_MULTI 3 #define FS_STATUS_OP_PUT_SINGLE 4 #define FS_STATUS_OP_PUT_MULTI 5 #define FS_STATUS_OP_RENMOV_SINGLE 6 #define FS_STATUS_OP_RENMOV_MULTI 7 #define FS_STATUS_OP_DELETE 8 #define FS_STATUS_OP_ATTRIB 9 #define FS_STATUS_OP_MKDIR 10 #define FS_STATUS_OP_EXEC 11 #define FS_STATUS_OP_CALCSIZE 12 #define FS_STATUS_OP_SEARCH 13 #define FS_STATUS_OP_SEARCH_TEXT 14 #define FS_STATUS_OP_SYNC_SEARCH 15 #define FS_STATUS_OP_SYNC_GET 16 #define FS_STATUS_OP_SYNC_PUT 17 #define FS_STATUS_OP_SYNC_DELETE 18 #define FS_STATUS_OP_GET_MULTI_THREAD 19 #define FS_STATUS_OP_PUT_MULTI_THREAD 20 #define FS_ICONFLAG_SMALL 1 #define FS_ICONFLAG_BACKGROUND 2 #define FS_ICON_USEDEFAULT 0 #define FS_ICON_EXTRACTED 1 #define FS_ICON_EXTRACTED_DESTROY 2 #define FS_ICON_DELAYED 3 #define FS_BITMAP_NONE 0 #define FS_BITMAP_EXTRACTED 1 #define FS_BITMAP_EXTRACT_YOURSELF 2 #define FS_BITMAP_EXTRACT_YOURSELF_ANDDELETE 3 #define FS_BITMAP_CACHE 256 #define FS_CRYPT_SAVE_PASSWORD 1 #define FS_CRYPT_LOAD_PASSWORD 2 #define FS_CRYPT_LOAD_PASSWORD_NO_UI 3 // Load password only if master password has already been entered! #define FS_CRYPT_COPY_PASSWORD 4 // Copy encrypted password to new connection name #define FS_CRYPT_MOVE_PASSWORD 5 // Move password when renaming a connection #define FS_CRYPT_DELETE_PASSWORD 6 // Delete password #define FS_CRYPTOPT_MASTERPASS_SET 1 // The user already has a master password defined #define BG_DOWNLOAD 1 // Plugin supports downloads in background #define BG_UPLOAD 2 // Plugin supports uploads in background #define BG_ASK_USER 4 // Plugin requires separate connection for background transfers -> ask user first // flags for FsFindFirst/FsFindNext #define FILE_ATTRIBUTE_DIRECTORY 16 #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 #define FILE_ATTRIBUTE_UNIX_MODE 0x80000000 typedef struct { DWORD SizeLow,SizeHigh; FILETIME LastWriteTime; int Attr; } RemoteInfoStruct; typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } FsDefaultParamStruct; // callback functions typedef int (DCPCALL *tProgressProc)(int PluginNr,char* SourceName, char* TargetName,int PercentDone); typedef int (DCPCALL *tProgressProcW)(int PluginNr,WCHAR* SourceName, WCHAR* TargetName,int PercentDone); typedef void (DCPCALL *tLogProc)(int PluginNr,int MsgType,char* LogString); typedef void (DCPCALL *tLogProcW)(int PluginNr,int MsgType,WCHAR* LogString); typedef BOOL (DCPCALL *tRequestProc)(int PluginNr,int RequestType,char* CustomTitle, char* CustomText,char* ReturnedText,int maxlen); typedef BOOL (DCPCALL *tRequestProcW)(int PluginNr,int RequestType,WCHAR* CustomTitle, WCHAR* CustomText,WCHAR* ReturnedText,int maxlen); typedef int (DCPCALL *tCryptProc)(int PluginNr,int CryptoNr,int Mode, char* ConnectionName,char* Password,int maxlen); typedef int (DCPCALL *tCryptProcW)(int PluginNr,int CryptoNr,int Mode, WCHAR* ConnectionName,WCHAR* Password,int maxlen); // Function prototypes int DCPCALL FsInit(int PluginNr,tProgressProc pProgressProc, tLogProc pLogProc,tRequestProc pRequestProc); int DCPCALL FsInitW(int PluginNr,tProgressProcW pProgressProcW, tLogProcW pLogProcW,tRequestProcW pRequestProcW); void DCPCALL FsSetCryptCallback(tCryptProc pCryptProc,int CryptoNr,int Flags); void DCPCALL FsSetCryptCallbackW(tCryptProcW pCryptProcW,int CryptoNr,int Flags); HANDLE DCPCALL FsFindFirst(char* Path,WIN32_FIND_DATAA *FindData); HANDLE DCPCALL FsFindFirstW(WCHAR* Path,WIN32_FIND_DATAW *FindData); BOOL DCPCALL FsFindNext(HANDLE Hdl,WIN32_FIND_DATAA *FindData); BOOL DCPCALL FsFindNextW(HANDLE Hdl,WIN32_FIND_DATAW *FindData); int DCPCALL FsFindClose(HANDLE Hdl); BOOL DCPCALL FsMkDir(char* Path); BOOL DCPCALL FsMkDirW(WCHAR* Path); int DCPCALL FsExecuteFile(HWND MainWin,char* RemoteName,char* Verb); int DCPCALL FsExecuteFileW(HWND MainWin,WCHAR* RemoteName,WCHAR* Verb); int DCPCALL FsRenMovFile(char* OldName,char* NewName,BOOL Move, BOOL OverWrite,RemoteInfoStruct* ri); int DCPCALL FsRenMovFileW(WCHAR* OldName,WCHAR* NewName,BOOL Move, BOOL OverWrite,RemoteInfoStruct* ri); int DCPCALL FsGetFile(char* RemoteName,char* LocalName,int CopyFlags, RemoteInfoStruct* ri); int DCPCALL FsGetFileW(WCHAR* RemoteName,WCHAR* LocalName,int CopyFlags, RemoteInfoStruct* ri); int DCPCALL FsPutFile(char* LocalName,char* RemoteName,int CopyFlags); int DCPCALL FsPutFileW(WCHAR* LocalName,WCHAR* RemoteName,int CopyFlags); BOOL DCPCALL FsDeleteFile(char* RemoteName); BOOL DCPCALL FsDeleteFileW(WCHAR* RemoteName); BOOL DCPCALL FsRemoveDir(char* RemoteName); BOOL DCPCALL FsRemoveDirW(WCHAR* RemoteName); BOOL DCPCALL FsDisconnect(char* DisconnectRoot); BOOL DCPCALL FsDisconnectW(WCHAR* DisconnectRoot); BOOL DCPCALL FsSetAttr(char* RemoteName,int NewAttr); BOOL DCPCALL FsSetAttrW(WCHAR* RemoteName,int NewAttr); BOOL DCPCALL FsSetTime(char* RemoteName,FILETIME *CreationTime, FILETIME *LastAccessTime,FILETIME *LastWriteTime); BOOL DCPCALL FsSetTimeW(WCHAR* RemoteName,FILETIME *CreationTime, FILETIME *LastAccessTime,FILETIME *LastWriteTime); void DCPCALL FsStatusInfo(char* RemoteDir,int InfoStartEnd,int InfoOperation); void DCPCALL FsStatusInfoW(WCHAR* RemoteDir,int InfoStartEnd,int InfoOperation); void DCPCALL FsGetDefRootName(char* DefRootName,int maxlen); int DCPCALL FsExtractCustomIcon(char* RemoteName,int ExtractFlags,HICON* TheIcon); int DCPCALL FsExtractCustomIconW(WCHAR* RemoteName,int ExtractFlags,HICON* TheIcon); void DCPCALL FsSetDefaultParams(FsDefaultParamStruct* dps); int DCPCALL FsGetPreviewBitmap(char* RemoteName,int width,int height,HBITMAP* ReturnedBitmap); int DCPCALL FsGetPreviewBitmapW(WCHAR* RemoteName,int width,int height,HBITMAP* ReturnedBitmap); BOOL DCPCALL FsLinksToLocalFiles(void); BOOL DCPCALL FsGetLocalName(char* RemoteName,int maxlen); BOOL DCPCALL FsGetLocalNameW(WCHAR* RemoteName,int maxlen); // ************************** content plugin extension **************************** // #define ft_nomorefields 0 #define ft_numeric_32 1 #define ft_numeric_64 2 #define ft_numeric_floating 3 #define ft_date 4 #define ft_time 5 #define ft_boolean 6 #define ft_multiplechoice 7 #define ft_string 8 #define ft_fulltext 9 #define ft_datetime 10 #define ft_stringw 11 // Should only be returned by Unicode function // for FsContentGetValue #define ft_nosuchfield -1 // error, invalid field number given #define ft_fileerror -2 // file i/o error #define ft_fieldempty -3 // field valid, but empty #define ft_ondemand -4 // field will be retrieved only when user presses #define ft_delayed 0 // field takes a long time to extract -> try again in background // for FsContentSetValue #define ft_setsuccess 0 // setting of the attribute succeeded // for FsContentGetSupportedFieldFlags #define contflags_edit 1 #define contflags_substsize 2 #define contflags_substdatetime 4 #define contflags_substdate 6 #define contflags_substtime 8 #define contflags_substattributes 10 #define contflags_substattributestr 12 #define contflags_substmask 14 // for FsContentSetValue #define setflags_first_attribute 1 // First attribute of this file #define setflags_last_attribute 2 // Last attribute of this file #define setflags_only_date 4 // Only set the date of the datetime value! #define CONTENT_DELAYIFSLOW 1 // ContentGetValue called in foreground typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } ContentDefaultParamStruct; typedef struct { WORD wYear; WORD wMonth; WORD wDay; } tdateformat,*pdateformat; typedef struct { WORD wHour; WORD wMinute; WORD wSecond; } ttimeformat,*ptimeformat; int DCPCALL FsContentGetSupportedField(int FieldIndex,char* FieldName,char* Units,int maxlen); int DCPCALL FsContentGetValue(char* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags); int DCPCALL FsContentGetValueW(WCHAR* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags); void DCPCALL FsContentStopGetValue(char* FileName); void DCPCALL FsContentStopGetValueW(WCHAR* FileName); int DCPCALL FsContentGetDefaultSortOrder(int FieldIndex); void DCPCALL FsContentPluginUnloading(void); int DCPCALL FsContentGetSupportedFieldFlags(int FieldIndex); int DCPCALL FsContentSetValue(char* FileName,int FieldIndex,int UnitIndex,int FieldType,void* FieldValue,int flags); int DCPCALL FsContentSetValueW(WCHAR* FileName,int FieldIndex,int UnitIndex,int FieldType,void* FieldValue,int flags); BOOL DCPCALL FsContentGetDefaultView(char* ViewContents,char* ViewHeaders,char* ViewWidths,char* ViewOptions,int maxlen); BOOL DCPCALL FsContentGetDefaultViewW(WCHAR* ViewContents,WCHAR* ViewHeaders,WCHAR* ViewWidths,WCHAR* ViewOptions,int maxlen);doublecmd-1.1.22/sdk/wfxplugin.pas0000644000175000001440000003470214743153644016125 0ustar alexxusersunit WfxPlugin; { Plugin definitions version 2.0 } interface uses SysUtils {$IFDEF MSWINDOWS}, Windows{$ENDIF}; { ids for FsGetFile } const FS_FILE_OK=0; FS_FILE_EXISTS=1; FS_FILE_NOTFOUND=2; FS_FILE_READERROR=3; FS_FILE_WRITEERROR=4; FS_FILE_USERABORT=5; FS_FILE_NOTSUPPORTED=6; FS_FILE_EXISTSRESUMEALLOWED=7; FS_EXEC_OK=0; FS_EXEC_ERROR=1; FS_EXEC_YOURSELF=-1; FS_EXEC_SYMLINK=-2; FS_COPYFLAGS_OVERWRITE=1; FS_COPYFLAGS_RESUME=2; FS_COPYFLAGS_MOVE=4; FS_COPYFLAGS_EXISTS_SAMECASE=8; FS_COPYFLAGS_EXISTS_DIFFERENTCASE=16; { flags for tRequestProc } const RT_Other=0; RT_UserName=1; RT_Password=2; RT_Account=3; RT_UserNameFirewall=4; RT_PasswordFirewall=5; RT_TargetDir=6; RT_URL=7; RT_MsgOK=8; RT_MsgYesNo=9; RT_MsgOKCancel=10; { flags for tLogProc } const msgtype_connect=1; msgtype_disconnect=2; msgtype_details=3; msgtype_transfercomplete=4; msgtype_connectcomplete=5; msgtype_importanterror=6; msgtype_operationcomplete=7; { flags for FsStatusInfo } const FS_STATUS_START=0; FS_STATUS_END=1; FS_STATUS_OP_LIST=1; FS_STATUS_OP_GET_SINGLE=2; FS_STATUS_OP_GET_MULTI=3; FS_STATUS_OP_PUT_SINGLE=4; FS_STATUS_OP_PUT_MULTI=5; FS_STATUS_OP_RENMOV_SINGLE=6; FS_STATUS_OP_RENMOV_MULTI=7; FS_STATUS_OP_DELETE=8; FS_STATUS_OP_ATTRIB=9; FS_STATUS_OP_MKDIR=10; FS_STATUS_OP_EXEC=11; FS_STATUS_OP_CALCSIZE=12; FS_STATUS_OP_SEARCH=13; FS_STATUS_OP_SEARCH_TEXT=14; FS_STATUS_OP_SYNC_SEARCH=15; FS_STATUS_OP_SYNC_GET=16; FS_STATUS_OP_SYNC_PUT=17; FS_STATUS_OP_SYNC_DELETE=18; FS_STATUS_OP_GET_MULTI_THREAD=19; FS_STATUS_OP_PUT_MULTI_THREAD=20; {Flags for FsExtractCustomIcon} const FS_ICONFLAG_SMALL=1; FS_ICONFLAG_BACKGROUND=2; FS_ICON_USEDEFAULT=0; FS_ICON_EXTRACTED=1; FS_ICON_EXTRACTED_DESTROY=2; FS_ICON_DELAYED=3; const FS_BITMAP_NONE=0; FS_BITMAP_EXTRACTED=1; FS_BITMAP_EXTRACT_YOURSELF=2; FS_BITMAP_EXTRACT_YOURSELF_ANDDELETE=3; FS_BITMAP_CACHE=256; {Flags for crypto callback function} FS_CRYPT_SAVE_PASSWORD=1; FS_CRYPT_LOAD_PASSWORD=2; FS_CRYPT_LOAD_PASSWORD_NO_UI=3; {Load password only if master password has already been entered!} FS_CRYPT_COPY_PASSWORD=4; FS_CRYPT_MOVE_PASSWORD=5; FS_CRYPT_DELETE_PASSWORD=6; FS_CRYPTOPT_MASTERPASS_SET=1; {The user already has a master password defined} {Flags for FsGetBackgroundFlags} BG_DOWNLOAD=1; { Plugin supports downloads in background } BG_UPLOAD=2; { Plugin supports uploads in background } BG_ASK_USER=4; { Plugin requires separate connection for background transfers -> ask user first } type { Unsigned integer with pointer size } THandle = {$IFDEF CPU64}QWord{$ELSE}LongWord{$ENDIF}; const wfxInvalidHandle: THandle = THandle(-1); { Some Windows specific stuff } const MAXDWORD = DWORD($FFFFFFFF); FILE_ATTRIBUTE_NORMAL = 128; FILE_ATTRIBUTE_DIRECTORY = 16; FILE_ATTRIBUTE_REPARSE_POINT = $0400; FILE_ATTRIBUTE_UNIX_MODE = $80000000; type TInt64Rec = packed record case Boolean of True : (Value : Int64); False : (Low, High : DWORD); end; BOOL = LongBool; HBITMAP = THandle; HICON = THandle; HWND = THandle; type {$IFDEF MSWINDOWS} FILETIME = Windows.FILETIME; {$ELSE} FILETIME = packed record dwLowDateTime : DWORD; dwHighDateTime : DWORD; end; {$ENDIF} TFileTime = FILETIME; // for compatibility with all plugins PFileTime = ^FILETIME; TWfxFileTime = FILETIME; PWfxFileTime = ^FILETIME; {$IFDEF MSWINDOWS} WIN32_FIND_DATAA = Windows.WIN32_FIND_DATA; {$ELSE} WIN32_FIND_DATAA = packed record dwFileAttributes : DWORD; ftCreationTime : TFILETIME; ftLastAccessTime : TFILETIME; ftLastWriteTime : TFILETIME; nFileSizeHigh : DWORD; nFileSizeLow : DWORD; dwReserved0 : DWORD; dwReserved1 : DWORD; cFileName : array[0..(MAX_PATH)-1] of CHAR; cAlternateFileName : array[0..13] of CHAR; end; {$ENDIF} TWin32FindData = WIN32_FIND_DATAA; {$IFDEF MSWINDOWS} WIN32_FIND_DATAW = Windows.WIN32_FIND_DATAW; {$ELSE} WIN32_FIND_DATAW = packed record dwFileAttributes : DWORD; ftCreationTime : TFILETIME; ftLastAccessTime : TFILETIME; ftLastWriteTime : TFILETIME; nFileSizeHigh : DWORD; nFileSizeLow : DWORD; dwReserved0 : DWORD; dwReserved1 : DWORD; cFileName : array[0..(MAX_PATH)-1] of WCHAR; cAlternateFileName : array[0..13] of WCHAR; end; {$ENDIF} TWin32FindDataW = WIN32_FIND_DATAW; type tRemoteInfo=record SizeLow,SizeHigh:longint; LastWriteTime:TFileTime; Attr:longint; end; pRemoteInfo=^tRemoteInfo; type tFsDefaultParamStruct=record size, PluginInterfaceVersionLow, PluginInterfaceVersionHi:longint; DefaultIniName:array[0..MAX_PATH-1] of char; end; pFsDefaultParamStruct=^tFsDefaultParamStruct; { For compatibility with Delphi use $IFDEF's to set calling convention } { callback functions } type TProgressProc=function(PluginNr:integer;SourceName, TargetName:pchar;PercentDone:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TProgressProcW=function(PluginNr:integer;SourceName, TargetName:pwidechar;PercentDone:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TLogProc=procedure(PluginNr,MsgType:integer;LogString:pchar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TLogProcW=procedure(PluginNr,MsgType:integer;LogString:pwidechar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TRequestProc=function(PluginNr,RequestType:integer;CustomTitle,CustomText, ReturnedText:pchar;maxlen:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TRequestProcW=function(PluginNr,RequestType:integer;CustomTitle,CustomText, ReturnedText:pwidechar;maxlen:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TCryptProc=function(PluginNr,CryptoNumber:integer;mode:integer;ConnectionName, Password:pchar;maxlen:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; TCryptProcW=function(PluginNr,CryptoNumber:integer;mode:integer;ConnectionName, Password:pwidechar;maxlen:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; { Function prototypes - the callback functions MUST be implemented exactly like this! } (* function FsInit(PluginNr:integer;pProgressProc:tProgressProc;pLogProc:tLogProc; pRequestProc:tRequestProc):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsInitW(PluginNr:integer;pProgressProcW:tProgressProcW;pLogProcW:tLogProcW; pRequestProcW:tRequestProcW):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsSetCryptCallback(CryptProc:TCryptProc;CryptoNr,Flags:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsSetCryptCallbackW(CryptProcW:TCryptProcW;CryptoNr,Flags:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsFindFirst(path :pchar;var FindData:tWIN32FINDDATA):thandle; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsFindFirstW(path :pwidechar;var FindData:tWIN32FINDDATAW):thandle; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsFindNext(Hdl:thandle;var FindData:tWIN32FINDDATA):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsFindNextW(Hdl:thandle;var FindDataW:tWIN32FINDDATAW):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsFindClose(Hdl:thandle):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsMkDir(RemoteDir:pchar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsMkDirW(RemoteDir:pwidechar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsExecuteFile(MainWin:HWND;RemoteName,Verb:pchar):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsExecuteFileW(MainWin:HWND;RemoteName,Verb:pwidechar):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsRenMovFile(OldName,NewName:pchar;Move,OverWrite:bool; RemoteInfo:pRemoteInfo):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsRenMovFileW(OldName,NewName:pwidechar;Move,OverWrite:bool; RemoteInfo:pRemoteInfo):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetFile(RemoteName,LocalName:pchar;CopyFlags:integer; RemoteInfo:pRemoteInfo):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetFileW(RemoteName,LocalName:pwidechar;CopyFlags:integer; RemoteInfo:pRemoteInfo):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsPutFile(LocalName,RemoteName:pchar;CopyFlags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsPutFileW(LocalName,RemoteName:pwidechar;CopyFlags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsDeleteFile(RemoteName:pchar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsDeleteFileW(RemoteName:pwidechar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsRemoveDir(RemoteName:pchar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsRemoveDirW(RemoteName:pwidechar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsDisconnect(DisconnectRoot:pchar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsDisconnectW(DisconnectRoot:pwidechar):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsSetAttr(RemoteName:pchar;NewAttr:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsSetAttrW(RemoteName:pwidechar;NewAttr:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsSetTime(RemoteName:pchar;CreationTime,LastAccessTime, LastWriteTime:PFileTime):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsSetTimeW(RemoteName:pwidechar;CreationTime,LastAccessTime, LastWriteTime:PFileTime):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsStatusInfo(RemoteDir:pchar;InfoStartEnd,InfoOperation:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsStatusInfoW(RemoteDir:pwidechar;InfoStartEnd,InfoOperation:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsGetDefRootName(DefRootName:pchar;maxlen:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsExtractCustomIcon(RemoteName:pchar;ExtractFlags:integer; var TheIcon:hicon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsExtractCustomIconW(RemoteName:pwidechar;ExtractFlags:integer; var TheIcon:hicon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsSetDefaultParams(dps:pFsDefaultParamStruct); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetPreviewBitmap(RemoteName:pchar;width,height:integer, var ReturnedBitmap:hbitmap):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetPreviewBitmapW(RemoteName:pwidechar;width,height:integer, var ReturnedBitmap:hbitmap):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsLinksToLocalFiles:bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetLocalName(RemoteName:pchar;maxlen:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetLocalNameW(RemoteName:pwidechar;maxlen:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; *) {****************************** content plugin part *****************************} const ft_nomorefields=0; ft_numeric_32=1; ft_numeric_64=2; ft_numeric_floating=3; ft_date=4; ft_time=5; ft_boolean=6; ft_multiplechoice=7; ft_string=8; ft_fulltext=9; ft_datetime=10; ft_stringw=11; // for ContentGetValue ft_nosuchfield=-1; ft_fileerror=-2; ft_fieldempty=-3; ft_ondemand=-4; ft_delayed=0; // for ContentSetValue ft_setsuccess=0; setflags_first_attribute=1; {First attribute of this file} setflags_last_attribute=2; setflags_only_date=4; CONTENT_DELAYIFSLOW=1; // ContentGetValue called in foreground type tContentDefaultParamStruct=record size, PluginInterfaceVersionLow, PluginInterfaceVersionHi:longint; DefaultIniName:array[0..MAX_PATH-1] of char; end; pContentDefaultParamStruct=^tContentDefaultParamStruct; type tdateformat=record wYear,wMonth,wDay:word; end; pdateformat=^tdateformat; type ttimeformat=record wHour,wMinute,wSecond:word; end; ptimeformat=^ttimeformat; { Function prototypes: } (* procedure FsContentGetDetectString(DetectString:pchar;maxlen:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetSupportedField(FieldIndex:integer;FieldName:pchar; Units:pchar;maxlen:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetValue(FileName:pchar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetValueW(FileName:pwidechar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsContentSetDefaultParams(dps:pContentDefaultParamStruct); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsContentStopGetValue(FileName:pchar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure FsContentStopGetValueW(FileName:pwidechar); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetDefaultSortOrder(FieldIndex:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetSupportedFieldFlags(FieldIndex:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentSetValue(FileName:pchar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentSetValueW(FileName:pwidechar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetDefaultView(ViewContents,ViewHeaders,ViewWidths, ViewOptions:pchar;maxlen:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsContentGetDefaultViewW(ViewContents,ViewHeaders,ViewWidths, ViewOptions:pwidechar;maxlen:integer):bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function FsGetBackgroundFlags:integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; *) implementation end. doublecmd-1.1.22/sdk/wlxplugin.h0000644000175000001440000000435614743153644015601 0ustar alexxusers#ifndef _WLX_H #define _WLX_H #include "common.h" /* Contents of file listplug.h */ #define lc_copy 1 #define lc_newparams 2 #define lc_selectall 3 #define lc_setpercent 4 #define lcp_wraptext 1 #define lcp_fittowindow 2 #define lcp_ansi 4 #define lcp_ascii 8 #define lcp_variable 12 #define lcp_forceshow 16 #define lcp_fitlargeronly 32 #define lcp_center 64 #define lcs_findfirst 1 #define lcs_matchcase 2 #define lcs_wholewords 4 #define lcs_backwards 8 #define itm_percent 0xFFFE #define itm_fontstyle 0xFFFD #define itm_wrap 0xFFFC #define itm_fit 0xFFFB #define itm_next 0xFFFA #define itm_center 0xFFF9 #define LISTPLUGIN_OK 0 #define LISTPLUGIN_ERROR 1 typedef struct { int size; DWORD PluginInterfaceVersionLow; DWORD PluginInterfaceVersionHi; char DefaultIniName[MAX_PATH]; } ListDefaultParamStruct; #ifdef __cplusplus extern "C" { #endif HWND DCPCALL ListLoad(HWND ParentWin,char* FileToLoad,int ShowFlags); HWND DCPCALL ListLoadW(HWND ParentWin,WCHAR* FileToLoad,int ShowFlags); int DCPCALL ListLoadNext(HWND ParentWin,HWND PluginWin,char* FileToLoad,int ShowFlags); int DCPCALL ListLoadNextW(HWND ParentWin,HWND PluginWin,WCHAR* FileToLoad,int ShowFlags); void DCPCALL ListCloseWindow(HWND ListWin); void DCPCALL ListGetDetectString(char* DetectString,int maxlen); int DCPCALL ListSearchText(HWND ListWin,char* SearchString,int SearchParameter); int DCPCALL ListSearchTextW(HWND ListWin,WCHAR* SearchString,int SearchParameter); int DCPCALL ListSearchDialog(HWND ListWin,int FindNext); int DCPCALL ListSendCommand(HWND ListWin,int Command,int Parameter); int DCPCALL ListPrint(HWND ListWin,char* FileToPrint,char* DefPrinter, int PrintFlags,RECT* Margins); int DCPCALL ListPrintW(HWND ListWin,WCHAR* FileToPrint,WCHAR* DefPrinter, int PrintFlags,RECT* Margins); int DCPCALL ListNotificationReceived(HWND ListWin,int Message,WPARAM wParam,LPARAM lParam); void DCPCALL ListSetDefaultParams(ListDefaultParamStruct* dps); HBITMAP DCPCALL ListGetPreviewBitmap(char* FileToLoad,int width,int height, char* contentbuf,int contentbuflen); HBITMAP DCPCALL ListGetPreviewBitmapW(WCHAR* FileToLoad,int width,int height, char* contentbuf,int contentbuflen); #ifdef __cplusplus } #endif #endif // _WLX_H doublecmd-1.1.22/sdk/wlxplugin.pas0000644000175000001440000000706014743153644016130 0ustar alexxusers// Lister API definitions. // This unit is written by Christian Ghisler, it's from Total Commander // Lister API Guide, which can be found at http://ghisler.com. // Version: 2.0. unit WlxPlugin; interface const lc_copy=1; lc_newparams=2; lc_selectall=3; lc_setpercent=4; lcp_wraptext=1; lcp_fittowindow=2; lcp_ansi=4; lcp_ascii=8; lcp_variable=12; lcp_forceshow=16; lcp_fitlargeronly=32; lcp_center=64; lcp_darkmode=128; lcp_darkmodenative=256; lcs_findfirst=1; lcs_matchcase=2; lcs_wholewords=4; lcs_backwards=8; itm_percent=$FFFE; itm_fontstyle=$FFFD; itm_wrap=$FFFC; itm_fit=$FFFB; itm_next=$FFFA; itm_center=$FFF9; LISTPLUGIN_OK=0; LISTPLUGIN_ERROR=1; const MAX_PATH=32000; type { Unsigned integer with pointer size } THandle = {$IFDEF CPU64}QWord{$ELSE}LongWord{$ENDIF}; const wlxInvalidHandle: THandle = THandle(0); type tListDefaultParamStruct=record size, PluginInterfaceVersionLow, PluginInterfaceVersionHi:longint; DefaultIniName:array[0..MAX_PATH-1] of char; end; pListDefaultParamStruct=^tListDefaultParamStruct; type tdateformat=record wYear,wMonth,wDay:word; end; pdateformat=^tdateformat; type ttimeformat=record wHour,wMinute,wSecond:word; end; ptimeformat=^ttimeformat; type HBITMAP = type THandle; { Function prototypes: Functions need to be defined exactly like this!} (* function ListLoad(ParentWin:thandle;FileToLoad:pchar;ShowFlags:integer):thandle; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListLoadW(ParentWin:thandle;FileToLoad:pwidechar;ShowFlags:integer):thandle; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListLoadNext(ParentWin,PluginWin:thandle;FileToLoad:pchar;ShowFlags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListLoadNextW(ParentWin,PluginWin:thandle;FileToLoad:pwidechar;ShowFlags:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ListCloseWindow(ListWin:thandle); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ListGetDetectString(DetectString:pchar;maxlen:integer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListSearchText(ListWin:thandle;SearchString:pchar; SearchParameter:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListSearchTextW(ListWin:thandle;SearchString:pwidechar; SearchParameter:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListSearchDialog(ListWin:thandle;FindNext:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListSendCommand(ListWin:thandle;Command,Parameter:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListPrint(ListWin:thandle;FileToPrint,DefPrinter:pchar; PrintFlags:integer;var Margins:trect):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListPrintW(ListWin:thandle;FileToPrint,DefPrinter:pwidechar; PrintFlags:integer;var Margins:trect):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListNotificationReceived(ListWin:thandle;Message,wParam,lParam:integer):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; procedure ListSetDefaultParams(dps:pListDefaultParamStruct); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListGetPreviewBitmap(FileToLoad:pchar;width,height:integer; contentbuf:pchar;contentbuflen:integer):hbitmap; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; function ListGetPreviewBitmapW(FileToLoad:pwidechar;width,height:integer; contentbuf:pchar;contentbuflen:integer):hbitmap; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; *) implementation end. doublecmd-1.1.22/src/0000755000175000001440000000000014743153644013375 5ustar alexxusersdoublecmd-1.1.22/src/DragCursors.lrs0000644000175000001440000003535114743153644016364 0ustar alexxusersLazarusResources.Add('ArrowCopy','CUR',[ #0#0#2#0#1#0' '#0#0#0#0#0#0#168#8#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1#0 +#8#0#0#0#0#0#0#4#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#1#0#0#0#0#0#0#255#255#255#0#0 +#183#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#2 +#2#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2 +#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#2 +#2#2#2#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#2#2#2#2#2#2#2#2#2#2#2#2#2 +#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#0#0#0 +#0#0#0#0#0#0#0#0#1#1#1#0#0#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0 +#0#0#1#1#0#0#0#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#0#0#0#0#1#0#0#0#0#0#1#1#1#0#0 +#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#1#1#0#0#0#0#0#0#0#0#0 +#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#1#1#1#0#0#1#1#1#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2 +#0#0#0#0#0#0#0#0#0#1#1#1#1#0#1#1#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0#0#0 +#0#0#0#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#1#1#1 +#1#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1 +#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1#1#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1 +#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#255#255 +#255#255#255#255#192#255#255#255#192#255#255#255#192#255#255#255#192#255#255 +#255#192#255#255#248#0#7#255#136#0#7#255#8#0#7#255#8#0#7'~'#8#0#7'>'#24#0#7 +#28#31#192#255#12'?'#192#255#0'?'#192#255#0#127#192#255#0#1#192#255#0#3#255 +#255#0#7#255#255#0#15#255#255#0#31#255#255#0'?'#255#255#0#127#255#255#0#255 +#255#255#1#255#255#255#3#255#255#255#7#255#255#255#15#255#255#255#31#255#255 +#255'?'#255#255#255#127#255#255#255 ]); LazarusResources.Add('ArrowMove','CUR',[ #0#0#2#0#1#0' '#0#0#0#0#0#0#168#8#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1#0 +#8#0#0#0#0#0#128#4#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#255#255#255#0 +#0#22'r'#0#15#31#244#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#3#3#3 +#3#3#3#3#3#3#3#3#3#3#3#2#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#2#3#3#3#3#3#3#3#3#3 +#3#3#3#3#3#2#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#2#3#3#3#3#3#3#3#3#3#3#3#3#3#3#2 +#0#0#0#0#0#0#0#0#0#0#0#1#1#1#0#0#2#3#3#3#3#3#3#3#3#3#3#3#3#3#3#2#0#0#0#0#0#0 +#0#0#0#0#0#1#1#0#0#0#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#0#0#0#0#1#0#0#0#0#0#1#1 +#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#1#1#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#0#0#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#0#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#1#1#1#1#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1 +#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1#1#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1 +#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#248#0#7#255#136#0#7#255#8#0#7#255#8#0#7'~'#8#0#7'>' +#24#0#7#28#31#255#255#12'?'#255#255#0'?'#255#255#0#127#255#255#0#1#255#255#0 +#3#255#255#0#7#255#255#0#15#255#255#0#31#255#255#0'?'#255#255#0#127#255#255#0 +#255#255#255#1#255#255#255#3#255#255#255#7#255#255#255#15#255#255#255#31#255 +#255#255'?'#255#255#255#127#255#255#255 ]); LazarusResources.Add('ArrowLink','CUR',[ #0#0#2#0#1#0' '#0#0#0#0#0#0#168#8#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1#0 +#8#0#0#0#0#0#128#4#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#255#255#255#0 +']'#18#4#0#156#30#7#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#2#2#2#2#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#2#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#2#2#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#3#3#2#0#0#0#0#0#0#0#0#2#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#2#3#3#2#2#0#0#0#0#0#0#2#2#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#2#3#3#3#2#2#0#0#0#2#3#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#2#3#3#3#3#2#2#2#2#3#3#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#3#3#3 +#3#3#3#3#3#3#3#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#2#3#3#3#3#3#3#3#3 +#3#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#0#2#3#3#3#3#3#3#3#3#2#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#1#1#1#0#0#0#0#0#0#2#3#3#3#3#3#3#3#2#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#1#1#0#0#0#0#0#0#0#2#3#3#3#3#3#3#3#2#0#0#0#0#0#0#0#1#0#0#0#0#0#1#1#1 +#0#0#0#0#0#0#2#3#3#3#3#3#3#3#3#2#0#0#0#0#0#0#0#1#1#0#0#0#0#1#1#0#0#0#0#0#0#2 +#3#3#3#3#3#3#3#3#3#2#0#0#0#0#0#0#0#1#1#1#0#0#1#1#1#0#0#0#0#0#2#2#2#2#2#2#2#2 +#2#2#2#2#0#0#0#0#0#0#0#1#1#1#1#0#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1 +#1#1#1#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1 +#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1#1#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#1#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#1#1#1#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#1 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#1#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#255 +#254#15#255#255#252'?'#255#255#252#127#255#255#248#127#191#255#248'??'#255 +#252#14'?'#255#252#0'?'#255#140#0'?'#255#14#0'?'#255#15#0'?~'#15#128'?>'#31 +#128'?'#28#31#0'?'#12'>'#0'?'#0'<'#0'?'#0#127#255#255#0#1#255#255#0#3#255#255 +#0#7#255#255#0#15#255#255#0#31#255#255#0'?'#255#255#0#127#255#255#0#255#255 +#255#1#255#255#255#3#255#255#255#7#255#255#255#15#255#255#255#31#255#255#255 +'?'#255#255#255#127#255#255#255 ]); doublecmd-1.1.22/src/dmcommondata.lfm0000644000175000001440000033165214743153644016552 0ustar alexxusersobject dmComData: TdmComData OnCreate = DataModuleCreate OldCreateOrder = False Height = 376 HorizontalOffset = 935 VerticalOffset = 230 Width = 500 PPI = 120 object OpenDialog: TOpenDialog FilterIndex = 0 Left = 40 Top = 30 end object SaveDialog: TSaveDialog FilterIndex = 0 Left = 150 Top = 30 end object ImageList: TImageList Height = 22 Width = 22 Left = 280 Top = 30 Bitmap = { 4C69020000001600000016000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000001A0000001F0000000CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF0000000026454947783232324C0000001C00000007FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0000000026555957F85B5F5DF8535654AE202020370000001800000004FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000026555A 57F8F7F8F7FFB0B4B2FC585B59F4494C4A87060606270000001300000001FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000026555A57F8FFFFFFFFFAFB FAFFF2F3F2FF909491F7585B5AE73B403D63000000220000000EFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF0000000026555A57F8FFFFFFFFE6EAE8FFF0F2F1FFFCFC FCFFE3E6E5FF727673F6575A59CA2B2F2F460000001F0000000AFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0000000026555A57F8FFFFFFFFE6EAE8FFE6EAE8FFE7EBE9FFF3F5F4FFFCFC FCFFCFD1CFFE5E6261F6515452A5191919330000001A00000006FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0008080825555A 57F8FFFFFFFFE6EAE8FFE6EAE8FFE7EAE9FFE7EBE9FFEAEDEBFFF6F8F7FFFAFA FAFFB2B6B3FA585C59F2484C4A7E131313260D0D0D150F0F0F03FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002A2A2A23565A58F8FFFFFFFFEAED EBFFEAEDECFFEAEEECFFEAEEECFFEAEEECFFEAEEECFFEFF1F0FFFAFBFAFFF3F4 F4FF919492F6595E5BE14A4A4A59303030213232320F33333301FFFFFF00FFFF FF00FFFFFF00FFFFFF004D4D4D21565A58F8FFFFFFFFEDF0EEFFEEF0EFFFEEF1 EFFFEEF1EFFFEEF1EFFFEDF0EEFFEAEEECFFE7EBE9FFEEF0EFFFFBFCFBFFE3E5 E4FF737775F55B5E5DC05353533354545418FFFFFF00FFFFFF00FFFFFF00FFFF FF006F6F6F1F565B58F8FFFFFFFFE7ECE9FFE8ECEAFFE8ECEAFFE8ECEAFFE6EA E8FFE6EAE8FFE6EAE8FFE5E9E7FFE4E9E7FFF3F5F4FFFCFDFDFFBFC2C0FD555A 58FA5D61614B76767617FFFFFF00FFFFFF00FFFFFF00FFFFFF009292921D565B 59F8FFFFFFFFE9ECEBFFEBEEECFFECEFEEFFEDF0EFFFEEF1EFFFEEF1EFFFEDF0 EFFFF3F5F4FFFDFDFDFFE3E4E3FF6E706FF65D625FB9707575369999990D9999 9901FFFFFF00FFFFFF00FFFFFF00FFFFFF00B3B3B31B575B59F7FFFFFFFFEDF0 EEFFEFF2F1FFF2F4F3FFF4F6F5FFF5F7F6FFF7F8F7FFFCFDFCFFF5F5F5FF9093 92F65C615FDC6D707050BABABA12BCBCBC03FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00D8D8D819575B59F7FFFFFFFFEEF1F0FFF1F4F3FFF5F6 F5FFF8F9F8FFFDFDFDFFFDFDFDFFBABBBAF95B5E5CF067696771D1D1D115DBDB DB06FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00F8F8F817575B59F7FFFFFFFFECEFEEFFEFF2F1FFF8F9F8FFFEFEFEFFD8D9 D8FD626564F665686799B8B8B821FFFFFF0AFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF17575B 59F7FFFFFFFFEEF1F0FFFBFCFCFFECEDECFF7B7D7CF6606463C18F949437FFFF FF0EFFFFFF02FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF17575B59F7FFFFFFFFF7F7 F7FF9FA1A0F65D605EE174777755FFFFFF12FFFFFF05FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF17565B59F7BDC0BFFB5D605EF3686C6A7AE9E9 E918FFFFFF09FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF175E6260CC626664A2B6B6B626FFFFFF0EFFFFFF02FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF15FFFF FF17FFFFFF12FFFFFF04FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF06FFFFFF07FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000001600000026000000260000002600000026000000260000 002600000017000000000000001B000000260000002600000026000000260000 0026000000260000001500000000000000000000000000000000000000000202 0223505452D6535755FF535755FF535755FF535755FF565A58F9080808250000 000002020225525654F2535755FF535755FF535755FF535755FF5C615EEC0101 012100000000000000000000000000000000000000000C0C0C22525654F1FCFC FCFFFFFFFFFFFFFFFFFFFFFFFFFF6B6F6DFE16161626000000000C0C0C24565A 58FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF626665FD0B0B0B20000000000000 000000000000000000000000000017171720525654F1FCFCFCFFDFE3E1FFDFE4 E2FFF8F9F8FF6B6F6DFE1F2020250000000017171722565A58FFFEFEFEFFDFE4 E2FFDFE4E2FFFBFBFBFF626665FD1616161F0000000000000000000000000000 0000000000002222221F525654F1FCFCFCFFDFE3E1FFDFE4E2FFF8F9F8FF6B6F 6DFE292A29240000000022222221565A58FFFEFEFEFFDFE4E2FFDFE4E2FFFBFB FBFF636665FD2222221D00000000000000000000000000000000000000002F2F 2F1D525654F1FCFCFCFFE0E4E2FFE0E4E2FFF8F9F8FF6B6F6DFE343535230000 00003030301F565A58FFFEFEFEFFE0E4E2FFE0E4E2FFFBFBFBFF636665FD2E2E 2E1C00000000000000000000000000000000000000003E3E3E1C535755F1FCFD FDFFE3E7E5FFE3E6E5FFF8F9F9FF6B6F6DFE41424221000000003E3E3E1E565A 58FFFEFEFEFFE3E7E5FFE2E6E4FFFBFCFBFF636665FD3C3C3C1B000000000000 00000000000000000000000000004D4D4D1B535755F1FDFDFDFFE7EAE8FFE6E9 E7FFF9FAFAFF6B6F6DFE4E4F4E20000000004E4E4E1C565A58FFFEFEFEFFD9DE DBFFD4DBD8FFFCFCFCFF636665FD4C4C4C190000000000000000000000000000 0000000000005F5F5F19535755F1FDFDFDFFE2E5E4FFDCE1DFFFFAFBFAFF6B6F 6DFE5D5E5D1F000000005F5F5F1B565A58FFFEFEFEFFDCE1DFFFDBE0DEFFFCFC FCFF636665FD5D5D5D1800000000000000000000000000000000000000007171 7118535755F1FDFDFDFFE3E7E6FFE1E5E3FFFBFBFBFF6B6F6DFE6C6C6C1D0000 000071717119565A58FFFEFFFFFFE2E6E5FFE0E5E3FFFCFDFCFF636665FD7171 7117000000000000000000000000000000000000000087878717535755F1FDFE FDFFE9ECEBFFE6E9E8FFFBFCFCFF6B6F6DFE7D7E7E1C0000000088888818565A 58FFFFFFFFFFE8EBEAFFE6E9E7FFFDFDFDFF636665FD86868615000000000000 00000000000000000000000000009F9F9F15535755F0FEFEFEFFEEF0EFFFE9EC EBFFFCFCFCFF6B6F6DFE9091911B00000000A0A0A017565A58FFFFFFFFFFEDEE EEFFE9ECEBFFFDFDFDFF646765FD9F9F9F140000000000000000000000000000 000000000000BABABA14535755F0FEFEFEFFFFFFFFFFFFFFFFFFFFFFFFFF6B6F 6DFEA4A5A51900000000BDBDBD15565A58FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF646765FDBABABA130000000000000000000000000000000000000000DBDB DB12555957D4545856FF545856FF545856FF545856FF595D5BFCCACBCA150000 0000DCDCDC14545856F2545856FF545856FF545856FF545856FF656866F4D9D9 D9110000000000000000000000000000000000000000FFFFFF0BF8F8F813F0F0 F014F0F0F014F0F0F014F0F0F014F7F7F713FFFFFF0B00000000FFFFFF0BF7F7 F713F0F0F014F0F0F014F0F0F014F0F0F014F8F8F813FFFFFF0A000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000 } end object ilEditorImages: TImageList Left = 400 Top = 30 Bitmap = { 4C692D00000010000000100000009E9E9EFF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF7C8C8CFF729F9FFF6AAEAFFF36E4 EDFF000000000000000000000000818181FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9BEEF2FF69F0F7FF4DF2FAFF46EF F7FF28EBF4FF0000000000000000818181FFFFFFFFFFECECECFFEAEAEAFFEAEA EAFFEBEBEBFFEBEBEBFFEBEBEBFFB4EDF0FF6AF0F7FF3AF4FCFF68F6FDFF6AF6 FDFF3CF2FBFF1EEFF9FF00000000818181FFFFFFFFFFEAEAEAFFEAEAEAFFEBEB EBFFEBEBEBFFECECECFFECECECFF9CEEF2FF4EF2FAFF67F6FDFFB5FAFEFFB8FA FEFF6BF5FDFF22EFFAFF00000000818181FFFFFFFFFFEAEAEAFFEBEBEBFFEBEB EBFFECECECFFECECECFFECECECFF9BEFF3FF4EF2FAFF6AF6FDFFBBFAFEFFBFFB FEFF6EF6FDFF22F0FAFF00000000818181FFFFFFFFFFEBEBEBFFEBEBEBFFECEC ECFFECECECFFECECECFFEDEDEDFFB1EEF1FF67F1F8FF40F4FDFF71F7FDFF72F7 FDFF43F3FCFF24ECF6FF00000000818181FFFFFFFFFFEBEBEBFFEBEBEBFFECEC ECFFECECECFFEDEDEDFFEDEDEDFFE0EEEFFF96EFF4FF63F1F8FF46F3FBFF45F3 FBFF5DEFF7FF0000000000000000818181FFFFFFFFFFEBEBEBFFECECECFFECEC ECFFEDEDEDFFEDEDEDFFEEEEEEFFEEEEEEFFE2EEEEFFB1F0F3FF92F0F5FF9AF0 F5FF779696FF0000000000000000818181FFFFFFFFFFECECECFFECECECFFEDED EDFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFEFEFEFFFEFEFEFFFF0F0F0FFFFFF FFFF818181FF0000000000000000818181FFFFFFFFFFECECECFFECECECFFEDED EDFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0F0FFF0F0F0FFFFFF FFFF818181FF0000000000000000818181FFFFFFFFFFECECECFFEDEDEDFFEEEE EEFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0F0FFF1F1F1FFF1F1F1FFF1F1F1FFFFFF FFFF818181FF0000000000000000818181FFFFFFFFFFEDEDEDFFEDEDEDFFEEEE EEFFEEEEEEFFEFEFEFFFF0F0F0FFF0F0F0FFF1F1F1FFF1F1F1FFF2F2F2FFFFFF FFFF818181FF0000000000000000818181FFFFFFFFFFEDEDEDFFEDEDEDFFEEEE EEFFEFEFEFFFEFEFEFFFF0F0F0FFF0F0F0FFF1F1F1FFF2F2F2FFF2F2F2FFFFFF FFFF818181FF0000000000000000818181FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF818181FF00000000000000009E9E9EFF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF9E9E9EFF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000006B6F6DFF6B6F6DFF6B6F6DFF6B6F 6DFF6B6F6DFF656967FF656967FF000000000000000000000000000000000000 00000000000000000000000000006B6F6DFFCECECEFFCECECEFFCECECEFFCECE CEFFCECECEFFCECECEFFC5C6C6FF616563FF0000000000000000000000000000 0000000000000000000000000000686C6AFFBFC0C0FF959796FF959796FF989C 9AFFA4A9A7FFA4A9A7FFA4A9A7FFA4A9A7FFA4A9A7FFA4A9A7FFA4A9A7FFA4A9 A7FFA4A9A7FF929996FF00000000656967FFC9C9C9FFA6A6A6FFA6A6A6FFA4A9 A7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFA4A9A7FF000000005F6361FFBFC0C0FF959796FF959796FFA4A9 A7FFFFFFFFFFF4F5F5FFF4F5F5FFF4F5F5FFF4F5F5FFF4F5F5FFF4F5F5FFF4F5 F5FFFFFFFFFFA4A9A7FF000000005B5F5DFFC9C9C9FFA6A6A6FFA6A6A6FFA4A9 A7FFFFFFFFFFF4F5F5FFCACCCCFFCACCCCFFCACCCCFFCACCCCFFCACCCCFFF4F5 F5FFFFFFFFFFA4A9A7FF000000005B5F5DFFBFC0C0FF959796FF959796FFA4A9 A7FFFFFFFFFFF4F5F5FFF4F5F5FFF4F5F5FFF4F5F5FFF4F5F5FFF4F5F5FFF4F5 F5FFFFFFFFFFA4A9A7FF00000000575B59FFC9C9C9FFA6A6A6FFA6A6A6FFA4A9 A7FFFFFFFFFFF4F5F5FFCACCCCFFCACCCCFFCACCCCFFD7D8D8FFF4F5F5FFF4F5 F5FFFFFFFFFFA4A9A7FF00000000535755FFBFC0C0FF9A7A61FFA46534FFA465 34FFA46534FFA46534FFA46534FFA46534FFA46534FFA46534FFA46534FFA465 34FFA46534FFA46534FF9D6B43FF535755FFC9C9C9FFA46534FFEBD8C6FFE8D2 BEFFE8D2BEFFE8D2BEFFE8D2BEFFE8D2BEFFE8D2BEFFE8D2BEFFE8D2BEFFE8D2 BEFFE8D2BEFFEBD8C6FFA46534FF535755FFBFC0C0FFA46534FFE3C7AEFFD8B1 8CFFD8B18CFFD8B18CFFD8B18CFFD8B18CFFD8B18CFFD8B18CFFD8B18CFFD8B1 8CFFD6AE89FFE0C2A6FFA46534FF535755FFC9C9C9FFA46534FFE3C7ADFFD7B0 8BFFD8B18CFFD7B08BFFD7AF8AFFD6AE88FFD5AC85FFD4A981FFD2A67CFFD0A2 76FFCF9F72FFDDBB9CFFA46534FF535755FFBFC0C0FF9B7658FFDDBB9BFFCE9E 70FFCF9D70FFCE9D6EFFCE9C6EFFCE9C6DFFCE9B6CFFCD9B6BFFCE9A6AFFCD99 69FFCD9968FFDBB694FFA46534FF535755FFA9ABA9FFD7AF89FFCD9B6BFFCD9A 6BFFCD9A6AFFCD9969FFCD9868FFCC9866FFCD9865FFCC9765FFCC9664FFCC95 63FFDEBA9AFF967153FF795D45FF89603EFFA46534FFA46534FFA46534FFA465 34FFA46534FFA46534FFA46534FFA46534FFA46534FFA46534FFA46534FFA465 34FFA46534FF86603FFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008B6738FF8B67 38FF8B6738FF8A693DFF80714AFF7A7858FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000E6CEB1FFEFDF D0FFECDBC5FFDFC29BFFA08B68FF886E43FF0000000000000000000000000000 0000000000000000000000000000887F6BFF737166FF757062FF856D4AFF9A74 41FF9F7844FFD9BF9EFFEBD9C1FFAF8651FF7D6A4EFF6B706EFF6B706EFF6B70 6EFF6B706EFF6B706EFF6B706EFF6E716BFFDDE6E2FFFFFFFFFFD6E1DDFFDDD6 C9FFB6996EFF8B6738FFE2CBABFFD3B792FF9B7D54FFE5DFD5FFFFFFFFFFFFFF FFFFFFFFFFFFF4F4F4FF6B706EFF6B7572FFFDFDFDFFEEEEEEFFEDEDEDFFDEE2 DFFFB09877FF8B6738FFCAA779FFCEB38FFF8E6B3DFFC3BCACFFEEEDEDFFEEEE EDFFEDEEEDFFF3F4F3FF6B706EFF6B706EFFFCFBFCFFECECEBFF8B6738FF8B67 38FF8B6738FF8B6738FFCAA779FFBD9258FF8B6738FF8B6738FF8B6738FF8B67 38FFECECECFFF3F3F3FF6B706EFF6B706EFFFAFAFAFFEAE9E9FFC4CFCAFF8B67 38FFDCBF98FFBF9F71FFBF9F71FFBF9F71FFC09F73FFD8BB96FF8B6738FFAFA9 95FFEAE9EAFFF2F2F2FF6B706EFF6B706EFFF9F9F9FFFAFAFAFFE4E4E4FFBFCB C5FF8B6738FFDCBF98FFC09F73FFC09F73FFDFC8ABFF8B6738FFACA692FFE4E4 E4FFF4F4F4FFF1F1F1FF6B706EFF6B706EFFF9F9F9FFEEEEEEFFFAFAFAFFE4E4 E4FFBFCBC5FF8B6738FFE3CBACFFDCBF98FF8F6B3BFFACA692FFE4E4E4FFFAFA FAFFEEEEEEFFF1F1F1FF6B706EFF6B706EFFF7F7F7FFE3E3E3FFEEEEEEFFFAFA FAFFFAFAFAFFC8D4CEFF8E6C3FFF8B6738FFB4AE9AFFFAFAFAFFFCFCFCFFEEEE EEFFE3E3E3FFF0F0F0FF6B706EFF6B706EFFFEFEFEFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F4F4FFF4F4F4FFEBEBEBFFEBEB EBFFE3E3E3FFF0F0F0FF6B706EFF6B706EFFCECECEFFC9C9C9FFC9C9C9FFC9C9 C9FFC9C9C9FFC5C5C5FFC9C9C9FFC9C9C9FFC5C5C5FFC5C5C5FFC5C5C5FFC5C5 C5FFC5C5C5FFD6D6D6FF6B706EFF6B706EFFCECECEFFC5C5C5FF9F9F9FFFAFAF AFFFBCBCBCFFC4C4C4FFC8C8C8FFD0D0D0FFA9A9A9FFD2D2D2FFA9A9A9FFD2D2 D2FFB9B9B9FFCACACAFF6B706EFF6B706EFFCDCDCDFFC3C3C3FFA9AAAAFFB4B4 B4FFC2C2C2FFC4C4C4FFC8C8C8FFCBCBCBFFA8A7A8FFD1D1D1FFA7A7A8FFD1D1 D1FFB6B6B7FFCACACAFF6B706EFF6B706EFFDDDDDDFFDCDCDCFFDCDCDCFFDCDC DCFFD5D5D5FFD5D5D5FFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCF CFFFCFCFCFFFCACACAFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B70 6EFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B70 6EFF6B706EFF6B706EFF6B706EFF0000000000000000000000008B6738FF8B67 38FF8B6738FF8A693DFF80714AFF7A7858FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000E6CEB1FFEFDF D0FFECDBC5FFDFC29BFFA08B68FF886E43FF0000000000000000000000000000 0000000000000000000000000000887F6BFF737166FF757062FF856D4AFF9A74 41FF9F7844FFD9BF9EFFEBD9C1FFAF8651FF7D6A4EFF6B706EFF6B706EFF6B70 6EFF6B706EFF6B706EFF6B706EFF6E716BFFDDE6E2FFFFFFFFFFD6E1DDFFDDD6 C9FFB6996EFF8B6738FFE2CBABFFD3B792FF9B7D54FFE5DFD5FFFFFFFFFFFFFF FFFFFFFFFFFFF4F4F4FF6B706EFF6B7572FFFDFDFDFFEEEEEEFFEDEDEDFFDEE2 DFFFB09877FF8B6738FFCAA779FFCEB38FFF8E6B3DFFC3BCACFFEEEDEDFFEEEE EDFFEDEEEDFFF3F4F3FF6B706EFF6B706EFFFCFBFCFFECECEBFF8B6738FF8B67 38FF8B6738FF8B6738FFCAA779FFBD9258FF8B6738FF8B6738FF8B6738FF8B67 38FFECECECFFF3F3F3FF6B706EFF6B706EFFFAFAFAFFEAE9E9FFC4CFCAFF8B67 38FFDCBF98FFBF9F71FFBF9F71FFBF9F71FFC09F73FFD8BB96FF8B6738FFAFA9 95FFEAE9EAFFF2F2F2FF6B706EFF6B706EFFF9F9F9FFFAFAFAFFE4E4E4FFBFCB C5FF8B6738FFDCBF98FFC09F73FFC09F73FFDFC8ABFF8B6738FFACA692FFE4E4 E4FFF4F4F4FFF1F1F1FF6B706EFF6B706EFFF9F9F9FFEEEEEEFFFAFAFAFFE4E4 E4FFBFCBC5FF8B6738FFE3CBACFFDCBF98FF8F6B3BFFACA692FFE4E4E4FFFAFA FAFFEEEEEEFFF1F1F1FF6B706EFF6B706EFFF7F7F7FFE3E3E3FFEEEEEEFFFAFA FAFFFAFAFAFFC8D4CEFF8E6C3FFF8B6738FFB4AE9AFFFAFAFAFFFCFCFCFFEEEE EEFFE3E3E3FFF0F0F0FF6B706EFF6B706EFFA1A4A3FFA1A4A2FFA1A4A3FFA1A4 A3FFA1A4A3FFA1A4A3FFA1A4A3FFA1A4A3FFA1A4A3FFA1A4A3FFA1A4A3FFA1A4 A3FFA1A4A3FFA1A4A3FF6B706EFF6B706EFFDCDCDCFFDBDBDCFFDBDCDCFFDCDC DCFFDCDBDCFFDBDCDCFFDCDBDCFFDCDCDCFFDBDCDBFFDCDCDBFF000000FFDBDC DCFFDCDCDBFFDCDCDCFF6B706EFF6B706EFFEFEFEFFFADB0AFFFAEB0AEFFAEB0 AFFFADB0AEFFADB0AFFFADB0AFFFADB0AFFFADB0AFFFEFEEEFFF000000FFEEEF EEFFEFEEEEFFEFEEEFFF6B706EFF6B706EFFFFFFFFFFB6B8B7FFB6B8B7FFB6B8 B7FFB6B8B7FFB6B8B7FFB6B8B7FFB6B8B7FFB6B8B7FFFFFFFFFF000000FFFFFF FFFFFFFFFFFFFFFFFFFF6B706EFF6B706EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF FFFFFFFFFFFFFFFFFFFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B70 6EFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B706EFF6B70 6EFF6B706EFF6B706EFF6B706EFF00000000999999FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF000000000000000000000000818181FFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFECECECFFEAEA EAFFEAEAEAFFEBEBEBFFEBEBEBFFEBEBEBFFECECECFFECECECFFEDEDEDFFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEAEAEAFFC4C4 C4FFC5C5C5FFC5C5C5FFC6C6C6FFC6C6C6FFC6C6C6FFC6C6C6FFC7C7C7FFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEAEAEAFFEBEB EBFFEBEBEBFF696969FF696969FF696969FFD2D2D2FFEDEDEDFFEEEEEEFFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEBEBEBFFC5C5 C5FFC6C6C6FFB0B0B0FF585858FF585858FF585858FFC6C6C6FFC7C7C7FFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEBEBEBFF6969 69FFD2D2D2FFECECECFFD2D2D2FF696969FF666969FFECECECFFEEEEEEFFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEBEBEBFF5858 58FF585858FFB0B0B0FF585858FF6A6A6AFF6A6A6AFFCCD2D2FFEEEEEEFFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFECECECFF6969 69FF696969FF696969FF6A6A6AFF6A6A6AFF6A6A6AFF6A6A6AFFD6D6D6FFF0F0 F0FFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFECECECFFB0B0 B0FF585858FF585858FF585858FF585858FF595959FF626262FF6C6C6CFFDCDC DCFFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFECECECFFEDED EDFFEEEEEEFFEEEEEEFFEFEFEFFFD4D4D4FF777777FF858585FF909090FF9D9D 9DFFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEDEDEDFFC6C6 C6FFC7C7C7FFC7C7C7FFC8C8C8FFC8C8C8FFB5B5B5FF929292FF9E9E9EFFABAB ABFFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFEDEDEDFFEDED EDFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0F0FFF0F0F0FFE0E0E0FFADADADFFBABA BAFFFFFFFFFF818181FF0000000000000000818181FFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF818181FF0000000000000000959595FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF959595FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000888D 8BFF909593FF00000000000000000000000000000000888D8BFF8C918FFF0000 00000000000000000000000000000000000000000000000000008B908EFFF7F7 F7FF888D8BFF000000000000000000000000000000008D9190FFD0D3D2FF8C91 8FFF000000000000000000000000000000000000000000000000888D8BFFD0D4 D2FFEFF0EFFF8F9492FF000000000000000000000000A7ACAAFFC3C8C6FF8A8F 8DFF0000000000000000000000000000000000000000000000008A8F8DFFB0B5 B3FFF6F7F7FF888D8BFF00000000000000008B908EFFC9CECCFFABAFAEFF888D 8BFF00000000000000000000000000000000000000000000000000000000888D 8BFFD9DCDBFFEFF0EFFF8E9391FF898E8CFFB3B8B6FFCBCECDFF888D8BFF0000 0000000000000000000000000000000000000000000000000000000000008A8F 8DFFB2B6B5FFF7F7F7FF888D8BFF9CA09FFFB3B6B5FFB5BAB8FF888D8BFF0000 0000000000000000000000000000000000000000000000000000000000000000 0000888D8BFFDFE1E1FFF5F6F5FF979C9AFFA5A9A8FF888D8BFF000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008A8F8DFFB7BBBAFFE6E8E7FFA7ACAAFF8B908EFF878C8AFF000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000848989FFC3C6C5FFAFB2B3FF2C2F9CFF00000000000000000000 0000000000000000000000000000000000000000000000000000000000001818 AEFF1616ABFF0606A6FF454AA3FF0202A6FF191AC7FF1717ADFF1818AEFF0000 00000000000000000000000000000000000000000000000000000707A9FF2020 D2FF1E1ECEFF0E0FB7FF0205A4FF0304A8FF1A1AC9FF2020D1FF1F1FCBFF0A0A A9FF00000000000000000000000000000000000000000606A8FF1F1FD0FF0303 A8FF1415C0FF0101A6FF00000000000000001C1DCDFF1315C0FF0303A8FF1D1D CDFF0606A7FF0000000000000000000000001414ABFF2323D5FF000000000000 00001D1DCEFF0A0AA9FF00000000000000000303A8FF1A1BCAFF000000000000 00002020D1FF1414ABFF00000000000000000D0DABFF1D1DCFFF000000000B0B B5FF2121D3FF0C0CAAFF00000000000000000909AAFF2323D6FF0D0DB8FF0000 00001F1FD1FF1111ABFF00000000000000001313ABFF2727DBFF1F1FD0FF1D1D CEFF0707A8FF000000000000000000000000000000000808AAFF2222D4FF1D1D CFFF1D1DCEFF1313ABFF0000000000000000000000000E0EAAFF1010ABFF1616 ABFF0000000000000000000000000000000000000000000000000D0DAAFF0B0B AAFF0B0BA9FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000979B 9AFF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FF858A88FF8A8F8DFF00000000000000000000000000000000878C 8AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF858A88FF00000000000000000000000000000000868B 89FFFFFFFFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFFFFFFFFF858A88FF00000000000000000000000000000000878C 8AFFFFFFFFFFEFF0F0FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7 C7FFEFF0F0FFFFFFFFFF858A88FF00000000000000000000000000000000868B 89FFFFFFFFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFFFFFFFFF858A88FF00000000000000000000000000000000878C 8AFFFFFFFFFFEFF0F0FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFEFF0 F0FFEFF0F0FFFFFFFFFF858A88FF00000000000000000000000000000000868B 89FFFFFFFFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0 F0FFFAFAFAFFF3F3F3FF858A88FF00000000000000000000000000000000878C 8AFFFFFFFFFFEFF0F0FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFEEEE EEFFF6F7F7FFC3C4C3FF858A88FF00000000000000000000000000000000878C 8AFFFFFFFFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FF898E8CFF898E 8CFF898E8CFF898E8CFF858A88FF00000000000000000000000000000000868B 89FFFDFEFEFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFFAFAFAFF959A98FFFAFA FAFFF7F8F8FFE2E4E3FF858A88FF00000000000000000000000000000000868B 89FFF9FAFAFFEFF0F0FFEFF0F0FFEFF0F0FFFAFAFAFFFAFAFAFF959A98FFFAFA FAFFE2E3E3FF858A88FF858A88FF00000000000000000000000000000000868B 89FFF4F4F4FFF6F7F7FFF5F6F6FFFBFCFCFFFBFBFBFFD4D4D4FF969A98FFE2E4 E3FF858A88FF000000000000000000000000000000000000000000000000898E 8CFF868B89FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF000000000000000000000000000000000000000000000000000000000000 00005E5F5FFF5C5C5CFF5C5C5CFF5C5C5CFF5C5C5CFF5E5F5FFF000000000000 0000000000000000000000000000000000000000000001446DFF01446CFF0344 6BFF5B5C5CFF899595FF8A9797FF8A9797FF899595FF5B5C5CFF03446BFF0144 6CFF01446CFF00000000000000000000000001446DFF2484C0FF3E7EA4FF646D 70FF5E5E5EFF7C7F7FFF7D8080FF7D8080FF7B7E7EFF5E5E5EFF646C6EFF407C A1FF237FB9FF01436CFF000000000000000002466FFF2788C6FF646F71FFF1F1 F1FFE0E0E0FFBBBBBBFFBBBBBBFFBBBBBBFFBBBBBBFFE0E0E0FFF2F2F2FF646D 6EFF2787C5FF00426AFF000000000000000002466FFF2788C6FF646866FFFFFF FFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002466FFF2687C5FF646866FFFFFF FFFFEFF0F0FFB5B5B3FFB5B5B3FFB5B5B3FFB5B5B3FFEEEFEFFFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002466FFF2687C5FF646866FFFFFF FFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEDEFEFFFEBEDEDFFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002466EFF2687C5FF646866FFFFFF FFFFEFF0F0FFB5B5B3FFB5B5B3FFB4B4B2FFB2B2B1FFE8EAEAFFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002466EFF2687C5FF646866FFFFFF FFFFEFF0F0FFEEEFEFFFECEDEDFFEAEBEBFFE8EAEAFFD9DBDBFFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002466EFF2687C5FF646866FFFFFF FFFFEDEEEEFFEBECECFFE9EBEBFFE7E9E9FFD8DADAFFCACDCCFFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002466EFF2687C5FF646866FFFFFF FFFFEAECECFFE8EAEAFFE6E8E8FFCBCECDFFB6BAB9FFB5B9B8FFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002456EFF2687C5FF646866FFFFFF FFFFE7E9E9FFE5E7E7FFD6D9D9FFB6B9B9FFFFFFFFFFFFFFFFFFFFFFFFFF6469 67FF2886C2FF00426AFF000000000000000002456EFF2687C5FF646866FFFFFF FFFFE4E7E7FFD5D8D8FFBEC2C1FFB4B7B7FFFFFFFFFFFFFFFFFF646967FF2787 C5FF2886C2FF00426AFF000000000000000002456EFF2687C5FF636D70FFEDEE EDFFFEFEFEFFFEFEFEFFFEFEFEFFEEEFEFFFFDFEFEFF646967FF2787C5FF2787 C5FF2787C5FF00426AFF000000000000000001436CFF237FBAFF3B7DA7FF646F 73FF686C6AFF686C6AFF686C6AFF686C6AFF686C6AFF3D7CA3FF3D7CA3FF3D7C A3FF227BB3FF01436BFF00000000000000000000000001436CFF01446CFF0144 6CFF01446CFF01446CFF01446CFF01446CFF01446CFF01446CFF01446CFF0144 6CFF01436BFF0000000000000000000000000000000000000000000000000000 00000000000000A0C4FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000A0C4FF00A0C4FF00000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000A0 C4FFADF3FBFF00A0C4FF00000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000A0C4FFADF3 FBFF25E4FBFF00A0C4FF00A0C4FF13A1BEFF159FBBFF1BA1BBFF000000000000 0000000000000000000000000000000000000000000000A0C4FFADF3FBFF31E1 F6FF20E3FAFF73ECFAFF6FEBFAFF6EE8F7FF6CE8F7FF14A1BCFF14A3C1FF0000 00000000000000000000000000000000000000A0C4FFADF3FBFF2FE0F6FF32E2 F7FF29DBF1FF2FE0F5FF29DBF1FF16CDE3FF36D9ECFF69E7F6FF41CEE3FF13A3 C1FF00000000000000000000000000A0C4FFADF3FBFF2FE0F6FF32E2F8FF32E2 F7FF32E2F7FF2FE0F5FF29DBF1FF1DD2E8FF1DD2E8FF1DD2E8FF36D9ECFF40CD E1FF16A1BDFF00000000000000000000000000A0C4FF79EDFBFF32E2F8FF2CDF F4FF04C0D6FF04C0D6FF04C0D6FF1DD2E8FF1DD2E8FF1DD2E8FF0BC8DFFF6AE5 F3FF1BABC5FF15A0BCFF00000000000000000000000000A0C4FF76EDFBFF04C3 DAFF76EDFBFF69EAF9FF69EAF9FF69EAF9FF69EAF9FF05DDF7FF0AC8DFFF07C2 D8FF6FDCEBFF1BA3BFFF0000000000000000000000000000000000A0C4FF76ED FBFF76EDFBFF00A0C4FF00A0C4FF00A0C4FF00A0C4FF01A9C4FF6EE1EEFF0FC9 DFFF69E4F2FF1AA4C0FF000000000000000000000000000000000000000000A0 C4FF76EDFBFF00A0C4FF0000000000000000000000000000000000A0C4FF6DE6 F5FF76E2EFFF19A3C1FF00000000000000000000000000000000000000000000 000000A0C4FF00A0C4FF000000000000000000000000000000000000000002AC C8FF88E7F2FF11A2C2FF00000000000000000000000000000000000000000000 00000000000000A0C4FF00000000000000000000000000000000000000000EAA CBFF5DDAE9FF23A6C0FF00000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000043C4 DBFF43C5D8FF0000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000066DB EAFF11A6C2FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000069A4EFF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000069A4EFF069A4EFF000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000069A4EFF6CF3AEFF069A4EFF0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000069A4EFF069A4EFF069A4EFF069A4EFF6CF3AEFF6CF3AEFF069A 4EFF00000000000000000000000000000000000000000000000000000000069A 4EFF0C9B8FFF49DEA9FF6AF1AEFF6BF2AEFF73F5B3FF61EFA6FF16D273FF6CF3 AEFF069A4EFF0000000000000000000000000000000000000000069A4EFF45D9 ACFF67EFAFFF50E9A1FF24DBA0FF24DBA0FF24DBA0FF24DBA0FF16D273FF16D2 73FF6CF3AEFF069A4EFF000000000000000000000000069A4EFF46D8A9FF65EF B1FF24DEA4FF2ADD97FF24DBA0FF24DBA0FF1AD7AFFF16D273FF16D273FF16D2 73FF18D375FF6CF3AEFF069A4EFF00000000069A4EFF30C29DFF60EDB1FF26DF A5FF1AD7AFFF1AD7AFFF09D0C8FF14D077FF16D273FF16D273FF16D273FF16D2 73FF34E28AFF069A4EFF00000000000000000C9F55FF63E9B1FF31E0BAFF17D4 CBFF22D69BFF23DAA1FF23DAA1FF23DAA1FF23DAA1FF23DED9FF16D273FF34E2 8AFF069A4EFF0000000000000000000000000A9D52FF64ECB2FF24D6CDFF0BA1 93FF069A4EFF069A4EFF069A4EFF069A4EFF069A4EFF1ED4CCFF34E28AFF069A 4EFF00000000000000000000000000000000069A4EFF46E2BEFF05A699FF069A 4EFF00000000000000000000000000000000069A4EFF34E28AFF069A4EFF0000 000000000000000000000000000000000000069A4EFF37D9B3FF069A4EFF0000 000000000000000000000000000000000000069A4EFF069A4EFF000000000000 000000000000000000000000000000000000069A4EFF3ADDB8FF069A4EFF0000 000000000000000000000000000000000000069A4EFF00000000000000000000 000000000000000000000000000000000000069A4EFF23C7AFFF059D91FF0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000FA85AFF2CD6C0FF0299 9AFF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000979B9AFF858A88FF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF8A8F8DFF0000 0000000000000000000000000000878C8AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF858A88FF0000 0000000000000000000000000000868B89FFFFFFFFFFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFFFFFFFFF858A88FF0000 0000000000000000000000000000878C8AFFFFFFFFFFEFF0F0FFC6C7C7FFC6C7 C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFEFF0F0FFFFFFFFFF858A88FF0000 0000000000000000000000000000868B89FFFFFFFFFFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFD5D6D6FF808381FF808381FF808381FF808381FF808482FF0000 0000000000000000000000000000878C8AFFFFFFFFFFEFF0F0FFC6C7C7FFC6C7 C7FFA6A9A8FF808381FFC8BAAEFFD2BCA6FFD4BAA2FFCDB9A8FF808381FF0000 0000000000000000000000000000868B89FFFFFFFFFFEFF0F0FFEFF0F0FFD5D7 D6FF808381FFC8B7A8FFD2AC8AFFE7D3BFFFEAD7C5FFD9BA9CFFCBAD90FF8083 81FF000000000000000000000000878C8AFFFFFFFFFFEFF0F0FFC6C7C7FF8083 81FFBBAEA3FFCFA985FFF2E6DCFFF7EEE8FFF5ECE4FFECDACAFFD8B28EFFCBAF 97FF808381FF0000000000000000878C8AFFFFFFFFFFEFF0F0FFEFF0F0FF8083 81FFD0B8A2FFDFC0A5FFF1E4D9FFF3EAE0FFF2E7DDFFE9D4C1FFDFBEA0FFD0A6 81FF808381FF0000000000000000868B89FFFDFEFEFFEFF0F0FFEFF0F0FF8083 81FFD6BFA9FFE0C1A5FFEEDED0FFF2E5DAFFEDDCCDFFECD9C8FFE8D0BCFFD1A7 80FF808381FF0000000000000000868B89FFF9FAFAFFEFF0F0FFEFF0F0FF8083 81FFC3B5A7FFD0AB89FFE5CAB3FFEBD7C3FFEAD4C1FFEEDDCFFFDABDA3FFCEAF 93FF808381FF0000000000000000868B89FFFFFFFFFFFFFFFFFFFFFFFFFFCDCF CFFF808381FFD1B89FFFD6B391FFDFC5AFFFE3CAB2FFD6BAA0FFD3B497FF8083 81FF737675FF0000000000000000898E8CFF868B89FF858A88FF858A88FF858A 88FF7B807EFF808381FFDCC8B3FFCFAC8BFFD1A880FFD0B399FF808381FFA3A4 A3FFA3A4A3FF6A6E6CFF00000000000000000000000000000000000000000000 0000000000006A6E6CFF808381FF808381FF808381FF808381FF8C8E8DFFB7B8 B8FFA3A4A3FFA3A4A3FF828484FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008C8E 8DFFB7B8B8FFA3A4A3FF828484FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008C8E8DFF8C8E8DFF828484FF000000000000000000000000000000008083 81FF808381FF808381FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000808381FFC8BA AEFFD4BAA2FFCCB9A7FF808381FF000000000000000000000000000000000000 00000000000000000000000000000000000000000000808381FFC8B7A7FFD1AC 8AFFEAD7C5FFD9B99BFFCBAC90FF808381FF838785FF858A88FF858A88FF858A 88FF8A8F8DFF000000000000000000000000808381FFBBAEA2FFCFA884FFF2E6 DCFFF5ECE4FFECDACAFFD8B18DFFCBB097FF808381FFFFFFFFFFFFFFFFFFFFFF FFFF858A88FF000000000000000000000000808381FFD0B8A2FFDEC0A4FFF1E4 D9FFF2E7DDFFEAD5C3FFDFBFA2FFD0A580FF808381FFEFF0F0FFEFF0F0FFFFFF FFFF02598FFF02598FFF0000000000000000808381FFC2B5A7FFD0AA88FFE8D0 BBFFEEDCCDFFF3E8DEFFDCC1A8FFCEB094FF808381FFC6C7C7FFEFF0F0FF0259 8FFFC6EAEEFF71ADCFFF02598FFF0000000000000000808381FFD1B89FFFD6B3 91FFE6D0BBFFD8BEA6FFD3B597FF808381FFD0D2D1FFEFF0F0FF02598FFFC7EB EFFF6AACD2FF5583A1FF02598FFF00000000828484FFA3A4A3FF808381FFDDC8 B3FFD1A77FFFD1B499FF808381FF939695FFC6C7C7FF02598FFFC7EBEFFF6AAC D2FF5787A4FF02598FFF00000000828484FFA3A4A3FFB7B8B8FF8C8E8DFF8083 81FF808381FF808381FFAFB1B0FFEFF0F0FF02598FFFC5E6EDFF69AACFFF5683 A0FF02598FFF0000000000000000828484FFB7B8B8FF8C8E8DFFFFFFFFFFEFF0 F0FFC6C7C7FFC6C7C7FFC6C7C7FF02598FFFC4E5EDFF649FC8FF5784A0FF0259 8FFF6A8089FF0000000000000000000000008C8E8DFF868B89FFFFFFFFFFEFF0 F0FFEFF0F0FFEFF0F0FFEEEFEFFF395B70FF8AABC2FF5585A3FF02598FFFCADC E7FF848987FF00000000000000000000000000000000868B89FFFDFEFEFFEFF0 F0FFEFF0F0FFEEEFEFFF02598FFF26424CFF36576BFF02598FFFAFC1CCFFEFEF EFFF7F8482FF00000000000000000000000000000000868B89FFF9FAFAFFEFF0 F0FFEFF0F0FFEDEEEEFF000000FF02598FFF96A9B3FFC2C2C2FFCACBCBFFE2E2 E2FF7B7F7DFF00000000000000000000000000000000868B89FFFFFFFFFFFFFF FFFFFFFFFFFFFEFEFEFFF7F7F7FFE9E9E9FFE2E2E2FFE5E5E5FFEAEAEAFFEFEF EFFF7F8482FF00000000000000000000000000000000898E8CFF868B89FF858A 88FF858A88FF858A88FF848987FF838886FF828785FF838886FF838886FF8388 86FF888D8BFF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000595D5BFF535755FF535755FF535755FF5357 55FF535755FF535755FF535755FF545856FF5A5E5CFF626564FF666968FF676A 68FF636765FF6B6E6DFF00000000535755FFA6A6A6FF858585FF797979FF6E6E 6EFF656565FF5D5D5DFF595959FFEDEFEFFFEFF1F1FFF3F4F4FFF5F6F6FFF5F6 F6FFECEEEDFF7D817FFF00000000535755FFADADADFF8C8C8CFF7F7F7FFF7575 75FF6C6C6CFF646464FF606060FFEDEFEFFFF2F3F3FFF7F8F8FFFAFBFBFFFBFB FBFFF9F9F9FF989B9AFF00000000535755FFBABABAFF959595FF898989FF7E7E 7EFF757575FF6E6E6EFF686868FFEEEFEFFFF2F4F4FFF9F9F9FF9292D7FF3E3E BCFFFAFAFAFFA1A3A2FF00000000535755FFBBBBBBFF9D9D9DFF949494FF8989 89FF7F7F7FFF767676FF707070FFEEF0F0FFEFF1F3FF6565C7FF5151C4FF1515 ACFFD3D4EDFF8889A2FF00000000535755FFBDBDBDFFA0A0A0FF979797FF8F8F 8FFF868686FF7E7E7EFF767676FFE1E3ECFF3C3CB9FF6161CDFFA7A7ECFF3030 BCFF2828B7FF2122B1FF0101A5FF535755FFBEBEBEFFA2A2A2FF9A9A9AFF9191 91FF888888FF808080FF6A6A7EFF2121B0FF6565D2FF8888E7FF8E8EE8FF9595 EAFF9696EAFF9A9AEBFF0101A5FF535755FFBEBEBEFFA4A4A4FF9C9C9CFF9393 93FF8B8B8BFF64648AFF1111A6FF5E5ED5FF6969E1FF4848DBFF4A4ADBFF4C4C DBFF4D4DDBFF8D8DE8FF0303A6FF535755FFBEBEBEFFA7A7A7FF9E9E9EFF9696 96FF8D8D8DFF1616A1FF3636C5FF5656DDFF2D2DD5FF2525D3FF1A1AD1FF1010 CFFF1B1BD2FF6E6EE2FF0404A6FF535755FFBEBEBEFFA9A9A9FFA1A1A1FF9898 98FF8F8F8FFF73738BFF0E0EA2FF2D2DC4FF3636D7FF0808CEFF0C0CCEFF0C0C CEFF0E0ECFFF5151DCFF0101A5FF535755FFBEBEBEFFAAAAAAFFA3A3A3FF9A9A 9AFF929292FF898989FF797986FF2425ACFF2424BCFF3838D6FF4141D9FF3A3A D4FF3C3CD2FF3D3DD2FF0000A5FF535755FFBEBEBEFFAAAAAAFFA5A5A5FF9D9D 9DFF959595FF8F8F8FFF828282FF5E5F64FF4849BBFF1B1BB5FF3535D3FF0404 A6FF1E1EB0FF1314A5FF0B0BAAFF535755FFBEBEBEFFAAAAAAFFA9A9A9FFA1A1 A1FF999999FF6F6F6FFF888A89FFD0D2D0FFE3E5E4FF6B6CC4FF1111ACFF0C0C A9FFE4E6E5FF868887FF00000000535755FFBEBEBEFFABABABFFAFAFAFFF8586 85FF8B8F8DFFC5C9C7FFD2D6D4FFD5D9D7FFD6DAD8FFD7DBD9FF8688C5FF4345 B6FFD4D8D6FF717573FF00000000535755FFC3C3C3FF979898FF909392FFBBC1 BEFFC1C6C3FFC3C8C6FFC3C9C6FFC4C9C6FFC4C9C6FFC4C9C6FFC4C9C6FFC4C9 C6FFC1C7C5FF5F6361FF00000000595D5BFF686B69FF545856FF555957FF565A 58FF565A58FF565A58FF565A58FF575B59FF575B59FF575B59FF575B59FF575B 59FF565A58FF5D615FFF00000000000000000000000000000000000000000000 0000874A20FF874A20FF874A20FF874A20FF874A20FF874A20FF000000000000 0000000000000000000000000000000000000000000000000000000000008D54 2CFFC1A18CFFDBC9BDFFF4EFEBFFF4EFEBFFDBC9BDFFC1A28CFF8D542CFF0000 00000000000000000000000000000000000000000000874A20FFA77A5BFFF0E8 E3FFD0B9A9FFAC8265FF96603BFF96603BFFAC8265FFD1BAAAFFF0E9E4FFA77B 5CFF874A20FF00000000000000000000000000000000AA7E61FFF2EBE7FFA678 59FF9C6947FFDECEC2FFF7F3F0FFF1EAE6FFD0B8A7FFA06F4DFFAD8264FFF3ED E8FFA87C5DFF0000000000000000000000008E552DFFF1EAE5FFA57858FF874A 20FFB0886CFFFEFDFDFFE9DED6FFF6F2EFFFFFFFFFFFDCCABDFF986038FFB389 6BFFF2EBE6FF8D552DFF00000000874A20FFC3A590FFD0B9A9FF874A20FF874A 20FF9F6E4BFFA06F4DFF945B32FFA87A59FFFFFFFFFFFDFCFBFFA16D46FF9F6A 43FFDAC6B7FFC6A994FF874A20FF874A20FFDDCCC0FFAC8265FF874A20FF8B50 27FF90562DFF955C34FF99623AFFC2A189FFFFFFFFFFF3ECE8FFA5724BFFA673 4DFFC3A186FFE1D2C6FF894C23FF874A20FFF5F0EDFF935C36FF8A4F25FF9056 2DFF955D34FF9A633BFFB58B6DFFFCFBF9FFFEFEFEFFC19D82FFAC7A54FFAD7C 56FFB78D6CFFF7F3EFFF884B21FF874A20FFF5F0EDFF945E38FF8E532AFF945B 33FF99623AFF9F6942FFF3EDE8FFFFFFFFFFD0B5A0FFB07F5AFFB2835EFFB485 60FFBD9475FFF8F3F0FF884B22FF874A20FFDDCCC0FFAF866AFF91582FFF9760 38FF9D6740FFA77651FFE4D4C8FFE5D6CAFFB48662FFB68763FFB98B67FFBA8E 6AFFD1B29BFFE6D7CCFF8A4E24FF874A20FFC3A590FFD3BCADFF945C33FF9A64 3CFFA16C45FFA97852FFC8A88FFFCCAD94FFB78965FFBB8F6BFFBF9370FFC196 73FFE7D7C9FFCFB4A0FF884B21FF000000008E552DFFF2EBE6FFB18769FF9D67 40FFA36F49FFB28462FFFFFFFFFFFFFFFFFFBD926FFFC19672FFC59B78FFD6B7 9DFFF7F1EDFF8F572FFF000000000000000000000000AB8163FFF3EEE9FFB78F 72FFA5724CFFB38765FFFFFFFFFFFFFFFFFFC19774FFC59B78FFD7B9A0FFF9F5 F1FFB2886BFF00000000000000000000000000000000874A20FFAC8264FFF3ED E9FFDDC9BAFFC7A58BFFBB9171FFC19979FFD5B79FFFE9DACDFFF8F3EFFFB58D 71FF8B4F26FF0000000000000000000000000000000000000000000000008F55 2EFFCBAF9BFFE5D6CBFFF8F4F1FFF9F5F2FFE8DBD1FFD3B9A6FF915831FF0000 0000000000000000000000000000000000000000000000000000000000000000 0000874A20FF894D23FF884C22FF884C22FF8B4F25FF884B21FF000000000000 000000000000000000000000000000000000000000008F9391FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF8F9391FF00000000000000000000000000000000858A88FFF1F1F1FFEBEB EBFFEBEBEBFFEBEBEBFFEAEAEAFFEAEAEAFFEAEAEAFFEAEAEAFFEAEAEAFFE9E9 E9FF858A88FF000000000000000000000000874A20FF858A88FFE7E7E7FFD7D7 D7FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD5D5D5FFD5D5D5FFDADADAFFDCDC DCFF858A88FF874A20FF00000000874A20FFDDBB9CFF777C7AFFD9D9D9FFBDBD BDFFBDBDBDFFBDBDBDFFBDBDBDFFBCBCBCFFBCBCBCFFBCBCBCFFBFBFBFFFC0C0 C0FF777C7AFFDDBB9CFF874A20FF874A20FFDDBB9CFF6A5B4EFFC9C9C9FF9C9C 9CFF9C9C9CFF9C9C9CFF9B9B9BFF9B9B9BFF9B9B9BFF9B9B9BFF9B9B9BFF9B9B 9BFF6A5B4EFFDDBB9CFF874A20FF874A20FFDDBB9CFF86522CFF86512BFF8651 2BFF86512BFF86512BFF86512BFF86522CFF86522CFF86522CFF86522CFF8652 2CFF86522CFFDDBB9CFF874A20FF874A20FFDDBB9CFFCA8A58FFCA8A58FFCA8A 58FFCA8A58FFCA8A58FFCA8A58FFCA8A58FFCA8A58FFCA8A58FFCA8A58FFCA8A 58FFCA8A58FFDDBB9CFF874A20FF874A20FFDDBB9CFFDDBB9CFFDDBB9CFFDDBB 9CFFDDBB9CFFDDBB9CFFDDBB9CFFDDBB9CFFDDBB9CFFDDBB9CFFDDBB9CFFDDBB 9CFFDDBB9CFFDDBB9CFF874A20FF874A20FFDDBB9CFFCF9F72FFCF9F72FFCF9F 72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F 72FFCF9F72FFDDBB9CFF874A20FF874920FF874A20FF874A20FF874A20FF874A 20FF874A20FF874A20FF874A20FF874A20FF874A20FF874A20FF874A20FF874A 20FF874A20FF874A20FF874920FF00000000000000006A6E6DFFCCCDCDFF6569 68FFAAACABFF6C6F6EFFAEB0AFFF6B6E6DFFB0B2B1FF6E7271FFB2B3B3FF6C70 6FFF0000000000000000000000000000000000000000727675FFC7C9C8FF797E 7BFF9E9F9EFF8E8F8FFFADAEADFF8C8D8CFFAEAFAEFF7C807FFFB7B8B7FF7679 78FF0000000000000000000000000000000000000000858988FFC9CBCAFF8388 85FFC4C4C4FF838885FFCACCCBFF9B9D9CFFC0C0C0FF7C807FFFE2E3E3FF8B8E 8DFF000000000000000000000000000000008C908FFF858988FFF6F6F6FF999C 9BFFABADACFF838885FFDEDFDEFF9C9F9EFFCCCECDFF989B9AFFEBEBEBFF9699 98FF000000000000000000000000000000008C908FFFFAFAFAFF949897FF999C 9BFF999C9BFF969A98FFEDEEEEFF949997FF9B9E9DFF989B9AFF8B8E8DFFFFFF FFFF8F9392FF0000000000000000000000008C908FFF919493FFADB0AFFF0000 000000000000909492FF9DA09FFF989C9AFF0000000000000000000000007B7E 7DFF989B9AFF000000000000000000000000898D8BFF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FF898E8CFF0000000000000000858A88FFFDFDFDFFFEFEFEFFFEFE FEFFFDFDFDFFFDFDFDFFFCFCFCFFFCFCFCFFFBFBFBFFFBFBFBFFFAFAFAFFFAFA FAFFF9F9F9FF888D8BFF0000000000000000858A88FFFDFDFDFFD6BEA8FFD7BF A9FFD7BFA9FFD8C0AAFFD8C0AAFFD9C1ABFFD9C1ABFFD9C1ABFFD9C1ABFFD9C1 ABFFF8F8F8FF888D8BFF0000000000000000858A88FFFEFEFEFFD7BFA9FFAF97 81FFAF9781FFAF9781FFAF9781FFDAC2ACFFAF9781FFAF9781FFAF9781FFDAC2 ACFFF8F8F8FF888D8BFF0000000000000000858A88FFFDFDFDFFD8C0AAFFAF97 81FFAF9781FFAF9781FFAF9781FFDBC3ADFFDBC3ADFFDBC3ADFFDBC3ADFFDBC3 ADFFF8F8F8FF888D8BFF0000000000000000858A88FFFDFDFDFFD8C0AAFFAF97 81FFAF9781FFAF9781FFAF9781FFDBC3ADFFDCC4AEFFDCC4AEFFDCC4AEFFEBEB EBFFF8F8F8FF888D8BFF0000000000000000858A88FFFCFCFCFFD9C1ABFFAF97 81FFAF9781FFAF9781FFAF9781FFDCC4AEFFAF9781FFAF9781FFDDC5AFFFECEC ECFFF8F8F8FF888D8BFF0000000000000000858A88FFFCFCFCFFDAC2ACFFDAC2 ACFFDBC3ADFFDCC4AEFFDDC5AFFFDDC5AFFFDEC6B0FFDEC6B0FFDEC6B0FFEEEE EEFFF8F8F8FF888D8BFF0000000000000000858A88FFFCFCFCFFDAC2ACFFDBC3 ADFFDCC4AEFFDDC5AFFFDDC5AFFFDEC6B0FFDEC6B0FFDFC7B1FFDFC7B1FFF0F0 F0FFF8F8F8FF888D8BFF0000000000000000858A88FFFBFBFBFFDAC2ACFFAF97 81FFAF9781FFAF9781FFAF9781FFAF9781FFAF9781FFAF9781FFE0C8B2FFF2F2 F2FFF7F7F7FF888D8BFF0000000000000000858A88FFFBFBFBFFDBC3ADFFDCC4 AEFFDDC5AFFFDEC6B0FFDEC6B0FF000000FFE0C8B2FF000000FFE1C9B3FFF4F4 F4FFF7F7F7FF888D8BFF0000000000000000858A88FFFAFAFAFFDBC3ADFFDCC4 AEFFDDC5AFFFDEC6B0FFDFC7B1FFE0C8B2FF000000FFF5F5F5FFF6F6F6FFF6F6 F6FFF7F7F7FF888D8BFF0000000000000000858A88FFF9F9F9FFDBC3ADFFB098 82FFB09882FFB09882FFB09882FFE0C8B2FF000000FFF7F7F7FFF8F8F8FFF7F7 F7FFF7F7F7FF888D8BFF0000000000000000858A88FFF9F9F9FFDBC3ADFFDCC4 AEFFDDC5AFFFDEC6B0FFDFC7B1FFE0C8B2FF000000FFF7F7F7FFF9F9F9FFF8F8 F8FFF7F7F7FF888D8BFF0000000000000000858A88FFF8F8F8FFF8F8F8FFF8F8 F8FFF8F8F8FFF8F8F8FFF8F8F8FF000000FFF8F8F8FF000000FFF8F8F8FFF8F8 F8FFF8F8F8FF888D8BFF0000000000000000898E8CFF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FF8A8F8DFF00000000FFFFFF00BBBBBBFF9B958AFFA09990FF948A 7CFF886F4FFF8B6738FF896A40FF7F7253FF858A88FF858A88FF858A88FF858A 88FF858A88FFBBBBBBFFFFFFFF00FFFFFF00858A88FFA59C8FFFB2ADA8FFBAA3 8FFFBAA38FFFBAA38FFFBAA38FFFCCBBADFF874A20FFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF858A88FFFFFFFF00FFFFFF00858A88FFBBBBBBFFBBBBBBFF948A 7CFF9A7441FF9F7844FFBAA38FFFBAA38FFFCCBBADFF874A20FFB7B7B7FFB7B7 B7FFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFFFFFFFFFF874A20FFBAA38FFFCCBBADFF874A20FFFFFFFFFFFFFF FFFFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFFBFBFBFFF874A20FFBAA38FFFCCBBADFF874A20FFBFBFBFFFBFBF BFFFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FF874A20FF874A 20FF874A20FF874A20FF874A20FFBAA38FFFCCBBADFF874A20FF874A20FF874A 20FF874A20FF874A20FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FF874A 20FFBAA38FFFBAA38FFFBAA38FFFB5957AFFB5957AFFB5957AFFB5957AFFCCBB ADFF874A20FF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFF874A20FFBAA38FFFB5957AFFB5957AFFB5957AFFB5957AFFCCBBADFF874A 20FFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFF874A20FFBAA38FFFB5957AFFB5957AFFCCBBADFF874A20FFC8C8 C8FFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFFFFFFFFFF874A20FFBAA38FFFCCBBADFF874A20FFFFFFFFFFFFFF FFFFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFFD4D4D4FFD4D4D4FF874A20FF874A20FFD4D4D4FFD4D4D4FFD4D4 D4FFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFEFEFEFF858A88FFFFFFFF00FFFFFF00858A88FFD8D8D8FFD8D8D8FFBBBB BBFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFE FEFFFFFFFFFF858A88FFFFFFFF00FFFFFF00BBBBBBFF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FFBBBBBBFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00A465341DA769 3A9FA76A3ADEA56736F6A76939E5A76A3ABCA4653453A4653405FFFFFF00FFFF FF00FFFFFF00A4653479A4653410FFFFFF00FFFFFF00A4653550A66838F6C090 68FAD3B08FFFDFC2A8FFDEC1A8FFD4B193FFB9875FF4A56737F0A4653458FFFF FF00A4663566A46534FFA465340FFFFFFF00A4653429A66939F5D3AD8CFFDCBD 9DFFDDBEA1FFE5CBB4FFE9D3BFFFEEDDCCFFF0E2D5FFE7D2BFFFAF774BF5A567 36C0AB7143F7A46635FCA465340EFFFFFF00A769399BC09069FDC59872FFA86B 3CFFA46635FFA76A3AFCB7855DF3D9BBA1FEF1E4D8FFF2E6DBFFF3E8DDFFCEA7 88FDEAD8C8FFA76A3AF9A465340DFFFFFF00A66838F3AB7041FFA96C3CFEA76A 3AF5A4653475A4653419A4653445A66938CDB98861F5EBDBCDFFF5EBE2FFF6EE E6FFF6EEE6FFA76A3AFAA465340BFFFFFF00A46535FEA76A3AFBC791689DA567 37E6A4653423FFFFFF00FFFFFF00FFFFFF00A4653460A46635FFE9D7C7FFEBD8 C6FFF5ECE3FFA66A3AFAA465340AFFFFFF00A46534FCB3794C7ECF9D762BBB83 5713A4653402FFFFFF00FFFFFF00A4653404A66838C4D0AC8FFAF6EEE7FFF2E6 DBFFF6EEE6FFA66A3AFBA4653409FFFFFF00A465340DFFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00A46534A0A46534FFAD7447F8AF774CF7AF77 4CF7AF784CF7A46534FFA4653408FFFFFF00A46534F9A46534FEA46534FEA465 34FDA46534FCA46534FBA46534B9A465341DA4653418A4653418A4653418A465 3418A4653418A465341CFFFFFF00FFFFFF00A46534FCF5EDE5FFF6EDE5FFF5EC E4FFD7B79CFDA66837E0A4653410FFFFFF00FFFFFF00FFFFFF00FFFFFF00D5A4 7E1ACD997239A46534FCA465340CFFFFFF00A46635FCF6EEE6FFEBD7C4FFEAD9 C9FFA46534FEA465346AFFFFFF00FFFFFF00FFFFFF00A465340BA56635E9C995 6C8DB77F53C2A46534FFA4653405FFFFFF00A56737FDF6EEE6FFF5ECE3FFF5ED E4FFE6D2C1FFB0794DF5A66938CAA4653436FFFFFF00A465346AA96B3CEDB67C 4FFFA76A3AFEA56837FAFFFFFF00FFFFFF00A66838FDF1E4D8FFD4B295FEF4E9 E0FFF3E8DDFFEDDCCCFFD2AD8FFEB0784CF5A56635FBA66939FFA66939FEA96D 3DFFB0784CFFA76A3AA8FFFFFF00FFFFFF00A56737FEB7845BF7A56736D4B17A 4EF4E3CAB4FFECDAC9FFE7D1BCFFE3C9B0FFDEBEA0FFD2AB88FFCEA582FFD3AE 8EFFA66838F5A465342AFFFFFF00FFFFFF00A46534FFA5673693FFFFFF00A465 3454A66737EEB58055F3CEA684FFD8B697FFDBB999FFD3AC8AFFC2946DFCA668 38F6A466355BFFFFFF00FFFFFF00FFFFFF00A46534A2A4653401FFFFFF00FFFF FF00A4653405A4653453A76A3ABEA66938E9A46635FAA76A3AE4A76B3BAAA465 3424FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 0000BA8545FFB9843FFFB9843FFFBA8545FF0000000000000000000000000000 00000000000000000000000000000000000000000000B98544AFB98443E90000 0000B78140FFE9D4B4FFE9D4B4FFB78140FF00000000B98443E9B98544AF0000 000000000000000000000000000000000000B98544AFCCA26CFFD4B080FFB983 43FFCCA470FFC9984EFFC9984EFFCCA470FFB98343FFD4B080FFCCA26CFFB985 44AF00000000000000000000000000000000B78242ECD3AE7CFFE7CBA4FFEAD4 B2FFE8D0ADFFCF9D56FFCF9D56FFE8D0ADFFEAD4B2FFE7CBA4FFD3AE7CFFB782 42EC000000000000000000000000000000000000002FBA8547FFCE9949FFDAB2 76FFC9944BFFBE8943FFBE8943FFC9944BFFDAB276FFCE9949FFBA8546FF0000 002F000000000000000000000000B98442FFB6803EFFCEA673FFDBAE6EFFCB95 4BFFB88344FF6E4F2A616E4F2A61B88344FFCD974AFFDCAE6DFFD0A772FFB981 3CFFBE843FFF0000000000000000C5995FFFF1DCBBFFECD2ACFFD6A152FFC18C 49FF70502A620000000C0000000C704F2861C88D44FFDFA24CFFEACEA6FFF1D7 B2FFD79A51FF0000000000000000C38F4EFFE2B572FFDEB06AFFDBA658FFC595 55FF926935300000000000000000AA7333436A8399FFCD9F5FFF298DE2FF2B8F E1FFB48B5AFF3081D29100000000B98545FFB78242FFC8934EFFDFAB5EFFE4C4 94FFB68245DAB8813F3CBE823B2561809CFF37A8EFFF399DE3FF4CCFFDFF4AC7 F8FF3D9EE1FF45AAE4FF3982CB9F0000003300000033B78242FFE4B163FFEBC6 8EFFEACFA9FFD1A774FFD9A970FFCCBBA4FF399CE1FF4CCEFBFF3FB0EEFF40B1 EFFF4FCFFCFF429EDCFF16324E3100000000B98443E9DDBB8CFFEEC486FFE8B4 66FFF1CC96FFF7DCB5FFFFDEADFF288CDFFF4CCEFBFF3FAFEDFFFAB66DFFC775 1FCE41B1EFFF52D0F9FF3F92D5FF00000000AA7A3FBED2A76FFFD7A561FFB882 41FFD39F58FFEDB96BFFF7B962FF288DE3FF4CCFFCFF40B0EDFFC39F7BFF9876 53CB42B1EEFF52D0F9FF3F92D5FF0000000000000023AA7A3EBFB68243ED0000 0033B58142FFF5C378FFFCC371FFAD7E49FF3B9EE3FF4ECFFBFF41B0EDFF42B1 EDFF50CFFAFF439EDCFF1B3D5F520000000000000000000000230000002F0000 0000B88445FFC89451FFCE934AFF6D8192FF40A9EAFF429EDDFF52D0F8FF52D0 F8FF439EDCFF48AAE2FF3980C8B6000000000000000000000000000000000000 0000000000330000003300000033000000332D73BAAF1B3D60523F93D4FF3F93 D4FF102438413578BAC300000024000000000000000000000000000000000000 0000000000000000000000000000000000000000001F00000008000000330000 0033000000040000002400000000FFFFFF00C17D4460C88B4DBBC88C4FEEC88C 4FF6C88C4FF7C88C4FF7C88D4FF7C98C4FF7C78B4FF7C5894BD4C4763B91B368 3C06FFFFFF00FFFFFF00FFFFFF00FFFFFF00C48549C3F7F2ECECF8F4EEFCF8F4 EDFFF8F3EDFFF8F3EDFFF8F3EDFFF8F2ECFFF7F2ECFFF2E6D7FFE2B27DFFDB94 65F5B3683B07FFFFFF00FFFFFF00FFFFFF00C5884BEAFAF6F2FCFAE0C7FFFBE1 C9FFFBE2C9FFFBE0C8FFF9DFC5FFF8DBC1FFF4D6B8FFFFFBF8FFB6CBC2FF58A5 D8FF85B1DBFF469DD0FF2B95D15EFFFFFF00C6894CF6F9F5F1FFFCE3CDFFFBE3 CEFFFBE3CDFFFBE2CBFFF9E0C8FFF8DCC2FFF5D6BAFFAFE3F1FF77BEE7FFB4D2 F0FFE5F3FFFFACD2EFFF488CC7E8FFFFFF00C6894BF7F9F5F1FFFCE3CFFFFBE4 D0FFFCE4CFFFFCE3CDFFFAE1CAFFF9DDC4FFAFCDC9FF81D5EEFFB2E3F9FF8BC0 E7FFAED3F6FFC4E0FCFF669FD3F7FFFFFF00C6894BF7F9F4F0FFFCE6D3FFFCE6 D4FFFDE7D3FFFCE4D1FFFBE3CDFFBED4D0FF7DD4EEFFC4F6FDFF6CDDF6FF6DCA EDFF63A3D7FF6499C8FE5192CA26FFFFFF00C6884AF7F9F4EFFFFEE7D7FFFDE7 D6FFFDE7D5FFFDE6D4FFBDD6D5FF79D3EEFFC7F7FDFF5FDCF5FF5BE2F7FF7AD6 F2FF51A1E0FFAD8560F9FFFFFF00FFFFFF00C68849F7F9F4EDFFFEE8D8FFFEE8 D8FFFEE8D7FFB0C6CCFF77CBE7FFC7F7FDFF5EDCF5FF5AE1F7FF7BD4F1FF4B99 DBFFD2DFE9FFC68245F7FFFFFF00FFFFFF00C68447F7F9F3ECFFFEE8D6FFFEE8 D7FFB3C6CCFF76B9D6FFC2F6FDFF63DFF7FF5DE2F8FF79D3F0FF4998DAFFE2D5 C8FFFAF2EAFFC68042F7FFFFFF00FFFFFF00C58245F7F8F2EBFFFEE7D6FFA6B6 BFFF7AB6D5FF90B7D1FF55C9E4FF5BDFF5FF78D0EDFF519BD9FFE1D6CDFFFBE1 C9FFFBF7F2FFC57C3FF7FFFFFF00FFFFFF00C58042F7F8F1E8FFFEE5D5FF4389 AAFFE0F2FFFF549AD8FF1A7ABEFF4998C5FF488CC2FFDAD2CDFFFBE0C9FFFBE1 C8FFFDFAF7FFC1763BF7FFFFFF00FFFFFF00C47C40F7F7F0E6FFF8B455FF2E66 82FF94C7F9FF91C9F9FF4185C9FF2668A6FFD2A865FFF7B251FFF7B24FFFF7B2 4FFFFCF9F5FFBF6F36F7FFFFFF00FFFFFF00C1783CF7F7EDE3FFFDC26EFF1842 57FF2B6187FF4C89BCFF709FB3FFE3C99AFFFFD695FFFFD594FFFFD493FFFBBE 65FFFBF7F4FFBB6731F7FFFFFF00FFFFFF00BF7138F5F5EBDFFEFDBF68FFFCBD 67FFFBBE65FFFCBE64FFFCBE64FFFCBD62FFFBBD63FFFBBC61FFFCBE60FFFCBC 62FFFDFBF8FDB9642DF3FFFFFF00FFFFFF00BC6933DEF8F1EAF2F7ECDFFDF6EB DEFFF6EADEFFF6EADCFFF6EADCFFFAF3EBFFFAF3EBFFFAF2EAFFFCF7F3FFFCF8 F4FDFEFEFDF0B7602AD5FFFFFF00FFFFFF00BB6A346BBA6530BCBB6631EDBA66 30F7BA6630F7BA6630F7BA6530F7BA652FF7B9652EF7B9652EF7B9642EF7B964 2EEFB7622CBDB7622E63FFFFFF00000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFC39D9DFF584545FF261D1DFF634F 4FFFE9BCBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFF7D6464FF000000FFCCA4A4FFE5B9 B9FFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF685353FF000000FF000000FF000000FF9C7D 7DFFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFBDBDBDFF000000FF787878FFFEFE FEFFEDEDEDFF2A2A2AFF353535FF685353FF000000FF000000FF000000FF9C7D 7DFFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFDFDFDFF767676FF000000FFC9C9 C9FF8A8A8AFF000000FFC2C2C2FFEABDBDFF796060FF000000FFD9AFAFFFEABD BDFFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF1C1C1CFF2A2A 2AFF000000FF7D7D7DFFFEFEFEFFEABDBDFF796060FF000000FFD9AFAFFFEABD BDFFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2B2B2FF0000 00FF000000FFE9E9E9FFFFFFFFFFEABDBDFF796060FF000000FFD9AFAFFFEABD BDFFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF959595FF0000 00FF000000FFC9C9C9FFFFFFFFFFEABDBDFF796060FF000000FFD9AFAFFFEABD BDFFEABDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5D5D5FF000000FF6565 65FF161616FF424242FFF3F3F3FFEABDBDFF796060FF000000FFD9AFAFFFEABD BDFFEABDBDFF000000FF4D4D4DFFFFFFFFFFF8F8F8FF565656FF0D0D0DFFE3E3 E3FFABABABFF000000FF969696FFEABDBDFF796060FF000000FFD9AFAFFFEABD BDFFEABDBDFF000000FF4D4D4DFFFFFFFFFFA8A8A8FF000000FFA3A3A3FFFFFF FFFFF6F6F6FF4B4B4BFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5D5D5FF606060FF2A2A2AFF6D6D 6DFFFEFEFEFFFFFFFFFFFFFFFFFFEABDBDFFEABDBDFFEABDBDFFEABDBDFFEABD BDFFEABDBDFFEABDBDFFEABDBDFFFFFFFFFF898989FF000000FFDEDEDEFFFAFA FAFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFEABDBDFFEABDBDFFEABDBDFFEABD BDFFEABDBDFFEABDBDFFEABDBDFF727272FF000000FF000000FF000000FFAAAA AAFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFAD8B8BFF000000FF6E5757FFE9BC BCFFD9AFAFFF261D1DFF302424FF727272FF000000FF000000FF000000FFAAAA AAFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFE8BBBBFF6B5555FF000000FFB894 94FF7E6565FF000000FFB18F8FFFFFFFFFFF848484FF000000FFEDEDEDFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFEABDBDFFD4ABABFF191212FF261D 1DFF000000FF725B5BFFE9BCBCFFFFFFFFFF848484FF000000FFEDEDEDFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFEABDBDFFEABDBDFFA38383FF0000 00FF000000FFD5ACACFFEABDBDFFFFFFFFFF848484FF000000FFEDEDEDFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFEABDBDFFEABDBDFF896D6DFF0000 00FF000000FFB89494FFEABDBDFFFFFFFFFF848484FF000000FFEDEDEDFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEABDBDFFEABDBDFFC39D9DFF000000FF5C49 49FF130D0DFF3C2F2FFFDFB4B4FFFFFFFFFF848484FF000000FFEDEDEDFFFFFF FFFFFFFFFFFF000000FF4D4D4DFFEABDBDFFE3B8B8FF4F3E3EFF0B0707FFD0A8 A8FF9D7E7EFF000000FF896E6EFFFFFFFFFF848484FF000000FFEDEDEDFFFFFF FFFFFFFFFFFF000000FF4D4D4DFFEABDBDFF9A7B7BFF000000FF967878FFEABD BDFFE2B7B7FF443535FF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF002E2E2EB02C2C2CFF2B2B2BFF2B2B2BFF2B2B 2BFF2B2B2BFF2B2B2BFF2B2B2BFF2B2B2BFF2B2B2BFF2B2B2BFF2A2A2AFF2A2A 2AFF2A2A2AFF2B2B2BFF2D2D2DB02C2C2CFF656565FF626363FF626262FF6464 64FF656565FF636364FF616162FF616161FF636363FF646464FF616161FF6161 61FF616161FF626262FF2A2A2AFF2C2C2CFF444341FF3E3D3BFF3C3B38FF4342 3FFF000000FF403F3DFF393836FF393835FF3F3E3BFF000000FF9A9A9BFF3B3A 37FF3B3A37FF9A9A9AFF262626FF2A2B2BFF656361FF585655FFFFFFFFFF615F 5EFF000000FF9E9D9CFFFFFFFFFFFFFFFFFFA7A6A5FF000000FFFCFCFBFF5653 52FF555352FFFBFBFAFF232324FF2B2B2BFF4D4C4BFFFCFDFDFFF7F7F7FF4847 45FF000000FFF7F5F5FF3F3E3DFF3F3E3DFFF5F4F4FF000000FF8C8C8BFFFEFE FFFFFDFEFEFF8B8C8AFF262626FF2E2E2EFF383737FF2A2828FFF8F8F8FF2F2E 2EFF000000FFFEFEFEFF2C2B2BFF2C2B2BFFFEFEFEFF000000FF383737FF3332 32FF323131FF373636FF2C2C2CFF313131FF000000FF000000FFF2F2F2FF0000 00FF000000FFF4F4F4FF000000FF000000FFF4F4F4FF000000FF000000FF0000 00FF000000FF000000FF303030FF313131FF110F0FFF060404FFF9F9F9FF0403 03FF000000FFEAEAEAFF000000FF000000FFEAEAEAFF010101FF0E0D0DFF0402 02FFFDFDFDFF070606FF2F2F2FFF303030FF2C2B2BFF232222FFFFFFFFFF2423 23FF030303FF757474FFFDFDFDFFFDFDFDFF757474FF030404FF262525FFFFFF FFFFF9F9F9FF201F1FFF2E2E2EFF2F2F2FFF272525FF242222FF211E1EFF2623 23FF000000FF222020FF1C1A1AFF1C1A1AFF222020FF000000FF252222FF1A18 18FF969696FF201D1DFF2E2E2EFF2E2E2EF22F2F2FFF2F2F2FFF2F2F2FFF3030 30FF313131FF2F2F2FFF2D2E2EFF2D2E2EFF2F2F2FFF313131FF2F2F2FFF2C2C 2CFF2A2A2AFF2D2D2DFF2E2E2EF2000000300000003300000033000000330000 0033000000330000003300000033000000330000003300000033000000330000 0033000000330000003300000030FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000BBB5 A4FFA8A195FFB4A88D2D000000000000000000000000BDB6A2FFB2A68FFF0000 00000000000000000000FFFFFF00FFFFFF005173D2FF0648FEFF0042FFFFBCB7 A5FF938873FF2154E4FF0447FFFF0748FCFF0043FFFFBDB7A4FF978B6EFF0045 FFFF0748FEFF5173D2FFFFFFFF00FFFFFF000138F1FF9DB3FBFF96AFFFFFC0BA A4FF80714EFF93A2D6FF9BB2FDFF9CB2FAFF97B0FFFFC1BBA4FF81714CFF98B1 FFFF9DB4FCFF0138F1FFFFFFFF00FFFFFF000020E7FF526FEFFF0016E5FF000A B1FF000CB3FF0019E9FF0018E3FF0018E2FF0018E6FF000BB1FF000BB2FF0016 E7FF526FEFFF0020E7FFFFFFFF00FFFFFF00A39C89FFFFFFFDFFF2EDDEFFF4F0 E1FFF6F2E3FFF7F2E1FFF6F0DFFFF6F0DEFFF6F1E0FFF5F1E2FFF4F0E1FFF2EE DEFFFFFFFDFFA39C89FFFFFFFF00FFFFFF00948F8BFFFFFFFEFFE6E6E2FFE9E9 E6FFF0F0ECFFCCCAC6FFEFEEEBFFF0EFEBFFF0F0ECFFEEEEEAFFEAE9E6FFE7E6 E3FFFFFFFEFF948F8BFFFFFFFF00FFFFFF008E8B88FFFEFEFDFFE8E7E6FFEEEC EBFF595959FF2A2A2BFFFBF9F8FF5E5E5DFF5E5E5EFF585859FFC7C6C5FFE9E8 E7FFFEFEFDFF8E8B88FFFFFFFF00FFFFFF008B8886FFFEFEFEFFEBEBEAFFEFEF EEFFDFDFDEFF616060FFFFFFFFFF3A3B3BFFFFFFFFFFFDFDFBFFF2F2F1FFEDED ECFFFFFFFFFF8C8886FFFFFFFF00FFFFFF00888682FFFFFFFFFFEFEEEEFFF1F0 F0FFFBFAFAFF5D5D5EFFFFFFFFFF626262FF575555FF606060FFEDEDECFFF5F4 F5FFF6F5F6FF878582FFFFFFFF00FFFFFF0085827FFFFFFFFFFFF2F2F1FFF3F3 F2FFFCFCFBFF5C5C5CFFFFFFFFFFFFFFFFFFFFFFFFFF585858FFCECDCEFFE7E6 E5FFB2B0AEFFA8A6A4FFFFFFFF00FFFFFF00827F7DFFFFFFFFFFF5F6F6FFF5F5 F6FFFCFCFCFF585858FFDAD9D9FF6A6A6AFF717171FF464545FF9F9C9AFFA09D 9BFFC1C0BEFFB9B7B5FFFFFFFF00FFFFFF007E7C79FFFFFFFFFFFAFAFAFFF9F9 F9FFFBFBFBFFFFFFFFFFFFFFFFFFDADADAFFD2D2D2FFC0BEBDFFEFEFEFFFEDEC ECFFD6D6D3FFB2B0AEFFFFFFFF00FFFFFF007D7976FFFFFFFFFFFFFFFFFFFDFD FDFFFEFEFEFFFEFEFEFFFFFFFFFFFFFFFFFFFFFFFFFF9F9D9AFFE7E7E6FFCFCE CDFFE9E8E7FFABA9A7FFFFFFFF00FFFFFF007C7977FFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6C4C3FFC1BFBEFFD4D3D1FFDFDE DEFFFFFFFFFFA7A5A3FFFFFFFF00FFFFFF0075726FC07A7773FF767370FF7673 6FFF76736FFF76736FFF767370FF76736FFF94918FFFA6A4A2FFA4A2A0FFA3A1 9EFFA3A19FFFA3A19FF2FFFFFF00FFFFFF000000002300000033000000330000 0033000000330000003300000033000000330000003300000033000000330000 00330000003300000030FFFFFF0000000000000000000000000000000000B26E 1795B06C13F7B06B11FFB06A11FFB06B11FFB06C13F7B26E1795000000000000 00000000000000000000FFFFFF000000000000000000B3701946B06A11FFD99C 55FFFAC18AFFFFCE9AFFFFCF9AFFFFCE9AFFFAC18AFFD99C55FFB06A11FFB370 19460000000000000000FFFFFF0000000000B3701946B57019FFF1B67BFFE6D3 B2FFBCE5E9FFADECFFFF63808BFFADECFEFFBCE4E8FFE5D2B1FFF1B67AFFB570 19FFB370194600000000FFFFFF0000000000B06B12FFEEB375FFD9DAC7FFB6F3 FFFFB8EFFCFFB8ECF7FFB8EBF6FFB7EAF4FFB4E9F5FFB2ECFCFFD7D7C3FFEEB2 74FFB06B12FF00000000FFFFFF00B26F1895D4934BFFE4CDA9FFBBF5FFFF5D52 4FFF95A8ADFFC2F2FAFFBEECF4FFBCEAF2FFBCE9F2FFBAEAF4FFB7EFFEFFE4CB A8FFD4934BFFB26F1895FFFFFF00B06D15F8EBAD6DFFC8E9EBFFC4F4FFFFA9C8 CCFF615652FFABC9CDFFC8F4FCFFC4EFF6FFC2ECF3FFC2ECF4FFC0EFF9FFC7E8 EAFFEBAD6DFFB06D15F8FFFFFF00B16D14FFF1B173FFC7FAFFFFC9F3FBFFCDF6 FDFFAECACEFF5E5351FFAEC9CEFFCCF6FCFFC8F0F6FFC7EEF4FFC8F1F9FFC7F9 FFFFF1B173FFB16D14FFFFFFFF00B16D14FFEEAD6AFF7F959EFFCEF6FCFFCEF4 F9FFD4FCFFFFB5D0D4FF5A504EFFADC5C8FFCEF4F9FFCDF2F7FFCEF6FCFF7F95 9EFFEEAD6AFFB16D14FFFFFFFF00B16D15FFE9A663FFD3FFFFFFD2F6FDFFD2F5 FAFFD7FBFFFF544947FFB3CCCEFFD6FAFFFFD2F5FAFFD1F3F9FFD2F6FDFFD3FF FFFFE9A663FFB16D15FFFFFFFF00B16D16F9DD9A52FFD9F0ECFFD6FBFFFFD6F8 FBFFD8F9FCFFDBFDFFFFDAFCFFFFD8F8FBFFD6F6F9FFD6F7FAFFD6FBFFFFD9F0 ECFFDD9A52FFB16D16F9FFFFFF009E6316A9C98435FFDDB98BFFDCFFFFFFDBFB FFFFDBF9FDFFDCFAFDFFDCF9FDFFDBF8FCFFDBF9FCFFDBFBFFFFDCFFFFFFDDB9 8BFFC98435FF9E6316A9FFFFFF000000001EB16D15FFD48D42FFDECCACFFE2FF FFFFE1FFFFFFE2FFFFFFE3FFFFFFE2FFFFFFE1FFFFFFE2FFFFFFDECCACFFD48D 42FFB16D15FF0000001EFFFFFF0000000000754A126BB46F18FFD0893BFFDCB3 80FFE4F4EDFFEBFFFFFF9AABB2FFEBFFFFFFE4F4EDFFDCB380FFD0893BFFB46F 18FF754A126B00000000FFFFFF00000000000000000E764A126BB26E16FFC27C 2BFFD08638FFD4893AFFD4893AFFD4893AFFD08638FFC27C2BFFB26E16FF764A 126B0000000E00000000FFFFFF0000000000000000000000000E000000339D63 18AAB16E18F9B26F18FFB26F18FFB26F18FFB16E18F99D6318AA000000330000 000E0000000000000000FFFFFF00000000000000000000000000000000000000 001E00000031000000330000003300000033000000310000001E000000000000 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 00003C86CFB05698D8FF5698D8FF3D86CFEE0000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 00003882CDFFDAF8FFFFDAF8FFFF3882CDFF0000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 00002E70B2AB90C6EFFFAFDDFAFF327AC4DB0000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF003D86CFB05297D8FF589BDAFF589B DAFF5698D8FFB3E3FCFFBCE9FFFF5698D8FF5A9CDAFF5498D8FF3D86CFB00000 00000000000000000000FFFFFF00FFFFFF003A83CDFFBFF6FFFFB9F0FFFFBCF0 FFFFC1F1FFFF56CBFFFF56CBFFFFC2F1FFFFC0F2FFFFC2F6FFFF3A82CDFF0000 00000000000000000000FFFFFF00FFFFFF003A83CDFFB6F6FFFFB1EEFFFF50CB FFFF20BAFFFF27BCFFFF27BCFFFF24BBFFFF1DBAFFFFB9F3FFFF3980CCFF0000 00000000000000000000FFFFFF00FFFFFF00397ABDBD4F96D8FF68ADE2FFB0EF FFFF2DC0FFFF34C2FFFF36C3FFFF34C2FFFF2DC0FFFFB2F1FFFF3E83CDFF3A81 CCD2448CD2FF4087CFEEFFFFFF00FFFFFF000000002300000033529BDAFFA7F0 FFFF36C6FFFF3CC8FFFF3EC8FFFF3DC8FFFF38C6FFFF5ED5FFFF9EEAFFFF79C7 F0FFAAFAFFFF3C84CEFFFFFFFF00FFFFFF000000000000000000519BDAFF9EEF FFFF3ECAFFFF43CBFFFF45CCFFFF44CCFFFF40CBFFFF5ED7FFFF96EAFFFF76C7 F0FFA1FAFFFF3D84CEFFFFFFFF00FFFFFF003F86CFC04C96D8FF5EADE2FF93EE FFFF45CEFFFF49CFFFFF49D0FFFF49CFFFFF46CFFFFF95F0FFFF3E83CDFF397C C4DB3D84CEFF3F85CDF1FFFFFF00FFFFFF003D82CDFF8DF6FFFF76E6FFFF58D9 FFFF7BE8FFFF7CE9FFFF7CE9FFFF7BE7FFFF61DDFFFF8BF1FFFF3B7FCCFF0000 002A0000003301030430FFFFFF00FFFFFF003D81CCFF83F2FFFF55DAFFFF6BE5 FFFF4E98D8FF4F9CDAFF4F9BDAFF59ADE2FF80EEFFFF7FF0FFFF3C81CCFF0000 00000000000000000000FFFFFF00FFFFFF003E82CDFF7CF6FFFF79F1FFFF7CF5 FFFF3D80CCFF00000033000000334896D7FF7BF4FFFF7BF6FFFF3E82CDFF0000 00000000000000000000FFFFFF00FFFFFF003F84CDF24897D8FF4A9CDAFF4897 D8FF3E81C8DD00000000000000003A7ABCBD4897D8FF4898D8FF3B7BBEC00000 00000000000000000000FFFFFF00FFFFFF000000003000000033000000330000 00330000002B0000000000000000000000230000003300000033000000230000 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00979B9AD0858A88FF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF8A8F8DAB0000 0000000000000000000000000000878C8AFDFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF858A88FF0000 0000000000000000000000000000868B89FDFFFFFFFFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFFFFFFFFF858A88FF0000 0000000000000000000000000000878C8AFDFFFFFFFFEFF0F0FFC6C7C7FFC6C7 C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFEFF0F0FFFFFFFFFF858A88FF0000 0000000000000000000000000000868B89FDFFFFFFFFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFD5D6D6FF808381FF808381FF808381FF808381FF808482FF0000 0000000000000000000000000000878C8AFDFFFFFFFFEFF0F0FFC6C7C7FFC6C7 C7FFA6A9A8FF808381FFC8BAAEFFD2BCA6FFD4BAA2FFCDB9A8FF808381FF7074 735C000000000000000000000000868B89FDFFFFFFFFEFF0F0FFEFF0F0FFD5D7 D6FF808381FFC8B7A8FFD2AC8AFFE7D3BFFFEAD7C5FFD9BA9CFFCBAD90FF8083 81FF6B6F6D310000000000000000878C8AFDFFFFFFFFEFF0F0FFC6C7C7FF8083 81FFBBAEA3FFCFA985FFF2E6DCFFF7EEE8FFF5ECE4FFECDACAFFD8B28EFFCBAF 97FD808381FF0000000000000000878C8AFDFFFFFFFFEFF0F0FFEFF0F0FF8083 81FFD0B8A2FFDFC0A5FFF1E4D9FFF3EAE0FFF2E7DDFFE9D4C1FFDFBEA0FFD0A6 81FE808381FF0000000000000000868B89FDFDFEFEFFEFF0F0FFEFF0F0FF8083 81FFD6BFA9FFE0C1A5FFEEDED0FFF2E5DAFFEDDCCDFFECD9C8FFE8D0BCFFD1A7 80FD808381FF0000000000000000868B89FBF9FAFAFFEFF0F0FFEFF0F0FF8083 81FFC3B5A7FFD0AB89FFE5CAB3FFEBD7C3FFEAD4C1FFEEDDCFFFDABDA3FFCEAF 93FB808381FF0000000000000000868B89FBFFFFFFFFFFFFFFFFFFFFFFFFCDCF CFFF808381FFD1B89FFFD6B391FFDFC5AFFFE3CAB2FFD6BAA0FFD3B497FF8083 81FF737675E20000000000000000898E8CA3868B89FF858A88FF858A88FF858A 88FF7B807EFF808381FFDCC8B3FFCFAC8BFFD1A880FFD0B399FF808381FFA3A4 A3FFA3A4A3FF6A6E6CD800000000000000000000000000000000000000000000 0000000000006A6E6C89808381FF808381FF808381FF808381FF8C8E8DFFB7B8 B8FFA3A4A3FFA3A4A3FF828484FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008C8E 8DFFB7B8B8FFA3A4A3FF828484FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00028C8E8DFF8C8E8DFF828484FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E9E629D9D9DE89B9B 9BF999999992FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E9E1B9C9C9CE4E1E1E1FFD2D2 D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B9B54B5B5B5FFE6E6E6FF9494 94EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0098989855B2B2B2FFD6D6D6FF9191 91DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF0096969602949494C5CBCBCBFFD2D2D2FFC9C9 C9FFD2D2D2FFC6C6C6FF858585E834B4D9D05EC2E1FA60C3E2FA60C3E2FA60C3 E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AFA3FFD5D5D5FFBBBBBBFFA6A6 A6FFA0A0A0FF848484E48282826236B3DAF8FDFEFEFFFEFFFFFFFEFEFFFFFDFE FFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA17CFFBCA595FF839DA5FC7BAE BEEC6395A58E81818117FFFFFF0035AFDAF0F7FCFEFF8EE4F8FF91DEF5FF9FE0 F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BEA3FFD58E64FFEEFBFEFFFAFD FFF936AFDAD4FFFFFF00FFFFFF0036AADAF2F1FAFDFF94DEF5FF93DCF4FFACBF BFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594DAFF3594DAFF3594DAFF3594 DAFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6FBFF7EC5EAFF4AA3DFFF5E97 C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEBE8FFF1F9FDFFF0F9FDFFFFFF FFFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFFFFFFF8FDFFFFF6FDFFFFF4F4 F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0F7FF72DDF6FF68DBF5FFE9F9 FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FCFEFFC8F2FCFFB9EFFBFF94DF EFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDDF6FF61DAF5FF57D7F4FFE7F8 FDFF3594DAFFFFFFFF00FFFFFF00369ADAF8F2FAFDFFB3EDFAFFA4E9F9FF95E6 F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DAF5FF54D6F3FF47D3F2FFE8F9 FDFF3594DAFFFFFFFF00FFFFFF003594DAF7EFFAFEFFA1E9F9FF91E5F8FF81E1 F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0F2FF2ECDF1FF26CBF0FFCAF2 FBFF3594DAF7FFFFFF00FFFFFF00338ED9E6DCF0FAF0A7DDF4FD9EDBF4FF96DA F3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2F1FF6CD0F1FF69CFF1FFC2EA F8FE338ED9F0FFFFFF00FFFFFF002C86D8702D88D8A62D87D8EA2D88D8F72D88 D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D87D8F72D88 D8F12C86D893FFFFFF00FFFFFF00000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000007B 001D000000010000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000005870A311399 28DB0E901AA60000000100000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000A870F33179E30DB37C7 71FF2DBC5DF80A8D159B00000000000000000000000000000000000000000000 00000000000000000000000000000000000005870A31169D2EDA37C770FF37C7 71FF18A031DB0A870F330000000000000000000000000A870F330A8D149B0000 00010000000000000000000000000A870F33179E30DB37C771FF37C771FF179E 30DB0A870F3300000000000000000000000005870A31169D2EDA2EBD5EFA0E90 1AA6008000020000000005870A31169D2EDA37C770FF37C771FF18A031DB0A87 0F33000000000000000000000000000000000A8D159B2DBC5DF837C871FF2DBC 5DF80D9019A30A890F34179E30DB37C771FF37C771FF179E30DB0A870F330000 000000000000000000000000000000000000000000010D9019A32DBC5DF837C8 71FF2DBC5DF819A133E337C771FF37C771FF179E30DB0A870F33000000000000 00000000000000000000000000000000000000000000000000010D9019A12CBA 5AF937C871FF37C871FF37C771FF18A031DB0A870F3300000000000000000000 0000000000000000000000000000000000000000000000000000000000010D90 19A12CBA5AF937C771FF18A031DB0A870F330000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00010D9019A3149927DC0A870F33000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000001007B001D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000500B66C0500 B66C0000000000000000000000000000000000000000000000000500B6690500 B66900000000000000000000000000000000000000000200B5680C00CFE90D00 D0EB0500B66D000000000000000000000000000000000200B56B0C00CFE90D00 D0EB0500B86B000000000000000000000000000000000200B5680C00CFE91400 E6FF0D00D0EB0500B66D00000000000000000200B56B0C00CFE91400E6FF0D00 D0EB0500B86B00000000000000000000000000000000000000000300B6650C00 CFE91400E6FF0D00D1EB0500B66D0300B7660C00CFE91400E6FF0D00D1EB0500 B66D000000000000000000000000000000000000000000000000000000000500 B66C0C00CFEA1400E6FF0C00D0EA0C00D0EA1400E6FF0C00CFEA0500B66C0000 0000000000000000000000000000000000000000000000000000000000000000 00000200B56B0C00D0E81400E6FF1400E6FF0D00D0EB0500B66D000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000200B56B0C00D0E81400E6FF1400E6FF0D00D0EB0500B66D000000000000 0000000000000000000000000000000000000000000000000000000000000500 B66C0C00CFEA1400E6FF0C00D0EA0C00D0EA1400E6FF0C00CFEA0500B66C0000 00000000000000000000000000000000000000000000000000000300B7660C00 CFE91400E6FF0D00D1EB0500B66D0300B6650C00CFE91400E6FF0D00D1EB0500 B66D00000000000000000000000000000000000000000200B5680C00CFE91400 E6FF0D00D0EB0500B66D00000000000000000200B56B0C00CFE91400E6FF0D00 D0EB0500B86B000000000000000000000000000000000200B5680C00CFE90D00 D0EB0500B66D000000000000000000000000000000000200B56B0C00CFE90D00 D0EB0500B86B00000000000000000000000000000000000000000500B6690500 B6690000000000000000000000000000000000000000000000000500B6690500 B669000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000BB874700BB874700BB874700BB874800BB87 4B00BB871A00BB871E00BB871F00BB871E00B98419EFB67E0EFFB47B09FFB47B 08FFB47B09FFB57B09FFB47B09FFBB874700BB874700BB874700BB874700BB87 4A00BB871900BB871D00BB871F00BA851C00B67E0EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFBB874700BB874700BB874700BB874700BB87 4900BB874D00BB871C00BB871F00BA851B00B47B09FFFFFFFFFFFFEFCDFFFFEF CEFFFFF3D2FF9E937EFFFFF3D2FFBB874700BB874700BB874700BB874600BB87 4700BB874C00BB871B00BB871E00BA851B00B47B09FFFFFFFFFFFFF0CFFFFFF0 D0FFFFF5D4FFA19682FFFFF4D4FFBB874700BB874700BA8545B1B98442FFBA85 4500BB874A00BB871A00BB871D00B9851A00B57D0CFFFFFFFFFFFFFAE2FFFFFA E0FFFFFDE0FFA59D89FFFFFBDDFFBB874700BA854500B88240FFECD7B7FFB680 3EFFB9844700BB861800B98519ADB78012FFB47C0AFFB17600FFB07500FFAC85 37FFA6A095FFA8A091FFA59C8CFFBA8545EEB88240FFB47D3AFFEED8B7FFECD3 AFFFB68141FFB9844900B78110FFFAEBD7FFF7E6CFFFF6E6CDFFF8E8D1FFB276 00FFFFFFF6FFA5A093FFFFFEE7FFB98442FFF4DEBBFFF1DAB5FFE7C592FFD8A2 52FFEDCB9AFFB88346FFB67F0CFFF8E8D1FFE2B777FFE2B777FFF7E6CEFFB276 00FFFFFFFAFFA59F93FFFFFEE9FFAB7A3FBFB88241FFB47E3DFFE5B265FFE7B4 67FFB68243FF00000033B78110FFFBEBD7FFF2D7B0FFF2D6AFFFFBE9D1FFB877 00FFFFFFFEFFB1A495FFFFFFEEFF0000002300000033B88343FFF5C57AFFB682 43FF00000033BB861800AA7915BDBB800DFFBD7C01FFBD7700FFBF7600FF887E 4EFF2285D8FF2080CEFF167BC8FFBB874700BB874700AB7B40C1B98545FF0000 0033BB874A00BD87170000000023000000333C99F2FF92FBFFFF93F7FFFF97F7 FFFF9BF6FFFF9EF6FFFF9EF6FFFFBB874700BB8747000000002300000033BC87 4600BF864500C4850A00CB840200449FF1004796E0FF9AF6FFFF46CDF4FF49CD F3FF4BCDF2FF4BCDF1FF4BCDF1FFBB874700BB874700BB874700BB874600BF86 4200C884360042A0F300499FEA004D9DE0004C95D8FF9CF6FFFF68DAF6FF6ADA F6FF6BDBF6FF6BDBF6FF6BDBF6FFBB874700BB874700BB874700BD874500C385 3B0042A0F1004D9EE200509DDD00519CDA004D97D8FF9FFAFFFF8AEEFFFF8BEE FFFF8CEFFFFF8DEFFFFF8DEFFFFFBB874700BB874700BB874700BD874500C685 3800459FEB004F9DDD00519DDA00519DDA00488EC7C04895D5FF4290D2FF3D8D D0FF378BCEFF3287CCFF2B85C9FF000000000000000000000000000000000000 0000000000000000000000000000000000000000002300000033000000330000 0033000000330000003300000033B98419EFB67E0EFFB67C09FFB67B07FFB67B 08FFB57B08FFB67B08FFB67B08FFB57B08FFB67B08FFB67B08FFB57B08FFB67C 09FFB67E0EFFB98419EFBB871E00B67E0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFB67E0EFFBA851C00B57C09FFFFFFFFFF44C3FFFF49C5FFFF47C6 FFFFE3B57EFF46C7FFFF46C7FFFFE3B57EFF46C7FFFF46C7FFFFE1B47EFF40C4 FFFFFFFFFFFFB57C09FFBA851B00B57B09FFFFFFFFFFDDB17CFFE0B47EFFE0B6 82FFDEB786FFE0B784FFE0B785FFDFB988FFE0B786FFE0B786FFDEB887FFDCB4 82FFFFFFFFFFB57C09FFBA851B00B47B08FFFFFFFFFFFFF5D7FFFFF6D9FFFFF9 DFFFD8B88FFFFFFFE9FFFFFFECFFDBBC98FFFFFFEDFFFFFFECFFDBBB97FFFFFF EAFFFFFFFFFFB57D0DFFBA851C00B47B08FFFFFFFFFFFFF7DFFFFFF8E1FFFFFB E7FFD9BC99FFD2AB5BFFB07600FFB07600FFB07400FFB07300FFB07400FFAF73 00FFB07600FFB57D0EFFB9841AE7B47B08FFFFFFFFFFD4B38CFFD5B58FFFD7B9 94FFDCC1A3FFB27802FFFDE9C8FFFBE5C2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFBE5C2FFFFEBCDFFB78114FFB47B08FFFFFFFFFFFFFBEBFFFFFCECFFFFFF F3FFDCC3A7FFB27903FFFBE9CFFFDA8802FFF0EEECFFB2ADA7FFB2ADA7FFF0EE ECFFDA8802FFFBEAD1FFB67F12FFB47B08FFFFFFFFFFFFFDF2FFFFFEF3FFFFFF FAFFDCC4ACFFB27904FFF8E1BAFFDD9419FFEEE9E9FFEFE6DEFFEFE6DEFFEEE9 E9FFDD9419FFF8E2BCFFB68012FFB47B08FFFFFFFFFFD4B999FFD5BA9AFFD7BE A0FFDCC7B1FFB27904FFF5D8AAFFE19E2FFFE7CAA1FFEBE2E0FFEBE2E0FFE7CA A1FFE19E2FFFF6D9ADFFB68014FFB47A08FFFFFFFFFFFFFFFDFFFFFFFDFFFFFF FFFFDDC8B3FFB27904FFF4D39CFFE4A641FFE3A43AFFE3A133FFE2A132FFE3A4 3AFFE3A641FFF4D49EFFB68114FFB47B09FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFDBC7B6FFB17804FFF2CD90FFE6AD4FFFEACFA9FFFFFFFFFFFDFFFFFFE8CE A7FFE6AD4EFFF3CE93FFB68115FFB67E0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFB27907FFF3CA89FFEBB65CFFF2EDEDFF7F7978FFF1E9E2FFEEE9 E9FFEAB55BFFF3CC8BFFB68116FFB78219F2B67E0EFFB47B09FFB47A07FFB47B 09FFB67E0EFFB57F12FFF6CC8AFFF3C275FFF9FCFFFF8B8D91FFF9F9F9FFF4F8 FCFFF2C174FFF6CD8BFFB78218FF000000300000003300000033000000330000 003300000033A87919B9B78218FFB68114FFB88010FFB9810FFFB87F0EFFB67E 0FFFB68013FFB78218FFB7831CF2000000000000000000000000000000000000 0000000000000000002200000033000000330000003300000033000000330000 0033000000330000003300000030B98419EFB67E0EFFB67C09FFB67B07FFB67B 08FFB57B08FFB67B08FFB67B08FFB57B08FFB67B08FFB67B08FFB57B08FFB67C 09FFB67E0EFFB98419EF00000000B67E0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFB67E0EFF00000000B57C09FFFFFFFFFF44C3FFFF49C5FFFF47C6 FFFFE3B57EFF46C7FFFF46C7FFFFE3B57EFF46C7FFFF46C7FFFFE1B47EFF40C4 FFFFFFFFFFFFB57C09FF00000000B57B09FFFFFFFFFFDDB17CFFE0B47EFFE0B6 82FFDEB786FFDFB683FFDFB683FFDEB786FFDFB683FFDFB683FFDDB684FFDBB3 7FFFFFFFFFFFB57B09FF00000000B47B08FFFFFFFFFFFFF5D7FFFFF6D9FFFFF9 DEFFD7B58BFFFFF9DFFFFFF9DFFFD7B58BFFFFF9DFFFFFF9DFFFD7B58AFFFFF8 DBFFFFFFFFFFB47B08FF00000000B47B08FFFFFFFFFFFFF7DFFFFFF8E1FFFFFB E5FFD6B78FFFFFFBE6FFFFFBE6FFD6B78FFFFFFBE6FFFFFBE6FFD5B78EFFFFFA E3FFFFFFFFFFB47B08FF00000000B47B08FFFFFFFFFFD4B38CFFD5B58FFFD7B8 92FFD8BA95FFD7B893FFD7B893FFD8BA95FFD7B893FFD9BA93FFDABB95FFD9B9 90FFFFFFFFFFB67C07FF00000000B47B08FFFFFFFFFFFFFBEBFFFFFCECFFFFFF F0FFD7BA96FFFFFFF1FFFFFFF1FFD8BB97FFFFFFF2FFFFFFF2FFE8C896FFFFFF F2FFFFFFFFFFC38501FF00000000B47B08FFFFFFFFFFFFFDF2FFFFFEF3FFFFFF F7FFD7BB9AFFFFFFF8FFFFFFF8FFDBBE9BFFFFFFF8FF7B85CBFF0319AAFF061B A9FF071DAFFF655464FF00000000B47B08FFFFFFFFFFD4B999FFD5BA9AFFD6BC 9EFFD8BFA1FFD7BD9EFFD8BE9EFFE4C9A2FF6968A6FF263DC6FF6B85FFFF728B FFFF6D87FFFF324ACCFF1D30B394B47A08FFFFFFFFFFFFFFFDFFFFFFFDFFFFFF FFFFD7BEA0FFFFFFFFFFFFFFFFFFEACFA5FF041AACFF5877FFFF5876FFFF5473 FEFF5877FFFF5E7BFFFF1D2EADFFB47B09FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFD6BDA2FFFFFFFFFFFFFFFFFFEACFA8FF061BABFFA8BAFFFFFFFFFFFFFFFF FFFFFFFFFFFFACBDFFFF1B2DACFFB67E0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF071EB1FF3E63FEFF3D61FBFF3A5E F9FF3D61FBFF4366FDFF1E30ADFFB78219F2B67E0EFFB47B09FFB47A07FFB47A 08FFB47B08FFB47A08FFB67C07FFC18403FF635467FF2139C7FF385FFBFF3961 FEFF3960FAFF283EC1FF1E2E9BAC000000300000003300000033000000330000 00330000003300000033000000330000003300000033182AA1A92132AEFF2232 ADFF2233ADFF1F2E9BAC0000001E000000000000000000000000000000000000 000000000000000000000000000000000000000000000000001E000000330000 0033000000330000001E00000000B9A697EFB7A495FFB6A393FFB6A393FFB6A3 93FFB6A393FFB6A393FFB6A393FFB6A393FFB6A393FFB7A494FFB7A595FFB5A2 92FFB4A191FFBBA99AFFB8A696B0B7A494FFE3DDD7FFE1D9D4FFE0D9D3FFE0D9 D3FFE0D9D3FFE0D9D3FFE0D9D3FFE0D9D3FFE1D9D4FFE3DCD7FFB39F8EFFFFFF FFFFFFFFFFFFFFFFFFFFB6A393FFB5A394FFF2EDE8FFF2E9E2FFF1E9E1FFF1E9 E1FFF1E9E1FFF1E9E1FFF1E9E1FFF1E9E1FFF2E9E2FFF2ECE7FFB19D8DFFF6F2 ECFF73706DFFF9F4EEFFB6A393FFB5A69BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2A194FFE8DF D4FFE8DED2FFE9DFD3FFB7A495FFB87F38FFB2772EFFAF7329FFAE7229FFAE72 29FFAE7229FFAE7229FFAE7229FFAE7229FFAF7329FFB2762DFFB67B31FFB7A6 9BFFB7A596FFB7A596FFAA988BC0B67F3CFFFFF4D8FFFFEED1FFFFEDD0FFFFED D0FFFFEDD0FFFFEDD0FFFFEDD0FFFFEDD0FFFFEED1FFFFF4D7FFB67C36FF0000 0033000000330000003300000023B57E3BFFFFF1D4FFF6D3A8FFF5D3A7FFF5D3 A7FFF5D3A7FFF5D3A7FFF5D3A7FFF5D3A7FFF6D3A8FFFFF1D4FFB57D38FF0000 0000000000000000000000000000B67F3CFFFFF4D8FFFDE5C3FFFDE5C2FFFDE5 C3FFFDE5C3FFFDE5C3FFFDE5C3FFFDE5C2FFFDE5C3FFFFF4D8FFB67F3BFF0000 0000000000000000000000000000B87F38FFB2772EFFAF732AFFAE732AFFAE73 2AFFAE732AFFAE732AFFAE732AFFAE732AFFAF732AFFB2772EFFB87F38FF0000 0000000000000000000000000000B5A59BFFFFFFFFFFFBFBFCFFFBFBFCFFFBFB FCFFFBFBFCFFFBFBFCFFFBFBFCFFFBFBFCFFFBFBFCFFFFFFFFFFB5A59BFF0000 0000000000000000000000000000B5A393FFFFFFFFFFF9F5F0FFF9F5F0FFF9F5 F0FFF9F5F0FFF9F5F0FFF9F5F0FFF9F5F0FFF9F5F0FFFFFFFFFFB5A393FF0000 0000000000000000000000000000B6A394FFB19D8CFFAF9A89FFAE9A89FFAE9A 89FFAE9A89FFAE9A89FFAE9A89FFAE9A89FFAF9A89FFB19D8CFFB6A394FF0000 0000000000000000000000000000B5A292FFFFFFFFFFF5ECE5FFF5ECE5FFF5ED E6FFF5EDE6FFF5EDE6FFF5EDE6FFF5ECE5FFF5ECE5FFFFFFFFFFB5A292FF0000 0000000000000000000000000000B5A393FFFFFFFFFFF3E8DFFFF3E8E0FFF3E9 E0FFF3E9E0FFF3E9E0FFF3E9E0FFF3E8E0FFF3E8DFFFFFFFFFFFB5A393FF0000 0000000000000000000000000000B6A494F2B5A393FFB5A292FFB5A292FFB5A2 92FFB5A292FFB5A292FFB5A292FFB5A292FFB5A292FFB5A393FFB6A494F20000 0000000000000000000000000000000000300000003300000033000000330000 0033000000330000003300000033000000330000003300000033000000300000 0000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004B4B4CEF444344FFB9B4B3FFB9B4 B3FFB9B4B3FFB9B4B3FFB9B6B4FFBBB6B4FFBCB8B6FFBCB9B7FFBCB9B8FFBCB9 B9FF444344FF4B4B4CEFFFFFFF00FFFFFF00414042FF59595AFFFAF4F1FFFAF4 F0FFFAF4F0FFFAF4F0FFFAF4F1FFFAF5F2FFFBF6F3FFFCF8F5FFFCF9F7FFFDFB F9FF646365FF414042FFFFFFFF00FFFFFF003F3E40FF616062FFFDFAF9FFCFB6 9CFFCFB69CFFCFB69CFFCFB69CFFCFB69DFFCFB79DFFD0B79EFFD0B89FFFFEFD FDFF616062FF3F3E40FFFFFFFF00FFFFFF003D3C3DFF5D5C5EFFFDFCFBFFFBF9 F8FFFBF9F9FFFBF9F8FFFBF9F8FFFAF8F7FFFAF7F5FFF9F6F4FFF8F4F2FFF9F6 F2FF5D5C5EFF3D3C3DFFFFFFFF00FFFFFF003B3A3BFF5A595BFFF7F3EEFFF7F3 EFFFF7F3EFFFF7F3EFFFF7F3EEFFF6F2EEFFF6F1EDFFF5F0EBFFF4EFE9FFF3ED E7FF5A595BFF3B3A3BFFFFFFFF00FFFFFF00383739FF565557FFF1EAE2FFB8A2 8BFFB8A28BFFB8A28BFFB8A28BFFB7A18AFFB7A18AFFB7A08AFFB6A089FFEDE5 DCFF565557FF383739FFFFFFFF00FFFFFF00363537FF535254FFE8DED4FFE8DD D0FFE8DDD0FFE8DDD0FFE7DCD0FFE7DCCFFFE7DBCFFFE6DBCEFFE6DACDFFE6DA CFFF535254FF363537FFFFFFFF00FFFFFF00333335FF4F4E51FF4F4E51FF4F4E 51FF4F4E51FF4F4E51FF4F4E51FF4F4E51FF4F4E51FF4F4E51FF4F4E51FF4F4E 51FF4F4E51FF333335FFFFFFFF00FFFFFF00313032FF4B4A4DFF4B4A4DFF4B4A 4DFF4B4A4DFF4B4A4DFF4B4A4DFF4B4A4DFF4B4A4DFF4B4A4DFF4B4A4DFF4B4A 4DFF4B4A4DFF313032FFFFFFFF00FFFFFF002E2D30FF464549FF464549FFCDCD CDFFD6D6D6FFD5D5D6FFD5D5D5FFD6D6D6FFD6D6D6FFD3D3D3FF272629FF2423 26FF464549FF2E2D30FFFFFFFF00FFFFFF002A292BFF403F42FF403F42FFA7A7 A7FF3D3C3FFF333335FFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFF414042FF2727 28FF444346FF2A292BFFFFFFFF00FFFFFF00252426FF39383BFF39383BFF9999 99FF323134FF262528FF9F9F9FFF9F9F9FFF9F9F9FFF9F9F9FFF3F3E41FF2524 26FF58575AFF252426FFFFFFFF00FFFFFF00222224ED2A2A2DFF323135FF8B8A 8BFF29282BFF201F21FF909090FF909090FF909090FF909090FF343336FF201F 21FF4E4D51FF212023FFFFFFFF00FFFFFF001F1F252F1D1D1FEC1C1B1EFF7575 75FF787878FF787878FF787878FF787878FF787878FF787878FF1A191BFF1919 1BFF1D1C1FFF1F1F21EFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00186FAB174345D3D63A3A CFB25353D418FFFFFF00FFFFFF00FFFFFF004B4B4CEF444344FFB9B4B3FFB9B4 B3FFB9B4B3FFB9B4B3FFB9B6B4FFBBB6B4FFB6B6B5FF34B6DEFF446AC0FF1B1B CEFF1111A3FF4A4A4DEFFFFFFF00FFFFFF00414042FF59595AFFFAF4F1FFFAF4 F0FFFAF4F0FFFAF4F0FFFAF4F1FFF9F5F2FF55C6E9FF36AFD4FF1E2020FF1D2B 85FF05079AFF3A394FFFFFFFFF00FFFFFF003F3E40FF616062FFFDFAF9FFCFB6 9CFFCFB69CFFCFB69CFFCFB69CFF5E9FABFF2EB3DBFF242B2DFF0B1C21FF11A0 CDFF2E607AFF3E3D3FFFFFFFFF00FFFFFF003D3C3DFF5D5C5EFFFDFCFBFFFBF9 F8FFFBF9F9FFFBF9F8FF94C3D1FF32C4F1FF27363BFF0E171AFF1598C1FF57A6 BEFF3D3C3EFF3B3A3BFFFFFFFF00FFFFFF003B3A3BFF5A595BFFF7F3EEFFF7F3 EFFFF7F3EFFFAFCFD7FF33CAF9FF2C454CFF151819FF178BB0FF3DA2C1FF8F8B 88FF464546FF3B3A3BFFFFFFFF00FFFFFF00383739FF565557FFF1EAE2FFB8A2 8BFF979D92FF71D8F7FF34565FFF1D1D1DFF117390FF2199BCFF5E5449FF9F9A 94FF555456FF383739FFFFFFFF00FFFFFF00363537FF535254FFE8DED4FFCCD0 C9FF84DCF7FF54808CFF252525FF12617AFF1CA6D1FF666867FF827B74FFDDD1 C7FF535254FF363537FFFFFFFF00FFFFFF00333335FF4F4E51FF4A5156FF67C6 E4FF4E899CFF252525FF094558FF0DA4D5FF1E2F36FF252426FF484749FF4F4E 51FF4F4E51FF333335FFFFFFFF00FFFFFF00313032FF494B4FFF46ADCEFF1582 A5FF262626FF0E3845FF0CABDDFF173641FF1D1C1DFF3D3D3FFF4B4A4DFF4B4A 4DFF4B4A4DFF313032FFFFFFFF00FFFFFF002E2D30FF298FB2FF1695BDFF2528 29FF18343DFF0EADDFFF2E5E6CFF424242FF959595FFD3D3D3FF272629FF2423 26FF464549FF2E2D30FFFFFFFF00FFFFFF004E606CFF2C9ABDFF242C2FFF2131 36FF0BA3D2FF0C5166FF2B2B2BFF606060FFAEAEAEFFAEAEAEFF414042FF2727 28FF444346FF2A292BFFFFFFFF00FFFFFF0088A1AFFFB0CAD6FF2C3A3EFF0B96 C1FF0C6885FF070707FF404040FF9C9C9CFF9F9F9FFF9F9F9FFF3F3E41FF2524 26FF58575AFF252426FFFFFFFF00567181049DBCCAFF7AB8CCFF3C92AEFF1F6E 89FF161517FF181719FF8A8A8AFF909090FF909090FF909090FF343336FF201F 21FF4E4D51FF212023FFFFFFFF006279867E364246FF44778DFB252D34FF7575 75FF787878FF787878FF787878FF787878FF787878FF787878FF1A191BFF1919 1BFF1D1C1FFF1F1F21EFFFFFFF004864725A36546523FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004753BC504733A65FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733AFF2A8C59F604743AAB04733A0CFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733AFFB7E1CBFF5AAB82F904743AE104733A2DFFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733AFFBBE3CEFFABDCC3FF84C6A4FE107A43F504733A65FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF0004743AE804733AFF04733AFF04733AFF0473 3AFF04763BF7B6E0CBFF6FC499FF91D2B1FF9CD4B7FF318F5FF604743BAC0473 3A0CFFFFFF00FFFFFF00FFFFFF0004733AFFA7DBC0FFAADCC2FFADDDC5FFAFDE C6FFB0DEC7FFB0DEC7FF64C191FF61C18FFF73C89DFF9FD9BBFF5AAB81FA0574 3AE104733A2DFFFFFF00FFFFFF0004733AFFA3D9BDFF54B985FF58BB88FF5BBC 8BFF5CBD8BFF5CBE8CFF5CC18DFF5AC28DFF55C28AFF58C38CFF8CD4AFFF7AC3 9CFE147C46F504733A65FFFFFF0004733AFF9CD7B9FF3BAF74FF33AC6EFF2BA9 68FF2FAC6BFF3DB678FF49BE82FF50C389FF4DC488FF49C284FF44BE80FF6DCA 9BFF89CEAAFF308F5EF604753B9D04733AFF7ECAA3FF069A4EFF069A4EFF069A 4EFF07A052FF09A757FF0BAE5BFF0EB25FFF17B866FF1FBA6CFF26BA6FFF55C6 8DFF76C99EFF268956F504753B9D04733AFF7ECAA3FF069A4EFF069A4EFF069C 4FFF08A454FF0BAC5AFF0DB35EFF0EB962FF0FBC64FF1CBF6CFF67D29CFF5DBB 8BFE0E7A42F504733A65FFFFFF0004733AFF7ECAA3FF7ECAA3FF7ECAA3FF7ECC A4FF7FD1A7FF81D5AAFF0EB761FF10BF66FF34CB7FFF78DAA8FF3EA671F90476 3BE104733A2DFFFFFF00FFFFFF0004743AE804733AFF04733AFF04733AFF0473 3AFF04783CF781D6ABFF11BA64FF52D392FF73D7A5FF1E8B53F504763CAC0473 3A0CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733AFF81D7ABFF6CD5A0FF58C18BFE0A7940F504743A65FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733AFF7BD3A6FF36A16AF804763CE104733A2DFFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733AFF18844DF504763BAB04733A0CFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004753BC504733A65FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000474 3AE804733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04743AE8FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFAEDEC6FFAADCC2FFA4DABEFF9FD8BBFF9AD6B7FF93D3B2FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB0DFC7FF5DBD8CFF54B985FF49B57DFF3EB076FF8FD1AFFF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB1DFC7FF5EBE8DFF55BA86FF4AB57EFF3FB176FF8ACFACFF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB0DFC7FF5EBE8DFF54B985FF49B57DFF3EB076FF85CDA9FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF0004753BC504733AFF04733AFF04733AFF0476 3BF7AFDEC6FF5BBC8BFF52B884FF47B47CFF35AD70FF7FCBA4FF04763BF70473 3AFF04733AFF04733AFF04753BC504733A65278956F6ACDCC4FFB2DFC8FFB0DE C7FFACDDC4FF58BD89FF4EBB84FF43B87CFF0FA458FF7FCEA5FF7ECDA4FF7ECC A4FF78C79FFF18824BF504733A65FFFFFF0004743BAC4DA478F89ED7BAFF61C0 90FF5BC18DFF55C18AFF3AB978FF11AD5EFF0BAB59FF0AAA59FF0CA958FF68C7 97FF349A65F804743BABFFFFFF00FFFFFF0004733A0C04743AE173BF98FE87D2 ACFF56C38CFF30BA74FF0CB15DFF0DB45FFF0DB45FFF0DB35EFF4EC589FF55B7 84FE04753BE104733A0CFFFFFF00FFFFFF00FFFFFF0004733A2D0B773EF68FD3 B0FF5BC891FF0DB45FFF0FB962FF0FBC65FF10BD65FF32C57BFF71CE9FFF0A78 3FF604733A2DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0004733A65238A 56F578D2A5FF1CBD6BFF11C067FF12C56AFF1FC973FF78DBA8FF1E8952F50473 3A65FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000475 3BAC3DA36FF969D59EFF12C469FF14CB6EFF6CE0A5FF3FA872F904763CABFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3A0C04763BE15DBF8DFE4CD18DFF4ED590FF5FC592FE04763CE104733A0CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733A2D0E7A42F674D1A2FF75D3A3FF0E7B42F604733A2DFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF0004733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFFFFFFFF00FFFFFF00FFFFFF00FFFFFF000474 3AE804733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04743AE8FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB0DEC7FFABDCC3FFA6DABFFF91D2B1FF7ECAA3FF7ECAA3FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB1DFC8FF5FBE8DFF55BA86FF37AE71FF069A4EFF7ECAA3FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB1DFC7FF5FBE8DFF55BA86FF41B278FF069A4EFF7ECAA3FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB0DEC7FF5DBD8CFF54B985FF47B47CFF069A4EFF7ECAA3FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF0004753BC504733AFF04733AFF04733AFF0476 3BF7ADDDC5FF59BC89FF50B882FF34AD6FFF069A4EFF7ECAA3FF04763BF70473 3AFF04733AFF04733AFF04753BC504733A65278956F6AADBC2FFAFDEC6FFADDD C5FFAADCC2FF56BD88FF4DBA82FF1FAA63FF08A253FF7FCEA5FF7ECDA4FF7ECC A4FF78C79FFF18824BF504733A65FFFFFF0004743BAC4FA57AF89BD6B8FF5DBE 8DFF58C08AFF51C087FF42BC7EFF0CAB5AFF0BAB59FF0AAA59FF0CA958FF68C7 97FF349A65F804743BABFFFFFF00FFFFFF0004733A0C04743AE175BF99FE83D1 A9FF52C289FF4DC387FF1EB669FF0DB45FFF0DB45FFF0DB35EFF4EC589FF55B7 84FE04753BE104733A0CFFFFFF00FFFFFF00FFFFFF0004733A2D0D7840F690D3 B1FF65CC98FF3BC27DFF0FB962FF0FBC65FF10BD65FF32C57BFF71CE9FFF0A78 3FF604733A2DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0004733A65268C 57F594DBB7FF31C379FF11C067FF12C56AFF1FC973FF78DBA8FF1E8952F50473 3A65FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000475 3BAC4CAA7AFA6DD6A0FF12C469FF14CB6EFF6CE0A5FF3FA872F904763CABFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3A0C04763BE15DBF8DFE4CD18DFF4ED590FF5FC592FE04763CE104733A0CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733A2D0E7A42F674D1A2FF75D3A3FF0E7B42F604733A2DFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF0004733A65248B56F5248B56F504733A65FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF0004763C9D04763C9DFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF0004753B9D04753B9DFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF0004733A65288957F5268956F504733A65FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733A2D0F7941F687CAA7FF7EC7A2FF0E7941F604733A2DFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3A0C04743AE172BD96FE72C59AFF6AC295FF5BB386FE04743AE104733A0CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000474 3BAC4EA578FA91D2B0FF48B47DFF3FB176FF6AC295FF3B9C6AF904743AABFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0004733A65288A 57F6A0D7BBFF5FBD8CFF4DB680FF44B37AFF1AA25CFF71C49AFF1D844FF50473 3A65FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0004733A2D0D7840F69CD4 B7FF7AC9A0FF5ABE8BFF51BC86FF38B474FF08A353FF2CAF6CFF6EC397FF0A77 3EF604733A2DFFFFFF00FFFFFF00FFFFFF0004733A0C04743AE180C4A1FE97D5 B5FF69C596FF60C591FF56C38BFF1DB066FF0BAC59FF0BAB59FF4DC185FF55B4 84FE04753BE104733A0CFFFFFF00FFFFFF0004743BAC56A97FF9B0DFC7FF77CB A0FF6CCA9AFF63CA96FF43C181FF0DB35EFF0DB55FFF0DB45FFF0FB25FFF6ACE 9BFF359C67F804753BABFFFFFF0004733A65288B58F6B5E0CAFFBCE5D0FFB8E5 CEFFB3E5CBFF63CD97FF19BA68FF0FBC64FF10BE65FF83DCAFFF82DBAEFF82D9 ACFF7BD3A6FF18844CF504733A6504753BC504733AFF04733AFF04733AFF0478 3CF7B2E6CBFF4BC989FF10BD65FF11C369FF12C76BFF84E1B2FF057A3EF70473 3AFF04733AFF04733AFF04753BC5FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFB0E5CAFF31C378FF11C067FF13C86CFF15CF71FF85E5B4FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFADE4C8FF1FBD6DFF10BF66FF12C56AFF13C96DFF84E3B3FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFA9E2C5FF16B665FF0FBA63FF10BE66FF11C167FF83DEB0FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFA5DFC1FF81D5AAFF81D7ABFF82D9ACFF82DAADFF82D9ADFF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000474 3AE804733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04743BE8FFFF FF00FFFFFF00FFFFFF00FFFFFF0004733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04733AFF0473 3AFF04733AFF04733AFF04733AFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0004733A2D0F7941F689CCA9FF7FC8A2FF0E7941F604733A2DFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3A0C04743AE173BD97FE74C69CFF6CC396FF5CB386FE04743AE104733A0CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000474 3BAC4FA679FA93D3B2FF4BB67FFF42B279FF6BC296FF3B9C6AF904743AABFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0004733A65298B 58F6A2D8BCFF62BE8FFF4FB782FF45B37BFF1AA25CFF71C49AFF1D844FF50473 3A65FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0004733A2D0D7840F69ED4 B8FF7CCAA2FF5CBD8BFF53BB85FF37B173FF08A153FF2CAF6CFF6EC397FF0A77 3EF604733A2DFFFFFF00FFFFFF00FFFFFF0004733A0C04743AE183C5A3FE99D5 B6FF69C395FF5FC18FFF56C18AFF1CAE63FF0AAA58FF0BAB59FF4DC286FF55B5 84FE04753BE104733A0CFFFFFF00FFFFFF0004743BAC57A97FF9B0DFC7FF75C7 9DFF6AC697FF60C692FF41BE7EFF0CB05CFF0DB35EFF0DB45FFF0FB460FF6ACF 9BFF359D68F804753BABFFFFFF0004733A65288B58F6B3DFC9FFB9E2CDFFB5E2 CBFFB1E2C9FF5FC992FF18B665FF0EB861FF0FBB64FF83DCAFFF83DCAFFF82DB AEFF7CD5A8FF19844DF504733A6504753BC504733AFF04733AFF04733AFF0477 3CF7AFE3C8FF47C384FF0EB861FF10BE66FF11C369FF84E1B2FF057A3EF70473 3AFF04733AFF04733AFF04763BC5FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFADE2C7FF2EBD74FF0FBA63FF11C168FF13C86CFF85E6B5FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFA9E1C5FF1BB668FF0EB962FF10C067FF12C66BFF84E3B3FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFA5DEC1FF14B161FF0DB560FF0FBB63FF10BF66FF83DEB0FF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000473 3AFFA1DCBEFF81D3A9FF81D5AAFF81D7ACFF82D9ADFF82DAADFF04733AFFFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000474 3AE804733AFF04733AFF04733AFF04733AFF04733AFF04733AFF04753BE8FFFF FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000002839 DD2D2A3EDD982C3FDDE3283BDDF9283BDDF92C3FDDE32A3EDD97293ADC2C0000 000000000000000000000000000000000000000000002449DB072B3BD59F3445 D8F57688E9FD9EB2F2FFB0C4F7FFB0C4F7FF9EB2F2FF7587E8FD3445D8F52A3C D69D2B2BD5060000000000000000000000002424DB072B37D0C95460DDF69AA7 F1FF8599EDFF718BEDFF6785ECFF6785ECFF718BEDFF8599EDFF9AA7F0FF535F DCF62A37D0C82B2BD50600000000000000002B33CA9F4F57D6F68992ECFF5765 D2FF4756BDFF576BE1FF5A71E8FF5A71E8FF576BE2FF4757BEFF5764D2FF8891 ECFF4E55D5F62C35C99B000000002D2DC12D3337C6F57C83E6FF555FE1FF777F D8FFC4C7E8FF4853BDFF4E5CDEFF4E5DDFFF4652BEFFC1C4E7FF7B83D9FF5560 E1FF7D83E6FF3337C6F52A2FC42B2D2FBC985356D2FC6167E0FF474FDCFFC7CA F5FFFFFFFFFFCACDEAFF444DBAFF444DBAFFCACDEAFFFFFFFFFFC7CAF5FF474F DCFF6167E0FF5254D0FC2E2EBD962E2CB6E45C5FD7FF494DD9FF4348D8FF4A51 DAFFCBCDF5FFFFFFFFFFCBCDEAFFCBCDEAFFFFFFFFFFCDCFF5FF4B51DAFF4348 D8FF4A4ED9FF5D5ED7FF2D2CB6E22E28AFF85757D6FF3F41D3FF3E41D4FF4044 D6FF4549D2FFC9CAEAFFFFFFFFFFFFFFFFFFCBCCEBFF464AD2FF4044D6FF3E41 D4FF3F41D3FF5757D6FF2E28AFF82E25A9F84C4AD2FF3B3ACFFF3A3AD1FF393A CCFF3739B1FFC7C8E8FFFFFFFFFFFFFFFFFFCACAE9FF383AB1FF393ACCFF3A3A D1FF3B3ACFFF4D4AD2FF2D25A9F72F23A3E3443EC7FF3A36CDFF3633CDFF3634 B2FFC5C4E6FFFFFFFFFFCCCBF3FFCCCBF3FFFFFFFFFFC6C6E7FF3634B2FF3633 CDFF3A36CDFF443EC7FF2F23A4E22F209D973B30B5FC3B36CBFF312CC9FFC0BE EDFFFFFFFFFFC8C7F1FF3B37CDFF3B37CDFFC8C7F1FFFFFFFFFFC0BEEDFF312C C9FF3B36CBFF3B30B4FC30219C952E1D972C331F97F54135C2FF3228C4FF6761 D5FFBFBDEEFF3630C9FF2F28C7FF2F28C7FF3630C9FFBFBDEEFF6761D5FF3329 C4FF4135C1FF341F98F5311E922A00000000321B909E39229BF54331B9FF3725 B8FF3322B9FF3323BAFF3223BBFF3223BBFF3323BAFF3322B9FF3725B8FF4331 B9FF3A239BF5321B919900000000000000002B2B8006351889C73F2395F55238 B1FF4930B1FF3F25AEFF3B20ADFF3B20ADFF3F25AEFF4930B1FF5138B0FF3E24 95F5341889C6330099050000000000000000000000002B0080063515829B3719 84F64D2D99FC5A3BA6FF6143AEFF6143AEFF5A3BA6FF4D2D99FC371984F53516 8299330099050000000000000000000000000000000000000000000000003512 7D2B36137C9636137CE235137BF835137BF836137DE137137B953712792A0000 0000000000000000000000000000454B49FF454B49FF454B49FF454B49FF454B 49FF454B49FF6C7170F6FFFFFF00FFFFFF001616A7A20B0BB9F2FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF484D4BFF1D1D9C170F0FB4E31717F9FF0101C6FFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF009A9B9BFF9A9B9BFF9A9B9BFF9A9B9BFF9A9B 9BFFFFFFFFFF393C66FF0707BFFB4D4DFCFFB7B7FFFF0101C6FFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF6B6BC7FF0404E3FF7F7FFFFFABABFFFFBCBCFFFF0101C6FFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF009A9B9BFF9A9B9BFF9A9B9BFF8F909BFF1E1E B1FF1E1EF9FF9B9BFFFF9191FFFF6F6FFFFFB6B6FFFF0303CAFF0101C6FF0101 C6FF0101C6FF0101C6FF0606C2FDFFFFFFFFFFFFFFFFB6B6E1FF0B0BC0FF4D4D FDFFA1A1FFFF7474FFFF6363FFFF6565FFFFB0B0FFFFB0B0FFFFAFAFFFFFADAD FFFFABABFFFFA8A8FFFF0101C6FF9A9B9BFF4647A3FF0404ECFF7676FFFF8F8F FFFF5E5EFFFF5B5BFFFF5F5FFFFF5F5FFFFF5E5EFFFF5C5CFFFF5B5BFFFF5858 FFFF5454FFFFA3A3FFFF0101C6FF5252AAFF1D1DF9FF8888FFFF7272FFFF4C4C FFFF5252FFFF5656FFFF5858FFFF4F4FFFFF4141FFFF3030FFFF2C2CFFFF3333 FFFF3B3BFFFF9C9CFFFF0101C6FF3B3B93FF1313F8FF7777FFFF5E5EFFFF3434 FFFF2F2FFFFF2727FFFF1D1DFFFF1818FFFF1212FFFF0B0BFFFF0707FFFF0707 FFFF0707FFFF7E7EFFFF0101C6FFFFFFFFFF6B6BC7FF0404DFFF5C5CFFFF7373 FFFF3030FFFF2525FFFF2222FFFF1D1DFFFF1616FFFF0F0FFFFF0808FFFF0707 FFFF0707FFFF7E7EFFFF0101C6FF9A9B9BFF9A9B9BFF71729DFF0909C2FF3737 FCFF8585FFFF4A4AFFFF2727FFFF2020FFFF8888FFFF8484FFFF8080FFFF7E7E FFFF7E7EFFFF7E7EFFFF0101C6FFFFFFFFFFFFFFFFFFFFFFFFFFEBEBF6FF2929 BEFF0E0EF8FF8080FFFF6565FFFF2525FFFF8888FFFF0303CDFF0101C6FF0101 C6FF0101C6FF0101C6FF0606C2FD454B49FF454B49FF454B49FF454B49FF454B 49FF282A86FF0404D6FF5C5CFFFF7979FFFF8A8AFFFF0101C6FFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF001B1BA1520707C3FB2E2EFBFF8383FFFF0101C6FFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF001D1D9C171010B6E30707F8FF0101C6FFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001616A7A20B0BB9F2FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000B0BB9F21616A7A2FFFFFF00FFFFFF006C7170F6454B49FF454B49FF454B 49FF454B49FF454B49FF454B49FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000101C6FF1717F9FF0F0FB4E31D1D9C17484D4BFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000101C6FFB7B7FFFF4D4DFCFF0707BFFB393C66FFFFFFFFFF9A9B9BFF9A9B 9BFF9A9B9BFF9A9B9BFF9A9B9BFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000101C6FFBCBCFFFFABABFFFF7F7FFFFF0404E3FF6B6BC7FFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF0606C2FD0101C6FF0101C6FF0101C6FF0101 C6FF0303CAFFB6B6FFFF6F6FFFFF9191FFFF9B9BFFFF1E1EF9FF1E1EB1FF8F90 9BFF9A9B9BFF9A9B9BFF9A9B9BFF0101C6FFA8A8FFFFABABFFFFADADFFFFAFAF FFFFB0B0FFFFB0B0FFFF6565FFFF6363FFFF7474FFFFA1A1FFFF4D4DFDFF0B0B C0FFB6B6E1FFFFFFFFFFFFFFFFFF0101C6FFA3A3FFFF5454FFFF5858FFFF5B5B FFFF5C5CFFFF5E5EFFFF5F5FFFFF5F5FFFFF5B5BFFFF5E5EFFFF8F8FFFFF7676 FFFF0404ECFF4647A3FF9A9B9BFF0101C6FF9C9CFFFF3B3BFFFF3333FFFF2C2C FFFF3030FFFF4141FFFF4F4FFFFF5858FFFF5656FFFF5252FFFF4C4CFFFF7272 FFFF8888FFFF1D1DF9FF5252AAFF0101C6FF7E7EFFFF0707FFFF0707FFFF0707 FFFF0B0BFFFF1212FFFF1818FFFF1D1DFFFF2727FFFF2F2FFFFF3434FFFF5E5E FFFF7777FFFF1313F8FF3B3B93FF0101C6FF7E7EFFFF0707FFFF0707FFFF0808 FFFF0F0FFFFF1616FFFF1D1DFFFF2222FFFF2525FFFF3030FFFF7373FFFF5C5C FFFF0404DFFF6B6BC7FFFFFFFFFF0101C6FF7E7EFFFF7E7EFFFF7E7EFFFF8080 FFFF8484FFFF8888FFFF2020FFFF2727FFFF4A4AFFFF8585FFFF3737FCFF0909 C2FF71729DFF9A9B9BFF9A9B9BFF0606C2FD0101C6FF0101C6FF0101C6FF0101 C6FF0303CDFF8888FFFF2525FFFF6565FFFF8080FFFF0E0EF8FF2929BEFFEBEB F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000101C6FF8A8AFFFF7979FFFF5C5CFFFF0404D6FF282A86FF454B49FF454B 49FF454B49FF454B49FF454B49FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000101C6FF8383FFFF2E2EFBFF0707C3FB1B1BA152FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000101C6FF0707F8FF1010B6E31D1D9C17FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000B0BB9F21616A7A2FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008888884B878787E4878787FF8787 87FF878787FF878787FF878787FF878787FF878787FF878787FF878787FF8787 87FF878787E38686864A0000000000000000878787E3E9E9E9D1F2F2F2FFF2F2 F2FFF0F0F0FFEEEEEEFFECECECFFEAEAEAFFE7E7E7FFE5E5E5FFE3E3E3FFE1E1 E1FFD8D8D8D0878787E20000000000000000878787FFF2F2F2FFD2D2D2FFD2D2 D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2 D2FFDDDDDDFF878787FF0000000000000000878787FFF2F2F2FFD9D9D9FFD9D9 D9FFD9D9D9FFD9D9D9FFD9D9D9FFD6D6D6FF4D4D4DFFD0D0D0FFD9D9D9FFD9D9 D9FFDBDBDBFF878787FF0000000000000000878787FFF0F0F0FFE0E0E0FFE0E0 E0FFE0E0E0FFE0E0E0FFE0E0E0FFB2B2B2FF8D8D8DFFD5D5D5FFE0E0E0FFE0E0 E0FFD9D9D9FF878787FF0000000000000000878787FFEEEEEEFFE7E7E7FFE7E7 E7FFE7E7E7FFE7E7E7FF8C8C8CFF656565FF929292FF3F3F3FFFE7E7E7FFE7E7 E7FFD7D7D7FF878787FF0000000000000000878787FFECECECFFEEEEEEFFEEEE EEFFEEEEEEFFEEEEEEFFDFDFDFFF9A9A9AFF707070FF2C2C2CFFEEEEEEFFEEEE EEFFD4D4D4FF878787FF0000000000000000878787FFEAEAEAFFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FF595959FFA4A4A4FFE8E8E8FF333333FFF5F5F5FFF5F5 F5FFD2D2D2FF878787FF0000000000000000878787FFE7E7E7FFF9F9F9FFF9F9 F9FFF9F9F9FFF9F9F9FF787878FF636363FF6A6A6AFF2E2E2EFFF5F5F5FFF9F9 F9FFD0D0D0FF878787FF0000000000000000878787FFE5E5E5FFF9F9F9FFF9F9 F9FFF9F9F9FFF9F9F9FFF9F9F9FFEBEBEBFFF8F8F8FFF9F9F9FFF9F9F9FFF9F9 F9FFCECECEFF878787FF0000000000000000878787FFE3E3E3FFB3B3B3FFB3B3 B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3 B3FFCCCCCCFF878787FF0000000000000000878787FFE1E1E1FFB3B3B3FFB3B3 B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3B3FFB3B3 B3FFCCCCCCFF878787FF0000000000000000878787E3DADADAD0DDDDDDFFDBDB DBFFD9D9D9FFD7D7D7FFD4D4D4FFD2D2D2FFD0D0D0FFCECECEFFCCCCCCFFCCCC CCFFCACACAD0878787E200000000000000008686864A878787E3878787FF8787 87FF878787FF878787FF878787FF878787FF878787FF878787FF878787FF8787 87FF878787E28888884900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000 } end object ilViewerImages: TImageList Left = 280 Top = 120 end end doublecmd-1.1.22/src/dmcommondata.pas0000644000175000001440000001014514743153644016546 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- General icons loaded at launch based on screen resolution Copyright (C) 2009-2020 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit dmCommonData; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Dialogs; type { TdmComData } TdmComData = class(TDataModule) ilEditorImages: TImageList; ilViewerImages: TImageList; ImageList: TImageList; OpenDialog: TOpenDialog; SaveDialog: TSaveDialog; procedure DataModuleCreate(Sender: TObject); private procedure LoadImages(Images: TImageList; const ANames: array of String); public { public declarations } end; var dmComData: TdmComData; implementation uses LCLVersion, Graphics, uPixMapManager; {$R *.lfm} const ViewerNames: array[0..26] of String = ( 'view-refresh', 'go-previous', 'go-next', 'edit-copy', 'edit-cut', 'edit-delete', 'zoom-in', 'zoom-out', 'object-rotate-left', 'object-rotate-right', 'object-flip-horizontal', 'media-playback-pause', 'media-playback-start', 'media-skip-backward', 'media-skip-forward', 'image-crop', 'image-red-eye', 'draw-freehand', 'draw-rectangle', 'draw-ellipse', 'edit-undo', 'document-edit', 'view-fullscreen', 'draw-path', 'document-page-setup', 'view-restore', 'camera-photo' ); EditorNames: array[0..44] of String = ( 'document-new', 'document-open', 'document-save', 'document-save-as', 'document-properties', 'edit-cut', 'edit-copy', 'edit-paste', 'edit-undo', 'edit-redo', 'edit-find', 'edit-find-replace', 'application-exit', 'help-about', 'edit-delete', 'edit-select-all', 'go-jump', 'view-refresh', 'mr-config', 'mr-editor', 'mr-filename', 'mr-extension', 'mr-counter', 'mr-date', 'mr-time', 'mr-plugin', 'view-file', 'mr-pathtools', 'mr-rename', 'mr-clearfield', 'mr-presets', 'mr-savepreset', 'mr-deletepreset', 'mr-droppresets', 'document-save-alt', 'document-save-as-alt', 'go-next', 'go-bottom', 'go-down', 'go-up', 'go-top', 'process-stop', 'copy-right-to-left', 'copy-left-to-right', 'choose-encoding' ); { TdmComData } procedure TdmComData.DataModuleCreate(Sender: TObject); begin if Assigned(PixMapManager) then begin LoadImages(ilViewerImages, ViewerNames); LoadImages(ilEditorImages, EditorNames); end; end; procedure TdmComData.LoadImages(Images: TImageList; const ANames: array of String); var AName: String; ASize16, ASize24, ASize32: Integer; ABitmap16, ABitmap24, ABitmap32: TCustomBitmap; begin Images.Clear; ASize16:= 16; // AdjustIconSize(16, 96); ASize24:= 24; // AdjustIconSize(24, 96); ASize32:= 32; // AdjustIconSize(32, 96); Images.RegisterResolutions([ASize16, ASize24, ASize32]); for AName in ANames do begin ABitmap16:= PixMapManager.GetThemeIcon(AName, ASize16); if (ABitmap16 = nil) then ABitmap16:= TBitmap.Create; ABitmap24:= PixMapManager.GetThemeIcon(AName, ASize24); if (ABitmap24 = nil) then ABitmap24:= TBitmap.Create; ABitmap32:= PixMapManager.GetThemeIcon(AName, ASize32); if (ABitmap32 = nil) then ABitmap32:= TBitmap.Create; Images.AddMultipleResolutions([ABitmap16, ABitmap24, ABitmap32]); ABitmap16.Free; ABitmap24.Free; ABitmap32.Free; end; end; end. doublecmd-1.1.22/src/dmhelpmanager.lfm0000644000175000001440000000072614743153644016706 0ustar alexxusersobject dmHelpManager: TdmHelpManager OnCreate = DataModuleCreate OldCreateOrder = False Height = 300 HorizontalOffset = 369 VerticalOffset = 200 Width = 400 object HTMLHelpDatabase: THTMLHelpDatabase BaseURL = 'file://doc/en/' AutoRegister = True KeywordPrefix = 'en/' left = 64 top = 48 end object HTMLBrowserHelpViewer: THTMLBrowserHelpViewer BrowserParams = '%s' AutoRegister = True left = 104 top = 48 end end doublecmd-1.1.22/src/dmhelpmanager.pas0000644000175000001440000000762414743153644016717 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Help manager Copyright (C) 2008-2021 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit dmHelpManager; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Dialogs, LazHelpHTML; type { TdmHelpManager } TdmHelpManager = class(TDataModule) HTMLBrowserHelpViewer: THTMLBrowserHelpViewer; HTMLHelpDatabase: THTMLHelpDatabase; procedure DataModuleCreate(Sender: TObject); private { private declarations } public { public declarations } end; procedure ShowHelpForKeywordWithAnchor(const Keyword: String); var dmHelpMgr: TdmHelpManager; implementation {$R *.lfm} uses {$IFDEF MSWINDOWS} LCLIntf, uOSUtils, uFileProcs, {$ELSE} HelpIntfs, {$ENDIF} uGlobsPaths, uGlobs, DCStrUtils, DCOSUtils, StrUtils, DCClassesUtf8; {$IF DEFINED(MSWINDOWS)} procedure OpenURLWithAnchor(URL: String); var hFile:THandle; TempoFilenameWithTheLink: String; begin TempoFilenameWithTheLink:= GetTempFolderDeletableAtTheEnd + 'FileWithALink.html'; hFile:= mbFileCreate(TempoFilenameWithTheLink); if hFile <> feInvalidHandle then try FileWriteLn(hFile,''); FileWriteLn(hFile,''); // In case browser doesn't support auto-redirection, give a link to user. FileWriteLn(hFile,'
Click here for help
'); FileWriteLn(hFile,''); finally FileClose(hFile); end; if mbFileExists(TempoFilenameWithTheLink) then OpenURL(TempoFilenameWithTheLink); end; {$ENDIF} procedure ShowHelpForKeywordWithAnchor(const Keyword: String); {$IF DEFINED(MSWINDOWS)} begin OpenURLWithAnchor(dmHelpMgr.HTMLHelpDatabase.BaseURL + Keyword); end; {$ELSE} begin ShowHelpOrErrorForKeyword('', Keyword); end; {$ENDIF} { TdmHelpManager } procedure TdmHelpManager.DataModuleCreate(Sender: TObject); {$IFDEF MSWindows} var ABrowser, AParams: String; {$ENDIF} var ATranslations: TStringList; begin if NumCountChars('.', gPOFileName) < 2 then gHelpLang:= 'en' else begin gHelpLang:= ExtractDelimited(2, gPOFileName, ['.']); if not mbDirectoryExists(gpExePath + 'doc' + PathDelim + gHelpLang) then begin ATranslations:= TStringListEx.Create; try ATranslations.LoadFromFile(gpExePath + 'doublecmd.help'); if ATranslations.IndexOf(gHelpLang) < 0 then gHelpLang:= 'en'; except gHelpLang:= 'en'; end; ATranslations.Free; end; end; if mbDirectoryExists(gpExePath + 'doc' + PathDelim + gHelpLang) then HTMLHelpDatabase.BaseURL:= 'file://' + gpExePath + 'doc' + PathDelim + gHelpLang else begin HTMLHelpDatabase.BaseURL:= 'https://doublecmd.github.io/doc/' + gHelpLang; end; HTMLHelpDatabase.KeywordPrefix:= '/'; {$IFDEF MSWindows} // Lazarus issue #0021637. if FindDefaultBrowser(ABrowser, AParams) then begin HTMLBrowserHelpViewer.BrowserPath := ABrowser; HTMLBrowserHelpViewer.BrowserParams := StringReplace(AParams, '%s', '"%s"', [rfReplaceAll]); end; {$ENDIF} end; end. doublecmd-1.1.22/src/dmhigh.json0000644000175000001440000006730714743153644015545 0ustar alexxusers{Styles:[{Name:"Light",Highlighters:[{Name:"C++",Attributes:[{Name:"Assembler",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Illegal char",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Preprocessor",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"}]},{Name:"Cascading style sheets",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Measurement unit",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Selector",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"}]},{Name:"Diff File",Attributes:[{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Diff Added line",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"},{Name:"Diff Changed Line",Value:"$1FFFFFFF|$00800080|$1FFFFFFF|0|1|0|0"},{Name:"Diff Chunk Line Counts",Value:"$1FFFFFFF|$00800080|$1FFFFFFF|0|1|1|0"},{Name:"Diff Chunk Marker",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Diff Chunk New Line Count",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|1|0"},{Name:"Diff Chunk Original Line Count",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|1|0"},{Name:"Diff Context Line",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Diff New File",Value:"$00008000|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Diff Original File",Value:"$000000FF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Diff Removed Line",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Unknown word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|2|0"}]},{Name:"HTML document",Attributes:[{Name:"Asp",Value:"$0000FFFF|$00000000|$1FFFFFFF|0|1|0|0"},{Name:"CDATA",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"DOCTYPE",Value:"$0000FFFF|$00000000|$1FFFFFFF|0|1|1|0"},{Name:"Escape ampersand",Value:"$1FFFFFFF|$0000FF00|$1FFFFFFF|0|1|1|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$00FF0080|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Text",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Unknown word",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|1|0"},{Name:"Value",Value:"$1FFFFFFF|$00FF8000|$1FFFFFFF|0|1|0|0"}]},{Name:"INI file",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|2|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Section",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Text",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"Java",Attributes:[{Name:"Annotation",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Documentation",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Invalid symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"}]},{Name:"Lazarus Form definition",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"Lua Script",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Function",Value:"$1FFFFFFF|$00C05000|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800080|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00000080|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"}]},{Name:"MS-DOS batch language",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"}]},{Name:"ObjectPascal",Attributes:[{Name:"Assembler",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"},{Name:"Case label",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Directive",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|1|0"},{Name:"IDE Directive",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Procedure header name",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"}]},{Name:"PHP",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Invalid symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"Perl",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Illegal char",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Operator",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Pragma",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"}]},{Name:"Python",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00808080|$1FFFFFFF|0|1|2|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Documentation",Value:"$1FFFFFFF|$00808000|$1FFFFFFF|0|1|0|0"},{Name:"Float",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Hexadecimal",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Non-reserved keyword",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|1|0"},{Name:"Number",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Octal",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"SyntaxError",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"System functions and variables",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"}]},{Name:"SQL",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Data type",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Default packages",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Exception",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|2|0"},{Name:"Function",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word (PL/SQL)",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"SQL*Plus command",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Table Name",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"TeX",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00808000|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Math Mode",Value:"$1FFFFFFF|$00008080|$1FFFFFFF|0|1|1|0"},{Name:"Round Bracket",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$00FFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Square Bracket",Value:"$1FFFFFFF|$00800080|$1FFFFFFF|0|1|0|0"},{Name:"TeX Command",Value:"$00FFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Text",Value:"$1FFFFFFF|$00000000|$1FFFFFFF|0|1|0|0"}]},{Name:"UNIX Shell Script",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|1|0"},{Name:"Second reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00000080|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$00800080|$1FFFFFFF|0|1|0|0"}]},{Name:"Visual Basic",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"}]},{Name:"XML document",Attributes:[{Name:"Attribute Name",Value:"$1FFFFFFF|$00000080|$1FFFFFFF|0|1|0|0"},{Name:"Attribute Value",Value:"$1FFFFFFF|$00800000|$1FFFFFFF|0|1|1|0"},{Name:"CDATA Section",Value:"$1FFFFFFF|$00008080|$1FFFFFFF|0|1|2|0"},{Name:"Comment",Value:"$00C0C0C0|$00808080|$1FFFFFFF|0|1|3|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"DOCTYPE Section",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|2|0"},{Name:"Element Name",Value:"$1FFFFFFF|$00000080|$1FFFFFFF|0|1|1|0"},{Name:"Entity Reference",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Namespace Attribute Name",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|0|0"},{Name:"Namespace Attribute Value",Value:"$1FFFFFFF|$000000FF|$1FFFFFFF|0|1|1|0"},{Name:"Processing Instruction",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|0|0"},{Name:"Text",Value:"$1FFFFFFF|$00000000|$1FFFFFFF|0|1|1|0"},{Name:"Whitespace",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"po language files",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|2|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Flags",Value:"$1FFFFFFF|$00808000|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$00008000|$1FFFFFFF|0|1|1|0"},{Name:"Key",Value:"$1FFFFFFF|$00FF0000|$1FFFFFFF|0|1|1|0"},{Name:"Previous value",Value:"$1FFFFFFF|$00008080|$1FFFFFFF|0|1|2|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF00FF|$1FFFFFFF|0|1|0|0"},{Name:"Text",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]}]},{Name:"Dark",Highlighters:[{Name:"C++",Attributes:[{Name:"Assembler",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Illegal char",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Preprocessor",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$80000005|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$00898BB9|$1FFFFFFF|0|1|0|0"}]},{Name:"Cascading style sheets",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Measurement unit",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00DA9396|$1FFFFFFF|0|1|0|0"},{Name:"Selector",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"}]},{Name:"Diff File",Attributes:[{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Diff Added line",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"},{Name:"Diff Changed Line",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Diff Chunk Line Counts",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Diff Chunk Marker",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Diff Chunk New Line Count",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|1|0"},{Name:"Diff Chunk Original Line Count",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|1|0"},{Name:"Diff Context Line",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Diff New File",Value:"$0076E56C|$80000011|$1FFFFFFF|0|1|1|0"},{Name:"Diff Original File",Value:"$006C6CE5|$80000017|$1FFFFFFF|0|1|1|0"},{Name:"Diff Removed Line",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Unknown word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|2|0"}]},{Name:"HTML document",Attributes:[{Name:"Asp",Value:"$0000FFFF|$00000000|$1FFFFFFF|0|1|0|0"},{Name:"CDATA",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"DOCTYPE",Value:"$0000FFFF|$00000000|$1FFFFFFF|0|1|1|0"},{Name:"Escape ampersand",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|1|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$00D15894|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Text",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Unknown word",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|1|0"},{Name:"Value",Value:"$1FFFFFFF|$00FBA249|$1FFFFFFF|0|1|0|0"}]},{Name:"INI file",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|2|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$00D4914E|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Section",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"},{Name:"Text",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"Java",Attributes:[{Name:"Annotation",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$00FF8000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Documentation",Value:"$1FFFFFFF|$00FF8000|$1FFFFFFF|0|1|1|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Invalid symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00C28789|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$80000005|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF8000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"}]},{Name:"Lazarus Form definition",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00FF8000|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00FF8000|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"Lua Script",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Function",Value:"$1FFFFFFF|$00D5A6A6|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00AC95B3|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$00ECA761|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00837189|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"}]},{Name:"MS-DOS batch language",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Key",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"}]},{Name:"ObjectPascal",Attributes:[{Name:"Assembler",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"},{Name:"Case label",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Directive",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|1|0"},{Name:"IDE Directive",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Procedure header name",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"}]},{Name:"PHP",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Invalid symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"Perl",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Illegal char",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Operator",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Pragma",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$80000005|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"}]},{Name:"Python",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00808080|$1FFFFFFF|0|1|2|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Documentation",Value:"$1FFFFFFF|$00808000|$1FFFFFFF|0|1|0|0"},{Name:"Float",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Hexadecimal",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Non-reserved keyword",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|1|0"},{Name:"Number",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Octal",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"SyntaxError",Value:"$1FFFFFFF|$006166C0|$1FFFFFFF|0|1|0|0"},{Name:"System functions and variables",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"}]},{Name:"SQL",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Data type",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Default packages",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Exception",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|2|0"},{Name:"Function",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Reserved word (PL/SQL)",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"SQL*Plus command",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$004D4DAA|$1FFFFFFF|0|1|0|0"},{Name:"Table Name",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"TeX",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00F0CAA6|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Math Mode",Value:"$1FFFFFFF|$0081D2D2|$1FFFFFFF|0|1|1|0"},{Name:"Round Bracket",Value:"$1FFFFFFF|$006F6F98|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$8000001D|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Square Bracket",Value:"$1FFFFFFF|$00AC95B3|$1FFFFFFF|0|1|0|0"},{Name:"TeX Command",Value:"$00F0CAA6|$00F0CAA6|$1FFFFFFF|0|1|1|0"},{Name:"Text",Value:"$1FFFFFFF|$00C0C0C0|$1FFFFFFF|0|1|0|0"}]},{Name:"UNIX Shell Script",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|0|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|1|0"},{Name:"Second reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00837189|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$004D4DAA|$1FFFFFFF|0|1|0|0"},{Name:"Variable",Value:"$1FFFFFFF|$00AC95B3|$1FFFFFFF|0|1|0|0"}]},{Name:"Visual Basic",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"Number",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|0|0"},{Name:"Reserved word",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$004D4DAA|$1FFFFFFF|0|1|0|0"}]},{Name:"XML document",Attributes:[{Name:"Attribute Name",Value:"$1FFFFFFF|$00817285|$1FFFFFFF|0|1|0|0"},{Name:"Attribute Value",Value:"$1FFFFFFF|$00E8BCBC|$1FFFFFFF|0|1|1|0"},{Name:"CDATA Section",Value:"$1FFFFFFF|$00008080|$1FFFFFFF|0|1|2|0"},{Name:"Comment",Value:"$1FFFFFFF|$00C0C0C0|$1FFFFFFF|0|1|3|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"DOCTYPE Section",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|2|0"},{Name:"Element Name",Value:"$1FFFFFFF|$00837189|$1FFFFFFF|0|1|1|0"},{Name:"Entity Reference",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|1|0"},{Name:"Namespace Attribute Name",Value:"$1FFFFFFF|$004D4DAA|$1FFFFFFF|0|1|0|0"},{Name:"Namespace Attribute Value",Value:"$1FFFFFFF|$004D4DAA|$1FFFFFFF|0|1|1|0"},{Name:"Processing Instruction",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Symbol",Value:"$1FFFFFFF|$00C09B61|$1FFFFFFF|0|1|0|0"},{Name:"Text",Value:"$1FFFFFFF|$00FFFFFF|$1FFFFFFF|0|1|1|0"},{Name:"Whitespace",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]},{Name:"po language files",Attributes:[{Name:"Comment",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|2|0"},{Name:"Default text",Value:"$80000005|$80000008|$1FFFFFFF|0|1|0|0"},{Name:"Flags",Value:"$1FFFFFFF|$00808000|$1FFFFFFF|0|1|0|0"},{Name:"Identifier",Value:"$1FFFFFFF|$008AD277|$1FFFFFFF|0|1|1|0"},{Name:"Key",Value:"$1FFFFFFF|$00E86363|$1FFFFFFF|0|1|1|0"},{Name:"Previous value",Value:"$1FFFFFFF|$00008080|$1FFFFFFF|0|1|2|0"},{Name:"Space",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"},{Name:"String",Value:"$1FFFFFFF|$00AF77D2|$1FFFFFFF|0|1|0|0"},{Name:"Text",Value:"$1FFFFFFF|$1FFFFFFF|$1FFFFFFF|0|1|0|0"}]}]}]} doublecmd-1.1.22/src/dmhigh.pas0000644000175000001440000006434114743153644015352 0ustar alexxusersunit dmHigh; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, SynEdit, DCStringHashListUtf8, LCLVersion, SynEditHighlighter, SynHighlighterJava, SynHighlighterXML, SynHighlighterLFM, SynHighlighterPHP, SynHighlighterSQL, SynHighlighterCss, SynHighlighterPython, SynHighlighterVB, SynHighlighterLua, SynUniHighlighter, uHighlighters, uColors, fpJson; const HighlighterConfig = 'highlighters.xml'; type { TdmHighl } TdmHighl = class(TComponent) private FTemp: Boolean; procedure LoadColors(AConfig: TJSONObject); procedure SaveColors(AConfig: TJSONObject); procedure LoadUniColors(AConfig: TJSONObject); procedure SaveUniColors(AConfig: TJSONObject); private procedure CreateHighlighters; procedure LoadUniHighlighters; function GetSyn(Index: Integer): TSynCustomHighlighter; function GetSyn(AClass: TSynCustomHighlighterClass): TSynCustomHighlighter; procedure CopyHighlighter(SourceHighlighter, TargetHighlighter: TSynCustomHighlighter); public SynHighlighterList: TStringList; SynHighlighterHashList: TStringHashListUtf8; public constructor Create(AOwner: TComponent; ATemp: Boolean); overload; destructor Destroy; override; procedure Assign(Source: TPersistent); override; function Clone: TdmHighl; function GetHighlighter(SynEdit: TCustomSynEdit; const sExtension: string): TSynCustomHighlighter; procedure SetHighlighter(SynEdit: TCustomSynEdit; Highlighter: TSynCustomHighlighter); property Highlighters[Index: Integer]: TSynCustomHighlighter read GetSyn; property SynPlainTextHighlighter: TSynCustomHighlighter index 0 read GetSyn; end; { THighlighters } THighlighters = class private FStyle: Integer; FStyles: array[0..Pred(THEME_COUNT)] of TJSONObject; private procedure LoadColors; overload; procedure SaveColors; overload; procedure LoadDefaults(const AKey: String; AConfig: TJSONObject); overload; public constructor Create; destructor Destroy; override; procedure UpdateStyle; procedure LoadDefaults; overload; procedure Load(const FileName: String); overload; procedure Save(const FileName: String); overload; procedure LoadColors(AConfig: TJSONObject); overload; procedure SaveColors(AConfig: TJSONObject); overload; end; var dmHighl: TdmHighl; gHighlighters: THighlighters; implementation uses Graphics, SynEditTypes, SynUniClasses, FileUtil, uHighlighterProcs, DCXmlConfig, LCLType, DCJsonConfig, uGlobsPaths, DCClassesUtf8, DCOSUtils, DCStrUtils, uLng, uGlobs, uSysFolders, SynUniRules; const ConfigVersion = 2; const DEFAULT_HIGHLIGHTERS: array[0..19] of TSynCustomHighlighterClass = ( TSynPlainTextHighlighter, TSynXMLSyn, TSynPerlSynEx, TSynPythonSyn, TSynUNIXShellScriptSynEx, TSynBatSynEx, TSynCppSynEx, TSynCssSyn, TSynDiffSynEx, TSynHTMLSynEx, TSynIniSynEx, TSynJavaSyn, TSynLFMSyn, TSynPasSynEx, TSynPHPSyn, TSynPoSynEx, TSynSQLSyn, TSynTeXSynEx, TSynVBSyn, TSynLuaSyn ); function SynHighlighterSortCompare(List: TStringList; Index1, Index2: Integer): Integer; begin if CompareStr(List[Index1], rsSynLangPlainText) = 0 then Result:= -1 else if CompareStr(List[Index2], rsSynLangPlainText) = 0 then Result:= 1 else Result:= CompareStr(List[Index1], List[Index2]); end; { TdmHighl } procedure TdmHighl.LoadColors(AConfig: TJSONObject); var I, J, K: Integer; AName, AValue: String; AValues: TStringArray; AList, Attributes: TJSONArray; AItem, AttributeNode: TJSONObject; Highlighter: TSynCustomHighlighter; Attribute: TSynHighlighterAttributes; begin if AConfig.Find('Highlighters', AList) then begin for I:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[I]; AName:= AItem.Get('Name', EmptyStr); Highlighter:= TSynCustomHighlighter(SynHighlighterHashList.Data[AName]); if Assigned(Highlighter) and (not (Highlighter is TSynUniSyn)) then begin Attributes:= AItem.Get('Attributes', TJSONArray(nil)); if Assigned(Attributes) and (Attributes.Count > 0) then begin for J:= 0 to Attributes.Count - 1 do begin AttributeNode:= Attributes.Objects[J]; AName:= AttributeNode.Get('Name', EmptyStr); AValue:= AttributeNode.Get('Value', EmptyStr); AValues:= AValue.Split(['|'], TStringSplitOptions.ExcludeEmpty); if (Length(AName) = 0) or (Length(AValues) <> 7) then Continue; for K:= 0 to Highlighter.AttrCount - 1 do begin Attribute:= Highlighter.Attribute[K]; if SameText(Attribute.StoredName, AName) then begin Attribute.Background := TColor(StrToIntDef(AValues[0], Integer(Attribute.Background))); Attribute.Foreground := TColor(StrToIntDef(AValues[1], Integer(Attribute.Foreground))); Attribute.FrameColor := TColor(StrToIntDef(AValues[2], Integer(Attribute.FrameColor))); Attribute.FrameStyle := TSynLineStyle(StrToIntDef(AValues[3], Integer(Attribute.FrameStyle))); Attribute.FrameEdges := TSynFrameEdges(StrToIntDef(AValues[4], Integer(Attribute.FrameEdges))); Attribute.IntegerStyle := StrToIntDef(AValues[5], Attribute.IntegerStyle); Attribute.IntegerStyleMask := StrToIntDef(AValues[6], Attribute.IntegerStyleMask); Break; end; end; end; end; end; end; end; end; procedure TdmHighl.SaveColors(AConfig: TJSONObject); var I, J: Integer; AValue: String; AttributeNode: TJSONObject; HighlighterNode: TJSONObject; AList, Attributes: TJSONArray; Highlighter: TSynCustomHighlighter; Attribute: TSynHighlighterAttributes; begin if AConfig.Find('Highlighters', AList) then AList.Clear else begin AList:= TJSONArray.Create; AConfig.Add('Highlighters', AList); end; for I := 0 to SynHighlighterList.Count - 1 do begin if SynHighlighterList.Objects[I] is TSynUniSyn then Continue; Highlighter:= TSynCustomHighlighter(SynHighlighterList.Objects[I]); HighlighterNode:= TJSONObject.Create; HighlighterNode.Add('Name', Highlighter.LanguageName); Attributes:= TJSONArray.Create; for J:= 0 to Highlighter.AttrCount - 1 do begin Attribute:= Highlighter.Attribute[J]; AttributeNode:= TJSONObject.Create; AttributeNode.Add('Name', Attribute.StoredName); AValue:= '$' + HexStr(Attribute.Background, 8) + '|' + '$' + HexStr(Attribute.Foreground, 8) + '|' + '$' + HexStr(Attribute.FrameColor, 8) + '|' + IntToStr(Integer(Attribute.FrameStyle)) + '|' + IntToStr(Integer(Attribute.FrameEdges)) + '|' + IntToStr(Attribute.IntegerStyle) + '|' + IntToStr(Attribute.IntegerStyleMask); AttributeNode.Add('Value', AValue); Attributes.Add(AttributeNode); end; HighlighterNode.Add('Attributes', Attributes); AList.Add(HighlighterNode); end; end; procedure TdmHighl.LoadUniColors(AConfig: TJSONObject); var I: Integer; AName: String; AList: TJSONArray; AItem: TJSONObject; ARanges: TJSONArray; Highlighter: TSynCustomHighlighter; function LoadRule(AList: TJSONArray; SymbRule: TSynRule): TJSONObject; var J: Integer; AValue: String; begin for J:= 0 to AList.Count - 1 do begin Result:= AList.Objects[J]; AName:= Result.Get('Name', EmptyStr); if SameStr(AName, SymbRule.Name) then begin AValue:= Result.Get('Attributes', EmptyStr); if Length(AValue) > 0 then begin SymbRule.Attribs.LoadFromString(AValue); end; Exit; end; end; Result:= nil; end; procedure LoadRange(ARanges: TJSONArray; ARange: TSynRange); var Index: Integer; AList: TJSONArray; ARule: TJSONObject; begin ARule:= LoadRule(ARanges, ARange); if (ARule = nil) then Exit; if (ARange.SetCount > 0) then begin AList:= ARule.Get('Sets', TJSONArray(nil)); if Assigned(AList) and (AList.Count > 0) then begin for Index:= 0 to ARange.SetCount - 1 do begin LoadRule(AList, ARange.Sets[Index]); end; end; end; if (ARange.KeyListCount > 0) then begin AList:= ARule.Get('KeyLists', TJSONArray(nil)); if Assigned(AList) and (AList.Count > 0) then begin for Index:= 0 to ARange.KeyListCount - 1 do begin LoadRule(AList, ARange.KeyLists[Index]); end; end; end; if (ARange.RangeCount > 0) then begin AList:= ARule.Get('Ranges', TJSONArray(nil)); if Assigned(AList) and (AList.Count > 0) then begin for Index:= 0 to ARange.RangeCount - 1 do begin LoadRange(AList, ARange.Ranges[Index]); end; end; end; end; begin if AConfig.Find('UniHighlighters', AList) then begin for I:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[I]; AName:= AItem.Get('Name', EmptyStr); Highlighter:= TSynCustomHighlighter(SynHighlighterHashList.Data[AName]); if Assigned(Highlighter) and (Highlighter is TSynUniSyn) then begin with TSynUniSyn(Highlighter) do begin ARanges:= AItem.Get('Ranges', TJSONArray(nil)); if Assigned(ARanges) and (ARanges.Count > 0) then begin LoadRange(ARanges, MainRules); end; end; end; end; end; end; procedure TdmHighl.SaveUniColors(AConfig: TJSONObject); var I: Integer; SynUniSyn: TSynUniSyn; procedure SaveRule(ARules: TJSONArray; SymbRule: TSynRule); var ARule: TJSONObject; begin ARule:= TJSONObject.Create; ARule.Add('Name', SymbRule.Name); ARule.Add('Attributes', SymbRule.Attribs.ToString); ARules.Add(ARule); end; procedure SaveRange(ARules: TJSONArray; ARange: TSynRange); var Index: Integer; ARule: TJSONObject; Sets, KeyLists, Ranges: TJSONArray; begin ARule:= TJSONObject.Create; ARule.Add('Name', ARange.Name); ARule.Add('Attributes', ARange.Attribs.ToString); if (ARange.SetCount > 0) then begin Sets:= TJSONArray.Create; for Index:= 0 to ARange.SetCount - 1 do begin SaveRule(Sets, ARange.Sets[Index]); end; ARule.Add('Sets', Sets); end; if (ARange.KeyListCount > 0) then begin KeyLists:= TJSONArray.Create; for Index:= 0 to ARange.KeyListCount - 1 do begin SaveRule(KeyLists, ARange.KeyLists[Index]); end; ARule.Add('KeyLists', KeyLists); end; if (ARange.RangeCount > 0) then begin Ranges:= TJSONArray.Create; for Index:= 0 to ARange.RangeCount - 1 do begin SaveRange(Ranges, ARange.Ranges[Index]); end; ARule.Add('Ranges', Ranges); end; ARules.Add(ARule); end; procedure SaveHighlighter(AList: TJSONArray); var AItem: TJSONObject; ARules: TJSONArray; begin AItem:= TJSONObject.Create; AItem.Add('Name', SynUniSyn.Info.General.Name); ARules:= TJSONArray.Create; SaveRange(ARules, SynUniSyn.MainRules); AItem.Add('Ranges', ARules); AList.Add(AItem); end; var AList: TJSONArray; begin if AConfig.Find('UniHighlighters', AList) then AList.Clear else begin AList:= TJSONArray.Create; AConfig.Add('UniHighlighters', AList); end; for I := 0 to SynHighlighterList.Count - 1 do begin if SynHighlighterList.Objects[I] is TSynUniSyn then begin SynUniSyn:= TSynUniSyn(SynHighlighterList.Objects[I]); //if SynUniSyn.Tag < 0 then begin SaveHighlighter(AList); SynUniSyn.Tag:= 0; end; end; end; end; procedure TdmHighl.LoadUniHighlighters; var AName: String; I, Index: Integer; AList: TStringList; AFileName: String = ''; ACache: TStringListEx; HighLighter: TSynCustomHighlighter; begin ACache:= TStringListEx.Create; ACache.CaseSensitive:= FileNameCaseSensitive; if not gUseConfigInProgramDir then begin AFileName:= IncludeTrailingBackslash(GetAppDataDir) + 'highlighters' + ';'; end; AList:= FindAllFiles(AFileName + gpHighPath, '*.hgl'); for I:= 0 to AList.Count - 1 do begin AFileName:= ExtractFileName(AList[I]); if ACache.IndexOf(AFileName) < 0 then begin HighLighter:= TSynUniSyn.Create(Self); try TSynUniSyn(HighLighter).LoadFromFile(AList[I]); AName:= TSynUniSyn(HighLighter).Info.General.Name; Index:= SynHighlighterList.IndexOf(AName); if (Index < 0) then SynHighlighterList.AddObject(AName, Highlighter) else begin // Add duplicate external highlighter if SynHighlighterList.Objects[Index] is TSynUniSyn then begin AName:= AName + ' #' + IntToStr(I); SynHighlighterList.AddObject(AName, Highlighter); end // Replace built-in highlighter else begin SynHighlighterList.Objects[Index].Free; SynHighlighterList.Objects[Index]:= Highlighter; end; end; ACache.Add(AFileName); except FreeAndNil(HighLighter); end; end; end; AList.Free; ACache.Free; end; function TdmHighl.GetSyn(Index: Integer): TSynCustomHighlighter; begin Result:= TSynCustomHighlighter(SynHighlighterList.Objects[Index]); end; function TdmHighl.GetSyn(AClass: TSynCustomHighlighterClass): TSynCustomHighlighter; var Index: Integer; begin for Index:= 0 to SynHighlighterList.Count - 1 do begin if SynHighlighterList.Objects[Index] is AClass then Exit(TSynCustomHighlighter(SynHighlighterList.Objects[Index])); end; Result:= nil; end; procedure TdmHighl.CreateHighlighters; var I: Integer; Highlighter: TSynCustomHighlighter; begin for I:= 0 to High(DEFAULT_HIGHLIGHTERS) do begin {$PUSH}{$HINTS OFF}{$WARNINGS OFF} Highlighter:= DEFAULT_HIGHLIGHTERS[I].Create(Self); {$POP} Highlighter.Tag:= PtrInt(I <> 0); SynHighlighterList.AddObject(HighLighter.LanguageName, HighLighter); end; LoadUniHighlighters; for I:= 0 to SynHighlighterList.Count - 1 do begin HighLighter:= TSynCustomHighlighter(SynHighlighterList.Objects[I]); SynHighlighterHashList.Add(HighLighter.LanguageName, HighLighter); if not (Highlighter is TSynUniSyn) then begin with HighLighter.AddSpecialAttribute(rsSynDefaultText, SYNS_XML_DefaultText) do begin Background:= clWindow; Foreground:= clWindowText; end; end; end; SynHighlighterList.CustomSort(@SynHighlighterSortCompare); end; constructor TdmHighl.Create(AOwner: TComponent; ATemp: Boolean); begin FTemp:= ATemp; SynHighlighterList:= TStringList.Create; SynHighlighterHashList:= TStringHashListUtf8.Create(True); if not FTemp then CreateHighlighters; inherited Create(AOwner); end; destructor TdmHighl.Destroy; begin inherited Destroy; SynHighlighterList.Free; SynHighlighterHashList.Free; end; procedure TdmHighl.CopyHighlighter(SourceHighlighter, TargetHighlighter: TSynCustomHighlighter); var J: Integer; begin if SourceHighlighter is TSynUniSyn then TSynUniSyn(TargetHighlighter).Assign(TSynUniSyn(SourceHighlighter)) else begin TargetHighlighter.Tag:= SourceHighlighter.Tag; TargetHighlighter.DefaultFilter:= SourceHighlighter.DefaultFilter; for J:= 0 to SourceHighlighter.AttrCount - 1 do begin TargetHighlighter.Attribute[J].Assign(SourceHighlighter.Attribute[J]); end; end; end; procedure TdmHighl.Assign(Source: TPersistent); var I: Integer; Highl: TdmHighl absolute Source; begin for I:= 0 to SynHighlighterList.Count - 1 do begin CopyHighlighter(TSynCustomHighlighter(Highl.SynHighlighterList.Objects[I]), TSynCustomHighlighter(SynHighlighterList.Objects[I]) ); end; end; function TdmHighl.Clone: TdmHighl; var I: Integer; AClass: TSynCustomHighlighterClass; Highlighter: TSynCustomHighlighter; SourceHighlighter: TSynCustomHighlighter; begin Result:= TdmHighl.Create(Application, True); for I:= 0 to SynHighlighterList.Count - 1 do begin SourceHighlighter:= TSynCustomHighlighter(SynHighlighterList.Objects[I]); AClass:= TSynCustomHighlighterClass(SourceHighlighter.ClassType); {$PUSH}{$HINTS OFF}{$WARNINGS OFF} Highlighter:= AClass.Create(Result); {$POP} if not (Highlighter is TSynUniSyn) then begin with HighLighter.AddSpecialAttribute(rsSynDefaultText, SYNS_XML_DefaultText) do begin Background:= clWindow; Foreground:= clWindowText; end; end; CopyHighlighter(SourceHighlighter, Highlighter); Result.SynHighlighterHashList.Add(Highlighter.LanguageName, HighLighter); Result.SynHighlighterList.AddObject(Highlighter.LanguageName, Highlighter); end; end; function TdmHighl.GetHighlighter(SynEdit: TCustomSynEdit; const sExtension: string): TSynCustomHighlighter; var Extension: String; begin Result:= GetHighlighterFromFileExt(SynHighlighterList, sExtension); // Determine file type by content if (Result = nil) and (SynEdit.Lines.Count > 0) then begin Extension:= SynEdit.Lines[0]; if StrBegins(Extension, ' 0) then Result:= GetSyn(TSynUNIXShellScriptSynEx) // Python script else if (Pos('python', Extension) > 0) then Result:= GetSyn(TSynPythonSyn) // Perl script else if (Pos('perl', Extension) > 0) then Result:= GetSyn(TSynPerlSynEx); end; end; // Default syntax highlighter if (Result = nil) then Result:= SynPlainTextHighlighter; end; procedure TdmHighl.SetHighlighter(SynEdit: TCustomSynEdit; Highlighter: TSynCustomHighlighter); var I: LongInt; Attribute: TSynHighlighterAttributes; begin if (Highlighter is TSynPlainTextHighlighter) then SynEdit.Highlighter:= nil else begin SynEdit.Highlighter:= Highlighter; end; if Highlighter is TSynUniSyn then Attribute:= TSynUniSyn(Highlighter).MainRules.Attribs else begin I:= Highlighter.AttrCount - 1; repeat Attribute:= Highlighter.Attribute[I]; Dec(I); until (I < 0) or SameText(Attribute.StoredName, SYNS_XML_DefaultText); end; SynEdit.Color:= Attribute.Background; SynEdit.Font.Color:= Attribute.Foreground; end; { THighlighters } procedure THighlighters.LoadColors; var AStyle: TJSONObject; begin AStyle:= FStyles[FStyle]; dmHighl.LoadColors(AStyle); dmHighl.LoadUniColors(AStyle); end; procedure THighlighters.SaveColors; var AStyle: TJSONObject; begin AStyle:= FStyles[FStyle]; dmHighl.SaveColors(AStyle); dmHighl.SaveUniColors(AStyle); end; procedure THighlighters.LoadDefaults(const AKey: String; AConfig: TJSONObject); var AName: String; I, J: Integer; Theme: TJSONObject; Themes: TJSONArray; procedure LoadItem(Index: Integer); var Idx: Integer; begin Idx:= Theme.IndexOfName(AKey); if (Idx >= 0) then begin FStyles[Index].Arrays[AKey]:= Theme.Extract(Idx) as TJSONArray; end; end; begin if AConfig.Find('Styles', Themes) then begin for I:= 0 to Themes.Count - 1 do begin Theme:= Themes.Objects[I]; AName:= Theme.Get('Name', EmptyStr); for J:= 0 to High(THEME_NAME) do begin if (AName = THEME_NAME[J]) then begin LoadItem(J); Break; end; end; end; end; end; constructor THighlighters.Create; begin FStyle:= TColorThemes.StyleIndex; dmHighl:= TdmHighl.Create(Application, False); LoadDefaults; end; destructor THighlighters.Destroy; var Index: Integer; begin inherited Destroy; for Index:= 0 to High(FStyles) do begin FStyles[Index].Free; end; end; procedure THighlighters.UpdateStyle; var ANewStyle: Integer; begin ANewStyle := TColorThemes.StyleIndex; if FStyle <> ANewStyle then begin SaveColors; FStyle:= ANewStyle; LoadColors; end; end; procedure THighlighters.LoadDefaults; var Index: Integer; ARoot: TJSONObject; AStream: TResourceStream; begin for Index:= 0 to High(FStyles) do begin FStyles[Index]:= TJSONObject.Create; FStyles[Index].Add('UniHighlighters', TJSONArray.Create); end; AStream:= TResourceStream.Create(HInstance, 'HIGHLIGHTERS', RT_RCDATA); try ARoot:= GetJSON(AStream, True) as TJSONObject; try LoadDefaults('Highlighters', ARoot); finally ARoot.Free; end; finally AStream.Free; end; if mbFileExists(gpHighPath + 'highlighters.json') then try with TJsonConfig.Create do try LoadFromFile(gpHighPath + 'highlighters.json'); LoadDefaults('UniHighlighters', Root); finally Free; end; except // Ignore end; LoadColors; end; procedure THighlighters.LoadColors(AConfig: TJSONObject); var AName: String; I, J: Integer; Theme: TJSONObject; Themes: TJSONArray; procedure LoadItem(const AKey: String; Index: Integer); var AItem: TJSONArray; begin if Theme.Find(AKey, AItem) then begin FStyles[Index].Arrays[AKey]:= AItem.Clone as TJSONArray; end; end; begin if AConfig.Find('Styles', Themes) then begin for I:= 0 to Themes.Count - 1 do begin Theme:= Themes.Objects[I]; AName:= Theme.Get('Name', EmptyStr); for J:= 0 to High(THEME_NAME) do begin if (AName = THEME_NAME[J]) then begin LoadItem('Highlighters', J); LoadItem('UniHighlighters', J); Break; end; end; end; LoadColors; end; end; procedure THighlighters.SaveColors(AConfig: TJSONObject); var AName: String; I, J: Integer; Theme: TJSONObject; Themes: TJSONArray; procedure SaveItem(const AKey: String; Index: Integer); var AItem: TJSONArray; begin if FStyles[Index].Find(AKey, AItem) then begin Theme.Arrays[AKey]:= AItem.Clone as TJSONArray; end; end; begin SaveColors; if AConfig.Find('Styles', Themes) then begin for I:= 0 to Themes.Count - 1 do begin Theme:= Themes.Objects[I]; AName:= Theme.Get('Name', EmptyStr); for J:= 0 to High(THEME_NAME) do begin if (AName = THEME_NAME[J]) then begin SaveItem('Highlighters', J); SaveItem('UniHighlighters', J); Break; end; end; end; end; end; procedure THighlighters.Load(const FileName: String); var J: LongInt; Config: TXmlConfig; AVersion: Integer = ConfigVersion; Highlighter: TSynCustomHighlighter; LanguageName, AttributeName: String; Attribute: TSynHighlighterAttributes; Root, FormNode, AttributeNode: TXmlNode; begin Config := TXmlConfig.Create(FileName, True); try Root := Config.FindNode(Config.RootNode, 'Highlighters'); if Assigned(Root) then begin AVersion := Config.GetAttr(Root, 'Version', ConfigVersion); FormNode := Config.FindNode(Root, 'Highlighter'); if Assigned(FormNode) then begin while Assigned(FormNode) do begin LanguageName:= Config.GetAttr(FormNode, 'Name', EmptyStr); Highlighter:= TSynCustomHighlighter(dmHighl.SynHighlighterHashList.Data[LanguageName]); if Assigned(Highlighter) then begin Highlighter.Tag := Config.GetAttr(FormNode, 'Tag', 1); Highlighter.DefaultFilter:= Config.GetValue(FormNode, 'DefaultFilter', Highlighter.DefaultFilter); // Import colors from old format if AVersion < 2 then begin AttributeNode := Config.FindNode(FormNode, 'Attribute'); if Assigned(AttributeNode) then begin while Assigned(AttributeNode) do begin AttributeName:= Config.GetAttr(AttributeNode, 'Name', EmptyStr); for J:= 0 to Highlighter.AttrCount - 1 do begin Attribute:= Highlighter.Attribute[J]; if SameText(Attribute.StoredName, AttributeName) or SameText(Attribute.Name, AttributeName) then begin Attribute.Style := TFontStyles(Config.GetValue(AttributeNode, 'Style', Integer(Attribute.Style))); Attribute.StyleMask := TFontStyles(Config.GetValue(AttributeNode, 'StyleMask', Integer(Attribute.StyleMask))); Attribute.Foreground := TColor(Config.GetValue(AttributeNode, 'Foreground', Integer(Attribute.Foreground))); Attribute.Background := TColor(Config.GetValue(AttributeNode, 'Background', Integer(Attribute.Background))); Attribute.FrameColor := TColor(Config.GetValue(AttributeNode, 'FrameColor', Integer(Attribute.FrameColor))); Attribute.FrameStyle := TSynLineStyle(Config.GetValue(AttributeNode, 'FrameStyle', Integer(Attribute.FrameStyle))); Attribute.FrameEdges := TSynFrameEdges(Config.GetValue(AttributeNode, 'FrameEdges', Integer(Attribute.FrameEdges))); Break; end; end; AttributeNode := AttributeNode.NextSibling; end; end; end; end; FormNode := FormNode.NextSibling; end; end; // Import colors from old format if AVersion < 2 then SaveColors; // Create config backup if (AVersion < ConfigVersion) then try Config.WriteToFile(FileName + '.bak'); except // Ignore end; end; finally Config.Free; end; end; procedure THighlighters.Save(const FileName: String); var I: LongInt; Config: TXmlConfig; Root, FormNode: TXmlNode; Highlighter: TSynCustomHighlighter; begin Config := TXmlConfig.Create; try Config.FileName := FileName; Root := Config.FindNode(Config.RootNode, 'Highlighters', True); Config.ClearNode(Root); Config.SetAttr(Root, 'Version', ConfigVersion); with dmHighl do begin for I := 0 to SynHighlighterList.Count - 1 do begin Highlighter := Highlighters[I]; FormNode := Config.AddNode(Root, 'Highlighter'); Config.SetAttr(FormNode, 'Tag', Highlighter.Tag); Config.SetAttr(FormNode, 'Name', Highlighter.LanguageName); Config.SetValue(FormNode, 'DefaultFilter', Highlighter.DefaultFilter); end; end; Config.Save; finally Config.Free; end; end; end. doublecmd-1.1.22/src/doublecmd.exe.manifest0000644000175000001440000000323214743153644017643 0ustar alexxusers Your application description here. true true doublecmd-1.1.22/src/doublecmd.ico0000644000175000001440000132262614743153644016043 0ustar alexxusers hf  00 %v@@ (B; (F} ( n(  Q~XnrOmpOlmOkkOjhOifOgdOsmW|gzr`{m> Ok&S#K F?94.(#   YO{Җ/R>94-'"DNЫIc84-'"Zj?X4- "]bhh֚4Kr,X7\ --2E+-ã6mWz>bm'A,ao34ģ6mido\m!:)",+2XXģ6mhf~vYlT^U]SYklģ6mheYo\o_iRZQWkkĘ/fh]r]ocqzHN`_ܜg{_t]oZivg`v_t]o[kXfoynv_zb{av_t\o[kXfVbOYw} qfjhfzdxcsap_l\fV`U\jlR$|*{*{*z*y*y*x*x*w*w*v*( @     SbElXBsYCtXAuV?sV>rU>qT=pTf1],X+T*Q(N&K$H#E"B!@=9631.+'%"E5:"Tk,Z'T"O"K!IEC@=:641.+(% "     E0uN9]BEC@=:641.+(% "    CKXXs@@=:641.+(% " pwX@=:641.+(% " -;X@:641.+(% VbK:641.+( $.?uBm4a.ZXt641.+( !% "sKu;f1\'S'P"@41.+'s~Ya   s_IqK=K<J<J;~J:}I9|I9|I8zH8zH7zH6yH5xH5wG4vG4vG2tD,lD,lD,kC+jC*jD-lK3pgRv7 EwoQWOnCl9c6a4^4[3Y1X0V/T.Q-O,N,K*I*H)G(D'B&@%?%<#;"9"7!5 31/.,*(&'#+)(6%wq\> #{{Md;j&U%R"O L IGEBA?=;86431/-*(&% # !    'vd$ GM_Cp)W$RLKJ!J!IFDCA><:86531.,*('%# !      ,zM ԥڽuXv5ZFDEDCA><:86531.,*('%# !     (FMdix|Ѥ%LjCACA><:86531.,*('%# !   ?I#8X>@><:86531.,*('%# !  ,8#h}=><:86531.,*('%# !  ck#><:86531.,*('%# #8:86531.,*('%# #686531.,*('% iier[n46531.,*(' !XdX\?CAD[Dp3a,[$S&QVs*F4531.,*( %!5?F l  Ox>i7c1\,W!N#Ns2531.,*( !jq    p ZGp?h8a1\-W'QGf~6O231.,* %/A^e     p iU{JqAi9b3[.V)QF}u -31.,*ztz    p pe[~OtDk=c6\0W)P.R721/,*'!   p pjgaWyLoBg;`5Z(Nl:R01/-'5Gbi   p pjihf`WxLnDe;]>^Xj031. &Vd+         p pjiihgeaZxQpAckz5963)q}'+p pjihhgfeec~[w$?)B&?$<1!)(() *#+&-*1/4?Dp pjihhgfefe`{9R=T9P6L*@%3.;0;2<5>9A=ECIHMKOVYp pjihhgfefe`zVkYlVhReI\DOLWNXPXQYRYRXRWQVOSW[p pjihhgfefea{Yo]q]p\nViP[V`T^T\S[SYRXRWQVOSW[p pjihhgfefcv~Zp]q]o\nWi_iT^T^S\S[SYRXRWQVOSW[p pjihhgfef`|j{\q]q]o\nYkmxOZT^S\S[SYRXRWQVOSW[p pjihhgffbsZp^r]q]o\n[lYi[eR\T\S[SYRXRWQVOSW[p pjihhgfcgYp^s]q]o\n\mUfR[R[S[SYRXRWQVOSW[p pjihhgbgfy^s^s]q]o\n[mZjerQZPXSZRXRWQVOSW[o pjihf`uZp_t^s]q]o\n[m\kVf]dKRPVQWQVOSW[uΎkdbbvbw_t_t^s]q]o\n[m\kZj_n^cJPHNHLRVsדɣv^t`t_t^s]q]o\n[m\k[kXgs~ýȽԇ"_v`v_t_t^s]q]o\n[m\k[kZiXg#`y`w`v_t_t^s]q]o\n[m\k[kZiYhYf#`yay`w`v_t_t^s]q]o\n[m\k[kZiYhYfWd#xa{bzay`w`v_t_t^s]q]o\n[m\k[kZiYhYfWdUbqy#e~b|c}azay`w`v_t_t^s]q]o\n[m\k[kZiYhYfWdVcT_Zd#k`|d}d~c}azay`w`v_t_t^s]q]o\n[m\k[kZiYhYfWdVcWaU_PZ]fלqa`dee~d~c}azay`w`v_t_t^s]q]o\n[m\k[kZiYhYfWdVcWaV`U_R\MVOWbhx|غԕTcgmacdefffee~d~c}azay`w`v_t_t^s]q]o\n[m\k[kZiYhYfWdVcWaV`U_T^T\S[PWMTKQGMNTPAE;{n{lfhgfeedd}c}b|azay`w`v_t_t]r\p\o[m[l[jZjYhXgXeWdVcVaV`U_T^S\S[RYPVMSX^d`{h)j~w{|mfeeijjjihhgf~f}e|ezcxcwbvbubsar`q_o_m^l\kZgUaT`S_R]R\V_biryojwdĸP ]ysolihjhigkhkhkgkfkfjejejcichbhbhah`g_g_g^g]f]f\e[eZdZdYcWaUaT`S`S`RbSeSo[V'EžWbfffffffffffffffffffffffffffffffe_Q1 (@ %+$'3888883&  ">Zpt|ws~ozozpzozpzpzpypzpypzpzpypzozozozpzozpzpzozpypzpzpyqzqzpzv{wxxwxxtxuX=(4ƼijNrA+h;.tHDHGGFFEECEBDAD@D?C>C>B=B4=4=3=3<2~<1}<1|;0{;/{;.z:-y:,y:+x9*w9*w9)v8(u8(t8's7'q7&r/Y+ RJ+c׫M! 4I;{lyLn>g5^2\0Y.W.U-S,R+Q*P)M(L(J'H&G&E%D%C$B#@#?"=!< :8754310.-+*('&%#" #!43L:}U5cU!iIFj1]+W(T%P#N"L!I GFDCA@>=;:9765320.,*)'&% # "       81O2eM k3a/]3\Qo}Ka965320-,*)'&&,wTX!õd?~pEp:f5b1]-Y)U2YTq/J6532/-,*('''EUw{,4   õh =~oJs?i8d4^0[-W*U&Q.Usas75320-,*)'(4NU    ôf >pRzFn?h8b4^/Z+V(S(Q,SZu.I5310.+*)(&N\2;    õg >r\NuFo?i9b4^/Y+U)R'P,Rb{bs732/.,*)),}:C     ôf >sfZ~PvHoAh;c5^1Y-U*R'O2U|!>410.,*)(e8_3Z/V,R*ODd6O410.,**)frx}'    ´f =slif`Y|QtImAgtmihgd_~VxNqGj@d;_7Z1UKhr~430/-,,%:$1  &´g =smjhghgb]}VvOoHjBd<^Gf%@631/-,3GX`"          ',³f >tliighgfeb]|XvRpKkLjy3L;7532/DU=H15g >tmjihhgeeddc_|\xZu|DZ'A$>";973Ud4A"#"####$$&!($)(,AEg =tljigigffedddd~e}Wj3L/H-E*B*@$tliihigffeddd~d~f~cuD[@W=S:P9N3HtEP0<1>3=4>7@9BFAHDJGLJNLO^bg >tmjihihffeeedd~gj{WkShQeNbN`I\yWaEPGRHQIRJSLTMTNTNTOTOTOSNR_cg >smjihihfffeeed~ii{^q\o[nZmZlXi{gpR\S]R\R[R[RZQXQWPVOUOTNSNR_bg >tmjihiheefeeed~mex^q\o[n[m[m[kvv~U`T^R\R[RZRYQXQWPVOUPUOTOS`cg >tljigihfffeeec~u^s^r\p[n[m[l[ljw\fU_S\S\S[SZRYRXQWPVPUNTOR`bg >tmjhhhgffeeeeh]q^r\p\n\n[m\lcqiqU_S]S\S[SYRYRXQWPVPUOSOS`cf >tliihigffeeeevu^s^r]p\o\n[m\l^n}XaS]R\S[SZRYRXQWPVPUOTNR_bg >smjhhhhffeeeigz^s^r\o\o\n[m[l\kiqT^S]S[SZRXRXQWPVPUOTOS`cg =smihghheeefhau^s^q]o[n[m[m[l\kgt]fS]S[RZRYRXPVOUOUOTOS`cg >tmjihhgfffgxu_t^r^r]p\o\n[m[l[k[j[eT\SZRYRXQWPVPUOTOS`cg =tlihghhffgbv_t^r]q]o\o\n[l[l[j[jmz]eS[SZRXQWOUOTNSNR_ch >vmjihihhox`t_t^r]q]p\o\n[l[l[j[j[kkrV]SYRXQWPUOTOSaeo =xmihefvcx`t_t^r^q\p[o[n[l[l[jZjYihuz}Z^NTNSNSOS`dqW|ьj`u_t_t]q]q]o[n[m[l[l[jZjZjZjzy{b' vaw`u_t_s^r^r]p\o\n[m[l[jZjYiXh]lb by`w_u_t_t^r^r]p\o\n[m[l[jZjYiXhYh`ms f|`x`w_u_t_t^r^r]p\o\m[m[l[jZiYiXhXgYfcos d|ay`w`v_t_t_t^r^r]p\o\n[m[k[jYjXiXhXgXeXecot yd}azay`w`w_u_t_t^r^r]p\o\n[m[l[jZjYiXhXgXeXdWd^jt qd|b{azax`w_w_t_t_t^r^r]p\o\n[l[l[jZjYiXhXfXeWdWdVb\gpxt ygc}c|a{`yay`w_v_u_t_t^r^r]p\o\n[m[l[jYiYiXhXgXeXdWdVbVaWa^h}s tle~d~c}c|a{azay_w`v^t^s^s]r]r]p[n[mZlZkZiZjXiWgWfWeXdWcVbVaV`T_Xb_hovs |qhddd~d~c|c|a{ayay`w`v_u_s_s^q^q]p[o[n[m[k[jYjYiXgXfXeWcWdVbUaV`U_U_S]T]Zadkrw㿿f5pponligfeedd~c}b|b|`{az`x`w`w_t_s_s^r^r]p\o\n[l[l[jZjYiXhXgXeXdWdWbVaV`T^U_S]S\S[SZT[V\W[X]Y]X[^cP<|_# ûkio}hghhfffedd~d~c}b|b|a{ayax`v`v_t_t^s]r]q\p\o[n[mZlZiZjXiXhXgWeWdVcVbVaU`U_U_R\S\S[SZRYRXQVOUOTMQ]_Y>u; M\Fxghhhfeeddee~d~c}c|a{azay`w`w_u_t_t^r^r]p\o\n[m[l[jZjYiXhXgXeXdWdWbVaU`T^T^R\R[RZRYRYRXQWQWOTejd[% .d[iggfffeed~d}c}b|b{azayax`v`v_t_s^s]q]q\o\n[m[lZkZiZiYhXgXgWeWdVcVbVaU`U_U_S]S\S[SZRYRXQVQVbfzt]@lF@dStfdccemoooonnmmlllkj~j}i|h{hzhygxgvgvfuetesdqdpcocn^jU`S^R]Q[PZQZPXZahnpdoSy\7`rZeWwnvwwvwuwuvtvtvsvsururuqtquqtptptotnsnsmsmrmrlrkrkqjqjqiqhqgpgpfpfpepeoeododocncmbmbmamal_gSY;id}S$ 2J\evvvwwwvwwwvwwwwwvwwvwwwwwwwwvwvvwwvwwvvwvvoaR7  ??( U=>1@D@D@D@D@D@D>==<<;;::9988766554433221100//..-,,++**))((''&&%%$##""!!  ~~}| { z z y x w v v u t s r r q p o o n m lkkk jhG!CT!D!C B!D!E EEECCBB@@@@@?====;;:::888766544422210////---,++**))'''&%%$$$""!!                 wih h gRG!D!D!E HHGGFFEDDCCBAA@@?>>==<;;::98877655443321100/..--,++**)((''&% % $ $ # " " ! !            j g fi"D-!E!E"HIII!K#M$M$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                  f f c,#F"F"E IJJ#N&P%P%O%N$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                   e d dF !F"E!IJ!M&R&Q&P%P%O%N$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                    d df !F"F"JK"N'R&R&Q&P%P%O%N$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                     d c$I"F"HK M'R'R&R&Q&P%P%O%N$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                     o d b"F"G LK%S'S'R&R&Q&P%P%O%N$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                      c aU#G#IL"O'T'S'R&R&Q&P%P%O%N$N$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                      m b!G=#F!JK%Q&S&R&Q%Q%P&O%O%N%M$M$M$L#K#K"J"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                      a \: C~!DHI&O%O%N%M$M$M$L#L#L$K#L#K#K"J#J"I"I"I!H!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                      ^[{ @ @DE#I"I"I"H!H!G"G!G!G"G!G!G"G!G"H!H!H"H!G!G!G F E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                    XU ><?? CCBBBA@AAAABBB DD D F F F!F E E EDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!                   ~~}|{SRo򬮲dwIa,H=>??ABC DDD DDCCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!            7=V[sw򦦦juwKb!?<=>?AACCBCBAA@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!             >=<<;::98876654432110//.--,++*))(''&%$$#""!           IQpv8Q8:<=?@@@@?>>=<<;::98876654432110//.--,++*))(''&%$$#""!          )3pv:Q79;=>???>>=<<;::98876654432110//.--,++*))(''&%$$#""!        +5pv;R79;=>>>>=<<;::98876654432110//.--,++*))(''&%$$#""!       /9pvv:69;<=>=<<;::98876654432110//.--,++*))(''&%$$#""!      ntpvUg579;<<<<;::98876654432110//.--,++*))(''&%$$#""!     MVpv|657:;;<;::98876654432110//.--,++*))(''&%$$#""!    {pv.E369:;;::98876654432110//.--,++*))(''&%$$#""    ".pvPb357::::98876654432110//.--,++*))(''&%$$#"!   ISpvZk24799:98876654432110//.--,++*))(''&%$$#! !   T]pvhw1468998876654432110//.--,++*))(''&%$$" !   bjpv~136888876654432110//.--,++*))(''&%$$"   zpvds03678876654432110//.--,++*))(''&%$#!  _hpuWf0357876654432110//.--,++*))(''&%#"  Q[pe媭GY035776654432110//.--,++*))(''&$" CN䭭`?<?A D D C CBA!B7TQht'>13666654432110//.--,++*))(''&#! !/gk>D!'   ~XU  B BEG$K#K#J#I"I"G!F ECA?'E^r/1456654432110//.--,++*))(''%"  NS         ^ Z)L"FJ!M&P%P%O%N$N$M$L#K"I"G EC@=2Nu.245654432110//.--,++*))('&$! s{|%          c ^.Q&I,V#O(S'S'R'Q&Q&P%O$N$M$K"J"H!EB@=.J6J/24554432110//.--,++*))('%# 2?#        f `.Q'JNs>e*U'T'S'R&R&Q&P%P%N%M#M#K#I!G EB>;G^.02554432110//.--,++*))(&$!6>        g b.Q'JNsRuOs0['S'R&R&Q&P%P%O%N$N$M$K"J"I FC@<&BVf.1444432110//.--,++*))(%# U_        g b.Q'JNsRuVxTx?f(S&R&Q&P%P%O%N$N$M$L#K#J!I!F DA<9fw6/244432110//.--,++*))'$"(X_        g b.Q'JNsRuVxUxUwKn/Y&Q&P%P%O%N$N$M$L#K#K"J"H!GDA>9arjw-033432110//.--,++*))&# hqT[        g b.Q'JNsRuVxUxUwUwSv?e(Q%P%O%N$N$M$L#K#K"J"I"H G DA=9Vi1/13432110//.--,++*)(%"'GN        g b.Q'JNsRuVxUxUwUwTwTvOq3[%O%N$N$M$L#K#K"J"I"I!H F DA<8k{cq-02332110//.--,++*)'$ cmah        g b.Q'JNsRuVxUxUwUwTwTvTuSuFj+S$N$M$L#K#K"J"I"I!H!G!FD@<7-.1332110//.--,++*(&#"v{        g b.Q'JNsRuVxUxUwUwTwTvTuSuStRs>c'P$L#K#K"J"I"I!H!G!G EB?::HX-0232110//.--,++*(%"EQ           g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsNo7[$L#K"J"I"I!H!G!G FDB>8/G+.222110//.--,++)'$!*           g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrKk1V"J"I"I!H!G!G F ED@;7t1-122110//.--,++)&#*ho            g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqFg,R"I!H!G!G F E DB>:8Zi,012110//.--,++)%"\g              g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpEf.S!G!G F E EC@<7br+.12110//.--,+*(%!T\              g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoFe/S F E ECA>97+-02110//.--,+*($"              g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnGg1T!FDB@;6o}3F,/2110//.--,+*'#2Adk               g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlLi7X$FA=8-Edq,/2110//.--,+*&"eo*               g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlMi:Z'H94+.2110//.--,+)&"                g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkMjKf@Z+Fq*.2110//.--,*)%!gn                g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkLgHaBY]n*.2110//.--,*)%!2=                g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkLhIbD[>S#8-2110//.--,*($#3                 g b.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMhJdE]>T>P-2110//.--,*($=J                  gh.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKdE]?UIY-2110//.--,*($HU               #)387< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKeF^?VTc-2110//.--,*'#S_v}          $)/7=8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKeG_@Vp{,A(B820//.--,*'#\gmt          !#,/77?8?8?8>8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKeG_@V}?RG]G]EZ;Q1H(@!92-,*'#gqck           (&0.87@:B9B9A9@8?8?8?8>8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKeG_@V}?RG]G]G]G\G[G[FZFYDX=P3H+>!3mvck      $'-%1*50<8B8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKeG_@Vv?RG]G]G]G\G[G[FZFYFYDXCU?P9Is|{+70=6D:F;H>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKeF_?Vp|?RG]G]G]G\G[G[FZFYFYDXCU?Q9Imu4?9E=I?J>J>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMiKdF^?Uiv?SG]G]G]G\G[G[FZFYFYEYCV@Q:Jfp3?8DJ>J>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkMhJdE]>Tbp@SG]G]G]G\G[G[FZFYFYEYCV@Q:J]h3>8CJ>J>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkLhIbD[?TK[@SG]G]G]G\G[G[FZFYFYEYDV@R;KHU4?7B;G>J>J>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkLgHaBYbr;M@TG]G]G]G\G[G[FZFYFYEYDWAS;L7FPY6A:F=I>J>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkMjKfF_AW:MAUG]G]G]G\G[G[FZFYFYEYDWBTI>J>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkMiJdE]?U;NBVG]G]G]G\G[G[FZFYFYEYDWBU=N8F3=8CJ>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlMjLhHbCZWiO9HDN6A:EI>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlMjKfF_AW_m>QCWG]G]G]G\G[G[FZFYFYEYEXCV?Q:J]g4?9C;G=I>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlLhHcD\AV=N?SDYG]G]G]G\G[G[FZFYFYEYEXDV@R;K8F4?7A:E=H>J=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlMkKfFaAX;N@UEZG]G]G]G\G[G[FZFYFYEYEXDWAS=M7Ftz4>8C;G=I=I=H8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlNkLiHcC\EZN9H6@5@:E8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlMjJfE_@XIY>RCYF\G]G]G]G\G[G[FZFYFYEYEXEXBU?P;JHU3=7B;F8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmNjLgGbBZ^p8C:F8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnNlLhHcC]@W>QBWF\G]G]G]G]G\G[G[FZFYFYEYEXEXCVBS>O8I|5>5@8C;E;G8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnOmMjIdE^?X>R@TCYG]H^G]G]G]G\G[G[FZFYFYEYEXEXDWCT@Q:K;I2<5@9C:F;F8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoOmMkIeE_AY=QBWE[G^H^G]G]G]G\G[G[FZFYFYEYEXEXDWCUAR8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpOmMjJfE`AYEV?TDYF\H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVBT>P:IANou2;5?8B:D;F8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqRqQpPoOnMjIeF`@Y7A9D;E8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsRrRqQpPnNlLiHeE^AYL\?TDZG]G^H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVCUAT>O:IER094=6@8B:C:D;C;C:C:C:B9B9A9@8?8?8?8>8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStSsRsRsQqQoOmMjKgGcC]Ka>QBWF]H_H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVBU@Q7@8A9B:B:B:C:B9B9A9@8?8?8?8>8>8=7<7<7< hj.Q'JNsRuVxUxUwUwTwTvTuSuStRrQrPqOnNkLiHdE`B[=Q@TD[G_H_H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVBUAS?O:I8Emr193;5>7?8@8A9B9A9A9A9@8?8?8?8>8>8=7<7<7< hj.Q'IMrQtUwTwTvTvSvSuSsQsQqPoNnMlKhIdFaC\`sq}>SCXF]H`I`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVBT@R=L8FjsKQ192:4;5=6?7?7@7?8?7>7>7>7=8>8=7<7<7< gj-O&HKnNpRsQsQrQrPrPpOoMmLkLiIfGdE`C\ex=PBWF\H_IaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUBS?O;J6CQW07182:4;4<5<5<5<5<6<6;6;6:59595: eg+K$DFhIiMkLkLjLjJiJhIfHeGcE`C^Qi>S@UE[H^H`IaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUBTAQ>M9G9FSBYF]I`JaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTBQ>M;I7D~ë=RAXE]H_IaJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTBR@P>M:H5Bšë=RBWE]H`IaJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSAQ@O=L9G5BÜë=RAXE\G`IbJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRAQ@ONNTBXF]HaJcKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQ@P>M;H7D4@ƥët?UBZF^IaJcKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQ@O=L;I8D4@nvɦëL_@WD[G`IbKcKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP?N>L;H8E5AGQǨë?UBYE]HaJdKeLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O?N>L;I9F6B3=ǨëWjAWD\G_IcKeKfLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O?M>LL=J;G8D6@2L=J2;Ǩëq@WB[D^GaIeLgMgMhMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?K>K=H:F8C6A3=1:fmǨëH`AZC\E_HbIeKgLiMiNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?J=IJ=I=I;F9D7B5?4=2;19SXǨëZoB[D^D^FaHcIeJfLiMjMjNkNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=H4<2:1806JQ|Ǩ'DJ>J>J=I=HJ>J>J=I=H5<3<3:391817171616150405,1 X^ )J!DAdJlQqPqPpPpOpPpPoOoOoPoOoPpPpQoQpPoQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H6=5<5<5<5;5:594849*. ]`#FB"F:]LpRuSvSuTuSuStStRtRsRrQrRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H7>7>7=7=7<6;6<" `]?U&I+PNrQtUxUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H8>8=7=7=r c%I"GCgNqTwUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H8>8=7>)/ c c&D"#G-QNqOsUwUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H8>7>7>u c f!F"F:]NqQsUwTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H8?7>$ d cF "G#FAcNpPsTwTvTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=H8?'- e ff #F#F"F<`NpNqRtTuSuStSsRsRsRrRqRqQpQpQpPoPnPnOmOlOlNlNkNkNjNiNiMhMhMgLgLfLeKeKeKdJdJcJbJbJaIaIaI`H_H_H^G]G]G]G\G[G[FZFYFYEYEXEXDWDVDVCVCUCUCTCSBRBRBRAQAQAP@O@O@N?N?N?M?L?L?K>J>J>J=I=HJ>J>J=I=HN>M>M=L=K=K=J/>/=.<.<.<-<-;,9,9,9,9,8,8,7,6,6+6*6*5*3*3*3)3)3&/!)#{ih h hX$I"AJ C B B A@@??>>==<<;;::9988766554433221100//..-,,++**))((''&&%%$##""!!  ~~}| { z z y x w v v u t s r r q p o o n m lkkk jiImU=>1AK?U?U?U?U?U>>>>>><<<<::::::::9999999777755555555444444422220000000////////----+++++++********((((&&&&&&&%%%%%%%%####!!!!!!!            } } } { { { { { z z z z z x x v v v v v u u u u u s s s q q q q q p p p ppnnnll l mkylo lP g*m!B6 Bx B B B A A AA@@@@????>>>====<<<<;;;;::::9998888777766665555444333322221111000////....----,,,,+++****))))((((''''&&&%%%%$$$$####""""!!!    ~~~}}}|| { { { z z y y y x x w w w v v u u u t t s s s r r r q q p p p o o n n n m m l llkkjji iw j5$I!B{!C C B B B B A A AA@@@@????>>>====<<<<;;;;::::9998888777766665555444333322221111000////....----,,,,+++****))))((((''''&&&%%%%$$$$####""""!!!    ~~~}}}|| { { { z z y y y x x w w w v v u u u t t s s s r r r q q p p p o o n n n m m l llkkjjjiiiiz f$@"C!D!C!C C B B B B A B!C D B B B B A A AA@@@@@@?>>>>=======<;;;::::9999888877776665444444433221110000000/....-------,,,,+***)))((((('''&&&&%%$$$$$$####""!                                            ~~}}xrljjjiihh i g h@@!Du!D!D!D!C!C C C EEFGFFFEEEEDDDCCCBBBBAAA@@@????>>>===<<<<;;;::::999888777766655544443332221111000////...---,,,,+++***))))((('''&&&&%% % $ $ $ $ # # # " " " ! ! ! !                   lihh h g g fs"D-!F!D!D!D!D!C!FGHGGGGFFFEEEEDDDCCCBBBBAAA@@@????>>>===<<<<;;;::::999888777766655544443332221111000////...---,,,,+++***))))((('''&&&&%% % $ $ $ $ # # # " " " ! ! ! !                    {i h g g f f e+#F_"E!E!D!D!D!GIHHHGGGGFFFEEEEDDDCCCBBBBAAA@@@????>>>===<<<<;;;::::999888777766655544443332221111000////...---,,,,+++***))))((('''&&&&%% % $ $ $ $ # # # " " " ! ! ! !                         h g f f f e[!F"E"E!E!D!FHIIHHHGI!J"L$L#M$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                t f f f e e33#E"E"E"E!E HJIIIHI"L$P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                    g f e e ef"F"F"E"E#FIJJII K#N&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                     j e e e e"G"F"F"E"FJJJJJ#M&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                      l e e d e!E\"F"F"F"G JJJJ L%Q&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                       l e d d dW$I*"F"F"F"GKKJJ!M'Q&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                        i d d ce&"H"F"F"F JKKJ!N'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                         e d c c"Gh"G"F"F"KKKK!M'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                          d c c cdK$G"G"F"HLKK!M'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                          o c c cf$H#G"G"F KLK K%R'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                           d c c c|$I#G#G"G"ILLK#P'S'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                           w c c bb #Ge#G#G"GKLL M'T'S'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                           c c b cb#H#G#G"ILLL$P'T'S'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                            r c b b"E%#F#F#F!KKK L(R'S'R'R'R'Q'Q&Q&P&P&P&O&O%O%N%N%N%M$M$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                            b a a]!#Fm"F"F"FKKK#O'R&R&Q&Q&Q&P&P%P%O%O%O%N%N$N$N$N$N$M$M$M$L$L$L$K#K#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                            b ` ` `h"F"E"E"GJII%P&Q%Q%P%P%P&O&O%O%N%N%N%M%M$M$M$M$M$L#L#L#K#K#L#K#K#K#J#J#J#J"J"J"I"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                            n _ _ _"E"D!D HIHH&P&O%O%N%N%N%M%M$M$M$M$M$L$L#L#K#K#L#K#K#K#J#K#K#J"J"K"J"J"J#I"I"I"H"I"I"H!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                          ] ^ ^1v!D!C!BFGFH%N%M$M$L$L$L$K$K#K#J#J#J#J#J"J"I"I#J#I"I"I"I"I"I"I"I"I"I"I"I"I!I!I"H"H"H"G!H!H!G!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                         [ \ \7 :B!C A AEED H#K#J"J"I#J#J#I#I"I"H"H"H"H"H!H!G!G"H"G!G!H!G!G!H"G!G!H!G!G!H"G!H!H!G!H!H!G!G!G!F!G!G F F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                         Y Z[N>  ;c B@?CCA F"I"H!G!G!G!G!F!F F E E!F!E!E E D E E!E E E E E E!E E F E!F!F!F F!G!F!F!G!F G G F!F!F E F E E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                            V XYQ_  ;q@>>A@?D!F!E E D D D C CDCCCB CCBBCBBCBCC CCDC D D DD E E E F!E E F E F F E E D E E DDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                        X VWNo  :?==?>=B C CBABBAAA@@@@@@@@@@@@@@A@AAAABBBCCC D CDE D D EDED D D CDDCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                                        ~ } } }|||{{|{Y TUO~ ƨ򫫫󭮰l~WmB\,J>=>>>>?>?@?@A@ABBBCCC DCDCDD CCCCCCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                              -4FK_cuy򨨨򥥥Ѫi|Ia%C=<===>>>?@@@AAABBBBCCCCCBBCBBBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                         7>\aѪ\p/K;;<<=>=>???@@AAABBBBBBBABBAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                       #MS| Ѫp@X;:;;<==>>>??@A@ABABBAABAAA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                     .6ej ѪOe;:::;<<==>???@@AAAAA@AA@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                    BI ѪAX89::;;<==>???@@@A@@@@@@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                   3; ѪWk =899:;;<==>???@?@@??@???>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                   RY Ѫ6O7899:;;<==>?>?@??????>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                   )2 ѪH]77899:;<===>?>?????>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                  =>>>>?>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !                3= ѪAX56889::;<<=>=>>>>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !              5? Ѫ,F66788:;;<===>=>>===<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !             ( Ѫo~ :567899:;<<=======<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !             fm ѪUi556779::;<<<=<==<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !             LU Ѫ)A466789:;;<<<<=<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !            & Ѫ`q4457789:;;;<<<<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!! !             Ya Ѫ":4557889::;<;<<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!!           ! ѪEZ34567899:;;;<;;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""!          >H Ѫbr23556889::;;:;;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"""          Yb Ѫ734567899::::;:::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###""!        ! Ѫ4J23557889:9:::::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###"!!        *6 Ѫ@S2335678999:9::99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$###!! !        6A ѪUf223557889999:99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$##"! !       NW Ѫu12345778989:99988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$#"" !      qx Ѫn{1224567889999988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$$"""      pw Ѫ212456778989988777666555444333222111000///...---,,,++***)))((('''&&&%%%$$#"" !      z Ѫ21335667888988777666555444333222111000///...---,,,++***)))((('''&&&%%%$##"! !       Ѫ|0123556778888777666555444333222111000///...---,,,++***)))((('''&&&%%%$##!!     w~ Ѫu002345677878777666555444333222111000///...---,,,++***)))((('''&&&%%%##"!     rz Ѫp~/1234567777777666555444333222111000///...---,,,++***)))((('''&&&%%$#""     nu ѪTe/113456767777666555444333222111000///...---,,,++***)))((('''&&&%$$#"!    NYѪ>Q/02345667677666555444333222111000///...---,,,++***)))((('''&&&$$$"!!    :GѪ4I/0234556667666555444333222111000///...---,,,++***)))((('''&&&$$#"!   -:܋7/113446566666555444333222111000///...---,,,++***)))((('''&&%$##!   'ۮ ;@=>@?>D D DDCCCBBBA@@?'GA\]rz/002345556666555444333222111000///...---,,,++***)))((('''&%%$#"   mqLP,2  ~ ~  ~ ~ ~~~~}}}}\ UVP  < A?@BA@ F!G!F!F!E!E!E D D D CCCBAA@@??@[qjx./1234456566555444333222111000///...---,,,++***)))((('''&%%#""   jrdh,4            _ WWS  ? B @ADDB!I#J#I"I"H"H"H"G"G!G!F!F E D DCBBA@@?>=:UzDW./123345556555444333222111000///...---,,,++***)))((('''%%$#"!   ALlp$+                   a YYT  @!D!B CFFE"L$M$K#K#K#K#K#J#J"I"H"H"H"G"G!F E D D CBA@??=>Si6.012245556555444333222111000///...---,,,++***)))(((''&%$$"!  'CI                     d [[X ,M!E!C!EHHG#N%O%N$N$M$M$M$L$L#L#K#K#J#I#I"H"H!G!F!E EDBBA?>=< ?fx-//1234455555444333222111000///...---,,,++***)))(((''&%$#!   W\                      g ] ][~3S"F"E"FJJI$P&Q&P%P%O%O%O%N%N$N$M$M$M$K$K#K"I"I"I"G!G F E DCBA@>=<=at[j./0123445555444333222111000///...---,,,++***)))((('&&$##!  ZdRX                     i _ ^\}5S"G"F'J!MKJ%R'S'Q&Q&P&P&P&O&O%O%N%N%N%M%M#M#L#K#K#I"I!H!G!F E DCB@?><;;^q'>-/013345455444333222111000///...---,,,++***)))(((&&%$#"  !/MT                    j ` _]|5V#G#F*NFk(TK%S'T'S&S&R&R&R&Q&P%P%O%O%O%N%N$N$M$M$L$K"K"J"I"H!H!F EDBB@?><:*F-./02234445444333222111000///...---,,,++***)))(((&&%#"!  z~                  l a `_{6Vą#H#G+NMrMq4\&S(T(S'S'R'R'R'Q'Q&Q&P&P&P&O&O$O$N$M$M$L#L#L#J"J"I"H!G F E DCA@><;:BYJ[-./1234445444333222111000///...---,,,++***)))(('&%%#"!  FR09                 l b a_{6Vą#H#G+ONsNsNrJp/Z(T'T'S'S'S'R'R&R&Q&Q&Q&P&O%O%N%N%N%M#M#L#K#K#K#I!I!H!G!F E CBA>=<:9at4-.0123344444333222111000///...---,,,++***)))(('&%$"! 'SY                 m b a`z6Vą#H#G+ONsNsNrTxRv7`'T'S'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%M$M$M$L#L#K#K"J"J"H!G!G!EDCA?><;9BYt,./013344444333222111000///...---,,,++***)))(''%%$"  v~-6                 m b a`z6Vą#H#G+ONsNsNrTxVyVxFm+V'S'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$L$L$K"K"K"I"I"H!F FDCB@>=;9&B*>-./02234344333222111000///...---,,,++***)))(''%$#! '5                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxQu6_'S'R'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$K#K#K"J"J"I"H!G F DCB@?=;:8ct,-.01134344333222111000///...---,,,++***)))''&$#"  U\                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwEk*U'R&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#J#J"J"I!H!G!F E DB@?=;:8NcCT,-/0123334333222111000///...---,,,++***)))''&$#" AN>F                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwPs5]&R&Q&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#J#I!I!I!G!F E CBA?=<98E[,,.0013334333222111000///...---,,,++***))('&%#"!  7@                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwEj*T&Q&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"I"I!H!G!F!EDC@?>;:7;SFW,-/012233333222111000///...---,,,++***))('&%#"! ER,6                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwQs7_&Q&P&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"I"H!H!H!F EDBA?=;97-G,,./02233333222111000///...---,,,++***)((&%$"! '                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvHl-U&P%P%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"H"H!G F ECBA?=:97=TFV,-.01123233222111000///...---,,,++***)((&%$"! DQ.7                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvSt?d(R%O%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"H"G G F DCB@?<:96K`+,-/0123233222111000///...---,,,++***(('%%#! =G                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuMp3Z%O%O%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"G!G G E DDA@><:86]o4G,-.0012233222111000///...---,,,++***(('%$#! />KS                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStEi+T%N$N$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!G!G F E DCA?><976p+,./012223222111000///...---,,,++***(''%$" ci                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStQs:_%O$N$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!F F EDC@?=;976"8+-//12223222111000///...---,,,++**)('&$#" -                   m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsMo3Z$M$M$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!F FDDA@?<:96+Eiu+,..01122222111000///...---,,,++**)('&$#!gp&                   m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsEh,S$M$L#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!FEDCA@><:76K_*,-.01122222111000///...---,,,++*))'&%#"! =F                     m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRr?c)P#L#L#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G EECBA?=;975sBT+--/0112222111000///...---,,,++*))'&%#" ANgn                      m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsPp9^%M#K#K#K#J"J"J"I"I"I"H!H!H!G!G!G F EDCB@>=:868*,-.0012222111000///...---,,,++*))'&%#!                        m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrNo8\$L#K#J"J"J"I"I"I"H!H!H!G!G!G F E DDCA?>;:85L`-+,./012222111000///...---,,,++))(&%$"!#=G                         m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqKk3X#J"J"J"I"I"I"H!H!H!G!G!G F F D DCBA?<;964JY+,-//12222111000///...---,,,++))(&%$" HU                          m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqIi0U"J"I"I"I"H!H!H!G!G!G F F E DDBA@=<:75+D*+-./01222111000///...---,,,+*))(&%#! (                           m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpGi.S"I"I"H!H!H!G!G!G F F E E DCBA?=;865n},+,./01222111000///...---,,,+*)('%$#!$bj                             m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpHh1U"H!H!H!G!G!G F F E E D CBB?><976#=@Q*,-.01222111000///...---,,,+*)('%$# =J                             m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpGg-R!H!G!G!G F F E E E CCB@?=:874wv*+-./1222111000///...---,,,+*)('%$" vmt                               m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoFg/S!G!G F F E E E CCCA@>;975'@)+-./0222111000///...---,,,**)('$#" %                               m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnIh2U!G F E E E DCCA@?<:864|$9*,-/0222111000///...---,,,**('&$#!"3ry                                m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnGg3V#G E E DDCBA?=;975,ERa*,-/0222111000///...---,,,**('&$#!R]*                                m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmLi8Y$I DDCBA@><:753}*+,.0222111000///...---,,,**('&$"!}                                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlNl>])LCBBA>=;864aq)+,.0222111000///...---,,+*)('%#"!U]                                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlFd1Q CA?=<975#;1+,./222111000///...---,,+*)(&%#")                                 m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlMjIf6U#C><:863S)+-/222111000///...---,++))'%$" tz                                   m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkMjLhLgJeHbF^D[AW>Thw0+-.222111000///...---,++)(&%$"*BM                                   m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkMjMhLgKeIbG_D\BX?TCX4G*,.222111000///...---,++)(&%$!4C                                   m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkMjMiLhKfIcG`E]BY?U=RM]*,.222111000///...---,++)(&%#!LX                                    m b a`z6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiLhKfJcH`E]CY?V=Rer*,.222111000///...---,++)(&%#!fp                                    m b aj6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiLhLgJdHaF^CZ@V>Sw*,.222111000///...---,++)(&$#!xy                                    & p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMhLgJdHaF^DZ@W>Tz*,.222111000///...---,++)(&$#!Yb                                 %+5;7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMhLgJdHbF_D[AW>Tcs*,.222111000///...---,++)(&$#!;E                              !)06<7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMhLgKdIbG_D[AX?TNa*,.222111000///...---,++)(&$#!".                           '.5;8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMiLhKdIbG`E[AX?TCX*,.222111000///...---,++)(%$#!#                      #*/68?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIbG`E\AX?U8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIcG`E\BY?U=R;M>Q=Q9Q.G#=411000///...---,+*)'%$#                      "+-67?9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIcG`E\BY?U=R;M>QATG]G]G]G]?U5L,D$=5///...---,+*)'%$#                      )(21::B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIcG`E\BY?U=R;M>QATG]G]G]G]G]G]G\G\G\FZ=S5L-D%=6/--++*)'%$#                    #)&10:9B;C:C:C:C:C:B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIcG`E\BY?U=R;M>QATG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFY?T8M/E)@#92+%$#                     $*$1-85?;E8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIcG`E\BY?U=R;M>QATG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDWCVAS?Q(7             $&+"0&2-93?8D8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIcG`E\BY?U=R;M>QATG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDWCVAS?Q=M:J8H6D$')+#0'5*7-;/>4B7D;H>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjMiLhKeIbG`E\AX?UQATG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDWCVAS?Q=M:K8H6D3>3?5A8C9E;G=H>I=J>J>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMiLhKdIbG`E[AX?UDY;M>QATG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDWCVAS@Q=M:K8H6DI=J>I>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMhLgKdIbG_D[AX?TQd;M>QATG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDWCVAT@Q=N;K9H6DEO3?5A7B9E;GI>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMhLgJdHbF_D[AW>Tgw;M>QAUG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDWCVAT@Q=N;K9H6EW`3>5A7B9E;GI>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiMhLgJdHaF^DZ@W>T;M>QAUG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDXCVAT@Q=N;K9H7Epw3>5@7B9D;GI>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiLhLgJdHaF^CZ@V>S;M>QAUG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDXCWBT@R=N;K9I7E2>4@6B8D:FI>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiLhKfJcH`E]CY?V=RQAUG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDXCWBT@R=N;L9I7E2=4?6A8D:FJ>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkMiLhKfIcG`E]BY?U=Rp|QAUG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYDXDXCWBT@R>O;L9I7Flu2=4?6A8C:E;G=H=I=I>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkMjMhLgKeIbG_D\BX?TEZZhOI>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkMjMhLgJeHbF^D[AW>TrDUO5@7B9D;FI>J>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkMjLhKfJdHaF^C[AV>S9LP4?6B8D:EJ>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkMjMjLhKfIdG`E]BY@U=R:L=O@SBVG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYDXDWCUAS?P=N:K8G6D2=4>6A8C:E;GI>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkMjMiLgJeIcG_D\BY?TG\:L=P@SBVG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYDXDWCUAT?Q=N;K9G7E:D3>5@7B9D;F;HI>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkMjLiLgJeHbF^D[AW?T|:M=P@SBWG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYDXDXCVBT?Q=N;L9H7Efn3=5?7B8C:E;GI>J>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlMjMjLhKfIdGaE]CZ@V>Rgu;M>P@TCWG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYDXDXCVBT?Q>OI>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlMjMiLhJeHcG`D\BY?UJ]CT;N>Q@TCWG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYDXDXCVBU@R>O5@7B9D:F;GI>J=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlMjLiKgJdHbF_C[AW?T9LQAUCWG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYDXDVCU@R>P=M:J8G6Dqw3=4?6A8C9E;FJ=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlMkMiLhKfIcG`E^BY@V>S:L6@8B8D:E;GI=J=I=I=I=H=H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlMkLiKgJfHbF_D\AX?UWi~:M=P?SBVDXG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYDXDWCVAS?Q=N;K9H7EyFO3=5?7A8C9D;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlMkMjLhKfIdGaE^C[@V>TO_;M=Q@SBVDYG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYDXDWCVAS@R>O6@7B9D:E;G8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlNkMkLjKgJfHcF_D\BY?UK]9LR@TBWDYG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYDWDVBT@R>P8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlNkMjLiKfIdGbE^C[AX>T:LRATCWEZG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYDWDVBTAS?Q=M;K9G6E2<4>5@7B9D:E;G8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlNkNkLiKhJeHcF`D\AY?VG[q}:M=P?SAUCXEZG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYDWDWBUAS?Q>N;K9I6Flv8A3=4?6@8B9D;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlNkMjLiJgIdGaE^C[@W>T>O;N=Q@TBVDXEZG]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYDWDWBUAT@R>O5?7A8C:E;G;H8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlNkNjMiKhIfHbF`D]AY?VPc:MR@UBWDYF[G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXDWCUBT@R?O=M;J8G6E=G2=4>6@7B9D:F;G;G8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmNkNkMiLhJfHdFaE^B[@W>T;N8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmNlNkMjMiKgIeGbE_C\AY?UpBSN5@7B9D9E:F;G8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmNlMjMiLgJfHcFaD]AZ?WAX:M=P>R@UBWDYE[G\G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXCVCUBT@Q>O=M:J8G6E3<2<4>6@7B8D9E:F;G8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnNlNkMiLhKfIdFaD^B[@X>Ut;N>Q?SAVCXEZF[G]G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXCVCUBTAR?P=N:K8I6Fpz1;3=5?6A7C8D:E;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnOmNkMjLhKfIdHbE_C\AY?Vj{=NR@TBWCYEZF\G]G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXCVCVBUAR@Q>O;L9I7G8EW^2;4>5?6A7B9D:E;E8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnOmOlMjLiKfJeHbF`C]AZ?VI^;M=P?S@UBXDZE[G\G]G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWCVCUBS@Q?O5@6A7B9D:E;E;F;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoOmOlNkLiKhJeHcF`D^A[@X>UTdQ@TAVCYE[F[G]G]G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWCVCVBSAR?P=N;K9I7EOZ1;3<3>5?6A8C9C:E:F;E;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoOnOlNkMkKhJfHcGaD^C[@Y>V:N5@7A8B9C9E:E;E;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpPnOnOmNkMjLiJfHdGaE^C[AY>Vmz;O>Q@TBWCXDZF\G\G]H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWCVCTBSAR>P5@7@8B8C9D:D;E;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpPoPnOmNlMjLiKgHdGaE^C[AY?Vo:M

RAUCXCYE[F\G]G]H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWCVCUBTAR?Q=O;L9I7F5DZa1:2<4>5?7@7B8C9D:D;E;F;F8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpPoPoOmNlMkLhKgIeGaE_C[AY@Wdu;N=Q?SBVDYDZE\G]G]H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWCUCTBS?Q>P8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpPoPoPnOnNlMkLiJfIeHbE_C\AY@W\n=O

S@UBWDZE[F\G^G]H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWCUCUBT@R?P=N;K9H7F7EKR1;2;4=4?6?7A8B9C:D:E;E;E8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpPoPoPnOmNlNjLiJgIdGbE_C\AZ?VcsO5?7A8B9C9D:D;D;E;D;D;D;D;D;C;C:C:C:C:C:B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqQpQoPnOnOmNlMkLhJfHeGaE_C]AY?Wq=O=P>S@VBWDZF\F\G^G^H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVCUCUAT@R?P=M;K9H7E7E[a1:1;3<4=5?6@7A8C9C:D:D;D:D:C;C;D;C;C:C:C:C:C:B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrQpQpQoPnOmNlNkMjKhJfHdFbE^C\AZ?W~Q?TAWCXE[F]F]G^G^H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVCUCUATAS?Q>N6@7A8A9B9C:C:C:C:C;C;B;C:C:C:C:C:B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrQqQqQoPoPnOlNlMjLiKhJfHcFaD_C[AY?W;M=P?S@VBXDZF\G]G^G^H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVCUBTAS@R?O=M;K9G7E5C081:2;3=4>5?7@8A8B9A9B9B:B:C:B;B:B:C:C:C:B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsQrQrQqQpPpPnOmOmNkLiKhJfIeGcF`C^B\AYJ`lyQ@TBWCYE[F]G^G^G^H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVCUBUATAS?P>N6?7@8@8A8A9A9B:A:B9B9B:B:B:B:B9B9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsQrQrQrQrQqPpPoOnOmNlMjLhJgIeHdGbE`D]A[@Yk};N=P?SBVBXD[F\G]H^G^H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVBUBUAT@Q?O=M;J9H7F6BPW091:2;3<4=5>6?6?7?8@8A9@9A9A9B9B9B9A:A9A9A9A9A9@9@8@8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+ONsNsNrTxVyVxUxUwUwUwUwUwTwTvTvTvTuStRtRsRsRsRrQqQqPqPpPpOnNmNlMjLiKhJeHdGbF`D^C]AZ?XM^R@TCWDZE\F]H^H_G^H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVBUBUATAR?P>O5>6>7?8?8@7@8A8A9A9A9A8A8@9@9@9?9?8?8?8?8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< p b am6Vą#H#G+NMrMrMqSwUxUwTwTvTvTvTvTvSvSuSuSuStStRtRrRrQrQpPpOoOoOnNnMlMkLjKhJfIeHbFaE_C]B[AZi{;O>Q@SBVDYD[F]G]H^H_H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVBUBUAS@Q?P=M6=7>6?7?7@8@8@8@7@8?8@8@8?8?7?7>7>8?8?8?8?8>8>8>8=7=7=7<7<7=7<7< o b am5V#G#F*NMrMqMpSvUwUvTvTuTuTuTuTuRuRtRtRtRsRrQrQqPpPpPnNnNnMmMlLkLiKhJgIeHcGaE_C]B[AZKa;N=P?SAUCXEZE\G^H^H_H_H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVBUBUBSAR@Q>N=L;J9F7D7D6>0819192:3;4<5<5<5=5>6>7?7>7?7?7?7?7?7>8>7>7>7>7>7>7>7>7=7=7=7<6<6<6;6;6<6;6; o a `l5T"G"F*MLpLpLoRuTvTuSuStStRsRsRsQsQrQrQrQqQpOpOoOoOnNlMlLkLjKiJhIfHeGcFaE`D^C\AZC\Zk

R@TBWDYF[F]G_H^H_I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVBUBTAS@R?O=M6=6>6>7=7=6=6=6=6=6=6=6=6<6<6<6;5;5;5:5:5;5:6; n ` _k3S"F"E)LKnKnKmPsRsRrQrQqQqQqQqQqPqPpPpOpOoOnNnMlMlLkLjKiJhIgIfHeGbFaE`D^C\B[H^;P>Q@TBVCXE[G\G^H_H_I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVBTBSAR@P?N=L;I9G8E5B3:/7071828292:3;3;4;4<4<4<5<5<5<5<5<5<5<5<5<5<5<5;5;5;5:4:4:49595:595: l _ ^j2R!E!D)KIlIlIjNpPpPpOpOoOoOoOoOnNnNmMmMlMkMkLjKiKhJhJfHeGdGcFbEaD_D^C]BZJa;O=Q?SAVCWDZF\G^G_H`H_I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVBTBTASAQ?O>NS@UBXDYF[G]H^H_H`I`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUBTBTAR@P?O=LR@UBWCYE[G\H^I_H`H`I`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUBTBTBRAQ@P?M=L;J9F7D5B[a.5.5/5.6/6/6060606060606060617171616161505050404051515 e YYb  .I A?%ECcBbB`GeHfHeGdGcGcGcGcGcFcFbFbFbE`E`D_C^C]B]B[[q;P=R?TAWCYE[F\G^H_I`H`IaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUBTBSARAQ?N>M$CA`@^@]DaEbE`D`D`D`D`D`D`C_C^C^C^C]Ri{=QS@VBYDZF\G]H^I_I`IaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUBSBSAR@P?N>L;J9G8E6C8Cfj:@,2-2-2-2-2-3-2-2-2-1,1,1,0,0-2-1.2 _ UV\ ︼L_T@VBXDZE\G^H^I_I`I`IaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUBSBSBRAP@O?NS@VBXCZE\F]H_I_I`I`JaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTBSBSBQAP@O=LM=LS?UAWBZD[F^G_H_I`I`JaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTBRBRAQ?O>M=L;J:H7E6C4A M=K;I9G7D5B4@ MM;K:H8F7D5A7B ?R=R?UAWBZD\E]F_G`HaIaIbJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSAQAQ@P@O?NNS?UAWBZD[F^G_G`HaIbIbIbJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRAQAQAQ@P>O=MS@VAWBZD[F^G_HaHaIbIcIbJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRAQAQAP?P>N=MS@VBXBZD[F^G_HaIbIbIcIcJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRAQAQ@P?O>N=M =R>T@VBXCZD\F^G_HaIbJcIcIcJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRAQ@Q@O?O>N=L m|>S?U@WBXD[E]F^G_HaIbJcJdIcJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBR@Q@P@O?O>M=L;J:H9F7D6B5@3?fn Tf>T@UAXBZD[E]G_G`HaIbJcJdJdJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRAR@P@P@O?N>M=L;I:H9G8D6B4A3?OY AT?T@VBXBZD\E]G_HaHaIbJcJdJdKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQ@P@P@N?N=M=KS?UAWBYDZD\F_G`HaIbIcJcJdJdKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQ@P@O@O>N>L=K ]n>T?VAXCZD\F]F_HaHaIbJdJcJdJdKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQ@O@O?O>M>L=KT\ >S?T@VBYC[E]F_G_HaIcJcJdKdJdJdKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAP@O?O?N>M>M=K2< kz?T@VAWBYD[E]F_HaIaIcJdKdKeKeKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P?N?N?M>L=K3=dj >T?UAWBYDZD\F^G`HaIcJcJdKeKeKeLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O?N?N?L>L=KL=LV@VAXBZD[E]F_H_HaIcJdKeKfLeKfKfLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O?M?M>M>L=L=J3<2;lr >U?WAYBYC[E]F^G`HaIbIcJdKeKfLgLfLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?M>M>L=K=J3=2<1; @X?W@XAZC[D\E^G`H`IbJcKdKeKfLfLgLgMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?M>M>L>K=K3=2<2= ?V@W@YAZB[D]E^F_GaHcIcJdKeLeKfLgLgLgMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?M?L>L>K=J=I2=1;0: n?V@WAYBZB\D^E^F`GaHbIcJeKeLfLgMfLgLgMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?L>L>K>J=J=HK>K=I=H;H;F:E9D8C7B6A5?4>3=2;2:0:V] AY@XAZAZC\D\D^F_GaGbHdIdJeKfKfLgLhMgMhMhNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?K>K>J>J3<2<1:092: K`@YAZBZC[D]D^E_F_GaHbIdIeJfJfKgLhLhMhMiMhNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?J>J=J=H3<2;1:1:09:C QhAZAZB[C\C]D^E_F`FaGbHcIdJeKfJgKhLhLhLiMiMiMiNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?J>J=I=I=H4=3<2<2;1:0908DJ atAYAZB[B\C]D^E^E_FaGaHbHdHdIeJeKfLgLhLiLiLiMjMjMiNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>I>I=I=I=H;H;F:F:E9C8C7B6@6?5?4>4=3<2;2:1918/7/6TYPfA[B[B[C\D\C]D^E_F`GbGbGcHdIdJeJfJgKgLgLhMiMiLjMkMjMjNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>I>I=IK>J>J>J>J>I=I5>4<3<2:2:29181707/6/6.6.5.4MRpt (B?<"A@^?\>[C_D_D_C_C^C^C^C^C^C^C]C]C^C]C^B^C]C^C^D^C^D_D_D`EaE`FaFbGbGbHcIcHdIeJfJgKhLhLiLiMiMjMkMjMkNjNkNkNkNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=H=H4<4<3;3:3:191818080706.6.5.5.5.3.3-3-2-2,2,2,2,2,1,1,1,0+0+0+/,0,1,0-1 [ TUV  #Av@>!@BaA`A^EbFcFbEbFbFbFbFbFbEbEaEaFbFaFaEaEaFaFbFaFbFbFcGdGdHdHeIeIeJfKgKgKhKhLiMjMkNjMkMlNkNlOlNlNlNkNkOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=H=G6>5=5<5<3;3;2:2:29281807070705/5/5.4.4.4.4.4.4.3.3.3.2-2-2-1-1.2.2.3 Y VW Vt  ;c B? @CdCcCaGfIgIfHfHeHeHeHeIfHfHeHeHeHdHeHeHeHeIeIeHeIfIfIgJhJgKhKiLiLiMjMiMjMkNkNlNlOlNlNmOlOmOmNlOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H6=5=5=4<4<4;3:2:29292917170706060606060605050504/4/4/3/3/4/4/3 W XXP`  8D!C A @AcFgEeIhLkLjKjKiKiKiKiKiJiJiKiKiKiKiJiKhKiKiLiKiKjLjLjLkMjMkMlNkNlNlOlNlOmOmOnOnPmOnOnOmOmPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H6>5=5=4<4;4;3;39392928282828282817171716161615151616+0 Y ZZNA /q!D!C!B>_HjHiJjOoOnNnNmNmNmNmNmMmMlMlMlMlMlMlMlMlMlNlMlMlMmNmNnNmOnOnOmPnPnPmOnPnPnPoPoPnOnPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H7>6>5=5=5<5;5;4;4:3:3:3:3:3:39393938282827282837%* [ \ \7$G!D!D7YJmIkJlQrQqPqPpPpPpPpPpOpOpOpOpOoPoOoOoOoOoOnOnOoOoOoOoPoPoPpPoQoQoQoPoPoPoQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H7>6>6=6=5=5<5<5<5<5;5;5:5:5:59494948494949  ] ^ _#G"E"E.PKoKnKnRrSsRsRrRrRrRrRsQsQrQrQrQqQqPqPpQqQqQpPpPpPqPqQqQpQqQqQpQpQpRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H7>6>6=6=6=6=6=6=6<6<6<6;5;5;5;5;5;5:s _ _ ^#Fm"F"F#GJnLoLoPsTuSuStStStStStRuRtRtRtRsRsQsRrRrRrRqQrQrQrQrQrQqQqRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H7>7>7>7>7>7=7=7=7<6<6<6<6<6<38 c ` ` `h"E%#F#F#F=bMqMqNrUvTwTvTvTvTvTvSvSuSuSuStStRtRsRsRsRrQrRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H7>7>7>7>7=7=7=7<6<6<6<6<6<#( b a a]!#G#G#G-RNrNrNrQtTwUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8>8>8=7=7>7=7=7=x c b b$Hj#G#G"GDiNrNrPsTxUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8>8>8=7=7=7=7=,1 c c b cg$I#G#G"G1UNrNrNqRuUwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8>8>8=7>7>7=7=| c c bb $H#G"G"FDhNrNqOqTwUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8>8>8>7>7>7=+1 d c c c|K#G"G"F*NMqNqNqPrUwUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8>8>7>7>7>6<r c c cf#Hn"G"F"F8\NqNqNqPsUwUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8>8>7>7>7>" d c c cjU"G"F"F#FBgNqNqNpQsUwUwTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H8?8?7>7>*0 d d c c$I*"F"F"F&JGkNqNpNpQsUvTwTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=H/6 k d d ce&!E\"F"F"F(KJlNpNpNpOrSvTvTvTvTuTuSuStStStSsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=HK>J>J>J>J>J=J=I=I=I=H=HK>J>J>J>J>J=J=I=I=I=H=HK>J>J>J>J>J=J=I=I=I=H=H& g f e e ef#E"E"E!E!D+MDgNpNpMoMoMoMnNpOqQrRsRsRsRsRsRsRrRrRrRqRqRqRpQpQpQpQpQpQoPoPoPnPnPnOmOmOlOlOlOlNlNlNkNkNkNjNjNjNiNiNiNhMhMhMhMhMhMgLgLgLfLfLfKeKeKeKeKeKeJdJdJdJcJcJcJbJbJaJaJaJaIaIaI`I`I`H_H_H_H^H^H^G]G]G]G]G]G]G\G\G\G[G[G[FZFZFZFYFYFYEYEYEYEXEXDWDWDWDVDVDVCVCVCVCUCUCUCTCTCTCSCSCSBRBRBRBRBRARAQAQAQAPAP@P@O@O@O@N@N?N?N?N?M?M?M?L?L?L?K?K>K>J>J>J>J>J=J=I=I=I=H=HN>N>N>M>M>M>L>L=L=K=K=K=K=J=JN>N>N>M>M>M>L>L=L=K=K=K=K=J=J(0i h g g f f f-@@!Du!D!D!D!C!C C#F/P:\EeLmMmLmLmLlLlLlLlLlKlKlKkKkKkKjKjKjJjJiJiJiJhJhJhJhJhJhJhJgJgJgJfIfIfIeIeIeIeIeHeHeHdHdHdHdHcGcGcGbGbGbGaGaGaGaGaGaGaG`G`G`F_F_F_F_F^F^F^F]E]E]E]E]E]E]E\D\D\D[D[D[D[DZDZCZCYCYCYCYCYCYCYCXCXCXCWCWCWCVBVBVBVBVBVBVBUAUAUATATATATASAS@S@R@R@R@R@R@R?R?Q?Q?Q?P?P?P?P?O?O?O?N?N?N?N>N>N>N>M>M>M>L>L=L=K=K=K=K=J=J'>'>'>'>'='='='='<'<'<%<%<%;%;%:%:%:%:$9$9$9$9$8$8$8$8#7#7#7#7#6#6#6#6"6"6"5"4"4"4"4"3!3!3!3!3!3!3 2 1 1 1 0 0 0 0 0 000....-------,+++********)))''''''''&&&&$$$$$$$#"""!!! |uljjjiihh i g h$I!B{!C C B B B B A A AA@@@@????>>>====<<<<;;;;::::9998888777766665555444333322221111000////....----,,,,+++****))))((((''''&&&%%%%$$$$####""""!!!    ~~~}}}|| { { { z z y y y x x w w w v v u u u t t s s s r r r q q p p p o o n n n m m l llkkjjjiiiiz f"D< A B B B A A AA@@@@????>>>====<<<<;;;;::::9998888777766665555444333322221111000////....----,,,,+++****))))((((''''&&&%%%%$$$$####""""!!!    ~~~}}}|| { { { z z y y y x x w w w v v u u u t t s s s r r r q q p p p o o n n n m m l llkkjjkj j:9 C*BQAr Ay B@ A A A ? ? ??>>>>>>><<<<;;;;;;;;9998888888866665555555333322222222000////////----,,,,,,,****))))))))''''&&&&&&&$$$$########!!!        ~~~}}}}}{{{zzzzz x x w w w w w u u u t t t t t r r r q q q q q o o n n n n n l mky kr lP g*q ???doublecmd-1.1.22/src/doublecmd.lpi0000644000175000001440000023025014743153644016043 0ustar alexxusers <Scaled Value="True"/> <ResourceType Value="res"/> <XPManifest> <DpiAware Value="True"/> </XPManifest> <Icon Value="0"/> <Resources Count="1"> <Resource_0 FileName="dmhigh.json" Type="RCDATA" ResourceName="HIGHLIGHTERS"/> </Resources> </General> <i18n> <EnableI18N Value="True"/> <OutDir Value="..\language"/> </i18n> <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="1"/> <MinorVersionNr Value="1"/> <RevisionNr Value="22"/> <Attributes pvaPreRelease="True"/> <StringTable FileDescription="Double Commander" InternalName="DOUBLECMD" LegalCopyright="Copyright (C) 2006-2024 Alexander Koblov" ProductName="Double Commander"/> </VersionInfo> <BuildModes Count="5"> <Item1 Name="Debug" Default="True"/> <Item2 Name="Debug + HeapTrc"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\doublecmd"/> </Target> <SearchPaths> <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/> <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin;filesources\gio\trash;filesources\winnet\wsl;filesources\shellfolder;platform\win\winrt;filesources\gio\network"/> <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/> <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> </Checks> <Optimizations> <OptimizationLevel Value="0"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> </Debugging> </Linking> <Other> <CustomOptions Value="-dHEAPTRC -dHEAPTRC_EXTRA"/> <ExecuteBefore> <Command Value="$(ProjPath)\platform\git2revisioninc$(ExeExt).cmd $MakeFile($(ProjOutDir))"/> <CompileReasons Run="False"/> </ExecuteBefore> </Other> </CompilerOptions> </Item2> <Item3 Name="NoDebug Full Optimizations"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\doublecmd"/> </Target> <SearchPaths> <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/> <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin;filesources\gio\trash;filesources\winnet\wsl;filesources\shellfolder;platform\win\winrt;filesources\gio\network"/> <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/> <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Optimizations> <OptimizationLevel Value="3"/> <VariablesInRegisters Value="True"/> <UncertainOptimizations Value="True"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> <UseLineInfoUnit Value="False"/> </Debugging> </Linking> <Other> <ExecuteBefore> <Command Value="$(ProjPath)\platform\git2revisioninc$(ExeExt).cmd $MakeFile($(ProjOutDir))"/> <CompileReasons Run="False"/> </ExecuteBefore> </Other> </CompilerOptions> </Item3> <Item4 Name="Release"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\doublecmd"/> </Target> <SearchPaths> <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/> <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin;filesources\gio\trash;filesources\winnet\wsl;filesources\shellfolder;platform\win\winrt;filesources\gio\network"/> <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/> <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/> </SearchPaths> <Conditionals Value="if (TargetOS = 'linux') then begin LinkerOptions += ' -z relro --as-needed'; end; if LCLWidgetType <> GetIDEValue('LCLWidgetType') then begin UnitPath += '$(FallbackOutputRoot)/LazControls/lib/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);'; UnitPath += '$(FallbackOutputRoot)/SynEdit/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);'; end; if ((LCLWidgetType = 'qt') or (LCLWidgetType = 'qt5')) and (TargetOS <> 'darwin') then begin UnitPath += 'platform/$(SrcOS)/qt5;'; end; if (LCLWidgetType = 'gtk2') and (SrcOS = 'unix') and (TargetOS <> 'darwin') then begin UnitPath += 'platform/$(SrcOS)/$(LCLWidgetType);'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> </Checks> <Optimizations> <OptimizationLevel Value="2"/> <VariablesInRegisters Value="True"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseLineInfoUnit Value="False"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> <CustomOptions Value="-dNIGHTLY_BUILD"/> <ExecuteBefore> <Command Value="$(ProjPath)\platform\git2revisioninc$(ExeExt).cmd $MakeFile($(ProjOutDir))"/> <CompileReasons Run="False"/> </ExecuteBefore> </Other> </CompilerOptions> </Item4> <Item5 Name="DarkWin"> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\doublecmd"/> </Target> <SearchPaths> <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/> <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin;..\components\DDetours\Source;filesources\gio\trash;filesources\winnet\wsl;filesources\shellfolder;platform\win\winrt;filesources\gio\network"/> <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/> <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <RelocatableUnit Value="True"/> <Checks> <IOChecks Value="True"/> </Checks> <Optimizations> <OptimizationLevel Value="2"/> <VariablesInRegisters Value="True"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseLineInfoUnit Value="False"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <PassLinkerOptions Value="True"/> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> <Other> <Verbosity> <ShowNotes Value="False"/> <ShowHints Value="False"/> </Verbosity> <CustomOptions Value="-dNIGHTLY_BUILD -dDARKWIN"/> <ExecuteBefore> <Command Value="$(ProjPath)\platform\git2revisioninc$(ExeExt).cmd $MakeFile($(ProjOutDir))"/> <CompileReasons Run="False"/> </ExecuteBefore> </Other> </CompilerOptions> </Item5> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"> <local> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="13"> <Item1> <PackageName Value="SynUni"/> <MinVersion Major="1" Minor="8" Release="2" Valid="True"/> </Item1> <Item2> <PackageName Value="DateTimeCtrls"/> </Item2> <Item3> <PackageName Value="kascrypt"/> <MinVersion Major="3" Valid="True"/> </Item3> <Item4> <PackageName Value="chsdet"/> </Item4> <Item5> <PackageName Value="LazControls"/> <MinVersion Valid="True"/> </Item5> <Item6> <PackageName Value="pkg_gifanim"/> <MinVersion Major="1" Minor="5" Valid="True"/> </Item6> <Item7> <PackageName Value="VirtualTerminal"/> </Item7> <Item8> <PackageName Value="KASComp"/> <MinVersion Major="1" Minor="9" Release="4" Valid="True"/> </Item8> <Item9> <PackageName Value="LCL"/> <MinVersion Major="2" Minor="2" Valid="True"/> </Item9> <Item10> <PackageName Value="SynEdit"/> <MinVersion Major="1" Valid="True"/> </Item10> <Item11> <PackageName Value="viewerpackage"/> </Item11> <Item12> <PackageName Value="doublecmd_common"/> <MinVersion Minor="4" Release="1" Valid="True"/> </Item12> <Item13> <PackageName Value="Image32"/> </Item13> </RequiredPackages> <Units Count="273"> <Unit0> <Filename Value="doublecmd.lpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="fmain.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMain"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMain"/> </Unit1> <Unit2> <Filename Value="uwcxprototypes.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWCXprototypes"/> </Unit2> <Unit3> <Filename Value="fviewer.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmViewer"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fViewer"/> </Unit3> <Unit4> <Filename Value="feditor.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmEditor"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fEditor"/> </Unit4> <Unit5> <Filename Value="fMsg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMsg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit5> <Unit6> <Filename Value="dmcommondata.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="dmComData"/> <HasResources Value="True"/> <ResourceBaseClass Value="DataModule"/> <UnitName Value="dmCommonData"/> </Unit6> <Unit7> <Filename Value="dmhigh.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="dmHigh"/> </Unit7> <Unit8> <Filename Value="ffindview.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmFindView"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fFindView"/> </Unit8> <Unit9> <Filename Value="fAbout.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmAbout"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit9> <Unit10> <Filename Value="foptions.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptions"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fOptions"/> </Unit10> <Unit11> <Filename Value="fFileOpDlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmFileOp"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit11> <Unit12> <Filename Value="fmkdir.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMkDir"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMkDir"/> </Unit12> <Unit13> <Filename Value="fcopymovedlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmCopyDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fCopyMoveDlg"/> </Unit13> <Unit14> <Filename Value="fFindDlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmFindDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit14> <Unit15> <Filename Value="fsymlink.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSymLink"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSymLink"/> </Unit15> <Unit16> <Filename Value="fhardlink.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmHardLink"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fHardLink"/> </Unit16> <Unit17> <Filename Value="fmultirename.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMultiRename"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMultiRename"/> </Unit17> <Unit18> <Filename Value="fpackdlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmPackDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fPackDlg"/> </Unit18> <Unit19> <Filename Value="flinker.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmLinker"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fLinker"/> </Unit19> <Unit20> <Filename Value="fsplitter.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSplitter"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSplitter"/> </Unit20> <Unit21> <Filename Value="ffileproperties.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmFileProperties"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fFileProperties"/> </Unit21> <Unit22> <Filename Value="fextractdlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmExtractDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fExtractDlg"/> </Unit22> <Unit23> <Filename Value="ulng.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uLng"/> </Unit23> <Unit24> <Filename Value="frames\foptionsfileassocextra.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFileAssocExtra"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFileAssocExtra"/> </Unit24> <Unit25> <Filename Value="fhackform.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmHackForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fHackForm"/> </Unit25> <Unit26> <Filename Value="fpackinfodlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmPackInfoDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fPackInfoDlg"/> </Unit26> <Unit27> <Filename Value="ftweakplugin.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmTweakPlugin"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fTweakPlugin"/> </Unit27> <Unit28> <Filename Value="udescr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDescr"/> </Unit28> <Unit29> <Filename Value="fdescredit.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmDescrEdit"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fDescrEdit"/> </Unit29> <Unit30> <Filename Value="platform\win\ugdiplus.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uGdiPlus"/> </Unit30> <Unit31> <Filename Value="platform\win\umywindows.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMyWindows"/> </Unit31> <Unit32> <Filename Value="platform\unix\umyunix.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMyUnix"/> </Unit32> <Unit33> <Filename Value="dmhelpmanager.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="dmHelpManager"/> <HasResources Value="True"/> <ResourceBaseClass Value="DataModule"/> <UnitName Value="dmHelpManager"/> </Unit33> <Unit34> <Filename Value="feditsearch.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmEditSearchReplace"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fEditSearch"/> </Unit34> <Unit35> <Filename Value="platform\udragdropex.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDragDropEx"/> </Unit35> <Unit36> <Filename Value="ushellexecute.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uShellExecute"/> </Unit36> <Unit37> <Filename Value="platform\uClipboard.pas"/> <IsPartOfProject Value="True"/> </Unit37> <Unit38> <Filename Value="platform\udragdropgtk.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDragDropGtk"/> </Unit38> <Unit39> <Filename Value="usearchtemplate.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uSearchTemplate"/> </Unit39> <Unit40> <Filename Value="platform\ukeyboard.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uKeyboard"/> </Unit40> <Unit41> <Filename Value="platform\udragdropqt.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDragDropQt"/> </Unit41> <Unit42> <Filename Value="fchecksumverify.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmCheckSumVerify"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fCheckSumVerify"/> </Unit42> <Unit43> <Filename Value="fchecksumcalc.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmCheckSumCalc"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fCheckSumCalc"/> </Unit43> <Unit44> <Filename Value="uformcommands.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFormCommands"/> </Unit44> <Unit45> <Filename Value="ufileviewnotebook.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileViewNotebook"/> </Unit45> <Unit46> <Filename Value="platform\unix\mime\umimeactions.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMimeActions"/> </Unit46> <Unit47> <Filename Value="fsetfileproperties.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSetFileProperties"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSetFileProperties"/> </Unit47> <Unit48> <Filename Value="platform\upixmapgtk.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uPixMapGtk"/> </Unit48> <Unit49> <Filename Value="uquickviewpanel.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uQuickViewPanel"/> </Unit49> <Unit50> <Filename Value="fmaskinputdlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMaskInputDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMaskInputDlg"/> </Unit50> <Unit51> <Filename Value="platform\uinfotooltip.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uInfoToolTip"/> </Unit51> <Unit52> <Filename Value="fattributesedit.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmAttributesEdit"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fAttributesEdit"/> </Unit52> <Unit53> <Filename Value="fmodview.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmModView"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fModView"/> </Unit53> <Unit54> <Filename Value="fdiffer.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmDiffer"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fDiffer"/> </Unit54> <Unit55> <Filename Value="fconnectionmanager.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmConnectionManager"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fConnectionManager"/> </Unit55> <Unit56> <Filename Value="ffileexecuteyourself.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmFileExecuteYourSelf"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fFileExecuteYourSelf"/> </Unit56> <Unit57> <Filename Value="uthumbnails.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uThumbnails"/> </Unit57> <Unit58> <Filename Value="platform\utrash.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uTrash"/> </Unit58> <Unit59> <Filename Value="uparitercontrols.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uPariterControls"/> </Unit59> <Unit60> <Filename Value="ucmdlineparams.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uCmdLineParams"/> </Unit60> <Unit61> <Filename Value="upathlabel.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uPathLabel"/> </Unit61> <Unit62> <Filename Value="frames\foptionstooltips.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsToolTips"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolTips"/> </Unit62> <Unit63> <Filename Value="frames\foptionsframe.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="OptionsEditor"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFrame"/> </Unit63> <Unit64> <Filename Value="frames\foptionspluginsgroup.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsGroup"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsGroup"/> </Unit64> <Unit65> <Filename Value="frames\foptionsfiletypescolors.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFileTypesColors"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFileTypesColors"/> </Unit65> <Unit66> <Filename Value="platform\utarwriter.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uTarWriter"/> </Unit66> <Unit67> <Filename Value="uconvencoding.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uConvEncoding"/> </Unit67> <Unit68> <Filename Value="uvfsmodule.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uVfsModule"/> </Unit68> <Unit69> <Filename Value="frames\foptionslanguage.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsLanguage"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsLanguage"/> </Unit69> <Unit70> <Filename Value="frames\foptionsbehavior.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsBehavior"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsBehavior"/> </Unit70> <Unit71> <Filename Value="frames\foptionstools.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsViewer"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsTools"/> </Unit71> <Unit72> <Filename Value="frames\foptionshotkeys.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsHotkeys"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsHotkeys"/> </Unit72> <Unit73> <Filename Value="frames\foptionslayout.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsLayout"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsLayout"/> </Unit73> <Unit74> <Filename Value="frames\foptionsfonts.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFonts"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFonts"/> </Unit74> <Unit75> <Filename Value="frames\foptionsfileoperations.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFileOperations"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFileOperations"/> </Unit75> <Unit76> <Filename Value="frames\foptionsquicksearchfilter.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsQuickSearchFilter"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsQuickSearchFilter"/> </Unit76> <Unit77> <Filename Value="frames\foptionstabs.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsTabs"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsTabs"/> </Unit77> <Unit78> <Filename Value="frames\foptionslog.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsLog"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsLog"/> </Unit78> <Unit79> <Filename Value="frames\foptionsconfiguration.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsConfiguration"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsConfiguration"/> </Unit79> <Unit80> <Filename Value="frames\foptionscustomcolumns.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsCustomColumns"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsCustomColumns"/> </Unit80> <Unit81> <Filename Value="frames\foptionsmisc.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsMisc"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsMisc"/> </Unit81> <Unit82> <Filename Value="frames\foptionsautorefresh.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsAutoRefresh"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsAutoRefresh"/> </Unit82> <Unit83> <Filename Value="frames\foptionsicons.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsIcons"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsIcons"/> </Unit83> <Unit84> <Filename Value="frames\foptionsignorelist.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsIgnoreList"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsIgnoreList"/> </Unit84> <Unit85> <Filename Value="frames\foptionsarchivers.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsArchivers"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsArchivers"/> </Unit85> <Unit86> <Filename Value="fselecttextrange.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSelectTextRange"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSelectTextRange"/> </Unit86> <Unit87> <Filename Value="frames\fquicksearch.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmQuickSearch"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fQuickSearch"/> </Unit87> <Unit88> <Filename Value="frames\foptionsgroups.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="fOptionsGroups"/> </Unit88> <Unit89> <Filename Value="frames\foptionsfilepanelscolors.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFilePanelsColors"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFilePanelsColors"/> </Unit89> <Unit90> <Filename Value="frames\foptionstoolbase.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsToolBase"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolBase"/> </Unit90> <Unit91> <Filename Value="frames\foptionsterminal.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsTerminal"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsTerminal"/> </Unit91> <Unit92> <Filename Value="frames\foptionsmouse.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsMouse"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsMouse"/> </Unit92> <Unit93> <Filename Value="frames\foptionskeyboard.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsKeyboard"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsKeyboard"/> </Unit93> <Unit94> <Filename Value="frames\foptionsdragdrop.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsDragDrop"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsDragDrop"/> </Unit94> <Unit95> <Filename Value="frames\foptionsfilesviews.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFilesViews"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFilesViews"/> </Unit95> <Unit96> <Filename Value="frames\foptionscolumnsview.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsColumnsView"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsColumnsView"/> </Unit96> <Unit97> <Filename Value="frames\foptionsdriveslistbutton.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsDrivesListButton"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsDrivesListButton"/> </Unit97> <Unit98> <Filename Value="platform\unix\uoverlayscrollbarfix.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uOverlayScrollBarFix"/> </Unit98> <Unit99> <Filename Value="umaincommands.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMainCommands"/> </Unit99> <Unit100> <Filename Value="platform\win\uexceptionhandlerfix.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uExceptionHandlerFix"/> </Unit100> <Unit101> <Filename Value="frames\foptionseditorcolors.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsEditorColors"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsEditorColors"/> </Unit101> <Unit102> <Filename Value="uoperationspanel.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uOperationsPanel"/> </Unit102> <Unit103> <Filename Value="foptionshotkeysedithotkey.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmEditHotkey"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fOptionsHotkeysEditHotkey"/> </Unit103> <Unit104> <Filename Value="ukastoolitemsextended.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uKASToolItemsExtended"/> </Unit104> <Unit105> <Filename Value="frames\foptionstoolbar.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsToolbar"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolbar"/> </Unit105> <Unit106> <Filename Value="fileviews\ufileviewwithmainctrl.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileViewWithMainCtrl"/> </Unit106> <Unit107> <Filename Value="filesources\uarchivefilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uArchiveFileSource"/> </Unit107> <Unit108> <Filename Value="filesources\uarchivefilesourceutil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uArchiveFileSourceUtil"/> </Unit108> <Unit109> <Filename Value="filesources\ufilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSource"/> </Unit109> <Unit110> <Filename Value="filesources\ufilesourcecalcchecksumoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceCalcChecksumOperation"/> </Unit110> <Unit111> <Filename Value="filesources\ufilesourcecalcstatisticsoperation.pas"/> <IsPartOfProject Value="True"/> </Unit111> <Unit112> <Filename Value="filesources\ufilesourcecombineoperation.pas"/> <IsPartOfProject Value="True"/> </Unit112> <Unit113> <Filename Value="filesources\ufilesourcecopyoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceCopyOperation"/> </Unit113> <Unit114> <Filename Value="filesources\ufilesourcecreatedirectoryoperation.pas"/> <IsPartOfProject Value="True"/> </Unit114> <Unit115> <Filename Value="filesources\ufilesourcedeleteoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceDeleteOperation"/> </Unit115> <Unit116> <Filename Value="filesources\ufilesourceexecuteoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceExecuteOperation"/> </Unit116> <Unit117> <Filename Value="filesources\ufilesourcelistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceListOperation"/> </Unit117> <Unit118> <Filename Value="filesources\ufilesourcemoveoperation.pas"/> <IsPartOfProject Value="True"/> </Unit118> <Unit119> <Filename Value="filesources\ufilesourceoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceOperation"/> </Unit119> <Unit120> <Filename Value="filesources\ufilesourceoperationmessageboxesui.pas"/> <IsPartOfProject Value="True"/> </Unit120> <Unit121> <Filename Value="filesources\ufilesourceoperationmisc.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceOperationMisc"/> </Unit121> <Unit122> <Filename Value="filesources\ufilesourceoperationoptions.pas"/> <IsPartOfProject Value="True"/> </Unit122> <Unit123> <Filename Value="filesources\ufilesourceoperationoptionsui.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="FileSourceOperationOptionsUI"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="uFileSourceOperationOptionsUI"/> </Unit123> <Unit124> <Filename Value="filesources\ufilesourceoperationtypes.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceOperationTypes"/> </Unit124> <Unit125> <Filename Value="filesources\ufilesourceoperationui.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceOperationUI"/> </Unit125> <Unit126> <Filename Value="filesources\ufilesourceproperty.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceProperty"/> </Unit126> <Unit127> <Filename Value="filesources\ufilesourcesetfilepropertyoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceSetFilePropertyOperation"/> </Unit127> <Unit128> <Filename Value="filesources\ufilesourcesplitoperation.pas"/> <IsPartOfProject Value="True"/> </Unit128> <Unit129> <Filename Value="filesources\ufilesourcetestarchiveoperation.pas"/> <IsPartOfProject Value="True"/> </Unit129> <Unit130> <Filename Value="filesources\ufilesourceutil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceUtil"/> </Unit130> <Unit131> <Filename Value="filesources\ufilesourcewipeoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSourceWipeOperation"/> </Unit131> <Unit132> <Filename Value="filesources\ulocalfilesource.pas"/> <IsPartOfProject Value="True"/> </Unit132> <Unit133> <Filename Value="filesources\uoperationthread.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uOperationThread"/> </Unit133> <Unit134> <Filename Value="filesources\urealfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uRealFileSource"/> </Unit134> <Unit135> <Filename Value="filesources\uvirtualfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uVirtualFileSource"/> </Unit135> <Unit136> <Filename Value="filesources\filesystem\ffilesystemcopymoveoperationoptions.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="FileSystemCopyMoveOperationOptionsUI"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fFileSystemCopyMoveOperationOptions"/> </Unit136> <Unit137> <Filename Value="filesources\filesystem\ufilesystemcalcchecksumoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemCalcChecksumOperation"/> </Unit137> <Unit138> <Filename Value="filesources\filesystem\ufilesystemcalcstatisticsoperation.pas"/> <IsPartOfProject Value="True"/> </Unit138> <Unit139> <Filename Value="filesources\filesystem\ufilesystemcombineoperation.pas"/> <IsPartOfProject Value="True"/> </Unit139> <Unit140> <Filename Value="filesources\filesystem\ufilesystemcopyoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemCopyOperation"/> </Unit140> <Unit141> <Filename Value="filesources\filesystem\ufilesystemcreatedirectoryoperation.pas"/> <IsPartOfProject Value="True"/> </Unit141> <Unit142> <Filename Value="filesources\filesystem\ufilesystemdeleteoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemDeleteOperation"/> </Unit142> <Unit143> <Filename Value="filesources\filesystem\ufilesystemexecuteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit143> <Unit144> <Filename Value="filesources\filesystem\ufilesystemfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemFileSource"/> </Unit144> <Unit145> <Filename Value="filesources\filesystem\ufilesystemlistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemListOperation"/> </Unit145> <Unit146> <Filename Value="filesources\filesystem\ufilesystemmoveoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemMoveOperation"/> </Unit146> <Unit147> <Filename Value="filesources\filesystem\ufilesystemsetfilepropertyoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemSetFilePropertyOperation"/> </Unit147> <Unit148> <Filename Value="filesources\filesystem\ufilesystemsplitoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemSplitOperation"/> </Unit148> <Unit149> <Filename Value="filesources\filesystem\ufilesystemutil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileSystemUtil"/> </Unit149> <Unit150> <Filename Value="filesources\filesystem\ufilesystemwipeoperation.pas"/> <IsPartOfProject Value="True"/> </Unit150> <Unit151> <Filename Value="filesources\multiarchive\fmultiarchivecopyoperationoptions.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="MultiArchiveCopyOperationOptionsUI"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMultiArchiveCopyOperationOptions"/> </Unit151> <Unit152> <Filename Value="filesources\multiarchive\umultiarchivecalcstatisticsoperation.pas"/> <IsPartOfProject Value="True"/> </Unit152> <Unit153> <Filename Value="filesources\multiarchive\umultiarchivecopyinoperation.pas"/> <IsPartOfProject Value="True"/> </Unit153> <Unit154> <Filename Value="filesources\multiarchive\umultiarchivecopyoutoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiArchiveCopyOutOperation"/> </Unit154> <Unit155> <Filename Value="filesources\multiarchive\umultiarchivedeleteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit155> <Unit156> <Filename Value="filesources\multiarchive\umultiarchiveexecuteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit156> <Unit157> <Filename Value="filesources\multiarchive\umultiarchivefilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiArchiveFileSource"/> </Unit157> <Unit158> <Filename Value="filesources\multiarchive\umultiarchivelistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiArchiveListOperation"/> </Unit158> <Unit159> <Filename Value="filesources\multiarchive\umultiarchivetestarchiveoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiArchiveTestArchiveOperation"/> </Unit159> <Unit160> <Filename Value="filesources\multiarchive\umultiarchiveutil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiArchiveUtil"/> </Unit160> <Unit161> <Filename Value="filesources\multilist\umultilistfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiListFileSource"/> </Unit161> <Unit162> <Filename Value="filesources\multilist\umultilistlistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiListListOperation"/> </Unit162> <Unit163> <Filename Value="filesources\searchresult\usearchresultfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uSearchResultFileSource"/> </Unit163> <Unit164> <Filename Value="filesources\searchresult\usearchresultlistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uSearchResultListOperation"/> </Unit164> <Unit165> <Filename Value="filesources\tempfilesystem\utempfilesystemfilesource.pas"/> <IsPartOfProject Value="True"/> </Unit165> <Unit166> <Filename Value="filesources\vfs\uvfsexecuteoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uVfsExecuteOperation"/> </Unit166> <Unit167> <Filename Value="filesources\vfs\uvfsfilesource.pas"/> <IsPartOfProject Value="True"/> </Unit167> <Unit168> <Filename Value="filesources\vfs\uvfslistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uVfsListOperation"/> </Unit168> <Unit169> <Filename Value="filesources\wcxarchive\fwcxarchivecopyoperationoptions.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="WcxArchiveCopyOperationOptionsUI"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fWcxArchiveCopyOperationOptions"/> </Unit169> <Unit170> <Filename Value="filesources\wcxarchive\uwcxarchivecalcstatisticsoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveCalcStatisticsOperation"/> </Unit170> <Unit171> <Filename Value="filesources\wcxarchive\uwcxarchivecopyinoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveCopyInOperation"/> </Unit171> <Unit172> <Filename Value="filesources\wcxarchive\uwcxarchivecopyoutoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveCopyOutOperation"/> </Unit172> <Unit173> <Filename Value="filesources\wcxarchive\uwcxarchivedeleteoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveDeleteOperation"/> </Unit173> <Unit174> <Filename Value="filesources\wcxarchive\uwcxarchiveexecuteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit174> <Unit175> <Filename Value="filesources\wcxarchive\uwcxarchivefilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveFileSource"/> </Unit175> <Unit176> <Filename Value="filesources\wcxarchive\uwcxarchivelistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveListOperation"/> </Unit176> <Unit177> <Filename Value="filesources\wcxarchive\uwcxarchivetestarchiveoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWcxArchiveTestArchiveOperation"/> </Unit177> <Unit178> <Filename Value="filesources\wfxplugin\fwfxplugincopymoveoperationoptions.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="WfxPluginCopyMoveOperationOptionsUI"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fWfxPluginCopyMoveOperationOptions"/> </Unit178> <Unit179> <Filename Value="filesources\wfxplugin\uwfxplugincopyinoperation.pas"/> <IsPartOfProject Value="True"/> </Unit179> <Unit180> <Filename Value="filesources\wfxplugin\uwfxplugincopyoperation.pas"/> <IsPartOfProject Value="True"/> </Unit180> <Unit181> <Filename Value="filesources\wfxplugin\uwfxplugincopyoutoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWfxPluginCopyOutOperation"/> </Unit181> <Unit182> <Filename Value="filesources\wfxplugin\uwfxplugincreatedirectoryoperation.pas"/> <IsPartOfProject Value="True"/> </Unit182> <Unit183> <Filename Value="filesources\wfxplugin\uwfxplugindeleteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit183> <Unit184> <Filename Value="filesources\wfxplugin\uwfxpluginexecuteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit184> <Unit185> <Filename Value="filesources\wfxplugin\uwfxpluginfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWfxPluginFileSource"/> </Unit185> <Unit186> <Filename Value="filesources\wfxplugin\uwfxpluginlistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWfxPluginListOperation"/> </Unit186> <Unit187> <Filename Value="filesources\wfxplugin\uwfxpluginmoveoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWfxPluginMoveOperation"/> </Unit187> <Unit188> <Filename Value="filesources\wfxplugin\uwfxpluginsetfilepropertyoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWfxPluginSetFilePropertyOperation"/> </Unit188> <Unit189> <Filename Value="filesources\wfxplugin\uwfxpluginutil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWfxPluginUtil"/> </Unit189> <Unit190> <Filename Value="filesources\winnet\uwinnetexecuteoperation.pas"/> <IsPartOfProject Value="True"/> </Unit190> <Unit191> <Filename Value="filesources\winnet\uwinnetfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWinNetFileSource"/> </Unit191> <Unit192> <Filename Value="filesources\winnet\uwinnetlistoperation.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWinNetListOperation"/> </Unit192> <Unit193> <Filename Value="fileviews\ubrieffileview.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uBriefFileView"/> </Unit193> <Unit194> <Filename Value="fileviews\ucolumnsfileview.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uColumnsFileView"/> </Unit194> <Unit195> <Filename Value="fileviews\ucolumnsfileviewvtv.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uColumnsFileViewVtv"/> </Unit195> <Unit196> <Filename Value="fileviews\ufileview.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileView"/> </Unit196> <Unit197> <Filename Value="fileviews\ufileviewheader.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileViewHeader"/> </Unit197> <Unit198> <Filename Value="fileviews\ufileviewhistory.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileViewHistory"/> </Unit198> <Unit199> <Filename Value="fileviews\ufileviewwithpanels.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileViewWithPanels"/> </Unit199> <Unit200> <Filename Value="fileviews\ufileviewworker.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileViewWorker"/> </Unit200> <Unit201> <Filename Value="fileviews\uorderedfileview.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uOrderedFileView"/> </Unit201> <Unit202> <Filename Value="fopenwith.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOpenWith"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fOpenWith"/> </Unit202> <Unit203> <Filename Value="platform\unix\ukeyfile.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uKeyFile"/> </Unit203> <Unit204> <Filename Value="fsyncdirsdlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSyncDirsDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSyncDirsDlg"/> </Unit204> <Unit205> <Filename Value="fsyncdirsperformdlg.pas"/> <IsPartOfProject Value="True"/> <HasResources Value="True"/> <UnitName Value="fSyncDirsPerformDlg"/> </Unit205> <Unit206> <Filename Value="platform\unix\glib\ugio2.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uGio2"/> </Unit206> <Unit207> <Filename Value="platform\unix\glib\ugobject2.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uGObject2"/> </Unit207> <Unit208> <Filename Value="platform\unix\glib\uglib2.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uGLib2"/> </Unit208> <Unit209> <Filename Value="uspecialdir.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uSpecialDir"/> </Unit209> <Unit210> <Filename Value="fstartingsplash.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmStartingSplash"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit210> <Unit211> <Filename Value="frames\foptionsdirectoryhotlist.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsDirectoryHotlist"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="foptionsDirectoryHotlist"/> </Unit211> <Unit212> <Filename Value="fhotdirexportimport.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmhotdirexportimport"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit212> <Unit213> <Filename Value="platform\unix\mime\umimecache.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMimeCache"/> </Unit213> <Unit214> <Filename Value="platform\unix\uxdg.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uXdg"/> </Unit214> <Unit215> <Filename Value="platform\unix\mime\umimetype.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMimeType"/> </Unit215> <Unit216> <Filename Value="frames\foptionstoolsdiffer.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsDiffer"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolsDiffer"/> </Unit216> <Unit217> <Filename Value="frames\foptionsfileassoc.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFileAssoc"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFileAssoc"/> </Unit217> <Unit218> <Filename Value="frames\foptionsbriefview.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsBriefView"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsBriefView"/> </Unit218> <Unit219> <Filename Value="fmaincommandsdlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMainCommandsDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMainCommandsDlg"/> </Unit219> <Unit220> <Filename Value="frames\fsearchplugin.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSearchPlugin"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fSearchPlugin"/> </Unit220> <Unit221> <Filename Value="udiffonp.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDiffONP"/> </Unit221> <Unit222> <Filename Value="udiffond.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDiffOND"/> </Unit222> <Unit223> <Filename Value="fdeletedlg.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmDeleteDlg"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fDeleteDlg"/> </Unit223> <Unit224> <Filename Value="ufavoritetabs.pas"/> <IsPartOfProject Value="True"/> </Unit224> <Unit225> <Filename Value="frames\foptionsfavoritetabs.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFavoriteTabs"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFavoriteTabs"/> </Unit225> <Unit226> <Filename Value="frames\foptionstoolseditor.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsEditor"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolsEditor"/> </Unit226> <Unit227> <Filename Value="frames\foptionstabsextra.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsTabsExtra"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsTabsExtra"/> </Unit227> <Unit228> <Filename Value="uaccentsutils.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uAccentsUtils"/> </Unit228> <Unit229> <Filename Value="frames\foptionstreeviewmenu.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsTreeViewMenu"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsTreeViewMenu"/> </Unit229> <Unit230> <Filename Value="frames\foptionstreeviewmenucolor.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsTreeViewMenuColor"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsTreeViewMenuColor"/> </Unit230> <Unit231> <Filename Value="uglobs.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uGlobs"/> </Unit231> <Unit232> <Filename Value="ftreeviewmenu.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmTreeViewMenu"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fTreeViewMenu"/> </Unit232> <Unit233> <Filename Value="fmultirenamewait.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmMultiRenameWait"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fMultiRenameWait"/> </Unit233> <Unit234> <Filename Value="filesources\multiarchive\umultiarchiveparser.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uMultiArchiveParser"/> </Unit234> <Unit235> <Filename Value="frames\foptionsfilesearch.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFileSearch"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFileSearch"/> </Unit235> <Unit236> <Filename Value="uexifreader.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uExifReader"/> </Unit236> <Unit237> <Filename Value="fviewoperations.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmViewOperations"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fViewOperations"/> </Unit237> <Unit238> <Filename Value="ffileunlock.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmFileUnlock"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fFileUnlock"/> </Unit238> <Unit239> <Filename Value="frames\foptionspluginsbase.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsBase"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsBase"/> </Unit239> <Unit240> <Filename Value="frames\foptionspluginsdsx.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsDSX"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsDSX"/> </Unit240> <Unit241> <Filename Value="frames\foptionspluginswcx.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsWCX"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsWCX"/> </Unit241> <Unit242> <Filename Value="frames\foptionspluginswdx.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsWDX"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsWDX"/> </Unit242> <Unit243> <Filename Value="frames\foptionspluginswfx.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsWFX"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsWFX"/> </Unit243> <Unit244> <Filename Value="frames\foptionspluginswlx.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsPluginsWLX"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsPluginsWLX"/> </Unit244> <Unit245> <Filename Value="uhotdir.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uHotDir"/> </Unit245> <Unit246> <Filename Value="ufilefunctions.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uFileFunctions"/> </Unit246> <Unit247> <Filename Value="frames\foptionsfilesviewscomplement.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsFilesViewsComplement"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsFilesViewsComplement"/> </Unit247> <Unit248> <Filename Value="frames\foptionstoolbarextra.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsToolbarExtra"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolbarExtra"/> </Unit248> <Unit249> <Filename Value="frames\foptionsdirectoryhotlistextra.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsDirectoryHotlistExtra"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsDirectoryHotlistExtra"/> </Unit249> <Unit250> <Filename Value="uvariablemenusupport.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uVariableMenuSupport"/> </Unit250> <Unit251> <Filename Value="fbenchmark.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmBenchmark"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fBenchmark"/> </Unit251> <Unit252> <Filename Value="filesources\gio\fgioauthdlg.pas"/> <IsPartOfProject Value="True"/> <HasResources Value="True"/> <UnitName Value="fGioAuthDlg"/> </Unit252> <Unit253> <Filename Value="filesources\gio\fgiocopymoveoperationoptions.pas"/> <IsPartOfProject Value="True"/> <HasResources Value="True"/> <UnitName Value="fGioCopyMoveOperationOptions"/> </Unit253> <Unit254> <Filename Value="fconfirmcommandline.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="TfrmConfirmCommandLine"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fConfirmCommandLine"/> </Unit254> <Unit255> <Filename Value="uwdxmodule.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uWDXModule"/> </Unit255> <Unit256> <Filename Value="uluapas.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uLuaPas"/> </Unit256> <Unit257> <Filename Value="fprintsetup.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmPrintSetup"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fPrintSetup"/> </Unit257> <Unit258> <Filename Value="frames\foptionstoolbarbase.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsToolbarBase"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolbarBase"/> </Unit258> <Unit259> <Filename Value="frames\foptionstoolbarmiddle.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsToolbarMiddle"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsToolbarMiddle"/> </Unit259> <Unit260> <Filename Value="frames\foptionsmultirename.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsMultiRename"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsMultiRename"/> </Unit260> <Unit261> <Filename Value="fsortanything.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSortAnything"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSortAnything"/> </Unit261> <Unit262> <Filename Value="fselectpathrange.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSelectPathRange"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSelectPathRange"/> </Unit262> <Unit263> <Filename Value="rpc\uadministrator.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uAdministrator"/> </Unit263> <Unit264> <Filename Value="fselectduplicates.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmSelectDuplicates"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fSelectDuplicates"/> </Unit264> <Unit265> <Filename Value="rpc\sys\felevation.pas"/> <IsPartOfProject Value="True"/> <HasResources Value="True"/> <UnitName Value="fElevation"/> </Unit265> <Unit266> <Filename Value="frames\foptionscolors.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmOptionsColors"/> <HasResources Value="True"/> <ResourceBaseClass Value="Frame"/> <UnitName Value="fOptionsColors"/> </Unit266> <Unit267> <Filename Value="filesources\gio\trash\utrashfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uTrashFileSource"/> </Unit267> <Unit268> <Filename Value="platform\unix\darwin\udarwinfswatch.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uDarwinFSWatch"/> </Unit268> <Unit269> <Filename Value="fchooseencoding.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="frmChooseEncoding"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="fChooseEncoding"/> </Unit269> <Unit270> <Filename Value="uhighlighters.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uHighlighters"/> </Unit270> <Unit271> <Filename Value="filesources\shellfolder\ushellfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uShellFileSource"/> </Unit271> <Unit272> <Filename Value="filesources\gio\network\unetworkfilesource.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="uNetworkFileSource"/> </Unit272> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="..\doublecmd"/> </Target> <SearchPaths> <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/> <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin;filesources\gio\trash;filesources\winnet\wsl;filesources\shellfolder;platform\win\winrt;filesources\gio\network"/> <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/> <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/> </SearchPaths> <Conditionals Value="if TargetOS = 'darwin' then begin UsageCustomOptions += ' -k-macosx_version_min -k10.5'; UsageCustomOptions += ' -XR/Developer/SDKs/MacOSX10.5.sdk/'; end;"/> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> </Checks> <Optimizations> <OptimizationLevel Value="0"/> <VariablesInRegisters Value="True"/> <UncertainOptimizations Value="True"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> </Debugging> </Linking> <Other> <ExecuteBefore> <Command Value="$(ProjPath)\platform\git2revisioninc$(ExeExt).cmd $MakeFile($(ProjOutDir))"/> <CompileReasons Run="False"/> </ExecuteBefore> </Other> </CompilerOptions> <Debugging> <Exceptions Count="1"> <Item1> <Name Value="EXmlConfigNotFound"/> </Item1> </Exceptions> </Debugging> </CONFIG> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/doublecmd.lpr������������������������������������������������������������������0000644�0001750�0000144�00000015253�14743153644�016060� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program doublecmd; {$IF DEFINED(LCLGTK3)} {$FATAL LCLGTK3 is not production ready} {$ENDIF} uses {$IFDEF MSWINDOWS} uElevation, {$IFDEF LCLQT5} uDarkStyle, {$ENDIF} {$ENDIF} {$IFDEF UNIX} {$IFNDEF HEAPTRC} cmem, {$ENDIF} cthreads, {$IFDEF DARWIN} iosxwstr, iosxlocale, {$ELSE} cwstring, clocale, {$ENDIF} {$IFDEF darwin} uAppleMagnifiedModeFix, uMyDarwin, {$ENDIF} uElevation, {$IFDEF LINUX} uAppImage, {$ENDIF} {$IFDEF LCLGTK2} uOverlayScrollBarFix, gtk2, Gtk2Int, {$ENDIF} {$IF DEFINED(LCLQT5) and not DEFINED(DARWIN)} uQt5Workaround, {$ENDIF} {$ENDIF} uSystem, uMoveConfig, uEarlyConfig, DCConvertEncoding, {$IF DEFINED(LCLWIN32) and DEFINED(DARKWIN)} uWin32WidgetSetDark, {$ENDIF} Interfaces, {$IFDEF LCLGTK2} uGtk2FixCursorPos, {$ENDIF} {$IFDEF LCLWIN32} uDClass, {$IF NOT DEFINED(DARKWIN)} uWin32WidgetSetFix, {$ENDIF} {$ENDIF} LCLProc, Classes, SysUtils, Forms, LCLVersion, Math, {$IF DEFINED(NIGHTLY_BUILD)} un_lineinfo, {$ENDIF} uGlobsPaths, uGlobs, fHackForm, fMain, uAccentsUtils, dmHigh, dmHelpManager, dmCommonData, uShowMsg, uCryptProc, uPixMapManager, uKeyboard, uUniqueInstance, uDCVersion, uCmdLineParams, uDebug, uOSUtils, uspecialdir, fstartingsplash, ulog, uVariableMenuSupport, uLng {$IFDEF MSWINDOWS} , uMyWindows {$ENDIF} {$IFDEF UNIX} , uMyUnix {$ENDIF} ; {$R *.res} {$IF DEFINED(MSWINDOWS)} {$SETPEOPTFLAGS $140} {$R doublecmd.manifest.rc} {$ENDIF} {$IFDEF HEAPTRC} var LogPath: String; {$ENDIF} begin // Initialize again uSystem.Initialize; DCDebug('Starting Double Commander'); // Initialize random number generator Randomize; {$IF DEFINED(NIGHTLY_BUILD)} InitLineInfo; AddLineInfoPath(ExtractFileDir(ParamStr(0))); {$ENDIF} {$IFDEF HEAPTRC} LogPath := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'logs'; CreateDir(LogPath); SetHeapTraceOutput(LogPath + '/heaptrc-' + FormatDateTime('yyyy-mm-dd hh.mm.ss', Now) + '.log'); {$ENDIF} {$IFDEF MSWINDOWS} uMyWindows.FixCommandLineToUTF8; {$ENDIF} Application.Scaled:= True; // Fix default BidiMode // see http://bugs.freepascal.org/view.php?id=22044 Application.BidiMode:= bdLeftToRight; Application.Title:='Double Commander'; Application.Initialize; {$IF DEFINED(DARWIN)} GetMacFormatSettings(DefaultFormatSettings); Application.Icon:= nil; {$ENDIF} uDCVersion.InitializeVersionInfo; // Initializing keyboard module on GTK needs GTKProc.InitKeyboardTables // which is called by Application.Initialize. uKeyboard.InitializeKeyboard; {$IF DEFINED(MSWINDOWS) and (DEFINED(LCLQT5) or DEFINED(DARKWIN))} ApplyDarkStyle; {$ENDIF} {$IF DEFINED(darwin)} FixMacFormatSettings; setMacOSAppearance( gAppMode ); {$ENDIF} // Use only current directory separator AllowDirectorySeparators:= [DirectorySeparator]; // Disable because we set a few of our own format settings and we don't want // them to be changed. There's no way currently to react to Application.IntfSettingsChange. // If in future we move to a Unicode RTL this could be removed. {$PUSH}{$WARN SYMBOL_PLATFORM OFF} Application.UpdateFormatSettings := False; {$POP} if Ord(DefaultFormatSettings.ThousandSeparator) > $7F then begin DefaultFormatSettings.ThousandSeparator:= ' '; end; {$IFDEF UNIX} uMyUnix.FixDateTimeSeparators; {$ENDIF} FixDateNamesToUTF8; DCDebug('Double Commander ' + dcVersion); DCDebug('Revision: ' + dcRevision); DCDebug('Commit: ' + dcCommit); DCDebug('Build: ' + dcBuildDate); DCDebug('Lazarus: ' + lazVersion); DCDebug('Free Pascal: ' + fpcVersion); DCDebug('Platform: ' + TargetCPU + '-' + TargetOS + '-' + TargetWS); DCDebug('System: ' + OSVersion); {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} DCDebug('Desktop Environment: ' + DesktopName[DesktopEnv]); {$ENDIF} if WSVersion <> EmptyStr then DCDebug('Widgetset library: ' + WSVersion); DCDebug('This program is free software released under terms of GNU GPL 2'); DCDebug(Copyright + LineEnding + ' and contributors (see about dialog)'); Application.ShowMainForm:= False; Application.CreateForm(TfrmHackForm, frmHackForm); ProcessCommandLineParams; // before load paths if (gSplashForm) and (not CommandLineParams.NoSplash) then begin // Let's show the starting slash screen to confirm user application has been started Application.CreateForm(TfrmStartingSplash, frmStartingSplash); end; LoadInMemoryOurAccentLookupTableList; // Used for conversion of string to remove accents. LoadPaths; // before loading config LoadWindowsSpecialDir; // Load the list with special path. *Must* be located AFTER "LoadPaths" and BEFORE "InitGlobs" if InitGlobs then //-- NOTE: before, only IsInstanceAllowed was called, and all the magic on creation // new instance or sending params to the existing server happened inside // IsInstanceAllowed() function as a side effect. // Functions with side effects are generally bad, so, // new function was added to explicitly initialize instance. InitInstance; if IsInstanceAllowed then begin if (log_start_shutdown in gLogOptions) then logWrite(rsMsgLogProgramStart + ' (' + GetCurrentUserName + '/' + GetComputerNetName + ')'); InitPasswordStore; LoadPixMapManager; Application.CreateForm(TfrmMain, frmMain); // main form Application.CreateForm(TdmComData, dmComData); // common data Application.CreateForm(TdmHelpManager, dmHelpMgr); // help manager {$IF DEFINED(LCLGTK2)} // LCLGTK2 uses Application.MainForm as the clipboard widget, however our // MainForm is TfrmHackForm and it never gets realized. GTK2 doesn't // seem to allow a not realized widget to have clipboard ownership. // We switch to frmMain instead which will be realized at some point. GTK2WidgetSet.SetClipboardWidget(PGtkWidget(frmMain.Handle)); {$ENDIF} // Hooking on QT needs the handle of the main form which is created // in Application.CreateForm above. uKeyboard.HookKeyboardLayoutChanged; frmMain.ShowOnTop; Application.ProcessMessages; Application.Run; if not UniqueInstance.isAnotherDCRunningWhileIamRunning then DeleteTempFolderDeletableAtTheEnd; FreeMemoryFromOurAccentLookupTableList; if (log_start_shutdown in gLogOptions) then logWrite(rsMsgLogProgramShutdown + ' (' + GetCurrentUserName + '/' + GetComputerNetName + ')'); end else begin DCDebug('Another instance of DC is already running. Exiting.'); end; uKeyboard.CleanupKeyboard; DCDebug('Finished Double Commander'); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/doublecmd.manifest.rc����������������������������������������������������������0000644�0001750�0000144�00000000145�14743153644�017466� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define RT_MANIFEST 24 #define APP_MANIFEST 1 APP_MANIFEST RT_MANIFEST "doublecmd.exe.manifest" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fAbout.lfm���������������������������������������������������������������������0000644�0001750�0000144�00000040061�14743153644�015316� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmAbout: TfrmAbout Left = 563 Height = 400 Top = 209 Width = 667 AutoSize = True BorderIcons = [biSystemMenu, biMaximize] Caption = 'About' ClientHeight = 400 ClientWidth = 667 Constraints.MinWidth = 667 KeyPreview = True OnCreate = FormCreate OnShow = frmAboutShow Position = poOwnerFormCenter LCLVersion = '3.5.0.0' object pnlText: TPanel AnchorSideLeft.Control = pnlInfo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 138 Height = 384 Top = 8 Width = 521 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Around = 8 BevelInner = bvRaised BevelOuter = bvLowered ClientHeight = 384 ClientWidth = 521 FullRepaint = False ParentFont = False TabOrder = 0 object lblHomePage: TLabel AnchorSideLeft.Control = memInfo AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = pnlText AnchorSideBottom.Side = asrBottom Left = 10 Height = 15 Top = 352 Width = 65 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 15 Caption = 'Home Page:' ParentColor = False ParentFont = False end object lblHomePageAddress: TLabel AnchorSideLeft.Control = lblHomePage AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = pnlText AnchorSideBottom.Side = asrBottom Left = 81 Height = 15 Top = 352 Width = 180 Anchors = [akLeft, akBottom] BorderSpacing.Left = 6 BorderSpacing.Top = 8 BorderSpacing.Bottom = 15 Caption = 'https://doublecmd.sourceforge.io' Font.Color = clBlue ParentColor = False ParentFont = False OnClick = lblHomePageAddressClick OnMouseEnter = lblHomePageAddressMouseEnter OnMouseLeave = lblHomePageAddressMouseLeave end object memInfo: TMemo AnchorSideLeft.Control = pnlText AnchorSideTop.Control = pnlText AnchorSideRight.Control = pnlText AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = lblHomePage Left = 10 Height = 334 Top = 10 Width = 501 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 8 BorderSpacing.Top = 8 BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 ParentFont = False ReadOnly = True ScrollBars = ssAutoBoth TabOrder = 0 end end object pnlInfo: TPanel Left = 9 Height = 253 Top = 9 Width = 121 AutoSize = True BorderSpacing.Around = 8 BevelOuter = bvNone ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 253 ClientWidth = 121 Constraints.MinHeight = 334 ParentFont = False TabOrder = 1 object imgLogo: TImage Left = 28 Height = 64 Top = 8 Width = 64 BorderSpacing.Top = 8 BorderSpacing.Bottom = 8 BorderSpacing.CellAlignHorizontal = ccaCenter Center = True Picture.Data = { 1754506F727461626C654E6574776F726B47726170686963D610000089504E47 0D0A1A0A0000000D4948445200000040000000400806000000AA6971DE000000 0970485973000013AF000013AF0163E68EC30000001974455874536F66747761 7265007777772E696E6B73636170652E6F72679BEE3C1A000010634944415478 9CED9B79901F4775C73F6FAEDFB99776B52BAD2DAD8D2C5F088BD896B108B688 8B0470C58194A99429822109458070958D2988932A02A6A89439420C011C0713 A8C4260125E13038408C1593C3088365CB8714C992AD952CEDFDDBDF3DD3FDF2 C7CCFCF4DB43BBABDD35B8125ED5ECFC76A6FB75BF6FBF7EFD5ECF6BF825FDFF 2639D58B7B7F6353BF35FCB68B7D998A9CA18A6754C18255050503A805551BFF 56C5C6AF500BD66AEBBD45514D9EA34449216B897929287179AB8A85989749EA ABB6BD074BF2DCC4FC503036EEBB5145AD4691B1C30DB50FB8C6DF795BB93CB2 2400765F72893FBD76E2532ADE1B7BBABA0BF942D195A4582AB85A4D3A10FF51 55688191084A0C46DC5B8D416903416DFC3F8930315F1BD7C1C6E514B0F1BDD5 9E8DDB8BEB26F56D1B78D07ADE88229E9D98320726262B4D6BBEDC9CACDD703B 84A704E09E579F93C93BEE7F7477F76C5DDBD7EFBA9EAB204967B4EDAE2D015A A39A76CA265AD02ADF5627014FD1B69157D15490F672ED3C12A16D0232AA49D9 A44C0A70AB6CAC15621557958C55F61C3D66F68D8E3E2C53B597DE068D5466A7 1D80A2E7FEDDDADEB55B07D6AD7383C057115960923CFF498987BB24C2858383 EE85FD035BB5A7F895F6322D0076FDD6791705BEFFAA356B7B5DCFF3F4E7DDD9 E79A2AC0F9EBFADD9CE75FFDD69EC28BD2E72900629CCC0DDD3D7D791547436B 89AC1259C524EA16AB788CEAF395D2FEA553C86ADCFFF49AB6CA796BFB0A819F B99144B7BDE4875F6D345F5E735C31F550554112C32622382A88802B820BC433 439E1760A4425B558C85C8248387C51AC5A8C5D89306BB98CFD268863B001F08 3D40EEBFFFFEDB326347078362012F08926156A2CA34CDC951EA4F3D49F3F0FF E0DB888C2304AE832F0E9E1303F18B3014E9481B552263695A4BC3581A91C178 011D176CA1EFFC17925FDB4FA6B32B19AC78ADEC2895CEF8DDB3CEBE6DC78E1D 6FF7003CCFBBB6B0798BBFA6AF8F5C2E37AF34AA4A657C8CD281C774F4DEAFE3 8C0C93F75DB2AE8B2F0E223F3F109458F0A6B5D42343358CF0360CB1F977DEC0 C00B2FA2A3AFEF94FDA9D56A644747FD52A9742D1003B01412118ABD7D147BAF 94F5DBAEA03236C2F03DFFA0D30FDE47D1F3C9780EBE2B33979555A654D59BC6 528D22CA61C4DAAB5EC9B6EBDE4867FFC0B20661C900B4938850ECEBE7BCEBDF 29956B5ECFC1BFFD4BADECDF4B47C623E73C37DAA080B14ADD18CACD90EC8B2E E6AAF7DC44714DEF8AF82E0B80762AF4F4B2E53D1F92137B7EA2CFDCFE31BA5C 879CE7E139AB07820291B554224329522EFAE047D870E965AB02F4AA68AC8830 B0F552B9F0A37748A9D84BA919D234B1FFBE52B2AA84D6321D46347A07F8B53B FE9E8DDB5EB222E113CFD4C22A019052BEBB878B3EF469696E3887E9664898B8 A8CBA578E4957218618736B1E3139FA3D0DDB3B4BA895B6DAD9D711963D2BB81 550600C00F326CB9E12352EBDF40B919121ABB2C1052B52F4711E6CCB3B9E2A3 9F22C8665BEFDB3560B6B0C698D6FFB39FB78131038086908497D660AD694578 CB21CFF7B9E8FD1F934AA19B6A14614E53135283578D0C8DAE35BCF4C3B7E2B8 EE0C61A228C218D3BAB78D2CAA3AE37F6B0C61B349D46C629A4D6C1401948196 1793FDA7579E7B7470C3C66E713DB556314671FB06710737D275C99574BEE07C C9168AA705C4F4C871F6DEFC365D1378E45C27F61E97100D1AAB5443C35833E2 B24FDE4EE7C0FA189834EC56454466FC9FDE637F659C138FFC8C23BBEEA7FACC D3948F0EE320A04A9708DFDB7F60F2CEA9F22050F712C09B9D8167FBF3595CDF 8BE36BAB44B531A2FDA3541FDBCD6818A95C70311B5FF71629ACE95B12001D6B 0738E3FA7732FAE5CFE0657CFC25AC0CAD791F459CF5E67750E8EB2799AE33C8 5A3B437880C9679EE6913B3E4769CFC3048EE02364816C2668F9CC5D0219110B 34014D9741E3BB42D677F17C2F0E268CC5AA83058CA7140297DA813D3CF5676F D7DC8E6B38FB356F10C775E70A306B54062FDF21C7BEF375AD8F1FC7F5177794 ACC66BBDF60FB2F1CAAB5AA33A9B77BB06448D060F7FF10B8CDDF73D72E2D013 F8B82238C97B9B6EAEA812D05AFB671A41997539223822B82278AE43CE73E9CA F8F4E533D807BECD639FFA536DD4AA8B1A1F0586AEFF232987D1A2065181D05A 2AA1E19CDF7B0788CC305CEDBCD3E7E5B1517E74F3FB98DEF503BA7D9F82EF91 755C5C27EEFF6CB966EBE09256811410D771C8FB2EDD599FFCD1833C76CB7BB5 5E29CF5E5EE680D13DB4095D3F446311DF2075736570033D9BCE9D97673B20F5 A929FEFBE6F7E10C3F4D87EF91755D5C114E671FE7B496C11488C075E8C8F874 D4A6D87FC7AD1A369BF3AEB52D0B6D2D03575F2BB5C8109D6245482D7F2D320C FEE6B5F3ADDB335680B05E67F7ADB790999EA4E87B04E29C96E0CB02A0554904 DF118A818777F07186EFFFAEB67778F648596BE9DEFC42EA2A44890ACF0120F1 F81A38ACB9E045F33A30E9A5AAECDBF955F4D0010A9E9744A3CB9164058ED049 4DF098BAE7ABD44B5373E66AFBC83941407EEB36423BBF1D88E7BF52DC7A294E 90990362FBFC2F1F3FC6F17BBF49C177F11D59B6F02B0200621032AE4B4194A3 DFFF173D9573925EB9CD174A1A23B48390C6F7A1B514365F30EFC8B7F37EEA1B 3B298810AC42E4B9220004701D21E7B9941FDC8509C3793520BDF2679E45D3C6 8ECE6CB2C906477168D3BCF33EE5699A4D2677FF2719D7890DDE4A0460156201 4704DF75C88475A60EED5FD0170FBAD6101A1B7FB969B303E917A5D05AFCEE9E 05A7D2E8DE3D045184BF4AFB0E2BDE0F00F01C21E33A940F3EA9858D9B049823 A088204180143B50DB98C3C3AAE2143B7132D996E7379FB19CDAF704BE138FFE AAF47DA50C0470105C47A84F8CB4466EB6AFDE122657C096EB73F85855245B68 B9B8A7A2E6D4049E7372AD5FE98EC3AA6800124F857062AC0500CC1D415545FC 8039036B0CA65EC7E6E7FAFCB3A97AE800C1D123B89E87E37A88E781E723AE8F 93C99C76D7570780843431760B910D9B98D2048D6613AD5509EB754C18528D94 2673638BD964AA551A1363B802927C8CB536FD200BE20538D91C4E368B9B2FE0 E5F2E09C9AEFEA009084B26E67D7A2451B870FD01819C611109DA925B65A5DB4 7ED0DB474822EC9C7E28A65127AAD7E3A536F13A9D4C0EAFD841D0D505B342FA 1503107FC18E973629742E5ADE94A7E65DBA1CC096A716AD1FF4AEA5AE27BF08 2DDE4125AA56092B15AACF1EC3F53C8C755B6ABA2A5B629155EA8D3AD9C1A105 4D73549986E9A9791B15013B394E54292FD856F796AD849AC4B2CB208D22D446 2DEC5606802A616982CAD307983E364C71F396058B579F39842F12ABFFAC772E E0895079E6D0823CFA2FB98C289325D2956DB8A6B43C005431D393D40FEDA336 7C984AB98CB7F5729C2058B05AF9F13DF88EE0CEA327AE08BE03938FFE6CE10E 0719BAB75F4943D3B49A95D1E901602D66EC388D838F111E7B1AD368D0B04A59 85B5AF79E3A29E4975EF4FD497D86F682F9C6E54F822941EDEBD6837365DFF16 EA8E43C8CAB5606900A862A6C6691E7A8268EC386A4CE2BA2AE5C8125C7135D9 75672EC8A239394EF3893D04327FF4E608F802F5471FA23939B120AFE28621FA 5EF55AAA16C2156AC1A200D8CA34E1D3FB884E1C41E3EDE4587855CAC6521B18 A2FF757FB0E8E88F3DF07DB258BC05362D3C81AC5A9EBDEFDE453B7EFE1FBE0B 1D7A01358D33CE960BC229015013119D384274F410DA8C7DF724498BA655A643 CB445064DD3B3F2C6E36B760236A224AF7EED49C23A78CE0047011B28E70E25B FF889A68419E5EBEC0C51FFD24D58E2E2AAA2D4D385D20E605C04E8D111EDE87 2DC5AA980A6E54A919CB546899EA59C7C04D9F90A06F60D146467EF85DFC8913 044EBC029CB233028180377A9C63F7FDEBA27CF3EB07D9F6E9BF261ADC485995 BA26E9742C1D8816000AD828223A769868E4283699E7469375DE584AA165B469 A85EB08DF51FF8B464D76F58B481A85A66FC6B776AC115FC45E277215E0AF38E 30FCE5CF13562A8BF2EF183A9BCB3FFF2532DBAF60CA2A15255E21980946FBD5 4EA993ECBE61D39A9BB2532772A6D9A06995A6551A261EF17268990C2D9581B3 295EFF3E5973F5EB65B1252FA5E1AF7C56FDFD7B28BAB1FAA73D483D60E564B2 51DA3901C25A9572B942EFB6972EDA869BC970C62B5E4561CB56460E1EA03C36 4AA48A49073001C400017000A7FA50643F49F2614480A054ABDB11C7E2781E56 21B2600B5D68773FFE792FA678D176C96E3C674942A734FEE02E1AF77F9B1ED7 C19399429E8ADAB560FC3B3B39F12BDBE8DF7EE592DA1BD87639FD97BE84C97D 4F7074D70F19F9AF1F517BF6188DD1712449AC74804622335017C0B9FBEEBBBF D953CCBFBAA7B35332994C2B809079BEFC2C95AACF3CC5F02DEFD5EEB04A4E04 8759599F49046754A595DD990430E9125B892CA56C812D1FBF9DE2C6B396DD17 1B454449A0D56C34182F9574BA5EFFCE75D75D778D03608C29E2674472059C7C 11375F5C91F0CDB1130C7FFC83DA1956C9269EDFE9ECDF08E00AE41CA150ABF0 E8CDEFA536727CD9FD713C8FA0B393A0B313AFA3032F9713634C119E83FC80C6 F1A31CF9F39BB4737A8CA21B7F3F58CEE6553C1520EF08D9F1133C7CE3DB281F 39BCDADD5D5D00A6F73EC4F02DEFD2E2F8313A3C27DEBA5A01BFD83D86822364 479FE56737BC95D19FFE78B5BA0BAC1200360C39BEF34E1DFF8B3FD69E46990E CFC177562765AE1D8462798AC73FF86EF6DDF9056C182E5A7729B4E20D91E947 7ECCF85D7FA5C1E8517A3D212312873A2BCC0F6AA7743A14447051C6EEFA2223 BBBECFE677DC48FFB6CB57C47B79005843E9E107297DF76E750F3F49B713E716 F8719E4D6B7F6E3529FE300BD944B36AC38779FC03EFE6C0055B18BAEE4DACDF FEB26519EE250360EA55AAFB1EA5BE77B7361EDA45A652A2DB814CE0B632AE9F 2BE1538AB7E06377D949F60F1A8F3FC2937F72234F74ADA1EFAA5FA7FFB2EDF4 BDF8E278337409E401D4EBF5BBAA0F7CEB52CF957C2DF05AC72F4CB58C4E8D63 4F0CA363CF12584BDE113A05FCC0C5174D322F92BDFFE748F0D9946A4346E28F 32BE42581AA7B4F36E46BE7617A1B8F8EB07C96D1822E8EDC32F76A089390E8C E5B048B577FBAFDE95F212C0FFC62BCEDEBBCE89CE0982405BD14F5A40C14171 547013A1D31DDDF4F84CEBB84B7A642675784EF57B014768CEEF567D6D9D4BB2 6DEDDAA44DAB4A686217384C9E1BD5245D3EE6D109FC086FFF97EAE116927479 05C2BCE3FC20E7BB9BBAFC58D1D2465049CE012927CF2969BB2FFF0BA5564A4F F2BF2FB15AFB809524204AEE1E30AD0E3EFC1BF1691A4DEBA9EFE9674BD62DAB 31E2398227F1E54AAC6EE946E6EA6500AF7E42F59C3C27E2682FBD77014FB9CE B4F5E4332463D75AAA77DC73F011A3FAED89081385E1CFFF04C4734C9DC04171 A3BA956FFC4DB9F968FA7C86AF5216E7CD13D6F9E96853C3B0D114350B7FA87C BE930364811EE0A038E1219187C66ACDDF6F2F3367A4775F72893FB566E25641 DFD4E950CCAAF544ED496304ADD3A369EE9DD1C438B41F60D4F4A0651C94A7B6 A375A6D040726E1293FC5063139E497B4A62F45223462BD33435B8A95D6A378A 24A731EBAA8C5A273A02E5267267FF74E3FD1F8268410052FAE6CBCFEDF39DF0 B5225C61D59E292A9E898F681225C2C6C765693BD498E4F0A5C6B2758832CE0B B26DC244C9014843DC5F63419313A3D628B605561B9FD6FBF424699C72DB3A3A 9B5864632D6A3532702454FE3DB4FE3FDF3E3D3DBA1C2DFA25FD5FA7FF05C879 747F48E5EE350000000049454E44AE426082 } Proportional = True end object lblTitle: TLabel Left = 0 Height = 15 Top = 80 Width = 111 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Double Commander' Font.Color = clRed Font.Style = [fsBold] ParentColor = False ParentFont = False end object lblVersion: TLabel Left = 0 Height = 15 Top = 99 Width = 38 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Version' ParentColor = False ParentFont = False end object lblRevision: TLabel Left = 0 Height = 15 Top = 118 Width = 44 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Revision' ParentColor = False ParentFont = False end object lblCommit: TLabel Left = 0 Height = 15 Top = 137 Width = 44 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Commit' ParentColor = False end object lblBuild: TLabel Left = 0 Height = 15 Top = 156 Width = 27 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Build' ParentColor = False ParentFont = False end object lblLazarusVer: TLabel Left = 0 Height = 15 Top = 175 Width = 39 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Lazarus' ParentColor = False ParentFont = False end object lblFreePascalVer: TLabel Left = 0 Height = 15 Top = 194 Width = 58 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Free Pascal' ParentColor = False ParentFont = False end object lblPlatform: TLabel Left = 0 Height = 1 Top = 213 Width = 1 BorderSpacing.CellAlignHorizontal = ccaLeftTop ParentColor = False ParentFont = False end object lblOperatingSystem: TLabel Left = 0 Height = 1 Top = 218 Width = 1 BorderSpacing.CellAlignHorizontal = ccaLeftTop ParentColor = False ParentFont = False end object lblWidgetsetVer: TLabel Left = 0 Height = 1 Top = 223 Width = 1 BorderSpacing.CellAlignHorizontal = ccaLeftTop ParentColor = False ParentFont = False end object btnCopyToClipboard: TButton Left = 0 Height = 25 Top = 228 Width = 121 AutoSize = True BorderSpacing.CellAlignHorizontal = ccaCenter Caption = 'Copy to clipboard' Constraints.MinWidth = 100 ParentFont = False TabOrder = 0 OnClick = btnCopyToClipboardClick end end object btnClose: TBitBtn AnchorSideLeft.Control = pnlInfo AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = pnlInfo AnchorSideTop.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 19 Height = 30 Top = 362 Width = 100 AutoSize = True BorderSpacing.Top = 20 BorderSpacing.Bottom = 8 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Close' Constraints.MinWidth = 100 Default = True Kind = bkClose ModalResult = 11 ParentFont = False TabOrder = 2 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fAbout.lrj���������������������������������������������������������������������0000644�0001750�0000144�00000003206�14743153644�015327� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":4691652,"name":"tfrmabout.caption","sourcebytes":[65,98,111,117,116],"value":"About"}, {"hash":122850234,"name":"tfrmabout.lblhomepage.caption","sourcebytes":[72,111,109,101,32,80,97,103,101,58],"value":"Home Page:"}, {"hash":92749407,"name":"tfrmabout.lblhomepageaddress.caption","sourcebytes":[104,116,116,112,115,58,47,47,100,111,117,98,108,101,99,109,100,46,115,111,117,114,99,101,102,111,114,103,101,46,105,111],"value":"https://doublecmd.sourceforge.io"}, {"hash":185879090,"name":"tfrmabout.lbltitle.caption","sourcebytes":[68,111,117,98,108,101,32,67,111,109,109,97,110,100,101,114],"value":"Double Commander"}, {"hash":214540302,"name":"tfrmabout.lblversion.caption","sourcebytes":[86,101,114,115,105,111,110],"value":"Version"}, {"hash":214997982,"name":"tfrmabout.lblrevision.caption","sourcebytes":[82,101,118,105,115,105,111,110],"value":"Revision"}, {"hash":78005252,"name":"tfrmabout.lblcommit.caption","sourcebytes":[67,111,109,109,105,116],"value":"Commit"}, {"hash":4833316,"name":"tfrmabout.lblbuild.caption","sourcebytes":[66,117,105,108,100],"value":"Build"}, {"hash":43026835,"name":"tfrmabout.lbllazarusver.caption","sourcebytes":[76,97,122,97,114,117,115],"value":"Lazarus"}, {"hash":86315532,"name":"tfrmabout.lblfreepascalver.caption","sourcebytes":[70,114,101,101,32,80,97,115,99,97,108],"value":"Free Pascal"}, {"hash":127162148,"name":"tfrmabout.btncopytoclipboard.caption","sourcebytes":[67,111,112,121,32,116,111,32,99,108,105,112,98,111,97,114,100],"value":"Copy to clipboard"}, {"hash":44709525,"name":"tfrmabout.btnclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fAbout.pas���������������������������������������������������������������������0000644�0001750�0000144�00000016611�14743153644�015327� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- About dialog Copyright (C) 2006-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fAbout; {$mode objfpc}{$H+} interface uses Graphics, Forms, Controls, StdCtrls, ExtCtrls, Buttons, SysUtils, Classes, LCLType, LMessages; type { TfrmAbout } TfrmAbout = class(TForm) btnClose: TBitBtn; btnCopyToClipboard: TButton; imgLogo: TImage; lblCommit: TLabel; lblWidgetsetVer: TLabel; lblPlatform: TLabel; lblOperatingSystem: TLabel; lblRevision: TLabel; lblHomePageAddress: TLabel; lblHomePage: TLabel; lblFreePascalVer: TLabel; lblTitle: TLabel; lblLazarusVer: TLabel; lblBuild: TLabel; lblVersion: TLabel; pnlText: TPanel; memInfo: TMemo; pnlInfo: TPanel; procedure btnCopyToClipboardClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure lblHomePageAddressClick(Sender: TObject); procedure lblHomePageAddressMouseEnter(Sender: TObject); procedure lblHomePageAddressMouseLeave(Sender: TObject); procedure frmAboutShow(Sender: TObject); private FMouseLeave, FMouseEnter: TColor; protected procedure UpdateStyle; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public { Public declarations } end; procedure ShowAboutBox(TheOwner: TComponent); implementation {$R *.lfm} uses Clipbrd, dmHelpManager, uDCVersion, uClipboard, uOSForms; const cIndention = LineEnding + #32#32; cAboutMsg = 'This program is free software under GNU GPL 2 license, see COPYING.txt file.' + LineEnding + LineEnding + 'Active developers: '+ cIndention + 'Alexander Koblov (alexx2000@mail.ru) - author, core developer' + cIndention + 'Rich Chang (rich2014.git@outlook.com) - developer' + LineEnding + LineEnding + 'Former developers: ' + cIndention + 'Denis Bisson (denis.bisson@denisbisson.org) - developer' + cIndention + 'Przemysław Nagay (cobines@gmail.com) - core developer' + cIndention + 'Dmitry Kolomiets (B4rr4cuda@rambler.ru) - developer' + cIndention + 'Radek Cervinka (radek.cervinka@centrum.cz) - author of Seksi Commander' + LineEnding + LineEnding + 'Contributors:' + cIndention + 'Tolstov Igor (attid@yandex.ru)' + cIndention + 'Anton Panferov (ast.a_s@mail.ru)' + cIndention + 'Rustem Rakhimov (dok_rust@bk.ru)' + cIndention + 'Moroz Serhiy (frost.asm@gmail.com)' + cIndention + 'Vitaly Zotov (vitalyzotov@mail.ru)' + cIndention + 'Zolotov Alex (zolotov-alex@shamangrad.net)' + cIndention + 'Peter Cernoch (pcernoch@volny.cz) - author PFM' + cIndention + 'Pavel Letko (letcuv@centrum.cz) - multirename, split, linker' + cIndention + 'Jiri Karasek (jkarasek@centrum.cz)' + cIndention + 'Vladimir Pilny (vladimir@pilny.com)' + cIndention + 'Vaclav Juza (vaclavjuza@seznam.cz)' + cIndention + 'Martin Matusu (xmat@volny.cz) - chown, chgrp' + cIndention + 'Radek Polak - some viewer fixes' + cIndention + 'Dmytro Zheludko (doublecmd@zheludko.mail.ua)' + cIndention + 'Andryei Gudyak - main icon' + cIndention + 'translators (see details in language files) ' + LineEnding + LineEnding + 'Double Commander uses icons from:' + LineEnding + '- Tango Icon Library (http://tango.freedesktop.org/Tango_Icon_Library)' + LineEnding + '- Silk icon set 1.3 by Mark James (http://www.famfamfam.com/lab/icons/silk/)' + LineEnding + '- Elementary icon theme 2.7.1 (https://github.com/elementary/icons)' + LineEnding + '- Adwaita Icon Theme (https://gitlab.gnome.org/GNOME/adwaita-icon-theme)' + LineEnding + '- Farm-Fresh Web Icons (https://www.fatcow.com/free-icons)' + LineEnding + '- Oxygen icon theme (https://invent.kde.org/frameworks/oxygen-icons)' + LineEnding + LineEnding + 'Big thanks to Lazarus and Free Pascal Team!'; procedure ShowAboutBox(TheOwner: TComponent); begin with TfrmAbout.Create(TheOwner) do try ShowModal; finally Free; end; end; procedure TfrmAbout.lblHomePageAddressMouseLeave(Sender: TObject); begin with Sender as TLabel do begin Font.Style:= []; Font.Color:= FMouseLeave; Cursor:= crDefault; end; end; procedure TfrmAbout.lblHomePageAddressMouseEnter(Sender: TObject); begin with Sender as TLabel do begin Font.Style:= [fsUnderLine]; Font.Color:= FMouseEnter; Cursor:= crHandPoint; end; end; procedure TfrmAbout.lblHomePageAddressClick(Sender: TObject); var ErrMsg: String; begin dmHelpMgr.HTMLHelpDatabase.ShowURL('https://doublecmd.sourceforge.io','Double Commander Web Site', ErrMsg); end; procedure TfrmAbout.btnCopyToClipboardClick(Sender: TObject); var StrInfo: String; begin StrInfo := Format('Double Commander' + LineEnding + 'Version: %s' + LineEnding + 'Revision: %s' + LineEnding + 'Commit: %s' + LineEnding + 'Build date: %s' + LineEnding + 'Lazarus: %s' + LineEnding + 'FPC: %s' + LineEnding + 'Platform: %s' + LineEnding + 'OS version: %s' + LineEnding, [dcVersion, dcRevision, dcCommit, dcBuildDate, lazVersion, fpcVersion, TargetCPU + '-' + TargetOS + '-' + TargetWS, OSVersion]); if WSVersion <> EmptyStr then StrInfo := StrInfo + LineEnding + 'Widgetset library: ' + WSVersion; ClipboardSetText(StrInfo); end; procedure TfrmAbout.FormCreate(Sender: TObject); begin UpdateStyle; lblTitle.Font.Color:= FMouseEnter; lblHomePageAddress.Font.Color:= FMouseLeave; end; procedure TfrmAbout.frmAboutShow(Sender: TObject); begin memInfo.Lines.Text := cAboutMsg; memInfo.CaretPos := Classes.Point(0, 0); lblVersion.Caption := lblVersion.Caption + #32 + dcVersion; lblRevision.Caption := lblRevision.Caption + #32 + dcRevision; lblCommit.Caption := lblCommit.Caption + #32 + dcCommit; lblBuild.Caption := lblBuild.Caption + #32 + dcBuildDate; lblLazarusVer.Caption := lblLazarusVer.Caption + #32 + lazVersion; lblFreePascalVer.Caption := lblFreePascalVer.Caption + #32 + fpcVersion; lblPlatform.Caption := TargetCPU + '-' + TargetOS + '-' + TargetWS; lblOperatingSystem.Caption := OSVersion; lblWidgetsetVer.Caption := WSVersion; Constraints.MinHeight := Height; btnClose.Anchors := [akLeft, akBottom]; end; procedure TfrmAbout.UpdateStyle; begin if DarkStyle then begin FMouseLeave:= RGBToColor(97, 155, 192); FMouseEnter:= RGBToColor(192, 102, 97); end else begin FMouseLeave:= clBlue; FMouseEnter:= clRed; end; end; procedure TfrmAbout.CMThemeChanged(var Message: TLMessage); begin UpdateStyle; end; end. �����������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fFileOpDlg.lfm�����������������������������������������������������������������0000644�0001750�0000144�00000012450�14743153644�016052� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFileOp: TfrmFileOp Left = 576 Height = 212 Top = 272 Width = 522 ClientHeight = 212 ClientWidth = 522 Constraints.MinWidth = 500 OnClose = FormClose OnCreate = FormCreate Position = poScreenCenter ShowInTaskBar = stAlways LCLVersion = '2.0.0.2' object pnlClient: TPanel Left = 3 Height = 141 Top = 3 Width = 516 Align = alTop AutoSize = True BorderSpacing.Around = 3 BevelOuter = bvNone ClientHeight = 141 ClientWidth = 516 TabOrder = 0 object pnlQueue: TPanel Left = 0 Height = 21 Top = 0 Width = 516 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 21 ClientWidth = 516 TabOrder = 0 object lblCurrentOperation: TLabel Left = 0 Height = 15 Top = 0 Width = 516 Align = alTop BorderSpacing.Bottom = 5 Caption = 'Current operation:' ParentColor = False end object lblCurrentOperationText: TLabel Left = 0 Height = 1 Top = 20 Width = 516 Align = alTop ParentColor = False end end object pnlFrom: TPanel Left = 0 Height = 15 Top = 21 Width = 516 Align = alTop AutoSize = True BorderSpacing.Bottom = 3 BevelOuter = bvNone ClientHeight = 15 ClientWidth = 516 TabOrder = 1 object lblFrom: TLabel Left = 0 Height = 15 Top = 0 Width = 40 Align = alLeft Caption = 'From:' Constraints.MinWidth = 40 ParentColor = False end object lblFileNameFrom: TLabel Left = 40 Height = 15 Top = 0 Width = 476 Align = alClient ParentColor = False ParentShowHint = False ShowAccelChar = False ShowHint = True end end object pnlTo: TPanel Left = 0 Height = 15 Top = 39 Width = 516 Align = alTop AutoSize = True BorderSpacing.Top = 3 BorderSpacing.Bottom = 3 BevelOuter = bvNone ClientHeight = 15 ClientWidth = 516 TabOrder = 2 object lblFileNameTo: TLabel Left = 40 Height = 15 Top = 0 Width = 476 Align = alClient ParentColor = False ParentShowHint = False ShowAccelChar = False ShowHint = True end object lblTo: TLabel Left = 0 Height = 15 Top = 0 Width = 40 Align = alLeft Caption = 'To:' Constraints.MinWidth = 40 ParentColor = False end end object lblEstimated: TLabel Left = 0 Height = 1 Top = 57 Width = 516 Align = alTop BorderSpacing.Top = 3 ParentColor = False end object pbCurrent: TKASProgressBar Left = 0 Height = 22 Top = 61 Width = 516 Align = alTop BorderSpacing.Top = 3 Max = 516 Smooth = True TabOrder = 3 BarShowText = True end object pbTotal: TKASProgressBar Left = 0 Height = 22 Top = 86 Width = 516 Align = alTop BorderSpacing.Top = 3 Max = 516 Smooth = True TabOrder = 4 BarShowText = True end object pnlButtons: TPanel Left = 0 Height = 30 Top = 111 Width = 516 Align = alTop AutoSize = True BorderSpacing.Top = 3 BevelOuter = bvNone ClientHeight = 30 ClientWidth = 516 TabOrder = 5 object btnMinimizeToPanel: TBitBtn Left = 0 Height = 30 Top = 0 Width = 72 Align = alLeft AutoSize = True BorderSpacing.Right = 3 Caption = '&To panel' OnClick = btnMinimizeToPanelClick TabOrder = 0 end object btnViewOperations: TBitBtn Left = 75 Height = 30 Top = 0 Width = 66 Align = alLeft AutoSize = True BorderSpacing.Right = 3 Caption = '&View all' OnClick = btnViewOperationsClick TabOrder = 1 end object btnCancel: TBitBtn Left = 377 Height = 30 Top = 0 Width = 86 Align = alRight AutoSize = True BorderSpacing.Left = 3 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Constraints.MinWidth = 50 Kind = bkCancel ModalResult = 2 OnClick = btnCancelClick TabOrder = 2 end object btnPauseStart: TBitBtn Left = 466 Height = 30 Top = 0 Width = 50 Align = alRight AutoSize = True BorderSpacing.Left = 3 Constraints.MinWidth = 50 GlyphShowMode = gsmAlways OnClick = btnPauseStartClick Spacing = 0 TabOrder = 3 end object lblFileCount: TLabel AnchorSideLeft.Control = btnViewOperations AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnCancel AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCancel Left = 144 Height = 1 Top = 15 Width = 230 Alignment = taCenter Anchors = [akTop, akLeft, akRight] ParentColor = False end end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fFileOpDlg.lrj�����������������������������������������������������������������0000644�0001750�0000144�00000001432�14743153644�016061� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":155261978,"name":"tfrmfileop.lblcurrentoperation.caption","sourcebytes":[67,117,114,114,101,110,116,32,111,112,101,114,97,116,105,111,110,58],"value":"Current operation:"}, {"hash":5084682,"name":"tfrmfileop.lblfrom.caption","sourcebytes":[70,114,111,109,58],"value":"From:"}, {"hash":23338,"name":"tfrmfileop.lblto.caption","sourcebytes":[84,111,58],"value":"To:"}, {"hash":24538892,"name":"tfrmfileop.btnminimizetopanel.caption","sourcebytes":[38,84,111,32,112,97,110,101,108],"value":"&To panel"}, {"hash":264850924,"name":"tfrmfileop.btnviewoperations.caption","sourcebytes":[38,86,105,101,119,32,97,108,108],"value":"&View all"}, {"hash":177752476,"name":"tfrmfileop.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fFileOpDlg.pas�����������������������������������������������������������������0000644�0001750�0000144�00000117214�14743153644�016063� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Window displaying progress for file source operations and queues. Copyright (C) 2008-2021 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2012 Przemysław Nagay (cobines@gmail.com) 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, see <http://www.gnu.org/licenses/>. } unit fFileOpDlg; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons, ExtCtrls, KASProgressBar, uOperationsManager, uFileSourceOperation, uFileSourceOperationUI, uOSForms; type TFileOpDlgLook = set of (fodl_from_lbl, fodl_to_lbl, fodl_current_pb, fodl_total_pb); TOperationProgressWindowEvent = (opwevOpened, opwevClosed); TOperationProgressWindowEvents = set of TOperationProgressWindowEvent; TOperationProgressWindowEventProc = procedure(OperationHandle: TOperationHandle; Event: TOperationProgressWindowEvent) of object; TOperationProgressWindowOption = (opwoIfExistsBringToFront, opwoStartMinimized); TOperationProgressWindowOptions = set of TOperationProgressWindowOption; { TfrmFileOp } TfrmFileOp = class(TModalDialog) btnCancel: TBitBtn; btnPauseStart: TBitBtn; btnViewOperations: TBitBtn; btnMinimizeToPanel: TBitBtn; lblFileCount: TLabel; lblCurrentOperationText: TLabel; lblEstimated: TLabel; lblFileNameFrom: TLabel; lblFileNameTo: TLabel; lblFrom: TLabel; lblCurrentOperation: TLabel; lblTo: TLabel; pnlQueue: TPanel; pbCurrent: TKASProgressBar; pbTotal: TKASProgressBar; pnlButtons: TPanel; pnlClient: TPanel; pnlFrom: TPanel; pnlTo: TPanel; procedure btnCancelClick(Sender: TObject); procedure btnMinimizeToPanelClick(Sender: TObject); procedure btnPauseStartClick(Sender: TObject); procedure btnViewOperationsClick(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); private FOperationHandle: TOperationHandle; FQueueIdentifier: TOperationsManagerQueueIdentifier; FUpdateTimer: TTimer; //<en Timer for updating statistics. FUserInterface: TFileSourceOperationUI; FStopOperationOnClose: Boolean; procedure OnUpdateTimer(Sender: TObject); function AddToOpenedForms(OpManItem: TOperationsManagerItem): Boolean; procedure CloseDialog; procedure FinalizeOperation; function GetFirstOperationHandle(QueueIdentifier: TOperationsManagerQueueIdentifier): TOperationHandle; function GetProgressBarStyle: TProgressBarStyle; procedure InitializeControls(OpManItem: TOperationsManagerItem; FileOpDlgLook: TFileOpDlgLook); function InitializeOperation: Boolean; procedure NotifyEvents(Events: TOperationProgressWindowEvents); procedure RemoveFromOpenedForms; procedure SetPauseGlyph; procedure SetPlayGlyph; procedure SetLabelCaption(ALabel: TLabel; const AText: String); procedure UpdateOperation(OpManItem: TOperationsManagerItem); procedure UpdatePauseStartButton(OpManItem: TOperationsManagerItem); procedure SetProgressBarStyle(const AValue: TProgressBarStyle); procedure SetProgressCount(Operation: TFileSourceOperation; DoneFiles: Int64; TotalFiles: Int64); procedure SetProgressBytes(Operation: TFileSourceOperation; ProgressBar: TKASProgressBar; CurrentBytes: Int64; TotalBytes: Int64); procedure SetProgressFiles(Operation: TFileSourceOperation; ProgressBar: TKASProgressBar; CurrentFiles: Int64; TotalFiles: Int64); procedure SetSpeedAndTime(Operation: TFileSourceOperation; RemainingTime: TDateTime; Speed: String); function StopOperationOrQueue: Boolean; procedure InitializeCopyOperation(OpManItem: TOperationsManagerItem); procedure InitializeMoveOperation(OpManItem: TOperationsManagerItem); procedure InitializeDeleteOperation(OpManItem: TOperationsManagerItem); procedure InitializeWipeOperation(OpManItem: TOperationsManagerItem); procedure InitializeSplitOperation(OpManItem: TOperationsManagerItem); procedure InitializeCombineOperation(OpManItem: TOperationsManagerItem); procedure InitializeCalcChecksumOperation(OpManItem: TOperationsManagerItem); procedure InitializeTestArchiveOperation(OpManItem: TOperationsManagerItem); procedure InitializeCalcStatisticsOperation(OpManItem: TOperationsManagerItem); procedure InitializeSetFilePropertyOperation(OpManItem: TOperationsManagerItem); procedure UpdateCopyOperation(Operation: TFileSourceOperation); procedure UpdateMoveOperation(Operation: TFileSourceOperation); procedure UpdateDeleteOperation(Operation: TFileSourceOperation); procedure UpdateWipeOperation(Operation: TFileSourceOperation); procedure UpdateSplitOperation(Operation: TFileSourceOperation); procedure UpdateCombineOperation(Operation: TFileSourceOperation); procedure UpdateCalcStatisticsOperation(Operation: TFileSourceOperation); procedure UpdateCalcChecksumOperation(Operation: TFileSourceOperation); procedure UpdateTestArchiveOperation(Operation: TFileSourceOperation); procedure UpdateSetFilePropertyOperation(Operation: TFileSourceOperation); class function GetOpenedForm(AOperationHandle: TOperationHandle): TfrmFileOp; class function GetOpenedForm(AQueueIdentifier: TOperationsManagerQueueIdentifier): TfrmFileOp; class procedure ShowExistingWindow(AWindow: TfrmFileOp; Options: TOperationProgressWindowOptions); class procedure ShowNewWindow(AWindow: TfrmFileOp; Options: TOperationProgressWindowOptions); property ProgressBarStyle: TProgressBarStyle read GetProgressBarStyle write SetProgressBarStyle; protected procedure DoAutoSize; override; public constructor Create(OperationHandle: TOperationHandle); reintroduce; constructor Create(QueueIdentifier: TOperationsManagerQueueIdentifier); reintroduce; destructor Destroy; override; procedure ExecuteModal; override; function ShowModal: Integer; override; function CloseQuery: Boolean; override; class procedure AddEventsListener(Events: TOperationProgressWindowEvents; FunctionToCall: TOperationProgressWindowEventProc); class procedure RemoveEventsListener(Events: TOperationProgressWindowEvents; FunctionToCall: TOperationProgressWindowEventProc); class function IsOpenedFor(AOperationHandle: TOperationHandle): Boolean; class function IsOpenedFor(AQueueIdentifier: TOperationsManagerQueueIdentifier): Boolean; class procedure ShowFor(AOperationHandle: TOperationHandle; Options: TOperationProgressWindowOptions); class procedure ShowFor(AQueueIdentifier: TOperationsManagerQueueIdentifier; Options: TOperationProgressWindowOptions); end; implementation {$R *.lfm} uses dmCommonData, uLng, uDCUtils, LCLVersion, uShowMsg, fViewOperations, uFileSourceOperationMisc, uFileSourceOperationTypes, uFileSourceCopyOperation, uFileSourceMoveOperation, uFileSourceDeleteOperation, uFileSourceWipeOperation, uFileSourceSplitOperation, uFileSourceCombineOperation, uFileSourceCalcChecksumOperation, uFileSourceCalcStatisticsOperation, uFileSourceTestArchiveOperation, uFileSourceSetFilePropertyOperation, uFileSourceOperationMessageBoxesUI ; type PEventsListItem = ^TEventsListItem; TEventsListItem = record EventFunction: TOperationProgressWindowEventProc; end; POpenedForm = ^TOpenedForm; TOpenedForm = record Form: TfrmFileOp; OperationHandle: TOperationHandle; QueueIdentifier: TOperationsManagerQueueIdentifier; end; var OpenedForms: TFPList; EventsListeners: array[TOperationProgressWindowEvent] of TFPList; procedure Initialize; var Event: TOperationProgressWindowEvent; begin OpenedForms := TFPList.Create; for Event := Low(EventsListeners) to High(EventsListeners) do EventsListeners[Event] := TFPList.Create; end; procedure Terminate; var Event: TOperationProgressWindowEvent; Item: PEventsListItem; OpenedForm: POpenedForm; begin for Event := Low(EventsListeners) to High(EventsListeners) do begin for Item in EventsListeners[Event] do Dispose(Item); FreeAndNil(EventsListeners[Event]); end; for OpenedForm in OpenedForms do Dispose(OpenedForm); OpenedForms.Free; end; procedure TfrmFileOp.btnCancelClick(Sender: TObject); begin if StopOperationOrQueue then ModalResult:= mrCancel; end; procedure TfrmFileOp.btnMinimizeToPanelClick(Sender: TObject); begin CloseDialog; end; procedure TfrmFileOp.btnPauseStartClick(Sender: TObject); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then begin if OpManItem.Queue.IsFree then OpManItem.Operation.TogglePause else OpManItem.Queue.TogglePause; UpdatePauseStartButton(OpManItem); end; end; procedure TfrmFileOp.btnViewOperationsClick(Sender: TObject); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then begin if OpManItem.Queue.IsFree then ShowOperationsViewer(OpManItem.Handle) else ShowOperationsViewer(OpManItem.Queue.Identifier); end; end; procedure TfrmFileOp.CloseDialog; begin FStopOperationOnClose := False; Close; end; procedure TfrmFileOp.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; FinalizeOperation; end; procedure TfrmFileOp.FormCreate(Sender: TObject); begin pbCurrent.DoubleBuffered:= True; pbTotal.DoubleBuffered:= True; Self.DoubleBuffered:= True; FUpdateTimer := TTimer.Create(Self); FUpdateTimer.Interval := 100; FUpdateTimer.OnTimer := @OnUpdateTimer; FUpdateTimer.Enabled := False; if not InitializeOperation then CloseDialog; // Workaround: TWinControl.WMSize loop detected Constraints.MaxWidth:= Screen.Width; Constraints.MaxHeight:= Screen.Height; end; function TfrmFileOp.GetFirstOperationHandle(QueueIdentifier: TOperationsManagerQueueIdentifier): TOperationHandle; var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[QueueIdentifier]; if Assigned(Queue) and (Queue.Count > 0) then Result := Queue.Items[0].Handle else Result := InvalidOperationHandle; end; class function TfrmFileOp.GetOpenedForm(AOperationHandle: TOperationHandle): TfrmFileOp; var Index: Integer; Item: POpenedForm; begin for Index := 0 to OpenedForms.Count - 1 do begin Item := OpenedForms[Index]; if Item^.OperationHandle = AOperationHandle then Exit(Item^.Form); end; Result := nil; end; class function TfrmFileOp.GetOpenedForm(AQueueIdentifier: TOperationsManagerQueueIdentifier): TfrmFileOp; var Index: Integer; Item: POpenedForm; begin for Index := 0 to OpenedForms.Count - 1 do begin Item := OpenedForms[Index]; if Item^.QueueIdentifier = AQueueIdentifier then Exit(Item^.Form); end; Result := nil; end; constructor TfrmFileOp.Create(OperationHandle: TOperationHandle); var OpManItem: TOperationsManagerItem; begin FOperationHandle := InvalidOperationHandle; inherited Create(Application); AutoSize := True; OpManItem := OperationsManager.GetItemByHandle(OperationHandle); if Assigned(OpManItem) then begin FStopOperationOnClose := True; FOperationHandle := OperationHandle; end else begin CloseDialog; end; end; constructor TfrmFileOp.Create(QueueIdentifier: TOperationsManagerQueueIdentifier); begin Create(GetFirstOperationHandle(QueueIdentifier)); end; destructor TfrmFileOp.Destroy; begin inherited Destroy; FreeAndNil(FUserInterface); end; procedure TfrmFileOp.ExecuteModal; var OpManItem: TOperationsManagerItem; begin if FOperationHandle <> InvalidOperationHandle then begin if Assigned(FUserInterface) then begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then OpManItem.Operation.Execute; end; end; end; function TfrmFileOp.ShowModal: Integer; begin BorderStyle:= bsDialog; ShowInTaskBar:= stNever; btnViewOperations.Visible:= False; btnMinimizeToPanel.Visible:= False; Result:= inherited ShowModal; // Workaround http://doublecmd.sourceforge.net/mantisbt/view.php?id=1323 {$IF DEFINED(DARWIN) and DEFINED(LCLQT)} Visible:= True; Visible:= False; {$ENDIF} end; procedure TfrmFileOp.FinalizeOperation; var OpManItem: TOperationsManagerItem; begin FUpdateTimer.Enabled := False; if FOperationHandle <> InvalidOperationHandle then begin if Assigned(FUserInterface) then begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then OpManItem.Operation.RemoveUserInterface(FUserInterface); end; RemoveFromOpenedForms; FOperationHandle := InvalidOperationHandle; end; end; function TfrmFileOp.CloseQuery: Boolean; begin Result := True; if FStopOperationOnClose then Result := StopOperationOrQueue; end; class procedure TfrmFileOp.AddEventsListener(Events: TOperationProgressWindowEvents; FunctionToCall: TOperationProgressWindowEventProc); var Item: PEventsListItem; Event: TOperationProgressWindowEvent; begin for Event in Events do begin New(Item); Item^.EventFunction := FunctionToCall; EventsListeners[Event].Add(Item); end; end; function TfrmFileOp.AddToOpenedForms(OpManItem: TOperationsManagerItem): Boolean; var Index: Integer; Item: POpenedForm; Found: Boolean = False; begin for Index := 0 to OpenedForms.Count - 1 do begin Item := OpenedForms[Index]; // Check if another form is not already opened for the operation or queue. if (Item^.OperationHandle = FOperationHandle) or (not OpManItem.Queue.IsFree and (Item^.QueueIdentifier = FQueueIdentifier)) then begin Exit(False); end else if Item^.Form = Self then begin Found := True; Break; end; end; if not Found then begin New(Item); OpenedForms.Add(Item); end; Item^.Form := Self; Item^.OperationHandle := FOperationHandle; Item^.QueueIdentifier := FQueueIdentifier; NotifyEvents([opwevOpened]); Result := True; end; class procedure TfrmFileOp.RemoveEventsListener(Events: TOperationProgressWindowEvents; FunctionToCall: TOperationProgressWindowEventProc); var Item: PEventsListItem; Event: TOperationProgressWindowEvent; i: Integer; begin for Event in Events do begin for i := 0 to EventsListeners[Event].Count - 1 do begin Item := PEventsListItem(EventsListeners[Event].Items[i]); if Item^.EventFunction = FunctionToCall then begin EventsListeners[Event].Delete(i); Dispose(Item); Break; // break from one for only end; end; end; end; procedure TfrmFileOp.RemoveFromOpenedForms; var i: Integer; Item: POpenedForm; begin for i := 0 to OpenedForms.Count - 1 do begin Item := OpenedForms[i]; if Item^.Form = Self then begin Dispose(Item); OpenedForms.Delete(i); NotifyEvents([opwevClosed]); Break; end; end; end; class function TfrmFileOp.IsOpenedFor(AOperationHandle: TOperationHandle): Boolean; begin Result := Assigned(GetOpenedForm(AOperationHandle)); end; class function TfrmFileOp.IsOpenedFor(AQueueIdentifier: TOperationsManagerQueueIdentifier): Boolean; begin Result := Assigned(GetOpenedForm(AQueueIdentifier)); end; class procedure TfrmFileOp.ShowFor(AOperationHandle: TOperationHandle; Options: TOperationProgressWindowOptions); var OperationDialog: TfrmFileOp; OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(AOperationHandle); if Assigned(OpManItem) then begin if not OpManItem.Queue.IsFree then begin ShowFor(OpManItem.Queue.Identifier, Options); end else begin OperationDialog := GetOpenedForm(AOperationHandle); if Assigned(OperationDialog) then ShowExistingWindow(OperationDialog, Options) else begin OperationDialog := TfrmFileOp.Create(AOperationHandle); ShowNewWindow(OperationDialog, Options); end; end; end; end; class procedure TfrmFileOp.ShowFor(AQueueIdentifier: TOperationsManagerQueueIdentifier; Options: TOperationProgressWindowOptions); var OperationDialog: TfrmFileOp; begin OperationDialog := GetOpenedForm(AQueueIdentifier); if Assigned(OperationDialog) then begin ShowExistingWindow(OperationDialog, Options); end else begin OperationDialog := TfrmFileOp.Create(AQueueIdentifier); ShowNewWindow(OperationDialog, Options); end; end; class procedure TfrmFileOp.ShowExistingWindow(AWindow: TfrmFileOp; Options: TOperationProgressWindowOptions); begin if opwoIfExistsBringToFront in Options then AWindow.ShowOnTop; end; class procedure TfrmFileOp.ShowNewWindow(AWindow: TfrmFileOp; Options: TOperationProgressWindowOptions); begin if opwoStartMinimized in Options then begin {$IF lcl_fullversion >= 093100} // Workaround for bug in Lazarus 0.9.31 #0021603. AWindow.Visible := True; AWindow.WindowState := wsMinimized; {$ELSE} AWindow.WindowState := wsMinimized; AWindow.Visible := True; {$ENDIF} end else AWindow.Show; end; procedure TfrmFileOp.DoAutoSize; begin inherited DoAutoSize; {$IF DEFINED(LCLQT5)} InvalidateBoundsRealized; {$ENDIF} end; function TfrmFileOp.StopOperationOrQueue: Boolean; var Paused: Boolean; OpManItem: TOperationsManagerItem; begin Result := True; OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then begin if OpManItem.Queue.IsFree then begin Paused := OpManItem.Operation.State in [fsosStarting, fsosRunning, fsosWaitingForConnection]; if Paused then OpManItem.Operation.Pause; end else begin Paused := not OpManItem.Queue.Paused; if Paused then OpManItem.Queue.Pause; end; Result:= msgYesNo(rsMsgCancelOperation, msmbYes); if Result then begin if OpManItem.Queue.IsFree then OpManItem.Operation.Stop else OpManItem.Queue.Stop; end else if Paused then begin if OpManItem.Queue.IsFree then OpManItem.Operation.TogglePause else begin OpManItem.Queue.TogglePause; end; end; end; end; procedure TfrmFileOp.OnUpdateTimer(Sender: TObject); var OpManItem: TOperationsManagerItem; Queue: TOperationsManagerQueue; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); // Check if operation did not change queues. if Assigned(OpManItem) and (OpManItem.Queue.Identifier <> FQueueIdentifier) then begin Queue := OperationsManager.QueueByIdentifier[FQueueIdentifier]; FinalizeOperation; if Assigned(Queue) and not Queue.IsFree then begin // Queue was begin followed - switch to next operation from that queue. FQueueIdentifier := Queue.Identifier; FOperationHandle := GetFirstOperationHandle(Queue.Identifier); end else begin // Follow the operation to new queue either because previously followed // queue was free-operations queue or old queue was destroyed. FQueueIdentifier := OpManItem.Queue.Identifier; FOperationHandle := OpManItem.Handle; end; if not InitializeOperation then begin CloseDialog; Exit; end; OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); end; // Check if first operation in the queue hasn't changed. if Assigned(OpManItem) and not OpManItem.Queue.IsFree and (GetFirstOperationHandle(FQueueIdentifier) <> FOperationHandle) then begin FinalizeOperation; FOperationHandle := GetFirstOperationHandle(FQueueIdentifier); if not InitializeOperation then begin CloseDialog; Exit; end; OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); end; if Assigned(OpManItem) then begin UpdateOperation(OpManItem); end else // Operation was destroyed begin Queue := OperationsManager.QueueByIdentifier[FQueueIdentifier]; if not Assigned(Queue) or Queue.IsFree then begin // Single operation was being followed and it has finished // or all operations in queue have finished - close window. CloseDialog; end else begin // Queue was begin followed - switch to next operation from that queue. FOperationHandle := GetFirstOperationHandle(FQueueIdentifier); OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); OpManItem.Operation.AddUserInterface(FUserInterface); end; end; end; procedure TfrmFileOp.InitializeControls(OpManItem: TOperationsManagerItem; FileOpDlgLook: TFileOpDlgLook); begin pnlQueue.Visible := not OpManItem.Queue.IsFree; lblFrom.Visible := fodl_from_lbl in FileOpDlgLook; lblFileNameFrom.Visible := lblFrom.Visible; lblTo.Visible := fodl_to_lbl in FileOpDlgLook; lblFileNameTo.Visible := lblTo.Visible; pbCurrent.Visible := fodl_current_pb in FileOpDlgLook; pbTotal.Visible := fodl_total_pb in FileOpDlgLook; pbCurrent.ShowInTaskbar := [fodl_current_pb, fodl_total_pb] * FileOpDlgLook = [fodl_current_pb]; pbTotal.ShowInTaskbar := fodl_total_pb in FileOpDlgLook; lblFileNameFrom.Caption := ''; lblFileNameTo.Caption := ''; lblEstimated.Caption := #32; lblFileCount.Caption := EmptyStr; end; procedure TfrmFileOp.NotifyEvents(Events: TOperationProgressWindowEvents); var Item: PEventsListItem; Event: TOperationProgressWindowEvent; i: Integer; begin for Event in Events do begin for i := 0 to EventsListeners[Event].Count - 1 do begin Item := EventsListeners[Event].Items[i]; Item^.EventFunction(FOperationHandle, Event); end; end; end; procedure TfrmFileOp.SetPauseGlyph; begin dmComData.ImageList.GetBitmap(1, btnPauseStart.Glyph); end; procedure TfrmFileOp.SetPlayGlyph; begin dmComData.ImageList.GetBitmap(0, btnPauseStart.Glyph); end; procedure TfrmFileOp.SetLabelCaption(ALabel: TLabel; const AText: String); begin ALabel.Hint := AText; ALabel.Caption := MinimizeFilePath(AText, ALabel.Canvas, ALabel.Width); end; procedure TfrmFileOp.SetProgressBytes(Operation: TFileSourceOperation; ProgressBar: TKASProgressBar; CurrentBytes: Int64; TotalBytes: Int64); begin if (CurrentBytes = -1) then ProgressBar.Style := pbstMarquee else begin if Operation.State = fsosRunning then ProgressBar.Style := pbstNormal; // Show only percent if TotalBytes < 0 then begin ProgressBar.SetProgress(CurrentBytes, -TotalBytes, EmptyStr); end else begin ProgressBar.SetProgress(CurrentBytes, TotalBytes, cnvFormatFileSize(CurrentBytes, uoscOperation) + '/' + cnvFormatFileSize(TotalBytes, uoscOperation) ); end; end; end; procedure TfrmFileOp.SetProgressFiles(Operation: TFileSourceOperation; ProgressBar: TKASProgressBar; CurrentFiles: Int64; TotalFiles: Int64); begin if (CurrentFiles = -1) then ProgressBar.Style := pbstMarquee else begin if Operation.State = fsosRunning then ProgressBar.Style := pbstNormal; // Show only percent if TotalFiles < 0 then begin ProgressBar.SetProgress(CurrentFiles, -TotalFiles, EmptyStr); end else begin ProgressBar.SetProgress(CurrentFiles, TotalFiles, IntToStrTS(CurrentFiles) + '/' + IntToStrTS(TotalFiles) ); end; end; end; procedure TfrmFileOp.SetSpeedAndTime(Operation: TFileSourceOperation; RemainingTime: TDateTime; Speed: String); var sEstimated: String; begin if Operation.State <> fsosRunning then sEstimated := #32 else begin if RemainingTime < 0 then sEstimated := #32 else if RemainingTime > 0 then begin // Normal view, less than 24 hours of estimated time if RemainingTime < 1.0 then sEstimated := FormatDateTime('HH:MM:SS', RemainingTime) else begin sEstimated := IntToStr(Trunc(RemainingTime)) + '``' + FormatDateTime('HH:MM:SS', RemainingTime); end; sEstimated := Format(rsDlgSpeedTime, [Speed, sEstimated]); end else sEstimated := Format(rsDlgSpeed, [Speed]); end; lblEstimated.Caption := sEstimated; end; procedure TfrmFileOp.InitializeCopyOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_to_lbl, fodl_current_pb, fodl_total_pb]); end; procedure TfrmFileOp.InitializeMoveOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_to_lbl, fodl_current_pb, fodl_total_pb]); end; function TfrmFileOp.InitializeOperation: Boolean; var OpManItem: TOperationsManagerItem; begin Result := False; OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) and not OpManItem.Queue.IsFree then begin FOperationHandle := GetFirstOperationHandle(OpManItem.Queue.Identifier); OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); end; if Assigned(OpManItem) then begin FQueueIdentifier := OpManItem.Queue.Identifier; if AddToOpenedForms(OpManItem) then begin if not Assigned(FUserInterface) then FUserInterface := TFileSourceOperationMessageBoxesUI.Create; OpManItem.Operation.AddUserInterface(FUserInterface); ProgressBarStyle:= pbstMarquee; case OpManItem.Operation.ID of fsoCopy, fsoCopyIn, fsoCopyOut: InitializeCopyOperation(OpManItem); fsoMove: InitializeMoveOperation(OpManItem); fsoDelete: InitializeDeleteOperation(OpManItem); fsoWipe: InitializeWipeOperation(OpManItem); fsoSplit: InitializeSplitOperation(OpManItem); fsoCombine: InitializeCombineOperation(OpManItem); fsoCalcChecksum: InitializeCalcChecksumOperation(OpManItem); fsoTestArchive: InitializeTestArchiveOperation(OpManItem); fsoCalcStatistics: InitializeCalcStatisticsOperation(OpManItem); fsoSetFileProperty: InitializeSetFilePropertyOperation(OpManItem); else begin InitializeControls(OpManItem, [fodl_total_pb]); end; end; UpdatePauseStartButton(OpManItem); Caption := EmptyStr; FUpdateTimer.Enabled := True; Result := True; end; end; if not Result then FOperationHandle := InvalidOperationHandle; end; procedure TfrmFileOp.InitializeDeleteOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_total_pb]); end; procedure TfrmFileOp.InitializeCalcStatisticsOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl]); end; procedure TfrmFileOp.InitializeSetFilePropertyOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_total_pb]); end; procedure TfrmFileOp.InitializeWipeOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_current_pb, fodl_total_pb]); end; procedure TfrmFileOp.InitializeSplitOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_to_lbl, fodl_current_pb, fodl_total_pb]); end; procedure TfrmFileOp.InitializeCombineOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_to_lbl, fodl_current_pb, fodl_total_pb]); end; procedure TfrmFileOp.InitializeCalcChecksumOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_current_pb, fodl_total_pb]); end; procedure TfrmFileOp.InitializeTestArchiveOperation(OpManItem: TOperationsManagerItem); begin InitializeControls(OpManItem, [fodl_from_lbl, fodl_to_lbl, fodl_current_pb, fodl_total_pb]); end; procedure TfrmFileOp.UpdateCopyOperation(Operation: TFileSourceOperation); var CopyOperation: TFileSourceCopyOperation; CopyStatistics: TFileSourceCopyOperationStatistics; begin CopyOperation := Operation as TFileSourceCopyOperation; CopyStatistics := CopyOperation.RetrieveStatistics; with CopyStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFileFrom); SetLabelCaption(lblFileNameTo, CurrentFileTo); SetProgressCount(Operation, DoneFiles, TotalFiles); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateMoveOperation(Operation: TFileSourceOperation); var MoveOperation: TFileSourceMoveOperation; MoveStatistics: TFileSourceMoveOperationStatistics; begin MoveOperation := Operation as TFileSourceMoveOperation; MoveStatistics := MoveOperation.RetrieveStatistics; with MoveStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFileFrom); SetLabelCaption(lblFileNameTo, CurrentFileTo); SetProgressCount(Operation, DoneFiles, TotalFiles); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateOperation(OpManItem: TOperationsManagerItem); var NewCaption: String; begin case OpManItem.Operation.ID of fsoCopy, fsoCopyIn, fsoCopyOut: UpdateCopyOperation(OpManItem.Operation); fsoMove: UpdateMoveOperation(OpManItem.Operation); fsoDelete: UpdateDeleteOperation(OpManItem.Operation); fsoWipe: UpdateWipeOperation(OpManItem.Operation); fsoSplit: UpdateSplitOperation(OpManItem.Operation); fsoCombine: UpdateCombineOperation(OpManItem.Operation); fsoCalcChecksum: UpdateCalcChecksumOperation(OpManItem.Operation); fsoCalcStatistics: UpdateCalcStatisticsOperation(OpManItem.Operation); fsoTestArchive: UpdateTestArchiveOperation(OpManItem.Operation); fsoSetFileProperty: UpdateSetFilePropertyOperation(OpManItem.Operation); else begin // Operation not currently supported for display. // Only show general progress. pbTotal.Position := Round(OpManItem.Operation.Progress * pbTotal.Max); end; end; UpdatePauseStartButton(OpManItem); if OpManItem.Queue.IsFree then begin NewCaption := GetProgressString(OpManItem.Operation.Progress) + ' ' + OpManItem.Operation.GetDescription(fsoddJob) + GetOperationStateString(OpManItem.Operation.State); end else begin if OpManItem.Queue.Paused then NewCaption := '[' + IntToStr(OpManItem.Queue.Count) + '] ' + OpManItem.Queue.GetDescription(False) + GetOperationStateString(fsosPaused) else NewCaption := '[' + IntToStr(OpManItem.Queue.Count) + '] ' + GetProgressString(OpManItem.Operation.Progress) + ' ' + OpManItem.Operation.GetDescription(fsoddJob) + ' - ' + OpManItem.Queue.GetDescription(False); lblCurrentOperationText.Caption := OpManItem.Operation.GetDescription(fsoddJob) + ' ' + GetProgressString(OpManItem.Operation.Progress); end; Caption := NewCaption; end; procedure TfrmFileOp.UpdatePauseStartButton(OpManItem: TOperationsManagerItem); begin if OpManItem.Queue.IsFree then begin case OpManItem.Operation.State of fsosNotStarted, fsosStopped, fsosPaused: begin btnPauseStart.Enabled := True; SetPlayGlyph; end; fsosStarting, fsosStopping, fsosPausing, fsosWaitingForFeedback: begin btnPauseStart.Enabled := False; end; fsosRunning, fsosWaitingForConnection: begin btnPauseStart.Enabled := True; SetPauseGlyph; end; else btnPauseStart.Enabled := False; end; end else begin btnPauseStart.Enabled := True; if OpManItem.Queue.Paused then SetPlayGlyph else SetPauseGlyph; end; end; procedure TfrmFileOp.UpdateDeleteOperation(Operation: TFileSourceOperation); var DeleteOperation: TFileSourceDeleteOperation; DeleteStatistics: TFileSourceDeleteOperationStatistics; begin DeleteOperation := Operation as TFileSourceDeleteOperation; DeleteStatistics := DeleteOperation.RetrieveStatistics; with DeleteStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFile); SetProgressFiles(Operation, pbTotal, DoneFiles, TotalFiles); SetSpeedAndTime(Operation, RemainingTime, IntToStrTS(FilesPerSecond)); end; end; procedure TfrmFileOp.UpdateWipeOperation(Operation: TFileSourceOperation); var WipeOperation: TFileSourceWipeOperation; WipeStatistics: TFileSourceWipeOperationStatistics; begin WipeOperation := Operation as TFileSourceWipeOperation; WipeStatistics := WipeOperation.RetrieveStatistics; with WipeStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFile); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateSplitOperation(Operation: TFileSourceOperation); var SplitOperation: TFileSourceSplitOperation; SplitStatistics: TFileSourceSplitOperationStatistics; begin SplitOperation := Operation as TFileSourceSplitOperation; SplitStatistics := SplitOperation.RetrieveStatistics; with SplitStatistics do begin SetLabelCaption(lblFileNameFrom ,CurrentFileFrom); SetLabelCaption(lblFileNameTo, CurrentFileTo); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateCombineOperation(Operation: TFileSourceOperation); var CombineOperation: TFileSourceCombineOperation; CombineStatistics: TFileSourceCombineOperationStatistics; begin CombineOperation := Operation as TFileSourceCombineOperation; CombineStatistics := CombineOperation.RetrieveStatistics; with CombineStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFileFrom); SetLabelCaption(lblFileNameTo, CurrentFileTo); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateCalcStatisticsOperation(Operation: TFileSourceOperation); var CalcStatisticsOperation: TFileSourceCalcStatisticsOperation; CalcStatisticsOperationStatistics: TFileSourceCalcStatisticsOperationStatistics; begin CalcStatisticsOperation := Operation as TFileSourceCalcStatisticsOperation; CalcStatisticsOperationStatistics := CalcStatisticsOperation.RetrieveStatistics; with CalcStatisticsOperationStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFile); SetSpeedAndTime(Operation, 0, IntToStrTS(FilesPerSecond)); end; end; procedure TfrmFileOp.UpdateCalcChecksumOperation(Operation: TFileSourceOperation); var CalcChecksumOperation: TFileSourceCalcChecksumOperation; CalcChecksumStatistics: TFileSourceCalcChecksumOperationStatistics; begin CalcChecksumOperation := Operation as TFileSourceCalcChecksumOperation; CalcChecksumStatistics := CalcChecksumOperation.RetrieveStatistics; with CalcChecksumStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFile); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateTestArchiveOperation(Operation: TFileSourceOperation); var TestArchiveOperation: TFileSourceTestArchiveOperation; TestArchiveStatistics: TFileSourceTestArchiveOperationStatistics; begin TestArchiveOperation := Operation as TFileSourceTestArchiveOperation; TestArchiveStatistics := TestArchiveOperation.RetrieveStatistics; with TestArchiveStatistics do begin SetLabelCaption(lblFileNameFrom, ArchiveFile); SetLabelCaption(lblFileNameTo, CurrentFile); SetProgressBytes(Operation, pbCurrent, CurrentFileDoneBytes, CurrentFileTotalBytes); SetProgressBytes(Operation, pbTotal, DoneBytes, TotalBytes); SetSpeedAndTime(Operation, RemainingTime, cnvFormatFileSize(BytesPerSecond, uoscOperation)); end; end; procedure TfrmFileOp.UpdateSetFilePropertyOperation(Operation: TFileSourceOperation); var SetOperation: TFileSourceSetFilePropertyOperation; SetStatistics: TFileSourceSetFilePropertyOperationStatistics; begin SetOperation := Operation as TFileSourceSetFilePropertyOperation; SetStatistics := SetOperation.RetrieveStatistics; with SetStatistics do begin SetLabelCaption(lblFileNameFrom, CurrentFile); SetProgressFiles(Operation, pbTotal, DoneFiles, TotalFiles); SetSpeedAndTime(Operation, RemainingTime, IntToStrTS(FilesPerSecond)); end; end; function TfrmFileOp.GetProgressBarStyle: TProgressBarStyle; begin if (pbCurrent.Style = pbstMarquee) and (pbTotal.Style = pbstMarquee) then Result:= pbstMarquee else Result:= pbstNormal; end; procedure TfrmFileOp.SetProgressBarStyle(const AValue: TProgressBarStyle); begin pbCurrent.Style:= AValue; pbTotal.Style:= AValue; end; procedure TfrmFileOp.SetProgressCount(Operation: TFileSourceOperation; DoneFiles: Int64; TotalFiles: Int64); begin if (DoneFiles < 0) or (TotalFiles = 0) then lblFileCount.Caption := EmptyStr else begin lblFileCount.Caption := IntToStrTS(DoneFiles) + ' / ' + IntToStrTS(TotalFiles); end; end; initialization Initialize; finalization Terminate; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fFindDlg.lfm�������������������������������������������������������������������0000644�0001750�0000144�00000150511�14743153644�015555� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFindDlg: TfrmFindDlg Left = 275 Height = 469 Top = 176 Width = 875 Caption = 'Find files' ClientHeight = 449 ClientWidth = 875 Constraints.MinHeight = 360 Constraints.MinWidth = 585 KeyPreview = True Menu = mmMainMenu OnClose = frmFindDlgClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnShow = frmFindDlgShow Position = poScreenCenter SessionProperties = 'Height;Left;Top;Width;WindowState' ShowInTaskBar = stAlways LCLVersion = '2.0.7.0' object pnlFindFile: TPanel Left = 3 Height = 443 Top = 3 Width = 869 Align = alClient BorderSpacing.Around = 3 BevelOuter = bvNone ClientHeight = 443 ClientWidth = 869 TabOrder = 0 object pgcSearch: TPageControl Left = 0 Height = 443 Top = 0 Width = 760 ActivePage = tsStandard Align = alClient TabIndex = 0 TabOrder = 0 OnChange = pgcSearchChange object tsStandard: TTabSheet Caption = 'Standard' ChildSizing.LeftRightSpacing = 3 ChildSizing.TopBottomSpacing = 3 ClientHeight = 415 ClientWidth = 752 OnEnter = tsStandardEnter object gbDirectories: TGroupBox AnchorSideLeft.Control = tsStandard AnchorSideTop.Control = tsStandard AnchorSideRight.Control = tsStandard AnchorSideRight.Side = asrBottom Left = 3 Height = 116 Top = 3 Width = 746 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Directories' ChildSizing.LeftRightSpacing = 5 ClientHeight = 96 ClientWidth = 742 TabOrder = 0 OnResize = gbDirectoriesResize object lblFindPathStart: TLabel AnchorSideLeft.Control = gbDirectories AnchorSideBottom.Control = cbFollowSymLinks AnchorSideBottom.Side = asrBottom Left = 5 Height = 15 Top = 4 Width = 87 Anchors = [akLeft, akBottom] Caption = 'Start in &directory' FocusControl = cmbFindPathStart ParentColor = False end object cbFollowSymLinks: TCheckBox AnchorSideTop.Control = gbDirectories AnchorSideRight.Control = gbDirectories AnchorSideRight.Side = asrBottom Left = 633 Height = 19 Top = 0 Width = 104 Anchors = [akTop, akRight] Caption = 'Follow s&ymlinks' TabOrder = 0 end object cmbFindPathStart: TComboBoxWithDelItems AnchorSideLeft.Control = lblFindPathStart AnchorSideTop.Control = cbFollowSymLinks AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnChooseFolder Left = 5 Height = 23 Top = 19 Width = 707 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 2 ItemHeight = 15 TabOrder = 1 end object btnChooseFolder: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cmbFindPathStart AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cmbFindPathStart AnchorSideBottom.Side = asrBottom Left = 714 Height = 23 Top = 19 Width = 23 Anchors = [akTop, akRight, akBottom] OnClick = btnSelDirClick end object lblExcludeDirectories: TLabel AnchorSideLeft.Control = cmbFindPathStart AnchorSideTop.Control = cmbFindPathStart AnchorSideTop.Side = asrBottom Left = 5 Height = 15 Top = 45 Width = 117 BorderSpacing.Top = 3 Caption = 'E&xclude subdirectories' FocusControl = cmbExcludeDirectories ParentColor = False end object cmbExcludeDirectories: TComboBoxWithDelItems AnchorSideLeft.Control = lblExcludeDirectories AnchorSideTop.Control = lblExcludeDirectories AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlDirectoriesDepth Left = 5 Height = 23 Hint = 'Enter directories names that should be excluded from search separated with ";"' Top = 60 Width = 527 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 5 BorderSpacing.Bottom = 5 ItemHeight = 15 ParentShowHint = False ShowHint = True TabOrder = 2 end object pnlDirectoriesDepth: TPanel AnchorSideTop.Control = lblExcludeDirectories AnchorSideRight.Control = gbDirectories AnchorSideRight.Side = asrBottom Left = 537 Height = 51 Top = 45 Width = 200 Anchors = [akTop, akRight] BevelOuter = bvNone ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 51 ClientWidth = 200 TabOrder = 3 object lblSearchDepth: TLabel Left = 0 Height = 15 Top = 0 Width = 200 Caption = 'Search su&bdirectories:' FocusControl = cmbSearchDepth ParentColor = False end object cmbSearchDepth: TComboBox Left = 0 Height = 23 Top = 15 Width = 200 ItemHeight = 15 Style = csDropDownList TabOrder = 0 end end object cbSelectedFiles: TCheckBox AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbFollowSymLinks AnchorSideBottom.Control = cbFollowSymLinks AnchorSideBottom.Side = asrBottom Left = 458 Height = 19 Top = 0 Width = 169 Anchors = [akRight, akBottom] BorderSpacing.Right = 6 Caption = 'Selected directories and files' OnChange = cbSelectedFilesChange TabOrder = 4 end object cbOpenedTabs: TCheckBox AnchorSideRight.Control = cbSelectedFiles AnchorSideBottom.Control = cbSelectedFiles AnchorSideBottom.Side = asrBottom Left = 365 Height = 19 Top = 0 Width = 87 Anchors = [akRight, akBottom] BorderSpacing.Right = 6 Caption = 'Opened tabs' OnChange = cbOpenedTabsChange TabOrder = 5 end end object gbFiles: TGroupBox AnchorSideLeft.Control = tsStandard AnchorSideTop.Control = gbDirectories AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsStandard AnchorSideRight.Side = asrBottom Left = 3 Height = 108 Top = 119 Width = 746 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Files' ChildSizing.LeftRightSpacing = 5 ClientHeight = 88 ClientWidth = 742 TabOrder = 1 object lblFindFileMask: TLabel AnchorSideLeft.Control = gbFiles AnchorSideBottom.Control = cbPartialNameSearch AnchorSideBottom.Side = asrBottom Left = 5 Height = 15 Top = 4 Width = 51 Anchors = [akLeft, akBottom] Caption = '&File mask' FocusControl = cmbFindFileMask Font.Style = [fsBold] ParentColor = False ParentFont = False end object cmbFindFileMask: TComboBoxWithDelItems AnchorSideLeft.Control = gbFiles AnchorSideTop.Control = lblFindFileMask AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFiles AnchorSideRight.Side = asrBottom Left = 5 Height = 23 Hint = 'Enter files names separated with ";"' Top = 19 Width = 732 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 ParentShowHint = False ShowHint = True TabOrder = 0 end object lblExcludeFiles: TLabel AnchorSideLeft.Control = cmbFindFileMask AnchorSideTop.Control = cmbFindFileMask AnchorSideTop.Side = asrBottom Left = 5 Height = 15 Top = 45 Width = 64 BorderSpacing.Top = 3 Caption = '&Exclude files' FocusControl = cmbExcludeFiles ParentColor = False end object cmbExcludeFiles: TComboBoxWithDelItems AnchorSideLeft.Control = gbFiles AnchorSideTop.Control = lblExcludeFiles AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFiles AnchorSideRight.Side = asrBottom Left = 5 Height = 23 Hint = 'Enter files names that should be excluded from search separated with ";"' Top = 60 Width = 732 Anchors = [akTop, akLeft, akRight] BorderSpacing.Bottom = 5 ItemHeight = 15 ParentShowHint = False ShowHint = True TabOrder = 1 end object cbPartialNameSearch: TCheckBox AnchorSideRight.Control = cbRegExp AnchorSideBottom.Control = cbRegExp AnchorSideBottom.Side = asrBottom Left = 450 Height = 19 Top = 0 Width = 163 Anchors = [akRight, akBottom] BorderSpacing.Right = 6 Caption = 'Searc&h for part of file name' Checked = True OnChange = cbPartialNameSearchChange State = cbChecked TabOrder = 3 end object cbRegExp: TCheckBox AnchorSideTop.Control = gbFiles AnchorSideRight.Control = gbFiles AnchorSideRight.Side = asrBottom Left = 619 Height = 19 Top = 0 Width = 118 Anchors = [akTop, akRight] Caption = '&Regular expression' OnChange = cbRegExpChange TabOrder = 4 end object cbFindInArchive: TCheckBox AnchorSideRight.Control = cbPartialNameSearch AnchorSideBottom.Control = cbPartialNameSearch AnchorSideBottom.Side = asrBottom Left = 330 Height = 19 Top = 0 Width = 114 Anchors = [akRight, akBottom] BorderSpacing.Right = 6 Caption = 'Search in &archives' OnChange = cbFindInArchiveChange TabOrder = 2 end end object gbFindData: TGroupBox AnchorSideLeft.Control = tsStandard AnchorSideTop.Control = gbFiles AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsStandard AnchorSideRight.Side = asrBottom Left = 3 Height = 123 Top = 227 Width = 746 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Find Data' ChildSizing.TopBottomSpacing = 2 ClientHeight = 103 ClientWidth = 742 TabOrder = 2 object lblEncoding: TLabel AnchorSideLeft.Control = gbFindData AnchorSideTop.Control = cmbEncoding AnchorSideTop.Side = asrCenter AnchorSideRight.Control = CheksPanel AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 81 Width = 53 BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = 'Encodin&g:' FocusControl = cmbEncoding ParentColor = False end object cbCaseSens: TCheckBox AnchorSideLeft.Control = cbNotContainingText AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbNotContainingText AnchorSideTop.Side = asrCenter Left = 239 Height = 19 Top = 55 Width = 93 BorderSpacing.Left = 36 BorderSpacing.Top = 4 BorderSpacing.Bottom = 8 Caption = 'Case sens&itive' OnChange = cbCaseSensChange TabOrder = 4 end object cbNotContainingText: TCheckBox AnchorSideLeft.Control = lblEncoding AnchorSideTop.Control = cmbReplaceText AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 55 Width = 197 BorderSpacing.Top = 4 Caption = 'Find files N&OT containing the text' TabOrder = 3 end object cmbEncoding: TComboBox AnchorSideLeft.Control = cmbReplaceText AnchorSideTop.Control = cbNotContainingText AnchorSideTop.Side = asrBottom Left = 112 Height = 23 Top = 77 Width = 100 BorderSpacing.Top = 3 BorderSpacing.Bottom = 3 ItemHeight = 15 OnSelect = cmbEncodingSelect Style = csDropDownList TabOrder = 7 end object btnEncoding: TKASButton AnchorSideLeft.Control = cmbEncoding AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cmbEncoding AnchorSideBottom.Control = cmbEncoding AnchorSideBottom.Side = asrBottom Left = 215 Height = 23 Top = 77 Width = 24 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 2 TabOrder = 8 TabStop = True OnClick = btnEncodingClick end object cmbFindText: TComboBoxWithDelItems AnchorSideLeft.Control = CheksPanel AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbFindData AnchorSideRight.Control = gbFindData AnchorSideRight.Side = asrBottom Left = 112 Height = 23 Top = 2 Width = 627 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 3 BorderSpacing.Right = 3 ItemHeight = 15 TabOrder = 1 end object cmbReplaceText: TComboBoxWithDelItems AnchorSideLeft.Control = cmbFindText AnchorSideTop.Control = cmbFindText AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFindData AnchorSideRight.Side = asrBottom Left = 112 Height = 23 Top = 28 Width = 627 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 3 BorderSpacing.Right = 3 ItemHeight = 15 TabOrder = 2 end object CheksPanel: TPanel AnchorSideLeft.Control = gbFindData AnchorSideTop.Control = cmbFindText AnchorSideBottom.Control = cmbReplaceText AnchorSideBottom.Side = asrBottom Left = 0 Height = 49 Top = 2 Width = 109 Anchors = [akTop, akLeft, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 49 ClientWidth = 109 TabOrder = 0 object cbFindText: TCheckBox AnchorSideLeft.Control = CheksPanel AnchorSideTop.Control = CheksPanel AnchorSideRight.Side = asrBottom Left = 6 Height = 19 Top = 2 Width = 97 BorderSpacing.Left = 6 BorderSpacing.Top = 2 BorderSpacing.Right = 6 Caption = 'Find &text in file' OnChange = cbFindTextChange TabOrder = 0 end object cbReplaceText: TCheckBox AnchorSideLeft.Control = CheksPanel AnchorSideTop.Control = CheksPanel AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = CheksPanel AnchorSideBottom.Side = asrBottom Left = 6 Height = 19 Top = 28 Width = 77 Anchors = [akLeft, akBottom] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Bottom = 2 Caption = 'Re&place by' OnChange = cbReplaceTextChange TabOrder = 1 end end object cbTextRegExp: TCheckBox AnchorSideLeft.Control = cbCaseSens AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCaseSens AnchorSideTop.Side = asrCenter Left = 344 Height = 19 Top = 55 Width = 118 BorderSpacing.Left = 12 Caption = 'Reg&ular expression' OnChange = cbTextRegExpChange TabOrder = 5 end object chkHex: TCheckBox AnchorSideLeft.Control = cbTextRegExp AnchorSideTop.Control = cmbEncoding AnchorSideTop.Side = asrCenter Left = 344 Height = 19 Top = 79 Width = 88 Caption = 'Hexadeci&mal' OnChange = chkHexChange TabOrder = 9 end object cbOfficeXML: TCheckBox AnchorSideLeft.Control = cbTextRegExp AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTextRegExp Left = 592 Height = 24 Top = 67 Width = 93 BorderSpacing.Left = 15 Caption = 'Offi&ce XML' OnChange = cbOfficeXMLChange ParentShowHint = False ShowHint = True TabOrder = 6 end end end object tsAdvanced: TTabSheet Caption = 'Advanced' ChildSizing.LeftRightSpacing = 3 ChildSizing.TopBottomSpacing = 3 ClientHeight = 356 ClientWidth = 752 ImageIndex = 1 object cbDateFrom: TCheckBox AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = seFileSizeFrom AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 127 Width = 76 BorderSpacing.Left = 6 BorderSpacing.Top = 13 Caption = '&Date from:' OnChange = cbDateFromChange TabOrder = 8 end object cbNotOlderThan: TCheckBox AnchorSideLeft.Control = seNotOlderThan AnchorSideTop.Control = tsAdvanced Left = 3 Height = 19 Top = 18 Width = 100 BorderSpacing.Top = 18 Caption = 'N&ot older than:' Color = clBtnFace OnChange = cbNotOlderThanChange ParentColor = False TabOrder = 0 end object seNotOlderThan: TSpinEdit AnchorSideLeft.Control = ZVDateFrom AnchorSideTop.Control = cbNotOlderThan AnchorSideTop.Side = asrBottom AnchorSideRight.Control = ZVDateFrom AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cmbNotOlderThanUnit AnchorSideBottom.Side = asrBottom Left = 3 Height = 23 Top = 37 Width = 83 Anchors = [akTop, akLeft, akRight, akBottom] MaxValue = 999999999 OnChange = seNotOlderThanChange TabOrder = 1 end object cmbNotOlderThanUnit: TComboBox AnchorSideLeft.Control = ZVDateTo AnchorSideTop.Control = cbNotOlderThan AnchorSideTop.Side = asrBottom AnchorSideRight.Control = ZVDateTo AnchorSideRight.Side = asrBottom Left = 116 Height = 23 Top = 37 Width = 83 Anchors = [akTop, akLeft, akRight] Enabled = False ItemHeight = 15 Style = csDropDownList TabOrder = 2 end object cbFileSizeFrom: TCheckBox AnchorSideLeft.Control = ZVDateFrom AnchorSideTop.Control = seNotOlderThan AnchorSideTop.Side = asrBottom Left = 3 Height = 19 Top = 72 Width = 72 BorderSpacing.Top = 12 Caption = 'S&ize from:' OnChange = cbFileSizeFromChange TabOrder = 3 end object cbDateTo: TCheckBox AnchorSideLeft.Control = ZVDateTo AnchorSideTop.Control = cbDateFrom AnchorSideTop.Side = asrCenter Left = 116 Height = 19 Top = 127 Width = 61 BorderSpacing.Top = 18 Caption = 'Dat&e to:' OnChange = cbDateToChange TabOrder = 10 end object cbFileSizeTo: TCheckBox AnchorSideLeft.Control = ZVDateTo AnchorSideTop.Control = cbFileSizeFrom Left = 116 Height = 19 Top = 72 Width = 57 Caption = 'Si&ze to:' OnChange = cbFileSizeToChange TabOrder = 5 end object seFileSizeFrom: TSpinEdit AnchorSideLeft.Control = ZVDateFrom AnchorSideTop.Control = cbFileSizeFrom AnchorSideTop.Side = asrBottom AnchorSideRight.Control = ZVDateFrom AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cmbFileSizeUnit AnchorSideBottom.Side = asrBottom Left = 3 Height = 23 Top = 91 Width = 83 Anchors = [akTop, akLeft, akRight, akBottom] MaxValue = 2147483647 OnChange = seFileSizeFromChange TabOrder = 4 end object seFileSizeTo: TSpinEdit AnchorSideLeft.Control = ZVDateTo AnchorSideTop.Control = cbFileSizeTo AnchorSideTop.Side = asrBottom AnchorSideRight.Control = ZVDateTo AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cmbFileSizeUnit AnchorSideBottom.Side = asrBottom Left = 116 Height = 23 Top = 91 Width = 83 Anchors = [akTop, akLeft, akRight, akBottom] MaxValue = 2147483647 OnChange = seFileSizeToChange TabOrder = 6 end object cmbFileSizeUnit: TComboBox AnchorSideLeft.Control = ZVTimeFrom AnchorSideTop.Control = cbFileSizeTo AnchorSideTop.Side = asrBottom AnchorSideRight.Control = ZVTimeTo AnchorSideRight.Side = asrBottom Left = 229 Height = 23 Top = 91 Width = 160 Anchors = [akTop, akLeft, akRight] Enabled = False ItemHeight = 15 Style = csDropDownList TabOrder = 7 end object cbTimeFrom: TCheckBox AnchorSideLeft.Control = ZVTimeFrom AnchorSideTop.Control = cbDateFrom AnchorSideTop.Side = asrCenter Left = 229 Height = 19 Top = 127 Width = 79 BorderSpacing.Top = 12 Caption = '&Time from:' OnChange = cbTimeFromChange TabOrder = 12 end object cbTimeTo: TCheckBox AnchorSideLeft.Control = ZVTimeTo AnchorSideTop.Control = cbDateFrom AnchorSideTop.Side = asrCenter Left = 324 Height = 19 Top = 127 Width = 64 Caption = 'Ti&me to:' OnChange = cbTimeToChange TabOrder = 14 end object Bevel2: TBevel AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = ZVDateFrom AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsAdvanced AnchorSideRight.Side = asrBottom Left = 6 Height = 4 Top = 181 Width = 740 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 12 BorderSpacing.Right = 6 Shape = bsTopLine Style = bsRaised end object ZVDateFrom: TDateTimePicker AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = cbDateFrom AnchorSideTop.Side = asrBottom Left = 3 Height = 23 Top = 146 Width = 83 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 9 BorderSpacing.Left = 3 TrailingSeparator = False LeadingZeros = True NullInputAllowed = False Kind = dtkDate TimeFormat = tf24 TimeDisplay = tdHMS DateMode = dmComboBox Date = 40598 Time = 0.925837488422985 UseDefaultSeparators = True HideDateTimeParts = [] MonthNames = 'Long' OnChange = ZVDateFromChange end object ZVDateTo: TDateTimePicker AnchorSideLeft.Control = ZVDateFrom AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ZVDateFrom AnchorSideTop.Side = asrCenter Left = 116 Height = 23 Top = 146 Width = 83 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 11 BorderSpacing.Left = 30 TrailingSeparator = False LeadingZeros = True NullInputAllowed = False Kind = dtkDate TimeFormat = tf24 TimeDisplay = tdHMS DateMode = dmComboBox Date = 40598 Time = 0.927234872688132 UseDefaultSeparators = True HideDateTimeParts = [] MonthNames = 'Long' OnChange = ZVDateToChange end object ZVTimeFrom: TDateTimePicker AnchorSideLeft.Control = ZVDateTo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ZVDateFrom AnchorSideBottom.Control = ZVDateFrom AnchorSideBottom.Side = asrBottom Left = 229 Height = 23 Top = 146 Width = 65 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 13 BorderSpacing.Left = 30 TrailingSeparator = False LeadingZeros = True Anchors = [akTop, akLeft, akBottom] NullInputAllowed = False Kind = dtkTime TimeFormat = tf24 TimeDisplay = tdHMS DateMode = dmComboBox Date = 40598 Time = 0.930765335644537 UseDefaultSeparators = True HideDateTimeParts = [] MonthNames = 'Long' OnChange = ZVTimeFromChange end object ZVTimeTo: TDateTimePicker AnchorSideLeft.Control = ZVTimeFrom AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ZVDateFrom AnchorSideBottom.Control = ZVDateFrom AnchorSideBottom.Side = asrBottom Left = 324 Height = 23 Top = 146 Width = 65 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 15 BorderSpacing.Left = 30 TrailingSeparator = False LeadingZeros = True Anchors = [akTop, akLeft, akBottom] NullInputAllowed = False Kind = dtkTime TimeFormat = tf24 TimeDisplay = tdHMS DateMode = dmComboBox Date = 40598 Time = 0.930765335644537 UseDefaultSeparators = True HideDateTimeParts = [] MonthNames = 'Long' OnChange = ZVTimeToChange end object lblAttributes: TLabel AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = Bevel2 AnchorSideTop.Side = asrBottom Left = 3 Height = 15 Top = 193 Width = 52 BorderSpacing.Left = 3 BorderSpacing.Top = 8 Caption = 'Attri&butes' FocusControl = edtAttrib ParentColor = False end object edtAttrib: TEdit AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = lblAttributes AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnAddAttribute Left = 3 Height = 23 Top = 212 Width = 636 HelpType = htKeyword HelpKeyword = '/findfiles.html#attributes' Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 3 BorderSpacing.Top = 4 BorderSpacing.Right = 3 ParentShowHint = False ShowHint = True TabOrder = 16 end object btnAddAttribute: TButton AnchorSideLeft.Control = edtAttrib AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAttrsHelp Left = 642 Height = 26 Top = 210 Width = 48 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Around = 3 Caption = '&Add' Constraints.MinHeight = 26 OnClick = btnAddAttributeClick TabOrder = 17 end object btnAttrsHelp: TButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrCenter AnchorSideRight.Control = tsAdvanced AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 693 Height = 27 Top = 210 Width = 53 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 1 Caption = '&Help' Constraints.MinHeight = 26 OnClick = btnAttrsHelpClick TabOrder = 18 end object chkDuplicates: TCheckBox AnchorSideLeft.Control = edtAttrib AnchorSideTop.Control = Bevel3 AnchorSideTop.Side = asrBottom Left = 3 Height = 19 Top = 263 Width = 122 BorderSpacing.Top = 12 Caption = 'Find du&plicate files:' OnChange = chkDuplicatesChange TabOrder = 19 end object pnlDuplicates: TPanel AnchorSideLeft.Control = chkDuplicates AnchorSideTop.Control = chkDuplicates AnchorSideTop.Side = asrBottom Left = 11 Height = 19 Top = 282 Width = 259 AutoSize = True BorderSpacing.Left = 8 BevelOuter = bvNone ChildSizing.HorizontalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 19 ClientWidth = 259 Enabled = False TabOrder = 20 object chkDuplicateName: TCheckBox Left = 0 Height = 19 Top = 0 Width = 81 Caption = 'same name' TabOrder = 0 end object chkDuplicateSize: TCheckBox Left = 89 Height = 19 Top = 0 Width = 70 Caption = 'same size' OnChange = chkDuplicateSizeChange TabOrder = 1 end object chkDuplicateHash: TCheckBox Left = 89 Height = 19 Top = 0 Width = 70 Caption = 'same hash' OnChange = chkDuplicateHashChange TabOrder = 2 end object chkDuplicateContent: TCheckBox Left = 167 Height = 19 Top = 0 Width = 92 Caption = 'same content' OnChange = chkDuplicateContentChange TabOrder = 3 end end object Bevel3: TBevel AnchorSideLeft.Control = tsAdvanced AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsAdvanced AnchorSideRight.Side = asrBottom Left = 6 Height = 4 Top = 247 Width = 740 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 12 BorderSpacing.Right = 6 Shape = bsTopLine Style = bsRaised end end object tsPlugins: TTabSheet Caption = 'Plugins' ChildSizing.LeftRightSpacing = 3 ChildSizing.TopBottomSpacing = 3 ClientHeight = 356 ClientWidth = 752 object cbUsePlugin: TCheckBox AnchorSideLeft.Control = tsPlugins AnchorSideTop.Control = cmbPlugin AnchorSideTop.Side = asrCenter Left = 3 Height = 19 Top = 12 Width = 116 Caption = '&Use search plugin:' OnChange = cbUsePluginChange TabOrder = 0 end object cmbPlugin: TComboBox AnchorSideLeft.Control = cbUsePlugin AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = tsPlugins AnchorSideRight.Control = tsPlugins AnchorSideRight.Side = asrBottom Left = 122 Height = 23 Top = 10 Width = 627 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 3 BorderSpacing.Top = 10 Enabled = False ItemHeight = 15 Style = csDropDownList TabOrder = 1 end inline frmContentPlugins: TfrmSearchPlugin AnchorSideLeft.Control = tsPlugins AnchorSideTop.Control = cmbPlugin AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsPlugins AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = tsPlugins AnchorSideBottom.Side = asrBottom Left = 6 Height = 311 Top = 39 Width = 740 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 6 ClientHeight = 311 ClientWidth = 740 TabOrder = 2 inherited pnlTable: TScrollBox Height = 196 Width = 740 end inherited pnlButtons: TPanel Top = 261 Width = 740 ClientWidth = 740 end inherited HeaderControl: THeaderControl Width = 740 end inherited pnlHeader: TPanel Width = 740 ClientWidth = 740 inherited chkUsePlugins: TCheckBox Width = 312 end inherited rbAnd: TRadioButton Left = 318 Width = 210 end inherited rbOr: TRadioButton Left = 534 Width = 206 end end end end object tsLoadSave: TTabSheet Caption = 'Load/Save' ChildSizing.LeftRightSpacing = 3 ChildSizing.TopBottomSpacing = 3 ClientHeight = 356 ClientWidth = 752 OnShow = tsLoadSaveShow object lblTemplateHeader: TLabel Left = 3 Height = 15 Top = 3 Width = 746 Align = alTop BorderSpacing.Left = 3 BorderSpacing.Top = 3 BorderSpacing.Right = 3 Caption = '&Previous searches:' FocusControl = lbSearchTemplates ParentColor = False end object lbSearchTemplates: TListBox Left = 3 Height = 272 Top = 18 Width = 746 Align = alClient BorderSpacing.Left = 3 BorderSpacing.Right = 3 BorderSpacing.Bottom = 3 ItemHeight = 0 OnDblClick = lbSearchTemplatesDblClick OnSelectionChange = lbSearchTemplatesSelectionChange ScrollWidth = 708 TabOrder = 2 end object lblSearchContents: TPanel Left = 3 Height = 21 Top = 296 Width = 746 Align = alBottom Alignment = taLeftJustify AutoSize = True BorderSpacing.Top = 3 BorderSpacing.Bottom = 3 BorderSpacing.Around = 3 BevelOuter = bvLowered Constraints.MinHeight = 21 TabOrder = 0 end object pnlLoadSaveBottom: TPanel Left = 3 Height = 30 Top = 323 Width = 746 Align = alBottom AutoSize = True BorderSpacing.Around = 3 BevelOuter = bvNone ClientHeight = 30 ClientWidth = 746 TabOrder = 1 object pnlLoadSaveBottomButtons: TPanel Left = 336 Height = 30 Top = 0 Width = 410 Align = alRight AutoSize = True BevelOuter = bvNone ChildSizing.Layout = cclTopToBottomThenLeftToRight ClientHeight = 30 ClientWidth = 410 TabOrder = 0 object btnSearchLoad: TButton Left = 0 Height = 30 Top = 0 Width = 75 AutoSize = True BorderSpacing.Right = 3 Caption = 'L&oad' Constraints.MinWidth = 75 OnClick = btnSearchLoadClick TabOrder = 0 end object btnSearchSave: TButton Left = 78 Height = 30 Top = 0 Width = 75 AutoSize = True BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'S&ave' Constraints.MinWidth = 75 OnClick = btnSearchSaveClick TabOrder = 1 end object btnSearchSaveWithStartingPath: TButton Left = 156 Height = 30 Hint = 'If saved then "Start in directory" will be restored when loading template. Use it if you want to fix searching to a certain directory' Top = 0 Width = 176 AutoSize = True BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'Sa&ve with "Start in directory"' Constraints.MinWidth = 75 OnClick = btnSearchSaveWithStartingPathClick ParentShowHint = False ShowHint = True TabOrder = 2 end object btnSearchDelete: TButton Left = 335 Height = 30 Top = 0 Width = 75 AutoSize = True BorderSpacing.Left = 3 Caption = '&Delete' Constraints.MinHeight = 30 Constraints.MinWidth = 75 OnClick = btnSearchDeleteClick TabOrder = 3 end end end end object tsResults: TTabSheet Caption = 'Results' ChildSizing.LeftRightSpacing = 3 ChildSizing.TopBottomSpacing = 3 ClientHeight = 356 ClientWidth = 752 object pnlResults: TPanel AnchorSideTop.Control = pnlFindFile Left = 3 Height = 350 Top = 3 Width = 746 Align = alClient BevelOuter = bvNone ClientHeight = 350 ClientWidth = 746 FullRepaint = False TabOrder = 0 object pnlStatus: TPanel Left = 0 Height = 8 Top = 0 Width = 746 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 8 ClientWidth = 746 FullRepaint = False TabOrder = 0 object lblStatus: TLabel AnchorSideLeft.Control = pnlStatus AnchorSideTop.Control = lblCurrent AnchorSideTop.Side = asrBottom Left = 3 Height = 1 Top = 7 Width = 1 BorderSpacing.Left = 3 BorderSpacing.Top = 3 ParentColor = False ParentFont = False end object lblCurrent: TLabel AnchorSideLeft.Control = pnlStatus AnchorSideTop.Control = pnlStatus Left = 3 Height = 1 Top = 3 Width = 1 BorderSpacing.Left = 3 BorderSpacing.Top = 3 ParentColor = False ParentFont = False end object lblFound: TLabel AnchorSideTop.Control = lblStatus AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlStatus AnchorSideRight.Side = asrBottom Left = 742 Height = 1 Top = 7 Width = 1 Anchors = [akTop, akRight] BorderSpacing.Right = 3 ParentColor = False ParentFont = False end end object lsFoundedFiles: TListBox Left = 3 Height = 300 Top = 11 Width = 740 Align = alClient BorderSpacing.Around = 3 ItemHeight = 0 MultiSelect = True OnDblClick = lsFoundedFilesDblClick OnKeyDown = lsFoundedFilesKeyDown OnMouseDown = lsFoundedFilesMouseDown OnMouseUp = lsFoundedFilesMouseUp OnMouseWheelDown = lsFoundedFilesMouseWheelDown OnMouseWheelUp = lsFoundedFilesMouseWheelUp ScrollWidth = 735 TabOrder = 1 end object pnlResultsBottom: TPanel Left = 3 Height = 33 Top = 314 Width = 740 Align = alBottom AutoSize = True BorderSpacing.Around = 3 BevelOuter = bvNone ClientHeight = 33 ClientWidth = 740 Enabled = False TabOrder = 2 object pnlResultsBottomButtons: TPanel Left = 426 Height = 33 Top = 0 Width = 314 Align = alRight AutoSize = True BevelOuter = bvNone ClientHeight = 33 ClientWidth = 314 TabOrder = 0 object btnWorkWithFound: TButton AnchorSideLeft.Side = asrBottom Left = 204 Height = 33 Top = 0 Width = 110 Action = actFeedToListbox Align = alRight AutoSize = True BorderSpacing.InnerBorder = 4 Constraints.MinWidth = 50 TabOrder = 0 end object btnGoToPath: TButton Left = 119 Height = 33 Top = 0 Width = 82 Action = actGoToFile Align = alRight AutoSize = True BorderSpacing.Left = 3 BorderSpacing.Right = 3 BorderSpacing.InnerBorder = 4 Constraints.MinWidth = 50 TabOrder = 3 end object btnView: TButton Left = 0 Height = 33 Top = 0 Width = 59 Action = actView Align = alRight AutoSize = True BorderSpacing.Right = 3 BorderSpacing.InnerBorder = 4 Constraints.MinWidth = 50 TabOrder = 1 end object btnEdit: TButton Left = 62 Height = 33 Top = 0 Width = 54 Action = actEdit Align = alRight AutoSize = True BorderSpacing.Right = 3 BorderSpacing.InnerBorder = 4 Constraints.MinWidth = 50 TabOrder = 2 end end end end end end object pnlButtons: TPanel Left = 766 Height = 403 Top = 40 Width = 103 Align = alRight Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 40 BevelOuter = bvNone ChildSizing.VerticalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 403 ClientWidth = 103 Constraints.MinWidth = 100 TabOrder = 1 object btnUseTemplate: TButton Left = 0 Height = 33 Top = 0 Width = 103 AutoSize = True BorderSpacing.InnerBorder = 4 Caption = 'Use template' ModalResult = 1 OnKeyDown = btnNewSearchKeyDown TabOrder = 0 Visible = False end object btnSaveTemplate: TButton AnchorSideBottom.Side = asrBottom Left = 0 Height = 33 Top = 39 Width = 103 AutoSize = True BorderSpacing.InnerBorder = 4 Caption = '&Save' ModalResult = 1 OnClick = btnSearchSaveClick OnKeyDown = btnNewSearchKeyDown TabOrder = 1 Visible = False end object btnStart: TButton Left = 0 Height = 33 Top = 78 Width = 103 Action = actStart AutoSize = True BorderSpacing.InnerBorder = 4 OnKeyDown = btnNewSearchKeyDown TabOrder = 2 end object btnStop: TButton Left = 0 Height = 33 Top = 117 Width = 103 Action = actCancel AutoSize = True BorderSpacing.InnerBorder = 4 OnKeyDown = btnNewSearchKeyDown TabOrder = 3 end object btnClose: TButton Left = 0 Height = 33 Top = 156 Width = 103 Action = actClose AutoSize = True BorderSpacing.InnerBorder = 4 OnKeyDown = btnNewSearchKeyDown TabOrder = 4 end object btnNewSearch: TButton Left = 0 Height = 33 Top = 219 Width = 103 Action = actNewSearch AutoSize = True BorderSpacing.Top = 30 BorderSpacing.InnerBorder = 4 OnKeyDown = btnNewSearchKeyDown TabOrder = 5 end object btnLastSearch: TButton Left = 0 Height = 33 Top = 258 Width = 103 Action = actLastSearch AutoSize = True BorderSpacing.InnerBorder = 4 OnKeyDown = btnNewSearchKeyDown TabOrder = 6 end end end object PopupMenuFind: TPopupMenu OnPopup = PopupMenuFindPopup left = 312 top = 48 object miOpenInNewTab: TMenuItem Caption = 'Open In New Tab(s)' OnClick = miOpenInNewTabClick end object miShowInViewer: TMenuItem Caption = 'Show In Viewer' OnClick = miShowInViewerClick end object miShowInEditor: TMenuItem Caption = 'Show In Editor' OnClick = miShowInEditorClick end object miRemoveFromLlist: TMenuItem Caption = 'Remove from list' OnClick = miRemoveFromLlistClick end object miShowAllFound: TMenuItem Caption = 'Show all found items' Enabled = False OnClick = miShowAllFoundClick end end object actList: TActionList left = 168 top = 48 object actIntelliFocus: TAction Caption = 'Find Data' OnExecute = actExecute end object actStart: TAction Caption = '&Start' OnExecute = actExecute end object actCancel: TAction Caption = 'C&ancel' Enabled = False OnExecute = actExecute end object actClose: TAction Caption = '&Close' OnExecute = actExecute end object actNewSearch: TAction Caption = '&New search' OnExecute = actExecute end object actNewSearchClearFilters: TAction Caption = 'New search (clear filters)' OnExecute = actExecute end object actLastSearch: TAction Caption = '&Last search' Enabled = False OnExecute = actExecute end object actView: TAction Caption = '&View' Enabled = False OnExecute = actExecute end object actEdit: TAction Caption = '&Edit' Enabled = False OnExecute = actExecute end object actGoToFile: TAction Caption = '&Go to file' Enabled = False OnExecute = actExecute end object actFeedToListbox: TAction Caption = 'Feed to &listbox' Enabled = False OnExecute = actExecute end object actPageStandard: TAction Caption = 'Go to page "Standard"' OnExecute = actExecute end object actPageAdvanced: TAction Caption = 'Go to page "Advanced"' OnExecute = actExecute end object actPagePlugins: TAction Caption = 'Go to page "Plugins"' OnExecute = actExecute end object actPageLoadSave: TAction Caption = 'Go to page "Load/Save"' OnExecute = actExecute end object actPageResults: TAction Caption = 'Go to page "Results"' OnExecute = actExecute end object actCancelClose: TAction Caption = 'Cancel search and close window' OnExecute = actExecute end object actFreeFromMem: TAction Caption = 'Cancel search, close and free from memory' OnExecute = actExecute end object actFreeFromMemAllOthers: TAction Caption = 'For all other "Find files", cancel, close and free from memory' OnExecute = actExecute end object actConfigFileSearchHotKeys: TAction Caption = 'Configuration of hot keys' OnExecute = actExecute end object actPageNext: TAction Caption = 'Switch to Nex&t Page' OnExecute = actExecute end object actPagePrev: TAction Caption = 'Switch to &Previous Page' OnExecute = actExecute end end object mmMainMenu: TMainMenu left = 232 top = 48 object miAction: TMenuItem Caption = '&Action' object miNewSearch: TMenuItem Action = actNewSearch end object miNewSearchClearFilters: TMenuItem Action = actNewSearchClearFilters end object miLastSearch: TMenuItem Action = actLastSearch end object miStart: TMenuItem Action = actStart end object miCancel: TMenuItem Action = actCancel end object miSeparator1: TMenuItem Caption = '-' end object miClose: TMenuItem Action = actClose end object miCancelClose: TMenuItem Action = actCancelClose end object miFreeFromMem: TMenuItem Action = actFreeFromMem end object miFreeFromMemAllOthers: TMenuItem Action = actFreeFromMemAllOthers Caption = 'For all others, cancel, close and free from memory' end end object miViewTab: TMenuItem Caption = '&View' object miPageStandard: TMenuItem Action = actPageStandard end object miPageAdvanced: TMenuItem Action = actPageAdvanced end object miPagePlugins: TMenuItem Action = actPagePlugins end object miPageLoadSave: TMenuItem Action = actPageLoadSave end object miPageResults: TMenuItem Action = actPageResults end object miSeparator2: TMenuItem Caption = '-' end end object miResult: TMenuItem Caption = '&Result' object miView: TMenuItem Action = actView end object miEdit: TMenuItem Action = actEdit end object miFeedToListbox: TMenuItem Action = actFeedToListbox end object miGoToFile: TMenuItem Action = actGoToFile end end object miOptions: TMenuItem Caption = 'Options' object miConfigFileSearchHotKeys: TMenuItem Action = actConfigFileSearchHotKeys end end end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fFindDlg.lrj�������������������������������������������������������������������0000644�0001750�0000144�00000036755�14743153644�015603� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":107491971,"name":"tfrmfinddlg.caption","sourcebytes":[70,105,110,100,32,102,105,108,101,115],"value":"Find files"}, {"hash":176467236,"name":"tfrmfinddlg.tsstandard.caption","sourcebytes":[83,116,97,110,100,97,114,100],"value":"Standard"}, {"hash":184387443,"name":"tfrmfinddlg.gbdirectories.caption","sourcebytes":[68,105,114,101,99,116,111,114,105,101,115],"value":"Directories"}, {"hash":235998121,"name":"tfrmfinddlg.lblfindpathstart.caption","sourcebytes":[83,116,97,114,116,32,105,110,32,38,100,105,114,101,99,116,111,114,121],"value":"Start in &directory"}, {"hash":225405123,"name":"tfrmfinddlg.cbfollowsymlinks.caption","sourcebytes":[70,111,108,108,111,119,32,115,38,121,109,108,105,110,107,115],"value":"Follow s&ymlinks"}, {"hash":49163891,"name":"tfrmfinddlg.lblexcludedirectories.caption","sourcebytes":[69,38,120,99,108,117,100,101,32,115,117,98,100,105,114,101,99,116,111,114,105,101,115],"value":"E&xclude subdirectories"}, {"hash":40753218,"name":"tfrmfinddlg.cmbexcludedirectories.hint","sourcebytes":[69,110,116,101,114,32,100,105,114,101,99,116,111,114,105,101,115,32,110,97,109,101,115,32,116,104,97,116,32,115,104,111,117,108,100,32,98,101,32,101,120,99,108,117,100,101,100,32,102,114,111,109,32,115,101,97,114,99,104,32,115,101,112,97,114,97,116,101,100,32,119,105,116,104,32,34,59,34],"value":"Enter directories names that should be excluded from search separated with \";\""}, {"hash":201746570,"name":"tfrmfinddlg.lblsearchdepth.caption","sourcebytes":[83,101,97,114,99,104,32,115,117,38,98,100,105,114,101,99,116,111,114,105,101,115,58],"value":"Search su&bdirectories:"}, {"hash":238646947,"name":"tfrmfinddlg.cbselectedfiles.caption","sourcebytes":[83,101,108,101,99,116,101,100,32,100,105,114,101,99,116,111,114,105,101,115,32,97,110,100,32,102,105,108,101,115],"value":"Selected directories and files"}, {"hash":187812819,"name":"tfrmfinddlg.cbopenedtabs.caption","sourcebytes":[79,112,101,110,101,100,32,116,97,98,115],"value":"Opened tabs"}, {"hash":5046979,"name":"tfrmfinddlg.gbfiles.caption","sourcebytes":[70,105,108,101,115],"value":"Files"}, {"hash":41260443,"name":"tfrmfinddlg.lblfindfilemask.caption","sourcebytes":[38,70,105,108,101,32,109,97,115,107],"value":"&File mask"}, {"hash":181442290,"name":"tfrmfinddlg.cmbfindfilemask.hint","sourcebytes":[69,110,116,101,114,32,102,105,108,101,115,32,110,97,109,101,115,32,115,101,112,97,114,97,116,101,100,32,119,105,116,104,32,34,59,34],"value":"Enter files names separated with \";\""}, {"hash":193387459,"name":"tfrmfinddlg.lblexcludefiles.caption","sourcebytes":[38,69,120,99,108,117,100,101,32,102,105,108,101,115],"value":"&Exclude files"}, {"hash":89629618,"name":"tfrmfinddlg.cmbexcludefiles.hint","sourcebytes":[69,110,116,101,114,32,102,105,108,101,115,32,110,97,109,101,115,32,116,104,97,116,32,115,104,111,117,108,100,32,98,101,32,101,120,99,108,117,100,101,100,32,102,114,111,109,32,115,101,97,114,99,104,32,115,101,112,97,114,97,116,101,100,32,119,105,116,104,32,34,59,34],"value":"Enter files names that should be excluded from search separated with \";\""}, {"hash":181172405,"name":"tfrmfinddlg.cbpartialnamesearch.caption","sourcebytes":[83,101,97,114,99,38,104,32,102,111,114,32,112,97,114,116,32,111,102,32,102,105,108,101,32,110,97,109,101],"value":"Searc&h for part of file name"}, {"hash":185056558,"name":"tfrmfinddlg.cbregexp.caption","sourcebytes":[38,82,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110],"value":"&Regular expression"}, {"hash":130525619,"name":"tfrmfinddlg.cbfindinarchive.caption","sourcebytes":[83,101,97,114,99,104,32,105,110,32,38,97,114,99,104,105,118,101,115],"value":"Search in &archives"}, {"hash":73721249,"name":"tfrmfinddlg.gbfinddata.caption","sourcebytes":[70,105,110,100,32,68,97,116,97],"value":"Find Data"}, {"hash":95209482,"name":"tfrmfinddlg.lblencoding.caption","sourcebytes":[69,110,99,111,100,105,110,38,103,58],"value":"Encodin&g:"}, {"hash":214401813,"name":"tfrmfinddlg.cbcasesens.caption","sourcebytes":[67,97,115,101,32,115,101,110,115,38,105,116,105,118,101],"value":"Case sens&itive"}, {"hash":22868708,"name":"tfrmfinddlg.cbnotcontainingtext.caption","sourcebytes":[70,105,110,100,32,102,105,108,101,115,32,78,38,79,84,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,116,101,120,116],"value":"Find files N&OT containing the text"}, {"hash":125468773,"name":"tfrmfinddlg.cbfindtext.caption","sourcebytes":[70,105,110,100,32,38,116,101,120,116,32,105,110,32,102,105,108,101],"value":"Find &text in file"}, {"hash":35720169,"name":"tfrmfinddlg.cbreplacetext.caption","sourcebytes":[82,101,38,112,108,97,99,101,32,98,121],"value":"Re&place by"}, {"hash":137727326,"name":"tfrmfinddlg.cbtextregexp.caption","sourcebytes":[82,101,103,38,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110],"value":"Reg&ular expression"}, {"hash":259470556,"name":"tfrmfinddlg.chkhex.caption","sourcebytes":[72,101,120,97,100,101,99,105,38,109,97,108],"value":"Hexadeci&mal"}, {"hash":214077868,"name":"tfrmfinddlg.cbofficexml.caption","sourcebytes":[79,102,102,105,38,99,101,32,88,77,76],"value":"Offi&ce XML"}, {"hash":197676484,"name":"tfrmfinddlg.tsadvanced.caption","sourcebytes":[65,100,118,97,110,99,101,100],"value":"Advanced"}, {"hash":122109610,"name":"tfrmfinddlg.cbdatefrom.caption","sourcebytes":[38,68,97,116,101,32,102,114,111,109,58],"value":"&Date from:"}, {"hash":34324922,"name":"tfrmfinddlg.cbnotolderthan.caption","sourcebytes":[78,38,111,116,32,111,108,100,101,114,32,116,104,97,110,58],"value":"N&ot older than:"}, {"hash":121136394,"name":"tfrmfinddlg.cbfilesizefrom.caption","sourcebytes":[83,38,105,122,101,32,102,114,111,109,58],"value":"S&ize from:"}, {"hash":113717674,"name":"tfrmfinddlg.cbdateto.caption","sourcebytes":[68,97,116,38,101,32,116,111,58],"value":"Dat&e to:"}, {"hash":235349146,"name":"tfrmfinddlg.cbfilesizeto.caption","sourcebytes":[83,105,38,122,101,32,116,111,58],"value":"Si&ze to:"}, {"hash":122046010,"name":"tfrmfinddlg.cbtimefrom.caption","sourcebytes":[38,84,105,109,101,32,102,114,111,109,58],"value":"&Time from:"}, {"hash":221716890,"name":"tfrmfinddlg.cbtimeto.caption","sourcebytes":[84,105,38,109,101,32,116,111,58],"value":"Ti&me to:"}, {"hash":193032515,"name":"tfrmfinddlg.lblattributes.caption","sourcebytes":[65,116,116,114,105,38,98,117,116,101,115],"value":"Attri&butes"}, {"hash":173988,"name":"tfrmfinddlg.btnaddattribute.caption","sourcebytes":[38,65,100,100],"value":"&Add"}, {"hash":2812976,"name":"tfrmfinddlg.btnattrshelp.caption","sourcebytes":[38,72,101,108,112],"value":"&Help"}, {"hash":39455530,"name":"tfrmfinddlg.chkduplicates.caption","sourcebytes":[70,105,110,100,32,100,117,38,112,108,105,99,97,116,101,32,102,105,108,101,115,58],"value":"Find du&plicate files:"}, {"hash":58146741,"name":"tfrmfinddlg.chkduplicatename.caption","sourcebytes":[115,97,109,101,32,110,97,109,101],"value":"same name"}, {"hash":58194565,"name":"tfrmfinddlg.chkduplicatesize.caption","sourcebytes":[115,97,109,101,32,115,105,122,101],"value":"same size"}, {"hash":58102040,"name":"tfrmfinddlg.chkduplicatehash.caption","sourcebytes":[115,97,109,101,32,104,97,115,104],"value":"same hash"}, {"hash":266181940,"name":"tfrmfinddlg.chkduplicatecontent.caption","sourcebytes":[115,97,109,101,32,99,111,110,116,101,110,116],"value":"same content"}, {"hash":121364483,"name":"tfrmfinddlg.tsplugins.caption","sourcebytes":[80,108,117,103,105,110,115],"value":"Plugins"}, {"hash":125449178,"name":"tfrmfinddlg.cbuseplugin.caption","sourcebytes":[38,85,115,101,32,115,101,97,114,99,104,32,112,108,117,103,105,110,58],"value":"&Use search plugin:"}, {"hash":91471358,"name":"tfrmfinddlg.frmcontentplugins.headercontrol.sections[0].text","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":5045284,"name":"tfrmfinddlg.frmcontentplugins.headercontrol.sections[1].text","sourcebytes":[70,105,101,108,100],"value":"Field"}, {"hash":113807362,"name":"tfrmfinddlg.frmcontentplugins.headercontrol.sections[2].text","sourcebytes":[79,112,101,114,97,116,111,114],"value":"Operator"}, {"hash":6063029,"name":"tfrmfinddlg.frmcontentplugins.headercontrol.sections[3].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, {"hash":125094805,"name":"tfrmfinddlg.tsloadsave.caption","sourcebytes":[76,111,97,100,47,83,97,118,101],"value":"Load/Save"}, {"hash":87316794,"name":"tfrmfinddlg.lbltemplateheader.caption","sourcebytes":[38,80,114,101,118,105,111,117,115,32,115,101,97,114,99,104,101,115,58],"value":"&Previous searches:"}, {"hash":5166452,"name":"tfrmfinddlg.btnsearchload.caption","sourcebytes":[76,38,111,97,100],"value":"L&oad"}, {"hash":5621957,"name":"tfrmfinddlg.btnsearchsave.caption","sourcebytes":[83,38,97,118,101],"value":"S&ave"}, {"hash":53200297,"name":"tfrmfinddlg.btnsearchsavewithstartingpath.hint","sourcebytes":[73,102,32,115,97,118,101,100,32,116,104,101,110,32,34,83,116,97,114,116,32,105,110,32,100,105,114,101,99,116,111,114,121,34,32,119,105,108,108,32,98,101,32,114,101,115,116,111,114,101,100,32,119,104,101,110,32,108,111,97,100,105,110,103,32,116,101,109,112,108,97,116,101,46,32,85,115,101,32,105,116,32,105,102,32,121,111,117,32,119,97,110,116,32,116,111,32,102,105,120,32,115,101,97,114,99,104,105,110,103,32,116,111,32,97,32,99,101,114,116,97,105,110,32,100,105,114,101,99,116,111,114,121],"value":"If saved then \"Start in directory\" will be restored when loading template. Use it if you want to fix searching to a certain directory"}, {"hash":171182594,"name":"tfrmfinddlg.btnsearchsavewithstartingpath.caption","sourcebytes":[83,97,38,118,101,32,119,105,116,104,32,34,83,116,97,114,116,32,105,110,32,100,105,114,101,99,116,111,114,121,34],"value":"Sa&ve with \"Start in directory\""}, {"hash":179055749,"name":"tfrmfinddlg.btnsearchdelete.caption","sourcebytes":[38,68,101,108,101,116,101],"value":"&Delete"}, {"hash":147506147,"name":"tfrmfinddlg.tsresults.caption","sourcebytes":[82,101,115,117,108,116,115],"value":"Results"}, {"hash":261119749,"name":"tfrmfinddlg.btnusetemplate.caption","sourcebytes":[85,115,101,32,116,101,109,112,108,97,116,101],"value":"Use template"}, {"hash":2857157,"name":"tfrmfinddlg.btnsavetemplate.caption","sourcebytes":[38,83,97,118,101],"value":"&Save"}, {"hash":247776137,"name":"tfrmfinddlg.miopeninnewtab.caption","sourcebytes":[79,112,101,110,32,73,110,32,78,101,119,32,84,97,98,40,115,41],"value":"Open In New Tab(s)"}, {"hash":178685522,"name":"tfrmfinddlg.mishowinviewer.caption","sourcebytes":[83,104,111,119,32,73,110,32,86,105,101,119,101,114],"value":"Show In Viewer"}, {"hash":198460146,"name":"tfrmfinddlg.mishowineditor.caption","sourcebytes":[83,104,111,119,32,73,110,32,69,100,105,116,111,114],"value":"Show In Editor"}, {"hash":53858676,"name":"tfrmfinddlg.miremovefromllist.caption","sourcebytes":[82,101,109,111,118,101,32,102,114,111,109,32,108,105,115,116],"value":"Remove from list"}, {"hash":125215667,"name":"tfrmfinddlg.mishowallfound.caption","sourcebytes":[83,104,111,119,32,97,108,108,32,102,111,117,110,100,32,105,116,101,109,115],"value":"Show all found items"}, {"hash":73721249,"name":"tfrmfinddlg.actintellifocus.caption","sourcebytes":[70,105,110,100,32,68,97,116,97],"value":"Find Data"}, {"hash":45787284,"name":"tfrmfinddlg.actstart.caption","sourcebytes":[38,83,116,97,114,116],"value":"&Start"}, {"hash":97012220,"name":"tfrmfinddlg.actcancel.caption","sourcebytes":[67,38,97,110,99,101,108],"value":"C&ancel"}, {"hash":44709525,"name":"tfrmfinddlg.actclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"}, {"hash":129025032,"name":"tfrmfinddlg.actnewsearch.caption","sourcebytes":[38,78,101,119,32,115,101,97,114,99,104],"value":"&New search"}, {"hash":177160185,"name":"tfrmfinddlg.actnewsearchclearfilters.caption","sourcebytes":[78,101,119,32,115,101,97,114,99,104,32,40,99,108,101,97,114,32,102,105,108,116,101,114,115,41],"value":"New search (clear filters)"}, {"hash":86573816,"name":"tfrmfinddlg.actlastsearch.caption","sourcebytes":[38,76,97,115,116,32,115,101,97,114,99,104],"value":"&Last search"}, {"hash":2871239,"name":"tfrmfinddlg.actview.caption","sourcebytes":[38,86,105,101,119],"value":"&View"}, {"hash":2800388,"name":"tfrmfinddlg.actedit.caption","sourcebytes":[38,69,100,105,116],"value":"&Edit"}, {"hash":188493653,"name":"tfrmfinddlg.actgotofile.caption","sourcebytes":[38,71,111,32,116,111,32,102,105,108,101],"value":"&Go to file"}, {"hash":91583208,"name":"tfrmfinddlg.actfeedtolistbox.caption","sourcebytes":[70,101,101,100,32,116,111,32,38,108,105,115,116,98,111,120],"value":"Feed to &listbox"}, {"hash":243911330,"name":"tfrmfinddlg.actpagestandard.caption","sourcebytes":[71,111,32,116,111,32,112,97,103,101,32,34,83,116,97,110,100,97,114,100,34],"value":"Go to page \"Standard\""}, {"hash":113755314,"name":"tfrmfinddlg.actpageadvanced.caption","sourcebytes":[71,111,32,116,111,32,112,97,103,101,32,34,65,100,118,97,110,99,101,100,34],"value":"Go to page \"Advanced\""}, {"hash":85053858,"name":"tfrmfinddlg.actpageplugins.caption","sourcebytes":[71,111,32,116,111,32,112,97,103,101,32,34,80,108,117,103,105,110,115,34],"value":"Go to page \"Plugins\""}, {"hash":192888738,"name":"tfrmfinddlg.actpageloadsave.caption","sourcebytes":[71,111,32,116,111,32,112,97,103,101,32,34,76,111,97,100,47,83,97,118,101,34],"value":"Go to page \"Load/Save\""}, {"hash":168300370,"name":"tfrmfinddlg.actpageresults.caption","sourcebytes":[71,111,32,116,111,32,112,97,103,101,32,34,82,101,115,117,108,116,115,34],"value":"Go to page \"Results\""}, {"hash":37402439,"name":"tfrmfinddlg.actcancelclose.caption","sourcebytes":[67,97,110,99,101,108,32,115,101,97,114,99,104,32,97,110,100,32,99,108,111,115,101,32,119,105,110,100,111,119],"value":"Cancel search and close window"}, {"hash":141485097,"name":"tfrmfinddlg.actfreefrommem.caption","sourcebytes":[67,97,110,99,101,108,32,115,101,97,114,99,104,44,32,99,108,111,115,101,32,97,110,100,32,102,114,101,101,32,102,114,111,109,32,109,101,109,111,114,121],"value":"Cancel search, close and free from memory"}, {"hash":261287225,"name":"tfrmfinddlg.actfreefrommemallothers.caption","sourcebytes":[70,111,114,32,97,108,108,32,111,116,104,101,114,32,34,70,105,110,100,32,102,105,108,101,115,34,44,32,99,97,110,99,101,108,44,32,99,108,111,115,101,32,97,110,100,32,102,114,101,101,32,102,114,111,109,32,109,101,109,111,114,121],"value":"For all other \"Find files\", cancel, close and free from memory"}, {"hash":16841203,"name":"tfrmfinddlg.actconfigfilesearchhotkeys.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,104,111,116,32,107,101,121,115],"value":"Configuration of hot keys"}, {"hash":142259365,"name":"tfrmfinddlg.actpagenext.caption","sourcebytes":[83,119,105,116,99,104,32,116,111,32,78,101,120,38,116,32,80,97,103,101],"value":"Switch to Nex&t Page"}, {"hash":67944341,"name":"tfrmfinddlg.actpageprev.caption","sourcebytes":[83,119,105,116,99,104,32,116,111,32,38,80,114,101,118,105,111,117,115,32,80,97,103,101],"value":"Switch to &Previous Page"}, {"hash":175812734,"name":"tfrmfinddlg.miaction.caption","sourcebytes":[38,65,99,116,105,111,110],"value":"&Action"}, {"hash":103712041,"name":"tfrmfinddlg.mifreefrommemallothers.caption","sourcebytes":[70,111,114,32,97,108,108,32,111,116,104,101,114,115,44,32,99,97,110,99,101,108,44,32,99,108,111,115,101,32,97,110,100,32,102,114,101,101,32,102,114,111,109,32,109,101,109,111,114,121],"value":"For all others, cancel, close and free from memory"}, {"hash":2871239,"name":"tfrmfinddlg.miviewtab.caption","sourcebytes":[38,86,105,101,119],"value":"&View"}, {"hash":193768468,"name":"tfrmfinddlg.miresult.caption","sourcebytes":[38,82,101,115,117,108,116],"value":"&Result"}, {"hash":108725763,"name":"tfrmfinddlg.mioptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"} ]} �������������������doublecmd-1.1.22/src/fFindDlg.pas�������������������������������������������������������������������0000644�0001750�0000144�00000262076�14743153644�015574� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Find dialog, with searching in thread Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz) 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, see <http://www.gnu.org/licenses/>. } unit fFindDlg; {$mode objfpc}{$H+} {$include calling.inc} interface uses Graphics, SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Menus, EditBtn, Spin, Buttons, DateTimePicker, KASComboBox, KASButton, fAttributesEdit, uDsxModule, DsxPlugin, uFindThread, uFindFiles, uRegExprU, uSearchTemplate, fSearchPlugin, uFileView, types, DCStrUtils, ActnList, uOSForms, uShellContextMenu, uExceptions, uFileSystemFileSource, uFormCommands, uHotkeyManager, LCLVersion, uWcxModule, uFileSource; {$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} {$DEFINE FIX_DEFAULT} {$ENDIF} const HotkeysCategory = 'Find files'; type { TfrmFindDlg } TfrmFindDlg = class(TModalForm, IFormCommands) actIntelliFocus: TAction; actCancel: TAction; actClose: TAction; actEdit: TAction; actGoToFile: TAction; actFeedToListbox: TAction; actCancelClose: TAction; actPagePrev: TAction; actPageNext: TAction; actPageResults: TAction; actPageLoadSave: TAction; actPagePlugins: TAction; actPageAdvanced: TAction; actPageStandard: TAction; actView: TAction; actLastSearch: TAction; actNewSearch: TAction; actStart: TAction; actList: TActionList; Bevel2: TBevel; Bevel3: TBevel; btnAddAttribute: TButton; btnAttrsHelp: TButton; btnClose: TButton; btnGoToPath: TButton; btnNewSearch: TButton; btnLastSearch: TButton; btnSaveTemplate: TButton; btnSearchDelete: TButton; btnSearchLoad: TButton; btnSearchSave: TButton; btnSearchSaveWithStartingPath: TButton; btnStart: TButton; btnUseTemplate: TButton; btnStop: TButton; btnView: TButton; btnEdit: TButton; btnWorkWithFound: TButton; cbFindText: TCheckBox; cbNotContainingText: TCheckBox; cbDateFrom: TCheckBox; cbNotOlderThan: TCheckBox; cbFileSizeFrom: TCheckBox; cbDateTo: TCheckBox; cbFileSizeTo: TCheckBox; cbReplaceText: TCheckBox; cbTimeFrom: TCheckBox; cbTimeTo: TCheckBox; cbPartialNameSearch: TCheckBox; cbFollowSymLinks: TCheckBox; cbUsePlugin: TCheckBox; cbSelectedFiles: TCheckBox; cbTextRegExp: TCheckBox; cbFindInArchive: TCheckBox; cbOpenedTabs: TCheckBox; cbOfficeXML: TCheckBox; chkDuplicateContent: TCheckBox; chkDuplicateSize: TCheckBox; chkDuplicateHash: TCheckBox; chkDuplicateName: TCheckBox; chkDuplicates: TCheckBox; chkHex: TCheckBox; cmbExcludeDirectories: TComboBoxWithDelItems; cmbNotOlderThanUnit: TComboBox; cmbFileSizeUnit: TComboBox; cmbEncoding: TComboBox; cmbSearchDepth: TComboBox; cbRegExp: TCheckBox; cmbPlugin: TComboBox; cmbReplaceText: TComboBoxWithDelItems; cmbFindText: TComboBoxWithDelItems; cmbExcludeFiles: TComboBoxWithDelItems; edtAttrib: TEdit; cmbFindPathStart: TComboBoxWithDelItems; frmContentPlugins: TfrmSearchPlugin; gbDirectories: TGroupBox; gbFiles: TGroupBox; btnEncoding: TKASButton; lblAttributes: TLabel; lblExcludeDirectories: TLabel; lblCurrent: TLabel; lblExcludeFiles: TLabel; lblFound: TLabel; lblStatus: TLabel; lblTemplateHeader: TLabel; lbSearchTemplates: TListBox; lblSearchContents: TPanel; lblSearchDepth: TLabel; lblEncoding: TLabel; lsFoundedFiles: TListBox; CheksPanel: TPanel; miOpenInNewTab: TMenuItem; miShowInEditor: TMenuItem; miShowAllFound: TMenuItem; miRemoveFromLlist: TMenuItem; pnlDuplicates: TPanel; pnlDirectoriesDepth: TPanel; pnlLoadSaveBottomButtons: TPanel; pnlLoadSaveBottom: TPanel; pnlButtons: TPanel; pnlResultsBottomButtons: TPanel; pnlResults: TPanel; pnlStatus: TPanel; pnlResultsBottom: TPanel; seNotOlderThan: TSpinEdit; seFileSizeFrom: TSpinEdit; seFileSizeTo: TSpinEdit; pnlFindFile: TPanel; pgcSearch: TPageControl; btnChooseFolder: TSpeedButton; tsPlugins: TTabSheet; tsResults: TTabSheet; tsLoadSave: TTabSheet; tsStandard: TTabSheet; lblFindPathStart: TLabel; lblFindFileMask: TLabel; cmbFindFileMask: TComboBoxWithDelItems; gbFindData: TGroupBox; cbCaseSens: TCheckBox; tsAdvanced: TTabSheet; PopupMenuFind: TPopupMenu; miShowInViewer: TMenuItem; ZVDateFrom: TDateTimePicker; ZVDateTo: TDateTimePicker; ZVTimeFrom: TDateTimePicker; ZVTimeTo: TDateTimePicker; actFreeFromMem: TAction; actFreeFromMemAllOthers: TAction; actConfigFileSearchHotKeys: TAction; actNewSearchClearFilters: TAction; mmMainMenu: TMainMenu; miNewSearchClearFilters: TMenuItem; miConfigFileSearchHotKeys: TMenuItem; miOptions: TMenuItem; miAction: TMenuItem; miNewSearch: TMenuItem; miLastSearch: TMenuItem; miStart: TMenuItem; miCancel: TMenuItem; miFreeFromMem: TMenuItem; miFreeFromMemAllOthers: TMenuItem; miSeparator1: TMenuItem; miCancelClose: TMenuItem; miClose: TMenuItem; miViewTab: TMenuItem; miPageStandard: TMenuItem; miPageAdvanced: TMenuItem; miPagePlugins: TMenuItem; miPageLoadSave: TMenuItem; miPageResults: TMenuItem; miSeparator2: TMenuItem; miResult: TMenuItem; miView: TMenuItem; miEdit: TMenuItem; miFeedToListbox: TMenuItem; miGoToFile: TMenuItem; procedure actExecute(Sender: TObject); procedure btnAddAttributeClick(Sender: TObject); procedure btnAttrsHelpClick(Sender: TObject); procedure btnEncodingClick(Sender: TObject); procedure btnNewSearchKeyDown(Sender: TObject; var Key: word; {%H-}Shift: TShiftState); procedure btnSearchDeleteClick(Sender: TObject); procedure btnSearchLoadClick(Sender: TObject); procedure btnSearchSaveWithStartingPathClick(Sender: TObject); procedure btnSearchSaveClick(Sender: TObject); procedure cbCaseSensChange(Sender: TObject); procedure cbDateFromChange(Sender: TObject); procedure cbDateToChange(Sender: TObject); procedure cbFindInArchiveChange(Sender: TObject); procedure cbOfficeXMLChange(Sender: TObject); procedure cbOpenedTabsChange(Sender: TObject); procedure cbPartialNameSearchChange(Sender: TObject); procedure cbRegExpChange(Sender: TObject); procedure cbTextRegExpChange(Sender: TObject); procedure cbSelectedFilesChange(Sender: TObject); procedure chkDuplicateContentChange(Sender: TObject); procedure chkDuplicateHashChange(Sender: TObject); procedure chkDuplicatesChange(Sender: TObject); procedure chkDuplicateSizeChange(Sender: TObject); procedure chkHexChange(Sender: TObject); procedure cmbEncodingSelect(Sender: TObject); procedure cbFindTextChange(Sender: TObject); procedure cbUsePluginChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnSelDirClick(Sender: TObject); procedure cbFileSizeFromChange(Sender: TObject); procedure cbFileSizeToChange(Sender: TObject); procedure cbNotOlderThanChange(Sender: TObject); procedure cbReplaceTextChange(Sender: TObject); procedure cbTimeFromChange(Sender: TObject); procedure cbTimeToChange(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormDestroy(Sender: TObject); {$IF DEFINED(FIX_DEFAULT)} procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); {$ENDIF} procedure frmFindDlgClose(Sender: TObject; var {%H-}CloseAction: TCloseAction); procedure frmFindDlgShow(Sender: TObject); procedure gbDirectoriesResize(Sender: TObject); procedure lbSearchTemplatesDblClick(Sender: TObject); procedure lbSearchTemplatesSelectionChange(Sender: TObject; {%H-}User: boolean); procedure lsFoundedFilesDblClick(Sender: TObject); procedure lsFoundedFilesKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); procedure lsFoundedFilesMouseDown(Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: integer); procedure lsFoundedFilesMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); procedure lsFoundedFilesMouseWheelDown(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var Handled: boolean); procedure lsFoundedFilesMouseWheelUp(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var Handled: boolean); procedure miOpenInNewTabClick(Sender: TObject); procedure miRemoveFromLlistClick(Sender: TObject); procedure miShowAllFoundClick(Sender: TObject); procedure miShowInEditorClick(Sender: TObject); procedure miShowInViewerClick(Sender: TObject); procedure pgcSearchChange(Sender: TObject); procedure seFileSizeFromChange(Sender: TObject); procedure seFileSizeToChange(Sender: TObject); procedure seNotOlderThanChange(Sender: TObject); procedure tsLoadSaveShow(Sender: TObject); procedure tsStandardEnter(Sender: TObject); procedure ZVDateFromChange(Sender: TObject); procedure ZVDateToChange(Sender: TObject); procedure ZVTimeFromChange(Sender: TObject); procedure ZVTimeToChange(Sender: TObject); procedure PopupMenuFindPopup(Sender: TObject); function GetTextSearchOptions: UIntPtr; procedure CancelCloseAndFreeMem; procedure LoadHistory; procedure SaveHistory; procedure LoadPlugins; private FSelectedFiles: TStringList; FFindThread: TFindThread; FTimeSearch: string; DsxPlugins: TDSXModuleList; FSearchingActive: boolean; FFrmAttributesEdit: TfrmAttributesEdit; FLastTemplateName: string; FLastSearchTemplate: TSearchTemplate; FUpdateTimer: TTimer; FUpdating: boolean; FRButtonPanelSender: TObject; // last focused button on Right Panel (pnlButtons) FCommands: TFormCommands; FSearchWithDSXPluginInProgress: boolean; FSearchWithWDXPluginInProgress: boolean; FFreeOnClose: boolean; FAtLeastOneSearchWasDone: boolean; FFileSource: IFileSource; FWcxModule: TWcxModule; property Commands: TFormCommands read FCommands implements IFormCommands; procedure DisableControlsForTemplate; procedure StopSearch; procedure AfterSearchStopped; //update button states after stop search(ThreadTerminate call this method) procedure AfterSearchFocus; //set correct focus after search stopped procedure UpdateEncodings; function GetEncodings(AList: TCustomComboBox): String; procedure SetEncodings(const AEncodings: String; AList: TCustomComboBox); procedure FindInArchive(AFileView: TFileView); procedure FillFindOptions(out FindOptions: TSearchTemplateRec; SetStartPath: boolean); procedure FindOptionsToDSXSearchRec(const AFindOptions: TSearchTemplateRec; out SRec: TDsxSearchRecord); procedure FoundedStringCopyAdded(Sender: TObject); procedure FoundedStringCopyChanged(Sender: TObject); procedure LoadTemplate(const Template: TSearchTemplateRec); procedure LoadSelectedTemplate; procedure SaveTemplate(SaveStartingPath: boolean); procedure SelectTemplate(const ATemplateName: string); procedure UpdateTemplatesList; procedure OnUpdateTimer(Sender: TObject); procedure OnAddAttribute(Sender: TObject); function InvalidRegExpr: Boolean; procedure SetWindowCaption(AWindowCaptionStyle: byte); function ObjectType(Index: Integer): TCheckBoxState; function GetFileMask: String; public FoundedStringCopy: TStringList; class function Instance: TfrmFindDlg; public LastClickResultsPath: string; constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure ClearFilter(bClearSearchLocation: boolean = True); procedure ClearResults; procedure ThreadTerminate(Sender: TObject); procedure EnableControls(AEnabled: Boolean); procedure FocusOnResults(Sender: TObject); // if press VK_LEFT or VK_RIGHT when on any button on left panel - focus on results and remember button in FRButtonPanelSender published procedure cm_IntelliFocus(const {%H-}Params: array of string); procedure cm_Start(const {%H-}Params: array of string); procedure cm_CancelClose(const {%H-}Params: array of string); procedure cm_Cancel(const {%H-}Params: array of string); procedure cm_Close(const {%H-}Params: array of string); procedure cm_NewSearch(const {%H-}Params: array of string); procedure cm_LastSearch(const {%H-}Params: array of string); procedure cm_View(const {%H-}Params: array of string); procedure cm_Edit(const {%H-}Params: array of string); procedure cm_GoToFile(const {%H-}Params: array of string); procedure cm_FeedToListbox(const {%H-}Params: array of string); procedure cm_PageNext(const Params: array of string); procedure cm_PagePrev(const Params: array of string); procedure cm_PageStandard(const {%H-}Params: array of string); procedure cm_PageAdvanced(const {%H-}Params: array of string); procedure cm_PagePlugins(const {%H-}Params: array of string); procedure cm_PageLoadSave(const {%H-}Params: array of string); procedure cm_PageResults(const {%H-}Params: array of string); procedure cm_NewSearchClearFilters(const {%H-}Params: array of string); procedure cm_FreeFromMem(const {%H-}Params: array of string); procedure cm_FreeFromMemAllOthers(const {%H-}Params: array of string); procedure cm_ConfigFileSearchHotKeys(const {%H-}Params: array of string); end; {en Shows the find files dialog. Cannot store FileView reference as it might get destroyed while Find Dialog is running. We can store FileSource though, if needed in future (as it is reference counted). @param(FileView For which file view the find dialog is executed, to get file source, current path and a list of selected files.) } { TListOffrmFindDlgInstance } TListOffrmFindDlgInstance = class(TList) private function GetfrmFindDlgInstance(Index: integer): TfrmFindDlg; public constructor Create; procedure Clear; override; function Add(AfrmFindDlg: TfrmFindDlg): integer; property frmFindDlgInstance[Index: integer]: TfrmFindDlg read GetfrmFindDlgInstance; end; var // [ ListOffrmFindDlgInstance ] // This list will hold in memory pointers to our find dialog forms. ListOffrmFindDlgInstance: TListOffrmFindDlgInstance; frmFindDlgUsingPluginDSX: TfrmFindDlg = nil; frmFindDlgUsingPluginWDX: TfrmFindDlg = nil; procedure ShowFindDlg(FileView: TFileView; const TemplateName: string; bCreateNewFindDlg: boolean = False); function ShowDefineTemplateDlg(var TemplateName: string): boolean; function ShowUseTemplateDlg(var Template: TSearchTemplate): boolean; implementation {$R *.lfm} uses LCLProc, LCLType, LConvEncoding, StrUtils, HelpIntfs, fViewer, fMain, uLng, uGlobs, uShowForm, uDCUtils, uFileSourceUtil, uOfficeXML, uSearchResultFileSource, uFile, uFileProperty, uColumnsFileView, uFileViewNotebook, uKeyboard, uOSUtils, uArchiveFileSourceUtil, DCOSUtils, uRegExprA, uRegExprW, uDebug, uShowMsg, uConvEncoding, uColumns, uFileFunctions, uFileSorting, uWcxArchiveFileSource, DCConvertEncoding, WcxPlugin, fChooseEncoding, dmCommonData {$IFDEF DARKWIN} , uDarkStyle {$ENDIF} ; const TimeUnitToComboIndex: array[TTimeUnit] of integer = (0, 1, 2, 3, 4, 5, 6); ComboIndexToTimeUnit: array[0..6] of TTimeUnit = (tuSecond, tuMinute, tuHour, tuDay, tuWeek, tuMonth, tuYear); FileSizeUnitToComboIndex: array[TFileSizeUnit] of integer = (0, 1, 2, 3, 4); ComboIndexToFileSizeUnit: array[0..4] of TFileSizeUnit = (suBytes, suKilo, suMega, suGiga, suTera); wcs_NewSearch = $01; wcs_StartSearch = $0A; wcs_EndSearch = $1B; type { TStringListTemp } TStringListTemp = class(TStringList) public function AddObject(const S: string; AObject: TObject): integer; override; end; var gSearchWithDSXPluginInProgress: boolean = False; gSearchWithWDXPluginInProgress: boolean = False; { TListOffrmFindDlgInstance.Create } constructor TListOffrmFindDlgInstance.Create; begin inherited Create; end; { TListOffrmFindDlgInstance.Clear } procedure TListOffrmFindDlgInstance.Clear; var i: integer; begin for i := pred(Count) downto 0 do if frmFindDlgInstance[i] <> nil then frmFindDlgInstance[i].Free; inherited Clear; end; { TListOffrmFindDlgInstance.Add } function TListOffrmFindDlgInstance.Add(AfrmFindDlg: TfrmFindDlg): integer; begin Result := inherited Add(AfrmFindDlg); end; { TListOffrmFindDlgInstance.GetfrmFindDlgInstance } function TListOffrmFindDlgInstance.GetfrmFindDlgInstance(Index: integer): TfrmFindDlg; begin Result := TfrmFindDlg(Items[Index]); end; procedure SAddFileProc({%H-}PlugNr: integer; FoundFile: PChar); dcpcall; var s: string; begin s := string(FoundFile); if s = '' then begin TfrmFindDlg.Instance.AfterSearchStopped; TfrmFindDlg.Instance.btnStart.Default := True; end else begin TfrmFindDlg.Instance.FoundedStringCopy.Add(s); Application.ProcessMessages; end; end; procedure SUpdateStatusProc({%H-}PlugNr: integer; CurrentFile: PChar; FilesScanned: integer); dcpcall; var sCurrentFile: string; begin sCurrentFile := string(CurrentFile); TfrmFindDlg.Instance.lblStatus.Caption := Format(rsFindScanned, [FilesScanned]) + TfrmFindDlg.Instance.FTimeSearch; if sCurrentFile = '' then TfrmFindDlg.Instance.lblCurrent.Caption := '' else TfrmFindDlg.Instance.lblCurrent.Caption := rsFindScanning + ': ' + sCurrentFile; Application.ProcessMessages; end; { ShowFindDlg } procedure ShowFindDlg(FileView: TFileView; const TemplateName: string; bCreateNewFindDlg: boolean = False); var ASelectedFiles: TFiles = nil; I: integer; AfrmFindDlgInstance: TfrmFindDlg; bFirstFindDlg: boolean; begin if not Assigned(FileView) then raise Exception.Create('ShowFindDlg: FileView=nil'); bFirstFindDlg := (ListOffrmFindDlgInstance.Count = 0); // 1. We create a new form: if it's the first search we do OR if we've been instructed to do so (cm_AddNewSearch) if bFirstFindDlg or bCreateNewFindDlg then begin AfrmFindDlgInstance := TfrmFindDlg.Create(nil); ListOffrmFindDlgInstance.add(AfrmFindDlgInstance); end else begin AfrmFindDlgInstance := ListOffrmFindDlgInstance.frmFindDlgInstance[pred(ListOffrmFindDlgInstance.Count)]; end; // 2. If we don't have a search in progress, then clear and set a few things. if not AfrmFindDlgInstance.FSearchingActive then begin with AfrmFindDlgInstance do begin // Prepare window for search files LoadHistory; LoadPlugins; ClearFilter; // SetWindowCaption(wcs_NewSearch); cmbFindPathStart.Text := FileView.CurrentPath; // Get paths of selected files, if any. FSelectedFiles.Clear; ASelectedFiles := FileView.CloneSelectedFiles; if Assigned(ASelectedFiles) then try if ASelectedFiles.Count > 0 then begin for I := 0 to ASelectedFiles.Count - 1 do FSelectedFiles.Add(ASelectedFiles[I].FullPath); end; finally FreeAndNil(ASelectedFiles); end; FindInArchive(FileView); if Length(TemplateName) > 0 then begin FUpdating := True; UpdateTemplatesList; SelectTemplate(TemplateName); LoadSelectedTemplate; FUpdating := False; end; end; end; AfrmFindDlgInstance.ShowOnTop; end; { ShowDefineTemplateDlg } function ShowDefineTemplateDlg(var TemplateName: string): boolean; var AIndex: integer; AForm: TfrmFindDlg; begin AForm := TfrmFindDlg.Create(nil); try with AForm do begin // Prepare window for define search template LoadHistory; LoadPlugins; Caption := rsFindDefineTemplate; DisableControlsForTemplate; btnSaveTemplate.Visible := True; btnSaveTemplate.Default := True; BorderIcons := [biSystemMenu, biMaximize]; if Length(TemplateName) > 0 then begin UpdateTemplatesList; AIndex := lbSearchTemplates.Items.IndexOf(TemplateName); if AIndex >= 0 then begin lbSearchTemplates.ItemIndex := AIndex; AForm.LoadSelectedTemplate; end; end; Result := (ShowModal = mrOk); if Result and (lbSearchTemplates.Count > 0) then begin TemplateName := FLastTemplateName; end; end; finally AForm.Free; end; end; { ShowUseTemplateDlg } function ShowUseTemplateDlg(var Template: TSearchTemplate): boolean; var AForm: TfrmFindDlg; SearchRec: TSearchTemplateRec; begin AForm := TfrmFindDlg.Create(nil); try with AForm do begin // Prepare window for define search template LoadHistory; LoadPlugins; Caption := rsFindDefineTemplate; DisableControlsForTemplate; btnUseTemplate.Visible := True; btnUseTemplate.Default := True; BorderIcons := [biSystemMenu, biMaximize]; if Assigned(Template) then AForm.LoadTemplate(Template.SearchRecord); Result := (ShowModal = mrOk); if Result then begin if not Assigned(Template) then Template := TSearchTemplate.Create; try Template.TemplateName := AForm.FLastTemplateName; AForm.FillFindOptions(SearchRec, False); Template.SearchRecord := SearchRec; except FreeAndNil(Template); raise; end; end; end; finally AForm.Free; end; end; { TStringListTemp } { TStringListTemp.AddObject } function TStringListTemp.AddObject(const S: string; AObject: TObject): integer; begin Result := Count; InsertItem(Result, S, AObject); end; { TfrmFindDlg } { TfrmFindDlg.FormCreate } procedure TfrmFindDlg.FormCreate(Sender: TObject); var I: integer; HMFindFiles: THMForm; begin if not gShowMenuBarInFindFiles then FreeAndNil(mmMainMenu); DsxPlugins := TDSXModuleList.Create; FoundedStringCopy := TStringListTemp.Create; FoundedStringCopy.OwnsObjects := True; FFreeOnClose := False; FAtLeastOneSearchWasDone := False; FSearchWithDSXPluginInProgress := False; FSearchWithWDXPluginInProgress := False; // load language cmbNotOlderThanUnit.Items.Add(rsTimeUnitSecond); cmbNotOlderThanUnit.Items.Add(rsTimeUnitMinute); cmbNotOlderThanUnit.Items.Add(rsTimeUnitHour); cmbNotOlderThanUnit.Items.Add(rsTimeUnitDay); cmbNotOlderThanUnit.Items.Add(rsTimeUnitWeek); cmbNotOlderThanUnit.Items.Add(rsTimeUnitMonth); cmbNotOlderThanUnit.Items.Add(rsTimeUnitYear); cmbFileSizeUnit.Items.Add(rsSizeUnitBytes); cmbFileSizeUnit.Items.Add(rsSizeUnitKBytes); cmbFileSizeUnit.Items.Add(rsSizeUnitMBytes); cmbFileSizeUnit.Items.Add(rsSizeUnitGBytes); cmbFileSizeUnit.Items.Add(rsSizeUnitTBytes); cbOfficeXML.Hint := StripHotkey(cbOfficeXML.Caption) + ' ' + OFFICE_FILTER; // fill search depth combobox cmbSearchDepth.Items.Add(rsFindDepthAll); cmbSearchDepth.Items.Add(rsFindDepthCurDir); for I := 1 to 100 do cmbSearchDepth.Items.Add(Format(rsFindDepth, [IntToStr(I)])); cmbSearchDepth.ItemIndex := 0; // fill encoding combobox cmbEncoding.Clear; GetSupportedEncodings(cmbEncoding.Items); I := cmbEncoding.Items.IndexOf('UTF-8BOM'); if I >= 0 then cmbEncoding.Items.Delete(I); cmbEncoding.Items.Insert(0, 'Default'); cmbEncoding.ItemIndex := 0; cmbEncoding.Items.Objects[0]:= TObject(PtrInt(True)); // gray disabled fields cbUsePluginChange(Sender); cbFindTextChange(Sender); cbReplaceTextChange(Sender); cbNotOlderThanChange(Sender); cbFileSizeFromChange(Sender); cbFileSizeToChange(Sender); ZVDateFrom.DateTime := Now(); ZVDateTo.DateTime := Now(); ZVTimeFrom.DateTime := Now(); ZVTimeTo.DateTime := Now(); cbDateFrom.Checked := False; cbDateTo.Checked := False; cbTimeFrom.Checked := False; cbTimeTo.Checked := False; btnStart.Default := True; cmbNotOlderThanUnit.ItemIndex := 3; // Days cmbFileSizeUnit.ItemIndex := 1; // Kilobytes cbPartialNameSearch.Checked := gPartialNameSearch; FontOptionsToFont(gFonts[dcfSearchResults], lsFoundedFiles.Font); InitPropStorage(Self); HMFindFiles := HotMan.Register(Self, HotkeysCategory); HMFindFiles.RegisterActionList(actList); CloneMainAction(frmMain.actAddNewSearch, actList, miViewTab, -1); CloneMainAction(frmMain.actViewSearches, actList, miViewTab, -1); CloneMainAction(frmMain.actDeleteSearches, actList, miAction, -1); CloneMainAction(frmMain.actConfigSearches, actList, miOptions, 0); {$IF DEFINED(FIX_DEFAULT)} if (ListOffrmFindDlgInstance.Count = 0) then Application.AddOnKeyDownBeforeHandler(@FormKeyDown); {$ENDIF} end; { TfrmFindDlg.cbUsePluginChange } procedure TfrmFindDlg.cbUsePluginChange(Sender: TObject); begin EnableControl(cmbPlugin, cbUsePlugin.Checked); if not FUpdating and cmbPlugin.Enabled and cmbPlugin.CanSetFocus and (Sender = cbUsePlugin) then begin cmbPlugin.SetFocus; cmbPlugin.SelectAll; end; end; { TfrmFindDlg.cmbEncodingSelect } procedure TfrmFindDlg.cmbEncodingSelect(Sender: TObject); var Index, ItemIndex: Integer; begin if (cmbEncoding.Tag = 1) then begin ItemIndex:= cmbEncoding.ItemIndex; for Index:= 0 to cmbEncoding.Items.Count - 1 do begin cmbEncoding.Items.Objects[Index]:= TObject(PtrInt((ItemIndex = Index))); end; end; UpdateEncodings; end; { TfrmFindDlg.Create } constructor TfrmFindDlg.Create(TheOwner: TComponent); var C: TPortableNetworkGraphic; begin FSelectedFiles := TStringList.Create; inherited Create(TheOwner); FUpdateTimer := TTimer.Create(Self); FUpdateTimer.Interval := 100; FUpdateTimer.Enabled := False; FUpdateTimer.OnTimer := @OnUpdateTimer; try C := TPortableNetworkGraphic.Create; C.LoadFromResourceName(hInstance, ResBtnSelDir); btnChooseFolder.Glyph.Assign(C); finally C.Free; end; dmComData.ilEditorImages.GetBitmap(44, btnEncoding.Glyph); FCommands := TFormCommands.Create(Self, actList); end; { TfrmFindDlg.Destroy } destructor TfrmFindDlg.Destroy; begin inherited Destroy; FSelectedFiles.Free; FLastSearchTemplate.Free; end; { TfrmFindDlg.DisableControlsForTemplate } procedure TfrmFindDlg.DisableControlsForTemplate; begin lblFindPathStart.Visible := False; cmbFindPathStart.Visible := False; cbFollowSymLinks.Visible := False; cbSelectedFiles.Visible := False; cbOpenedTabs.Visible := False; btnStart.Visible := False; btnStop.Visible := False; btnNewSearch.Visible := False; btnLastSearch.Visible := False; btnSearchSaveWithStartingPath.Visible := False; gbFindData.Visible := False; tsResults.TabVisible := False; actPageResults.Enabled := False; chkDuplicates.Visible:= False; pnlDuplicates.Visible:= False; if mmMainMenu <> nil then FreeAndNil(mmMainMenu); end; { TfrmFindDlg.cbFindTextChange } procedure TfrmFindDlg.cbFindTextChange(Sender: TObject); begin EnableControl(chkHex, cbFindText.Checked); EnableControl(cmbFindText, cbFindText.Checked); EnableControl(cmbEncoding, cbFindText.Checked); EnableControl(cbCaseSens, cbFindText.Checked); EnableControl(cbReplaceText, cbFindText.Checked and not (cbFindInArchive.Checked or chkHex.Checked or cbOfficeXML.Checked)); EnableControl(cbNotContainingText, cbFindText.Checked); EnableControl(cbTextRegExp, cbFindText.Checked); EnableControl(cbOfficeXML, cbFindText.Checked); lblEncoding.Enabled := cbFindText.Checked; cbReplaceText.Checked := False; UpdateEncodings; if not FUpdating and cmbFindText.Enabled and cmbFindText.CanSetFocus and (Sender = cbFindText) then begin cmbFindText.SetFocus; cmbFindText.SelectAll; end; end; { TfrmFindDlg.ClearFilter } procedure TfrmFindDlg.ClearFilter(bClearSearchLocation: boolean = True); var FreezeTime: TDateTime; begin FUpdating := True; FLastTemplateName := ''; if bClearSearchLocation then begin cmbFindPathStart.Text := ''; cmbExcludeDirectories.Text := ''; end; if gInitiallyClearFileMask then cmbFindFileMask.Text := '' else if glsMaskHistory.Count > 0 then begin cmbFindFileMask.Text:= glsMaskHistory[0]; end; // If we already search text then use last searched text if not gFirstTextSearch then begin if glsSearchHistory.Count > 0 then cmbFindText.Text := glsSearchHistory[0]; end; cmbSearchDepth.ItemIndex := 0; cmbExcludeFiles.Text := ''; cbPartialNameSearch.Checked := gPartialNameSearch; cbRegExp.Checked := False; // attributes edtAttrib.Text := ''; // file date/time FreezeTime := Now; ZVDateFrom.DateTime := FreezeTime; ZVDateTo.DateTime := FreezeTime; ZVTimeFrom.DateTime := FreezeTime; ZVTimeTo.DateTime := FreezeTime; cbDateFrom.Checked := False; cbDateTo.Checked := False; cbTimeFrom.Checked := False; cbTimeTo.Checked := False; // not older then cbNotOlderThan.Checked := False; seNotOlderThan.Value := 1; cmbNotOlderThanUnit.ItemIndex := 3; // Days // file size cbFileSizeFrom.Checked := False; cbFileSizeTo.Checked := False; seFileSizeFrom.Value := 0; seFileSizeTo.Value := 10; cmbFileSizeUnit.ItemIndex := 1; // Kilobytes // find/replace text // do not clear search/replace text just clear checkbox chkHex.Checked := False; cbFindText.Checked := False; cbReplaceText.Checked := False; cbCaseSens.Checked := False; cbOfficeXML.Checked := False; cbNotContainingText.Checked := False; cmbEncoding.ItemIndex := 0; cmbEncoding.Tag := 1; cmbEncodingSelect(nil); // duplicates chkDuplicates.Checked:= False; // plugins cbUsePlugin.Checked:= False; frmContentPlugins.chkUsePlugins.Checked:= False; FUpdating := False; end; { TfrmFindDlg.ClearResults } procedure TfrmFindDlg.ClearResults; begin lsFoundedFiles.Clear; lsFoundedFiles.Tag := 0; lsFoundedFiles.ScrollWidth := 0; FoundedStringCopy.Clear; EnableControls(False); end; { TfrmFindDlg.btnSearchLoadClick } procedure TfrmFindDlg.btnSearchLoadClick(Sender: TObject); begin LoadSelectedTemplate; end; { TfrmFindDlg.btnSearchSaveWithStartingPathClick } procedure TfrmFindDlg.btnSearchSaveWithStartingPathClick(Sender: TObject); begin SaveTemplate(True); end; { TfrmFindDlg.btnSearchDeleteClick } procedure TfrmFindDlg.btnSearchDeleteClick(Sender: TObject); var OldIndex: integer; begin OldIndex := lbSearchTemplates.ItemIndex; if OldIndex < 0 then Exit; gSearchTemplateList.DeleteTemplate(OldIndex); lbSearchTemplates.Items.Delete(OldIndex); if OldIndex < lbSearchTemplates.Count then lbSearchTemplates.ItemIndex := OldIndex else if lbSearchTemplates.Count > 0 then lbSearchTemplates.ItemIndex := lbSearchTemplates.Count - 1; end; { TfrmFindDlg.btnAttrsHelpClick } procedure TfrmFindDlg.btnAttrsHelpClick(Sender: TObject); begin ShowHelpOrErrorForKeyword('', edtAttrib.HelpKeyword); end; procedure TfrmFindDlg.btnEncodingClick(Sender: TObject); var I, Index, ACount: Integer; begin if ChooseEncoding(Self, cmbEncoding.Items) then begin I:= 0; ACount:= 0; for Index:= 0 to cmbEncoding.Items.Count - 1 do begin if (PtrInt(cmbEncoding.Items.Objects[Index]) <> 0) then begin I:= Index; Inc(ACount); end; end; if ACount > 1 then begin I:= 0; end else if (ACount = 0) then begin I:= 0; ACount:= 1; cmbEncoding.Items.Objects[I]:= TObject(PtrInt(True)); end; cmbEncoding.Tag:= ACount; cmbEncoding.ItemIndex:= I; cmbEncoding.Enabled:= (ACount <= 1); UpdateEncodings; end; end; { TfrmFindDlg.actExecute } procedure TfrmFindDlg.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; { TfrmFindDlg.btnAddAttributeClick } procedure TfrmFindDlg.btnAddAttributeClick(Sender: TObject); begin if not Assigned(FFrmAttributesEdit) then begin FFrmAttributesEdit := TfrmAttributesEdit.Create(Self); FFrmAttributesEdit.OnOk := @OnAddAttribute; end; FFrmAttributesEdit.Reset; {$IFDEF DARKWIN} if g_darkModeEnabled then FFrmAttributesEdit.ShowModal else {$ENDIF} if not (fsModal in FormState) then FFrmAttributesEdit.Show else begin FFrmAttributesEdit.ShowModal; end; end; { TfrmFindDlg.btnSearchSaveClick } procedure TfrmFindDlg.btnSearchSaveClick(Sender: TObject); begin SaveTemplate(False); end; { TfrmFindDlg.cbCaseSensChange } procedure TfrmFindDlg.cbCaseSensChange(Sender: TObject); begin if cbCaseSens.Checked then cbTextRegExp.Checked := False; end; { TfrmFindDlg.cbDateFromChange } procedure TfrmFindDlg.cbDateFromChange(Sender: TObject); begin UpdateColor(ZVDateFrom, cbDateFrom.Checked); end; { TfrmFindDlg.cbDateToChange } procedure TfrmFindDlg.cbDateToChange(Sender: TObject); begin UpdateColor(ZVDateTo, cbDateTo.Checked); end; { TfrmFindDlg.cbFindInArchiveChange } procedure TfrmFindDlg.cbFindInArchiveChange(Sender: TObject); begin EnableControl(cbReplaceText, cbFindText.Checked and not cbFindInArchive.Checked); if cbReplaceText.Checked then cbReplaceText.Checked := cbReplaceText.Enabled; actView.Enabled := pnlResultsBottom.Enabled and (not cbFindInArchive.Checked); actEdit.Enabled := pnlResultsBottom.Enabled and (not cbFindInArchive.Checked); actFeedToListbox.Enabled := pnlResultsBottom.Enabled and (not cbFindInArchive.Checked); cbReplaceTextChange(cbReplaceText); end; procedure TfrmFindDlg.cbOfficeXMLChange(Sender: TObject); begin if cbOfficeXML.Checked then begin chkHex.Checked:= False; cbReplaceText.Checked:= False; end; cbReplaceText.Enabled:= not (chkHex.Checked or cbOfficeXML.Checked); end; { TfrmFindDlg.cbOpenedTabsChange } procedure TfrmFindDlg.cbOpenedTabsChange(Sender: TObject); begin cbSelectedFiles.Enabled := not cbOpenedTabs.Checked AND (FSelectedFiles.Count > 0); cbFollowSymLinks.Enabled := not cbOpenedTabs.Checked; cmbFindPathStart.Enabled := not cbOpenedTabs.Checked; end; { TfrmFindDlg.cbPartialNameSearchChange } procedure TfrmFindDlg.cbPartialNameSearchChange(Sender: TObject); begin if cbPartialNameSearch.Checked then cbRegExp.Checked := False; end; { TfrmFindDlg.cbRegExpChange } procedure TfrmFindDlg.cbRegExpChange(Sender: TObject); begin if cbRegExp.Checked then cbPartialNameSearch.Checked := False; end; { TfrmFindDlg.cbTextRegExpChange } procedure TfrmFindDlg.cbTextRegExpChange(Sender: TObject); begin if cbTextRegExp.Checked then begin if cbCaseSens.Enabled then begin cbCaseSens.Tag := Integer(cbCaseSens.Checked); end; end else if not cbCaseSens.Enabled then begin cbCaseSens.Checked := Boolean(cbCaseSens.Tag); end; UpdateEncodings; end; { TfrmFindDlg.cbSelectedFilesChange } procedure TfrmFindDlg.cbSelectedFilesChange(Sender: TObject); begin cmbFindPathStart.Enabled := not cbSelectedFiles.Checked; end; procedure TfrmFindDlg.chkDuplicateContentChange(Sender: TObject); begin if chkDuplicateContent.Checked then begin chkDuplicateSize.Checked:= True; chkDuplicateHash.Checked:= False; end; end; procedure TfrmFindDlg.chkDuplicateHashChange(Sender: TObject); begin if chkDuplicateHash.Checked then begin chkDuplicateSize.Checked:= True; chkDuplicateContent.Checked:= False; end; end; procedure TfrmFindDlg.chkDuplicatesChange(Sender: TObject); begin pnlDuplicates.Enabled:= chkDuplicates.Checked; if chkDuplicates.Checked then begin if not (chkDuplicateName.Checked or chkDuplicateSize.Checked) then chkDuplicateName.Checked:= True; end; end; procedure TfrmFindDlg.chkDuplicateSizeChange(Sender: TObject); begin if not chkDuplicateSize.Checked then begin chkDuplicateHash.Checked:= False; chkDuplicateContent.Checked:= False; end; end; procedure TfrmFindDlg.chkHexChange(Sender: TObject); begin if chkHex.Checked then begin cmbEncoding.ItemIndex:= 0; if cbCaseSens.Enabled then begin cbCaseSens.Tag := Integer(cbCaseSens.Checked); end; cbOfficeXML.Checked:= False; cbReplaceText.Checked:= False; end else if not cbCaseSens.Enabled then begin cbCaseSens.Checked := Boolean(cbCaseSens.Tag); end; cbReplaceText.Enabled:= not (chkHex.Checked or cbOfficeXML.Checked); UpdateEncodings; end; { TfrmFindDlg.btnSelDirClick } procedure TfrmFindDlg.btnSelDirClick(Sender: TObject); var S, AFolder: String; begin S := cmbFindPathStart.Text; AFolder:= ExtractFilePath(ExcludeTrailingBackslash(S)); if not mbDirectoryExists(AFolder) then AFolder := EmptyStr; if SelectDirectory(rsFindWhereBeg, AFolder, S, gShowSystemFiles) then cmbFindPathStart.Text := S; end; { TfrmFindDlg.btnNewSearchKeyDown } procedure TfrmFindDlg.btnNewSearchKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin if ((Key = VK_LEFT) or (Key = VK_RIGHT)) and (lsFoundedFiles.Count > 0) then FocusOnResults(Sender); end; { TfrmFindDlg.FillFindOptions } procedure TfrmFindDlg.FillFindOptions(out FindOptions: TSearchTemplateRec; SetStartPath: boolean); begin with FindOptions do begin if SetStartPath then StartPath := cmbFindPathStart.Text else StartPath := ''; ExcludeDirectories := cmbExcludeDirectories.Text; FilesMasks := GetFileMask; ExcludeFiles := cmbExcludeFiles.Text; SearchDepth := cmbSearchDepth.ItemIndex - 1; RegExp := cbRegExp.Checked; IsPartialNameSearch := cbPartialNameSearch.Checked; FollowSymLinks := cbFollowSymLinks.Checked; FindInArchives := cbFindInArchive.Checked; { File attributes } AttributesPattern := edtAttrib.Text; { Date/time } DateTimeFrom := 0; DateTimeTo := 0; IsDateFrom := False; IsDateTo := False; IsTimeFrom := False; IsTimeTo := False; if cbDateFrom.Checked then begin IsDateFrom := True; DateTimeFrom := ZVDateFrom.Date; end; if cbDateTo.Checked then begin IsDateTo := True; DateTimeTo := ZVDateTo.Date; end; if cbTimeFrom.Checked then begin IsTimeFrom := True; DateTimeFrom := DateTimeFrom + ZVTimeFrom.Time; end; if cbTimeTo.Checked then begin IsTimeTo := True; DateTimeTo := DateTimeTo + ZVTimeTo.Time; end; { Not Older Than } IsNotOlderThan := cbNotOlderThan.Checked; NotOlderThan := seNotOlderThan.Value; NotOlderThanUnit := ComboIndexToTimeUnit[cmbNotOlderThanUnit.ItemIndex]; { File size } IsFileSizeFrom := cbFileSizeFrom.Checked; IsFileSizeTo := cbFileSizeTo.Checked; FileSizeFrom := seFileSizeFrom.Value; FileSizeTo := seFileSizeTo.Value; FileSizeUnit := ComboIndexToFileSizeUnit[cmbFileSizeUnit.ItemIndex]; { Find/replace text } IsFindText := cbFindText.Checked; FindText := cmbFindText.Text; IsReplaceText := cbReplaceText.Checked; ReplaceText := cmbReplaceText.Text; HexValue := chkHex.Checked; CaseSensitive := cbCaseSens.Checked; NotContainingText := cbNotContainingText.Checked; TextRegExp := cbTextRegExp.Checked; TextEncoding := GetEncodings(cmbEncoding); OfficeXML := cbOfficeXML.Checked; { Duplicates } Duplicates:= chkDuplicates.Checked; DuplicateName:= chkDuplicateName.Checked; DuplicateSize:= chkDuplicateSize.Checked; DuplicateHash:= chkDuplicateHash.Checked; DuplicateContent:= chkDuplicateContent.Checked; { Plugins } if not cbUsePlugin.Checked then SearchPlugin := EmptyStr else begin SearchPlugin := cmbPlugin.Text; end; frmContentPlugins.Save(FindOptions); end; end; { TfrmFindDlg.FindOptionsToDSXSearchRec } procedure TfrmFindDlg.FindOptionsToDSXSearchRec( const AFindOptions: TSearchTemplateRec; out SRec: TDsxSearchRecord); begin with AFindOptions do begin FillByte(SRec{%H-}, SizeOf(SRec), 0); SRec.StartPath := Copy(StartPath, 1, SizeOf(SRec.StartPath)); if IsPartialNameSearch then SRec.FileMask := '*' + Copy(FilesMasks, 1, SizeOf(SRec.FileMask) - 2) + '*' else SRec.FileMask := Copy(FilesMasks, 1, SizeOf(SRec.FileMask)); SRec.Attributes := faAnyFile; // AttrStrToFileAttr? SRec.AttribStr := Copy(AttributesPattern, 1, SizeOf(SRec.AttribStr)); SRec.CaseSensitive := CaseSensitive; {Date search} SRec.IsDateFrom := IsDateFrom; SRec.IsDateTo := IsDateTo; SRec.DateTimeFrom := DateTimeFrom; SRec.DateTimeTo := DateTimeTo; {Time search} SRec.IsTimeFrom := IsTimeFrom; SRec.IsTimeTo := IsTimeTo; (* File size search *) SRec.IsFileSizeFrom := IsFileSizeFrom; SRec.IsFileSizeTo := IsFileSizeTo; SRec.FileSizeFrom := FileSizeFrom; SRec.FileSizeTo := FileSizeTo; (* Find text *) SRec.NotContainingText := NotContainingText; SRec.IsFindText := IsFindText; SRec.FindText := Copy(FindText, 1, SizeOf(SRec.FindText)); (* Replace text *) SRec.IsReplaceText := IsReplaceText; SRec.ReplaceText := Copy(ReplaceText, 1, SizeOf(SRec.ReplaceText)); end; end; { TfrmFindDlg.StopSearch } procedure TfrmFindDlg.StopSearch; begin if FSearchingActive then begin if (cbUsePlugin.Checked) and (cmbPlugin.ItemIndex <> -1) then begin if FSearchWithDSXPluginInProgress then begin DSXPlugins.GetDSXModule(cmbPlugin.ItemIndex).CallStopSearch; DSXPlugins.GetDSXModule(cmbPlugin.ItemIndex).CallFinalize; end; AfterSearchStopped; AfterSearchFocus; end; if Assigned(FFindThread) then begin FFindThread.Terminate; FFindThread := nil; end; end; end; { TfrmFindDlg.Instance } class function TfrmFindDlg.Instance: TfrmFindDlg; begin Result:=frmFindDlgUsingPluginDSX; end; { TfrmFindDlg.lbSearchTemplatesDblClick } procedure TfrmFindDlg.lbSearchTemplatesDblClick(Sender: TObject); begin LoadSelectedTemplate; end; { TfrmFindDlg.AfterSearchStopped } procedure TfrmFindDlg.AfterSearchStopped; begin actCancel.Enabled := False; actStart.Enabled := True;; actClose.Enabled := True; actNewSearch.Enabled := True; actNewSearchClearFilters.Enabled := True; actLastSearch.Enabled := True; FSearchingActive := False; if FSearchWithDSXPluginInProgress then begin FSearchWithDSXPluginInProgress := False; gSearchWithDSXPluginInProgress := False; end; if FSearchWithWDXPluginInProgress then begin FSearchWithWDXPluginInProgress := False; gSearchWithWDXPluginInProgress := False; end; end; { TfrmFindDlg.AfterSearchFocus } procedure TfrmFindDlg.AfterSearchFocus; var LastButton: TButton; begin if Assigned(Self) and Visible then begin if FRButtonPanelSender <> nil then // if user press a keys while search - keep focus on it begin LastButton := (FRButtonPanelSender as TButton); if LastButton.Enabled then LastButton.SetFocus else btnNewSearch.SetFocus; end else begin // if user don't press anything - focus on results if (pgcSearch.ActivePage = tsResults) and (lsFoundedFiles.Count > 0) then begin btnGoToPath.SetFocus; lsFoundedFiles.SetFocus; if lsFoundedFiles.ItemIndex<0 then lsFoundedFiles.ItemIndex:=0; lsFoundedFiles.Selected[lsFoundedFiles.ItemIndex] := True; end else begin if actNewSearch.Enabled then btnNewSearch.SetFocus else btnStart.SetFocus; end; end; end; end; procedure TfrmFindDlg.UpdateEncodings; var Index: Integer; Encoding: String; SupportedEncoding: Boolean; begin SupportedEncoding:= True; for Index:= 0 to cmbEncoding.Items.Count - 1 do begin if (PtrInt(cmbEncoding.Items.Objects[Index]) <> 0) then begin Encoding:= cmbEncoding.Items[Index]; SupportedEncoding:= SingleByteEncoding(Encoding); if (not SupportedEncoding) and TRegExprU.AvailableNew then begin Encoding := NormalizeEncoding(Encoding); if Encoding = EncodingDefault then Encoding := GetDefaultTextEncoding; SupportedEncoding := Encoding = EncodingUTF8; end; if not SupportedEncoding then Break; end; end; btnEncoding.Visible:= not cbReplaceText.Checked; btnEncoding.Enabled:= cbFindText.Checked and (not chkHex.Checked); cmbEncoding.Enabled:= btnEncoding.Enabled and (cmbEncoding.Tag < 2); cbTextRegExp.Enabled := cbFindText.Checked and SupportedEncoding and (not chkHex.Checked); if not cbTextRegExp.Enabled then cbTextRegExp.Checked := False; cbCaseSens.Enabled:= cbFindText.Checked and (not cbReplaceText.Checked) and (not chkHex.Checked) and (not cbTextRegExp.Checked); if cbFindText.Checked and (not cbCaseSens.Enabled) then cbCaseSens.Checked := not cbTextRegExp.Checked; end; function TfrmFindDlg.GetEncodings(AList: TCustomComboBox): String; var Index: Integer; begin Result:= EmptyStr; for Index:= 0 to AList.Items.Count - 1 do begin if (PtrInt(AList.Items.Objects[Index]) <> 0) then begin Result+= AList.Items[Index] + '|'; end; end; if Length(Result) = 0 then Result:= AList.Text; end; procedure TfrmFindDlg.SetEncodings(const AEncodings: String; AList: TCustomComboBox); var S: TStringArray; I, Index, ACount: Integer; begin ACount:= 0; S:= SplitString(AEncodings, '|'); for Index:= 0 to High(S) do begin I:= AList.Items.IndexOf(S[Index]); if (I >= 0) then begin Inc(ACount); AList.Items.Objects[I]:= TObject(PtrInt(True)); end; end; AList.Tag:= ACount; if ACount = 1 then AList.ItemIndex:= I; end; procedure TfrmFindDlg.FindInArchive(AFileView: TFileView); var AEnabled: Boolean; AFileSource: IWcxArchiveFileSource; begin FFileSource:= aFileView.FileSource; AEnabled:= FFileSource.IsClass(TWcxArchiveFileSource); cbOpenedTabs.Visible:= not AEnabled; cbSelectedFiles.Visible:= not AEnabled; cbFindInArchive.Enabled:= not AEnabled; cbReplaceText.Enabled:= (not AEnabled) and (cbFindText.Checked); cmbFindPathStart.Enabled:= not AEnabled; btnChooseFolder.Enabled:= not AEnabled; chkDuplicates.Enabled:= not AEnabled; cmbSearchDepth.Enabled:= not AEnabled; tsPlugins.TabVisible:= not AEnabled; actPagePlugins.Enabled:= not AEnabled; cbFollowSymLinks.Enabled:= not AEnabled; if not AEnabled then FWcxModule:= nil else begin AFileSource:= (FFileSource as IWcxArchiveFileSource); FWcxModule:= AFileSource.WcxModule; end; cbFindText.Enabled:= (AEnabled = False) or (AFileSource.PluginCapabilities and PK_CAPS_SEARCHTEXT <> 0); if AEnabled then begin cmbSearchDepth.ItemIndex:= 0; cbFindInArchive.Checked:= True; cbReplaceText.Checked:= False; chkDuplicates.Checked:= False; cbOpenedTabs.Checked:= False; cbSelectedFiles.Checked:= False; cbFollowSymLinks.Checked:= False; cmbFindPathStart.Text:= aFileView.CurrentAddress; end; end; procedure TfrmFindDlg.FoundedStringCopyAdded(Sender: TObject); begin if FoundedStringCopy.Count > 0 then begin EnableControls(True); FoundedStringCopyChanged(Sender); FoundedStringCopy.OnChange:= @FoundedStringCopyChanged; end; end; { TfrmFindDlg.FoundedStringCopyChanged } procedure TfrmFindDlg.FoundedStringCopyChanged(Sender: TObject); var sText: string; iTemp: integer; begin if FoundedStringCopy.Count > 0 then begin iTemp := FoundedStringCopy.Count - 1; Sender := FoundedStringCopy.Objects[iTemp]; sText := FoundedStringCopy[iTemp]; iTemp := Length(sText); if iTemp > lsFoundedFiles.Tag then begin lsFoundedFiles.Tag := iTemp; iTemp := lsFoundedFiles.Canvas.TextWidth(sText); if iTemp > lsFoundedFiles.ScrollWidth then lsFoundedFiles.ScrollWidth := iTemp + 32; end; lsFoundedFiles.Items.AddObject(sText, Sender); {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} Application.ProcessMessages; {$ENDIF} end; end; { TfrmFindDlg.cbFileSizeFromChange } procedure TfrmFindDlg.cbFileSizeFromChange(Sender: TObject); begin UpdateColor(seFileSizeFrom, cbFileSizeFrom.Checked); EnableControl(cmbFileSizeUnit, cbFileSizeFrom.Checked or cbFileSizeTo.Checked); end; { TfrmFindDlg.cbFileSizeToChange } procedure TfrmFindDlg.cbFileSizeToChange(Sender: TObject); begin UpdateColor(seFileSizeTo, cbFileSizeTo.Checked); EnableControl(cmbFileSizeUnit, cbFileSizeFrom.Checked or cbFileSizeTo.Checked); end; { TfrmFindDlg.cbNotOlderThanChange } procedure TfrmFindDlg.cbNotOlderThanChange(Sender: TObject); begin UpdateColor(seNotOlderThan, cbNotOlderThan.Checked); EnableControl(cmbNotOlderThanUnit, cbNotOlderThan.Checked); end; { TfrmFindDlg.cbReplaceTextChange } procedure TfrmFindDlg.cbReplaceTextChange(Sender: TObject); var Index: Integer; begin EnableControl(cmbReplaceText, cbReplaceText.Checked and cbFindText.Checked); cbNotContainingText.Checked := False; cbNotContainingText.Enabled := (not cbReplaceText.Checked and cbFindText.Checked); if cmbReplaceText.Enabled and (cmbEncoding.Tag > 1) then begin for Index:= cmbEncoding.Items.Count - 1 downto 0 do begin if (PtrInt(cmbEncoding.Items.Objects[Index]) <> 0) then begin if cmbEncoding.Tag = 1 then begin cmbEncoding.ItemIndex:= Index; Break; end; cmbEncoding.Tag:= cmbEncoding.Tag - 1; cmbEncoding.Items.Objects[Index]:= nil; end; end; end; UpdateEncodings; if not FUpdating and cmbReplaceText.Enabled and cmbReplaceText.CanSetFocus then begin cmbReplaceText.SetFocus; cmbReplaceText.SelectAll; end; end; { TfrmFindDlg.cbTimeFromChange } procedure TfrmFindDlg.cbTimeFromChange(Sender: TObject); begin UpdateColor(ZVTimeFrom, cbTimeFrom.Checked); end; { TfrmFindDlg.cbTimeToChange } procedure TfrmFindDlg.cbTimeToChange(Sender: TObject); begin UpdateColor(ZVTimeTo, cbTimeTo.Checked); end; { TfrmFindDlg.ThreadTerminate } procedure TfrmFindDlg.ThreadTerminate(Sender: TObject); begin FFindThread := TFindThread(Sender); if FFindThread.TimeOfScan <> 0 then FTimeSearch := ' , ' + rsFindTimeOfScan + formatdatetime('hh:nn:ss.zzz', FFindThread.TimeOfScan); FUpdateTimer.OnTimer(FUpdateTimer); FUpdateTimer.Enabled := False; FFindThread := nil; SetWindowCaption(wcs_EndSearch); AfterSearchStopped; AfterSearchFocus; end; procedure TfrmFindDlg.EnableControls(AEnabled: Boolean); begin actView.Enabled:= AEnabled; actEdit.Enabled:= AEnabled; actGoToFile.Enabled:= AEnabled; actFeedToListbox.Enabled:= AEnabled; pnlResultsBottom.Enabled:= AEnabled; end; { TfrmFindDlg.FocusOnResults } procedure TfrmFindDlg.FocusOnResults(Sender: TObject); begin FRButtonPanelSender := Sender; if pgcSearch.ActivePage = tsResults then begin btnStart.Default := False; if lsFoundedFiles.SelCount = 0 then lsFoundedFiles.ItemIndex := 0; lsFoundedFiles.SetFocus; lsFoundedFiles.Selected[lsFoundedFiles.ItemIndex] := True; end; end; { TfrmFindDlg.cm_IntelliFocus } procedure TfrmFindDlg.cm_IntelliFocus(const Params: array of string); begin if FFindThread <> nil then begin FFindThread.OnTerminate := nil; FFindThread.Terminate; FUpdateTimer.OnTimer(FUpdateTimer); FUpdateTimer.Enabled := False; FFindThread := nil; end; AfterSearchStopped; btnStart.Default := True; if cmbFindText.Focused then // if F7 on already focused textSearch field- disable text search and set focun on file mask begin cbFindText.Checked := False; cmbFindFileMask.SetFocus; cmbFindFileMask.SelectAll; exit; end else begin pgcSearch.PageIndex := 0; cbFindText.Checked := True; cmbFindText.SetFocus; cmbFindText.SelectAll; end; end; { TfrmFindDlg.cm_Start } procedure TfrmFindDlg.cm_Start(const Params: array of string); var sPath: String; sr: TDsxSearchRecord; SearchTemplate, TmpTemplate: TSearchTemplateRec; PassedSelectedFiles: TStringList = nil; begin cm_Cancel([]); Self.Repaint; Application.ProcessMessages; if cbFindInArchive.Enabled then begin if (cmbFindPathStart.Text = '') then begin cmbFindPathStart.Text:= mbGetCurrentDir; end; for sPath in SplitPath(cmbFindPathStart.Text) do begin if not mbDirectoryExists(sPath) then begin ShowMessage(Format(rsFindDirNoEx, [sPath])); Exit; end; end; end; if (cbFindText.Checked and chkHex.Checked) then try HexToBin(cmbFindText.Text); except on E: EConvertError do begin MessageDlg(E.Message, mtError, [mbOK], 0, mbOK); Exit; end; end; SaveHistory; FAtLeastOneSearchWasDone := True; if cbSelectedFiles.Checked and (FSelectedFiles.Count = 0) then begin ShowMessage(rsMsgNoFilesSelected); cbSelectedFiles.Checked := False; Exit; end; if not (chkDuplicateName.Checked or chkDuplicateSize.Checked) then chkDuplicates.Checked:= False; // Show search results page pgcSearch.ActivePage := tsResults; if lsFoundedFiles.CanSetFocus then lsFoundedFiles.SetFocus; ClearResults; miShowAllFound.Enabled := False; FSearchingActive := True; actCancel.Enabled := True; btnStop.Default := True; actStart.Enabled := False; actClose.Enabled := False; actNewSearch.Enabled := False; actNewSearchClearFilters.Enabled := False; actLastSearch.Enabled := False; try if (frmContentPlugins.chkUsePlugins.Checked) and (gSearchWithWDXPluginInProgress) then raise EConvertError.Create(rsSearchWithWDXPluginInProgress); FillFindOptions(SearchTemplate, True); if frmContentPlugins.chkUsePlugins.Checked then begin gSearchWithWDXPluginInProgress := True; FSearchWithWDXPluginInProgress := True; frmFindDlgUsingPluginWDX := Self; end; if not Assigned(FLastSearchTemplate) then FLastSearchTemplate := TSearchTemplate.Create; TmpTemplate := SearchTemplate; TmpTemplate.StartPath := ''; // Don't remember starting path. FLastSearchTemplate.SearchRecord := TmpTemplate; FoundedStringCopy.OnChange:= @FoundedStringCopyAdded; if (cbUsePlugin.Checked) and (cmbPlugin.ItemIndex <> -1) then begin if not gSearchWithDSXPluginInProgress then begin gSearchWithDSXPluginInProgress := True; FSearchWithDSXPluginInProgress := True; frmFindDlgUsingPluginDSX := Self; if DSXPlugins.LoadModule(cmbPlugin.ItemIndex) then begin FindOptionsToDSXSearchRec(SearchTemplate, sr); DSXPlugins.GetDSXModule(cmbPlugin.ItemIndex).CallInit(@SAddFileProc, @SUpdateStatusProc); DSXPlugins.GetDSXModule(cmbPlugin.ItemIndex).CallStartSearch(sr); end else StopSearch; end else begin MsgError(rsSearchWithDSXPluginInProgress); StopSearch; end; end else begin if cbSelectedFiles.Checked then PassedSelectedFiles := FSelectedFiles; if cbOpenedTabs.Checked then begin frmMain.GetListOpenedPaths(FSelectedFiles); PassedSelectedFiles := FSelectedFiles; end; FFindThread := TFindThread.Create(SearchTemplate, PassedSelectedFiles); with FFindThread do begin Archive := FWcxModule; Items := FoundedStringCopy; OnTerminate := @ThreadTerminate; // will update the buttons after search is finished end; SetWindowCaption(wcs_StartSearch); FTimeSearch := ''; FFindThread.Start; FUpdateTimer.Enabled := True; FUpdateTimer.OnTimer(FUpdateTimer); FRButtonPanelSender := nil; end; except on E: Exception do begin if (E is EConvertError) then msgError(E.Message) else raise; StopSearch; AfterSearchStopped; AfterSearchFocus; end; end; end; //cm_Start { TfrmFindDlg.cm_CancelClose } procedure TfrmFindDlg.cm_CancelClose(const Params: array of string); begin if FSearchingActive then StopSearch else Close; end; { TfrmFindDlg.cm_Cancel } procedure TfrmFindDlg.cm_Cancel(const Params: array of string); begin StopSearch; AfterSearchStopped; AfterSearchFocus; end; { TfrmFindDlg.cm_NewSearch } procedure TfrmFindDlg.cm_NewSearch(const Params: array of string); var Param: string; sActionWithFilters: string = ''; begin StopSearch; if length(Params) = 0 then begin case gNewSearchClearFiltersAction of fonsClear: sActionWithFilters := 'clear'; fonsPrompt: if msgYesNo(rsClearFiltersOrNot) then sActionWithFilters := 'clear'; end; end; for Param in Params do GetParamValue(Param, 'filters', sActionWithFilters); if sActionWithFilters = 'clear' then ClearFilter(False); pgcSearch.PageIndex := 0; ClearResults; miShowAllFound.Enabled := False; lblStatus.Caption := EmptyStr; lblCurrent.Caption := EmptyStr; lblFound.Caption := EmptyStr; SetWindowCaption(wcs_NewSearch); if pgcSearch.ActivePage = tsStandard then cmbFindFileMask.SetFocus; end; { TfrmFindDlg.cm_LastSearch } procedure TfrmFindDlg.cm_LastSearch(const Params: array of string); begin if Assigned(FLastSearchTemplate) then begin LoadTemplate(FLastSearchTemplate.SearchRecord); pgcSearch.ActivePage := tsStandard; cmbFindFileMask.SetFocus; end; end; { TfrmFindDlg.cm_View } procedure TfrmFindDlg.cm_View(const Params: array of string); begin if pgcSearch.ActivePage = tsResults then if lsFoundedFiles.ItemIndex <> -1 then begin if (ObjectType(lsFoundedFiles.ItemIndex) = cbChecked) then msgError(rsMsgErrNotSupported) else ShowViewerByGlob(lsFoundedFiles.Items[lsFoundedFiles.ItemIndex]); end; end; { TfrmFindDlg.cm_Edit } procedure TfrmFindDlg.cm_Edit(const Params: array of string); var FileName: String; begin if pgcSearch.ActivePage = tsResults then if lsFoundedFiles.ItemIndex <> -1 then begin if (ObjectType(lsFoundedFiles.ItemIndex) = cbChecked) then msgError(rsMsgErrNotSupported) else begin FileName:= lsFoundedFiles.Items[lsFoundedFiles.ItemIndex]; if mbFileExists(FileName) then ShowEditorByGlob(FileName) else msgError(Format(rsMsgFileNotFound, [FileName])); end; end; end; { TfrmFindDlg.cm_GoToFile } procedure TfrmFindDlg.cm_GoToFile(const Params: array of string); var AFile: TFile = nil; TargetFile: string; ArchiveFile: string; FileSource: IFileSource; begin if lsFoundedFiles.ItemIndex <> -1 then try StopSearch; TargetFile := lsFoundedFiles.Items[lsFoundedFiles.ItemIndex]; if (ObjectType(lsFoundedFiles.ItemIndex) = cbChecked) then begin ArchiveFile := ExtractWord(1, TargetFile, [ReversePathDelim]); TargetFile := PathDelim + ExtractWord(2, TargetFile, [ReversePathDelim]); AFile := TFileSystemFileSource.CreateFileFromFile(ArchiveFile); try FileSource:= GetArchiveFileSource(TFileSystemFileSource.GetFileSource, AFile, EmptyStr, False, False); finally AFile.Free; end; if Assigned(FileSource) then begin frmMain.ActiveFrame.AddFileSource(FileSource, ExtractFilePath(TargetFile)); frmMain.ActiveFrame.SetActiveFile(ExtractFileName(TargetFile)); end; end else begin if not mbFileSystemEntryExists(TargetFile) then begin msgError(rsMsgObjectNotExists + LineEnding + TargetFile); Exit; end; SetFileSystemPath(frmMain.ActiveFrame, ExtractFilePath(TargetFile)); frmMain.ActiveFrame.SetActiveFile(ExtractFileName(TargetFile)); end; frmMain.RestoreWindow; Close; except on E: Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; end; { TfrmFindDlg.cm_FeedToListbox } procedure TfrmFindDlg.cm_FeedToListbox(const Params: array of string); const PluginDuplicate = 'Plugin().Duplicate{}'; var I: integer; sFileName: string; SearchResultFS: ISearchResultFileSource; FileList: TFileTree; aFile: TFile; Notebook: TFileViewNotebook; NewPage: TFileViewPage; DCFunc: String; AProperty: TFileVariantProperty; ANewSet: TPanelColumnsClass; NewSorting: TFileSortings; AHeader: TWCXHeader; begin StopSearch; FileList := TFileTree.Create; for i := 0 to lsFoundedFiles.Items.Count - 1 do begin if Assigned(FWcxModule) then begin AHeader:= TWCXHeader(lsFoundedFiles.Items.Objects[I]); aFile := TWcxArchiveFileSource.CreateFile(ExtractFilePath(AHeader.FileName), AHeader); FileList.AddSubNode(aFile); end else try sFileName := lsFoundedFiles.Items[I]; aFile := TFileSystemFileSource.CreateFileFromFile(sFileName); if FLastSearchTemplate.SearchRecord.Duplicates then begin AProperty:= TFileVariantProperty.Create(PluginDuplicate); AProperty.Value:= TDuplicate(lsFoundedFiles.Items.Objects[I]).Index; aFile.Properties[fpVariant]:= AProperty; end; FileList.AddSubNode(aFile); except on EFileNotFound do ; end; end; // Create search result file source. // Currently only searching FileSystem is supported. SearchResultFS := TSearchResultFileSource.Create; SearchResultFS.AddList(FileList, FFileSource); // Add new tab for search results. Notebook := frmMain.ActiveNotebook; NewPage := Notebook.NewPage(Notebook.ActiveView); if FLastSearchTemplate.SearchRecord.Duplicates then begin if not (NewPage.FileView is TColumnsFileView) then begin NewPage.FileView:= TColumnsFileView.Create(NewPage, NewPage.FileView, EmptyStr); NewPage.FileView.SetFocus; end; ANewSet:= TPanelColumnsClass.Create; DCFunc := '[' + sFuncTypeDC + '().%s{}]'; I:= Notebook.ActiveView.ClientWidth; ANewSet.Add(rsFuncName, Format(DCFunc, [TFileFunctionStrings[fsfName]]), I * 40 div 100, taLeftJustify); ANewSet.Add(rsFuncGroup, '[' + PluginDuplicate + ']', I * 20 div 100, taCenter); ANewSet.Add(rsFuncPath, Format(DCFunc, [TFileFunctionStrings[fsfPath]]), I * 40 div 100, taLeftJustify); TColumnsFileView(NewPage.FileView).isSlave:= True; TColumnsFileView(NewPage.FileView).ActiveColmSlave:= ANewSet; TColumnsFileView(NewPage.FileView).UpdateColumnsView; SetLength(NewSorting, 1); SetLength(NewSorting[0].SortFunctions, 2); NewSorting[0].SortFunctions[0] := fsfVariant; NewSorting[0].SortFunctions[1] := fsfName; NewSorting[0].SortDirection := sdAscending; NewPage.FileView.Sorting:= NewSorting; end; NewPage.FileView.AddFileSource(SearchResultFS, SearchResultFS.GetRootDir); NewPage.FileView.FlatView := True; NewPage.MakeActive; Close; end; procedure TfrmFindDlg.cm_PageNext(const Params: array of string); begin with pgcSearch do begin if PageIndex = PageCount - 1 then ActivePage := Pages[0] else ActivePage := Pages[PageIndex + 1]; end; end; procedure TfrmFindDlg.cm_PagePrev(const Params: array of string); begin with pgcSearch do begin if PageIndex = 0 then ActivePage := Pages[PageCount - 1] else ActivePage := Pages[PageIndex - 1]; end; end; { TfrmFindDlg.cm_PageStandard } procedure TfrmFindDlg.cm_PageStandard(const Params: array of string); begin pgcSearch.ActivePage := tsStandard; end; { TfrmFindDlg.cm_PageAdvanced } procedure TfrmFindDlg.cm_PageAdvanced(const Params: array of string); begin pgcSearch.ActivePage := tsAdvanced; end; { TfrmFindDlg.cm_PagePlugins } procedure TfrmFindDlg.cm_PagePlugins(const Params: array of string); begin pgcSearch.ActivePage := tsPlugins; end; { TfrmFindDlg.cm_PageLoadSave } procedure TfrmFindDlg.cm_PageLoadSave(const Params: array of string); begin pgcSearch.ActivePage := tsLoadSave; end; { TfrmFindDlg.cm_PageResults } procedure TfrmFindDlg.cm_PageResults(const Params: array of string); begin pgcSearch.ActivePage := tsResults; end; { TfrmFindDlg.FormCloseQuery } procedure TfrmFindDlg.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin if FFindThread <> nil then // We can't call StopSearch because it method will set focus on unavailable field begin FFindThread.OnTerminate := nil; FFindThread.Terminate; FUpdateTimer.OnTimer(FUpdateTimer); FUpdateTimer.Enabled := False; FFindThread := nil; end; AfterSearchStopped; btnStart.Default := True; CanClose := not Assigned(FFindThread); end; { TfrmFindDlg.FormDestroy } procedure TfrmFindDlg.FormDestroy(Sender: TObject); begin {$IF DEFINED(FIX_DEFAULT)} if ListOffrmFindDlgInstance.Count = 0 then Application.RemoveOnKeyDownBeforeHandler(@FormKeyDown); {$ENDIF} FreeAndNil(FoundedStringCopy); FreeAndNil(DsxPlugins); end; {$IF DEFINED(FIX_DEFAULT)} procedure TfrmFindDlg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var AParentForm: TCustomForm; begin if Key = VK_RETURN then begin if Sender is TControl then begin AParentForm := GetParentForm(TControl(Sender)); if (AParentForm is TfrmFindDlg) then begin if (Sender = TfrmFindDlg(AParentForm).lsFoundedFiles) then TCustomListBox(Sender).OnKeyDown(Sender, Key, Shift) else if (Sender is TCustomButton) then begin TCustomButton(Sender).Click; Key:= 0; end {$if (lcl_fullversion < 1090000) and defined(lclgtk2)} else begin Key := 0; if btnStart.Enabled then btnStart.Click else btnStop.Click; end; {$endif} end; end; end; end; {$ENDIF} { TfrmFindDlg.FormClose } procedure TfrmFindDlg.frmFindDlgClose(Sender: TObject; var CloseAction: TCloseAction); const CLOSETAG: longint = $233528DE; var iSearchingForm: integer; begin if Assigned(FFrmAttributesEdit) then begin FFrmAttributesEdit.Close; FreeAndNil(FFrmAttributesEdit); end; // Remove the whole thing from memory if no search was made at all. // We remove it also if we've been asked to remove it. // We ned to remove it from our list of instances "ListOffrmFindDlgInstance". // We'll use the trick to give current form a magic tag number and then pass the list to delete the matching one. if (not FAtLeastOneSearchWasDone) or FFreeOnClose then begin tag := CLOSETAG; for iSearchingForm := pred(ListOffrmFindDlgInstance.Count) downto 0 do if ListOffrmFindDlgInstance.frmFindDlgInstance[iSearchingForm].Tag = CLOSETAG then ListOffrmFindDlgInstance.Delete(iSearchingForm); CloseAction := caFree; // This will destroy the from on next step in the flow. end; {$IFDEF DARKWIN} if g_darkModeEnabled and (CloseAction <> caFree) then DestroyHandle; {$ENDIF} end; { TfrmFindDlg.SetWindowCaption } procedure TfrmFindDlg.SetWindowCaption(AWindowCaptionStyle: byte); var sBuildingCaptionName: string; begin sBuildingCaptionName := rsFindSearchFiles; case (AWindowCaptionStyle and $07) of 2: sBuildingCaptionName := sBuildingCaptionName + ' - ' + rsFindScanning; 3: sBuildingCaptionName := sBuildingCaptionName + ' - ' + rsOperFinished; end; if (AWindowCaptionStyle and $10) <> 0 then sBuildingCaptionName := sBuildingCaptionName + ' - ' + lblFound.Caption; if (AWindowCaptionStyle and $08) <> 0 then begin sBuildingCaptionName := sBuildingCaptionName + ' - Files: ' + GetFileMask; if cbFindText.Checked then sBuildingCaptionName := sBuildingCaptionName + ' - Text: ' + cmbFindText.Text; end; Caption := sBuildingCaptionName; end; function TfrmFindDlg.ObjectType(Index: Integer): TCheckBoxState; var ATemp: TObject; begin ATemp:= lsFoundedFiles.Items.Objects[Index]; if (ATemp = nil) then Result:= cbUnchecked else if (ATemp is TWcxHeader) then Result:= cbChecked else Result:= cbGrayed; end; function TfrmFindDlg.GetFileMask: String; begin if Length(cmbFindFileMask.Text) = 0 then Result := AllFilesMask else begin Result := cmbFindFileMask.Text; end; end; { TfrmFindDlg.LoadHistory } procedure TfrmFindDlg.LoadHistory; begin cmbFindFileMask.Items.Assign(glsMaskHistory); cmbFindPathStart.Items.Assign(glsSearchDirectories); cmbExcludeDirectories.Items.Assign(glsSearchExcludeDirectories); cmbExcludeFiles.Items.Assign(glsSearchExcludeFiles); cmbFindText.Items.Assign(glsSearchHistory); cmbReplaceText.Items.Assign(glsReplaceHistory); end; { TfrmFindDlg.SaveHistory } procedure TfrmFindDlg.SaveHistory; begin // 1. Add to find mask history InsertFirstItem(cmbFindFileMask.Text, cmbFindFileMask); glsMaskHistory.Assign(cmbFindFileMask.Items); // 1. Add to find directory history InsertFirstItem(cmbFindPathStart.Text, cmbFindPathStart); glsSearchDirectories.Assign(cmbFindPathStart.Items); // 2. Add to exclude directories history InsertFirstItem(cmbExcludeDirectories.Text, cmbExcludeDirectories); glsSearchExcludeFiles.Assign(cmbExcludeFiles.Items); // 3. Add to exclude files history InsertFirstItem(cmbExcludeFiles.Text, cmbExcludeFiles); glsSearchExcludeDirectories.Assign(cmbExcludeDirectories.Items); // 4. Add to search text history if cbFindText.Checked then begin InsertFirstItem(cmbFindText.Text, cmbFindText, GetTextSearchOptions); // Update search history, so it can be used in // Viewer/Editor opened from find files dialog gFirstTextSearch := False; glsSearchHistory.Assign(cmbFindText.Items); end; // 5. Add to replace text history if cbReplaceText.Checked then begin InsertFirstItem(cmbReplaceText.Text, cmbReplaceText); // Update replace history, so it can be used in // Editor opened from find files dialog (issue 0000539) glsReplaceHistory.Assign(cmbReplaceText.Items); end; end; procedure TfrmFindDlg.LoadPlugins; var I: Integer; AModule: TDsxModule; begin cmbPlugin.Clear; DSXPlugins.Assign(gDSXPlugins); for I := 0 to DSXPlugins.Count - 1 do begin AModule:= DSXPlugins.GetDSXModule(I); if Length(AModule.Descr) = 0 then cmbPlugin.Items.Add(AModule.Name) else cmbPlugin.Items.Add(AModule.Name + ' (' + AModule.Descr + ')'); end; cbUsePlugin.Enabled := (cmbPlugin.Items.Count > 0); if (cbUsePlugin.Enabled) then cmbPlugin.ItemIndex := 0; end; { TfrmFindDlg.FormShow } procedure TfrmFindDlg.frmFindDlgShow(Sender: TObject); begin {$IFDEF LCLCOCOA} pgcSearch.DoAdjustClientRectChange(); {$ENDIF} pgcSearch.PageIndex := 0; if cmbFindFileMask.Visible then cmbFindFileMask.SelectAll; lsFoundedFiles.Canvas.Font := lsFoundedFiles.Font; if pgcSearch.ActivePage = tsStandard then if cmbFindFileMask.CanSetFocus then cmbFindFileMask.SetFocus; cbSelectedFiles.Checked := FSelectedFiles.Count > 0; cbSelectedFiles.Enabled := cbSelectedFiles.Checked; end; { TfrmFindDlg.gbDirectoriesResize } procedure TfrmFindDlg.gbDirectoriesResize(Sender: TObject); begin pnlDirectoriesDepth.Width := gbDirectories.Width div 3; end; { TfrmFindDlg.lbSearchTemplatesSelectionChange } procedure TfrmFindDlg.lbSearchTemplatesSelectionChange(Sender: TObject; User: boolean); begin if lbSearchTemplates.ItemIndex < 0 then lblSearchContents.Caption := '' else begin with gSearchTemplateList.Templates[lbSearchTemplates.ItemIndex].SearchRecord do begin if StartPath <> '' then lblSearchContents.Caption := '"' + FilesMasks + '" -> "' + StartPath + '"' else begin lblSearchContents.Caption := '"' + FilesMasks + '"'; end; pnlLoadSaveBottom.Enabled:= cbFindInArchive.Enabled or ((Duplicates = False) and (ContentPlugin = False) and (SearchPlugin = EmptyStr) and (IsReplaceText = False)); end; end; end; { TfrmFindDlg.LoadSelectedTemplate } procedure TfrmFindDlg.LoadSelectedTemplate; var SearchTemplate: TSearchTemplate; begin if lbSearchTemplates.ItemIndex < 0 then Exit; SearchTemplate := gSearchTemplateList.Templates[lbSearchTemplates.ItemIndex]; if Assigned(SearchTemplate) then begin FLastTemplateName := SearchTemplate.TemplateName; LoadTemplate(SearchTemplate.SearchRecord); end; end; { TfrmFindDlg.LoadTemplate } procedure TfrmFindDlg.LoadTemplate(const Template: TSearchTemplateRec); begin with Template do begin if cbFindInArchive.Enabled then begin if StartPath <> '' then cmbFindPathStart.Text := StartPath; cbFollowSymLinks.Checked := FollowSymLinks; cbFindInArchive.Checked := FindInArchives; if (SearchDepth + 1 >= 0) and (SearchDepth + 1 < cmbSearchDepth.Items.Count) then cmbSearchDepth.ItemIndex := SearchDepth + 1 else cmbSearchDepth.ItemIndex := 0; end; cmbExcludeDirectories.Text := ExcludeDirectories; cmbFindFileMask.Text := FilesMasks; cmbExcludeFiles.Text := ExcludeFiles; cbRegExp.Checked := RegExp; cbPartialNameSearch.Checked := IsPartialNameSearch; // attributes edtAttrib.Text := AttributesPattern; // file date/time cbDateFrom.Checked := IsDateFrom; if IsDateFrom then ZVDateFrom.Date := DateTimeFrom; cbDateTo.Checked := IsDateTo; if IsDateTo then ZVDateTo.Date := DateTimeTo; cbTimeFrom.Checked := IsTimeFrom; if IsTimeFrom then ZVTimeFrom.Time := DateTimeFrom; cbTimeTo.Checked := IsTimeTo; if IsTimeTo then ZVTimeTo.Time := DateTimeTo; // not older then cbNotOlderThan.Checked := IsNotOlderThan; seNotOlderThan.Value := NotOlderThan; cmbNotOlderThanUnit.ItemIndex := TimeUnitToComboIndex[NotOlderThanUnit]; // file size cbFileSizeFrom.Checked := IsFileSizeFrom; cbFileSizeTo.Checked := IsFileSizeTo; seFileSizeFrom.Value := FileSizeFrom; seFileSizeTo.Value := FileSizeTo; cmbFileSizeUnit.ItemIndex := FileSizeUnitToComboIndex[FileSizeUnit]; // find/replace text cbFindText.Checked := IsFindText; cmbFindText.Text := FindText; if cbFindInArchive.Enabled then begin cbReplaceText.Checked := IsReplaceText; cmbReplaceText.Text := ReplaceText; end; chkHex.Checked := HexValue; cbCaseSens.Checked := CaseSensitive; cbNotContainingText.Checked := NotContainingText; cbTextRegExp.Checked := TextRegExp; SetEncodings(TextEncoding, cmbEncoding); cbOfficeXML.Checked := OfficeXML; UpdateEncodings; if cbFindInArchive.Enabled then begin // duplicates chkDuplicates.Checked := Duplicates; chkDuplicateName.Checked := DuplicateName; chkDuplicateSize.Checked := DuplicateSize; chkDuplicateHash.Checked := DuplicateHash; chkDuplicateContent.Checked := DuplicateContent; // plugins if cbUsePlugin.Enabled then begin cmbPlugin.Tag := cmbPlugin.Items.IndexOf(SearchPlugin); cbUsePlugin.Checked:= (cmbPlugin.Tag >= 0); if cbUsePlugin.Checked then cmbPlugin.ItemIndex := cmbPlugin.Tag; end; frmContentPlugins.Load(Template); end; //Let's switch to the most pertinent tab after having load the template. //If we would just load and no switching, user has not a real feedback visually he loaded something. //1. If we're using at least plug in, switch to it. //2. If not but we're using at least something from the "Advanced" tab, switch to it. //3. If nothing above, at least switch to "Standard" tab. pgcSearch.Options:= pgcSearch.Options + [nboDoChangeOnSetIndex]; if (cbUsePlugin.Checked OR frmContentPlugins.chkUsePlugins.Checked) then pgcSearch.ActivePage := tsPlugins else if (cbNotOlderThan.Checked OR cbFileSizeFrom.Checked OR cbFileSizeTo.Checked OR cbDateFrom.Checked OR cbDateTo.Checked OR cbTimeFrom.Checked OR cbTimeTo.Checked OR (edtAttrib.Text<>'')) then pgcSearch.ActivePage := tsAdvanced else begin pgcSearch.ActivePage := tsStandard; end; pgcSearch.Options:= pgcSearch.Options - [nboDoChangeOnSetIndex]; end; end; { TfrmFindDlg.lsFoundedFilesDblClick } procedure TfrmFindDlg.lsFoundedFilesDblClick(Sender: TObject); begin cm_GoToFile([]); end; { TfrmFindDlg.lsFoundedFilesKeyDown } procedure TfrmFindDlg.lsFoundedFilesKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin if (Shift = []) and (lsFoundedFiles.ItemIndex <> -1) then begin case Key of VK_DELETE: begin miRemoveFromLlistClick(Sender); Key := 0; end; VK_RETURN: begin if not FSearchingActive then begin cm_GotoFile([]); Key := 0; end; end; VK_RIGHT, VK_LEFT: begin if not FSearchingActive then begin if FRButtonPanelSender <> nil then (FRButtonPanelSender as TButton).SetFocus else btnNewSearch.SetFocus; Key := 0; end else begin Key := 0; btnStop.SetFocus; end; end; end; end; end; { TfrmFindDlg.lsFoundedFilesMouseDown } procedure TfrmFindDlg.lsFoundedFilesMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); var i: integer; begin i := lsFoundedFiles.ItemAtPos(Point(X, Y), False); if (i >= 0) then begin LastClickResultsPath := GetDeepestExistingPath(lsFoundedFiles.Items[i]); if (Button = mbRight) and (lsFoundedFiles.Selected[i] <> True) then begin lsFoundedFiles.ClearSelection; lsFoundedFiles.Selected[i] := True; end; end; end; { TfrmFindDlg.lsFoundedFilesMouseUp } procedure TfrmFindDlg.lsFoundedFilesMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); var i: integer; sPath: string; AFile: TFile; AFiles: TFiles; pt: TPoint; begin if Button = mbRight then begin if Shift = [ssCtrl] then // Show System context menu begin {$IF DEFINED(MSWINDOWS)} try AFiles := TFiles.Create(LastClickResultsPath); AFiles.Path := LastClickResultsPath; i := 0; while i < lsFoundedFiles.Count do begin if lsFoundedFiles.Selected[i] then begin sPath := lsFoundedFiles.Items[i]; AFile := TFileSystemFileSource.CreateFile(sPath); AFiles.Add(aFile); end; Inc(i); end; try pt.X := X; pt.Y := Y; pt := ClientToScreen(pt); ShowContextMenu(lsFoundedFiles, AFiles, pt.X, pt.Y, False, nil); finally FreeAndNil(AFiles); end; except on E: EContextMenuException do ShowException(E) else; end; {$ENDIF} end else begin PopupMenuFind.PopUp; // Show DC menu end; end; end; { TfrmFindDlg.lsFoundedFilesMouseWheelDown } procedure TfrmFindDlg.lsFoundedFilesMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: boolean); begin if (Shift = [ssCtrl]) and (gFonts[dcfSearchResults].Size > gFonts[dcfSearchResults].MinValue) then begin dec(gFonts[dcfSearchResults].Size); lsFoundedFiles.Font.Size := gFonts[dcfSearchResults].Size; Handled := True; end; end; { TfrmFindDlg.lsFoundedFilesMouseWheelUp } procedure TfrmFindDlg.lsFoundedFilesMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: boolean); begin if (Shift = [ssCtrl]) and (gFonts[dcfSearchResults].Size < gFonts[dcfSearchResults].MaxValue) then begin inc(gFonts[dcfSearchResults].Size); lsFoundedFiles.Font.Size := gFonts[dcfSearchResults].Size; Handled := True; end; end; { TfrmFindDlg.miOpenInNewTabClick } procedure TfrmFindDlg.miOpenInNewTabClick(Sender: TObject); var i: integer; sPath: string; Notebook: TFileViewNotebook; NewPage: TFileViewPage; begin Notebook := frmMain.ActiveNotebook; i := 0; while i < lsFoundedFiles.Count do begin if lsFoundedFiles.Selected[i] then begin sPath := lsFoundedFiles.Items[i]; sPath := GetDeepestExistingPath(sPath); NewPage := Notebook.NewPage(Notebook.ActiveView); NewPage.FileView.CurrentPath := sPath; NewPage.FileView.SetActiveFile(ExtractFileName(lsFoundedFiles.Items[i])); end; Inc(i); end; end; { TfrmFindDlg.miRemoveFromLlistClick } procedure TfrmFindDlg.miRemoveFromLlistClick(Sender: TObject); var i: integer; begin if lsFoundedFiles.ItemIndex = -1 then Exit; if lsFoundedFiles.SelCount = 0 then Exit; for i := lsFoundedFiles.Items.Count - 1 downto 0 do if lsFoundedFiles.Selected[i] then lsFoundedFiles.Items.Delete(i); miShowAllFound.Enabled := True; end; { TfrmFindDlg.miShowAllFoundClick } procedure TfrmFindDlg.miShowAllFoundClick(Sender: TObject); begin lsFoundedFiles.Clear; lsFoundedFiles.Items.AddStrings(FoundedStringCopy); miShowAllFound.Enabled := False; end; { TfrmFindDlg.miShowInEditorClick } procedure TfrmFindDlg.miShowInEditorClick(Sender: TObject); begin if lsFoundedFiles.ItemIndex >= 0 then ShowEditorByGlob(lsFoundedFiles.Items[lsFoundedFiles.ItemIndex]); end; { TfrmFindDlg.miShowInViewerClick } procedure TfrmFindDlg.miShowInViewerClick(Sender: TObject); var sl: TStringList; i: integer; begin if lsFoundedFiles.ItemIndex = -1 then Exit; sl := TStringList.Create; try for i := 0 to lsFoundedFiles.Items.Count - 1 do if lsFoundedFiles.Selected[i] then sl.Add(lsFoundedFiles.Items[i]); ShowViewer(sl); finally sl.Free; end; end; { TfrmFindDlg.seFileSizeFromChange } procedure TfrmFindDlg.seFileSizeFromChange(Sender: TObject); begin if not FUpdating then cbFileSizeFrom.Checked := (seFileSizeFrom.Value > 0); end; { TfrmFindDlg.seFileSizeToChange } procedure TfrmFindDlg.seFileSizeToChange(Sender: TObject); begin if not FUpdating then cbFileSizeTo.Checked := (seFileSizeTo.Value > 0); end; { TfrmFindDlg.SelectTemplate } procedure TfrmFindDlg.SelectTemplate(const ATemplateName: string); var i: integer; begin for i := 0 to lbSearchTemplates.Count - 1 do if lbSearchTemplates.Items[i] = ATemplateName then begin lbSearchTemplates.ItemIndex := i; Break; end; end; { TfrmFindDlg.seNotOlderThanChange } procedure TfrmFindDlg.seNotOlderThanChange(Sender: TObject); begin if not FUpdating then cbNotOlderThan.Checked := (seNotOlderThan.Value > 0); end; { TfrmFindDlg.tsLoadSaveShow } procedure TfrmFindDlg.tsLoadSaveShow(Sender: TObject); begin UpdateTemplatesList; if (lbSearchTemplates.Count > 0) and (lbSearchTemplates.ItemIndex = -1) then lbSearchTemplates.ItemIndex := 0; end; { TfrmFindDlg.tsStandardEnter } procedure TfrmFindDlg.tsStandardEnter(Sender: TObject); begin btnStart.Default := True; end; { TfrmFindDlg.UpdateTemplatesList } procedure TfrmFindDlg.UpdateTemplatesList; var OldIndex: integer; begin OldIndex := lbSearchTemplates.ItemIndex; gSearchTemplateList.LoadToStringList(lbSearchTemplates.Items); if OldIndex <> -1 then lbSearchTemplates.ItemIndex := OldIndex; end; { TfrmFindDlg.OnUpdateTimer } procedure TfrmFindDlg.OnUpdateTimer(Sender: TObject); begin if Assigned(FFindThread) then begin lblStatus.Caption := Format(rsFindScanned, [FFindThread.FilesScanned]) + FTimeSearch; lblFound.Caption := Format(rsFindFound, [FFindThread.FilesFound]); lblCurrent.Caption := rsFindScanning + ': ' + FFindThread.CurrentDir; end; end; { TfrmFindDlg.ZVDateFromChange } procedure TfrmFindDlg.ZVDateFromChange(Sender: TObject); begin if not FUpdating then cbDateFrom.Checked := True; end; { TfrmFindDlg.ZVDateToChange } procedure TfrmFindDlg.ZVDateToChange(Sender: TObject); begin if not FUpdating then cbDateTo.Checked := True; end; { TfrmFindDlg.ZVTimeFromChange } procedure TfrmFindDlg.ZVTimeFromChange(Sender: TObject); begin if not FUpdating then cbTimeFrom.Checked := True; end; { TfrmFindDlg.ZVTimeToChange } procedure TfrmFindDlg.ZVTimeToChange(Sender: TObject); begin if not FUpdating then cbTimeTo.Checked := True; end; procedure TfrmFindDlg.PopupMenuFindPopup(Sender: TObject); begin if (lsFoundedFiles.ItemIndex <> -1) then begin miShowInViewer.Enabled:= (ObjectType(lsFoundedFiles.ItemIndex) <> cbChecked); miShowInEditor.Enabled:= (ObjectType(lsFoundedFiles.ItemIndex) <> cbChecked); end; end; { TfrmFindDlg.OnAddAttribute } procedure TfrmFindDlg.OnAddAttribute(Sender: TObject); var sAttr: string; begin sAttr := edtAttrib.Text; if edtAttrib.SelStart > 0 then // Insert at caret position. Insert((Sender as TfrmAttributesEdit).AttrsAsText, sAttr, edtAttrib.SelStart + 1) else sAttr := sAttr + (Sender as TfrmAttributesEdit).AttrsAsText; edtAttrib.Text := sAttr; end; { TfrmFindDlg.InvalidRegExpr } function TfrmFindDlg.InvalidRegExpr: Boolean; var sMsg, sEncoding: String; begin Result:= False; try if cbRegExp.Checked then begin uRegExprW.ExecRegExpr(CeUtf8ToUtf16(cmbFindFileMask.Text), ''); end; if cbTextRegExp.Checked then begin sMsg:= cmbFindText.Text; sEncoding:= NormalizeEncoding(cmbEncoding.Text); if sEncoding = EncodingDefault then sEncoding:= GetDefaultTextEncoding; // Use correct RegExp engine if TRegExprU.Available and (sEncoding = EncodingUTF8) then uRegExprU.ExecRegExpr(sMsg, '') else if SingleByteEncoding(sEncoding) then uRegExprA.ExecRegExpr(sMsg, '') else if (sEncoding = EncodingUTF16LE) then uRegExprW.ExecRegExpr(CeUtf8ToUtf16(sMsg), ''); end; except on E: Exception do begin Result:= True; sMsg:= StringReplace(cbRegExp.Caption, '&', '', [rfReplaceAll]); MessageDlg(sMsg + ': ' + E.Message, mtError, [mbOK], 0); end; end; end; { TfrmFindDlg.pgcSearchChange } procedure TfrmFindDlg.pgcSearchChange(Sender: TObject); begin if pgcSearch.ActivePage = tsStandard then begin if (not cmbFindFileMask.Focused) and (cmbFindFileMask.CanSetFocus) then cmbFindFileMask.SetFocus; end else if pgcSearch.ActivePage = tsResults then begin if (not lsFoundedFiles.Focused) and (lsFoundedFiles.CanSetFocus) then lsFoundedFiles.SetFocus; end; end; { TfrmFindDlg.SaveTemplate } procedure TfrmFindDlg.SaveTemplate(SaveStartingPath: boolean); var sName: string; SearchTemplate: TSearchTemplate; SearchRec: TSearchTemplateRec; begin if InvalidRegExpr then Exit; sName := FLastTemplateName; if not InputQuery(rsFindSaveTemplateCaption, rsFindSaveTemplateTitle, sName) then begin ModalResult := mrCancel; Exit; end; FLastTemplateName := sName; SearchTemplate := gSearchTemplateList.TemplateByName[sName]; if Assigned(SearchTemplate) then begin // TODO: Ask for overwriting existing template. FillFindOptions(SearchRec, SaveStartingPath); SearchTemplate.SearchRecord := SearchRec; Exit; end; SearchTemplate := TSearchTemplate.Create; try SearchTemplate.TemplateName := sName; FillFindOptions(SearchRec, SaveStartingPath); SearchTemplate.SearchRecord := SearchRec; gSearchTemplateList.Add(SearchTemplate); except FreeAndNil(SearchTemplate); raise; end; UpdateTemplatesList; SelectTemplate(FLastTemplateName); end; function TfrmFindDlg.GetTextSearchOptions: UIntPtr; var Options: TTextSearchOptions absolute Result; begin Result:= 0; if cbCaseSens.Checked then Include(Options, tsoMatchCase); if cbTextRegExp.Checked then Include(Options, tsoRegExpr); if chkHex.Checked then Include(Options, tsoHex); end; procedure TfrmFindDlg.CancelCloseAndFreeMem; begin cm_FreeFromMem([]); end; { TfrmFindDlg.cm_Close } procedure TfrmFindDlg.cm_Close(const Params: array of string); begin Hide; Close; end; { TfrmFindDlg.cm_NewSearchClearFilters } procedure TfrmFindDlg.cm_NewSearchClearFilters(const Params: array of string); begin cm_NewSearch(['filters=clear']); end; { TfrmFindDlg.cm_FreeFromMem } // We will set the flag "FFreeOnClose" to "true" (it was to "false" since "FormCreate". // This flag will be checked in "FormClose" to set "CloseAction" to "caFree" so form will be destroy. // But we need to remove the pointer to that form from our "ListOffrmFindDlgInstance". // To determine which one to remove, we set the tag to a magic number, then scan our list and delete the one pointing the form with that magic number. // We just delete the pointer. The actual form will be destroyed properly because of the "CloseAction" set to "caFree". procedure TfrmFindDlg.cm_FreeFromMem(const {%H-}Params: array of string); var iSearchingForm: integer; const CLOSETAG: longint = $233528DE; begin if FSearchingActive then StopSearch; // Remove our pointer from our list of forms tag := CLOSETAG; for iSearchingForm := pred(ListOffrmFindDlgInstance.Count) downto 1 do begin if ListOffrmFindDlgInstance.frmFindDlgInstance[iSearchingForm].Tag = CLOSETAG then ListOffrmFindDlgInstance.Delete(iSearchingForm); end; FFreeOnClose := True; // Prepare the "free mem" // Do the "close" Close; end; { TfrmFindDlg.cm_FreeFromMemAllOthers } // We set the tag of our actual current form to a magic number and then scan // all forms in our list to close all the ones that does not have that magic // tag number. procedure TfrmFindDlg.cm_FreeFromMemAllOthers(const {%H-}Params: array of string); const KEEPOPENTAG: longint = $270299; var iIndex: integer; begin if ListOffrmFindDlgInstance.Count > 1 then begin tag := KEEPOPENTAG; try for iIndex := pred(ListOffrmFindDlgInstance.Count) downto 0 do if ListOffrmFindDlgInstance.frmFindDlgInstance[iIndex].Tag <> KEEPOPENTAG then ListOffrmFindDlgInstance.frmFindDlgInstance[iIndex].CancelCloseAndFreeMem; finally tag := 0; // Don't forget to set back tag to 0!!! end; end else begin msgOK(rsNoOtherFindFilesWindowToClose); end; end; { TfrmFindDlg.cm_ConfigFileSearchHotKeys } procedure TfrmFindDlg.cm_ConfigFileSearchHotKeys(const {%H-}Params: array of string); begin frmMain.Commands.cm_ConfigHotKeys([Format('category=%s', [rsHotkeyCategoryFindFiles])]); end; initialization TFormCommands.RegisterCommandsForm(TfrmFindDlg, HotkeysCategory, @rsHotkeyCategoryFindFiles); ListOffrmFindDlgInstance := TListOffrmFindDlgInstance.Create; finalization ListOffrmFindDlgInstance.Destroy; // "Destroy" does call the "Clear" who will free the forms. end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fMsg.lfm�����������������������������������������������������������������������0000644�0001750�0000144�00000002633�14743153644�014775� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMsg: TfrmMsg Left = 572 Height = 254 Top = 233 Width = 426 HorzScrollBar.Page = 425 VertScrollBar.Page = 253 AutoSize = True ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 254 ClientWidth = 426 Constraints.MinWidth = 250 DefaultMonitor = dmMainForm KeyPreview = True OnClose = FormClose OnCreate = FormCreate OnKeyDown = FormKeyDown OnKeyPress = FormKeyPress LCLVersion = '1.6.0.4' object lblMsg: TLabel AnchorSideRight.Side = asrBottom Left = 12 Height = 18 Top = 12 Width = 402 Align = alTop BorderSpacing.Left = 12 BorderSpacing.Top = 12 BorderSpacing.Right = 12 Caption = '456456465465465' ParentColor = False ShowAccelChar = False end object pnlButtons: TPanel AnchorSideBottom.Side = asrBottom Left = 12 Height = 200 Top = 42 Width = 402 Align = alClient AutoSize = True BorderSpacing.Left = 12 BorderSpacing.Top = 12 BorderSpacing.Right = 12 BorderSpacing.Bottom = 12 BevelOuter = bvNone ChildSizing.LeftRightSpacing = 12 ChildSizing.HorizontalSpacing = 12 ChildSizing.VerticalSpacing = 4 ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 3 TabOrder = 0 end object mnuOther: TPopupMenu left = 120 top = 48 end end �����������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fMsg.lrj�����������������������������������������������������������������������0000644�0001750�0000144�00000000250�14743153644�014777� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":16852869,"name":"tfrmmsg.lblmsg.caption","sourcebytes":[52,53,54,52,53,54,52,54,53,52,54,53,52,54,53],"value":"456456465465465"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fMsg.pas�����������������������������������������������������������������������0000644�0001750�0000144�00000006105�14743153644�015000� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fMsg; interface uses SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, Menus, uOSForms; type { TfrmMsg } TfrmMsg = class(TModalForm) lblMsg: TLabel; pnlButtons: TPanel; mnuOther: TPopupMenu; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormKeyPress(Sender: TObject; var Key: Char); public ActionHandler: procedure(Tag: PtrInt) of object; Escape: Integer; iSelected: Integer; procedure ButtonClick(Sender:TObject); procedure ButtonOtherClick(Sender:TObject); procedure MouseUpEvent(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); end; implementation {$R *.lfm} uses LCLType, LazUTF8, Clipbrd; procedure TfrmMsg.FormCreate(Sender: TObject); begin Escape:= -1; iSelected:= -1; pnlButtons.ParentColor:= true; end; procedure TfrmMsg.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin if (iSelected = -1) and (Escape >= 0) then iSelected:= Escape; end; procedure TfrmMsg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var Index: Integer; NextOrder: Integer; begin if (Key in [VK_UP, VK_DOWN]) and (ActiveControl is TButton) then begin NextOrder:= pnlButtons.ChildSizing.ControlsPerLine; if Key = VK_UP then NextOrder:= -NextOrder; NextOrder:= ActiveControl.TabOrder + NextOrder; for Index:= 0 to pnlButtons.ControlCount - 1 do begin if pnlButtons.Controls[Index] is TButton then begin if NextOrder = TButton(pnlButtons.Controls[Index]).TabOrder then begin ActiveControl:= TButton(pnlButtons.Controls[Index]); Key:= 0; Break; end; end; end; end else if (Key = VK_C) and (ssModifier in Shift) then begin Clipboard.AsText:= Caption + LineEnding + StringOfChar('-', UTF8Length(Caption)) + LineEnding + LineEnding + lblMsg.Caption; end; end; procedure TfrmMsg.ButtonClick(Sender: TObject); var aTag: PtrInt; begin aTag:= (Sender as TComponent).Tag; if (aTag < -1) then begin if Assigned(ActionHandler) then ActionHandler(aTag); end else begin iSelected:= aTag; Close; end; end; procedure TfrmMsg.MouseUpEvent(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin {$IF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} if (Button = mbLeft) and (Sender = FindLCLControl(Mouse.CursorPos)) then begin ButtonClick(Sender); end; {$ENDIF} end; procedure TfrmMsg.FormKeyPress(Sender: TObject; var Key: Char); begin if (Key = #27) and (Escape >= 0) then begin Key:= #0; iSelected:= Escape; Close; end; end; procedure TfrmMsg.ButtonOtherClick(Sender: TObject); var Point: TPoint; Button: TButton absolute Sender; begin Point.X:= Button.Left; Point.Y:= Button.Top + Button.Height; Point:= pnlButtons.ClientToScreen(Point); mnuOther.PopUp(Point.X, Point.Y); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fattributesedit.lfm������������������������������������������������������������0000644�0001750�0000144�00000034035�14743153644�017304� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmAttributesEdit: TfrmAttributesEdit Left = 388 Height = 284 Top = 144 Width = 329 AutoSize = True BorderIcons = [biSystemMenu] Caption = 'Choose attributes' ClientHeight = 284 ClientWidth = 329 FormStyle = fsStayOnTop Position = poOwnerFormCenter ShowInTaskBar = stNever LCLVersion = '1.1' object pnlTopAttrs: TPanel Left = 0 Height = 23 Top = 5 Width = 329 Align = alTop AutoSize = True BorderSpacing.Top = 5 BevelOuter = bvNone ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.ShrinkHorizontal = crsHomogenousSpaceResize ChildSizing.ShrinkVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ClientHeight = 23 ClientWidth = 329 TabOrder = 0 object cbSymlink: TCheckBox Left = 58 Height = 23 Top = 0 Width = 72 AllowGrayed = True Caption = '&Symlink' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 0 end object cbDirectory: TCheckBox Left = 188 Height = 23 Top = 0 Width = 84 AllowGrayed = True Caption = '&Directory' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 1 end end object pnlUnixAttrs: TPanel Left = 10 Height = 181 Top = 28 Width = 309 Align = alClient BorderSpacing.Left = 10 BorderSpacing.Right = 10 BevelOuter = bvNone ClientHeight = 181 ClientWidth = 309 TabOrder = 1 Visible = False object lblAttrOwnerStr: TLabel AnchorSideTop.Control = cbReadOwner AnchorSideTop.Side = asrCenter Left = 8 Height = 18 Top = 33 Width = 46 Caption = 'Owner' ParentColor = False end object lblWrite: TLabel AnchorSideTop.Side = asrBottom Left = 176 Height = 18 Top = 8 Width = 38 BorderSpacing.Top = 8 Caption = 'Write' ParentColor = False end object lblRead: TLabel AnchorSideTop.Side = asrBottom Left = 104 Height = 18 Top = 8 Width = 32 BorderSpacing.Top = 8 Caption = 'Read' ParentColor = False end object lblExec: TLabel AnchorSideTop.Side = asrBottom Left = 240 Height = 18 Top = 8 Width = 53 BorderSpacing.Top = 8 Caption = 'Execute' ParentColor = False end object lblAttrGroupStr: TLabel AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrCenter Left = 8 Height = 18 Top = 59 Width = 41 Caption = 'Group' ParentColor = False end object lblAttrOtherStr: TLabel AnchorSideTop.Control = cbReadOther AnchorSideTop.Side = asrCenter Left = 8 Height = 18 Top = 85 Width = 40 Caption = 'Other' ParentColor = False end object lblAttrBitsStr: TLabel AnchorSideTop.Control = cbSuid AnchorSideTop.Side = asrCenter Left = 8 Height = 18 Top = 112 Width = 29 Caption = 'Bits:' ParentColor = False end object cbReadOwner: TCheckBox AnchorSideTop.Control = lblRead AnchorSideTop.Side = asrBottom Left = 112 Height = 20 Top = 32 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 0 end object cbWriteOwner: TCheckBox AnchorSideTop.Control = lblWrite AnchorSideTop.Side = asrBottom Left = 184 Height = 20 Top = 32 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 1 end object cbExecOwner: TCheckBox AnchorSideTop.Control = lblExec AnchorSideTop.Side = asrBottom Left = 256 Height = 20 Top = 32 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 2 end object cbReadGroup: TCheckBox AnchorSideTop.Control = cbReadOwner AnchorSideTop.Side = asrBottom Left = 112 Height = 20 Top = 58 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 3 end object cbWriteGroup: TCheckBox AnchorSideTop.Control = cbWriteOwner AnchorSideTop.Side = asrBottom Left = 184 Height = 20 Top = 58 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 4 end object cbExecGroup: TCheckBox AnchorSideTop.Control = cbExecOwner AnchorSideTop.Side = asrBottom Left = 256 Height = 20 Top = 58 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 5 end object cbReadOther: TCheckBox AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrBottom Left = 112 Height = 20 Top = 84 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 6 end object cbWriteOther: TCheckBox AnchorSideTop.Control = cbWriteGroup AnchorSideTop.Side = asrBottom Left = 184 Height = 20 Top = 84 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 7 end object cbExecOther: TCheckBox AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrBottom Left = 256 Height = 20 Top = 84 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 8 end object cbSuid: TCheckBox AnchorSideTop.Control = cbReadOther AnchorSideTop.Side = asrBottom Left = 112 Height = 23 Top = 110 Width = 57 AllowGrayed = True BorderSpacing.Top = 6 Caption = 'SUID' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 9 end object cbSgid: TCheckBox AnchorSideTop.Control = cbWriteOther AnchorSideTop.Side = asrBottom Left = 184 Height = 23 Top = 110 Width = 58 AllowGrayed = True BorderSpacing.Top = 6 Caption = 'SGID' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 10 end object cbSticky: TCheckBox AnchorSideTop.Control = cbExecOther AnchorSideTop.Side = asrBottom Left = 256 Height = 23 Top = 110 Width = 61 AllowGrayed = True BorderSpacing.Top = 6 Caption = 'Sticky' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 11 end end object pnlWinAttrs: TPanel Left = 10 Height = 181 Top = 28 Width = 309 Align = alClient AutoSize = True BorderSpacing.Left = 10 BorderSpacing.Right = 10 BevelOuter = bvNone ChildSizing.HorizontalSpacing = 10 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.ShrinkVertical = crsHomogenousChildResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ClientHeight = 181 ClientWidth = 309 TabOrder = 2 Visible = False object gbWinGeneral: TGroupBox Left = 0 Height = 181 Top = 0 Width = 150 AutoSize = True Caption = 'General attributes' ChildSizing.LeftRightSpacing = 5 ChildSizing.TopBottomSpacing = 5 ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.ShrinkHorizontal = crsHomogenousSpaceResize ChildSizing.ShrinkVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 158 ClientWidth = 146 Constraints.MinWidth = 150 TabOrder = 0 object cbArchive: TCheckBox Left = 30 Height = 23 Top = 12 Width = 86 AllowGrayed = True Caption = '&Archive' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 0 end object cbReadOnly: TCheckBox Left = 30 Height = 23 Top = 47 Width = 86 AllowGrayed = True Caption = 'Read o&nly' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 1 end object cbHidden: TCheckBox Left = 30 Height = 23 Top = 82 Width = 86 AllowGrayed = True Caption = '&Hidden' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 2 end object cbSystem: TCheckBox Left = 30 Height = 23 Top = 117 Width = 86 AllowGrayed = True Caption = 'S&ystem' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 3 end end object gbNtfsAttributes: TGroupBox Left = 160 Height = 181 Top = 0 Width = 150 AutoSize = True Caption = 'NTFS attributes' ChildSizing.LeftRightSpacing = 5 ChildSizing.TopBottomSpacing = 5 ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.ShrinkHorizontal = crsHomogenousSpaceResize ChildSizing.ShrinkVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 158 ClientWidth = 146 Constraints.MinWidth = 150 TabOrder = 1 object cbCompressed: TCheckBox Left = 22 Height = 23 Top = 12 Width = 103 AllowGrayed = True Caption = 'Co&mpressed' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 0 end object cbEncrypted: TCheckBox Left = 22 Height = 23 Top = 47 Width = 103 AllowGrayed = True Caption = '&Encrypted' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 1 end object cbTemporary: TCheckBox Left = 22 Height = 23 Top = 82 Width = 103 AllowGrayed = True Caption = '&Temporary' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 2 end object cbSparse: TCheckBox Left = 22 Height = 23 Top = 117 Width = 103 AllowGrayed = True Caption = 'S&parse' OnChange = cbAttrCheckBoxChanged OnClick = cbAttrCheckBoxClicked State = cbGrayed TabOrder = 3 end end end object pnlTextAttrs: TPanel Left = 10 Height = 28 Top = 214 Width = 309 Align = alBottom AutoSize = True BorderSpacing.Left = 10 BorderSpacing.Top = 5 BorderSpacing.Right = 10 BevelOuter = bvNone ClientHeight = 28 ClientWidth = 309 TabOrder = 3 object lblTextAttrs: TLabel AnchorSideLeft.Control = pnlTextAttrs AnchorSideTop.Control = pnlTextAttrs AnchorSideTop.Side = asrCenter Left = 0 Height = 18 Top = 5 Width = 53 Caption = 'As te&xt:' FocusControl = edtTextAttrs ParentColor = False end object edtTextAttrs: TEdit AnchorSideLeft.Control = lblTextAttrs AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlTextAttrs AnchorSideRight.Side = asrBottom Left = 63 Height = 28 Top = 0 Width = 246 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ReadOnly = True TabOrder = 0 end end object pnlButtons: TPanel Left = 5 Height = 32 Top = 247 Width = 319 Align = alBottom AutoSize = True BorderSpacing.Around = 5 BevelOuter = bvNone ChildSizing.HorizontalSpacing = 10 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.ShrinkVertical = crsHomogenousChildResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ClientHeight = 32 ClientWidth = 319 TabOrder = 4 object btnReset: TButton Left = 0 Height = 32 Top = 0 Width = 87 Caption = '&Reset' OnClick = btnResetClick TabOrder = 0 end object btnOk: TBitBtn Left = 97 Height = 32 Top = 0 Width = 94 Caption = '&OK' Constraints.MinHeight = 30 Default = True Kind = bkOK ModalResult = 1 OnClick = btnOkClick TabOrder = 1 end object btnCancel: TBitBtn Left = 201 Height = 32 Top = 0 Width = 118 Cancel = True Caption = '&Cancel' Constraints.MinHeight = 30 Kind = bkCancel ModalResult = 2 OnClick = btnCancelClick TabOrder = 2 end end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fattributesedit.lrj������������������������������������������������������������0000644�0001750�0000144�00000006726�14743153644�017323� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":29800211,"name":"tfrmattributesedit.caption","sourcebytes":[67,104,111,111,115,101,32,97,116,116,114,105,98,117,116,101,115],"value":"Choose attributes"}, {"hash":184823547,"name":"tfrmattributesedit.cbsymlink.caption","sourcebytes":[38,83,121,109,108,105,110,107],"value":"&Symlink"}, {"hash":146283929,"name":"tfrmattributesedit.cbdirectory.caption","sourcebytes":[38,68,105,114,101,99,116,111,114,121],"value":"&Directory"}, {"hash":5694658,"name":"tfrmattributesedit.lblattrownerstr.caption","sourcebytes":[79,119,110,101,114],"value":"Owner"}, {"hash":6197413,"name":"tfrmattributesedit.lblwrite.caption","sourcebytes":[87,114,105,116,101],"value":"Write"}, {"hash":363380,"name":"tfrmattributesedit.lblread.caption","sourcebytes":[82,101,97,100],"value":"Read"}, {"hash":216771813,"name":"tfrmattributesedit.lblexec.caption","sourcebytes":[69,120,101,99,117,116,101],"value":"Execute"}, {"hash":5150400,"name":"tfrmattributesedit.lblattrgroupstr.caption","sourcebytes":[71,114,111,117,112],"value":"Group"}, {"hash":5680834,"name":"tfrmattributesedit.lblattrotherstr.caption","sourcebytes":[79,116,104,101,114],"value":"Other"}, {"hash":4787050,"name":"tfrmattributesedit.lblattrbitsstr.caption","sourcebytes":[66,105,116,115,58],"value":"Bits:"}, {"hash":362964,"name":"tfrmattributesedit.cbsuid.caption","sourcebytes":[83,85,73,68],"value":"SUID"}, {"hash":359380,"name":"tfrmattributesedit.cbsgid.caption","sourcebytes":[83,71,73,68],"value":"SGID"}, {"hash":95091241,"name":"tfrmattributesedit.cbsticky.caption","sourcebytes":[83,116,105,99,107,121],"value":"Sticky"}, {"hash":197332467,"name":"tfrmattributesedit.gbwingeneral.caption","sourcebytes":[71,101,110,101,114,97,108,32,97,116,116,114,105,98,117,116,101,115],"value":"General attributes"}, {"hash":143258213,"name":"tfrmattributesedit.cbarchive.caption","sourcebytes":[38,65,114,99,104,105,118,101],"value":"&Archive"}, {"hash":108290121,"name":"tfrmattributesedit.cbreadonly.caption","sourcebytes":[82,101,97,100,32,111,38,110,108,121],"value":"Read o&nly"}, {"hash":183478942,"name":"tfrmattributesedit.cbhidden.caption","sourcebytes":[38,72,105,100,100,101,110],"value":"&Hidden"}, {"hash":98609901,"name":"tfrmattributesedit.cbsystem.caption","sourcebytes":[83,38,121,115,116,101,109],"value":"S&ystem"}, {"hash":61805299,"name":"tfrmattributesedit.gbntfsattributes.caption","sourcebytes":[78,84,70,83,32,97,116,116,114,105,98,117,116,101,115],"value":"NTFS attributes"}, {"hash":130462964,"name":"tfrmattributesedit.cbcompressed.caption","sourcebytes":[67,111,38,109,112,114,101,115,115,101,100],"value":"Co&mpressed"}, {"hash":178444020,"name":"tfrmattributesedit.cbencrypted.caption","sourcebytes":[38,69,110,99,114,121,112,116,101,100],"value":"&Encrypted"}, {"hash":74723929,"name":"tfrmattributesedit.cbtemporary.caption","sourcebytes":[38,84,101,109,112,111,114,97,114,121],"value":"&Temporary"}, {"hash":97946053,"name":"tfrmattributesedit.cbsparse.caption","sourcebytes":[83,38,112,97,114,115,101],"value":"S&parse"}, {"hash":128423722,"name":"tfrmattributesedit.lbltextattrs.caption","sourcebytes":[65,115,32,116,101,38,120,116,58],"value":"As te&xt:"}, {"hash":45664708,"name":"tfrmattributesedit.btnreset.caption","sourcebytes":[38,82,101,115,101,116],"value":"&Reset"}, {"hash":11067,"name":"tfrmattributesedit.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmattributesedit.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} ]} ������������������������������������������doublecmd-1.1.22/src/fattributesedit.pas������������������������������������������������������������0000644�0001750�0000144�00000015063�14743153644�017311� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Graphic control that allows choosing file attributes. Copyright (C) 2010 Przemysław Nagay (cobines@gmail.com) 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 } unit fAttributesEdit; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, ExtCtrls, StdCtrls, Buttons; type { TfrmAttributesEdit } TfrmAttributesEdit = class(TForm) btnOk: TBitBtn; btnCancel: TBitBtn; btnReset: TButton; cbExecGroup: TCheckBox; cbExecOther: TCheckBox; cbExecOwner: TCheckBox; cbReadGroup: TCheckBox; cbReadOther: TCheckBox; cbReadOwner: TCheckBox; cbSgid: TCheckBox; cbSticky: TCheckBox; cbSuid: TCheckBox; cbWriteGroup: TCheckBox; cbWriteOther: TCheckBox; cbWriteOwner: TCheckBox; cbDirectory: TCheckBox; cbSymlink: TCheckBox; cbCompressed: TCheckBox; cbEncrypted: TCheckBox; cbTemporary: TCheckBox; cbSparse: TCheckBox; cbArchive: TCheckBox; cbHidden: TCheckBox; cbReadOnly: TCheckBox; cbSystem: TCheckBox; edtTextAttrs: TEdit; gbWinGeneral: TGroupBox; gbNtfsAttributes: TGroupBox; lblAttrBitsStr: TLabel; lblAttrGroupStr: TLabel; lblAttrOtherStr: TLabel; lblAttrOwnerStr: TLabel; lblTextAttrs: TLabel; lblExec: TLabel; lblRead: TLabel; lblWrite: TLabel; pnlTextAttrs: TPanel; pnlTopAttrs: TPanel; pnlUnixAttrs: TPanel; pnlWinAttrs: TPanel; pnlButtons: TPanel; procedure btnCancelClick(Sender: TObject); procedure btnOkClick(Sender: TObject); procedure btnResetClick(Sender: TObject); procedure cbAttrCheckBoxChanged(Sender: TObject); procedure cbAttrCheckBoxClicked(Sender: TObject); private FOnOk: TNotifyEvent; FUpdatingControls: Boolean; function GetAttrsAsText: String; procedure UpdateText; function GetCheckStr(CheckBox: TCheckBox; AttrStr: String): String; public constructor Create(TheOwner: TComponent); override; procedure Reset; property OnOk: TNotifyEvent read FOnOk write FOnOk; property AttrsAsText: String read GetAttrsAsText; end; implementation {$R *.lfm} uses LCLVersion; procedure TfrmAttributesEdit.btnOkClick(Sender: TObject); begin if Assigned(FOnOk) then FOnOk(Self); Close; end; procedure TfrmAttributesEdit.btnCancelClick(Sender: TObject); begin Close; end; procedure TfrmAttributesEdit.btnResetClick(Sender: TObject); begin Reset; end; procedure TfrmAttributesEdit.cbAttrCheckBoxChanged(Sender: TObject); begin {$if lcl_fullversion = 2000004} // Workaround: https://bugs.freepascal.org/view.php?id=35018 if csLoading in TCheckBox(Sender).ComponentState then Exit; {$endif} // Note: OnChange may work incorrectly with tri-state checkboxes, // so OnClick is also used. UpdateText; end; procedure TfrmAttributesEdit.cbAttrCheckBoxClicked(Sender: TObject); begin {$if lcl_fullversion >= 2000004} // Workaround: https://bugs.freepascal.org/view.php?id=35018 if csLoading in TCheckBox(Sender).ComponentState then Exit; {$endif} UpdateText; end; constructor TfrmAttributesEdit.Create(TheOwner: TComponent); begin FOnOk := nil; FUpdatingControls := False; inherited Create(TheOwner); {$IF DEFINED(MSWINDOWS)} pnlWinAttrs.Visible := True; {$ELSEIF DEFINED(UNIX)} pnlUnixAttrs.Visible := True; {$ENDIF} end; procedure TfrmAttributesEdit.Reset; begin FUpdatingControls := True; cbDirectory.State := cbGrayed; cbSymlink.State := cbGrayed; cbReadOwner.State := cbGrayed; cbWriteOwner.State := cbGrayed; cbExecOwner.State := cbGrayed; cbReadGroup.State := cbGrayed; cbWriteGroup.State := cbGrayed; cbExecGroup.State := cbGrayed; cbReadOther.State := cbGrayed; cbWriteOther.State := cbGrayed; cbExecOther.State := cbGrayed; cbSuid.State := cbGrayed; cbSgid.State := cbGrayed; cbSticky.State := cbGrayed; cbArchive.State := cbGrayed; cbReadOnly.State := cbGrayed; cbHidden.State := cbGrayed; cbSystem.State := cbGrayed; cbCompressed.State := cbGrayed; cbEncrypted.State := cbGrayed; cbTemporary.State := cbGrayed; cbSparse.State := cbGrayed; edtTextAttrs.Text := ''; edtTextAttrs.Text := ''; FUpdatingControls := False; end; function TfrmAttributesEdit.GetAttrsAsText: String; begin Result := edtTextAttrs.Text; end; procedure TfrmAttributesEdit.UpdateText; var s: string = ''; begin if not FUpdatingControls then begin FUpdatingControls := True; s := s + GetCheckStr(cbDirectory, 'd'); s := s + GetCheckStr(cbSymlink, 'l'); if pnlUnixAttrs.Visible then begin s := s + GetCheckStr(cbReadOwner, 'ur'); s := s + GetCheckStr(cbWriteOwner, 'uw'); s := s + GetCheckStr(cbExecOwner, 'ux'); s := s + GetCheckStr(cbReadGroup, 'gr'); s := s + GetCheckStr(cbWriteGroup, 'gw'); s := s + GetCheckStr(cbExecGroup, 'gx'); s := s + GetCheckStr(cbReadOther, 'or'); s := s + GetCheckStr(cbWriteOther, 'ow'); s := s + GetCheckStr(cbExecOther, 'ox'); s := s + GetCheckStr(cbSuid, 'us'); s := s + GetCheckStr(cbSgid, 'gs'); s := s + GetCheckStr(cbSticky, 'sb'); end; if pnlWinAttrs.Visible then begin s := s + GetCheckStr(cbArchive, 'a'); s := s + GetCheckStr(cbReadOnly, 'r'); s := s + GetCheckStr(cbHidden, 'h'); s := s + GetCheckStr(cbSystem, 's'); s := s + GetCheckStr(cbCompressed, 'c'); s := s + GetCheckStr(cbEncrypted, 'e'); s := s + GetCheckStr(cbTemporary, 't'); s := s + GetCheckStr(cbSparse, 'p'); end; edtTextAttrs.Text := s; FUpdatingControls := False; end; end; function TfrmAttributesEdit.GetCheckStr(CheckBox: TCheckBox; AttrStr: String): String; begin case CheckBox.State of cbChecked: Result := AttrStr + '+'; cbUnchecked: Result := AttrStr + '-'; else Result := ''; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fbenchmark.lfm�����������������������������������������������������������������0000644�0001750�0000144�00000003146�14743153644�016201� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmBenchmark: TfrmBenchmark Left = 705 Height = 560 Top = 188 Width = 480 Caption = 'Benchmark' ClientHeight = 560 ClientWidth = 480 OnClose = FormClose Position = poOwnerFormCenter ShowInTaskBar = stAlways LCLVersion = '1.8.1.0' object stgResult: TStringGrid Left = 0 Height = 479 Top = 35 Width = 480 Align = alClient AutoEdit = False AutoFillColumns = True ColCount = 3 Columns = < item Title.Caption = 'Hash' Width = 159 end item Alignment = taRightJustify Title.Caption = 'Time (ms)' Width = 159 end item Alignment = taRightJustify Title.Caption = 'Speed (MB/s)' Width = 161 end> FixedCols = 0 Flat = True TabOrder = 0 ColWidths = ( 159 159 161 ) end object ButtonPanel: TButtonPanel Left = 6 Height = 34 Top = 520 Width = 468 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 1 ShowButtons = [pbClose] end object lblBenchmarkSize: TLabel Left = 10 Height = 15 Top = 10 Width = 460 Align = alTop Alignment = taCenter BorderSpacing.Left = 10 BorderSpacing.Top = 10 BorderSpacing.Right = 10 BorderSpacing.Bottom = 10 Caption = 'Benchmark data size: %d MB' ParentColor = False end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fbenchmark.lrj�����������������������������������������������������������������0000644�0001750�0000144�00000001424�14743153644�016207� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":77557835,"name":"tfrmbenchmark.caption","sourcebytes":[66,101,110,99,104,109,97,114,107],"value":"Benchmark"}, {"hash":321688,"name":"tfrmbenchmark.stgresult.columns[0].title.caption","sourcebytes":[72,97,115,104],"value":"Hash"}, {"hash":57855833,"name":"tfrmbenchmark.stgresult.columns[1].title.caption","sourcebytes":[84,105,109,101,32,40,109,115,41],"value":"Time (ms)"}, {"hash":125308217,"name":"tfrmbenchmark.stgresult.columns[2].title.caption","sourcebytes":[83,112,101,101,100,32,40,77,66,47,115,41],"value":"Speed (MB/s)"}, {"hash":197921842,"name":"tfrmbenchmark.lblbenchmarksize.caption","sourcebytes":[66,101,110,99,104,109,97,114,107,32,100,97,116,97,32,115,105,122,101,58,32,37,100,32,77,66],"value":"Benchmark data size: %d MB"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fbenchmark.pas�����������������������������������������������������������������0000644�0001750�0000144�00000011276�14743153644�016211� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fBenchmark; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Grids, Contnrs, ButtonPanel, StdCtrls, uFile, uFileSourceOperation, uOSForms, uFileSourceCalcChecksumOperation; type { TfrmBenchmark } TfrmBenchmark = class(TAloneForm) ButtonPanel: TButtonPanel; lblBenchmarkSize: TLabel; stgResult: TStringGrid; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); end; { TBenchmarkResult } TBenchmarkResult = class Hash: String; Time: QWord; Speed: Double; end; { TBenchmarkOperation } TBenchmarkOperation = class(TFileSourceCalcChecksumOperation) private FFiles: TFiles; FBuffer: TBytes; FOwner: TCustomForm; FSpeedResult: TObjectList; FStatistics: TFileSourceCalcChecksumOperationStatistics; protected procedure MainExecute; override; procedure OnBenchmarkStateChanged(Operation: TFileSourceOperation; AState: TFileSourceOperationState); public constructor Create(TheOwner: TCustomForm); reintroduce; destructor Destroy; override; end; implementation uses ISAAC, DCOSUtils, uFileSystemFileSource, uHash, uGlobs, uDCUtils; const cSize = 1024 * 1024 * 256; function CompareFunc(Item1, Item2: Pointer): Integer; begin if TBenchmarkResult(Item1).Time = TBenchmarkResult(Item2).Time then Result:= 0 else if TBenchmarkResult(Item1).Time < TBenchmarkResult(Item2).Time then Result:= -1 else begin Result:= +1; end; end; { TfrmBenchmark } procedure TfrmBenchmark.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; end; { TBenchmarkOperation } procedure TBenchmarkOperation.MainExecute; var ASize: Int64; AHash: String; ARandom: isaac_ctx; ABufferSize: Integer; Context: THashContext; Index: THashAlgorithm; AStart, AFinish: QWord; AResult: TBenchmarkResult; begin ABufferSize := gHashBlockSize; SetLength(FBuffer, ABufferSize); isaac_init(ARandom, Int32(GetTickCount64)); isaac_read(ARandom, @FBuffer[0], ABufferSize); ASize:= (cSize div ABufferSize) * ABufferSize; FStatistics.TotalFiles := (Length(HashName) - 1); FStatistics.TotalBytes:= ASize * FStatistics.TotalFiles; for Index := Low(THashAlgorithm) to Pred(High(THashAlgorithm)) do begin if Index = HASH_SFV then Continue; with FStatistics do begin CurrentFile := HashName[Index]; CurrentFileTotalBytes := ASize; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics); AStart:= GetTickCountEx; HashInit(Context, Index); while FStatistics.CurrentFileDoneBytes < ASize do begin HashUpdate(Context, FBuffer[0], ABufferSize); with FStatistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + ABufferSize; DoneBytes := DoneBytes + ABufferSize; UpdateStatistics(FStatistics); end; CheckOperationState; // check pause and stop end; HashFinal(Context, AHash); AFinish:= GetTickCountEx - AStart; Inc(FStatistics.DoneFiles); UpdateStatistics(FStatistics); AResult:= TBenchmarkResult.Create; AResult.Hash:= HashName[Index]; AResult.Time:= AFinish; AResult.Speed:= (cSize / (1024 * 1024)) / (AFinish / 1000); FSpeedResult.Add(AResult); end; FSpeedResult.Sort(@CompareFunc); end; procedure TBenchmarkOperation.OnBenchmarkStateChanged( Operation: TFileSourceOperation; AState: TFileSourceOperationState); var Index: Integer; AValue: TBenchmarkResult; begin if (AState = fsosStopped) and (Operation.Result = fsorFinished) then begin with TfrmBenchmark.Create(FOwner) do begin stgResult.BeginUpdate; stgResult.RowCount:= FSpeedResult.Count + 1; try for Index:= 0 to FSpeedResult.Count - 1 do begin AValue:= TBenchmarkResult(FSpeedResult[Index]); stgResult.Cells[0, Index + 1]:= AValue.Hash; stgResult.Cells[1, Index + 1]:= IntToStr(AValue.Time); stgResult.Cells[2, Index + 1]:= FloatToStrF(AValue.Speed, ffFixed, 15, 3); end; FreeAndNil(FSpeedResult); lblBenchmarkSize.Caption:= Format(lblBenchmarkSize.Caption, [cSize div (1024 * 1024)]); finally stgResult.EndUpdate(); end; Show; end; end; end; constructor TBenchmarkOperation.Create(TheOwner: TCustomForm); begin FOwner:= TheOwner; inherited Create(TFileSystemFileSource.GetFileSource, FFiles, EmptyStr, EmptyStr); AddStateChangedListener([fsosStopped], @OnBenchmarkStateChanged); FSpeedResult:= TObjectList.Create; Mode:= checksum_calc; end; destructor TBenchmarkOperation.Destroy; begin FSpeedResult.Free; inherited Destroy; end; {$R *.lfm} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fbuttonform.lfm����������������������������������������������������������������0000644�0001750�0000144�00000013216�14743153644�016445� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmButtonForm: TfrmButtonForm Left = 634 Height = 402 Top = 161 Width = 609 ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 402 ClientWidth = 609 LCLVersion = '1.6.0.4' object pnlContent: TPanel Left = 8 Height = 348 Top = 8 Width = 593 Align = alClient AutoSize = True BevelOuter = bvNone TabOrder = 0 end object pnlButtons: TPanel AnchorSideTop.Side = asrBottom Left = 8 Height = 34 Top = 360 Width = 593 Align = alBottom Anchors = [akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 BevelOuter = bvNone ClientHeight = 34 ClientWidth = 593 TabOrder = 1 object btnAddToQueue: TBitBtn Left = 0 Height = 34 Top = 0 Width = 127 Align = alLeft AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'A&dd To Queue' Constraints.MinHeight = 34 Constraints.MinWidth = 88 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 000004733AFF21824FFF638272FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004733AFF7ACFA4FF2C8C5AFF3D7659FFAEAEAEFF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004733AFF82D8ACFF76D6A6FF3C9D6AFF27744CFFACAEADFF000000000000 0000000000000000000000000000000000000000000000000000000000000000 000009773FFF83DBAEFF1FC671FF72DEA7FF4BB27FFF177445FFA8ADAAFF0000 0000000000000000000000000000000000000000000000000000000000000000 000004733AFF83DCAFFF11C369FF1ACC73FF69DFA3FF5AC28DFF137643FF9EA7 A3FF000000000000000000000000000000000000000000000000000000000000 000004733AFFA9DCC1FF10BD65FF11C167FF13C269FF59D395FF67C998FF167C 47FF889C92FF0000000000000000000000000000000000000000000000000000 000004733AFFA9DCC1FF0DB35EFF0EB660FF0EB660FF0DB45FFF47C484FF70CA 9CFF1D824DFF678C79FF00000000000000000000000000000000000000000000 000004733AFFA9DCC1FF0CAA58FF12AE5EFF15AF60FF16AD61FF13AA5DFF3AB6 77FF75C79DFF288957FF4E8367FF000000000000000000000000000000000000 000004733AFFA9DCC1FF2EAD6BFF2BAD6AFF27AB68FF22A964FF1CA55FFF41B2 78FF78C69FFF298858FF678C79FF000000000000000000000000000000000000 000004733AFFA9DCC1FF36AD70FF32AC6DFF2DAA6AFF28A866FF58BC89FF78C5 9DFF1F804EFF839A8EFF00000000000000000000000000000000000000000000 000004733AFFA9DCC1FF3EB176FF3AAF73FF36AE70FF6FC598FF71BF97FF187B 49FFA6B0ABFF0000000000000000000000000000000000000000000000000000 000004733AFFA9DCC1FF45B47BFF47B47CFF82CCA6FF67B68CFF177745FFC1C5 C3FF000000000000000000000000000000000000000000000000000000000000 000004733AFFA5DABFFF57BB87FF90D2B0FF5BAB82FF23774CFFD4D5D4FF0000 0000000000000000000000000000000000000000000000000000000000000000 000004733AFFA9DCC1FF9BD5B7FF4C9F73FF3D7D5CFF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004733AFFA4D9BEFF3D9366FF5F8873FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004733AFF2D8859FF859C90FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ModalResult = 1 OnClick = btnAddToQueueClick TabOrder = 0 end object btnCreateSpecialQueue: TBitBtn Left = 127 Height = 34 Top = 0 Width = 23 Align = alLeft BorderSpacing.Right = 12 Glyph.Data = { 72000000424D7200000000000000360000002800000005000000030000000100 2000000000003C00000064000000640000000000000000000000000000000000 0000000000FF000000000000000000000000000000FF000000FF000000FF0000 0000000000FF000000FF000000FF000000FF000000FF } GlyphShowMode = gsmAlways Layout = blGlyphBottom OnClick = btnCreateSpecialQueueClick PopupMenu = pmQueuePopup TabOrder = 1 end object btnCancel: TBitBtn Left = 411 Height = 34 Top = 0 Width = 86 Align = alRight AutoSize = True BorderSpacing.Left = 12 BorderSpacing.Right = 8 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 TabOrder = 2 end object btnOK: TBitBtn Left = 505 Height = 34 Top = 0 Width = 88 Align = alRight AutoSize = True BorderSpacing.InnerBorder = 2 Caption = '&OK' Constraints.MinHeight = 34 Constraints.MinWidth = 88 Default = True Kind = bkOK ModalResult = 1 OnClick = btnOKClick TabOrder = 3 end end object pmQueuePopup: TPopupMenu Left = 280 Top = 280 object mnuNewQueue: TMenuItem Caption = 'New queue' OnClick = mnuNewQueueClick end object mnuQueue1: TMenuItem Caption = 'Queue 1' OnClick = mnuQueueNumberClick end object mnuQueue2: TMenuItem Caption = 'Queue 2' OnClick = mnuQueueNumberClick end object mnuQueue3: TMenuItem Caption = 'Queue 3' OnClick = mnuQueueNumberClick end object mnuQueue4: TMenuItem Caption = 'Queue 4' OnClick = mnuQueueNumberClick end object mnuQueue5: TMenuItem Caption = 'Queue 5' OnClick = mnuQueueNumberClick end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fbuttonform.pas����������������������������������������������������������������0000644�0001750�0000144�00000011076�14743153644�016454� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fButtonForm; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, Buttons, Menus, uOperationsManager, uFileSource, uFormCommands; type { TfrmButtonForm } TfrmButtonForm = class(TForm, IFormCommands) btnAddToQueue: TBitBtn; btnCancel: TBitBtn; btnCreateSpecialQueue: TBitBtn; btnOK: TBitBtn; mnuNewQueue: TMenuItem; mnuQueue1: TMenuItem; mnuQueue2: TMenuItem; mnuQueue3: TMenuItem; mnuQueue4: TMenuItem; mnuQueue5: TMenuItem; pmQueuePopup: TPopupMenu; pnlContent: TPanel; pnlButtons: TPanel; procedure btnAddToQueueClick(Sender: TObject); procedure btnCreateSpecialQueueClick(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure mnuNewQueueClick(Sender: TObject); procedure mnuQueueNumberClick(Sender: TObject); private FCommands: TFormCommands; function GetQueueIdentifier: TOperationsManagerQueueIdentifier; property {%H-}Commands: TFormCommands read FCommands implements IFormCommands; protected procedure DoAutoSize; override; public constructor Create(TheOwner: TComponent); override; constructor Create(TheOwner: TComponent; FileSource: IFileSource); reintroduce; property QueueIdentifier: TOperationsManagerQueueIdentifier read GetQueueIdentifier; published procedure cm_AddToQueue(const Params: array of String); end; var frmButtonForm: TfrmButtonForm; implementation uses LCLStrConsts, DCStrUtils, uFileSourceProperty, uHotkeyManager, uGlobs; {$R *.lfm} const HotkeysCategory = 'Confirmation'; var FQueueIdentifier: TOperationsManagerQueueIdentifier = SingleQueueId; { TfrmButtonForm } procedure TfrmButtonForm.btnCreateSpecialQueueClick(Sender: TObject); begin btnCreateSpecialQueue.PopupMenu.PopUp; end; procedure TfrmButtonForm.btnAddToQueueClick(Sender: TObject); begin ModalResult := btnAddToQueue.ModalResult; end; procedure TfrmButtonForm.btnOKClick(Sender: TObject); begin if FQueueIdentifier <> ModalQueueId then FQueueIdentifier := FreeOperationsQueueId; end; procedure TfrmButtonForm.mnuNewQueueClick(Sender: TObject); begin FQueueIdentifier := OperationsManager.GetNewQueueIdentifier; ModalResult := btnAddToQueue.ModalResult; end; procedure TfrmButtonForm.mnuQueueNumberClick(Sender: TObject); var NewQueueNumber: TOperationsManagerQueueIdentifier; begin if TryStrToInt(Copy((Sender as TMenuItem).Name, 9, 1), NewQueueNumber) then begin FQueueIdentifier := NewQueueNumber; ModalResult := btnAddToQueue.ModalResult; end; end; function TfrmButtonForm.GetQueueIdentifier: TOperationsManagerQueueIdentifier; begin Result:= FQueueIdentifier; end; procedure TfrmButtonForm.DoAutoSize; begin inherited DoAutoSize; if (btnCancel.Left - btnCreateSpecialQueue.BoundsRect.Right) < 16 then begin Constraints.MinWidth:= Width + (16 - (btnCancel.Left - btnCreateSpecialQueue.BoundsRect.Right)); end; end; constructor TfrmButtonForm.Create(TheOwner: TComponent); begin Create(TheOwner, nil); end; constructor TfrmButtonForm.Create(TheOwner: TComponent; FileSource: IFileSource); var HMForm: THMForm; Hotkey: THotkey; begin FCommands := TFormCommands.Create(Self); inherited Create(TheOwner); if FQueueIdentifier <= FreeOperationsQueueId then FQueueIdentifier:= SingleQueueId; btnAddToQueue.Caption:= btnAddToQueue.Caption + ' #' + IntToStr(FQueueIdentifier); if Assigned(FileSource) and (fspListOnMainThread in FileSource.Properties) then begin btnAddToQueue.Visible:= False; FQueueIdentifier:= ModalQueueId; btnCreateSpecialQueue.Visible:= btnAddToQueue.Visible; end; HMForm := HotMan.Register(Self, HotkeysCategory); Hotkey := HMForm.Hotkeys.FindByCommand('cm_AddToQueue'); if Assigned(Hotkey) then btnAddToQueue.Caption := btnAddToQueue.Caption + ' (' + ShortcutsToText(Hotkey.Shortcuts) + ')'; end; procedure TfrmButtonForm.cm_AddToQueue(const Params: array of String); var Value: Integer; sQueueId: String; begin if FQueueIdentifier = ModalQueueId then Exit; if GetParamValue(Params, 'queueid', sQueueId) and TryStrToInt(sQueueId, Value) then begin if Value < 0 then mnuNewQueue.Click else FQueueIdentifier := Value end else FQueueIdentifier := SingleQueueId; ModalResult := btnAddToQueue.ModalResult; end; initialization TFormCommands.RegisterCommandsForm(TfrmButtonForm, HotkeysCategory, @rsMtConfirmation); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchecksumcalc.lfm��������������������������������������������������������������0000644�0001750�0000144�00000007353�14743153644�016700� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmCheckSumCalc: TfrmCheckSumCalc Left = 321 Height = 400 Top = 59 Width = 400 AutoSize = True BorderIcons = [biSystemMenu] Caption = 'Calculate checksum...' ClientHeight = 400 ClientWidth = 400 Constraints.MinHeight = 400 Constraints.MinWidth = 400 OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter SessionProperties = 'cbOpenAfterJobIsComplete.Checked;cbSeparateFile.Checked;lbHashAlgorithm.ItemIndex' inherited pnlContent: TPanel Height = 346 Width = 384 ClientHeight = 346 ClientWidth = 384 ParentColor = True object lblSaveTo: TLabel[0] Left = 0 Height = 15 Top = 0 Width = 130 Caption = '&Save checksum file(s) to:' FocusControl = edtSaveTo ParentColor = False end object edtSaveTo: TEdit[1] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = lblSaveTo AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom Left = 0 Height = 23 Top = 21 Width = 384 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 0 end object cbSeparateFile: TCheckBox[2] AnchorSideLeft.Control = edtSaveTo AnchorSideTop.Control = edtSaveTo AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 50 Width = 242 BorderSpacing.Top = 6 Caption = 'C&reate separate checksum file for each file' OnChange = cbSeparateFileChange TabOrder = 1 end object lbHashAlgorithm: TListBox[3] AnchorSideLeft.Control = edtSaveTo AnchorSideTop.Control = rbWindows AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtSaveTo AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 0 Height = 219 Top = 125 Width = 384 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 6 ItemHeight = 0 OnSelectionChange = lbHashAlgorithmSelectionChange ScrollWidth = 150 TabOrder = 5 end object cbOpenAfterJobIsComplete: TCheckBox[4] AnchorSideLeft.Control = edtSaveTo AnchorSideTop.Control = cbSeparateFile AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 75 Width = 243 BorderSpacing.Top = 6 Caption = 'Open checksum file after job is completed' OnChange = cbSeparateFileChange TabOrder = 2 end object lblFileFormat: TLabel[5] AnchorSideLeft.Control = cbOpenAfterJobIsComplete AnchorSideTop.Control = rbWindows AnchorSideTop.Side = asrCenter Left = 0 Height = 15 Top = 102 Width = 57 BorderSpacing.Top = 6 Caption = 'File &format' FocusControl = rbWindows ParentColor = False end object rbWindows: TRadioButton[6] AnchorSideLeft.Control = lblFileFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbOpenAfterJobIsComplete AnchorSideTop.Side = asrBottom Left = 69 Height = 19 Top = 100 Width = 69 BorderSpacing.Left = 12 BorderSpacing.Top = 6 Caption = 'Windows' TabOrder = 3 end object rbUnix: TRadioButton[7] AnchorSideLeft.Control = rbWindows AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbWindows AnchorSideTop.Side = asrCenter Left = 144 Height = 19 Top = 100 Width = 44 BorderSpacing.Left = 6 Caption = 'Unix' TabOrder = 4 end end inherited pnlButtons: TPanel Top = 358 Width = 384 ClientWidth = 384 inherited btnCancel: TBitBtn Left = 202 end inherited btnOK: TBitBtn Left = 296 end end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchecksumcalc.lrj��������������������������������������������������������������0000644�0001750�0000144�00000002571�14743153644�016706� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":124685262,"name":"tfrmchecksumcalc.caption","sourcebytes":[67,97,108,99,117,108,97,116,101,32,99,104,101,99,107,115,117,109,46,46,46],"value":"Calculate checksum..."}, {"hash":117557194,"name":"tfrmchecksumcalc.lblsaveto.caption","sourcebytes":[38,83,97,118,101,32,99,104,101,99,107,115,117,109,32,102,105,108,101,40,115,41,32,116,111,58],"value":"&Save checksum file(s) to:"}, {"hash":222079109,"name":"tfrmchecksumcalc.cbseparatefile.caption","sourcebytes":[67,38,114,101,97,116,101,32,115,101,112,97,114,97,116,101,32,99,104,101,99,107,115,117,109,32,102,105,108,101,32,102,111,114,32,101,97,99,104,32,102,105,108,101],"value":"C&reate separate checksum file for each file"}, {"hash":20936404,"name":"tfrmchecksumcalc.cbopenafterjobiscomplete.caption","sourcebytes":[79,112,101,110,32,99,104,101,99,107,115,117,109,32,102,105,108,101,32,97,102,116,101,114,32,106,111,98,32,105,115,32,99,111,109,112,108,101,116,101,100],"value":"Open checksum file after job is completed"}, {"hash":136754340,"name":"tfrmchecksumcalc.lblfileformat.caption","sourcebytes":[70,105,108,101,32,38,102,111,114,109,97,116],"value":"File &format"}, {"hash":235189939,"name":"tfrmchecksumcalc.rbwindows.caption","sourcebytes":[87,105,110,100,111,119,115],"value":"Windows"}, {"hash":378120,"name":"tfrmchecksumcalc.rbunix.caption","sourcebytes":[85,110,105,120],"value":"Unix"} ]} ���������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchecksumcalc.pas��������������������������������������������������������������0000644�0001750�0000144�00000013201�14743153644�016672� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Calculate checksum dialog Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fCheckSumCalc; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, StdCtrls, Buttons, fButtonForm, uHash, uOperationsManager; type { TfrmCheckSumCalc } TfrmCheckSumCalc = class(TfrmButtonForm) cbSeparateFile: TCheckBox; cbOpenAfterJobIsComplete: TCheckBox; edtSaveTo: TEdit; lblFileFormat: TLabel; lblSaveTo: TLabel; lbHashAlgorithm: TListBox; rbWindows: TRadioButton; rbUnix: TRadioButton; procedure cbSeparateFileChange(Sender: TObject); procedure edtSaveToChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure lbHashAlgorithmSelectionChange(Sender: TObject; User: boolean); private FFileName: String; FAlgorithm: THashAlgorithm; public { public declarations } end; function ShowCalcCheckSum(var sFileName: String; out SeparateFile: Boolean; out HashAlgorithm: THashAlgorithm; out OpenFileAfterJobCompleted: Boolean; out TextLineBreakStyle: TTextLineBreakStyle; out QueueId: TOperationsManagerQueueIdentifier): Boolean; function ShowCalcVerifyCheckSum(out Hash: String; out HashAlgorithm: THashAlgorithm; out QueueId: TOperationsManagerQueueIdentifier): Boolean; implementation {$R *.lfm} uses uGlobs, uLng; function ShowCalcCheckSum(var sFileName: String; out SeparateFile: Boolean; out HashAlgorithm: THashAlgorithm; out OpenFileAfterJobCompleted: Boolean; out TextLineBreakStyle: TTextLineBreakStyle; out QueueId: TOperationsManagerQueueIdentifier): Boolean; const TextLineBreak: array[Boolean] of TTextLineBreakStyle = (tlbsLF, tlbsCRLF); begin with TfrmCheckSumCalc.Create(Application) do try FFileName:= sFileName; if (DefaultTextLineBreakStyle = tlbsCRLF) then rbWindows.Checked:= True else begin rbUnix.Checked:= True; end; Result:= (ShowModal = mrOK); if Result then begin sFileName:= edtSaveTo.Text; SeparateFile:= cbSeparateFile.Checked; TextLineBreakStyle:= TextLineBreak[rbWindows.Checked]; OpenFileAfterJobCompleted:=(cbOpenAfterJobIsComplete.Checked AND cbOpenAfterJobIsComplete.Enabled); HashAlgorithm:= FAlgorithm; QueueId:= QueueIdentifier end; finally Free; end; end; function ShowCalcVerifyCheckSum(out Hash: String; out HashAlgorithm: THashAlgorithm; out QueueId: TOperationsManagerQueueIdentifier): Boolean; begin with TfrmCheckSumCalc.Create(Application) do try OnShow:= nil; edtSaveTo.Text:= EmptyStr; SessionProperties:= EmptyStr; Caption:= rsCheckSumVerifyTitle; cbSeparateFile.Visible:= False; cbOpenAfterJobIsComplete.Visible:= False; lbHashAlgorithm.OnSelectionChange:= nil; edtSaveTo.OnChange:= @edtSaveToChange; lblSaveTo.Caption:= rsCheckSumVerifyText; Result:= (ShowModal = mrOK); if Result then begin Hash:= TrimHash(edtSaveTo.Text); Result:= Length(Hash) > 0; QueueId:= QueueIdentifier; HashAlgorithm:= THashAlgorithm(lbHashAlgorithm.ItemIndex); end; finally Free; end; end; { TfrmCheckSumCalc } procedure TfrmCheckSumCalc.cbSeparateFileChange(Sender: TObject); begin if cbSeparateFile.Checked then edtSaveTo.Text:= ExtractFilePath(edtSaveTo.Text) + '*.' + HashFileExt[FAlgorithm] else edtSaveTo.Text:= ExtractFilePath(edtSaveTo.Text) + ExtractFileName(FFileName) + '.' + HashFileExt[FAlgorithm]; cbOpenAfterJobIsComplete.Enabled:=not cbSeparateFile.Checked; end; procedure TfrmCheckSumCalc.edtSaveToChange(Sender: TObject); begin case Length(TrimHash(edtSaveTo.Text)) of 8: lbHashAlgorithm.ItemIndex:= Integer(HASH_SFV); 32: lbHashAlgorithm.ItemIndex:= Integer(HASH_MD5); 40: lbHashAlgorithm.ItemIndex:= Integer(HASH_SHA1); 64: lbHashAlgorithm.ItemIndex:= Integer(HASH_SHA256); 96: lbHashAlgorithm.ItemIndex:= Integer(HASH_SHA384); 128: lbHashAlgorithm.ItemIndex:= Integer(HASH_SHA512); end; end; procedure TfrmCheckSumCalc.FormCreate(Sender: TObject); var I: THashAlgorithm; begin for I:= Low(HashName) to High(HashName) do begin lbHashAlgorithm.Items.Add(UpperCase(HashName[I])); end; InitPropStorage(Self); // Must be *after* lbHashAlgorithm.Items has been loaded so index is restored correctly. if (lbHashAlgorithm.ItemIndex=-1) AND (lbHashAlgorithm.Count>0) then lbHashAlgorithm.ItemIndex:= 0; end; procedure TfrmCheckSumCalc.FormShow(Sender: TObject); begin edtSaveTo.Text:= FFileName + ExtensionSeparator; lbHashAlgorithmSelectionChange(lbHashAlgorithm,FALSE); end; procedure TfrmCheckSumCalc.lbHashAlgorithmSelectionChange(Sender: TObject; User: boolean); begin FAlgorithm:= THashAlgorithm(lbHashAlgorithm.ItemIndex); edtSaveTo.Text:= ChangeFileExt(edtSaveTo.Text, '.' + HashFileExt[FAlgorithm]); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchecksumverify.lfm������������������������������������������������������������0000644�0001750�0000144�00000020407�14743153644�017275� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmCheckSumVerify: TfrmCheckSumVerify Left = 290 Height = 300 Top = 175 Width = 400 Caption = 'Verify checksum...' ClientHeight = 300 ClientWidth = 400 Constraints.MinHeight = 200 Constraints.MinWidth = 300 KeyPreview = True OnClose = FormClose OnKeyDown = FormKeyDown Position = poScreenCenter ShowInTaskBar = stAlways LCLVersion = '1.6.0.4' inline seCheckSumVerify: TSynEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnClose Left = 10 Height = 240 Top = 10 Width = 380 BorderSpacing.Left = 10 BorderSpacing.Top = 10 BorderSpacing.Right = 10 BorderSpacing.Bottom = 10 Anchors = [akTop, akLeft, akRight, akBottom] Color = clWindow Font.Color = clWindowText ParentColor = False ParentFont = False TabOrder = 0 Gutter.Visible = False Gutter.Width = 0 Gutter.MouseActions = <> RightGutter.Width = 0 RightGutter.MouseActions = <> Keystrokes = < item Command = ecUp ShortCut = 38 end item Command = ecSelUp ShortCut = 8230 end item Command = ecScrollUp ShortCut = 16422 end item Command = ecDown ShortCut = 40 end item Command = ecSelDown ShortCut = 8232 end item Command = ecScrollDown ShortCut = 16424 end item Command = ecLeft ShortCut = 37 end item Command = ecSelLeft ShortCut = 8229 end item Command = ecWordLeft ShortCut = 16421 end item Command = ecSelWordLeft ShortCut = 24613 end item Command = ecRight ShortCut = 39 end item Command = ecSelRight ShortCut = 8231 end item Command = ecWordRight ShortCut = 16423 end item Command = ecSelWordRight ShortCut = 24615 end item Command = ecPageDown ShortCut = 34 end item Command = ecSelPageDown ShortCut = 8226 end item Command = ecPageBottom ShortCut = 16418 end item Command = ecSelPageBottom ShortCut = 24610 end item Command = ecPageUp ShortCut = 33 end item Command = ecSelPageUp ShortCut = 8225 end item Command = ecPageTop ShortCut = 16417 end item Command = ecSelPageTop ShortCut = 24609 end item Command = ecLineStart ShortCut = 36 end item Command = ecSelLineStart ShortCut = 8228 end item Command = ecEditorTop ShortCut = 16420 end item Command = ecSelEditorTop ShortCut = 24612 end item Command = ecLineEnd ShortCut = 35 end item Command = ecSelLineEnd ShortCut = 8227 end item Command = ecEditorBottom ShortCut = 16419 end item Command = ecSelEditorBottom ShortCut = 24611 end item Command = ecToggleMode ShortCut = 45 end item Command = ecCopy ShortCut = 16429 end item Command = ecPaste ShortCut = 8237 end item Command = ecDeleteChar ShortCut = 46 end item Command = ecCut ShortCut = 8238 end item Command = ecDeleteLastChar ShortCut = 8 end item Command = ecDeleteLastChar ShortCut = 8200 end item Command = ecDeleteLastWord ShortCut = 16392 end item Command = ecUndo ShortCut = 32776 end item Command = ecRedo ShortCut = 40968 end item Command = ecLineBreak ShortCut = 13 end item Command = ecSelectAll ShortCut = 16449 end item Command = ecCopy ShortCut = 16451 end item Command = ecBlockIndent ShortCut = 24649 end item Command = ecLineBreak ShortCut = 16461 end item Command = ecInsertLine ShortCut = 16462 end item Command = ecDeleteWord ShortCut = 16468 end item Command = ecBlockUnindent ShortCut = 24661 end item Command = ecPaste ShortCut = 16470 end item Command = ecCut ShortCut = 16472 end item Command = ecDeleteLine ShortCut = 16473 end item Command = ecDeleteEOL ShortCut = 24665 end item Command = ecUndo ShortCut = 16474 end item Command = ecRedo ShortCut = 24666 end item Command = EcFoldCurrent ShortCut = 41005 end item Command = EcUnFoldCurrent ShortCut = 41003 end item Command = EcToggleMarkupWord ShortCut = 32845 end item Command = ecNormalSelect ShortCut = 24654 end item Command = ecColumnSelect ShortCut = 24643 end item Command = ecLineSelect ShortCut = 24652 end item Command = ecTab ShortCut = 9 end item Command = ecShiftTab ShortCut = 8201 end item Command = ecMatchBracket ShortCut = 24642 end item Command = ecColSelUp ShortCut = 40998 end item Command = ecColSelDown ShortCut = 41000 end item Command = ecColSelLeft ShortCut = 40997 end item Command = ecColSelRight ShortCut = 40999 end item Command = ecColSelPageDown ShortCut = 40994 end item Command = ecColSelPageBottom ShortCut = 57378 end item Command = ecColSelPageUp ShortCut = 40993 end item Command = ecColSelPageTop ShortCut = 57377 end item Command = ecColSelLineStart ShortCut = 40996 end item Command = ecColSelLineEnd ShortCut = 40995 end item Command = ecColSelEditorTop ShortCut = 57380 end item Command = ecColSelEditorBottom ShortCut = 57379 end> MouseActions = <> MouseTextActions = <> MouseSelActions = <> VisibleSpecialChars = [vscSpace, vscTabAtLast] ReadOnly = True ScrollBars = ssAutoBoth SelectedColor.BackPriority = 50 SelectedColor.ForePriority = 50 SelectedColor.FramePriority = 50 SelectedColor.BoldPriority = 50 SelectedColor.ItalicPriority = 50 SelectedColor.UnderlinePriority = 50 SelectedColor.StrikeOutPriority = 50 BracketHighlightStyle = sbhsBoth BracketMatchColor.Background = clNone BracketMatchColor.Foreground = clNone BracketMatchColor.Style = [fsBold] FoldedCodeColor.Background = clNone FoldedCodeColor.Foreground = clGray FoldedCodeColor.FrameColor = clGray MouseLinkColor.Background = clNone MouseLinkColor.Foreground = clBlue LineHighlightColor.Background = clNone LineHighlightColor.Foreground = clNone OnSpecialLineColors = seCheckSumVerifySpecialLineColors inline SynLeftGutterPartList1: TSynGutterPartList end end object btnClose: TBitBtn AnchorSideLeft.Control = seCheckSumVerify AnchorSideLeft.Side = asrCenter AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 150 Height = 30 Top = 260 Width = 100 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 10 Caption = '&Close' Kind = bkClose TabOrder = 1 end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchecksumverify.lrj������������������������������������������������������������0000644�0001750�0000144�00000000474�14743153644�017310� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":202286430,"name":"tfrmchecksumverify.caption","sourcebytes":[86,101,114,105,102,121,32,99,104,101,99,107,115,117,109,46,46,46],"value":"Verify checksum..."}, {"hash":44709525,"name":"tfrmchecksumverify.btnclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchecksumverify.pas������������������������������������������������������������0000644�0001750�0000144�00000012107�14743153644�017300� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Verify checksum dialog Copyright (C) 2009-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fCheckSumVerify; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Buttons, SynEdit, LMessages, uOSForms, Graphics, uFileSourceCalcChecksumOperation, DCBasicTypes, Controls; type { TfrmCheckSumVerify } TfrmCheckSumVerify = class(TAloneForm) btnClose: TBitBtn; seCheckSumVerify: TSynEdit; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure seCheckSumVerifySpecialLineColors(Sender: TObject; Line: integer; var Special: boolean; var FG, BG: TColor); private procedure AddHeader(const aText: String; aCount: Integer; aColor: TColor); procedure ProcessResult(const aResult: TDynamicStringArray; const aText: String; aColor: TColor); protected procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public { public declarations } end; procedure ShowVerifyCheckSum(const VerifyResult: TVerifyChecksumResult); implementation {$R *.lfm} uses uLng, uGlobs, uClassesEx, uLog; procedure ShowVerifyCheckSum(const VerifyResult: TVerifyChecksumResult); var aTotalCount: Integer; begin with TfrmCheckSumVerify.Create(Application) do begin seCheckSumVerify.Lines.BeginUpdate; try seCheckSumVerify.Lines.AddObject(rsCheckSumVerifyGeneral, TObject(PtrInt(clWindowText))); aTotalCount:= Length(VerifyResult.Success) + Length(VerifyResult.ReadError) + Length(VerifyResult.Broken) + Length(VerifyResult.Missing); // Add header information AddHeader(rsCheckSumVerifyTotal, aTotalCount, clWindowText); AddHeader(rsCheckSumVerifySuccess, Length(VerifyResult.Success), Ord(lmtSuccess)); AddHeader(rsCheckSumVerifyMissing, Length(VerifyResult.Missing), Ord(lmtError)); AddHeader(rsCheckSumVerifyBroken, Length(VerifyResult.Broken), Ord(lmtError)); AddHeader(rsCheckSumVerifyReadError, Length(VerifyResult.ReadError), Ord(lmtError)); // Add broken files ProcessResult(VerifyResult.Broken, rsCheckSumVerifyBroken, Ord(lmtError)); // Add read error files ProcessResult(VerifyResult.ReadError, rsCheckSumVerifyReadError, Ord(lmtError)); // Add missing files ProcessResult(VerifyResult.Missing, rsCheckSumVerifyMissing, Ord(lmtError)); // Add good files ProcessResult(VerifyResult.Success, rsCheckSumVerifySuccess, Ord(lmtSuccess)); finally seCheckSumVerify.Lines.EndUpdate; end; Show; end; end; { TfrmCheckSumVerify } procedure TfrmCheckSumVerify.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; end; procedure TfrmCheckSumVerify.FormCreate(Sender: TObject); begin seCheckSumVerify.FixDefaultKeystrokes; end; procedure TfrmCheckSumVerify.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = 27 then Close; end; procedure TfrmCheckSumVerify.seCheckSumVerifySpecialLineColors(Sender: TObject; Line: integer; var Special: boolean; var FG, BG: TColor); var AColor: IntPtr; begin Special:= True; AColor:= IntPtr(seCheckSumVerify.Lines.Objects[Line - 1]); with gColors.Log^ do begin case AColor of Ord(lmtError): FG:= ErrorColor; Ord(lmtSuccess): FG:= SuccessColor; else FG:= TColor(AColor); end; end; end; procedure TfrmCheckSumVerify.AddHeader(const aText: String; aCount: Integer; aColor: TColor); begin if aCount = 0 then aColor:= clWindowText; seCheckSumVerify.Lines.AddObject(#32 + aText + #32 + IntToStr(aCount), TObject(PtrInt(aColor))); end; procedure TfrmCheckSumVerify.ProcessResult(const aResult: TDynamicStringArray; const aText: String; aColor: TColor); var I: Integer; begin if Length(aResult) > 0 then begin seCheckSumVerify.Lines.Add(EmptyStr); seCheckSumVerify.Lines.AddObject(aText, TObject(PtrInt(aColor))); for I:= Low(aResult) to High(aResult) do begin seCheckSumVerify.Lines.AddObject(#32 + aResult[I], TObject(PtrInt(aColor))); end; end; end; procedure TfrmCheckSumVerify.CMThemeChanged(var Message: TLMessage); begin seCheckSumVerify.Repaint; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchooseencoding.lfm������������������������������������������������������������0000644�0001750�0000144�00000002164�14743153644�017235� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmChooseEncoding: TfrmChooseEncoding Left = 522 Height = 240 Top = 145 Width = 320 BorderStyle = bsToolWindow Caption = 'Encoding' ClientHeight = 240 ClientWidth = 320 OnCreate = FormCreate Position = poOwnerFormCenter LCLVersion = '2.2.5.0' object ButtonPanel: TButtonPanel Left = 6 Height = 34 Top = 200 Width = 308 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 0 ShowButtons = [pbOK, pbCancel] end object ScrollBox: TScrollBox Left = 0 Height = 194 Top = 0 Width = 320 HorzScrollBar.Page = 1 VertScrollBar.Page = 1 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 TabOrder = 1 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchooseencoding.lrj������������������������������������������������������������0000644�0001750�0000144�00000000226�14743153644�017243� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":77966471,"name":"tfrmchooseencoding.caption","sourcebytes":[69,110,99,111,100,105,110,103],"value":"Encoding"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fchooseencoding.pas������������������������������������������������������������0000644�0001750�0000144�00000003451�14743153644�017242� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fChooseEncoding; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ButtonPanel, StdCtrls; type { TfrmChooseEncoding } TfrmChooseEncoding = class(TForm) ButtonPanel: TButtonPanel; ScrollBox: TScrollBox; procedure FormCreate(Sender: TObject); procedure CheckBoxChange(Sender: TObject); private FList: TStrings; public constructor Create(TheOwner: TComponent; AList: TStrings); reintroduce; destructor Destroy; override; end; function ChooseEncoding(TheOwner: TComponent; AList: TStrings): Boolean; implementation uses uConvEncoding; function ChooseEncoding(TheOwner: TComponent; AList: TStrings): Boolean; begin with TfrmChooseEncoding.Create(TheOwner, AList) do try Result:= (ShowModal = mrOK); if Result then AList.Assign(FList); finally Free; end; end; {$R *.lfm} { TfrmChooseEncoding } procedure TfrmChooseEncoding.CheckBoxChange(Sender: TObject); begin with TCheckBox(Sender) do begin FList.Objects[Tag]:= TObject(PtrInt(Checked)); end; end; constructor TfrmChooseEncoding.Create(TheOwner: TComponent; AList: TStrings); begin inherited Create(TheOwner); FList:= TStringList.Create; FList.Assign(AList); end; destructor TfrmChooseEncoding.Destroy; begin inherited Destroy; FList.Free; end; procedure TfrmChooseEncoding.FormCreate(Sender: TObject); var Index: Integer; CheckBox: TCheckBox; begin for Index:= 0 to FList.Count - 1 do begin CheckBox:= TCheckBox.Create(Self); CheckBox.Parent:= ScrollBox; CheckBox.Caption:= FList[Index]; CheckBox.Tag:= Index; CheckBox.OnChange:= @CheckBoxChange; CheckBox.Checked:= Boolean(PtrInt(FList.Objects[Index])); end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fconfirmcommandline.lfm��������������������������������������������������������0000644�0001750�0000144�00000006213�14743153644�020111� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object TfrmConfirmCommandLine: TTfrmConfirmCommandLine Left = 403 Height = 205 Top = 360 Width = 500 ActiveControl = btnOK ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 205 ClientWidth = 500 OnCreate = FormCreate Position = poScreenCenter SessionProperties = 'Width' LCLVersion = '1.2.6.0' object btnCancel: TBitBtn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 392 Height = 32 Top = 165 Width = 100 Anchors = [akRight, akBottom] BorderSpacing.Top = 12 Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 TabOrder = 2 end object btnOK: TBitBtn AnchorSideTop.Control = btnCancel AnchorSideRight.Control = btnCancel AnchorSideBottom.Side = asrBottom Left = 286 Height = 32 Top = 165 Width = 100 Anchors = [akTop, akRight] BorderSpacing.Right = 6 Caption = '&OK' Default = True Kind = bkOK ModalResult = 1 TabOrder = 1 end object lbleCommandLine: TLabeledEdit AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 23 Top = 30 Width = 484 Anchors = [akTop, akLeft, akRight] EditLabel.AnchorSideLeft.Control = lbleCommandLine EditLabel.AnchorSideRight.Control = lbleCommandLine EditLabel.AnchorSideRight.Side = asrBottom EditLabel.AnchorSideBottom.Control = lbleCommandLine EditLabel.Left = 8 EditLabel.Height = 15 EditLabel.Top = 12 EditLabel.Width = 484 EditLabel.Caption = 'Command line:' EditLabel.ParentColor = False TabOrder = 0 end object lbleParameters: TLabeledEdit AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 23 Top = 80 Width = 484 Anchors = [akTop, akLeft, akRight] EditLabel.AnchorSideLeft.Control = lbleParameters EditLabel.AnchorSideRight.Control = lbleParameters EditLabel.AnchorSideRight.Side = asrBottom EditLabel.AnchorSideBottom.Control = lbleParameters EditLabel.Left = 8 EditLabel.Height = 15 EditLabel.Top = 62 EditLabel.Width = 484 EditLabel.Caption = 'Parameters:' EditLabel.ParentColor = False TabOrder = 3 end object lbleStartPath: TLabeledEdit AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 23 Top = 130 Width = 484 Anchors = [akTop, akLeft, akRight] EditLabel.AnchorSideLeft.Control = lbleStartPath EditLabel.AnchorSideRight.Control = lbleStartPath EditLabel.AnchorSideRight.Side = asrBottom EditLabel.AnchorSideBottom.Control = lbleStartPath EditLabel.Left = 8 EditLabel.Height = 15 EditLabel.Top = 112 EditLabel.Width = 484 EditLabel.Caption = 'Start path:' EditLabel.ParentColor = False TabOrder = 4 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fconfirmcommandline.lrj��������������������������������������������������������0000644�0001750�0000144�00000001375�14743153644�020126� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":177752476,"name":"ttfrmconfirmcommandline.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":11067,"name":"ttfrmconfirmcommandline.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":202824842,"name":"ttfrmconfirmcommandline.lblecommandline.editlabel.caption","sourcebytes":[67,111,109,109,97,110,100,32,108,105,110,101,58],"value":"Command line:"}, {"hash":60572138,"name":"ttfrmconfirmcommandline.lbleparameters.editlabel.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115,58],"value":"Parameters:"}, {"hash":103555626,"name":"ttfrmconfirmcommandline.lblestartpath.editlabel.caption","sourcebytes":[83,116,97,114,116,32,112,97,116,104,58],"value":"Start path:"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fconfirmcommandline.pas��������������������������������������������������������0000644�0001750�0000144�00000004614�14743153644�020121� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Window to confirm the execution of command line and its parameters Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) 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 } unit fConfirmCommandLine; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons; type { TTfrmConfirmCommandLine } TTfrmConfirmCommandLine = class(TForm) btnCancel: TBitBtn; btnOK: TBitBtn; lbleCommandLine: TLabeledEdit; lbleStartPath: TLabeledEdit; lbleParameters: TLabeledEdit; procedure FormCreate(Sender: TObject); private { private declarations } public { public declarations } end; var TfrmConfirmCommandLine: TTfrmConfirmCommandLine; function ConfirmCommandLine(var sCommandLine: string; var sParameter:string; var sStartPath:string):boolean; implementation {$R *.lfm} uses uLng,uGlobs; function ConfirmCommandLine(var sCommandLine: string; var sParameter:string; var sStartPath:string):boolean; begin with TTfrmConfirmCommandLine.Create(Application) do try Caption:= rsConfirmExecution; lbleCommandLine.Text:=sCommandLine; lbleParameters.Text:=sParameter; lbleStartPath.Text:=sStartPath; Result:= (ShowModal = mrOK); if Result then begin sCommandLine:=lbleCommandLine.Text; sParameter:=lbleParameters.Text; sStartPath:=lbleStartPath.Text; end; finally Free; end; end; { TTfrmConfirmCommandLine } procedure TTfrmConfirmCommandLine.FormCreate(Sender: TObject); begin InitPropStorage(Self); end; end. ��������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fconnectionmanager.lfm���������������������������������������������������������0000644�0001750�0000144�00000027453�14743153644�017750� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmConnectionManager: TfrmConnectionManager Left = 321 Height = 366 Top = 149 Width = 431 Caption = 'Connection manager' ClientHeight = 366 ClientWidth = 431 OnDestroy = FormDestroy Position = poScreenCenter LCLVersion = '1.1' object gbConnectTo: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = btnConnect AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 360 Top = 0 Width = 281 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 6 BorderSpacing.Right = 12 BorderSpacing.Bottom = 6 Caption = 'Connect to:' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ClientHeight = 337 ClientWidth = 277 TabOrder = 0 object tvConnections: TTreeView Left = 4 Height = 329 Top = 4 Width = 269 Align = alClient DefaultItemHeight = 24 ReadOnly = True StateImages = ImageList TabOrder = 0 OnSelectionChanged = tvConnectionsSelectionChanged Options = [tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips] end end object btnConnect: TBitBtn AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 299 Height = 30 Top = 16 Width = 120 Anchors = [akTop, akRight] BorderSpacing.Right = 12 Caption = 'C&onnect' Enabled = False OnClick = btnConnectClick TabOrder = 1 end object btnAdd: TBitBtn AnchorSideLeft.Control = btnConnect AnchorSideTop.Control = btnConnect AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnConnect AnchorSideRight.Side = asrBottom Left = 299 Height = 30 Top = 64 Width = 120 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 18 Caption = 'A&dd' Enabled = False OnClick = btnAddClick TabOrder = 2 end object btnEdit: TBitBtn AnchorSideLeft.Control = btnAdd AnchorSideTop.Control = btnAdd AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnAdd AnchorSideRight.Side = asrBottom Left = 299 Height = 30 Top = 100 Width = 120 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = '&Edit' Enabled = False OnClick = btnEditClick TabOrder = 3 end object btnDelete: TBitBtn AnchorSideLeft.Control = btnEdit AnchorSideTop.Control = btnEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnEdit AnchorSideRight.Side = asrBottom Left = 299 Height = 30 Top = 136 Width = 120 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = '&Delete' Enabled = False OnClick = btnDeleteClick TabOrder = 4 end object btnCancel: TBitBtn AnchorSideLeft.Control = btnDelete AnchorSideTop.Control = btnDelete AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnDelete AnchorSideRight.Side = asrBottom Left = 299 Height = 30 Top = 172 Width = 120 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 TabOrder = 5 end object ImageList: TImageList Height = 22 Width = 22 left = 345 top = 253 Bitmap = { 4C69020000001600000016000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000373AD01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000273 AD00000000000373AD00007AB9FF007AB9FF007AB9FF007AB9FF007AB9FF007A B9FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000529A00007A B9FFA4FEFDFE9BF6FBFF96F1FDFF92EDFDFF8EE8FEFF8CE5FFFE0275B1FF0046 8A0F0373AD000000000000000000000000000000000000000000000000000000 0000000000000000000000000000006AA700007AB9FF93E6F2FF8FE4F3FF8CE1 F5FF89DFF6FF86DDF7FF83DBF8FF80D9F9FF80DAFDFF0275B1FF00000000006B A506006CA506006CA506006CA506006CA506006CA506006CA506006CA506006D A60400000000007AB9FFB8F5FEFEACEDFAFFA9EAF8FFA5E7F8FFA1E4F8FF9EE1 F7FF9ADEF6FF96DBF6FF92D9F5FE96DDFCFF0372ADFF0371ABFF0370A9FF046E A7FF056EA5FF056CA3FF056BA1FF066A9EFF06699DFF358DB900004B79140079 B8FFB7FBFFFFA4F5FEFFA2F3FDFF9FF1FCFF9DEEFCFF9AEDFBFF99EBFAFF95E9 F8FF94E6F8FF91E4F8FF8FE2F6FF8DE0F6FF8ADDF4FF88DBF4FF85D9F3FF82D7 F2FF80D4F1FF7ED3F1FF7BD1F0FF096395FF00507F000178B6FFB5FAFFFFA1F4 FDFF9FF1FDFF9DEFFCFF9AEDFBFF98EBF9FF96E9FAFF93E7F9FF91E5F7FF8EE2 F7FF8CE1F6FF8ADEF6FF88DCF4FF85DAF4FF83D7F3FF80D5F2FF7ED4F2FF7CD1 F0FF79D1F0FF096394FF00507F000177B4FFB2F8FFFF9FF3FCFF9EF0FDFF9BEF FCFF99ECFBFF97EAF9FF94E8F9FF92E5F9FF8FE3F7FF8DE1F6FF8ADFF6FF88DD F5FF85DAF4FF83D9F3FF81D6F2FF7FD5F2FF7DD3F1FF7AD0F0FF77CFF0FF0962 93FF00507F000176B2FFB0F7FFFF9FF1FCFF9CEFFBFF99EDFAFF97EBFAFF95E8 F9FF92E6F8FF90E3F8FF8EE2F7FF8CE0F6FF89DDF5FF87DCF4FF84D9F3FF82D7 F2FF7FD5F2FF7ED3F0FF7AD0F1FF78CEF0FF76CDEFFF0A6292FF00517F000275 B1FFAEF5FEFF9DEFFCFF9BEDFAFF98EBFBFF96E9F9FF93E7F9FF91E4F7FF8FE3 F7FF8CE0F6FF89DEF6FF87DCF4FF85DAF4FF83D8F2FF80D6F2FF7FD3F2FF7BD1 F0FF79CFF0FF77CCEFFF74CCEEFF0A6191FF00517F000274AFFFACF4FEFF9BEE FBFF98ECFBFF96E9F9FF93E7F8FF91E5F7FF8FE3F7FF8DE0F6FF8BDFF6FF88DC F5FF85DBF4FF83D9F3FF81D6F2FF7FD4F1FF7CD2F0FF7AD0F0FF77CDEFFF76CC EEFF73CAEEFF0A6090FF00517F000372AEFFAAF2FDFF9AECFAFF97EAFAFF94E8 F9FF92E6F8FF8FE3F7FF8EE1F7FF8BDFF6FF89DDF5FF86DBF5FF84D9F3FF82D7 F3FF7FD5F2FF7CD2F1FF7AD1F0FF78CEEFFF76CCEFFF73CAEDFF71C9EEFF0A5F 8FFF00517F000472ABFFA8F0FCFF98EBFAFF95E9FAFF92E6F8FF90E4F7FF8EE2 F7FF8CE0F6FF8ADFF6FF87DCF4FF85DAF3FF83D7F2FF80D6F2FF7ED3F1FF7BD1 F0FF79CFEFFF76CDEFFF73CAEDFF72C8EDFF70C7ECFF0A5F8EFF00527F000470 AAFFA5EEFBFF96EAFAFF93E7F9FF91E6F8FF8FE3F7FF8CE1F7FF8ADFF5FF88DC F5FF85DAF4FF83D8F3FF81D7F2FF7ED3F1FF7CD2F1FF7ACFF0FF77CEEFFF74CB EEFF72C9EEFF70C7ECFF6DC6EDFF0A5F8DFF00528000046FA8FFA4ECFBFF94E7 F8FF92E5F8FF8FE3F7FF8DE2F6FF8BDFF6FF89DDF5FF87DBF4FF84D8F3FF82D7 F2FF7FD5F2FF7CD3F1FF7AD0F0FF78CEEFFF75CBEEFF74CAEEFF71C8EDFF6EC5 ECFF6CC4EBFF0B5E8CFF00528000056EA7FFA1EBF9FF93E7F8FF90E4F7FF8EE2 F7FF8CE0F6FF89DEF4FF87DCF4FF84D9F4FF82D8F2FF80D5F2FF7ED3F1FF7BD0 F0FF78CFEFFF76CCEEFF74CAEDFF72C9EDFF6FC6ECFF6CC4EBFF6AC2ECFF0B5D 8BFF01528000056DA4FF9FE9F9FF91E5F7FF8FE2F7FF8CE0F7FF8ADEF6FF88DD F5FF85DAF4FF83D8F3FF80D5F1FF7ED4F1FF7BD1F1FF79D0F0FF77CCEFFF75CB EEFF72C9EEFF6FC6EDFF6EC5ECFF6BC3EBFF69C2EBFF0C5C89FF01528000066C A3FF9CE8F8FF8EE3F8FF8CE1F7FF8ADFF6FF88DDF5FF86DBF5FF83D9F4FF81D7 F3FF7ED5F3FF7CD3F1FF7AD1F1FF77CEF0FF75CCEFFF73CAEEFF71C8EEFF6EC6 EDFF6CC4EBFF69C1EBFF68C0ECFF0B5C89FF01538000066BA2FFB1E7F7FEA6E0 F3FFA2DDF1FF9EDBF0FF9AD9EEFF96D6EDFF92D3ECFF8FD0EAFF8ACDE9FF87CA E7FF82C8E6FF7FC5E4FF7BC2E4FF77BFE2FF73BCE0FF6FBADFFF6BB7DDFF67B4 DCFF63B2DBFF0B5B87FF025380000043761107679BFF07679AFF086699FF0865 98FF086597FF086496FF096395FF096393FF096293FF096191FF0A6191FF0A60 8FFF0A5F8EFF0B5E8DFF0B5E8CFF0B5D8CFF0B5D8AFF0B5C89FF0C5B88FF0352 7F00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000C5B88000000 000000000000000000000000000000000000606060FF606060FF606060FF6060 60FF606060FF606060FF606060FF606060FF606060FF606060FF606060FF0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000606060FFE4E4E4FFFDFDFDFFFDFDFDFFFCFCFCFFFAFAFAFFFAFA FAFFF9F9F9FFF8F8F8FFF7F7F7FFF7F7F7FFC6C6C6FF606060FF000000000000 0000000000000000000000000000000000000000000000000000606060FFF9F9 F9FFFDFDFDFFFDFDFDFFFCFCFCFFFCFCFCFFFAFAFAFFFAFAFAFFF9F9F9FFF9F9 F9FFF7F7F7FFF7F7F7FFF6F6F6FFEEEEEEFF606060FF00000000000000000000 000000000000000000000000000000000000606060FFFAFAFAFFBDBDBDFFBDBD BDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBD BDFFBDBDBDFFFDFDFDFF606060FF000000000000000000000000000000000000 00000000000000000000606060FFFAFAFAFFB3B3B3FFE3E3E3FFE3E3E3FFE3E3 E3FFE3E3E3FFE3E3E3FFE3E3E3FFE3E3E3FFE3E3E3FFE3E3E3FFB3B3B3FFF4F4 F4FF606060FF0000000000000000000000000000000000000000000000000000 0000606060FFFAFAFAFFBCBCBCFFDADADAFFD9D9D9FFD8D8D8FFD6D6D6FFD5D5 D5FFD4D4D4FFD3D3D3FFD2D2D2FFD2D2D2FFB7B7B7FFF2F2F2FF606060FF0000 0000000000000000000000000000000000000000000000000000606060FFFAFA FAFFB1B1B1FFB6B6B6FFB6B6B6FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5 B5FFB4B4B4FFB4B4B4FFB1B1B1FFF2F2F2FF606060FF00000000000000000000 000000000000000000000000000000000000606060FFF8F8F8FFBCBCBCFFE6E6 E6FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE4E4E4FFE4E4E4FFE3E3E3FFE2E2 E2FFBBBBBBFFF4F4F4FF606060FF000000000000000000000000000000000000 00006060603E606060B3606060FFF8F8F8FFBBBBBBFFD1D1D1FFCFCFCFFFCECE CEFFCDCDCDFFCCCCCCFFCBCBCBFFCACACAFFC9C9C9FFC8C8C8FFB6B6B6FFF1F1 F1FF606060FF606060FF606060B30000000000000000CDCDCD10CDCDCD2FCDCD CD5E606060FFF8F8F8FFB2B2B2FFB7B7B7FFB7B7B7FFB6B6B6FFB6B6B6FFB6B6 B6FFB6B6B6FFB6B6B6FFB6B6B6FFB5B5B5FFB2B2B2FFF2F2F2FF606060FFCDCD CDBFCDCDCD76CDCDCD37CDCDCD170000000000000000606060B3606060FFFAFA FAFFE8E8E8FFE5E5E5FFE5E5E5FFE4E4E4FFE2E2E2FFE3E3E3FFDCDCDCFFDCDC DCFFE2E2E2FFD9D9D9FFDFDFDFFFF3F3F3FF606060FF606060FF606060B30000 000000000000000000000000000000000000606060FFFEFEFEFFA5A5A5FF8A8A 8AFFABABABFFD5D5D5FFBDBDBDFFBABABAFFB9B9B9FFB9B9B9FFB9B9B9FFB9B9 B9FFB8B8B8FFFCFCFCFF606060FF000000000000000000000000000000000000 00000000000000000000606060FFFEFEFEFF888888FFB2B2B2FF7E7E7EFFD6D6 D6FFC3C3C3FFDCDCDCFFDCDCDCFFDCDCDCFFDBDBDBFFDBDBDBFFB5B5B5FFFCFC FCFF606060FF0000000000000000000000000000000000000000000000000000 0000606060FFFDFDFDFFAAAAAAFF7C7C7CFFD3D3D3FFDEDEDEFFBDBDBDFFBDBD BDFFBCBCBCFFBCBCBCFFBCBCBCFFBCBCBCFFBDBDBDFFFCFCFCFF606060FF0000 0000000000000000000000000000000000000000000000000000606060FFFDFD FDFFDEDEDEFFDCDCDCFFDBDBDBFFDBDBDBFFDBDBDBFFDADADAFFDADADAFFDADA DAFFDADADAFFDADADAFFD9D9D9FFFCFCFCFF606060FF00000000000000000000 000000000000000000000000000000000000606060FFFDFDFDFFDADADAFFDADA DAFFAFAFAFFFC3C3C3FFA5A5A5FFC1C1C1FFADADADFFC3C3C3FFA3A3A3FFDCDC DCFFD7D7D7FFFCFCFCFF606060FF000000000000000000000000000000000000 00000000000000000000606060FFFDFDFDFFD7D7D7FFD6D6D6FFAEAEAEFFDBDB DBFFB6B6B6FFDADADAFFBBBBBBFFDCDCDCFFB4B4B4FFD7D7D7FFD3D3D3FFFCFC FCFF606060FF0000000000000000000000000000000000000000000000000000 0000606060FFFDFDFDFFD6D6D6FFD5D5D5FFB3B3B3FFD5D5D5FFAEAEAEFFD7D7 D7FFAFAFAFFFD6D6D6FFAAAAAAFFD4D4D4FFD3D3D3FFFCFCFCFF606060FF0000 0000000000000000000000000000000000000000000000000000606060FFFEFE FEFFFCFCFCFFFCFCFCFFFBFBFBFFFCFCFCFFFBFBFBFFFCFCFCFFFBFBFBFFFCFC FCFFFBFBFBFFFCFCFCFFFCFCFCFFFEFEFEFF606060FF00000000000000000000 00000000000000000000000000000000000053575591606060FF606060FF6060 60FF606060FF606060FF606060FF606060FF606060FF606060FF606060FF6060 60FF606060FF606060FF53575591000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000 } end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fconnectionmanager.lrj���������������������������������������������������������0000644�0001750�0000144�00000001711�14743153644�017746� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":227436834,"name":"tfrmconnectionmanager.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,32,109,97,110,97,103,101,114],"value":"Connection manager"}, {"hash":200024170,"name":"tfrmconnectionmanager.gbconnectto.caption","sourcebytes":[67,111,110,110,101,99,116,32,116,111,58],"value":"Connect to:"}, {"hash":224743412,"name":"tfrmconnectionmanager.btnconnect.caption","sourcebytes":[67,38,111,110,110,101,99,116],"value":"C&onnect"}, {"hash":277668,"name":"tfrmconnectionmanager.btnadd.caption","sourcebytes":[65,38,100,100],"value":"A&dd"}, {"hash":2800388,"name":"tfrmconnectionmanager.btnedit.caption","sourcebytes":[38,69,100,105,116],"value":"&Edit"}, {"hash":179055749,"name":"tfrmconnectionmanager.btndelete.caption","sourcebytes":[38,68,101,108,101,116,101],"value":"&Delete"}, {"hash":177752476,"name":"tfrmconnectionmanager.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} ]} �������������������������������������������������������doublecmd-1.1.22/src/fconnectionmanager.pas���������������������������������������������������������0000644�0001750�0000144�00000014151�14743153644�017744� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fConnectionManager; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, ComCtrls, uFileView; type { TfrmConnectionManager } TfrmConnectionManager = class(TForm) btnCancel: TBitBtn; btnDelete: TBitBtn; btnEdit: TBitBtn; btnAdd: TBitBtn; btnConnect: TBitBtn; gbConnectTo: TGroupBox; ImageList: TImageList; tvConnections: TTreeView; procedure btnAddClick(Sender: TObject); procedure btnConnectClick(Sender: TObject); procedure btnDeleteClick(Sender: TObject); procedure btnEditClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure tvConnectionsSelectionChanged(Sender: TObject); private FFileView: TFileView; public constructor Create(TheOwner: TComponent; FileView: TFileView); reintroduce; end; function ShowConnectionManager(FileView: TFileView): Boolean; implementation {$R *.lfm} uses uGlobs, uDCUtils, uShowMsg, uWfxModule, WfxPlugin, uWfxPluginFileSource, uLng, uConnectionManager; function ShowConnectionManager(FileView: TFileView): Boolean; begin with TfrmConnectionManager.Create(Application, FileView) do begin try Result:= (ShowModal = mrOK); finally Free; end; end; end; { TfrmConnectionManager } procedure TfrmConnectionManager.tvConnectionsSelectionChanged(Sender: TObject); var bEnabled: Boolean; begin if not Assigned(tvConnections.Selected) then begin btnConnect.Enabled:= False; btnAdd.Enabled:= False; btnEdit.Enabled:= False; btnDelete.Enabled:= False; end else begin bEnabled:= Assigned(tvConnections.Selected.Data); btnConnect.Enabled:= not bEnabled; btnAdd.Enabled:= bEnabled; btnEdit.Enabled:= not bEnabled; btnDelete.Enabled:= not bEnabled; end; end; procedure TfrmConnectionManager.btnAddClick(Sender: TObject); var WfxPluginFileSource: IWfxPluginFileSource; Connection: String; begin { WfxPluginFileSource:= PFileSourceRecord(tvConnections.Selected.Data)^.FileSource as IWfxPluginFileSource; if Assigned(WfxPluginFileSource) then begin if WfxPluginFileSource.WfxModule.WfxNetworkManageConnection(Handle, Connection, FS_NM_ACTION_ADD) then begin with tvConnections.Items.AddChild(tvConnections.Selected, Connection) do StateIndex:= 1; end; end; } end; procedure TfrmConnectionManager.btnConnectClick(Sender: TObject); var WfxPluginFileSource: IWfxPluginFileSource; Connection, RemotePath, RootPath: String; begin { WfxPluginFileSource:= PFileSourceRecord(tvConnections.Selected.Parent.Data)^.FileSource as IWfxPluginFileSource; if Assigned(WfxPluginFileSource) then begin Connection:= tvConnections.Selected.Text; if WfxPluginFileSource.WfxModule.WfxNetworkOpenConnection(Connection, RootPath, RemotePath) then begin DoDirSeparators(RootPath); DoDirSeparators(RemotePath); WfxPluginFileSource.SetCurrentAddress(Connection); WfxPluginFileSource.SetRootDir(IncludeTrailingPathDelimiter(RootPath)); FFileView.AddFileSource(WfxPluginFileSource, ExcludeTrailingPathDelimiter(RootPath) + RemotePath); tvConnections.Selected.Parent.Data:= nil; Close; end else begin msgError(Format(rsMsgErrCanNotConnect, [Connection])); end; end; } end; procedure TfrmConnectionManager.btnDeleteClick(Sender: TObject); var WfxPluginFileSource: IWfxPluginFileSource; Connection: String; begin { WfxPluginFileSource:= PFileSourceRecord(tvConnections.Selected.Parent.Data)^.FileSource as IWfxPluginFileSource; if Assigned(WfxPluginFileSource) then begin Connection:= tvConnections.Selected.Text; if WfxPluginFileSource.WfxModule.WfxNetworkManageConnection(Handle, Connection, FS_NM_ACTION_DELETE) then begin tvConnections.Items.BeginUpdate; tvConnections.Items.Delete(tvConnections.Selected); tvConnections.Items.EndUpdate; end; end; } end; procedure TfrmConnectionManager.btnEditClick(Sender: TObject); var WfxPluginFileSource: IWfxPluginFileSource; Connection: String; begin { WfxPluginFileSource:= PFileSourceRecord(tvConnections.Selected.Parent.Data)^.FileSource as IWfxPluginFileSource; if Assigned(WfxPluginFileSource) then begin Connection:= tvConnections.Selected.Text; if WfxPluginFileSource.WfxModule.WfxNetworkManageConnection(Handle, Connection, FS_NM_ACTION_EDIT) then tvConnections.Selected.Text:= Connection; end; } end; procedure TfrmConnectionManager.FormDestroy(Sender: TObject); var I: Integer; begin { for I:= 0 to tvConnections.Items.Count - 1 do begin if Assigned(tvConnections.Items.Item[I].Data) then DisposeFileSourceRecord(tvConnections.Items.Item[I].Data); end; } end; constructor TfrmConnectionManager.Create(TheOwner: TComponent; FileView: TFileView); var I, J: Integer; WfxPluginFileSource: IWfxPluginFileSource = nil; sModuleFileName, Connection: String; Node, SubNode: TTreeNode; begin { FFileView:= FileView; inherited Create(TheOwner); for I:= 0 to gWfxPlugins.Count - 1 do begin if gWfxPlugins.Enabled[I] then begin sModuleFileName:= GetCmdDirFromEnvVar(gWfxPlugins.FileName[I]); WfxPluginFileSource:= TWfxPluginFileSource.Create(sModuleFileName, gWfxPlugins.Name[I]); try if Assigned(WfxPluginFileSource) then with WfxPluginFileSource do begin if WFXmodule.VFSNetworkSupport then begin Node:= tvConnections.Items.Add(nil, gWfxPlugins.Name[I]); Node.Data:= NewFileSourceRecord(WfxPluginFileSource); Node.StateIndex:= 0; J:= 0; while WfxModule.WfxNetworkGetConnection(J, Connection) do begin SubNode:= tvConnections.Items.AddChild(Node, Connection); SubNode.StateIndex:= 1; Inc(J); end; end else begin WfxPluginFileSource:= nil; end; end; except WfxPluginFileSource:= nil; end; end; end; } end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fcopymovedlg.lfm���������������������������������������������������������������0000644�0001750�0000144�00000026036�14743153644�016602� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmCopyDlg: TfrmCopyDlg Left = 462 Height = 263 Top = 260 Width = 612 HorzScrollBar.Page = 349 HorzScrollBar.Range = 337 VertScrollBar.Page = 205 VertScrollBar.Range = 186 ActiveControl = edtDst AutoSize = True BorderIcons = [biSystemMenu, biMaximize] Caption = 'Copy file(s)' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 263 ClientWidth = 612 KeyPreview = True OnCreate = FormCreate OnDestroy = FormDestroy OnKeyDown = FormKeyDown OnPaint = FormPaint OnShow = frmCopyDlgShow Position = poOwnerFormCenter LCLVersion = '1.2.4.0' object lblCopySrc: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 20 Top = 8 Width = 596 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Top = 8 BorderSpacing.Right = 8 ParentColor = False ShowAccelChar = False end object edtDst: TKASPathEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblCopySrc AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 27 Top = 34 Width = 596 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Top = 6 BorderSpacing.Right = 8 TabOrder = 0 ObjectTypes = [otFolders, otNonFolders] FileSortType = fstFoldersFirst end object pnlSelector: TPanel AnchorSideLeft.Control = edtDst AnchorSideTop.Control = edtDst AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtDst AnchorSideRight.Side = asrBottom Left = 8 Height = 1 Top = 69 Width = 596 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 8 BevelOuter = bvNone TabOrder = 1 end object pnlButtons: TPanel AnchorSideLeft.Control = edtDst AnchorSideTop.Control = pnlSelector AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtDst AnchorSideRight.Side = asrBottom Left = 8 Height = 36 Top = 74 Width = 596 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 BevelOuter = bvNone ClientHeight = 36 ClientWidth = 596 TabOrder = 2 object btnOptions: TButton Left = 0 Height = 36 Top = 0 Width = 100 Align = alLeft AutoSize = True Caption = 'O&ptions' Constraints.MinWidth = 100 OnClick = btnOptionsClick TabOrder = 0 end object btnAddToQueue: TBitBtn Left = 268 Height = 36 Top = 0 Width = 118 Align = alRight AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'A&dd To Queue' Constraints.MinHeight = 34 Constraints.MinWidth = 88 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 00000000000004753BC504733A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF18844DF504763BAB04733A0C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF7ACFA4FF36A16AF804763CE104733A2D000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF82D8ACFF6CD5A0FF58C18BFE0A7940F504743A650000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004743AFE83DBAEFF11BA64FF52D392FF73D7A5FF1E8B53F50476 3CAC04733A0C0000000000000000000000000000000000000000000000000000 00000000000004733AFF83DCAFFF0EB761FF10BF66FF34CB7FFF78DAA8FF3EA6 71F904763BE104733A2D00000000000000000000000000000000000000000000 00000000000004733AFFA9DCC1FF0DB35EFF0EB962FF0FBC64FF1CBF6CFF67D2 9CFF5DBB8BFE0E7A42F504733A65000000000000000000000000000000000000 00000000000004733AFFA9DCC1FF0BAE5BFF0EB25FFF17B866FF1FBA6CFF26BA 6FFF55C68DFF76C99EFF268956F504753B9D0000000000000000000000000000 00000000000004733AFFA9DCC1FF49BE82FF50C389FF4DC488FF49C284FF44BE 80FF6DCA9BFF89CEAAFF308F5EF604753B9D0000000000000000000000000000 00000000000004733AFFA9DCC1FF5CC18DFF5AC28DFF55C28AFF58C38CFF8CD4 AFFF7AC39CFE147C46F504733A65000000000000000000000000000000000000 00000000000004733AFFA9DCC1FF64C191FF61C18FFF73C89DFF9FD9BBFF5AAB 81FA05743AE104733A2D00000000000000000000000000000000000000000000 00000000000004743AFEA9DCC1FF6FC499FF91D2B1FF9CD4B7FF318F5FF60474 3BAC04733A0C0000000000000000000000000000000000000000000000000000 00000000000004733AFFA9DCC1FFABDCC3FF84C6A4FE107A43F504733A650000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFFA5DABFFF5AAB82F904743AE104733A2D000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF2A8C59F604743AAB04733A0C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004753BC504733A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ModalResult = 1 TabOrder = 1 end object btnCreateSpecialQueue: TBitBtn Left = 386 Height = 36 Top = 0 Width = 23 Align = alRight BorderSpacing.Right = 12 Glyph.Data = { 72000000424D7200000000000000360000002800000005000000030000000100 2000000000003C00000064000000640000000000000000000000000000000000 0000000000FF000000000000000000000000000000FF000000FF000000FF0000 0000000000FF000000FF000000FF000000FF000000FF } GlyphShowMode = gsmAlways Layout = blGlyphBottom OnClick = btnCreateSpecialQueueClick PopupMenu = pmQueuePopup TabOrder = 2 end object btnCancel: TBitBtn Left = 421 Height = 36 Top = 0 Width = 79 Align = alRight AutoSize = True BorderSpacing.Left = 12 BorderSpacing.Right = 8 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 TabOrder = 3 end object btnOK: TBitBtn Left = 508 Height = 36 Top = 0 Width = 88 Align = alRight AutoSize = True BorderSpacing.InnerBorder = 2 Constraints.MinHeight = 34 Constraints.MinWidth = 88 Default = True Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 00000000000004753BC504733A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF18844DF504763BAB04733A0C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF7ACFA4FF36A16AF804763CE104733A2D000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF82D8ACFF6CD5A0FF58C18BFE0A7940F504743A650000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004743AFE83DBAEFF11BA64FF52D392FF73D7A5FF1E8B53F50476 3CAC04733A0C0000000000000000000000000000000000000000000000000000 00000000000004733AFF83DCAFFF0EB761FF10BF66FF34CB7FFF78DAA8FF3EA6 71F904763BE104733A2D00000000000000000000000000000000000000000000 00000000000004733AFFA9DCC1FF0DB35EFF0EB962FF0FBC64FF1CBF6CFF67D2 9CFF5DBB8BFE0E7A42F504733A65000000000000000000000000000000000000 00000000000004733AFFA9DCC1FF0BAE5BFF0EB25FFF17B866FF1FBA6CFF26BA 6FFF55C68DFF76C99EFF268956F504753B9D0000000000000000000000000000 00000000000004733AFFA9DCC1FF49BE82FF50C389FF4DC488FF49C284FF44BE 80FF6DCA9BFF89CEAAFF308F5EF604753B9D0000000000000000000000000000 00000000000004733AFFA9DCC1FF5CC18DFF5AC28DFF55C28AFF58C38CFF8CD4 AFFF7AC39CFE147C46F504733A65000000000000000000000000000000000000 00000000000004733AFFA9DCC1FF64C191FF61C18FFF73C89DFF9FD9BBFF5AAB 81FA05743AE104733A2D00000000000000000000000000000000000000000000 00000000000004743AFEA9DCC1FF6FC499FF91D2B1FF9CD4B7FF318F5FF60474 3BAC04733A0C0000000000000000000000000000000000000000000000000000 00000000000004733AFFA9DCC1FFABDCC3FF84C6A4FE107A43F504733A650000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFFA5DABFFF5AAB82F904743AE104733A2D000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004733AFF2A8C59F604743AAB04733A0C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000004753BC504733A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ModalResult = 1 OnClick = btnOKClick TabOrder = 4 end end object pnlOptions: TPanel AnchorSideLeft.Control = edtDst AnchorSideTop.Control = pnlButtons AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtDst AnchorSideRight.Side = asrBottom Left = 8 Height = 39 Top = 114 Width = 596 AutoSize = True BorderSpacing.Top = 4 BorderSpacing.Bottom = 4 BevelOuter = bvNone ClientHeight = 39 ClientWidth = 596 TabOrder = 3 OnResize = pnlOptionsResize object grpOptions: TGroupBox AnchorSideLeft.Control = pnlOptions AnchorSideTop.Control = pnlOptions AnchorSideRight.Control = pnlOptions AnchorSideRight.Side = asrBottom Left = 0 Height = 4 Top = 0 Width = 596 Anchors = [akTop, akLeft, akRight] AutoSize = True ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 TabOrder = 0 end object btnSaveOptions: TButton AnchorSideLeft.Control = grpOptions AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = grpOptions AnchorSideTop.Side = asrBottom Left = 207 Height = 27 Top = 12 Width = 183 AutoSize = True BorderSpacing.Top = 8 Caption = 'Sa&ve these options as default' Constraints.MinWidth = 201 OnClick = btnSaveOptionsClick TabOrder = 1 end end object pmQueuePopup: TPopupMenu left = 296 top = 184 object mnuNewQueue: TMenuItem Caption = 'New queue' OnClick = mnuNewQueueClick end object mnuQueue1: TMenuItem Caption = 'Queue 1' OnClick = mnuQueueNumberClick end object mnuQueue2: TMenuItem Caption = 'Queue 2' OnClick = mnuQueueNumberClick end object mnuQueue3: TMenuItem Caption = 'Queue 3' OnClick = mnuQueueNumberClick end object mnuQueue4: TMenuItem Caption = 'Queue 4' OnClick = mnuQueueNumberClick end object mnuQueue5: TMenuItem Caption = 'Queue 5' OnClick = mnuQueueNumberClick end end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fcopymovedlg.lrj���������������������������������������������������������������0000644�0001750�0000144�00000002753�14743153644�016613� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":140772409,"name":"tfrmcopydlg.caption","sourcebytes":[67,111,112,121,32,102,105,108,101,40,115,41],"value":"Copy file(s)"}, {"hash":226165059,"name":"tfrmcopydlg.btnoptions.caption","sourcebytes":[79,38,112,116,105,111,110,115],"value":"O&ptions"}, {"hash":43178309,"name":"tfrmcopydlg.btnaddtoqueue.caption","sourcebytes":[65,38,100,100,32,84,111,32,81,117,101,117,101],"value":"A&dd To Queue"}, {"hash":177752476,"name":"tfrmcopydlg.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":179353140,"name":"tfrmcopydlg.btnsaveoptions.caption","sourcebytes":[83,97,38,118,101,32,116,104,101,115,101,32,111,112,116,105,111,110,115,32,97,115,32,100,101,102,97,117,108,116],"value":"Sa&ve these options as default"}, {"hash":158918773,"name":"tfrmcopydlg.mnunewqueue.caption","sourcebytes":[78,101,119,32,113,117,101,117,101],"value":"New queue"}, {"hash":146585441,"name":"tfrmcopydlg.mnuqueue1.caption","sourcebytes":[81,117,101,117,101,32,49],"value":"Queue 1"}, {"hash":146585442,"name":"tfrmcopydlg.mnuqueue2.caption","sourcebytes":[81,117,101,117,101,32,50],"value":"Queue 2"}, {"hash":146585443,"name":"tfrmcopydlg.mnuqueue3.caption","sourcebytes":[81,117,101,117,101,32,51],"value":"Queue 3"}, {"hash":146585444,"name":"tfrmcopydlg.mnuqueue4.caption","sourcebytes":[81,117,101,117,101,32,52],"value":"Queue 4"}, {"hash":146585445,"name":"tfrmcopydlg.mnuqueue5.caption","sourcebytes":[81,117,101,117,101,32,53],"value":"Queue 5"} ]} ���������������������doublecmd-1.1.22/src/fcopymovedlg.pas���������������������������������������������������������������0000644�0001750�0000144�00000033255�14743153644�016610� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Dialog window when copying/moving files confirming filenames and other options Copyright (C) 2009-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fCopyMoveDlg; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, ExtCtrls, Menus, ActnList, KASPathEdit, uFileSource, uFileViewNotebook, uFileSourceOperation, uFileSourceOperationOptionsUI, uOperationsManager, uFormCommands; type TCopyMoveDlgType = (cmdtCopy, cmdtMove); TCurrentCopyDlgNameSelectionStep = (ccdnssWholeCompleteFilename, ccdnssJustFilenameNoExt, ccdnssJustFilenameWithExt, ccdnssJustExtension, ccdnssJustPath, ccdnssInvalid); //Note: ccdnssInvalid *must* be the last one. { TfrmCopyDlg } TfrmCopyDlg = class(TForm, IFormCommands) btnCancel: TBitBtn; btnOK: TBitBtn; btnAddToQueue: TBitBtn; btnOptions: TButton; btnSaveOptions: TButton; edtDst: TKASPathEdit; grpOptions: TGroupBox; lblCopySrc: TLabel; mnuQueue2: TMenuItem; mnuQueue3: TMenuItem; mnuQueue4: TMenuItem; mnuQueue5: TMenuItem; mnuQueue1: TMenuItem; mnuNewQueue: TMenuItem; pmQueuePopup: TPopupMenu; pnlButtons: TPanel; pnlOptions: TPanel; pnlSelector: TPanel; btnCreateSpecialQueue: TBitBtn; procedure btnCreateSpecialQueueClick(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure btnOptionsClick(Sender: TObject); procedure btnSaveOptionsClick(Sender: TObject); procedure btnStartModeClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormPaint(Sender: TObject); procedure frmCopyDlgShow(Sender: TObject); procedure mnuNewQueueClick(Sender: TObject); procedure mnuQueueNumberClick(Sender: TObject); procedure pnlOptionsResize(Sender: TObject); private FCommands: TFormCommands; FDialogType: TCopyMoveDlgType; noteb: TFileViewNotebook; FFileSource: IFileSource; FOperationOptionsUIClass: TFileSourceOperationOptionsUIClass; FOperationOptionsUI: TFileSourceOperationOptionsUI; FCurrentCopyDlgNameSelectionStep: TCurrentCopyDlgNameSelectionStep; function GetQueueIdentifier: TOperationsManagerQueueIdentifier; procedure SetQueueIdentifier(AValue: TOperationsManagerQueueIdentifier); function ShowTabsSelector: integer; procedure TabsSelector(Sender: TObject); procedure TabsSelectorMouseDown(Sender: TObject; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer); procedure ShowOptions(bShow: Boolean); procedure UpdateSize; property {%H-}Commands: TFormCommands read FCommands implements IFormCommands; public constructor Create(TheOwner: TComponent; DialogType: TCopyMoveDlgType; AFileSource: IFileSource; AOperationOptionsUIClass: TFileSourceOperationOptionsUIClass); reintroduce; constructor Create(TheOwner: TComponent); override; procedure SetOperationOptions(Operation: TFileSourceOperation); property QueueIdentifier: TOperationsManagerQueueIdentifier read GetQueueIdentifier write SetQueueIdentifier; published procedure cm_AddToQueue(const Params: array of String); procedure cm_ToggleSelectionInName(const {%H-}Params: array of string); end; implementation {$R *.lfm} uses LazUTF8, fMain, LCLType, LCLVersion, uGlobs, uLng, uHotkeyManager, DCStrUtils; const HotkeysCategory = 'Copy/Move Dialog'; var FQueueIdentifier: TOperationsManagerQueueIdentifier = SingleQueueId; constructor TfrmCopyDlg.Create(TheOwner: TComponent; DialogType: TCopyMoveDlgType; AFileSource: IFileSource; AOperationOptionsUIClass: TFileSourceOperationOptionsUIClass); begin FDialogType := DialogType; FFileSource := AFileSource; FOperationOptionsUIClass := AOperationOptionsUIClass; FCommands := TFormCommands.Create(Self); inherited Create(TheOwner); end; constructor TfrmCopyDlg.Create(TheOwner: TComponent); begin Create(TheOwner, cmdtCopy, nil, nil); end; procedure TfrmCopyDlg.SetOperationOptions(Operation: TFileSourceOperation); begin if Assigned(FOperationOptionsUI) then FOperationOptionsUI.SetOperationOptions(Operation); end; procedure TfrmCopyDlg.cm_AddToQueue(const Params: array of String); var Value: Integer; sQueueId: String; begin if FQueueIdentifier = ModalQueueId then Exit; if GetParamValue(Params, 'queueid', sQueueId) and TryStrToInt(sQueueId, Value) then begin if Value < 0 then mnuNewQueue.Click else FQueueIdentifier := Value end else FQueueIdentifier := SingleQueueId; ModalResult := btnAddToQueue.ModalResult; end; { TfrmCopyDlg.cm_ToggleSelectionInName } procedure TfrmCopyDlg.cm_ToggleSelectionInName(const Params: array of string); var iInitialStart, iInitialLength, iFullLength, iPath, iExtension, iSelStart, iSelLenght: integer; begin iFullLength := UTF8Length(edtDst.Text); iPath := UTF8Length(ExtractFilePath(edtDst.Text)); iExtension := UTF8Length(ExtractFileExt(edtDst.Text)); iInitialStart := edtDst.SelStart; iInitialLength := edtDst.SelLength; if iFullLength = 0 then exit; repeat FCurrentCopyDlgNameSelectionStep := TCurrentCopyDlgNameSelectionStep((ord(FCurrentCopyDlgNameSelectionStep)+1) mod ord(ccdnssInvalid)); case FCurrentCopyDlgNameSelectionStep of ccdnssJustFilenameNoExt: begin iSelStart := iPath; iSelLenght := iFullLength - (iPath+iExtension); end; ccdnssJustFilenameWithExt: begin iSelStart := iPath; iSelLenght := iFullLength - iPath; end; ccdnssJustExtension: begin iSelStart := succ(iPath + (iFullLength - (iPath+iExtension))); iSelLenght := pred(iExtension); end; ccdnssJustPath: begin iSelStart := 0; iSelLenght := pred(iPath); end; else //Which includes also "ccdnssWholeCompleteFilename". begin iSelStart := 0; iSelLenght := iFullLength; end; end; until ((iSelStart <> iInitialStart) OR (iInitialLength <> iSelLenght)) AND (iSelLenght > 0); edtDst.SelStart := iSelStart; edtDst.SelLength := iSelLenght; end; procedure TfrmCopyDlg.TabsSelector(Sender: TObject); begin edtDst.Text := noteb[(Sender as TButton).tag].CurrentPath; end; procedure TfrmCopyDlg.TabsSelectorMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin edtDst.Text := noteb[(Sender as TButton).tag].CurrentPath; end; function TfrmCopyDlg.ShowTabsSelector: integer; var btnS, btnL: TButton; i, tc: PtrInt; st: TStringList; s: String; begin noteb := frmMain.NotActiveNotebook; if noteb.PageCount = 1 then begin Result:=0; exit; end; tc := noteb.PageCount; st := TStringList.Create; try for i:=0 to tc-1 do if noteb.View[i].Visible then begin s:=noteb[i].CurrentPath; if st.IndexOf(s)=-1 then begin st.Add(s); st.Objects[st.Count-1]:=TObject(i); end; end; tc := st.Count; btnL := nil; if tc>10 then tc:=10; for i:=0 to tc-1 do begin btnS:= TButton.Create(Self); btnS.TabOrder:= i; btns.Parent:=pnlSelector; btns.Tag:=PtrInt(st.Objects[i]); if i < 9 then btns.Caption := IntToStr(i+1) + ' - ' + noteb.Page[PtrInt(st.Objects[i])].Caption else btns.Caption := '0 - ' + noteb.Page[PtrInt(st.Objects[i])].Caption; btnS.OnClick := @TabsSelector; btnS.OnMouseDown := @TabsSelectorMouseDown; btns.AutoSize:=True; btns.Left := 0; btns.Top := 0; btns.Anchors :=[akLeft,akTop,akBottom]; btns.Visible := True; if btnL <> nil then begin btns.AnchorSideLeft.Control := btnL; btns.AnchorSideLeft.Side := asrRight; end; btnL := btnS; if (Self.Width < (btnL.Left+btnL.Width+200)) then // 200 = Ok + Cancel Self.Width := (btnL.Left+btnL.Width+200); end; finally st.Free; end; end; function TfrmCopyDlg.GetQueueIdentifier: TOperationsManagerQueueIdentifier; begin Result:= FQueueIdentifier; end; procedure TfrmCopyDlg.SetQueueIdentifier(AValue: TOperationsManagerQueueIdentifier); begin FQueueIdentifier:= AValue; end; procedure TfrmCopyDlg.frmCopyDlgShow(Sender: TObject); begin case FDialogType of cmdtCopy: begin Caption := rsDlgCp; end; cmdtMove: begin Caption := rsDlgMv; end; end; if gShowCopyTabSelectPanel then ShowTabsSelector; edtDst.SelectAll; FCurrentCopyDlgNameSelectionStep := ccdnssWholeCompleteFilename; edtDst.SetFocus; btnCreateSpecialQueue.Left:= btnAddToQueue.BoundsRect.Right; end; procedure TfrmCopyDlg.mnuNewQueueClick(Sender: TObject); begin FQueueIdentifier := OperationsManager.GetNewQueueIdentifier; ModalResult := btnAddToQueue.ModalResult; end; procedure TfrmCopyDlg.mnuQueueNumberClick(Sender: TObject); var NewQueueNumber: TOperationsManagerQueueIdentifier; begin if TryStrToInt(Copy((Sender as TMenuItem).Name, 9, 1), NewQueueNumber) then begin FQueueIdentifier := NewQueueNumber; ModalResult := btnAddToQueue.ModalResult; end; end; procedure TfrmCopyDlg.pnlOptionsResize(Sender: TObject); begin UpdateSize; end; procedure TfrmCopyDlg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if gShowCopyTabSelectPanel and (Integer(Key) - VK_1 < pnlSelector.ControlCount) then begin if (ssAlt in Shift) or (edtDst.Focused = False) then begin if (Key >= VK_1) and (Key <= VK_9) then begin TButton(pnlSelector.Controls[Key - VK_1]).Click; Key := 0; end; if (Key = VK_0) and (pnlSelector.ControlCount = 10) then begin TButton(pnlSelector.Controls[9]).Click; Key := 0; end; end; end; {$IF lcl_fullversion < 093100} case Key of VK_ESCAPE: // Must handle before drag manager. Lazarus bug 0020676. begin ModalResult := mrCancel; Key := 0; end; end; {$ENDIF} end; procedure TfrmCopyDlg.FormPaint(Sender: TObject); begin OnPaint := nil; AutoSize := False; Constraints.MinWidth := 0; end; procedure TfrmCopyDlg.btnCreateSpecialQueueClick(Sender: TObject); begin btnCreateSpecialQueue.PopupMenu.PopUp; end; procedure TfrmCopyDlg.btnOKClick(Sender: TObject); begin if FQueueIdentifier <> ModalQueueId then FQueueIdentifier := FreeOperationsQueueId; end; procedure TfrmCopyDlg.btnOptionsClick(Sender: TObject); begin Constraints.MinWidth := Width; ShowOptions(not pnlOptions.Visible); btnOptions.Enabled := not btnOptions.Enabled; ClientWidth := pnlOptions.Width + ChildSizing.LeftRightSpacing * 2; pnlOptions.Anchors := pnlOptions.Anchors + [akRight]; MoveToDefaultPosition; Constraints.MinWidth := 0; end; procedure TfrmCopyDlg.btnSaveOptionsClick(Sender: TObject); begin if Assigned(FOperationOptionsUI) then FOperationOptionsUI.SaveOptions; end; procedure TfrmCopyDlg.btnStartModeClick(Sender: TObject); begin btnOK.PopupMenu.PopUp; end; procedure TfrmCopyDlg.FormCreate(Sender: TObject); var HMForm: THMForm; Hotkey: THotkey; begin Constraints.MinWidth := Width; pnlSelector.Visible := gShowCopyTabSelectPanel; btnOK.Caption := rsDlgOpStart; if FQueueIdentifier <= FreeOperationsQueueId then FQueueIdentifier:= SingleQueueId; btnAddToQueue.Caption:= btnAddToQueue.Caption + ' #' + IntToStr(FQueueIdentifier); // Fix align of options panel and dialog size at start. if not pnlSelector.Visible then pnlOptions.Top := pnlOptions.Top - (pnlSelector.Height + pnlSelector.BorderSpacing.Top + pnlSelector.BorderSpacing.Bottom); // Operation options. if Assigned(FOperationOptionsUIClass) then begin FOperationOptionsUI := FOperationOptionsUIClass.Create(Self, FFileSource); FOperationOptionsUI.Parent := grpOptions; FOperationOptionsUI.Align := alClient; end else btnOptions.Visible := False; pnlOptions.Visible:= false; HMForm := HotMan.Register(Self, HotkeysCategory); Hotkey := HMForm.Hotkeys.FindByCommand('cm_AddToQueue'); if Assigned(Hotkey) then btnAddToQueue.Caption := btnAddToQueue.Caption + ' (' + ShortcutsToText(Hotkey.Shortcuts) + ')'; end; procedure TfrmCopyDlg.FormDestroy(Sender: TObject); begin HotMan.UnRegister(Self); end; procedure TfrmCopyDlg.ShowOptions(bShow: Boolean); begin pnlOptions.Visible := bShow; UpdateSize; end; procedure TfrmCopyDlg.UpdateSize; begin if pnlOptions.Visible then Self.Height := pnlOptions.Top + pnlOptions.Height + pnlOptions.BorderSpacing.Top + pnlOptions.BorderSpacing.Bottom else Self.Height := pnlOptions.Top; end; initialization TFormCommands.RegisterCommandsForm(TfrmCopyDlg, HotkeysCategory, @rsHotkeyCategoryCopyMoveDialog); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdeletedlg.lfm�����������������������������������������������������������������0000644�0001750�0000144�00000002551�14743153644�016177� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmDeleteDlg: TfrmDeleteDlg Left = 347 Height = 86 Top = 169 Width = 415 ActiveControl = btnOK AutoSize = True BorderStyle = bsDialog ClientHeight = 86 ClientWidth = 415 Constraints.MaxWidth = 800 Constraints.MinWidth = 400 KeyPreview = True OnKeyDown = FormKeyDown Position = poScreenCenter inherited pnlContent: TPanel Height = 1 Width = 399 Align = alTop ClientHeight = 1 ClientWidth = 399 ParentColor = True object lblMessage: TLabel[0] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = pnlContent AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom Left = 0 Height = 1 Top = 0 Width = 399 Anchors = [akTop, akLeft, akRight] ParentColor = False ShowAccelChar = False WordWrap = True end end inherited pnlButtons: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = pnlContent AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Top = 41 Width = 399 Align = alNone Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 32 ClientWidth = 399 ParentColor = True inherited btnCancel: TBitBtn Left = 221 end inherited btnOK: TBitBtn Left = 311 end end end �������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdeletedlg.pas�����������������������������������������������������������������0000644�0001750�0000144�00000002376�14743153644�016211� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fDeleteDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, Buttons, Menus, StdCtrls, fButtonForm, uOperationsManager, uFileSource; type { TfrmDeleteDlg } TfrmDeleteDlg = class(TfrmButtonForm) lblMessage: TLabel; procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); private { private declarations } public { public declarations } end; function ShowDeleteDialog(const Message: String; FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier): Boolean; implementation uses LCLType; function ShowDeleteDialog(const Message: String; FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier): Boolean; begin with TfrmDeleteDlg.Create(Application, FileSource) do begin Caption:= Application.Title; lblMessage.Caption:= Message; Result:= ShowModal = mrOK; QueueId:= QueueIdentifier; Free; end; end; {$R *.lfm} { TfrmDeleteDlg } procedure TfrmDeleteDlg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (Key = VK_RETURN) and (ssShift in Shift) then begin btnOK.Click; Key:= 0; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdescredit.lfm�����������������������������������������������������������������0000644�0001750�0000144�00000007405�14743153644�016217� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmDescrEdit: TfrmDescrEdit Left = 290 Height = 300 Top = 175 Width = 400 ActiveControl = memDescr BorderIcons = [biSystemMenu, biMaximize] Caption = 'File/folder comment' ClientHeight = 300 ClientWidth = 400 Constraints.MinHeight = 300 Constraints.MinWidth = 400 OnCreate = FormCreate OnDestroy = FormDestroy Position = poScreenCenter SessionProperties = 'Height;WindowState;Width' LCLVersion = '2.0.4.0' object lblEditCommentFor: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 12 Height = 15 Top = 12 Width = 96 BorderSpacing.Left = 12 BorderSpacing.Top = 12 Caption = 'E&dit comment for:' FocusControl = memDescr ParentColor = False end object lblEncoding: TLabel AnchorSideLeft.Control = memDescr AnchorSideTop.Side = asrCenter AnchorSideBottom.Control = cbEncoding AnchorSideBottom.Side = asrCenter Left = 12 Height = 15 Top = 252 Width = 53 Anchors = [akLeft, akBottom] Caption = '&Encoding:' ParentColor = False end object lblFileName: TLabel AnchorSideLeft.Control = lblEditCommentFor AnchorSideTop.Control = lblEditCommentFor AnchorSideTop.Side = asrBottom Left = 12 Height = 15 Top = 33 Width = 15 BorderSpacing.Top = 6 Caption = '???' Font.Style = [fsBold] ParentColor = False ParentFont = False end object memDescr: TMemo AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblFileName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = KASButtonPanel Left = 12 Height = 184 Top = 56 Width = 376 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 12 BorderSpacing.Top = 8 BorderSpacing.Right = 12 BorderSpacing.Bottom = 12 OnKeyDown = memDescrKeyDown TabOrder = 0 end object KASButtonPanel: TKASButtonPanel AnchorSideRight.Control = memDescr AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 226 Height = 41 Top = 273 Width = 207 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.Bottom = 18 BevelOuter = bvNone ClientHeight = 41 ClientWidth = 207 TabOrder = 1 object btnOK: TBitBtn AnchorSideTop.Control = btnCancel AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCancel Left = 0 Height = 30 Top = 0 Width = 90 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 6 Caption = '&OK' Default = True Kind = bkOK ModalResult = 1 TabOrder = 0 end object btnCancel: TBitBtn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = KASButtonPanel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = KASButtonPanel AnchorSideBottom.Side = asrBottom Left = 107 Height = 30 Top = 0 Width = 90 Anchors = [akRight, akBottom] AutoSize = True Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 TabOrder = 1 end end object cbEncoding: TStaticText AnchorSideLeft.Control = lblEncoding AnchorSideLeft.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = KASButtonPanel AnchorSideBottom.Side = asrCenter Left = 69 Height = 1 Top = 266 Width = 100 Anchors = [akLeft, akBottom] AutoSize = True BorderSpacing.Left = 4 TabOrder = 2 end object ActionList: TActionList Left = 348 Top = 9 object actSaveDescription: TAction Caption = 'Save Description' OnExecute = actExecute end end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdescredit.lrj�����������������������������������������������������������������0000644�0001750�0000144�00000001747�14743153644�016233� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":25983908,"name":"tfrmdescredit.caption","sourcebytes":[70,105,108,101,47,102,111,108,100,101,114,32,99,111,109,109,101,110,116],"value":"File/folder comment"}, {"hash":127690170,"name":"tfrmdescredit.lbleditcommentfor.caption","sourcebytes":[69,38,100,105,116,32,99,111,109,109,101,110,116,32,102,111,114,58],"value":"E&dit comment for:"}, {"hash":173566186,"name":"tfrmdescredit.lblencoding.caption","sourcebytes":[38,69,110,99,111,100,105,110,103,58],"value":"&Encoding:"}, {"hash":17199,"name":"tfrmdescredit.lblfilename.caption","sourcebytes":[63,63,63],"value":"???"}, {"hash":11067,"name":"tfrmdescredit.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmdescredit.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":4783918,"name":"tfrmdescredit.actsavedescription.caption","sourcebytes":[83,97,118,101,32,68,101,115,99,114,105,112,116,105,111,110],"value":"Save Description"} ]} �������������������������doublecmd-1.1.22/src/fdescredit.pas�����������������������������������������������������������������0000644�0001750�0000144�00000011176�14743153644�016224� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Dialog for editing file comments. Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fDescrEdit; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, StdCtrls, Buttons, ActnList, uDescr, uFormCommands, KASButtonPanel, uFileView; type { TfrmDescrEdit } TfrmDescrEdit = class(TForm, IFormCommands) actSaveDescription: TAction; ActionList: TActionList; btnOK: TBitBtn; btnCancel: TBitBtn; cbEncoding: TStaticText; KASButtonPanel: TKASButtonPanel; lblFileName: TLabel; lblEncoding: TLabel; lblEditCommentFor: TLabel; memDescr: TMemo; procedure actExecute(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure memDescrKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState); private FDescr: TDescription; FCommands: TFormCommands; procedure DisplayEncoding; property Commands: TFormCommands read FCommands implements IFormCommands; public constructor Create(TheOwner: TComponent); override; published procedure cm_SaveDescription(const {%H-}Params: array of string); end; function ShowDescrEditDlg(const sFileName: String; FileView: TFileView): Boolean; implementation {$R *.lfm} uses TypInfo, LCLType, LConvEncoding, DCStrUtils, uHotkeyManager, uLng, uGlobs, uFileSystemFileSource, uConvEncoding; const HotkeysCategory = 'Edit Comment Dialog'; function ShowDescrEditDlg(const sFileName: String; FileView: TFileView): Boolean; const nbsp = #194#160; var FileSystem: Boolean; begin Result:= False; FileSystem:= FileView.FileSource.IsClass(TFileSystemFileSource); with TfrmDescrEdit.Create(Application) do try if not FileSystem then FDescr:= TDescription.Create(False) else begin FDescr:= (FileView.FileSource as TFileSystemFileSource).Description; FDescr.Reset; end; lblFileName.Caption:= sFileName; // Read description memDescr.Lines.Text:= StringReplace(FDescr.ReadDescription(sFileName), nbsp, LineEnding, [rfReplaceAll]); DisplayEncoding; if ShowModal = mrOK then begin if Length(memDescr.Lines.Text) = 0 then FDescr.DeleteDescription(sFileName) else begin FDescr.WriteDescription(sFileName, StringReplace(memDescr.Lines.Text, LineEnding, nbsp, [rfReplaceAll])); end; FDescr.SaveDescription; FileView.Reload(True); Result:= True; end; if not FileSystem then FDescr.Free; finally Free; end; end; { TfrmDescrEdit } procedure TfrmDescrEdit.FormCreate(Sender: TObject); var HMForm: THMForm; Hotkey: THotkey; begin // Initialize property storage InitPropStorage(Self); HMForm := HotMan.Register(Self, HotkeysCategory); Hotkey := HMForm.Hotkeys.FindByCommand('cm_SaveDescription'); if Assigned(Hotkey) then btnOK.Caption := btnOK.Caption + ' (' + ShortcutsToText(Hotkey.Shortcuts) + ')'; end; procedure TfrmDescrEdit.FormDestroy(Sender: TObject); begin HotMan.UnRegister(Self); end; procedure TfrmDescrEdit.memDescrKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then ModalResult:= btnCancel.ModalResult; end; procedure TfrmDescrEdit.DisplayEncoding; begin cbEncoding.Caption:= Copy(GetEnumName(System.TypeInfo(TMacroEncoding), Ord(FDescr.Encoding)), 3 , MaxInt); end; constructor TfrmDescrEdit.Create(TheOwner: TComponent); begin inherited Create(TheOwner); FCommands := TFormCommands.Create(Self, actionList); end; procedure TfrmDescrEdit.cm_SaveDescription(const Params: array of string); begin ModalResult:= btnOK.ModalResult; end; procedure TfrmDescrEdit.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; initialization TFormCommands.RegisterCommandsForm(TfrmDescrEdit, HotkeysCategory, @rsHotkeyCategoryEditCommentDialog); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdialogbox.pas�����������������������������������������������������������������0000644�0001750�0000144�00000072144�14743153644�016230� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains realization of Dialog API functions. Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fDialogBox; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Types, Buttons, ExtCtrls, EditBtn, Extension, ComCtrls, DividerBevel, SynEdit; type { TDialogBox } TDialogBox = class(TForm) DialogTimer: TTimer; DialogButton: TButton; DialogBitBtn: TBitBtn; DialogFileNameEdit: TFileNameEdit; DialogDirectoryEdit: TDirectoryEdit; DialogComboBox: TComboBox; DialogListBox: TListBox; DialogCheckBox: TCheckBox; DialogGroupBox: TGroupBox; DialogLabel: TLabel; DialogPanel: TPanel; DialogEdit: TEdit; DialogMemo: TMemo; DialogImage: TImage; DialogSynEdit: TSynEdit; DialogTabSheet: TTabSheet; DialogScrollBox: TScrollBox; DialogRadioGroup: TRadioGroup; DialogPageControl: TPageControl; DialogProgressBar: TProgressBar; DialogDividerBevel: TDividerBevel; // Dialog events procedure DialogBoxShow(Sender: TObject); procedure DialogBoxClose(Sender: TObject; var CloseAction: TCloseAction); // Button events procedure ButtonClick(Sender: TObject); procedure ButtonEnter(Sender: TObject); procedure ButtonExit(Sender: TObject); procedure ButtonKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure ButtonKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); // ComboBox events procedure ComboBoxClick(Sender: TObject); procedure ComboBoxDblClick(Sender: TObject); procedure ComboBoxChange(Sender: TObject); procedure ComboBoxEnter(Sender: TObject); procedure ComboBoxExit(Sender: TObject); procedure ComboBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure ComboBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); // Edit events procedure EditClick(Sender: TObject); procedure EditDblClick(Sender: TObject); procedure EditChange(Sender: TObject); procedure EditEnter(Sender: TObject); procedure EditExit(Sender: TObject); procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure EditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); // ListBox events procedure ListBoxClick(Sender: TObject); procedure ListBoxDblClick(Sender: TObject); procedure ListBoxSelectionChange(Sender: TObject; User: boolean); procedure ListBoxEnter(Sender: TObject); procedure ListBoxExit(Sender: TObject); procedure ListBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure ListBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); // CheckBox events procedure CheckBoxChange(Sender: TObject); // Timer events procedure TimerTimer(Sender: TObject); private FRect: TRect; FText: String; FSelf: UIntPtr; FLRSData: String; FResult: LongBool; FDlgProc: TDlgProc; FTranslator: TAbstractTranslator; protected procedure ShowDialogBox; procedure ProcessResource; override; function InitResourceComponent(Instance: TComponent; RootAncestor: TClass): Boolean; public constructor Create(const LRSData: String; DlgProc: TDlgProc); reintroduce; destructor Destroy; override; end; function InputBox(Caption, Prompt: PAnsiChar; MaskInput: LongBool; Value: PAnsiChar; ValueMaxLen: Integer): LongBool; dcpcall; function MessageBox(Text, Caption: PAnsiChar; Flags: Longint): Integer; dcpcall; function MsgChoiceBox(Text, Caption: PAnsiChar; Buttons: PPAnsiChar; BtnDef, BtnEsc: Integer): Integer; dcpcall; function DialogBoxLFM(LFMData: Pointer; DataSize: LongWord; DlgProc: TDlgProc): LongBool; dcpcall; function DialogBoxLRS(LRSData: Pointer; DataSize: LongWord; DlgProc: TDlgProc): LongBool; dcpcall; function DialogBoxLFMFile(lfmFileName: PAnsiChar; DlgProc: TDlgProc): LongBool; dcpcall; function DialogBoxParam(Data: Pointer; DataSize: LongWord; DlgProc: TDlgProc; Flags: UInt32; UserData, Reserved: Pointer): UIntPtr; dcpcall; function SendDlgMsg(pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall; implementation uses LCLStrConsts, LazFileUtils, DCClassesUtf8, DCOSUtils, DCStrUtils, uShowMsg, uDebug, uTranslator, uGlobs, uFileProcs; type TControlProtected = class(TControl); function InputBox(Caption, Prompt: PAnsiChar; MaskInput: LongBool; Value: PAnsiChar; ValueMaxLen: Integer): LongBool; dcpcall; var sValue: String; begin sValue:= StrPas(Value); Result:= ShowInputQuery(Caption, Prompt, MaskInput, sValue); if Result then StrLCopy(Value, PAnsiChar(sValue), ValueMaxLen); end; function MessageBox(Text, Caption: PAnsiChar; Flags: Longint): Integer; dcpcall; begin Result:= ShowMessageBox(Text, Caption, Flags); end; function MsgChoiceBox(Text, Caption: PAnsiChar; Buttons: PPAnsiChar; BtnDef, BtnEsc: Integer): Integer; dcpcall; var AButtons: TStringArray; begin AButtons:= Default(TStringArray); while (Buttons^ <> nil) do begin AddString(AButtons, Buttons^); Inc(Buttons); end; Result:= uShowMsg.MsgChoiceBox(nil, Text, Caption, AButtons, BtnDef, BtnEsc); end; function LFMToLRS(const LFMData: String): String; var LFMStream: TStringStream = nil; LRSStream: TStringStream = nil; begin try LRSStream:= TStringStream.Create(''); LFMStream:= TStringStream.Create(LFMData); LRSObjectTextToBinary(LFMStream, LRSStream); Result:= LRSStream.DataString; finally FreeAndNil(LFMStream); FreeAndNil(LRSStream); end; end; function DialogBox(const LRSData: String; DlgProc: TDlgProc; UserData: Pointer): LongBool; var Dialog: TDialogBox; Data: PtrInt absolute UserData; begin Dialog:= TDialogBox.Create(LRSData, DlgProc); try with Dialog do begin Tag:= Data; TThread.Synchronize(nil, @ShowDialogBox); Result:= FResult; end; finally FreeAndNil(Dialog); end; end; function DialogBoxLFM(LFMData: Pointer; DataSize: LongWord; DlgProc: TDlgProc): LongBool; dcpcall; var DataString: String; begin if Assigned(LFMData) and (DataSize > 0) then begin SetString(DataString, LFMData, DataSize); Result := DialogBox(LFMToLRS(DataString), DlgProc, nil); end else Result := False; end; function DialogBoxLRS(LRSData: Pointer; DataSize: LongWord; DlgProc: TDlgProc): LongBool; dcpcall; var DataString: String; begin if Assigned(LRSData) and (DataSize > 0) then begin SetString(DataString, LRSData, DataSize); Result := DialogBox(DataString, DlgProc, nil); end else Result := False; end; function DialogBoxLFMFile(lfmFileName: PAnsiChar; DlgProc: TDlgProc): LongBool; dcpcall; var DataString: String; begin if (lfmFileName = nil) then Result := False else begin DataString := mbReadFileToString(lfmFileName); Result := DialogBox(LFMToLRS(DataString), DlgProc, nil); end; end; function DialogBoxParam(Data: Pointer; DataSize: LongWord; DlgProc: TDlgProc; Flags: UInt32; UserData, Reserved: Pointer): UIntPtr; dcpcall; var DataString: String; begin if (Data = nil) then Exit(0); if (DataSize = 0) then Exit(0); SetString(DataString, Data, DataSize); if (Flags and DB_FILENAME <> 0) then begin DataString:= LFMToLRS(mbReadFileToString(DataString)); end else if (Flags and DB_LRS = 0) then begin DataString:= LFMToLRS(DataString); end; Result:= UIntPtr(DialogBox(DataString, DlgProc, UserData)); end; function SendDlgMsg(pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall; var Key: Word; AText: String; Component: TComponent; lText: PAnsiChar absolute lParam; wText: PAnsiChar absolute wParam; pResult: Pointer absolute Result; DialogBox: TDialogBox absolute pDlg; Control: TControl absolute Component; begin // find component by name if (DlgItemName = nil) then Component:= DialogBox else begin Component:= DialogBox.FindComponent(DlgItemName); if (Component = nil) then Exit(-1); end; // process message case Msg of DM_CLOSE: begin DialogBox.Close; if wParam <> -1 then DialogBox.ModalResult:= wParam; end; DM_ENABLE: begin if (Component is TTimer) then begin Result:= PtrInt(TTimer(Component).Enabled); if wParam <> -1 then TTimer(Component).Enabled:= Boolean(wParam); end else begin Result:= PtrInt(Control.Enabled); if wParam <> -1 then Control.Enabled:= Boolean(wParam); end; end; DM_GETCHECK: begin if Control is TCheckBox then Result:= PtrInt((Control as TCheckBox).State); if Control is TRadioButton then Result := PtrInt((Control as TRadioButton).Checked); end; DM_GETDLGBOUNDS: begin with DialogBox do begin FRect.Left:= DialogBox.Left; FRect.Top:= DialogBox.Top; FRect.Right:= DialogBox.Left + DialogBox.Width; FRect.Bottom:= DialogBox.Top + DialogBox.Height; pResult:= @FRect; end; end; DM_GETDLGDATA: begin Result:= DialogBox.Tag; end; DM_GETDROPPEDDOWN: begin if Control is TComboBox then Result:= PtrInt((Control as TComboBox).DroppedDown); end; DM_GETITEMBOUNDS: begin with DialogBox do begin FRect.Left:= Control.Left; FRect.Top:= Control.Top; FRect.Right:= Control.Left + Control.Width; FRect.Bottom:= Control.Top + Control.Height; pResult:= @FRect; end; end; DM_GETITEMDATA: begin Result:= Control.Tag; end; DM_LISTADD: begin AText:= StrPas(wText); if Control is TComboBox then Result:= TComboBox(Control).Items.AddObject(AText, TObject(lText)) else if Control is TListBox then Result:= TListBox(Control).Items.AddObject(AText, TObject(lText)) else if Control is TMemo then Result:= TMemo(Control).Lines.AddObject(AText, TObject(lText)) else if Control is TSynEdit then Result:= TSynEdit(Control).Lines.AddObject(AText, TObject(lText)); end; DM_LISTADDSTR: begin AText:= StrPas(wText); if Control is TComboBox then Result:= TComboBox(Control).Items.Add(AText) else if Control is TListBox then Result:= TListBox(Control).Items.Add(AText) else if Control is TMemo then Result:= TMemo(Control).Lines.Add(AText) else if Control is TSynEdit then Result:= TSynEdit(Control).Lines.Add(AText); end; DM_LISTDELETE: begin if Control is TComboBox then TComboBox(Control).Items.Delete(wParam) else if Control is TListBox then TListBox(Control).Items.Delete(wParam) else if Control is TMemo then TMemo(Control).Lines.Delete(wParam) else if Control is TSynEdit then TSynEdit(Control).Lines.Delete(wParam); end; DM_LISTINDEXOF: begin AText:= StrPas(lText); if Control is TComboBox then Result:= TComboBox(Control).Items.IndexOf(AText) else if Control is TListBox then Result:= TListBox(Control).Items.IndexOf(AText) else if Control is TMemo then Result:= TMemo(Control).Lines.IndexOf(AText) else if Control is TSynEdit then Result:= TSynEdit(Control).Lines.IndexOf(AText); end; DM_LISTINSERT: begin AText:= StrPas(lText); if Control is TComboBox then TComboBox(Control).Items.Insert(wParam, AText) else if Control is TListBox then TListBox(Control).Items.Insert(wParam, AText) else if Control is TMemo then TMemo(Control).Lines.Insert(wParam, AText) else if Control is TSynEdit then TSynEdit(Control).Lines.Insert(wParam, AText); end; DM_LISTGETCOUNT: begin if Control is TComboBox then Result:= TComboBox(Control).Items.Count else if Control is TListBox then Result:= TListBox(Control).Items.Count else if Control is TMemo then Result:= TMemo(Control).Lines.Count else if Control is TSynEdit then Result:= TSynEdit(Control).Lines.Count; end; DM_LISTGETDATA: begin if Control is TComboBox then Result:= PtrInt(TComboBox(Control).Items.Objects[wParam]) else if Control is TListBox then Result:= PtrInt(TListBox(Control).Items.Objects[wParam]) else if Control is TMemo then Result:= PtrInt(TMemo(Control).Lines.Objects[wParam]) else if Control is TSynEdit then Result:= PtrInt(TSynEdit(Control).Lines.Objects[wParam]); end; DM_LISTGETITEM: begin with DialogBox do begin if Control is TComboBox then FText:= TComboBox(Control).Items[wParam] else if Control is TListBox then FText:= TListBox(Control).Items[wParam] else if Control is TMemo then FText:= TMemo(Control).Lines[wParam] else if Control is TSynEdit then FText:= TSynEdit(Control).Lines[wParam]; pResult:= PAnsiChar(FText); end; end; DM_LISTGETITEMINDEX: begin Result:= -1; if Control is TComboBox then Result:= TComboBox(Control).ItemIndex else if Control is TListBox then Result:= TListBox(Control).ItemIndex else if Control is TRadioGroup then Result:= TRadioGroup(Control).ItemIndex; end; DM_LISTSETITEMINDEX: begin if Control is TComboBox then TComboBox(Control).ItemIndex:= wParam else if Control is TListBox then TListBox(Control).ItemIndex:= wParam else if Control is TRadioGroup then TRadioGroup(Control).ItemIndex:= wParam; end; DM_LISTUPDATE: begin AText:= StrPas(lText); if Control is TComboBox then TComboBox(Control).Items[wParam]:= AText else if Control is TListBox then TListBox(Control).Items[wParam]:= AText else if Control is TMemo then TMemo(Control).Lines[wParam]:= AText else if Control is TSynEdit then TSynEdit(Control).Lines[wParam]:= AText; end; DM_LISTCLEAR: begin if Control is TComboBox then TComboBox(Control).Clear else if Control is TListBox then TListBox(Control).Clear else if Control is TMemo then TMemo(Control).Clear else if Control is TSynEdit then TSynEdit(Control).Clear; end; DM_GETTEXT: begin with DialogBox do begin if Control is TButton then FText:= TButton(Control).Caption else if Control is TComboBox then FText:= TComboBox(Control).Text else if Control is TCheckBox then FText:= TCheckBox(Control).Caption else if Control is TMemo then FText:= TMemo(Control).Text else if Control is TEdit then FText:= TEdit(Control).Text else if Control is TGroupBox then FText:= TGroupBox(Control).Caption else if Control is TLabel then FText:= TLabel(Control).Caption else if Control is TFileNameEdit then FText:= TFileNameEdit(Control).Text else begin FText:= TControlProtected(Control).Text end; pResult:= PAnsiChar(FText); end; end; DM_KEYDOWN: begin Key:= wParam; DialogBox.KeyDown(Key, GetKeyShiftState); Result:= Key; end; DM_KEYUP: begin Key:= wParam; DialogBox.KeyUp(Key, GetKeyShiftState); Result:= Key; end; DM_REDRAW: begin DialogBox.Repaint; end; DM_SETCHECK: begin if Control is TCheckBox then begin Result:= PtrInt((Control as TCheckBox).State); (Control as TCheckBox).State:= TCheckBoxState(wParam) end; if Control is TRadioButton then begin Result := PtrInt((Control as TRadioButton).Checked); (Control as TRadioButton).Checked:= Boolean(wParam); end; end; DM_LISTSETDATA: begin if Control is TComboBox then TComboBox(Control).Items.Objects[wParam]:= TObject(lText) else if Control is TListBox then TListBox(Control).Items.Objects[wParam]:= TObject(lText) else if Control is TMemo then TMemo(Control).Lines.Objects[wParam]:= TObject(lText) else if Control is TSynEdit then TSynEdit(Control).Lines.Objects[wParam]:= TObject(lText); end; DM_SETDLGBOUNDS: begin with DialogBox do begin FRect:= PRect(wText)^; DialogBox.Left:= FRect.Left; DialogBox.Top:= FRect.Top; DialogBox.Width:= FRect.Right - FRect.Left; DialogBox.Height:= FRect.Bottom - FRect.Top; end; end; DM_SETDLGDATA: begin Result:= DialogBox.Tag; DialogBox.Tag:= wParam; end; DM_SETDROPPEDDOWN: begin if Control is TComboBox then (Control as TComboBox).DroppedDown:= Boolean(wParam); end; DM_SETFOCUS: begin if Control.Visible then (Control as TWinControl).SetFocus; end; DM_SETITEMBOUNDS: begin with DialogBox do begin FRect:= PRect(wText)^; Control.Left:= FRect.Left; Control.Top:= FRect.Top; Control.Width:= FRect.Right - FRect.Left; Control.Height:= FRect.Bottom - FRect.Top; end; end; DM_SETITEMDATA: begin Control.Tag:= wParam; end; DM_SETMAXTEXTLENGTH: begin Result:= -1; if Control is TComboBox then begin Result:= (Control as TComboBox).MaxLength; (Control as TComboBox).MaxLength:= wParam; end; if Control is TEdit then begin Result:= (Control as TEdit).MaxLength; (Control as TEdit).MaxLength:= wParam; end; end; DM_SETTEXT: begin AText:= StrPas(wText); if Control is TButton then TButton(Control).Caption:= AText else if Control is TComboBox then TComboBox(Control).Text:= AText else if Control is TCheckBox then TCheckBox(Control).Caption:= AText else if Control is TMemo then TMemo(Control).Text:= AText else if Control is TEdit then TEdit(Control).Text:= AText else if Control is TGroupBox then TGroupBox(Control).Caption:= AText else if Control is TLabel then TLabel(Control).Caption:= AText else if Control is TFileNameEdit then TFileNameEdit(Control).Text:= AText else begin TControlProtected(Control).Text:= AText; end; end; DM_SHOWDIALOG: begin if wParam = 0 then DialogBox.Hide; if wParam = 1 then DialogBox.Show; end; DM_SHOWITEM: begin Result:= PtrInt(Control.Visible); if wParam <> -1 then Control.Visible:= Boolean(wParam); end; DM_SETPROGRESSVALUE: begin if (Control is TProgressBar) then begin TProgressBar(Control).Position:= wParam; end; end; DM_SETPROGRESSSTYLE: begin if (Control is TProgressBar) then begin TProgressBar(Control).Style:= TProgressBarStyle(wParam); end; end; DM_SETPASSWORDCHAR: begin if (Control is TCustomEdit) then begin TCustomEdit(Control).PasswordChar:= Char(wParam); end; end; DM_TIMERSETINTERVAL: begin if (Component is TTimer) then begin TTimer(Component).Interval:= wParam; end; end; end; end; { TDialogBox } procedure TDialogBox.ShowDialogBox; begin FResult:= (ShowModal = mrOK); end; procedure TDialogBox.ProcessResource; begin if not InitResourceComponent(Self, TForm) then if RequireDerivedFormResource then raise EResNotFound.CreateFmt(rsFormResourceSNotFoundForResourcelessFormsCreateNew, [ClassName]) else DCDebug(Format(rsFormResourceSNotFoundForResourcelessFormsCreateNew, [ClassName])); end; function TDialogBox.InitResourceComponent(Instance: TComponent; RootAncestor: TClass): Boolean; function InitComponent(ClassType: TClass): Boolean; var Stream: TStream; Reader: TReader; DestroyDriver: Boolean; Driver: TAbstractObjectReader; begin Result := False; if (ClassType = TComponent) or (ClassType = RootAncestor) then Exit; if Assigned(ClassType.ClassParent) then Result := InitComponent(ClassType.ClassParent); Stream := TStringStream.Create(FLRSData); try //DCDebug('Form Stream "', ClassType.ClassName, '"'); DestroyDriver := False; Reader := CreateLRSReader(Stream, DestroyDriver); if Assigned(FTranslator) then begin Reader.OnReadStringProperty:= @FTranslator.TranslateStringProperty; end; try Reader.ReadRootComponent(Instance); finally Driver := Reader.Driver; Reader.Free; if DestroyDriver then Driver.Free; end; finally Stream.Free; end; Result := True; end; begin if Instance.ComponentState * [csLoading, csInline] <> [] then begin // global loading not needed Result := InitComponent(Instance.ClassType); end else try BeginGlobalLoading; Result := InitComponent(Instance.ClassType); NotifyGlobalLoading; finally EndGlobalLoading; end; end; constructor TDialogBox.Create(const LRSData: String; DlgProc: TDlgProc); var Path: String; Language: String; FileName: String; begin FLRSData:= LRSData; FDlgProc:= DlgProc; FSelf:= UIntPtr(Self); FileName:= mbGetModuleName(DlgProc); Path:= ExtractFilePath(FileName) + 'language' + PathDelim; Language:= ExtractFileExt(ExtractFileNameOnly(gPOFileName)); FileName:= Path + ExtractFileNameOnly(FileName) + Language + '.po'; if mbFileExists(FileName) then FTranslator:= TTranslator.Create(FileName); inherited Create(Screen.ActiveForm); end; destructor TDialogBox.Destroy; begin inherited Destroy; FTranslator.Free; end; procedure TDialogBox.DialogBoxShow(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_INITDIALOG,0,0); end; procedure TDialogBox.DialogBoxClose(Sender: TObject; var CloseAction: TCloseAction); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CLOSE, 0, 0); end; procedure TDialogBox.ButtonClick(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CLICK,0,0); end; procedure TDialogBox.ButtonEnter(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_GOTFOCUS,0,0); end; procedure TDialogBox.ButtonExit(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KILLFOCUS,0,0); end; procedure TDialogBox.ButtonKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYDOWN, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.ButtonKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYUP, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.ComboBoxClick(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CLICK,PtrInt((Sender as TComboBox).ItemIndex),0); end; procedure TDialogBox.ComboBoxDblClick(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_DBLCLICK,PtrInt((Sender as TComboBox).ItemIndex),0); end; procedure TDialogBox.ComboBoxChange(Sender: TObject); begin if Assigned(fDlgProc) then begin fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CHANGE, PtrInt((Sender as TComboBox).ItemIndex),0); end; end; procedure TDialogBox.ComboBoxEnter(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_GOTFOCUS,0,0); end; procedure TDialogBox.ComboBoxExit(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KILLFOCUS,0,0); end; procedure TDialogBox.ComboBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYDOWN, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.ComboBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYUP, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.EditClick(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CLICK,0,0); end; procedure TDialogBox.EditDblClick(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_DBLCLICK,0,0); end; procedure TDialogBox.EditChange(Sender: TObject); var sText: String; begin if Assigned(fDlgProc) then begin sText:= (Sender as TEdit).Text; fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CHANGE, PtrInt(PAnsiChar(sText)), 0); end; end; procedure TDialogBox.EditEnter(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_GOTFOCUS,0,0); end; procedure TDialogBox.EditExit(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KILLFOCUS,0,0); end; procedure TDialogBox.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYDOWN, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.EditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYUP, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.ListBoxClick(Sender: TObject); begin if Assigned(fDlgProc) then begin fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CLICK, PtrInt((Sender as TListBox).ItemIndex),0); end; end; procedure TDialogBox.ListBoxDblClick(Sender: TObject); begin if Assigned(fDlgProc) then begin fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_DBLCLICK, PtrInt((Sender as TListBox).ItemIndex),0); end; end; procedure TDialogBox.ListBoxSelectionChange(Sender: TObject; User: boolean); begin if Assigned(fDlgProc) then begin fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CHANGE, PtrInt((Sender as TListBox).ItemIndex),0); end; end; procedure TDialogBox.ListBoxEnter(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_GOTFOCUS,0,0); end; procedure TDialogBox.ListBoxExit(Sender: TObject); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KILLFOCUS,0,0); end; procedure TDialogBox.ListBoxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYDOWN, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.ListBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Assigned(fDlgProc) then fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_KEYUP, PtrInt(@Key), Integer(Shift)); end; procedure TDialogBox.CheckBoxChange(Sender: TObject); begin if Assigned(fDlgProc) then begin fDlgProc(FSelf, PAnsiChar((Sender as TControl).Name), DN_CHANGE, PtrInt((Sender as TCheckBox).Checked),0); end; end; procedure TDialogBox.TimerTimer(Sender: TObject); begin if Assigned(fDlgProc) then begin fDlgProc(FSelf, PAnsiChar((Sender as TTimer).Name), DN_TIMER, 0, 0); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdiffer.lfm��������������������������������������������������������������������0000644�0001750�0000144�00000047243�14743153644�015514� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmDiffer: TfrmDiffer Left = 237 Height = 369 Top = 142 Width = 760 Caption = 'Compare files' ClientHeight = 349 ClientWidth = 760 Menu = MainMenu OnClose = FormClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnKeyDown = FormKeyDown OnResize = FormResize SessionProperties = 'Height;Left;Top;Width;WindowState' ShowHint = True ShowInTaskBar = stAlways LCLVersion = '2.2.0.4' object ToolBar: TToolBar Left = 0 Height = 22 Top = 0 Width = 760 AutoSize = True ButtonHeight = 20 ButtonWidth = 20 Images = dmComData.ilEditorImages ParentShowHint = False ShowHint = True TabOrder = 0 object btnSave: TToolButton Left = 21 Top = 2 Action = actSave end object btnSaveAs: TToolButton Left = 41 Top = 2 Action = actSaveAs end object Divider1: TToolButton Left = 61 Height = 20 Top = 2 Style = tbsDivider end object btnCompare: TToolButton Left = 66 Top = 2 Action = actStartCompare end object btnLast: TToolButton Left = 156 Top = 2 Action = actLastDifference end object btnNext: TToolButton Left = 111 Top = 2 Action = actNextDifference end object btnPrev: TToolButton Left = 131 Top = 2 Action = actPrevDifference end object btnFirst: TToolButton Left = 176 Top = 2 Action = actFirstDifference end object Divider2: TToolButton Left = 106 Height = 20 Top = 2 Style = tbsDivider end object Divider3: TToolButton Left = 151 Height = 20 Top = 2 Style = tbsDivider end object btnCancelCompare: TToolButton Left = 86 Top = 2 Action = actCancelCompare end object Divider4: TToolButton Left = 196 Height = 20 Top = 2 Style = tbsDivider end object btnReload: TToolButton Left = 1 Top = 2 Action = actReload end object btnCopyRightToLeft: TToolButton Left = 201 Top = 2 Action = actCopyRightToLeft end object btnCopyLeftToRight: TToolButton Left = 221 Top = 2 Action = actCopyLeftToRight end object Divider5: TToolButton Left = 241 Height = 20 Top = 2 Style = tbsSeparator end object btnEditUndo: TToolButton Left = 249 Top = 2 Action = actEditUndo end object btnEditRedo: TToolButton Left = 269 Top = 2 Action = actEditRedo end end object pnlLeft: TPanel Left = 0 Height = 304 Top = 22 Width = 379 Align = alLeft BevelOuter = bvNone ClientHeight = 304 ClientWidth = 379 TabOrder = 1 object pnlLeftBox: TPanel Left = 0 Height = 23 Top = 0 Width = 379 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 23 ClientWidth = 379 FullRepaint = False ParentShowHint = False ShowHint = True TabOrder = 0 object edtFileNameLeft: TFileNameEdit AnchorSideLeft.Control = btnLeftEncoding AnchorSideLeft.Side = asrBottom Left = 69 Height = 23 Top = 0 Width = 285 OnAcceptFileName = edtFileNameLeftAcceptFileName DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 0 end object btnLeftEncoding: TSpeedButton AnchorSideLeft.Control = btnLeftSaveAs AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlLeftBox AnchorSideBottom.Control = edtFileNameLeft AnchorSideBottom.Side = asrBottom Left = 46 Height = 23 Hint = 'Encoding' Top = 0 Width = 23 Anchors = [akTop, akLeft, akBottom] Images = dmComData.ilEditorImages ImageIndex = 44 OnClick = btnLeftEncodingClick end object btnLeftSave: TSpeedButton AnchorSideLeft.Control = pnlLeftBox AnchorSideTop.Control = pnlLeftBox AnchorSideBottom.Control = edtFileNameLeft AnchorSideBottom.Side = asrBottom Left = 0 Height = 23 Top = 0 Width = 23 Action = actSaveLeft Anchors = [akTop, akLeft, akBottom] Images = dmComData.ilEditorImages ImageIndex = 34 ShowCaption = False end object btnLeftSaveAs: TSpeedButton AnchorSideLeft.Control = btnLeftSave AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlLeftBox AnchorSideBottom.Control = edtFileNameLeft AnchorSideBottom.Side = asrBottom Left = 23 Height = 23 Top = 0 Width = 23 Action = actSaveLeftAs Anchors = [akTop, akLeft, akBottom] Images = dmComData.ilEditorImages ImageIndex = 35 ShowCaption = False end end end object Splitter: TSplitter Left = 379 Height = 304 Top = 22 Width = 5 end object pnlRight: TPanel Left = 384 Height = 304 Top = 22 Width = 376 Align = alClient BevelOuter = bvNone ClientHeight = 304 ClientWidth = 376 TabOrder = 3 object pnlRightBox: TPanel Left = 0 Height = 23 Top = 0 Width = 376 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 23 ClientWidth = 376 FullRepaint = False ParentShowHint = False ShowHint = True TabOrder = 0 object edtFileNameRight: TFileNameEdit AnchorSideLeft.Control = btnRightEncoding AnchorSideLeft.Side = asrBottom Left = 69 Height = 23 Top = 0 Width = 282 OnAcceptFileName = edtFileNameRightAcceptFileName DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 0 end object btnRightEncoding: TSpeedButton AnchorSideLeft.Control = btnRightSaveAs AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlRightBox AnchorSideBottom.Control = edtFileNameRight AnchorSideBottom.Side = asrBottom Left = 46 Height = 23 Hint = 'Encoding' Top = 0 Width = 23 Anchors = [akTop, akLeft, akBottom] Images = dmComData.ilEditorImages ImageIndex = 44 OnClick = btnRightEncodingClick end object btnRightSave: TSpeedButton AnchorSideLeft.Control = pnlRightBox AnchorSideTop.Control = pnlRightBox AnchorSideBottom.Control = edtFileNameRight AnchorSideBottom.Side = asrBottom Left = 0 Height = 23 Top = 0 Width = 23 Action = actSaveRight Anchors = [akTop, akLeft, akBottom] Images = dmComData.ilEditorImages ImageIndex = 34 ShowCaption = False end object btnRightSaveAs: TSpeedButton AnchorSideLeft.Control = btnRightSave AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlRightBox AnchorSideBottom.Control = edtFileNameRight AnchorSideBottom.Side = asrBottom Left = 23 Height = 23 Top = 0 Width = 23 Action = actSaveRightAs Anchors = [akTop, akLeft, akBottom] Images = dmComData.ilEditorImages ImageIndex = 35 ShowCaption = False end end end object StatusBar: TStatusBar Left = 0 Height = 23 Top = 326 Width = 760 Panels = < item Width = 100 end item Width = 100 end item Width = 100 end item Width = 100 end> SimplePanel = False end object MainMenu: TMainMenu Images = dmComData.ilEditorImages Left = 88 Top = 136 object mnuFile: TMenuItem Caption = '&File' object miOpenLeft: TMenuItem Action = actOpenLeft OnClick = actOpenLeftExecute end object miOpenRight: TMenuItem Action = actOpenRight OnClick = actOpenRightExecute end object miReload: TMenuItem Action = actReload end object miDivider7: TMenuItem Caption = '-' end object miSaveLeft: TMenuItem Action = actSaveLeft end object miSaveRight: TMenuItem Action = actSaveRight end object miSaveLeftAs: TMenuItem Action = actSaveLeftAs OnClick = actSaveLeftAsExecute end object miSaveRightAs: TMenuItem Action = actSaveRightAs OnClick = actSaveRightAsExecute end object miDivider6: TMenuItem Caption = '-' end object miExit: TMenuItem Action = actExit end end object mnuEdit: TMenuItem Caption = '&Edit' object miEditUndo: TMenuItem Action = actEditUndo OnClick = actEditUndoExecute end object miEditRedo: TMenuItem Action = actEditRedo OnClick = actEditRedoExecute end object miDivider8: TMenuItem Caption = '-' end object miEditCut: TMenuItem Action = actEditCut OnClick = actEditCutExecute end object miEditCopy: TMenuItem Action = actEditCopy OnClick = actEditCopyExecute end object miEditPaste: TMenuItem Action = actEditPaste OnClick = actEditPasteExecute end object miEditDelete: TMenuItem Action = actEditDelete OnClick = actEditDeleteExecute end object miEditSelectAll: TMenuItem Action = actEditSelectAll OnClick = actEditSelectAllExecute end object miDivider11: TMenuItem Caption = '-' end object miFind: TMenuItem Action = actFind end object miFindNext: TMenuItem Action = actFindNext end object miFindPrev: TMenuItem Action = actFindPrev end object miFindReplace: TMenuItem Action = actFindReplace end object miGotoLine: TMenuItem Action = actGotoLine end end object mnuOptions: TMenuItem Caption = '&Options' object miAutoCompare: TMenuItem Action = actAutoCompare AutoCheck = True end object miDivider10: TMenuItem Caption = '-' end object miIgnoreWhiteSpace: TMenuItem Action = actIgnoreWhiteSpace AutoCheck = True end object miIgnoreCase: TMenuItem Action = actIgnoreCase AutoCheck = True end object miDivider4: TMenuItem Caption = '-' end object miPaintBackground: TMenuItem Action = actPaintBackground AutoCheck = True OnClick = actPaintBackgroundExecute end object miLineDifferences: TMenuItem Action = actLineDifferences AutoCheck = True end object miDivider3: TMenuItem Caption = '-' end object miBinaryCompare: TMenuItem Action = actBinaryCompare AutoCheck = True OnClick = actBinaryCompareExecute end object miKeepScrolling: TMenuItem Action = actKeepScrolling AutoCheck = True OnClick = actKeepScrollingExecute end end object mnuActions: TMenuItem Caption = '&Actions' object miStartCompare: TMenuItem Action = actStartCompare end object miCancelCompare: TMenuItem Action = actCancelCompare end object miDivider1: TMenuItem Caption = '-' end object miNextDiff: TMenuItem Action = actNextDifference end object miPrevDiff: TMenuItem Action = actPrevDifference end object miDivider2: TMenuItem Caption = '-' end object miFirstDiff: TMenuItem Action = actFirstDifference end object miLastDiff: TMenuItem Action = actLastDifference end object miDivider5: TMenuItem Caption = '-' end object miCopyLeftToRight: TMenuItem Action = actCopyLeftToRight end object miCopyRightToLeft: TMenuItem Action = actCopyRightToLeft end end object mnuEncoding: TMenuItem Caption = 'En&coding' object miEncodingLeft: TMenuItem Caption = '&Left' end object miEncodingRight: TMenuItem Caption = '&Right' end end object miAbout: TMenuItem Action = actAbout end end object ActionList: TActionList Images = dmComData.ilEditorImages Left = 24 Top = 136 object actSave: TAction Caption = 'Save' Hint = 'Save' ImageIndex = 2 OnExecute = actSaveExecute end object actSaveAs: TAction Caption = 'Save as...' Hint = 'Save as...' ImageIndex = 3 OnExecute = actSaveAsExecute end object actStartCompare: TAction Caption = 'Compare' Hint = 'Compare' ImageIndex = 36 OnExecute = actStartCompareExecute end object actLastDifference: TAction Caption = 'Last Difference' Hint = 'Last Difference' ImageIndex = 37 OnExecute = actExecute end object actNextDifference: TAction Caption = 'Next Difference' Hint = 'Next Difference' ImageIndex = 38 OnExecute = actExecute end object actPrevDifference: TAction Caption = 'Previous Difference' Hint = 'Previous Difference' ImageIndex = 39 OnExecute = actExecute end object actFirstDifference: TAction Caption = 'First Difference' Hint = 'First Difference' ImageIndex = 40 OnExecute = actExecute end object actIgnoreCase: TAction Category = 'Options' AutoCheck = True Caption = 'Ignore Case' DisableIfNoHandler = False OnExecute = actIgnoreCaseExecute end object actIgnoreWhiteSpace: TAction Category = 'Options' AutoCheck = True Caption = 'Ignore Blanks' DisableIfNoHandler = False OnExecute = actIgnoreCaseExecute end object actKeepScrolling: TAction AutoCheck = True Caption = 'Keep Scrolling' Checked = True OnExecute = actKeepScrollingExecute end object actCancelCompare: TAction Caption = 'Cancel' Enabled = False Hint = 'Cancel' ImageIndex = 41 OnExecute = actCancelCompareExecute end object actBinaryCompare: TAction Category = 'Options' AutoCheck = True Caption = 'Binary Mode' OnExecute = actBinaryCompareExecute end object actPaintBackground: TAction Category = 'Options' AutoCheck = True Caption = 'Paint Background' Checked = True OnExecute = actPaintBackgroundExecute end object actCopyLeftToRight: TAction Caption = 'Copy Block Right' Hint = 'Copy Block Right' ImageIndex = 43 OnExecute = actExecute end object actCopyRightToLeft: TAction Caption = 'Copy Block Left' Hint = 'Copy Block Left' ImageIndex = 42 OnExecute = actExecute end object actSaveLeft: TAction Caption = 'Save Left' Hint = 'Save Left' ImageIndex = 34 OnExecute = actExecute end object actSaveRight: TAction Caption = 'Save Right' Hint = 'Save Right' ImageIndex = 34 OnExecute = actExecute end object actReload: TAction Caption = '&Reload' Hint = 'Reload' ImageIndex = 17 OnExecute = actExecute end object actOpenLeft: TAction Caption = 'Open Left...' ImageIndex = 1 OnExecute = actOpenLeftExecute end object actOpenRight: TAction Caption = 'Open Right...' ImageIndex = 1 OnExecute = actOpenRightExecute end object actExit: TAction Caption = 'E&xit' ImageIndex = 12 OnExecute = actExecute end object actEditCut: TAction Category = 'Edit' Caption = 'Cut' ImageIndex = 5 OnExecute = actEditCutExecute end object actEditCopy: TAction Category = 'Edit' Caption = 'Copy' ImageIndex = 6 OnExecute = actEditCopyExecute end object actEditPaste: TAction Category = 'Edit' Caption = 'Paste' ImageIndex = 7 OnExecute = actEditPasteExecute end object actEditDelete: TAction Category = 'Edit' Caption = 'Delete' ImageIndex = 14 OnExecute = actEditDeleteExecute end object actEditSelectAll: TAction Category = 'Edit' Caption = 'Select &All' ImageIndex = 15 OnExecute = actEditSelectAllExecute end object actFind: TAction Category = 'Edit' Caption = '&Find' HelpType = htKeyword Hint = 'Find' ImageIndex = 10 OnExecute = actExecute end object actFindNext: TAction Category = 'Edit' Caption = 'Find next' Hint = 'Find next' OnExecute = actExecute end object actFindPrev: TAction Category = 'Edit' Caption = 'Find previous' Hint = 'Find previous' OnExecute = actExecute end object actFindReplace: TAction Category = 'Edit' Caption = '&Replace' HelpType = htKeyword Hint = 'Replace' ImageIndex = 11 OnExecute = actExecute end object actGotoLine: TAction Category = 'Edit' Caption = 'Goto Line...' Hint = 'Goto Line' ImageIndex = 16 OnExecute = actExecute end object actEditRedo: TAction Category = 'Edit' Caption = 'Redo' Hint = 'Redo' ImageIndex = 9 OnExecute = actEditRedoExecute end object actEditUndo: TAction Category = 'Edit' Caption = 'Undo' Hint = 'Undo' ImageIndex = 8 OnExecute = actEditUndoExecute end object actSaveLeftAs: TAction Caption = 'Save Left As...' Hint = 'Save Left As...' ImageIndex = 35 OnExecute = actSaveLeftAsExecute end object actSaveRightAs: TAction Caption = 'Save Right As...' Hint = 'Save Right As...' ImageIndex = 35 OnExecute = actSaveRightAsExecute end object actAbout: TAction Caption = 'About' OnExecute = actAboutExecute end object actLineDifferences: TAction Category = 'Options' AutoCheck = True Caption = 'Line Differences' OnExecute = actLineDifferencesExecute end object actAutoCompare: TAction Category = 'Options' AutoCheck = True Caption = 'Auto Compare' DisableIfNoHandler = False end end object ContextMenu: TPopupMenu Images = dmComData.ilEditorImages Left = 160 Top = 136 object miUndoContext: TMenuItem Action = actEditUndo OnClick = actEditUndoExecute end object miSeparator1: TMenuItem Caption = '-' end object miCutContext: TMenuItem Action = actEditCut OnClick = actEditCutExecute end object miCopyContext: TMenuItem Action = actEditCopy OnClick = actEditCopyExecute end object miPasteContext: TMenuItem Action = actEditPaste OnClick = actEditPasteExecute end object miDeleteContext: TMenuItem Action = actEditDelete OnClick = actEditDeleteExecute end object miSeparator2: TMenuItem Caption = '-' end object miSelectAllContext: TMenuItem Action = actEditSelectAll OnClick = actEditSelectAllExecute end end object pmEncodingLeft: TPopupMenu Left = 248 Top = 136 end object pmEncodingRight: TPopupMenu Left = 352 Top = 136 end object tmProgress: TTimer OnTimer = tmProgressTimer Left = 568 Top = 170 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdiffer.lrj��������������������������������������������������������������������0000644�0001750�0000144�00000022277�14743153644�015525� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":218671619,"name":"tfrmdiffer.caption","sourcebytes":[67,111,109,112,97,114,101,32,102,105,108,101,115],"value":"Compare files"}, {"hash":77966471,"name":"tfrmdiffer.btnleftencoding.hint","sourcebytes":[69,110,99,111,100,105,110,103],"value":"Encoding"}, {"hash":77966471,"name":"tfrmdiffer.btnrightencoding.hint","sourcebytes":[69,110,99,111,100,105,110,103],"value":"Encoding"}, {"hash":2805797,"name":"tfrmdiffer.mnufile.caption","sourcebytes":[38,70,105,108,101],"value":"&File"}, {"hash":2800388,"name":"tfrmdiffer.mnuedit.caption","sourcebytes":[38,69,100,105,116],"value":"&Edit"}, {"hash":108726499,"name":"tfrmdiffer.mnuoptions.caption","sourcebytes":[38,79,112,116,105,111,110,115],"value":"&Options"}, {"hash":128649459,"name":"tfrmdiffer.mnuactions.caption","sourcebytes":[38,65,99,116,105,111,110,115],"value":"&Actions"}, {"hash":212198471,"name":"tfrmdiffer.mnuencoding.caption","sourcebytes":[69,110,38,99,111,100,105,110,103],"value":"En&coding"}, {"hash":2829268,"name":"tfrmdiffer.miencodingleft.caption","sourcebytes":[38,76,101,102,116],"value":"&Left"}, {"hash":45678068,"name":"tfrmdiffer.miencodingright.caption","sourcebytes":[38,82,105,103,104,116],"value":"&Right"}, {"hash":366789,"name":"tfrmdiffer.actsave.caption","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":366789,"name":"tfrmdiffer.actsave.hint","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":124639694,"name":"tfrmdiffer.actsaveas.caption","sourcebytes":[83,97,118,101,32,97,115,46,46,46],"value":"Save as..."}, {"hash":124639694,"name":"tfrmdiffer.actsaveas.hint","sourcebytes":[83,97,118,101,32,97,115,46,46,46],"value":"Save as..."}, {"hash":174352581,"name":"tfrmdiffer.actstartcompare.caption","sourcebytes":[67,111,109,112,97,114,101],"value":"Compare"}, {"hash":174352581,"name":"tfrmdiffer.actstartcompare.hint","sourcebytes":[67,111,109,112,97,114,101],"value":"Compare"}, {"hash":111958485,"name":"tfrmdiffer.actlastdifference.caption","sourcebytes":[76,97,115,116,32,68,105,102,102,101,114,101,110,99,101],"value":"Last Difference"}, {"hash":111958485,"name":"tfrmdiffer.actlastdifference.hint","sourcebytes":[76,97,115,116,32,68,105,102,102,101,114,101,110,99,101],"value":"Last Difference"}, {"hash":61628309,"name":"tfrmdiffer.actnextdifference.caption","sourcebytes":[78,101,120,116,32,68,105,102,102,101,114,101,110,99,101],"value":"Next Difference"}, {"hash":61628309,"name":"tfrmdiffer.actnextdifference.hint","sourcebytes":[78,101,120,116,32,68,105,102,102,101,114,101,110,99,101],"value":"Next Difference"}, {"hash":118545253,"name":"tfrmdiffer.actprevdifference.caption","sourcebytes":[80,114,101,118,105,111,117,115,32,68,105,102,102,101,114,101,110,99,101],"value":"Previous Difference"}, {"hash":118545253,"name":"tfrmdiffer.actprevdifference.hint","sourcebytes":[80,114,101,118,105,111,117,115,32,68,105,102,102,101,114,101,110,99,101],"value":"Previous Difference"}, {"hash":111729605,"name":"tfrmdiffer.actfirstdifference.caption","sourcebytes":[70,105,114,115,116,32,68,105,102,102,101,114,101,110,99,101],"value":"First Difference"}, {"hash":111729605,"name":"tfrmdiffer.actfirstdifference.hint","sourcebytes":[70,105,114,115,116,32,68,105,102,102,101,114,101,110,99,101],"value":"First Difference"}, {"hash":138116597,"name":"tfrmdiffer.actignorecase.caption","sourcebytes":[73,103,110,111,114,101,32,67,97,115,101],"value":"Ignore Case"}, {"hash":192359699,"name":"tfrmdiffer.actignorewhitespace.caption","sourcebytes":[73,103,110,111,114,101,32,66,108,97,110,107,115],"value":"Ignore Blanks"}, {"hash":77690103,"name":"tfrmdiffer.actkeepscrolling.caption","sourcebytes":[75,101,101,112,32,83,99,114,111,108,108,105,110,103],"value":"Keep Scrolling"}, {"hash":77089212,"name":"tfrmdiffer.actcancelcompare.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"}, {"hash":77089212,"name":"tfrmdiffer.actcancelcompare.hint","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"}, {"hash":167657765,"name":"tfrmdiffer.actbinarycompare.caption","sourcebytes":[66,105,110,97,114,121,32,77,111,100,101],"value":"Binary Mode"}, {"hash":76187108,"name":"tfrmdiffer.actpaintbackground.caption","sourcebytes":[80,97,105,110,116,32,66,97,99,107,103,114,111,117,110,100],"value":"Paint Background"}, {"hash":102067732,"name":"tfrmdiffer.actcopylefttoright.caption","sourcebytes":[67,111,112,121,32,66,108,111,99,107,32,82,105,103,104,116],"value":"Copy Block Right"}, {"hash":102067732,"name":"tfrmdiffer.actcopylefttoright.hint","sourcebytes":[67,111,112,121,32,66,108,111,99,107,32,82,105,103,104,116],"value":"Copy Block Right"}, {"hash":241300196,"name":"tfrmdiffer.actcopyrighttoleft.caption","sourcebytes":[67,111,112,121,32,66,108,111,99,107,32,76,101,102,116],"value":"Copy Block Left"}, {"hash":241300196,"name":"tfrmdiffer.actcopyrighttoleft.hint","sourcebytes":[67,111,112,121,32,66,108,111,99,107,32,76,101,102,116],"value":"Copy Block Left"}, {"hash":209023572,"name":"tfrmdiffer.actsaveleft.caption","sourcebytes":[83,97,118,101,32,76,101,102,116],"value":"Save Left"}, {"hash":209023572,"name":"tfrmdiffer.actsaveleft.hint","sourcebytes":[83,97,118,101,32,76,101,102,116],"value":"Save Left"}, {"hash":123561268,"name":"tfrmdiffer.actsaveright.caption","sourcebytes":[83,97,118,101,32,82,105,103,104,116],"value":"Save Right"}, {"hash":123561268,"name":"tfrmdiffer.actsaveright.hint","sourcebytes":[83,97,118,101,32,82,105,103,104,116],"value":"Save Right"}, {"hash":193738068,"name":"tfrmdiffer.actreload.caption","sourcebytes":[38,82,101,108,111,97,100],"value":"&Reload"}, {"hash":93074804,"name":"tfrmdiffer.actreload.hint","sourcebytes":[82,101,108,111,97,100],"value":"Reload"}, {"hash":131838302,"name":"tfrmdiffer.actopenleft.caption","sourcebytes":[79,112,101,110,32,76,101,102,116,46,46,46],"value":"Open Left..."}, {"hash":162756318,"name":"tfrmdiffer.actopenright.caption","sourcebytes":[79,112,101,110,32,82,105,103,104,116,46,46,46],"value":"Open Right..."}, {"hash":4710148,"name":"tfrmdiffer.actexit.caption","sourcebytes":[69,38,120,105,116],"value":"E&xit"}, {"hash":19140,"name":"tfrmdiffer.acteditcut.caption","sourcebytes":[67,117,116],"value":"Cut"}, {"hash":304761,"name":"tfrmdiffer.acteditcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":5671589,"name":"tfrmdiffer.acteditpaste.caption","sourcebytes":[80,97,115,116,101],"value":"Paste"}, {"hash":78392485,"name":"tfrmdiffer.acteditdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":171665052,"name":"tfrmdiffer.acteditselectall.caption","sourcebytes":[83,101,108,101,99,116,32,38,65,108,108],"value":"Select &All"}, {"hash":2805828,"name":"tfrmdiffer.actfind.caption","sourcebytes":[38,70,105,110,100],"value":"&Find"}, {"hash":315460,"name":"tfrmdiffer.actfind.hint","sourcebytes":[70,105,110,100],"value":"Find"}, {"hash":73859572,"name":"tfrmdiffer.actfindnext.caption","sourcebytes":[70,105,110,100,32,110,101,120,116],"value":"Find next"}, {"hash":73859572,"name":"tfrmdiffer.actfindnext.hint","sourcebytes":[70,105,110,100,32,110,101,120,116],"value":"Find next"}, {"hash":97034739,"name":"tfrmdiffer.actfindprev.caption","sourcebytes":[70,105,110,100,32,112,114,101,118,105,111,117,115],"value":"Find previous"}, {"hash":97034739,"name":"tfrmdiffer.actfindprev.hint","sourcebytes":[70,105,110,100,32,112,114,101,118,105,111,117,115],"value":"Find previous"}, {"hash":147268901,"name":"tfrmdiffer.actfindreplace.caption","sourcebytes":[38,82,101,112,108,97,99,101],"value":"&Replace"}, {"hash":147269573,"name":"tfrmdiffer.actfindreplace.hint","sourcebytes":[82,101,112,108,97,99,101],"value":"Replace"}, {"hash":102945374,"name":"tfrmdiffer.actgotoline.caption","sourcebytes":[71,111,116,111,32,76,105,110,101,46,46,46],"value":"Goto Line..."}, {"hash":185950757,"name":"tfrmdiffer.actgotoline.hint","sourcebytes":[71,111,116,111,32,76,105,110,101],"value":"Goto Line"}, {"hash":363439,"name":"tfrmdiffer.acteditredo.caption","sourcebytes":[82,101,100,111],"value":"Redo"}, {"hash":363439,"name":"tfrmdiffer.acteditredo.hint","sourcebytes":[82,101,100,111],"value":"Redo"}, {"hash":378031,"name":"tfrmdiffer.acteditundo.caption","sourcebytes":[85,110,100,111],"value":"Undo"}, {"hash":378031,"name":"tfrmdiffer.acteditundo.hint","sourcebytes":[85,110,100,111],"value":"Undo"}, {"hash":171783006,"name":"tfrmdiffer.actsaveleftas.caption","sourcebytes":[83,97,118,101,32,76,101,102,116,32,65,115,46,46,46],"value":"Save Left As..."}, {"hash":171783006,"name":"tfrmdiffer.actsaveleftas.hint","sourcebytes":[83,97,118,101,32,76,101,102,116,32,65,115,46,46,46],"value":"Save Left As..."}, {"hash":18171454,"name":"tfrmdiffer.actsaverightas.caption","sourcebytes":[83,97,118,101,32,82,105,103,104,116,32,65,115,46,46,46],"value":"Save Right As..."}, {"hash":18171454,"name":"tfrmdiffer.actsaverightas.hint","sourcebytes":[83,97,118,101,32,82,105,103,104,116,32,65,115,46,46,46],"value":"Save Right As..."}, {"hash":4691652,"name":"tfrmdiffer.actabout.caption","sourcebytes":[65,98,111,117,116],"value":"About"}, {"hash":197494083,"name":"tfrmdiffer.actlinedifferences.caption","sourcebytes":[76,105,110,101,32,68,105,102,102,101,114,101,110,99,101,115],"value":"Line Differences"}, {"hash":250141125,"name":"tfrmdiffer.actautocompare.caption","sourcebytes":[65,117,116,111,32,67,111,109,112,97,114,101],"value":"Auto Compare"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fdiffer.pas��������������������������������������������������������������������0000644�0001750�0000144�00000146650�14743153644�015523� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Internal diff and merge tool Copyright (C) 2010-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fDiffer; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Dialogs, Menus, ComCtrls, ActnList, ExtCtrls, EditBtn, Buttons, SynEdit, uSynDiffControls, LMessages, uPariterControls, uDiffOND, uFormCommands, uHotkeyManager, uOSForms, uBinaryDiffViewer, uShowForm, KASStatusBar, Graphics, StdCtrls, fEditSearch; type { TStatusBar } TStatusBar = class(TKASStatusBar); { TfrmDiffer } TfrmDiffer = class(TAloneForm, IFormCommands) actBinaryCompare: TAction; actCopyLeftToRight: TAction; actCopyRightToLeft: TAction; actExit: TAction; actEditCut: TAction; actEditCopy: TAction; actEditDelete: TAction; actEditUndo: TAction; actEditRedo: TAction; actFind: TAction; actFindNext: TAction; actFindPrev: TAction; actFindReplace: TAction; actGotoLine: TAction; actEditSelectAll: TAction; actEditPaste: TAction; actAbout: TAction; actAutoCompare: TAction; actLineDifferences: TAction; actSaveRightAs: TAction; actSaveLeftAs: TAction; actOpenRight: TAction; actOpenLeft: TAction; actReload: TAction; actSaveRight: TAction; actSaveLeft: TAction; actPaintBackground: TAction; actStartCompare: TAction; actFirstDifference: TAction; actIgnoreCase: TAction; actIgnoreWhiteSpace: TAction; actCancelCompare: TAction; actKeepScrolling: TAction; actPrevDifference: TAction; actLastDifference: TAction; actNextDifference: TAction; actSaveAs: TAction; actSave: TAction; ActionList: TActionList; edtFileNameLeft: TFileNameEdit; edtFileNameRight: TFileNameEdit; MainMenu: TMainMenu; miAutoCompare: TMenuItem; miDivider10: TMenuItem; miDivider11: TMenuItem; miLineDifferences: TMenuItem; miEncodingRight: TMenuItem; miEncodingLeft: TMenuItem; miAbout: TMenuItem; mnuEncoding: TMenuItem; miSaveRightAs: TMenuItem; miSaveLeftAs: TMenuItem; miCopyContext: TMenuItem; miCutContext: TMenuItem; miDeleteContext: TMenuItem; miFind: TMenuItem; miFindNext: TMenuItem; miFindPrevious: TMenuItem; miFindReplace: TMenuItem; miGotoLine: TMenuItem; miEditSelectAll: TMenuItem; miEditDelete: TMenuItem; miEditPaste: TMenuItem; miEditCopy: TMenuItem; miEditCut: TMenuItem; miDivider8: TMenuItem; miEditRedo: TMenuItem; miEditUndo: TMenuItem; miDivider7: TMenuItem; miPasteContext: TMenuItem; miReload: TMenuItem; miDivider6: TMenuItem; miExit: TMenuItem; miSaveRight: TMenuItem; miOpenRight: TMenuItem; miOpenLeft: TMenuItem; miCopyRightToLeft: TMenuItem; miCopyLeftToRight: TMenuItem; miDivider5: TMenuItem; miPaintBackground: TMenuItem; miDivider4: TMenuItem; miBinaryCompare: TMenuItem; miKeepScrolling: TMenuItem; miDivider3: TMenuItem; miLastDiff: TMenuItem; miFirstDiff: TMenuItem; miDivider2: TMenuItem; miPrevDiff: TMenuItem; miNextDiff: TMenuItem; miDivider1: TMenuItem; miCancelCompare: TMenuItem; miSelectAllContext: TMenuItem; miSeparator1: TMenuItem; miSeparator2: TMenuItem; miStartCompare: TMenuItem; miUndoContext: TMenuItem; mnuActions: TMenuItem; miIgnoreCase: TMenuItem; miIgnoreWhiteSpace: TMenuItem; mnuOptions: TMenuItem; mnuEdit: TMenuItem; miSaveLeft: TMenuItem; mnuFile: TMenuItem; ContextMenu: TPopupMenu; pnlLeftBox: TPanel; pnlRight: TPanel; pnlLeft: TPanel; pnlRightBox: TPanel; btnLeftEncoding: TSpeedButton; btnRightEncoding: TSpeedButton; btnLeftSave: TSpeedButton; btnLeftSaveAs: TSpeedButton; btnRightSave: TSpeedButton; btnRightSaveAs: TSpeedButton; pmEncodingLeft: TPopupMenu; pmEncodingRight: TPopupMenu; Splitter: TSplitter; StatusBar: TStatusBar; tmProgress: TTimer; ToolBar: TToolBar; btnSave: TToolButton; btnSaveAs: TToolButton; Divider1: TToolButton; btnCompare: TToolButton; btnLast: TToolButton; btnNext: TToolButton; btnPrev: TToolButton; btnFirst: TToolButton; Divider2: TToolButton; Divider3: TToolButton; btnCancelCompare: TToolButton; Divider4: TToolButton; btnReload: TToolButton; btnCopyRightToLeft: TToolButton; btnCopyLeftToRight: TToolButton; Divider5: TToolButton; btnEditUndo: TToolButton; btnEditRedo: TToolButton; procedure actAboutExecute(Sender: TObject); procedure actBinaryCompareExecute(Sender: TObject); procedure actCancelCompareExecute(Sender: TObject); procedure actExecute(Sender: TObject); procedure actEditCopyExecute(Sender: TObject); procedure actEditCutExecute(Sender: TObject); procedure actEditDeleteExecute(Sender: TObject); procedure actEditPasteExecute(Sender: TObject); procedure actEditRedoExecute(Sender: TObject); procedure actEditSelectAllExecute(Sender: TObject); procedure actEditUndoExecute(Sender: TObject); procedure actIgnoreCaseExecute(Sender: TObject); procedure actLineDifferencesExecute(Sender: TObject); procedure actOpenLeftExecute(Sender: TObject); procedure actOpenRightExecute(Sender: TObject); procedure actPaintBackgroundExecute(Sender: TObject); procedure actSaveAsExecute(Sender: TObject); procedure actSaveExecute(Sender: TObject); procedure actSaveLeftAsExecute(Sender: TObject); procedure actSaveRightAsExecute(Sender: TObject); procedure actStartCompareExecute(Sender: TObject); procedure actKeepScrollingExecute(Sender: TObject); procedure btnLeftEncodingClick(Sender: TObject); procedure btnRightEncodingClick(Sender: TObject); procedure edtFileNameLeftAcceptFileName(Sender: TObject; var Value: String); procedure edtFileNameRightAcceptFileName(Sender: TObject; var Value: String); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormResize(Sender: TObject); procedure btnCancelClick(Sender: TObject); procedure tmProgressTimer(Sender: TObject); private BinaryDiffList: TFPList; BinaryDiffIndex: Integer; BinaryCompare: TBinaryCompare; BinaryViewerLeft, BinaryViewerRight: TBinaryDiffViewer; procedure BinaryCompareFinish; private Diff: TDiff; SynDiffEditActive: TSynDiffEdit; SynDiffEditLeft: TSynDiffEdit; SynDiffEditRight: TSynDiffEdit; SynDiffHighlighterLeft, SynDiffHighlighterRight: TSynDiffHighlighter; HashListLeft, HashListRight: array of Integer; EncodingList: TStringList; ScrollLock: LongInt; FShowIdentical: Boolean; FModal: Boolean; FCancel: Boolean; frmProgress: TForm; FWaitData: TWaitData; FElevate: TDuplicates; FCommands: TFormCommands; FLeftLen, FRightLen: Integer; FSearchOptions: TEditSearchOptions; private procedure ShowDialog; procedure ShowIdentical; procedure ShowTextIdentical; procedure ShowProgressDialog; procedure CloseProgressDialog; procedure Clear(bLeft, bRight: Boolean); procedure BuildHashList(bLeft, bRight: Boolean); procedure ChooseEncoding(SynDiffEdit: TSynDiffEdit); function GetDisplayNumber(LineNumber: Integer): Integer; procedure SetColors(cAdded, cDeleted, cModified: TColor); procedure ChooseEncoding(MenuItem: TMenuItem; Encoding: String); procedure FillEncodingMenu(TheOwner: TMenuItem; MenuHandler: TNotifyEvent; GroupIndex: LongInt); procedure LoadFromFile(SynDiffEdit: TSynDiffEdit; const FileName: String); procedure SaveToFile(SynDiffEdit: TSynDiffEdit; const FileName: String); procedure OpenFileLeft(const FileName: String); procedure OpenFileRight(const FileName: String); procedure SetEncodingLeft(Sender: TObject); procedure SetEncodingRight(Sender: TObject); procedure SynDiffEditEnter(Sender: TObject); procedure ShowFirstDifference(Data: PtrInt); procedure SynDiffEditLeftStatusChange(Sender: TObject; Changes: TSynStatusChanges); procedure SynDiffEditRightStatusChange(Sender: TObject; Changes: TSynStatusChanges); property Commands: TFormCommands read FCommands implements IFormCommands; protected procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure AfterConstruction; override; published procedure cm_CopyLeftToRight(const Params: array of string); procedure cm_CopyRightToLeft(const Params: array of string); procedure cm_Find(const Params: array of string); procedure cm_FindNext(const Params: array of string); procedure cm_FindPrev(const Params: array of string); procedure cm_FindReplace(const Params: array of string); procedure cm_GotoLine(const Params: array of string); procedure cm_Exit(const Params: array of string); procedure cm_FirstDifference(const Params: array of string); procedure cm_LastDifference(const Params: array of string); procedure cm_NextDifference(const Params: array of string); procedure cm_PrevDifference(const Params: array of string); procedure cm_Reload(const Params: array of string); procedure cm_SaveLeft(const Params: array of string); procedure cm_SaveRight(const Params: array of string); end; procedure ShowDiffer(const FileNameLeft, FileNameRight: String; WaitData: TWaitData = nil; Modal: Boolean = False); implementation {$R *.lfm} uses Math, LCLType, LazFileUtils, LConvEncoding, SynEditTypes, uHash, uLng, uGlobs, uShowMsg, DCClassesUtf8, dmCommonData, uDCUtils, uConvEncoding, uAdministrator, uFileProcs; const HotkeysCategory = 'Differ'; procedure ShowDiffer(const FileNameLeft, FileNameRight: String; WaitData: TWaitData = nil; Modal: Boolean = False); var Binary: Boolean; Differ: TfrmDiffer; begin Differ := TfrmDiffer.Create(Application); with Differ do begin FModal := Modal; FWaitData := WaitData; FShowIdentical := True; edtFileNameLeft.Text:= FileNameLeft; edtFileNameRight.Text:= FileNameRight; try PushPop(FElevate); try Binary:= not (mbFileIsText(FileNameLeft) and mbFileIsText(FileNameRight)); finally PushPop(FElevate); end; if Binary then actBinaryCompare.Execute else begin OpenFileLeft(FileNameLeft); OpenFileRight(FileNameRight); if actStartCompare.Enabled then actStartCompare.Execute else begin tmProgress.Enabled:= False; CloseProgressDialog; ShowDialog; end; end; except on E: Exception do begin tmProgress.Enabled:= False; CloseProgressDialog; msgError(E.Message); Free; end; end; end; end; { TfrmDiffer } procedure TfrmDiffer.actStartCompareExecute(Sender: TObject); var I: Integer; LineNumberLeft, LineNumberRight: PtrInt; begin FCancel:= False; try if actBinaryCompare.Checked then begin if (BinaryViewerLeft.IsFileOpen and BinaryViewerRight.IsFileOpen) then begin actStartCompare.Enabled := False; actCancelCompare.Enabled := True; actBinaryCompare.Enabled := False; BinaryCompare:= TBinaryCompare.Create(BinaryViewerLeft.GetDataAdr, BinaryViewerRight.GetDataAdr, BinaryViewerLeft.FileSize, BinaryViewerRight.FileSize, BinaryDiffList); BinaryCompare.OnFinish:= @BinaryCompareFinish; BinaryCompare.Start; end; end else begin Inc(ScrollLock); Screen.BeginWaitCursor; try if SynDiffEditLeft.Modified then SynDiffEditLeft.Lines.RemoveFake; if SynDiffEditRight.Modified then SynDiffEditRight.Lines.RemoveFake; BuildHashList(SynDiffEditLeft.Modified, SynDiffEditRight.Modified); if (Length(HashListLeft) = 0) or (Length(HashListRight) = 0) then begin FCancel := True; Exit; end; actStartCompare.Enabled := False; actCancelCompare.Enabled := True; Diff.Execute( PInteger(@HashListLeft[0]), PInteger(@HashListRight[0]), Length(HashListLeft), Length(HashListRight) ); tmProgress.Enabled:= False; if Diff.Cancelled then Exit; SynDiffEditLeft.StartCompare; SynDiffEditRight.StartCompare; for I := 0 to Diff.Count - 1 do with Diff.Compares[I] do begin LineNumberLeft:= oldIndex1 + 1; LineNumberRight:= oldIndex2 + 1; case Kind of ckAdd: begin SynDiffEditLeft.Lines.InsertFake(I, Kind); SynDiffEditRight.Lines.SetKindAndNumber(I, Kind, LineNumberRight); end; ckDelete: begin SynDiffEditLeft.Lines.SetKindAndNumber(I, Kind, LineNumberLeft); SynDiffEditRight.Lines.InsertFake(I, Kind); end; else begin SynDiffEditLeft.Lines.SetKindAndNumber(I, Kind, LineNumberLeft); SynDiffEditRight.Lines.SetKindAndNumber(I, Kind, LineNumberRight); end; end; end; finally SynDiffEditLeft.FinishCompare; SynDiffEditRight.FinishCompare; actStartCompare.Enabled := True; actCancelCompare.Enabled := False; Screen.EndWaitCursor; Dec(ScrollLock); end; if actLineDifferences.Checked then begin SynDiffEditLeft.Highlighter:= SynDiffHighlighterLeft; SynDiffEditRight.Highlighter:= SynDiffHighlighterRight; end; with Diff.DiffStats do begin StatusBar.Panels[0].Text := rsDiffMatches + IntToStr(matches); StatusBar.Panels[1].Text := rsDiffModifies + IntToStr(modifies); StatusBar.Panels[2].Text := rsDiffAdds + IntToStr(adds); StatusBar.Panels[3].Text := rsDiffDeletes + IntToStr(deletes); if FShowIdentical then begin CloseProgressDialog; FShowIdentical:= (modifies = 0) and (adds = 0) and (deletes = 0); if FShowIdentical then ShowIdentical else begin FShowIdentical:= False; Application.QueueAsyncCall(@ShowFirstDifference, 0); ShowDialog; end; end else if (modifies = 0) and (adds = 0) and (deletes = 0) then begin if (SynDiffEditLeft.Encoding <> SynDiffEditRight.Encoding) or (SynDiffEditLeft.Lines.TextLineBreakStyle <> SynDiffEditRight.Lines.TextLineBreakStyle) then begin ShowTextIdentical; end; end; end; end; finally if FShowIdentical and FCancel then Free; end; end; procedure TfrmDiffer.actOpenLeftExecute(Sender: TObject); begin dmComData.OpenDialog.FileName:= edtFileNameLeft.Text; dmComData.OpenDialog.Filter:= AllFilesMask; if dmComData.OpenDialog.Execute then begin edtFileNameLeft.Text:= dmComData.OpenDialog.FileName; actReload.Execute; end; end; procedure TfrmDiffer.actOpenRightExecute(Sender: TObject); begin dmComData.OpenDialog.FileName:= edtFileNameRight.Text; dmComData.OpenDialog.Filter:= AllFilesMask; if dmComData.OpenDialog.Execute then begin edtFileNameRight.Text:= dmComData.OpenDialog.FileName; actReload.Execute; end; end; procedure TfrmDiffer.actPaintBackgroundExecute(Sender: TObject); begin if actPaintBackground.Checked then begin SynDiffEditLeft.PaintStyle:= psBackground; SynDiffEditRight.PaintStyle:= psBackground; end else begin SynDiffEditLeft.PaintStyle:= psForeground; SynDiffEditRight.PaintStyle:= psForeground; end; SynDiffHighlighterLeft.UpdateColors; SynDiffHighlighterRight.UpdateColors; end; procedure TfrmDiffer.actSaveAsExecute(Sender: TObject); begin if SynDiffEditActive = SynDiffEditLeft then actSaveLeftAs.Execute else if SynDiffEditActive = SynDiffEditRight then actSaveRightAs.Execute; end; procedure TfrmDiffer.actSaveExecute(Sender: TObject); begin if SynDiffEditActive = SynDiffEditLeft then actSaveLeft.Execute else if SynDiffEditActive = SynDiffEditRight then actSaveRight.Execute; end; procedure TfrmDiffer.actSaveLeftAsExecute(Sender: TObject); begin dmComData.SaveDialog.FileName:= edtFileNameLeft.FileName; if dmComData.SaveDialog.Execute then begin PushPop(FElevate); try SaveToFile(SynDiffEditLeft, dmComData.SaveDialog.FileName); finally PushPop(FElevate); end; edtFileNameLeft.FileName:= dmComData.SaveDialog.FileName; end; end; procedure TfrmDiffer.actSaveRightAsExecute(Sender: TObject); begin dmComData.SaveDialog.FileName:= edtFileNameRight.FileName; if dmComData.SaveDialog.Execute then begin PushPop(FElevate); try SaveToFile(SynDiffEditRight, dmComData.SaveDialog.FileName); finally PushPop(FElevate); end; edtFileNameRight.FileName:= dmComData.SaveDialog.FileName; end; end; procedure TfrmDiffer.actBinaryCompareExecute(Sender: TObject); begin mnuEdit.Enabled:= not actBinaryCompare.Checked; mnuEncoding.Enabled:= not actBinaryCompare.Checked; btnLeftEncoding.Enabled:= not actBinaryCompare.Checked; btnRightEncoding.Enabled:= not actBinaryCompare.Checked; actCopyLeftToRight.Enabled:= not actBinaryCompare.Checked; actCopyRightToLeft.Enabled:= not actBinaryCompare.Checked; actEditUndo.Enabled:= not actBinaryCompare.Checked; actEditRedo.Enabled:= not actBinaryCompare.Checked; actFind.Enabled:= not actBinaryCompare.Checked; actFindNext.Enabled:= not actBinaryCompare.Checked; actFindPrev.Enabled:= not actBinaryCompare.Checked; actFindReplace.Enabled:= not actBinaryCompare.Checked; actGotoLine.Enabled:= not actBinaryCompare.Checked; actSave.Enabled:= not actBinaryCompare.Checked; actSaveAs.Enabled:= not actBinaryCompare.Checked; actSaveLeft.Enabled:= not actBinaryCompare.Checked; actSaveLeftAs.Enabled:= not actBinaryCompare.Checked; actSaveRight.Enabled:= not actBinaryCompare.Checked; actSaveRightAs.Enabled:= not actBinaryCompare.Checked; actIgnoreCase.Enabled:= not actBinaryCompare.Checked; actIgnoreWhiteSpace.Enabled:= not actBinaryCompare.Checked; actPaintBackground.Enabled:= not actBinaryCompare.Checked; actLineDifferences.Enabled:= not actBinaryCompare.Checked; SynDiffEditLeft.Visible:= not actBinaryCompare.Checked; SynDiffEditRight.Visible:= not actBinaryCompare.Checked; BinaryViewerLeft.Visible:= actBinaryCompare.Checked; BinaryViewerRight.Visible:= actBinaryCompare.Checked; if actBinaryCompare.Checked then begin PushPop(FElevate); try BinaryDiffList.Clear; BinaryViewerLeft.FileName:= edtFileNameLeft.Text; BinaryViewerRight.FileName:= edtFileNameRight.Text; finally PushPop(FElevate); end; if FShowIdentical then begin if not BinaryViewerLeft.IsFileOpen then raise EFOpenError.Create(BinaryViewerLeft.LastError + LineEnding + edtFileNameLeft.Text); if not BinaryViewerRight.IsFileOpen then raise EFOpenError.Create(BinaryViewerRight.LastError + LineEnding + edtFileNameRight.Text); end; StatusBar.Panels[0].Text := EmptyStr; StatusBar.Panels[1].Text := EmptyStr; StatusBar.Panels[2].Text := EmptyStr; StatusBar.Panels[3].Text := EmptyStr; end else begin BinaryViewerLeft.FileName:= EmptyStr; BinaryViewerRight.FileName:= EmptyStr; OpenFileLeft(edtFileNameLeft.Text); OpenFileRight(edtFileNameRight.Text); end; actStartCompare.Execute; end; procedure TfrmDiffer.actCancelCompareExecute(Sender: TObject); begin if not actBinaryCompare.Checked then Diff.Cancel else begin if Assigned(BinaryCompare) then begin BinaryCompare.Terminate; BinaryCompare:= nil; end; end; end; procedure TfrmDiffer.actAboutExecute(Sender: TObject); begin ShowMessage('Internal Differ tool of Double Commander.' + LineEnding + LineEnding + 'It is inspired by Flavio Etrusco''s Pariter tool.' + LineEnding + 'You can find it on: http://sourceforge.net/projects/pariter' + LineEnding + 'It is based on Angus Johnson''s excellent TDiff component.' + LineEnding + 'You can find it on: http://www.users.on.net/johnson/delphi'); end; procedure TfrmDiffer.actEditCopyExecute(Sender: TObject); begin SynDiffEditActive.CopyToClipboard; end; procedure TfrmDiffer.actEditCutExecute(Sender: TObject); begin SynDiffEditActive.CutToClipboard; end; procedure TfrmDiffer.actEditDeleteExecute(Sender: TObject); begin SynDiffEditActive.ClearSelection; end; procedure TfrmDiffer.actEditPasteExecute(Sender: TObject); begin SynDiffEditActive.PasteFromClipboard; end; procedure TfrmDiffer.actEditRedoExecute(Sender: TObject); begin SynDiffEditActive.Redo; end; procedure TfrmDiffer.actEditSelectAllExecute(Sender: TObject); begin SynDiffEditActive.SelectAll; end; procedure TfrmDiffer.actEditUndoExecute(Sender: TObject); begin SynDiffEditActive.Undo; end; procedure TfrmDiffer.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; procedure TfrmDiffer.actIgnoreCaseExecute(Sender: TObject); begin if actAutoCompare.Checked then actStartCompare.Execute; end; procedure TfrmDiffer.actLineDifferencesExecute(Sender: TObject); begin if actLineDifferences.Checked and (Diff.Count <> 0) then begin SynDiffEditLeft.Highlighter:= SynDiffHighlighterLeft; SynDiffEditRight.Highlighter:= SynDiffHighlighterRight; end else begin SynDiffEditLeft.Highlighter:= nil; SynDiffEditRight.Highlighter:= nil; end; SynDiffEditLeft.Repaint; SynDiffEditRight.Repaint; end; procedure TfrmDiffer.actKeepScrollingExecute(Sender: TObject); begin BinaryViewerLeft.KeepScrolling:= actKeepScrolling.Checked; BinaryViewerRight.KeepScrolling:= actKeepScrolling.Checked; end; procedure TfrmDiffer.btnLeftEncodingClick(Sender: TObject); begin pmEncodingLeft.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmDiffer.btnRightEncodingClick(Sender: TObject); begin pmEncodingRight.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmDiffer.edtFileNameLeftAcceptFileName(Sender: TObject; var Value: String); begin OpenFileLeft(Value); if actAutoCompare.Checked then actStartCompare.Execute; end; procedure TfrmDiffer.edtFileNameRightAcceptFileName(Sender: TObject; var Value: String); begin OpenFileRight(Value); if actAutoCompare.Checked then actStartCompare.Execute; end; procedure TfrmDiffer.FormCreate(Sender: TObject); begin ScrollLock:= 0; Diff:= TDiff.Create(Self); SynDiffEditLeft:= TSynDiffEdit.Create(Self); SynDiffEditRight:= TSynDiffEdit.Create(Self); SynDiffHighlighterLeft:= TSynDiffHighlighter.Create(SynDiffEditLeft); SynDiffHighlighterRight:= TSynDiffHighlighter.Create(SynDiffEditRight); SynDiffEditLeft.Parent:= pnlLeft; SynDiffEditRight.Parent:= pnlRight; SynDiffEditLeft.Align:= alClient; SynDiffEditRight.Align:= alClient; SynDiffEditLeft.PopupMenu:= ContextMenu; SynDiffEditRight.PopupMenu:= ContextMenu; SynDiffEditLeft.ModifiedFile:= SynDiffEditRight; SynDiffEditRight.OriginalFile:= SynDiffEditLeft; SynDiffEditLeft.OnEnter:= @SynDiffEditEnter; SynDiffEditRight.OnEnter:= @SynDiffEditEnter; SynDiffEditLeft.OnStatusChange:= @SynDiffEditLeftStatusChange; SynDiffEditRight.OnStatusChange:= @SynDiffEditRightStatusChange; // Set active editor SynDiffEditActive:= SynDiffEditLeft; BinaryDiffList:= TFPList.Create; BinaryViewerLeft:= TBinaryDiffViewer.Create(Self); BinaryViewerRight:= TBinaryDiffViewer.Create(Self); BinaryViewerLeft.OnFileOpen:= @FileOpenUAC; BinaryViewerRight.OnFileOpen:= @FileOpenUAC; BinaryViewerLeft.Visible:= False; BinaryViewerRight.Visible:= False; BinaryViewerLeft.Parent:= pnlLeft; BinaryViewerRight.Parent:= pnlRight; BinaryViewerLeft.Align:= alClient; BinaryViewerRight.Align:= alClient; BinaryViewerLeft.SecondViewer:= BinaryViewerRight; BinaryViewerRight.SecondViewer:= BinaryViewerLeft; with gColors.Differ^ do begin BinaryViewerLeft.Modified:= ModifiedBinaryColor; BinaryViewerRight.Modified:= ModifiedBinaryColor; SetColors(AddedColor, DeletedColor, ModifiedColor); end; FontOptionsToFont(gFonts[dcfEditor], SynDiffEditLeft.Font); FontOptionsToFont(gFonts[dcfEditor], SynDiffEditRight.Font); FontOptionsToFont(gFonts[dcfViewer], BinaryViewerLeft.Font); FontOptionsToFont(gFonts[dcfViewer], BinaryViewerRight.Font); // Load settings actIgnoreCase.Checked := gDifferIgnoreCase; actAutoCompare.Checked := gDifferAutoCompare; actKeepScrolling.Checked := gDifferKeepScrolling; actLineDifferences.Checked := gDifferLineDifferences; actPaintBackground.Checked := gDifferPaintBackground; actIgnoreWhiteSpace.Checked := gDifferIgnoreWhiteSpace; // Initialize mode actKeepScrollingExecute(actKeepScrolling); actPaintBackgroundExecute(actPaintBackground); // Initialize property storage InitPropStorage(Self); // Fill encoding menu EncodingList:= TStringList.Create; GetSupportedEncodings(EncodingList); FillEncodingMenu(miEncodingLeft, @SetEncodingLeft, 1); FillEncodingMenu(miEncodingRight, @SetEncodingRight, 2); FillEncodingMenu(pmEncodingLeft.Items, @SetEncodingLeft, 1); FillEncodingMenu(pmEncodingRight.Items, @SetEncodingRight, 2); EncodingList.Free; end; procedure TfrmDiffer.FormDestroy(Sender: TObject); begin FreeAndNil(Diff); FreeAndNil(BinaryDiffList); end; procedure TfrmDiffer.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then begin Key:= 0; Close; end; end; procedure TfrmDiffer.FormResize(Sender: TObject); begin pnlLeft.Width:= (ClientWidth div 2) - (Splitter.Width div 2); end; procedure TfrmDiffer.btnCancelClick(Sender: TObject); begin FCancel:= True; if actBinaryCompare.Checked and Assigned(BinaryCompare) then BinaryCompare.Terminate else begin Diff.Cancel; end; CloseProgressDialog; end; procedure TfrmDiffer.tmProgressTimer(Sender: TObject); begin tmProgress.Enabled:= False; ShowProgressDialog; end; procedure TfrmDiffer.BinaryCompareFinish; begin BinaryCompare:= nil; if FCancel then begin if FShowIdentical then Free; Exit; end; BinaryDiffIndex:= -1; tmProgress.Enabled:= False; StatusBar.Panels[0].Text := EmptyStr; StatusBar.Panels[1].Text := rsDiffModifies + IntToStr(BinaryDiffList.Count); StatusBar.Panels[2].Text := EmptyStr; StatusBar.Panels[3].Text := EmptyStr; actStartCompare.Enabled := True; actCancelCompare.Enabled := False; actBinaryCompare.Enabled := True; if FShowIdentical then begin CloseProgressDialog; FShowIdentical:= (BinaryDiffList.Count = 0); if FShowIdentical then ShowIdentical else begin FShowIdentical:= False; Application.QueueAsyncCall(@ShowFirstDifference, 0); ShowDialog; end; end; end; procedure TfrmDiffer.ShowDialog; begin if FModal then ShowModal else if (FWaitData = nil) then ShowOnTop else FWaitData.ShowOnTop(Self); end; procedure TfrmDiffer.ShowIdentical; var Message: String; Encoding, LineBreak: Boolean; DlgType: TMsgDlgType = mtInformation; begin Message:= rsDiffFilesIdentical + LineEnding + LineEnding; Message+= edtFileNameLeft.Text + LineEnding + edtFileNameRight.Text; if not actBinaryCompare.Checked then begin Encoding:= (SynDiffEditLeft.Encoding <> SynDiffEditRight.Encoding); LineBreak:= (SynDiffEditLeft.Lines.TextLineBreakStyle <> SynDiffEditRight.Lines.TextLineBreakStyle); if Encoding or LineBreak then begin DlgType:= mtWarning; Message:= rsDiffTextIdenticalNotMatch; if Encoding then begin Message+= LineEnding + rsDiffTextDifferenceEncoding + Format(' (%s, %s)', [SynDiffEditLeft.Encoding, SynDiffEditRight.Encoding]); end; if LineBreak then begin Message+= LineEnding + rsDiffTextDifferenceLineEnding; end; end else if actIgnoreCase.Checked or actIgnoreWhiteSpace.Checked then begin DlgType:= mtWarning; Message:= rsDiffTextIdentical; if actIgnoreCase.Checked then begin Message+= LineEnding + actIgnoreCase.Caption; end; if actIgnoreWhiteSpace.Checked then begin Message+= LineEnding + actIgnoreWhiteSpace.Caption; end; end; end; if MessageDlg(rsToolDiffer, Message, DlgType, [mbIgnore, mbCancel], 0, mbIgnore) = mrCancel then Close else begin FShowIdentical:= False; ShowDialog; end; end; procedure TfrmDiffer.ShowTextIdentical; var Message: String; begin Message:= rsDiffTextIdenticalNotMatch; if (SynDiffEditLeft.Encoding <> SynDiffEditRight.Encoding) then Message+= LineEnding + rsDiffTextDifferenceEncoding; if (SynDiffEditLeft.Lines.TextLineBreakStyle <> SynDiffEditRight.Lines.TextLineBreakStyle) then Message+= LineEnding + rsDiffTextDifferenceLineEnding; MessageDlg(rsToolDiffer, Message, mtWarning, [mbOK], 0, mbOK); end; procedure TfrmDiffer.ShowProgressDialog; var lblPrompt : TLabel; btnCancel : TBitBtn; pbProgress: TProgressBar; begin frmProgress := TModalDialog.CreateNew(nil, 0); with frmProgress do begin BorderStyle := bsDialog; Position := poOwnerFormCenter; AutoSize := True; Height := 120; ChildSizing.TopBottomSpacing := 8; ChildSizing.LeftRightSpacing := 8; Caption := Self.Caption; lblPrompt := TLabel.Create(frmProgress); with lblPrompt do begin Parent := frmProgress; Caption := rsDiffComparing; Top := 6; Left := 6; end; pbProgress:= TProgressBar.Create(frmProgress); with pbProgress do begin Parent := frmProgress; Style:= pbstMarquee; Left := 6; AnchorToNeighbour(akTop, 6, lblPrompt); Constraints.MinWidth := Math.Max(280, Screen.Width div 4); end; btnCancel := TBitBtn.Create(frmProgress); with btnCancel do begin AutoSize := True; Parent := frmProgress; Kind := bkCancel; Cancel := True; OnClick:= @btnCancelClick; Anchors := [akTop, akRight]; AnchorToNeighbour(akTop, 18, pbProgress); AnchorSide[akRight].Control := pbProgress; AnchorSide[akRight].Side := asrCenter; end; if FModal then ShowModal else if (FWaitData = nil) then ShowOnTop else FWaitData.ShowOnTop(frmProgress); end; end; procedure TfrmDiffer.CloseProgressDialog; begin if Assigned(frmProgress) then begin frmProgress.Close; FreeAndNil(frmProgress); end; end; procedure TfrmDiffer.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; // Save settings gDifferIgnoreCase := actIgnoreCase.Checked; gDifferAutoCompare := actAutoCompare.Checked; gDifferKeepScrolling := actKeepScrolling.Checked; gDifferPaintBackground := actPaintBackground.Checked; gDifferIgnoreWhiteSpace := actIgnoreWhiteSpace.Checked; if actLineDifferences.Enabled then begin gDifferLineDifferences := actLineDifferences.Checked; end; end; procedure TfrmDiffer.FormCloseQuery(Sender: TObject; var CanClose: boolean); var Result: TMyMsgResult; begin if SynDiffEditLeft.Modified then begin Result:= msgYesNoCancel(Format(rsMsgFileChangedSave, [edtFileNameLeft.FileName])); CanClose:= Result <> mmrCancel; if Result = mmrYes then actSaveLeft.Execute else if Result = mmrCancel then Exit; end; if SynDiffEditRight.Modified then begin Result:= msgYesNoCancel(Format(rsMsgFileChangedSave, [edtFileNameRight.FileName])); CanClose:= Result <> mmrCancel; if Result = mmrYes then actSaveRight.Execute else if Result = mmrCancel then Exit; end; end; procedure TfrmDiffer.Clear(bLeft, bRight: Boolean); begin if bLeft then begin SynDiffEditLeft.Lines.Clear; SetLength(HashListLeft, 0); end; if bRight then begin SynDiffEditRight.Lines.Clear; SetLength(HashListRight, 0); end; Diff.Clear; StatusBar.Panels[0].Text := EmptyStr; StatusBar.Panels[1].Text := EmptyStr; StatusBar.Panels[2].Text := EmptyStr; StatusBar.Panels[3].Text := EmptyStr; actStartCompare.Enabled := True; end; procedure TfrmDiffer.cm_CopyLeftToRight(const Params: array of string); var I, iStart, iFinish: Integer; begin I := SynDiffEditLeft.CaretY - 1; iStart:= SynDiffEditLeft.DiffBegin(I); iFinish:= SynDiffEditLeft.DiffEnd(I); if SynDiffEditLeft.Lines.Kind[iStart] <> ckAdd then begin for I:= iStart to iFinish do begin SynDiffEditRight.Lines[I]:= SynDiffEditLeft.Lines[I]; if SynDiffEditLeft.Lines.Kind[I] = ckDelete then begin SynDiffEditLeft.Lines.Kind[I]:= ckNone; SynDiffEditRight.Lines.SetKindAndNumber(I, ckNone, 0); end; end; end else begin for I:= iStart to iFinish do begin if SynDiffEditLeft.Lines[iStart] <> EmptyStr then begin SynDiffEditRight.Lines[iStart]:= SynDiffEditLeft.Lines[iStart]; Inc(iStart); end else begin SynDiffEditLeft.Lines.Delete(iStart); SynDiffEditRight.Lines.Delete(iStart); end; end; end; SynDiffEditLeft.Renumber; SynDiffEditRight.Renumber; end; procedure TfrmDiffer.cm_CopyRightToLeft(const Params: array of string); var I, iStart, iFinish: Integer; begin I := SynDiffEditRight.CaretY - 1; iStart:= SynDiffEditRight.DiffBegin(I); iFinish:= SynDiffEditRight.DiffEnd(I); if SynDiffEditLeft.Lines.Kind[iStart] <> ckDelete then begin for I:= iStart to iFinish do begin SynDiffEditLeft.Lines[I]:= SynDiffEditRight.Lines[I]; if SynDiffEditRight.Lines.Kind[I] = ckAdd then begin SynDiffEditRight.Lines.Kind[I]:= ckNone; SynDiffEditLeft.Lines.SetKindAndNumber(I, ckNone, 0); end; end; end else begin for I:= iStart to iFinish do begin if SynDiffEditRight.Lines[iStart] <> EmptyStr then begin SynDiffEditLeft.Lines[iStart]:= SynDiffEditRight.Lines[iStart]; Inc(iStart); end else begin SynDiffEditLeft.Lines.Delete(iStart); SynDiffEditRight.Lines.Delete(iStart); end; end; end; SynDiffEditLeft.Renumber; SynDiffEditRight.Renumber; end; procedure TfrmDiffer.cm_Find(const Params: array of string); begin if not actBinaryCompare.Checked then begin ShowSearchReplaceDialog(Self, SynDiffEditActive, cbUnchecked, FSearchOptions); end; end; procedure TfrmDiffer.cm_FindNext(const Params: array of string); begin if not actBinaryCompare.Checked then begin if gFirstTextSearch then begin FSearchOptions.Flags -= [ssoBackwards]; ShowSearchReplaceDialog(Self, SynDiffEditActive, cbUnchecked, FSearchOptions); end else if FSearchOptions.SearchText <> '' then begin DoSearchReplaceText(SynDiffEditActive, False, False, FSearchOptions); FSearchOptions.Flags -= [ssoEntireScope]; end; end; end; procedure TfrmDiffer.cm_FindPrev(const Params: array of string); begin if not actBinaryCompare.Checked then begin if gFirstTextSearch then begin FSearchOptions.Flags += [ssoBackwards]; ShowSearchReplaceDialog(Self, SynDiffEditActive, cbUnchecked, FSearchOptions); end else if FSearchOptions.SearchText <> '' then begin SynDiffEditActive.SelEnd := SynDiffEditActive.SelStart; DoSearchReplaceText(SynDiffEditActive, False, True, FSearchOptions); FSearchOptions.Flags -= [ssoEntireScope]; end; end; end; procedure TfrmDiffer.cm_FindReplace(const Params: array of string); begin if not actBinaryCompare.Checked then begin ShowSearchReplaceDialog(Self, SynDiffEditActive, cbChecked, FSearchOptions); end; end; procedure TfrmDiffer.cm_GotoLine(const Params: array of string); var P: TPoint; Value: String; NewTopLine: Integer; begin if not actBinaryCompare.Checked then begin if ShowInputQuery(rsEditGotoLineTitle, rsEditGotoLineQuery, Value) then begin P.X := 1; P.Y := GetDisplayNumber(StrToIntDef(Value, 1)); NewTopLine := P.Y - (SynDiffEditActive.LinesInWindow div 2); if NewTopLine < 1 then begin NewTopLine := 1; end; SynDiffEditActive.CaretXY := P; SynDiffEditActive.TopLine := NewTopLine; SynDiffEditActive.SetFocus; end; end; end; procedure TfrmDiffer.cm_Exit(const Params: array of string); begin Close; end; procedure TfrmDiffer.cm_FirstDifference(const Params: array of string); var Line: Integer; Kind: TChangeKind; begin if actBinaryCompare.Checked then begin if BinaryDiffList.Count > 0 then begin BinaryDiffIndex:= 0; BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); if not actKeepScrolling.Checked then BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); end; end else begin // Start at first line Line := 0; if Line = SynDiffEditLeft.Lines.Count then Exit; // Skip unmodified lines Kind := ckNone; while (Line < SynDiffEditLeft.Lines.Count - 1) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line); Inc(Line); SynDiffEditLeft.CaretY := Line; SynDiffEditLeft.TopLine := Line; SynDiffEditRight.CaretY := Line; if not actKeepScrolling.Checked then begin SynDiffEditRight.TopLine := Line; end; end; end; procedure TfrmDiffer.cm_LastDifference(const Params: array of string); var Line: Integer; Kind: TChangeKind; begin if actBinaryCompare.Checked then begin if BinaryDiffList.Count > 0 then begin BinaryDiffIndex:= BinaryDiffList.Count - 1; BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); if not actKeepScrolling.Checked then BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); end; end else begin Line := SynDiffEditLeft.Lines.Count - 1; if Line = 0 then Exit; // Skip unmodified lines Kind := ckNone; while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line); // Find top line of previous difference Kind:= SynDiffEditLeft.Lines.Kind[Line]; while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line); if (Line <> 0) then Inc(Line, 2); SynDiffEditLeft.CaretY := Line; SynDiffEditLeft.TopLine := Line; SynDiffEditRight.CaretY := Line; if not actKeepScrolling.Checked then begin SynDiffEditRight.TopLine := Line; end; end; end; procedure TfrmDiffer.cm_NextDifference(const Params: array of string); var Line: Integer; Kind: TChangeKind; begin if actBinaryCompare.Checked then begin if BinaryDiffIndex < BinaryDiffList.Count - 1 then begin BinaryDiffIndex:= BinaryDiffIndex + 1; BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); if not actKeepScrolling.Checked then BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); end; end else begin Line := SynDiffEditLeft.CaretY - 1; if Line = SynDiffEditLeft.Lines.Count - 1 then Exit; // Skip lines with current difference type Kind := SynDiffEditLeft.Lines.Kind[Line]; while (Line < SynDiffEditLeft.Lines.Count - 1) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line); if SynDiffEditLeft.Lines.Kind[Line] = ckNone then begin // Skip unmodified lines Kind := ckNone; while (Line < SynDiffEditLeft.Lines.Count - 1) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line); end; Inc(Line); SynDiffEditLeft.CaretY := Line; SynDiffEditLeft.TopLine := Line; SynDiffEditRight.CaretY := Line; if not actKeepScrolling.Checked then begin SynDiffEditRight.TopLine := Line; end; end; end; procedure TfrmDiffer.cm_PrevDifference(const Params: array of string); var Line: Integer; Kind: TChangeKind; begin if actBinaryCompare.Checked then begin if BinaryDiffIndex > 0 then begin BinaryDiffIndex:= BinaryDiffIndex - 1; BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); if not actKeepScrolling.Checked then BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]); end; end else begin Line := SynDiffEditLeft.CaretY - 1; if Line = 0 then Exit; // Skip lines with current difference type Kind := SynDiffEditLeft.Lines.Kind[Line]; while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line); if SynDiffEditLeft.Lines.Kind[Line] = ckNone then begin // Skip unmodified lines Kind := ckNone; while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line); end; // Find top line of previous difference Kind:= SynDiffEditLeft.Lines.Kind[Line]; while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line); if (Line <> 0) then Inc(Line, 2); SynDiffEditLeft.CaretY := Line; SynDiffEditLeft.TopLine := Line; SynDiffEditRight.CaretY := Line; if not actKeepScrolling.Checked then begin SynDiffEditRight.TopLine := Line; end; end; end; procedure TfrmDiffer.cm_Reload(const Params: array of string); begin OpenFileLeft(edtFileNameLeft.FileName); OpenFileRight(edtFileNameRight.FileName); if actAutoCompare.Checked then actStartCompare.Execute; end; procedure TfrmDiffer.cm_SaveLeft(const Params: array of string); begin PushPop(FElevate); try SaveToFile(SynDiffEditLeft, edtFileNameLeft.FileName); finally PushPop(FElevate); end; end; procedure TfrmDiffer.cm_SaveRight(const Params: array of string); begin PushPop(FElevate); try SaveToFile(SynDiffEditRight, edtFileNameRight.FileName); finally PushPop(FElevate); end; end; constructor TfrmDiffer.Create(TheOwner: TComponent); var HMForm: THMForm; begin inherited Create(TheOwner); FCommands := TFormCommands.Create(Self, actionList); HMForm := HotMan.Register(Self, HotkeysCategory); HMForm.RegisterActionList(actionList); end; destructor TfrmDiffer.Destroy; begin BinaryViewerLeft.SecondViewer:= nil; BinaryViewerRight.SecondViewer:= nil; HotMan.UnRegister(Self); inherited Destroy; if Assigned(FWaitData) then FWaitData.Done; end; procedure TfrmDiffer.AfterConstruction; begin inherited AfterConstruction; ToolBar.ImagesWidth:= gToolIconsSize; ToolBar.SetButtonSize(gToolIconsSize + ScaleX(6, 96), gToolIconsSize + ScaleY(6, 96)); end; procedure TfrmDiffer.BuildHashList(bLeft, bRight: Boolean); var S: String; I: Integer; begin if bLeft then begin FLeftLen:= 0; SetLength(HashListLeft, SynDiffEditLeft.Lines.Count); for I := 0 to SynDiffEditLeft.Lines.Count - 1 do begin S:= SynDiffEditLeft.Lines[I]; FLeftLen:= Max(FLeftLen, Length(S)); HashListLeft[I]:= Integer(HashString(S, actIgnoreCase.Checked, actIgnoreWhiteSpace.Checked)); end; end; if bRight then begin FRightLen:= 0; SetLength(HashListRight, SynDiffEditRight.Lines.Count); for I := 0 to SynDiffEditRight.Lines.Count - 1 do begin S:= SynDiffEditRight.Lines[I]; FRightLen:= Max(FRightLen, Length(S)); HashListRight[I]:= Integer(HashString(S, actIgnoreCase.Checked, actIgnoreWhiteSpace.Checked)); end; end; actLineDifferences.Enabled:= (FLeftLen < High(UInt16)) and (FRightLen < High(UInt16)); if not actLineDifferences.Enabled then actLineDifferences.Checked:= False; actStartCompare.Enabled := (Length(HashListLeft) > 0) and (Length(HashListRight) > 0); actCopyLeftToRight.Enabled := actStartCompare.Enabled; actCopyRightToLeft.Enabled := actStartCompare.Enabled; end; procedure TfrmDiffer.SetColors(cAdded, cDeleted, cModified: TColor); begin with SynDiffEditLeft do begin Colors.Added:= cAdded; Colors.Deleted:= cDeleted; Colors.Modified:= cModified; end; with SynDiffEditRight do begin Colors.Added:= cAdded; Colors.Deleted:= cDeleted; Colors.Modified:= cModified; end; SynDiffHighlighterLeft.UpdateColors; SynDiffHighlighterRight.UpdateColors; end; procedure TfrmDiffer.ChooseEncoding(SynDiffEdit: TSynDiffEdit); begin if SynDiffEdit = SynDiffEditLeft then begin ChooseEncoding(miEncodingLeft, SynDiffEdit.Encoding); ChooseEncoding(pmEncodingLeft.Items, SynDiffEdit.Encoding); end else begin ChooseEncoding(miEncodingRight, SynDiffEdit.Encoding); ChooseEncoding(pmEncodingRight.Items, SynDiffEdit.Encoding); end; end; function TfrmDiffer.GetDisplayNumber(LineNumber: Integer): Integer; var I: Integer; begin Result := 1; for I := 0 to SynDiffEditActive.Lines.Count - 1 do begin if SynDiffEditActive.Lines.Number[I] = LineNumber then begin Result := I + 1; Break; end; end; end; procedure TfrmDiffer.ChooseEncoding(MenuItem: TMenuItem; Encoding: String); var I: Integer; begin Encoding:= NormalizeEncoding(Encoding); for I:= 0 to MenuItem.Count - 1 do if SameText(NormalizeEncoding(MenuItem.Items[I].Caption), Encoding) then MenuItem.Items[I].Checked:= True; end; procedure TfrmDiffer.FillEncodingMenu(TheOwner: TMenuItem; MenuHandler: TNotifyEvent; GroupIndex: LongInt); var I: Integer; mi: TMenuItem; begin for I:= 0 to EncodingList.Count - 1 do begin mi:= TMenuItem.Create(TheOwner); mi.Caption:= EncodingList[I]; mi.RadioItem:= True; mi.GroupIndex:= GroupIndex; mi.OnClick:= MenuHandler; TheOwner.Add(mi); end; end; procedure TfrmDiffer.LoadFromFile(SynDiffEdit: TSynDiffEdit; const FileName: String); var AText: String; fsFileStream: TFileStreamUAC; begin try fsFileStream:= TFileStreamUAC.Create(FileName, fmOpenRead or fmShareDenyNone); try SetLength(AText, fsFileStream.Size); fsFileStream.Read(Pointer(AText)^, Length(AText)); if Length(SynDiffEdit.Encoding) = 0 then begin SynDiffEdit.Encoding:= DetectEncoding(AText); ChooseEncoding(SynDiffEdit); end; with SynDiffEdit do begin if (Encoding = EncodingUTF16LE) or (Encoding = EncodingUTF16BE) then begin AText:= Copy(AText, 3, MaxInt); // Skip BOM end; AText:= ConvertEncoding(AText, Encoding, EncodingUTF8); end; SynDiffEdit.Lines.Text:= AText; // Add empty line if needed if (Length(AText) > 0) and (AText[Length(AText)] in [#10, #13]) then SynDiffEdit.Lines.Add(EmptyStr); // Determine line break style SynDiffEdit.Lines.TextLineBreakStyle := GuessLineBreakStyle(AText); finally FreeAndNil(fsFileStream); end; except on E: Exception do begin E.Message:= E.Message + LineEnding + FileName; if FShowIdentical then raise; msgError(E.Message); end; end; end; procedure TfrmDiffer.SaveToFile(SynDiffEdit: TSynDiffEdit; const FileName: String); var AText: String; begin AText := EmptyStr; if (SynDiffEdit.Encoding = EncodingUTF16LE) then AText := UTF16LEBOM else if (SynDiffEdit.Encoding = EncodingUTF16BE) then begin AText := UTF16BEBOM end; with TStringListEx.Create do try Assign(SynDiffEdit.Lines); SkipLastLineBreak:= True; // remove fake lines RemoveFake; // restore encoding AText+= ConvertEncoding(Text, EncodingUTF8, SynDiffEdit.Encoding); finally Free; end; // save to file try with TFileStreamUAC.Create(FileName, fmCreate) do try WriteBuffer(Pointer(AText)^, Length(AText)); finally Free; end; SynDiffEdit.Modified:= False; // needed for the undo stack except on E: Exception do msgError(rsMsgErrSaveFile + ' ' + FileName + LineEnding + E.Message); end; end; procedure TfrmDiffer.OpenFileLeft(const FileName: String); begin PushPop(FElevate); try if not FileExistsUAC(FileName) then Exit; if actBinaryCompare.Checked then begin BinaryDiffList.Clear; BinaryViewerLeft.FileName:= FileName end else begin Clear(True, False); LoadFromFile(SynDiffEditLeft, FileName); BuildHashList(True, False); SynDiffEditLeft.Repaint; end; finally PushPop(FElevate); end; end; procedure TfrmDiffer.OpenFileRight(const FileName: String); begin PushPop(FElevate); try if not FileExistsUAC(FileName) then Exit; if actBinaryCompare.Checked then begin BinaryDiffList.Clear; BinaryViewerRight.FileName:= FileName end else begin Clear(False, True); LoadFromFile(SynDiffEditRight, FileName); BuildHashList(False, True); SynDiffEditRight.Repaint; end; finally PushPop(FElevate); end; end; procedure TfrmDiffer.SetEncodingLeft(Sender: TObject); begin SynDiffEditLeft.Encoding:= (Sender as TMenuItem).Caption; ChooseEncoding(miEncodingLeft, SynDiffEditLeft.Encoding); ChooseEncoding(pmEncodingLeft.Items, SynDiffEditLeft.Encoding); actReload.Execute; end; procedure TfrmDiffer.SetEncodingRight(Sender: TObject); begin SynDiffEditRight.Encoding:= (Sender as TMenuItem).Caption; ChooseEncoding(miEncodingRight, SynDiffEditRight.Encoding); ChooseEncoding(pmEncodingRight.Items, SynDiffEditRight.Encoding); actReload.Execute; end; procedure TfrmDiffer.SynDiffEditEnter(Sender: TObject); begin SynDiffEditActive:= (Sender as TSynDiffEdit); end; procedure TfrmDiffer.ShowFirstDifference(Data: PtrInt); begin cm_FirstDifference([]); end; procedure TfrmDiffer.SynDiffEditLeftStatusChange(Sender: TObject; Changes: TSynStatusChanges); begin if (actKeepScrolling.Checked) and (ScrollLock = 0) and ((scTopLine in Changes) or (scLeftChar in Changes)) then try Inc(ScrollLock); while (SynDiffEditRight.PaintLock <> 0) do Sleep(1); SynDiffEditRight.TopLine:= SynDiffEditLeft.TopLine; SynDiffEditRight.LeftChar:= SynDiffEditLeft.LeftChar; finally Dec(ScrollLock); end; end; procedure TfrmDiffer.SynDiffEditRightStatusChange(Sender: TObject; Changes: TSynStatusChanges); begin if (actKeepScrolling.Checked) and (ScrollLock = 0) and ((scTopLine in Changes) or (scLeftChar in Changes)) then try Inc(ScrollLock); while (SynDiffEditLeft.PaintLock <> 0) do Sleep(1); SynDiffEditLeft.TopLine:= SynDiffEditRight.TopLine; SynDiffEditLeft.LeftChar:= SynDiffEditRight.LeftChar; finally Dec(ScrollLock); end; end; procedure TfrmDiffer.CMThemeChanged(var Message: TLMessage); begin with gColors.Differ^ do begin BinaryViewerLeft.Modified:= ModifiedBinaryColor; BinaryViewerRight.Modified:= ModifiedBinaryColor; SetColors(AddedColor, DeletedColor, ModifiedColor); end; if not actBinaryCompare.Checked then begin SynDiffEditLeft.Repaint; SynDiffEditRight.Repaint; end else begin BinaryViewerLeft.Repaint; BinaryViewerRight.Repaint; end; end; initialization TFormCommands.RegisterCommandsForm(TfrmDiffer, HotkeysCategory, @rsHotkeyCategoryDiffer); end. ����������������������������������������������������������������������������������������doublecmd-1.1.22/src/feditor.lfm��������������������������������������������������������������������0000644�0001750�0000144�00000130755�14743153644�015544� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmEditor: TfrmEditor Left = 566 Height = 480 Top = 271 Width = 640 ActiveControl = Editor Caption = 'Editor' ClientHeight = 460 ClientWidth = 640 Icon.Data = { 7E04000000000100010010100000010020006804000016000000280000001000 0000200000000100200000000000000000000000000000000000000000000000 000000000000858A88A3858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88A3000000000000 000000000000858A88FFEEEEEEFFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2 B2FFB2B2B2FFB2B2B2FFB1B1B1FFB2B2B2FFB2B2B2FF858A88FF000000000000 000000000000858A88FFFFFFFFFFECECECFFEBEBEBFFEAEAEAFFEAEAEAFFE9E9 E9FFEBEBEBFFEAEAEAFFEBEBEBFFECECECFFB2B2B2FF858A88FF000000000000 000000000000858A88FFFFFFFFFFDBDBDBFFCBCBCBFFC4C4C4FF000000FF0259 8FFF636363FF8C8C8CFFCACACAFFDADADAFFB2B2B2FF858A88FF000000020000 000000000000858A88FFFFFFFFFFECECECFFECECECFFE9E9E9FF02598FFF2642 4CFF36576BFF02598FFF9D9D9DFFD6D6D6FFAEAEAEFF858A88FF000000000000 000000000000858A88FFFFFFFFFFDBDBDBFFCCCCCCFFCBCBCBFF757575FF395B 70FF8AABC2FF5585A3FF02598FFF8F8F8FFF868686FF858A88FF000000010000 000000000000858A88FFFFFFFFFFECECECFFECECECFFECECECFFEBEBEBFF0259 8FFFC4E5EDFF649FC8FF5787A4FF02598FFF717171FF858A88FF000000000000 000100000000858A88FFFFFFFFFFDBDBDBFFCCCCCCFFCCCCCCFFCCCCCCFFB7B7 B7FF02598FFFC5E6EDFF68A6CEFF5784A0FF02598FFF858A88FF000000000000 000100000000858A88FFFFFFFFFFECECECFFECECECFFECECECFFECECECFFECEC ECFFD3D3D3FF02598FFFC6EAEEFF69AACFFF5683A0FF02598FFF02598F330000 000000000000858A88FFFFFFFFFFDBDBDBFFCCCCCCFFCCCCCCFFCCCCCCFFCCCC CCFFCCCCCCFFB7B7B7FF02598FFFC7EBEFFF6AACD2FF5787A4FF02598FFF0259 8F3300000000858A88FFFFFFFFFFECECECFFECECECFFECECECFFECECECFFECEC ECFFECECECFFECECECFFD3D3D3FF02598FFFC7EBEFFF6AACD2FF5583A1FC0259 8FFF00000000858A88FFEBEBEBFF00A0C4FFBCBCBCFF00A0C4FFB8B8B8FF00A0 C4FFB8B8B8FF00A0C4FFB8B8B8FF00A0C4FF02598FFFC6EAEEFF71ADCFFF0259 8FFF00000000858A88FF00A0C4FF3DB1EBFF00A0C4FF3DB1EBFF00A0C4FF3DB1 EBFF00A0C4FF3DB1EBFF00A0C4FF3DB1EBFF00A0C4FF02598FFF02598FFF0259 8F5C00000000858A886600A0C4FFC6E8F9FF00A0C4FFC6E8F9FF00A0C4FFC6E8 F9FF00A0C4FFC6E8F9FF00A0C4FFC6E8F9FF00A0C4FF00000000000000000000 0000000000000000000000A0C44400A0C4FF00A0C44400A0C4FF00A0C44400A0 C4FF00A0C44400A0C4FF00A0C44400A0C4FF00A0C44400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000800300008003000080030000800300008003000080030000800300008003 00008003000080010000800000008000000080010000C0070000EAAF0000FFFF 0000 } KeyPreview = True Menu = MainMenu1 OnClose = frmEditorClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate SessionProperties = 'Height;Width;WindowState;Left;Top' ShowInTaskBar = stAlways LCLVersion = '2.2.3.0' object StatusBar: TStatusBar Left = 0 Height = 23 Top = 437 Width = 640 Panels = < item Width = 50 end item Width = 150 end item Width = 96 end item Width = 50 end item Width = 128 end> SimplePanel = False end inline Editor: TSynEdit Left = 0 Height = 411 Top = 26 Width = 640 Align = alClient Anchors = [akTop] Font.Color = clBlack Font.Height = 13 Font.Name = 'adobe-courier' Font.Pitch = fpFixed Font.Quality = fqNonAntialiased ParentColor = False ParentFont = False PopupMenu = pmContextMenu TabOrder = 0 OnMouseWheelDown = EditorMouseWheelDown OnMouseWheelUp = EditorMouseWheelUp BookMarkOptions.BookmarkImages = ilBookmarks BookMarkOptions.Xoffset = 48 Gutter.Width = 53 Gutter.MouseActions = < item ClickCount = ccAny ClickDir = cdDown Command = emcOnMainGutterClick end item Button = mbRight Command = emcContextMenu end> RightGutter.Width = 0 RightGutter.MouseActions = < item ClickCount = ccAny ClickDir = cdDown Command = emcOnMainGutterClick end item Button = mbRight Command = emcContextMenu end> Keystrokes = < item Command = ecUp ShortCut = 38 end item Command = ecSelUp ShortCut = 8230 end item Command = ecScrollUp ShortCut = 16422 end item Command = ecDown ShortCut = 40 end item Command = ecSelDown ShortCut = 8232 end item Command = ecScrollDown ShortCut = 16424 end item Command = ecLeft ShortCut = 37 end item Command = ecSelLeft ShortCut = 8229 end item Command = ecWordLeft ShortCut = 16421 end item Command = ecSelWordLeft ShortCut = 24613 end item Command = ecRight ShortCut = 39 end item Command = ecSelRight ShortCut = 8231 end item Command = ecWordRight ShortCut = 16423 end item Command = ecSelWordRight ShortCut = 24615 end item Command = ecPageDown ShortCut = 34 end item Command = ecSelPageDown ShortCut = 8226 end item Command = ecPageBottom ShortCut = 16418 end item Command = ecSelPageBottom ShortCut = 24610 end item Command = ecPageUp ShortCut = 33 end item Command = ecSelPageUp ShortCut = 8225 end item Command = ecPageTop ShortCut = 16417 end item Command = ecSelPageTop ShortCut = 24609 end item Command = ecLineStart ShortCut = 36 end item Command = ecSelLineStart ShortCut = 8228 end item Command = ecEditorTop ShortCut = 16420 end item Command = ecSelEditorTop ShortCut = 24612 end item Command = ecLineEnd ShortCut = 35 end item Command = ecSelLineEnd ShortCut = 8227 end item Command = ecEditorBottom ShortCut = 16419 end item Command = ecSelEditorBottom ShortCut = 24611 end item Command = ecToggleMode ShortCut = 45 end item Command = ecCopy ShortCut = 16429 end item Command = ecPaste ShortCut = 8237 end item Command = ecDeleteChar ShortCut = 46 end item Command = ecCut ShortCut = 8238 end item Command = ecDeleteLastChar ShortCut = 8 end item Command = ecDeleteLastChar ShortCut = 8200 end item Command = ecDeleteLastWord ShortCut = 16392 end item Command = ecUndo ShortCut = 32776 end item Command = ecRedo ShortCut = 40968 end item Command = ecLineBreak ShortCut = 13 end item Command = ecSelectAll ShortCut = 16449 end item Command = ecCopy ShortCut = 16451 end item Command = ecBlockIndent ShortCut = 24649 end item Command = ecLineBreak ShortCut = 16461 end item Command = ecInsertLine ShortCut = 16462 end item Command = ecDeleteWord ShortCut = 16468 end item Command = ecBlockUnindent ShortCut = 24661 end item Command = ecPaste ShortCut = 16470 end item Command = ecCut ShortCut = 16472 end item Command = ecDeleteLine ShortCut = 16473 end item Command = ecDeleteEOL ShortCut = 24665 end item Command = ecUndo ShortCut = 16474 end item Command = ecRedo ShortCut = 24666 end item Command = ecGotoMarker0 ShortCut = 16432 end item Command = ecGotoMarker1 ShortCut = 16433 end item Command = ecGotoMarker2 ShortCut = 16434 end item Command = ecGotoMarker3 ShortCut = 16435 end item Command = ecGotoMarker4 ShortCut = 16436 end item Command = ecGotoMarker5 ShortCut = 16437 end item Command = ecGotoMarker6 ShortCut = 16438 end item Command = ecGotoMarker7 ShortCut = 16439 end item Command = ecGotoMarker8 ShortCut = 16440 end item Command = ecGotoMarker9 ShortCut = 16441 end item Command = ecSetMarker0 ShortCut = 24624 end item Command = ecSetMarker1 ShortCut = 24625 end item Command = ecSetMarker2 ShortCut = 24626 end item Command = ecSetMarker3 ShortCut = 24627 end item Command = ecSetMarker4 ShortCut = 24628 end item Command = ecSetMarker5 ShortCut = 24629 end item Command = ecSetMarker6 ShortCut = 24630 end item Command = ecSetMarker7 ShortCut = 24631 end item Command = ecSetMarker8 ShortCut = 24632 end item Command = ecSetMarker9 ShortCut = 24633 end item Command = ecNormalSelect ShortCut = 24654 end item Command = ecColumnSelect ShortCut = 24643 end item Command = ecLineSelect ShortCut = 24652 end item Command = ecTab ShortCut = 9 end item Command = ecShiftTab ShortCut = 8201 end item Command = ecMatchBracket ShortCut = 24642 end item Command = ecColSelUp ShortCut = 40998 end item Command = ecColSelDown ShortCut = 41000 end item Command = ecColSelLeft ShortCut = 40997 end item Command = ecColSelRight ShortCut = 40999 end item Command = ecColSelPageDown ShortCut = 40994 end item Command = ecColSelPageBottom ShortCut = 57378 end item Command = ecColSelPageUp ShortCut = 40993 end item Command = ecColSelPageTop ShortCut = 57377 end item Command = ecColSelLineStart ShortCut = 40996 end item Command = ecColSelLineEnd ShortCut = 40995 end item Command = ecColSelEditorTop ShortCut = 57380 end item Command = ecColSelEditorBottom ShortCut = 57379 end> MouseActions = < item ShiftMask = [ssShift, ssAlt] ClickDir = cdDown Command = emcStartSelections MoveCaret = True end item Shift = [ssShift] ShiftMask = [ssShift, ssAlt] ClickDir = cdDown Command = emcStartSelections MoveCaret = True Option = 1 end item Shift = [ssAlt] ShiftMask = [ssShift, ssAlt] ClickDir = cdDown Command = emcStartColumnSelections MoveCaret = True end item Shift = [ssShift, ssAlt] ShiftMask = [ssShift, ssAlt] ClickDir = cdDown Command = emcStartColumnSelections MoveCaret = True Option = 1 end item Button = mbRight Command = emcContextMenu end item ClickCount = ccDouble ClickDir = cdDown Command = emcSelectWord MoveCaret = True end item ClickCount = ccTriple ClickDir = cdDown Command = emcSelectLine MoveCaret = True end item ClickCount = ccQuad ClickDir = cdDown Command = emcSelectPara MoveCaret = True end item Button = mbMiddle ClickDir = cdDown Command = emcPasteSelection MoveCaret = True end item Shift = [ssCtrl] ShiftMask = [ssShift, ssAlt, ssCtrl] Command = emcMouseLink end> MouseTextActions = <> MouseSelActions = < item ClickDir = cdDown Command = emcStartDragMove end> MouseOptions = [emAltSetsColumnMode] VisibleSpecialChars = [vscSpace, vscTabAtLast] SelectedColor.BackPriority = 50 SelectedColor.ForePriority = 50 SelectedColor.FramePriority = 50 SelectedColor.BoldPriority = 50 SelectedColor.ItalicPriority = 50 SelectedColor.UnderlinePriority = 50 SelectedColor.StrikeOutPriority = 50 BracketHighlightStyle = sbhsBoth BracketMatchColor.Background = clNone BracketMatchColor.Foreground = clNone BracketMatchColor.Style = [fsBold] FoldedCodeColor.Background = clNone FoldedCodeColor.Foreground = clGray FoldedCodeColor.FrameColor = clGray MouseLinkColor.Background = clNone MouseLinkColor.Foreground = clBlue LineHighlightColor.Background = clNone LineHighlightColor.Foreground = clNone OnChange = EditorChange OnReplaceText = EditorReplaceText OnStatusChange = EditorStatusChange inline SynLeftGutterPartList1: TSynGutterPartList object SynGutterMarks1: TSynGutterMarks Width = 24 MouseActions = <> end object SynGutterLineNumber1: TSynGutterLineNumber Width = 13 MouseActions = <> MarkupInfo.Background = clBtnFace MarkupInfo.Foreground = clBtnText DigitCount = 2 ShowOnlyLineNumbersMultiplesOf = 1 ZeroStart = False LeadingZeros = False end object SynGutterChanges1: TSynGutterChanges Width = 4 MouseActions = <> ModifiedColor = 59900 SavedColor = clGreen end object SynGutterSeparator1: TSynGutterSeparator Width = 2 MouseActions = <> MarkupInfo.Background = clWindow MarkupInfo.Foreground = clGrayText end object SynGutterCodeFolding1: TSynGutterCodeFolding MouseActions = < item Button = mbRight Command = emcCodeFoldContextMenu end item ShiftMask = [ssShift] Button = mbMiddle ClickCount = ccAny ClickDir = cdDown Command = emcCodeFoldCollaps end item Shift = [ssShift] ShiftMask = [ssShift] Button = mbMiddle ClickCount = ccAny ClickDir = cdDown Command = emcCodeFoldCollaps Option = 1 end item ClickCount = ccAny ClickDir = cdDown Command = emcNone end> MarkupInfo.Background = clNone MarkupInfo.Foreground = clGray MouseActionsExpanded = < item ClickCount = ccAny ClickDir = cdDown Command = emcCodeFoldCollaps end> MouseActionsCollapsed = < item Shift = [ssCtrl] ShiftMask = [ssCtrl] ClickCount = ccAny ClickDir = cdDown Command = emcCodeFoldExpand end item ShiftMask = [ssCtrl] ClickCount = ccAny ClickDir = cdDown Command = emcCodeFoldExpand Option = 1 end> end end end object tbToolBar: TToolBar Left = 0 Height = 26 Top = 0 Width = 640 AutoSize = True Images = dmComData.ilEditorImages ParentShowHint = False ShowHint = True TabOrder = 1 object tbNew: TToolButton Left = 1 Top = 2 Action = actFileNew end object tbOpen: TToolButton Left = 24 Top = 2 Action = actFileOpen end object tbSave: TToolButton Left = 47 Top = 2 Action = actFileSave end object tbSeparator1: TToolButton Left = 70 Height = 22 Top = 2 Style = tbsSeparator end object tbCut: TToolButton Left = 78 Top = 2 Action = actEditCut end object tbCopy: TToolButton Left = 101 Top = 2 Action = actEditCopy end object tbPaste: TToolButton Left = 124 Top = 2 Action = actEditPaste end object tbSeparator2: TToolButton Left = 147 Height = 22 Top = 2 Style = tbsSeparator end object tbUndo: TToolButton Left = 155 Top = 2 Action = actEditUndo end object tbRedo: TToolButton Left = 178 Top = 2 Action = actEditRedo end object tbSeparator3: TToolButton Left = 201 Height = 22 Top = 2 Style = tbsSeparator end object tbConfig: TToolButton Left = 209 Top = 2 Action = actConfHigh end object tbHelp: TToolButton Left = 232 Top = 2 Action = actAbout end end object MainMenu1: TMainMenu Images = dmComData.ilEditorImages Left = 48 Top = 32 object miFile: TMenuItem Caption = '&File' object New1: TMenuItem Action = actFileNew end object MenuItem1: TMenuItem Caption = '-' end object Open1: TMenuItem Action = actFileOpen end object miFileReload: TMenuItem Action = actFileReload end object Save1: TMenuItem Action = actFileSave end object SaveAs1: TMenuItem Action = actFileSaveAs end object miDiv: TMenuItem Caption = '-' end object miConfHigh: TMenuItem Action = actConfHigh end object N1: TMenuItem Caption = '-' end object Exit1: TMenuItem Action = actFileExit end end object miEdit: TMenuItem Caption = '&Edit' object miUndo: TMenuItem Action = actEditUndo end object miRedo: TMenuItem Action = actEditRedo end object N3: TMenuItem Caption = '-' end object miCut: TMenuItem Action = actEditCut end object miCopy: TMenuItem Action = actEditCopy end object miPaste: TMenuItem Action = actEditPaste end object miDelete: TMenuItem Action = actEditDelete end object miSelectAll: TMenuItem Action = actEditSelectAll end object N4: TMenuItem Caption = '-' end object miFind: TMenuItem Action = actEditFind end object miFindNext: TMenuItem Action = actEditFindNext end object miFindPrevious: TMenuItem Action = actEditFindPrevious end object miReplace: TMenuItem Action = actEditRplc end object miGotoLine: TMenuItem Action = actEditGotoLine end object N5: TMenuItem Caption = '-' end object miLineEndType: TMenuItem Caption = 'End Of Line' object miEditLineEndCrLf: TMenuItem Action = actEditLineEndCrLf AutoCheck = True end object miEditLineEndLf: TMenuItem Action = actEditLineEndLf AutoCheck = True end object miEditLineEndCr: TMenuItem Action = actEditLineEndCr AutoCheck = True end end end object miEncoding: TMenuItem Caption = 'En&coding' object miEncodingIn: TMenuItem Caption = 'Open as' end object miEncodingOut: TMenuItem Caption = 'Save as' end end object miHighlight: TMenuItem Caption = 'Syntax highlight' end object Help1: TMenuItem Caption = '&Help' object miAbout: TMenuItem Action = actAbout end end end object ActListEdit: TActionList Images = dmComData.ilEditorImages Left = 112 Top = 32 object actAbout: TAction Category = 'Help' Caption = 'About' HelpType = htKeyword Hint = 'About' ImageIndex = 13 OnExecute = actExecute end object actFileOpen: TAction Category = 'File' Caption = '&Open' HelpType = htKeyword Hint = 'Open' ImageIndex = 1 OnExecute = actExecute end object actFileClose: TAction Category = 'File' Caption = '&Close' HelpType = htKeyword Hint = 'Close' OnExecute = actExecute end object actFileSave: TAction Category = 'File' Caption = '&Save' HelpType = htKeyword Hint = 'Save' ImageIndex = 2 OnExecute = actExecute end object actFileSaveAs: TAction Category = 'File' Caption = 'Save &As...' HelpType = htKeyword Hint = 'Save As' ImageIndex = 3 OnExecute = actExecute end object actFileNew: TAction Category = 'File' Caption = '&New' HelpType = htKeyword Hint = 'New' ImageIndex = 0 OnExecute = actExecute end object actFileExit: TAction Category = 'File' Caption = 'E&xit' HelpType = htKeyword Hint = 'Exit' ImageIndex = 12 OnExecute = actExecute end object actEditFind: TAction Category = 'Edit' Caption = '&Find' HelpType = htKeyword Hint = 'Find' ImageIndex = 10 OnExecute = actExecute end object actEditRplc: TAction Category = 'Edit' Caption = '&Replace' HelpType = htKeyword Hint = 'Replace' ImageIndex = 11 OnExecute = actExecute end object actConfHigh: TAction Category = 'File' Caption = '&Configuration' HelpType = htKeyword Hint = 'Configuration' ImageIndex = 4 OnExecute = actExecute end object actEditCut: TAction Category = 'Edit' Caption = 'Cut' HelpType = htKeyword Hint = 'Cut' ImageIndex = 5 OnExecute = actExecute end object actEditCopy: TAction Category = 'Edit' Caption = 'Copy' HelpType = htKeyword Hint = 'Copy' ImageIndex = 6 OnExecute = actExecute end object actEditPaste: TAction Category = 'Edit' Caption = 'Paste' HelpType = htKeyword Hint = 'Paste' ImageIndex = 7 OnExecute = actExecute end object actEditUndo: TAction Category = 'Edit' Caption = 'Undo' HelpType = htKeyword Hint = 'Undo' ImageIndex = 8 OnExecute = actExecute end object actEditRedo: TAction Category = 'Edit' Caption = 'Redo' HelpType = htKeyword Hint = 'Redo' ImageIndex = 9 OnExecute = actExecute end object actEditSelectAll: TAction Category = 'Edit' Caption = 'Select&All' HelpType = htKeyword Hint = 'Select All' ImageIndex = 15 OnExecute = actExecute end object actEditDelete: TAction Category = 'Edit' Caption = 'Delete' Hint = 'Delete' ImageIndex = 14 OnExecute = actExecute end object actEditFindNext: TAction Category = 'Edit' Caption = 'Find next' Hint = 'Find next' OnExecute = actExecute end object actEditLineEndCr: TAction Category = 'Edit' AutoCheck = True Caption = 'Mac (CR)' GroupIndex = 1 Hint = 'Mac (CR)' OnExecute = actExecute end object actEditLineEndLf: TAction Category = 'Edit' AutoCheck = True Caption = 'Unix (LF)' GroupIndex = 1 Hint = 'Unix (LF)' OnExecute = actExecute end object actEditLineEndCrLf: TAction Category = 'Edit' AutoCheck = True Caption = 'Windows (CRLF)' GroupIndex = 1 Hint = 'Windows (CRLF)' OnExecute = actExecute end object actEditGotoLine: TAction Category = 'Edit' Caption = 'Goto Line...' ImageIndex = 16 OnExecute = actExecute end object actEditFindPrevious: TAction Category = 'Edit' Caption = 'Find previous' OnExecute = actExecute end object actFileReload: TAction Category = 'File' Caption = 'Reload' ImageIndex = 17 OnExecute = actExecute end end object pmContextMenu: TPopupMenu Images = dmComData.ilEditorImages Left = 208 Top = 32 object miUndoContext: TMenuItem Action = actEditUndo end object miSeparator1: TMenuItem Caption = '-' end object miCutContext: TMenuItem Action = actEditCut end object miCopyContext: TMenuItem Action = actEditCopy end object miPasteContext: TMenuItem Action = actEditPaste end object miDeleteContext: TMenuItem Action = actEditDelete end object miSeparator2: TMenuItem Caption = '-' end object miSelectAllContext: TMenuItem Action = actEditSelectAll end end object ilBookmarks: TImageList Height = 11 Width = 11 Left = 312 Top = 32 Bitmap = { 4C7A0A0000000B0000000B0000003D0300000000000078DAED586D4B536118F6 87682F0C03ED831264948A88E24CD1658926268D32136B29352B75E0CB3E5414 F4EAD25C38DB104DD1A14E7C295F5233D30F65A5150541D8878559B9F23889BB 733D79C60CCF4B9011B2EBD30EE7E2BE9FFBBE9EEB7E9E1D3FBF5F7868D4A886 2B92AD03A549CE5E432275162538ED85F1D6E693712A3F2F8C1A35EA51633237 529E4483A58974AF6437759E8923BB3E96EE16C470F5BA68B5100FBCD18A247A 6E3590DBF5998045D71C8D54E9A9511749B6BC48AE2E379CE545BCE1B204C69B B8A9A32E7D140D5D394ADCFC1CD5E7EEA03B3961549B1DC6D687BC03867816AF 9BE775E4EFA296BCEDECD97A38946AB521745B1BCAEAC0FA7ACFC6B277E0B5F2 BCC62321ECB9362B88CC0782E8566630AB177574E8A3D93BC46BCC0E21DBC160 F66CDEAFA2EA741555A5073AEDA7E3ADA8B7A5208AADAFF7BC966CDAADE4284B A3852FB3549DBA914CFB3690297513EB1FFA827AFBAF9DA085AF9F583CF01CC6 2C32ED0DA0CA147FAE322580F519FD435F58BD7C1D581FF2221E7837F6F8ABBD F540FFD017335F2FEAC0FA905788E78DB5D418DA3DB594D08F2537ABAF95EF8D 98C6CF2CC58CF7A2E532E3361FDB29AA3178533C0FDA010D39DB4435EE5ADE0B ADCB7B019A8869DC5610E1D118B0646E11D518EB435EC4637B216DB3A8C6A883 AD8FCF0B30DE3AD178AD7CDC5714E3F1F1C0C543C4F11E91D2B8F354144D3B6A F8BDB148F72FE5886A8CBCAE8FEFC9F9729CEC856A498DDD0B2E7A5C57CE3466 3C098D57834FE3BFABB1E07760D26E52E4E32E63063F5F677DB35AC1AC8626D3 F6ABB2B3FA81414DAF781EF682DCAC167883E732656735009E9259BD1A7CB35A 5AE3D520A631007FC277F09394C6BFDFB9E4341600BF4BCDEA3FF1B1B7C6723E C65C17B0DE7CCCFFA699B1765AE2BEB1FADE3D72886AFC81E7CDBE1EA7BE528D ACC688D7CFF3946ABC383FA7486300B3DF37ABD7C6C798D5DE3E06949CC74F1A 2E283A8F055E7B8946D2C71E5E71B2ECBD1A403CB93B17EAF0FC67433CDFBD5A F6CE05EED8F53C4577AE373D96157B4CEACE05BFFB7CFC7F6A2CF50D64A246BF 62564B7D03F13E8F9B8E8793FBFBBCEC79DCA48BA099C9219AEAB68A6AFC76A4 8DE545BCA91E1B993302FF89C63F015CBC5D28 } BitmapAdv = { 4C69030000004C7A0A0000001000000010000000A50700000000000078DAED5A F957D45514B79FFD17AC4C5B5D4A330DCB85549055425291484D7234080A9B10 0141404BE4B41C0B05C5619451901D84C101864586815129B1345617D4D85416 4548B34FEF5E9CE9B870E63B734ECBA979E77CCFC01C3E73EFBBF77EDEE7DEC7 8C19F3E7D2C77A3C5113E361571DBD445119E5DEA6DDE2064DB82BD49B5DDA0A 36392B723F73B2CBFAD4F189318F59B5B11E636B6397A4D4C42C812EDA1D5551 6ED046BAA224CC05EA502714842C46CEA78EC808764849FF64D1D847B11EA575 B14BA08F71876EAB1B74DB9642B763252AB77B4313E18E02F92264072FC0918F 17E070E05BA5AA80F9638D3E935DC2D60AAC3EDA0DAD45BB71E7561F8CEBD75B BD68C8FA06591FCFC791C07938143017A9FE73530E6C7893F74B3EEBEF63CFAA 22F1FBBD7BE83C5D869FD2BF40C3E1EDB872AA84DFAB4ED888B40F6743B56136 0EAC9F0DA5CC8E6345FB259FABA35CD059AFC1506F27CAC31DA1F96C3E8A82E7 E068F03C0C5EEFC0F99A021C92CDC4C10F5E83523C0ABF991C678A5555A40BAA 229CD0F943296E76B4A1443E1F6A812D08B2438EFF2CF45D69C685DA42A4FA4D 83F2FD57A058330DC96BA6738E28CEE511CED08639A2E3FB520CFCD2C6D8A381 76C8F59F890CD974F45E6E62FBCAD593A1583519C9BE53B0EFBDA99CDF927017 946C5E0CCDA645B85A5F8281ABAD6C97B099029BB6762A7ADB9BD0AACB87E2DD 1790ECF33CF6FABC80249F97B83628BFEA100714CA17E0F2490DFA059E7C3662 55AB5EC28DF646B456E762DF8A89485A310189E23571C5735C57541B94DFBC60 7B5C147BA45865F9BF8E34BF97A15A3D09A9E2B9D973054DE519485A361E7BDE 795A3CE3B17BD904AE49AA2BAA0DCA2FE5887275A1AE08BABD9B51BD2744D8CD 13EFFD06F5F6D5D8E3F514762F7D12094B9F4282D7D35CCF54935457541B94DF 9387E3303470C3543F43FDD7A14BDE721F3B0E099EE3F09DE7B89404CF27990B E99F2C1C4B35497545B541F9556DB043DA47A2D6C4E7ED17F1269FD92E61DF1E 572A9E073840F5CC35497545B541F9F59DCC71A658D17EC967B2FB30D6B8A89E A926A9AEA83628BF94238A33C52AC16BBC9DD1E7C7AD7F13FF990F319ECC7F6D CC721C1578A9FC271ED6ED7C17833D974D392C8F5F2B89FF3A8135C4FB9AB0DD 3F1BF8551BB71A99016F98E53F63BBDB19D3AC4E822131987F2EFDDC17E91B66 99E57FC7F79A116C511273B8767710FFAE89F1C6E175D3CDF2BFEE2B3F18BE0B 30F1BFE6DB8F185F1CF50E52D74C31CBFF62B93D9F5946FE1FFFE643C61746BC 0DA5EF8B66F94F675D5ED01B26FE577C29637CC1667728563E6B96FFB9417390 1560878CF53398FFDAF80F189F1BE28AE4E5CF98E53FE588E2CCB112FB2D89F3 637CB6DC19498493C0FF43B2D790BA761AC74AB3632DE333E54E16F19F73B46A 24D60765B3C49E27DAF8FF3FD0FF8BDA54DC68A9B75AFF2BC21DA00D5DF080FE AB439D7167E816CEAA1566F95FB66921DB35F2BFFE60B4D87F3F6EF776236F93 8B64FE97452FC52FA72B387E7D575A901FE22C89FF851BED7126EB2BDCB93D80 7B777FC54F0589485FF72A0EF83E2F89FF94273E779BEB5114E1C1FACF58EF89 92F87FD1508C61A1DDB58A2D26FDAF4A90A3E2DB8DC80FF732CBFF0B023FDA6A AACA36CBFF23C10EC8D8E8C8756AD47FE2BFD26F8688F9241BFF6DFCFFDBF8DF 527A105DE7EAACE23FD96DD628D179B656E0FB04BE0B39F2C516EB3FF5FFD981 73C57970130DF97BCCF2FF67F57E74899ECBD6FFDBFA7FAAE9B20857ABFA7FE6 92B0DFD374C2E2FEFFF81627E1BF2BAE351A4C3520B5FF27ECF148C2D631AEF3 C76A8BFAFF11BB23D87379BB2CEEFFDB75D926AC35FD3FCDFF83D7AEB25DC29E C9D9C57843CA56E485BA4B9AFF475B52E6FF63515E1C2BDA2FF94C76397F5F07 20DDFF4D5BFFFF1FE7BF216E05CFD0B53B7D4CFA4FFCD76C5DC633A439FE7737 948F5A7F97446D9AE37F778316C37DDD38971967D2FF1F0E6DC3A9D458947FB9 DE2CFFBB4E6B71ABE33C6BB851FFF3851ED24C2B85FFA3DDFFD13C2C85FF74FF 777778103D8D27F8EE82F4BFAD2A0B85616E92F8DF5898F800F6EFD6FF87E77F 4BF55FB3CD17752951D0EF8FB04AFFE96F1F5E96E87F5AA0FD23FDBF4DFFADD3 7FE18389FFA40B52F55F277C683B968C2151B3C645F92F169A2245FFBBEE9F21 DD42BB8DFC3FA18C4476D03CB3FC6F48960B63BFE37CA9129A107B8BF97F599F 2366975E94853A58CDFFE181EB68D7E75BC57FD27F5A7706FBADE23FE9FF5D31 ABD0CC620DFF6DF7FF36FDFF27F5FFCC7E391AB3763EA2FFB76F74F2DD9294FE BF32CCE111FDA73BB40B756AABE6FF7AD536AEE9E68A0C2BEEFF62C471740FDD 4DA790B67E9645F33F61F91C14D874D90C8BEEFFD9E7FB762DB9FF23FD3F16BD 9CF76BB46BC9FD1FF5FFC7627DD8EFB278D988CF6497B012FBFFA2686FC697C4 AFE3FDB2CF645722FF5365AF739D2AC50C41B1A2FDDAF86FFBFFBF94FBBF4B55 69DCBF57467B5A75FFA78F5F85E1FE6BACDF46FDB7E4FEAF6A87AFD0BB1EABF5 BFA54C65D37F9BFEDBF8FF17F05FCAF77F46E33F2D29DFFF21FDAFFCDC1B176B 724DFC6FADCCC4EDBE1E49DFFF79DCFC9F267C1E1233C9D962A5E5F3FF9AC938 9DBD8B7B89C2C8E566F94F339A7E5F9869FEBF7472649E6911678014FD2F88F0 E2B3C2B86EF65C8541B503FB563E2799FFE2F34CF33FC5FADFACFF7F00EAD5FF C14C7A0A00000016000000160000007B0800000000000078DAED9CFB4F54D716 C7FD43466DAD56AB562B16C582A02822C3AB3E4B05452854B9803C2E22A0C863 62D2D88634F716451EE525CA1B41CA63780C4FE16A2F15699AA6B7B7ADD2D642 1FDAA4B6FEF6ED5E7BE69C9E811960CE1C1B9BEE95EC407232DFECB3F75AEB73 D63A7B66D122DB366408D20DE40625F56705D6F66605A23B3310C6D3FE68CFD0 A3355D5FDB724A9FD47472B76E910376C3109C379C1B8CC1DC20F4E704C29415 809E4C7FA6AB4747BA1F5AD3FCD092BA1B4D277D519FBC2B6F3EBD1143B06EC4 10347983E90DB331C43407B203D077D69FE9EA99AE1F3AD27CD17ACA17CD2777 A129C587E9EE444DE2CEC9AB09DE3AFB9AC193A386208C180271233790E90660 204BCF74F5E839B31BC60C5FB49FDA85D6933E684ED989C6E41DA84BF446F509 6F5C89DF3E5915B74D6743976B725DA639CC346FE61DC1F71F0F62A67D3BDE07 63CE4134266E435D8217AAE3BD7025CE1397633D2767AE27DD3BCD53D2BC9517 8EC73F7F0F7BF6EB8369B49DDD8BDA380F5C8D7547558C072A63DC517EDC9DAF F7506E908EF66838C77CEFA4399CAD97E7393DD18FA1B742D095EA8DF6946DE8 CED9876F6EF7F26B93633DA88ED9822BC7DD5079CC0D156C94BDE986D2E8CDDC 97062D7B44EB39C43407CFFAC9F31AE69ADBD199E285B6A4AD684970474766B0 7CFDEA31575445BBA222CA1565512FA3F40D57363671FFECCF36EF3BEDD140A6 1FFA337DE5CF75334D2369267BE07AC22BB816E78686D84DF2F5AA681754BEB1 01E5911B501AB101EF47B8A0246223F779F24FF225DA7713DB77D3691FF973A4 D99EE48156A6D912B7194DFF7045DDB18DF2F5CAC8F5288F5887D2F0175112BE 0EC57CACE771443E4FFE49BED493B10BDD693BE5CFD13C959AF5C75C501DFD92 7CBD3C7C0D4A8FAC41C991D5280E5B8DA2B0B52864836293E2887C9EFCD398E6 834EB647925D4FB4D6AC895A8FAB912FCAD74BC356A12474258A0FAD4411FB5B 7868152E1D5ACDE39D6293E2887CBE2D7507DA52B6CB9FA3F5B4D28C588BCBE1 ABE5EB25AFAF4051C872145AC6A59015280859C9625D5F4BF1FE018B4D8AA3EB 29DE6849F6923F477B44EB5913F5129F27695684AD94AF17872C43E1C16751C0 C732369EC3C5D796F3BC443984E29D62B339793B9A123DE5CFB1DCC5D67303AE 44AEC3E5A36B507178158B85ADF2F5C203CFE0D281A5B8B89FC633B87080C6B2 A4A6543F1DE525CA2114EF0D2C361B4E6CE53E4F76EFC32E5C63D72B8FAE45F9 E117501BEF892F46DBF8B5FF8F7C8082FD4B7071DF125CD8BB988D25C8DFB714 17F62FE57982721DE525CA2114EF149B2DE9C178F4D394DD38FEE587FB2CC636 33CDC55C337FAF0EF97B16D3B0CA9B94EB282F510EA178A7D86C4AF5C757B7BA 6669D23C2FB3EBD23CF3F7E8F878EF55DDE4CC7C46F9D39CEB3C590E7137C73B 8B4D1E47E4F3E49FCC9768CF698F683DFF98A759930D9B3998F227E53ACA4B3C 8750BCB3D8E471443E1F2AE92EE37B944FEBC9EE7D2E4DA551AEE37989E59092 48171E9B45616BCC3E4FFEC97C89F69DF668E67ACE6765D16E3ACA4B944328DE 2936298E0A429EE7FE49BE7461FFB30E7153F0F8CFE1313189F871E37C181E3F B46628E511353C1ECEF6E79C1B7D3BD426972937511E7194C75CF3BCB5E64715 59F2FF8D27DC5117BBC5611EF3792AEEFD36D3241E4B561FEB869A98CD0EF358 39CF71D2B4F058B2BAE32FA3FACD8DAA794C9A4A1E4BC6733D6388A33CA6E79B 4ECB738392C792113F78AE7790C7F4CC44EB3993C7921193881F8EF2B835D993 3F33CDE4B164C4B9B2D0E71DE67173A2079AE2B7CCE2B16465875630CDE50EF3 B831DE9DFB12DF77058F257B3FE43914332D47794C3E5F13B389FB12DF770B8F E5E7068BA6A33CA63832FBBC8BD99768DFD91E299F1BCC9A8EF398E288FB3CF9 27F952E81FCF39FCDE058F058F457D2CEA630DEBE33EC6CEDEF41D36EBE3B6D3 01AAEBE31EA6D965D154F2B823C31F93FF35D71C773F346AC2E39B4569F23C1F FDF41D1A927638C563E399407C3DD66DA5D998E4ED148F271ADEB5F2AF4F3B2B CCB5AC4A1E1BB3F7E0C72F2664BD1F3E1F47D7B930B93E56CB63A5E658CD3B56 F53169AAE5B1642DA7FCAC786CBEF7E5AA79BC507394C70B35C163C163C163C1 63C163B3E64CD382C7CA3A5EA95B97B04DB3FAB899C5C2DD9B1D5CFBCBFFB46B 561F138FEB4F78897EB5E8570B1E0B1E3FD17EB5C99297C7AB0C9AF5AB8949C4 8F3B55B99AF5ABFBCF9839375195332B96D5F6AB393B337CF0B142F3FE6D93D3 FD6A9AA7B566AF26FDEA89199A5AF5AB6D696AD1AFB6F7FED8D97EF5424DEDFB E3F94CF4AB45BF5AF058F0582B1E2FD41CE5F142CD511E4BD627D788E6DA8BEA 24AA69D4F258B25E4BDDA9AC8FA94E52CBE3F9CE7339FBFED8DE792E67796CCB EEB17AFBDA3F7D9CE2B13DFBBBD4C7F678EC6C7D6C8FC7CED6C78F1E4CCDB96F 6AEBE3B96A6E511F0B1E8BFAD80FFF6BBB8487773F99151F7DEFC6AAAA8F6FBE 7378CE9EB529EFB8AAFA58D27CFC701A772A7334E1F1E76D05B2E6C0B9839AF1 F8E77BE6F5BC5399FD97E2F17D4BEFFF69E7B164DF8CF5F05EBD563C96CF999F 0E10FD6AD1AF163C163C16F5F13CFD6A5BF5B1DCAF55D9AFB6571F3F89F7C7A3 C5E99ABF3F569EBD7A12E7B9EEDE326A72BE5AA979EF56A726E7AB67693A719E 4BAA8F957B246B3A719E4BAA8F95EBA9C5792EA93E96BFE7A6D1792EA95F6DF5 3D37DA23B69EFCDE9DEC57CBDF73B3F4ABF91EB1B98A7EB5E0B138CF25CE733D A9EF1F0FB29A5BCBF35C53ECFEC9BE1B37C194B347B3F35C03E75EC36F0FA7E7 AC63D59CE732190EE0B707D39AD7C7DF5ADEF18BFA58D4C782C782C782C782C7 4F2B8FD5FC1EC87C3C56FB7B20B447BD397B193F6DF4C159DDA9F6F740ECBD3F 76F6F740E67A7FDCFFAF04AE39F5D99866EF8FEBD9B3C8A31FEF73DDD1728326 EF8FFBFE9D286BFEC2FEAAA98FBBCE47DB6731D3AC6231A6A63E369E8F9AA537 F5D94718A93827EAE3A780C7BF030321037B4C7A0A0000002100000021000000 5D0E00000000000078DAED5DF957544716CE1F32EE1A77C515911D641575124D DC4010454076651157D4999C999C392789A3020D3434FB266B038240B3883A2A B8641283313A333FCC44A333F90FEEDC5BAF5FFB5EF39A74CB7BAFCD4CDD73EE E95FDEE9AFAA5ED5BD5F7D7DABFA830F9CB7E10BDB03860BB61758CE6DB30C9E DB060367B7C18DD351D07B6A2BF4A077E7475ACCF99105ED7991011FA86C6317 7614DCBCB81D46CF6F8791826D30846E3917856D8882FED35B85369C8CC43644 00B6013AF222A02D37025A73C20B668A7DEBE28E00741843BF7901DB803E725E DA86ADAC0D7DA722A1F76484D0861311D0911B0EED3961D0921D06CDC743A1E9 58E83B8DCBED8B3B2CB7B1EFB72E083E867E13F1470BA2702CA2C082F8036723 B10D91AC0DD7F3C3A1FB441898F3C2B00D61D096130AADD9A1D07C2C049AB2B6 40436688C555FC3BBFDB0E776C6DD80663882FB661F8DC561842FCC133D806EC 7FDFC970B88EF8DD88DF951B0A1D3921D096BD055A8E6DC13604436366303464 04435D7A90C5F9FEEF60F8E4B72F6E83DB621B0AB6C2E8B9486C43240C9D8980 C1D3E1D07F2A1CDB108A6D0881EEDC1030237E07E2B721764B56103467064163 4620D4A707425D5A20D4A405589CEDBF14FFD685286C4314B62112FE6EA9819F 5F3C06257BF3C34398ECAB848EE341D09A1508D73203A02923001AD3FDA13ECD 1FEA52FDA126C51FAA52FC2C8EE6DFED8B0AF8887DEBFC5686EF08DBDE5E3F7B 00AD887F2DC31F9AD2FDA021D50FF17DA1F6A82F54A357A19B927D0214DA609B 7FF6F863F80E9CC517EDA7EF1F40739A0F34A6FA407D8A37D4A2D71CF586EAE4 CD5099E40D2674FBF53F666BC3DBF117F1FF315423FBFE1783553070620BF4E7 05416F4E20F464074257B63F4CF696CB9EFBA6BB0C1A8E6E86BA642FA841AF4E F282AAC44D5099E80526F48A235EB6F841F1E7A675FDD1DC135C78FF3407A563 F062A00A06F383E1C68920E8CB0D845EC4EE3EE607E62C5FE8C8F486EF7A8CB6 675F3D1D87FA244FA84BF4841AF4AA239E507964239812364245822794A38BF1 97E2DFA875FDDFB4CE7F013F0246CE86CBFA3678221806B0FF3710FF3AE2F71C F783AE2C1FE8CCF481F6F4CDD092EA257BBE2E7103D41C590FD509EBA1F2F07A 30A157A0971F428FDF08C6C31B58FCA7F84B4E6B7FF49CB0FE4671FD8F9C8D80 E13361B2EF14F1FB7210FF982F7433FCCDD091EE05AD299E702DD553F67CED91 75507D782D541D5A0BA6F8B550815E8E6E442F8B5F87BE9EE59F216B0E18B1C6 1F5AFFC3B8FE8770FD0F9D0A957D27C3C7FE5FB7E29B33087F13C36F39BA019A 93D7CB9EAF39BC06F13D10DF032AE2564339BA31CE03CAD04BC963D7B0FC47B1 9FF95921FE51FCB120BE05F1074F86C8BE93FACFF0F1DD137E27E2B7A76C8456 C4BF96B40E1A8FAC953D5F1DBF0A2A0FAE0253DC2AC45F09C6D8955016BB8A79 E981D5D886D52CFF52FE1BB0C67F8ABF14FF06117F00F1FB71FE4BAD47D27F7B FCA6C435507FD843F67C65DC0A30C5AE80F203CBC1885E16B31C4AD14B625630 37C4AC64F99F729FE0912CF632C7F87B233F04FAF28265DFC9F03325F838F622 7E43C26AA83FB44AF6BCE9C052C45F06C6E8A550865E8A5EB21F7DDF3230EC5F 0E86E8E52CF79353EE637E5288FFBD88DF8BF8D7738364DF29CCBFA9FD6F388C F8F12BA1F6E00AD9F3E5D14BC0B87F3194A197EEFB107D3118AC5EBC6F09FA32 C67F887F50FEA7FC4BF98FF24F4FDE16E8C90D866E8C3F5213E7BF227EDC72A8 8E5D267BDE88B8657B1741E9DE8550826ED843BE088AF77C08457BC99730FED5 932FF08F6E6BFEA5FCD795138CB12F08CCC70364DF29CE7F11BF51825F83F855 314B64CF1376E99E0560D88D8E9FC5BBC9174211F91EF2458CFF994F4432FE63 B6E67FCABF9DD9C1D089F81D59FEB2EFA4F54FEB8FE63FCD3F7AFF34FED5567C D3FE0FE56DD8331F4A76CF07C327F3A088FC53D1174021FAD5DD0B19FF24FE47 FC8BF84F8735FF53FE6DCF0A80B64C3FD97736256F80C6C4750CBFEED06AA88D 477C1C03861FBD182AF62D923D5F8278C59FCE85E24FE642D1AEB950889F85EC 731EFA7CB8BA6B01CB9FC43F89FF11FF6AB3F20FCAFF947F5BD27D31074EBCCD 43E612A8C731A8C336D41C5C89FD47FCD8A5608A417C1C8307D72ED99EFDE737 B7B1FF73A078D71CC49F8DD8E83B67C3D59D73109B7CAE2D7712FF25FE49FC8F F817F11FE21FCD98FF29FF52FE93DAD79DC55083635085EFA012D79D09C7A022 5A8E4F36DEF825E28BB8E81FCF822BE8573F9E0D577692CF95F16EE2BFC43F89 FF11FF22FE43FC83F23FE5DF9793E32EF1071A0311BF90E1CEB2B5E1CA4782DB 7318E2DFC47F897F12FF23FED590E6CBF807E57FCABF2F27EFBB803F4782FF1B C446FF48F45970F9E3598A7CBF21738B85F82FF14F81FFF90AFC873808B681F2 EFA38E62F8F1BB7B0EB0EFC078D357D6F9271DFFB7F8977FCB7C5A5E4BFC9BF8 6F2DF24FE27F8C7F11FF21FE41F99FF22FCB7F2B85F84FF117E35009C6215AFF 6CFDD1BCDF355B32FECEE38B46FC9BF82FF14FE27F8C7F11FF21FE41F99FF22F E53FCA3FAC0D8B59FCA3F8436B9FAD3F9A73B6F7EF1ABE68C4BF89FF12FF64FC 8FF817F11FE21F94FF29F752FEC3FCC3E23FC55F8A7DD4061C075A7F5768FE5B E79FABF8A211FF26FECBF827F13FE45F46E44365B636AC10F21FE51F8AFFAC0D 0B58FCA1F5CFD6DF34F3CF1523FE4BFC93F81F722F81FF20FF60F91FF32FE53F 967FF07D14B23650FC9B3765FDAB61C43F89FF11FF22FE43FC83F23FE5DFA2BD 8B59FEA1F82FC65F2D8C6B205C03E11A88B206427BC061EB1EE83FCF1F29E62E 2D3510610F2CEC011DE1931107D44203A177407B70DA034F874F461C9438A09A 1AC84DDA879F09879133CAFDFF4B61969CFFA7FBC0B5346F684AD9AC9A06328A E33F723A0C7E56C0BF5798C13410A9B5A46D86E6542F683CBA49350D84FAAF84 7F17F1450D44B60749D9044D473D117FA36A1A88D2F8DF2BCA90692053F62049 1B700FB05E130D441C7F7B0D446A6C0F447B9084359A6820D47F250D446AF509 1EC21E08F7206A6920A401F6891A98030D44A6832136EDC1D81E48250D843448 518373A481C87430DA83E21E90EDC154D2404803A5F5D765D3E0A66A20320D2A 4EDC832E514D03210D9634D0CE0C6F871A88D4D81E9CF6C0B807554B03E9CCF2 631A2C69A08E34109906152DECC18DFB16AAA681B467FA405BBA37D3601D6920 52230DC288D86588A9960642F19FE22F8B7F0E3410990645F8885BBA7B9E6A1A 08CB3F3806147F85F8375503911AC347EC12C4534B03A1FCC7F24FF246167F59 FCB3D340641AD46E2BFEAE39AA6A2042FEDB00B50914FFD708F18FE20FADFFE8 25533428A1FFEA6B202CFFB1FCE321C45F16FF96B1F52F357AF75A6A2042FEF3 10E23FC55F8A7F0A6DE01A08D740B806C23510AE81700D84D781F03A105E07F2 7ED481900661C13DB8145FEF3A10869F2FC19FA60EE4DB2E830D9F7E07544B03 A1F947EF5FECBFA33A906FCD06D9183CEE28D24D0319FD2269CADA7CF9DD3DDD 3490275D0605FCBBBA6820635F26C14F4FC795F175D04094B0C9FAFF10F7B60E 42230D64EC528A2236BD7B691D88561A88B406428A3DF879FC943A102D349027 92F82BDA5F71DD39AA03D1420391DAABC97118FC5382C33A101BBECA1A884C83 75A08108F3CF3AFE1A68203331B5349019B541250D6426C63510AE81700D846B 205C03E11A08D740B806C23510AE81700D647A0D643AD34B0399CEF4AA0399CE 7E7C7257F73A10AAC3F8BAEDAAAC1D0F5BFEAC6B1D88A8813C6ABD6C6BC3BFBE BDA36B1D083F0BC3CFC2F0B330FC2C0CD740B806C23510AE81700DE4D7751686 F620B407B85792ED96B33016EB1EE8BE1DBE5E676186AC7BC071C371B79C8561 7BE0532130E1005FEBB330C3D63DF844C9B1697994566761087F88F00D53F1EF 5C49D3FC2C8CA84138C2D7E32C8CA3F1277CBDCEC228CDBF3B9753753D0BE3A8 FF7A9E859982EF86B330CEDC07A2F55998999816F781B86A5ADC07E2721BF859 187E16869F85E16761B806C23510AE81700D846B206ED54066626A6920336A83 4A1AC84C4C2D0D446AA206A2540742BF83D2EF905A68205213EB101CD581B0DF 4135D0405CAD03D1420371F54E54ADEF0371E64E54ADEF0371E64E543D341047 F66AF2BEED2C80961A8833A6C5599877315E07F2BF5B07E28C06A2751D88331A 88D67520CE68205AD781BC7A3AE1F2DA54BB0EE4DDF0D5D5405E3A390EBC0E84 6B205C03E11A08D740B806F23ED6813C28CB65E7301C9E0179F650B33A9047C6 BC5FBC8FD4F6FBBF0675208F8CB96E3B0B4375208F15F09FF79BE05E51962E1A 08D581D8DF477ADF90A5AB0662FF0E268AB374D740FE2699FF34FEEED640EEE3 FBE71A08C0F7BDE5F0E6D904D740DCA481D8DB93EE52DD35107B7C776820FC7F 61F859187E16869F85E11A08D740B806C23510AE81F03A105E07A2CD5998E9EA 40A4A6D559985FAA03919D83D0E02CCCAFE13E9091AF92DD7A1FC888C29DA07A DE07A2742769FFE787DC7A276AFF1FE375BB1375F48B4405FC83BADD07A2DCFF 83BAFD2F8C22BE0E77A28A7520230EF0B5BE1355AC03B15FFF6FDFBFB677A24A EB401CBE7F8DEF4495D681D8AF3FBDEE4495D681C8FE9348C73B51A56761A6FC 37B7F52C0CCD7F61FECDD7FC2C8CEC7F91246761D8FAC331A0F9A7F55918D97F 734BCEC2D018B0F587738D6B205C03E11A08D740B806C235107E272ABF1395DF 89FAFEDC89EAEA59182D3410693DD40F374C6EB913F5797FA5AC6FCF70EEB9E3 4ED47F63FC71AD0E439B3B515D312D34903718FBDC5907F2B4AFC2ED7520AF25 63C0EB40781D08AF03E175205C03E11A08D740B806C23510AE81700D846B205C 03F9FFD640D4AC0379570D8469006ED44064BFC3AAA881B8AA41B0DF6135A803 99BC5E06AFBF1F77A8FF7CDD2ED720F4BE0F843408D200B4B813D595FB40FA3E 3BA0C99DA8AEDC0742FA8FED5C5FF325DDEF03E9FD7D8C6C0CBACEEFD5F53E90 DECF62A6EC7FF5BA13B5F7B3587828D1C1443317EC51BD0EC4150DC45CB05793 3A1067EFE230E31CD0AA0E64BA719868B90C5D17F7F33A10AE81700D44450DE4 BFC65861F0 } end end �������������������doublecmd-1.1.22/src/feditor.lrj��������������������������������������������������������������������0000644�0001750�0000144�00000014420�14743153644�015543� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":79367010,"name":"tfrmeditor.caption","sourcebytes":[69,100,105,116,111,114],"value":"Editor"}, {"hash":2805797,"name":"tfrmeditor.mifile.caption","sourcebytes":[38,70,105,108,101],"value":"&File"}, {"hash":2800388,"name":"tfrmeditor.miedit.caption","sourcebytes":[38,69,100,105,116],"value":"&Edit"}, {"hash":97085973,"name":"tfrmeditor.milineendtype.caption","sourcebytes":[69,110,100,32,79,102,32,76,105,110,101],"value":"End Of Line"}, {"hash":212198471,"name":"tfrmeditor.miencoding.caption","sourcebytes":[69,110,38,99,111,100,105,110,103],"value":"En&coding"}, {"hash":107742931,"name":"tfrmeditor.miencodingin.caption","sourcebytes":[79,112,101,110,32,97,115],"value":"Open as"}, {"hash":160200403,"name":"tfrmeditor.miencodingout.caption","sourcebytes":[83,97,118,101,32,97,115],"value":"Save as"}, {"hash":125641556,"name":"tfrmeditor.mihighlight.caption","sourcebytes":[83,121,110,116,97,120,32,104,105,103,104,108,105,103,104,116],"value":"Syntax highlight"}, {"hash":2812976,"name":"tfrmeditor.help1.caption","sourcebytes":[38,72,101,108,112],"value":"&Help"}, {"hash":4691652,"name":"tfrmeditor.actabout.caption","sourcebytes":[65,98,111,117,116],"value":"About"}, {"hash":4691652,"name":"tfrmeditor.actabout.hint","sourcebytes":[65,98,111,117,116],"value":"About"}, {"hash":2844350,"name":"tfrmeditor.actfileopen.caption","sourcebytes":[38,79,112,101,110],"value":"&Open"}, {"hash":353982,"name":"tfrmeditor.actfileopen.hint","sourcebytes":[79,112,101,110],"value":"Open"}, {"hash":44709525,"name":"tfrmeditor.actfileclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"}, {"hash":4863637,"name":"tfrmeditor.actfileclose.hint","sourcebytes":[67,108,111,115,101],"value":"Close"}, {"hash":2857157,"name":"tfrmeditor.actfilesave.caption","sourcebytes":[38,83,97,118,101],"value":"&Save"}, {"hash":366789,"name":"tfrmeditor.actfilesave.hint","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":49409406,"name":"tfrmeditor.actfilesaveas.caption","sourcebytes":[83,97,118,101,32,38,65,115,46,46,46],"value":"Save &As..."}, {"hash":160199891,"name":"tfrmeditor.actfilesaveas.hint","sourcebytes":[83,97,118,101,32,65,115],"value":"Save As"}, {"hash":177351,"name":"tfrmeditor.actfilenew.caption","sourcebytes":[38,78,101,119],"value":"&New"}, {"hash":21703,"name":"tfrmeditor.actfilenew.hint","sourcebytes":[78,101,119],"value":"New"}, {"hash":4710148,"name":"tfrmeditor.actfileexit.caption","sourcebytes":[69,38,120,105,116],"value":"E&xit"}, {"hash":315140,"name":"tfrmeditor.actfileexit.hint","sourcebytes":[69,120,105,116],"value":"Exit"}, {"hash":2805828,"name":"tfrmeditor.acteditfind.caption","sourcebytes":[38,70,105,110,100],"value":"&Find"}, {"hash":315460,"name":"tfrmeditor.acteditfind.hint","sourcebytes":[70,105,110,100],"value":"Find"}, {"hash":147268901,"name":"tfrmeditor.acteditrplc.caption","sourcebytes":[38,82,101,112,108,97,99,101],"value":"&Replace"}, {"hash":147269573,"name":"tfrmeditor.acteditrplc.hint","sourcebytes":[82,101,112,108,97,99,101],"value":"Replace"}, {"hash":116155166,"name":"tfrmeditor.actconfhigh.caption","sourcebytes":[38,67,111,110,102,105,103,117,114,97,116,105,111,110],"value":"&Configuration"}, {"hash":116154878,"name":"tfrmeditor.actconfhigh.hint","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110],"value":"Configuration"}, {"hash":19140,"name":"tfrmeditor.acteditcut.caption","sourcebytes":[67,117,116],"value":"Cut"}, {"hash":19140,"name":"tfrmeditor.acteditcut.hint","sourcebytes":[67,117,116],"value":"Cut"}, {"hash":304761,"name":"tfrmeditor.acteditcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":304761,"name":"tfrmeditor.acteditcopy.hint","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":5671589,"name":"tfrmeditor.acteditpaste.caption","sourcebytes":[80,97,115,116,101],"value":"Paste"}, {"hash":5671589,"name":"tfrmeditor.acteditpaste.hint","sourcebytes":[80,97,115,116,101],"value":"Paste"}, {"hash":378031,"name":"tfrmeditor.acteditundo.caption","sourcebytes":[85,110,100,111],"value":"Undo"}, {"hash":378031,"name":"tfrmeditor.acteditundo.hint","sourcebytes":[85,110,100,111],"value":"Undo"}, {"hash":363439,"name":"tfrmeditor.acteditredo.caption","sourcebytes":[82,101,100,111],"value":"Redo"}, {"hash":363439,"name":"tfrmeditor.acteditredo.hint","sourcebytes":[82,101,100,111],"value":"Redo"}, {"hash":195247116,"name":"tfrmeditor.acteditselectall.caption","sourcebytes":[83,101,108,101,99,116,38,65,108,108],"value":"Select&All"}, {"hash":195288076,"name":"tfrmeditor.acteditselectall.hint","sourcebytes":[83,101,108,101,99,116,32,65,108,108],"value":"Select All"}, {"hash":78392485,"name":"tfrmeditor.acteditdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":78392485,"name":"tfrmeditor.acteditdelete.hint","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":73859572,"name":"tfrmeditor.acteditfindnext.caption","sourcebytes":[70,105,110,100,32,110,101,120,116],"value":"Find next"}, {"hash":73859572,"name":"tfrmeditor.acteditfindnext.hint","sourcebytes":[70,105,110,100,32,110,101,120,116],"value":"Find next"}, {"hash":122867065,"name":"tfrmeditor.acteditlineendcr.caption","sourcebytes":[77,97,99,32,40,67,82,41],"value":"Mac (CR)"}, {"hash":122867065,"name":"tfrmeditor.acteditlineendcr.hint","sourcebytes":[77,97,99,32,40,67,82,41],"value":"Mac (CR)"}, {"hash":10661081,"name":"tfrmeditor.acteditlineendlf.caption","sourcebytes":[85,110,105,120,32,40,76,70,41],"value":"Unix (LF)"}, {"hash":10661081,"name":"tfrmeditor.acteditlineendlf.hint","sourcebytes":[85,110,105,120,32,40,76,70,41],"value":"Unix (LF)"}, {"hash":42146617,"name":"tfrmeditor.acteditlineendcrlf.caption","sourcebytes":[87,105,110,100,111,119,115,32,40,67,82,76,70,41],"value":"Windows (CRLF)"}, {"hash":42146617,"name":"tfrmeditor.acteditlineendcrlf.hint","sourcebytes":[87,105,110,100,111,119,115,32,40,67,82,76,70,41],"value":"Windows (CRLF)"}, {"hash":102945374,"name":"tfrmeditor.acteditgotoline.caption","sourcebytes":[71,111,116,111,32,76,105,110,101,46,46,46],"value":"Goto Line..."}, {"hash":97034739,"name":"tfrmeditor.acteditfindprevious.caption","sourcebytes":[70,105,110,100,32,112,114,101,118,105,111,117,115],"value":"Find previous"}, {"hash":93074804,"name":"tfrmeditor.actfilereload.caption","sourcebytes":[82,101,108,111,97,100],"value":"Reload"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/feditor.pas��������������������������������������������������������������������0000644�0001750�0000144�00000071015�14743153644�015542� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Build-in Editor using SynEdit and his Highlighters Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Legacy comment from its origin: Build-in Editor for Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz This form used SynEdit and his Highlighters contributors: Copyright (C) 2006-2015 Alexander Koblov (Alexx2000@mail.ru) } unit fEditor; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, ActnList, Menus, SynEdit, StdCtrls, LMessages, ComCtrls, SynEditSearch, SynEditHighlighter, uDebug, uOSForms, uShowForm, types, Graphics, uFormCommands, uHotkeyManager, LCLVersion, SynPluginMultiCaret, fEditSearch; const HotkeysCategory = 'Editor'; type { TfrmEditor } TfrmEditor = class(TAloneForm,IFormCommands) actEditCut: TAction; actEditCopy: TAction; actEditSelectAll: TAction; actEditUndo: TAction; actEditRedo: TAction; actEditPaste: TAction; actEditDelete: TAction; actEditFindNext: TAction; actEditLineEndCrLf: TAction; actEditLineEndCr: TAction; actEditLineEndLf: TAction; actEditGotoLine: TAction; actEditFindPrevious: TAction; actFileReload: TAction; ilBookmarks: TImageList; MainMenu1: TMainMenu; ActListEdit: TActionList; actAbout: TAction; actFileOpen: TAction; actFileClose: TAction; actFileSave: TAction; actFileSaveAs: TAction; actFileNew: TAction; actFileExit: TAction; MenuItem1: TMenuItem; miFileReload: TMenuItem; miFindPrevious: TMenuItem; miGotoLine: TMenuItem; miEditLineEndCr: TMenuItem; miEditLineEndLf: TMenuItem; miEditLineEndCrLf: TMenuItem; miLineEndType: TMenuItem; N5: TMenuItem; miEncodingOut: TMenuItem; miEncodingIn: TMenuItem; miEncoding: TMenuItem; miFindNext: TMenuItem; miDelete: TMenuItem; miSelectAll: TMenuItem; miRedo: TMenuItem; miDeleteContext: TMenuItem; miSelectAllContext: TMenuItem; miSeparator2: TMenuItem; miPasteContext: TMenuItem; miCopyContext: TMenuItem; miCutContext: TMenuItem; miSeparator1: TMenuItem; miUndoContext: TMenuItem; miFile: TMenuItem; New1: TMenuItem; Open1: TMenuItem; pmContextMenu: TPopupMenu; Save1: TMenuItem; SaveAs1: TMenuItem; N1: TMenuItem; Exit1: TMenuItem; miEdit: TMenuItem; miUndo: TMenuItem; N3: TMenuItem; miCut: TMenuItem; miCopy: TMenuItem; miPaste: TMenuItem; N4: TMenuItem; miFind: TMenuItem; miReplace: TMenuItem; Help1: TMenuItem; miAbout: TMenuItem; StatusBar: TStatusBar; Editor: TSynEdit; miHighlight: TMenuItem; actEditFind: TAction; actEditRplc: TAction; actConfHigh: TAction; miDiv: TMenuItem; miConfHigh: TMenuItem; tbToolBar: TToolBar; tbNew: TToolButton; tbOpen: TToolButton; tbSave: TToolButton; tbSeparator1: TToolButton; tbCut: TToolButton; tbCopy: TToolButton; tbPaste: TToolButton; tbSeparator2: TToolButton; tbUndo: TToolButton; tbRedo: TToolButton; tbSeparator3: TToolButton; tbConfig: TToolButton; tbHelp: TToolButton; procedure actExecute(Sender: TObject); procedure EditorMouseWheelDown(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var Handled: Boolean); procedure EditorMouseWheelUp(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var Handled: Boolean); procedure FormCreate(Sender: TObject); procedure EditorReplaceText(Sender: TObject; const ASearch, AReplace: string; {%H-}Line, {%H-}Column: integer; var ReplaceAction: TSynReplaceAction); procedure EditorChange(Sender: TObject); procedure EditorStatusChange(Sender: TObject; {%H-}Changes: TSynStatusChanges); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure frmEditorClose(Sender: TObject; var CloseAction: TCloseAction); private { Private declarations } bNoName: Boolean; FSearchOptions: TEditSearchOptions; FFileName: String; sEncodingIn, sEncodingOut, sEncodingStat, sOriginalText: String; FWaitData: TWaitData; FElevate: TDuplicates; FCommands: TFormCommands; FMultiCaret: TSynPluginMultiCaret; property Commands: TFormCommands read FCommands implements IFormCommands; procedure ChooseEncoding(mnuMenuItem: TMenuItem; sEncoding: String); {en Saves editor content to a file. @returns(@true if successful) } function SaveFile(const aFileName: String): Boolean; procedure SetFileName(const AValue: String); protected procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public { Public declarations } SynEditSearch: TSynEditSearch; { Function CreateNewTab:Integer; // return tab number Function OpenFileNewTab(const sFileName:String):Integer; } destructor Destroy; override; procedure AfterConstruction; override; {en Opens a file. @returns(@true if successful) } function OpenFile(const aFileName: String): Boolean; procedure UpdateStatus; procedure SetEncodingIn(Sender:TObject); procedure SetEncodingOut(Sender:TObject); procedure SetHighLighter(Sender:TObject); procedure UpdateHighlighter(Highlighter: TSynCustomHighlighter); procedure LoadGlobalOptions; property FileName: String read FFileName write SetFileName; published procedure cm_FileReload(const Params: array of string); procedure cm_EditFind(const {%H-}Params:array of string); procedure cm_EditFindNext(const {%H-}Params:array of string); procedure cm_EditFindPrevious(const {%H-}Params:array of string); procedure cm_EditGotoLine(const {%H-}Params:array of string); procedure cm_EditLineEndCr(const {%H-}Params:array of string); procedure cm_EditLineEndCrLf(const {%H-}Params:array of string); procedure cm_EditLineEndLf(const {%H-}Params:array of string); procedure cm_EditDelete(const {%H-}Params:array of string); procedure cm_EditRedo(const {%H-}Params:array of string); procedure cm_About(const {%H-}Params:array of string); procedure cm_EditCopy(const {%H-}Params:array of string); procedure cm_EditCut(const {%H-}Params:array of string); procedure cm_EditPaste(const {%H-}Params:array of string); procedure cm_EditSelectAll(const {%H-}Params:array of string); procedure cm_FileNew(const {%H-}Params:array of string); procedure cm_FileOpen(const {%H-}Params:array of string); procedure cm_EditUndo(const {%H-}Params:array of string); procedure cm_FileSave(const {%H-}Params:array of string); procedure cm_FileSaveAs(const {%H-}Params:array of string); procedure cm_FileExit(const {%H-}Params:array of string); procedure cm_ConfHigh(const {%H-}Params:array of string); procedure cm_EditRplc(const {%H-}Params:array of string); end; procedure ShowEditor(const sFileName: String; WaitData: TWaitData = nil); var LastEditorUsedForConfiguration: TfrmEditor = nil; implementation {$R *.lfm} uses Clipbrd, dmCommonData, dmHigh, SynEditTypes, LCLType, LConvEncoding, uLng, uShowMsg, uGlobs, fOptions, DCClassesUtf8, uAdministrator, uHighlighters, uOSUtils, uConvEncoding, fOptionsToolsEditor, uDCUtils, uClipboard, uFindFiles, DCOSUtils; procedure ShowEditor(const sFileName: String; WaitData: TWaitData = nil); var Editor: TfrmEditor; begin Editor := TfrmEditor.Create(Application); Editor.FWaitData := WaitData; if sFileName = '' then Editor.cm_FileNew(['']) else begin if not Editor.OpenFile(sFileName) then Exit; end; if (WaitData = nil) then Editor.ShowOnTop else begin WaitData.ShowOnTop(Editor); end; LastEditorUsedForConfiguration := Editor; end; procedure TfrmEditor.FormCreate(Sender: TObject); var i:Integer; mi:TMenuItem; HMEditor: THMForm; miOther: TMenuItem = nil; EncodingsList: TStringList; Options: TTextSearchOptions; begin InitPropStorage(Self); Menu.Images:= dmComData.ilEditorImages; LoadGlobalOptions; // update menu highlighting miHighlight.Clear; for i:= 0 to dmHighl.SynHighlighterList.Count - 1 do begin mi:= TMenuItem.Create(miHighlight); mi.Caption:= TSynCustomHighlighter(dmHighl.SynHighlighterList.Objects[i]).LanguageName; mi.Tag:= i; mi.Enabled:= True; mi.OnClick:=@SetHighLighter; if not TSynCustomHighlighter(dmHighl.SynHighlighterList.Objects[i]).Other then miHighlight.Add(mi) else begin if (miOther = nil) then begin miOther:= TMenuItem.Create(miHighlight); miOther.Caption:= rsDlgButtonOther; end; miOther.Add(mi); end; end; if Assigned(miOther) then miHighlight.Add(miOther); // update menu encoding miEncodingIn.Clear; miEncodingOut.Clear; EncodingsList:= TStringList.Create; GetSupportedEncodings(EncodingsList); for I:= 0 to EncodingsList.Count - 1 do begin mi:= TMenuItem.Create(miEncodingIn); mi.Caption:= EncodingsList[I]; mi.AutoCheck:= True; mi.RadioItem:= True; mi.GroupIndex:= 1; mi.OnClick:= @SetEncodingIn; miEncodingIn.Add(mi); end; for I:= 0 to EncodingsList.Count - 1 do begin mi:= TMenuItem.Create(miEncodingOut); mi.Caption:= EncodingsList[I]; mi.AutoCheck:= True; mi.RadioItem:= True; mi.GroupIndex:= 2; mi.OnClick:= @SetEncodingOut; miEncodingOut.Add(mi); end; EncodingsList.Free; FSearchOptions.Flags := [ssoEntireScope]; // if we already search text then use last searched text if not gFirstTextSearch then begin for I:= 0 to glsSearchHistory.Count - 1 do begin Options:= TTextSearchOptions(UInt32(UIntPtr(glsSearchHistory.Objects[I]))); if (tsoHex in Options) then Continue; if (tsoMatchCase in Options) then FSearchOptions.Flags += [ssoMatchCase]; if (tsoRegExpr in Options) then FSearchOptions.Flags += [ssoRegExpr]; FSearchOptions.SearchText:= glsSearchHistory[I]; Break; end; end; FixFormIcon(Handle); HMEditor := HotMan.Register(Self, HotkeysCategory); HMEditor.RegisterActionList(ActListEdit); FCommands := TFormCommands.Create(Self, ActListEdit); FMultiCaret := TSynPluginMultiCaret.Create(Editor); end; procedure TfrmEditor.LoadGlobalOptions; begin Editor.Options:= gEditorSynEditOptions; FontOptionsToFont(gFonts[dcfEditor], Editor.Font); Editor.TabWidth := gEditorSynEditTabWidth; Editor.RightEdge := gEditorSynEditRightEdge; Editor.BlockIndent := gEditorSynEditBlockIndent; end; procedure TfrmEditor.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; procedure TfrmEditor.EditorMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); var t:integer; begin if (Shift=[ssCtrl])and(gFonts[dcfEditor].Size > gFonts[dcfEditor].MinValue) then begin t:=Editor.TopLine; gFonts[dcfEditor].Size:=gFonts[dcfEditor].Size-1; FontOptionsToFont(gFonts[dcfEditor], Editor.Font); Editor.TopLine:=t; Editor.Refresh; Handled:=True; end; end; procedure TfrmEditor.EditorMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); var t:integer; begin if (Shift=[ssCtrl])and(gFonts[dcfEditor].Size < gFonts[dcfEditor].MaxValue) then begin t:=Editor.TopLine; gFonts[dcfEditor].Size:=gFonts[dcfEditor].Size+1; FontOptionsToFont(gFonts[dcfEditor], Editor.Font); Editor.TopLine:=t; Editor.Refresh; Handled:=True; end; end; function TfrmEditor.OpenFile(const aFileName: String): Boolean; var Buffer: AnsiString; Reader: TFileStreamUAC; Highlighter: TSynCustomHighlighter; begin PushPop(FElevate); try Result := False; try Reader := TFileStreamUAC.Create(aFileName, fmOpenRead or fmShareDenyNone); try SetLength(sOriginalText, Reader.Size); actFileSave.Enabled:= not FileIsReadOnlyEx(Reader.Handle); Reader.Read(Pointer(sOriginalText)^, Length(sOriginalText)); finally Reader.Free; end; // Try to detect encoding by first 4 kb of text Buffer := Copy(sOriginalText, 1, 4096); sEncodingIn := DetectEncoding(Buffer); ChooseEncoding(miEncodingIn, sEncodingIn); sEncodingOut := sEncodingIn; // by default ChooseEncoding(miEncodingOut, sEncodingOut); // Try to guess line break style with Editor.Lines do begin if (sEncodingIn <> EncodingUTF16LE) and (sEncodingIn <> EncodingUTF16BE) then TextLineBreakStyle := GuessLineBreakStyle(Buffer) else begin sOriginalText := Copy(sOriginalText, 3, MaxInt); // Skip BOM TextLineBreakStyle := GuessLineBreakStyle(ConvertEncoding(Buffer, sEncodingIn, EncodingUTF8)); end; case TextLineBreakStyle of tlbsCRLF: actEditLineEndCrLf.Checked := True; tlbsCR: actEditLineEndCr.Checked := True; tlbsLF: actEditLineEndLf.Checked := True; end; end; // Convert encoding if needed if sEncodingIn = EncodingUTF8 then Buffer := sOriginalText else begin Buffer := ConvertEncoding(sOriginalText, sEncodingIn, EncodingUTF8); end; // Load text into editor Editor.Lines.Text := Buffer; // Add empty line if needed if (Length(Buffer) > 0) and (Buffer[Length(Buffer)] in [#10, #13]) then Editor.Lines.Add(EmptyStr); Result := True; except on E: EFCreateError do begin DCDebug(E.Message); msgError(rsMsgErrECreate + ' ' + aFileName); Exit; end; on E: EFOpenError do begin DCDebug(E.Message); msgError(rsMsgErrEOpen + ' ' + aFileName); Exit; end; on E: EReadError do begin DCDebug(E.Message); msgError(rsMsgErrERead + ' ' + aFileName); Exit; end; end; // set up highlighter Highlighter := dmHighl.GetHighlighter(Editor, ExtractFileExt(aFileName)); UpdateHighlighter(Highlighter); FileName := aFileName; Editor.Modified := False; bNoname := False; UpdateStatus; finally PushPop(FElevate); end; end; function TfrmEditor.SaveFile(const aFileName: String): Boolean; var TextOut: String; Encoding: String; Writer: TFileStreamUAC; begin PushPop(FElevate); try Result := False; try Writer := TFileStreamUAC.Create(aFileName, fmCreate); try Encoding := NormalizeEncoding(sEncodingOut); // If file is empty and encoding with BOM then write only BOM if (Editor.Lines.Count = 0) then begin if (Encoding = EncodingUTF8BOM) then Writer.WriteBuffer(UTF8BOM, SizeOf(UTF8BOM)) else if (Encoding = EncodingUTF16LE) then Writer.WriteBuffer(UTF16LEBOM, SizeOf(UTF16LEBOM)) else if (Encoding = EncodingUTF16BE) then Writer.WriteBuffer(UTF16BEBOM, SizeOf(UTF16BEBOM)); end else begin TextOut := EmptyStr; if (Encoding = EncodingUTF16LE) then TextOut := UTF16LEBOM else if (Encoding = EncodingUTF16BE) then begin TextOut := UTF16BEBOM end; TextOut += ConvertEncoding(Editor.Lines[0], EncodingUTF8, sEncodingOut); Writer.WriteBuffer(Pointer(TextOut)^, Length(TextOut)); // If file has only one line then write it without line break if Editor.Lines.Count > 1 then begin TextOut := TextLineBreakValue[Editor.Lines.TextLineBreakStyle]; TextOut += GetTextRange(Editor.Lines, 1, Editor.Lines.Count - 2); // Special case for UTF-8 and UTF-8 with BOM if (Encoding <> EncodingUTF8) and (Encoding <> EncodingUTF8BOM) then begin TextOut:= ConvertEncoding(TextOut, EncodingUTF8, sEncodingOut); end; Writer.WriteBuffer(Pointer(TextOut)^, Length(TextOut)); // Write last line without line break TextOut:= Editor.Lines[Editor.Lines.Count - 1]; // Special case for UTF-8 and UTF-8 with BOM if (Encoding <> EncodingUTF8) and (Encoding <> EncodingUTF8BOM) then begin TextOut:= ConvertEncoding(TextOut, EncodingUTF8, sEncodingOut); end; Writer.WriteBuffer(Pointer(TextOut)^, Length(TextOut)); end; end; // Refresh original text and encoding if (sEncodingIn <> sEncodingOut) or (Length(sOriginalText) = 0) then begin sEncodingIn:= sEncodingOut; ChooseEncoding(miEncodingIn, sEncodingIn); if (sEncodingOut <> EncodingUTF16LE) and (sEncodingOut <> EncodingUTF16BE) then begin Writer.Seek(0, soBeginning); SetLength(sOriginalText, Writer.Size); end else begin Writer.Seek(2, soBeginning); SetLength(sOriginalText, Writer.Size - 2); end; Writer.Read(Pointer(sOriginalText)^, Length(sOriginalText)); end; finally Writer.Free; end; Editor.Modified := False; // needed for the undo stack Editor.MarkTextAsSaved; Result := True; except on E: Exception do msgError(rsMsgErrSaveFile + ' ' + aFileName + LineEnding + E.Message); end; finally PushPop(FElevate); end; end; procedure TfrmEditor.SetFileName(const AValue: String); begin if FFileName = AValue then Exit; FFileName := AValue; Caption := ReplaceHome(FFileName); end; procedure TfrmEditor.CMThemeChanged(var Message: TLMessage); var Highlighter: TSynCustomHighlighter; begin Highlighter:= TSynCustomHighlighter(dmHighl.SynHighlighterHashList.Data[StatusBar.Panels[4].Text]); if Assigned(Highlighter) then dmHighl.SetHighlighter(Editor, Highlighter); end; destructor TfrmEditor.Destroy; begin LastEditorUsedForConfiguration := nil; HotMan.UnRegister(Self); inherited Destroy; if Assigned(FWaitData) then FWaitData.Done; end; procedure TfrmEditor.AfterConstruction; begin inherited AfterConstruction; tbToolBar.ImagesWidth:= gToolIconsSize; tbToolBar.SetButtonSize(gToolIconsSize + ScaleX(6, 96), gToolIconsSize + ScaleY(6, 96)); end; procedure TfrmEditor.EditorReplaceText(Sender: TObject; const ASearch, AReplace: string; Line, Column: integer; var ReplaceAction: TSynReplaceAction ); begin if ASearch = AReplace then ReplaceAction := raSkip else begin case MsgBox(rsMsgReplaceThisText, [msmbYes, msmbNo, msmbCancel, msmbAll], msmbYes, msmbNo) of mmrYes: ReplaceAction := raReplace; mmrAll: ReplaceAction := raReplaceAll; mmrNo: ReplaceAction := raSkip; else ReplaceAction := raCancel; end; end; end; procedure TfrmEditor.SetHighLighter(Sender:TObject); var Highlighter: TSynCustomHighlighter; begin Highlighter:= TSynCustomHighlighter(dmHighl.SynHighlighterList.Objects[TMenuItem(Sender).Tag]); UpdateHighlighter(Highlighter); end; (* This is code for multi tabs editor, it's buggy because Synedit bad handle scrollbars in page control, maybe in future, workaround: new tab must be visible and maybe must have focus procedure TfrmEditor.cm_FileNewExecute(Sender: TObject); var iPageIndex:Integer; begin inherited; iPageIndex:=CreateNewTab; with pgEditor.Pages[iPageIndex] do begin Caption:='New'+IntToStr(iPageIndex); Hint:=''; // filename end; end; Function TfrmEditor.CreateNewTab:Integer; // return tab number var iPageIndex:Integer; begin with TTabSheet.Create(pgEditor) do // create Tab begin PageControl:=pgEditor; iPageIndex:=PageIndex; // now create Editor with TSynEdit.Create(pgEditor.Pages[PageIndex]) do begin Parent:=pgEditor.Pages[PageIndex]; Align:=alClient; Lines.Clear; end; end; end; procedure TfrmEditor.cm_FileOpenExecute(const Params:array of string); var iPageIndex:Integer; begin inherited; dmDlg.OpenDialog.Filter:='*.*'; if dmDlg.OpenDialog.Execute then OpenFileNewTab(dmDlg.OpenDialog.FileName); end; Function TfrmEditor.OpenFileNewTab(const sFileName:String):Integer; var iPageIndex:Integer; begin inherited; iPageIndex:=CreateNewTab; pgEditor.ActivePageIndex:=iPageIndex; with pgEditor.Pages[iPageIndex] do begin Caption:=sFileName; Hint:=sFileName; TSynEdit(pgEditor.Pages[iPageIndex].Components[0]).Lines.LoadFromFile(sFileName); end; end; procedure ShowEditor(lsFiles:TStringList); var i:Integer; begin with TfrmEditor.Create(Application) do begin try for i:=0 to lsFiles.Count-1 do OpenFileNewTab(lsFiles.Strings[i]); ShowModal; finally Free; end; end; end; *) procedure TfrmEditor.EditorChange(Sender: TObject); begin UpdateStatus; end; procedure TfrmEditor.UpdateStatus; const BreakStyle: array[TTextLineBreakStyle] of String = ('LF', 'CRLF', 'CR'); begin if Editor.Modified then StatusBar.Panels[0].Text:= '*' else begin StatusBar.Panels[0].Text:= ''; end; StatusBar.Panels[1].Text:= Format('%d:%d',[Editor.CaretX, Editor.CaretY]); StatusBar.Panels[2].Text:= sEncodingStat; StatusBar.Panels[3].Text:= BreakStyle[Editor.Lines.TextLineBreakStyle]; end; procedure TfrmEditor.SetEncodingIn(Sender: TObject); begin sEncodingStat:= (Sender as TMenuItem).Caption; sEncodingIn:= sEncodingStat; sEncodingOut:= sEncodingStat; ChooseEncoding(miEncodingOut, sEncodingOut); Editor.Lines.Text:= ConvertEncoding(sOriginalText, sEncodingIn, EncodingUTF8); UpdateStatus; end; procedure TfrmEditor.SetEncodingOut(Sender: TObject); begin sEncodingOut:= (Sender as TMenuItem).Caption; end; procedure TfrmEditor.EditorStatusChange(Sender: TObject; Changes: TSynStatusChanges); begin UpdateStatus; miEncodingIn.Enabled := not Editor.Modified; end; procedure TfrmEditor.UpdateHighlighter(Highlighter: TSynCustomHighlighter); begin dmHighl.SetHighlighter(Editor, Highlighter); StatusBar.Panels[4].Text:= Highlighter.LanguageName; end; procedure TfrmEditor.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if not Editor.Modified then CanClose:= True else begin case msgYesNoCancel(Format(rsMsgFileChangedSave,[FileName])) of mmrYes: begin cm_FileSave(['']); CanClose:= not Editor.Modified; end; mmrNo: CanClose:= True; else CanClose:= False; end; end; end; procedure TfrmEditor.cm_FileReload(const Params: array of string); begin if Editor.Modified then begin if not msgYesNo(rsMsgFileReloadWarning) then Exit; end; OpenFile(FFileName); end; procedure TfrmEditor.cm_EditFind(const Params: array of string); begin ShowSearchReplaceDialog(Self, Editor, cbUnchecked, FSearchOptions); end; procedure TfrmEditor.cm_EditFindNext(const Params:array of string); begin if gFirstTextSearch then begin FSearchOptions.Flags -= [ssoBackwards]; ShowSearchReplaceDialog(Self, Editor, cbUnchecked, FSearchOptions) end else if FSearchOptions.SearchText <> '' then begin DoSearchReplaceText(Editor, False, False, FSearchOptions); FSearchOptions.Flags -= [ssoEntireScope]; end; end; procedure TfrmEditor.cm_EditFindPrevious(const Params: array of string); begin if gFirstTextSearch then begin FSearchOptions.Flags += [ssoBackwards]; ShowSearchReplaceDialog(Self, Editor, cbUnchecked, FSearchOptions); end else if FSearchOptions.SearchText <> '' then begin Editor.SelEnd := Editor.SelStart; DoSearchReplaceText(Editor, False, True, FSearchOptions); FSearchOptions.Flags -= [ssoEntireScope]; end; end; procedure TfrmEditor.cm_EditGotoLine(const Params:array of string); var P: TPoint; Value: String; NewTopLine: Integer; begin if ShowInputQuery(rsEditGotoLineTitle, rsEditGotoLineQuery, Value) then begin P.X := 1; P.Y := StrToIntDef(Value, 1); NewTopLine := P.Y - (Editor.LinesInWindow div 2); if NewTopLine < 1 then NewTopLine:= 1; Editor.CaretXY := P; Editor.TopLine := NewTopLine; Editor.SetFocus; end; end; procedure TfrmEditor.cm_EditLineEndCr(const Params:array of string); begin Editor.Lines.TextLineBreakStyle:= tlbsCR; UpdateStatus; end; procedure TfrmEditor.cm_EditLineEndCrLf(const Params:array of string); begin Editor.Lines.TextLineBreakStyle:= tlbsCRLF; UpdateStatus; end; procedure TfrmEditor.cm_EditLineEndLf(const Params:array of string); begin Editor.Lines.TextLineBreakStyle:= tlbsLF; UpdateStatus; end; procedure TfrmEditor.cm_About(const Params:array of string); begin msgOK(rsEditAboutText); end; procedure TfrmEditor.cm_EditCopy(const Params:array of string); begin editor.CopyToClipboard; {$IF DEFINED(LCLGTK2) and (LCL_FULLVERSION < 1100000)} // Workaround for Lazarus bug #0021453 ClipboardSetText(Clipboard.AsText); {$ENDIF} end; procedure TfrmEditor.cm_EditCut(const Params:array of string); begin Editor.CutToClipboard; {$IF DEFINED(LCLGTK2) and (LCL_FULLVERSION < 1100000)} // Workaround for Lazarus bug #0021453 ClipboardSetText(Clipboard.AsText); {$ENDIF} end; procedure TfrmEditor.cm_EditPaste(const Params:array of string); begin editor.PasteFromClipboard; end; procedure TfrmEditor.cm_EditDelete(const Params:array of string); begin Editor.ClearSelection; end; procedure TfrmEditor.cm_EditRedo(const Params:array of string); begin editor.Redo; end; procedure TfrmEditor.cm_EditSelectAll(const Params:array of string); begin editor.SelectAll; end; procedure TfrmEditor.cm_FileNew(const Params:array of string); var CanClose: Boolean = False; begin FormCloseQuery(Self, CanClose); if not CanClose then Exit; FileName := rsMsgNewFile; Editor.Lines.Clear; Editor.Modified:= False; actFileSave.Enabled:= True; bNoname:= True; UpdateStatus; end; procedure TfrmEditor.cm_FileOpen(const Params:array of string); var CanClose: Boolean = False; begin FormCloseQuery(Self, CanClose); if not CanClose then Exit; dmComData.OpenDialog.Filter:= AllFilesMask; if not dmComData.OpenDialog.Execute then Exit; if OpenFile(dmComData.OpenDialog.FileName) then UpdateStatus; end; procedure TfrmEditor.cm_EditUndo(const Params:array of string); begin Editor.Undo; UpdateStatus; end; procedure TfrmEditor.cm_FileSave(const Params:array of string); begin if bNoname then actFileSaveAs.Execute else begin SaveFile(FileName); UpdateStatus; end; end; procedure TfrmEditor.cm_FileSaveAs(const Params:array of string); var Highlighter: TSynCustomHighlighter; begin dmComData.SaveDialog.FileName := FileName; dmComData.SaveDialog.Filter:= AllFilesMask; // rewrite for highlighter if not dmComData.SaveDialog.Execute then Exit; FileName := dmComData.SaveDialog.FileName; if SaveFile(FileName) then begin actFileSave.Enabled:= True; end; bNoname:=False; UpdateStatus; Highlighter:= dmHighl.GetHighlighter(Editor, ExtractFileExt(FileName)); UpdateHighlighter(Highlighter); end; procedure TfrmEditor.cm_FileExit(const Params:array of string); begin Close; end; procedure TfrmEditor.cm_ConfHigh(const Params:array of string); begin LastEditorUsedForConfiguration := Self; ShowOptions(TfrmOptionsEditor); end; procedure TfrmEditor.cm_EditRplc(const Params: array of string); begin ShowSearchReplaceDialog(Self, Editor, cbChecked, FSearchOptions) end; procedure TfrmEditor.frmEditorClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:=caFree; end; procedure TfrmEditor.ChooseEncoding(mnuMenuItem: TMenuItem; sEncoding: String); var I: Integer; begin sEncoding:= NormalizeEncoding(sEncoding); for I:= 0 to mnuMenuItem.Count - 1 do begin if SameText(NormalizeEncoding(mnuMenuItem.Items[I].Caption), sEncoding) then begin mnuMenuItem.Items[I].Checked:= True; if (mnuMenuItem = miEncodingIn) then sEncodingStat:= mnuMenuItem.Items[I].Caption; end; end; end; initialization TFormCommands.RegisterCommandsForm(TfrmEditor, HotkeysCategory, @rsHotkeyCategoryEditor); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/feditsearch.lfm����������������������������������������������������������������0000644�0001750�0000144�00000014475�14743153644�016371� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmEditSearchReplace: TfrmEditSearchReplace Left = 606 Height = 274 Top = 251 Width = 385 ActiveControl = cbSearchText AutoSize = True BorderIcons = [] ChildSizing.TopBottomSpacing = 6 ClientHeight = 274 ClientWidth = 385 Constraints.MinWidth = 385 OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnShow = FormShow Position = poOwnerFormCenter SessionProperties = 'Left;Top;Width;Height' LCLVersion = '2.2.0.4' object lblSearchFor: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = cbSearchText AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 16 Width = 56 BorderSpacing.Left = 12 Caption = '&Search for:' FocusControl = cbSearchText ParentColor = False end object lblReplaceWith: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = cbReplaceText AnchorSideTop.Side = asrCenter Left = 12 Height = 19 Top = 43 Width = 90 BorderSpacing.Left = 12 Caption = '&Replace with:' Color = clDefault OnChange = lblReplaceWithChange ParentColor = False TabOrder = 1 end object cbSearchText: TComboBox AnchorSideLeft.Control = lblSearchFor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 74 Height = 23 Top = 12 Width = 303 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 12 BorderSpacing.Right = 8 ItemHeight = 15 TabOrder = 0 end object gbSearchOptions: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = cbReplaceText AnchorSideTop.Side = asrBottom Left = 12 Height = 156 Top = 76 Width = 142 AutoSize = True BorderSpacing.Left = 12 BorderSpacing.Top = 12 BorderSpacing.Right = 6 Caption = 'Option' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 136 ClientWidth = 138 TabOrder = 3 object cbSearchCaseSensitive: TCheckBox AnchorSideLeft.Control = gbSearchOptions AnchorSideTop.Control = gbSearchOptions Left = 8 Height = 19 Top = 6 Width = 100 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = 'C&ase sensitivity' TabOrder = 0 end object cbSearchWholeWords: TCheckBox AnchorSideLeft.Control = gbSearchOptions AnchorSideTop.Control = cbSearchCaseSensitive AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 27 Width = 115 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = '&Whole words only' TabOrder = 1 end object cbSearchSelectedOnly: TCheckBox AnchorSideLeft.Control = gbSearchOptions AnchorSideTop.Control = cbSearchWholeWords AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 48 Width = 113 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = 'Selected &text only' TabOrder = 2 end object cbSearchFromCursor: TCheckBox AnchorSideLeft.Control = gbSearchOptions AnchorSideTop.Control = cbSearchSelectedOnly AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 69 Width = 113 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = 'S&earch from caret' TabOrder = 3 end object cbSearchRegExp: TCheckBox AnchorSideLeft.Control = gbSearchOptions AnchorSideTop.Control = cbSearchFromCursor AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 90 Width = 124 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = '&Regular expressions' TabOrder = 4 end object cbMultiLine: TCheckBox AnchorSideLeft.Control = gbSearchOptions AnchorSideTop.Control = cbSearchRegExp AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 111 Width = 108 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = '&Multiline pattern' TabOrder = 5 end end object rgSearchDirection: TRadioGroup AnchorSideLeft.Control = gbSearchOptions AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbReplaceText AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbSearchText AnchorSideRight.Side = asrBottom Left = 160 Height = 70 Top = 76 Width = 217 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 12 Caption = 'Direction' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 50 ClientWidth = 213 Items.Strings = ( '&Forward' '&Backward' ) TabOrder = 4 end object cbReplaceText: TComboBox AnchorSideLeft.Control = lblReplaceWith AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbSearchText AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 108 Height = 23 Top = 41 Width = 269 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 8 ItemHeight = 15 TabOrder = 2 end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbSearchOptions AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 26 Top = 242 Width = 373 Align = alNone Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 OKButton.Name = 'OKButton' OKButton.Caption = '&OK' OKButton.OnClick = btnOKClick HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.Caption = '&Cancel' TabOrder = 5 Spacing = 12 ShowButtons = [pbOK, pbCancel] ShowBevel = False end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/feditsearch.lrj����������������������������������������������������������������0000644�0001750�0000144�00000003756�14743153644�016402� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":186617562,"name":"tfrmeditsearchreplace.lblsearchfor.caption","sourcebytes":[38,83,101,97,114,99,104,32,102,111,114,58],"value":"&Search for:"}, {"hash":263925658,"name":"tfrmeditsearchreplace.lblreplacewith.caption","sourcebytes":[38,82,101,112,108,97,99,101,32,119,105,116,104,58],"value":"&Replace with:"}, {"hash":90681438,"name":"tfrmeditsearchreplace.gbsearchoptions.caption","sourcebytes":[79,112,116,105,111,110],"value":"Option"}, {"hash":128736681,"name":"tfrmeditsearchreplace.cbsearchcasesensitive.caption","sourcebytes":[67,38,97,115,101,32,115,101,110,115,105,116,105,118,105,116,121],"value":"C&ase sensitivity"}, {"hash":151740121,"name":"tfrmeditsearchreplace.cbsearchwholewords.caption","sourcebytes":[38,87,104,111,108,101,32,119,111,114,100,115,32,111,110,108,121],"value":"&Whole words only"}, {"hash":231163145,"name":"tfrmeditsearchreplace.cbsearchselectedonly.caption","sourcebytes":[83,101,108,101,99,116,101,100,32,38,116,101,120,116,32,111,110,108,121],"value":"Selected &text only"}, {"hash":60025108,"name":"tfrmeditsearchreplace.cbsearchfromcursor.caption","sourcebytes":[83,38,101,97,114,99,104,32,102,114,111,109,32,99,97,114,101,116],"value":"S&earch from caret"}, {"hash":8115171,"name":"tfrmeditsearchreplace.cbsearchregexp.caption","sourcebytes":[38,82,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115],"value":"&Regular expressions"}, {"hash":135735390,"name":"tfrmeditsearchreplace.cbmultiline.caption","sourcebytes":[38,77,117,108,116,105,108,105,110,101,32,112,97,116,116,101,114,110],"value":"&Multiline pattern"}, {"hash":146466142,"name":"tfrmeditsearchreplace.rgsearchdirection.caption","sourcebytes":[68,105,114,101,99,116,105,111,110],"value":"Direction"}, {"hash":11067,"name":"tfrmeditsearchreplace.buttonpanel.okbutton.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmeditsearchreplace.buttonpanel.cancelbutton.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} ]} ������������������doublecmd-1.1.22/src/feditsearch.pas����������������������������������������������������������������0000644�0001750�0000144�00000032473�14743153644�016374� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Search & Replace dialog Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz) Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fEditSearch; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, StdCtrls, ExtCtrls, Buttons, ButtonPanel, SynEdit, SynEditTypes, uOSForms, DCClassesUtf8; type { TEditSearchOptions } TEditSearchOptions = record SearchText: String; ReplaceText: String; Flags: TSynSearchOptions; end; { TEditSearchDialogOption } //Not only it helps to show what we want to offer to user, it will help to determine the default //When used as parameters of function, place on required. //When used as a returned value, we'll include the status of all. TEditSearchDialogOption = set of (eswoCaseSensitiveChecked, eswoCaseSensitiveUnchecked, eswoWholeWordChecked, eswoWholeWordUnchecked, eswoSelectedTextChecked, eswoSelectedTextUnchecked, eswoSearchFromCursorChecked, eswoSearchFromCursorUnchecked, eswoRegularExpressChecked, eswoRegularExpressUnchecked, eswoDirectionDisabled, eswoDirectionEnabledForward, eswoDirectionEnabledBackward); { TfrmEditSearchReplace } TfrmEditSearchReplace = class(TModalForm) ButtonPanel: TButtonPanel; cbSearchText: TComboBox; cbSearchCaseSensitive: TCheckBox; cbSearchWholeWords: TCheckBox; cbSearchSelectedOnly: TCheckBox; cbSearchFromCursor: TCheckBox; cbSearchRegExp: TCheckBox; cbReplaceText: TComboBox; cbMultiLine: TCheckBox; gbSearchOptions: TGroupBox; lblReplaceWith: TCheckBox; lblSearchFor: TLabel; rgSearchDirection: TRadioGroup; procedure btnOKClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure lblReplaceWithChange(Sender: TObject); procedure RequestAlign(Data: PtrInt); private function GetSearchOptions: TEditSearchOptions; procedure SetSearchOptions(AValue: TEditSearchOptions); function GetTextSearchOptions: UIntPtr; public constructor Create(AOwner: TComponent; AReplace: TCheckBoxState); reintroduce; property SearchOptions: TEditSearchOptions read GetSearchOptions write SetSearchOptions; end; function GetSimpleSearchAndReplaceString(AOwner: TComponent; OptionAllowed: TEditSearchDialogOption; var sSearchText: string; var sReplaceText: string; var OptionsToReturn:TEditSearchDialogOption; PastSearchList:TStringListEx; PastReplaceList:TStringListEx):boolean; procedure DoSearchReplaceText(AEditor: TCustomSynEdit; AReplace, ABackwards: Boolean; AOptions: TEditSearchOptions); procedure ShowSearchReplaceDialog(AOwner: TComponent; AEditor: TCustomSynEdit; AReplace: TCheckBoxState; var AOptions: TEditSearchOptions); implementation {$R *.lfm} uses Math, Graphics, uGlobs, uLng, uDCUtils, uFindFiles, uShowMsg; function GetSimpleSearchAndReplaceString(AOwner:TComponent; OptionAllowed:TEditSearchDialogOption; var sSearchText:string; var sReplaceText:string; var OptionsToReturn:TEditSearchDialogOption; PastSearchList:TStringListEx; PastReplaceList:TStringListEx):boolean; var dlg: TfrmEditSearchReplace; begin result:=FALSE; OptionsToReturn:=[]; dlg := TfrmEditSearchReplace.Create(AOwner, cbChecked); try with dlg do begin //1. Let's enable to options host wanted to offer to user cbSearchCaseSensitive.Enabled := ((eswoCaseSensitiveChecked in OptionAllowed) OR (eswoCaseSensitiveUnchecked in OptionAllowed)); cbSearchWholeWords.Enabled := ((eswoWholeWordChecked in OptionAllowed) OR (eswoWholeWordUnchecked in OptionAllowed)); cbSearchSelectedOnly.Enabled := ((eswoSelectedTextChecked in OptionAllowed) OR (eswoSelectedTextUnchecked in OptionAllowed)); cbSearchFromCursor.Enabled := ((eswoSearchFromCursorChecked in OptionAllowed) OR (eswoSearchFromCursorUnchecked in OptionAllowed)); cbSearchRegExp.Enabled := ((eswoRegularExpressChecked in OptionAllowed) OR (eswoRegularExpressUnchecked in OptionAllowed)); rgSearchDirection.Enabled := ((eswoDirectionEnabledForward in OptionAllowed) OR (eswoDirectionEnabledBackward in OptionAllowed)); cbMultiLine.Enabled := cbSearchRegExp.Enabled; //2. Let's set the option to their default according to what host wants to offer cbSearchCaseSensitive.Checked := (eswoCaseSensitiveChecked in OptionAllowed); cbSearchWholeWords.Checked := (eswoWholeWordChecked in OptionAllowed); cbSearchSelectedOnly.Checked := (eswoSelectedTextChecked in OptionAllowed); cbSearchFromCursor.Checked := (eswoSearchFromCursorChecked in OptionAllowed); cbSearchRegExp.Checked := (eswoRegularExpressChecked in OptionAllowed); rgSearchDirection.ItemIndex:=ifthen((eswoDirectionEnabledBackward in OptionAllowed),1,0); //3. Setup the SEARCH info if sSearchText='' then sSearchText:=rsEditSearchCaption; cbSearchText.Items.Assign(PastSearchList); cbSearchText.Text:= sSearchText; //4. Setup the REPLACE info if sReplaceText='' then sReplaceText:=rsEditSearchReplace; cbReplaceText.Items.Assign(PastReplaceList); cbReplaceText.Text:=sReplaceText; //5. Get feedback from user if ShowModal=mrOk then begin //6. Let's set the options wanted by the user if cbSearchCaseSensitive.Enabled then if cbSearchCaseSensitive.Checked then OptionsToReturn:=OptionsToReturn+[eswoCaseSensitiveChecked] else OptionsToReturn:=OptionsToReturn+[eswoCaseSensitiveUnchecked]; if cbSearchWholeWords.Enabled then if cbSearchWholeWords.Checked then OptionsToReturn:=OptionsToReturn+[eswoWholeWordChecked] else OptionsToReturn:=OptionsToReturn+[eswoWholeWordUnchecked]; if cbSearchSelectedOnly.Enabled then if cbSearchSelectedOnly.Checked then OptionsToReturn:=OptionsToReturn+[eswoSelectedTextChecked] else OptionsToReturn:=OptionsToReturn+[eswoSelectedTextUnchecked]; if cbSearchFromCursor.Enabled then if cbSearchFromCursor.Checked then OptionsToReturn:=OptionsToReturn+[eswoSearchFromCursorChecked] else OptionsToReturn:=OptionsToReturn+[eswoSearchFromCursorUnchecked]; if cbSearchRegExp.Enabled then if cbSearchRegExp.Checked then OptionsToReturn:=OptionsToReturn+[eswoRegularExpressChecked] else OptionsToReturn:=OptionsToReturn+[eswoRegularExpressUnchecked]; if rgSearchDirection.Enabled then if rgSearchDirection.ItemIndex=1 then OptionsToReturn:=OptionsToReturn+[eswoDirectionEnabledBackward] else OptionsToReturn:=OptionsToReturn+[eswoDirectionEnabledForward]; //7. Let's set our history PastSearchList.Assign(cbSearchText.Items); PastReplaceList.Assign(cbReplaceText.Items); //8. And FINALLY, our valuable text to search we wanted to replace! sSearchText:=cbSearchText.Text; sReplaceText:=cbReplaceText.Text; result:=((sSearchText<>sReplaceText) AND (sSearchText<>'')); end; end; finally FreeAndNil(Dlg); end; end; procedure DoSearchReplaceText(AEditor: TCustomSynEdit; AReplace, ABackwards: Boolean; AOptions: TEditSearchOptions); var Flags: TSynSearchOptions; begin Flags := AOptions.Flags; if ABackwards then Include(Flags, ssoBackwards) else begin Exclude(Flags, ssoBackwards); end; if AReplace then begin Flags += [ssoPrompt, ssoReplace, ssoReplaceAll]; end; try if AEditor.SearchReplace(AOptions.SearchText, AOptions.ReplaceText, Flags) = 0 then begin if ssoBackwards in Flags then AEditor.BlockEnd := AEditor.BlockBegin else begin AEditor.BlockBegin := AEditor.BlockEnd; end; AEditor.CaretXY := AEditor.BlockBegin; msgOK(Format(rsViewNotFound, ['"' + AOptions.SearchText + '"'])); end; except on E: Exception do msgError(E.Message); end; end; procedure ShowSearchReplaceDialog(AOwner: TComponent; AEditor: TCustomSynEdit; AReplace: TCheckBoxState; var AOptions: TEditSearchOptions); var Options: TEditSearchOptions; begin with TfrmEditSearchReplace.Create(AOwner, AReplace) do try Options := AOptions; if AEditor.SelAvail and (AEditor.BlockBegin.Y <> AEditor.BlockEnd.Y) then Options.Flags += [ssoSelectedOnly]; // If something is selected then search for that text if AEditor.SelAvail and (AEditor.BlockBegin.Y = AEditor.BlockEnd.Y) then Options.SearchText := AEditor.SelText else begin if gEditorFindWordAtCursor then Options.SearchText := AEditor.GetWordAtRowCol(AEditor.CaretXY); end; cbSearchText.Items.Text := glsSearchHistory.Text; cbReplaceText.Items.Text := glsReplaceHistory.Text; // Assign search options SearchOptions := Options; if ShowModal = mrOK then begin AOptions := SearchOptions; AReplace := lblReplaceWith.State; glsSearchHistory.Assign(cbSearchText.Items); glsReplaceHistory.Assign(cbReplaceText.Items); if AOptions.SearchText <> '' then begin DoSearchReplaceText(AEditor, AReplace = cbChecked, ssoBackwards in AOptions.Flags, AOptions); AOptions.Flags -= [ssoEntireScope]; gFirstTextSearch := False; end; end; finally Free; end; end; { TfrmEditSearchReplace } procedure TfrmEditSearchReplace.btnOKClick(Sender: TObject); begin InsertFirstItem(cbSearchText.Text, cbSearchText, GetTextSearchOptions); ModalResult := mrOK end; procedure TfrmEditSearchReplace.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin if ModalResult = mrOK then InsertFirstItem(cbReplaceText.Text, cbReplaceText, GetTextSearchOptions); end; procedure TfrmEditSearchReplace.FormCreate(Sender: TObject); begin InitPropStorage(Self); end; procedure TfrmEditSearchReplace.FormShow(Sender: TObject); begin if cbSearchText.Text = EmptyStr then begin if cbSearchText.Items.Count > 0 then cbSearchText.Text:= cbSearchText.Items[0]; end; cbSearchText.SelectAll; // Fixes AutoSize under Qt Application.QueueAsyncCall(@RequestAlign, 0); end; procedure TfrmEditSearchReplace.lblReplaceWithChange(Sender: TObject); begin if lblReplaceWith.Checked then Caption:= rsEditSearchReplace else begin Caption:= rsEditSearchCaption; end; cbReplaceText.Enabled := lblReplaceWith.Checked; end; procedure TfrmEditSearchReplace.RequestAlign(Data: PtrInt); begin Width := Width + 1; Width := Width - 1; end; function TfrmEditSearchReplace.GetSearchOptions: TEditSearchOptions; begin Result.SearchText:= cbSearchText.Text; Result.ReplaceText := cbReplaceText.Text; Result.Flags := []; if cbSearchCaseSensitive.Checked then Result.Flags += [ssoMatchCase]; if cbSearchWholeWords.Checked then Result.Flags += [ssoWholeWord]; if cbSearchSelectedOnly.Checked then Result.Flags += [ssoSelectedOnly]; if not cbSearchFromCursor.Checked then Result.Flags += [ssoEntireScope]; if cbSearchRegExp.Checked then Result.Flags += [ssoRegExpr]; if cbMultiLine.Checked then Result.Flags += [ssoRegExprMultiLine]; if rgSearchDirection.ItemIndex = 1 then Result.Flags += [ssoBackwards]; end; procedure TfrmEditSearchReplace.SetSearchOptions(AValue: TEditSearchOptions); begin cbSearchText.Text := AValue.SearchText; cbReplaceText.Text := AValue.ReplaceText; with AValue do begin cbSearchCaseSensitive.Checked := ssoMatchCase in Flags; cbSearchWholeWords.Checked := ssoWholeWord in Flags; cbSearchSelectedOnly.Checked := ssoSelectedOnly in Flags; cbSearchFromCursor.Checked := not (ssoEntireScope in Flags); cbSearchRegExp.Checked := ssoRegExpr in Flags; cbMultiLine.Checked := ssoRegExprMultiLine in Flags; rgSearchDirection.ItemIndex := Ord(ssoBackwards in Flags); end; end; function TfrmEditSearchReplace.GetTextSearchOptions: UIntPtr; var Options: TTextSearchOptions absolute Result; begin Result:= 0; if cbSearchCaseSensitive.Checked then Include(Options, tsoMatchCase); if cbSearchRegExp.Checked then Include(Options, tsoRegExpr); end; constructor TfrmEditSearchReplace.Create(AOwner: TComponent; AReplace: TCheckBoxState); begin inherited Create(AOwner); lblReplaceWith.Visible:= (AReplace <> cbGrayed); cbReplaceText.Visible:= (AReplace <> cbGrayed); cbReplaceText.Enabled := (AReplace = cbChecked); lblReplaceWith.Checked := (AReplace = cbChecked); if (AReplace = cbChecked) then Caption:= rsEditSearchReplace else begin Caption:= rsEditSearchCaption; end; rgSearchDirection.Items.Strings[0]:= rsEditSearchFrw; rgSearchDirection.Items.Strings[1]:= rsEditSearchBack; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fextractdlg.lfm����������������������������������������������������������������0000644�0001750�0000144�00000013060�14743153644�016404� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmExtractDlg: TfrmExtractDlg Left = 462 Height = 293 Top = 174 Width = 496 HelpContext = 160 HorzScrollBar.Page = 446 HorzScrollBar.Range = 437 HorzScrollBar.Visible = False VertScrollBar.Page = 182 VertScrollBar.Range = 177 ActiveControl = edtExtractTo AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Unpack files' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 293 ClientWidth = 496 OnCreate = FormCreate Position = poOwnerFormCenter inherited pnlContent: TPanel Height = 218 Top = 0 Width = 481 Align = alNone ChildSizing.TopBottomSpacing = 4 ClientHeight = 218 ClientWidth = 481 object lblFileMask: TLabel[0] AnchorSideLeft.Control = pnlCheckBoxes AnchorSideTop.Control = cbFileMask AnchorSideTop.Side = asrCenter Left = 0 Height = 22 Top = 15 Width = 211 BorderSpacing.Top = 3 Caption = '&Extract files matching file mask:' FocusControl = cbFileMask ParentColor = False end object lblExtractTo: TLabel[1] AnchorSideLeft.Control = pnlCheckBoxes AnchorSideTop.Control = edtExtractTo AnchorSideTop.Side = asrCenter Left = 0 Height = 22 Top = 59 Width = 108 BorderSpacing.Top = 8 Caption = 'To the &directory:' FocusControl = edtExtractTo ParentColor = False end object lblPassword: TLabel[2] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = edtPassword AnchorSideTop.Side = asrCenter AnchorSideBottom.Side = asrBottom Left = 0 Height = 22 Top = 185 Width = 193 BorderSpacing.Bottom = 3 Caption = '&Password for encrypted files:' FocusControl = edtPassword ParentColor = False end object cbFileMask: TComboBox[3] AnchorSideLeft.Control = lblFileMask AnchorSideLeft.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 221 Height = 36 Top = 8 Width = 260 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Top = 8 Constraints.MinWidth = 260 ItemHeight = 28 ParentFont = False TabOrder = 0 Text = '*.*' end object edtExtractTo: TDirectoryEdit[4] AnchorSideLeft.Control = cbFileMask AnchorSideTop.Control = cbFileMask AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbFileMask AnchorSideRight.Side = asrBottom Left = 221 Height = 36 Top = 52 Width = 260 ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 8 MaxLength = 0 TabOrder = 1 end object edtPassword: TEdit[5] AnchorSideLeft.Control = cbFileMask AnchorSideTop.Control = pnlCheckBoxes AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtExtractTo AnchorSideRight.Side = asrBottom Left = 221 Height = 36 Top = 178 Width = 260 Anchors = [akTop, akLeft, akRight] EchoMode = emPassword Enabled = False PasswordChar = '*' TabOrder = 3 end object pnlCheckBoxes: TPanel[6] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = edtExtractTo AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 90 Top = 88 Width = 446 AutoSize = True BevelOuter = bvNone ChildSizing.TopBottomSpacing = 6 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 90 ClientWidth = 446 TabOrder = 2 object cbInSeparateFolder: TCheckBox AnchorSideTop.Side = asrBottom Left = 0 Height = 26 Top = 6 Width = 446 AllowGrayed = True BorderSpacing.Top = 2 Caption = 'Unpack each archive to a &separate subdir (name of the archive)' TabOrder = 0 end object cbExtractPath: TCheckBox AnchorSideTop.Side = asrBottom Left = 0 Height = 26 Top = 32 Width = 446 Caption = '&Unpack path names if stored with files' Checked = True OnChange = cbExtractPathChange State = cbChecked TabOrder = 1 end object cbOverwrite: TCheckBox AnchorSideTop.Side = asrBottom Left = 0 Height = 26 Top = 58 Width = 446 Caption = 'O&verwrite existing files' Checked = True State = cbChecked TabOrder = 2 end end end inherited pnlButtons: TPanel AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = DividerBevel AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom Height = 38 Top = 248 Width = 481 Align = alNone Anchors = [akTop, akLeft, akRight] ClientHeight = 38 ClientWidth = 481 inherited btnCancel: TBitBtn Left = 282 Height = 38 Width = 91 end inherited btnOK: TBitBtn Left = 382 Top = 0 end end object DividerBevel: TDividerBevel[2] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = pnlContent AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom Left = 8 Height = 22 Top = 222 Width = 481 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 Font.Style = [fsBold] ParentFont = False end inherited pmQueuePopup: TPopupMenu[3] Left = 232 Top = 224 end end��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fextractdlg.lrj����������������������������������������������������������������0000644�0001750�0000144�00000003406�14743153644�016420� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":145335635,"name":"tfrmextractdlg.caption","sourcebytes":[85,110,112,97,99,107,32,102,105,108,101,115],"value":"Unpack files"}, {"hash":134744266,"name":"tfrmextractdlg.lblfilemask.caption","sourcebytes":[38,69,120,116,114,97,99,116,32,102,105,108,101,115,32,109,97,116,99,104,105,110,103,32,102,105,108,101,32,109,97,115,107,58],"value":"&Extract files matching file mask:"}, {"hash":106032954,"name":"tfrmextractdlg.lblpassword.caption","sourcebytes":[38,80,97,115,115,119,111,114,100,32,102,111,114,32,101,110,99,114,121,112,116,101,100,32,102,105,108,101,115,58],"value":"&Password for encrypted files:"}, {"hash":154698666,"name":"tfrmextractdlg.lblextractto.caption","sourcebytes":[84,111,32,116,104,101,32,38,100,105,114,101,99,116,111,114,121,58],"value":"To the &directory:"}, {"hash":11530,"name":"tfrmextractdlg.cbfilemask.text","sourcebytes":[42,46,42],"value":"*.*"}, {"hash":45675769,"name":"tfrmextractdlg.cbinseparatefolder.caption","sourcebytes":[85,110,112,97,99,107,32,101,97,99,104,32,97,114,99,104,105,118,101,32,116,111,32,97,32,38,115,101,112,97,114,97,116,101,32,115,117,98,100,105,114,32,40,110,97,109,101,32,111,102,32,116,104,101,32,97,114,99,104,105,118,101,41],"value":"Unpack each archive to a &separate subdir (name of the archive)"}, {"hash":211866595,"name":"tfrmextractdlg.cbextractpath.caption","sourcebytes":[38,85,110,112,97,99,107,32,112,97,116,104,32,110,97,109,101,115,32,105,102,32,115,116,111,114,101,100,32,119,105,116,104,32,102,105,108,101,115],"value":"&Unpack path names if stored with files"}, {"hash":212923379,"name":"tfrmextractdlg.cboverwrite.caption","sourcebytes":[79,38,118,101,114,119,114,105,116,101,32,101,120,105,115,116,105,110,103,32,102,105,108,101,115],"value":"O&verwrite existing files"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fextractdlg.pas����������������������������������������������������������������0000644�0001750�0000144�00000026017�14743153644�016417� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File unpacking window Copyright (C) 2007-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fExtractDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, StdCtrls, EditBtn, ExtCtrls, Buttons, Menus, DividerBevel, uFile, uFileSource, uArchiveFileSource, fButtonForm, uOperationsManager; type { TfrmExtractDlg } TfrmExtractDlg = class(TfrmButtonForm) cbExtractPath: TCheckBox; cbInSeparateFolder: TCheckBox; cbOverwrite: TCheckBox; DividerBevel: TDividerBevel; edtPassword: TEdit; edtExtractTo: TDirectoryEdit; lblExtractTo: TLabel; lblPassword: TLabel; cbFileMask: TComboBox; lblFileMask: TLabel; pnlCheckBoxes: TPanel; procedure cbExtractPathChange(Sender: TObject); procedure FormCreate(Sender: TObject); private { private declarations } FArcType: String; procedure SwitchOptions; procedure ExtractArchive(ArchiveFileSource: IArchiveFileSource; TargetFileSource: IFileSource; const TargetPath, TargetMask: String; QueueId: TOperationsManagerQueueIdentifier); protected procedure DoAutoSize; override; public { public declarations } end; // Frees 'SourceFiles'. procedure ShowExtractDlg(TheOwner: TComponent; SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetFileSource: IFileSource; sDestPath: String); implementation {$R *.lfm} uses Dialogs, uGlobs, uDCUtils, uShowMsg, uLng, DCStrUtils, uFileSourceOperation, uFileSystemFileSource, uArchiveFileSourceUtil, uFileSourceOperationTypes, uMultiArchiveFileSource, uMultiArchiveCopyOutOperation, uWcxArchiveFileSource, uWcxArchiveCopyOutOperation, uFileSourceOperationOptions, uArchiveCopyOperation, uMasks; function GetTargetPath(FileSource: IArchiveFileSource; const TargetPath: String): String; begin // if destination path is not absolute then extract to path there archive is located if GetPathType(TargetPath) <> ptAbsolute then Result := GetAbsoluteFileName(ExtractFilePath(FileSource.ArchiveFileName), TargetPath) else Result := IncludeTrailingPathDelimiter(TargetPath); end; procedure ShowExtractDlg(TheOwner: TComponent; SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetFileSource: IFileSource; sDestPath: String); var Result: Boolean; I, Count: Integer; extractDialog: TfrmExtractDlg; Operation: TFileSourceOperation; ArchiveFileSource: IArchiveFileSource; QueueId: TOperationsManagerQueueIdentifier; begin if not TargetFileSource.IsClass(TFileSystemFileSource) then begin msgWarning(rsMsgErrNotSupported); Exit; end; extractDialog := TfrmExtractDlg.Create(TheOwner); if Assigned(extractDialog) then try with extractDialog do begin Count := SourceFiles.Count; edtExtractTo.Text := sDestPath; if SourceFileSource.IsClass(TArchiveFileSource) then cbInSeparateFolder.Visible := False; cbFileMask.Items.Assign(glsMaskHistory); EnableControl(edtPassword, False); // If one archive is selected if (Count = 1) then begin FArcType:= SourceFiles[0].Extension; SwitchOptions; end; // Show form Result := (ShowModal = mrOk); if Result then begin if glsMaskHistory.IndexOf(cbFileMask.Text) < 0 then glsMaskHistory.Add(cbFileMask.Text); sDestPath := edtExtractTo.Text; // if in archive if SourceFileSource.IsClass(TArchiveFileSource) then begin if fsoCopyOut in SourceFileSource.GetOperationsTypes then begin sDestPath := GetTargetPath(SourceFileSource as IArchiveFileSource, sDestPath); Operation := SourceFileSource.CreateCopyOutOperation(TargetFileSource, SourceFiles, sDestPath); if Assigned(Operation) then begin TArchiveCopyOutOperation(Operation).ExtractMask := cbFileMask.Text; // Start operation. OperationsManager.AddOperation(Operation, QueueIdentifier, False); end else msgWarning(rsMsgNotImplemented); end else msgWarning(rsMsgErrNotSupported); end else // if filesystem if SourceFileSource.IsClass(TFileSystemFileSource) then begin // if archives count > 1 then put to queue if (Count > 1) and (QueueIdentifier = FreeOperationsQueueId) then QueueId := OperationsManager.GetNewQueueIdentifier else begin QueueId := QueueIdentifier; end; // extract all selected archives for I := 0 to Count - 1 do begin try // Check if there is a ArchiveFileSource for possible archive. ArchiveFileSource := GetArchiveFileSource(SourceFileSource, SourceFiles[i], EmptyStr, False, True); // Try to determine archive type by content if (ArchiveFileSource = nil) then begin ArchiveFileSource := GetArchiveFileSource(SourceFileSource, SourceFiles[i], EmptyStr, True, True); end; // Extract current item ExtractArchive(ArchiveFileSource, TargetFileSource, sDestPath, cbFileMask.Text, QueueId); except on E: Exception do begin MessageDlg(E.Message, mtError, [mbOK], 0); end; end; end; // for end else msgWarning(rsMsgErrNotSupported); gExtractOverwrite := cbOverwrite.Checked; end; // if Result end; finally if Assigned(extractDialog) then FreeAndNil(extractDialog); if Assigned(SourceFiles) then FreeAndNil(SourceFiles); end; end; { TfrmExtractDlg } procedure TfrmExtractDlg.FormCreate(Sender: TObject); begin InitPropStorage(Self); cbOverwrite.Checked := gExtractOverwrite; end; procedure TfrmExtractDlg.cbExtractPathChange(Sender: TObject); begin SwitchOptions; end; procedure TfrmExtractDlg.SwitchOptions; var I: LongInt; begin // Check for this archive will be processed by MultiArc for I := 0 to gMultiArcList.Count - 1 do with gMultiArcList.Items[I] do begin if FEnabled and MatchesMaskList(FArcType, FExtension, ',') then begin // If addon supports unpacking without path if (Length(FExtractWithoutPath) <> 0) then cbExtractPath.Enabled:= True else begin cbExtractPath.Enabled:= False; cbExtractPath.Checked:= True; end; // If addon supports unpacking with password if cbExtractPath.Checked then EnableControl(edtPassword, (Pos('%W', FExtract) <> 0)) else EnableControl(edtPassword, (Pos('%W', FExtractWithoutPath) <> 0)); Break; end; end; end; procedure TfrmExtractDlg.ExtractArchive(ArchiveFileSource: IArchiveFileSource; TargetFileSource: IFileSource; const TargetPath, TargetMask: String; QueueId: TOperationsManagerQueueIdentifier); var FilesToExtract: TFiles; Operation: TFileSourceOperation; sTmpPath: string; begin if Assigned(ArchiveFileSource) then begin // Check if List and CopyOut are supported. if [fsoList, fsoCopyOut] * ArchiveFileSource.GetOperationsTypes = [fsoList, fsoCopyOut] then begin // Get files to extract. FilesToExtract := ArchiveFileSource.GetFiles(ArchiveFileSource.GetRootDir); if Assigned(FilesToExtract) then try sTmpPath := GetTargetPath(ArchiveFileSource, TargetPath); // if each archive in separate folder if cbInSeparateFolder.Checked then begin sTmpPath := sTmpPath + ExtractOnlyFileName(ArchiveFileSource.ArchiveFileName) + PathDelim; end; // extract all files Operation := ArchiveFileSource.CreateCopyOutOperation(TargetFileSource, FilesToExtract, sTmpPath); // Set operation specific options if Assigned(Operation) then begin if cbInSeparateFolder.State = cbGrayed then begin with Operation as TArchiveCopyOutOperation do ExtractFlags:= ExtractFlags + [efSmartExtract]; end; if ArchiveFileSource.IsInterface(IMultiArchiveFileSource) then begin with Operation as TMultiArchiveCopyOutOperation do begin ExtractMask := TargetMask; Password := edtPassword.Text; ExtractWithoutPath:= not cbExtractPath.Checked; end; end else if ArchiveFileSource.IsInterface(IWcxArchiveFileSource) then begin with Operation as TWcxArchiveCopyOutOperation do begin ExtractMask := TargetMask; if cbOverwrite.Checked then FileExistsOption := fsoofeOverwrite; ExtractWithoutPath:= not cbExtractPath.Checked; end; end; // Start operation. OperationsManager.AddOperation(Operation, QueueId, False); end else msgWarning(rsMsgNotImplemented); finally if Assigned(FilesToExtract) then FreeAndNil(FilesToExtract); end; end else msgWarning(rsMsgErrNotSupported); end; end; procedure TfrmExtractDlg.DoAutoSize; var Index: Integer; AControl: TControl; AMaxControl: TControl; AMaxWidth: Integer = 0; begin inherited DoAutoSize; for Index:= 0 to pnlContent.ControlCount - 1 do begin AControl:= pnlContent.Controls[Index]; if AControl is TCustomLabel then begin if AControl.Width > AMaxWidth then begin AMaxControl:= AControl; AMaxWidth:= AControl.Width; end; end; end; cbFileMask.AnchorSide[akLeft].Control:= AMaxControl; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileexecuteyourself.lfm�������������������������������������������������������0000644�0001750�0000144�00000005020�14743153644�020333� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFileExecuteYourSelf: TfrmFileExecuteYourSelf Left = 366 Height = 102 Top = 182 Width = 320 AutoSize = True BorderIcons = [biSystemMenu, biMinimize] BorderStyle = bsSingle Caption = 'Wait...' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 102 ClientWidth = 320 OnClose = FormClose OnCreate = FormCreate ShowInTaskBar = stAlways LCLVersion = '1.6.0.4' object lblPrompt: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 15 Top = 8 Width = 304 Anchors = [akTop, akLeft, akRight] Caption = 'Click on Close when the temporary file can be deleted!' ParentColor = False end object btnClose: TBitBtn AnchorSideLeft.Control = Owner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = lblFromPathValue AnchorSideTop.Side = asrBottom Left = 123 Height = 30 Top = 45 Width = 75 AutoSize = True BorderSpacing.Top = 8 Caption = '&Close' Kind = bkClose TabOrder = 0 end object lblFileNameValue: TLabel AnchorSideLeft.Control = lblFileName AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblPrompt AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 68 Height = 1 Top = 29 Width = 244 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 ParentColor = False end object lblFromPathValue: TLabel AnchorSideLeft.Control = lblFromPath AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblFileNameValue AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 45 Height = 1 Top = 36 Width = 267 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 ParentColor = False end object lblFileName: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblPrompt AnchorSideTop.Side = asrBottom Left = 8 Height = 15 Top = 29 Width = 54 BorderSpacing.Top = 6 Caption = 'File name:' ParentColor = False end object lblFromPath: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblFileName AnchorSideTop.Side = asrBottom Left = 8 Height = 15 Top = 50 Width = 31 BorderSpacing.Top = 6 Caption = 'From:' ParentColor = False end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileexecuteyourself.lrj�������������������������������������������������������0000644�0001750�0000144�00000001575�14743153644�020357� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":226521438,"name":"tfrmfileexecuteyourself.caption","sourcebytes":[87,97,105,116,46,46,46],"value":"Wait..."}, {"hash":30419601,"name":"tfrmfileexecuteyourself.lblprompt.caption","sourcebytes":[67,108,105,99,107,32,111,110,32,67,108,111,115,101,32,119,104,101,110,32,116,104,101,32,116,101,109,112,111,114,97,114,121,32,102,105,108,101,32,99,97,110,32,98,101,32,100,101,108,101,116,101,100,33],"value":"Click on Close when the temporary file can be deleted!"}, {"hash":44709525,"name":"tfrmfileexecuteyourself.btnclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"}, {"hash":124826538,"name":"tfrmfileexecuteyourself.lblfilename.caption","sourcebytes":[70,105,108,101,32,110,97,109,101,58],"value":"File name:"}, {"hash":5084682,"name":"tfrmfileexecuteyourself.lblfrompath.caption","sourcebytes":[70,114,111,109,58],"value":"From:"} ]} �����������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileexecuteyourself.pas�������������������������������������������������������0000644�0001750�0000144�00000012260�14743153644�020344� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Copy out, execute and delete files from non FileSystemFileSource Copyright (C) 2010-2016 Alexander Koblov (alexx2000@mail.ru) 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 } unit fFileExecuteYourSelf; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, StdCtrls, Buttons, uFile, uFileSource, uFileView, uOSForms, uShowForm; type { TfrmFileExecuteYourSelf } TfrmFileExecuteYourSelf = class(TAloneForm) btnClose: TBitBtn; lblFromPath: TLabel; lblFileName: TLabel; lblFromPathValue: TLabel; lblFileNameValue: TLabel; lblPrompt: TLabel; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); private FFileSource: IFileSource; FWaitData: TWaitData; public constructor Create(TheOwner: TComponent; aFileSource: IFileSource; const FileName, FromPath: String); reintroduce; destructor Destroy; override; end; procedure ShowFileEditExternal(const FileName, FromPath: string; aWaitData: TWaitData; Modal: Boolean = False); function ShowFileExecuteYourSelf(aFileView: TFileView; aFile: TFile; bWithAll: Boolean): Boolean; implementation {$R *.lfm} uses DCOSUtils, DCStrUtils, uTempFileSystemFileSource, uFileSourceOperation, uFileSourceCopyOperation, uShellExecute; procedure ShowFileEditExternal(const FileName, FromPath: string; aWaitData: TWaitData; Modal: Boolean = False); begin // Create wait window with TfrmFileExecuteYourSelf.Create(Application, nil, FileName, FromPath) do begin FWaitData:= aWaitData; // Show wait window if Modal then ShowModal else Visible := True; end; end; function ShowFileExecuteYourSelf(aFileView: TFileView; aFile: TFile; bWithAll: Boolean): Boolean; var TempFiles: TFiles = nil; TempFileSource: ITempFileSystemFileSource = nil; Operation: TFileSourceOperation = nil; CurrentDir, FileName: String; begin Result:= False; try TempFileSource:= TTempFileSystemFileSource.GetFileSource; if bWithAll then begin FileName:= TempFileSource.FileSystemRoot + ExcludeFrontPathDelimiter(aFile.FullPath); TempFiles:= aFileView.FileSource.GetFiles(aFileView.FileSource.GetRootDir); end else begin FileName:= TempFileSource.FileSystemRoot + aFile.Name; TempFiles:= TFiles.Create(aFileView.CurrentPath); TempFiles.Add(aFile.Clone); end; Operation := aFileView.FileSource.CreateCopyOutOperation( TempFileSource, TempFiles, TempFileSource.FileSystemRoot); if not Assigned(Operation) then Exit; // Execute operation Operation.Execute; // Create wait window with TfrmFileExecuteYourSelf.Create(Application, TempFileSource, aFile.Name, aFileView.CurrentAddress + aFileView.CurrentPath) do begin FWaitData:= TEditorWaitData.Create(Operation as TFileSourceCopyOperation); // Show wait window Show; // Save current directory CurrentDir:= mbGetCurrentDir; Result:= ShellExecuteEx('open', FileName, TempFileSource.FileSystemRoot + ExcludeFrontPathDelimiter(aFile.Path)); // Restore current directory mbSetCurrentDir(CurrentDir); // If file can not be opened then close wait window if not Result then Close; end; finally FreeAndNil(Operation); FreeAndNil(TempFiles); end; end; { TfrmFileExecuteYourSelf } procedure TfrmFileExecuteYourSelf.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; end; procedure TfrmFileExecuteYourSelf.FormCreate(Sender: TObject); begin // Workaround: TWinControl.WMSize loop detected // http://doublecmd.sourceforge.net/mantisbt/view.php?id=1378 Constraints.MaxWidth:= Screen.Width; Constraints.MaxHeight:= Screen.Height; end; constructor TfrmFileExecuteYourSelf.Create(TheOwner: TComponent; aFileSource: IFileSource; const FileName, FromPath: String); begin inherited Create(TheOwner); FFileSource:= aFileSource; lblFileNameValue.Caption:= FileName; lblFromPathValue.Caption:= FromPath; end; destructor TfrmFileExecuteYourSelf.Destroy; begin // Delete the temporary file source and all files inside. FFileSource:= nil; inherited Destroy; if Assigned(FWaitData) then FWaitData.Done; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileproperties.lfm������������������������������������������������������������0000644�0001750�0000144�00000065066�14743153644�017314� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFileProperties: TfrmFileProperties Left = 764 Height = 483 Top = 123 Width = 458 ActiveControl = pcPageControl AutoSize = True Caption = 'Properties' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 483 ClientWidth = 458 Constraints.MinHeight = 432 Constraints.MinWidth = 458 KeyPreview = True OnCreate = FormCreate OnKeyDown = FormKeyDown Position = poScreenCenter SessionProperties = 'Height;Width' LCLVersion = '2.2.4.0' object pcPageControl: TPageControl AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = ButtonPanel Left = 8 Height = 432 Top = 8 Width = 442 ActivePage = tsProperties Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Bottom = 6 TabIndex = 0 TabOrder = 0 object tsProperties: TTabSheet AutoSize = True Caption = 'Properties' ClientHeight = 397 ClientWidth = 436 object pnlData: TPanel Left = 0 Height = 397 Top = 0 Width = 436 Align = alClient BevelOuter = bvNone ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 397 ClientWidth = 436 Color = clForm ParentColor = False TabOrder = 0 object pnlIcon: TPanel Left = 10 Height = 32 Top = 12 Width = 107 BevelOuter = bvNone ClientHeight = 32 ClientWidth = 107 TabOrder = 0 object imgFileIcon: TImage Left = 0 Height = 32 Top = 0 Width = 32 Stretch = True end end object lblFileName: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 127 Height = 32 Top = 12 Width = 24 BorderSpacing.Left = 10 BorderSpacing.Top = 12 BorderSpacing.Right = 10 Caption = '???' Layout = tlCenter ParentColor = False ShowAccelChar = False end object lblFolderStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 63 Width = 107 BorderSpacing.Top = 16 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Path:' ParentColor = False end object lblFolder: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 60 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblTypeStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 88 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Type:' ParentColor = False end object lblType: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 85 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblMediaTypeStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 113 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Media type:' ParentColor = False end object lblMediaType: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 110 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblSymlinkStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 138 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Symlink to:' ParentColor = False end object lblSymlink: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 135 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblSizeStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 163 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Size:' ParentColor = False end object lblSize: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 160 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblSizeOnDiskStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 188 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Size on disk:' ParentColor = False end object lblSizeOnDisk: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 185 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblContainsStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 213 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Contains:' ParentColor = False end object lblContains: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 210 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblLinksStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 238 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Links:' ParentColor = False end object lblLinks: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 235 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblCreatedStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 269 Width = 107 BorderSpacing.Top = 10 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Created:' ParentColor = False end object lblCreated: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 268 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblLastModifStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 294 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Modified:' ParentColor = False end object lblLastModif: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 291 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblLastAccessStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 319 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Accessed:' ParentColor = False end object lblLastAccess: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 316 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end object lblLastStChangeStr: TLabel AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 343 Width = 107 BorderSpacing.Top = 2 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'Status changed:' ParentColor = False end object lblLastStChange: TKASCDEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Cursor = crIBeam Left = 127 Height = 23 Top = 340 Width = 24 AutoSize = True DrawStyle = dsExtra1 Lines.Strings = ( '???' ) ReadOnly = True end end end object tsAttributes: TTabSheet AutoSize = True Caption = 'Attributes' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ClientHeight = 397 ClientWidth = 436 object lblFileStr: TLabel AnchorSideTop.Control = tsAttributes Left = 10 Height = 17 Top = 12 Width = 54 BorderSpacing.Top = 12 Caption = 'File name' ParentColor = False end object lblFile: TLabel AnchorSideTop.Control = tsAttributes Left = 106 Height = 17 Top = 12 Width = 54 BorderSpacing.Top = 12 Caption = 'File name' ParentColor = False ParentFont = False end object lblAttrOwnerStr: TLabel AnchorSideTop.Control = cbReadOwner AnchorSideTop.Side = asrCenter Left = 10 Height = 17 Top = 74 Width = 37 Caption = 'Owner' ParentColor = False end object lblWrite: TLabel AnchorSideLeft.Control = cbWriteOwner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = DividerBevel1 AnchorSideTop.Side = asrBottom Left = 187 Height = 17 Top = 48 Width = 30 Caption = 'Write' ParentColor = False end object lblRead: TLabel AnchorSideLeft.Control = cbReadOwner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = DividerBevel1 AnchorSideTop.Side = asrBottom Left = 116 Height = 17 Top = 48 Width = 28 Caption = 'Read' ParentColor = False end object lblExec: TLabel AnchorSideLeft.Control = cbExecOwner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = DividerBevel1 AnchorSideTop.Side = asrBottom Left = 252 Height = 17 Top = 48 Width = 44 Caption = 'Execute' ParentColor = False end object lblAttrGroupStr: TLabel AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrCenter Left = 10 Height = 17 Top = 102 Width = 35 Caption = 'Group' ParentColor = False end object lblAttrOtherStr: TLabel AnchorSideTop.Control = cbReadOther AnchorSideTop.Side = asrCenter Left = 10 Height = 17 Top = 130 Width = 32 Caption = 'Other' ParentColor = False end object lblAttrTextStr: TLabel AnchorSideLeft.Control = edtOctal AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtOctal AnchorSideTop.Side = asrCenter Left = 211 Height = 17 Top = 229 Width = 26 BorderSpacing.Left = 12 BorderSpacing.Top = 6 Caption = 'Text:' ParentColor = False end object lblAttrText: TLabel AnchorSideLeft.Control = lblAttrTextStr AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblAttrTextStr AnchorSideTop.Side = asrCenter Left = 245 Height = 17 Top = 229 Width = 44 BorderSpacing.Left = 8 Caption = '-----------' ParentColor = False ParentFont = False end object lblAttrBitsStr: TLabel AnchorSideTop.Control = cbSuid AnchorSideTop.Side = asrCenter Left = 10 Height = 17 Top = 171 Width = 24 Caption = 'Bits:' ParentColor = False end object lblOctal: TLabel AnchorSideLeft.Control = lblAttrBitsStr AnchorSideTop.Control = edtOctal AnchorSideTop.Side = asrCenter Left = 10 Height = 17 Top = 229 Width = 32 Caption = 'Octal:' FocusControl = edtOctal ParentColor = False end object cbReadOwner: TCheckBox AnchorSideTop.Control = lblRead AnchorSideTop.Side = asrBottom Left = 119 Height = 22 Top = 71 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 0 end object cbWriteOwner: TCheckBox AnchorSideTop.Control = lblWrite AnchorSideTop.Side = asrBottom Left = 191 Height = 22 Top = 71 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 1 end object cbExecOwner: TCheckBox AnchorSideTop.Control = lblExec AnchorSideTop.Side = asrBottom Left = 263 Height = 22 Top = 71 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 2 end object cbReadGroup: TCheckBox AnchorSideTop.Control = cbReadOwner AnchorSideTop.Side = asrBottom Left = 119 Height = 22 Top = 99 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 3 end object cbWriteGroup: TCheckBox AnchorSideLeft.Control = cbWriteOwner AnchorSideTop.Control = cbWriteOwner AnchorSideTop.Side = asrBottom Left = 191 Height = 22 Top = 99 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 4 end object cbExecGroup: TCheckBox AnchorSideLeft.Control = cbExecOwner AnchorSideTop.Control = cbExecOwner AnchorSideTop.Side = asrBottom Left = 263 Height = 22 Top = 99 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 5 end object cbReadOther: TCheckBox AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrBottom Left = 119 Height = 22 Top = 127 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 6 end object cbWriteOther: TCheckBox AnchorSideLeft.Control = cbWriteOwner AnchorSideTop.Control = cbWriteGroup AnchorSideTop.Side = asrBottom Left = 191 Height = 22 Top = 127 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 7 end object cbExecOther: TCheckBox AnchorSideLeft.Control = cbExecOwner AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrBottom Left = 263 Height = 22 Top = 127 Width = 22 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 8 end object cbSuid: TCheckBox AnchorSideLeft.Control = cbReadOther AnchorSideTop.Control = DividerBevel2 AnchorSideTop.Side = asrBottom Left = 119 Height = 22 Top = 168 Width = 53 AllowGrayed = True Caption = 'SUID' OnClick = cbChangeModeClick State = cbGrayed TabOrder = 9 end object cbSgid: TCheckBox AnchorSideLeft.Control = cbWriteOther AnchorSideTop.Control = DividerBevel2 AnchorSideTop.Side = asrBottom Left = 191 Height = 22 Top = 168 Width = 53 AllowGrayed = True Caption = 'SGID' OnClick = cbChangeModeClick State = cbGrayed TabOrder = 10 end object cbSticky: TCheckBox AnchorSideLeft.Control = cbExecOther AnchorSideTop.Control = DividerBevel2 AnchorSideTop.Side = asrBottom Left = 263 Height = 22 Top = 168 Width = 56 AllowGrayed = True Caption = 'Sticky' OnClick = cbChangeModeClick State = cbGrayed TabOrder = 11 end object edtOctal: TEdit AnchorSideLeft.Control = cbSuid AnchorSideTop.Control = chkExecutable AnchorSideTop.Side = asrBottom Left = 119 Height = 27 Top = 224 Width = 80 BorderSpacing.Top = 6 MaxLength = 4 OnKeyPress = edtOctalKeyPress OnKeyUp = edtOctalKeyUp TabOrder = 13 end object chkExecutable: TCheckBox AnchorSideLeft.Control = cbSuid AnchorSideTop.Control = cbSuid AnchorSideTop.Side = asrBottom Left = 119 Height = 22 Top = 196 Width = 199 BorderSpacing.Top = 6 Caption = 'Allow &executing file as program' OnClick = chkExecutableChange TabOrder = 12 end object lblExecutable: TLabel AnchorSideLeft.Control = lblAttrBitsStr AnchorSideTop.Control = chkExecutable AnchorSideTop.Side = asrCenter Left = 10 Height = 17 Top = 199 Width = 47 Caption = 'Execute:' ParentColor = False end object DividerBevel1: TDividerBevel AnchorSideLeft.Control = tsAttributes AnchorSideTop.Control = lblFile AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsAttributes AnchorSideRight.Side = asrBottom Left = 10 Height = 17 Top = 31 Width = 416 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Top = 2 BorderSpacing.Right = 8 Font.Style = [fsBold] ParentFont = False Style = gsHorLines end object DividerBevel2: TDividerBevel AnchorSideLeft.Control = DividerBevel1 AnchorSideTop.Control = cbWriteOther AnchorSideTop.Side = asrBottom AnchorSideRight.Control = DividerBevel1 AnchorSideRight.Side = asrBottom Left = 10 Height = 17 Top = 151 Width = 416 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Font.Style = [fsBold] ParentFont = False Style = gsHorLines end object DividerBevel3: TDividerBevel AnchorSideLeft.Control = tsAttributes AnchorSideTop.Control = edtOctal AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsAttributes AnchorSideRight.Side = asrBottom Left = 10 Height = 17 Top = 257 Width = 416 Caption = 'Owner' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ParentFont = False Style = gsHorLines end object pnlOwner: TPanel AnchorSideLeft.Control = tsAttributes AnchorSideTop.Control = DividerBevel3 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsAttributes AnchorSideRight.Side = asrBottom Left = 10 Height = 74 Top = 274 Width = 416 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ClientHeight = 74 ClientWidth = 416 ParentColor = False TabOrder = 14 object lblOwnerStr: TLabel AnchorSideLeft.Control = pnlOwner AnchorSideTop.Control = cbxUsers AnchorSideTop.Side = asrCenter Left = 0 Height = 17 Top = 12 Width = 37 Caption = 'O&wner' FocusControl = cbxUsers ParentColor = False end object lblGroupStr: TLabel AnchorSideLeft.Control = pnlOwner AnchorSideTop.Control = cbxGroups AnchorSideTop.Side = asrCenter Left = 0 Height = 17 Top = 45 Width = 35 Caption = '&Group' FocusControl = cbxGroups ParentColor = False end object cbxUsers: TComboBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlOwner AnchorSideRight.Control = pnlOwner AnchorSideRight.Side = asrBottom Left = 110 Height = 29 Top = 6 Width = 306 Anchors = [akTop, akLeft, akRight] AutoComplete = True AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchCaseSensitive, cbactSearchAscending] BorderSpacing.Top = 6 ItemHeight = 0 Sorted = True TabOrder = 0 end object cbxGroups: TComboBox AnchorSideTop.Control = cbxUsers AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlOwner AnchorSideRight.Side = asrBottom Left = 110 Height = 29 Top = 39 Width = 306 Anchors = [akTop, akLeft, akRight] AutoComplete = True AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchCaseSensitive, cbactSearchAscending] BorderSpacing.Top = 4 BorderSpacing.Bottom = 6 ItemHeight = 0 Sorted = True TabOrder = 1 end end object DividerBevel4: TDividerBevel AnchorSideLeft.Control = tsAttributes AnchorSideTop.Control = pnlOwner AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsAttributes AnchorSideRight.Side = asrBottom Left = 10 Height = 17 Top = 350 Width = 416 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Top = 2 BorderSpacing.Right = 8 Font.Style = [fsBold] ParentFont = False Style = gsHorLines end object chkRecursive: TCheckBox AnchorSideLeft.Control = tsAttributes AnchorSideTop.Control = DividerBevel4 AnchorSideTop.Side = asrBottom Left = 10 Height = 22 Top = 367 Width = 78 Caption = '&Recursive' TabOrder = 15 end end object tsPlugins: TTabSheet Caption = 'Plugins' ClientHeight = 397 ClientWidth = 436 TabVisible = False object sgPlugins: TStringGrid Left = 0 Height = 397 Top = 0 Width = 436 Align = alClient AutoEdit = False AutoFillColumns = True BorderStyle = bsNone ColCount = 2 Columns = < item ReadOnly = True SizePriority = 0 Title.Caption = 'Name' Width = 218 end item Title.Caption = 'Value' Width = 218 end> FixedCols = 0 MouseWheelOption = mwGrid Options = [goSmoothScroll, goCellHints, goTruncCellHints, goCellEllipsis] ParentShowHint = False ShowHint = True TabOrder = 0 TitleStyle = tsNative ColWidths = ( 218 218 ) end end end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = Owner AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 8 Height = 29 Top = 446 Width = 442 Align = alNone Anchors = [akLeft, akRight, akBottom] OKButton.Name = 'OKButton' OKButton.DefaultCaption = True OKButton.OnClick = OKButtonClick HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True Color = clForm ButtonOrder = boCloseOKCancel TabOrder = 1 ShowButtons = [pbOK, pbCancel] ShowBevel = False end object tmUpdateFolderSize: TTimer Enabled = False Interval = 500 OnTimer = tmUpdateFolderSizeTimer Left = 360 Top = 88 end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileproperties.lrj������������������������������������������������������������0000644�0001750�0000144�00000012274�14743153644�017316� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":114087587,"name":"tfrmfileproperties.caption","sourcebytes":[80,114,111,112,101,114,116,105,101,115],"value":"Properties"}, {"hash":114087587,"name":"tfrmfileproperties.tsproperties.caption","sourcebytes":[80,114,111,112,101,114,116,105,101,115],"value":"Properties"}, {"hash":17199,"name":"tfrmfileproperties.lblfilename.caption","sourcebytes":[63,63,63],"value":"???"}, {"hash":5671610,"name":"tfrmfileproperties.lblfolderstr.caption","sourcebytes":[80,97,116,104,58],"value":"Path:"}, {"hash":6030986,"name":"tfrmfileproperties.lbltypestr.caption","sourcebytes":[84,121,112,101,58],"value":"Type:"}, {"hash":53066874,"name":"tfrmfileproperties.lblmediatypestr.caption","sourcebytes":[77,101,100,105,97,32,116,121,112,101,58],"value":"Media type:"}, {"hash":1474330,"name":"tfrmfileproperties.lblsymlinkstr.caption","sourcebytes":[83,121,109,108,105,110,107,32,116,111,58],"value":"Symlink to:"}, {"hash":5902474,"name":"tfrmfileproperties.lblsizestr.caption","sourcebytes":[83,105,122,101,58],"value":"Size:"}, {"hash":175865594,"name":"tfrmfileproperties.lblsizeondiskstr.caption","sourcebytes":[83,105,122,101,32,111,110,32,100,105,115,107,58],"value":"Size on disk:"}, {"hash":94883594,"name":"tfrmfileproperties.lblcontainsstr.caption","sourcebytes":[67,111,110,116,97,105,110,115,58],"value":"Contains:"}, {"hash":87052906,"name":"tfrmfileproperties.lbllinksstr.caption","sourcebytes":[76,105,110,107,115,58],"value":"Links:"}, {"hash":146321370,"name":"tfrmfileproperties.lblcreatedstr.caption","sourcebytes":[67,114,101,97,116,101,100,58],"value":"Created:"}, {"hash":184332074,"name":"tfrmfileproperties.lbllastmodifstr.caption","sourcebytes":[77,111,100,105,102,105,101,100,58],"value":"Modified:"}, {"hash":164289770,"name":"tfrmfileproperties.lbllastaccessstr.caption","sourcebytes":[65,99,99,101,115,115,101,100,58],"value":"Accessed:"}, {"hash":114874186,"name":"tfrmfileproperties.lbllaststchangestr.caption","sourcebytes":[83,116,97,116,117,115,32,99,104,97,110,103,101,100,58],"value":"Status changed:"}, {"hash":150815091,"name":"tfrmfileproperties.tsattributes.caption","sourcebytes":[65,116,116,114,105,98,117,116,101,115],"value":"Attributes"}, {"hash":41356085,"name":"tfrmfileproperties.lblfilestr.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":41356085,"name":"tfrmfileproperties.lblfile.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":5694658,"name":"tfrmfileproperties.lblattrownerstr.caption","sourcebytes":[79,119,110,101,114],"value":"Owner"}, {"hash":6197413,"name":"tfrmfileproperties.lblwrite.caption","sourcebytes":[87,114,105,116,101],"value":"Write"}, {"hash":363380,"name":"tfrmfileproperties.lblread.caption","sourcebytes":[82,101,97,100],"value":"Read"}, {"hash":216771813,"name":"tfrmfileproperties.lblexec.caption","sourcebytes":[69,120,101,99,117,116,101],"value":"Execute"}, {"hash":5150400,"name":"tfrmfileproperties.lblattrgroupstr.caption","sourcebytes":[71,114,111,117,112],"value":"Group"}, {"hash":5680834,"name":"tfrmfileproperties.lblattrotherstr.caption","sourcebytes":[79,116,104,101,114],"value":"Other"}, {"hash":5951354,"name":"tfrmfileproperties.lblattrtextstr.caption","sourcebytes":[84,101,120,116,58],"value":"Text:"}, {"hash":265289741,"name":"tfrmfileproperties.lblattrtext.caption","sourcebytes":[45,45,45,45,45,45,45,45,45,45,45],"value":"-----------"}, {"hash":4787050,"name":"tfrmfileproperties.lblattrbitsstr.caption","sourcebytes":[66,105,116,115,58],"value":"Bits:"}, {"hash":89827322,"name":"tfrmfileproperties.lbloctal.caption","sourcebytes":[79,99,116,97,108,58],"value":"Octal:"}, {"hash":362964,"name":"tfrmfileproperties.cbsuid.caption","sourcebytes":[83,85,73,68],"value":"SUID"}, {"hash":359380,"name":"tfrmfileproperties.cbsgid.caption","sourcebytes":[83,71,73,68],"value":"SGID"}, {"hash":95091241,"name":"tfrmfileproperties.cbsticky.caption","sourcebytes":[83,116,105,99,107,121],"value":"Sticky"}, {"hash":74922797,"name":"tfrmfileproperties.chkexecutable.caption","sourcebytes":[65,108,108,111,119,32,38,101,120,101,99,117,116,105,110,103,32,102,105,108,101,32,97,115,32,112,114,111,103,114,97,109],"value":"Allow &executing file as program"}, {"hash":247123530,"name":"tfrmfileproperties.lblexecutable.caption","sourcebytes":[69,120,101,99,117,116,101,58],"value":"Execute:"}, {"hash":5694658,"name":"tfrmfileproperties.dividerbevel3.caption","sourcebytes":[79,119,110,101,114],"value":"Owner"}, {"hash":85845186,"name":"tfrmfileproperties.lblownerstr.caption","sourcebytes":[79,38,119,110,101,114],"value":"O&wner"}, {"hash":44996288,"name":"tfrmfileproperties.lblgroupstr.caption","sourcebytes":[38,71,114,111,117,112],"value":"&Group"}, {"hash":181090421,"name":"tfrmfileproperties.chkrecursive.caption","sourcebytes":[38,82,101,99,117,114,115,105,118,101],"value":"&Recursive"}, {"hash":121364483,"name":"tfrmfileproperties.tsplugins.caption","sourcebytes":[80,108,117,103,105,110,115],"value":"Plugins"}, {"hash":346165,"name":"tfrmfileproperties.sgplugins.columns[0].title.caption","sourcebytes":[78,97,109,101],"value":"Name"}, {"hash":6063029,"name":"tfrmfileproperties.sgplugins.columns[1].title.caption","sourcebytes":[86,97,108,117,101],"value":"Value"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileproperties.pas������������������������������������������������������������0000644�0001750�0000144�00000067724�14743153644�017324� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------- File Properties Dialog Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz) Copyright (C) 2003 Martin Matusu <xmat@volny.cz> Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fFileProperties; {$mode objfpc}{$H+} interface uses LResources, SysUtils, Classes, Graphics, Forms, StdCtrls, Buttons, ComCtrls, Dialogs, Controls, ExtCtrls, Grids, ButtonPanel, DividerBevel, KASCDEdit, DCBasicTypes, uFile, uFileProperty, uFileSource, uFileSourceOperation, uFileSourceCalcStatisticsOperation, uFileSourceSetFilePropertyOperation, DCOSUtils; type { TfrmFileProperties } TfrmFileProperties = class(TForm) ButtonPanel: TButtonPanel; cbExecGroup: TCheckBox; cbExecOther: TCheckBox; cbExecOwner: TCheckBox; cbReadGroup: TCheckBox; cbReadOther: TCheckBox; cbReadOwner: TCheckBox; cbSgid: TCheckBox; cbSticky: TCheckBox; cbSuid: TCheckBox; cbWriteGroup: TCheckBox; cbWriteOther: TCheckBox; cbWriteOwner: TCheckBox; cbxGroups: TComboBox; cbxUsers: TComboBox; chkExecutable: TCheckBox; chkRecursive: TCheckBox; DividerBevel1: TDividerBevel; DividerBevel2: TDividerBevel; DividerBevel3: TDividerBevel; DividerBevel4: TDividerBevel; edtOctal: TEdit; lblExecutable: TLabel; lblFileName: TLabel; imgFileIcon: TImage; lblFolder: TKASCDEdit; lblFolderStr: TLabel; lblGroupStr: TLabel; lblLastAccess: TKASCDEdit; lblLastAccessStr: TLabel; lblLastModif: TKASCDEdit; lblLastModifStr: TLabel; lblLastStChange: TKASCDEdit; lblLastStChangeStr: TLabel; lblCreated: TKASCDEdit; lblCreatedStr: TLabel; lblOctal: TLabel; lblAttrBitsStr: TLabel; lblAttrText: TLabel; lblExec: TLabel; lblFileStr: TLabel; lblFile: TLabel; lblAttrGroupStr: TLabel; lblAttrOtherStr: TLabel; lblAttrOwnerStr: TLabel; lblOwnerStr: TLabel; lblRead: TLabel; lblSize: TKASCDEdit; lblSizeOnDisk: TKASCDEdit; lblContains: TKASCDEdit; lblSizeStr: TLabel; lblSizeOnDiskStr: TLabel; lblContainsStr: TLabel; lblSymlink: TKASCDEdit; lblAttrTextStr: TLabel; lblSymlinkStr: TLabel; lblMediaType: TKASCDEdit; lblMediaTypeStr: TLabel; lblType: TKASCDEdit; lblTypeStr: TLabel; lblLinks: TKASCDEdit; lblLinksStr: TLabel; lblWrite: TLabel; pnlOwner: TPanel; pnlCaption: TPanel; pnlData: TPanel; pnlIcon: TPanel; pcPageControl: TPageControl; sgPlugins: TStringGrid; tsPlugins: TTabSheet; tmUpdateFolderSize: TTimer; tsProperties: TTabSheet; tsAttributes: TTabSheet; procedure cbChangeModeClick(Sender: TObject); procedure chkExecutableChange(Sender: TObject); procedure edtOctalKeyPress(Sender: TObject; var Key: char); procedure edtOctalKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormCreate(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure OKButtonClick(Sender: TObject); procedure tmUpdateFolderSizeTimer(Sender: TObject); procedure FileSourceOperationStateChangedNotify(Operation: TFileSourceOperation; State: TFileSourceOperationState); private bPerm: Boolean; FFileSource: IFileSource; FFiles: TFiles; FPropertyFormatter: IFilePropertyFormatter; FFileSourceCalcStatisticsOperation: TFileSourceCalcStatisticsOperation; FChangeTriggersEnabled: Boolean; FFileAttr: TFileAttributeData; FFileType, OriginalAttr: TFileAttrs; OriginalUser, OriginalGroup: String; FOperation: TFileSourceSetFilePropertyOperation; procedure ShowType(Attrs: TFileAttrs); procedure ShowExecutable; procedure ShowPermissions(Mode: TFileAttrs); function GetModeFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs; function FormatSize(ASize: Int64): String; procedure ShowMany; procedure ShowFile(iIndex:Integer); procedure StartCalcFolderSize; procedure StopCalcFolderSize; procedure ShowPlugin(iIndex:Integer); procedure UpdateAllowGrayed(AllowGrayed: Boolean); function FormatUnixAttributesEx(iAttr: TFileAttrs): String; public constructor Create(AOwner: TComponent; aFileSource: IFileSource; theFiles: TFiles); reintroduce; destructor Destroy; override; end; procedure ShowFileProperties(aFileSource: IFileSource; const aFiles: TFiles); implementation {$R *.lfm} uses LCLType, LazUTF8, uLng, BaseUnix, uUsersGroups, uDCUtils, uDefaultFilePropertyFormatter, uMyUnix, DCFileAttributes, uGlobs, uWdxModule, uFileSourceOperationTypes, uFileSystemFileSource, uOperationsManager, WdxPlugin, uFileSourceOperationOptions, uKeyboard, DCStrUtils, uPixMapManager, uFileSourceProperty, DCDateTimeUtils, uTypes; procedure ShowFileProperties(aFileSource: IFileSource; const aFiles: TFiles); begin if aFiles.Count > 0 then begin with TfrmFileProperties.Create(Application, aFileSource, aFiles) do try ShowModal; finally Free; end; end; end; constructor TfrmFileProperties.Create(AOwner: TComponent; aFileSource: IFileSource; theFiles: TFiles); var ASize: Integer; AFiles: TFiles; HasAttr: Boolean; ActiveFile: TFile; aFileProperties: TFileProperties; begin FFiles := theFiles.Clone; FFileSource:= aFileSource; FChangeTriggersEnabled := True; FPropertyFormatter := MaxDetailsFilePropertyFormatter; ActiveFile:= FFiles[0]; HasAttr:= (fspDirectAccess in aFileSource.Properties) and (mbFileGetAttr(ActiveFile.FullPath, FFileAttr)); if HasAttr then begin {$IFDEF UNIX} if not (fpOwner in ActiveFile.SupportedProperties) then begin ActiveFile.Properties[fpOwner]:= TFileOwnerProperty.Create; end; ActiveFile.OwnerProperty.Group:= FFileAttr.FindData.st_gid; ActiveFile.OwnerProperty.Owner:= FFileAttr.FindData.st_uid; {$ENDIF} if fpModificationTime in ActiveFile.SupportedProperties then ActiveFile.ModificationTime:= FileTimeToDateTime(DCBasicTypes.TFileTime(FFileAttr.LastWriteTime)); if fpChangeTime in ActiveFile.SupportedProperties then ActiveFile.ChangeTime:= FileTimeToDateTime(DCBasicTypes.TFileTime(FFileAttr.PlatformTime)); if fpLastAccessTime in ActiveFile.SupportedProperties then ActiveFile.LastAccessTime:= FileTimeToDateTime(DCBasicTypes.TFileTime(FFileAttr.LastAccessTime)); end; if (fsoSetFileProperty in aFileSource.GetOperationsTypes) then begin AFiles:= FFiles.Clone; FillByte(aFileProperties, SizeOf(aFileProperties), 0); if fpAttributes in ActiveFile.SupportedProperties then aFileProperties[fpAttributes]:= ActiveFile.Properties[fpAttributes].Clone; if fpOwner in ActiveFile.SupportedProperties then aFileProperties[fpOwner]:= ActiveFile.Properties[fpOwner].Clone; FOperation:= aFileSource.CreateSetFilePropertyOperation(AFiles, aFileProperties) as TFileSourceSetFilePropertyOperation; end; inherited Create(AOwner); tsProperties.AutoSize:= True; tsAttributes.AutoSize:= True; // Enable only supported file properties if Assigned(FOperation) then begin if fpAttributes in FOperation.SupportedProperties then begin UpdateAllowGrayed((FFiles.Count > 1) or FFiles[0].IsDirectory); end; end; ASize:= gIconsSize * Round( Application.MainForm.GetCanvasScaleFactor ); if ASize > 48 then ASize:= 48; imgFileIcon.Width:= ASize; imgFileIcon.Height:= ASize; pnlOwner.Enabled:= Assigned(FOperation) and (fpOwner in FOperation.SupportedProperties); tsAttributes.Enabled:= Assigned(FOperation) and (fpAttributes in FOperation.SupportedProperties); end; destructor TfrmFileProperties.Destroy; begin FFiles.Free; StopCalcFolderSize; FreeAndNil( FOperation ); inherited Destroy; FPropertyFormatter := nil; // free interface end; function TfrmFileProperties.GetModeFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs; begin Result:= 0; ExcludeAttrs:= 0; case cbReadOwner.State of cbChecked: Result:= (Result or S_IRUSR); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IRUSR; end; case cbWriteOwner.State of cbChecked: Result:= (Result or S_IWUSR); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWUSR; end; case cbExecOwner.State of cbChecked: Result:= (Result or S_IXUSR); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXUSR; end; case cbReadGroup.State of cbChecked: Result:= (Result or S_IRGRP); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IRGRP; end; case cbWriteGroup.State of cbChecked: Result:= (Result or S_IWGRP); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWGRP; end; case cbExecGroup.State of cbChecked: Result:= (Result or S_IXGRP); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXGRP; end; case cbReadOther.State of cbChecked: Result:= (Result or S_IROTH); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IROTH; end; case cbWriteOther.State of cbChecked: Result:= (Result or S_IWOTH); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWOTH; end; case cbExecOther.State of cbChecked: Result:= (Result or S_IXOTH); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXOTH; end; case cbSuid.State of cbChecked: Result:= (Result or S_ISUID); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISUID; end; case cbSgid.State of cbChecked: Result:= (Result or S_ISGID); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISGID; end; case cbSticky.State of cbChecked: Result:= (Result or S_ISVTX); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISVTX; end; end; function TfrmFileProperties.FormatSize(ASize: Int64): String; begin if (ASize < 0) then Result:= '???' else if gFileSizeFormat in [fsfByte, fsfPersonalizedByte] then Result:= cnvFormatFileSize(ASize) else begin Result:= Format('%s (%s)', [cnvFormatFileSize(ASize), IntToStrTS(ASize)]); end; end; procedure TfrmFileProperties.ShowMany; var ASize: Int64; AFile: TFile; Index: Integer; ABitmap: TBitmap; UserID: Cardinal; Files, Directories: Integer; begin ASize := 0; Files := 0; Directories := 0; ABitmap := PixMapManager.GetThemeIcon('edit-copy', gIconsSize); if Assigned(ABitmap) then begin imgFileIcon.Picture.Bitmap := ABitmap; ABitmap.Free; end; for Index:= 0 to FFiles.Count - 1 do begin AFile:= FFiles[Index]; if AFile.IsDirectory then Inc(Directories) else begin Inc(Files); Inc(ASize, AFile.Size); end; end; chkRecursive.Visible:= (Directories > 0); DividerBevel4.Visible:= chkRecursive.Visible; if (Directories = 0) then begin lblSize.Caption := FormatSize(ASize); end else if (fsoCalcStatistics in FFileSource.GetOperationsTypes) then begin StartCalcFolderSize // Start calculate folder size operation end; // Chown if Assigned(FOperation.NewProperties[fpOwner]) then begin OriginalUser := '*'; OriginalGroup := '*'; // Get current user ID UserID := fpGetUID; // Only owner or root can change owner bPerm := (UserID = FFileAttr.FindData.st_uid) or (UserID = 0); // Owner combo box cbxUsers.Text := OriginalUser; // Only root can change owner cbxUsers.Enabled := (UserID = 0); if cbxUsers.Enabled then begin GetUsers(cbxUsers.Items); cbxUsers.Sorted:= False; cbxUsers.Items.Insert(0, '*'); end; // Group combo box cbxGroups.Text := OriginalGroup; cbxGroups.Enabled := bPerm; if bPerm then begin GetUsrGroups(UserID, cbxGroups.Items); cbxGroups.Sorted:= False; cbxGroups.Items.Insert(0, '*'); end; end; lblFile.Caption := Format(rsPropsContains, [Files, Directories]); lblFileName.Caption := lblFile.Caption; lblContains.Visible:= (Directories > 0); lblContainsStr.Visible:= (Directories > 0); lblMediaType.Visible:= False; lblMediaTypeStr.Visible:= False; lblSizeOnDisk.Visible:= False; lblSizeOnDiskStr.Visible:= False; lblSymlink.Visible:= False; lblSymlinkStr.Visible:= False; lblLinks.Visible:= False; lblLinksStr.Visible:= False; lblLastAccess.Visible:= False; lblLastAccessStr.Visible:= False; lblLastModif.Visible:= False; lblLastModifStr.Visible:= False; lblLastStChange.Visible:= False; lblLastStChangeStr.Visible:= False; lblCreated.Visible := False; lblCreatedStr.Visible := False; lblFolder.Caption:= FFiles.Path; lblExecutable.Visible:= False; chkExecutable.Visible:= False; FFileType:= FFiles[0].Attributes and S_IFMT; for Index:= 1 to FFiles.Count - 1 do begin if (FFileType <> (FFiles[Index].Attributes and S_IFMT)) then begin lblType.Caption:= rsPropsMultipleTypes; Exit; end; end; ShowType(FFileType); end; procedure TfrmFileProperties.cbChangeModeClick(Sender: TObject); var AMode, ExcludeAttrs: TFileAttrs; CheckBox: TCheckBox absolute Sender; begin if fsCreating in FormState then exit; if FChangeTriggersEnabled then begin FChangeTriggersEnabled := False; if CheckBox.State = cbGrayed then begin edtOctal.Text:= EmptyStr; lblAttrText.Caption:= EmptyStr; end else begin AMode:= GetModeFromForm(ExcludeAttrs); edtOctal.Text:= DecToOct(AMode); lblAttrText.Caption:= FormatUnixAttributesEx(AMode); end; FChangeTriggersEnabled := True; end; end; procedure TfrmFileProperties.chkExecutableChange(Sender: TObject); begin if chkExecutable.Tag = 0 then begin chkExecutable.Tag:= 1; case chkExecutable.State of cbChecked, cbUnchecked: begin cbExecOwner.Checked:= chkExecutable.Checked; cbExecGroup.Checked:= chkExecutable.Checked; cbExecOther.Checked:= chkExecutable.Checked; end; cbGrayed: begin cbExecOwner.Checked:= ((OriginalAttr and S_IXUSR) = S_IXUSR); cbExecGroup.Checked:= ((OriginalAttr and S_IXGRP) = S_IXGRP); cbExecOther.Checked:= ((OriginalAttr and S_IXOTH) = S_IXOTH); end; end; chkExecutable.Tag:= 0; end; end; procedure TfrmFileProperties.edtOctalKeyPress(Sender: TObject; var Key: char); begin if not ((Key in ['0'..'7']) or (Key = Chr(VK_BACK)) or (Key = Chr(VK_DELETE))) then Key:= #0; end; procedure TfrmFileProperties.edtOctalKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); var AMode: TFileAttrs; begin if FChangeTriggersEnabled then begin FChangeTriggersEnabled := False; AMode:= OctToDec(edtOctal.Text); lblAttrText.Caption := FormatUnixAttributesEx(AMode); ShowPermissions(AMode); FChangeTriggersEnabled := True; end; end; procedure TfrmFileProperties.ShowPermissions(Mode: TFileAttrs); begin cbReadOwner.Checked:= ((Mode AND S_IRUSR) = S_IRUSR); cbWriteOwner.Checked:= ((Mode AND S_IWUSR) = S_IWUSR); cbExecOwner.Checked:= ((Mode AND S_IXUSR) = S_IXUSR); cbReadGroup.Checked:= ((Mode AND S_IRGRP) = S_IRGRP); cbWriteGroup.Checked:= ((Mode AND S_IWGRP) = S_IWGRP); cbExecGroup.Checked:= ((Mode AND S_IXGRP) = S_IXGRP); cbReadOther.Checked:= ((Mode AND S_IROTH) = S_IROTH); cbWriteOther.Checked:= ((Mode AND S_IWOTH) = S_IWOTH); cbExecOther.Checked:= ((Mode AND S_IXOTH) = S_IXOTH); cbSuid.Checked:= ((Mode AND S_ISUID) = S_ISUID); cbSgid.Checked:= ((Mode AND S_ISGID) = S_ISGID); cbSticky.Checked:= ((Mode AND S_ISVTX) = S_ISVTX); ShowExecutable; end; procedure TfrmFileProperties.ShowFile(iIndex:Integer); var Idx: PtrInt; ASize: Int64; UserID: Cardinal; hasSize: Boolean; ABitmap: TBitmap; Attrs: TFileAttrs; AMimeType: String; isFileSystem: Boolean; begin isFileSystem := FFileSource.IsClass(TFileSystemFileSource); Idx := PixMapManager.GetIconByFile(FFiles[iIndex], isFileSystem, True, sim_all_and_exe, True); if Idx < 0 then Idx:= PixMapManager.GetDefaultIcon(FFiles[iIndex]); ABitmap:= PixMapManager.GetBitmap(Idx); imgFileIcon.Picture.Bitmap := ABitmap; ABitmap.Free; with FFiles[iIndex] do begin lblFileName.Caption:= Name; lblFile.Caption:= Name; lblFolder.Caption:= Path; if not (fpCreationTime in SupportedProperties) then begin if fpCreationTime in FFileSource.RetrievableFileProperties then begin FFileSource.RetrieveProperties(FFiles[iIndex], [fpCreationTime], []); end; end; // Size hasSize := (fpSize in SupportedProperties) and (not IsLinkToDirectory); if hasSize then begin if IsDirectory and (fsoCalcStatistics in FFileSource.GetOperationsTypes) then StartCalcFolderSize // Start calculate folder size operation else lblSize.Caption := FormatSize(Size); end; lblSize.Visible := hasSize; lblSizeStr.Visible := hasSize; lblContains.Visible:= IsDirectory; lblContainsStr.Visible:= IsDirectory; // Size on disk hasSize:= (fpAttributes in SupportedProperties) and (FPS_ISREG(Attributes)) and (FFileAttr.FindData.st_ino <> 0); if hasSize then begin ASize:= FFileAttr.FindData.st_blocks * 512; lblSizeOnDisk.Caption:= FormatSize(ASize); end; lblSizeOnDisk.Visible:= hasSize; lblSizeOnDiskStr.Visible:= hasSize; // Links lblLinks.Visible:= isFileSystem and (FPS_ISREG(Attributes)) and (FFileAttr.FindData.st_nlink > 1); if lblLinks.Visible then lblLinks.Caption:= IntToStrTS(FFileAttr.FindData.st_nlink); lblLinksStr.Visible:= lblLinks.Visible; // Times lblLastAccess.Visible := fpLastAccessTime in SupportedProperties; lblLastAccessStr.Visible := fpLastAccessTime in SupportedProperties; if fpLastAccessTime in SupportedProperties then lblLastAccess.Caption := Properties[fpLastAccessTime].Format(FPropertyFormatter) else lblLastAccess.Caption := ''; lblLastStChange.Visible := fpChangeTime in SupportedProperties; lblLastStChangeStr.Visible := fpChangeTime in SupportedProperties; if fpChangeTime in SupportedProperties then lblLastStChange.Caption := Properties[fpChangeTime].Format(FPropertyFormatter) else lblLastStChange.Caption := ''; lblLastModif.Visible := fpModificationTime in SupportedProperties; lblLastModifStr.Visible := fpModificationTime in SupportedProperties; if fpModificationTime in SupportedProperties then lblLastModif.Caption := Properties[fpModificationTime].Format(FPropertyFormatter) else lblLastModif.Caption := ''; lblCreated.Visible := fpCreationTime in SupportedProperties; lblCreatedStr.Visible := fpCreationTime in SupportedProperties; if fpCreationTime in SupportedProperties then lblCreated.Caption := Properties[fpCreationTime].Format(FPropertyFormatter) else lblCreated.Caption := ''; // Chown if fpOwner in SupportedProperties then begin OriginalUser := UIDToStr(OwnerProperty.Owner); OriginalGroup := GIDToStr(OwnerProperty.Group); // Get current user ID UserID := fpGetUID; // Only owner or root can change owner bPerm := (UserID = OwnerProperty.Owner) or (UserID = 0); // Owner combo box cbxUsers.Text := OriginalUser; // Only root can change owner cbxUsers.Enabled := (UserID = 0); if cbxUsers.Enabled then GetUsers(cbxUsers.Items); // Group combo box cbxGroups.Text := OriginalGroup; cbxGroups.Enabled := bPerm; if bPerm then GetUsrGroups(UserID, cbxGroups.Items); end; // MIME type hasSize:= isFileSystem; if hasSize then begin AMimeType:= GetFileMimeType(FullPath); hasSize:= Length(AMimeType) > 0; lblMediaType.Caption:= AMimeType; end; lblMediaType.Visible:= hasSize; lblMediaTypeStr.Visible:= hasSize; // Attributes if fpAttributes in SupportedProperties then begin Attrs := AttributesProperty.Value; FFileType:= Attrs and S_IFMT; OriginalAttr := Attrs and $0FFF; ShowPermissions(Attrs); lblExecutable.Visible:= FPS_ISREG(Attrs); chkExecutable.Visible:= lblExecutable.Visible; lblAttrText.Caption := Properties[fpAttributes].Format(DefaultFilePropertyFormatter); ShowType(Attrs); chkRecursive.Visible := IsDirectory; DividerBevel4.Visible:= chkRecursive.Visible; lblSymlink.Visible := FPS_ISLNK(Attrs); lblSymlinkStr.Visible := lblSymlink.Visible; if lblSymlink.Visible then begin if isFileSystem then lblSymlink.Caption := ReadSymLink(FullPath) else if (Assigned(LinkProperty) and LinkProperty.IsValid) then lblSymlink.Caption := LinkProperty.LinkTo else begin lblSymlink.Visible := False; lblSymlinkStr.Visible := False; end; end; end else begin chkRecursive.Visible:= False; DividerBevel4.Visible:= False; edtOctal.Text:= rsMsgErrNotSupported; lblAttrText.Caption:= rsMsgErrNotSupported; lblType.Caption:= rsPropsUnknownType; lblSymlink.Caption:= ''; end; end; tsPlugins.Visible:= isFileSystem; if isFileSystem then ShowPlugin(iIndex); end; procedure TfrmFileProperties.FormCreate(Sender: TObject); begin InitPropStorage(Self); if (FFiles.Count = 1) then ShowFile(0) else begin ShowMany; end; end; procedure TfrmFileProperties.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of VK_TAB: begin if Shift * KeyModifiersShortcut = [ssCtrl] then begin pcPageControl.SelectNextPage(True); Key := 0; end else if Shift * KeyModifiersShortcut = [ssCtrl, ssShift] then begin pcPageControl.SelectNextPage(False); Key := 0; end; end; end; end; procedure TfrmFileProperties.OKButtonClick(Sender: TObject); var theNewProperties: TFileProperties; begin if Assigned(FOperation) then begin with FOperation do begin theNewProperties:= NewProperties; if fpAttributes in SupportedProperties then begin if theNewProperties[fpAttributes] is TUnixFileAttributesProperty then IncludeAttributes:= GetModeFromForm(ExcludeAttributes); // Nothing changed, clear new property if (IncludeAttributes = 0) and (ExcludeAttributes = 0) then begin theNewProperties[fpAttributes].Free; theNewProperties[fpAttributes]:= nil; end; end; if fpOwner in SupportedProperties then begin if (OriginalUser <> cbxUsers.Text) or (OriginalGroup <> cbxGroups.Text) then begin TFileOwnerProperty(theNewProperties[fpOwner]).Owner:= StrToUID(cbxUsers.Text); TFileOwnerProperty(theNewProperties[fpOwner]).Group:= StrToGID(cbxGroups.Text); end // Nothing changed, clear new property else begin theNewProperties[fpOwner].Free; theNewProperties[fpOwner]:= nil; end; end; NewProperties:= theNewProperties; Recursive:= chkRecursive.Checked; end; OperationsManager.AddOperation(FOperation); FOperation:= nil; end; end; procedure TfrmFileProperties.tmUpdateFolderSizeTimer(Sender: TObject); begin if Assigned(FFileSourceCalcStatisticsOperation) then with FFileSourceCalcStatisticsOperation.RetrieveStatistics do begin lblSize.Caption := FormatSize(Size); lblContains.Caption := Format(rsPropsContains, [Files, Directories]); end; end; procedure TfrmFileProperties.FileSourceOperationStateChangedNotify( Operation: TFileSourceOperation; State: TFileSourceOperationState); begin if Assigned(FFileSourceCalcStatisticsOperation) and (State = fsosStopped) then begin tmUpdateFolderSize.Enabled:= False; tmUpdateFolderSizeTimer(tmUpdateFolderSize); FFileSourceCalcStatisticsOperation := nil; end; end; procedure TfrmFileProperties.ShowType(Attrs: TFileAttrs); begin if FPS_ISDIR(Attrs) then lblType.Caption:= rsPropsFolder {$IFDEF UNIX} else if FPS_ISREG(Attrs) then lblType.Caption:= rsPropsFile else if FPS_ISCHR(Attrs) then lblType.Caption:= rsPropsSpChrDev else if FPS_ISBLK(Attrs) then lblType.Caption:= rsPropsSpBlkDev else if FPS_ISFIFO(Attrs) then lblType.Caption:= rsPropsNmdPipe else if FPS_ISLNK(Attrs) then lblType.Caption:= rsPropsSymLink else if FPS_ISSOCK(Attrs) then lblType.Caption:= rsPropsSocket {$ENDIF} else lblType.Caption:= rsPropsUnknownType; end; procedure TfrmFileProperties.ShowExecutable; begin if chkExecutable.Tag = 0 then begin if cbExecOwner.Checked and cbExecGroup.Checked and cbExecOther.Checked then chkExecutable.State:= cbChecked else if not (cbExecOwner.Checked or cbExecGroup.Checked or cbExecOther.Checked) then chkExecutable.State:= cbUnchecked else begin chkExecutable.AllowGrayed:= True; chkExecutable.State:= cbGrayed; end; end; end; procedure TfrmFileProperties.StartCalcFolderSize; var aFiles: TFiles; begin aFiles:= FFiles.Clone; try FFileSourceCalcStatisticsOperation:= FFileSource.CreateCalcStatisticsOperation(aFiles) as TFileSourceCalcStatisticsOperation; if Assigned(FFileSourceCalcStatisticsOperation) then begin FFileSourceCalcStatisticsOperation.SkipErrors:= True; FFileSourceCalcStatisticsOperation.SymLinkOption:= fsooslDontFollow; FFileSourceCalcStatisticsOperation.AddStateChangedListener([fsosStopped], @FileSourceOperationStateChangedNotify); OperationsManager.AddOperation(FFileSourceCalcStatisticsOperation, False); tmUpdateFolderSize.Enabled:= True; end; finally aFiles.Free; end; end; procedure TfrmFileProperties.StopCalcFolderSize; begin if Assigned(FFileSourceCalcStatisticsOperation) then begin tmUpdateFolderSize.Enabled:= False; FFileSourceCalcStatisticsOperation.Stop; end; FFileSourceCalcStatisticsOperation:= nil; end; procedure TfrmFileProperties.ShowPlugin(iIndex: Integer); var I, J: Integer; Value: String; Index: Integer; FileName: String; WdxModule: TWdxModule; begin FileName:= FFiles[iIndex].FullPath; Value:= LowerCase(FFiles[iIndex].Extension); for Index:= 0 to gWdxPlugins.Count - 1 do begin WdxModule:= gWdxPlugins.GetWdxModule(Index); if (Length(WdxModule.DetectStr) > 0) and WdxModule.FileParamVSDetectStr(FFiles[iIndex]) then begin if not gWdxPlugins.IsLoaded(Index) then begin if not gWdxPlugins.LoadModule(Index) then Continue; end; J:= 0; sgPlugins.RowCount:= WdxModule.FieldList.Count + 1; for I:= 0 to WdxModule.FieldList.Count - 1 do begin if not (TWdxField(WdxModule.FieldList.Objects[I]).FType in [ft_fulltext, ft_fulltextw]) then begin Value:= WdxModule.CallContentGetValue(FileName, I, 0, CONTENT_DELAYIFSLOW); if (Length(Value) > 0) then begin Inc(J); sgPlugins.Cells[1, J]:= Value; sgPlugins.Cells[0, J]:= TWdxField(WdxModule.FieldList.Objects[I]).LName; end; end; end; sgPlugins.RowCount:= J + 1; tsPlugins.TabVisible:= J > 0; if tsPlugins.TabVisible then Break; end; end; end; procedure TfrmFileProperties.UpdateAllowGrayed(AllowGrayed: Boolean); var Index: Integer; begin for Index:= 0 to tsAttributes.ControlCount - 1 do begin if tsAttributes.Controls[Index] is TCheckBox then TCheckBox(tsAttributes.Controls[Index]).AllowGrayed:= AllowGrayed; end; end; function TfrmFileProperties.FormatUnixAttributesEx(iAttr: TFileAttrs): String; begin if (FFiles.Count = 1) then Result:= FormatUnixAttributes(FFileType or iAttr) else begin Result:= Copy(FormatUnixAttributes(iAttr), 2, MaxInt); end; end; end. ��������������������������������������������doublecmd-1.1.22/src/ffileunlock.lfm����������������������������������������������������������������0000644�0001750�0000144�00000005665�14743153644�016412� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFileUnlock: TfrmFileUnlock Left = 326 Height = 342 Top = 203 Width = 638 BorderIcons = [biSystemMenu, biMaximize] Caption = 'Unlock' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ClientHeight = 342 ClientWidth = 638 Constraints.MinWidth = 600 DesignTimePPI = 120 OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '1.8.4.0' object stgFileHandles: TStringGrid AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnClose Left = 12 Height = 276 Top = 12 Width = 614 Anchors = [akTop, akLeft, akRight, akBottom] AutoFillColumns = True BorderSpacing.Top = 12 BorderSpacing.Bottom = 12 ColCount = 3 Columns = < item SizePriority = 0 Title.Caption = 'File Handle' Width = 100 end item SizePriority = 0 Title.Caption = 'Process ID' Width = 100 end item Title.Caption = 'Executable Path' Width = 413 end> FixedCols = 0 Flat = True Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goRowSelect, goSmoothScroll] TabOrder = 0 OnDblClick = stgFileHandlesDblClick OnSelection = stgFileHandlesSelection ColWidths = ( 100 100 413 ) end object btnUnlockAll: TButton AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnClose AnchorSideBottom.Control = btnClose AnchorSideBottom.Side = asrBottom Left = 459 Height = 30 Top = 300 Width = 93 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.Right = 12 Caption = 'Unlock All' OnClick = btnUnlockAllClick TabOrder = 2 end object btnUnlock: TButton AnchorSideTop.Control = btnUnlockAll AnchorSideRight.Control = btnUnlockAll Left = 376 Height = 30 Top = 300 Width = 71 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 12 Caption = 'Unlock' OnClick = btnUnlockClick TabOrder = 1 end object btnClose: TButton AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 564 Height = 30 Top = 300 Width = 62 Anchors = [akRight, akBottom] AutoSize = True Caption = 'Close' ModalResult = 11 TabOrder = 3 end object btnTerminate: TButton AnchorSideLeft.Control = Owner AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 12 Height = 30 Top = 300 Width = 93 Anchors = [akLeft, akBottom] AutoSize = True Caption = 'Terminate' OnClick = btnTerminateClick TabOrder = 4 end end ���������������������������������������������������������������������������doublecmd-1.1.22/src/ffileunlock.lrj����������������������������������������������������������������0000644�0001750�0000144�00000002161�14743153644�016407� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":96810395,"name":"tfrmfileunlock.caption","sourcebytes":[85,110,108,111,99,107],"value":"Unlock"}, {"hash":78334293,"name":"tfrmfileunlock.stgfilehandles.columns[0].title.caption","sourcebytes":[70,105,108,101,32,72,97,110,100,108,101],"value":"File Handle"}, {"hash":164572548,"name":"tfrmfileunlock.stgfilehandles.columns[1].title.caption","sourcebytes":[80,114,111,99,101,115,115,32,73,68],"value":"Process ID"}, {"hash":165250008,"name":"tfrmfileunlock.stgfilehandles.columns[2].title.caption","sourcebytes":[69,120,101,99,117,116,97,98,108,101,32,80,97,116,104],"value":"Executable Path"}, {"hash":93881116,"name":"tfrmfileunlock.btnunlockall.caption","sourcebytes":[85,110,108,111,99,107,32,65,108,108],"value":"Unlock All"}, {"hash":96810395,"name":"tfrmfileunlock.btnunlock.caption","sourcebytes":[85,110,108,111,99,107],"value":"Unlock"}, {"hash":4863637,"name":"tfrmfileunlock.btnclose.caption","sourcebytes":[67,108,111,115,101],"value":"Close"}, {"hash":155193957,"name":"tfrmfileunlock.btnterminate.caption","sourcebytes":[84,101,114,109,105,110,97,116,101],"value":"Terminate"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffileunlock.pas����������������������������������������������������������������0000644�0001750�0000144�00000010750�14743153644�016406� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fFileUnlock; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Grids, uFileUnlock; type { TfrmFileUnlock } TfrmFileUnlock = class(TForm) btnUnlockAll: TButton; btnUnlock: TButton; btnClose: TButton; btnTerminate: TButton; stgFileHandles: TStringGrid; procedure btnTerminateClick(Sender: TObject); procedure btnUnlockAllClick(Sender: TObject); procedure btnUnlockClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure stgFileHandlesDblClick(Sender: TObject); procedure stgFileHandlesSelection(Sender: TObject; aCol, aRow: Integer); private procedure ShowThread; procedure UnlockRow(Index: Integer); public end; function ShowUnlockForm(ProcessInfo: TProcessInfoArray): Boolean; implementation {$R *.lfm} uses Windows, Math, LCLStrConsts, DCConvertEncoding, fMain, uMyWindows, uLng; function ShowUnlockForm(ProcessInfo: TProcessInfoArray): Boolean; var Index: Integer; UnlockEnabled: Boolean = False; begin with TfrmFileUnlock.Create(frmMain) do try stgFileHandles.RowCount:= Length(ProcessInfo) + 1; for Index:= 1 to stgFileHandles.RowCount - 1 do begin if (ProcessInfo[Index - 1].FileHandle <> 0) then begin UnlockEnabled:= True; stgFileHandles.Cells[0, Index]:= IntToStr(ProcessInfo[Index - 1].FileHandle); end; stgFileHandles.Cells[1, Index]:= IntToStr(ProcessInfo[Index - 1].ProcessId); stgFileHandles.Cells[2, Index]:= ProcessInfo[Index - 1].ExecutablePath; end; btnUnlockAll.Enabled:= UnlockEnabled; btnTerminate.Enabled:= Length(ProcessInfo) > 0; stgFileHandles.Row:= IfThen(UnlockEnabled, 1, 0); btnUnlock.Enabled:= UnlockEnabled and (Length(stgFileHandles.Cells[0, 1]) > 0); TThread.Synchronize(nil, @ShowThread); Result:= (ModalResult = mrOK); finally Free; end; end; { TfrmFileUnlock } procedure TfrmFileUnlock.stgFileHandlesSelection(Sender: TObject; aCol, aRow: Integer); begin btnUnlock.Enabled:= (aRow > 0) and (Length(stgFileHandles.Cells[0, aRow]) > 0); end; procedure TfrmFileUnlock.btnUnlockClick(Sender: TObject); begin UnlockRow(stgFileHandles.Row); if (stgFileHandles.RowCount = 1) then begin Close; ModalResult:= mrOK; end; end; procedure TfrmFileUnlock.FormShow(Sender: TObject); var Index: Integer; begin for Index:= 0 to stgFileHandles.Columns.Count - 1 do begin stgFileHandles.Columns[Index].Width:= stgFileHandles.Canvas.TextWidth(stgFileHandles.Columns[Index].Title.Caption + 'W'); end; end; procedure TfrmFileUnlock.stgFileHandlesDblClick(Sender: TObject); var AHandle: HWND; ProcessId: DWORD; begin if (stgFileHandles.Row > 0) then begin ProcessId:= StrToDWord(stgFileHandles.Cells[1, stgFileHandles.Row]); AHandle:= FindMainWindow(ProcessId); if AHandle <> 0 then ShowWindowEx(AHandle); end; end; procedure TfrmFileUnlock.btnUnlockAllClick(Sender: TObject); var Index: Integer; begin for Index:= stgFileHandles.RowCount - 1 downto 1 do begin UnlockRow(Index); end; if (stgFileHandles.RowCount = 1) then begin Close; ModalResult:= mrOK; end; end; procedure TfrmFileUnlock.btnTerminateClick(Sender: TObject); var Index: Integer; ProcessId: DWORD; begin if (stgFileHandles.Row > 0) then begin if MessageBoxW(Handle, PWideChar(CeUtf8ToUtf16(rsMsgTerminateProcess)), PWideChar(CeUtf8ToUtf16(rsMtWarning)), MB_YESNO or MB_ICONWARNING) = IDYES then begin ProcessId:= StrToDWord(stgFileHandles.Cells[1, stgFileHandles.Row]); if uFileUnlock.TerminateProcess(ProcessId) then begin for Index:= stgFileHandles.RowCount - 1 downto 1 do begin if (ProcessId = StrToDWord(stgFileHandles.Cells[1, Index])) then stgFileHandles.DeleteRow(Index); end; if (stgFileHandles.RowCount = 1) then begin Close; ModalResult:= mrOK; end; end; end; end; end; procedure TfrmFileUnlock.ShowThread; begin ShowModal; end; procedure TfrmFileUnlock.UnlockRow(Index: Integer); var ProcessId: DWORD; FileHandle: HANDLE; begin ProcessId:= StrToDWord(stgFileHandles.Cells[1, Index]); FileHandle:= StrToQWord(stgFileHandles.Cells[0, Index]); if FileUnlock(ProcessId, FileHandle) then stgFileHandles.DeleteRow(Index); end; end. ������������������������doublecmd-1.1.22/src/ffindview.lfm������������������������������������������������������������������0000644�0001750�0000144�00000006433�14743153644�016064� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmFindView: TfrmFindView Left = 365 Height = 151 Top = 311 Width = 430 HorzScrollBar.Page = 343 HorzScrollBar.Range = 103 VertScrollBar.Page = 96 VertScrollBar.Range = 90 ActiveControl = cbDataToFind AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Find' ChildSizing.TopBottomSpacing = 6 ClientHeight = 151 ClientWidth = 430 DesignTimePPI = 120 OnActivate = FormActivate OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '2.0.12.0' object cbDataToFind: TComboBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 28 Top = 15 Width = 410 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Top = 15 BorderSpacing.Right = 10 Constraints.MinWidth = 410 ItemHeight = 20 OnKeyUp = cbDataToFindKeyUp ParentFont = False TabOrder = 0 end object btnFind: TBitBtn AnchorSideTop.Control = btnClose AnchorSideRight.Control = btnClose AnchorSideBottom.Side = asrBottom Left = 188 Height = 30 Top = 114 Width = 112 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 8 BorderSpacing.Bottom = 5 Caption = '&Find' Constraints.MinWidth = 112 Default = True OnClick = btnFindClick ParentFont = False TabOrder = 5 end object btnClose: TBitBtn AnchorSideTop.Control = cbBackwards AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 308 Height = 30 Top = 114 Width = 112 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 15 BorderSpacing.Right = 10 BorderSpacing.Bottom = 5 Caption = '&Cancel' Constraints.MinWidth = 112 Kind = bkCancel ModalResult = 2 ParentFont = False TabOrder = 6 end object cbCaseSens: TCheckBox AnchorSideLeft.Control = cbDataToFind AnchorSideTop.Control = cbDataToFind AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 51 Width = 115 BorderSpacing.Top = 8 Caption = 'C&ase sensitive' ParentFont = False TabOrder = 1 end object chkHex: TCheckBox AnchorSideLeft.Control = cbCaseSens AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCaseSens AnchorSideTop.Side = asrCenter Left = 140 Height = 24 Top = 51 Width = 111 BorderSpacing.Left = 15 Caption = 'Hexadecimal' OnChange = chkHexChange ParentFont = False TabOrder = 2 end object cbRegExp: TCheckBox AnchorSideLeft.Control = chkHex AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = chkHex AnchorSideTop.Side = asrCenter Left = 261 Height = 24 Top = 51 Width = 155 BorderSpacing.Left = 10 Caption = '&Regular expressions' OnChange = cbRegExpChange ParentFont = False TabOrder = 3 end object cbBackwards: TCheckBox AnchorSideLeft.Control = cbCaseSens AnchorSideTop.Control = cbCaseSens AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 75 Width = 94 Caption = '&Backwards' OnChange = cbBackwardsChange TabOrder = 4 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ffindview.lrj������������������������������������������������������������������0000644�0001750�0000144�00000001700�14743153644�016065� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":315460,"name":"tfrmfindview.caption","sourcebytes":[70,105,110,100],"value":"Find"}, {"hash":2805828,"name":"tfrmfindview.btnfind.caption","sourcebytes":[38,70,105,110,100],"value":"&Find"}, {"hash":177752476,"name":"tfrmfindview.btnclose.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":219655237,"name":"tfrmfindview.cbcasesens.caption","sourcebytes":[67,38,97,115,101,32,115,101,110,115,105,116,105,118,101],"value":"C&ase sensitive"}, {"hash":183979276,"name":"tfrmfindview.chkhex.caption","sourcebytes":[72,101,120,97,100,101,99,105,109,97,108],"value":"Hexadecimal"}, {"hash":8115171,"name":"tfrmfindview.cbregexp.caption","sourcebytes":[38,82,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115],"value":"&Regular expressions"}, {"hash":170860739,"name":"tfrmfindview.cbbackwards.caption","sourcebytes":[38,66,97,99,107,119,97,114,100,115],"value":"&Backwards"} ]} ����������������������������������������������������������������doublecmd-1.1.22/src/ffindview.pas������������������������������������������������������������������0000644�0001750�0000144�00000005315�14743153644�016067� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Seksi Commander ---------------------------- Find dialog for Viewer Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz contributors: } unit fFindView; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, uOSForms; type { TfrmFindView } TfrmFindView = class(TModalForm) cbDataToFind: TComboBox; btnFind: TBitBtn; btnClose: TBitBtn; cbCaseSens: TCheckBox; cbBackwards: TCheckBox; chkHex: TCheckBox; cbRegExp: TCheckBox; procedure cbBackwardsChange(Sender: TObject); procedure cbRegExpChange(Sender: TObject); procedure chkHexChange(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormShow(Sender: TObject); procedure btnFindClick(Sender: TObject); procedure cbDataToFindKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); private function GetTextSearchOptions: UIntPtr; public { Public declarations } end; implementation {$R *.lfm} uses LCLProc, LCLType, uFindFiles, uDCUtils; procedure TfrmFindView.FormShow(Sender: TObject); begin if cbDataToFind.Text = EmptyStr then begin if cbDataToFind.Items.Count > 0 then cbDataToFind.Text:= cbDataToFind.Items[0]; end; cbDataToFind.SelectAll; end; procedure TfrmFindView.chkHexChange(Sender: TObject); begin if not chkHex.Checked then cbCaseSens.Checked:= Boolean(cbCaseSens.Tag) else begin cbCaseSens.Tag:= Integer(cbCaseSens.Checked); cbCaseSens.Checked:= True; end; cbCaseSens.Enabled:= not chkHex.Checked; end; procedure TfrmFindView.FormActivate(Sender: TObject); begin cbDataToFind.SetFocus; end; procedure TfrmFindView.cbBackwardsChange(Sender: TObject); begin if cbBackwards.Checked then cbRegExp.Checked:= False end; procedure TfrmFindView.cbRegExpChange(Sender: TObject); begin if cbRegExp.Checked then cbBackwards.Checked:= False; end; procedure TfrmFindView.btnFindClick(Sender: TObject); begin InsertFirstItem(cbDataToFind.Text, cbDataToFind, GetTextSearchOptions); ModalResult:= mrOk; end; procedure TfrmFindView.cbDataToFindKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (Key = VK_Down) and (cbDataToFind.Items.Count > 0) then cbDataToFind.DroppedDown:= True; if Key = 13 then begin Key:= 0; btnFind.Click; end; if Key = 27 then begin Key:= 0; ModalResult:= mrCancel; end; end; function TfrmFindView.GetTextSearchOptions: UIntPtr; var Options: TTextSearchOptions absolute Result; begin Result:= 0; if cbCaseSens.Checked then Include(Options, tsoMatchCase); if cbRegExp.Checked then Include(Options, tsoRegExpr); if chkHex.Checked then Include(Options, tsoHex); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhackform.lfm������������������������������������������������������������������0000644�0001750�0000144�00000000252�14743153644�016034� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmHackForm: TfrmHackForm Left = 455 Height = 300 Top = 236 Width = 400 Position = poScreenCenter ShowInTaskBar = stNever LCLVersion = '1.0.1.3' end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhackform.pas������������������������������������������������������������������0000644�0001750�0000144�00000000444�14743153644�016044� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fHackForm; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms; type { TfrmHackForm } TfrmHackForm = class(TForm) private { private declarations } public { public declarations } end; var frmHackForm: TfrmHackForm; implementation {$R *.lfm} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhardlink.lfm������������������������������������������������������������������0000644�0001750�0000144�00000005213�14743153644�016040� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmHardLink: TfrmHardLink Left = 320 Height = 177 Top = 320 Width = 512 ActiveControl = edtLinkToCreate AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Create hard link' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 177 ClientWidth = 512 KeyPreview = True OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '1.8.4.0' object lblExistingFile: TLabel AnchorSideLeft.Control = edtExistingFile AnchorSideTop.Control = edtLinkToCreate AnchorSideTop.Side = asrBottom Left = 6 Height = 16 Top = 59 Width = 240 BorderSpacing.Top = 6 Caption = '&Destination that the link will point to' FocusControl = edtExistingFile ParentColor = False end object lblLinkToCreate: TLabel AnchorSideLeft.Control = edtLinkToCreate AnchorSideTop.Control = Owner Left = 6 Height = 16 Top = 6 Width = 69 Caption = '&Link name' FocusControl = edtLinkToCreate ParentColor = False end object edtExistingFile: TEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblExistingFile AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 81 Width = 500 BorderSpacing.Top = 6 Constraints.MinWidth = 400 TabOrder = 1 end object edtLinkToCreate: TEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblLinkToCreate AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 28 Width = 500 BorderSpacing.Top = 6 Constraints.MinWidth = 400 TabOrder = 0 end object btnOK: TBitBtn AnchorSideTop.Control = edtExistingFile AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnCancel Left = 300 Height = 36 Top = 118 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 12 BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 2 Caption = '&OK' Constraints.MinWidth = 100 Default = True Kind = bkOK ModalResult = 1 OnClick = btnOKClick TabOrder = 2 end object btnCancel: TBitBtn AnchorSideTop.Control = edtExistingFile AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtExistingFile AnchorSideRight.Side = asrBottom Left = 406 Height = 36 Top = 118 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 12 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Constraints.MinWidth = 100 Kind = bkCancel ModalResult = 2 TabOrder = 3 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhardlink.lrj������������������������������������������������������������������0000644�0001750�0000144�00000001456�14743153644�016056� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":13036155,"name":"tfrmhardlink.caption","sourcebytes":[67,114,101,97,116,101,32,104,97,114,100,32,108,105,110,107],"value":"Create hard link"}, {"hash":37813087,"name":"tfrmhardlink.lblexistingfile.caption","sourcebytes":[38,68,101,115,116,105,110,97,116,105,111,110,32,116,104,97,116,32,116,104,101,32,108,105,110,107,32,119,105,108,108,32,112,111,105,110,116,32,116,111],"value":"&Destination that the link will point to"}, {"hash":81130805,"name":"tfrmhardlink.lbllinktocreate.caption","sourcebytes":[38,76,105,110,107,32,110,97,109,101],"value":"&Link name"}, {"hash":11067,"name":"tfrmhardlink.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmhardlink.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhardlink.pas������������������������������������������������������������������0000644�0001750�0000144�00000004771�14743153644�016055� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fHardLink; interface uses SysUtils, Classes, Controls, Forms, StdCtrls, Buttons; type { TfrmHardLink } TfrmHardLink = class(TForm) lblExistingFile: TLabel; lblLinkToCreate: TLabel; edtExistingFile: TEdit; edtLinkToCreate: TEdit; btnOK: TBitBtn; btnCancel: TBitBtn; procedure btnOKClick(Sender: TObject); procedure FormShow(Sender: TObject); private FCurrentPath: String; public constructor Create(TheOwner: TComponent; CurrentPath: String); reintroduce; end; function ShowHardLinkForm(TheOwner: TComponent; const sExistingFile, sLinkToCreate, CurrentPath: String): Boolean; implementation {$R *.lfm} uses LazFileUtils, uLng, uGlobs, uLog, uShowMsg, DCStrUtils, DCOSUtils, uAdministrator; function ShowHardLinkForm(TheOwner: TComponent; const sExistingFile, sLinkToCreate, CurrentPath: String): Boolean; begin with TfrmHardLink.Create(TheOwner, CurrentPath) do begin try edtLinkToCreate.Text := sLinkToCreate; edtExistingFile.Text := sExistingFile; Result:= (ShowModal = mrOK); finally Free; end; end; end; constructor TfrmHardLink.Create(TheOwner: TComponent; CurrentPath: String); begin inherited Create(TheOwner); FCurrentPath := CurrentPath; end; procedure TfrmHardLink.btnOKClick(Sender: TObject); var sSrc, sDst, Message: String; AElevate: TDuplicates = dupIgnore; begin sSrc:=edtExistingFile.Text; sDst:=edtLinkToCreate.Text; if CompareFilenames(sSrc, sDst) = 0 then Exit; sSrc := GetAbsoluteFileName(FCurrentPath, sSrc); sDst := GetAbsoluteFileName(FCurrentPath, sDst); PushPop(AElevate); try if CreateHardLinkUAC(sSrc, sDst) then begin // write log if (log_cp_mv_ln in gLogOptions) and (log_success in gLogOptions) then logWrite(Format(rsMsgLogSuccess+rsMsgLogLink,[sSrc+' -> '+sDst]), lmtSuccess); end else begin Message:= mbSysErrorMessage; // write log if (log_cp_mv_ln in gLogOptions) and (log_errors in gLogOptions) then logWrite(Format(rsMsgLogError+rsMsgLogLink,[sSrc+' -> '+sDst]), lmtError); // Standart error modal dialog MsgError(rsHardErrCreate + LineEnding + LineEnding + Message); end; finally PushPop(AElevate); end; end; procedure TfrmHardLink.FormShow(Sender: TObject); begin edtLinkToCreate.SelectAll; end; end. �������doublecmd-1.1.22/src/fhotdirexportimport.lfm��������������������������������������������������������0000644�0001750�0000144�00000004154�14743153644�020235� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmhotdirexportimport: Tfrmhotdirexportimport Left = 686 Height = 283 Top = 295 Width = 427 Caption = 'Select the entries your want to import' ClientHeight = 283 ClientWidth = 427 OnCreate = FormCreate Position = poScreenCenter SessionProperties = 'Height;Width;WindowState' LCLVersion = '1.2.4.0' object lblHintHoldControl: TLabel Left = 8 Height = 15 Top = 24 Width = 267 Caption = 'Hold CTRL and click entries to select multiple ones' ParentColor = False end object lbHint: TLabel Left = 8 Height = 15 Top = 8 Width = 298 Caption = 'When clicking a sub-menu, it will select the whole menu' ParentColor = False end object btnSelectAll: TBitBtn Left = 115 Height = 30 Top = 243 Width = 150 Anchors = [akRight, akBottom] Caption = 'Import all!' Kind = bkAll ModalResult = 8 TabOrder = 0 end object btnSelectionDone: TBitBtn Left = 269 Height = 30 Top = 243 Width = 150 Anchors = [akRight, akBottom] Caption = 'Import selected' Default = True Kind = bkOK ModalResult = 1 TabOrder = 1 end object btnCancelImportation: TBitBtn Left = 8 Height = 30 Top = 243 Width = 104 Anchors = [akRight, akBottom] Cancel = True DefaultCaption = True Kind = bkCancel ModalResult = 2 TabOrder = 2 end object tvDirectoryHotlistToExportImport: TTreeView AnchorSideRight.Side = asrBottom Left = 8 Height = 193 Top = 40 Width = 408 Anchors = [akTop, akLeft, akBottom] DefaultItemHeight = 18 DragMode = dmAutomatic HideSelection = False HotTrack = True MultiSelect = True MultiSelectStyle = [msControlSelect, msShiftSelect, msVisibleOnly, msSiblingOnly] ParentFont = False ReadOnly = True RowSelect = True TabOrder = 3 Options = [tvoAllowMultiselect, tvoAutoItemHeight, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhotdirexportimport.lrj��������������������������������������������������������0000644�0001750�0000144�00000002454�14743153644�020247� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":60646548,"name":"tfrmhotdirexportimport.caption","sourcebytes":[83,101,108,101,99,116,32,116,104,101,32,101,110,116,114,105,101,115,32,121,111,117,114,32,119,97,110,116,32,116,111,32,105,109,112,111,114,116],"value":"Select the entries your want to import"}, {"hash":131520499,"name":"tfrmhotdirexportimport.lblhintholdcontrol.caption","sourcebytes":[72,111,108,100,32,67,84,82,76,32,97,110,100,32,99,108,105,99,107,32,101,110,116,114,105,101,115,32,116,111,32,115,101,108,101,99,116,32,109,117,108,116,105,112,108,101,32,111,110,101,115],"value":"Hold CTRL and click entries to select multiple ones"}, {"hash":232028565,"name":"tfrmhotdirexportimport.lbhint.caption","sourcebytes":[87,104,101,110,32,99,108,105,99,107,105,110,103,32,97,32,115,117,98,45,109,101,110,117,44,32,105,116,32,119,105,108,108,32,115,101,108,101,99,116,32,116,104,101,32,119,104,111,108,101,32,109,101,110,117],"value":"When clicking a sub-menu, it will select the whole menu"}, {"hash":154551681,"name":"tfrmhotdirexportimport.btnselectall.caption","sourcebytes":[73,109,112,111,114,116,32,97,108,108,33],"value":"Import all!"}, {"hash":222469476,"name":"tfrmhotdirexportimport.btnselectiondone.caption","sourcebytes":[73,109,112,111,114,116,32,115,101,108,101,99,116,101,100],"value":"Import selected"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fhotdirexportimport.pas��������������������������������������������������������0000644�0001750�0000144�00000001550�14743153644�020237� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fhotdirexportimport; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, ComCtrls; type { Tfrmhotdirexportimport } Tfrmhotdirexportimport = class(TForm) btnSelectAll: TBitBtn; btnSelectionDone: TBitBtn; btnCancelImportation: TBitBtn; lblHintHoldControl: TLabel; lbHint: TLabel; tvDirectoryHotlistToExportImport: TTreeView; procedure FormCreate(Sender: TObject); private { private declarations } public { public declarations } end; var frmhotdirexportimport: Tfrmhotdirexportimport; implementation {$R *.lfm} uses uGlobs; { Tfrmhotdirexportimport } procedure Tfrmhotdirexportimport.FormCreate(Sender: TObject); begin // Initialize property storage InitPropStorage(Self); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015720� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020104� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ffilesystemcopymoveoperationoptions.lfm�����������������0000644�0001750�0000144�00000025563�14743153644�030270� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object FileSystemCopyMoveOperationOptionsUI: TFileSystemCopyMoveOperationOptionsUI Left = 438 Height = 248 Top = 173 Width = 637 AutoSize = True ClientHeight = 248 ClientWidth = 637 LCLVersion = '1.6.0.4' object pnlComboBoxes: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 0 Height = 75 Top = 0 Width = 265 AutoSize = True BorderSpacing.Right = 10 BevelOuter = bvNone ChildSizing.TopBottomSpacing = 5 ChildSizing.HorizontalSpacing = 5 ChildSizing.VerticalSpacing = 10 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 75 ClientWidth = 265 TabOrder = 0 object lblFileExists: TLabel Left = 0 Height = 14 Top = 5 Width = 160 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When &file exists' FocusControl = cmbFileExists ParentColor = False end object lblDirectoryExists: TLabel Left = 0 Height = 14 Top = 29 Width = 160 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When dir&ectory exists' FocusControl = cmbDirectoryExists ParentColor = False end object lblSetPropertyError: TLabel Left = 0 Height = 14 Top = 53 Width = 160 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When ca&nnot set property' FocusControl = cmbSetPropertyError ParentColor = False end object cmbFileExists: TComboBoxAutoWidth AnchorSideLeft.Control = lblFileExists AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblFileExists AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 165 Height = 20 Top = 2 Width = 100 Anchors = [akTop, akLeft, akRight] ItemHeight = 14 Style = csDropDownList TabOrder = 0 end object cmbDirectoryExists: TComboBoxAutoWidth AnchorSideLeft.Control = lblDirectoryExists AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblDirectoryExists AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 165 Height = 20 Top = 26 Width = 100 Anchors = [akTop, akLeft, akRight] ItemHeight = 14 Style = csDropDownList TabOrder = 1 end object cmbSetPropertyError: TComboBoxAutoWidth AnchorSideLeft.Control = lblSetPropertyError AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblSetPropertyError AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 165 Height = 20 Hint = 'What to do when cannot set file time, attributes, etc.' Top = 50 Width = 100 Anchors = [akTop, akLeft, akRight] ItemHeight = 14 ParentShowHint = False ShowHint = True Style = csDropDownList TabOrder = 2 end end object pnlCheckboxes: TPanel AnchorSideLeft.Control = pnlComboBoxes AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlComboBoxes AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 275 Height = 190 Top = 0 Width = 146 AutoSize = True BevelOuter = bvNone BevelWidth = 8 ClientHeight = 190 ClientWidth = 146 TabOrder = 1 object cbCheckFreeSpace: TCheckBox AnchorSideLeft.Control = pnlCheckboxes AnchorSideTop.Control = chkVerify AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 19 Width = 128 Caption = 'C&heck free space' TabOrder = 1 end object cbFollowLinks: TCheckBox AnchorSideLeft.Control = pnlCheckboxes AnchorSideTop.Control = cbReserveSpace AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 57 Width = 93 AllowGrayed = True Caption = 'Fo&llow links' TabOrder = 3 Visible = False end object cbCorrectLinks: TCheckBox AnchorSideLeft.Control = cbFollowLinks AnchorSideTop.Control = cbFollowLinks AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 76 Width = 100 Caption = 'Correct lin&ks' TabOrder = 4 end object cbCopyAttributes: TCheckBox AnchorSideLeft.Control = cbCorrectLinks AnchorSideTop.Control = cbCorrectLinks AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 95 Width = 118 Caption = 'Cop&y attributes' OnChange = cbCopyAttributesChange TabOrder = 5 end object cbDropReadOnlyFlag: TCheckBox AnchorSideLeft.Control = cbCopyAttributes AnchorSideTop.Control = cbCopyAttributes AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 114 Width = 136 BorderSpacing.Left = 10 Caption = 'Drop readonly fla&g' TabOrder = 6 Visible = False end object cbCopyTime: TCheckBox AnchorSideLeft.Control = cbCopyAttributes AnchorSideTop.Control = cbDropReadOnlyFlag AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 133 Width = 117 Caption = 'Copy d&ate/time' TabOrder = 7 end object cbCopyOwnership: TCheckBox AnchorSideLeft.Control = cbCopyTime AnchorSideTop.Control = cbCopyTime AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 152 Width = 120 Caption = 'Copy o&wnership' TabOrder = 8 end object cbReserveSpace: TCheckBox AnchorSideLeft.Control = pnlCheckboxes AnchorSideTop.Control = cbCheckFreeSpace AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 38 Width = 110 Caption = '&Reserve space' OnChange = cbReserveSpaceChange TabOrder = 2 end object cbCopyPermissions: TCheckBox AnchorSideLeft.Control = cbCopyOwnership AnchorSideTop.Control = cbCopyOwnership AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 171 Width = 130 Caption = 'Copy &permissions' TabOrder = 9 Visible = False end object chkVerify: TCheckBox AnchorSideLeft.Control = pnlCheckboxes AnchorSideTop.Control = pnlCheckboxes Left = 0 Height = 19 Top = 0 Width = 58 Caption = '&Verify' TabOrder = 0 end object chkCopyOnWrite: TCheckBox AnchorSideLeft.Control = cbCopyPermissions AnchorSideTop.Control = cbCopyPermissions AnchorSideTop.Side = asrBottom Left = 0 Height = 23 Top = 230 Width = 111 AllowGrayed = True Caption = 'Copy on write' TabOrder = 10 end end object gbFileTemplate: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = pnlComboBoxes AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlComboBoxes AnchorSideRight.Side = asrBottom Left = 0 Height = 74 Top = 75 Width = 265 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Use file template' ClientHeight = 56 ClientWidth = 261 TabOrder = 2 object btnSearchTemplate: TBitBtn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbFileTemplate AnchorSideRight.Control = gbFileTemplate AnchorSideRight.Side = asrBottom Left = 224 Height = 32 Hint = 'Choose template...' Top = 0 Width = 32 Anchors = [akTop, akRight] BorderSpacing.Right = 5 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000009700 00FF000000000000000000000000000000FF00000000000000FFC2B5B3E30000 00FF000000000000000000000000000000000000000000000000000000000000 0000970000FF00000000000000000000000000000000C5B8B570E3DBD9FF8975 7375000000000000000000000000000000000000000000000000000000000000 000000000000970000FF000000000000000000000000C2B4B26FE1D9D7FF8571 6E75000000000000000000000000000000000000000000000000000000000000 0000970000FF00000000000000000000000000000000B3A4A26FD6C9C7FF705E 5B75000000000000000000000000000000000000000000000000000000009700 00FF0000000000000000000000000000000000000000A798967DD9CBCAFF7362 6184000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000005B494812D4C6C5FFD1C2C1FE8F7E 7DFF5B4B4E160000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000C2B3B3C0EEE2E2FED5C8C7FFD6C9 C8FE746363C60000000000000000000000000000000000000000000000000000 00000000000000000000000000009D8B8B5CF9EEEFFFEDE1E0FFDED1D1FFEADE DCFFB1A1A0FF645455630000000000000000000000000000000000000000D2C6 C36CEEE5E2C3BEADABB100000002D2C4C3FBFDF5F4FEE0D4D3FFDACCCBFFE8DD DBFFD2C4C2FE796868FD61525509000000000000000000000000000000008B78 754B00000000000000007C6B6BFCF7ECECFFFEF6F4FFCFC2C0FFD4C7C7FFEDE3 E1FFCDBDBBFF998887FE605151BC00000000000000000000000000000000806F 6D350000000062514F4CCEBEBEFFFBF2F0FFFBF6F5FFC7B9B7FFD0C3C3FFF8F0 EFFFC7B7B4FFA69593FF665555FF5545464D000000000000000000000000D8CF CE59D1C5C299978484FFF4EBEBFEFEFDFDFFF4EEEDFFC3B5B3FFD8CBC9FFFFFC FCFFD8CBC9FFB2A1A0FF867474FE524343FA0000000200000000000000000000 00007767669CE0D3D1FFFFFEFEFFFFFFFFFFEFE7E6FFAF9E9BFFD6C6C4FFFCF7 F7FFD8CACAFFAE9D9EFF827173FF5B4A4EFF67595C9F00000000000000000000 00008E7F7ED8E2D7D6FFCCC2C2FFCDC6C6FFD0C9C9FFD7D1D2FFD6D1D2FFCEC6 C6FFCBC5C5FFC7C0C0FFC2B8B8FFA39698FF726468DC00000000000000000000 0000ACA2A3DEAC9C99FFC9BCBBFFDBCDCAFFF3E6E2FEFFFFFEFFF5EEECFFB9A7 A3FFF3EDEBFEF7F3F3FFA99998FFA49695FFB1A6A7E700000000000000000000 0000000000005F5054459C919391B7ADAFB4BBB2B2C3C0B5B6CFC0B6B7D2BBB2 B3D0BCB2B3C3BBB3B4B59D929592615156460000000000000000 } OnClick = btnSearchTemplateClick ParentShowHint = False ShowHint = True TabOrder = 0 end object lblTemplateName: TLabel AnchorSideLeft.Control = gbFileTemplate AnchorSideTop.Control = btnSearchTemplate AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnSearchTemplate Left = 5 Height = 14 Top = 9 Width = 209 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 5 BorderSpacing.Right = 10 Caption = '<no template>' ParentColor = False end object cbExcludeEmptyDirectories: TCheckBox AnchorSideLeft.Control = gbFileTemplate AnchorSideTop.Control = btnSearchTemplate AnchorSideTop.Side = asrBottom Left = 5 Height = 19 Top = 37 Width = 183 BorderSpacing.Left = 5 BorderSpacing.Top = 5 BorderSpacing.Right = 5 Caption = 'E&xclude empty directories' Checked = True State = cbChecked TabOrder = 1 end end end���������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ffilesystemcopymoveoperationoptions.lrj�����������������0000644�0001750�0000144�00000007525�14743153644�030277� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":73409731,"name":"tfilesystemcopymoveoperationoptionsui.lblfileexists.caption","sourcebytes":[87,104,101,110,32,38,102,105,108,101,32,101,120,105,115,116,115],"value":"When &file exists"}, {"hash":219592963,"name":"tfilesystemcopymoveoperationoptionsui.lbldirectoryexists.caption","sourcebytes":[87,104,101,110,32,100,105,114,38,101,99,116,111,114,121,32,101,120,105,115,116,115],"value":"When dir&ectory exists"}, {"hash":46399081,"name":"tfilesystemcopymoveoperationoptionsui.lblsetpropertyerror.caption","sourcebytes":[87,104,101,110,32,99,97,38,110,110,111,116,32,115,101,116,32,112,114,111,112,101,114,116,121],"value":"When ca&nnot set property"}, {"hash":171515630,"name":"tfilesystemcopymoveoperationoptionsui.cmbsetpropertyerror.hint","sourcebytes":[87,104,97,116,32,116,111,32,100,111,32,119,104,101,110,32,99,97,110,110,111,116,32,115,101,116,32,102,105,108,101,32,116,105,109,101,44,32,97,116,116,114,105,98,117,116,101,115,44,32,101,116,99,46],"value":"What to do when cannot set file time, attributes, etc."}, {"hash":250179989,"name":"tfilesystemcopymoveoperationoptionsui.cbcheckfreespace.caption","sourcebytes":[67,38,104,101,99,107,32,102,114,101,101,32,115,112,97,99,101],"value":"C&heck free space"}, {"hash":76535811,"name":"tfilesystemcopymoveoperationoptionsui.cbfollowlinks.caption","sourcebytes":[70,111,38,108,108,111,119,32,108,105,110,107,115],"value":"Fo&llow links"}, {"hash":28881891,"name":"tfilesystemcopymoveoperationoptionsui.cbcorrectlinks.caption","sourcebytes":[67,111,114,114,101,99,116,32,108,105,110,38,107,115],"value":"Correct lin&ks"}, {"hash":88860499,"name":"tfilesystemcopymoveoperationoptionsui.cbcopyattributes.caption","sourcebytes":[67,111,112,38,121,32,97,116,116,114,105,98,117,116,101,115],"value":"Cop&y attributes"}, {"hash":193111863,"name":"tfilesystemcopymoveoperationoptionsui.cbdropreadonlyflag.caption","sourcebytes":[68,114,111,112,32,114,101,97,100,111,110,108,121,32,102,108,97,38,103],"value":"Drop readonly fla&g"}, {"hash":231770837,"name":"tfilesystemcopymoveoperationoptionsui.cbcopytime.caption","sourcebytes":[67,111,112,121,32,100,38,97,116,101,47,116,105,109,101],"value":"Copy d&ate/time"}, {"hash":58641088,"name":"tfilesystemcopymoveoperationoptionsui.cbcopyownership.caption","sourcebytes":[67,111,112,121,32,111,38,119,110,101,114,115,104,105,112],"value":"Copy o&wnership"}, {"hash":263433445,"name":"tfilesystemcopymoveoperationoptionsui.cbreservespace.caption","sourcebytes":[38,82,101,115,101,114,118,101,32,115,112,97,99,101],"value":"&Reserve space"}, {"hash":37050051,"name":"tfilesystemcopymoveoperationoptionsui.cbcopypermissions.caption","sourcebytes":[67,111,112,121,32,38,112,101,114,109,105,115,115,105,111,110,115],"value":"Copy &permissions"}, {"hash":197955577,"name":"tfilesystemcopymoveoperationoptionsui.chkverify.caption","sourcebytes":[38,86,101,114,105,102,121],"value":"&Verify"}, {"hash":169428869,"name":"tfilesystemcopymoveoperationoptionsui.chkcopyonwrite.caption","sourcebytes":[67,111,112,121,32,111,110,32,119,114,105,116,101],"value":"Copy on write"}, {"hash":150587493,"name":"tfilesystemcopymoveoperationoptionsui.gbfiletemplate.caption","sourcebytes":[85,115,101,32,102,105,108,101,32,116,101,109,112,108,97,116,101],"value":"Use file template"}, {"hash":24093710,"name":"tfilesystemcopymoveoperationoptionsui.btnsearchtemplate.hint","sourcebytes":[67,104,111,111,115,101,32,116,101,109,112,108,97,116,101,46,46,46],"value":"Choose template..."}, {"hash":121893262,"name":"tfilesystemcopymoveoperationoptionsui.lbltemplatename.caption","sourcebytes":[60,110,111,32,116,101,109,112,108,97,116,101,62],"value":"<no template>"}, {"hash":190840595,"name":"tfilesystemcopymoveoperationoptionsui.cbexcludeemptydirectories.caption","sourcebytes":[69,38,120,99,108,117,100,101,32,101,109,112,116,121,32,100,105,114,101,99,116,111,114,105,101,115],"value":"E&xclude empty directories"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ffilesystemcopymoveoperationoptions.pas�����������������0000644�0001750�0000144�00000027347�14743153644�030277� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fFileSystemCopyMoveOperationOptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ExtCtrls, Buttons, uFileSourceOperationOptionsUI, uFileSystemCopyOperation, uFileSystemMoveOperation, uSearchTemplate, KASComboBox; type { TFileSystemCopyMoveOperationOptionsUI } TFileSystemCopyMoveOperationOptionsUI = class(TFileSourceOperationOptionsUI) btnSearchTemplate: TBitBtn; cbCheckFreeSpace: TCheckBox; cbCorrectLinks: TCheckBox; cbDropReadOnlyFlag: TCheckBox; cbFollowLinks: TCheckBox; cbCopyAttributes: TCheckBox; cbCopyTime: TCheckBox; cbCopyOwnership: TCheckBox; cbExcludeEmptyDirectories: TCheckBox; cbReserveSpace: TCheckBox; cbCopyPermissions: TCheckBox; chkCopyOnWrite: TCheckBox; chkVerify: TCheckBox; cmbDirectoryExists: TComboBoxAutoWidth; cmbFileExists: TComboBoxAutoWidth; cmbSetPropertyError: TComboBoxAutoWidth; gbFileTemplate: TGroupBox; grpOptions: TGroupBox; lblSetPropertyError: TLabel; lblTemplateName: TLabel; lblDirectoryExists: TLabel; lblFileExists: TLabel; pnlComboBoxes: TPanel; pnlCheckboxes: TPanel; procedure btnSearchTemplateClick(Sender: TObject); procedure cbCopyAttributesChange(Sender: TObject); procedure cbReserveSpaceChange(Sender: TObject); private FTemplate: TSearchTemplate; procedure SetOperationOptions(CopyOperation: TFileSystemCopyOperation); overload; procedure SetOperationOptions(MoveOperation: TFileSystemMoveOperation); overload; public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; destructor Destroy; override; procedure SaveOptions; override; procedure SetOperationOptions(Operation: TObject); override; end; TFileSystemCopyOperationOptionsUI = class(TFileSystemCopyMoveOperationOptionsUI) public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; end; TFileSystemMoveOperationOptionsUI = class(TFileSystemCopyMoveOperationOptionsUI) end; implementation {$R *.lfm} uses uGlobs, uLng, uFileSourceOperationOptions, DCOSUtils, DCStrUtils, fFindDlg, uFileCopyEx; procedure SetCopyOption(var Options: TCopyAttributesOptions; Option: TCopyAttributesOption; IsSet: Boolean); begin if IsSet then Options := Options + [Option] else Options := Options - [Option]; end; { TFileSystemCopyMoveOperationOptionsUI } procedure TFileSystemCopyMoveOperationOptionsUI.btnSearchTemplateClick(Sender: TObject); begin if ShowUseTemplateDlg(FTemplate) and Assigned(FTemplate) then begin if FTemplate.TemplateName = '' then lblTemplateName.Caption := rsSearchTemplateUnnamed else lblTemplateName.Caption := FTemplate.TemplateName; end; end; procedure TFileSystemCopyMoveOperationOptionsUI.cbCopyAttributesChange(Sender: TObject); begin cbDropReadOnlyFlag.Enabled := cbCopyAttributes.Checked; end; procedure TFileSystemCopyMoveOperationOptionsUI.cbReserveSpaceChange(Sender: TObject); begin if (cbReserveSpace.Checked = False) then cbCheckFreeSpace.Checked := Boolean(cbCheckFreeSpace.Tag) else begin cbCheckFreeSpace.Tag := PtrInt(cbCheckFreeSpace.Checked); cbCheckFreeSpace.Checked := cbReserveSpace.Checked; end; cbCheckFreeSpace.Enabled := not cbReserveSpace.Checked; end; constructor TFileSystemCopyMoveOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited; {$IFDEF DARWIN} chkVerify.Visible := False; {$ENDIF} {$IFDEF MSWINDOWS} cbCopyOwnership.Visible := False; cbCopyPermissions.Visible := True; {$ENDIF} {$IFNDEF LINUX} chkCopyOnWrite.Visible := False; {$ENDIF} if Assigned(FileCopyEx) then begin cbCopyTime.Visible:= False; cbReserveSpace.Visible:= False; cbCopyAttributes.Visible:= False; end; ParseLineToList(rsFileOpFileExistsOptions, cmbFileExists.Items); ParseLineToList(rsFileOpDirectoryExistsOptions, cmbDirectoryExists.Items); ParseLineToList(rsFileOpSetPropertyErrorOptions, cmbSetPropertyError.Items); // Load default options. case gOperationOptionFileExists of fsoofeNone : cmbFileExists.ItemIndex := 0; fsoofeOverwrite : cmbFileExists.ItemIndex := 1; fsoofeOverwriteOlder: cmbFileExists.ItemIndex := 2; fsoofeSkip : cmbFileExists.ItemIndex := 3; end; case gOperationOptionDirectoryExists of fsoodeNone : cmbDirectoryExists.ItemIndex := 0; fsoodeCopyInto : cmbDirectoryExists.ItemIndex := 1; fsoodeSkip : cmbDirectoryExists.ItemIndex := 2; end; case gOperationOptionSetPropertyError of fsoospeNone : cmbSetPropertyError.ItemIndex := 0; fsoospeDontSet : cmbSetPropertyError.ItemIndex := 1; fsoospeIgnoreErrors : cmbSetPropertyError.ItemIndex := 2; end; case gOperationOptionCopyOnWrite of fsoogNone : chkCopyOnWrite.State:= cbGrayed; fsoogYes : chkCopyOnWrite.State:= cbChecked; fsoogNo : chkCopyOnWrite.State:= cbUnchecked; end; cbCopyAttributes.Checked := gOperationOptionCopyAttributes; cbCopyTime.Checked := gOperationOptionCopyTime; cbCopyOwnership.Checked := gOperationOptionCopyOwnership; cbCopyPermissions.Checked := gOperationOptionCopyPermissions; cbDropReadOnlyFlag.Checked := gDropReadOnlyFlag; case gOperationOptionSymLinks of fsooslFollow : cbFollowLinks.State := cbChecked; fsooslDontFollow : cbFollowLinks.State := cbUnchecked; fsooslNone : cbFollowLinks.State := cbGrayed; end; chkVerify.Checked := gOperationOptionVerify; cbCorrectLinks.Checked := gOperationOptionCorrectLinks; cbReserveSpace.Checked := gOperationOptionReserveSpace; cbCheckFreeSpace.Checked := gOperationOptionCheckFreeSpace; cbExcludeEmptyDirectories.Checked := gOperationOptionExcludeEmptyDirectories; end; destructor TFileSystemCopyMoveOperationOptionsUI.Destroy; begin inherited Destroy; FTemplate.Free; end; procedure TFileSystemCopyMoveOperationOptionsUI.SaveOptions; begin case cmbFileExists.ItemIndex of 0: gOperationOptionFileExists := fsoofeNone; 1: gOperationOptionFileExists := fsoofeOverwrite; 2: gOperationOptionFileExists := fsoofeOverwriteOlder; 3: gOperationOptionFileExists := fsoofeSkip; end; case cmbDirectoryExists.ItemIndex of 0: gOperationOptionDirectoryExists := fsoodeNone; 1: gOperationOptionDirectoryExists := fsoodeCopyInto; 2: gOperationOptionDirectoryExists := fsoodeSkip; end; case cmbSetPropertyError.ItemIndex of 0: gOperationOptionSetPropertyError := fsoospeNone; 1: gOperationOptionSetPropertyError := fsoospeDontSet; 2: gOperationOptionSetPropertyError := fsoospeIgnoreErrors; end; case chkCopyOnWrite.State of cbGrayed : gOperationOptionCopyOnWrite := fsoogNone; cbChecked : gOperationOptionCopyOnWrite := fsoogYes; cbUnchecked : gOperationOptionCopyOnWrite := fsoogNo; end; gOperationOptionVerify := chkVerify.Checked; gOperationOptionCopyAttributes := cbCopyAttributes.Checked; gOperationOptionCopyTime := cbCopyTime.Checked; gOperationOptionCopyOwnership := cbCopyOwnership.Checked; gOperationOptionCopyPermissions := cbCopyPermissions.Checked; gDropReadOnlyFlag := cbDropReadOnlyFlag.Checked; case cbFollowLinks.State of cbChecked : gOperationOptionSymLinks := fsooslFollow; cbUnchecked : gOperationOptionSymLinks := fsooslDontFollow; cbGrayed : gOperationOptionSymLinks := fsooslNone; end; gOperationOptionCorrectLinks := cbCorrectLinks.Checked; gOperationOptionReserveSpace := cbReserveSpace.Checked; gOperationOptionCheckFreeSpace := cbCheckFreeSpace.Checked; gOperationOptionExcludeEmptyDirectories := cbExcludeEmptyDirectories.Checked; end; procedure TFileSystemCopyMoveOperationOptionsUI.SetOperationOptions(Operation: TObject); begin if Operation is TFileSystemCopyOperation then SetOperationOptions(Operation as TFileSystemCopyOperation) else if Operation is TFileSystemMoveOperation then SetOperationOptions(Operation as TFileSystemMoveOperation); end; procedure TFileSystemCopyMoveOperationOptionsUI.SetOperationOptions(CopyOperation: TFileSystemCopyOperation); var Options: TCopyAttributesOptions; begin with CopyOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeOverwriteOlder; 3: FileExistsOption := fsoofeSkip; end; case cmbDirectoryExists.ItemIndex of 0: DirExistsOption := fsoodeNone; 1: DirExistsOption := fsoodeCopyInto; 2: DirExistsOption := fsoodeSkip; end; case cmbSetPropertyError.ItemIndex of 0: SetPropertyError := fsoospeNone; 1: SetPropertyError := fsoospeDontSet; 2: SetPropertyError := fsoospeIgnoreErrors; end; case cbFollowLinks.State of cbChecked : SymLinkOption := fsooslFollow; cbUnchecked: SymLinkOption := fsooslDontFollow; cbGrayed : SymLinkOption := fsooslNone; end; case chkCopyOnWrite.State of cbGrayed : CopyOnWrite := fsoogNone; cbChecked : CopyOnWrite := fsoogYes; cbUnchecked : CopyOnWrite := fsoogNo; end; Options := CopyAttributesOptions; SetCopyOption(Options, caoCopyAttributes, cbCopyAttributes.Checked); SetCopyOption(Options, caoCopyTime, cbCopyTime.Checked); SetCopyOption(Options, caoCopyOwnership, cbCopyOwnership.Checked); SetCopyOption(Options, caoCopyPermissions, cbCopyPermissions.Checked); SetCopyOption(Options, caoRemoveReadOnlyAttr, cbDropReadOnlyFlag.Checked); CopyAttributesOptions := Options; CorrectSymLinks := cbCorrectLinks.Checked; CheckFreeSpace := cbCheckFreeSpace.Checked; ReserveSpace := cbReserveSpace.Checked; Verify := chkVerify.Checked; if Assigned(FTemplate) then begin SearchTemplate := FTemplate; FTemplate := nil; end; ExcludeEmptyTemplateDirectories := cbExcludeEmptyDirectories.Checked; end; end; procedure TFileSystemCopyMoveOperationOptionsUI.SetOperationOptions(MoveOperation: TFileSystemMoveOperation); var Options: TCopyAttributesOptions; begin with MoveOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeOverwriteOlder; 3: FileExistsOption := fsoofeSkip; end; case cmbDirectoryExists.ItemIndex of 0: DirExistsOption := fsoodeNone; 1: DirExistsOption := fsoodeCopyInto; 2: DirExistsOption := fsoodeSkip; end; case cmbSetPropertyError.ItemIndex of 0: SetPropertyError := fsoospeNone; 1: SetPropertyError := fsoospeDontSet; 2: SetPropertyError := fsoospeIgnoreErrors; end; case chkCopyOnWrite.State of cbGrayed : CopyOnWrite := fsoogNone; cbChecked : CopyOnWrite := fsoogYes; cbUnchecked : CopyOnWrite := fsoogNo; end; CorrectSymLinks := cbCorrectLinks.Checked; CheckFreeSpace := cbCheckFreeSpace.Checked; ReserveSpace := cbReserveSpace.Checked; Verify := chkVerify.Checked; Options := CopyAttributesOptions; SetCopyOption(Options, caoCopyAttributes, cbCopyAttributes.Checked); SetCopyOption(Options, caoCopyTime, cbCopyTime.Checked); SetCopyOption(Options, caoCopyOwnership, cbCopyOwnership.Checked); SetCopyOption(Options, caoCopyPermissions, cbCopyPermissions.Checked); CopyAttributesOptions := Options; if Assigned(FTemplate) then begin SearchTemplate := FTemplate; FTemplate := nil; end; ExcludeEmptyTemplateDirectories := cbExcludeEmptyDirectories.Checked; end; end; { TFileSystemCopyOperationOptionsUI } constructor TFileSystemCopyOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited; cbFollowLinks.Visible := True; cbDropReadOnlyFlag.Visible := (FileCopyEx = nil); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemcalcchecksumoperation.pas��������������������0000644�0001750�0000144�00000043504�14743153644�027457� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemCalcChecksumOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, contnrs, uFileSourceCalcChecksumOperation, uFileSource, uFileSourceOperationOptions, uFileSourceOperationUI, uFile, uGlobs, uLog, uHash, DCClassesUtf8; type { TFileSystemCalcChecksumOperation } TFileSystemCalcChecksumOperation = class(TFileSourceCalcChecksumOperation) private FFullFilesTree: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceCalcChecksumOperationStatistics; // local copy of statistics FCheckSumFile: TStringListEx; FBuffer: Pointer; FBufferSize: LongWord; FChecksumsList: TObjectList; // Options. FFileExistsOption: TFileSourceOperationOptionFileExists; FSymLinkOption: TFileSourceOperationOptionSymLink; FSkipErrors: Boolean; procedure InitializeVerifyMode; function SimpleFileChecksum: Boolean; procedure InitializeRightToLeft(const Path: String); procedure InitializeLeftToRight(const Path: String); procedure AddFile(const Path, FileName, Hash: String); function CheckSumCalc(aFile: TFile; out aValue: String): Boolean; procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); function CalcChecksumProcessFile(aFile: TFile): Boolean; function VerifyChecksumProcessFile(aFile: TFile; ExpectedChecksum: String): Boolean; function FileExists(var AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles; aTargetPath: String; aTargetMask: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses Math, Forms, LazUTF8, DCConvertEncoding, LConvEncoding, uLng, uFileSystemUtil, uFileSystemFileSource, DCOSUtils, DCStrUtils, uFileProcs, uDCUtils, uShowMsg; type TChecksumEntry = class public Checksum: String; Algorithm: THashAlgorithm; end; const SFV_HEADER = '; Generated by WIN-SFV32 v1.0'; DC_HEADER = '; (Compatible: Double Commander)'; constructor TFileSystemCalcChecksumOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles; aTargetPath: String; aTargetMask: String); begin FBuffer := nil; FSymLinkOption := fsooslNone; FFileExistsOption := fsoofeNone; FSkipErrors := False; FFullFilesTree := nil; FCheckSumFile := TStringListEx.Create; FChecksumsList := TObjectList.Create(True); inherited Create(aTargetFileSource, theFiles, aTargetPath, aTargetMask); end; destructor TFileSystemCalcChecksumOperation.Destroy; begin inherited Destroy; if Assigned(FBuffer) then begin FreeMem(FBuffer); FBuffer := nil; end; FreeAndNil(FFullFilesTree); FreeAndNil(FCheckSumFile); FreeAndNil(FChecksumsList); end; procedure TFileSystemCalcChecksumOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; case Mode of checksum_calc: begin FillAndCount(Files, False, False, FFullFilesTree, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) FCheckSumFile.TextLineBreakStyle:= TextLineBreakStyle; if (Algorithm = HASH_SFV) and OneFile then begin FCheckSumFile.Add(SFV_HEADER); FCheckSumFile.Add(DC_HEADER); end; end; checksum_verify: InitializeVerifyMode; end; FBufferSize := gHashBlockSize; GetMem(FBuffer, FBufferSize); end; procedure TFileSystemCalcChecksumOperation.MainExecute; var aFile: TFile; CurrentFileIndex: Integer; OldDoneBytes: Int64; // for if there was an error Entry: TChecksumEntry; TargetFileName: String; begin if OneFile and (Mode = checksum_calc) then begin TargetFileName:= TargetMask; case FileExists(TargetFileName) of fsoofeSkip: Exit; fsoofeOverwrite: ; end; end; for CurrentFileIndex := 0 to FFullFilesTree.Count - 1 do begin aFile := FFullFilesTree[CurrentFileIndex]; with FStatistics do begin CurrentFile := aFile.Path + aFile.Name; CurrentFileTotalBytes := aFile.Size; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics); if not (aFile.IsDirectory or aFile.IsLinkToDirectory) then begin // If there will be an error in ProcessFile the DoneBytes value // will be inconsistent, so remember it here. OldDoneBytes := FStatistics.DoneBytes; case Mode of checksum_calc: CalcChecksumProcessFile(aFile); checksum_verify: begin Entry := FChecksumsList.Items[CurrentFileIndex] as TChecksumEntry; Algorithm := Entry.Algorithm; VerifyChecksumProcessFile(aFile, Entry.Checksum); end; end; with FStatistics do begin DoneFiles := DoneFiles + 1; DoneBytes := OldDoneBytes + aFile.Size; UpdateStatistics(FStatistics); end; end; CheckOperationState; end; case Mode of checksum_calc: // make result if OneFile then try CurrentFileIndex:= IfThen(Algorithm = HASH_SFV, 2, 0); if (FCheckSumFile.Count > CurrentFileIndex) then FCheckSumFile.SaveToFile(TargetFileName); except on E: EFCreateError do AskQuestion(rsMsgErrECreate + ' ' + TargetFileName + ':', E.Message, [fsourOk], fsourOk, fsourOk); on E: EWriteError do AskQuestion(rsMsgErrEWrite + ' ' + TargetFileName + ':', E.Message, [fsourOk], fsourOk, fsourOk); end; checksum_verify: begin end; end; end; procedure TFileSystemCalcChecksumOperation.Finalize; begin end; procedure TFileSystemCalcChecksumOperation.AddFile(const Path, FileName, Hash: String); var aFileToVerify: TFile; Entry: TChecksumEntry; begin try aFileToVerify := TFileSystemFileSource.CreateFileFromFile(Path + FileName); if not (aFileToVerify.IsDirectory or aFileToVerify.IsLinkToDirectory) then begin with FStatistics do begin TotalFiles := TotalFiles + 1; TotalBytes := TotalBytes + aFileToVerify.Size; end; FFullFilesTree.Add(aFileToVerify); Entry := TChecksumEntry.Create; FChecksumsList.Add(Entry); Entry.Checksum := Hash; Entry.Algorithm := Algorithm; end else FreeAndNil(aFileToVerify); except on EFileNotFound do begin AddString(FResult.Missing, FileName); end else begin FreeAndNil(aFileToVerify); raise; end; end; end; procedure TFileSystemCalcChecksumOperation.InitializeRightToLeft(const Path: String); var I: Integer; Hash, FileName: String; begin for I := 0 to FCheckSumFile.Count - 1 do begin // Skip empty lines if (Length(FCheckSumFile[I]) = 0) then Continue; // Skip comments if (FCheckSumFile[I][1] = ';') then Continue; FileName := FCheckSumFile[I]; Hash := Copy(FileName, Length(FileName) - 7, 8); FileName := Copy(FileName, 1, Length(FileName) - 9); AddFile(Path, FileName, Hash); CheckOperationState; end; end; procedure TFileSystemCalcChecksumOperation.InitializeLeftToRight(const Path: String); var I: Integer; FileName: String; HashType: Boolean = False; begin for I := 0 to FCheckSumFile.Count - 1 do begin // Skip empty lines if (Length(FCheckSumFile[I]) = 0) then Continue; // Skip comments if (FCheckSumFile[I][1] in [';', '#']) then Continue; // Determine hash type by length if (HashType = False) and (Algorithm = HASH_SHA3_224) then begin HashType := True; case Length(FCheckSumFile.Names[I]) of 56: ; // HASH_SHA3_224 64: Algorithm := HASH_SHA3_256; 96: Algorithm := HASH_SHA3_384; 128: Algorithm := HASH_SHA3_512; end; end; FileName := FCheckSumFile.ValueFromIndex[I]; if (Length(FileName) > 0) and (FileName[1] in [' ', '*']) then begin Delete(FileName, 1, 1); end; AddFile(Path, FileName, FCheckSumFile.Names[I]); CheckOperationState; end; end; function TFileSystemCalcChecksumOperation.SimpleFileChecksum: Boolean; var ATemp: Integer; ALeft, ARight: String; begin Result:= True; // Skip empty lines and comments while (FCheckSumFile.Count > 0) do begin ALeft:= FCheckSumFile[0]; if (Length(ALeft) = 0) or (ALeft[1] = ';') then FCheckSumFile.Delete(0) else Break; end; if (FCheckSumFile.Count > 0) then begin ALeft:= FCheckSumFile.Names[0]; ARight:= FCheckSumFile.ValueFromIndex[0]; // Old doublecmd version had generated .sfv file in the wrong format: // (hash *filename), try to determine file format for backward compatibility Result:= (Length(ALeft) <> 8) or (not TryStrToInt('$' + ALeft, ATemp)) or ((Length(ARight) > 0) and (ARight[1] <> '*')) or (TryStrToInt('$' + RightStr(ARight, 8), ATemp)); end; end; procedure TFileSystemCalcChecksumOperation.InitializeVerifyMode; var aFile: TFile; AText: String; Entry: TChecksumEntry; CurrentFileIndex: Integer; {$IF DEFINED(UNIX)} PText: PAnsiChar; {$ENDIF} begin FFullFilesTree := TFiles.Create(Files.Path); if Length(TargetPath) > 0 then begin aFile := Files[0].Clone; with FStatistics do begin TotalFiles := TotalFiles + 1; TotalBytes := TotalBytes + aFile.Size; end; FFullFilesTree.Add(aFile); Entry := TChecksumEntry.Create; FChecksumsList.Add(Entry); Entry.Checksum := TargetPath; Entry.Algorithm := Algorithm; CheckOperationState; Exit; end; FChecksumsList.Clear; for CurrentFileIndex := 0 to Files.Count - 1 do begin aFile := Files[CurrentFileIndex]; FCheckSumFile.Clear; FCheckSumFile.NameValueSeparator:= #32; AText:= mbReadFileToString(aFile.FullPath); {$IF DEFINED(UNIX)} if (GuessLineBreakStyle(AText) = tlbsCRLF) then begin PText:= PAnsiChar(AText); while (PText^ <> #0) do begin if (PText^ = '\') then PText^:= PathDelim; Inc(PText); end; end; {$ENDIF} if StrBegins(AText, UTF8BOM) then FCheckSumFile.Text:= Copy(AText, 4, MaxInt) else if FindInvalidUTF8Codepoint(PChar(AText), Length(AText), True) = -1 then FCheckSumFile.Text:= AText else begin FCheckSumFile.Text:= CeAnsiToUtf8(AText); end; if (FCheckSumFile.Count = 0) then Continue; Algorithm := FileExtToHashAlg(aFile.Extension); if (Algorithm = HASH_SFV) and (SimpleFileChecksum) then InitializeRightToLeft(aFile.Path) else begin InitializeLeftToRight(aFile.Path); end; end; end; function TFileSystemCalcChecksumOperation.CalcChecksumProcessFile(aFile: TFile): Boolean; const TextLineBreak: array[TTextLineBreakStyle] of String = ('/', '\', PathDelim); var FileName: String; sCheckSum: String; TargetFileName: String; begin Result := False; FileName := aFile.FullPath; if not OneFile then begin FCheckSumFile.Clear; if Algorithm = HASH_SFV then begin FCheckSumFile.Add(SFV_HEADER); FCheckSumFile.Add(DC_HEADER); end; TargetFileName:= FileName + '.' + HashFileExt[Algorithm]; case FileExists(TargetFileName) of fsoofeOverwrite: ; fsoofeSkip: Exit(True); end; end; if not CheckSumCalc(aFile, sCheckSum) then Exit; FileName:= ExtractDirLevel(FFullFilesTree.Path, aFile.Path) + aFile.Name; if (TextLineBreak[TextLineBreakStyle] <> PathDelim) then begin FileName:= StringReplace(FileName, PathDelim, TextLineBreak[TextLineBreakStyle], [rfReplaceAll]); end; if Algorithm = HASH_SFV then begin FCheckSumFile.Add(FileName + ' ' + sCheckSum); end else begin FCheckSumFile.Add(sCheckSum + ' *' + FileName); end; if not OneFile then try FCheckSumFile.SaveToFile(TargetFileName); except on E: EFCreateError do AskQuestion(rsMsgErrECreate + ' ' + TargetFileName + LineEnding, E.Message, [fsourOk], fsourOk, fsourOk); on E: EWriteError do AskQuestion(rsMsgErrEWrite + ' ' + TargetFileName + LineEnding, E.Message, [fsourOk], fsourOk, fsourOk); end; end; function TFileSystemCalcChecksumOperation.VerifyChecksumProcessFile( aFile: TFile; ExpectedChecksum: String): Boolean; var sCheckSum: String; sFileName: String; begin Result:= False; sFileName:= ExtractDirLevel(FFullFilesTree.Path, aFile.Path) + aFile.Name; if (CheckSumCalc(aFile, sCheckSum) = False) then AddString(FResult.ReadError, sFileName) else begin if (CompareText(sCheckSum, ExpectedChecksum) = 0) then AddString(FResult.Success, sFileName) else AddString(FResult.Broken, sFileName); end; end; function TFileSystemCalcChecksumOperation.FileExists(var AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; const Responses: array[0..5] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourRenameSource, fsourOverwriteAll, fsourSkipAll, fsourCancel); var Answer: Boolean; Message: String; begin if not mbFileExists(AbsoluteTargetFileName) then Result:= fsoofeOverwrite else case FFileExistsOption of fsoofeNone: repeat Answer := True; Message:= rsMsgFileExistsOverwrite + LineEnding + WrapTextSimple(AbsoluteTargetFileName, 100) + LineEnding; case AskQuestion(Message, '', Responses, fsourOverwrite, fsourSkip) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourRenameSource: begin Message:= ExtractFileName(AbsoluteTargetFileName); Answer:= ShowInputQuery(Thread, Application.Title, rsEditNewFileName, Message); if Answer then begin Result:= fsoofeAutoRenameSource; AbsoluteTargetFileName:= ExtractFilePath(AbsoluteTargetFileName) + Message; Answer:= not mbFileExists(AbsoluteTargetFileName); end; end; fsourNone, fsourCancel: RaiseAbortOperation; end; until Answer; else Result := FFileExistsOption; end; end; function TFileSystemCalcChecksumOperation.CheckSumCalc(aFile: TFile; out aValue: String): Boolean; var hFile: THandle; bRetryRead: Boolean; Context: THashContext; TotalBytesToRead: Int64 = 0; BytesRead, BytesToRead: Int64; begin BytesToRead := FBufferSize; repeat hFile:= mbFileOpen(aFile.FullPath, fmOpenRead or fmShareDenyWrite); Result:= hFile <> feInvalidHandle; if not Result then begin case AskQuestion(rsMsgErrEOpen + ' ' + aFile.FullPath + LineEnding + mbSysErrorMessage, '', [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: ; fsourAbort: RaiseAbortOperation; fsourSkip: Exit(False); end; // case end; until Result; HashInit(Context, Algorithm); try TotalBytesToRead := FileGetSize(hFile); while TotalBytesToRead > 0 do begin // Without the following line the reading is very slow // if it tries to read past end of file. if TotalBytesToRead < BytesToRead then BytesToRead := TotalBytesToRead; repeat try bRetryRead := False; BytesRead := FileRead(hFile, FBuffer^, BytesToRead); if (BytesRead <= 0) then Raise EReadError.Create(mbSysErrorMessage(GetLastOSError)); TotalBytesToRead := TotalBytesToRead - BytesRead; HashUpdate(Context, FBuffer^, BytesRead); except on E: EReadError do begin if gSkipFileOpError then begin LogMessage(rsMsgErrERead + ' ' + aFile.FullPath + ': ' + E.Message, [], lmtError); Exit(False); end; case AskQuestion(rsMsgErrERead + ' ' + aFile.FullPath + LineEnding + E.Message, '', [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryRead := True; fsourAbort: RaiseAbortOperation; fsourSkip: Exit(False); end; // case end; end; until not bRetryRead; with FStatistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + BytesRead; DoneBytes := DoneBytes + BytesRead; UpdateStatistics(FStatistics); end; CheckOperationState; // check pause and stop end;//while finally FileClose(hFile); HashFinal(Context, aValue); end; end; procedure TFileSystemCalcChecksumOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemcalcstatisticsoperation.pas������������������0000644�0001750�0000144�00000012253�14743153644�030044� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCalcStatisticsOperation, uFileSource, uFileSourceOperationUI, uFile, uGlobs, uLog; type TFileSystemCalcStatisticsOperation = class(TFileSourceCalcStatisticsOperation) private FErrorCount: Integer; FStatistics: TFileSourceCalcStatisticsOperationStatistics; // local copy of statistics procedure ProcessFile(aFile: TFile); procedure ProcessLink(aFile: TFile); procedure ProcessSubDirs(const srcPath: String); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses uFileSourceOperationOptions, DCOSUtils, uLng, uFindEx, uFileSystemFileSource, uFileProperty, uOSUtils; constructor TFileSystemCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin inherited Create(aTargetFileSource, theFiles); end; destructor TFileSystemCalcStatisticsOperation.Destroy; begin inherited Destroy; end; procedure TFileSystemCalcStatisticsOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; end; procedure TFileSystemCalcStatisticsOperation.MainExecute; var CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to Files.Count - 1 do begin ProcessFile(Files[CurrentFileIndex]); CheckOperationState; end; if (FStatistics.Size = 0) and (FErrorCount > 0) then begin FStatistics.Size := FOLDER_SIZE_ERRO; UpdateStatistics(FStatistics); end; end; procedure TFileSystemCalcStatisticsOperation.ProcessFile(aFile: TFile); begin FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); if aFile.IsLink then begin Inc(FStatistics.Links); case FSymLinkOption of fsooslFollow: ProcessLink(aFile); fsooslDontFollow: ; // do nothing fsooslNone: begin case AskQuestion('', Format(rsMsgFollowSymlink, [aFile.Name]), [fsourYes, fsourAll, fsourNo, fsourSkipAll], fsourYes, fsourNo) of fsourYes: ProcessLink(aFile); fsourAll: begin FSymLinkOption := fsooslFollow; ProcessLink(aFile); end; fsourNo: ; // do nothing fsourSkipAll: FSymLinkOption := fsooslDontFollow; end; end; end; end else if aFile.IsDirectory then begin Inc(FStatistics.Directories); ProcessSubDirs(aFile.Path + aFile.Name + DirectorySeparator); end else begin // Not always this will be regular file (on Unix can be socket, FIFO, block, char, etc.) // Maybe check with: FPS_ISREG() on Unix? Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + aFile.Size; if aFile.ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := aFile.ModificationTime; if aFile.ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := aFile.ModificationTime; end; UpdateStatistics(FStatistics); end; procedure TFileSystemCalcStatisticsOperation.ProcessLink(aFile: TFile); var PathToFile: String; aLinkFile: TFile = nil; begin PathToFile := mbReadAllLinks(aFile.FullPath); if PathToFile <> '' then begin try aLinkFile := TFileSystemFileSource.CreateFileFromFile(PathToFile); try ProcessFile(aLinkFile); finally FreeAndNil(aLinkFile); end; except on EFileNotFound do begin LogMessage(rsMsgErrInvalidLink + ': ' + aFile.FullPath + ' -> ' + PathToFile, [log_errors], lmtError); end; end; end else begin LogMessage(rsMsgErrInvalidLink + ': ' + aFile.FullPath + ' -> ' + PathToFile, [log_errors], lmtError); end; end; procedure TFileSystemCalcStatisticsOperation.ProcessSubDirs(const srcPath: String); var sr: TSearchRecEx; aFile: TFile; FindResult: Longint; begin FindResult := FindFirstEx(srcPath + '*', 0, sr); try if FindResult <> 0 then begin if AccessDenied(FindResult) then Inc(FErrorCount); end else repeat if (sr.Name='.') or (sr.Name='..') then Continue; aFile := TFileSystemFileSource.CreateFile(srcPath, @sr); try ProcessFile(aFile); finally FreeAndNil(aFile); end; CheckOperationState; until FindNextEx(sr) <> 0; finally FindCloseEx(sr); end; end; procedure TFileSystemCalcStatisticsOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemcombineoperation.pas�������������������������0000644�0001750�0000144�00000043347�14743153644�026453� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemCombineOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCombineOperation, uFileSource, uFileSourceOperationUI, uFile, uGlobs, uLog, DCClassesUtf8; type { TFileSystemCombineOperation } TFileSystemCombineOperation = class(TFileSourceCombineOperation) private FFullFilesTreeToCombine: TFiles; // source files including all files FStatistics: TFileSourceCombineOperationStatistics; // local copy of statistics FTargetPath: String; FBuffer: Pointer; FBufferSize: LongWord; FCheckFreeSpace: Boolean; FExtensionLengthRequired : longint; protected function Combine(aSourceFile: TFile; aTargetFileStream: TFileStreamEx): Boolean; procedure ShowError(sMessage: String); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); function TryToGetInfoFromTheCRC32VerificationFile: Boolean; procedure BegForPresenceOfThisFile(aFilename: String); public constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetFile: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses //Lazarus, Free-Pascal, etc. LCLProc, LazUTF8, DCcrc32, //DC uOSUtils, DCOSUtils, uLng, uFileSystemUtil, uFileSystemFileSource, DCBasicTypes, uAdministrator, DCConvertEncoding; { TFileSystemCombineOperation.Create } constructor TFileSystemCombineOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetFile: String); begin FFullFilesTreeToCombine := nil; FCheckFreeSpace := True; FTargetPath := ExtractFilePath(aTargetFile); FBufferSize := gCopyBlockSize; GetMem(FBuffer, FBufferSize); inherited Create(aFileSource, theSourceFiles, aTargetFile); end; { TFileSystemCombineOperation.Destroy } destructor TFileSystemCombineOperation.Destroy; begin inherited Destroy; if Assigned(FBuffer) then begin FreeMem(FBuffer); FBuffer := nil; end; if Assigned(FFullFilesTreeToCombine) then FreeAndNil(FFullFilesTreeToCombine); end; { TFileSystemCombineOperation.Initialize } procedure TFileSystemCombineOperation.Initialize; var MaybeFileIndex: integer; MaybeAdditionalSourceFilename: String; MaybeFile: TFile; begin // If we're under "RequireDynamicMode", we have just ONE file in "SourceFiles" list, // so let's see immediately if we would have the other ready... if RequireDynamicMode then begin // If we're under "RequireDynamicMode", we'll make sure the ".001" file is // the first one in the list and available. We need to do that since in main // panel we did not force user to select the ".001" file to make this // user friendly // // Also, since we're here, let''s try to see if we have other files // in the series ready in the current same folder. // It is pertinent to do that so the bar graph will be set as close // as possible right from the start as oppose as TC which don't have a global graph. FExtensionLengthRequired:=length(SourceFiles[0].Extension); MaybeFileIndex:=1; repeat MaybeAdditionalSourceFilename:=SourceFiles[0].Path + SourceFiles[0].NameNoExt + ExtensionSeparator + Format('%.*d',[FExtensionLengthRequired, MaybeFileIndex]); if (FileExistsUAC(MaybeAdditionalSourceFilename)) OR (MaybeFileIndex=1) then begin //Let's make sure the first file is available and if not, beg for it! if (FileExistsUAC(MaybeAdditionalSourceFilename)=FALSE) AND (MaybeFileIndex=1) then BegForPresenceOfThisFile(MaybeAdditionalSourceFilename); MaybeFile := TFileSystemFileSource.CreateFileFromFile(MaybeAdditionalSourceFilename); SourceFiles.Add(MaybeFile); end; inc(MaybeFileIndex); until (not FileExistsUAC(MaybeAdditionalSourceFilename)) AND (MaybeFileIndex<>1); SourceFiles.Delete(0); //We may now delete the first one, which could have been any of the series end; //if RequireDynamicMode then... // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FStatistics.CurrentFileTo:= TargetFile; FillAndCount(SourceFiles, False, False, FFullFilesTreeToCombine, FStatistics.TotalFiles, FStatistics.TotalBytes); // count files //If we're under "RequireDynamicMode", check if we have a summary file like TC //We do that *after* the standard statistic in case we need to correct them from info in the summary file if RequireDynamicMode AND (not WeGotTheCRC32VerificationFile) then TryToGetInfoFromTheCRC32VerificationFile; end; { TFileSystemCombineOperation.MainExecute } procedure TFileSystemCombineOperation.MainExecute; var Attrs: TFileAttrs; aFile, DynamicNextFile: TFile; CurrentFileIndex: Integer; iTotalDiskSize, iFreeDiskSize: Int64; TargetFileStream: TFileStreamUAC = nil; DynamicNextFilename : String; UserAnswer: TFileSourceOperationUIResponse; begin try { Check disk free space } if FCheckFreeSpace = True then begin GetDiskFreeSpace(FTargetPath, iFreeDiskSize, iTotalDiskSize); if FStatistics.TotalBytes > iFreeDiskSize then begin AskQuestion('', rsMsgNoFreeSpaceCont, [fsourAbort], fsourAbort, fsourAbort); RaiseAbortOperation; end; end; Attrs:= FileGetAttrUAC(TargetFile); if Attrs <> faInvalidAttributes then begin if FPS_ISDIR(Attrs) then begin AskQuestion(Format(rsMsgErrDirExists, [TargetFile]), '', [fsourAbort], fsourAbort, fsourAbort, nil); RaiseAbortOperation; end; if AskQuestion(Format(rsMsgFileExistsRwrt, [TargetFile]), '', [fsourOverwrite, fsourAbort], fsourOverwrite, fsourAbort, nil) <> fsourOverwrite then begin RaiseAbortOperation; end; end; // Create destination file TargetFileStream := TFileStreamUAC.Create(TargetFile, fmCreate); try CurrentFileIndex:=0; while (CurrentFileIndex<FFullFilesTreeToCombine.Count) OR (RequireDynamicMode AND (FStatistics.DoneBytes < FStatistics.TotalBytes)) do begin // In "RequireDynamicMode", we might be here with the next file not available. // Let's make sure it's not the case and if so, let's add it to current list if (CurrentFileIndex>=FFullFilesTreeToCombine.Count) then begin DynamicNextFilename:=SourceFiles[0].Path + SourceFiles[0].NameNoExt + ExtensionSeparator + Format('%.*d',[FExtensionLengthRequired, (CurrentFileIndex+1)]); BegForPresenceOfThisFile(DynamicNextFilename); DynamicNextFile := TFileSystemFileSource.CreateFileFromFile(DynamicNextFilename); SourceFiles.Add(DynamicNextFile); FFullFilesTreeToCombine.Add(DynamicNextFile.Clone); end; aFile := FFullFilesTreeToCombine[CurrentFileIndex]; with FStatistics do begin CurrentFileFrom := aFile.FullPath; CurrentFileTotalBytes := aFile.Size; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics); // Combine with current file if not Combine(aFile, TargetFileStream) then Break; with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; CheckOperationState; inc(CurrentFileIndex); end; finally if Assigned(TargetFileStream) then begin FreeAndNil(TargetFileStream); if (FStatistics.DoneBytes <> FStatistics.TotalBytes) then begin // There was some error, because not all files has been combined. // Delete the not completed target file. DeleteFileUAC(TargetFile); // In "RequireDynamicMode", to give little feedback to user, let's him know he won't have his file if RequireDynamicMode then begin ShowError(rsMsgLogError + Format(rsMsgIncorrectFilelength,[TargetFile])); end; end else begin // If all the data have been copied, in the case of the "RequireDynamicMode", we may validate the CRC32, // if it was available, so we could valide the integrity of resulting file if RequireDynamicMode AND (ExpectedCRC32<>$00000000) then begin if CurrentCRC32<>ExpectedCRC32 then begin UserAnswer:=AskQuestion('',rsMsgLogError + Format(rsMsgBadCRC32,[TargetFile]),[fsourNo,fsourYes], fsourNo, fsourNo); if UserAnswer=fsourNo then mbDeleteFile(TargetFile); RaiseAbortOperation; end; end; end; end; end; except on EFCreateError do begin ShowError(rsMsgLogError + rsMsgErrECreate + ': ' + TargetFile); end; end; end; { TFileSystemCombineOperation.Finalize } procedure TFileSystemCombineOperation.Finalize; begin end; { TFileSystemCombineOperation.Combine } function TFileSystemCombineOperation.Combine(aSourceFile: TFile; aTargetFileStream: TFileStreamEx): Boolean; var SourceFileStream: TFileStreamUAC; iTotalDiskSize, iFreeDiskSize: Int64; bRetryRead, bRetryWrite: Boolean; BytesRead, BytesToRead, BytesWrittenTry, BytesWritten: Int64; TotalBytesToRead: Int64 = 0; begin Result := False; BytesToRead := FBufferSize; SourceFileStream := nil; // for safety exception handling try try SourceFileStream := TFileStreamUAC.Create(aSourceFile.FullPath, fmOpenRead or fmShareDenyNone); TotalBytesToRead := SourceFileStream.Size; while TotalBytesToRead > 0 do begin // Without the following line the reading is very slow // if it tries to read past end of file. if TotalBytesToRead < BytesToRead then BytesToRead := TotalBytesToRead; repeat try bRetryRead := False; BytesRead := SourceFileStream.Read(FBuffer^, BytesToRead); if (BytesRead = 0) then Raise EReadError.Create(mbSysErrorMessage(GetLastOSError)); TotalBytesToRead := TotalBytesToRead - BytesRead; BytesWritten := 0; if BytesRead > 0 then begin CurrentCRC32:= crc32_16bytes(FBuffer, BytesRead, CurrentCRC32); end; repeat try bRetryWrite := False; BytesWrittenTry := aTargetFileStream.Write((FBuffer + BytesWritten)^, BytesRead); BytesWritten := BytesWritten + BytesWrittenTry; if BytesWrittenTry = 0 then begin Raise EWriteError.Create(mbSysErrorMessage(GetLastOSError)); end else if BytesWritten < BytesRead then begin bRetryWrite := True; // repeat and try to write the rest end; except on E: EWriteError do begin { Check disk free space } GetDiskFreeSpace(FTargetPath, iFreeDiskSize, iTotalDiskSize); if BytesRead > iFreeDiskSize then begin case AskQuestion(rsMsgNoFreeSpaceRetry, '', [fsourYes, fsourNo], fsourYes, fsourNo) of fsourYes: bRetryWrite := True; fsourNo: RaiseAbortOperation; end; // case end else begin case AskQuestion(rsMsgErrEWrite + ' ' + TargetFile + ':', E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryWrite := True; fsourAbort: RaiseAbortOperation; fsourSkip: Exit; end; // case end; end; // on do end; // except until not bRetryWrite; except on E: EReadError do begin case AskQuestion(rsMsgErrERead + ' ' + aSourceFile.FullPath + ':', E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryRead := True; fsourAbort: RaiseAbortOperation; fsourSkip: Exit; end; // case end; end; until not bRetryRead; with FStatistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + BytesRead; DoneBytes := DoneBytes + BytesRead; UpdateStatistics(FStatistics); end; CheckOperationState; // check pause and stop end;//while finally if Assigned(SourceFileStream) then FreeAndNil(SourceFileStream); end; Result:= True; except on EFOpenError do begin ShowError(rsMsgLogError + rsMsgErrEOpen + ': ' + aSourceFile.FullPath); end; on EWriteError do begin ShowError(rsMsgLogError + rsMsgErrEWrite + ': ' + TargetFile); end; end; end; { TFileSystemCombineOperation.ShowError } procedure TFileSystemCombineOperation.ShowError(sMessage: String); begin if gSkipFileOpError then logWrite(Thread, sMessage, lmtError, True) else begin AskQuestion(sMessage, '', [fsourAbort], fsourAbort, fsourAbort); RaiseAbortOperation; end; end; { TFileSystemCombineOperation.LogMessage } procedure TFileSystemCombineOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; { TFileSystemCombineOperation.TryToGetInfroFromTheCRC32VerificationFile } function TFileSystemCombineOperation.TryToGetInfoFromTheCRC32VerificationFile: Boolean; var PosOfEqualSign: integer; MaybeSummaryFilename: String; SummaryLines: TStringListUAC; LineToParse: string; UserAnswer: TFileSourceOperationUIResponse; i: integer; begin Result:= False; //We just mimic TC who set in uppercase the "CRC" extension if the filename (without extension!) is made all with capital letters. if SourceFiles[0].NameNoExt = UTF8UpperCase(SourceFiles[0].NameNoExt) then MaybeSummaryFilename:= SourceFiles[0].Path + SourceFiles[0].NameNoExt + ExtensionSeparator + 'CRC' else begin MaybeSummaryFilename:= SourceFiles[0].Path + SourceFiles[0].NameNoExt + ExtensionSeparator + 'crc'; end; //If CRC32 verification file is not found, try to ask user to make it available for us or maybe continue without it if it is what user want UserAnswer:=fsourOk; while (not FileExistsUAC(MaybeSummaryFilename)) AND (UserAnswer=fsourOk) do begin UserAnswer:=AskQuestion(Format(msgTryToLocateCRCFile,[MaybeSummaryFilename]), '' , [fsourOk,fsourCancel], fsourOk, fsourCancel); end; if FileExistsUAC(MaybeSummaryFilename) then begin SummaryLines := TStringListUAC.Create; try SummaryLines.LoadFromFile(MaybeSummaryFilename); for i := 0 to SummaryLines.Count - 1 do begin LineToParse := SummaryLines[i]; PosOfEqualSign := UTF8Pos('=', LineToParse); if PosOfEqualSign > 0 then //Investiguate *only* if the equal sign is present begin // Let's see if we could extract final filename. // We first look for a UTF8 filename style. If so, take it, if not, search for the ANSI flavor if UTF8Pos('filenameutf8=', UTF8LowerCase(LineToParse)) > 0 then begin TargetFile:= ExtractFilePath(TargetFile) + UTF8Copy(LineToParse, (PosOfEqualSign + 1), MaxInt); end else begin if Pos('filename=', LowerCase(LineToParse)) > 0 then TargetFile:= ExtractFilePath(TargetFile) + CeSysToUtf8(Copy(LineToParse,(PosOfEqualSign + 1) ,MaxInt)); end; //Let's see if we could extract final filesize... if UTF8Pos('size=',UTF8LowerCase(LineToParse))>0 then FStatistics.TotalBytes:=StrToInt64(UTF8Copy(LineToParse,(PosOfEqualSign+1),(UTF8length(LineToParse)-PosOfEqualSign))); //Let's see if we could extract final CRC32... if UTF8Pos('crc32=',UTF8LowerCase(LineToParse))>0 then ExpectedCRC32:=StrToQWord('x'+UTF8Copy(LineToParse,(PosOfEqualSign+1),(UTF8length(LineToParse)-PosOfEqualSign))); end; end; finally SummaryLines.Free; end; WeGotTheCRC32VerificationFile:=TRUE; result:=TRUE; end; end; { TFileSystemCombineOperation.BegForPresenceOfThisFile } procedure TFileSystemCombineOperation.BegForPresenceOfThisFile(aFilename: String); begin while not FileExistsUAC(aFilename) do begin case AskQuestion(Format(rsMsgFileNotFound+#$0A+rsMsgProvideThisFile,[aFilename]), '', [fsourRetry, fsourAbort], fsourRetry, fsourAbort) of fsourAbort: RaiseAbortOperation; end; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemcopyoperation.pas����������������������������0000644�0001750�0000144�00000017417�14743153644�026010� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemCopyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCopyOperation, uFileSource, uFileSourceOperationTypes, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uFileSystemUtil, DCOSUtils, uSearchTemplate; type { TFileSystemCopyOperation } TFileSystemCopyOperation = class(TFileSourceCopyOperation) private FOperationHelper: TFileSystemOperationHelper; FExcludeEmptyTemplateDirectories: Boolean; FSearchTemplate: TSearchTemplate; FCopyOnWrite: TFileSourceOperationOptionGeneral; FSetPropertyError: TFileSourceOperationOptionSetPropertyError; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics // Options. FVerify, FReserveSpace, FCheckFreeSpace: Boolean; FSkipAllBigFiles: Boolean; FAutoRenameItSelf: Boolean; FCorrectSymLinks: Boolean; procedure SetSearchTemplate(AValue: TSearchTemplate); public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property Verify: Boolean read FVerify write FVerify; property CheckFreeSpace: Boolean read FCheckFreeSpace write FCheckFreeSpace; property ReserveSpace: Boolean read FReserveSpace write FReserveSpace; property SkipAllBigFiles: Boolean read FSkipAllBigFiles write FSkipAllBigFiles; property AutoRenameItSelf: Boolean read FAutoRenameItSelf write FAutoRenameItSelf; property CorrectSymLinks: Boolean read FCorrectSymLinks write FCorrectSymLinks; property CopyOnWrite: TFileSourceOperationOptionGeneral read FCopyOnWrite write FCopyOnWrite; property SetPropertyError: TFileSourceOperationOptionSetPropertyError read FSetPropertyError write FSetPropertyError; property ExcludeEmptyTemplateDirectories: Boolean read FExcludeEmptyTemplateDirectories write FExcludeEmptyTemplateDirectories; {en Operation takes ownership of assigned template and will free it. } property SearchTemplate: TSearchTemplate read FSearchTemplate write SetSearchTemplate; end; { Both operations are the same, just source and target reversed. Implement them in terms of the same functions, or have one use the other. } { TFileSystemCopyInOperation } TFileSystemCopyInOperation = class(TFileSystemCopyOperation) protected function GetID: TFileSourceOperationType; override; end; { TFileSystemCopyOutOperation } TFileSystemCopyOutOperation = class(TFileSystemCopyOperation) protected function GetID: TFileSourceOperationType; override; end; implementation uses fFileSystemCopyMoveOperationOptions, uGlobs; // -- TFileSystemCopyOperation --------------------------------------------- constructor TFileSystemCopyOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin // Here we can read global settings if there are any FSymLinkOption := gOperationOptionSymLinks; FSetPropertyError := gOperationOptionSetPropertyError; FReserveSpace := gOperationOptionReserveSpace; FCheckFreeSpace := gOperationOptionCheckFreeSpace; FSkipAllBigFiles := False; FAutoRenameItSelf := False; FCorrectSymLinks := gOperationOptionCorrectLinks; FExcludeEmptyTemplateDirectories := True; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); // Here we can read global settings if there are any FCopyOnWrite := gOperationOptionCopyOnWrite; FFileExistsOption := gOperationOptionFileExists; FDirExistsOption := gOperationOptionDirectoryExists; if gOperationOptionCopyAttributes then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyAttributes]; if gOperationOptionCopyXattributes then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyXattributes]; if gOperationOptionCopyTime then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyTime]; if gOperationOptionCopyOwnership then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyOwnership]; if gOperationOptionCopyPermissions then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyPermissions]; if gDropReadOnlyFlag then FCopyAttributesOptions := FCopyAttributesOptions + [caoRemoveReadOnlyAttr]; end; destructor TFileSystemCopyOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); FreeAndNil(FOperationHelper); FreeAndNil(FSearchTemplate); end; procedure TFileSystemCopyOperation.Initialize; var TreeBuilder: TFileSystemTreeBuilder; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TFileSystemTreeBuilder.Create( @AskQuestion, @CheckOperationState); try TreeBuilder.SymLinkOption := Self.SymLinkOption; TreeBuilder.SearchTemplate := Self.SearchTemplate; TreeBuilder.ExcludeEmptyTemplateDirectories := Self.ExcludeEmptyTemplateDirectories; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; if FVerify then FStatistics.TotalBytes := FStatistics.TotalBytes * 2; finally FreeAndNil(TreeBuilder); end; if Assigned(FOperationHelper) then FreeAndNil(FOperationHelper); FOperationHelper := TFileSystemOperationHelper.Create( @AskQuestion, @RaiseAbortOperation, @AppProcessMessages, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, Thread, fsohmCopy, TargetPath, FStatistics); FOperationHelper.Verify := FVerify; FOperationHelper.RenameMask := RenameMask; FOperationHelper.CopyOnWrite := FCopyOnWrite; FOperationHelper.ReserveSpace := FReserveSpace; FOperationHelper.CheckFreeSpace := CheckFreeSpace; FOperationHelper.CopyAttributesOptions := CopyAttributesOptions; FOperationHelper.SkipAllBigFiles := SkipAllBigFiles; FOperationHelper.AutoRenameItSelf := AutoRenameItSelf; FOperationHelper.CorrectSymLinks := CorrectSymLinks; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.DirExistsOption := DirExistsOption; FOperationHelper.SetPropertyError := SetPropertyError; FOperationHelper.Initialize; end; procedure TFileSystemCopyOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree); end; procedure TFileSystemCopyOperation.SetSearchTemplate(AValue: TSearchTemplate); begin FSearchTemplate.Free; FSearchTemplate := AValue; end; procedure TFileSystemCopyOperation.Finalize; begin FileExistsOption := FOperationHelper.FileExistsOption; FreeAndNil(FOperationHelper); end; class function TFileSystemCopyOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TFileSystemCopyOperationOptionsUI; end; { TFileSystemCopyInOperation } function TFileSystemCopyInOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopyIn; end; { TFileSystemCopyOutOperation } function TFileSystemCopyOutOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopyOut; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemcreatedirectoryoperation.pas�����������������0000644�0001750�0000144�00000003615�14743153644�030221� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemCreateDirectoryOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCreateDirectoryOperation, uFileSource, uFileSystemFileSource; type TFileSystemCreateDirectoryOperation = class(TFileSourceCreateDirectoryOperation) private FFileSystemFileSource: IFileSystemFileSource; public constructor Create(aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uFileSourceOperationUI, uLog, uLng, uGlobs, DCOSUtils, uAdministrator; constructor TFileSystemCreateDirectoryOperation.Create( aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); begin FFileSystemFileSource := aTargetFileSource as IFileSystemFileSource; inherited Create(aTargetFileSource, aCurrentPath, aDirectoryPath); end; procedure TFileSystemCreateDirectoryOperation.Initialize; begin end; procedure TFileSystemCreateDirectoryOperation.MainExecute; begin if FileGetAttrUAC(AbsolutePath) <> faInvalidAttributes then begin AskQuestion(Format(rsMsgErrDirExists, [AbsolutePath]), '', [fsourOk], fsourOk, fsourOk); end else if ForceDirectoriesUAC(AbsolutePath) = False then begin if (log_dir_op in gLogOptions) and (log_errors in gLogOptions) then logWrite(Thread, Format(rsMsgLogError+rsMsgLogMkDir, [AbsolutePath]), lmtError); AskQuestion(Format(rsMsgErrForceDir, [AbsolutePath]), '', [fsourOk], fsourOk, fsourOk); end else begin if (log_dir_op in gLogOptions) and (log_success in gLogOptions) then logWrite(Thread, Format(rsMsgLogSuccess+rsMsgLogMkDir,[AbsolutePath]), lmtSuccess); end; end; procedure TFileSystemCreateDirectoryOperation.Finalize; begin end; end. �������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemdeleteoperation.pas��������������������������0000644�0001750�0000144�00000031565�14743153644�026300� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceDeleteOperation, uFileSource, uFileSourceOperationOptions, uFileSourceOperationUI, uFile, uDescr, uGlobs, uLog; type { TFileSystemDeleteOperation } TFileSystemDeleteOperation = class(TFileSourceDeleteOperation) private FFullFilesTreeToDelete: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceDeleteOperationStatistics; // local copy of statistics FDescription: TDescription; // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; FSkipErrors: Boolean; FRecycle: Boolean; FDeleteReadOnly, FDeleteDirectly: TFileSourceOperationOptionGeneral; procedure DeleteSubDirectory(const aFile: TFile); protected procedure ProcessFile(aFile: TFile); procedure ProcessList(aFiles: TFiles); function ShowError(sMessage: String): TFileSourceOperationUIResponse; procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; // For delete to trash property Recycle : boolean read FRecycle write FRecycle default false; property DeleteReadOnly: TFileSourceOperationOptionGeneral read FDeleteReadOnly write FDeleteReadOnly; property SymLinkOption: TFileSourceOperationOptionSymLink read FSymLinkOption write FSymLinkOption; property SkipErrors: Boolean read FSkipErrors write FSkipErrors; end; implementation uses DCOSUtils, DCStrUtils, uLng, uFileSystemUtil, uTrash, uAdministrator {$IF DEFINED(MSWINDOWS)} , Windows, uFileUnlock, fFileUnlock, uSuperUser {$ENDIF} ; constructor TFileSystemDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FSymLinkOption := fsooslNone; FSkipErrors := gSkipFileOpError; FRecycle := False; FDeleteReadOnly := fsoogNone; FDeleteDirectly:= fsoogNone; if gProcessComments then FDescription := TDescription.Create(True); inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TFileSystemDeleteOperation.Destroy; begin inherited Destroy; if Assigned(FDescription) then begin FDescription.SaveDescription; FreeAndNil(FDescription); end; if not FRecycle then begin FreeAndNil(FFullFilesTreeToDelete); end; end; procedure TFileSystemDeleteOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; if FRecycle then begin FFullFilesTreeToDelete:= FilesToDelete; FStatistics.TotalFiles:= FFullFilesTreeToDelete.Count; end else begin FillAndCount(FilesToDelete, True, False, FFullFilesTreeToDelete, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; if gProcessComments then FDescription.Clear; {$IF DEFINED(MSWINDOWS)} if (ElevateAction = dupIgnore) then ElevateAction:= dupError; {$ENDIF} end; procedure TFileSystemDeleteOperation.MainExecute; begin ProcessList(FFullFilesTreeToDelete); end; procedure TFileSystemDeleteOperation.Finalize; begin end; procedure TFileSystemDeleteOperation.DeleteSubDirectory(const aFile: TFile); var RootFiles: TFiles = nil; SubFiles: TFiles = nil; FilesCount, BytesCount: Int64; begin RootFiles := TFiles.Create(aFile.Path); try RootFiles.Add(aFile.Clone); // Only count statistics for subfiles because statistics for the root dir // have already been counted. FillAndCount(RootFiles, True, True, SubFiles, FilesCount, BytesCount); FStatistics.TotalFiles := FStatistics.TotalFiles + FilesCount; FStatistics.TotalBytes := FStatistics.TotalBytes + BytesCount; // Only now insert root directory. SubFiles.Insert(aFile.Clone, 0); // This function will only be called if deleting to trash failed // so we can assume Recycle is True. Turn off temporarily as we delete this subdirectory. FRecycle := False; ProcessList(SubFiles); finally RootFiles.Free; SubFiles.Free; FRecycle := True; end; end; procedure TFileSystemDeleteOperation.ProcessFile(aFile: TFile); const ResponsesError: array[0..3] of TFileSourceOperationUIResponse = (fsourRetry, fsourSkip, fsourSkipAll, fsourAbort); var FileName: String; bRetry: Boolean; LastError: Integer; RemoveDirectly: TFileSourceOperationOptionGeneral = fsoogNone; sMessage, sQuestion: String; logOptions: TLogOptions; DeleteResult: Boolean; PossibleResponses: array of TFileSourceOperationUIResponse; {$IF DEFINED(MSWINDOWS)} ProcessInfo: TProcessInfoArray; {$ENDIF} begin FileName := aFile.FullPath; if FileIsReadOnly(aFile.Attributes) then begin case FDeleteReadOnly of fsoogNone: case AskQuestion(Format(rsMsgFileReadOnly, [WrapTextSimple(FileName)]), '', [fsourYes, fsourSkip, fsourAbort, fsourAll, fsourSkipAll], fsourYes, fsourAbort) of fsourAll: FDeleteReadOnly := fsoogYes; fsourSkip: Exit; fsourSkipAll: begin FDeleteReadOnly := fsoogNo; Exit; end; fsourAbort: RaiseAbortOperation; end; fsoogNo: Exit; end; end; repeat bRetry := False; if (FRecycle = False) then begin if FileIsReadOnly(aFile.Attributes) then FileSetReadOnlyUAC(FileName, False); if aFile.IsDirectory then // directory begin DeleteResult := RemoveDirectoryUAC(FileName); end else begin // files and other stuff DeleteResult := DeleteFileUAC(FileName); end; end else begin // Delete to trash (one function for file and folder) DeleteResult:= FileTrashUtf8(FileName); if not DeleteResult then begin DeleteResult:= not mbFileSystemEntryExists(FileName); end; if not DeleteResult then begin case FDeleteDirectly of fsoogNone: begin case AskQuestion(Format(rsMsgDelToTrashForce, [WrapTextSimple(FileName)]), '', [fsourYes, fsourAll, fsourSkip, fsourSkipAll, fsourAbort], fsourYes, fsourAbort) of fsourYes: RemoveDirectly:= fsoogYes; fsourAll: begin FDeleteDirectly := fsoogYes; RemoveDirectly:= fsoogYes; end; fsourSkip: RemoveDirectly:= fsoogNo; fsourSkipAll: begin FDeleteDirectly := fsoogNo; RemoveDirectly:= fsoogNo; end; fsourAbort: RaiseAbortOperation; end; end; fsoogYes: RemoveDirectly:= fsoogYes; fsoogNo: RemoveDirectly:= fsoogNo; end; if RemoveDirectly = fsoogYes then begin if aFile.IsLink and aFile.IsDirectory then begin DeleteResult := RemoveDirectoryUAC(FileName); end else if aFile.IsDirectory then // directory begin DeleteSubDirectory(aFile); // This directory has already been processed. Exit; end else // files and other stuff begin DeleteResult := DeleteFileUAC(FileName); end; end; end; end; if DeleteResult then begin // success // process comments if need if gProcessComments then begin FDescription.DeleteDescription(FileName); if mbCompareFileNames(aFile.Name, DESCRIPT_ION) then FDescription.Reset; end; if aFile.IsDirectory then begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogRmDir, [FileName]), [log_dir_op, log_delete], lmtSuccess); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogDelete, [FileName]), [log_delete], lmtSuccess); end; end else // error begin if aFile.IsDirectory then begin logOptions := [log_dir_op, log_delete]; sMessage := Format(rsMsgLogError + rsMsgLogRmDir, [FileName]); sQuestion := Format(rsMsgCannotDeleteDirectory, [FileName]); end else begin logOptions := [log_delete]; sMessage := Format(rsMsgLogError + rsMsgLogDelete, [FileName]); sQuestion := Format(rsMsgNotDelete, [FileName]); end; if FSkipErrors or (RemoveDirectly = fsoogNo) then LogMessage(sMessage, logOptions, lmtError) else begin if (FRecycle = False) or (RemoveDirectly = fsoogYes) then begin LastError:= GetLastOSError; {$IF DEFINED(MSWINDOWS)} if GetFileInUseProcessFast(FileName, ProcessInfo) then begin sQuestion+= LineEnding + LineEnding + rsMsgOpenInAnotherProgram + LineEnding; sQuestion+= LineEnding + Format(rsMsgProcessId, [ProcessInfo[0].ProcessId]) + LineEnding; if (Length(ProcessInfo[0].ApplicationName) > 0) then begin sQuestion+= Format(rsMsgApplicationName, [ProcessInfo[0].ApplicationName]) + LineEnding; end; if (Length(ProcessInfo[0].ExecutablePath) > 0) then begin sQuestion+= Format(rsMsgExecutablePath, [ProcessInfo[0].ExecutablePath]) + LineEnding; end; end else {$ENDIF} sQuestion+= LineEnding + mbSysErrorMessage(LastError); end; {$IF DEFINED(MSWINDOWS)} if (ElevateAction <> dupAccept) and ElevationRequired(LastError) then begin SetLength(PossibleResponses, Length(ResponsesError) + 1); Move(ResponsesError[0], PossibleResponses[0], SizeOf(ResponsesError)); PossibleResponses[High(PossibleResponses)]:= fsourRetryAdmin; end else {$ENDIF} begin SetLength(PossibleResponses, Length(ResponsesError)); Move(ResponsesError[0], PossibleResponses[0], SizeOf(ResponsesError)); end; {$IF DEFINED(MSWINDOWS)} if (Length(ProcessInfo) > 0) or (LastError = ERROR_ACCESS_DENIED) or (LastError = ERROR_SHARING_VIOLATION) then begin SetLength(PossibleResponses, Length(PossibleResponses) + 1); PossibleResponses[High(PossibleResponses)]:= fsourUnlock; end; {$ENDIF} case AskQuestion(sQuestion, '', PossibleResponses, fsourRetry, fsourAbort) of fsourRetry: bRetry := True; fsourSkipAll: FSkipErrors := True; fsourAbort: RaiseAbortOperation; {$IF DEFINED(MSWINDOWS)} fsourRetryAdmin: begin bRetry:= True; ElevateAction:= dupAccept; end; fsourUnlock: begin bRetry:= True; GetFileInUseProcessSlow(FileName, LastError, ProcessInfo); ShowUnlockForm(ProcessInfo); end; {$ENDIF} end; end; end; until bRetry = False; end; procedure TFileSystemDeleteOperation.ProcessList(aFiles: TFiles); var aFile: TFile; CurrentFileIndex: Integer; begin for CurrentFileIndex := aFiles.Count - 1 downto 0 do begin aFile := aFiles[CurrentFileIndex]; FStatistics.CurrentFile := aFile.FullPath; UpdateStatistics(FStatistics); ProcessFile(aFile); with FStatistics do begin DoneFiles := DoneFiles + 1; DoneBytes := DoneBytes + aFile.Size; end; UpdateStatistics(FStatistics); AppProcessMessages(); CheckOperationState; end; end; function TFileSystemDeleteOperation.ShowError(sMessage: String): TFileSourceOperationUIResponse; begin if FSkipErrors then begin logWrite(Thread, sMessage, lmtError, True); Result := fsourSkip; end else begin Result := AskQuestion(sMessage, '', [fsourSkip, fsourCancel], fsourSkip, fsourCancel); if Result = fsourCancel then RaiseAbortOperation; end; end; procedure TFileSystemDeleteOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemexecuteoperation.pas�������������������������0000644�0001750�0000144�00000004727�14743153644�026500� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource, uFileSourceExecuteOperation, uFileSystemFileSource, uFile; type { TFileSystemExecuteOperation } TFileSystemExecuteOperation = class(TFileSourceExecuteOperation) private FFileSystemFileSource: IFileSystemFileSource; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses Forms, Controls, DCOSUtils, uOSUtils, uOSForms, uShellContextMenu, uExceptions; constructor TFileSystemExecuteOperation.Create( aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FFileSystemFileSource := aTargetFileSource as IFileSystemFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TFileSystemExecuteOperation.Initialize; begin Screen.Cursor:= crHourGlass; end; procedure TFileSystemExecuteOperation.MainExecute; var aFiles: TFiles; begin if Verb = 'properties' then begin FExecuteOperationResult:= fseorSuccess; aFiles:= TFiles.Create(ExecutableFile.Path); try aFiles.Add(ExecutableFile.Clone); try Screen.Cursor:= crDefault; ShowFilePropertiesDialog(FFileSystemFileSource, aFiles); except on E: EContextMenuException do ShowException(E); end; finally FreeAndNil(aFiles); end; Exit; end; // if file is link to folder then return fseorSymLink if FileIsLinkToFolder(AbsolutePath, FResultString) then begin FExecuteOperationResult:= fseorSymLink; Exit; end; // try to open by system mbSetCurrentDir(CurrentPath); case ShellExecute(AbsolutePath) of True: FExecuteOperationResult:= fseorSuccess; False: FExecuteOperationResult:= fseorError; end; end; procedure TFileSystemExecuteOperation.Finalize; begin Screen.Cursor:= crDefault; end; end. �����������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemfilesource.pas�������������������������������0000644�0001750�0000144�00000104203�14743153644�025243� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceOperationTypes, uLocalFileSource, uFileSource, uFileSourceProperty, uFileProperty, uFile, uDescr, DCBasicTypes, DCStrUtils, uFindEx ; type {en Real file system. } IFileSystemFileSource = interface(ILocalFileSource) ['{59EDCF45-F151-4AE2-9DCE-3586E6191496}'] end; { TFileSystemFileSource } TFileSystemFileSource = class(TLocalFileSource, IFileSystemFileSource) private FDescr: TDescription; protected function GetCurrentWorkingDirectory: String; override; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; procedure DoReload(const PathsToReload: TPathsArray); override; public constructor Create; override; destructor Destroy; override; class function CreateFile(const APath: String): TFile; override; class function CreateFile(const APath: String; pSearchRecord: PSearchRecEx): TFile; overload; {en Creates a file object using an existing file/directory as a template. All the properties will reflect the existing file. @param(FilePath denotes absolute path to a file to use as a template.) } class function CreateFileFromFile(const aFilePath: String): TFile; {en Creates file list from a list of template files. @param(APath Path to which the files names are relative.) @param(FileNamesList A list of absolute paths to files.) @param(OmitNotExisting If @true then silently omits not existing files. If @false an exception is raised when file not exists.) } class function CreateFilesFromFileList(const APath: String; const FileNamesList: TStringList; OmitNotExisting: Boolean = False): TFiles; procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); override; class function GetFileSource: IFileSystemFileSource; function GetSupportedFileProperties: TFilePropertiesTypes; override; function GetRetrievableFileProperties: TFilePropertiesTypes; override; function GetOperationsTypes: TFileSourceOperationTypes; override; function GetProperties: TFileSourceProperties; override; function IsPathAtRoot(Path: String): Boolean; override; function GetParentDir(sPath : String): String; override; function GetRootDir(sPath: String): String; override; overload; function GetRootDir: String; override; overload; function GetPathType(sPath : String): TPathType; override; function CreateDirectory(const Path: String): Boolean; override; function FileSystemEntryExists(const Path: String): Boolean; override; function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; override; function CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; override; function CreateCombineOperation(var SourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; override; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override; // ------------------------------------------------------ property Description: TDescription read FDescr; end; { TFileSystemFileSourceConnection } TFileSystemFileSourceConnection = class(TFileSourceConnection) protected procedure SetCurrentPath(NewPath: String); override; end; implementation uses uOSUtils, DCOSUtils, DCDateTimeUtils, uGlobs, uGlobsPaths, uLog, uLng, {$IFDEF MSWINDOWS} DCWindows, uMyWindows, Windows, {$ENDIF} {$IFDEF UNIX} BaseUnix, uUsersGroups, LazUTF8, DCUnix, uMyUnix, {$IFDEF DARWIN} uMyDarwin, {$ENDIF} {$IFDEF LINUX} statx, {$ENDIF} {$ENDIF} uFileFunctions, uFileSystemListOperation, uFileSystemCopyOperation, uFileSystemMoveOperation, uFileSystemDeleteOperation, uFileSystemWipeOperation, uFileSystemSplitOperation, uFileSystemCombineOperation, uFileSystemCreateDirectoryOperation, uFileSystemExecuteOperation, uFileSystemCalcChecksumOperation, uFileSystemCalcStatisticsOperation, uFileSystemSetFilePropertyOperation; {$IF DEFINED(MSWINDOWS)} procedure SetOwner(AFile: TFile); var sUser, sGroup: String; begin with AFile do begin OwnerProperty := TFileOwnerProperty.Create; if GetFileOwner(FullPath, sUser, sGroup) then begin OwnerProperty.OwnerStr := sUser; OwnerProperty.GroupStr := sGroup; end; end; end; procedure FillLinkProperty(const AFilePath: String; dwAttrs: DWORD; LinkProperty: TFileLinkProperty); var LinkAttrs: TFileAttrs; begin LinkProperty.LinkTo := ReadSymLink(AFilePath); if StrBegins(LinkProperty.LinkTo, 'Volume{') then begin LinkProperty.IsLinkToDirectory := True; LinkProperty.IsValid:= mbDriveReady(AFilePath + PathDelim); end else begin LinkAttrs := mbFileGetAttrNoLinks(AFilePath); LinkProperty.IsValid := LinkAttrs <> faInvalidAttributes; if LinkProperty.IsValid then LinkProperty.IsLinkToDirectory := fpS_ISDIR(LinkAttrs) else begin // On Windows links to directories are marked with Directory flag on the link. LinkProperty.IsLinkToDirectory := fpS_ISDIR(dwAttrs); end; end; end; procedure FillFromFindData( AFile: TFile; AFilePath: String; pFindData: PWIN32FINDDATAW); begin with AFile do begin AttributesProperty := TNtfsFileAttributesProperty.Create( pFindData^.dwFileAttributes); SizeProperty := TFileSizeProperty.Create( QWord(pFindData^.nFileSizeHigh) shl 32 + pFindData^.nFileSizeLow); ModificationTimeProperty := TFileModificationDateTimeProperty.Create( WinFileTimeToDateTime(pFindData^.ftLastWriteTime)); CreationTimeProperty := TFileCreationDateTimeProperty.Create( WinFileTimeToDateTime(pFindData^.ftCreationTime)); LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create( WinFileTimeToDateTime(pFindData^.ftLastAccessTime)); LinkProperty := TFileLinkProperty.Create; if fpS_ISLNK(pFindData^.dwFileAttributes) then begin FillLinkProperty(AFilePath, pFindData^.dwFileAttributes, LinkProperty); end; end; end; {$ELSEIF DEFINED(UNIX)} procedure FillFromStat( AFile: TFile; AFilePath: String; pStatInfo: PDCStat); var LinkStatInfo: BaseUnix.Stat; begin with AFile do begin AttributesProperty := TUnixFileAttributesProperty.Create(pStatInfo^.st_mode); if fpS_ISDIR(pStatInfo^.st_mode) then // On Unix a size for directory entry on filesystem is returned in StatInfo. // We don't want to use it. SizeProperty := TFileSizeProperty.Create(0) else SizeProperty := TFileSizeProperty.Create(Int64(pStatInfo^.st_size)); ModificationTimeProperty := TFileModificationDateTimeProperty.Create( FileTimeToDateTimeEx(pStatInfo^.mtime)); Properties[fpChangeTime] := TFileChangeDateTimeProperty.Create( FileTimeToDateTimeEx(pStatInfo^.ctime)); LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create( FileTimeToDateTimeEx(pStatInfo^.atime)); LinkProperty := TFileLinkProperty.Create; if fpS_ISLNK(pStatInfo^.st_mode) then begin LinkProperty.LinkTo := ReadSymLink(AFilePath); // Stat (as opposed to Lstat) will take info of the file that the link points to (recursively). LinkProperty.IsValid := fpStat(UTF8ToSys(AFilePath), LinkStatInfo) = 0; if LinkProperty.IsValid then begin LinkProperty.IsLinkToDirectory := FPS_ISDIR(LinkStatInfo.st_mode); if LinkProperty.IsLinkToDirectory then SizeProperty.Value := 0; end; end; end; end; {$ELSE} procedure FillFromSearchRecord( AFile: TFile; AFilePath: String; pSearchRecord: PSearchRecEx; PropertiesToSet: TFilePropertiesTypes = []); begin with AFile do begin AttributesProperty := TFileAttributesProperty.Create(pSearchRecord^.Attr); SizeProperty := TFileSizeProperty.Create(pSearchRecord^.Size); ModificationTimeProperty := TFileModificationDateTimeProperty.Create(pSearchRecord^.Time); CreationTimeProperty := TFileCreationDateTimeProperty.Create(pSearchRecord^.Time); LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create(pSearchRecord^.Time); LinkProperty := TFileLinkProperty.Create; end; end; {$ENDIF} // ---------------------------------------------------------------------------- constructor TFileSystemFileSource.Create; begin inherited Create; FDescr := TDescription.Create(False); FOperationsClasses[fsoList] := TFileSystemListOperation.GetOperationClass; FOperationsClasses[fsoCopy] := TFileSystemCopyOperation.GetOperationClass; FOperationsClasses[fsoCopyIn] := TFileSystemCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TFileSystemCopyOutOperation.GetOperationClass; FOperationsClasses[fsoMove] := TFileSystemMoveOperation.GetOperationClass; FOperationsClasses[fsoDelete] := TFileSystemDeleteOperation.GetOperationClass; FOperationsClasses[fsoWipe] := TFileSystemWipeOperation.GetOperationClass; FOperationsClasses[fsoCombine] := TFileSystemCombineOperation.GetOperationClass; FOperationsClasses[fsoCreateDirectory] := TFileSystemCreateDirectoryOperation.GetOperationClass; FOperationsClasses[fsoCalcChecksum] := TFileSystemCalcChecksumOperation.GetOperationClass; FOperationsClasses[fsoCalcStatistics] := TFileSystemCalcStatisticsOperation.GetOperationClass; FOperationsClasses[fsoSetFileProperty] := TFileSystemSetFilePropertyOperation.GetOperationClass; FOperationsClasses[fsoExecute] := TFileSystemExecuteOperation.GetOperationClass; end; destructor TFileSystemFileSource.Destroy; begin inherited Destroy; FDescr.Free; end; class function TFileSystemFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes; SizeProperty := TFileSizeProperty.Create; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; CreationTimeProperty := TFileCreationDateTimeProperty.Create; LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create; LinkProperty := TFileLinkProperty.Create; OwnerProperty := TFileOwnerProperty.Create; TypeProperty := TFileTypeProperty.Create; CommentProperty := TFileCommentProperty.Create; end; end; class function TFileSystemFileSource.CreateFile(const APath: String; pSearchRecord: PSearchRecEx): TFile; var AFilePath: String; LinkAttrs: TFileAttrs; begin Result := TFile.Create(APath); with Result do begin {$IF DEFINED(UNIX)} ChangeTimeProperty := TFileChangeDateTimeProperty.Create(UnixFileTimeToDateTimeEx(pSearchRecord^.FindData.ctime)); {$IF DEFINED(DARWIN)} CreationTimeProperty := TFileCreationDateTimeProperty.Create(UnixFileTimeToDateTimeEx(pSearchRecord^.FindData.birthtime)); {$ENDIF} ModificationTimeProperty := TFileModificationDateTimeProperty.Create(UnixFileTimeToDateTimeEx(pSearchRecord^.FindData.mtime)); LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create(UnixFileTimeToDateTimeEx(pSearchRecord^.FindData.atime)); {$ELSE} CreationTimeProperty := TFileCreationDateTimeProperty.Create(DCBasicTypes.TFileTime(pSearchRecord^.PlatformTime)); ModificationTimeProperty := TFileModificationDateTimeProperty.Create(pSearchRecord^.Time); LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create(DCBasicTypes.TFileTime(pSearchRecord^.LastAccessTime)); {$ENDIF} SizeProperty := TFileSizeProperty.Create(pSearchRecord^.Size); AttributesProperty := TFileAttributesProperty.CreateOSAttributes(pSearchRecord^.Attr); LinkProperty := TFileLinkProperty.Create; if fpS_ISLNK(pSearchRecord^.Attr) then begin AFilePath:= Path + pSearchRecord^.Name; LinkAttrs := mbFileGetAttrNoLinks(AFilePath); LinkProperty.LinkTo := ReadSymLink(AFilePath); LinkProperty.IsValid := LinkAttrs <> faInvalidAttributes; {$IF DEFINED(UNIX)} if LinkProperty.IsValid then begin LinkProperty.IsLinkToDirectory := fpS_ISDIR(LinkAttrs); if LinkProperty.IsLinkToDirectory then SizeProperty.Value := 0; end; {$ELSE} if StrBegins(LinkProperty.LinkTo, 'Volume{') then begin LinkProperty.IsLinkToDirectory := True; LinkProperty.IsValid:= mbDriveReady(AFilePath + PathDelim); end else if LinkProperty.IsValid then LinkProperty.IsLinkToDirectory := fpS_ISDIR(LinkAttrs) else begin // On Windows links to directories are marked with Directory flag on the link. LinkProperty.IsLinkToDirectory := fpS_ISDIR(pSearchRecord^.Attr); end; {$ENDIF} end; end; // Set name after assigning Attributes property, because it is used to get extension. Result.Name := pSearchRecord^.Name; end; class function TFileSystemFileSource.CreateFileFromFile(const aFilePath: String): TFile; var {$IF DEFINED(MSWINDOWS)} FindData: TWIN32FINDDATAW; FindHandle: THandle; {$ELSEIF DEFINED(UNIX)} StatInfo: TDCStat; {$ELSE} SearchRecord: TSearchRecEx; FindResult: Longint; {$ENDIF} begin Result := nil; {$IF DEFINED(MSWINDOWS)} FindHandle := FindFirstFileW(PWideChar(UTF16LongName(aFilePath)), @FindData); if FindHandle = INVALID_HANDLE_VALUE then raise EFileNotFound.Create(aFilePath); Windows.FindClose(FindHandle); FindData.dwFileAttributes:= ExtractFileAttributes(FindData); Result := TFile.Create(ExtractFilePath(aFilePath)); FillFromFindData(Result, aFilePath, @FindData); {$ELSEIF DEFINED(UNIX)} if DC_fpLstat(UTF8ToSys(AFilePath), StatInfo) = -1 then raise EFileNotFound.Create(aFilePath); Result := TFile.Create(ExtractFilePath(aFilePath)); FillFromStat(Result, aFilePath, @StatInfo); {$ELSE} FindResult := FindFirstEx(aFilePath, 0, SearchRecord); try if FindResult <> 0 then raise EFileNotFound.Create(aFilePath); Result := TFile.Create(ExtractFilePath(aFilePath)); FillFromSearchRecord(Result, aFilePath, @SearchRecord); finally FindCloseEx(SearchRecord); end; {$ENDIF} // Set name after assigning Attributes property, because it is used to get extension. Result.FullPath := aFilePath; end; class function TFileSystemFileSource.CreateFilesFromFileList( const APath: String; const FileNamesList: TStringList; OmitNotExisting: Boolean): TFiles; var i: Integer; begin Result := TFiles.Create(APath); if Assigned(FileNamesList) and (FileNamesList.Count > 0) then begin for i := 0 to FileNamesList.Count - 1 do begin try Result.Add(CreateFileFromFile(FileNamesList[i])); except on EFileNotFound do if not OmitNotExisting then begin FreeAndNil(Result); raise; end; on Exception do begin FreeAndNil(Result); raise; end; end; end; end; end; procedure TFileSystemFileSource.RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); var AIndex: Integer; sFullPath: String; Attrs: TFileAttrs; AProp: TFilePropertyType; AProps: TFilePropertiesTypes; AVariant: TFileVariantProperty; {$IF DEFINED(LINUX)} StatXInfo: TStatX; {$ENDIF} {$IF DEFINED(UNIX)} StatInfo: TDCStat; LinkInfo: BaseUnix.Stat; //buffer for stat info {$ELSEIF DEFINED(MSWINDOWS)} FindData: TWIN32FINDDATAW; FindHandle: THandle; {$ELSE} SearchRec: TSearchRecEx; {$ENDIF} begin AProps := AFile.AssignedProperties; // Omit properties that are already assigned. PropertiesToSet := PropertiesToSet - AProps; if PropertiesToSet = [] then Exit; // Already have requested properties. // Assume that Name property is always present. sFullPath := AFile.FullPath; with AFile do begin {$IF DEFINED(MSWINDOWS)} // Check if need to get file info record. if ([fpAttributes, fpSize, fpModificationTime, fpCreationTime, fpLastAccessTime] * PropertiesToSet <> []) or ((fpLink in PropertiesToSet) and (not (fpAttributes in AProps))) then begin FindHandle := FindFirstFileW(PWideChar(UTF16LongName(sFullPath)), @FindData); if FindHandle = INVALID_HANDLE_VALUE then raise EFileNotFound.Create(sFullPath); Windows.FindClose(FindHandle); FindData.dwFileAttributes:= ExtractFileAttributes(FindData); if not (fpAttributes in AProps) then AttributesProperty := TNtfsFileAttributesProperty.Create( FindData.dwFileAttributes); if not (fpSize in AProps) then SizeProperty := TFileSizeProperty.Create( QWord(FindData.nFileSizeHigh) shl 32 + FindData.nFileSizeLow); if not (fpModificationTime in AProps) then ModificationTimeProperty := TFileModificationDateTimeProperty.Create( WinFileTimeToDateTime(FindData.ftLastWriteTime)); if not (fpCreationTime in AProps) then CreationTimeProperty := TFileCreationDateTimeProperty.Create( WinFileTimeToDateTime(FindData.ftCreationTime)); if not (fpLastAccessTime in AProps) then LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create( WinFileTimeToDateTime(FindData.ftLastAccessTime)); end; if fpLink in PropertiesToSet then begin Attrs := Attributes; LinkProperty := TFileLinkProperty.Create; if fpS_ISLNK(Attrs) then begin FillLinkProperty(sFullPath, Attrs, LinkProperty); end; end; if fpOwner in PropertiesToSet then begin SetOwner(AFile); end; if fpType in PropertiesToSet then begin TypeProperty := TFileTypeProperty.Create; TypeProperty.Value := GetFileDescription(sFullPath); end; if fpCompressedSize in PropertiesToSet then begin CompressedSizeProperty := TFileCompressedSizeProperty.Create; CompressedSizeProperty.Value := mbGetCompressedFileSize(sFullPath); end; if fpChangeTime in PropertiesToSet then begin ChangeTimeProperty := TFileChangeDateTimeProperty.Create(MinDateTime); ChangeTimeProperty.IsValid := mbGetFileChangeTime(sFullPath, FindData.ftCreationTime); if ChangeTimeProperty.IsValid then begin ChangeTimeProperty.Value := WinFileTimeToDateTime(FindData.ftCreationTime); end; end; {$ELSEIF DEFINED(UNIX)} if ([fpAttributes, fpSize, fpModificationTime, fpChangeTime, fpLastAccessTime, fpOwner] * PropertiesToSet <> []) or ((uFileProperty.fpLink in PropertiesToSet) and (not (fpAttributes in AssignedProperties))) then begin if DC_fpLStat(UTF8ToSys(sFullPath), StatInfo) = -1 then raise EFileNotFound.Create(sFullPath); if not (fpAttributes in AssignedProperties) then AttributesProperty := TUnixFileAttributesProperty.Create(StatInfo.st_mode); if not (fpSize in AssignedProperties) then begin if fpS_ISDIR(StatInfo.st_mode) then // On Unix a size for directory entry on filesystem is returned in StatInfo. // We don't want to use it. SizeProperty := TFileSizeProperty.Create(0) else SizeProperty := TFileSizeProperty.Create(Int64(StatInfo.st_size)); end; if not (fpModificationTime in AssignedProperties) then ModificationTimeProperty := TFileModificationDateTimeProperty.Create( FileTimeToDateTimeEx(StatInfo.mtime)); if not (fpChangeTime in AssignedProperties) then Properties[fpChangeTime] := TFileChangeDateTimeProperty.Create( FileTimeToDateTimeEx(StatInfo.ctime)); if not (fpLastAccessTime in AssignedProperties) then LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create( FileTimeToDateTimeEx(StatInfo.atime)); {$IF DEFINED(DARWIN)} if not (fpCreationTime in AssignedProperties) then CreationTimeProperty := TFileCreationDateTimeProperty.Create( FileTimeToDateTimeEx(StatInfo.birthtime)); {$ENDIF} end; if uFileProperty.fpLink in PropertiesToSet then begin Attrs := Attributes; LinkProperty := TFileLinkProperty.Create; if fpS_ISLNK(Attrs) then begin LinkProperty.LinkTo := ReadSymLink(sFullPath); // Stat (as opposed to Lstat) will take info of the file that the link points to (recursively). LinkProperty.IsValid := fpStat(UTF8ToSys(sFullPath), LinkInfo) = 0; if LinkProperty.IsValid then begin LinkProperty.IsLinkToDirectory := FPS_ISDIR(LinkInfo.st_mode); end; end; end; if fpOwner in PropertiesToSet then begin OwnerProperty := TFileOwnerProperty.Create; OwnerProperty.Owner := StatInfo.st_uid; OwnerProperty.Group := StatInfo.st_gid; OwnerProperty.OwnerStr := UIDToStr(StatInfo.st_uid); OwnerProperty.GroupStr := GIDToStr(StatInfo.st_gid); end; if fpType in PropertiesToSet then begin TypeProperty := TFileTypeProperty.Create; {$IF DEFINED(DARWIN)} TypeProperty.Value:= GetFileDescription(sFullPath); {$ELSE} TypeProperty.Value:= GetFileMimeType(sFullPath); {$ENDIF} end; {$IF DEFINED(LINUX)} if fpCreationTime in PropertiesToSet then begin CreationTimeProperty := TFileCreationDateTimeProperty.Create(MinDateTime); CreationTimeProperty.IsValid := HasStatX and (fpstatx(0, sFullPath, 0, STATX_BTIME, @StatXInfo) >= 0) and (StatXInfo.stx_mask and STATX_BTIME <> 0) and (StatXInfo.stx_btime.tv_sec > 0); if CreationTimeProperty.IsValid then begin CreationTimeProperty.Value:= FileTimeToDateTimeEx(TFileTimeEx.Create(Int64(StatXInfo.stx_btime.tv_sec), Int64(StatXInfo.stx_btime.tv_nsec))); end; end; {$ENDIF} {$ELSE} if FindFirstEx(sFullPath, 0, SearchRec) = -1 then raise EFileNotFound.Create(sFullPath); if not (fpAttributes in AssignedProperties) then AttributesProperty := TFileAttributesProperty.Create(SearchRec.Attr); if not (fpSize in AssignedProperties) then SizeProperty := TFileSizeProperty.Create(SearchRec.Size); if not (fpModificationTime in AssignedProperties) then ModificationTimeProperty := TFileModificationDateTimeProperty.Create(SearchRec.Time); if not (fpCreationTime in AssignedProperties) then CreationTimeProperty := TFileCreationDateTimeProperty.Create(SearchRec.Time); if not (fpLastAccessTime in AssignedProperties) then LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create(SearchRec.Time); FindCloseEx(SearchRec); if fpLink in PropertiesToSet then LinkProperty := TFileLinkProperty.Create; if fpOwner in PropertiesToSet then OwnerProperty := TFileOwnerProperty.Create; if fpType in PropertiesToSet then TypeProperty := TFileTypeProperty.Create; {$ENDIF} if fpComment in PropertiesToSet then begin CommentProperty := TFileCommentProperty.Create; CommentProperty.Value := FDescr.ReadDescription(sFullPath); end; PropertiesToSet:= PropertiesToSet * fpVariantAll; for AProp in PropertiesToSet do begin AIndex:= Ord(AProp) - Ord(fpVariant); if (AIndex >= 0) and (AIndex <= High(AVariantProperties)) then begin AVariant:= TFileVariantProperty.Create(AVariantProperties[AIndex]); AVariant.Value:= GetVariantFileProperty(AVariantProperties[AIndex], AFile, Self); Properties[AProp]:= AVariant; end; end; end; end; class function TFileSystemFileSource.GetFileSource: IFileSystemFileSource; var aFileSource: IFileSource; begin aFileSource := FileSourceManager.Find(TFileSystemFileSource, ''); if not Assigned(aFileSource) then Result := TFileSystemFileSource.Create else Result := aFileSource as IFileSystemFileSource; end; function TFileSystemFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoList, fsoCopy, fsoCopyIn, fsoCopyOut, fsoMove, fsoDelete, fsoWipe, fsoSplit, fsoCombine, fsoCreateDirectory, fsoCalcChecksum, fsoCalcStatistics, fsoSetFileProperty, fsoExecute]; end; function TFileSystemFileSource.GetProperties: TFileSourceProperties; begin Result := [ fspDirectAccess, fspListFlatView, fspNoneParent {$IFDEF UNIX} , fspCaseSensitive {$ENDIF} ]; end; function TFileSystemFileSource.GetCurrentWorkingDirectory: String; begin Result := mbGetCurrentDir(); if Result <> '' then Result := IncludeTrailingPathDelimiter(Result); end; function TFileSystemFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin if not mbDirectoryExists(NewDir) then Result := False else Result := mbSetCurrentDir(NewDir); end; procedure TFileSystemFileSource.DoReload(const PathsToReload: TPathsArray); begin FDescr.Reset; end; function TFileSystemFileSource.IsPathAtRoot(Path: String): Boolean; var sPath: String; begin sPath := ExcludeTrailingPathDelimiter(Path); if (Pos('\\', sPath) = 1) and (NumCountChars(PathDelim, sPath) = 3) then Exit(True); Result := (DCStrUtils.GetParentDir(Path) = ''); end; function TFileSystemFileSource.GetParentDir(sPath: String): String; begin Result:= inherited GetParentDir(sPath); Result:= GetDeepestExistingPath(Result); if Length(Result) = 0 then Result:= gpExePath; end; function TFileSystemFileSource.GetRootDir(sPath : String): String; begin Result := DCStrUtils.GetRootDir(sPath); end; function TFileSystemFileSource.GetRootDir: String; begin Result := Self.GetRootDir(mbGetCurrentDir); end; function TFileSystemFileSource.GetPathType(sPath : String): TPathType; begin Result := DCStrUtils.GetPathType(sPath); end; function TFileSystemFileSource.CreateDirectory(const Path: String): Boolean; begin Result := mbCreateDir(Path); if Result then begin if (log_dir_op in gLogOptions) and (log_success in gLogOptions) then logWrite(Format(rsMsgLogSuccess + rsMsgLogMkDir, [Path]), lmtSuccess); end else begin if (log_dir_op in gLogOptions) and (log_errors in gLogOptions) then logWrite(Format(rsMsgLogError + rsMsgLogMkDir, [Path]), lmtError); end; end; function TFileSystemFileSource.FileSystemEntryExists(const Path: String): Boolean; begin Result:= mbFileSystemEntryExists(Path); end; function TFileSystemFileSource.GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; begin Result := uOSUtils.GetDiskFreeSpace(Path, FreeSize, TotalSize); end; function TFileSystemFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpSize, fpAttributes, fpModificationTime, {$IF DEFINED(MSWINDOWS)} fpCreationTime, {$ELSE} fpChangeTime, {$ENDIF} fpLastAccessTime, uFileProperty.fpLink ]; end; function TFileSystemFileSource.GetRetrievableFileProperties: TFilePropertiesTypes; begin Result := inherited GetRetrievableFileProperties + [fpSize, fpAttributes, fpModificationTime, {$IF DEFINED(MSWINDOWS)} fpCreationTime, {$ENDIF} fpChangeTime, fpLastAccessTime, uFileProperty.fpLink, fpOwner, fpType, fpComment {$IF DEFINED(MSWINDOWS)} , fpCompressedSize {$ENDIF} ] + fpVariantAll; {$IF DEFINED(LINUX)} if HasStatX then Result += [fpCreationTime]; {$ENDIF} end; function TFileSystemFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemListOperation.Create(TargetFileSource, TargetPath); end; function TFileSystemFileSource.CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var FileSource: IFileSource; begin FileSource := Self; Result := TFileSystemCopyOperation.Create(FileSource, FileSource, SourceFiles, TargetPath); end; function TFileSystemFileSource.CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemCopyInOperation.Create( SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TFileSystemFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TFileSystemCopyOutOperation.Create( SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TFileSystemFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemMoveOperation.Create(TargetFileSource, SourceFiles, TargetPath); end; function TFileSystemFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemDeleteOperation.Create(TargetFileSource, FilesToDelete); end; function TFileSystemFileSource.CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemWipeOperation.Create(TargetFileSource, FilesToWipe); end; function TFileSystemFileSource.CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TFileSystemSplitOperation.Create(SourceFileSource, aSourceFile, aTargetPath); end; function TFileSystemFileSource.CreateCombineOperation(var SourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TFileSystemCombineOperation.Create(SourceFileSource, SourceFiles, aTargetFile); end; function TFileSystemFileSource.CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemCreateDirectoryOperation.Create(TargetFileSource, BasePath, DirectoryPath); end; function TFileSystemFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TFileSystemExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; function TFileSystemFileSource.CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemCalcChecksumOperation.Create( TargetFileSource, theFiles, aTargetPath, aTargetMask); end; function TFileSystemFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemCalcStatisticsOperation.Create(TargetFileSource, theFiles); end; function TFileSystemFileSource.CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TFileSystemSetFilePropertyOperation.Create( TargetFileSource, theTargetFiles, theNewProperties); end; { TFileSystemFileSourceConnection } procedure TFileSystemFileSourceConnection.SetCurrentPath(NewPath: String); begin if not mbDirectoryExists(NewPath) then NewPath := mbGetCurrentDir else mbSetCurrentDir(NewPath); inherited SetCurrentPath(NewPath); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemlistoperation.pas����������������������������0000644�0001750�0000144�00000004251�14743153644�026001� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uFileSource ; type { TFileSystemListOperation } TFileSystemListOperation = class(TFileSourceListOperation) private procedure FlatView(const APath: String); public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses DCOSUtils, uFile, uFindEx, uOSUtils, uFileSystemFileSource; procedure TFileSystemListOperation.FlatView(const APath: String); var AFile: TFile; sr: TSearchRecEx; begin try if FindFirstEx(APath + '*', 0, sr) = 0 then repeat CheckOperationState; if (sr.Name = '.') or (sr.Name = '..') then Continue; if FPS_ISDIR(sr.Attr) then FlatView(APath + sr.Name + DirectorySeparator) else begin AFile := TFileSystemFileSource.CreateFile(APath, @sr); FFiles.Add(AFile); end; until FindNextEx(sr) <> 0; finally FindCloseEx(sr); end; end; constructor TFileSystemListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); inherited Create(aFileSource, aPath); end; procedure TFileSystemListOperation.MainExecute; var AFile: TFile; sr: TSearchRecEx; IsRootPath, Found: Boolean; begin FFiles.Clear; if FFlatView then begin FlatView(Path); Exit; end; IsRootPath := FileSource.IsPathAtRoot(Path); Found := FindFirstEx(FFiles.Path + '*', 0, sr) = 0; try if not Found then begin { No files have been found. } if not IsRootPath then begin AFile := TFileSystemFileSource.CreateFile(Path); AFile.Name := '..'; AFile.Attributes := faFolder; FFiles.Add(AFile); end; end else begin repeat CheckOperationState; if sr.Name='.' then Continue; // Don't include '..' in the root directory. if (sr.Name='..') and IsRootPath then Continue; AFile := TFileSystemFileSource.CreateFile(Path, @sr); FFiles.Add(AFile); until FindNextEx(sr)<>0; end; finally FindCloseEx(sr); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemmoveoperation.pas����������������������������0000644�0001750�0000144�00000016226�14743153644�026001� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemMoveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceMoveOperation, uFileSource, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uFileSystemUtil, DCOSUtils, uSearchTemplate; type { TFileSystemMoveOperation } TFileSystemMoveOperation = class(TFileSourceMoveOperation) private FCopyAttributesOptions: TCopyAttributesOptions; FOperationHelper: TFileSystemOperationHelper; FExcludeEmptyTemplateDirectories: Boolean; FSearchTemplate: TSearchTemplate; FSetPropertyError: TFileSourceOperationOptionSetPropertyError; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceMoveOperationStatistics; // local copy of statistics // Options. FVerify, FReserveSpace, FCheckFreeSpace: Boolean; FSkipAllBigFiles: Boolean; FCorrectSymlinks: Boolean; FCopyOnWrite: TFileSourceOperationOptionGeneral; procedure SetSearchTemplate(AValue: TSearchTemplate); protected function Recursive: Boolean; public constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property Verify: Boolean read FVerify write FVerify; property CheckFreeSpace: Boolean read FCheckFreeSpace write FCheckFreeSpace; property ReserveSpace: Boolean read FReserveSpace write FReserveSpace; property CopyAttributesOptions: TCopyAttributesOptions read FCopyAttributesOptions write FCopyAttributesOptions; property SkipAllBigFiles: Boolean read FSkipAllBigFiles write FSkipAllBigFiles; property CorrectSymLinks: Boolean read FCorrectSymLinks write FCorrectSymLinks; property CopyOnWrite: TFileSourceOperationOptionGeneral read FCopyOnWrite write FCopyOnWrite; property SetPropertyError: TFileSourceOperationOptionSetPropertyError read FSetPropertyError write FSetPropertyError; property ExcludeEmptyTemplateDirectories: Boolean read FExcludeEmptyTemplateDirectories write FExcludeEmptyTemplateDirectories; {en Operation takes ownership of assigned template and will free it. } property SearchTemplate: TSearchTemplate read FSearchTemplate write SetSearchTemplate; end; implementation uses fFileSystemCopyMoveOperationOptions, uGlobs; constructor TFileSystemMoveOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin // Here we can read global settings if there are any FSetPropertyError := gOperationOptionSetPropertyError; FReserveSpace := gOperationOptionReserveSpace; FCheckFreeSpace := gOperationOptionCheckFreeSpace; FSkipAllBigFiles := False; FCorrectSymLinks := gOperationOptionCorrectLinks; FExcludeEmptyTemplateDirectories := True; inherited Create(aFileSource, theSourceFiles, aTargetPath); // Here we can read global settings if there are any FCopyOnWrite := gOperationOptionCopyOnWrite; FFileExistsOption := gOperationOptionFileExists; FDirExistsOption := gOperationOptionDirectoryExists; if gOperationOptionCopyAttributes then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyAttributes]; if gOperationOptionCopyXattributes then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyXattributes]; if gOperationOptionCopyTime then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyTime]; if gOperationOptionCopyOwnership then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyOwnership]; if gOperationOptionCopyPermissions then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyPermissions]; if gDropReadOnlyFlag then FCopyAttributesOptions := FCopyAttributesOptions + [caoRemoveReadOnlyAttr]; end; destructor TFileSystemMoveOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); FreeAndNil(FOperationHelper); FreeAndNil(FSearchTemplate); end; procedure TFileSystemMoveOperation.Initialize; var TreeBuilder: TFileSystemTreeBuilder; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TFileSystemTreeBuilder.Create( @AskQuestion, @CheckOperationState); try TreeBuilder.Recursive := Recursive; // In move operation don't follow symlinks. TreeBuilder.SymLinkOption := fsooslDontFollow; TreeBuilder.SearchTemplate := Self.SearchTemplate; TreeBuilder.ExcludeEmptyTemplateDirectories := Self.ExcludeEmptyTemplateDirectories; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; if Assigned(FOperationHelper) then FreeAndNil(FOperationHelper); FOperationHelper := TFileSystemOperationHelper.Create( @AskQuestion, @RaiseAbortOperation, @AppProcessMessages, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, Thread, fsohmMove, TargetPath, FStatistics); FOperationHelper.Verify := FVerify; FOperationHelper.RenameMask := RenameMask; FOperationHelper.CopyOnWrite := FCopyOnWrite; FOperationHelper.ReserveSpace := FReserveSpace; FOperationHelper.CheckFreeSpace := CheckFreeSpace; FOperationHelper.CopyAttributesOptions := CopyAttributesOptions; FOperationHelper.SkipAllBigFiles := SkipAllBigFiles; FOperationHelper.CorrectSymLinks := CorrectSymLinks; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.DirExistsOption := DirExistsOption; FOperationHelper.SetPropertyError := SetPropertyError; FOperationHelper.Initialize; end; procedure TFileSystemMoveOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree); end; procedure TFileSystemMoveOperation.SetSearchTemplate(AValue: TSearchTemplate); begin FSearchTemplate.Free; FSearchTemplate := AValue; end; function TFileSystemMoveOperation.Recursive: Boolean; begin // First check that both paths on the same volume if not mbFileSameVolume(ExcludeTrailingBackslash(SourceFiles.Path), ExcludeTrailingBackslash(TargetPath)) then begin Exit(True); end; if ((RenameMask <> '*.*') and (RenameMask <> '')) or (FCorrectSymlinks) or Assigned(FSearchTemplate) then begin Exit(True); end; Result:= False; end; procedure TFileSystemMoveOperation.Finalize; begin FileExistsOption := FOperationHelper.FileExistsOption; FreeAndNil(FOperationHelper); end; class function TFileSystemMoveOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TFileSystemMoveOperationOptionsUI; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemsetfilepropertyoperation.pas�����������������0000644�0001750�0000144�00000034124�14743153644�030270� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemSetFilePropertyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LazUTF8, uFileSourceSetFilePropertyOperation, uFileSource, uFileSourceOperationOptions, uFileSourceOperationUI, uFile, uFileProperty, uDescr; type { TFileSystemSetFilePropertyOperation } TFileSystemSetFilePropertyOperation = class(TFileSourceSetFilePropertyOperation) private FFullFilesTree: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceSetFilePropertyOperationStatistics; // local copy of statistics FDescription: TDescription; // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; FFileExistsOption: TFileSourceOperationUIResponse; FDirExistsOption: TFileSourceOperationUIResponse; FCurrentFile: TFile; FCurrentTargetFilePath: String; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); function RenameFile(aFile: TFile; NewName: String): TSetFilePropertyResult; protected procedure ShowCompareFilesUI(SourceFile: TFile; const TargetFilePath: String); function SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; override; public constructor Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uGlobs, uLng, DCDateTimeUtils, uFileSystemUtil, uShowForm, DCOSUtils, DCStrUtils, DCBasicTypes, uAdministrator {$IF DEFINED(UNIX)} , BaseUnix, DCUnix {$ENDIF} ; constructor TFileSystemSetFilePropertyOperation.Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); begin FSymLinkOption := fsooslNone; FFullFilesTree := nil; inherited Create(aTargetFileSource, theTargetFiles, theNewProperties); // Assign after calling inherited constructor. FSupportedProperties := [fpName, {$IF DEFINED(UNIX)} // Set owner/group before MODE because it clears SUID bit. fpOwner, {$ENDIF} fpAttributes, fpModificationTime, fpCreationTime, fpLastAccessTime]; if gProcessComments then begin FDescription := TDescription.Create(False); end; end; destructor TFileSystemSetFilePropertyOperation.Destroy; begin inherited Destroy; if Recursive then begin if Assigned(FFullFilesTree) then FreeAndNil(FFullFilesTree); end; if Assigned(FDescription) then begin FDescription.SaveDescription; FreeAndNil(FDescription); end; end; procedure TFileSystemSetFilePropertyOperation.Initialize; var TotalBytes: Int64; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; if not Recursive then begin FFullFilesTree := TargetFiles; FStatistics.TotalFiles := FFullFilesTree.Count; end else begin FillAndCount(TargetFiles, True, False, FFullFilesTree, FStatistics.TotalFiles, TotalBytes); // gets full list of files (recursive) end; end; procedure TFileSystemSetFilePropertyOperation.MainExecute; var aFile: TFile; aTemplateFile: TFile; CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to FFullFilesTree.Count - 1 do begin aFile := FFullFilesTree[CurrentFileIndex]; FStatistics.CurrentFile := aFile.FullPath; UpdateStatistics(FStatistics); if Assigned(TemplateFiles) and (CurrentFileIndex < TemplateFiles.Count) then aTemplateFile := TemplateFiles[CurrentFileIndex] else aTemplateFile := nil; SetProperties(CurrentFileIndex, aFile, aTemplateFile); with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; CheckOperationState; end; end; procedure TFileSystemSetFilePropertyOperation.Finalize; begin end; function TFileSystemSetFilePropertyOperation.SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; begin Result := sfprSuccess; try case aTemplateProperty.GetID of fpName: if (aTemplateProperty as TFileNameProperty).Value <> aFile.Name then begin Result := RenameFile( aFile, (aTemplateProperty as TFileNameProperty).Value); if (Result = sfprSuccess) and gProcessComments then begin FDescription.Rename(aFile.FullPath, (aTemplateProperty as TFileNameProperty).Value); end; end else Result := sfprSkipped; fpAttributes: if (aTemplateProperty as TFileAttributesProperty).Value <> (aFile.Properties[fpAttributes] as TFileAttributesProperty).Value then begin if not FileSetAttrUAC( aFile.FullPath, (aTemplateProperty as TFileAttributesProperty).Value) then begin Result := sfprError; end; end else Result := sfprSkipped; fpModificationTime: if (aTemplateProperty as TFileModificationDateTimeProperty).Value <> (aFile.Properties[fpModificationTime] as TFileModificationDateTimeProperty).Value then begin if not FileSetTimeUAC( aFile.FullPath, DateTimeToFileTimeEx((aTemplateProperty as TFileModificationDateTimeProperty).Value), TFileTimeExNull, TFileTimeExNull) then begin Result := sfprError; end; end else Result := sfprSkipped; fpCreationTime: if (aTemplateProperty as TFileCreationDateTimeProperty).Value <> (aFile.Properties[fpCreationTime] as TFileCreationDateTimeProperty).Value then begin if not FileSetTimeUAC( aFile.FullPath, TFileTimeExNull, DateTimeToFileTimeEx((aTemplateProperty as TFileCreationDateTimeProperty).Value), TFileTimeExNull) then begin Result := sfprError; end; end else Result := sfprSkipped; fpLastAccessTime: if (aTemplateProperty as TFileLastAccessDateTimeProperty).Value <> (aFile.Properties[fpLastAccessTime] as TFileLastAccessDateTimeProperty).Value then begin if not FileSetTimeUAC( aFile.FullPath, TFileTimeExNull, TFileTimeExNull, DateTimeToFileTimeEx((aTemplateProperty as TFileLastAccessDateTimeProperty).Value)) then begin Result := sfprError; end; end else Result := sfprSkipped; {$IF DEFINED(UNIX)} fpOwner: begin if fplchown(aFile.FullPath, (aTemplateProperty as TFileOwnerProperty).Owner, (aTemplateProperty as TFileOwnerProperty).Group) <> 0 then begin Result := sfprError;; end; end {$ENDIF} else raise Exception.Create('Trying to set unsupported property'); end; except on e: EDateOutOfRange do begin if not gSkipFileOpError then case AskQuestion(rsMsgLogError + Format(rsMsgErrDateNotSupported, [DateTimeToStr(e.DateTime)]), '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) of fsourSkip: Result := sfprSkipped; fsourAbort: RaiseAbortOperation; end; end; on e: EConvertError do begin if not gSkipFileOpError then case AskQuestion(rsMsgLogError + e.Message, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) of fsourSkip: Result := sfprSkipped; fsourAbort: RaiseAbortOperation; end; end; end; end; procedure TFileSystemSetFilePropertyOperation.QuestionActionHandler( Action: TFileSourceOperationUIAction); begin if Action = fsouaCompare then ShowCompareFilesUI(FCurrentFile, FCurrentTargetFilePath); end; function TFileSystemSetFilePropertyOperation.RenameFile(aFile: TFile; NewName: String): TSetFilePropertyResult; var OldName: String; NewAttr: TFileAttributeData; function OverwriteOlder: TFileSourceOperationUIResponse; begin if aFile.ModificationTime > FileTimeToDateTime(NewAttr.LastWriteTime) then Result := fsourOverwrite else Result := fsourSkip; end; function OverwriteSmaller: TFileSourceOperationUIResponse; begin if aFile.Size > NewAttr.Size then Result := fsourOverwrite else Result := fsourSkip; end; function OverwriteLarger: TFileSourceOperationUIResponse; begin if aFile.Size < NewAttr.Size then Result := fsourOverwrite else Result := fsourSkip; end; function AskIfOverwrite: TFileSourceOperationUIResponse; var sQuestion: String; begin if DCOSUtils.FPS_ISDIR(NewAttr.Attr) then begin if FDirExistsOption <> fsourInvalid then Exit(FDirExistsOption); Result := AskQuestion(Format(rsMsgErrDirExists, [NewName]), '', [fsourSkip, fsourSkipAll, fsourAbort], fsourSkip, fsourAbort); if Result = fsourSkipAll then begin FDirExistsOption:= fsourSkip; Result:= FDirExistsOption; end; end else begin case FFileExistsOption of fsourNone, fsourInvalid: begin FCurrentFile := aFile; FCurrentTargetFilePath := NewName; sQuestion:= FileExistsMessage(NewName, aFile.FullPath, aFile.Size, aFile.ModificationTime); Result := AskQuestion(sQuestion, '', [fsourOverwrite, fsourSkip, fsourOverwriteSmaller, fsourOverwriteAll, fsourSkipAll, fsourOverwriteLarger, fsourOverwriteOlder, fsourAbort, fsouaCompare ], fsourOverwrite, fsourAbort, @QuestionActionHandler); case Result of fsourOverwriteAll: begin Result:= fsourOverwrite; FFileExistsOption:= Result; end; fsourSkipAll: begin Result:= fsourSkip; FFileExistsOption:= Result; end; fsourOverwriteOlder: begin FFileExistsOption := OverwriteOlder; Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin FFileExistsOption := fsourOverwriteSmaller; Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin FFileExistsOption := fsourOverwriteLarger; Result:= OverwriteLarger; end; end; // case end; fsourOverwriteOlder: begin Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin Result:= OverwriteLarger; end; else Result := FFileExistsOption; end; // case end; end; {$IFDEF UNIX} var OldAttr: TFileAttributeData; {$ENDIF} begin OldName:= aFile.FullPath; if FileSource.GetPathType(NewName) <> ptAbsolute then begin NewName := ExtractFilePath(OldName) + TrimPath(NewName); end; if OldName = NewName then Exit(sfprSkipped); {$IFDEF UNIX} // Check if target file exists. if FileGetAttrUAC(NewName, NewAttr) then begin // Cannot overwrite file by directory and vice versa if fpS_ISDIR(NewAttr.FindData.st_mode) <> aFile.IsDirectory then Exit(sfprError); // Special case when filenames differ only by case, // see comments in mbRenameFile function for details if (UTF8LowerCase(OldName) <> UTF8LowerCase(NewName)) then OldAttr.FindData.st_ino:= not NewAttr.FindData.st_ino else begin if not FileGetAttrUAC(OldName, OldAttr) then Exit(sfprError); end; // Check if source and target are the same files (same inode and same device). if (OldAttr.FindData.st_ino = NewAttr.FindData.st_ino) and (OldAttr.FindData.st_dev = NewAttr.FindData.st_dev) and // Check number of links, if it is 1 then source and target names most // probably differ only by case on a case-insensitive filesystem. ((NewAttr.FindData.st_nlink = 1) or fpS_ISDIR(NewAttr.FindData.st_mode)) then begin // File names differ only by case on a case-insensitive filesystem. end else begin case AskIfOverwrite of fsourOverwrite: ; // continue fsourSkip: Exit(sfprSkipped); fsourAbort: RaiseAbortOperation; end; end; end; {$ELSE} // Windows doesn't allow two filenames that differ only by case (even on NTFS). if UTF8LowerCase(OldName) <> UTF8LowerCase(NewName) then begin if FileGetAttrUAC(NewName, NewAttr) then // If target file exists. begin // Cannot overwrite file by directory and vice versa if fpS_ISDIR(NewAttr.Attr) <> aFile.IsDirectory then Exit(sfprError); case AskIfOverwrite of fsourOverwrite: ; // continue fsourSkip: Exit(sfprSkipped); fsourAbort: RaiseAbortOperation; end; end; end; {$ENDIF} if RenameFileUAC(OldName, NewName) then Result := sfprSuccess else Result := sfprError; end; procedure TFileSystemSetFilePropertyOperation.ShowCompareFilesUI( SourceFile: TFile; const TargetFilePath: String); var TargetFile: TFile; begin TargetFile := FileSource.CreateFileObject(ExtractFilePath(TargetFilePath)); try TargetFile.Name := ExtractFileName(TargetFilePath); PrepareToolData(FileSource, SourceFile, FileSource, TargetFile, @ShowDifferByGlobList, True); finally TargetFile.Free; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemsplitoperation.pas���������������������������0000644�0001750�0000144�00000031555�14743153644�026170� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemSplitOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceSplitOperation, uFileSource, uFileSourceOperationUI, uFile, uGlobs, uLog, DCClassesUtf8; type { TFileSystemSplitOperation } TFileSystemSplitOperation = class(TFileSourceSplitOperation) private FStatistics: TFileSourceSplitOperationStatistics; // local copy of statistics FTargetpath: String; FBuffer: Pointer; FBufferSize: LongWord; FCheckFreeSpace: Boolean; protected function Split(aSourceFileStream: TFileStreamEx; TargetFile: String): Boolean; procedure ShowError(sMessage: String); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aFileSource: IFileSource; var aSourceFile: TFile; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses //Lazarus, Free-Pascal, etc. LCLProc, LazUTF8, DCcrc32, //DC DCConvertEncoding, uOSUtils, DCOSUtils, uLng, uFileProcs; constructor TFileSystemSplitOperation.Create(aFileSource: IFileSource; var aSourceFile: TFile; aTargetPath: String); begin FCheckFreeSpace := True; FTargetpath := IncludeTrailingPathDelimiter(aTargetPath); FBufferSize := gCopyBlockSize; GetMem(FBuffer, FBufferSize); inherited Create(aFileSource, aSourceFile, aTargetPath); end; destructor TFileSystemSplitOperation.Destroy; begin inherited Destroy; if Assigned(FBuffer) then begin FreeMem(FBuffer); FBuffer := nil; end; end; //TC, when creating the CRC32 verification file after a split will include the target filename with both ANSI and UTF8 string filename //In the ANSI filename, he puts "_" to replace any UTF8 needed character, not present in regular ANSI set. //Let's do the same! // function ConvertStringToTCStringUTF8CharReplacedByUnderscore(const sString: string): string; begin Result:= StringReplace(CeUtf8ToSys(sString), '?', '_', [rfReplaceAll]); end; procedure TFileSystemSplitOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; with FStatistics do begin CurrentFileFrom:= SourceFile.FullPath; TotalFiles:= VolumeNumber; TotalBytes:= SourceFile.Size; end; end; procedure TFileSystemSplitOperation.MainExecute; var iExt, CurrentFileIndex: Integer; iTotalDiskSize, iFreeDiskSize: Int64; SourceFileStream: TFileStreamEx = nil; TargetFilename: String; hSummaryFile: THandle; SummaryFilename:String; respAutomaticSwapDisk: TFileSourceOperationUIResponse; begin try if not AutomaticSplitMode then begin { Check disk free space } if FCheckFreeSpace = True then begin GetDiskFreeSpace(TargetPath, iFreeDiskSize, iTotalDiskSize); if FStatistics.TotalBytes > iFreeDiskSize then begin AskQuestion('', rsMsgNoFreeSpaceCont, [fsourAbort], fsourAbort, fsourAbort); RaiseAbortOperation; end; end; end; // Open source file SourceFileStream := TFileStreamEx.Create(SourceFile.FullPath, fmOpenRead or fmShareDenyNone); try // Calculate extension length iExt:= 3; // Minimum length 3 symbols if not AutomaticSplitMode then begin CurrentFileIndex:= (FStatistics.TotalFiles div 1000); while CurrentFileIndex >= 1 do begin CurrentFileIndex:= CurrentFileIndex div 10; Inc(iExt); end; end; //For-loop has been replaced by a while if for any reason the number of files has been miscomputed, it won't create hundreds of file of 0 byte long! CurrentFileIndex:=1; while ((CurrentFileIndex<=FStatistics.TotalFiles) OR AutomaticSplitMode) AND (FStatistics.TotalBytes>FStatistics.DoneBytes) do begin //Determine what will be the next filename to the output file if RequireACRC32VerificationFile then TargetFilename:= FTargetpath + SourceFile.NameNoExt + ExtensionSeparator + Format('%.*d',[iExt, CurrentFileIndex]) //like TC else TargetFilename:= FTargetpath + SourceFile.Name + ExtensionSeparator + Format('%.*d',[iExt, CurrentFileIndex]); //like DC originally if AutomaticSplitMode then begin repeat GetDiskFreeSpace(TargetPath, iFreeDiskSize, iTotalDiskSize); VolumeSize:=iFreeDiskSize-(64*1024); //Let's keep a possible 64KB free of space on target even after copy if VolumeSize<(64*1024) then begin respAutomaticSwapDisk:=AskQuestion('',Format(rsMsgInsertNextDisk,[TargetFilename,(FStatistics.TotalBytes-FStatistics.DoneBytes)]),[fsourOk,fsourAbort],fsourOk,fsourAbort); if respAutomaticSwapDisk = fsourAbort then RaiseAbortOperation; if respAutomaticSwapDisk = fsourOk then VolumeSize:=1*1024*1024; //~~~Debug end; until (VolumeSize >= (64*1024)); FStatistics.TotalFiles:=FStatistics.TotalFiles+1; end; with FStatistics do begin // Last file can be smaller then volume size if (TotalBytes - DoneBytes) < VolumeSize then VolumeSize:= TotalBytes - DoneBytes; CurrentFileTo := TargetFilename; CurrentFileTotalBytes := VolumeSize; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics); // Split with current file if not Split(SourceFileStream, TargetFilename) then Break; with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; CheckOperationState; inc(CurrentFileIndex); end; finally if Assigned(SourceFileStream) then begin FreeAndNil(SourceFileStream); if (FStatistics.DoneBytes <> FStatistics.TotalBytes) then begin for CurrentFileIndex := 1 to FStatistics.TotalFiles do // There was some error, because not all files has been created. // Delete the not completed target files. mbDeleteFile(FTargetpath + SourceFile.NameNoExt + ExtensionSeparator + Format('%.*d',[iExt, CurrentFileIndex])); end else begin //If requested, let's create the CRC32 verification file if RequireACRC32VerificationFile then begin //We just mimic TC who set in uppercase the "CRC" extension if the filename (without extension!) is made all with capital letters. if SourceFile.NameNoExt = UTF8UpperCase(SourceFile.NameNoExt) then SummaryFilename:= FTargetpath + SourceFile.NameNoExt + ExtensionSeparator + 'CRC' else SummaryFilename:= FTargetpath + SourceFile.NameNoExt + ExtensionSeparator + 'crc'; hSummaryFile := mbFileCreate(SummaryFilename); try FileWriteLn(hSummaryFile,'filename='+ConvertStringToTCStringUTF8CharReplacedByUnderscore(SourceFile.Name)); FileWriteLn(hSummaryFile,'filenameutf8='+SourceFile.Name); FileWriteLn(hSummaryFile,'size='+IntToStr(SourceFile.Size)); FileWriteLn(hSummaryFile,'crc32='+hexStr(CurrentCRC32,8)); finally FileClose(hSummaryFile); end; end; end; end; end; except on EFOpenError do begin ShowError(rsMsgLogError + rsMsgErrEOpen + ': ' + SourceFile.FullPath); end; end; end; procedure TFileSystemSplitOperation.Finalize; begin end; function TFileSystemSplitOperation.Split(aSourceFileStream: TFileStreamEx; TargetFile: String): Boolean; var TargetFileStream: TFileStreamEx = nil; // for safety exception handling iTotalDiskSize, iFreeDiskSize: Int64; bRetryRead, bRetryWrite: Boolean; BytesRead, BytesToRead, BytesWrittenTry, BytesWritten: Int64; TotalBytesToRead: Int64 = 0; begin Result := False; BytesToRead := FBufferSize; try try TargetFileStream := TFileStreamEx.Create(TargetFile, fmCreate); TotalBytesToRead := VolumeSize; while TotalBytesToRead > 0 do begin // Without the following line the reading is very slow // if it tries to read past end of file. if TotalBytesToRead < BytesToRead then BytesToRead := TotalBytesToRead; repeat try bRetryRead := False; BytesRead := aSourceFileStream.Read(FBuffer^, BytesToRead); if (BytesRead = 0) then Raise EReadError.Create(mbSysErrorMessage(GetLastOSError)); if RequireACRC32VerificationFile then begin CurrentCRC32:= crc32_16bytes(FBuffer, BytesRead, CurrentCRC32); end; TotalBytesToRead := TotalBytesToRead - BytesRead; BytesWritten := 0; repeat try bRetryWrite := False; BytesWrittenTry := TargetFileStream.Write((FBuffer + BytesWritten)^, BytesRead); BytesWritten := BytesWritten + BytesWrittenTry; if BytesWrittenTry = 0 then begin Raise EWriteError.Create(mbSysErrorMessage(GetLastOSError)); end else if BytesWritten < BytesRead then begin bRetryWrite := True; // repeat and try to write the rest end; except on E: EWriteError do begin { Check disk free space } GetDiskFreeSpace(TargetPath, iFreeDiskSize, iTotalDiskSize); if BytesRead > iFreeDiskSize then begin case AskQuestion(rsMsgNoFreeSpaceRetry, '', [fsourYes, fsourNo], fsourYes, fsourNo) of fsourYes: bRetryWrite := True; fsourNo: RaiseAbortOperation; end; // case end else begin case AskQuestion(rsMsgErrEWrite + ' ' + TargetFile + ':', E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryWrite := True; fsourAbort: RaiseAbortOperation; fsourSkip: Exit; end; // case end; end; // on do end; // except until not bRetryWrite; except on E: EReadError do begin case AskQuestion(rsMsgErrERead + ' ' + SourceFile.FullPath + ':', E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryRead := True; fsourAbort: RaiseAbortOperation; fsourSkip: Exit; end; // case end; end; until not bRetryRead; with FStatistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + BytesRead; DoneBytes := DoneBytes + BytesRead; UpdateStatistics(FStatistics); end; CheckOperationState; // check pause and stop end; //while finally if Assigned(TargetFileStream) then FreeAndNil(TargetFileStream); end; Result:= True; except on EFCreateError do begin ShowError(rsMsgLogError + rsMsgErrECreate + ': ' + TargetFile); end; on EWriteError do begin ShowError(rsMsgLogError + rsMsgErrEWrite + ': ' + TargetFile); end; end; end; procedure TFileSystemSplitOperation.ShowError(sMessage: String); begin if gSkipFileOpError then logWrite(Thread, sMessage, lmtError, True) else begin AskQuestion(sMessage, '', [fsourAbort], fsourAbort, fsourAbort); RaiseAbortOperation; end; end; procedure TFileSystemSplitOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemutil.pas�������������������������������������0000644�0001750�0000144�00000214467�14743153644�024076� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSystemUtil; {$mode objfpc}{$H+} {$if FPC_FULLVERSION >= 30300} {$modeswitch arraytodynarray} {$endif} interface uses Classes, SysUtils, uDescr, uLog, uGlobs, DCOSUtils, uFile, uFileSourceOperation, uFileSourceOperationOptions, uFileSourceOperationUI, uFileSourceCopyOperation, uFileSourceTreeBuilder; function ApplyRenameMask(aFile: TFile; NameMask: String; ExtMask: String): String; overload; procedure FillAndCount(Files: TFiles; CountDirs: Boolean; ExcludeRootDir: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); function FileExistsMessage(const TargetName, SourceName: String; SourceSize: Int64; SourceTime: TDateTime): String; type TUpdateStatisticsFunction = procedure(var NewStatistics: TFileSourceCopyOperationStatistics) of object; TFileSystemOperationTargetExistsResult = (fsoterNotExists, fsoterDeleted, fsoterAddToTarget, fsoterResume, fsoterSkip, fsoterRenamed); TFileSystemOperationHelperMode = (fsohmCopy, fsohmMove); TFileSystemOperationHelperCopyMode = (fsohcmDefault, fsohcmAppend, fsohcmResume); TFileSystemOperationHelperMoveOrCopy = function(SourceFile: TFile; TargetFileName: String; Mode: TFileSystemOperationHelperCopyMode): Boolean of object; { TFileSystemTreeBuilder } TFileSystemTreeBuilder = class(TFileSourceTreeBuilder) protected procedure AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); override; procedure AddFilesInDirectory(srcPath: String; CurrentNode: TFileTreeNode); override; end; { TFileSystemOperationHelper } TFileSystemOperationHelper = class private FOperationThread: TThread; FMode: TFileSystemOperationHelperMode; FBuffer: Pointer; FBufferSize: LongWord; FRootTargetPath: String; FRenameMask: String; FRenameNameMask, FRenameExtMask: String; FSetPropertyError: TFileSourceOperationOptionSetPropertyError; FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics FDescription: TDescription; FLogCaption: String; FRenamingFiles: Boolean; FRenamingRootDir: Boolean; FRootDir: TFile; FVerify, FReserveSpace, FCheckFreeSpace: Boolean; FSkipAllBigFiles: Boolean; FSkipAllCopyItSelf: Boolean; {$IF DEFINED(UNIX)} FSkipAllSpecialFiles: Boolean; {$ENDIF} FSkipRenameError: Boolean; FSkipOpenForReadingError: Boolean; FSkipOpenForWritingError: Boolean; FSkipCreateSymLinkError: Boolean; FSkipReadError: Boolean; FSkipWriteError: Boolean; FSkipCopyError: Boolean; FAutoRenameItSelf: Boolean; FCorrectSymLinks: Boolean; FCopyAttributesOptions: TCopyAttributesOptions; FMaxPathOption: TFileSourceOperationUIResponse; FCopyOnWrite: TFileSourceOperationOptionGeneral; FDeleteFileOption: TFileSourceOperationUIResponse; FFileExistsOption: TFileSourceOperationOptionFileExists; FDirExistsOption: TFileSourceOperationOptionDirectoryExists; {$IF DEFINED(LINUX)} FCache: record Device: QWord; DirtyLimit: Int64 end; {$ENDIF} FCurrentFile: TFile; FCurrentTargetFilePath: String; AskQuestion: TAskQuestionFunction; AbortOperation: TAbortOperationFunction; CheckOperationState: TCheckOperationStateFunction; UpdateStatistics: TUpdateStatisticsFunction; AppProcessMessages: TAppProcessMessagesFunction; ShowCompareFilesUI: TShowCompareFilesUIFunction; MoveOrCopy: TFileSystemOperationHelperMoveOrCopy; procedure ShowError(sMessage: String); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); function DeleteFile(SourceFile: TFile): Boolean; function CheckFileHash(const FileName, Hash: String; Size: Int64): Boolean; function CompareFiles(const FileName1, FileName2: String; Size: Int64): Boolean; function CopyFile(SourceFile: TFile; TargetFileName: String; Mode: TFileSystemOperationHelperCopyMode): Boolean; function MoveFile(SourceFile: TFile; TargetFileName: String; Mode: TFileSystemOperationHelperCopyMode): Boolean; procedure CopyProperties(SourceFile: TFile; TargetFileName: String); function ProcessNode(aFileTreeNode: TFileTreeNode; CurrentTargetPath: String): Boolean; function ProcessDirectory(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; function ProcessLink(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; function ProcessFile(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; function TargetExists(aNode: TFileTreeNode; var AbsoluteTargetFileName: String) : TFileSystemOperationTargetExistsResult; function DirExists(aFile: TFile; AbsoluteTargetFileName: String; AllowCopyInto: Boolean; AllowDelete: Boolean): TFileSourceOperationOptionDirectoryExists; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); function FileExists(aFile: TFile; var AbsoluteTargetFileName: String; AllowAppend: Boolean): TFileSourceOperationOptionFileExists; procedure SkipStatistics(aNode: TFileTreeNode); procedure CountStatistics(aNode: TFileTreeNode); public constructor Create(AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; AppProcessMessagesFunction: TAppProcessMessagesFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; ShowCompareFilesUIFunction: TShowCompareFilesUIFunction; OperationThread: TThread; Mode: TFileSystemOperationHelperMode; TargetPath: String; StartingStatistics: TFileSourceCopyOperationStatistics); destructor Destroy; override; procedure Initialize; procedure ProcessTree(aFileTree: TFileTree); property Verify: Boolean read FVerify write FVerify; property CopyOnWrite: TFileSourceOperationOptionGeneral read FCopyOnWrite write FCopyOnWrite; property FileExistsOption: TFileSourceOperationOptionFileExists read FFileExistsOption write FFileExistsOption; property DirExistsOption: TFileSourceOperationOptionDirectoryExists read FDirExistsOption write FDirExistsOption; property CheckFreeSpace: Boolean read FCheckFreeSpace write FCheckFreeSpace; property ReserveSpace: Boolean read FReserveSpace write FReserveSpace; property SetPropertyError: TFileSourceOperationOptionSetPropertyError read FSetPropertyError write FSetPropertyError; property SkipAllBigFiles: Boolean read FSkipAllBigFiles write FSkipAllBigFiles; property AutoRenameItSelf: Boolean read FAutoRenameItSelf write FAutoRenameItSelf; property CopyAttributesOptions: TCopyAttributesOptions read FCopyAttributesOptions write FCopyAttributesOptions; property CorrectSymLinks: Boolean read FCorrectSymLinks write FCorrectSymLinks; property RenameMask: String read FRenameMask write FRenameMask; end; implementation uses uDebug, uDCUtils, uOSUtils, DCStrUtils, FileUtil, uFindEx, DCClassesUtf8, uFileProcs, uLng, DCBasicTypes, uFileSource, uFileSystemFileSource, uFileProperty, uAdministrator, StrUtils, DCDateTimeUtils, uShowMsg, Forms, LazUTF8, uHash, uFileCopyEx, SysConst, Math, DateUtils {$IFDEF UNIX} , BaseUnix, Unix, DCUnix {$ENDIF} ; const HASH_TYPE = HASH_BEST; function ApplyRenameMask(aFile: TFile; NameMask: String; ExtMask: String): String; overload; begin // Only change name for files. if aFile.IsDirectory or aFile.IsLink then Result := aFile.Name else Result := ApplyRenameMask(aFile.Name, NameMask, ExtMask); end; procedure FillAndCount(Files: TFiles; CountDirs: Boolean; ExcludeRootDir: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); procedure FillAndCountRec(const srcPath: String); var sr: TSearchRecEx; aFile: TFile; begin if FindFirstUAC(srcPath + '*', 0, sr) = 0 then begin repeat if (sr.Name='.') or (sr.Name='..') then Continue; aFile := TFileSystemFileSource.CreateFile(srcPath, @sr); NewFiles.Add(aFile); if aFile.IsLink then begin end else if aFile.IsDirectory then begin if CountDirs then Inc(FilesCount); FillAndCountRec(srcPath + sr.Name + DirectorySeparator); // go down to directory end else begin FilesSize:= FilesSize + aFile.Size; Inc(FilesCount); end; until FindNextUAC(sr) <> 0; end; FindCloseUAC(sr); end; var i: Integer; aFile: TFile; aFindData: TFileAttributeData; begin FilesCount:= 0; FilesSize:= 0; if ExcludeRootDir then begin if Files.Count <> 1 then raise Exception.Create('Only a single directory can be set with ExcludeRootDir=True'); NewFiles := TFiles.Create(Files[0].FullPath); FillAndCountRec(Files[0].FullPath + DirectorySeparator); end else begin NewFiles := TFiles.Create(Files.Path); for i := 0 to Files.Count - 1 do begin aFile := Files[i]; // Update file attributes if FileGetAttrUAC(aFile.FullPath, aFindData) then begin aFile.Size:= aFindData.Size; aFile.Attributes:= aFindData.Attr; aFile.ModificationTime:= FileTimeToDateTime(aFindData.LastWriteTime); end; NewFiles.Add(aFile.Clone); if aFile.IsLink then begin end else if aFile.IsDirectory then begin if CountDirs then Inc(FilesCount); FillAndCountRec(aFile.FullPath + DirectorySeparator); // recursive browse child dir end else begin Inc(FilesCount); FilesSize:= FilesSize + aFile.Size; // in first level we know file size -> use it end; end; end; end; function FileExistsMessage(const TargetName, SourceName: String; SourceSize: Int64; SourceTime: TDateTime): String; var ASize: String; TargetInfo: TFileAttributeData; begin Result:= rsMsgFileExistsOverwrite + LineEnding + WrapTextSimple(TargetName, 100) + LineEnding; if FileGetAttrUAC(TargetName, TargetInfo) then begin Result:= Result + Format(rsMsgFileExistsFileInfo, [IntToStrTS(TargetInfo.Size), DateTimeToStr(FileTimeToDateTime(TargetInfo.LastWriteTime))]) + LineEnding; end; if (SourceSize < 0) then ASize:= '?' else begin ASize:= IntToStrTS(SourceSize); end; Result:= Result + LineEnding + rsMsgFileExistsWithFile + LineEnding + WrapTextSimple(SourceName, 100) + LineEnding + Format(rsMsgFileExistsFileInfo, [ASize, DateTimeToStr(SourceTime)]); end; function FileCopyProgress(TotalBytes, DoneBytes: Int64; UserData: Pointer): LongBool; var Helper: TFileSystemOperationHelper absolute UserData; begin with Helper do begin FStatistics.DoneBytes+= (DoneBytes - FStatistics.CurrentFileDoneBytes); // File has alternate data streams if TotalBytes > FStatistics.CurrentFileTotalBytes then begin FStatistics.TotalBytes+= (TotalBytes - FStatistics.CurrentFileTotalBytes); FStatistics.CurrentFileTotalBytes:= TotalBytes; end; FStatistics.CurrentFileDoneBytes:= DoneBytes; UpdateStatistics(FStatistics); try CheckOperationState; except on E: EFileSourceOperationAborting do Exit(False); end; end; Result:= True; end; // ---------------------------------------------------------------------------- procedure TFileSystemTreeBuilder.AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); var LinkedFilePath: String; LinkedFile: TFile = nil; AddedNode: TFileTreeNode; AddedIndex: Integer; begin LinkedFilePath := mbReadAllLinks(aFile.FullPath); if (LinkedFilePath <> '') and not (aFile.IsLinkToDirectory and IsInPath(LinkedFilePath, aFile.FullPath, True, True)) then begin try LinkedFile := TFileSystemFileSource.CreateFileFromFile(LinkedFilePath); // Add link to current node. AddedIndex := CurrentNode.AddSubNode(aFile); AddedNode := CurrentNode.SubNodes[AddedIndex]; AddedNode.Data := TFileTreeNodeData.Create(FRecursive); (CurrentNode.Data as TFileTreeNodeData).SubnodesHaveLinks := True; // Then add linked file/directory as a subnode of the link. AddItem(LinkedFile, AddedNode); except on EFileNotFound do begin // Link target doesn't exist - add symlink instead of target (or ask user). AddLink(aFile, CurrentNode); end; end; end else begin // error - cannot follow symlink - adding symlink instead of target (or ask user) AddLink(aFile, CurrentNode); end; end; procedure TFileSystemTreeBuilder.AddFilesInDirectory( srcPath: String; CurrentNode: TFileTreeNode); var sr: TSearchRecEx; aFile: TFile; begin if FindFirstUAC(srcPath + '*', 0, sr) = 0 then begin repeat if (sr.Name = '.') or (sr.Name = '..') then Continue; aFile := TFileSystemFileSource.CreateFile(srcPath, @sr); AddItem(aFile, CurrentNode); until FindNextUAC(sr) <> 0; end; FindCloseUAC(sr); end; // ---------------------------------------------------------------------------- constructor TFileSystemOperationHelper.Create( AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; AppProcessMessagesFunction: TAppProcessMessagesFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; ShowCompareFilesUIFunction: TShowCompareFilesUIFunction; OperationThread: TThread; Mode: TFileSystemOperationHelperMode; TargetPath: String; StartingStatistics: TFileSourceCopyOperationStatistics); begin AskQuestion := AskQuestionFunction; AbortOperation := AbortOperationFunction; AppProcessMessages := AppProcessMessagesFunction; CheckOperationState := CheckOperationStateFunction; UpdateStatistics := UpdateStatisticsFunction; ShowCompareFilesUI := ShowCompareFilesUIFunction; FOperationThread := OperationThread; FMode := Mode; FBufferSize := gCopyBlockSize; GetMem(FBuffer, FBufferSize); FCheckFreeSpace := True; FSkipAllBigFiles := False; FSkipReadError := False; FSkipWriteError := False; FCopyAttributesOptions := CopyAttributesOptionCopyAll; FFileExistsOption := fsoofeNone; FDirExistsOption := fsoodeNone; FSetPropertyError := fsoospeNone; FRootTargetPath := TargetPath; FRenameMask := ''; FStatistics := StartingStatistics; FRenamingFiles := False; FRenamingRootDir := False; FRootDir := nil; if gProcessComments then FDescription := TDescription.Create(True) else FDescription := nil; case FMode of fsohmCopy: begin MoveOrCopy := @CopyFile; FLogCaption := rsMsgLogCopy; end; fsohmMove: begin MoveOrCopy := @MoveFile; FLogCaption := rsMsgLogMove; end; else raise Exception.Create('Invalid operation mode'); end; inherited Create; end; destructor TFileSystemOperationHelper.Destroy; begin inherited Destroy; if Assigned(FBuffer) then begin FreeMem(FBuffer); FBuffer := nil; end; if Assigned(FDescription) then begin FDescription.SaveDescription; FreeAndNil(FDescription); end; end; procedure TFileSystemOperationHelper.Initialize; begin SplitFileMask(FRenameMask, FRenameNameMask, FRenameExtMask); // Create destination path if it doesn't exist. if not DirectoryExistsUAC(FRootTargetPath) then if not ForceDirectoriesUAC(FRootTargetPath) then Exit; // do error end; procedure TFileSystemOperationHelper.ProcessTree(aFileTree: TFileTree); var aFile: TFile; begin FRenamingFiles := (FRenameMask <> '*.*') and (FRenameMask <> ''); // If there is a single root dir and rename mask doesn't have wildcards // treat is as a rename of the root dir. if (aFileTree.SubNodesCount = 1) and FRenamingFiles then begin aFile := aFileTree.SubNodes[0].TheFile; if (aFile.IsDirectory or aFile.IsLinkToDirectory) and not ContainsWildcards(FRenameMask) then begin FRenamingFiles := False; FRenamingRootDir := True; FRootDir := aFile; end; end; ProcessNode(aFileTree, FRootTargetPath); end; // ---------------------------------------------------------------------------- function TFileSystemOperationHelper.CopyFile( SourceFile: TFile; TargetFileName: String; Mode: TFileSystemOperationHelperCopyMode): Boolean; var SourceFileStream, TargetFileStream: TFileStreamUAC; iTotalDiskSize, iFreeDiskSize: Int64; bRetryRead, bRetryWrite: Boolean; BytesRead, BytesToRead, BytesWrittenTry, BytesWritten: Int64; TotalBytesToRead: Int64 = 0; NewPos: Int64; Hash: String; Options: UInt32; Context: THashContext; bDeleteFile: Boolean = False; {$IFDEF LINUX} Sbfs: TStatFS; Info: BaseUnix.Stat; {$ENDIF} procedure OpenSourceFile; var bRetry: Boolean = True; begin while bRetry do begin bRetry := False; SourceFileStream.Free; // In case stream was created but 'while' loop run again try SourceFileStream := TFileStreamUAC.Create(SourceFile.FullPath, fmOpenRead or fmShareDenyNone); except on EFOpenError do begin if not FSkipOpenForReadingError then begin case AskQuestion(rsMsgErrEOpen + ': ' + SourceFile.FullPath, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetry := True; fsourAbort: AbortOperation; fsourSkip: ; // Do nothing fsourSkipAll: FSkipOpenForReadingError := True; end; end; end; end; end; if not Assigned(SourceFileStream) and (log_errors in gLogOptions) then logWrite(FOperationThread, rsMsgLogError + rsMsgErrEOpen + ': ' + SourceFile.FullPath, lmtError, True); end; procedure OpenTargetFile; function GetMsgByMode: String; begin if Mode in [fsohcmAppend, fsohcmResume] then Result := rsMsgErrEOpen else Result := rsMsgErrECreate; end; function HandleError: Boolean; begin Result := False; if not FSkipOpenForWritingError then begin case AskQuestion(GetMsgByMode + ': ' + TargetFileName, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: Result := True; fsourAbort: AbortOperation; fsourSkip: ; // Do nothing fsourSkipAll: FSkipOpenForWritingError := True; end; end; end; var Flags: LongWord = 0; bRetry: Boolean = True; begin while bRetry do begin bRetry := False; {$IF NOT DEFINED(LINUX)} if FVerify then Flags := fmOpenSync; {$ENDIF} try TargetFileStream.Free; // In case stream was created but 'while' loop run again case Mode of fsohcmAppend: begin TargetFileStream := TFileStreamUAC.Create(TargetFileName, fmOpenReadWrite or Flags); TargetFileStream.Seek(0, soFromEnd); // seek to end TotalBytesToRead := SourceFileStream.Size; end; fsohcmResume: begin TargetFileStream := TFileStreamUAC.Create(TargetFileName, fmOpenReadWrite or Flags); NewPos := TargetFileStream.Seek(0, soFromEnd); SourceFileStream.Seek(NewPos, soFromBeginning); TotalBytesToRead := SourceFileStream.Size - NewPos; end else begin TargetFileStream := TFileStreamUAC.Create(TargetFileName, fmCreate or Flags); TotalBytesToRead := SourceFileStream.Size; if FReserveSpace then begin TargetFileStream.Capacity:= SourceFileStream.Size; TargetFileStream.Seek(0, fsFromBeginning); end; end; end; except on EFOpenError do bRetry := HandleError; on EFCreateError do bRetry := HandleError; end; end; if not Assigned(TargetFileStream) and (log_errors in gLogOptions) then logWrite(FOperationThread, rsMsgLogError + GetMsgByMode + ': ' + TargetFileName, lmtError, True); end; begin Result := False; { Check disk free space } if FCheckFreeSpace and GetDiskFreeSpace(ExtractFilePath(TargetFileName), iFreeDiskSize, iTotalDiskSize) then begin if SourceFile.Size > iFreeDiskSize then begin if FSkipAllBigFiles = True then begin Exit; end else begin case AskQuestion('', rsMsgNoFreeSpaceCont, [fsourYes, fsourAll, fsourNo, fsourSkip, fsourSkipAll], fsourYes, fsourNo) of fsourNo: AbortOperation; fsourSkip: Exit; fsourAll: FCheckFreeSpace := False; fsourSkipAll: begin FSkipAllBigFiles := True; Exit; end; end; end; end; end; if Assigned(FileCopyEx) and (Mode = fsohcmDefault) then begin if FVerify then Options:= FILE_COPY_NO_BUFFERING else begin Options:= 0; end; repeat bRetryWrite:= False; Result:= FileCopyUAC(SourceFile.FullPath, TargetFileName, Options, @FileCopyProgress, Self); if not Result then begin if FSkipCopyError then Exit; case AskQuestion('', Format(rsMsgErrCannotCopyFile, [WrapTextSimple(SourceFile.FullPath, 64), WrapTextSimple(TargetFileName, 64)]) + LineEnding + LineEnding + mbSysErrorMessage, [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryWrite := True; fsourAbort: AbortOperation; fsourSkip: Exit; fsourSkipAll: begin FSkipCopyError := True; Exit; end; end; // case end; until not bRetryWrite; if Result and FVerify then begin Result:= CompareFiles(SourceFile.FullPath, TargetFileName, SourceFile.Size); end; if Result then begin CopyProperties(SourceFile, TargetFileName); end; Exit; end; SourceFileStream := nil; TargetFileStream := nil; // for safety exception handling BytesToRead := FBufferSize; if FVerify then HashInit(Context, HASH_TYPE); try try OpenSourceFile; if not Assigned(SourceFileStream) then Exit; {$IF DEFINED(LINUX)} if (Mode = fsohcmDefault) and ((FCopyOnWrite <> fsoogNo) or (FMode = fsohmMove)) then begin bRetryWrite:= FReserveSpace; FReserveSpace:= False; try OpenTargetFile; finally FReserveSpace:= bRetryWrite; end; if not Assigned(TargetFileStream) then Exit; Result:= fpCloneFile(SourceFileStream.Handle, TargetFileStream.Handle); if Result then begin FreeAndNil(TargetFileStream); CopyProperties(SourceFile, TargetFileName); Exit; end else if (FCopyOnWrite = fsoogYes) then begin bDeleteFile := True; if FSkipCopyError then Exit; case AskQuestion('', Format(rsMsgErrCannotCopyFile, [WrapTextSimple(SourceFile.FullPath, 64), WrapTextSimple(TargetFileName, 64)]) + LineEnding + LineEnding + mbSysErrorMessage, [fsourSkip, fsourSkipAll, fsourAbort], fsourSkip, fsourAbort) of fsourAbort: AbortOperation; fsourSkipAll: FSkipCopyError := True; end; // case Exit; end; if FReserveSpace then begin TargetFileStream.Capacity:= SourceFileStream.Size; TargetFileStream.Seek(0, fsFromBeginning); end; end else {$ENDIF} OpenTargetFile; if not Assigned(TargetFileStream) then Exit; {$IF DEFINED(LINUX)} if FVerify then TargetFileStream.AutoSync:= True else if (fpFStatFS(TargetFileStream.Handle, @Sbfs) = 0) then begin case UInt32(Sbfs.fstype) of NFS_SUPER_MAGIC: begin TargetFileStream.AutoSync:= True; end; end; end; if TargetFileStream.AutoSync then begin if (fpFStat(TargetFileStream.Handle, Info) = 0) then begin if FCache.Device = QWord(Info.st_dev) then TargetFileStream.DirtyLimit:= FCache.DirtyLimit else FCache.Device:= QWord(Info.st_dev); end; end; {$ENDIF} while TotalBytesToRead > 0 do begin // Without the following line the reading is very slow // if it tries to read past end of file. if TotalBytesToRead < BytesToRead then BytesToRead := TotalBytesToRead; repeat try bRetryRead := False; BytesRead := SourceFileStream.Read(FBuffer^, BytesToRead); if (BytesRead = 0) then Raise EReadError.Create(mbSysErrorMessage(GetLastOSError)); if FVerify then HashUpdate(Context, FBuffer^, BytesRead); TotalBytesToRead := TotalBytesToRead - BytesRead; BytesWritten := 0; repeat try bRetryWrite := False; BytesWrittenTry := TargetFileStream.Write((FBuffer + BytesWritten)^, BytesRead); BytesWritten := BytesWritten + BytesWrittenTry; if BytesWrittenTry = 0 then begin Raise EWriteError.Create(mbSysErrorMessage(GetLastOSError)); end else if BytesWritten < BytesRead then begin bRetryWrite := True; // repeat and try to write the rest Dec(BytesRead, BytesWrittenTry); end; except on E: EWriteError do begin { Check disk free space } if GetDiskFreeSpace(ExtractFilePath(TargetFileName), iFreeDiskSize, iTotalDiskSize) and (BytesRead > iFreeDiskSize) then begin case AskQuestion(rsMsgNoFreeSpaceRetry, '', [fsourYes, fsourNo, fsourSkip], fsourYes, fsourNo) of fsourYes: bRetryWrite := True; fsourNo: AbortOperation; fsourSkip: Exit; end; // case end else begin bDeleteFile := FSkipWriteError and not (Mode in [fsohcmAppend, fsohcmResume]); if FSkipWriteError then Exit; case AskQuestion(rsMsgErrEWrite + ' ' + TargetFileName + ':', E.Message, [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryWrite := True; fsourAbort: AbortOperation; fsourSkip: Exit; fsourSkipAll: begin bDeleteFile := not (Mode in [fsohcmAppend, fsohcmResume]); FSkipWriteError := True; Exit; end; end; // case end; end; // on do end; // except until not bRetryWrite; except on E: EReadError do begin bDeleteFile := FSkipReadError and not (Mode in [fsohcmAppend, fsohcmResume]); if FSkipReadError then Exit; case AskQuestion(rsMsgErrERead + ' ' + SourceFile.FullPath + ':', E.Message, [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryRead := True; fsourAbort: AbortOperation; fsourSkip: Exit; fsourSkipAll: begin bDeleteFile := not (Mode in [fsohcmAppend, fsohcmResume]); FSkipReadError := True; Exit; end; end; // case end; end; until not bRetryRead; with FStatistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + BytesRead; DoneBytes := DoneBytes + BytesRead; UpdateStatistics(FStatistics); end; AppProcessMessages; CheckOperationState; // check pause and stop end;//while if FVerify then begin HashFinal(Context, Hash); TargetFileStream.Flush; end; Result:= True; except on EFileSourceOperationAborting do begin // Always delete file when user aborted operation. bDeleteFile := True; raise; end; end; finally FreeAndNil(SourceFileStream); if FVerify then Context.Free; if Assigned(TargetFileStream) then begin {$IF DEFINED(LINUX)} if TargetFileStream.AutoSync then FCache.DirtyLimit:= TargetFileStream.DirtyLimit; {$ENDIF} FreeAndNil(TargetFileStream); if TotalBytesToRead > 0 then begin // There was some error, because not all of the file has been copied. // Ask if delete the not completed target file. if bDeleteFile or (AskQuestion('', rsMsgDeletePartiallyCopied, [fsourYes, fsourNo], fsourYes, fsourNo) = fsourYes) then begin DeleteFileUAC(TargetFileName); end; end; if Result and FVerify then begin Result:= CheckFileHash(TargetFileName, Hash, SourceFile.Size); end; end; end; if Result then CopyProperties(SourceFile, TargetFileName); end; procedure TFileSystemOperationHelper.CopyProperties(SourceFile: TFile; TargetFileName: String); var Msg: String = ''; ACopyTime: Boolean; CreationTime, LastAccessTime: TFileTimeEx; CopyAttrResult: TCopyAttributesOptions = []; ACopyAttributesOptions: TCopyAttributesOptions; begin if FCopyAttributesOptions <> [] then begin ACopyAttributesOptions := FCopyAttributesOptions; if SourceFile.IsDirectory or SourceFile.IsLink then ACopyAttributesOptions += CopyAttributesOptionEx; ACopyTime := (FMode = fsohmMove) and ([caoCopyTime, caoCopyTimeEx] * ACopyAttributesOptions <> []); if ACopyTime then ACopyAttributesOptions -= [caoCopyTime, caoCopyTimeEx]; if ACopyAttributesOptions <> [] then begin CopyAttrResult := FileCopyAttrUAC(SourceFile.FullPath, TargetFileName, ACopyAttributesOptions); end; if ACopyTime then try if not (caoCopyTimeEx in CopyAttributesOptionEx) then begin if fpCreationTime in SourceFile.AssignedProperties then CreationTime:= DateTimeToFileTimeEx(SourceFile.CreationTime) else begin CreationTime:= TFileTimeExNull; end; LastAccessTime:= DateTimeToFileTimeEx(SourceFile.LastAccessTime); end else begin CreationTime:= TFileTimeExNull; LastAccessTime:= TFileTimeExNull; end; // Copy time from properties because move operation change time of original folder if not FileSetTimeUAC(TargetFileName, DateTimeToFileTimeEx(SourceFile.ModificationTime), CreationTime, LastAccessTime) then CopyAttrResult += [caoCopyTime]; except on E: EDateOutOfRange do CopyAttrResult += [caoCopyTime]; end; if CopyAttrResult <> [] then begin case FSetPropertyError of fsoospeIgnoreErrors: ; // Do nothing fsoospeDontSet: FCopyAttributesOptions := FCopyAttributesOptions - CopyAttrResult; fsoospeNone: begin if caoCopyAttributes in CopyAttrResult then AddStrWithSep(Msg, Format(rsMsgErrSetAttribute, [TargetFileName]), LineEnding); if caoCopyTime in CopyAttrResult then AddStrWithSep(Msg, Format(rsMsgErrSetDateTime, [TargetFileName]), LineEnding); if caoCopyOwnership in CopyAttrResult then AddStrWithSep(Msg, Format(rsMsgErrSetOwnership, [TargetFileName]), LineEnding); if caoCopyPermissions in CopyAttrResult then AddStrWithSep(Msg, Format(rsMsgErrSetPermissions, [TargetFileName]), LineEnding); if caoCopyXattributes in CopyAttrResult then AddStrWithSep(Msg, Format(rsMsgErrSetXattribute, [TargetFileName]), LineEnding); case AskQuestion(Msg, '', [fsourSkip, fsourSkipAll, fsourIgnoreAll, fsourAbort], fsourSkip, fsourIgnoreAll) of //fsourSkip: do nothing fsourSkipAll: // Don't set properties that failed to be set anymore. FCopyAttributesOptions := FCopyAttributesOptions - CopyAttrResult; fsourIgnoreAll: FSetPropertyError := fsoospeIgnoreErrors; fsourAbort: AbortOperation; end; end else Assert(False, 'Invalid TFileSourceOperationOptionSetPropertyError value.'); end; end; end; end; function TFileSystemOperationHelper.MoveFile(SourceFile: TFile; TargetFileName: String; Mode: TFileSystemOperationHelperCopyMode): Boolean; var Message: String; RetryRename: Boolean; begin if not (Mode in [fsohcmAppend, fsohcmResume]) then begin repeat RetryRename := True; if RenameFileUAC(SourceFile.FullPath, TargetFileName) then Exit(True); if (GetLastOSError <> ERROR_NOT_SAME_DEVICE) then begin if FSkipRenameError then Exit(False); Message := Format(rsMsgErrCannotMoveFile, [WrapTextSimple(SourceFile.FullPath, 100)]) + LineEnding + LineEnding + mbSysErrorMessage; case AskQuestion('', Message, [fsourSkip, fsourRetry, fsourAbort, fsourSkipAll], fsourSkip, fsourAbort) of fsourSkip: Exit(False); fsourAbort: AbortOperation; fsourRetry: RetryRename := False; fsourSkipAll: FSkipRenameError := True; end; end; until RetryRename; end; if FVerify then FStatistics.TotalBytes += SourceFile.Size; if CopyFile(SourceFile, TargetFileName, Mode) then begin Result:= DeleteFile(SourceFile); end else Result := False; end; function TFileSystemOperationHelper.ProcessNode(aFileTreeNode: TFileTreeNode; CurrentTargetPath: String): Boolean; var aFile: TFile; TargetName: String; ProcessedOk: Boolean; CurrentFileIndex: Integer; CurrentSubNode: TFileTreeNode; AskResult: TFileSourceOperationUIResponse; begin Result := True; for CurrentFileIndex := 0 to aFileTreeNode.SubNodesCount - 1 do begin CurrentSubNode := aFileTreeNode.SubNodes[CurrentFileIndex]; aFile := CurrentSubNode.TheFile; if FRenamingRootDir and (aFile = FRootDir) then TargetName := CurrentTargetPath + FRenameMask else if FRenamingFiles then TargetName := CurrentTargetPath + ApplyRenameMask(aFile, FRenameNameMask, FRenameExtMask) else TargetName := CurrentTargetPath + aFile.Name; with FStatistics do begin CurrentFileFrom := aFile.FullPath; CurrentFileTo := TargetName; CurrentFileTotalBytes := aFile.Size; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics); // Check if moving to the same file. if mbFileSame(TargetName, aFile.FullPath) then begin if (FMode = fsohmCopy) and FAutoRenameItSelf then TargetName := GetNextCopyName(TargetName, aFile.IsDirectory or aFile.IsLinkToDirectory) else begin if FSkipAllCopyItSelf then AskResult:= fsourSkip else begin AskResult:= AskQuestion(Format(rsMsgCanNotCopyMoveItSelf, [TargetName]), '', [fsourAbort, fsourSkip, fsourSkipAll], fsourAbort, fsourSkip); FSkipAllCopyItSelf:= (AskResult = fsourSkipAll); end; case AskResult of fsourAbort: AbortOperation(); else begin Result := False; SkipStatistics(CurrentSubNode); AppProcessMessages; CheckOperationState; Continue; end; end; end; end; // Check MAX_PATH if gLongNameAlert and (UTF8Length(TargetName) > MAX_PATH - 1) then begin if FMaxPathOption <> fsourInvalid then AskResult := FMaxPathOption else begin AskResult := AskQuestion(Format(rsMsgFilePathOverMaxPath, [UTF8Length(TargetName), MAX_PATH - 1, LineEnding + WrapTextSimple(TargetName, 100) + LineEnding]), '', [fsourIgnore, fsourSkip, fsourAbort, fsourIgnoreAll, fsourSkipAll], fsourIgnore, fsourSkip); if AskResult = fsourSkipAll then FMaxPathOption := fsourSkip; end; case AskResult of fsourAbort: AbortOperation(); fsourSkip, fsourSkipAll: begin Result := False; SkipStatistics(CurrentSubNode); AppProcessMessages; CheckOperationState; Continue; end; fsourIgnore: ; fsourIgnoreAll: FMaxPathOption := fsourIgnore; end; end; if aFile.IsLink then ProcessedOk := ProcessLink(CurrentSubNode, TargetName) else if aFile.IsDirectory then ProcessedOk := ProcessDirectory(CurrentSubNode, TargetName) else ProcessedOk := ProcessFile(CurrentSubNode, TargetName); if not ProcessedOk then Result := False // Process comments if need else if gProcessComments then begin case FMode of fsohmCopy: FDescription.CopyDescription(CurrentSubNode.TheFile.FullPath, TargetName); fsohmMove: FDescription.MoveDescription(CurrentSubNode.TheFile.FullPath, TargetName); end; end; AppProcessMessages; CheckOperationState; end; end; function TFileSystemOperationHelper.ProcessDirectory(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; var bRenameDirectory: Boolean; bRemoveDirectory: Boolean; NodeData: TFileTreeNodeData; begin NodeData := aNode.Data as TFileTreeNodeData; // If some files will not be moved then source directory cannot be deleted. bRemoveDirectory := (FMode = fsohmMove) and (NodeData.SubnodesHaveExclusions = False); case TargetExists(aNode, AbsoluteTargetFileName) of fsoterSkip: begin Result := False; SkipStatistics(aNode); end; fsoterDeleted, fsoterNotExists: begin // Try moving whole directory tree. It can be done only if we don't have // to process each subnode: if there are no links, or they're not being // processed, if the files are not being renamed or excluded. bRenameDirectory:= (FMode = fsohmMove) and (not FRenamingFiles) and ((FCorrectSymlinks = False) or (NodeData.SubnodesHaveLinks = False)) and (NodeData.SubnodesHaveExclusions = False); if bRenameDirectory then begin bRenameDirectory:= RenameFileUAC(aNode.TheFile.FullPath, AbsoluteTargetFileName); if not bRenameDirectory and (GetLastOSError = ERROR_NOT_SAME_DEVICE) then begin if (not NodeData.Recursive) then begin with TFileSystemTreeBuilder.Create(AskQuestion, CheckOperationState) do try // In move operation don't follow symlinks. SymLinkOption := fsooslDontFollow; BuildFromNode(aNode); FStatistics.TotalFiles += FilesCount; FStatistics.TotalBytes += FilesSize; finally Free; end; NodeData.Recursive:= True; end; end; end; if bRenameDirectory then begin // Success. CountStatistics(aNode); Result := True; bRemoveDirectory := False; end else if NodeData.Recursive then begin // Create target directory. if CreateDirectoryUAC(AbsoluteTargetFileName) then begin // Copy/Move all files inside. Result := ProcessNode(aNode, IncludeTrailingPathDelimiter(AbsoluteTargetFileName)); // Copy attributes after copy/move directory contents, because this operation can change date/time CopyProperties(aNode.TheFile, AbsoluteTargetFileName); end else begin // Error - all files inside not copied/moved. ShowError(rsMsgLogError + Format(rsMsgErrForceDir, [AbsoluteTargetFileName]) + LineEnding + LineEnding + mbSysErrorMessage); Result := False; CountStatistics(aNode); end; end else begin ShowError(rsMsgLogError + Format(rsMsgErrCannotMoveDirectory, [aNode.TheFile.FullPath]) + LineEnding + LineEnding + mbSysErrorMessage); Result := False; CountStatistics(aNode); end; end; fsoterAddToTarget: begin if (FMode = fsohmMove) and (not NodeData.Recursive) then begin with TFileSystemTreeBuilder.Create(AskQuestion, CheckOperationState) do try // In move operation don't follow symlinks. SymLinkOption := fsooslDontFollow; BuildFromNode(aNode); FStatistics.TotalFiles += FilesCount; FStatistics.TotalBytes += FilesSize; finally Free; end; end; // Don't create existing directory, but copy files into it. Result := ProcessNode(aNode, IncludeTrailingPathDelimiter(AbsoluteTargetFileName)); end; else raise Exception.Create('Invalid TargetExists result'); end; if bRemoveDirectory and Result then begin if FileIsReadOnly(aNode.TheFile.Attributes) then FileSetReadOnlyUAC(aNode.TheFile.FullPath, False); RemoveDirectoryUAC(aNode.TheFile.FullPath); end; end; function TFileSystemOperationHelper.ProcessLink(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; var LinkTarget, CorrectedLink: String; aFile: TFile; aSubNode: TFileTreeNode; begin Result := True; // If link was followed then it's target is stored in a subnode. if aNode.SubNodesCount > 0 then begin aSubNode := aNode.SubNodes[0]; //DCDebug('Link ' + aFile.FullPath + ' followed to ' // + (aSubNode.TheFile as TFileSystemFile).FullPath // + ' will be copied as: ' + AbsoluteTargetFileName); if aSubNode.TheFile.AttributesProperty.IsDirectory then Result := ProcessDirectory(aSubNode, AbsoluteTargetFileName) else Result := ProcessFile(aSubNode, AbsoluteTargetFileName); Exit; // exit without counting statistics, because they are not counted for followed links end; aFile := aNode.TheFile; case TargetExists(aNode, AbsoluteTargetFileName) of fsoterSkip: Result := False; fsoterDeleted, fsoterNotExists: begin if (FMode <> fsohmMove) or (not RenameFileUAC(aFile.FullPath, AbsoluteTargetFileName)) then begin LinkTarget := ReadSymLink(aFile.FullPath); // use sLinkTo ? if LinkTarget <> '' then begin if FCorrectSymlinks then begin CorrectedLink := GetAbsoluteFileName(aFile.Path, LinkTarget); // If the link was relative - make also the corrected link relative. if GetPathType(LinkTarget) = ptRelative then LinkTarget := ExtractRelativepath(AbsoluteTargetFileName, CorrectedLink) else LinkTarget := CorrectedLink; end; if CreateSymbolicLinkUAC(LinkTarget, AbsoluteTargetFileName) then begin CopyProperties(aFile, AbsoluteTargetFileName); if (FMode = fsohmMove) then Result:= DeleteFile(aFile); end else begin if not FSkipCreateSymLinkError then begin case AskQuestion(rsSymErrCreate.TrimRight(['.']) + ' ' + WrapTextSimple(AbsoluteTargetFileName, 64) + LineEnding + LineEnding + mbSysErrorMessage, '', [fsourSkip, fsourSkipAll, fsourAbort], fsourSkip, fsourAbort) of fsourAbort: AbortOperation; fsourSkip: ; // Do nothing fsourSkipAll: FSkipCreateSymLinkError := True; end; end; Result := False; end; end else begin DCDebug('Error reading link'); Result := False; end; end; end; fsoterAddToTarget: raise Exception.Create('Cannot add to link'); else raise Exception.Create('Invalid TargetExists result'); end; if Result = True then begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogSymLink, [aNode.TheFile.FullPath + ' -> ' + AbsoluteTargetFileName]), [log_cp_mv_ln], lmtSuccess); end else begin LogMessage(Format(rsMsgLogError + rsMsgLogSymLink, [aNode.TheFile.FullPath + ' -> ' + AbsoluteTargetFileName]), [log_cp_mv_ln], lmtError); end; Inc(FStatistics.DoneFiles); UpdateStatistics(FStatistics); end; function TFileSystemOperationHelper.ProcessFile(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; var OldDoneBytes, OldTotalBytes: Int64; // for if there was an error begin // If there will be an error the DoneBytes value // will be inconsistent, so remember it here. OldDoneBytes := FStatistics.DoneBytes; OldTotalBytes := FStatistics.TotalBytes; // Skip descript.ion, it will be processed below if gProcessComments and (FStatistics.TotalFiles > 1) and mbCompareFileNames(aNode.TheFile.Name, DESCRIPT_ION) then Result:= True else begin Result:= False; {$IF DEFINED(UNIX)} if not fpS_ISREG(aNode.TheFile.Attributes) then begin if FSkipAllSpecialFiles then Exit(False); case AskQuestion('', Format(rsMsgCannotCopySpecialFile, [LineEnding + aNode.TheFile.FullPath]), [fsourSkip, fsourSkipAll, fsourAbort], fsourSkip, fsourAbort) of fsourSkip: Exit(False); fsourSkipAll: begin FSkipAllSpecialFiles:= True; Exit(False); end else AbortOperation; end; end; {$ENDIF} if (aNode.TheFile.Size > GetDiskMaxFileSize(ExtractFileDir(AbsoluteTargetFileName))) then case AskQuestion('', Format(rsMsgFileSizeTooBig, [aNode.TheFile.Name]), [fsourSkip, fsourAbort], fsourSkip, fsourAbort) of fsourSkip: Result := False; else AbortOperation; end else case TargetExists(aNode, AbsoluteTargetFileName) of fsoterSkip: begin with FStatistics do begin Inc(DoneFiles); Dec(TotalBytes, aNode.TheFile.Size); if FVerify and (FMode = fsohmCopy) then Dec(TotalBytes, aNode.TheFile.Size); UpdateStatistics(FStatistics); end; Exit(False); end; fsoterDeleted, fsoterNotExists: Result := MoveOrCopy(aNode.TheFile, AbsoluteTargetFileName, fsohcmDefault); fsoterAddToTarget: Result := MoveOrCopy(aNode.TheFile, AbsoluteTargetFileName, fsohcmAppend); fsoterResume: Result := MoveOrCopy(aNode.TheFile, AbsoluteTargetFileName, fsohcmResume); else raise Exception.Create('Invalid TargetExists result'); end; end; if Result = True then begin LogMessage(Format(rsMsgLogSuccess+FLogCaption, [aNode.TheFile.FullPath + ' -> ' + AbsoluteTargetFileName]), [log_cp_mv_ln], lmtSuccess); end else begin LogMessage(Format(rsMsgLogError+FLogCaption, [aNode.TheFile.FullPath + ' -> ' + AbsoluteTargetFileName]), [log_cp_mv_ln], lmtError); end; with FStatistics do begin DoneFiles := DoneFiles + 1; if not Result then begin DoneBytes := OldDoneBytes + aNode.TheFile.Size; // Increase DoneBytes twice when copy file or move file between different partitions if FVerify and ((FMode = fsohmCopy) or (OldTotalBytes <> TotalBytes)) then DoneBytes += aNode.TheFile.Size; end; UpdateStatistics(FStatistics); end; end; // ---------------------------------------------------------------------------- function TFileSystemOperationHelper.TargetExists(aNode: TFileTreeNode; var AbsoluteTargetFileName: String): TFileSystemOperationTargetExistsResult; var Attrs, LinkTargetAttrs: TFileAttrs; SourceFile: TFile; function DoDirectoryExists(AllowCopyInto: Boolean; AllowDeleteDirectory: Boolean): TFileSystemOperationTargetExistsResult; begin case DirExists(SourceFile, AbsoluteTargetFileName, AllowCopyInto, AllowDeleteDirectory) of fsoodeSkip: Exit(fsoterSkip); fsoodeDelete: begin DeleteFileUAC(AbsoluteTargetFileName); Exit(fsoterDeleted); end; fsoodeCopyInto: begin Exit(fsoterAddToTarget); end; else raise Exception.Create('Invalid dir exists option'); end; end; function DoFileExists(AllowAppend: Boolean): TFileSystemOperationTargetExistsResult; begin case FileExists(SourceFile, AbsoluteTargetFileName, AllowAppend) of fsoofeSkip: Exit(fsoterSkip); fsoofeOverwrite: begin if FileIsReadOnly(Attrs) then FileSetReadOnlyUAC(AbsoluteTargetFileName, False); if FPS_ISLNK(Attrs) or (FMode = fsohmMove) then begin DeleteFileUAC(AbsoluteTargetFileName); Exit(fsoterDeleted); end; Exit(fsoterNotExists); end; fsoofeAppend: begin Exit(fsoterAddToTarget); end; fsoofeResume: begin Exit(fsoterResume); end; fsoofeAutoRenameTarget, fsoofeAutoRenameSource: begin Exit(fsoterRenamed); end else raise Exception.Create('Invalid file exists option'); end; end; function IsLinkFollowed: Boolean; begin // If link was followed then it's target is stored in a subnode. Result := SourceFile.AttributesProperty.IsLink and (aNode.SubNodesCount > 0); end; function AllowAppendFile: Boolean; begin Result := (not SourceFile.AttributesProperty.IsDirectory) and (not FReserveSpace) and ((not SourceFile.AttributesProperty.IsLink) or (IsLinkFollowed and (not aNode.SubNodes[0].TheFile.AttributesProperty.IsDirectory))); end; function AllowCopyInto: Boolean; begin Result := SourceFile.AttributesProperty.IsDirectory or (IsLinkFollowed and aNode.SubNodes[0].TheFile.IsDirectory); end; begin repeat Attrs := FileGetAttrUAC(AbsoluteTargetFileName); if Attrs <> faInvalidAttributes then begin SourceFile := aNode.TheFile; // Target exists - ask user what to do. if FPS_ISLNK(Attrs) then begin // Check if target of the link exists. LinkTargetAttrs := FileGetAttrUAC(AbsoluteTargetFileName, True); if (LinkTargetAttrs <> faInvalidAttributes) then begin if FPS_ISDIR(LinkTargetAttrs) then Result := DoDirectoryExists(AllowCopyInto, False) else Result := DoFileExists(AllowAppendFile); end else // Target of link doesn't exist. Treat link as file and don't allow append. Result := DoFileExists(False); end else if FPS_ISDIR(Attrs) then begin Result := DoDirectoryExists(AllowCopyInto, False) end else // Existing target is a file. Result := DoFileExists(AllowAppendFile); end else Result := fsoterNotExists; until Result <> fsoterRenamed; end; function TFileSystemOperationHelper.DirExists( aFile: TFile; AbsoluteTargetFileName: String; AllowCopyInto: Boolean; AllowDelete: Boolean): TFileSourceOperationOptionDirectoryExists; var Message: String; PossibleResponses: array of TFileSourceOperationUIResponse = nil; DefaultOkResponse: TFileSourceOperationUIResponse; procedure AddResponse(Response: TFileSourceOperationUIResponse); begin SetLength(PossibleResponses, Length(PossibleResponses) + 1); PossibleResponses[Length(PossibleResponses) - 1] := Response; end; begin if (FDirExistsOption = fsoodeNone) or ((FDirExistsOption = fsoodeDelete) and (AllowDelete = False)) or ((FDirExistsOption = fsoodeCopyInto) and (AllowCopyInto = False)) then begin if AllowDelete then AddResponse(fsourOverwrite); if AllowCopyInto then begin AddResponse(fsourCopyInto); AddResponse(fsourCopyIntoAll); end; AddResponse(fsourSkip); if AllowDelete then AddResponse(fsourOverwriteAll); if AllowCopyInto or AllowDelete then AddResponse(fsourSkipAll); AddResponse(fsourCancel); if AllowCopyInto then DefaultOkResponse := fsourCopyInto else if AllowDelete then DefaultOkResponse := fsourOverwrite else DefaultOkResponse := fsourSkip; if AllowCopyInto or AllowDelete then Message:= Format(rsMsgFolderExistsRwrt, [AbsoluteTargetFileName]) else begin Message:= Format(rsMsgCannotOverwriteDirectory, [AbsoluteTargetFileName, aFile.FullPath]); end; case AskQuestion(Message, '', PossibleResponses, DefaultOkResponse, fsourSkip) of fsourOverwrite: Result := fsoodeDelete; fsourCopyInto: Result := fsoodeCopyInto; fsourCopyIntoAll: begin FDirExistsOption := fsoodeCopyInto; Result := fsoodeCopyInto; end; fsourSkip: Result := fsoodeSkip; fsourOverwriteAll: begin FDirExistsOption := fsoodeDelete; Result := fsoodeDelete; end; fsourSkipAll: begin FDirExistsOption := fsoodeSkip; Result := fsoodeSkip; end; fsourNone, fsourCancel: AbortOperation; end; end else Result := FDirExistsOption; end; procedure TFileSystemOperationHelper.QuestionActionHandler( Action: TFileSourceOperationUIAction); begin if Action = fsouaCompare then ShowCompareFilesUI(FCurrentFile, FCurrentTargetFilePath); end; function TFileSystemOperationHelper.FileExists(aFile: TFile; var AbsoluteTargetFileName: String; AllowAppend: Boolean ): TFileSourceOperationOptionFileExists; const Responses: array[0..13] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourRenameSource, fsourOverwriteAll, fsourSkipAll, fsourResume, fsourOverwriteOlder, fsourCancel, fsouaCompare, fsourAppend, fsourOverwriteSmaller, fsourOverwriteLarger, fsourAutoRenameSource, fsourAutoRenameTarget); ResponsesNoAppend: array[0..11] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourRenameSource, fsourOverwriteAll, fsourSkipAll, fsouaCompare, fsourOverwriteOlder, fsourCancel, fsourOverwriteSmaller, fsourOverwriteLarger, fsourAutoRenameSource, fsourAutoRenameTarget); var Answer: Boolean; Message: String; PossibleResponses: TFileSourceOperationUIResponses; function RenameTarget: TFileSourceOperationOptionFileExists; var bRetry: Boolean; begin repeat Message:= GetNextCopyName(AbsoluteTargetFileName, aFile.IsDirectory or aFile.IsLinkToDirectory); if RenameFileUAC(AbsoluteTargetFileName, Message) then Exit(fsoofeAutoRenameTarget); bRetry:= False; Message:= Format(rsMsgErrRename, [AbsoluteTargetFileName, Message]); case AskQuestion(Message, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetry:= True; fsourSkip: Result := fsoofeSkip; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourNone, fsourAbort: AbortOperation; end; until not bRetry; end; function OverwriteOlder: TFileSourceOperationOptionFileExists; begin if CompareDateTime(aFile.ModificationTime, FileTimeToDateTimeEx(mbFileGetTime(AbsoluteTargetFileName))) = GreaterThanValue then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteSmaller: TFileSourceOperationOptionFileExists; begin if aFile.Size > mbFileSize(AbsoluteTargetFileName) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteLarger: TFileSourceOperationOptionFileExists; begin if aFile.Size < mbFileSize(AbsoluteTargetFileName) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; begin case FFileExistsOption of fsoofeNone: repeat Answer := True; case AllowAppend of True : PossibleResponses := Responses; False: PossibleResponses := ResponsesNoAppend; end; Message:= FileExistsMessage(AbsoluteTargetFileName, aFile.FullPath, aFile.Size, aFile.ModificationTime); FCurrentFile := aFile; FCurrentTargetFilePath := AbsoluteTargetFileName; case AskQuestion(Message, '', PossibleResponses, fsourOverwrite, fsourSkip, @QuestionActionHandler) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourAppend: begin //FFileExistsOption := fsoofeAppend; - for AppendAll Result := fsoofeAppend; end; fsourResume: begin Result := fsoofeResume; end; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourOverwriteOlder: begin FFileExistsOption := fsoofeOverwriteOlder; Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin FFileExistsOption := fsoofeOverwriteSmaller; Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin FFileExistsOption := fsoofeOverwriteLarger; Result:= OverwriteLarger; end; fsourAutoRenameSource: begin Result:= fsoofeAutoRenameSource; FFileExistsOption:= fsoofeAutoRenameSource; AbsoluteTargetFileName:= GetNextCopyName(AbsoluteTargetFileName, aFile.IsDirectory or aFile.IsLinkToDirectory); end; fsourAutoRenameTarget: begin FFileExistsOption := fsoofeAutoRenameTarget; Result:= RenameTarget; end; fsourRenameSource: begin Message:= ExtractFileName(AbsoluteTargetFileName); Answer:= ShowInputQuery(FOperationThread, Application.Title, rsEditNewFileName, Message); if Answer then begin Result:= fsoofeAutoRenameSource; AbsoluteTargetFileName:= ExtractFilePath(AbsoluteTargetFileName) + Message; end; end; fsourNone, fsourCancel: AbortOperation; end; until Answer; fsoofeOverwriteOlder: begin Result:= OverwriteOlder; end; fsoofeOverwriteSmaller: begin Result:= OverwriteSmaller; end; fsoofeOverwriteLarger: begin Result:= OverwriteLarger; end; fsoofeAutoRenameTarget: begin Result:= RenameTarget; end; fsoofeAutoRenameSource: begin Result:= fsoofeAutoRenameSource; AbsoluteTargetFileName:= GetNextCopyName(AbsoluteTargetFileName, aFile.IsDirectory or aFile.IsLinkToDirectory); end; else Result := FFileExistsOption; end; end; procedure TFileSystemOperationHelper.SkipStatistics(aNode: TFileTreeNode); procedure SkipNodeStatistics(aNode: TFileTreeNode); var aFileAttrs: TFileAttributesProperty; i: Integer; begin aFileAttrs := aNode.TheFile.AttributesProperty; with FStatistics do begin if aFileAttrs.IsDirectory then begin // No statistics for directory. // Go through subdirectories. for i := 0 to aNode.SubNodesCount - 1 do SkipNodeStatistics(aNode.SubNodes[i]); end else if aFileAttrs.IsLink then begin // Count only not-followed links. if aNode.SubNodesCount = 0 then TotalFiles := TotalFiles - 1 else // Count target of link. SkipNodeStatistics(aNode.SubNodes[0]); end else begin // Count files. TotalFiles := TotalFiles - 1; TotalBytes := TotalBytes - aNode.TheFile.Size; end; end; end; begin SkipNodeStatistics(aNode); UpdateStatistics(FStatistics); end; procedure TFileSystemOperationHelper.ShowError(sMessage: String); begin if gSkipFileOpError then begin if log_errors in gLogOptions then logWrite(FOperationThread, sMessage, lmtError, True); end else begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) <> fsourSkip then begin AbortOperation; end; end; end; procedure TFileSystemOperationHelper.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(FOperationThread, sMessage, logMsgType); end; end; function TFileSystemOperationHelper.DeleteFile(SourceFile: TFile): Boolean; var Message: String; RetryDelete: Boolean; begin repeat RetryDelete := True; if FileIsReadOnly(SourceFile.Attributes) then FileSetReadOnlyUAC(SourceFile.FullPath, False); Result := DeleteFileUAC(SourceFile.FullPath); if (not Result) and (FDeleteFileOption = fsourInvalid) then begin Message := Format(rsMsgNotDelete, [WrapTextSimple(SourceFile.FullPath, 100)]) + LineEnding + LineEnding + mbSysErrorMessage; case AskQuestion('', Message, [fsourSkip, fsourRetry, fsourAbort, fsourSkipAll], fsourSkip, fsourAbort) of fsourAbort: AbortOperation; fsourRetry: RetryDelete := False; fsourSkipAll: FDeleteFileOption := fsourSkipAll; end; end; until RetryDelete; end; function TFileSystemOperationHelper.CheckFileHash(const FileName, Hash: String; Size: Int64): Boolean; const BLOCK_SIZE = $20000; var Handle: THandle; FileHash: String; bRetryRead: Boolean; Context: THashContext; Buffer, Aligned: Pointer; TotalBytesToRead: Int64 = 0; BytesRead, BytesToRead: Int64; begin Result := False; FStatistics.CurrentFileDoneBytes:= 0; // Flag fmOpenDirect requires: file access sizes must be for a number of bytes // that is an integer multiple of the volume block size, file access buffer // addresses for read and write operations should be physical block size aligned BytesToRead:= BLOCK_SIZE; Buffer:= GetMem(BytesToRead * 2 - 1); {$PUSH}{$HINTS OFF}{$WARNINGS OFF} Aligned:= Pointer(PtrUInt(Buffer + BytesToRead - 1) and not (BytesToRead - 1)); {$POP} HashInit(Context, HASH_TYPE); try Handle:= FileOpenUAC(FileName, fmOpenRead or fmShareDenyWrite or fmOpenSync or fmOpenDirect); if Handle = feInvalidHandle then begin case AskQuestion(rsMsgVerify, rsMsgErrEOpen + ' ' + FileName, [fsourSkip, fsourAbort], fsourAbort, fsourSkip) of fsourAbort: AbortOperation(); fsourSkip: Exit(False); end; // case end else begin TotalBytesToRead := Size; while TotalBytesToRead > 0 do begin repeat try bRetryRead := False; BytesRead := FileRead(Handle, Aligned^, BytesToRead); if (BytesRead <= 0) then Raise EReadError.Create(mbSysErrorMessage(GetLastOSError)); TotalBytesToRead := TotalBytesToRead - BytesRead; HashUpdate(Context, Aligned^, BytesRead); except on E: EReadError do begin case AskQuestion(rsMsgVerify + ' ' + rsMsgErrERead + ' ' + FileName + LineEnding, E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryRead := True; fsourAbort: AbortOperation(); fsourSkip: Exit(False); end; // case end; end; until not bRetryRead; with FStatistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + BytesRead; DoneBytes := DoneBytes + BytesRead; UpdateStatistics(FStatistics); end; CheckOperationState; // check pause and stop end; // while Result := True; end; finally FreeMem(Buffer); HashFinal(Context, FileHash); if Handle <> feInvalidHandle then begin FileClose(Handle); end; if Result then begin Result:= SameText(Hash, FileHash); if not Result then begin case AskQuestion(rsMsgVerify, rsMsgVerifyWrong + LineEnding + FileName, [fsourSkip, fsourAbort], fsourAbort, fsourSkip) of fsourAbort: AbortOperation(); end; // case end; end; end; end; function TFileSystemOperationHelper.CompareFiles(const FileName1, FileName2: String; Size: Int64): Boolean; const BLOCK_SIZE = $20000; BUF_LEN = 1024 * 1024 * 8; var Count: Int64; Buffer1, Buffer2: PByte; Aligned1, Aligned2: PByte; File1, File2: TFileStreamUAC; begin Buffer1:= GetMem(BUF_LEN * 2); Buffer2:= GetMem(BUF_LEN * 2); try if (Buffer1 = nil) or (Buffer2 = nil) then raise EOutOfMemory.Create(SOutOfMemory); Aligned1:= Align(Buffer1, BLOCK_SIZE); Aligned2:= Align(Buffer2, BLOCK_SIZE); try File1 := TFileStreamUAC.Create(FileName1, fmOpenRead or fmShareDenyWrite or fmOpenSync or fmOpenDirect); try File2 := TFileStreamUAC.Create(FileName2, fmOpenRead or fmShareDenyWrite or fmOpenSync or fmOpenDirect); try FStatistics.CurrentFileDoneBytes:= 0; repeat if Size - FStatistics.CurrentFileDoneBytes <= BUF_LEN then Count := Size - FStatistics.CurrentFileDoneBytes else begin Count := BUF_LEN; end; File1.ReadBuffer(Aligned1^, Count); File2.ReadBuffer(Aligned2^, Count); if (Count <> BUF_LEN) then Result := CompareMem(Aligned1, Aligned2, Count) else begin Result := CompareDWord(Aligned1^, Aligned2^, Count div SizeOf(Dword)) = 0; end; with FStatistics do begin DoneBytes += Count; CurrentFileDoneBytes += Count; UpdateStatistics(FStatistics); end; CheckOperationState; // check pause and stop until not Result or (FStatistics.CurrentFileDoneBytes >= Size); finally File2.Free; end; finally File1.Free; end; except on E: Exception do begin if E is EFileSourceOperationAborting then raise; case AskQuestion(rsMsgVerify, E.Message, [fsourSkip, fsourAbort], fsourAbort, fsourSkip) of fsourAbort: AbortOperation(); fsourSkip: Exit(False); end; // case end; end; finally if Assigned(Buffer1) then FreeMem(Buffer1); if Assigned(Buffer2) then FreeMem(Buffer2); end; end; procedure TFileSystemOperationHelper.CountStatistics(aNode: TFileTreeNode); procedure CountNodeStatistics(aNode: TFileTreeNode); var aFileAttrs: TFileAttributesProperty; i: Integer; begin aFileAttrs := aNode.TheFile.AttributesProperty; with FStatistics do begin if aFileAttrs.IsDirectory then begin // No statistics for directory. // Go through subdirectories. for i := 0 to aNode.SubNodesCount - 1 do CountNodeStatistics(aNode.SubNodes[i]); end else if aFileAttrs.IsLink then begin // Count only not-followed links. if aNode.SubNodesCount = 0 then DoneFiles := DoneFiles + 1 else // Count target of link. CountNodeStatistics(aNode.SubNodes[0]); end else begin // Count files. DoneFiles := DoneFiles + 1; DoneBytes := DoneBytes + aNode.TheFile.Size; end; end; end; begin CountNodeStatistics(aNode); UpdateStatistics(FStatistics); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/filesystem/ufilesystemwipeoperation.pas����������������������������0000644�0001750�0000144�00000033224�14743153644�025774� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This module implements a secure erase of disk media as per the Department of Defense clearing and sanitizing standard: DOD 5220.22-M The standard states that hard disk media is erased by overwriting with a character, then the character's complement, and then a random character. Note that the standard specicically states that this method is not suitable for TOP SECRET information. TOP SECRET data sanatizing is only achievable by a Type 1 or 2 degauss of the disk, or by disintegrating, incinerating, pulverizing, shreding, or melting the disk. Copyright (C) 2008-2018 Alexander Koblov (alexx2000@mail.ru) Based on: WP - wipes files in a secure way. version 3.2 - By Uri Fridman. urifrid@yahoo.com www.geocities.com/urifrid 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, see <http://www.gnu.org/licenses/>. } unit uFileSystemWipeOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, ISAAC, uFileSourceWipeOperation, uFileSource, uFileSourceOperationOptions, uFileSourceOperationUI, uFile, uDescr, uGlobs, uLog; type { TFileSystemWipeOperation } TFileSystemWipeOperation = class(TFileSourceWipeOperation) private FRandom: isaac_ctx; FBuffer: array [0..2, 0..4095] of Byte; private procedure Fill(Step: Integer); function WipeDir(const FileName: String): Boolean; function WipeLink(const FileName: String): Boolean; function WipeFile(const FileName: String): Boolean; function Rename(const FileName: String; out NewName: String): Boolean; private FDescription: TDescription; FFullFilesTreeToDelete: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceWipeOperationStatistics; // local copy of statistics // Options FSkipErrors: Boolean; FWipePassNumber: Integer; FSymLinkOption: TFileSourceOperationOptionSymLink; FDeleteReadOnly: TFileSourceOperationOptionGeneral; protected procedure Wipe(aFile: TFile); function HandleError(const Message: String): Boolean; procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFilesToWipe: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses uDebug, uLng, DCClassesUtf8, uFileSystemUtil, uRandom, uAdministrator, DCOSUtils; constructor TFileSystemWipeOperation.Create(aTargetFileSource: IFileSource; var theFilesToWipe: TFiles); begin FSkipErrors := False; FSymLinkOption := fsooslNone; FDeleteReadOnly := fsoogNone; FFullFilesTreeToDelete := nil; FWipePassNumber:= gWipePassNumber; if gProcessComments then FDescription := TDescription.Create(True) else FDescription := nil; inherited Create(aTargetFileSource, theFilesToWipe); end; destructor TFileSystemWipeOperation.Destroy; begin inherited Destroy; if Assigned(FDescription) then begin FDescription.SaveDescription; FreeAndNil(FDescription); end; FreeAndNil(FFullFilesTreeToDelete); end; procedure TFileSystemWipeOperation.Initialize; begin Fill(0); Fill(1); isaac_init(FRandom, Int32(GetTickCount64)); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FillAndCount(FilesToWipe, True, False, FFullFilesTreeToDelete, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) if gProcessComments then FDescription.Clear; end; procedure TFileSystemWipeOperation.MainExecute; var aFile: TFile; CurrentFileIndex: Integer; OldDoneBytes: Int64; // for if there was an error begin for CurrentFileIndex := FFullFilesTreeToDelete.Count - 1 downto 0 do begin aFile := FFullFilesTreeToDelete[CurrentFileIndex]; FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); // If there will be an error in Wipe the DoneBytes value // will be inconsistent, so remember it here. OldDoneBytes := FStatistics.DoneBytes; Wipe(aFile); with FStatistics do begin DoneFiles := DoneFiles + 1; // Correct statistics if file not correctly processed. if DoneBytes < (OldDoneBytes + aFile.Size) then DoneBytes := OldDoneBytes + aFile.Size; UpdateStatistics(FStatistics); end; CheckOperationState; end; end; //fill buffer with characters //0 = with 0, 1 = with 1 and 2 = random procedure TFileSystemWipeOperation.Fill(Step: Integer); var Index: Integer; Count: Integer; begin Count:= SizeOf(FBuffer[Step]); case Step of 0: begin Count:= Count div SizeOf(DWord); FillDWord(FBuffer[Step, 0], Count, $00000000); end; 1: begin Count:= Count div SizeOf(DWord); FillDWord(FBuffer[Step, 0], Count, $FFFFFFFF); end; 2: begin Index:= 0; while Index < Count do begin Move(FRandom.randrsl[0], FBuffer[Step, Index], SizeOf(FRandom.randrsl)); Inc(Index, SizeOf(FRandom.randrsl)); isaac_generate(FRandom); end; end; end; end; function TFileSystemWipeOperation.Rename(const FileName: String; out NewName: String): Boolean; var bRetry: Boolean; begin repeat bRetry := False; NewName:= GetTempName(ExtractFilePath(FileName)); Result := RenameFileUAC(FileName, NewName); if not Result then bRetry := HandleError(Format(rsMsgErrRename, [FileName, NewName])); until not bRetry; end; function TFileSystemWipeOperation.WipeDir(const FileName: String): Boolean; var bRetry: Boolean; sTempFileName: String; begin Result:= Rename(FileName, sTempFileName); if Result then begin repeat bRetry := False; Result:= RemoveDirectoryUAC(sTempFileName); if not Result then bRetry := HandleError(Format(rsMsgCannotDeleteDirectory, [sTempFileName])); until not bRetry; end; end; function TFileSystemWipeOperation.WipeLink(const FileName: String): Boolean; var bRetry: Boolean; sTempFileName: String; begin Result:= Rename(FileName, sTempFileName); if Result then repeat bRetry := False; Result := DeleteFileUAC(sTempFileName); if not Result then begin bRetry := HandleError(Format(rsMsgNotDelete, [sTempFileName]) + LineEnding + mbSysErrorMessage); end; until not bRetry; end; function TFileSystemWipeOperation.WipeFile(const FileName: String): Boolean; var i, j: Integer; bRetry: Boolean; sTempFileName: String; TotalBytesToWrite: Int64; TargetFileStream: TFileStreamUAC; BytesToWrite, BytesWrittenTry, BytesWritten: Int64; begin // Check file access repeat bRetry := False; Result:= mbFileAccess(FileName, fmOpenWrite); if not Result then begin bRetry := HandleError(rsMsgErrEOpen + ' ' + FileName); if not bRetry then Exit(False); end; until not bRetry; if not Rename(FileName, sTempFileName) then Exit(False); // Try to open file repeat bRetry := False; try TargetFileStream := TFilestreamUAC.Create(sTempFileName, fmOpenReadWrite or fmShareExclusive); except on E: Exception do begin bRetry := HandleError(rsMsgErrEOpen + ' ' + sTempFileName + LineEnding + E.Message); if not bRetry then Exit(False); end; end; until not bRetry; try for i := 1 to FWipePassNumber do begin CheckOperationState; // check pause and stop FStatistics.CurrentFileTotalBytes:= TargetFileStream.Size * 3; FStatistics.CurrentFileDoneBytes:= 0; UpdateStatistics(FStatistics); for j:= 0 to 2 do begin TargetFileStream.Position := 0; TotalBytesToWrite := TargetFileStream.Size; while TotalBytesToWrite > 0 do begin BytesWritten := 0; if (j = 2) then Fill(j); if TotalBytesToWrite > SizeOf(FBuffer[j]) then BytesToWrite := SizeOf(FBuffer[j]) else begin BytesToWrite := TotalBytesToWrite; end; repeat bRetry := False; try BytesWrittenTry := TargetFileStream.Write(FBuffer[j, BytesWritten], BytesToWrite); BytesWritten := BytesWritten + BytesWrittenTry; if BytesWrittenTry = 0 then begin raise EWriteError.Create(mbSysErrorMessage(GetLastOSError)); end else if BytesWritten < BytesToWrite then begin bRetry := True; // repeat and try to write the rest Dec(BytesToWrite, BytesWrittenTry); end; except on E: Exception do begin bRetry:= HandleError(rsMsgErrEWrite + ' ' + sTempFileName + LineEnding + E.Message); if not bRetry then Exit(False); end; end; until not bRetry; Dec(TotalBytesToWrite, BytesWritten); with FStatistics do begin Inc(CurrentFileDoneBytes, BytesWritten); Inc(DoneBytes, BytesWritten div (3 * Int64(FWipePassNumber))); UpdateStatistics(FStatistics); CheckOperationState; // check pause and stop end; end; // Flush data to disk repeat bRetry := False; Result := FileFlush(TargetFileStream.Handle); if not Result then begin bRetry := HandleError(rsMsgErrEWrite + ' ' + sTempFileName + LineEnding + mbSysErrorMessage); if not bRetry then Exit; end; until not bRetry; CheckOperationState; // check pause and stop end; end; // Truncate file size to zero repeat bRetry := False; Result := FileTruncate(TargetFileStream.Handle, 0); if not Result then begin bRetry := HandleError(rsMsgErrEWrite + ' ' + sTempFileName + LineEnding + mbSysErrorMessage); if not bRetry then Exit; end; until not bRetry; finally FreeAndNil(TargetFileStream); end; if Result then repeat bRetry := False; Result := DeleteFileUAC(sTempFileName); if not Result then begin bRetry := HandleError(Format(rsMsgNotDelete, [sTempFileName]) + LineEnding + mbSysErrorMessage); end; until not bRetry; end; procedure TFileSystemWipeOperation.Wipe(aFile: TFile); var FileName: String; WipeResult: Boolean; begin FileName := aFile.FullPath; if FileIsReadOnly(aFile.Attributes) then begin case FDeleteReadOnly of fsoogNone: case AskQuestion(Format(rsMsgFileReadOnly, [FileName]), '', [fsourYes, fsourSkip, fsourAbort, fsourAll, fsourSkipAll], fsourYes, fsourAbort) of fsourAll: FDeleteReadOnly := fsoogYes; fsourSkip: Exit; fsourSkipAll: begin FDeleteReadOnly := fsoogNo; Exit; end; fsourAbort: RaiseAbortOperation; end; fsoogNo: Exit; end; end; if FileIsReadOnly(aFile.Attributes) then FileSetReadOnlyUAC(FileName, False); if aFile.IsDirectory then // directory WipeResult := WipeDir(FileName) else if aFile.IsLink then // symbolic link WipeResult := WipeLink(FileName) else begin // normal file WipeResult := WipeFile(FileName); end; if aFile.IsDirectory then begin if not WipeResult then LogMessage(Format(rsMsgLogError + rsMsgLogWipeDir, [FileName]), [log_dir_op, log_delete], lmtError) else LogMessage(Format(rsMsgLogSuccess + rsMsgLogWipeDir, [FileName]), [log_dir_op, log_delete], lmtSuccess); end else begin if not WipeResult then LogMessage(Format(rsMsgLogError + rsMsgLogWipe, [FileName]), [log_delete], lmtError) else LogMessage(Format(rsMsgLogSuccess + rsMsgLogWipe, [FileName]), [log_delete], lmtSuccess); end; // Process comments if need if WipeResult and gProcessComments then FDescription.DeleteDescription(FileName); end; function TFileSystemWipeOperation.HandleError(const Message: String): Boolean; begin Result := False; if gSkipFileOpError then begin logWrite(Thread, Message, lmtError, True); end else if not FSkipErrors then begin case AskQuestion(Message, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: Result := True; fsourAbort: RaiseAbortOperation; fsourSkip: ; // Do nothing fsourSkipAll: FSkipErrors := True; end; end; end; procedure TFileSystemWipeOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016476� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/fgioauthdlg.lfm������������������������������������������������0000644�0001750�0000144�00000027636�14743153644�021511� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmGioAuthDialog: TfrmGioAuthDialog Left = 487 Height = 215 Top = 67 Width = 375 AutoSize = True BorderStyle = bsDialog ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 215 ClientWidth = 375 Constraints.MinWidth = 375 Position = poScreenCenter LCLVersion = '1.6.0.4' object imgAuth: TImage AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 8 Height = 48 Top = 8 Width = 48 AutoSize = True Picture.Data = { 1754506F727461626C654E6574776F726B477261706869639E0C000089504E47 0D0A1A0A0000000D49484452000000300000003008060000005702F987000000 017352474200AECE1CE900000006624B474400FF00FF00FFA0BDA79300000009 7048597300000DD700000DD70142289B780000000774494D4507DB080F071810 46DD836300000C1E4944415468DEED99696C5CD775C7FFF7BE75567286FB4E4A 946451FB92C892BA08B12CD5B69C1510827C285023C856A4881D470E69B4982F 7165C9551314719AB641F3A51FE43A4E1D25B2C5489614CB5A182D96646DDCB7 216786E4BCD9E76DF7DE7E9811CB2869E02816ED02BDC0C50CDE9CF3707FE79C 7BCEB97780FFE383FC6F3F9C3C79D2AF7AA4373CBAE7615DD36555D50A9515A1 F16231F72BCBB2DF4CA5B2C7366FDE5CF8C8029C38D57BA3BEB6BEABA9B119B2 A2429115A8AA0AC77190CEA45028E4529665FFB8E09A3F58BF727DFF470EA0F7 ADA37CD3BA8F93A9E94930E62210A8444B730B2CCB86AA2A2084229FCFC148CD 8942A1D06B99C57D9B363D7C6DB101E8EF2163966DC1B48A30D2C6778D64AA66 70F0CEA3F178F4603C3E356EA4E62049148D0DCDA4AEB661B7C7E7BBDC77F9C2 BF9EEC3B59FF9100101CE763F1289A1A9B0190AF1AC6CCEAAEAEB5C73B3B1FDA D7D27271492697FED4ECDCEC9BF1C4342714686FED901A6AEBBFE8A7DAC0E9B7 4FFEF5871E42478F1E0DCA3A195CD1B9A2C6A37B71EBF60DC7B2EDAFEFDAF9D8 0F17CADD18B8B18A30719052F258385405894A181D1F412693FE0FDBE45FDEBD 7B77FE43010080DEDE23CBA8A2FCAA6BC5AA7A55D5717BE0268AF9DCCB3E6FFE D96DDBF61617CABE7BFDE22EEEF2433E5F60556D4D2DA663D3181E1932870747 662DCBC901483026AE13224E158B9EDE48E46F320F1C00008E1D3BD64264F67A 5B6BFB86CA8A10C627C661A4674708A4AF3FFA89BFF8C55DB9175E7AA14B97E4 7FEA5CD6F9677575F5726B4B3B72B90C46C68621530D54926099261289193B11 9F7518633F1682753FF7DC73D9070A0000478E1CF16A5EF9DF7D5EEFDEF6B60E 388E83F1C93198A6F95330F6DCBBEFBEB79DCAF4E5952BBBB4D87482FA033ED4 D5D56049C712148B266289692C695F0ADBB2E03206C7B171FBCE803D32343AE3 38D8D5D3F3ECCD070A00004208F2CB136F7E89CAE4859AAADAF0D28E6548A753 38DF775644A7A6F8C73FB645BA72F92AEAEBEBB17EFD5A080023A3837868D94A 4CC7A730376BA0ABAB0B9665C2765CC812453C9E1017CE5F4A3A8EB5B9BBBB7B F403CD42BF454A88D8B5F3B11FC29597C713B17FBE72EDD73C9E886162224AB6 6DDD2E0DF40FA1A6BA06EBD7AF43201044DA48636C64323B363186C6FA26B8CC 16972F5D81AAE9A004B01D1BB575B564C3C6B52145D17E1E8944E80305B83B76 EEDC39B7EB91C7BF5AB48A5BCEF59D8B3FF4D00AE40B7918C934D66F5C8B5C3E 034A292E5EBC84C6E6FA002040A90C5991AD3B7706012E402905A5121CC7466B 6B330D87431D5EAFFF8B8B02309F757E7D63B2982F56B4B4B462B07F18EBD6AD 06E70C9C7364B319D8B68BBAEA3A04FD15181A1940A150B846482962A9248152 0A42081CD7C5EAB52BBD94D26F2D2A0083B3A7B5A58D73C66024D3686E6982EB B890CA96ED58D28E4B97DF15935313666236716AF0CEE8FAA6A606C88A0C4208 2452F282E00C55E12AA8AADA78E0C081A57FE83AE4FB059065795B5575D89B4E 67E1F379A1280A6CDB02A5148EEB60E5CAE5B06D8B5CBF7A471742EC686F6FC3 B6ED5B21B88044244002280400094270545787D9D858612380A14501A0200DAA AA2197CB4255D5D2334A21840000D8B68575EBD660C38675E09CC3EBF54140C0 751C104A4041200909800040E0F3F9144250BD681E0050E442409452ECFCC604 0444F9B96599701C079C73A4520602C10AE89A064A693935030214945230CE04 40DC45DB035CB09BB94C96852A2A90C96421D1D24238E7C8E5F2309249CCCECE 219BCBC1B26D702150C8E5C05C0610024A4AF2129520491272D9BC0DB0F14503 70B97B2A3A1D2D042B2B000264B279082E70EBD66DC46271E4727970CE41CAD5 92828250A050CC838094C2A8EC3521041289844708D1B768004BDB569C4C1B29 DB344D842A2B30D03F009FDF875028044A040821A5C513024228082D7D7221E0 D81608290148928CA9A99820845CE8EEEE36160D60EFDEBDCCE5ACE7CAE5CB85 CE651DB8736700F97C014B3ADA21ABDA6F742B64BE6B21902885CBDCB2F54B21 77E9E295A265B9DD8B5A0700C02A38FF964A1B971389B8D3D45C8F13C7DF02A5 0A562C5F01BFCF575AB3004048C9E28494810884E02020E8EBBB683A8EFD9F3D 3DFBDE5974804824C2298A4F0E8F8E4E575404A0A80A7E71F40D70C6D0D1B114 ADAD6D08852AA1EB1EE89A024DD7A1697A290B09829B376FB1B1D1F16B994CFA 2B1FF891F2FD8EA79F8EA408A0D4D7376069673B344DC14F7EF23AAE5DBB0E89 4AA8AAAA4175751582C14A783C1EC89204C761E04240D3344A08FA23918879DF 05F58F053874E890C7E5569522CBA80A57419224787D31F40F0CE0EAD5EBF0FB FDF8DCE73E09084040802A145CE4C05C070D0D0D8473EC7E2087FAF73B9E79E6 992221F8FB2BD7AF145455452010404B4B33EA1BAAB17CC51214CD8298994942 966548B4D4C4C9928CA269A2A232084D537DF7D3037D6000A5AAC65F8B4E44F5 4C26035996C1184355388C254B97A0582C3867CF9E2B663219288A024996A069 2A0AF90220085A5A9AC19878F44301884422F41FBF77E0652AAB7D1B366C2415 C10A101098A6054551C0980BCBCE8B4462F61BAFBEFA5FC69933E74C4A283C1E 0F2CCB826D5B686B6BF1EABAFE990F05C0EB55D6CBB2FA977B9E7852EBECEC24 5C7030C6619945783C5E1849033E9FFF4277F7BE7F9124F967B222498CB1524D 20402A9D467D431D1CC7FD93575E79455A74004678D0716C52340BF3876BD32C 82730E8FD783583C6672CE7FBA7FFFFE559462EFDA35AB15D775C13883A66A30 92B3D0351DC1A09F0D0D8D6F5C7480EE6FFDED29DB743E7BE2C4F1ECCCCCAC90 6505D96C0E9AAA419664C462319711F4027447737353B95B2D75AF5EAF8E39C3 80E338686D6D5125E9FEB2D11FBD89BFFDEDE78FB9AEFD77232343454A095269 03814000C54211B66DBB3DCFF6DCE49C9E181E1EC1E1C3AFE64F9D7E3B373D15 13FE4010AEE3209D4EA1A1A1419365F9338B5A07BE73F03BAB3DB2FA82107CB3 00426D6DEDBA6DDB706C1BA1501813D14948941C07809E9E676F0B217CFBF7EF 5F3A3A52FC6C3693ED79FCF1DD153E9F17B3C939B4B6B4C175DDD59148C41B89 440A8BE201954A7FD5D6DEF6C49E3D9F6CF8C2E7BFA037373523954E43D33CF0 FA7C88C5A6338ECD7EB6F05A261C0E8FC9B2FC312A490AE70CC1400552460A12 95100E878BBAAEFFE9A28510A5D4234BB253110CE2EEC92C9BC92014AA84E01C B1585C755571FCAEFC8B2FBE18C8E70B6FD737D4EDD9B163BBD7652EFC8100F2 851C6CDB465373634051D43D8B06609BECF9FE8101DB4819A52B1200D96C06D5 55D5481A491082D8F34F3F3FBDC0033ED7659BB66CD9A40380EB32E8BA064228 32D934EAEA6A28409F583400429C660891E8EFEF679450148A45702E50595981 582CCE39134717CAEFDBB72F46A974A6B7F7547E2E999A3F3BFBFD3E18461295 9595E09C351E3C78B0F68103BC74E8408FAAEBE7B73EBCB5EDE12D5B25102093 CE201008824A0AA2D1C92C13EED17BF5BEF9CD6F7C229FCB7CEDD45B6F174647 26C08580DFE7472A950221404D4D95EDBAE291070E40089EFED4939FF6AE5CB9 4AA612052514D95C06E1AA305CC7C15C72CE63E69DD3BFEB7E9531761610B4AA 3A0CC65CF87DFEF9B6A2A1A12EA069CAA71F14000120B7B7B7EB103C1E9D8ABA 840094500801E47239842B4388CF24204BF2ED728F7FEFED379165E507CB972F 95155502671CB22243D554188681503804D7658F00D0CA299E7C1075800290CA B2D2E8E8A8D477E1CAE705C8D9DA9ADA406D6D1DF2F92C0821F0FB03B8FEDE7B 762E9FFB39001D0003E0960F9614800C821ADDA3CB9CF3BB775A08F883300C03 9AEA018028004F59F7AEBE0B80DF8F074879F14A79AA00B4C3870F272727A3DD BDC77F59304D1373C924828120F2F93C868787D87474EA4C59765EA7FC5D9E9D 99FBFEB5AB37F217CE5D2CCC2593E09C83CA14F1C40C060606AD6432F94A595E 2D1B4DFE7DDE90DE07C05D0FD085F3FCB90B835BB76E69BC71EB46576226614A 9244CEF79DB70C23F5BD7F78E9BBAF952DC6CBD69F37D83BEF9CE99F9818FF51 5D5D5D3A39975E3D31314526C6A2C865F3C9542AF3C6E9D3277F343E3E9E5FA0 BF70DED73F34BF1142F74CB266CD1AFF23BB766C095586FE3C9F2D5C3870E0A5 D717B8FFB7436881BECFE7939F7AEAA9EDA3A3D1D123475E8B2E58287BBF2144 FEC04D7CAF27EED517F7588CDDE301B20080CE5F16FDCF058C58F00EF63BF4FF 7F7CE4C67F0326A2B675DDA7D6BA0000000049454E44AE426082 } end object pnlUser: TPanel AnchorSideLeft.Control = pnlConnect AnchorSideTop.Control = pnlConnect AnchorSideTop.Side = asrBottom Left = 72 Height = 72 Top = 79 Width = 287 AutoSize = True BorderSpacing.Top = 10 BevelOuter = bvNone ClientHeight = 72 ClientWidth = 287 Color = clForm ParentColor = False TabOrder = 0 object lblUserName: TLabel AnchorSideLeft.Control = pnlUser AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrCenter Left = 0 Height = 14 Top = 3 Width = 69 Caption = 'User name:' ParentColor = False end object edtUserName: TEdit AnchorSideLeft.Control = lblUserName AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlUser AnchorSideRight.Side = asrBottom Left = 87 Height = 20 Top = 0 Width = 200 BorderSpacing.Left = 18 TabOrder = 0 end object lblDomain: TLabel AnchorSideLeft.Control = pnlUser AnchorSideTop.Control = edtDomain AnchorSideTop.Side = asrCenter Left = 0 Height = 14 Top = 29 Width = 50 Caption = 'Domain:' ParentColor = False end object edtDomain: TEdit AnchorSideLeft.Control = edtUserName AnchorSideTop.Control = edtUserName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtPassword AnchorSideRight.Side = asrBottom Left = 87 Height = 20 Top = 26 Width = 200 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 1 end object lblPassword: TLabel AnchorSideLeft.Control = pnlUser AnchorSideTop.Control = edtPassword AnchorSideTop.Side = asrCenter Left = 0 Height = 14 Top = 55 Width = 59 Caption = 'Password:' ParentColor = False end object edtPassword: TEdit AnchorSideLeft.Control = edtUserName AnchorSideTop.Control = edtDomain AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtUserName AnchorSideRight.Side = asrBottom Left = 87 Height = 20 Top = 52 Width = 200 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 EchoMode = emPassword PasswordChar = '*' TabOrder = 2 end end object lblMessage: TLabel AnchorSideLeft.Control = imgAuth AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = imgAuth AnchorSideRight.Control = pnlUser AnchorSideRight.Side = asrBottom Left = 72 Height = 1 Top = 8 Width = 287 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 16 ParentColor = False WordWrap = True end object pnlConnect: TPanel AnchorSideLeft.Control = imgAuth AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblMessage AnchorSideTop.Side = asrBottom Left = 72 Height = 40 Top = 29 Width = 159 AutoSize = True BorderSpacing.Left = 16 BorderSpacing.Top = 20 BevelOuter = bvNone ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 40 ClientWidth = 159 Color = clForm ParentColor = False TabOrder = 1 object rbAnonymous: TRadioButton Left = 0 Height = 20 Top = 0 Width = 159 Caption = 'Connect anonymously' Checked = True OnChange = rbAnonymousChange TabOrder = 1 TabStop = True end object rbConnetAs: TRadioButton Left = 0 Height = 20 Top = 20 Width = 159 Caption = 'Connect as user:' TabOrder = 0 end end object ButtonPanel: TButtonPanel AnchorSideTop.Control = pnlUser AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlUser AnchorSideRight.Side = asrBottom Left = 188 Height = 28 Top = 167 Width = 171 Align = alNone Anchors = [akTop, akRight] BorderSpacing.Top = 16 BorderSpacing.Around = 0 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 2 Spacing = 10 ShowButtons = [pbOK, pbCancel] ShowBevel = False end end ��������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/fgioauthdlg.lrj������������������������������������������������0000644�0001750�0000144�00000001417�14743153644�021507� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":74566218,"name":"tfrmgioauthdialog.lblusername.caption","sourcebytes":[85,115,101,114,32,110,97,109,101,58],"value":"User name:"}, {"hash":191070298,"name":"tfrmgioauthdialog.lbldomain.caption","sourcebytes":[68,111,109,97,105,110,58],"value":"Domain:"}, {"hash":179191546,"name":"tfrmgioauthdialog.lblpassword.caption","sourcebytes":[80,97,115,115,119,111,114,100,58],"value":"Password:"}, {"hash":71686025,"name":"tfrmgioauthdialog.rbanonymous.caption","sourcebytes":[67,111,110,110,101,99,116,32,97,110,111,110,121,109,111,117,115,108,121],"value":"Connect anonymously"}, {"hash":29514890,"name":"tfrmgioauthdialog.rbconnetas.caption","sourcebytes":[67,111,110,110,101,99,116,32,97,115,32,117,115,101,114,58],"value":"Connect as user:"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/fgioauthdlg.pas������������������������������������������������0000644�0001750�0000144�00000004134�14743153644�021502� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fGioAuthDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, ButtonPanel, uGio2; type { TfrmGioAuthDialog } TfrmGioAuthDialog = class(TForm) ButtonPanel: TButtonPanel; edtDomain: TEdit; edtPassword: TEdit; edtUserName: TEdit; imgAuth: TImage; lblDomain: TLabel; lblMessage: TLabel; lblPassword: TLabel; lblUserName: TLabel; pnlUser: TPanel; pnlConnect: TPanel; rbAnonymous: TRadioButton; rbConnetAs: TRadioButton; procedure rbAnonymousChange(Sender: TObject); private procedure ShowThread; public { public declarations } end; function ShowAuthDlg(const Message: String; var Flags: TGAskPasswordFlags; var DefaultUser, DefaultDomain: String; out Password: String): Boolean; implementation function ShowAuthDlg(const Message: String; var Flags: TGAskPasswordFlags; var DefaultUser, DefaultDomain: String; out Password: String): Boolean; begin with TfrmGioAuthDialog.Create(Application) do try Caption:= Application.Title; lblMessage.Caption:= Message; rbAnonymous.Checked:= (Flags and G_ASK_PASSWORD_ANONYMOUS_SUPPORTED <> 0); pnlConnect.Visible:= rbAnonymous.Checked; pnlUser.Enabled:= not pnlConnect.Visible; edtUserName.Text:= DefaultUser; edtDomain.Text:= DefaultDomain; lblDomain.Visible:= (Flags and G_ASK_PASSWORD_NEED_DOMAIN <> 0); edtDomain.Visible:= lblDomain.Visible; TThread.Synchronize(nil, @ShowThread); Result:= ModalResult = mrOK; if Result then begin if not rbAnonymous.Checked then begin Password:= edtPassword.Text; DefaultUser:= edtUserName.Text; DefaultDomain:= edtDomain.Text; if pnlConnect.Visible then Flags -= G_ASK_PASSWORD_ANONYMOUS_SUPPORTED; end; end; finally Free; end; end; {$R *.lfm} { TfrmGioAuthDialog } procedure TfrmGioAuthDialog.rbAnonymousChange(Sender: TObject); begin pnlUser.Enabled:= not rbAnonymous.Checked; end; procedure TfrmGioAuthDialog.ShowThread; begin ShowModal; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/fgiocopymoveoperationoptions.lfm�������������������������������0000644�0001750�0000144�00000005070�14743153644�025243� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object GioCopyMoveOperationOptionsUI: TGioCopyMoveOperationOptionsUI Left = 453 Height = 158 Top = 166 Width = 549 AutoSize = True ClientHeight = 158 ClientWidth = 549 LCLVersion = '1.4.0.4' object pnlComboBoxes: TPanel AnchorSideLeft.Control = Owner Left = 0 Height = 57 Top = 0 Width = 240 AutoSize = True BevelOuter = bvNone ChildSizing.TopBottomSpacing = 5 ChildSizing.HorizontalSpacing = 5 ChildSizing.VerticalSpacing = 10 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 57 ClientWidth = 240 TabOrder = 0 object lblFileExists: TLabel Left = 0 Height = 14 Top = 8 Width = 135 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When file exists' FocusControl = cmbFileExists ParentColor = False end object cmbFileExists: TComboBoxAutoWidth Left = 140 Height = 20 Top = 5 Width = 100 ItemHeight = 14 Items.Strings = ( 'Ask' 'Overwrite' 'Skip' ) Style = csDropDownList TabOrder = 0 end object lblDirectoryExists: TLabel Left = 0 Height = 14 Top = 35 Width = 135 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When dir&ectory exists' FocusControl = cmbDirectoryExists ParentColor = False end object cmbDirectoryExists: TComboBoxAutoWidth AnchorSideLeft.Control = lblDirectoryExists AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblDirectoryExists AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 140 Height = 20 Top = 32 Width = 100 ItemHeight = 14 Style = csDropDownList TabOrder = 1 end end object pnlCheckboxes: TPanel AnchorSideLeft.Control = pnlComboBoxes AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlComboBoxes Left = 248 Height = 29 Top = 0 Width = 95 AutoSize = True BorderSpacing.Left = 8 BevelOuter = bvNone BevelWidth = 8 ChildSizing.TopBottomSpacing = 5 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 29 ClientWidth = 95 TabOrder = 1 object cbFollowLinks: TCheckBox AnchorSideLeft.Control = pnlCheckboxes AnchorSideTop.Control = pnlCheckboxes Left = 0 Height = 19 Top = 5 Width = 95 AllowGrayed = True Caption = 'Fo&llow links' TabOrder = 0 end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/fgiocopymoveoperationoptions.lrj�������������������������������0000644�0001750�0000144�00000001137�14743153644�025254� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":111687171,"name":"tgiocopymoveoperationoptionsui.lblfileexists.caption","sourcebytes":[87,104,101,110,32,102,105,108,101,32,101,120,105,115,116,115],"value":"When file exists"}, {"hash":219592963,"name":"tgiocopymoveoperationoptionsui.lbldirectoryexists.caption","sourcebytes":[87,104,101,110,32,100,105,114,38,101,99,116,111,114,121,32,101,120,105,115,116,115],"value":"When dir&ectory exists"}, {"hash":76535811,"name":"tgiocopymoveoperationoptionsui.cbfollowlinks.caption","sourcebytes":[70,111,38,108,108,111,119,32,108,105,110,107,115],"value":"Fo&llow links"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/fgiocopymoveoperationoptions.pas�������������������������������0000644�0001750�0000144�00000010075�14743153644�025251� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fGioCopyMoveOperationOptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ExtCtrls, uFileSourceOperationOptionsUI, KASComboBox, uGioCopyOperation, uGioMoveOperation; type { TGioCopyMoveOperationOptionsUI } TGioCopyMoveOperationOptionsUI = class(TFileSourceOperationOptionsUI) cbFollowLinks: TCheckBox; cmbDirectoryExists: TComboBoxAutoWidth; cmbFileExists: TComboBoxAutoWidth; grpOptions: TGroupBox; lblDirectoryExists: TLabel; lblFileExists: TLabel; pnlCheckboxes: TPanel; pnlComboBoxes: TPanel; private procedure SetOperationOptions(CopyOperation: TGioCopyOperation); overload; procedure SetOperationOptions(MoveOperation: TGioMoveOperation); overload; public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; procedure SaveOptions; override; procedure SetOperationOptions(Operation: TObject); override; end; TGioCopyOperationOptionsUI = class(TGioCopyMoveOperationOptionsUI) end; { TGioMoveOperationOptionsUI } TGioMoveOperationOptionsUI = class(TGioCopyMoveOperationOptionsUI) public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; end; implementation {$R *.lfm} uses DCStrUtils, uLng, uGlobs, uFileSourceOperationOptions; { TGioCopyMoveOperationOptionsUI } constructor TGioCopyMoveOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited Create(AOwner, AFileSource); ParseLineToList(rsFileOpFileExistsOptions, cmbFileExists.Items); ParseLineToList(rsFileOpDirectoryExistsOptions, cmbDirectoryExists.Items); // Load default options. case gOperationOptionFileExists of fsoofeNone : cmbFileExists.ItemIndex := 0; fsoofeOverwrite: cmbFileExists.ItemIndex := 1; fsoofeSkip : cmbFileExists.ItemIndex := 2; end; case gOperationOptionDirectoryExists of fsoodeNone : cmbDirectoryExists.ItemIndex := 0; fsoodeCopyInto : cmbDirectoryExists.ItemIndex := 1; fsoodeSkip : cmbDirectoryExists.ItemIndex := 2; end; case gOperationOptionSymLinks of fsooslFollow : cbFollowLinks.State := cbChecked; fsooslDontFollow : cbFollowLinks.State := cbUnchecked; fsooslNone : cbFollowLinks.State := cbGrayed; end; end; procedure TGioCopyMoveOperationOptionsUI.SaveOptions; begin // TODO: Saving options for each file source operation separately. end; procedure TGioCopyMoveOperationOptionsUI.SetOperationOptions(Operation: TObject); begin if Operation is TGioCopyOperation then SetOperationOptions(Operation as TGioCopyOperation) else if Operation is TGioMoveOperation then SetOperationOptions(Operation as TGioMoveOperation); end; procedure TGioCopyMoveOperationOptionsUI.SetOperationOptions( CopyOperation: TGioCopyOperation); begin with CopyOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; case cmbDirectoryExists.ItemIndex of 0: DirExistsOption := fsoodeNone; 1: DirExistsOption := fsoodeCopyInto; 2: DirExistsOption := fsoodeSkip; end; case cbFollowLinks.State of cbChecked : SymLinkOption := fsooslFollow; cbUnchecked: SymLinkOption := fsooslDontFollow; cbGrayed : SymLinkOption := fsooslNone; end; end; end; procedure TGioCopyMoveOperationOptionsUI.SetOperationOptions( MoveOperation: TGioMoveOperation); begin with MoveOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; case cmbDirectoryExists.ItemIndex of 0: DirExistsOption := fsoodeNone; 1: DirExistsOption := fsoodeCopyInto; 2: DirExistsOption := fsoodeSkip; end; end; end; { TGioMoveOperationOptionsUI } constructor TGioMoveOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited Create(AOwner, AFileSource); cbFollowLinks.Visible:= False; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/network/�������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020167� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/network/unetworkfilesource.pas���������������������������������0000644�0001750�0000144�00000003116�14743153644�024634� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uNetworkFileSource; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, uFile, uFileSourceOperationTypes, uGioFileSource, uGio2; type INetworkFileSource = interface(IGioFileSource) ['{C7128E35-76FC-4635-842D-4091AB4AC520}'] end; { TNetworkFileSource } TNetworkFileSource = class(TGioFileSource, INetworkFileSource) public constructor Create; override; function GetOperationsTypes: TFileSourceOperationTypes; override; class function GetMainIcon(out Path: String): Boolean; override; class function IsSupportedPath(const Path: String): Boolean; override; class function CreateFile(const APath: String; AFolder: PGFile; AFileInfo: PGFileInfo): TFile; override; end; implementation uses DCStrUtils; { TNetworkFileSource } constructor TNetworkFileSource.Create; begin inherited Create; FCurrentAddress:= 'network://'; end; function TNetworkFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result:= [fsoList, fsoExecute]; end; class function TNetworkFileSource.GetMainIcon(out Path: String): Boolean; begin Result:= True; Path:= 'network-workgroup'; end; class function TNetworkFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= StrBegins(Path, 'network://'); end; class function TNetworkFileSource.CreateFile(const APath: String; AFolder: PGFile; AFileInfo: PGFileInfo): TFile; var ADisplayName: String; begin Result:= inherited CreateFile(APath, AFolder, AFileInfo); ADisplayName:= g_file_info_get_display_name(AFileInfo); if Length(ADisplayName) > 0 then Result.Name:= ADisplayName; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/trash/���������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017617� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/trash/utrashdeleteoperation.pas��������������������������������0000644�0001750�0000144�00000001763�14743153644�024745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uTrashDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uGioDeleteOperation, uFileSource, uFile; type { TTrashDeleteOperation } TTrashDeleteOperation = class(TGioDeleteOperation) public procedure Initialize; override; procedure Finalize; override; end; implementation procedure TTrashDeleteOperation.Initialize; var I: Integer; aFile: TFile; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FFullFilesTreeToDelete:= FilesToDelete; for I := 0 to FFullFilesTreeToDelete.Count - 1 do begin aFile := FFullFilesTreeToDelete[I]; with FStatistics do begin if aFile.IsDirectory and (not aFile.IsLinkToDirectory) then Inc(TotalFiles) else begin Inc(TotalFiles); Inc(TotalBytes, aFile.Size); end; end; end; end; procedure TTrashDeleteOperation.Finalize; begin FFullFilesTreeToDelete:= nil; inherited Finalize; end; end. �������������doublecmd-1.1.22/src/filesources/gio/trash/utrashfilesource.pas�������������������������������������0000644�0001750�0000144�00000014744�14743153644�023725� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uTrashFileSource; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Menus, uGLib2, uGio2, uFile, uFileSource, uGioFileSource, uFileSourceProperty, uFileProperty, uFileSourceOperationTypes, uFileSourceOperation; type ITrashFileSource = interface(IGioFileSource) ['{5EABE432-2310-460B-8A59-32C2D2C28207}'] end; { TTrashFileSource } TTrashFileSource = class(TGioFileSource, ITrashFileSource) private FFiles: TFiles; FMenu: TPopupMenu; procedure RestoreItem(Sender: TObject); public constructor Create; override; destructor Destroy; override; function GetFileSystem: String; override; function GetProperties: TFileSourceProperties; override; class function GetMainIcon(out Path: String): Boolean; override; function GetOperationsTypes: TFileSourceOperationTypes; override; class function IsSupportedPath(const Path: String): Boolean; override; function GetRetrievableFileProperties: TFilePropertiesTypes; override; function GetDefaultView(out DefaultView: TFileSourceFields): Boolean; override; function QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; override; procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; end; implementation uses System.UITypes, Dialogs, DCStrUtils, uGObject2, uLng, uGio, uFileProcs, uGioFileSourceUtil, uTrashDeleteOperation; const G_FILE_ATTRIBUTE_TRASH_ORIG_PATH = 'trash::orig-path'; { TTrashFileSource } procedure TTrashFileSource.RestoreItem(Sender: TObject); var AFile: TFile; APath: String; AIndex: Integer; AInfo: PGFileInfo; AError: PGError = nil; SourceFile, TargetFile: PGFile; begin for AIndex:= 0 to FFiles.Count - 1 do begin AFile:= FFiles[AIndex]; SourceFile:= GioNewFile(AFile.FullPath); try AInfo:= g_file_query_info(SourceFile, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, nil); if Assigned(AInfo) then try APath:= g_file_info_get_attribute_byte_string(AInfo, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH); mbForceDirectory(ExtractFileDir(APath)); TargetFile:= GioNewFile(APAth); try if not g_file_move(SourceFile, TargetFile, G_FILE_COPY_NOFOLLOW_SYMLINKS or G_FILE_COPY_ALL_METADATA or G_FILE_COPY_NO_FALLBACK_FOR_MOVE, nil, nil, nil, @AError) then begin if Assigned(AError) then try if MessageDlg(AError^.message, mtError, [mbAbort, mbIgnore], 0, mbAbort) = mrAbort then Break; finally FreeAndNil(AError); end; end; finally g_object_unref(PGObject(TargetFile)); end; finally g_object_unref(AInfo); end; finally g_object_unref(PGObject(SourceFile)); end; end; Reload(PathDelim); end; constructor TTrashFileSource.Create; begin inherited Create; FCurrentAddress:= 'trash://'; FMenu:= TPopupMenu.Create(nil); FFiles:= TFiles.Create(EmptyStr); end; destructor TTrashFileSource.Destroy; begin inherited Destroy; FFiles.Free; FMenu.Free; end; function TTrashFileSource.GetFileSystem: String; begin Result:= 'Trash'; end; function TTrashFileSource.GetProperties: TFileSourceProperties; begin Result:= (inherited GetProperties) + [fspContextMenu, fspDefaultView]; end; class function TTrashFileSource.GetMainIcon(out Path: String): Boolean; begin Result:= True; Path:= 'user-trash'; end; function TTrashFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result:= [fsoList, fsoCopyOut, fsoDelete, fsoCalcStatistics]; end; class function TTrashFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= StrBegins(Path, 'trash://'); end; function TTrashFileSource.GetDefaultView(out DefaultView: TFileSourceFields): Boolean; begin Result:= True; SetLength(DefaultView, 3); DefaultView[0].Header:= rsColName; DefaultView[0].Content:= '[DC().GETFILENAMENOEXT{}]'; DefaultView[0].Width:= 30; DefaultView[1].Header:= rsColExt; DefaultView[1].Content:= '[DC().GETFILEEXT{}]'; DefaultView[1].Width:= 15; DefaultView[2].Header:= rsFuncTrashOrigPath; DefaultView[2].Content:= '[Plugin(FS).' + G_FILE_ATTRIBUTE_TRASH_ORIG_PATH + '{}]'; DefaultView[2].Width:= 55; end; function TTrashFileSource.QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; var Index: Integer; MenuItem: TMenuItem; begin if AFiles.Count = 0 then Exit(False); if AFiles[0].Path = 'trash:///' then begin FMenu.Assign(AMenu); MenuItem:= TMenuItem.Create(FMenu); MenuItem.Caption:= '-'; Index:= FMenu.Items.Count - 2; FMenu.Items.Insert(Index, MenuItem); MenuItem:= TMenuItem.Create(FMenu); MenuItem.Caption:= rsMnuRestore; MenuItem.OnClick:= @RestoreItem; Index:= FMenu.Items.Count - 2; FMenu.Items.Insert(Index, MenuItem); FFiles.Clear; AFiles.CloneTo(FFiles); AMenu:= FMenu; end; Result:= True; end; function TTrashFileSource.GetRetrievableFileProperties: TFilePropertiesTypes; begin Result:= inherited GetRetrievableFileProperties + fpVariantAll; end; procedure TTrashFileSource.RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); var AGFile: PGFile; AIndex: Integer; AInfo: PGFileInfo; AProp: TFilePropertyType; AVariant: TFileVariantProperty; begin PropertiesToSet:= PropertiesToSet * fpVariantAll; for AProp in PropertiesToSet do begin AIndex:= Ord(AProp) - Ord(fpVariant); if (AIndex >= 0) and (AIndex <= High(AVariantProperties)) then begin AVariant:= TFileVariantProperty.Create(AVariantProperties[AIndex]); AGFile:= GioNewFile(AFile.FullPath); AInfo:= g_file_query_info(AGFile, 'trash::*', G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, nil); if Assigned(AInfo) then begin AVariant.Value:= g_file_info_get_attribute_byte_string(AInfo, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH); AFile.Properties[AProp]:= AVariant; g_object_unref(AInfo); end; g_object_unref(PGObject(AGFile)); end; end; end; function TTrashFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; FilesToDelete.Path:= FCurrentAddress + FilesToDelete.Path; Result := TTrashDeleteOperation.Create(TargetFileSource, FilesToDelete); end; end. ����������������������������doublecmd-1.1.22/src/filesources/gio/ugiocalcstatisticsoperation.pas��������������������������������0000644�0001750�0000144�00000010126�14743153644�025025� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCalcStatisticsOperation, uFileSource, uGioFileSource, uFile, uGlobs, uLog; type TGioCalcStatisticsOperation = class(TFileSourceCalcStatisticsOperation) private FStatistics: TFileSourceCalcStatisticsOperationStatistics; procedure ProcessFile(aFile: TFile); procedure ProcessSubDirs(const srcPath: String); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses uGLib2, uGObject2, uGio2, uGioFileSourceUtil, uGio; constructor TGioCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin inherited Create(aTargetFileSource, theFiles); end; destructor TGioCalcStatisticsOperation.Destroy; begin inherited Destroy; end; procedure TGioCalcStatisticsOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; end; procedure TGioCalcStatisticsOperation.MainExecute; var CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to Files.Count - 1 do begin ProcessFile(Files[CurrentFileIndex]); CheckOperationState; end; end; procedure TGioCalcStatisticsOperation.ProcessFile(aFile: TFile); begin FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); if aFile.IsLink then begin Inc(FStatistics.Links); end else if aFile.IsDirectory then begin Inc(FStatistics.Directories); ProcessSubDirs(aFile.Path + aFile.Name + DirectorySeparator); end else begin // Not always this will be regular file (on Unix can be socket, FIFO, block, char, etc.) // Maybe check with: FPS_ISREG() on Unix? Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + aFile.Size; if aFile.ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := aFile.ModificationTime; if aFile.ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := aFile.ModificationTime; end; UpdateStatistics(FStatistics); end; procedure TGioCalcStatisticsOperation.ProcessSubDirs(const srcPath: String); var AFile: TFile; AFolder: PGFile; AInfo: PGFileInfo; AFileName: Pgchar; AError: PGError = nil; AFileEnum: PGFileEnumerator; begin AFolder:= GioNewFile(srcPath); try AFileEnum:= g_file_enumerate_children (AFolder, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, @AError); if Assigned(AFileEnum) then try AInfo:= g_file_enumerator_next_file (AFileEnum, nil, @AError); while Assigned(AInfo) do begin AFileName:= g_file_info_get_name(AInfo); if (aFileName <> '.') and (aFileName <> '..') then begin aFile:= TGioFileSource.CreateFile(srcPath, AFolder, AInfo); try ProcessFile(aFile); finally FreeAndNil(aFile); end; end; g_object_unref(AInfo); CheckOperationState; AInfo:= g_file_enumerator_next_file (AFileEnum, nil, @AError); end; finally if Assigned(AError) then begin LogMessage(AError^.message, [log_errors], lmtError); g_error_free(AError); end; g_object_unref(AFileEnum); end; finally g_object_unref(PGObject(AFolder)); end; end; procedure TGioCalcStatisticsOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiocopyoperation.pas������������������������������������������0000644�0001750�0000144�00000007521�14743153644�022767� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioCopyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceCopyOperation, uFileSource, uFileSourceOperationTypes, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uGioFileSourceUtil; type { TGioCopyOperation } TGioCopyOperation = class(TFileSourceCopyOperation) private FOperationHelper: TGioOperationHelper; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; end; { Both operations are the same, just source and target reversed. Implement them in terms of the same functions, or have one use the other. } { TGioCopyInOperation } TGioCopyInOperation = class(TGioCopyOperation) protected function GetID: TFileSourceOperationType; override; end; { TGioCopyOutOperation } TGioCopyOutOperation = class(TGioCopyOperation) protected function GetID: TFileSourceOperationType; override; end; implementation uses fGioCopyMoveOperationOptions, uGio2; constructor TGioCopyOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); end; destructor TGioCopyOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); end; procedure TGioCopyOperation.Initialize; var TreeBuilder: TGioTreeBuilder; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TGioTreeBuilder.Create(@AskQuestion, @CheckOperationState); try TreeBuilder.SymLinkOption := Self.SymLinkOption; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; FOperationHelper := TGioOperationHelper.Create( FileSource as IFileSource, Self, FStatistics, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, g_file_copy, TargetPath); FOperationHelper.RenameMask := RenameMask; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.DirExistsOption := DirExistsOption; FOperationHelper.Initialize; end; procedure TGioCopyOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree); end; procedure TGioCopyOperation.Finalize; begin FileExistsOption := FOperationHelper.FileExistsOption; FOperationHelper.Free; end; class function TGioCopyOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TGioCopyOperationOptionsUI; end; { TGioCopyInOperation } function TGioCopyInOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopyIn; end; { TGioCopyOutOperation } function TGioCopyOutOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopyOut; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiocreatedirectoryoperation.pas�������������������������������0000644�0001750�0000144�00000002661�14743153644�025205� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioCreateDirectoryOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCreateDirectoryOperation, uFileSource; type TGioCreateDirectoryOperation = class(TFileSourceCreateDirectoryOperation) public procedure MainExecute; override; end; implementation uses uFileSourceOperationUI, uLog, uLng, uGlobs, uGio2, uGio, uGLib2, uGObject2; procedure TGioCreateDirectoryOperation.MainExecute; var AGFile: PGFile; AResult: Boolean; AError: PGError = nil; begin AGFile:= GioNewFile(AbsolutePath); AResult:= g_file_make_directory_with_parents(AGFile, nil, @AError); g_object_unref(PGObject(AGFile)); if Assigned(AError) then begin AResult:= g_error_matches (AError, g_io_error_quark(), G_IO_ERROR_EXISTS); if not AResult then begin if g_error_matches (AError, g_io_error_quark(), G_IO_ERROR_NOT_SUPPORTED) then AskQuestion(rsMsgErrNotSupported, '', [fsourOk], fsourOk, fsourOk) else begin // write log error if (log_vfs_op in gLogOptions) and (log_errors in gLogOptions) then logWrite(Thread, Format(rsMsgLogError+rsMsgLogMkDir, [AbsolutePath]), lmtError); end; end; g_error_free(AError); end; if AResult then begin // write log success if (log_vfs_op in gLogOptions) and (log_success in gLogOptions) then logWrite(Thread, Format(rsMsgLogSuccess+rsMsgLogMkDir, [AbsolutePath]), lmtSuccess) end end; end. �������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiodeleteoperation.pas����������������������������������������0000644�0001750�0000144�00000013336�14743153644�023260� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceDeleteOperation, uGioFileSource, uFileSource, uFileSourceOperationOptions, uFileSourceOperationUI, uFile, uGlobs, uLog; type TGioDeleteOperation = class(TFileSourceDeleteOperation) protected FWfxPluginFileSource: IGioFileSource; FFullFilesTreeToDelete: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceDeleteOperationStatistics; // local copy of statistics // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; FSkipErrors: Boolean; FDeleteReadOnly: TFileSourceOperationOptionGeneral; protected function ProcessFile(aFile: TFile): Boolean; function ShowError(sMessage: String): TFileSourceOperationUIResponse; procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses DCOSUtils, uLng, uGio2, uGObject2, uGio, uGioFileSourceUtil; constructor TGioDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FSymLinkOption := fsooslNone; FSkipErrors := False; FDeleteReadOnly := fsoogNone; FFullFilesTreeToDelete := nil; FWfxPluginFileSource:= aTargetFileSource as IGioFileSource; inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TGioDeleteOperation.Destroy; begin inherited Destroy; FFullFilesTreeToDelete.Free; end; procedure TGioDeleteOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FillAndCount(FilesToDelete, True, FFullFilesTreeToDelete, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; procedure TGioDeleteOperation.MainExecute; var aFile: TFile; CurrentFileIndex: Integer; begin for CurrentFileIndex := FFullFilesTreeToDelete.Count - 1 downto 0 do begin aFile := FFullFilesTreeToDelete[CurrentFileIndex]; FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); ProcessFile(aFile); with FStatistics do begin DoneFiles := DoneFiles + 1; DoneBytes := DoneBytes + aFile.Size; UpdateStatistics(FStatistics); end; CheckOperationState; end; end; function TGioDeleteOperation.ProcessFile(aFile: TFile): Boolean; var AGFile: PGFile; FileName: String; bRetry: Boolean; sMessage, sQuestion: String; logOptions: TLogOptions; begin Result := False; FileName := aFile.Path + aFile.Name; if FileIsReadOnly(aFile.Attributes) then begin case FDeleteReadOnly of fsoogNone: case AskQuestion(Format(rsMsgFileReadOnly, [FileName]), '', [fsourYes, fsourAll, fsourSkip, fsourSkipAll], fsourYes, fsourSkip) of fsourAll: FDeleteReadOnly := fsoogYes; fsourSkip: Exit; fsourSkipAll: begin FDeleteReadOnly := fsoogNo; Exit; end; end; fsoogNo: Exit; end; end; repeat bRetry := False; //if FileIsReadOnly(aFile.Attributes) then // mbFileSetReadOnly(FileName, False); AGFile:= GioNewFile(FileName); Result:= g_file_delete(AGFile, nil, nil); g_object_unref(PGObject(AGFile)); if Result then begin // success if aFile.IsDirectory then begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogRmDir, [FileName]), [log_vfs_op], lmtSuccess); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogDelete, [FileName]), [log_vfs_op], lmtSuccess); end; end else // error begin if aFile.IsDirectory then begin logOptions := [log_vfs_op]; sMessage := Format(rsMsgLogError + rsMsgLogRmDir, [FileName]); sQuestion := Format(rsMsgNotDelete, [FileName]); end else begin logOptions := [log_vfs_op]; sMessage := Format(rsMsgLogError + rsMsgLogDelete, [FileName]); sQuestion := Format(rsMsgNotDelete, [FileName]); end; if gSkipFileOpError or (FSkipErrors = True) then LogMessage(sMessage, logOptions, lmtError) else begin case AskQuestion(sQuestion, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetry := True; fsourSkipAll: FSkipErrors := True; fsourAbort: RaiseAbortOperation; end; end; end; until bRetry = False; end; function TGioDeleteOperation.ShowError(sMessage: String): TFileSourceOperationUIResponse; begin if gSkipFileOpError then begin logWrite(Thread, sMessage, lmtError, True); Result := fsourSkip; end else begin Result := AskQuestion(sMessage, '', [fsourSkip, fsourCancel], fsourSkip, fsourCancel); if Result = fsourCancel then RaiseAbortOperation; end; end; procedure TGioDeleteOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugioexecuteoperation.pas���������������������������������������0000644�0001750�0000144�00000002220�14743153644�023446� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource, uFileSourceExecuteOperation; type { TGioExecuteOperation } TGioExecuteOperation = class(TFileSourceExecuteOperation) public procedure MainExecute; override; end; implementation uses DCFileAttributes, uGio, uGio2, uGObject2, uGLib2, fFileProperties, uFile; procedure TGioExecuteOperation.MainExecute; var AFile: PGFile; AFiles: TFiles; AInfo: PGFileInfo; AFileType: TGFileType; begin if Verb = 'properties' then begin AFiles:= TFiles.Create(CurrentPath); try AFiles.Add(ExecutableFile.Clone); ShowFileProperties(FileSource as IFileSource, AFiles); finally AFiles.Free; end; Exit; end; if (ExecutableFile.Attributes and S_IFMT) = (S_IFDIR or S_IFLNK) then begin ResultString:= ExecutableFile.LinkProperty.LinkTo; if Length(ResultString) > 0 then begin FExecuteOperationResult:= fseorSymLink; Exit(); end; end; if GioOpen(AbsolutePath) then FExecuteOperationResult:= fseorSuccess else begin FExecuteOperationResult:= fseorError; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiofilesource.pas���������������������������������������������0000644�0001750�0000144�00000045737�14743153644�022247� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Dialogs, URIParser, SyncObjs, uFileSourceProperty, uFileSourceOperationTypes, uRealFileSource, uFileProperty, uFileSource, DCStrUtils, uFileSourceOperation, uFile, uGLib2, uGObject2, uGio2; type IGioFileSource = interface(IRealFileSource) ['{6DC5BCCA-BDD5-43DA-A0D6-7BAA26D93B92}'] function MountPath(AFile: PGFile; out AError: PGError): Boolean; end; { TGioFileSource } TGioFileSource = class(TRealFileSource, IGioFileSource) private MountTry: Integer; MountLoop: TSimpleEvent; MountError: PGError; protected function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; public function MountPath(AFile: PGFile; out AError: PGError): Boolean; public constructor Create(const URI: TURI); override; class function IsSupportedPath(const Path: String): Boolean; override; function GetPathType(sPath : String): TPathType; override; function CreateDirectory(const Path: String): Boolean; override; function FileSystemEntryExists(const Path: String): Boolean; override; function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; override; class function CreateFile(const APath: String): TFile; override; class function CreateFile(const APath: String; AFolder: PGFile; AFileInfo: PGFileInfo): TFile; virtual; procedure Reload(const PathsToReload: TPathsArray); override; function GetParentDir(sPath : String): String; override; function IsPathAtRoot(Path: String): Boolean; override; function GetRootDir(sPath: String): String; override; overload; function GetRootDir: String; override; overload; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; override; function GetOperationsTypes: TFileSourceOperationTypes; override; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override; end; implementation uses DCFileAttributes, DCDateTimeUtils, uGioListOperation, uGioCopyOperation, uGioDeleteOperation, uGioExecuteOperation, uGioCreateDirectoryOperation, uGioMoveOperation, uGioSetFilePropertyOperation, uDebug, fGioAuthDlg, DCBasicTypes, uShowMsg, uGioCalcStatisticsOperation, uGio; { TGioFileSource } function TGioFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result:= [fsoList, fsoCopy, fsoCopyIn, fsoCopyOut, fsoDelete, fsoExecute, fsoCreateDirectory, fsoMove, fsoCalcStatistics, fsoSetFileProperty]; end; class function TGioFileSource.CreateFile(const APath: String): TFile; begin Result:=inherited CreateFile(APath); with Result do begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes; SizeProperty := TFileSizeProperty.Create; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; CreationTimeProperty := TFileCreationDateTimeProperty.Create; LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create; LinkProperty := TFileLinkProperty.Create; OwnerProperty := TFileOwnerProperty.Create; TypeProperty := TFileTypeProperty.Create; CommentProperty := TFileCommentProperty.Create; end; end; class function TGioFileSource.CreateFile(const APath: String; AFolder: PGFile; AFileInfo: PGFileInfo): TFile; var Addr: TURI; AFile: PGFile; ATarget: Pgchar; AFileType: TGFileType; ASymlinkInfo: PGFileInfo; begin Result:= CreateFile(APath); Result.Name:= g_file_info_get_name(AFileInfo); Result.Attributes:= g_file_info_get_attribute_uint32(AFileInfo, FILE_ATTRIBUTE_UNIX_MODE); Result.ModificationTime:= UnixFileTimeToDateTime(g_file_info_get_attribute_uint64 (AFileInfo, FILE_ATTRIBUTE_TIME_MODIFIED)); if g_file_info_has_attribute(AFileInfo, FILE_ATTRIBUTE_STANDARD_SIZE) then Result.Size:= g_file_info_get_size(AFileInfo) else begin Result.SizeProperty.IsValid:= False; end; // Get a file's type (whether it is a regular file, symlink, etc). AFileType:= g_file_info_get_file_type (AFileInfo); if AFileType = G_FILE_TYPE_DIRECTORY then begin Result.Size:= 0; Result.Attributes:= Result.Attributes or S_IFDIR; end else if AFileType = G_FILE_TYPE_SYMBOLIC_LINK then begin ATarget:= g_file_info_get_symlink_target(AFileInfo); Result.LinkProperty.IsValid := Assigned(ATarget); if Assigned(ATarget) then begin AFile:= g_file_get_child(AFolder, ATarget); ASymlinkInfo := g_file_query_info (AFile, FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, nil, nil); Result.LinkProperty.LinkTo := ATarget; Result.LinkProperty.IsValid := Assigned(ASymlinkInfo); if (Result.LinkProperty.IsValid) then begin AFileType:= g_file_info_get_file_type(ASymlinkInfo); Result.LinkProperty.IsLinkToDirectory := (AFileType = G_FILE_TYPE_DIRECTORY); if Result.LinkProperty.IsLinkToDirectory then Result.Size := 0; g_object_unref(ASymlinkInfo); end; g_object_unref(PGObject(AFile)); end; end else if AFileType in [G_FILE_TYPE_SHORTCUT, G_FILE_TYPE_MOUNTABLE] then begin Result.Attributes:= Result.Attributes or S_IFLNK or S_IFDIR; Result.ModificationTimeProperty.IsValid:= g_file_info_has_attribute(AFileInfo, FILE_ATTRIBUTE_TIME_MODIFIED); ATarget:= g_file_info_get_attribute_string(AFileInfo, FILE_ATTRIBUTE_STANDARD_TARGET_URI); Result.LinkProperty.IsValid := Length(ATarget) > 0; Result.LinkProperty.LinkTo := ATarget; // Remove a standard port from address Addr:= ParseURI(Result.LinkProperty.LinkTo); if Addr.Port > 0 then begin case Addr.Port of 22: if (Addr.Protocol = 'sftp') then Addr.Port:= 0; 445: if (Addr.Protocol = 'smb') then Addr.Port:= 0; 2049: if (Addr.Protocol = 'nfs') then Addr.Port:= 0; end; if Addr.Port = 0 then Result.LinkProperty.LinkTo:= EncodeURI(Addr); end; end; end; procedure TGioFileSource.Reload(const PathsToReload: TPathsArray); var Index: Integer; PathList: TPathsArray; begin SetLength(PathList, Length(PathsToReload)); for Index:= Low(PathsToReload) to High(PathsToReload) do begin PathList[Index]:= StringReplace(PathsToReload[Index], FCurrentAddress, '', []); end; inherited Reload(PathList); end; function TGioFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin Result:= True; end; procedure ask_password_cb (op: PGMountOperation; const message: Pgchar; const default_user: Pgchar; const default_domain: Pgchar; flags: TGAskPasswordFlags; user_data: gpointer); cdecl; var UserName, Password, Domain: String; password_save: TGPasswordSave; mount_handled: gboolean = FALSE; FileSource: TGioFileSource absolute user_data; begin Inc(FileSource.MountTry); //* First pass, look if we have a password to supply */ if (FileSource.MountTry = 1) then begin if ((flags and G_ASK_PASSWORD_NEED_USERNAME <> 0) and (Length(FileSource.FURI.Username) > 0)) then begin g_printf ('(WW) ask_password_cb: mount_try = %d, trying login with saved username...\n', [FileSource.MountTry]); g_mount_operation_set_username (op, Pgchar(FileSource.FURI.Username)); mount_handled := TRUE; end; if ((flags and G_ASK_PASSWORD_NEED_PASSWORD <> 0) and (Length(FileSource.FURI.Password) > 0)) then begin g_printf ('(WW) ask_password_cb: mount_try = %d, trying login with saved password...\n', [FileSource.MountTry]); g_mount_operation_set_password (op, Pgchar(FileSource.FURI.Password)); mount_handled := TRUE; end; if (mount_handled) then begin g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); Exit; end; end; //* Handle abort message from certain backends properly */ //* - e.g. SMB backends use this to mask multiple auth callbacks from smbclient */ if ((default_user <> nil) and (strcomp(default_user, 'ABORT') = 0)) then begin g_print ('(WW) default_user == "ABORT", aborting\n', []); g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); Exit; end; password_save := G_PASSWORD_SAVE_NEVER; Username:= default_user; Domain:= default_domain; if not ShowAuthDlg(message, flags, UserName, Domain, Password) then g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED) else begin if (flags and G_ASK_PASSWORD_NEED_USERNAME <> 0) then g_mount_operation_set_username (op, Pgchar(Username)); if (flags and G_ASK_PASSWORD_NEED_DOMAIN <> 0) then g_mount_operation_set_domain (op, Pgchar(Domain)); if (flags and G_ASK_PASSWORD_NEED_PASSWORD <> 0) then g_mount_operation_set_password (op, Pgchar(password)); if (flags and G_ASK_PASSWORD_ANONYMOUS_SUPPORTED <> 0) then g_mount_operation_set_anonymous (op, True); end; if (flags and G_ASK_PASSWORD_SAVING_SUPPORTED <> 0) then g_mount_operation_set_password_save (op, password_save); g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); end; procedure ask_question_cb(op: PGMountOperation; const message: Pgchar; const choices: PPgchar; user_data: gpointer); cdecl; var len: Integer = 0; choice: Integer = -1; buttons: TDynamicStringArray; begin g_print('(WW) ask_question_cb: message = "%s"\n', [message]); while (choices[len] <> nil) do begin AddString(buttons, StrPas(choices[len])); g_print('(WW) ask_question_cb: choice[%d] = "%s"\n', [len, choices[len]]); Inc(len); end; DCDebug(' (II) Spawning callback_ask_question...'); // At this moment, only SFTP uses ask_question and the second button is cancellation choice:= MsgChoiceBox(nil, message, buttons, -1, -1); g_print(' (II) Received choice = %d\n', [choice]); if (choice < 0) then g_mount_operation_reply(op, G_MOUNT_OPERATION_ABORTED) else begin g_mount_operation_set_choice(op, choice); g_mount_operation_reply(op, G_MOUNT_OPERATION_HANDLED); end; end; procedure mount_done_cb (object_: PGObject; res: PGAsyncResult; user_data: gpointer); cdecl; var Result: gboolean; FileSource: TGioFileSource absolute user_data; begin Result := g_file_mount_enclosing_volume_finish (PGFile(object_), res, @FileSource.MountError); if Result then begin DCDebug('(II) Mount successful.'); FileSource.MountError:= nil; end else begin g_print ('(EE) Error mounting location: %s\n', [FileSource.MountError^.message]); end; FileSource.MountLoop.SetEvent; end; function TGioFileSource.MountPath(AFile: PGFile; out AError: PGError): Boolean; var Operation: PGMountOperation; begin Operation:= g_mount_operation_new(); g_signal_connect_data(Operation, 'ask-password', TGCallback(@ask_password_cb), Self, nil, 0); g_signal_connect_data(Operation, 'ask-question', TGCallback(@ask_question_cb), Self, nil, 0); MountTry:= 0; MountError:= nil; MountLoop:= TSimpleEvent.Create; g_file_mount_enclosing_volume (AFile, G_MOUNT_MOUNT_NONE, Operation, nil, @mount_done_cb, Self); repeat if g_main_context_pending(g_main_context_default) then g_main_context_iteration(g_main_context_default, False); until MountLoop.WaitFor(1) <> wrTimeout; MountLoop.Free; g_object_unref (Operation); Result:= MountError = nil; AError:= MountError; end; constructor TGioFileSource.Create(const URI: TURI); begin inherited Create(URI); FOperationsClasses[fsoMove] := TGioMoveOperation.GetOperationClass; FOperationsClasses[fsoCopy] := TGioCopyOperation.GetOperationClass; FOperationsClasses[fsoCopyIn] := TGioCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TGioCopyOutOperation.GetOperationClass; end; class function TGioFileSource.IsSupportedPath(const Path: String): Boolean; var GVfs: PGVfs; Schemes: PPgchar; begin GVfs := g_vfs_get_default (); Schemes := g_vfs_get_supported_uri_schemes (GVfs); while Schemes^ <> nil do begin Result := (Pos(Schemes^ + '://', Path) = 1); if Result then Exit; Inc(Schemes); end; end; function TGioFileSource.GetPathType(sPath: String): TPathType; begin if (Pos('://', sPath) > 0) then Result:= ptAbsolute else Result:= inherited GetPathType(sPath); end; function TGioFileSource.CreateDirectory(const Path: String): Boolean; var AGFile: PGFile; TargetPath: String; begin if StrBegins(Path, FCurrentAddress) then TargetPath := Path else begin TargetPath := FCurrentAddress + Path; end; AGFile:= GioNewFile(TargetPath); Result:= g_file_make_directory_with_parents(AGFile, nil, nil); g_object_unref(PGObject(AGFile)); end; function TGioFileSource.FileSystemEntryExists(const Path: String): Boolean; var AGFile: PGFile; TargetPath: String; begin if StrBegins(Path, FCurrentAddress) then TargetPath := Path else begin TargetPath := FCurrentAddress + Path; end; AGFile := GioNewFile(TargetPath); Result := g_file_query_exists (AGFile, nil); g_object_unref(PGObject(AGFile)); end; function TGioFileSource.GetFreeSpace(Path: String; out FreeSize, TotalSize: Int64): Boolean; var AFile: PGFile; AInfo: PGFileInfo; begin AFile := GioNewFile(Path); AInfo := g_file_query_filesystem_info (AFile, FILE_ATTRIBUTE_FILESYSTEM_FREE + ',' + FILE_ATTRIBUTE_FILESYSTEM_SIZE, nil, nil); Result := Assigned(AInfo); if Result then begin FreeSize := g_file_info_get_attribute_uint64(AInfo, FILE_ATTRIBUTE_FILESYSTEM_FREE); TotalSize := g_file_info_get_attribute_uint64(AInfo, FILE_ATTRIBUTE_FILESYSTEM_SIZE); g_object_unref(AInfo); end; g_object_unref(PGObject(AFile)); end; function TGioFileSource.GetParentDir(sPath: String): String; begin Result:=inherited GetParentDir(sPath); end; function TGioFileSource.IsPathAtRoot(Path: String): Boolean; begin Result:=inherited IsPathAtRoot(Path); end; function TGioFileSource.GetRootDir(sPath: String): String; begin Result:=inherited GetRootDir(sPath); end; function TGioFileSource.GetRootDir: String; begin Result:=inherited GetRootDir; end; function TGioFileSource.GetProperties: TFileSourceProperties; begin Result:=inherited GetProperties; end; function TGioFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TGioListOperation.Create(TargetFileSource, FCurrentAddress + TargetPath); end; function TGioFileSource.CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; SourceFiles.Path:= FCurrentAddress + SourceFiles.Path; Result:= TGioCopyOperation.Create(SourceFileSource, SourceFileSource, SourceFiles, FCurrentAddress + TargetPath); end; function TGioFileSource.CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; if not StrBegins(TargetPath, FCurrentAddress) then TargetPath:= FCurrentAddress + TargetPath; Result:= TGioCopyInOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TGioFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; if not StrBegins(SourceFiles.Path, FCurrentAddress) then SourceFiles.Path:= FCurrentAddress + SourceFiles.Path; Result := TGioCopyOutOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TGioFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; SourceFiles.Path:= FCurrentAddress + SourceFiles.Path; Result := TGioMoveOperation.Create(TargetFileSource, SourceFiles, FCurrentAddress + TargetPath); end; function TGioFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; FilesToDelete.Path:= FCurrentAddress + FilesToDelete.Path; Result := TGioDeleteOperation.Create(TargetFileSource, FilesToDelete); end; function TGioFileSource.CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TGioCreateDirectoryOperation.Create(TargetFileSource, FCurrentAddress + BasePath, DirectoryPath); end; function TGioFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TGioExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; function TGioFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TGioCalcStatisticsOperation.Create(TargetFileSource, theFiles); end; function TGioFileSource.CreateSetFilePropertyOperation( var theTargetFiles: TFiles; var theNewProperties: TFileProperties ): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; if not StrBegins(theTargetFiles.Path, FCurrentAddress) then theTargetFiles.Path:= FCurrentAddress + theTargetFiles.Path; Result := TGioSetFilePropertyOperation.Create(TargetFileSource, theTargetFiles, theNewProperties); end; end. ���������������������������������doublecmd-1.1.22/src/filesources/gio/ugiofilesourceutil.pas�����������������������������������������0000644�0001750�0000144�00000070101�14743153644�023124� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioFileSourceUtil; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCStrUtils, uFile, uFileSource, uFileSourceOperation, uFileSourceCopyOperation, uFileSystemUtil, uFileSourceOperationOptions, uFileSourceTreeBuilder, uGioFileSource, uGLib2, uGio2, uLog, uGlobs, uFileSourceOperationUI; const CONST_DEFAULT_QUERY_INFO_ATTRIBUTES = FILE_ATTRIBUTE_STANDARD_TYPE + ',' + FILE_ATTRIBUTE_STANDARD_NAME + ',' + FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME + ',' + FILE_ATTRIBUTE_STANDARD_SIZE + ',' + FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET + ',' + FILE_ATTRIBUTE_TIME_MODIFIED + ',' + FILE_ATTRIBUTE_TIME_ACCESS + ',' + FILE_ATTRIBUTE_TIME_CREATED + ',' + FILE_ATTRIBUTE_UNIX_MODE + ',' + FILE_ATTRIBUTE_UNIX_UID + ',' + FILE_ATTRIBUTE_UNIX_GID + ',' + FILE_ATTRIBUTE_STANDARD_TARGET_URI; type TUpdateStatisticsFunction = procedure(var NewStatistics: TFileSourceCopyOperationStatistics) of object; TCopyMoveFileFunction = function(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; error: PPGError): gboolean; cdecl; { TGioTreeBuilder } TGioTreeBuilder = class(TFileSourceTreeBuilder) protected procedure AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); override; procedure AddFilesInDirectory(srcPath: String; CurrentNode: TFileTreeNode); override; end; { TGioOperationHelper } TGioOperationHelper = class private FGioFileSource: IGioFileSource; FOperation: TFileSourceOperation; FCopyMoveFile: TCopyMoveFileFunction; FRootTargetPath: String; FRenameMask: String; FRenameNameMask, FRenameExtMask: String; FLogCaption: String; FRenamingFiles, FRenamingRootDir: Boolean; FCancel: PGCancellable; FRootDir: TFile; FOldDoneBytes: Int64; FSkipAnyError: Boolean; FStatistics: TFileSourceCopyOperationStatistics; FFileExistsOption: TFileSourceOperationOptionFileExists; FDirExistsOption: TFileSourceOperationOptionDirectoryExists; FCurrentFile: TFile; FCurrentTargetFilePath: String; AskQuestion: TAskQuestionFunction; AbortOperation: TAbortOperationFunction; CheckOperationState: TCheckOperationStateFunction; UpdateStatistics: TUpdateStatisticsFunction; ShowCompareFilesUI: TShowCompareFilesUIFunction; procedure ShowError(const Message: String; AError: PGError); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); function ProcessNode(aFileTreeNode: TFileTreeNode; CurrentTargetPath: String): Boolean; function ProcessDirectory(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; function ProcessLink(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; function ProcessFile(aNode: TFileTreeNode; AbsoluteTargetFileName: String; Flags: TGFileCopyFlags): Boolean; function TargetExists(aNode: TFileTreeNode; var aTargetFile: PGFile; var AbsoluteTargetFileName: String) : TFileSystemOperationTargetExistsResult; function DirExists(aFile: TFile; AbsoluteTargetFileName: String; AllowCopyInto: Boolean): TFileSourceOperationOptionDirectoryExists; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); function FileExists(aFile: TFile; aTargetInfo: PGFileInfo; var AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; procedure CountStatistics(aNode: TFileTreeNode); public constructor Create(FileSource: IFileSource; Operation: TFileSourceOperation; Statistics: TFileSourceCopyOperationStatistics; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; ShowCompareFilesUIFunction: TShowCompareFilesUIFunction; CopyMoveFileFunction: TCopyMoveFileFunction; TargetPath: String ); destructor Destroy; override; procedure Initialize; procedure ProcessTree(aFileTree: TFileTree); property FileExistsOption: TFileSourceOperationOptionFileExists read FFileExistsOption write FFileExistsOption; property DirExistsOption: TFileSourceOperationOptionDirectoryExists read FDirExistsOption write FDirExistsOption; property RenameMask: String read FRenameMask write FRenameMask; end; procedure ShowError(AError: PGError); procedure FreeAndNil(var AError: PGError); overload; procedure FillAndCount(Files: TFiles; CountDirs: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); implementation uses Forms, StrUtils, DCDateTimeUtils, uDCUtils, uFileProperty, uShowMsg, uLng, uGObject2, uGio, DCFileAttributes; procedure ShowError(AError: PGError); begin msgError(nil, AError^.message); g_error_free(AError); end; procedure FillAndCount(Files: TFiles; CountDirs: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); var I: Integer; aFile: TFile; procedure FillAndCountRec(const srcPath: String); var AFolder: PGFile; AInfo: PGFileInfo; AFileName: Pgchar; AError: PGError = nil; AFileEnum: PGFileEnumerator; begin AFolder:= GioNewFile(srcPath); try AFileEnum:= g_file_enumerate_children (AFolder, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, @AError); if Assigned(AFileEnum) then begin AInfo:= g_file_enumerator_next_file (AFileEnum, nil, @AError); while Assigned(AInfo) do begin AFileName:= g_file_info_get_name(AInfo); if (aFileName <> '.') and (aFileName <> '..') then begin aFile:= TGioFileSource.CreateFile(srcPath, AFolder, AInfo); NewFiles.Add(aFile); if aFile.IsLink then begin end else if aFile.IsDirectory then begin if CountDirs then Inc(FilesCount); FillAndCountRec(srcPath + aFileName + PathDelim); end else begin Inc(FilesSize, aFile.Size); Inc(FilesCount); end; end; g_object_unref(AInfo); AInfo:= g_file_enumerator_next_file (AFileEnum, nil, @AError); end; g_object_unref(AFileEnum); end; if Assigned(AError) then ShowError(AError); finally g_object_unref(PGObject(AFolder)); end; end; begin FilesCount:= 0; FilesSize:= 0; NewFiles := TFiles.Create(Files.Path); for I := 0 to Files.Count - 1 do begin aFile := Files[I]; NewFiles.Add(aFile.Clone); if aFile.IsDirectory and (not aFile.IsLinkToDirectory) then begin if CountDirs then Inc(FilesCount); FillAndCountRec(aFile.FullPath + DirectorySeparator); // recursive browse child dir end else begin Inc(FilesCount); Inc(FilesSize, aFile.Size); // in first level we know file size -> use it end; end; end; function FileExistsMessage(SourceFile: TFile; TargetInfo: PGFileInfo; const TargetName: String): String; begin Result:= rsMsgFileExistsOverwrite + LineEnding + TargetName + LineEnding + Format(rsMsgFileExistsFileInfo, [IntToStrTS(g_file_info_get_size(TargetInfo)), DateTimeToStr(UnixFileTimeToDateTime(g_file_info_get_attribute_uint64(TargetInfo, FILE_ATTRIBUTE_TIME_MODIFIED)))]) + LineEnding; Result:= Result + LineEnding + rsMsgFileExistsWithFile + LineEnding + SourceFile.FullPath + LineEnding + Format(rsMsgFileExistsFileInfo, [IntToStrTS(SourceFile.Size), DateTimeToStr(SourceFile.ModificationTime)]); end; procedure FreeAndNil(var AError: PGError); begin g_error_free(AError); AError:= nil; end; procedure ProgressCallback(current_num_bytes: gint64; total_num_bytes: gint64; user_data: gpointer); cdecl; var Helper: TGioOperationHelper absolute user_data; begin with Helper do begin if FOperation.State = fsosStopping then // Cancel operation begin g_cancellable_cancel(FCancel); Exit; end; with FStatistics do begin CurrentFileDoneBytes:= current_num_bytes; CurrentFileTotalBytes:= total_num_bytes; DoneBytes:= FOldDoneBytes + current_num_bytes; end; UpdateStatistics(FStatistics); CheckOperationState; end; end; { TGioTreeBuilder } procedure TGioTreeBuilder.AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); begin // Add as normal file/directory aFile.Attributes:= aFile.Attributes and (not S_IFLNK); if aFile.IsLinkToDirectory then begin aFile.Attributes:= aFile.Attributes or S_IFDIR; AddDirectory(aFile, CurrentNode); end else begin AddFile(aFile, CurrentNode); end; end; procedure TGioTreeBuilder.AddFilesInDirectory(srcPath: String; CurrentNode: TFileTreeNode); var AFile: TFile; AFolder: PGFile; AInfo: PGFileInfo; AError: PGError = nil; AFileEnum: PGFileEnumerator; begin AFolder:= GioNewFile(srcPath); try AFileEnum := g_file_enumerate_children (AFolder, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, @AError); // List files try AInfo:= g_file_enumerator_next_file(AFileEnum, nil, @AError); while Assigned(AInfo) do begin CheckOperationState; AFile:= TGioFileSource.CreateFile(srcPath, AFolder, AInfo); g_object_unref(AInfo); AddItem(aFile, CurrentNode); AInfo:= g_file_enumerator_next_file(AFileEnum, nil, @AError); end; if Assigned(AError) then ShowError(AError); finally g_object_unref(AFileEnum); end; finally g_object_unref(PGObject(AFolder)); end; end; { TGioOperationHelper } procedure TGioOperationHelper.ShowError(const Message: String; AError: PGError); begin try if not gSkipFileOpError then begin if AskQuestion(Message + LineEnding + AError^.message, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin AbortOperation; end; end; if log_errors in gLogOptions then logWrite(FOperation.Thread, Message, lmtError, gSkipFileOpError); finally g_error_free(AError); end; end; procedure TGioOperationHelper.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(FOperation.Thread, sMessage, logMsgType); end; end; function TGioOperationHelper.ProcessNode(aFileTreeNode: TFileTreeNode; CurrentTargetPath: String): Boolean; var aFile: TFile; ProcessedOk: Boolean; TargetName: String; CurrentFileIndex: Integer; CurrentSubNode: TFileTreeNode; begin Result := True; for CurrentFileIndex := 0 to aFileTreeNode.SubNodesCount - 1 do begin CurrentSubNode := aFileTreeNode.SubNodes[CurrentFileIndex]; aFile := CurrentSubNode.TheFile; if FRenamingRootDir and (aFile = FRootDir) then TargetName := CurrentTargetPath + FRenameMask else if FRenamingFiles then TargetName := CurrentTargetPath + ApplyRenameMask(aFile, FRenameNameMask, FRenameExtMask) else TargetName := CurrentTargetPath + aFile.Name; with FStatistics do begin CurrentFileFrom := aFile.FullPath; CurrentFileTo := TargetName; CurrentFileTotalBytes := aFile.Size; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics); if aFile.IsDirectory then ProcessedOk := ProcessDirectory(CurrentSubNode, TargetName) else if aFile.IsLink then ProcessedOk := ProcessLink(CurrentSubNode, TargetName) else ProcessedOk := ProcessFile(CurrentSubNode, TargetName, G_FILE_COPY_NONE); if not ProcessedOk then Result := False; CheckOperationState; end; end; function TGioOperationHelper.ProcessDirectory(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; var AError: PGError = nil; bRemoveDirectory: Boolean; NodeData: TFileTreeNodeData; SourceFile, TargetFile: PGFile; begin NodeData := aNode.Data as TFileTreeNodeData; SourceFile:= GioNewFile(aNode.TheFile.FullPath); TargetFile:= GioNewFile(AbsoluteTargetFileName); try // If some files will not be moved then source directory cannot be deleted. bRemoveDirectory := (FCopyMoveFile = g_file_move) and (NodeData.SubnodesHaveExclusions = False); case TargetExists(aNode, TargetFile, AbsoluteTargetFileName) of fsoterSkip: begin Result := False; CountStatistics(aNode); end; fsoterNotExists: begin // Try moving whole directory tree. It can be done only if we don't have // to process each subnode: if the files are not being renamed or excluded. if (FCopyMoveFile = g_file_move) and (not FRenamingFiles) and (NodeData.SubnodesHaveExclusions = False) and g_file_move(SourceFile, TargetFile, G_FILE_COPY_NOFOLLOW_SYMLINKS or G_FILE_COPY_NO_FALLBACK_FOR_MOVE, nil, nil, nil, nil) then begin // Success. CountStatistics(aNode); Result := True; bRemoveDirectory := False; end else begin // Create target directory. if g_file_make_directory_with_parents(TargetFile, nil, @AError) then begin // Copy/Move all files inside. Result := ProcessNode(aNode, IncludeTrailingPathDelimiter(AbsoluteTargetFileName)); end else begin // Error - all files inside not copied/moved. ShowError(rsMsgLogError + Format(rsMsgErrForceDir, [AbsoluteTargetFileName]), AError); Result := False; CountStatistics(aNode); end; end; end; fsoterAddToTarget: begin // Don't create existing directory, but copy files into it. Result := ProcessNode(aNode, IncludeTrailingPathDelimiter(AbsoluteTargetFileName)); end; else raise Exception.Create('Invalid TargetExists result'); end; if bRemoveDirectory and Result then begin g_file_delete(SourceFile, nil, nil); end; finally g_object_unref(PGObject(SourceFile)); g_object_unref(PGObject(TargetFile)); end; end; function TGioOperationHelper.ProcessLink(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Boolean; begin Result:= ProcessFile(aNode, AbsoluteTargetFileName, G_FILE_COPY_NOFOLLOW_SYMLINKS); end; function TGioOperationHelper.ProcessFile(aNode: TFileTreeNode; AbsoluteTargetFileName: String; Flags: TGFileCopyFlags): Boolean; var AError: PGError = nil; SourceFile, TargetFile: PGFile; begin FOldDoneBytes:= FStatistics.DoneBytes; FCancel:= g_cancellable_new(); SourceFile:= GioNewFile(aNode.TheFile.FullPath); TargetFile:= GioNewFile(AbsoluteTargetFileName); try repeat Result:= FCopyMoveFile(SourceFile, TargetFile, Flags, FCancel, @ProgressCallback, Self, @AError); if Assigned(AError) then try if AError^.code = G_IO_ERROR_CANCELLED then AbortOperation else if AError^.code = G_IO_ERROR_EXISTS then begin case TargetExists(aNode, TargetFile, AbsoluteTargetFileName) of fsoterDeleted: begin FreeAndNil(AError); Flags += G_FILE_COPY_OVERWRITE; end; fsoterSkip: begin Result:= True; Break; end; fsoterNotExists: FreeAndNil(AError); end; end else begin if FSkipAnyError then Break; case AskQuestion(AError^.message, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourCancel], fsourRetry, fsourCancel) of fsourSkip: Break; fsourSkipAll: begin FSkipAnyError:= True; Break; end; fsourRetry: FreeAndNil(AError); fsourCancel: AbortOperation; end; end; except on EFileSourceOperationAborting do begin FreeAndNil(AError); raise; end; end; until Result; if Result then begin LogMessage(Format(rsMsgLogSuccess + FLogCaption, [aNode.TheFile.FullPath + ' -> ' + AbsoluteTargetFileName]), [log_vfs_op], lmtSuccess); end else begin LogMessage(Format(rsMsgLogError + FLogCaption, [aNode.TheFile.FullPath + ' -> ' + AbsoluteTargetFileName]) + LineEnding + AError^.message, [log_vfs_op], lmtError); FreeAndNil(AError); end; finally g_object_unref(FCancel); g_object_unref(PGObject(SourceFile)); g_object_unref(PGObject(TargetFile)); end; with FStatistics do begin DoneFiles := DoneFiles + 1; DoneBytes := FOldDoneBytes + aNode.TheFile.Size; UpdateStatistics(FStatistics); end; end; function TGioOperationHelper.TargetExists(aNode: TFileTreeNode; var aTargetFile: PGFile; var AbsoluteTargetFileName: String ): TFileSystemOperationTargetExistsResult; var AInfo, ASymlinkInfo: PGFileInfo; AFileType: TGFileType; SourceFile: TFile; function DoDirectoryExists(AllowCopyInto: Boolean): TFileSystemOperationTargetExistsResult; begin case DirExists(SourceFile, AbsoluteTargetFileName, AllowCopyInto) of fsoodeSkip: Exit(fsoterSkip); fsoodeCopyInto: begin Exit(fsoterAddToTarget); end; else raise Exception.Create('Invalid dir exists option'); end; end; function DoFileExists(): TFileSystemOperationTargetExistsResult; begin case FileExists(SourceFile, AInfo, AbsoluteTargetFileName) of fsoofeSkip: Exit(fsoterSkip); fsoofeAutoRenameSource: begin g_object_unref(PGObject(aTargetFile)); aTargetFile:= GioNewFile(AbsoluteTargetFileName); Exit(fsoterRenamed); end; fsoofeOverwrite: Exit(fsoterDeleted); else raise Exception.Create('Invalid file exists option'); end; end; begin repeat AInfo:= g_file_query_info(aTargetFile, FILE_ATTRIBUTE_STANDARD_TYPE + ',' + FILE_ATTRIBUTE_STANDARD_SIZE +','+ FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, nil); if Assigned(AInfo) then begin SourceFile:= aNode.TheFile; AFileType:= g_file_info_get_file_type(AInfo); // Target exists - ask user what to do. if AFileType = G_FILE_TYPE_DIRECTORY then begin Result := DoDirectoryExists(SourceFile.IsDirectory) end else if AFileType = G_FILE_TYPE_SYMBOLIC_LINK then begin // Check if target of the link exists. ASymlinkInfo:= g_file_query_info(aTargetFile, FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, nil, nil); if Assigned(ASymlinkInfo) then begin AFileType:= g_file_info_get_file_type(ASymlinkInfo); if AFileType = G_FILE_TYPE_DIRECTORY then Result := DoDirectoryExists(SourceFile.IsDirectory) else begin Result := DoFileExists(); end; g_object_unref(ASymlinkInfo); end else // Target of link doesn't exist. Treat link as file. Result := DoFileExists(); end else begin // Existing target is a file. Result := DoFileExists(); end; g_object_unref(AInfo); end else Result := fsoterNotExists; until Result <> fsoterRenamed; end; function TGioOperationHelper.DirExists(aFile: TFile; AbsoluteTargetFileName: String; AllowCopyInto: Boolean ): TFileSourceOperationOptionDirectoryExists; var PossibleResponses: array of TFileSourceOperationUIResponse = nil; DefaultOkResponse: TFileSourceOperationUIResponse; procedure AddResponse(Response: TFileSourceOperationUIResponse); begin SetLength(PossibleResponses, Length(PossibleResponses) + 1); PossibleResponses[Length(PossibleResponses) - 1] := Response; end; begin case FDirExistsOption of fsoodeNone: begin if AllowCopyInto then begin AddResponse(fsourCopyInto); AddResponse(fsourCopyIntoAll); end; AddResponse(fsourSkip); AddResponse(fsourSkipAll); AddResponse(fsourCancel); if AllowCopyInto then DefaultOkResponse := fsourCopyInto else DefaultOkResponse := fsourSkip; case AskQuestion(Format(rsMsgFolderExistsRwrt, [AbsoluteTargetFileName]), '', PossibleResponses, DefaultOkResponse, fsourSkip) of fsourCopyInto: Result := fsoodeCopyInto; fsourCopyIntoAll: begin FDirExistsOption := fsoodeCopyInto; Result := fsoodeCopyInto; end; fsourSkip: Result := fsoodeSkip; fsourSkipAll: begin FDirExistsOption := fsoodeSkip; Result := fsoodeSkip; end; fsourNone, fsourCancel: AbortOperation; end; end; else Result := FDirExistsOption; end; end; procedure TGioOperationHelper.QuestionActionHandler( Action: TFileSourceOperationUIAction); begin if Action = fsouaCompare then ShowCompareFilesUI(FCurrentFile, FCurrentTargetFilePath); end; function TGioOperationHelper.FileExists(aFile: TFile; aTargetInfo: PGFileInfo; var AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; const Responses: array[0..9] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourRenameSource, fsourOverwriteAll, fsourSkipAll, fsourOverwriteOlder,fsourOverwriteSmaller, fsourCancel, fsouaCompare, fsourOverwriteLarger); var Answer: Boolean; Message: String; function OverwriteOlder: TFileSourceOperationOptionFileExists; begin if aFile.ModificationTime > UnixFileTimeToDateTime(g_file_info_get_attribute_uint64(aTargetInfo, FILE_ATTRIBUTE_TIME_MODIFIED)) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteSmaller: TFileSourceOperationOptionFileExists; begin if aFile.Size > g_file_info_get_size(aTargetInfo) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteLarger: TFileSourceOperationOptionFileExists; begin if aFile.Size < g_file_info_get_size(aTargetInfo) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; begin case FFileExistsOption of fsoofeNone: repeat Answer := True; Message:= FileExistsMessage(aFile, aTargetInfo, AbsoluteTargetFileName); FCurrentFile := aFile; FCurrentTargetFilePath := AbsoluteTargetFileName; case AskQuestion(Message, '', Responses, fsourOverwrite, fsourSkip, @QuestionActionHandler) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourOverwriteOlder: begin FFileExistsOption := fsoofeOverwriteOlder; Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin FFileExistsOption := fsoofeOverwriteSmaller; Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin FFileExistsOption := fsoofeOverwriteLarger; Result:= OverwriteLarger; end; fsourRenameSource: begin Message:= ExtractFileName(AbsoluteTargetFileName); Answer:= ShowInputQuery(FOperation.Thread, Application.Title, rsEditNewFileName, Message); if Answer then begin Result:= fsoofeAutoRenameSource; AbsoluteTargetFileName:= ExtractFilePath(AbsoluteTargetFileName) + Message; end; end; fsourNone, fsourCancel: AbortOperation; end; until Answer; fsoofeOverwriteOlder: begin Result:= OverwriteOlder; end; fsoofeOverwriteSmaller: begin Result:= OverwriteSmaller; end; fsoofeOverwriteLarger: begin Result:= OverwriteLarger; end; else Result := FFileExistsOption; end; end; procedure TGioOperationHelper.CountStatistics(aNode: TFileTreeNode); procedure CountNodeStatistics(aNode: TFileTreeNode); var aFileAttrs: TFileAttributesProperty; i: Integer; begin aFileAttrs := aNode.TheFile.AttributesProperty; with FStatistics do begin if aFileAttrs.IsDirectory then begin // No statistics for directory. // Go through subdirectories. for i := 0 to aNode.SubNodesCount - 1 do CountNodeStatistics(aNode.SubNodes[i]); end else if aFileAttrs.IsLink then begin // Count only not-followed links. if aNode.SubNodesCount = 0 then DoneFiles := DoneFiles + 1 else // Count target of link. CountNodeStatistics(aNode.SubNodes[0]); end else begin // Count files. DoneFiles := DoneFiles + 1; DoneBytes := DoneBytes + aNode.TheFile.Size; end; end; end; begin CountNodeStatistics(aNode); UpdateStatistics(FStatistics); end; constructor TGioOperationHelper.Create(FileSource: IFileSource; Operation: TFileSourceOperation; Statistics: TFileSourceCopyOperationStatistics; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; ShowCompareFilesUIFunction: TShowCompareFilesUIFunction; CopyMoveFileFunction: TCopyMoveFileFunction; TargetPath: String); begin FGioFileSource:= FileSource as IGioFileSource; FOperation:= Operation; FStatistics:= Statistics; AskQuestion := AskQuestionFunction; AbortOperation := AbortOperationFunction; CheckOperationState := CheckOperationStateFunction; UpdateStatistics := UpdateStatisticsFunction; ShowCompareFilesUI := ShowCompareFilesUIFunction; FCopyMoveFile := CopyMoveFileFunction; FFileExistsOption := fsoofeNone; FRootTargetPath := TargetPath; FRenameMask := ''; FRenamingFiles := False; FRenamingRootDir := False; inherited Create; end; destructor TGioOperationHelper.Destroy; begin inherited Destroy; end; procedure TGioOperationHelper.Initialize; begin if FCopyMoveFile = g_file_copy then FLogCaption := rsMsgLogCopy else begin FLogCaption := rsMsgLogMove; end; SplitFileMask(FRenameMask, FRenameNameMask, FRenameExtMask); end; procedure TGioOperationHelper.ProcessTree(aFileTree: TFileTree); var aFile: TFile; begin FRenamingFiles := (FRenameMask <> '*.*') and (FRenameMask <> ''); // If there is a single root dir and rename mask doesn't have wildcards // treat is as a rename of the root dir. if (aFileTree.SubNodesCount = 1) and FRenamingFiles then begin aFile := aFileTree.SubNodes[0].TheFile; if (aFile.IsDirectory or aFile.IsLinkToDirectory) and not ContainsWildcards(FRenameMask) then begin FRenamingFiles := False; FRenamingRootDir := True; FRootDir := aFile; end; end; ProcessNode(aFileTree, FRootTargetPath); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiolistoperation.pas������������������������������������������0000644�0001750�0000144�00000005111�14743153644�022761� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioListOperation; {$macro on} {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uGioFileSource, uFileSource, uGLib2, uGio2; type { TGioListOperation } TGioListOperation = class(TFileSourceListOperation) private FGioFileSource: IGioFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses LCLProc, Dialogs, uFile, DCDateTimeUtils, uGioFileSourceUtil, uGObject2, uGio; {$DEFINE G_IO_ERROR:= g_io_error_quark()} constructor TGioListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FGioFileSource := aFileSource as IGioFileSource; inherited Create(aFileSource, aPath); end; procedure TGioListOperation.MainExecute; var AFile: TFile; AFolder: PGFile; AInfo: PGFileInfo; AError: PGError = nil; AFileEnum: PGFileEnumerator; AFileSource: TGioFileSource; begin FFiles.Clear; with FGioFileSource do begin AFolder:= GioNewFile(Path); try while True do begin AFileEnum := g_file_enumerate_children (AFolder, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nil, @AError); if Assigned(AError) then begin // Mount the target if g_error_matches(AError, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED) then begin FreeAndNil(AError); if FGioFileSource.MountPath(AFolder, AError) then Continue else begin ShowError(AError); Exit; end; end else if g_error_matches(AError, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) then begin FreeAndNil(AError); Exit; end else begin ShowError(AError); Exit; end; end; Break; end; // List files try AFileSource:= TGioFileSource(GetClass); AInfo:= g_file_enumerator_next_file(AFileEnum, nil, @AError); while Assigned(AInfo) do begin CheckOperationState; AFile:= AFileSource.CreateFile(Path, AFolder, AInfo); g_object_unref(AInfo); FFiles.Add(AFile); AInfo:= g_file_enumerator_next_file(AFileEnum, nil, @AError); end; if Assigned(AError) then ShowError(AError); finally g_object_unref(AFileEnum); end; finally g_object_unref(PGObject(AFolder)); end; end; // FGioFileSource end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiomoveoperation.pas������������������������������������������0000644�0001750�0000144�00000005125�14743153644�022761� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioMoveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceMoveOperation, uFileSource, uFile, uGioFileSourceUtil; type { TGioMoveOperation } TGioMoveOperation = class(TFileSourceMoveOperation) private FOperationHelper: TGioOperationHelper; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceMoveOperationStatistics; // local copy of statistics public constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); virtual reintroduce; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uFileSourceOperationOptions, uGio2; constructor TGioMoveOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin inherited Create(aFileSource, theSourceFiles, aTargetPath); end; destructor TGioMoveOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); end; procedure TGioMoveOperation.Initialize; var TreeBuilder: TGioTreeBuilder; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TGioTreeBuilder.Create(@AskQuestion, @CheckOperationState); try TreeBuilder.SymLinkOption := fsooslDontFollow; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; FOperationHelper := TGioOperationHelper.Create( FileSource as IFileSource, Self, FStatistics, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, g_file_move, TargetPath); FOperationHelper.RenameMask := RenameMask; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.DirExistsOption := DirExistsOption; FOperationHelper.Initialize; end; procedure TGioMoveOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree); end; procedure TGioMoveOperation.Finalize; begin FileExistsOption := FOperationHelper.FileExistsOption; FOperationHelper.Free; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/gio/ugiosetfilepropertyoperation.pas�������������������������������0000644�0001750�0000144�00000014374�14743153644�025261� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGioSetFilePropertyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceSetFilePropertyOperation, uFileSource, uFileSourceOperationOptions, uFile, uGio2, uGLib2, uFileProperty, uWfxPluginFileSource; type { TGioSetFilePropertyOperation } TGioSetFilePropertyOperation = class(TFileSourceSetFilePropertyOperation) private FFullFilesTree: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceSetFilePropertyOperationStatistics; // local copy of statistics // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; private function SetFileTime(AFile: PGFile; ATime: Pgchar; AValue: TDateTime): Boolean; protected function SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; override; public constructor Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses DCBasicTypes, DCDateTimeUtils, uGioFileSourceUtil, uGObject2, uGio; constructor TGioSetFilePropertyOperation.Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); begin FSymLinkOption := fsooslNone; FFullFilesTree := nil; inherited Create(aTargetFileSource, theTargetFiles, theNewProperties); // Assign after calling inherited constructor. FSupportedProperties := [fpName, fpAttributes, fpModificationTime, fpCreationTime, fpLastAccessTime]; end; destructor TGioSetFilePropertyOperation.Destroy; begin inherited Destroy; if Recursive then begin if Assigned(FFullFilesTree) then FreeAndNil(FFullFilesTree); end; end; procedure TGioSetFilePropertyOperation.Initialize; var TotalBytes: Int64; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; if not Recursive then begin FFullFilesTree := TargetFiles; FStatistics.TotalFiles:= FFullFilesTree.Count; end else begin FillAndCount(TargetFiles, True, FFullFilesTree, FStatistics.TotalFiles, TotalBytes); // gets full list of files (recursive) end; end; procedure TGioSetFilePropertyOperation.MainExecute; var aFile: TFile; aTemplateFile: TFile; CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to FFullFilesTree.Count - 1 do begin aFile := FFullFilesTree[CurrentFileIndex]; FStatistics.CurrentFile := aFile.FullPath; UpdateStatistics(FStatistics); if Assigned(TemplateFiles) and (CurrentFileIndex < TemplateFiles.Count) then aTemplateFile := TemplateFiles[CurrentFileIndex] else aTemplateFile := nil; SetProperties(CurrentFileIndex, aFile, aTemplateFile); with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; CheckOperationState; end; end; function TGioSetFilePropertyOperation.SetFileTime(AFile: PGFile; ATime: Pgchar; AValue: TDateTime): Boolean; begin Result:= g_file_set_attribute_uint64 (AFile, ATime, DateTimeToUnixFileTime(AValue), G_FILE_QUERY_INFO_NONE, nil, nil); end; function TGioSetFilePropertyOperation.SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; var AGFile: PGFile; AGNewFile: PGFile; NewAttributes: TFileAttrs; begin Result := sfprSuccess; AGFile:= GioNewFile(aFile.FullPath); case aTemplateProperty.GetID of fpName: if (aTemplateProperty as TFileNameProperty).Value <> aFile.Name then begin AGNewFile:= g_file_set_display_name(AGFile, Pgchar((aTemplateProperty as TFileNameProperty).Value), nil, nil); if (AGNewFile = nil) then Result := sfprError else begin g_object_unref(PGObject(AGNewFile)); end; end else Result := sfprSkipped; fpAttributes: if (aTemplateProperty as TFileAttributesProperty).Value <> (aFile.Properties[fpAttributes] as TFileAttributesProperty).Value then begin NewAttributes := (aTemplateProperty as TFileAttributesProperty).Value; if aTemplateProperty is TUnixFileAttributesProperty then begin if not g_file_set_attribute_uint32 (AGFile, FILE_ATTRIBUTE_UNIX_MODE, NewAttributes, G_FILE_QUERY_INFO_NONE, nil, nil) then Result := sfprError; end else raise Exception.Create('Unsupported file attributes type'); end else Result := sfprSkipped; fpModificationTime: if (aTemplateProperty as TFileModificationDateTimeProperty).Value <> (aFile.Properties[fpModificationTime] as TFileModificationDateTimeProperty).Value then begin if not SetFileTime(AGFile, FILE_ATTRIBUTE_TIME_MODIFIED, (aTemplateProperty as TFileModificationDateTimeProperty).Value) then Result := sfprError; end else Result := sfprSkipped; fpCreationTime: if (aTemplateProperty as TFileCreationDateTimeProperty).Value <> (aFile.Properties[fpCreationTime] as TFileCreationDateTimeProperty).Value then begin if not SetFileTime(AGFile, FILE_ATTRIBUTE_TIME_CREATED, (aTemplateProperty as TFileCreationDateTimeProperty).Value) then Result := sfprError; end else Result := sfprSkipped; fpLastAccessTime: if (aTemplateProperty as TFileLastAccessDateTimeProperty).Value <> (aFile.Properties[fpLastAccessTime] as TFileLastAccessDateTimeProperty).Value then begin if not SetFileTime(AGFile, FILE_ATTRIBUTE_TIME_ACCESS, (aTemplateProperty as TFileLastAccessDateTimeProperty).Value) then Result := sfprError; end else Result := sfprSkipped; else raise Exception.Create('Trying to set unsupported property'); end; g_object_unref(PGObject(AGFile)); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020414� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/fmultiarchivecopyoperationoptions.lfm�����������������0000644�0001750�0000144�00000001517�14743153644�030212� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object MultiArchiveCopyOperationOptionsUI: TMultiArchiveCopyOperationOptionsUI Left = 535 Height = 158 Top = 391 Width = 549 AutoSize = True ClientHeight = 158 ClientWidth = 549 LCLVersion = '1.8.4.0' object lblFileExists: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = cmbFileExists AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 4 Width = 81 BorderSpacing.Around = 6 Caption = 'When file exists' FocusControl = cmbFileExists ParentColor = False end object cmbFileExists: TComboBox AnchorSideLeft.Control = lblFileExists AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Owner Left = 95 Height = 23 Top = 0 Width = 109 BorderSpacing.Left = 8 ItemHeight = 15 Style = csDropDownList TabOrder = 0 end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/fmultiarchivecopyoperationoptions.lrj�����������������0000644�0001750�0000144�00000000335�14743153644�030220� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":111687171,"name":"tmultiarchivecopyoperationoptionsui.lblfileexists.caption","sourcebytes":[87,104,101,110,32,102,105,108,101,32,101,120,105,115,116,115],"value":"When file exists"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/fmultiarchivecopyoperationoptions.pas�����������������0000644�0001750�0000144�00000005035�14743153644�030216� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fMultiArchiveCopyOperationOptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ExtCtrls, uFileSourceOperationOptionsUI, uMultiArchiveCopyInOperation, uMultiArchiveCopyOutOperation; type { TMultiArchiveCopyOperationOptionsUI } TMultiArchiveCopyOperationOptionsUI = class(TFileSourceOperationOptionsUI) cmbFileExists: TComboBox; grpOptions: TGroupBox; lblFileExists: TLabel; private procedure SetOperationOptions(CopyInOperation: TMultiArchiveCopyInOperation); overload; procedure SetOperationOptions(CopyOutOperation: TMultiArchiveCopyOutOperation); overload; public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; procedure SaveOptions; override; procedure SetOperationOptions(Operation: TObject); override; end; implementation {$R *.lfm} uses DCStrUtils, uLng, uGlobs, uFileSourceOperationOptions; { TMultiArchiveCopyOperationOptionsUI } constructor TMultiArchiveCopyOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited; ParseLineToList(rsFileOpCopyMoveFileExistsOptions, cmbFileExists.Items); // Load default options. case gOperationOptionFileExists of fsoofeNone : cmbFileExists.ItemIndex := 0; fsoofeOverwrite: cmbFileExists.ItemIndex := 1; fsoofeSkip : cmbFileExists.ItemIndex := 2; end; end; procedure TMultiArchiveCopyOperationOptionsUI.SaveOptions; begin // TODO: Saving options for each file source operation separately. end; procedure TMultiArchiveCopyOperationOptionsUI.SetOperationOptions(Operation: TObject); begin if Operation is TMultiArchiveCopyInOperation then SetOperationOptions(Operation as TMultiArchiveCopyInOperation) else if Operation is TMultiArchiveCopyOutOperation then SetOperationOptions(Operation as TMultiArchiveCopyOutOperation); end; procedure TMultiArchiveCopyOperationOptionsUI.SetOperationOptions(CopyInOperation: TMultiArchiveCopyInOperation); begin { with CopyInOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; end; } end; procedure TMultiArchiveCopyOperationOptionsUI.SetOperationOptions(CopyOutOperation: TMultiArchiveCopyOutOperation); begin with CopyOutOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivecalcstatisticsoperation.pas��������������0000644�0001750�0000144�00000007553�14743153644�030673� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCalcStatisticsOperation, uFileSource, uMultiArchiveFileSource, uFile; type TMultiArchiveCalcStatisticsOperation = class(TFileSourceCalcStatisticsOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; FStatistics: TFileSourceCalcStatisticsOperationStatistics; // local copy of statistics procedure ProcessFile(aFile: TFile); procedure ProcessSubDirs(const srcPath: String); public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses uMultiArc, DCStrUtils; constructor TMultiArchiveCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin inherited Create(aTargetFileSource, theFiles); FMultiArchiveFileSource:= aTargetFileSource as IMultiArchiveFileSource; end; destructor TMultiArchiveCalcStatisticsOperation.Destroy; begin inherited Destroy; end; procedure TMultiArchiveCalcStatisticsOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; end; procedure TMultiArchiveCalcStatisticsOperation.MainExecute; var CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to Files.Count - 1 do begin ProcessFile(Files[CurrentFileIndex]); CheckOperationState; end; end; procedure TMultiArchiveCalcStatisticsOperation.ProcessFile(aFile: TFile); begin FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); if aFile.IsDirectory then begin Inc(FStatistics.Directories); ProcessSubDirs(aFile.Path + aFile.Name + DirectorySeparator); end else if aFile.IsLink then begin Inc(FStatistics.Links); end else begin // Not always this will be regular file (on Unix can be socket, FIFO, block, char, etc.) // Maybe check with: FPS_ISREG() on Unix? Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + aFile.Size; if aFile.ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := aFile.ModificationTime; if aFile.ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := aFile.ModificationTime; end; UpdateStatistics(FStatistics); end; procedure TMultiArchiveCalcStatisticsOperation.ProcessSubDirs(const srcPath: String); var I: Integer; AFileList: TList; CurrFileName: String; ArchiveItem: TArchiveItem; ModificationTime: TDateTime; begin AFileList:= FMultiArchiveFileSource.ArchiveFileList.LockList; try for I:= 0 to AFileList.Count - 1 do begin ArchiveItem := TArchiveItem(AFileList.Items[I]); CurrFileName := PathDelim + ArchiveItem.FileName; if not IsInPath(srcPath, CurrFileName, True, False) then Continue; if FMultiArchiveFileSource.FileIsDirectory(ArchiveItem) then Inc(FStatistics.Directories) else if FMultiArchiveFileSource.FileIsLink(ArchiveItem) then Inc(FStatistics.Links) else begin Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + ArchiveItem.UnpSize; try with ArchiveItem do ModificationTime := EncodeDate(Year, Month, Day) + EncodeTime(Hour, Minute, Second, 0); if ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := ModificationTime; if ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := ModificationTime; except on EConvertError do; end; end; end; finally FMultiArchiveFileSource.ArchiveFileList.UnlockList; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivecopyinoperation.pas����������������������0000644�0001750�0000144�00000031301�14743153644�027143� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveCopyInOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uLog, uGlobs, un_process, uFileSourceOperation, uFileSourceCopyOperation, uFileSource, uFile, uArchiveCopyOperation, uMultiArchiveFileSource; type { TMultiArchiveCopyInOperation } TMultiArchiveCopyInOperation = class(TArchiveCopyInOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; FRemoveFilesTree: TFiles; FPassword: String; FVolumeSize: String; FCustomParams: String; FCallResult: Boolean; procedure ShowError(sMessage: String; logOptions: TLogOptions = []); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); function CheckForErrors(const FileName: String; ExitStatus: LongInt): Boolean; procedure DeleteFile(const BasePath: String; aFile: TFile); procedure DeleteFiles(const BasePath: String; aFiles: TFiles); protected FExProcess: TExProcess; FTempFile: String; FErrorLevel: LongInt; FCommandLine: String; function Tar: Boolean; procedure OnReadLn(str: string); procedure OperationProgressHandler; procedure OnQueryString(str: string); procedure UpdateProgress(SourceName, TargetName: String; IncSize: Int64); procedure FileSourceOperationStateChangedNotify(Operation: TFileSourceOperation; AState: TFileSourceOperationState); public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; property PackingFlags: Integer read FPackingFlags write FPackingFlags; property Password: String read FPassword write FPassword; property VolumeSize: String read FVolumeSize write FVolumeSize; property CustomParams: String read FCustomParams write FCustomParams; property TarBefore: Boolean read FTarBefore write FTarBefore; end; implementation uses LazUTF8, DCStrUtils, uDCUtils, uMultiArc, uLng, WcxPlugin, uFileSourceOperationUI, uFileSystemFileSource, uFileSystemUtil, uMultiArchiveUtil, DCOSUtils, uOSUtils, uTarWriter, uShowMsg, uAdministrator; constructor TMultiArchiveCopyInOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FMultiArchiveFileSource := aTargetFileSource as IMultiArchiveFileSource; FPassword:= FMultiArchiveFileSource.Password; FFullFilesTree := nil; FRemoveFilesTree := nil; FPackingFlags := 0; FVolumeSize := EmptyStr; FTarBefore:= False; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; with FStatistics do begin DoneFiles := -1; CurrentFileDoneBytes := -1; UpdateStatistics(FStatistics); end; end; destructor TMultiArchiveCopyInOperation.Destroy; begin inherited Destroy; FreeAndNil(FFullFilesTree); FreeAndNil(FRemoveFilesTree); end; procedure TMultiArchiveCopyInOperation.Initialize; begin with FMultiArchiveFileSource do begin if (ExtractFileExt(ArchiveFileName) = GetSfxExt) and (Length(MultiArcItem.FAddSelfExtract) <> 0) then FCommandLine:= MultiArcItem.FAddSelfExtract else FCommandLine:= MultiArcItem.FAdd; end; if (TargetPath <> PathDelim) and (Pos('%R', FCommandLine) = 0) then begin AskQuestion('', rsMsgErrNotSupported, [fsourOk], fsourOk, fsourOk); RaiseAbortOperation; end; FExProcess:= TExProcess.Create(EmptyStr); FExProcess.OnReadLn:= @OnReadLn; FExProcess.OnOperationProgress:= @OperationProgressHandler; FTempFile:= GetTempName(GetTempFolder); with FMultiArchiveFileSource.MultiArcItem do if Length(FPasswordQuery) <> 0 then begin FExProcess.QueryString:= UTF8ToConsole(FPasswordQuery); FExProcess.OnQueryString:= @OnQueryString; end; AddStateChangedListener([fsosStarting, fsosPausing, fsosStopping], @FileSourceOperationStateChangedNotify); with FStatistics do begin if SourceFiles.Count = 1 then CurrentFileFrom:= SourceFiles[0].FullPath else begin CurrentFileFrom:= SourceFiles.Path + AllFilesMask; end; CurrentFileTo:= FMultiArchiveFileSource.ArchiveFileName; end; ElevateAction:= dupError; FillAndCount(SourceFiles, False, False, FFullFilesTree, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; procedure TMultiArchiveCopyInOperation.MainExecute; var I: Integer; sRootPath, sDestPath: String; MultiArcItem: TMultiArcItem; aFile: TFile; sReadyCommand: String; begin // Put to TAR archive if needed if FTarBefore then Tar; MultiArcItem := FMultiArchiveFileSource.MultiArcItem; sDestPath := ExcludeFrontPathDelimiter(TargetPath); sDestPath := ExcludeTrailingPathDelimiter(sDestPath); sRootPath:= FFullFilesTree.Path; ChangeFileListRoot(EmptyStr, FFullFilesTree); // Get maximum acceptable command errorlevel FErrorLevel:= ExtractErrorLevel(FCommandLine); if Pos('%F', FCommandLine) <> 0 then // pack file by file for I:= FFullFilesTree.Count - 1 downto 0 do begin aFile:= FFullFilesTree[I]; UpdateProgress(sRootPath + aFile.FullPath, sDestPath, 0); sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, FCommandLine, FMultiArchiveFileSource.ArchiveFileName, nil, aFile.FullPath, sDestPath, FTempFile, Password, VolumeSize, CustomParams ); OnReadLn(sReadyCommand); // Set archiver current path to file list root FExProcess.Process.CurrentDirectory:= sRootPath; FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; UpdateProgress(sRootPath + aFile.FullPath, sDestPath, aFile.Size); // Check for errors. if CheckForErrors(sRootPath + aFile.FullPath, FExProcess.ExitStatus) then begin if (PackingFlags and PK_PACK_MOVE_FILES) <> 0 then DeleteFile(sRootPath, aFile); end; end else // pack whole file list begin sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, FCommandLine, FMultiArchiveFileSource.ArchiveFileName, FFullFilesTree, EmptyStr, sDestPath, FTempFile, Password, VolumeSize, CustomParams ); OnReadLn(sReadyCommand); // Set archiver current path to file list root FExProcess.Process.CurrentDirectory:= sRootPath; FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; // Check for errors. if CheckForErrors(FMultiArchiveFileSource.ArchiveFileName, FExProcess.ExitStatus) then begin if (PackingFlags and PK_PACK_MOVE_FILES) <> 0 then DeleteFiles(sRootPath, FFullFilesTree); end; end; // Delete temporary TAR archive if needed if FTarBefore then begin mbDeleteFile(FTarFileName); if FCallResult and (PackingFlags and PK_PACK_MOVE_FILES <> 0) then DeleteFiles(EmptyStr, FRemoveFilesTree); end; end; procedure TMultiArchiveCopyInOperation.Finalize; begin FreeAndNil(FExProcess); with FMultiArchiveFileSource.MultiArcItem do if not FDebug then mbDeleteFile(FTempFile); end; procedure TMultiArchiveCopyInOperation.ShowError(sMessage: String; logOptions: TLogOptions); begin if not gSkipFileOpError then begin if AskQuestion(sMessage, '', [fsourSkip, fsourCancel], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end else begin LogMessage(sMessage, logOptions, lmtError); end; end; procedure TMultiArchiveCopyInOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; function TMultiArchiveCopyInOperation.CheckForErrors(const FileName: String; ExitStatus: LongInt): Boolean; begin if ExitStatus > FErrorLevel then begin Result:= False; ShowError(Format(rsMsgLogError + rsMsgLogPack, [FileName + ' - Exit status: ' + IntToStr(ExitStatus)]), [log_arc_op]); end else begin Result:= True; LogMessage(Format(rsMsgLogSuccess + rsMsgLogPack, [FileName]), [log_arc_op], lmtSuccess); end; FCallResult:= Result; end; procedure TMultiArchiveCopyInOperation.DeleteFile(const BasePath: String; aFile: TFile); begin if aFile.IsDirectory then mbRemoveDir(BasePath + aFile.FullPath) else mbDeleteFile(BasePath + aFile.FullPath); end; procedure TMultiArchiveCopyInOperation.DeleteFiles(const BasePath: String; aFiles: TFiles); var I: Integer; aFile: TFile; begin for I:= aFiles.Count - 1 downto 0 do begin aFile:= aFiles[I]; if aFile.IsDirectory then mbRemoveDir(BasePath + aFile.FullPath) else mbDeleteFile(BasePath + aFile.FullPath); end; end; function TMultiArchiveCopyInOperation.Tar: Boolean; var TarWriter: TTarWriter = nil; begin Result:= False; FTarFileName:= RemoveFileExt(FMultiArchiveFileSource.ArchiveFileName); TarWriter:= TTarWriter.Create(FTarFileName, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics ); try if TarWriter.ProcessTree(FFullFilesTree, FStatistics) then begin // Fill file list with tar archive file FRemoveFilesTree:= FFullFilesTree; FFullFilesTree:= TFiles.Create(ExtractFilePath(FTarFileName)); FFullFilesTree.Add(TFileSystemFileSource.CreateFileFromFile(FTarFileName)); Result:= True; end; finally FreeAndNil(TarWriter); end; end; procedure TMultiArchiveCopyInOperation.OnReadLn(str: string); begin with FMultiArchiveFileSource.MultiArcItem do if FOutput or FDebug then logWrite(Thread, str, lmtInfo, True, False); end; procedure TMultiArchiveCopyInOperation.OperationProgressHandler; var ArchiveSize: Int64; begin Self.CheckOperationState; with FStatistics do begin ArchiveSize := mbFileSize(FMultiArchiveFileSource.ArchiveFileName); if ArchiveSize > DoneBytes then DoneBytes := ArchiveSize; UpdateStatistics(FStatistics); end; end; procedure TMultiArchiveCopyInOperation.OnQueryString(str: string); var pcPassword: PAnsiChar; begin ShowInputQuery(FMultiArchiveFileSource.MultiArcItem.FDescription, rsMsgPasswordEnter, True, FPassword); pcPassword:= PAnsiChar(UTF8ToConsole(FPassword + LineEnding)); FExProcess.Process.Input.Write(pcPassword^, Length(pcPassword)); end; procedure TMultiArchiveCopyInOperation.UpdateProgress(SourceName, TargetName: String; IncSize: Int64); begin with FStatistics do begin FStatistics.CurrentFileFrom:= SourceName; FStatistics.CurrentFileTo:= TargetName; CurrentFileDoneBytes:= IncSize; DoneBytes := DoneBytes + CurrentFileDoneBytes; UpdateStatistics(FStatistics); end; end; procedure TMultiArchiveCopyInOperation.FileSourceOperationStateChangedNotify( Operation: TFileSourceOperation; AState: TFileSourceOperationState); begin case AState of fsosStarting: FExProcess.Process.Resume; fsosPausing: FExProcess.Process.Suspend; fsosStopping: FExProcess.Stop; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivecopyoutoperation.pas���������������������0000644�0001750�0000144�00000056216�14743153644�027360� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveCopyOutOperation; {$mode objfpc}{$H+} interface uses LazFileUtils,LazUtf8,Classes, SysUtils, DCStringHashListUtf8, uLog, uGlobs, un_process, uFileSourceOperation, uFileSourceCopyOperation, uFileSourceOperationUI, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFileSource, uFile, uArchiveCopyOperation, uMultiArchiveFileSource; type { TMultiArchiveCopyOutOperation } TMultiArchiveCopyOutOperation = class(TArchiveCopyOutOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics FFullFilesTreeToExtract: TFiles; // source files including all files/dirs in subdirectories // Options FPassword: String; FExtractWithoutPath: Boolean; {en Creates neccessary paths before extracting files from archive. @param(Files List of files/directories to extract (relative to archive root).) @param(sDestPath Destination path where the files will be extracted.) @param(CurrentArchiveDir Path inside the archive from where the files will be extracted.) @param(CreatedPaths This list will be filled with absolute paths to directories that were created, together with their attributes.)} procedure CreateDirs(const theFiles: TFiles; sDestPath: String; CurrentArchiveDir: String; var CreatedPaths: TStringHashListUtf8); {en Sets attributes for directories. @param(Paths The list of absolute paths, which attributes are to be set. Each list item's data field must be a pointer to TMultiArchiveFile, from where the attributes are retrieved.} function SetDirsAttributes(const Paths: TStringHashListUtf8): Boolean; function DoFileExists(aFile: TFile; const AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; procedure ShowError(sMessage: String; logOptions: TLogOptions = []); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); procedure CheckForErrors(const SourceName, TargetName: String; ExitStatus: LongInt); protected FCurrentFile: TFile; FCurrentTargetFilePath: String; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); protected FExProcess: TExProcess; FTempFile: String; FErrorLevel: LongInt; procedure OnReadLn(str: string); procedure OnQueryString(str: string); procedure UpdateProgress(SourceName, TargetName: String; IncSize: Int64); procedure FileSourceOperationStateChangedNotify(Operation: TFileSourceOperation; AState: TFileSourceOperationState); public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property Password: String read FPassword write FPassword; property ExtractWithoutPath: Boolean read FExtractWithoutPath write FExtractWithoutPath; end; implementation uses LCLProc, FileUtil, uOSUtils, DCOSUtils, DCStrUtils, uMultiArc, fMultiArchiveCopyOperationOptions, uMultiArchiveUtil, uFileProcs, uLng, DCDateTimeUtils, DCBasicTypes, uShowMsg, uFileSystemUtil; constructor TMultiArchiveCopyOutOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FMultiArchiveFileSource := aSourceFileSource as IMultiArchiveFileSource; FPassword:= FMultiArchiveFileSource.Password; FFullFilesTreeToExtract:= nil; FFileExistsOption := fsoofeNone; FExtractWithoutPath:= False; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; with FStatistics do begin DoneBytes := -1; DoneFiles := -1; RemainingTime := -1; CurrentFileDoneBytes := -1; UpdateStatistics(FStatistics); end; end; destructor TMultiArchiveCopyOutOperation.Destroy; begin FreeAndNil(FFullFilesTreeToExtract); inherited Destroy; end; procedure TMultiArchiveCopyOutOperation.Initialize; var Index: Integer; ACount: Integer; AFileName: String; ArcFileList: TList; begin FExProcess:= TExProcess.Create(EmptyStr); FExProcess.OnReadLn:= @OnReadLn; FExProcess.OnOperationProgress:= @CheckOperationState; FTempFile:= GetTempName(GetTempFolder); with FMultiArchiveFileSource.MultiArcItem do if Length(FPasswordQuery) <> 0 then begin FExProcess.QueryString:= UTF8ToConsole(FPasswordQuery); FExProcess.OnQueryString:= @OnQueryString; end; if efSmartExtract in ExtractFlags then begin ACount:= 0; ArcFileList := FMultiArchiveFileSource.ArchiveFileList.Clone; try for Index := 0 to ArcFileList.Count - 1 do begin AFileName := PathDelim + TArchiveItem(ArcFileList[Index]).FileName; if IsInPath(PathDelim, AFileName, False, False) then begin Inc(ACount); if (ACount > 1) then begin FTargetPath := FTargetPath + ExtractOnlyFileName(FMultiArchiveFileSource.ArchiveFileName) + PathDelim; Break; end; end; end; finally ArcFileList.Free; end; end; AddStateChangedListener([fsosStarting, fsosPausing, fsosStopping], @FileSourceOperationStateChangedNotify); if FExtractMask = '' then FExtractMask := '*'; // extract all selected files/folders with FMultiArchiveFileSource do FillAndCount(FExtractMask, SourceFiles, True, FFullFilesTreeToExtract, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; procedure TMultiArchiveCopyOutOperation.MainExecute; var TargetFileName, SourcePath, sTempDir: String; CreatedPaths: TStringHashListUtf8 = nil; I: Integer; aFile: TFile; MultiArcItem: TMultiArcItem; sReadyCommand, sCommandLine: String; FilesToExtract: TFiles = nil; begin MultiArcItem := FMultiArchiveFileSource.MultiArcItem; try // Archive current path SourcePath:= ExcludeFrontPathDelimiter(SourceFiles.Path); // Check ExtractWithoutPath option if FExtractWithoutPath then sCommandLine:= MultiArcItem.FExtractWithoutPath else begin // Create needed directories. CreatedPaths := TStringHashListUtf8.Create(True); CreateDirs(FFullFilesTreeToExtract, TargetPath, SourcePath, CreatedPaths); sCommandLine:= MultiArcItem.FExtract; end; // Get maximum acceptable command errorlevel FErrorLevel:= ExtractErrorLevel(sCommandLine); if Pos('%F', sCommandLine) <> 0 then // extract file by file begin FStatistics.DoneBytes:= 0; for I:= 0 to FFullFilesTreeToExtract.Count - 1 do begin CheckOperationState; aFile:= FFullFilesTreeToExtract[I]; // Now check if the file is to be extracted. if (not aFile.AttributesProperty.IsDirectory) then // Omit directories (we handle them ourselves). begin // Check ExtractWithoutPath option if FExtractWithoutPath then TargetFileName := TargetPath + aFile.Name else TargetFileName := TargetPath + ExtractDirLevel(SourcePath, aFile.FullPath); // Check existence of target file if (DoFileExists(aFile, TargetFileName) <> fsoofeOverwrite) then Continue; // Get target directory sTempDir:= ExtractFileDirEx(TargetFileName); UpdateProgress(aFile.FullPath, TargetFileName, 0); sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, sCommandLine, FMultiArchiveFileSource.ArchiveFileName, nil, aFile.FullPath, TargetPath, FTempFile, FPassword ); OnReadLn(sReadyCommand); // Set target directory as archiver current directory FExProcess.Process.CurrentDirectory:= sTempDir; FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; UpdateProgress(aFile.FullPath, TargetFileName, aFile.Size); // Check for errors. CheckForErrors(aFile.FullPath, TargetFileName, FExProcess.ExitStatus); end; end // for end else // extract whole file list begin sTempDir:= TargetPath; // directory where files will be unpacked // if extract from not root directory and with path if (SourceFiles.Path <> PathDelim) and (FExtractWithoutPath = False) then begin sTempDir:= GetTempName(TargetPath); mbCreateDir(sTempDir); end; // Check existence of target files FilesToExtract:= TFiles.Create(FFullFilesTreeToExtract.Path); for I:= 0 to FFullFilesTreeToExtract.Count - 1 do begin aFile:= FFullFilesTreeToExtract[I]; if FExtractWithoutPath then TargetFileName := TargetPath + aFile.Name else TargetFileName := TargetPath + ExtractDirLevel(SourcePath, aFile.FullPath); if (DoFileExists(aFile, TargetFileName) = fsoofeOverwrite) then FilesToExtract.Add(aFile.Clone); end; if FilesToExtract.Count = 0 then Exit; with FStatistics do begin if FilesToExtract.Count = 1 then begin FStatistics.CurrentFileFrom:= FilesToExtract[0].FullPath; FStatistics.CurrentFileTo:= TargetFileName; end else begin FStatistics.CurrentFileFrom:= SourceFiles.Path; FStatistics.CurrentFileTo:= TargetPath; end; UpdateStatistics(FStatistics); end; sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, sCommandLine, FMultiArchiveFileSource.ArchiveFileName, FilesToExtract, EmptyStr, TargetPath, FTempFile, FPassword ); OnReadLn(sReadyCommand); // Set target directory as archiver current directory FExProcess.Process.CurrentDirectory:= sTempDir; FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; // Check for errors. CheckForErrors(FMultiArchiveFileSource.ArchiveFileName, EmptyStr, FExProcess.ExitStatus); // if extract from not root directory and with path if (SourceFiles.Path <> PathDelim) and (FExtractWithoutPath = False) then begin FStatistics.DoneBytes:= 0; // move files to real target directory for I:= 0 to FilesToExtract.Count - 1 do begin aFile:= FilesToExtract[I]; if not aFile.AttributesProperty.IsDirectory then begin TargetFileName := TargetPath + ExtractDirLevel(SourcePath, aFile.FullPath); UpdateProgress(aFile.FullPath, TargetFileName, 0); mbRenameFile(sTempDir + PathDelim + aFile.FullPath, TargetFileName); UpdateProgress(aFile.FullPath, TargetFileName, aFile.Size); end end; DelTree(sTempDir); end; end; if (FExtractWithoutPath = False) then SetDirsAttributes(CreatedPaths); finally FreeAndNil(CreatedPaths); FreeAndNil(FilesToExtract); end; end; procedure TMultiArchiveCopyOutOperation.Finalize; begin FreeAndNil(FExProcess); with FMultiArchiveFileSource.MultiArcItem do if not FDebug then mbDeleteFile(FTempFile); end; procedure TMultiArchiveCopyOutOperation.CreateDirs( const theFiles: TFiles; sDestPath: String; CurrentArchiveDir: String; var CreatedPaths: TStringHashListUtf8); var // List of paths that we know must be created. PathsToCreate: TStringHashListUtf8; // List of possible directories to create with their attributes. // This hash list is created to speed up searches for attributes in archive file list. DirsAttributes: TStringHashListUtf8; i: Integer; CurrentFileName: String; aFile: TFile; Directories: TStringList; PathIndex: Integer; ListIndex: Integer; TargetDir: String; begin { First, collect all the paths that need to be created and their attributes. } PathsToCreate := TStringHashListUtf8.Create(True); DirsAttributes := TStringHashListUtf8.Create(True); for I := 0 to theFiles.Count - 1 do begin aFile := theFiles[I]; if aFile.AttributesProperty.IsDirectory then begin CurrentFileName := ExtractDirLevel(CurrentArchiveDir, aFile.FullPath); // Save this directory and a pointer to its entry. DirsAttributes.Add(CurrentFileName, aFile); // Paths in PathsToCreate list must end with path delimiter. CurrentFileName := IncludeTrailingPathDelimiter(CurrentFileName); if PathsToCreate.Find(CurrentFileName) < 0 then PathsToCreate.Add(CurrentFileName); end else begin CurrentFileName := ExtractDirLevel(CurrentArchiveDir, aFile.Path); // If CurrentFileName is empty now then it was a file in current archive // directory, therefore we don't have to create any paths for it. if Length(CurrentFileName) > 0 then if PathsToCreate.Find(CurrentFileName) < 0 then PathsToCreate.Add(CurrentFileName); end; end; { Second, create paths and save which paths were created and their attributes. } Directories := TStringList.Create; try sDestPath := IncludeTrailingPathDelimiter(sDestPath); // Create path to destination directory (we don't have attributes for that). mbForceDirectory(sDestPath); CreatedPaths.Clear; for PathIndex := 0 to PathsToCreate.Count - 1 do begin Directories.Clear; // Create also all parent directories of the path to create. // This adds directories to list in order from the outer to inner ones, // for example: dir, dir/dir2, dir/dir2/dir3. if GetDirs(PathsToCreate.List[PathIndex]^.Key, Directories) <> -1 then try for i := 0 to Directories.Count - 1 do begin TargetDir := sDestPath + Directories.Strings[i]; if (CreatedPaths.Find(TargetDir) = -1) and (not DirPathExists(TargetDir)) then begin if mbForceDirectory(TargetDir) = False then begin // Error, cannot create directory. Break; // Don't try to create subdirectories. end else begin // Retrieve attributes for this directory, if they are stored. ListIndex := DirsAttributes.Find(Directories.Strings[i]); if ListIndex <> -1 then aFile := TFile(DirsAttributes.List[ListIndex]^.Data) else aFile := nil; CreatedPaths.Add(TargetDir, aFile); end; end; end; except end; end; finally FreeAndNil(PathsToCreate); FreeAndNil(DirsAttributes); FreeAndNil(Directories); end; end; function TMultiArchiveCopyOutOperation.SetDirsAttributes(const Paths: TStringHashListUtf8): Boolean; var PathIndex: Integer; TargetDir: String; aFile: TFile; Time: TFileTime; begin Result := True; for PathIndex := 0 to Paths.Count - 1 do begin // Get attributes. aFile := TFile(Paths.List[PathIndex]^.Data); if Assigned(aFile) then begin TargetDir := Paths.List[PathIndex]^.Key; try {$IF DEFINED(MSWINDOWS)} // Restore attributes, e.g., hidden, read-only. // On Unix attributes value would have to be translated somehow. mbFileSetAttr(TargetDir, aFile.Attributes); {$ENDIF} Time:= DateTimeToFileTime(aFile.ModificationTime); // Set creation, modification time mbFileSetTime(TargetDir, Time, Time, Time); except Result := False; end; end; end; end; procedure TMultiArchiveCopyOutOperation.QuestionActionHandler( Action: TFileSourceOperationUIAction); var aFile: TFile; begin if Action = fsouaCompare then begin aFile := FCurrentFile.Clone; try aFile.FullPath := IncludeFrontPathDelimiter(aFile.FullPath); ShowCompareFilesUI(aFile, FCurrentTargetFilePath); finally aFile.Free; end; end; end; function TMultiArchiveCopyOutOperation.DoFileExists(aFile: TFile; const AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; const PossibleResponses: array[0..8] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourOverwriteLarger, fsourOverwriteAll, fsourSkipAll, fsourOverwriteSmaller, fsourOverwriteOlder, fsouaCompare, fsourCancel); var Message: String; function OverwriteOlder: TFileSourceOperationOptionFileExists; begin if aFile.ModificationTime > FileTimeToDateTime(mbFileAge(AbsoluteTargetFileName)) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteSmaller: TFileSourceOperationOptionFileExists; begin if aFile.Size > mbFileSize(AbsoluteTargetFileName) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteLarger: TFileSourceOperationOptionFileExists; begin if aFile.Size < mbFileSize(AbsoluteTargetFileName) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; begin if not mbFileExists(AbsoluteTargetFileName) then Result:= fsoofeOverwrite else case FFileExistsOption of fsoofeNone: begin Message:= FileExistsMessage(AbsoluteTargetFileName, aFile.FullPath, aFile.Size, aFile.ModificationTime); FCurrentFile := aFile; FCurrentTargetFilePath := AbsoluteTargetFileName; case AskQuestion(Message, '', PossibleResponses, fsourOverwrite, fsourSkip, @QuestionActionHandler) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourOverwriteOlder: begin FFileExistsOption := fsoofeOverwriteOlder; Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin FFileExistsOption := fsoofeOverwriteSmaller; Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin FFileExistsOption := fsoofeOverwriteLarger; Result:= OverwriteLarger; end; fsourNone, fsourCancel: RaiseAbortOperation; end; end; fsoofeOverwriteOlder: begin Result:= OverwriteOlder; end; fsoofeOverwriteSmaller: begin Result:= OverwriteSmaller; end; fsoofeOverwriteLarger: begin Result:= OverwriteLarger; end; else begin Result := FFileExistsOption; end; end; end; procedure TMultiArchiveCopyOutOperation.ShowError(sMessage: String; logOptions: TLogOptions); begin if not gSkipFileOpError then begin if AskQuestion(sMessage, '', [fsourSkip, fsourCancel], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end else begin LogMessage(sMessage, logOptions, lmtError); end; end; procedure TMultiArchiveCopyOutOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TMultiArchiveCopyOutOperation.CheckForErrors(const SourceName, TargetName: String; ExitStatus: LongInt); begin if ExitStatus > FErrorLevel then begin ShowError(Format(rsMsgLogError + rsMsgLogExtract, [FMultiArchiveFileSource.ArchiveFileName + PathDelim + SourceName + ' -> ' + TargetName + ' - Exit status: ' + IntToStr(ExitStatus)]), [log_arc_op]); end // Error else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogExtract, [FMultiArchiveFileSource.ArchiveFileName + PathDelim + SourceName +' -> ' + TargetName]), [log_arc_op], lmtSuccess); end; // Success end; procedure TMultiArchiveCopyOutOperation.OnReadLn(str: string); begin with FMultiArchiveFileSource.MultiArcItem do if FOutput or FDebug then logWrite(Thread, str, lmtInfo, True, False); end; procedure TMultiArchiveCopyOutOperation.OnQueryString(str: string); var pcPassword: PAnsiChar; begin ShowInputQuery(FMultiArchiveFileSource.MultiArcItem.FDescription, rsMsgPasswordEnter, True, FPassword); pcPassword:= PAnsiChar(UTF8ToConsole(FPassword + LineEnding)); FExProcess.Process.Input.Write(pcPassword^, Length(pcPassword)); end; procedure TMultiArchiveCopyOutOperation.UpdateProgress(SourceName, TargetName: String; IncSize: Int64); begin with FStatistics do begin FStatistics.CurrentFileFrom:= SourceName; FStatistics.CurrentFileTo:= TargetName; CurrentFileDoneBytes:= IncSize; DoneBytes := DoneBytes + CurrentFileDoneBytes; UpdateStatistics(FStatistics); end; end; procedure TMultiArchiveCopyOutOperation.FileSourceOperationStateChangedNotify( Operation: TFileSourceOperation; AState: TFileSourceOperationState); begin case AState of fsosStarting: FExProcess.Process.Resume; fsosPausing: FExProcess.Process.Suspend; fsosStopping: FExProcess.Stop; end; end; class function TMultiArchiveCopyOutOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result:= TMultiArchiveCopyOperationOptionsUI; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivedeleteoperation.pas����������������������0000644�0001750�0000144�00000015623�14743153644�027115� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceDeleteOperation, uFileSource, uFileSourceOperationUI, uFile, uMultiArchiveFileSource, uGlobs, uLog, un_process; type { TMultiArchiveDeleteOperation } TMultiArchiveDeleteOperation = class(TFileSourceDeleteOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; FStatistics: TFileSourceDeleteOperationStatistics; // local copy of statistics FFullFilesTreeToDelete: TFiles; // source files including all files/dirs in subdirectories procedure ShowError(sMessage: String; logOptions: TLogOptions); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); procedure CheckForErrors(const FileName: String; ExitStatus: LongInt); protected FExProcess: TExProcess; FTempFile: String; FErrorLevel: LongInt; procedure OnReadLn(str: string); procedure UpdateProgress(SourceName: String; IncSize: Int64); procedure FileSourceOperationStateChangedNotify(Operation: TFileSourceOperation; AState: TFileSourceOperationState); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uOSUtils, DCOSUtils, uLng, uMultiArc, uMultiArchiveUtil, LCLProc; constructor TMultiArchiveDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FMultiArchiveFileSource := aTargetFileSource as IMultiArchiveFileSource; FFullFilesTreeToDelete:= nil; inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TMultiArchiveDeleteOperation.Destroy; begin FreeAndNil(FFullFilesTreeToDelete); inherited Destroy; end; procedure TMultiArchiveDeleteOperation.Initialize; begin FExProcess:= TExProcess.Create(EmptyStr); FExProcess.OnReadLn:= @OnReadLn; FExProcess.OnOperationProgress:= @CheckOperationState; FTempFile:= GetTempName(GetTempFolder); AddStateChangedListener([fsosStarting, fsosPausing, fsosStopping], @FileSourceOperationStateChangedNotify); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; with FMultiArchiveFileSource do FillAndCount('*.*', FilesToDelete, True, FFullFilesTreeToDelete, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; procedure TMultiArchiveDeleteOperation.MainExecute; var I: Integer; MultiArcItem: TMultiArcItem; aFile: TFile; sReadyCommand, sCommandLine: String; begin MultiArcItem := FMultiArchiveFileSource.MultiArcItem; sCommandLine:= MultiArcItem.FDelete; // Get maximum acceptable command errorlevel FErrorLevel:= ExtractErrorLevel(sCommandLine); if Pos('%F', sCommandLine) <> 0 then // delete file by file for I:=0 to FFullFilesTreeToDelete.Count - 1 do begin aFile:= FFullFilesTreeToDelete[I]; UpdateProgress(aFile.FullPath, 0); sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, sCommandLine, FMultiArchiveFileSource.ArchiveFileName, nil, aFile.FullPath ); OnReadLn(sReadyCommand); FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; UpdateProgress(aFile.FullPath, aFile.Size); // Check for errors. CheckForErrors(aFile.FullPath , FExProcess.ExitStatus); end else // delete whole file list begin sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, sCommandLine, FMultiArchiveFileSource.ArchiveFileName, FFullFilesTreeToDelete, EmptyStr, EmptyStr, FTempFile ); OnReadLn(sReadyCommand); FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; // Check for errors. CheckForErrors(FMultiArchiveFileSource.ArchiveFileName, FExProcess.ExitStatus); end; end; procedure TMultiArchiveDeleteOperation.Finalize; begin FreeAndNil(FExProcess); with FMultiArchiveFileSource.MultiArcItem do if not FDebug then mbDeleteFile(FTempFile); end; procedure TMultiArchiveDeleteOperation.ShowError(sMessage: String; logOptions: TLogOptions); begin if not gSkipFileOpError then begin if AskQuestion(sMessage, '', [fsourSkip, fsourCancel], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end else begin LogMessage(sMessage, logOptions, lmtError); end; end; procedure TMultiArchiveDeleteOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TMultiArchiveDeleteOperation.OnReadLn(str: string); begin with FMultiArchiveFileSource.MultiArcItem do if FOutput or FDebug then logWrite(Thread, str, lmtInfo, True, False); end; procedure TMultiArchiveDeleteOperation.CheckForErrors(const FileName: String; ExitStatus: LongInt); begin if ExitStatus > FErrorLevel then begin ShowError(Format(rsMsgLogError + rsMsgLogDelete, [FileName + ' - Exit status: ' + IntToStr(ExitStatus)]), [log_arc_op]); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogDelete, [FileName]), [log_arc_op], lmtSuccess); end; end; procedure TMultiArchiveDeleteOperation.UpdateProgress(SourceName: String; IncSize: Int64); begin with FStatistics do begin FStatistics.CurrentFile:= SourceName; DoneBytes := DoneBytes + IncSize; UpdateStatistics(FStatistics); end; end; procedure TMultiArchiveDeleteOperation.FileSourceOperationStateChangedNotify( Operation: TFileSourceOperation; AState: TFileSourceOperationState); begin case AState of fsosStarting: FExProcess.Process.Resume; fsosPausing: FExProcess.Process.Suspend; fsosStopping: FExProcess.Stop; end; end; end. �������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivedynamicparser.pas������������������������0000644�0001750�0000144�00000030120�14743153644�026560� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Multi archive dynamic parser Copyright (C) 2016-2021 Alexander Koblov (alexx2000@mail.ru) Based on TFTPList (http://www.ararat.cz/synapse) Copyright (C) 1999-2011, Lukas Gebauer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Lukas Gebauer nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } unit uMultiArchiveDynamicParser; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uMultiArc, uMultiArchiveParser; type { TMultiArchiveDynamicParser } TMultiArchiveDynamicParser = class(TMultiArchiveParser) protected FLines: TStringList; FMasks: TStringList; FUnparsedLines: TStringList; BlockSize: string; PackBlockSize: string; FileName: string; FileExt: string; Day: string; Month: string; ThreeMonth: string; Year: string; Hours: string; HoursModif: Ansistring; Minutes: string; Seconds: string; Size: Ansistring; PackSize: AnsiString; Attributes: Ansistring; procedure ClearStore; virtual; function CheckValues: Boolean; virtual; procedure FillRecord(const Value: TArchiveItem); virtual; function ParseByMask(Value, NextValue, Mask: ansistring): Integer; virtual; public constructor Create(AMultiArcItem: TMultiArcItem); override; destructor Destroy; override; procedure Prepare; override; procedure ParseLines; override; procedure AddLine(const Str: String); override; class function NeedDynamic(Format: TStringList): Boolean; property Masks: TStringList read FMasks; property UnparsedLines: TStringList read FUnparsedLines; property OnGetArchiveItem: TOnGetArchiveItem write FOnGetArchiveItem; end; implementation uses DCDateTimeUtils, DCStrUtils; { TMultiArchiveDynamicParser } constructor TMultiArchiveDynamicParser.Create(AMultiArcItem: TMultiArcItem); begin inherited Create(AMultiArcItem); FLines := TStringList.Create; FMasks := AMultiArcItem.FFormat; FUnparsedLines := TStringList.Create; end; destructor TMultiArchiveDynamicParser.Destroy; begin Prepare; FLines.Free; FUnparsedLines.Free; inherited Destroy; end; procedure TMultiArchiveDynamicParser.Prepare; begin FLines.Clear; FUnparsedLines.Clear; end; procedure TMultiArchiveDynamicParser.ClearStore; begin BlockSize := ''; PackBlockSize := ''; FileName := ''; FileExt := ''; Day := ''; Month := ''; ThreeMonth := ''; Year := ''; Hours := ''; HoursModif := ''; Minutes := ''; Seconds := ''; Size := ''; PackSize := ''; Attributes := ''; end; function TMultiArchiveDynamicParser.ParseByMask(Value, NextValue, Mask: ansistring): Integer; var Ivalue, IMask: integer; MaskC, LastMaskC: AnsiChar; c: AnsiChar; s: string; begin ClearStore; Result := 0; if Value = '' then Exit; if Mask = '' then Exit; Ivalue := 1; IMask := 1; Result := 1; LastMaskC := ' '; while Imask <= Length(mask) do begin if (Mask[Imask] <> '+') and (Ivalue > Length(Value)) then begin Result := 0; Exit; end; MaskC := Mask[Imask]; if Ivalue > Length(Value) then Exit; c := Value[Ivalue]; case MaskC of 'n': FileName := FileName + c; 'e': FileExt := FileExt + c; 'd': Day := Day + c; 't': Month := Month + c; 'T': ThreeMonth := ThreeMonth + c; 'y': Year := Year + c; 'h': Hours := Hours + c; 'H': HoursModif := HoursModif + c; 'm': Minutes := Minutes + c; 's': Seconds := Seconds + c; 'z': Size := Size + c; 'p': PackSize := PackSize + c; 'a': Attributes := Attributes + c; 'x': if c <> ' ' then begin Result := 0; Exit; end; '+': begin s := ''; if LastMaskC in ['n', 'e'] then begin if Imask = Length(Mask) then s := Copy(Value, IValue, Maxint) else while IValue <= Length(Value) do begin if Value[Ivalue] = ' ' then break; s := s + Value[Ivalue]; Inc(Ivalue); end; case LastMaskC of 'n': FileName := FileName + s; 'e': FileExt := FileExt + s; end; end else begin while IValue <= Length(Value) do begin if not(Value[Ivalue] in ['0'..'9']) then break; s := s + Value[Ivalue]; Inc(Ivalue); end; case LastMaskC of 'z': Size := Size + s; 'p': PackSize := PackSize + s; end; end; Dec(IValue); end; '*': begin while IValue <= Length(Value) do begin if Value[Ivalue] = ' ' then break; Inc(Ivalue); end; while IValue <= Length(Value) do begin if Value[Ivalue] <> ' ' then break; Inc(Ivalue); end; Dec(IValue); end; '$': begin while IValue <= Length(Value) do begin if not(Value[Ivalue] in [' ', #9]) then break; Inc(Ivalue); end; Dec(IValue); end; '=': begin s := ''; case LastmaskC of 'z', 'p': begin while Imask <= Length(Mask) do begin if not(Mask[Imask] in ['0'..'9']) then break; s := s + Mask[Imask]; Inc(Imask); end; Dec(Imask); case LastMaskC of 'z': BlockSize := s; 'p': PackBlockSize := s; end; end; end; end; '\': begin Value := NextValue; IValue := 0; Result := 2; end; '?': ; end; Inc(Ivalue); Inc(Imask); LastMaskC := MaskC; end; end; function TMultiArchiveDynamicParser.CheckValues: Boolean; var x, n: integer; begin Result := false; if (FileName = '') then Exit; if Day <> '' then begin Day := Trim(Day); x := StrToIntDef(day, -1); if (x < 1) or (x > 31) then Exit; end; if Month <> '' then begin Month := Trim(Month); x := StrToIntDef(Month, -1); if (x < 1) or (x > 12) then Exit; end; if Hours <> '' then begin Hours := Trim(Hours); x := StrToIntDef(Hours, -1); if (x < 0) or (x > 24) then Exit; end; if HoursModif <> '' then begin if not (HoursModif[1] in ['a', 'A', 'p', 'P']) then Exit; end; if Minutes <> '' then begin Minutes := Trim(Minutes); x := StrToIntDef(Minutes, -1); if (x < 0) or (x > 59) then Exit; end; if Seconds <> '' then begin Seconds := Trim(Seconds); x := StrToIntDef(Seconds, -1); if (x < 0) or (x > 59) then Exit; end; if Size <> '' then begin Size := Trim(Size); for n := 1 to Length(Size) do if not (Size[n] in ['0'..'9']) then Exit; end; if ThreeMonth <> '' then begin x := MonthToNumberDef(ThreeMonth, 0); if (x = 0) then Exit; end; if Year <> '' then begin Year := Trim(Year); x := StrToIntDef(Year, -1); if (x = -1) then Exit; if Length(Year) = 4 then begin if not((x > 1900) and (x < 2100)) then Exit; end else if Length(Year) = 2 then begin if not((x >= 0) and (x <= 99)) then Exit; end else if Length(Year) = 3 then begin if not((x >= 100) and (x <= 110)) then Exit; end else Exit; end; Result := True; end; procedure TMultiArchiveDynamicParser.FillRecord(const Value: TArchiveItem); var X: Int64; begin Value.FileName:= FGetFileName(FileName); Value.FileExt:= FGetFileName(FileExt); Value.PackSize:= StrToInt64Def(PackSize, -1); Value.UnpSize:= StrToInt64Def(Size, -1); Value.Year:= YearShortToLong(StrToIntDef(Year, 0)); Value.Month:= StrToIntDef(Month, 1); Value.Day:= StrToIntDef(Day, 1); Value.Hour:= StrToIntDef(Hours, 0); Value.Minute:= StrToIntDef(Minutes, 0); Value.Second:= StrToIntDef(Seconds, 0); Value.Attributes:= FGetFileAttr(Attributes); if ThreeMonth <> '' then begin Value.Month:= MonthToNumberDef(ThreeMonth, 1); end; if HoursModif <> '' then begin Value.Hour:= TwelveToTwentyFour(Value.Hour, HoursModif); end; if BlockSize <> '' then begin X := StrToIntDef(BlockSize, 1); Value.UnpSize := X * Value.UnpSize; end; if PackBlockSize <> '' then begin X := StrToIntDef(PackBlockSize, 1); Value.PackSize := X * Value.PackSize; end; end; procedure TMultiArchiveDynamicParser.ParseLines; var n, m: Integer; S: string; x: integer; b: Boolean; begin n := 0; while n < FLines.Count do begin if n = FLines.Count - 1 then s := '' else s := FLines[n + 1]; b := False; x := 0; for m := 0 to Masks.Count - 1 do begin x := ParseByMask(FLines[n], s, Masks[m]); if x > 0 then if CheckValues then begin if Assigned(FOnGetArchiveItem) then begin FArchiveItem := TArchiveItem.create; FillRecord(FArchiveItem); UpdateFileName; FOnGetArchiveItem(FArchiveItem); end; b := True; Break; end; end; if not b then FUnparsedLines.Add(FLines[n]); Inc(n); if x > 1 then Inc(n, x - 1); end; end; procedure TMultiArchiveDynamicParser.AddLine(const Str: String); begin FLines.Add(Str); end; class function TMultiArchiveDynamicParser.NeedDynamic(Format: TStringList): Boolean; var P: Integer; Index: Integer; begin Result := False; for Index:= 0 to Format.Count - 1 do begin P:= Pos('+', Format[Index]); if (P > 0) and (P < Length(Format[Index])) then Exit(True); if ContainsOneOf(Format[Index], '$x=\') then Exit(True); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchiveexecuteoperation.pas���������������������0000644�0001750�0000144�00000003444�14743153644�027313� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uFileSourceExecuteOperation, uMultiArchiveFileSource; type { TMultiArchiveExecuteOperation } TMultiArchiveExecuteOperation = class(TFileSourceExecuteOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses fPackInfoDlg, uMasks, uGlobs; constructor TMultiArchiveExecuteOperation.Create( aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FMultiArchiveFileSource := aTargetFileSource as IMultiArchiveFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TMultiArchiveExecuteOperation.Initialize; begin end; procedure TMultiArchiveExecuteOperation.MainExecute; begin if (Verb <> 'properties') and MatchesMaskList(ExecutableFile.Name, gAutoExtractOpenMask) then FExecuteOperationResult:= fseorYourSelf else begin FExecuteOperationResult:= ShowPackInfoDlg(FMultiArchiveFileSource, ExecutableFile); end; end; procedure TMultiArchiveExecuteOperation.Finalize; begin end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivefilesource.pas���������������������������0000644�0001750�0000144�00000055077�14743153644�026101� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, contnrs, DCStringHashListUtf8, uOSUtils, uMultiArc, uFile, uFileSourceProperty, uFileSourceOperationTypes, uArchiveFileSource, uFileProperty, uFileSource, uFileSourceOperation, uMultiArchiveUtil, DCBasicTypes, uClassesEx; type { IMultiArchiveFileSource } IMultiArchiveFileSource = interface(IArchiveFileSource) ['{71BF41D3-1E40-4E84-83BB-B6D3E0DEB6FC}'] function GetPassword: String; function GetArcFileList: TThreadObjectList; function GetMultiArcItem: TMultiArcItem; function FileIsLink(ArchiveItem: TArchiveItem): Boolean; function FileIsDirectory(ArchiveItem: TArchiveItem): Boolean; procedure FillAndCount(const FileMask: String; Files: TFiles; CountDirs: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); property Password: String read GetPassword; property ArchiveFileList: TThreadObjectList read GetArcFileList; property MultiArcItem: TMultiArcItem read GetMultiArcItem; end; { TMultiArchiveFileSource } TMultiArchiveFileSource = class(TArchiveFileSource, IMultiArchiveFileSource) private FPassword: String; FOutputParser: TOutputParser; FArcFileList : TThreadObjectList; FMultiArcItem: TMultiArcItem; FAllDirsList, FExistsDirList: TStringHashListUtf8; FLinkAttribute, FDirectoryAttribute: TFileAttrs; function GetPassword: String; function GetMultiArcItem: TMultiArcItem; procedure OnGetArchiveItem(ArchiveItem: TArchiveItem); function ReadArchive(bCanYouHandleThisFile : Boolean = False): Boolean; function FileIsLink(ArchiveItem: TArchiveItem): Boolean; function FileIsDirectory(ArchiveItem: TArchiveItem): Boolean; function GetArcFileList: TThreadObjectList; protected function GetPacker: String; override; function GetSupportedFileProperties: TFilePropertiesTypes; override; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; procedure DoReload(const PathsToReload: TPathsArray); override; public procedure FillAndCount(const FileMask: String; Files: TFiles; CountDirs: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); public constructor Create(anArchiveFileSource: IFileSource; anArchiveFileName: String; aMultiArcItem: TMultiArcItem); reintroduce; destructor Destroy; override; class function CreateFile(const APath: String; ArchiveItem: TArchiveItem; FormMode: Integer): TFile; overload; // Retrieve operations permitted on the source. = capabilities? function GetOperationsTypes: TFileSourceOperationTypes; override; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; override; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; class function CreateByArchiveSign(anArchiveFileSource: IFileSource; anArchiveFileName: String): IMultiArchiveFileSource; class function CreateByArchiveType(anArchiveFileSource: IFileSource; anArchiveFileName, anArchiveType: String): IMultiArchiveFileSource; class function CreateByArchiveName(anArchiveFileSource: IFileSource; anArchiveFileName: String): IMultiArchiveFileSource; {en Returns @true if there is an addon registered for the archive name. } class function CheckAddonByName(const anArchiveFileName: String): Boolean; property Password: String read GetPassword; property ArchiveFileList: TThreadObjectList read GetArcFileList; property MultiArcItem: TMultiArcItem read GetMultiArcItem; end; implementation uses uDebug, uGlobs, DCFileAttributes, DCOSUtils, DCStrUtils, DCDateTimeUtils, FileUtil, uMasks, uMultiArchiveListOperation, uMultiArchiveCopyInOperation, uMultiArchiveCopyOutOperation, uMultiArchiveDeleteOperation, uMultiArchiveExecuteOperation, uMultiArchiveTestArchiveOperation, uMultiArchiveCalcStatisticsOperation ; class function TMultiArchiveFileSource.CreateByArchiveSign(anArchiveFileSource: IFileSource; anArchiveFileName: String): IMultiArchiveFileSource; var I: Integer; aMultiArcItem: TMultiArcItem; begin Result := nil; // Check if there is a registered addon for the archive file by content. for I := 0 to gMultiArcList.Count - 1 do begin aMultiArcItem:= gMultiArcList.Items[I]; if (aMultiArcItem.FEnabled) and (aMultiArcItem.FID <> EmptyStr) then begin if aMultiArcItem.CanYouHandleThisFile(anArchiveFileName) then begin Result := TMultiArchiveFileSource.Create(anArchiveFileSource, anArchiveFileName, aMultiArcItem); DCDebug('Found registered addon "' + aMultiArcItem.FDescription + '" for archive ' + anArchiveFileName); Break; end; end; end; end; class function TMultiArchiveFileSource.CreateByArchiveType( anArchiveFileSource: IFileSource; anArchiveFileName, anArchiveType: String): IMultiArchiveFileSource; var I: Integer; aMultiArcItem: TMultiArcItem; begin Result := nil; // Check if there is a registered addon for the extension of the archive file name. for I := 0 to gMultiArcList.Count - 1 do begin aMultiArcItem:= gMultiArcList.Items[I]; if (aMultiArcItem.FEnabled) and MatchesMaskList(anArchiveType, aMultiArcItem.FExtension, ',') then begin Result := TMultiArchiveFileSource.Create(anArchiveFileSource, anArchiveFileName, aMultiArcItem); DCDebug('Found registered addon "' + aMultiArcItem.FDescription + '" for archive ' + anArchiveFileName); Break; end; end; end; class function TMultiArchiveFileSource.CreateByArchiveName( anArchiveFileSource: IFileSource; anArchiveFileName: String): IMultiArchiveFileSource; var I: Integer; aMultiArcItem: TMultiArcItem; begin Result := nil; // Check if there is a registered addon for the archive file name. for I := 0 to gMultiArcList.Count - 1 do begin aMultiArcItem:= gMultiArcList.Items[I]; if (aMultiArcItem.FEnabled) and aMultiArcItem.Matches(anArchiveFileName) then begin Result := TMultiArchiveFileSource.Create(anArchiveFileSource, anArchiveFileName, aMultiArcItem); DCDebug('Found registered addon "' + aMultiArcItem.FDescription + '" for archive ' + anArchiveFileName); Break; end; end; end; class function TMultiArchiveFileSource.CheckAddonByName(const anArchiveFileName: String): Boolean; var I: Integer; aMultiArcItem: TMultiArcItem; begin for I := 0 to gMultiArcList.Count - 1 do begin aMultiArcItem:= gMultiArcList.Items[I]; if (aMultiArcItem.FEnabled) and aMultiArcItem.Matches(anArchiveFileName) then Exit(True); end; Result := False; end; // ---------------------------------------------------------------------------- constructor TMultiArchiveFileSource.Create(anArchiveFileSource: IFileSource; anArchiveFileName: String; aMultiArcItem: TMultiArcItem); begin inherited Create(anArchiveFileSource, anArchiveFileName); FMultiArcItem := aMultiArcItem; FArcFileList := TThreadObjectList.Create; FOutputParser := TOutputParser.Create(aMultiArcItem, anArchiveFileName); FOutputParser.OnGetArchiveItem:= @OnGetArchiveItem; FOperationsClasses[fsoCopyIn] := TMultiArchiveCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TMultiArchiveCopyOutOperation.GetOperationClass; with FMultiArcItem do begin if (FFormMode and MAF_UNIX_ATTR) <> 0 then begin FLinkAttribute:= S_IFLNK; FDirectoryAttribute:= S_IFDIR; end else if (FFormMode and MAF_WIN_ATTR) <> 0 then begin FLinkAttribute:= FILE_ATTRIBUTE_REPARSE_POINT; FDirectoryAttribute:= FILE_ATTRIBUTE_DIRECTORY; end else begin FLinkAttribute:= faSymLink; FDirectoryAttribute:= faFolder; end; end; ReadArchive; end; destructor TMultiArchiveFileSource.Destroy; begin inherited Destroy; if Assigned(FArcFileList) then FreeAndNil(FArcFileList); end; class function TMultiArchiveFileSource.CreateFile(const APath: String; ArchiveItem: TArchiveItem; FormMode: Integer): TFile; begin Result := TFile.Create(APath); with Result do begin SizeProperty := TFileSizeProperty.Create(ArchiveItem.UnpSize); SizeProperty.IsValid := (ArchiveItem.UnpSize >= 0); CompressedSizeProperty := TFileCompressedSizeProperty.Create(ArchiveItem.PackSize); CompressedSizeProperty.IsValid := (ArchiveItem.PackSize >= 0); if (FormMode and MAF_UNIX_ATTR) <> 0 then AttributesProperty := TUnixFileAttributesProperty.Create(ArchiveItem.Attributes) else if (FormMode and MAF_WIN_ATTR) <> 0 then AttributesProperty := TNtfsFileAttributesProperty.Create(ArchiveItem.Attributes) else begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes(ArchiveItem.Attributes); end; if AttributesProperty.IsDirectory then begin if not SizeProperty.IsValid then begin SizeProperty.IsValid := True; SizeProperty.Value := FOLDER_SIZE_UNKN; end; if not CompressedSizeProperty.IsValid then begin CompressedSizeProperty.IsValid := True; CompressedSizeProperty.Value := FOLDER_SIZE_UNKN; end; end; ModificationTimeProperty := TFileModificationDateTimeProperty.Create(0); try with ArchiveItem do ModificationTime := EncodeDate(Year, Month, Day) + EncodeTime(Hour, Minute, Second, 0); except on EConvertError do ModificationTimeProperty.IsValid:= False; end; if AttributesProperty.IsLink and (Length(ArchiveItem.FileLink) > 0) then begin LinkProperty := TFileLinkProperty.Create; LinkProperty.LinkTo := ArchiveItem.FileLink; end; // Set name after assigning Attributes property, because it is used to get extension. Name := ExtractFileNameEx(ArchiveItem.FileName); if ArchiveItem.FileExt <> EmptyStr then Name:= Name + '.' + ArchiveItem.FileExt; end; end; function TMultiArchiveFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoExecute]; if (FMultiArcItem.FList <> EmptyStr) or (mafFileNameList in FMultiArcItem.FFlags) then Result := Result + [fsoList, fsoCalcStatistics]; if FMultiArcItem.FAdd <> EmptyStr then Result := Result + [fsoCopyIn]; if FMultiArcItem.FExtract <> EmptyStr then Result := Result + [fsoCopyOut]; if FMultiArcItem.FDelete <> EmptyStr then Result := Result + [fsoDelete]; if FMultiArcItem.FTest <> EmptyStr then Result := Result + [fsoTestArchive]; end; function TMultiArchiveFileSource.GetProperties: TFileSourceProperties; begin Result := []; end; function TMultiArchiveFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpLink]; end; function TMultiArchiveFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; var I: Integer; AFileList: TList; ArchiveItem: TArchiveItem; begin Result := False; if Length(NewDir) > 0 then begin if NewDir = GetRootDir() then Exit(True); NewDir := IncludeTrailingPathDelimiter(NewDir); AFileList:= FArcFileList.LockList; try // Search file list for a directory with name NewDir. for I := 0 to AFileList.Count - 1 do begin ArchiveItem := TArchiveItem(AFileList.Items[I]); if FileIsDirectory(ArchiveItem) and (Length(ArchiveItem.FileName) > 0) then begin if NewDir = IncludeTrailingPathDelimiter(GetRootDir() + ArchiveItem.FileName) then Exit(True); end; end; finally FArcFileList.UnlockList; end; end; end; function TMultiArchiveFileSource.GetArcFileList: TThreadObjectList; begin Result := FArcFileList; end; function TMultiArchiveFileSource.GetMultiArcItem: TMultiArcItem; begin Result := FMultiArcItem; end; function TMultiArchiveFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TMultiArchiveListOperation.Create(TargetFileSource, TargetPath); end; function TMultiArchiveFileSource.CreateCopyInOperation( SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TMultiArchiveCopyInOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TMultiArchiveFileSource.CreateCopyOutOperation( TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TMultiArchiveCopyOutOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TMultiArchiveFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TMultiArchiveDeleteOperation.Create(TargetFileSource, FilesToDelete); end; function TMultiArchiveFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TMultiArchiveExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; function TMultiArchiveFileSource.CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result:= TMultiArchiveTestArchiveOperation.Create(SourceFileSource, theSourceFiles); end; function TMultiArchiveFileSource.CreateCalcStatisticsOperation( var theFiles: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TMultiArchiveCalcStatisticsOperation.Create(TargetFileSource, theFiles); end; procedure TMultiArchiveFileSource.OnGetArchiveItem(ArchiveItem: TArchiveItem); procedure CollectDirs(Path: PAnsiChar; var DirsList: TStringHashListUtf8); var I : Integer; Dir : AnsiString; begin // Scan from the second char from the end, to the second char from the beginning. for I := strlen(Path) - 2 downto 1 do begin if Path[I] = PathDelim then begin SetString(Dir, Path, I); if DirsList.Find(Dir) = -1 then // Add directory and continue scanning for parent directories. DirsList.Add(Dir) else // This directory is already in the list and we assume // that all parent directories are too. Exit; end end; end; var NameLength: Integer; begin // Some archivers end directories with path delimiter. // And not set directory attribute. So delete path // delimiter if present and add directory attribute. NameLength := Length(ArchiveItem.FileName); if (NameLength > 0) and (ArchiveItem.FileName[NameLength] = PathDelim) then begin Delete(ArchiveItem.FileName, NameLength, 1); ArchiveItem.Attributes := ArchiveItem.Attributes or FDirectoryAttribute; end; //**************************************************************************** // Workaround for archivers that don't give a list of folders // or the list does not include all of the folders. if FileIsDirectory(ArchiveItem) then begin // Collect directories that the plugin supplies. if (FExistsDirList.Find(ArchiveItem.FileName) < 0) then FExistsDirList.Add(ArchiveItem.FileName); end; // Collect all directories. CollectDirs(PAnsiChar(ArchiveItem.FileName), FAllDirsList); //**************************************************************************** FArcFileList.Add(ArchiveItem); end; function TMultiArchiveFileSource.GetPacker: String; begin Result:= FMultiArcItem.FPacker; end; function TMultiArchiveFileSource.GetPassword: String; begin Result:= FPassword; end; function TMultiArchiveFileSource.ReadArchive(bCanYouHandleThisFile : Boolean = False): Boolean; var I : Integer; AFileList: TList; ArchiveTime: TSystemTime; ArchiveItem: TArchiveItem; begin if not mbFileAccess(ArchiveFileName, fmOpenRead) then begin Result := False; Exit; end; { if bCanYouHandleThisFile and (Assigned(WcxModule.CanYouHandleThisFile) or Assigned(WcxModule.CanYouHandleThisFileW)) then begin Result := WcxModule.WcxCanYouHandleThisFile(ArchiveFileName); if not Result then Exit; end; } { Get File List } AFileList:= FArcFileList.LockList; try AFileList.Clear; // Get archive file time DateTimeToSystemTime(FileTimeToDateTime(mbFileAge(ArchiveFileName)), ArchiveTime); if mafFileNameList in FMultiArcItem.FFlags then begin ArchiveItem:= TArchiveItem.Create; ArchiveItem.FileName := ExtractOnlyFileName(ArchiveFileName); ArchiveItem.Year:= ArchiveTime.Year; ArchiveItem.Month:= ArchiveTime.Month; ArchiveItem.Day:= ArchiveTime.Day; ArchiveItem.Hour:= ArchiveTime.Hour; ArchiveItem.Minute:= ArchiveTime.Minute; ArchiveItem.Second:= ArchiveTime.Second; ArchiveItem.Attributes := mbFileGetAttr(ArchiveFileName); AFileList.Add(ArchiveItem); Exit(True); end; FExistsDirList := TStringHashListUtf8.Create(True); FAllDirsList := TStringHashListUtf8.Create(True); try DCDebug('Get File List'); FOutputParser.Password:= FPassword; FOutputParser.Prepare; FOutputParser.Execute; FPassword:= FOutputParser.Password; (* if archiver does not give a list of folders *) for I := 0 to FAllDirsList.Count - 1 do begin // Add only those directories that were not supplied by the plugin. if FExistsDirList.Find(FAllDirsList.List[I]^.Key) < 0 then begin ArchiveItem:= TArchiveItem.Create; try ArchiveItem.FileName := FAllDirsList.List[I]^.Key; ArchiveItem.Year:= ArchiveTime.Year; ArchiveItem.Month:= ArchiveTime.Month; ArchiveItem.Day:= ArchiveTime.Day; ArchiveItem.Hour:= ArchiveTime.Hour; ArchiveItem.Minute:= ArchiveTime.Minute; ArchiveItem.Second:= ArchiveTime.Second; ArchiveItem.Attributes := FDirectoryAttribute; AFileList.Add(ArchiveItem); except FreeAndNil(ArchiveItem); end; end; end; finally FreeAndNil(FAllDirsList); FreeAndNil(FExistsDirList); end; finally FArcFileList.UnlockList; end; Result := True; end; function TMultiArchiveFileSource.FileIsLink(ArchiveItem: TArchiveItem): Boolean; begin Result:= (ArchiveItem.Attributes and FLinkAttribute <> 0); end; function TMultiArchiveFileSource.FileIsDirectory(ArchiveItem: TArchiveItem): Boolean; begin Result:= (ArchiveItem.Attributes and FDirectoryAttribute <> 0); end; procedure TMultiArchiveFileSource.DoReload(const PathsToReload: TPathsArray); begin ReadArchive; end; procedure TMultiArchiveFileSource.FillAndCount(const FileMask: String; Files: TFiles; CountDirs: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); var aFile: TFile; I, J: Integer; AFileList: TList; sFileName: String; MaskList: TMaskList; ArchiveItem: TArchiveItem; begin FilesSize:= 0; FilesCount:= 0; NewFiles:= TFiles.Create(Files.Path); if (FileMask = '*.*') or (FileMask = '*') then MaskList:= nil else begin MaskList:= TMaskList.Create(FileMask); end; AFileList:= ArchiveFileList.LockList; try for I := 0 to AFileList.Count - 1 do begin ArchiveItem := TArchiveItem(AFileList.Items[I]); sFileName:= PathDelim + ArchiveItem.FileName; // And name matches file mask if ((MaskList = nil) or MaskList.Matches(ExtractFileNameEx(ArchiveItem.FileName))) then begin for J := 0 to Files.Count - 1 do begin aFile := Files[J]; if (aFile.FullPath = sFileName) or // Item in the list is a file, only compare names. (aFile.AttributesProperty.IsDirectory and IsInPath(aFile.FullPath, sFileName, True, False)) then // Check if 'FileName' is in this directory or any of its subdirectories. begin if FileIsDirectory(ArchiveItem) then begin if CountDirs then Inc(FilesCount); end else begin Inc(FilesCount); Inc(FilesSize, aFile.Size); end; aFile:= TMultiArchiveFileSource.CreateFile(ExtractFilePathEx(ArchiveItem.FileName), ArchiveItem, FMultiArcItem.FFormMode); aFile.FullPath:= ExcludeFrontPathDelimiter(aFile.FullPath); NewFiles.Add(aFile); end; end; // for J end; end; // for I finally ArchiveFileList.UnlockList; end; MaskList.Free; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivelistoperation.pas������������������������0000644�0001750�0000144�00000003347�14743153644�026626� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uMultiArchiveFileSource, uFileSource; type TMultiArchiveListOperation = class(TFileSourceListOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses LCLProc, uOSUtils, DCStrUtils, uMultiArc, uFile; constructor TMultiArchiveListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FMultiArchiveFileSource := aFileSource as IMultiArchiveFileSource; inherited Create(aFileSource, aPath); end; procedure TMultiArchiveListOperation.MainExecute; var I : Integer; CurrFileName : String; // Current file name ArcFileList: TList; aFile: TFile; begin FFiles.Clear; if FMultiArchiveFileSource.Changed then begin FMultiArchiveFileSource.Reload(Path); end; if not FileSource.IsPathAtRoot(Path) then begin aFile := TMultiArchiveFileSource.CreateFile(Path); aFile.Name := '..'; aFile.Attributes := faFolder; FFiles.Add(AFile); end; ArcFileList := FMultiArchiveFileSource.ArchiveFileList.Clone; try for I := 0 to ArcFileList.Count - 1 do begin CheckOperationState; CurrFileName := PathDelim + TArchiveItem(ArcFileList.Items[I]).FileName; if not IsInPath(Path, CurrFileName, False, False) then Continue; with FMultiArchiveFileSource.MultiArcItem do aFile := TMultiArchiveFileSource.CreateFile(Path, TArchiveItem(ArcFileList.Items[I]), FFormMode); FFiles.Add(AFile); end; finally ArcFileList.Free; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchiveparser.pas�������������������������������0000644�0001750�0000144�00000020273�14743153644�025223� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveParser; {$mode objfpc}{$H+} {.$DEFINE DEBUG} interface uses Classes, SysUtils, DCBasicTypes, uMultiArc; type TGetFileAttr = function(sAttr: String): TFileAttrs; TGetFileName = function(const Str: String): String; TOnGetArchiveItem = procedure(ArchiveItem: TArchiveItem) of object; TKeyPos = record Index, Start, Count: longint; end; type { TMultiArchiveParser } TMultiArchiveParser = class protected FArchiveItem: TArchiveItem; FGetFileAttr: TGetFileAttr; FGetFileName: TGetFileName; FMultiArcItem: TMultiArcItem; FOnGetArchiveItem: TOnGetArchiveItem; private procedure SplitFileName; protected procedure UpdateFileName; public constructor Create(AMultiArcItem: TMultiArcItem); virtual; procedure Prepare; virtual; abstract; procedure ParseLines; virtual; abstract; procedure AddLine(const Str: String); virtual; abstract; property OnGetArchiveItem: TOnGetArchiveItem write FOnGetArchiveItem; end; { TMultiArchiveStaticParser } TMultiArchiveStaticParser = class(TMultiArchiveParser) private FExtPos, FNamePos, FUnpSizePos, FPackSizePos, FYearPos, FMonthPos, FMonthNamePos, FDayPos, FHourPos, FHourModifierPos, FMinPos, FSecPos, FAttrPos: TKeyPos; private FFormatIndex: Integer; private function FixPosition(const Str: String; Key: TKeyPos): LongInt; function KeyPos(Key: char; out Position: TKeyPos): boolean; function GetKeyValue(const str: String; Key: TKeyPos): String; public procedure Prepare; override; procedure ParseLines; override; procedure AddLine(const Str: String); override; end; implementation uses LazUTF8, StrUtils, DCFileAttributes, DCDateTimeUtils; function GetUnixFileName(const Str: String): String; var I: Integer; begin Result:= Str; for I:= 1 to Length(Str) do if Result[I] = '/' then Result[I]:= PathDelim; end; function GetWinFileName(const Str: String): String; var I: Integer; begin Result:= Str; for I:= 1 to Length(Str) do if Result[I] = '\' then Result[I]:= PathDelim; end; function GetDefFileName(const Str: String): String; begin Result:= Str; end; { TMultiArchiveParser } procedure TMultiArchiveParser.SplitFileName; var Index: Integer; begin Index:= Pos(' -> ', FArchiveItem.FileName); if Index > 0 then begin FArchiveItem.FileLink:= Copy(FArchiveItem.FileName, Index + 4, MaxInt); FArchiveItem.FileName:= Copy(FArchiveItem.FileName, 1, Index - 1); end end; constructor TMultiArchiveParser.Create(AMultiArcItem: TMultiArcItem); begin FMultiArcItem:= AMultiArcItem; with FMultiArcItem do begin // Setup function to process file attributes if (FFormMode and MAF_UNIX_ATTR) <> 0 then FGetFileAttr:= @UnixStrToFileAttr else if (FFormMode and MAF_WIN_ATTR) <> 0 then FGetFileAttr:= @WinStrToFileAttr else FGetFileAttr:= @StrToFileAttr; // Setup function to process file name if ((FFormMode and MAF_UNIX_PATH) <> 0) and (PathDelim <> '/') then FGetFileName:= @GetUnixFileName else if ((FFormMode and MAF_WIN_PATH) <> 0) and (PathDelim <> '\') then FGetFileName:= @GetWinFileName else FGetFileName:= @GetDefFileName; end; end; procedure TMultiArchiveParser.UpdateFileName; begin with FArchiveItem do begin if ((Attributes and S_IFLNK) <> 0) or ((Attributes and FILE_ATTRIBUTE_REPARSE_POINT) <> 0) then SplitFileName; if Length(FileExt) > 0 then begin FileName := FileName + ExtensionSeparator + FileExt; end; end; end; { TMultiArchiveStaticParser } function TMultiArchiveStaticParser.FixPosition(const Str: String; Key: TKeyPos): LongInt; var I, K, U, C: LongInt; Format: String; begin I:= 0; U:= 0; Result:= Key.Start; Format:= FMultiArcItem.FFormat[Key.Index]; repeat C:= 0; I:= PosEx('*', Format, I + 1); if (I = 0) or (I >= Result) then Exit; if (I > 0) then begin I:= I + U; K:= I; while (K <= Length(Str)) and (Str[K] <> #32) do begin Inc(C); Inc(K); end; if C > 0 then U:= C - 1 else U:= 0; Result:= Result + U; end; until I = 0; end; function TMultiArchiveStaticParser.KeyPos(Key: char; out Position: TKeyPos): boolean; var I, L: Integer; Format: String; begin Result := False; Position.Index := -1; for I := 0 to FMultiArcItem.FFormat.Count - 1 do with FMultiArcItem do begin Format := FFormat[I]; Position.Start := Pos(Key, Format); if Position.Start = 0 then Continue; L := Length(Format); if (Position.Start = L - 1) and (Format[L] = '+') then Position.Count := MaxInt else begin Position.Count := Position.Start; while ((Position.Count <= L) and (Format[Position.Count] = Key)) do Inc(Position.Count); Position.Count := Position.Count - Position.Start; end; Position.Index := I; {$IFDEF DEBUG} DCDebug('Key: ' + Key, ' Format: ' + IntToStr(I), ' Start: ' + IntToStr(Position.Start), ' Count: ' + IntToStr(Position.Count)); {$ENDIF} Result := True; Break; end; end; function TMultiArchiveStaticParser.GetKeyValue(const str: String; Key: TKeyPos): String; begin Result:= Copy(str, FixPosition(str, Key), Key.Count); end; procedure TMultiArchiveStaticParser.Prepare; begin // get positions of all properties KeyPos('e', FExtPos); // file ext KeyPos('n', FNamePos); // file name KeyPos('z', FUnpSizePos); // unpacked size KeyPos('p', FPackSizePos); // packed size KeyPos('y', FYearPos); KeyPos('t', FMonthPos); KeyPos('T', FMonthNamePos); KeyPos('d', FDayPos); KeyPos('h', FHourPos); KeyPos('H', FHourModifierPos); KeyPos('m', FMinPos); KeyPos('s', FSecPos); KeyPos('a', FAttrPos); end; procedure TMultiArchiveStaticParser.ParseLines; begin end; procedure TMultiArchiveStaticParser.AddLine(const Str: String); begin // if next item if FFormatIndex = 0 then begin FArchiveItem := TArchiveItem.Create; FArchiveItem.PackSize := -1; FArchiveItem.UnpSize := -1; end; // get all file properties if FExtPos.Index = FFormatIndex then FArchiveItem.FileExt := FGetFileName(Trim(GetKeyValue(str, FExtPos))); if FNamePos.Index = FFormatIndex then FArchiveItem.FileName := FGetFileName(Trim(GetKeyValue(str, FNamePos))); if FUnpSizePos.Index = FFormatIndex then FArchiveItem.UnpSize := StrToInt64Def(Trim(GetKeyValue(str, FUnpSizePos)), -1); if FPackSizePos.Index = FFormatIndex then FArchiveItem.PackSize := StrToInt64Def(Trim(GetKeyValue(str, FPackSizePos)), -1); if FYearPos.Index = FFormatIndex then FArchiveItem.Year := YearShortToLong(StrToIntDef(Trim(GetKeyValue(str, FYearPos)), 0)); if FMonthPos.Index = FFormatIndex then FArchiveItem.Month := StrToIntDef(Trim(GetKeyValue(str, FMonthPos)), 0); if FMonthNamePos.Index = FFormatIndex then FArchiveItem.Month := MonthToNumberDef(GetKeyValue(str, FMonthNamePos), 0); if FDayPos.Index = FFormatIndex then FArchiveItem.Day := StrToIntDef(Trim(GetKeyValue(str, FDayPos)), 0); if FHourPos.Index = FFormatIndex then FArchiveItem.Hour := StrToIntDef(Trim(GetKeyValue(str, FHourPos)), 0); if FHourModifierPos.Index = FFormatIndex then FArchiveItem.Hour := TwelveToTwentyFour(FArchiveItem.Hour, GetKeyValue(str, FHourModifierPos)); if FMinPos.Index = FFormatIndex then FArchiveItem.Minute := StrToIntDef(Trim(GetKeyValue(str, FMinPos)), 0); if FSecPos.Index = FFormatIndex then FArchiveItem.Second := StrToIntDef(Trim(GetKeyValue(str, FSecPos)), 0); if FAttrPos.Index = FFormatIndex then FArchiveItem.Attributes := FGetFileAttr(GetKeyValue(str, FAttrPos)); FFormatIndex := FFormatIndex + 1; if FFormatIndex >= FMultiArcItem.FFormat.Count then begin FFormatIndex := 0; UpdateFileName; {$IFDEF DEBUG} DCDebug('FileName: ', FArchiveItem.FileName); DCDebug('Size: ', IntToStr(FArchiveItem.UnpSize)); DCDebug('Pack size: ', IntToStr(FArchiveItem.PackSize)); DCDebug('Attributes: ', IntToStr(FArchiveItem.Attributes)); DCDebug('-------------------------------------'); {$ENDIF} if Assigned(FOnGetArchiveItem) then FOnGetArchiveItem(FArchiveItem); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchivetestarchiveoperation.pas�����������������0000644�0001750�0000144�00000017511�14743153644�030172� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Archive test operation for mutiarchive manager Copyright (C) 2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uMultiArchiveTestArchiveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceTestArchiveOperation, uFileSource, uFileSourceOperationUI, uFile, uMultiArchiveFileSource, uGlobs, uLog, un_process; type { TMultiArchiveTestArchiveOperation } TMultiArchiveTestArchiveOperation = class(TFileSourceTestArchiveOperation) private FMultiArchiveFileSource: IMultiArchiveFileSource; FStatistics: TFileSourceTestArchiveOperationStatistics; // local copy of statistics FFullFilesTreeToTest: TFiles; // source files including all files/dirs in subdirectories procedure ShowError(sMessage: String; logOptions: TLogOptions); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); procedure CheckForErrors(const FileName: String; ExitStatus: LongInt); protected FExProcess: TExProcess; FTempFile: String; FErrorLevel: LongInt; procedure OnReadLn(str: string); procedure UpdateProgress(SourceName: String; IncSize: Int64); procedure FileSourceOperationStateChangedNotify({%H-}Operation: TFileSourceOperation; AState: TFileSourceOperationState); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uOSUtils, DCOSUtils, uLng, uMultiArc, uMultiArchiveUtil, LCLProc; constructor TMultiArchiveTestArchiveOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FMultiArchiveFileSource := aTargetFileSource as IMultiArchiveFileSource; FFullFilesTreeToTest:= nil; inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TMultiArchiveTestArchiveOperation.Destroy; begin FreeAndNil(FFullFilesTreeToTest); inherited Destroy; end; procedure TMultiArchiveTestArchiveOperation.Initialize; begin FExProcess:= TExProcess.Create(EmptyStr); FExProcess.OnReadLn:= @OnReadLn; FExProcess.OnOperationProgress:= @CheckOperationState; FTempFile:= GetTempName(GetTempFolder); AddStateChangedListener([fsosStarting, fsosPausing, fsosStopping], @FileSourceOperationStateChangedNotify); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FStatistics.ArchiveFile:= FMultiArchiveFileSource.ArchiveFileName; with FMultiArchiveFileSource do FillAndCount('*.*', SourceFiles, True, FFullFilesTreeToTest, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; procedure TMultiArchiveTestArchiveOperation.MainExecute; var I: Integer; MultiArcItem: TMultiArcItem; aFile: TFile; sReadyCommand, sCommandLine: String; begin MultiArcItem := FMultiArchiveFileSource.MultiArcItem; sCommandLine:= MultiArcItem.FTest; // Get maximum acceptable command errorlevel FErrorLevel:= ExtractErrorLevel(sCommandLine); if Pos('%F', sCommandLine) <> 0 then // test file by file for I:=0 to FFullFilesTreeToTest.Count - 1 do begin aFile:= FFullFilesTreeToTest[I]; UpdateProgress(aFile.FullPath, 0); sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, sCommandLine, FMultiArchiveFileSource.ArchiveFileName, nil, aFile.FullPath ); OnReadLn(sReadyCommand); FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; UpdateProgress(aFile.FullPath, aFile.Size); // Check for errors. CheckForErrors(aFile.FullPath , FExProcess.ExitStatus); end else // test whole file list begin sReadyCommand:= FormatArchiverCommand( MultiArcItem.FArchiver, sCommandLine, FMultiArchiveFileSource.ArchiveFileName, FFullFilesTreeToTest, EmptyStr, EmptyStr, FTempFile ); OnReadLn(sReadyCommand); FExProcess.SetCmdLine(sReadyCommand); FExProcess.Execute; // Check for errors. CheckForErrors(FMultiArchiveFileSource.ArchiveFileName, FExProcess.ExitStatus); end; end; procedure TMultiArchiveTestArchiveOperation.Finalize; begin FreeAndNil(FExProcess); with FMultiArchiveFileSource.MultiArcItem do if not FDebug then mbDeleteFile(FTempFile); end; procedure TMultiArchiveTestArchiveOperation.ShowError(sMessage: String; logOptions: TLogOptions); begin if not gSkipFileOpError then begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end else begin LogMessage(sMessage, logOptions, lmtError); end; end; procedure TMultiArchiveTestArchiveOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TMultiArchiveTestArchiveOperation.OnReadLn(str: string); begin with FMultiArchiveFileSource.MultiArcItem do if FOutput or FDebug then logWrite(Thread, str, lmtInfo, True, False); end; procedure TMultiArchiveTestArchiveOperation.CheckForErrors(const FileName: String; ExitStatus: LongInt); begin if (ExitStatus > FErrorLevel) then begin ShowError(Format(rsMsgLogError + rsMsgLogTest, [FileName + ' - ' + rsMsgExitStatusCode + ' ' + IntToStr(ExitStatus)]), [log_arc_op]); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogTest, [FileName]), [log_arc_op], lmtSuccess); end; end; procedure TMultiArchiveTestArchiveOperation.UpdateProgress(SourceName: String; IncSize: Int64); begin with FStatistics do begin FStatistics.CurrentFile:= SourceName; DoneBytes := DoneBytes + IncSize; UpdateStatistics(FStatistics); end; end; procedure TMultiArchiveTestArchiveOperation.FileSourceOperationStateChangedNotify (Operation: TFileSourceOperation; AState: TFileSourceOperationState); begin case AState of fsosStarting: FExProcess.Process.Resume; fsosPausing: FExProcess.Process.Suspend; fsosStopping: FExProcess.Stop; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multiarchive/umultiarchiveutil.pas���������������������������������0000644�0001750�0000144�00000034200�14743153644�024677� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiArchiveUtil; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCConvertEncoding, uMultiArc, un_process, uFile, uMultiArchiveParser; type { TOutputParser } TOutputParser = class FPassword: String; FExProcess: TExProcess; FMultiArcItem: TMultiArcItem; FParser: TMultiArchiveParser; FConvertEncoding: function (const Source: String): RawByteString; private FArchiveName: String; FStartParsing: boolean; function PrepareCommand: String; procedure SetOnGetArchiveItem(AValue: TOnGetArchiveItem); protected procedure OnProcessExit; procedure OnReadLn(str: string); procedure OnQueryString(str: string); function CheckOut(const SubStr, Str: string): boolean; public constructor Create(aMultiArcItem: TMultiArcItem; const anArchiveName: String); destructor Destroy; override; procedure Prepare; procedure Execute; property Password: String read FPassword write FPassword; property OnGetArchiveItem: TOnGetArchiveItem write SetOnGetArchiveItem; end; function ExtractErrorLevel(var Command: String): LongInt; function FormatArchiverCommand(const Archiver, sCmd, anArchiveName: String; aFiles: TFiles = nil; sFileName: String = ''; aDestPath: String = ''; sTempFile: String = ''; sPassword: String = ''; sVolumeSize: String = ''; sCustomParams: String = ''): string; implementation uses LazUTF8, DCClassesUtf8, uDCUtils, DCOSUtils, uOSUtils, uDebug, uShowMsg, uLng, uMultiArchiveDynamicParser; function Utf8ToUtf8(const Source: String): RawByteString; begin Result:= Source; end; { TOutputParser } function TOutputParser.PrepareCommand: String; var Index: Integer; begin Result:= FMultiArcItem.FList; Index:= Pos('%O', Result); FConvertEncoding:= @DCOSUtils.ConsoleToUTF8; if (Index > 0) and (Index + 2 <= Length(Result)) then begin case (Result[Index + 2]) of 'A': FConvertEncoding:= CeSysToUtf8; 'U': FConvertEncoding:= @Utf8ToUtf8; end; Delete(Result, Index, 3); end; end; procedure TOutputParser.SetOnGetArchiveItem(AValue: TOnGetArchiveItem); begin FParser.OnGetArchiveItem:= AValue; end; procedure TOutputParser.OnProcessExit; begin FParser.ParseLines; end; procedure TOutputParser.OnReadLn(str: string); begin str:= FConvertEncoding(str); if FMultiArcItem.FDebug then DCDebug(str); if (str = EmptyStr) or (Trim(str) = EmptyStr) then Exit; // skip empty lines if not FStartParsing then FStartParsing := (FMultiArcItem.FStart = EmptyStr); // if not defined start line if FStartParsing and (FMultiArcItem.FEnd <> EmptyStr) and CheckOut(FMultiArcItem.FEnd, Str) then begin FExProcess.Stop; Exit; end; if FStartParsing then begin FParser.AddLine(Str); end else begin FStartParsing := (FMultiArcItem.FStart = EmptyStr) or CheckOut(FMultiArcItem.FStart, Str); end; end; procedure TOutputParser.OnQueryString(str: string); var pcPassword: PAnsiChar; begin if not ShowInputQuery(FMultiArcItem.FDescription, rsMsgPasswordEnter, True, FPassword) then FExProcess.Stop else begin pcPassword:= PAnsiChar(UTF8ToConsole(FPassword + LineEnding)); FExProcess.Process.Input.Write(pcPassword^, Length(pcPassword)); end; end; function TOutputParser.CheckOut(const SubStr, Str: string): boolean; begin if SubStr[1] = '^' then Result := (Pos(PChar(SubStr) + 1, Str) = 1) else Result := (Pos(SubStr, Str) > 0); end; constructor TOutputParser.Create(aMultiArcItem: TMultiArcItem; const anArchiveName: String); begin FArchiveName := anArchiveName; FMultiArcItem := aMultiArcItem; if TMultiArchiveDynamicParser.NeedDynamic(FMultiArcItem.FFormat) then FParser:= TMultiArchiveDynamicParser.Create(FMultiArcItem) else begin FParser:= TMultiArchiveStaticParser.Create(FMultiArcItem); end; DCDebug(FParser.ClassName, '.Create'); end; destructor TOutputParser.Destroy; begin FreeAndNil(FParser); FreeAndNil(FExProcess); inherited Destroy; end; procedure TOutputParser.Execute; begin FParser.Prepare; // execute archiver FExProcess.Execute; end; procedure TOutputParser.Prepare; var sCommandLine: String; begin FStartParsing:= False; FreeAndNil(FExProcess); sCommandLine:= PrepareCommand; sCommandLine:= FormatArchiverCommand(FMultiArcItem.FArchiver, sCommandLine, FArchiveName, nil, '', '','', FPassword); if FMultiArcItem.FDebug then DCDebug(sCommandLine); FExProcess := TExProcess.Create(sCommandLine); FExProcess.OnReadLn := @OnReadLn; FExProcess.OnProcessExit:= @OnProcessExit; FExProcess.Process.CurrentDirectory:= ExtractFileDir(FArchiveName); if Length(FMultiArcItem.FPasswordQuery) <> 0 then begin FExProcess.QueryString:= UTF8ToConsole(FMultiArcItem.FPasswordQuery); FExProcess.OnQueryString:= @OnQueryString; end; end; function ExtractErrorLevel(var Command: String): LongInt; var I, J: Integer; sErrorLevel: String; begin Result:= 0; I:= Pos('%E', Command); if I > 0 then begin J:= I + 2; while (J <= Length(Command)) and (Command[J] in ['0'..'9']) do Inc(J); sErrorLevel:= Copy(Command, I + 2, J - I - 2); Delete(Command, I, J - I); Result:= StrToIntDef(sErrorLevel, 0); end; end; function FormatArchiverCommand(const Archiver, sCmd, anArchiveName: String; aFiles: TFiles; sFileName: String; aDestPath: String; sTempFile: String; sPassword: String; sVolumeSize: String; sCustomParams: String): string; type TFunctType = (ftNone, ftArchiverLongName, ftArchiverShortName, ftArchiveLongName, ftArchiveShortName, ftFileListLongName, ftFileListShortName, ftFileName, ftTargetArchiveDir, ftVolumeSize, ftPassword, ftCustomParams); TStatePos = (spNone, spPercent, spFunction, spComplete); TFuncModifiers = set of (fmOnlyFiles, fmQuoteWithSpaces, fmQuoteAny, fmNameOnly, fmPathOnly, fmUTF8, fmAnsi); TState = record pos: TStatePos; functStartIndex, bracketStartIndex: integer; funct: TFunctType; FuncModifiers: TFuncModifiers; closeBracket: Boolean; end; var index: integer; state: Tstate; sOutput: string = ''; parseStartIndex: integer; function BuildName(const sFileName: String): String; begin Result := sFileName; if fmNameOnly in state.FuncModifiers then Result := ExtractFileName(Result); if fmPathOnly in state.FuncModifiers then Result := ExtractFilePath(Result); if (fmQuoteWithSpaces in state.FuncModifiers) and (Pos(#32, Result) <> 0) then Result := '"' + Result + '"'; if (fmQuoteAny in state.FuncModifiers) then Result := '"' + Result + '"'; end; function BuildFileList(bShort: boolean): String; var I: integer; FileName: String; FileList: TStringListEx; begin if not Assigned(aFiles) then Exit(EmptyStr); Result := sTempFile; FileList := TStringListEx.Create; for I := 0 to aFiles.Count - 1 do begin if aFiles[I].IsDirectory and (fmOnlyFiles in state.FuncModifiers) then Continue; if bShort then FileName := BuildName(mbFileNameToSysEnc(aFiles[I].FullPath)) else begin FileName := BuildName(aFiles[I].FullPath); end; if (fmAnsi in state.FuncModifiers) then FileName := CeUtf8ToSys(FileName) else if not (fmUTF8 in state.FuncModifiers) then begin FileName := UTF8ToConsole(FileName); end; FileList.Add(FileName); end; try FileList.SaveToFile(Result); except Result := EmptyStr; end; FileList.Free; end; function BuildOutput: String; begin case state.funct of ftArchiverLongName: // TProcess arguments must be enclosed with double quotes and not escaped. Result := '"' + mbExpandFileName(Archiver) + '"'; ftArchiverShortName: // TProcess arguments must be enclosed with double quotes and not escaped. Result := '"' + mbFileNameToSysEnc(mbExpandFileName(Archiver)) + '"'; ftArchiveLongName: Result := BuildName(anArchiveName); ftArchiveShortName: Result := BuildName(mbFileNameToSysEnc(anArchiveName)); ftFileListLongName: Result := BuildFileList(False); ftFileListShortName: Result := BuildFileList(True); ftFileName: Result:= BuildName(sFileName); ftTargetArchiveDir: Result := BuildName(aDestPath); ftVolumeSize: Result:= sVolumeSize; ftPassword: Result:= sPassword; ftCustomParams: Result:= sCustomParams; else Exit(''); end; end; procedure ResetState(var aState: TState); begin with aState do begin pos := spNone; funct := ftNone; functStartIndex := 0; FuncModifiers := []; if closeBracket then begin closeBracket:= False; bracketStartIndex:= 0; end; end; end; procedure AddParsedText(limit: integer); begin // Copy [parseStartIndex .. limit - 1]. if limit > parseStartIndex then sOutput := sOutput + Copy(sCmd, parseStartIndex, limit - parseStartIndex); parseStartIndex := index; end; procedure AddBrackedText(limit: integer); begin // Copy [state.bracketStartIndex + 1 .. limit - 1]. if limit > state.bracketStartIndex then sOutput := sOutput + Copy(sCmd, state.bracketStartIndex + 1, limit - state.bracketStartIndex - 1); end; procedure DoFunction; var aOutput: String; begin aOutput:= BuildOutput; if (aOutput = EmptyStr) and (state.bracketStartIndex <> 0) then begin AddParsedText(state.bracketStartIndex); end else begin if (state.bracketStartIndex <> 0) then begin // add text before bracket AddParsedText(state.bracketStartIndex); //add text after bracket AddBrackedText(state.functStartIndex); end else AddParsedText(state.functStartIndex); sOutput := sOutput + aOutput; end; ResetState(state); end; begin try index := 1; parseStartIndex := index; FillByte(state, SizeOf(state), 0); ResetState(state); while index <= Length(sCmd) do begin case state.pos of spNone: case sCmd[index] of '%': begin state.pos := spPercent; state.functStartIndex := index; end; '{': begin state.bracketStartIndex := index; end; end; spPercent: case sCmd[index] of 'P': begin state.funct := ftArchiverLongName; state.pos := spFunction; end; 'p': begin state.funct := ftArchiverShortName; state.pos := spFunction; end; 'A': begin state.funct := ftArchiveLongName; state.pos := spFunction; end; 'a': begin state.funct := ftArchiveShortName; state.pos := spFunction; end; 'L': begin state.funct := ftFileListLongName; state.pos := spFunction; end; 'l': begin state.funct := ftFileListShortName; state.pos := spFunction; end; 'F': begin state.funct := ftFileName; state.pos := spFunction; end; 'R': begin state.funct := ftTargetArchiveDir; state.pos := spFunction; end; 'V': begin state.funct := ftVolumeSize; state.pos := spFunction; end; 'W': begin state.funct := ftPassword; state.pos := spFunction; end; 'S': begin state.funct := ftCustomParams; state.pos := spFunction; end; else state.pos := spFunction; end; spFunction: case sCmd[index] of 'F': begin state.FuncModifiers := state.FuncModifiers + [fmOnlyFiles]; state.pos := spFunction; end; 'Q': begin state.FuncModifiers := state.FuncModifiers + [fmQuoteWithSpaces]; state.pos := spFunction; end; 'q': begin state.FuncModifiers := state.FuncModifiers + [fmQuoteAny]; state.pos := spFunction; end; 'W': begin state.FuncModifiers := state.FuncModifiers + [fmNameOnly]; state.pos := spFunction; end; 'P': begin state.FuncModifiers := state.FuncModifiers + [fmPathOnly]; state.pos := spFunction; end; 'U': begin state.FuncModifiers := state.FuncModifiers + [fmUTF8]; state.pos := spFunction; end; 'A': begin state.FuncModifiers := state.FuncModifiers + [fmAnsi]; state.pos := spFunction; end; '}': begin state.closeBracket:= True; end else state.pos := spComplete; end; end; if state.pos <> spComplete then Inc(index) // check next character else // Process function and then check current character again after resetting state. DoFunction; end; // while // Finish current parse. if state.pos in [spFunction] then DoFunction else AddParsedText(index); Result := sOutput; finally end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multilist/���������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017746� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multilist/umultilistfilesource.pas���������������������������������0000644�0001750�0000144�00000024327�14743153644�024757� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiListFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uFileSourceProperty, uFileSourceOperation, uFileSourceOperationTypes, uFileProperty; type IMultiListFileSource = interface(IFileSource) ['{A64C591C-EBC6-4E06-89D2-9965E1A3009A}'] procedure AddList(var aFileList: TFileTree; aFileSource: IFileSource); function GetFileList: TFileTree; function GetFileSource: IFileSource; property FileList: TFileTree read GetFileList; property FileSource: IFileSource read GetFileSource; end; {en File source that generates files from file lists generated by other file sources. This virtual file source contains "links" to files from other file sources, e.g., paths to files on FileSystem file source, or paths to files within certain archive. Therefore properties of virtual file source and operations will depend on the underlying file source. It should be possible to store links to different file sources within the same virtual file source, in which case there has to be a file source associated with each file or a group of files, although presentation of such file lists should probably be different than that of a single file source. Files can be virtual (from virtual file sources). Currently can only use a single file source with a single file list. } { TMultiListFileSource } TMultiListFileSource = class(TFileSource, IMultiListFileSource) private {en File list for the file source. } FFileList: TFileTree; {en File source from which files in FileList come from. Currently only single file source is supported. } FFileSource: IFileSource; procedure FileSourceReloadEvent(const aFileSource: IFileSource; const ReloadedPaths: TPathsArray); protected function GetFileList: TFileTree; function GetFileSource: IFileSource; procedure DoReload(const PathsToReload: TPathsArray); override; public constructor Create; override; destructor Destroy; override; {en Adds a list of files associated with a file source to the storage. Only single file source supported now (adding list will overwrite previous list). @param(aFileList List of files. Class takes ownership of the pointer.) @param(aFileSource The file source from which files in aFileList are from.) } procedure AddList(var aFileList: TFileTree; aFileSource: IFileSource); virtual; function GetSupportedFileProperties: TFilePropertiesTypes; override; function GetOperationsTypes: TFileSourceOperationTypes; override; function GetProperties: TFileSourceProperties; override; function CreateDirectory(const Path: String): Boolean; override; function FileSystemEntryExists(const Path: String): Boolean; override; function GetRetrievableFileProperties: TFilePropertiesTypes; override; procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); override; function CanRetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes): Boolean; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; override; function CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override; property FileList: TFileTree read FFileList; property FileSource: IFileSource read FFileSource; end; implementation uses uMultiListListOperation; constructor TMultiListFileSource.Create; begin FFileList := nil; FFileSource := nil; inherited Create; end; destructor TMultiListFileSource.Destroy; begin if Assigned(FFileSource) then begin FFileSource.RemoveReloadEventListener(@FileSourceReloadEvent); end; inherited Destroy; FreeAndNil(FFileList); FFileSource := nil; end; procedure TMultiListFileSource.AddList(var aFileList: TFileTree; aFileSource: IFileSource); begin if Assigned(FFileList) then FreeAndNil(FFileList); FFileList := aFileList; aFileList := nil; FFileSource := aFileSource; FFileSource.AddReloadEventListener(@FileSourceReloadEvent); end; function TMultiListFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := FFileSource.GetSupportedFileProperties; end; function TMultiListFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin // Only fsoList is supported by default. // All other operations only if file source supports them. // However, this will work only for single file source. Result := [fsoList] + FFileSource.GetOperationsTypes * [fsoCopyOut, //fsoMove, fsoDelete, fsoWipe, fsoCalcChecksum, fsoCalcStatistics, fsoSetFileProperty, fsoExecute, fsoTestArchive]; end; function TMultiListFileSource.GetProperties: TFileSourceProperties; begin // Flags depend on the underlying file source. Result := FFileSource.GetProperties; end; function TMultiListFileSource.CreateDirectory(const Path: String): Boolean; begin Result:= FFileSource.CreateDirectory(Path); end; function TMultiListFileSource.FileSystemEntryExists(const Path: String): Boolean; begin Result:= FFileSource.FileSystemEntryExists(Path); end; function TMultiListFileSource.GetRetrievableFileProperties: TFilePropertiesTypes; begin Result:= FFileSource.GetRetrievableFileProperties; end; procedure TMultiListFileSource.RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); begin FFileSource.RetrieveProperties(AFile, PropertiesToSet, AVariantProperties); end; function TMultiListFileSource.CanRetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes): Boolean; begin Result:= FFileSource.CanRetrieveProperties(AFile, PropertiesToSet); end; procedure TMultiListFileSource.FileSourceReloadEvent( const aFileSource: IFileSource; const ReloadedPaths: TPathsArray); begin Reload(ReloadedPaths); end; function TMultiListFileSource.GetFileList: TFileTree; begin Result := FFileList; end; function TMultiListFileSource.GetFileSource: IFileSource; begin Result := FFileSource; end; procedure TMultiListFileSource.DoReload(const PathsToReload: TPathsArray); procedure ReloadNode(aNode: TFileTreeNode); var Index: Integer; ASubNode: TFileTreeNode; begin if Assigned(aNode) then begin for Index := aNode.SubNodesCount - 1 downto 0 do begin ASubNode:= aNode.SubNodes[Index]; if FFileSource.FileSystemEntryExists(ASubNode.TheFile.FullPath) then ReloadNode(ASubNode) else begin aNode.RemoveSubNode(Index); end; end; end; end; begin ReloadNode(FileList); end; function TMultiListFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; begin Result := TMultiListListOperation.Create(Self, TargetPath); end; function TMultiListFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin Result := FFileSource.CreateCopyOutOperation(TargetFileSource, SourceFiles, TargetPath); end; function TMultiListFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin Result := FFileSource.CreateMoveOperation(SourceFiles, TargetPath); end; function TMultiListFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; begin Result := FFileSource.CreateDeleteOperation(FilesToDelete); end; function TMultiListFileSource.CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; begin Result := FFileSource.CreateWipeOperation(FilesToWipe); end; function TMultiListFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; begin Result := FFileSource.CreateExecuteOperation(ExecutableFile, ExecutableFile.Path, Verb); end; function TMultiListFileSource.CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; begin Result := FFileSource.CreateTestArchiveOperation(theSourceFiles); end; function TMultiListFileSource.CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; begin Result := FFileSource.CreateCalcChecksumOperation(theFiles, aTargetPath, aTargetMask); end; function TMultiListFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; begin Result := FFileSource.CreateCalcStatisticsOperation(theFiles); end; function TMultiListFileSource.CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; begin Result := FFileSource.CreateSetFilePropertyOperation(theTargetFiles, theNewProperties); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/multilist/umultilistlistoperation.pas������������������������������0000644�0001750�0000144�00000003753�14743153644�025513� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMultiListListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uFileSource, uMultiListFileSource; type TMultiListListOperation = class(TFileSourceListOperation) private FFileSource: IMultiListFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses uOSUtils, DCStrUtils, uFile, uFileProperty; constructor TMultiListListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FFileSource := aFileSource as IMultiListFileSource; inherited Create(aFileSource, aPath); end; procedure TMultiListListOperation.MainExecute; var AFile: TFile; IsRootPath: Boolean; CurrentNode: TFileTreeNode; CurrentPath: String; Found: Boolean; i: Integer; begin FFiles.Clear; IsRootPath := FileSource.IsPathAtRoot(Path); CurrentNode := FFileSource.FileList; CurrentPath := FileSource.GetRootDir; // Search for files in the given path. while (Path <> CurrentPath) and IsInPath(CurrentPath, Path, True, False) do begin CheckOperationState; Found := False; for i := 0 to CurrentNode.SubNodesCount - 1 do begin if IsInPath(IncludeTrailingPathDelimiter(CurrentPath) + CurrentNode.SubNodes[i].TheFile.Name, Path, True, False) then begin CurrentNode := CurrentNode.SubNodes[i]; Found := True; Break; end; end; if not Found then Break; end; if not IsRootPath then begin AFile := FileSource.CreateFileObject(Path); AFile.Name := '..'; if fpAttributes in AFile.SupportedProperties then AFile.Attributes := faFolder; FFiles.Add(AFile); end; if Path = CurrentPath then begin for i := 0 to CurrentNode.SubNodesCount - 1 do begin CheckOperationState; AFile := CurrentNode.SubNodes[i].TheFile; FFiles.Add(AFile); end; end; end; end. ���������������������doublecmd-1.1.22/src/filesources/recyclebin/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020037� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/recyclebin/urecyclebinfilesource.pas�������������������������������0000644�0001750�0000144�00000007241�14743153644�025135� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uRecycleBinFileSource; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Dialogs, uFileSourceProperty, uVirtualFileSource, uFileProperty, uFileSource, uFileSourceOperation, uFile, uFileSourceOperationTypes; type { IRecycleBinFileSource } IRecycleBinFileSource = interface(IVirtualFileSource) ['{1E598290-5E66-423C-BB55-333E293106E8}'] end; { TRecycleBinFileSource } TRecycleBinFileSource = class(TVirtualFileSource, IRecycleBinFileSource) protected function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; public class function IsSupportedPath(const Path: String): Boolean; override; class function CreateFile(const APath: String): TFile; override; class function GetMainIcon(out Path: String): Boolean; override; function GetOperationsTypes: TFileSourceOperationTypes; override; function GetSupportedFileProperties: TFilePropertiesTypes; override; function GetLocalName(var aFile: TFile): Boolean; override; function GetRootDir(sPath: String): String; override; overload; function GetProperties: TFileSourceProperties; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; end; implementation uses uRecycleBinListOperation, uLng; { TRecycleBinFileSource } function TRecycleBinFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin Result := IsPathAtRoot(NewDir); end; class function TRecycleBinFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= SameText(ExcludeTrailingBackslash(Path), PathDelim + PathDelim + PathDelim + rsVfsRecycleBin); end; class function TRecycleBinFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes; SizeProperty := TFileSizeProperty.Create; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; CreationTimeProperty := TFileCreationDateTimeProperty.Create; LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create; ChangeTimeProperty:= TFileChangeDateTimeProperty.Create; LinkProperty := TFileLinkProperty.Create; CommentProperty := TFileCommentProperty.Create; end; end; class function TRecycleBinFileSource.GetMainIcon(out Path: String): Boolean; begin Result:= True; Path:= '%SystemRoot%\System32\shell32.dll,31'; end; function TRecycleBinFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoList]; end; function TRecycleBinFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpSize, fpAttributes, fpModificationTime, fpCreationTime, fpLastAccessTime, fpChangeTime, uFileProperty.fpLink, fpComment ]; end; function TRecycleBinFileSource.GetLocalName(var aFile: TFile): Boolean; begin Result:= True; aFile.FullPath:= aFile.LinkProperty.LinkTo; end; function TRecycleBinFileSource.GetRootDir(sPath: String): String; begin Result:= PathDelim + PathDelim + PathDelim + rsVfsRecycleBin + PathDelim; end; function TRecycleBinFileSource.GetProperties: TFileSourceProperties; begin Result := [fspDirectAccess, fspVirtual, fspLinksToLocalFiles]; end; function TRecycleBinFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TRecycleBinListOperation.Create(TargetFileSource, TargetPath); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/recyclebin/urecyclebinlistoperation.pas����������������������������0000644�0001750�0000144�00000005423�14743153644�025671� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uRecycleBinListOperation; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, uFileSystemListOperation, uRecycleBinFileSource, uFileSource; type { TRecycleBinListOperation } TRecycleBinListOperation = class(TFileSystemListOperation) public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses Windows, ShlObj, ComObj, JwaShlGuid, Variants, DCOSUtils, DCDateTimeUtils, ActiveX, uFile, uShellFolder, uShlObjAdditional, uShowMsg; const SID_DISPLACED = '{9B174B33-40FF-11d2-A27E-00C04FC30871}'; SCID_OriginalLocation: TSHColumnID = ( fmtid: SID_DISPLACED; pid: PID_DISPLACED_FROM ); SCID_DateDeleted: TSHColumnID = ( fmtid: SID_DISPLACED; pid: PID_DISPLACED_DATE ); { TRecycleBinListOperation } constructor TRecycleBinListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); inherited Create(aFileSource, aPath); end; procedure TRecycleBinListOperation.MainExecute; var AFile: TFile; NumIDs: LongWord = 0; AFolder: IShellFolder2; EnumIDList: IEnumIDList; Attr: TFileAttributeData; DesktopFolder: IShellFolder; PIDL, TrashPIDL: PItemIDList; begin FFiles.Clear; try OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(0, CSIDL_BITBUCKET, 0, 0, {%H-}TrashPIDL)); try OleCheckUTF8(DesktopFolder.BindToObject(TrashPIDL, nil, IID_IShellFolder2, Pointer(AFolder))); OleCheckUTF8(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumIDList)); while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try CheckOperationState; aFile:= TRecycleBinFileSource.CreateFile(Path); AFile.FullPath:= GetDisplayName(AFolder, PIDL, SHGDN_NORMAL); AFile.LinkProperty.LinkTo:= GetDisplayName(AFolder, PIDL, SHGDN_FORPARSING); if mbFileGetAttr(AFile.LinkProperty.LinkTo, Attr) then begin AFile.Size:= Attr.Size; AFile.Attributes:= Attr.Attr; AFile.CreationTime:= WinFileTimeToDateTime(Attr.PlatformTime); AFile.LastAccessTime:= WinFileTimeToDateTime(Attr.LastAccessTime); AFile.ModificationTime:= WinFileTimeToDateTime(Attr.LastWriteTime); AFile.CommentProperty.Value:= GetDetails(AFolder, PIDL, SCID_OriginalLocation); AFile.ChangeTime:= VariantTimeToDateTime(VarToDateTime(GetDetails(AFolder, PIDL, SCID_DateDeleted))); end; FFiles.Add(AFile); finally CoTaskMemFree(PIDL); end; finally CoTaskMemFree(TrashPIDL); end; except on E: Exception do msgError(Thread, E.Message); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/searchresult/������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020424� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/searchresult/usearchresultfilesource.pas���������������������������0000644�0001750�0000144�00000004016�14743153644�026104� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uSearchResultFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uMultiListFileSource, uFileSourceOperation, uFileSourceProperty; type ISearchResultFileSource = interface(IMultiListFileSource) ['{5076D4C2-3AB8-4029-9318-0AF115F7FDDD}'] end; {en File source for search results. } { TSearchResultFileSource } TSearchResultFileSource = class(TMultiListFileSource, ISearchResultFileSource) public function GetRootDir(sPath : String): String; override; function GetProperties: TFileSourceProperties; override; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; class function CreateFile(const APath: String): TFile; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function GetLocalName(var aFile: TFile): Boolean; override; end; implementation uses uFileSystemFileSource, uSearchResultListOperation, uLng; function TSearchResultFileSource.GetRootDir(sPath: String): String; begin Result:= PathDelim + PathDelim + PathDelim + rsSearchResult + PathDelim; end; function TSearchResultFileSource.GetProperties: TFileSourceProperties; begin Result := inherited GetProperties - [fspNoneParent, fspListFlatView]; if (fspDirectAccess in Result) then Result+= [fspLinksToLocalFiles]; end; function TSearchResultFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin // Only Root dir allowed (for flat mode). Result := IsPathAtRoot(NewDir); end; class function TSearchResultFileSource.CreateFile(const APath: String): TFile; begin Result:= TFileSystemFileSource.CreateFile(APath); end; function TSearchResultFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; begin Result := TSearchResultListOperation.Create(Self, TargetPath); end; function TSearchResultFileSource.GetLocalName(var aFile: TFile): Boolean; begin if (fspLinksToLocalFiles in FileSource.Properties) then Result:= FileSource.GetLocalName(aFile) else Result:= True; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/searchresult/usearchresultlistoperation.pas������������������������0000644�0001750�0000144�00000002343�14743153644�026641� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uSearchResultListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uFileSource, uSearchResultFileSource; type TSearchResultListOperation = class(TFileSourceListOperation) private FFileSource: ISearchResultFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses uFile; constructor TSearchResultListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FFileSource := aFileSource as ISearchResultFileSource; inherited Create(aFileSource, aPath); FNeedsConnection := False; end; procedure TSearchResultListOperation.MainExecute; procedure AddNode(aNode: TFileTreeNode); var i: Integer; begin if Assigned(aNode) then begin for i := 0 to aNode.SubNodesCount - 1 do begin CheckOperationState; FFiles.Add(aNode.SubNodes[i].TheFile.Clone); AddNode(aNode.SubNodes[i]); end; end; end; begin FFiles.Clear; // For now "flat mode" always enabled (add all files from the tree). if FileSource.IsPathAtRoot(Path) then AddNode(FFileSource.FileList); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/�������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020223� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellcalcstatisticsoperation.pas����������������������0000644�0001750�0000144�00000007756�14743153644�027122� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Windows, ShlObj, ComObj, ActiveX, uFileSourceCalcStatisticsOperation, uFileSource, uShellFileSource, uFile, uGlobs, uLog; type TShellCalcStatisticsOperation = class(TFileSourceCalcStatisticsOperation) private FShellFileSource: IShellFileSource; FStatistics: TFileSourceCalcStatisticsOperationStatistics; procedure ProcessFile(aFile: TFile); procedure ProcessSubDirs(AParent: IShellFolder2; AObject: PItemIDList); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses uShellFileSourceUtil, uShellFolder; constructor TShellCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin FShellFileSource:= aTargetFileSource as IShellFileSource; inherited Create(aTargetFileSource, theFiles); end; destructor TShellCalcStatisticsOperation.Destroy; begin inherited Destroy; end; procedure TShellCalcStatisticsOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; end; procedure TShellCalcStatisticsOperation.MainExecute; var CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to Files.Count - 1 do begin ProcessFile(Files[CurrentFileIndex]); CheckOperationState; end; end; procedure TShellCalcStatisticsOperation.ProcessFile(aFile: TFile); var AObject: PItemIDList; AFolder: IShellFolder2; begin FStatistics.CurrentFile := aFile.FullPath; UpdateStatistics(FStatistics); if aFile.IsDirectory then begin Inc(FStatistics.Directories); if Succeeded(FShellFileSource.FindFolder(AFile.Path, AFolder)) then begin if Succeeded(FShellFileSource.FindObject(AFolder, aFile.Name, AObject)) then try ProcessSubDirs(AFolder, AObject); finally CoTaskMemFree(AObject); end; end; end else begin Inc(FStatistics.Files); Inc(FStatistics.Size, aFile.Size); if aFile.ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := aFile.ModificationTime; if aFile.ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := aFile.ModificationTime; end; UpdateStatistics(FStatistics); end; procedure TShellCalcStatisticsOperation.ProcessSubDirs(AParent: IShellFolder2; AObject: PItemIDList); var ASize: Int64; PIDL: PItemIDList; NumIDs: LongWord = 0; EnumIDList: IEnumIDList; AFolder: IShellFolder2; begin try OleCheck(AParent.BindToObject(AObject, nil, IID_IShellFolder2, Pointer(AFolder))); OleCheck(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList)); while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try if GetIsFolder(AParent, PIDL) then begin Inc(FStatistics.Directories); ProcessSubDirs(AFolder, PIDL); end else begin ASize:= GetDetails(AFolder, PIDL, SCID_FileSize); Inc(FStatistics.Size, ASize); Inc(FStatistics.Files); end; CheckOperationState; UpdateStatistics(FStatistics); finally CoTaskMemFree(PIDL); end; except on E: Exception do LogMessage(E.Message, [log_errors], lmtError); end; end; procedure TShellCalcStatisticsOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellcopyoperation.pas��������������������������������0000644�0001750�0000144�00000012444�14743153644�025045� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellCopyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Windows, ShlObj, ComObj, uFileSourceOperation, uFileSourceCopyOperation, uFileSource, uFileSourceOperationTypes, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uShellFileSource, uShellFileOperation, uShellFileSourceUtil; type { TShellCopyOperation } TShellCopyOperation = class(TFileSourceCopyOperation) protected FFileOp: IFileOperation; FTargetFolder: IShellItem; FSourceFilesTree: TItemList; FShellFileSource: IShellFileSource; FStatistics: TFileSourceCopyOperationStatistics; procedure ShowError(const sMessage: String); public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; { TShellCopyInOperation } TShellCopyInOperation = class(TShellCopyOperation) protected function GetID: TFileSourceOperationType; override; public procedure Initialize; override; end; { TShellCopyOutOperation } TShellCopyOutOperation = class(TShellCopyOperation) protected function GetID: TFileSourceOperationType; override; end; implementation uses ActiveX, DCConvertEncoding, uFileSourceOperationUI, uShlObjAdditional, uShellFolder, uGlobs, uLog; procedure TShellCopyOperation.ShowError(const sMessage: String); begin if (log_cp_mv_ln in gLogOptions) and (log_errors in gLogOptions) then begin logWrite(Thread, sMessage, lmtError); end; if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; constructor TShellCopyOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin case GetID of fsoCopy, fsoCopyOut: FShellFileSource:= aSourceFileSource as IShellFileSource; fsoCopyIn: FShellFileSource:= aTargetFileSource as IShellFileSource; end; FFileOp:= CreateComObject(CLSID_FileOperation) as IFileOperation; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); end; destructor TShellCopyOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); end; procedure TShellCopyOperation.Initialize; var Index: Integer; AObject: PItemIDList; AFolder: IShellFolder2; begin FStatistics := RetrieveStatistics; FSourceFilesTree:= TItemList.Create; try for Index := 0 to SourceFiles.Count - 1 do begin AObject:= ILClone(TFileShellProperty(SourceFiles[Index].LinkProperty).Item); FSourceFilesTree.Add(AObject); end; case GetID of fsoCopy: begin OleCheck(FShellFileSource.FindFolder(TargetPath, AFolder)); OleCheck(SHGetIDListFromObject(AFolder, AObject)); try OleCheck(SHCreateItemFromIDList(AObject, IShellItem, FTargetFolder)); finally CoTaskMemFree(AObject); end; end; fsoCopyOut: OleCheck(SHCreateItemFromParsingName(PWideChar(CeUtf8ToUtf16(TargetPath)), nil, IShellItem, FTargetFolder)); end; except on E: Exception do ShowError(E.Message); end; end; procedure TShellCopyOperation.MainExecute; var Res: HRESULT; dwCookie: DWORD; siItemArray: IShellItemArray; ASink: TFileOperationProgressSink; begin ASink:= TFileOperationProgressSink.Create(@FStatistics, @UpdateStatistics, @CheckOperationStateSafe); FFileOp.SetOperationFlags(FOF_SILENT or FOF_NOCONFIRMMKDIR); try FFileOp.Advise(ASink, @dwCookie); try OleCheck(SHCreateShellItemArrayFromIDLists(FSourceFilesTree.Count, PPItemIDList(FSourceFilesTree.List), siItemArray)); OleCheck(FFileOp.CopyItems(siItemArray, FTargetFolder)); Res:= FFileOp.PerformOperations; if Failed(Res) then begin if Res = COPYENGINE_E_USER_CANCELLED then RaiseAbortOperation else OleError(Res); end; finally FFileOp.Unadvise(dwCookie); end; except on E: EOleError do ShowError(E.Message); end; end; { TShellCopyInOperation } function TShellCopyInOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopyIn; end; procedure TShellCopyInOperation.Initialize; var aFile: TFile; Index: Integer; AObject: PItemIDList; AFolder: IShellFolder2; begin FStatistics := RetrieveStatistics; FSourceFilesTree:= TItemList.Create; try for Index := 0 to SourceFiles.Count - 1 do begin aFile := SourceFiles[Index]; AObject:= ILCreateFromPathW(PWideChar(CeUtf8ToUtf16(aFile.FullPath))); FSourceFilesTree.Add(AObject); end; OleCheck(FShellFileSource.FindFolder(TargetPath, AFolder)); OleCheck(SHGetIDListFromObject(AFolder, AObject)); OleCheck(SHCreateItemFromIDList(AObject, IShellItem, FTargetFolder)); except on E: Exception do ShowError(E.Message); end; end; { TShellCopyOutOperation } function TShellCopyOutOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopyOut; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellcreatedirectoryoperation.pas���������������������0000644�0001750�0000144�00000003044�14743153644�027257� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellCreateDirectoryOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCreateDirectoryOperation, uShellFileSource, uFileSource; type { TShellCreateDirectoryOperation } TShellCreateDirectoryOperation = class(TFileSourceCreateDirectoryOperation) private FShellFileSource: IShellFileSource; public constructor Create(aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); override; procedure MainExecute; override; end; implementation uses uFileSourceOperationUI, uGlobs, uLog, uLng; { TShellCreateDirectoryOperation } constructor TShellCreateDirectoryOperation.Create(aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); begin FShellFileSource := aTargetFileSource as IShellFileSource; inherited Create(aTargetFileSource, aCurrentPath, aDirectoryPath); end; procedure TShellCreateDirectoryOperation.MainExecute; begin if FShellFileSource.CreateDirectory(AbsolutePath) then begin if (log_dir_op in gLogOptions) and (log_success in gLogOptions) then logWrite(Thread, Format(rsMsgLogSuccess + rsMsgLogMkDir, [AbsolutePath]), lmtSuccess); end else begin if (log_dir_op in gLogOptions) and (log_errors in gLogOptions) then logWrite(Thread, Format(rsMsgLogError + rsMsgLogMkDir, [AbsolutePath]), lmtError); AskQuestion(Format(rsMsgErrForceDir, [AbsolutePath]), '', [fsourOk], fsourOk, fsourOk); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushelldeleteoperation.pas������������������������������0000644�0001750�0000144�00000005775�14743153644�025346� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Windows, ShlObj, ComObj, uFileSourceDeleteOperation, uShellFileSource, uFileSource, uShellFileOperation, uShellFileSourceUtil, uFileSourceOperationUI, uFile, uGlobs, uLog; type { TShellDeleteOperation } TShellDeleteOperation = class(TFileSourceDeleteOperation) protected FFileOp: IFileOperation; FSourceFilesTree: TItemList; FShellFileSource: IShellFileSource; FStatistics: TFileSourceDeleteOperationStatistics; procedure ShowError(const sMessage: String); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses DCOSUtils, uLng, uShellFolder, uShlObjAdditional; procedure TShellDeleteOperation.ShowError(const sMessage: String); begin if (log_errors in gLogOptions) and (log_delete in gLogOptions) then begin logWrite(Thread, sMessage, lmtError); end; if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; constructor TShellDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FShellFileSource:= aTargetFileSource as IShellFileSource; FFileOp:= CreateComObject(CLSID_FileOperation) as IFileOperation; inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TShellDeleteOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); end; procedure TShellDeleteOperation.Initialize; var Index: Integer; AObject: PItemIDList; begin FStatistics := RetrieveStatistics; FSourceFilesTree:= TItemList.Create; try for Index := 0 to FilesToDelete.Count - 1 do begin AObject:= ILClone(TFileShellProperty(FilesToDelete[Index].LinkProperty).Item); FSourceFilesTree.Add(AObject); end; except on E: Exception do ShowError(E.Message); end; end; procedure TShellDeleteOperation.MainExecute; var Res: HRESULT; dwCookie: DWORD; siItemArray: IShellItemArray; ASink: TFileOperationProgressSink; begin ASink:= TFileOperationProgressSink.Create(@FStatistics, @UpdateStatistics, @CheckOperationStateSafe); FFileOp.SetOperationFlags(FOF_SILENT or FOF_NOCONFIRMATION or FOF_NORECURSION); try FFileOp.Advise(ASink, @dwCookie); try OleCheck(SHCreateShellItemArrayFromIDLists(FSourceFilesTree.Count, PPItemIDList(FSourceFilesTree.List), siItemArray)); OleCheck(FFileOp.DeleteItems(siItemArray)); Res:= FFileOp.PerformOperations; if Failed(Res) then begin if Res = COPYENGINE_E_USER_CANCELLED then RaiseAbortOperation else OleError(Res); end; finally FFileOp.Unadvise(dwCookie); end; except on E: EOleError do ShowError(E.Message); end; end; end. ���doublecmd-1.1.22/src/filesources/shellfolder/ushellexecuteoperation.pas�����������������������������0000644�0001750�0000144�00000005140�14743153644�025530� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uShellFileSource, uFileSourceExecuteOperation; type { TShellExecuteOperation } TShellExecuteOperation = class(TFileSourceExecuteOperation) private FShellFileSource: IShellFileSource; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure MainExecute; override; end; implementation uses Windows, ComObj, ShlObj, ShellAPI, DCOSUtils, DCConvertEncoding, uShellFileSourceUtil, fMain; constructor TShellExecuteOperation.Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FShellFileSource := aTargetFileSource as IShellFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TShellExecuteOperation.MainExecute; var PIDL: PItemIDList; Menu: IContextMenu; AFolder: IShellFolder2; cmici: TCMInvokeCommandInfo; AExecInfo: TShellExecuteInfoW; begin if Verb = 'properties' then try PIDL:= TFileShellProperty(ExecutableFile.LinkProperty).Item; OleCheck(SHBindToParent(PIDL, IID_IShellFolder2, AFolder, PIDL)); OleCheck(AFolder.GetUIObjectOf(frmMain.Handle, 1, PIDL, IID_IContextMenu, nil, Menu)); if Assigned(Menu) then begin cmici:= Default(TCMInvokeCommandInfo); with cmici do begin cbSize := SizeOf(TCMInvokeCommandInfo); hwnd := frmMain.Handle; lpVerb := PAnsiChar(Verb); nShow := SW_SHOWNORMAL; end; OleCheck(Menu.InvokeCommand(cmici)); end; except FExecuteOperationResult:= fseorError; end else if FShellFileSource.IsPathAtRoot(CurrentPath) then begin FResultString:= ExecutableFile.LinkProperty.LinkTo; FExecuteOperationResult:= fseorSymLink; end else begin AExecInfo:= Default(TShellExecuteInfoW); AExecInfo.cbSize:= SizeOf(TShellExecuteInfoW); AExecInfo.lpIDList:= TFileShellProperty(ExecutableFile.LinkProperty).Item; AExecInfo.fMask:= SEE_MASK_IDLIST; if ShellExecuteExW(@AExecInfo) then FExecuteOperationResult:= fseorSuccess else begin FExecuteOperationResult:= fseorError; end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellfilesource.pas�����������������������������������0000644�0001750�0000144�00000040411�14743153644�024305� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellFileSource; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Dialogs, Windows, ShlObj, uFileSourceProperty, uDrive, uDrivesList, uVirtualFileSource, uFileProperty, uFileSource, uFileSourceOperation, uFile, uFileSourceOperationTypes; type { IShellFileSource } IShellFileSource = interface(IVirtualFileSource) ['{1E598290-5E66-423C-BB55-333E293106E8}'] function CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT; function FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT; function FindObject(const AObject: String; out AValue: PItemIDList): HRESULT; function FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT; end; { TShellFileSource } TShellFileSource = class(TVirtualFileSource, IShellFileSource) private FRootPath: String; FDrives: PItemIDList; FRootFolder: IShellFolder2; FDesktopFolder: IShellFolder; protected function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; public constructor Create; override; destructor Destroy; override; class function IsSupportedPath(const Path: String): Boolean; override; class function CreateFile(const APath: String): TFile; override; class function GetMainIcon(out Path: String): Boolean; override; class function RootName: String; class procedure ListDrives(DrivesList: TDrivesList; UpperCase: Boolean); function CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT; function FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT; function FindObject(const AObject: String; out AValue: PItemIDList): HRESULT; function FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT; function CreateDirectory(const Path: String): Boolean; override; function FileSystemEntryExists(const Path: String): Boolean; override; function GetOperationsTypes: TFileSourceOperationTypes; override; function GetSupportedFileProperties: TFilePropertiesTypes; override; function GetRootDir(sPath: String): String; override; overload; function GetProperties: TFileSourceProperties; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override; end; implementation uses ActiveX, ComObj,DCConvertEncoding, uShellFolder, uShellListOperation, uShellCopyOperation, uShellFileOperation, uShellCreateDirectoryOperation, uShellExecuteOperation, uShellSetFilePropertyOperation, uShellFileSourceUtil, uShellDeleteOperation, uShellMoveOperation, UShellCalcStatisticsOperation, DCStrUtils, uLng, uShlObjAdditional; { TShellFileSource } function TShellFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin Result := True; end; constructor TShellFileSource.Create; begin inherited Create; OleCheck(SHGetDesktopFolder(FDesktopFolder)); OleCheck(SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, {%H-}FDrives)); OleCheck(FDesktopFolder.BindToObject(FDrives, nil, IID_IShellFolder2, Pointer(FRootFolder))); FRootPath := GetDisplayName(FDesktopFolder, FDrives, SHGDN_INFOLDER); FOperationsClasses[fsoMove] := TShellMoveOperation.GetOperationClass; FOperationsClasses[fsoCopy] := TShellCopyOperation.GetOperationClass; FOperationsClasses[fsoCopyIn] := TShellCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TShellCopyOutOperation.GetOperationClass; end; destructor TShellFileSource.Destroy; begin inherited Destroy; CoTaskMemFree(FDrives); end; class function TShellFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= StrBegins(Path, PathDelim + PathDelim + PathDelim + RootName); end; class function TShellFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes; SizeProperty := TFileSizeProperty.Create; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; CreationTimeProperty := TFileCreationDateTimeProperty.Create; LinkProperty := TFileShellProperty.Create; CommentProperty := TFileCommentProperty.Create; end; end; class function TShellFileSource.GetMainIcon(out Path: String): Boolean; begin Result:= True; Path:= '%SystemRoot%\System32\shell32.dll,15'; end; class function TShellFileSource.RootName: String; var DrivesPIDL: PItemIDList; DesktopFolder: IShellFolder; begin OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, {%H-}DrivesPIDL)); Result:= GetDisplayName(DesktopFolder, DrivesPIDL, SHGDN_INFOLDER); CoTaskMemFree(DrivesPIDL); end; class procedure TShellFileSource.ListDrives(DrivesList: TDrivesList; UpperCase: Boolean); const SFGAOF_DEFAULT = SFGAO_FILESYSTEM or SFGAO_FOLDER; const UPPER_LETTER: array[0..11] of String = ('Ù', 'Ú', 'Û', 'Ü', 'Ũ', 'Ū', 'Ŭ', 'Ů', 'Ű', 'Ų', 'Ȕ', 'Ȗ'); LOWER_LETTER: array[0..11] of String = ('ù', 'ú', 'û', 'ü', 'ũ', 'ū', 'ŭ', 'ů', 'ű', 'ų', 'ȕ', 'ȗ'); var ADrive: PDrive; RootPath: String; DeviceId: String; PIDL: PItemIDList; rgfInOut: LongWord; Index: Integer = 0; NumIDs: LongWord = 0; AFolder: IShellFolder2; EnumIDList: IEnumIDList; DrivesPIDL: PItemIDList; DesktopFolder: IShellFolder; begin OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, {%H-}DrivesPIDL)); try OleCheckUTF8(DesktopFolder.BindToObject(DrivesPIDL, nil, IID_IShellFolder2, Pointer(AFolder))); OleCheckUTF8(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_STORAGE, EnumIDList)); RootPath:= '\\\' + GetDisplayName(DesktopFolder, DrivesPIDL, SHGDN_INFOLDER); while (EnumIDList.Next(1, PIDL, NumIDs) = S_OK) do try rgfInOut:= SFGAOF_DEFAULT; if Succeeded(AFolder.GetAttributesOf(1, PIDL, rgfInOut)) then begin if (SFGAOF_DEFAULT and rgfInOut) = SFGAO_FOLDER then begin DeviceId:= GetDisplayName(AFolder, PIDL, SHGDN_FORPARSING); if Pos('\\?\usb', DeviceId) > 0 then begin New(ADrive); ZeroMemory(ADrive, SizeOf(TDrive)); if UpperCase then ADrive^.DisplayName:= UPPER_LETTER[Index] else begin ADrive^.DisplayName:= LOWER_LETTER[Index]; end; ADrive^.IsMounted:= True; ADrive^.DeviceId:= DeviceId; ADrive^.DriveType:= dtSpecial; ADrive^.IsMediaAvailable:= True; ADrive^.DriveLabel:= GetDisplayNameEx(AFolder, PIDL, SHGDN_INFOLDER); ADrive^.Path:= RootPath + PathDelim + ADrive^.DriveLabel; DrivesList.Add(ADrive); Inc(Index); if (Index > High(LOWER_LETTER)) then Break; end; end; end; finally CoTaskMemFree(PIDL); end; finally CoTaskMemFree(DrivesPIDL); end; end; function TShellFileSource.FindObject(const AObject: String; out AValue: PItemIDList): HRESULT; var APath: String; AFolder: IShellFolder2; AItemPIDL, AFolderPIDL: PItemIDList; begin APath:= ExtractFileDir(AObject); Result:= FindFolder(APath, AFolder); if Succeeded(Result) then begin Result:= FindObject(AFolder, ExtractFileName(AObject), AItemPIDL); if Succeeded(Result) then begin Result:= SHGetIDListFromObject(AFolder, AFolderPIDL); if Succeeded(Result) then begin AValue:= ILCombine(AFolderPIDL, AItemPIDL); CoTaskMemFree(AFolderPIDL); end; CoTaskMemFree(AItemPIDL); end; end; end; function TShellFileSource.FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT; var AItemName: String; PIDL: PItemIDList; NumIDs: LongWord = 0; EnumIDList: IEnumIDList; begin Result:= AParent.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList); if Succeeded(Result) then begin while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do begin AItemName:= GetDisplayNameEx(AParent, PIDL, SHGDN_INFOLDER); if AName = AItemName then begin AValue:= PIDL; Exit(S_OK); end; CoTaskMemFree(PIDL); end; end; Result:= STG_E_FILENOTFOUND; end; function TShellFileSource.FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT; function List(var AFolder: IShellFolder2; const AObject: String): HRESULT; var AName: String; PIDL: PItemIDList; NumIDs: LongWord = 0; AValue: IShellFolder2; EnumIDList: IEnumIDList; begin Result:= AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList); if Succeeded(Result) then begin while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try AName:= GetDisplayNameEx(AFolder, PIDL, SHGDN_INFOLDER); if AName = AObject then begin Result:= AFolder.BindToObject(PIDL, nil, IID_IShellFolder2, Pointer(AValue)); if Succeeded(Result) then AFolder:= AValue; Exit; end; finally CoTaskMemFree(PIDL); end; end; Result:= STG_E_PATHNOTFOUND; end; var Index: Integer; APath: TStringArray; begin APath:= Path.Split([PathDelim], TStringSplitOptions.ExcludeEmpty); if Length(APath) = 0 then Result:= STG_E_PATHNOTFOUND else begin if (APath[0] <> FRootPath) then Result:= STG_E_PATHNOTFOUND else begin AValue:= FRootFolder; // Find subdirectory for Index:= 1 to High(APath) do begin Result:= List(AValue, APath[Index]); if Failed(Result) then Exit; end; end; end; end; function TShellFileSource.CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT; var AName: WideString; AParentItem: IShellItem; AFileOp: IFileOperation; AParentPIDL: PItemIDList; begin AName:= CeUtf8ToUtf16(Name); Result:= SHGetIDListFromObject(AParent, AParentPIDL); if Succeeded(Result) then try Result:= SHCreateItemFromIDList(AParentPIDL, IShellItem, AParentItem); if Succeeded(Result) then begin AFileOp:= CreateComObject(CLSID_FileOperation) as IFileOperation; Result:= AFileOp.NewItem(AParentItem, FILE_ATTRIBUTE_DIRECTORY, PWideChar(AName), nil, nil); if Succeeded(Result) then begin Result:= AFileOp.PerformOperations(); end; end; finally CoTaskMemFree(AParentPIDL); end; end; function TShellFileSource.CreateDirectory(const Path: String): Boolean; var AName: String; AParent: IShellFolder2; begin AName:= ExtractFileName(Path); Result:= Succeeded(FindFolder(ExtractFileDir(Path), AParent)); if Result then begin Result:= Succeeded(CreateFolder(AParent, AName)); end; end; function TShellFileSource.FileSystemEntryExists(const Path: String): Boolean; var AObject: PItemIDList; begin Result:= Succeeded(FindObject(Path, AObject)); if Result then CoTaskMemFree(AObject); end; function TShellFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoList, fsoExecute, fsoDelete, fsoCreateDirectory, fsoCopyIn, fsoCopyOut, fsoSetFileProperty, fsoCalcStatistics]; end; function TShellFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpSize, fpAttributes, fpModificationTime, fpCreationTime, uFileProperty.fpLink, fpComment ]; end; function TShellFileSource.GetRootDir(sPath: String): String; begin Result:= PathDelim + PathDelim + PathDelim + FRootPath + PathDelim; end; function TShellFileSource.GetProperties: TFileSourceProperties; begin Result := [fspVirtual]; end; function TShellFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TShellListOperation.Create(TargetFileSource, TargetPath); end; function TShellFileSource.CreateDeleteOperation(var FilesToDelete: TFiles ): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TShellDeleteOperation.Create(TargetFileSource, FilesToDelete); end; function TShellFileSource.CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TShellCreateDirectoryOperation.Create(TargetFileSource, BasePath, DirectoryPath); end; function TShellFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TShellExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; function TShellFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TShellMoveOperation.Create(TargetFileSource, SourceFiles, TargetPath); end; function TShellFileSource.CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result:= TShellCopyOperation.Create(SourceFileSource, SourceFileSource, SourceFiles, TargetPath); end; function TShellFileSource.CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TShellCopyInOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TShellFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TShellCopyOutOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TShellFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles ): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TShellCalcStatisticsOperation.Create(TargetFileSource, theFiles); end; function TShellFileSource.CreateSetFilePropertyOperation( var theTargetFiles: TFiles; var theNewProperties: TFileProperties ): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TShellSetFilePropertyOperation.Create(TargetFileSource, theTargetFiles, theNewProperties); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellfilesourceutil.pas�������������������������������0000644�0001750�0000144�00000035260�14743153644�025211� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellFileSourceUtil; {$mode delphi} interface uses Classes, SysUtils, Windows, ActiveX, ShlObj, ComObj, ShlWAPI, ShellAPI, uShellFolder, uShellFileOperation, uFileSourceCopyOperation, uFileProperty, uFileSourceDeleteOperation, uFileSourceSetFilePropertyOperation, uGlobs, uLog; type { TItemList } TItemList = class(TFPList) public destructor Destroy; override; end; { TFileShellProperty } TFileShellProperty = class(TFileLinkProperty) private FItem: PItemIDList; public destructor Destroy; override; function Clone: TFileLinkProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; property Item: PItemIDList read FItem write FItem; end; TCheckOperationState = function(): Boolean of object; TUpdateCopyStatisticsFunction = procedure(var NewStatistics: TFileSourceCopyOperationStatistics) of object; TUpdateDeleteStatisticsFunction = procedure(var NewStatistics: TFileSourceDeleteOperationStatistics) of object; TUpdateSetFilePropertyStatisticsFunction = procedure(var NewStatistics: TFileSourceSetFilePropertyOperationStatistics) of object; { TFileOperationProgressSink } TFileOperationProgressSink = class(TInterfacedObject, IFileOperationProgressSink) private FCheckOperationState: TCheckOperationState; FCopyStatistics: PFileSourceCopyOperationStatistics; FUpdateCopyStatistics: TUpdateCopyStatisticsFunction; FDeleteStatistics: PFileSourceDeleteOperationStatistics; FUpdateDeleteStatistics: TUpdateDeleteStatisticsFunction; FUpdateSetFilePropertyStatistics: TUpdateSetFilePropertyStatisticsFunction; FSetFilePropertyStatistics: PFileSourceSetFilePropertyOperationStatistics; protected procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(AStatistics: PFileSourceCopyOperationStatistics; AUpdateStatistics: TUpdateCopyStatisticsFunction; ACheckOperationState: TCheckOperationState); reintroduce; overload; constructor Create(AStatistics: PFileSourceDeleteOperationStatistics; AUpdateStatistics: TUpdateDeleteStatisticsFunction; ACheckOperationState: TCheckOperationState); reintroduce; overload; constructor Create(AStatistics: PFileSourceSetFilePropertyOperationStatistics; AUpdateStatistics: TUpdateSetFilePropertyStatisticsFunction; ACheckOperationState: TCheckOperationState); reintroduce; overload; public function StartOperations: HResult; stdcall; function FinishOperations(hrResult: HResult): HResult; stdcall; function PreRenameItem(dwFlags: DWORD; psiItem: IShellItem; pszNewName: LPCWSTR): HResult; stdcall; function PostRenameItem(dwFlags: DWORD; psiItem: IShellItem; pszNewName: LPCWSTR; hrRename: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; function PreMoveItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR): HResult; stdcall; function PostMoveItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; hrMove: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; function PreCopyItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR): HResult; stdcall; function PostCopyItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; hrCopy: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; function PreDeleteItem(dwFlags: DWORD; psiItem: IShellItem): HResult; stdcall; function PostDeleteItem(dwFlags: DWORD; psiItem: IShellItem; hrDelete: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; function PreNewItem(dwFlags: DWORD; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR): HResult; stdcall; function PostNewItem(dwFlags: DWORD; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; pszTemplateName: LPCWSTR; dwFileAttributes: DWORD; hrNew: HRESULT; psiNewItem: IShellItem): HResult; stdcall; function UpdateProgress(iWorkTotal: UINT; iWorkSoFar: UINT): HResult; stdcall; function ResetTimer: HResult; stdcall; function PauseTimer: HResult; stdcall; function ResumeTimer: HResult; stdcall; end; function SHBindToParent(pidl: LPCITEMIDLIST; constref riid: TREFIID; out ppv; var ppidlLast: LPCITEMIDLIST): HRESULT; stdcall; external Shell32; var SHCreateItemWithParent: function(pidlParent: PCIDLIST_ABSOLUTE; psfParent: IShellFolder; pidl: PCUITEMID_CHILD; const riid: REFIID; out ppvItem): HRESULT; stdcall; SHGetIDListFromObject: function(punk: IUnknown; out ppidl): HRESULT; stdcall; SHCreateItemFromIDList: function(pidl: PItemIDList; const riid: REFIID; out ppv): HRESULT; stdcall; SHCreateItemFromParsingName: function(pszPath: LPCWSTR; const pbc: IBindCtx; const riid: TIID; out ppv): HRESULT; stdcall; SHCreateShellItemArray: function(pidlParent: PCIDLIST_ABSOLUTE; psf: IShellFolder; cidl: UINT; ppidl: PPItemIDList; out ppsiItemArray): HRESULT; stdcall; SHCreateShellItemArrayFromIDLists: function(cidl: UINT; rgpidl: PPItemIDList; out ppsiItemArray): HRESULT; stdcall; implementation uses DCOSUtils, DCConvertEncoding, uShlObjAdditional, uLng; var AModule: HMODULE; { TItemList } destructor TItemList.Destroy; var AItem: PItemIDList; begin for AItem in Self do begin CoTaskMemFree(AItem); end; inherited Destroy; end; { TFileShellProperty } destructor TFileShellProperty.Destroy; begin inherited Destroy; if Assigned(FItem) then CoTaskMemFree(FItem); end; function TFileShellProperty.Clone: TFileLinkProperty; begin Result := TFileShellProperty.Create; CloneTo(Result); end; procedure TFileShellProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); if FileProperty is TFileShellProperty then begin TFileShellProperty(FileProperty).FItem := ILClone(Self.FItem); end; end; end; { TFileOperationProgressSink } procedure TFileOperationProgressSink.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(nil, sMessage, logMsgType); end; end; constructor TFileOperationProgressSink.Create( AStatistics: PFileSourceCopyOperationStatistics; AUpdateStatistics: TUpdateCopyStatisticsFunction; ACheckOperationState: TCheckOperationState); begin FCopyStatistics:= AStatistics; FUpdateCopyStatistics:= AUpdateStatistics; FCheckOperationState:= ACheckOperationState; end; constructor TFileOperationProgressSink.Create( AStatistics: PFileSourceDeleteOperationStatistics; AUpdateStatistics: TUpdateDeleteStatisticsFunction; ACheckOperationState: TCheckOperationState); begin FDeleteStatistics:= AStatistics; FUpdateDeleteStatistics:= AUpdateStatistics; FCheckOperationState:= ACheckOperationState; end; constructor TFileOperationProgressSink.Create( AStatistics: PFileSourceSetFilePropertyOperationStatistics; AUpdateStatistics: TUpdateSetFilePropertyStatisticsFunction; ACheckOperationState: TCheckOperationState); begin FSetFilePropertyStatistics:= AStatistics; FUpdateSetFilePropertyStatistics:= AUpdateStatistics; FCheckOperationState:= ACheckOperationState; end; function TFileOperationProgressSink.StartOperations: HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.FinishOperations(hrResult: HResult ): HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.PreRenameItem(dwFlags: DWORD; psiItem: IShellItem; pszNewName: LPCWSTR): HResult; stdcall; var AFileName: PWideChar; begin if Succeeded(psiItem.GetDisplayName(SIGDN(SIGDN_DESKTOPABSOLUTEEDITING), @AFileName)) then begin FSetFilePropertyStatistics^.CurrentFile:= CeUtf16ToUtf8(AFileName); CoTaskMemFree(AFileName); end; Result:= S_OK; end; function TFileOperationProgressSink.PostRenameItem(dwFlags: DWORD; psiItem: IShellItem; pszNewName: LPCWSTR; hrRename: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.PreMoveItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR ): HResult; stdcall; begin Result:= PreCopyItem(dwFlags, psiItem, psiDestinationFolder, pszNewName); end; function TFileOperationProgressSink.PostMoveItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; hrMove: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; begin if (log_cp_mv_ln in gLogOptions) and (hrMove <> COPYENGINE_E_USER_CANCELLED) then begin with FCopyStatistics^ do begin if Succeeded(hrMove) then begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogMove, [CurrentFileFrom + ' -> ' + CurrentFileTo]), [log_cp_mv_ln], lmtSuccess); end else begin LogMessage(Format(rsMsgLogError + rsMsgLogMove, [CurrentFileFrom + ' -> ' + CurrentFileTo]), [log_cp_mv_ln], lmtError); end; end; end; Result:= S_OK; end; function TFileOperationProgressSink.PreCopyItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR ): HResult; stdcall; var AFileName: PWideChar; begin if Succeeded(psiItem.GetDisplayName(SIGDN(SIGDN_DESKTOPABSOLUTEEDITING), @AFileName)) then begin FCopyStatistics^.CurrentFileFrom:= CeUtf16ToUtf8(AFileName); CoTaskMemFree(AFileName); end; if Succeeded(psiDestinationFolder.GetDisplayName(SIGDN(SIGDN_DESKTOPABSOLUTEEDITING), @AFileName)) then begin with FCopyStatistics^ do begin CurrentFileTo:= CeUtf16ToUtf8(AFileName); CoTaskMemFree(AFileName); if Assigned(pszNewName) and (pszNewName^ <> #0) then CurrentFileTo:= CurrentFileTo + CeUtf16ToUtf8(pszNewName) else begin CurrentFileTo:= CurrentFileTo + ExtractFileName(CurrentFileFrom); end; end; end; FUpdateCopyStatistics(FCopyStatistics^); Result:= S_OK; end; function TFileOperationProgressSink.PostCopyItem(dwFlags: DWORD; psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; hrCopy: HRESULT; psiNewlyCreated: IShellItem): HResult; stdcall; begin if (log_cp_mv_ln in gLogOptions) and (hrCopy <> COPYENGINE_E_USER_CANCELLED) then begin with FCopyStatistics^ do begin if Succeeded(hrCopy) then begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogCopy, [CurrentFileFrom + ' -> ' + CurrentFileTo]), [log_cp_mv_ln], lmtSuccess); end else begin LogMessage(Format(rsMsgLogError + rsMsgLogCopy, [CurrentFileFrom + ' -> ' + CurrentFileTo]), [log_cp_mv_ln], lmtError); end; end; end; Result:= S_OK; end; function TFileOperationProgressSink.PreDeleteItem(dwFlags: DWORD; psiItem: IShellItem): HResult; stdcall; var AFileName: PWideChar; begin if Succeeded(psiItem.GetDisplayName(SIGDN(SIGDN_DESKTOPABSOLUTEEDITING), @AFileName)) then begin FDeleteStatistics^.CurrentFile:= CeUtf16ToUtf8(AFileName); CoTaskMemFree(AFileName); end; Result:= S_OK; end; function TFileOperationProgressSink.PostDeleteItem(dwFlags: DWORD; psiItem: IShellItem; hrDelete: HRESULT; psiNewlyCreated: IShellItem ): HResult; stdcall; var AText: String; sfgaoAttribs: SFGAOF = 0; begin if (log_delete in gLogOptions) and (hrDelete <> COPYENGINE_E_USER_CANCELLED) then begin psiItem.GetAttributes(SFGAO_FOLDER, @sfgaoAttribs); if (sfgaoAttribs and SFGAO_FOLDER) = 0 then AText:= rsMsgLogDelete else begin AText:= rsMsgLogRmDir; end; with FDeleteStatistics^ do begin if Succeeded(hrDelete) then begin LogMessage(Format(rsMsgLogSuccess + AText, [CurrentFile]), [log_delete], lmtSuccess); end else begin LogMessage(Format(rsMsgLogError + AText, [CurrentFile]), [log_delete], lmtError); end; end; end; Result:= S_OK; end; function TFileOperationProgressSink.PreNewItem(dwFlags: DWORD; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR): HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.PostNewItem(dwFlags: DWORD; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; pszTemplateName: LPCWSTR; dwFileAttributes: DWORD; hrNew: HRESULT; psiNewItem: IShellItem): HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.UpdateProgress(iWorkTotal: UINT; iWorkSoFar: UINT): HResult; stdcall; begin if Assigned(FCopyStatistics) then begin FCopyStatistics^.TotalBytes:= iWorkTotal; FCopyStatistics^.DoneBytes:= iWorkSoFar; FUpdateCopyStatistics(FCopyStatistics^); end else if Assigned(FDeleteStatistics) then begin FDeleteStatistics^.TotalFiles:= iWorkTotal; FDeleteStatistics^.DoneFiles:= iWorkSoFar; FUpdateDeleteStatistics(FDeleteStatistics^); end else if Assigned(FSetFilePropertyStatistics) then begin FSetFilePropertyStatistics^.TotalFiles:= iWorkTotal; FSetFilePropertyStatistics^.DoneFiles:= iWorkSoFar; FUpdateSetFilePropertyStatistics(FSetFilePropertyStatistics^); end; if FCheckOperationState() then Result:= S_OK else begin Result:= COPYENGINE_E_USER_CANCELLED; end; end; function TFileOperationProgressSink.ResetTimer: HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.PauseTimer: HResult; stdcall; begin Result:= S_OK; end; function TFileOperationProgressSink.ResumeTimer: HResult; stdcall; begin Result:= S_OK; end; initialization if (Win32MajorVersion > 5) then begin AModule:= GetModuleHandleW(Shell32); @SHGetIDListFromObject:= GetProcAddress(AModule, 'SHGetIDListFromObject'); @SHCreateItemFromIDList:= GetProcAddress(AModule, 'SHCreateItemFromIDList'); @SHCreateItemWithParent:= GetProcAddress(AModule, 'SHCreateItemWithParent'); @SHCreateShellItemArray:= GetProcAddress(AModule, 'SHCreateShellItemArray'); @SHCreateItemFromParsingName:= GetProcAddress(AModule, 'SHCreateItemFromParsingName'); @SHCreateShellItemArrayFromIDLists:= GetProcAddress(AModule, 'SHCreateShellItemArrayFromIDLists'); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushelllistoperation.pas��������������������������������0000644�0001750�0000144�00000013672�14743153644�025052� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellListOperation; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Windows, ShlObj, ComObj, uFileSourceListOperation, uShellFileSource, uFileSource; type { TShellListOperation } TShellListOperation = class(TFileSourceListOperation) private FShellFileSource: IShellFileSource; procedure ListFolder(AFolder: IShellFolder2; grfFlags: DWORD); procedure ListDrives; procedure ListDirectory; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses ActiveX, Variants, DCOSUtils, DCDateTimeUtils, ShellAPI, DCStrUtils, uFile, uShellFolder, uShlObjAdditional, uShowMsg, uShellFileSourceUtil; { TShellListOperation } procedure TShellListOperation.ListFolder(AFolder: IShellFolder2; grfFlags: DWORD); const SFGAOF_DEFAULT = SFGAO_STORAGE or SFGAO_HIDDEN or SFGAO_FOLDER; var AFile: TFile; PIDL: PItemIDList; AValue: OleVariant; rgfInOut: LongWord; AParent: PItemIDList; NumIDs: LongWord = 0; EnumIDList: IEnumIDList; begin OleCheckUTF8(SHGetIDListFromObject(AFolder, AParent)); try OleCheckUTF8(AFolder.EnumObjects(0, grfFlags, EnumIDList)); while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try CheckOperationState; aFile:= TShellFileSource.CreateFile(Path); AFile.Name:= GetDisplayNameEx(AFolder, PIDL, SHGDN_INFOLDER); TFileShellProperty(AFile.LinkProperty).Item:= ILCombine(AParent, PIDL); AFile.LinkProperty.LinkTo:= GetDisplayName(AFolder, PIDL, SHGDN_INFOLDER or SHGDN_FORPARSING); rgfInOut:= SFGAOF_DEFAULT; if Succeeded(AFolder.GetAttributesOf(1, PIDL, rgfInOut)) then begin if (rgfInOut and SFGAO_STORAGE <> 0) then begin AFile.Attributes:= FILE_ATTRIBUTE_DEVICE or FILE_ATTRIBUTE_VIRTUAL; end; if (rgfInOut and SFGAO_FOLDER <> 0) then begin AFile.Attributes:= AFile.Attributes or FILE_ATTRIBUTE_DIRECTORY; end; if (rgfInOut and SFGAO_HIDDEN <> 0) then begin AFile.Attributes:= AFile.Attributes or FILE_ATTRIBUTE_HIDDEN; end; end; AValue:= GetDetails(AFolder, PIDL, SCID_FileSize); if VarIsOrdinal(AValue) then AFile.Size:= AValue else if AFile.IsDirectory then AFile.Size:= 0 else begin AFile.SizeProperty.IsValid:= False; end; AValue:= GetDetails(AFolder, PIDL, SCID_DateModified); if AValue <> Unassigned then AFile.ModificationTime:= AValue else begin AFile.ModificationTimeProperty.IsValid:= False; end; AValue:= GetDetails(AFolder, PIDL, SCID_DateCreated); if AValue <> Unassigned then AFile.CreationTime:= AValue else begin AFile.CreationTimeProperty.IsValid:= False; end; FFiles.Add(AFile); finally CoTaskMemFree(PIDL); end; finally CoTaskMemFree(AParent); end; end; procedure TShellListOperation.ListDrives; const SFGAOF_DEFAULT = SFGAO_FILESYSTEM or SFGAO_FOLDER; var AFile: TFile; LinkTo: String; PIDL: PItemIDList; rgfInOut: LongWord; AValue: OleVariant; NumIDs: LongWord = 0; AFolder: IShellFolder2; EnumIDList: IEnumIDList; DrivesPIDL: PItemIDList; DesktopFolder: IShellFolder; begin OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, {%H-}DrivesPIDL)); try OleCheckUTF8(DesktopFolder.BindToObject(DrivesPIDL, nil, IID_IShellFolder2, Pointer(AFolder))); OleCheckUTF8(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_STORAGE, EnumIDList)); while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try CheckOperationState; LinkTo:= GetDisplayName(AFolder, PIDL, SHGDN_INFOLDER or SHGDN_FORPARSING); // Skip virtual folders if StrBegins(LinkTo, '::{') then Continue; aFile:= TShellFileSource.CreateFile(Path); AFile.LinkProperty.LinkTo:= LinkTo; AFile.Name:= GetDisplayNameEx(AFolder, PIDL, SHGDN_INFOLDER); TFileShellProperty(AFile.LinkProperty).Item:= ILCombine(DrivesPIDL, PIDL); rgfInOut:= SFGAOF_DEFAULT; AFile.Attributes:= FILE_ATTRIBUTE_DEVICE or FILE_ATTRIBUTE_VIRTUAL; if Succeeded(AFolder.GetAttributesOf(1, PIDL, rgfInOut)) then begin if (SFGAO_FILESYSTEM and rgfInOut) <> 0 then begin AFile.Attributes:= AFile.Attributes or FILE_ATTRIBUTE_NORMAL; end else if (rgfInOut and SFGAO_FOLDER <> 0) then begin AFile.Attributes:= AFile.Attributes or FILE_ATTRIBUTE_DIRECTORY; end; end; AFile.ModificationTimeProperty.IsValid:= False; AValue:= GetDetails(AFolder, PIDL, SCID_Capacity); if VarIsOrdinal(AValue) then AFile.Size:= AValue else if AFile.IsDirectory then AFile.Size:= 0 else begin AFile.SizeProperty.IsValid:= False; end; FFiles.Add(AFile); finally CoTaskMemFree(PIDL); end; finally CoTaskMemFree(DrivesPIDL); end; end; procedure TShellListOperation.ListDirectory; var AFolder: IShellFolder2; begin if Succeeded(FShellFileSource.FindFolder(ExcludeTrailingBackslash(Path), AFolder)) then begin ListFolder(AFolder, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN); end; end; constructor TShellListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FShellFileSource:= aFileSource as IShellFileSource; inherited Create(aFileSource, aPath); end; procedure TShellListOperation.MainExecute; begin FFiles.Clear; try if FShellFileSource.IsPathAtRoot(Path) then ListDrives else begin ListDirectory; end; except on E: Exception do msgError(Thread, E.Message); end; end; end. ����������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellmoveoperation.pas��������������������������������0000644�0001750�0000144�00000006616�14743153644�025045� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellMoveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Windows, ShlObj, ComObj, ActiveX, uFileSourceOperation, uFileSourceMoveOperation, uFileSource, uFile, uShellFileSource, uShellFileOperation, uShellFileSourceUtil; type { TShellMoveOperation } TShellMoveOperation = class(TFileSourceMoveOperation) protected FFileOp: IFileOperation; FTargetFolder: IShellItem; FSourceFilesTree: TItemList; FShellFileSource: IShellFileSource; FStatistics: TFileSourceMoveOperationStatistics; procedure ShowError(const sMessage: String); public constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); virtual reintroduce; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uFileSourceOperationOptions, uFileSourceOperationUI, uShellFolder, uGlobs, uShlObjAdditional, uLog, uLng; procedure TShellMoveOperation.ShowError(const sMessage: String); begin if (log_errors in gLogOptions) then begin logWrite(Thread, sMessage, lmtError); end; if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; constructor TShellMoveOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FShellFileSource:= aFileSource as IShellFileSource; FFileOp:= CreateComObject(CLSID_FileOperation) as IFileOperation; inherited Create(aFileSource, theSourceFiles, aTargetPath); end; destructor TShellMoveOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); end; procedure TShellMoveOperation.Initialize; var Index: Integer; AObject: PItemIDList; AFolder: IShellFolder2; begin FStatistics := RetrieveStatistics; FSourceFilesTree:= TItemList.Create; try for Index := 0 to SourceFiles.Count - 1 do begin AObject:= ILClone(TFileShellProperty(SourceFiles[Index].LinkProperty).Item); FSourceFilesTree.Add(AObject); end; OleCheck(FShellFileSource.FindFolder(TargetPath, AFolder)); OleCheck(SHGetIDListFromObject(AFolder, AObject)); try OleCheck(SHCreateItemFromIDList(AObject, IShellItem, FTargetFolder)); finally CoTaskMemFree(AObject); end; except on E: Exception do ShowError(E.Message); end; end; procedure TShellMoveOperation.MainExecute; var Res: HRESULT; dwCookie: DWORD; siItemArray: IShellItemArray; ASink: TFileOperationProgressSink; begin ASink:= TFileOperationProgressSink.Create(@FStatistics, @UpdateStatistics, @CheckOperationStateSafe); FFileOp.SetOperationFlags(FOF_SILENT or FOF_NOCONFIRMMKDIR); try FFileOp.Advise(ASink, @dwCookie); try OleCheck(SHCreateShellItemArrayFromIDLists(FSourceFilesTree.Count, PPItemIDList(FSourceFilesTree.List), siItemArray)); OleCheck(FFileOp.MoveItems(siItemArray, FTargetFolder)); Res:= FFileOp.PerformOperations; if Failed(Res) then begin if Res = COPYENGINE_E_USER_CANCELLED then RaiseAbortOperation else OleError(Res); end; finally FFileOp.Unadvise(dwCookie); end; except on E: EOleError do ShowError(E.Message); end; end; procedure TShellMoveOperation.Finalize; begin end; end. ������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/shellfolder/ushellsetfilepropertyoperation.pas���������������������0000644�0001750�0000144�00000011351�14743153644�027327� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellSetFilePropertyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceSetFilePropertyOperation, uFileSource, uFile, uFileProperty, uShellFileSource, uShellFileOperation, uShellFileSourceUtil; type { TShellSetFilePropertyOperation } TShellSetFilePropertyOperation = class(TFileSourceSetFilePropertyOperation) private FFileOp: IFileOperation; FCurrentFileIndex: Integer; FSourceFilesTree: TItemList; FShellFileSource: IShellFileSource; FStatistics: TFileSourceSetFilePropertyOperationStatistics; procedure ShowError(const sMessage: String); protected function SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; override; public constructor Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses Windows, ActiveX, ShlObj, ComObj, DCConvertEncoding, uShlObjAdditional, uFileSourceOperationUI, uShellFolder, uGlobs, uLog, uLng; procedure TShellSetFilePropertyOperation.ShowError(const sMessage: String); begin if (log_errors in gLogOptions) then begin logWrite(Thread, sMessage, lmtError); end; if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; constructor TShellSetFilePropertyOperation.Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); begin FShellFileSource:= aTargetFileSource as IShellFileSource; FFileOp:= CreateComObject(CLSID_FileOperation) as IFileOperation; inherited Create(aTargetFileSource, theTargetFiles, theNewProperties); // Assign after calling inherited constructor. FSupportedProperties := [fpName]; end; destructor TShellSetFilePropertyOperation.Destroy; begin inherited Destroy; FreeAndNil(FSourceFilesTree); end; procedure TShellSetFilePropertyOperation.Initialize; var Index: Integer; AObject: PItemIDList; begin FStatistics := RetrieveStatistics; FSourceFilesTree:= TItemList.Create; try for Index := 0 to TargetFiles.Count - 1 do begin AObject:= ILClone(TFileShellProperty(TargetFiles[Index].LinkProperty).Item); FSourceFilesTree.Add(AObject); end; except on E: Exception do ShowError(E.Message); end; end; procedure TShellSetFilePropertyOperation.MainExecute; var aFile: TFile; dwCookie: DWORD; aTemplateFile: TFile; CurrentFileIndex: Integer; ASink: TFileOperationProgressSink; begin ASink:= TFileOperationProgressSink.Create(@FStatistics, @UpdateStatistics, @CheckOperationStateSafe); FFileOp.SetOperationFlags(FOF_SILENT or FOF_NOCONFIRMMKDIR); FFileOp.Advise(ASink, @dwCookie); for CurrentFileIndex := 0 to FSourceFilesTree.Count - 1 do begin FCurrentFileIndex:= CurrentFileIndex; AFile:= TargetFiles[FCurrentFileIndex]; if Assigned(TemplateFiles) and (FCurrentFileIndex < TemplateFiles.Count) then aTemplateFile := TemplateFiles[FCurrentFileIndex] else aTemplateFile := nil; SetProperties(FCurrentFileIndex, aFile, aTemplateFile); with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; CheckOperationState; end; FFileOp.Unadvise(dwCookie); end; function TShellSetFilePropertyOperation.SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; var Res: HRESULT; PIDL: PItemIDList; AItem: IShellItem; begin Result := sfprSuccess; PIDL:= PItemIDList(FSourceFilesTree[FCurrentFileIndex]); if Failed(SHCreateItemFromIDList(PIDL, IShellItem, AItem)) then Exit(sfprError); case aTemplateProperty.GetID of fpName: begin if (aTemplateProperty as TFileNameProperty).Value <> aFile.Name then begin if not Succeeded(FFileOp.RenameItem(AItem, PWideChar(CeUtf8ToUtf16((aTemplateProperty as TFileNameProperty).Value)), nil)) then Result := sfprError else begin Res:= FFileOp.PerformOperations(); if Failed(Res) then begin if Res = COPYENGINE_E_USER_CANCELLED then RaiseAbortOperation else Result := sfprError end; end; end else Result := sfprSkipped; end else raise Exception.Create('Trying to set unsupported property'); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/tempfilesystem/����������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020772� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/tempfilesystem/utempfilesystemfilesource.pas�����������������������0000644�0001750�0000144�00000007553�14743153644�027031� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uTempFileSystemFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSystemFileSource; type ITempFileSystemFileSource = interface(IFileSystemFileSource) ['{1B6CFF05-15D5-45AF-A382-9C12C1A52024}'] function GetDeleteOnDestroy: Boolean; procedure SetDeleteOnDestroy(NewDeleteOnDestroy: Boolean); property DeleteOnDestroy: Boolean read GetDeleteOnDestroy write SetDeleteOnDestroy; property FileSystemRoot: String read GetRootDir; end; { TTempFileSystemFileSource } {en Filesystem file source that stores temporary files. Operations can be done like on a regular file system but all the contents can be deleted when the file source is destroyed, depending on DeleteOnDestroy property. } TTempFileSystemFileSource = class(TFileSystemFileSource, ITempFileSystemFileSource) private FDeleteOnDestroy: Boolean; FTempRootDir: String; function GetDeleteOnDestroy: Boolean; procedure SetDeleteOnDestroy(NewDeleteOnDestroy: Boolean); protected public constructor Create; override; constructor Create(const aPath: String); virtual; overload; destructor Destroy; override; class function GetFileSource: ITempFileSystemFileSource; function IsPathAtRoot(Path: String): Boolean; override; function GetParentDir(sPath: String): String; override; function GetRootDir(sPath: String): String; override; overload; function GetRootDir: String; override; overload; function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; override; property DeleteOnDestroy: Boolean read FDeleteOnDestroy write FDeleteOnDestroy default True; property FilesystemRoot: String read FTempRootDir; end; ETempFileSourceException = class(Exception); ECannotCreateTempFileSourceException = class(ETempFileSourceException); implementation uses DCOSUtils, uOSUtils, DCStrUtils, uFileProcs; constructor TTempFileSystemFileSource.Create; begin Create(''); end; constructor TTempFileSystemFileSource.Create(const aPath: String); begin inherited Create; if (aPath <> EmptyStr) and mbDirectoryExists(aPath) then FTempRootDir := aPath else begin FTempRootDir := GetTempName(GetTempFolder); if (FTempRootDir = EmptyStr) or (mbForceDirectory(FTempRootDir) = False) then begin FDeleteOnDestroy := False; raise ECannotCreateTempFileSourceException.Create('Cannot create temp file source'); end; end; FCurrentAddress := FTempRootDir; FDeleteOnDestroy := True; FTempRootDir := IncludeTrailingPathDelimiter(FTempRootDir); end; destructor TTempFileSystemFileSource.Destroy; begin inherited Destroy; if FDeleteOnDestroy and mbDirectoryExists(FTempRootDir) then begin DelTree(FCurrentAddress); mbRemoveDir(FCurrentAddress); end; end; function TTempFileSystemFileSource.GetDeleteOnDestroy: Boolean; begin Result := FDeleteOnDestroy; end; procedure TTempFileSystemFileSource.SetDeleteOnDestroy(NewDeleteOnDestroy: Boolean); begin FDeleteOnDestroy := NewDeleteOnDestroy; end; class function TTempFileSystemFileSource.GetFileSource: ITempFileSystemFileSource; begin Result := TTempFileSystemFileSource.Create; end; function TTempFileSystemFileSource.GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; begin Result := GetDiskFreeSpace(FTempRootDir, FreeSize, TotalSize); end; function TTempFileSystemFileSource.IsPathAtRoot(Path: String): Boolean; begin Result := (IncludeTrailingPathDelimiter(Path) = FTempRootDir); end; function TTempFileSystemFileSource.GetParentDir(sPath: String): String; begin if IsPathAtRoot(sPath) then Result := '' else Result := DCStrUtils.GetParentDir(sPath); end; function TTempFileSystemFileSource.GetRootDir(sPath: String): String; begin Result := FTempRootDir; end; function TTempFileSystemFileSource.GetRootDir: String; begin Result := FTempRootDir; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/uarchivecopyoperation.pas������������������������������������������0000644�0001750�0000144�00000004633�14743153644�023055� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uArchiveCopyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceCopyOperation, uFileSource, uFile; type TExtractFlag = (efSmartExtract); TExtractFlags = set of TExtractFlag; { TArchiveCopyInOperation } TArchiveCopyInOperation = class(TFileSourceCopyInOperation) protected FStatistics: TFileSourceCopyOperationStatistics; // Local copy of statistics FPackingFlags: Integer; // Packing flags passed to plugin FFullFilesTree: TFiles; // Full list of files (recursive) FCreateNew: Boolean; // Create new archive FTarBefore: Boolean; // Create TAR archive first FTarFileName: String; // Temporary TAR archive name procedure DoReloadFileSources; override; public function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; property CreateNew: Boolean read FCreateNew write FCreateNew; end; { TArchiveCopyOutOperation } TArchiveCopyOutOperation = class(TFileSourceCopyOutOperation) protected FExtractMask: String; FExtractFlags: TExtractFlags; public function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; property ExtractMask: String read FExtractMask write FExtractMask; property ExtractFlags: TExtractFlags read FExtractFlags write FExtractFlags; end; implementation uses uLng; { TArchiveCopyInOperation } procedure TArchiveCopyInOperation.DoReloadFileSources; begin if not FCreateNew then inherited DoReloadFileSources; end; function TArchiveCopyInOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if SourceFiles.Count = 1 then Result := Format(rsOperPackingSomethingTo, [SourceFiles[0].Name, TargetFileSource.CurrentAddress]) else Result := Format(rsOperPackingFromTo, [SourceFiles.Path, TargetFileSource.CurrentAddress]); end; else Result := rsOperPacking; end; end; { TArchiveCopyOutOperation } function TArchiveCopyOutOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperExtractingFromTo, [SourceFileSource.CurrentAddress, TargetPath]); else Result := rsOperExtracting; end; end; end. �����������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/uarchivefilesource.pas���������������������������������������������0000644�0001750�0000144�00000005227�14743153644�022322� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uArchiveFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCOSUtils, uLocalFileSource, uFileSource, uFile, uFileProperty; type IArchiveFileSource = interface(ILocalFileSource) ['{13A8637C-FFDF-46B0-B5B4-E7C6851C157A}'] function Changed: Boolean; function GetPacker: String; property Packer: String read GetPacker; {en Full path to the archive on the ParentFileSource. } property ArchiveFileName: String read GetCurrentAddress; end; { TArchiveFileSource } TArchiveFileSource = class(TLocalFileSource, IArchiveFileSource) private FAttributeData: TFileAttributeData; protected function GetPacker: String; virtual; abstract; function GetSupportedFileProperties: TFilePropertiesTypes; override; public {en Creates an archive file source. @param(anArchiveFileSource File source that stores the archive. Usually it will be direct-access file source, like filesystem.) @param(anArchiveFileName Full path to the archive on the ArchiveFileSource.) } constructor Create(anArchiveFileSource: IFileSource; anArchiveFileName: String); virtual reintroduce overload; class function CreateFile(const APath: String): TFile; override; function Changed: Boolean; property ArchiveFileName: String read GetCurrentAddress; end; implementation constructor TArchiveFileSource.Create(anArchiveFileSource: IFileSource; anArchiveFileName: String); begin FCurrentAddress := anArchiveFileName; inherited Create; ParentFileSource := anArchiveFileSource; mbFileGetAttr(anArchiveFileName, FAttributeData); end; class function TArchiveFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin SizeProperty := TFileSizeProperty.Create; CompressedSizeProperty := TFileCompressedSizeProperty.Create; AttributesProperty := TFileAttributesProperty.CreateOSAttributes; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; end; end; function TArchiveFileSource.Changed: Boolean; var Attr: TFileAttributeData; begin if not mbFileGetAttr(ArchiveFileName, Attr) then Result:= False else begin Result:= (Attr.Size <> FAttributeData.Size) or (Attr.LastWriteTime <> FAttributeData.LastWriteTime); if Result then FAttributeData:= Attr; end; end; function TArchiveFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpSize, fpCompressedSize, fpAttributes, fpModificationTime]; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/uarchivefilesourceutil.pas�����������������������������������������0000644�0001750�0000144�00000037616�14743153644�023227� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uArchiveFileSourceUtil; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileView, uFile, uArchiveFileSource, uFileSource, uOperationsManager; function GetArchiveFileSource(SourceFileSource: IFileSource; ArchiveFile: TFile; ArchiveType: String; ArchiveSign: Boolean; IncludeHidden: Boolean): IArchiveFileSource; procedure TestArchive(aFileView: TFileView; aFiles: TFiles; QueueIdentifier: TOperationsManagerQueueIdentifier); function FileIsArchive(const FileName: String): Boolean; procedure FillAndCount(Files: TFiles; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); procedure InstallPlugin(const FileName: String); implementation uses DCOSUtils, DCClassesUtf8, DCStrUtils, uFindEx, uShowMsg, uLng, uGlobs, uDefaultPlugins, uFileSourceProperty, uWcxModule, uWfxModule, uFileProcs, uWcxArchiveFileSource, uMultiArchiveFileSource, uFileSystemFileSource, uTempFileSystemFileSource, uFileSourceOperation, uArchiveCopyOperation, uFileSourceOperationTypes, uGlobsPaths, uSysFolders, fOptionsPluginsBase, fOptions; // Only for direct access file sources. function GetArchiveFileSourceDirect(SourceFileSource: IFileSource; ArchiveFileName: String; ArchiveType: String; ArchiveSign: Boolean; IncludeHidden: Boolean): IArchiveFileSource; begin if not (fspDirectAccess in SourceFileSource.Properties) then Exit(nil); // Check if there is a registered WCX plugin for possible archive. Result := FileSourceManager.Find(TWcxArchiveFileSource, ArchiveFileName) as IArchiveFileSource; if not Assigned(Result) then begin if ArchiveSign then Result := TWcxArchiveFileSource.CreateByArchiveSign(SourceFileSource, ArchiveFileName) else if (ArchiveType = EmptyStr) then Result := TWcxArchiveFileSource.CreateByArchiveName(SourceFileSource, ArchiveFileName) else Result := TWcxArchiveFileSource.CreateByArchiveType(SourceFileSource, ArchiveFileName, ArchiveType, IncludeHidden); end; // Check if there is a registered MultiArc addon for possible archive. if not Assigned(Result) then begin Result := FileSourceManager.Find(TMultiArchiveFileSource, ArchiveFileName) as IArchiveFileSource; if not Assigned(Result) then begin if ArchiveSign then Result := TMultiArchiveFileSource.CreateByArchiveSign(SourceFileSource, ArchiveFileName) else if (ArchiveType = EmptyStr) then Result := TMultiArchiveFileSource.CreateByArchiveName(SourceFileSource, ArchiveFileName) else Result := TMultiArchiveFileSource.CreateByArchiveType(SourceFileSource, ArchiveFileName, ArchiveType); end; end; end; function GetArchiveFileSource(SourceFileSource: IFileSource; ArchiveFile: TFile; ArchiveType: String; ArchiveSign: Boolean; IncludeHidden: Boolean): IArchiveFileSource; var TempFS: ITempFileSystemFileSource = nil; Operation: TFileSourceOperation = nil; Files: TFiles = nil; LocalArchiveFile: TFile; begin if fspDirectAccess in SourceFileSource.Properties then begin Result := GetArchiveFileSourceDirect(SourceFileSource, ArchiveFile.FullPath, ArchiveType, ArchiveSign, IncludeHidden); Exit; end; Result := nil; if fspLinksToLocalFiles in SourceFileSource.Properties then begin LocalArchiveFile := ArchiveFile.Clone; try if SourceFileSource.GetLocalName(LocalArchiveFile) then begin TempFS := TTempFileSystemFileSource.Create(LocalArchiveFile.Path); // Source FileSource manages the files, not the TempFileSource. TempFS.DeleteOnDestroy := False; // The files on temp file source are valid as long as source FileSource is valid. TempFS.ParentFileSource := SourceFileSource; Result := GetArchiveFileSourceDirect(TempFS, LocalArchiveFile.FullPath, ArchiveType, ArchiveSign, IncludeHidden); // If not successful will try to get files through CopyOut below. end; finally FreeAndNil(LocalArchiveFile); end; end; if (not Assigned(Result)) and (fsoCopyOut in SourceFileSource.GetOperationsTypes) then begin // If checking by extension we don't have to unpack files yet. // First check if there is a registered plugin for the archive extension. if (not ArchiveSign) and (not (TWcxArchiveFileSource.CheckPluginByName(ArchiveFile.Name) or TMultiArchiveFileSource.CheckAddonByName(ArchiveFile.Name))) then begin // No registered handlers for the archive extension. Exit; end; // else either there is a handler for the archive extension // or we have to unpack files first to check // (if creating file source by archive signature). try TempFS := TTempFileSystemFileSource.Create; Files := TFiles.Create(ArchiveFile.Path); Files.Add(ArchiveFile.Clone); Operation := SourceFileSource.CreateCopyOutOperation(TempFS, Files, TempFS.FilesystemRoot); if Assigned(Operation) then begin OperationsManager.AddOperationModal(Operation); if Operation.Result = fsorFinished then begin Result := GetArchiveFileSourceDirect( TempFS, IncludeTrailingPathDelimiter(TempFS.FilesystemRoot) + ArchiveFile.Name, ArchiveType, ArchiveSign, IncludeHidden); end; end; finally TempFS := nil; FreeAndNil(Files); end; end; end; procedure TestArchive(aFileView: TFileView; aFiles: TFiles; QueueIdentifier: TOperationsManagerQueueIdentifier); var I: Integer; FilesToTest: TFiles = nil; Operation: TFileSourceOperation = nil; ArchiveFileSource: IArchiveFileSource; QueueId: TOperationsManagerQueueIdentifier; begin try // if in archive if aFileView.FileSource.IsClass(TArchiveFileSource) then begin FilesToTest := aFiles.Clone; if fsoTestArchive in aFileView.FileSource.GetOperationsTypes then begin Operation := aFileView.FileSource.CreateTestArchiveOperation(FilesToTest); if Assigned(Operation) then begin // Start operation. OperationsManager.AddOperation(Operation, QueueIdentifier, False, True); end else msgWarning(rsMsgNotImplemented); end else msgWarning(rsMsgErrNotSupported); end else // if filesystem if aFileView.FileSource.IsClass(TFileSystemFileSource) then begin // If archives count > 1 then put to queue if (aFiles.Count > 1) and (QueueIdentifier = FreeOperationsQueueId) then QueueId := OperationsManager.GetNewQueueIdentifier else begin QueueId := QueueIdentifier; end; for I := 0 to aFiles.Count - 1 do // test all selected archives try // Check if there is a ArchiveFileSource for possible archive. ArchiveFileSource := GetArchiveFileSource(aFileView.FileSource, aFiles[i], EmptyStr, False, True); if Assigned(ArchiveFileSource) then begin // Check if List and fsoTestArchive are supported. if [fsoList, fsoTestArchive] * ArchiveFileSource.GetOperationsTypes = [fsoList, fsoTestArchive] then begin // Get files to test. FilesToTest := ArchiveFileSource.GetFiles(ArchiveFileSource.GetRootDir); if Assigned(FilesToTest) then try // test all files Operation := ArchiveFileSource.CreateTestArchiveOperation(FilesToTest); if Assigned(Operation) then begin // Start operation. OperationsManager.AddOperation(Operation, QueueId, False, True); end else msgWarning(rsMsgNotImplemented); finally FreeAndNil(FilesToTest); end; end else msgWarning(rsMsgErrNotSupported); end; except on E: Exception do msgError(E.Message + LineEnding + aFiles[i].FullPath); end; // for end else msgWarning(rsMsgErrNotSupported); finally end; end; function FileIsArchive(const FileName: String): Boolean; begin Result:= TWcxArchiveFileSource.CheckPluginByName(FileName) or TMultiArchiveFileSource.CheckAddonByName(FileName); end; procedure FillAndCount(Files: TFiles; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); procedure FillAndCountRec(const srcPath: String); var J: Integer; aFile: TFile; sr: TSearchRecEx; aFolders: TStringList; begin aFolders:= TStringList.Create; if FindFirstEx(srcPath + '*', 0, sr) = 0 then begin repeat if (sr.Name='.') or (sr.Name='..') then Continue; aFile := TFileSystemFileSource.CreateFile(srcPath, @sr); if aFile.IsLink then begin NewFiles.Add(aFile.Clone); end else if aFile.IsDirectory then begin aFolders.AddObject(srcPath + sr.Name + DirectorySeparator, aFile); end else begin Inc(FilesCount); NewFiles.Add(aFile); FilesSize:= FilesSize + aFile.Size; end; until FindNextEx(sr) <> 0; end; // Process directories for J := 0 to aFolders.Count - 1 do begin NewFiles.Add(TFile(aFolders.Objects[J])); FillAndCountRec(aFolders[J]); // go down to directory end; FindCloseEx(sr); aFolders.Free; end; var I: Integer; aFile: TFile; aFolderList: TStringList; begin FilesSize:= 0; FilesCount:= 0; aFolderList:= TStringList.Create; NewFiles := TFiles.Create(Files.Path); for I := 0 to Files.Count - 1 do begin aFile := Files[I]; if aFile.IsLink then begin NewFiles.Add(aFile.Clone); end else if aFile.IsDirectory then begin aFolderList.AddObject(aFile.Path + aFile.Name + DirectorySeparator, aFile.Clone); end else begin Inc(FilesCount); NewFiles.Add(aFile.Clone); FilesSize:= FilesSize + aFile.Size; // in first level we know file size -> use it end; end; // Process directories for I := 0 to aFolderList.Count - 1 do begin NewFiles.Add(TFile(aFolderList.Objects[I])); FillAndCountRec(aFolderList[I]); // recursive browse child dir end; aFolderList.Free; end; procedure InstallPlugin(const FileName: String); var AFile: TFile; sExt: String; Flags: PtrInt; sType: String; Sfile: String; AFiles: TFiles; Index: Integer; Ini: TIniFileEx; sPlugin: String; sRootName: String; InstallDir: String; sDefaultDir: String; PluginsPath: String; SourceFiles: TFiles; Result: Integer = -1; WcxModule: TWcxModule; WfxModule: TWfxModule; FileSource: IArchiveFileSource; Temp: ITempFileSystemFileSource; Operation: TArchiveCopyOutOperation; begin if FileIsArchive(FileName) then try AFile:= TFileSystemFileSource.CreateFileFromFile(FileName); // Check if there is a ArchiveFileSource for possible archive. FileSource := GetArchiveFileSource(TFileSystemFileSource.GetFileSource, aFile, EmptyStr, False, False); if (FileSource = nil) then raise Exception.Create(rsSimpleWordError); AFiles:= FileSource.GetFiles(PathDelim); try for Index:= 0 to AFiles.Count - 1 do begin sPlugin:= AFiles[Index].Name; if (Length(sPlugin) = 12) and (CompareText(sPlugin, 'pluginst.inf') = 0) then begin SourceFiles:= TFiles.Create(PathDelim); SourceFiles.Add(AFiles[Index].Clone); Temp:= TTempFileSystemFileSource.GetFileSource; Operation:= FileSource.CreateCopyOutOperation(Temp, SourceFiles, Temp.GetRootDir) as TArchiveCopyOutOperation; try Operation.Execute; finally Operation.Free; end; if mbFileExists(Temp.GetRootDir + sPlugin) then begin Ini:= TIniFileEx.Create(Temp.GetRootDir + sPlugin, fmOpenRead); try sFile:= Ini.ReadString('PluginInstall', 'File', EmptyStr); sExt:= Ini.ReadString('PluginInstall', 'DefaultExtension', EmptyStr); sType:= LowerCase(Ini.ReadString('PluginInstall', 'Type', EmptyStr)); sDefaultDir:= ExtractFileName(Ini.ReadString('PluginInstall', 'DefaultDir', ExtractOnlyFileName(sFile))); finally Ini.Free; end; if gUseConfigInProgramDir then PluginsPath:= gpExePath else begin PluginsPath:= IncludeTrailingBackslash(GetAppDataDir); end; PluginsPath += 'plugins' + PathDelim; InstallDir:= PluginsPath + sType + PathDelim + sDefaultDir; // Create plugin target directory if mbForceDirectory(InstallDir) then begin Operation:= FileSource.CreateCopyOutOperation(TFileSystemFileSource.GetFileSource, AFiles, InstallDir) as TArchiveCopyOutOperation; try Operation.Execute; if Operation.Result = fsorAborted then Exit; finally Operation.Free; end; sPlugin:= InstallDir + PathDelim + sFile; if not CheckPlugin(sPlugin) then begin Result:= MaxInt; DelTree(InstallDir); end else if (sType = 'wcx') then begin WcxModule:= gWcxPlugins.LoadModule(sPlugin); if Assigned(WcxModule) then begin Flags:= WcxModule.GetPluginCapabilities; for sExt in SplitString(sExt, ',') do begin Result:= gWcxPlugins.Add(sExt, Flags, sPlugin); gWcxPlugins.FileName[Result]:= GetPluginFilenameToSave(sPlugin); end; end; end else if (sType = 'wdx') then begin Result:= gWdxPlugins.Add(sPlugin); gWdxPlugins.GetWdxModule(Result).FileName:= GetPluginFilenameToSave(sPlugin); end else if (sType = 'wfx') then begin WfxModule:= gWfxPlugins.LoadModule(sPlugin); if Assigned(WfxModule) then begin sRootName:= WfxModule.VFSRootName; if Length(sRootName) = 0 then begin sRootName:= ExtractOnlyFileName(sFile); end; Result:= gWfxPlugins.Add(sRootName, sPlugin); gWfxPlugins.FileName[Result]:= GetPluginFilenameToSave(sPlugin); end; end else if (sType = 'wlx') then begin Result:= gWlxPlugins.Add(sPlugin); gWlxPlugins.GetWlxModule(Result).FileName:= GetPluginFilenameToSave(sPlugin); end; end; end; if (Result >= 0) and (Result < MaxInt) then begin ShowOptions('TfrmOptionsPlugins' + UpCase(sType)); end; Break; end; end; finally AFiles.Free; end; except on E: Exception do begin Result:= 0; msgError(E.Message); end; end; if Result < 0 then begin msgError(rsSimpleWordError); end; end; end. ������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesource.pas����������������������������������������������������0000644�0001750�0000144�00000077665�14743153644�020777� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCStrUtils, syncobjs, LCLProc, URIParser, Menus, uFileSourceOperation, uFileSourceOperationTypes, uFileSourceProperty, uFileProperty, uFile; type TFileSource = class; TFileSourceConnection = class; IFileSource = interface; TFileSourceField = record Content: String; Header: String; Width: Integer; Option: String; Align: TAlignment; end; TFileSourceFields = array of TFileSourceField; TPathsArray = array of string; TFileSourceOperationsClasses = array[TFileSourceOperationType] of TFileSourceOperationClass; TFileSourceReloadEventNotify = procedure(const aFileSource: IFileSource; const ReloadedPaths: TPathsArray) of object; { IFileSource } IFileSource = interface(IInterface) ['{B7F0C4C8-59F6-4A35-A54C-E8242F4AD809}'] function Equals(aFileSource: IFileSource): Boolean; function IsInterface(InterfaceGuid: TGuid): Boolean; function IsClass(ClassType: TClass): Boolean; function GetClass: TFileSource; function GetURI: TURI; function GetClassName: String; function GetRefCount: Integer; function GetFileSystem: String; function GetCurrentAddress: String; function GetCurrentWorkingDirectory: String; function SetCurrentWorkingDirectory(NewDir: String): Boolean; function GetSupportedFileProperties: TFilePropertiesTypes; function GetRetrievableFileProperties: TFilePropertiesTypes; function GetOperationsTypes: TFileSourceOperationTypes; function GetProperties: TFileSourceProperties; function GetFiles(TargetPath: String): TFiles; function GetParentFileSource: IFileSource; procedure SetParentFileSource(NewValue: IFileSource); function CreateFileObject(const APath: String): TFile; function CanRetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes): Boolean; procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); function CreateListOperation(TargetPath: String): TFileSourceOperation; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; function CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; function CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; function CreateCombineOperation(var theSourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; function CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; function CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; function GetOperationClass(OperationType: TFileSourceOperationType): TFileSourceOperationClass; function IsPathAtRoot(Path: String): Boolean; function GetParentDir(sPath : String): String; function GetRootDir(sPath : String): String; overload; function GetRootDir: String; overload; function GetPathType(sPath : String): TPathType; function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; function GetLocalName(var aFile: TFile): Boolean; function CreateDirectory(const Path: String): Boolean; function FileSystemEntryExists(const Path: String): Boolean; function GetDefaultView(out DefaultView: TFileSourceFields): Boolean; function QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; function GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; procedure RemoveOperationFromQueue(Operation: TFileSourceOperation); procedure AddChild(AFileSource: IFileSource); procedure Reload(const PathsToReload: TPathsArray); procedure Reload(const PathToReload: String); procedure AddReloadEventListener(FunctionToCall: TFileSourceReloadEventNotify); procedure RemoveReloadEventListener(FunctionToCall: TFileSourceReloadEventNotify); property URI: TURI read GetURI; property ClassName: String read GetClassName; property FileSystem: String read GetFileSystem; property CurrentAddress: String read GetCurrentAddress; property ParentFileSource: IFileSource read GetParentFileSource write SetParentFileSource; property Properties: TFileSourceProperties read GetProperties; property SupportedFileProperties: TFilePropertiesTypes read GetSupportedFileProperties; property RetrievableFileProperties: TFilePropertiesTypes read GetRetrievableFileProperties; end; { TFileSource } TFileSource = class(TInterfacedObject, IFileSource) private FReloadEventListeners: TMethodList; {en File source on which this file source is dependent on (files that it accesses are on the parent file source). } FParentFileSource: IFileSource; {en Callback called when an operation assigned to a connection finishes. It just redirects to a virtual function. } procedure OperationFinishedCallback(Operation: TFileSourceOperation; State: TFileSourceOperationState); protected FURI: TURI; FCurrentAddress: String; FOperationsClasses: TFileSourceOperationsClasses; {en Children file source list } FChildrenFileSource: TInterfaceList; function GetURI: TURI; {en Retrieves the full address of the file source (the CurrentPath is relative to this). This may be used for specifying address: - archive : path to archive - network : address of server etc. } function GetCurrentAddress: String; virtual; {en Retrieves the current directory of the file source. } function GetCurrentWorkingDirectory: String; virtual; {en Sets the current directory for the file source. @returns(@true if path change was successful, @false otherwise) } function SetCurrentWorkingDirectory(NewDir: String): Boolean; virtual; {en Returns all the properties supported by the file type of the given file source. } function GetSupportedFileProperties: TFilePropertiesTypes; virtual; {en Returns all the file properties that can be retrieved by the file source. } function GetRetrievableFileProperties: TFilePropertiesTypes; virtual; function GetParentFileSource: IFileSource; procedure SetParentFileSource(NewValue: IFileSource); {en Checks if the connection is available and, if it is, assigns it to the operation. @returns(Connection object if the connection is available, @nil otherwise.) } function TryAcquireConnection(connection: TFileSourceConnection; operation: TFileSourceOperation): TFileSourceConnection; virtual; procedure OperationFinished(Operation: TFileSourceOperation); virtual; {en Reloads any internal file lists/caches. @param(PathsToReload Describes paths in file source from which file lists should be reloaded. The function may also reload any subpaths, though that is dependent on the specific file source implementation.) } procedure DoReload(const PathsToReload: TPathsArray); virtual; function CreateFileObject(const APath: String): TFile; public constructor Create; virtual; overload; constructor Create(const URI: TURI); virtual; overload; destructor Destroy; override; function Equals(aFileSource: IFileSource): Boolean; overload; function IsInterface(InterfaceGuid: TGuid): Boolean; function IsClass(aClassType: TClass): Boolean; function GetClass: TFileSource; function GetClassName: String; // For debugging purposes. function GetRefCount: Integer; // For debugging purposes. // Retrieve operations permitted on the source. = capabilities? function GetOperationsTypes: TFileSourceOperationTypes; virtual; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; virtual; // Retrieves a list of files. // This is the same as GetOperation(fsoList), executing it // and returning the result of Operation.ReleaseFiles. // Caller is responsible for freeing the result list. function GetFiles(TargetPath: String): TFiles; virtual; // Create an empty TFile object with appropriate properties for the file. class function CreateFile(const APath: String): TFile; virtual; procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); virtual; function CanRetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes): Boolean; virtual; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; virtual; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; virtual; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; virtual; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; virtual; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; virtual; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; virtual; function CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; virtual; function CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; virtual; function CreateCombineOperation(var theSourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; virtual; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; virtual; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; virtual; function CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; virtual; function CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; virtual; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; virtual; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; virtual; function GetOperationClass(OperationType: TFileSourceOperationType): TFileSourceOperationClass; class function GetMainIcon(out Path: String): Boolean; virtual; {en Returns @true if the given path is supported by the file source, @false otherwise. } class function IsSupportedPath(const Path: String): Boolean; virtual; {en Returns @true if the given path is the root path of the file source, @false otherwise. } function IsPathAtRoot(Path: String): Boolean; virtual; function GetParentDir(sPath : String): String; virtual; function GetRootDir(sPath : String): String; virtual; overload; function GetRootDir: String; virtual; overload; function GetPathType(sPath : String): TPathType; virtual; function GetFileSystem: String; virtual; function CreateDirectory(const Path: String): Boolean; virtual; function FileSystemEntryExists(const Path: String): Boolean; virtual; function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; virtual; function QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; virtual; function GetDefaultView(out DefaultView: TFileSourceFields): Boolean; virtual; function GetLocalName(var aFile: TFile): Boolean; virtual; function GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; virtual; {en This function is to ensure the operation does not stay in the queue when it's being destroyed. } procedure RemoveOperationFromQueue(Operation: TFileSourceOperation); virtual; procedure AddChild(AFileSource: IFileSource); {en Reloads the file list from the file source. This is used if a file source has any internal cache or file list. Overwrite DoReload in descendant classes. } procedure Reload(const PathsToReload: TPathsArray); virtual; overload; procedure Reload(const PathToReload: String); overload; procedure AddReloadEventListener(FunctionToCall: TFileSourceReloadEventNotify); procedure RemoveReloadEventListener(FunctionToCall: TFileSourceReloadEventNotify); property CurrentAddress: String read GetCurrentAddress; property ParentFileSource: IFileSource read GetParentFileSource write SetParentFileSource; property Properties: TFileSourceProperties read GetProperties; property SupportedFileProperties: TFilePropertiesTypes read GetSupportedFileProperties; property RetrievableFileProperties: TFilePropertiesTypes read GetRetrievableFileProperties; end; { TFileSourceConnection } TFileSourceConnection = class private FAssignedOperation: TFileSourceOperation; FOperationLock: TCriticalSection; function GetAssignedOperation: TFileSourceOperation; protected FCurrentPath: String; // Always includes trailing path delimiter. function GetCurrentPath: String; virtual; procedure SetCurrentPath(NewPath: String); virtual; public constructor Create; virtual; destructor Destroy; override; function IsAvailable: Boolean; function Acquire(Operation: TFileSourceOperation): Boolean; procedure Release; property CurrentPath: String read GetCurrentPath write SetCurrentPath; property AssignedOperation: TFileSourceOperation read GetAssignedOperation; end; { TFileSources } TFileSources = class(TInterfaceList) private function Get(I: Integer): IFileSource; public procedure Assign(otherFileSources: TFileSources); property Items[I: Integer]: IFileSource read Get; default; end; { TFileSourceManager } TFileSourceManager = class private FFileSources: TFileSources; // Only allow adding and removing to/from Manager by TFileSource constructor and destructor. procedure Add(aFileSource: IFileSource); procedure Remove(aFileSource: IFileSource); public constructor Create; destructor Destroy; override; function Find(FileSourceClass: TClass; Address: String; CaseSensitive: Boolean = True): IFileSource; end; EFileSourceException = class(Exception); EFileNotFound = class(EFileSourceException) private FFilePath: String; public constructor Create(const AFilePath: string); reintroduce; property FilePath: String read FFilePath; end; var FileSourceManager: TFileSourceManager; implementation uses uDebug, uFileSourceListOperation, uLng; { TFileSource } constructor TFileSource.Create; begin if ClassType = TFileSource then raise Exception.Create('Cannot construct abstract class'); inherited Create; FReloadEventListeners := TMethodList.Create; FileSourceManager.Add(Self); // Increases RefCount // We don't want to count the reference in Manager, because we want to detect // when there are no more references other than this single one in the Manager. // So, we remove this reference here. // When RefCount reaches 0 Destroy gets called and the last remaining reference // (in the Manager) is removed there. InterLockedDecrement(frefcount); DCDebug('Creating ', ClassName); end; constructor TFileSource.Create(const URI: TURI); var AddressURI: TURI; begin Create; FURI:= URI; FillChar(AddressURI, SizeOf(TURI), 0); AddressURI.Protocol:= FURI.Protocol; AddressURI.Username:= FURI.Username; AddressURI.Host:= FURI.Host; AddressURI.Port:= FURI.Port; AddressURI.HasAuthority:= FURI.HasAuthority; FCurrentAddress:= EncodeURI(AddressURI); end; destructor TFileSource.Destroy; begin DCDebug('Destroying ', ClassName, ' when refcount=', DbgS(refcount)); if RefCount <> 0 then begin // There could have been an exception raised in the constructor // in which case RefCount will be 1, so only issue warning if there was no exception. // This will check for any exception, but it's enough for a warning. if not Assigned(ExceptObject) then DCDebug('Error: RefCount <> 0 for ', Self.ClassName); end; if Assigned(FileSourceManager) then begin // Restore reference removed in Create and // remove the instance remaining in Manager. // Increase refcount by 2, because we don't want removing the last instance // from Manager to trigger another Destroy. // RefCount = 0 InterLockedIncrement(frefcount); InterLockedIncrement(frefcount); // RefCount = 2 FileSourceManager.Remove(Self); // RefCount = 1 InterLockedDecrement(frefcount); // RefCount = 0 (back at the final value) end else DCDebug('Error: Cannot remove file source - manager already destroyed!'); FreeAndNil(FChildrenFileSource); FreeAndNil(FReloadEventListeners); inherited Destroy; end; function TFileSource.Equals(aFileSource: IFileSource): Boolean; begin // Both interface variables must be brought to the same interface. Result := (Self as IFileSource) = (aFileSource as IFileSource); end; function TFileSource.IsInterface(InterfaceGuid: TGuid): Boolean; var t: TObject; begin Result := (Self.QueryInterface(InterfaceGuid, t) = S_OK); if Result then _Release; // QueryInterface increases refcount. end; function TFileSource.IsClass(aClassType: TClass): Boolean; begin Result := Self is aClassType; end; function TFileSource.GetClass: TFileSource; begin Result := Self end; function TFileSource.GetClassName: String; begin Result := ClassName; end; function TFileSource.GetRefCount: Integer; begin Result := RefCount; end; function TFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := []; end; function TFileSource.GetProperties: TFileSourceProperties; begin Result := []; end; function TFileSource.GetURI: TURI; begin Result := FURI; end; function TFileSource.GetCurrentAddress: String; begin Result := FCurrentAddress; end; function TFileSource.GetCurrentWorkingDirectory: String; begin Result := ''; end; function TFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin // By default every path setting succeeds. Result := True; end; function TFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := [fpName]; end; function TFileSource.GetRetrievableFileProperties: TFilePropertiesTypes; begin Result := []; end; function TFileSource.GetParentFileSource: IFileSource; begin Result := FParentFileSource; end; procedure TFileSource.SetParentFileSource(NewValue: IFileSource); begin FParentFileSource := NewValue; end; function TFileSource.IsPathAtRoot(Path: String): Boolean; begin Result := (Path = GetRootDir(Path)); end; function TFileSource.GetParentDir(sPath : String): String; begin Result := DCStrUtils.GetParentDir(sPath); end; function TFileSource.GetRootDir(sPath : String): String; begin // Default root is '/'. Override in descendant classes for other. Result := PathDelim; end; function TFileSource.GetRootDir: String; begin Result := GetRootDir(''); end; function TFileSource.GetPathType(sPath : String): TPathType; begin Result := ptNone; if sPath <> '' then begin // Default root is '/'. Override in descendant classes for other. if (sPath[1] = PathDelim) then Result := ptAbsolute else if ( Pos( PathDelim, sPath ) > 0 ) then Result := ptRelative; end; end; function TFileSource.GetFileSystem: String; begin Result:= EmptyStr; end; function TFileSource.CreateDirectory(const Path: String): Boolean; begin Result := False; end; function TFileSource.FileSystemEntryExists(const Path: String): Boolean; begin Result := True; end; function TFileSource.GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; begin Result := False; // not supported by default end; function TFileSource.QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; begin Result:= False; end; function TFileSource.GetDefaultView(out DefaultView: TFileSourceFields): Boolean; begin Result:= False; end; function TFileSource.GetLocalName(var aFile: TFile): Boolean; begin Result:= False; end; // Operations. function TFileSource.GetFiles(TargetPath: String): TFiles; var Operation: TFileSourceOperation; ListOperation: TFileSourceListOperation; begin Result := nil; if fsoList in GetOperationsTypes then begin Operation := CreateListOperation(TargetPath); if Assigned(Operation) then try ListOperation := Operation as TFileSourceListOperation; ListOperation.Execute; Result := ListOperation.ReleaseFiles; finally FreeAndNil(Operation); end; end; end; class function TFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); end; function TFileSource.CreateFileObject(const APath: String): TFile; begin Result := CreateFile(APath); end; procedure TFileSource.RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); begin // Does not set any properties by default. end; function TFileSource.CanRetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes): Boolean; begin Result := ((PropertiesToSet - AFile.AssignedProperties) * RetrievableFileProperties) <> []; end; function TFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateCombineOperation(var theSourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; begin Result:= nil; end; function TFileSource.CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; begin Result := nil; end; function TFileSource.CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; begin Result := nil; end; function TFileSource.GetOperationClass(OperationType: TFileSourceOperationType): TFileSourceOperationClass; begin Result := FOperationsClasses[OperationType]; end; class function TFileSource.GetMainIcon(out Path: String): Boolean; begin Result := False; end; class function TFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= True; end; function TFileSource.GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; begin // By default connections are not supported. Result := nil; end; function TFileSource.TryAcquireConnection(connection: TFileSourceConnection; operation: TFileSourceOperation): TFileSourceConnection; begin if connection.Acquire(operation) then begin // We must know when the operation is finished, // that is when the connection is free again. operation.AddStateChangedListener([fsosStopped], @OperationFinishedCallback); Result := connection; end else begin Result := nil; end; end; procedure TFileSource.RemoveOperationFromQueue(Operation: TFileSourceOperation); begin // Nothing by default. end; procedure TFileSource.AddChild(AFileSource: IFileSource); begin if (FChildrenFileSource = nil) then begin FChildrenFileSource:= TInterfaceList.Create; end else if FChildrenFileSource.Count > 32 then begin FChildrenFileSource.Delete(0); end; FChildrenFileSource.Add(AFileSource); end; procedure TFileSource.OperationFinishedCallback(Operation: TFileSourceOperation; State: TFileSourceOperationState); begin if State = fsosStopped then begin Operation.RemoveStateChangedListener([fsosStopped], @OperationFinishedCallback); OperationFinished(Operation); end; end; procedure TFileSource.OperationFinished(Operation: TFileSourceOperation); begin // Nothing by default. end; procedure TFileSource.DoReload(const PathsToReload: TPathsArray); begin // Nothing by default. end; procedure TFileSource.Reload(const PathsToReload: TPathsArray); var i: Integer; FunctionToCall: TFileSourceReloadEventNotify; begin DoReload(PathsToReload); if Assigned(FReloadEventListeners) then for i := 0 to FReloadEventListeners.Count - 1 do begin FunctionToCall := TFileSourceReloadEventNotify(FReloadEventListeners.Items[i]); FunctionToCall(Self, PathsToReload); end; end; procedure TFileSource.Reload(const PathToReload: String); var PathsToReload: TPathsArray; begin SetLength(PathsToReload, 1); PathsToReload[0] := PathToReload; Reload(PathsToReload); end; procedure TFileSource.AddReloadEventListener(FunctionToCall: TFileSourceReloadEventNotify); begin FReloadEventListeners.Add(TMethod(FunctionToCall)); end; procedure TFileSource.RemoveReloadEventListener(FunctionToCall: TFileSourceReloadEventNotify); begin FReloadEventListeners.Remove(TMethod(FunctionToCall)); end; { TFileSourceConnection } constructor TFileSourceConnection.Create; begin FOperationLock := TCriticalSection.Create; inherited Create; DCDebug('Creating connection ', ClassName); end; destructor TFileSourceConnection.Destroy; begin if Assigned(FAssignedOperation) and (FAssignedOperation.State <> fsosStopped) then DCDebug('Error: Destroying connection ', ClassName, ' with active operation ', FAssignedOperation.ClassName); inherited Destroy; DCDebug('Destroying connection ', ClassName); FreeAndNil(FOperationLock); end; function TFileSourceConnection.GetAssignedOperation: TFileSourceOperation; begin // For just reading lock is probably not needed here. Result := FAssignedOperation; end; function TFileSourceConnection.GetCurrentPath: String; begin Result := FCurrentPath; end; procedure TFileSourceConnection.SetCurrentPath(NewPath: String); begin if NewPath <> '' then NewPath := IncludeTrailingPathDelimiter(NewPath); FCurrentPath := NewPath; end; function TFileSourceConnection.IsAvailable: Boolean; begin Result := (GetAssignedOperation() = nil); end; function TFileSourceConnection.Acquire(Operation: TFileSourceOperation): Boolean; begin FOperationLock.Acquire; try Result := (FAssignedOperation = nil); if Result then FAssignedOperation := Operation; finally FOperationLock.Release; end; end; procedure TFileSourceConnection.Release; begin FOperationLock.Acquire; try FAssignedOperation := nil; finally FOperationLock.Release; end; end; { TFileSources } function TFileSources.Get(I: Integer): IFileSource; begin if (I >= 0) and (I < Count) then Result := inherited Items[I] as IFileSource else Result := nil; end; procedure TFileSources.Assign(otherFileSources: TFileSources); var i: Integer; begin Clear; for i := 0 to otherFileSources.Count - 1 do Add(otherFileSources.Items[i]); end; { TFileSourceManager } constructor TFileSourceManager.Create; begin FFileSources := TFileSources.Create; end; destructor TFileSourceManager.Destroy; var i: Integer; begin if FFileSources.Count > 0 then begin DCDebug('Warning: Destroying manager with existing file sources!'); for i := 0 to FFileSources.Count - 1 do begin // Restore the reference taken in TFileSource.Create before removing // all file sources from the list. FFileSources[i]._AddRef; // Free instance. FFileSources.put(i, nil); end; end; FreeAndNil(FFileSources); inherited Destroy; end; procedure TFileSourceManager.Add(aFileSource: IFileSource); begin if FFileSources.IndexOf(aFileSource) < 0 then begin FFileSources.Add(aFileSource); end else DCDebug('Error: File source already exists in manager!'); end; procedure TFileSourceManager.Remove(aFileSource: IFileSource); begin FFileSources.Remove(aFileSource); end; function TFileSourceManager.Find(FileSourceClass: TClass; Address: String; CaseSensitive: Boolean): IFileSource; var I: Integer; StrCmp: function(const S1, S2: String): Integer; begin if CaseSensitive then StrCmp:= @CompareStr else begin StrCmp:= @CompareText; end; for I := 0 to FFileSources.Count - 1 do begin if (FFileSources[I].IsClass(FileSourceClass)) and (StrCmp(FFileSources[I].CurrentAddress, Address) = 0) then begin Result := FFileSources[I]; Exit; end; end; Result := nil; end; constructor EFileNotFound.Create(const AFilePath: string); begin FFilePath := AFilePath; inherited Create(Format(rsMsgFileNotFound, [aFilePath])); end; initialization FileSourceManager := TFileSourceManager.Create; finalization FreeAndNil(FileSourceManager); end. ���������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcecalcchecksumoperation.pas�������������������������������0000644�0001750�0000144�00000014745�14743153644�025254� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceCalcChecksumOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, DCBasicTypes, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile, uHash; type TCalcCheckSumOperationMode = (checksum_calc, checksum_verify); TVerifyChecksumResult = record Success: TDynamicStringArray; Broken: TDynamicStringArray; Missing: TDynamicStringArray; ReadError: TDynamicStringArray; end; TFileSourceCalcChecksumOperationStatistics = record CurrentFile: String; CurrentFileTotalBytes: Int64; CurrentFileDoneBytes: Int64; TotalFiles: Int64; DoneFiles: Int64; TotalBytes: Int64; DoneBytes: Int64; BytesPerSecond: Int64; RemainingTime: TDateTime; end; {en Operation that calculates checksum of the files. } { TFileSourceCalcChecksumOperation } TFileSourceCalcChecksumOperation = class(TFileSourceOperation) private FStatistics: TFileSourceCalcChecksumOperationStatistics; FStatisticsAtStartTime: TFileSourceCalcChecksumOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FFiles: TFiles; FMode: TCalcCheckSumOperationMode; FTargetPath: String; FTargetMask: String; FAlgorithm: THashAlgorithm; FOneFile: Boolean; FOpenFileAfterOperationCompleted: Boolean; protected FResult: TVerifyChecksumResult; FTextLineBreakStyle: TTextLineBreakStyle; function GetID: TFileSourceOperationType; override; procedure UpdateStatistics(var NewStatistics: TFileSourceCalcChecksumOperationStatistics); procedure UpdateStatisticsAtStartTime; override; procedure DoReloadFileSources; override; property FileSource: IFileSource read FFileSource; property Files: TFiles read FFiles; property TargetPath: String read FTargetPath; property TargetMask: String read FTargetMask; public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles; aTargetPath: String; aTargetMask: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceCalcChecksumOperationStatistics; property Mode: TCalcCheckSumOperationMode read FMode write FMode; property Algorithm: THashAlgorithm read FAlgorithm write FAlgorithm; property OneFile: Boolean read FOneFile write FOneFile; property TextLineBreakStyle: TTextLineBreakStyle read FTextLineBreakStyle write FTextLineBreakStyle; property OpenFileAfterOperationCompleted: Boolean read FOpenFileAfterOperationCompleted write FOpenFileAfterOperationCompleted; property Result: TVerifyChecksumResult read FResult; end; implementation uses uDCUtils, uLng, uShowForm; constructor TFileSourceCalcChecksumOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles; aTargetPath: String; aTargetMask: String); begin with FStatistics do begin CurrentFile := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; FFiles := theFiles; theFiles := nil; FTargetPath := aTargetPath; FTargetMask := aTargetMask; FMode := checksum_calc; FAlgorithm := HASH_MD5; FOneFile := False; FOpenFileAfterOperationCompleted := FALSE; end; destructor TFileSourceCalcChecksumOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FFiles) then FreeAndNil(FFiles); end; function TFileSourceCalcChecksumOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Mode of checksum_calc: case Details of fsoddJobAndTarget: begin if Files.Count = 1 then Result := Format(rsOperCalculatingCheckSumOf, [Files[0].FullPath]) else Result := Format(rsOperCalculatingCheckSumIn, [Files.Path]); end; else Result := rsOperCalculatingCheckSum; end; checksum_verify: case Details of fsoddJobAndTarget: begin if Files.Count = 1 then Result := Format(rsOperVerifyingCheckSumOf, [Files[0].FullPath]) else Result := Format(rsOperVerifyingCheckSumIn, [Files.Path]); end; else Result := rsOperVerifyingCheckSum; end; else Result := inherited GetDescription(Details); end; end; function TFileSourceCalcChecksumOperation.GetID: TFileSourceOperationType; begin Result := fsoCalcChecksum; end; procedure TFileSourceCalcChecksumOperation.UpdateStatistics( var NewStatistics: TFileSourceCalcChecksumOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, DoneBytes, TotalBytes, StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalFiles <> 0 then UpdateProgress(DoneBytes/TotalBytes); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceCalcChecksumOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceCalcChecksumOperation.RetrieveStatistics: TFileSourceCalcChecksumOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceCalcChecksumOperation.DoReloadFileSources; begin if OneFile AND OpenFileAfterOperationCompleted then ShowViewerByGlob(TargetMask); end; end. ���������������������������doublecmd-1.1.22/src/filesources/ufilesourcecalcstatisticsoperation.pas�����������������������������0000644�0001750�0000144�00000011361�14743153644�025633� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSourceOperationOptions, uFileSource, uFileProperty, uFile; type TFileSourceCalcStatisticsOperationStatistics = record SupportedProperties: TFilePropertiesTypes; CurrentFile: String; Files: Int64; // only files, i.e., not directories Directories: Int64; Links: Int64; Size: Int64; // total size of all the files CompressedSize: Int64; // if fpCompressedSize supported OldestFile: TDateTime; // if fpModificationTime (or fpDateTime) supported NewestFile: TDateTime; FilesPerSecond: Int64; // Maybe some other: // SystemFiles // ReadOnlyFiles // ExecutableFiles end; {en Operation that calculates several statistics for a directory tree. } { TFileSourceCalcStatisticsOperation } TFileSourceCalcStatisticsOperation = class(TFileSourceOperation) private FStatistics: TFileSourceCalcStatisticsOperationStatistics; FStatisticsAtStartTime: TFileSourceCalcStatisticsOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FFiles: TFiles; protected // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; FSkipErrors: Boolean; function GetID: TFileSourceOperationType; override; procedure UpdateStatistics(var NewStatistics: TFileSourceCalcStatisticsOperationStatistics); procedure UpdateStatisticsAtStartTime; override; property FileSource: IFileSource read FFileSource; property Files: TFiles read FFiles; public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceCalcStatisticsOperationStatistics; property SymLinkOption: TFileSourceOperationOptionSymLink read FSymLinkOption write FSymLinkOption; property SkipErrors: Boolean read FSkipErrors write FSkipErrors; end; implementation uses uGlobs, uDCUtils, uLng; constructor TFileSourceCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin with FStatistics do begin SupportedProperties := aTargetFileSource.SupportedFileProperties; CurrentFile := ''; Files := 0; Directories := 0; Links := 0; Size := 0; CompressedSize := 0; // if fpCompressedSize supported OldestFile := 0; NewestFile := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; FFiles := theFiles; theFiles := nil; FSymLinkOption := fsooslNone; FSkipErrors := gSkipFileOpError; end; destructor TFileSourceCalcStatisticsOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FFiles) then FreeAndNil(FFiles); end; function TFileSourceCalcStatisticsOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperCalculatingStatisticsIn, [Files.Path]); else Result := rsOperCalculatingStatictics; end; end; function TFileSourceCalcStatisticsOperation.GetID: TFileSourceOperationType; begin Result := fsoCalcStatistics; end; procedure TFileSourceCalcStatisticsOperation.UpdateStatistics( var NewStatistics: TFileSourceCalcStatisticsOperationStatistics); begin FStatisticsLock.Acquire; try // Cannot determine progress or remaining time for this operation. // Only calculate speed. EstimateRemainingTime(FStatisticsAtStartTime.Files, NewStatistics.Files, 0, // unknown StartTime, SysUtils.Now, NewStatistics.FilesPerSecond); FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceCalcStatisticsOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceCalcStatisticsOperation.RetrieveStatistics: TFileSourceCalcStatisticsOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcecombineoperation.pas������������������������������������0000644�0001750�0000144�00000013527�14743153644�024240� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceCombineOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile, uFileSourceCopyOperation; type TFileSourceCombineOperationStatistics = TFileSourceCopyOperationStatistics; {en Operation that combine files within the same file source. } { TFileSourceCombineOperation } TFileSourceCombineOperation = class(TFileSourceOperation) private FStatistics: TFileSourceCombineOperationStatistics; FStatisticsAtStartTime: TFileSourceCombineOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FSourceFiles: TFiles; FTargetFile: String; FRequireDynamicMode, FWeGotTheCRC32VerificationFile: boolean; FExpectedCRC32: dword; FCurrentCRC32: dword; protected function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceCombineOperationStatistics); procedure UpdateStatisticsAtStartTime; override; property FileSource: IFileSource read FFileSource; property SourceFiles: TFiles read FSourceFiles; property TargetFile: String read FTargetFile write FTargetFile; //FTargetFile might be written when in "RequireDynamicMode" public {en @param(aFileSource File source within which the operation should take place. Class takes ownership of the pointer.) @param(theSourceFiles Files which are to be combined. Class takes ownership of the pointer.) @param(aTargetFile Target name of combined file.) } constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetFile: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceCombineOperationStatistics; property RequireDynamicMode: boolean read FRequireDynamicMode write FRequireDynamicMode; property CurrentCRC32: dword read FCurrentCRC32 write FCurrentCRC32; property ExpectedCRC32: dword read FExpectedCRC32 write FExpectedCRC32; property WeGotTheCRC32VerificationFile: boolean read FWeGotTheCRC32VerificationFile write FWeGotTheCRC32VerificationFile; end; implementation uses uDCUtils, uLng; // -- TFileSourceCombineOperation ------------------------------------------------ constructor TFileSourceCombineOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetFile: String); begin with FStatistics do begin CurrentFileFrom := ''; CurrentFileTo := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; CurrentFileTotalBytes := 0; CurrentFileDoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; RequireDynamicMode := FALSE; // By default, DC mode which means user selected ALL the files. ExpectedCRC32 := $00000000; // By default, the expected CRC32 is 0, which is undefined CurrentCRC32 := $00000000; // Initial value of CRC32 WeGotTheCRC32VerificationFile := FALSE; // By default, we still don't have in hand info from summary file end; FStatisticsLock := TCriticalSection.Create; inherited Create(aFileSource); FFileSource := aFileSource; FSourceFiles := theSourceFiles; theSourceFiles := nil; FTargetFile := aTargetFile; end; destructor TFileSourceCombineOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FSourceFiles) then FreeAndNil(FSourceFiles); end; procedure TFileSourceCombineOperation.UpdateStatistics(var NewStatistics: TFileSourceCombineOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, DoneBytes, TotalBytes, StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalBytes <> 0 then UpdateProgress(DoneBytes/TotalBytes); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceCombineOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceCombineOperation.RetrieveStatistics: TFileSourceCombineOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceCombineOperation.GetID: TFileSourceOperationType; begin Result := fsoCombine; end; procedure TFileSourceCombineOperation.DoReloadFileSources; var Paths: TPathsArray; begin SetLength(Paths, 1); Paths[0] := ExtractFilePath(FTargetFile); // Combine target path FFileSource.Reload(Paths); end; function TFileSourceCombineOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperCombiningFromTo, [SourceFiles.Path, TargetFile]); else Result := rsOperCombining; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcecopyoperation.pas���������������������������������������0000644�0001750�0000144�00000022576�14743153644�023602� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceCopyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, DCOSUtils, uFileSourceOperation, uFileSourceOperationTypes, uFileSourceOperationOptions, uFileSource, uFile; type // Statistics are the same for CopyIn and CopyOut operations. PFileSourceCopyOperationStatistics = ^TFileSourceCopyOperationStatistics; TFileSourceCopyOperationStatistics = record CurrentFileFrom: String; CurrentFileTo: String; CurrentFileTotalBytes: Int64; CurrentFileDoneBytes: Int64; TotalFiles: Int64; DoneFiles: Int64; TotalBytes: Int64; DoneBytes: Int64; BytesPerSecond: Int64; RemainingTime: TDateTime; end; {en Base class for CopyIn and CopyOut operations. } { TFileSourceCopyOperation } TFileSourceCopyOperation = class(TFileSourceOperation) private FStatistics: TFileSourceCopyOperationStatistics; FStatisticsAtStartTime: TFileSourceCopyOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FSourceFileSource: IFileSource; FTargetFileSource: IFileSource; FSourceFiles: TFiles; FRenameMask: String; protected FTargetPath: String; FCopyAttributesOptions: TCopyAttributesOptions; FSymLinkOption: TFileSourceOperationOptionSymLink; FFileExistsOption: TFileSourceOperationOptionFileExists; FDirExistsOption: TFileSourceOperationOptionDirectoryExists; protected function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceCopyOperationStatistics); procedure UpdateStatisticsAtStartTime; override; procedure ShowCompareFilesUI(SourceFile: TFile; const TargetFilePath: String); procedure ShowCompareFilesUIByFileObject(SourceFile: TFile; TargetFile: TFile); property TargetPath: String read FTargetPath; public {en @param(aSourceFileSource File source from which the files will be copied.) @param(aTargetFileSource File source to which the files will be copied.) @param(theSourceFiles Files which are to be copied. Class takes ownership of the pointer.) @param(aTargetPath Path in the target file source where the files should be copied to.) } constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceCopyOperationStatistics; property SourceFiles: TFiles read FSourceFiles; property SourceFileSource: IFileSource read FSourceFileSource; property TargetFileSource: IFileSource read FTargetFileSource; property RenameMask: String read FRenameMask write FRenameMask; property SymLinkOption: TFileSourceOperationOptionSymLink read FSymLinkOption write FSymLinkOption; property FileExistsOption: TFileSourceOperationOptionFileExists read FFileExistsOption write FFileExistsOption; property CopyAttributesOptions: TCopyAttributesOptions read FCopyAttributesOptions write FCopyAttributesOptions; property DirExistsOption: TFileSourceOperationOptionDirectoryExists read FDirExistsOption write FDirExistsOption; end; {en Operation that copies files from another file source into a file source of specific type (to file system for TFileSystemCopyInOperation, to network for TNetworkCopyInOperation, etc.). Source file source must be a file system file source. (Or is it enough if it's a file source with directly accessible files ? (DirectAccess flag)) Target file source should match the class type. Example meaning of this operation: - archive: pack - network: upload } TFileSourceCopyInOperation = class(TFileSourceCopyOperation) protected function GetID: TFileSourceOperationType; override; end; {en Operation that copies files into another file source from a file source of specific type (from file system for TFileSystemCopyOutOperation, from network for TNetworkCopyOutOperation, etc.). Source file source should match the class type. Target file source must be a file system file source. (Or is it enough if it's a file source with directly accessible files ? (DirectAccess flag)) Example meaning of this operation: - archive: unpack - network: download } TFileSourceCopyOutOperation = class(TFileSourceCopyOperation) protected function GetID: TFileSourceOperationType; override; end; implementation uses uDCUtils, uLng, uGlobs, uShowForm; // -- TFileSourceCopyOperation ------------------------------------------------ constructor TFileSourceCopyOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin with FStatistics do begin CurrentFileFrom := ''; CurrentFileTo := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; CurrentFileTotalBytes := 0; CurrentFileDoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; case GetID of fsoCopy, fsoCopyIn: // Copy into target - run on target. inherited Create(aTargetFileSource); fsoCopyOut: // Copy out from source - run on source. inherited Create(aSourceFileSource); else raise Exception.Create('Invalid file source type'); end; FSourceFileSource := aSourceFileSource; FTargetFileSource := aTargetFileSource; FSourceFiles := theSourceFiles; theSourceFiles := nil; FTargetPath := IncludeTrailingPathDelimiter(aTargetPath); FRenameMask := ''; if gOperationOptionCopyTime then FCopyAttributesOptions := FCopyAttributesOptions + [caoCopyTime]; end; destructor TFileSourceCopyOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FSourceFiles) then FreeAndNil(FSourceFiles); end; function TFileSourceCopyOperation.GetID: TFileSourceOperationType; begin Result:= fsoCopy; end; procedure TFileSourceCopyOperation.DoReloadFileSources; begin FTargetFileSource.Reload(FTargetPath); end; function TFileSourceCopyOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if SourceFiles.Count = 1 then Result := Format(rsOperCopyingSomethingTo, [SourceFiles[0].Name, TargetPath]) else Result := Format(rsOperCopyingFromTo, [SourceFiles.Path, TargetPath]); end; else Result := rsOperCopying; end; end; procedure TFileSourceCopyOperation.UpdateStatistics(var NewStatistics: TFileSourceCopyOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, Abs(DoneBytes), Abs(TotalBytes), StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalBytes <> 0 then UpdateProgress(Abs(DoneBytes / TotalBytes)); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceCopyOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceCopyOperation.RetrieveStatistics: TFileSourceCopyOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceCopyOperation.ShowCompareFilesUIByFileObject(SourceFile: TFile; TargetFile: TFile); begin PrepareToolData(SourceFileSource, SourceFile, TargetFileSource, TargetFile, @ShowDifferByGlobList, True); end; procedure TFileSourceCopyOperation.ShowCompareFilesUI(SourceFile: TFile; const TargetFilePath: String); var TargetFile: TFile = nil; begin TargetFile := TargetFileSource.CreateFileObject(ExtractFilePath(TargetFilePath)); TargetFile.Name := ExtractFileName(TargetFilePath); try PrepareToolData(SourceFileSource, SourceFile, TargetFileSource, TargetFile, @ShowDifferByGlobList, True); finally TargetFile.Free; end; end; // -- TFileSourceCopyInOperation ---------------------------------------------- function TFileSourceCopyInOperation.GetID: TFileSourceOperationType; begin Result := fsoCopyIn; end; // -- TFileSourceCopyOutOperation --------------------------------------------- function TFileSourceCopyOutOperation.GetID: TFileSourceOperationType; begin Result := fsoCopyOut; end; end. ����������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcecreatedirectoryoperation.pas����������������������������0000644�0001750�0000144�00000005655�14743153644�026017� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceCreateDirectoryOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceOperationTypes, uFileSource; type { TFileSourceCreateDirectoryOperation } TFileSourceCreateDirectoryOperation = class(TFileSourceOperation) private FFileSource: IFileSource; FBasePath: String; FDirectoryPath: String; FAbsolutePath: String; FRelativePath: String; protected function GetID: TFileSourceOperationType; override; procedure UpdateStatisticsAtStartTime; override; procedure DoReloadFileSources; override; property BasePath: String read FBasePath; property DirectoryPath: String read FDirectoryPath; property AbsolutePath: String read FAbsolutePath; property RelativePath: String read FRelativePath; public {en @param(aTargetFileSource File source where the directory should be created.) @param(aCurrentPath Absolute path to current directory where the new directory should be created (if its path is not absolute).) @param(aDirectoryPath Absolute or relative (to TargetFileSource.CurrentPath) path to a directory that should be created.) } constructor Create(aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; end; implementation uses DCStrUtils, uLng; constructor TFileSourceCreateDirectoryOperation.Create( aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); begin inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; FBasePath := aCurrentPath; FDirectoryPath := aDirectoryPath; if FFileSource.GetPathType(FDirectoryPath) = ptAbsolute then begin FAbsolutePath := FDirectoryPath; FRelativePath := ExtractDirLevel(aCurrentPath, FDirectoryPath); end else begin FAbsolutePath := aCurrentPath + FDirectoryPath; FRelativePath := FDirectoryPath; end; end; destructor TFileSourceCreateDirectoryOperation.Destroy; begin inherited Destroy; end; procedure TFileSourceCreateDirectoryOperation.UpdateStatisticsAtStartTime; begin // empty end; function TFileSourceCreateDirectoryOperation.GetID: TFileSourceOperationType; begin Result := fsoCreateDirectory; end; procedure TFileSourceCreateDirectoryOperation.DoReloadFileSources; begin FFileSource.Reload(FFileSource.GetParentDir(FAbsolutePath)); end; function TFileSourceCreateDirectoryOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperCreatingSomeDirectory, [AbsolutePath]); else Result := rsOperCreatingDirectory; end; end; end. �����������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcedeleteoperation.pas�������������������������������������0000644�0001750�0000144�00000011046�14743153644�024060� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile; type PFileSourceDeleteOperationStatistics = ^TFileSourceDeleteOperationStatistics; TFileSourceDeleteOperationStatistics = record CurrentFile: String; TotalFiles: Int64; DoneFiles: Int64; TotalBytes: Int64; DoneBytes: Int64; FilesPerSecond: Int64; RemainingTime: TDateTime; end; {en Operation that deletes files from an arbitrary file source. File source should match the class type. } { TFileSourceDeleteOperation } TFileSourceDeleteOperation = class(TFileSourceOperation) private FStatistics: TFileSourceDeleteOperationStatistics; FStatisticsAtStartTime: TFileSourceDeleteOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FFilesToDelete: TFiles; protected function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceDeleteOperationStatistics); procedure UpdateStatisticsAtStartTime; override; property FileSource: IFileSource read FFileSource; property FilesToDelete: TFiles read FFilesToDelete; public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceDeleteOperationStatistics; end; implementation uses uDCUtils, uLng; constructor TFileSourceDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin with FStatistics do begin CurrentFile := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; FilesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; aTargetFileSource := nil; FFilesToDelete := theFilesToDelete; theFilesToDelete := nil; end; destructor TFileSourceDeleteOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FFilesToDelete) then FreeAndNil(FFilesToDelete); end; function TFileSourceDeleteOperation.GetID: TFileSourceOperationType; begin Result := fsoDelete; end; procedure TFileSourceDeleteOperation.DoReloadFileSources; begin FFileSource.Reload(FFilesToDelete.Path); end; function TFileSourceDeleteOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if FilesToDelete.Count = 1 then Result := Format(rsOperDeletingSomething, [FilesToDelete[0].FullPath]) else Result := Format(rsOperDeletingIn, [FilesToDelete.Path]); end; else Result := rsOperDeleting; end; end; procedure TFileSourceDeleteOperation.UpdateStatistics(var NewStatistics: TFileSourceDeleteOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneFiles <> NewStatistics.DoneFiles then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneFiles, DoneFiles, TotalFiles, StartTime, SysUtils.Now, FilesPerSecond); // Update overall progress. if TotalFiles <> 0 then UpdateProgress(DoneFiles/TotalFiles); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceDeleteOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceDeleteOperation.RetrieveStatistics: TFileSourceDeleteOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceexecuteoperation.pas������������������������������������0000644�0001750�0000144�00000007015�14743153644�024261� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile; type TFileSourceExecuteOperationResult = (fseorSuccess, //<en the command was executed successfully fseorError, //<en execution failed fseorCancelled, //<en cancelled by user (nothing happened) fseorYourSelf, //<en DC should download/extract the file and execute it locally fseorWithAll, //<en DC should download/extract all files and execute chosen file locally fseorSymLink); //<en this was a (symbolic) link or .lnk file pointing to a different directory { TFileSourceExecuteOperation } TFileSourceExecuteOperation = class(TFileSourceOperation) private FFileSource: IFileSource; FCurrentPath: String; FExecutableFile: TFile; FAbsolutePath: String; FRelativePath: String; FVerb: String; protected FResultString: String; FExecuteOperationResult: TFileSourceExecuteOperationResult; function GetID: TFileSourceOperationType; override; procedure UpdateStatisticsAtStartTime; override; procedure DoReloadFileSources; override; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; property CurrentPath: String read FCurrentPath; property ExecutableFile: TFile read FExecutableFile; property ResultString: String read FResultString write FResultString; property AbsolutePath: String read FAbsolutePath; property RelativePath: String read FRelativePath; property Verb: String read FVerb; property ExecuteOperationResult: TFileSourceExecuteOperationResult read FExecuteOperationResult; end; implementation uses uLng; constructor TFileSourceExecuteOperation.Create( aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; FCurrentPath := aCurrentPath; FExecutableFile := aExecutableFile; aExecutableFile := nil; FVerb := aVerb; FExecuteOperationResult := fseorCancelled; FAbsolutePath := FExecutableFile.FullPath; FRelativePath := FExecutableFile.Name; end; destructor TFileSourceExecuteOperation.Destroy; begin inherited Destroy; FreeAndNil(FExecutableFile); end; procedure TFileSourceExecuteOperation.UpdateStatisticsAtStartTime; begin // empty end; function TFileSourceExecuteOperation.GetID: TFileSourceOperationType; begin Result := fsoExecute; end; procedure TFileSourceExecuteOperation.DoReloadFileSources; begin if FExecuteOperationResult <> fseorCancelled then FFileSource.Reload(FCurrentPath); end; function TFileSourceExecuteOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperExecutingSomething, [ExecutableFile.Name]); else Result := rsOperExecuting; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcelistoperation.pas���������������������������������������0000644�0001750�0000144�00000004070�14743153644�023570� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uFileSourceOperationTypes, uFile, uFileSource; type { TFileSourceListOperation } TFileSourceListOperation = class(TFileSourceOperation) private FFileSource: IFileSource; FPath: String; protected FFiles: TFiles; FFlatView: Boolean; function GetFiles: TFiles; function GetID: TFileSourceOperationType; override; procedure UpdateStatisticsAtStartTime; override; property FileSource: IFileSource read FFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; // Retrieves files and revokes ownership of TFiles list. // The result of this function should be freed by the caller. function ReleaseFiles: TFiles; property Files: TFiles read GetFiles; property Path: String read FPath; property FlatView: Boolean write FFlatView; end; implementation uses uLng; constructor TFileSourceListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFileSource := aFileSource; FPath := aPath; inherited Create(FFileSource); end; destructor TFileSourceListOperation.Destroy; begin inherited Destroy; if Assigned(FFiles) then FreeAndNil(FFiles); end; function TFileSourceListOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperListingIn, [Path]); else Result := rsOperListing; end; end; function TFileSourceListOperation.GetID: TFileSourceOperationType; begin Result := fsoList; end; function TFileSourceListOperation.GetFiles: TFiles; begin Result := FFiles; end; function TFileSourceListOperation.ReleaseFiles: TFiles; begin Result := FFiles; FFiles := nil; // revoke ownership end; procedure TFileSourceListOperation.UpdateStatisticsAtStartTime; begin // Empty. end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcemoveoperation.pas���������������������������������������0000644�0001750�0000144�00000014767�14743153644�023601� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceMoveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSourceOperationOptions, uFileSource, uFile, uFileSourceCopyOperation; type TFileSourceMoveOperationStatistics = TFileSourceCopyOperationStatistics; {en Operation that moves or renames files within the same file source (for example: in the same archive, in the same ftp server). } { TFileSourceMoveOperation } TFileSourceMoveOperation = class(TFileSourceOperation) private FStatistics: TFileSourceMoveOperationStatistics; FStatisticsAtStartTime: TFileSourceMoveOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FSourceFiles: TFiles; FTargetPath: String; FRenameMask: String; protected FFileExistsOption: TFileSourceOperationOptionFileExists; FDirExistsOption: TFileSourceOperationOptionDirectoryExists; protected function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceMoveOperationStatistics); procedure UpdateStatisticsAtStartTime; override; procedure ShowCompareFilesUI(SourceFile: TFile; const TargetFilePath: String); procedure ShowCompareFilesUIByFileObject(SourceFile: TFile; TargetFile: TFile); property FileSource: IFileSource read FFileSource; property SourceFiles: TFiles read FSourceFiles; property TargetPath: String read FTargetPath; public {en @param(aFileSource File source within which the operation should take place. Class takes ownership of the pointer.) @param(theSourceFiles Files which are to be moved. Class takes ownership of the pointer.) @param(aTargetPath Path in the file source where the files should be moved.) } constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceMoveOperationStatistics; property RenameMask: String read FRenameMask write FRenameMask; property FileExistsOption: TFileSourceOperationOptionFileExists read FFileExistsOption write FFileExistsOption; property DirExistsOption: TFileSourceOperationOptionDirectoryExists read FDirExistsOption write FDirExistsOption; end; implementation uses uDCUtils, uLng, uShowForm; // -- TFileSourceMoveOperation ------------------------------------------------ constructor TFileSourceMoveOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin with FStatistics do begin CurrentFileFrom := ''; CurrentFileTo := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; CurrentFileTotalBytes := 0; CurrentFileDoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aFileSource); FFileSource := aFileSource; FSourceFiles := theSourceFiles; theSourceFiles := nil; FTargetPath := IncludeTrailingPathDelimiter(aTargetPath); FRenameMask := ''; end; destructor TFileSourceMoveOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FSourceFiles) then FreeAndNil(FSourceFiles); end; procedure TFileSourceMoveOperation.UpdateStatistics(var NewStatistics: TFileSourceMoveOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, DoneBytes, TotalBytes, StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalBytes <> 0 then UpdateProgress(DoneBytes/TotalBytes); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceMoveOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceMoveOperation.RetrieveStatistics: TFileSourceMoveOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceMoveOperation.ShowCompareFilesUIByFileObject(SourceFile: TFile; TargetFile: TFile); begin PrepareToolData(FFileSource, SourceFile, FFileSource, TargetFile, @ShowDifferByGlobList, True); end; procedure TFileSourceMoveOperation.ShowCompareFilesUI(SourceFile: TFile; const TargetFilePath: String); var TargetFile: TFile = nil; begin TargetFile := FFileSource.CreateFileObject(ExtractFilePath(TargetFilePath)); TargetFile.Name := ExtractFileName(TargetFilePath); try PrepareToolData(FFileSource, SourceFile, FFileSource, TargetFile, @ShowDifferByGlobList, True); finally TargetFile.Free; end; end; function TFileSourceMoveOperation.GetID: TFileSourceOperationType; begin Result := fsoMove; end; procedure TFileSourceMoveOperation.DoReloadFileSources; var Paths: TPathsArray; begin SetLength(Paths, 2); Paths[0] := FSourceFiles.Path; // Move source path Paths[1] := FTargetPath; // Move target path FFileSource.Reload(Paths); end; function TFileSourceMoveOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if SourceFiles.Count = 1 then Result := Format(rsOperMovingSomethingTo, [SourceFiles[0].Name, TargetPath]) else Result := Format(rsOperMovingFromTo, [SourceFiles.Path, TargetPath]); end; else Result := rsOperMoving; end; end; end. ���������doublecmd-1.1.22/src/filesources/ufilesourceoperation.pas�������������������������������������������0000644�0001750�0000144�00000114461�14743153644�022702� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceOperation; {$mode objfpc}{$H+} // If defined causes to synchronize executing callback for events. // This ensures that the callbacks always have the operation in the current state, // which might be safer, but it is slower because the operation must wait // until all callbacks are executed. // If undefined then all events are sent asynchronously, which is faster. // However, it may result in those events to be reported much later after // they have happened in the operation and the operation state might // not be valid anymore. //{$DEFINE fsoSynchronizeEvents} // If defined it will only send one event and will not send more // until that event is processed (so some events may be lost). // This normally shouldn't be defined. //{$DEFINE fsoSendOnlyCurrentState} //{$DEFINE debugFileSourceOperation} interface uses Classes, SysUtils, syncobjs, uLng, uFileSourceOperationOptionsUI, uFileSourceOperationTypes, uFileSourceOperationUI, uFile; type TFileSourceOperationState = (fsosNotStarted, //<en before operation has started fsosStarting, //<en responded to Start command fsosRunning, fsosPausing, //<en responded to Pause command fsosPaused, fsosWaitingForFeedback, //<en waiting for a response from a user through the assigned UI fsosWaitingForConnection, //<en waiting for an available connection to TFileSource fsosStopping, //<en responded to Stop command fsosStopped); //<en finished due to Stop command or on its own TFileSourceOperationStates = set of TFileSourceOperationState; const fsosAllStates = [Low(TFileSourceOperationState) .. High(TFileSourceOperationState)]; type TFileSourceOperationResult = (fsorFinished, //<en operation has finished successfully fsorAborted); //<en operation has been aborted by user TFileSourceOperationDescriptionDetails = (fsoddJob, //<en What the operation is supposed to be doing in general: copying, deleting, etc. fsoddJobAndTarget); //<en Job + on what the operation works: copying from /path to /path2, deleting from /path, etc. const FileSourceOperationStateText: array[TFileSourceOperationState] of string = (rsOperNotStarted, rsOperStarting, rsOperRunning, rsOperPausing, rsOperPaused, rsOperWaitingForFeedback, rsOperWaitingForConnection, rsOperStopping, rsOperStopped); FileSourceOperationResultText: array[TFileSourceOperationResult] of string = (rsOperFinished, rsOperAborted); type TFileSourceOperation = class; TFileSourceOperationStateChangedNotify = procedure(Operation: TFileSourceOperation; State: TFileSourceOperationState) of object; TAskQuestionFunction = function(Msg: String; Question: String; PossibleResponses: array of TFileSourceOperationUIResponse; DefaultOKResponse: TFileSourceOperationUIResponse; DefaultCancelResponse: TFileSourceOperationUIAnswer; ActionHandler: TFileSourceOperationUIActionHandler = nil ) : TFileSourceOperationUIAnswer of object; TAbortOperationFunction = procedure of object; TCheckOperationStateFunction = procedure of object; TAppProcessMessagesFunction = function(CheckState: Boolean = False): Boolean of object; TShowCompareFilesUIFunction = procedure(SourceFile: TFile; const TargetFilePath: String) of object; TShowCompareFilesUIByFileObjectFunction = procedure(SourceFile: TFile; TargetFile: TFile) of object; TFileSourceOperationClass = class of TFileSourceOperation; {en Base class for each file source operation. } { TFileSourceOperation } TFileSourceOperation = class private { Progress and StopReason don't need synchronization, because they are written to from a single thread only (operation running thread) and just read from other threads. DesiredState works the other way around. It is written to only by the GUI thread and read from only by the operation running thread, so also no synchronization needed. State must by synchronized as its written to by both threads. } {en General progress of the operation (0 - 100 %). Specific statistics are returned by the individual operations. } FProgress: Double; FDesiredState: TFileSourceOperationState; FOperationResult: TFileSourceOperationResult; FState: TFileSourceOperationState; FStateLock: TCriticalSection; {en This event is used to wait for start and wait for unpausing. } FPauseEvent: TSimpleEvent; {en This event is used to wait for an available connection to TFileSource. } FConnectionAvailableEvent: TSimpleEvent; {en A list of listeners of state-changed event. Must be synchronized using FEventsLock. } FStateChangedEventListeners: TFPList; {en Used to synchronize access to: - FStateChangedEventListeners - FScheduledEventsListenersCalls - FNoEventsListenersCallsScheduledEvent } FEventsLock: TCriticalSection; {en The thread that runs this operation. It is used for synchronizing events (notifying of them from the main thread). } FThread: TThread; {$IFNDEF fsoSynchronizeEvents} {en How many events are scheduled to execute. } FScheduledEventsListenersCalls: Integer; {en Before finishing, the operation waits for this event, so that it doesn't finish until all scheduled calls to CallEventsListeners are made. } FNoEventsListenersCallsScheduledEvent: PRTLEvent; {$ENDIF} {en List of assigned user interfaces that operation can use to ask user questions. Don't access this list from the operation thread. } FUserInterfaces: TFPList; // of TFileSourceOperationUI {en Event used to notify operation thread that an UI was assigned, so it can wake up and ask questions. } FUserInterfaceAssignedEvent: PRTLEvent; // Parameters for UI question. // Used to pass from operation thread to GUI thread. FUIMessage: String; FUIQuestion: String; FUIPossibleResponses: array of TFileSourceOperationUIResponse; FUIDefaultOKResponse: TFileSourceOperationUIResponse; FUIDefaultCancelResponse: TFileSourceOperationUIAnswer; FUIActionHandler: TFileSourceOperationUIActionHandler; FUIResponse: TFileSourceOperationUIAnswer; FTryAskQuestionResult: Boolean; {en Used to determine whether the operation has started or not. } FOperationInitialized : Boolean; {en Last start time (when operation started or resumed after pause). } FStartTime: TDateTime; {en File source on which this operation is executed. } FFileSource: IInterface; {en Execute operation elevated. } FElevate: TDuplicates; // This function is called from main thread. {$IFDEF fsoSynchronizeEvents} procedure CallEventsListeners; {$ELSE} procedure CallEventsListeners(Data: Pointer); {$ENDIF} // This should be run from GUI thread only. procedure TryAskQuestion; {en Checks (under lock) if current state is one of ExpectedStates. If yes then changes state to NewState and returns @true. If no then does not change state and returns @false. If state already is NewState then does nothing and returns @true. } function UpdateState(NewState: TFileSourceOperationState; ExpectedStates: TFileSourceOperationStates = fsosAllStates): Boolean; function GetState: TFileSourceOperationState; function GetUserInterface: TFileSourceOperationUI; procedure UpdateStartTime(NewStartTime: TDateTime); {en Must be called from the operation thread. @param(DesiredStates If desired state is one of these states the pause is executed. Otherwise nothing happens.) } procedure DoPauseIfNeeded(DesiredStates: TFileSourceOperationStates); {en Must be called from the controller thread (GUI). } procedure DoUnPause; function DoWaitForConnection: TWaitResult; {en Pauses the operation until it is notified that a connection is available. } function WaitForConnection: TWaitResult; {en Reloads any file sources changed by the operation. } procedure ReloadFileSources; protected {en File source connection. } FConnection: TObject; {en If @true a connection is requested from file source before the operation starts. By default this is @true if file source has fspUsesConnections property, but this variable may be changed on a per-operation basis in the operation's constructor. } FNeedsConnection: Boolean; {en If @true then file source should create a new connection on request. By default this is @false, but this variable can be changed on a per-operation basis. } FWantsNewConnection: Boolean; {en Sets the time to wait while trying to request a connection before terminating the attempt. The default value is INFINITE, but this variable can be changed on a per-operation basis. } FConnectionTimeout: Cardinal; {en So that when operation runs another operation the inner operation can access some inheritable properties, like user interface. } FParentOperation: TFileSourceOperation; procedure UpdateProgress(NewProgress: Double); function GetDesiredState: TFileSourceOperationState; {en Reloads changed file sources. It is called from main thread. } procedure DoReloadFileSources; virtual; {en Retrieves an available connection from the file source (TFileSourceConnection). } function GetConnection: TObject; virtual; {en This should be set to the correct file operation type in each concrete descendant. We rely on this when making a decision based on operation type. This way it's easier to maintain different sorts of things we can do with operations and statistics, without having to include knowledge of those things in the operations classes hierarchy. } function GetID: TFileSourceOperationType; virtual abstract; procedure Initialize; virtual; procedure MainExecute; virtual abstract; procedure Finalize; virtual; {en Notifies all listeners that operation has changed its state. This function can be called from the operation thread or from the main thread. Don't call it under the FEventsLock lock. } procedure NotifyStateChanged(NewState: TFileSourceOperationState); {en General function to ask questions from operations. It is run from the operation thread and is thread-safe. The function stops executing the operation until the question can be asked and the response from the user is received. While the operation is waiting for a response it may be aborted by the user in which case the function will throw EFileSourceOperationAborting exception. The most recently (last) assigned user interface is used to ask the question. } function AskQuestion( Msg: String; Question: String; PossibleResponses: array of TFileSourceOperationUIResponse; DefaultOKResponse: TFileSourceOperationUIResponse; DefaultCancelResponse: TFileSourceOperationUIAnswer; ActionHandler: TFileSourceOperationUIActionHandler = nil ) : TFileSourceOperationUIAnswer; {en Remember statistics at start time (used for estimating remaining time). } procedure UpdateStatisticsAtStartTime; virtual abstract; {en This function does some checks on the current and desired state of the operation: If the desired state is fsosPaused it pauses the thread. If the desired state is fsosStopped it throws EFileSourceOperationAborting exception. The function should be run from the operation thread from the most repeated points. } procedure CheckOperationState; {en Same as CheckOperationState but does not throw exception. } function CheckOperationStateSafe: Boolean; function AppProcessMessages(CheckState: Boolean = False): Boolean; class procedure RaiseAbortOperation; property ParentOperation: TFileSourceOperation read FParentOperation write FParentOperation; public constructor Create(const aFileSource: IInterface); virtual; destructor Destroy; override; {en Executes operation. } procedure Execute; { The Start/Pause/Stop functions only have sense if the operation is run in a separate thread (most probably via OperationsManager). } {en Tries to start/resume operation. First immediately sets state to fsosStarting and after it is started to fsosRunning. } procedure Start; {en Tries to put operation into a paused state. First immediately sets state to fsosPausing and after it is paused to fsosPaused. } procedure Pause; {en Tries to stop operation. First immediately sets state to fsosStopping and after it is stopped to fsosStopped. } procedure Stop; {en Prevents auto start of the operation on Execute. Makes sense only before first call to Execute. } procedure PreventStart; {en If the operation can be paused it pauses otherwise starts the operation. } procedure TogglePause; {en Notifies the operation that possibly a connection is available from the file source, but it does not guarantee it. The operation should ask the file source for the connection. Usually will be called from the file source. } procedure ConnectionAvailableNotify; {en Sets the thread assigned to this operation. } procedure AssignThread(AThread: TThread); {en Adds a function to call when the operation's state changes. @param(States The function will be called if the operation changes its state to one of these states.) } procedure AddStateChangedListener( States: TFileSourceOperationStates; FunctionToCall: TFileSourceOperationStateChangedNotify); {en Removes a registered function callback for state-changed event. } procedure RemoveStateChangedListener( States: TFileSourceOperationStates; FunctionToCall: TFileSourceOperationStateChangedNotify); // These functions are run from the GUI thread. procedure AddUserInterface(UserInterface: TFileSourceOperationUI); procedure RemoveUserInterface(UserInterface: TFileSourceOperationUI); {en Returns graphical interface class for user to set operation options. } class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; virtual; class function GetOperationClass: TFileSourceOperationClass; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; virtual; property Thread: TThread read FThread; property Progress: Double read FProgress; property ID: TFileSourceOperationType read GetID; property State: TFileSourceOperationState read GetState; property StartTime: TDateTime read FStartTime; property Result: TFileSourceOperationResult read FOperationResult; property FileSource: IInterface read FFileSource; property Elevate: TDuplicates read FElevate write FElevate; property WantsNewConnection: Boolean read FWantsNewConnection write FWantsNewConnection; end; EFileSourceOperationAborting = class(Exception) public constructor Create; reintroduce; end; implementation uses InterfaceBase, Forms, uFileSource, uFileSourceProperty, uDebug, uExceptions, uAdministrator {$IFNDEF fsoSynchronizeEvents} , uGuiMessageQueue {$ENDIF} ; type PStateChangedEventEntry = ^TStateChangedEventEntry; TStateChangedEventEntry = record FunctionToCall: TFileSourceOperationStateChangedNotify; States : TFileSourceOperationStates; end; PUserInterfacesEntry = ^TUserInterfacesEntry; TUserInterfacesEntry = record UserInterface: TFileSourceOperationUI; end; constructor TFileSourceOperation.Create(const aFileSource: IInterface); begin FState := fsosNotStarted; FDesiredState := fsosRunning; // set for auto-start unless prevented by PreventStart FOperationResult := fsorFinished; FPauseEvent := TSimpleEvent.Create; FConnectionAvailableEvent := TSimpleEvent.Create; FStateLock := TCriticalSection.Create; FEventsLock := TCriticalSection.Create; {$IFNDEF fsoSynchronizeEvents} FNoEventsListenersCallsScheduledEvent := RTLEventCreate; // Set at start because we don't have any calls scheduled at this time. RTLeventSetEvent(FNoEventsListenersCallsScheduledEvent); {$ENDIF} FUserInterfaces := TFPList.Create; FUserInterfaceAssignedEvent := RTLEventCreate; // Reset at start because we have no interface assigned. RTLeventResetEvent(FUserInterfaceAssignedEvent); FStateChangedEventListeners := TFPList.Create; FFileSource := aFileSource; FWantsNewConnection := False; FConnectionTimeout := SyncObjs.INFINITE; FNeedsConnection := (fspUsesConnections in (FileSource as IFileSource).Properties); inherited Create; end; destructor TFileSourceOperation.Destroy; var i: Integer; begin inherited Destroy; // Remove operation from the queue of operations waiting for a connection // (it can still be there if it was aborted while waiting). (FileSource as IFileSource).RemoveOperationFromQueue(Self); for i := 0 to FStateChangedEventListeners.Count - 1 do Dispose(PStateChangedEventEntry(FStateChangedEventListeners.Items[i])); FreeAndNil(FStateChangedEventListeners); for i := 0 to FUserInterfaces.Count - 1 do Dispose(PUserInterfacesEntry(FUserInterfaces.Items[i])); FreeAndNil(FUserInterfaces); // Just to be sure - set all events when we're destroying the object // in case the thread is still waiting (this should normally not happen). FPauseEvent.SetEvent; FConnectionAvailableEvent.SetEvent; {$IFNDEF fsoSynchronizeEvents} RTLeventSetEvent(FNoEventsListenersCallsScheduledEvent); {$ENDIF} RTLeventSetEvent(FUserInterfaceAssignedEvent); FreeAndNil(FPauseEvent); FreeAndNil(FConnectionAvailableEvent); {$IFNDEF fsoSynchronizeEvents} RTLeventdestroy(FNoEventsListenersCallsScheduledEvent); {$ENDIF} RTLeventdestroy(FUserInterfaceAssignedEvent); FreeAndNil(FStateLock); FreeAndNil(FEventsLock); end; procedure TFileSourceOperation.Initialize; begin // Override in descendant classes. end; procedure TFileSourceOperation.Finalize; begin // Override in descendant classes. end; procedure TFileSourceOperation.Execute; begin try {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(Self), ' ', FormatDateTime('nnss.zzzz', Now), ': Start operation ', ClassName); {$ENDIF} UpdateProgress(0); FOperationResult := fsorAborted; try // Wait for start command if not started automatically. DoPauseIfNeeded([fsosNotStarted, fsosPaused]); // Check if wasn't aborted while paused. CheckOperationState; if FNeedsConnection then begin // Wait for connection to file source. while True do begin FConnection := GetConnection; if Assigned(FConnection) then break; UpdateState(fsosWaitingForConnection); if DoWaitForConnection = wrTimeout then break; // Allow pausing and aborting the operation. CheckOperationState; end; end; // Initialize. UpdateState(fsosStarting); ElevateAction:= FElevate; Initialize; FOperationInitialized := True; UpdateStartTime(SysUtils.Now); UpdateState(fsosRunning); {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(Self), ' ', FormatDateTime('nnss.zzzz', Now), ': Before main execute'); {$ENDIF} MainExecute; {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(Self), ' ', FormatDateTime('nnss.zzzz', Now), ': After main execute'); {$ENDIF} FOperationResult := fsorFinished; except on EFileSourceOperationAborting do begin FOperationResult := fsorAborted; end; end; if FOperationInitialized then begin FElevate:= ElevateAction; Finalize; end; UpdateProgress(1); finally UpdateState(fsosStopped); {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(self), ' ', FormatDateTime('nnss.zzzz', Now), ': Operation finished ', ClassName); {$ENDIF} {$IFNDEF fsoSynchronizeEvents} // Wait until all the scheduled calls to events listeners have been processed // by the main thread (otherwise the calls can be made to a freed memory location). RTLeventWaitFor(FNoEventsListenersCallsScheduledEvent); {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(self), ' ', FormatDateTime('nnss.zzzz', Now), ': After wait for events'); {$ENDIF} {$ENDIF} end; // It is best to reload after the operation and all events are finished. if FOperationInitialized then ReloadFileSources; end; procedure TFileSourceOperation.UpdateProgress(NewProgress: Double); begin FProgress := NewProgress; end; function TFileSourceOperation.UpdateState(NewState: TFileSourceOperationState; ExpectedStates: TFileSourceOperationStates): Boolean; begin FStateLock.Acquire; try if FState = NewState then Exit(True) else if not (FState in ExpectedStates) then Exit(False); FState := NewState; finally FStateLock.Release; end; {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(self), ' ', FormatDateTime('nnss.zzzz', Now), ': Updated state to ', IntToStr(Integer(NewState))); {$ENDIF} NotifyStateChanged(NewState); Result := True; end; function TFileSourceOperation.GetDesiredState: TFileSourceOperationState; begin Result := FDesiredState; end; function TFileSourceOperation.GetState: TFileSourceOperationState; begin FStateLock.Acquire; try Result := FState; finally FStateLock.Release; end; end; function TFileSourceOperation.GetUserInterface: TFileSourceOperationUI; begin if Assigned(ParentOperation) then Result := ParentOperation.GetUserInterface else begin if FUserInterfaces.Count > 0 then // Get the UI that was most recently added. Result := PUserInterfacesEntry(FUserInterfaces.Last)^.UserInterface else Result := nil; end; end; procedure TFileSourceOperation.DoPauseIfNeeded(DesiredStates: TFileSourceOperationStates); begin FStateLock.Acquire; try if not (GetDesiredState in DesiredStates) then Exit; FPauseEvent.ResetEvent; finally FStateLock.Release; end; if GetCurrentThreadId <> MainThreadID then FPauseEvent.WaitFor(INFINITE) // wait indefinitely else begin while FPauseEvent.WaitFor(100) = wrTimeout do WidgetSet.AppProcessMessages; end; end; procedure TFileSourceOperation.DoUnPause; begin FPauseEvent.SetEvent; end; function TFileSourceOperation.DoWaitForConnection: TWaitResult; begin FConnectionAvailableEvent.ResetEvent; Result:= FConnectionAvailableEvent.WaitFor(FConnectionTimeout); end; function TFileSourceOperation.WaitForConnection: TWaitResult; begin UpdateState(fsosWaitingForConnection); Result:= DoWaitForConnection; UpdateStartTime(SysUtils.Now); UpdateState(fsosRunning); end; procedure TFileSourceOperation.ConnectionAvailableNotify; begin FConnectionAvailableEvent.SetEvent; end; function TFileSourceOperation.GetConnection: TObject; begin Result := (FileSource as IFileSource).GetConnection(Self); end; function TFileSourceOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin Result := rsOperWorking; end; procedure TFileSourceOperation.CheckOperationState; begin case GetDesiredState of fsosPaused: begin if UpdateState(fsosPaused, [fsosPausing]) then begin DoPauseIfNeeded([fsosPaused]); // Check if the operation was unpaused because it is being aborted. if GetDesiredState = fsosStopped then RaiseAbortOperation; UpdateStartTime(SysUtils.Now); if FOperationInitialized then UpdateState(fsosRunning) else UpdateState(fsosStarting); end; end; fsosStopped: // operation was asked to stop (via Stop function) begin RaiseAbortOperation; end; // else: we're left with fsosRunning end; end; function TFileSourceOperation.CheckOperationStateSafe: Boolean; begin try CheckOperationState; except on E: EFileSourceOperationAborting do Exit(False); end; Result:= True; end; function TFileSourceOperation.AppProcessMessages(CheckState: Boolean): Boolean; begin if GetCurrentThreadId = MainThreadID then begin WidgetSet.AppProcessMessages; end; if CheckState then try CheckOperationState; except on E: EFileSourceOperationAborting do Exit(False); end; Result:= True; end; procedure TFileSourceOperation.UpdateStartTime(NewStartTime: TDateTime); begin FStartTime := NewStartTime; UpdateStatisticsAtStartTime; end; procedure TFileSourceOperation.Start; var LocalState: TFileSourceOperationState; begin FStateLock.Acquire; try if FState in [fsosPausing] then // The operation didn't manage to pause yet, so simply go back to running state. FState := fsosRunning else if FState in [fsosNotStarted, fsosPaused] then FState := fsosStarting else Exit; LocalState := FState; finally FStateLock.Release; end; NotifyStateChanged(LocalState); FDesiredState := fsosRunning; DoUnPause; end; procedure TFileSourceOperation.Pause; begin FStateLock.Acquire; try if FState in [fsosStarting, fsosRunning, fsosWaitingForConnection] then FState := fsosPausing else Exit; finally FStateLock.Release; end; NotifyStateChanged(fsosPausing); FDesiredState := fsosPaused; // Also set "Connection available" event in case the operation is waiting // for a connection and the user wants to pause it // (this must be after setting desired state). ConnectionAvailableNotify; end; procedure TFileSourceOperation.Stop; begin FStateLock.Acquire; try if not (FState in [fsosStopping, fsosStopped]) then FState := fsosStopping else Exit; finally FStateLock.Release; end; NotifyStateChanged(fsosStopping); FDesiredState := fsosStopped; DoUnPause; // Also set "Connection available" event in case the operation is waiting // for a connection and the user wants to abort it // (this must be after setting desired state). ConnectionAvailableNotify; // The operation may be waiting for the user's response. // Wake it up then, because it is being aborted // (this must be after setting state to Stopping). RTLeventSetEvent(FUserInterfaceAssignedEvent); end; procedure TFileSourceOperation.TogglePause; begin if State in [fsosStarting, fsosRunning, fsosWaitingForConnection] then Pause else Start; end; procedure TFileSourceOperation.PreventStart; begin FDesiredState := fsosNotStarted; end; procedure TFileSourceOperation.AssignThread(AThread: TThread); begin FThread := AThread; end; procedure TFileSourceOperation.AddStateChangedListener( States: TFileSourceOperationStates; FunctionToCall: TFileSourceOperationStateChangedNotify); var Entry: PStateChangedEventEntry; i: Integer; begin FEventsLock.Acquire; try // Check if this function isn't already added. for i := 0 to FStateChangedEventListeners.Count - 1 do begin Entry := PStateChangedEventEntry(FStateChangedEventListeners.Items[i]); if Entry^.FunctionToCall = FunctionToCall then begin // Add states to listen for. Entry^.States := Entry^.States + States; Exit; end; end; // Add new listener. Entry := New(PStateChangedEventEntry); Entry^.FunctionToCall := FunctionToCall; Entry^.States := States; FStateChangedEventListeners.Add(Entry); finally FEventsLock.Release; end; end; procedure TFileSourceOperation.RemoveStateChangedListener( States: TFileSourceOperationStates; FunctionToCall: TFileSourceOperationStateChangedNotify); var Entry: PStateChangedEventEntry; i: Integer; begin FEventsLock.Acquire; try for i := 0 to FStateChangedEventListeners.Count - 1 do begin Entry := PStateChangedEventEntry(FStateChangedEventListeners.Items[i]); if Entry^.FunctionToCall = FunctionToCall then begin // Remove listening for states. Entry^.States := Entry^.States - States; // If all states removed - remove the callback function itself. if Entry^.States = [] then begin FStateChangedEventListeners.Delete(i); Dispose(Entry); end; break; end; end; finally FEventsLock.Release; end; end; procedure TFileSourceOperation.NotifyStateChanged(NewState: TFileSourceOperationState); var i: Integer; found: Boolean = False; begin FEventsLock.Acquire; try {$IFNDEF fsoSynchronizeEvents} {$IFDEF fsoSendOnlyCurrentState} // If we only want to notify about the current state, first check // if there already isn't scheduled (queued) a call to CallEventsListeners. if FScheduledEventsListenersCalls > 0 then Exit; {$ENDIF} {$ENDIF} // Check if there is at least one listener that wants the new state. for i := 0 to FStateChangedEventListeners.Count - 1 do begin if NewState in PStateChangedEventEntry(FStateChangedEventListeners.Items[i])^.States then begin found := True; break; end; end; if not found then Exit; {$IFNDEF fsoSynchronizeEvents} // This must be under the same lock as in CallEventsListeners. InterLockedIncrement(FScheduledEventsListenersCalls); RTLeventResetEvent(FNoEventsListenersCallsScheduledEvent); {$ENDIF} finally FEventsLock.Release; end; {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(self), ' ', FormatDateTime('nnss.zzzz', Now), ': Before notify events'); {$ENDIF} if GetCurrentThreadID <> MainThreadID then // NotifyStateChanged() is run from the operation thread so we cannot // call event listeners directly, because they may update the GUI. {$IFDEF fsoSynchronizeEvents} // Call listeners through Synchronize. TThread.Synchronize(Thread, @CallEventsListeners) {$ELSE} // Schedule listeners through asynchronous message queue. GuiMessageQueue.QueueMethod(@CallEventsListeners, Pointer(PtrUInt(NewState))) {$ENDIF} else begin // The function was called from main thread - call directly. if GetCurrentThreadID <> MainThreadID then begin // The operation runs in a thread. // Handle exceptions for the GUI thread because it controls the operation // and in case of error the operation may be left in infinite waiting state. try {$IFDEF fsoSynchronizeEvents} CallEventsListeners; {$ELSE} CallEventsListeners(Pointer(PtrUInt(NewState))); {$ENDIF} except on Exception do begin WriteExceptionToErrorFile; DCDebug(ExceptionToString); ShowExceptionDialog; end; end; end else begin {$IFDEF fsoSynchronizeEvents} CallEventsListeners; {$ELSE} CallEventsListeners(Pointer(PtrUInt(NewState))); {$ENDIF} end; end; {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(self), ' ', FormatDateTime('nnss.zzzz', Now), ': After notify events'); {$ENDIF} end; {$IFDEF fsoSynchronizeEvents} procedure TFileSourceOperation.CallEventsListeners; {$ELSE} procedure TFileSourceOperation.CallEventsListeners(Data: Pointer); {$ENDIF} var Entry: PStateChangedEventEntry; i: Integer; aState: TFileSourceOperationState; FunctionsToCall: array of TFileSourceOperationStateChangedNotify; FunctionsCount: Integer = 0; begin {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(self), ' ', FormatDateTime('nnss.zzzz', Now), ': Before call events'); {$ENDIF} {$IFDEF fsoSynchronizeEvents} aState := Self.State; {$ELSE} {$IFDEF fsoSendOnlyCurrentState} aState := Self.State; {$ELSE} aState := TFileSourceOperationState(PtrUInt(Data)); {$ENDIF} InterLockedDecrement(FScheduledEventsListenersCalls); {$ENDIF} // First the listeners functions must be copied under lock before calling them, // because any function called may attempt to add/remove listeners from the list. FEventsLock.Acquire; try SetLength(FunctionsToCall, FStateChangedEventListeners.Count); for i := 0 to FStateChangedEventListeners.Count - 1 do begin Entry := PStateChangedEventEntry(FStateChangedEventListeners.Items[i]); // Check if the listener wants this state. if (aState in Entry^.States) then begin FunctionsToCall[FunctionsCount] := Entry^.FunctionToCall; Inc(FunctionsCount, 1); end; end; finally FEventsLock.Release; end; // Call each listener function (not under lock). for i := 0 to FunctionsCount - 1 do FunctionsToCall[i](Self, aState); {$IFNDEF fsoSynchronizeEvents} FEventsLock.Acquire; try // This must be under the same lock as in NotifyStateChanged. if FScheduledEventsListenersCalls = 0 then RTLeventSetEvent(FNoEventsListenersCallsScheduledEvent); finally FEventsLock.Release; end; {$ENDIF} {$IFDEF debugFileSourceOperation} DCDebug('Op: ', hexStr(Self), ' ', FormatDateTime('nnss.zzzz', Now), ': After call events'); {$ENDIF} end; procedure TFileSourceOperation.AddUserInterface(UserInterface: TFileSourceOperationUI); var Entry: PUserInterfacesEntry; begin Entry := New(PUserInterfacesEntry); Entry^.UserInterface := UserInterface; FUserInterfaces.Add(Entry); // Notify a possibly waiting operation thread that an UI was assigned. RTLeventSetEvent(FUserInterfaceAssignedEvent); end; procedure TFileSourceOperation.RemoveUserInterface(UserInterface: TFileSourceOperationUI); var Entry: PUserInterfacesEntry; i: Integer; begin for i := 0 to FUserInterfaces.Count - 1 do begin Entry := PUserInterfacesEntry(FUserInterfaces.Items[i]); if Entry^.UserInterface = UserInterface then begin FUserInterfaces.Delete(i); Dispose(Entry); break; end; end; if FUserInterfaces.Count = 0 then // Last interface was removed - reset event so that operation // thread will wait for an UI if it wants to ask a question. RTLeventResetEvent(FUserInterfaceAssignedEvent); end; class function TFileSourceOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := nil; end; class function TFileSourceOperation.GetOperationClass: TFileSourceOperationClass; begin Result := Self; end; function TFileSourceOperation.AskQuestion( Msg: String; Question: String; PossibleResponses: array of TFileSourceOperationUIResponse; DefaultOKResponse: TFileSourceOperationUIResponse; DefaultCancelResponse: TFileSourceOperationUIAnswer; ActionHandler: TFileSourceOperationUIActionHandler = nil ) : TFileSourceOperationUIAnswer; var i: Integer; bStateChanged: Boolean = False; OldState: TFileSourceOperationState; begin FStateLock.Acquire; try if FState in [fsosStopping, fsosStopped] then RaiseAbortOperation else begin OldState := FState; FState := fsosWaitingForFeedback; end; finally FStateLock.Release; end; NotifyStateChanged(fsosWaitingForFeedback); // Set up parameters through variables because // we cannot pass them via Synchronize call to TryAskQuestion. FUIMessage := Msg; FUIQuestion := Question; SetLength(FUIPossibleResponses, Length(PossibleResponses)); for i := 0 to Length(PossibleResponses) - 1 do FUIPossibleResponses[i] := PossibleResponses[i]; FUIDefaultOKResponse := DefaultOKResponse; FUIDefaultCancelResponse := DefaultCancelResponse; FUIActionHandler := ActionHandler; if GetCurrentThreadID <> MainThreadID then begin while True do begin TThread.Synchronize(Thread, @TryAskQuestion); // Check result of TryAskQuestion. if FTryAskQuestionResult = False then begin // There is no UI assigned - wait until it is assigned. RTLeventWaitFor(FUserInterfaceAssignedEvent); // Check why the event was set. // It is either because an UI was assigned or because the operation is being aborted. if State in [fsosStopping, fsosStopped] then begin // The operation is being aborted. RaiseAbortOperation; break; end; // else we got an UI assigned - retry asking question end else begin // Received answer from the user. Result := FUIResponse; break; end; end; end else begin // The operation is probably run from main thread - call directly. TryAskQuestion; if FTryAskQuestionResult = False then // There is no UI assigned - assume default OK answer. Result := DefaultOKResponse else Result := FUIResponse; end; FStateLock.Acquire; try // Check, if the state is still the same as before asking question. if FState = fsosWaitingForFeedback then begin UpdateStartTime(SysUtils.Now); FState := OldState; bStateChanged := True; end; finally FStateLock.Release; end; if bStateChanged then NotifyStateChanged(OldState); end; procedure TFileSourceOperation.TryAskQuestion; var UI: TFileSourceOperationUI; begin // This is run from GUI thread. FTryAskQuestionResult := False; // We have no answer yet. UI := GetUserInterface; if Assigned(UI) then begin FUIResponse := UI.AskQuestion( FUIMessage, FUIQuestion, FUIPossibleResponses, FUIDefaultOKResponse, FUIDefaultCancelResponse, FUIActionHandler); FTryAskQuestionResult := True; // We do have an answer now. end; // else We have no UIs assigned - cannot ask question. end; procedure TFileSourceOperation.ReloadFileSources; begin TThread.Synchronize(Thread, @DoReloadFileSources); // Calls virtual function end; procedure TFileSourceOperation.DoReloadFileSources; begin // Nothing by default. end; class procedure TFileSourceOperation.RaiseAbortOperation; begin raise EFileSourceOperationAborting.Create; end; constructor EFileSourceOperationAborting.Create; begin inherited Create('aborting file source operation'); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceoperationmessageboxesui.pas�����������������������������0000644�0001750�0000144�00000007123�14743153644�025642� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceOperationMessageBoxesUI; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperationUI, uShowMsg; type {en We assume here the UI is used only from the GUI thread. } { TFileSourceOperationMessageBoxesUI } TFileSourceOperationMessageBoxesUI = class(TFileSourceOperationUI) private FUIActionHandler: TFileSourceOperationUIActionHandler; protected procedure QuestionActionHandler(Button: TMyMsgActionButton); public constructor Create; override; destructor Destroy; override; function AskQuestion(Msg: String; Question: String; PossibleResponses: array of TFileSourceOperationUIResponse; DefaultOKResponse: TFileSourceOperationUIResponse; DefaultCancelResponse: TFileSourceOperationUIAnswer; ActionHandler: TFileSourceOperationUIActionHandler = nil ) : TFileSourceOperationUIAnswer; override; end; implementation const ResponseToButton: array[TFileSourceOperationUIResponse] of TMyMsgButton = (msmbOK, msmbOK, msmbNo, msmbYes, msmbCancel, msmbNone, msmbAppend, msmbResume, msmbCopyInto, msmbCopyIntoAll, msmbOverwrite, msmbOverwriteAll, msmbOverwriteOlder, msmbOverwriteSmaller, msmbOverwriteLarger, msmbAutoRenameSource, msmbAutoRenameTarget, msmbRenameSource, msmbSkip, msmbSkipAll, msmbIgnore, msmbIgnoreAll, msmbAll, msmbRetry, msmbAbort, msmbRetryAdmin, msmbUnlock, // Actions: msmbCompare); ResultToResponse: array[TMyMsgResult] of TFileSourceOperationUIResponse = (fsourOk, fsourNo, fsourYes, fsourCancel, fsourNone, fsourAppend, fsourResume, fsourCopyInto, fsourCopyIntoAll, fsourOverwrite, fsourOverwriteAll, fsourOverwriteOlder, fsourOverwriteSmaller, fsourOverwriteLarger, fsourAutoRenameSource, fsourAutoRenameTarget, fsourRenameSource, fsourSkip, fsourSkipAll, fsourIgnore, fsourIgnoreAll, fsourAll, fsourRetry, fsourAbort, fsourRetryAdmin, fsourUnlock); ButtonToUIAction: array[TMyMsgActionButton] of TFileSourceOperationUIAction = (fsouaCompare); constructor TFileSourceOperationMessageBoxesUI.Create; begin inherited; end; destructor TFileSourceOperationMessageBoxesUI.Destroy; begin inherited; end; function TFileSourceOperationMessageBoxesUI.AskQuestion( Msg: String; Question: String; PossibleResponses: array of TFileSourceOperationUIResponse; DefaultOKResponse: TFileSourceOperationUIResponse; DefaultCancelResponse: TFileSourceOperationUIAnswer; ActionHandler: TFileSourceOperationUIActionHandler = nil ) : TFileSourceOperationUIAnswer; var Buttons: array of TMyMsgButton; i: Integer; MsgResult: TMyMsgResult; TextMessage: String; begin FUIActionHandler := ActionHandler; SetLength(Buttons, Length(PossibleResponses)); for i := 0 to Length(PossibleResponses) - 1 do Buttons[i] := ResponseToButton[PossibleResponses[i]]; TextMessage := Msg; if (Msg <> '') and (Question <> '') then TextMessage := TextMessage { + LineEnding} + ' '; TextMessage := TextMessage + Question; MsgResult := MsgBox(TextMessage, Buttons, ResponseToButton[DefaultOKResponse], ResponseToButton[DefaultCancelResponse], @QuestionActionHandler); Result := ResultToResponse[MsgResult]; end; procedure TFileSourceOperationMessageBoxesUI.QuestionActionHandler( Button: TMyMsgActionButton); begin if Assigned(FUIActionHandler) then FUIActionHandler(ButtonToUIAction[Button]); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceoperationmisc.pas���������������������������������������0000644�0001750�0000144�00000006051�14743153644�023551� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Miscellaneous functions for file source operations and queues. Copyright (C) 2012 Przemysław Nagay (cobines@gmail.com) 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 } unit uFileSourceOperationMisc; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation, uOperationsManager; function GetOperationStateString(OperationState: TFileSourceOperationState): String; function GetProgressString(const Progress: Double): String; procedure PlaySound(OpManItem: TOperationsManagerItem); procedure ShowOperation(OpManItem: TOperationsManagerItem); procedure ShowOperationModal(OpManItem: TOperationsManagerItem); implementation uses DateUtils, fFileOpDlg, uFileSourceOperationTypes, uGlobs, uPlaySound; function GetOperationStateString(OperationState: TFileSourceOperationState): String; begin if OperationState <> fsosRunning then Result := ' [' + FileSourceOperationStateText[OperationState] + ']' else Result := ''; end; function GetProgressString(const Progress: Double): String; begin Result := FloatToStrF(Progress * 100, ffFixed, 0, 0) + '%'; end; procedure PlaySound(OpManItem: TOperationsManagerItem); var FileName: String; begin if (gFileOperationDuration >= 0) and (SecondsBetween(Now, OpManItem.Operation.StartTime) >= gFileOperationDuration) then begin if OpManItem.Operation.ID in [fsoCopy, fsoCopyIn, fsoCopyOut] then FileName:= gFileOperationsSounds[fsoCopy] else begin FileName:= gFileOperationsSounds[OpManItem.Operation.ID]; end; if (Length(FileName) > 0) then uPlaySound.PlaySound(FileName); end; end; procedure ShowOperation(OpManItem: TOperationsManagerItem); var Options: TOperationProgressWindowOptions = []; begin if OpManItem.Queue.IsFree or (OpManItem.Queue.Count = 1) then begin if gFileOperationsProgressKind in [fopkSeparateWindow, fopkSeparateWindowMinimized] then begin if gFileOperationsProgressKind = fopkSeparateWindowMinimized then Options := Options + [opwoStartMinimized]; TfrmFileOp.ShowFor(OpManItem.Handle, Options); end; end; end; procedure ShowOperationModal(OpManItem: TOperationsManagerItem); begin // with TfrmFileOp.Create(OpManItem.Queue.Identifier) do with TfrmFileOp.Create(OpManItem.Handle) do try ShowModal; finally Free; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceoperationoptions.pas������������������������������������0000644�0001750�0000144�00000001346�14743153644�024313� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceOperationOptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type TFileSourceOperationOptionGeneral = (fsoogNone, fsoogYes, fsoogNo); TFileSourceOperationOptionSymLink = (fsooslNone, fsooslFollow, fsooslDontFollow); TFileSourceOperationOptionFileExists = (fsoofeNone, fsoofeSkip, fsoofeOverwrite, fsoofeOverwriteOlder, fsoofeOverwriteSmaller, fsoofeOverwriteLarger, fsoofeAutoRenameSource, fsoofeAutoRenameTarget, fsoofeAppend, fsoofeResume); TFileSourceOperationOptionDirectoryExists = (fsoodeNone, fsoodeSkip, fsoodeDelete, fsoodeCopyInto); TFileSourceOperationOptionSetPropertyError = (fsoospeNone, fsoospeDontSet, fsoospeIgnoreErrors); implementation end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceoperationoptionsui.pas����������������������������������0000644�0001750�0000144�00000001673�14743153644�024654� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceOperationOptionsUI; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms; type TFileSourceOperationOptionsUIClass = class of TFileSourceOperationOptionsUI; { TFileSourceOperationOptionsUI } TFileSourceOperationOptionsUI = class(TFrame) public constructor Create(AOwner: TComponent; AFileSource: IInterface); virtual; reintroduce; class function GetOptionsClass: TFileSourceOperationOptionsUIClass; procedure SaveOptions; virtual; abstract; {en Set operation options from GUI controls. } procedure SetOperationOptions(Operation: TObject); virtual; abstract; end; implementation { TFileSourceOperationOptionsUI } constructor TFileSourceOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited Create(AOwner); end; class function TFileSourceOperationOptionsUI.GetOptionsClass: TFileSourceOperationOptionsUIClass; begin Result := Self; end; end. ���������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceoperationtypes.pas��������������������������������������0000644�0001750�0000144�00000001421�14743153644�023756� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceOperationTypes; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type // Capabilities. // (or make a separate type TFileSourceCapability with fsc... ?) TFileSourceOperationType = ( fsoList, fsoCopy, // Copy files within the same file source. fsoCopyIn, fsoCopyOut, fsoMove, // Move/rename files within the same file source. fsoDelete, fsoWipe, fsoSplit, fsoCombine, fsoCreateDirectory, //fsoCreateFile, //fsoCreateLink, fsoCalcChecksum, fsoCalcStatistics, // Should probably always be supported if fsoList is supported. fsoSetFileProperty, fsoExecute, fsoTestArchive ); TFileSourceOperationTypes = set of TFileSourceOperationType; implementation end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceoperationui.pas�����������������������������������������0000644�0001750�0000144�00000004401�14743153644�023230� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceOperationUI; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type TFileSourceOperationUIResponse = (fsourInvalid, fsourOk, fsourNo, fsourYes, fsourCancel, fsourNone, fsourAppend, // for files fsourResume, // for files fsourCopyInto, // for directories fsourCopyIntoAll, // for directories fsourOverwrite, fsourOverwriteAll, fsourOverwriteOlder, fsourOverwriteSmaller, fsourOverwriteLarger, fsourAutoRenameSource, fsourAutoRenameTarget, fsourRenameSource, fsourSkip, fsourSkipAll, fsourIgnore, fsourIgnoreAll, fsourAll, fsourRetry, fsourAbort, fsourRetryAdmin, fsourUnlock, // Actions will never be returned since they do not close the window, handle them in ActionHandler. fsouaCompare); // The first action, hardcoded. Add new actions after this and new answers before this line. TFileSourceOperationUIResponses = array of TFileSourceOperationUIResponse; TFileSourceOperationUIAnswer = Low(TFileSourceOperationUIResponse)..Pred(fsouaCompare); TFileSourceOperationUIAction = fsouaCompare..High(TFileSourceOperationUIResponse); TFileSourceOperationUIActionHandler = procedure(Action: TFileSourceOperationUIAction) of object; {en General interface for communication: operation <-> user. } TFileSourceOperationUI = class public constructor Create; virtual; destructor Destroy; override; function AskQuestion(Msg: String; Question: String; PossibleResponses: array of TFileSourceOperationUIResponse; DefaultOKResponse: TFileSourceOperationUIResponse; DefaultCancelResponse: TFileSourceOperationUIAnswer; ActionHandler: TFileSourceOperationUIActionHandler = nil ) : TFileSourceOperationUIAnswer; virtual abstract; // Add possibility to display files properties (for example: to compare older - newer) // Add general option "remember this choice for all files of this type" (checkbox) end; implementation constructor TFileSourceOperationUI.Create; begin inherited; end; destructor TFileSourceOperationUI.Destroy; begin inherited; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceproperty.pas��������������������������������������������0000644�0001750�0000144�00000003272�14743153644�022563� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceProperty; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type TFileSourceProperty = ( {en Set, if the files are available directly (for example: real file system). Not sure what it would do yet, but I'll leave it for now. } fspDirectAccess, {en Set, if filenames are case sensitive. } fspCaseSensitive, {en Set, if the file source has virtual files (like a VFS list, or results from searching, etc.). Non-virtual files are all files that are physical (regardless if they are directly accessible). } fspVirtual, {en Set, if the files are links to local files that available directly (for example: results from searching, etc.). } fspLinksToLocalFiles, {en Set, if the file source uses TFileSourceConnection objects for access by operations. } fspUsesConnections, {en Set, if the file source supports file listing on main thread only. } fspListOnMainThread, {en Set, if the file source supports copy in on the main thread only. } fspCopyInOnMainThread, {en Set, if the file source supports copy out on the main thread only. } fspCopyOutOnMainThread, {en Set, if the file source supports flat listing mode. } fspListFlatView, {en Set, if the file source cannot be a child } fspNoneParent, {en Set, if the file source has default columns view } fspDefaultView, {en Set, if the file source supports custom context menu. } fspContextMenu ); TFileSourceProperties = set of TFileSourceProperty; implementation end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcesetfilepropertyoperation.pas����������������������������0000644�0001750�0000144�00000030205�14743153644�026054� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceSetFilePropertyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, DCBasicTypes, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile, uFileProperty; type TSetFilePropertyResult = (sfprSuccess, sfprError, sfprSkipped); TSetFilePropertyResultFunction = procedure(Index: Integer; aFile: TFile; aTemplate: TFileProperty; Result: TSetFilePropertyResult) of object; PFileSourceSetFilePropertyOperationStatistics = ^TFileSourceSetFilePropertyOperationStatistics; TFileSourceSetFilePropertyOperationStatistics = record CurrentFile: String; TotalFiles: Int64; DoneFiles: Int64; FilesPerSecond: Int64; RemainingTime: TDateTime; end; {en Operation that can set any of the file properties supported by a file source. It doesn't have to support all the file properties supported by the file source, it can be a subset. There are two methods of setting properties available: - NewProperties Set via constructor, this is a list of properties that should be set for each file. If a property in this list is not assigned it is not set. If a property in this list is not supported by the file source or by this operation it is also not set. - TemplateFiles Set by calling SetTemplateFiles. Template files describe 1 to 1 correspondence between files and their new properties. Each i-th file in the TargetFiles list will be assigned properties based on propertes of i-th template file. Template files need not be of the same type as target files, it is enough for them to have properties supported by the target files. If template file is not used for i-th file, then the i-th member of the list should be set to @nil, but should be present to maintain the correct correspondence between target and template files. In other words number of target files must be the same as number of template files. The two above methods can be used together. Template files, if present, always take precedence over NewProperties. If a template file is not present (= @nil), then theNewProperties are used as a template. Template files usually will not be used when Recursive is @true, although this behaviour is dependent on the concrete descendant operations. If template files list is @nil, to indicate that the template files are not used, then only the NewProperties are used.) } { TFileSourceSetFilePropertyOperation } TFileSourceSetFilePropertyOperation = class(TFileSourceOperation) private FStatistics: TFileSourceSetFilePropertyOperationStatistics; FStatisticsAtStartTime: TFileSourceSetFilePropertyOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FTargetFiles: TFiles; FTemplateFiles: TFiles; FNewProperties: TFileProperties; FRecursive: Boolean; FSkipErrors: Boolean; protected FSupportedProperties: TFilePropertiesTypes; FSetFilePropertyResultFunction: TSetFilePropertyResultFunction; function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceSetFilePropertyOperationStatistics); procedure UpdateStatisticsAtStartTime; override; procedure SetProperties(Index: Integer; aFile: TFile; aTemplateFile: TFile); function SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; virtual abstract; function GetErrorString(aFile: TFile; aProperty: TFileProperty): String; property FileSource: IFileSource read FFileSource; public IncludeAttributes: TFileAttrs; ExcludeAttributes: TFileAttrs; public {en @param(aTargetFileSource File source on which the operation will be executed.) @param(theTargetFiles List of files which properties should be changed.) @param(theNewProperties Describes the set of properties that should be set for each file of theTargetFiles. All elements of this parameter will be freed automatically.) } constructor Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); virtual reintroduce; destructor Destroy; override; procedure SetTemplateFiles(var theTemplateFiles: TFiles); function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceSetFilePropertyOperationStatistics; property TargetFiles: TFiles read FTargetFiles; property NewProperties: TFileProperties read FNewProperties write FNewProperties; property TemplateFiles: TFiles read FTemplateFiles; // set by SetTemplateFiles because can't use "var" in properties property Recursive: Boolean read FRecursive write FRecursive; property SupportedProperties: TFilePropertiesTypes read FSupportedProperties; property SkipErrors: Boolean read FSkipErrors write FSkipErrors; property OnSetFilePropertyResult: TSetFilePropertyResultFunction write FSetFilePropertyResultFunction; end; implementation uses uDCUtils, uGlobs, uLog, uLng, uFileSourceOperationUI; constructor TFileSourceSetFilePropertyOperation.Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); begin with FStatistics do begin CurrentFile := ''; TotalFiles := 0; DoneFiles := 0; FilesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; aTargetFileSource := nil; FTargetFiles := theTargetFiles; theTargetFiles := nil; FNewProperties := theNewProperties; FillByte(theNewProperties, SizeOf(theNewProperties), 0); FTemplateFiles := nil; FRecursive := False; FSkipErrors := gSkipFileOpError; FSupportedProperties := []; end; destructor TFileSourceSetFilePropertyOperation.Destroy; var prop: TFilePropertyType; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FTargetFiles) then FreeAndNil(FTargetFiles); if Assigned(FTemplateFiles) then FreeAndNil(FTemplateFiles); for prop := Low(FNewProperties) to High(FNewProperties) do if Assigned(FNewProperties[prop]) then FreeAndNil(FNewProperties[prop]); end; function TFileSourceSetFilePropertyOperation.GetID: TFileSourceOperationType; begin Result := fsoSetFileProperty; end; procedure TFileSourceSetFilePropertyOperation.DoReloadFileSources; begin FFileSource.Reload(FTargetFiles.Path); end; function TFileSourceSetFilePropertyOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if TargetFiles.Count = 1 then Result := Format(rsOperSettingPropertyOf, [TargetFiles[0].FullPath]) else Result := Format(rsOperSettingPropertyIn, [TargetFiles.Path]); end; else Result := rsOperSettingProperty; end; end; procedure TFileSourceSetFilePropertyOperation.UpdateStatistics(var NewStatistics: TFileSourceSetFilePropertyOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneFiles <> NewStatistics.DoneFiles then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneFiles, DoneFiles, TotalFiles, StartTime, SysUtils.Now, FilesPerSecond); // Update overall progress. if TotalFiles <> 0 then UpdateProgress(DoneFiles/TotalFiles); end; end; FStatistics := NewStatistics; AppProcessMessages(); finally FStatisticsLock.Release; end; end; procedure TFileSourceSetFilePropertyOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceSetFilePropertyOperation.RetrieveStatistics: TFileSourceSetFilePropertyOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceSetFilePropertyOperation.SetTemplateFiles(var theTemplateFiles: TFiles); begin if Assigned(FTemplateFiles) then FreeAndNil(FTemplateFiles); FTemplateFiles := theTemplateFiles; theTemplateFiles := nil; end; procedure TFileSourceSetFilePropertyOperation.SetProperties(Index: Integer; aFile: TFile; aTemplateFile: TFile); var FileAttrs: TFileAttrs; AProp: TFilePropertyType; templateProperty: TFileProperty; bRetry: Boolean; sMessage, sQuestion: String; SetResult: TSetFilePropertyResult; ErrorString: String; begin // Iterate over all properties supported by this operation. for AProp := Low(SupportedProperties) to High(SupportedProperties) do begin repeat bRetry := False; SetResult := sfprSuccess; // Double-check that the property really is supported by the file. if ((AProp in (aFile.SupportedProperties * fpAll)) or (AProp in (FFileSource.GetRetrievableFileProperties * fpAll))) then begin // Get template property from template file (if exists) or NewProperties. if Assigned(aTemplateFile) then templateProperty := aTemplateFile.Properties[AProp] else templateProperty := NewProperties[AProp]; // Check if there is a new property to be set. if Assigned(templateProperty) then begin // Special case for attributes property if templateProperty is TFileAttributesProperty then begin if (IncludeAttributes <> 0) or (ExcludeAttributes <> 0) then begin FileAttrs:= aFile.Attributes; FileAttrs:= FileAttrs or IncludeAttributes; FileAttrs:= FileAttrs and not ExcludeAttributes; TFileAttributesProperty(templateProperty).Value:= FileAttrs; end; end; SetResult := SetNewProperty(aFile, templateProperty); if Assigned(FSetFilePropertyResultFunction) then begin FSetFilePropertyResultFunction(Index, aFile, templateProperty, SetResult); end; end; end; if SetResult = sfprError then begin ErrorString := GetErrorString(aFile, templateProperty); sMessage := rsMsgLogError + ErrorString; sQuestion := ErrorString; if FSkipErrors then logWrite(Thread, sMessage, lmtError) else begin case AskQuestion(sQuestion, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourAbort) of fsourRetry: bRetry := True; fsourSkipAll: FSkipErrors := True; fsourAbort: RaiseAbortOperation; end; end; end; until bRetry = False; end; end; function TFileSourceSetFilePropertyOperation.GetErrorString(aFile: TFile; aProperty: TFileProperty): String; begin case aProperty.GetID of fpName: Result := Format(rsMsgErrRename, [aFile.FullPath, (aProperty as TFileNameProperty).Value]); fpAttributes: Result := Format(rsMsgErrSetAttribute, [aFile.FullPath]); fpModificationTime, fpCreationTime, fpLastAccessTime: Result := Format(rsMsgErrSetDateTime, [aFile.FullPath]); fpOwner: Result := Format(rsMsgErrSetOwnership, [aFile.FullPath]); else Result := rsMsgLogError; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcesplitoperation.pas��������������������������������������0000644�0001750�0000144�00000012732�14743153644�023754� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceSplitOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile, uFileSourceCopyOperation; type TFileSourceSplitOperationStatistics = TFileSourceCopyOperationStatistics; {en Operation that split file within the same file source. } { TFileSourceSplitOperation } TFileSourceSplitOperation = class(TFileSourceOperation) private FStatistics: TFileSourceSplitOperationStatistics; FStatisticsAtStartTime: TFileSourceSplitOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FSourceFile: TFile; FTargetPath: String; FVolumeSize: Int64; FVolumeNumber: LongInt; FRequireACRC32VerificationFile: boolean; FCurrentCRC32: dword; FAutomaticSplitMode: boolean; protected function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceSplitOperationStatistics); procedure UpdateStatisticsAtStartTime; override; property FileSource: IFileSource read FFileSource; property SourceFile: TFile read FSourceFile; property TargetPath: String read FTargetPath; public {en @param(aFileSource File source within which the operation should take place. Class takes ownership of the pointer.) @param(aSourceFile The file which are to be splitted. Class takes ownership of the pointer.) @param(aTargetPath Target path for splitted files.) } constructor Create(aFileSource: IFileSource; var aSourceFile: TFile; aTargetPath: String); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceSplitOperationStatistics; property VolumeSize: Int64 read FVolumeSize write FVolumeSize; property VolumeNumber: LongInt read FVolumeNumber write FVolumeNumber; property RequireACRC32VerificationFile: boolean read FRequireACRC32VerificationFile write FRequireACRC32VerificationFile; property CurrentCRC32: dword read FCurrentCRC32 write FCurrentCRC32; property AutomaticSplitMode: boolean read FAutomaticSplitMode write FAutomaticSplitMode; end; implementation uses uDCUtils, uLng; // -- TFileSourceSplitOperation ------------------------------------------------ constructor TFileSourceSplitOperation.Create(aFileSource: IFileSource; var aSourceFile: TFile; aTargetPath: String); begin with FStatistics do begin CurrentFileFrom := ''; CurrentFileTo := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; CurrentFileTotalBytes := 0; CurrentFileDoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aFileSource); FFileSource := aFileSource; FSourceFile := aSourceFile; aSourceFile := nil; FTargetPath := IncludeTrailingPathDelimiter(aTargetPath); end; destructor TFileSourceSplitOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FSourceFile) then FreeAndNil(FSourceFile); end; procedure TFileSourceSplitOperation.UpdateStatistics(var NewStatistics: TFileSourceSplitOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, DoneBytes, TotalBytes, StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalBytes <> 0 then UpdateProgress(DoneBytes/TotalBytes); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceSplitOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceSplitOperation.RetrieveStatistics: TFileSourceSplitOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceSplitOperation.GetID: TFileSourceOperationType; begin Result := fsoSplit; end; procedure TFileSourceSplitOperation.DoReloadFileSources; var Paths: TPathsArray; begin SetLength(Paths, 1); Paths[0] := FTargetPath; // Split target path FFileSource.Reload(Paths); end; function TFileSourceSplitOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: Result := Format(rsOperSplittingFromTo, [SourceFile.Path, TargetPath]); else Result := rsOperSplitting; end; end; end. ��������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcetestarchiveoperation.pas��������������������������������0000644�0001750�0000144�00000011421�14743153644�025134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceTestArchiveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile; type // Statistics for TestArchive operation. TFileSourceTestArchiveOperationStatistics = record ArchiveFile: String; CurrentFile: String; CurrentFileTotalBytes: Int64; CurrentFileDoneBytes: Int64; TotalFiles: Int64; DoneFiles: Int64; TotalBytes: Int64; DoneBytes: Int64; BytesPerSecond: Int64; RemainingTime: TDateTime; end; {en Operation that test files in archive. } { TFileSourceTestArchiveOperation } TFileSourceTestArchiveOperation = class(TFileSourceOperation) private FStatistics: TFileSourceTestArchiveOperationStatistics; FStatisticsAtStartTime: TFileSourceTestArchiveOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FSourceFileSource: IFileSource; FSourceFiles: TFiles; protected function GetID: TFileSourceOperationType; override; procedure UpdateStatistics(var NewStatistics: TFileSourceTestArchiveOperationStatistics); procedure UpdateStatisticsAtStartTime; override; property SourceFiles: TFiles read FSourceFiles; public {en @param(aSourceFileSource File source from which the files will be copied.) @param(theSourceFiles Files which are to be copied. Class takes ownership of the pointer.) } constructor Create(aSourceFileSource: IFileSource; var theSourceFiles: TFiles); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceTestArchiveOperationStatistics; end; implementation uses uDCUtils, uLng; // -- TFileSourceTestArchiveOperation ------------------------------------------------ constructor TFileSourceTestArchiveOperation.Create(aSourceFileSource: IFileSource; var theSourceFiles: TFiles); begin with FStatistics do begin ArchiveFile := ''; CurrentFile := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; CurrentFileTotalBytes := 0; CurrentFileDoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aSourceFileSource); FSourceFileSource := aSourceFileSource; FSourceFiles := theSourceFiles; theSourceFiles := nil; end; destructor TFileSourceTestArchiveOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FSourceFiles) then FreeAndNil(FSourceFiles); end; function TFileSourceTestArchiveOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if SourceFiles.Count = 1 then Result := Format(rsOperTestingSomething, [SourceFiles[0].Name]) else Result := Format(rsOperTestingIn, [SourceFiles.Path]); end; else Result := rsOperTesting; end; end; function TFileSourceTestArchiveOperation.GetID: TFileSourceOperationType; begin Result:= fsoTestArchive; end; procedure TFileSourceTestArchiveOperation.UpdateStatistics(var NewStatistics: TFileSourceTestArchiveOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, Abs(DoneBytes), Abs(TotalBytes), StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalBytes <> 0 then UpdateProgress(Abs(DoneBytes / TotalBytes)); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceTestArchiveOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceTestArchiveOperation.RetrieveStatistics: TFileSourceTestArchiveOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcetreebuilder.pas�����������������������������������������0000644�0001750�0000144�00000021146�14743153644�023205� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceTreeBuilder; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSourceOperation, uFileSourceOperationOptions, uFileSourceOperationUI, uSearchTemplate, uFindFiles; type // Additional data for the filesystem tree node. { TFileTreeNodeData } TFileTreeNodeData = class public Recursive: Boolean; // True if any of the subnodes (recursively) are links. SubnodesHaveLinks: Boolean; // Whether directory or subdirectories have any elements that will not be copied/moved. SubnodesHaveExclusions: Boolean; constructor Create(ARecursive: Boolean); overload; end; { TFileSourceTreeBuilder } TFileSourceTreeBuilder = class protected FFilesTree: TFileTree; FFilesCount: Int64; FCurrentDepth: Integer; FDirectoriesCount: Int64; FFilesSize: Int64; FExcludeRootDir: Boolean; FFileTemplate: TSearchTemplate; FExcludeEmptyTemplateDirectories: Boolean; FSymlinkOption: TFileSourceOperationOptionSymLink; FRecursive: Boolean; FFileChecks: TFindFileChecks; FRootDir: String; AskQuestion: TAskQuestionFunction; CheckOperationState: TCheckOperationStateFunction; procedure AddItem(aFile: TFile; CurrentNode: TFileTreeNode); procedure AddFilesInDirectory(srcPath: String; CurrentNode: TFileTreeNode); virtual; abstract; procedure AddFile(aFile: TFile; CurrentNode: TFileTreeNode); procedure AddLink(aFile: TFile; CurrentNode: TFileTreeNode); virtual; procedure AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); virtual; abstract; procedure AddDirectory(aFile: TFile; CurrentNode: TFileTreeNode); procedure DecideOnLink(aFile: TFile; CurrentNode: TFileTreeNode); function GetItemsCount: Int64; public constructor Create(AskQuestionFunction: TAskQuestionFunction; CheckOperationStateFunction: TCheckOperationStateFunction); destructor Destroy; override; procedure BuildFromNode(aNode: TFileTreeNode); procedure BuildFromFiles(Files: TFiles); function ReleaseTree: TFileTree; property ExcludeRootDir: Boolean read FExcludeRootDir write FExcludeRootDir; property Recursive: Boolean read FRecursive write FRecursive; property SymLinkOption: TFileSourceOperationOptionSymLink read FSymlinkOption write FSymlinkOption; property FilesTree: TFileTree read FFilesTree; property FilesSize: Int64 read FFilesSize; property FilesCount: Int64 read FFilesCount; property DirectoriesCount: Int64 read FDirectoriesCount; property ItemsCount: Int64 read GetItemsCount; property ExcludeEmptyTemplateDirectories: Boolean read FExcludeEmptyTemplateDirectories write FExcludeEmptyTemplateDirectories; {en Does not take ownership of SearchTemplate and does not free it. } property SearchTemplate: TSearchTemplate read FFileTemplate write FFileTemplate; end; implementation uses uGlobs, uLng; { TFileTreeNodeData } constructor TFileTreeNodeData.Create(ARecursive: Boolean); begin Recursive:= ARecursive; end; constructor TFileSourceTreeBuilder.Create(AskQuestionFunction: TAskQuestionFunction; CheckOperationStateFunction: TCheckOperationStateFunction); begin AskQuestion := AskQuestionFunction; CheckOperationState := CheckOperationStateFunction; FRecursive := True; FSymlinkOption := fsooslNone; end; destructor TFileSourceTreeBuilder.Destroy; begin inherited Destroy; FFilesTree.Free; end; procedure TFileSourceTreeBuilder.BuildFromNode(aNode: TFileTreeNode); begin FFilesSize := 0; FFilesCount := 0; FCurrentDepth := 0; FDirectoriesCount := 0; FFilesTree := aNode; FRootDir := aNode.TheFile.Path; TFileTreeNodeData(FFilesTree.Data).Recursive:= FRecursive; AddFilesInDirectory(aNode.TheFile.FullPath + DirectorySeparator, FFilesTree); FFilesTree := nil; end; procedure TFileSourceTreeBuilder.BuildFromFiles(Files: TFiles); var i: Integer; begin FreeAndNil(FFilesTree); FFilesTree := TFileTreeNode.Create; FFilesTree.Data := TFileTreeNodeData.Create(FRecursive); FFilesSize := 0; FFilesCount := 0; FDirectoriesCount := 0; FCurrentDepth := 0; FRootDir := Files.Path; if Assigned(FFileTemplate) then SearchTemplateToFindFileChecks(FFileTemplate.SearchRecord, FFileChecks); if ExcludeRootDir then begin for i := 0 to Files.Count - 1 do if Files[i].IsDirectory then AddFilesInDirectory(Files[i].FullPath + DirectorySeparator, FFilesTree); end else begin for i := 0 to Files.Count - 1 do AddItem(Files[i].Clone, FFilesTree); end; end; procedure TFileSourceTreeBuilder.AddFile(aFile: TFile; CurrentNode: TFileTreeNode); var AddedNode: TFileTreeNode; AddedIndex: Integer; begin AddedIndex := CurrentNode.AddSubNode(aFile); AddedNode := CurrentNode.SubNodes[AddedIndex]; AddedNode.Data := TFileTreeNodeData.Create(FRecursive); Inc(FFilesCount); FFilesSize:= FFilesSize + aFile.Size; CheckOperationState; end; procedure TFileSourceTreeBuilder.AddLink(aFile: TFile; CurrentNode: TFileTreeNode); var AddedNode: TFileTreeNode; AddedIndex: Integer; begin AddedIndex := CurrentNode.AddSubNode(aFile); AddedNode := CurrentNode.SubNodes[AddedIndex]; AddedNode.Data := TFileTreeNodeData.Create(FRecursive); (CurrentNode.Data as TFileTreeNodeData).SubnodesHaveLinks := True; Inc(FFilesCount); end; procedure TFileSourceTreeBuilder.AddDirectory(aFile: TFile; CurrentNode: TFileTreeNode); var AddedNode: TFileTreeNode; AddedIndex: Integer; NodeData: TFileTreeNodeData; begin AddedIndex := CurrentNode.AddSubNode(aFile); AddedNode := CurrentNode.SubNodes[AddedIndex]; NodeData := TFileTreeNodeData.Create(FRecursive); AddedNode.Data := NodeData; Inc(FDirectoriesCount); if FRecursive then begin if not Assigned(FFileTemplate) or (FFileTemplate.SearchRecord.SearchDepth < 0) or (FCurrentDepth <= FFileTemplate.SearchRecord.SearchDepth) then begin Inc(FCurrentDepth); AddFilesInDirectory(aFile.FullPath + DirectorySeparator, AddedNode); Dec(FCurrentDepth); end; if Assigned(FFileTemplate) and FExcludeEmptyTemplateDirectories and (AddedNode.SubNodesCount = 0) then begin CurrentNode.RemoveSubNode(AddedIndex); (CurrentNode.Data as TFileTreeNodeData).SubnodesHaveExclusions := True; end else begin // Propagate flags to parent. if NodeData.SubnodesHaveLinks then (CurrentNode.Data as TFileTreeNodeData).SubnodesHaveLinks := True; if NodeData.SubnodesHaveExclusions then (CurrentNode.Data as TFileTreeNodeData).SubnodesHaveExclusions := True; end; end; end; procedure TFileSourceTreeBuilder.DecideOnLink(aFile: TFile; CurrentNode: TFileTreeNode); begin case FSymLinkOption of fsooslFollow: AddLinkTarget(aFile, CurrentNode); fsooslDontFollow: AddLink(aFile, CurrentNode); fsooslNone: begin case AskQuestion('', Format(rsMsgFollowSymlink, [aFile.Name]), [fsourYes, fsourAll, fsourNo, fsourSkipAll], fsourYes, fsourNo) of fsourYes: AddLinkTarget(aFile, CurrentNode); fsourAll: begin FSymLinkOption := fsooslFollow; AddLinkTarget(aFile, CurrentNode); end; fsourNo: AddLink(aFile, CurrentNode); fsourSkipAll: begin FSymLinkOption := fsooslDontFollow; AddLink(aFile, CurrentNode); end; else raise Exception.Create('Invalid user response'); end; end; else raise Exception.Create('Invalid symlink option'); end; end; procedure TFileSourceTreeBuilder.AddItem(aFile: TFile; CurrentNode: TFileTreeNode); var Matches: Boolean; begin if Assigned(FFileTemplate) then begin if AFile.IsDirectory or AFile.IsLinkToDirectory then begin Matches := CheckDirectoryName(FFileChecks, aFile.Name) and CheckDirectoryNameEx(FFileChecks, aFile.FullPath, FRootDir); end else begin Matches := CheckFile(FFileTemplate.SearchRecord, FFileChecks, aFile); end; if not Matches then begin (CurrentNode.Data as TFileTreeNodeData).SubnodesHaveExclusions := True; Exit; end; end; if aFile.IsLink then DecideOnLink(aFile, CurrentNode) else if aFile.IsDirectory then AddDirectory(aFile, CurrentNode) else AddFile(aFile, CurrentNode); end; function TFileSourceTreeBuilder.ReleaseTree: TFileTree; begin Result := FFilesTree; FFilesTree := nil; end; function TFileSourceTreeBuilder.GetItemsCount: Int64; begin Result := FilesCount + DirectoriesCount; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourceutil.pas������������������������������������������������0000644�0001750�0000144�00000033723�14743153644�021660� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceUtil; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource, uFileView, uFile, uFileSourceOperationTypes, uFileSourceSetFilePropertyOperation; {en Decides what should be done when user chooses a file in a file view. This function may add/remove a file source from the view, change path, execute a file or a command, etc. } procedure ChooseFile(aFileView: TFileView; aFileSource: IFileSource; aFile: TFile); {en Checks if choosing the given file will change to another file source, and adds this new file source to the view if it does. @returns @true if the file matched any rules and a new file source was created, @false otherwise, which means no action was taken. } function ChooseFileSource(aFileView: TFileView; aFileSource: IFileSource; aFile: TFile): Boolean; overload; function ParseFileSource(var aPath: String; const CurrentFileSource: IFileSource = nil): IFileSource; function ChooseFileSource(aFileView: TFileView; const aPath: String; bLocal: Boolean = False): Boolean; overload; function ChooseArchive(aFileView: TFileView; aFileSource: IFileSource; aFile: TFile; bForce: Boolean = False): Boolean; procedure ChooseSymbolicLink(aFileView: TFileView; aFile: TFile); procedure SetFileSystemPath(aFileView: TFileView; aPath: String); function RenameFile(aFileSource: IFileSource; const aFile: TFile; const NewFileName: String; Interactive: Boolean): TSetFilePropertyResult; function GetCopyOperationType(SourceFileSource, TargetFileSource: IFileSource; out OperationType: TFileSourceOperationType): Boolean; implementation uses LCLProc, fFileExecuteYourSelf, uGlobs, uShellExecute, uFindEx, uDebug, uOSUtils, uShowMsg, uLng, uVfsModule, DCOSUtils, DCStrUtils, uFileSourceOperation, uFileSourceExecuteOperation, uVfsFileSource, uFileSourceProperty, uFileSystemFileSource, uWfxPluginFileSource, uArchiveFileSourceUtil, uFileSourceOperationMessageBoxesUI, uFileProperty, URIParser, WcxPlugin, uWcxModule, uHash, uSuperUser; procedure ChooseFile(aFileView: TFileView; aFileSource: IFileSource; aFile: TFile); var Index, PathIndex: Integer; sCmd, sParams, sStartPath: String; Operation: TFileSourceExecuteOperation = nil; aFileCopy: TFile = nil; begin // First test for file sources. if ChooseFileSource(aFileView, aFileSource, aFile) then Exit; // For now work only for local files. if aFileView.FileSource.Properties * [fspDirectAccess, fspLinksToLocalFiles] <> [] then begin // Now test if exists Open command in "extassoc.xml" :) if gExts.GetExtActionCmd(aFile, 'open', sCmd, sParams, sStartPath) then begin try // Resolve filename here since ProcessExtCommandFork doesn't do it (as of 2017) // The limitation is that only one file will be opened on a FileSource of links if fspLinksToLocalFiles in aFileView.FileSource.Properties then begin aFileCopy := aFile.Clone; aFileView.FileSource.GetLocalName(aFileCopy); end; if ProcessExtCommandFork(sCmd,sParams,sStartPath,aFileCopy) then Exit; finally FreeAndNil(aFileCopy); end; end; if (fsoCalcChecksum in aFileView.FileSource.GetOperationsTypes) and FileExtIsHash(aFile.Extension) then begin ProcessExtCommandFork('cm_CheckSumVerify'); Exit; end; end; if (fsoExecute in aFileView.FileSource.GetOperationsTypes) then try aFileCopy := aFile.Clone; Operation := aFileView.FileSource.CreateExecuteOperation( aFileCopy, aFileView.CurrentPath, 'open') as TFileSourceExecuteOperation; if Assigned(Operation) then begin Operation.Execute; case Operation.ExecuteOperationResult of fseorError: begin // Show error message if Length(Operation.ResultString) = 0 then msgError(rsMsgErrEOpen) else msgError(Operation.ResultString); end; fseorYourSelf: begin // Copy out file to temp file system and execute if not ShowFileExecuteYourSelf(aFileView, aFile, False) then DCDebug('Execution error!'); end; fseorWithAll: begin // Copy out all files to temp file system and execute chosen if not ShowFileExecuteYourSelf(aFileView, aFile, True) then DCDebug('Execution error!'); end; fseorSymLink: begin // change directory to new path (returned in Operation.ResultString) DCDebug('Change directory to ', Operation.ResultString); with aFileView do begin // If path is URI Index:= Pos('://', Operation.ResultString); PathIndex:= Pos(PathDelim, Operation.ResultString); if (Index > 0) and ((PathIndex > Index) or (PathIndex = 0)) then ChooseFileSource(aFileView, Operation.ResultString) else if (FileSource.IsClass(TFileSystemFileSource)) or (mbSetCurrentDir(ExcludeTrailingPathDelimiter(Operation.ResultString)) = False) then begin // Simply change path CurrentPath:= Operation.ResultString; end else begin // Get a new filesystem file source AddFileSource(TFileSystemFileSource.GetFileSource, Operation.ResultString); end; end; end; end; // case end; // assigned finally FreeAndNil(aFileCopy); FreeAndNil(Operation); end; end; function ChooseFileSource(aFileView: TFileView; aFileSource: IFileSource; aFile: TFile): Boolean; var FileSource: IFileSource; VfsModule: TVfsModule; begin Result := False; if ChooseArchive(aFileView, aFileSource, aFile) then Exit(True); // Work only for TVfsFileSource. if aFileView.FileSource.IsClass(TVfsFileSource) then begin // Check if there is a registered WFX plugin by file system root name. FileSource := FileSourceManager.Find(TWfxPluginFileSource, 'wfx://' + aFile.Name); if not Assigned(FileSource) then FileSource := TWfxPluginFileSource.CreateByRootName(aFile.Name); if not Assigned(FileSource) then begin // Check if there is a registered Vfs module by file system root name. VfsModule:= gVfsModuleList.VfsModule[aFile.Name]; if Assigned(VfsModule) then begin FileSource := FileSourceManager.Find(VfsModule.FileSourceClass, aFile.Name); if not Assigned(FileSource) then FileSource := VfsModule.FileSourceClass.Create; end; end; if Assigned(FileSource) then begin aFileView.AddFileSource(FileSource, FileSource.GetRootDir); Exit(True); end; end; end; function ParseFileSource(var aPath: String; const CurrentFileSource: IFileSource = nil): IFileSource; var URI: TURI; aFileSourceClass: TFileSourceClass; begin aFileSourceClass:= gVfsModuleList.GetFileSource(aPath); // If found special FileSource for path if Assigned(aFileSourceClass) then begin // If path is URI if Pos('://', aPath) > 0 then begin URI:= ParseURI(aPath); aPath:= NormalizePathDelimiters(URI.Path + URI.Document); aPath:= IncludeTrailingPathDelimiter(aPath); Result:= FileSourceManager.Find(aFileSourceClass, URI.Protocol + '://' + URI.Host, not SameText(URI.Protocol, 'smb') ); if not Assigned(Result) then try // Create new FileSource with given URI Result := aFileSourceClass.Create(URI); except Result := nil; end; end // If found FileSource is same as current then simply change path else if aFileSourceClass.ClassNameIs(CurrentFileSource.ClassName) then Result := CurrentFileSource // Else create new FileSource with given path else Result := aFileSourceClass.Create; end else Result:= nil; end; function ChooseFileSource(aFileView: TFileView; const aPath: String; bLocal: Boolean): Boolean; var RemotePath: String; FileSource: IFileSource; begin Result:= True; RemotePath:= aPath; FileSource:= ParseFileSource(RemotePath, aFileView.FileSource); // If found special FileSource for path if Assigned(FileSource) then begin // If path is URI if RemotePath <> aPath then aFileView.AddFileSource(FileSource, RemotePath) // If found FileSource is same as current then simply change path else if aFileView.FileSource.Equals(FileSource) then aFileView.CurrentPath := aPath // Else create new FileSource with given path else aFileView.AddFileSource(FileSource, aPath); end // If current FileSource has address else if bLocal and (Length(aFileView.CurrentAddress) > 0) then aFileView.CurrentPath := aPath // Else use FileSystemFileSource else begin SetFileSystemPath(aFileView, aPath); Result:= mbSetCurrentDir(aPath); end; end; function ChooseArchive(aFileView: TFileView; aFileSource: IFileSource; aFile: TFile; bForce: Boolean): Boolean; var FileSource: IFileSource; begin try // Check if there is a ArchiveFileSource for possible archive. FileSource := GetArchiveFileSource(aFileSource, aFile, EmptyStr, bForce, False); except on E: Exception do begin if (E is EWcxModuleException) and (EWcxModuleException(E).ErrorCode = E_HANDLED) then Exit(True); if not bForce then begin msgError(E.Message + LineEnding + aFile.FullPath); Exit(True); end; end; end; if Assigned(FileSource) then begin if not mbCompareFileNames(aFileView.CurrentPath, aFile.Path) then begin if aFileSource.Properties * [fspDirectAccess, fspLinksToLocalFiles] <> [] then SetFileSystemPath(aFileView, aFile.Path); end; aFileView.AddFileSource(FileSource, FileSource.GetRootDir); Exit(True); end; Result := False; end; procedure ChooseSymbolicLink(aFileView: TFileView; aFile: TFile); var sPath: String; LastError: Integer; SearchRec: TSearchRecEx; begin if not aFileView.FileSource.IsClass(TFileSystemFileSource) then begin aFileView.ChangePathToChild(aFile); Exit; end; sPath:= aFileView.CurrentPath + IncludeTrailingPathDelimiter(aFile.Name); try LastError:= FindFirstEx(sPath + AllFilesMask, 0, SearchRec); if (LastError = 0) then begin with aFileView do CurrentPath := CurrentPath + IncludeTrailingPathDelimiter(aFile.Name); end else if AccessDenied(LastError) then begin sPath:= ReadSymLink(aFile.FullPath); if sPath <> EmptyStr then aFileView.CurrentPath := IncludeTrailingPathDelimiter(GetAbsoluteFileName(aFileView.CurrentPath, sPath)) else msgError(Format(rsMsgChDirFailed, [aFile.FullPath])); end else begin aFileView.ChangePathToChild(aFile); end; finally FindCloseEx(SearchRec); end; end; procedure SetFileSystemPath(aFileView: TFileView; aPath: String); begin with aFileView do begin if TFileSystemFileSource.ClassNameIs(FileSource.ClassName) then CurrentPath := aPath else AddFileSource(TFileSystemFileSource.GetFileSource, aPath); end; end; function RenameFile(aFileSource: IFileSource; const aFile: TFile; const NewFileName: String; Interactive: Boolean): TSetFilePropertyResult; var aFiles: TFiles = nil; Operation: TFileSourceSetFilePropertyOperation = nil; NewProperties: TFileProperties; UserInterface: TFileSourceOperationMessageBoxesUI = nil; begin Result:= sfprError; if fsoSetFileProperty in aFileSource.GetOperationsTypes then begin FillByte(NewProperties, SizeOf(NewProperties), 0); NewProperties[fpName] := TFileNameProperty.Create(NewFileName); try aFiles := TFiles.Create(aFile.Path); aFiles.Add(aFile.Clone); Operation := aFileSource.CreateSetFilePropertyOperation( aFiles, NewProperties) as TFileSourceSetFilePropertyOperation; if Assigned(Operation) then begin // Only if the operation can change file name. if fpName in Operation.SupportedProperties then begin Operation.SkipErrors := not Interactive; if Interactive then begin UserInterface := TFileSourceOperationMessageBoxesUI.Create; Operation.AddUserInterface(UserInterface); end; Operation.Execute; case Operation.Result of fsorFinished: Result:= sfprSuccess; fsorAborted: Result:= sfprSkipped; end; end; end; finally FreeAndNil(NewProperties[fpName]); FreeAndNil(Operation); FreeAndNil(UserInterface); FreeAndNil(aFiles); end; end; end; function GetCopyOperationType(SourceFileSource, TargetFileSource: IFileSource; out OperationType: TFileSourceOperationType): Boolean; begin // If same file source and address if (fsoCopy in SourceFileSource.GetOperationsTypes) and (fsoCopy in TargetFileSource.GetOperationsTypes) and SourceFileSource.Equals(TargetFileSource) and SameText(SourceFileSource.GetCurrentAddress, TargetFileSource.GetCurrentAddress) then begin Result:= True; OperationType := fsoCopy; end else if TargetFileSource.IsClass(TFileSystemFileSource) and (fsoCopyOut in SourceFileSource.GetOperationsTypes) then begin Result:= True; OperationType := fsoCopyOut; end else if SourceFileSource.IsClass(TFileSystemFileSource) and (fsoCopyIn in TargetFileSource.GetOperationsTypes) then begin Result:= True; OperationType := fsoCopyIn; end else begin Result:= False; end; end; end. ���������������������������������������������doublecmd-1.1.22/src/filesources/ufilesourcewipeoperation.pas���������������������������������������0000644�0001750�0000144�00000010744�14743153644�023566� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSourceWipeOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs, uFileSourceOperation, uFileSourceOperationTypes, uFileSource, uFile; type TFileSourceWipeOperationStatistics = record CurrentFile: String; CurrentFileTotalBytes: Int64; CurrentFileDoneBytes: Int64; TotalFiles: Int64; DoneFiles: Int64; TotalBytes: Int64; DoneBytes: Int64; BytesPerSecond: Int64; RemainingTime: TDateTime; end; {en Operation that wipes files from an arbitrary file source. File source should match the class type. } { TFileSourceWipeOperation } TFileSourceWipeOperation = class(TFileSourceOperation) private FStatistics: TFileSourceWipeOperationStatistics; FStatisticsAtStartTime: TFileSourceWipeOperationStatistics; FStatisticsLock: TCriticalSection; //<en For synchronizing statistics. FFileSource: IFileSource; FFilesToWipe: TFiles; protected function GetID: TFileSourceOperationType; override; procedure DoReloadFileSources; override; procedure UpdateStatistics(var NewStatistics: TFileSourceWipeOperationStatistics); procedure UpdateStatisticsAtStartTime; override; property FileSource: IFileSource read FFileSource; property FilesToWipe: TFiles read FFilesToWipe; public constructor Create(aTargetFileSource: IFileSource; var theFilesToWipe: TFiles); virtual reintroduce; destructor Destroy; override; function GetDescription(Details: TFileSourceOperationDescriptionDetails): String; override; function RetrieveStatistics: TFileSourceWipeOperationStatistics; end; implementation uses uDCUtils, uLng; constructor TFileSourceWipeOperation.Create(aTargetFileSource: IFileSource; var theFilesToWipe: TFiles); begin with FStatistics do begin CurrentFile := ''; TotalFiles := 0; DoneFiles := 0; TotalBytes := 0; DoneBytes := 0; CurrentFileTotalBytes := 0; CurrentFileDoneBytes := 0; BytesPerSecond := 0; RemainingTime := 0; end; FStatisticsLock := TCriticalSection.Create; inherited Create(aTargetFileSource); FFileSource := aTargetFileSource; FFilesToWipe := theFilesToWipe; theFilesToWipe := nil; end; destructor TFileSourceWipeOperation.Destroy; begin inherited Destroy; if Assigned(FStatisticsLock) then FreeAndNil(FStatisticsLock); if Assigned(FFilesToWipe) then FreeAndNil(FFilesToWipe); end; function TFileSourceWipeOperation.GetID: TFileSourceOperationType; begin Result := fsoWipe; end; procedure TFileSourceWipeOperation.DoReloadFileSources; begin FFileSource.Reload(FFilesToWipe.Path); end; function TFileSourceWipeOperation.GetDescription(Details: TFileSourceOperationDescriptionDetails): String; begin case Details of fsoddJobAndTarget: begin if FilesToWipe.Count = 1 then Result := Format(rsOperWipingSomething, [FilesToWipe[0].FullPath]) else Result := Format(rsOperWipingIn, [FilesToWipe.Path]); end; else Result := rsOperWiping; end; end; procedure TFileSourceWipeOperation.UpdateStatistics(var NewStatistics: TFileSourceWipeOperationStatistics); begin FStatisticsLock.Acquire; try // Check if the value by which we calculate progress and remaining time has changed. if FStatistics.DoneBytes <> NewStatistics.DoneBytes then begin with NewStatistics do begin RemainingTime := EstimateRemainingTime(FStatisticsAtStartTime.DoneBytes, DoneBytes, TotalBytes, StartTime, SysUtils.Now, BytesPerSecond); // Update overall progress. if TotalBytes <> 0 then UpdateProgress(DoneBytes/TotalBytes); end; end; FStatistics := NewStatistics; finally FStatisticsLock.Release; end; end; procedure TFileSourceWipeOperation.UpdateStatisticsAtStartTime; begin FStatisticsLock.Acquire; try Self.FStatisticsAtStartTime := Self.FStatistics; finally FStatisticsLock.Release; end; end; function TFileSourceWipeOperation.RetrieveStatistics: TFileSourceWipeOperationStatistics; begin // Statistics have to be synchronized because there are multiple values // and they all have to be consistent at every moment. FStatisticsLock.Acquire; try Result := Self.FStatistics; finally FStatisticsLock.Release; end; end; end. ����������������������������doublecmd-1.1.22/src/filesources/uflatviewfilesource.pas��������������������������������������������0000644�0001750�0000144�00000001525�14743153644�022517� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFlatViewFileSource; {$mode objfpc}{$H+} interface uses uMultiListFileSource, uFileSourceOperation, uSearchResultFileSource; type { TFlatViewFileSource } TFlatViewFileSource = class(TSearchResultFileSource) public function IsPathAtRoot(Path: String): Boolean; override; function GetRootDir(sPath : String): String; override; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; end; implementation { TFlatViewFileSource } function TFlatViewFileSource.IsPathAtRoot(Path: String): Boolean; begin Result:= True; end; function TFlatViewFileSource.GetRootDir(sPath: String): String; begin Result:= FileSource.GetRootDir(sPath); end; function TFlatViewFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin Result:= True; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/ulocalfilesource.pas�����������������������������������������������0000644�0001750�0000144�00000000624�14743153644�021767� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uLocalFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uRealFileSource; type ILocalFileSource = interface(IRealFileSource) end; {en Base for classes of local file sources. Empty placeholder for now, allows to check whether a certain file source is local. } TLocalFileSource = class(TRealFileSource, ILocalFileSource) end; implementation end. ������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/uoperationthread.pas�����������������������������������������������0000644�0001750�0000144�00000002117�14743153644�022003� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uOperationThread; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceOperation; type {en Thread executing a file source operation. } TOperationThread = class(TThread) private FOperation: TFileSourceOperation; protected procedure Execute; override; public {en Creates a new thread for executing an operation. @param(CreateSuspended if @true the thread is not immediately started on creation.) @param(Operation is the file source operation that will be executed.) } constructor Create(CreateSuspended: Boolean; Operation: TFileSourceOperation); reintroduce; end; implementation uses uDebug, uExceptions; constructor TOperationThread.Create(CreateSuspended: Boolean; Operation: TFileSourceOperation); begin FreeOnTerminate := True; FOperation := Operation; FOperation.AssignThread(Self); inherited Create(CreateSuspended, DefaultStackSize); end; procedure TOperationThread.Execute; begin try FOperation.Execute; except on e: Exception do HandleException(e, Self); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/urealfilesource.pas������������������������������������������������0000644�0001750�0000144�00000000566�14743153644�021625� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uRealFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource; type IRealFileSource = interface(IFileSource) end; {en Base class for any real file source (filesystem, archive, network, ... - all sources able to produce real files). } TRealFileSource = class(TFileSource, IRealFileSource) end; implementation end. ������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/usampleforconfigfilesource.pas�������������������������������������0000644�0001750�0000144�00000005664�14743153644�024064� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uSampleForConfigFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uLocalFileSource, uFileSourceOperation, uFileSourceProperty, uFileSourceOperationTypes, uFileProperty; const SAMPLE_PATH = PathDelim+PathDelim+'DoubleCommander'+PathDelim; type ISampleForConfigFileSource = interface(ILocalFileSource) ['{C7D75C6D-38B6-4038-B3C4-4BB200A6FF28}'] end; {en File source for configuration purpose, just fake files. } { TSampleForConfigFileSource } TSampleForConfigFileSource = class(TLocalFileSource, ISampleForConfigFileSource) protected function GetSupportedFileProperties: TFilePropertiesTypes; override; public function GetRootDir(sPath : String): String; override; function GetProperties: TFileSourceProperties; override; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; // Retrieve operations permitted on the source. = capabilities? function GetOperationsTypes: TFileSourceOperationTypes; override; class function CreateFile(const APath: String): TFile; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function GetLocalName(var aFile: TFile): Boolean; override; end; implementation uses uFileSystemFileSource, uSampleForConfigListOperation, uLng; function TSampleForConfigFileSource.GetRootDir(sPath: String): String; begin Result:=sPath; end; function TSampleForConfigFileSource.GetProperties: TFileSourceProperties; begin Result := [fspVirtual]; end; function TSampleForConfigFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin Result := true; end; function TSampleForConfigFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; begin Result := TSampleForConfigListOperation.Create(Self, TargetPath); end; function TSampleForConfigFileSource.GetLocalName(var aFile: TFile): Boolean; begin Result:= True; end; function TSampleForConfigFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoList]; end; function TSampleForConfigFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := [fpName, fpSize]; end; class function TSampleForConfigFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes; SizeProperty := TFileSizeProperty.Create; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; CreationTimeProperty := TFileCreationDateTimeProperty.Create; LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create; LinkProperty := TFileLinkProperty.Create; OwnerProperty := TFileOwnerProperty.Create; TypeProperty := TFileTypeProperty.Create; CommentProperty := TFileCommentProperty.Create; end; end; end. ����������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/usampleforconfiglistoperation.pas����������������������������������0000644�0001750�0000144�00000003320�14743153644�024603� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uSampleForConfigListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uFileSource, uSampleForConfigFileSource; type TSampleForConfigListOperation = class(TFileSourceListOperation) private FFileSource: ISampleForConfigFileSource; public constructor Create(aFileSource: IFileSource; aPath: string); override; procedure MainExecute; override; end; implementation uses uFile; constructor TSampleForConfigListOperation.Create(aFileSource: IFileSource; aPath: string); begin FFiles := TFiles.Create(aPath); FFileSource := aFileSource as ISampleForConfigFileSource; inherited Create(aFileSource, aPath); end; procedure TSampleForConfigListOperation.MainExecute; var FakeFile: TFile; IndexFile: integer; const BaseName: array[0..11] of string = ('config', 'Step', 'Prog', 'setup', 'Report', 'Skip', 'Closer', 'Face', 'Win', 'Unix', 'App', 'Klopp'); SuffixName: array[0..11] of string = ('red', 'new', 'fst', 'South', 'slow', 'Cheap', 'dc', 'config', 'stop', 'Batch', 'Bash', 'rgctvcvt'); ExtName: array[0..11] of string = ('bin', 'exe', 'txt', 's19', 'Rar', 'zip', 'xlsx', 'pdf', 'cpp', 'pas', 'DPR', 'tmp'); begin FFiles.Clear; randseed:=Trunc(now); // Random from a day to another, but not during the day. So during the day, user will do refresh and always the same thing is re-shown. for Indexfile := 1 to 30 do begin FakeFile := TSampleForConfigFileSource.CreateFile(SAMPLE_PATH); FakeFile.Name := BaseName[random(12)] + SuffixName[random(12)] + '.' + ExtName[random(12)]; FakeFile.Size := 5000 + random(1000000); FFiles.Add(FakeFile); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/uvirtualfilesource.pas���������������������������������������������0000644�0001750�0000144�00000000666�14743153644�022371� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uVirtualFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource; type IVirtualFileSource = interface(IFileSource) end; {en Base class for any virtual file source (this can be any list of files, internal lists, temporary, links to favourite files, results from search queries, etc.). } TVirtualFileSource = class(TFileSource, IVirtualFileSource) end; implementation end. ��������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/vfs/���������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016516� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/vfs/uvfsexecuteoperation.pas���������������������������������������0000644�0001750�0000144�00000003654�14743153644�023522� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uVfsExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uFileSourceExecuteOperation, uVfsFileSource; type { TVfsExecuteOperation } TVfsExecuteOperation = class(TFileSourceExecuteOperation) private FVfsFileSource: IVfsFileSource; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses Forms, uWfxModule, uDCUtils, uGlobs; constructor TVfsExecuteOperation.Create( aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FVfsFileSource := aTargetFileSource as IVfsFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TVfsExecuteOperation.Initialize; begin end; procedure TVfsExecuteOperation.MainExecute; var Index: Integer; WfxModule: TWfxModule; begin FExecuteOperationResult:= fseorSuccess; if SameText(Verb, 'properties') then with FVfsFileSource do begin Index:= VfsFileList.FindFirstEnabledByName(RelativePath); if Index >= 0 then begin WfxModule:= gWFXPlugins.LoadModule(VfsFileList.FileName[Index]); if Assigned(WfxModule) then begin WfxModule.VFSInit; WfxModule.VFSConfigure(Application.MainForm.Tag); end; end; end; end; procedure TVfsExecuteOperation.Finalize; begin end; end. ������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/vfs/uvfsfilesource.pas���������������������������������������������0000644�0001750�0000144�00000006334�14743153644�022275� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uVfsFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uWFXModule, uFileSourceProperty, uFileSourceOperationTypes, uVirtualFileSource, uFileProperty, uFileSource, uFileSourceOperation, uFile; type IVfsFileSource = interface(IVirtualFileSource) ['{87D0A3EF-C168-44C1-8B10-3AEC0753846A}'] function GetWfxModuleList: TWFXModuleList; property VfsFileList: TWFXModuleList read GetWfxModuleList; end; { TVfsFileSource } TVfsFileSource = class(TVirtualFileSource, IVfsFileSource) private FWFXModuleList: TWFXModuleList; function GetWfxModuleList: TWFXModuleList; protected function GetSupportedFileProperties: TFilePropertiesTypes; override; public constructor Create(aWFXModuleList: TWFXModuleList); reintroduce; destructor Destroy; override; class function CreateFile(const APath: String): TFile; override; // Retrieve operations permitted on the source. = capabilities? function GetOperationsTypes: TFileSourceOperationTypes; override; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; override; function GetRootDir(sPath : String): String; override; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; property VfsFileList: TWFXModuleList read FWFXModuleList; end; implementation uses LCLProc, uVfsListOperation, uVfsExecuteOperation; constructor TVfsFileSource.Create(aWFXModuleList: TWFXModuleList); begin inherited Create; FWFXModuleList:= TWFXModuleList.Create; FWFXModuleList.Assign(aWFXModuleList); end; destructor TVfsFileSource.Destroy; begin FreeAndNil(FWFXModuleList); inherited Destroy; end; class function TVfsFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin LinkProperty:= TFileLinkProperty.Create; AttributesProperty := TNtfsFileAttributesProperty.Create; end; end; function TVfsFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoList, fsoExecute]; end; function TVfsFileSource.GetProperties: TFileSourceProperties; begin Result := [fspVirtual]; end; function TVfsFileSource.GetRootDir(sPath: String): String; begin Result:= 'vfs:' + PathDelim; end; function TVfsFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpAttributes, fpLink]; end; function TVfsFileSource.GetWfxModuleList: TWFXModuleList; begin Result := FWFXModuleList; end; function TVfsFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TVfsListOperation.Create(TargetFileSource, TargetPath); end; function TVfsFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TVfsExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/vfs/uvfslistoperation.pas������������������������������������������0000644�0001750�0000144�00000003447�14743153644�023033� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uVfsListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uVfsFileSource, uFileSource; type TVfsListOperation = class(TFileSourceListOperation) private FVfsFileSource: IVfsFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses LCLProc, DCFileAttributes, uFile, uVfsModule, uDCUtils; constructor TVfsListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FVfsFileSource := aFileSource as IVfsFileSource; inherited Create(aFileSource, aPath); end; procedure TVfsListOperation.MainExecute; var I : Integer; aFile: TFile; APath: String; VfsModule: TVfsModule; begin FFiles.Clear; with FVfsFileSource do for I := 0 to VfsFileList.Count - 1 do begin CheckOperationState; if VfsFileList.Enabled[I] then begin aFile := TVfsFileSource.CreateFile(Path); aFile.Name:= VfsFileList.Name[I]; aFile.Attributes:= FILE_ATTRIBUTE_NORMAL or FILE_ATTRIBUTE_VIRTUAL; aFile.LinkProperty.LinkTo:= mbExpandFileName(VfsFileList.FileName[I]); FFiles.Add(aFile); end; end; for I:= 0 to gVfsModuleList.Count - 1 do begin CheckOperationState; VfsModule:= TVfsModule(gVfsModuleList.Objects[I]); if VfsModule.Visible then begin aFile := TVfsFileSource.CreateFile(Path); aFile.Name:= gVfsModuleList.Strings[I]; if VfsModule.FileSourceClass.GetMainIcon(APath) then begin aFile.LinkProperty.LinkTo:= mbExpandFileName(APath); aFile.Attributes:= FILE_ATTRIBUTE_OFFLINE or FILE_ATTRIBUTE_VIRTUAL; end; FFiles.Add(aFile); end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020063� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/fwcxarchivecopyoperationoptions.lfm���������������������0000644�0001750�0000144�00000004046�14743153644�027330� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object WcxArchiveCopyOperationOptionsUI: TWcxArchiveCopyOperationOptionsUI Left = 0 Height = 158 Top = 0 Width = 549 AutoSize = True ClientHeight = 158 ClientWidth = 549 TabOrder = 0 DesignLeft = 114 DesignTop = 311 object pnlComboBoxes: TPanel AnchorSideLeft.Control = Owner Left = 0 Height = 23 Top = 0 Width = 187 AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 5 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 23 ClientWidth = 187 TabOrder = 0 object lblFileExists: TLabel Left = 0 Height = 15 Top = 4 Width = 82 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When file exists' FocusControl = cmbFileExists ParentColor = False end object cmbFileExists: TComboBox Left = 87 Height = 23 Top = 0 Width = 100 ItemHeight = 15 Style = csDropDownList TabOrder = 0 end end object pnlCheckboxes: TPanel AnchorSideLeft.Control = pnlComboBoxes AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlComboBoxes Left = 195 Height = 19 Top = 0 Width = 60 AutoSize = True BorderSpacing.Left = 8 BevelOuter = bvNone BevelWidth = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 19 ClientWidth = 60 TabOrder = 1 Visible = False object cbEncrypt: TCheckBox Left = 0 Height = 19 Top = 0 Width = 60 Caption = 'Encr&ypt' TabOrder = 0 end end object btnConfig: TButton AnchorSideLeft.Control = Owner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = pnlComboBoxes AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 231 Height = 33 Top = 23 Width = 87 AutoSize = True BorderSpacing.InnerBorder = 4 Caption = 'Con&figure' OnClick = btnConfigClick TabOrder = 2 Visible = False end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/fwcxarchivecopyoperationoptions.lrj���������������������0000644�0001750�0000144�00000001011�14743153644�027326� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":111687171,"name":"twcxarchivecopyoperationoptionsui.lblfileexists.caption","sourcebytes":[87,104,101,110,32,102,105,108,101,32,101,120,105,115,116,115],"value":"When file exists"}, {"hash":77915316,"name":"twcxarchivecopyoperationoptionsui.cbencrypt.caption","sourcebytes":[69,110,99,114,38,121,112,116],"value":"Encr&ypt"}, {"hash":214649477,"name":"twcxarchivecopyoperationoptionsui.btnconfig.caption","sourcebytes":[67,111,110,38,102,105,103,117,114,101],"value":"Con&figure"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/fwcxarchivecopyoperationoptions.pas���������������������0000644�0001750�0000144�00000006112�14743153644�027331� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fWcxArchiveCopyOperationOptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ExtCtrls, uFileSourceOperationOptionsUI, uWcxArchiveFileSource, uWcxArchiveCopyInOperation; type { TWcxArchiveCopyOperationOptionsUI } TWcxArchiveCopyOperationOptionsUI = class(TFileSourceOperationOptionsUI) btnConfig: TButton; cbEncrypt: TCheckBox; cmbFileExists: TComboBox; lblFileExists: TLabel; pnlCheckboxes: TPanel; pnlComboBoxes: TPanel; procedure btnConfigClick(Sender: TObject); private FFileSource: IWcxArchiveFileSource; procedure SetOperationOptions(CopyInOperation: TWcxArchiveCopyInOperation); overload; public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; procedure SaveOptions; override; procedure SetOperationOptions(Operation: TObject); override; end; { TWcxArchiveCopyInOperationOptionsUI } TWcxArchiveCopyInOperationOptionsUI = class(TWcxArchiveCopyOperationOptionsUI) public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; end; implementation {$R *.lfm} uses Dialogs, DCStrUtils, WcxPlugin, uLng, uGlobs, uFileSourceOperationOptions, uFileSourceCopyOperation; { TWcxArchiveCopyInOperationOptionsUI } constructor TWcxArchiveCopyInOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin FFileSource := AFileSource as IWcxArchiveFileSource; inherited Create(AOwner, AFileSource); pnlCheckboxes.Visible := True; btnConfig.Visible := True; end; { TWcxArchiveCopyOperationOptionsUI } procedure TWcxArchiveCopyOperationOptionsUI.btnConfigClick(Sender: TObject); begin try FFileSource.WcxModule.VFSConfigure(Handle); except on E: Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; end; procedure TWcxArchiveCopyOperationOptionsUI.SetOperationOptions( CopyInOperation: TWcxArchiveCopyInOperation); var AFlags: Integer; begin AFlags := CopyInOperation.PackingFlags; if cbEncrypt.Checked then AFlags := AFlags or PK_PACK_ENCRYPT; CopyInOperation.PackingFlags := AFlags; end; constructor TWcxArchiveCopyOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited; ParseLineToList(rsFileOpCopyMoveFileExistsOptions, cmbFileExists.Items); // Load default options. case gOperationOptionFileExists of fsoofeNone : cmbFileExists.ItemIndex := 0; fsoofeOverwrite: cmbFileExists.ItemIndex := 1; fsoofeSkip : cmbFileExists.ItemIndex := 2; end; end; procedure TWcxArchiveCopyOperationOptionsUI.SaveOptions; begin // TODO: Saving options for each file source operation separately. end; procedure TWcxArchiveCopyOperationOptionsUI.SetOperationOptions(Operation: TObject); begin with Operation as TFileSourceCopyOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; end; if Operation is TWcxArchiveCopyInOperation then SetOperationOptions(TWcxArchiveCopyInOperation(Operation)); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivecalcstatisticsoperation.pas������������������0000644�0001750�0000144�00000007166�14743153644�030011� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCalcStatisticsOperation, uFileSource, uWcxArchiveFileSource, uFile; type TWcxArchiveCalcStatisticsOperation = class(TFileSourceCalcStatisticsOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; FStatistics: TFileSourceCalcStatisticsOperationStatistics; // local copy of statistics procedure ProcessFile(aFile: TFile); procedure ProcessSubDirs(const srcPath: String); public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; end; implementation uses DCOSUtils, uWcxModule, DCStrUtils, DCDateTimeUtils; constructor TWcxArchiveCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin inherited Create(aTargetFileSource, theFiles); FWcxArchiveFileSource:= aTargetFileSource as IWcxArchiveFileSource; end; destructor TWcxArchiveCalcStatisticsOperation.Destroy; begin inherited Destroy; end; procedure TWcxArchiveCalcStatisticsOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; end; procedure TWcxArchiveCalcStatisticsOperation.MainExecute; var CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to Files.Count - 1 do begin ProcessFile(Files[CurrentFileIndex]); CheckOperationState; end; end; procedure TWcxArchiveCalcStatisticsOperation.ProcessFile(aFile: TFile); begin FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); if aFile.IsDirectory then begin Inc(FStatistics.Directories); ProcessSubDirs(aFile.Path + aFile.Name + DirectorySeparator); end else if aFile.IsLink then begin Inc(FStatistics.Links); end else begin // Not always this will be regular file (on Unix can be socket, FIFO, block, char, etc.) // Maybe check with: FPS_ISREG() on Unix? Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + aFile.Size; if aFile.ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := aFile.ModificationTime; if aFile.ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := aFile.ModificationTime; end; UpdateStatistics(FStatistics); end; procedure TWcxArchiveCalcStatisticsOperation.ProcessSubDirs(const srcPath: String); var I: Integer; AFileList: TList; Header: TWCXHeader; CurrFileName: String; ModificationTime: TDateTime; begin AFileList:= FWcxArchiveFileSource.ArchiveFileList.LockList; try for I:= 0 to AFileList.Count - 1 do begin Header := TWCXHeader(AFileList.Items[I]); CurrFileName := PathDelim + Header.FileName; if not IsInPath(srcPath, CurrFileName, True, False) then Continue; if FPS_ISDIR(Header.FileAttr) then Inc(FStatistics.Directories) else if FPS_ISLNK(Header.FileAttr) then Inc(FStatistics.Links) else begin Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + Header.UnpSize; ModificationTime:= Header.DateTime; if ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := ModificationTime; if ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := ModificationTime; end; end; finally FWcxArchiveFileSource.ArchiveFileList.UnlockList; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivecopyinoperation.pas��������������������������0000644�0001750�0000144�00000042463�14743153644�026274� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveCopyInOperation; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, DCStringHashListUtf8, WcxPlugin, uLog, uGlobs, uFileSourceCopyOperation, uFileSource, uFileSourceOperation, uFile, uWcxModule, uWcxArchiveFileSource, uArchiveCopyOperation, uFileSourceOperationUI, uFileSourceOperationOptions, uFileSourceOperationOptionsUI; type { TWcxArchiveCopyInOperation } TWcxArchiveCopyInOperation = class(TArchiveCopyInOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; FFileList: TStringHashListUtf8; {en Convert TFiles into a string separated with #0 (format used by WCX). } function GetFileList(const theFiles: TFiles): String; procedure SetTarBefore(const AValue: Boolean); procedure ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions = []); procedure LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); procedure DeleteFiles(const aFiles: TFiles); protected function Tar: Boolean; procedure SetProcessDataProc(hArcData: TArcHandle); protected FCurrentFile: TFile; FCurrentTargetFilePath: String; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); function FileExistsMessage(aSourceFile: TFile; aTargetHeader: TWcxHeader): String; function FileExists(aSourceFile: TFile; aTargetHeader: TWcxHeader): TFileSourceOperationOptionFileExists; public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class procedure ClearCurrentOperation; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property PackingFlags: Integer read FPackingFlags write FPackingFlags; property TarBefore: Boolean read FTarBefore write SetTarBefore; end; implementation uses LazUTF8, FileUtil, DCStrUtils, uDCUtils, uLng, fWcxArchiveCopyOperationOptions, uFileSystemFileSource, DCOSUtils, uTarWriter, uClassesEx, DCConvertEncoding, DCDateTimeUtils, uArchiveFileSourceUtil; // ---------------------------------------------------------------------------- // WCX callbacks var // This global variable is used to store currently running operation // for plugins that not supports background operations (see GetBackgroundFlags) WcxCopyInOperationG: TWcxArchiveCopyInOperation = nil; threadvar // This thread variable is used to store currently running operation // for plugins that supports background operations (see GetBackgroundFlags) WcxCopyInOperationT: TWcxArchiveCopyInOperation; function ProcessDataProc(WcxCopyInOperation: TWcxArchiveCopyInOperation; FileName: String; Size: LongInt): LongInt; begin //DCDebug('Working (' + IntToStr(GetCurrentThreadId) + ') ' + FileName + ' Size = ' + IntToStr(Size)); Result := 1; if Assigned(WcxCopyInOperation) then begin if WcxCopyInOperation.State = fsosStopping then // Cancel operation Exit(0); with WcxCopyInOperation.FStatistics do begin CurrentFileFrom:= FileName; // Get the number of bytes processed since the previous call if Size > 0 then begin DoneBytes := DoneBytes + Size; if TotalFiles = 1 then begin CurrentFileDoneBytes := DoneBytes; CurrentFileTotalBytes := TotalBytes; end; end // Get progress percent value to directly set progress bar else if Size < 0 then begin // Total operation percent if (Size >= -100) and (Size <= -1) then begin DoneBytes := TotalBytes * Int64(-Size) div 100; end // Current file percent else if (Size >= -1100) and (Size <= -1000) then begin // Show only percent CurrentFileTotalBytes := -100; CurrentFileDoneBytes := Int64(-Size) - 1000; end; end; WcxCopyInOperation.UpdateStatistics(WcxCopyInOperation.FStatistics); if not WcxCopyInOperation.AppProcessMessages(True) then Exit(0); end; end; end; function ProcessDataProcAG(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyInOperationG, CeSysToUtf8(StrPas(FileName)), Size); end; function ProcessDataProcWG(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyInOperationG, UTF16ToUTF8(UnicodeString(FileName)), Size); end; function ProcessDataProcAT(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyInOperationT, CeSysToUtf8(StrPas(FileName)), Size); end; function ProcessDataProcWT(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyInOperationT, UTF16ToUTF8(UnicodeString(FileName)), Size); end; // ---------------------------------------------------------------------------- constructor TWcxArchiveCopyInOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FWcxArchiveFileSource := aTargetFileSource as IWcxArchiveFileSource; FPackingFlags := PK_PACK_SAVE_PATHS; FTarBefore:= False; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); FNeedsConnection:= (FWcxArchiveFileSource.WcxModule.BackgroundFlags and BACKGROUND_PACK = 0); FFileList:= TStringHashListUtf8.Create(True); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; with FStatistics do begin DoneFiles := -1; CurrentFileDoneBytes := -1; UpdateStatistics(FStatistics); end; end; destructor TWcxArchiveCopyInOperation.Destroy; var Index: Integer; begin inherited Destroy; for Index:= 0 to FFileList.Count - 1 do begin TObject(FFileList.List[Index]^.Data).Free; end; FreeAndNil(FFileList); FreeAndNil(FFullFilesTree); end; procedure TWcxArchiveCopyInOperation.Initialize; var Index: Integer; Item: TObjectEx; AFileList: TList; begin // Is plugin allow multiple Operations? if FNeedsConnection then WcxCopyInOperationG := Self else WcxCopyInOperationT := Self; // Gets full list of files (recursive) FillAndCount(SourceFiles, FFullFilesTree, FStatistics.TotalFiles, FStatistics.TotalBytes); // Need to check file existence if FFileExistsOption <> fsoofeOverwrite then begin AFileList:= FWcxArchiveFileSource.ArchiveFileList.LockList; try // Populate archive file list for Index:= 0 to AFileList.Count - 1 do begin Item:= TObjectEx(AFileList[Index]).Clone; FFileList.Add(UTF8LowerCase(TWcxHeader(Item).FileName), Item); end; finally FWcxArchiveFileSource.ArchiveFileList.UnlockList; end; end; end; procedure TWcxArchiveCopyInOperation.MainExecute; var iResult: Integer; sFileList: String; sDestPath: String; WcxModule: TWcxModule; begin // Put to TAR archive if needed if FTarBefore and Tar then Exit; WcxModule := FWcxArchiveFileSource.WcxModule; sDestPath := ExcludeFrontPathDelimiter(TargetPath); sDestPath := ExcludeTrailingPathDelimiter(sDestPath); sDestPath := sDestPath; with FStatistics do begin if FTarBefore then CurrentFileDoneBytes := -1; CurrentFileTo:= FWcxArchiveFileSource.ArchiveFileName; UpdateStatistics(FStatistics); end; SetProcessDataProc(wcxInvalidHandle); WcxModule.WcxSetChangeVolProc(wcxInvalidHandle); // Convert TFiles into String; sFileList:= GetFileList(FFullFilesTree); // Nothing to pack (user skip all files) if sFileList = #0 then Exit; iResult := WcxModule.WcxPackFiles( FWcxArchiveFileSource.ArchiveFileName, sDestPath, // no trailing path delimiter here IncludeTrailingPathDelimiter(FFullFilesTree.Path), // end with path delimiter here sFileList, PackingFlags); // Check for errors. if iResult <> E_SUCCESS then begin // User aborted operation. if iResult = E_EABORTED then RaiseAbortOperation; ShowError(Format(rsMsgLogError + rsMsgLogPack, [FWcxArchiveFileSource.ArchiveFileName + ' : ' + GetErrorMsg(iResult)]), iResult, [log_arc_op]); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogPack, [FWcxArchiveFileSource.ArchiveFileName]), [log_arc_op], lmtSuccess); FStatistics.DoneFiles:= FStatistics.TotalFiles; UpdateStatistics(FStatistics); end; // Delete temporary TAR archive if needed if FTarBefore then mbDeleteFile(FTarFileName); end; procedure TWcxArchiveCopyInOperation.Finalize; begin ClearCurrentOperation; end; function TWcxArchiveCopyInOperation.GetFileList(const theFiles: TFiles): String; var I: Integer; SubPath: String; FileName: String; Header: TWCXHeader; ArchiveExists: Boolean; begin Result := ''; ArchiveExists := FFileList.Count > 0; SubPath := UTF8LowerCase(ExcludeFrontPathDelimiter(TargetPath)); for I := 0 to theFiles.Count - 1 do begin // Filenames must be relative to the current directory. FileName := ExtractDirLevel(theFiles.Path, theFiles[I].FullPath); // Special treatment of directories. if theFiles[i].IsDirectory then begin // TC ends paths to directories to be packed with '\'. FileName := IncludeTrailingPathDelimiter(FileName); end // Need to check file existence else if ArchiveExists then begin Header := TWcxHeader(FFileList[SubPath + UTF8LowerCase(FileName)]); if Assigned(Header) then begin if FileExists(theFiles[I], Header) = fsoofeSkip then Continue; end; end; Result := Result + FileName + #0; end; Result := Result + #0; end; procedure TWcxArchiveCopyInOperation.SetTarBefore(const AValue: Boolean); begin with FWcxArchiveFileSource, FWcxArchiveFileSource.WcxModule do begin FTarBefore:= AValue; if FTarBefore and Assigned(PackToMem) and (PluginCapabilities and PK_CAPS_MEMPACK <> 0) then FNeedsConnection:= (BackgroundFlags and BACKGROUND_MEMPACK = 0) else FNeedsConnection:= (BackgroundFlags and BACKGROUND_PACK = 0); end; end; procedure TWcxArchiveCopyInOperation.ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions); begin LogMessage(sMessage, logOptions, lmtError); if (gSkipFileOpError = False) and (iError > E_SUCCESS) then begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; end; procedure TWcxArchiveCopyInOperation.LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TWcxArchiveCopyInOperation.DeleteFiles(const aFiles: TFiles); var I: Integer; aFile: TFile; begin for I:= aFiles.Count - 1 downto 0 do begin aFile:= aFiles[I]; if aFile.IsDirectory then mbRemoveDir(aFile.FullPath) else mbDeleteFile(aFile.FullPath); end; end; procedure TWcxArchiveCopyInOperation.SetProcessDataProc(hArcData: TArcHandle); begin with FWcxArchiveFileSource.WcxModule do begin if FNeedsConnection then WcxSetProcessDataProc(hArcData, @ProcessDataProcAG, @ProcessDataProcWG) else WcxSetProcessDataProc(hArcData, @ProcessDataProcAT, @ProcessDataProcWT); end; end; procedure TWcxArchiveCopyInOperation.QuestionActionHandler( Action: TFileSourceOperationUIAction); begin if Action = fsouaCompare then ShowCompareFilesUI(FCurrentFile, IncludeFrontPathDelimiter(FCurrentTargetFilePath)); end; function TWcxArchiveCopyInOperation.FileExistsMessage(aSourceFile: TFile; aTargetHeader: TWcxHeader): String; begin Result:= rsMsgFileExistsOverwrite + LineEnding + aTargetHeader.FileName + LineEnding; Result:= Result + Format(rsMsgFileExistsFileInfo, [IntToStrTS(aTargetHeader.UnpSize), DateTimeToStr(aTargetHeader.DateTime)]) + LineEnding; Result:= Result + LineEnding + rsMsgFileExistsWithFile + LineEnding + aSourceFile.FullPath + LineEnding + Format(rsMsgFileExistsFileInfo, [IntToStrTS(aSourceFile.Size), DateTimeToStr(aSourceFile.ModificationTime)]); end; function TWcxArchiveCopyInOperation.FileExists(aSourceFile: TFile; aTargetHeader: TWcxHeader): TFileSourceOperationOptionFileExists; const PossibleResponses: array[0..8] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourOverwriteLarger, fsourOverwriteAll, fsourSkipAll, fsourOverwriteSmaller, fsourOverwriteOlder, fsouaCompare, fsourCancel); function OverwriteOlder: TFileSourceOperationOptionFileExists; begin if aSourceFile.ModificationTime > aTargetHeader.DateTime then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteSmaller: TFileSourceOperationOptionFileExists; begin if aSourceFile.Size > aTargetHeader.UnpSize then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteLarger: TFileSourceOperationOptionFileExists; begin if aSourceFile.Size < aTargetHeader.UnpSize then Result := fsoofeOverwrite else Result := fsoofeSkip; end; begin case FFileExistsOption of fsoofeNone: begin FCurrentFile := aSourceFile; FCurrentTargetFilePath := aTargetHeader.FileName; case AskQuestion(FileExistsMessage(aSourceFile, aTargetHeader), '', PossibleResponses, fsourOverwrite, fsourSkip, @QuestionActionHandler) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourOverwriteOlder: begin FFileExistsOption := fsoofeOverwriteOlder; Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin FFileExistsOption := fsoofeOverwriteSmaller; Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin FFileExistsOption := fsoofeOverwriteLarger; Result:= OverwriteLarger; end; fsourNone, fsourCancel: RaiseAbortOperation; end; end; fsoofeOverwriteOlder: begin Result:= OverwriteOlder; end; fsoofeOverwriteSmaller: begin Result:= OverwriteSmaller; end; fsoofeOverwriteLarger: begin Result:= OverwriteLarger; end; else Result := FFileExistsOption; end; end; class procedure TWcxArchiveCopyInOperation.ClearCurrentOperation; begin WcxCopyInOperationG := nil; end; class function TWcxArchiveCopyInOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result:= TWcxArchiveCopyInOperationOptionsUI; end; function TWcxArchiveCopyInOperation.Tar: Boolean; var TarWriter: TTarWriter = nil; begin with FWcxArchiveFileSource, FWcxArchiveFileSource.WcxModule do begin if Assigned(PackToMem) and (PluginCapabilities and PK_CAPS_MEMPACK <> 0) then begin FTarFileName:= ArchiveFileName; TarWriter:= TTarWriter.Create(FTarFileName, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, WcxModule ); Result:= True; end else begin FTarFileName:= RemoveFileExt(ArchiveFileName); TarWriter:= TTarWriter.Create(FTarFileName, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics ); Result:= False; end; end; try if TarWriter.ProcessTree(FFullFilesTree, FStatistics) then begin if Result and (PackingFlags and PK_PACK_MOVE_FILES <> 0) then DeleteFiles(FFullFilesTree) else begin // Fill file list with tar archive file FFullFilesTree.Clear; FFullFilesTree.Path:= ExtractFilePath(FTarFileName); FFullFilesTree.Add(TFileSystemFileSource.CreateFileFromFile(FTarFileName)); end; end; finally FreeAndNil(TarWriter); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivecopyoutoperation.pas�������������������������0000644�0001750�0000144�00000064661�14743153644�026501� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveCopyOutOperation; {$mode objfpc}{$H+} {$if FPC_FULLVERSION >= 30300} {$modeswitch arraytodynarray} {$endif} {$include calling.inc} interface uses Classes, LazFileUtils,SysUtils, DCStringHashListUtf8, WcxPlugin, uLog, uGlobs, uFileSourceCopyOperation, uArchiveCopyOperation, uFileSource, uFileSourceOperation, uFileSourceOperationUI, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uMasks, uWcxModule, uWcxArchiveFileSource; type { TWcxArchiveCopyOutOperation } TWcxArchiveCopyOutOperation = class(TArchiveCopyOutOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics FRenamingFiles: Boolean; FRenameNameMask, FRenameExtMask: String; // Options. FExtractWithoutPath: Boolean; {en Creates neccessary paths before extracting files from archive. Also counts size of all files that will be extracted. @param(Files List of files/directories to extract (relative to archive root).) @param(MaskList Only directories containing files matching this mask will be created.) @param(sDestPath Destination path where the files will be extracted.) @param(CurrentArchiveDir Path inside the archive from where the files will be extracted.) @param(CreatedPaths This list will be filled with absolute paths to directories that were created, together with their attributes.)} procedure CreateDirsAndCountFiles(const theFiles: TFiles; MaskList: TMaskList; sDestPath: String; CurrentArchiveDir: String; var CreatedPaths: TStringHashListUtf8); {en Sets attributes for directories. @param(Paths The list of absolute paths, which attributes are to be set. Each list item's data field must be a pointer to THeaderData, from where the attributes are retrieved.} function SetDirsAttributes(const Paths: TStringHashListUtf8): Boolean; function DoFileExists(Header: TWcxHeader; var AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; procedure ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions = []); procedure LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); protected FCurrentFilePath: String; FCurrentTargetFilePath: String; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); procedure SetProcessDataProc(hArcData: TArcHandle); public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class procedure ClearCurrentOperation; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property ExtractWithoutPath: Boolean read FExtractWithoutPath write FExtractWithoutPath; end; implementation uses Forms, LazUTF8, FileUtil, contnrs, DCOSUtils, DCStrUtils, uDCUtils, Math, DateUtils, fWcxArchiveCopyOperationOptions, uFileSystemUtil, uFileProcs, uLng, DCDateTimeUtils, DCBasicTypes, uShowMsg, DCConvertEncoding; // ---------------------------------------------------------------------------- // WCX callbacks var // This global variable is used to store currently running operation // for plugins that not supports background operations (see GetBackgroundFlags) WcxCopyOutOperationG: TWcxArchiveCopyOutOperation = nil; threadvar // This thread variable is used to store currently running operation // for plugins that supports background operations (see GetBackgroundFlags) WcxCopyOutOperationT: TWcxArchiveCopyOutOperation; function ProcessDataProc(WcxCopyOutOperation: TWcxArchiveCopyOutOperation; FileName: String; Size: LongInt; UpdateName: Pointer): LongInt; begin //DCDebug('Working (' + IntToStr(GetCurrentThreadId) + ') ' + FileName + ' Size = ' + IntToStr(Size)); Result := 1; if Assigned(WcxCopyOutOperation) then begin if WcxCopyOutOperation.State = fsosStopping then // Cancel operation Exit(0); with WcxCopyOutOperation.FStatistics do begin // Update file name if Assigned(UpdateName) then begin CurrentFileFrom:= FileName; end; // Get the number of bytes processed since the previous call if Size > 0 then begin if CurrentFileDoneBytes < 0 then begin CurrentFileDoneBytes:= 0; end; CurrentFileDoneBytes := CurrentFileDoneBytes + Size; if CurrentFileDoneBytes > CurrentFileTotalBytes then begin CurrentFileDoneBytes := CurrentFileTotalBytes; end; DoneBytes := DoneBytes + Size; end // Get progress percent value to directly set progress bar else if Size < 0 then begin // Total operation percent if (Size >= -100) and (Size <= -1) then begin if (TotalBytes = 0) then TotalBytes:= -100; DoneBytes := Abs(TotalBytes) * Int64(-Size) div 100; end // Current file percent else if (Size >= -1100) and (Size <= -1000) then begin if (CurrentFileTotalBytes = 0) then CurrentFileTotalBytes:= -100; CurrentFileDoneBytes := Abs(CurrentFileTotalBytes) * (Int64(-Size) - 1000) div 100; end; end; //DCDebug('CurrentDone = ' + IntToStr(CurrentFileDoneBytes) + ' Done = ' + IntToStr(DoneBytes)); //DCDebug('CurrentTotal = ' + IntToStr(CurrentFileTotalBytes) + ' Total = ' + IntToStr(TotalBytes)); WcxCopyOutOperation.UpdateStatistics(WcxCopyOutOperation.FStatistics); if not WcxCopyOutOperation.AppProcessMessages(True) then Exit(0); end; end; end; function ProcessDataProcAG(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyOutOperationG, CeSysToUtf8(StrPas(FileName)), Size, FileName); end; function ProcessDataProcWG(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyOutOperationG, UTF16ToUTF8(UnicodeString(FileName)), Size, FileName); end; function ProcessDataProcAT(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyOutOperationT, CeSysToUtf8(StrPas(FileName)), Size, FileName); end; function ProcessDataProcWT(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxCopyOutOperationT, UTF16ToUTF8(UnicodeString(FileName)), Size, FileName); end; // ---------------------------------------------------------------------------- constructor TWcxArchiveCopyOutOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FWcxArchiveFileSource := aSourceFileSource as IWcxArchiveFileSource; FFileExistsOption := fsoofeNone; FExtractWithoutPath := False; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); FNeedsConnection:= (FWcxArchiveFileSource.WcxModule.BackgroundFlags and BACKGROUND_UNPACK = 0); end; destructor TWcxArchiveCopyOutOperation.Destroy; begin inherited Destroy; end; procedure TWcxArchiveCopyOutOperation.Initialize; var Index: Integer; ACount: Integer; AFileName: String; ArcFileList: TList; begin // Is plugin allow multiple Operations? if FNeedsConnection then WcxCopyOutOperationG := Self else WcxCopyOutOperationT := Self; // Extract without path from flat view if not FExtractWithoutPath then begin FExtractWithoutPath := SourceFiles.Flat; end; if efSmartExtract in ExtractFlags then begin ACount:= 0; ArcFileList := FWcxArchiveFileSource.ArchiveFileList.Clone; try for Index := 0 to ArcFileList.Count - 1 do begin AFileName := PathDelim + TWcxHeader(ArcFileList[Index]).FileName; if IsInPath(PathDelim, AFileName, False, False) then begin Inc(ACount); if (ACount > 1) then begin FTargetPath := FTargetPath + ExtractOnlyFileName(FWcxArchiveFileSource.ArchiveFileName) + PathDelim; Break; end; end; end; finally ArcFileList.Free; end; end; // Check rename mask FRenamingFiles := (RenameMask <> '*.*') and (RenameMask <> ''); if FRenamingFiles then SplitFileMask(RenameMask, FRenameNameMask, FRenameExtMask); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; end; procedure TWcxArchiveCopyOutOperation.MainExecute; var ArcHandle: TArcHandle; Header: TWCXHeader; TargetFileName: String; CreatedPaths: TStringHashListUtf8; OpenResult: Longint; iResult: Integer; Files: TFiles = nil; WcxModule: TWcxModule; MaskList: TMaskList; begin WcxModule := FWcxArchiveFileSource.WcxModule; ArcHandle := WcxModule.OpenArchiveHandle(FWcxArchiveFileSource.ArchiveFileName, PK_OM_EXTRACT, OpenResult); if ArcHandle = 0 then begin AskQuestion(uWcxModule.GetErrorMsg(OpenResult), '', [fsourOk], fsourOk, fsourOk); RaiseAbortOperation; end; // Extract all selected files/folders if (FExtractMask = '') or (FExtractMask = '*.*') or (FExtractMask = '*') then MaskList:= nil else begin MaskList:= TMaskList.Create(FExtractMask); end; // Convert file list so that filenames are relative to archive root. Files := SourceFiles.Clone; ChangeFileListRoot(PathDelim, Files); CreatedPaths := TStringHashListUtf8.Create(True); try // Count total files size and create needed directories. CreateDirsAndCountFiles(Files, MaskList, TargetPath, Files.Path, CreatedPaths); SetProcessDataProc(ArcHandle); WcxModule.WcxSetChangeVolProc(ArcHandle); while (WcxModule.ReadWCXHeader(ArcHandle, Header) = E_SUCCESS) do try CheckOperationState; // Now check if the file is to be extracted. if (not FPS_ISDIR(Header.FileAttr)) // Omit directories (we handle them ourselves). and MatchesFileList(Files, Header.FileName) // Check if it's included in the filelist and ((MaskList = nil) or MaskList.Matches(ExtractFileNameEx(Header.FileName))) // And name matches file mask then begin if FExtractWithoutPath then TargetFileName := ExtractFileNameEx(Header.FileName) else TargetFileName := ExtractDirLevel(Files.Path, Header.FileName); if FRenamingFiles then begin TargetFileName := ExtractFilePathEx(TargetFileName) + ApplyRenameMask(ExtractFileNameEx(TargetFileName), FRenameNameMask, FRenameExtMask); end; TargetFileName := TargetPath + ReplaceInvalidChars(TargetFileName); with FStatistics do begin CurrentFileFrom := Header.FileName; CurrentFileTo := TargetFileName; if (Header.UnpSize < 0) then CurrentFileTotalBytes := 0 else begin CurrentFileTotalBytes := Header.UnpSize; end; CurrentFileDoneBytes := -1; UpdateStatistics(FStatistics); end; if (DoFileExists(Header, TargetFileName) = fsoofeOverwrite) then iResult := WcxModule.WcxProcessFile(ArcHandle, PK_EXTRACT, EmptyStr, TargetFileName) else iResult := WcxModule.WcxProcessFile(ArcHandle, PK_SKIP, EmptyStr, EmptyStr); if iResult <> E_SUCCESS then begin // User aborted operation. if iResult = E_EABORTED then RaiseAbortOperation; ShowError(Format(rsMsgLogError + rsMsgLogExtract, [FWcxArchiveFileSource.ArchiveFileName + PathDelim + Header.FileName + ' -> ' + TargetFileName + ' : ' + GetErrorMsg(iResult)]), iResult, [log_arc_op]); end // Error else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogExtract, [FWcxArchiveFileSource.ArchiveFileName + PathDelim + Header.FileName +' -> ' + TargetFileName]), [log_arc_op], lmtSuccess); end; // Success with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; end // Extract else // Skip begin iResult := WcxModule.WcxProcessFile(ArcHandle, PK_SKIP, EmptyStr, EmptyStr); //Check for errors if iResult <> E_SUCCESS then begin ShowError(Format(rsMsgLogError + rsMsgLogExtract, [FWcxArchiveFileSource.ArchiveFileName + PathDelim + Header.FileName + ' -> ' + TargetFileName + ' : ' + GetErrorMsg(iResult)]), iResult, [log_arc_op]); end; end; // Skip finally FreeAndNil(Header); end; finally // Close archive, ignore function result, see: // https://www.ghisler.ch/board/viewtopic.php?p=299809#p299809 iResult := WcxModule.CloseArchive(ArcHandle); // Execute after CloseArchive if (ExceptObject = nil) and (FExtractWithoutPath = False) then begin SetDirsAttributes(CreatedPaths); end; // Free memory FreeAndNil(Files); FreeAndNil(MaskList); FreeAndNil(CreatedPaths); end; end; procedure TWcxArchiveCopyOutOperation.Finalize; begin ClearCurrentOperation; end; procedure TWcxArchiveCopyOutOperation.CreateDirsAndCountFiles( const theFiles: TFiles; MaskList: TMaskList; sDestPath: String; CurrentArchiveDir: String; var CreatedPaths: TStringHashListUtf8); var // List of paths that we know must be created. PathsToCreate: TStringHashListUtf8; // List of possible directories to create with their attributes. // This hash list is created to speed up searches for attributes in archive file list. DirsAttributes: TStringHashListUtf8; i: Integer; CurrentFileName: String; Header: TWCXHeader; Directories: TStringList = nil; PathIndex: Integer; ListIndex: Integer; TargetDir: String; FileList: TObjectList; begin { First, collect all the paths that need to be created and their attributes. } PathsToCreate := TStringHashListUtf8.Create(True); DirsAttributes := TStringHashListUtf8.Create(True); FileList := FWcxArchiveFileSource.ArchiveFileList.LockList; try for i := 0 to FileList.Count - 1 do begin Header := TWCXHeader(FileList.Items[i]); // Check if the file from the archive fits the selection given via SourceFiles. if not MatchesFileList(theFiles, Header.FileName) then Continue; if FPS_ISDIR(Header.FileAttr) then begin CurrentFileName := ExtractDirLevel(CurrentArchiveDir, Header.FileName); CurrentFileName := ReplaceInvalidChars(CurrentFileName); // Save this directory and a pointer to its entry. DirsAttributes.Add(CurrentFileName, Header); // If extracting all files and directories, add this directory // to PathsToCreate so that empty directories are also created. if (MaskList = nil) then begin // Paths in PathsToCreate list must end with path delimiter. CurrentFileName := IncludeTrailingPathDelimiter(CurrentFileName); if PathsToCreate.Find(CurrentFileName) < 0 then PathsToCreate.Add(CurrentFileName); end; end else begin if ((MaskList = nil) or MaskList.Matches(ExtractFileNameEx(Header.FileName))) then begin if (Header.UnpSize > 0) then begin Inc(FStatistics.TotalBytes, Header.UnpSize); end; Inc(FStatistics.TotalFiles, 1); CurrentFileName := ExtractDirLevel(CurrentArchiveDir, ExtractFilePathEx(Header.FileName)); CurrentFileName := ReplaceInvalidChars(CurrentFileName); // If CurrentFileName is empty now then it was a file in current archive // directory, therefore we don't have to create any paths for it. if Length(CurrentFileName) > 0 then if PathsToCreate.Find(CurrentFileName) < 0 then PathsToCreate.Add(CurrentFileName); end; end; end; finally FWcxArchiveFileSource.ArchiveFileList.UnlockList; end; if FExtractWithoutPath then Exit; { Second, create paths and save which paths were created and their attributes. } Directories := TStringList.Create; try sDestPath := IncludeTrailingPathDelimiter(sDestPath); // Create path to destination directory (we don't have attributes for that). mbForceDirectory(sDestPath); CreatedPaths.Clear; for PathIndex := 0 to PathsToCreate.Count - 1 do begin Directories.Clear; // Create also all parent directories of the path to create. // This adds directories to list in order from the outer to inner ones, // for example: dir, dir/dir2, dir/dir2/dir3. if GetDirs(PathsToCreate.List[PathIndex]^.Key, Directories) <> -1 then try for i := 0 to Directories.Count - 1 do begin TargetDir := sDestPath + Directories.Strings[i]; if (CreatedPaths.Find(TargetDir) = -1) and (not DirPathExists(TargetDir)) then begin if mbForceDirectory(TargetDir) = False then begin // Error, cannot create directory. Break; // Don't try to create subdirectories. end else begin // Retrieve attributes for this directory, if they are stored. ListIndex := DirsAttributes.Find(Directories.Strings[i]); if ListIndex <> -1 then Header := TWcxHeader(DirsAttributes.List[ListIndex]^.Data) else Header := nil; CreatedPaths.Add(TargetDir, Header); end; end; end; except end; end; finally FreeAndNil(PathsToCreate); FreeAndNil(DirsAttributes); FreeAndNil(Directories); end; end; function TWcxArchiveCopyOutOperation.SetDirsAttributes(const Paths: TStringHashListUtf8): Boolean; var PathIndex: Integer; TargetDir: String; Header: TWCXHeader; Time: TFileTimeEx; begin Result := True; for PathIndex := 0 to Paths.Count - 1 do begin // Get attributes. Header := TWCXHeader(Paths.List[PathIndex]^.Data); if Assigned(Header) then begin TargetDir := Paths.List[PathIndex]^.Key; try // Restore attributes mbFileSetAttr(TargetDir, Header.FileAttr); Time := DateTimeToFileTimeEx(Header.DateTime); // Set creation, modification time mbFileSetTimeEx(TargetDir, Time, Time, Time); except Result := False; end; end; end; end; procedure TWcxArchiveCopyOutOperation.QuestionActionHandler( Action: TFileSourceOperationUIAction); var aFile: TFile; begin if Action = fsouaCompare then begin aFile := TFile.Create(''); try aFile.FullPath := IncludeFrontPathDelimiter(FCurrentFilePath); ShowCompareFilesUI(aFile, FCurrentTargetFilePath); finally aFile.Free; end; end; end; function TWcxArchiveCopyOutOperation.DoFileExists(Header: TWcxHeader; var AbsoluteTargetFileName: String): TFileSourceOperationOptionFileExists; const Responses: array[0..10] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourOverwriteLarger, fsourOverwriteAll, fsourSkipAll, fsourOverwriteSmaller, fsourOverwriteOlder, fsourCancel, fsouaCompare, fsourRenameSource, fsourAutoRenameSource); ResponsesNoCompare: array[0..9] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourOverwriteLarger, fsourOverwriteAll, fsourSkipAll, fsourOverwriteSmaller, fsourOverwriteOlder, fsourCancel, fsourRenameSource, fsourAutoRenameSource); ResponsesNoSize: array[0..8] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourRenameSource, fsourOverwriteAll, fsourSkipAll, fsourAutoRenameSource, fsourOverwriteOlder, fsourCancel, fsouaCompare); ResponsesNoSizeNoCompare: array[0..7] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourRenameSource, fsourOverwriteAll, fsourSkipAll, fsourAutoRenameSource, fsourOverwriteOlder, fsourCancel); var PossibleResponses: TFileSourceOperationUIResponses; Answer: Boolean; Message: String; function OverwriteOlder: TFileSourceOperationOptionFileExists; begin if CompareDateTime(Header.DateTime, FileTimeToDateTimeEx(mbFileGetTime(AbsoluteTargetFileName))) = GreaterThanValue then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteSmaller: TFileSourceOperationOptionFileExists; begin if Header.UnpSize > mbFileSize(AbsoluteTargetFileName) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; function OverwriteLarger: TFileSourceOperationOptionFileExists; begin if Header.UnpSize < mbFileSize(AbsoluteTargetFileName) then Result := fsoofeOverwrite else Result := fsoofeSkip; end; begin if not mbFileExists(AbsoluteTargetFileName) then Result:= fsoofeOverwrite else case FFileExistsOption of fsoofeNone: repeat Answer := True; // Can't asynchoronously extract file for comparison when multiple operations are not supported // TODO: implement synchronous CopyOut to temp directory or close the connection until the question is answered case FNeedsConnection of True : begin if (Header.UnpSize < 0) then PossibleResponses := ResponsesNoSizeNoCompare else begin PossibleResponses := ResponsesNoCompare; end; end; False: begin if (Header.UnpSize < 0) then PossibleResponses := ResponsesNoSize else begin PossibleResponses := Responses; end; end; end; Message:= FileExistsMessage(AbsoluteTargetFileName, Header.FileName, Header.UnpSize, Header.DateTime); FCurrentFilePath := Header.FileName; FCurrentTargetFilePath := AbsoluteTargetFileName; case AskQuestion(Message, '', PossibleResponses, fsourOverwrite, fsourSkip, @QuestionActionHandler) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourOverwriteOlder: begin FFileExistsOption := fsoofeOverwriteOlder; Result:= OverwriteOlder; end; fsourOverwriteSmaller: begin FFileExistsOption := fsoofeOverwriteSmaller; Result:= OverwriteSmaller; end; fsourOverwriteLarger: begin FFileExistsOption := fsoofeOverwriteLarger; Result:= OverwriteLarger; end; fsourAutoRenameSource: begin Result:= fsoofeOverwrite; FFileExistsOption:= fsoofeAutoRenameSource; AbsoluteTargetFileName:= GetNextCopyName(AbsoluteTargetFileName, FPS_ISDIR(Header.FileAttr)); end; fsourRenameSource: begin Message:= ExtractFileNameEx(AbsoluteTargetFileName); Answer:= ShowInputQuery(Thread, Application.Title, rsEditNewFileName, Message); if Answer then begin Result:= fsoofeOverwrite; AbsoluteTargetFileName:= ExtractFilePathEx(AbsoluteTargetFileName) + Message; end; end; fsourNone, fsourCancel: RaiseAbortOperation; end; until Answer; fsoofeOverwriteOlder: begin Result:= OverwriteOlder; end; fsoofeOverwriteSmaller: begin Result:= OverwriteSmaller; end; fsoofeOverwriteLarger: begin Result:= OverwriteLarger; end; fsoofeAutoRenameSource: begin Result:= fsoofeOverwrite; AbsoluteTargetFileName:= GetNextCopyName(AbsoluteTargetFileName, FPS_ISDIR(Header.FileAttr)); end; else begin Result := FFileExistsOption; end; end; end; procedure TWcxArchiveCopyOutOperation.ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions); begin LogMessage(sMessage, logOptions, lmtError); if (gSkipFileOpError = False) and (iError > E_SUCCESS) then begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; end; procedure TWcxArchiveCopyOutOperation.LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TWcxArchiveCopyOutOperation.SetProcessDataProc(hArcData: TArcHandle); begin with FWcxArchiveFileSource.WcxModule do begin if FNeedsConnection then WcxSetProcessDataProc(hArcData, @ProcessDataProcAG, @ProcessDataProcWG) else WcxSetProcessDataProc(hArcData, @ProcessDataProcAT, @ProcessDataProcWT); end; end; class procedure TWcxArchiveCopyOutOperation.ClearCurrentOperation; begin WcxCopyOutOperationG := nil; end; class function TWcxArchiveCopyOutOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result:= TWcxArchiveCopyOperationOptionsUI; end; end. �������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivedeleteoperation.pas��������������������������0000644�0001750�0000144�00000017356�14743153644�026240� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveDeleteOperation; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, uFileSourceDeleteOperation, uFileSource, uFileSourceOperation, uFileSourceOperationUI, uFile, uWcxArchiveFileSource, uGlobs, uLog; type { TWcxArchiveDeleteOperation } TWcxArchiveDeleteOperation = class(TFileSourceDeleteOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; FStatistics: TFileSourceDeleteOperationStatistics; // local copy of statistics procedure CountFiles(const theFiles: TFiles; FileMask: String); {en Convert TFiles into a string separated with #0 (format used by WCX). } function GetFileList(const theFiles: TFiles): String; protected procedure ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions); procedure LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class procedure ClearCurrentOperation; end; implementation uses DCOSUtils, DCStrUtils, uDCUtils, uLng, uShowMsg, uWCXmodule, WcxPlugin, uMasks, FileUtil, LazUTF8, DCConvertEncoding; // ---------------------------------------------------------------------------- // WCX callbacks var // WCX interface cannot discern different operations (for reporting progress), // so this global variable is used to store currently running operation. // (There may be other running concurrently, but only one may report progress.) WcxDeleteOperation: TWcxArchiveDeleteOperation = nil; function ProcessDataProc(FileName: String; Size: LongInt): LongInt; begin //DCDebug('Working ' + FileName + ' Size = ' + IntToStr(Size)); Result := 1; if Assigned(WcxDeleteOperation) then begin if WcxDeleteOperation.State = fsosStopping then // Cancel operation Exit(0); with WcxDeleteOperation.FStatistics do begin CurrentFile := FileName; // Get the number of bytes processed since the previous call if Size > 0 then begin if TotalBytes > 0 then begin TotalFiles := 100; DoneBytes := DoneBytes + Size; DoneFiles := DoneBytes * 100 div TotalBytes; end; end // Get progress percent value to directly set progress bar else if Size < 0 then begin // Total operation percent if (Size >= -100) and (Size <= -1) then begin TotalFiles := 100; DoneFiles := -Size; end; end; WcxDeleteOperation.UpdateStatistics(WcxDeleteOperation.FStatistics); if not WcxDeleteOperation.CheckOperationStateSafe then Exit(0); end; end; end; function ProcessDataProcA(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(CeSysToUtf8(StrPas(FileName)), Size); end; function ProcessDataProcW(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(UTF16ToUTF8(UnicodeString(FileName)), Size); end; // ---------------------------------------------------------------------------- constructor TWcxArchiveDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FWcxArchiveFileSource := aTargetFileSource as IWcxArchiveFileSource; inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TWcxArchiveDeleteOperation.Destroy; begin inherited Destroy; end; procedure TWcxArchiveDeleteOperation.Initialize; begin if Assigned(WcxDeleteOperation) and (WcxDeleteOperation <> Self) then raise Exception.Create('Another WCX delete operation is already running'); WcxDeleteOperation := Self; // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; CountFiles(FilesToDelete, '*.*'); end; procedure TWcxArchiveDeleteOperation.MainExecute; var iResult: Integer; WcxModule: TWcxModule; begin WcxModule := FWcxArchiveFileSource.WcxModule; WcxModule.WcxSetChangeVolProc(wcxInvalidHandle); WcxModule.WcxSetProcessDataProc(wcxInvalidHandle, @ProcessDataProcA, @ProcessDataProcW); iResult := WcxModule.WcxDeleteFiles(FWcxArchiveFileSource.ArchiveFileName, GetFileList(FilesToDelete)); // Check for errors. if iResult <> E_SUCCESS then begin // User aborted operation. if iResult = E_EABORTED then Exit; ShowError(Format(rsMsgLogError + rsMsgLogDelete, [FWcxArchiveFileSource.ArchiveFileName + ' - ' + GetErrorMsg(iResult)]), iResult, [log_arc_op]); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogDelete, [FWcxArchiveFileSource.ArchiveFileName]), [log_arc_op], lmtSuccess); end; end; procedure TWcxArchiveDeleteOperation.Finalize; begin ClearCurrentOperation; end; procedure TWcxArchiveDeleteOperation.ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions); begin LogMessage(sMessage, logOptions, lmtError); if (gSkipFileOpError = False) and (iError > E_SUCCESS) then begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; end; procedure TWcxArchiveDeleteOperation.LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TWcxArchiveDeleteOperation.CountFiles(const theFiles: TFiles; FileMask: String); var i: Integer; Header: TWCXHeader; ArcFileList: TList; begin ArcFileList := FWcxArchiveFileSource.ArchiveFileList.LockList; try for i := 0 to ArcFileList.Count - 1 do begin Header := TWCXHeader(ArcFileList.Items[I]); // Check if the file from the archive fits the selection given via theFiles. if (not FPS_ISDIR(Header.FileAttr)) // Omit directories and MatchesFileList(theFiles, Header.FileName) // Check if it's included in the filelist and ((FileMask = '*.*') or (FileMask = '*') // And name matches file mask or MatchesMaskList(ExtractFileName(Header.FileName), FileMask)) then begin Inc(FStatistics.TotalBytes, Header.UnpSize); Inc(FStatistics.TotalFiles, 1); end; end; finally FWcxArchiveFileSource.ArchiveFileList.UnlockList; end; UpdateStatistics(FStatistics); end; function TWcxArchiveDeleteOperation.GetFileList(const theFiles: TFiles): String; var I : Integer; FileName : String; begin Result := ''; for I := 0 to theFiles.Count - 1 do begin // Filenames must be relative to archive root and shouldn't start with path delimiter. FileName := ExcludeFrontPathDelimiter(theFiles[I].FullPath); //ExtractDirLevel(FWcxArchiveFileSource.GetRootString, theFiles[I].FullPath) // Special treatment of directories. if theFiles[i].IsDirectory then // TC ends paths to directories to be deleted with '\*.*' // (which means delete this directory and all files in it). FileName := IncludeTrailingPathDelimiter(FileName) + '*.*'; Result := Result + FileName + #0; end; Result := Result + #0; end; class procedure TWcxArchiveDeleteOperation.ClearCurrentOperation; begin WcxDeleteOperation := nil; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchiveexecuteoperation.pas�������������������������0000644�0001750�0000144�00000003625�14743153644�026432� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uFileSourceExecuteOperation, uWcxArchiveFileSource; type { TWcxArchiveExecuteOperation } TWcxArchiveExecuteOperation = class(TFileSourceExecuteOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; protected procedure DoReloadFileSources; override; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses fPackInfoDlg, uMasks, uGlobs; procedure TWcxArchiveExecuteOperation.DoReloadFileSources; begin // Empty end; constructor TWcxArchiveExecuteOperation.Create( aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FWcxArchiveFileSource := aTargetFileSource as IWcxArchiveFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TWcxArchiveExecuteOperation.Initialize; begin end; procedure TWcxArchiveExecuteOperation.MainExecute; begin if (Verb <> 'properties') and MatchesMaskList(ExecutableFile.Name, gAutoExtractOpenMask) then FExecuteOperationResult:= fseorYourSelf else begin FExecuteOperationResult:= ShowPackInfoDlg(FWcxArchiveFileSource, ExecutableFile); end; end; procedure TWcxArchiveExecuteOperation.Finalize; begin end; end. �����������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivefilesource.pas�������������������������������0000644�0001750�0000144�00000076636�14743153644�025223� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveFileSource; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, contnrs, syncobjs, DCStringHashListUtf8, WcxPlugin, uWCXmodule, uFile, uFileSourceProperty, uFileSourceOperationTypes, uArchiveFileSource, uFileProperty, uFileSource, uFileSourceOperation, uClassesEx; type TWcxArchiveFileSourceConnection = class; { IWcxArchiveFileSource } IWcxArchiveFileSource = interface(IArchiveFileSource) ['{DB32E8A8-486B-4053-9448-4C145C1A33FA}'] function GetArcFileList: TThreadObjectList; function GetPluginCapabilities: PtrInt; function GetWcxModule: TWcxModule; property ArchiveFileList: TThreadObjectList read GetArcFileList; property PluginCapabilities: PtrInt read GetPluginCapabilities; property WcxModule: TWCXModule read GetWcxModule; end; { TWcxArchiveFileSource } TWcxArchiveFileSource = class(TArchiveFileSource, IWcxArchiveFileSource) private FModuleFileName: String; FPluginCapabilities: PtrInt; FArcFileList : TThreadObjectList; FWcxModule: TWCXModule; FOpenResult: LongInt; procedure SetCryptCallback; function ReadArchive(anArchiveHandle: TArcHandle = 0): Boolean; function GetArcFileList: TThreadObjectList; function GetPluginCapabilities: PtrInt; function GetWcxModule: TWcxModule; function CreateConnection: TFileSourceConnection; procedure CreateConnections; procedure AddToConnectionQueue(Operation: TFileSourceOperation); procedure RemoveFromConnectionQueue(Operation: TFileSourceOperation); procedure AddConnection(Connection: TFileSourceConnection); procedure RemoveConnection(Connection: TFileSourceConnection); {en Searches connections list for a connection assigned to operation. } function FindConnectionByOperation(operation: TFileSourceOperation): TFileSourceConnection; virtual; procedure NotifyNextWaitingOperation(allowedOps: TFileSourceOperationTypes); procedure ClearCurrentOperation(Operation: TFileSourceOperation); protected function GetPacker: String; override; procedure OperationFinished(Operation: TFileSourceOperation); override; function GetSupportedFileProperties: TFilePropertiesTypes; override; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; procedure DoReload(const {%H-}PathsToReload: TPathsArray); override; public constructor Create(anArchiveFileSource: IFileSource; anArchiveFileName: String; aWcxPluginFileName: String; aWcxPluginCapabilities: PtrInt); reintroduce; constructor Create(anArchiveFileSource: IFileSource; anArchiveFileName: String; aWcxPluginModule: TWcxModule; aWcxPluginCapabilities: PtrInt; anArchiveHandle: TArcHandle); reintroduce; destructor Destroy; override; class function CreateFile(const APath: String; WcxHeader: TWCXHeader): TFile; overload; // Retrieve operations permitted on the source. = capabilities? function GetOperationsTypes: TFileSourceOperationTypes; override; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; override; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; class function CreateByArchiveSign(anArchiveFileSource: IFileSource; anArchiveFileName: String): IWcxArchiveFileSource; class function CreateByArchiveType(anArchiveFileSource: IFileSource; anArchiveFileName: String; anArchiveType: String; bIncludeHidden: Boolean = False): IWcxArchiveFileSource; class function CreateByArchiveName(anArchiveFileSource: IFileSource; anArchiveFileName: String; bIncludeHidden: Boolean = False): IWcxArchiveFileSource; {en Returns @true if there is a plugin registered for the archive name. } class function CheckPluginByName(const anArchiveFileName: String): Boolean; function GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; override; procedure RemoveOperationFromQueue(Operation: TFileSourceOperation); override; property ArchiveFileList: TThreadObjectList read FArcFileList; property PluginCapabilities: PtrInt read FPluginCapabilities; property WcxModule: TWCXModule read FWcxModule; end; { TWcxArchiveFileSourceConnection } TWcxArchiveFileSourceConnection = class(TFileSourceConnection) private FWcxModule: TWCXModule; public constructor Create(aWcxModule: TWCXModule); reintroduce; property WcxModule: TWCXModule read FWcxModule; end; EModuleNotLoadedException = class(EFileSourceException); implementation uses LazUTF8, uDebug, DCStrUtils, uGlobs, DCOSUtils, DCDateTimeUtils, uMasks, DCConvertEncoding, DCFileAttributes, FileUtil, uCryptProc, uWcxArchiveListOperation, uWcxArchiveCopyInOperation, uWcxArchiveCopyOutOperation, uWcxArchiveDeleteOperation, uWcxArchiveExecuteOperation, uWcxArchiveTestArchiveOperation, uWcxArchiveCalcStatisticsOperation; const connCopyIn = 0; connCopyOut = 1; connDelete = 2; connTestArchive = 3; var // Always use appropriate lock to access these lists. WcxConnections: TObjectList; // store connections created by Wcx file sources WcxOperationsQueue: TObjectList; // store queued operations, use only under FOperationsQueueLock WcxConnectionsLock: TCriticalSection; // used to synchronize access to connections WcxOperationsQueueLock: TCriticalSection; // used to synchronize access to operations queue function CryptProc({%H-}CryptoNumber: Integer; Mode: Integer; ArchiveName: String; var Password: String): Integer; const cPrefix = 'wcx'; cResult: array[TCryptStoreResult] of Integer = (E_SUCCESS, E_ECREATE, E_EWRITE, E_EREAD, E_NO_FILES); var sGroup, sPassword: AnsiString; MyResult: TCryptStoreResult; begin MyResult:= csrSuccess; sGroup:= ExtractOnlyFileExt(ArchiveName); case Mode of PK_CRYPT_SAVE_PASSWORD: begin MyResult:= PasswordStore.WritePassword(cPrefix, sGroup, ArchiveName, Password); end; PK_CRYPT_LOAD_PASSWORD, PK_CRYPT_LOAD_PASSWORD_NO_UI: begin if (Mode = PK_CRYPT_LOAD_PASSWORD_NO_UI) and (PasswordStore.HasMasterKey = False) then Exit(E_NO_FILES); MyResult:= PasswordStore.ReadPassword(cPrefix, sGroup, ArchiveName, Password); end; PK_CRYPT_COPY_PASSWORD, PK_CRYPT_MOVE_PASSWORD: begin MyResult:= PasswordStore.ReadPassword(cPrefix, sGroup, ArchiveName, sPassword); if MyResult = csrSuccess then begin MyResult:= PasswordStore.WritePassword(cPrefix, sGroup, Password, sPassword); if (MyResult = csrSuccess) and (Mode = PK_CRYPT_MOVE_PASSWORD) then begin if not PasswordStore.DeletePassword(cPrefix, sGroup, ArchiveName) then MyResult:= csrWriteError; end; end; end; PK_CRYPT_DELETE_PASSWORD: begin if not PasswordStore.DeletePassword(cPrefix, sGroup, ArchiveName) then MyResult:= csrWriteError; end; end; Result:= cResult[MyResult]; end; function CryptProcA(CryptoNumber: Integer; Mode: Integer; ArchiveName, Password: PAnsiChar; MaxLen: Integer): Integer; dcpcall; var sArchiveName, sPassword: String; begin sArchiveName:= CeSysToUtf8(StrPas(ArchiveName)); sPassword:= CeSysToUtf8(StrPas(Password)); Result:= CryptProc(CryptoNumber, Mode, sArchiveName, sPassword); if Result = E_SUCCESS then begin if Password <> nil then StrPLCopy(Password, CeUtf8ToSys(sPassword), MaxLen); end; end; function CryptProcW(CryptoNumber: Integer; Mode: Integer; ArchiveName, Password: PWideChar; MaxLen: Integer): Integer; dcpcall; var sArchiveName, sPassword: String; begin sArchiveName:= UTF16ToUTF8(UnicodeString(ArchiveName)); sPassword:= UTF16ToUTF8(UnicodeString(Password)); Result:= CryptProc(CryptoNumber, Mode, sArchiveName, sPassword); if Result = E_SUCCESS then begin if Password <> nil then StrPLCopyW(Password, CeUtf8ToUtf16(sPassword), MaxLen); end; end; function ProcessDataProcAG(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= 1; end; function ProcessDataProcWG(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= 1; end; //-------------------------------------------------------------------------------------------------- class function TWcxArchiveFileSource.CreateByArchiveSign( anArchiveFileSource: IFileSource; anArchiveFileName: String): IWcxArchiveFileSource; var I: Integer; ModuleFileName: String; bFound: Boolean = False; lOpenResult: LongInt; anArchiveHandle: TArcHandle = 0; WcxPlugin, WcxPrevious: TWcxModule; begin Result := nil; WcxPrevious := nil; // Check if there is a registered plugin for the archive file by content. for I := 0 to gWCXPlugins.Count - 1 do begin if (gWCXPlugins.Enabled[I]) then begin ModuleFileName := gWCXPlugins.FileName[I]; WcxPlugin := gWCXPlugins.LoadModule(ModuleFileName); if Assigned(WcxPlugin) then begin if ((gWCXPlugins.Flags[I] and PK_CAPS_BY_CONTENT) = PK_CAPS_BY_CONTENT) then begin if (WcxPlugin <> WcxPrevious) then begin WcxPrevious:= WcxPlugin; if WcxPlugin.WcxCanYouHandleThisFile(anArchiveFileName) then begin anArchiveHandle:= WcxPlugin.OpenArchiveHandle(anArchiveFileName, PK_OM_LIST, lOpenResult); if (anArchiveHandle <> 0) and (lOpenResult = E_SUCCESS) then begin bFound:= True; Break; end; end; end; end else if ((gWCXPlugins.Flags[I] and PK_CAPS_HIDE) = PK_CAPS_HIDE) then begin bFound:= MatchesMask(anArchiveFileName, AllFilesMask + ExtensionSeparator + gWCXPlugins.Ext[I]); if bFound then Break; end; end; end; end; if bFound then begin Result := TWcxArchiveFileSource.Create(anArchiveFileSource, anArchiveFileName, WcxPlugin, gWCXPlugins.Flags[I], anArchiveHandle); DCDebug('Found registered plugin ' + ModuleFileName + ' for archive ' + anArchiveFileName); end; end; class function TWcxArchiveFileSource.CreateByArchiveType( anArchiveFileSource: IFileSource; anArchiveFileName: String; anArchiveType: String; bIncludeHidden: Boolean): IWcxArchiveFileSource; var i: Integer; ModuleFileName: String; begin Result := nil; // Check if there is a registered plugin for the extension of the archive file name. for i := 0 to gWCXPlugins.Count - 1 do begin if (gWCXPlugins.Enabled[i]) and SameText(anArchiveType, gWCXPlugins.Ext[i]) and ((bIncludeHidden) or ((gWCXPlugins.Flags[I] and PK_CAPS_HIDE) <> PK_CAPS_HIDE)) then begin ModuleFileName := gWCXPlugins.FileName[I]; Result := TWcxArchiveFileSource.Create(anArchiveFileSource, anArchiveFileName, ModuleFileName, gWCXPlugins.Flags[I]); DCDebug('Found registered plugin ' + ModuleFileName + ' for archive ' + anArchiveFileName); break; end; end; end; class function TWcxArchiveFileSource.CreateByArchiveName( anArchiveFileSource: IFileSource; anArchiveFileName: String; bIncludeHidden: Boolean): IWcxArchiveFileSource; var i: Integer; aMask: String; ModuleFileName: String; begin Result := nil; // Check if there is a registered plugin for the archive file name. for i := 0 to gWCXPlugins.Count - 1 do begin aMask:= AllFilesMask + ExtensionSeparator + gWCXPlugins.Ext[i]; if (gWCXPlugins.Enabled[i]) and MatchesMask(anArchiveFileName, aMask) and ((bIncludeHidden) or ((gWCXPlugins.Flags[I] and PK_CAPS_HIDE) <> PK_CAPS_HIDE)) then begin ModuleFileName := gWCXPlugins.FileName[I]; Result := TWcxArchiveFileSource.Create(anArchiveFileSource, anArchiveFileName, ModuleFileName, gWCXPlugins.Flags[I]); DCDebug('Found registered plugin ' + ModuleFileName + ' for archive ' + anArchiveFileName); break; end; end; end; class function TWcxArchiveFileSource.CheckPluginByName(const anArchiveFileName: String): Boolean; var i: Integer; aMask: String; begin for i := 0 to gWCXPlugins.Count - 1 do begin aMask:= AllFilesMask + ExtensionSeparator + gWCXPlugins.Ext[i]; if (gWCXPlugins.Enabled[i]) and MatchesMask(anArchiveFileName, aMask) then Exit(True); end; Result := False; end; // ---------------------------------------------------------------------------- constructor TWcxArchiveFileSource.Create(anArchiveFileSource: IFileSource; anArchiveFileName: String; aWcxPluginFileName: String; aWcxPluginCapabilities: PtrInt); begin inherited Create(anArchiveFileSource, anArchiveFileName); FModuleFileName := aWcxPluginFileName; FPluginCapabilities := aWcxPluginCapabilities; FArcFileList := TThreadObjectList.Create; FWcxModule := gWCXPlugins.LoadModule(FModuleFileName); if not Assigned(FWcxModule) then raise EModuleNotLoadedException.Create('Cannot load WCX module ' + FModuleFileName); FOperationsClasses[fsoCopyIn] := TWcxArchiveCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TWcxArchiveCopyOutOperation.GetOperationClass; SetCryptCallback; if mbFileExists(anArchiveFileName) then begin if not ReadArchive then raise EWcxModuleException.Create(FOpenResult); end; CreateConnections; end; constructor TWcxArchiveFileSource.Create(anArchiveFileSource: IFileSource; anArchiveFileName: String; aWcxPluginModule: TWcxModule; aWcxPluginCapabilities: PtrInt; anArchiveHandle: TArcHandle); begin inherited Create(anArchiveFileSource, anArchiveFileName); FPluginCapabilities := aWcxPluginCapabilities; FArcFileList := TThreadObjectList.Create; FWcxModule := aWcxPluginModule; FOperationsClasses[fsoCopyIn] := TWcxArchiveCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TWcxArchiveCopyOutOperation.GetOperationClass; SetCryptCallback; if mbFileExists(anArchiveFileName) then begin if not ReadArchive(anArchiveHandle) then raise EWcxModuleException.Create(FOpenResult); end; CreateConnections; end; destructor TWcxArchiveFileSource.Destroy; begin inherited Destroy; if Assigned(FArcFileList) then FreeAndNil(FArcFileList); end; class function TWcxArchiveFileSource.CreateFile(const APath: String; WcxHeader: TWCXHeader): TFile; begin Result := TFile.Create(APath); with Result do begin { FileCRC, CompressionMethod, Comment, } AttributesProperty := {TNtfsFileAttributesProperty or Unix?} TFileAttributesProperty.CreateOSAttributes(WcxHeader.FileAttr); if AttributesProperty.IsDirectory then begin SizeProperty := TFileSizeProperty.Create(0); CompressedSizeProperty := TFileCompressedSizeProperty.Create(0); end else begin SizeProperty := TFileSizeProperty.Create(WcxHeader.UnpSize); SizeProperty.IsValid := (WcxHeader.UnpSize >= 0); CompressedSizeProperty := TFileCompressedSizeProperty.Create(WcxHeader.PackSize); CompressedSizeProperty.IsValid := (WcxHeader.PackSize >= 0); end; ModificationTimeProperty := TFileModificationDateTimeProperty.Create(WcxHeader.DateTime); ModificationTimeProperty.IsValid := (WcxHeader.DateTime <= SysUtils.MaxDateTime); // Set name after assigning Attributes property, because it is used to get extension. Name := ExtractFileNameEx(WcxHeader.FileName); end; end; function TWcxArchiveFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin Result := [fsoList, fsoCopyOut, fsoTestArchive, fsoExecute, fsoCalcStatistics]; // by default with FWcxModule do begin if (((FPluginCapabilities and PK_CAPS_NEW) <> 0) or ((FPluginCapabilities and PK_CAPS_MODIFY) <> 0)) and (Assigned(PackFiles) or Assigned(PackFilesW)) then Result:= Result + [fsoCopyIn]; if ((FPluginCapabilities and PK_CAPS_DELETE) <> 0) and (Assigned(DeleteFiles) or Assigned(DeleteFilesW)) then Result:= Result + [fsoDelete]; end; end; function TWcxArchiveFileSource.GetProperties: TFileSourceProperties; begin Result := [fspUsesConnections, fspListFlatView]; end; function TWcxArchiveFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties; end; function TWcxArchiveFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; var I: Integer; AFileList: TList; Header: TWCXHeader; begin Result := False; if Length(NewDir) > 0 then begin if NewDir = GetRootDir() then Exit(True); NewDir := IncludeTrailingPathDelimiter(NewDir); AFileList:= FArcFileList.LockList; try // Search file list for a directory with name NewDir. for I := 0 to AFileList.Count - 1 do begin Header := TWCXHeader(AFileList.Items[I]); if FPS_ISDIR(Header.FileAttr) and (Length(Header.FileName) > 0) then begin if mbCompareFileNames(NewDir, IncludeTrailingPathDelimiter(GetRootDir() + Header.FileName)) then Exit(True); end; end; finally FArcFileList.UnlockList; end; end; end; function TWcxArchiveFileSource.GetPacker: String; begin Result:= FWcxModule.ModuleName; end; procedure TWcxArchiveFileSource.SetCryptCallback; var AFlags: Integer; begin if not PasswordStore.MasterKeySet then AFlags:= 0 else begin AFlags:= PK_CRYPTOPT_MASTERPASS_SET; end; FWcxModule.WcxSetCryptCallback(0, AFlags, @CryptProcA, @CryptProcW); end; function TWcxArchiveFileSource.GetArcFileList: TThreadObjectList; begin Result := FArcFileList; end; function TWcxArchiveFileSource.GetPluginCapabilities: PtrInt; begin Result := FPluginCapabilities; end; function TWcxArchiveFileSource.GetWcxModule: TWcxModule; begin Result := FWcxModule; end; function TWcxArchiveFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWcxArchiveListOperation.Create(TargetFileSource, TargetPath); end; function TWcxArchiveFileSource.CreateCopyInOperation( SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWcxArchiveCopyInOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TWcxArchiveFileSource.CreateCopyOutOperation( TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TWcxArchiveCopyOutOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TWcxArchiveFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWcxArchiveDeleteOperation.Create(TargetFileSource, FilesToDelete); end; function TWcxArchiveFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TWcxArchiveExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; function TWcxArchiveFileSource.CreateTestArchiveOperation(var theSourceFiles: TFiles): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result:= TWcxArchiveTestArchiveOperation.Create(SourceFileSource, theSourceFiles); end; function TWcxArchiveFileSource.CreateCalcStatisticsOperation( var theFiles: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWcxArchiveCalcStatisticsOperation.Create(TargetFileSource, theFiles); end; function TWcxArchiveFileSource.ReadArchive(anArchiveHandle: TArcHandle): Boolean; procedure CollectDirs(Path: PAnsiChar; var DirsList: TStringHashListUtf8); var I : Integer; Dir : AnsiString; begin // Scan from the second char from the end, to the second char from the beginning. for I := strlen(Path) - 2 downto 1 do begin if Path[I] = PathDelim then begin SetString(Dir, Path, I); if DirsList.Find(Dir) = -1 then // Add directory and continue scanning for parent directories. DirsList.Add(Dir) else // This directory is already in the list and we assume // that all parent directories are too. Exit; end end; end; var ArcHandle : TArcHandle; Header: TWCXHeader; AFileList: TList; AllDirsList, ExistsDirList : TStringHashListUtf8; I : Integer; NameLength: Integer; ArchiveTime: TDateTime; begin Result:= False; if anArchiveHandle <> 0 then ArcHandle:= anArchiveHandle else begin if not mbFileAccess(ArchiveFileName, fmOpenRead) then begin FOpenResult := E_EREAD; Exit; end; DCDebug('Open Archive'); ArcHandle := WcxModule.OpenArchiveHandle(ArchiveFileName, PK_OM_LIST, FOpenResult); if ArcHandle = 0 then Exit; end; WcxModule.WcxSetChangeVolProc(ArcHandle); WcxModule.WcxSetProcessDataProc(ArcHandle, @ProcessDataProcAG, @ProcessDataProcWG); DCDebug('Get File List'); (*Get File List*) AFileList:= FArcFileList.LockList; try AFileList.Clear; ExistsDirList := TStringHashListUtf8.Create(True); AllDirsList := TStringHashListUtf8.Create(True); try while (WcxModule.ReadWCXHeader(ArcHandle, Header) = E_SUCCESS) do begin // Some plugins end directories with path delimiter. // And not set directory attribute. So delete path // delimiter if present and add directory attribute. NameLength := Length(Header.FileName); if (NameLength > 0) and (Header.FileName[NameLength] = PathDelim) then begin Delete(Header.FileName, NameLength, 1); Header.FileAttr := Header.FileAttr or GENERIC_ATTRIBUTE_FOLDER; end; //********************************************************************** // Workaround for plugins that don't give a list of // folders or the list does not include all of the folders. if FPS_ISDIR(Header.FileAttr) then begin // Collect directories that the plugin supplies. if (ExistsDirList.Find(Header.FileName) < 0) then ExistsDirList.Add(Header.FileName); end; // Collect all directories. CollectDirs(PAnsiChar(Header.FileName), AllDirsList); //********************************************************************** AFileList.Add(Header); // get next file FOpenResult := WcxModule.WcxProcessFile(ArcHandle, PK_SKIP, EmptyStr, EmptyStr); // Check for errors if FOpenResult <> E_SUCCESS then Exit; end; // while ArchiveTime:= FileTimeToDateTimeEx(mbFileGetTime(ArchiveFileName)); (* if plugin does not give a list of folders *) for I := 0 to AllDirsList.Count - 1 do begin // Add only those directories that were not supplied by the plugin. if ExistsDirList.Find(AllDirsList.List[I]^.Key) < 0 then begin Header := TWCXHeader.Create; try Header.FileName := AllDirsList.List[I]^.Key; Header.ArcName := ArchiveFileName; Header.FileAttr := GENERIC_ATTRIBUTE_FOLDER; Header.DateTime := ArchiveTime; AFileList.Add(Header); except FreeAndNil(Header); end; end; end; Result:= True; finally AllDirsList.Free; ExistsDirList.Free; WcxModule.CloseArchive(ArcHandle); end; finally FArcFileList.UnlockList; end; end; procedure TWcxArchiveFileSource.AddToConnectionQueue(Operation: TFileSourceOperation); begin WcxOperationsQueueLock.Acquire; try if WcxOperationsQueue.IndexOf(Operation) < 0 then WcxOperationsQueue.Add(Operation); finally WcxOperationsQueueLock.Release; end; end; procedure TWcxArchiveFileSource.RemoveFromConnectionQueue(Operation: TFileSourceOperation); begin WcxOperationsQueueLock.Acquire; try WcxOperationsQueue.Remove(Operation); finally WcxOperationsQueueLock.Release; end; end; procedure TWcxArchiveFileSource.AddConnection(Connection: TFileSourceConnection); begin WcxConnectionsLock.Acquire; try if WcxConnections.IndexOf(Connection) < 0 then WcxConnections.Add(Connection); finally WcxConnectionsLock.Release; end; end; procedure TWcxArchiveFileSource.RemoveConnection(Connection: TFileSourceConnection); begin WcxConnectionsLock.Acquire; try WcxConnections.Remove(Connection); finally WcxConnectionsLock.Release; end; end; function TWcxArchiveFileSource.GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; begin Result := nil; case Operation.ID of fsoCopyIn: Result := WcxConnections[connCopyIn] as TFileSourceConnection; fsoCopyOut: Result := WcxConnections[connCopyOut] as TFileSourceConnection; fsoDelete: Result := WcxConnections[connDelete] as TFileSourceConnection; fsoTestArchive: Result := WcxConnections[connTestArchive] as TFileSourceConnection; else begin Result := CreateConnection; if Assigned(Result) then AddConnection(Result); end; end; if Assigned(Result) then Result := TryAcquireConnection(Result, Operation); // No available connection - wait. if not Assigned(Result) then AddToConnectionQueue(Operation) else // Connection acquired. // The operation may have been waiting in the queue // for the connection, so remove it from the queue. RemoveFromConnectionQueue(Operation); end; procedure TWcxArchiveFileSource.RemoveOperationFromQueue(Operation: TFileSourceOperation); begin RemoveFromConnectionQueue(Operation); end; function TWcxArchiveFileSource.CreateConnection: TFileSourceConnection; begin Result := TWcxArchiveFileSourceConnection.Create(FWcxModule); end; procedure TWcxArchiveFileSource.CreateConnections; begin WcxConnectionsLock.Acquire; try if WcxConnections.Count = 0 then begin // Reserve some connections (only once). WcxConnections.Add(CreateConnection); // connCopyIn WcxConnections.Add(CreateConnection); // connCopyOut WcxConnections.Add(CreateConnection); // connDelete WcxConnections.Add(CreateConnection); // connTestArchive end; finally WcxConnectionsLock.Release; end; end; function TWcxArchiveFileSource.FindConnectionByOperation(operation: TFileSourceOperation): TFileSourceConnection; var i: Integer; connection: TFileSourceConnection; begin Result := nil; WcxConnectionsLock.Acquire; try for i := 0 to WcxConnections.Count - 1 do begin connection := WcxConnections[i] as TFileSourceConnection; if connection.AssignedOperation = operation then Exit(connection); end; finally WcxConnectionsLock.Release; end; end; procedure TWcxArchiveFileSource.OperationFinished(Operation: TFileSourceOperation); var allowedIDs: TFileSourceOperationTypes = []; connection: TFileSourceConnection; begin ClearCurrentOperation(Operation); connection := FindConnectionByOperation(Operation); if Assigned(connection) then begin connection.Release; // unassign operation WcxConnectionsLock.Acquire; try // If there are operations waiting, take the first one and notify // that a connection is available. // Only check operation types for which there are reserved connections. if Operation.ID in [fsoCopyIn, fsoCopyOut, fsoDelete, fsoTestArchive] then begin Include(allowedIDs, Operation.ID); NotifyNextWaitingOperation(allowedIDs); end else begin WcxConnections.Remove(connection); end; finally WcxConnectionsLock.Release; end; end; end; procedure TWcxArchiveFileSource.NotifyNextWaitingOperation(allowedOps: TFileSourceOperationTypes); var i: Integer; operation: TFileSourceOperation; begin WcxOperationsQueueLock.Acquire; try for i := 0 to WcxOperationsQueue.Count - 1 do begin operation := WcxOperationsQueue.Items[i] as TFileSourceOperation; if (operation.State = fsosWaitingForConnection) and (operation.ID in allowedOps) then begin operation.ConnectionAvailableNotify; Exit; end; end; finally WcxOperationsQueueLock.Release; end; end; procedure TWcxArchiveFileSource.ClearCurrentOperation(Operation: TFileSourceOperation); begin case Operation.ID of fsoCopyIn: TWcxArchiveCopyInOperation.ClearCurrentOperation; fsoCopyOut: TWcxArchiveCopyOutOperation.ClearCurrentOperation; fsoDelete: TWcxArchiveDeleteOperation.ClearCurrentOperation; fsoTestArchive: TWcxArchiveTestArchiveOperation.ClearCurrentOperation; end; end; procedure TWcxArchiveFileSource.DoReload(const PathsToReload: TPathsArray); begin ReadArchive; end; { TWcxArchiveFileSourceConnection } constructor TWcxArchiveFileSourceConnection.Create(aWcxModule: TWCXModule); begin FWcxModule := aWcxModule; inherited Create; end; initialization WcxConnections := TObjectList.Create(True); // True = destroy objects when destroying list WcxConnectionsLock := TCriticalSection.Create; WcxOperationsQueue := TObjectList.Create(False); // False = don't destroy operations (only store references) WcxOperationsQueueLock := TCriticalSection.Create; finalization FreeAndNil(WcxConnections); FreeAndNil(WcxConnectionsLock); FreeAndNil(WcxOperationsQueue); FreeAndNil(WcxOperationsQueueLock); end. ��������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivelistoperation.pas����������������������������0000644�0001750�0000144�00000003557�14743153644�025747� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uWcxArchiveFileSource, uFileSource; type TWcxArchiveListOperation = class(TFileSourceListOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses DCOSUtils, uOSUtils, DCStrUtils, uWCXmodule, uFile; constructor TWcxArchiveListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FWcxArchiveFileSource := aFileSource as IWcxArchiveFileSource; inherited Create(aFileSource, aPath); end; procedure TWcxArchiveListOperation.MainExecute; var I : Integer; aFile: TFile; Header: TWcxHeader; ArcFileList: TList; CurrFileName : String; // Current file name begin FFiles.Clear; if FWcxArchiveFileSource.Changed then begin FWcxArchiveFileSource.Reload(Path); end; if not FileSource.IsPathAtRoot(Path) then begin aFile := TWcxArchiveFileSource.CreateFile(Path); aFile.Name := '..'; aFile.Attributes := faFolder; FFiles.Add(AFile); end; ArcFileList := FWcxArchiveFileSource.ArchiveFileList.Clone; try for I := 0 to ArcFileList.Count - 1 do begin CheckOperationState; Header := TWcxHeader(ArcFileList.Items[I]); CurrFileName := PathDelim + Header.FileName; if not IsInPath(Path, CurrFileName, FFlatView, False) then Continue; if FFlatView = False then aFile := TWcxArchiveFileSource.CreateFile(Path, Header) else begin if FPS_ISDIR(Header.FileAttr) then Continue; aFile := TWcxArchiveFileSource.CreateFile(ExtractFilePath(CurrFileName), Header) end; FFiles.Add(aFile); end; finally ArcFileList.Free; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wcxarchive/uwcxarchivetestarchiveoperation.pas���������������������0000644�0001750�0000144�00000023244�14743153644�027310� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWcxArchiveTestArchiveOperation; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, WcxPlugin, uLog, uGlobs, uFileSourceTestArchiveOperation, uFileSource, uFileSourceOperation, uFile, uWcxArchiveFileSource; type { TWcxArchiveTestArchiveOperation } TWcxArchiveTestArchiveOperation = class(TFileSourceTestArchiveOperation) private FWcxArchiveFileSource: IWcxArchiveFileSource; FStatistics: TFileSourceTestArchiveOperationStatistics; // local copy of statistics procedure ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions = []); procedure LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); protected procedure SetProcessDataProc(hArcData: TArcHandle); public constructor Create(aSourceFileSource: IFileSource; var theSourceFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class procedure ClearCurrentOperation; end; implementation uses FileUtil, LazUTF8, DCOSUtils, DCStrUtils, uDCUtils, uShowMsg, uFileSourceOperationUI, uWCXmodule, uLng, DCConvertEncoding; // ---------------------------------------------------------------------------- // WCX callbacks var // This global variable is used to store currently running operation // for plugins that not supports background operations (see GetBackgroundFlags) WcxTestArchiveOperationG: TWcxArchiveTestArchiveOperation = nil; threadvar // This thread variable is used to store currently running operation // for plugins that supports background operations (see GetBackgroundFlags) WcxTestArchiveOperationT: TWcxArchiveTestArchiveOperation; function ProcessDataProc(WcxTestArchiveOperation: TWcxArchiveTestArchiveOperation; FileName: String; Size: LongInt; UpdateName: Pointer): LongInt; begin //DCDebug('Working (' + IntToStr(GetCurrentThreadId) + ') ' + FileName + ' Size = ' + IntToStr(Size)); Result := 1; if Assigned(WcxTestArchiveOperation) then begin if WcxTestArchiveOperation.State = fsosStopping then // Cancel operation Exit(0); with WcxTestArchiveOperation.FStatistics do begin // Update file name if Assigned(UpdateName) then begin CurrentFile:= FileName; end; // Get the number of bytes processed since the previous call if Size > 0 then begin if CurrentFileDoneBytes < 0 then begin CurrentFileDoneBytes:= 0; end; CurrentFileDoneBytes := CurrentFileDoneBytes + Size; if CurrentFileDoneBytes > CurrentFileTotalBytes then begin CurrentFileDoneBytes := CurrentFileTotalBytes; end; DoneBytes := DoneBytes + Size; end // Get progress percent value to directly set progress bar else if Size < 0 then begin // Total operation percent if (Size >= -100) and (Size <= -1) then begin if (TotalBytes = 0) then TotalBytes:= -100; DoneBytes := Abs(TotalBytes) * Int64(-Size) div 100; end // Current file percent else if (Size >= -1100) and (Size <= -1000) then begin if (CurrentFileTotalBytes = 0) then CurrentFileTotalBytes:= -100; CurrentFileDoneBytes := Abs(CurrentFileTotalBytes) * (Int64(-Size) - 1000) div 100; end; end; WcxTestArchiveOperation.UpdateStatistics(WcxTestArchiveOperation.FStatistics); if not WcxTestArchiveOperation.CheckOperationStateSafe then Exit(0); end; end; end; function ProcessDataProcAG(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxTestArchiveOperationG, CeSysToUtf8(StrPas(FileName)), Size, FileName); end; function ProcessDataProcWG(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxTestArchiveOperationG, UTF16ToUTF8(UnicodeString(FileName)), Size, FileName); end; function ProcessDataProcAT(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxTestArchiveOperationT, CeSysToUtf8(StrPas(FileName)), Size, FileName); end; function ProcessDataProcWT(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin Result:= ProcessDataProc(WcxTestArchiveOperationT, UTF16ToUTF8(UnicodeString(FileName)), Size, FileName); end; // ---------------------------------------------------------------------------- constructor TWcxArchiveTestArchiveOperation.Create(aSourceFileSource: IFileSource; var theSourceFiles: TFiles); begin FWcxArchiveFileSource := aSourceFileSource as IWcxArchiveFileSource; inherited Create(aSourceFileSource, theSourceFiles); FNeedsConnection:= (FWcxArchiveFileSource.WcxModule.BackgroundFlags and BACKGROUND_UNPACK = 0); end; destructor TWcxArchiveTestArchiveOperation.Destroy; begin inherited Destroy; end; procedure TWcxArchiveTestArchiveOperation.Initialize; begin // Is plugin allow multiple Operations? if FNeedsConnection then WcxTestArchiveOperationG := Self else WcxTestArchiveOperationT := Self; // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FStatistics.ArchiveFile:= FWcxArchiveFileSource.ArchiveFileName; end; procedure TWcxArchiveTestArchiveOperation.MainExecute; var ArcHandle: TArcHandle; Header: TWCXHeader; OpenResult: Longint; iResult: Integer; Files: TFiles = nil; WcxModule: TWcxModule; begin WcxModule := FWcxArchiveFileSource.WcxModule; ArcHandle := WcxModule.OpenArchiveHandle(FWcxArchiveFileSource.ArchiveFileName, PK_OM_EXTRACT, OpenResult); if ArcHandle = 0 then begin AskQuestion(uWcxModule.GetErrorMsg(OpenResult), '', [fsourOk], fsourOk, fsourOk); RaiseAbortOperation; end; // Convert file list so that filenames are relative to archive root. Files := SourceFiles.Clone; ChangeFileListRoot(PathDelim, Files); try SetProcessDataProc(ArcHandle); WcxModule.WcxSetChangeVolProc(ArcHandle); while (WcxModule.ReadWCXHeader(ArcHandle, Header) = E_SUCCESS) do try CheckOperationState; // Now check if the file is to be extracted. if (not FPS_ISDIR(Header.FileAttr)) // Omit directories (we handle them ourselves). and MatchesFileList(Files, Header.FileName) // Check if it's included in the filelist then begin with FStatistics do begin CurrentFile := Header.FileName; if (Header.UnpSize < 0) then CurrentFileTotalBytes := 0 else begin CurrentFileTotalBytes := Header.UnpSize; end; CurrentFileDoneBytes := -1; UpdateStatistics(FStatistics); end; iResult := WcxModule.WcxProcessFile(ArcHandle, PK_TEST, EmptyStr, EmptyStr); if iResult <> E_SUCCESS then begin // User aborted operation. if iResult = E_EABORTED then Break; ShowError(Format(rsMsgLogError + rsMsgLogTest, [FWcxArchiveFileSource.ArchiveFileName + PathDelim + Header.FileName + ' : ' + GetErrorMsg(iResult)]), iResult, [log_arc_op]); end // Error else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogTest, [FWcxArchiveFileSource.ArchiveFileName + PathDelim + Header.FileName]), [log_arc_op], lmtSuccess); end; // Success end // Extract else // Skip begin iResult := WcxModule.WcxProcessFile(ArcHandle, PK_SKIP, EmptyStr, EmptyStr); //Check for errors if iResult <> E_SUCCESS then begin ShowError(Format(rsMsgLogError + rsMsgLogTest, [FWcxArchiveFileSource.ArchiveFileName + PathDelim + Header.FileName + ' : ' + GetErrorMsg(iResult)]), iResult, [log_arc_op]); end; end; // Skip finally FreeAndNil(Header); end; finally WcxModule.CloseArchive(ArcHandle); FreeAndNil(Files); end; end; procedure TWcxArchiveTestArchiveOperation.Finalize; begin ClearCurrentOperation; end; procedure TWcxArchiveTestArchiveOperation.ShowError(const sMessage: String; iError: Integer; logOptions: TLogOptions); begin LogMessage(sMessage, logOptions, lmtError); if (gSkipFileOpError = False) and (iError > E_SUCCESS) then begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin RaiseAbortOperation; end; end; end; procedure TWcxArchiveTestArchiveOperation.LogMessage(const sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; procedure TWcxArchiveTestArchiveOperation.SetProcessDataProc(hArcData: TArcHandle); begin with FWcxArchiveFileSource.WcxModule do begin if FNeedsConnection then WcxSetProcessDataProc(hArcData, @ProcessDataProcAG, @ProcessDataProcWG) else WcxSetProcessDataProc(hArcData, @ProcessDataProcAT, @ProcessDataProcWT); end; end; class procedure TWcxArchiveTestArchiveOperation.ClearCurrentOperation; begin WcxTestArchiveOperationG := nil; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/���������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017743� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/fwfxplugincopymoveoperationoptions.lfm�������������������0000644�0001750�0000144�00000003727�14743153644�027764� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object WfxPluginCopyMoveOperationOptionsUI: TWfxPluginCopyMoveOperationOptionsUI Left = 305 Height = 158 Top = 222 Width = 549 AutoSize = True ClientHeight = 158 ClientWidth = 549 LCLVersion = '1.8.4.0' object pnlComboBoxes: TPanel AnchorSideLeft.Control = Owner Left = 0 Height = 23 Top = 0 Width = 186 AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 5 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 23 ClientWidth = 186 TabOrder = 0 object lblFileExists: TLabel Left = 0 Height = 15 Top = 4 Width = 81 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'When file exists' FocusControl = cmbFileExists ParentColor = False end object cmbFileExists: TComboBox Left = 86 Height = 23 Top = 0 Width = 100 ItemHeight = 15 Style = csDropDownList TabOrder = 0 end end object pnlCheckboxes: TPanel AnchorSideLeft.Control = pnlComboBoxes AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlComboBoxes Left = 194 Height = 38 Top = 0 Width = 246 AutoSize = True BorderSpacing.Left = 8 BevelOuter = bvNone BevelWidth = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 38 ClientWidth = 246 TabOrder = 1 object cbWorkInBackground: TCheckBox AnchorSideTop.Control = cbCopyTime AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 19 Width = 246 Caption = 'Work in background (separate connection)' OnChange = cbWorkInBackgroundChange TabOrder = 1 Visible = False end object cbCopyTime: TCheckBox AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 0 Width = 103 Caption = 'Copy d&ate/time' TabOrder = 0 end end end �����������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/fwfxplugincopymoveoperationoptions.lrj�������������������0000644�0001750�0000144�00000001307�14743153644�027765� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":111687171,"name":"twfxplugincopymoveoperationoptionsui.lblfileexists.caption","sourcebytes":[87,104,101,110,32,102,105,108,101,32,101,120,105,115,116,115],"value":"When file exists"}, {"hash":31854361,"name":"twfxplugincopymoveoperationoptionsui.cbworkinbackground.caption","sourcebytes":[87,111,114,107,32,105,110,32,98,97,99,107,103,114,111,117,110,100,32,40,115,101,112,97,114,97,116,101,32,99,111,110,110,101,99,116,105,111,110,41],"value":"Work in background (separate connection)"}, {"hash":231770837,"name":"twfxplugincopymoveoperationoptionsui.cbcopytime.caption","sourcebytes":[67,111,112,121,32,100,38,97,116,101,47,116,105,109,101],"value":"Copy d&ate/time"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/fwfxplugincopymoveoperationoptions.pas�������������������0000644�0001750�0000144�00000015716�14743153644�027772� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fWfxPluginCopyMoveOperationOptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ExtCtrls, uFileSourceOperationOptionsUI, uFileSourceCopyOperation, uWfxPluginCopyOperation, uWfxPluginMoveOperation, uWfxPluginCopyInOperation, uWfxPluginCopyOutOperation; type { TWfxPluginCopyMoveOperationOptionsUI } TWfxPluginCopyMoveOperationOptionsUI = class(TFileSourceOperationOptionsUI) cbCopyTime: TCheckBox; cbWorkInBackground: TCheckBox; cmbFileExists: TComboBox; grpOptions: TGroupBox; lblFileExists: TLabel; pnlCheckboxes: TPanel; pnlComboBoxes: TPanel; procedure cbWorkInBackgroundChange(Sender: TObject); private procedure SetCopyOptions(CopyOperation: TFileSourceCopyOperation); procedure SetOperationOptions(CopyOperation: TWfxPluginCopyOperation); overload; procedure SetOperationOptions(MoveOperation: TWfxPluginMoveOperation); overload; procedure SetOperationOptions(CopyInOperation: TWfxPluginCopyInOperation); overload; procedure SetOperationOptions(CopyOutOperation: TWfxPluginCopyOutOperation); overload; public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; procedure SaveOptions; override; procedure SetOperationOptions(Operation: TObject); override; end; TWfxPluginCopyOperationOptionsUI = class(TWfxPluginCopyMoveOperationOptionsUI) end; TWfxPluginMoveOperationOptionsUI = class(TWfxPluginCopyMoveOperationOptionsUI) end; { TWfxPluginCopyInOperationOptionsUI } TWfxPluginCopyInOperationOptionsUI = class(TWfxPluginCopyMoveOperationOptionsUI) public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; end; { TWfxPluginCopyOutOperationOptionsUI } TWfxPluginCopyOutOperationOptionsUI = class(TWfxPluginCopyMoveOperationOptionsUI) public constructor Create(AOwner: TComponent; AFileSource: IInterface); override; end; implementation {$R *.lfm} uses DCStrUtils, uLng, DCOSUtils, WfxPlugin, fCopyMoveDlg, uGlobs, uWfxPluginFileSource, uFileSourceOperationOptions, uOperationsManager; { TWfxPluginCopyMoveOperationOptionsUI } constructor TWfxPluginCopyMoveOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); begin inherited Create(AOwner, AFileSource); ParseLineToList(rsFileOpCopyMoveFileExistsOptions, cmbFileExists.Items); // Load default options. case gOperationOptionFileExists of fsoofeNone : cmbFileExists.ItemIndex := 0; fsoofeOverwrite: cmbFileExists.ItemIndex := 1; fsoofeSkip : cmbFileExists.ItemIndex := 2; end; with (AFileSource as IWfxPluginFileSource).WfxModule do begin cbCopyTime.Visible := Assigned(FsSetTime) or Assigned(FsSetTimeW); cbCopyTime.Checked := cbCopyTime.Visible and gOperationOptionCopyTime; end; end; procedure TWfxPluginCopyMoveOperationOptionsUI.SaveOptions; begin // TODO: Saving options for each file source operation separately. end; procedure TWfxPluginCopyMoveOperationOptionsUI.SetOperationOptions(Operation: TObject); begin if Operation is TWfxPluginCopyOperation then SetOperationOptions(Operation as TWfxPluginCopyOperation) else if Operation is TWfxPluginMoveOperation then SetOperationOptions(Operation as TWfxPluginMoveOperation) else if Operation is TWfxPluginCopyInOperation then SetOperationOptions(Operation as TWfxPluginCopyInOperation) else if Operation is TWfxPluginCopyOutOperation then SetOperationOptions(Operation as TWfxPluginCopyOutOperation); end; procedure TWfxPluginCopyMoveOperationOptionsUI.cbWorkInBackgroundChange( Sender: TObject); begin with (Owner as TfrmCopyDlg) do begin if not cbWorkInBackground.Checked then QueueIdentifier:= ModalQueueId else begin QueueIdentifier:= SingleQueueId; end; btnAddToQueue.Visible:= cbWorkInBackground.Checked; btnCreateSpecialQueue.Visible:= btnAddToQueue.Visible; end; end; procedure TWfxPluginCopyMoveOperationOptionsUI.SetCopyOptions(CopyOperation: TFileSourceCopyOperation); begin with CopyOperation do begin if cbCopyTime.Checked then CopyAttributesOptions := CopyAttributesOptions + [caoCopyTime] else begin CopyAttributesOptions := CopyAttributesOptions - [caoCopyTime]; end; end; end; procedure TWfxPluginCopyMoveOperationOptionsUI.SetOperationOptions(CopyOperation: TWfxPluginCopyOperation); begin with CopyOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; SetCopyOptions(CopyOperation); end; end; procedure TWfxPluginCopyMoveOperationOptionsUI.SetOperationOptions(MoveOperation: TWfxPluginMoveOperation); begin with MoveOperation do begin case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; end; end; procedure TWfxPluginCopyMoveOperationOptionsUI.SetOperationOptions(CopyInOperation: TWfxPluginCopyInOperation); begin with CopyInOperation do begin NeedsConnection:= not cbWorkInBackground.Checked; case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; SetCopyOptions(CopyInOperation); end; end; procedure TWfxPluginCopyMoveOperationOptionsUI.SetOperationOptions(CopyOutOperation: TWfxPluginCopyOutOperation); begin with CopyOutOperation do begin NeedsConnection:= not cbWorkInBackground.Checked; case cmbFileExists.ItemIndex of 0: FileExistsOption := fsoofeNone; 1: FileExistsOption := fsoofeOverwrite; 2: FileExistsOption := fsoofeSkip; end; SetCopyOptions(CopyOutOperation); end; end; { TWfxPluginCopyInOperationOptionsUI } constructor TWfxPluginCopyInOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); const CAN_UPLOAD = BG_UPLOAD or BG_ASK_USER; begin inherited Create(AOwner, AFileSource); with (AFileSource as IWfxPluginFileSource) do begin cbWorkInBackground.Visible:= (WfxModule.BackgroundFlags and CAN_UPLOAD) = CAN_UPLOAD; if cbWorkInBackground.Visible then cbWorkInBackground.Checked:= False else cbWorkInBackground.Checked:= (WfxModule.BackgroundFlags and BG_UPLOAD <> 0); end; cbWorkInBackgroundChange(cbWorkInBackground); end; { TWfxPluginCopyOutOperationOptionsUI } constructor TWfxPluginCopyOutOperationOptionsUI.Create(AOwner: TComponent; AFileSource: IInterface); const CAN_DOWNLOAD = BG_DOWNLOAD or BG_ASK_USER; begin inherited Create(AOwner, AFileSource); with (AFileSource as IWfxPluginFileSource) do begin cbWorkInBackground.Visible:= (WfxModule.BackgroundFlags and CAN_DOWNLOAD) = CAN_DOWNLOAD; if cbWorkInBackground.Visible then cbWorkInBackground.Checked:= False else cbWorkInBackground.Checked:= (WfxModule.BackgroundFlags and BG_DOWNLOAD <> 0); end; cbWorkInBackgroundChange(cbWorkInBackground); end; end. ��������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxplugincalcstatisticsoperation.pas��������������������0000644�0001750�0000144�00000006512�14743153644�027543� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginCalcStatisticsOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCalcStatisticsOperation, uFileSource, uWfxPluginFileSource, uFile; type { TWfxPluginCalcStatisticsOperation } TWfxPluginCalcStatisticsOperation = class(TFileSourceCalcStatisticsOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FStatistics: TFileSourceCalcStatisticsOperationStatistics; // local copy of statistics procedure ProcessFile(aFile: TFile); procedure ProcessSubDirs(const srcPath: String); public constructor Create(aTargetFileSource: IFileSource; var theFiles: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses WfxPlugin, uWfxModule; constructor TWfxPluginCalcStatisticsOperation.Create( aTargetFileSource: IFileSource; var theFiles: TFiles); begin inherited Create(aTargetFileSource, theFiles); FWfxPluginFileSource:= aTargetFileSource as IWfxPluginFileSource; end; destructor TWfxPluginCalcStatisticsOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginCalcStatisticsOperation.Initialize; begin // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(Files.Path, FS_STATUS_START, FS_STATUS_OP_CALCSIZE); end; end; procedure TWfxPluginCalcStatisticsOperation.MainExecute; var CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to Files.Count - 1 do begin ProcessFile(Files[CurrentFileIndex]); end; end; procedure TWfxPluginCalcStatisticsOperation.Finalize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(Files.Path, FS_STATUS_END, FS_STATUS_OP_CALCSIZE); end; end; procedure TWfxPluginCalcStatisticsOperation.ProcessFile(aFile: TFile); begin FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); AppProcessMessages; CheckOperationState; if aFile.IsDirectory then begin Inc(FStatistics.Directories); ProcessSubDirs(aFile.Path + aFile.Name + DirectorySeparator); end else if aFile.IsLink then begin Inc(FStatistics.Links); end else begin Inc(FStatistics.Files); FStatistics.Size := FStatistics.Size + aFile.Size; if aFile.ModificationTime < FStatistics.OldestFile then FStatistics.OldestFile := aFile.ModificationTime; if aFile.ModificationTime > FStatistics.NewestFile then FStatistics.NewestFile := aFile.ModificationTime; end; UpdateStatistics(FStatistics); end; procedure TWfxPluginCalcStatisticsOperation.ProcessSubDirs(const srcPath: String); var AFile: TFile; Handle: THandle; FindData: TWfxFindData; begin with FWfxPluginFileSource.WfxModule do begin Handle := WfxFindFirst(srcPath, FindData); if Handle = wfxInvalidHandle then Exit; repeat if (FindData.FileName = '.') or (FindData.FileName = '..') then Continue; AFile := TWfxPluginFileSource.CreateFile(srcPath, FindData); try ProcessFile(aFile); finally FreeAndNil(aFile); end; until not WfxFindNext(Handle, FindData); FsFindClose(Handle); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxplugincopyinoperation.pas����������������������������0000644�0001750�0000144�00000013226�14743153644�026027� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginCopyInOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCopyOperation, uFileSource, uFileSourceOperation, uFileSourceOperationOptionsUI, uFile, uWfxPluginFileSource, uWfxPluginUtil; type { TWfxPluginCopyInOperation } TWfxPluginCopyInOperation = class(TFileSourceCopyInOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FOperationHelper: TWfxPluginOperationHelper; FCallbackDataClass: TCallbackDataClass; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics // Options FInfoOperation: LongInt; procedure SetNeedsConnection(AValue: Boolean); protected function UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property NeedsConnection: Boolean read FNeedsConnection write SetNeedsConnection; end; implementation uses uFileSourceOperationOptions, fWfxPluginCopyMoveOperationOptions, WfxPlugin, uFileSystemUtil, uAdministrator; // -- TWfxPluginCopyInOperation --------------------------------------------- procedure TWfxPluginCopyInOperation.SetNeedsConnection(AValue: Boolean); begin FNeedsConnection:= AValue; if (FNeedsConnection = False) then FInfoOperation:= FS_STATUS_OP_PUT_MULTI_THREAD else if (SourceFiles.Count > 1) then FInfoOperation:= FS_STATUS_OP_PUT_MULTI else FInfoOperation:= FS_STATUS_OP_PUT_SINGLE; end; function TWfxPluginCopyInOperation.UpdateProgress(SourceName,TargetName: PAnsiChar; PercentDone: Integer): Integer; var iTemp: Int64; begin Result := 0; //DCDebug('SourceName=', SourceName, #32, 'TargetName=', TargetName, #32, 'PercentDone=', IntToStr(PercentDone)); if State = fsosStopping then // Cancel operation Exit(1); with FStatistics do begin if Assigned(SourceName) then begin FStatistics.CurrentFileFrom:= SourceName; end; if Assigned(TargetName) then begin FStatistics.CurrentFileTo:= TargetName; end; iTemp:= CurrentFileTotalBytes * PercentDone div 100; DoneBytes := DoneBytes + (iTemp - CurrentFileDoneBytes); CurrentFileDoneBytes:= iTemp; UpdateStatistics(FStatistics); end; if not AppProcessMessages(True) then Exit(1); end; constructor TWfxPluginCopyInOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FWfxPluginFileSource:= aTargetFileSource as IWfxPluginFileSource; with FWfxPluginFileSource do FCallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNumber]); inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); SetNeedsConnection(FNeedsConnection); end; destructor TWfxPluginCopyInOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginCopyInOperation.Initialize; var TreeBuilder: TFileSystemTreeBuilder; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(TargetPath, FS_STATUS_START, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= @UpdateProgress; UpdateProgressFunction:= @UpdateProgress; end; // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TFileSystemTreeBuilder.Create(@AskQuestion, @CheckOperationState); try ElevateAction:= dupError; TreeBuilder.SymLinkOption:= fsooslFollow; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; if Assigned(FOperationHelper) then FreeAndNil(FOperationHelper); FOperationHelper := TWfxPluginOperationHelper.Create( FWfxPluginFileSource, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, @ShowCompareFilesUIByFileObject, Thread, wpohmCopyIn, TargetPath); FOperationHelper.RenameMask := RenameMask; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.CopyAttributesOptions := CopyAttributesOptions; FOperationHelper.Initialize; end; procedure TWfxPluginCopyInOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree, FStatistics); end; procedure TWfxPluginCopyInOperation.Finalize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(TargetPath, FS_STATUS_END, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= nil; UpdateProgressFunction:= nil; end; FileExistsOption := FOperationHelper.FileExistsOption; FOperationHelper.Free; end; class function TWfxPluginCopyInOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TWfxPluginCopyInOperationOptionsUI; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxplugincopyoperation.pas������������������������������0000644�0001750�0000144�00000012404�14743153644�025475� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginCopyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCopyOperation, uFileSource, uFileSourceOperation, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uWfxPluginFileSource, uWfxPluginUtil; type { TWfxPluginCopyOperation } TWfxPluginCopyOperation = class(TFileSourceCopyOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FOperationHelper: TWfxPluginOperationHelper; FCallbackDataClass: TCallbackDataClass; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics // Options FInfoOperation: LongInt; protected function UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; end; implementation uses fWfxPluginCopyMoveOperationOptions, WfxPlugin; // -- TWfxPluginCopyOperation --------------------------------------------- function TWfxPluginCopyOperation.UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; var iTemp: Int64; begin Result := 0; //DCDebug('SourceName=', SourceName, #32, 'TargetName=', TargetName, #32, 'PercentDone=', IntToStr(PercentDone)); if State = fsosStopping then // Cancel operation Exit(1); with FStatistics do begin if Assigned(SourceName) then begin FStatistics.CurrentFileFrom:= SourceName; end; if Assigned(TargetName) then begin FStatistics.CurrentFileTo:= TargetName; end; iTemp:= CurrentFileTotalBytes * PercentDone div 100; DoneBytes := DoneBytes + (iTemp - CurrentFileDoneBytes); CurrentFileDoneBytes:= iTemp; UpdateStatistics(FStatistics); end; if not AppProcessMessages(True) then Exit(1); end; constructor TWfxPluginCopyOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FWfxPluginFileSource:= aSourceFileSource as IWfxPluginFileSource; with FWfxPluginFileSource do FCallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNumber]); if theSourceFiles.Count > 1 then FInfoOperation:= FS_STATUS_OP_RENMOV_MULTI else FInfoOperation:= FS_STATUS_OP_RENMOV_SINGLE; inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); end; destructor TWfxPluginCopyOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginCopyOperation.Initialize; var TreeBuilder: TWfxTreeBuilder; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(SourceFiles.Path, FS_STATUS_START, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= @UpdateProgress; UpdateProgressFunction:= @UpdateProgress; // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TWfxTreeBuilder.Create(@AskQuestion, @CheckOperationState); try TreeBuilder.WfxModule:= WfxModule; TreeBuilder.SymLinkOption:= fsooslFollow; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; end; if Assigned(FOperationHelper) then FreeAndNil(FOperationHelper); FOperationHelper := TWfxPluginOperationHelper.Create( FWfxPluginFileSource, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, @ShowCompareFilesUIByFileObject, Thread, wpohmCopy, TargetPath); FOperationHelper.RenameMask := RenameMask; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.CopyAttributesOptions := CopyAttributesOptions; FOperationHelper.Initialize; end; procedure TWfxPluginCopyOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree, FStatistics); end; procedure TWfxPluginCopyOperation.Finalize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(SourceFiles.Path, FS_STATUS_END, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= nil; UpdateProgressFunction:= nil; end; FileExistsOption := FOperationHelper.FileExistsOption; FOperationHelper.Free; end; class function TWfxPluginCopyOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TWfxPluginCopyOperationOptionsUI; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxplugincopyoutoperation.pas���������������������������0000644�0001750�0000144�00000013252�14743153644�026227� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginCopyOutOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCopyOperation, uFileSource, uFileSourceOperation, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uWfxPluginFileSource, uWfxPluginUtil; type { TWfxPluginCopyOutOperation } TWfxPluginCopyOutOperation = class(TFileSourceCopyOutOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FOperationHelper: TWfxPluginOperationHelper; FCallbackDataClass: TCallbackDataClass; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceCopyOperationStatistics; // local copy of statistics // Options FInfoOperation: LongInt; procedure SetNeedsConnection(AValue: Boolean); protected function UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; public constructor Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; property NeedsConnection: Boolean read FNeedsConnection write SetNeedsConnection; end; implementation uses fWfxPluginCopyMoveOperationOptions, WfxPlugin; // -- TWfxPluginCopyOutOperation --------------------------------------------- procedure TWfxPluginCopyOutOperation.SetNeedsConnection(AValue: Boolean); begin FNeedsConnection:= AValue; if (FNeedsConnection = False) then FInfoOperation:= FS_STATUS_OP_GET_MULTI_THREAD else if (SourceFiles.Count > 1) then FInfoOperation:= FS_STATUS_OP_GET_MULTI else FInfoOperation:= FS_STATUS_OP_GET_SINGLE; end; function TWfxPluginCopyOutOperation.UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; var iTemp: Int64; begin Result := 0; //DCDebug('SourceName=', SourceName, #32, 'TargetName=', TargetName, #32, 'PercentDone=', IntToStr(PercentDone)); if State = fsosStopping then // Cancel operation Exit(1); with FStatistics do begin if Assigned(SourceName) then begin FStatistics.CurrentFileFrom:= SourceName; end; if Assigned(TargetName) then begin FStatistics.CurrentFileTo:= TargetName; end; iTemp:= CurrentFileTotalBytes * PercentDone div 100; DoneBytes := DoneBytes + (iTemp - CurrentFileDoneBytes); CurrentFileDoneBytes:= iTemp; UpdateStatistics(FStatistics); end; if not AppProcessMessages(True) then Exit(1); end; constructor TWfxPluginCopyOutOperation.Create(aSourceFileSource: IFileSource; aTargetFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FWfxPluginFileSource:= aSourceFileSource as IWfxPluginFileSource; with FWfxPluginFileSource do FCallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNumber]); inherited Create(aSourceFileSource, aTargetFileSource, theSourceFiles, aTargetPath); SetNeedsConnection(FNeedsConnection); end; destructor TWfxPluginCopyOutOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginCopyOutOperation.Initialize; var TreeBuilder: TWfxTreeBuilder; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(SourceFiles.Path, FS_STATUS_START, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= @UpdateProgress; UpdateProgressFunction:= @UpdateProgress; // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TWfxTreeBuilder.Create(@AskQuestion, @CheckOperationState); try TreeBuilder.WfxModule:= WfxModule; TreeBuilder.SymLinkOption:= fsooslFollow; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; end; if Assigned(FOperationHelper) then FreeAndNil(FOperationHelper); FOperationHelper := TWfxPluginOperationHelper.Create( FWfxPluginFileSource, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, @ShowCompareFilesUIByFileObject, Thread, wpohmCopyOut, TargetPath); FOperationHelper.RenameMask := RenameMask; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.CopyAttributesOptions := CopyAttributesOptions; FOperationHelper.Initialize; end; procedure TWfxPluginCopyOutOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree, FStatistics); end; procedure TWfxPluginCopyOutOperation.Finalize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(SourceFiles.Path, FS_STATUS_END, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= nil; UpdateProgressFunction:= nil; end; FileExistsOption := FOperationHelper.FileExistsOption; FOperationHelper.Free; end; class function TWfxPluginCopyOutOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TWfxPluginCopyOutOperationOptionsUI; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxplugincreatedirectoryoperation.pas�������������������0000644�0001750�0000144�00000003576�14743153644�027725� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginCreateDirectoryOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceCreateDirectoryOperation, uFileSource, uWfxPluginFileSource; type TWfxPluginCreateDirectoryOperation = class(TFileSourceCreateDirectoryOperation) private FWfxPluginFileSource: IWfxPluginFileSource; public constructor Create(aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses uFileSourceOperationUI, uLog, uLng, uGlobs, uWfxModule; constructor TWfxPluginCreateDirectoryOperation.Create( aTargetFileSource: IFileSource; aCurrentPath: String; aDirectoryPath: String); begin FWfxPluginFileSource := aTargetFileSource as IWfxPluginFileSource; inherited Create(aTargetFileSource, aCurrentPath, aDirectoryPath); end; procedure TWfxPluginCreateDirectoryOperation.Initialize; begin end; procedure TWfxPluginCreateDirectoryOperation.MainExecute; begin with FWfxPluginFileSource do begin case WfxModule.WfxMkDir(BasePath, AbsolutePath) of WFX_NOTSUPPORTED: AskQuestion(rsMsgErrNotSupported, '', [fsourOk], fsourOk, fsourOk); WFX_SUCCESS: begin // write log success if (log_vfs_op in gLogOptions) and (log_success in gLogOptions) then logWrite(Thread, Format(rsMsgLogSuccess+rsMsgLogMkDir, [AbsolutePath]), lmtSuccess) end; else begin // write log error if (log_vfs_op in gLogOptions) and (log_errors in gLogOptions) then logWrite(Thread, Format(rsMsgLogError+rsMsgLogMkDir, [AbsolutePath]), lmtError); end; end; // case end; // with end; procedure TWfxPluginCreateDirectoryOperation.Finalize; begin end; end. ����������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxplugindeleteoperation.pas����������������������������0000644�0001750�0000144�00000014430�14743153644�025766� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginDeleteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceDeleteOperation, uWfxPluginFileSource, uFileSource, uFileSourceOperationOptions, uFileSourceOperationUI, uFile, uGlobs, uLog; type TWfxPluginDeleteOperation = class(TFileSourceDeleteOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FFullFilesTreeToDelete: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceDeleteOperationStatistics; // local copy of statistics // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; FSkipErrors: Boolean; FDeleteReadOnly: TFileSourceOperationOptionGeneral; protected function ProcessFile(aFile: TFile): Boolean; function ShowError(sMessage: String): TFileSourceOperationUIResponse; procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); public constructor Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses DCOSUtils, uLng, WfxPlugin; constructor TWfxPluginDeleteOperation.Create(aTargetFileSource: IFileSource; var theFilesToDelete: TFiles); begin FSymLinkOption := fsooslNone; FSkipErrors := False; FDeleteReadOnly := fsoogNone; FFullFilesTreeToDelete := nil; FWfxPluginFileSource:= aTargetFileSource as IWfxPluginFileSource; inherited Create(aTargetFileSource, theFilesToDelete); end; destructor TWfxPluginDeleteOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginDeleteOperation.Initialize; begin with FWfxPluginFileSource do WfxModule.WfxStatusInfo(FilesToDelete.Path, FS_STATUS_START, FS_STATUS_OP_DELETE); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; FWfxPluginFileSource.FillAndCount(FilesToDelete, True, False, FFullFilesTreeToDelete, FStatistics.TotalFiles, FStatistics.TotalBytes); // gets full list of files (recursive) end; procedure TWfxPluginDeleteOperation.MainExecute; var aFile: TFile; CurrentFileIndex: Integer; begin for CurrentFileIndex := FFullFilesTreeToDelete.Count - 1 downto 0 do begin aFile := FFullFilesTreeToDelete[CurrentFileIndex]; FStatistics.CurrentFile := aFile.Path + aFile.Name; UpdateStatistics(FStatistics); ProcessFile(aFile); with FStatistics do begin DoneFiles := DoneFiles + 1; DoneBytes := DoneBytes + aFile.Size; UpdateStatistics(FStatistics); end; AppProcessMessages; CheckOperationState; end; end; procedure TWfxPluginDeleteOperation.Finalize; begin with FWfxPluginFileSource do WfxModule.WfxStatusInfo(FilesToDelete.Path, FS_STATUS_END, FS_STATUS_OP_DELETE); end; function TWfxPluginDeleteOperation.ProcessFile(aFile: TFile): Boolean; var aFileName: String; bRetry: Boolean; sMessage, sQuestion: String; logOptions: TLogOptions; begin Result := False; aFileName := aFile.Path + aFile.Name; if FileIsReadOnly(aFile.Attributes) then begin case FDeleteReadOnly of fsoogNone: case AskQuestion(Format(rsMsgFileReadOnly, [aFileName]), '', [fsourYes, fsourAll, fsourSkip, fsourSkipAll], fsourYes, fsourSkip) of fsourAll: FDeleteReadOnly := fsoogYes; fsourSkip: Exit; fsourSkipAll: begin FDeleteReadOnly := fsoogNo; Exit; end; end; fsoogNo: Exit; end; end; repeat bRetry := False; //if FileIsReadOnly(aFile.Attributes) then // mbFileSetReadOnly(aFileName, False); with FWfxPluginFileSource.WfxModule do if aFile.IsDirectory then // directory begin Result := WfxRemoveDir(aFileName); end else begin // files and other stuff Result := WfxDeleteFile(aFileName); end; if Result then begin // success if aFile.IsDirectory then begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogRmDir, [aFileName]), [log_vfs_op], lmtSuccess); end else begin LogMessage(Format(rsMsgLogSuccess + rsMsgLogDelete, [aFileName]), [log_vfs_op], lmtSuccess); end; end else // error begin if aFile.IsDirectory then begin logOptions := [log_vfs_op]; sMessage := Format(rsMsgLogError + rsMsgLogRmDir, [aFileName]); sQuestion := Format(rsMsgNotDelete, [aFileName]); end else begin logOptions := [log_vfs_op]; sMessage := Format(rsMsgLogError + rsMsgLogDelete, [aFileName]); sQuestion := Format(rsMsgNotDelete, [aFileName]); end; if gSkipFileOpError or (FSkipErrors = True) then LogMessage(sMessage, logOptions, lmtError) else begin case AskQuestion(sQuestion, '', [fsourRetry, fsourSkip, fsourSkipAll, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetry := True; fsourSkipAll: FSkipErrors := True; fsourAbort: RaiseAbortOperation; end; end; end; until bRetry = False; end; function TWfxPluginDeleteOperation.ShowError(sMessage: String): TFileSourceOperationUIResponse; begin if gSkipFileOpError then begin logWrite(Thread, sMessage, lmtError, True); Result := fsourSkip; end else begin Result := AskQuestion(sMessage, '', [fsourSkip, fsourCancel], fsourSkip, fsourCancel); if Result = fsourCancel then RaiseAbortOperation; end; end; procedure TWfxPluginDeleteOperation.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(Thread, sMessage, logMsgType); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxpluginexecuteoperation.pas���������������������������0000644�0001750�0000144�00000004500�14743153644�026163� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uFileSourceExecuteOperation, uWfxPluginFileSource; type { TWfxPluginExecuteOperation } TWfxPluginExecuteOperation = class(TFileSourceExecuteOperation) private FWfxPluginFileSource: IWfxPluginFileSource; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses Forms, WfxPlugin; constructor TWfxPluginExecuteOperation.Create( aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FWfxPluginFileSource := aTargetFileSource as IWfxPluginFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TWfxPluginExecuteOperation.Initialize; begin with FWfxPluginFileSource do WfxModule.WfxStatusInfo(CurrentPath, FS_STATUS_START, FS_STATUS_OP_EXEC); end; procedure TWfxPluginExecuteOperation.MainExecute; var RemoteName: String; iResult: LongInt; begin if Pos('quote ', Verb) = 1 then RemoteName:= CurrentPath else begin RemoteName:= AbsolutePath; end; iResult:= FWfxPluginFileSource.WfxModule.WfxExecuteFile(Application.MainForm.Tag, RemoteName, Verb); case iResult of FS_EXEC_OK: FExecuteOperationResult:= fseorSuccess; FS_EXEC_ERROR: FExecuteOperationResult:= fseorError; FS_EXEC_YOURSELF: FExecuteOperationResult:= fseorYourSelf; FS_EXEC_SYMLINK: begin FResultString:= RemoteName; FExecuteOperationResult:= fseorSymLink; end; end; end; procedure TWfxPluginExecuteOperation.Finalize; begin with FWfxPluginFileSource do WfxModule.WfxStatusInfo(CurrentPath, FS_STATUS_END, FS_STATUS_OP_EXEC); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxpluginfilesource.pas���������������������������������0000644�0001750�0000144�00000120651�14743153644�024746� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginFileSource; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, URIParser, uWFXModule, WfxPlugin, uFile, uFileSourceProperty, uFileSourceOperationTypes, uFileProperty, uFileSource, uFileSourceOperation; type TUpdateProgress = function(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer of object; { IWfxPluginFileSource } IWfxPluginFileSource = interface(IFileSource) ['{F1F728C6-F718-4B17-8DE2-BE0134134ED8}'] procedure FillAndCount(Files: TFiles; CountDirs: Boolean; ExcludeRootDir: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); function FillSingleFile(const FullPath: String; out aFile: TFile): Boolean; function WfxCopyMove(sSourceFile, sTargetFile: String; Flags: LongInt; RemoteInfo: PRemoteInfo; Internal, CopyMoveIn: Boolean): LongInt; function GetPluginNumber: LongInt; function GetWfxModule: TWfxModule; property PluginNumber: LongInt read GetPluginNumber; property WfxModule: TWfxModule read GetWfxModule; end; { TWfxPluginFileSource } TWfxPluginFileSource = class; { TCallbackDataClass } TCallbackDataClass = class public // Must use class here instead of interface because of circular reference // between TWfxPluginFileSource and TCallbackDataClass, which would cause // the file source never to be destroyed. // TWfxPluginFileSource controls the lifetime of TCallbackDataClass though, // so it should be fine. FileSource: TWfxPluginFileSource; UpdateProgressFunction: TUpdateProgress; constructor Create(aFileSource: TWfxPluginFileSource); end; { TWfxPluginFileSource } TWfxPluginFileSource = class(TFileSource, IWfxPluginFileSource) private FModuleFileName, FPluginRootName: String; FWFXModule: TWFXModule; FPluginNumber: LongInt; FCallbackDataClass: TCallbackDataClass; function GetPluginNumber: LongInt; function GetWfxModule: TWfxModule; function CreateConnection: TFileSourceConnection; procedure CreateConnections; procedure AddToConnectionQueue(Operation: TFileSourceOperation); procedure RemoveFromConnectionQueue(Operation: TFileSourceOperation); procedure AddConnection(Connection: TFileSourceConnection); procedure RemoveConnection(Connection: TFileSourceConnection); {en Searches connections list for a connection assigned to operation. } function FindConnectionByOperation(operation: TFileSourceOperation): TFileSourceConnection; virtual; procedure NotifyNextWaitingOperation(allowedOps: TFileSourceOperationTypes); protected function GetSupportedFileProperties: TFilePropertiesTypes; override; function GetRetrievableFileProperties: TFilePropertiesTypes; override; function GetCurrentAddress: String; override; procedure OperationFinished(Operation: TFileSourceOperation); override; public procedure FillAndCount(Files: TFiles; CountDirs: Boolean; ExcludeRootDir: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); function FillSingleFile(const FullPath: String; out aFile: TFile): Boolean; function WfxCopyMove(sSourceFile, sTargetFile: String; Flags: LongInt; RemoteInfo: PRemoteInfo; Internal, CopyMoveIn: Boolean): LongInt; public constructor Create(const URI: TURI); override; constructor Create(aModuleFileName, aPluginRootName: String); reintroduce; destructor Destroy; override; class function CreateFile(const APath: String): TFile; override; class function CreateFile(const APath: String; FindData: TWfxFindData): TFile; overload; procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); override; // Retrieve operations permitted on the source. = capabilities? function GetOperationsTypes: TFileSourceOperationTypes; override; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; override; function GetFileSystem: String; override; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; function GetLocalName(var aFile: TFile): Boolean; override; function CreateDirectory(const Path: String): Boolean; override; function GetDefaultView(out DefaultView: TFileSourceFields): Boolean; override; class function IsSupportedPath(const Path: String): Boolean; override; class function CreateByRootName(aRootName: String): IWfxPluginFileSource; function GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; override; procedure RemoveOperationFromQueue(Operation: TFileSourceOperation); override; property PluginNumber: LongInt read FPluginNumber; property WfxModule: TWfxModule read FWfxModule; end; { TWfxPluginFileSourceConnection } TWfxPluginFileSourceConnection = class(TFileSourceConnection) private FWfxModule: TWfxModule; public constructor Create(aWfxModule: TWfxModule); reintroduce; property WfxModule: TWfxModule read FWfxModule; end; var // Used in callback functions WfxOperationList: TStringList = nil; threadvar // Main operation progress callback function // Declared as threadvar so each operation has it own callback function UpdateProgressFunction: TUpdateProgress; implementation uses LazUTF8, FileUtil, StrUtils, {} LCLType, uShowMsg, {} uGlobs, DCStrUtils, uDCUtils, uLog, uDebug, uLng, uCryptProc, DCFileAttributes, uConnectionManager, contnrs, syncobjs, fMain, uWfxPluginCopyInOperation, uWfxPluginCopyOutOperation, uWfxPluginMoveOperation, uVfsModule, uWfxPluginExecuteOperation, uWfxPluginListOperation, uWfxPluginCreateDirectoryOperation, uWfxPluginDeleteOperation, uWfxPluginSetFilePropertyOperation, uWfxPluginCopyOperation, DCConvertEncoding, uWfxPluginCalcStatisticsOperation, uFileFunctions; const connCopyIn = 0; connCopyOut = 1; connDelete = 2; connCopyMove = 3; var // Always use appropriate lock to access these lists. WfxConnections: TObjectList; // store connections created by Wcx file sources WfxOperationsQueue: TObjectList; // store queued operations, use only under FOperationsQueueLock WfxConnectionsLock: TCriticalSection; // used to synchronize access to connections WfxOperationsQueueLock: TCriticalSection; // used to synchronize access to operations queue { CallBack functions } function MainProgressProc(PluginNr: Integer; SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; var CallbackDataClass: TCallbackDataClass; begin Result:= 0; // DCDebug('MainProgressProc ('+IntToStr(PluginNr)+','+SourceName+','+TargetName+','+IntToStr(PercentDone)+')=' ,IntTostr(Result)); if Assigned(UpdateProgressFunction) then // Call operation progress function Result:= UpdateProgressFunction(SourceName, TargetName, PercentDone) else begin // Operation callback function not found, may be plugin call progress function // from non operation thread, call global progress function in this case DCDebug('Warning UpdateProgressFunction does not found for thread ' + hexStr(Pointer(GetCurrentThreadId))); CallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNr]); if Assigned(CallbackDataClass) and Assigned(CallbackDataClass.UpdateProgressFunction) then Result:= CallbackDataClass.UpdateProgressFunction(SourceName, TargetName, PercentDone) else // Global callback function not found, incorrect // FileSourceOperation implementation, notify about it DCDebug('Warning UpdateProgressFunction does not found for plugin number %d', [PluginNr]); end; end; function MainProgressProcA(PluginNr: Integer; SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; dcpcall; var sSourceName, sTargetName: String; begin if Assigned(SourceName) then begin sSourceName:= CeSysToUtf8(StrPas(SourceName)); SourceName:= PAnsiChar(sSourceName); end; if Assigned(TargetName) then begin sTargetName:= CeSysToUtf8(StrPas(TargetName)); TargetName:= PAnsiChar(sTargetName); end; Result:= MainProgressProc(PluginNr, SourceName, TargetName, PercentDone); end; function MainProgressProcW(PluginNr: Integer; SourceName, TargetName: PWideChar; PercentDone: Integer): Integer; dcpcall; var sSourceName, sTargetName: String; begin if Assigned(SourceName) then begin sSourceName:= UTF16ToUTF8(UnicodeString(SourceName)); SourceName:= Pointer(PAnsiChar(sSourceName)); end; if Assigned(TargetName) then begin sTargetName:= UTF16ToUTF8(UnicodeString(TargetName)); TargetName:= Pointer(PAnsiChar(sTargetName)); end; Result:= MainProgressProc(PluginNr, Pointer(SourceName), Pointer(TargetName), PercentDone); end; procedure MainLogProc(PluginNr, MsgType: Integer; LogString: String); var I: Integer; bLogFile: Boolean; bLogWindow: Boolean; sMsg, sName, sPath: String; LogMsgType: TLogMsgType = lmtInfo; CallbackDataClass: TCallbackDataClass; Begin sMsg:= rsMsgLogInfo; bLogWindow:= frmMain.seLogWindow.Visible; bLogFile:= ((log_vfs_op in gLogOptions) and (log_info in gLogOptions)); CallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNr]); case MsgType of msgtype_connect: begin bLogWindow:= True; if Assigned(CallbackDataClass) then begin if Length(LogString) > 0 then begin I:= Pos(#32, LogString); sName:= WfxOperationList[PluginNr]; sPath:= Copy(LogString, I + 1, MaxInt); AddNetworkConnection(sName, sPath, CallbackDataClass.FileSource); end; end; sMsg:= sMsg + '[' + IntToStr(MsgType) + ']'; end; msgtype_disconnect: begin if Assigned(CallbackDataClass) then begin bLogWindow:= False; I:= Pos(#32, LogString); sName:= WfxOperationList[PluginNr]; sPath:= Copy(LogString, I + 1, MaxInt); RemoveNetworkConnection(sName, sPath); end; sMsg:= sMsg + '[' + IntToStr(MsgType) + ']'; end; msgtype_details, msgtype_operationcomplete, msgtype_transfercomplete, msgtype_connectcomplete: sMsg:= sMsg + '[' + IntToStr(MsgType) + ']'; msgtype_importanterror: begin LogMsgType:= lmtError; sMsg:= rsMsgLogError + '[' + IntToStr(MsgType) + ']'; bLogFile:= (log_vfs_op in gLogOptions) and (log_errors in gLogOptions); end; end; // write log info logWrite(sMsg + ', ' + logString, LogMsgType, bLogWindow, bLogFile); // DCDebug('MainLogProc ('+ sMsg + ',' + logString + ')'); end; procedure MainLogProcA(PluginNr, MsgType: Integer; LogString: PAnsiChar); dcpcall; begin MainLogProc(PluginNr, MsgType, CeSysToUtf8(StrPas(LogString))); end; procedure MainLogProcW(PluginNr, MsgType: Integer; LogString: PWideChar); dcpcall; begin MainLogProc(PluginNr, MsgType, UTF16ToUTF8(UnicodeString(LogString))); end; function MainRequestProc(PluginNr, RequestType: Integer; CustomTitle, CustomText: String; var ReturnedText: String): Bool; begin if CustomTitle = '' then CustomTitle:= 'Double Commander'; case RequestType of RT_Other: Result:= ShowInputQuery(CustomTitle, CustomText, ReturnedText); RT_UserName: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgUserName, CustomText), ReturnedText); RT_Password: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgPassword, CustomText), True, ReturnedText); RT_Account: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgAccount, CustomText), ReturnedText); RT_UserNameFirewall: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgUserNameFirewall, CustomText), ReturnedText); RT_PasswordFirewall: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgPasswordFirewall, CustomText), True, ReturnedText); RT_TargetDir: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgTargetDir, CustomText), ReturnedText); RT_URL: Result:= ShowInputQuery(CustomTitle, IfThen(CustomText = EmptyStr, rsMsgURL, CustomText), ReturnedText); RT_MsgOK: Result:= (ShowMessageBox(CustomText, CustomTitle, MB_OK) = IDOK); RT_MsgYesNo: Result:= (ShowMessageBox(CustomText, CustomTitle, MB_YESNO) = IDYES); RT_MsgOKCancel: Result:= (ShowMessageBox(CustomText, CustomTitle, MB_OKCANCEL) = IDOK); else begin Result:= False; end; end; // DCDebug('MainRequestProc ('+IntToStr(PluginNr)+','+IntToStr(RequestType)+','+CustomTitle+','+CustomText+','+ReturnedText+')', BoolToStr(Result, True)); end; function MainRequestProcA(PluginNr, RequestType: Integer; CustomTitle, CustomText, ReturnedText: PAnsiChar; MaxLen: Integer): Bool; dcpcall; var sCustomTitle, sCustomText, sReturnedText: String; begin sCustomTitle:= CeSysToUtf8(StrPas(CustomTitle)); sCustomText:= CeSysToUtf8(StrPas(CustomText)); sReturnedText:= CeSysToUtf8(StrPas(ReturnedText)); Result:= MainRequestProc(PluginNr, RequestType, sCustomTitle, sCustomText, sReturnedText); if Result then begin if ReturnedText <> nil then StrPLCopy(ReturnedText, CeUtf8ToSys(sReturnedText), MaxLen); end; end; function MainRequestProcW(PluginNr, RequestType: Integer; CustomTitle, CustomText, ReturnedText: PWideChar; MaxLen: Integer): Bool; dcpcall; var sCustomTitle, sCustomText, sReturnedText: String; begin sCustomTitle:= UTF16ToUTF8(UnicodeString(CustomTitle)); sCustomText:= UTF16ToUTF8(UnicodeString(CustomText)); sReturnedText:= UTF16ToUTF8(UnicodeString(ReturnedText)); Result:= MainRequestProc(PluginNr, RequestType, sCustomTitle, sCustomText, sReturnedText); if Result then begin if ReturnedText <> nil then StrPLCopyW(ReturnedText, CeUtf8ToUtf16(sReturnedText), MaxLen); end; end; function CryptProc({%H-}PluginNr, CryptoNumber: Integer; Mode: Integer; ConnectionName: String; var Password: String): Integer; const cPrefix = 'wfx'; cResult: array[TCryptStoreResult] of Integer = (FS_FILE_OK, FS_FILE_NOTSUPPORTED, FS_FILE_WRITEERROR, FS_FILE_READERROR, FS_FILE_NOTFOUND); var sGroup, sPassword: AnsiString; MyResult: TCryptStoreResult; begin MyResult:= csrSuccess; sGroup:= WfxOperationList[CryptoNumber]; case Mode of FS_CRYPT_SAVE_PASSWORD: begin MyResult:= PasswordStore.WritePassword(cPrefix, sGroup, ConnectionName, Password); end; FS_CRYPT_LOAD_PASSWORD, FS_CRYPT_LOAD_PASSWORD_NO_UI: begin if (Mode = FS_CRYPT_LOAD_PASSWORD_NO_UI) and (PasswordStore.HasMasterKey = False) then Exit(FS_FILE_NOTFOUND); MyResult:= PasswordStore.ReadPassword(cPrefix, sGroup, ConnectionName, Password); end; FS_CRYPT_COPY_PASSWORD, FS_CRYPT_MOVE_PASSWORD: begin MyResult:= PasswordStore.ReadPassword(cPrefix, sGroup, ConnectionName, sPassword); if MyResult = csrSuccess then begin MyResult:= PasswordStore.WritePassword(cPrefix, sGroup, Password, sPassword); if (MyResult = csrSuccess) and (Mode = FS_CRYPT_MOVE_PASSWORD) then begin if not PasswordStore.DeletePassword(cPrefix, sGroup, ConnectionName) then MyResult:= csrWriteError; end; end; end; FS_CRYPT_DELETE_PASSWORD: begin if not PasswordStore.DeletePassword(cPrefix, sGroup, ConnectionName) then MyResult:= csrWriteError; end; end; Result:= cResult[MyResult]; end; function CryptProcA(PluginNr, CryptoNumber: Integer; Mode: Integer; ConnectionName, Password: PAnsiChar; MaxLen: Integer): Integer; dcpcall; var sConnectionName, sPassword: String; begin sConnectionName:= CeSysToUtf8(StrPas(ConnectionName)); sPassword:= CeSysToUtf8(StrPas(Password)); Result:= CryptProc(PluginNr, CryptoNumber, Mode, sConnectionName, sPassword); if Result = FS_FILE_OK then begin if Password <> nil then StrPLCopy(Password, CeUtf8ToSys(sPassword), MaxLen); end; end; function CryptProcW(PluginNr, CryptoNumber: Integer; Mode: Integer; ConnectionName, Password: PWideChar; MaxLen: Integer): Integer; dcpcall; var sConnectionName, sPassword: String; begin sConnectionName:= UTF16ToUTF8(UnicodeString(ConnectionName)); sPassword:= UTF16ToUTF8(UnicodeString(Password)); Result:= CryptProc(PluginNr, CryptoNumber, Mode, sConnectionName, sPassword); if Result = FS_FILE_OK then begin if Password <> nil then StrPLCopyW(Password, CeUtf8ToUtf16(sPassword), MaxLen); end; end; { TWfxPluginFileSource } constructor TWfxPluginFileSource.Create(aModuleFileName, aPluginRootName: String); var AFlags: Integer; begin inherited Create; FPluginNumber:= -1; FCallbackDataClass:= nil; FModuleFileName:= aModuleFileName; FPluginRootName:= aPluginRootName; FWfxModule:= gWFXPlugins.LoadModule(FModuleFileName); if not Assigned(FWfxModule) then raise EFileSourceException.Create('Cannot load WFX module ' + FModuleFileName); with FWfxModule do begin FPluginNumber:= WfxOperationList.IndexOf(FPluginRootName); if FPluginNumber >= 0 then WfxOperationList.Objects[FPluginNumber]:= TCallbackDataClass.Create(Self) else begin FCallbackDataClass:= TCallbackDataClass.Create(Self); FPluginNumber:= WfxOperationList.AddObject(FPluginRootName, FCallbackDataClass); if Assigned(FsInit) then FsInit(FPluginNumber, @MainProgressProcA, @MainLogProcA, @MainRequestProcA); if Assigned(FsInitW) then FsInitW(FPluginNumber, @MainProgressProcW, @MainLogProcW, @MainRequestProcW); VFSInit; if not PasswordStore.MasterKeySet then AFlags:= 0 else begin AFlags:= FS_CRYPTOPT_MASTERPASS_SET; end; if Assigned(FsSetCryptCallbackW) then FsSetCryptCallbackW(@CryptProcW, FPluginNumber, AFlags); if Assigned(FsSetCryptCallback) then FsSetCryptCallback(@CryptProcA, FPluginNumber, AFlags); end; end; FOperationsClasses[fsoList] := TWfxPluginListOperation.GetOperationClass; FOperationsClasses[fsoCopy] := TWfxPluginCopyOperation.GetOperationClass; FOperationsClasses[fsoCopyIn] := TWfxPluginCopyInOperation.GetOperationClass; FOperationsClasses[fsoCopyOut] := TWfxPluginCopyOutOperation.GetOperationClass; FOperationsClasses[fsoMove] := TWfxPluginMoveOperation.GetOperationClass; FOperationsClasses[fsoDelete] := TWfxPluginDeleteOperation.GetOperationClass; FOperationsClasses[fsoCreateDirectory] := TWfxPluginCreateDirectoryOperation.GetOperationClass; FOperationsClasses[fsoSetFileProperty] := TWfxPluginSetFilePropertyOperation.GetOperationClass; FOperationsClasses[fsoExecute] := TWfxPluginExecuteOperation.GetOperationClass; CreateConnections; end; destructor TWfxPluginFileSource.Destroy; begin if (FPluginNumber >= 0) and (FPluginNumber < WfxOperationList.Count) then WfxOperationList.Objects[FPluginNumber]:= nil; FreeAndNil(FCallbackDataClass); inherited Destroy; end; class function TWfxPluginFileSource.CreateFile(const APath: String): TFile; begin Result := TFile.Create(APath); with Result do begin AttributesProperty := TFileAttributesProperty.CreateOSAttributes; SizeProperty := TFileSizeProperty.Create; ModificationTimeProperty := TFileModificationDateTimeProperty.Create; LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create; CreationTimeProperty := TFileCreationDateTimeProperty.Create; LinkProperty := TFileLinkProperty.Create; end; end; class function TWfxPluginFileSource.CreateFile(const APath: String; FindData: TWfxFindData): TFile; begin Result := TFile.Create(APath); with Result do begin // Check that attributes is used if (FindData.FileAttributes and FILE_ATTRIBUTE_UNIX_MODE) = 0 then // Windows attributes begin LinkProperty := TFileLinkProperty.Create; LinkProperty.IsLinkToDirectory := ((FindData.FileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) and ((FindData.FileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) <> 0); AttributesProperty := TNtfsFileAttributesProperty.Create(FindData.FileAttributes); end else // Unix attributes begin LinkProperty := TFileLinkProperty.Create; LinkProperty.IsLinkToDirectory := (((FindData.FileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) or ((FindData.FileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) <> 0)) and ((FindData.Reserved0 and S_IFMT) = S_IFLNK); if ((FindData.FileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) and ((FindData.Reserved0 and S_IFMT) <> S_IFDIR) and (not LinkProperty.IsLinkToDirectory) then FindData.Reserved0:= FindData.Reserved0 or S_IFDIR; AttributesProperty := TUnixFileAttributesProperty.Create(FindData.Reserved0); end; SizeProperty := TFileSizeProperty.Create(FindData.FileSize); SizeProperty.IsValid := (FindData.FileSize >= 0); ModificationTimeProperty := TFileModificationDateTimeProperty.Create(FindData.LastWriteTime); ModificationTimeProperty.IsValid := (FindData.LastWriteTime <= SysUtils.MaxDateTime); LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create(FindData.LastAccessTime); CreationTimeProperty := TFileCreationDateTimeProperty.Create(FindData.CreationTime); // Set name after assigning Attributes property, because it is used to get extension. Name := FindData.FileName; end; end; procedure TWfxPluginFileSource.RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); var AIndex: Integer; AProp: TFilePropertyType; AVariant: TFileVariantProperty; begin if WfxModule.ContentPlugin then begin PropertiesToSet:= PropertiesToSet * fpVariantAll; for AProp in PropertiesToSet do begin AIndex:= Ord(AProp) - Ord(fpVariant); if (AIndex >= 0) and (AIndex <= High(AVariantProperties)) then begin AVariant:= TFileVariantProperty.Create(AVariantProperties[AIndex]); AVariant.Value:= GetVariantFileProperty(AVariantProperties[AIndex], AFile, Self); AFile.Properties[AProp]:= AVariant; end; end; end; end; function TWfxPluginFileSource.GetOperationsTypes: TFileSourceOperationTypes; begin with WfxModule do begin Result := [fsoList, fsoCalcStatistics]; // supports by any plugin if Assigned(FsPutFile) or Assigned(FsPutFileW) then Result:= Result + [fsoCopyIn]; if Assigned(FsGetFile) or Assigned(FsGetFileW) then Result:= Result + [fsoCopyOut]; if Assigned(FsRenMovFile) or Assigned(FsRenMovFileW) then Result:= Result + [fsoCopy, fsoMove]; if Assigned(FsDeleteFile) or Assigned(FsDeleteFileW) then Result:= Result + [fsoDelete]; if Assigned(FsMkDir) or Assigned(FsMkDirW) then Result:= Result + [fsoCreateDirectory]; if Assigned(FsExecuteFile) or Assigned(FsExecuteFileW) then Result:= Result + [fsoExecute]; if Assigned(FsSetAttr) or Assigned(FsSetAttrW) or Assigned(FsExecuteFile) or Assigned(FsExecuteFileW) or Assigned(FsRenMovFile) or Assigned(FsRenMovFileW) then Result:= Result + [fsoSetFileProperty]; end; end; function TWfxPluginFileSource.GetProperties: TFileSourceProperties; begin Result := [fspUsesConnections, fspListOnMainThread]; with FWfxModule do begin if Assigned(FsLinksToLocalFiles) and FsLinksToLocalFiles() then Result:= Result + [fspLinksToLocalFiles]; if (BackgroundFlags = 0) or (BackgroundFlags and BG_ASK_USER <> 0) then Result:= Result + [fspCopyInOnMainThread, fspCopyOutOnMainThread] else begin if (BackgroundFlags and BG_UPLOAD = 0) then Result:= Result + [fspCopyInOnMainThread]; if (BackgroundFlags and BG_DOWNLOAD = 0) then Result:= Result + [fspCopyOutOnMainThread]; end; if Assigned(FsContentGetDefaultView) or Assigned(FsContentGetDefaultViewW) then Result := Result + [fspDefaultView]; end; end; function TWfxPluginFileSource.GetFileSystem: String; begin Result:= FPluginRootName; end; function TWfxPluginFileSource.GetSupportedFileProperties: TFilePropertiesTypes; begin Result := inherited GetSupportedFileProperties + [fpSize, fpAttributes, fpModificationTime, fpCreationTime, fpLastAccessTime, fpLink]; end; function TWfxPluginFileSource.GetRetrievableFileProperties: TFilePropertiesTypes; begin Result:= inherited GetRetrievableFileProperties; if WfxModule.ContentPlugin then Result += fpVariantAll; end; function TWfxPluginFileSource.GetCurrentAddress: String; begin Result:= 'wfx://' + FPluginRootName; end; function TWfxPluginFileSource.GetPluginNumber: LongInt; begin Result := FPluginNumber; end; function TWfxPluginFileSource.GetWfxModule: TWfxModule; begin Result := FWFXModule; end; procedure TWfxPluginFileSource.FillAndCount(Files: TFiles; CountDirs: Boolean; ExcludeRootDir: Boolean; out NewFiles: TFiles; out FilesCount: Int64; out FilesSize: Int64); procedure FillAndCountRec(const srcPath: String); var FindData: TWfxFindData; Handle: THandle; aFile: TFile; begin with FWfxModule do begin Handle := WfxFindFirst(srcPath, FindData); if Handle = wfxInvalidHandle then Exit; repeat if (FindData.FileName = '.') or (FindData.FileName = '..') then Continue; aFile:= TWfxPluginFileSource.CreateFile(srcPath, FindData); NewFiles.Add(aFile); if aFile.IsDirectory then begin if CountDirs then Inc(FilesCount); FillAndCountRec(srcPath + FindData.FileName + PathDelim); end else begin Inc(FilesSize, aFile.Size); Inc(FilesCount); end; until not WfxFindNext(Handle, FindData); FsFindClose(Handle); end; end; var I: Integer; aFile: TFile; begin FilesCount:= 0; FilesSize:= 0; if ExcludeRootDir then begin if Files.Count <> 1 then raise Exception.Create('Only a single directory can be set with ExcludeRootDir=True'); NewFiles := TFiles.Create(Files[0].FullPath); FillAndCountRec(Files[0].FullPath + DirectorySeparator); end else begin NewFiles := TFiles.Create(Files.Path); for I := 0 to Files.Count - 1 do begin aFile := Files[I]; NewFiles.Add(aFile.Clone); if aFile.AttributesProperty.IsDirectory and (not aFile.LinkProperty.IsLinkToDirectory) then begin if CountDirs then Inc(FilesCount); FillAndCountRec(aFile.Path + aFile.Name + DirectorySeparator); // recursive browse child dir end else begin Inc(FilesCount); Inc(FilesSize, aFile.Size); // in first level we know file size -> use it end; end; end; end; function TWfxPluginFileSource.FillSingleFile(const FullPath: String; out aFile: TFile): Boolean; var FilePath, ExpectedFileName: String; FindData: TWfxFindData; Handle: THandle; begin Result := False; aFile := nil; FilePath := ExtractFilePath(FullPath); ExpectedFileName := ExtractFileName(FullPath); with FWfxModule do begin Handle := WfxFindFirst(FilePath, FindData); if Handle = wfxInvalidHandle then Exit; repeat if (FindData.FileName = ExpectedFileName) then begin aFile := TWfxPluginFileSource.CreateFile(FilePath, FindData); Result := True; Break; end; until not WfxFindNext(Handle, FindData); FsFindClose(Handle); end; end; function TWfxPluginFileSource.WfxCopyMove(sSourceFile, sTargetFile: String; Flags: LongInt; RemoteInfo: PRemoteInfo; Internal, CopyMoveIn: Boolean): LongInt; var bMove, bOverWrite: Boolean; begin with FWfxModule do begin if Internal then begin bMove:= ((Flags and FS_COPYFLAGS_MOVE) <> 0); bOverWrite:= ((Flags and FS_COPYFLAGS_OVERWRITE) <> 0); Result:= WfxRenMovFile(sSourceFile, sTargetFile, bMove, bOverWrite, RemoteInfo); end else begin if CopyMoveIn then Result:= WfxPutFile(sSourceFile, sTargetFile, Flags) else Result:= WfxGetFile(sSourceFile, sTargetFile, Flags, RemoteInfo); end; end; end; constructor TWfxPluginFileSource.Create(const URI: TURI); var Index: Integer; begin // Check if there is a registered plugin for the name of the file system plugin. Index:= gWFXPlugins.FindFirstEnabledByName(URI.Host); if Index < 0 then begin raise EFileSourceException.Create('Cannot find Wfx module ' + URI.Host); end; Create(gWFXPlugins.FileName[Index], URI.Host); DCDebug('Found registered plugin ' + gWFXPlugins.FileName[Index] + ' for file system ' + URI.Host); end; function TWfxPluginFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginListOperation.Create(TargetFileSource, TargetPath); end; function TWfxPluginFileSource.CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var FileSource: IFileSource; begin FileSource := Self; Result := TWfxPluginCopyOperation.Create(FileSource, FileSource, SourceFiles, TargetPath); end; function TWfxPluginFileSource.CreateCopyInOperation( SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginCopyInOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TWfxPluginFileSource.CreateCopyOutOperation( TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var SourceFileSource: IFileSource; begin SourceFileSource := Self; Result := TWfxPluginCopyOutOperation.Create(SourceFileSource, TargetFileSource, SourceFiles, TargetPath); end; function TWfxPluginFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginMoveOperation.Create(TargetFileSource, SourceFiles, TargetPath); end; function TWfxPluginFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginDeleteOperation.Create(TargetFileSource, FilesToDelete); end; function TWfxPluginFileSource.CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginCreateDirectoryOperation.Create(TargetFileSource, BasePath, DirectoryPath); end; function TWfxPluginFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TWfxPluginExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb); end; function TWfxPluginFileSource.CreateSetFilePropertyOperation( var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginSetFilePropertyOperation.Create( TargetFileSource, theTargetFiles, theNewProperties); end; function TWfxPluginFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result := TWfxPluginCalcStatisticsOperation.Create(TargetFileSource, theFiles); end; function TWfxPluginFileSource.GetLocalName(var aFile: TFile): Boolean; var sFileName: String; begin Result:= False; sFileName:= aFile.FullPath; if FWfxModule.WfxGetLocalName(sFileName) then begin aFile.FullPath:= sFileName; Result:= True; end; end; function TWfxPluginFileSource.CreateDirectory(const Path: String): Boolean; begin Result:= WfxModule.WfxMkDir(ExtractFilePath(Path), Path) = WFX_SUCCESS; if Result then begin if (log_vfs_op in gLogOptions) and (log_success in gLogOptions) then logWrite(Format(rsMsgLogSuccess + rsMsgLogMkDir, [Path]), lmtSuccess) end else begin if (log_vfs_op in gLogOptions) and (log_errors in gLogOptions) then logWrite(Format(rsMsgLogError + rsMsgLogMkDir, [Path]), lmtError); end; end; function TWfxPluginFileSource.GetDefaultView(out DefaultView: TFileSourceFields): Boolean; begin Result:= FWFXModule.WfxContentGetDefaultView(DefaultView); end; class function TWfxPluginFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= Pos('wfx://', Path) = 1; end; class function TWfxPluginFileSource.CreateByRootName(aRootName: String): IWfxPluginFileSource; var Index: Integer; begin Result:= nil; if gWFXPlugins.Count = 0 then Exit; // Check if there is a registered plugin for the name of the file system plugin. Index:= gWFXPlugins.FindFirstEnabledByName(aRootName); if Index >= 0 then begin Result:= TWfxPluginFileSource.Create(gWFXPlugins.FileName[Index], aRootName); DCDebug('Found registered plugin ' + gWFXPlugins.FileName[Index] + ' for file system ' + aRootName); end; end; procedure TWfxPluginFileSource.AddToConnectionQueue(Operation: TFileSourceOperation); begin WfxOperationsQueueLock.Acquire; try if WfxOperationsQueue.IndexOf(Operation) < 0 then WfxOperationsQueue.Add(Operation); finally WfxOperationsQueueLock.Release; end; end; procedure TWfxPluginFileSource.RemoveFromConnectionQueue(Operation: TFileSourceOperation); begin WfxOperationsQueueLock.Acquire; try WfxOperationsQueue.Remove(Operation); finally WfxOperationsQueueLock.Release; end; end; procedure TWfxPluginFileSource.AddConnection(Connection: TFileSourceConnection); begin WfxConnectionsLock.Acquire; try if WfxConnections.IndexOf(Connection) < 0 then WfxConnections.Add(Connection); finally WfxConnectionsLock.Release; end; end; procedure TWfxPluginFileSource.RemoveConnection(Connection: TFileSourceConnection); begin WfxConnectionsLock.Acquire; try WfxConnections.Remove(Connection); finally WfxConnectionsLock.Release; end; end; function TWfxPluginFileSource.GetConnection(Operation: TFileSourceOperation): TFileSourceConnection; begin Result := nil; case Operation.ID of fsoCopy, fsoMove: Result := WfxConnections[connCopyMove] as TFileSourceConnection; fsoCopyIn: Result := WfxConnections[connCopyIn] as TFileSourceConnection; fsoCopyOut: Result := WfxConnections[connCopyOut] as TFileSourceConnection; fsoDelete: Result := WfxConnections[connDelete] as TFileSourceConnection; else begin Result := CreateConnection; if Assigned(Result) then AddConnection(Result); end; end; if Assigned(Result) then Result := TryAcquireConnection(Result, Operation); // No available connection - wait. if not Assigned(Result) then AddToConnectionQueue(Operation) else // Connection acquired. // The operation may have been waiting in the queue // for the connection, so remove it from the queue. RemoveFromConnectionQueue(Operation); end; procedure TWfxPluginFileSource.RemoveOperationFromQueue(Operation: TFileSourceOperation); begin RemoveFromConnectionQueue(Operation); end; function TWfxPluginFileSource.CreateConnection: TFileSourceConnection; begin Result := TWfxPluginFileSourceConnection.Create(FWfxModule); end; procedure TWfxPluginFileSource.CreateConnections; begin WfxConnectionsLock.Acquire; try if WfxConnections.Count = 0 then begin // Reserve some connections (only once). WfxConnections.Add(CreateConnection); // connCopyIn WfxConnections.Add(CreateConnection); // connCopyOut WfxConnections.Add(CreateConnection); // connDelete WfxConnections.Add(CreateConnection); // connCopyMove end; finally WfxConnectionsLock.Release; end; end; function TWfxPluginFileSource.FindConnectionByOperation(operation: TFileSourceOperation): TFileSourceConnection; var i: Integer; connection: TFileSourceConnection; begin Result := nil; WfxConnectionsLock.Acquire; try for i := 0 to WfxConnections.Count - 1 do begin connection := WfxConnections[i] as TFileSourceConnection; if connection.AssignedOperation = operation then Exit(connection); end; finally WfxConnectionsLock.Release; end; end; procedure TWfxPluginFileSource.OperationFinished(Operation: TFileSourceOperation); var allowedIDs: TFileSourceOperationTypes = []; connection: TFileSourceConnection; begin connection := FindConnectionByOperation(Operation); if Assigned(connection) then begin connection.Release; // unassign operation WfxConnectionsLock.Acquire; try // If there are operations waiting, take the first one and notify // that a connection is available. // Only check operation types for which there are reserved connections. if Operation.ID in [fsoCopyIn, fsoCopyOut, fsoDelete, fsoCopy, fsoMove] then begin Include(allowedIDs, Operation.ID); NotifyNextWaitingOperation(allowedIDs); end else begin WfxConnections.Remove(connection); end; finally WfxConnectionsLock.Release; end; end; end; procedure TWfxPluginFileSource.NotifyNextWaitingOperation(allowedOps: TFileSourceOperationTypes); var i: Integer; operation: TFileSourceOperation; begin WfxOperationsQueueLock.Acquire; try for i := 0 to WfxOperationsQueue.Count - 1 do begin operation := WfxOperationsQueue.Items[i] as TFileSourceOperation; if (operation.State = fsosWaitingForConnection) and (operation.ID in allowedOps) then begin operation.ConnectionAvailableNotify; Exit; end; end; finally WfxOperationsQueueLock.Release; end; end; { TWfxPluginFileSourceConnection } constructor TWfxPluginFileSourceConnection.Create(aWfxModule: TWfxModule); begin FWfxModule := aWfxModule; inherited Create; end; { TCallbackDataClass } constructor TCallbackDataClass.Create(aFileSource: TWfxPluginFileSource); begin inherited Create; FileSource:= aFileSource; UpdateProgressFunction:= nil; end; initialization WfxOperationList:= TStringList.Create; WfxConnections := TObjectList.Create(True); // True = destroy objects when destroying list WfxConnectionsLock := TCriticalSection.Create; WfxOperationsQueue := TObjectList.Create(False); // False = don't destroy operations (only store references) WfxOperationsQueueLock := TCriticalSection.Create; RegisterVirtualFileSource('WfxPlugin', TWfxPluginFileSource, False); finalization FreeAndNil(WfxOperationList); FreeAndNil(WfxConnections); FreeAndNil(WfxConnectionsLock); FreeAndNil(WfxOperationsQueue); FreeAndNil(WfxOperationsQueueLock); end. ���������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxpluginlistoperation.pas������������������������������0000644�0001750�0000144�00000006176�14743153644�025507� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceListOperation, uWfxPluginFileSource, uFileSource; type { TWfxPluginListOperation } TWfxPluginListOperation = class(TFileSourceListOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FCallbackDataClass: TCallbackDataClass; FCurrentPath: String; protected function UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; public constructor Create(aFileSource: IFileSource; aPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses DCFileAttributes, DCStrUtils, uFile, uFileSourceOperation, WfxPlugin, uWfxModule, uLog, uLng; function TWfxPluginListOperation.UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; begin if State = fsosStopping then // Cancel operation Exit(1); logWrite(rsMsgLoadingFileList + IntToStr(PercentDone) + '%', lmtInfo, False, False); if CheckOperationStateSafe then Result := 0 else begin Result := 1; end; end; constructor TWfxPluginListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FWfxPluginFileSource := aFileSource as IWfxPluginFileSource; with FWfxPluginFileSource do FCallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNumber]); FCurrentPath:= ExcludeBackPathDelimiter(aPath); inherited Create(aFileSource, aPath); end; destructor TWfxPluginListOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginListOperation.Initialize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(FCurrentPath, FS_STATUS_START, FS_STATUS_OP_LIST); FCallbackDataClass.UpdateProgressFunction:= @UpdateProgress; UpdateProgressFunction:= @UpdateProgress; end; end; procedure TWfxPluginListOperation.MainExecute; var aFile: TFile; Handle: THandle; FindData : TWfxFindData; HaveUpDir: Boolean = False; begin with FWfxPluginFileSource.WFXModule do try FFiles.Clear; Handle := WfxFindFirst(FCurrentPath, FindData); if Handle <> wfxInvalidHandle then try repeat CheckOperationState; if (FindData.FileName = '.') then Continue; if (FindData.FileName = '..') then HaveUpDir:= True; aFile := TWfxPluginFileSource.CreateFile(Path, FindData); FFiles.Add(aFile); until (not WfxFindNext(Handle, FindData)); finally FsFindClose(Handle); end; finally if not HaveUpDir then begin aFile := TWfxPluginFileSource.CreateFile(Path); aFile.Name := '..'; aFile.Attributes := GENERIC_ATTRIBUTE_FOLDER; FFiles.Insert(aFile, 0); end; end; // with end; procedure TWfxPluginListOperation.Finalize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(FCurrentPath, FS_STATUS_END, FS_STATUS_OP_LIST); FCallbackDataClass.UpdateProgressFunction:= nil; UpdateProgressFunction:= nil; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxpluginmoveoperation.pas������������������������������0000644�0001750�0000144�00000012014�14743153644�025466� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginMoveOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceMoveOperation, uFileSource, uFileSourceOperation, uFileSourceOperationOptions, uFileSourceOperationOptionsUI, uFile, uWfxPluginFileSource, uWfxPluginUtil; type { TWfxPluginMoveOperation } TWfxPluginMoveOperation = class(TFileSourceMoveOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FOperationHelper: TWfxPluginOperationHelper; FCallbackDataClass: TCallbackDataClass; FSourceFilesTree: TFileTree; // source files including all files/dirs in subdirectories FStatistics: TFileSourceMoveOperationStatistics; // local copy of statistics // Options FInfoOperation: LongInt; protected function UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; public constructor Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; class function GetOptionsUIClass: TFileSourceOperationOptionsUIClass; override; end; implementation uses fWfxPluginCopyMoveOperationOptions, WfxPlugin; // -- TWfxPluginMoveOperation --------------------------------------------- function TWfxPluginMoveOperation.UpdateProgress(SourceName, TargetName: PAnsiChar; PercentDone: Integer): Integer; var iTemp: Int64; begin Result := 0; //DCDebug('SourceName=', SourceName, #32, 'TargetName=', TargetName, #32, 'PercentDone=', IntToStr(PercentDone)); if State = fsosStopping then // Cancel operation Exit(1); with FStatistics do begin if Assigned(SourceName) then begin FStatistics.CurrentFileFrom:= SourceName; end; if Assigned(TargetName) then begin FStatistics.CurrentFileTo:= TargetName; end; iTemp:= CurrentFileTotalBytes * PercentDone div 100; DoneBytes := DoneBytes + (iTemp - CurrentFileDoneBytes); CurrentFileDoneBytes:= iTemp; UpdateStatistics(FStatistics); end; if not AppProcessMessages(True) then Exit(1); end; constructor TWfxPluginMoveOperation.Create(aFileSource: IFileSource; var theSourceFiles: TFiles; aTargetPath: String); begin FWfxPluginFileSource:= aFileSource as IWfxPluginFileSource; with FWfxPluginFileSource do FCallbackDataClass:= TCallbackDataClass(WfxOperationList.Objects[PluginNumber]); if theSourceFiles.Count > 1 then FInfoOperation:= FS_STATUS_OP_RENMOV_MULTI else FInfoOperation:= FS_STATUS_OP_RENMOV_SINGLE; inherited Create(aFileSource, theSourceFiles, aTargetPath); end; destructor TWfxPluginMoveOperation.Destroy; begin inherited Destroy; end; procedure TWfxPluginMoveOperation.Initialize; var TreeBuilder: TWfxTreeBuilder; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(SourceFiles.Path, FS_STATUS_START, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= @UpdateProgress; UpdateProgressFunction:= @UpdateProgress; // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; TreeBuilder := TWfxTreeBuilder.Create(@AskQuestion, @CheckOperationState); try TreeBuilder.WfxModule:= WfxModule; TreeBuilder.SymLinkOption:= fsooslDontFollow; TreeBuilder.BuildFromFiles(SourceFiles); FSourceFilesTree := TreeBuilder.ReleaseTree; FStatistics.TotalFiles := TreeBuilder.FilesCount; FStatistics.TotalBytes := TreeBuilder.FilesSize; finally FreeAndNil(TreeBuilder); end; end; if Assigned(FOperationHelper) then FreeAndNil(FOperationHelper); FOperationHelper := TWfxPluginOperationHelper.Create( FWfxPluginFileSource, @AskQuestion, @RaiseAbortOperation, @CheckOperationState, @UpdateStatistics, @ShowCompareFilesUI, @ShowCompareFilesUIByFileObject, Thread, wpohmMove, TargetPath); FOperationHelper.RenameMask := RenameMask; FOperationHelper.FileExistsOption := FileExistsOption; FOperationHelper.Initialize; end; procedure TWfxPluginMoveOperation.MainExecute; begin FOperationHelper.ProcessTree(FSourceFilesTree, FStatistics); end; procedure TWfxPluginMoveOperation.Finalize; begin with FWfxPluginFileSource do begin WfxModule.WfxStatusInfo(SourceFiles.Path, FS_STATUS_END, FInfoOperation); FCallbackDataClass.UpdateProgressFunction:= nil; UpdateProgressFunction:= nil; end; FileExistsOption := FOperationHelper.FileExistsOption; FOperationHelper.Free; end; class function TWfxPluginMoveOperation.GetOptionsUIClass: TFileSourceOperationOptionsUIClass; begin Result := TWfxPluginMoveOperationOptionsUI; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxpluginsetfilepropertyoperation.pas�������������������0000644�0001750�0000144�00000015525�14743153644�027772� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginSetFilePropertyOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSourceSetFilePropertyOperation, uFileSource, uFileSourceOperationOptions, uFile, uFileProperty, uWfxPluginFileSource; type TWfxPluginSetFilePropertyOperation = class(TFileSourceSetFilePropertyOperation) private FWfxPluginFileSource: IWfxPluginFileSource; FFullFilesTree: TFiles; // source files including all files/dirs in subdirectories FStatistics: TFileSourceSetFilePropertyOperationStatistics; // local copy of statistics // Options. FSymLinkOption: TFileSourceOperationOptionSymLink; protected function SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; override; public constructor Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); override; destructor Destroy; override; procedure Initialize; override; procedure MainExecute; override; procedure Finalize; override; end; implementation uses DCFileAttributes, Forms, DCBasicTypes, DCStrUtils, WfxPlugin, uWfxPluginUtil, DCDateTimeUtils; constructor TWfxPluginSetFilePropertyOperation.Create(aTargetFileSource: IFileSource; var theTargetFiles: TFiles; var theNewProperties: TFileProperties); begin FSymLinkOption := fsooslNone; FFullFilesTree := nil; FWfxPluginFileSource:= aTargetFileSource as IWfxPluginFileSource; inherited Create(aTargetFileSource, theTargetFiles, theNewProperties); // Assign after calling inherited constructor. FSupportedProperties := [fpName, fpAttributes, fpModificationTime, fpCreationTime, fpLastAccessTime]; end; destructor TWfxPluginSetFilePropertyOperation.Destroy; begin inherited Destroy; if Recursive then begin if Assigned(FFullFilesTree) then FreeAndNil(FFullFilesTree); end; end; procedure TWfxPluginSetFilePropertyOperation.Initialize; var TotalBytes: Int64; begin with FWfxPluginFileSource do WfxModule.WfxStatusInfo(TargetFiles.Path, FS_STATUS_START, FS_STATUS_OP_ATTRIB); // Get initialized statistics; then we change only what is needed. FStatistics := RetrieveStatistics; if not Recursive then begin FFullFilesTree := TargetFiles; FStatistics.TotalFiles:= FFullFilesTree.Count; end else begin FWfxPluginFileSource.FillAndCount(TargetFiles, True, False, FFullFilesTree, FStatistics.TotalFiles, TotalBytes); // gets full list of files (recursive) end; end; procedure TWfxPluginSetFilePropertyOperation.MainExecute; var aFile: TFile; aTemplateFile: TFile; CurrentFileIndex: Integer; begin for CurrentFileIndex := 0 to FFullFilesTree.Count - 1 do begin aFile := FFullFilesTree[CurrentFileIndex]; FStatistics.CurrentFile := aFile.FullPath; UpdateStatistics(FStatistics); if Assigned(TemplateFiles) and (CurrentFileIndex < TemplateFiles.Count) then aTemplateFile := TemplateFiles[CurrentFileIndex] else aTemplateFile := nil; SetProperties(CurrentFileIndex, aFile, aTemplateFile); with FStatistics do begin DoneFiles := DoneFiles + 1; UpdateStatistics(FStatistics); end; CheckOperationState; end; end; procedure TWfxPluginSetFilePropertyOperation.Finalize; begin with FWfxPluginFileSource do WfxModule.WfxStatusInfo(TargetFiles.Path, FS_STATUS_END, FS_STATUS_OP_ATTRIB); end; function TWfxPluginSetFilePropertyOperation.SetNewProperty(aFile: TFile; aTemplateProperty: TFileProperty): TSetFilePropertyResult; var AFileName: String; ftTime: TWfxFileTime; NewAttributes: TFileAttrs; begin Result := sfprSuccess; case aTemplateProperty.GetID of fpName: if (aTemplateProperty as TFileNameProperty).Value <> aFile.Name then begin if not WfxRenameFile(FWfxPluginFileSource, aFile, (aTemplateProperty as TFileNameProperty).Value) then Result := sfprError; end else Result := sfprSkipped; fpAttributes: if (aTemplateProperty as TFileAttributesProperty).Value <> (aFile.Properties[fpAttributes] as TFileAttributesProperty).Value then begin NewAttributes := (aTemplateProperty as TFileAttributesProperty).Value; AFileName := aFile.FullPath; with FWfxPluginFileSource.WfxModule do if aTemplateProperty is TNtfsFileAttributesProperty then begin if not WfxSetAttr(AFileName, NewAttributes) then Result := sfprError; end else if aTemplateProperty is TUnixFileAttributesProperty then begin if WfxExecuteFile(Application.MainForm.Tag, AFileName, 'chmod' + #32 + DecToOct(NewAttributes AND (not S_IFMT))) <> FS_EXEC_OK then Result := sfprError; end else raise Exception.Create('Unsupported file attributes type'); end else Result := sfprSkipped; fpModificationTime: if (aTemplateProperty as TFileModificationDateTimeProperty).Value <> (aFile.Properties[fpModificationTime] as TFileModificationDateTimeProperty).Value then begin ftTime := DateTimeToWfxFileTime((aTemplateProperty as TFileModificationDateTimeProperty).Value); with FWfxPluginFileSource.WfxModule do if not WfxSetTime(aFile.FullPath, nil, nil, @ftTime) then Result := sfprError; end else Result := sfprSkipped; fpCreationTime: if (aTemplateProperty as TFileCreationDateTimeProperty).Value <> (aFile.Properties[fpCreationTime] as TFileCreationDateTimeProperty).Value then begin ftTime := DateTimeToWfxFileTime((aTemplateProperty as TFileCreationDateTimeProperty).Value); with FWfxPluginFileSource.WfxModule do if not WfxSetTime(aFile.FullPath, @ftTime, nil, nil) then Result := sfprError; end else Result := sfprSkipped; fpLastAccessTime: if (aTemplateProperty as TFileLastAccessDateTimeProperty).Value <> (aFile.Properties[fpLastAccessTime] as TFileLastAccessDateTimeProperty).Value then begin ftTime := DateTimeToWfxFileTime((aTemplateProperty as TFileLastAccessDateTimeProperty).Value); with FWfxPluginFileSource.WfxModule do if not WfxSetTime(aFile.FullPath, nil, @ftTime, nil) then Result := sfprError; end else Result := sfprSkipped; else raise Exception.Create('Trying to set unsupported property'); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/wfxplugin/uwfxpluginutil.pas���������������������������������������0000644�0001750�0000144�00000051670�14743153644�023567� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWfxPluginUtil; {$mode objfpc}{$H+} {$if FPC_FULLVERSION >= 30300} {$modeswitch arraytodynarray} {$endif} interface uses Classes, SysUtils, LCLProc, DCOSUtils, uLog, uGlobs, WfxPlugin, uWfxModule, uFile, uFileSource, uFileSourceOperation, uFileSourceTreeBuilder, uFileSourceOperationOptions, uFileSourceOperationUI, uFileSourceCopyOperation, uWfxPluginFileSource; type TWfxPluginOperationHelperMode = (wpohmCopy, wpohmCopyIn, wpohmCopyOut, wpohmMove); TUpdateStatisticsFunction = procedure(var NewStatistics: TFileSourceCopyOperationStatistics) of object; { TWfxTreeBuilder } TWfxTreeBuilder = class(TFileSourceTreeBuilder) private FWfxModule: TWfxModule; protected procedure AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); override; procedure AddFilesInDirectory(srcPath: String; CurrentNode: TFileTreeNode); override; public property WfxModule: TWfxModule read FWfxModule write FWfxModule; end; { TWfxPluginOperationHelper } TWfxPluginOperationHelper = class private FRootDir: TFile; FWfxPluginFileSource: IWfxPluginFileSource; FOperationThread: TThread; FMode: TWfxPluginOperationHelperMode; FRootTargetPath: String; FRenameMask: String; FRenameNameMask, FRenameExtMask: String; FLogCaption: String; FRenamingFiles, FRenamingRootDir, FInternal: Boolean; FStatistics: PFileSourceCopyOperationStatistics; FCopyAttributesOptions: TCopyAttributesOptions; FFileExistsOption: TFileSourceOperationOptionFileExists; FCurrentFile: TFile; FCurrentTargetFile: TFile; FCurrentTargetFilePath: String; AskQuestion: TAskQuestionFunction; AbortOperation: TAbortOperationFunction; CheckOperationState: TCheckOperationStateFunction; UpdateStatistics: TUpdateStatisticsFunction; ShowCompareFilesUI: TShowCompareFilesUIFunction; ShowCompareFilesUIByFileObject: TShowCompareFilesUIByFileObjectFunction; procedure ShowError(sMessage: String); procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); function ProcessNode(aFileTreeNode: TFileTreeNode; CurrentTargetPath: String): Integer; function ProcessDirectory(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Integer; function ProcessLink(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Integer; function ProcessFile(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Integer; procedure QuestionActionHandler(Action: TFileSourceOperationUIAction); function FileExists(aFile: TFile; AbsoluteTargetFileName: String; AllowResume: Boolean): TFileSourceOperationOptionFileExists; procedure CopyProperties(SourceFile: TFile; const TargetFileName: String); procedure CountStatistics(aNode: TFileTreeNode); public constructor Create(FileSource: IFileSource; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; ShowCompareFilesUIFunction: TShowCompareFilesUIFunction; ShowCompareFilesUIByFileObjectFunction: TShowCompareFilesUIByFileObjectFunction; OperationThread: TThread; Mode: TWfxPluginOperationHelperMode; TargetPath: String ); destructor Destroy; override; procedure Initialize; procedure ProcessTree(aFileTree: TFileTree; var Statistics: TFileSourceCopyOperationStatistics); property FileExistsOption: TFileSourceOperationOptionFileExists read FFileExistsOption write FFileExistsOption; property CopyAttributesOptions: TCopyAttributesOptions read FCopyAttributesOptions write FCopyAttributesOptions; property RenameMask: String read FRenameMask write FRenameMask; end; function WfxRenameFile(aFileSource: IWfxPluginFileSource; const aFile: TFile; const NewFileName: String): Boolean; function WfxFileTimeToDateTime(FileTime : TWfxFileTime) : TDateTime; inline; function DateTimeToWfxFileTime(DateTime : TDateTime) : TWfxFileTime; inline; function RepairPluginName(const AName: String): String; implementation uses uDCUtils, uFileProcs, StrUtils, DCStrUtils, uLng, uFileSystemUtil, uFileProperty, DCDateTimeUtils, DCBasicTypes, DCFileAttributes; function WfxRenameFile(aFileSource: IWfxPluginFileSource; const aFile: TFile; const NewFileName: String): Boolean; var ASize: Int64; RemoteInfo: TRemoteInfo; begin with aFileSource do begin with RemoteInfo do begin ASize := aFile.Size; Attr := LongInt(aFile.Attributes); SizeLow := LongInt(Int64Rec(ASize).Lo); SizeHigh := LongInt(Int64Rec(ASize).Hi); LastWriteTime := DateTimeToWfxFileTime(aFile.ModificationTime); end; Result := (WfxCopyMove(aFile.Path + aFile.Name, aFile.Path + NewFileName, FS_COPYFLAGS_MOVE, @RemoteInfo, True, True) = FS_FILE_OK); end; end; function WfxFileTimeToDateTime(FileTime: TWfxFileTime): TDateTime; const NULL_DATE_TIME = TDateTime(2958466.0); begin if (FileTime.dwLowDateTime = $FFFFFFFE) and (FileTime.dwHighDateTime = $FFFFFFFF) then Result:= NULL_DATE_TIME else if (TWinFileTime(FileTime) = 0) then Result:= NULL_DATE_TIME else Result:= WinFileTimeToDateTime(TWinFileTime(FileTime)); end; function DateTimeToWfxFileTime(DateTime: TDateTime): TWfxFileTime; begin if (DateTime <= SysUtils.MaxDateTime) then Result:= TWfxFileTime(DateTimeToWinFileTime(DateTime)) else begin Result.dwLowDateTime:= $FFFFFFFE; Result.dwHighDateTime:= $FFFFFFFF; end; end; function RepairPluginName(const AName: String): String; var Index: Integer; DenySym: set of AnsiChar = ['\', '/', ':']; begin Result:= AName; for Index:= 1 to Length(Result) do begin if Result[Index] in DenySym then begin Result[Index]:= '_'; end; end; end; { TWfxTreeBuilder } procedure TWfxTreeBuilder.AddLinkTarget(aFile: TFile; CurrentNode: TFileTreeNode); begin // Add as normal file/directory if aFile.AttributesProperty is TNtfsFileAttributesProperty then aFile.Attributes:= aFile.Attributes and (not FILE_ATTRIBUTE_REPARSE_POINT) else aFile.Attributes:= aFile.Attributes and (not S_IFLNK); if not aFile.IsLinkToDirectory then AddFile(aFile, CurrentNode) else begin if aFile.AttributesProperty is TNtfsFileAttributesProperty then aFile.Attributes:= aFile.Attributes or FILE_ATTRIBUTE_DIRECTORY else begin aFile.Attributes:= aFile.Attributes or S_IFDIR; end; AddDirectory(aFile, CurrentNode); end; end; procedure TWfxTreeBuilder.AddFilesInDirectory(srcPath: String; CurrentNode: TFileTreeNode); var FindData: TWfxFindData; Handle: THandle; aFile: TFile; begin with FWfxModule do begin Handle := WfxFindFirst(srcPath, FindData); if Handle = wfxInvalidHandle then Exit; repeat if (FindData.FileName = '.') or (FindData.FileName = '..') then Continue; aFile:= TWfxPluginFileSource.CreateFile(srcPath, FindData); AddItem(aFile, CurrentNode); until not WfxFindNext(Handle, FindData); FsFindClose(Handle); end; end; { TWfxPluginOperationHelper } procedure TWfxPluginOperationHelper.ShowError(sMessage: String); begin if gSkipFileOpError then begin if log_errors in gLogOptions then logWrite(FOperationThread, sMessage, lmtError, True); end else begin if AskQuestion(sMessage, '', [fsourSkip, fsourAbort], fsourSkip, fsourAbort) = fsourAbort then begin AbortOperation; end; end; end; procedure TWfxPluginOperationHelper.LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType); begin case logMsgType of lmtError: if not (log_errors in gLogOptions) then Exit; lmtInfo: if not (log_info in gLogOptions) then Exit; lmtSuccess: if not (log_success in gLogOptions) then Exit; end; if logOptions <= gLogOptions then begin logWrite(FOperationThread, sMessage, logMsgType); end; end; function TWfxPluginOperationHelper.ProcessNode(aFileTreeNode: TFileTreeNode; CurrentTargetPath: String): Integer; var aFile: TFile; TargetName: String; ProcessedOk: Integer; CurrentFileIndex: Integer; CurrentSubNode: TFileTreeNode; begin Result := FS_FILE_OK; for CurrentFileIndex := 0 to aFileTreeNode.SubNodesCount - 1 do begin CurrentSubNode := aFileTreeNode.SubNodes[CurrentFileIndex]; aFile := CurrentSubNode.TheFile; if FRenamingRootDir and (aFile = FRootDir) then TargetName := FRenameMask else if FRenamingFiles then TargetName := ApplyRenameMask(aFile, FRenameNameMask, FRenameExtMask) else TargetName := aFile.Name; if FMode <> wpohmCopyOut then TargetName := CurrentTargetPath + TargetName else begin TargetName := CurrentTargetPath + ReplaceInvalidChars(TargetName); end; with FStatistics^ do begin CurrentFileFrom := aFile.FullPath; CurrentFileTo := TargetName; CurrentFileTotalBytes := aFile.Size; CurrentFileDoneBytes := 0; end; UpdateStatistics(FStatistics^); if aFile.IsLink then ProcessedOk := ProcessLink(CurrentSubNode, TargetName) else if aFile.IsDirectory then ProcessedOk := ProcessDirectory(CurrentSubNode, TargetName) else ProcessedOk := ProcessFile(CurrentSubNode, TargetName); if ProcessedOk <> FS_FILE_OK then Result := ProcessedOk; if ProcessedOk = FS_FILE_USERABORT then AbortOperation(); if ProcessedOk = FS_FILE_OK then CopyProperties(aFile, TargetName); if ProcessedOk = FS_FILE_OK then begin LogMessage(Format(rsMsgLogSuccess+FLogCaption, [aFile.FullPath + ' -> ' + TargetName]), [log_vfs_op], lmtSuccess); end else begin ShowError(Format(rsMsgLogError + FLogCaption, [aFile.FullPath + ' -> ' + TargetName + ' - ' + GetErrorMsg(ProcessedOk)])); LogMessage(Format(rsMsgLogError+FLogCaption, [aFile.FullPath + ' -> ' + TargetName]), [log_vfs_op], lmtError); end; CheckOperationState; end; end; function TWfxPluginOperationHelper.ProcessDirectory(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Integer; begin // Create target directory if (FMode <> wpohmCopyOut) then Result:= FWfxPluginFileSource.WfxModule.WfxMkDir('', AbsoluteTargetFileName) else begin if mbForceDirectory(AbsoluteTargetFileName) then Result:= FS_FILE_OK else Result:= WFX_ERROR; end; if Result = FS_FILE_OK then begin // Copy/Move all files inside. Result := ProcessNode(aNode, IncludeTrailingPathDelimiter(AbsoluteTargetFileName)); end else begin // Error - all files inside not copied/moved. ShowError(rsMsgLogError + Format(rsMsgErrForceDir, [AbsoluteTargetFileName])); CountStatistics(aNode); end; if (Result = FS_FILE_OK) and (FMode = wpohmMove) then FWfxPluginFileSource.WfxModule.WfxRemoveDir(aNode.TheFile.FullPath); end; function TWfxPluginOperationHelper.ProcessLink(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Integer; var aSubNode: TFileTreeNode; begin if (FMode = wpohmMove) then Result := ProcessFile(aNode, AbsoluteTargetFileName) else if aNode.SubNodesCount > 0 then begin aSubNode := aNode.SubNodes[0]; if aSubNode.TheFile.AttributesProperty.IsDirectory then Result := ProcessDirectory(aSubNode, AbsoluteTargetFileName) else Result := ProcessFile(aSubNode, AbsoluteTargetFileName); end; end; function TWfxPluginOperationHelper.ProcessFile(aNode: TFileTreeNode; AbsoluteTargetFileName: String): Integer; var iFlags: Integer = 0; RemoteInfo: TRemoteInfo; iTemp: TInt64Rec; bCopyMoveIn: Boolean; aFile: TFile; OldDoneBytes: Int64; // for if there was an error begin // If there will be an error the DoneBytes value // will be inconsistent, so remember it here. OldDoneBytes := FStatistics^.DoneBytes; aFile:= aNode.TheFile; with FWfxPluginFileSource do begin with RemoteInfo do begin iTemp.Value := aFile.Size; SizeLow := LongInt(iTemp.Low); SizeHigh := LongInt(iTemp.High); LastWriteTime := DateTimeToWfxFileTime(aFile.ModificationTime); Attr := LongInt(aFile.Attributes); end; if (FMode = wpohmMove) then iFlags:= iFlags + FS_COPYFLAGS_MOVE; if FFileExistsOption = fsoofeOverwrite then iFlags:= iFlags + FS_COPYFLAGS_OVERWRITE; bCopyMoveIn:= (FMode = wpohmCopyIn); Result := WfxCopyMove(aFile.Path + aFile.Name, AbsoluteTargetFileName, iFlags, @RemoteInfo, FInternal, bCopyMoveIn); case Result of FS_FILE_EXISTS, // The file already exists, and resume isn't supported FS_FILE_EXISTSRESUMEALLOWED: // The file already exists, and resume is supported begin case FileExists(aFile, AbsoluteTargetFileName, Result = FS_FILE_EXISTSRESUMEALLOWED) of fsoofeSkip: Exit(FS_FILE_OK); fsoofeOverwrite: iFlags:= iFlags + FS_COPYFLAGS_OVERWRITE; fsoofeResume: iFlags:= iFlags + FS_COPYFLAGS_RESUME; else raise Exception.Create('Invalid file exists option'); end; Result := WfxCopyMove(aFile.Path + aFile.Name, AbsoluteTargetFileName, iFlags, @RemoteInfo, FInternal, bCopyMoveIn); end; end; end; with FStatistics^ do begin if Result = FS_FILE_OK then DoneFiles := DoneFiles + 1; DoneBytes := OldDoneBytes + aFile.Size; UpdateStatistics(FStatistics^); end; end; procedure TWfxPluginOperationHelper.QuestionActionHandler( Action: TFileSourceOperationUIAction); begin if Action = fsouaCompare then begin if Assigned(FCurrentTargetFile) then ShowCompareFilesUIByFileObject(FCurrentFile, FCurrentTargetFile) else ShowCompareFilesUI(FCurrentFile, FCurrentTargetFilePath); end; end; function FileExistsMessage(TargetFile: TFile; SourceFile: TFile): String; begin Result:= rsMsgFileExistsOverwrite + LineEnding + TargetFile.FullPath + LineEnding + Format(rsMsgFileExistsFileInfo, [IntToStrTS(TargetFile.Size), DateTimeToStr(TargetFile.ModificationTime)]) + LineEnding; Result:= Result + LineEnding + rsMsgFileExistsWithFile + LineEnding + SourceFile.FullPath + LineEnding + Format(rsMsgFileExistsFileInfo, [IntToStrTS(SourceFile.Size), DateTimeToStr(SourceFile.ModificationTime)]); end; function TWfxPluginOperationHelper.FileExists(aFile: TFile; AbsoluteTargetFileName: String; AllowResume: Boolean ): TFileSourceOperationOptionFileExists; const Responses: array[0..6] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourResume, fsourOverwriteAll, fsourSkipAll, fsouaCompare, fsourCancel); ResponsesNoResume: array[0..5] of TFileSourceOperationUIResponse = (fsourOverwrite, fsourSkip, fsourOverwriteAll, fsourSkipAll, fsouaCompare, fsourCancel); var Message: String; PossibleResponses: TFileSourceOperationUIResponses; begin case FFileExistsOption of fsoofeNone: try FCurrentTargetFile := nil; case AllowResume of True : PossibleResponses := Responses; False: PossibleResponses := ResponsesNoResume; end; if FMode = wpohmCopyOut then Message := uFileSystemUtil.FileExistsMessage(AbsoluteTargetFileName, aFile.FullPath, aFile.Size, aFile.ModificationTime) else if FWfxPluginFileSource.FillSingleFile(AbsoluteTargetFileName, FCurrentTargetFile) then Message := FileExistsMessage(FCurrentTargetFile, aFile) else Message := Format(rsMsgFileExistsRwrt, [AbsoluteTargetFileName]); FCurrentFile := aFile; FCurrentTargetFilePath := AbsoluteTargetFileName; case AskQuestion(Message, '', PossibleResponses, fsourOverwrite, fsourSkip, @QuestionActionHandler) of fsourOverwrite: Result := fsoofeOverwrite; fsourSkip: Result := fsoofeSkip; fsourResume: begin // FFileExistsOption := fsoofeResume; - for ResumeAll Result := fsoofeResume; end; fsourOverwriteAll: begin FFileExistsOption := fsoofeOverwrite; Result := fsoofeOverwrite; end; fsourSkipAll: begin FFileExistsOption := fsoofeSkip; Result := fsoofeSkip; end; fsourNone, fsourCancel: AbortOperation; end; finally FreeAndNil(FCurrentTargetFile); end; else Result := FFileExistsOption; end; end; procedure TWfxPluginOperationHelper.CopyProperties(SourceFile: TFile; const TargetFileName: String); var WfxFileTime: TWfxFileTime; begin if caoCopyTime in FCopyAttributesOptions then begin if (FMode = wpohmCopyOut) then begin if SourceFile.ModificationTimeProperty.IsValid then mbFileSetTime(TargetFileName, DateTimeToFileTime(SourceFile.ModificationTime)); end else begin WfxFileTime := DateTimeToWfxFileTime(SourceFile.ModificationTime); FWfxPluginFileSource.WfxModule.WfxSetTime(TargetFileName, nil, nil, @WfxFileTime); end; end; end; procedure TWfxPluginOperationHelper.CountStatistics(aNode: TFileTreeNode); procedure CountNodeStatistics(aNode: TFileTreeNode); var aFileAttrs: TFileAttributesProperty; i: Integer; begin aFileAttrs := aNode.TheFile.AttributesProperty; with FStatistics^ do begin if aFileAttrs.IsDirectory then begin // No statistics for directory. // Go through subdirectories. for i := 0 to aNode.SubNodesCount - 1 do CountNodeStatistics(aNode.SubNodes[i]); end else if aFileAttrs.IsLink then begin // Count only not-followed links. if aNode.SubNodesCount = 0 then DoneFiles := DoneFiles + 1 else // Count target of link. CountNodeStatistics(aNode.SubNodes[0]); end else begin // Count files. DoneFiles := DoneFiles + 1; DoneBytes := DoneBytes + aNode.TheFile.Size; end; end; end; begin CountNodeStatistics(aNode); UpdateStatistics(FStatistics^); end; constructor TWfxPluginOperationHelper.Create(FileSource: IFileSource; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; ShowCompareFilesUIFunction: TShowCompareFilesUIFunction; ShowCompareFilesUIByFileObjectFunction: TShowCompareFilesUIByFileObjectFunction; OperationThread: TThread; Mode: TWfxPluginOperationHelperMode; TargetPath: String ); begin FWfxPluginFileSource:= FileSource as IWfxPluginFileSource; AskQuestion := AskQuestionFunction; AbortOperation := AbortOperationFunction; CheckOperationState := CheckOperationStateFunction; UpdateStatistics := UpdateStatisticsFunction; ShowCompareFilesUI := ShowCompareFilesUIFunction; ShowCompareFilesUIByFileObject := ShowCompareFilesUIByFileObjectFunction; FOperationThread:= OperationThread; FMode := Mode; FInternal:= (FMode in [wpohmCopy, wpohmMove]); FFileExistsOption := fsoofeNone; FRootTargetPath := TargetPath; FRenameMask := ''; FRenamingFiles := False; FRenamingRootDir := False; inherited Create; end; destructor TWfxPluginOperationHelper.Destroy; begin inherited Destroy; end; procedure TWfxPluginOperationHelper.Initialize; begin case FMode of wpohmCopy, wpohmCopyIn, wpohmCopyOut: FLogCaption := rsMsgLogCopy; wpohmMove: FLogCaption := rsMsgLogMove; end; SplitFileMask(FRenameMask, FRenameNameMask, FRenameExtMask); end; procedure TWfxPluginOperationHelper.ProcessTree(aFileTree: TFileTree; var Statistics: TFileSourceCopyOperationStatistics); var aFile: TFile; begin FRenamingFiles := (FRenameMask <> '*.*') and (FRenameMask <> ''); // If there is a single root dir and rename mask doesn't have wildcards // treat is as a rename of the root dir. if (aFileTree.SubNodesCount = 1) and FRenamingFiles then begin aFile := aFileTree.SubNodes[0].TheFile; if (aFile.IsDirectory or aFile.IsLinkToDirectory) and not ContainsWildcards(FRenameMask) then begin FRenamingFiles := False; FRenamingRootDir := True; FRootDir := aFile; end; end; FStatistics:= @Statistics; ProcessNode(aFileTree, FRootTargetPath); end; end. ������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017224� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/uwinnetexecuteoperation.pas���������������������������������0000644�0001750�0000144�00000005262�14743153644�024733� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWinNetExecuteOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile, uFileSource, uWinNetFileSource, uFileSourceExecuteOperation; type { TWinNetExecuteOperation } TWinNetExecuteOperation = class(TFileSourceExecuteOperation) private FWinNetFileSource: IWinNetFileSource; public {en @param(aTargetFileSource File source where the file should be executed.) @param(aExecutableFile File that should be executed.) @param(aCurrentPath Path of the file source where the execution should take place.) } constructor Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); override; procedure MainExecute; override; end; implementation uses Windows, JwaWinNetWk, DCStrUtils, DCOSUtils, DCConvertEncoding; constructor TWinNetExecuteOperation.Create(aTargetFileSource: IFileSource; var aExecutableFile: TFile; aCurrentPath, aVerb: String); begin FWinNetFileSource := aTargetFileSource as IWinNetFileSource; inherited Create(aTargetFileSource, aExecutableFile, aCurrentPath, aVerb); end; procedure TWinNetExecuteOperation.MainExecute; var nFile: TNetResourceW; lpBuffer: array [0..4095] of Byte; ResInfo: TNetResourceW absolute lpBuffer; pszSystem: PWideChar; dwBufferSize: DWORD; dwResult: DWORD; FileName: WideString; begin FExecuteOperationResult:= fseorError; FResultString:= IncludeFrontPathDelimiter(ExecutableFile.FullPath); // Workstation/Server if Pos('\\', FResultString) = 1 then begin FileName:= CeUtf8ToUtf16(FResultString); with FWinNetFileSource do try dwBufferSize:= SizeOf(lpBuffer); FillChar(nFile, SizeOf(TNetResource), #0); nFile.dwScope:= RESOURCE_GLOBALNET; nFile.dwType:= RESOURCETYPE_ANY; nFile.lpRemoteName:= PWideChar(FileName); nFile.lpProvider:= PWideChar(ProviderName); dwResult:= WNetAddConnection2W(nFile, nil, nil, CONNECT_INTERACTIVE); if (dwResult <> NO_ERROR) then Exit; dwResult:= WNetGetResourceInformationW(nFile, @lpBuffer, dwBufferSize, pszSystem); if (dwResult <> NO_ERROR) then Exit; if (ResInfo.dwType = RESOURCETYPE_PRINT) then begin if (ShellExecuteW(0, 'open', ResInfo.lpRemoteName, nil, nil, SW_SHOW) > 32) then FExecuteOperationResult:= fseorSuccess; Exit; end; finally if (dwResult <> NO_ERROR) then FResultString:= mbSysErrorMessage(dwResult); end; end; FExecuteOperationResult:= fseorSymLink; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/uwinnetfilesource.pas���������������������������������������0000644�0001750�0000144�00000026244�14743153644�023513� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWinNetFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Dialogs, uFileSourceProperty, uVirtualFileSource, uFileSystemFileSource, uFileProperty, uFileSource, uFileSourceOperation, uFile; type { IWinNetFileSource } IWinNetFileSource = interface(IVirtualFileSource) ['{55329161-3CFC-4F15-B66D-6649B42E9357}'] function GetSamba1: Boolean; function GetProviderName: UnicodeString; function IsNetworkPath(const Path: String): Boolean; property Samba1: Boolean read GetSamba1; property ProviderName: UnicodeString read GetProviderName; end; { TWinNetFileSource } TWinNetFileSource = class(TFileSystemFileSource, IWinNetFileSource) private FSamba1: Boolean; FProviderName: array[0..MAX_PATH-1] of WideChar; function GetProviderName: UnicodeString; function GetSamba1: Boolean; protected function IsNetworkPath(const Path: String): Boolean; function SetCurrentWorkingDirectory(NewDir: String): Boolean; override; public constructor Create; override; class function IsSupportedPath(const Path: String): Boolean; override; class function GetMainIcon(out Path: String): Boolean; override; function GetParentDir(sPath : String): String; override; function IsPathAtRoot(Path: String): Boolean; override; function GetRootDir(sPath: String): String; override; overload; function GetRootDir: String; override; overload; function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; override; // Retrieve some properties of the file source. function GetProperties: TFileSourceProperties; override; // These functions create an operation object specific to the file source. function CreateListOperation(TargetPath: String): TFileSourceOperation; override; function CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override; function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override; function CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; override; function CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; override; function CreateCombineOperation(var SourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; override; function CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; override; function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override; function CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; override; function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override; function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override; end; implementation uses LazUTF8, uWinNetListOperation, uWinNetExecuteOperation, uMyWindows, Windows, JwaWinNetWk, uVfsModule, uShowMsg, DCOSUtils, DCStrUtils, DCConvertEncoding; function TWinNetFileSource.GetParentDir(sPath: String): String; var nFile: TNetResourceW; lpBuffer: array [0..4095] of Byte; ParentPath: TNetResourceW absolute lpBuffer; dwBufferSize: DWORD; dwResult: DWORD; FilePath: UnicodeString; begin Result:= GetRootDir; if Pos('\\', sPath) = 1 then begin if not FSamba1 then begin if IsNetworkPath(sPath) then Result:= ExcludeFrontPathDelimiter(DCStrUtils.GetParentDir(sPath)) else begin Result:= DCStrUtils.GetParentDir(sPath); end; Exit; end; FilePath:= CeUtf8ToUtf16(ExcludeTrailingPathDelimiter(sPath)); FillByte(nFile, SizeOf(TNetResourceW), 0); with nFile do begin dwScope := RESOURCE_GLOBALNET; dwType := RESOURCETYPE_DISK; dwDisplayType := RESOURCEDISPLAYTYPE_SERVER; dwUsage := RESOURCEUSAGE_CONTAINER; lpRemoteName := PWideChar(FilePath); lpProvider := @FProviderName; end; dwBufferSize:= SizeOf(lpBuffer); dwResult := WNetGetResourceParentW(nFile, @lpBuffer, dwBufferSize); if dwResult <> NO_ERROR then msgError(mbWinNetErrorMessage(GetLastError)) else begin FilePath:= UnicodeString(ParentPath.lpRemoteName); Result := IncludeFrontPathDelimiter(UTF16ToUTF8(FilePath)); Result := IncludeTrailingPathDelimiter(Result); end; end; end; function TWinNetFileSource.IsPathAtRoot(Path: String): Boolean; begin Result := (DCStrUtils.GetParentDir(Path) = ''); end; function TWinNetFileSource.GetRootDir(sPath: String): String; begin Result:= PathDelim; end; function TWinNetFileSource.GetRootDir: String; begin Result:= PathDelim; end; function TWinNetFileSource.GetFreeSpace(Path: String; out FreeSize, TotalSize: Int64): Boolean; begin if IsNetworkPath(Path) then Result:= False else Result:= inherited GetFreeSpace(Path, FreeSize, TotalSize); end; function TWinNetFileSource.GetProperties: TFileSourceProperties; begin Result := inherited GetProperties + [fspVirtual] - [fspNoneParent]; end; function TWinNetFileSource.GetProviderName: UnicodeString; begin Result:= UnicodeString(FProviderName); end; function TWinNetFileSource.GetSamba1: Boolean; begin Result:= FSamba1; end; function TWinNetFileSource.IsNetworkPath(const Path: String): Boolean; begin Result:= (NumCountChars(PathDelim, ExcludeTrailingPathDelimiter(Path)) < 3); end; function TWinNetFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean; begin if IsNetworkPath(NewDir) then Result:= True else Result:= mbSetCurrentDir(NewDir); end; constructor TWinNetFileSource.Create; var dwBufferSize: DWORD = MAX_PATH; begin inherited Create; if WNetGetProviderNameW(WNNC_NET_LANMAN, @FProviderName, dwBufferSize) <> NO_ERROR then raise EOSError.Create(mbWinNetErrorMessage(GetLastError)); FSamba1:= (Win32MajorVersion < 6) or (GetServiceStatus('mrxsmb10') = SERVICE_RUNNING); end; class function TWinNetFileSource.IsSupportedPath(const Path: String): Boolean; begin Result:= (Pos('\\', Path) = 1); end; class function TWinNetFileSource.GetMainIcon(out Path: String): Boolean; begin Result:= True; Path:= '%SystemRoot%\System32\shell32.dll,17'; end; function TWinNetFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TWinNetListOperation.Create(TargetFileSource, TargetPath); end; function TWinNetFileSource.CreateCopyOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin if IsNetworkPath(TargetPath) then Result:= nil else Result:= inherited CreateCopyOperation(SourceFiles, TargetPath); end; function TWinNetFileSource.CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin if IsNetworkPath(TargetPath) then Result:= nil else Result:=inherited CreateCopyInOperation(SourceFileSource, SourceFiles, TargetPath); end; function TWinNetFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin if IsNetworkPath(SourceFiles.Path) then Result:= nil else Result:= inherited CreateCopyOutOperation(TargetFileSource, SourceFiles, TargetPath); end; function TWinNetFileSource.CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; begin if IsNetworkPath(SourceFiles.Path) then Result:= nil else Result:= inherited CreateMoveOperation(SourceFiles, TargetPath); end; function TWinNetFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; begin if IsNetworkPath(FilesToDelete.Path) then Result:= nil else Result:= inherited CreateDeleteOperation(FilesToDelete); end; function TWinNetFileSource.CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; begin if IsNetworkPath(FilesToWipe.Path) then Result:= nil else Result:= inherited CreateWipeOperation(FilesToWipe); end; function TWinNetFileSource.CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; begin if IsNetworkPath(aSourceFile.Path) then Result:= nil else Result:= inherited CreateSplitOperation(aSourceFile, aTargetPath); end; function TWinNetFileSource.CreateCombineOperation(var SourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; begin if IsNetworkPath(SourceFiles.Path) then Result:= nil else Result:= inherited CreateCombineOperation(SourceFiles, aTargetFile); end; function TWinNetFileSource.CreateCreateDirectoryOperation(BasePath: String; DirectoryPath: String): TFileSourceOperation; begin if IsNetworkPath(BasePath) then Result:= nil else Result:= inherited CreateCreateDirectoryOperation(BasePath, DirectoryPath); end; function TWinNetFileSource.CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; if IsNetworkPath(BasePath) then Result:= TWinNetExecuteOperation.Create(TargetFileSource, ExecutableFile, BasePath, Verb) else Result:= inherited CreateExecuteOperation(ExecutableFile, BasePath, Verb); end; function TWinNetFileSource.CreateCalcChecksumOperation(var theFiles: TFiles; aTargetPath: String; aTargetMask: String): TFileSourceOperation; begin if IsNetworkPath(theFiles.Path) then Result:= nil else Result:= inherited CreateCalcChecksumOperation(theFiles, aTargetPath, aTargetMask); end; function TWinNetFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; begin if (NumCountChars(PathDelim, ExcludeTrailingPathDelimiter(theFiles.Path)) < 2) then Result:= nil else Result:= inherited CreateCalcStatisticsOperation(theFiles); end; function TWinNetFileSource.CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties ): TFileSourceOperation; begin if IsNetworkPath(theTargetFiles.Path) then Result:= nil else Result:= inherited CreateSetFilePropertyOperation(theTargetFiles, theNewProperties); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/uwinnetlistoperation.pas������������������������������������0000644�0001750�0000144�00000016505�14743153644�024246� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWinNetListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSystemListOperation, uWinNetFileSource, uFileSource; type { TWinNetListOperation } TWinNetListOperation = class(TFileSystemListOperation) private FWinNetFileSource: IWinNetFileSource; private procedure ShareEnum; procedure ShellEnum; procedure WorkgroupEnum; function Connect: Boolean; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses LazUTF8, uFile, Windows, JwaWinNetWk, JwaLmCons, JwaLmShare, JwaLmApiBuf, StrUtils, DCStrUtils, uShowMsg, DCOSUtils, uOSUtils, uNetworkThread, uMyWindows, ActiveX, ShlObj, ComObj, DCConvertEncoding, uShellFolder, uShlObjAdditional; function TWinNetListOperation.Connect: Boolean; var dwResult: DWORD; ServerPath: UnicodeString; AbortMethod: TThreadMethod; begin if GetCurrentThreadId = MainThreadID then AbortMethod:= nil else begin AbortMethod:= @CheckOperationState; end; if FWinNetFileSource.IsNetworkPath(Path) then ServerPath:= CeUtf8ToUtf16(ExcludeTrailingPathDelimiter(Path)) else begin dwResult:= NPos(PathDelim, Path, 4); if dwResult = 0 then dwResult:= MaxInt; ServerPath:= CeUtf8ToUtf16(Copy(Path, 1, dwResult - 1)); end; dwResult:= TNetworkThread.Connect(nil, PWideChar(ServerPath), RESOURCETYPE_ANY, AbortMethod); if dwResult <> NO_ERROR then begin if dwResult = ERROR_CANCELLED then RaiseAbortOperation; msgError(Thread, mbWinNetErrorMessage(dwResult)); Exit(False); end; Result:= True; end; procedure TWinNetListOperation.WorkgroupEnum; var I: DWORD; aFile: TFile; nFile: TNetResourceW; nFileList: PNetResourceW; dwResult: DWORD; dwCount, dwBufferSize: DWORD; hEnum: THandle = INVALID_HANDLE_VALUE; lpBuffer: Pointer = nil; FilePath: String; FileName: UnicodeString; begin with FWinNetFileSource do try ZeroMemory(@nFile, SizeOf(TNetResourceW)); nFile.dwScope:= RESOURCE_GLOBALNET; nFile.dwType:= RESOURCETYPE_ANY; nFile.lpProvider:= PWideChar(ProviderName); if not IsPathAtRoot(Path) then begin FilePath:= ExcludeTrailingPathDelimiter(Path); FileName:= CeUtf8ToUtf16(ExcludeFrontPathDelimiter(FilePath)); nFile.lpRemoteName:= PWideChar(FileName); end; dwResult := WNetOpenEnumW(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, @nFile, hEnum); if (dwResult <> NO_ERROR) then Exit; dwCount := DWORD(-1); // 1024 Kb must be enough dwBufferSize:= $100000; // Allocate output buffer GetMem(lpBuffer, dwBufferSize); // Enumerate all resources dwResult:= WNetEnumResourceW(hEnum, dwCount, lpBuffer, dwBufferSize); if dwResult = ERROR_NO_MORE_ITEMS then Exit; if (dwResult <> NO_ERROR) then Exit; nFileList:= PNetResourceW(lpBuffer); for I := 0 to dwCount - 1 do begin CheckOperationState; aFile:= TWinNetFileSource.CreateFile(Path); aFile.FullPath:= UTF16ToUTF8(UnicodeString(nFileList^.lpRemoteName)); aFile.CommentProperty.Value:= UTF16ToUTF8(UnicodeString(nFileList^.lpComment)); if nFileList^.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE then aFile.Attributes:= faFolder; FFiles.Add(aFile); Inc(nFileList); end; finally if (hEnum <> INVALID_HANDLE_VALUE) then dwResult := WNetCloseEnum(hEnum); if (dwResult <> NO_ERROR) and (dwResult <> ERROR_NO_MORE_ITEMS) then msgError(Thread, mbWinNetErrorMessage(dwResult)); if Assigned(lpBuffer) then FreeMem(lpBuffer); end; end; procedure TWinNetListOperation.ShareEnum; var I: DWORD; aFile: TFile; dwResult: NET_API_STATUS; dwEntriesRead: DWORD = 0; dwTotalEntries: DWORD = 0; ServerPath: UnicodeString; BufPtr, nFileList: PShareInfo1; begin if not Connect then Exit; ServerPath:= CeUtf8ToUtf16(ExcludeTrailingPathDelimiter(Path)); BufPtr:= nil; repeat // Call the NetShareEnum function dwResult:= NetShareEnum (PWideChar(ServerPath), 1, PByte(BufPtr), MAX_PREFERRED_LENGTH, @dwEntriesRead, @dwTotalEntries, nil); // If the call succeeds if (dwResult = ERROR_SUCCESS) or (dwResult = ERROR_MORE_DATA) then begin nFileList:= BufPtr; // Loop through the entries for I:= 1 to dwEntriesRead do begin CheckOperationState; aFile:= TWinNetFileSource.CreateFile(Path); aFile.Name:= UTF16ToUTF8(UnicodeString(nFileList^.shi1_netname)); aFile.CommentProperty.Value:= UTF16ToUTF8(UnicodeString(nFileList^.shi1_remark)); case (nFileList^.shi1_type and $FF) of STYPE_DISKTREE: aFile.Attributes:= FILE_ATTRIBUTE_DIRECTORY; STYPE_IPC: aFile.Attributes:= FILE_ATTRIBUTE_SYSTEM; end; // Mark special items as hidden if (nFileList^.shi1_type and STYPE_SPECIAL = STYPE_SPECIAL) then aFile.Attributes:= aFile.Attributes or FILE_ATTRIBUTE_HIDDEN; // Mark special items as hidden if (lstrcmpiW(nFileList^.shi1_netname, 'FAX$') = 0) then aFile.Attributes:= aFile.Attributes or FILE_ATTRIBUTE_HIDDEN; // Mark special items as hidden if (lstrcmpiW(nFileList^.shi1_netname, 'PRINT$') = 0) then aFile.Attributes:= aFile.Attributes or FILE_ATTRIBUTE_HIDDEN; FFiles.Add(aFile); Inc(nFileList); end; // Free the allocated buffer NetApiBufferFree(BufPtr); end; // Continue to call NetShareEnum while there are more entries until (dwResult <> ERROR_MORE_DATA); // Show error if failed if (dwResult <> ERROR_SUCCESS) then msgError(Thread, mbSysErrorMessage(dwResult)); end; procedure TWinNetListOperation.ShellEnum; var AFile: TFile; NumIDs: LongWord = 0; AFolder: IShellFolder; EnumIDList: IEnumIDList; DesktopFolder: IShellFolder; PIDL, NetworkPIDL: PItemIDList; begin try OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(0, CSIDL_NETWORK, 0, 0, {%H-}NetworkPIDL)); try OleCheckUTF8(DesktopFolder.BindToObject(NetworkPIDL, nil, IID_IShellFolder, Pointer(AFolder))); OleCheckUTF8(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumIDList)); while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try CheckOperationState; aFile:= TWinNetFileSource.CreateFile(Path); AFile.FullPath:= GetDisplayName(AFolder, PIDL, SHGDN_FORPARSING or SHGDN_FORADDRESSBAR); FFiles.Add(AFile); finally CoTaskMemFree(PIDL); end; finally CoTaskMemFree(NetworkPIDL); end; except on E: Exception do msgError(Thread, E.Message); end; end; constructor TWinNetListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FWinNetFileSource := aFileSource as IWinNetFileSource; inherited Create(aFileSource, aPath); end; procedure TWinNetListOperation.MainExecute; begin FFiles.Clear; with FWinNetFileSource do begin // Shared directory if not IsNetworkPath(Path) then begin if Connect then inherited MainExecute; end else begin // Workstation/Server if (IsPathAtRoot(Path) = False) and (Pos('\\', Path) = 1) then ShareEnum // Root/Domain/Workgroup else if not Samba1 then ShellEnum else WorkgroupEnum; end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/wsl/��������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�020031� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/wsl/uwslfilesource.pas��������������������������������������0000644�0001750�0000144�00000004322�14743153644�023612� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWslFileSource; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Dialogs, uFileSource, uFileSourceOperation, uWinNetFileSource; type { TWslFileSource } TWslFileSource = class(TWinNetFileSource) public function GetParentDir(sPath : String): String; override; function IsPathAtRoot(Path: String): Boolean; override; function GetRootDir(sPath: String): String; override; overload; function GetRootDir: String; override; overload; class function Available: Boolean; class function IsSupportedPath(const Path: String): Boolean; override; class function GetMainIcon(out Path: String): Boolean; override; function CreateListOperation(TargetPath: String): TFileSourceOperation; override; end; implementation uses LazUTF8, DCOSUtils, DCStrUtils, uMyWindows, uWslListOperation; { TWslFileSource } function TWslFileSource.GetParentDir(sPath: String): String; begin Result:= DCStrUtils.GetParentDir(sPath); end; function TWslFileSource.IsPathAtRoot(Path: String): Boolean; begin Path:= IncludeTrailingBackslash(LowerCase(Path)); Result:= SameStr(Path, '\\wsl$\') or SameStr(Path, '\\wsl.localhost\'); end; function TWslFileSource.GetRootDir(sPath: String): String; begin if (Win32BuildNumber >= 22000) then Result:= '\\wsl.localhost\' else begin Result:= '\\wsl$\'; end; end; function TWslFileSource.GetRootDir: String; begin Result:= GetRootDir(EmptyStr); end; class function TWslFileSource.Available: Boolean; begin Result:= GetServiceStatus('LxssManager') <> 0; end; class function TWslFileSource.IsSupportedPath(const Path: String): Boolean; var APath: String; begin APath:= IncludeTrailingBackslash(LowerCase(Path)); Result:= StrBegins(APath, '\\wsl$\') or StrBegins(APath, '\\wsl.localhost\'); end; class function TWslFileSource.GetMainIcon(out Path: String): Boolean; begin if IsWow64 then Path:= '%SystemRoot%\Sysnative\wsl.exe' else begin Path:= '%SystemRoot%\System32\wsl.exe'; end; Result:= True; end; function TWslFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation; var TargetFileSource: IFileSource; begin TargetFileSource := Self; Result:= TWslListOperation.Create(TargetFileSource, TargetPath); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/filesources/winnet/wsl/uwsllistoperation.pas�����������������������������������0000644�0001750�0000144�00000004375�14743153644�024356� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWslListOperation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSystemListOperation, uWinNetFileSource, uFileSource; type { TWslListOperation } TWslListOperation = class(TFileSystemListOperation) private FWinNetFileSource: IWinNetFileSource; private procedure LinuxEnum; public constructor Create(aFileSource: IFileSource; aPath: String); override; procedure MainExecute; override; end; implementation uses LazUTF8, uFile, Windows, uShowMsg, DCOSUtils, uMyWindows, ShlObj, ComObj, ActiveX, DCConvertEncoding, uShellFolder, uShlObjAdditional; procedure TWslListOperation.LinuxEnum; var AFile: TFile; pchEaten: ULONG; APath: UnicodeString; NumIDs: LongWord = 0; AFolder: IShellFolder; dwAttributes: ULONG = 0; EnumIDList: IEnumIDList; DesktopFolder: IShellFolder; PIDL, NetworkPIDL: PItemIDList; begin try OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); APath:= CeUtf8ToUtf16(ExcludeTrailingPathDelimiter(Path)); OleCheckUTF8(DeskTopFolder.ParseDisplayName(0, nil, PWideChar(APath), pchEaten, NetworkPIDL, dwAttributes)); try OleCheckUTF8(DesktopFolder.BindToObject(NetworkPIDL, nil, IID_IShellFolder, Pointer(AFolder))); OleCheckUTF8(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumIDList)); while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do try CheckOperationState; aFile:= TWinNetFileSource.CreateFile(Path); aFile.Attributes:= FILE_ATTRIBUTE_DIRECTORY; AFile.FullPath:= GetDisplayName(AFolder, PIDL, SHGDN_FORPARSING or SHGDN_FORADDRESSBAR); FFiles.Add(AFile); finally CoTaskMemFree(PIDL); end; finally CoTaskMemFree(NetworkPIDL); end; except on E: Exception do msgError(Thread, E.Message); end; end; constructor TWslListOperation.Create(aFileSource: IFileSource; aPath: String); begin FFiles := TFiles.Create(aPath); FWinNetFileSource := aFileSource as IWinNetFileSource; inherited Create(aFileSource, aPath); end; procedure TWslListOperation.MainExecute; begin FFiles.Clear; with FWinNetFileSource do begin if IsNetworkPath(Path) then LinuxEnum else begin inherited MainExecute; end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/���������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015372� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ubrieffileview.pas���������������������������������������������������0000644�0001750�0000144�00000044026�14743153644�021114� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uBriefFileView; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, LMessages, Grids, Graphics, uDisplayFile, DCXmlConfig, uTypes, uFileViewWithGrid, uFile, uFileSource, uFileProperty; type TBriefFileView = class; { TBriefDrawGrid } TBriefDrawGrid = class(TFileViewGrid) protected FBriefView: TBriefFileView; protected procedure UpdateView; override; procedure CalculateColRowCount; override; procedure CalculateColumnWidth; override; procedure DoMouseMoveScroll(X, Y: Integer); protected procedure KeyDown(var Key : Word; Shift : TShiftState); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override; function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override; procedure DragOver(Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean); override; public constructor Create(AOwner: TComponent; AParent: TWinControl); override; function CellToIndex(ACol, ARow: Integer): Integer; override; procedure IndexToCell(Index: Integer; out ACol, ARow: Integer); override; procedure DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); override; end; { TBriefFileView } TBriefFileView = class (TFileViewWithGrid) protected procedure CreateDefault(AOwner: TWinControl); override; function GetFileViewGridClass: TFileViewGridClass; override; procedure ShowRenameFileEdit(var aFile: TFile); override; procedure UpdateRenameFileEditPosition; override; function GetVisibleFilesIndexes: TRange; override; function GetIconRect(FileIndex: PtrInt): TRect; override; procedure MouseScrollTimer(Sender: TObject); override; procedure DoFileRenamed(ADisplayFile: TDisplayFile); override; procedure DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes = []); override; public function Clone(NewParent: TWinControl): TBriefFileView; override; procedure SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); override; end; implementation uses LCLIntf, LCLType, LCLVersion, LCLProc, Math, StdCtrls, uGlobs, uPixmapManager, uKeyboard, fMain, uFileSourceProperty, uOrderedFileView; const CELL_PADDING = 1; { TBriefDrawGrid } procedure TBriefDrawGrid.UpdateView; function CalculateDefaultRowHeight: Integer; var OldFont, NewFont: TFont; MaxFontHeight: Integer = 0; CurrentHeight: Integer; begin // Start with height of the icons. if gShowIcons <> sim_none then MaxFontHeight := gIconsSize; // Assign temporary font. OldFont := Canvas.Font; NewFont := TFont.Create; Canvas.Font := NewFont; Canvas.Font.PixelsPerInch := NewFont.PixelsPerInch; // Search columns settings for the biggest font (in height). Canvas.Font.Name := gFonts[dcfMain].Name; Canvas.Font.Style := gFonts[dcfMain].Style; Canvas.Font.Size := gFonts[dcfMain].Size; CurrentHeight := Canvas.GetTextHeight('Wg'); MaxFontHeight := Max(MaxFontHeight, CurrentHeight); // Restore old font. Canvas.Font := OldFont; FreeAndNil(NewFont); Result := MaxFontHeight + gExtraLineSpan; end; var TempRowHeight: Integer; begin // Fix border blinking while scroll window Flat := True; // gInterfaceFlat; // Calculate row height. TempRowHeight := CalculateDefaultRowHeight; if TempRowHeight > 0 then DefaultRowHeight := TempRowHeight; // Calculate column width CalculateColumnWidth; end; procedure TBriefDrawGrid.CalculateColRowCount; var ARowCount: Integer; AIndex, ACol, ARow: Integer; begin if (csDesigning in ComponentState) then Exit; if not Assigned(FBriefView.FFiles) then Exit; if (ClientHeight > 0) and (DefaultRowHeight > 0) then begin // Save active file index AIndex:= CellToIndex(Col, Row); ARowCount := (ClientHeight - BorderWidth * 2) div DefaultRowHeight; if ARowCount > 0 then begin RowCount := ARowCount; ColCount := (FBriefView.FFiles.Count + ARowCount - 1) div ARowCount; // Restore active file index if AIndex >= 0 then begin IndexToCell(AIndex, ACol, ARow); MoveExtend(False, ACol, ARow); end; end; end; Invalidate; end; procedure TBriefDrawGrid.CalculateColumnWidth; var I, J, M: Integer; ARefresh: Boolean; AFile: TDisplayFile; begin if not Assigned(FBriefView.FFiles) or (FBriefView.FFiles.Count = 0) then Exit; if gBriefViewMode = bvmFixedWidth then DefaultColWidth:= Min(ClientWidth, gBriefViewFixedWidth) else if gBriefViewMode = bvmFixedCount then DefaultColWidth:= ClientWidth div Max(1, gBriefViewFixedCount) else if (FBriefView.FFiles.Count = 1) and (FBriefView.FFiles[0].FSFile.Name = '..') then DefaultColWidth:= ClientWidth div 3 else begin J:= 0; M:= 0; ARefresh:= (Canvas.Font.Name <> gFonts[dcfMain].Name) or (Canvas.Font.Size <> gFonts[dcfMain].Size) or (Canvas.Font.Style <> gFonts[dcfMain].Style); FontOptionsToFont(gFonts[dcfMain], Canvas.Font); for I:= 0 to FBriefView.FFiles.Count - 1 do begin AFile:= FBriefView.FFiles[I]; if ARefresh or (AFile.Tag <= 0) then begin AFile.Tag:= Canvas.TextWidth(AFile.FSFile.Name); end; if AFile.Tag > M then begin M:= AFile.Tag; J:= I; end; end; M:= Canvas.TextWidth(FBriefView.FFiles[J].FSFile.Name + 'WWW'); if (gShowIcons = sim_none) then M:= M + 2 else M:= M + gIconsSize + 4; if M > ClientWidth then M:= ClientWidth - 4; DefaultColWidth:= M; end; end; procedure TBriefDrawGrid.DoMouseMoveScroll(X, Y: Integer); var TickCount: QWord; AEvent: SmallInt; begin TickCount := GetTickCount64; if X < 25 then AEvent := SB_LINEUP else if X > ClientWidth - 25 then AEvent := SB_LINEDOWN else begin FBriefView.tmMouseScroll.Enabled := False; Exit; end; if (FLastMouseMoveTime = 0) then FLastMouseMoveTime := TickCount else if (FLastMouseScrollTime = 0) then FLastMouseScrollTime := TickCount else if (TickCount - FLastMouseMoveTime > 200) and (TickCount - FLastMouseScrollTime > 50) then begin Scroll(LM_HSCROLL, AEvent); FLastMouseScrollTime := GetTickCount64; FBriefView.tmMouseScroll.Enabled := True; end; end; function TBriefDrawGrid.CellToIndex(ACol, ARow: Integer): Integer; begin if (ARow < 0) or (ARow >= RowCount) or (ACol < 0) or (ACol >= ColCount) then Exit(-1); Result:= ACol * RowCount + ARow; if (Result < 0) or (Result >= FBriefView.FFiles.Count) then Result:= -1; end; procedure TBriefDrawGrid.IndexToCell(Index: Integer; out ACol, ARow: Integer); begin if (Index < 0) or (Index >= FBriefView.FFiles.Count) or (RowCount = 0) then begin ACol:= -1; ARow:= -1; end else begin ACol:= Index div RowCount; ARow:= Index mod RowCount; end; end; procedure TBriefDrawGrid.KeyDown(var Key: Word; Shift: TShiftState); var SavedKey: Word; FileIndex: Integer; ACol, ARow: Integer; begin if FBriefView.IsLoadingFileList then begin FBriefView.HandleKeyDownWhenLoading(Key, Shift); Exit; end; SavedKey := Key; // Set RangeSelecting before cursor is moved. FBriefView.FRangeSelecting := (ssShift in Shift) and (SavedKey in [VK_LEFT, VK_RIGHT, VK_HOME, VK_END, VK_PRIOR, VK_NEXT]); // Special case for selection with shift key (works like VK_INSERT) if (SavedKey in [VK_UP, VK_DOWN]) and (ssShift in Shift) then FBriefView.InvertActiveFile; case Key of VK_LEFT: begin if (Col - 1 < 0) then begin MoveExtend(False, 0, 0); Key:= 0; end; end; VK_RIGHT: begin if (CellToIndex(Col + 1, Row) < 0) then begin IndexToCell(FBriefView.FFiles.Count - 1, ACol, ARow); MoveExtend(False, ACol, ARow); Key:= 0; end; end; VK_PRIOR: begin FileIndex:= CellToIndex(Col, Row) - (VisibleRowCount - 1); if FileIndex < 0 then FileIndex:= 0; IndexToCell(FileIndex, ACol, ARow); MoveExtend(False, ACol, ARow); Key:= 0; end; VK_NEXT: begin FileIndex:= CellToIndex(Col, Row) + (VisibleRowCount - 1); if FileIndex >= FBriefView.FFiles.Count then FileIndex:= FBriefView.FFiles.Count - 1; IndexToCell(FileIndex, ACol, ARow); MoveExtend(False, ACol, ARow); Key:= 0; end; VK_HOME: begin MoveExtend(False, 0, 0); Key:= 0; end; VK_END: begin IndexToCell(FBriefView.FFiles.Count - 1, ACol, ARow); MoveExtend(False, ACol, ARow); Key:= 0; end; VK_UP, VK_DOWN: begin if (CellToIndex(Col, Row) >= FBriefView.FFiles.Count - 1) and (Key = VK_DOWN) then begin Key:= 0; end else if ((Row = RowCount-1) and (Key = VK_DOWN)) then begin if (Col < ColCount - 1) then begin Row:= 0; Col:= Col + 1; end; Key:= 0; end else if (Row = FixedRows) and (Key = VK_UP) then begin if (Col > 0) then begin Row:= RowCount - 1; Col:= Col - 1; end; Key:= 0; end; end; end; inherited KeyDown(Key, Shift); if FBriefView.FRangeSelecting then begin FileIndex := CellToIndex(Col, Row); if FileIndex <> InvalidFileIndex then FBriefView.Selection(SavedKey, FileIndex); end; end; procedure TBriefDrawGrid.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited MouseMove(Shift, X, Y); if FBriefView.IsMouseSelecting then DoMouseMoveScroll(X, Y); end; function TBriefDrawGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; begin if not FBriefView.IsLoadingFileList then begin if (Shift=[ssCtrl])and(gFonts[dcfMain].Size > gFonts[dcfMain].MinValue) then begin gFonts[dcfMain].Size:=gFonts[dcfMain].Size-1; frmMain.FrameLeft.UpdateView; frmMain.FrameRight.UpdateView; Result:=True; Exit; end; Result:= inherited DoMouseWheelDown(Shift, MousePos); Result:= Perform(LM_HSCROLL, SB_LINERIGHT, 0) = 0; end else Result := True; // Handled end; function TBriefDrawGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; begin if not FBriefView.IsLoadingFileList then begin if (Shift=[ssCtrl])and(gFonts[dcfMain].Size < gFonts[dcfMain].MaxValue) then begin gFonts[dcfMain].Size:=gFonts[dcfMain].Size+1; frmMain.FrameLeft.UpdateView; frmMain.FrameRight.UpdateView; Result:=True; Exit; end; Result:= inherited DoMouseWheelUp(Shift, MousePos); Result:= Perform(LM_HSCROLL, SB_LINELEFT, 0) = 0; end else Result := True; // Handled end; procedure TBriefDrawGrid.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin inherited DragOver(Source, X, Y, State, Accept); DoMouseMoveScroll(X, Y); end; constructor TBriefDrawGrid.Create(AOwner: TComponent; AParent: TWinControl); begin FBriefView:= AParent as TBriefFileView; inherited Create(AOwner, AParent); // Fix vertical bar flash ScrollBars := ssAutoHorizontal; end; procedure TBriefDrawGrid.DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var Idx: Integer; //shared variables s: string; iTextTop: Integer; AFile: TDisplayFile; FileSourceDirectAccess: Boolean; //------------------------------------------------------ //begin subprocedures //------------------------------------------------------ procedure DrawIconCell; //------------------------------------------------------ var Y: Integer; IconID: PtrInt; begin if (gShowIcons <> sim_none) then begin IconID := AFile.IconID; // Draw default icon if there is no icon for the file. if IconID = -1 then IconID := PixMapManager.GetDefaultIcon(AFile.FSFile); // center icon vertically Y:= aRect.Top + (RowHeights[ARow] - gIconsSize) div 2; if gShowHiddenDimmed and AFile.FSFile.IsHidden then PixMapManager.DrawBitmapAlpha(IconID, Canvas, aRect.Left + CELL_PADDING, Y ) else // Draw icon for a file PixMapManager.DrawBitmap(IconID, Canvas, aRect.Left + CELL_PADDING, Y ); // Draw overlay icon for a file if needed if gIconOverlays then begin PixMapManager.DrawBitmapOverlay(AFile, FileSourceDirectAccess, Canvas, aRect.Left + 1, Y ); end; end; // Print filename with align Y:= (DefaultColWidth - 2 - Canvas.TextWidth('I')); if (gShowIcons <> sim_none) then Y:= Y - gIconsSize - 2; if (not gBriefViewFileExtAligned) or (AFile.FSFile.Extension = '') then begin s:= AFile.DisplayStrings[0]; s:= FitFileName(s, Canvas, AFile.FSFile, Y); end else begin // Right align extention print s:= AFile.FSFile.Extension; Canvas.TextOut(aRect.Left + DefaultColWidth - Canvas.TextWidth(s + 'I'), iTextTop, s); s:= AFile.FSFile.NameNoExt; s:= FitFileName(s, Canvas, AFile.FSFile, Y - Canvas.TextWidth(AFile.FSFile.Extension + 'I')); end; if (gShowIcons <> sim_none) then Canvas.TextOut(aRect.Left + gIconsSize + 4, iTextTop, s) else Canvas.TextOut(aRect.Left + 2, iTextTop, s); end; //of DrawIconCell //------------------------------------------------------ //end of subprocedures //------------------------------------------------------ begin Idx:= CellToIndex(aCol, aRow); if (Idx >= 0) and (FBriefView.FFiles.Count > 0) then begin AFile:= FBriefView.FFiles[Idx]; FileSourceDirectAccess:= fspDirectAccess in FBriefView.FileSource.Properties; if AFile.DisplayStrings.Count = 0 then FBriefView.MakeColumnsStrings(AFile); PrepareColors(aFile, aCol, aRow, aRect, aState); iTextTop := aRect.Top + (RowHeights[aRow] - Canvas.TextHeight('Wg')) div 2; DrawIconCell; end else begin // Draw background. Canvas.Brush.Color := FBriefView.DimColor(gColors.FilePanel^.BackColor); Canvas.FillRect(aRect); end; DrawCellGrid(aCol, aRow, aRect, aState); DrawLines(Idx, aCol, aRow, aRect, aState); end; { TBriefFileView } procedure TBriefFileView.CreateDefault(AOwner: TWinControl); begin inherited CreateDefault(AOwner); tmMouseScroll.Interval := 350; // Changing height of a FileView with horizontal scrolling when hiding quick search causes file jumps under mouse quickSearch.LimitedAutoHide := True; end; function TBriefFileView.GetFileViewGridClass: TFileViewGridClass; begin Result:= TBriefDrawGrid; end; procedure TBriefFileView.ShowRenameFileEdit(var aFile: TFile); begin if not edtRename.Visible then begin edtRename.Font.Name := gFonts[dcfMain].Name; edtRename.Font.Size := gFonts[dcfMain].Size; edtRename.Font.Style := gFonts[dcfMain].Style; dgPanel.LeftCol:= dgPanel.Col; UpdateRenameFileEditPosition; end; inherited ShowRenameFileEdit(AFile); end; procedure TBriefFileView.UpdateRenameFileEditPosition; var ARect: TRect; begin inherited UpdateRenameFileEditPosition; ARect := dgPanel.CellRect(dgPanel.Col, dgPanel.Row); Dec(ARect.Top, 2); Inc(ARect.Bottom, 2); if gShowIcons <> sim_none then Inc(ARect.Left, gIconsSize + 2); if gInplaceRenameButton and (ARect.Right + edtRename.ButtonWidth < dgPanel.ClientWidth) then Inc(ARect.Right, edtRename.ButtonWidth); edtRename.SetBounds(ARect.Left, ARect.Top, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top); end; function TBriefFileView.GetVisibleFilesIndexes: TRange; begin with dgPanel do begin if (TopRow < 0) or (csLoading in ComponentState) then begin Result.First:= 0; Result.Last:= -1; end else begin Result.First:= (LeftCol * VisibleRowCount - 1); Result.Last:= (LeftCol + VisibleColCount + 1) * VisibleRowCount - 1; if Result.First < 0 then Result.First:= 0; if Result.Last >= FFiles.Count then Result.Last:= FFiles.Count - 1; end; end; end; function TBriefFileView.GetIconRect(FileIndex: PtrInt): TRect; var ACol, ARow: Integer; begin dgPanel.IndexToCell(FileIndex, ACol, ARow); Result := dgPanel.CellRect(ACol, ARow); Result.Top:= Result.Top + (dgPanel.RowHeights[ARow] - gIconsSize) div 2; Result.Left:= Result.Left + CELL_PADDING; Result.Right:= Result.Left + gIconsSize; Result.Bottom:= Result.Bottom + gIconsSize; end; procedure TBriefFileView.MouseScrollTimer(Sender: TObject); var APoint: TPoint; begin if DragManager.IsDragging or IsMouseSelecting then begin APoint := dgPanel.ScreenToClient(Mouse.CursorPos); TBriefDrawGrid(dgPanel).DoMouseMoveScroll(APoint.X, APoint.Y); end; end; procedure TBriefFileView.DoFileRenamed(ADisplayFile: TDisplayFile); begin ADisplayFile.Tag:= -1; end; procedure TBriefFileView.DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes); begin inherited DoFileUpdated(AFile, UpdatedProperties); AFile.Tag:= -1; end; function TBriefFileView.Clone(NewParent: TWinControl): TBriefFileView; begin Result := TBriefFileView.Create(NewParent, Self); end; procedure TBriefFileView.SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); begin inherited SaveConfiguration(AConfig, ANode, ASaveHistory); AConfig.SetAttr(ANode, 'Type', 'brief'); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ucolumnsfileview.pas�������������������������������������������������0000644�0001750�0000144�00000206310�14743153644�021501� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uColumnsFileView; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, Controls, Forms, ExtCtrls, Grids, LMessages, LCLIntf, LCLType, Menus, LCLVersion, uFile, uFileProperty, uFileView, uFileViewWithMainCtrl, uFileSource, uDisplayFile, uColumns, uFileSorting, DCXmlConfig, DCBasicTypes, uTypes, uFileViewWithGrid; type TFunctionDime = function (AColor: TColor): TColor of Object; TColumnsSortDirections = array of TSortDirection; TColumnsFileView = class; { TDrawGridEx } TDrawGridEx = class(TDrawGrid) private FMouseDownY: Integer; FLastMouseMoveTime: QWord; FLastMouseScrollTime: QWord; ColumnsView: TColumnsFileView; function GetGridHorzLine: Boolean; function GetGridVertLine: Boolean; procedure SetGridHorzLine(const AValue: Boolean); procedure SetGridVertLine(const AValue: Boolean); protected procedure DragCanceled; override; procedure DoMouseMoveScroll(X, Y: Integer); procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override; procedure DragOver(Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean); override; procedure InitializeWnd; override; procedure FinalizeWnd; override; procedure DrawColumnText(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); override; procedure DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); override; procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; public ColumnsOwnDim: TFunctionDime; constructor Create(AOwner: TComponent; AParent: TWinControl); reintroduce; procedure UpdateView; function MouseOnGrid(X, Y: LongInt): Boolean; // Returns height of all the header rows. function GetHeaderHeight: Integer; // Adapted from TCustomGrid.GetVisibleGrid only for visible rows. function GetVisibleRows: TRange; {en Retrieves first and last fully visible row number. } function GetFullVisibleRows: TRange; function IsRowVisible(aRow: Integer): Boolean; procedure ScrollHorizontally(ForwardDirection: Boolean); property GridVertLine: Boolean read GetGridVertLine write SetGridVertLine; property GridHorzLine: Boolean read GetGridHorzLine write SetGridHorzLine; end; TColumnResized = procedure (Sender: TObject; ColumnIndex: Integer; ColumnNewsize: integer) of object; { TColumnsFileView } TColumnsFileView = class(TFileViewWithMainCtrl) private FColumnsFunctions: String; FColumnsSortDirections: TColumnsSortDirections; FFileNameColumn: Integer; FExtensionColumn: Integer; pmColumnsMenu: TPopupMenu; dgPanel: TDrawGridEx; FOnColumnResized: TColumnResized; function GetColumnsClass: TPanelColumnsClass; procedure SetRowCount(Count: Integer); procedure SetFilesDisplayItems; procedure SetColumns; procedure MakeVisible(iRow: Integer); procedure MakeActiveVisible; procedure UpdateFooterDetails(AInfo: Boolean); {en Format and cache all columns strings. } procedure MakeColumnsStrings(AFile: TDisplayFile); procedure MakeColumnsStrings(AFile: TDisplayFile; ColumnsClass: TPanelColumnsClass); procedure EachViewUpdateColumns(AFileView: TFileView; UserData: Pointer); {en Translates file sorting by functions to sorting directions of columns. } procedure SetColumnsSortDirections; {en Checks which file properties are needed for displaying. } function GetFilePropertiesNeeded: TFilePropertiesTypes; // -- Events -------------------------------------------------------------- procedure dgPanelBeforeSelection(Sender: TObject; aCol, aRow: Integer); procedure dgPanelHeaderClick(Sender: TObject;IsColumn: Boolean; index: Integer); procedure dgPanelMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure dgPanelMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure dgPanelSelection(Sender: TObject; aCol, aRow: Integer); procedure dgPanelTopLeftChanged(Sender: TObject); procedure dgPanelResize(Sender: TObject); procedure dgPanelHeaderSized(Sender: TObject; IsColumn: Boolean; index: Integer); procedure ColumnsMenuClick(Sender: TObject); procedure CopyFileDetails(AList: TStringList); protected procedure CreateDefault(AOwner: TWinControl); override; procedure BeforeMakeFileList; override; procedure ClearAfterDragDrop; override; procedure DisplayFileListChanged; override; procedure DoColumnResized(Sender: TObject; ColumnIndex: Integer; ColumnNewSize: Integer); procedure DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes = []); override; procedure DoHandleKeyDown(var Key: Word; Shift: TShiftState); override; procedure DoUpdateView; override; procedure FileSourceFileListLoaded; override; function GetActiveFileIndex: PtrInt; override; function GetFileIndexFromCursor(X, Y: Integer; out AtFileList: Boolean): PtrInt; override; function GetFileRect(FileIndex: PtrInt): TRect; override; function GetIconRect(FileIndex: PtrInt): TRect; override; function GetVisibleFilesIndexes: TRange; override; procedure RedrawFile(FileIndex: PtrInt); override; procedure RedrawFile(DisplayFile: TDisplayFile); override; procedure RedrawFiles; override; procedure SetActiveFile(FileIndex: PtrInt; ScrollTo: Boolean; aLastTopRowIndex: PtrInt = -1); override; procedure SetSorting(const NewSortings: TFileSortings); override; procedure ShowRenameFileEdit(var aFile: TFile); override; procedure UpdateRenameFileEditPosition; override; procedure UpdateInfoPanel; override; procedure MouseScrollTimer(Sender: TObject); override; procedure AfterChangePath; override; function GetVariantFileProperties: TDynamicStringArray; override; public ActiveColm: String; ActiveColmSlave: TPanelColumnsClass; isSlave:boolean; Demo: Boolean; //--------------------- constructor Create(AOwner: TWinControl; AFileSource: IFileSource; APath: String; AFlags: TFileViewFlags = []); override; constructor Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags = []); override; constructor Create(AOwner: TWinControl; AFileView: TFileView; AColumnSet: String; AFlags: TFileViewFlags = []); virtual; constructor Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); override; destructor Destroy; override; function Clone(NewParent: TWinControl): TColumnsFileView; override; procedure CloneTo(FileView: TFileView); override; function AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; override; procedure LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); override; procedure SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); override; procedure UpdateColor; override; procedure UpdateColumnsView; procedure SetColumnSet(const AName: String); procedure SetGridFunctionDim(ExternalDimFunction:TFunctionDime); property OnColumnResized: TColumnResized read FOnColumnResized write FOnColumnResized; published procedure cm_SaveFileDetailsToFile(const Params: array of string); procedure cm_CopyFileDetailsToClip(const Params: array of string); end; implementation uses LCLProc, Buttons, Clipbrd, DCStrUtils, uLng, uGlobs, uPixmapManager, uDebug, DCClassesUtf8, dmCommonData, uDCUtils, math, fMain, fOptions, uClipboard, uOrderedFileView, uShowMsg, uFileSourceProperty, uKeyboard, uFileFunctions, uFileViewNotebook, fOptionsCustomColumns; const CELL_PADDING = 2; type TEachViewCallbackReason = (evcrUpdateColumns); TEachViewCallbackMsg = record Reason: TEachViewCallbackReason; UpdatedColumnsSetName: String; NewColumnsSetName: String; // If columns name renamed end; PEachViewCallbackMsg = ^TEachViewCallbackMsg; procedure TColumnsFileView.SetSorting(const NewSortings: TFileSortings); begin inherited SetSorting(NewSortings); SetColumnsSortDirections; end; procedure TColumnsFileView.LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); var ColumnsClass: TPanelColumnsClass; SortColumn: Integer; SortDirection: TSortDirection; ColumnsViewNode: TXmlNode; NewSorting: TFileSortings = nil; Column: TPanelColumn; SortFunctions: TFileFunctions; begin inherited LoadConfiguration(AConfig, ANode); // Try to read new view-specific node. ColumnsViewNode := AConfig.FindNode(ANode, 'ColumnsView'); if Assigned(ColumnsViewNode) then ANode := ColumnsViewNode; ActiveColm := AConfig.GetValue(ANode, 'ColumnsSet', 'Default'); // Load sorting options. ColumnsClass := GetColumnsClass; ANode := ANode.FindNode('Sorting'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('Sort') = 0 then begin if AConfig.TryGetValue(ANode, 'Column', SortColumn) and (SortColumn >= 0) and (SortColumn < ColumnsClass.ColumnsCount) then begin Column := ColumnsClass.GetColumnItem(SortColumn); if Assigned(Column) then begin SortFunctions := ColumnsClass.GetColumnFunctions(SortColumn); SortDirection := TSortDirection(AConfig.GetValue(ANode, 'Direction', Integer(sdNone))); AddSorting(NewSorting, SortFunctions, SortDirection); end; end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; inherited SetSorting(NewSorting); end; end; procedure TColumnsFileView.SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); begin inherited SaveConfiguration(AConfig, ANode, ASaveHistory); AConfig.SetAttr(ANode, 'Type', 'columns'); ANode := AConfig.FindNode(ANode, 'ColumnsView', True); AConfig.ClearNode(ANode); with FileSource do begin if (FileSystem = EmptyStr) or (FileSystem = FS_GENERAL) then AConfig.SetValue(ANode, 'ColumnsSet', ActiveColm); end; end; procedure TColumnsFileView.UpdateColor; begin inherited UpdateColor; dgPanel.GridLineColor:= gColors.FilePanel^.GridLine; end; procedure TColumnsFileView.dgPanelHeaderClick(Sender: TObject; IsColumn: Boolean; index: Integer); var ShiftState : TShiftState; SortingDirection : TSortDirection; ColumnsClass: TPanelColumnsClass; Column: TPanelColumn; NewSorting: TFileSortings; SortFunctions: TFileFunctions; begin if (not IsColumn) or (not gTabHeader) then Exit; ColumnsClass := GetColumnsClass; Column := ColumnsClass.GetColumnItem(Index); if Assigned(Column) then begin NewSorting := Sorting; SortFunctions := ColumnsClass.GetColumnFunctions(Index); if Length(SortFunctions) = 0 then Exit; ShiftState := GetKeyShiftStateEx; if [ssShift, ssCtrl] * ShiftState = [] then begin SortingDirection := GetSortDirection(NewSorting, SortFunctions); if SortingDirection = sdNone then begin // If there is no direction currently, sort "sdDescending" for size and date. // Commonly, we search seek more often for most recent files then older any others. // When sorting by size, often it is to find larger file to make room. // Anyway, it makes DC like TC, and also, Windows Explorer do the same. case SortFunctions[0] of fsfSize, fsfModificationTime, fsfCreationTime, fsfLastAccessTime: SortingDirection:=sdDescending; else SortingDirection:=sdAscending; end; end else begin SortingDirection := ReverseSortDirection(SortingDirection); end; NewSorting := nil; end else begin // If there is no direction currently, sort "sdDescending" for size and date (see previous comment). case SortFunctions[0] of fsfSize, fsfModificationTime, fsfCreationTime, fsfLastAccessTime: SortingDirection:=sdDescending; else SortingDirection:=sdAscending; end; end; AddOrUpdateSorting(NewSorting, SortFunctions, SortingDirection); SetSorting(NewSorting); end; end; procedure TColumnsFileView.dgPanelMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); var I: Integer; begin Handled:= True; if not IsLoadingFileList then begin if (Shift=[ssCtrl])and(gFonts[dcfMain].Size < gFonts[dcfMain].MaxValue) then begin gFonts[dcfMain].Size:=gFonts[dcfMain].Size+1; frmMain.FrameLeft.UpdateView; frmMain.FrameRight.UpdateView; Handled:=True; Exit; end; case gScrollMode of smLineByLine: for I:= 1 to gWheelScrollLines do dgPanel.Perform(LM_VSCROLL, SB_LINEUP, 0); smPageByPage: dgPanel.Perform(LM_VSCROLL, SB_PAGEUP, 0); else Handled:= False; end; end; end; procedure TColumnsFileView.dgPanelMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); var I: Integer; begin Handled:= True; if not IsLoadingFileList then begin if (Shift=[ssCtrl])and(gFonts[dcfMain].Size > gFonts[dcfMain].MinValue) then begin gFonts[dcfMain].Size:=gFonts[dcfMain].Size-1; frmMain.FrameLeft.UpdateView; frmMain.FrameRight.UpdateView; Handled:=True; Exit; end; case gScrollMode of smLineByLine: for I:= 1 to gWheelScrollLines do dgPanel.Perform(LM_VSCROLL, SB_LINEDOWN, 0); smPageByPage: dgPanel.Perform(LM_VSCROLL, SB_PAGEDOWN, 0); else Handled:= False; end; end; end; procedure TColumnsFileView.dgPanelSelection(Sender: TObject; aCol, aRow: Integer); begin dgPanel.Options := dgPanel.Options - [goDontScrollPartCell]; DoFileIndexChanged(aRow - dgPanel.FixedRows, dgPanel.TopRow); if (FSelectedCount = 0) then UpdateFooterDetails(False); end; procedure TColumnsFileView.dgPanelTopLeftChanged(Sender: TObject); begin if not FUpdatingActiveFile then FLastTopRowIndex:= dgPanel.TopRow; Notify([fvnVisibleFilePropertiesChanged]); end; procedure TColumnsFileView.dgPanelResize(Sender: TObject); begin {$IF DEFINED(LCLGTK2)} // Workaround: https://doublecmd.sourceforge.io/mantisbt/view.php?id=1992 if dgPanel.Flat then dgPanel.Invalidate; {$ENDIF} Notify([fvnVisibleFilePropertiesChanged]); end; procedure TColumnsFileView.AfterChangePath; begin inherited AfterChangePath; if not IsLoadingFileList then begin FUpdatingActiveFile := True; dgPanel.Row := 0; FUpdatingActiveFile := False; end; end; function TColumnsFileView.GetVariantFileProperties: TDynamicStringArray; begin Result:= GetColumnsClass.GetColumnsVariants; end; procedure TColumnsFileView.SetGridFunctionDim(ExternalDimFunction: TFunctionDime); begin dgPanel.ColumnsOwnDim:=ExternalDimFunction; end; procedure TColumnsFileView.ShowRenameFileEdit(var aFile: TFile); begin if FFileNameColumn <> -1 then begin if not edtRename.Visible then begin edtRename.Font.Name := GetColumnsClass.GetColumnFontName(FFileNameColumn); edtRename.Font.Size := GetColumnsClass.GetColumnFontSize(FFileNameColumn); edtRename.Font.Style := GetColumnsClass.GetColumnFontStyle(FFileNameColumn); UpdateRenameFileEditPosition; end; inherited ShowRenameFileEdit(AFile); end; end; procedure TColumnsFileView.UpdateRenameFileEditPosition; var ARect: TRect; begin inherited UpdateRenameFileEditPosition; ARect := dgPanel.CellRect(FFileNameColumn, dgPanel.Row); Dec(ARect.Top, 2); Inc(ARect.Bottom, 2); if (gShowIcons <> sim_none) and (FFileNameColumn = 0) then Inc(ARect.Left, gIconsSize + 2); if Succ(FFileNameColumn) = FExtensionColumn then Inc(ARect.Right, dgPanel.ColWidths[FExtensionColumn]); if gInplaceRenameButton and (ARect.Right + edtRename.ButtonWidth < dgPanel.ClientWidth) then Inc(ARect.Right, edtRename.ButtonWidth); edtRename.SetBounds(ARect.Left, ARect.Top, ARect.Width, ARect.Height); end; procedure TColumnsFileView.UpdateInfoPanel; begin inherited UpdateInfoPanel; UpdateFooterDetails(True); end; procedure TColumnsFileView.MouseScrollTimer(Sender: TObject); var APoint: TPoint; begin if DragManager.IsDragging or IsMouseSelecting then begin APoint := dgPanel.ScreenToClient(Mouse.CursorPos); dgPanel.DoMouseMoveScroll(APoint.X, APoint.Y); end; end; procedure TColumnsFileView.RedrawFile(FileIndex: PtrInt); begin dgPanel.InvalidateRow(FileIndex + dgPanel.FixedRows); end; procedure TColumnsFileView.SetColumnsSortDirections; var Columns: TPanelColumnsClass; function SetSortDirection(ASortFunction: TFileFunction; ASortDirection: TSortDirection; Overwrite: Boolean): Boolean; var k, l: Integer; ColumnFunctions: TFileFunctions; begin for k := 0 to Columns.Count - 1 do begin ColumnFunctions := Columns.GetColumnFunctions(k); for l := 0 to Length(ColumnFunctions) - 1 do if ColumnFunctions[l] = ASortFunction then begin if Overwrite or (FColumnsSortDirections[k] = sdNone) then begin FColumnsSortDirections[k] := ASortDirection; Exit(True); end; end; end; Result := False; end; var i, j: Integer; ASortings: TFileSortings; begin Columns := GetColumnsClass; ASortings := Sorting; SetLength(FColumnsSortDirections, Columns.Count); for i := 0 to Length(FColumnsSortDirections) - 1 do FColumnsSortDirections[i] := sdNone; for i := 0 to Length(ASortings) - 1 do begin for j := 0 to Length(ASortings[i].SortFunctions) - 1 do begin // Search for the column containing the sort function and add sorting // by that column. If function is Name and it is not found try searching // for NameNoExtension + Extension and vice-versa. if not SetSortDirection(ASortings[i].SortFunctions[j], ASortings[i].SortDirection, True) then begin if ASortings[i].SortFunctions[j] = fsfName then begin SetSortDirection(fsfNameNoExtension, ASortings[i].SortDirection, False); SetSortDirection(fsfExtension, ASortings[i].SortDirection, False); end else if ASortings[i].SortFunctions[j] in [fsfNameNoExtension, fsfExtension] then begin SetSortDirection(fsfName, ASortings[i].SortDirection, False); end; end; end; end; end; procedure TColumnsFileView.SetFilesDisplayItems; var i: Integer; begin for i := 0 to FFiles.Count - 1 do FFiles[i].DisplayItem := Pointer(i + dgPanel.FixedRows); end; function TColumnsFileView.GetFilePropertiesNeeded: TFilePropertiesTypes; var i, j: Integer; ColumnsClass: TPanelColumnsClass; FileFunctionsUsed: TFileFunctions; begin // By default always use some properties. Result := [fpName, fpSize, // For info panel (total size, selected size) fpAttributes, // For distinguishing directories fpLink, // For distinguishing directories (link to dir) and link icons fpModificationTime // For selecting/coloring files (by SearchTemplate) ]; ColumnsClass := GetColumnsClass; FFileNameColumn := -1; FExtensionColumn := -1; // Scan through all columns. for i := 0 to ColumnsClass.Count - 1 do begin FileFunctionsUsed := ColumnsClass.GetColumnFunctions(i); if Length(FileFunctionsUsed) > 0 then begin // Scan through all functions in the column. for j := Low(FileFunctionsUsed) to High(FileFunctionsUsed) do begin // Add file properties needed to display the function. Result := Result + GetFilePropertyType(FileFunctionsUsed[j]); if (FFileNameColumn = -1) and (FileFunctionsUsed[j] in [fsfName, fsfNameNoExtension]) then FFileNameColumn := i; if (FExtensionColumn = -1) and (FileFunctionsUsed[j] in [fsfExtension]) then FExtensionColumn := i; end; end; end; end; function TColumnsFileView.GetFileRect(FileIndex: PtrInt): TRect; begin Result := dgPanel.CellRect(0, FileIndex + dgPanel.FixedRows); end; function TColumnsFileView.GetIconRect(FileIndex: PtrInt): TRect; begin FileIndex:= FileIndex + dgPanel.FixedRows; Result := dgPanel.CellRect(0, FileIndex); Result.Top:= Result.Top + (Result.Height - gIconsSize) div 2; Result.Left:= Result.Left + CELL_PADDING; Result.Right:= Result.Left + gIconsSize; Result.Bottom:= Result.Bottom + gIconsSize; end; procedure TColumnsFileView.SetRowCount(Count: Integer); begin FUpdatingActiveFile := True; // Remove a fake bottom padding for last row if dgPanel.RowCount > dgPanel.FixedRows then begin dgPanel.RowHeights[dgPanel.RowCount - 1] := dgPanel.DefaultRowHeight; end; dgPanel.RowCount := dgPanel.FixedRows + Count; // Add a fake bottom padding for last row if Count > 0 then begin dgPanel.RowHeights[dgPanel.RowCount - 1] := dgPanel.DefaultRowHeight + CELL_PADDING; end; FUpdatingActiveFile := False; end; procedure TColumnsFileView.SetColumns; var X: Integer; AColumnsFunctions: String; ColumnsClass: TPanelColumnsClass; begin ColumnsClass := GetColumnsClass; dgPanel.Columns.BeginUpdate; try dgPanel.Columns.Clear; AColumnsFunctions:= EmptyStr; for X:= 0 to ColumnsClass.ColumnsCount - 1 do begin with dgPanel.Columns.Add do begin // SizePriority = 0 means don't modify Width with AutoFill. // Last column is always modified if all columns have SizePriority = 0. if (X = 0) and (gAutoSizeColumn = 0) then SizePriority := 1 else SizePriority := 0; Width:= ColumnsClass.GetColumnWidth(X); Title.Caption:= ColumnsClass.GetColumnTitle(X); AColumnsFunctions+= ColumnsClass.GetColumnFuncString(X); end; end; finally dgPanel.Columns.EndUpdate; end; if Assigned(FAllDisplayFiles) then begin // Clear display strings in case columns have changed for X := 0 to FAllDisplayFiles.Count - 1 do begin FAllDisplayFiles[X].DisplayStrings.Clear; end; // Clear variant file properties in case columns have changed if not SameText(FColumnsFunctions, AColumnsFunctions) then begin for X := 0 to FAllDisplayFiles.Count - 1 do begin FAllDisplayFiles[X].FSFile.ClearVariantProperties; end; // Forced to reload variant file properties FSortingProperties := FSortingProperties * fpAll; FilePropertiesNeeded := FilePropertiesNeeded * fpAll; end; end; FColumnsFunctions := AColumnsFunctions; end; procedure TColumnsFileView.MakeVisible(iRow:Integer); var AVisibleRows: TRange; begin with dgPanel do begin AVisibleRows := GetFullVisibleRows; if iRow < AVisibleRows.First then TopRow := iRow; if iRow > AVisibleRows.Last then TopRow := iRow - (AVisibleRows.Last - AVisibleRows.First); end; end; procedure TColumnsFileView.MakeActiveVisible; begin if dgPanel.Row>=0 then MakeVisible(dgPanel.Row); end; procedure TColumnsFileView.UpdateFooterDetails(AInfo: Boolean); var AFile: TFile; AText: String; begin if gColumnsLongInStatus and (FSelectedCount = 0) and (not FlatView) then begin AFile:= CloneActiveFile; if Assigned(AFile) then try if AFile.IsNameValid then begin if gDirBrackets and AFile.IsLinkToDirectory then begin AText := gFolderPrefix + AFile.Name + gFolderPostfix; if Assigned(AFile.LinkProperty) then begin AText += ' -> ' + gFolderPrefix + AFile.LinkProperty.LinkTo + gFolderPostfix; end; end else if AFile.IsLink then begin AText := AFile.Name; if Assigned(AFile.LinkProperty) then begin AText += ' -> ' + AFile.LinkProperty.LinkTo; end; end else if gDirBrackets and AFile.IsDirectory then AText := gFolderPrefix + AFile.Name + gFolderPostfix else begin AText := AFile.Name; end; lblInfo.Caption := AText; end else if not AInfo then begin inherited UpdateInfoPanel; end; finally AFile.Free; end; end; end; procedure TColumnsFileView.SetActiveFile(FileIndex: PtrInt; ScrollTo: Boolean; aLastTopRowIndex: PtrInt = -1); begin if not ScrollTo then dgPanel.SetColRow(dgPanel.Col, FileIndex + dgPanel.FixedRows) else begin dgPanel.Row := FileIndex + dgPanel.FixedRows; if (aLastTopRowIndex <> -1) then dgPanel.TopRow := aLastTopRowIndex; MakeVisible(dgPanel.Row); end; end; procedure TColumnsFileView.dgPanelBeforeSelection(Sender: TObject; aCol, aRow: Integer); begin if dgPanel.IsRowVisible(aRow) then dgPanel.Options := dgPanel.Options + [goDontScrollPartCell]; end; procedure TColumnsFileView.RedrawFile(DisplayFile: TDisplayFile); begin dgPanel.InvalidateRow(PtrInt(DisplayFile.DisplayItem)); end; procedure TColumnsFileView.RedrawFiles; begin dgPanel.Invalidate; end; procedure TColumnsFileView.UpdateColumnsView; var ColumnsClass: TPanelColumnsClass; OldFilePropertiesNeeded: TFilePropertiesTypes; begin // If the ActiveColm set doesn't exist this will retrieve either // the first set or the default set. ColumnsClass := GetColumnsClass; // Set name in case a different set was loaded. ActiveColm := ColumnsClass.Name; SetColumns; SetColumnsSortDirections; dgPanel.FocusRectVisible := ColumnsClass.UseCursorBorder and not ColumnsClass.UseFrameCursor; dgPanel.FocusColor := ColumnsClass.CursorBorderColor; dgPanel.UpdateView; OldFilePropertiesNeeded := FilePropertiesNeeded; FilePropertiesNeeded := GetFilePropertiesNeeded; if FilePropertiesNeeded >= OldFilePropertiesNeeded then begin ReleaseBusy; Notify([fvnVisibleFilePropertiesChanged]); end; end; procedure TColumnsFileView.SetColumnSet(const AName: String); begin if ColSet.Items.IndexOf(AName) >= 0 then begin ActiveColm:= AName; if Assigned(ActiveColmSlave) then begin isSlave:= False; FreeAndNil(ActiveColmSlave); end; UpdateColumnsView; RedrawFiles; end; end; procedure TColumnsFileView.ColumnsMenuClick(Sender: TObject); begin Case (Sender as TMenuItem).Tag of 1001: //All columns, but current one will be selected. begin ShowOptions(TfrmOptionsCustomColumns); end; else begin ActiveColm:=ColSet.Items[(Sender as TMenuItem).Tag]; if Assigned(ActiveColmSlave) then begin isSlave:= False; FreeAndNil(ActiveColmSlave); end; UpdateColumnsView; RedrawFiles; end; end; end; constructor TColumnsFileView.Create(AOwner: TWinControl; AFileSource: IFileSource; APath: String; AFlags: TFileViewFlags = []); begin ActiveColm := 'Default'; FOnColumnResized := nil; inherited Create(AOwner, AFileSource, APath, AFlags); end; constructor TColumnsFileView.Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags = []); begin inherited Create(AOwner, AFileView, AFlags); end; constructor TColumnsFileView.Create(AOwner: TWinControl; AFileView: TFileView; AColumnSet: String; AFlags: TFileViewFlags); begin if ColSet.Items.IndexOf(AColumnSet) >= 0 then ActiveColm := AColumnSet; inherited Create(AOwner, AFileView, AFlags); end; constructor TColumnsFileView.Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); begin inherited Create(AOwner, AConfig, ANode, AFlags); end; procedure TColumnsFileView.CreateDefault(AOwner: TWinControl); begin DCDebug('TColumnsFileView.Create components'); inherited CreateDefault(AOwner); FFileNameColumn := -1; FExtensionColumn := -1; // -- other components dgPanel:=TDrawGridEx.Create(Self, Self); MainControl := dgPanel; // --- dgPanel.OnHeaderClick:=@dgPanelHeaderClick; dgPanel.OnMouseWheelUp := @dgPanelMouseWheelUp; dgPanel.OnMouseWheelDown := @dgPanelMouseWheelDown; dgPanel.OnSelection:= @dgPanelSelection; dgPanel.OnBeforeSelection:= @dgPanelBeforeSelection; dgPanel.OnTopLeftChanged:= @dgPanelTopLeftChanged; dgpanel.OnResize:= @dgPanelResize; dgPanel.OnHeaderSized:= @dgPanelHeaderSized; pmColumnsMenu := TPopupMenu.Create(Self); pmColumnsMenu.Parent := Self; if Assigned(NotebookPage) then begin FOnColumnResized:= @DoColumnResized; end; end; destructor TColumnsFileView.Destroy; begin inherited Destroy; end; function TColumnsFileView.Clone(NewParent: TWinControl): TColumnsFileView; begin Result := TColumnsFileView.Create(NewParent, Self); end; procedure TColumnsFileView.CloneTo(FileView: TFileView); begin if Assigned(FileView) then begin inherited CloneTo(FileView); if FileView is TColumnsFileView then with TColumnsFileView(FileView) do begin FColumnsSortDirections := Self.FColumnsSortDirections; ActiveColm := Self.ActiveColm; ActiveColmSlave := nil; isSlave := False; end; end; end; function TColumnsFileView.AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; begin Result:= inherited AddFileSource(aFileSource, aPath); if Result and (not IsLoadingFileList) then begin FUpdatingActiveFile := True; dgPanel.Row := 0; FUpdatingActiveFile := False; end; end; procedure TColumnsFileView.BeforeMakeFileList; begin inherited; if gListFilesInThread then begin // Display info that file list is being loaded. UpdateInfoPanel; end; end; procedure TColumnsFileView.ClearAfterDragDrop; begin inherited ClearAfterDragDrop; // reset TCustomGrid state dgPanel.FGridState := gsNormal; end; procedure TColumnsFileView.FileSourceFileListLoaded; begin inherited; FUpdatingActiveFile := True; dgPanel.Row := 0; FUpdatingActiveFile := False; end; procedure TColumnsFileView.DisplayFileListChanged; var ScrollTo: Boolean; begin ScrollTo := IsActiveFileVisible; // Row count updates and Content updates should be grouped in one transaction // otherwise, Grids may have subtle synchronization issues. dgPanel.BeginUpdate; SetRowCount(FFiles.Count); // Update grid row count. SetFilesDisplayItems; RedrawFiles; dgPanel.EndUpdate; if SetActiveFileNow(RequestedActiveFile, True, FLastTopRowIndex) then RequestedActiveFile := '' // Requested file was not found, restore position to last active file. else if not SetActiveFileNow(LastActiveFile, ScrollTo, FLastTopRowIndex) then // Make sure at least that the previously active file is still visible after displaying file list. MakeActiveVisible; Notify([fvnVisibleFilePropertiesChanged]); inherited; end; procedure TColumnsFileView.DoColumnResized(Sender: TObject; ColumnIndex: Integer; ColumnNewSize: Integer); procedure UpdateWidth(Notebook: TFileViewNotebook); var I: Integer; ColumnsView: TColumnsFileView; begin for I:= 0 to Notebook.PageCount - 1 do begin if Notebook.View[I] is TColumnsFileView then begin ColumnsView:= TColumnsFileView(Notebook.View[I]); if ColumnsView.ActiveColm = ActiveColm then begin ColumnsView.dgPanel.ColWidths[ColumnIndex]:= ColumnNewSize; end; end; end; end; begin if gColumnsAutoSaveWidth then begin GetColumnsClass.SetColumnWidth(ColumnIndex, ColumnNewSize); UpdateWidth(frmMain.LeftTabs); UpdateWidth(frmMain.RightTabs); end; end; procedure TColumnsFileView.MakeColumnsStrings(AFile: TDisplayFile); begin MakeColumnsStrings(AFile, GetColumnsClass); end; procedure TColumnsFileView.MakeColumnsStrings(AFile: TDisplayFile; ColumnsClass: TPanelColumnsClass); var ACol: Integer; begin AFile.DisplayStrings.Clear; for ACol := 0 to ColumnsClass.Count - 1 do begin AFile.DisplayStrings.Add(ColumnsClass.GetColumnItemResultString( ACol, AFile.FSFile, FileSource)); end; end; procedure TColumnsFileView.EachViewUpdateColumns(AFileView: TFileView; UserData: Pointer); var ColumnsView: TColumnsFileView; PMsg: PEachViewCallbackMsg; begin if AFileView is TColumnsFileView then begin ColumnsView := TColumnsFileView(AFileView); PMsg := UserData; if ColumnsView.ActiveColm = PMsg^.UpdatedColumnsSetName then begin ColumnsView.ActiveColm := PMsg^.NewColumnsSetName; ColumnsView.UpdateColumnsView; ColumnsView.RedrawFiles; end; end; end; procedure TColumnsFileView.DoUpdateView; begin inherited DoUpdateView; UpdateColumnsView; end; function TColumnsFileView.GetActiveFileIndex: PtrInt; begin Result := dgPanel.Row - dgPanel.FixedRows; end; function TColumnsFileView.GetVisibleFilesIndexes: TRange; begin Result := dgPanel.GetVisibleRows; Dec(Result.First, dgPanel.FixedRows); Dec(Result.Last, dgPanel.FixedRows); end; function TColumnsFileView.GetColumnsClass: TPanelColumnsClass; begin if isSlave then Result := ActiveColmSlave else Result := ColSet.GetColumnSet(ActiveColm); end; function TColumnsFileView.GetFileIndexFromCursor(X, Y: Integer; out AtFileList: Boolean): PtrInt; var bTemp: Boolean; iRow, iCol: LongInt; begin with dgPanel do begin bTemp:= AllowOutboundEvents; AllowOutboundEvents:= False; MouseToCell(X, Y, iCol, iRow); AllowOutboundEvents:= bTemp; Result:= IfThen(iRow < 0, InvalidFileIndex, iRow - FixedRows); AtFileList := Y >= GetHeaderHeight; end; end; procedure TColumnsFileView.DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes); begin MakeColumnsStrings(AFile); inherited DoFileUpdated(AFile, UpdatedProperties); end; procedure TColumnsFileView.DoHandleKeyDown(var Key: Word; Shift: TShiftState); var AFile: TDisplayFile; begin case Key of VK_INSERT: begin if not IsEmpty then begin if IsActiveItemValid then begin InvertFileSelection(GetActiveDisplayFile, False); DoSelectionChanged(dgPanel.Row - dgPanel.FixedRows); end; if dgPanel.Row < dgPanel.RowCount-1 then dgPanel.Row := dgPanel.Row + 1; MakeActiveVisible; end; Key := 0; end; // cursors keys in Lynx like mode VK_LEFT: if (Shift = []) then begin if gLynxLike then ChangePathToParent(True) else dgPanel.ScrollHorizontally(False); Key := 0; end; VK_RIGHT: if (Shift = []) then begin if gLynxLike then ChooseFile(GetActiveDisplayFile, True) else dgPanel.ScrollHorizontally(True); Key := 0; end; VK_SPACE: if Shift * KeyModifiersShortcut = [] then begin aFile := GetActiveDisplayFile; if IsItemValid(aFile) then begin if (aFile.FSFile.IsDirectory or aFile.FSFile.IsLinkToDirectory) and not aFile.Selected then begin CalculateSpace(aFile); end; InvertFileSelection(aFile, False); end; if gSpaceMovesDown and (dgPanel.Row + 1 < dgPanel.RowCount) then dgPanel.Row := dgPanel.Row + 1; MakeActiveVisible; DoSelectionChanged(dgPanel.Row - dgPanel.FixedRows); Key := 0; end; end; inherited DoHandleKeyDown(Key, Shift); end; procedure TColumnsFileView.dgPanelHeaderSized(Sender: TObject; IsColumn: Boolean; index: Integer); begin if IsColumn then if Assigned(FOnColumnResized) then begin FOnColumnResized(Self, index, dgPanel.ColWidths[index]); end; end; procedure TColumnsFileView.CopyFileDetails(AList: TStringList); var I: Integer; AFile: TDisplayFile; ColumnsClass: TPanelColumnsClass; procedure AddFile; var J: Integer; S: String; begin if AFile.FSFile.IsNameValid then begin S:= EmptyStr; if AFile.DisplayStrings.Count = 0 then begin MakeColumnsStrings(AFile, ColumnsClass); end; for J:= 0 to AFile.DisplayStrings.Count - 1 do begin S:= S + AFile.DisplayStrings[J] + #09; end; J:= Length(S); if J > 0 then AList.Add(Copy(S, 1, J - 1)); end; end; begin ColumnsClass:= GetColumnsClass; for I:= 0 to FFiles.Count - 1 do begin AFile:= FFiles[I]; if AFile.Selected then AddFile; end; if AList.Count = 0 then begin AFile:= GetActiveDisplayFile; AddFile; end; end; procedure TColumnsFileView.cm_CopyFileDetailsToClip(const Params: array of string); var sl: TStringList; begin if DisplayFiles.Count > 0 then begin sl:= TStringList.Create; try CopyFileDetails(sl); Clipboard.Clear; // prevent multiple formats in Clipboard ClipboardSetText(TrimRightLineEnding(sl.Text, sl.TextLineBreakStyle)); finally FreeAndNil(sl); end; end; end; procedure TColumnsFileView.cm_SaveFileDetailsToFile(const Params: array of string); var AFileName: String; sl: TStringListEx; begin if DisplayFiles.Count > 0 then begin if Length(Params) > 0 then AFileName:= Params[0] else begin with dmComData do begin SaveDialog.DefaultExt := '.txt'; SaveDialog.Filter := '*.txt|*.txt'; SaveDialog.FileName := EmptyStr; if not SaveDialog.Execute then Exit; AFileName:= SaveDialog.FileName; end; end; if (AFileName <> EmptyStr) then try sl:= TStringListEx.Create; try CopyFileDetails(sl); sl.SaveToFile(AFileName); finally FreeAndNil(sl); end; except on E: Exception do msgError(rsMsgErrSaveFile + '-' + E.Message); end; end; end; { TDrawGridEx } constructor TDrawGridEx.Create(AOwner: TComponent; AParent: TWinControl); begin inherited Create(AOwner); ColumnsView := AParent as TColumnsFileView; ColumnsOwnDim := @ColumnsView.DimColor; // Workaround for Lazarus issue 18832. // Set Fixed... before setting ...Count. FixedRows := 0; FixedCols := 0; // Override default values to start with no columns and no rows. RowCount := 0; ColCount := 0; DoubleBuffered := True; Align := alClient; Options := [goFixedVertLine, goFixedHorzLine, goTabs, goRowSelect, goColSizing, goThumbTracking, goSmoothScroll, goHeaderHotTracking, goHeaderPushedLook]; TitleStyle := gColumnsTitleStyle; TabStop := False; Self.Parent := AParent; UpdateView; end; procedure TDrawGridEx.UpdateView; function CalculateDefaultRowHeight: Integer; var OldFont, NewFont: TFont; i: Integer; MaxFontHeight: Integer = 0; CurrentHeight: Integer; ColumnsSet: TPanelColumnsClass; begin // Start with height of the icons. if gShowIcons <> sim_none then MaxFontHeight := gIconsSize; // Get columns settings. with (Parent as TColumnsFileView) do begin if not isSlave then ColumnsSet := ColSet.GetColumnSet(ActiveColm) else ColumnsSet := ActiveColmSlave; end; // Assign temporary font. OldFont := Canvas.Font; NewFont := TFont.Create; Canvas.Font := NewFont; Canvas.Font.PixelsPerInch := NewFont.PixelsPerInch; // Search columns settings for the biggest font (in height). for i := 0 to ColumnsSet.Count - 1 do begin Canvas.Font.Name := ColumnsSet.GetColumnFontName(i); Canvas.Font.Style := ColumnsSet.GetColumnFontStyle(i); Canvas.Font.Size := ColumnsSet.GetColumnFontSize(i); CurrentHeight := Canvas.GetTextHeight('Wg'); MaxFontHeight := Max(MaxFontHeight, CurrentHeight); end; // Restore old font. Canvas.Font := OldFont; FreeAndNil(NewFont); Result := MaxFontHeight + gExtraLineSpan; end; function CalculateTabHeaderHeight: Integer; var OldFont: TFont; begin OldFont := Canvas.Font; Canvas.Font := Font; SetCanvasFont(GetColumnFont(0, True)); Result := Canvas.TextHeight('Wg'); Canvas.Font := OldFont; end; var TabHeaderHeight: Integer; TempRowHeight: Integer; begin Flat := gInterfaceFlat; AutoFillColumns:= gAutoFillColumns; GridVertLine:= gGridVertLine; GridHorzLine:= gGridHorzLine; // Calculate row height. TempRowHeight := CalculateDefaultRowHeight; if TempRowHeight > 0 then DefaultRowHeight := TempRowHeight; // Set rows of header. if gTabHeader then begin if RowCount < 1 then RowCount := 1; FixedRows := 1; TabHeaderHeight := Max(gIconsSize, CalculateTabHeaderHeight); TabHeaderHeight := TabHeaderHeight + 2; // for borders if not gInterfaceFlat then begin TabHeaderHeight := TabHeaderHeight + 2; // additional borders if not flat end; RowHeights[0] := TabHeaderHeight; end else begin if FixedRows > 0 then begin // First reduce number of rows so that the 0'th row, which will be changed // to not-fixed, won't be counted as a row having a file. if RowCount > 1 then begin RowCount := RowCount - 1; FixedRows := 0; end else begin FixedRows := 0; RowCount := 0; end; end; end; FixedCols := 0; // Set column number to zero, must be called after fixed columns change MoveExtend(False, 0, Row); end; procedure TDrawGridEx.InitializeWnd; begin inherited InitializeWnd; ColumnsView.InitializeDragDropEx(Self); end; procedure TDrawGridEx.FinalizeWnd; begin ColumnsView.FinalizeDragDropEx(Self); inherited FinalizeWnd; end; procedure TDrawGridEx.DrawColumnText(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var SortingDirection: TSortDirection; TextStyle: TTextStyle; begin SortingDirection := ColumnsView.FColumnsSortDirections[ACol]; if SortingDirection <> sdNone then begin PixMapManager.DrawBitmap( PixMapManager.GetIconBySortingDirection(SortingDirection), Canvas, aRect.Left, aRect.Top + (RowHeights[aRow] - gIconsSize) div 2); aRect.Left += gIconsSize; end; if gColumnsTitleLikeValues then begin TextStyle := Canvas.TextStyle; TextStyle.Alignment := ColumnsView.GetColumnsClass.GetColumnAlign(ACol); Canvas.TextStyle := TextStyle; end; DrawCellText(aCol, aRow, aRect, aState, GetColumnTitle(aCol)); end; function TDrawGridEx.GetFullVisibleRows: TRange; begin Result.First := GCache.FullVisibleGrid.Top; Result.Last := GCache.FullVisibleGrid.Bottom; end; procedure TDrawGridEx.DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var //shared variables s: string; iTextTop: Integer; AFile: TDisplayFile; FileSourceDirectAccess: Boolean; ColumnsSet: TPanelColumnsClass; //------------------------------------------------------ // begin subprocedures //------------------------------------------------------ procedure DrawFixed; //------------------------------------------------------ var TextStyle: TTextStyle; begin SetCanvasFont(GetColumnFont(aCol, True)); Canvas.Brush.Color := GetColumnColor(ACol, True); TextStyle := Canvas.TextStyle; TextStyle.Layout := tlCenter; Canvas.TextStyle := TextStyle; DefaultDrawCell(aCol, aRow, aRect, aState); end; // of DrawHeader //------------------------------------------------------ procedure DrawIconCell; //------------------------------------------------------ var Y: Integer; IconID: PtrInt; begin if (gShowIcons <> sim_none) then begin IconID := AFile.IconID; // Draw default icon if there is no icon for the file. if IconID = -1 then IconID := PixMapManager.GetDefaultIcon(AFile.FSFile); // center icon vertically Y := aRect.Top + (aRect.Height - gIconsSize) div 2; if gShowHiddenDimmed and AFile.FSFile.IsHidden then PixMapManager.DrawBitmapAlpha(IconID, Canvas, aRect.Left + CELL_PADDING, Y ) else // Draw icon for a file PixMapManager.DrawBitmap(IconID, Canvas, aRect.Left + CELL_PADDING, Y ); // Draw overlay icon for a file if needed if gIconOverlays then begin PixMapManager.DrawBitmapOverlay(AFile, FileSourceDirectAccess, Canvas, aRect.Left + CELL_PADDING, Y ); end; end; s := AFile.DisplayStrings.Strings[ACol]; if gCutTextToColWidth then begin Y:= (aRect.Width) - 2*CELL_PADDING; if (gShowIcons <> sim_none) then Y:= Y - gIconsSize - 2; s:= FitFileName(s, Canvas, AFile.FSFile, Y); end; if (gShowIcons <> sim_none) then Canvas.TextOut(aRect.Left + CELL_PADDING + gIconsSize + 2, iTextTop, s) else Canvas.TextOut(aRect.Left + CELL_PADDING, iTextTop, s); end; //of DrawIconCell //------------------------------------------------------ procedure DrawOtherCell; //------------------------------------------------------ var tw, vTextLeft: Integer; begin s := AFile.DisplayStrings.Strings[ACol]; if gCutTextToColWidth then s := FitOtherCellText(s, Canvas, ARect.Width - 2*CELL_PADDING); case ColumnsSet.GetColumnAlign(ACol) of taRightJustify: begin tw := Canvas.TextWidth(s); vTextLeft := aRect.Right - tw - CELL_PADDING; if aCol = ColCount - 1 then Dec(vTextLeft, CELL_PADDING); Canvas.TextOut(vTextLeft, iTextTop, s); end; taLeftJustify: begin Canvas.TextOut(aRect.Left + CELL_PADDING, iTextTop, s); end; taCenter: begin tw := Canvas.TextWidth(s); Canvas.TextOut((aRect.Left + aRect.Right - tw) div 2, iTextTop, s); end; end; //of case end; //of DrawOtherCell //------------------------------------------------------ procedure PrepareColors; //------------------------------------------------------ var TextColor: TColor = clDefault; BackgroundColor: TColor; IsCursor: Boolean; IsCursorInactive: Boolean; //--------------------- begin Canvas.Font.Name := ColumnsSet.GetColumnFontName(ACol); Canvas.Font.Size := ColumnsSet.GetColumnFontSize(ACol); Canvas.Font.Style := ColumnsSet.GetColumnFontStyle(ACol); Canvas.Font.Quality := ColumnsSet.GetColumnFontQuality(ACol); IsCursor := (gdSelected in aState) and ColumnsView.Active and (not ColumnsSet.UseFrameCursor); IsCursorInactive := (gdSelected in aState) and (not ColumnsView.Active) and (not ColumnsSet.UseFrameCursor); // Set up default background color first. if IsCursor then BackgroundColor := ColumnsSet.GetColumnCursorColor(ACol) else begin if IsCursorInactive AND ColumnsSet.GetColumnUseInactiveSelColor(ACol) then BackgroundColor := ColumnsSet.GetColumnInactiveCursorColor(ACol) else // Alternate rows background color. if odd(ARow) then BackgroundColor := ColumnsSet.GetColumnBackground(ACol) else BackgroundColor := ColumnsSet.GetColumnBackground2(ACol); end; // Set text color. if ColumnsSet.GetColumnOvercolor(ACol) then TextColor := AFile.TextColor; if (TextColor = clDefault) or (TextColor = clNone) then TextColor := ColumnsSet.GetColumnTextColor(ACol); if AFile.Selected then begin if ColumnsSet.GetColumnUseInvertedSelection(ACol) then begin //------------------------------------------------------ if IsCursor OR (IsCursorInactive AND ColumnsSet.GetColumnUseInactiveSelColor(ACol)) then begin TextColor := InvertColor(ColorToRGB(ColumnsSet.GetColumnCursorText(ACol))); end else begin if ColumnsView.Active OR (not ColumnsSet.GetColumnUseInactiveSelColor(ACol)) then BackgroundColor := ColumnsSet.GetColumnMarkColor(ACol) else BackgroundColor := ColumnsSet.GetColumnInactiveMarkColor(ACol); TextColor := ColumnsSet.GetColumnBackground(ACol); end; //------------------------------------------------------ end else begin if ColumnsView.Active OR (not ColumnsSet.GetColumnUseInactiveSelColor(ACol)) then TextColor := ColumnsSet.GetColumnMarkColor(ACol) else TextColor := ColumnsSet.GetColumnInactiveMarkColor(ACol); end; end else if IsCursor then begin TextColor := ColumnsSet.GetColumnCursorText(ACol); end; BackgroundColor := ColumnsOwnDim(BackgroundColor); if AFile.RecentlyUpdatedPct <> 0 then begin if ColorIsLight(BackgroundColor) then begin TextColor := LightColor(TextColor, AFile.RecentlyUpdatedPct); BackgroundColor := LightColor(BackgroundColor, AFile.RecentlyUpdatedPct) end else begin TextColor := DarkColor(TextColor, AFile.RecentlyUpdatedPct); BackgroundColor := DarkColor(BackgroundColor, AFile.RecentlyUpdatedPct); end; end; // Draw background. Canvas.Brush.Color := BackgroundColor; Canvas.FillRect(aRect); Canvas.Font.Color := TextColor; Canvas.Brush.Style := bsClear; end;// of PrepareColors; procedure DrawLines; var delta:integer; begin // Draw frame cursor. Canvas.Pen.Width := ColumnsSet.GetColumnBorderFrameWidth(ACol); if Canvas.Pen.Width<=1 then begin delta:=0; end else begin if odd(Canvas.Pen.Width) then delta:=Canvas.Pen.Width shr 1 else delta:=(Canvas.Pen.Width shr 1)+1; end; if ColumnsSet.UseFrameCursor and (gdSelected in aState) and (ColumnsView.Active OR ColumnsSet.GetColumnUseInactiveSelColor(Acol)) then begin if ColumnsView.Active then Canvas.Pen.Color := ColumnsSet.GetColumnCursorColor(ACol) else Canvas.Pen.Color := ColumnsSet.GetColumnInactiveCursorColor(ACol); if ACol=0 then begin Canvas.Line(aRect.Left + 1, aRect.Top + delta , aRect.Right , aRect.Top + delta ); Canvas.Line(aRect.Left + 1, aRect.Bottom - 1 - delta, aRect.Right, aRect.Bottom - 1 - delta); Canvas.Line(aRect.Left + delta, aRect.Top + delta , aRect.Left + delta, aRect.Bottom - delta - 1); end else if ACol<ColCount-1 then begin Canvas.Line(aRect.Left, aRect.Top + delta , aRect.Right , aRect.Top + delta ); Canvas.Line(aRect.Left, aRect.Bottom - 1 - delta, aRect.Right, aRect.Bottom - 1 - delta); end else begin Canvas.Line(aRect.Left, aRect.Top + delta , aRect.Right - delta - 1, aRect.Top + delta ); Canvas.Line(aRect.Left, aRect.Bottom - 1 - delta, aRect.Right - delta -1, aRect.Bottom - 1 - delta); Canvas.Line(aRect.Right - delta - 1, aRect.Top + delta , aRect.Right - delta - 1, aRect.Bottom - delta - 1); end; end; // Draw drop selection. if ARow - FixedRows = ColumnsView.FDropFileIndex then begin Canvas.Pen.Color := ColumnsSet.GetColumnTextColor(ACol); if ACol=0 then begin Canvas.Line(aRect.Left + 1, aRect.Top + delta , aRect.Right , aRect.Top + delta ); Canvas.Line(aRect.Left + 1, aRect.Bottom - 1 - delta, aRect.Right, aRect.Bottom - 1 - delta); Canvas.Line(aRect.Left + delta, aRect.Top + delta , aRect.Left + delta, aRect.Bottom - delta - 1); end else if ACol<ColCount-1 then begin Canvas.Line(aRect.Left, aRect.Top + delta , aRect.Right , aRect.Top + delta ); Canvas.Line(aRect.Left, aRect.Bottom - 1 - delta, aRect.Right, aRect.Bottom - 1 - delta); end else begin Canvas.Line(aRect.Left, aRect.Top + delta , aRect.Right - delta - 1, aRect.Top + delta ); Canvas.Line(aRect.Left, aRect.Bottom - 1 - delta, aRect.Right - delta -1, aRect.Bottom - 1 - delta); Canvas.Line(aRect.Right - delta - 1, aRect.Top + delta , aRect.Right - delta - 1, aRect.Bottom - delta - 1); end; end; end; procedure DrawExtendedCells; type TCell = record Col: Integer; // column index Rect: TRect; // initial rect LeftBound, // new left bound RightBound: Integer; // new right bound end; procedure GetCellBounds(var ACell: TCell); var CellText: string; CellWidth: Integer; ColAlign: TAlignment; begin CellText := AFile.DisplayStrings[ACell.Col]; CellWidth := Canvas.TextWidth(CellText) + 3*CELL_PADDING; if (ACell.Col = 0) and (gShowIcons <> sim_none) then CellWidth := CellWidth + gIconsSize + 2; ColAlign := ColumnsSet.GetColumnAlign(ACell.Col); if (ColAlign = taLeftJustify) or (ACell.Col = 0) then begin ACell.LeftBound := ACell.Rect.Left; ACell.RightBound := ACell.LeftBound + CellWidth; end else if ColAlign = taRightJustify then begin ACell.RightBound := ACell.Rect.Right; ACell.LeftBound := ACell.RightBound - CellWidth; end else begin ACell.LeftBound := (ACell.Rect.Left + ACell.Rect.Right - CellWidth) div 2; if (ACell.Rect.Left <= ACell.LeftBound) or (not gCutTextToColWidth) then ACell.RightBound := ACell.LeftBound + CellWidth else begin ACell.LeftBound := ACell.Rect.Left; ACell.RightBound := ACell.Rect.Right; end; end; end; procedure FindNextCell(ACurrentCol, ADirection: Integer; out ACell: TCell); var C: Integer; begin C := ACurrentCol + ADirection; while (C >= 0) and (C < ColCount) do begin if (AFile.DisplayStrings[C] <> '') and (ColWidths[C] <> 0) then begin ACell.Col := C; ACell.Rect := CellRect(C, aRow); GetCellBounds(ACell); Exit; end; C := C + ADirection; end; ACell.Col := -1; end; procedure ReconcileBounds(var LCell, RCell: TCell); var LeftEdge: Integer absolute LCell.RightBound; RightEdge: Integer absolute RCell.LeftBound; LeftColEdge: Integer absolute LCell.Rect.Right; begin if (LeftEdge <= RightEdge) or (not gCutTextToColWidth) then Exit; if (RightEdge < LeftColEdge) and (LeftColEdge < LeftEdge) then begin LeftEdge := LeftColEdge; RightEdge := LeftColEdge; end else if LeftEdge <= LeftColEdge then RightEdge := LeftEdge else LeftEdge := RightEdge; end; procedure DrawCell(const ACell: TCell); begin aCol := ACell.Col; aRect.Left := ACell.LeftBound; aRect.Right := ACell.RightBound; if aCol = 0 then DrawIconCell else DrawOtherCell; end; var CCell, LCell, RCell: TCell; begin CCell.Col := aCol; CCell.Rect := aRect; FindNextCell(CCell.Col, -1, LCell); FindNextCell(CCell.Col, +1, RCell); if AFile.DisplayStrings[CCell.Col] = '' then begin if (LCell.Col <> -1) and (RCell.Col <> -1) then ReconcileBounds(LCell, RCell); if (LCell.Col <> -1) and (CCell.Rect.Left < LCell.RightBound) then DrawCell(LCell); if (RCell.Col <> -1) and (RCell.LeftBound < CCell.Rect.Right) then DrawCell(RCell); end else begin GetCellBounds(CCell); if LCell.Col <> -1 then begin ReconcileBounds(LCell, CCell); if CCell.Rect.Left < LCell.RightBound then DrawCell(LCell); end; if RCell.Col <> -1 then begin ReconcileBounds(CCell, RCell); if RCell.LeftBound < CCell.Rect.Right then DrawCell(RCell); end; DrawCell(CCell); end; aCol := CCell.Col; aRect := CCell.Rect; end; //------------------------------------------------------ //end of subprocedures //------------------------------------------------------ begin ColumnsSet := ColumnsView.GetColumnsClass; if gdFixed in aState then begin DrawFixed; // Draw column headers if TitleStyle <> tsNative then DrawCellGrid(aCol, aRow, aRect, aState); end else if ColumnsView.IsFileIndexInRange(ARow - FixedRows) then begin // remove fake padding from last row if aRow = RowCount - 1 then Dec(aRect.Bottom, CELL_PADDING); AFile := ColumnsView.FFiles[ARow - FixedRows]; // substract fixed rows (header) FileSourceDirectAccess := fspDirectAccess in ColumnsView.FileSource.Properties; if AFile.DisplayStrings.Count = 0 then ColumnsView.MakeColumnsStrings(AFile, ColumnsSet); PrepareColors; iTextTop := aRect.Top + (aRect.Height - Canvas.TextHeight('Wg')) div 2; if gExtendCellWidth then DrawExtendedCells else begin if ACol = 0 then DrawIconCell // Draw icon in the first column else DrawOtherCell; end; DrawCellGrid(aCol,aRow,aRect,aState); DrawLines; // brush fake padding for last row if aRow = RowCount - 1 then begin Canvas.Brush.Color := Self.Color; aRect.Top := aRect.Bottom; Inc(aRect.Bottom, CELL_PADDING); Canvas.FillRect(aRect); end; end else begin Canvas.Brush.Color := Self.Color; Canvas.FillRect(aRect); end; end; procedure TDrawGridEx.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); begin // Don't auto adjust layout end; procedure TDrawGridEx.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var I : Integer; Point: TPoint; MI: TMenuItem; FileSystem: String; Background: Boolean; begin if ColumnsView.IsLoadingFileList then Exit; {$IFDEF LCLGTK2} // Workaround for two doubleclicks being sent on GTK. // MouseUp event is sent just after doubleclick, so if we drop // doubleclick events we have to also drop MouseUp events that follow them. if ColumnsView.TooManyDoubleClicks then Exit; {$ENDIF} // Handle only if button-up was not lifted to finish drag&drop operation. if not ColumnsView.FMainControlMouseDown then Exit; inherited MouseUp(Button, Shift, X, Y); ColumnsView.FMainControlMouseDown := False; if ColumnsView.Demo then Exit; if Button = mbRight then begin { If right click on header } if (Y >= 0) and (Y < GetHeaderHeight) then begin //Load Columns into menu ColumnsView.pmColumnsMenu.Items.Clear; if ColSet.Items.Count>0 then begin if Pos('wfx://', ColumnsView.CurrentAddress) = 1 then FileSystem:= Copy(ColumnsView.CurrentAddress, 7, MaxInt) else begin FileSystem:= FS_GENERAL; end; // Current file system specific columns set for I:= 0 to ColSet.Items.Count - 1 do begin if SameText(FileSystem, ColSet.GetColumnSet(I).FileSystem) then begin MI:= TMenuItem.Create(ColumnsView.pmColumnsMenu); MI.Tag:= I; MI.Caption:= ColSet.Items[I]; MI.Checked:= (ColSet.Items[I] = ColumnsView.ActiveColm); MI.OnClick:= @ColumnsView.ColumnsMenuClick; ColumnsView.pmColumnsMenu.Items.Add(MI); end; end; if not SameText(FileSystem, FS_GENERAL) then begin //- if ColumnsView.pmColumnsMenu.Items.Count > 0 then begin MI:=TMenuItem.Create(ColumnsView.pmColumnsMenu); MI.Caption:='-'; ColumnsView.pmColumnsMenu.Items.Add(MI); end; // General columns set for I:= 0 to ColSet.Items.Count - 1 do begin if SameText(FS_GENERAL, ColSet.GetColumnSet(I).FileSystem) then begin MI:= TMenuItem.Create(ColumnsView.pmColumnsMenu); MI.Tag:= I; MI.Caption:= ColSet.Items[I]; MI.Checked:= (ColSet.Items[I] = ColumnsView.ActiveColm); MI.OnClick:= @ColumnsView.ColumnsMenuClick; ColumnsView.pmColumnsMenu.Items.Add(MI); end; end; end; end; //- I:= ColumnsView.pmColumnsMenu.Items.Count - 1; if (I >= 0) and (ColumnsView.pmColumnsMenu.Items[I].Caption <> '-') then begin MI:=TMenuItem.Create(ColumnsView.pmColumnsMenu); MI.Caption:='-'; ColumnsView.pmColumnsMenu.Items.Add(MI); end; //Configure custom columns MI:=TMenuItem.Create(ColumnsView.pmColumnsMenu); MI.Tag:=1001; MI.Caption:=rsMenuConfigureCustomColumns; MI.OnClick:=@ColumnsView.ColumnsMenuClick; ColumnsView.pmColumnsMenu.Items.Add(MI); Point:=ClientToScreen(Classes.Point(0,0)); Point.Y:=Point.Y+GetHeaderHeight; Point.X:=Point.X+X-50; ColumnsView.pmColumnsMenu.PopUp(Point.X,Point.Y); end { If right click on file/directory } else if ((gMouseSelectionButton<>1) or not gMouseSelectionEnabled) then begin Background:= not MouseOnGrid(X, Y); Point := ClientToScreen(Classes.Point(X, Y)); frmMain.Commands.DoContextMenu(ColumnsView, Point.x, Point.y, Background); end else if (gMouseSelectionEnabled and (gMouseSelectionButton = 1)) then begin ColumnsView.tmContextMenu.Enabled:= False; // stop context menu timer end; end { Open folder in new tab on middle click } else if (Button = mbMiddle) and (Y > GetHeaderHeight) and MouseOnGrid(X, Y) then begin frmMain.Commands.cm_OpenDirInNewTab([]); end; end; procedure TDrawGridEx.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin inherited DragOver(Source, X, Y, State, Accept); DoMouseMoveScroll(X, Y); end; procedure TDrawGridEx.MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); begin FLastMouseMoveTime := 0; FLastMouseScrollTime := 0; if ColumnsView.IsLoadingFileList then Exit; {$IFDEF LCLGTK2} // Workaround for two doubleclicks being sent on GTK. // MouseDown event is sent just before doubleclick, so if we drop // doubleclick events we have to also drop MouseDown events that precede them. if ColumnsView.TooManyDoubleClicks then Exit; {$ENDIF} FMouseDownY := Y; ColumnsView.FMainControlMouseDown := True; AllowOutboundEvents := False; inherited MouseDown(Button, Shift, X, Y); AllowOutboundEvents := True; if not Focused then begin if CanSetFocus then SetFocus; end; end; procedure TDrawGridEx.MouseMove(Shift: TShiftState; X, Y: Integer); begin AllowOutboundEvents := False; inherited MouseMove(Shift, X, Y); AllowOutboundEvents := True; if ColumnsView.IsMouseSelecting then DoMouseMoveScroll(X, Y); end; function TDrawGridEx.MouseOnGrid(X, Y: LongInt): Boolean; var bTemp: Boolean; iRow, iCol: LongInt; begin bTemp:= AllowOutboundEvents; AllowOutboundEvents:= False; MouseToCell(X, Y, iCol, iRow); AllowOutboundEvents:= bTemp; Result:= not ((iCol < 0) and (iRow < 0)); end; function TDrawGridEx.GetHeaderHeight: Integer; var i : Integer; begin Result := 0; for i := 0 to FixedRows-1 do Result := Result + RowHeights[i]; if Flat and (BorderStyle = bsSingle) then // TCustomGrid.GetBorderWidth Result := Result + 1; end; function TDrawGridEx.GetGridHorzLine: Boolean; begin Result := goHorzLine in Options; end; function TDrawGridEx.GetGridVertLine: Boolean; begin Result := goVertLine in Options; end; procedure TDrawGridEx.SetGridHorzLine(const AValue: Boolean); begin if AValue then Options := Options + [goHorzLine] else Options := Options - [goHorzLine]; end; procedure TDrawGridEx.SetGridVertLine(const AValue: Boolean); begin if AValue then Options := Options + [goVertLine] else Options := Options - [goVertLine]; end; function TDrawGridEx.GetVisibleRows: TRange; var w: Integer; rc: Integer; begin if (TopRow<0)or(csLoading in ComponentState) then begin Result.First := 0; Result.Last := -1; Exit; end; // visible TopLeft Cell Result.First:=TopRow; Result.Last:=Result.First; rc := RowCount; // Top Margin of next visible Row and Bottom most visible cell if rc>FixedRows then begin w:=RowHeights[Result.First] + GCache.FixedHeight - GCache.TLRowOff; while (Result.Last<rc-1)and(W<GCache.ClientHeight) do begin Inc(Result.Last); W:=W+RowHeights[Result.Last]; end; end else begin Result.Last := Result.First - 1; // no visible cells here end; end; function TDrawGridEx.IsRowVisible(aRow: Integer): Boolean; begin with GCache.FullVisibleGrid do Result:= (Top<=aRow)and(aRow<=Bottom); end; procedure TDrawGridEx.DragCanceled; begin fGridState:= gsNormal; end; procedure TDrawGridEx.DoMouseMoveScroll(X, Y: Integer); procedure Scroll(ScrollCode: SmallInt); var Msg: TLMVScroll; begin Msg.Msg := LM_VSCROLL; Msg.ScrollCode := ScrollCode; Msg.SmallPos := 1; // How many lines scroll Msg.ScrollBar := Handle; Dispatch(Msg); end; var TickCount: QWord; AEvent: SmallInt; begin TickCount := GetTickCount64; if Y < DefaultRowHeight then AEvent := SB_LINEUP else if (Y > ClientHeight - DefaultRowHeight) and (Y - 1 > FMouseDownY) then AEvent := SB_LINEDOWN else begin ColumnsView.tmMouseScroll.Enabled := False; Exit; end; if (FLastMouseMoveTime = 0) then FLastMouseMoveTime := TickCount else if (FLastMouseScrollTime = 0) then FLastMouseScrollTime := TickCount else if (TickCount - FLastMouseMoveTime > 200) and (TickCount - FLastMouseScrollTime > 50) then begin Scroll(AEvent); FLastMouseScrollTime := GetTickCount64; ColumnsView.tmMouseScroll.Enabled := True; if (AEvent = SB_LINEDOWN) then FMouseDownY := -1; end; end; procedure TDrawGridEx.KeyDown(var Key: Word; Shift: TShiftState); var SavedKey: Word; begin if ColumnsView.IsLoadingFileList then begin ColumnsView.HandleKeyDownWhenLoading(Key, Shift); Exit; end; SavedKey := Key; // Set RangeSelecting before cursor is moved. ColumnsView.FRangeSelecting := (ssShift in Shift) and (SavedKey in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT]); // Special case for selection with shift key (works like VK_INSERT) if (SavedKey in [VK_UP, VK_DOWN]) and (ssShift in Shift) then ColumnsView.InvertActiveFile; {$IFDEF LCLGTK2} // Workaround for GTK2 - up and down arrows moving through controls. if Key in [VK_UP, VK_DOWN] then begin if ((Row = RowCount-1) and (Key = VK_DOWN)) or ((Row = FixedRows) and (Key = VK_UP)) then Key := 0; end; {$ENDIF} inherited KeyDown(Key, Shift); if (ColumnsView.FRangeSelecting) and (Row >= FixedRows) then ColumnsView.Selection(SavedKey, Row - FixedRows); end; procedure TDrawGridEx.ScrollHorizontally(ForwardDirection: Boolean); function TryMove(ACol: Integer): Boolean; begin Result := not IscellVisible(ACol, Row); if Result then MoveExtend(False, ACol, Row); end; var i: Integer; begin if ForwardDirection then begin for i := Col + 1 to ColCount - 1 do if TryMove(i) then Break; end else begin for i := Col - 1 downto 0 do if TryMove(i) then Break; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ufileview.pas��������������������������������������������������������0000644�0001750�0000144�00000334577�14743153644�020121� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- FileView, base class of all of them Copyright (C) 2016 Alexander Koblov (alexx2000@mail.ru) 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 } unit uFileView; {$mode objfpc}{$H+} interface uses uFindFiles, Classes, SysUtils, Controls, ExtCtrls, Graphics, ComCtrls, contnrs, fgl, LMessages, uFile, uDisplayFile, uFileSource, uFormCommands, uDragDropEx, DCXmlConfig, DCBasicTypes, DCClassesUtf8, uFileSorting, uFileViewHistory, uFileProperty, uFileViewWorker, uFunctionThread, uFileSystemWatcher, fQuickSearch, DCStringHashListUtf8, uGlobs; type TFileView = class; TFileViewClass = class of TFileView; TChangePathReason = (cprAdd, cprRemove, cprChange); {en Called before path is changed. If it returns @true the paths is changed (and if successful, OnAfterChangePath is called). If it returns @false, the path is not changed. NewFileSource is @nil the last file source is to be removed. } TOnBeforeChangePath = function (FileView: TFileView; NewFileSource: IFileSource; Reason: TChangePathReason; const NewPath : String): Boolean of object; TOnAfterChangePath = procedure (FileView: TFileView) of object; TOnChangeActiveFile = procedure (FileView: TFileView; const aFile : TFile) of object; TOnActivate = procedure (aFileView: TFileView) of object; TOnFileListChanged = procedure (aFileView: TFileView) of object; TDropParams = class; TDragDropType = (ddtInternal, ddtExternal); // Lists all operations supported by dragging and dropping items // in the panel (external, internal and via menu). TDragDropOperation = (ddoCopy, ddoMove, ddoSymLink, ddoHardLink); TFileViewWorkers = specialize TFPGObjectList<TFileViewWorker>; TFileViewFlag = (fvfDelayLoadingFiles, fvfDontLoadFiles, fvfDontWatch); TFileViewFlags = set of TFileViewFlag; TFileViewRequest = (fvrqApplyPendingFilesChanges, // Pending files changes need to be applied to the file list fvrqHashFileList, // Files names need rehashing due to file list changes fvrqMakeDisplayFileList); // Filtered file list needs to be created TFileViewRequests = set of TFileViewRequest; TFileViewNotification = (fvnDisplayFileListChanged, // Filtered file list was created (filter changed, show/hide hidden files option changed, etc.) fvnFileSourceFileListLoaded, // File list was loaded from FileSource fvnFileSourceFileListUpdated, // File list was updated (files added, removed or updated) fvnSelectionChanged, // Files were selected/deselected fvnVisibleFilePropertiesChanged); // Different files or their properties are now visible TFileViewNotifications = set of TFileViewNotification; TFileViewApplyFilterResult = (fvaprRemoved, fvaprInserted, fvaprExisting, fvaprNotExisting); { TMarkApplyOnAllDispatcher } TMarkApplyOnAllDispatcher = (tmaoa_Mark, tmaoa_UnMark, tmaoa_InvertMark); {en Base class for any view of a file or files. There should always be at least one file displayed on the view. } { TFileView } TFileView = class(TCustomControl) private {en History of viewed paths and file sources. Contains: - File sources hierarchy associated with this view. Last element is the file source that is currently being viewed, parent file source is (index-1) and so on up to zero (first file source). - Visited paths history for each file source. Last path is the currently viewed path. } FHistory: TFileViewHistory; FSortings: TFileSortings; {en Which file properties are needed to be displayed for each file. } FFilePropertiesNeeded: TFilePropertiesTypes; FFileViewWorkers: TFileViewWorkers; FFlags: TFileViewFlags; FHashedFiles: TBucketList; //<en Contains pointers to file source files for quick checking if a file object is still valid FHashedNames: TStringHashListUtf8; FPendingFilesChanges: TFPList; FPendingFilesTimer: TTimer; FReloadNeeded: Boolean; //<en If file list should be reloaded FWorkersThread: TFunctionThread; FReloadTimer: TTimer; FLoadFilesStartTime: TDateTime; FLoadFilesFinishTime: TDateTime; FLoadFilesNoDelayCount: Integer; //<en How many reloads have been accepted without delay FNotifications: TFileViewNotifications; FRecentlyUpdatedFiles: TDisplayFiles; //<en Recently updated files. FRecentlyUpdatedFilesTimer: TTimer; FRequests: TFileViewRequests; FUpdateCount: Integer; //<en Nr of times BeginUpdate was called without corresponding EndUpdate FWatcherEventLastTime: TDateTime; FWatcherEventsApplied: Integer; //<en How many filesystem watcher events have been applied immediately before postponing them FActive: Boolean; //<en Is this view active FLastActiveFile: String; //<en Last active file (cursor) {en File name which should be selected. Sometimes the file might not yet exist in the filelist (for example after rename or create), but will be in the list on next reload. } FRequestedActiveFile: String; FFilterOptions: TQuickSearchOptions; FWatchPath: String; FLastMark: String; FLastMarkCaseSensitive: Boolean; FLastMarkIgnoreAccents: Boolean; FLastLoadedFileSource: IFileSource; FLastLoadedPath: String; FLoadingFileListLongTime: Boolean; FMethods: TFormCommands; FForceReload: Boolean; FOnBeforeChangePath : TOnBeforeChangePath; FOnAfterChangePath : TOnAfterChangePath; FOnChangeActiveFile: TOnChangeActiveFile; FOnActivate : TOnActivate; FOnFileListChanged : TOnFileListChanged; FLoadingFileListLongTimer: TTimer; // when not in FlatView Mode, FileName only used as Key for FHashedNames // to save resource; // otherwise, subPath+FileName should be used as Key // to identify files with the same name in different subdirectories function calcFileHashKey(const FileName, APath: String): String; procedure AddFile(const FileName, APath: String; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); procedure AddEventToPendingFilesChanges(const EventData: TFSWatcherEventData); function ApplyFilter(ADisplayFile: TDisplayFile; NewFilesPosition: TNewFilesPosition): TFileViewApplyFilterResult; procedure ApplyPendingFilesChanges(NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); procedure ClearPendingFilesChanges; procedure ClearRecentlyUpdatedFiles; procedure DoOnFileListChanged; procedure EachViewDeactivate(AFileView: TFileView; {%H-}UserData: Pointer); function FileListLoaded: Boolean; function GetCurrentAddress: String; function GetCurrentLocation: String; function GetNotebookPage: TControl; function GetCurrentFileSource: IFileSource; function GetCurrentFileSourceIndex: Integer; function GetCurrentPathIndex: Integer; function GetFileSource(Index: Integer): IFileSource; function GetFileSourcesCount: Integer; function GetFiltered: Boolean; function GetPath(FileSourceIndex, PathIndex: Integer): String; function GetPathsCount(FileSourceIndex: Integer): Integer; function GetSortingProperties: TFilePropertiesTypes; function GetSortingForSorter: TFileSortings; function GetWatcherActive: Boolean; procedure HandleNotifications; procedure HandleRequests; {en Store pointers to file source files in a fast to read structure. } procedure HashFileList; procedure InsertFile(ADisplayFile: TDisplayFile; AFileList: TDisplayFiles; NewFilesPosition: TNewFilesPosition); procedure RemoveFile(ADisplayFile: TDisplayFile); procedure RemoveFile(const FileName, APath: String); procedure RenameFile(const NewFileName, OldFileName, APath: String; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); procedure ResortFile(ADisplayFile: TDisplayFile; AFileList: TDisplayFiles); procedure SetActive(bActive: Boolean); inline; overload; procedure SetActive(bActive, bNotify: Boolean); overload; procedure SetFlags(AValue: TFileViewFlags); procedure SetLoadingFileListLongTime(AValue: Boolean); procedure StartRecentlyUpdatedTimerIfNeeded; procedure StartUpdatePendingTimer; procedure UpdateFile(const FileName, APath: String; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); procedure UpdatedFilesTimerEvent(Sender: TObject); procedure UpdatePath({%H-}UpdateAddressToo: Boolean); procedure UpdatePendingTimerEvent(Sender: TObject); procedure UpdateTitle; procedure VisualizeFileUpdate(AFile: TDisplayFile); {en Assigns the built lists to the file view and displays new the file list. } procedure SetFileList(var NewAllDisplayFiles: TDisplayFiles; var NewFilteredDisplayFiles: TDisplayFiles); procedure EnableWatcher(Enable: Boolean); procedure SetFlatView(AFlatView: Boolean); procedure ActivateEvent(Sender: TObject); function CheckIfDelayReload: Boolean; procedure DoReload; procedure HandleFSWatcherEvent(const EventData: TFSWatcherEventData; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); procedure LoadingFileListTimer(Sender: TObject); procedure ReloadEvent(const aFileSource: IFileSource; const ReloadedPaths: TPathsArray); procedure ReloadTimerEvent(Sender: TObject); procedure WatcherEvent(const EventData: TFSWatcherEventData); protected FFlatView: Boolean; FFileFilter: String; FAllDisplayFiles: TDisplayFiles; //<en List of all files that can be displayed FFiles: TDisplayFiles; //<en List of displayed files (filtered) FSavedSelection: TStringListEx; FSortingProperties: TFilePropertiesTypes; {en Initializes parts of the view common to all creation methods. } procedure CreateDefault(AOwner: TWinControl); virtual; procedure PushRenameEvent(AFile: TFile; const NewFileName: String); procedure AddWorker(const Worker: TFileViewWorker; SetEvents: Boolean = True); procedure DoFileChanged(ADisplayFile: TDisplayFile; APropertiesChanged: TFilePropertiesTypes); virtual; procedure DoFileRenamed(ADisplayFile: TDisplayFile); virtual; procedure BeginUpdate; procedure CalculateSpace(AFile: TDisplayFile); procedure CalculateSpace(var AFileList: TFVWorkerFileList); procedure CalculateSpaceOnUpdate(const UpdatedFile: TDisplayFile; const UserData: Pointer); procedure CancelLastPathChange; procedure ReleaseBusy; procedure ClearFiles; {en Called when display file list (filtered list) has changed. } procedure DisplayFileListChanged; virtual; procedure EndUpdate; procedure EnsureDisplayProperties; virtual; abstract; {en Called after file list has been retrieved from file source. Runs from GUI thread. } procedure FileSourceFileListLoaded; virtual; {en Called when files were added, removed or updated in the filesource file list. } procedure FileSourceFileListUpdated; virtual; function GetCurrentPath: String; virtual; procedure SetCurrentPath(NewPath: String); virtual; function GetActiveDisplayFile: TDisplayFile; virtual; abstract; function GetWorkersThread: TFunctionThread; procedure InvertFileSelection(AFile: TDisplayFile; bNotify: Boolean = True); function IsLoadingFileList: Boolean; inline; function IsVisibleToUser: Boolean; procedure Notify(NewNotifications: TFileViewNotifications); procedure PropertiesRetrieverOnUpdate(const UpdatedFile: TDisplayFile; const UserData: Pointer); procedure Request(NewRequests: TFileViewRequests); {en This function should set active file by reference of TFile or at least by all the properties of the given TFile, in case the object is a clone. It could be useful in case there are multiple files with the same name in the panel and SetActiveFile(String) is not enough. } procedure SetActiveFile(const {%H-}aFile: TFile); virtual; overload; {en Executed before file list has been retrieved. Runs from GUI thread. } procedure BeforeMakeFileList; virtual; function BeginDragExternal(DragFile: TDisplayFile; DragDropSource: uDragDropEx.TDragDropSource; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; procedure ChooseFile(const AFile: TDisplayFile; FolderMode: Boolean = False); virtual; function DimColor(AColor: TColor): TColor; procedure DoActiveChanged; virtual; procedure DoFileUpdated(AFile: TDisplayFile; {%H-}UpdatedProperties: TFilePropertiesTypes = []); virtual; procedure DoHandleKeyDown(var Key: Word; Shift: TShiftState); virtual; {en Handles keys when file list is being loaded. } procedure DoHandleKeyDownWhenLoading(var Key: Word; {%H-}Shift: TShiftState); virtual; procedure DoLoadingFileListLongTime; virtual; procedure DoSelectionChanged; virtual; procedure DoUpdateView; virtual; {en Returns current work type in progress. } function GetCurrentWorkType: TFileViewWorkType; procedure HandleKeyDownWhenLoading(var Key: Word; Shift: TShiftState); function IsActiveItemValid: Boolean; function IsReferenceValid(aFile: TDisplayFile): Boolean; {en Returns True if there are no files shown in the panel. } function IsEmpty: Boolean; inline; {en Returns True if item is not nil and not '..'. May be extended to include other conditions. } function IsItemValid(AFile: TDisplayFile): Boolean; procedure SetSorting(const NewSortings: TFileSortings); virtual; procedure SortAllDisplayFiles; {en Retrieves file list from file source into FAllDisplayFiles. Either runs directly or starts a new thread. } procedure MakeFileSourceFileList; {en Called before changing path. If returns @false the path is not changed. NewFileSource is @nil if the last file source is to be removed. } function BeforeChangePath(NewFileSource: IFileSource; Reason: TChangePathReason; NewPath: String): Boolean; virtual; {en Called after path is changed. } procedure AfterChangePath; virtual; {en Makes a new display file list and redisplays the changed list. } procedure ReDisplayFileList; {en Redraw DisplayFile if it is visible. } procedure RedrawFile(DisplayFile: TDisplayFile); virtual; abstract; procedure RedrawFiles; virtual; abstract; procedure WorkerStarting(const Worker: TFileViewWorker); virtual; procedure WorkerFinished(const Worker: TFileViewWorker); virtual; procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message LM_ERASEBKGND; function GetVariantFileProperties: TDynamicStringArray; virtual; property Active: Boolean read FActive write SetActive; property FilePropertiesNeeded: TFilePropertiesTypes read FFilePropertiesNeeded write FFilePropertiesNeeded; property History: TFileViewHistory read FHistory; property LastActiveFile: String read FLastActiveFile write FLastActiveFile; property RequestedActiveFile: String read FRequestedActiveFile write FRequestedActiveFile; property SortingForSorter: TFileSortings read GetSortingForSorter; property WorkersThread: TFunctionThread read GetWorkersThread; public property DisplayFiles: TDisplayFiles read FFiles; public constructor Create(AOwner: TWinControl; AFileSource: IFileSource; APath: String; AFlags: TFileViewFlags = []); virtual reintroduce; // Constructor for cloning. constructor Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags = []); virtual reintroduce; constructor Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); virtual reintroduce; destructor Destroy; override; procedure Clear; function Clone({%H-}NewParent: TWinControl): TFileView; virtual; procedure CloneTo(AFileView: TFileView); virtual; function AddHistory(aFileSource: IFileSource; aPath: String): Boolean; function AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; virtual; function RemoveCurrentFileSource: Boolean; virtual; procedure RemoveAllFileSources; virtual; {en Assigns the list of file sources and paths into those file sources from another file view. } procedure AssignFileSources(const otherFileView: TFileView); virtual; {en Returns a copy of currently active file. Caller is responsible for freeing it. There should always be at least one file in the view at any time, but what 'active' means depends on the specific view, so ActiveFile may return 'nil' if there is no such file. Usually it is the file pointed to by the cursor or some other indicator. } function CloneActiveFile: TFile; {en A list of all files in the file view. Caller is responsible for freeing the list. } function CloneFiles: TFiles; {en A list of files selected by the user (this should be a subset of displayed files list returned by Files). Caller is responsible for freeing the list. } function CloneSelectedFiles: TFiles; function CloneSelectedDirectories: TFiles; {en A list of files selected by the user (this should be a subset of displayed files list returned by Files). If there are no selected files then the active file pointed to by the cursor is added to the list as the only file. Caller is responsible for freeing the list. } function CloneSelectedOrActiveFiles: TFiles; function CloneSelectedOrActiveDirectories: TFiles; function GetActiveFileName: String; {en Retrieves files from file source again and displays the new list of files. Returns @true if reloading is done, @false if reloading will not be done (for example paths don't match). } function Reload(const PathsToReload: TPathsArray = nil): Boolean; overload; function Reload(const PathToReload: String): Boolean; overload; procedure Reload(AForced: Boolean); procedure ReloadIfNeeded; procedure StopWorkers; virtual; // For now we use here the knowledge that there are tabs. // Config should be independent of that in the future. procedure LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); virtual; procedure SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); virtual; procedure UpdateView; procedure ApplySettings; procedure UpdateColor; virtual; abstract; {en Moves the selection focus to the file specified by aFilePath. @param(aFilePath may be an absolute path to the file or just a file name.) } procedure SetActiveFile({%H-}aFilePath: String); virtual; overload; {en If given path is a path to the directory, then changes current path to the given one; if given path is a path to the file, then changes current path to the path to a given file, and moves the selection to the file. @param(aFilePath may be an absolute path to the directory or to the file) } procedure ChangePathAndSetActiveFile({%H-}aFilePath: String); virtual; overload; procedure CalculateSpaceOfAllDirectories; {en Changes the current path to a parent directory. @param(AllowChangingFileSource If this parameter is @true and current path is the root path of the current file source, then the current file source will be removed (closed) and a previous file source will be displayed.) } procedure ChangePathToParent(AllowChangingFileSource: Boolean); virtual; {en Change the current path to a subdirectory pointed to by aFile. } procedure ChangePathToChild(const aFile: TFile); virtual; procedure ExecuteCommand(CommandName: String; const Params: array of String); virtual; {en Returns @true if at least one file is somehow selected. What "selected" means depends on the concrete file view implementation. (Usually it will be a different method of selecting than ActiveFile.) } function HasSelectedFiles: Boolean; virtual; procedure InvertAll; procedure LoadSelectionFromClipboard; procedure LoadSelectionFromFile(const AFileName: String); procedure MarkCurrentName(bSelect: Boolean); procedure MarkCurrentNameExt(bSelect: Boolean); procedure MarkCurrentExtension(bSelect: Boolean); procedure MarkCurrentPath(bSelect: Boolean); procedure MarkFile(AFile: TDisplayFile; bSelect: Boolean; bNotify: Boolean = True); procedure MarkFiles(bSelect: Boolean); procedure MarkFiles(FromIndex, ToIndex: PtrInt; bSelect: Boolean); procedure MarkApplyOnAllFiles(const MarkApplyOnAllDispatcher: TMarkApplyOnAllDispatcher; MarkFileChecks: TFindFileChecks); procedure MarkGroup(const sMask: String; bSelect: Boolean; pbCaseSensitive:PBoolean = nil; pbIgnoreAccents: PBoolean = nil; pbWindowsInterpretation: PBoolean = nil; pMarkFileChecks: TPFindFileChecks = nil); procedure MarkGroup(bSelect: Boolean; pbCaseSensitive:PBoolean = nil; pbIgnoreAccents: PBoolean = nil; pbWindowsInterpretation: PBoolean = nil; psAttribute:PString = nil); procedure OpenActiveFile; procedure RestoreSelection; procedure SaveSelection; procedure SaveSelectionToFile(const AFileName: String); {en Handles drag&drop operations onto the file view. Does any graphic work and executes operations with dropped files if allowed. Handles freeing DropParams. } procedure DoDragDropOperation(Operation: TDragDropOperation; var DropParams: TDropParams); virtual abstract; procedure GoToHistoryIndex(aFileSourceIndex, aPathIndex: Integer); procedure GoToPrevHistory; procedure GoToNextHistory; procedure SetDragCursor(Shift: TShiftState); virtual; abstract; procedure SetFileFilter(NewFilter: String; NewFilterOptions: TQuickSearchOptions); procedure JustForColorPreviewSetActiveState(bActive: Boolean); property CurrentAddress: String read GetCurrentAddress; property CurrentFileSourceIndex: Integer read GetCurrentFileSourceIndex; property CurrentPath: String read GetCurrentPath write SetCurrentPath; property CurrentPathIndex: Integer read GetCurrentPathIndex; property CurrentLocation: String read GetCurrentLocation; property FileFilter: String read FFileFilter; property FilterOptions: TQuickSearchOptions read FFilterOptions; property Filtered: Boolean read GetFiltered; property FileSource: IFileSource read GetCurrentFileSource; property FileSources[Index: Integer]: IFileSource read GetFileSource; property FileSourcesCount: Integer read GetFileSourcesCount; property Flags: TFileViewFlags read FFlags write SetFlags; property FlatView: Boolean read FFlatView write SetFlatView; property Path[FileSourceIndex, PathIndex: Integer]: String read GetPath; property PathsCount[FileSourceIndex: Integer]: Integer read GetPathsCount; property Sorting: TFileSortings read FSortings write SetSorting; property WatcherActive: Boolean read GetWatcherActive; property NotebookPage: TControl read GetNotebookPage; property OnBeforeChangePath : TOnBeforeChangePath read FOnBeforeChangePath write FOnBeforeChangePath; property OnAfterChangePath : TOnAfterChangePath read FOnAfterChangePath write FOnAfterChangePath; property OnChangeActiveFile : TOnChangeActiveFile read FOnChangeActiveFile write FOnChangeActiveFile; property OnActivate : TOnActivate read FOnActivate write FOnActivate; {en Called when files on the file source in the currently displayed path change (are added, removed or updated). It is not called when simply the list of files is filtered. } property OnFileListChanged : TOnFileListChanged read FOnFileListChanged write FOnFileListChanged; end; { TDropParams } { Parameters passed to functions handling drag&drop. FileList List of files dropped (the class handles freeing it). DropEffect Desired action to take with regard to the files. ScreenDropPoint Point where the drop occurred. DropIntoDirectories If true it is/was allowed to drop into specific directories (directories may have been tracked while dragging). Target path will be modified accordingly if ScreenDropPoint points to a directory in the target panel. SourcePanel If drag drop type is internal, this field points to the source panel. TargetPanel Panel, where the drop occurred. } TDropParams = class public Files: TFiles; DropEffect: TDropEffect; ScreenDropPoint: TPoint; DropIntoDirectories: Boolean; SourcePanel: TFileView; TargetPanel: TFileView; TargetFileSource: IFileSource; TargetPath: String; constructor Create(var aFiles: TFiles; aDropEffect: TDropEffect; aScreenDropPoint: TPoint; aDropIntoDirectories: Boolean; aSourcePanel: TFileView; aTargetPanel: TFileView; aTargetFileSource: IFileSource; aTargetPath: String); destructor Destroy; override; // States, whether the drag&drop operation was internal or external. // If SourcePanel is not nil, then it's assumed it was internal. function GetDragDropType: TDragDropType; end; PDropParams = ^TDropParams; implementation uses Clipbrd, Dialogs, LCLProc, LCLType, Forms, dmCommonData, uShellExecute, fMaskInputDlg, uMasks, DCOSUtils, uOSUtils, DCStrUtils, uDCUtils, uDebug, uLng, uShowMsg, uFileSystemFileSource, uFileSourceUtil, uFileViewNotebook, uSearchTemplate, uKeyboard, uFileFunctions, fMain, uSearchResultFileSource, uFileSourceProperty, uVfsModule, uFileViewWithPanels; const MinimumReloadInterval = 1000; // 1 second UpdateFilelistInterval = 500; constructor TFileView.Create(AOwner: TWinControl; AFileSource: IFileSource; APath: String; AFlags: TFileViewFlags = []); begin DisableAutoSizing; try FFlags := AFlags; CreateDefault(AOwner); FHistory.AddFileSource(AFileSource); ChangePathAndSetActiveFile(aPath); FileSource.AddReloadEventListener(@ReloadEvent); // Update view before making file source file list, // so that file list isn't unnecessarily displayed twice. UpdateView; MakeFileSourceFileList; finally EnableAutoSizing; end; end; constructor TFileView.Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags = []); begin DisableAutoSizing; try FFlags := AFlags; CreateDefault(AOwner); AFileView.CloneTo(Self); if Assigned(FileSource) then FileSource.AddReloadEventListener(@ReloadEvent); UpdateView; finally EnableAutoSizing; end; end; constructor TFileView.Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); begin DisableAutoSizing; try FFlags := AFlags; CreateDefault(AOwner); LoadConfiguration(AConfig, ANode); // Update view before making file source file list, // so that file list isn't unnecessarily displayed twice. UpdateView; if FileSourcesCount > 0 then begin MakeFileSourceFileList; end; finally EnableAutoSizing; end; end; procedure TFileView.CreateDefault(AOwner: TWinControl); begin FMethods := TFormCommands.Create(Self); FHistory := TFileViewHistory.Create; FSavedSelection:= TStringListEx.Create; FLastMark := '*'; FLastMarkCaseSensitive := gbMarkMaskCaseSensitive; FLastMarkIgnoreAccents := gbMarkMaskIgnoreAccents; FFiles := TDisplayFiles.Create(False); FFilterOptions := gQuickSearchOptions; FHashedNames := TStringHashListUtf8.Create(True); FFileViewWorkers := TFileViewWorkers.Create(False); FReloadTimer := TTimer.Create(Self); FReloadTimer.Enabled := False; FReloadTimer.OnTimer := @ReloadTimerEvent; FLoadingFileListLongTimer := TTimer.Create(Self); FLoadingFileListLongTimer.Enabled := False; FLoadingFileListLongTimer.Interval := 2000; FLoadingFileListLongTimer.OnTimer := @LoadingFileListTimer; BorderStyle := bsNone; // Before Create or the window handle may be recreated inherited Create(AOwner); Align := alClient; Parent := AOwner; if Parent is TFileViewPage then (Parent as TFileViewPage).OnActivate := @ActivateEvent; end; destructor TFileView.Destroy; var i: Integer; DbgWorkersThread: TFunctionThread; begin Clear; if Assigned(FWorkersThread) then begin // Wait until all the workers finish. FWorkersThread.Finish; DCDebug('Waiting for workers thread ', hexStr(FWorkersThread)); DbgWorkersThread := FWorkersThread; TFunctionThread.Finalize(FWorkersThread); DCDebug('Finalized workers thread ', hexStr(DbgWorkersThread)); end; // Now all the workers can be safely freed. if Assigned(FFileViewWorkers) then begin for i := 0 to FFileViewWorkers.Count - 1 do begin with FFileViewWorkers[i] do begin if Working then DCDebug('Error: Worker still working.') else if not CanBeDestroyed then DCDebug('Error: Worker cannot be destroyed.'); Free; end; end; FreeAndNil(FFileViewWorkers); end; inherited Destroy; FreeAndNil(FHashedFiles); FreeAndNil(FHashedNames); FreeAndNil(FHistory); FreeAndNil(FSavedSelection); FreeAndNil(FPendingFilesChanges); FreeAndNil(FRecentlyUpdatedFiles); end; function TFileView.Clone(NewParent: TWinControl): TFileView; begin raise Exception.Create('Cannot create object of abstract class'); Result := nil; // For compiler warning. end; procedure TFileView.CloneTo(AFileView: TFileView); var I: Integer; begin if Assigned(AFileView) then begin AFileView.FFlags := FFlags; AFileView.FFlatView := FFlatView; AFileView.FLastLoadedFileSource := FLastLoadedFileSource; AFileView.FLastLoadedPath := FLastLoadedPath; AFileView.FLastMark := FLastMark; AFileView.FLastMarkCaseSensitive := FLastMarkCaseSensitive; AFileView.FLastMarkIgnoreAccents := FLastMarkIgnoreAccents; // FFileSource should have been passed to FileView constructor already. // FMethods are created in FileView constructor. AFileView.OnBeforeChangePath := Self.OnBeforeChangePath; AFileView.OnAfterChangePath := Self.OnAfterChangePath; AFileView.OnActivate := Self.OnActivate; AFileView.OnFileListChanged := Self.OnFileListChanged; for I := 0 to FSavedSelection.Count - 1 do AFileView.FSavedSelection.Add(FSavedSelection.Strings[I]); AFileView.FHistory.Assign(Self.FHistory); AFileView.FSortings := CloneSortings(Self.FSortings); AFileView.FSortingProperties := GetSortingProperties; AFileView.FLastActiveFile := Self.FLastActiveFile; AFileView.FRequestedActiveFile := Self.FRequestedActiveFile; AFileView.FReloadNeeded := Self.FReloadNeeded; if Assigned(Self.FAllDisplayFiles) then begin AFileView.FAllDisplayFiles := Self.FAllDisplayFiles.Clone(True); AFileView.Notify([fvnFileSourceFileListLoaded]); AFileView.Request([fvrqHashFileList]); end; AFileView.FFileFilter := Self.FFileFilter; AFileView.FFilterOptions := Self.FFilterOptions; // FFiles need to be recreated because the filter is not cloned. // This is done in AFileView.UpdateView. // UPDATE: Added filter cloning, is the aforementioned statement relevant now? end; end; function TFileView.AddHistory(aFileSource: IFileSource; aPath: String): Boolean; begin if FileSource.Equals(aFileSource) then FHistory.AddPath(aPath) else begin FHistory.Add(aFileSource, aPath); end; end; procedure TFileView.AddEventToPendingFilesChanges(const EventData: TFSWatcherEventData); function CheckLast(const sFileName: String; const EventType: TFSWatcherEventTypes; bDelete: Boolean): Boolean; var i: Integer; pEvent: PFSWatcherEventData; begin Result := False; for i := FPendingFilesChanges.Count - 1 downto 0 do begin pEvent := PFSWatcherEventData(FPendingFilesChanges[i]); if pEvent^.FileName = sFileName then begin if pEvent^.EventType in EventType then begin Result := True; if bDelete then begin Dispose(pEvent); FPendingFilesChanges.Delete(i); end else Break; end else Break; end; end; end; var pEvent: PFSWatcherEventData; begin if not Assigned(FPendingFilesChanges) then FPendingFilesChanges := TFPList.Create; if (Assigned(FAllDisplayFiles) and (FAllDisplayFiles.Count > 0) and (FPendingFilesChanges.Count > FAllDisplayFiles.Count div 4)) or (FPendingFilesChanges.Count > 100) then begin // Too many changes. Reload the whole file list again. Reload(EventData.Path); end else begin // Remove obsolete events if they exist. case EventData.EventType of fswFileCreated: CheckLast(EventData.FileName, [fswFileChanged, fswFileCreated, fswFileDeleted], True); fswFileDeleted: CheckLast(EventData.FileName, [fswFileChanged, fswFileCreated, fswFileDeleted], True); fswFileChanged: // If FileChanged or FileCreated already exists then new one is not scheduled. // FileCreated will cause update anyway if a file already exists in the filelist. if CheckLast(EventData.FileName, [fswFileChanged, fswFileCreated], False) then Exit; fswFileRenamed: CheckLast(EventData.FileName, [fswFileChanged, fswFileCreated, fswFileDeleted], True); end; New(pEvent); FPendingFilesChanges.Add(pEvent); pEvent^ := EventData; end; end; procedure TFileView.ApplyPendingFilesChanges(NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); var i: Integer; pEvent: PFSWatcherEventData; begin if Assigned(FPendingFilesChanges) then begin BeginUpdate; try // Check if another reload was not issued. if FileListLoaded and (GetCurrentWorkType <> fvwtCreate) then begin for i := 0 to FPendingFilesChanges.Count - 1 do begin pEvent := PFSWatcherEventData(FPendingFilesChanges[i]); // Insert new files at sorted position since the filelist hasn't been // shown to the user yet, so no need to use user setting. HandleFSWatcherEvent(pEvent^, NewFilesPosition, UpdatedFilesPosition); // HandleFSWatcherEvent might call Reload which clears FPendingFilesChanges, so check for it. if not Assigned(FPendingFilesChanges) then Break; end; end; ClearPendingFilesChanges; finally EndUpdate; end; end; end; procedure TFileView.ClearPendingFilesChanges; var pEvent: PFSWatcherEventData; i: Integer; begin if Assigned(FPendingFilesTimer) then FPendingFilesTimer.Enabled := False; if Assigned(FPendingFilesChanges) then begin for i := 0 to FPendingFilesChanges.Count - 1 do begin pEvent := PFSWatcherEventData(FPendingFilesChanges[i]); Dispose(pEvent); end; FreeAndNil(FPendingFilesChanges); end; end; procedure TFileView.ClearRecentlyUpdatedFiles; begin if Assigned(FRecentlyUpdatedFilesTimer) then FRecentlyUpdatedFilesTimer.Enabled := False; if Assigned(FRecentlyUpdatedFiles) then FRecentlyUpdatedFiles.Clear; end; function TFileView.DimColor(AColor: TColor): TColor; begin if (not Active) and (gInactivePanelBrightness < 100) then Result := ModColor(AColor, gInactivePanelBrightness) else if FLoadingFileListLongTime then Result := DarkColor(AColor, 25) else Result := AColor; end; procedure TFileView.DisplayFileListChanged; begin // Empty. end; procedure TFileView.DoActiveChanged; begin // Empty. end; procedure TFileView.DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes); begin RedrawFile(AFile); end; procedure TFileView.DoHandleKeyDown(var Key: Word; Shift: TShiftState); begin case Key of VK_BACK: begin ChangePathToParent(True); Key := 0; end; VK_RETURN, VK_SELECT: begin if (Shift * KeyModifiersShortcut = []) then begin // Only if there are items in the panel. if not IsEmpty then begin ChooseFile(GetActiveDisplayFile); Key := 0; end; end // execute active file in terminal (Shift+Enter) else if (Shift * KeyModifiersShortcut = [ssShift]) then begin if IsActiveItemValid then begin ProcessExtCommandFork(CurrentPath + GetActiveDisplayFile.FSFile.Name, '', CurrentPath, nil, True, True); Key := 0; end; end; end; end; end; procedure TFileView.DoHandleKeyDownWhenLoading(var Key: Word; Shift: TShiftState); begin case Key of VK_BACK: begin ChangePathToParent(True); Key := 0; end; end; end; procedure TFileView.DoLoadingFileListLongTime; begin RedrawFiles; end; function TFileView.FileListLoaded: Boolean; begin Result := Assigned(FAllDisplayFiles); end; procedure TFileView.FileSourceFileListLoaded; begin FLoadingFileListLongTimer.Enabled := False; end; procedure TFileView.FileSourceFileListUpdated; begin // Empty. end; procedure TFileView.Clear; var i: Integer; begin StopWorkers; for i := 0 to FHistory.Count - 1 do FHistory.FileSource[i].RemoveReloadEventListener(@ReloadEvent); ClearRecentlyUpdatedFiles; ClearPendingFilesChanges; RemoveAllFileSources; FreeAndNil(FFiles); FreeAndNil(FAllDisplayFiles); HashFileList; end; procedure TFileView.ClearFiles; begin if Assigned(FAllDisplayFiles) then begin ClearRecentlyUpdatedFiles; ClearPendingFilesChanges; FFiles.Clear; FAllDisplayFiles.Clear; // Clear references to files from the source. HashFileList; Notify([fvnDisplayFileListChanged]); end; end; function TFileView.GetNotebookPage: TControl; begin if Parent is TFileViewPage then Result := TFileViewPage(Parent) else Result := nil; end; function TFileView.calcFileHashKey(const FileName, APath: String): String; var subPath: String; begin if not FFlatView then begin Result := FileName; end else begin subPath := APath.Substring( currentPath.Length ); if subPath<>EmptyStr then subPath := IncludeTrailingPathDelimiter(subPath); Result := subPath + FileName; end; end; procedure TFileView.AddFile(const FileName, APath: String; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); var ADisplayFile: TDisplayFile; AFile: TFile; I: Integer; AFileKey: String; begin AFileKey := calcFileHashKey(FileName, APath); I := FHashedNames.Find(AFileKey); if I < 0 then begin AFile := TFile.Create(APath); AFile.Name := FileName; try FileSource.RetrieveProperties(AFile, FilePropertiesNeeded, GetVariantFileProperties); if FFlatView and AFile.IsDirectory then raise EFileSourceException.Create(EmptyStr); except on EFileSourceException do begin FreeAndNil(AFile); Reload(APath); Exit; end; end; ADisplayFile := TDisplayFile.Create(AFile); FHashedFiles.Add(ADisplayFile, nil); FHashedNames.Add(AFileKey, ADisplayFile); InsertFile(ADisplayFile, FAllDisplayFiles, NewFilesPosition); if not TFileListBuilder.MatchesFilter(ADisplayFile.FSFile, FileFilter, FFilterOptions) then begin InsertFile(ADisplayFile, FFiles, NewFilesPosition); VisualizeFileUpdate(ADisplayFile); Notify([fvnFileSourceFileListUpdated, fvnDisplayFileListChanged]); end else Notify([fvnFileSourceFileListUpdated]); end else UpdateFile(FileName, APath, NewFilesPosition, UpdatedFilesPosition); end; procedure TFileView.RemoveFile(const FileName, APath: String); var I: Integer; begin I := FHashedNames.Find( calcFileHashKey(FileName,APath) ); if I >= 0 then RemoveFile(TDisplayFile(FHashedNames.List[I]^.Data)); end; procedure TFileView.RemoveFile(ADisplayFile: TDisplayFile); begin FHashedNames.Remove( calcFileHashKey(ADisplayFile.FSFile.Name, ADisplayFile.FSFile.Path) ); FHashedFiles.Remove(ADisplayFile); FFiles.Remove(ADisplayFile); FAllDisplayFiles.Remove(ADisplayFile); if Assigned(FRecentlyUpdatedFiles) then FRecentlyUpdatedFiles.Remove(ADisplayFile); Notify([fvnFileSourceFileListUpdated, fvnDisplayFileListChanged]); end; procedure TFileView.RenameFile(const NewFileName, OldFileName, APath: String; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); var ADisplayFile: TDisplayFile; OldIndex, NewIndex: Integer; ANotifications: TFileViewNotifications; OldFileKey, NewFileKey : String; begin OldFileKey := calcFileHashKey(OldFileName,APath); NewFileKey := calcFileHashKey(NewFileName,APath); OldIndex := FHashedNames.Find( OldFileKey ); NewIndex := FHashedNames.Find( NewFileKey ); if OldIndex >= 0 then begin ADisplayFile := TDisplayFile(FHashedNames.List[OldIndex]^.Data); if NewIndex < 0 then begin ADisplayFile.FSFile.Name := NewFileName; FHashedNames.Remove(OldFileKey); FHashedNames.Add(NewFileKey, ADisplayFile); ADisplayFile.Busy:= []; ADisplayFile.IconID := -1; ADisplayFile.Selected := False; ADisplayFile.IconOverlayID := -1; ADisplayFile.TextColor := clNone; ADisplayFile.DisplayStrings.Clear; ResortFile(ADisplayFile, FAllDisplayFiles); DoFileRenamed(ADisplayFile); ANotifications := [fvnFileSourceFileListUpdated]; case ApplyFilter(ADisplayFile, NewFilesPosition) of fvaprInserted, fvaprRemoved: Include(ANotifications, fvnDisplayFileListChanged); fvaprExisting: begin if GetActiveDisplayFile = ADisplayFile then RequestedActiveFile := ADisplayFile.FSFile.FullPath; ResortFile(ADisplayFile, FFiles); VisualizeFileUpdate(ADisplayFile); Include(ANotifications, fvnDisplayFileListChanged); end; end; Notify(ANotifications); end else begin RemoveFile(ADisplayFile); UpdateFile(NewFileName, APath, NewFilesPosition, UpdatedFilesPosition); end; end else begin if NewIndex < 0 then AddFile(NewFileName, APath, NewFilesPosition, UpdatedFilesPosition) else UpdateFile(NewFileName, APath, NewFilesPosition, UpdatedFilesPosition); end; end; procedure TFileView.Request(NewRequests: TFileViewRequests); begin FRequests := FRequests + NewRequests; if FUpdateCount = 0 then HandleRequests; end; procedure TFileView.ResortFile(ADisplayFile: TDisplayFile; AFileList: TDisplayFiles); var I: Integer; begin I := AFileList.Find(ADisplayFile); if I >= 0 then TDisplayFileSorter.ResortSingle(I, AFileList, SortingForSorter); end; procedure TFileView.StartRecentlyUpdatedTimerIfNeeded; begin if Assigned(FRecentlyUpdatedFiles) and (FRecentlyUpdatedFiles.Count > 0) then begin if not Assigned(FRecentlyUpdatedFilesTimer) then begin FRecentlyUpdatedFilesTimer := TTimer.Create(Self); FRecentlyUpdatedFilesTimer.Interval := 50; FRecentlyUpdatedFilesTimer.OnTimer := @UpdatedFilesTimerEvent; end; FRecentlyUpdatedFilesTimer.Enabled := True; end; end; procedure TFileView.StartUpdatePendingTimer; begin if not Assigned(FPendingFilesTimer) then begin FPendingFilesTimer := TTimer.Create(Self); FPendingFilesTimer.Interval := UpdateFilelistInterval; FPendingFilesTimer.OnTimer := @UpdatePendingTimerEvent; end; FPendingFilesTimer.Enabled := True; end; procedure TFileView.UpdateFile(const FileName, APath: String; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); var AFile: TFile; ADisplayFile: TDisplayFile; OldFile: TFile; propertiesChanged: TFilePropertiesTypes; // which property changed I: Integer; ANotifications: TFileViewNotifications; procedure Resort; begin ResortFile(ADisplayFile, FAllDisplayFiles); ResortFile(ADisplayFile, FFiles); end; procedure Update; begin case UpdatedFilesPosition of ufpNoChange: ; // Do nothing ufpSameAsNewFiles: if NewFilesPosition = nfpSortedPosition then Resort else begin FAllDisplayFiles.OwnsObjects := False; FAllDisplayFiles.Remove(ADisplayFile); // Remove only temporarily FAllDisplayFiles.OwnsObjects := True; InsertFile(ADisplayFile, FAllDisplayFiles, NewFilesPosition); FFiles.Remove(ADisplayFile); InsertFile(ADisplayFile, FFiles, NewFilesPosition); end; ufpSortedPosition: Resort; else raise Exception.Create('Unsupported UpdatedFilesPosition setting.'); end; // there are two cases of file update // 1. modified: VisualizeFileUpdate() should be called // 2. no modified: need not Visual Blink if TFileSystemWatcher.CanWatch(FWatchPath) and ((propertiesChanged+[fpLastAccessTime,fpChangeTime])=[fpLastAccessTime,fpChangeTime]) then exit; VisualizeFileUpdate(ADisplayFile); end; begin I := FHashedNames.Find( calcFileHashKey(FileName,APath) ); if I >= 0 then begin ADisplayFile := TDisplayFile(FHashedNames.List[I]^.Data); AFile := ADisplayFile.FSFile; OldFile := AFile.Clone; AFile.ClearProperties; try try FileSource.RetrieveProperties(AFile, FilePropertiesNeeded, GetVariantFileProperties); propertiesChanged:= AFile.Compare(OldFile); if propertiesChanged = [] then Exit; finally FreeAndNil(OldFile); end; except on EFileNotFound do begin RemoveFile(ADisplayFile); Exit; end; on EFileSourceException do begin Exit; end; end; ADisplayFile.TextColor := clNone; ADisplayFile.IconOverlayID := -1; ADisplayFile.DisplayStrings.Clear; ADisplayFile.Busy := ADisplayFile.Busy - [bsProp]; DoFileChanged(ADisplayFile, propertiesChanged); ANotifications := [fvnFileSourceFileListUpdated]; case ApplyFilter(ADisplayFile, NewFilesPosition) of fvaprInserted, fvaprRemoved: Include(ANotifications, fvnDisplayFileListChanged); fvaprExisting: begin Update; Include(ANotifications, fvnDisplayFileListChanged); end; end; Notify(ANotifications); end else AddFile(FileName, APath, NewFilesPosition, UpdatedFilesPosition); end; procedure TFileView.UpdatedFilesTimerEvent(Sender: TObject); var AFile: TDisplayFile; i: Integer = 0; begin while i < FRecentlyUpdatedFiles.Count do begin AFile := FRecentlyUpdatedFiles[i]; if AFile.RecentlyUpdatedPct = 0 then begin FRecentlyUpdatedFiles.Delete(i); end else begin AFile.RecentlyUpdatedPct := AFile.RecentlyUpdatedPct - 10; Inc(i); RedrawFile(AFile); end; end; if i = 0 then FRecentlyUpdatedFilesTimer.Enabled := False; end; procedure TFileView.UpdatePath(UpdateAddressToo: Boolean); begin // Maybe better to do via some notification like FileSourceHasChanged. UpdateView; end; procedure TFileView.UpdatePendingTimerEvent(Sender: TObject); begin FPendingFilesTimer.Enabled := False; ApplyPendingFilesChanges(gNewFilesPosition, gUpdatedFilesPosition); end; procedure TFileView.UpdateTitle; begin if Parent is TFileViewPage then TFileViewPage(Parent).UpdateTitle; end; procedure TFileView.VisualizeFileUpdate(AFile: TDisplayFile); begin if gHighlightUpdatedFiles then begin if not Assigned(FRecentlyUpdatedFiles) then FRecentlyUpdatedFiles := TDisplayFiles.Create(False); if FRecentlyUpdatedFiles.Find(AFile) < 0 then begin FRecentlyUpdatedFiles.Add(AFile); AFile.RecentlyUpdatedPct := 100; end; end; end; function TFileView.GetCurrentAddress: String; begin if FileSourcesCount > 0 then Result := FileSource.CurrentAddress else Result := ''; end; function TFileView.GetCurrentLocation: String; begin if Length(CurrentAddress) = 0 then Result := GetCurrentPath else begin Result := CurrentAddress; if (PathDelim = '/') then {%H-}Result += GetCurrentPath else Result += StringReplace(GetCurrentPath, PathDelim, '/', [rfReplaceAll]); end; end; procedure TFileView.PushRenameEvent(AFile: TFile; const NewFileName: String); begin Self.RenameFile(NewFileName, AFile.Name, AFile.Path, gNewFilesPosition, gUpdatedFilesPosition); end; procedure TFileView.AddWorker(const Worker: TFileViewWorker; SetEvents: Boolean = True); begin FFileViewWorkers.Add(Worker); if SetEvents then begin Worker.OnStarting := @WorkerStarting; Worker.OnFinished := @WorkerFinished; end; end; procedure TFileView.DoFileChanged(ADisplayFile: TDisplayFile; APropertiesChanged: TFilePropertiesTypes); begin // Empty end; procedure TFileView.DoFileRenamed(ADisplayFile: TDisplayFile); begin // Empty end; procedure TFileView.BeginUpdate; begin Inc(FUpdateCount); end; procedure TFileView.CalculateSpace(AFile: TDisplayFile); var AFileList: TFVWorkerFileList; begin AFileList := TFVWorkerFileList.Create; try if IsItemValid(AFile) and AFile.FSFile.IsDirectory then AFileList.AddClone(AFile, AFile); CalculateSpace(AFileList); finally FreeAndNil(AFileList); end; end; procedure TFileView.CalculateSpace(var AFileList: TFVWorkerFileList); var Worker: TFileViewWorker; begin if GetCurrentWorkType = fvwtCreate then Exit; if AFileList.Count > 0 then begin Worker := TCalculateSpaceWorker.Create( FileSource, WorkersThread, @CalculateSpaceOnUpdate, AFileList); AddWorker(Worker); WorkersThread.QueueFunction(@Worker.StartParam); end else FreeAndNil(AFileList); end; procedure TFileView.CalculateSpaceOfAllDirectories; var i: Integer; AFileList: TFVWorkerFileList; AFile: TDisplayFile; begin if IsLoadingFileList then Exit; AFileList := TFVWorkerFileList.Create; try for i := 0 to FFiles.Count - 1 do begin AFile := FFiles[i]; if IsItemValid(AFile) and AFile.FSFile.IsDirectory then AFileList.AddClone(AFile, AFile); end; CalculateSpace(AFileList); finally FreeAndNil(AFileList); end; end; procedure TFileView.CalculateSpaceOnUpdate(const UpdatedFile: TDisplayFile; const UserData: Pointer); var OrigDisplayFile: TDisplayFile; begin OrigDisplayFile := TDisplayFile(UserData); if not IsReferenceValid(OrigDisplayFile) then Exit; // File does not exist anymore (reference is invalid). OrigDisplayFile.FSFile.Size := UpdatedFile.FSFile.Size; DoFileUpdated(OrigDisplayFile, [fpSize]); end; procedure TFileView.CancelLastPathChange; var FSIndex, PathIndex: Integer; begin // Get previous entry in history. FSIndex := FHistory.CurrentFileSourceIndex; PathIndex := FHistory.CurrentPathIndex - 1; while PathIndex < 0 do begin Dec(FSIndex); if FSIndex < 0 then Break; PathIndex := FHistory.PathsCount[FSIndex] - 1; end; // Go to it if it is the same as last loaded file list. if (FSIndex >= 0) and FHistory.FileSource[FSIndex].Equals(FLastLoadedFileSource) and (FHistory.Path[FSIndex, PathIndex] = FLastLoadedPath) then begin // Don't reload file list because we already have it. Flags := Flags + [fvfDontLoadFiles]; GoToHistoryIndex(FSIndex, PathIndex); Flags := Flags - [fvfDontLoadFiles]; end else ClearFiles; end; procedure TFileView.ReleaseBusy; var Index: Integer; begin for Index := 0 to FFiles.Count - 1 do FFiles[Index].Busy:= []; end; procedure TFileView.DoOnFileListChanged; begin if Assigned(OnFileListChanged) then OnFileListChanged(Self); end; procedure TFileView.EndUpdate; begin Dec(FUpdateCount); if (FUpdateCount = 0) and // This condition prevents endless recursion. ((FRequests <> []) or (FNotifications <> [])) then begin BeginUpdate; try HandleRequests; HandleNotifications; finally EndUpdate; end; end; end; function TFileView.GetCurrentPath: String; begin Result := FHistory.CurrentPath; end; procedure TFileView.SetCurrentPath(NewPath: String); begin if (NewPath <> CurrentPath) and BeforeChangePath(FileSource, cprChange, NewPath) then begin FFlatView:= False; EnableWatcher(False); FHistory.AddPath(NewPath); // Sets CurrentPath. AfterChangePath; EnableWatcher(True); {$IFDEF DEBUG_HISTORY} FHistory.DebugShow; {$ENDIF} end; end; procedure TFileView.SetFlags(AValue: TFileViewFlags); var AddedFlags, RemovedFlags: TFileViewFlags; begin if FFlags = AValue then Exit; AddedFlags := AValue - FFlags; RemovedFlags := FFlags - AValue; FFlags := AValue; if fvfDontWatch in AddedFlags then EnableWatcher(False); if ([fvfDelayLoadingFiles, fvfDontLoadFiles] * RemovedFlags <> []) then begin if not (FileListLoaded or (GetCurrentWorkType = fvwtCreate)) then Reload; EnableWatcher(True); end; if fvfDontWatch in RemovedFlags then EnableWatcher(True); end; procedure TFileView.SetLoadingFileListLongTime(AValue: Boolean); begin FLoadingFileListLongTimer.Enabled := False; if FLoadingFileListLongTime <> AValue then begin FLoadingFileListLongTime := AValue; DoLoadingFileListLongTime; end; end; function TFileView.CloneActiveFile: TFile; var aFile: TDisplayFile; begin aFile := GetActiveDisplayFile; if Assigned(aFile) then Result := aFile.FSFile.Clone else Result := nil; end; function TFileView.CloneFiles: TFiles; var i: Integer; begin Result := TFiles.Create(CurrentPath); for i := 0 to FFiles.Count - 1 do begin Result.Add(FFiles[i].FSFile.Clone); end; end; function TFileView.CloneSelectedFiles: TFiles; var i: Integer; begin Result := TFiles.Create(CurrentPath); for i := 0 to FFiles.Count - 1 do begin if FFiles[i].Selected then Result.Add(FFiles[i].FSFile.Clone); end; end; function TFileView.CloneSelectedDirectories: TFiles; var i: Integer; begin Result := TFiles.Create(CurrentPath); for i := 0 to FFiles.Count - 1 do begin if FFiles[i].Selected then if FFiles[i].FSFile.IsDirectory then Result.Add(FFiles[i].FSFile.Clone); end; end; function TFileView.CloneSelectedOrActiveFiles: TFiles; var aFile: TDisplayFile; begin Result := CloneSelectedFiles; Result.Flat := FFlatView; // If no files are selected, add currently active file if it is valid. if (Result.Count = 0) then begin aFile := GetActiveDisplayFile; if IsItemValid(aFile) then Result.Add(aFile.FSFile.Clone); end; end; function TFileView.CloneSelectedOrActiveDirectories: TFiles; var aFile: TDisplayFile; begin Result := CloneSelectedDirectories; // If no directory(ies) is(are) selected, add currently active directory if it is valid. if (Result.Count = 0) then begin aFile := GetActiveDisplayFile; if IsItemValid(aFile) then if aFile.FSFile.IsDirectory then Result.Add(aFile.FSFile.Clone); end; end; function TFileView.GetWorkersThread: TFunctionThread; begin if not Assigned(FWorkersThread) then FWorkersThread := TFunctionThread.Create(False); Result := FWorkersThread; end; procedure TFileView.SaveSelection; var I: Integer; begin FSavedSelection.Clear; for I := 0 to FFiles.Count - 1 do with FFiles[I] do begin if Selected then FSavedSelection.Add(FSFile.Name); end; end; procedure TFileView.SaveSelectionToFile(const AFileName: String); begin with dmComData do begin SaveDialog.DefaultExt := '.txt'; SaveDialog.Filter := '*.txt|*.txt'; SaveDialog.FileName := AFileName; if (AFileName <> EmptyStr) or SaveDialog.Execute then try SaveSelection; FSavedSelection.SaveToFile(SaveDialog.FileName); except on E: Exception do msgError(rsMsgErrSaveFile + '-' + E.Message); end; end; end; procedure TFileView.RestoreSelection; var I: Integer; begin BeginUpdate; try for I := 0 to FFiles.Count - 1 do with FFiles[I] do Selected:= (FSavedSelection.IndexOf(FSFile.Name) >= 0); Notify([fvnSelectionChanged]); finally EndUpdate; end; end; procedure TFileView.InvertFileSelection(AFile: TDisplayFile; bNotify: Boolean = True); begin MarkFile(AFile, not AFile.Selected, bNotify); end; procedure TFileView.InvertAll; var i: Integer; begin BeginUpdate; try for i := 0 to FFiles.Count-1 do InvertFileSelection(FFiles[i]); finally EndUpdate; end; end; procedure TFileView.MarkFile(AFile: TDisplayFile; bSelect: Boolean; bNotify: Boolean = True); begin // Don't check if valid when just unselecting. if not bSelect then begin if not Assigned(AFile) then Exit; end else if not IsItemValid(AFile) then Exit; AFile.Selected := bSelect; if bNotify then Notify([fvnSelectionChanged]); end; procedure TFileView.MarkFiles(bSelect: Boolean); begin MarkFiles(0, FFiles.Count - 1, bSelect); end; procedure TFileView.MarkFiles(FromIndex, ToIndex: PtrInt; bSelect: Boolean); var Index: PtrInt; begin BeginUpdate; try for Index := FromIndex to ToIndex do MarkFile(FFiles[Index], bSelect); finally EndUpdate; end; end; { TFileView.MarkApplyOnAllFiles } procedure TFileView.MarkApplyOnAllFiles(const MarkApplyOnAllDispatcher: TMarkApplyOnAllDispatcher; MarkFileChecks: TFindFileChecks); var Index: PtrInt; bInitialValue: boolean; bSelected: boolean = False; begin BeginUpdate; try for Index := 0 to pred(FFiles.Count) do begin if FFiles[Index].FSFile.Name = '..' then Continue; if CheckFileAttributes(MarkFileChecks, FFiles[Index].FSFile.Attributes) then begin bInitialValue := FFiles[Index].Selected; case MarkApplyOnAllDispatcher of tmaoa_Mark: FFiles[Index].Selected := True; tmaoa_UnMark: FFiles[Index].Selected := False; tmaoa_InvertMark: FFiles[Index].Selected := not FFiles[Index].Selected; end; bSelected := bSelected OR (bInitialValue xor FFiles[Index].Selected); end; end; if bSelected then Notify([fvnSelectionChanged]); finally EndUpdate; end; end; { TFileView.MarkGroup (Where we have all the parameters) } procedure TFileView.MarkGroup(const sMask: String; bSelect: Boolean; pbCaseSensitive:PBoolean = nil; pbIgnoreAccents: PBoolean = nil; pbWindowsInterpretation: PBoolean = nil; pMarkFileChecks: TPFindFileChecks = nil); var I: Integer; MaskList: TMaskList; SearchTemplate: TSearchTemplate = nil; bSelected: Boolean = False; bCaseSensitive, bIgnoreAccents, bWindowsInterpretation: boolean; LocalMarkFileChecks: TFindFileChecks; AOptions: TMaskOptions = []; begin BeginUpdate; try if IsMaskSearchTemplate(sMask) then begin SearchTemplate:= gSearchTemplateList.TemplateByName[sMask]; if Assigned(SearchTemplate) then for I := 0 to FFiles.Count - 1 do begin if FFiles[I].FSFile.Name = '..' then Continue; if SearchTemplate.CheckFile(FFiles[I].FSFile) then begin FFiles[I].Selected := bSelect; bSelected := True; end; end; end else begin if pbCaseSensitive <> nil then bCaseSensitive := pbCaseSensitive^ else bCaseSensitive := gbMarkMaskCaseSensitive; if pbIgnoreAccents <> nil then bIgnoreAccents := pbIgnoreAccents^ else bIgnoreAccents := gbMarkMaskIgnoreAccents; if pbWindowsInterpretation <> nil then bWindowsInterpretation := pbWindowsInterpretation^ else bWindowsInterpretation := gMarkMaskFilterWindows; if pMarkFileChecks<> nil then LocalMarkFileChecks:=pMarkFileChecks^ else LocalMarkFileChecks.Attributes:=nil; if bCaseSensitive then AOptions+= [moCaseSensitive]; if bIgnoreAccents then AOptions+= [moIgnoreAccents]; if bWindowsInterpretation then AOptions+= [moWindowsMask]; MaskList := TMaskList.Create(sMask, ';,', AOptions); for I := 0 to FFiles.Count - 1 do begin if FFiles[I].FSFile.Name = '..' then Continue; if CheckFileAttributes(LocalMarkFileChecks, FFiles[I].FSFile.Attributes) then begin if MaskList.Matches(FFiles[I].FSFile.Name) then begin FFiles[I].Selected := bSelect; bSelected := True; end; end; end; MaskList.Free; end; if bSelected then Notify([fvnSelectionChanged]); finally EndUpdate; end; end; { TFileView.MarkGroup (Where we prompt the user) } procedure TFileView.MarkGroup(bSelect: Boolean; pbCaseSensitive:PBoolean = nil; pbIgnoreAccents: PBoolean = nil; pbWindowsInterpretation: PBoolean = nil; psAttribute:PString = nil); var s, ADlgTitle, sAttribute: String; bCaseSensitive, bIgnoreAccents, bWindowsInterpretation: boolean; MarkSearchTemplateRec: TSearchTemplateRec; MarkFileChecks: TFindFileChecks; begin if not IsEmpty then begin if bSelect then ADlgTitle := rsMarkPlus else ADlgTitle := rsMarkMinus; s := FLastMark; if pbCaseSensitive <> nil then bCaseSensitive := pbCaseSensitive^ else bCaseSensitive := FLastMarkCaseSensitive; if pbIgnoreAccents <> nil then bIgnoreAccents := pbIgnoreAccents^ else bIgnoreAccents := FLastMarkIgnoreAccents; if pbWindowsInterpretation <> nil then bWindowsInterpretation := pbWindowsInterpretation^ else bWindowsInterpretation := gMarkMaskFilterWindows; if psAttribute <> nil then sAttribute := psAttribute^ else if not gMarkShowWantedAttribute then sAttribute:=gMarkDefaultWantedAttribute else sAttribute := gMarkLastWantedAttribute; if ShowExtendedMaskInputDlg(ADlgTitle, rsMaskInput, glsMaskHistory, s, midsFull, bCaseSensitive, bIgnoreAccents, sAttribute) then begin FLastMark := s; FLastMarkCaseSensitive := bCaseSensitive; FLastMarkIgnoreAccents := bIgnoreAccents; gbMarkMaskCaseSensitive := bCaseSensitive; gbMarkMaskIgnoreAccents := bIgnoreAccents; if (psAttribute = nil) AND gMarkShowWantedAttribute then gMarkLastWantedAttribute:=sAttribute; MarkSearchTemplateRec.AttributesPattern := sAttribute; AttrsPatternOptionsToChecks(MarkSearchTemplateRec, MarkFileChecks); MarkGroup(s, bSelect, @bCaseSensitive, @bIgnoreAccents, @bWindowsInterpretation, @MarkFileChecks); end; end; end; procedure TFileView.MarkCurrentExtension(bSelect: Boolean); var sGroup: String; bCaseSensitive: boolean = false; bIgnoreAccents: boolean = false; bWindowsInterpretation: boolean = false; begin if IsActiveItemValid then begin sGroup := GetActiveDisplayFile.FSFile.Extension; if sGroup <> '' then sGroup := '.' + sGroup; MarkGroup('*' + sGroup, bSelect, @bCaseSensitive, @bIgnoreAccents, @bWindowsInterpretation); end; end; procedure TFileView.MarkCurrentPath(bSelect: Boolean); var I: Integer; sPath: String; bSelected: Boolean = False; begin if IsActiveItemValid then begin sPath := GetActiveDisplayFile.FSFile.Path; BeginUpdate; try for I := 0 to FFiles.Count - 1 do begin if FFiles[I].FSFile.IsDirectory then Continue; if mbCompareFileNames(FFiles[I].FSFile.Path, sPath) then begin FFiles[I].Selected := bSelect; bSelected := True; end; end; if bSelected then Notify([fvnSelectionChanged]); finally EndUpdate; end; end; end; function TFileView.IsVisibleToUser: Boolean; begin if NotebookPage is TFileViewPage then Result := TFileViewPage(NotebookPage).IsActive else Result := True; end; procedure TFileView.PropertiesRetrieverOnUpdate(const UpdatedFile: TDisplayFile; const UserData: Pointer); var propType: TFilePropertyType; aFile: TFile; OrigDisplayFile: TDisplayFile; begin OrigDisplayFile := TDisplayFile(UserData); if not IsReferenceValid(OrigDisplayFile) then Exit; // File does not exist anymore (reference is invalid). aFile := OrigDisplayFile.FSFile; {$IF (fpc_version>2) or ((fpc_version=2) and (fpc_release>4))} // This is a bit faster. for propType in UpdatedFile.FSFile.AssignedProperties - aFile.AssignedProperties do {$ELSE} for propType := Low(TFilePropertyType) to High(TFilePropertyType) do if (propType in UpdatedFile.FSFile.AssignedProperties) and (not (propType in aFile.AssignedProperties)) then {$ENDIF} begin aFile.Properties[propType] := UpdatedFile.FSFile.ReleaseProperty(propType); end; if UpdatedFile.IconID <> -1 then OrigDisplayFile.IconID := UpdatedFile.IconID; if UpdatedFile.IconOverlayID <> -1 then OrigDisplayFile.IconOverlayID := UpdatedFile.IconOverlayID; if UpdatedFile.TextColor <> clNone then OrigDisplayFile.TextColor := UpdatedFile.TextColor; DoFileUpdated(OrigDisplayFile); OrigDisplayFile.Busy:= OrigDisplayFile.Busy - [bsProp]; end; function TFileView.GetActiveFileName: String; var aFile: TDisplayFile; begin aFile := GetActiveDisplayFile; if Assigned(aFile) then Result := aFile.FSFile.Name else Result := ''; end; procedure TFileView.SetActiveFile(const aFile: TFile); begin end; procedure TFileView.SetActiveFile(aFilePath: String); begin end; procedure TFileView.ChangePathAndSetActiveFile(aFilePath: String); begin end; procedure TFileView.SetActive(bActive, bNotify: Boolean); begin if FActive <> bActive then begin FActive := bActive; DoActiveChanged; end; if bActive and bNotify then begin // Deactivate all other views. frmMain.ForEachView(@EachViewDeactivate, nil); if Assigned(OnActivate) then OnActivate(Self); end; end; procedure TFileView.SetActive(bActive: Boolean); begin SetActive(bActive, True); end; procedure TFileView.JustForColorPreviewSetActiveState(bActive: Boolean); begin SetActive(bActive, False); end; procedure TFileView.SetSorting(const NewSortings: TFileSortings); var SortingProperties: TFilePropertiesTypes; begin FSortings := CloneSortings(NewSortings); if not IsLoadingFileList then begin SortingProperties:= GetSortingProperties; // Force reload if new sorting properties needed FForceReload:= (SortingProperties <> []) and (SortingProperties <> FSortingProperties); FSortingProperties:= SortingProperties; if FForceReload then Reload() else begin SortAllDisplayFiles; ReDisplayFileList; end; end; end; procedure TFileView.SortAllDisplayFiles; begin TDisplayFileSorter.Sort(FAllDisplayFiles, SortingForSorter); end; procedure TFileView.MakeFileSourceFileList; var Worker: TFileViewWorker; AThread: TFunctionThread = nil; ClonedDisplayFiles: TDisplayFiles = nil; DisplayFilesHashed: TStringHashListUtf8 = nil; i: Integer; begin if (csDestroying in ComponentState) or (FileSourcesCount = 0) or ([fvfDelayLoadingFiles, fvfDontLoadFiles] * Flags <> []) then Exit; {$IFDEF timeFileView} filelistTime := GetTickCount64; filelistPrevTime := filelistTime; filelistLoaderTime := filelistTime; DCDebug('--------- Start ---------'); {$ENDIF} StopWorkers; if gListFilesInThread and not (fspListOnMainThread in FileSource.GetProperties) then AThread := GetWorkersThread; if FileSource.Equals(FLastLoadedFileSource) and (FLastLoadedPath = CurrentPath) and (FAllDisplayFiles.Count > 0) and (FForceReload = False) then begin // Clone all properties of display files, but don't clone the FS files // themselves because new ones will be retrieved from FileSource. ClonedDisplayFiles := FAllDisplayFiles.Clone(False); DisplayFilesHashed := TStringHashListUtf8.Create(True); // Map filename to display file. for i := 0 to FAllDisplayFiles.Count - 1 do DisplayFilesHashed.Add(FAllDisplayFiles[i].FSFile.FullPath, ClonedDisplayFiles[i]); end; // Drop FForceReload flag FForceReload := False; Worker := TFileListBuilder.Create( FileSource, CurrentFileSourceIndex, FileFilter, FilterOptions, CurrentPath, SortingForSorter, FlatView, AThread, FSortingProperties, GetVariantFileProperties, @SetFileList, ClonedDisplayFiles, DisplayFilesHashed); AddWorker(Worker); ClearPendingFilesChanges; if gListFilesInThread and not (fspListOnMainThread in FileSource.GetProperties) then begin ClearRecentlyUpdatedFiles; BeforeMakeFileList; AThread.QueueFunction(@Worker.StartParam); end else begin BeforeMakeFileList; Worker.Start; end; end; function TFileView.ApplyFilter(ADisplayFile: TDisplayFile; NewFilesPosition: TNewFilesPosition): TFileViewApplyFilterResult; var bFilterOut: Boolean; FilteredFilesIndex: Integer; begin bFilterOut := TFileListBuilder.MatchesFilter(ADisplayFile.FSFile, FileFilter, FFilterOptions); FilteredFilesIndex := FFiles.Find(ADisplayFile); if FilteredFilesIndex >= 0 then begin if bFilterOut then begin FFiles.Delete(FilteredFilesIndex); if Assigned(FRecentlyUpdatedFiles) then FRecentlyUpdatedFiles.Remove(ADisplayFile); Result := fvaprRemoved; end else Result := fvaprExisting; end else if not bFilterOut then begin InsertFile(ADisplayFile, FFiles, NewFilesPosition); VisualizeFileUpdate(ADisplayFile); Result := fvaprInserted; end else Result := fvaprNotExisting; end; procedure TFileView.BeforeMakeFileList; begin FLoadingFileListLongTimer.Enabled := True; end; function TFileView.BeginDragExternal(DragFile: TDisplayFile; DragDropSource: uDragDropEx.TDragDropSource; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; var fileNamesList: TStringList; i: Integer; begin Result := False; if Assigned(DragDropSource) then begin fileNamesList := TStringList.Create; try if IsItemValid(DragFile) = True then begin for i := 0 to FFiles.Count-1 do begin if FFiles[i].Selected then fileNamesList.Add(FFiles[i].FSFile.FullPath); end; // If there were no files selected add the dragged file. if fileNamesList.Count = 0 then fileNamesList.Add(DragFile.FSFile.FullPath); // Initiate external drag&drop operation. Result := DragDropSource.DoDragDrop(fileNamesList, MouseButton, ScreenStartPoint); // Refresh source file panel after drop to (possibly) another application // (files could have been moved for example). // 'draggedFileItem' is invalid after this. Reload; end; finally FreeAndNil(fileNamesList); end; end; end; procedure TFileView.ChooseFile(const AFile: TDisplayFile; FolderMode: Boolean = False); var FSFile: TFile; begin if Assigned(AFile) and not IsLoadingFileList then begin FSFile := AFile.FSFile.Clone; try if FSFile.Name = '..' then ChangePathToParent(True) else if FSFile.IsLinkToDirectory then ChooseSymbolicLink(Self, FSFile) else if FSFile.IsDirectory then ChangePathToChild(FSFile) else if not FolderMode then try uFileSourceUtil.ChooseFile(Self, FileSource, FSFile); except on e: EInvalidCommandLine do MessageDlg(rsMsgInvalidCommandLine, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0); on e: Exception do MessageDlg('Error', e.Message, mtError, [mbOK], 0); end; finally FSFile.Free; end; end; end; procedure TFileView.DoSelectionChanged; begin // Empty. end; procedure TFileView.DoUpdateView; begin // Empty. end; procedure TFileView.EachViewDeactivate(AFileView: TFileView; UserData: Pointer); var ThisFileViewPage, OtherFileViewPage: TFileViewPage; begin if AFileView <> Self then begin ThisFileViewPage := TFileViewPage(GetNotebookPage); OtherFileViewPage := TFileViewPage(AFileView.GetNotebookPage); // Pages on the same notebook set to active and others to not active. if Assigned(ThisFileViewPage) and Assigned(OtherFileViewPage) then AFileView.SetActive(ThisFileViewPage.Notebook = OtherFileViewPage.Notebook, False); end; end; function TFileView.GetCurrentWorkType: TFileViewWorkType; var i: Integer; begin if Assigned(FFileViewWorkers) then begin for i := 0 to FFileViewWorkers.Count - 1 do if FFileViewWorkers[i].Working then Exit(FFileViewWorkers[i].WorkType); end; Result := fvwtNone; end; procedure TFileView.HashFileList; var i: Integer; AFile: TFile; begin // Cannot use FHashedFiles.Clear because it also destroys the buckets. FHashedFiles.Free; // TBucketList seems to do fairly well without needing a proper hash table. FHashedFiles := TBucketList.Create(bl256); FHashedNames.Clear; if Assigned(FAllDisplayFiles) then begin for i := 0 to FAllDisplayFiles.Count - 1 do begin AFile := FAllDisplayFiles[i].FSFile; FHashedFiles.Add(FAllDisplayFiles[i], nil); FHashedNames.Add( calcFileHashKey(AFile.Name,AFile.Path) , FAllDisplayFiles[i] ); end; end; end; procedure TFileView.InsertFile(ADisplayFile: TDisplayFile; AFileList: TDisplayFiles; NewFilesPosition: TNewFilesPosition); procedure InsertAfterUpDir; var i, InsertPos: Integer; begin InsertPos := AFileList.Count; for i := 0 to AFileList.Count - 1 do begin if (AFileList[i].FSFile.Name <> '..') and (AFileList[i].FSFile.Name <> '.') then begin InsertPos := i; Break; end; end; AFileList.List.Insert(InsertPos, ADisplayFile); end; procedure InsertIntoSortedPosition; begin TDisplayFileSorter.InsertSort(ADisplayFile, AFileList, SortingForSorter); end; var EmptySortings: TFileSortings = nil; begin if ADisplayFile.FSFile.IsDirectory or ADisplayFile.FSFile.IsLinkToDirectory then InsertIntoSortedPosition else case NewFilesPosition of nfpTop: InsertAfterUpDir; nfpTopAfterDirectories: if gSortFolderMode <> sfmSortLikeFile then // Will only sort by directory attribute. TDisplayFileSorter.InsertSort(ADisplayFile, AFileList, EmptySortings, True) else InsertIntoSortedPosition; nfpSortedPosition: InsertIntoSortedPosition; nfpBottom: AFileList.Add(ADisplayFile); else raise Exception.Create('Unsupported NewFilesPosition setting.'); end; end; function TFileView.HasSelectedFiles: Boolean; var i: Integer; begin for i := 0 to FFiles.Count - 1 do begin if FFiles[i].Selected then Exit(True); end; Result := False; end; function TFileView.IsActiveItemValid:Boolean; begin Result := IsItemValid(GetActiveDisplayFile); end; function TFileView.IsReferenceValid(aFile: TDisplayFile): Boolean; begin Result := FHashedFiles.Exists(aFile); end; function TFileView.IsEmpty: Boolean; begin Result := (FFiles.Count = 0); end; function TFileView.IsItemValid(AFile: TDisplayFile): Boolean; begin if Assigned(AFile) and (AFile.FSFile.Name <> '..') then Result := True else Result := False; end; function TFileView.IsLoadingFileList: Boolean; begin Result := GetCurrentWorkType = fvwtCreate; end; function TFileView.Reload(const PathsToReload: TPathsArray = nil): Boolean; var i: Integer; begin if csDestroying in ComponentState then Exit(False); if Assigned(PathsToReload) then begin Result := False; for i := Low(PathsToReload) to High(PathsToReload) do if IsInPath(PathsToReload[i], CurrentPath, True, True) then begin Result := True; Break; end; if not Result then Exit; end; if FReloadTimer.Enabled then begin // Reload is already scheduled. Result := True; end else if CheckIfDelayReload then begin // Delay reloading. Result := False; FReloadNeeded := True; end else begin if GetCurrentWorkType = fvwtCreate then begin Result := False; // Allow interrupting loading a few times. if FLoadFilesNoDelayCount < 2 then begin Inc(FLoadFilesNoDelayCount); DoReload; end else begin // Let current loading finish and another will be scheduled after delay via timer. FReloadNeeded := True; end; end else begin Result := True; if DateTimeToTimeStamp(SysUtils.Now - FLoadFilesFinishTime).Time > MinimumReloadInterval then begin FLoadFilesNoDelayCount := 0; DoReload; end // Allow a few reloads in quick succession. else if FLoadFilesNoDelayCount < 4 then begin Inc(FLoadFilesNoDelayCount); DoReload; end else begin FReloadTimer.Interval := MinimumReloadInterval; FReloadTimer.Enabled := True; end; end; end; end; function TFileView.Reload(const PathToReload: String): Boolean; var Paths: TPathsArray; begin SetLength(Paths, 1); Paths[0] := PathToReload; Result := Reload(Paths); end; procedure TFileView.Reload(AForced: Boolean); begin FForceReload:= AForced; DoReload; end; procedure TFileView.ReloadIfNeeded; begin if FReloadNeeded then Reload; end; procedure TFileView.StopWorkers; var i: Integer = 0; begin // Abort any working workers and destroy those that have finished. while i < FFileViewWorkers.Count do begin if FFileViewWorkers[i].CanBeDestroyed then begin FFileViewWorkers[i].Free; FFileViewWorkers.Delete(i); end else begin if FFileViewWorkers[i].Working then FFileViewWorkers[i].Abort; Inc(i); end; end; SetLoadingFileListLongTime(False); end; procedure TFileView.LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); var HistoryNode, EntryNode, FSNode, PathsNode: TXmlNode; SortingsNode, SortingSubNode, SortFunctionNode: TXmlNode; FileSourceClass: TFileSourceClass; sFSType, sPath, sFilename: String; aFileSource: IFileSource = nil; ActiveFSIndex: Integer = -1; ActivePathIndex: Integer = -1; NewSorting: TFileSortings = nil; SortDirection: TSortDirection; SortFunctions: TFileFunctions; SortFunctionInt: Integer; APage: TFileViewPage; begin RemoveAllFileSources; // Sorting. SortingsNode := AConfig.FindNode(ANode, 'Sortings'); if Assigned(SortingsNode) then begin SortingSubNode := SortingsNode.FirstChild; while Assigned(SortingSubNode) do begin if SortingSubNode.CompareName('Sorting') = 0 then begin if AConfig.TryGetValue(SortingSubNode, 'Direction', Integer(SortDirection)) then begin SortFunctions := nil; SortFunctionNode := SortingSubNode.FirstChild; while Assigned(SortFunctionNode) do begin if SortFunctionNode.CompareName('Function') = 0 then begin if TryStrToInt(AConfig.GetContent(SortFunctionNode), SortFunctionInt) then AddSortFunction(SortFunctions, TFileFunction(SortFunctionInt)); end; SortFunctionNode := SortFunctionNode.NextSibling; end; AddSorting(NewSorting, SortFunctions, SortDirection); end; end; SortingSubNode := SortingSubNode.NextSibling; end; end; FSortings := NewSorting; // SetSorting not needed here, will be called in UpdateView // History. HistoryNode := AConfig.FindNode(ANode, 'History'); if Assigned(HistoryNode) then begin EntryNode := HistoryNode.FirstChild; while Assigned(EntryNode) do begin if EntryNode.CompareName('Entry') = 0 then begin FSNode := EntryNode.FindNode('FileSource'); if Assigned(FSNode) then begin if AConfig.TryGetAttr(FSNode, 'Type', sFSType) then begin // Create file source based on saved configuration or create empty and // allow it to read its configuration from FSNode. if sFSType = 'FileSystem' then aFileSource := TFileSystemFileSource.GetFileSource else begin FileSourceClass := gVfsModuleList.FindFileSource(sFSType); if Assigned(FileSourceClass) then aFileSource := FileSourceClass.Create; end; if Assigned(aFileSource) then begin FHistory.AddFileSource(aFileSource); // Load paths history. PathsNode := AConfig.FindNode(EntryNode, 'Paths'); if Assigned(PathsNode) then begin PathsNode := PathsNode.FirstChild; while Assigned(PathsNode) do begin if PathsNode.CompareName('Path') = 0 then begin sPath := AConfig.GetContent(PathsNode); if sPath <> EmptyStr then begin FHistory.AddPath(sPath); if AConfig.GetAttr(PathsNode, 'Active', False) then ActivePathIndex := FHistory.PathsCount[FHistory.Count - 1] - 1; //-- if selected filename is specified in xml file, load it too if AConfig.TryGetAttr(PathsNode, 'Filename', sFilename) then begin FHistory.SetFilenameForCurrentPath(sFilename); end end; end; PathsNode := PathsNode.NextSibling; end; end; // Delete the file source if no paths loaded. if FHistory.PathsCount[FHistory.Count - 1] = 0 then FHistory.DeleteFromCurrentFileSource else begin // Check if the current history entry is active. if AConfig.GetAttr(EntryNode, 'Active', False) then ActiveFSIndex := FHistory.Count - 1; end; end; end; end; end; EntryNode := EntryNode.NextSibling; end; end; // Set current history position. if (ActiveFSIndex < 0) or (ActiveFSIndex > FHistory.Count - 1) then ActiveFSIndex := FHistory.Count - 1; if ActiveFSIndex <> -1 then begin if (ActivePathIndex < 0) or (ActivePathIndex > FHistory.PathsCount[ActiveFSIndex] - 1) then ActivePathIndex := FHistory.PathsCount[ActiveFSIndex] - 1; end else ActivePathIndex := -1; FHistory.SetIndexes(ActiveFSIndex, ActivePathIndex); aFileSource:= GetCurrentFileSource; if Assigned(aFileSource) and TFileSystemFileSource.ClassNameIs(aFileSource.ClassName) then begin APage := TFileViewPage(NotebookPage); // Go to lock path if tab is locked if Assigned(APage) and (APage.LockState <> tlsNormal) then begin if not mbCompareFileNames(FHistory.CurrentPath, APage.LockPath) then begin FileSourceClass:= gVfsModuleList.GetFileSource(APage.LockPath); if Assigned(FileSourceClass) then aFileSource := FileSourceClass.Create; FHistory.Add(aFileSource, APage.LockPath); end; end; if TFileSystemFileSource.ClassNameIs(aFileSource.ClassName) then begin // Go to upper directory if current doesn't exist sPath := GetDeepestExistingPath(FHistory.CurrentPath); if Length(sPath) = 0 then sPath := mbGetCurrentDir; if not mbCompareFileNames(sPath, FHistory.CurrentPath) then FHistory.Add(aFileSource, sPath); end; end; if Assigned(aFileSource) then begin FSortingProperties := GetSortingProperties; FileSource.AddReloadEventListener(@ReloadEvent); end; //TODO: probably it's not the best place for calling SetActiveFile() : // initially-active file should be set in the same place where // initial path is set SetActiveFile(FHistory.CurrentFilename); // No automatic reload here. end; procedure TFileView.LoadingFileListTimer(Sender: TObject); begin SetLoadingFileListLongTime(True); end; procedure TFileView.LoadSelectionFromClipboard; begin FSavedSelection.Text:= Clipboard.AsText; RestoreSelection; end; procedure TFileView.LoadSelectionFromFile(const AFileName: String); begin with dmComData do begin OpenDialog.DefaultExt := '.txt'; OpenDialog.Filter := '*.txt|*.txt'; OpenDialog.FileName := AFileName; if ((AFileName <> EmptyStr) and mbFileExists(AFileName)) or OpenDialog.Execute then try FSavedSelection.LoadFromFile(OpenDialog.FileName); RestoreSelection; except on E: Exception do msgError(rsMsgErrEOpen + '-' + E.Message); end; end; end; procedure TFileView.MarkCurrentName(bSelect: Boolean); var sGroup: String; bCaseSensitive: boolean = false; bIgnoreAccents: boolean = false; bWindowsInterpretation: boolean = True; begin if IsActiveItemValid then begin sGroup := GetActiveDisplayFile.FSFile.NameNoExt; if Length(sGroup) > 0 then sGroup += ExtensionSeparator + '*'; MarkGroup(sGroup, bSelect, @bCaseSensitive, @bIgnoreAccents, @bWindowsInterpretation); end; end; procedure TFileView.MarkCurrentNameExt(bSelect: Boolean); var sGroup: String; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False; begin if IsActiveItemValid then begin sGroup := GetActiveDisplayFile.FSFile.Name; MarkGroup(sGroup, bSelect, @bCaseSensitive, @bIgnoreAccents, @bWindowsInterpretation); end; end; procedure TFileView.SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); var HistoryNode, EntryNode, FSNode, PathsNode, PathNode: TXmlNode; SortingsNode, SortingSubNode: TXmlNode; i, j: Integer; PathIndex: Integer; ASorting: TFileSortings; begin //-- remember currently active filename // TODO: move this call to some generic place that is called // ALWAYS when currently selected file is changed if not (fvfDelayLoadingFiles in Flags) then FHistory.SetFilenameForCurrentPath(GetActiveFileName()); AConfig.ClearNode(ANode); // Sorting. ASorting := Sorting; if Length(ASorting) > 0 then begin SortingsNode := AConfig.FindNode(ANode, 'Sortings', True); for i := Low(ASorting) to High(ASorting) do begin SortingSubNode := AConfig.AddNode(SortingsNode, 'Sorting'); AConfig.AddValue(SortingSubNode, 'Direction', Integer(ASorting[i].SortDirection)); for j := Low(ASorting[i].SortFunctions) to High(ASorting[i].SortFunctions) do AConfig.AddValue(SortingSubNode, 'Function', Integer(ASorting[i].SortFunctions[j])); end; end; // History. HistoryNode := AConfig.FindNode(ANode, 'History', True); AConfig.ClearNode(HistoryNode); for i := 0 to FileSourcesCount - 1 do begin // Currently saves only FileSystem. if FHistory.FileSource[i].IsClass(TFileSystemFileSource) then begin EntryNode := AConfig.AddNode(HistoryNode, 'Entry'); if FHistory.CurrentFileSourceIndex = i then AConfig.SetAttr(EntryNode, 'Active', True); FSNode := AConfig.AddNode(EntryNode, 'FileSource'); if TFileSystemFileSource.ClassNameIs(FHistory.FileSource[i].ClassName) then AConfig.SetAttr(FSNode, 'Type', 'FileSystem') else begin AConfig.SetAttr(FSNode, 'Type', FHistory.FileSource[i].ClassName); end; // Save paths history. PathsNode := AConfig.AddNode(EntryNode, 'Paths'); if ASaveHistory then begin for j := 0 to FHistory.PathsCount[i] - 1 do begin PathNode := AConfig.AddNode(PathsNode, 'Path'); // Mark path as active (don't need to if it is the last one). if (FHistory.CurrentFileSourceIndex = i) and (FHistory.CurrentPathIndex = j) and (j < FHistory.PathsCount[i] - 1) then begin AConfig.SetAttr(PathNode, 'Active', True); end; //-- set path AConfig.SetContent(PathNode, FHistory.Path[i, j]); //-- set selected filename AConfig.SetAttr(PathNode, 'Filename', FHistory.Filename[i, j]); end; end else begin if FHistory.CurrentFileSourceIndex = i then PathIndex := FHistory.CurrentPathIndex else PathIndex := FHistory.PathsCount[i] - 1; AConfig.AddValue(PathsNode, 'Path', FHistory.Path[i, PathIndex]); end; end; end; end; procedure TFileView.UpdateView; var bLoadingFilelist: Boolean; begin bLoadingFilelist := GetCurrentWorkType = fvwtCreate; StopWorkers; DoUpdateView; if bLoadingFilelist then MakeFileSourceFileList else begin // Always recreate file list because things like ignore list might have changed. if Assigned(FAllDisplayFiles) then Request([fvrqMakeDisplayFileList]); end; EnableWatcher(IsFileSystemWatcher); UpdateTitle; end; procedure TFileView.ApplySettings; var Index: Integer; begin SortAllDisplayFiles; ReDisplayFileList; for Index := 0 to FFiles.Count - 1 do begin FFiles[Index].TextColor := clNone; end; Notify([fvnVisibleFilePropertiesChanged]); end; function TFileView.BeforeChangePath(NewFileSource: IFileSource; Reason: TChangePathReason; NewPath: String): Boolean; var AForm: TCustomForm; begin if NewPath <> '' then begin if Assigned(OnBeforeChangePath) then if not OnBeforeChangePath(Self, NewFileSource, Reason, NewPath) then Exit(False); //-- before changing path, remember currently active filename // TODO: move this call to some generic place that is called // ALWAYS when currently selected file is changed FHistory.SetFilenameForCurrentPath(GetActiveFileName()); if Assigned(NewFileSource) and not NewFileSource.SetCurrentWorkingDirectory(NewPath) then begin AForm:= GetParentForm(Self); if Assigned(AForm) and AForm.Visible then begin msgError(Format(rsMsgChDirFailed, [NewPath])); end; DCDebug(rsMsgChDirFailed, [NewPath]); Exit(False); end; Result := True; end else Result := False; end; procedure TFileView.AfterChangePath; begin LastActiveFile := ''; RequestedActiveFile := ''; FReloadNeeded := False; FReloadTimer.Enabled := False; FLoadFilesStartTime := 0; FLoadFilesFinishTime := 0; FLoadFilesNoDelayCount := 0; if Assigned(OnAfterChangePath) then OnAfterChangePath(Self); UpdateTitle; MakeFileSourceFileList; end; procedure TFileView.ChangePathToParent(AllowChangingFileSource: Boolean); var PreviousSubDirectory, sUpLevel: String; begin AllowChangingFileSource:= AllowChangingFileSource and not (fspNoneParent in FileSource.Properties); // Check if this is root level of the current file source. if FileSource.IsPathAtRoot(CurrentPath) then begin // If there is a higher level file source then change to it. if (FileSourcesCount > 1) and AllowChangingFileSource then begin RemoveCurrentFileSource; end; end else begin PreviousSubDirectory := ExtractFileName(ExcludeTrailingPathDelimiter(CurrentPath)); sUpLevel:= FileSource.GetParentDir(CurrentPath); if sUpLevel <> EmptyStr then begin CurrentPath := sUpLevel; SetActiveFile(PreviousSubDirectory); end; end; end; procedure TFileView.ChangePathToChild(const aFile: TFile); begin if Assigned(aFile) and aFile.IsNameValid and (aFile.IsDirectory or aFile.IsLinkToDirectory) then begin // Workaround for Search Result File Source if FileSource is TSearchResultFileSource then SetFileSystemPath(Self, aFile.FullPath) else CurrentPath := CurrentPath + IncludeTrailingPathDelimiter(aFile.Name); end; end; procedure TFileView.ExecuteCommand(CommandName: String; const Params: array of String); begin FMethods.ExecuteCommand(CommandName, Params); end; function TFileView.AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; var IsNewFileSource: Boolean; begin IsNewFileSource := not aFileSource.Equals(FileSource); Result:= BeforeChangePath(aFileSource, cprAdd, aPath); if Result then begin FFlatView := False; if Assigned(FileSource) and IsNewFileSource then FileSource.RemoveReloadEventListener(@ReloadEvent); EnableWatcher(False); FHistory.Add(aFileSource, aPath); AfterChangePath; if Assigned(FileSource) and IsNewFileSource then begin UpdatePath(True); FileSource.AddReloadEventListener(@ReloadEvent); end; EnableWatcher(True); {$IFDEF DEBUG_HISTORY} FHistory.DebugShow; {$ENDIF} end; end; function TFileView.RemoveCurrentFileSource: Boolean; var NewFileSource: IFileSource = nil; NewPath: String = ''; IsNewFileSource: Boolean; PrevIndex: Integer; FocusedFile: String; begin Result:= True; if FileSourcesCount > 0 then begin FFlatView := False; // TODO: Do this by remembering focused file name in a list? FocusedFile := ExtractFileName(FileSource.CurrentAddress); PrevIndex := FHistory.CurrentFileSourceIndex - 1; if PrevIndex < 0 then begin FileSource.RemoveReloadEventListener(@ReloadEvent); EnableWatcher(False); FHistory.Clear; AfterChangePath; end else begin NewFileSource := FHistory.FileSource[PrevIndex]; NewPath := FHistory.Path[PrevIndex, FHistory.PathsCount[PrevIndex] - 1]; Result:= BeforeChangePath(NewFileSource, cprRemove, NewPath); if Result then begin IsNewFileSource := not NewFileSource.Equals(FileSource); if IsNewFileSource then FileSource.RemoveReloadEventListener(@ReloadEvent); EnableWatcher(False); FHistory.DeleteFromCurrentFileSource; AfterChangePath; if Assigned(FileSource) and IsNewFileSource then begin UpdatePath(True); FileSource.AddReloadEventListener(@ReloadEvent); end; EnableWatcher(True); SetActiveFile(FocusedFile); {$IFDEF DEBUG_HISTORY} FHistory.DebugShow; {$ENDIF} end; end; end; end; procedure TFileView.RemoveAllFileSources; begin if FileSourcesCount > 0 then begin FileSource.RemoveReloadEventListener(@ReloadEvent); EnableWatcher(False); FHistory.Clear; if not (csDestroying in ComponentState) then AfterChangePath; {$IFDEF DEBUG_HISTORY} FHistory.DebugShow; {$ENDIF} end; end; procedure TFileView.AssignFileSources(const otherFileView: TFileView); begin FileSource.RemoveReloadEventListener(@ReloadEvent); EnableWatcher(False); FHistory.Assign(otherFileView.FHistory); UpdatePath(True); FileSource.AddReloadEventListener(@ReloadEvent); AfterChangePath; EnableWatcher(True); end; function TFileView.GetCurrentFileSource: IFileSource; begin Result := FHistory.CurrentFileSource; end; function TFileView.GetCurrentFileSourceIndex: Integer; begin Result := FHistory.CurrentFileSourceIndex; end; function TFileView.GetCurrentPathIndex: Integer; begin Result := FHistory.CurrentPathIndex; end; function TFileView.GetFileSource(Index: Integer): IFileSource; begin Result := FHistory.FileSource[Index]; end; function TFileView.GetFileSourcesCount: Integer; begin Result := FHistory.Count; end; function TFileView.GetFiltered: Boolean; begin Result := Self.FileFilter <> EmptyStr; end; function TFileView.GetPath(FileSourceIndex, PathIndex: Integer): String; begin with FHistory do begin if (Count > 0) and (PathIndex >= 0) and (PathIndex < PathsCount[FileSourceIndex]) then Result := Path[FileSourceIndex, PathIndex] else Result := EmptyStr; end; end; function TFileView.GetPathsCount(FileSourceIndex: Integer): Integer; begin with FHistory do begin if Count > 0 then Result := PathsCount[FileSourceIndex] else Result := 0; end; end; function TFileView.GetSortingProperties: TFilePropertiesTypes; var I, J: Integer; begin Result:= []; // Retrieve RetrievableFileProperties which used in sorting for I:= Low(FSortings) to High(FSortings) do begin for J:= Low(FSortings[I].SortFunctions) to High(FSortings[I].SortFunctions) do begin Result:= Result + GetFilePropertyType(FSortings[I].SortFunctions[J]); end; end; Result:= (Result - FileSource.SupportedFileProperties) * FileSource.RetrievableFileProperties; end; function TFileView.GetSortingForSorter: TFileSortings; begin Result := CloneAndAddSortByNameIfNeeded(Sorting); end; function TFileView.GetWatcherActive: Boolean; begin Result := FWatchPath <> EmptyStr; end; procedure TFileView.HandleNotifications; begin BeginUpdate; try while FNotifications <> [] do begin if fvnFileSourceFileListLoaded in FNotifications then begin FNotifications := FNotifications - [fvnFileSourceFileListLoaded]; FileSourceFileListLoaded; DoOnFileListChanged; end else if fvnFileSourceFileListUpdated in FNotifications then begin FNotifications := FNotifications - [fvnFileSourceFileListUpdated]; FileSourceFileListUpdated; DoOnFileListChanged; end else if fvnDisplayFileListChanged in FNotifications then begin FNotifications := FNotifications - [fvnDisplayFileListChanged]; DisplayFileListChanged; StartRecentlyUpdatedTimerIfNeeded; end else if fvnVisibleFilePropertiesChanged in FNotifications then begin FNotifications := FNotifications - [fvnVisibleFilePropertiesChanged]; EnsureDisplayProperties; end else if fvnSelectionChanged in FNotifications then begin FNotifications := FNotifications - [fvnSelectionChanged]; DoSelectionChanged; end; end; finally EndUpdate; end; end; procedure TFileView.HandleRequests; begin BeginUpdate; try while FRequests <> [] do begin // Order is important because of dependencies. // Remove request before acting on it, since a function called may request it again. if fvrqHashFileList in FRequests then begin FRequests := FRequests - [fvrqHashFileList]; HashFileList; end else if fvrqApplyPendingFilesChanges in FRequests then begin FRequests := FRequests - [fvrqApplyPendingFilesChanges]; ApplyPendingFilesChanges(nfpSortedPosition, ufpSortedPosition); end else if fvrqMakeDisplayFileList in FRequests then begin FRequests := FRequests - [fvrqMakeDisplayFileList]; ReDisplayFileList; end; end; finally EndUpdate; end; end; procedure TFileView.Notify(NewNotifications: TFileViewNotifications); begin FNotifications := FNotifications + NewNotifications; if FUpdateCount = 0 then HandleNotifications; end; procedure TFileView.OpenActiveFile; begin ChooseFile(GetActiveDisplayFile); end; procedure TFileView.SetFileFilter(NewFilter: String; NewFilterOptions: TQuickSearchOptions); begin // do not reload if filter has not changed if (FFileFilter = NewFilter) and (FFilterOptions = NewFilterOptions) then Exit; FFileFilter := NewFilter; FFilterOptions := NewFilterOptions; Request([fvrqMakeDisplayFileList]); end; procedure TFileView.SetFileList(var NewAllDisplayFiles: TDisplayFiles; var NewFilteredDisplayFiles: TDisplayFiles); var ARequests: TFileViewRequests; begin ClearRecentlyUpdatedFiles; FFiles.Free; FFiles := NewFilteredDisplayFiles; NewFilteredDisplayFiles := nil; FAllDisplayFiles.Free; FAllDisplayFiles := NewAllDisplayFiles; NewAllDisplayFiles := nil; FLastLoadedFileSource := FileSource; FLastLoadedPath := CurrentPath; BeginUpdate; try ARequests := [fvrqHashFileList]; if not FReloadNeeded then Include(ARequests, fvrqApplyPendingFilesChanges) else ClearPendingFilesChanges; Request(ARequests); Notify([fvnFileSourceFileListLoaded, fvnDisplayFileListChanged]); finally EndUpdate; end; // We have just reloaded file list, so the requested file should be there. // Regardless if it is there or not it should be cleared so that it doesn't // get selected on further reloads. RequestedActiveFile := ''; end; procedure TFileView.EnableWatcher(Enable: Boolean); var WatchFilter: TFSWatchFilter; begin if Enable then begin if ([fvfDelayLoadingFiles, fvfDontWatch] * Flags = []) and Assigned(FileSource) and FileSource.IsClass(TFileSystemFileSource) and (FWatchPath <> CurrentPath) then begin if WatcherActive then EnableWatcher(False); // If current path is in exclude list then exit. if (watch_exclude_dirs in gWatchDirs) and (gWatchDirsExclude <> '') then begin if IsInPathList(gWatchDirsExclude, CurrentPath) then Exit; end; WatchFilter := []; if watch_file_name_change in gWatchDirs then Include(WatchFilter, wfFileNameChange); if watch_attributes_change in gWatchDirs then Include(WatchFilter, wfAttributesChange); if WatchFilter <> [] then begin FWatchPath := CurrentPath; if TFileSystemWatcher.AddWatch(FWatchPath, WatchFilter, @WatcherEvent, self) = False then FWatchPath := EmptyStr; end; end; end else begin TFileSystemWatcher.RemoveWatch(FWatchPath, @WatcherEvent); FWatchPath := EmptyStr; end; end; procedure TFileView.SetFlatView(AFlatView: Boolean); begin FFlatView:= AFlatView; {$IFDEF DARWIN} TFileSystemWatcher.UpdateWatch; {$ENDIF} end; procedure TFileView.ActivateEvent(Sender: TObject); begin SetFlags(Flags - [fvfDelayLoadingFiles]); ReloadIfNeeded; end; function TFileView.CheckIfDelayReload: Boolean; begin Result := ((watch_only_foreground in gWatchDirs) and (not Application.Active)) or (not IsVisibleToUser); end; procedure TFileView.DoReload; begin FReloadNeeded := False; MakeFileSourceFileList; end; procedure TFileView.HandleFSWatcherEvent(const EventData: TFSWatcherEventData; NewFilesPosition: TNewFilesPosition; UpdatedFilesPosition: TUpdatedFilesPosition); begin case EventData.EventType of fswFileCreated: Self.AddFile(EventData.FileName, EventData.Path, NewFilesPosition, UpdatedFilesPosition); fswFileChanged: Self.UpdateFile(EventData.FileName, EventData.Path, NewFilesPosition, UpdatedFilesPosition); fswFileDeleted: Self.RemoveFile(EventData.FileName, EventData.Path); fswFileRenamed: Self.RenameFile(EventData.NewFileName, EventData.FileName, EventData.Path, NewFilesPosition, UpdatedFilesPosition); fswSelfDeleted: CurrentPath:= GetDeepestExistingPath(CurrentPath); else Reload(); end; end; procedure TFileView.HandleKeyDownWhenLoading(var Key: Word; Shift: TShiftState); begin // Only allow some keys and always zero Key (handled). DoHandleKeyDownWhenLoading(Key, Shift); Key := 0; end; procedure TFileView.ReloadEvent(const aFileSource: IFileSource; const ReloadedPaths: TPathsArray); var NoWatcher: Boolean; begin if aFileSource.Equals(FileSource) then begin // Reload file view but only if the file source is // currently viewed and FileSystemWatcher is not being used. NoWatcher:= not (WatcherActive and TFileSystemWatcher.CanWatch(ReloadedPaths) and TFileSystemFileSource.ClassNameIs(FileSource.ClassName) ); if (NoWatcher or FlatView) then Reload(ReloadedPaths); end; end; procedure TFileView.ReloadTimerEvent(Sender: TObject); begin FReloadTimer.Enabled := False; DoReload; end; procedure TFileView.WatcherEvent(const EventData: TFSWatcherEventData); var CurrentTime: TDateTime; AddToPending: Boolean; begin if (not FReloadNeeded) and CheckIfDelayReload then begin // Delay reloading FReloadNeeded:= True; Exit; end; if not (csDestroying in ComponentState) and not FReloadNeeded and String(IncludeTrailingPathDelimiter(EventData.Path)).StartsWith(CurrentPath) then begin if GetCurrentWorkType = fvwtCreate then begin // If some unknown change then we can only reload the whole file list. if EventData.EventType <> fswUnknownChange then AddEventToPendingFilesChanges(EventData) else Reload(); end else begin if FileListLoaded then begin AddToPending := Assigned(FPendingFilesTimer) and FPendingFilesTimer.Enabled; if not AddToPending then begin CurrentTime := SysUtils.Now; if DateTimeToTimeStamp(CurrentTime - FWatcherEventLastTime).Time > UpdateFilelistInterval then FWatcherEventsApplied := 0; FWatcherEventLastTime := CurrentTime; if FWatcherEventsApplied < 5 then begin Inc(FWatcherEventsApplied); HandleFSWatcherEvent(EventData, gNewFilesPosition, gUpdatedFilesPosition); end else AddToPending := True; end; if AddToPending then begin AddEventToPendingFilesChanges(EventData); StartUpdatePendingTimer; end; end // else filelist not loaded and not even started loading - discard the event end; end; end; procedure TFileView.WMEraseBkgnd(var Message: TLMEraseBkgnd); begin Message.Result := 1; end; function TFileView.GetVariantFileProperties: TDynamicStringArray; begin SetLength(Result, 0); end; procedure TFileView.GoToHistoryIndex(aFileSourceIndex, aPathIndex: Integer); var IsNewFileSource: Boolean; FilenameFromHistory: String; begin //-- before changing path, remember currently active filename // TODO: move this call to some generic place that is called // ALWAYS when currently selected file is changed FHistory.SetFilenameForCurrentPath(GetActiveFileName()); IsNewFileSource := not FHistory.FileSource[aFileSourceIndex].Equals(FHistory.CurrentFileSource); if BeforeChangePath(FHistory.FileSource[aFileSourceIndex], cprChange, FHistory.Path[aFileSourceIndex, aPathIndex]) then begin FFlatView := False; FilenameFromHistory := FHistory.Filename[aFileSourceIndex, aPathIndex]; if Assigned(FileSource) and IsNewFileSource then FileSource.RemoveReloadEventListener(@ReloadEvent); EnableWatcher(False); FHistory.SetIndexes(aFileSourceIndex, aPathIndex); if Assigned(FileSource) and IsNewFileSource then begin UpdatePath(True); FileSource.AddReloadEventListener(@ReloadEvent); end; AfterChangePath; EnableWatcher(True); if FilenameFromHistory <> '' then SetActiveFile(FilenameFromHistory) {$IFDEF DEBUG_HISTORY} FHistory.DebugShow; {$ENDIF} end; end; procedure TFileView.GoToPrevHistory; var aFileSourceIndex, aPathIndex: Integer; begin if FHistory.CurrentPathIndex > 0 then begin aFileSourceIndex := FHistory.CurrentFileSourceIndex; aPathIndex := FHistory.CurrentPathIndex - 1; end else if FHistory.CurrentFileSourceIndex > 0 then begin aFileSourceIndex := FHistory.CurrentFileSourceIndex - 1; aPathIndex := FHistory.PathsCount[aFileSourceIndex] - 1; end else Exit; GoToHistoryIndex(aFileSourceIndex, aPathIndex); end; procedure TFileView.GoToNextHistory; var aFileSourceIndex, aPathIndex: Integer; begin if FHistory.CurrentFileSourceIndex >= 0 then begin if FHistory.CurrentPathIndex < FHistory.PathsCount[FHistory.CurrentFileSourceIndex] - 1 then begin aFileSourceIndex := FHistory.CurrentFileSourceIndex; aPathIndex := FHistory.CurrentPathIndex + 1; end else if FHistory.CurrentFileSourceIndex < FHistory.Count - 1 then begin aFileSourceIndex := FHistory.CurrentFileSourceIndex + 1; aPathIndex := 0; end else Exit; GoToHistoryIndex(aFileSourceIndex, aPathIndex); end; end; procedure TFileView.ReDisplayFileList; begin case GetCurrentWorkType of fvwtNone: ; // Ok to continue. fvwtCreate: // File list is being loaded from file source - cannot display yet. Exit; fvwtUpdate: StopWorkers; else Exit; end; // Redisplaying file list is done in the main thread because it takes // relatively short time, so the user usually won't notice it and it is // a bit faster this way. TFileListBuilder.MakeDisplayFileList( FAllDisplayFiles, FFiles, FileFilter, FFilterOptions); Notify([fvnDisplayFileListChanged]); end; procedure TFileView.WorkerStarting(const Worker: TFileViewWorker); begin if (Worker.WorkType = fvwtCreate) and not Worker.Aborted then begin FLoadFilesStartTime := SysUtils.Now; end; end; procedure TFileView.WorkerFinished(const Worker: TFileViewWorker); var Interval: Integer; begin if (Worker.WorkType = fvwtCreate) and not Worker.Aborted then begin FLoadFilesFinishTime := SysUtils.Now; // Schedule another reload if needed. if FReloadNeeded and not CheckIfDelayReload then begin // Delay by half the time taken by previous loading. Interval := DateTimeToTimeStamp(SysUtils.Now - FLoadFilesStartTime).Time div 2; if Interval < MinimumReloadInterval then Interval := MinimumReloadInterval; FReloadTimer.Interval := Interval; FReloadTimer.Enabled := True; end; SetLoadingFileListLongTime(False); end; if (Worker is TCalculateSpaceWorker) and (Worker.Aborted = False) then begin if TCalculateSpaceWorker(Worker).CompletedCalculations > 1 then begin SortAllDisplayFiles; ReDisplayFileList; end; end; end; { TDropParams } constructor TDropParams.Create( var aFiles: TFiles; aDropEffect: TDropEffect; aScreenDropPoint: TPoint; aDropIntoDirectories: Boolean; aSourcePanel: TFileView; aTargetPanel: TFileView; aTargetFileSource: IFileSource; aTargetPath: String); begin Files := aFiles; aFiles := nil; DropEffect := aDropEffect; ScreenDropPoint := aScreenDropPoint; DropIntoDirectories := aDropIntoDirectories; SourcePanel := aSourcePanel; TargetPanel := aTargetPanel; TargetFileSource := aTargetFileSource; TargetPath := aTargetPath; end; destructor TDropParams.Destroy; begin inherited Destroy; FreeAndNil(Files); end; function TDropParams.GetDragDropType: TDragDropType; begin if Assigned(SourcePanel) then Result := ddtInternal else Result := ddtExternal; end; end. ���������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ufileviewheader.pas��������������������������������������������������0000644�0001750�0000144�00000042466�14743153644�021263� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileViewHeader; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, ExtCtrls, ComCtrls, LCLVersion, uPathLabel, uFileView, KASPathEdit, uFileSorting; type { TFileViewHeader } TFileViewHeader = class(TPanel) private FFileView: TFileView; FAddressLabel: TPathLabel; FPathLabel: TPathLabel; FPathEdit: TKASPathEdit; procedure HeaderResize(Sender: TObject); procedure PathEditExit(Sender: TObject); procedure onKeyESCAPE(Sender: TObject); procedure onKeyRETURN(Sender: TObject); procedure PathLabelClick(Sender: TObject); procedure PathLabelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure AddressLabelClick(Sender: TObject); procedure AddressLabelMouseEnter(Sender: TObject); procedure PathLabelDblClick(Sender: TObject); procedure tmViewHistoryMenuTimer(Sender: TObject); procedure PathLabelMouseWheelUp(Sender: TObject;Shift: TShiftState; MousePos: TPoint;var Handled:Boolean); procedure PathLabelMouseWheelDown(Sender: TObject;Shift: TShiftState; MousePos: TPoint;var Handled:Boolean); procedure HeaderShowHint(Sender: TObject; HintInfo: PHintInfo); procedure EachViewUpdateHeader(AFileView: TFileView; {%H-}UserData: Pointer); protected tmViewHistoryMenu: TTimer; procedure PathLabelSetColor(APathLabel: TPathLabel); public constructor Create(AOwner: TFileView; AParent: TWinControl); reintroduce; procedure UpdateAddressLabel; procedure UpdatePathLabel; procedure UpdateColor; procedure UpdateFont; procedure ShowPathEdit; procedure SetActive(bActive: Boolean); property PathLabel: TPathLabel read FPathLabel; end; { TFileViewFixedHeader } TFileViewFixedHeader = class(THeaderControl) private FFileView: TFileView; FDown: Boolean; FMouseInControl: Boolean; FSelectedSection: Integer; FSorting: TFileSortings; procedure UpdateState; protected procedure SectionClick(Section: THeaderSection); override; procedure MouseEnter; override; procedure MouseLeave; override; procedure MouseDown({%H-}Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer); override; procedure MouseMove({%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer); override; procedure MouseUp({%H-}Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer); override; {$if lcl_fullversion >= 1070000} procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; {$endif} public constructor Create(AOwner: TFileView; AParent: TWinControl); reintroduce; destructor Destroy; override; procedure Click; override; procedure DblClick; override; procedure UpdateHeader; procedure UpdateSorting(Sorting: TFileSortings); end; implementation uses LCLType, ShellCtrls, Graphics, uDCUtils, DCOSUtils, DCStrUtils, uKeyboard, fMain, uFileSourceUtil, uGlobs, uPixMapManager, uLng, uFileFunctions, uArchiveFileSource, uFileViewWithPanels, uVfsModule; const SortingImageIndex: array[TSortDirection] of Integer = (-1, 0, 1); { TFileViewHeader } procedure TFileViewHeader.PathEditExit(Sender: TObject); begin FPathEdit.Visible := False; end; procedure TFileViewHeader.PathLabelClick(Sender: TObject); var walkPath, selectedDir, dirNameToSelect: String; begin FFileView.SetFocus; if FPathLabel.SelectedDir <> '' then begin // User clicked on a subdirectory of the path. walkPath := FFileView.CurrentPath; selectedDir := FPathLabel.SelectedDir; FFileView.CurrentPath := selectedDir; while (Length(walkPath) > Length(selectedDir) + 1) do begin dirNameToSelect := ExtractFileName(ExcludeTrailingPathDelimiter(walkPath)); walkPath := FFileView.FileSource.GetParentDir(walkPath); end; FFileView.SetActiveFile(dirNameToSelect); end else tmViewHistoryMenu.Enabled:=TRUE; //Let's start timer. If it's a double-click, we'll abort timer otherwise we'll show history as before but 250ms later. end; procedure TFileViewHeader.tmViewHistoryMenuTimer(Sender: TObject); begin tmViewHistoryMenu.Enabled:=FALSE; frmMain.Commands.cm_ViewHistory([]); end; procedure TFileViewHeader.PathLabelMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint;var Handled:Boolean); begin if (ssCtrl in Shift) and (gFonts[dcfPathEdit].Size < gFonts[dcfPathEdit].MaxValue) then begin gFonts[dcfPathEdit].Size:= gFonts[dcfPathEdit].Size + 1; frmMain.ForEachView(@EachViewUpdateHeader, nil); end; end; procedure TFileViewHeader.PathLabelMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint;var Handled:Boolean); begin if (ssCtrl in Shift) and (gFonts[dcfPathEdit].Size > gFonts[dcfPathEdit].MinValue) then begin gFonts[dcfPathEdit].Size:= gFonts[dcfPathEdit].Size - 1; frmMain.ForEachView(@EachViewUpdateHeader, nil); end; end; { TFileViewHeader.PathLabelDblClick } { -If we double-click on the the path label, it shows the Hot Dir popup menu at the cursor position. -If we click just once, after the 250ms of the timer, it shows the history. This will make both kind of people happy AND will make DC like TC} procedure TFileViewHeader.PathLabelDblClick(Sender: TObject); begin tmViewHistoryMenu.Enabled:=FALSE; //Cancel the possibility of a left click if gDblClickEditPath then ShowPathEdit else begin FFileView.SetFocus; frmMain.Commands.cm_DirHotList(['position=cursor']); end; end; procedure TFileViewHeader.PathLabelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin case Button of mbMiddle: begin FFileView.SetFocus; frmMain.Commands.cm_DirHotList(['position=cursor']); end; mbRight: begin ShowPathEdit; end; end; end; procedure TFileViewHeader.AddressLabelClick(Sender: TObject); var walkPath, dirNameToSelect: String; begin FFileView.SetFocus; if (FAddressLabel.AllowHighlight) and (Length(FAddressLabel.SelectedDir) > 0) then begin // User clicked on a subdirectory of the address. walkPath := FFileView.CurrentAddress; SetFileSystemPath(FFileView, FAddressLabel.SelectedDir); while (Length(walkPath) > Length(FAddressLabel.SelectedDir) + 1) do begin dirNameToSelect := ExtractFileName(ExcludeTrailingPathDelimiter(walkPath)); walkPath := FFileView.FileSource.GetParentDir(walkPath); end; FFileView.SetActiveFile(dirNameToSelect); end; end; procedure TFileViewHeader.AddressLabelMouseEnter(Sender: TObject); begin FAddressLabel.AllowHighlight:= FFileView.FileSource is TArchiveFileSource; end; procedure TFileViewHeader.EachViewUpdateHeader(AFileView: TFileView; UserData: Pointer); begin TFileViewWithPanels(AFileView).Header.UpdateFont; end; procedure TFileViewHeader.PathLabelSetColor(APathLabel: TPathLabel); begin with gColors.Path^ do begin APathLabel.ActiveColor:= ActiveColor; APathLabel.ActiveFontColor:= ActiveFontColor; APathLabel.InactiveColor:= InactiveColor; APathLabel.InactiveFontColor:= InactiveFontColor; end; end; procedure TFileViewHeader.onKeyESCAPE(Sender: TObject); begin FPathEdit.Visible:=False; FFileView.SetFocus; end; procedure TFileViewHeader.onKeyRETURN(Sender: TObject); var NewPath: String; AClass: TFileSourceClass; begin NewPath:= NormalizePathDelimiters(FPathEdit.Text); NewPath:= ReplaceEnvVars(ReplaceTilde(NewPath)); AClass:= gVfsModuleList.GetFileSource(NewPath); // Check file name on the local file system only if not ((AClass = nil) and mbFileExists(NewPath)) then begin if not ChooseFileSource(FFileView, NewPath, True) then Exit; end else begin if not ChooseFileSource(FFileView, ExtractFileDir(NewPath)) then Exit; FFileView.SetActiveFile(ExtractFileName(NewPath)); end; FPathEdit.Visible := False; FFileView.SetFocus; end; constructor TFileViewHeader.Create(AOwner: TFileView; AParent: TWinControl); begin inherited Create(AOwner); FFileView:= AOwner; Parent:= AParent; Align:= alTop; BevelInner:= bvNone; BevelOuter:= bvNone; AutoSize:= True; DoubleBuffered:= True; FAddressLabel := TPathLabel.Create(Self, False); FAddressLabel.Parent := Self; FAddressLabel.BorderSpacing.Bottom := 1; FPathLabel := TPathLabel.Create(Self, True); FPathLabel.Parent := Self; UpdateColor; // Display path below address. // For correct alignment, first put path at the top, then address at the top. FPathLabel.Align := alTop; FAddressLabel.Align := alTop; FPathEdit:= TKASPathEdit.Create(FPathLabel); FPathEdit.Parent:= Self; FPathEdit.Visible:= False; FPathEdit.TabStop:= False; FPathEdit.BorderStyle:= bsNone; FPathEdit.ObjectTypes:= [otFolders, otHidden]; OnResize:= @HeaderResize; OnShowHint:=@HeaderShowHint; FPathEdit.OnExit:= @PathEditExit; FPathEdit.onKeyESCAPE:=@onKeyESCAPE; FPathEdit.onKeyRETURN:=@onKeyRETURN; FPathEdit.OnShowHint:=@HeaderShowHint; FPathLabel.OnClick := @PathLabelClick; FPathLabel.OnDblClick := @PathLabelDblClick; FPathLabel.OnMouseUp := @PathLabelMouseUp; FPathLabel.OnMouseWheelDown := @PathLabelMouseWheelDown; FPathLabel.OnMouseWheelUp := @PathLabelMouseWheelUp; FPathLabel.OnShowHint:=@HeaderShowHint; FAddressLabel.OnClick := @AddressLabelClick; FAddressLabel.OnMouseEnter:= @AddressLabelMouseEnter; FAddressLabel.OnShowHint:=@HeaderShowHint; tmViewHistoryMenu := TTimer.Create(Self); //Timer used to show history after a while in case it was not a double click to show Hot dir tmViewHistoryMenu.Enabled := False; tmViewHistoryMenu.Interval := 250; tmViewHistoryMenu.OnTimer := @tmViewHistoryMenuTimer; UpdateFont; end; procedure TFileViewHeader.HeaderResize(Sender: TObject); begin UpdateAddressLabel; UpdatePathLabel; end; // 1. in most cases, as not to bother users, // the Header does not need to show hint, // 2. so set hint to the full path, only when the path in PathLabel is shortened // due to insufficient width procedure TFileViewHeader.HeaderShowHint(Sender: TObject; HintInfo: PHintInfo); begin HintInfo^.HintStr := ''; if FFileView.CurrentAddress<>'' then exit; if IncludeTrailingPathDelimiter(FPathLabel.Caption) <> FFileView.CurrentPath then HintInfo^.HintStr := FFileView.CurrentPath; end; procedure TFileViewHeader.UpdateAddressLabel; begin if FFileView.CurrentAddress = '' then begin FAddressLabel.Visible := False; end else begin FAddressLabel.Top:= 0; FAddressLabel.Caption := FFileView.CurrentAddress; FAddressLabel.Visible := True; end; end; procedure TFileViewHeader.UpdatePathLabel; begin FPathLabel.Caption := MinimizeFilePath(FFileView.CurrentPath, FPathLabel.Canvas, FPathLabel.Width); end; procedure TFileViewHeader.UpdateColor; begin PathLabelSetColor(FPathLabel); PathLabelSetColor(FAddressLabel); end; procedure TFileViewHeader.UpdateFont; begin FontOptionsToFont(gFonts[dcfPathEdit], FAddressLabel.Font); FontOptionsToFont(gFonts[dcfPathEdit], FPathLabel.Font); FontOptionsToFont(gFonts[dcfPathEdit], FPathEdit.Font); end; procedure TFileViewHeader.ShowPathEdit; begin with FPathLabel do begin FPathEdit.SetBounds(Left, Top, Width, Height); FPathEdit.Text := FFileView.CurrentPath; FPathEdit.Visible := True; FPathEdit.SetFocus; end; end; procedure TFileViewHeader.SetActive(bActive: Boolean); begin FAddressLabel.SetActive(bActive); FPathLabel.SetActive(bActive); end; { TFileViewFixedHeader } procedure TFileViewFixedHeader.UpdateState; var i, Index: Integer; MaxState: THeaderSectionState; P: TPoint; begin MaxState := hsNormal; if Enabled then if FDown then begin MaxState := hsPressed; Index := FSelectedSection; end else if FMouseInControl then begin MaxState := hsHot; P := ScreenToClient(Mouse.CursorPos); Index := GetSectionAt(P); end; for i := 0 to Sections.Count - 1 do if (i <> Index) then Sections[i].State := hsNormal else Sections[i].State := MaxState; end; procedure TFileViewFixedHeader.SectionClick(Section: THeaderSection); var SortingDirection : TSortDirection; NewSorting: TFileSortings; SortFunctions: TFileFunctions; begin with FFileView do begin NewSorting := Sorting; SortFunctions := FSorting[Section.Index].SortFunctions; if [ssShift, ssCtrl] * GetKeyShiftStateEx = [] then begin SortingDirection := GetSortDirection(NewSorting, SortFunctions); if SortingDirection = sdNone then begin // If there is no direction currently, sort "sdDescending" for size and date. // Commonly, we search seek more often for most recent files then older any others. // When sorting by size, often it is to find larger file to make room. // Anyway, it makes DC like TC, and also, Windows Explorer do the same. case SortFunctions[0] of fsfSize, fsfModificationTime, fsfCreationTime, fsfLastAccessTime: SortingDirection:= sdDescending; else SortingDirection:= sdAscending; end; end else begin SortingDirection := ReverseSortDirection(SortingDirection); end; NewSorting := nil; end else begin // If there is no direction currently, sort "sdDescending" for size and date (see previous comment). case SortFunctions[0] of fsfSize, fsfModificationTime, fsfCreationTime, fsfLastAccessTime: SortingDirection:= sdDescending; else SortingDirection:= sdAscending; end; end; AddOrUpdateSorting(NewSorting, SortFunctions, SortingDirection); FFileView.Sorting:= NewSorting; end; inherited SectionClick(Section); end; procedure TFileViewFixedHeader.Click; var Index: Integer; begin if FDown then begin inherited Click; Index := GetSectionAt(ScreenToClient(Mouse.CursorPos)); if Index <> -1 then SectionClick(Sections[Index]); end; end; procedure TFileViewFixedHeader.DblClick; begin Click; end; procedure TFileViewFixedHeader.UpdateHeader; var I: Integer; begin for I:= 0 to Sections.Count - 1 do begin Sections[I].ImageIndex:= SortingImageIndex[FSorting[I].SortDirection]; end; end; procedure TFileViewFixedHeader.UpdateSorting(Sorting: TFileSortings); var I, J: Integer; begin for I:= Low(FSorting) to High(FSorting) do begin FSorting[I].SortDirection:= sdNone; for J:= Low(Sorting) to High(Sorting) do begin if (FSorting[I].SortFunctions[0] = Sorting[J].SortFunctions[0]) or ((Sorting[J].SortFunctions[0] = fsfName) and (FSorting[I].SortFunctions[0] = fsfNameNoExtension))then begin FSorting[I].SortDirection:= Sorting[J].SortDirection; Break; end; end; end; UpdateHeader; end; procedure TFileViewFixedHeader.MouseEnter; begin inherited MouseEnter; if not (csDesigning in ComponentState) then begin FMouseInControl := True; UpdateState; end; end; procedure TFileViewFixedHeader.MouseLeave; begin inherited MouseLeave; if not (csDesigning in ComponentState) then begin FMouseInControl := False; FDown := False; UpdateState; end; end; procedure TFileViewFixedHeader.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if not (csDesigning in ComponentState) then begin FDown:= True; FSelectedSection:=GetSectionAt(Point(X, Y)); UpdateState; end; end; procedure TFileViewFixedHeader.MouseMove(Shift: TShiftState; X, Y: Integer); begin if not (csDesigning in ComponentState) then begin UpdateState; end; end; procedure TFileViewFixedHeader.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if not (csDesigning in ComponentState) then begin FDown:= False; UpdateState; end; end; {$if lcl_fullversion >= 1070000} procedure TFileViewFixedHeader.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); begin // Don't auto adjust vertical layout inherited DoAutoAdjustLayout(AMode, AXProportion, 1.0); end; {$endif} constructor TFileViewFixedHeader.Create(AOwner: TFileView; AParent: TWinControl); var I: Integer; ABitmap: TBitmap; begin inherited Create(AOwner); FFileView:= AOwner; Parent:= AParent; Align:= alTop; DoubleBuffered:= True; Sections.Add.Text:= rsColName; Sections.Add.Text:= rsColExt; Sections.Add.Text:= rsColSize; Sections.Add.Text:= rsColDate; Sections.Add.Text:= rsColAttr; Images:= TImageList.CreateSize(gIconsSize, gIconsSize); ABitmap:= PixMapManager.GetBitmap(PixMapManager.GetIconBySortingDirection(sdAscending)); Images.Add(ABitmap, nil); ABitmap.Free; ABitmap:= PixMapManager.GetBitmap(PixMapManager.GetIconBySortingDirection(sdDescending)); Images.Add(ABitmap, nil); ABitmap.Free;; SetLength(FSorting, 5); for I:= Low(FSorting) to High(FSorting) do SetLength(FSorting[I].SortFunctions, 1); FSorting[0].SortDirection:= sdNone; FSorting[0].SortFunctions[0]:= fsfNameNoExtension; FSorting[1].SortDirection:= sdNone; FSorting[1].SortFunctions[0]:= fsfExtension; FSorting[2].SortDirection:= sdNone; FSorting[2].SortFunctions[0]:= fsfSize; FSorting[3].SortDirection:= sdNone; FSorting[3].SortFunctions[0]:= fsfModificationTime; FSorting[4].SortDirection:= sdNone; FSorting[4].SortFunctions[0]:= fsfAttr; end; destructor TFileViewFixedHeader.Destroy; begin Images.Free; inherited Destroy; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ufileviewhistory.pas�������������������������������������������������0000644�0001750�0000144�00000023460�14743153644�021525� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- History of visited paths, file sources for a file view. Copyright (C) 2010 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uFileViewHistory; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource; type { TFileViewHistory } TFileViewHistory = class private FCurrentFileSource: Integer; FCurrentPath: Integer; FHistory: TFPList; // of PFileViewHistoryEntry procedure Delete(Index: Integer); {en Delete history after current indexes. } procedure DeleteAfterCurrent; function GetCount: Integer; // = FileSourcesCount function GetCurrentFileSource: IFileSource; function GetCurrentPath: String; function GetCurrentFilename: String; function GetFileSource(Index: Integer): IFileSource; function GetPath(FileSourceIndex, PathIndex: Integer): String; function GetFilename(FileSourceIndex, FilenameIndex: Integer): String; function GetPathsCount(Index: Integer): Integer; public constructor Create; destructor Destroy; override; procedure Clear; {$IFDEF DEBUG_HISTORY} procedure DebugShow; {$ENDIF} procedure Add(aFileSource: IFileSource; aPath: String); procedure AddFileSource(aFileSource: IFileSource); procedure AddPath(aPath: String); procedure SetFilenameForCurrentPath(aFilename: String); procedure Assign(otherHistory: TFileViewHistory); procedure DeleteFromCurrentFileSource; procedure SetIndexes(aFileSourceIndex: Integer; aCurrentPathIndex: Integer); property Count: Integer read GetCount; property CurrentFileSource: IFileSource read GetCurrentFileSource; property CurrentFileSourceIndex: Integer read FCurrentFileSource write FCurrentFileSource; property CurrentPath: String read GetCurrentPath; property CurrentFilename: String read GetCurrentFilename; property CurrentPathIndex: Integer read FCurrentPath write FCurrentPath; property FileSource[Index: Integer]: IFileSource read GetFileSource; property Path[FileSourceIndex, PathIndex: Integer]: String read GetPath; property Filename[FileSourceIndex, FilenameIndex: Integer]: String read GetFilename; property PathsCount[Index: Integer]: Integer read GetPathsCount; end; implementation type PFileViewHistoryEntry = ^TFileViewHistoryEntry; TFileViewHistoryEntry = record FileSource: IFileSource; PathsList : TStringList; // paths always include trailing path delimiter FilenamesList : TStringList; //TODO: refactor this! // it's much better to store list of objects each of them contain // both path and filename, instead of keeping two separate lists. // (right now, quick-n-dirty solution was applied) end; { TFileViewHistory } constructor TFileViewHistory.Create; begin FHistory := TFPList.Create; FCurrentFileSource := -1; FCurrentPath := -1; end; destructor TFileViewHistory.Destroy; begin inherited Destroy; Clear; FreeAndNil(FHistory); end; procedure TFileViewHistory.Clear; var i: Integer; begin for i := FHistory.Count - 1 downto 0 do Delete(i); FCurrentFileSource := -1; FCurrentPath := -1; end; {$IFDEF DEBUG_HISTORY} procedure TFileViewHistory.DebugShow; var i, j: Integer; HistEntry: PFileViewHistoryEntry; begin for i := 0 to FHistory.Count - 1 do begin HistEntry := PFileViewHistoryEntry(FHistory.Items[i]); WriteLn('--------------------------------------'); WriteLn(' ', HistEntry^.FileSource.ClassName); for j := 0 to HistEntry^.PathsList.Count - 1 do begin if (i = FCurrentFileSource) and (j = FCurrentPath) then Write('=> ') else Write(' '); WriteLn(HistEntry^.PathsList.Strings[j]); end; end; end; {$ENDIF} function TFileViewHistory.GetCount: Integer; begin Result := FHistory.Count; end; function TFileViewHistory.GetCurrentFileSource: IFileSource; begin if FCurrentFileSource >= 0 then Result := PFileViewHistoryEntry(FHistory[FCurrentFileSource])^.FileSource else Result := nil; end; function TFileViewHistory.GetCurrentPath: String; begin if (FCurrentFileSource >= 0) and (FCurrentPath >= 0) then Result := PFileViewHistoryEntry(FHistory[FCurrentFileSource])^.PathsList[FCurrentPath] else Result := EmptyStr; end; function TFileViewHistory.GetCurrentFilename: String; begin if (FCurrentFileSource >= 0) and (FCurrentPath >= 0) then Result := PFileViewHistoryEntry(FHistory[FCurrentFileSource])^.FilenamesList[FCurrentPath] else Result := EmptyStr; end; function TFileViewHistory.GetFileSource(Index: Integer): IFileSource; begin Result := PFileViewHistoryEntry(FHistory.Items[Index])^.FileSource; end; function TFileViewHistory.GetPath(FileSourceIndex, PathIndex: Integer): String; begin Result := PFileViewHistoryEntry(FHistory.Items[FileSourceIndex])^.PathsList.Strings[PathIndex]; end; function TFileViewHistory.GetFilename(FileSourceIndex, FilenameIndex: Integer): String; begin Result := PFileViewHistoryEntry(FHistory.Items[FileSourceIndex])^.FilenamesList.Strings[FilenameIndex]; end; function TFileViewHistory.GetPathsCount(Index: Integer): Integer; begin Result := PFileViewHistoryEntry(FHistory.Items[Index])^.PathsList.Count; end; procedure TFileViewHistory.Add(aFileSource: IFileSource; aPath: String); begin AddFileSource(aFileSource); AddPath(aPath); end; procedure TFileViewHistory.AddFileSource(aFileSource: IFileSource); var HistEntry: PFileViewHistoryEntry; begin if FCurrentFileSource >= 0 then begin DeleteAfterCurrent; HistEntry := PFileViewHistoryEntry(FHistory.Items[FCurrentFileSource]); // Don't add if the current file source is the same. if HistEntry^.FileSource.Equals(aFileSource) then Exit; end; New(HistEntry); FHistory.Add(HistEntry); HistEntry^.FileSource := aFileSource; HistEntry^.PathsList := TStringList.Create; HistEntry^.FilenamesList := TStringList.Create; Inc(FCurrentFileSource); FCurrentPath := -1; end; procedure TFileViewHistory.SetFilenameForCurrentPath(aFilename: String); var aFilenames: TStringList; begin aFilenames := PFileViewHistoryEntry(FHistory.Items[FCurrentFileSource])^.FilenamesList; if (FCurrentPath >= 0) then begin aFilenames[FCurrentPath] := aFilename; end end; procedure TFileViewHistory.AddPath(aPath: String); var aPaths: TStringList; aFilenames: TStringList; begin if FCurrentFileSource >= 0 then begin DeleteAfterCurrent; aPaths := PFileViewHistoryEntry(FHistory.Items[FCurrentFileSource])^.PathsList; aFilenames := PFileViewHistoryEntry(FHistory.Items[FCurrentFileSource])^.FilenamesList; if aPath <> '' then aPath := IncludeTrailingPathDelimiter(aPath); if (aPaths.Count = 0) or (aPaths.Strings[FCurrentPath] <> aPath) then begin aPaths.Add(aPath); aFilenames.Add(''); if aPaths.Count > 50 then begin aPaths.Delete(0); aFilenames.Delete(0); end else Inc(FCurrentPath); end; end; end; procedure TFileViewHistory.Assign(otherHistory: TFileViewHistory); var i: Integer; HistEntry, otherHistEntry: PFileViewHistoryEntry; begin Clear; for i := 0 to otherHistory.FHistory.Count - 1 do begin otherHistEntry := PFileViewHistoryEntry(otherHistory.FHistory.Items[i]); New(HistEntry); FHistory.Add(HistEntry); HistEntry^.FileSource := otherHistEntry^.FileSource; HistEntry^.PathsList := TStringList.Create; HistEntry^.PathsList.AddStrings(otherHistEntry^.PathsList); HistEntry^.FilenamesList := TStringList.Create; HistEntry^.FilenamesList.AddStrings(otherHistEntry^.FilenamesList); end; FCurrentFileSource := otherHistory.FCurrentFileSource; FCurrentPath := otherHistory.FCurrentPath; end; procedure TFileViewHistory.Delete(Index: Integer); var HistEntry: PFileViewHistoryEntry; begin HistEntry := PFileViewHistoryEntry(FHistory.Items[Index]); FHistory.Delete(Index); HistEntry^.FileSource := nil; HistEntry^.PathsList.Free; HistEntry^.FilenamesList.Free; Dispose(HistEntry); end; procedure TFileViewHistory.DeleteAfterCurrent; var i: Integer; aPaths: TStringList; aFilenames: TStringList; begin if FHistory.Count > 0 then begin for i := FHistory.Count - 1 downto FCurrentFileSource + 1 do Delete(i); aPaths := PFileViewHistoryEntry(FHistory.Items[FCurrentFileSource])^.PathsList; aFilenames := PFileViewHistoryEntry(FHistory.Items[FCurrentFileSource])^.FilenamesList; for i := aPaths.Count - 1 downto FCurrentPath + 1 do begin aPaths.Delete(i); aFilenames.Delete(i); end; end; end; procedure TFileViewHistory.DeleteFromCurrentFileSource; var i: Integer; begin if FHistory.Count > 0 then begin for i := FHistory.Count - 1 downto FCurrentFileSource do Delete(i); Dec(FCurrentFileSource); if FCurrentFileSource >= 0 then // Set to last entry. FCurrentPath := PathsCount[FCurrentFileSource] - 1 else FCurrentFileSource := -1; end; end; procedure TFileViewHistory.SetIndexes(aFileSourceIndex: Integer; aCurrentPathIndex: Integer); begin FCurrentFileSource := aFileSourceIndex; FCurrentPath := aCurrentPathIndex; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ufileviewwithgrid.pas������������������������������������������������0000644�0001750�0000144�00000070262�14743153644�021647� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileViewWithGrid; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, Grids, Graphics, StdCtrls, LCLVersion, uDisplayFile, DCXmlConfig, uFileSorting, uFileProperty, uFileViewWithMainCtrl, uFile, uFileViewHeader, uFileView, uFileSource; type TFileViewWithGrid = class; { TFileViewGrid } TFileViewGrid = class(TDrawGrid) protected FLastMouseMoveTime: QWord; FLastMouseScrollTime: QWord; FFileView: TFileViewWithGrid; protected procedure Scroll(Message: Cardinal; ScrollCode: SmallInt); {$IF lcl_fullversion < 1080003} function SelectCell(aCol, aRow: Integer): Boolean; override; {$ENDIF} procedure RowHeightsChanged; override; procedure ColWidthsChanged; override; procedure FinalizeWnd; override; procedure InitializeWnd; override; function MouseOnGrid(X, Y: LongInt): Boolean; procedure DoOnResize; override; procedure DragCanceled; override; procedure KeyDown(var Key : Word; Shift : TShiftState); override; procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure TopLeftChanged; override; function GetBorderWidth: Integer; protected procedure SetColRowCount(Count: Integer); procedure DrawLines(aIdx, aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); procedure PrepareColors(aFile: TDisplayFile; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); procedure UpdateView; virtual; abstract; procedure CalculateColRowCount; virtual; abstract; procedure CalculateColumnWidth; virtual; abstract; {$if lcl_fullversion >= 1070000} procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; {$endif} public constructor Create(AOwner: TComponent; AParent: TWinControl); reintroduce; virtual; function CellToIndex(ACol, ARow: Integer): Integer; virtual; abstract; procedure IndexToCell(Index: Integer; out ACol, ARow: Integer); virtual; abstract; property BorderWidth: Integer read GetBorderWidth; end; { TFileViewGridClass } TFileViewGridClass = class of TFileViewGrid; { TFileViewWithGrid } TFileViewWithGrid = class (TFileViewWithMainCtrl) protected TabHeader: TFileViewFixedHeader; dgPanel: TFileViewGrid; lblDetails: TLabel; private procedure SetFilesDisplayItems; procedure UpdateFooterDetails; procedure dgPanelSelection(Sender: TObject; aCol, aRow: Integer); protected procedure MakeColumnsStrings(AFile: TDisplayFile); function GetFileViewGridClass: TFileViewGridClass; virtual; abstract; protected procedure CreateDefault(AOwner: TWinControl); override; procedure BeforeMakeFileList; override; procedure ClearAfterDragDrop; override; procedure AfterChangePath; override; procedure DisplayFileListChanged; override; procedure DoOnResize; override; procedure FileSourceFileListLoaded; override; function GetActiveFileIndex: PtrInt; override; function GetFileIndexFromCursor(X, Y: Integer; out AtFileList: Boolean): PtrInt; override; function GetFileRect(FileIndex: PtrInt): TRect; override; procedure RedrawFile(FileIndex: PtrInt); override; procedure RedrawFile(DisplayFile: TDisplayFile); override; procedure RedrawFiles; override; procedure SetActiveFile(FileIndex: PtrInt; ScrollTo: Boolean; aLastTopRowIndex: PtrInt = -1); override; procedure DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes = []); override; procedure DoHandleKeyDown(var Key: Word; Shift: TShiftState); override; procedure UpdateFlatFileName; override; procedure UpdateInfoPanel; override; procedure DoUpdateView; override; procedure SetSorting(const NewSortings: TFileSortings); override; public constructor Create(AOwner: TWinControl; AFileSource: IFileSource; APath: String; AFlags: TFileViewFlags = []); override; constructor Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); override; constructor Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags = []); override; destructor Destroy; override; procedure CloneTo(FileView: TFileView); override; function AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; override; procedure LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); override; end; function FitFileName(const AFileName: String; ACanvas: TCanvas; AFile: TFile; ATargetWidth: Integer): String; function FitOtherCellText(const sStringToFit:String; ACanvas:TCanvas; ATargetWidth: Integer): String; implementation uses Types, LCLIntf, LCLType, LCLProc, LazUTF8, Math, LMessages, DCStrUtils, uGlobs, uPixmapManager, uKeyboard, uDCUtils, fMain, uFileFunctions; { Workaround https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40934 } function TextFitInfo(ACanvas: TCanvas; const Text: String; MaxWidth: Integer): Integer; var lSize: TSize; begin Result:= 0; LCLIntf.GetTextExtentExPoint(ACanvas.Handle, PChar(Text), Length(Text), MaxWidth, @Result, nil, lSize); end; function FitFileName(const AFileName: String; ACanvas: TCanvas; AFile: TFile; ATargetWidth: Integer): String; var S: String; Index: Integer; AMaxWidth: Integer; begin Index:= UTF8Length(AFileName); AMaxWidth:= TextFitInfo(ACanvas, AFileName, ATargetWidth); if Index <= AMaxWidth then Result:= AFileName else begin if gDirBrackets and (AFile.IsDirectory or AFile.IsLinkToDirectory) then S:= '..' + gFolderPostfix else begin S:= '..'; end; Index:= TextFitInfo(ACanvas, AFileName, ATargetWidth - ACanvas.TextWidth(S)); Result:= UTF8Copy(AFileName, 1, Index) + S; end; end; { FitOtherCellText } function FitOtherCellText(const sStringToFit:String; ACanvas:TCanvas; ATargetWidth: Integer): String; const ELLIPSIS = '..'; var Index: Integer; AMaxWidth: Integer; begin Index:= UTF8Length(sStringToFit); AMaxWidth:= TextFitInfo(ACanvas, sStringToFit, ATargetWidth); if Index <= AMaxWidth then Result:= sStringToFit else begin Index:= TextFitInfo(ACanvas, sStringToFit, ATargetWidth - ACanvas.TextWidth(ELLIPSIS)); Result:= UTF8Copy(sStringToFit, 1, Index) + ELLIPSIS; end; end; { TFileViewGrid } procedure TFileViewGrid.InitializeWnd; begin inherited InitializeWnd; FFileView.InitializeDragDropEx(Self); end; procedure TFileViewGrid.DoOnResize; begin CalculateColRowCount; CalculateColumnWidth; inherited DoOnResize; end; procedure TFileViewGrid.DragCanceled; begin fGridState:= gsNormal; end; procedure TFileViewGrid.KeyDown(var Key: Word; Shift: TShiftState); begin {$IFDEF LCLGTK2} // Workaround for GTK2 - up and down arrows moving through controls. if Key in [VK_UP, VK_DOWN] then begin if ((Row = RowCount-1) and (Key = VK_DOWN)) or ((Row = FixedRows) and (Key = VK_UP)) then Key := 0; end; {$ENDIF} inherited KeyDown(Key, Shift); end; procedure TFileViewGrid.Scroll(Message: Cardinal; ScrollCode: SmallInt); var Msg: TLMScroll; begin Msg.Msg := Message; Msg.ScrollCode := ScrollCode; Msg.SmallPos := 1; // How many lines scroll Msg.ScrollBar := Handle; Dispatch(Msg); end; {$IF lcl_fullversion < 1080003} // Workaround for Lazarus issue 31942. function TFileViewGrid.SelectCell(aCol, aRow: Integer): Boolean; begin Result:= inherited SelectCell(aCol, aRow); // ScrollToCell hangs when Width = 0 if Width = 0 then begin Result:= False; SetColRow(aCol, aRow); end; end; {$ENDIF} procedure TFileViewGrid.RowHeightsChanged; begin inherited RowHeightsChanged; CalculateColRowCount; end; procedure TFileViewGrid.ColWidthsChanged; begin inherited ColWidthsChanged; CalculateColRowCount; end; function TFileViewGrid.MouseOnGrid(X, Y: LongInt): Boolean; var bTemp: Boolean; iRow, iCol: LongInt; begin bTemp:= AllowOutboundEvents; AllowOutboundEvents:= False; MouseToCell(X, Y, iCol, iRow); AllowOutboundEvents:= bTemp; Result:= not (CellToIndex(iCol, iRow) < 0); end; procedure TFileViewGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FLastMouseMoveTime := 0; FLastMouseScrollTime := 0; if FFileView.IsLoadingFileList then Exit; {$IF DECLARED(lcl_fullversion) and (lcl_fullversion >= 093100)} // Don't scroll partially visible cells on mouse click Options:= Options + [goDontScrollPartCell]; {$ENDIF} {$IFDEF LCLGTK2} // Workaround for two doubleclicks being sent on GTK. // MouseDown event is sent just before doubleclick, so if we drop // doubleclick events we have to also drop MouseDown events that precede them. if FFileView.TooManyDoubleClicks then Exit; {$ENDIF} FFileView.FMainControlMouseDown := True; if MouseOnGrid(X, Y) then inherited MouseDown(Button, Shift, X, Y) else begin if Assigned(OnMouseDown) then begin OnMouseDown(Self, Button, Shift, X, Y); end; if not Focused then begin if CanSetFocus then SetFocus; end; end; end; procedure TFileViewGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var BackgroundClick: Boolean; Point: TPoint; begin if FFileView.IsLoadingFileList then Exit; {$IF DECLARED(lcl_fullversion) and (lcl_fullversion >= 093100)} // Don't scroll partially visible cells on mouse click Options:= Options - [goDontScrollPartCell]; {$ENDIF} {$IFDEF LCLGTK2} // Workaround for two doubleclicks being sent on GTK. // MouseUp event is sent just after doubleclick, so if we drop // doubleclick events we have to also drop MouseUp events that follow them. if FFileView.TooManyDoubleClicks then Exit; {$ENDIF} // Handle only if button-up was not lifted to finish drag&drop operation. if not FFileView.FMainControlMouseDown then Exit; inherited MouseUp(Button, Shift, X, Y); FFileView.FMainControlMouseDown := False; if Button = mbRight then begin { If right click on file/directory } if ((gMouseSelectionButton <> 1) or not gMouseSelectionEnabled) then begin BackgroundClick:= not MouseOnGrid(X, Y); Point := ClientToScreen(Classes.Point(X, Y)); frmMain.Commands.DoContextMenu(FFileView, Point.x, Point.y, BackgroundClick); end else if (gMouseSelectionEnabled and (gMouseSelectionButton = 1)) then begin FFileView.tmContextMenu.Enabled:= False; // stop context menu timer end; end { Open folder in new tab on middle click } else if (Button = mbMiddle) and MouseOnGrid(X, Y) then begin frmMain.Commands.cm_OpenDirInNewTab([]); end; end; procedure TFileViewGrid.TopLeftChanged; begin inherited TopLeftChanged; FFileView.Notify([fvnVisibleFilePropertiesChanged]); end; function TFileViewGrid.GetBorderWidth: Integer; begin if Flat and (BorderStyle = bsSingle) then Result := 1 else Result := 0; end; procedure TFileViewGrid.SetColRowCount(Count: Integer); var aCol, aRow: Integer; begin if CellToIndex(Col, Row) < 0 then begin FFileView.FUpdatingActiveFile := True; IndexToCell(Count - 1, ACol, ARow); MoveExtend(False, aCol, aRow); FFileView.FUpdatingActiveFile := False; end; end; procedure TFileViewGrid.DrawLines(aIdx, aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var delta:integer; begin //Canvas.Pen.Width := ColumnsSet.GetColumnBorderFrameWidth(ACol); Canvas.Pen.Width := gBorderFrameWidth; delta := Canvas.Pen.Width shr 1; Canvas.Brush.Style:=bsClear; // Draw frame cursor. if gUseFrameCursor and (gdSelected in aState) and (FFileView.Active or gUseInactiveSelColor) then begin with gColors.FilePanel^ do begin if FFileView.Active then Canvas.Pen.Color := CursorColor else begin Canvas.Pen.Color := InactiveCursorColor; end; end; Canvas.Rectangle(Rect(aRect.Left+delta, aRect.Top+delta , aRect.Right - delta, aRect.Bottom - delta)); end; // Draw drop selection. if (FFileView.FDropFileIndex >= 0) and (aIdx = FFileView.FDropFileIndex) then begin Canvas.Pen.Color := gColors.FilePanel^.ForeColor; Canvas.Rectangle(Rect(aRect.Left+delta, aRect.Top+delta , aRect.Right - delta, aRect.Bottom - delta)); end; Canvas.Brush.Style:=bsSolid; end; procedure TFileViewGrid.PrepareColors(aFile: TDisplayFile; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var TextColor: TColor = clDefault; BackgroundColor: TColor; IsCursor: Boolean; IsCursorInactive: Boolean; begin Canvas.Font.Name := gFonts[dcfMain].Name; Canvas.Font.Size := gFonts[dcfMain].Size; Canvas.Font.Style := gFonts[dcfMain].Style; IsCursor := (gdSelected in aState) and FFileView.Active and (not gUseFrameCursor); IsCursorInactive := (gdSelected in aState) and (not FFileView.Active) and (not gUseFrameCursor); with gColors.FilePanel^ do begin // Set up default background color first. if IsCursor then BackgroundColor := CursorColor else begin if IsCursorInactive AND gUseInactiveSelColor then BackgroundColor := InactiveCursorColor else // Alternate rows background color. if odd(ARow) then BackgroundColor := BackColor else BackgroundColor := BackColor2; end; // Set text color. TextColor := AFile.TextColor; if (TextColor = clDefault) or (TextColor = clNone) then TextColor := ForeColor; if AFile.Selected then begin if gUseInvertedSelection then begin //------------------------------------------------------ if IsCursor OR (IsCursorInactive AND gUseInactiveSelColor) then begin TextColor := InvertColor(CursorText); end else begin if FFileView.Active OR (not gUseInactiveSelColor) then BackgroundColor := MarkColor else BackgroundColor := InactiveMarkColor; TextColor := BackColor; end; //------------------------------------------------------ end else begin if FFileView.Active OR (not gUseInactiveSelColor) then TextColor := MarkColor else TextColor := InactiveMarkColor; end; end else if IsCursor then begin TextColor := CursorText; end; end; BackgroundColor := FFileView.DimColor(BackgroundColor); if AFile.RecentlyUpdatedPct <> 0 then begin if ColorIsLight(BackgroundColor) then begin TextColor := LightColor(TextColor, AFile.RecentlyUpdatedPct); BackgroundColor := LightColor(BackgroundColor, AFile.RecentlyUpdatedPct) end else begin TextColor := DarkColor(TextColor, AFile.RecentlyUpdatedPct); BackgroundColor := DarkColor(BackgroundColor, AFile.RecentlyUpdatedPct); end; end; // Draw background. Canvas.Brush.Color := BackgroundColor; Canvas.FillRect(aRect); Canvas.Font.Color := TextColor; end; {$if lcl_fullversion >= 1070000} procedure TFileViewGrid.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); begin // Don't auto adjust vertical layout inherited DoAutoAdjustLayout(AMode, AXProportion, 1.0); end; {$endif} constructor TFileViewGrid.Create(AOwner: TComponent; AParent: TWinControl); begin FFileView := AParent as TFileViewWithGrid; inherited Create(AOwner); // Workaround for Lazarus issue 18832. // Set Fixed... before setting ...Count. FixedRows := 0; FixedCols := 0; // Override default values to start with one column and one rows. RowCount := 1; ColCount := 1; DefaultColWidth := 200; BorderStyle := bsNone; // Border no need as grid inside pagectl Self.Parent := AParent; DoubleBuffered := True; Align := alClient; MouseWheelOption:= mwGrid; AllowOutboundEvents := False; Options := [goTabs, goThumbTracking]; TabStop := False; UpdateView; end; procedure TFileViewGrid.FinalizeWnd; begin FFileView.FinalizeDragDropEx(Self); inherited FinalizeWnd; end; { TFileViewWithGrid } procedure TFileViewWithGrid.RedrawFile(DisplayFile: TDisplayFile); var ACol, ARow: Integer; begin dgPanel.IndexToCell(PtrInt(DisplayFile.DisplayItem), ACol, ARow); dgPanel.InvalidateCell(ACol, ARow); end; procedure TFileViewWithGrid.RedrawFiles; begin dgPanel.Invalidate; end; procedure TFileViewWithGrid.MakeColumnsStrings(AFile: TDisplayFile); begin AFile.DisplayStrings.BeginUpdate; try AFile.DisplayStrings.Clear; AFile.DisplayStrings.Add(FormatFileFunction('DC().GETFILENAME{}', AFile.FSFile, FileSource)); finally AFile.DisplayStrings.EndUpdate; end; end; procedure TFileViewWithGrid.RedrawFile(FileIndex: PtrInt); var ACol, ARow: Integer; begin dgPanel.IndexToCell(FileIndex, ACol, ARow); dgPanel.InvalidateCell(ACol, ARow); end; procedure TFileViewWithGrid.DisplayFileListChanged; var ScrollTo: Boolean; begin ScrollTo := IsActiveFileVisible; // Row count updates and Content updates should be grouped in one transaction // otherwise, Grids may have subtle synchronization issues. dgPanel.BeginUpdate; dgPanel.SetColRowCount(FFiles.Count); // Update grid col and row count dgPanel.CalculateColRowCount; dgPanel.CalculateColumnWidth; SetFilesDisplayItems; dgPanel.EndUpdate; if SetActiveFileNow(RequestedActiveFile, True, FLastTopRowIndex) then RequestedActiveFile := '' else // Requested file was not found, restore position to last active file. SetActiveFileNow(LastActiveFile, ScrollTo, FLastTopRowIndex); Notify([fvnVisibleFilePropertiesChanged]); inherited DisplayFileListChanged; end; procedure TFileViewWithGrid.CreateDefault(AOwner: TWinControl); begin inherited CreateDefault(AOwner); dgPanel:= GetFileViewGridClass.Create(Self, Self); MainControl := dgPanel; TabHeader:= TFileViewFixedHeader.Create(Self, Self); TabHeader.Top:= pnlHeader.Height; lblDetails:= TLabel.Create(pnlFooter); lblDetails.Align:= alRight; lblDetails.Alignment:= taRightJustify; lblDetails.Parent:= pnlFooter; dgPanel.OnSelection:= @dgPanelSelection; // By default always use some properties. FilePropertiesNeeded := [fpName, fpSize, // For info panel (total size, selected size) fpAttributes, // For distinguishing directories fpLink, // For distinguishing directories (link to dir) and link icons fpModificationTime // For selecting/coloring files (by SearchTemplate) ]; end; procedure TFileViewWithGrid.BeforeMakeFileList; begin inherited BeforeMakeFileList; end; procedure TFileViewWithGrid.FileSourceFileListLoaded; begin inherited; FUpdatingActiveFile := True; dgPanel.MoveExtend(False, 0, 0); FUpdatingActiveFile := False; dgPanel.CalculateColRowCount; dgPanel.CalculateColumnWidth; end; procedure TFileViewWithGrid.ClearAfterDragDrop; begin inherited ClearAfterDragDrop; // reset TCustomGrid state dgPanel.FGridState := gsNormal; end; procedure TFileViewWithGrid.AfterChangePath; begin inherited AfterChangePath; if not IsLoadingFileList then begin FUpdatingActiveFile := True; dgPanel.MoveExtend(False, 0, 0); FUpdatingActiveFile := False; end; end; function TFileViewWithGrid.GetActiveFileIndex: PtrInt; begin Result := dgPanel.CellToIndex(dgPanel.Col, dgPanel.Row); end; function TFileViewWithGrid.GetFileIndexFromCursor(X, Y: Integer; out AtFileList: Boolean): PtrInt; var bTemp: Boolean; iRow, iCol: LongInt; begin with dgPanel do begin bTemp:= AllowOutboundEvents; AllowOutboundEvents:= False; MouseToCell(X, Y, iCol, iRow); AllowOutboundEvents:= bTemp; Result:= CellToIndex(iCol, iRow); AtFileList := True; // Always at file list because header in dgPanel not used end; end; function TFileViewWithGrid.GetFileRect(FileIndex: PtrInt): TRect; var ACol, ARow: Integer; begin dgPanel.IndexToCell(FileIndex, ACol, ARow); Result := dgPanel.CellRect(ACol, ARow); end; procedure TFileViewWithGrid.DoOnResize; var I: Integer; AWidth: Integer; begin inherited DoOnResize; if Assigned(TabHeader) then begin AWidth:= Width div TabHeader.Sections.Count; for I:= 0 to TabHeader.Sections.Count - 1 do TabHeader.Sections[I].Width:= AWidth; end; UpdateFooterDetails; Notify([fvnVisibleFilePropertiesChanged]); end; constructor TFileViewWithGrid.Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); begin inherited Create(AOwner, AConfig, ANode, AFlags); end; constructor TFileViewWithGrid.Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags); var I: Integer; begin inherited Create(AOwner, AFileView, AFlags); if (not (AFileView is TFileViewWithGrid)) and Assigned(FAllDisplayFiles) then begin // Update display strings in case FileView type have changed. for I := 0 to FAllDisplayFiles.Count - 1 do MakeColumnsStrings(FAllDisplayFiles[I]); end; TabHeader.UpdateSorting(Sorting); end; destructor TFileViewWithGrid.Destroy; begin inherited Destroy; end; procedure TFileViewWithGrid.CloneTo(FileView: TFileView); begin if Assigned(FileView) then begin inherited CloneTo(FileView); if FileView is TFileViewWithGrid then with FileView as TFileViewWithGrid do begin TabHeader.UpdateSorting(Self.Sorting); end; end; end; function TFileViewWithGrid.AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; begin Result:= inherited AddFileSource(aFileSource, aPath); if Result and (not IsLoadingFileList) then begin FUpdatingActiveFile := True; dgPanel.MoveExtend(False, 0, 0); FUpdatingActiveFile := False; end; end; procedure TFileViewWithGrid.LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); begin inherited LoadConfiguration(AConfig, ANode); TabHeader.UpdateSorting(Sorting); end; procedure TFileViewWithGrid.SetActiveFile(FileIndex: PtrInt; ScrollTo: Boolean; aLastTopRowIndex: PtrInt = -1); var ACol, ARow: Integer; begin dgPanel.IndexToCell(FileIndex, ACol, ARow); if not ScrollTo then dgPanel.SetColRow(ACol, ARow) else begin dgPanel.MoveExtend(False, ACol, ARow); dgPanel.Click; end; end; procedure TFileViewWithGrid.SetFilesDisplayItems; var i: Integer; begin for i := 0 to FFiles.Count - 1 do FFiles[i].DisplayItem := Pointer(i); end; procedure TFileViewWithGrid.UpdateFooterDetails; var AFile: TFile; AFileName: String; begin if not Assigned(FAllDisplayFiles) or (FAllDisplayFiles.Count = 0) or (FSelectedCount > 0) then lblDetails.Caption:= EmptyStr else begin AFile:= CloneActiveFile; if Assigned(AFile) then try // Get details info about file AFileName:= #32#32 +FormatFileFunction('DC().GETFILEEXT{}', AFile, FileSource); AFileName:= AFileName + #32#32 + FormatFileFunction('DC().GETFILESIZE{}', AFile, FileSource); AFileName:= AFileName + #32#32 + FormatFileFunction('DC().GETFILETIME{}', AFile, FileSource); AFileName:= AFileName + #32#32 + FormatFileFunction('DC().GETFILEATTR{}', AFile, FileSource); lblDetails.Caption:= AFileName; // Get file name if not FlatView then begin AFileName:= FormatFileFunction('DC().GETFILENAMENOEXT{}', AFile, FileSource); lblInfo.Caption:= FitFileName(AFileName, lblInfo.Canvas, AFile, lblInfo.ClientWidth); end; finally AFile.Free; end; end; end; procedure TFileViewWithGrid.dgPanelSelection(Sender: TObject; aCol, aRow: Integer); begin DoFileIndexChanged(dgPanel.CellToIndex(aCol, aRow), dgPanel.TopRow); UpdateFooterDetails; end; procedure TFileViewWithGrid.UpdateInfoPanel; begin inherited UpdateInfoPanel; UpdateFooterDetails; end; procedure TFileViewWithGrid.DoUpdateView; function CalculateTabHeaderHeight: Integer; var OldFont: TFont; begin with TabHeader do begin OldFont := Canvas.Font; Canvas.Font := Font; Result := Canvas.TextHeight('Wg'); Canvas.Font := OldFont; end; end; var TabHeaderHeight: Integer; begin inherited DoUpdateView; dgPanel.FocusRectVisible := gUseCursorBorder and not gUseFrameCursor; dgPanel.FocusColor := gColors.FilePanel^.CursorBorderColor; dgPanel.UpdateView; TabHeader.Visible := gTabHeader; // Set rows of header. if gTabHeader then begin TabHeader.UpdateHeader; TabHeaderHeight := Max(gIconsSize, CalculateTabHeaderHeight); TabHeaderHeight := TabHeaderHeight + 2; // for borders if not gInterfaceFlat then begin TabHeaderHeight := TabHeaderHeight + 2; // additional borders if not flat end; TabHeader.Height := TabHeaderHeight; end; Notify([fvnVisibleFilePropertiesChanged]); end; procedure TFileViewWithGrid.SetSorting(const NewSortings: TFileSortings); begin inherited SetSorting(NewSortings); TabHeader.UpdateSorting(NewSortings); end; constructor TFileViewWithGrid.Create(AOwner: TWinControl; AFileSource: IFileSource; APath: String; AFlags: TFileViewFlags); begin inherited Create(AOwner, AFileSource, APath, AFlags); end; procedure TFileViewWithGrid.DoFileUpdated(AFile: TDisplayFile; UpdatedProperties: TFilePropertiesTypes); begin MakeColumnsStrings(AFile); inherited DoFileUpdated(AFile, UpdatedProperties); end; procedure TFileViewWithGrid.DoHandleKeyDown(var Key: Word; Shift: TShiftState); var Index, aCol, aRow: Integer; AFile: TDisplayFile; begin case Key of VK_INSERT: begin if not IsEmpty then begin Index:= GetActiveFileIndex; if IsFileIndexInRange(Index) then begin AFile := FFiles[Index]; if IsItemValid(AFile) then begin InvertFileSelection(AFile, False); DoSelectionChanged(Index); end; dgPanel.IndexToCell(Index + 1, aCol, aRow); if not ((aCol < 0) and (aRow < 0)) then begin dgPanel.Col:= aCol; dgPanel.Row:= aRow; end; end; end; Key := 0; end; VK_SPACE: if Shift * KeyModifiersShortcut = [] then begin Index:= GetActiveFileIndex; if IsFileIndexInRange(Index) then begin AFile := FFiles[Index]; if IsItemValid(aFile) then begin if (aFile.FSFile.IsDirectory or aFile.FSFile.IsLinkToDirectory) and not aFile.Selected then begin CalculateSpace(aFile); end; InvertFileSelection(aFile, False); DoSelectionChanged(Index); if gSpaceMovesDown then begin dgPanel.IndexToCell(Index + 1, aCol, aRow); if not ((aCol < 0) and (aRow < 0)) then begin dgPanel.Col:= aCol; dgPanel.Row:= aRow; end; end; end; end; Key := 0; end; end; inherited DoHandleKeyDown(Key, Shift); end; procedure TFileViewWithGrid.UpdateFlatFileName; var AFile: TFile; AFileName: String; begin AFile:= CloneActiveFile; if Assigned(AFile) then try AFileName:= ExtractDirLevel(CurrentPath, AFile.Path) + AFile.NameNoExt; lblInfo.Caption := MinimizeFilePath(AFileName, lblInfo.Canvas, lblInfo.Width); finally AFile.Free; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/ufileviewwithmainctrl.pas��������������������������������������������0000644�0001750�0000144�00000153747�14743153644�022545� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Base class for file views which have a main control with a list of files. Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) Copyright (C) 2015-2023 Alexander Koblov (alexx2000@mail.ru) 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 } unit uFileViewWithMainCtrl; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, ExtCtrls, StdCtrls, LCLType, LMessages, EditBtn, Graphics, LCLVersion, uFile, uFileViewWorker, uOrderedFileView, uFileView, uDragDropEx, uFileViewNotebook, uDebug; type TRenameFileActionType=(rfatName,rfatExt,rfatFull,rfatToSeparators,rfatNextSeparated); TRenameFileEditInfo=record LenNam:integer; // length of renaming file name LenExt:integer; // length of renaming file ext LenFul:integer; // full length of renaming file name with ext and dot CylceFinished:boolean; UserManualEdit:boolean; // true if user press a key or click/select part of filename, false - if pressed F2(or assigned key) LastAction:TRenameFileActionType; // need for organize correct cycle Name-FullName-Ext (or FullName-Name-Ext) end; { TEditButtonEx } TEditButtonEx = class(TEditButton) private procedure handleSpecialKeys( Key: Word ); function GetFont: TFont; procedure SetFont(AValue: TFont); protected // Workaround: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/36006 {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and (LCL_FULLVERSION < 3020000)} procedure Hack(Data: PtrInt); procedure EditExit; override; {$ENDIF} function CalcButtonVisible: Boolean; override; function GetDefaultGlyphName: String; override; procedure EditKeyDown(var Key: word; Shift: TShiftState); override; public onKeyESCAPE: TNotifyEvent; onKeyRETURN: TNotifyEvent; property Font: TFont read GetFont write SetFont; end; { TFileViewWithMainCtrl } TFileViewWithMainCtrl = class(TOrderedFileView) private {$IFDEF LCLGTK2} FLastDoubleClickTime : TDateTime; {$ENDIF} FMainControl: TWinControl; { Events for drag&drop from external applications } function OnExDragBegin: Boolean; function OnExDragEnd: Boolean; function OnExDragEnter(var DropEffect: TDropEffect; ScreenPoint: TPoint): Boolean; function OnExDragOver(var DropEffect: TDropEffect; ScreenPoint: TPoint): Boolean; function OnExDrop(const FileNamesList: TStringList; DropEffect: TDropEffect; ScreenPoint: TPoint): Boolean; function OnExDragLeave: Boolean; procedure SetMainControl(AValue: TWinControl); procedure tmContextMenuTimer(Sender: TObject); // Needed for rename on mouse procedure tmRenameFileTimer(Sender: TObject); // If internal dragging is currently in effect, this function // stops internal dragging and starts external. procedure TransformDraggingToExternal(ScreenPoint: TPoint); procedure edtRenameEnter(Sender: TObject); procedure edtRenameExit(Sender: TObject); procedure edtRenameButtonClick(Sender: TObject); procedure edtRenameMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); {$IFDEF LCLWIN32} procedure edtRenameKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); {$ENDIF} procedure edtRenameOnKeyESCAPE(Sender: TObject); procedure edtRenameOnKeyRETURN(Sender: TObject); protected edtRename: TEditButtonEx; FRenameFile: TFile; FRenFile:TRenameFileEditInfo; FRenTags:string; // rename separators FWindowProc: TWndMethod; // Used to register as a drag and drop source and target. FDragDropSource: uDragDropEx.TDragDropSource; FDragDropTarget: uDragDropEx.TDragDropTarget; FHintFileIndex: PtrInt; FMainControlLastMouseButton: TMouseButton; // Mouse button that initiated dragging {en Used to check if button-up was received after button-down or after dropping something after dragging with right mouse button. } FMainControlMouseDown: Boolean; FMainControlMouseDownPoint: TPoint; FMouseSelectionStartIndex: Integer; FMouseSelectionLastState: Boolean; FDragStartPoint: TPoint; FDragFileIndex: PtrInt; FDropFileIndex: PtrInt; FStartDrag: Boolean; tmContextMenu: TTimer; tmMouseScroll: TTimer; // Needed for rename on mouse FRenameFileIndex: PtrInt; tmRenameFile: TTimer; FMouseRename: Boolean; FMouseFocus: Boolean; {$IFNDEF LCLWIN32} FMouseEnter: Boolean; {$ENDIF} procedure AfterChangePath; override; // Simulates releasing mouse button that started a dragging operation, // but was released in another window or another application. procedure ClearAfterDragDrop; virtual; procedure CreateDefault(AOwner: TWinControl); override; procedure DisplayFileListChanged; override; {en Changes drawing colors depending on if this panel is active. } procedure DoActiveChanged; override; procedure DoLoadingFileListLongTime; override; procedure DoUpdateView; override; procedure FinalizeDragDropEx(AControl: TWinControl); {en Retrieves file index under mouse cursor. @param(X, Y Should be client coordinates of MainControl.) @param(AtFileList Whether X, Y point to the filelist, not at specific file but at empty space. If AtFileList is @false then X, Y point somewhere outside the file list.) } function GetFileIndexFromCursor(X, Y: Integer; out AtFileList: Boolean): PtrInt; virtual; abstract; procedure InitializeDragDropEx(AControl: TWinControl); procedure MouseScrollTimer(Sender: TObject); virtual; abstract; {en Returns @true if currently selecting with right mouse button. } function IsMouseSelecting: Boolean; inline; procedure MainControlDblClick(Sender: TObject); procedure DoMainControlFileWork; procedure MouseStateReset; procedure MainControlQuadClick(Sender: TObject); procedure MainControlDragDrop(Sender, Source: TObject; X, Y: Integer); procedure MainControlDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure MainControlEndDrag(Sender, Target: TObject; X, Y: Integer); procedure MainControlEnter(Sender: TObject); procedure MainControlExit(Sender: TObject); procedure MainControlKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure MainControlKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure MainControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure MainControlMouseLeave(Sender: TObject); procedure MainControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure MainControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure MainControlShowHint(Sender: TObject; HintInfo: PHintInfo); procedure MainControlUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); procedure MainControlResize(Sender: TObject); procedure MainControlWindowProc(var TheMessage: TLMessage); {en Updates the drop row index, which is used to draw a rectangle on directories during drag&drop operations. } procedure SetDropFileIndex(NewFileIndex: PtrInt); function GetIconRect(FileIndex: PtrInt): TRect; virtual; procedure WorkerStarting(const Worker: TFileViewWorker); override; procedure WorkerFinished(const Worker: TFileViewWorker); override; procedure ShowRenameFileEditInitSelect(Data: PtrInt); procedure ShowRenameFileEdit(var AFile: TFile); virtual; procedure UpdateRenameFileEditPosition; virtual; procedure RenameSelectPart(AActionType:TRenameFileActionType); virtual; property MainControl: TWinControl read FMainControl write SetMainControl; {$IFDEF LCLGTK2} function TooManyDoubleClicks: Boolean; {$ENDIF} public destructor Destroy; override; procedure DoDragDropOperation(Operation: TDragDropOperation; var DropParams: TDropParams); override; function Focused: Boolean; override; procedure SetFocus; override; procedure SetDragCursor(Shift: TShiftState); override; procedure UpdateColor; override; published procedure cm_RenameOnly(const Params: array of string); procedure cm_ContextMenu(const Params: array of string); end; implementation uses {$IF DEFINED(LCLGTK2)} Gtk2Proc, // for ReleaseMouseCapture GTK2Globals, // for DblClickTime {$ENDIF} LCLIntf, LCLProc, LazUTF8, Forms, Dialogs, Buttons, DCOSUtils, DCStrUtils, fMain, uShowMsg, uLng, uFileProperty, uFileSource, uFileSourceOperationTypes, uGlobs, uInfoToolTip, uDisplayFile, uFileSystemFileSource, uFileSourceUtil, uArchiveFileSourceUtil, uFormCommands, uKeyboard, uFileSourceSetFilePropertyOperation, uFileSystemWatcher; type TControlHandlersHack = class(TWinControl) end; { TEditButtonEx } procedure TEditButtonEx.EditKeyDown(var Key: Word; Shift: TShiftState); begin inherited EditKeyDown(Key, Shift); case Key of VK_ESCAPE, VK_RETURN, VK_SELECT: handleSpecialKeys( Key ); {$IFDEF LCLGTK2} // Workaround for GTK2 - up and down arrows moving through controls. VK_UP, VK_DOWN: Key := 0; {$ENDIF} end; end; procedure TEditButtonEx.handleSpecialKeys( Key: Word ); begin if Key=VK_ESCAPE then begin if Assigned(onKeyESCAPE) then onKeyESCAPE( self ); end else begin if Assigned(onKeyRETURN) then onKeyRETURN( self ); end; end; function TEditButtonEx.GetFont: TFont; begin Result:= BaseEditor.Font; end; procedure TEditButtonEx.SetFont(AValue: TFont); begin BaseEditor.Font:= AValue; end; {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and (LCL_FULLVERSION < 3020000)} procedure TEditButtonEx.Hack(Data: PtrInt); begin if (csClicked in Button.ControlState) then begin BuddyClick; Button.ControlState:= Button.ControlState - [csClicked]; end; inherited EditExit; end; procedure TEditButtonEx.EditExit; begin Application.QueueAsyncCall(@Hack, 0); end; {$ENDIF} function TEditButtonEx.GetDefaultGlyphName: String; begin Result:= BitBtnResNames[idButtonOk]; end; function TEditButtonEx.CalcButtonVisible: Boolean; begin Result:= (inherited CalcButtonVisible) and gInplaceRenameButton; end; { TFileViewWithMainCtrl } {$IFDEF LCLWIN32} procedure TFileViewWithMainCtrl.edtRenameKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin case Key of // Workaround for Win32 - right arrow must clear selection at first move. VK_RIGHT: begin if (Win32MajorVersion < 10) and (Shift = []) and (edtRename.SelLength > 0) then begin Key := edtRename.CaretPos.X; edtRename.SelLength := 0; edtRename.CaretPos := Classes.Point(Key, 0); Key := 0; end; FRenFile.UserManualEdit:=True; // user begin manual edit - no need cycle Name,Ext,FullName selection end; VK_LEFT: FRenFile.UserManualEdit:=True; // user begin manual edit - no need cycle Name,Ext,FullName selection end; end; {$ENDIF} procedure TFileViewWithMainCtrl.edtRenameOnKeyESCAPE(Sender: TObject); begin edtRename.Visible:=False; SetFocus; end; procedure TFileViewWithMainCtrl.edtRenameOnKeyRETURN(Sender: TObject); var NewFileName: String; OldFileName: String; begin NewFileName := edtRename.Text; OldFileName := ExtractFileName(edtRename.Hint); try case uFileSourceUtil.RenameFile(FileSource, FRenameFile, NewFileName, True) of sfprSuccess: begin // FRenameFile is nil when a file list // already updated by the real 'rename' event if FlatView and Assigned(FRenameFile) and (TFileSystemWatcher.Features * [fsfFlatView] = []) then begin PushRenameEvent(FRenameFile, NewFileName); end; edtRename.Visible:= False; SetActiveFile(CurrentPath + NewFileName); SetFocus; end; sfprError: msgError(Format(rsMsgErrRename, [OldFileName, NewFileName])); end; except on e: EInvalidFileProperty do msgError(Format(rsMsgErrRename + ':' + LineEnding + '%s (%s)', [OldFileName, NewFileName, rsMsgInvalidFileName, e.Message])); end; end; procedure TFileViewWithMainCtrl.ClearAfterDragDrop; begin tmMouseScroll.Enabled := False; // Clear some control specific flags. MainControl.ControlState := MainControl.ControlState - [csClicked, csLButtonDown]; end; procedure TFileViewWithMainCtrl.cm_ContextMenu(const Params: array of string); var Rect: TRect; Point: TPoint; AFileIndex: PtrInt; UserWishForContextMenu: TUserWishForContextMenu = uwcmComplete; bUserWishJustActionMenu: boolean; begin if IsLoadingFileList then Exit; if Length(Params)>0 then begin GetParamBoolValue(Params[0], 'justactionmenu', bUserWishJustActionMenu); if bUserWishJustActionMenu then UserWishForContextMenu:=uwcmJustDCAction else UserWishForContextMenu:=uwcmComplete; end; AFileIndex:= GetActiveFileIndex; if AFileIndex < 0 then begin Point.X:= 0; Point.Y:= 0; end else begin Rect := GetFileRect(AFileIndex); Point.X := Rect.Left + ((Rect.Right - Rect.Left) div 2); Point.Y := Rect.Top + ((Rect.Bottom - Rect.Top) div 2); end; Point := MainControl.ClientToScreen(Point); // SetCursorPos(Point.X+100, Point.Y+25); frmMain.Commands.DoContextMenu(Self, Point.X, Point.Y, False, UserWishForContextMenu); end; procedure TFileViewWithMainCtrl.CreateDefault(AOwner: TWinControl); begin FDropFileIndex := -1; FHintFileIndex := -1; {$IFDEF LCLGTK2} FLastDoubleClickTime := Now; {$ENDIF} FStartDrag := False; inherited CreateDefault(AOwner); edtRename := TEditButtonEx.Create(Self); edtRename.Visible := False; edtRename.TabStop := False; edtRename.AutoSize := False; {$IFDEF LCLWIN32} edtRename.onKeyDown:=@edtRenameKeyDown; {$ENDIF} edtRename.onKeyESCAPE:=@edtRenameOnKeyESCAPE; edtRename.onKeyRETURN:=@edtRenameOnKeyRETURN; edtRename.OnMouseDown:=@edtRenameMouseDown; edtRename.OnEnter := @edtRenameEnter; edtRename.OnExit := @edtRenameExit; edtRename.OnButtonClick := @edtRenameButtonClick; tmMouseScroll := TTimer.Create(Self); tmMouseScroll.Enabled := False; tmMouseScroll.Interval := 100; tmMouseScroll.OnTimer := @MouseScrollTimer; tmContextMenu := TTimer.Create(Self); tmContextMenu.Enabled := False; tmContextMenu.Interval := 500; tmContextMenu.OnTimer := @tmContextMenuTimer; tmRenameFile := TTimer.Create(Self); tmRenameFile.Enabled := False; tmRenameFile.Interval := 1000; tmRenameFile.OnTimer := @tmRenameFileTimer; FRenameFileIndex := -1; end; destructor TFileViewWithMainCtrl.Destroy; begin if Assigned(HotMan) then HotMan.UnRegister(MainControl); inherited Destroy; end; procedure TFileViewWithMainCtrl.DisplayFileListChanged; begin inherited DisplayFileListChanged; if edtRename.Visible then UpdateRenameFileEditPosition; end; procedure TFileViewWithMainCtrl.DoActiveChanged; begin inherited DoActiveChanged; UpdateColor; // Needed for rename on mouse FMouseRename := False; end; procedure TFileViewWithMainCtrl.DoDragDropOperation(Operation: TDragDropOperation; var DropParams: TDropParams); var AFile: TDisplayFile; ClientDropPoint: TPoint; FileIndex: PtrInt; AtFileList: Boolean; FileSourceIndex, PathIndex: Integer; begin try with DropParams do begin if Files.Count > 0 then begin ClientDropPoint := MainControl.ScreenToClient(ScreenDropPoint); FileIndex := GetFileIndexFromCursor(ClientDropPoint.X, ClientDropPoint.Y, AtFileList); // default to current active directory in the destination panel TargetPath := Self.CurrentPath; if (DropIntoDirectories = True) and IsFileIndexInRange(FileIndex) then begin AFile := FFiles[FileIndex]; // If dropped into a directory modify destination path and file source accordingly. if Assigned(AFile) and (AFile.FSFile.IsDirectory or AFile.FSFile.IsLinkToDirectory) then begin if AFile.FSFile.Name = '..' then begin if TargetFileSource.IsPathAtRoot(CurrentPath) then begin // Change to previous file source and last path. FileSourceIndex := History.CurrentFileSourceIndex - 1; if FileSourceIndex < 0 then TargetFileSource := nil // No parent file sources. else begin PathIndex := History.PathsCount[FileSourceIndex] - 1; if PathIndex < 0 then TargetFileSource := nil // No paths. else begin TargetFileSource := FileSources[FileSourceIndex]; TargetPath := History.Path[FileSourceIndex, PathIndex]; end; end; end else begin // Remove the last subdirectory in the path. TargetPath := TargetFileSource.GetParentDir(TargetPath); end; end else TargetPath := TargetPath + AFile.FSFile.Name + DirectorySeparator; end else if FileIsArchive(AFile.FSFile.FullPath) then try TargetFileSource:= GetArchiveFileSource(FileSource, AFile.FSFile, EmptyStr, False, False); if Assigned(TargetFileSource) then TargetPath:= TargetFileSource.GetRootDir; except on E: Exception do msgError(E.Message + LineEnding + AFile.FSFile.FullPath); end; end; end; end; // Execute the operation. frmMain.DoDragDropOperation(Operation, DropParams); finally FreeAndNil(DropParams); end; end; procedure TFileViewWithMainCtrl.DoLoadingFileListLongTime; begin UpdateColor; inherited DoLoadingFileListLongTime; end; procedure TFileViewWithMainCtrl.DoUpdateView; begin inherited DoUpdateView; UpdateColor; end; procedure TFileViewWithMainCtrl.UpdateColor; begin inherited UpdateColor; MainControl.Color := DimColor(gColors.FilePanel^.BackColor); end; procedure TFileViewWithMainCtrl.FinalizeDragDropEx(AControl: TWinControl); begin FreeAndNil(FDragDropSource); FreeAndNil(FDragDropTarget); end; function TFileViewWithMainCtrl.Focused: Boolean; begin Result := Assigned(MainControl) and MainControl.Focused; end; procedure TFileViewWithMainCtrl.InitializeDragDropEx(AControl: TWinControl); begin // Register as drag&drop source and target. FDragDropSource := uDragDropEx.CreateDragDropSource(AControl); if Assigned(FDragDropSource) then FDragDropSource.RegisterEvents(nil, nil, @OnExDragEnd); FDragDropTarget := uDragDropEx.CreateDragDropTarget(AControl); if Assigned(FDragDropTarget) then FDragDropTarget.RegisterEvents(@OnExDragEnter, @OnExDragOver, @OnExDrop, @OnExDragLeave); end; function TFileViewWithMainCtrl.IsMouseSelecting: Boolean; begin Result := FMainControlMouseDown and (FMainControlLastMouseButton = mbRight) and gMouseSelectionEnabled and (gMouseSelectionButton = 1); end; procedure TFileViewWithMainCtrl.MainControlDblClick(Sender: TObject); {$IFDEF LCLCOCOA} // Trigger MouseUp Event if Tab Changed var OldTabIndex: Integer; NewTabIndex: Integer; begin if not Assigned(NotebookPage) then begin DoMainControlFileWork(); exit; end; OldTabIndex := TFileViewPage(NotebookPage).Notebook.ActivePageIndex; DoMainControlFileWork(); NewTabIndex := TFileViewPage(NotebookPage).Notebook.ActivePageIndex; if NewTabIndex<> OldTabIndex then TControl(Sender).Perform(LM_LBUTTONUP,0,0); end; {$ELSE} begin DoMainControlFileWork(); end; {$ENDIF} procedure TFileViewWithMainCtrl.DoMainControlFileWork; var Point : TPoint; FileIndex : PtrInt; AtFileList: Boolean; begin // Needed for rename on mouse tmRenameFile.Enabled := False; FRenameFileIndex := -1; if IsLoadingFileList then Exit; {$IFDEF LCLGTK2} // Workaround for two doubleclicks being sent on GTK. if TooManyDoubleClicks then Exit; {$ENDIF} FStartDrag := False; // don't start drag on double click Point := FMainControlMouseDownPoint; // If on a file/directory then choose it. FileIndex := GetFileIndexFromCursor(Point.x, Point.y, AtFileList); if IsFileIndexInRange(FileIndex) then begin {$IF DEFINED(LCLQT) or DEFINED(LCLQT5)} // Workaround: under Qt4 widgetset long operation (opening archive // for example) blocking mouse at whole system while operation executing Sleep(100); Application.ProcessMessages; {$ENDIF} ChooseFile(FFiles[FileIndex]); end else if gDblClickToParent and AtFileList then begin ChangePathToParent(True); end; {$IFDEF LCLGTK2} FLastDoubleClickTime := Now; {$ENDIF} end; procedure TFileViewWithMainCtrl.MouseStateReset; begin FStartDrag := False; FRangeSelecting := False; if IsMouseSelecting and (GetCaptureControl = MainControl) then SetCaptureControl(nil); FMainControlMouseDown := False; end; procedure TFileViewWithMainCtrl.MainControlDragDrop(Sender, Source: TObject; X, Y: Integer); var SourcePanel: TFileViewWithMainCtrl; SourceFiles: TFiles; DropParams: TDropParams; begin if not (Source is TWinControl) or not (TWinControl(Source).Parent is TFileViewWithMainCtrl) then Exit; SourcePanel := ((Source as TWinControl).Parent) as TFileViewWithMainCtrl; // Get file names from source panel. SourceFiles := SourcePanel.CloneSelectedOrActiveFiles; try // Drop onto target panel. DropParams := TDropParams.Create( SourceFiles, // Will be freed automatically. GetDropEffectByKeyAndMouse(GetKeyShiftStateEx, SourcePanel.FMainControlLastMouseButton, gDefaultDropEffect), MainControl.ClientToScreen(Classes.Point(X, Y)), True, SourcePanel, Self, Self.FileSource, Self.CurrentPath); frmMain.DropFiles(DropParams); SetDropFileIndex(-1); except FreeAndNil(SourceFiles); raise; end; end; procedure TFileViewWithMainCtrl.MainControlDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var AFile: TDisplayFile; SourcePanel: TFileView; TargetPanel: TFileView; SourceDir, TargetDir: String; FileIndex: PtrInt; AtFileList: Boolean; begin Accept := False; if not (Source is TWinControl) or not (TWinControl(Source).Parent is TFileView) then Exit; SourcePanel := ((Source as TWinControl).Parent) as TFileView; TargetPanel := Self; FileIndex := GetFileIndexFromCursor(X, Y, AtFileList); // Always allow dropping into an empty panel. // And it is also allowed to drop onto header in case all visible items // are directories and the user wants to drop into panel's current directory. if FileIndex = InvalidFileIndex then begin SetDropFileIndex(-1); Accept := Sender <> Source; Exit; end; SourceDir := SourcePanel.CurrentPath; TargetDir := TargetPanel.CurrentPath; AFile := FFiles[FileIndex]; if AFile.FSFile.IsDirectory or AFile.FSFile.IsLinkToDirectory or FileIsArchive(AFile.FSFile.FullPath) then begin if State = dsDragLeave then // Mouse is leaving the control or drop will occur immediately. // Don't draw DropRow rectangle. SetDropFileIndex(-1) else SetDropFileIndex(FileIndex); if Sender = Source then begin if not ((FileIndex = FDragFileIndex) or (AFile.Selected = True)) then Accept := True; end else begin if Assigned(SourcePanel) and Assigned(TargetPanel) then begin if AFile.FSFile.Name = '..' then TargetDir := TargetPanel.FileSource.GetParentDir(TargetDir) else TargetDir := TargetDir + AFile.FSFile.Name + DirectorySeparator; if SourceDir <> TargetDir then Accept := True; end else Accept := True; end; end else if (Sender <> Source) then begin SetDropFileIndex(-1); if Assigned(SourcePanel) then begin if SourcePanel.CurrentPath <> TargetPanel.CurrentPath then Accept := True; end else Accept := True; end else begin SetDropFileIndex(-1); end; end; procedure TFileViewWithMainCtrl.MainControlEndDrag(Sender, Target: TObject; X, Y: Integer); procedure ClearDropNode(aFileView: TFileView); begin if aFileView is TFileViewWithMainCtrl then TFileViewWithMainCtrl(aFileView).SetDropFileIndex(-1); end; begin // If cancelled by the user, DragManager does not send drag-leave event // to the target, so we must clear the DropRow in both panels. ClearDropNode(frmMain.FrameLeft); ClearDropNode(frmMain.FrameRight); if uDragDropEx.TransformDragging = False then ClearAfterDragDrop; end; procedure TFileViewWithMainCtrl.MainControlEnter(Sender: TObject); begin Active := True; {$IFNDEF LCLWIN32} FMouseEnter:= ssLeft in GetKeyShiftStateEx; {$ENDIF} end; procedure TFileViewWithMainCtrl.MainControlExit(Sender: TObject); begin FRangeSelecting := False; end; procedure TFileViewWithMainCtrl.MainControlKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var ScreenPoint: TPoint; begin if IsLoadingFileList then Exit; case Key of VK_APPS: begin cm_ContextMenu([]); Key := 0; end; {$IFDEF DARWIN} VK_LWIN, VK_RWIN, {$ENDIF} VK_MENU: // Alt key if MainControl.Dragging then begin // Force transform to external dragging in anticipation of user // pressing Alt+Tab to change active application window. // Disable flag, so that dragging isn't immediately transformed // back to internal before the other application window is shown. uDragDropEx.AllowTransformToInternal := False; GetCursorPos(ScreenPoint); TransformDraggingToExternal(ScreenPoint); end; end; DoHandleKeyDown(Key, Shift); end; procedure TFileViewWithMainCtrl.MainControlKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin FRangeSelecting := False; end; procedure TFileViewWithMainCtrl.MainControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var FileIndex: PtrInt; AtFileList: Boolean; AFile, APreviousFile: TDisplayFile; begin SetDragCursor(Shift); FMainControlMouseDownPoint:= Classes.Point(X, Y); if gRenameConfirmMouse and edtRename.Visible then edtRenameOnKeyRETURN(edtRename); if (DragManager <> nil) and DragManager.IsDragging and (Button = mbRight) then Exit; FileIndex := GetFileIndexFromCursor(X, Y, AtFileList); if not AtFileList then Exit; {$IF DEFINED(LCLWIN32) OR DEFINED(LCLCOCOA)} FMouseFocus:= MainControl.Focused; SetFocus; {$ELSE} FMouseFocus := not FMouseEnter; FMouseEnter := False; {$ENDIF} // history navigation for mice with extra buttons if Button in [mbExtra1, mbExtra2] then begin MouseStateReset; case Button of mbExtra1: GoToPrevHistory; mbExtra2: GoToNextHistory; end; Exit; end; if IsLoadingFileList then Exit; if IsFileIndexInRange(FileIndex) then begin AFile := FFiles[FileIndex]; FMainControlLastMouseButton := Button; // Needed for rename on mouse FRenameFileIndex := -1; case Button of mbRight: begin SetActiveFile(FileIndex, False); if gMouseSelectionEnabled and (gMouseSelectionButton = 1) then begin FMouseSelectionStartIndex := FileIndex; FMouseSelectionLastState := not AFile.Selected; tmContextMenu.Enabled:= True; // start context menu timer MarkFile(AFile, FMouseSelectionLastState, False); DoSelectionChanged(FileIndex); SetCaptureControl(MainControl); end; end; mbLeft: begin if gMouseSelectionEnabled then begin if ssModifier in Shift then begin // if there is no selected files then select also previous file if not HasSelectedFiles then begin APreviousFile := GetActiveDisplayFile; if Assigned(APreviousFile) and (APreviousFile <> AFile) then MarkFile(APreviousFile, True, False); end; InvertFileSelection(AFile, False); DoSelectionChanged(FileIndex); end else if ssShift in Shift then begin FRangeSelecting := True; SelectRange(FileIndex); end else begin if FMouseRename then begin APreviousFile := GetActiveDisplayFile; // Start the rename file timer if the actual file is clicked again if Assigned(APreviousFile) and (APreviousFile = AFile) then begin if AFile.FSFile.IsNameValid then begin FRenameFileIndex := FileIndex; tmRenameFile.Enabled := True; end; end; end; // Select files/folders with a left click on their icons if (gMouseSelectionIconClick > 0) and (PtInRect(GetIconRect(FileIndex), Classes.Point(X, Y))) then begin InvertFileSelection(AFile, False); DoSelectionChanged(FileIndex); FMainControlMouseDown:= False; end // If mark with left button enable else if (gMouseSelectionButton = 0) then begin if not AFile.Selected then MarkFiles(False); end; end; end;//of mouse selection handler end; else begin SetActiveFile(FileIndex); Exit; end; end; { Dragging } // Check if not already dragging (started by a different button) // and if the mouse button is not used for selection. if not MainControl.Dragging and not (gMouseSelectionEnabled and (Button = mbRight) and (gMouseSelectionButton = Integer(Button))) then begin // indicate that drag start at next mouse move event FStartDrag := True; FDragStartPoint.X := X; FDragStartPoint.Y := Y; FDragFileIndex := FileIndex; uDragDropEx.TransformDragging := False; uDragDropEx.AllowTransformToInternal := True; end; end else // if mouse on empty space begin if (Button = mbRight) and (gMouseSelectionEnabled) and (gMouseSelectionButton = 1) then tmContextMenu.Enabled:= True; // start context menu timer end; // Needed for rename on mouse FMouseRename := gInplaceRename; end; procedure TFileViewWithMainCtrl.MainControlMouseLeave(Sender: TObject); begin end; procedure TFileViewWithMainCtrl.MainControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var Point: TPoint; AFile: TDisplayFile; ExpectedButton: TShiftStateEnum; FileIndex: PtrInt; AtFileList: Boolean; SelStartIndex, SelEndIndex: Integer; begin SetDragCursor(Shift); if FMainControlMouseDown and MainControl.Dragging then begin // If dragging has started then clear MouseDown flag. if (Abs(FDragStartPoint.X - X) > DragManager.DragThreshold) or (Abs(FDragStartPoint.Y - Y) > DragManager.DragThreshold) then begin FMainControlMouseDown := False; end; end; // If dragging is currently in effect, the window has mouse capture and // we can retrieve the window over which the mouse cursor currently is. if MainControl.Dragging and uDragDropEx.IsExternalDraggingSupported then begin Point := MainControl.ClientToScreen(Classes.Point(X, Y)); // use specifically LCLIntf.WindowFromPoint to avoid confusion with Windows.WindowFromPoint if LCLIntf.WindowFromPoint(Point) = 0 then begin // If result is 0 then the window belongs to another process // and we transform intra-process dragging into inter-process dragging. TransformDraggingToExternal(Point); end; end else // if we are about to start dragging if FStartDrag and ((Abs(FDragStartPoint.X - X) > DragManager.DragThreshold) or (Abs(FDragStartPoint.Y - Y) > DragManager.DragThreshold)) then begin FStartDrag := False; case FMainControlLastMouseButton of mbLeft : ExpectedButton := ssLeft; mbMiddle : ExpectedButton := ssMiddle; mbRight : ExpectedButton := ssRight; else Exit; end; // Make sure the same mouse button is still pressed. if not (ExpectedButton in Shift) then begin ClearAfterDragDrop; end else if IsFileIndexInRange(FDragFileIndex) then begin AFile := FFiles[FDragFileIndex]; // Check if valid item is being dragged. if IsItemValid(AFile) then begin MainControl.BeginDrag(False); // Restore selection of active file if (FSelectedCount > 0) and (not AFile.Selected) then MarkFile(AFile, True); end; end; end; // Disable the rename file timer if we are dragging if FMouseRename and MainControl.Dragging then begin tmRenameFile.Enabled := False; FRenameFileIndex := -1; end; // Show file info tooltip. if ShowHint and not MainControl.Dragging and ([ssLeft, ssMiddle, ssRight] * Shift = []) then begin FileIndex := GetFileIndexFromCursor(X, Y, AtFileList); if FileIndex <> FHintFileIndex then begin FHintFileIndex := FileIndex; Application.CancelHint; end; end; if edtRename.Visible then Exit; // A single click starts programs and opens files if (gMouseSingleClickStart in [1..3]) and (FMainControlMouseDown = False) and (Shift * [ssShift, ssAlt, ssModifier] = []) and (not MainControl.Dragging) then begin FileIndex := GetFileIndexFromCursor(X, Y, AtFileList); if IsFileIndexInRange(FileIndex) and (GetActiveFileIndex <> FileIndex) then begin SetActiveFile(FileIndex); end; end; // Selection with right mouse button, if enabled. if FMainControlMouseDown and (FMainControlLastMouseButton = mbRight) and gMouseSelectionEnabled and (gMouseSelectionButton = 1) then begin FileIndex := GetFileIndexFromCursor(X, Y, AtFileList); if IsFileIndexInRange(FileIndex) and (GetActiveFileIndex <> FileIndex) then begin tmContextMenu.Enabled:= False; // stop context menu timer if FMouseSelectionStartIndex < FileIndex then begin SelStartIndex := FMouseSelectionStartIndex; SelEndIndex := FileIndex; end else begin SelStartIndex := FileIndex; SelEndIndex := FMouseSelectionStartIndex; end; SetActiveFile(FileIndex, False); MarkFiles(SelStartIndex, SelEndIndex, FMouseSelectionLastState); end; end; end; procedure TFileViewWithMainCtrl.MainControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var FileIndex: PtrInt; AtFileList: Boolean; begin if IsLoadingFileList then Exit; FStartDrag := False; FRangeSelecting := False; // Handle only if button-up was not lifted to finish drag&drop operation. if not FMainControlMouseDown then Exit; if IsMouseSelecting and (GetCaptureControl = MainControl) then SetCaptureControl(nil); // A single click is used to open items if (gMouseSingleClickStart > 0) and (Button = mbLeft) and (Shift * [ssShift, ssAlt, ssModifier, ssDouble] = []) and FMouseFocus then begin // A single click only opens folders. For files, a double click is needed. if (gMouseSingleClickStart and 2 <> 0) then begin FileIndex := GetFileIndexFromCursor(X, Y, AtFileList); if IsFileIndexInRange(FileIndex) then begin with FFiles[FileIndex].FSFile do begin if (IsDirectory or IsLinkToDirectory) then DoMainControlFileWork(); end; end end // A single click starts programs and opens files else begin DoMainControlFileWork(); end; end; FMainControlMouseDown := False; end; procedure TFileViewWithMainCtrl.MainControlQuadClick(Sender: TObject); begin DoMainControlFileWork(); end; procedure TFileViewWithMainCtrl.MainControlShowHint(Sender: TObject; HintInfo: PHintInfo); var sHint: String; AFile: TDisplayFile; begin HintInfo^.HintStr:= EmptyStr; if not gShowToolTip then Exit; if not IsFileIndexInRange(FHintFileIndex) then Exit; AFile := FFiles[FHintFileIndex]; if AFile.FSFile.Name = '..' then Exit; HintInfo^.HintStr:= AFile.FSFile.Name; sHint:= GetFileInfoToolTip(FileSource, AFile.FSFile); if (sHint <> EmptyStr) then HintInfo^.HintStr:= HintInfo^.HintStr + LineEnding + sHint; if gFileInfoToolTipValue[ord(gToolTipHideTimeOut)] <> -1 then HintInfo^.HideTimeout := gFileInfoToolTipValue[ord(gToolTipHideTimeOut)]; end; procedure TFileViewWithMainCtrl.MainControlUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); begin if IsLoadingFileList then Exit; // check if ShiftState is equal to quick search / filter modes if quickSearch.CheckSearchOrFilter(UTF8Key) then Exit; end; procedure TFileViewWithMainCtrl.MainControlResize(Sender: TObject); begin if edtRename.Visible then UpdateRenameFileEditPosition; end; procedure TFileViewWithMainCtrl.MainControlWindowProc(var TheMessage: TLMessage); begin // Cancel rename if user scroll file list by mouse if (TheMessage.Msg = LM_VSCROLL) or (TheMessage.Msg = LM_HSCROLL) or (TheMessage.Msg = LM_MOUSEWHEEL) then begin edtRename.Hide; SetFocus; end; FWindowProc(TheMessage); end; function TFileViewWithMainCtrl.OnExDragBegin: Boolean; begin Result := True; end; function TFileViewWithMainCtrl.OnExDragEnd: Boolean; {$IF DEFINED(MSWINDOWS)} var startPoint: TPoint; currentPoint: TPoint; {$ENDIF} begin {$IF DEFINED(MSWINDOWS)} // On windows dragging can be transformed back into internal. // Check if drag was aborted due to mouse moving back into // the application window or the user just cancelled it. if TransformDragging and (FDragDropSource.GetLastStatus = DragDropAborted) then begin // Transform to internal dragging again. // Save current mouse position. GetCursorPos(currentPoint); // Temporarily set cursor position to the point where the drag was started // so that DragManager can properly read the control being dragged. startPoint := MainControl.ClientToScreen(FDragStartPoint); SetCursorPos(startPoint.X, startPoint.Y); // Begin internal dragging. MainControl.BeginDrag(True); // Move cursor back. SetCursorPos(currentPoint.X, currentPoint.Y); // Clear flag. TransformDragging := False; Exit(True); end; {$ENDIF} ClearAfterDragDrop; Result := True; end; function TFileViewWithMainCtrl.OnExDragEnter(var DropEffect: TDropEffect; ScreenPoint: TPoint): Boolean; begin Result := True; end; function TFileViewWithMainCtrl.OnExDragLeave: Boolean; begin SetDropFileIndex(-1); Result := True; end; function TFileViewWithMainCtrl.OnExDragOver(var DropEffect: TDropEffect; ScreenPoint: TPoint): Boolean; var ClientPoint: TPoint; AFile: TDisplayFile; FileIndex: PtrInt; AtFileList: Boolean; begin // Dropping into empty panel allowed. Result := True; ClientPoint := MainControl.ScreenToClient(ScreenPoint); FileIndex := GetFileIndexFromCursor(ClientPoint.x, ClientPoint.y, AtFileList); if IsFileIndexInRange(FileIndex) then begin // Get the file over which there is something dragged. AFile := FFiles[FileIndex]; // If it is a directory or link mark possibility of drop. if AFile.FSFile.IsDirectory or AFile.FSFile.IsLinkToDirectory or FileIsArchive(AFile.FSFile.FullPath) then SetDropFileIndex(FileIndex) else SetDropFileIndex(-1); end else SetDropFileIndex(-1); end; function TFileViewWithMainCtrl.OnExDrop(const FileNamesList: TStringList; DropEffect: TDropEffect; ScreenPoint: TPoint): Boolean; var AFiles: TFiles = nil; DropParams: TDropParams; begin Result := False; if FileNamesList.Count > 0 then try AFiles := TFileSystemFileSource.CreateFilesFromFileList( ExtractFilePath(FileNamesList[0]), FileNamesList); try DropParams := TDropParams.Create( AFiles, DropEffect, ScreenPoint, True, nil, Self, Self.FileSource, Self.CurrentPath); frmMain.DropFiles(DropParams); Result := True; finally FreeAndNil(AFiles); end; except on e: EFileNotFound do MessageDlg(e.Message, mtError, [mbOK], 0); end; SetDropFileIndex(-1); end; procedure TFileViewWithMainCtrl.SetDropFileIndex(NewFileIndex: PtrInt); var OldDropIndex: PtrInt; begin if FDropFileIndex <> NewFileIndex then begin OldDropIndex := FDropFileIndex; // Set new index before redrawing. FDropFileIndex := NewFileIndex; if IsFileIndexInRange(OldDropIndex) then RedrawFile(OldDropIndex); if IsFileIndexInRange(NewFileIndex) then RedrawFile(NewFileIndex); end; end; function TFileViewWithMainCtrl.GetIconRect(FileIndex: PtrInt): TRect; begin Result:= Classes.Rect(0, 0, 0, 0); end; procedure TFileViewWithMainCtrl.SetFocus; begin // CanFocus checks parent controls, but not parent form. if GetParentForm(Self).CanFocus and MainControl.CanFocus then begin if FFocusQuickSearch then begin MainControl.SetFocus; inherited SetFocus; Exit; end; inherited SetFocus; MainControl.SetFocus; {$IFDEF LCLCOCOA} Active := true; {$ENDIF} end; end; procedure TFileViewWithMainCtrl.SetDragCursor(Shift: TShiftState); var DropEffect: TDropEffect; begin if (DragManager <> nil) and DragManager.IsDragging then begin DropEffect := GetDropEffectByKey(Shift, gDefaultDropEffect); if DropEffect = DropMoveEffect then TControlHandlersHack(MainControl).DragCursor:= crArrowMove else if DropEffect = DropLinkEffect then TControlHandlersHack(MainControl).DragCursor:= crArrowLink else if DropEffect = DropCopyEffect then TControlHandlersHack(MainControl).DragCursor:= crArrowCopy else TControlHandlersHack(MainControl).DragCursor:= crDrag; DragManager.DragMove(Mouse.CursorPos); end else TControlHandlersHack(MainControl).DragCursor:= crDrag; end; procedure TFileViewWithMainCtrl.cm_RenameOnly(const Params: array of string); var aFile: TFile; begin if not IsLoadingFileList and (fsoSetFileProperty in FileSource.GetOperationsTypes) then begin aFile:= CloneActiveFile; if Assigned(aFile) then try if aFile.IsNameValid then ShowRenameFileEdit(aFile) else if gCurDir then ShowPathEdit; finally FreeAndNil(aFile); end; end; end; procedure TFileViewWithMainCtrl.SetMainControl(AValue: TWinControl); begin if FMainControl = AValue then Exit; FMainControl := AValue; FMainControl.ControlStyle := FMainControl.ControlStyle + [csQuadClicks]; FMainControl.OnEnter := @MainControlEnter; FMainControl.OnExit := @MainControlExit; FMainControl.OnKeyDown := @MainControlKeyDown; FMainControl.OnKeyUp := @MainControlKeyUp; FMainControl.OnShowHint := @MainControlShowHint; FMainControl.OnUTF8KeyPress := @MainControlUTF8KeyPress; FMainControl.AddHandlerOnResize(@MainControlResize); TControlHandlersHack(FMainControl).OnDblClick := @MainControlDblClick; TControlHandlersHack(FMainControl).OnQuadClick := @MainControlQuadClick; TControlHandlersHack(FMainControl).OnDragDrop := @MainControlDragDrop; TControlHandlersHack(FMainControl).OnDragOver := @MainControlDragOver; TControlHandlersHack(FMainControl).OnEndDrag := @MainControlEndDrag; TControlHandlersHack(FMainControl).OnMouseDown := @MainControlMouseDown; TControlHandlersHack(FMainControl).OnMouseLeave := @MainControlMouseLeave; TControlHandlersHack(FMainControl).OnMouseMove := @MainControlMouseMove; TControlHandlersHack(FMainControl).OnMouseUp := @MainControlMouseUp; edtRename.Parent := FMainControl; HotMan.Register(MainControl, 'Files Panel'); end; procedure TFileViewWithMainCtrl.tmContextMenuTimer(Sender: TObject); var AFile: TDisplayFile; Index, Count: Integer; ClientPoint, MousePoint: TPoint; Background: Boolean; FileIndex: PtrInt; AtFileList: Boolean; Status: Boolean; begin FMainControlMouseDown:= False; tmContextMenu.Enabled:= False; // stop context menu timer MousePoint := Mouse.CursorPos; ClientPoint := MainControl.ScreenToClient(MousePoint); FileIndex := GetFileIndexFromCursor(ClientPoint.x, ClientPoint.y, AtFileList); Background := not IsFileIndexInRange(FileIndex); if not Background then begin // Skip if a rename is in progress on the same file if FRenameFileIndex = FileIndex then Exit; // Restore selection status by default Status := not FMouseSelectionLastState; if (Status = False) then begin Count := 0; for Index := 0 to FFiles.Count - 1 do begin if FFiles[Index].Selected then begin Inc(Count); // If multiple files selected then // select file under cursor too if Count > 1 then begin Status := True; Break; end; end; end; end; AFile := FFiles[FileIndex]; MarkFile(AFile, Status, False); DoSelectionChanged(FileIndex); end; frmMain.Commands.DoContextMenu(Self, MousePoint.x, MousePoint.y, Background); end; procedure TFileViewWithMainCtrl.tmRenameFileTimer(Sender: TObject); var ClientPoint, MousePoint: TPoint; Background: Boolean; FileIndex: PtrInt; AtFileList: Boolean; begin if FMainControlMouseDown = True then begin FMainControlMouseDown := False; tmRenameFile.Enabled := False; // stop timer Exit; end; tmRenameFile.Enabled := False; // stop timer MousePoint := Mouse.CursorPos; ClientPoint := MainControl.ScreenToClient(MousePoint); FileIndex := GetFileIndexFromCursor(ClientPoint.x, ClientPoint.y, AtFileList); Background := not IsFileIndexInRange(FileIndex); if not Background then begin if FRenameFileIndex = FileIndex then begin FMouseRename := False; cm_RenameOnly([]); end; end; FRenameFileIndex := -1; end; procedure TFileViewWithMainCtrl.TransformDraggingToExternal(ScreenPoint: TPoint); begin // Set flag temporarily before stopping internal dragging, // so that triggered events will know that dragging is transforming. TransformDragging := True; // Stop internal dragging DragManager.DragStop(False); {$IF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} // Under GTK, DragManager does not release it's mouse capture on // DragStop(). We must release it here manually or LCL will get confused // with who "owns" the capture after the GTK drag&drop finishes. ReleaseMouseCapture; {$ENDIF} // Clear flag before starting external dragging. TransformDragging := False; // Start external dragging. // On Windows it does not return until dragging is finished. if IsFileIndexInRange(FDragFileIndex) then begin BeginDragExternal(FFiles[FDragFileIndex], FDragDropSource, FMainControlLastMouseButton, ScreenPoint); end; end; procedure TFileViewWithMainCtrl.edtRenameEnter(Sender: TObject); begin FWindowProc:= MainControl.WindowProc; MainControl.WindowProc:= @MainControlWindowProc; end; procedure TFileViewWithMainCtrl.edtRenameExit(Sender: TObject); begin FreeAndNil(FRenameFile); edtRename.Visible := False; MainControl.WindowProc:= FWindowProc; // OnEnter don't called automatically (bug?) // TODO: Check on which widgetset/OS this is needed. FMainControl.OnEnter(Self); end; procedure TFileViewWithMainCtrl.edtRenameButtonClick(Sender: TObject); begin edtRenameOnKeyRETURN(Sender); end; procedure TFileViewWithMainCtrl.edtRenameMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FRenFile.UserManualEdit:=True; // user begin manual edit - no need cycle Name,Ext,FullName selection end; procedure TFileViewWithMainCtrl.AfterChangePath; begin if edtRename.Visible then begin edtRename.Hide; SetFocus; end; inherited AfterChangePath; if IsMouseSelecting then begin MouseStateReset; end; end; {$IFDEF LCLGTK2} function TFileViewWithMainCtrl.TooManyDoubleClicks: Boolean; begin Result := ((Now - FLastDoubleClickTime) <= ((1/86400)*(DblClickTime/1000))); end; {$ENDIF} procedure TFileViewWithMainCtrl.WorkerFinished(const Worker: TFileViewWorker); begin inherited WorkerFinished(Worker); MainControl.Cursor := crDefault; // Update status line only if not (csDestroying in ComponentState) then UpdateInfoPanel; end; procedure TFileViewWithMainCtrl.ShowRenameFileEditInitSelect(Data: PtrInt); begin if Assigned(FRenameFile) then begin if gRenameSelOnlyName and not (FRenameFile.IsDirectory or FRenameFile.IsLinkToDirectory) then RenameSelectPart(rfatName) else RenameSelectPart(rfatFull); end; end; procedure TFileViewWithMainCtrl.ShowRenameFileEdit(var AFile: TFile); var S: String; begin S:= AFile.Name; FRenFile.LenFul := UTF8Length(S); FRenFile.LenExt := UTF8Length(ExtractFileExt(S)); FRenFile.LenNam := FRenFile.LenFul - FRenFile.LenExt; if edtRename.Visible then begin if AFile.IsDirectory or AFile.IsLinkToDirectory then Exit; if FRenFile.UserManualEdit then FRenFile.CylceFinished:=True; if not FRenFile.CylceFinished then begin if gRenameSelOnlyName then begin if FRenFile.LastAction = rfatName then RenameSelectPart(rfatFull) else begin RenameSelectPart(rfatExt); FRenFile.CylceFinished:= True; Exit; end; end else begin if FRenFile.LastAction = rfatFull then RenameSelectPart(rfatName) else begin RenameSelectPart(rfatExt); FRenFile.CylceFinished:= True; Exit; end; end; exit; end; // if Cycle not finished - below code wil never execute, so cycle finished: if FRenFile.UserManualEdit then // if user do something(selecting by mouse or press key) and then press F2 - extend to nearest separators begin RenameSelectPart(rfatToSeparators); FRenFile.UserManualEdit:= False; end else // else - select next sepoarated part of file RenameSelectPart(rfatNextSeparated); end else begin FRenameFile := aFile; edtRename.Hint := aFile.FullPath; edtRename.Text := aFile.Name; edtRename.Visible := True; edtRename.SetFocus; FRenTags:= ' -_.'; // separator set FRenFile.CylceFinished:= False; // cycle of selection Name-FullName-Ext of FullName-Name-Ext, after finish this cycle will be part selection mechanism if FRenFile.LenExt = 0 then FRenFile.CylceFinished:= True; // don't need cycle if no extension Application.QueueAsyncCall(@ShowRenameFileEditInitSelect, 0); aFile:= nil; end; end; procedure TFileViewWithMainCtrl.UpdateRenameFileEditPosition; var AFile: TDisplayFile; begin if edtRename.Visible then begin AFile:= GetActiveDisplayFile; // Cannot find original file, cancel rename if (AFile = nil) or (not mbCompareFileNames(AFile.FSFile.FullPath, FRenameFile.FullPath)) then begin edtRename.Hide; SetFocus; end; end; end; procedure TFileViewWithMainCtrl.RenameSelectPart(AActionType: TRenameFileActionType); var ib,ie:integer; begin FRenFile.LastAction:=AActionType; case AActionType of // get current selection action type rfatName: begin {$IFDEF LCLGTK2} edtRename.SelStart:=1; {$ENDIF} edtRename.SelStart:=0; edtRename.SelLength:=FRenFile.LenNam; end; rfatExt : begin edtRename.SelStart:=FRenFile.LenNam+1; edtRename.SelLength:=FRenFile.LenExt; end; rfatFull: begin {$IFDEF LCLGTK2} edtRename.SelStart:=1; {$ENDIF} edtRename.SelStart:=0; edtRename.SelLength:=FRenFile.LenFul; end; rfatToSeparators: begin // search backward the separator to set begin of selection ib:=TagPos(FRenTags,edtRename.Text,edtRename.SelStart,True); // begin // skip next separators if exist while (ib>0)and(ib<FRenFile.LenFul)and(Pos(edtRename.Text[ib+1],FRenTags)>0)do inc(ib); if ib>=FRenFile.LenFul then ib:=0; if ib>=edtRename.SelStart+edtRename.SelLength+1 then // if new position index higher of the same - search end index from it ie:=TagPos(FRenTags,edtRename.Text,ib+1,False) else // else search of end begin from last start index+selectionLength+1 ie:=TagPos(FRenTags,edtRename.Text,edtRename.SelStart+edtRename.SelLength+1,False); // end edtRename.SelStart:=ib; edtRename.SelLength:=ie-ib-1; end; rfatNextSeparated: begin ib:=TagPos(FRenTags,edtRename.Text,edtRename.SelStart+edtRename.SelLength+1,False); // skip next separators if exist while (ib>0)and(ib<FRenFile.LenFul)and(Pos(edtRename.Text[ib+1],FRenTags)>0)do inc(ib); //UTF8FindNearestCharStart(); if ib>=FRenFile.LenFul then edtRename.SelStart:=0 else edtRename.SelStart:=ib; ie:=TagPos(FRenTags,edtRename.Text,edtRename.SelStart+1,False)-1; // end if ie<0 then ie:=FRenFile.LenFul; edtRename.SelLength:=ie-edtRename.SelStart; end; end; end; procedure TFileViewWithMainCtrl.WorkerStarting(const Worker: TFileViewWorker); begin inherited WorkerStarting(Worker); MainControl.Cursor := crHourGlass; UpdateInfoPanel; // Update status line only end; end. �������������������������doublecmd-1.1.22/src/fileviews/ufileviewwithpanels.pas����������������������������������������������0000644�0001750�0000144�00000015772�14743153644�022211� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Generic file view containing default panels (header, footer, etc.) Copyright (C) 2012-2018 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) 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, see <http://www.gnu.org/licenses/>. } unit uFileViewWithPanels; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, ExtCtrls, StdCtrls, uFileView, uFileViewHeader, uFileSource; type { TFileViewWithPanels } TFileViewWithPanels = class(TFileView) protected FSelectedCount: Integer; lblInfo: TLabel; pnlFooter: TPanel; pnlHeader: TFileViewHeader; procedure UpdateStatusBarFont; procedure AfterChangePath; override; procedure CreateDefault(AOwner: TWinControl); override; procedure DisplayFileListChanged; override; procedure DoActiveChanged; override; procedure DoSelectionChanged; override; procedure ShowPathEdit; procedure DoUpdateView; override; procedure UpdateFlatFileName; virtual; procedure UpdateInfoPanel; virtual; public property Header:TFileViewHeader read pnlHeader; function AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; override; function RemoveCurrentFileSource: Boolean; override; procedure UpdateColor; override; published procedure cm_EditPath(const {%H-}Params: array of string); end; implementation uses DCStrUtils, uFile, uGlobs, uLng, uFileProperty, uFileViewWorker, uDCUtils; { TFileViewWithPanels } function TFileViewWithPanels.AddFileSource(aFileSource: IFileSource; aPath: String): Boolean; begin Result:= inherited AddFileSource(aFileSource, aPath); if Result then pnlHeader.UpdateAddressLabel; end; procedure TFileViewWithPanels.UpdateStatusBarFont; begin FontOptionsToFont(gFonts[dcfStatusBar], lblInfo.Font); lblInfo.Height := lblInfo.Canvas.TextHeight('Wg'); end; procedure TFileViewWithPanels.AfterChangePath; begin inherited AfterChangePath; if FileSourcesCount > 0 then pnlHeader.UpdatePathLabel; end; procedure TFileViewWithPanels.cm_EditPath(const Params: array of string); begin ShowPathEdit; end; procedure TFileViewWithPanels.CreateDefault(AOwner: TWinControl); begin inherited CreateDefault(AOwner); pnlHeader := TFileViewHeader.Create(Self, Self); pnlFooter := TPanel.Create(Self); pnlFooter.Parent := Self; pnlFooter.Align := alBottom; pnlFooter.BevelInner := bvNone; pnlFooter.BevelOuter := bvNone; pnlFooter.AutoSize := True; pnlFooter.DoubleBuffered := True; lblInfo := TLabel.Create(pnlFooter); lblInfo.Parent := pnlFooter; lblInfo.AutoSize := False; lblInfo.Align := alClient; {$IF DEFINED(LCLGTK2)} // Workaround: "Layout and line" // http://doublecmd.sourceforge.net/mantisbt/view.php?id=573 pnlFooter.Visible := False; {$ENDIF} UpdateStatusBarFont; {$IFDEF LCLCARBON} // Under Carbon AutoSize don't work without it pnlHeader.ClientHeight:= 0; pnlFooter.ClientHeight:= 0; {$ENDIF} end; procedure TFileViewWithPanels.DisplayFileListChanged; begin inherited DisplayFileListChanged; UpdateInfoPanel; end; procedure TFileViewWithPanels.DoActiveChanged; begin inherited DoActiveChanged; pnlHeader.SetActive(Active); end; procedure TFileViewWithPanels.DoSelectionChanged; begin inherited DoSelectionChanged; UpdateInfoPanel; end; procedure TFileViewWithPanels.DoUpdateView; begin inherited DoUpdateView; pnlHeader.Visible := gCurDir; // Current directory pnlFooter.Visible := gStatusBar; // Status bar pnlHeader.UpdateFont; pnlHeader.UpdateAddressLabel; pnlHeader.UpdatePathLabel; UpdateStatusBarFont; end; function TFileViewWithPanels.RemoveCurrentFileSource: Boolean; begin Result:= inherited RemoveCurrentFileSource; if Result and (FileSourcesCount > 0) then pnlHeader.UpdateAddressLabel; end; procedure TFileViewWithPanels.UpdateColor; begin pnlHeader.UpdateColor; end; procedure TFileViewWithPanels.ShowPathEdit; begin pnlHeader.ShowPathEdit; end; procedure TFileViewWithPanels.UpdateFlatFileName; var AFile: TFile; begin AFile:= CloneActiveFile; if Assigned(AFile) then try lblInfo.Caption := MinimizeFilePath(ExtractDirLevel(CurrentPath, AFile.FullPath), lblInfo.Canvas, lblInfo.Width); finally AFile.Free; end; end; procedure TFileViewWithPanels.UpdateInfoPanel; var i: Integer; FilesInDir, FilesSelected, FolderInDir, FolderSelected: Integer; SizeInDir, SizeSelected: Int64; SizeProperty: TFileSizeProperty; begin FSelectedCount := 0; if GetCurrentWorkType = fvwtCreate then begin lblInfo.Caption := rsMsgLoadingFileList; end else if not Assigned(FAllDisplayFiles) or (FAllDisplayFiles.Count = 0) then begin lblInfo.Caption := rsMsgNoFiles; end else if Assigned(FileSource) then begin FilesInDir := 0; FilesSelected := 0; SizeInDir := 0; SizeSelected := 0; FolderInDir := 0; FolderSelected := 0; for i := 0 to FFiles.Count - 1 do begin with FFiles[i] do begin if FSFile.Name = '..' then Continue; if FSFile.IsDirectory then inc(FolderInDir) else inc(FilesInDir); if Selected then begin if FSFile.IsDirectory then inc(FolderSelected) else inc(FilesSelected); end; // Count size if Size property exists. if fpSize in FSFile.AssignedProperties then begin SizeProperty := FSFile.SizeProperty; if SizeProperty.Value > 0 then begin if Selected then SizeSelected := SizeSelected + SizeProperty.Value; SizeInDir := SizeInDir + SizeProperty.Value; end; end; end; end; FSelectedCount := FilesSelected + FolderSelected; if FlatView and (FSelectedCount = 0) then UpdateFlatFileName else lblInfo.Caption := Format(rsMsgSelectedInfo, [cnvFormatFileSize(SizeSelected, uoscFooter), cnvFormatFileSize(SizeInDir, uoscFooter), FilesSelected, FilesInDir, FolderSelected, FolderInDir]); end else if not (csDestroying in ComponentState) then lblInfo.Caption := ''; end; end. ������doublecmd-1.1.22/src/fileviews/ufileviewworker.pas��������������������������������������������������0000644�0001750�0000144�00000077555�14743153644�021353� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileViewWorker; {$mode objfpc}{$H+} interface uses Classes, SysUtils, contnrs, syncobjs, DCStringHashListUtf8, uDisplayFile, uFile, uFileSource, uFileSorting, uFileProperty, DCBasicTypes, uFileSourceOperation, uFileSourceListOperation, fQuickSearch,uMasks; type TFileViewWorkType = (fvwtNone, fvwtCreate, // Creates file list fvwtUpdate); // Updates file list TFileViewWorker = class; TStartingWorkMethod = procedure (const Worker: TFileViewWorker) of object; TFinishedWorkMethod = procedure (const Worker: TFileViewWorker) of object; { TFileViewWorker } TFileViewWorker = class strict private FAborted: Boolean; {en After FCanBeDestroyed is set to True the worker may be destroyed.} FCanBeDestroyed: Boolean; FWorking: Boolean; FOnStarting: TStartingWorkMethod; FOnFinished: TFinishedWorkMethod; FThread: TThread; procedure DoFinished; procedure DoStarting; protected FWorkType: TFileViewWorkType; procedure DoneWorking; procedure Execute; virtual; abstract; function IsWorking: Boolean; virtual; property Thread: TThread read FThread; public constructor Create(AThread: TThread); virtual; procedure Abort; virtual; procedure Start; procedure StartParam(Params: Pointer); property Aborted: Boolean read FAborted; property CanBeDestroyed: Boolean read FCanBeDestroyed; property OnFinished: TFinishedWorkMethod read FOnFinished write FOnFinished; property OnStarting: TStartingWorkMethod read FOnStarting write FOnStarting; property Working: Boolean read IsWorking; property WorkType: TFileViewWorkType read FWorkType; end; TFVWorkerFileList = class private FFiles: TFPObjectList; FUserData: TFPList; function GetCount: Integer; function GetFile(Index: Integer): TDisplayFile; function GetData(Index: Integer): Pointer; public constructor Create; destructor Destroy; override; function AddClone(const AFile: TDisplayFile; UserData: Pointer): Integer; property Count: Integer read GetCount; property Files[Index: Integer]: TDisplayFile read GetFile; property Data[Index: Integer]: Pointer read GetData; property UserData: TFPList read FUserData; end; TSetFileListMethod = procedure (var NewAllDisplayFiles: TDisplayFiles; var NewFilteredDisplayFiles: TDisplayFiles) of object; TUpdateFileMethod = procedure (const UpdatedFile: TDisplayFile; const UserData: Pointer) of object; TAbortFileMethod = procedure (AStart: Integer; AList: TFPList) of object; { TFileListBuilder } TFileListBuilder = class(TFileViewWorker) private FFilteredDisplayFiles: TDisplayFiles; FAllDisplayFiles: TDisplayFiles; FExistingDisplayFilesHashed: TStringHashListUtf8; FSetFileListMethod: TSetFileListMethod; FListOperation: TFileSourceListOperation; FListOperationLock: TCriticalSection; // Data captured from the file view before start. FFileSource: IFileSource; FFileSourceIndex: Integer; FFileFilter: String; FFilterOptions: TQuickSearchOptions; FCurrentPath: String; FFlatView: Boolean; FSortings: TFileSortings; FVariantProperties: TDynamicStringArray; FFilePropertiesNeeded: TFilePropertiesTypes; {en Calls the update method with the new built lists. It is called from GUI thread. } procedure DoSetFileList; class function InternalMatchesFilter(aFile: TFile; const aFileFilter: String; const aFilterOptions: TQuickSearchOptions): Boolean;overload; class function InternalMatchesFilter(aFile: TFile; const aMasks: TMaskList; const aFilterOptions: TQuickSearchOptions): Boolean;overload; protected {en Retrieves file list from file source, sorts and creates a display file list. It may be run from a worker thread so it cannot access GUI directly. } procedure Execute; override; public constructor Create(AFileSource: IFileSource; AFileSourceIndex: Integer; const AFileFilter: String; const AFilterOptions: TQuickSearchOptions; const ACurrentPath: String; const ASorting: TFileSortings; AFlatView: Boolean; AThread: TThread; AFilePropertiesNeeded: TFilePropertiesTypes; AVariantProperties: TDynamicStringArray; ASetFileListMethod: TSetFileListMethod; var ExistingDisplayFiles: TDisplayFiles; var ExistingDisplayFilesHashed: TStringHashListUtf8); reintroduce; destructor Destroy; override; procedure Abort; override; {en Prepare filter string based on options. } class function PrepareFilter(const aFileFilter: String; const aFilterOptions: TQuickSearchOptions): String; {en Fills aFiles with files from aFileSourceFiles. Filters out any files that shouldn't be shown using aFileFilter. } class procedure MakeDisplayFileList(allDisplayFiles: TDisplayFiles; filteredDisplayFiles: TDisplayFiles; aFileFilter: String; const aFilterOptions: TQuickSearchOptions); class procedure MakeAllDisplayFileList(aFileSource: IFileSource; aFileSourceFiles: TFiles; aDisplayFiles: TDisplayFiles; const aSortings: TFileSortings); class procedure MakeAllDisplayFileList(aFileSource: IFileSource; aFileSourceFiles: TFiles; aExistingDisplayFiles: TDisplayFiles; const aSortings: TFileSortings; aExistingDisplayFilesHashed: TStringHashListUtf8); class function MatchesFilter(aFile: TFile; aFileFilter: String; const aFilterOptions: TQuickSearchOptions): Boolean; end; { TFilePropertiesRetriever } TFilePropertiesRetriever = class(TFileViewWorker) private FIndex: Integer; FWorkingFile: TDisplayFile; FWorkingUserData: Pointer; FFileList: TFVWorkerFileList; FUpdateFileMethod: TUpdateFileMethod; FAbortFileMethod: TAbortFileMethod; FFileSource: IFileSource; FVariantProperties: TDynamicStringArray; FFilePropertiesNeeded: TFilePropertiesTypes; {en Updates file in the file view with new data from FWorkerData. It is called from GUI thread. } procedure DoUpdateFile; protected procedure Execute; override; public constructor Create(AFileSource: IFileSource; AThread: TThread; AFilePropertiesNeeded: TFilePropertiesTypes; AVariantProperties: TDynamicStringArray; AUpdateFileMethod: TUpdateFileMethod; ABreakFileMethod: TAbortFileMethod; var AFileList: TFVWorkerFileList); reintroduce; destructor Destroy; override; procedure Abort; override; end; { TCalculateSpaceWorker } TCalculateSpaceWorker = class(TFileViewWorker) private FWorkingIndex: Integer; FWorkingFile: TDisplayFile; FWorkingUserData: Pointer; FFileList: TFVWorkerFileList; FCompletedCalculations: Integer; FUpdateFileMethod: TUpdateFileMethod; FFileSource: IFileSource; FOperation: TFileSourceOperation; FOperationLock: TCriticalSection; {en Updates file in the file view with new data. It is called from GUI thread. } procedure DoUpdateFile; procedure DoUpdateFolders; protected procedure Execute; override; public constructor Create(AFileSource: IFileSource; AThread: TThread; AUpdateFileMethod: TUpdateFileMethod; var AFileList: TFVWorkerFileList); reintroduce; destructor Destroy; override; procedure Abort; override; property CompletedCalculations: Integer read FCompletedCalculations; end; {$IFDEF timeFileView} var filelistTime, filelistPrevTime, filelistLoaderTime: QWord; {$ENDIF} implementation uses {$IFDEF timeFileView} uDebug, {$ENDIF} LCLProc, Graphics, DCFileAttributes, uFileSourceOperationTypes, uOSUtils, DCStrUtils, uDCUtils, uExceptions, uGlobs, uPixMapManager, uFileSourceProperty, uFileSourceCalcStatisticsOperation, uFileSourceOperationOptions; {$IFDEF timeFileView} procedure filelistPrintTime(const AMessage: String); inline; begin filelistTime:= GetTickCount64; DCDebug(AMessage + IntToStr(filelistTime - filelistLoaderTime) + ', offset ' + IntToStr(filelistTime - filelistPrevTime)); filelistPrevTime:= filelistTime; end; {$ENDIF} { TFVWorkerFileList } constructor TFVWorkerFileList.Create; begin FFiles := TFPObjectList.Create(True); FUserData := TFPList.Create; inherited; end; destructor TFVWorkerFileList.Destroy; begin inherited; FFiles.Free; FUserData.Free; end; function TFVWorkerFileList.AddClone(const AFile: TDisplayFile; UserData: Pointer): Integer; var ClonedFile: TDisplayFile; begin ClonedFile := AFile.Clone(True); Result := FFiles.Add(ClonedFile); FUserData.Add(UserData); end; function TFVWorkerFileList.GetCount: Integer; begin Result := FFiles.Count; end; function TFVWorkerFileList.GetFile(Index: Integer): TDisplayFile; begin Result := TDisplayFile(FFiles.Items[Index]); end; function TFVWorkerFileList.GetData(Index: Integer): Pointer; begin Result := FUserData.Items[Index]; end; { TFileViewWorker } constructor TFileViewWorker.Create(AThread: TThread); begin // Set Working=True on creation because these workers are usually scheduled // to run by a non-main thread, so it might take a while for Execute to be called. FWorking := True; FWorkType := fvwtNone; FThread := AThread; end; procedure TFileViewWorker.Abort; begin FAborted := True; end; procedure TFileViewWorker.DoFinished; begin FWorking := False; try FOnFinished(Self); except on e: Exception do HandleException(e); end; end; procedure TFileViewWorker.DoStarting; begin try FOnStarting(Self); except on e: Exception do HandleException(e); end; end; procedure TFileViewWorker.DoneWorking; begin FWorking := False; end; function TFileViewWorker.IsWorking: Boolean; begin Result := FWorking and not FAborted; end; procedure TFileViewWorker.Start; begin try if not Aborted then begin if Assigned(FOnStarting) then TThread.Synchronize(Thread, @DoStarting); if not Aborted then Execute; // virtual call if Assigned(FOnFinished) then TThread.Synchronize(Thread, @DoFinished); end; finally FWorking := False; FCanBeDestroyed := True; end; end; procedure TFileViewWorker.StartParam(Params: Pointer); begin Start; end; { TFileListBuilder } constructor TFileListBuilder.Create(AFileSource: IFileSource; AFileSourceIndex: Integer; const AFileFilter: String; const AFilterOptions: TQuickSearchOptions; const ACurrentPath: String; const ASorting: TFileSortings; AFlatView: Boolean; AThread: TThread; AFilePropertiesNeeded: TFilePropertiesTypes; AVariantProperties: TDynamicStringArray; ASetFileListMethod: TSetFileListMethod; var ExistingDisplayFiles: TDisplayFiles; var ExistingDisplayFilesHashed: TStringHashListUtf8); begin inherited Create(AThread); FAllDisplayFiles := ExistingDisplayFiles; ExistingDisplayFiles := nil; FExistingDisplayFilesHashed := ExistingDisplayFilesHashed; ExistingDisplayFilesHashed := nil; FWorkType := fvwtCreate; FListOperation := nil; FListOperationLock := TCriticalSection.Create; FFileSource := AFileSource; FFileSourceIndex := AFileSourceIndex; FFlatView := AFlatView; FFileFilter := AFileFilter; FFilterOptions := AFilterOptions; FCurrentPath := ACurrentPath; FSortings := CloneSortings(ASorting); FVariantProperties := AVariantProperties; FFilePropertiesNeeded := AFilePropertiesNeeded; FSetFileListMethod := ASetFileListMethod; end; destructor TFileListBuilder.Destroy; begin inherited Destroy; FListOperationLock.Free; FExistingDisplayFilesHashed.Free; FFilteredDisplayFiles.Free; FAllDisplayFiles.Free; end; procedure TFileListBuilder.Abort; begin inherited; FListOperationLock.Acquire; try if Assigned(FListOperation) then FListOperation.Stop; finally FListOperationLock.Release; end; end; procedure TFileListBuilder.Execute; var AFile: TFile; I: Integer; HaveUpDir: Boolean = False; FileSourceFiles: TFiles = nil; begin try if Aborted then Exit; if fsoList in FFileSource.GetOperationsTypes then begin FListOperationLock.Acquire; try FListOperation := FFileSource.CreateListOperation(FCurrentPath) as TFileSourceListOperation; finally FListOperationLock.Release; end; if Assigned(FListOperation) then try FListOperation.FlatView := FFlatView; FListOperation.AssignThread(Thread); FListOperation.Execute; if FListOperation.Result = fsorFinished then FileSourceFiles := FListOperation.ReleaseFiles; finally FListOperationLock.Acquire; try FreeAndNil(FListOperation); finally FListOperationLock.Release; end; end; end; {$IFDEF timeFileView} filelistPrintTime('Loaded files : '); {$ENDIF} if Aborted then Exit; if Assigned(FileSourceFiles) then begin // Check if up-dir '..' is present. // If it is present it will usually be the first file. for i := 0 to FileSourceFiles.Count - 1 do begin if FileSourceFiles[i].Name = '..' then begin HaveUpDir := True; Break; end; end; if (not HaveUpDir) and ((not FFileSource.IsPathAtRoot(FCurrentPath)) or // Add '..' to go to higher level file source, if there is more than one. ((FFileSourceIndex > 0) and not (fspNoneParent in FFileSource.Properties))) then begin AFile := FFileSource.CreateFileObject(FCurrentPath); AFile.Name := '..'; if fpAttributes in AFile.SupportedProperties then begin if AFile.AttributesProperty is TNtfsFileAttributesProperty then AFile.Attributes := FILE_ATTRIBUTE_DIRECTORY else if AFile.AttributesProperty is TUnixFileAttributesProperty then AFile.Attributes := S_IFDIR else AFile.Attributes := faFolder; end; FileSourceFiles.Insert(AFile, 0); end; end; if Aborted then Exit; // Retrieve RetrievableFileProperties which used in sorting if FFilePropertiesNeeded <> [] then begin for I:= 0 to FileSourceFiles.Count - 1 do FFileSource.RetrieveProperties(FileSourceFiles[I], FFilePropertiesNeeded, FVariantProperties); end; // Make display file list from file source file list. if Assigned(FAllDisplayFiles) and Assigned(FExistingDisplayFilesHashed) then begin // Updating existing list. MakeAllDisplayFileList( FFileSource, FileSourceFiles, FAllDisplayFiles, FSortings, FExistingDisplayFilesHashed); end else begin // Creating new list. if Assigned(FAllDisplayFiles) then FAllDisplayFiles.Clear else FAllDisplayFiles := TDisplayFiles.Create(True); MakeAllDisplayFileList(FFileSource, FileSourceFiles, FAllDisplayFiles, FSortings); end; // By now the TFile objects have been transfered to FAllDisplayFiles. if Assigned(FileSourceFiles) then FileSourceFiles.OwnsObjects := False; {$IFDEF timeFileView} filelistPrintTime('Made sorted disp.lst: '); {$ENDIF} FFilteredDisplayFiles := TDisplayFiles.Create(False); MakeDisplayFileList(FAllDisplayFiles, FFilteredDisplayFiles, FFileFilter, FFilterOptions); {$IFDEF timeFileView} filelistPrintTime('Made filtered list : '); {$ENDIF} if Aborted then Exit; // Loading file list is complete. Update grid with the new file list. TThread.Synchronize(Thread, @DoSetFilelist); {$IFDEF timeFileView} filelistPrintTime('Grid files updated : '); {$ENDIF} finally {$IFDEF timeFileView} filelistPrintTime('Finished : '); {$ENDIF} FreeAndNil(FFilteredDisplayFiles); FreeAndNil(FileSourceFiles); FreeAndNil(FAllDisplayFiles); end; end; class function TFileListBuilder.InternalMatchesFilter(aFile: TFile; const aFileFilter: String; const aFilterOptions: TQuickSearchOptions): Boolean; const ACaseSensitive: array[Boolean] of TMaskOptions = ([], [moCaseSensitive]); begin if (gShowSystemFiles = False) and AFile.IsSysFile and (AFile.Name <> '..') then Result := True // Ignore list else if gIgnoreListFileEnabled and MatchesMaskListEx(AFile, glsIgnoreList) then Result := True // Filter files. else if aFileFilter <> EmptyStr then begin Result := True; if (AFile.Name = '..') or (AFile.Name = '.') then Result := False else if (aFilterOptions.Items = qsiFiles) and (AFile.IsDirectory or AFile.IsLinkToDirectory) then Result := False else if (aFilterOptions.Items = qsiDirectories) and not AFile.IsDirectory and not AFile.IsLinkToDirectory then Result := False else begin if MatchesMask(AFile.Name, aFileFilter, ACaseSensitive[aFilterOptions.SearchCase = qscSensitive]) then Result := False; end; end else Result := False; end; class function TFileListBuilder.InternalMatchesFilter(aFile: TFile; const aMasks: TMaskList; const aFilterOptions: TQuickSearchOptions): Boolean; begin if (gShowSystemFiles = False) and AFile.IsSysFile and (AFile.Name <> '..') then Result := True // Ignore list else if gIgnoreListFileEnabled and MatchesMaskListEx(AFile, glsIgnoreList) then Result := True // Filter files. else if aMasks.Count <> 0 then begin Result := True; if (AFile.Name = '..') or (AFile.Name = '.') then Result := False else if (aFilterOptions.Items = qsiFiles) and (AFile.IsDirectory or AFile.IsLinkToDirectory) then Result := False else if (aFilterOptions.Items = qsiDirectories) and not AFile.IsDirectory and not AFile.IsLinkToDirectory then Result := False else begin // Match the file name and Pinyin letter if aMasks.Matches(AFile.Name) then Result := False; end; end else Result := False; end; class function TFileListBuilder.PrepareFilter(const aFileFilter: String; const aFilterOptions: TQuickSearchOptions): String; var Index: Integer; sFileExt: String; sFilterNameNoExt: String; begin Result := aFileFilter; if Result <> EmptyStr then begin Index:= Pos('.', Result); if (Index > 0) and ((Index > 1) or FirstDotAtFileNameStartIsExtension) then begin sFileExt := ExtractFileExt(Result); sFilterNameNoExt := ExtractOnlyFileName(Result); if not (qsmBeginning in aFilterOptions.Match) then sFilterNameNoExt := '*' + sFilterNameNoExt; if not (qsmEnding in aFilterOptions.Match) then sFilterNameNoExt := sFilterNameNoExt + '*'; Result := sFilterNameNoExt + sFileExt + '*'; end else begin if not (qsmBeginning in aFilterOptions.Match) then Result := '*' + Result; Result := Result + '*'; end; end; end; class procedure TFileListBuilder.MakeDisplayFileList( allDisplayFiles: TDisplayFiles; filteredDisplayFiles: TDisplayFiles; aFileFilter: String; const aFilterOptions: TQuickSearchOptions); var S: String; I: Integer; AFile: TFile; AFilter: Boolean; Masks: TMaskList; AOptions: TMaskOptions = [moPinyin]; begin filteredDisplayFiles.Clear; if qscSensitive in [aFilterOptions.SearchCase] then AOptions += [moCaseSensitive]; if Assigned(allDisplayFiles) then try Masks:= TMaskList.Create(aFileFilter, ';,', AOptions); for I := 0 to Masks.Count - 1 do begin S:= Masks.Items[I].Template; S:= PrepareFilter(S, aFilterOptions); Masks.Items[I].Template:= S; end; for I := 0 to allDisplayFiles.Count - 1 do begin AFile := allDisplayFiles[I].FSFile; try AFilter := InternalMatchesFilter(AFile, Masks, aFilterOptions); except on EConvertError do aFileFilter := EmptyStr; end; if not AFilter then filteredDisplayFiles.Add(allDisplayFiles[I]); end; finally Masks.Free; end; end; class procedure TFileListBuilder.MakeAllDisplayFileList( aFileSource: IFileSource; aFileSourceFiles: TFiles; aDisplayFiles: TDisplayFiles; const aSortings: TFileSortings); var i: PtrInt; AFile: TDisplayFile; HaveIcons: Boolean; DirectAccess: Boolean; begin aDisplayFiles.Clear; if Assigned(aFileSourceFiles) then begin HaveIcons := gShowIcons <> sim_none; DirectAccess := fspDirectAccess in aFileSource.Properties; if HaveIcons and gIconsExclude and DirectAccess then begin DirectAccess := not IsInPathList(gIconsExcludeDirs, aFileSourceFiles.Path); end; for i := 0 to aFileSourceFiles.Count - 1 do begin AFile := TDisplayFile.Create(aFileSourceFiles[i]); AFile.TextColor:= gColorExt.GetColorBy(AFile.FSFile); if HaveIcons then begin AFile.IconID := PixMapManager.GetIconByFile(AFile.FSFile, DirectAccess, not gLoadIconsSeparately, gShowIcons, not gIconOverlays); end; aDisplayFiles.Add(AFile); end; TDisplayFileSorter.Sort(aDisplayFiles, aSortings); end; end; class procedure TFileListBuilder.MakeAllDisplayFileList( aFileSource: IFileSource; aFileSourceFiles: TFiles; aExistingDisplayFiles: TDisplayFiles; const aSortings: TFileSortings; aExistingDisplayFilesHashed: TStringHashListUtf8); var i: PtrInt; j: Integer; AFile: TDisplayFile; aNewFiles: TDisplayFiles; HaveIcons: Boolean; DirectAccess: Boolean; begin if Assigned(aFileSourceFiles) then begin HaveIcons := gShowIcons <> sim_none; DirectAccess := fspDirectAccess in aFileSource.Properties; if HaveIcons and gIconsExclude and DirectAccess then begin DirectAccess := not IsInPathList(gIconsExcludeDirs, aFileSourceFiles.Path); end; aNewFiles := TDisplayFiles.Create(False); try for i := 0 to aFileSourceFiles.Count - 1 do begin j := aExistingDisplayFilesHashed.Find(aFileSourceFiles[i].FullPath); if j >= 0 then begin // Existing file. AFile := TDisplayFile(aExistingDisplayFilesHashed.List[j]^.Data); AFile.FSFile := aFileSourceFiles[i]; end else begin AFile := TDisplayFile.Create(aFileSourceFiles[i]); AFile.TextColor:= gColorExt.GetColorBy(AFile.FSFile); if HaveIcons then begin AFile.IconID := PixMapManager.GetIconByFile(AFile.FSFile, DirectAccess, not gLoadIconsSeparately, gShowIcons, not gIconOverlays); end; // New file. aNewFiles.Add(AFile); end; end; // Remove files that don't exist anymore. for i := aExistingDisplayFiles.Count - 1 downto 0 do begin if not Assigned(aExistingDisplayFiles[i].FSFile) then aExistingDisplayFiles.Delete(i); end; // Merge new files into existing files list. TDisplayFileSorter.InsertSort(aNewFiles, aExistingDisplayFiles, aSortings); finally aNewFiles.Free; end; end else begin aExistingDisplayFiles.Clear; end; end; class function TFileListBuilder.MatchesFilter(aFile: TFile; aFileFilter: String; const aFilterOptions: TQuickSearchOptions): Boolean; begin aFileFilter := PrepareFilter(aFileFilter, aFilterOptions); try Result := InternalMatchesFilter(AFile, aFileFilter, aFilterOptions); except on EConvertError do Result := False; end; end; procedure TFileListBuilder.DoSetFileList; begin DoneWorking; if not Aborted and Assigned(FSetFileListMethod) then FSetFileListMethod(FAllDisplayFiles, FFilteredDisplayFiles); end; { TFilePropertiesRetriever } constructor TFilePropertiesRetriever.Create(AFileSource: IFileSource; AThread: TThread; AFilePropertiesNeeded: TFilePropertiesTypes; AVariantProperties: TDynamicStringArray; AUpdateFileMethod: TUpdateFileMethod; ABreakFileMethod: TAbortFileMethod; var AFileList: TFVWorkerFileList); begin inherited Create(AThread); FWorkType := fvwtUpdate; FFileList := AFileList; AFileList := nil; FFileSource := AFileSource; FVariantProperties := AVariantProperties; FFilePropertiesNeeded := AFilePropertiesNeeded; FUpdateFileMethod := AUpdateFileMethod; FAbortFileMethod := ABreakFileMethod; end; destructor TFilePropertiesRetriever.Destroy; begin FFileList.Free; inherited Destroy; end; procedure TFilePropertiesRetriever.Abort; begin inherited Abort; if Assigned(FAbortFileMethod) then begin FAbortFileMethod(FIndex, FFileList.FUserData); end; end; procedure TFilePropertiesRetriever.Execute; var HaveIcons: Boolean; DirectAccess: Boolean; begin HaveIcons := gShowIcons <> sim_none; DirectAccess := fspDirectAccess in FFileSource.Properties; if HaveIcons and gIconsExclude and DirectAccess then begin DirectAccess := not IsInPathList(gIconsExcludeDirs, FFileList.Files[0].FSFile.Path); end; while (FIndex < FFileList.Count) and (Aborted = False) do begin try FWorkingFile := FFileList.Files[FIndex]; FWorkingUserData := FFileList.Data[FIndex]; if FFileSource.CanRetrieveProperties(FWorkingFile.FSFile, FFilePropertiesNeeded) then FFileSource.RetrieveProperties(FWorkingFile.FSFile, FFilePropertiesNeeded, FVariantProperties); if FWorkingFile.TextColor = clNone then FWorkingFile.TextColor:= gColorExt.GetColorBy(FWorkingFile.FSFile); if HaveIcons then begin if FWorkingFile.IconID < 0 then FWorkingFile.IconID := PixMapManager.GetIconByFile( FWorkingFile.FSFile, DirectAccess, True, gShowIcons, not gIconOverlays); {$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)} if gIconOverlays and (FWorkingFile.IconOverlayID < 0) then FWorkingFile.IconOverlayID := PixMapManager.GetIconOverlayByFile( FWorkingFile.FSFile, DirectAccess); {$ENDIF} end; TThread.Synchronize(Thread, @DoUpdateFile); except on EListError do; on EFileNotFound do; end; Inc(FIndex); end; end; procedure TFilePropertiesRetriever.DoUpdateFile; begin if Assigned(FUpdateFileMethod) then FUpdateFileMethod(FWorkingFile, FWorkingUserData); end; { TCalculateSpaceWorker } constructor TCalculateSpaceWorker.Create(AFileSource: IFileSource; AThread: TThread; AUpdateFileMethod: TUpdateFileMethod; var AFileList: TFVWorkerFileList); begin inherited Create(AThread); FWorkType := fvwtUpdate; FFileList := AFileList; AFileList := nil; FFileSource := AFileSource; FUpdateFileMethod := AUpdateFileMethod; FOperation := nil; FOperationLock := TCriticalSection.Create; end; destructor TCalculateSpaceWorker.Destroy; begin FFileList.Free; inherited Destroy; FOperationLock.Free; end; procedure TCalculateSpaceWorker.Abort; begin inherited; FOperationLock.Acquire; try if Assigned(FOperation) then FOperation.Stop; finally FOperationLock.Release; end; end; procedure TCalculateSpaceWorker.Execute; var CalcStatisticsOperation: TFileSourceCalcStatisticsOperation; CalcStatisticsOperationStatistics: TFileSourceCalcStatisticsOperationStatistics; TargetFiles: TFiles = nil; AFile: TFile; begin if fsoCalcStatistics in FFileSource.GetOperationsTypes then begin FWorkingIndex:= 0; TThread.Synchronize(Thread, @DoUpdateFolders); try while FWorkingIndex < FFileList.Count do begin if Aborted then Break; FWorkingFile := FFileList.Files[FWorkingIndex]; FWorkingUserData := FFileList.Data[FWorkingIndex]; AFile := FWorkingFile.FSFile; if (fpSize in AFile.SupportedProperties) and (AFile.IsDirectory and not AFile.IsLinkToDirectory) then begin TargetFiles := TFiles.Create(AFile.Path); try TargetFiles.Add(AFile.Clone); AFile.Size:= FOLDER_SIZE_CALC; TThread.Synchronize(Thread, @DoUpdateFile); FOperationLock.Acquire; try FOperation := FFileSource.CreateCalcStatisticsOperation(TargetFiles); finally FOperationLock.Release; end; CalcStatisticsOperation := FOperation as TFileSourceCalcStatisticsOperation; CalcStatisticsOperation.SkipErrors := True; CalcStatisticsOperation.SymLinkOption := fsooslDontFollow; if fspListOnMainThread in FFileSource.Properties then TThread.Synchronize(Thread, @FOperation.Execute) else begin FOperation.Execute; // blocks until finished end; if Aborted then Break; if FOperation.Result = fsorFinished then begin CalcStatisticsOperationStatistics := CalcStatisticsOperation.RetrieveStatistics; AFile.Size := CalcStatisticsOperationStatistics.Size; if AFile.Size = 0 then AFile.Size:= FOLDER_SIZE_ZERO; Inc(FCompletedCalculations); TThread.Synchronize(Thread, @DoUpdateFile); end; finally FreeAndNil(TargetFiles); FOperationLock.Acquire; try FreeAndNil(FOperation); finally FOperationLock.Release; end; end; end; Inc(FWorkingIndex); end; finally if Aborted then begin TThread.Synchronize(Thread, @DoUpdateFolders); end; end; end; end; procedure TCalculateSpaceWorker.DoUpdateFile; begin if Assigned(FUpdateFileMethod) then FUpdateFileMethod(FWorkingFile, FWorkingUserData); end; procedure TCalculateSpaceWorker.DoUpdateFolders; var ASize: Int64; Index: Integer; begin if Assigned(FUpdateFileMethod) then begin if Aborted then ASize:= FOLDER_SIZE_UNKN else begin ASize:= FOLDER_SIZE_WAIT; end; Index:= FWorkingIndex; while Index < FFileList.Count do begin FWorkingFile:= FFileList.Files[Index]; FWorkingUserData := FFileList.Data[Index]; if FWorkingFile.FSFile.IsDirectory and not FWorkingFile.FSFile.IsLinkToDirectory then begin FWorkingFile.FSFile.Size:= ASize; FUpdateFileMethod(FWorkingFile, FWorkingUserData); end; Inc(Index); end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/uorderedfileview.pas�������������������������������������������������0000644�0001750�0000144�00000071154�14743153644�021453� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Base class for file views which display an ordered (indexed) list of files Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uOrderedFileView; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, StdCtrls, Menus, uTypes, fQuickSearch, uFileView, uFileViewWithPanels, uDisplayFile; const InvalidFileIndex = PtrInt(-1); type { TOrderedFileView } TOrderedFileView = class(TFileViewWithPanels) private pmOperationsCancel: TPopupMenu; procedure lblFilterClick(Sender: TObject); procedure pmOperationsCancelClick(Sender: TObject); procedure quickSearchChangeSearch(Sender: TObject; ASearchText: String; const ASearchOptions: TQuickSearchOptions; InvertSelection: Boolean = False); procedure quickSearchChangeFilter(Sender: TObject; AFilterText: String; const AFilterOptions: TQuickSearchOptions); procedure quickSearchExecute(Sender: TObject); procedure quickSearchHide(Sender: TObject); procedure UpdateRangeSelectionState; protected lblFilter: TLabel; quickSearch: TfrmQuickSearch; FFocusQuickSearch: Boolean; FLastActiveFileIndex: PtrInt; FLastTopRowIndex: PtrInt; FRangeSelecting: Boolean; FRangeSelectionStartIndex: Integer; FRangeSelectionEndIndex: Integer; FRangeSelectionState: Boolean; FUpdatingActiveFile: Boolean; procedure InvertActiveFile; procedure AfterChangePath; override; procedure CreateDefault(AOwner: TWinControl); override; procedure DoFileIndexChanged(NewFileIndex, TopRowIndex: PtrInt); procedure DoHandleKeyDown(var Key: Word; Shift: TShiftState); override; procedure DoHandleKeyDownWhenLoading(var Key: Word; Shift: TShiftState); override; procedure DoSelectionChanged; override; overload; procedure DoSelectionChanged(FileIndex: PtrInt); overload; procedure EnsureDisplayProperties; override; function GetActiveDisplayFile: TDisplayFile; override; function GetActiveFileIndex: PtrInt; virtual; abstract; function GetFileRect(FileIndex: PtrInt): TRect; virtual; abstract; function GetVisibleFilesIndexes: TRange; virtual; abstract; function IsFileIndexVisible(FileIndex: PtrInt): Boolean; function IsFileIndexInRange(FileIndex: PtrInt): Boolean; inline; function IsActiveFileVisible: Boolean; {en If marking a single file only redraws that file. Otherwise files are marked and full update is performed. } procedure MarkFilesWithCheck(FromIndex, ToIndex: PtrInt; bSelect: Boolean); procedure RedrawFile(FileIndex: PtrInt); overload; virtual; abstract; {en Search and position in a file that matches name taking into account passed options. } procedure SearchFile(SearchTerm,SeparatorCharset: String; SearchOptions: TQuickSearchOptions; InvertSelection: Boolean = False); procedure Selection(Key: Word; CurIndex: PtrInt); procedure SelectRange(FileIndex: PtrInt); procedure SetActiveFile(FileIndex: PtrInt; ScrollTo: Boolean = True; aLastTopRowIndex: PtrInt = -1); overload; virtual; abstract; procedure SetLastActiveFile(FileIndex, TopRowIndex: PtrInt); {en Sets a file as active if the file currently exists. @returns(@true if the file was found and selected.) } function SetActiveFileNow(aFilePath: String; ScrollTo: Boolean = True; aLastTopRowIndex: PtrInt = -1): Boolean; procedure PropertiesRetrieverOnAbort(AStart: Integer; AList: TFPList); public procedure CloneTo(AFileView: TFileView); override; procedure SetActiveFile(aFilePath: String); override; overload; procedure ChangePathAndSetActiveFile(aFilePath: String); override; overload; procedure SetFocus; override; published // commands procedure cm_QuickSearch(const Params: array of string); procedure cm_QuickFilter(const Params: array of string); procedure cm_GoToFirstEntry(const {%H-}Params: array of string); procedure cm_GoToLastEntry(const {%H-}Params: array of string); procedure cm_GoToNextEntry(const {%H-}Params: array of string); procedure cm_GoToPrevEntry(const {%H-}Params: array of string); procedure cm_GoToFirstFile(const Params: array of string); procedure cm_GoToLastFile(const Params: array of string); end; implementation uses LCLProc, LCLType, math, Forms, Graphics, DCStrUtils, DCOSUtils, uLng, uGlobs, uMasks, uDCUtils, uFileSourceProperty, uPixMapManager, uFileViewWorker, uFileProperty, uFileSource, uFile; const CANCEL_FILTER = 0; CANCEL_OPERATION = 1; { TOrderedFileView } procedure TOrderedFileView.AfterChangePath; begin if Filtered or quickSearch.Visible then begin FFileFilter:= EmptyStr; quickSearch.Finalize; end; FLastActiveFileIndex := -1; inherited AfterChangePath; end; procedure TOrderedFileView.CloneTo(AFileView: TFileView); begin if Assigned(AFileView) then begin inherited CloneTo(AFileView); with AFileView as TOrderedFileView do begin FLastActiveFileIndex := Self.FLastActiveFileIndex; FRangeSelectionStartIndex := Self.FRangeSelectionStartIndex; FRangeSelectionEndIndex := Self.FRangeSelectionEndIndex; FRangeSelectionState := Self.FRangeSelectionState; lblFilter.Caption := Self.lblFilter.Caption; lblFilter.Visible := Self.lblFilter.Visible; Self.quickSearch.CloneTo(quickSearch); FFocusQuickSearch := Self.quickSearch.edtSearch.Focused; end; end; end; procedure TOrderedFileView.cm_GoToFirstEntry(const Params: array of string); begin if not (IsEmpty or IsLoadingFileList) then begin SetFocus; SetActiveFile(0); end; end; procedure TOrderedFileView.cm_GoToLastEntry(const Params: array of string); begin if not (IsEmpty or IsLoadingFileList) then begin SetFocus; SetActiveFile(FFiles.Count - 1); end; end; procedure TOrderedFileView.cm_GoToNextEntry(const Params: array of string); var Index: PtrInt; begin Index:= GetActiveFileIndex + 1; if IsFileIndexInRange(Index) then begin SetActiveFile(Index); end; end; procedure TOrderedFileView.cm_GoToPrevEntry(const Params: array of string); var Index: PtrInt; begin Index:= GetActiveFileIndex - 1; if IsFileIndexInRange(Index) then begin SetActiveFile(Index); end; end; procedure TOrderedFileView.cm_GoToFirstFile(const Params: array of string); var I: Integer; begin if not (IsEmpty or IsLoadingFileList) then begin SetFocus; for I:= 0 to FFiles.Count - 1 do if not (FFiles[I].FSFile.IsDirectory or FFiles[I].FSFile.IsLinkToDirectory) then begin SetActiveFile(I); Exit; end; end; end; procedure TOrderedFileView.cm_GoToLastFile(const Params: array of string); var I: Integer; begin if not (IsEmpty or IsLoadingFileList) then begin SetFocus; for I:= FFiles.Count - 1 downto 0 do if not (FFiles[I].FSFile.IsDirectory or FFiles[I].FSFile.IsLinkToDirectory) then begin SetActiveFile(I); Exit; end; end; end; procedure TOrderedFileView.cm_QuickFilter(const Params: array of string); begin if not IsLoadingFileList then quickSearch.Execute(qsFilter, Params); end; procedure TOrderedFileView.cm_QuickSearch(const Params: array of string); begin if not IsLoadingFileList then quickSearch.Execute(qsSearch, Params); end; procedure TOrderedFileView.CreateDefault(AOwner: TWinControl); begin inherited CreateDefault(AOwner); FLastActiveFileIndex := -1; FRangeSelectionState := True; lblFilter := TLabel.Create(pnlFooter); lblFilter.Parent := pnlFooter; lblFilter.Align := alRight; lblFilter.Visible := False; lblFilter.OnClick := @lblFilterClick; quickSearch := TfrmQuickSearch.Create(Self); quickSearch.Parent := Self; quickSearch.Visible := False; quickSearch.Align := alBottom; quickSearch.OnChangeSearch := @quickSearchChangeSearch; quickSearch.OnChangeFilter := @quickSearchChangeFilter; quickSearch.OnExecute := @quickSearchExecute; quickSearch.OnHide := @quickSearchHide; pmOperationsCancel := TPopupMenu.Create(Self); pmOperationsCancel.Parent := Self; end; procedure TOrderedFileView.DoFileIndexChanged(NewFileIndex, TopRowIndex: PtrInt); begin if IsFileIndexInRange(NewFileIndex) and ( (FLastActiveFileIndex <> NewFileIndex) or (FLastTopRowIndex <> TopRowIndex) ) then begin if not FRangeSelecting then begin // Set range selection starting point. FRangeSelectionStartIndex := NewFileIndex; FRangeSelectionEndIndex := NewFileIndex; UpdateRangeSelectionState; end; if not FUpdatingActiveFile then begin SetLastActiveFile(NewFileIndex, TopRowIndex); end; if Assigned(OnChangeActiveFile) then OnChangeActiveFile(Self, FFiles[NewFileIndex].FSFile); if FlatView and (FSelectedCount = 0) then UpdateFlatFileName; end; end; procedure TOrderedFileView.DoHandleKeyDown(var Key: Word; Shift: TShiftState); var mi: TMenuItem; begin // check if ShiftState is equal to quick search / filter modes if quickSearch.CheckSearchOrFilter(Key) then Exit; case Key of VK_ESCAPE: begin if quickSearch.Visible and not Filtered then begin quickSearch.Finalize; Key := 0; end; if Filtered and (GetCurrentWorkType <> fvwtNone) then begin pmOperationsCancel.Items.Clear; mi := TMenuItem.Create(pmOperationsCancel); mi.Tag := CANCEL_FILTER; mi.Caption := rsCancelFilter; mi.OnClick := @pmOperationsCancelClick; pmOperationsCancel.Items.Add(mi); mi := TMenuItem.Create(pmOperationsCancel); mi.Tag := CANCEL_OPERATION; mi.Caption := rsCancelOperation; mi.OnClick := @pmOperationsCancelClick; pmOperationsCancel.Items.Add(mi); pmOperationsCancel.PopUp; Key := 0; end else if Filtered then begin quickSearch.Finalize; Key := 0; end else if GetCurrentWorkType <> fvwtNone then begin StopWorkers; Key := 0; end; end; end; inherited DoHandleKeyDown(Key, Shift); end; procedure TOrderedFileView.DoHandleKeyDownWhenLoading(var Key: Word; Shift: TShiftState); var bLoading: Boolean; begin case Key of VK_ESCAPE: if GetCurrentWorkType <> fvwtNone then begin bLoading := IsLoadingFileList; StopWorkers; if bLoading then CancelLastPathChange; Key := 0; end; end; inherited DoHandleKeyDownWhenLoading(Key, Shift); end; procedure TOrderedFileView.DoSelectionChanged; begin inherited DoSelectionChanged; RedrawFiles; UpdateRangeSelectionState; end; procedure TOrderedFileView.DoSelectionChanged(FileIndex: PtrInt); begin inherited DoSelectionChanged; if IsFileIndexInRange(FileIndex) then RedrawFile(FileIndex); UpdateRangeSelectionState; end; procedure TOrderedFileView.EnsureDisplayProperties; var VisibleFiles: TRange; i: Integer; AFileList: TFVWorkerFileList = nil; Worker: TFileViewWorker; AFile: TDisplayFile; HaveIcons: Boolean; DirectAccess: Boolean; AFilePropertiesNeeded: TFilePropertiesTypes; begin if (csDestroying in ComponentState) or (GetCurrentWorkType = fvwtCreate) or IsEmpty then Exit; HaveIcons := gShowIcons <> sim_none; VisibleFiles := GetVisibleFilesIndexes; AFilePropertiesNeeded := FilePropertiesNeeded; DirectAccess := fspDirectAccess in FileSource.Properties; // Property fpComment should be retrieved in main thread if gListFilesInThread and (fpComment in AFilePropertiesNeeded) then begin for i := VisibleFiles.First to VisibleFiles.Last do begin AFile := FFiles[i]; if FileSource.CanRetrieveProperties(AFile.FSFile, [fpComment]) then try FileSource.RetrieveProperties(AFile.FSFile, [fpComment], []); except on EFileNotFound do; end; end; AFilePropertiesNeeded := AFilePropertiesNeeded - [fpComment]; end; if not gListFilesInThread then begin if HaveIcons and gIconsExclude and DirectAccess then begin DirectAccess := not IsInPathList(gIconsExcludeDirs, CurrentPath); end; for i := VisibleFiles.First to VisibleFiles.Last do begin AFile := FFiles[i]; if AFile.TextColor = clNone then AFile.TextColor:= gColorExt.GetColorBy(AFile.FSFile); if AFile.FSFile.Name <> '..' then begin if HaveIcons then begin if AFile.IconID < 0 then AFile.IconID := PixMapManager.GetIconByFile(AFile.FSFile, DirectAccess, True, gShowIcons, not gIconOverlays); {$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)} if gIconOverlays and (AFile.IconOverlayID < 0) then begin AFile.IconOverlayID := PixMapManager.GetIconOverlayByFile(AFile.FSFile, DirectAccess); end; {$ENDIF} end; if FileSource.CanRetrieveProperties(AFile.FSFile, FilePropertiesNeeded) then try FileSource.RetrieveProperties(AFile.FSFile, FilePropertiesNeeded, GetVariantFileProperties); except on EFileNotFound do; end; end; end; end else begin try for i := VisibleFiles.First to VisibleFiles.Last do begin AFile := FFiles[i]; if (AFile.FSFile.Name <> '..') and (AFile.Busy * [bsProp] = []) and (FileSource.CanRetrieveProperties(AFile.FSFile, AFilePropertiesNeeded) or (AFile.TextColor = clNone) or (HaveIcons and ((AFile.IconID < 0) {$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)} or (gIconOverlays and (AFile.IconOverlayID < 0)) {$ENDIF} ))) then begin if not Assigned(AFileList) then AFileList := TFVWorkerFileList.Create; AFileList.AddClone(AFile, AFile); AFile.Busy := AFile.Busy + [bsProp]; end; end; if Assigned(AFileList) and (AFileList.Count > 0) then begin Worker := TFilePropertiesRetriever.Create( FileSource, WorkersThread, AFilePropertiesNeeded, GetVariantFileProperties, @PropertiesRetrieverOnUpdate, @PropertiesRetrieverOnAbort, AFileList); AddWorker(Worker, False); WorkersThread.QueueFunction(@Worker.StartParam); end; finally AFileList.Free; end; end; end; function TOrderedFileView.GetActiveDisplayFile: TDisplayFile; var Index: PtrInt; begin Index := GetActiveFileIndex; if IsFileIndexInRange(Index) then Result := FFiles[Index] else Result := nil; end; function TOrderedFileView.IsFileIndexVisible(FileIndex: PtrInt): Boolean; var VisibleFiles: TRange; begin VisibleFiles := GetVisibleFilesIndexes; Result := InRange(FileIndex, VisibleFiles.First, VisibleFiles.Last); end; function TOrderedFileView.IsFileIndexInRange(FileIndex: PtrInt): Boolean; begin Result := InRange(FileIndex, 0, FFiles.Count - 1); end; function TOrderedFileView.IsActiveFileVisible: Boolean; begin Result := IsFileIndexVisible(GetActiveFileIndex); end; procedure TOrderedFileView.lblFilterClick(Sender: TObject); begin quickSearch.Execute(qsFilter, []); end; procedure TOrderedFileView.MarkFilesWithCheck(FromIndex, ToIndex: PtrInt; bSelect: Boolean); begin if FromIndex = ToIndex then begin MarkFile(FFiles[FromIndex], bSelect, False); DoSelectionChanged(FromIndex); end else MarkFiles(FromIndex, ToIndex, bSelect); end; procedure TOrderedFileView.pmOperationsCancelClick(Sender: TObject); begin if (Sender is TMenuItem) then begin case (Sender as TMenuItem).Tag of CANCEL_FILTER: quickSearch.Finalize; CANCEL_OPERATION: StopWorkers; end; end; end; procedure TOrderedFileView.quickSearchChangeFilter(Sender: TObject; AFilterText: String; const AFilterOptions: TQuickSearchOptions); begin if not ((FFileFilter = '') and (AFilterText = '')) then Active := True; // position in file before filtering, otherwise position could be lost if // current file is filtered out causing jumps SearchFile(AFilterText,';,', AFilterOptions); SetFileFilter(AFilterText, AFilterOptions); lblFilter.Caption := Format('(%s: %s)', [rsFilterStatus, AFilterText]); lblFilter.Visible := Filtered; end; procedure TOrderedFileView.quickSearchChangeSearch(Sender: TObject; ASearchText: String; const ASearchOptions: TQuickSearchOptions; InvertSelection: Boolean = False); var Index, MaybeFoundIndex: PtrInt; begin Index:=GetActiveFileIndex; Active := True; SearchFile(ASearchText,';, ', ASearchOptions, InvertSelection); MaybeFoundIndex:=GetActiveFileIndex; if (MaybeFoundIndex <= Index) AND (ASearchOptions.CancelSearchMode=qscmCancelIfNoFound) then begin SetActiveFile(Index-1); quickSearch.Finalize; end else begin lblFilter.Caption := Format('(%s: %s)', [rsSearchStatus, ASearchText]); lblFilter.Visible := (ASearchText<>EmptyStr); end; end; procedure TOrderedFileView.quickSearchExecute(Sender: TObject); begin Active := True; ChooseFile(GetActiveDisplayFile); end; procedure TOrderedFileView.quickSearchHide(Sender: TObject); begin if CanFocus then SetFocus; end; procedure TOrderedFileView.SearchFile(SearchTerm,SeparatorCharset: String; SearchOptions: TQuickSearchOptions; InvertSelection: Boolean); var I, Index, StopIndex, ActiveIndex: PtrInt; S: String; NewSelectedState, FirstFound, Result: Boolean; sFileName : String; AFile: TFile; Masks: TMaskList; AOptions: TMaskOptions = [moPinyin]; function NextIndexWrap(Index: PtrInt): PtrInt; begin Result := Index + 1; if Result = FFiles.Count then Result := 0; end; function PrevIndexWrap(Index: PtrInt): PtrInt; begin Result := Index - 1; if Result < 0 then Result := FFiles.Count - 1; end; begin if IsEmpty then Exit; Index := GetActiveFileIndex; // start search from current position if not IsFileIndexInRange(Index) then begin Index := 0; InvertSelection := False; end; if InvertSelection then begin ActiveIndex := Index; FirstFound := False; NewSelectedState := not FFiles[Index].Selected; MarkFile(FFiles[Index], NewSelectedState, False); DoSelectionChanged(Index); end; case SearchOptions.Direction of qsdFirst: Index := 0; // begin search from first file qsdLast: Index := FFiles.Count - 1; // begin search from last file qsdNext: Index := NextIndexWrap(Index); // begin search from next file qsdPrevious: Index := PrevIndexWrap(Index); // begin search from previous file end; StopIndex := Index; try if (SearchOptions.SearchCase = qscSensitive) then AOptions += [moCaseSensitive]; Masks:= TMaskList.Create(SearchTerm, ';,', AOptions); for I := 0 to Masks.Count - 1 do begin S:= Masks.Items[I].Template; S:= TFileListBuilder.PrepareFilter(S, SearchOptions); Masks.Items[I].Template:= S; end; try repeat Result := True; AFile := FFiles[Index].FSFile; if (SearchOptions.Items = qsiFiles) and (AFile.IsDirectory or AFile.IsLinkToDirectory) then Result := False; if (SearchOptions.Items = qsiDirectories) and not AFile.IsDirectory and not AFile.IsLinkToDirectory then Result := False; sFileName := AFile.Name; // Match the file name and Pinyin letter if not (Masks.Matches(sFileName)) then Result := False; if Result then begin if InvertSelection and (SearchOptions.Direction in [qsdFirst, qsdLast]) then begin if not FirstFound then begin FirstFound := True; SetActiveFile(Index); if ((SearchOptions.Direction = qsdFirst) and (Index < ActiveIndex) or (SearchOptions.Direction = qsdLast) and (Index > ActiveIndex)) then StopIndex := ActiveIndex // continue to mark files until the starting index else break; end; MarkFile(FFiles[Index], NewSelectedState, False); DoSelectionChanged(Index); end else begin SetActiveFile(Index); Break; end; end; // check next file depending on search direction if SearchOptions.Direction in [qsdNone, qsdFirst, qsdNext] then Index := NextIndexWrap(Index) else Index := PrevIndexWrap(Index); until Index = StopIndex; finally Masks.Free; end; except on EConvertError do; // bypass else raise; end; end; procedure TOrderedFileView.Selection(Key: Word; CurIndex: PtrInt); procedure OneLess; begin if CurIndex > FRangeSelectionStartIndex then Dec(CurIndex) else if CurIndex < FRangeSelectionStartIndex then Inc(CurIndex); end; begin // Key value doesn't neccessarily matter. // It just needs to correspond to scroll positions (similar to TScrollCode). case Key of VK_HOME, VK_END: ; VK_PRIOR, VK_UP, VK_LEFT: if CurIndex > 0 then OneLess; VK_NEXT, VK_DOWN, VK_RIGHT: if CurIndex < FFiles.Count - 1 then OneLess; else Exit; end; SelectRange(CurIndex); end; procedure TOrderedFileView.SelectRange(FileIndex: PtrInt); begin // Initially select file at starting point. if FRangeSelectionStartIndex = FRangeSelectionEndIndex then MarkFilesWithCheck(FRangeSelectionStartIndex, FRangeSelectionEndIndex, FRangeSelectionState); if FileIndex <> FRangeSelectionEndIndex then begin if FileIndex < FRangeSelectionStartIndex then begin // Focused file is before selection startpoint. // If previously selection was from startpoint forwards deselect all files after startpoint. if FRangeSelectionEndIndex > FRangeSelectionStartIndex then begin MarkFilesWithCheck(FRangeSelectionStartIndex + 1, FRangeSelectionEndIndex, not FRangeSelectionState); FRangeSelectionEndIndex := FRangeSelectionStartIndex; end; if FileIndex > FRangeSelectionEndIndex then // Decrease selection range. MarkFilesWithCheck(FRangeSelectionEndIndex, FileIndex - 1, not FRangeSelectionState) else if FileIndex < FRangeSelectionEndIndex then // Increase selection range. MarkFilesWithCheck(FileIndex, FRangeSelectionEndIndex - 1, FRangeSelectionState); end else begin // Focused file is after selection startpoint. // If previously selection was from startpoint backwards deselect all files before startpoint. if FRangeSelectionEndIndex < FRangeSelectionStartIndex then begin MarkFilesWithCheck(FRangeSelectionEndIndex, FRangeSelectionStartIndex - 1, not FRangeSelectionState); FRangeSelectionEndIndex := FRangeSelectionStartIndex; end; if FileIndex > FRangeSelectionEndIndex then // Increase selection range. MarkFilesWithCheck(FRangeSelectionEndIndex + 1, FileIndex, FRangeSelectionState) else if FileIndex < FRangeSelectionEndIndex then // Decrease selection range. MarkFilesWithCheck(FileIndex + 1, FRangeSelectionEndIndex, not FRangeSelectionState); end; FRangeSelectionEndIndex := FileIndex; end; end; procedure TOrderedFileView.SetActiveFile(aFilePath: String); begin if GetCurrentWorkType = fvwtCreate then begin // File list is currently loading - remember requested file for later. RequestedActiveFile := aFilePath; end else begin // First try to select the file in the current file list. // If not found save it for later selection (possibly after reload). if SetActiveFileNow(aFilePath) then RequestedActiveFile := '' else RequestedActiveFile := aFilePath; end; end; procedure TOrderedFileView.ChangePathAndSetActiveFile(aFilePath: String); begin if not mbFileExists(aFilePath) then CurrentPath := aFilePath else begin CurrentPath := ExtractFileDir(aFilePath); SetActiveFile(ExtractFileName(aFilePath)); end; end; procedure TOrderedFileView.SetFocus; begin inherited SetFocus; if FFocusQuickSearch then begin FFocusQuickSearch := False; if quickSearch.Visible then quickSearch.edtSearch.SetFocus; end; end; function TOrderedFileView.SetActiveFileNow(aFilePath: String; ScrollTo: Boolean; aLastTopRowIndex: PtrInt): Boolean; procedure SetUpdate(Index: PtrInt); begin FUpdatingActiveFile := True; SetActiveFile(Index, ScrollTo, aLastTopRowIndex); FUpdatingActiveFile := False; SetLastActiveFile(Index, aLastTopRowIndex); end; var APath: String; Index: PtrInt; PathIsAbsolute: Boolean; begin if aFilePath <> '' then // find correct cursor position in Panel (drawgrid) begin PathIsAbsolute := FileSource.GetPathType(aFilePath) = ptAbsolute; for Index := 0 to FFiles.Count - 1 do begin if PathIsAbsolute then Result := (FFiles[Index].FSFile.FullPath = aFilePath) else Result := (FFiles[Index].FSFile.Name = aFilePath); if Result then begin SetUpdate(Index); if Assigned(OnChangeActiveFile) then OnChangeActiveFile(Self, FFiles[Index].FSFile); Exit(True); end; end; if (FLastActiveFileIndex > -1) then begin if (StrBegins(LastActiveFile, CurrentAddress)) then APath:= CurrentLocation else begin APath:= CurrentPath; end; if FlatView or IsInPath(APath, LastActiveFile, False, False) then begin if (PathIsAbsolute and mbCompareFileNames(LastActiveFile, aFilePath)) or (FlatView) or (mbCompareFileNames(LastActiveFile, CurrentPath + aFilePath)) then begin if FLastActiveFileIndex < FFiles.Count then SetUpdate(FLastActiveFileIndex) else begin SetUpdate(FFiles.Count - 1); end; if Assigned(OnChangeActiveFile) then OnChangeActiveFile(Self, FFiles[FLastActiveFileIndex].FSFile); end; end; end; end; Result := False; end; procedure TOrderedFileView.PropertiesRetrieverOnAbort(AStart: Integer; AList: TFPList); var ADisplayFile: TDisplayFile; begin while AStart < AList.Count do begin ADisplayFile := TDisplayFile(AList[AStart]); if IsReferenceValid(ADisplayFile) then begin ADisplayFile.Busy:= ADisplayFile.Busy - [bsProp]; end; Inc(AStart); end; end; procedure TOrderedFileView.SetLastActiveFile(FileIndex, TopRowIndex: PtrInt); begin if IsFileIndexInRange(FileIndex) then begin LastActiveFile := FFiles[FileIndex].FSFile.FullPath; FLastActiveFileIndex := FileIndex; FLastTopRowIndex := TopRowIndex; end; end; procedure TOrderedFileView.UpdateRangeSelectionState; var NewSelectionState: Boolean; begin if not FRangeSelecting then begin if IsFileIndexInRange(FRangeSelectionStartIndex) then begin NewSelectionState := not FFiles[FRangeSelectionStartIndex].Selected; if (FRangeSelectionState <> NewSelectionState) and (FRangeSelectionStartIndex = FRangeSelectionEndIndex) then begin // Selection of starting point has changed. end else begin // Update was called but selection of starting point didn't change. // That means some other file's selection changed - reset starting point. FRangeSelectionStartIndex := GetActiveFileIndex; FRangeSelectionEndIndex := FRangeSelectionStartIndex; end; FRangeSelectionState := NewSelectionState; end; end; end; procedure TOrderedFileView.InvertActiveFile; var Index: PtrInt; begin if IsActiveItemValid then begin Index:= GetActiveFileIndex; if IsFileIndexInRange(Index) then begin InvertFileSelection(FFiles[Index], False); DoSelectionChanged(Index); end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fileviews/uthumbfileview.pas���������������������������������������������������0000644�0001750�0000144�00000057056�14743153644�021153� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uThumbFileView; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, Grids, Types, DCXmlConfig, uFileSource, uOrderedFileView, uDisplayFile, uFileViewWorker, uThumbnails, uFileView, uTypes, uFileViewWithGrid, uFileProperty, uFile; type { TFileThumbnailsRetriever } TFileThumbnailsRetriever = class(TFileViewWorker) private FIndex: Integer; FWorkingFile: TDisplayFile; FWorkingUserData: Pointer; FFileList: TFVWorkerFileList; FThumbnailManager: TThumbnailManager; FUpdateFileMethod: TUpdateFileMethod; FAbortFileMethod: TAbortFileMethod; FFileSource: IFileSource; FBitmapList: TBitmapList; {en Updates file in the file view with new data from FWorkerData. It is called from GUI thread. } procedure DoUpdateFile; protected procedure Execute; override; public constructor Create(AFileSource: IFileSource; AThread: TThread; ABitmapList: TBitmapList; AUpdateFileMethod: TUpdateFileMethod; ABreakFileMethod: TAbortFileMethod; AThumbnailManager: TThumbnailManager; var AFileList: TFVWorkerFileList); reintroduce; destructor Destroy; override; procedure Abort; override; end; TThumbFileView = class; { TThumbDrawGrid } TThumbDrawGrid = class(TFileViewGrid) private FThumbSize: TSize; FMouseDownY: Integer; FThumbView: TThumbFileView; FUpdateColCount: Integer; protected procedure KeyDown(var Key : Word; Shift : TShiftState); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure DragOver(Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean); override; protected procedure UpdateView; override; procedure CalculateColRowCount; override; procedure CalculateColumnWidth; override; procedure DoMouseMoveScroll(Sender: TObject; X, Y: Integer); public constructor Create(AOwner: TComponent; AParent: TWinControl); override; function CellToIndex(ACol, ARow: Integer): Integer; override; procedure IndexToCell(Index: Integer; out ACol, ARow: Integer); override; procedure DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); override; end; { TThumbFileView } TThumbFileView = class(TFileViewWithGrid) private FBitmapList: TBitmapList; FThumbnailManager: TThumbnailManager; procedure ThumbnailsRetrieverOnAbort(AStart: Integer; AList: TFPList); procedure ThumbnailsRetrieverOnUpdate(const UpdatedFile: TDisplayFile; const UserData: Pointer); protected procedure CreateDefault(AOwner: TWinControl); override; procedure AfterChangePath; override; procedure EnsureDisplayProperties; override; function GetFileViewGridClass: TFileViewGridClass; override; function GetVisibleFilesIndexes: TRange; override; procedure ShowRenameFileEdit(var aFile: TFile); override; procedure UpdateRenameFileEditPosition(); override; function GetIconRect(FileIndex: PtrInt): TRect; override; procedure MouseScrollTimer(Sender: TObject); override; procedure DoFileChanged(ADisplayFile: TDisplayFile; APropertiesChanged: TFilePropertiesTypes); override; public constructor Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags = []); override; constructor Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags = []); override; destructor Destroy; override; function Clone(NewParent: TWinControl): TThumbFileView; override; procedure SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); override; end; implementation uses LCLIntf, LCLType, LMessages, Graphics, Math, StdCtrls, uFileSourceProperty, uGlobs, uPixMapManager; { TFileThumbnailsRetriever } procedure TFileThumbnailsRetriever.DoUpdateFile; begin if Assigned(FUpdateFileMethod) then FUpdateFileMethod(FWorkingFile, FWorkingUserData); end; procedure TFileThumbnailsRetriever.Execute; var Bitmap: TBitmap; begin while (FIndex < FFileList.Count) and (Aborted = False) do begin FWorkingFile := FFileList.Files[FIndex]; FWorkingUserData := FFileList.Data[FIndex]; try if FWorkingFile.Tag < 0 then begin Bitmap:= FThumbnailManager.CreatePreview(FWorkingFile.FSFile); if Assigned(Bitmap) then begin FWorkingFile.Tag := FBitmapList.Add(Bitmap); end; end; TThread.Synchronize(Thread, @DoUpdateFile); except on EFileNotFound do; end; Inc(FIndex); end; end; constructor TFileThumbnailsRetriever.Create(AFileSource: IFileSource; AThread: TThread; ABitmapList: TBitmapList; AUpdateFileMethod: TUpdateFileMethod; ABreakFileMethod: TAbortFileMethod; AThumbnailManager: TThumbnailManager; var AFileList: TFVWorkerFileList); begin inherited Create(AThread); FWorkType := fvwtUpdate; FFileList := AFileList; AFileList := nil; FFileSource := AFileSource; FBitmapList := ABitmapList; FAbortFileMethod := ABreakFileMethod; FThumbnailManager := AThumbnailManager; FUpdateFileMethod := AUpdateFileMethod; end; destructor TFileThumbnailsRetriever.Destroy; begin FFileList.Free; inherited Destroy; end; procedure TFileThumbnailsRetriever.Abort; begin inherited Abort; if Assigned(FAbortFileMethod) then begin FAbortFileMethod(FIndex, FFileList.UserData); end; end; { TThumbDrawGrid } procedure TThumbDrawGrid.KeyDown(var Key: Word; Shift: TShiftState); var SavedKey: Word; FileIndex: Integer; ACol, ARow: Integer; begin if FThumbView.IsLoadingFileList then begin FThumbView.HandleKeyDownWhenLoading(Key, Shift); Exit; end; SavedKey := Key; // Set RangeSelecting before cursor is moved. FThumbView.FRangeSelecting := (ssShift in Shift) and (SavedKey in [VK_UP, VK_DOWN, VK_HOME, VK_END, VK_PRIOR, VK_NEXT]); // Special case for selection with shift key (works like VK_INSERT) if (SavedKey in [VK_LEFT, VK_RIGHT]) and (ssShift in Shift) then FThumbView.InvertActiveFile; case Key of VK_LEFT: begin if (Col - 1 < 0) and (Row > 0) then begin MoveExtend(False, ColCount - 1, Row - 1); Key:= 0; end; end; VK_RIGHT: begin if (CellToIndex(Col + 1, Row) < 0) then begin if (Row + 1 < RowCount) then MoveExtend(False, 0, Row + 1) else begin IndexToCell(FThumbView.FFiles.Count - 1, ACol, ARow); MoveExtend(False, ACol, ARow); end; Key:= 0; end; end; VK_HOME: begin MoveExtend(False, 0, 0); Key:= 0; end; VK_END: begin IndexToCell(FThumbView.FFiles.Count - 1, ACol, ARow); MoveExtend(False, ACol, ARow); Key:= 0; end; VK_DOWN: begin if (CellToIndex(Col, Row + 1) < 0) then begin IndexToCell(FThumbView.FFiles.Count - 1, ACol, ARow); MoveExtend(False, ACol, ARow); Key:= 0; end end; end; inherited KeyDown(Key, Shift); if FThumbView.FRangeSelecting then begin FileIndex := CellToIndex(Col, Row); if FileIndex <> InvalidFileIndex then FThumbView.Selection(SavedKey, FileIndex); end; end; procedure TThumbDrawGrid.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited MouseMove(Shift, X, Y); if FThumbView.IsMouseSelecting then DoMouseMoveScroll(nil, X, Y); end; procedure TThumbDrawGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FMouseDownY := Y; inherited MouseDown(Button, Shift, X, Y); end; procedure TThumbDrawGrid.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin inherited DragOver(Source, X, Y, State, Accept); DoMouseMoveScroll(nil, X, Y); end; procedure TThumbDrawGrid.UpdateView; var I: Integer; function CalculateDefaultRowHeight: Integer; var OldFont, NewFont: TFont; begin // Assign temporary font. OldFont := Canvas.Font; NewFont := TFont.Create; Canvas.Font := NewFont; Canvas.Font.PixelsPerInch := NewFont.PixelsPerInch; // Search columns settings for the biggest font (in height). Canvas.Font.Name := gFonts[dcfMain].Name; Canvas.Font.Style := gFonts[dcfMain].Style; Canvas.Font.Size := gFonts[dcfMain].Size; if gUseFrameCursor then Result := gThumbSize.cy + Canvas.GetTextHeight('Wg') + gBorderFrameWidth*2 + 4 else Result := gThumbSize.cy + Canvas.GetTextHeight('Wg') + 6; // Restore old font. Canvas.Font := OldFont; FreeAndNil(NewFont); end; begin // Fix border blinking while scroll window Flat := True; // gInterfaceFlat; // Calculate row height. DefaultRowHeight := CalculateDefaultRowHeight; // Calculate column width CalculateColumnWidth; // Refresh thumbnails if (FThumbSize.cx <> gThumbSize.cx) or (FThumbSize.cy <> gThumbSize.cy) then begin FThumbSize:= gThumbSize; FThumbView.FBitmapList.Clear; if Assigned(FThumbView.FAllDisplayFiles) then begin // Clear thumbnail image index for I := 0 to FThumbView.FAllDisplayFiles.Count - 1 do FThumbView.FAllDisplayFiles[I].Tag:= -1; end; FThumbView.Notify([fvnVisibleFilePropertiesChanged]); end; end; procedure TThumbDrawGrid.CalculateColRowCount; var AIndex, ACol, ARow: Integer; AColCount, ABorderWidth: Integer; begin if (csDesigning in ComponentState) or (FUpdateColCount > 0) then Exit; if not Assigned(FFileView.DisplayFiles) then Exit; BeginUpdate; Inc(FUpdateColCount); try if (ClientWidth > 0) and (DefaultColWidth > 0) then begin // Save active file index AIndex:= CellToIndex(Col, Row); ABorderWidth:= BorderWidth * 2; AColCount := (ClientWidth - ABorderWidth) div DefaultColWidth; if AColCount > 0 then begin ColCount := AColCount; RowCount := (FFileView.DisplayFiles.Count + AColCount - 1) div AColCount; if ColCount > 0 then begin ARow := (ClientWidth - ABorderWidth) div ColCount; // Update columns widths for ACol := 0 to ColCount - 1 do ColWidths[ACol]:= ARow; end; // Restore active file index if AIndex >= 0 then begin IndexToCell(AIndex, ACol, ARow); MoveExtend(False, ACol, ARow); end; end; end; finally EndUpdate(True); Dec(FUpdateColCount); end; end; procedure TThumbDrawGrid.CalculateColumnWidth; begin if gUseFrameCursor then DefaultColWidth := gThumbSize.cx + gBorderFrameWidth*2 + 2 else DefaultColWidth := gThumbSize.cx + 4; end; procedure TThumbDrawGrid.DoMouseMoveScroll(Sender: TObject; X, Y: Integer); const LastPos: Integer = 0; var Delta: Integer; TickCount: QWord; AEvent: SmallInt = -1; begin TickCount := GetTickCount64; Delta := DefaultRowHeight div 3; if Y < Delta then AEvent := SB_LINEUP else if (Y > ClientHeight - Delta) and (Y - FMouseDownY > 8) then begin AEvent := SB_LINEDOWN; end; // Scroll at each 8 pixel mouse move if (Abs(LastPos - Y) < 8) and (Sender <> FThumbView.tmMouseScroll) then Exit; if (AEvent = -1) then begin FThumbView.tmMouseScroll.Enabled := False; Exit; end; LastPos := Y; if (FLastMouseMoveTime = 0) then FLastMouseMoveTime := TickCount else if (FLastMouseScrollTime = 0) then FLastMouseScrollTime := TickCount else if (TickCount - FLastMouseMoveTime > 200) and (TickCount - FLastMouseScrollTime > 50) then begin Scroll(LM_VSCROLL, AEvent); FLastMouseScrollTime := GetTickCount64; FThumbView.tmMouseScroll.Enabled := True; if (AEvent = SB_LINEDOWN) then FMouseDownY := -1; end; end; function TThumbDrawGrid.CellToIndex(ACol, ARow: Integer): Integer; begin if (ARow < 0) or (ARow >= RowCount) or (ACol < 0) or (ACol >= ColCount) then Exit(-1); Result:= ARow * ColCount + ACol; if (Result < 0) or (Result >= FFileView.DisplayFiles.Count) then Result:= -1; end; procedure TThumbDrawGrid.IndexToCell(Index: Integer; out ACol, ARow: Integer); begin if (Index < 0) or (Index >= FFileView.DisplayFiles.Count) or (ColCount = 0) then begin ACol:= -1; ARow:= -1; end else begin ARow:= Index div ColCount; ACol:= Index mod ColCount; end; end; constructor TThumbDrawGrid.Create(AOwner: TComponent; AParent: TWinControl); begin FThumbSize:= gThumbSize; FThumbView:= AParent as TThumbFileView; inherited Create(AOwner, AParent); // Fix horizontal bar flash ScrollBars := ssAutoVertical; Options := Options + [goDontScrollPartCell]; end; procedure TThumbDrawGrid.DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var Idx: Integer; //shared variables AFile: TDisplayFile; FileSourceDirectAccess: Boolean; //------------------------------------------------------ //begin subprocedures //------------------------------------------------------ procedure DrawIconCell(aRect: TRect); var iTextTop: Integer; X, Y: Integer; s: string; IconID: PtrInt; Bitmap: TBitmap; begin iTextTop := aRect.Bottom - Canvas.TextHeight('Wg'); IconID := AFile.Tag; if (AFile.FSFile.IsNameValid) and (IconID >= 0) and (IconID < FThumbView.FBitmapList.Count) then begin Bitmap:= FThumbView.FBitmapList[IconID]; X:= aRect.Left + (aRect.Right - aRect.Left - Bitmap.Width) div 2; Y:= aRect.Top + (iTextTop - aRect.Top - Bitmap.Height) div 2; Canvas.Draw(X, Y, Bitmap); end else begin IconID := AFile.IconID; // Draw default icon if there is no icon for the file. if IconID = -1 then IconID := PixMapManager.GetDefaultIcon(AFile.FSFile); // Center icon X:= aRect.Left + (aRect.Right - aRect.Left - gIconsSize) div 2; Y:= aRect.Top + (iTextTop - aRect.Top - gIconsSize) div 2; // Draw icon for a file PixMapManager.DrawBitmap(IconID, Canvas, X, Y); end; // Draw overlay icon for a file if needed if gIconOverlays then begin PixMapManager.DrawBitmapOverlay(AFile, FileSourceDirectAccess, Canvas, aRect.Left + 2, iTextTop - gIconsSize - 2 ); end; s:= AFile.DisplayStrings[0]; s:= FitFileName(s, Canvas, AFile.FSFile, aRect.Width - 4); Canvas.TextOut(aRect.Left + 2, iTextTop - 1, s); Canvas.Pen.Color:= InvertColor(ColorToRGB(gColors.FilePanel^.BackColor)); Canvas.Pen.Width := 1; Canvas.Frame(aRect.Left + 1, aRect.Top + 1, aRect.Right - 1, aRect.Bottom - Canvas.TextHeight('Pp') - 1); end; //of DrawIconCell //------------------------------------------------------ //end of subprocedures //------------------------------------------------------ begin Idx:= CellToIndex(aCol, aRow); if (Idx >= 0) and (FThumbView.FFiles.Count > 0) then begin AFile:= FThumbView.FFiles[Idx]; FileSourceDirectAccess:= fspDirectAccess in FFileView.FileSource.Properties; if AFile.DisplayStrings.Count = 0 then FThumbView.MakeColumnsStrings(AFile); PrepareColors(AFile, aCol, aRow, aRect, aState); if gUseFrameCursor then DrawIconCell(Rect(aRect.Left + gBorderFrameWidth - 1, aRect.Top + gBorderFrameWidth - 1, aRect.Right - gBorderFrameWidth + 1, aRect.Bottom - gBorderFrameWidth + 1)) else DrawIconCell(aRect); end else begin // Draw background. Canvas.Brush.Color := FThumbView.DimColor(gColors.FilePanel^.BackColor); Canvas.FillRect(aRect); end; DrawCellGrid(aCol, aRow, aRect, aState); DrawLines(Idx, aCol, aRow, aRect, aState); end; { TThumbFileView } procedure TThumbFileView.ThumbnailsRetrieverOnAbort(AStart: Integer; AList: TFPList); var ADisplayFile: TDisplayFile; begin while AStart < AList.Count do begin ADisplayFile := TDisplayFile(AList[AStart]); if IsReferenceValid(ADisplayFile) then begin ADisplayFile.Busy:= ADisplayFile.Busy - [bsTag]; end; Inc(AStart); end; end; procedure TThumbFileView.ThumbnailsRetrieverOnUpdate( const UpdatedFile: TDisplayFile; const UserData: Pointer); var OrigDisplayFile: TDisplayFile absolute UserData; begin if not IsReferenceValid(OrigDisplayFile) then Exit; // File does not exist anymore (reference is invalid). OrigDisplayFile.Busy:= OrigDisplayFile.Busy - [bsTag]; if UpdatedFile.Tag <> -1 then begin if OrigDisplayFile.Tag = -1 then begin OrigDisplayFile.Tag := UpdatedFile.Tag; RedrawFile(OrigDisplayFile); end // The file was changed while we creating a thumbnail // so we need to request a thumbnail creation again else begin OrigDisplayFile.Tag:= -1; FBitmapList[UpdatedFile.Tag]:= nil; Notify([fvnVisibleFilePropertiesChanged]); end; end; end; procedure TThumbFileView.CreateDefault(AOwner: TWinControl); begin inherited CreateDefault(AOwner); tmMouseScroll.Interval := 200; FBitmapList:= TBitmapList.Create(True); FThumbnailManager:= TThumbnailManager.Create(gColors.FilePanel^.BackColor); end; procedure TThumbFileView.AfterChangePath; begin FBitmapList.Clear; inherited AfterChangePath; end; procedure TThumbFileView.EnsureDisplayProperties; var VisibleFiles: TRange; i: Integer; Bitmap: TBitmap; AFileList: TFVWorkerFileList = nil; Worker: TFileViewWorker; AFile: TDisplayFile; begin if (csDestroying in ComponentState) or (GetCurrentWorkType = fvwtCreate) or IsEmpty then Exit; if fspDirectAccess in FileSource.Properties then begin VisibleFiles := GetVisibleFilesIndexes; if not gListFilesInThread then begin for i := VisibleFiles.First to VisibleFiles.Last do begin AFile := FFiles[i]; if (AFile.Tag < 0) and AFile.FSFile.IsNameValid then begin Bitmap:= FThumbnailManager.CreatePreview(AFile.FSFile); if Assigned(Bitmap) then begin AFile.Tag := FBitmapList.Add(Bitmap); end; end; end; end else begin try for i := VisibleFiles.First to VisibleFiles.Last do begin AFile := FFiles[i]; if (AFile.Tag < 0) and AFile.FSFile.IsNameValid and (AFile.Busy * [bsTag] = []) then begin if not Assigned(AFileList) then AFileList := TFVWorkerFileList.Create; AFileList.AddClone(AFile, AFile); AFile.Busy := AFile.Busy + [bsTag]; end; end; if Assigned(AFileList) and (AFileList.Count > 0) then begin Worker := TFileThumbnailsRetriever.Create( FileSource, WorkersThread, FBitmapList, @ThumbnailsRetrieverOnUpdate, @ThumbnailsRetrieverOnAbort, FThumbnailManager, AFileList); AddWorker(Worker, True); WorkersThread.QueueFunction(@Worker.StartParam); end; finally AFileList.Free; end; end; end; inherited EnsureDisplayProperties; end; function TThumbFileView.GetFileViewGridClass: TFileViewGridClass; begin Result:= TThumbDrawGrid; end; function TThumbFileView.GetVisibleFilesIndexes: TRange; begin with dgPanel do begin if (TopRow < 0) or (csLoading in ComponentState) then begin Result.First:= 0; Result.Last:= -1; end else begin Result.First:= (TopRow * VisibleColCount - 1); Result.Last:= (TopRow + VisibleRowCount + 1) * VisibleColCount - 1; if Result.First < 0 then Result.First:= 0; if Result.Last >= FFiles.Count then Result.Last:= FFiles.Count - 1; end; end; end; procedure TThumbFileView.ShowRenameFileEdit(var aFile: TFile); begin if not edtRename.Visible then begin edtRename.Font.Name := gFonts[dcfMain].Name; edtRename.Font.Size := gFonts[dcfMain].Size; edtRename.Font.Style := gFonts[dcfMain].Style; UpdateRenameFileEditPosition; end; inherited ShowRenameFileEdit(AFile); end; procedure TThumbFileView.UpdateRenameFileEditPosition(); var ARect: TRect; begin inherited UpdateRenameFileEditPosition; ARect := dgPanel.CellRect(dgPanel.Col, dgPanel.Row); ARect.Top := ARect.Bottom - dgPanel.Canvas.TextHeight('Wg') - 4; if gInplaceRenameButton and (ARect.Right + edtRename.ButtonWidth < dgPanel.ClientWidth) then Inc(ARect.Right, edtRename.ButtonWidth); edtRename.SetBounds(ARect.Left, ARect.Top, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top); end; function TThumbFileView.GetIconRect(FileIndex: PtrInt): TRect; begin Result:= GetFileRect(FileIndex); Result.Right:= Result.Left + (Result.Right - Result.Left) div 4; end; procedure TThumbFileView.MouseScrollTimer(Sender: TObject); var APoint: TPoint; begin if DragManager.IsDragging or IsMouseSelecting then begin APoint := dgPanel.ScreenToClient(Mouse.CursorPos); TThumbDrawGrid(dgPanel).DoMouseMoveScroll(tmMouseScroll, APoint.X, APoint.Y); end; end; procedure TThumbFileView.DoFileChanged(ADisplayFile: TDisplayFile; APropertiesChanged: TFilePropertiesTypes); begin if (APropertiesChanged * [fpSize, fpModificationTime] = []) then Exit; ADisplayFile.Busy := ADisplayFile.Busy - [bsTag]; if InRange(ADisplayFile.Tag, 0, FBitmapList.Count - 1) then begin FBitmapList[ADisplayFile.Tag]:= nil; ADisplayFile.Tag:= -1; end else if ADisplayFile.Tag < 0 then ADisplayFile.Tag:= ADisplayFile.Tag - 1 else begin ADisplayFile.Tag:= -1; end; end; constructor TThumbFileView.Create(AOwner: TWinControl; AConfig: TXmlConfig; ANode: TXmlNode; AFlags: TFileViewFlags); begin inherited Create(AOwner, AConfig, ANode, AFlags); end; constructor TThumbFileView.Create(AOwner: TWinControl; AFileView: TFileView; AFlags: TFileViewFlags); var I: Integer; begin inherited Create(AOwner, AFileView, AFlags); if Assigned(FAllDisplayFiles) then begin // Clear thumbnail image index for I := 0 to FAllDisplayFiles.Count - 1 do FAllDisplayFiles[I].Tag:= -1; // Load thumbnails Notify([fvnVisibleFilePropertiesChanged]); end; end; destructor TThumbFileView.Destroy; begin inherited Destroy; FreeAndNil(FBitmapList); FreeAndNil(FThumbnailManager); end; function TThumbFileView.Clone(NewParent: TWinControl): TThumbFileView; begin Result := TThumbFileView.Create(NewParent, Self); end; procedure TThumbFileView.SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode; ASaveHistory:boolean); begin inherited SaveConfiguration(AConfig, ANode, ASaveHistory); AConfig.SetAttr(ANode, 'Type', 'thumbnails'); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/flinker.lfm��������������������������������������������������������������������0000644�0001750�0000144�00000012160�14743153644�015527� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmLinker: TfrmLinker Left = 411 Height = 425 Top = 166 Width = 397 HorzScrollBar.Page = 359 HorzScrollBar.Range = 289 VertScrollBar.Page = 363 VertScrollBar.Range = 331 ActiveControl = edSave BorderIcons = [biSystemMenu, biMaximize] Caption = 'Linker' ClientHeight = 425 ClientWidth = 397 OnCreate = FormCreate Position = poOwnerFormCenter SessionProperties = 'Height;Width' inherited pnlContent: TPanel AnchorSideBottom.Control = pnlButtons Height = 371 Width = 381 ClientHeight = 371 ClientWidth = 381 object gbSaveTo: TGroupBox[0] AnchorSideLeft.Control = pnlContent AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlContent AnchorSideBottom.Side = asrBottom Left = 0 Height = 76 Top = 290 Width = 381 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Bottom = 6 Caption = 'Save to...' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 56 ClientWidth = 377 TabOrder = 1 object lblFileName: TLabel AnchorSideLeft.Control = gbSaveTo AnchorSideTop.Control = gbSaveTo Left = 6 Height = 15 Top = 6 Width = 51 Caption = '&File name' FocusControl = edSave ParentColor = False end object edSave: TEdit AnchorSideLeft.Control = gbSaveTo AnchorSideTop.Control = lblFileName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnSave Left = 6 Height = 23 Top = 27 Width = 334 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 6 TabOrder = 0 end object btnSave: TButton AnchorSideTop.Control = edSave AnchorSideRight.Control = gbSaveTo AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edSave AnchorSideBottom.Side = asrBottom Left = 346 Height = 23 Top = 27 Width = 25 Anchors = [akTop, akRight, akBottom] BorderSpacing.InnerBorder = 4 Caption = '...' OnClick = btnSaveClick TabOrder = 1 end end object grbxControl: TGroupBox[1] AnchorSideTop.Control = lstFile AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = lstFile AnchorSideBottom.Side = asrBottom Left = 281 Height = 284 Top = 0 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True Caption = 'Item' ClientHeight = 264 ClientWidth = 96 TabOrder = 2 object spbtnUp: TButton AnchorSideLeft.Control = grbxControl AnchorSideRight.Control = grbxControl AnchorSideRight.Side = asrBottom Left = 4 Height = 32 Hint = 'Up' Top = 1 Width = 88 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 4 BorderSpacing.Right = 4 BorderSpacing.InnerBorder = 4 Caption = '&Up' OnClick = spbtnUpClick ParentShowHint = False TabOrder = 0 end object spbtnDown: TButton AnchorSideLeft.Control = grbxControl AnchorSideTop.Control = spbtnUp AnchorSideTop.Side = asrBottom AnchorSideRight.Control = grbxControl AnchorSideRight.Side = asrBottom Left = 4 Height = 32 Hint = 'Down' Top = 39 Width = 88 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 4 BorderSpacing.Top = 6 BorderSpacing.Right = 4 BorderSpacing.InnerBorder = 4 Caption = 'Do&wn' OnClick = spbtnDownClick ParentShowHint = False TabOrder = 1 end object spbtnRem: TButton AnchorSideLeft.Control = grbxControl AnchorSideTop.Control = spbtnDown AnchorSideTop.Side = asrBottom AnchorSideRight.Control = grbxControl AnchorSideRight.Side = asrBottom Left = 4 Height = 32 Hint = 'Delete' Top = 77 Width = 88 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 4 BorderSpacing.Top = 6 BorderSpacing.Right = 4 BorderSpacing.InnerBorder = 4 Caption = '&Remove' OnClick = spbtnRemClick ParentShowHint = False TabOrder = 2 end end object lstFile: TListBox[2] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = pnlContent AnchorSideRight.Control = grbxControl AnchorSideBottom.Control = gbSaveTo Left = 0 Height = 284 Top = 0 Width = 275 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Right = 6 BorderSpacing.Bottom = 6 ItemHeight = 0 ScrollWidth = 240 TabOrder = 0 end end inherited pnlButtons: TPanel AnchorSideTop.Side = asrTop end object dlgSaveAll: TSaveDialog[3] Filter = 'All files|*.*' FilterIndex = 0 left = 288 top = 160 end end����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/flinker.lrj��������������������������������������������������������������������0000644�0001750�0000144�00000002263�14743153644�015543� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":87052738,"name":"tfrmlinker.caption","sourcebytes":[76,105,110,107,101,114],"value":"Linker"}, {"hash":125868494,"name":"tfrmlinker.gbsaveto.caption","sourcebytes":[83,97,118,101,32,116,111,46,46,46],"value":"Save to..."}, {"hash":41282357,"name":"tfrmlinker.lblfilename.caption","sourcebytes":[38,70,105,108,101,32,110,97,109,101],"value":"&File name"}, {"hash":12558,"name":"tfrmlinker.btnsave.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":330429,"name":"tfrmlinker.grbxcontrol.caption","sourcebytes":[73,116,101,109],"value":"Item"}, {"hash":1472,"name":"tfrmlinker.spbtnup.hint","sourcebytes":[85,112],"value":"Up"}, {"hash":11200,"name":"tfrmlinker.spbtnup.caption","sourcebytes":[38,85,112],"value":"&Up"}, {"hash":308958,"name":"tfrmlinker.spbtndown.hint","sourcebytes":[68,111,119,110],"value":"Down"}, {"hash":4922846,"name":"tfrmlinker.spbtndown.caption","sourcebytes":[68,111,38,119,110],"value":"Do&wn"}, {"hash":78392485,"name":"tfrmlinker.spbtnrem.hint","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":193742565,"name":"tfrmlinker.spbtnrem.caption","sourcebytes":[38,82,101,109,111,118,101],"value":"&Remove"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/flinker.pas��������������������������������������������������������������������0000644�0001750�0000144�00000014645�14743153644�015546� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Take selected files and put them together to form one single file. Copyright (C) 2018-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Original comment: ---------------------------- Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : Pavel Letko (letcuv@centrum.cz) File combiner contributors: Radek Cervinka } unit fLinker; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. SysUtils, Classes, Forms, Dialogs, StdCtrls, //DC fButtonForm, uFileSource, uFile; type { TfrmLinker } TfrmLinker = class(TfrmButtonForm) lblFileName: TLabel; lstFile: TListBox; gbSaveTo: TGroupBox; edSave: TEdit; btnSave: TButton; grbxControl: TGroupBox; spbtnUp: TButton; spbtnDown: TButton; spbtnRem: TButton; dlgSaveAll: TSaveDialog; procedure spbtnUpClick(Sender: TObject); procedure spbtnDownClick(Sender: TObject); procedure spbtnRemClick(Sender: TObject); procedure btnSaveClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; { ShowLinkerFilesForm: "TMainCommands.cm_FileLinker" function from "uMainCommands.pas" is calling this routine.} function ShowLinkerFilesForm(TheOwner: TComponent; aFileSource: IFileSource; aFiles: TFiles; TargetPath: String): Boolean; { DoDynamicFilesLinking: "TMainCommands.cm_FileLinker" function from "uMainCommands.pas" is calling this routine.} procedure DoDynamicFilesLinking(aFileSource: IFileSource; aFiles: TFiles; TargetPath, aFirstFilenameOfSeries: String); implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. LCLProc, Controls, //DC DCStrUtils, uLng, uFileProcs, uOperationsManager, uFileSourceCombineOperation, DCOSUtils, uShowMsg, uGlobs; { ShowLinkerFilesForm: "TMainCommands.cm_FileLinker" function from "uMainCommands.pas" is calling this routine.} function ShowLinkerFilesForm(TheOwner: TComponent; aFileSource: IFileSource; aFiles: TFiles; TargetPath: String): Boolean; var I: Integer; AFileName: String; ADirectory: String; xFiles: TFiles = nil; Operation: TFileSourceCombineOperation = nil; begin with TfrmLinker.Create(TheOwner) do begin try // Fill file list box for I:= 0 to aFiles.Count - 1 do with lstFile.Items do begin AddObject(aFiles[I].Name, aFiles[I]); end; // Use first file name without extension as target file name edSave.Text:= TargetPath + aFiles[0].NameNoExt; // Show form Result:= (ShowModal = mrOk); if Result then begin ADirectory:= ExtractFileDir(edSave.Text); if Length(ADirectory) > 0 then begin AFileName:= edSave.Text end else begin AFileName:= aFiles.Path + edSave.Text; ADirectory:= ExcludeTrailingBackslash(aFiles.Path); end; for I:= 0 to lstFile.Count - 1 do begin with lstFile.Items do if mbCompareFileNames(TFile(Objects[I]).FullPath, AFileName) then begin msgError(Format(rsMsgCanNotCopyMoveItSelf, [AFileName])); Exit; end; end; if mbForceDirectory(ADirectory) then try // Fill file list with new file order xFiles:= TFiles.Create(aFiles.Path); for I:= 0 to lstFile.Count - 1 do with lstFile.Items do begin xFiles.Add(TFile(Objects[I]).Clone); end; Operation:= aFileSource.CreateCombineOperation(xFiles, AFileName) as TFileSourceCombineOperation; OperationsManager.AddOperation(Operation, QueueIdentifier, False); finally FreeAndNil(xFiles); end; end; finally Free; end; end; end; { DoDynamicFilesLinking: "TMainCommands.cm_FileLinker" function from "uMainCommands.pas" is calling this routine.} procedure DoDynamicFilesLinking(aFileSource: IFileSource; aFiles: TFiles; TargetPath, aFirstFilenameOfSeries: String); var xFiles: TFiles = nil; Operation: TFileSourceCombineOperation = nil; begin xFiles:= TFiles.Create(aFiles.Path); try //Fill file list with new file order xFiles.Add(aFiles[0].Clone); Operation:= aFileSource.CreateCombineOperation(xFiles, TargetPath + aFiles[0].NameNoExt) as TFileSourceCombineOperation; Operation.RequireDynamicMode:=TRUE; OperationsManager.AddOperation(Operation); finally FreeAndNil(xFiles); end; end; { TfrmLinker.spbtnDownClick } procedure TfrmLinker.spbtnDownClick(Sender: TObject); var iSelected: Integer; begin with lstFile do begin if ItemIndex < 0 then Exit; if ItemIndex = Items.Count - 1 then Exit; iSelected:= ItemIndex; Items.Move(iSelected, iSelected + 1); ItemIndex:= iSelected + 1; end; end; { TfrmLinker.spbtnUpClick } procedure TfrmLinker.spbtnUpClick(Sender: TObject); var iSelected: Integer; begin with lstFile do begin if ItemIndex < 1 then Exit; iSelected:= ItemIndex; Items.Move(iSelected, iSelected - 1); ItemIndex:= iSelected - 1; end; end; { TfrmLinker.spbtnRemClick } procedure TfrmLinker.spbtnRemClick(Sender: TObject); begin with lstFile do begin if ItemIndex > -1 then Items.Delete(ItemIndex); end; end; { TfrmLinker.btnSaveClick } procedure TfrmLinker.btnSaveClick(Sender: TObject); begin dlgSaveAll.InitialDir:= ExtractFileDir(edSave.Text); dlgSaveAll.FileName:= ExtractFileName(edSave.Text); if dlgSaveAll.Execute then edSave.Text:= dlgSaveAll.FileName; end; {TfrmLinker.FormCreate } procedure TfrmLinker.FormCreate(Sender: TObject); begin InitPropStorage(Self); // Initialize property storage dlgSaveAll.Filter := ParseLineToFileFilter([rsFilterAnyFiles, AllFilesMask]); end; end. �������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmain.lfm����������������������������������������������������������������������0000644�0001750�0000144�00000453534�14743153644�015205� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMain: TfrmMain Left = 485 Height = 370 Top = 269 Width = 760 Caption = 'Double Commander' ClientHeight = 370 ClientWidth = 760 Constraints.MaxHeight = 32767 Constraints.MaxWidth = 32767 KeyPreview = True OnClose = frmMainClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnKeyDown = FormKeyDown OnKeyPress = FormKeyPress OnKeyUp = FormKeyUp OnResize = FormResize OnShow = frmMainShow OnUTF8KeyPress = FormUTF8KeyPress OnWindowStateChange = FormWindowStateChange SessionProperties = 'nbConsole.Height;seLogWindow.Height;TreePanel.Width' ShowHint = True ShowInTaskBar = stAlways LCLVersion = '1.8.4.0' object MainToolbar: TKASToolBar AnchorSideTop.Control = Owner Left = 0 Height = 20 Top = 0 Width = 760 AutoSize = True Constraints.MinHeight = 20 EdgeBorders = [] Flat = True TabOrder = 1 OnDragDrop = MainToolBarDragDrop OnDragOver = MainToolBarDragOver OnMouseUp = MainToolBarMouseUp OnLoadButtonGlyph = MainToolBarLoadButtonGlyph OnLoadButtonOverlay = MainToolBarLoadButtonOverlay OnToolButtonMouseDown = MainToolBarToolButtonMouseDown OnToolButtonMouseUp = MainToolBarToolButtonMouseUp OnToolButtonDragDrop = MainToolBarToolButtonDragDrop OnToolButtonDragOver = MainToolBarToolButtonDragOver OnToolItemShortcutsHint = MainToolBarToolItemShortcutsHint GlyphSize = 16 end object TreePanel: TPanel Left = 0 Height = 191 Top = 20 Width = 121 Align = alLeft BevelOuter = bvNone TabOrder = 0 Visible = False end object TreeSplitter: TSplitter Left = 121 Height = 191 Top = 20 Width = 5 end object pnlMain: TPanel Left = 126 Height = 191 Top = 20 Width = 634 Align = alClient BevelOuter = bvNone ClientHeight = 191 ClientWidth = 634 TabOrder = 5 object pnlDisk: TKASToolPanel AnchorSideTop.Control = MainToolbar Left = 0 Height = 24 Top = 0 Width = 634 Align = alTop AutoSize = True EdgeBorders = [ebTop, ebBottom] Visible = False object pnlDskLeft: TPanel AnchorSideLeft.Control = pnlDisk AnchorSideTop.Control = pnlDisk Left = 0 Height = 24 Top = 0 Width = 170 AutoSize = True BevelOuter = bvNone ClientHeight = 24 ClientWidth = 170 TabOrder = 0 Visible = False object dskLeft: TKASToolBar Left = 0 Height = 20 Top = 0 Width = 170 AutoSize = True Constraints.MinHeight = 20 EdgeBorders = [] Flat = True ShowCaptions = True TabOrder = 0 OnToolButtonClick = dskLeftToolButtonClick OnToolButtonMouseDown = dskToolButtonMouseDown OnToolButtonMouseUp = dskToolButtonMouseUp OnToolButtonDragDrop = dskLeftRightToolButtonDragDrop RadioToolBar = True GlyphSize = 16 end end object pnlDskRight: TPanel AnchorSideTop.Control = pnlDisk AnchorSideRight.Control = pnlDisk AnchorSideRight.Side = asrBottom Left = 46 Height = 24 Top = 0 Width = 588 AutoSize = True Anchors = [akTop, akRight] BevelOuter = bvNone ClientHeight = 24 ClientWidth = 588 TabOrder = 1 Visible = False object dskRight: TKASToolBar Left = 0 Height = 20 Top = 0 Width = 588 AutoSize = True Constraints.MinHeight = 20 EdgeBorders = [] Flat = True ShowCaptions = True TabOrder = 0 OnToolButtonClick = dskRightToolButtonClick OnToolButtonMouseDown = dskToolButtonMouseDown OnToolButtonMouseUp = dskToolButtonMouseUp OnToolButtonDragDrop = dskLeftRightToolButtonDragDrop RadioToolBar = True GlyphSize = 16 end end end object pnlNotebooks: TPanel Left = 0 Height = 167 Top = 24 Width = 634 Align = alClient BevelOuter = bvNone ClientHeight = 167 ClientWidth = 634 FullRepaint = False TabOrder = 1 OnResize = pnlNotebooksResize object pnlLeft: TPanel Left = 0 Height = 167 Top = 0 Width = 511 Align = alLeft BevelOuter = bvNone ClientHeight = 167 ClientWidth = 511 TabOrder = 0 OnDblClick = pnlLeftRightDblClick OnResize = pnlLeftResize object pnlDiskLeftInner: TKASToolPanel Left = 0 Height = 10 Top = 0 Width = 511 Align = alTop AutoSize = True EdgeBorders = [ebTop, ebBottom] Visible = False end object pnlLeftTools: TPanel Left = 0 Height = 24 Top = 10 Width = 511 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 24 ClientWidth = 511 TabOrder = 0 Visible = False object btnLeftDrive: TSpeedButton Left = 0 Height = 24 Top = 0 Width = 48 Action = actLeftOpenDrives Align = alLeft Constraints.MinHeight = 24 OnMouseUp = btnDriveMouseUp end object btnLeftHome: TSpeedButton Left = 465 Height = 24 Hint = 'Go to home directory' Top = 0 Width = 23 Align = alRight Caption = '~' OnClick = btnLeftClick end object btnLeftUp: TSpeedButton Left = 442 Height = 24 Hint = 'Go to parent directory' Top = 0 Width = 23 Align = alRight Caption = '..' OnClick = btnLeftClick end object btnLeftRoot: TSpeedButton Left = 419 Height = 24 Hint = 'Go to root directory' Top = 0 Width = 23 Align = alRight Caption = '/' OnClick = btnLeftClick end object btnLeftDirectoryHotlist: TSpeedButton Left = 396 Height = 24 Hint = 'Directory Hotlist' Top = 0 Width = 23 Align = alRight Caption = '*' OnClick = btnLeftDirectoryHotlistClick end object btnLeftEqualRight: TSpeedButton Left = 488 Height = 24 Hint = 'Show current directory of the right panel in the left panel' Top = 0 Width = 23 Action = actLeftEqualRight Align = alRight Caption = '<' end object pbxLeftDrive: TPaintBox AnchorSideLeft.Control = lblLeftDriveInfo AnchorSideTop.Control = lblLeftDriveInfo AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblLeftDriveInfo AnchorSideRight.Side = asrBottom Left = 52 Height = 10 Top = 1 Width = 342 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 BorderSpacing.Right = 2 OnPaint = sboxDrivePaint end object lblLeftDriveInfo: TLabel AnchorSideLeft.Control = btnLeftDrive AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlLeftTools AnchorSideRight.Side = asrBottom Left = 50 Height = 1 Top = 0 Width = 346 Alignment = taCenter Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 BorderSpacing.Right = 2 ParentColor = False OnDblClick = lblDriveInfoDblClick OnResize = lblDriveInfoResize end end end object MiddleToolbar: TKASToolBar Left = 511 Height = 161 Top = 0 Width = 20 Align = alLeft AutoSize = True Constraints.MinHeight = 20 Constraints.MinWidth = 20 EdgeBorders = [] Flat = True TabOrder = 3 Visible = False OnDragDrop = MainToolBarDragDrop OnDragOver = MainToolBarDragOver OnMouseUp = MainToolBarMouseUp OnLoadButtonGlyph = MainToolBarLoadButtonGlyph OnLoadButtonOverlay = MainToolBarLoadButtonOverlay OnToolButtonMouseDown = MainToolBarToolButtonMouseDown OnToolButtonMouseUp = MainToolBarToolButtonMouseUp OnToolButtonDragDrop = MainToolBarToolButtonDragDrop OnToolButtonDragOver = MainToolBarToolButtonDragOver OnToolItemShortcutsHint = MainToolBarToolItemShortcutsHint GlyphSize = 16 end object pnlRight: TPanel Left = 511 Height = 167 Top = 0 Width = 123 Align = alClient BevelOuter = bvNone ClientHeight = 167 ClientWidth = 123 TabOrder = 1 OnDblClick = pnlLeftRightDblClick OnResize = pnlRightResize object pnlDiskRightInner: TKASToolPanel Left = 0 Height = 10 Top = 0 Width = 123 Align = alTop AutoSize = True EdgeBorders = [ebTop, ebBottom] Visible = False end object pnlRightTools: TPanel Left = 0 Height = 24 Top = 10 Width = 123 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 24 ClientWidth = 123 TabOrder = 0 Visible = False object btnRightDrive: TSpeedButton Left = 0 Height = 24 Top = 0 Width = 48 Action = actRightOpenDrives Align = alLeft Constraints.MinHeight = 24 OnMouseUp = btnDriveMouseUp end object btnRightHome: TSpeedButton Left = 77 Height = 24 Top = 0 Width = 23 Align = alRight Caption = '~' OnClick = btnRightClick end object btnRightUp: TSpeedButton Left = 54 Height = 24 Top = 0 Width = 23 Align = alRight Caption = '..' OnClick = btnRightClick end object btnRightRoot: TSpeedButton Left = 31 Height = 24 Top = 0 Width = 23 Align = alRight Caption = '/' OnClick = btnRightClick end object btnRightDirectoryHotlist: TSpeedButton Left = 25 Height = 24 Hint = 'Directory Hotlist' Top = 0 Width = 23 Align = alRight Caption = '*' OnClick = btnRightDirectoryHotlistClick end object btnRightEqualLeft: TSpeedButton Left = 100 Height = 24 Hint = 'Show current directory of the left panel in the right panel' Top = 0 Width = 23 Action = actRightEqualLeft Align = alRight Caption = '>' end object pbxRightDrive: TPaintBox AnchorSideLeft.Control = lblRightDriveInfo AnchorSideTop.Control = lblRightDriveInfo AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblRightDriveInfo AnchorSideRight.Side = asrBottom Left = 52 Height = 10 Top = 1 Width = 0 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 BorderSpacing.Right = 2 OnPaint = sboxDrivePaint end object lblRightDriveInfo: TLabel AnchorSideLeft.Control = btnRightDrive AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlRightTools AnchorSideRight.Side = asrBottom Left = 50 Height = 1 Top = 0 Width = 0 Alignment = taCenter Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 BorderSpacing.Right = 2 ParentColor = False OnDblClick = lblDriveInfoDblClick OnResize = lblDriveInfoResize end end end object MainSplitter: TPanel Cursor = crHSplit Left = 429 Height = 78 Top = -40 Width = 5 Anchors = [] BevelOuter = bvNone PopupMenu = pmSplitterPercent TabOrder = 2 OnDblClick = MainSplitterDblClick OnMouseDown = MainSplitterMouseDown OnMouseMove = MainSplitterMouseMove OnMouseUp = MainSplitterMouseUp end end end object PanelAllProgress: TPanel Left = 0 Height = 0 Top = 211 Width = 760 Align = alBottom AutoSize = True BevelOuter = bvNone TabOrder = 2 Visible = False end object ConsoleSplitter: TSplitter Cursor = crVSplit Left = 0 Height = 3 Top = 211 Width = 760 Align = alBottom AutoSnap = False OnCanResize = ConsoleSplitterCanResize OnMoved = ConsoleSplitterMoved ResizeAnchor = akBottom ResizeStyle = rsLine Visible = False end object pnlCommand: TPanel AnchorSideBottom.Control = LogSplitter Left = 0 Height = 81 Top = 214 Width = 760 Align = alBottom AutoSize = True BevelOuter = bvNone ClientHeight = 81 ClientWidth = 760 FullRepaint = False TabOrder = 8 object pnlCmdLine: TPanel Left = 0 Height = 27 Top = 54 Width = 760 Align = alClient AutoSize = True BevelOuter = bvNone ChildSizing.TopBottomSpacing = 2 ClientHeight = 27 ClientWidth = 760 TabOrder = 1 object lblCommandPath: TLabel AnchorSideTop.Control = edtCommand AnchorSideTop.Side = asrCenter Left = 2 Height = 15 Top = 6 Width = 24 BorderSpacing.Left = 2 Caption = 'Path' ParentColor = False ShowAccelChar = False end object edtCommand: TComboBoxWithDelItems AnchorSideLeft.Control = lblCommandPath AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlCmdLine AnchorSideRight.Control = pnlCmdLine AnchorSideRight.Side = asrBottom Left = 28 Height = 23 Top = 2 Width = 732 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 BorderSpacing.Right = 2 ItemHeight = 15 OnExit = edtCommandExit OnKeyDown = edtCommandKeyDown TabOrder = 0 TabStop = False end end object nbConsole: TPageControl Left = 0 Height = 54 Top = 0 Width = 760 TabStop = False ActivePage = pgConsole Align = alTop ShowTabs = False TabIndex = 0 TabOrder = 0 Visible = False object pgConsole: TTabSheet end end end object LogSplitter: TSplitter AnchorSideBottom.Control = seLogWindow Cursor = crVSplit Left = 0 Height = 4 Top = 295 Width = 760 Align = alBottom AutoSnap = False ResizeAnchor = akBottom ResizeStyle = rsLine Visible = False end inline seLogWindow: TSynEdit AnchorSideBottom.Control = pnlKeys Left = 0 Height = 51 Top = 299 Width = 760 Align = alBottom Color = clWindow Font.Color = clWindowText Font.Height = -16 Font.Name = 'courier' Font.Pitch = fpFixed Font.Quality = fqNonAntialiased ParentColor = False ParentFont = False PopupMenu = pmLogMenu TabOrder = 4 TabStop = False Visible = False Gutter.Width = 0 Gutter.MouseActions = <> RightGutter.Width = 0 RightGutter.MouseActions = <> Keystrokes = < item Command = ecUp ShortCut = 38 end item Command = ecSelUp ShortCut = 8230 end item Command = ecScrollUp ShortCut = 16422 end item Command = ecDown ShortCut = 40 end item Command = ecSelDown ShortCut = 8232 end item Command = ecScrollDown ShortCut = 16424 end item Command = ecLeft ShortCut = 37 end item Command = ecSelLeft ShortCut = 8229 end item Command = ecWordLeft ShortCut = 16421 end item Command = ecSelWordLeft ShortCut = 24613 end item Command = ecRight ShortCut = 39 end item Command = ecSelRight ShortCut = 8231 end item Command = ecWordRight ShortCut = 16423 end item Command = ecSelWordRight ShortCut = 24615 end item Command = ecPageDown ShortCut = 34 end item Command = ecSelPageDown ShortCut = 8226 end item Command = ecPageBottom ShortCut = 16418 end item Command = ecSelPageBottom ShortCut = 24610 end item Command = ecPageUp ShortCut = 33 end item Command = ecSelPageUp ShortCut = 8225 end item Command = ecPageTop ShortCut = 16417 end item Command = ecSelPageTop ShortCut = 24609 end item Command = ecLineStart ShortCut = 36 end item Command = ecSelLineStart ShortCut = 8228 end item Command = ecEditorTop ShortCut = 16420 end item Command = ecSelEditorTop ShortCut = 24612 end item Command = ecLineEnd ShortCut = 35 end item Command = ecSelLineEnd ShortCut = 8227 end item Command = ecEditorBottom ShortCut = 16419 end item Command = ecSelEditorBottom ShortCut = 24611 end item Command = ecToggleMode ShortCut = 45 end item Command = ecCopy ShortCut = 16429 end item Command = ecPaste ShortCut = 8237 end item Command = ecDeleteChar ShortCut = 46 end item Command = ecCut ShortCut = 8238 end item Command = ecDeleteLastChar ShortCut = 8 end item Command = ecDeleteLastChar ShortCut = 8200 end item Command = ecDeleteLastWord ShortCut = 16392 end item Command = ecUndo ShortCut = 32776 end item Command = ecRedo ShortCut = 40968 end item Command = ecLineBreak ShortCut = 13 end item Command = ecSelectAll ShortCut = 16449 end item Command = ecCopy ShortCut = 16451 end item Command = ecBlockIndent ShortCut = 24649 end item Command = ecLineBreak ShortCut = 16461 end item Command = ecInsertLine ShortCut = 16462 end item Command = ecDeleteWord ShortCut = 16468 end item Command = ecBlockUnindent ShortCut = 24661 end item Command = ecPaste ShortCut = 16470 end item Command = ecCut ShortCut = 16472 end item Command = ecDeleteLine ShortCut = 16473 end item Command = ecDeleteEOL ShortCut = 24665 end item Command = ecUndo ShortCut = 16474 end item Command = ecRedo ShortCut = 24666 end item Command = ecGotoMarker0 ShortCut = 16432 end item Command = ecGotoMarker1 ShortCut = 16433 end item Command = ecGotoMarker2 ShortCut = 16434 end item Command = ecGotoMarker3 ShortCut = 16435 end item Command = ecGotoMarker4 ShortCut = 16436 end item Command = ecGotoMarker5 ShortCut = 16437 end item Command = ecGotoMarker6 ShortCut = 16438 end item Command = ecGotoMarker7 ShortCut = 16439 end item Command = ecGotoMarker8 ShortCut = 16440 end item Command = ecGotoMarker9 ShortCut = 16441 end item Command = ecSetMarker0 ShortCut = 24624 end item Command = ecSetMarker1 ShortCut = 24625 end item Command = ecSetMarker2 ShortCut = 24626 end item Command = ecSetMarker3 ShortCut = 24627 end item Command = ecSetMarker4 ShortCut = 24628 end item Command = ecSetMarker5 ShortCut = 24629 end item Command = ecSetMarker6 ShortCut = 24630 end item Command = ecSetMarker7 ShortCut = 24631 end item Command = ecSetMarker8 ShortCut = 24632 end item Command = ecSetMarker9 ShortCut = 24633 end item Command = ecNormalSelect ShortCut = 24654 end item Command = ecColumnSelect ShortCut = 24643 end item Command = ecLineSelect ShortCut = 24652 end item Command = ecTab ShortCut = 9 end item Command = ecShiftTab ShortCut = 8201 end item Command = ecMatchBracket ShortCut = 24642 end> MouseActions = <> MouseTextActions = <> MouseSelActions = <> VisibleSpecialChars = [vscSpace, vscTabAtLast] ReadOnly = True RightEdge = 0 ScrollBars = ssVertical SelectedColor.BackPriority = 50 SelectedColor.ForePriority = 50 SelectedColor.FramePriority = 50 SelectedColor.BoldPriority = 50 SelectedColor.ItalicPriority = 50 SelectedColor.UnderlinePriority = 50 SelectedColor.StrikeOutPriority = 50 BracketHighlightStyle = sbhsBoth BracketMatchColor.Background = clNone BracketMatchColor.Foreground = clNone BracketMatchColor.Style = [fsBold] FoldedCodeColor.Background = clNone FoldedCodeColor.Foreground = clGray FoldedCodeColor.FrameColor = clGray MouseLinkColor.Background = clNone MouseLinkColor.Foreground = clBlue LineHighlightColor.Background = clNone LineHighlightColor.Foreground = clNone OnSpecialLineColors = seLogWindowSpecialLineColors inline SynLeftGutterPartList1: TSynGutterPartList end end object pnlKeys: TPanel Left = 0 Height = 20 Top = 350 Width = 760 Align = alBottom BevelOuter = bvNone ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.ShrinkVertical = crsHomogenousChildResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ClientHeight = 20 ClientWidth = 760 FullRepaint = False TabOrder = 3 Visible = False object btnF3: TSpeedButton Left = 0 Height = 20 Top = 0 Width = 89 Action = actView Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF4: TSpeedButton Left = 89 Height = 20 Top = 0 Width = 84 Action = actEdit Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF5: TSpeedButton Left = 173 Height = 20 Top = 0 Width = 92 Action = actCopy Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF6: TSpeedButton Left = 265 Height = 20 Top = 0 Width = 94 Action = actRename Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF7: TSpeedButton Left = 359 Height = 20 Top = 0 Width = 112 Action = actMakeDir Caption = 'Directory' Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF8: TSpeedButton Left = 471 Height = 20 Top = 0 Width = 97 Caption = 'Delete' Flat = True OnClick = btnF8Click OnMouseDown = btnF8MouseDown OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF9: TSpeedButton Left = 568 Height = 20 Top = 0 Width = 110 Action = actRunTerm Caption = 'Terminal' Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end object btnF10: TSpeedButton Left = 678 Height = 20 Top = 0 Width = 82 Action = actExit Caption = 'Exit' Flat = True OnMouseWheelDown = btnF3MouseWheelDown OnMouseWheelUp = btnF3MouseWheelUp end end object mnuMain: TMainMenu ParentBidiMode = False left = 232 top = 8 object mnuFiles: TMenuItem Caption = '&Files' object mnuFilesSymLink: TMenuItem Action = actSymLink end object mnuFilesHardLink: TMenuItem Action = actHardLink end object miMakeDir: TMenuItem Action = actMakeDir end object miLine1: TMenuItem Caption = '-' end object mnuSetFileProperties: TMenuItem Action = actSetFileProperties end object mnuFilesProperties: TMenuItem Action = actFileProperties end object miEditComment: TMenuItem Action = actEditComment end object mnuFilesSpace: TMenuItem Action = actCalculateSpace end object mnuFilesCmpCnt: TMenuItem Action = actCompareContents end object miMultiRename: TMenuItem Action = actMultiRename end object miLine2: TMenuItem Caption = '-' end object mnuPackFiles: TMenuItem Action = actPackFiles end object mnuExtractFiles: TMenuItem Action = actExtractFiles end object mnuTestArchive: TMenuItem Action = actTestArchive end object mnuFilesSplit: TMenuItem Action = actFileSpliter end object mnuFilesCombine: TMenuItem Action = actFileLinker end object mnuCheckSumCalc: TMenuItem Action = actCheckSumCalc end object mnuCheckSumVerify: TMenuItem Action = actCheckSumVerify end object miLine4: TMenuItem Caption = '-' end object miWipe: TMenuItem Action = actWipe end object miDelete: TMenuItem Action = actDelete end object miLine50: TMenuItem Caption = '-' end object miExit: TMenuItem Action = actExit end end object mnuMark: TMenuItem Caption = '&Mark' object mnuMarkSGroup: TMenuItem Action = actMarkPlus end object mnuMarkUGroup: TMenuItem Action = actMarkMinus end object mnuMarkSAll: TMenuItem Action = actMarkMarkAll end object mnuMarkUAll: TMenuItem Action = actMarkUnmarkAll end object mnuMarkInvert: TMenuItem Action = actMarkInvert end object mnuMarkCurrentExtension: TMenuItem Action = actMarkCurrentExtension end object mnuUnmarkCurrentExtension: TMenuItem Action = actUnmarkCurrentExtension end object miLine47: TMenuItem Caption = '-' end object mnuSaveSelection: TMenuItem Action = actSaveSelection end object mnuRestoreSelection: TMenuItem Action = actRestoreSelection end object mnuSaveSelectionToFile: TMenuItem Action = actSaveSelectionToFile end object mnuLoadSelectionFromFile: TMenuItem Action = actLoadSelectionFromFile end object mnuLoadSelectionFromClip: TMenuItem Action = actLoadSelectionFromClip end object miLine5: TMenuItem Caption = '-' end object miCopyNamesToClip: TMenuItem Action = actCopyNamesToClip end object miCopyFullNamesToClip: TMenuItem Action = actCopyFullNamesToClip end object miCopyFileDetailsToClip: TMenuItem Action = actCopyFileDetailsToClip end object miLine37: TMenuItem Caption = '-' end object miCompareDirectories: TMenuItem Action = actCompareDirectories end end object mnuCmd: TMenuItem Caption = '&Commands' object mnuCmdSearch: TMenuItem Action = actSearch end object mnuCmdAddNewSearch: TMenuItem Action = actAddNewSearch end object mnuCmdViewSearches: TMenuItem Action = actViewSearches end object mnuCmdDirHotlist: TMenuItem Action = actDirHotList end object mnuCmdSyncDirs: TMenuItem Action = actSyncDirs end object miLine6: TMenuItem Caption = '-' end object miRunTerm: TMenuItem Action = actRunTerm end object mnuDoAnyCmCommand: TMenuItem Action = actDoAnyCmCommand end object miLine9: TMenuItem Caption = '-' end object miFlatView: TMenuItem Action = actFlatView end object mnuOpenVFSList: TMenuItem Action = actOpenVirtualFileSystemList end object mnuCmdSwapSourceTarget: TMenuItem Action = actExchange end object mnuCmdTargetIsSource: TMenuItem Action = actTargetEqualSource end object miLine22: TMenuItem Caption = '-' end object mnuCountDirContent: TMenuItem Action = actCountDirContent end end object mnuNetwork: TMenuItem Caption = 'Network' object miNetworkConnect: TMenuItem Action = actNetworkConnect end object miNetworkQuickConnect: TMenuItem Action = actNetworkQuickConnect Visible = False end object miNetworkDisconnect: TMenuItem Action = actNetworkDisconnect Enabled = False end end object mnuTabs: TMenuItem Caption = '&Tabs' object mnuNewTab: TMenuItem Action = actNewTab end object mnuRenameTab: TMenuItem Action = actRenameTab end object mnuOpenDirInNewTab: TMenuItem Action = actOpenDirInNewTab end object miLine15: TMenuItem Caption = '-' end object mnuCloseTab: TMenuItem Action = actCloseTab end object mnuCloseAllTabs: TMenuItem Action = actCloseAllTabs end object mnuCloseDuplicateTabs: TMenuItem Action = actCloseDuplicateTabs end object miLine11: TMenuItem Caption = '-' end object mnuTabOptions: TMenuItem Caption = 'Tab &Options' object mnuTabOptionNormal: TMenuItem Action = actSetTabOptionNormal GroupIndex = 1 RadioItem = True end object mnuTabOptionPathLocked: TMenuItem Action = actSetTabOptionPathLocked GroupIndex = 1 RadioItem = True end object mnuTabOptionPathResets: TMenuItem Action = actSetTabOptionPathResets GroupIndex = 1 RadioItem = True end object mnuTabOptionDirsInNewTabs: TMenuItem Action = actSetTabOptionDirsInNewTab GroupIndex = 1 RadioItem = True end object miLine10: TMenuItem Caption = '-' end object mnuSetAllTabsOptionNormal: TMenuItem Action = actSetAllTabsOptionNormal end object mnuSetAllTabsOptionPathLocked: TMenuItem Action = actSetAllTabsOptionPathLocked end object mnuSetAllTabsOptionPathResets: TMenuItem Action = actSetAllTabsOptionPathResets end object mnuSetAllTabsOptionDirsInNewTab: TMenuItem Action = actSetAllTabsOptionDirsInNewTab end end object miLine17: TMenuItem Caption = '-' end object mnuNextTab: TMenuItem Action = actNextTab end object mnuPrevTab: TMenuItem Action = actPrevTab end object miLine38: TMenuItem Caption = '-' end object mnuSaveTabs: TMenuItem Action = actSaveTabs end object mnuLoadTabs: TMenuItem Action = actLoadTabs end object mnuSaveFavoriteTabs: TMenuItem Action = actSaveFavoriteTabs end object mnuLoadFavoriteTabs: TMenuItem Action = actLoadFavoriteTabs end object miLine39: TMenuItem Caption = '-' end object mnuConfigurationFolderTabs: TMenuItem Action = actConfigFolderTabs end object mnuConfigurationFavoriteTabs: TMenuItem Action = actConfigFavoriteTabs end end object mnuFavoriteTabs: TMenuItem Caption = 'Favorites' object mnuCreateNewFavoriteTabs: TMenuItem Action = actSaveFavoriteTabs end object mnuRewriteFavoriteTabs: TMenuItem Action = actResaveFavoriteTabs end object mnuReloadActiveFavoriteTabs: TMenuItem Action = actReloadFavoriteTabs end object mnuConfigureFavoriteTabs: TMenuItem Action = actConfigFavoriteTabs end end object mnuShow: TMenuItem Caption = '&Show' object mnuBriefView: TMenuItem Action = actBriefView end object mnuColumnsView: TMenuItem Action = actColumnsView end object mnuThumbnailsView: TMenuItem Action = actThumbnailsView end object miLine33: TMenuItem Caption = '-' end object mnuQuickView: TMenuItem Action = actQuickView end object mnuTreeView: TMenuItem Action = actTreeView end object miLine32: TMenuItem Caption = '-' end object mnuShowName: TMenuItem Action = actSortByName end object mnuShowExtension: TMenuItem Action = actSortByExt end object mnuShowSize: TMenuItem Action = actSortBySize end object mnuShowTime: TMenuItem Action = actSortByDate end object mnuShowAttrib: TMenuItem Action = actSortByAttr end object miLine7: TMenuItem Caption = '-' end object mnuShowReverse: TMenuItem Action = actReverseOrder end object mnuShowReread: TMenuItem Action = actRefresh end object miLine3: TMenuItem Caption = '-' end object mnuFilesShwSysFiles: TMenuItem Action = actShowSysFiles end object miLine20: TMenuItem Caption = '-' end object mnuShowHorizontalFilePanels: TMenuItem Action = actHorizontalFilePanels end object miLine13: TMenuItem Caption = '-' end object mnuShowOperations: TMenuItem Action = actOperationsViewer end end object mnuConfig: TMenuItem Caption = 'C&onfiguration' object mnuConfigOptions: TMenuItem Action = actOptions end object miLine40: TMenuItem Caption = '-' end object mnuCmdConfigDirHotlist: TMenuItem Action = actConfigDirHotList end object mnuConfigFavoriteTabs: TMenuItem Action = actConfigFavoriteTabs end object mnuFileAssoc: TMenuItem Action = actFileAssoc end object mnuConfigFolderTabs: TMenuItem Action = actConfigFolderTabs end object miConfigArchivers: TMenuItem Action = actConfigArchivers end object miLine55: TMenuItem Caption = '-' end object mnuConfigSavePos: TMenuItem Action = actConfigSavePos end object mnuConfigSaveSettings: TMenuItem Action = actConfigSaveSettings end end object mnuHelp: TMenuItem Caption = '&Help' object mnuHelpIndex: TMenuItem Action = actHelpIndex end object mnuHelpKeyboard: TMenuItem Action = actKeyboard end object mnuHelpVisitHomePage: TMenuItem Action = actVisitHomePage end object miLine18: TMenuItem Caption = '-' end object mnuHelpAbout: TMenuItem Action = actAbout end end object mnuAllOperProgress: TMenuItem RightJustify = True Visible = False OnClick = mnuAllOperProgressClick end object mnuAllOperStart: TMenuItem Caption = 'Start' RightJustify = True Visible = False OnClick = mnuAllOperStartClick end object mnuAllOperPause: TMenuItem Caption = '||' RightJustify = True Visible = False OnClick = mnuAllOperPauseClick end object mnuAllOperStop: TMenuItem Caption = 'Cancel' RightJustify = True Visible = False OnClick = mnuAllOperStopClick end end object actionLst: TActionList left = 320 top = 24 object actHorizontalFilePanels: TAction Tag = 16 Category = 'Window' Caption = '&Horizontal Panels Mode' GroupIndex = 5 OnExecute = actExecute end object actPanelsSplitterPerPos: TAction Tag = 16 Category = 'Window' Caption = 'Set splitter position' OnExecute = actExecute end object actView: TAction Tag = 4 Category = 'File Operations' Caption = 'View' HelpType = htKeyword OnExecute = actExecute end object actEdit: TAction Tag = 4 Category = 'File Operations' Caption = 'Edit' HelpType = htKeyword OnExecute = actExecute end object actHelpIndex: TAction Tag = 15 Category = 'Help' Caption = '&Contents' OnExecute = actExecute end object actKeyboard: TAction Tag = 15 Category = 'Help' Caption = '&Keyboard' OnExecute = actExecute end object actVisitHomePage: TAction Tag = 15 Category = 'Help' Caption = '&Visit Double Commander Website' OnExecute = actExecute end object actAbout: TAction Tag = 15 Category = 'Help' Caption = '&About' HelpType = htKeyword OnExecute = actExecute end object actOptions: TAction Tag = 5 Category = 'Configuration' Caption = '&Options...' HelpType = htKeyword OnExecute = actExecute end object actMultiRename: TAction Tag = 18 Category = 'Tools' Caption = 'Multi-&Rename Tool' HelpType = htKeyword OnExecute = actExecute end object actSearch: TAction Tag = 18 Category = 'Tools' Caption = '&Search...' HelpType = htKeyword OnExecute = actExecute end object actAddNewSearch: TAction Tag = 18 Category = 'Tools' Caption = 'New search instance...' HelpType = htKeyword OnExecute = actExecute end object actViewSearches: TAction Tag = 18 Category = 'Tools' Caption = 'View current search instances' HelpType = htKeyword OnExecute = actExecute end object actDeleteSearches: TAction Tag = 18 Category = 'Tools' Caption = 'For all searches, cancel, close and free memory' HelpType = htKeyword OnExecute = actExecute end object actSyncDirs: TAction Tag = 18 Category = 'Tools' Caption = 'Syn&chronize dirs...' HelpType = htKeyword OnExecute = actExecute end object actConfigToolbars: TAction Tag = 5 Category = 'Configuration' Caption = 'Toolbar...' OnExecute = actExecute end object actConfigDirHotList: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of Directory Hotlist' OnExecute = actExecute end object actWorkWithDirectoryHotlist: TAction Tag = 5 Category = 'Configuration' Caption = 'Work with Directory Hotlist and parameters' OnExecute = actExecute end object actFileAssoc: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of File &Associations' OnExecute = actExecute end object actCompareContents: TAction Tag = 18 Category = 'Tools' Caption = 'Compare by &Contents' HelpType = htKeyword OnExecute = actExecute end object actShowMainMenu: TAction Tag = 16 Category = 'Window' Caption = 'Menu' HelpType = htKeyword OnExecute = actExecute end object actShowButtonMenu: TAction Tag = 16 Category = 'Window' Caption = 'Show button menu' OnExecute = actExecute end object actOperationsViewer: TAction Tag = 16 Category = 'Window' Caption = 'Operations &Viewer' OnExecute = actExecute end object actRefresh: TAction Tag = 19 Category = 'View' Caption = '&Refresh' HelpType = htKeyword OnExecute = actExecute end object actShowSysFiles: TAction Tag = 19 Category = 'View' Caption = 'Show &Hidden/System Files' Checked = True GroupIndex = 2 HelpType = htKeyword OnExecute = actExecute end object actDirHistory: TAction Tag = 14 Category = 'Navigation' Caption = 'Directory history' HelpType = htKeyword OnExecute = actExecute end object actDirHotList: TAction Tag = 14 Category = 'Navigation' Caption = 'Directory &Hotlist' HelpType = htKeyword OnExecute = actExecute end object actMarkPlus: TAction Tag = 10 Category = 'Mark' Caption = 'Select a &Group...' HelpType = htKeyword OnExecute = actExecute end object actMarkMinus: TAction Tag = 10 Category = 'Mark' Caption = 'Unselect a Gro&up...' HelpType = htKeyword OnExecute = actExecute end object actMarkMarkAll: TAction Tag = 10 Category = 'Mark' Caption = '&Select All' HelpType = htKeyword OnExecute = actExecute end object actMarkUnmarkAll: TAction Tag = 10 Category = 'Mark' Caption = '&Unselect All' HelpType = htKeyword OnExecute = actExecute end object actCalculateSpace: TAction Tag = 7 Category = 'Miscellaneous' Caption = 'Calculate &Occupied Space' HelpType = htKeyword OnExecute = actExecute end object actBenchmark: TAction Tag = 7 Category = 'Miscellaneous' Caption = '&Benchmark' OnExecute = actExecute end object actNewTab: TAction Tag = 21 Category = 'Tabs' Caption = '&New Tab' HelpType = htKeyword OnExecute = actExecute end object actCutToClipboard: TAction Tag = 12 Category = 'Clipboard' Caption = 'Cu&t' OnExecute = actExecute end object actCopyToClipboard: TAction Tag = 12 Category = 'Clipboard' Caption = '&Copy' OnExecute = actExecute end object actPasteFromClipboard: TAction Tag = 12 Category = 'Clipboard' Caption = '&Paste' OnExecute = actExecute end object actRunTerm: TAction Tag = 7 Category = 'Miscellaneous' Caption = 'Run &Terminal' HelpType = htKeyword OnExecute = actExecute end object actMarkInvert: TAction Tag = 10 Category = 'Mark' Caption = '&Invert Selection' HelpType = htKeyword OnExecute = actExecute end object actMarkCurrentPath: TAction Tag = 10 Category = 'Mark' Caption = 'Select all in same path' OnExecute = actExecute end object actUnmarkCurrentPath: TAction Tag = 10 Category = 'Mark' Caption = 'Unselect all in same path' OnExecute = actExecute end object actMarkCurrentName: TAction Tag = 10 Category = 'Mark' Caption = 'Select all files with same name' OnExecute = actExecute end object actUnmarkCurrentName: TAction Tag = 10 Category = 'Mark' Caption = 'Unselect all files with same name' OnExecute = actExecute end object actMarkCurrentExtension: TAction Tag = 10 Category = 'Mark' Caption = 'Select All with the Same E&xtension' OnExecute = actExecute end object actUnmarkCurrentExtension: TAction Tag = 10 Category = 'Mark' Caption = 'Unselect All with the Same Ex&tension' OnExecute = actExecute end object actMarkCurrentNameExt: TAction Tag = 10 Category = 'Mark' Caption = 'Select all files with same name and extension' OnExecute = actExecute end object actUnmarkCurrentNameExt: TAction Tag = 10 Category = 'Mark' Caption = 'Unselect all files with same name and extension' OnExecute = actExecute end object actCompareDirectories: TAction Tag = 10 Category = 'Mark' Caption = 'Compare Directories' Hint = 'Compare Directories' OnExecute = actExecute end object actEditNew: TAction Tag = 4 Category = 'File Operations' Caption = 'Edit new file' HelpType = htKeyword OnExecute = actExecute end object actCopy: TAction Tag = 4 Category = 'File Operations' Caption = 'Copy' HelpType = htKeyword OnExecute = actExecute end object actCopyNoAsk: TAction Tag = 4 Category = 'File Operations' Caption = 'Copy files without asking for confirmation' OnExecute = actExecute end object actCopySamePanel: TAction Tag = 4 Category = 'File Operations' Caption = 'Copy to same panel' HelpType = htKeyword OnExecute = actExecute end object actRename: TAction Tag = 4 Category = 'File Operations' Caption = 'Move' HelpType = htKeyword OnExecute = actExecute end object actRenameNoAsk: TAction Tag = 4 Category = 'File Operations' Caption = 'Move/Rename files without asking for confirmation' OnExecute = actExecute end object actRenameOnly: TAction Tag = 4 Category = 'File Operations' Caption = 'Rename' HelpType = htKeyword OnExecute = actExecute end object actMakeDir: TAction Tag = 4 Category = 'File Operations' Caption = 'Create &Directory' HelpType = htKeyword OnExecute = actExecute end object actDelete: TAction Tag = 4 Category = 'File Operations' Caption = 'Delete' HelpType = htKeyword OnExecute = actExecute end object actWipe: TAction Tag = 4 Category = 'File Operations' Caption = 'Wipe' OnExecute = actExecute end object actPackFiles: TAction Tag = 4 Category = 'File Operations' Caption = '&Pack Files...' OnExecute = actExecute end object actTestArchive: TAction Tag = 4 Category = 'File Operations' Caption = '&Test Archive(s)' OnExecute = actExecute end object actOpenArchive: TAction Tag = 4 Category = 'File Operations' Caption = 'Try open archive' OnExecute = actExecute end object actExtractFiles: TAction Tag = 4 Category = 'File Operations' Caption = '&Extract Files...' OnExecute = actExecute end object actOpenVirtualFileSystemList: TAction Tag = 4 Category = 'File Operations' Caption = 'Open &VFS List' OnExecute = actExecute end object actFileProperties: TAction Tag = 4 Category = 'File Operations' Caption = 'Show &File Properties' HelpType = htKeyword OnExecute = actExecute end object actOpenDirInNewTab: TAction Tag = 21 Category = 'Tabs' Caption = 'Open &Folder in a New Tab' OnExecute = actExecute end object actNextTab: TAction Tag = 21 Category = 'Tabs' Caption = 'Switch to Nex&t Tab' OnExecute = actExecute end object actPrevTab: TAction Tag = 21 Category = 'Tabs' Caption = 'Switch to &Previous Tab' OnExecute = actExecute end object actMoveTabLeft: TAction Tag = 21 Category = 'Tabs' Caption = 'Move current tab to the left' OnExecute = actExecute end object actMoveTabRight: TAction Tag = 21 Category = 'Tabs' Caption = 'Move current tab to the right' OnExecute = actExecute end object actSwitchIgnoreList: TAction Tag = 19 Category = 'View' Caption = 'Enable/disable ignore list file to not show file names' GroupIndex = 4 OnExecute = actExecute end object actCopyNamesToClip: TAction Tag = 12 Category = 'Clipboard' Caption = 'Copy &Filename(s) to Clipboard' OnExecute = actExecute end object actCopyFullNamesToClip: TAction Tag = 12 Category = 'Clipboard' Caption = 'Copy Filename(s) with Full &Path' OnExecute = actExecute end object actSaveSelection: TAction Tag = 10 Category = 'Mark' Caption = 'Sa&ve Selection' OnExecute = actExecute end object actRestoreSelection: TAction Tag = 10 Category = 'Mark' Caption = '&Restore Selection' OnExecute = actExecute end object actSaveSelectionToFile: TAction Tag = 10 Category = 'Mark' Caption = 'Save S&election to File...' OnExecute = actExecute end object actLoadSelectionFromFile: TAction Tag = 10 Category = 'Mark' Caption = '&Load Selection from File...' OnExecute = actExecute end object actLoadSelectionFromClip: TAction Tag = 10 Category = 'Mark' Caption = 'Load Selection from Clip&board' OnExecute = actExecute end object actNetworkConnect: TAction Tag = 6 Category = 'Network' Caption = 'Network &Connect...' OnExecute = actExecute end object actNetworkQuickConnect: TAction Tag = 6 Category = 'Network' Caption = 'Network &Quick Connect...' OnExecute = actExecute end object actNetworkDisconnect: TAction Tag = 6 Category = 'Network' Caption = 'Network &Disconnect' OnExecute = actExecute end object actCopyNetNamesToClip: TAction Tag = 6 Category = 'Network' Caption = 'Copy names with UNC path' OnExecute = actExecute end object actCopyPathOfFilesToClip: TAction Tag = 12 Category = 'Clipboard' Caption = 'Copy Full Path of selected file(s)' OnExecute = actExecute end object actCopyPathNoSepOfFilesToClip: TAction Tag = 12 Category = 'Clipboard' Caption = 'Copy Full Path of selected file(s) with no ending dir separator' OnExecute = actExecute end object actCopyFileDetailsToClip: TAction Tag = 12 Category = 'Clipboard' Caption = 'Copy all shown &columns' OnExecute = actExecute end object actRenameTab: TAction Tag = 21 Category = 'Tabs' Caption = '&Rename Tab' OnExecute = actExecute end object actLeftBriefView: TAction Tag = 2 Category = 'Left Panel' Caption = 'Brief view on left panel' OnExecute = actExecute end object actLeftColumnsView: TAction Tag = 2 Category = 'Left Panel' Caption = 'Columns view on left panel' OnExecute = actExecute end object actLeftThumbView: TAction Tag = 2 Category = 'Left Panel' Caption = 'Thumbnails view on left panel' OnExecute = actExecute end object actLeftFlatView: TAction Tag = 2 Category = 'Left Panel' Caption = '&Flat view on left panel' OnExecute = actExecute end object actLeftSortByName: TAction Tag = 2 Category = 'Left Panel' Caption = 'Sort left panel by &Name' OnExecute = actExecute end object actLeftSortByExt: TAction Tag = 2 Category = 'Left Panel' Caption = 'Sort left panel by &Extension' OnExecute = actExecute end object actLeftSortBySize: TAction Tag = 2 Category = 'Left Panel' Caption = 'Sort left panel by &Size' OnExecute = actExecute end object actLeftSortByDate: TAction Tag = 2 Category = 'Left Panel' Caption = 'Sort left panel by &Date' OnExecute = actExecute end object actLeftSortByAttr: TAction Tag = 2 Category = 'Left Panel' Caption = 'Sort left panel by &Attributes' OnExecute = actExecute end object actLeftReverseOrder: TAction Tag = 2 Category = 'Left Panel' Caption = 'Re&verse order on left panel' OnExecute = actExecute end object actLeftOpenDrives: TAction Tag = 2 Category = 'Left Panel' Caption = 'Open left drive list' OnExecute = actExecute end object actRightBriefView: TAction Tag = 3 Category = 'Right Panel' Caption = 'Brief view on right panel' OnExecute = actExecute end object actRightColumnsView: TAction Tag = 3 Category = 'Right Panel' Caption = 'Columns view on right panel' OnExecute = actExecute end object actRightThumbView: TAction Tag = 3 Category = 'Right Panel' Caption = 'Thumbnails view on right panel' OnExecute = actExecute end object actRightFlatView: TAction Tag = 3 Category = 'Right Panel' Caption = '&Flat view on right panel' OnExecute = actExecute end object actRightSortByName: TAction Tag = 3 Category = 'Right Panel' Caption = 'Sort right panel by &Name' OnExecute = actExecute end object actRightSortByExt: TAction Tag = 3 Category = 'Right Panel' Caption = 'Sort right panel by &Extension' OnExecute = actExecute end object actRightSortBySize: TAction Tag = 3 Category = 'Right Panel' Caption = 'Sort right panel by &Size' OnExecute = actExecute end object actRightSortByDate: TAction Tag = 3 Category = 'Right Panel' Caption = 'Sort right panel by &Date' OnExecute = actExecute end object actRightSortByAttr: TAction Tag = 3 Category = 'Right Panel' Caption = 'Sort right panel by &Attributes' OnExecute = actExecute end object actRightReverseOrder: TAction Tag = 3 Category = 'Right Panel' Caption = 'Re&verse order on right panel' OnExecute = actExecute end object actRightOpenDrives: TAction Tag = 3 Category = 'Right Panel' Caption = 'Open right drive list' OnExecute = actExecute end object actFocusCmdLine: TAction Tag = 17 Category = 'Command Line' Caption = 'Focus command line' OnExecute = actExecute end object actShowCmdLineHistory: TAction Tag = 17 Category = 'Command Line' Caption = 'Show command line history' HelpType = htKeyword OnExecute = actExecute end object actSyncChangeDir: TAction Tag = 14 Category = 'Navigation' Caption = 'Synchronous navigation' Hint = 'Synchronous directory changing in both panels' GroupIndex = 7 OnExecute = actExecute end object actChangeDirToParent: TAction Tag = 14 Category = 'Navigation' Caption = 'Change Directory To Parent' OnExecute = actExecute end object actChangeDirToHome: TAction Tag = 14 Category = 'Navigation' Caption = 'Change directory to home' OnExecute = actExecute end object actChangeDirToRoot: TAction Tag = 14 Category = 'Navigation' Caption = 'Change directory to root' OnExecute = actExecute end object actTargetEqualSource: TAction Tag = 14 Category = 'Navigation' Caption = 'Target &= Source' OnExecute = actExecute end object actTransferLeft: TAction Tag = 14 Category = 'Navigation' Caption = 'Transfer dir under cursor to left window' OnExecute = actExecute end object actTransferRight: TAction Tag = 14 Category = 'Navigation' Caption = 'Transfer dir under cursor to right window' OnExecute = actExecute end object actLeftEqualRight: TAction Tag = 14 Category = 'Navigation' Caption = 'Left &= Right' OnExecute = actExecute end object actRightEqualLeft: TAction Tag = 14 Category = 'Navigation' Caption = 'Right &= Left' OnExecute = actExecute end object actBriefView: TAction Tag = 1 Category = 'Active Panel' AutoCheck = True Caption = 'Brief view' GroupIndex = 6 Hint = 'Brief View' OnExecute = actExecute end object actColumnsView: TAction Tag = 1 Category = 'Active Panel' AutoCheck = True Caption = 'Full' GroupIndex = 6 Hint = 'Columns View' OnExecute = actExecute end object actThumbnailsView: TAction Tag = 1 Category = 'Active Panel' AutoCheck = True Caption = 'Thumbnails' GroupIndex = 6 Hint = 'Thumbnails View' OnExecute = actExecute end object actFlatView: TAction Tag = 1 Category = 'Active Panel' Caption = '&Flat view' OnExecute = actExecute end object actFlatViewSel: TAction Tag = 1 Category = 'Active Panel' Caption = '&Flat view, only selected' OnExecute = actExecute end object actQuickView: TAction Tag = 1 Category = 'Active Panel' Caption = '&Quick View Panel' GroupIndex = 1 OnExecute = actExecute end object actSortByName: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sort by &Name' HelpType = htKeyword OnExecute = actExecute end object actSortByExt: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sort by &Extension' HelpType = htKeyword OnExecute = actExecute end object actSortBySize: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sort by &Size' HelpType = htKeyword OnExecute = actExecute end object actSortByDate: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sort by &Date' HelpType = htKeyword OnExecute = actExecute end object actSortByAttr: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sort by &Attributes' HelpType = htKeyword OnExecute = actExecute end object actReverseOrder: TAction Tag = 1 Category = 'Active Panel' Caption = 'Re&verse Order' HelpType = htKeyword OnExecute = actExecute end object actSrcOpenDrives: TAction Tag = 1 Category = 'Active Panel' Caption = 'Open drive list' OnExecute = actExecute end object actExchange: TAction Tag = 14 Category = 'Navigation' Caption = 'Swap &Panels' OnExecute = actExecute end object actQuickSearch: TAction Tag = 14 Category = 'Navigation' Caption = 'Quick search' OnExecute = actExecute end object actViewLogFile: TAction Tag = 23 Category = 'Log' Caption = 'View log file' OnExecute = actExecute end object actClearLogFile: TAction Tag = 23 Category = 'Log' Caption = 'Clear log file' OnExecute = actExecute end object actClearLogWindow: TAction Tag = 23 Category = 'Log' Caption = 'Clear log window' OnExecute = actExecute end object actQuickFilter: TAction Tag = 14 Category = 'Navigation' Caption = 'Quick filter' OnExecute = actExecute end object actEditPath: TAction Tag = 14 Category = 'Navigation' Caption = 'Edit path field above file list' OnExecute = actExecute end object actChangeDir: TAction Tag = 14 Category = 'Navigation' Caption = 'Change directory' OnExecute = actExecute end object actCmdLineNext: TAction Tag = 17 Category = 'Command Line' Caption = 'Next Command Line' Hint = 'Set command line to next command in history' OnExecute = actExecute end object actCmdLinePrev: TAction Tag = 17 Category = 'Command Line' Caption = 'Previous Command Line' Hint = 'Set command line to previous command in history' OnExecute = actExecute end object actAddPathToCmdLine: TAction Tag = 17 Category = 'Command Line' Caption = 'Copy path to command line' OnExecute = actExecute end object actAddFilenameToCmdLine: TAction Tag = 17 Category = 'Command Line' Caption = 'Add file name to command line' OnExecute = actExecute end object actAddPathAndFilenameToCmdLine: TAction Tag = 17 Category = 'Command Line' Caption = 'Add path and file name to command line' OnExecute = actExecute end object actGoToFirstEntry: TAction Tag = 14 Category = 'Navigation' Caption = 'Place cursor on first folder or file' OnExecute = actExecute end object actGoToLastEntry: TAction Tag = 14 Category = 'Navigation' Caption = 'Place cursor on last folder or file' OnExecute = actExecute end object actGoToNextEntry: TAction Tag = 14 Category = 'Navigation' Caption = 'Place cursor on next folder or file' OnExecute = actExecute end object actGoToPrevEntry: TAction Tag = 14 Category = 'Navigation' Caption = 'Place cursor on previous folder or file' OnExecute = actExecute end object actGoToFirstFile: TAction Tag = 14 Category = 'Navigation' Caption = 'Place cursor on first file in list' OnExecute = actExecute end object actGoToLastFile: TAction Tag = 14 Category = 'Navigation' Caption = 'Place cursor on last file in list' OnExecute = actExecute end object actViewHistory: TAction Tag = 14 Category = 'Navigation' Caption = 'Show history of visited paths for active view' OnExecute = actExecute end object actViewHistoryNext: TAction Tag = 14 Category = 'Navigation' Caption = 'Go to next entry in history' OnExecute = actExecute end object actViewHistoryPrev: TAction Tag = 14 Category = 'Navigation' Caption = 'Go to previous entry in history' OnExecute = actExecute end object actOpenDriveByIndex: TAction Tag = 14 Category = 'Navigation' Caption = 'Open Drive by Index' OnExecute = actExecute end object actOpenBar: TAction Tag = 16 Category = 'Window' Caption = 'Open bar file' OnExecute = actExecute end object actMinimize: TAction Tag = 16 Category = 'Window' Caption = 'Minimize window' OnExecute = actExecute end object actExit: TAction Tag = 16 Category = 'Window' Caption = 'E&xit' HelpType = htKeyword OnExecute = actExecute end object actDebugShowCommandParameters: TAction Tag = 18 Category = 'Tools' Caption = 'Show Command Parameters' OnExecute = actExecute end object actDoAnyCmCommand: TAction Tag = 18 Category = 'Tools' Caption = 'Execute &internal command...' Hint = 'Select any command and execute it' OnExecute = actExecute end object actSetFileProperties: TAction Tag = 4 Category = 'File Operations' Caption = 'Change &Attributes...' OnExecute = actExecute end object actEditComment: TAction Tag = 4 Category = 'File Operations' Caption = 'Edit Co&mment...' OnExecute = actExecute end object actContextMenu: TAction Tag = 4 Category = 'File Operations' Caption = 'Show context menu' OnExecute = actExecute end object actOpen: TAction Tag = 4 Category = 'File Operations' Caption = 'Open' OnExecute = actExecute end object actShellExecute: TAction Tag = 4 Category = 'File Operations' Caption = 'Open' Hint = 'Open using system associations' OnExecute = actExecute end object actSymLink: TAction Tag = 4 Category = 'File Operations' Caption = 'Create Symbolic &Link...' HelpType = htKeyword OnExecute = actExecute end object actHardLink: TAction Tag = 4 Category = 'File Operations' Caption = 'Create &Hard Link...' HelpType = htKeyword OnExecute = actExecute end object actFileSpliter: TAction Tag = 4 Category = 'File Operations' Caption = 'Spl&it File...' HelpType = htKeyword OnExecute = actExecute end object actFileLinker: TAction Tag = 4 Category = 'File Operations' Caption = 'Com&bine Files...' HelpType = htKeyword OnExecute = actExecute end object actCheckSumCalc: TAction Tag = 4 Category = 'File Operations' Caption = 'Calculate Check&sum...' OnExecute = actExecute end object actCheckSumVerify: TAction Tag = 4 Category = 'File Operations' Caption = '&Verify Checksum...' OnExecute = actExecute end object actUniversalSingleDirectSort: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sort according to parameters' OnExecute = actExecute end object actCountDirContent: TAction Tag = 1 Category = 'Active Panel' Caption = 'Sho&w Occupied Space' OnExecute = actExecute end object actToggleFullscreenConsole: TAction Tag = 17 Category = 'Command Line' Caption = 'Toggle fullscreen mode console' OnExecute = actExecute end object actTreeView: TAction Tag = 16 Category = 'Window' Caption = '&Tree View Panel' GroupIndex = 3 OnExecute = actExecute end object actFocusTreeView: TAction Tag = 16 Category = 'Window' Caption = 'Focus on tree view' Hint = 'Switch between current file list and tree view (if enabled)' OnExecute = actExecute end object actConfigFolderTabs: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of folder tabs' OnExecute = actExecute end object actConfigFavoriteTabs: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of Favorite Tabs' OnExecute = actExecute end object actCloseTab: TAction Tag = 21 Category = 'Tabs' Caption = '&Close Tab' HelpType = htKeyword OnExecute = actExecute end object actCloseAllTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Close &All Tabs' OnExecute = actExecute end object actCloseDuplicateTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Close Duplicate Tabs' OnExecute = actExecute end object actCopyAllTabsToOpposite: TAction Tag = 21 Category = 'Tabs' Caption = 'Copy all tabs to opposite side' OnExecute = actExecute end object actLoadTabs: TAction Tag = 21 Category = 'Tabs' Caption = '&Load Tabs from File' OnExecute = actExecute end object actSaveTabs: TAction Tag = 21 Category = 'Tabs' Caption = '&Save Tabs to File' OnExecute = actExecute end object actSetTabOptionNormal: TAction Tag = 21 Category = 'Tabs' Caption = '&Normal' OnExecute = actExecute end object actSetTabOptionPathLocked: TAction Tag = 21 Category = 'Tabs' Caption = '&Locked' OnExecute = actExecute end object actSetTabOptionPathResets: TAction Tag = 21 Category = 'Tabs' Caption = 'Locked with &Directory Changes Allowed' OnExecute = actExecute end object actSetTabOptionDirsInNewTab: TAction Tag = 21 Category = 'Tabs' Caption = 'Locked with Directories Opened in New &Tabs' OnExecute = actExecute end object actSetAllTabsOptionNormal: TAction Tag = 21 Category = 'Tabs' Caption = 'Set all tabs to Normal' OnExecute = actExecute end object actSetAllTabsOptionPathLocked: TAction Tag = 21 Category = 'Tabs' Caption = 'Set all tabs to Locked' OnExecute = actExecute end object actSetAllTabsOptionPathResets: TAction Tag = 21 Category = 'Tabs' Caption = 'All tabs Locked with Dir Changes Allowed' OnExecute = actExecute end object actSetAllTabsOptionDirsInNewTab: TAction Tag = 21 Category = 'Tabs' Caption = 'All tabs Locked with Dir Opened in New Tabs' OnExecute = actExecute end object actLoadFavoriteTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Load tabs from Favorite Tabs' OnExecute = actExecute end object actSaveFavoriteTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Save current tabs to a New Favorite Tabs' OnExecute = actExecute end object actReloadFavoriteTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Reload the last Favorite Tabs loaded' OnExecute = actExecute end object actResaveFavoriteTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Resave on the last Favorite Tabs loaded' OnExecute = actExecute end object actPreviousFavoriteTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Load the Previous Favorite Tabs in the list' OnExecute = actExecute end object actNextFavoriteTabs: TAction Tag = 21 Category = 'Tabs' Caption = 'Load the Next Favorite Tabs in the list' OnExecute = actExecute end object actActivateTabByIndex: TAction Tag = 21 Category = 'Tabs' Caption = 'Activate Tab By Index' OnExecute = actExecute end object actConfigTreeViewMenus: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of Tree View Menu' OnExecute = actExecute end object actConfigTreeViewMenusColors: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of Tree View Menu Colors' OnExecute = actExecute end object actConfigSearches: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of searches' HelpType = htKeyword OnExecute = actExecute end object actConfigHotKeys: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of hot keys' HelpType = htKeyword OnExecute = actExecute end object actConfigSavePos: TAction Tag = 5 Category = 'Configuration' Caption = 'Save Position' OnExecute = actExecute end object actConfigSaveSettings: TAction Tag = 5 Category = 'Configuration' Caption = 'Save Settings' OnExecute = actExecute end object actExecuteScript: TAction Tag = 7 Category = 'Miscellaneous' Caption = 'Execute Script' OnExecute = actExecute end object actFocusSwap: TAction Tag = 14 Category = 'Navigation' Caption = 'Swap focus' Hint = 'Switch between left and right file list' OnExecute = actExecute end object actConfigArchivers: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of Archivers' OnExecute = actExecute end object actConfigTooltips: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of tooltips' OnExecute = actExecute end object actConfigPlugins: TAction Tag = 5 Category = 'Configuration' Caption = 'Configuration of Plugins' OnExecute = actExecute end object actAddPlugin: TAction Tag = 5 Category = 'Configuration' Caption = 'Add Plugin' OnExecute = actExecute end object actLoadList: TAction Tag = 7 Category = 'Miscellaneous' Caption = 'Load List' Hint = 'Load list of files/folders from the specified text file' OnExecute = actExecute end object actSaveFileDetailsToFile: TAction Tag = 10 Category = 'Mark' Caption = 'Save all shown columns to file' OnExecute = actExecute end object actShowTabsList: TAction Tag = 21 Category = 'Tabs' Caption = 'Show Tabs List' Hint = 'Show list of all open tabs' OnExecute = actExecute end end object pmHotList: TPopupMenu Images = imgLstDirectoryHotlist left = 128 top = 88 end object pmDirHistory: TPopupMenu AutoPopup = False left = 184 top = 104 end object pmToolBar: TPopupMenu OnPopup = pmToolBarPopup left = 48 top = 152 object tbEdit: TMenuItem Caption = 'Edit' OnClick = tbEditClick end object tbDelete: TMenuItem Caption = 'Delete' OnClick = tbDeleteClick end object tbChangeDir: TMenuItem Caption = 'CD' OnClick = tbChangeDirClick end object tbSeparator: TMenuItem Caption = '-' Visible = False end object tbCut: TMenuItem Caption = 'Cut' Visible = False OnClick = tbCopyClick end object tbCopy: TMenuItem Caption = 'Copy' Visible = False OnClick = tbCopyClick end object tbPaste: TMenuItem Caption = 'Paste' Visible = False OnClick = tbPasteClick end end object pmContextMenu: TPopupMenu left = 40 top = 96 object mnuContextOpen: TMenuItem Action = actOpen end object mnuContextView: TMenuItem Action = actView end object mnuContextLine1: TMenuItem Caption = '-' end object mnuContextCopy: TMenuItem Action = actCopy end object mnuContextRenameOnly: TMenuItem Action = actRenameOnly end object mnuContextDelete: TMenuItem Action = actDelete end object mnuContextLine2: TMenuItem Caption = '-' end object mnuContextFileProperties: TMenuItem Action = actFileProperties end end object pmColumnsMenu: TPopupMenu left = 344 top = 144 object MenuItem2: TMenuItem Caption = '-' end end object pmSplitterPercent: TPopupMenu left = 312 top = 96 object mi2080: TMenuItem Tag = 20 Caption = '&20/80' OnClick = mnuSplitterPercentClick end object mi3070: TMenuItem Tag = 30 Caption = '&30/70' OnClick = mnuSplitterPercentClick end object mi4060: TMenuItem Tag = 40 Caption = '&40/60' OnClick = mnuSplitterPercentClick end object mi5050: TMenuItem Tag = 50 Caption = '&50/50' OnClick = mnuSplitterPercentClick end object mi6040: TMenuItem Tag = 60 Caption = '&60/40' OnClick = mnuSplitterPercentClick end object mi7030: TMenuItem Tag = 70 Caption = '&70/30' OnClick = mnuSplitterPercentClick end object mi8020: TMenuItem Tag = 80 Caption = '&80/20' OnClick = mnuSplitterPercentClick end end object pmDropMenu: TPopupMenu left = 384 top = 72 object miCopy: TMenuItem Caption = 'Copy...' OnClick = mnuDropClick end object miMove: TMenuItem Caption = 'Move...' OnClick = mnuDropClick end object miHardLink: TMenuItem Caption = 'Create link...' OnClick = mnuDropClick end object miSymLink: TMenuItem Caption = 'Create symlink...' OnClick = mnuDropClick end object miLine12: TMenuItem Caption = '-' end object miCancel: TMenuItem Caption = 'Cancel' OnClick = mnuDropClick end end object MainTrayIcon: TTrayIcon PopUpMenu = pmTrayIconMenu Icon.Data = { 267D000000000100040010100000010020006804000046000000202000000100 2000A8100000AE0400003030000001002000A825000056150000404000000100 200028420000FE3A000028000000100000002000000001002000000000004004 00000000000000000000000000000000000000000000BCA3A51A8182BB517E82 C1586E72B94F6D70B64F6C6DB34F6B6BB14F6A68AE4F6966AB4F6764A84F736D AB57837CB1677A72AB607B6D9E3EFEEDD506B7A4B60D4F6BDAE62653E6FE234B DEFE2046D7FE1D3FD1FE1A39CAFE1834C4FE142EBEFE1228B8FE0F23B2FE0D1C ABFE0A17A4FF06109EFE050C97FE594F997BCECFD296BEC6DBFEB1BAD9FE889A D9FF2F52D7FF193ED2FF1939CCFF1634C6FF132DBFFF1127B9FF0E22B3FF0314 AAFF444EB3FF9295C4FFB1B2CCFFC2C2CFF7D1D0D0ABD7D7D5FFD6D6D5FFD6D6 D5FFD9D9D4FF4963D0FF1738CCFF1634C6FF132DBFFF1127B9FF0E22B3FF848B C5FFDBDBD7FFD6D6D5FFD7D7D6FED7D7D6FFAFB5D15A6A87E1FB8B9DD6FFD9D7 D2FFD3D3D3FFD1D1D2FF3F58CBFF1634C6FF132DBFFF0B22B8FF9299C8FFD7D6 D4FFD3D3D3FFC1C2CEFF5D62B1FF6868B0D69AA7E3344B72EDF92C58E9FF375C DDFFBFC2D0FFD0D0D0FFAAB0CAFF0D2DC6FF132DBFFF3245BDFFCECECFFFD3D3 D1FF9A9DC2FF040F9EFF000697FF2B2DA1C3A3ADE1366D8CF0F9577AECFF3E62 E3FF6D83D6FFCECECCFFD7D6CCFF2741C3FF122CBFFF616FC0FFCDCDCCFFC4C4 CAFF0514A5FF0712A0FF070E9AFF3334A3C4A3ADE1366D8CF0F96988EEFF6482 E9FF6F86DEFFCDCCCAFFD1D0CAFF5C6DC7FF213AC4FF8991C4FFCBCBCAFF9EA2 C3FF1C29ADFF222CAAFF2B32A9FF5858B3C4A3ADE1366D8CF0F96888EEFF6684 EAFF7E92E0FFD8D7D5FFDCDBD6FF7686D1FF596CD3FF9DA4CEFFD6D6D6FFB8BB D0FF545EC1FF555DBDFF5359BAFF6B6CBCC4A3ADE1366D8CF0F96888EEFF6583 EAFFAFBAE1FFE5E5E5FFE6E5E1FF596FD7FF5C6FD3FF8690D2FFE5E5E5FFE9E8 E5FF5F69C0FF525ABDFF5157B9FF6B6BBBC498A4E72F6687F1F96887EBFFA7B4 E3FFE6E6E5FFE6E6E6FFA5AFDCFF5D72D8FF5D6FD3FF6371CEFFE0E0E3FFE6E6 E6FFDBDCE1FF7A7FC4FF484EB5FF605FB4C2D9D9DC9CD8DAE1FFEAE8E3FFE7E7 E6FFE7E7E6FFD5D7E2FF677BDBFF5F74D8FF5D6FD3FF5A69CFFF7681CBFFE6E6 E5FFE6E6E6FFEBEBE8FFE6E6E3FFD7D8DEF9E0E0E0ABE8E8E8FFE9E9E8FFEEED E9FFB6BFE0FF677FE0FF6076DCFF5F74D8FF5D6FD3FF5B6BCFFF5866CBFF6F79 C9FFDBDCE0FFEEEDEAFFE9E9E8FEE8E8E8FFCECCD36EAFBDE9FD9BADE7FE768F E6FF5F7AE5FF627BE0FF6176DCFF5F74D8FF5C6FD3FF5B6BCFFF5866CBFF5662 C6FF4F59C0FF777DC4FF9699CBFFB5B2CCDEFFF0D5098283BBCA718EEFFC6683 E8FB6A82E4FB687FE0FB667ADCFB6478D7FB6373D3FB6170CEFB5F6CCBFB5C66 C5FB5660C0FB555CBCFB6A6CBDF9998DB15200000000FFFFFF0399839924917C 962A907B962A8F7B942A8F7A942A8F79942A8E79942A8E78932A8E78922A8F77 922A8F77922A8E76912A9D83921F000000008000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF8001FFFF2800000020000000400000000100 2000000000008010000000000000000000000000000000000000000000000000 000000000000FFFFFF03FFFFFF07FFFFFF0BFFFFFF14FFFFFF09FFFFFF07FFFF FF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFF FF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF0CFFFFFF1AFFFFFF1CFFFF FF1CFFFFFF17FFFFFF0AFFFFFF04000000000000000000000000000000000000 0000FFFFFF10E1D6D55362456CBA584273D6594374DD584175D3563F73D2563E 72D2553E71D2543D70D2543C70D2543B6ED2533B6ED2533A6DD2533A6DD25338 6BD252396BD252386AD252376AD2513669D253386AD5513262E6513262E85132 61E8503161E4533563CA89729187FFFFFF2BFCFCFC040000000000000000FFFF FF08948BB17F5263C1FF3E66E8FF315DEBFF2C58E7FF2B54E4FF2A51E1FF284E DDFF264BDAFF2448D7FF2345D4FF2242D0FF2140CDFF1F3DCAFF1E39C7FF1C36 C4FF1B33C1FF1A31BEFF192EBBFF172BB7FF1527B3FF1425B1FF1322AEFF121F ABFF101CA8FF141EA5FF191A92FF45357FE4FEF6EE3AFFFFFF0200000000FFFF FF22546BD1F12C5AEBFE2754E8FF224FE4FF224BE1FF2149DEFF1E45DAFF1D43 D6FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0C1FB0FF0A1CACFF0A19A9FF0816A5FF0613 A2FF040F9FFF010A9BFF020A98FF0B139DFF453075C7FFFFFF0ECACACA4EDBDB DBE7C5C9D8FFC0C5D7FFB7BED6FF8598D7FF395DDCFF1842DFFF1E45DAFF1D43 D6FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0C1FB0FF0A1CACFF0A19A9FF0615A5FF000C A0FF434BACFF9395C1FFB7B8CAFFBDBECFFFC7C6D1FDD6D6D6E3C8C8C858D7D7 D7FFD7D7D7FFD7D7D7FFD8D8D7FFDCDBD8FFE1DED5FFB3BAD4FF5873D6FF1940 D6FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0C1FB0FF081AABFF0F1DA8FF7077BCFFCECE D4FFE2E2DBFFDADAD8FFD8D8D7FFD7D7D7FFD7D7D7FFD4D4D4FFC8C8C858D5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD7D6D6FF9FA9 D1FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0B1FB0FF2D3BB0FFD7D8D9FFD6D6D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD3D3D3FFC7C7C758D3D3 D3FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD8D7 D4FFBBBFD2FF1F40CFFF193ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0B20B3FF5662B9FFD4D4D5FFD4D4D4FFD4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD2D2D2FFC8C8C84BD1CF D0E9BBC3D9FFBDC2D4FFCCCDD1FFD8D7D3FFD4D3D3FFD3D3D3FFD3D3D3FFD3D3 D3FFD5D5D4FFB1B6CCFF193ACBFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0D24B6FF2E3FB6FFD3D4D5FFD2D3D3FFD3D3D3FFD3D3D3FFD3D3 D3FFD5D5D4FFD8D8D5FFC2C2CEFFB4B5CAFFB6B7CAFDD3D3D2DBFFFFFF05BAA4 AD75426DF1FF3461EBFF2E5AE8FF5874D4FFCECFD1FFD2D2D2FFD2D2D2FFD2D2 D2FFD2D2D2FFD3D2D2FF8491CAFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0A21B4FFCECFD2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD3D3 D2FFAAACC6FF1D259FFF070F9AFF030996FF181B9CF4FAEEE322FFFFFF04B9A2 AD734B75F2FF3B66ECFF315CE8FF2753E6FF2750DEFF96A3D1FFD1D1D0FFD0D0 D0FFD0D0D0FFD0D0D0FFCDCDCDFF2240C7FF1534C6FF1431C3FF132EC0FF112B BDFF1027BAFF737EC3FFD3D3D1FFD0D0D0FFD0D0D0FFD0D0D0FFD7D6D1FF5961 B3FF000B9DFF020C9CFF030B99FF000695FF161A9BF4FFF4E71FFFFFFF04B7A1 AD735F84F3FF4971EDFF3C65E9FF325BE5FF2B54E2FF2049DEFFB5BACEFFD0CF CEFFCECECEFFCECECEFFD2D2CFFF848FC1FF1130C7FF1431C3FF132EC0FF112B BDFF0F26B9FFB6B9CBFFCECECEFFCECECEFFCECECEFFD0CFCFFF6067B4FF0411 A2FF05109FFF030D9CFF030B99FF010795FF171A9BF4FFF4E71FFFFFFF04B7A0 AC736D8FF5FF6384EFFF5074EBFF4268E7FF365DE3FF2E55E0FF3256DAFFC8C9 CCFFCDCDCDFFCDCDCDFFCDCDCDFFC4C4C6FF1C39C5FF1532C3FF142FC0FF112A BDFF273BB8FFD4D3CDFFCDCDCDFFCDCDCDFFCECDCDFFBABBC6FF0412A4FF0714 A2FF06119FFF050E9CFF040C99FF030896FF191D9CF4FFF3E71FFFFFFF04B7A0 AC736D90F5FF6A8AF0FF6887EEFF5D7EEAFF4E71E6FF4164E2FF375ADDFFA7B0 D0FFCCCCCCFFCDCDCDFFCDCDCDFFCCCCCDFF364EC3FF1733C3FF152FC0FF1029 BDFF6A75BCFFD2D1CEFFCDCDCDFFCDCDCDFFD3D3CEFF444EAFFF0715A6FF0915 A4FF0914A0FF09129EFF0A119BFF0A1099FF2226A0F4FDF1E61FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF617EE7FF5372E3FF909D D3FFCCCCCAFFCACACAFFCACACAFFCACACAFF4B60C5FF213BC5FF1D37C2FF152E BFFF979DC1FFCDCDCBFFCACACAFFCACACAFFCCCCCAFF1626ACFF1220A9FF131F A7FF141EA5FF161FA2FF1920A2FF1D23A1FF3639A8F4F8ECE41FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF6580E5FF94A1 D6FFCCCCCAFFCACACAFFCACACAFFCACACAFF6778CBFF3850CCFF324AC8FF293F C4FFB0B3C5FFCCCBCBFFCACACAFFCACACAFFC1C2C9FF2A38B4FF2935B1FF2C36 B0FF3039AFFF353DAFFF3D44B0FF4448B1FF595CB7F4EFE3E01FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF647FE5FF9EA9 D6FFD3D3D2FFD2D2D2FFD2D2D2FFD1D2D2FF7988D1FF5C70D5FF586BD2FF5163 D0FFADB0C5FFD4D3D2FFD2D2D2FFD2D2D2FFCBCCCFFF515CC1FF505AC0FF525B BEFF535BBDFF535ABBFF5257B9FF5054B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF6580E5FFBAC0 D9FFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FF7182D3FF5D71D6FF5D6FD3FF596B D2FF989EC6FFDDDCDAFFD9D9D9FFD9D9D9FFDDDCD9FF656FC2FF545EC2FF535C BFFF535BBDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF6781E3FFDBDC DEFFE2E2E2FFE2E2E2FFE2E2E2FFDDDDDDFF6175D5FF5D71D6FF5D6FD3FF5A6C D1FF737EC8FFE5E5E1FFE2E2E2FFE2E2E2FFE4E4E3FFB4B6CEFF4E59C0FF535C BFFF535BBDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF637FE8FFB5BDD6FFE8E8 E7FFE6E6E6FFE6E6E6FFE8E8E7FFB5BAD4FF5B71D8FF5D71D6FF5D6FD3FF5B6D D1FF5A69CFFFD7D8DBFFE6E6E6FFE6E6E6FFE5E5E5FFEAE9E8FF737BC2FF535C BFFF535BBDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6180EBFFA4B0DCFFE6E6E5FFE5E5 E6FFE6E6E6FFE6E6E6FFE7E6E3FF687BD7FF5E74D8FF5D71D6FF5D6FD3FF5B6D D1FF5B6ACFFFA6ACD1FFE7E7E6FFE5E5E5FFE6E6E6FFE5E5E5FFDDDEE1FF5E66 BAFF5159BDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EFE3E11FFFFFFF01B29F BC6E6A8DF6FF6586F1FF6584EDFF8097E4FFBDC4DDFFEBEAE5FFE5E5E5FFE6E6 E6FFE5E5E5FFE7E7E6FFB3BADAFF5F74DBFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF6270C9FFE2E1DFFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E5 E4FF9296C9FF5D62B8FF4B51B6FF4A4FB4FF595BB8F4D3B9BA1BCDCDCC3CD2CF D6CFB5C0E0FFC2C8DCFFE0E0DFFFE7E7E6FFE6E6E5FFE6E6E6FFE5E5E5FFE5E5 E5FFE6E6E6FFDFDFDFFF6277D8FF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5968CDFF7681C9FFE5E5E4FFE5E6E6FFE5E5E5FFE5E5E5FFE5E5 E5FFE6E6E6FFEAE9E8FFD2D3D7FFB6B7CFFFB0B0CEFBD5D4D4B3D2D2D259E6E6 E6FFE8E8E6FEE8E7E7FFE7E7E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 E7FFE1E1E3FF7085DAFF6076DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF9299CBFFEEEEE8FFE6E6E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE7E7E7FFE8E8E7FFE8E8E7FFE2E2E2FFD2D2D258E6E6 E6FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE9E9E7FFD3D6 E0FF6D83D8FF6179DEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5360C9FF8B92C9FFE1E1E3FFE9E9E8FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE2E2E2FFD2D2D258E7E7 E7FFE8E8E8FFE8E8E8FFE7E7E7FFE7E7E7FFE8E8E8FFEAEAE6FF9BA8D8FF647E E2FF627CE0FF627ADEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5865C9FF5663C5FF5E68C4FFC0C2D3FFECEC EBFFE8E8E8FFE7E7E7FFE8E8E8FFE8E8E8FFE8E8E8FFE3E3E3FFCECECE57E1E1 E1FFE1E1E3FFDEDFE0FFCDD2E1FFB5BFE2FF93A6E4FF6C86E3FF627DE6FF647E E3FF627CE0FF627ADEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5865C9FF5663C5FF5660C4FF515BC0FF6B72 C1FF9498CAFFB8BAD2FFD1D1DAFFDEDFDFFEE1E1E2FFDBDBDBFC00000000EFE3 E3386779D2FF6385F2FE6485F0FF6585EDFF6684EAFF6682E8FF647FE5FF647D E3FF627CE0FF627ADEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5865C9FF5663C5FF5761C4FF555FC1FF535C BFFF525ABDFF4F55BAFF4B51B7FF494FB7FF55468DEAFFFFFF0900000000FFFF FF1D837DAED37395F7FF6786EFFE6786ECFF6684EAFF6581E8FF647FE5FF637D E3FF627CE0FF6179DEFF6077DCFF5F74DAFF5E74D8FF5D71D6FF5C6ED3FF5B6D D1FF5B6ACEFF5969CDFF5867CBFF5764C9FF5662C5FF5761C4FF555FC1FF535C BFFF535BBDFF5157BAFF4E53B7FE6562ADFFA18DA574FFFFFF0400000000F6F5 F604CFC0C3428D85AFC27C84CAF46874C6FF6874C5FF6A74C4FF6C75C2FF6C74 C2FF6C73BFFF6B71BEFF6A6FBCFF696EBBFF696DB9FF686BB8FF676AB6FF6669 B5FF6667B3FF6566B2FF6464B1FF6462AEFF6261ACFF5C5AA9FF5B58A7FF5A57 A6FF5B56A4FF655EA5FF7F76ABEF95819C93FFFFFF1300000000000000000000 0000FBFAFB02FFFFFF11FFFFFF2AFFFFF937D4C5C340D4C5C340D4C5C340D4C5 C340D4C5C340D5C6C340D5C6C440D5C6C440D5C6C440D5C6C440D5C6C440D5C6 C440D5C6C440D5C6C440D5C6C440D5C6C440D5C6C540D5C6C440D5C7C540D5C7 C540D5C6C440EBE2DF3BFFFFFF2CFFFFFF0E0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E0000007C000 0001800000008000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000800000008000000080000001C0000003FFFFFFFF280000003000 0000600000000100200000000000802500000000000000000000000000000000 00000000000000000000000000000000000000000000FFFFFF01FFFFFF03FFFF FF04FFFFFF07FFFFFF0BFFFFFF08FFFFFF04FFFFFF03FFFFFF03FFFFFF03FFFF FF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFF FF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFF FF03FFFFFF03FFFFFF05FFFFFF0BFFFFFF0FFFFFFF10FFFFFF10FFFFFF10FFFF FF0EFFFFFF09FFFFFF04FFFFFF02000000000000000000000000000000000000 0000000000000000000000000000FFFFFF01FFFFFF0AF0EBEC1FD4CAD332CCC3 D03BD4CDD947D9D3DD53D4CDD948CCC4D23BCAC1D039CAC1D039CAC1D039C9C1 D039C9C1D039C9C1CF39C9C0D039C9C1CF39C9C0CF39C9C0CF39C9C0CF39C9C0 CF39C9C0CF39C9C0CE39C9C0CE39C8C0CE39C9BFCE39C9BFCE39C9BFCE39C9BF CE39C9C0CE3ACEC6D340D8D1DB53DBD4DD61DCD5DE64DCD5DE64DCD5DE63DAD2 DC5DD3CBD64BCDC4D039D7CFD829FBFAF916FFFFFF0700000000000000000000 00000000000000000000FFFFFF02FFFFFE12D8CFD63F9B8CA88B675687CC5243 81E7514688EF504586F2504588EE4F4487EB4E4286EB4E4285EB4D4185EB4C40 84EB4C3F83EB4B3F82EB4B3E82EB4B3D80EB4B3C7FEB4A3C7FEB4A3B7EEB4A3A 7DEB49397CEB49397CEB49387AEB48387AEB48377AEB483679EB483578EB4835 77EB473476EB473476EC473274F2442C6CFA442C6CFA442C6BFA432B6AFB432A 6AFA442D6CF04B3370DE675284B6A394AE76E1D9DE37FFFFFF0EFFFFFF020000 00000000000000000000FFFFFF0BD1CAD545776FA3BB5157ABFF4F6EDEFF436C F0FF3963EEFF3661EBFF345EE9FF345BE7FF3359E4FF3158E2FF3056E0FF2F54 DEFF2E51DBFF2D4FDAFF2C4ED8FF2C4BD6FF2A49D3FF2A48D1FF2947D0FF2844 CDFF2742CBFF2640CAFF253FC8FF253CC5FF233BC3FF2239C2FF2237BFFF2135 BDFF2033BBFF1F31B9FF1E2FB7FF1D2EB5FF1C2CB4FF1B2AB1FF1B28AFFF1926 ADFF1C27ADFF232BA8FF292894FF362577FF715C8AADDAD1D83EFFFFFF0C0000 000000000000FFFFFF02DEDAE7237B7BB79D4D64CCFF3B6AF5FF2655EAFE2552 E6FF224FE3FF204CE1FF2049DFFF1F47DDFF1E45DBFF1C42D8FF1B41D5FF193F D3FF183DD1FF173BCFFF1638CDFF1636CBFF1534C9FF1433C6FF1331C4FF122F C2FF112DC0FF102ABEFF0F28BCFF0F26B9FF0E25B7FF0D23B5FF0B21B3FF0A1F B1FF091CAFFF081AACFF0818A9FF0716A7FF0615A5FF0513A3FF0411A1FF030E 9FFF010C9CFF00099AFF000699FE09129FFF271F83FF7664939CEDE9F024FFFF FF0100000000BAB9B309B2B6D9474D5FC2F14370F4FF2957EAFE2452E9FF1D4C E6FF1D4BE4FF1F4AE2FF214ADFFF2149DDFF1F46DBFF1E44D8FF1D43D6FF1C41 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0A1AAAFF0918A8FF0817A6FF0715A4FF0612A2FF010D 9FFF00079CFF000298FF000597FF000695FE09119CFF2C1F7AEFC4C1CF4DB0B0 AF0CB0B0B016D4D4D4A5D1D2DABD9DA8D5FF98A9E0FF92A4DCFF899CDCFF758D DCFF5876DBFF355ADDFF1B46DFFF1A44DEFF1E45DBFF1E44D8FF1D43D6FF1C41 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0A1AAAFF0918A8FF0716A6FF000EA2FF000C9FFF1E28 A3FF464DAEFF6469B5FF787CB9FF8285BCFF8184BBFE8E8BB7FFD3D3D6C4D1D1 D1A4B1B1B125D5D5D5FFD9D9D9FFDDDCD8FEDEDCD7FEDDDBD5FFDCDBD5FFD4D5 D6FFC4C8D7FFAEB7D7FF8A9BD7FF4C6AD6FF1B43DAFF1A41D8FF1C43D6FF1C41 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0A1AAAFF0414A7FF0615A4FF3F49ADFF8489C1FFABAE CBFFC2C3D1FFD4D5D5FFDDDDD8FFDFDFD9FFE0E0DBFEE0E1DCFEDADADAFFD4D4 D4FFB0B0B023D4D4D4FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD8D7 D7FFD9D9D7FFDBDAD7FFD5D5D5FFC3C8D7FF97A4D4FF3858D3FF173ED6FF1B40 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0515A9FF2C38ACFF969AC6FFC5C6D3FFD7D7D6FFDDDC D9FFDAD9D8FFD8D8D7FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD4D4 D4FFB0B0B023D3D3D3FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6 D6FFD6D6D6FFD6D6D6FFD6D6D6FFD8D8D6FFD4D5D5FFC3C6D5FF687DCFFF183D D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF091AABFF636BB9FFC6C8D4FFD5D5D5FFD9D9D7FFD6D6D6FFD6D6 D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD3D3 D3FFB0B0B023D2D2D2FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD6D5D5FFD2D3D6FF8895 CCFF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0C20 B2FF0C1FAFFF888EC1FFD6D6D8FFD6D6D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD2D2 D2FFB0B0B023D2D2D2FFD4D4D4FFD3D3D3FFD3D3D3FFD4D4D4FFD4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D3FFD6D6 D6FF99A3CBFF1438CFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0A1F B0FF989DC4FFD8D8D8FFD4D4D3FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD3D3D3FFD3D3D3FFD3D3D3FFD4D4D4FFD1D1 D1FFB0B0B023D4D4D4FFD5D5D5FDD3D4D6FFD3D3D5FFD1D2D3FFD2D3D3FFD3D3 D3FFD4D4D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3 D3FFD5D5D5FF818EC7FF1436CDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0A20B3FF828A C0FFDAD9D8FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD4D4 D3FFD4D4D4FFD3D3D3FFD2D2D3FFD3D3D4FFD2D3D4FFD2D2D4FFD5D5D5FCD4D4 D4FBB5B5B50CC5C4C469AAA6BDB46989E5FF6583E0FF728AD8FF909FD0FFB6BC CFFFCBCCD2FFD1D2D2FFD3D3D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2 D2FFD2D2D2FFD1D1D3FF5B6EC6FF1434CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0B21B5FF5864BAFFD8D8 D7FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD3D3D3FFD2D2 D2FFCDCED3FFB4B5CBFF8084BAFF585CACFF3F43A3FF4144A3FFB1ACBF9DC1C1 C15B00000000FDF6F71A9B93BD914470F4FF3361EEFF2C5BECFF2453EBFF2651 E3FF5673D4FFA2ADD1FFCBCDD2FFD2D2D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1 D1FFD1D1D1FFD2D2D1FFBFC2CDFF2A46C7FF1434C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF0D25B8FF2135B6FFC6C8D2FFD1D1 D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1D1FFD2D2D2FFCDCED1FF9FA2 C5FF3F46A8FF000899FF000197FF000395FF000193FF060B97FFA59AC26CFFFF FF0AFFFFFF01F0EAEC209E96BD934F78F3FF3E69EEFF3763EBFF315CE9FF2C57 E7FF214EE6FF234EDEFF7389D5FFC1C4D0FFD1D1D0FFD0D0D0FFD0D0D0FFD0D0 D0FFD0D0D0FFD1D0D0FFCECED0FF8792C5FF1232C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF0921B7FF8B93C5FFD0D0D1FFD0D0 D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD2D2D1FFC4C5CDFF6A71B6FF0814 9EFF00069CFF020C9BFF030B99FF020997FF000694FF0A0F98FFA79CC270F9F8 F910FFFFFF01F0EAEC20A098BD935A81F3FF4770EEFF3F68ECFF3861E9FF315C E7FF2D57E4FF2751E3FF1C47DFFF667ED3FFC3C6CFFFD0D0CFFFCFCFCFFFCFCF CFFFCFCFCFFFCFCFCFFFD1D0CFFFBBBECBFF364FC4FF1232C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF0D25BAFF2F41B8FFC5C6CFFFD0D0CFFFCFCF CFFFCFCFCFFFCFCFCFFFCFCFCFFFD1D1CFFFC4C5CCFF5E65B4FF000D9FFF020E 9FFF040F9DFF030C9BFF020B99FF020997FF000694FF0B1098FFA79CC270F9F8 F910FFFFFF01EFEAEC20A39ABD93698CF5FF557BEFFF4A71EDFF4169EAFF3962 E8FF335BE5FF2E56E2FF2951E1FF1D46DDFF7D8FD1FFCBCCCFFFCECECEFFCECE CEFFCECECEFFCECECEFFCFCFCEFFC7C8CCFF7582C2FF0C2DC8FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF061EB9FF7A83C1FFCACBCEFFCECECEFFCECE CEFFCECECEFFCECECEFFCFCFCEFFCACACEFF747AB8FF020FA1FF0411A2FF0511 A0FF040F9DFF030D9BFF030B99FF020997FF000794FF0C1098FFA79CC270F9F8 F910FFFFFF01EFEAEC20A39BBD937092F5FF6587F1FF5B7EEEFF4F74EBFF446B E9FF3D63E6FF365CE3FF3057E1FF2950DFFF2E52D9FFACB3CEFFCCCCCDFFCDCD CDFFCDCDCDFFCDCDCDFFCDCDCDFFCECDCCFF9EA5C4FF1A37C5FF1432C5FF1531 C3FF132FC0FF122CBEFF112ABCFF0F27B8FFA9ADC7FFCECECDFFCDCDCDFFCDCD CDFFCDCDCDFFCDCDCDFFCDCDCDFFA7AAC4FF1421A6FF0412A3FF0713A2FF0611 9FFF050F9DFF040E9BFF040C9AFF040A98FF020895FF0D1299FFA79CC270F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8BF2FF6788F0FF6182EEFF5779 EBFF4C6FE8FF4267E5FF3B60E2FF355AE0FF284EDEFF6C81CFFFCACBCFFFCDCD CCFFCCCCCCFFCCCCCCFFCCCCCCFFCECECCFFB2B6C8FF3A52C1FF1230C5FF1631 C3FF152FC0FF132DBEFF0E27BCFF3547B8FFB9BCCAFFCECECDFFCCCCCCFFCCCC CCFFCCCCCCFFCDCDCDFFC5C6CBFF6269B4FF000EA5FF0916A4FF0814A2FF0712 A0FF06109EFF060F9CFF060E9AFF070D99FF060B96FF11179BFFA89DC270F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6685 EDFF6080EAFF5778E8FF4C6EE5FF4465E2FF3B5DDFFF3E5ED9FFC7C9CEFFCDCD CDFFCDCDCDFFCDCDCDFFCDCDCDFFCECECDFFBDBFC9FF586AC0FF1230C6FF1733 C3FF1631C0FF152EBFFF0D26BDFF5664BBFFBFC1CAFFCECDCDFFCDCDCDFFCDCD CDFFCDCDCDFFCDCDCDFFBDBECAFF1E2BA9FF0917A7FF0A17A6FF0A16A3FF0A15 A1FF0A149FFF0B139EFF0B139CFF0C129BFF0C1299FF191E9EFFA99EC370F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6988EFFF6887 EEFF6786EBFF6583EAFF617FE8FF5A78E6FF5170E2FF4163E0FFB1B7CEFFCBCB CBFFCBCBCBFFCBCBCBFFCBCBCBFFCCCCCBFFC1C2C8FF6B7AC1FF1835C8FF1E39 C4FF1C36C2FF1A33C0FF0F29BDFF717DBEFFC4C4C9FFCCCBCBFFCBCBCBFFCBCB CBFFCBCBCBFFCBCBCBFFABAFC4FF0617A9FF101EA9FF101DA7FF111DA5FF111C A4FF121BA3FF131CA1FF151CA0FF181E9FFF191F9FFF272BA4FFABA0C370F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6581E7FF637EE5FF5B77E4FFA7B0CFFFC8C8 C9FFC9C9C9FFC9C9C9FFC9C9C9FFC9C9C9FFC5C5C6FF838DC3FF243FCBFF2942 C8FF263FC5FF243CC3FF1831C1FF838BC0FFC5C5C7FFC9C9C9FFC9C9C9FFC9C9 C9FFC9C9C9FFC7C7C8FF8F95BFFF1221ADFF1B29ACFF1B28ABFF1D28AAFF1E29 A9FF202AA8FF232BA7FF262DA7FF2A31A8FF2F34A8FF3F44AEFFAEA3C570F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF6580E6FF607BE5FFAAB1D1FFCBCB CBFFCBCBCBFFCBCBCBFFCBCBCBFFCCCCCBFFC9C9CAFF8F99C8FF3952D0FF3D54 CCFF3950CAFF364CC7FF2A40C5FF949AC5FFCACACBFFCCCCCBFFCBCBCBFFCBCB CBFFCBCBCBFFC9CACBFF9398C2FF2533B4FF2E3BB4FF303BB3FF323CB2FF353E B2FF3941B2FF3D45B2FF4349B3FF484DB4FF4B4FB4FF5659B8FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF6580E6FF607AE5FFB1B7D2FFD0D0 D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1D1FFCACBCEFF919BCAFF566BD7FF596C D4FF5668D2FF5265D0FF495CCEFF959CC6FFCDCDCEFFD1D1D1FFD1D1D1FFD1D1 D1FFD1D1D1FFCFCFD0FF9EA2C6FF444FBEFF4C57BFFF4E58BDFF5058BCFF5159 BCFF5259BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF6580E6FF617BE4FFC6C9D2FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD6D6D5FFCCCDD2FF8D99CEFF596FD8FF5D71 D6FF5D70D3FF5C6ED2FF5669D2FF939BC8FFCFCFD2FFD6D5D5FFD5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFBABCCEFF505BC3FF5660C2FF545EC0FF545CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF637FE7FF7689D8FFD7D8DBFFDBDB DBFFDBDBDBFFDBDBDBFFDBDBDBFFDCDCDBFFCBCDD7FF7E8CCFFF5A70D8FF5D71 D6FF5D6FD3FF5C6ED2FF5769D2FF818AC7FFCFD0D7FFDBDBDBFFDBDBDBFFDBDB DBFFDBDBDBFFDBDBDAFFCDCED6FF5F69C0FF545EC2FF545EC0FF535CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF607CE6FFA5AFD7FFDEDEE0FFE0E0 E0FFE0E0E0FFE0E0E0FFE0E0E0FFE2E2E0FFC7CADAFF6A7BD0FF5C71D8FF5D71 D6FF5D6FD3FF5C6ED2FF596BD2FF6D78C7FFCDCED8FFE1E1E0FFE0E0E0FFE0E0 E0FFE0E0E0FFE1E1E0FFDADADEFF8C92C6FF4F5AC1FF545EC0FF535CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6683E9FF627FE8FF7389DDFFD6D8DFFFE5E5E5FFE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E3FFB7BDD7FF5A70D7FF5E72D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6CD1FF5969CDFFBDC1D2FFE4E4E4FFE5E5E5FFE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFC6C8D7FF5B65BFFF525CC0FF545CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6381EAFF6781E2FFB5BDDAFFE4E5E5FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFDDDEE3FF919CD3FF5970D9FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5C6DD1FF5566D0FF969DC8FFE0E1E3FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE1E2E4FF9EA3CAFF525BBDFF525BBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6282EBFF6783E4FFA6B1DCFFE1E2E3FFE6E6E5FFE5E5E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E5FFCDD1DEFF6679D5FF5E73D9FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5A6ACFFF6572C8FFCFD1DAFFE5E5E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE5E5E6FFE7E7E6FFDBDCE0FF8F95C8FF515ABBFF5058 BDFF535ABBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB2A8C86FF9F8 F910FFFFFF01EFEAED20A39BC1937092F5FF6A8AF2FF6989F0FF6888EFFF6686 EFFF6081ECFF758DE1FFB1BADEFFE0E1E3FFE6E6E5FFE6E6E6FFE5E5E5FFE6E6 E6FFE5E5E5FFE6E6E6FFE2E3E5FF99A3D4FF5A70DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5666CDFF99A0C9FFE4E4E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE7E7E6FFDBDCE0FF9EA2CBFF5D64 BBFF4B52BAFF5056BAFF5157B9FF5156B7FF4F53B5FF575BB9FFA596B775F7F5 F71000000000FDF6FF159D99CE8E6B8FF6FF6487F4FF6284F2FF6283EEFF768F E3FFA1AFDDFFCCD0E0FFE4E4E4FFE7E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6 E6FFE6E6E6FFE5E5E5FFC5C8D9FF6277D9FF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5A6ACEFF5F6EC9FFC9CBD5FFE6E6 E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE7E7E6FFE2E2E3FFC3C5 D7FF9093C3FF5E63B5FF4A50B5FF484EB5FF484CB4FF5256B8FF9580A473FFFF FF05B4B4B413D7D6D793C3C2D6C9A3B4E5FFA7B5E0FFB2BCDEFFC5CBDEFFD5D9 E3FFE0E1E4FFE6E6E5FFE6E6E6FFE5E5E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5 E5FFE6E6E6FFDCDDDFFF7687D5FF5E74DCFF6074DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5867CDFF737EC7FFE1E1 E0FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE6E6E6FFE6E6 E5FFDFDFE3FFD3D3DEFFBEC0D2FFABADCBFF9B9DC7FF9799C8FFC3BDC8BDD4D3 D487B2B2B222E0E0E0FFE4E4E5FCE1E2E5FFE2E3E5FFE3E3E4FFE5E5E5FFE6E6 E5FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6 E6FFE4E4E2FF8897D4FF5F76DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5867CBFF888F C6FFE8E8E5FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5 E5FFE6E6E6FFE6E6E6FFE5E5E5FFE3E3E4FFE1E1E3FFE1E1E3FFE4E4E4FBDFDF DFF8B2B2B223E1E1E1FFE7E7E7FFE7E7E6FEE7E7E6FFE7E7E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE7E7E7FFE8E7 E5FF8E9CD5FF6079DEFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 C9FF8C93C8FFE8E8E4FFE7E7E7FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE7E7E6FFE7E7E6FFE7E7E6FEE7E7E7FFE1E1 E1FFB2B2B223E1E1E1FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE6E7E7FFE1E1E2FF8797 D5FF6079E0FF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF888EC5FFE3E3E2FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE1E1 E1FFB2B2B223E1E1E1FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E7FFE5E5E7FFC9CCDCFF788BDAFF617B E1FF627ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5562C5FF7179C3FFCBCCD9FFE6E6E7FFE8E8E7FFE8E8E8FFE8E8 E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE1E1 E1FFB2B2B223E2E2E2FFE8E8E8FFE8E8E8FEE8E8E8FFE8E8E8FFE8E8E8FFE9E9 E8FFE9E9E8FFE7E7E6FFE1E2E7FFD3D6E3FF99A7D9FF657EE1FF627CE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF545FC4FF5A64C2FF959AC9FFD0D1DCFFE1E1E5FFE7E7 E6FFE9E9E8FFE9E9E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FEE8E8E8FFE2E2 E2FFB2B2B223DFDFDFFFE5E5E5FEE4E5E6FFE5E5E5FEE2E3E4FFDEDFE5FFD9DC E6FFD0D5E5FFBDC6E2FF95A5DEFF6B84E2FF607CE6FF647DE4FF647EE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF5761C4FF555FC3FF505AC1FF5D66BFFF8C91C6FFB6B8 D2FFCACCDBFFD6D6DFFFDCDDE1FFE2E3E4FFE3E4E4FEE5E5E5FFE4E4E4FEDEDE DEFDB1B1B114D7D7D79CD3D1DAC0AAB1D5FFACBAE8FEA5B4E3FF97A9E3FF879C E2FF718BE3FF6180E9FF607FEAFF6480E7FF6580E6FF657EE4FF647EE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF5761C4FF5660C3FF555FC2FF525CC0FF4D56BEFF4F57 BBFF6268BAFF787CBEFF8B8EC3FF9A9DC9FF9B9ECAFEA09CBEFFD5D3D8BAD4D4 D4950000000000000000BBB4CF546367B2FF6D91FCFF6183F1FE6384F0FF6484 EFFF6585ECFF6684EAFF6683E9FF6681E7FF6580E6FF657EE4FF647EE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF5761C4FF5660C3FF555FC2FF545EC0FF545CBFFF535B BDFF5057BBFF4D54B9FF4B51B8FF474DB4FE4E54BBFF50418BF9D5CFE2450000 000000000000FFFFFF06D8D1DA3B7B6E9CCA7B8FE1FF6C8FF6FE6686EFFE6887 EEFF6786EBFF6684EAFF6583E9FF6581E7FF647FE6FF647DE4FF637DE2FF627C E0FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5D72D7FF5C70 D5FF5C6FD3FF5B6DD2FF5B6CD1FF5B6ACFFF5A6ACDFF5968CCFF5867CBFF5865 C9FF5764C8FF5663C5FF5661C4FF5660C3FF555FC2FF545EC0FF535CBFFF535B BDFF5259BBFF5056B9FF4D53B7FE585EBEFF6460ADFF7B6895AEE7E2E929FFFF FF0300000000FFFFFF02F8F4F419BBAEBE6A7E77A7E07B89D4FF7C9AF7FF6D8D F4FF6688F1FF6587F0FF6585EFFF6986EDFF6A88ECFF6A86EBFF6A85EAFF6984 E7FF6882E6FF6881E4FF677FE3FF667EE2FF667DE1FF657CDFFF657ADEFF6378 DCFF6377DAFF6276D9FF6275D7FF6273D6FF6172D4FF6071D3FF5F6FD2FF5F6D D0FF5E6CCFFF5C6BCCFF5A67CAFF5561C7FF5460C6FF535FC4FF525DC3FF525C C1FF565FC1FF6269C5FF7279CBFF6F6AADFF776491D3C4B8C650FCFAFA0E0000 00000000000000000000FFFFFF05F9F7F620BFB2C05D978DB2A47973A9DF6F6C ABFC6968AAFF6A68AAFF6967A9FF6B68A8FF6B68A7FF6B67A7FF6B66A7FF6B66 A5FF6A65A4FF6A65A4FF6A63A3FF6963A3FF6862A2FF6862A1FF6861A0FF6860 9FFF675F9EFF675F9EFF675E9DFF675D9CFF665D9CFF665C9BFF655B9AFF655A 99FF645A98FF645997FF635796FF615595FF615494FF605393FF605392FF6052 91FF625392FF65538DFF6F5B8BEA917F9EAEC0B2BF56FEFDFC17FFFFFF020000 0000000000000000000000000000FFFFFF04FFFFFF10DBD1D827C1B6C745C5BE D157B3A8BB62A696AA66A898AB66A797AB66A797AB66A797AA66A797AB66A797 AA66A796AA66A796AA66A796AA66A796AA66A696AA66A696A966A695A966A695 A966A695A966A695A866A695A866A694A866A694A866A694A866A694A866A694 A766A594A766A593A766A594A766A694A766A693A766A593A766A593A666A593 A666A593A665B5A7B95FC1B4C351DDD3D831FFFFFF11FFFFFF03000000000000 00000000000000000000000000000000000000000000FFFFFF02FFFFFF07FFFF FF0AFFFFFA0CF6EFEA0CF7F1EB0CF7F1EB0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1 EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F2EC0CF7F2 EC0CF7F2EC0CF7F2EC0CF7F2ED0CF7F2ED0CF7F2ED0CF7F2ED0CF7F2ED0CF7F2 ED0CF8F2ED0CF8F2ED0CF8F2ED0CF8F2ED0CF8F3ED0CF8F3ED0CF8F3EE0CF8F2 ED0CF8F3EE0CFFFFFF0BFFFFFF09FFFFFF05FFFFFF0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8000000001FFFFFE00000000007FFFFC00000000001FFFFC00000000001 FFFF800000000000FFFF800000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF800000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF800000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFFC00000000001FFFF800000000000FFFF800000000001 FFFFC00000000001FFFFE00000000003FFFFF80000000007FFFFFFFFFFFFFFFF FFFF280000004000000080000000010020000000000000420000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F7F7FA01FBFBFC04FCFCFC05FBFB FD03F6F6F90100000000F7F6FA0100000000F6F6F901F6F6F901F6F6F901F7F6 F901F6F6F901F6F6F901F7F6F901F6F6F901F7F6F901F6F5F901F6F5F901F6F5 F801F6F6F901F6F6F901F6F6F901F5F5F801F6F5F801F6F5F801F6F6F901F6F6 F901F6F5F801F6F5F801F6F5F801F6F6F901F6F5F801F6F5F801FCFCFD04FCFC FD07FDFDFD08FCFCFD08FCFCFD08FDFDFD08FDFDFD08FCFCFC07FCFCFD04F5F4 F701000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FBFA FB01FBFBFC04FCFCFD0EFAF9F914F4F0F117F0EDF01BF4F1F325F4F1F32BF4F1 F324F1EDEF1BEEE9ED16EFEAED16EEEAED16EDE9EC15EFEAED16EDE9EC15EFEB ED16EFEAED16EFEBED16EFEAED16EEEAEC16EFEAED16EFEAED16EFEAED16EFEA ED16EFEAED16EFEAED16EEE9EC16EEEAED16EFEAED16EFEAED16EDE9EC15EFEA ED16EEEAED15EFEBEE16EFEBEE16EFEBED16EFEBEE17F2EEF01BF4F1F327F6F3 F533F5F3F438F5F3F438F5F3F438F5F3F438F5F3F438F4F2F333F4F2F326F4F1 F41AFBF9F913FCFCFC0DFBFBFB05F9F8F9020000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDFDFD02FBFB FC0CF8F7F822E9E5E83ED5C8C95AA289927090748A80977C908A93778A979980 92879073897E8D6F867A8D6F867A8D70867A8D6F867A8D70867A8D70867A8C70 86798D70867A8D7086798D70857A8D70857A8D7085798D70857A8E6F867A8E6F 867A8E6F867A8E70867A8D6F857A8D70867A8D70867A8C6F867A8D7086798D70 857A8C70867A8D7086798D71867A8D71867A8D70867A92768B80977B908E9477 89A094788AA795788BA794778AA794788AA795788AA6917486A194788C8EA48E A275D7CACD58E4DEE53DF4F2F428FBFBFC16FAFAFB0600000000000000000000 00000000000000000000000000000000000000000000FCFCFD02F9F9F912F1EF F234C6BCCB696A4E72C4412B68F63B2E74FD48448DFD484793FE474693FD4645 92FE454391FE454290FE444190FE44408FFE443F8DFE433E8DFE433E8CFE423D 8BFD423C8AFE423B8AFE413B88FD413A87FE413986FE403985FE403785FE3F37 84FE3F3683FE3F3582FE3E3481FE3D3480FE3D3380FE3D337FFE3C327EFD3C31 7DFE3C317CFE3B307BFE3B2F7BFE3B2E7AFD3A2D79FE3A2C79FE3A2B78FD392A 77FE392A77FE392976FE382875FE382874FE382773FE372771FE372672FE2F16 59FD2B0C52FD4A2B63D7AB9CB085E0DAE14DF7F7F921FCFCFC09000000000000 00000000000000000000000000000000000000000000FAFAFB0DEFEDF034A699 B084493B7BEF6C79C9FD4C6EE1FD3E67EAFD355EE8FE325CE6FE3059E4FD2E57 E2FE2E55E1FE2D53DFFE2C52DEFE2B51DCFE2A50DAFE294DD8FE284CD7FE284A D5FD2748D4FE2647D2FE2645D0FD2544CFFE2543CEFE2442CCFE2340CBFE233F C9FE223DC7FE213CC6FE203AC4FE1F38C2FE1F37C1FE1E35BFFE1E34BEFD1D33 BCFE1C31BBFE1B30B9FE1B2EB8FE1A2DB6FD192BB4FE192AB2FE1828B1FD1727 AFFE1726AEFE1625ACFE1523AAFE1522A9FE1420A7FE131FA6FD121DA4FE1923 A6FD1C219EFD34339BFD4C3A7DFD553563CACCC3D055F8F7F921FBFAFB060000 000000000000000000000000000000000000F7F7F904F6F5F71FBFB7CC694946 93F76A8BF0FD315DE9FD2B57E6FE2854E5FE2550E3FE234EE0FF224CDFFE2149 DDFF2047DCFF1F46DAFF1F44D8FF1D43D6FF1D41D4FF1C40D3FF1A3ED1FF1A3D CFFE193BCEFF183ACCFF1839CBFE1737C9FF1736C7FF1635C6FF1533C4FF1532 C3FF1430C1FF132EBFFF122CBDFF112ABBFF1129BAFF1027B8FF0F26B7FE0E25 B5FF0D23B3FF0D22B2FF0C20B0FF0B1FAFFE0B1DACFF0A1BAAFF0A1AA9FE0918 A7FF0817A6FF0816A4FF0614A2FF0613A1FF05119FFF04109EFF040E9CFF030C 9AFE030B99FE000695FE070F9BFC38318AFD4F3265CDDCD6DE4DFAFAFA16F5F5 F70200000000000000000000000000000000FAFBFC0BD8D5E33C4A4592D95B82 F2FD315EEAFD2D59E8FE2A56E6FE2753E5FE2451E3FE234FE1FE214CE0FE2049 DEFE2048DDFE1F47DBFE1E44D9FE1D43D7FE1C42D5FE1C41D4FE1A3FD2FE1A3D D0FE193CCFFE183ACDFE1839CCFE1737CAFE1736C8FE1635C7FE1533C5FE1532 C4FE1430C2FE132EC0FE122CBEFE112ABCFE1129BBFE1027B9FE0F26B8FE0E25 B6FE0D23B4FE0D22B3FE0C20B1FE0B1FB0FE0B1DADFE0A1BABFE0A1AAAFE0918 A8FE0817A7FE0816A5FE0614A3FE0613A2FE0511A0FE04109FFE040E9DFE030C 9BFE020B9AFE020A98FE010895FE050A96FC302A8EFDA395AF87F3F1F429F8F8 FA05000000000000000000000000B6B6B608E2E2E419C2C4E05D4B69D7F65278 EDFD315EE9FE2E5AE8FE2956E6FF2652E4FD2350E2FF224DE0FF214BDFFD204A DDFF2049DCFF1E46DAFF1E44D9FF1D43D7FF1C42D4FF1C40D3FF193FD1FF1A3D D0FD193BCEFF173ACCFF1839CCFD1736C9FF1735C8FF1534C6FF1533C5FF1532 C4FF132FC2FF122EBFFF112BBDFF112ABBFF1129BAFF1026B8FF0F26B8FD0E24 B5FF0C23B3FF0C22B2FF0B20B0FF0B1FB0FD0A1DACFF091AABFF0A1AAAFD0818 A8FF0817A6FF0816A4FF0614A3FF0613A2FF0511A0FF04109FFF040E9DFF040C 9BFF030C9AFE040C99FF060B97FE060894FE1F229EFD3C2369DFD8D5DB40D2D2 D312B2B2B20300000000A6A6A605BDBDBD60C8C8C872B2B4CDA98597D5FD6B87 DEFE6D87DFFE6985DEFF4A6EE2FE3F65E1FD3860E0FF3158DEFF2850DEFD214A DDFF1F48DDFF1E46DAFF1E44D8FF1D43D6FF1C42D4FF1C40D4FF1A3FD2FF1A3D D0FD193CCFFF183ACDFF1839CCFD1737CAFF1735C8FF1635C6FF1533C4FF1532 C4FF1430C2FF132EC0FF122CBEFF112ABBFF1128BBFF1027B9FF0F26B8FD0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0B1FB0FD0B1DADFF0A1AABFF0A1AAAFD0817 A8FF0817A7FF0816A5FF0614A3FF0512A1FF0814A0FF111BA0FF1821A2FF2027 A2FF252CA3FF3C42A8FE4F53ABFE4C4FA5FE5052A6FD564D8EFDC8C7C4A7C0C0 C07BB6B6B62D00000000A1A1A10CCFCFCFF7D8D8D8FCD8D8D6FCD8D8D7FED9D8 D6FED8D7D5FED9D8D6FED9D8D6FFD1D4D9FEBEC3D4FFA3ADD0FF7187D2FE3A5E DCFF274EDCFF2148DAFF1D44D9FF1D43D6FF1C42D4FF1B40D4FF1A3FD2FF193C CFFE193BCFFF1839CCFF1838CCFE1737CAFF1736C8FF1535C7FF1433C5FF1432 C4FF1330C1FF132EC0FF122BBEFF1129BCFF1128BBFF1027B9FF0E26B7FE0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0B1EB0FE0A1CADFF091BABFF0A1AA9FE0918 A8FF0817A6FF0917A5FF0C19A4FF161DA4FF3840AAFF7E82B9FFACAEC8FFC6C7 D4FFD6D7D6FFD8D8D5FFD8D9D7FFD9D9D8FEDADAD9FEDCDBD9FDD9D9D9FCD8D8 D8FDC0C0C07400000000A1A1A10CCFCFCFF3D6D6D6FCD5D5D5FDD6D6D6FED6D6 D7FED5D5D6FED6D6D7FED4D5D6FED4D5D6FDD5D6D7FED8D9D9FED9D9D7FDC7C9 D0FE8596D2FE4A67D6FE2C4FD7FE1E44D6FE1C42D4FE1C41D3FE1A3FD2FE1A3D D0FD193CCFFE183ACDFE1839CCFD1737CAFE1735C8FE1635C7FE1532C5FE1532 C4FE1430C2FE132EC0FE112CBEFE112ABCFE1129BBFE1027B9FE0F26B8FD0E25 B6FE0D22B4FE0D22B3FE0C20B1FE0B1FB0FD0B1DADFE0A1BABFE0A1AAAFD0919 A8FE0D1CA6FE2530AAFE4B54B2FE9FA3C3FED9D9D8FEDDDDDCFED6D7D7FED5D5 D6FED5D5D6FED5D5D6FED5D5D6FED5D5D6FED5D5D6FED5D5D6FED5D5D5FDD6D6 D6FDC0C0C07300000000A1A1A10DCFCFCFF5D5D5D5FDD5D5D5FDD6D6D6FED6D6 D6FED6D6D6FED6D6D6FED6D6D6FED6D6D6FDD6D6D6FED5D5D5FED5D5D6FDD4D4 D6FED4D5D6FECCCED6FE909DCCFE3C5CD5FE2549D4FE1C41D3FE1A3FD1FE193D D0FD193BCEFE1739CCFE1839CBFD1636CAFE1635C8FE1535C7FE1532C4FE1532 C3FE142FC2FE122DBFFE122BBDFE112ABCFE1128BAFE1027B9FE0F26B8FD0E25 B5FE0D22B4FE0D22B2FE0C20B1FE0B1EAFFD0B1DADFE0A1BABFE0B1BA9FD1826 AAFE4650AFFEACAEC9FED5D6D9FED5D5D7FED5D5D6FED5D5D5FED5D5D5FED5D5 D5FED6D6D6FED6D6D6FED6D6D6FED6D6D6FED6D6D6FED5D5D5FED5D5D5FDD5D5 D5FEC0C0C07400000000A1A1A10DCFCFCFF5D4D4D4FED4D4D4FED5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FED5D5D5FFD4D4D4FFD4D4D4FED5D5 D5FFD4D4D4FFD4D3D5FFD5D5D7FFB7BCD0FF6379CFFF294CD2FF1C40D2FF193D CFFE193CCEFF183ACDFF1839CCFE1737CAFF1736C8FF1635C7FF1533C5FF1532 C4FF1430C2FF132EC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0B1FB0FE0B1DADFF0E20ABFF2B38ADFE7F84 BEFFCBCCD4FFD7D7D7FFD3D3D4FFD4D4D4FFD5D5D5FFD4D4D4FFD5D5D5FFD4D4 D4FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD4D4D4FFD4D4D4FED4D4 D4FFC0C0C07400000000A1A1A10DCECECEF5D3D3D3FED3D3D3FED4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FED3D3D3FFD3D3D3FFD4D4D4FED4D4 D4FFD4D4D4FFD3D3D4FFD2D2D3FFD3D3D4FFC8CAD4FF8290CBFF3252D1FF1C3F CFFE193CCEFF1739CDFF1839CCFE1737CAFF1736C8FF1635C6FF1532C4FF1532 C3FF1430C2FF132EC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0C1FB0FE1324AEFF3B48B3FFA8ACCBFED4D4 D7FFD3D3D4FFD2D2D3FFD3D3D3FFD3D3D3FFD4D4D4FFD3D3D3FFD4D4D4FFD3D3 D3FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD3D3D3FED4D4 D4FFC0C0C07400000000A2A2A20CCDCDCDF4D2D3D2FDD2D2D2FDD3D3D4FED3D3 D4FED3D3D3FED4D4D3FED4D4D4FED4D4D4FED3D3D3FED3D3D3FED4D4D4FED4D4 D4FED4D4D4FED4D4D4FED3D3D3FED2D2D3FED2D2D3FECCCDD3FE939FCEFE3855 CEFE1C3DCEFE183ACCFE1839CCFE1737CAFE1736C8FE1635C7FE1533C5FE1532 C4FE1430C2FE132EC0FE122CBEFE112ABCFE1129BBFE1027B9FE0F25B8FE0E25 B6FE0D23B4FE0D22B2FE0D21B1FE1426B0FE4955B5FEB3B6CEFED3D4D5FED2D2 D2FED2D2D3FED3D3D3FED3D3D3FED3D3D3FED4D4D4FED3D3D3FED4D4D4FED3D3 D3FED4D4D4FED4D4D4FED4D4D4FED3D3D3FED3D3D3FED3D3D3FED2D2D2FDD3D3 D3FEBFBFBF7300000000A2A2A20CCECECEF3D3D3D3FDD2D2D2FDD3D3D3FED3D3 D3FED3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FED2D2D2FFD2D2D2FFD3D3D3FED3D3 D3FFD3D3D3FFD3D3D3FFD2D2D2FFD3D3D3FFD3D3D3FFD2D3D4FFCFD0D2FF9AA3 CBFE3552CCFF193BCDFF1839CBFE1736CAFF1735C7FF1635C6FF1533C4FF1531 C3FF1330C2FF132EC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D23B4FF0E22B3FF1226B2FF4956B8FEB5B8CEFFD2D2D3FFD1D2D2FED3D3 D3FFD3D3D3FFD3D3D3FFD3D3D3FFD2D2D2FFD3D3D3FFD3D3D3FFD4D4D4FFD2D2 D2FFD3D3D3FFD3D3D3FFD2D2D3FFD2D2D3FFD2D2D3FED2D2D2FED2D2D2FDD3D3 D3FDBFBFBF7300000000A2A2A20CCCCCCCEFD1D1D1F9CFCFCFFCCFD0D3FECFD0 D3FED0D0D0FFD3D2D1FFD4D4D3FFD3D3D4FED2D2D2FFD2D2D2FFD3D3D3FED3D3 D3FFD3D3D3FFD3D3D3FFD2D2D2FFD2D2D2FFD3D3D3FFD2D2D2FFD1D1D2FFC7C9 CFFE8893C9FF2947CCFF193ACBFE1737C9FF1736C8FF1635C7FF1533C5FF1532 C4FF1430C2FF132EC0FF122CBDFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D24B4FF1124B2FF3C4BB6FFAAAECFFED1D2D5FFD2D2D2FFD3D3D3FED2D2 D2FFD3D3D3FFD3D3D3FFD3D3D3FFD2D2D2FFD3D3D3FFD2D2D2FFD2D2D3FFD2D2 D2FFD4D4D4FFD5D5D4FFD4D4D2FFCECED1FFCCCCD0FECDCDD0FED0D0D0FAD1D1 D1F9BEBEBE7100000000A4A4A408C7C7C7A9CFD0CFC0B7B4C0E8A1B0DAFE9EAD D9FEA2ADD2FEACB5D1FEB9BED1FEC6C8D0FECECED0FED0D1D1FED1D1D2FED1D1 D1FED2D2D2FED2D2D2FED2D2D2FED2D2D2FED2D2D2FED2D2D2FED1D1D1FED1D1 D2FEC1C4D0FE7181C7FE203FCAFE1837C9FE1736C8FE1635C7FE1433C5FE1432 C4FE1430C2FE132EC0FE122CBEFE1129BCFE1129BAFE1027B8FE0F26B7FE0E25 B6FE1025B5FE2B3CB4FE959BC6FECCCDD1FED0D0D1FED1D1D1FED1D1D1FED2D2 D2FED2D2D2FED2D2D2FED2D2D2FED1D1D1FED1D1D1FED1D1D2FED2D2D3FECECE D1FEC0C1CEFEAFB0C9FEA4A4C3FE9292BDFE8C8CBAFE9293BCFECAC8CBCDCDCC CDB4BDBDBD4F0000000000000000EFF0F109ECEAF03B7C6C9CBB3E6BF1FE3361 ECFE2F5DEBFF335CE2FF516FD3FF7D8FCDFE9EAAD1FFB3BAD1FFCCCDCFFED2D2 D2FFD1D1D1FFD2D2D1FFD1D1D1FFD1D1D1FFD2D2D2FFD1D1D1FFD1D1D1FFD0D0 D0FED0D0D0FFABB1CDFF4B61C7FE1A39C9FF1736C8FF1635C6FF1533C4FF1532 C4FF1430C2FF132DC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B7FE0F26 B6FF182CB5FF7780C0FFC5C7D0FFD1D1D3FED1D1D1FFD1D1D1FFD1D1D1FED1D1 D1FFD2D2D2FFD1D1D1FFD1D1D2FFD0D0D1FFD3D3D3FFC4C5CDFFACAECAFF9194 C1FF5458A9FF1B219AFF030695FF020494FF020392FE15199CFEC3B5C864F1F0 F113C9C9CA010000000000000000F4F4F50EEDEBF03F7E709DBC4570F0FD3A66 ECFD3562EAFE315DE8FE2D59E7FE2955E5FD3259DEFE5471D6FE96A3CEFDC1C4 D2FED0D0D1FED0D0D1FED0D0D0FED1D1D1FED1D1D1FED1D1D1FED1D1D1FED0D0 D0FDCFD0D0FECDCDCFFE959FC9FD2F4AC6FE1836C8FE1635C7FE1533C4FE1532 C3FE142FC2FE122DBFFE122CBDFE112ABBFE1128BBFE1027B9FE1027B8FD1027 B6FE4555B9FEABB0CAFED0D0D1FECFCFD0FDD1D1D1FED0D0D0FED0D0D0FDD1D1 D1FED1D1D1FED0D0D0FED0D0D1FECDCED0FEBABCCCFE777BB6FE2C34A3FE0811 9BFE020A99FE020A98FE020A96FE020895FE010593FD171C9DFDC3B5C868F3F2 F318D7D7DA020000000000000000FCFDFD0BEFECF13D7E6F9CBB4A73F1FD3F69 EDFD3864ECFF345EE9FF305BE7FF2D57E5FD2A55E3FF2651E2FF2E55DDFD7388 CFFFB2B9CFFFCFCECEFFCFCFCFFFD0D0CFFFCFCFCFFFD0D0D0FFCFCFCFFFCFCF CFFDCFCFCFFFCECED0FFB8BBCBFD6173C5FF1837C8FF1735C6FF1533C5FF1532 C4FF1430C1FF132DC0FF122CBEFF112ABCFF1129BBFF1027B9FF1128B8FD1F34 B7FF9097C6FFCECFD0FFCECECFFFD0D0CFFDCFCFCFFFD0D0D0FFCFCFCFFDCFCF D0FFCFCFD0FFCECECFFFCCCCCFFFA3A6C7FF4E55ACFF0D169FFF050F9DFF040D 9BFF030C9AFF010A98FF010795FF000694FF000392FD161B9CFDC3B4C766F7F6 F715000000000000000000000000FCFDFD0CEFEDF23E80709DBC527AF2FD466E EEFD3F68EBFF3862EAFF345EE8FF2F5AE6FD2B56E3FF2853E1FF2851E0FD2C53 DCFF5A75D1FFB4BACDFFCECECFFFCECFCEFFCFCFCFFFCFCFCFFFCFCFCFFFCECE CEFDCECFCFFFCDCDCEFFCCCDCCFD949DC6FF2E49C5FF1635C6FF1533C5FF1431 C4FF1330C1FF132EC0FF112BBEFF112ABCFF1129BBFF1128B9FF0F26B8FD4E5C BCFFAEB2CAFFCECECFFFCECECEFFCFCFCFFDCFCFCFFFCFCFCFFFCECECEFDCFCF CFFFCDCDCFFFCBCBCEFFA2A4C4FF323BA9FF0A16A1FF06119FFF040E9DFF030C 9BFF010A99FF010998FF000896FF010795FF000493FD171C9DFDC3B5C867F8F6 F815F4F4F9010000000000000000FDFDFE0BEFEDF13E81729DBB5C82F2FD4E75 EEFD466FECFF3F69EAFF3962E8FF345EE7FD2F59E4FF2B55E2FF2952E0FD2750 DEFF2C52DCFF627BD2FFBEC1CDFFCDCECEFFCECECEFFCECECEFFCECECEFFCECE CEFDCECECEFFCDCDCDFFCDCECEFDB8BBC8FF6273C1FF1837C6FF1633C5FF1532 C3FF142FC1FF132EBFFF122CBDFF112ABBFF1129BAFF1129B9FF172CB8FD7D86 C2FFC6C7CBFFCCCDCDFFCDCDCEFFCECECDFDCECECEFFCECECEFFCDCDCDFDCDCD CDFFCCCCCFFFA6A9C4FF3A43ABFF0C18A2FF0611A0FF04109EFF030D9DFF030C 9BFF020B9AFF010A98FF010896FF010795FF000593FD171C9DFDC3B4C866F8F6 F816F4F4FA010000000000000000FDFDFE0CF0EDF23E83739DBC668AF3FE5A7E EFFE5076EDFF486FEBFF4168E9FF3B63E7FE355EE5FF3159E3FF2D55E1FE2A52 DFFF274FDDFF3255D9FF7C8ECCFFC8CACEFFCCCCCCFFCDCDCDFFCDCDCDFFCDCD CDFECDCDCDFFCDCDCDFFCCCCCDFEC6C7CBFF808CC6FF213EC5FF1634C5FF1431 C3FF1330C2FF132EC0FF122CBEFF112ABCFF1129BBFF1028B9FF3C4DB9FEA3A8 C6FFCECECDFFCCCDCDFFCDCDCDFFCECECEFECECECEFFCECECEFFCDCDCDFECCCC CDFFBDBECAFF4F58B0FF101EA4FF0713A2FF0511A0FF04109FFF040E9DFF030C 9BFF030B9AFF020B98FF020996FF020895FF000593FE171C9DFEC2B5C867F8F6 F816F4F4F9010000000000000000FDFEFE0BF0EDF23D83739DBC6C8DF3FD6587 F0FD5D80EEFF5479ECFF4B71EAFF456BE8FD3E65E6FF385FE3FF335AE2FD2F56 E0FF2C52DEFF2A4FDCFF4464D6FFA6AECCFFCDCCCEFFCBCCCCFFCCCCCCFFCCCC CCFDCCCCCCFFCCCCCCFFCBCCCCFDCACACBFF969EC7FF364FC3FF1634C5FF1531 C3FF1330C1FF132EC0FF122CBEFF112ABCFF122ABBFF1229BAFF6672BDFDBCBE C9FFCCCCCCFFCCCCCCFFCDCDCDFFCCCCCCFDCDCDCDFFCCCCCCFFCBCBCCFDCACB CCFF787DB7FF1A27A7FF0615A3FF0613A2FF0511A0FF04109EFF040F9DFF040D 9BFF030C9AFF030B98FF020996FF020896FF010694FD191E9EFDC2B4C766F8F6 F815F5F5FA010000000000000000FDFEFE0CF0EDF23D83739DBC6C8DF3FE698A F0FE6688EFFF6082EDFF597CEBFF5174E9FE496DE7FF4167E5FF3C61E2FE365C E1FF3157DFFF2E53DDFF3457D8FF6C81CFFFCCCCCCFFCACBCBFFCBCCCCFFCBCB CBFECCCCCCFFCCCCCBFFCBCBCBFECACACBFFB0B4C5FF5669C0FF1432C5FF1733 C3FF1430C2FF142FC0FF132DBEFF122BBCFF122BBBFF1930B9FF7D87C2FEC5C6 CBFFCACACBFFCBCBCBFFCCCCCCFFCBCBCBFECCCCCCFFCBCBCBFFCACACBFEB8B8 C6FF3642ADFF0A18A5FF0815A3FF0714A2FF0612A0FF05109EFF050F9DFF040E 9CFF040D9BFF030C99FF040B98FF040A96FF040994FE1C219FFEC2B4C767F8F6 F816F5F5FA010000000000000000FDFEFE0CF0EEF23E84749DBC6D8EF4FE6989 F0FE6888EFFF6787EEFF6484ECFF5F7EEBFE5678E9FF4E71E6FF476AE4FE4064 E2FF3B5FE0FF375ADEFF3155DBFF4B68D7FFB2B7CAFFCBCBCCFFCBCBCBFFCCCC CBFECBCBCBFFCBCBCBFFCBCBCBFECACACBFFC2C2C4FF727EBFFF1734C5FF1733 C3FF1430C2FF142FC0FF132DBEFF122CBCFF132CBBFF253ABAFF8B93C5FEC9CA CCFFCACBCBFFCBCBCCFFCCCCCCFFCBCBCBFECCCCCCFFCBCBCBFFCDCDCDFE8B8F BBFF2431A9FF0A18A6FF0815A4FF0714A3FF0713A1FF06129FFF06119EFF0710 9CFF060F9BFF060E9AFF070E98FF080E97FF090D96FE2026A0FEC2B4C767F7F6 F716F5F5FA010000000000000000FDFDFD0CEFEDF13D84739DBC6D8EF4FE6A8A F1FE6888F0FE6787EEFE6886EDFE6785ECFE6281EAFE5D7DE8FE5676E6FE4F6F E4FE486AE2FE4264E0FE3C5EDEFE4766DAFE8B99D0FECACACBFECACACBFECBCB CAFECBCBCBFECBCBCBFECACACAFEC9C9CAFEC7C7C5FE838DC0FE2540C5FE1A36 C4FE1733C2FE1631C1FE152FBFFE152DBDFE142CBCFE3347BAFE969CC3FEC9C9 CAFEC9CACAFECACACAFECBCBCBFECACACAFECBCBCBFEC9C9CAFED0D0CDFE5860 B3FE1422A8FE0C19A6FE0B17A5FE0A16A3FE0A15A2FE0A15A0FE0A149FFE0B14 9EFE0B139DFE0B139CFE0C139BFE0E149AFE0F1499FE272CA3FEC2B3C766F8F6 F815F5F5FA010000000000000000FDFEFE0CEFEDF13E84749DBC6C8DF4FE6989 F0FE6988F0FF6788EEFF6886EDFF6785ECFE6685EAFF6584E9FF6280E8FE5D7C E6FF5876E4FF5270E2FF4B6BE0FF4C6ADDFF798CD4FFC9CACBFFC8C9CAFFCACA CAFECACACAFFCACACAFFCACAC9FEC9C9CAFFC8C7C7FF8D96C1FF334CC4FF1F3B C5FF1C37C3FF1A35C1FF1933BFFF1832BEFF162FBDFF4455B9FFA1A5C3FEC9C9 C9FFC9C9C9FFCACACAFFCACACAFFCACACAFECACACAFFC8C8C9FFC6C6C8FE3D48 B1FF0F1EA9FF0F1DA7FF0E1BA6FF0F1BA5FF0F1BA3FF0F1AA2FF101AA1FF111A A0FF111AA0FF131B9FFF151B9EFF171D9EFF191E9DFE3135A8FEC1B3C767F7F6 F816F5F6FA010000000000000000FDFEFE0CF0EEF23E84749DBC6D8EF3FE6A8A F1FE6989F0FF6888EFFF6887EDFF6785ECFE6585EAFF6584E9FF6482E8FE6481 E7FF637FE6FF5F7CE5FF5C78E3FF5A75DFFF7C8FD6FFC8C9CCFFC7C8C9FFC9C9 C9FEC9C9C9FFC9C9C9FFC9C9C8FEC8C8C8FFC7C7C7FF989FC3FF445AC3FF2741 C7FF243EC5FF223BC3FF1F39C1FF1F37BFFF1B33BEFF5564BBFFACAFC2FEC8C8 C8FFC8C8C8FFC9C9C8FFC9C9C9FFC9C9C9FEC8C8C8FFC7C8C9FFACAFC2FE3441 B1FF1422ABFF1523AAFF1522A9FF1623A8FF1723A6FF1723A5FF1923A5FF1A24 A4FF1C24A4FF1F26A4FF2128A4FF2429A4FF282CA4FE4145AEFEC1B2C667F7F5 F815F6F6FB010000000000000000FDFEFE0CEFEEF13D84749CBB6C8EF3FE6A8A F0FE6988F0FE6787EFFE6987EEFE6785ECFE6684EBFE6684E9FE6582E8FE6481 E7FE6480E6FE647FE5FE647EE4FE657DE1FE8394D8FEC8C9CDFEC7C8C9FEC9C9 C9FEC9C9C9FEC9C9C9FEC8C8C8FEC8C8C8FEC7C7C7FEA3A9C4FE576AC6FE334C CAFE2F48C8FE2D45C6FE2A42C4FE2A40C2FE243CC1FE6572BDFEB4B7C3FEC8C8 C8FEC8C8C8FEC9C9C8FEC9C9C9FEC9C9C9FEC8C8C8FEC7C8C9FE9C9FBFFE3844 B3FE1F2DAFFE202EAEFE212DADFE222EACFE242EABFE242FAAFE2730AAFE2932 ABFE2C34ABFE2F36ABFE3339ABFE383CACFE3D40ACFE5357B6FEC0B2C667F7F5 F816F7F7FB010000000000000000FDFEFE0CEFEEF23E84749DBC6C8DF4FE6989 F0FE6989F0FF6888EFFF6987EEFF6785ECFE6685EBFF6684EAFF6583E8FE6482 E8FF6480E6FF647EE5FF647EE3FF667EE1FF8596D9FFCACBCEFFCACACBFFCBCB CBFECBCBCBFFCBCBCBFFCBCBCBFECACACAFFCBCBCAFFA8AEC8FF6375C8FF445B CEFF4057CCFF3D53CBFF3A50C8FF394EC6FF3348C5FF7480C1FFBCBDC6FECACA CBFFCACACAFFCBCBCBFFCBCBCBFFCBCBCBFECACACAFFCACACBFF9FA3C2FE4550 B8FF303CB5FF313EB4FF333DB3FF343EB2FF3740B2FF3942B2FF3C44B2FF3E46 B3FF4148B2FF444AB2FF474CB3FF4A4EB3FF4C4FB3FE5E62BBFEBFB1C667F7F5 F816F7F7FB010000000000000000FDFEFE0CF0EEF23E84749DBC6D8EF3FE6A8A F1FE6989F0FF6888EFFF6987EDFF6886EDFE6685EBFF6684EAFF6583E9FE6582 E8FF6581E6FF647FE5FF647EE4FF677FE1FF8899DAFFCECFD2FFCECECFFFCFCF D0FECFCFCFFFD0D0D0FFCFCFCFFECFCFCFFFCECECEFFA9AFCAFF6A7BCDFF576B D3FF5368D1FF5165D0FF4E62CDFF4E60CCFF495CCBFF7984C4FFBBBDC8FECECF CFFFCFCFCFFFD0D0CFFFD0D0D0FFD0D0CFFECFCFCFFFCFCECFFFA5A8C4FE5761 BDFF4550BDFF4752BCFF4851BBFF4952BAFF4A53B9FF4C54B9FF4D54B8FF4E54 B8FF4E54B7FF4F54B7FF4F54B6FF4F53B5FF4E52B4FE5F63BBFEBFB1C667F7F5 F716F7F7FB010000000000000000FDFDFD0CEFEEF13E84739DBC6D8EF4FE6A8A F1FE6989EFFE6888EEFE6987EEFE6886EDFE6685EBFE6684EAFE6683E9FE6582 E7FE6581E7FE657FE5FE647EE4FE6981E1FE909FDAFED1D2D3FED2D2D3FED2D2 D3FED3D3D3FED3D3D3FED2D2D2FED2D2D2FED0D0D0FEA7ADCCFE697BD0FE5E71 D5FE5C6FD3FE5B6ED2FE5A6DD1FE5A6CD0FE5869D0FE7B86C7FEB9BCCBFED2D2 D2FED2D2D2FED3D3D2FED3D3D3FED3D3D2FED2D2D2FED2D2D2FEB8BAC8FE6770 C3FE525CC2FE535DC0FE525CBFFE525BBEFE525BBCFE525ABBFE5158BAFE5157 B9FE5056B8FE4F55B7FE4F54B5FE4E53B5FE4E52B4FE5F62BBFEBFB1C667F7F5 F716F7F7FB010000000000000000FDFEFE0CEFEDF23E84749DBC6D8EF4FE6A8A F1FE6989F0FF6887EFFF6987EEFF6886EDFE6585EBFF6584E9FF6683E9FE6582 E7FF6580E7FF657FE5FF647EE3FF6D84E0FFA0ABD6FFD5D5D6FFD6D6D6FFD6D6 D6FED7D7D7FFD7D7D7FFD6D6D6FED6D6D6FFD2D2D1FFA3ABCDFF6578D4FF5E71 D5FF5C6FD4FF5B6ED2FF5B6DD1FF5B6DD0FF5B6BD0FF7681CAFFB6BACEFED5D5 D6FFD6D6D6FFD6D6D6FFD7D7D7FFD6D6D6FED6D6D6FFD5D5D6FFD0D0D0FE767E C5FF5560C2FF545EC0FF525CBEFF525BBDFF525ABCFF5259BBFF5158BAFF5157 B9FF5056B8FF4F55B7FF5055B6FF4F54B6FF4F53B5FE6063BCFEBFB0C667F7F5 F815F8F8FC010000000000000000FCFDFD0CF0EEF13E84749CBC6C8EF4FE6A8A F1FE6989F0FE6787EFFE6987EEFE6886ECFE6685EAFE6683EAFE6683E9FE6582 E8FE6581E7FE657FE5FE637EE4FE758BDEFEBDC1D0FED9D9DAFED9D9D9FEDADA DAFEDADADAFEDADADAFED9D9D9FED9D9DAFED1D1D2FE98A2CDFE5E73D7FE5E72 D6FE5C70D4FE5B6ED3FE5B6DD1FE5B6CD0FE5B6CCFFE6A77CBFEAEB3D0FED8D8 D9FED9D9D9FED9D9D9FEDADADAFED9D9D9FEDADADAFED9D9D9FEDBDBD9FE8E94 C5FE5C66C1FE555FC0FE535CBFFE535CBEFE535BBDFE535ABCFE5259BBFE5258 BAFE5157B9FE5056B8FE5055B6FE4E54B6FE4F52B5FE6062BCFEBFB1C667F7F5 F816F8F8FC010000000000000000FCFDFD0CF0EEF23E84749DBC6D8EF4FD6A8A F1FD6889F0FE6888EFFE6887EEFE6786EDFD6685EBFE6684E9FE6583E9FD6582 E7FE6580E7FE6580E5FE6881E1FE8D9CD8FEDAD9DAFEDEDEDEFEDFDFDFFEDFDF DFFDDFDFDFFEDFDFDEFEDEDEDEFDDDDEDEFEC9CBD4FE8894CEFE5D71D7FE5E72 D6FE5C70D4FE5C6ED3FE5C6ED1FE5B6DD1FE5C6CD0FE6371CCFEA7ADD1FDD9D9 DBFEDEDEDEFEDEDEDEFEDFDFDFFEDFDFDFFDDFDFDFFEDEDEDEFEDFDFDFFDB4B7 CFFE6971C4FE555FC1FE535DBEFE535CBEFE535BBCFE5359BCFE5259BBFE5258 BAFE5157B9FE5056B8FE5055B6FE4F53B6FE4F53B5FD6063BCFDBFB1C666F7F5 F816F8F8FC010000000000000000FCFDFD0CEFEEF23E84749DBC6C8EF3FE6989 F0FE6989F0FF6888EFFF6987EDFF6785ECFE6685EBFF6684EAFF6582E8FE6582 E8FF6581E6FF6580E5FF768CE0FFB8BFD8FFE3E3E4FFE2E2E2FFE3E3E3FFE3E3 E3FEE3E3E3FFE3E3E2FFE2E2E2FEE0E1E2FFBBC0D9FF7585D2FF5E73D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5C6CD0FF5E6ECEFF989FCBFED5D5 D9FFE2E2E3FFE2E2E2FFE3E3E3FFE3E3E3FEE3E3E3FFE2E2E2FFE1E1E2FED6D6 DBFF7D84C6FF5861C0FF535DBFFF525CBEFF535BBDFF535ABCFF5259BBFF5258 BAFF5157B9FF5056B8FF5055B6FF4F54B6FF4E52B4FE5F62BBFEBFB1C567F6F5 F816F8F8FC010000000000000000FDFEFE0CF0EEF23E84739DBC6D8EF4FE6A8A F1FE6888EFFF6888EFFF6887EEFF6886EDFE6685EBFF6683E9FF6583E9FE6581 E7FF6581E7FF6983E3FF92A1D8FFDADBE0FFE3E3E4FFE5E5E4FFE4E4E4FFE5E5 E5FEE5E5E5FFE4E4E4FFE4E4E4FEE0E0E2FFAEB6DAFF677AD4FF5E73D6FF5E72 D5FF5C6FD5FF5C6FD3FF5C6ED1FF5B6DD1FF5B6CD0FF5C6BCEFF828BC5FEC8C9 D5FFE3E3E4FFE4E4E4FFE4E4E4FFE4E4E4FEE5E5E5FFE5E5E5FFE4E4E4FEE3E3 E3FFB6B9D1FF6971C1FF545EBEFF535DBEFF535BBDFF535ABCFF5258BAFF5258 BAFF5157B8FF5056B8FF5055B6FF4F54B6FF4F53B4FE6063BCFEBFB1C667F6F5 F816F8F8FC010000000000000000FDFEFE0BF0EEF23D84739CBB6D8EF4FD698A F1FD6888EFFF6787EFFF6886EDFF6886EDFD6584EAFF6583EAFF6583E9FD6682 E7FF6883E6FF8296DDFFC8CCDAFFE3E4E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5 E5FDE5E5E5FFE4E4E4FFE5E4E5FDD6D7DDFF98A2D2FF6175D6FF5E73D6FF5E71 D5FF5D6FD5FF5B6ED2FF5B6DD1FF5B6DD1FF5B6CCFFF5C6BCEFF6774CAFDAEB3 D0FFDFDFDFFFE4E4E4FFE4E4E4FFE4E4E4FDE5E5E5FFE5E5E5FFE5E5E5FDE4E4 E4FFDEDEE0FF999EC8FF5D66BFFF535DBFFF535BBCFF525ABBFF5259BAFF5258 BAFF5056B9FF4F55B7FF4F55B5FF4F54B5FF4F53B5FD6063BCFDBEB0C567F6F4 F716F7F7FB010000000000000000FDFEFE0CF0EDF23E83749DBC6D8EF3FE6A8A F1FE6989F0FF6888EFFF6887EEFF6786ECFE6685EBFF6684E9FF6683E8FE6783 E7FF788EDFFFBCC3D8FFE2E2E2FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5 E5FEE5E5E5FFE4E4E4FFE4E3E4FEBEC3DAFF7585D3FF5F74D7FF5E72D6FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6BCEFF5B6ACDFE8E96 CBFFD0D1DAFFE4E4E4FFE4E4E4FFE5E5E5FEE5E5E5FFE5E5E5FFE5E5E5FEE5E5 E5FFE3E3E4FFD3D3DDFF8F94C4FF5B65BEFF545CBDFF535ABCFF5259BAFF5258 BAFF5157B9FF5056B8FF5055B6FF4F54B6FF4F53B5FE6063BCFEBEB0C567F6F4 F716F8F8FB010000000000000000FDFDFE0BEFEDF23D84749CBB6C8EF4FE6989 F1FE6888F0FE6787EFFE6886EDFE6886ECFE6685EAFE6684EAFE6784E8FE8195 DDFEBAC2DCFEE0E1E2FEE4E4E4FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5 E5FEE5E5E5FEE4E4E4FED7D9E0FE9DA7D7FE6276D8FE5F74D7FE5E72D6FE5D71 D6FE5D6FD5FE5C6FD2FE5C6ED1FE5B6CD0FE5B6CD0FE5B6ACEFE5B6ACDFE6D7A C8FEB8BCD4FEE2E2E2FEE4E4E4FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5 E5FEE5E5E5FEE4E4E4FED1D2DBFE9599C7FE5D65BCFE535BBCFE535ABBFE5258 B9FE5157B8FE4F55B7FE4F54B6FE4E53B6FE4E52B5FE5F63BCFEBAAABF68F6F4 F615000000000000000000000000F8F8F80DEFEDF33E8376AEBC6D8EF3FD6A8A F0FD6989EFFF6888EEFF6987EDFF6887ECFD6886EAFF6F8BE5FF96A5D8FDCBCF E1FFE0E0E2FFE5E5E6FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6E6FFE5E5E5FFE5E5 E5FDE4E4E4FFE4E4E4FFC0C6DEFD7888D4FF6074D9FF5F74D8FF5E72D6FF5D71 D6FF5D70D4FF5C6FD3FF5C6ED1FF5B6CD1FF5B6CD0FF5B6ACEFF5B6ACDFD5B6B CCFF9198C7FFD1D2D9FFE3E3E4FFE5E4E4FDE5E5E5FFE5E5E5FFE5E5E5FDE5E5 E5FFE5E5E5FFE5E5E5FFE4E4E5FFD4D5DEFFAFB1CEFF6B72BEFF565DBAFF5359 BAFF5258B9FF5157B8FF5055B6FF4F54B6FF4F53B5FD6165BCFDA892A86FF1ED F017E1E1E3010000000000000000F5F5F60BEEECF43D8278BCBB6D8EF3FD698A F2FE6888F1FE6586F0FF6686EDFF768FE0FD9AAADBFFB9C2E1FFD3D6DEFDE4E4 E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5 E5FDE4E4E4FFD1D4DDFF94A0D5FD6378D8FF6074D8FF5F74D8FF5E72D6FF5E71 D6FF5C70D5FF5B6FD3FF5B6ED2FF5B6CD1FF5B6CD0FF5B6ACEFF5A6ACDFD5969 CDFF6875C9FFAFB4D1FFDDDEE0FFE4E4E4FDE5E5E5FFE5E5E5FFE5E5E5FDE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E5FFDFDFE1FFC2C4D8FFA4A6CBFF7A7D B9FF5A5EB3FF4E54B7FF4E53B6FF4E53B6FE4F53B5FE6064BEFDA28AA171EFEB EE15D0D0D10100000000A7A7A704C9C9C957DBDBDB7C9F99C2D18CA3E5FE8EA1 DFFE96A6DCFFA2B0DBFFB6BEDAFFC9CFE1FED7D9E1FFE0E1E3FFE5E5E5FEE4E4 E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E4FFE4E4 E4FEDCDDE2FFACB4D8FF6A7FD8FE6075DAFF5F74D9FF5F74D8FF5D71D7FF5D71 D5FF5D6FD4FF5B6ED3FF5B6DD1FF5B6CD0FF5B6CCFFF5B6ACDFF5A6ACDFE5A6A CCFF5A6ACCFF7A85C6FFC5C8D7FFE4E3E3FEE4E4E4FFE5E5E5FFE5E5E5FEE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E4FFE5E5E5FFE4E4E4FFDBDBDFFFD0D0 DCFFBDBDD1FFA4A6C5FF9194BEFF8587BDFF797BBBFE8385C1FEB7ACB7A0D0D0 D062B9B9B927000000009F9F9F0BD7D7D7D1E2E2E2E1D6D5DCF4D0D5E3FED1D5 E2FED4D7E0FED9DADFFFE0E0DFFFE5E5E4FEE5E5E5FFE5E5E5FFE4E5E5FEE5E5 E5FFE5E5E5FFE6E6E6FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE4E4E4FFE0E0 E1FEBBC1D8FF7688D7FF6177DBFE6075D9FF5F74D8FF5F73D8FF5E72D7FF5E72 D6FF5D70D4FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6ACEFF5A6ACDFE5969 CDFF5868CBFF5D6CC8FF8991CAFFCDCFDCFEE3E3E4FFE5E4E4FFE6E6E6FEE5E5 E5FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E4FFE4E4E4FFE6E6 E6FFE4E4E3FFDCDCDEFFD5D5DBFFD1D1DBFECCCDDBFECDCEDBFEDCDADCE9E1E1 E1DCC4C4C462000000009E9E9E0CD8D8D8F3E5E5E5FDE3E3E4FDE4E4E5FEE4E4 E5FEE4E4E5FEE3E3E4FFE4E4E5FFE4E4E4FDE4E4E4FFE5E5E5FFE5E5E5FDE5E5 E5FFE5E5E5FFE4E4E4FFE5E5E5FFE5E5E5FFE4E4E4FFE3E3E4FFE2E2E3FFC6CA DBFD8292D5FF6279DBFF6077DAFD5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CCFFF5B6ACEFF5A6ACDFD5969 CDFF5868CBFF5968CAFF606DC8FF979ECBFDD5D6DDFFE3E4E4FFE4E4E4FDE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E4FFE4E4 E4FFE4E4E4FFE4E4E4FFE4E4E4FFE4E4E5FEE4E4E5FEE4E4E4FEE4E4E4FDE5E5 E5FDC6C6C673000000009E9E9E0CD8D8D8F4E5E5E5FDE5E5E5FDE6E6E6FEE6E6 E6FEE6E6E6FFE5E5E5FFE5E5E5FFE6E6E6FEE6E6E6FFE6E6E6FFE6E6E6FEE6E6 E6FFE5E5E5FFE5E5E5FFE6E6E6FFE5E5E5FFE4E5E5FFE3E3E4FFC8CCDCFF8191 D5FE667CDBFF6078DCFF6077DBFE5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6DD2FF5B6DD1FF5B6CD0FF5B6ACEFF5A69CDFE5969 CDFF5868CBFF5867CAFF5966C9FF636FC8FE9A9FCBFFD6D6DEFFE4E4E5FEE5E5 E5FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FEE5E5E5FEE5E5E5FDE5E5 E5FEC6C6C673000000009E9E9E0DD9D9D9F5E6E6E6FEE6E6E6FEE7E7E7FEE7E7 E7FEE7E7E7FEE6E6E6FEE6E6E6FEE7E7E7FEE7E7E7FEE6E6E6FEE7E7E7FEE6E6 E6FEE6E6E6FEE6E6E6FEE5E6E6FEE5E5E5FEE3E3E2FEC3C7D8FE8092D9FE647C DCFE6179DCFE6077DBFE6076DBFE5F74DAFE5F74D9FE5F74D7FE5E72D7FE5E72 D6FE5D70D5FE5C6FD3FE5C6ED2FE5B6DD1FE5B6BD0FE5B6ACEFE596ACDFE5869 CDFE5868CBFE5867CBFE5865C8FE5865C8FE636FC6FE9198C9FED4D5DFFEE5E5 E6FEE4E4E5FEE6E6E6FEE6E6E6FEE6E6E6FEE6E6E6FEE6E6E6FEE6E6E6FEE7E7 E7FEE7E7E7FEE7E7E7FEE7E7E7FEE7E7E7FEE7E7E7FEE6E6E6FEE6E6E6FEE6E6 E6FEC6C6C674000000009E9E9E0DD8D8D8F5E6E6E6FEE6E6E6FEE7E7E7FFE7E7 E7FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FEE6E6E6FFE6E6E6FFE7E7E7FEE7E7 E6FFE6E6E5FFE5E5E6FFE4E5E5FFDDDEE2FFB3BBDAFF798CDCFF647DDEFF617A DEFE6179DCFF6077DCFF6077DBFE5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6ACEFF5A6ACDFE5969 CDFF5868CBFF5867CAFF5865C9FF5864C7FE5764C6FF5E6AC5FF868CC4FEC7C8 D8FFE3E3E5FFE5E5E6FFE5E5E5FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7E7FFE6E6 E6FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7E7FFE7E7E7FFE6E6E6FFE6E6E6FEE6E6 E6FFC6C6C674000000009E9E9E0DD9D9D9F5E6E6E6FEE6E6E6FEE7E7E7FEE7E7 E7FFE7E7E7FEE6E6E6FFE7E7E7FFE7E7E7FEE7E7E7FFE6E6E6FFE7E7E7FEE6E6 E6FFE5E6E6FFE6E6E6FFCFD2DDFF919FD9FF7187DFFF647CE0FF627BDFFF617A DDFE6178DCFF6077DCFF5F77DAFE5F74D9FF5F74D8FF5F74D8FF5E72D6FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6CD1FF5B6CD0FF5B6ACDFF5A6ACCFE5969 CDFF5868CBFF5866CBFF5865C8FF5764C8FE5764C6FF5662C5FF5C67C2FE7078 C6FFA4A8C8FFDCDDE0FFE6E6E6FFE4E5E6FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FEE7E7E7FFE6E6E6FEE6E6E6FEE6E6 E6FFC7C7C774000000009E9E9E0CD8D8D8F4E6E6E6FDE6E6E6FDE7E7E7FEE7E7 E7FEE6E6E7FFE6E6E6FFE6E6E7FFE6E6E7FEE6E6E7FFE5E6E6FFE8E8E8FEE7E6 E7FFCDD0DCFFA4B1DCFF798EDDFF6780E1FF637DE1FF637CE0FF617BDEFF6079 DEFE6179DDFF6077DCFF5F76DBFE5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6ACEFF5969CCFE5969 CDFF5868CBFF5867CBFF5865C9FF5864C8FE5764C6FF5662C4FF5661C4FE5761 C3FF5E68C2FF7D84C4FFB0B2CFFFD7D7DBFFE8E8E7FFE7E7E8FFE6E6E7FFE6E6 E6FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7E7FFE7E7E7FEE6E6E6FEE6E6E6FDE6E6 E6FEC6C6C673000000009E9E9E0CD9D9D9F3E7E7E7FCE6E6E6FDE7E7E7FEE6E6 E7FEE6E7E7FEE6E6E7FEE5E6E7FEE6E7E7FDE6E7E9FEDEDFE3FEC3C8D6FD90A0 D8FE748DE4FE6C85E4FE657EE3FE647EE3FE637DE1FE637CE0FE617BDFFE617A DDFD6179DCFE5F77DBFE6076DBFD5E74D9FE5E73D8FE5E73D7FE5D72D6FE5D72 D5FE5D70D5FE5B6ED3FE5B6DD2FE5A6CD0FE5A6BCFFE5A69CDFE5A6ACDFD5869 CCFE5767CAFE5766CAFE5765C8FE5864C8FD5763C5FE5662C5FE5661C4FD5660 C3FE545FC2FE5862C0FE5F68C0FE6F76C4FE9DA0C5FEC7C8D1FEDCDCDFFEE4E4 E5FEE4E5E5FEE5E5E5FEE5E5E6FEE5E5E6FEE5E6E6FEE5E5E6FEE6E6E7FCE7E7 E7FDC7C7C77300000000A4A4A40CC6C6C6D8DADADAE6D2D1D6F2C9CCD7FDCCD0 DCFEC6CAD7FEB7BFD7FFAEB8D9FF9CACE0FD8A9EE3FF7C95E3FF718BE5FD6884 E6FF6481E7FF647FE5FF647EE3FF647EE2FF637CE1FF637CE1FF617BDFFF6179 DEFD6179DDFF6077DCFF6076DAFD5F75DAFF5F73D8FF5F73D7FF5E71D6FF5E71 D6FF5D70D5FF5B6FD3FF5B6ED2FF5B6DD1FF5B6BCFFF5B6ACDFF596ACCFD5969 CDFF5867CBFF5866CBFF5865C9FF5763C7FD5764C6FF5662C4FF5561C4FD5660 C3FF555FC2FF555FC1FF535DBFFF545DBEFF5A61BDFF646BBEFF7277C0FF8186 C3FF989AC7FFADAECAFFC1C2CFFFC0C0CCFEC7C8D3FEC7C6CFFDD0D0D1EBD2D2 D2E3BFBFBF6600000000A4A4A401C3C3C31CE0DFE235A599B894889AE0FD708F EFFE708EEEFE6F8CEDFF6E8BEBFE6C89EBFE6986E9FF6784E9FF6683E9FE6582 E8FF6581E6FF647FE4FF647EE3FF637DE3FF627CE2FF627CE1FF607BDFFF617A DEFE6078DDFF6077DCFF6077DBFE5F74D9FF5F73D9FF5F73D8FF5E72D7FF5E72 D5FF5D70D5FF5C6FD3FF5C6ED2FF5B6CD1FF5B6CD0FF5B6ACEFF5A6ACDFE5969 CDFF5868CBFF5867CBFF5865C9FF5864C8FE5764C5FF5762C5FF5661C5FE5660 C3FF545EC2FF555FC0FF535DBFFF535CBEFF535BBDFF535ABCFF545BBBFF565C BAFF575BBAFF585DB9FE595DB8FF585BB7FE5E63BBFE503C7CFDDCDAE05FD5D5 D523BEBEBE0D0000000000000000F2F2F402F7F5F81BC3BBCF6B696FB8FA7D9A F5FD6888F0FE6788EFFE6887EEFF6886ECFD6685EAFF6684E9FF6683E8FD6582 E7FF6481E7FF647EE5FF647EE4FF637DE3FF627CE2FF627CE1FF617BDEFF6179 DEFD6178DDFF6076DCFF6076DBFD5F74DAFF5F74D9FF5E73D8FF5D72D6FF5D71 D6FF5C70D5FF5C6FD3FF5B6ED2FF5B6DD1FF5A6CD0FF5A69CEFF5A6ACDFD5869 CDFF5868CAFF5867CAFF5765C9FF5764C8FD5663C6FF5662C4FF5661C5FD5560 C3FF555FC2FF555FC1FF525CBFFF535CBEFF535BBDFF535ABCFF5259BBFF5258 BAFF5156B9FF4F55B8FF4F54B6FE4D51B4FE5D5FB5FD593E75D8E6E1EA3BFCFC FD0C000000000000000000000000E9E8EA01FAFAFB13DBD4DD4D5C4678E08AA0 EDFD6786EEFD6889EEFE6887EEFE6886EDFD6685EAFE6584EAFE6582E9FD6481 E8FE6480E7FE657FE5FE657EE4FE647EE3FE637DE2FE637CE1FE617BDFFE617A DEFD6179DDFE6077DCFE6077DBFD5F75DAFE5F74D9FE5F74D8FE5E72D7FE5E72 D6FE5D70D5FE5C6FD3FE5C6ED2FE5B6DD1FE5B6CD0FE5B6ACEFE5A6ACDFD5969 CDFE5868CBFE5867CBFE5865C9FE5864C8FD5764C6FE5762C5FE5661C5FD5560 C3FE545EC2FE545EC1FE525CBFFE525BBEFE525ABDFE5259BCFE5259BBFE5258 BAFE5157B9FE5157B8FE4F54B5FE656AC0FC645B9EFDA99AB580F3F1F425F9F9 FA0600000000000000000000000000000000FBFBFC09F3F0F12EAD9BAA85645B 94FA93A8EFFD6989EEFD6787EDFE6785ECFD6684EAFE6683E9FE6682E8FD6581 E7FE6580E6FE647EE4FE647DE3FE637DE2FE627CE1FE627BE0FE617ADEFE6179 DDFD6178DCFE6076DBFE6076DAFD5F74D9FE5F73D8FE5E73D7FE5D71D5FE5D71 D5FE5C6FD4FE5C6ED2FE5B6DD1FE5B6CD0FE5A6BCFFE5A69CDFE5A69CCFD5968 CCFE5867CAFE5867CAFE5765C8FE5764C7FD5663C5FE5662C4FE5661C4FD5560 C2FE555FC1FE555FC0FE535DBEFE535CBDFE535BBCFE535ABBFE5259BAFE5258 B9FE5156B8FE5156B7FE6266BDFD7A74B2FD5D406CCFDCD6DF46FBFAFB100000 000000000000000000000000000000000000FBFAFB01FAFAFA14EBE7EA40A392 A791645388F48B97D7FD93ACF9FD7492F1FD6686ECFD6484EBFE6382EAFD6381 E9FE6581E9FE6D88E9FE6F89E8FE6F88E7FE6F88E6FE6F87E5FE6E86E3FE6E85 E2FD6D84E1FE6D82E0FE6C82DFFD6C81DEFE6C80DDFE6B7FDCFE6A7EDBFE6A7D DAFE697CD9FE687BD8FE687AD7FE6879D6FE6778D5FE6776D4FE6776D3FD6675 D2FE6574D1FE6573D0FE6471CEFE6470CDFD636FCCFE636ECBFE5E6AC8FD5560 C4FE535EC2FE525DC1FE515BBFFE505ABEFE515ABDFE5058BCFE5A61BFFE686E C4FE8186CFFE9297D5FD70649CFD6F5379CBCFC5CF5CF8F6F81FFBFAFB040000 00000000000000000000000000000000000000000000FDFCFD05FAF9FA16F0EE F137CFC7D560725A7FB365578BE5776EA0F47677B2FA7776B1F97775B2FA7775 B1FA7674B0FA7674AFFA7673AFFA7673AEFA7572AEFA7572ADFA7571ABFA7471 ABFA7571AAFA7470A9FA7470A9FA746FA9FA746EA8FA736EA8FA736DA7FA736D A7FA726DA6FA726CA6FA726BA5FA726BA4FA716AA4FA716AA3FA7169A3FA7168 A2FA7167A2FA7067A1FA7066A1FA7066A0FA7065A0FA70659FFA6F659EFA6F64 9DFA6F649DFA6F639CFA6E639CFA6D629BF96D629BFA6D619AFA6D6198F96C5F 97FA675384F6593B69E381647DA9D7CED753F8F6F824FBFBFB09000000000000 0000000000000000000000000000000000000000000000000000FBFBFB03FCFB FC0EF9F8FA1DE3DDE432DAD5DE4AD7D1DD5CCDC6D365A28D9C76A28D9C76A28D 9C76A18C9C77A28C9B77A18C9B77A28C9B76A28C9A77A28C9B77A18C9A77A28C 9B76A28C9B77A28C9A77A28C9A77A28C9A77A28C9A77A28C9A76A28B9A77A28C 9A77A18B9A76A18B9A77A28B9A77A28B9977A28A9977A28B9977A18A9977A28B 9877A28A9877A18B9876A18B9977A18B9976A18B9976A18A9877A18B9977A18B 9976A18B9977A18B9977A18B9976A18B9976A08A9877A18A9876A0899776B09E AB6FCFC6D161DCD5DD52EAE5E937FAF9FA1AFBFAFB09FCFCFC01000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F7F7F903FCFCFC08FBFBFC10FAF9FA17F7F6F718EEEAED18EEEAEC19EEE9 EC18EFEBED19EFEBED19EFEBED19EEEAEC19EFEBED19EFEBED19EFEBED19EEEA ED18EFEBED19EFEBED19EDE9EB18EFEBED19EFEBED19EFEBED19EFEBED19EFEB ED19EFEBED19EFEBED19EFEBED19EEEAEC18EFEBED19EFEBED19EEEAEC19EEEA EC19EEEAEC18EEEAEC19EFEBED19EEEAEC18EFEBED19EFEBED19EFEBED19EEEA EC19EFEBED19EFEBED19EEEAEC19EFEBED19EEEAEC19EEEAEC19EEEAEC19F2F0 F119F9F8F918FBFBFC14FDFCFD0BFAF9FA030000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F6F6F901F6F6F901F6F5 F801F7F6F901F6F6F901F6F6F901F6F5F801F6F6F901F6F6F901F6F6F901F6F6 F901F6F6F901F6F5F801F6F6F901F6F6F901F6F6F901F6F5F801F6F6F901F6F6 F901F6F6F901F6F6F901F6F6F901F6F6F901F6F5F801F6F5F801F6F5F801F6F5 F801F5F5F801F6F5F801F6F5F801F6F5F801F6F6F901F6F5F801F6F5F801F6F5 F801F6F6F801F6F5F801F6F5F801F6F5F801F6F5F801F6F5F801F6F5F801F6F5 F801000000000000000000000000000000000000000000000000000000000000 00000000000000000000FFFFFFFFFFFFFFFFFFC14000000003FFF80000000000 003FF00000000000001FE00000000000000FE000000000000007C00000000000 0003C00000000000000380000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001800000000000000180000000000000018000000000000003800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0003800000000000000180000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001000000000000000180000000000000038000000000000003C00000000000 0007C000000000000007E00000000000000FF00000000000000FFC0000000000 003FFFE00000000003FF } Hint = 'Double Commander - click to restore' OnClick = MainTrayIconClick OnDblClick = MainTrayIconClick left = 220 top = 168 end object pmTabMenu: TPopupMenu left = 392 top = 128 object miNewTab: TMenuItem Action = actNewTab OnClick = mnuTabMenuClick end object miRenameTab: TMenuItem Action = actRenameTab OnClick = mnuTabMenuClick end object miOpenDirInNewTab: TMenuItem Action = actOpenDirInNewTab OnClick = mnuTabMenuClick end object miLine14: TMenuItem Caption = '-' end object miCloseTab: TMenuItem Action = actCloseTab OnClick = mnuTabMenuClick end object miCloseAllTabs: TMenuItem Action = actCloseAllTabs OnClick = mnuTabMenuClick end object miCloseDuplicateTabs: TMenuItem Action = actCloseDuplicateTabs end object miLine19: TMenuItem Caption = '-' end object miTabOptions: TMenuItem Caption = 'Tab options' object miTabOptionNormal: TMenuItem Action = actSetTabOptionNormal GroupIndex = 1 RadioItem = True OnClick = mnuTabMenuClick end object miTabOptionPathLocked: TMenuItem Action = actSetTabOptionPathLocked GroupIndex = 1 RadioItem = True OnClick = mnuTabMenuClick end object miTabOptionPathResets: TMenuItem Action = actSetTabOptionPathResets GroupIndex = 1 RadioItem = True OnClick = mnuTabMenuClick end object miTabOptionDirsInNewTab: TMenuItem Action = actSetTabOptionDirsInNewTab GroupIndex = 1 RadioItem = True OnClick = mnuTabMenuClick end object miLine16: TMenuItem Caption = '-' end object miSetAllTabsOptionNormal: TMenuItem Action = actSetAllTabsOptionNormal end object miSetAllTabsOptionPathLocked: TMenuItem Action = actSetAllTabsOptionPathLocked end object miSetAllTabsOptionPathResets: TMenuItem Action = actSetAllTabsOptionPathResets end object miSetAllTabsOptionDirsInNewTab: TMenuItem Action = actSetAllTabsOptionDirsInNewTab end end object miLine21: TMenuItem Caption = '-' end object miNextTab: TMenuItem Action = actNextTab end object miPrevTab: TMenuItem Action = actPrevTab end object miLine23: TMenuItem Caption = '-' end object miSaveTabs: TMenuItem Action = actSaveTabs end object miLoadTabs: TMenuItem Action = actLoadTabs end object miSaveFavoriteTabs: TMenuItem Action = actSaveFavoriteTabs end object miLoadFavoriteTabs: TMenuItem Action = actLoadFavoriteTabs end object miLine26: TMenuItem Caption = '-' end object miConfigFolderTabs: TMenuItem Action = actConfigFolderTabs end object miConfigFavoriteTabs: TMenuItem Action = actConfigFavoriteTabs end end object pmTrayIconMenu: TPopupMenu left = 294 top = 193 object miTrayIconRestore: TMenuItem Caption = 'Restore' OnClick = miTrayIconRestoreClick end object miLine8: TMenuItem Caption = '-' end object miTrayIconExit: TMenuItem Caption = 'E&xit' OnClick = miTrayIconExitClick end end object pmLogMenu: TPopupMenu left = 440 top = 136 object miLogCopy: TMenuItem Caption = 'Copy' OnClick = miLogMenuClick end object miLine24: TMenuItem Caption = '-' end object miLogSelectAll: TMenuItem Tag = 1 Caption = 'Select All' OnClick = miLogMenuClick end object miLine25: TMenuItem Caption = '-' end object miLogClear: TMenuItem Tag = 2 Caption = 'Clear' OnClick = miLogMenuClick end object miLogHide: TMenuItem Tag = 3 Caption = 'Hide' OnClick = miLogMenuClick end end object Timer: TTimer Enabled = False Interval = 100 OnTimer = AllProgressOnUpdateTimer left = 704 top = 152 end object imgLstActions: TImageList left = 64 top = 224 end object imgLstDirectoryHotlist: TImageList left = 200 top = 224 end object pmFavoriteTabs: TPopupMenu Images = imgLstActions left = 128 top = 152 end end��������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmain.lrj����������������������������������������������������������������������0000644�0001750�0000144�00000145551�14743153644�015213� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":185879090,"name":"tfrmmain.caption","sourcebytes":[68,111,117,98,108,101,32,67,111,109,109,97,110,100,101,114],"value":"Double Commander"}, {"hash":234286985,"name":"tfrmmain.btnlefthome.hint","sourcebytes":[71,111,32,116,111,32,104,111,109,101,32,100,105,114,101,99,116,111,114,121],"value":"Go to home directory"}, {"hash":126,"name":"tfrmmain.btnlefthome.caption","sourcebytes":[126],"value":"~"}, {"hash":167727721,"name":"tfrmmain.btnleftup.hint","sourcebytes":[71,111,32,116,111,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,121],"value":"Go to parent directory"}, {"hash":782,"name":"tfrmmain.btnleftup.caption","sourcebytes":[46,46],"value":".."}, {"hash":229108969,"name":"tfrmmain.btnleftroot.hint","sourcebytes":[71,111,32,116,111,32,114,111,111,116,32,100,105,114,101,99,116,111,114,121],"value":"Go to root directory"}, {"hash":47,"name":"tfrmmain.btnleftroot.caption","sourcebytes":[47],"value":"/"}, {"hash":93897556,"name":"tfrmmain.btnleftdirectoryhotlist.hint","sourcebytes":[68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116],"value":"Directory Hotlist"}, {"hash":42,"name":"tfrmmain.btnleftdirectoryhotlist.caption","sourcebytes":[42],"value":"*"}, {"hash":134552684,"name":"tfrmmain.btnleftequalright.hint","sourcebytes":[83,104,111,119,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,114,105,103,104,116,32,112,97,110,101,108,32,105,110,32,116,104,101,32,108,101,102,116,32,112,97,110,101,108],"value":"Show current directory of the right panel in the left panel"}, {"hash":60,"name":"tfrmmain.btnleftequalright.caption","sourcebytes":[60],"value":"<"}, {"hash":126,"name":"tfrmmain.btnrighthome.caption","sourcebytes":[126],"value":"~"}, {"hash":782,"name":"tfrmmain.btnrightup.caption","sourcebytes":[46,46],"value":".."}, {"hash":47,"name":"tfrmmain.btnrightroot.caption","sourcebytes":[47],"value":"/"}, {"hash":93897556,"name":"tfrmmain.btnrightdirectoryhotlist.hint","sourcebytes":[68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116],"value":"Directory Hotlist"}, {"hash":42,"name":"tfrmmain.btnrightdirectoryhotlist.caption","sourcebytes":[42],"value":"*"}, {"hash":144103628,"name":"tfrmmain.btnrightequalleft.hint","sourcebytes":[83,104,111,119,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,108,101,102,116,32,112,97,110,101,108,32,105,110,32,116,104,101,32,114,105,103,104,116,32,112,97,110,101,108],"value":"Show current directory of the left panel in the right panel"}, {"hash":62,"name":"tfrmmain.btnrightequalleft.caption","sourcebytes":[62],"value":">"}, {"hash":354472,"name":"tfrmmain.lblcommandpath.caption","sourcebytes":[80,97,116,104],"value":"Path"}, {"hash":146472345,"name":"tfrmmain.btnf7.caption","sourcebytes":[68,105,114,101,99,116,111,114,121],"value":"Directory"}, {"hash":78392485,"name":"tfrmmain.btnf8.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":211026396,"name":"tfrmmain.btnf9.caption","sourcebytes":[84,101,114,109,105,110,97,108],"value":"Terminal"}, {"hash":315140,"name":"tfrmmain.btnf10.caption","sourcebytes":[69,120,105,116],"value":"Exit"}, {"hash":44892867,"name":"tfrmmain.mnufiles.caption","sourcebytes":[38,70,105,108,101,115],"value":"&Files"}, {"hash":2832523,"name":"tfrmmain.mnumark.caption","sourcebytes":[38,77,97,114,107],"value":"&Mark"}, {"hash":105082387,"name":"tfrmmain.mnucmd.caption","sourcebytes":[38,67,111,109,109,97,110,100,115],"value":"&Commands"}, {"hash":80471771,"name":"tfrmmain.mnunetwork.caption","sourcebytes":[78,101,116,119,111,114,107],"value":"Network"}, {"hash":2860947,"name":"tfrmmain.mnutabs.caption","sourcebytes":[38,84,97,98,115],"value":"&Tabs"}, {"hash":64866531,"name":"tfrmmain.mnutaboptions.caption","sourcebytes":[84,97,98,32,38,79,112,116,105,111,110,115],"value":"Tab &Options"}, {"hash":225003075,"name":"tfrmmain.mnufavoritetabs.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, {"hash":2858855,"name":"tfrmmain.mnushow.caption","sourcebytes":[38,83,104,111,119],"value":"&Show"}, {"hash":32269806,"name":"tfrmmain.mnuconfig.caption","sourcebytes":[67,38,111,110,102,105,103,117,114,97,116,105,111,110],"value":"C&onfiguration"}, {"hash":2812976,"name":"tfrmmain.mnuhelp.caption","sourcebytes":[38,72,101,108,112],"value":"&Help"}, {"hash":5941396,"name":"tfrmmain.mnualloperstart.caption","sourcebytes":[83,116,97,114,116],"value":"Start"}, {"hash":2108,"name":"tfrmmain.mnualloperpause.caption","sourcebytes":[124,124],"value":"||"}, {"hash":77089212,"name":"tfrmmain.mnualloperstop.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"}, {"hash":205778373,"name":"tfrmmain.acthorizontalfilepanels.caption","sourcebytes":[38,72,111,114,105,122,111,110,116,97,108,32,80,97,110,101,108,115,32,77,111,100,101],"value":"&Horizontal Panels Mode"}, {"hash":190227950,"name":"tfrmmain.actpanelssplitterperpos.caption","sourcebytes":[83,101,116,32,115,112,108,105,116,116,101,114,32,112,111,115,105,116,105,111,110],"value":"Set splitter position"}, {"hash":380871,"name":"tfrmmain.actview.caption","sourcebytes":[86,105,101,119],"value":"View"}, {"hash":310020,"name":"tfrmmain.actedit.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, {"hash":106606355,"name":"tfrmmain.acthelpindex.caption","sourcebytes":[38,67,111,110,116,101,110,116,115],"value":"&Contents"}, {"hash":217674644,"name":"tfrmmain.actkeyboard.caption","sourcebytes":[38,75,101,121,98,111,97,114,100],"value":"&Keyboard"}, {"hash":220405653,"name":"tfrmmain.actvisithomepage.caption","sourcebytes":[38,86,105,115,105,116,32,68,111,117,98,108,101,32,67,111,109,109,97,110,100,101,114,32,87,101,98,115,105,116,101],"value":"&Visit Double Commander Website"}, {"hash":44537540,"name":"tfrmmain.actabout.caption","sourcebytes":[38,65,98,111,117,116],"value":"&About"}, {"hash":9324734,"name":"tfrmmain.actoptions.caption","sourcebytes":[38,79,112,116,105,111,110,115,46,46,46],"value":"&Options..."}, {"hash":159468684,"name":"tfrmmain.actmultirename.caption","sourcebytes":[77,117,108,116,105,45,38,82,101,110,97,109,101,32,84,111,111,108],"value":"Multi-&Rename Tool"}, {"hash":143338174,"name":"tfrmmain.actsearch.caption","sourcebytes":[38,83,101,97,114,99,104,46,46,46],"value":"&Search..."}, {"hash":196870062,"name":"tfrmmain.actaddnewsearch.caption","sourcebytes":[78,101,119,32,115,101,97,114,99,104,32,105,110,115,116,97,110,99,101,46,46,46],"value":"New search instance..."}, {"hash":28039203,"name":"tfrmmain.actviewsearches.caption","sourcebytes":[86,105,101,119,32,99,117,114,114,101,110,116,32,115,101,97,114,99,104,32,105,110,115,116,97,110,99,101,115],"value":"View current search instances"}, {"hash":78460649,"name":"tfrmmain.actdeletesearches.caption","sourcebytes":[70,111,114,32,97,108,108,32,115,101,97,114,99,104,101,115,44,32,99,97,110,99,101,108,44,32,99,108,111,115,101,32,97,110,100,32,102,114,101,101,32,109,101,109,111,114,121],"value":"For all searches, cancel, close and free memory"}, {"hash":223665710,"name":"tfrmmain.actsyncdirs.caption","sourcebytes":[83,121,110,38,99,104,114,111,110,105,122,101,32,100,105,114,115,46,46,46],"value":"Syn&chronize dirs..."}, {"hash":42862446,"name":"tfrmmain.actconfigtoolbars.caption","sourcebytes":[84,111,111,108,98,97,114,46,46,46],"value":"Toolbar..."}, {"hash":196668100,"name":"tfrmmain.actconfigdirhotlist.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116],"value":"Configuration of Directory Hotlist"}, {"hash":25350211,"name":"tfrmmain.actworkwithdirectoryhotlist.caption","sourcebytes":[87,111,114,107,32,119,105,116,104,32,68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116,32,97,110,100,32,112,97,114,97,109,101,116,101,114,115],"value":"Work with Directory Hotlist and parameters"}, {"hash":63627011,"name":"tfrmmain.actfileassoc.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,70,105,108,101,32,38,65,115,115,111,99,105,97,116,105,111,110,115],"value":"Configuration of File &Associations"}, {"hash":109519843,"name":"tfrmmain.actcomparecontents.caption","sourcebytes":[67,111,109,112,97,114,101,32,98,121,32,38,67,111,110,116,101,110,116,115],"value":"Compare by &Contents"}, {"hash":343125,"name":"tfrmmain.actshowmainmenu.caption","sourcebytes":[77,101,110,117],"value":"Menu"}, {"hash":225144965,"name":"tfrmmain.actshowbuttonmenu.caption","sourcebytes":[83,104,111,119,32,98,117,116,116,111,110,32,109,101,110,117],"value":"Show button menu"}, {"hash":74141794,"name":"tfrmmain.actoperationsviewer.caption","sourcebytes":[79,112,101,114,97,116,105,111,110,115,32,38,86,105,101,119,101,114],"value":"Operations &Viewer"}, {"hash":146640424,"name":"tfrmmain.actrefresh.caption","sourcebytes":[38,82,101,102,114,101,115,104],"value":"&Refresh"}, {"hash":217084787,"name":"tfrmmain.actshowsysfiles.caption","sourcebytes":[83,104,111,119,32,38,72,105,100,100,101,110,47,83,121,115,116,101,109,32,70,105,108,101,115],"value":"Show &Hidden/System Files"}, {"hash":100091209,"name":"tfrmmain.actdirhistory.caption","sourcebytes":[68,105,114,101,99,116,111,114,121,32,104,105,115,116,111,114,121],"value":"Directory history"}, {"hash":45361572,"name":"tfrmmain.actdirhotlist.caption","sourcebytes":[68,105,114,101,99,116,111,114,121,32,38,72,111,116,108,105,115,116],"value":"Directory &Hotlist"}, {"hash":210973262,"name":"tfrmmain.actmarkplus.caption","sourcebytes":[83,101,108,101,99,116,32,97,32,38,71,114,111,117,112,46,46,46],"value":"Select a &Group..."}, {"hash":35869182,"name":"tfrmmain.actmarkminus.caption","sourcebytes":[85,110,115,101,108,101,99,116,32,97,32,71,114,111,38,117,112,46,46,46],"value":"Unselect a Gro&up..."}, {"hash":193846284,"name":"tfrmmain.actmarkmarkall.caption","sourcebytes":[38,83,101,108,101,99,116,32,65,108,108],"value":"&Select All"}, {"hash":6544428,"name":"tfrmmain.actmarkunmarkall.caption","sourcebytes":[38,85,110,115,101,108,101,99,116,32,65,108,108],"value":"&Unselect All"}, {"hash":248745749,"name":"tfrmmain.actcalculatespace.caption","sourcebytes":[67,97,108,99,117,108,97,116,101,32,38,79,99,99,117,112,105,101,100,32,83,112,97,99,101],"value":"Calculate &Occupied Space"}, {"hash":77434955,"name":"tfrmmain.actbenchmark.caption","sourcebytes":[38,66,101,110,99,104,109,97,114,107],"value":"&Benchmark"}, {"hash":80304322,"name":"tfrmmain.actnewtab.caption","sourcebytes":[38,78,101,119,32,84,97,98],"value":"&New Tab"}, {"hash":305108,"name":"tfrmmain.actcuttoclipboard.caption","sourcebytes":[67,117,38,116],"value":"Cu&t"}, {"hash":2795129,"name":"tfrmmain.actcopytoclipboard.caption","sourcebytes":[38,67,111,112,121],"value":"&Copy"}, {"hash":45517477,"name":"tfrmmain.actpastefromclipboard.caption","sourcebytes":[38,80,97,115,116,101],"value":"&Paste"}, {"hash":89386892,"name":"tfrmmain.actrunterm.caption","sourcebytes":[82,117,110,32,38,84,101,114,109,105,110,97,108],"value":"Run &Terminal"}, {"hash":235402462,"name":"tfrmmain.actmarkinvert.caption","sourcebytes":[38,73,110,118,101,114,116,32,83,101,108,101,99,116,105,111,110],"value":"&Invert Selection"}, {"hash":262721944,"name":"tfrmmain.actmarkcurrentpath.caption","sourcebytes":[83,101,108,101,99,116,32,97,108,108,32,105,110,32,115,97,109,101,32,112,97,116,104],"value":"Select all in same path"}, {"hash":61395240,"name":"tfrmmain.actunmarkcurrentpath.caption","sourcebytes":[85,110,115,101,108,101,99,116,32,97,108,108,32,105,110,32,115,97,109,101,32,112,97,116,104],"value":"Unselect all in same path"}, {"hash":36779621,"name":"tfrmmain.actmarkcurrentname.caption","sourcebytes":[83,101,108,101,99,116,32,97,108,108,32,102,105,108,101,115,32,119,105,116,104,32,115,97,109,101,32,110,97,109,101],"value":"Select all files with same name"}, {"hash":36792933,"name":"tfrmmain.actunmarkcurrentname.caption","sourcebytes":[85,110,115,101,108,101,99,116,32,97,108,108,32,102,105,108,101,115,32,119,105,116,104,32,115,97,109,101,32,110,97,109,101],"value":"Unselect all files with same name"}, {"hash":250335950,"name":"tfrmmain.actmarkcurrentextension.caption","sourcebytes":[83,101,108,101,99,116,32,65,108,108,32,119,105,116,104,32,116,104,101,32,83,97,109,101,32,69,38,120,116,101,110,115,105,111,110],"value":"Select All with the Same E&xtension"}, {"hash":48981918,"name":"tfrmmain.actunmarkcurrentextension.caption","sourcebytes":[85,110,115,101,108,101,99,116,32,65,108,108,32,119,105,116,104,32,116,104,101,32,83,97,109,101,32,69,120,38,116,101,110,115,105,111,110],"value":"Unselect All with the Same Ex&tension"}, {"hash":232101886,"name":"tfrmmain.actmarkcurrentnameext.caption","sourcebytes":[83,101,108,101,99,116,32,97,108,108,32,102,105,108,101,115,32,119,105,116,104,32,115,97,109,101,32,110,97,109,101,32,97,110,100,32,101,120,116,101,110,115,105,111,110],"value":"Select all files with same name and extension"}, {"hash":229218302,"name":"tfrmmain.actunmarkcurrentnameext.caption","sourcebytes":[85,110,115,101,108,101,99,116,32,97,108,108,32,102,105,108,101,115,32,119,105,116,104,32,115,97,109,101,32,110,97,109,101,32,97,110,100,32,101,120,116,101,110,115,105,111,110],"value":"Unselect all files with same name and extension"}, {"hash":127528883,"name":"tfrmmain.actcomparedirectories.caption","sourcebytes":[67,111,109,112,97,114,101,32,68,105,114,101,99,116,111,114,105,101,115],"value":"Compare Directories"}, {"hash":127528883,"name":"tfrmmain.actcomparedirectories.hint","sourcebytes":[67,111,109,112,97,114,101,32,68,105,114,101,99,116,111,114,105,101,115],"value":"Compare Directories"}, {"hash":119974181,"name":"tfrmmain.acteditnew.caption","sourcebytes":[69,100,105,116,32,110,101,119,32,102,105,108,101],"value":"Edit new file"}, {"hash":304761,"name":"tfrmmain.actcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":187513902,"name":"tfrmmain.actcopynoask.caption","sourcebytes":[67,111,112,121,32,102,105,108,101,115,32,119,105,116,104,111,117,116,32,97,115,107,105,110,103,32,102,111,114,32,99,111,110,102,105,114,109,97,116,105,111,110],"value":"Copy files without asking for confirmation"}, {"hash":147302908,"name":"tfrmmain.actcopysamepanel.caption","sourcebytes":[67,111,112,121,32,116,111,32,115,97,109,101,32,112,97,110,101,108],"value":"Copy to same panel"}, {"hash":345797,"name":"tfrmmain.actrename.caption","sourcebytes":[77,111,118,101],"value":"Move"}, {"hash":261649614,"name":"tfrmmain.actrenamenoask.caption","sourcebytes":[77,111,118,101,47,82,101,110,97,109,101,32,102,105,108,101,115,32,119,105,116,104,111,117,116,32,97,115,107,105,110,103,32,102,111,114,32,99,111,110,102,105,114,109,97,116,105,111,110],"value":"Move/Rename files without asking for confirmation"}, {"hash":93079605,"name":"tfrmmain.actrenameonly.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, {"hash":42112025,"name":"tfrmmain.actmakedir.caption","sourcebytes":[67,114,101,97,116,101,32,38,68,105,114,101,99,116,111,114,121],"value":"Create &Directory"}, {"hash":78392485,"name":"tfrmmain.actdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":385125,"name":"tfrmmain.actwipe.caption","sourcebytes":[87,105,112,101],"value":"Wipe"}, {"hash":173381502,"name":"tfrmmain.actpackfiles.caption","sourcebytes":[38,80,97,99,107,32,70,105,108,101,115,46,46,46],"value":"&Pack Files..."}, {"hash":90852617,"name":"tfrmmain.acttestarchive.caption","sourcebytes":[38,84,101,115,116,32,65,114,99,104,105,118,101,40,115,41],"value":"&Test Archive(s)"}, {"hash":267061525,"name":"tfrmmain.actopenarchive.caption","sourcebytes":[84,114,121,32,111,112,101,110,32,97,114,99,104,105,118,101],"value":"Try open archive"}, {"hash":142412926,"name":"tfrmmain.actextractfiles.caption","sourcebytes":[38,69,120,116,114,97,99,116,32,70,105,108,101,115,46,46,46],"value":"&Extract Files..."}, {"hash":227876452,"name":"tfrmmain.actopenvirtualfilesystemlist.caption","sourcebytes":[79,112,101,110,32,38,86,70,83,32,76,105,115,116],"value":"Open &VFS List"}, {"hash":36577715,"name":"tfrmmain.actfileproperties.caption","sourcebytes":[83,104,111,119,32,38,70,105,108,101,32,80,114,111,112,101,114,116,105,101,115],"value":"Show &File Properties"}, {"hash":151491698,"name":"tfrmmain.actopendirinnewtab.caption","sourcebytes":[79,112,101,110,32,38,70,111,108,100,101,114,32,105,110,32,97,32,78,101,119,32,84,97,98],"value":"Open &Folder in a New Tab"}, {"hash":126330690,"name":"tfrmmain.actnexttab.caption","sourcebytes":[83,119,105,116,99,104,32,116,111,32,78,101,120,38,116,32,84,97,98],"value":"Switch to Nex&t Tab"}, {"hash":71354354,"name":"tfrmmain.actprevtab.caption","sourcebytes":[83,119,105,116,99,104,32,116,111,32,38,80,114,101,118,105,111,117,115,32,84,97,98],"value":"Switch to &Previous Tab"}, {"hash":120834372,"name":"tfrmmain.actmovetableft.caption","sourcebytes":[77,111,118,101,32,99,117,114,114,101,110,116,32,116,97,98,32,116,111,32,116,104,101,32,108,101,102,116],"value":"Move current tab to the left"}, {"hash":53924996,"name":"tfrmmain.actmovetabright.caption","sourcebytes":[77,111,118,101,32,99,117,114,114,101,110,116,32,116,97,98,32,116,111,32,116,104,101,32,114,105,103,104,116],"value":"Move current tab to the right"}, {"hash":212173059,"name":"tfrmmain.actswitchignorelist.caption","sourcebytes":[69,110,97,98,108,101,47,100,105,115,97,98,108,101,32,105,103,110,111,114,101,32,108,105,115,116,32,102,105,108,101,32,116,111,32,110,111,116,32,115,104,111,119,32,102,105,108,101,32,110,97,109,101,115],"value":"Enable/disable ignore list file to not show file names"}, {"hash":241547140,"name":"tfrmmain.actcopynamestoclip.caption","sourcebytes":[67,111,112,121,32,38,70,105,108,101,110,97,109,101,40,115,41,32,116,111,32,67,108,105,112,98,111,97,114,100],"value":"Copy &Filename(s) to Clipboard"}, {"hash":252413336,"name":"tfrmmain.actcopyfullnamestoclip.caption","sourcebytes":[67,111,112,121,32,70,105,108,101,110,97,109,101,40,115,41,32,119,105,116,104,32,70,117,108,108,32,38,80,97,116,104],"value":"Copy Filename(s) with Full &Path"}, {"hash":259895502,"name":"tfrmmain.actsaveselection.caption","sourcebytes":[83,97,38,118,101,32,83,101,108,101,99,116,105,111,110],"value":"Sa&ve Selection"}, {"hash":109395278,"name":"tfrmmain.actrestoreselection.caption","sourcebytes":[38,82,101,115,116,111,114,101,32,83,101,108,101,99,116,105,111,110],"value":"&Restore Selection"}, {"hash":237579518,"name":"tfrmmain.actsaveselectiontofile.caption","sourcebytes":[83,97,118,101,32,83,38,101,108,101,99,116,105,111,110,32,116,111,32,70,105,108,101,46,46,46],"value":"Save S&election to File..."}, {"hash":116708158,"name":"tfrmmain.actloadselectionfromfile.caption","sourcebytes":[38,76,111,97,100,32,83,101,108,101,99,116,105,111,110,32,102,114,111,109,32,70,105,108,101,46,46,46],"value":"&Load Selection from File..."}, {"hash":65805316,"name":"tfrmmain.actloadselectionfromclip.caption","sourcebytes":[76,111,97,100,32,83,101,108,101,99,116,105,111,110,32,102,114,111,109,32,67,108,105,112,38,98,111,97,114,100],"value":"Load Selection from Clip&board"}, {"hash":224130478,"name":"tfrmmain.actnetworkconnect.caption","sourcebytes":[78,101,116,119,111,114,107,32,38,67,111,110,110,101,99,116,46,46,46],"value":"Network &Connect..."}, {"hash":76511870,"name":"tfrmmain.actnetworkquickconnect.caption","sourcebytes":[78,101,116,119,111,114,107,32,38,81,117,105,99,107,32,67,111,110,110,101,99,116,46,46,46],"value":"Network &Quick Connect..."}, {"hash":29760996,"name":"tfrmmain.actnetworkdisconnect.caption","sourcebytes":[78,101,116,119,111,114,107,32,38,68,105,115,99,111,110,110,101,99,116],"value":"Network &Disconnect"}, {"hash":213414664,"name":"tfrmmain.actcopynetnamestoclip.caption","sourcebytes":[67,111,112,121,32,110,97,109,101,115,32,119,105,116,104,32,85,78,67,32,112,97,116,104],"value":"Copy names with UNC path"}, {"hash":219077657,"name":"tfrmmain.actcopypathoffilestoclip.caption","sourcebytes":[67,111,112,121,32,70,117,108,108,32,80,97,116,104,32,111,102,32,115,101,108,101,99,116,101,100,32,102,105,108,101,40,115,41],"value":"Copy Full Path of selected file(s)"}, {"hash":3203618,"name":"tfrmmain.actcopypathnosepoffilestoclip.caption","sourcebytes":[67,111,112,121,32,70,117,108,108,32,80,97,116,104,32,111,102,32,115,101,108,101,99,116,101,100,32,102,105,108,101,40,115,41,32,119,105,116,104,32,110,111,32,101,110,100,105,110,103,32,100,105,114,32,115,101,112,97,114,97,116,111,114],"value":"Copy Full Path of selected file(s) with no ending dir separator"}, {"hash":25510579,"name":"tfrmmain.actcopyfiledetailstoclip.caption","sourcebytes":[67,111,112,121,32,97,108,108,32,115,104,111,119,110,32,38,99,111,108,117,109,110,115],"value":"Copy all shown &columns"}, {"hash":136107570,"name":"tfrmmain.actrenametab.caption","sourcebytes":[38,82,101,110,97,109,101,32,84,97,98],"value":"&Rename Tab"}, {"hash":19168668,"name":"tfrmmain.actleftbriefview.caption","sourcebytes":[66,114,105,101,102,32,118,105,101,119,32,111,110,32,108,101,102,116,32,112,97,110,101,108],"value":"Brief view on left panel"}, {"hash":58779596,"name":"tfrmmain.actleftcolumnsview.caption","sourcebytes":[67,111,108,117,109,110,115,32,118,105,101,119,32,111,110,32,108,101,102,116,32,112,97,110,101,108],"value":"Columns view on left panel"}, {"hash":178493820,"name":"tfrmmain.actleftthumbview.caption","sourcebytes":[84,104,117,109,98,110,97,105,108,115,32,118,105,101,119,32,111,110,32,108,101,102,116,32,112,97,110,101,108],"value":"Thumbnails view on left panel"}, {"hash":118738556,"name":"tfrmmain.actleftflatview.caption","sourcebytes":[38,70,108,97,116,32,118,105,101,119,32,111,110,32,108,101,102,116,32,112,97,110,101,108],"value":"&Flat view on left panel"}, {"hash":175854005,"name":"tfrmmain.actleftsortbyname.caption","sourcebytes":[83,111,114,116,32,108,101,102,116,32,112,97,110,101,108,32,98,121,32,38,78,97,109,101],"value":"Sort left panel by &Name"}, {"hash":35795934,"name":"tfrmmain.actleftsortbyext.caption","sourcebytes":[83,111,114,116,32,108,101,102,116,32,112,97,110,101,108,32,98,121,32,38,69,120,116,101,110,115,105,111,110],"value":"Sort left panel by &Extension"}, {"hash":175872133,"name":"tfrmmain.actleftsortbysize.caption","sourcebytes":[83,111,114,116,32,108,101,102,116,32,112,97,110,101,108,32,98,121,32,38,83,105,122,101],"value":"Sort left panel by &Size"}, {"hash":175816485,"name":"tfrmmain.actleftsortbydate.caption","sourcebytes":[83,111,114,116,32,108,101,102,116,32,112,97,110,101,108,32,98,121,32,38,68,97,116,101],"value":"Sort left panel by &Date"}, {"hash":42161907,"name":"tfrmmain.actleftsortbyattr.caption","sourcebytes":[83,111,114,116,32,108,101,102,116,32,112,97,110,101,108,32,98,121,32,38,65,116,116,114,105,98,117,116,101,115],"value":"Sort left panel by &Attributes"}, {"hash":104307628,"name":"tfrmmain.actleftreverseorder.caption","sourcebytes":[82,101,38,118,101,114,115,101,32,111,114,100,101,114,32,111,110,32,108,101,102,116,32,112,97,110,101,108],"value":"Re&verse order on left panel"}, {"hash":131203188,"name":"tfrmmain.actleftopendrives.caption","sourcebytes":[79,112,101,110,32,108,101,102,116,32,100,114,105,118,101,32,108,105,115,116],"value":"Open left drive list"}, {"hash":58570300,"name":"tfrmmain.actrightbriefview.caption","sourcebytes":[66,114,105,101,102,32,118,105,101,119,32,111,110,32,114,105,103,104,116,32,112,97,110,101,108],"value":"Brief view on right panel"}, {"hash":154538780,"name":"tfrmmain.actrightcolumnsview.caption","sourcebytes":[67,111,108,117,109,110,115,32,118,105,101,119,32,111,110,32,114,105,103,104,116,32,112,97,110,101,108],"value":"Columns view on right panel"}, {"hash":186906764,"name":"tfrmmain.actrightthumbview.caption","sourcebytes":[84,104,117,109,98,110,97,105,108,115,32,118,105,101,119,32,111,110,32,114,105,103,104,116,32,112,97,110,101,108],"value":"Thumbnails view on right panel"}, {"hash":2140252,"name":"tfrmmain.actrightflatview.caption","sourcebytes":[38,70,108,97,116,32,118,105,101,119,32,111,110,32,114,105,103,104,116,32,112,97,110,101,108],"value":"&Flat view on right panel"}, {"hash":148414997,"name":"tfrmmain.actrightsortbyname.caption","sourcebytes":[83,111,114,116,32,114,105,103,104,116,32,112,97,110,101,108,32,98,121,32,38,78,97,109,101],"value":"Sort right panel by &Name"}, {"hash":138997454,"name":"tfrmmain.actrightsortbyext.caption","sourcebytes":[83,111,114,116,32,114,105,103,104,116,32,112,97,110,101,108,32,98,121,32,38,69,120,116,101,110,115,105,111,110],"value":"Sort right panel by &Extension"}, {"hash":148277029,"name":"tfrmmain.actrightsortbysize.caption","sourcebytes":[83,111,114,116,32,114,105,103,104,116,32,112,97,110,101,108,32,98,121,32,38,83,105,122,101],"value":"Sort right panel by &Size"}, {"hash":148328069,"name":"tfrmmain.actrightsortbydate.caption","sourcebytes":[83,111,114,116,32,114,105,103,104,116,32,112,97,110,101,108,32,98,121,32,38,68,97,116,101],"value":"Sort right panel by &Date"}, {"hash":3057491,"name":"tfrmmain.actrightsortbyattr.caption","sourcebytes":[83,111,114,116,32,114,105,103,104,116,32,112,97,110,101,108,32,98,121,32,38,65,116,116,114,105,98,117,116,101,115],"value":"Sort right panel by &Attributes"}, {"hash":40097100,"name":"tfrmmain.actrightreverseorder.caption","sourcebytes":[82,101,38,118,101,114,115,101,32,111,114,100,101,114,32,111,110,32,114,105,103,104,116,32,112,97,110,101,108],"value":"Re&verse order on right panel"}, {"hash":253252116,"name":"tfrmmain.actrightopendrives.caption","sourcebytes":[79,112,101,110,32,114,105,103,104,116,32,100,114,105,118,101,32,108,105,115,116],"value":"Open right drive list"}, {"hash":104366453,"name":"tfrmmain.actfocuscmdline.caption","sourcebytes":[70,111,99,117,115,32,99,111,109,109,97,110,100,32,108,105,110,101],"value":"Focus command line"}, {"hash":66134857,"name":"tfrmmain.actshowcmdlinehistory.caption","sourcebytes":[83,104,111,119,32,99,111,109,109,97,110,100,32,108,105,110,101,32,104,105,115,116,111,114,121],"value":"Show command line history"}, {"hash":175182782,"name":"tfrmmain.actsyncchangedir.caption","sourcebytes":[83,121,110,99,104,114,111,110,111,117,115,32,110,97,118,105,103,97,116,105,111,110],"value":"Synchronous navigation"}, {"hash":193097747,"name":"tfrmmain.actsyncchangedir.hint","sourcebytes":[83,121,110,99,104,114,111,110,111,117,115,32,100,105,114,101,99,116,111,114,121,32,99,104,97,110,103,105,110,103,32,105,110,32,98,111,116,104,32,112,97,110,101,108,115],"value":"Synchronous directory changing in both panels"}, {"hash":109035716,"name":"tfrmmain.actchangedirtoparent.caption","sourcebytes":[67,104,97,110,103,101,32,68,105,114,101,99,116,111,114,121,32,84,111,32,80,97,114,101,110,116],"value":"Change Directory To Parent"}, {"hash":74842917,"name":"tfrmmain.actchangedirtohome.caption","sourcebytes":[67,104,97,110,103,101,32,100,105,114,101,99,116,111,114,121,32,116,111,32,104,111,109,101],"value":"Change directory to home"}, {"hash":74752884,"name":"tfrmmain.actchangedirtoroot.caption","sourcebytes":[67,104,97,110,103,101,32,100,105,114,101,99,116,111,114,121,32,116,111,32,114,111,111,116],"value":"Change directory to root"}, {"hash":140855781,"name":"tfrmmain.acttargetequalsource.caption","sourcebytes":[84,97,114,103,101,116,32,38,61,32,83,111,117,114,99,101],"value":"Target &= Source"}, {"hash":85185511,"name":"tfrmmain.acttransferleft.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,100,105,114,32,117,110,100,101,114,32,99,117,114,115,111,114,32,116,111,32,108,101,102,116,32,119,105,110,100,111,119],"value":"Transfer dir under cursor to left window"}, {"hash":228838439,"name":"tfrmmain.acttransferright.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,100,105,114,32,117,110,100,101,114,32,99,117,114,115,111,114,32,116,111,32,114,105,103,104,116,32,119,105,110,100,111,119],"value":"Transfer dir under cursor to right window"}, {"hash":233152308,"name":"tfrmmain.actleftequalright.caption","sourcebytes":[76,101,102,116,32,38,61,32,82,105,103,104,116],"value":"Left &= Right"}, {"hash":17489316,"name":"tfrmmain.actrightequalleft.caption","sourcebytes":[82,105,103,104,116,32,38,61,32,76,101,102,116],"value":"Right &= Left"}, {"hash":193156919,"name":"tfrmmain.actbriefview.caption","sourcebytes":[66,114,105,101,102,32,118,105,101,119],"value":"Brief view"}, {"hash":193025847,"name":"tfrmmain.actbriefview.hint","sourcebytes":[66,114,105,101,102,32,86,105,101,119],"value":"Brief View"}, {"hash":318508,"name":"tfrmmain.actcolumnsview.caption","sourcebytes":[70,117,108,108],"value":"Full"}, {"hash":32764807,"name":"tfrmmain.actcolumnsview.hint","sourcebytes":[67,111,108,117,109,110,115,32,86,105,101,119],"value":"Columns View"}, {"hash":59888115,"name":"tfrmmain.actthumbnailsview.caption","sourcebytes":[84,104,117,109,98,110,97,105,108,115],"value":"Thumbnails"}, {"hash":258790103,"name":"tfrmmain.actthumbnailsview.hint","sourcebytes":[84,104,117,109,98,110,97,105,108,115,32,86,105,101,119],"value":"Thumbnails View"}, {"hash":140862183,"name":"tfrmmain.actflatview.caption","sourcebytes":[38,70,108,97,116,32,118,105,101,119],"value":"&Flat view"}, {"hash":5637460,"name":"tfrmmain.actflatviewsel.caption","sourcebytes":[38,70,108,97,116,32,118,105,101,119,44,32,111,110,108,121,32,115,101,108,101,99,116,101,100],"value":"&Flat view, only selected"}, {"hash":11026572,"name":"tfrmmain.actquickview.caption","sourcebytes":[38,81,117,105,99,107,32,86,105,101,119,32,80,97,110,101,108],"value":"&Quick View Panel"}, {"hash":21242613,"name":"tfrmmain.actsortbyname.caption","sourcebytes":[83,111,114,116,32,98,121,32,38,78,97,109,101],"value":"Sort by &Name"}, {"hash":112305870,"name":"tfrmmain.actsortbyext.caption","sourcebytes":[83,111,114,116,32,98,121,32,38,69,120,116,101,110,115,105,111,110],"value":"Sort by &Extension"}, {"hash":21170117,"name":"tfrmmain.actsortbysize.caption","sourcebytes":[83,111,114,116,32,98,121,32,38,83,105,122,101],"value":"Sort by &Size"}, {"hash":21220965,"name":"tfrmmain.actsortbydate.caption","sourcebytes":[83,111,114,116,32,98,121,32,38,68,97,116,101],"value":"Sort by &Date"}, {"hash":163194803,"name":"tfrmmain.actsortbyattr.caption","sourcebytes":[83,111,114,116,32,98,121,32,38,65,116,116,114,105,98,117,116,101,115],"value":"Sort by &Attributes"}, {"hash":11159250,"name":"tfrmmain.actreverseorder.caption","sourcebytes":[82,101,38,118,101,114,115,101,32,79,114,100,101,114],"value":"Re&verse Order"}, {"hash":7462852,"name":"tfrmmain.actsrcopendrives.caption","sourcebytes":[79,112,101,110,32,100,114,105,118,101,32,108,105,115,116],"value":"Open drive list"}, {"hash":248236563,"name":"tfrmmain.actexchange.caption","sourcebytes":[83,119,97,112,32,38,80,97,110,101,108,115],"value":"Swap &Panels"}, {"hash":34632008,"name":"tfrmmain.actquicksearch.caption","sourcebytes":[81,117,105,99,107,32,115,101,97,114,99,104],"value":"Quick search"}, {"hash":157964709,"name":"tfrmmain.actviewlogfile.caption","sourcebytes":[86,105,101,119,32,108,111,103,32,102,105,108,101],"value":"View log file"}, {"hash":120491445,"name":"tfrmmain.actclearlogfile.caption","sourcebytes":[67,108,101,97,114,32,108,111,103,32,102,105,108,101],"value":"Clear log file"}, {"hash":262004295,"name":"tfrmmain.actclearlogwindow.caption","sourcebytes":[67,108,101,97,114,32,108,111,103,32,119,105,110,100,111,119],"value":"Clear log window"}, {"hash":54903570,"name":"tfrmmain.actquickfilter.caption","sourcebytes":[81,117,105,99,107,32,102,105,108,116,101,114],"value":"Quick filter"}, {"hash":227422212,"name":"tfrmmain.acteditpath.caption","sourcebytes":[69,100,105,116,32,112,97,116,104,32,102,105,101,108,100,32,97,98,111,118,101,32,102,105,108,101,32,108,105,115,116],"value":"Edit path field above file list"}, {"hash":208233241,"name":"tfrmmain.actchangedir.caption","sourcebytes":[67,104,97,110,103,101,32,100,105,114,101,99,116,111,114,121],"value":"Change directory"}, {"hash":12067941,"name":"tfrmmain.actcmdlinenext.caption","sourcebytes":[78,101,120,116,32,67,111,109,109,97,110,100,32,76,105,110,101],"value":"Next Command Line"}, {"hash":88408521,"name":"tfrmmain.actcmdlinenext.hint","sourcebytes":[83,101,116,32,99,111,109,109,97,110,100,32,108,105,110,101,32,116,111,32,110,101,120,116,32,99,111,109,109,97,110,100,32,105,110,32,104,105,115,116,111,114,121],"value":"Set command line to next command in history"}, {"hash":204683509,"name":"tfrmmain.actcmdlineprev.caption","sourcebytes":[80,114,101,118,105,111,117,115,32,67,111,109,109,97,110,100,32,76,105,110,101],"value":"Previous Command Line"}, {"hash":202537465,"name":"tfrmmain.actcmdlineprev.hint","sourcebytes":[83,101,116,32,99,111,109,109,97,110,100,32,108,105,110,101,32,116,111,32,112,114,101,118,105,111,117,115,32,99,111,109,109,97,110,100,32,105,110,32,104,105,115,116,111,114,121],"value":"Set command line to previous command in history"}, {"hash":860949,"name":"tfrmmain.actaddpathtocmdline.caption","sourcebytes":[67,111,112,121,32,112,97,116,104,32,116,111,32,99,111,109,109,97,110,100,32,108,105,110,101],"value":"Copy path to command line"}, {"hash":236945685,"name":"tfrmmain.actaddfilenametocmdline.caption","sourcebytes":[65,100,100,32,102,105,108,101,32,110,97,109,101,32,116,111,32,99,111,109,109,97,110,100,32,108,105,110,101],"value":"Add file name to command line"}, {"hash":164955621,"name":"tfrmmain.actaddpathandfilenametocmdline.caption","sourcebytes":[65,100,100,32,112,97,116,104,32,97,110,100,32,102,105,108,101,32,110,97,109,101,32,116,111,32,99,111,109,109,97,110,100,32,108,105,110,101],"value":"Add path and file name to command line"}, {"hash":87722821,"name":"tfrmmain.actgotofirstentry.caption","sourcebytes":[80,108,97,99,101,32,99,117,114,115,111,114,32,111,110,32,102,105,114,115,116,32,102,111,108,100,101,114,32,111,114,32,102,105,108,101],"value":"Place cursor on first folder or file"}, {"hash":26911845,"name":"tfrmmain.actgotolastentry.caption","sourcebytes":[80,108,97,99,101,32,99,117,114,115,111,114,32,111,110,32,108,97,115,116,32,102,111,108,100,101,114,32,111,114,32,102,105,108,101],"value":"Place cursor on last folder or file"}, {"hash":132097125,"name":"tfrmmain.actgotonextentry.caption","sourcebytes":[80,108,97,99,101,32,99,117,114,115,111,114,32,111,110,32,110,101,120,116,32,102,111,108,100,101,114,32,111,114,32,102,105,108,101],"value":"Place cursor on next folder or file"}, {"hash":241610469,"name":"tfrmmain.actgotopreventry.caption","sourcebytes":[80,108,97,99,101,32,99,117,114,115,111,114,32,111,110,32,112,114,101,118,105,111,117,115,32,102,111,108,100,101,114,32,111,114,32,102,105,108,101],"value":"Place cursor on previous folder or file"}, {"hash":254828868,"name":"tfrmmain.actgotofirstfile.caption","sourcebytes":[80,108,97,99,101,32,99,117,114,115,111,114,32,111,110,32,102,105,114,115,116,32,102,105,108,101,32,105,110,32,108,105,115,116],"value":"Place cursor on first file in list"}, {"hash":139264356,"name":"tfrmmain.actgotolastfile.caption","sourcebytes":[80,108,97,99,101,32,99,117,114,115,111,114,32,111,110,32,108,97,115,116,32,102,105,108,101,32,105,110,32,108,105,115,116],"value":"Place cursor on last file in list"}, {"hash":232256295,"name":"tfrmmain.actviewhistory.caption","sourcebytes":[83,104,111,119,32,104,105,115,116,111,114,121,32,111,102,32,118,105,115,105,116,101,100,32,112,97,116,104,115,32,102,111,114,32,97,99,116,105,118,101,32,118,105,101,119],"value":"Show history of visited paths for active view"}, {"hash":7072137,"name":"tfrmmain.actviewhistorynext.caption","sourcebytes":[71,111,32,116,111,32,110,101,120,116,32,101,110,116,114,121,32,105,110,32,104,105,115,116,111,114,121],"value":"Go to next entry in history"}, {"hash":57781273,"name":"tfrmmain.actviewhistoryprev.caption","sourcebytes":[71,111,32,116,111,32,112,114,101,118,105,111,117,115,32,101,110,116,114,121,32,105,110,32,104,105,115,116,111,114,121],"value":"Go to previous entry in history"}, {"hash":70269112,"name":"tfrmmain.actopendrivebyindex.caption","sourcebytes":[79,112,101,110,32,68,114,105,118,101,32,98,121,32,73,110,100,101,120],"value":"Open Drive by Index"}, {"hash":237685493,"name":"tfrmmain.actopenbar.caption","sourcebytes":[79,112,101,110,32,98,97,114,32,102,105,108,101],"value":"Open bar file"}, {"hash":47984407,"name":"tfrmmain.actminimize.caption","sourcebytes":[77,105,110,105,109,105,122,101,32,119,105,110,100,111,119],"value":"Minimize window"}, {"hash":4710148,"name":"tfrmmain.actexit.caption","sourcebytes":[69,38,120,105,116],"value":"E&xit"}, {"hash":142873059,"name":"tfrmmain.actdebugshowcommandparameters.caption","sourcebytes":[83,104,111,119,32,67,111,109,109,97,110,100,32,80,97,114,97,109,101,116,101,114,115],"value":"Show Command Parameters"}, {"hash":35037726,"name":"tfrmmain.actdoanycmcommand.caption","sourcebytes":[69,120,101,99,117,116,101,32,38,105,110,116,101,114,110,97,108,32,99,111,109,109,97,110,100,46,46,46],"value":"Execute &internal command..."}, {"hash":170156852,"name":"tfrmmain.actdoanycmcommand.hint","sourcebytes":[83,101,108,101,99,116,32,97,110,121,32,99,111,109,109,97,110,100,32,97,110,100,32,101,120,101,99,117,116,101,32,105,116],"value":"Select any command and execute it"}, {"hash":207287774,"name":"tfrmmain.actsetfileproperties.caption","sourcebytes":[67,104,97,110,103,101,32,38,65,116,116,114,105,98,117,116,101,115,46,46,46],"value":"Change &Attributes..."}, {"hash":101439822,"name":"tfrmmain.acteditcomment.caption","sourcebytes":[69,100,105,116,32,67,111,38,109,109,101,110,116,46,46,46],"value":"Edit Co&mment..."}, {"hash":163354629,"name":"tfrmmain.actcontextmenu.caption","sourcebytes":[83,104,111,119,32,99,111,110,116,101,120,116,32,109,101,110,117],"value":"Show context menu"}, {"hash":353982,"name":"tfrmmain.actopen.caption","sourcebytes":[79,112,101,110],"value":"Open"}, {"hash":353982,"name":"tfrmmain.actshellexecute.caption","sourcebytes":[79,112,101,110],"value":"Open"}, {"hash":233849651,"name":"tfrmmain.actshellexecute.hint","sourcebytes":[79,112,101,110,32,117,115,105,110,103,32,115,121,115,116,101,109,32,97,115,115,111,99,105,97,116,105,111,110,115],"value":"Open using system associations"}, {"hash":87681710,"name":"tfrmmain.actsymlink.caption","sourcebytes":[67,114,101,97,116,101,32,83,121,109,98,111,108,105,99,32,38,76,105,110,107,46,46,46],"value":"Create Symbolic &Link..."}, {"hash":11863774,"name":"tfrmmain.acthardlink.caption","sourcebytes":[67,114,101,97,116,101,32,38,72,97,114,100,32,76,105,110,107,46,46,46],"value":"Create &Hard Link..."}, {"hash":170886382,"name":"tfrmmain.actfilespliter.caption","sourcebytes":[83,112,108,38,105,116,32,70,105,108,101,46,46,46],"value":"Spl&it File..."}, {"hash":149064718,"name":"tfrmmain.actfilelinker.caption","sourcebytes":[67,111,109,38,98,105,110,101,32,70,105,108,101,115,46,46,46],"value":"Com&bine Files..."}, {"hash":66284686,"name":"tfrmmain.actchecksumcalc.caption","sourcebytes":[67,97,108,99,117,108,97,116,101,32,67,104,101,99,107,38,115,117,109,46,46,46],"value":"Calculate Check&sum..."}, {"hash":36611454,"name":"tfrmmain.actchecksumverify.caption","sourcebytes":[38,86,101,114,105,102,121,32,67,104,101,99,107,115,117,109,46,46,46],"value":"&Verify Checksum..."}, {"hash":65392019,"name":"tfrmmain.actuniversalsingledirectsort.caption","sourcebytes":[83,111,114,116,32,97,99,99,111,114,100,105,110,103,32,116,111,32,112,97,114,97,109,101,116,101,114,115],"value":"Sort according to parameters"}, {"hash":15440613,"name":"tfrmmain.actcountdircontent.caption","sourcebytes":[83,104,111,38,119,32,79,99,99,117,112,105,101,100,32,83,112,97,99,101],"value":"Sho&w Occupied Space"}, {"hash":135333461,"name":"tfrmmain.acttogglefullscreenconsole.caption","sourcebytes":[84,111,103,103,108,101,32,102,117,108,108,115,99,114,101,101,110,32,109,111,100,101,32,99,111,110,115,111,108,101],"value":"Toggle fullscreen mode console"}, {"hash":35721468,"name":"tfrmmain.acttreeview.caption","sourcebytes":[38,84,114,101,101,32,86,105,101,119,32,80,97,110,101,108],"value":"&Tree View Panel"}, {"hash":149035031,"name":"tfrmmain.actfocustreeview.caption","sourcebytes":[70,111,99,117,115,32,111,110,32,116,114,101,101,32,118,105,101,119],"value":"Focus on tree view"}, {"hash":145180425,"name":"tfrmmain.actfocustreeview.hint","sourcebytes":[83,119,105,116,99,104,32,98,101,116,119,101,101,110,32,99,117,114,114,101,110,116,32,102,105,108,101,32,108,105,115,116,32,97,110,100,32,116,114,101,101,32,118,105,101,119,32,40,105,102,32,101,110,97,98,108,101,100,41],"value":"Switch between current file list and tree view (if enabled)"}, {"hash":34270371,"name":"tfrmmain.actconfigfoldertabs.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,102,111,108,100,101,114,32,116,97,98,115],"value":"Configuration of folder tabs"}, {"hash":110317811,"name":"tfrmmain.actconfigfavoritetabs.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,70,97,118,111,114,105,116,101,32,84,97,98,115],"value":"Configuration of Favorite Tabs"}, {"hash":110489666,"name":"tfrmmain.actclosetab.caption","sourcebytes":[38,67,108,111,115,101,32,84,97,98],"value":"&Close Tab"}, {"hash":74631107,"name":"tfrmmain.actclosealltabs.caption","sourcebytes":[67,108,111,115,101,32,38,65,108,108,32,84,97,98,115],"value":"Close &All Tabs"}, {"hash":91106819,"name":"tfrmmain.actcloseduplicatetabs.caption","sourcebytes":[67,108,111,115,101,32,68,117,112,108,105,99,97,116,101,32,84,97,98,115],"value":"Close Duplicate Tabs"}, {"hash":31278373,"name":"tfrmmain.actcopyalltabstoopposite.caption","sourcebytes":[67,111,112,121,32,97,108,108,32,116,97,98,115,32,116,111,32,111,112,112,111,115,105,116,101,32,115,105,100,101],"value":"Copy all tabs to opposite side"}, {"hash":20366981,"name":"tfrmmain.actloadtabs.caption","sourcebytes":[38,76,111,97,100,32,84,97,98,115,32,102,114,111,109,32,70,105,108,101],"value":"&Load Tabs from File"}, {"hash":235591461,"name":"tfrmmain.actsavetabs.caption","sourcebytes":[38,83,97,118,101,32,84,97,98,115,32,116,111,32,70,105,108,101],"value":"&Save Tabs to File"}, {"hash":190223196,"name":"tfrmmain.actsettaboptionnormal.caption","sourcebytes":[38,78,111,114,109,97,108],"value":"&Normal"}, {"hash":188064148,"name":"tfrmmain.actsettaboptionpathlocked.caption","sourcebytes":[38,76,111,99,107,101,100],"value":"&Locked"}, {"hash":40389188,"name":"tfrmmain.actsettaboptionpathresets.caption","sourcebytes":[76,111,99,107,101,100,32,119,105,116,104,32,38,68,105,114,101,99,116,111,114,121,32,67,104,97,110,103,101,115,32,65,108,108,111,119,101,100],"value":"Locked with &Directory Changes Allowed"}, {"hash":12351107,"name":"tfrmmain.actsettaboptiondirsinnewtab.caption","sourcebytes":[76,111,99,107,101,100,32,119,105,116,104,32,68,105,114,101,99,116,111,114,105,101,115,32,79,112,101,110,101,100,32,105,110,32,78,101,119,32,38,84,97,98,115],"value":"Locked with Directories Opened in New &Tabs"}, {"hash":107254188,"name":"tfrmmain.actsetalltabsoptionnormal.caption","sourcebytes":[83,101,116,32,97,108,108,32,116,97,98,115,32,116,111,32,78,111,114,109,97,108],"value":"Set all tabs to Normal"}, {"hash":105358180,"name":"tfrmmain.actsetalltabsoptionpathlocked.caption","sourcebytes":[83,101,116,32,97,108,108,32,116,97,98,115,32,116,111,32,76,111,99,107,101,100],"value":"Set all tabs to Locked"}, {"hash":207701892,"name":"tfrmmain.actsetalltabsoptionpathresets.caption","sourcebytes":[65,108,108,32,116,97,98,115,32,76,111,99,107,101,100,32,119,105,116,104,32,68,105,114,32,67,104,97,110,103,101,115,32,65,108,108,111,119,101,100],"value":"All tabs Locked with Dir Changes Allowed"}, {"hash":99885971,"name":"tfrmmain.actsetalltabsoptiondirsinnewtab.caption","sourcebytes":[65,108,108,32,116,97,98,115,32,76,111,99,107,101,100,32,119,105,116,104,32,68,105,114,32,79,112,101,110,101,100,32,105,110,32,78,101,119,32,84,97,98,115],"value":"All tabs Locked with Dir Opened in New Tabs"}, {"hash":105962483,"name":"tfrmmain.actloadfavoritetabs.caption","sourcebytes":[76,111,97,100,32,116,97,98,115,32,102,114,111,109,32,70,97,118,111,114,105,116,101,32,84,97,98,115],"value":"Load tabs from Favorite Tabs"}, {"hash":29531011,"name":"tfrmmain.actsavefavoritetabs.caption","sourcebytes":[83,97,118,101,32,99,117,114,114,101,110,116,32,116,97,98,115,32,116,111,32,97,32,78,101,119,32,70,97,118,111,114,105,116,101,32,84,97,98,115],"value":"Save current tabs to a New Favorite Tabs"}, {"hash":163923364,"name":"tfrmmain.actreloadfavoritetabs.caption","sourcebytes":[82,101,108,111,97,100,32,116,104,101,32,108,97,115,116,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,108,111,97,100,101,100],"value":"Reload the last Favorite Tabs loaded"}, {"hash":63258452,"name":"tfrmmain.actresavefavoritetabs.caption","sourcebytes":[82,101,115,97,118,101,32,111,110,32,116,104,101,32,108,97,115,116,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,108,111,97,100,101,100],"value":"Resave on the last Favorite Tabs loaded"}, {"hash":201540580,"name":"tfrmmain.actpreviousfavoritetabs.caption","sourcebytes":[76,111,97,100,32,116,104,101,32,80,114,101,118,105,111,117,115,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,105,110,32,116,104,101,32,108,105,115,116],"value":"Load the Previous Favorite Tabs in the list"}, {"hash":164033780,"name":"tfrmmain.actnextfavoritetabs.caption","sourcebytes":[76,111,97,100,32,116,104,101,32,78,101,120,116,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,105,110,32,116,104,101,32,108,105,115,116],"value":"Load the Next Favorite Tabs in the list"}, {"hash":98943880,"name":"tfrmmain.actactivatetabbyindex.caption","sourcebytes":[65,99,116,105,118,97,116,101,32,84,97,98,32,66,121,32,73,110,100,101,120],"value":"Activate Tab By Index"}, {"hash":45842709,"name":"tfrmmain.actconfigtreeviewmenus.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117],"value":"Configuration of Tree View Menu"}, {"hash":255739843,"name":"tfrmmain.actconfigtreeviewmenuscolors.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117,32,67,111,108,111,114,115],"value":"Configuration of Tree View Menu Colors"}, {"hash":219249491,"name":"tfrmmain.actconfigsearches.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,115,101,97,114,99,104,101,115],"value":"Configuration of searches"}, {"hash":16841203,"name":"tfrmmain.actconfighotkeys.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,104,111,116,32,107,101,121,115],"value":"Configuration of hot keys"}, {"hash":254597918,"name":"tfrmmain.actconfigsavepos.caption","sourcebytes":[83,97,118,101,32,80,111,115,105,116,105,111,110],"value":"Save Position"}, {"hash":87462179,"name":"tfrmmain.actconfigsavesettings.caption","sourcebytes":[83,97,118,101,32,83,101,116,116,105,110,103,115],"value":"Save Settings"}, {"hash":186670788,"name":"tfrmmain.actexecutescript.caption","sourcebytes":[69,120,101,99,117,116,101,32,83,99,114,105,112,116],"value":"Execute Script"}, {"hash":40564547,"name":"tfrmmain.actfocusswap.caption","sourcebytes":[83,119,97,112,32,102,111,99,117,115],"value":"Swap focus"}, {"hash":49986228,"name":"tfrmmain.actfocusswap.hint","sourcebytes":[83,119,105,116,99,104,32,98,101,116,119,101,101,110,32,108,101,102,116,32,97,110,100,32,114,105,103,104,116,32,102,105,108,101,32,108,105,115,116],"value":"Switch between left and right file list"}, {"hash":9348211,"name":"tfrmmain.actconfigarchivers.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,65,114,99,104,105,118,101,114,115],"value":"Configuration of Archivers"}, {"hash":81417667,"name":"tfrmmain.actconfigtooltips.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,116,111,111,108,116,105,112,115],"value":"Configuration of tooltips"}, {"hash":122831395,"name":"tfrmmain.actconfigplugins.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,80,108,117,103,105,110,115],"value":"Configuration of Plugins"}, {"hash":91735966,"name":"tfrmmain.actaddplugin.caption","sourcebytes":[65,100,100,32,80,108,117,103,105,110],"value":"Add Plugin"}, {"hash":124093428,"name":"tfrmmain.actloadlist.caption","sourcebytes":[76,111,97,100,32,76,105,115,116],"value":"Load List"}, {"hash":228327845,"name":"tfrmmain.actloadlist.hint","sourcebytes":[76,111,97,100,32,108,105,115,116,32,111,102,32,102,105,108,101,115,47,102,111,108,100,101,114,115,32,102,114,111,109,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,116,101,120,116,32,102,105,108,101],"value":"Load list of files/folders from the specified text file"}, {"hash":230704005,"name":"tfrmmain.actsavefiledetailstofile.caption","sourcebytes":[83,97,118,101,32,97,108,108,32,115,104,111,119,110,32,99,111,108,117,109,110,115,32,116,111,32,102,105,108,101],"value":"Save all shown columns to file"}, {"hash":104763204,"name":"tfrmmain.actshowtabslist.caption","sourcebytes":[83,104,111,119,32,84,97,98,115,32,76,105,115,116],"value":"Show Tabs List"}, {"hash":154792195,"name":"tfrmmain.actshowtabslist.hint","sourcebytes":[83,104,111,119,32,108,105,115,116,32,111,102,32,97,108,108,32,111,112,101,110,32,116,97,98,115],"value":"Show list of all open tabs"}, {"hash":310020,"name":"tfrmmain.tbedit.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, {"hash":78392485,"name":"tfrmmain.tbdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":1140,"name":"tfrmmain.tbchangedir.caption","sourcebytes":[67,68],"value":"CD"}, {"hash":19140,"name":"tfrmmain.tbcut.caption","sourcebytes":[67,117,116],"value":"Cut"}, {"hash":304761,"name":"tfrmmain.tbcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":5671589,"name":"tfrmmain.tbpaste.caption","sourcebytes":[80,97,115,116,101],"value":"Paste"}, {"hash":43332272,"name":"tfrmmain.mi2080.caption","sourcebytes":[38,50,48,47,56,48],"value":"&20/80"}, {"hash":43397792,"name":"tfrmmain.mi3070.caption","sourcebytes":[38,51,48,47,55,48],"value":"&30/70"}, {"hash":43463312,"name":"tfrmmain.mi4060.caption","sourcebytes":[38,52,48,47,54,48],"value":"&40/60"}, {"hash":43528832,"name":"tfrmmain.mi5050.caption","sourcebytes":[38,53,48,47,53,48],"value":"&50/50"}, {"hash":43594352,"name":"tfrmmain.mi6040.caption","sourcebytes":[38,54,48,47,52,48],"value":"&60/40"}, {"hash":43659872,"name":"tfrmmain.mi7030.caption","sourcebytes":[38,55,48,47,51,48],"value":"&70/30"}, {"hash":43725392,"name":"tfrmmain.mi8020.caption","sourcebytes":[38,56,48,47,50,48],"value":"&80/20"}, {"hash":174571854,"name":"tfrmmain.micopy.caption","sourcebytes":[67,111,112,121,46,46,46],"value":"Copy..."}, {"hash":74219870,"name":"tfrmmain.mimove.caption","sourcebytes":[77,111,118,101,46,46,46],"value":"Move..."}, {"hash":173835486,"name":"tfrmmain.mihardlink.caption","sourcebytes":[67,114,101,97,116,101,32,108,105,110,107,46,46,46],"value":"Create link..."}, {"hash":148506318,"name":"tfrmmain.misymlink.caption","sourcebytes":[67,114,101,97,116,101,32,115,121,109,108,105,110,107,46,46,46],"value":"Create symlink..."}, {"hash":77089212,"name":"tfrmmain.micancel.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"}, {"hash":102797859,"name":"tfrmmain.mitaboptions.caption","sourcebytes":[84,97,98,32,111,112,116,105,111,110,115],"value":"Tab options"}, {"hash":147502805,"name":"tfrmmain.mitrayiconrestore.caption","sourcebytes":[82,101,115,116,111,114,101],"value":"Restore"}, {"hash":4710148,"name":"tfrmmain.mitrayiconexit.caption","sourcebytes":[69,38,120,105,116],"value":"E&xit"}, {"hash":304761,"name":"tfrmmain.milogcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":195288076,"name":"tfrmmain.milogselectall.caption","sourcebytes":[83,101,108,101,99,116,32,65,108,108],"value":"Select All"}, {"hash":4860802,"name":"tfrmmain.milogclear.caption","sourcebytes":[67,108,101,97,114],"value":"Clear"}, {"hash":323493,"name":"tfrmmain.miloghide.caption","sourcebytes":[72,105,100,101],"value":"Hide"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmain.pas����������������������������������������������������������������������0000644�0001750�0000144�00000674106�14743153644�015212� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Licence : GNU GPL v 2.0 Copyright (C) 2006-2023 Alexander Koblov (Alexx2000@mail.ru) Main Dialog window based on: Seksi Commander (radekc.regnet.cz) ---------------------------- Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz Main Dialog window and other stuff contributors: based on (heavy rewriten): main Unit of PFM : Peter's File Manager --------------------------------------- Copyright : Peter Cernoch 2002 Contact : pcernoch@volny.cz Licence : GNU GPL v 2.0 contributors: Copyright (C) 2008 Vitaly Zotov (vitalyzotov@mail.ru) } unit fMain; {$mode objfpc}{$H+} interface uses ufavoritetabs, Graphics, Forms, Menus, Controls, StdCtrls, ExtCtrls, ActnList, Buttons, SysUtils, Classes, SynEdit, LCLType, ComCtrls, LResources, KASToolBar, KASComboBox, uFilePanelSelect, uBriefFileView, VTEmuCtl, VTEmuPty, uFileView, uFileSource, uFileViewNotebook, uFile, LCLVersion, KASToolPanel, uOperationsManager, uFileSourceOperation, uDrivesList, DCClassesUtf8, DCXmlConfig, uDrive, uDriveWatcher, uDCVersion, uMainCommands, uFormCommands, uOperationsPanel, KASToolItems, uKASToolItemsExtended, uCmdLineParams, uOSForms {$IF DEFINED(LCLQT)} , Qt4, QtWidgets {$ELSEIF DEFINED(LCLQT5)} , Qt5, QtWidgets {$ELSEIF DEFINED(LCLQT6)} , Qt6, QtWidgets {$ELSEIF DEFINED(LCLGTK2)} , Glib2, Gtk2 {$ELSEIF DEFINED(DARWIN)} , uMyDarwin {$ENDIF} , Types, LMessages; type TForEachViewFunction = procedure (AFileView: TFileView; UserData: Pointer) of object; { TfrmMain } TfrmMain = class(TAloneForm, IFormCommands) actAddPlugin: TAction; actShowTabsList: TAction; actSaveFileDetailsToFile: TAction; actLoadList: TAction; actExtractFiles: TAction; actAddPathToCmdLine: TAction; actFileAssoc: TAction; actFocusCmdLine: TAction; actContextMenu: TAction; actCopyNamesToClip: TAction; actCopyFullNamesToClip: TAction; actCutToClipboard: TAction; actCopyToClipboard: TAction; actSyncChangeDir: TAction; actChangeDirToRoot: TAction; actCountDirContent: TAction; actCheckSumVerify: TAction; actCheckSumCalc: TAction; actClearLogFile: TAction; actClearLogWindow: TAction; actChangeDir: TAction; actAddFilenameToCmdLine: TAction; actAddPathAndFilenameToCmdLine: TAction; actCopyNoAsk: TAction; actChangeDirToParent: TAction; actEditPath: TAction; actHorizontalFilePanels: TAction; actGoToFirstEntry: TAction; actGoToLastEntry: TAction; actGoToNextEntry: TAction; actGoToPrevEntry: TAction; actGoToFirstFile: TAction; actGoToLastFile: TAction; actCompareDirectories: TAction; actCmdLineNext: TAction; actCmdLinePrev: TAction; actBriefView: TAction; actColumnsView: TAction; actChangeDirToHome: TAction; actCopyFileDetailsToClip: TAction; actFlatView: TAction; actFlatViewSel: TAction; actConfigDirHotList: TAction; actCopyPathOfFilesToClip: TAction; actCopyPathNoSepOfFilesToClip: TAction; actDoAnyCmCommand: TAction; actCloseDuplicateTabs: TAction; actCopyAllTabsToOpposite: TAction; actConfigTreeViewMenus: TAction; actConfigTreeViewMenusColors: TAction; actConfigSavePos: TAction; actConfigSaveSettings: TAction; actExecuteScript: TAction; actFocusSwap: TAction; actConfigArchivers: TAction; actConfigTooltips: TAction; actConfigPlugins: TAction; actUnmarkCurrentNameExt: TAction; actMarkCurrentNameExt: TAction; actUnmarkCurrentName: TAction; actMarkCurrentName: TAction; actUnmarkCurrentPath: TAction; actMarkCurrentPath: TAction; actTreeView: TAction; actFocusTreeView: TAction; actToggleFullscreenConsole: TAction; actSrcOpenDrives: TAction; actRightReverseOrder: TAction; actLeftReverseOrder: TAction; actRightFlatView: TAction; actLeftFlatView: TAction; actRightSortByAttr: TAction; actRightSortByDate: TAction; actRightSortBySize: TAction; actRightSortByExt: TAction; actRightSortByName: TAction; actLeftSortByAttr: TAction; actLeftSortByDate: TAction; actLeftSortBySize: TAction; actLeftSortByExt: TAction; actLeftSortByName: TAction; actLeftThumbView: TAction; actRightThumbView: TAction; actRightColumnsView: TAction; actLeftColumnsView: TAction; actRightBriefView: TAction; actLeftBriefView: TAction; actWorkWithDirectoryHotlist: TAction; actUniversalSingleDirectSort: TAction; actViewLogFile: TAction; actLoadTabs: TAction; actSaveTabs: TAction; actSyncDirs: TAction; actThumbnailsView: TAction; actShellExecute: TAction; actRenameTab: TAction; actOperationsViewer: TAction; actCopyNetNamesToClip: TAction; actNetworkDisconnect: TAction; actNetworkQuickConnect: TAction; actNetworkConnect: TAction; actViewHistory: TAction; actViewHistoryPrev: TAction; actViewHistoryNext: TAction; actLoadSelectionFromClip: TAction; actLoadSelectionFromFile: TAction; actSaveSelectionToFile: TAction; actSaveSelection: TAction; actRestoreSelection: TAction; actSwitchIgnoreList: TAction; actTestArchive: TAction; actQuickView: TAction; actOpenBar: TAction; actSetFileProperties: TAction; actQuickFilter: TAction; actRenameNoAsk: TAction; actPanelsSplitterPerPos: TAction; actMinimize: TAction; actRightEqualLeft: TAction; actLeftEqualRight: TAction; actPasteFromClipboard: TAction; actExchange: TAction; actEditComment: TAction; actHelpIndex: TAction; actVisitHomePage: TAction; actKeyboard: TAction; actPrevTab: TAction; actNextTab: TAction; actMoveTabLeft: TAction; actMoveTabRight: TAction; actActivateTabByIndex: TAction; actCloseAllTabs: TAction; actSetTabOptionNormal: TAction; actSetTabOptionPathLocked: TAction; actSetTabOptionPathResets: TAction; actSetTabOptionDirsInNewTab: TAction; actUnmarkCurrentExtension: TAction; actMarkCurrentExtension: TAction; actWipe: TAction; actOpenDirInNewTab: TAction; actTargetEqualSource: TAction; actOpen: TAction; actQuickSearch: TAction; actShowButtonMenu: TAction; actOpenArchive: TAction; actTransferRight: TAction; actTransferLeft: TAction; actRightOpenDrives: TAction; actLeftOpenDrives: TAction; actOpenVirtualFileSystemList: TAction; actPackFiles: TAction; actCloseTab: TAction; actNewTab: TAction; actConfigToolbars: TAction; actDebugShowCommandParameters: TAction; actOpenDriveByIndex: TAction; btnF10: TSpeedButton; btnF3: TSpeedButton; btnF4: TSpeedButton; btnF5: TSpeedButton; btnF6: TSpeedButton; btnF7: TSpeedButton; btnF8: TSpeedButton; btnF9: TSpeedButton; btnLeftDirectoryHotlist: TSpeedButton; btnRightDirectoryHotlist: TSpeedButton; dskLeft: TKASToolBar; dskRight: TKASToolBar; edtCommand: TComboBoxWithDelItems; imgLstActions: TImageList; imgLstDirectoryHotlist: TImageList; lblRightDriveInfo: TLabel; lblLeftDriveInfo: TLabel; lblCommandPath: TLabel; mnuDoAnyCmCommand: TMenuItem; miConfigArchivers: TMenuItem; mnuConfigSavePos: TMenuItem; mnuConfigSaveSettings: TMenuItem; miLine55: TMenuItem; mnuConfigureFavoriteTabs: TMenuItem; mnuRewriteFavoriteTabs: TMenuItem; mnuCreateNewFavoriteTabs: TMenuItem; mnuReloadActiveFavoriteTabs: TMenuItem; mnuFavoriteTabs: TMenuItem; mnuCloseDuplicateTabs: TMenuItem; miCloseDuplicateTabs: TMenuItem; mnuTreeView: TMenuItem; mnuCmdConfigDirHotlist: TMenuItem; mnuLoadTabs: TMenuItem; mnuSaveTabs: TMenuItem; miLine38: TMenuItem; miFlatView: TMenuItem; miMakeDir: TMenuItem; miWipe: TMenuItem; miDelete: TMenuItem; miLine50: TMenuItem; miCopyFileDetailsToClip: TMenuItem; mnuCmdSyncDirs: TMenuItem; mnuContextRenameOnly: TMenuItem; mnuContextCopy: TMenuItem; mnuContextOpen: TMenuItem; mnuContextLine1: TMenuItem; mnuContextLine2: TMenuItem; mnuContextFileProperties: TMenuItem; mnuContextDelete: TMenuItem; mnuContextView: TMenuItem; mnuThumbnailsView: TMenuItem; mnuColumnsView: TMenuItem; mnuBriefView: TMenuItem; miLine33: TMenuItem; mnuAllOperStart: TMenuItem; mnuAllOperStop: TMenuItem; mnuAllOperPause: TMenuItem; mnuAllOperProgress: TMenuItem; miCompareDirectories: TMenuItem; miLine37: TMenuItem; miRenameTab: TMenuItem; pnlMain: TPanel; tbChangeDir: TMenuItem; mnuShowHorizontalFilePanels: TMenuItem; miLine20: TMenuItem; miNetworkDisconnect: TMenuItem; miNetworkQuickConnect: TMenuItem; miNetworkConnect: TMenuItem; mnuNetwork: TMenuItem; pnlDskLeft: TPanel; pnlDiskLeftInner: TKASToolPanel; pnlDskRight: TPanel; pnlDiskRightInner: TKASToolPanel; Timer: TTimer; PanelAllProgress: TPanel; pbxRightDrive: TPaintBox; pbxLeftDrive: TPaintBox; tbPaste: TMenuItem; tbCopy: TMenuItem; tbCut: TMenuItem; tbSeparator: TMenuItem; mnuLoadSelectionFromClip: TMenuItem; mnuLoadSelectionFromFile: TMenuItem; mnuSaveSelectionToFile: TMenuItem; mnuRestoreSelection: TMenuItem; mnuSaveSelection: TMenuItem; miLine47: TMenuItem; mnuTestArchive: TMenuItem; mnuQuickView: TMenuItem; miLine32: TMenuItem; miLine14: TMenuItem; mnuTabOptionNormal: TMenuItem; mnuTabOptionDirsInNewTabs: TMenuItem; mnuTabOptions: TMenuItem; miTabOptionPathResets: TMenuItem; miTabOptionDirsInNewTab: TMenuItem; miTabOptionPathLocked: TMenuItem; miTabOptionNormal: TMenuItem; miTabOptions: TMenuItem; miLine19: TMenuItem; mnuSetFileProperties: TMenuItem; mnuShowOperations: TMenuItem; miLine13: TMenuItem; miLogClear: TMenuItem; miLogHide: TMenuItem; miLine25: TMenuItem; miLogSelectAll: TMenuItem; miLogCopy: TMenuItem; miLine24: TMenuItem; miTrayIconRestore: TMenuItem; miLine8: TMenuItem; miTrayIconExit: TMenuItem; mnuCheckSumCalc: TMenuItem; mnuCheckSumVerify: TMenuItem; mnuCountDirContent: TMenuItem; miLine22: TMenuItem; miLine18: TMenuItem; mnuHelpIndex: TMenuItem; mnuHelpVisitHomePage: TMenuItem; mnuHelpKeyboard: TMenuItem; MenuItem2: TMenuItem; mnuPrevTab: TMenuItem; mnuNextTab: TMenuItem; miLine17: TMenuItem; miLine16: TMenuItem; mnuTabOptionPathLocked: TMenuItem; mnuTabOptionPathResets: TMenuItem; mnuCloseAllTabs: TMenuItem; mnuCloseTab: TMenuItem; miLine15: TMenuItem; mnuOpenDirInNewTab: TMenuItem; mnuNewTab: TMenuItem; miCloseAllTabs: TMenuItem; miCloseTab: TMenuItem; miNewTab: TMenuItem; miEditComment: TMenuItem; mnuMarkCurrentExtension: TMenuItem; mnuTabs: TMenuItem; mnuUnmarkCurrentExtension: TMenuItem; miSymLink: TMenuItem; miHardLink: TMenuItem; miCancel: TMenuItem; miLine12: TMenuItem; miCopy: TMenuItem; miMove: TMenuItem; mi8020: TMenuItem; mi7030: TMenuItem; mi6040: TMenuItem; mi5050: TMenuItem; mi4060: TMenuItem; mi3070: TMenuItem; mi2080: TMenuItem; miCopyFullNamesToClip: TMenuItem; miCopyNamesToClip: TMenuItem; mnuFileAssoc: TMenuItem; nbConsole: TPageControl; pgConsole: TTabSheet; pnlCmdLine: TPanel; MainSplitter: TPanel; MainToolBar: TKASToolBar; MiddleToolBar: TKASToolBar; mnuOpenVFSList: TMenuItem; mnuExtractFiles: TMenuItem; pmContextMenu: TPopupMenu; pmSplitterPercent: TPopupMenu; pnlCommand: TPanel; pnlKeys: TPanel; pnlLeftTools: TPanel; pnlRightTools: TPanel; pnlRight: TPanel; pnlLeft: TPanel; btnLeftDrive: TSpeedButton; btnLeftHome: TSpeedButton; btnLeftUp: TSpeedButton; btnLeftRoot: TSpeedButton; btnRightDrive: TSpeedButton; btnRightHome: TSpeedButton; btnRightUp: TSpeedButton; btnRightRoot: TSpeedButton; LogSplitter: TSplitter; pmColumnsMenu: TPopupMenu; pmDropMenu: TPopupMenu; pmTabMenu: TPopupMenu; pmTrayIconMenu: TPopupMenu; pmLogMenu: TPopupMenu; seLogWindow: TSynEdit; btnRightEqualLeft: TSpeedButton; btnLeftEqualRight: TSpeedButton; ConsoleSplitter: TSplitter; tbDelete: TMenuItem; tbEdit: TMenuItem; mnuMain: TMainMenu; pnlNotebooks: TPanel; pnlDisk: TKASToolPanel; mnuHelp: TMenuItem; mnuHelpAbout: TMenuItem; mnuShow: TMenuItem; mnuShowName: TMenuItem; mnuShowExtension: TMenuItem; mnuShowTime: TMenuItem; mnuShowSize: TMenuItem; mnuShowAttrib: TMenuItem; miLine7: TMenuItem; mnuShowReverse: TMenuItem; mnuShowReread: TMenuItem; mnuFiles: TMenuItem; mnuPackFiles : TMenuItem; mnuFilesSplit: TMenuItem; mnuFilesCombine: TMenuItem; mnuCmd: TMenuItem; mnuCmdDirHotlist: TMenuItem; miLine2: TMenuItem; mnuFilesSpace: TMenuItem; mnuFilesAttrib: TMenuItem; mnuFilesProperties: TMenuItem; miLine6: TMenuItem; mnuCmdSwapSourceTarget: TMenuItem; mnuCmdTargetIsSource: TMenuItem; miLine3: TMenuItem; mnuFilesShwSysFiles: TMenuItem; miLine1: TMenuItem; mnuFilesHardLink: TMenuItem; mnuFilesSymLink: TMenuItem; mnuConfig: TMenuItem; mnuConfigOptions: TMenuItem; mnuMark: TMenuItem; mnuMarkSGroup: TMenuItem; mnuMarkUGroup: TMenuItem; mnuMarkSAll: TMenuItem; mnuMarkUAll: TMenuItem; mnuMarkInvert: TMenuItem; miLine5: TMenuItem; mnuCmdSearch: TMenuItem; mnuCmdAddNewSearch:TMenuItem; mnuCmdViewSearches:TMenuItem; actionLst: TActionList; actExit: TAction; actView: TAction; actEdit: TAction; actCopy: TAction; actRename: TAction; actMakeDir: TAction; actDelete: TAction; actAbout: TAction; actShowSysFiles: TAction; actOptions: TAction; mnuFilesCmpCnt: TMenuItem; actCompareContents: TAction; actShowMainMenu: TAction; actRefresh: TAction; actSearch: TAction; actAddNewSearch: TAction; actViewSearches: TAction; actDeleteSearches: TAction; actConfigSearches: TAction; actConfigHotKeys: TAction; actDirHotList: TAction; actMarkMarkAll: TAction; actMarkInvert: TAction; actMarkUnmarkAll: TAction; pmHotList: TPopupMenu; actMarkPlus: TAction; actMarkMinus: TAction; actSymLink: TAction; actHardLink: TAction; actReverseOrder: TAction; actSortByName: TAction; actSortByExt: TAction; actSortBySize: TAction; actSortByDate: TAction; actSortByAttr: TAction; miLine4: TMenuItem; miExit: TMenuItem; actMultiRename: TAction; miMultiRename: TMenuItem; actCopySamePanel: TAction; actRenameOnly: TAction; actEditNew: TAction; actDirHistory: TAction; pmDirHistory: TPopupMenu; actShowCmdLineHistory: TAction; actRunTerm: TAction; miLine9: TMenuItem; miRunTerm: TMenuItem; actBenchmark: TAction; actCalculateSpace: TAction; actFileProperties: TAction; actFileLinker: TAction; actFileSpliter: TAction; pmToolBar: TPopupMenu; MainTrayIcon: TTrayIcon; TreePanel: TPanel; TreeSplitter: TSplitter; ShellTreeView: TCustomTreeView; miLine10: TMenuItem; miLine11: TMenuItem; miLine21: TMenuItem; miLine23: TMenuItem; miLine26: TMenuItem; miLine39: TMenuItem; miLine40: TMenuItem; actSetAllTabsOptionNormal: TAction; actSetAllTabsOptionPathLocked: TAction; actSetAllTabsOptionPathResets: TAction; actSetAllTabsOptionDirsInNewTab: TAction; actConfigFolderTabs: TAction; actLoadFavoriteTabs: TAction; actConfigFavoriteTabs: TAction; actSaveFavoriteTabs: TAction; actReloadFavoriteTabs: TAction; actNextFavoriteTabs: TAction; actPreviousFavoriteTabs: TAction; pmFavoriteTabs: TPopupMenu; mnuRenameTab: TMenuItem; mnuConfigFolderTabs: TMenuItem; mnuConfigFavoriteTabs: TMenuItem; mnuConfigurationFavoriteTabs: TMenuItem; mnuSaveFavoriteTabs: TMenuItem; mnuLoadFavoriteTabs: TMenuItem; mnuConfigurationFolderTabs: TMenuItem; mnuSetAllTabsOptionNormal: TMenuItem; mnuSetAllTabsOptionPathLocked: TMenuItem; mnuSetAllTabsOptionPathResets: TMenuItem; mnuSetAllTabsOptionDirsInNewTab: TMenuItem; miConfigFolderTabs: TMenuItem; miConfigFavoriteTabs: TMenuItem; miNextTab: TMenuItem; miPrevTab: TMenuItem; miSaveTabs: TMenuItem; miLoadTabs: TMenuItem; miSaveFavoriteTabs: TMenuItem; miLoadFavoriteTabs: TMenuItem; miSetAllTabsOptionNormal: TMenuItem; miSetAllTabsOptionPathLocked: TMenuItem; miSetAllTabsOptionPathResets: TMenuItem; miSetAllTabsOptionDirsInNewTab: TMenuItem; miOpenDirInNewTab: TMenuItem; actResaveFavoriteTabs: TAction; procedure actExecute(Sender: TObject); procedure btnF3MouseWheelDown(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var {%H-}Handled: Boolean); procedure btnF3MouseWheelUp(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var {%H-}Handled: Boolean); procedure btnF8MouseDown(Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer); procedure ConsoleSplitterMoved(Sender: TObject); procedure dskToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormKeyUp( Sender: TObject; var {%H-}Key: Word; Shift: TShiftState) ; procedure FormResize(Sender: TObject); procedure lblDriveInfoResize(Sender: TObject); function MainToolBarToolItemShortcutsHint(Sender: TObject; ToolItem: TKASNormalItem): String; procedure mnuAllOperStartClick(Sender: TObject); procedure mnuAllOperStopClick(Sender: TObject); procedure mnuAllOperPauseClick(Sender: TObject); procedure mnuAllOperProgressClick(Sender: TObject); procedure btnF8Click(Sender: TObject); procedure btnLeftClick(Sender: TObject); procedure btnLeftDirectoryHotlistClick(Sender: TObject); procedure btnRightClick(Sender: TObject); procedure btnRightDirectoryHotlistClick(Sender: TObject); procedure btnDriveMouseUp(Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer); procedure ConsoleSplitterCanResize(Sender: TObject; var NewSize: Integer; var {%H-}Accept: Boolean); procedure dskLeftRightToolButtonDragDrop(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: Integer); procedure dskToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure lblAllProgressPctClick(Sender: TObject); procedure MainToolBarToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer); procedure MainToolBarToolButtonDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean; NumberOfButton: Integer); procedure MainToolBarToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure MainToolBarToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure miLogMenuClick(Sender: TObject); procedure miTrayIconExitClick(Sender: TObject); procedure miTrayIconRestoreClick(Sender: TObject); procedure PanelButtonClick(Button: TSpeedButton; FileView: TFileView); procedure ShellTreeViewSelect; procedure ShellTreeViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure ShellTreeViewMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure tbDeleteClick(Sender: TObject); procedure dskLeftToolButtonClick(Sender: TObject); procedure dskRightToolButtonClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormDropFiles(Sender: TObject; const FileNames: array of String); procedure FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); procedure FormWindowStateChange(Sender: TObject); procedure MainSplitterDblClick(Sender: TObject); procedure MainSplitterMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure MainSplitterMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure MainSplitterMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure MainTrayIconClick(Sender: TObject); procedure lblDriveInfoDblClick(Sender: TObject); procedure MainToolBarDragDrop(Sender, Source: TObject; X, Y: Integer); procedure MainToolBarDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); function MainToolBarLoadButtonGlyph(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; function MainToolBarLoadButtonOverlay(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; procedure MainToolBarMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure frmMainClose(Sender: TObject; var CloseAction: TCloseAction); procedure frmMainAfterShow(Sender: TObject); procedure frmMainShow(Sender: TObject); procedure mnuDropClick(Sender: TObject); procedure mnuSplitterPercentClick(Sender: TObject); procedure mnuTabMenuExecute(Sender: TObject); procedure mnuTabMenuClick(Sender: TObject); procedure nbPageAfterMouseDown(Data: PtrInt); procedure nbPageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure nbPageChanged(Sender: TObject); procedure nbPageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure NotebookDragDrop(Sender, Source: TObject; X, Y: Integer); procedure NotebookDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure NotebookCloseTabClicked(Sender: TObject); procedure pmDropMenuClose(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); procedure edtCommandKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure pmToolBarPopup(Sender: TObject); procedure ShellTreeViewAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean); procedure pnlLeftResize(Sender: TObject); procedure pnlLeftRightDblClick(Sender: TObject); procedure pnlNotebooksResize(Sender: TObject); procedure pnlRightResize(Sender: TObject); procedure sboxDrivePaint(Sender: TObject); procedure PaintDriveFreeBar(Sender: TObject; const bIndUseGradient: boolean; const pIndForeColor, pIndThresholdForeColor, pIndBackColor: TColor); procedure seLogWindowSpecialLineColors(Sender: TObject; Line: integer; var Special: boolean; var FG, BG: TColor); procedure FileViewFreeAsync(Data: PtrInt); function FileViewAutoSwitch(FileSource: IFileSource; var FileView: TFileView; Reason: TChangePathReason; const NewPath: String): Boolean; function FileViewBeforeChangePath(FileView: TFileView; NewFileSource: IFileSource; Reason: TChangePathReason; const NewPath : String): Boolean; procedure FileViewAfterChangePath(FileView: TFileView); procedure FileViewActivate(FileView: TFileView); procedure FileViewFilesChanged(FileView: TFileView); procedure edtCommandKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure edtCommandExit(Sender: TObject); procedure tbChangeDirClick(Sender: TObject); procedure tbCopyClick(Sender: TObject); procedure tbEditClick(Sender: TObject); procedure OnUniqueInstanceMessage(Sender: TObject; Params: TCommandLineParams); procedure tbPasteClick(Sender: TObject); procedure AllProgressOnUpdateTimer(Sender: TObject); procedure OperationManagerNotify(Item: TOperationsManagerItem; Event: TOperationManagerEvent); {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)} private QEventHook: QObject_hookH; function QObjectEventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; {$ENDIF} {$IF DEFINED(LCLGTK2)} procedure WindowStateUpdate(Data: PtrInt); {$ENDIF} private { Private declarations } FMainSplitterPos: Double; PanelSelected: TFilePanelSelect; DrivesList : TDrivesList; MainSplitterHintWnd: THintWindow; HiddenToTray: Boolean; HidingTrayIcon: Boolean; // @true if the icon is in the process of hiding nbLeft, nbRight: TFileViewNotebook; cmdConsole: TVirtualTerminal; FCommands: TMainCommands; FInitializedView: Boolean; {en Used to pass drag&drop parameters to pmDropMenu. Single variable can be used, because the user can do only one menu popup at a time. } FDropParams: TDropParams; FDrivesListPopup: TDrivesListPopup; FOperationsPanel: TOperationsPanel; FSyncChangeParent: Boolean; FSyncChangeDir: String; sStaticTitleBarString: String; // frost_asm begin // mainsplitter MainSplitterLeftMouseBtnDown: Boolean; MainSplitterMouseDownX, MainSplitterMouseDownY: Integer; FResizingFilePanels: Boolean; // lastWindowState lastWindowState:TWindowState; // frost_asm end // for dragging buttons and etc NumberOfMoveButton, NumberOfNewMoveButton: integer; Draging : boolean; FUpdateDiskCount: Boolean; FModalOperationResult: Boolean; FRestoredLeft: Integer; FRestoredTop: Integer; FRestoredWidth: Integer; FRestoredHeight: Integer; FDelayedEventCtr: Integer; FDelayedWMMove, FDelayedWMSize: Boolean; procedure DelayedEvent(Data: PtrInt); procedure CheckCommandLine(ShiftEx: TShiftState; var Key: Word); function ExecuteCommandFromEdit(sCmd: String; bRunInTerm: Boolean): Boolean; procedure SetMainSplitterPos(AValue: Double); procedure SetPanelSelected(AValue: TFilePanelSelect); procedure UpdateActionIcons; procedure UpdateHotDirIcons; procedure TypeInCommandLine(Str: String); procedure AddSpecialButtons(dskPanel: TKASToolBar); procedure HideToTray; procedure RestoreFromTray; procedure ShowTrayIcon(bShow: Boolean); procedure HideTrayIconDelayed(Data: PtrInt); procedure PopupDragDropMenu(var DropParams: TDropParams); procedure CloseNotebook(ANotebook: TFileViewNotebook); procedure DriveListDriveSelected(Sender: TObject; ADriveIndex: Integer; APanel: TFilePanelSelect); procedure DriveListClose(Sender: TObject); function FindMatchingDrive(Address, Path: String): Integer; procedure UpdateDriveToolbarSelection(DriveToolbar: TKAStoolBar; FileView: TFileView); procedure UpdateDriveButtonSelection(DriveButton: TSpeedButton; FileView: TFileView); {$IF DEFINED(MSWINDOWS)} procedure OnDriveIconLoaded(Data: PtrInt); {$ENDIF} procedure OnDriveGetFreeSpace(Data: PtrInt); procedure OnDriveWatcherEvent(EventType: TDriveWatcherEvent; const ADrive: PDrive); procedure AppActivate(Sender: TObject); procedure AppDeActivate(Sender: TObject); procedure AppEndSession(Sender: TObject); procedure AppThemeChange(Sender: TObject); procedure AppQueryEndSession(var Cancel: Boolean); procedure AppException(Sender: TObject; E: Exception); procedure AppShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); {en Convert toolbar configuration from .bar file to global config. } procedure ConvertToolbarBarConfig(BarFileName: String); procedure ConvertIniToolbarItem(Loader: TKASToolBarIniLoader; var Item: TKASToolItem; const Shortcut: String); procedure CreateDefaultToolbar; procedure EditToolbarButton(Toolbar: TKASToolBar; Button: TKASToolButton); procedure ToolbarExecuteCommand(ToolItem: TKASToolItem); procedure ToolbarExecuteProgram(ToolItem: TKASToolItem); procedure LeftDriveBarExecuteDrive(ToolItem: TKASToolItem); procedure RightDriveBarExecuteDrive(ToolItem: TKASToolItem); procedure SetDragCursor(Shift: TShiftState); {$IFDEF DARWIN} procedure createDarwinAppMenu; procedure aboutOnClick(Sender: TObject); procedure optionsOnClick(Sender: TObject); {$ENDIF} protected procedure CreateWnd; override; procedure DoFirstShow; override; procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; procedure WMMove(var Message: TLMMove); message LM_MOVE; procedure WMSize(var message: TLMSize); message LM_Size; public constructor Create(TheOwner: TComponent); override; procedure AfterConstruction; override; Function ActiveFrame: TFileView; // get Active frame Function NotActiveFrame: TFileView; // get NotActive frame :) function ActiveNotebook: TFileViewNotebook; function NotActiveNotebook: TFileViewNotebook; function FrameLeft: TFileView; function FrameRight: TFileView; procedure ForEachView(CallbackFunction: TForEachViewFunction; UserData: Pointer); procedure GetListOpenedPaths(const APaths:TStringList); //check selected count and generate correct msg, parameters is lng indexs Function GetFileDlgStr(sLngOne, sLngMulti : String; Files: TFiles):String; procedure HotDirSelected(Sender:TObject); procedure HotDirActualSwitchToDir(Index:longint); procedure HistorySelected(Sender:TObject); procedure HistorySomeSelected(Sender:TObject); procedure ViewHistorySelected(Sender:TObject); procedure ViewHistoryPrevSelected(Sender:TObject); procedure ViewHistoryNextSelected(Sender:TObject); procedure CreatePopUpDirHistory(UseTreeViewMenu: Boolean; FromPathIndex: Integer); procedure ShowFileViewHistory(const Params: array of string); procedure ShowFileViewHistory(const Params: array of string; FromFileSourceIndex, FromPathIndex, ToFileSourceIndex, ToPathIndex: Integer); procedure miHotAddOrConfigClick(Sender: TObject); procedure OnCopyOutTempStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); {en Returns @true if copy operation has been successfully started. } function CopyFiles(SourceFileSource, TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload; {en Returns @true if move operation has been successfully started. } function MoveFiles(SourceFileSource, TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload; function CopyFiles(sDestPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload; // this is for F5 and Shift+F5 function MoveFiles(sDestPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; overload; procedure GetDestinationPathAndMask(SourceFiles: TFiles; TargetFileSource: IFileSource; EnteredPath: String; BaseDir: String; out DestPath, DestMask: String); overload; procedure GetDestinationPathAndMask(SourceFiles: TFiles; SourceFileSource: IFileSource; var TargetFileSource: IFileSource; EnteredPath: String; BaseDir: String; out DestPath, DestMask: String); overload; procedure SetActiveFrame(panel: TFilePanelSelect); procedure SetActiveFrame(FileView: TFileView); procedure UpdateFileView; procedure UpdateShellTreeView; procedure UpdateTreeViewPath; procedure UpdateTreeView; procedure UpdateDiskCount; procedure UpdateSelectedDrives; procedure UpdateGUIFunctionKeys; procedure UpdateMainTitleBar; procedure CreateDiskPanel(dskPanel : TKASToolBar); procedure UpdateSelectedDrive(ANoteBook: TFileViewNotebook); procedure SetPanelDrive(aPanel: TFilePanelSelect; Drive: PDrive; ActivateIfNeeded: Boolean); function CreateFileView(sType: String; Page: TFileViewPage; AConfig: TXmlConfig; ANode: TXmlNode): TFileView; procedure AssignEvents(AFileView: TFileView); function RemovePage(ANoteBook: TFileViewNotebook; iPageIndex:Integer; CloseLocked: Boolean = True; ConfirmCloseLocked: integer = 0; ShowButtonAll: Boolean = False): LongInt; procedure LoadTabsXml(AConfig: TXmlConfig; ABranch:string; ANoteBook: TFileViewNotebook); procedure SaveTabsXml(AConfig: TXmlConfig; ABranch:string; ANoteBook: TFileViewNotebook; ASaveHistory: boolean); procedure LoadTheseTabsWithThisConfig(Config: TXmlConfig; ABranch:string; Source, Destination:TTabsConfigLocation; DestinationToKeep : TTabsConfigLocation; var TabsAlreadyDestroyedFlags:TTabsFlagsAlreadyDestroyed); procedure ToggleConsole; procedure UpdateWindowView; procedure MinimizeWindow; procedure RestoreWindow; procedure LoadTabs; procedure LoadTabsCommandLine(Params: TCommandLineParams); procedure AddTab(ANoteBook: TFileViewNotebook; aPath: String); {$IF DEFINED(DARWIN)} procedure OnNSServiceOpenWithNewTab( filenames:TStringList ); function NSServiceMenuIsReady(): boolean; function NSServiceMenuGetFilenames(): TStringList; procedure NSThemeChangedHandler(); {$ENDIF} procedure LoadWindowState; procedure SaveWindowState; procedure LoadToolbar(AToolBar: TKASToolBar); procedure SaveToolBar(AToolBar: TKASToolBar); procedure ShowLogWindow(Data: PtrInt); function IsCommandLineVisible: Boolean; procedure ShowCommandLine(AFocus: Boolean); procedure ConfigSaveSettings(bForce: Boolean); procedure ShowDrivesList(APanel: TFilePanelSelect); procedure ExecuteCommandLine(bRunInTerm: Boolean); procedure UpdatePrompt; procedure UpdateFreeSpace(Panel: TFilePanelSelect; Clear: Boolean); procedure ReLoadTabs(ANoteBook: TFileViewNotebook); procedure ShowOptionsLayout(Data: PtrInt); procedure ToggleFullscreenConsole; {en This function is called from various points to handle dropping files into the panel. It converts drop effects available on the system into TDragDropOperation operations. Handles freeing DropParams. } procedure DropFiles(var DropParams: TDropParams); {en Performs all drag&drop actions. Frees DropParams. } procedure DoDragDropOperation(Operation: TDragDropOperation; var DropParams: TDropParams); property Drives: TDrivesList read DrivesList; property SyncChangeDir: String write FSyncChangeDir; property Commands: TMainCommands read FCommands implements IFormCommands; property SelectedPanel: TFilePanelSelect read PanelSelected write SetPanelSelected; property LeftTabs: TFileViewNotebook read nbLeft; property RightTabs: TFileViewNotebook read nbRight; property MainSplitterPos: Double read FMainSplitterPos write SetMainSplitterPos; property StaticTitle: String read sStaticTitleBarString write sStaticTitleBarString; end; var frmMain: TfrmMain; Cons: TCustomPtyDevice = nil; implementation {$R *.lfm} uses Themes, uFileProcs, uShellContextMenu, fTreeViewMenu, uSearchResultFileSource, Math, LCLIntf, Dialogs, uGlobs, uLng, uMasks, fCopyMoveDlg, uQuickViewPanel, uShowMsg, uDCUtils, uLog, uGlobsPaths, LCLProc, uOSUtils, uPixMapManager, LazUTF8, uDragDropEx, uKeyboard, uFileSystemFileSource, fViewOperations, uMultiListFileSource, uFileSourceOperationTypes, uFileSourceCopyOperation, uFileSourceMoveOperation, uFileSourceProperty, uFileSourceExecuteOperation, uArchiveFileSource, uThumbFileView, uShellExecute, fSymLink, fHardLink, uExceptions, uUniqueInstance, Clipbrd, ShellCtrls, uFileSourceOperationOptionsUI, uDebug, uHotkeyManager, uFileSourceUtil, uTempFileSystemFileSource, Laz2_XMLRead, DCOSUtils, DCStrUtils, fOptions, fOptionsFrame, fOptionsToolbar, uClassesEx, uHotDir, uFileSorting, DCBasicTypes, foptionsDirectoryHotlist, uConnectionManager, fOptionsToolbarBase, fOptionsToolbarMiddle, fEditor, uColumns, StrUtils, uSysFolders, uColumnsFileView, dmHigh, uFileSourceOperationMisc {$IFDEF MSWINDOWS} , uShellFileSource, uNetworkThread {$ENDIF} ; const HotkeysCategory = 'Main'; DCToolItemClipboardHeader = 'DOUBLECMD#TOOLBAR#XMLDATA'; TCToolbarClipboardHeader = 'TOTALCMD#BAR#DATA'; DCToolbarClipboardHeader = 'DOUBLECMD#BAR#DATA'; {$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} var LastActiveWindow: TCustomForm = nil; {$ENDIF} {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)} var CloseQueryResult: Boolean = False; {$ENDIF} {$IFDEF LCLGTK2} var MinimizedWindowButton: Boolean = False; {$ENDIF} var FunctionButtonsCaptions: array[0..7] of record ACaption: String; ACommand: String; end = ((ACaption: ''; ACommand: 'cm_View'), (ACaption: ''; ACommand: 'cm_Edit'), (ACaption: ''; ACommand: 'cm_Copy'), (ACaption: ''; ACommand: 'cm_Rename'), (ACaption: ''; ACommand: 'cm_MakeDir'), (ACaption: ''; ACommand: 'cm_Delete'), (ACaption: ''; ACommand: 'cm_RunTerm'), (ACaption: ''; ACommand: 'cm_Exit')); type { TFreeSpaceData } TFreeSpaceData = class Path: String; Result: Boolean; OnFinish: TDataEvent; Panel: TFilePanelSelect; FileSource: IFileSource; FreeSize, TotalSize : Int64; procedure GetFreeSpaceInThread; end; { TShellTreeView } TShellTreeView = class(ShellCtrls.TShellTreeView) protected function CanExpand(Node: TTreeNode): Boolean; override; function ShellTreeViewSort(Node1, Node2: TTreeNode): Integer; end; function HistoryIndexesToTag(aFileSourceIndex, aPathIndex: Integer): Longint; begin Result := (aFileSourceIndex << 16) or aPathIndex; end; procedure HistoryIndexesFromTag(aTag: Longint; out aFileSourceIndex, aPathIndex: Integer); begin aFileSourceIndex := aTag >> 16; aPathIndex := aTag and ((1<<16) - 1); end; { TFreeSpaceData } procedure TFreeSpaceData.GetFreeSpaceInThread; begin Result:= FileSource.GetFreeSpace(Path, FreeSize, TotalSize); if Assigned(Application) and not (AppDoNotCallAsyncQueue in Application.Flags) then Application.QueueAsyncCall(OnFinish, PtrInt(Self)); end; { TShellTreeView } function TShellTreeView.CanExpand(Node: TTreeNode): Boolean; begin Result:= inherited CanExpand(Node); if Result then Node.CustomSort(@ShellTreeViewSort); end; function TShellTreeView.ShellTreeViewSort(Node1, Node2: TTreeNode): Integer; begin Result:= CompareStrings(Node1.Text, Node2.Text, gSortNatural, gSortSpecial, gSortCaseSensitivity); end; { TfrmMain } procedure TfrmMain.FormCreate(Sender: TObject); function CreateNotebook(aParent: TWinControl; aSide: TFilePanelSelect): TFileViewNotebook; begin Result := TFileViewNotebook.Create(aParent, aSide); Result.Align := alClient; Result.Options := [nboHidePageListPopup]; {$if lcl_fullversion >= 1070000} Result.Options := Result.Options + [nboDoChangeOnSetIndex]; {$endif} Result.OnCloseTabClicked := @NotebookCloseTabClicked; Result.OnMouseDown := @nbPageMouseDown; Result.OnMouseUp := @nbPageMouseUp; Result.OnChange := @nbPageChanged; Result.OnDblClick := @pnlLeftRightDblClick; Result.OnDragOver:= @NotebookDragOver; Result.OnDragDrop:= @NotebookDragDrop; end; function GenerateTitle(): String; var R: Integer; ARevision, AServerName: String; begin if Length(UniqueInstance.ServernameByUser) > 0 then AServerName := ' [' + UniqueInstance.ServernameByUser + ']' else begin AServerName := EmptyStr; end; if TryStrToInt(dcRevision, R) then ARevision:= '~' + dcRevision else begin ARevision:= EmptyStr; end; Result := Format('%s%s %s%s', ['Double Commander', AServerName, Copy2Space(dcVersion), ARevision] ); end; var HMMainForm: THMForm; I: Integer; begin Application.OnException := @AppException; Application.OnActivate := @AppActivate; Application.OnDeActivate := @AppDeActivate; Application.OnShowHint := @AppShowHint; Application.OnEndSession := @AppEndSession; Application.OnQueryEndSession := @AppQueryEndSession; {$IF DEFINED(DARWIN)} // in LCL's DARWIN implements, there is no way but to Use LCL's method of dropping files // from external applications frmMain.OnDropFiles := @FormDropFiles; AllowDropFiles := true; // DARWIN support external DragDragSource only, not DragDragTarget {$ELSE} // Use LCL's method of dropping files from external // applications if we don't support it ourselves. if not IsExternalDraggingSupported then frmMain.OnDropFiles := @FormDropFiles; AllowDropFiles := not uDragDropEx.IsExternalDraggingSupported; {$ENDIF} {$IF DEFINED(DARWIN)} // MainForm receives in Mac OS closing events on system shortcut Command-Q // See details at http://doublecmd.sourceforge.net/mantisbt/view.php?id=712 Application.MainForm.OnClose := @frmMainClose; Application.MainForm.OnCloseQuery := @FormCloseQuery; {$ENDIF} ConvertToolbarBarConfig(gpCfgDir + 'default.bar'); CreateDefaultToolbar; sStaticTitleBarString := GenerateTitle(); // Remove the initial caption of the button, which is just a text of the associated action. // The text would otherwise be briefly shown before the drive button was updated. btnLeftDrive.Caption := ''; btnRightDrive.Caption := ''; //Have the correct button label to indicate root btnLeftRoot.Caption:=DirectorySeparator; btnRightRoot.Caption:=DirectorySeparator; for I := 0 to pnlKeys.ControlCount - 1 do FunctionButtonsCaptions[I].ACaption := pnlKeys.Controls[I].Caption; {$IF DEFINED(LCLGTK2)} // Workaround: "Layout and line" // http://doublecmd.sourceforge.net/mantisbt/view.php?id=573 TreePanel.Visible := False; pnlLeftTools.Visible := False; pnlRightTools.Visible := False; PanelAllProgress.Visible := False; {$ENDIF} InitPropStorage(Self); PanelSelected:=fpLeft; seLogWindow.FixDefaultKeystrokes; HMMainForm := HotMan.Register(Self, HotkeysCategory); HotMan.Register(edtCommand, 'Command Line'); nbLeft := CreateNotebook(pnlLeft, fpLeft); nbRight := CreateNotebook(pnlRight, fpRight); FDrivesListPopup := TDrivesListPopup.Create(Self, Self); FDrivesListPopup.OnDriveSelected := @DriveListDriveSelected; FDrivesListPopup.OnClose := @DriveListClose; //NOTE: we don't check gOnlyOneAppInstance anymore, because cmdline option "--client" was implemented, // so, we should always listen for the messages if Assigned(UniqueInstance) then UniqueInstance.OnMessage:= @OnUniqueInstanceMessage; MainFormCreate(Self); // Load command line history edtCommand.Items.Assign(glsCmdLineHistory); // Initialize actions. actShowSysFiles.Checked := uGlobs.gShowSystemFiles; actHorizontalFilePanels.Checked := gHorizontalFilePanels; MainToolBar.AddToolItemExecutor(TKASCommandItem, @ToolbarExecuteCommand); MainToolBar.AddToolItemExecutor(TKASProgramItem, @ToolbarExecuteProgram); MiddleToolBar.AddToolItemExecutor(TKASCommandItem, @ToolbarExecuteCommand); MiddleToolBar.AddToolItemExecutor(TKASProgramItem, @ToolbarExecuteProgram); // Use the same tooltips for some left and right panel butttons. btnRightDirectoryHotlist.Hint := btnLeftDirectoryHotlist.Hint; btnRightHome.Hint := btnLeftHome.Hint; btnRightRoot.Hint := btnLeftRoot.Hint; btnRightUp.Hint := btnLeftUp.Hint; { *HotKeys* } if (HotMan.Forms.Count = 0) or (HotMan.Version < hkVersion) then LoadDefaultHotkeyBindings; // Register action list for main form hotkeys. HMMainForm.RegisterActionList(actionlst); { *HotKeys* } UpdateActionIcons; {$IF DEFINED(LCLCOCOA)} // 1. TCustomTabControl.GetControlClassDefaultSize() return 200 for Default Width // 2. on Cocoa, it is likely to cause TCocoaTabControl not wide enough to // accommodate all tabs loaded in LoadTabsXml() during startup. // 3. when setting PageIndex in LoadTabsXml(), it will cause an extra tab switch. // 4. and it will cause an extra directory to be monitored in FileView. // 5. the issue can be effectively avoided by setting a larger width. nbLeft.Width:= 2048; nbRight.Width:= 2048; {$ENDIF} LoadTabs; // Must be after LoadTabs TDriveWatcher.Initialize(GetWindowHandle(Application.MainForm)); TDriveWatcher.AddObserver(@OnDriveWatcherEvent); {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)} // Fixes bug - [0000033] "DC cancels shutdown in KDE" // http://doublecmd.sourceforge.net/mantisbt/view.php?id=33 QEventHook:= QObject_hook_create(TQtWidget(Self.Handle).Widget); QObject_hook_hook_events(QEventHook, @QObjectEventFilter); {$ENDIF} OperationsManager.AddEventsListener([omevOperationAdded, omevOperationRemoved], @OperationManagerNotify); UpdateWindowView; gFavoriteTabsList.AssociatedMainMenuItem := mnuFavoriteTabs; gFavoriteTabsList.RefreshAssociatedMainMenu; // Update selected drive and free space before main form is shown, // otherwise there is a bit of delay. UpdateTreeView; UpdateTreeViewPath; UpdateSelectedDrives; UpdateFreeSpace(fpLeft, True); UpdateFreeSpace(fpRight, True); ThemeServices.OnThemeChange:= @AppThemeChange; {$IF DEFINED(DARWIN)} InitNSServiceProvider( @OnNSServiceOpenWithNewTab, @NSServiceMenuIsReady, @NSServiceMenuGetFilenames ); InitNSThemeChangedObserver( @NSThemeChangedHandler ); createDarwinAppMenu; {$ENDIF} end; procedure TfrmMain.btnLeftClick(Sender: TObject); begin PanelButtonClick(Sender as TSpeedButton, FrameLeft); end; procedure TfrmMain.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.Commands.ExecuteCommand(cmd, []); end; procedure TfrmMain.btnF3MouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (ssCtrl in Shift) and (gFonts[dcfFunctionButtons].Size > gFonts[dcfFunctionButtons].MinValue) then begin Dec(gFonts[dcfFunctionButtons].Size); UpdateGUIFunctionKeys; end; end; procedure TfrmMain.btnF3MouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (ssCtrl in Shift) and (gFonts[dcfFunctionButtons].Size < gFonts[dcfFunctionButtons].MaxValue) then begin Inc(gFonts[dcfFunctionButtons].Size); UpdateGUIFunctionKeys; end; end; procedure TfrmMain.btnF8MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Point: TPoint; begin if Button = mbRight then begin Point := (Sender as TControl).ClientToScreen(Classes.Point(X, Y)); ShowTrashContextMenu(Self, Point.X, Point.Y, nil); end; end; procedure TfrmMain.ConsoleSplitterMoved(Sender: TObject); var AHeight: Integer; begin AHeight:= nbConsole.Height + nbConsole.Tag - pnlCommand.Height; if AHeight > 0 then begin nbConsole.Height := AHeight; cmdConsole.Visible:= True; end else begin cmdConsole.Hide; nbConsole.Height := 0; end; end; procedure TfrmMain.dskToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ANotebook: TFileViewNotebook; begin if Button = mbMiddle then begin if Sender is TKASToolButton then begin if TKASToolButton(Sender).ToolBar = dskLeft then begin ANotebook:= nbLeft; end else if gDriveBar2 then begin ANotebook:= nbRight; end else begin ANotebook:= ActiveNotebook; end; Commands.DoNewTab(ANotebook); TKASToolButton(Sender).Click; end; end; end; procedure TfrmMain.mnuAllOperStopClick(Sender: TObject); begin OperationsManager.StopAll; end; procedure TfrmMain.mnuAllOperPauseClick(Sender: TObject); begin OperationsManager.PauseAll; end; procedure TfrmMain.mnuAllOperProgressClick(Sender: TObject); begin ShowOperationsViewer; end; procedure TfrmMain.mnuAllOperStartClick(Sender: TObject); begin OperationsManager.UnPauseAll; end; procedure TfrmMain.btnF8Click(Sender: TObject); begin if GetKeyShiftStateEx * KeyModifiersShortcut = [ssShift] then Commands.cm_Delete(['trashcan=reversesetting']) else Commands.cm_Delete([]); end; { TfrmMain.btnLeftDirectoryHotlistClick} //To make appear the Directory Hotlist popup menu when pressing "*" button on left // procedure TfrmMain.btnLeftDirectoryHotlistClick(Sender: TObject); var P:TPoint; begin if tb_activate_panel_on_click in gDirTabOptions then SetActiveFrame(fpLeft); gDirectoryHotlist.PopulateMenuWithHotDir(pmHotList,@HotDirSelected,@miHotAddOrConfigClick,mpHOTDIRSWITHCONFIG,0); p := Classes.Point(btnLeftDirectoryHotlist.Left,btnLeftDirectoryHotlist.Height); p := pnlLeftTools.ClientToScreen(p); pmHotList.PopUp(P.x,P.y); end; procedure TfrmMain.btnRightClick(Sender: TObject); begin PanelButtonClick(Sender as TSpeedButton, FrameRight); end; { TfrmMain.btnRightDirectoryHotlistClick} //To make appear the Directory Hotlist popup menu when pressing "*" button on right // procedure TfrmMain.btnRightDirectoryHotlistClick(Sender: TObject); var P:TPoint; begin if tb_activate_panel_on_click in gDirTabOptions then SetActiveFrame(fpRight); gDirectoryHotlist.PopulateMenuWithHotDir(pmHotList,@HotDirSelected,@miHotAddOrConfigClick,mpHOTDIRSWITHCONFIG,0); p := Classes.Point(btnRightDirectoryHotlist.Left,btnRightDirectoryHotlist.Height); p := pnlRightTools.ClientToScreen(p); pmHotList.PopUp(P.x,P.y); end; procedure TfrmMain.btnDriveMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var pt: TPoint; begin if Button = mbRight then with Sender as TSpeedButton do begin if (Tag >= 0) and (Tag < DrivesList.Count) then begin pt.X := X; pt.Y := Y; pt := ClientToScreen(pt); ShowDriveContextMenu(Parent, DrivesList[Tag], pt.X, pt.Y, nil); end; end; end; procedure TfrmMain.ConsoleSplitterCanResize(Sender: TObject; var NewSize: Integer; var Accept: Boolean); begin // ConsoleSplitter is trying to resize pnlCommand, // so NewSize is the new size of pnlCommand. // Instead, resize nbConsole by the same difference. nbConsole.Tag := NewSize; end; procedure TfrmMain.ConvertToolbarBarConfig(BarFileName: String); var ToolBarLoader: TKASToolBarIniLoader; MainToolBarNode: TXmlNode; begin MainToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/MainToolbar', False); if not Assigned(MainToolBarNode) then begin if mbFileExists(BarFileName) then begin ToolBarLoader := TKASToolBarIniLoader.Create(Commands.Commands); try ToolBarLoader.Load(BarFileName, MainToolBar, nil, @ConvertIniToolbarItem); SaveToolBar(MainToolBar); SaveGlobs; // Save toolbar and hotkeys mbRenameFile(BarFileName, BarFileName + '.obsolete'); finally ToolBarLoader.Free; end; end; end; end; procedure TfrmMain.dskRightToolButtonClick(Sender: TObject); var FileView : TFileView; begin if gDriveBar2 then FileView := FrameRight else FileView := ActiveFrame; PanelButtonClick(Sender as TKASToolButton, FileView); end; procedure TfrmMain.dskLeftRightToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer); var ToolItem: TKASToolItem; SourceFiles: TFiles; TargetFileSource: IFileSource; TargetPath: String; begin if Sender is TKASToolButton then begin SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles; try ToolItem := TKASToolButton(Sender).ToolItem; if ToolItem is TKASDriveItem then begin TargetPath := TKASDriveItem(ToolItem).Drive^.Path; TargetFileSource := ParseFileSource(TargetPath, ActiveFrame.FileSource); TargetPath := IncludeTrailingPathDelimiter(TargetPath); if not Assigned(TargetFileSource) then TargetFileSource := TFileSystemFileSource.GetFileSource; case GetDropEffectByKeyAndMouse(GetKeyShiftStateEx, mbLeft, gDefaultDropEffect) of DropCopyEffect: Self.CopyFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop); DropMoveEffect: Self.MoveFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop); end; end; finally SourceFiles.Free; end; end; end; procedure TfrmMain.dskToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin btnDriveMouseUp(Sender, Button, Shift, X, Y); end; procedure TfrmMain.EditToolbarButton(Toolbar: TKASToolBar; Button: TKASToolButton); var Editor: TOptionsEditor; Options: IOptionsDialog; EditorClass: TOptionsEditorClass; begin if ToolBar = MainToolBar then EditorClass := TfrmOptionsToolbar else begin EditorClass := TfrmOptionsToolbarMiddle; end; Options := ShowOptions(EditorClass); Application.ProcessMessages; Editor := Options.GetEditor(EditorClass); if Assigned(Button) then begin (Editor as TfrmOptionsToolbarBase).SelectButton(Button.Tag); end; Application.ProcessMessages; if Editor.CanFocus then Editor.SetFocus; end; procedure TfrmMain.lblAllProgressPctClick(Sender: TObject); begin ShowOperationsViewer; end; procedure TfrmMain.MainToolBarToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer); var I: LongWord; SelectedFiles: TFiles = nil; Param: string; ToolItem: TKASToolItem; Toolbar: TKASToolBar; begin Toolbar:= (Sender as TKASToolButton).ToolBar; if (ssShift in GetKeyShiftState) then // Button was moved. SaveToolBar(Toolbar) else if (Sender is TKASToolButton) and not Draging then begin ToolItem := TKASToolButton(Sender).ToolItem; if ToolItem is TKASProgramItem then begin SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count > 0 then begin Param:= EmptyStr; for I := 0 to SelectedFiles.Count - 1 do begin // Workaround for not fully implemented TMultiListFileSource. if ActiveFrame.FileSource.IsClass(TMultiListFileSource) then Param := Param + QuoteStr(SelectedFiles[I].FullPath) + ' ' else Param := Param + QuoteStr(ActiveFrame.CurrentAddress + SelectedFiles[I].FullPath) + ' '; end; TKASProgramItem(ToolItem).Command := ReplaceEnvVars(ReplaceTilde(TKASProgramItem(ToolItem).Command)); Param := PrepareParameter(Param, nil, []); if not (Commands.Commands.ExecuteCommand(TKASProgramItem(ToolItem).Command, [Param]) = cfrSuccess) then ProcessExtCommandFork(TKASProgramItem(ToolItem).Command, Param, TKASProgramItem(ToolItem).StartPath); end; finally FreeAndNil(SelectedFiles); end; end; end; end; procedure TfrmMain.MainToolBarToolButtonDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean; NumberOfButton: Integer); var aFile: TFile; tmp: Integer; ToolItem: TKASProgramItem; Toolbar: TKASToolBar; begin Toolbar:= (Sender as TKASToolButton).ToolBar; if (ssShift in GetKeyShiftState) then begin if not (Source is TKASToolButton) and not Draging then begin aFile := ActiveFrame.CloneActiveFile; try if Assigned(aFile) and aFile.IsNameValid then begin ToolItem := TKASProgramItem.Create; ToolItem.Command := aFile.FullPath; ToolItem.StartPath := aFile.Path; ToolItem.Icon := aFile.FullPath; ToolItem.Hint := ExtractOnlyFileName(aFile.Name); // ToolItem.Text := ExtractOnlyFileName(aFile.Name); Toolbar.InsertButton(Sender as TKASToolButton, ToolItem); NumberOfMoveButton := (Sender as TSpeedButton).Tag; NumberOfNewMoveButton := (Sender as TSpeedButton).Tag-1; Draging := True; Accept := True; end else begin Accept := False; Exit; end; finally FreeAndNil(aFile); end; end; if (Source is TKASToolButton) and (Toolbar <> TKASToolButton(Source).ToolBar) then begin Accept := False; Exit; end; if (NumberOfMoveButton <> (Sender as TSpeedButton).Tag) then begin Draging := True; if Source is TSpeedButton then Toolbar.MoveButton((Source as TSpeedButton).Tag, (Sender as TSpeedButton).Tag) else begin tmp:= (Sender as TSpeedButton).Tag; Toolbar.MoveButton(NumberOfNewMoveButton, (Sender as TSpeedButton).Tag); NumberOfNewMoveButton := tmp; end; NumberOfMoveButton := (Sender as TSpeedButton).Tag; Accept := True; end; end else begin Accept := not Draging and (Sender is TKASToolButton) and (TKASToolButton(Sender).ToolItem is TKASProgramItem); if Accept then begin aFile := ActiveFrame.CloneActiveFile; try Accept := Assigned(aFile) and aFile.IsNameValid; finally FreeAndNil(aFile); end; end; end; end; procedure TfrmMain.MainToolBarToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (ssShift in Shift) and (Button = mbLeft) then begin (Sender as TKASToolButton).BeginDrag(False, 5); NumberOfMoveButton:= (Sender as TKASToolButton).Tag; end; Draging:= False; end; procedure TfrmMain.MainToolBarToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbRight then MainToolBarMouseUp(Sender, Button, Shift, X, Y); end; function TfrmMain.MainToolBarToolItemShortcutsHint(Sender: TObject; ToolItem: TKASNormalItem): String; begin if Sender = MainToolBar then Result := ShortcutsToText(TfrmOptionsToolbar.GetShortcuts(ToolItem)) else Result := ShortcutsToText(TfrmOptionsToolbarMiddle.GetShortcuts(ToolItem)); end; procedure TfrmMain.miLogMenuClick(Sender: TObject); begin case (Sender as TMenuItem).Tag of 0: seLogWindow.CopyToClipboard; 1: seLogWindow.SelectAll; 2: Commands.cm_ClearLogWindow([]); 3: ShowLogWindow(PtrInt(False)); end; end; procedure TfrmMain.miTrayIconExitClick(Sender: TObject); begin RestoreFromTray; Close; end; procedure TfrmMain.miTrayIconRestoreClick(Sender: TObject); begin RestoreFromTray; end; procedure TfrmMain.PanelButtonClick(Button: TSpeedButton; FileView: TFileView); begin with FileView do begin if Button.Caption = DirectorySeparator then Commands.DoChangeDirToRoot(FileView) else if Button.Caption = '..' then ChangePathToParent(True) else if Button.Caption = '~' then SetFileSystemPath(FileView, GetHomeDir); end; if tb_activate_panel_on_click in gDirTabOptions then SetActiveFrame(FileView); end; procedure TfrmMain.ShellTreeViewSelect; begin ShellTreeView.Tag := 1; try SetFileSystemPath(ActiveFrame, (ShellTreeView as TShellTreeView).Path); finally ShellTreeView.Tag := 0; end; end; procedure TfrmMain.ShellTreeViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_RETURN then ShellTreeViewSelect; end; procedure TfrmMain.ShellTreeViewMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AFile: TFile; AFiles: TFiles; APoint: TPoint; AFileName: String; begin {$IF DEFINED(MSWINDOWS)} if Button = mbRight then try AFileName:= ExcludeTrailingBackslash((ShellTreeView as TShellTreeView).Path); AFile:= TFileSystemFileSource.CreateFileFromFile(AFileName); try AFiles:= TFiles.Create(AFile.Path); AFiles.Add(AFile); APoint := ShellTreeView.ClientToScreen(Classes.Point(X, Y)); ShowContextMenu(ShellTreeView, AFiles, APoint.X, APoint.Y, False, nil); finally FreeAndNil(AFiles); end; except on E: EContextMenuException do ShowException(E) else; end; {$ENDIF} if Button = mbLeft then ShellTreeViewSelect; end; procedure TfrmMain.FormDestroy(Sender: TObject); begin DCDebug('Destroying main form'); if Assigned(HotMan) then begin HotMan.UnRegister(edtCommand); HotMan.UnRegister(Self); end; OperationsManager.RemoveEventsListener([omevOperationAdded, omevOperationRemoved], @OperationManagerNotify); TDriveWatcher.RemoveObserver(@OnDriveWatcherEvent); TDriveWatcher.Finalize; DCDebug('Drive watcher finished'); // Close all tabs. CloseNotebook(LeftTabs); CloseNotebook(RightTabs); FreeAndNil(DrivesList); {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)} QObject_hook_destroy(QEventHook); {$ENDIF} DCDebug('Main form destroyed'); end; procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: boolean); var Index: Integer; AForm: TfrmEditor; begin if OperationsManager.OperationsCount > 0 then begin CanClose := MessageDlg(rsMsgFileOperationsActive, rsMsgFileOperationsActiveLong + LineEnding + rsMsgConfirmQuit, mtConfirmation, [mbYes, mbNo], 0, mbNo) = mrYes; end else if gConfirmQuit then begin CanClose := MessageDlg('', rsMsgConfirmQuit, mtConfirmation, [mbYes, mbNo], 0, mbNo) = mrYes; end else begin CanClose := True; end; if CanClose then begin for Index:= 0 to Screen.FormCount - 1 do begin if Screen.Forms[Index] is TfrmEditor then begin AForm:= TfrmEditor(Screen.Forms[Index]); if AForm.Editor.Modified then begin if Assigned(AForm.OnCloseQuery) then begin AForm.ShowOnTop; AForm.OnCloseQuery(AForm, CanClose); if not CanClose then Exit; end; end; end; end; end; {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)} CloseQueryResult:= CanClose; {$ENDIF} end; procedure TfrmMain.FormDropFiles(Sender: TObject; const FileNames: array of String); var TargetFileView: TFileView = nil; TargetControl: TControl; I: Integer; Files: TFiles = nil; FileNamesList: TStringList = nil; Point: TPoint; DropParams: TDropParams; begin Point.x := 0; Point.y := 0; TargetControl := FindLCLControl(Mouse.CursorPos); while TargetControl <> nil do begin if TargetControl = FrameLeft then begin // drop on left panel TargetFileView := FrameLeft; break; end else if TargetControl = FrameRight then begin // drop on right panel TargetFileView := FrameRight; break; end; TargetControl := TargetControl.Parent; end; if Assigned(TargetFileView) then try // fill file list by files FileNamesList := TStringList.Create; for I := Low(FileNames) to High(FileNames) do begin if Length(FileNames[I]) > 0 then FileNamesList.Add(FileNames[I]); end; if FileNamesList.Count > 0 then try Files := TFileSystemFileSource.CreateFilesFromFileList( ExtractFilePath(FileNamesList[0]), FileNamesList); if Files.Count > 0 then begin GetCursorPos(Point); DropParams := TDropParams.Create( Files, GetDropEffectByKeyAndMouse(GetKeyShiftState, mbLeft, gDefaultDropEffect), Point, False, nil, TargetFileView, TargetFileView.FileSource, TargetFileView.CurrentPath); DropFiles(DropParams); end; except on e: EFileNotFound do MessageDlg(e.Message, mtError, [mbOK], 0); end; finally FreeAndNil(Files); FreeAndNil(FileNamesList); end; end; procedure TfrmMain.DropFiles(var DropParams: TDropParams); begin if Assigned(DropParams) then begin if DropParams.Files.Count > 0 then begin case DropParams.DropEffect of DropMoveEffect: DropParams.TargetPanel.DoDragDropOperation(ddoMove, DropParams); DropCopyEffect: DropParams.TargetPanel.DoDragDropOperation(ddoCopy, DropParams); DropLinkEffect: DropParams.TargetPanel.DoDragDropOperation(ddoSymLink, DropParams); DropAskEffect: begin // Ask the user what he would like to do by displaying a menu. // Returns immediately after showing menu. PopupDragDropMenu(DropParams); end; else FreeAndNil(DropParams); end; end else FreeAndNil(DropParams); end; end; procedure TfrmMain.DoDragDropOperation(Operation: TDragDropOperation; var DropParams: TDropParams); var SourceFileName, TargetFileName: string; begin try with DropParams do begin if Assigned(TargetFileSource) then begin {$IF DEFINED(MSWINDOWS)} // If drop from external application and from temporary directory then // in most cases it is a drop from archiver application that extracting // files via temporary directory and requires run operation in the main thread // See http://doublecmd.sourceforge.net/mantisbt/view.php?id=1124 if (GetDragDropType = ddtExternal) and (Operation in [ddoMove, ddoCopy]) and IsInPath(GetTempDir, DropParams.Files[0].FullPath, True, True) then begin if gShowDialogOnDragDrop then begin case Operation of ddoMove: SourceFileName := GetFileDlgStr(rsMsgRenSel, rsMsgRenFlDr, DropParams.Files); ddoCopy: SourceFileName := GetFileDlgStr(rsMsgCpSel, rsMsgCpFlDr, DropParams.Files); end; if MessageDlg(SourceFileName, mtConfirmation, [mbOK, mbCancel], 0) <> mrOK then Exit; end; case Operation of ddoMove: Self.MoveFiles(TFileSystemFileSource.GetFileSource, TargetFileSource, Files, TargetPath, False, ModalQueueId); ddoCopy: Self.CopyFiles(TFileSystemFileSource.GetFileSource, TargetFileSource, Files, TargetPath, False, ModalQueueId); end; end else {$ENDIF} case Operation of ddoMove: if GetDragDropType = ddtInternal then begin if Self.MoveFiles(SourcePanel.FileSource, TargetFileSource, Files, TargetPath, gShowDialogOnDragDrop) then begin SourcePanel.MarkFiles(False); end; end else begin Self.MoveFiles(TFileSystemFileSource.GetFileSource, TargetFileSource, Files, TargetPath, gShowDialogOnDragDrop); end; ddoCopy: if GetDragDropType = ddtInternal then begin if Self.CopyFiles(SourcePanel.FileSource, TargetFileSource, Files, TargetPath, gShowDialogOnDragDrop) then begin SourcePanel.MarkFiles(False); end; end else begin Self.CopyFiles(TFileSystemFileSource.GetFileSource, TargetFileSource, Files, TargetPath, gShowDialogOnDragDrop); end; ddoSymLink, ddoHardLink: begin // Only for filesystem. if ((GetDragDropType = ddtExternal) or (SourcePanel.FileSource.IsClass(TFileSystemFileSource))) and (TargetFileSource.IsClass(TFileSystemFileSource)) then begin // TODO: process multiple files SourceFileName := Files.Items[0].FullPath; TargetFileName := TargetPath + ExtractFileName(SourceFileName); if ((Operation = ddoSymLink) and ShowSymLinkForm(Self, SourceFileName, TargetFileName, TargetPath)) or ((Operation = ddoHardLink) and ShowHardLinkForm(Self, SourceFileName, TargetFileName, TargetPath)) then TargetFileSource.Reload(TargetPath); end else begin msgWarning(rsMsgErrNotSupported); end; end; end; end else msgWarning(rsMsgErrNotSupported); end; finally FreeAndNil(DropParams); end; end; procedure TfrmMain.FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); begin // Either left or right panel has to be focused. if not FrameLeft.Focused and not FrameRight.Focused then begin Exit; end; // Check for certain Ascii keys. if (not ((Length(UTF8Key) = 1) and (UTF8Key[1] in ['-', '*', '+', #0..#32]))) then begin if (gKeyTyping[ktmNone] = ktaCommandLine) {$IFDEF MSWINDOWS} // Allow entering international characters with Ctrl+Alt on Windows, // if there is no action for Ctrl+Alt and command line typing has no modifiers. or (HasKeyboardAltGrKey and (GetKeyShiftStateEx * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]) and (gKeyTyping[ktmCtrlAlt] = ktaNone)) {$ENDIF} then begin TypeInCommandLine(UTF8Key); UTF8Key := ''; end; end end; {$IF DEFINED(LCLGTK2)} procedure TfrmMain.WindowStateUpdate(Data: PtrInt); begin Resizing(lastWindowState); end; {$ENDIF} procedure TfrmMain.FormWindowStateChange(Sender: TObject); begin if FUpdateDiskCount and (WindowState <> wsMinimized) then begin UpdateDiskCount; FUpdateDiskCount:= False; end; {$IF DEFINED(LCLGTK2)} if MinimizedWindowButton then begin MinimizedWindowButton:= False; Application.QueueAsyncCall(@WindowStateUpdate, 0); Exit; end; {$ENDIF} if WindowState = wsMinimized then begin // Minimized MainToolBar.Top:= 0; // restore toolbar position if not HiddenToTray then begin {$IF DEFINED(LCLGTK2)} MinimizedWindowButton:= True; {$ENDIF} if gMinimizeToTray or gAlwaysShowTrayIcon then begin HideToTray; end; end else begin // If we get wsMinimized while HiddenToTray is true, // then this means it was sent by LCL when a hidden, minimized window was shown. // We don't react to this message in this case. HiddenToTray := False; {$IF DEFINED(LCLGTK2)} Application.QueueAsyncCall(@WindowStateUpdate, 0); {$ENDIF} end; end else begin // Not minimized // save window state before minimize for // future loading after restore from tray lastWindowState:=WindowState; HiddenToTray := False; end; end; procedure TfrmMain.MainSplitterDblClick(Sender: TObject); begin // To prevent MainSplitterMouseUp processing MainSplitterLeftMouseBtnDown:=false; MainSplitter.ParentColor:=true; // Set splitter to 50/50 Commands.DoPanelsSplitterPerPos(50); end; procedure TfrmMain.MainSplitterMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Button=mbLeft) and (not MainSplitterLeftMouseBtnDown) then begin // Under Linux MainSplitter.Color:=clBlack Doesn't work MainSplitter.ParentColor:=true; MainSplitter.Color:=ColorToRGB(clBlack); MainSplitterMouseDownX:=X; MainSplitterMouseDownY:=Y; MainSplitterLeftMouseBtnDown:=true; end; end; procedure TfrmMain.MainSplitterMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var Rect: TRect; sHint: String; Delta: Integer; APoint: TPoint; Moved: Boolean = False; begin if MainSplitterLeftMouseBtnDown then begin if not gHorizontalFilePanels and (MainSplitter.Left + X > MainSplitter.Width) and (MainSplitter.Left + X + MainSplitter.Width < pnlNotebooks.Width) then begin MainSplitter.Left := MainSplitter.Left + X - MainSplitterMouseDownX; Moved := True; end else if gHorizontalFilePanels and (MainSplitter.Top + Y > MainSplitter.Height) and (MainSplitter.Top + Y + MainSplitter.Height < pnlNotebooks.Height) then begin MainSplitter.Top := MainSplitter.Top + Y - MainSplitterMouseDownY; Moved := True; end; if Moved then begin // create hint if not Assigned(MainSplitterHintWnd) then begin MainSplitterHintWnd := THintWindow.Create(nil); MainSplitterHintWnd.Color := Application.HintColor; end; // calculate percent if not gHorizontalFilePanels then begin Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Width); FMainSplitterPos:= MainSplitter.Left * 100 / (pnlNotebooks.Width-MainSplitter.Width - Delta); end else begin Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Height); FMainSplitterPos:= MainSplitter.Top * 100 / (pnlNotebooks.Height-MainSplitter.Height - Delta); end; // generate hint text sHint:= FloatToStrF(FMainSplitterPos, ffFixed, 15, 1) + '%'; // calculate hint position Rect:= MainSplitterHintWnd.CalcHintRect(200, sHint, nil); APoint:= Mouse.CursorPos; with Rect do begin Right:= APoint.X + 8 + Right; Bottom:= APoint.Y + 12 + Bottom; Left:= APoint.X + 8; Top:= APoint.Y + 12; end; // show hint MainSplitterHintWnd.ActivateHint(Rect, sHint); end; end; end; procedure TfrmMain.MainSplitterMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin // hide and destroy hint if Assigned(MainSplitterHintWnd) then begin MainSplitterHintWnd.Hide; FreeAndNil(MainSplitterHintWnd); end; if (MainSplitterLeftMouseBtnDown) then begin MainSplitter.ParentColor:=true; MainSplitterLeftMouseBtnDown:=false; if not FResizingFilePanels then begin FResizingFilePanels := True; if not gHorizontalFilePanels then pnlLeft.Width := MainSplitter.Left else pnlLeft.Height := MainSplitter.Top; FResizingFilePanels := False; end; end; end; procedure TfrmMain.MainTrayIconClick(Sender: TObject); begin // Only react to clicks if the icon is not scheduled to be hidden. if not HidingTrayIcon then begin if WindowState = wsMinimized then begin RestoreFromTray; end else begin MinimizeWindow; HideToTray; end; end; end; { TfrmMain.lblDriveInfoDblClick } //Shows the Directory Hotlist at the cursor position after double-clicking the panel. //This is NOT like TC but was here as legacy in DC. Let it there for respect to original authors. //Double-clicking on the "FPathLabel" of the "TFileViewHeader" does the same as in TC and is implemented now. // procedure TfrmMain.lblDriveInfoDblClick(Sender: TObject); begin if tb_activate_panel_on_click in gDirTabOptions then begin if Sender = lblRightDriveInfo then SetActiveFrame(fpRight) else if Sender = lblLeftDriveInfo then SetActiveFrame(fpLeft); end; Commands.cm_DirHotList(['position=cursor']); end; procedure TfrmMain.LeftDriveBarExecuteDrive(ToolItem: TKASToolItem); var DriveItem: TKASDriveItem; begin DriveItem := ToolItem as TKASDriveItem; SetPanelDrive(fpLeft, DriveItem.Drive, True); end; procedure TfrmMain.MainToolBarDragDrop(Sender, Source: TObject; X, Y: Integer); var aFile: TFile; ToolItem: TKASProgramItem; Toolbar: TKASToolBar absolute Sender; begin if not (Source is TSpeedButton) and not Draging then begin aFile := ActiveFrame.CloneActiveFile; try if Assigned(aFile) and aFile.IsNameValid then begin ToolItem := TKASProgramItem.Create; ToolItem.Command := GetToolbarFilenameToSave(tpmeCommand, aFile.FullPath); ToolItem.StartPath := GetToolbarFilenameToSave(tpmeStartingPath, aFile.Path); ToolItem.Hint := ExtractOnlyFileName(aFile.Name); // ToolItem.Text := ExtractOnlyFileName(aFile.Name); ToolItem.Icon := GetToolbarFilenameToSave(tpmeIcon, aFile.FullPath); Toolbar.AddButton(ToolItem); end; finally FreeAndNil(aFile); end; end; SaveToolBar(Toolbar); Draging := False; end; procedure TfrmMain.MainToolBarDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var aFile: TFile; begin if (Source is TSpeedButton) then Accept := False else begin aFile := ActiveFrame.CloneActiveFile; try Accept := Assigned(aFile) and aFile.IsNameValid; finally FreeAndNil(aFile); end; end; end; function TfrmMain.MainToolBarLoadButtonGlyph(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; begin if ToolItem is TKASNormalItem then Result := PixMapManager.LoadBitmapEnhanced(TKASNormalItem(ToolItem).Icon, iIconSize, True, clBackColor, nil) else Result := nil; end; function TfrmMain.MainToolBarLoadButtonOverlay(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; begin if ToolItem is TKASMenuItem then Result := PixMapManager.LoadBitmapEnhanced('emblem-symbolic-link', iIconSize, True, clBackColor, nil) else Result := nil; end; procedure TfrmMain.tbDeleteClick(Sender: TObject); var Toolbar: TKASToolBar; Button: TKASToolButton; begin Button := TKASToolButton(pmToolBar.Tag); if Assigned(Button) then begin if msgYesNo(Format(rsMsgDelSel, [Button.Hint])) then begin Toolbar:= Button.ToolBar; ToolBar.RemoveButton(Button); SaveToolBar(Toolbar); end; end; end; procedure TfrmMain.dskLeftToolButtonClick(Sender: TObject); begin PanelButtonClick(Sender as TKASToolButton, FrameLeft); end; procedure TfrmMain.MainToolBarMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Point : TPoint; begin case Button of mbRight: begin Point.X := X; Point.Y := Y; Point := (Sender as TControl).ClientToScreen(Point); if Sender is TKASToolButton then begin pmToolBar.Tag := PtrInt(Sender); pmToolBar.PopupComponent := TKASToolButton(Sender).ToolBar; end else begin pmToolBar.Tag := 0; pmToolBar.PopupComponent := TComponent(Sender); end; pmToolBar.PopUp(Point.X, Point.Y); end; end; end; procedure TfrmMain.frmMainClose(Sender: TObject; var CloseAction: TCloseAction); begin // Process all queued asynchronous events before closing // (frmMainAfterShow, nbPageAfterMouseDown, etc.). Application.ProcessMessages; if tb_close_duplicate_when_closing in gDirTabOptions then begin Commands.cm_CloseDuplicateTabs(['LeftTabs']); Commands.cm_CloseDuplicateTabs(['RightTabs']); end; if gSaveConfiguration then ConfigSaveSettings(False); FreeAndNil(Cons); Application.Terminate; end; procedure TfrmMain.frmMainAfterShow(Sender: TObject); begin OnPaint := nil; if Assigned(ActiveFrame) then ActiveFrame.SetFocus else begin DCDebug('ActiveFrame = nil'); end; HiddenToTray := False; end; procedure TfrmMain.frmMainShow(Sender: TObject); begin DCDebug('frmMain.frmMainShow'); {$IF NOT (DEFINED(LCLWIN32) or DEFINED(LCLGTK2) or DEFINED(LCLCOCOA) OR (DEFINED(DARWIN) and DEFINED(LCLQT)))} OnPaint := @frmMainAfterShow; {$ELSE} Application.QueueAsyncCall(TDataEvent(@frmMainAfterShow), 0); {$ENDIF} end; procedure TfrmMain.mnuDropClick(Sender: TObject); var DropParamsRef: TDropParams; begin if (Sender is TMenuItem) and Assigned(FDropParams) then begin // Make a copy of the reference to parameters and clear FDropParams, // so that they're not destroyed if pmDropMenuClose is called while we're processing. DropParamsRef := FDropParams; FDropParams := nil; // release ownership with DropParamsRef do begin if (Sender as TMenuItem).Name = 'miMove' then begin TargetPanel.DoDragDropOperation(ddoMove, DropParamsRef); end else if (Sender as TMenuItem).Name = 'miCopy' then begin TargetPanel.DoDragDropOperation(ddoCopy, DropParamsRef); end else if (Sender as TMenuItem).Name = 'miSymLink' then begin TargetPanel.DoDragDropOperation(ddoSymLink, DropParamsRef); end else if (Sender as TMenuItem).Name = 'miHardLink' then begin TargetPanel.DoDragDropOperation(ddoHardLink, DropParamsRef); end else if (Sender as TMenuItem).Name = 'miCancel' then begin FreeAndNil(DropParamsRef); end; end; //with end; end; procedure TfrmMain.PopupDragDropMenu(var DropParams: TDropParams); begin // Disposing of the params is handled in pmDropMenuClose or mnuDropClick. if Assigned(DropParams) then begin FDropParams := DropParams; DropParams := nil; pmDropMenu.PopUp(FDropParams.ScreenDropPoint.X, FDropParams.ScreenDropPoint.Y); end; end; procedure TfrmMain.pmDropMenuClose(Sender: TObject); begin // Free drop parameters given to drop menu. FreeAndNil(FDropParams); end; procedure TfrmMain.mnuSplitterPercentClick(Sender: TObject); begin with (Sender as TMenuItem) do begin Commands.DoPanelsSplitterPerPos(Tag); end; end; procedure TfrmMain.mnuTabMenuExecute(Sender: TObject); begin (Sender as TAction).OnExecute:= @actExecute; end; procedure TfrmMain.mnuTabMenuClick(Sender: TObject); var Cmd: String; MenuItem: TMenuItem; NoteBook: TFileViewNotebook; begin MenuItem := (Sender as TMenuItem); NoteBook := (pmTabMenu.Parent as TFileViewNotebook); // pmTabMenu.Tag stores tab page nr where the menu was activated. if MenuItem = miCloseTab then Commands.DoCloseTab(NoteBook, pmTabMenu.Tag) else if MenuItem = miRenameTab then Commands.DoRenameTab(NoteBook.Page[pmTabMenu.Tag]) else if MenuItem = miTabOptionNormal then NoteBook.Page[pmTabMenu.Tag].LockState := tlsNormal else if MenuItem = miTabOptionPathLocked then NoteBook.Page[pmTabMenu.Tag].LockState := tlsPathLocked else if MenuItem = miTabOptionPathResets then NoteBook.Page[pmTabMenu.Tag].LockState := tlsPathResets else if MenuItem = miTabOptionDirsInNewTab then NoteBook.Page[pmTabMenu.Tag].LockState := tlsDirsInNewTab else begin Cmd:= MenuItem.Action.Name; Cmd:= 'cm_' + Copy(Cmd, 4, Length(Cmd) - 3); Commands.Commands.ExecuteCommand(Cmd, NoteBook.Name); end; // On click first the OnClick and then the Action.OnExecute is called MenuItem.Action.OnExecute:= @mnuTabMenuExecute; end; procedure TfrmMain.nbPageAfterMouseDown(Data: PtrInt); var Notebook: TFileViewNotebook; begin if TObject(Data) is TFileViewNotebook then begin Notebook := TObject(Data) as TFileViewNotebook; if (Notebook = nbLeft) and (FrameLeft <> nil) then begin if PanelSelected = fpLeft then // same panel FrameLeft.SetFocus else if (tb_activate_panel_on_click in gDirTabOptions) then SetActiveFrame(fpLeft) else FrameRight.SetFocus; end; if (Notebook = nbRight) and (FrameRight <> nil) then begin if PanelSelected = fpRight then // same panel FrameRight.SetFocus else if (tb_activate_panel_on_click in gDirTabOptions) then SetActiveFrame(fpRight) else FrameLeft.SetFocus; end; end; end; procedure TfrmMain.nbPageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); {$IFNDEF LCLCOCOA} begin {$ELSE} var Notebook: TFileViewNotebook; TabNr: Integer; begin Notebook := TFileViewNotebook(Sender); TabNr := Notebook.IndexOfPageAt(Point(X, Y)); if TabNr <> -1 then Notebook.ActivePageIndex := TabNr; {$ENDIF} Application.QueueAsyncCall(@nbPageAfterMouseDown, PtrInt(Sender)); end; procedure TfrmMain.nbPageChanged(Sender: TObject); var Notebook: TFileViewNotebook; Page: TFileViewPage; begin Notebook := Sender as TFileViewNotebook; Page := Notebook.ActivePage; if Assigned(Page) then begin if Page.LockState = tlsPathResets then // if locked with directory change ChooseFileSource(Page.FileView, Page.LockPath); // Update selected drive only on non-active panel, // because active panel is updated on focus change. if (PanelSelected <> Notebook.Side) and not (tb_activate_panel_on_click in gDirTabOptions) then begin UpdateSelectedDrive(Notebook); UpdateFreeSpace(Notebook.Side, True); end; end; QuickViewClose; if Visible then UpdatePrompt; UpdateTreeViewPath; UpdateMainTitleBar; end; procedure TfrmMain.nbPageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var PopUpPoint: TPoint; NoteBook: TFileViewNotebook; TabNr: Integer; begin NoteBook := Sender as TFileViewNotebook; case Button of mbMiddle: begin TabNr := NoteBook.IndexOfPageAt(Point(X, Y)); if TabNr <> -1 then begin Commands.DoCloseTab(NoteBook, TabNr); end; end; mbRight: begin TabNr := NoteBook.IndexOfPageAt(Point(X, Y)); if TabNr <> -1 then begin PopUpPoint := NoteBook.ClientToScreen(Point(X, Y)); // Check tab options items. case NoteBook.Page[TabNr].LockState of tlsNormal: miTabOptionNormal.Checked := True; tlsPathLocked: miTabOptionPathLocked.Checked := True; tlsDirsInNewTab: miTabOptionDirsInNewTab.Checked := True; tlsPathResets: miTabOptionPathResets.Checked := True; end; pmTabMenu.Parent := NoteBook; pmTabMenu.Tag := TabNr; pmTabMenu.PopUp(PopUpPoint.x, PopUpPoint.y); end; end; end; end; procedure TfrmMain.NotebookDragDrop(Sender, Source: TObject; X, Y: Integer); var ATabIndex: Integer; TargetPath: String; SourceFiles: TFiles; TargetFileSource: IFileSource; ANotebook: TFileViewNotebook absolute Sender; begin if (Source is TWinControl) and (TWinControl(Source).Parent is TFileView) then begin ATabIndex := ANotebook.IndexOfPageAt(Classes.Point(X, Y)); if (ATabIndex > -1) then begin SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles; try begin TargetPath := ANotebook.View[ATabIndex].CurrentPath; TargetFileSource := ANotebook.View[ATabIndex].FileSource; case GetDropEffectByKeyAndMouse(GetKeyShiftStateEx, mbLeft, gDefaultDropEffect) of DropCopyEffect: Self.CopyFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop); DropMoveEffect: Self.MoveFiles(ActiveFrame.FileSource, TargetFileSource, SourceFiles, TargetPath, gShowDialogOnDragDrop); end; end; finally SourceFiles.Free; end; end; end; end; procedure TfrmMain.NotebookDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var ATabIndex: Integer; APage: TFileViewPage; ANotebook: TFileViewNotebook absolute Sender; begin Accept := False; if (Source is TWinControl) and (TWinControl(Source).Parent is TFileView) then begin ATabIndex := ANotebook.IndexOfPageAt(Classes.Point(X, Y)); if (ATabIndex > -1) then begin APage:= ANotebook.Page[ATabIndex]; Accept := (APage.FileView <> TWinControl(Source).Parent) and ((APage.LockState = tlsNormal) or (APage.LockPath = APage.FileView.CurrentPath)); end; end; end; procedure TfrmMain.NotebookCloseTabClicked(Sender: TObject); begin with (Sender As TFileViewPage) do if PageIndex <> -1 then begin RemovePage(Notebook, PageIndex); end; end; procedure TfrmMain.ConvertIniToolbarItem(Loader: TKASToolBarIniLoader; var Item: TKASToolItem; const Shortcut: String); procedure ConvertHotkeys(CommandItem: TKASCommandItem; Hotkeys: THotkeys; SearchHotkey: THotkey); var Hotkey: THotkey; begin Hotkey := Hotkeys.FindByContents(SearchHotkey); if Assigned(Hotkey) then begin Hotkey.Command := 'cm_ExecuteToolbarItem'; Hotkey.Params := nil; SetValue(Hotkey.Params, 'ToolItemID', CommandItem.ID); end; end; var HMForm: THMForm; Hotkey: THotkey; CommandItem: TKASCommandItem; MenuItem: TKASMenuItem; BarFileName: String; begin if Item is TKASCommandItem then begin CommandItem := TKASCommandItem(Item); // Convert toolbar hotkey to use ID as parameter. if Shortcut <> '' then begin Hotkey := THotkey.Create; try Hotkey.Command := 'cm_Int_RunCommandFromBarFile'; AddString(Hotkey.Shortcuts, Shortcut); Hotkey.Params := Hotkey.Shortcuts; HMForm := HotMan.Forms.Find('Main'); if Assigned(HMForm) then ConvertHotkeys(CommandItem, HMForm.Hotkeys, Hotkey); finally Hotkey.Free; end; end; if ((CommandItem.Command = 'cm_OpenBar') or (CommandItem.Command = 'cm_ShowButtonMenu')) and (Length(CommandItem.Params) > 0) then begin BarFileName := CommandItem.Params[0]; if Pos(PathDelim, BarFileName) <> 0 then BarFileName := GetCmdDirFromEnvVar(BarFileName) else BarFileName := gpCfgDir + BarFileName; if mbFileExists(BarFileName) then begin MenuItem := TKASMenuItem.Create; MenuItem.Assign(Item); // Copy whatever is possible from Command item Loader.Load(BarFileName, nil, MenuItem, @ConvertIniToolbarItem); mbRenameFile(BarFileName, BarFileName + '.obsolete'); Item.Free; Item := MenuItem; end; end; end; end; procedure TfrmMain.FormKeyPress(Sender: TObject; var Key: Char); var ModifierKeys: TShiftState; begin // Either left or right panel has to be focused. if not FrameLeft.Focused and not FrameRight.Focused then begin Exit; end; ModifierKeys := GetKeyShiftStateEx; if gCmdLine and // If command line is enabled (GetKeyTypingAction(ModifierKeys) = ktaCommandLine) and not ((Key in ['-', '*', '+', #0..#32]) and (Trim(edtCommand.Text) = '')) then begin TypeInCommandLine(Key); Key := #0; end; end; function TfrmMain.ActiveFrame: TFileView; begin case PanelSelected of fpLeft: Result := FrameLeft; fpRight: Result := FrameRight; else assert(false,'Bad active frame'); end; end; function TfrmMain.NotActiveFrame: TFileView; begin case PanelSelected of fpRight: Result := FrameLeft; fpLeft: Result := FrameRight; else assert(false,'Bad active frame'); Result:=FrameLeft;// only for compilator warning; end; end; function TfrmMain.ActiveNotebook: TFileViewNotebook; begin case PanelSelected of fpLeft: Result := nbLeft; fpRight: Result := nbRight; else assert(false,'Bad active notebook'); end; end; function TfrmMain.NotActiveNotebook: TFileViewNotebook; begin case PanelSelected of fpLeft: Result := nbRight; fpRight: Result := nbLeft; else assert(false,'Bad active notebook'); end; end; function TfrmMain.FrameLeft: TFileView; begin Result := nbLeft.ActiveView; end; function TfrmMain.FrameRight: TFileView; begin Result := nbRight.ActiveView; end; procedure TfrmMain.ForEachView(CallbackFunction: TForEachViewFunction; UserData: Pointer); procedure EnumerateNotebook(ANoteBook: TFileViewNotebook); var i: Integer; begin for i := 0 to ANoteBook.PageCount - 1 do CallbackFunction(ANoteBook.View[i], UserData); end; begin EnumerateNotebook(nbLeft); EnumerateNotebook(nbRight); end; procedure TfrmMain.GetListOpenedPaths(const APaths: TStringList); procedure GetNotebookPaths(ANoteBook: TFileViewNotebook); var S: String; I: Integer; begin for I := 0 to ANoteBook.PageCount - 1 do begin S:= ANoteBook.View[I].CurrentPath; APaths.Add(S); end; end; begin APaths.Clear; GetNotebookPaths(nbLeft); GetNotebookPaths(nbRight); end; procedure TfrmMain.AppException(Sender: TObject; E: Exception); begin WriteExceptionToErrorFile; ShowExceptionDialog; end; procedure TfrmMain.AppShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); begin // Refresh monitor list Screen.UpdateMonitors; // Show hint only when application is active CanShow:= Application.Active; end; constructor TfrmMain.Create(TheOwner: TComponent); begin FMainSplitterPos := 50.0; inherited Create(TheOwner); FCommands := TMainCommands.Create(Self, actionLst); if Assigned(Application.Icon) then begin MainTrayIcon.Icon.Assign(Application.Icon); end; Screen.Cursors[crArrowCopy] := LoadCursorFromLazarusResource('ArrowCopy'); Screen.Cursors[crArrowMove] := LoadCursorFromLazarusResource('ArrowMove'); Screen.Cursors[crArrowLink] := LoadCursorFromLazarusResource('ArrowLink'); end; procedure TfrmMain.AfterConstruction; begin FResizingFilePanels:= True; inherited AfterConstruction; FResizingFilePanels:= False; pnlNotebooksResize(pnlNotebooks); end; procedure TfrmMain.UpdateActionIcons; var I: Integer; imgIndex: Integer; iconsDir: String; fileName: String; iconImg: TPicture; actionName: TComponentName; begin if not gIconsInMenus then Exit; actionLst.Images := nil; pmTabMenu.Images := nil; mnuMain.Images := nil; imgLstActions.Clear; // Temporarily while feature is not implemented // http://doublecmd.sourceforge.net/mantisbt/view.php?id=11 fileName := IntToStr(gIconsInMenusSize); iconsDir := gpPixmapPath + 'dctheme' + PathDelim + fileName; iconsDir := iconsDir + 'x' + fileName + PathDelim + 'actions'; if not mbDirectoryExists(iconsDir) then Exit; iconImg := TPicture.Create; try imgLstActions.Width := gIconsInMenusSize; imgLstActions.Height := gIconsInMenusSize; actionLst.Images := imgLstActions; pmTabMenu.Images := imgLstActions; mnuMain.Images := imgLstActions; for I:= 0 to actionLst.ActionCount - 1 do begin actionName := UTF8LowerCase(actionLst.Actions[I].Name); fileName := iconsDir + PathDelim + 'cm_' + UTF8Copy(actionName, 4, Length(actionName) - 3) + '.png'; if mbFileExists(fileName) then try iconImg.LoadFromFile(fileName); imgIndex := imgLstActions.Add(iconImg.Bitmap, nil); if imgIndex >= 0 then begin TAction(actionLst.Actions[I]).ImageIndex := imgIndex; end; except // Skip end; end; finally FreeAndNil(iconImg); end; end; procedure TfrmMain.UpdateHotDirIcons; var I: Integer; iconsDir: String; fileName: String; iconImg: TPicture; begin pmHotList.Images:=nil; { TODO -oDB : The images of popup menu in configuration should also be nilled to be correct } imgLstDirectoryHotlist.Clear; fileName := IntToStr(gIconsInMenusSize); iconsDir := gpPixmapPath + 'dctheme' + PathDelim + fileName; iconsDir := iconsDir + 'x' + fileName + PathDelim + 'actions'; if not mbDirectoryExists(iconsDir) then Exit; iconImg := TPicture.Create; try fileName := IntToStr(gIconsInMenusSize); iconsDir := gpPixmapPath + 'dctheme' + PathDelim + fileName; iconsDir := iconsDir + 'x' + fileName + PathDelim + 'dirhotlist'; imgLstDirectoryHotlist.Width := gIconsInMenusSize; imgLstDirectoryHotlist.Height := gIconsInMenusSize; pmHotList.Images:=imgLstDirectoryHotlist; for I:=0 to pred(length(ICONINDEXNAME)) do begin filename:=iconsDir+PathDelim+ICONINDEXNAME[I]+'.png'; if mbFileExists(fileName) then try iconImg.LoadFromFile(fileName); imgLstDirectoryHotlist.Add(iconImg.Bitmap, nil); except // Skip end; end; finally FreeAndNil(iconImg); end; end; procedure TfrmMain.CreateDefaultToolbar; var AToolbar: TKASToolBar; procedure AddCommand(const Command: String); var CommandItem: TKASCommandItem; begin CommandItem := TKASCommandItem.Create(Commands.Commands); CommandItem.Icon := UTF8LowerCase(Command); CommandItem.Command := Command; // Leave CommandItem.Hint empty. It will be loaded at startup based on language. AToolbar.AddButton(CommandItem); end; procedure AddSeparator(Style: Boolean = False); var SeparatorItem: TKASSeparatorItem; begin SeparatorItem:= TKASSeparatorItem.Create; SeparatorItem.Style:= Style; AToolbar.AddButton(SeparatorItem); end; var MainToolBarNode: TXmlNode; begin if MainToolBar.ButtonCount = 0 then begin MainToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + MainToolBar.Name, False); if not Assigned(MainToolBarNode) then begin AToolbar := MainToolBar; AddCommand('cm_Refresh'); AddCommand('cm_RunTerm'); AddCommand('cm_Options'); AddSeparator; AddCommand('cm_BriefView'); AddCommand('cm_ColumnsView'); AddCommand('cm_ThumbnailsView'); AddSeparator; AddCommand('cm_FlatView'); AddSeparator; AddCommand('cm_ViewHistoryPrev'); AddCommand('cm_ViewHistoryNext'); AddSeparator; AddCommand('cm_MarkPlus'); AddCommand('cm_MarkMinus'); AddCommand('cm_MarkInvert'); AddSeparator; AddCommand('cm_PackFiles'); AddCommand('cm_ExtractFiles'); AddSeparator; AddCommand('cm_NetworkConnect'); AddCommand('cm_Search'); AddCommand('cm_MultiRename'); AddCommand('cm_SyncDirs'); AddCommand('cm_CopyFullNamesToClip'); SaveToolBar(MainToolBar); end; end; if MiddleToolBar.ButtonCount = 0 then begin MainToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + MiddleToolBar.Name, False); if not Assigned(MainToolBarNode) then begin AToolbar := MiddleToolBar; AddCommand('cm_View'); AddCommand('cm_Edit'); AddCommand('cm_Copy'); AddCommand('cm_Rename'); AddSeparator(True); AddCommand('cm_PackFiles'); AddCommand('cm_MakeDir'); SaveToolBar(MiddleToolBar); end; end; end; function TfrmMain.GetFileDlgStr(sLngOne, sLngMulti: String; Files: TFiles): String; begin if Files.Count = 0 then raise Exception.Create(rsMsgNoFilesSelected); if Files.Count > 1 then Result := Format(sLngMulti, [Files.Count]) else Result := Format(sLngOne, [Files[0].Name]); end; procedure TfrmMain.miHotAddOrConfigClick(Sender: TObject); begin with Sender as TComponent do Commands.cm_WorkWithDirectoryHotlist(['action='+HOTLISTMAGICWORDS[tag], 'source='+QuoteStr(ActiveFrame.CurrentLocation), 'target='+QuoteStr(NotActiveFrame.CurrentLocation), 'index=0']); end; procedure TfrmMain.CreatePopUpDirHistory(UseTreeViewMenu: Boolean; FromPathIndex: Integer); var I, Finish: Integer; MenuItem: TMenuItem; begin pmDirHistory.Items.Clear; if UseTreeViewMenu then Finish:= glsDirHistory.Count - 1 else begin Finish:= Min(FromPathIndex + gDirHistoryCount, glsDirHistory.Count - 1); end; if (not UseTreeViewMenu) and (FromPathIndex > 0) then begin MenuItem := TMenuItem.Create(pmDirHistory); MenuItem.Caption := '...'; MenuItem.OnClick := @HistorySomeSelected; MenuItem.Tag := Max(0, FromPathIndex - gDirHistoryCount - 1); pmDirHistory.Items.Add(MenuItem); end; for I:= FromPathIndex to Finish do begin MenuItem:= TMenuItem.Create(pmDirHistory); MenuItem.Caption:= glsDirHistory[I].Replace('&','&&'); MenuItem.Hint:= glsDirHistory[I]; MenuItem.OnClick:= @HistorySelected; pmDirHistory.Items.Add(MenuItem); end; if (not UseTreeViewMenu) and (Finish < glsDirHistory.Count - 1) then begin MenuItem := TMenuItem.Create(pmDirHistory); MenuItem.Caption := '...'; MenuItem.OnClick := @HistorySomeSelected; MenuItem.Tag := Finish + 1; pmDirHistory.Items.Add(MenuItem); end; end; procedure TfrmMain.ShowFileViewHistory(const Params: array of string); begin ShowFileViewHistory(Params, -1, -1, -1, -1); end; procedure TfrmMain.ShowFileViewHistory(const Params: array of string; FromFileSourceIndex, FromPathIndex, ToFileSourceIndex, ToPathIndex: Integer); const MaxItemsShown = 20; var ItemsBackward: Integer = 0; ItemsForward: Integer = 0; function GoBack(var FileSourceIndex, PathIndex: Integer): Boolean; begin if PathIndex = 0 then begin if FileSourceIndex = 0 then Result := False else begin Dec(FileSourceIndex); PathIndex := ActiveFrame.PathsCount[FileSourceIndex] - 1; Result := True; end; end else begin Dec(PathIndex); Result := True; end; end; function GoForward(var FileSourceIndex, PathIndex: Integer): Boolean; begin if PathIndex = ActiveFrame.PathsCount[FileSourceIndex] - 1 then begin if FileSourceIndex = ActiveFrame.FileSourcesCount - 1 then Result := False else begin Inc(FileSourceIndex); PathIndex := 0; Result := True; end; end else begin Inc(PathIndex); Result := True; end; end; procedure AddCaptionItem(s: String); var mi: TMenuItem; begin mi := TMenuItem.Create(pmDirHistory); mi.Caption := s; mi.Enabled := False; pmDirHistory.Items.Add(mi); end; procedure FindBoundsBackward; var I: Integer; begin GoBack(ToFileSourceIndex, ToPathIndex); FromFileSourceIndex := ToFileSourceIndex; FromPathIndex := ToPathIndex; for i := 0 to MaxItemsShown - 1 do begin if GoBack(FromFileSourceIndex, FromPathIndex) then Inc(ItemsBackward); end; end; procedure FindBoundsFromCenter; var I: Integer; begin FromFileSourceIndex := ActiveFrame.CurrentFileSourceIndex; FromPathIndex := ActiveFrame.CurrentPathIndex; ToFileSourceIndex := FromFileSourceIndex; ToPathIndex := FromPathIndex; for i := 0 to (MaxItemsShown div 2) - 1 do begin if GoBack(FromFileSourceIndex, FromPathIndex) then Inc(ItemsBackward); if GoForward(ToFileSourceIndex, ToPathIndex) then Inc(ItemsForward); end; for i := ItemsForward to (MaxItemsShown div 2) - 1 do begin if GoBack(FromFileSourceIndex, FromPathIndex) then Inc(ItemsBackward); end; for i := ItemsBackward to (MaxItemsShown div 2) - 1 do begin if GoForward(ToFileSourceIndex, ToPathIndex) then Inc(ItemsForward); end; end; procedure FindBoundsForward; var I: Integer; begin GoForward(FromFileSourceIndex, FromPathIndex); ToFileSourceIndex := FromFileSourceIndex; ToPathIndex := FromPathIndex; for i := 0 to MaxItemsShown - 1 do begin if GoForward(ToFileSourceIndex, ToPathIndex) then Inc(ItemsForward); end; end; var bUseTreeViewMenu: boolean = false; bUsePanel: boolean = false; // As opposed as the other popup, for that one, by legacy, the position of the popup is the cursor position instead of top left corner of active panel. p: TPoint; iWantedWidth: integer = 0; iWantedHeight: integer = 0; sMaybeMenuItem: TMenuItem = nil; I: Integer; mi: TMenuItem; begin pmDirHistory.Items.Clear; p.x := 0; p.y := 0; if FromFileSourceIndex <> -1 then FindBoundsForward else if ToFileSourceIndex <> - 1 then FindBoundsBackward else FindBoundsFromCenter; if (FromFileSourceIndex > 0) or (FromPathIndex > 0) then begin mi := TMenuItem.Create(pmDirHistory); mi.Caption := '...'; mi.OnClick := @ViewHistoryPrevSelected; mi.Tag := HistoryIndexesToTag(FromFileSourceIndex, FromPathIndex); pmDirHistory.Items.Add(mi); end; for i := 0 to ItemsForward + ItemsBackward do begin mi := TMenuItem.Create(pmDirHistory); pmDirHistory.Items.Add(mi); mi.Caption := ActiveFrame.Path[FromFileSourceIndex, FromPathIndex].Replace('&','&&'); mi.OnClick := @ViewHistorySelected; // Remember indexes into history. mi.Tag := HistoryIndexesToTag(FromFileSourceIndex, FromPathIndex); // Mark current history position. if (FromFileSourceIndex = ActiveFrame.CurrentFileSourceIndex) and (FromPathIndex = ActiveFrame.CurrentPathIndex) then mi.Checked := True; if not GoForward(FromFileSourceIndex, FromPathIndex) then Break; // Add separator and address of a file source as a caption. if FromPathIndex = 0 then begin AddCaptionItem('-'); AddCaptionItem('- ' + ActiveFrame.FileSources[FromFileSourceIndex].CurrentAddress.Replace('&','&&') + ' -'); end; end; if (ToFileSourceIndex < ActiveFrame.FileSourcesCount - 1) or (ToPathIndex < ActiveFrame.PathsCount[ToFileSourceIndex] - 1) then begin mi := TMenuItem.Create(pmDirHistory); mi.Caption := '...'; mi.OnClick := @ViewHistoryNextSelected; mi.Tag := HistoryIndexesToTag(ToFileSourceIndex, ToPathIndex); pmDirHistory.Items.Add(mi); end; Application.ProcessMessages; // 1. Let's parse our parameters. Commands.DoParseParametersForPossibleTreeViewMenu(Params, gUseTreeViewMenuWithViewHistory, gUseTreeViewMenuWithViewHistory, bUseTreeViewMenu, bUsePanel, p); // 2. Show the appropriate menu. if bUseTreeViewMenu then begin if not bUsePanel then iWantedHeight := 0 else begin iWantedWidth := frmMain.ActiveFrame.Width; iWantedHeight := frmMain.ActiveFrame.Height; end; sMaybeMenuItem := GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(pmDirHistory, tvmcViewHistory, p.X, p.Y, iWantedWidth, iWantedHeight); if sMaybeMenuItem <> nil then sMaybeMenuItem.OnClick(sMaybeMenuItem); end else begin pmDirHistory.Popup(p.X, p.Y); end; end; { TfrmMain.HotDirActualSwitchToDir } // Actual routine called when user click the item from the Directory Hotlist popup menu to switch to a hot directory // The index received is the index from the "gDirectoryHotlist" to read hotdir entry from. // procedure TfrmMain.HotDirActualSwitchToDir(Index:longint); var aPath: String; isSHIFTDown, isCTRLDown: boolean; PossibleCommande,PossibleParam: string; PosFirstSpace: integer; Editor: TOptionsEditor; Options: IOptionsDialog; begin // This handler is used by HotDir AND SpecialDir. // HotDirs AND SpecialDirs are only supported by filesystem. // If the index is larger or equal to "TAGOFFSET_FORCHANGETOSPECIALDIR", it means it's a "SpecialDir" and we'll change accordingly if (Index < TAGOFFSET_FORCHANGETOSPECIALDIR) AND (Index >= 0) then begin isSHIFTDown:=((GetKeyState(VK_SHIFT) AND $80) <> 0); if not isSHIFTDown then //if SHIFT is NOT down, it's to change directory begin case gDirectoryHotlist.HotDir[Index].Dispatcher of hd_CHANGEPATH: begin isCTRLDown:=((GetKeyState(VK_CONTROL) AND $80) <> 0); //if CTRL is down, it's to request to DON'T CHANGE TARGET even if in the directoryhotlist entry it was requesting to do so aPath := gDirectoryHotlist.HotDir[Index].HotDirPath; if aPath<>'' then begin case gDirectoryHotlist.HotDir[Index].HotDirPathSort of 1: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_NAME,STR_ASCENDING]); //Name, a-z 2: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_NAME,STR_DESCENDING]); //Name, z-a 3: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_EXTENSION,STR_ASCENDING]); //Ext, a-z 4: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_EXTENSION,STR_DESCENDING]); //Ext, z-a 5: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_SIZE,STR_DESCENDING]); //Size 9-0 6: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_SIZE,STR_ASCENDING]); //Size 0-9 7: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_DESCENDING]); //Date 9-0 8: Commands.cm_UniversalSingleDirectSort([STR_ACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_ASCENDING]); //Date 0-9 end; aPath := mbExpandFileName(aPath); ChooseFileSource(ActiveFrame, aPath); if (not isCTRLDown) then //We don't change target folder if CTRL key is pressed begin aPath := gDirectoryHotlist.HotDir[Index].HotDirTarget; if aPath<>'' then begin case gDirectoryHotlist.HotDir[Index].HotDirTargetSort of 1: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_NAME,STR_ASCENDING]); //Name, a-z 2: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_NAME,STR_DESCENDING]); //Name, z-a 3: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_EXTENSION,STR_ASCENDING]); //Ext, a-z 4: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_EXTENSION,STR_DESCENDING]); //Ext, z-a 5: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_SIZE,STR_DESCENDING]); //Size 9-0 6: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_SIZE,STR_ASCENDING]); //Size 0-9 7: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_DESCENDING]); //Date 9-0 8: Commands.cm_UniversalSingleDirectSort([STR_NOTACTIVEFRAME,STR_MODIFICATIONDATETIME,STR_ASCENDING]); //Date 0-9 end; aPath := mbExpandFileName(aPath); ChooseFileSource(NotActiveFrame, aPath); end; end; end; end; //hd_CHANGEPATH: hd_COMMAND: begin PosFirstSpace:=pos(' ',gDirectoryHotlist.HotDir[Index].HotDirPath); if PosFirstSpace=0 then begin PossibleCommande:=gDirectoryHotlist.HotDir[Index].HotDirPath; PossibleParam:=''; end else begin PossibleCommande:=leftstr(gDirectoryHotlist.HotDir[Index].HotDirPath,(PosFirstSpace-1)); PossibleParam:=rightstr(gDirectoryHotlist.HotDir[Index].HotDirPath,length(gDirectoryHotlist.HotDir[Index].HotDirPath)-PosFirstSpace); end; Commands.Commands.ExecuteCommand(PossibleCommande, SplitString(PossibleParam,' ')); end; end; //case gDirectoryHotlist.HotDir[Index].Dispatcher of end else begin //if SHIFT IS down, it's to EDIT current selected entry from the Directory Hotlist that the current selected popup menu selection is pointing. Options := ShowOptions(TfrmOptionsDirectoryHotlist); Editor := Options.GetEditor(TfrmOptionsDirectoryHotlist); Application.ProcessMessages; if Editor.CanFocus then Editor.SetFocus; TfrmOptionsDirectoryHotlist(Editor).SubmitToAddOrConfigToHotDirDlg(ACTION_DIRECTLYCONFIGENTRY,ActiveFrame.CurrentPath,NotActiveFrame.CurrentPath,Index); end; end else begin if Index>=0 then begin //So it's a SpecialDir... Index:=Index-TAGOFFSET_FORCHANGETOSPECIALDIR; aPath := mbExpandFileName((gSpecialDirList.SpecialDir[Index].PathValue)); ChooseFileSource(ActiveFrame, aPath); end; end; end; procedure TfrmMain.HotDirSelected(Sender: TObject); begin HotDirActualSwitchToDir((Sender as TMenuItem).Tag); end; procedure TfrmMain.HistorySelected(Sender: TObject); var aPath: String; begin // This handler is used by DirHistory. aPath := (Sender as TMenuItem).Hint; aPath := mbExpandFileName(aPath); ChooseFileSource(ActiveFrame, aPath); end; procedure TfrmMain.HistorySomeSelected(Sender: TObject); var P: TPoint; begin if Sender is TMenuItem then begin P:= ActiveFrame.ClientToScreen(Classes.Point(0, 0)); CreatePopUpDirHistory(False, TMenuItem(Sender).Tag); pmDirHistory.Popup(P.X, P.Y); end; end; procedure TfrmMain.ViewHistorySelected(Sender: TObject); var FileSourceIndex, PathIndex: Integer; begin if Sender is TMenuItem then begin HistoryIndexesFromTag((Sender as TMenuItem).Tag, FileSourceIndex, PathIndex); ActiveFrame.GoToHistoryIndex(FileSourceIndex, PathIndex); end; end; procedure TfrmMain.ViewHistoryPrevSelected(Sender:TObject); var FileSourceIndex, PathIndex: Integer; begin if Sender is TMenuItem then begin HistoryIndexesFromTag((Sender as TMenuItem).Tag, FileSourceIndex, PathIndex); ShowFileViewHistory([], -1, -1, FileSourceIndex, PathIndex); end; end; procedure TfrmMain.ViewHistoryNextSelected(Sender:TObject); var FileSourceIndex, PathIndex: Integer; begin if Sender is TMenuItem then begin HistoryIndexesFromTag((Sender as TMenuItem).Tag, FileSourceIndex, PathIndex); ShowFileViewHistory([], FileSourceIndex, PathIndex, -1, -1); end; end; procedure TfrmMain.edtCommandKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (key=VK_Down) and (Shift=[ssCtrl]) and (edtCommand.Items.Count>0) then begin Key:=0; edtCommand.DroppedDown:=True; edtCommand.SetFocus; end; end; procedure TfrmMain.OnCopyOutTempStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); begin FModalOperationResult:= Operation.Result = fsorFinished; end; function TfrmMain.CopyFiles(SourceFileSource, TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier): Boolean; var BaseDir: String; sDestination: String; sDstMaskTemp: String; FileSource: IFileSource; TargetFiles: TFiles = nil; CopyDialog: TfrmCopyDlg = nil; OperationTemp: Boolean = False; OperationType: TFileSourceOperationType; OperationClass: TFileSourceOperationClass; Operation: TFileSourceCopyOperation = nil; OperationOptionsUIClass: TFileSourceOperationOptionsUIClass = nil; begin Result := False; try if SourceFiles.Count = 0 then Exit; if (SourceFiles.Count = 1) and ((not (SourceFiles[0].IsDirectory or SourceFiles[0].IsLinkToDirectory)) or (TargetPath = '')) then sDestination := TargetPath + ReplaceInvalidChars(SourceFiles[0].Name) else sDestination := TargetPath + '*.*'; // If same file source and address if (fsoCopy in SourceFileSource.GetOperationsTypes) and (fsoCopy in TargetFileSource.GetOperationsTypes) and SourceFileSource.Equals(TargetFileSource) and SameText(SourceFileSource.GetCurrentAddress, TargetFileSource.GetCurrentAddress) then begin OperationType := fsoCopy; FileSource := SourceFileSource; OperationClass := SourceFileSource.GetOperationClass(fsoCopy); end else if TargetFileSource.IsClass(TFileSystemFileSource) and (fsoCopyOut in SourceFileSource.GetOperationsTypes) then begin OperationType := fsoCopyOut; FileSource := SourceFileSource; OperationClass := SourceFileSource.GetOperationClass(fsoCopyOut); end else if SourceFileSource.IsClass(TFileSystemFileSource) and (fsoCopyIn in TargetFileSource.GetOperationsTypes) then begin OperationType := fsoCopyIn; FileSource := TargetFileSource; OperationClass := TargetFileSource.GetOperationClass(fsoCopyIn); end else if (fsoCopyOut in SourceFileSource.GetOperationsTypes) and (fsoCopyIn in TargetFileSource.GetOperationsTypes) then begin OperationTemp := True; OperationType := fsoCopyOut; FileSource := SourceFileSource; OperationClass := SourceFileSource.GetOperationClass(fsoCopyOut); if (fspCopyOutOnMainThread in SourceFileSource.Properties) or (fspCopyInOnMainThread in TargetFileSource.Properties) then begin QueueIdentifier:= ModalQueueId; end; end else begin msgWarning(rsMsgErrNotSupported); Exit; end; if bShowDialog then begin if Assigned(OperationClass) then OperationOptionsUIClass := OperationClass.GetOptionsUIClass; CopyDialog := TfrmCopyDlg.Create(Self, cmdtCopy, FileSource, OperationOptionsUIClass); CopyDialog.edtDst.Text := sDestination; CopyDialog.edtDst.ReadOnly := OperationTemp; CopyDialog.lblCopySrc.Caption := GetFileDlgStr(rsMsgCpSel, rsMsgCpFlDr, SourceFiles); if OperationTemp and (QueueIdentifier = ModalQueueId) then begin CopyDialog.QueueIdentifier:= QueueIdentifier; CopyDialog.btnAddToQueue.Visible:= False; CopyDialog.btnCreateSpecialQueue.Visible:= False; CopyDialog.btnOptions.Visible:= False; end; while True do begin if CopyDialog.ShowModal = mrCancel then Exit; sDestination := CopyDialog.edtDst.Text; if SourceFileSource.IsClass(TArchiveFileSource) then BaseDir := ExtractFilePath(SourceFileSource.CurrentAddress) else begin BaseDir := SourceFiles.Path; end; GetDestinationPathAndMask(SourceFiles, SourceFileSource, TargetFileSource, sDestination, BaseDir, TargetPath, sDstMaskTemp); if (TargetFileSource = nil) or (Length(TargetPath) = 0) then begin MessageDlg(rsMsgInvalidPath, rsMsgErrNotSupported, mtWarning, [mbOK], 0); Continue; end; if HasPathInvalidCharacters(TargetPath) then MessageDlg(rsMsgInvalidPath, Format(rsMsgInvalidPathLong, [TargetPath]), mtWarning, [mbOK], 0) else Break; end; QueueIdentifier := CopyDialog.QueueIdentifier; end else GetDestinationPathAndMask(SourceFiles, TargetFileSource, sDestination, SourceFiles.Path, TargetPath, sDstMaskTemp); // Copy via temp directory if OperationTemp then begin // Execute both operations in one new queue if QueueIdentifier = FreeOperationsQueueId then QueueIdentifier := OperationsManager.GetNewQueueIdentifier; // Save real target sDestination := TargetPath; FileSource := TargetFileSource; TargetFiles := SourceFiles.Clone; // Replace target by temp directory TargetFileSource := TTempFileSystemFileSource.Create(); TargetPath := TargetFileSource.GetRootDir; ChangeFileListRoot(TargetPath, TargetFiles); end; case OperationType of fsoCopy: begin // Copy within the same file source. Operation := SourceFileSource.CreateCopyOperation( SourceFiles, TargetPath) as TFileSourceCopyOperation; end; fsoCopyOut: // CopyOut to filesystem. Operation := SourceFileSource.CreateCopyOutOperation( TargetFileSource, SourceFiles, TargetPath) as TFileSourceCopyOperation; fsoCopyIn: // CopyIn from filesystem. Operation := TargetFileSource.CreateCopyInOperation( SourceFileSource, SourceFiles, TargetPath) as TFileSourceCopyOperation; end; if Assigned(Operation) then begin // Set operation options based on settings in dialog. Operation.RenameMask := sDstMaskTemp; if Assigned(CopyDialog) then CopyDialog.SetOperationOptions(Operation); if OperationTemp and (QueueIdentifier = ModalQueueId) then begin Operation.AddStateChangedListener([fsosStopped], @OnCopyOutTempStateChanged); end; // Start operation. OperationsManager.AddOperation(Operation, QueueIdentifier, False, True); Result := True; end else msgWarning(rsMsgNotImplemented); // Copy via temp directory if OperationTemp and Result and ((QueueIdentifier <> ModalQueueId) or FModalOperationResult) then begin // CopyIn from temp filesystem Operation := FileSource.CreateCopyInOperation( TargetFileSource, TargetFiles, sDestination) as TFileSourceCopyOperation; Result := Assigned(Operation); if Result then begin if Assigned(CopyDialog) then CopyDialog.SetOperationOptions(Operation); // Start operation. OperationsManager.AddOperation(Operation, QueueIdentifier, False, True); end; end; finally FreeAndNil(TargetFiles); FreeAndNil(SourceFiles); FreeAndNil(CopyDialog); end; end; function TfrmMain.MoveFiles(SourceFileSource, TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; var sDestination: String; sDstMaskTemp: String; Operation: TFileSourceMoveOperation; bMove: Boolean; MoveDialog: TfrmCopyDlg = nil; begin Result := False; try // Special case for Search Result File Source if SourceFileSource.IsClass(TSearchResultFileSource) then begin SourceFileSource:= ISearchResultFileSource(SourceFileSource).FileSource; end; // Only allow moving within the same file source. if (SourceFileSource.IsInterface(TargetFileSource) or TargetFileSource.IsInterface(SourceFileSource)) and (SourceFileSource.CurrentAddress = TargetFileSource.CurrentAddress) and (fsoMove in SourceFileSource.GetOperationsTypes) and (fsoMove in TargetFileSource.GetOperationsTypes) then begin bMove := True; end else if ((fsoCopyOut in SourceFileSource.GetOperationsTypes) and (fsoCopyIn in TargetFileSource.GetOperationsTypes)) then begin bMove := False; // copy + delete through temporary file system msgWarning(rsMsgNotImplemented); Exit; end else begin msgWarning(rsMsgErrNotSupported); Exit; end; if SourceFiles.Count = 0 then Exit; if (SourceFiles.Count = 1) and (not (SourceFiles[0].IsDirectory or SourceFiles[0].IsLinkToDirectory)) then sDestination := TargetPath + ExtractFileName(SourceFiles[0].Name) else sDestination := TargetPath + '*.*'; if bShowDialog then begin MoveDialog := TfrmCopyDlg.Create(Self, cmdtMove, SourceFileSource, SourceFileSource.GetOperationClass(fsoMove).GetOptionsUIClass); MoveDialog.edtDst.Text := sDestination; MoveDialog.lblCopySrc.Caption := GetFileDlgStr(rsMsgRenSel, rsMsgRenFlDr, SourceFiles); while True do begin if MoveDialog.ShowModal = mrCancel then Exit; sDestination := MoveDialog.edtDst.Text; GetDestinationPathAndMask(SourceFiles, SourceFileSource, TargetFileSource, sDestination, SourceFiles.Path, TargetPath, sDstMaskTemp); if (TargetFileSource = nil) or (Length(TargetPath) = 0) then begin MessageDlg(EmptyStr, rsMsgInvalidPath, mtWarning, [mbOK], 0); Continue; end; if HasPathInvalidCharacters(TargetPath) then MessageDlg(rsMsgInvalidPath, Format(rsMsgInvalidPathLong, [TargetPath]), mtWarning, [mbOK], 0) else Break; end; QueueIdentifier := MoveDialog.QueueIdentifier; end else GetDestinationPathAndMask(SourceFiles, TargetFileSource, sDestination, SourceFiles.Path, TargetPath, sDstMaskTemp); if bMove then begin Operation := SourceFileSource.CreateMoveOperation( SourceFiles, TargetPath) as TFileSourceMoveOperation; if Assigned(Operation) then begin // Set operation options based on settings in dialog. Operation.RenameMask := sDstMaskTemp; if Assigned(MoveDialog) then MoveDialog.SetOperationOptions(Operation); // Start operation. OperationsManager.AddOperation(Operation, QueueIdentifier, False, True); Result := True; end else msgWarning(rsMsgNotImplemented); end else begin // Use CopyOut, CopyIn operations. end; finally FreeAndNil(SourceFiles); FreeAndNil(MoveDialog); end; end; function TfrmMain.CopyFiles(sDestPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; var FileSource: IFileSource; SourceFiles: TFiles = nil; begin SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles; if Assigned(SourceFiles) then begin if Length(sDestPath) > 0 then FileSource := NotActiveFrame.FileSource else begin FileSource := ActiveFrame.FileSource; end; try Result := CopyFiles(ActiveFrame.FileSource, FileSource, SourceFiles, sDestPath, bShowDialog, QueueIdentifier); if Result then ActiveFrame.MarkFiles(False); finally FreeAndNil(SourceFiles); end; end else Result := False; end; function TfrmMain.MoveFiles(sDestPath: String; bShowDialog: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier = FreeOperationsQueueId): Boolean; var SourceFiles: TFiles = nil; begin SourceFiles := ActiveFrame.CloneSelectedOrActiveFiles; if Assigned(SourceFiles) then begin try Result := MoveFiles(ActiveFrame.FileSource, NotActiveFrame.FileSource, SourceFiles, sDestPath, bShowDialog, QueueIdentifier); if Result then ActiveFrame.MarkFiles(False); finally FreeAndNil(SourceFiles); end; end else Result := False; end; procedure TfrmMain.GetDestinationPathAndMask(SourceFiles: TFiles; TargetFileSource: IFileSource; EnteredPath: String; BaseDir: String; out DestPath, DestMask: String); var AbsolutePath: String; begin if TargetFileSource.GetPathType(EnteredPath) = ptAbsolute then AbsolutePath := EnteredPath else begin // This only work for filesystem for now. if TargetFileSource.IsClass(TFileSystemFileSource) then AbsolutePath := BaseDir + EnteredPath else AbsolutePath := PathDelim{TargetFileSource.GetRoot} + EnteredPath; end; AbsolutePath := NormalizePathDelimiters(AbsolutePath); // normalize path delimiters AbsolutePath := ExpandAbsolutePath(AbsolutePath); if Length(AbsolutePath) = 0 then Exit; // If the entered path ends with a path delimiter // treat it as a path to a not yet existing directory // which should be created. if (AbsolutePath[Length(AbsolutePath)] = PathDelim) or ((TargetFileSource.IsClass(TFileSystemFileSource)) and mbDirectoryExists(AbsolutePath)) then begin // Destination is a directory. DestPath := AbsolutePath; DestMask := '*.*'; end else begin // Destination is a file name or mask. DestPath := ExtractFilePath(AbsolutePath); DestMask := ExtractFileName(AbsolutePath); if (SourceFiles.Count > 1) and not ContainsWildcards(DestMask) then begin // Assume it is a path to a directory because cannot put multiple // files/directories into one file. DestPath := AbsolutePath; DestMask := '*.*'; end // For convenience, treat '*' as "whole file name". // To remove extension '*.' can be used. else if DestMask = '*' then DestMask := '*.*'; end; end; procedure TfrmMain.GetDestinationPathAndMask(SourceFiles: TFiles; SourceFileSource: IFileSource; var TargetFileSource: IFileSource; EnteredPath: String; BaseDir: String; out DestPath, DestMask: String); var FileSourceIndex, PathIndex: Integer; begin // If it is a file source root and we trying to copy/move to parent directory if StrBegins(EnteredPath, '..') and SourceFileSource.IsPathAtRoot(SourceFiles.Path) then begin // Change to previous file source and last path. FileSourceIndex := ActiveFrame.CurrentFileSourceIndex - 1; if FileSourceIndex < 0 then TargetFileSource := nil // No parent file sources. else begin PathIndex := ActiveFrame.PathsCount[FileSourceIndex] - 1; if PathIndex < 0 then TargetFileSource := nil // No paths. else begin TargetFileSource := ActiveFrame.FileSources[FileSourceIndex]; // Determine destination type if (Length(EnteredPath) = 2) or (EnteredPath[Length(EnteredPath)] = PathDelim) then EnteredPath:= EmptyStr // Destination is a directory else EnteredPath:= ExtractFileName(EnteredPath); // Destination is a file name or mask // Combine destination path EnteredPath := ActiveFrame.Path[FileSourceIndex, PathIndex] + EnteredPath; end; end; end; // Target file source is valid if Assigned(TargetFileSource) then begin GetDestinationPathAndMask(SourceFiles, TargetFileSource, EnteredPath, BaseDir, DestPath, DestMask); end; end; procedure TfrmMain.SetDragCursor(Shift: TShiftState); begin FrameLeft.SetDragCursor(Shift); FrameRight.SetDragCursor(Shift); end; procedure TfrmMain.CreateWnd; begin // Must be before CreateWnd LoadWindowState; inherited CreateWnd; // Save real main form handle Application.MainForm.Tag:= Handle; end; procedure TfrmMain.DoFirstShow; var ANode: TXmlNode; begin inherited DoFirstShow; // Load window state ANode := gConfig.FindNode(gConfig.RootNode, 'MainWindow/Position', True); if gConfig.GetValue(ANode, 'Maximized', True) then Self.WindowState := wsMaximized; lastWindowState := WindowState; end; procedure TfrmMain.WMMove(var Message: TLMMove); begin inherited WMMove(Message); if not (csDestroying in ComponentState) then begin FDelayedWMMove := True; Inc(FDelayedEventCtr); Application.QueueAsyncCall(@DelayedEvent, 0); end; end; procedure TfrmMain.WMSize(var message: TLMSize); begin // https://github.com/doublecmd/doublecmd/issues/736 if (Message.Width > High(Int16)) or (Message.Height > High(Int16)) then begin DCDebug('TfrmMain.WMSize invalid size %u x %u', [Message.Width, Message.Height]); Exit; end; inherited WMSize(Message); if not (csDestroying in ComponentState) then begin FDelayedWMSize := True; Inc(FDelayedEventCtr); Application.QueueAsyncCall(@DelayedEvent, 0); end; end; procedure TfrmMain.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); begin if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then begin DisableAutoSizing; try // ScaleFontsPPI(AYProportion); BorderSpacing.AutoAdjustLayout(AXProportion, AYProportion); Constraints.AutoAdjustLayout(AXProportion, AYProportion); finally EnableAutoSizing; end; end; end; procedure TfrmMain.FormKeyUp( Sender: TObject; var Key: Word; Shift: TShiftState) ; begin SetDragCursor(Shift); end; procedure TfrmMain.FormResize(Sender: TObject); begin UpdatePrompt; end; procedure TfrmMain.lblDriveInfoResize(Sender: TObject); begin with TLabel(Sender) do begin if Canvas.TextWidth(Caption) > Width then Alignment:= taLeftJustify else begin Alignment:= taCenter; end; end; end; procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var ShiftEx : TShiftState; CmdText : String; begin SetDragCursor(Shift); // Either left or right panel has to be focused. if not FrameLeft.Focused and not FrameRight.Focused then begin Exit; end; ShiftEx := GetKeyShiftStateEx; case Key of VK_BACK: if IsCommandLineVisible and (GetKeyTypingAction(ShiftEx) = ktaCommandLine) and (edtCommand.Text <> '') then begin // Delete last character. CmdText := edtCommand.Text; UTF8Delete(CmdText, UTF8Length(CmdText), 1); edtCommand.Text := CmdText; edtCommand.SetFocus; edtCommand.SelStart := UTF8Length(edtCommand.Text) + 1; Key := 0; end; VK_ESCAPE: if IsCommandLineVisible and (GetKeyTypingAction(ShiftEx) = ktaCommandLine) and (edtCommand.Text <> '') then begin edtCommand.Text := ''; Key := 0; end; VK_RETURN, VK_SELECT: if IsCommandLineVisible and (GetKeyTypingAction(ShiftEx) = ktaCommandLine) and (edtCommand.Text <> '') then begin // execute command line (in terminal with Shift) ExecuteCommandLine(Shift = [ssShift]); Key := 0; end; VK_SPACE: if (GetKeyTypingAction(ShiftEx) = ktaCommandLine) and (edtCommand.Text <> '') then begin TypeInCommandLine(' '); Key := 0; end; VK_TAB: begin if (QuickViewPanel = nil) then begin // Select opposite panel. case PanelSelected of fpLeft: SetActiveFrame(fpRight); fpRight: SetActiveFrame(fpLeft); else SetActiveFrame(fpLeft); end; end; Key := 0; end; end; CheckCommandLine(ShiftEx, Key); end; procedure TfrmMain.pmToolBarPopup(Sender: TObject); var sText: String; sDir: String; bPaste: Boolean; ToolItem: TKASToolItem; Button: TKASToolButton; begin Button := TKASToolButton(pmToolBar.Tag); tbSeparator.Visible:= Assigned(Button); tbCut.Visible:= Assigned(Button); tbCopy.Visible:= Assigned(Button); tbChangeDir.Visible:= False; tbDelete.Visible:= Assigned(Button); if Assigned(Button) then begin ToolItem := Button.ToolItem; if ToolItem is TKASProgramItem then begin sDir := TKASProgramItem(ToolItem).StartPath; sDir:= PrepareParameter(sDir, nil, [ppoNormalizePathDelims, ppoReplaceTilde]); tbChangeDir.Caption := 'CD ' + sDir; tbChangeDir.Visible := True; end; end; sText:= Clipboard.AsText; bPaste:= StrBegins(sText, DCToolItemClipboardHeader) or StrBegins(sText, DCToolbarClipboardHeader) or StrBegins(sText, TCToolbarClipboardHeader); if bPaste then tbSeparator.Visible:= True; tbPaste.Visible:= bPaste; end; procedure TfrmMain.ShellTreeViewAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean); begin Node.ImageIndex:= 0; Node.SelectedIndex:= 0; end; procedure TfrmMain.pnlLeftResize(Sender: TObject); begin if gDriveBar1 and gDriveBar2 and not gHorizontalFilePanels then begin pnlDskLeft.Constraints.MinWidth:= pnlLeft.Width; pnlDskLeft.Constraints.MaxWidth:= pnlLeft.Width; end; // Put splitter after left panel. if not gHorizontalFilePanels then begin MainSplitter.Left := pnlLeft.Width; MainSplitter.Top := pnlLeft.Top; MainSplitter.Height := pnlLeft.Height; MainSplitter.Width := 3; end else begin MainSplitter.Top := pnlLeft.Height; MainSplitter.Left := pnlLeft.Left; MainSplitter.Width := pnlLeft.Width; MainSplitter.Height := 3; end; end; procedure TfrmMain.pnlLeftRightDblClick(Sender: TObject); var APanel: TPanel; APoint: TPoint; FileViewNotebook: TFileViewNotebook; begin if Sender is TPanel then begin APanel := Sender as TPanel; if APanel = pnlLeft then begin APoint := FrameLeft.ClientToScreen(Classes.Point(0, FrameLeft.Top)); if Mouse.CursorPos.Y < APoint.Y then Commands.DoNewTab(nbLeft); end else if APanel = pnlRight then begin APoint := FrameRight.ClientToScreen(Classes.Point(0, FrameRight.Top)); if Mouse.CursorPos.Y < APoint.Y then Commands.DoNewTab(nbRight); end; end; if Sender is TFileViewNotebook then begin FileViewNotebook:= Sender as TFileViewNotebook; if FileViewNotebook.DoubleClickPageIndex < 0 then Commands.DoNewTab(FileViewNotebook) else begin case gDirTabActionOnDoubleClick of tadc_Nothing: begin end; tadc_CloseTab: Commands.DoCloseTab(FileViewNotebook, FileViewNotebook.DoubleClickPageIndex); tadc_FavoriteTabs: Commands.cm_LoadFavoriteTabs(['position=cursor']); tadc_TabsPopup: begin if FileViewNotebook.DoubleClickPageIndex<>-1 then begin // Check tab options items. case FileViewNotebook.Page[FileViewNotebook.DoubleClickPageIndex].LockState of tlsNormal: miTabOptionNormal.Checked := True; tlsPathLocked: miTabOptionPathLocked.Checked := True; tlsDirsInNewTab: miTabOptionDirsInNewTab.Checked := True; tlsPathResets: miTabOptionPathResets.Checked := True; end; pmTabMenu.Parent := FileViewNotebook; pmTabMenu.Tag := FileViewNotebook.DoubleClickPageIndex; pmTabMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; end; end; end; end; end; procedure TfrmMain.pnlNotebooksResize(Sender: TObject); var Delta: Integer; begin if not FResizingFilePanels then begin FResizingFilePanels := True; if not gHorizontalFilePanels then begin pnlLeft.BorderSpacing.Bottom:= 0; Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Width); pnlLeft.BorderSpacing.Right:= 4 - (pnlNotebooks.Width - Delta) mod 2; pnlLeft.Width := Round(Double(pnlNotebooks.Width - pnlLeft.BorderSpacing.Right - Delta) * FMainSplitterPos / 100.0); end else begin pnlLeft.BorderSpacing.Right:= 0; Delta:= IfThen(MiddleToolBar.Visible, MiddleToolBar.Height); pnlLeft.BorderSpacing.Bottom:= 4 - (pnlNotebooks.Height - Delta) mod 2; pnlLeft.Height := Round(Double(pnlNotebooks.Height - pnlLeft.BorderSpacing.Bottom - Delta) * FMainSplitterPos / 100.0); end; FResizingFilePanels := False; end; end; procedure TfrmMain.pnlRightResize(Sender: TObject); var AWidth: Integer; begin if gDriveBar1 and not gHorizontalFilePanels then begin if gDriveBar2 then AWidth := pnlRight.Width + 1 else begin AWidth := pnlNotebooks.Width - 2; end; if AWidth < 0 then AWidth := 0; pnlDskRight.Constraints.MinWidth := AWidth; pnlDskRight.Constraints.MaxWidth := AWidth; end else if gHorizontalFilePanels and not gDriveBar2 then begin AWidth := Max(0, pnlNotebooks.Width - 2); pnlDskRight.Constraints.MinWidth := AWidth; pnlDskRight.Constraints.MaxWidth := AWidth; end; end; procedure TfrmMain.sboxDrivePaint(Sender: TObject); begin with gColors.FreeSpaceInd^ do PaintDriveFreeBar(Sender, gIndUseGradient, ForeColor, ThresholdForeColor, BackColor); end; procedure TfrmMain.PaintDriveFreeBar(Sender: TObject; const bIndUseGradient: boolean; const pIndForeColor, pIndThresholdForeColor, pIndBackColor: TColor); const OccupiedThresholdPercent = 90; var pbxDrive: TPaintBox absolute Sender; FillPercentage: PtrInt; i: Integer; AColor, AColor2: TColor; ARect: TRect; begin FillPercentage:= pbxDrive.Tag; if FillPercentage <> -1 then begin pbxDrive.Canvas.Brush.Color:= clBlack; pbxDrive.Canvas.FrameRect(0, 0, pbxDrive.Width - 1, pbxDrive.Height - 1); ARect.Top := 1; ARect.Bottom := pbxDrive.Height - 2; if not bIndUseGradient then begin ARect.Left := 1; ARect.Right := 1 + FillPercentage * (pbxDrive.Width - 2) div 100; if FillPercentage <= OccupiedThresholdPercent then AColor := pIndForeColor else AColor := pIndThresholdForeColor; pbxDrive.Canvas.GradientFill(ARect, LightColor(AColor, 25), DarkColor(AColor, 25), gdVertical); ARect.Left := ARect.Right + 1; ARect.Right := pbxDrive.Width - 2; AColor := pIndBackColor; pbxDrive.Canvas.GradientFill(ARect, DarkColor(AColor, 25), LightColor(AColor, 25), gdVertical); end else begin ARect.Right := 1; for i := 0 to FillPercentage - 1 do begin if i <= OccupiedThresholdPercent then AColor:= RGB((i * 255) div OccupiedThresholdPercent, 255, 0) else AColor:= RGB(255, ((100 - i) * 255) div (100 - OccupiedThresholdPercent), 0); AColor2:= DarkColor(AColor, 50); ARect.Left := ARect.Right; ARect.Right := 1 + (i + 1) * (pbxDrive.Width - 2) div 100; pbxDrive.Canvas.GradientFill(ARect, AColor, AColor2, gdVertical); end; ARect.Left := ARect.Right; ARect.Right := pbxDrive.Width - 2; pbxDrive.Canvas.GradientFill(ARect, clSilver, clWhite, gdVertical); end; end; end; procedure TfrmMain.seLogWindowSpecialLineColors(Sender: TObject; Line: integer; var Special: boolean; var FG, BG: TColor); var LogMsgTypeObject: TObject; LogMsgType : TLogMsgType absolute LogMsgTypeObject; begin LogMsgTypeObject := seLogWindow.Lines.Objects[Line-1]; Special := True; with gColors.Log^ do begin case LogMsgType of lmtInfo: FG := InfoColor; lmtSuccess: FG := SuccessColor; lmtError: FG := ErrorColor else FG := clWindowText; end; end; end; procedure TfrmMain.FileViewFreeAsync(Data: PtrInt); var FileView: TFileView absolute Data; begin FileView.Free; end; function TfrmMain.FileViewAutoSwitch(FileSource: IFileSource; var FileView: TFileView; Reason: TChangePathReason; const NewPath: String): Boolean; var AName: String; Index: Integer; AWidth: Integer; Percent: Double; Page: TFileViewPage; AClientWidth: Integer; RestoreFocus: Boolean; ColSe: TPanelColumnsClass; DefaultView: TFileSourceFields; begin Result:= True; if FileSource.Equals(FileView.FileSource) then Exit; Page:= TFileViewPage(FileView.NotebookPage); if Page.Tag > 0 then Exit; Page.Tag:= MaxInt; try RestoreFocus:= (ActiveFrame = FileView); if (fspDefaultView in FileSource.Properties) then begin AName:= '<' + FileSource.FileSystem + '>'; ColSe:= ColSet.GetColumnSet(AName, FileSource.FileSystem); if (ColSe = nil) then begin if FileSource.GetDefaultView(DefaultView) then begin AWidth:= 0; for Index:= 0 to High(DefaultView) do begin AWidth += DefaultView[Index].Width; end; AClientWidth:= FileView.ClientWidth; // Scale columns width if AWidth < AClientWidth then begin for Index:= 0 to High(DefaultView) do begin Percent:= DefaultView[Index].Width / AWidth; DefaultView[Index].Width:= Floor(AClientWidth * Percent); end; end; ColSe:= TPanelColumnsClass.Create; for Index:= 0 to High(DefaultView) do begin with DefaultView[Index] do ColSe.Add(Header, Content, Width, Align); end; ColSe.FileSystem:= FileSource.FileSystem; ColSe.Name:= AName; ColSet.Add(ColSe); end; end; if Assigned(ColSe) then begin // Save current file view type Page.BackupViewClass := TFileViewClass(FileView.ClassType); if (FileView is TColumnsFileView) then begin // Save current columns set name Page.BackupColumnSet:= TColumnsFileView(FileView).ActiveColm; TColumnsFileView(Page.FileView).SetColumnSet(ColSe.Name); end else begin Result:= False; Page.RemoveComponent(FileView); Application.QueueAsyncCall(@FileViewFreeAsync, PtrInt(FileView)); FileView:= TColumnsFileView.Create(Page, FileView, ColSe.Name); if Assigned(Page.OnChangeFileView) then Page.OnChangeFileView(FileView); if RestoreFocus then Page.FileView.SetFocus; end; Page.BackupViewMode:= FileSource.FileSystem; end; end else if (Length(Page.BackupViewMode) > 0) then begin Page.BackupViewMode:= EmptyStr; // Restore previous file view type if (FileView is Page.BackupViewClass) then begin if (FileView is TColumnsFileView) then TColumnsFileView(FileView).SetColumnSet(Page.BackupColumnSet) end else begin Result:= False; Page.RemoveComponent(FileView); Application.QueueAsyncCall(@FileViewFreeAsync, PtrInt(FileView)); if Page.BackupViewClass <> TColumnsFileView then FileView:= Page.BackupViewClass.Create(Page, FileView) else begin FileView:= TColumnsFileView.Create(Page, FileView, Page.BackupColumnSet); end; if Assigned(Page.OnChangeFileView) then Page.OnChangeFileView(FileView); end; if RestoreFocus then Page.FileView.SetFocus; end; if not Result then begin case Reason of cprAdd: FileView.AddFileSource(FileSource, NewPath); cprRemove: FileView.RemoveCurrentFileSource; end; end; finally Page.Tag:= 0; end; end; function TfrmMain.FileViewBeforeChangePath(FileView: TFileView; NewFileSource: IFileSource; Reason: TChangePathReason; const NewPath: String ): Boolean; var i: Integer; AFileSource: IFileSource; ANoteBook: TFileViewNotebook; Page, NewPage: TFileViewPage; PageAlreadyExists: Boolean = False; tlsLockStateToEvaluate: TTabLockState; begin Result:= True; if FileView.NotebookPage is TFileViewPage then begin Page := FileView.NotebookPage as TFileViewPage; tlsLockStateToEvaluate:=Page.LockState; if tlsLockStateToEvaluate=tlsPathLocked then if MsgBox(Format(rsMsgTabForOpeningInNewTab,[Page.Caption]), [msmbYes, msmbCancel], msmbCancel, msmbCancel) = mmrYes then tlsLockStateToEvaluate:=tlsDirsInNewTab; case tlsLockStateToEvaluate of tlsPathLocked: Result := False; // do not change directory in this tab tlsDirsInNewTab: begin Result := False; // do not change directory in this tab if Assigned(NewFileSource) then begin ANoteBook := Page.Notebook; if tb_reusing_tab_when_possible in gDirTabOptions then begin for i := 0 to ANotebook.PageCount - 1 do begin NewPage := ANotebook.Page[i]; PageAlreadyExists := Assigned(NewPage.FileView) and mbCompareFileNames(NewPage.FileView.CurrentAddress, NewFileSource.CurrentAddress) and mbCompareFileNames(NewPage.FileView.CurrentPath, NewPath); if PageAlreadyExists then Break; end; end; if not PageAlreadyExists then begin // Open in a new page, cloned view. NewPage := ANotebook.NewPage(Page.FileView); NewPage.FileView.AddFileSource(NewFileSource, NewPath); end; NewPage.MakeActive; end; end; end; if Result and Assigned(NewFileSource) then begin if not FileViewAutoSwitch(NewFileSource, FileView, Reason, NewPath) then Exit(False); end; if actSyncChangeDir.Checked and (FileView = NotActiveFrame) then begin if not Result then actSyncChangeDir.Checked:= False else begin if Assigned(NewFileSource) and not NewFileSource.SetCurrentWorkingDirectory(NewPath) then begin actSyncChangeDir.Checked:= False; Exit(False); end else if not FSyncChangeParent then begin if Assigned(NewFileSource) then AFileSource:= NewFileSource else begin AFileSource:= FileView.FileSource; end; if not AFileSource.FileSystemEntryExists(ExcludeTrailingBackslash(NewPath)) then begin actSyncChangeDir.Checked:= False; Exit(False); end; end end; end; end; end; procedure TfrmMain.FileViewAfterChangePath(FileView: TFileView); var S: String; Index: Integer; Page: TFileViewPage; ANoteBook : TFileViewNotebook; begin if FileView.NotebookPage is TFileViewPage then begin Page := FileView.NotebookPage as TFileViewPage; ANoteBook := Page.Notebook; if Page.IsActive then begin if Assigned(FileView.FileSource) then begin if FileView.FileSource.IsClass(TFileSystemFileSource) then begin // Store only first 255 items if glsDirHistory.Count > $FF then begin glsDirHistory.Delete(glsDirHistory.Count - 1); end; Index:= glsDirHistory.IndexOf(FileView.CurrentPath); if Index = -1 then glsDirHistory.Insert(0, FileView.CurrentPath) else begin glsDirHistory.Move(Index, 0); end; UpdateTreeViewPath; UpdateMainTitleBar; end; if actSyncChangeDir.Checked and (FileView = ActiveFrame) then begin S:= ExcludeTrailingBackslash(FileView.CurrentPath); // Go to child directory if Length(S) > Length(FSyncChangeDir) then begin FSyncChangeParent:= False; if ExtractFileDir(S) = FSyncChangeDir then NotActiveFrame.CurrentPath:= NotActiveFrame.CurrentPath + ExtractFileName(S) else actSyncChangeDir.Checked:= False; end // Go to parent directory else begin FSyncChangeParent:= True; if S = ExtractFileDir(FSyncChangeDir) then NotActiveFrame.ChangePathToParent(True) else actSyncChangeDir.Checked:= False; end; if actSyncChangeDir.Checked then FSyncChangeDir:= S else begin FSyncChangeDir:= EmptyStr; end; end; UpdateSelectedDrive(ANoteBook); UpdatePrompt; end; // Update page hint ANoteBook.Hint := FileView.CurrentPath; end; {if (fspDirectAccess in FileView.FileSource.GetProperties) then begin if gTermWindow and Assigned(Cons) then Cons.Terminal.SetCurrentDir(FileView.CurrentPath); end;} end; end; procedure TfrmMain.FileViewActivate(FileView: TFileView); var Page: TFileViewPage; begin if FileView.NotebookPage is TFileViewPage then begin Page := FileView.NotebookPage as TFileViewPage; SelectedPanel := Page.Notebook.Side; UpdateSelectedDrive(Page.Notebook); UpdateFreeSpace(Page.Notebook.Side, False); end; UpdateFileView; end; procedure TfrmMain.FileViewFilesChanged(FileView: TFileView); var Page: TFileViewPage; begin if FileView.NotebookPage is TFileViewPage then begin Page := FileView.NotebookPage as TFileViewPage; if Page.IsActive then begin UpdateFreeSpace(Page.Notebook.Side, False); end; end; end; procedure TfrmMain.SetActiveFrame(panel: TFilePanelSelect); begin SelectedPanel:= panel; SetActiveFrame(ActiveFrame); end; procedure TfrmMain.SetActiveFrame(FileView: TFileView); begin FileView.SetFocus; if (fspDirectAccess in FileView.FileSource.GetProperties) then begin if gTermWindow and Assigned(Cons) then Cons.SetCurrentDir(FileView.CurrentPath); end; end; procedure TfrmMain.UpdateFileView; var AFileView: TFileView; begin AFileView:= ActiveFrame; if AFileView is TColumnsFileView then actColumnsView.Checked:= True else if AFileView is TBriefFileView then actBriefView.Checked:= True else if AFileView is TThumbFileView then actThumbnailsView.Checked:= True; end; procedure TfrmMain.UpdateShellTreeView; begin actTreeView.Checked := gSeparateTree; TreeSplitter.Visible := gSeparateTree; TreePanel.Visible := gSeparateTree; if gSeparateTree and (ShellTreeView = nil) then begin ShellTreeView := TShellTreeView.Create(TreePanel); ShellTreeView.Parent := TreePanel; ShellTreeView.Align := alClient; ShellTreeView.ScrollBars := ssAutoBoth; with ShellTreeView as TShellTreeView do begin UpdateTreeView; ReadOnly := True; RightClickSelect := True; FileSortType := fstNone; PopulateWithBaseFiles; CustomSort(@ShellTreeViewSort); Images := TImageList.Create(Self); Images.Width := gIconsSize; Images.Height := gIconsSize; Images.Add(PixMapManager.GetFolderIcon(gIconsSize, ShellTreeView.Color), nil); OnKeyDown := @ShellTreeViewKeyDown; OnMouseUp := @ShellTreeViewMouseUp; OnAdvancedCustomDrawItem := @ShellTreeViewAdvancedCustomDrawItem; ExpandSignType := tvestPlusMinus; Options := Options - [tvoThemedDraw]; Options := Options + [tvoReadOnly, tvoRightClickSelect]; end; end; if gSeparateTree then begin with gColors.FilePanel^ do begin ShellTreeView.Font.Color := ForeColor; ShellTreeView.BackgroundColor := BackColor; ShellTreeView.SelectionColor := CursorColor; end; FontOptionsToFont(gFonts[dcfMain], ShellTreeView.Font); end; end; procedure TfrmMain.UpdateTreeViewPath; begin if (ShellTreeView = nil) then Exit; if (ShellTreeView.Tag <> 0) then Exit; if (fspDirectAccess in ActiveFrame.FileSource.Properties) then try (ShellTreeView as TShellTreeView).Path := ActiveFrame.CurrentPath; except // Skip end; end; procedure TfrmMain.UpdateTreeView; begin if (ShellTreeView = nil) then Exit; with (ShellTreeView as TShellTreeView) do begin if gShowSystemFiles then ObjectTypes:= ObjectTypes + [otHidden] else begin ObjectTypes:= ObjectTypes - [otHidden]; end; end; end; function CompareDrives(Item1, Item2: Pointer): Integer; begin Result := CompareText(PDrive(Item1)^.DisplayName, PDrive(Item2)^.DisplayName); end; procedure TfrmMain.UpdateDiskCount; var I: Integer; Drive: PDrive; begin DrivesList.Free; DrivesList := TDriveWatcher.GetDrivesList; DrivesList.Sort(@CompareDrives); { Delete drives that in drives black list } for I:= DrivesList.Count - 1 downto 0 do begin Drive := DrivesList[I]; if (gDriveBlackListUnmounted and not Drive^.IsMounted) or MatchesMaskList(Drive^.Path, gDriveBlackList) or MatchesMaskList(Drive^.DeviceId, gDriveBlackList) then DrivesList.Remove(I); end; {$IF DEFINED(MSWINDOWS)} if (not (cimDrive in gCustomIcons)) then begin for I:= DrivesList.Count - 1 downto 0 do begin Drive := DrivesList[I]; if Drive^.DriveType = dtNetwork then begin with TNetworkDriveLoader.Create(Drive, dskRight.GlyphSize, clBtnFace, @OnDriveIconLoaded) do Start; end; end; end; if (Win32MajorVersion > 5) then begin TShellFileSource.ListDrives(DrivesList, gUpperCaseDriveLetter); end; {$ENDIF} UpdateDriveList(DrivesList); // Add virtual drive New(Drive); FillChar(Drive^, SizeOf(TDrive), 0); Drive^.IsMounted:= True; Drive^.DriveType:= dtVirtual; Drive^.Path:= 'vfs:' + PathDelim; Drive^.DisplayName:= PathDelim + PathDelim; Drive^.DriveLabel:= StripHotkey(actOpenVirtualFileSystemList.Caption); Drive^.FileSystem:= 'VFS'; DrivesList.Add(Drive); // create drives drop down menu FDrivesListPopup.UpdateDrivesList(DrivesList); // create drives left/right panels if gDriveBar1 then begin CreateDiskPanel(dskRight); if gDriveBar2 then CreateDiskPanel(dskLeft); end; dskLeft.AddToolItemExecutor(TKASDriveItem, @LeftDriveBarExecuteDrive); dskRight.AddToolItemExecutor(TKASDriveItem, @RightDriveBarExecuteDrive); if gSeparateTree and Assigned(ShellTreeView) then begin TShellTreeView(ShellTreeView).PopulateWithBaseFiles; UpdateTreeViewPath; end; end; procedure TfrmMain.AddSpecialButtons(dskPanel: TKASToolBar); procedure AddItem(FromButton: TSpeedButton); var Button: TKASToolButton; ToolItem: TKASNormalItem; begin ToolItem := TKASNormalItem.Create; ToolItem.Text := FromButton.Caption; ToolItem.Hint := FromButton.Hint; Button := dskPanel.AddButton(ToolItem); Button.GroupIndex := 0; end; begin AddItem(btnLeftRoot); AddItem(btnLeftUp); AddItem(btnLeftHome); end; procedure TfrmMain.CreateDiskPanel(dskPanel: TKASToolBar); var I, Count: Integer; Drive : PDrive; BitmapTmp: Graphics.TBitmap; ToolItem: TKASDriveItem; Button: TKASToolButton; begin dskPanel.BeginUpdate; try dskPanel.Clear; dskPanel.Flat := gDriveBarFlat; Count := DrivesList.Count - 1; for I := 0 to Count do begin Drive := DrivesList.Items[I]; ToolItem := TKASDriveItem.Create; ToolItem.Drive := Drive; ToolItem.Text := Drive^.DisplayName; ToolItem.Hint := GetDriveLabelOrStatus(Drive); Button := dskPanel.AddButton(ToolItem); // Set drive icon. BitmapTmp := PixMapManager.GetDriveIcon(Drive, dskPanel.GlyphSize, clBtnFace, False); Button.Glyph.Assign(BitmapTmp); FreeAndNil(BitmapTmp); {Set Buttons Transparent. Is need? } Button.Glyph.Transparent := True; Button.Transparent := True; {/Set Buttons Transparent} Button.Layout := blGlyphLeft; end; // for // Add special buttons if not gDrivesListButton then AddSpecialButtons(dskPanel); finally dskPanel.EndUpdate; end; end; function TfrmMain.CreateFileView(sType: String; Page: TFileViewPage; AConfig: TXmlConfig; ANode: TXmlNode): TFileView; var FileViewFlags: TFileViewFlags = []; begin // This function should be changed to a separate TFileView factory. if gDelayLoadingTabs then FileViewFlags := [fvfDelayLoadingFiles]; if sType = 'columns' then Result := TColumnsFileView.Create(Page, AConfig, ANode, FileViewFlags) else if sType = 'brief' then Result := TBriefFileView.Create(Page, AConfig, ANode, FileViewFlags) else if sType = 'thumbnails' then Result := TThumbFileView.Create(Page, AConfig, ANode, FileViewFlags) else begin DCDebug(rsMsgLogError + 'Invalid file view type "%s"', [sType]); Result := TColumnsFileView.Create(Page, AConfig, ANode, FileViewFlags); end; end; procedure TfrmMain.AssignEvents(AFileView: TFileView); begin with AFileView do begin OnBeforeChangePath := @FileViewBeforeChangePath; OnAfterChangePath := @FileViewAfterChangePath; OnActivate := @FileViewActivate; OnFileListChanged := @FileViewFilesChanged; end; end; // We ask the closing locked tab confirmation according to... // ConfirmCloseLocked = 0 ...option "tb_confirm_close_locked_tab". // ConfirmCloseLocked = 1 ...no matter the option, we ask confirmation // ConfirmCloseLocked = 2 ...no matter the option, we do not ask confirmation function TfrmMain.RemovePage(ANoteBook: TFileViewNotebook; iPageIndex:Integer; CloseLocked: Boolean = True; ConfirmCloseLocked: integer = 0; ShowButtonAll: Boolean = False): LongInt; var UserAnswer: TMyMsgResult; begin Result:= -1; if (ANoteBook.PageCount > 1) and (iPageIndex >= 0) and (iPageIndex < ANoteBook.PageCount) then begin if (ANoteBook.Page[iPageIndex].LockState <> tlsNormal) AND (((ConfirmCloseLocked=0) AND (tb_confirm_close_locked_tab in gDirTabOptions)) OR (ConfirmCloseLocked=1)) then begin if CloseLocked then begin if ShowButtonAll then UserAnswer := MsgBox(Format(rsMsgCloseLockedTab, [ANoteBook.Page[iPageIndex].Caption]), [msmbYes, msmbAll, msmbNo, msmbCancel], msmbYes, msmbCancel) else UserAnswer := MsgBox(Format(rsMsgCloseLockedTab, [ANoteBook.Page[iPageIndex].Caption]), [msmbYes, msmbNo, msmbCancel], msmbYes, msmbCancel); case UserAnswer of mmrNo: Exit(1); mmrCancel, mmrNone: Exit(2); end end else Exit(1); end; QuickViewClose; ANoteBook.RemovePage(iPageIndex); if UserAnswer=mmrAll then Result:=3 else Result:= 0; end; end; procedure TfrmMain.ReLoadTabs(ANoteBook: TFileViewNotebook); var I : Integer; begin for I := 0 to ANoteBook.PageCount - 1 do begin ANoteBook.View[I].UpdateView; end; end; procedure TfrmMain.LoadTabsXml(AConfig: TXmlConfig; ABranch:string; ANoteBook: TFileViewNotebook); // default was ABranch: 'Tabs/OpenedTabs/' var sPath, sViewType: String; iActiveTab: Integer; Page: TFileViewPage; AFileView: TFileView; AFileViewFlags: TFileViewFlags; aFileSource: IFileSource; RootNode, TabNode, ViewNode: TXmlNode; begin RootNode := AConfig.FindNode(AConfig.RootNode,ABranch); if Assigned(RootNode) then begin TabNode := RootNode.FirstChild; while Assigned(TabNode) do begin if TabNode.CompareName('Tab') = 0 then begin Page := nil; AFileView := nil; ViewNode := AConfig.FindNode(TabNode, 'FileView', False); if Assigned(ViewNode) then begin // File view has its own configuration. if AConfig.TryGetAttr(ViewNode, 'Type', sViewType) then begin Page := ANoteBook.AddPage; Page.LoadConfiguration(AConfig, TabNode); AFileView := CreateFileView(sViewType, Page, AConfig, ViewNode); end else DCDebug('File view type not specified in configuration: ' + AConfig.GetPathFromNode(ViewNode) + '.'); end // Else try old configuration. else if AConfig.TryGetValue(TabNode, 'Path', sPath) then begin sPath := GetDeepestExistingPath(sPath); if sPath <> EmptyStr then begin Page := ANoteBook.AddPage; Page.LoadConfiguration(AConfig, TabNode); AFileView := CreateFileView('columns', Page, AConfig, TabNode); AFileView.AddFileSource(TFileSystemFileSource.GetFileSource, sPath); end; end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(TabNode) + '.'); if Assigned(Page) then begin if (not Assigned(AFileView)) or (AFileView.FileSourcesCount = 0) then begin ANoteBook.RemovePage(Page); end else begin if (Page.LockState in [tlsPathLocked, tlsPathResets, tlsDirsInNewTab]) and (Page.LockPath = '') then Page.LockPath := AFileView.CurrentPath; // Assign events after loading file source. AssignEvents(AFileView); end; end; end; TabNode := TabNode.NextSibling; end; end; // Create at least one tab. if ANoteBook.PageCount = 0 then begin Page := ANoteBook.AddPage; aFileSource := TFileSystemFileSource.GetFileSource; if gDelayLoadingTabs then AFileViewFlags := [fvfDelayLoadingFiles] else AFileViewFlags := []; AFileView := TColumnsFileView.Create(Page, aFileSource, gpExePath, AFileViewFlags); Commands.DoSortByFunctions(AFileView, ColSet.GetColumnSet('Default').GetColumnFunctions(0)); AssignEvents(AFileView); end else if Assigned(RootNode) then begin // read active tab index iActiveTab := AConfig.GetValue(RootNode, 'ActiveTab', 0); // set active tab if (iActiveTab >= 0) and (iActiveTab < ANoteBook.PageCount) then begin if ANoteBook.PageIndex = iActiveTab then nbPageChanged(ANoteBook) else ANoteBook.PageIndex := iActiveTab; end; end; end; procedure TfrmMain.SaveTabsXml(AConfig: TXmlConfig;ABranch:string; ANoteBook: TFileViewNotebook; ASaveHistory:boolean); // default was: 'Tabs/OpenedTabs' var I: Integer; TabsSection: String; Page: TFileViewPage; RootNode, TabNode, ViewNode: TXmlNode; begin RootNode := AConfig.FindNode(AConfig.RootNode, ABranch, True); if ANoteBook = nbLeft then TabsSection := 'Left' else TabsSection := 'Right'; RootNode := AConfig.FindNode(RootNode, TabsSection, True); AConfig.ClearNode(RootNode); AConfig.AddValue(RootNode, 'ActiveTab', ANoteBook.PageIndex); for I:= 0 to ANoteBook.PageCount - 1 do begin TabNode := AConfig.AddNode(RootNode, 'Tab'); ViewNode := AConfig.AddNode(TabNode, 'FileView'); Page := ANoteBook.Page[I]; Page.SaveConfiguration(AConfig, TabNode); Page.FileView.SaveConfiguration(AConfig, ViewNode, ASaveHistory); end; end; { TfrmMain.LoadTheseTabsWithThisConfig } // Will have tabs section from Xml from either left or right and store it back on actual form on left, right, active, inactive, both or none, with setting keep or not etc. // The "ABranch" *must* include the trailing slash when calling here. procedure TfrmMain.LoadTheseTabsWithThisConfig(Config: TXmlConfig; ABranch:string; Source, Destination:TTabsConfigLocation; DestinationToKeep : TTabsConfigLocation; var TabsAlreadyDestroyedFlags:TTabsFlagsAlreadyDestroyed); var sSourceSectionName: string; CheckNode: TXmlNode; begin if Destination<>tclNone then begin QuickViewClose; // 1. Normalize our destination side and destination to keep in case params specified active/inactive if ((Destination=tclActive) and (ActiveFrame=FrameLeft)) OR ((Destination=tclInactive) and (NotActiveFrame=FrameLeft)) then Destination:=tclLeft; if ((Destination=tclActive) and (ActiveFrame=FrameRight)) OR ((Destination=tclInactive) and (NotActiveFrame=FrameRight)) then Destination:=tclRight; if ((DestinationToKeep=tclActive) and (ActiveFrame=FrameLeft)) OR ((DestinationToKeep=tclInactive) and (NotActiveFrame=FrameLeft)) then DestinationToKeep:=tclLeft; if ((DestinationToKeep=tclActive) and (ActiveFrame=FrameRight)) OR ((DestinationToKeep=tclInactive) and (NotActiveFrame=FrameRight)) then DestinationToKeep:=tclRight; // 2. Setup our source section name. case Source of tclLeft: sSourceSectionName := 'Left'; tclRight: sSourceSectionName := 'Right'; end; // 3. Actual load infos from config file. if (Destination=tclLeft) OR (Destination=tclBoth) then begin CheckNode := Config.FindNode(Config.RootNode, ABranch + sSourceSectionName); if Assigned(CheckNode) then begin if (DestinationToKeep<>tclLeft) AND (DestinationToKeep<>tclBoth) AND (not(tfadLeft in TabsAlreadyDestroyedFlags)) then begin frmMain.LeftTabs.DestroyAllPages; TabsAlreadyDestroyedFlags := TabsAlreadyDestroyedFlags + [tfadLeft]; // To don't delete it twice in case both target are left. end; end; LoadTabsXml(Config, ABranch + sSourceSectionName, LeftTabs); end; if (Destination=tclRight) OR (Destination=tclBoth) then begin CheckNode := Config.FindNode(Config.RootNode, ABranch + sSourceSectionName); if Assigned(CheckNode) then begin if (DestinationToKeep<>tclRight) AND (DestinationToKeep<>tclBoth) AND (not(tfadRight in TabsAlreadyDestroyedFlags)) then begin frmMain.RightTabs.DestroyAllPages; TabsAlreadyDestroyedFlags := TabsAlreadyDestroyedFlags + [tfadRight]; // To don't delete it twice in case both target are right. end; LoadTabsXml(Config, ABranch + sSourceSectionName, RightTabs); end; end; // 4. Refresh content of tabs. case Destination of tclLeft: FrameLeft.Flags := FrameLeft.Flags - [fvfDelayLoadingFiles]; tclRight: FrameRight.Flags := FrameRight.Flags - [fvfDelayLoadingFiles]; tclBoth: begin FrameLeft.Flags := FrameLeft.Flags - [fvfDelayLoadingFiles]; FrameRight.Flags := FrameRight.Flags - [fvfDelayLoadingFiles]; end; end; end; // if Destination<>tclNone then end; procedure TfrmMain.ToggleConsole; begin if gTermWindow then begin if not Assigned(cmdConsole) then begin cmdConsole:= TVirtualTerminal.Create(pgConsole); cmdConsole.Parent:= pgConsole; cmdConsole.Align:= alClient; cmdConsole.ShowHint:= False; end; FontOptionsToFont(gFonts[dcfConsole], cmdConsole.Font); //We set the font here because if we're coming back from configuration the font in options, we'll later pass here to affect that font if ever displayed. if not Assigned(Cons) then begin Cons:= TPtyDevice.Create(Self); cmdConsole.PtyDevice:= Cons; Cons.Connected:= True; end; end else begin if Assigned(cmdConsole) then begin cmdConsole.Hide; FreeAndNil(cmdConsole); end; FreeAndNil(Cons); end; nbConsole.Visible:= gTermWindow; ConsoleSplitter.Visible:= gTermWindow; end; procedure TfrmMain.ShowOptionsLayout(Data: PtrInt); begin ShowOptions('TfrmOptionsLayout'); end; procedure TfrmMain.ToggleFullscreenConsole; begin if not gTermWindow then begin if MessageDlg(rsMsgTerminalDisabled, mtWarning, [mbYes, mbNo], 0, mbYes) = mrYes then Application.QueueAsyncCall(@ShowOptionsLayout, 0); end else if nbConsole.Height < (nbConsole.Height + pnlNotebooks.Height - 1) then begin nbConsole.Height := nbConsole.Height + pnlNotebooks.Height; if not cmdConsole.Visible then cmdConsole.Visible:= True; if cmdConsole.CanFocus then cmdConsole.SetFocus; end else begin cmdConsole.Hide; nbConsole.Height := 0; if ActiveFrame.CanFocus then ActiveFrame.SetFocus; end; end; procedure TfrmMain.ToolbarExecuteCommand(ToolItem: TKASToolItem); var CommandItem: TKASCommandItem; CommandFuncResult: TCommandFuncResult; begin if not Draging then begin CommandItem := ToolItem as TKASCommandItem; CommandFuncResult:=Commands.Commands.ExecuteCommand(CommandItem.Command, CommandItem.Params); if gToolbarReportErrorWithCommands AND (CommandFuncResult=cfrNotFound) then begin MsgError(Format(rsMsgCommandNotFound, [CommandItem.Command])); end; end; Draging := False; end; procedure TfrmMain.ToolbarExecuteProgram(ToolItem: TKASToolItem); var ProgramItem: TKASProgramItem; CommandExecResult: boolean; begin if not Draging then begin ProgramItem := ToolItem as TKASProgramItem; CommandExecResult:=ProcessExtCommandFork(ProgramItem.Command, ProgramItem.Params, ProgramItem.StartPath); if gToolbarReportErrorWithCommands AND (CommandExecResult=FALSE) then MsgError(Format(rsMsgProblemExecutingCommand,[ProgramItem.Command])); end; Draging := False; end; procedure TfrmMain.UpdateWindowView; procedure UpdateNoteBook(NoteBook: TFileViewNotebook); var I: Integer; begin NoteBook.ShowTabs := ((NoteBook.PageCount > 1) or (tb_always_visible in gDirTabOptions)) and gDirectoryTabs; if tb_show_close_button in gDirTabOptions then begin NoteBook.Options := NoteBook.Options + [nboShowCloseButtons]; end else begin NoteBook.Options := NoteBook.Options - [nboShowCloseButtons]; end; if nbcMultiline in NoteBook.GetCapabilities then NoteBook.MultiLine := tb_multiple_lines in gDirTabOptions; case gDirTabPosition of tbpos_top: NoteBook.TabPosition := tpTop; tbpos_bottom: NoteBook.TabPosition := tpBottom; else NoteBook.TabPosition := tpTop; end; if FInitializedView then begin // Update all tabs for I := 0 to NoteBook.PageCount - 1 do begin NoteBook.View[I].UpdateView; end; // Update active tab if Assigned(NoteBook.ActiveView) then begin NoteBook.ActiveView.ApplySettings; end; end; end; procedure AnchorHorizontalBetween(AControl, ALeftSibling, ARightSibling: TControl); begin AControl.Anchors := AControl.Anchors + [akLeft, akRight]; AControl.AnchorSide[akLeft].Control := ALeftSibling; AControl.AnchorSide[akLeft].Side := asrRight; AControl.AnchorSide[akRight].Control := ARightSibling; AControl.AnchorSide[akRight].Side := asrLeft; end; procedure AnchorHorizontal(AControl, ASibling: TControl); begin AControl.Anchors := AControl.Anchors + [akLeft, akRight]; AControl.AnchorSide[akLeft].Control := ASibling; AControl.AnchorSide[akLeft].Side := asrLeft; AControl.AnchorSide[akRight].Control := ASibling; AControl.AnchorSide[akRight].Side := asrRight; end; procedure AnchorFreeSpace(LeftControl, RightControl: TControl; ExcludeVert: Boolean); begin if gDrivesListButton then begin AnchorHorizontalBetween(LeftControl, btnLeftDrive, btnLeftDirectoryHotlist); AnchorHorizontalBetween(RightControl, btnRightDrive, btnRightDirectoryHotlist); if not ExcludeVert then begin LeftControl.AnchorVerticalCenterTo(pnlLeftTools); RightControl.AnchorVerticalCenterTo(pnlRightTools); end; end else begin AnchorHorizontal(LeftControl, pnlLeftTools); AnchorHorizontal(RightControl, pnlRightTools); if not ExcludeVert then begin LeftControl.AnchorSide[akTop].Control := pnlLeftTools; LeftControl.AnchorSide[akTop].Side := asrTop; RightControl.AnchorSide[akTop].Control := pnlRightTools; RightControl.AnchorSide[akTop].Side := asrTop; end; end; end; var I: Integer; HMForm: THMForm; FunButton: TSpeedButton; Hotkey: THotkey; begin DisableAutoSizing; try if gHorizontalFilePanels then begin pnlLeft.Align := alTop; pnlLeft.BorderSpacing.Right := 0; pnlLeft.BorderSpacing.Bottom := 3; MainSplitter.Cursor := crVSplit; MiddleToolBar.Align:= alTop; MiddleToolBar.Top:= pnlLeft.Height + 1; end else begin pnlLeft.Align := alLeft; pnlLeft.BorderSpacing.Right := 3; pnlLeft.BorderSpacing.Bottom := 0; MainSplitter.Cursor := crHSplit; MiddleToolBar.Align:= alLeft; MiddleToolBar.Left:= pnlLeft.Width + 1; end; (* Middle Tool Bar *) MiddleToolbar.Visible:= gMiddleToolBar; MiddleToolbar.Flat:= gMiddleToolBarFlat; MiddleToolbar.GlyphSize:= gMiddleToolBarIconSize; MiddleToolbar.ShowCaptions:= gMiddleToolBarShowCaptions; MiddleToolbar.SetButtonSize(gMiddleToolBarButtonSize, gMiddleToolBarButtonSize); LoadToolbar(MiddleToolBar); pnlLeftResize(pnlLeft); pnlNotebooksResize(pnlNotebooks); (* Disk Panels *) if gHorizontalFilePanels and gDriveBar1 and gDriveBar2 then begin dskLeft.Parent := pnlDiskLeftInner; dskRight.Parent := pnlDiskRightInner; end else begin dskLeft.Parent := pnlDskLeft; dskRight.Parent := pnlDskRight; end; pnlRightResize(pnlRight); dskLeft.GlyphSize:= gDiskIconsSize; dskRight.GlyphSize:= gDiskIconsSize; dskLeft.ButtonHeight:= gDiskIconsSize + 6; dskRight.ButtonHeight:= gDiskIconsSize + 6; pnlDiskLeftInner.Visible := gHorizontalFilePanels and gDriveBar1 and gDriveBar2; pnlDiskRightInner.Visible := gHorizontalFilePanels and gDriveBar1 and gDriveBar2; pnlDskLeft.Visible := not gHorizontalFilePanels and gDriveBar1 and gDriveBar2; pnlDskRight.Visible := gDriveBar1 and (not gHorizontalFilePanels or not gDriveBar2); pnlDisk.Visible := pnlDskLeft.Visible or pnlDskRight.Visible; if gHorizontalFilePanels and gDriveBar1 and gDriveBar2 then begin pnlLeftTools.Top := pnlDiskLeftInner.Height + 1; pnlRightTools.Top := pnlDiskRightInner.Height + 1; end; // Create disk panels after assigning parent. UpdateDiskCount; // Update list of showed drives (*/ Disk Panels *) FDrivesListPopup.UpdateView; (*Main menu*) Commands.DoShowMainMenu(gMainMenu); (*Main Tool Bar*) MainToolBar.Visible:= gButtonBar; MainToolBar.Flat:= gToolBarFlat; MainToolBar.GlyphSize:= gToolBarIconSize; MainToolBar.ShowCaptions:= gToolBarShowCaptions; MainToolBar.SetButtonSize(gToolBarButtonSize, gToolBarButtonSize); LoadToolbar(MainToolBar); btnLeftDrive.Visible := gDrivesListButton; btnLeftDrive.Flat := gInterfaceFlat; btnLeftRoot.Visible := gDrivesListButton; btnLeftRoot.Flat := gInterfaceFlat; btnLeftUp.Visible := gDrivesListButton; btnLeftUp.Flat := gInterfaceFlat; btnLeftHome.Visible := gDrivesListButton; btnLeftHome.Flat := gInterfaceFlat; btnLeftDirectoryHotlist.Visible := gDrivesListButton; btnLeftDirectoryHotlist.Flat := gInterfaceFlat; btnLeftEqualRight.Visible := gDrivesListButton; btnLeftEqualRight.Flat:= gInterfaceFlat; lblLeftDriveInfo.Visible:= gDriveFreeSpace; pbxLeftDrive.Visible := gDriveInd; pnlLeftTools.Visible:= gDrivesListButton or gDriveFreeSpace or gDriveInd; pnlLeftTools.DoubleBuffered := True; btnRightDrive.Visible := gDrivesListButton; btnRightDrive.Flat := gInterfaceFlat; btnRightRoot.Visible := gDrivesListButton; btnRightRoot.Flat := gInterfaceFlat; btnRightUp.Visible := gDrivesListButton; btnRightUp.Flat := gInterfaceFlat; btnRightHome.Visible := gDrivesListButton;; btnRightHome.Flat := gInterfaceFlat; btnRightDirectoryHotlist.Visible := gDrivesListButton; btnRightDirectoryHotlist.Flat := gInterfaceFlat; btnRightEqualLeft.Visible := gDrivesListButton; btnRightEqualLeft.Flat:= gInterfaceFlat; lblRightDriveInfo.Visible:= gDriveFreeSpace; pbxRightDrive.Visible := gDriveInd; pnlRightTools.Visible:= gDrivesListButton or gDriveFreeSpace or gDriveInd; pnlRightTools.DoubleBuffered := True; // Free space indicator. if gDriveFreeSpace then begin AnchorFreeSpace(lblLeftDriveInfo, lblRightDriveInfo, gDriveInd); if gDriveInd then begin lblLeftDriveInfo.AnchorSide[akTop].Side := asrTop; lblRightDriveInfo.AnchorSide[akTop].Side := asrTop; end; end; // Drive free space indicator if gDriveInd then begin AnchorFreeSpace(pbxLeftDrive, pbxRightDrive, gDriveFreeSpace); if gDriveFreeSpace then begin pbxLeftDrive.AnchorSide[akTop].Control := lblLeftDriveInfo; pbxLeftDrive.AnchorSide[akTop].Side := asrBottom; pbxRightDrive.AnchorSide[akTop].Control := lblRightDriveInfo; pbxRightDrive.AnchorSide[akTop].Side := asrBottom; end; end; // Separate tree UpdateShellTreeView; UpdateTreeView; // Operations panel and menu if (gPanelOfOp = False) then FreeAndNil(FOperationsPanel) else if (FOperationsPanel = nil) then begin FOperationsPanel := TOperationsPanel.Create(Self); FOperationsPanel.Parent := PanelAllProgress; FOperationsPanel.DoubleBuffered := True; PanelAllProgress.OnResize := @FOperationsPanel.ParentResized; end; PanelAllProgress.Visible := gPanelOfOp; Timer.Enabled := (gPanelOfOp or gProgInMenuBar) and (OperationsManager.OperationsCount > 0); // Log window seLogWindow.Visible := gLogWindow; LogSplitter.Visible := gLogWindow; // Align log window seLogWindow.Top := 0; LogSplitter.Top := 0; FontOptionsToFont(gFonts[dcfLog], seLogWindow.Font); // Command line pnlCmdLine.Visible := gCmdLine; pnlCommand.Visible := gCmdLine or gTermWindow; // Align command line and terminal window pnlCommand.Top := -Height; ConsoleSplitter.Top:= -Height; ToggleConsole; // Function keys pnlKeys.Visible := gKeyButtons; if gKeyButtons then begin pnlKeys.Top:= Height * 2; HMForm := HotMan.Forms.Find('Main'); for I := 0 to pnlKeys.ControlCount - 1 do begin if pnlKeys.Controls[I] is TSpeedButton then begin FunButton := pnlKeys.Controls[I] as TSpeedButton; FunButton.Flat := gInterfaceFlat; if Assigned(HMForm) then begin Hotkey := HMForm.Hotkeys.FindByCommand(FunctionButtonsCaptions[I].ACommand); if Assigned(Hotkey) then FunButton.Caption := FunctionButtonsCaptions[I].ACaption + ' ' + ShortcutsToText(Hotkey.Shortcuts); end; end; end; UpdateGUIFunctionKeys; end; UpdateNoteBook(nbLeft); UpdateNoteBook(nbRight); if FInitializedView then begin UpdateSelectedDrives; UpdateFreeSpace(fpLeft, True); UpdateFreeSpace(fpRight, True); end; UpdateHotDirIcons; // Preferable to be loaded even if not required in popupmenu *because* in the tree it's a must, especially when checking for missing directories ShowTrayIcon(gAlwaysShowTrayIcon); UpdateMainTitleBar; FInitializedView := True; finally EnableAutoSizing; end; end; procedure TfrmMain.edtCommandKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if not edtCommand.DroppedDown and ((Key=VK_UP) or (Key=VK_DOWN)) then begin ActiveFrame.SetFocus; Key:= 0; end else if edtCommand.DroppedDown and (Key in [VK_RETURN, VK_SELECT, VK_ESCAPE]) then begin edtCommand.DroppedDown := False; Key := 0; end else case Key of VK_ESCAPE: begin if edtCommand.Text <> '' then edtCommand.Text := '' else ActiveFrame.SetFocus; Key := 0; end; VK_RETURN, VK_SELECT: begin if (Shift * [ssCtrl, ssAlt, ssMeta, ssAltGr] = []) then begin ExecuteCommandLine(ssShift in Shift); Key := 0; end; end; VK_TAB: begin ActiveFrame.SetFocus; Key := 0; end; VK_PAUSE: begin { if gTermWindow and Assigned(Cons) then Cons.Terminal.SendBreak_pty(); } end; end; CheckCommandLine(GetKeyShiftStateEx, Key); end; procedure TfrmMain.edtCommandExit(Sender: TObject); begin // Hide command line if it was temporarily shown. if (not gCmdLine) and IsCommandLineVisible and (edtCommand.Text = '') then begin pnlCmdLine.Visible := False; pnlCommand.Visible := gTermWindow; end; end; procedure TfrmMain.tbChangeDirClick(Sender: TObject); var sDir: String; ToolItem: TKASToolItem; Button: TKASToolButton; begin Button := TKASToolButton(pmToolBar.Tag); if Assigned(Button) then begin ToolItem := Button.ToolItem; if ToolItem is TKASProgramItem then begin sDir := TKASProgramItem(ToolItem).StartPath; sDir := PrepareParameter(sDir, nil, [ppoNormalizePathDelims, ppoReplaceTilde]); Commands.cm_ChangeDir([sDir]); end; end; end; procedure TfrmMain.tbCopyClick(Sender: TObject); var ToolItem: TKASToolItem; ItemClone: TKASToolItem = nil; Serializer: TKASToolBarSerializer = nil; Stream: TStringStream = nil; Button: TKASToolButton; Toolbar: TKASToolBar; begin Button := TKASToolButton(pmToolBar.Tag); if Assigned(Button) then try Toolbar := Button.ToolBar; ToolItem := Button.ToolItem; // Create a copy so that ID of the button is different. if Sender = tbCopy then begin ItemClone := ToolItem.Clone; ToolItem := ItemClone; end; Stream := TStringStream.Create(''); Stream.WriteString(DCToolItemClipboardHeader); Serializer := TKASToolBarSerializer.Create; Serializer.Serialize(Stream, ToolItem); Clipboard.SetFormat(PredefinedClipboardFormat(pcfText), Stream); if Sender = tbCut then Toolbar.RemoveButton(Button); SaveToolBar(Toolbar); finally ItemClone.Free; Serializer.Free; Stream.Free; end; end; procedure TfrmMain.tbEditClick(Sender: TObject); begin EditToolbarButton(TKASToolBar(pmToolBar.PopupComponent), TKASToolButton(pmToolBar.Tag)); end; procedure TfrmMain.OnUniqueInstanceMessage(Sender: TObject; Params: TCommandLineParams); begin RestoreWindow; LoadTabsCommandLine(Params); end; procedure TfrmMain.tbPasteClick(Sender: TObject); var Data: TStringList = nil; ProgramItem: TKASProgramItem; ToolItem: TKASToolItem; Loader: TKASToolBarLoader = nil; Serializer: TKASToolBarSerializer = nil; Stream: TStringStream = nil; Pasted: Boolean = False; Button: TKASToolButton; Toolbar: TKASToolBar; begin Stream := TStringStream.Create(''); if Clipboard.GetFormat(PredefinedClipboardFormat(pcfText), Stream) then try Button := TKASToolButton(pmToolBar.Tag); Toolbar := TKASToolBar(pmToolBar.PopupComponent); // Cut any trailing zeros. while Stream.DataString[Length(Stream.DataString)] = #0 do Stream.Size := Stream.Size - 1; if StrBegins(Stream.DataString, TCToolbarClipboardHeader) or StrBegins(Stream.DataString, DCToolbarClipboardHeader) then begin Data:= TStringList.Create; Data.Text:= Stream.DataString; if Data.Count < 6 then Exit; if (Data[0] = TCToolbarClipboardHeader) or (Data[0] = DCToolbarClipboardHeader) then begin ProgramItem := TKASProgramItem.Create; ProgramItem.Command := Data[1]; ProgramItem.Params := Data[2]; ProgramItem.Icon := Data[3]; ProgramItem.Hint := Data[4]; ProgramItem.StartPath := Data[5]; Toolbar.InsertButton(Button, ProgramItem); SaveToolBar(Toolbar); Pasted := True; end; end else if StrBegins(Stream.DataString, DCToolItemClipboardHeader) then begin Stream.Position := Length(DCToolItemClipboardHeader); Serializer := TKASToolBarSerializer.Create; Loader := TKASToolBarExtendedLoader.Create(Commands.Commands); try ToolItem := Serializer.Deserialize(Stream, Loader); Toolbar.InsertButton(Button, ToolItem); SaveToolBar(Toolbar); Pasted := True; except on EXMLReadError do; end; end; if not Pasted then MessageDlg(Application.Title, rsClipboardContainsInvalidToolbarData, mtWarning, [mbOK], 0); finally Data.Free; Loader.Free; Serializer.Free; Stream.Free; end; end; procedure TfrmMain.CheckCommandLine(ShiftEx: TShiftState; var Key: Word); var ModifierKeys: TShiftState; UTF8Char: TUTF8Char; KeyTypingModifier: TKeyTypingModifier; begin for KeyTypingModifier in TKeyTypingModifier do begin if gKeyTyping[KeyTypingModifier] = ktaCommandLine then begin ModifierKeys := TKeyTypingModifierToShift[KeyTypingModifier]; if ((ModifierKeys <> []) and (ShiftEx * KeyModifiersShortcutNoText = ModifierKeys)) {$IFDEF MSWINDOWS} // Allow entering international characters with Ctrl+Alt on Windows, // if there is no action for Ctrl+Alt and command line typing has no modifiers. or (HasKeyboardAltGrKey and (ShiftEx * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]) and (gKeyTyping[ktmCtrlAlt] = ktaNone) and (gKeyTyping[ktmNone] = ktaCommandLine)) {$ENDIF} then begin if (Key <> VK_SPACE) or (edtCommand.Text <> '') then begin UTF8Char := VirtualKeyToUTF8Char(Key, ShiftEx - ModifierKeys); if (UTF8Char <> '') and (not ((Length(UTF8Char) = 1) and (UTF8Char[1] in [#0..#31]))) then begin TypeInCommandLine(UTF8Char); Key := 0; end; end; end; Break; end; end; end; function TfrmMain.ExecuteCommandFromEdit(sCmd: String; bRunInTerm: Boolean): Boolean; var iIndex: Integer; aFile: TFile = nil; sDir, sParams: String; sFilename: String = ''; Operation: TFileSourceExecuteOperation = nil; begin Result:= True; InsertFirstItem(sCmd, edtCommand); // only cMaxStringItems(see uGlobs.pas) is stored if edtCommand.Items.Count>cMaxStringItems then edtCommand.Items.Delete(edtCommand.Items.Count-1); edtCommand.DroppedDown:= False; if (fspDirectAccess in ActiveFrame.FileSource.GetProperties) then begin if FileNameCaseSensitive then sDir:= sCmd else begin sDir:= LowerCase(sCmd); end; iIndex:= Pos('cd ', sDir); if (iIndex = 1) or (sDir = 'cd') then begin sCmd:= ReplaceEnvVars(sCmd); if (iIndex <> 1) then sDir:= GetHomeDir else begin sDir:= RemoveQuotation(Copy(sCmd, iIndex + 3, Length(sCmd))); sDir:= NormalizePathDelimiters(Trim(sDir)); if (sDir = DirectorySeparator) or (sDir = '..') then begin if (sDir = DirectorySeparator) then Commands.DoChangeDirToRoot(ActiveFrame) else begin ActiveFrame.ChangePathToParent(True); end; Exit; end; sDir:= ReplaceTilde(sDir); sDir:= GetAbsoluteFileName(ActiveFrame.CurrentPath, sDir); if mbFileExists(sDir) then //if user entered an existing file, let's switch to the parent folder AND select that file begin sFilename:= ExtractFileName(sDir); sDir:= ExtractFileDir(sDir); end; end; // Choose FileSource by path ChooseFileSource(ActiveFrame, sDir, True); if sFilename <> '' then ActiveFrame.SetActiveFile(sFilename); if SameText(ExcludeBackPathDelimiter(ActiveFrame.CurrentPath), sDir) then begin if gTermWindow and Assigned(Cons) then Cons.SetCurrentDir(sDir); end; end else begin {$IFDEF MSWINDOWS} //Let's see if user typed something like "c:", "X:", etc. and if so, switch active panel to that drive (like TC) if (length(sCmd)=2) AND (pos(':',sCmd)=2) then begin iIndex:=0; while (iIndex<DrivesList.Count) AND (sCmd<>'') do begin if lowercase(sCmd[1]) = lowercase(PDrive(DrivesList.Items[iIndex])^.DisplayName) then begin SetPanelDrive(PanelSelected, DrivesList.Items[iIndex],false); sCmd:=''; end; inc(iIndex); end; end; {$ENDIF} if sCmd<>'' then begin if gTermWindow and Assigned(Cons) then begin sCmd:= ReplaceEnvVars(sCmd); Cons.WriteStr(sCmd + sLineBreak) end else begin try SplitCmdLineToCmdParams(sCmd, sCmd, sParams); //TODO:Hum... ProcessExtCommandFork(sCmd, sParams, ActiveFrame.CurrentPath, nil, bRunInTerm, bRunInTerm); except on e: EInvalidCommandLine do MessageDlg(rsMsgInvalidCommandLine, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0); end; end; end; end; end else begin aFile:= ActiveFrame.CloneActiveFile; if Assigned(aFile) then try sCmd:= 'quote' + #32 + sCmd; aFile.FullPath:= ActiveFrame.CurrentPath; Operation:= ActiveFrame.FileSource.CreateExecuteOperation( aFile, ActiveFrame.CurrentPath, sCmd) as TFileSourceExecuteOperation; if Assigned(Operation) then begin Operation.Execute; case Operation.ExecuteOperationResult of fseorSuccess: begin ActiveFrame.Reload(True); end; fseorError: begin // Show error message if Length(Operation.ResultString) = 0 then msgError(rsMsgErrEOpen) else msgError(Operation.ResultString); end; fseorSymLink: begin // Change directory to new path (returned in Operation.ResultString) with ActiveFrame do begin // If path is URI if Pos('://', Operation.ResultString) > 0 then ChooseFileSource(ActiveFrame, Operation.ResultString) else if not mbSetCurrentDir(ExcludeTrailingPathDelimiter(Operation.ResultString)) then begin // Simply change path CurrentPath:= Operation.ResultString; end else begin // Get a new filesystem file source AddFileSource(TFileSystemFileSource.GetFileSource, Operation.ResultString); end; end; end; end; end; finally FreeAndNil(aFile); FreeAndNil(Operation); end; end; end; procedure TfrmMain.SetMainSplitterPos(AValue: Double); begin if (AValue >= 0) and (AValue <= 100) then FMainSplitterPos:= AValue; end; procedure TfrmMain.SetPanelSelected(AValue: TFilePanelSelect); begin if PanelSelected = AValue then Exit; PanelSelected := AValue; UpdateTreeViewPath; UpdateMainTitleBar; UpdatePrompt; if actSyncChangeDir.Checked then begin FSyncChangeDir:= ExcludeTrailingBackslash(ActiveFrame.CurrentPath); end; end; procedure TfrmMain.TypeInCommandLine(Str: String); begin Commands.cm_FocusCmdLine([]); edtCommand.Text := edtCommand.Text + Str; edtCommand.SelStart := UTF8Length(edtCommand.Text) + 1; end; //LaBero begin //Minimize the main window procedure TfrmMain.MinimizeWindow; begin Self.WindowState := wsMinimized; end; //LaBero end procedure TfrmMain.RestoreWindow; begin if HiddenToTray then RestoreFromTray else begin WindowState:= lastWindowState; BringToFront; end; end; procedure TfrmMain.LoadTabs; var AConfig: TXmlConfig; begin if gConfig.FindNode(gConfig.RootNode, 'Tabs/OpenedTabs') <> nil then AConfig:= gConfig else begin AConfig:= TXmlConfig.Create(gpCfgDir + 'tabs.xml', True); end; try LoadTabsXml(AConfig, 'Tabs/OpenedTabs/Left', nbLeft); LoadTabsXml(AConfig, 'Tabs/OpenedTabs/Right', nbRight); finally if (AConfig <> gConfig) then AConfig.Free; end; if not CommandLineParams.ActivePanelSpecified then begin CommandLineParams.ActivePanelSpecified:= True; CommandLineParams.ActiveRight:= gActiveRight; end; LoadTabsCommandLine(CommandLineParams); if gDelayLoadingTabs then begin // Load only the current active tab of each notebook. FrameLeft.Flags := FrameLeft.Flags - [fvfDelayLoadingFiles]; FrameRight.Flags := FrameRight.Flags - [fvfDelayLoadingFiles]; end; end; procedure TfrmMain.LoadTabsCommandLine(Params: TCommandLineParams); procedure LoadPanel(aNoteBook: TFileViewNotebook; aPath: String); begin if Length(aPath) <> 0 then begin aPath:= ReplaceEnvVars(ReplaceTilde(aPath)); if not mbFileSystemEntryExists(aPath) then aPath:= GetDeepestExistingPath(aPath); if Length(aPath) <> 0 then begin if Params.NewTab then AddTab(aNoteBook, aPath) else aNoteBook.ActivePage.FileView.ChangePathAndSetActiveFile(aPath) end; end; end; begin //-- set path for left panel (if set) LoadPanel(nbLeft, Params.LeftPath); //-- set path for right panel (if set) LoadPanel(nbRight, Params.RightPath); //-- set active panel, if needed if Params.ActivePanelSpecified then begin if Params.ActiveRight then SetActiveFrame(fpRight) else SetActiveFrame(fpLeft); end; //-- set path for active panel (if set) if ActiveFrame.NotebookPage is TFileViewPage then begin LoadPanel((ActiveFrame.NotebookPage as TFileViewPage).Notebook, Params.ActivePanelPath); end; ActiveFrame.SetFocus; end; procedure TfrmMain.AddTab(ANoteBook: TFileViewNotebook; aPath: String); var Page: TFileViewPage; AFileView: TFileView; AFileViewFlags: TFileViewFlags; aFileSource: IFileSource; begin Page := ANoteBook.AddPage; aFileSource := TFileSystemFileSource.GetFileSource; if gDelayLoadingTabs then AFileViewFlags := [fvfDelayLoadingFiles] else AFileViewFlags := []; AFileView := TColumnsFileView.Create(Page, aFileSource, aPath, AFileViewFlags); AssignEvents(AFileView); ANoteBook.PageIndex := ANoteBook.PageCount - 1; end; {$IF DEFINED(DARWIN)} procedure TfrmMain.OnNSServiceOpenWithNewTab( filenames:TStringList ); begin if Assigned(filenames) and (filenames.Count>0) then begin AddTab( nbRight, filenames[0] ); SetActiveFrame(fpRight); ActiveFrame.SetFocus; end; end; function TfrmMain.NSServiceMenuIsReady(): boolean; begin Result:= true; end; function TfrmMain.NSServiceMenuGetFilenames(): TStringList; var filenames: TStringList; i: Integer; files: TFiles; activeFile: TFile; begin Result:= nil; filenames:= TStringList.Create; files:= ActiveFrame.CloneSelectedFiles(); if files.Count>0 then begin for i:=0 to files.Count-1 do begin filenames.add( files[i].FullPath ); end; end; FreeAndNil( files ); if filenames.Count = 0 then begin activeFile:= ActiveFrame.CloneActiveFile; if activeFile.IsNameValid() then filenames.add( activeFile.FullPath ) else filenames.add( activeFile.Path ); FreeAndNil( activeFile ); end; if filenames.Count>0 then Result:= filenames; end; procedure TfrmMain.NSThemeChangedHandler; begin ThemeServices.IntfDoOnThemeChange; end; {$ENDIF} procedure TfrmMain.LoadWindowState; var ANode: TXmlNode; FPixelsPerInch: Integer; begin // Load window bounds ANode := gConfig.FindNode(gConfig.RootNode, 'MainWindow/Position', True); begin MainSplitterPos := gConfig.GetValue(ANode, 'Splitter', 50.0); FRestoredLeft := gConfig.GetValue(ANode, 'Left', 80); FRestoredTop := gConfig.GetValue(ANode, 'Top', 48); FRestoredWidth := gConfig.GetValue(ANode, 'Width', 800); FRestoredHeight := gConfig.GetValue(ANode, 'Height', 480); FPixelsPerInch := gConfig.GetValue(ANode, 'PixelsPerInch', DesignTimePPI); if Scaled and (Screen.PixelsPerInch <> FPixelsPerInch) then begin FRestoredWidth := MulDiv(FRestoredWidth, Screen.PixelsPerInch, FPixelsPerInch); FRestoredHeight := MulDiv(FRestoredHeight, Screen.PixelsPerInch, FPixelsPerInch); end; if gConfig.GetValue(ANode, 'Maximized', True) then lastWindowState:= TWindowState.wsMaximized else lastWindowState:= TWindowState.wsNormal; SetBounds(FRestoredLeft, FRestoredTop, FRestoredWidth, FRestoredHeight); end; end; procedure TfrmMain.SaveWindowState; var ANode: TXmlNode; begin // Save window bounds and state ANode := gConfig.FindNode(gConfig.RootNode, 'MainWindow/Position', True); begin gConfig.SetValue(ANode, 'Left', FRestoredLeft); gConfig.SetValue(ANode, 'Top', FRestoredTop); gConfig.SetValue(ANode, 'Width', FRestoredWidth); gConfig.SetValue(ANode, 'Height', FRestoredHeight); gConfig.SetValue(ANode, 'PixelsPerInch', Screen.PixelsPerInch); gConfig.SetValue(ANode, 'Maximized', (WindowState in [wsMaximized,wsFullScreen])); gConfig.SetValue(ANode, 'Splitter', FMainSplitterPos); end; end; procedure TfrmMain.LoadToolbar(AToolBar: TKASToolBar); var ToolBarLoader: TKASToolBarExtendedLoader; ToolBarNode: TXmlNode; begin AToolBar.BeginUpdate; ToolBarLoader := TKASToolBarExtendedLoader.Create(Commands.Commands); try AToolBar.Clear; ToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + AToolBar.Name, False); if Assigned(ToolBarNode) then AToolBar.LoadConfiguration(gConfig, ToolBarNode, ToolBarLoader, tocl_FlushCurrentToolbarContent); finally ToolBarLoader.Free; AToolBar.EndUpdate; end; end; procedure TfrmMain.SaveToolBar(AToolBar: TKASToolBar); var ToolBarNode: TXmlNode; begin ToolBarNode := gConfig.FindNode(gConfig.RootNode, 'Toolbars/' + AToolBar.Name, True); gConfig.ClearNode(ToolBarNode); AToolBar.SaveConfiguration(gConfig, ToolBarNode); end; procedure TfrmMain.ShowLogWindow(Data: PtrInt); var bShow: Boolean absolute Data; begin LogSplitter.Visible:= bShow; seLogWindow.Visible:= bShow; LogSplitter.Top:= seLogWindow.Top - LogSplitter.Height; end; procedure TfrmMain.ConfigSaveSettings(bForce: Boolean); var AConfig: TXmlConfig; begin try DebugLn('Saving configuration'); if gSaveCmdLineHistory then glsCmdLineHistory.Assign(edtCommand.Items); (* Save all tabs *) if gSaveFolderTabs or bForce then begin AConfig:= TXmlConfig.Create(gpCfgDir + 'tabs.xml'); try SaveTabsXml(AConfig, 'Tabs/OpenedTabs/', nbLeft, gSaveDirHistory); SaveTabsXml(AConfig, 'Tabs/OpenedTabs/', nbRight, gSaveDirHistory); AConfig.Save; finally AConfig.Free; end; gConfig.DeleteNode(gConfig.RootNode, 'Tabs/OpenedTabs'); end; if gSaveWindowState then SaveWindowState; if gButtonBar then SaveToolBar(MainToolBar); SaveGlobs; // Should be last, writes configuration file except on E: Exception do DebugLn('Cannot save main configuration: ', e.Message); end; end; function TfrmMain.IsCommandLineVisible: Boolean; begin Result := (edtCommand.Visible and pnlCommand.Visible and pnlCmdLine.Visible); end; procedure TfrmMain.ShowCommandLine(AFocus: Boolean); begin if edtCommand.Visible then begin // Show temporarily command line on user request. if not (gCmdLine and frmMain.IsCommandLineVisible) then begin pnlCommand.Show; pnlCmdLine.Show; end; if AFocus then edtCommand.SetFocus; end; end; function TfrmMain.FindMatchingDrive(Address, Path: String): Integer; var I : Integer; DrivePath: String; DrivePathLen: PtrInt; LongestPathLen: Integer = 0; begin Result := -1; if Assigned(DrivesList) then begin Path := UTF8UpperCase(Path); for I := 0 to DrivesList.Count - 1 do begin if (DrivesList[I]^.DriveType = dtSpecial) and (Length(Address) > 0) then begin if Pos(Address, DrivesList[I]^.Path) = 1 then Exit(I); end else begin DrivePath := UTF8UpperCase(DrivesList[I]^.Path); DrivePathLen := UTF8Length(DrivePath); if (DrivePathLen > LongestPathLen) and IsInPath(DrivePath, Path, True, True) then begin LongestPathLen := DrivePathLen; Result := I; end; end; end; end; end; procedure TfrmMain.UpdateDriveToolbarSelection(DriveToolbar: TKAStoolBar; FileView: TFileView); var DriveIndex: Integer; begin DriveIndex := FindMatchingDrive(FileView.CurrentAddress, FileView.CurrentPath); if (DriveIndex >= 0) and (DriveIndex < DriveToolbar.ButtonCount) then DriveToolbar.Buttons[DriveIndex].Down := True else // Path not found in toolbar. DriveToolbar.UncheckAllButtons; end; procedure TfrmMain.UpdateDriveButtonSelection(DriveButton: TSpeedButton; FileView: TFileView); var Drive: PDrive; BitmapTmp: Graphics.TBitmap = nil; begin DriveButton.Tag := FindMatchingDrive(FileView.CurrentAddress, FileView.CurrentPath); if not gDrivesListButton then Exit; if DriveButton.Tag >= 0 then begin Drive := DrivesList[DriveButton.Tag]; DriveButton.Caption := Drive^.DisplayName; BitmapTmp := PixMapManager.GetDriveIcon(Drive, gDiskIconsSize, DriveButton.Color); end else begin DriveButton.Caption := ''; if FileView.FileSource.IsClass(TArchiveFileSource) then BitmapTmp := PixMapManager.GetArchiveIcon(gDiskIconsSize, DriveButton.Color) else BitmapTmp := PixMapManager.GetDefaultDriveIcon(gDiskIconsSize, DriveButton.Color); end; DriveButton.Glyph := BitmapTmp; DriveButton.Width := DriveButton.Glyph.Width + DriveButton.Canvas.TextWidth(DriveButton.Caption) + 24; FreeAndNil(BitmapTmp); end; procedure TfrmMain.UpdateSelectedDrive(ANoteBook: TFileViewNotebook); var FileView: TFileView; begin FileView := ANoteBook.ActiveView; if Assigned(FileView) then begin // Change left drive toolbar for left drive button. if (ANoteBook = nbLeft) then begin if gDriveBar1 then // If drives toolbar enabled at all begin if gDriveBar2 then // If showing two toolbars UpdateDriveToolbarSelection(dskLeft, FileView) else // dskRight is the main toolbar. UpdateDriveToolbarSelection(dskRight, FileView); end; UpdateDriveButtonSelection(btnLeftDrive, FileView); end // Change right drive toolbar for right drive button else if (ANoteBook = nbRight) then begin if gDriveBar1 then UpdateDriveToolbarSelection(dskRight, FileView); UpdateDriveButtonSelection(btnRightDrive, FileView); end; end; end; {$IF DEFINED(MSWINDOWS)} procedure TfrmMain.OnDriveIconLoaded(Data: PtrInt); var ADrive: TKASDriveItem; AIcon: TDriveIcon absolute Data; procedure UpdateDriveIcon(dskPanel: TKASToolBar); var Index: Integer; begin for Index:= 0 to dskPanel.ButtonCount - 1 do begin if dskPanel.Buttons[Index].ToolItem is TKASDriveItem then begin ADrive:= TKASDriveItem(dskPanel.Buttons[Index].ToolItem); if SameText(ADrive.Drive^.Path, AIcon.Drive.Path) then begin dskPanel.Buttons[Index].Glyph.Assign(AIcon.Bitmap); Break; end; end; end; end; begin if gDriveBar2 then UpdateDriveIcon(dskLeft); if gDriveBar1 then UpdateDriveIcon(dskRight); AIcon.Free; end; {$ENDIF} procedure TfrmMain.UpdateSelectedDrives; begin if gDriveBar1 then begin if gDriveBar2 then begin UpdateDriveToolbarSelection(dskLeft, FrameLeft); UpdateDriveToolbarSelection(dskRight, FrameRight); end else // dskRight is the main toolbar. UpdateDriveToolbarSelection(dskRight, ActiveFrame); end; UpdateDriveButtonSelection(btnLeftDrive, FrameLeft); UpdateDriveButtonSelection(btnRightDrive, FrameRight); end; procedure TfrmMain.UpdateMainTitleBar; var sTmp: String; begin if gShowCurDirTitleBar and (fspDirectAccess in ActiveFrame.FileSource.Properties) then begin sTmp := ActiveFrame.CurrentPath; Self.Caption:= Format('%s (%s) - %s', [GetLastDir(sTmp), sTmp, sStaticTitleBarString] ); end else begin Self.Caption := sStaticTitleBarString; end; end; procedure TfrmMain.UpdateGUIFunctionKeys; var I: Integer; H: Integer = 0; AButton: TSpeedButton; begin for I:= 0 to pnlKeys.ControlCount - 1 do begin if pnlKeys.Controls[I] is TSpeedButton then begin AButton:= TSpeedButton(pnlKeys.Controls[I]); FontOptionsToFont(gFonts[dcfFunctionButtons], AButton.Font); H:= Max(H, AButton.Canvas.TextHeight(AButton.Caption)); end; end; pnlKeys.Height := H + 4; end; procedure TfrmMain.ShowDrivesList(APanel: TFilePanelSelect); var p: TPoint; ADriveIndex: Integer; begin if tb_activate_panel_on_click in gDirTabOptions then SetActiveFrame(APanel); case APanel of fpLeft: begin p := Classes.Point(btnLeftDrive.Left, btnLeftDrive.Height); p := pnlLeftTools.ClientToScreen(p); ADriveIndex := btnLeftDrive.Tag; end; fpRight: begin p := Classes.Point(btnRightDrive.Left, btnRightDrive.Height); p := pnlRightTools.ClientToScreen(p); ADriveIndex := btnRightDrive.Tag; end; end; p := ScreenToClient(p); FDrivesListPopup.Show(p, APanel, ADriveIndex); end; procedure TfrmMain.HideToTray; {$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} var ActiveWindow: HWND; LCLObject: TObject; {$ENDIF} begin { If a modal form is active we have to hide it first before hiding the main form to avoid bugs: On GTK2 a modal form loses it's modal state after the main window is restored (GTK still says the window is modal and resetting modal state doesn't do anything). On QT the tray icon does not receive any mouse events (because the modal window has capture) thus preventing the user from restoring the main window. So when the main form is hidden the modal window is hidden too. } {$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} LastActiveWindow := nil; if not Self.Active then // If there is another window active begin ActiveWindow := GetActiveWindow; if ActiveWindow <> 0 then begin LCLObject := GetLCLOwnerObject(ActiveWindow); if Assigned(LCLObject) and (LCLObject is TCustomForm) and (fsModal in (LCLObject as TCustomForm).FormState) then // only for modal windows begin LastActiveWindow := LCLObject as TCustomForm; {$IFDEF LCLGTK2} // Cannot use Hide method, because it closes the modal form. // We only want to hide it. LastActiveWindow.Visible := False; {$ENDIF} {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} // Have to use QT directly to hide the window for this to work. TQtWidget(LastActiveWindow.Handle).setVisible(False); {$ENDIF} end; end; end; {$ENDIF} Hide; ShowTrayIcon(True); HiddenToTray := True; end; procedure TfrmMain.RestoreFromTray; begin if lastWindowState=wsMaximized then WindowState:=wsMaximized; ShowOnTop; if not gAlwaysShowTrayIcon then ShowTrayIcon(False); // After the main form is shown, restore the last active modal form if there was any. {$IF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} if Assigned(LastActiveWindow) then begin {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} TQtWidget(LastActiveWindow.Handle).setVisible(true); {$ENDIF} {$IFDEF LCLGTK2} LastActiveWindow.Show; {$ENDIF} LastActiveWindow := nil; end; {$ENDIF} end; procedure TfrmMain.RightDriveBarExecuteDrive(ToolItem: TKASToolItem); var DriveItem: TKASDriveItem; Panel: TFilePanelSelect; begin DriveItem := ToolItem as TKASDriveItem; if gDriveBar2 then Panel := fpRight else Panel := ActiveNotebook.Side; SetPanelDrive(Panel, DriveItem.Drive, True); end; procedure TfrmMain.ShowTrayIcon(bShow: Boolean); begin if (bShow <> MainTrayIcon.Visible) and (HidingTrayIcon = False) then begin if bShow then begin MainTrayIcon.Visible := True; end else begin // ShowTrayIcon might be called from within OnClick event of the icon // (MainTrayIconClick->RestoreFromTray->ShowTrayIcon), so the MainTrayIcon // cannot be hidden here, because it would be destroyed causing A/V. // Hiding it must be delayed until after the mouse click handler of the icon is finished. HidingTrayIcon := True; Application.QueueAsyncCall(@HideTrayIconDelayed, 0); end; end; end; procedure TfrmMain.HideTrayIconDelayed(Data: PtrInt); begin MainTrayIcon.Visible := False; HidingTrayIcon := False; end; procedure TfrmMain.ExecuteCommandLine(bRunInTerm: Boolean); begin mbSetCurrentDir(ActiveFrame.CurrentPath); ExecuteCommandFromEdit(edtCommand.Text, bRunInTerm); edtCommand.Text := ''; ActiveFrame.Reload; ActiveFrame.SetFocus; {$IF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} // workaround for GTK // edtCommandExit is not always called when losing focus edtCommandExit(Self); {$ENDIF} end; procedure TfrmMain.UpdatePrompt; var st: String; Properties: TFileSourceProperties; begin if (fsoExecute in ActiveFrame.FileSource.GetOperationsTypes) then begin with lblCommandPath do begin Visible := True; st := ExcludeTrailingBackslash(ActiveFrame.CurrentPath); Hint := st; Caption := MinimizeFilePath(Format(fmtCommandPath, [st]), Canvas, pnlCommand.Width div 3); end; // Change path in terminal if (fspDirectAccess in ActiveFrame.FileSource.GetProperties) then begin if gTermWindow and Assigned(Cons) then Cons.SetCurrentDir(ActiveFrame.CurrentPath); end; edtCommand.Visible := True; end else begin lblCommandPath.Visible := False; edtCommand.Visible := False; end; // Change program current path Properties := ActiveFrame.FileSource.GetProperties; if (fspDirectAccess in Properties) and not (fspLinksToLocalFiles in Properties) then begin mbSetCurrentDir(ActiveFrame.CurrentPath); end; end; procedure TfrmMain.OnDriveGetFreeSpace(Data: PtrInt); var aFileView: TFileView; sboxDrive: TPaintBox; lblDriveInfo: TLabel; AData: TFreeSpaceData absolute Data; begin case AData.Panel of fpLeft : begin sboxDrive := pbxLeftDrive; aFileView := FrameLeft; lblDriveInfo :=lblLeftDriveInfo; end; fpRight: begin sboxDrive := pbxRightDrive; aFileView := FrameRight; lblDriveInfo := lblRightDriveInfo; end; end; if mbCompareFileNames(AData.Path, aFileView.CurrentPath) then begin if not AData.Result then begin lblDriveInfo.Caption := ''; lblDriveInfo.Hint := ''; sboxDrive.Hint := ''; sboxDrive.Tag := -1; sboxDrive.Invalidate; end else begin if gDriveInd = True then begin if AData.TotalSize > 0 then sboxDrive.Tag := 100 - Round((AData.FreeSize / AData.TotalSize) * 100) // Save busy percent else begin sboxDrive.Tag := -1; end; sboxDrive.Invalidate; end; lblDriveInfo.Hint := Format(rsFreeMsg, [cnvFormatFileSize(AData.FreeSize, uoscHeader), cnvFormatFileSize(AData.TotalSize, uoscHeader)]); if gShortFormatDriveInfo then lblDriveInfo.Caption := Format(rsFreeMsgShort, [cnvFormatFileSize(AData.FreeSize, uoscHeader)]) else begin lblDriveInfo.Caption := lblDriveInfo.Hint; end; sboxDrive.Hint := lblDriveInfo.Hint; end; end; AData.Free; end; procedure TfrmMain.UpdateFreeSpace(Panel: TFilePanelSelect; Clear: Boolean); var aFileView: TFileView; sboxDrive: TPaintBox; lblDriveInfo: TLabel; AData: TFreeSpaceData; begin case Panel of fpLeft : begin sboxDrive := pbxLeftDrive; aFileView := FrameLeft; lblDriveInfo :=lblLeftDriveInfo; end; fpRight: begin sboxDrive := pbxRightDrive; aFileView := FrameRight; lblDriveInfo := lblRightDriveInfo; end; end; if Clear then begin lblDriveInfo.Caption := ''; lblDriveInfo.Hint := ''; sboxDrive.Hint := ''; sboxDrive.Tag := -1; sboxDrive.Invalidate; end; AData := TFreeSpaceData.Create; AData.Panel := Panel; AData.Path := aFileView.CurrentPath; AData.OnFinish := @OnDriveGetFreeSpace; AData.FileSource := aFileView.FileSource; TThread.ExecuteInThread(@AData.GetFreeSpaceInThread); end; procedure TfrmMain.CloseNotebook(ANotebook: TFileViewNotebook); var I: Integer; begin for I := 0 to ANotebook.PageCount - 1 do ANotebook.View[I].Clear; ANotebook.DestroyAllPages; end; procedure TfrmMain.DriveListDriveSelected(Sender: TObject; ADriveIndex: Integer; APanel: TFilePanelSelect); begin SetPanelDrive(APanel, DrivesList.Items[ADriveIndex], True); end; procedure TfrmMain.DriveListClose(Sender: TObject); begin SetActiveFrame(SelectedPanel); end; procedure TfrmMain.AllProgressOnUpdateTimer(Sender: TObject); var AllProgressPoint: Integer; begin if gPanelOfOp = True then begin FOperationsPanel.UpdateView; end; // Show progress in the menu if gProgInMenuBar = True then begin AllProgressPoint:= Round(OperationsManager.AllProgressPoint * 100); mnuAllOperProgress.Caption:= IntToStr(AllProgressPoint) + ' %'; end; Sleep(0); end; procedure TfrmMain.OperationManagerNotify(Item: TOperationsManagerItem; Event: TOperationManagerEvent); begin if Event = omevOperationRemoved then begin // Hide progress bar if there are no operations if OperationsManager.OperationsCount = 0 then begin mnuAllOperProgress.Visible:= False; mnuAllOperPause.Visible:= False; mnuAllOperStart.Visible:= False; mnuAllOperStop.Visible:= False; end; PlaySound(Item); end else if Event = omevOperationAdded then begin if gProgInMenuBar = True then begin mnuAllOperProgress.Visible:= True; mnuAllOperPause.Visible:= True; mnuAllOperStart.Visible:= True; mnuAllOperStop.Visible:= True; end; end; AllProgressOnUpdateTimer(Timer); Timer.Enabled := (gPanelOfOp or gProgInMenuBar) and (OperationsManager.OperationsCount > 0); end; procedure TfrmMain.SetPanelDrive(aPanel: TFilePanelSelect; Drive: PDrive; ActivateIfNeeded: Boolean); var Index: Integer; DrivePath: String; DriveIndex: Integer; FoundPath: Boolean = False; aFileView, OtherFileView: TFileView; begin if (Drive^.DriveType in [dtSpecial, dtVirtual]) or IsAvailable(Drive, True) then begin case aPanel of fpLeft: begin aFileView := FrameLeft; OtherFileView := FrameRight; end; fpRight: begin aFileView := FrameRight; OtherFileView := FrameLeft; end; end; // Special case for special drive if Drive^.DriveType = dtSpecial then begin ChooseFileSource(aFileView, Drive^.Path); if ActivateIfNeeded and (tb_activate_panel_on_click in gDirTabOptions) then SetActiveFrame(aPanel); Exit; end; // Special case for virtual drive if Drive^.DriveType = dtVirtual then begin if Drive^.FileSystem = 'VFS' then Commands.DoOpenVirtualFileSystemList(aFileView) else begin ChooseFileSource(aFileView, GetNetworkPath(Drive)); if ActivateIfNeeded and (tb_activate_panel_on_click in gDirTabOptions) then SetActiveFrame(aPanel); end; Exit; end; DrivePath:= ExcludeTrailingPathDelimiter(Drive^.Path); // Copy path opened in the other panel if the file source and drive match // and that path is not already opened in this panel. if (not gGoToRoot) and OtherFileView.FileSource.IsClass(TFileSystemFileSource) and mbCompareFileNames(ExtractRootDir(OtherFileView.CurrentPath), DrivePath) and not mbCompareFileNames(OtherFileView.CurrentPath, aFileView.CurrentPath) then begin FoundPath:= True; SetFileSystemPath(aFileView, OtherFileView.CurrentPath); end // Open archive parent directory else if (gGoToRoot = False) and OtherFileView.FileSource.IsClass(TArchiveFileSource) and (not IsInPath(GetTempFolder, OtherFileView.FileSource.CurrentAddress, True, False)) and mbCompareFileNames(ExtractRootDir(OtherFileView.FileSource.CurrentAddress), DrivePath) and not mbCompareFileNames(ExtractFilePath(OtherFileView.FileSource.CurrentAddress), aFileView.CurrentPath) then begin FoundPath:= True; SetFileSystemPath(aFileView, ExtractFilePath(OtherFileView.FileSource.CurrentAddress)); end // Open latest path from history for chosen drive else if (gGoToRoot = False) and aFileView.FileSource.IsClass(TFileSystemFileSource) and not mbCompareFileNames(ExtractRootDir(aFileView.CurrentPath), DrivePath) then begin for Index:= 0 to glsDirHistory.Count - 1 do begin DriveIndex:= FindMatchingDrive(EmptyStr, glsDirHistory[Index]); if (DriveIndex >= 0) and (DriveIndex < DrivesList.Count) then begin if mbCompareFileNames(Drive^.Path, DrivesList[DriveIndex]^.Path) then begin if mbDirectoryExists(ExcludeBackPathDelimiter(glsDirHistory[Index])) then begin SetFileSystemPath(aFileView, glsDirHistory[Index]); FoundPath:= True; Break; end; end; end; end; end; if not FoundPath then begin SetFileSystemPath(aFileView, Drive^.Path); end; if ActivateIfNeeded and (tb_activate_panel_on_click in gDirTabOptions) then SetActiveFrame(aPanel); end else begin msgWarning(rsMsgDiskNotAvail); // Restore previous selected button. case aPanel of fpLeft: UpdateSelectedDrive(LeftTabs); fpRight: UpdateSelectedDrive(RightTabs); end; end; end; procedure TfrmMain.OnDriveWatcherEvent(EventType: TDriveWatcherEvent; const ADrive: PDrive); begin // Update disk panel does not work correctly when main // window is minimized. So set FUpdateDiskCount flag instead // and update disk count later in WindowStateChange event if WindowState = wsMinimized then FUpdateDiskCount:= True else begin UpdateDiskCount; end; if (FrameLeft = nil) or (FrameRight = nil) then Exit; if (EventType = dweDriveRemoved) and Assigned(ADrive) then begin if IsInPath(ADrive^.Path, ActiveFrame.CurrentPath, True, True) then ActiveFrame.CurrentPath:= GetHomeDir else if IsInPath(ADrive^.Path, NotActiveFrame.CurrentPath, True, True) then NotActiveFrame.CurrentPath:= GetHomeDir; end; UpdateSelectedDrives; end; procedure TfrmMain.DelayedEvent(Data: PtrInt); begin { discard duplicate calls, accept last call only } Dec(FDelayedEventCtr); if FDelayedEventCtr > 0 then Exit; { update restored bounds } if WindowState = wsNormal then begin if FDelayedWMMove then begin FRestoredLeft := Left; FRestoredTop := Top; end; if FDelayedWMSize then begin FRestoredWidth := Width; FRestoredHeight := Height; end; end; FDelayedWMMove := False; FDelayedWMSize := False; // Sync position and size with real main form with BoundsRect do Application.MainForm.SetBounds(Left, Top, Width, Height); end; procedure TfrmMain.AppActivate(Sender: TObject); begin if Assigned(FrameLeft) then FrameLeft.ReloadIfNeeded; if Assigned(FrameRight) then FrameRight.ReloadIfNeeded; end; procedure TfrmMain.AppDeActivate(Sender: TObject); begin if Assigned(frmTreeViewMenu) then begin frmTreeViewMenu.Close; end; Application.CancelHint; end; procedure TfrmMain.AppEndSession(Sender: TObject); var CloseAction: TCloseAction; begin frmMainClose(Sender, CloseAction); end; procedure TfrmMain.AppThemeChange(Sender: TObject); procedure UpdateNoteBook(NoteBook: TFileViewNotebook); var Index: Integer; begin for Index := 0 to NoteBook.PageCount - 1 do begin NoteBook.View[Index].UpdateColor; end; end; var Index: Integer; begin UpdateNoteBook(LeftTabs); UpdateNoteBook(RightTabs); ColSet.UpdateStyle; gColorExt.UpdateStyle; gHighlighters.UpdateStyle; DCDebug('AppThemeChange'); for Index:= 0 to Screen.CustomFormCount - 1 do begin Screen.CustomForms[Index].Perform(CM_THEMECHANGED, 0, 0); end; end; procedure TfrmMain.AppQueryEndSession(var Cancel: Boolean); var CanClose: Boolean = True; begin FormCloseQuery(Self, CanClose); Cancel := not CanClose; end; {$IFDEF DARWIN} procedure TfrmMain.createDarwinAppMenu; var appMenu: TMenuItem; aboutItem: TMenuItem; sepItem: TMenuItem; prefItem: TMenuItem; begin appMenu:= TMenuItem.Create(mnuMain); appMenu.Caption:= ''; mnuMain.Items.Insert(0, appMenu); aboutItem:= TMenuItem.Create(mnuMain); aboutItem.Caption:= 'About ' + Application.Title; aboutItem.OnClick:= @aboutOnClick; appMenu.Add(aboutItem); sepItem := TMenuItem.Create(mnuMain); sepItem.Caption := '-'; appMenu.Add(sepItem); prefItem := TMenuItem.Create(mnuMain); prefItem.Caption := 'Preferences...'; prefItem.OnClick := @optionsOnClick; prefItem.Shortcut := ShortCut(VK_OEM_COMMA, [ssMeta]); appMenu.Add(prefItem); end; procedure TfrmMain.aboutOnClick(Sender: TObject); begin Commands.cm_About([]); end; procedure TfrmMain.optionsOnClick(Sender: TObject); begin Commands.cm_Options([]); end; {$ENDIF} {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not DEFINED(MSWINDOWS)} function TfrmMain.QObjectEventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; begin Result:= False; case QEvent_type(Event) of QEventApplicationPaletteChange: begin ThemeServices.IntfDoOnThemeChange; end; QEventClose: begin TQtWidget(Self.Handle).SlotClose; Result:= CloseQueryResult; if Result then QEvent_accept(Event) else QEvent_ignore(Event); end; end; end; {$ENDIF} initialization {$I DragCursors.lrs} TFormCommands.RegisterCommandsForm(TfrmMain, HotkeysCategory, @rsHotkeyCategoryMain); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmaincommandsdlg.lfm�����������������������������������������������������������0000644�0001750�0000144�00000025246�14743153644�017411� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMainCommandsDlg: TfrmMainCommandsDlg Left = 77 Height = 350 Top = 189 Width = 600 HorzScrollBar.Page = 464 HorzScrollBar.Range = 369 VertScrollBar.Page = 301 VertScrollBar.Range = 227 ActiveControl = lbledtFilter BorderIcons = [biSystemMenu] Caption = 'Select your internal command' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 350 ClientWidth = 600 Constraints.MinHeight = 350 Constraints.MinWidth = 600 KeyPreview = True OnActivate = FormActivate OnCreate = FormCreate OnDestroy = FormDestroy Position = poScreenCenter SessionProperties = 'cbCategorySortOrNot.ItemIndex;cbCommandsSortOrNot.ItemIndex;Height;Width;cbSelectAllCategoryDefault.Checked' LCLVersion = '1.6.0.4' object lblCategory: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = lbledtFilter AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 34 Width = 59 Caption = '&Categories:' FocusControl = lbCategory ParentColor = False end object lblCommandName: TLabel AnchorSideLeft.Control = lbCommands AnchorSideTop.Control = lbledtFilter AnchorSideTop.Side = asrBottom Left = 162 Height = 15 Top = 34 Width = 93 BorderSpacing.Left = 1 Caption = 'Command &name:' FocusControl = lbCommands ParentColor = False end object lblHint: TLabel AnchorSideLeft.Control = lblCommandName AnchorSideTop.Control = lbledtFilter AnchorSideTop.Side = asrBottom Left = 412 Height = 15 Top = 34 Width = 26 BorderSpacing.Left = 250 Caption = 'Hint:' ParentColor = False end object lbCategory: TListBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblCategory AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbCategorySortOrNot AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbCategorySortOrNot Left = 6 Height = 185 Top = 49 Width = 150 Anchors = [akTop, akLeft, akRight, akBottom] Constraints.MinWidth = 150 ItemHeight = 0 OnEnter = lbCategoryEnter OnExit = lbCategoryExit OnSelectionChange = lbCategorySelectionChange ScrollWidth = 134 TabOrder = 2 end object lbCommands: TListBox AnchorSideLeft.Control = lbCategory AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblCommandName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnCancel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbCommandsSortOrNot Left = 161 Height = 185 Top = 49 Width = 433 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 5 ItemHeight = 0 OnDblClick = lbCommandsDblClick OnDrawItem = lbCommandsDrawItem OnEnter = lbCommandsEnter OnExit = lbCommandsExit OnKeyPress = lbCommandsKeyPress ScrollWidth = 445 Style = lbOwnerDrawFixed TabOrder = 1 end object lbledtFilter: TLabeledEdit AnchorSideLeft.Control = lbCommands AnchorSideTop.Control = Owner Left = 161 Height = 23 Top = 6 Width = 250 BorderSpacing.Bottom = 5 EditLabel.AnchorSideTop.Control = lbledtFilter EditLabel.AnchorSideTop.Side = asrCenter EditLabel.AnchorSideRight.Control = lbledtFilter EditLabel.AnchorSideBottom.Control = lbledtFilter EditLabel.AnchorSideBottom.Side = asrBottom EditLabel.Left = 129 EditLabel.Height = 15 EditLabel.Top = 10 EditLabel.Width = 29 EditLabel.Caption = '&Filter:' EditLabel.ParentColor = False LabelPosition = lpLeft TabOrder = 0 OnChange = lbledtFilterChange OnEnter = lbledtFilterEnter OnExit = lbledtFilterExit OnKeyDown = lbledtFilterKeyDown end object btnOK: TBitBtn AnchorSideLeft.Control = btnCancel AnchorSideRight.Control = btnCancel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnCancel Left = 496 Height = 33 Top = 274 Width = 98 Anchors = [akLeft, akRight, akBottom] BorderSpacing.InnerBorder = 2 Caption = '&OK' Default = True Kind = bkOK ModalResult = 1 TabOrder = 7 end object btnCancel: TBitBtn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 496 Height = 31 Top = 313 Width = 98 Anchors = [akRight, akBottom] BorderSpacing.Top = 6 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 TabOrder = 8 end object cbCategorySortOrNot: TComboBoxAutoWidth AnchorSideLeft.Control = Owner AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gbSelection Left = 6 Height = 23 Top = 237 Width = 136 Anchors = [akLeft, akBottom] BorderSpacing.Top = 3 ItemHeight = 15 ItemIndex = 0 Items.Strings = ( 'Legacy sorted' 'A-Z sorted' ) OnChange = cbCategorySortOrNotChange Style = csDropDownList TabOrder = 3 Text = 'Legacy sorted' end object cbCommandsSortOrNot: TComboBoxAutoWidth AnchorSideLeft.Control = lbCommands AnchorSideTop.Control = lbCommands AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = gbSelection Left = 161 Height = 23 Top = 237 Width = 136 Anchors = [akLeft, akBottom] BorderSpacing.Top = 3 BorderSpacing.Right = 5 ItemHeight = 15 ItemIndex = 0 Items.Strings = ( 'Legacy sorted' 'Sorted A-Z' ) OnChange = cbCommandsSortOrNotChange Style = csDropDownList TabOrder = 4 Text = 'Legacy sorted' end object gbSelection: TGroupBox AnchorSideLeft.Control = Owner AnchorSideRight.Control = btnCancel AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 78 Top = 266 Width = 480 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Top = 6 BorderSpacing.Right = 10 Caption = 'Selection:' ClientHeight = 58 ClientWidth = 476 TabOrder = 6 object lblSelectedCommand: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbSelection AnchorSideRight.Control = pnlImage Left = 373 Height = 15 Top = 0 Width = 53 Anchors = [akTop, akRight] BorderSpacing.Left = 10 BorderSpacing.Right = 10 Caption = 'cm_name' Font.Style = [fsBold] ParentColor = False ParentFont = False OnClick = lblPlaceCaptionInClipClick end object lblSelectedCommandHint: TLabel AnchorSideTop.Control = lblSelectedCommand AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblSelectedCommand AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 402 Height = 15 Top = 15 Width = 24 Anchors = [akTop, akRight] BorderSpacing.Left = 10 Caption = 'Hint' Font.Style = [fsBold] ParentColor = False ParentFont = False OnClick = lblPlaceCaptionInClipClick end object lblSelectedCommandHelp: TLabel AnchorSideTop.Control = pnlImage AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlImage AnchorSideRight.Side = asrBottom Cursor = crHandPoint Left = 440 Height = 15 Top = 40 Width = 32 Alignment = taCenter Anchors = [akTop, akRight] BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 Caption = 'Help' Constraints.MinWidth = 32 Font.Style = [fsUnderline] ParentColor = False ParentFont = False OnClick = lblSelectedCommandHelpClick OnMouseEnter = lblSelectedCommandHelpMouseEnter OnMouseLeave = lblSelectedCommandHelpMouseLeave end object lblSelectedCommandHotkey: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblSelectedCommandHint AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblSelectedCommand AnchorSideRight.Side = asrBottom Left = 385 Height = 15 Top = 30 Width = 41 Anchors = [akTop, akRight] BorderSpacing.Left = 10 Caption = 'Hotkey' Font.Color = clRed Font.Style = [fsBold] ParentColor = False ParentFont = False OnClick = lblPlaceCaptionInClipClick end object lblSelectedCommandCategory: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbSelection AnchorSideRight.Control = lblSelectedCommand Left = 315 Height = 15 Top = 0 Width = 48 Anchors = [akTop, akRight] BorderSpacing.Left = 10 BorderSpacing.Right = 10 Caption = 'Category' ParentColor = False ParentFont = False OnClick = lblPlaceCaptionInClipClick end object pnlImage: TPanel AnchorSideTop.Control = gbSelection AnchorSideRight.Control = gbSelection AnchorSideRight.Side = asrBottom Left = 436 Height = 40 Top = 0 Width = 40 Anchors = [akTop, akRight] BevelOuter = bvNone ClientHeight = 40 ClientWidth = 40 TabOrder = 0 object imgCommandIcon: TImage AnchorSideLeft.Control = pnlImage AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = pnlImage AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 4 Height = 32 Top = 4 Width = 32 BorderSpacing.Top = 3 BorderSpacing.Right = 10 OnDblClick = lbCommandsDblClick end end end object cbSelectAllCategoryDefault: TCheckBox AnchorSideLeft.Control = cbCommandsSortOrNot AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCommandsSortOrNot AnchorSideTop.Side = asrCenter Left = 302 Height = 19 Top = 239 Width = 179 Caption = 'Select all categories by default' Checked = True OnChange = cbSelectAllCategoryDefaultChange State = cbChecked TabOrder = 5 end object lblHotKey: TLabel AnchorSideLeft.Control = lblCommandName AnchorSideTop.Control = lbledtFilter AnchorSideTop.Side = asrBottom Left = 312 Height = 15 Top = 34 Width = 41 BorderSpacing.Left = 150 Caption = 'Hotkey:' Font.Color = clRed ParentColor = False ParentFont = False end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmaincommandsdlg.lrj�����������������������������������������������������������0000644�0001750�0000144�00000005013�14743153644�017410� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":53701060,"name":"tfrmmaincommandsdlg.caption","sourcebytes":[83,101,108,101,99,116,32,121,111,117,114,32,105,110,116,101,114,110,97,108,32,99,111,109,109,97,110,100],"value":"Select your internal command"}, {"hash":12678826,"name":"tfrmmaincommandsdlg.lblcategory.caption","sourcebytes":[38,67,97,116,101,103,111,114,105,101,115,58],"value":"&Categories:"}, {"hash":77071178,"name":"tfrmmaincommandsdlg.lblcommandname.caption","sourcebytes":[67,111,109,109,97,110,100,32,38,110,97,109,101,58],"value":"Command &name:"}, {"hash":5178746,"name":"tfrmmaincommandsdlg.lblhint.caption","sourcebytes":[72,105,110,116,58],"value":"Hint:"}, {"hash":218345210,"name":"tfrmmaincommandsdlg.lbledtfilter.editlabel.caption","sourcebytes":[38,70,105,108,116,101,114,58],"value":"&Filter:"}, {"hash":11067,"name":"tfrmmaincommandsdlg.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmmaincommandsdlg.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":87810132,"name":"tfrmmaincommandsdlg.cbcategorysortornot.text","sourcebytes":[76,101,103,97,99,121,32,115,111,114,116,101,100],"value":"Legacy sorted"}, {"hash":87810132,"name":"tfrmmaincommandsdlg.cbcommandssortornot.text","sourcebytes":[76,101,103,97,99,121,32,115,111,114,116,101,100],"value":"Legacy sorted"}, {"hash":196049466,"name":"tfrmmaincommandsdlg.gbselection.caption","sourcebytes":[83,101,108,101,99,116,105,111,110,58],"value":"Selection:"}, {"hash":171329621,"name":"tfrmmaincommandsdlg.lblselectedcommand.caption","sourcebytes":[99,109,95,110,97,109,101],"value":"cm_name"}, {"hash":323668,"name":"tfrmmaincommandsdlg.lblselectedcommandhint.caption","sourcebytes":[72,105,110,116],"value":"Hint"}, {"hash":322608,"name":"tfrmmaincommandsdlg.lblselectedcommandhelp.caption","sourcebytes":[72,101,108,112],"value":"Help"}, {"hash":83276233,"name":"tfrmmaincommandsdlg.lblselectedcommandhotkey.caption","sourcebytes":[72,111,116,107,101,121],"value":"Hotkey"}, {"hash":145482249,"name":"tfrmmaincommandsdlg.lblselectedcommandcategory.caption","sourcebytes":[67,97,116,101,103,111,114,121],"value":"Category"}, {"hash":5485524,"name":"tfrmmaincommandsdlg.cbselectallcategorydefault.caption","sourcebytes":[83,101,108,101,99,116,32,97,108,108,32,99,97,116,101,103,111,114,105,101,115,32,98,121,32,100,101,102,97,117,108,116],"value":"Select all categories by default"}, {"hash":258677898,"name":"tfrmmaincommandsdlg.lblhotkey.caption","sourcebytes":[72,111,116,107,101,121,58],"value":"Hotkey:"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmaincommandsdlg.pas�����������������������������������������������������������0000644�0001750�0000144�00000042576�14743153644�017423� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Internal Main Commands Selection Dialog Window Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) 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 } unit fMainCommandsDlg; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, Buttons, Menus, ExtCtrls, //DC KASComboBox, uFormCommands, types; type { TfrmMainCommandsDlg } TfrmMainCommandsDlg = class(TForm) btnCancel: TBitBtn; btnOK: TBitBtn; cbCategorySortOrNot: TComboBoxAutoWidth; cbCommandsSortOrNot: TComboBoxAutoWidth; cbSelectAllCategoryDefault: TCheckBox; gbSelection: TGroupBox; imgCommandIcon: TImage; lblSelectedCommandCategory: TLabel; lblSelectedCommandHotkey: TLabel; lblHotKey: TLabel; lblSelectedCommandHelp: TLabel; lbledtFilter: TLabeledEdit; lblCategory: TLabel; lblCommandName: TLabel; lblHint: TLabel; lbCategory: TListBox; lbCommands: TListBox; lblSelectedCommand: TLabel; lblSelectedCommandHint: TLabel; pnlImage: TPanel; procedure cbCategorySortOrNotChange(Sender: TObject); procedure cbCommandsSortOrNotChange(Sender: TObject); procedure cbSelectAllCategoryDefaultChange(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure lbCategoryEnter(Sender: TObject); procedure lbCategoryExit(Sender: TObject); procedure lbCategorySelectionChange(Sender: TObject; {%H-}User: boolean); procedure lbCommandsDblClick(Sender: TObject); procedure lbCommandsDrawItem(Control: TWinControl; Index: integer; ARect: TRect; State: TOwnerDrawState); procedure lbCommandsEnter(Sender: TObject); procedure lbCommandsExit(Sender: TObject); procedure lbCommandsKeyPress(Sender: TObject; var Key: char); procedure lbledtFilterChange(Sender: TObject); procedure AttemptToSetupForThisCommand(CommandToShow: string); procedure lbledtFilterEnter(Sender: TObject); procedure lbledtFilterExit(Sender: TObject); procedure lbledtFilterKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure lblPlaceCaptionInClipClick(Sender: TObject); procedure lblSelectedCommandHelpClick(Sender: TObject); procedure lblSelectedCommandHelpMouseEnter(Sender: TObject); procedure lblSelectedCommandHelpMouseLeave(Sender: TObject); private { Private declarations } FFormCommands: IFormCommands; ListCommands: TStringList; OffsetForHotKey: integer; OffsetForHint: integer; lbCommandsItemHeight: Integer; public { Public declarations } procedure LoadCategoryListbox(CategoryToSelectIfAny: string); procedure LoadCommandsListbox(WantedCommandToSelect: string); end; { ShowSplitterFileForm: "TMainCommands.cm_FileSpliter" function from "uMainCommands.pas" is calling this routine.} function ShowMainCommandDlgForm(DefaultCmd: string; var ReturnedCmd: string): boolean; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Clipbrd, LCLType, Graphics, LazUTF8, LCLIntf, Math, //DC DCStrUtils, dmHelpManager, uLng, uPixMapManager, uGlobs, fMain, uDebug, uClipboard; function ShowMainCommandDlgForm(DefaultCmd: string; var ReturnedCmd: string): boolean; var frmMainCommandsDlg: TfrmMainCommandsDlg; begin ReturnedCmd := ''; frmMainCommandsDlg := TfrmMainCommandsDlg.Create(Application); //Did not use the "with..." here to make absolutely sure of what is referenced in the following. try // Show form frmMainCommandsDlg.AttemptToSetupForThisCommand(DefaultCmd); Result := (frmMainCommandsDlg.ShowModal = mrOk) and (frmMainCommandsDlg.lbCommands.ItemIndex <> -1); if Result then begin ReturnedCmd := frmMainCommandsDlg.lbCommands.Items.Strings[frmMainCommandsDlg.lbCommands.ItemIndex]; if pos('|', ReturnedCmd) <> 0 then ReturnedCmd := leftstr(ReturnedCmd, (pos('|', ReturnedCmd) - 1)); end; finally frmMainCommandsDlg.Free; end; end; { TfrmMainCommandsDlg.FormCreate } procedure TfrmMainCommandsDlg.FormCreate(Sender: TObject); begin ParseLineToList(rsCmdKindOfSort, cbCategorySortOrNot.Items); ParseLineToList(rsCmdKindOfSort, cbCommandsSortOrNot.Items); InitPropStorage(Self); // Initialize property storage FFormCommands := frmMain as IFormCommands; ListCommands := TStringList.Create; end; { TfrmMainCommandsDlg.FormDestroy } procedure TfrmMainCommandsDlg.FormDestroy(Sender: TObject); begin ListCommands.Free; end; { TfrmMainCommandsDlg.lbCategoryEnter } procedure TfrmMainCommandsDlg.lbCategoryEnter(Sender: TObject); begin lblCategory.Font.Style := [fsBold]; end; { TfrmMainCommandsDlg.lbCategoryExit } procedure TfrmMainCommandsDlg.lbCategoryExit(Sender: TObject); begin lblCategory.Font.Style := []; end; { TfrmMainCommandsDlg.lbCategorySelectionChange } procedure TfrmMainCommandsDlg.lbCategorySelectionChange(Sender: TObject; User: boolean); begin LoadCommandsListbox(''); lbledtFilter.OnChange := nil; lbledtFilter.Text := ''; lbledtFilter.OnChange := @lbledtFilterChange; end; { TfrmMainCommandsDlg.lbCommandsDblClick } procedure TfrmMainCommandsDlg.lbCommandsDblClick(Sender: TObject); begin ModalResult := mrOk; //No need to call "CLOSE", setting the "ModalResult" close the window there. end; { TfrmMainCommandsDlg.lbCommandsDrawItem } procedure TfrmMainCommandsDlg.lbCommandsDrawItem(Control: TWinControl; Index: integer; ARect: TRect; State: TOwnerDrawState); var sCommand: string = ''; sHint: string = ''; sHotKey: string = ''; sCategory: string = ''; FlagCategoryTitle: boolean = False; Bitmap: TBitmap = nil; begin lbCommandsItemHeight := ARect.Height; with Control as TListbox do begin FFormCommands.ExtractCommandFields(Items.Strings[Index], sCategory, sCommand, sHint, sHotKey, FlagCategoryTitle); if FlagCategoryTitle then begin Canvas.Brush.Color := clBtnFace; Canvas.FillRect(ARect); Canvas.Font.Style := [fsItalic, fsBold]; if (odSelected in State) then Canvas.Font.Color := clBlack; Canvas.TextOut(ARect.Left, ARect.Top, ' ' + rsSimpleWordCategory + ': ' + sCommand); //A little offset to the right, it's prettier. end else begin Canvas.FillRect(ARect); Canvas.TextOut(ARect.Left, ARect.Top, sCommand); Canvas.TextOut(ARect.Left + OffsetForHint, ARect.Top, sHint); if not (odSelected in State) then Canvas.Font.Color := clRed; Canvas.TextOut(ARect.Left + OffsetForHotKey, ARect.Top, sHotKey); end; if odSelected in State then begin if not FlagCategoryTitle then begin lblSelectedCommand.Caption := sCommand; if sHotKey <> '' then lblSelectedCommandHotkey.Caption := '(' + sHotKey + ')' else lblSelectedCommandHotkey.Caption := ''; if sCategory <> '' then lblSelectedCommandCategory.Caption := rsSimpleWordCategory + ': ' + sCategory + ' -' else lblSelectedCommandCategory.Caption := ''; lblSelectedCommandHint.Caption := sHint; try Bitmap := PixMapManager.LoadBitmapEnhanced(LowerCase(sCommand), 32, True, clDefault, nil); imgCommandIcon.Picture.Bitmap.Assign(Bitmap); finally Bitmap.Free; end; end else begin lblSelectedCommand.Caption := ''; lblSelectedCommandHotkey.Caption := ''; lblSelectedCommandHint.Caption := ''; lblSelectedCommandCategory.Caption := ''; imgCommandIcon.Picture.Bitmap.Clear; end; end; end; end; { TfrmMainCommandsDlg.lbCommandsEnter } procedure TfrmMainCommandsDlg.lbCommandsEnter(Sender: TObject); begin lblCommandName.Font.Style := [fsBold]; end; { TfrmMainCommandsDlg.lbCommandsExit } procedure TfrmMainCommandsDlg.lbCommandsExit(Sender: TObject); begin lblCommandName.Font.Style := []; end; procedure TfrmMainCommandsDlg.lbCommandsKeyPress(Sender: TObject; var Key: char); begin case Key of #$0D: begin Key := #$00; ModalResult := mrOk; end; #$1B: begin Key := #$00; ModalResult := mrCancel; end; else inherited; end; end; { TfrmMainCommandsDlg.lbledtFilterChange } procedure TfrmMainCommandsDlg.lbledtFilterChange(Sender: TObject); var IndexItem: longint; LastSelectedText: string; begin lblSelectedCommand.Caption := ''; lblSelectedCommandHotkey.Caption := ''; lblSelectedCommandHint.Caption := ''; lblSelectedCommandCategory.Caption := ''; imgCommandIcon.Picture.Bitmap.Clear; if lbCommands.ItemIndex <> -1 then LastSelectedText := lbCommands.Items.Strings[lbCommands.ItemIndex] else LastSelectedText := ''; lbCommands.Items.Clear; for IndexItem := 0 to pred(ListCommands.Count) do begin if (lbledtFilter.Text = '') or (Pos(UTF8LowerCase(lbledtFilter.Text), UTF8LowerCase(ListCommands.Strings[IndexItem])) <> 0) then lbCommands.Items.Add(ListCommands.Strings[IndexItem]); end; if LastSelectedText <> '' then lbCommands.ItemIndex := lbCommands.Items.IndexOf(LastSelectedText); if (lbCommands.ItemIndex = -1) and (lbCommands.Items.Count > 0) then lbCommands.ItemIndex := 0; end; { procedure TfrmMainCommandsDlg.cbCategorySortOrNotChange } procedure TfrmMainCommandsDlg.cbCategorySortOrNotChange(Sender: TObject); begin LoadCategoryListbox(''); lbledtFilter.OnChange := nil; lbledtFilter.Text := ''; lbledtFilter.OnChange := @lbledtFilterChange; end; { TfrmMainCommandsDlg.cbCommandsSortOrNotChange } procedure TfrmMainCommandsDlg.cbCommandsSortOrNotChange(Sender: TObject); begin LoadCommandsListbox(''); lbledtFilter.OnChange := nil; lbledtFilter.Text := ''; lbledtFilter.OnChange := @lbledtFilterChange; end; { TfrmMainCommandsDlg.cbSelectAllCategoryDefaultChange } procedure TfrmMainCommandsDlg.cbSelectAllCategoryDefaultChange(Sender: TObject); begin if cbSelectAllCategoryDefault.Checked then if (lbCategory.ItemIndex <> 0) and (lbCategory.Count > 0) then lbCategory.ItemIndex := 0; end; procedure TfrmMainCommandsDlg.FormActivate(Sender: TObject); begin lbCommands.MakeCurrentVisible; //Looks like it's not necessary with Windows, but with Linux it is. lbCategory.MakeCurrentVisible; end; { TfrmMainCommandsDlg.LoadCategoryListbox } procedure TfrmMainCommandsDlg.LoadCategoryListbox(CategoryToSelectIfAny: string); var ListCategory: TStringList; LastCategorySelected: string; begin ListCategory := TStringList.Create; try if lbCategory.ItemIndex <> -1 then LastCategorySelected := lbCategory.Items.Strings[lbCategory.ItemIndex] else LastCategorySelected := ''; FFormCommands.GetCommandCategoriesList(ListCategory, TCommandCategorySortOrder(cbCategorySortOrNot.ItemIndex)); lbCategory.Items.Assign(ListCategory); lbCategory.ItemIndex := lbCategory.Items.IndexOf(CategoryToSelectIfAny); if lbCategory.ItemIndex = -1 then begin if LastCategorySelected <> '' then lbCategory.ItemIndex := lbCategory.Items.IndexOf(LastCategorySelected); if (lbCategory.ItemIndex = -1) and (lbCategory.Items.Count > 0) then lbCategory.ItemIndex := 0; end; finally ListCategory.Free; end; end; { TfrmMainCommandsDlg.LoadCommandsListbox } procedure TfrmMainCommandsDlg.LoadCommandsListbox(WantedCommandToSelect: string); var LastSelectedCommand: string; SearchingIndex, WantedCommandIndex, LastSelectedIndex: longint; sCommand: string = ''; sHint: string = ''; sHotKey: string = ''; sCategory: string; FlagCategoryTitle: boolean = False; LargestCommandName, LargestHotKeyName: longint; begin LastSelectedCommand := ''; if lbCommands.ItemIndex <> -1 then begin FFormCommands.ExtractCommandFields(ListCommands.Strings[lbCommands.ItemIndex], sCategory, sCommand, sHint, sHotKey, FlagCategoryTitle); if not FlagCategoryTitle then LastSelectedCommand := sCommand; end; FFormCommands.GetCommandsListForACommandCategory(ListCommands, lbCategory.Items.Strings[lbCategory.ItemIndex], TCommandSortOrder(cbCommandsSortOrNot.ItemIndex)); LargestCommandName := lblCommandName.Canvas.TextWidth(lblCommandName.Caption); LargestHotKeyName := lblCommandName.Canvas.TextWidth(lblHotKey.Caption); //This way, if the word "hotkey" once translated is longer than a hotkey, label will not be overwritten. WantedCommandIndex := -1; LastSelectedIndex := -1; SearchingIndex := 0; while (SearchingIndex < ListCommands.Count) do begin FFormCommands.ExtractCommandFields(ListCommands.Strings[SearchingIndex], sCategory, sCommand, sHint, sHotKey, FlagCategoryTitle); if not FlagCategoryTitle then begin if lblCommandName.Canvas.TextWidth(sCommand) > LargestCommandName then LargestCommandName := lblCommandName.Canvas.TextWidth(sCommand); if lblCommandName.Canvas.TextWidth(sHotKey) > LargestHotKeyName then LargestHotKeyName := lblCommandName.Canvas.TextWidth(sHotKey); if (WantedCommandToSelect <> '') and (WantedCommandToSelect = sCommand) then WantedCommandIndex := SearchingIndex; if (LastSelectedCommand <> '') and (LastSelectedCommand = sCommand) then LastSelectedIndex := SearchingIndex; end; Inc(SearchingIndex); end; OffsetForHotKey := LargestCommandName + 10; lblHotKey.BorderSpacing.Left := OffsetForHotKey + 1; OffsetForHint := LargestCommandName + 10 + LargestHotKeyName + 10; lblHint.BorderSpacing.Left := OffsetForHint + 1; lbCommands.Items.Assign(ListCommands); if WantedCommandIndex <> -1 then lbCommands.ItemIndex := WantedCommandIndex else if LastSelectedIndex <> -1 then lbCommands.ItemIndex := LastSelectedIndex else if lbCommands.Items.Count > 0 then lbCommands.ItemIndex := 0; end; { TfrmMainCommandsDlg.AttemptToSetupForThisCommand } procedure TfrmMainCommandsDlg.AttemptToSetupForThisCommand(CommandToShow: string); var CommandRec: PCommandRec; begin CommandRec := frmMain.Commands.Commands.GetCommandRec(CommandToShow); if Assigned(CommandRec) then begin if Assigned(CommandRec^.Action) and CommandRec^.Action.Enabled then begin if cbSelectAllCategoryDefault.Checked then LoadCategoryListbox('') else LoadCategoryListbox(CommandRec^.Action.Category); LoadCommandsListbox(CommandToShow); end; end; end; { TfrmMainCommandsDlg.lbledtFilterEnter } procedure TfrmMainCommandsDlg.lbledtFilterEnter(Sender: TObject); begin lbledtFilter.EditLabel.Font.Style := [fsBold]; end; { TfrmMainCommandsDlg.lbledtFilterExit } procedure TfrmMainCommandsDlg.lbledtFilterExit(Sender: TObject); begin lbledtFilter.EditLabel.Font.Style := []; end; procedure TfrmMainCommandsDlg.lbledtFilterKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var NewIndex: Integer; begin case Key of VK_UP: NewIndex := lbCommands.ItemIndex - 1; VK_DOWN: NewIndex := lbCommands.ItemIndex + 1; VK_PRIOR: NewIndex := lbCommands.ItemIndex - (lbCommands.ClientHeight div lbCommandsItemHeight) + 1; VK_NEXT: NewIndex := lbCommands.ItemIndex + (lbCommands.ClientHeight div lbCommandsItemHeight) - 1; VK_HOME: if (ssCtrl in Shift) then NewIndex := 0 else Exit; VK_END: if (ssCtrl in Shift) then NewIndex := lbCommands.Items.Count - 1 else Exit; else Exit; end; Key := 0; if lbCommands.Items.Count > 0 then lbCommands.ItemIndex := EnsureRange(NewIndex, 0, lbCommands.Items.Count - 1); end; { TfrmMainCommandsDlg.lblPlaceCaptionInClipClick } procedure TfrmMainCommandsDlg.lblPlaceCaptionInClipClick(Sender: TObject); begin with Sender as TLabel do ClipboardSetText(Caption); ShowMessage(Format(rsMsgThisIsNowInClipboard, [Clipboard.AsText])); end; { TfrmMainCommandsDlg.lblSelectedCommandHelpClick } procedure TfrmMainCommandsDlg.lblSelectedCommandHelpClick(Sender: TObject); begin ShowHelpForKeywordWithAnchor('/cmds.html#' + lblSelectedCommand.Caption); end; { TfrmMainCommandsDlg.lblSelectedCommandHelpClick } procedure TfrmMainCommandsDlg.lblSelectedCommandHelpMouseEnter(Sender: TObject); begin lblSelectedCommandHelp.Font.Color := clRed; end; { TfrmMainCommandsDlg.lblSelectedCommandHelpMouseLeave } procedure TfrmMainCommandsDlg.lblSelectedCommandHelpMouseLeave(Sender: TObject); begin lblSelectedCommandHelp.Font.Color := clDefault; end; end. ����������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmaskinputdlg.lfm��������������������������������������������������������������0000644�0001750�0000144�00000013756�14743153644�016761� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMaskInputDlg: TfrmMaskInputDlg Left = 458 Height = 300 Top = 396 Width = 331 BorderIcons = [biSystemMenu] ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ClientHeight = 300 ClientWidth = 331 OnCreate = FormCreate Position = poScreenCenter SessionProperties = 'Height;Width' LCLVersion = '1.6.0.4' object lblPrompt: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 10 Width = 311 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Right = 10 Caption = 'Input Mask:' ParentColor = False WordWrap = True end object cmbMask: TComboBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblPrompt AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 25 Width = 311 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Right = 10 DropDownCount = 10 ItemHeight = 15 TabOrder = 0 end object chkCaseSensitive: TCheckBox AnchorSideLeft.Control = cmbMask AnchorSideTop.Control = cmbMask AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 50 Width = 93 BorderSpacing.Top = 2 Caption = 'Case sensitive' TabOrder = 1 end object chkIgnoreAccentsAndLigatures: TCheckBox AnchorSideLeft.Control = cmbMask AnchorSideTop.Control = chkCaseSensitive AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 69 Width = 168 Caption = 'Ignore accents and ligatures' TabOrder = 2 end object lblSearchTemplate: TLabel AnchorSideLeft.Control = cmbMask AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 125 Width = 185 BorderSpacing.Top = 10 Caption = 'O&r select predefined selection type:' FocusControl = lbxSearchTemplate ParentColor = False WordWrap = True end object lbxSearchTemplate: TListBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblSearchTemplate AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnOK Left = 10 Height = 116 Top = 140 Width = 311 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 10 BorderSpacing.Right = 10 ItemHeight = 0 OnClick = lbxSearchTemplateClick OnDblClick = lbxSearchTemplateDblClick ScrollWidth = 317 Sorted = True TabOrder = 6 end object btnDefineTemplate: TBitBtn AnchorSideTop.Control = btnOK AnchorSideRight.Control = btnOK AnchorSideBottom.Control = btnOK AnchorSideBottom.Side = asrBottom Left = 9 Height = 30 Top = 262 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 2 Caption = '&Define...' Constraints.MinWidth = 100 OnClick = btnDefineTemplateClick TabOrder = 7 end object btnOK: TBitBtn AnchorSideLeft.Side = asrBottom AnchorSideRight.Control = btnCancel AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 115 Height = 30 Top = 262 Width = 100 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 2 Caption = '&OK' Constraints.MinWidth = 100 Default = True Kind = bkOK ModalResult = 1 TabOrder = 8 end object btnCancel: TBitBtn AnchorSideRight.Control = lbxSearchTemplate AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 221 Height = 30 Top = 262 Width = 100 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.Top = 6 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Constraints.MinWidth = 100 Kind = bkCancel ModalResult = 2 TabOrder = 9 end object lblAttributes: TLabel AnchorSideLeft.Control = cmbMask AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrCenter Left = 13 Height = 15 Top = 96 Width = 55 BorderSpacing.Left = 3 BorderSpacing.Top = 8 Caption = 'Attri&butes:' FocusControl = edtAttrib ParentColor = False end object edtAttrib: TEdit AnchorSideLeft.Control = lblAttributes AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = chkIgnoreAccentsAndLigatures AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnAddAttribute Left = 71 Height = 23 Top = 92 Width = 143 HelpType = htKeyword HelpKeyword = '/findfiles.html#attributes' Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 3 BorderSpacing.Top = 4 BorderSpacing.Right = 3 ParentShowHint = False ShowHint = True TabOrder = 3 end object btnAddAttribute: TButton AnchorSideLeft.Control = edtAttrib AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAttrsHelp Left = 217 Height = 26 Top = 90 Width = 48 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Around = 3 Caption = '&Add' Constraints.MinHeight = 26 OnClick = btnAddAttributeClick TabOrder = 4 end object btnAttrsHelp: TButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtAttrib AnchorSideTop.Side = asrCenter AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 268 Height = 27 Top = 90 Width = 53 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 1 Caption = '&Help' Constraints.MinHeight = 26 OnClick = btnAttrsHelpClick TabOrder = 5 end end ������������������doublecmd-1.1.22/src/fmaskinputdlg.lrj��������������������������������������������������������������0000644�0001750�0000144�00000003077�14743153644�016765� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":103013930,"name":"tfrmmaskinputdlg.lblprompt.caption","sourcebytes":[73,110,112,117,116,32,77,97,115,107,58],"value":"Input Mask:"}, {"hash":219672053,"name":"tfrmmaskinputdlg.chkcasesensitive.caption","sourcebytes":[67,97,115,101,32,115,101,110,115,105,116,105,118,101],"value":"Case sensitive"}, {"hash":76256915,"name":"tfrmmaskinputdlg.chkignoreaccentsandligatures.caption","sourcebytes":[73,103,110,111,114,101,32,97,99,99,101,110,116,115,32,97,110,100,32,108,105,103,97,116,117,114,101,115],"value":"Ignore accents and ligatures"}, {"hash":228881322,"name":"tfrmmaskinputdlg.lblsearchtemplate.caption","sourcebytes":[79,38,114,32,115,101,108,101,99,116,32,112,114,101,100,101,102,105,110,101,100,32,115,101,108,101,99,116,105,111,110,32,116,121,112,101,58],"value":"O&r select predefined selection type:"}, {"hash":218557374,"name":"tfrmmaskinputdlg.btndefinetemplate.caption","sourcebytes":[38,68,101,102,105,110,101,46,46,46],"value":"&Define..."}, {"hash":11067,"name":"tfrmmaskinputdlg.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmmaskinputdlg.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":135730394,"name":"tfrmmaskinputdlg.lblattributes.caption","sourcebytes":[65,116,116,114,105,38,98,117,116,101,115,58],"value":"Attri&butes:"}, {"hash":173988,"name":"tfrmmaskinputdlg.btnaddattribute.caption","sourcebytes":[38,65,100,100],"value":"&Add"}, {"hash":2812976,"name":"tfrmmaskinputdlg.btnattrshelp.caption","sourcebytes":[38,72,101,108,112],"value":"&Help"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmaskinputdlg.pas��������������������������������������������������������������0000644�0001750�0000144�00000015770�14743153644�016764� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File mask input dialog Copyright (C) 2010-2016 Alexander Koblov (alexx2000@mail.ru) 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 } unit fMaskInputDlg; {$mode objfpc}{$H+} interface uses Classes, Forms, Controls, StdCtrls, Buttons; type { TMaskInputDlgStyle } TMaskInputDlgStyle = (midsLegacy, midsFull); { TfrmMaskInputDlg } TfrmMaskInputDlg = class(TForm) btnDefineTemplate: TBitBtn; chkIgnoreAccentsAndLigatures: TCheckBox; chkCaseSensitive: TCheckBox; lblPrompt: TLabel; lblSearchTemplate: TLabel; cmbMask: TComboBox; btnOK: TBitBtn; btnCancel: TBitBtn; lbxSearchTemplate: TListBox; lblAttributes: TLabel; edtAttrib: TEdit; btnAddAttribute: TButton; btnAttrsHelp: TButton; procedure btnDefineTemplateClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure lbxSearchTemplateClick(Sender: TObject); procedure lbxSearchTemplateDblClick(Sender: TObject); procedure btnAddAttributeClick(Sender: TObject); procedure btnAttrsHelpClick(Sender: TObject); private { private declarations } procedure OnAddAttribute(Sender: TObject); public { public declarations } end; function ShowMaskInputDlg(const sCaption, sPrompt: string; slValueList: TStringList; var sValue: string): boolean; function ShowExtendedMaskInputDlg(const sCaption, sPrompt: string; slValueList: TStringList; var sValue: string; AMaskInputDlgStyle: TMaskInputDlgStyle; var bCaseSensitive: boolean; var bIgnoreAccents: boolean; var sAttribute:string): boolean; implementation {$R *.lfm} uses HelpIntfs, fAttributesEdit, fFindDlg, uGlobs, uSearchTemplate; { ShowMaskInputDlg } function ShowMaskInputDlg(const sCaption, sPrompt: string; slValueList: TStringList; var sValue: string): boolean; var dummybCaseSensitive: boolean = False; dummybIgnoreAccents: boolean = False; dummysAttribute: string = ''; begin Result := ShowExtendedMaskInputDlg(sCaption, sPrompt, slValueList, sValue, midsLegacy, dummybCaseSensitive, dummybIgnoreAccents, dummysAttribute); end; { ShowExtendedMaskInputDlg } function ShowExtendedMaskInputDlg(const sCaption, sPrompt: string; slValueList: TStringList; var sValue: string; AMaskInputDlgStyle: TMaskInputDlgStyle; var bCaseSensitive: boolean; var bIgnoreAccents: boolean; var sAttribute:string): boolean; var Index, iCurrentPos: integer; begin Result := False; with TfrmMaskInputDlg.Create(Application) do try Caption := sCaption; lblPrompt.Caption := sPrompt; cmbMask.Items.Assign(slValueList); cmbMask.Text := sValue; edtAttrib.Text := sAttribute; case AMaskInputDlgStyle of midsFull: begin chkCaseSensitive.Checked := bCaseSensitive; chkIgnoreAccentsAndLigatures.Checked := bIgnoreAccents; end; midsLegacy: begin chkIgnoreAccentsAndLigatures.Visible := False; chkCaseSensitive.Visible := False; end; end; // Don't show the attribute filter if we're in legacy request mode OR if user request to don't use it. if (AMaskInputDlgStyle=midsLegacy) OR (not gMarkShowWantedAttribute) then begin lblAttributes.Visible := False; btnAddAttribute.Visible := False; btnAttrsHelp.Visible := False; edtAttrib.Visible := False; end; if IsMaskSearchTemplate(sValue) then begin Index := lbxSearchTemplate.Items.IndexOf(PAnsiChar(sValue) + 1); if Index >= 0 then lbxSearchTemplate.ItemIndex := Index; end; if ShowModal = mrOk then begin if not IsMaskSearchTemplate(cmbMask.Text) then begin iCurrentPos := slValueList.IndexOf(cmbMask.Text); if iCurrentPos <> -1 then slValueList.Delete(iCurrentPos); if slValueList.Count = 0 then slValueList.Add(cmbMask.Text) else slValueList.Insert(0, cmbMask.Text); end; sValue := cmbMask.Text; bCaseSensitive := chkCaseSensitive.Checked; bIgnoreAccents := chkIgnoreAccentsAndLigatures.Checked; sAttribute := edtAttrib.Text; Result := True; end; finally Free; end; end; { TfrmMaskInputDlg } procedure TfrmMaskInputDlg.lbxSearchTemplateClick(Sender: TObject); begin if lbxSearchTemplate.ItemIndex < 0 then Exit; cmbMask.Text := cTemplateSign + lbxSearchTemplate.Items[lbxSearchTemplate.ItemIndex]; end; procedure TfrmMaskInputDlg.lbxSearchTemplateDblClick(Sender: TObject); begin if lbxSearchTemplate.ItemIndex < 0 then Exit; cmbMask.Text := cTemplateSign + lbxSearchTemplate.Items[lbxSearchTemplate.ItemIndex]; Close; ModalResult := mrOk; end; procedure TfrmMaskInputDlg.FormCreate(Sender: TObject); var I: integer; begin InitPropStorage(Self); for I := 0 to gSearchTemplateList.Count - 1 do lbxSearchTemplate.Items.Add(gSearchTemplateList.Templates[I].TemplateName); end; procedure TfrmMaskInputDlg.btnDefineTemplateClick(Sender: TObject); var Index: Integer; sTemplateName: String; begin if lbxSearchTemplate.ItemIndex >= 0 then sTemplateName := lbxSearchTemplate.Items[lbxSearchTemplate.ItemIndex]; if ShowDefineTemplateDlg(sTemplateName) then begin Index:= lbxSearchTemplate.Items.IndexOf(sTemplateName); if Index >= 0 then lbxSearchTemplate.ItemIndex := Index else begin lbxSearchTemplate.ItemIndex := lbxSearchTemplate.Items.Add(sTemplateName); end; cmbMask.Text := cTemplateSign + sTemplateName; end; end; procedure TfrmMaskInputDlg.btnAddAttributeClick(Sender: TObject); var FFrmAttributesEdit: TfrmAttributesEdit; begin FFrmAttributesEdit := TfrmAttributesEdit.Create(Self); try FFrmAttributesEdit.OnOk := @OnAddAttribute; FFrmAttributesEdit.Reset; FFrmAttributesEdit.ShowModal; finally FFrmAttributesEdit.Free; end; end; procedure TfrmMaskInputDlg.btnAttrsHelpClick(Sender: TObject); begin ShowHelpOrErrorForKeyword('', edtAttrib.HelpKeyword); end; procedure TfrmMaskInputDlg.OnAddAttribute(Sender: TObject); var sAttr: String; begin sAttr := edtAttrib.Text; if edtAttrib.SelStart > 0 then Insert((Sender as TfrmAttributesEdit).AttrsAsText, sAttr, edtAttrib.SelStart + 1) // Insert at caret position. else sAttr := sAttr + (Sender as TfrmAttributesEdit).AttrsAsText; edtAttrib.Text := sAttr; end; end. ��������doublecmd-1.1.22/src/fmkdir.lfm���������������������������������������������������������������������0000644�0001750�0000144�00000012717�14743153644�015361� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMkDir: TfrmMkDir Left = 366 Height = 125 Top = 429 Width = 350 ActiveControl = cbMkDir AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Create new directory' ClientHeight = 125 ClientWidth = 350 Constraints.MinHeight = 50 Constraints.MinWidth = 350 KeyPreview = True OnCreate = FormCreate Position = poOwnerFormCenter SessionProperties = 'cbMkDir.AutoComplete;btnAutoComplete.Down' LCLVersion = '3.5.0.0' object lblMakeDir: TLabel Left = 6 Height = 15 Top = 6 Width = 338 Align = alTop BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = '&Input new directory name:' FocusControl = cbMkDir ParentColor = False end object pnlMkDir: TPanel Left = 6 Height = 23 Top = 28 Width = 338 Align = alTop AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 3 BevelOuter = bvNone ClientHeight = 23 ClientWidth = 338 TabOrder = 0 object cbMkDir: TComboBox AnchorSideLeft.Control = pnlMkDir AnchorSideTop.Control = pnlMkDir AnchorSideRight.Control = btnAutoComplete Left = 0 Height = 23 Top = 0 Width = 313 Anchors = [akTop, akLeft, akRight] AutoCompleteText = [cbactEndOfLineComplete, cbactRetainPrefixCase, cbactSearchAscending] BorderSpacing.Right = 2 DropDownCount = 16 ItemHeight = 15 TabOrder = 0 OnChange = cbMkDirChange OnKeyUp = cbMkDirKeyUp end object btnAutoComplete: TSpeedButton AnchorSideTop.Control = cbMkDir AnchorSideRight.Control = pnlMkDir AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbMkDir AnchorSideBottom.Side = asrBottom Left = 315 Height = 23 Top = 0 Width = 23 AllowAllUp = True Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000CCFF0000CC550000CCFF00000000000000000000 0000DD9F64FFD8965CFFD39054FFCD884BFFC98043FFC3783CFFBE7133FFBA6B 2BFFB56324FF00000000000000000000CCFF0000000000000000000000000000 0000DD9F64FFD8965CFFD39054FFCD884BFFC98043FFC3783CFFBE7133FFBA6B 2BFFB56324FF00000000000000000000CCFF0000000000000000000000000000 0000DD9F64FFD8965CFFD39054FFCD884BFFC98043FFC3783CFFBE7133FFBA6B 2BFFB56324FF00000000000000000000CCFF0000000000000000000000000000 0000DD9F64FFD8965CFFD39054FFCD884BFFC98043FFC3783CFFBE7133FFBA6B 2BFFB56324FF00000000000000000000CCFF0000000000000000000000000000 0000DD9F64FFD8965CFFD39054FFCD884BFFC98043FFC3783CFFBE7133FFBA6B 2BFFB56324FF00000000000000000000CCFF0000000000000000000000000000 0000DD9F64FFD8965CFFD39054FFCD884BFFC98043FFC3783CFFBE7133FFBA6B 2BFFB56324FF00000000000000000000CCFF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000CCFF0000CC550000CCFF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } GroupIndex = 1 OnClick = btnAutoCompleteClick end end object cbExtended: TCheckBox Left = 6 Height = 18 Top = 54 Width = 338 Align = alTop Anchors = [akLeft] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = '&Extended syntax' TabOrder = 1 OnChange = cbExtendedChange end object lblExample: TLabel Left = 6 Height = 1 Top = 78 Width = 338 Align = alTop BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 end object ButtonPanel: TButtonPanel Left = 6 Height = 27 Top = 91 Width = 338 Align = alTop BorderSpacing.Top = 6 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True ButtonOrder = boCloseOKCancel TabOrder = 2 ShowButtons = [pbOK, pbCancel] ShowBevel = False end end �������������������������������������������������doublecmd-1.1.22/src/fmkdir.lrj���������������������������������������������������������������������0000644�0001750�0000144�00000001070�14743153644�015360� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":80444489,"name":"tfrmmkdir.caption","sourcebytes":[67,114,101,97,116,101,32,110,101,119,32,100,105,114,101,99,116,111,114,121],"value":"Create new directory"}, {"hash":122714874,"name":"tfrmmkdir.lblmakedir.caption","sourcebytes":[38,73,110,112,117,116,32,110,101,119,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,58],"value":"&Input new directory name:"}, {"hash":225074456,"name":"tfrmmkdir.cbextended.caption","sourcebytes":[38,69,120,116,101,110,100,101,100,32,115,121,110,116,97,120],"value":"&Extended syntax"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmkdir.pas���������������������������������������������������������������������0000644�0001750�0000144�00000007000�14743153644�015353� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fMkDir; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, ExtCtrls, ButtonPanel; type { TfrmMkDir } TfrmMkDir = class(TForm) pnlMkDir: TPanel; ButtonPanel: TButtonPanel; cbExtended: TCheckBox; cbMkDir: TComboBox; lblExample: TLabel; lblMakeDir: TLabel; btnAutoComplete: TSpeedButton; procedure cbExtendedChange(Sender: TObject); procedure cbMkDirChange(Sender: TObject); procedure cbMkDirKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure btnAutoCompleteClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure RefreshExample; public end; function ShowMkDir(TheOwner: TComponent; var sPath: String): Boolean; implementation {$R *.lfm} uses DCStrUtils, uGlobs; function sReplace(sMask: string): string; var iStart, iEnd: integer; begin Result := ''; while Length(sMask) > 0 do begin iStart := Pos('[', sMask); if iStart > 0 then begin iEnd := Pos(']', sMask); if iEnd > iStart then begin Result := Result + Copy(sMask, 1, iStart - 1) + FormatDateTime(Copy(sMask, iStart + 1, iEnd - iStart - 1), Now); Delete(sMask, 1, iEnd); end else Break; end else Break; end; Result := Result + sMask; end; procedure TfrmMkDir.RefreshExample; var sPath: String; begin if not cbExtended.Checked then lblExample.Caption:= ' ' else begin sPath:= TrimPath(cbMkDir.Text); if StrBegins(sPath, '<') then lblExample.Caption:= sReplace(Copy(sPath, 2, MaxInt)) else lblExample.Caption:= ' ' end; end; procedure TfrmMkDir.cbMkDirKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin RefreshExample; end; procedure TfrmMkDir.btnAutoCompleteClick(Sender: TObject); begin cbMkDir.AutoComplete:= btnAutoComplete.Down; end; procedure TfrmMkDir.FormCreate(Sender: TObject); begin InitPropStorage(Self).IniSection:= ClassName; end; procedure TfrmMkDir.cbExtendedChange(Sender: TObject); begin RefreshExample; end; procedure TfrmMkDir.cbMkDirChange(Sender: TObject); var Index: Integer; begin Index:= cbMkDir.ItemIndex; if (Index >= 0) then begin cbExtended.Checked:= Boolean(UIntPtr(cbMkDir.Items.Objects[Index])); end; end; function ShowMkDir(TheOwner: TComponent; var sPath: String): Boolean; const MAX_LINES = 20; var Index: Integer; Syntax: TObject; begin with TfrmMkDir.Create(TheOwner) do try ActiveControl := cbMkDir; cbMkDir.Items.Assign(glsCreateDirectoriesHistory); if (sPath <> '..') then cbMkDir.Text := sPath else begin cbMkDir.Text := ''; end; RefreshExample; cbMkDir.SelectAll; Result := (ShowModal = mrOK); if Result then begin sPath := TrimPath(cbMkDir.Text); Syntax := TObject(UIntPtr(cbExtended.Checked)); glsCreateDirectoriesHistory.CaseSensitive := FileNameCaseSensitive; Index := glsCreateDirectoriesHistory.IndexOf(sPath); if (Index = -1) then glsCreateDirectoriesHistory.InsertObject(0, sPath, Syntax) else begin glsCreateDirectoriesHistory.Move(Index, 0); glsCreateDirectoriesHistory.Objects[0]:= Syntax; end; if (glsCreateDirectoriesHistory.Count > MAX_LINES) then glsCreateDirectoriesHistory.Delete(glsCreateDirectoriesHistory.Count - 1); if cbExtended.Checked and StrBegins(sPath, '<') then begin sPath := lblExample.Caption; end; end; finally Free; end; end; end. doublecmd-1.1.22/src/fmodview.lfm�������������������������������������������������������������������0000644�0001750�0000144�00000033141�14743153644�015717� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmModView: TfrmModView Left = 395 Height = 319 Top = 104 Width = 488 AutoSize = True BorderIcons = [biSystemMenu] Caption = 'New Size' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ClientHeight = 319 ClientWidth = 488 OnClose = FormClose OnCreate = FormCreate OnKeyPress = FormKeyPress OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '2.2.6.0' object bplButtons: TButtonPanel Left = 10 Height = 34 Top = 279 Width = 468 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True OKButton.OnClick = btnOkClick HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True CancelButton.OnClick = btnCancelClick TabOrder = 0 ShowButtons = [pbOK, pbCancel] end object pnlMain: TPanel Left = 10 Height = 267 Top = 6 Width = 468 Align = alClient AutoSize = True BevelOuter = bvNone ClientHeight = 267 ClientWidth = 468 TabOrder = 1 object pnlQuality: TPanel AnchorSideRight.Control = pnlSize AnchorSideRight.Side = asrBottom Left = 0 Height = 273 Top = 0 Width = 468 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 273 ClientWidth = 468 TabOrder = 2 object tbQuality: TTrackBar AnchorSideTop.Control = lblQuality AnchorSideTop.Side = asrBottom Left = 0 Height = 22 Top = 71 Width = 140 Max = 100 Min = 1 OnChange = tbQualityChange Position = 80 BorderSpacing.Top = 12 TabOrder = 0 end object lblQuality: TLabel Left = 32 Height = 15 Top = 47 Width = 141 Caption = 'Quality of compress to Jpg' Enabled = False ParentColor = False end object teQuality: TSpinEdit AnchorSideTop.Control = tbQuality AnchorSideTop.Side = asrCenter Left = 144 Height = 36 Top = 38 Width = 75 MaxValue = 100 MinValue = 1 OnChange = teQualityChange TabOrder = 1 Value = 1 end end object pnlCopyMoveFile: TPanel AnchorSideRight.Side = asrBottom Left = 0 Height = 273 Top = 0 Width = 468 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 273 ClientWidth = 468 Constraints.MinWidth = 300 TabOrder = 0 object tePath1: TEdit AnchorSideLeft.Control = rbPath1 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlCopyMoveFile AnchorSideRight.Control = btnPath1 Left = 38 Height = 23 Top = 5 Width = 398 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 5 BorderSpacing.Right = 6 TabOrder = 0 end object tePath2: TEdit AnchorSideLeft.Control = tePath1 AnchorSideTop.Control = tePath1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tePath1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 38 Height = 23 Top = 34 Width = 398 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 1 end object tePath3: TEdit AnchorSideLeft.Control = tePath1 AnchorSideTop.Control = tePath2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tePath1 AnchorSideRight.Side = asrBottom Left = 38 Height = 23 Top = 63 Width = 398 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 2 end object btnPath1: TSpeedButton AnchorSideTop.Control = tePath1 AnchorSideRight.Control = pnlCopyMoveFile AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = tePath1 AnchorSideBottom.Side = asrBottom Left = 442 Height = 23 Top = 5 Width = 21 Anchors = [akTop, akRight, akBottom] BorderSpacing.Right = 5 Caption = '...' OnClick = btnPathClick end object tePath4: TEdit AnchorSideLeft.Control = tePath1 AnchorSideTop.Control = tePath3 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tePath1 AnchorSideRight.Side = asrBottom Left = 38 Height = 23 Top = 92 Width = 398 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 TabOrder = 3 end object tePath5: TEdit AnchorSideLeft.Control = tePath1 AnchorSideTop.Control = tePath4 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tePath1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 38 Height = 23 Top = 121 Width = 398 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Bottom = 10 TabOrder = 4 end object rbPath1: TRadioButton AnchorSideTop.Control = tePath1 AnchorSideBottom.Control = tePath1 AnchorSideBottom.Side = asrBottom Left = 18 Height = 23 Top = 5 Width = 20 Anchors = [akTop, akLeft, akBottom] Checked = True OnKeyPress = FormKeyPress ParentBidiMode = False TabOrder = 5 TabStop = True end object rbPath2: TRadioButton AnchorSideTop.Control = tePath2 AnchorSideBottom.Control = tePath2 AnchorSideBottom.Side = asrBottom Left = 18 Height = 23 Top = 34 Width = 20 Anchors = [akTop, akLeft, akBottom] OnKeyPress = FormKeyPress TabOrder = 6 end object rbPath3: TRadioButton AnchorSideTop.Control = tePath3 AnchorSideBottom.Control = tePath3 AnchorSideBottom.Side = asrBottom Left = 18 Height = 23 Top = 63 Width = 20 Anchors = [akTop, akLeft, akBottom] OnKeyPress = FormKeyPress TabOrder = 7 end object rbPath4: TRadioButton AnchorSideTop.Control = tePath4 AnchorSideBottom.Control = tePath4 AnchorSideBottom.Side = asrBottom Left = 18 Height = 23 Top = 92 Width = 20 Anchors = [akTop, akLeft, akBottom] OnKeyPress = FormKeyPress TabOrder = 8 end object rbPath5: TRadioButton AnchorSideTop.Control = tePath5 AnchorSideBottom.Control = tePath5 AnchorSideBottom.Side = asrBottom Left = 18 Height = 23 Top = 121 Width = 20 Anchors = [akTop, akLeft, akBottom] OnKeyPress = FormKeyPress TabOrder = 9 end object btnPath2: TSpeedButton AnchorSideLeft.Control = btnPath1 AnchorSideTop.Control = tePath2 AnchorSideRight.Control = btnPath1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = tePath2 AnchorSideBottom.Side = asrBottom Left = 442 Height = 23 Top = 34 Width = 21 Anchors = [akTop, akLeft, akRight, akBottom] Caption = '...' OnClick = btnPathClick end object btnPath3: TSpeedButton AnchorSideLeft.Control = btnPath1 AnchorSideTop.Control = tePath3 AnchorSideRight.Control = btnPath1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = tePath3 AnchorSideBottom.Side = asrBottom Left = 442 Height = 23 Top = 63 Width = 21 Anchors = [akTop, akLeft, akRight, akBottom] Caption = '...' OnClick = btnPathClick end object btnPath4: TSpeedButton AnchorSideLeft.Control = btnPath1 AnchorSideTop.Control = tePath4 AnchorSideRight.Control = btnPath1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = tePath4 AnchorSideBottom.Side = asrBottom Left = 442 Height = 23 Top = 92 Width = 21 Anchors = [akTop, akLeft, akRight, akBottom] Caption = '...' OnClick = btnPathClick end object btnPath5: TSpeedButton AnchorSideLeft.Control = btnPath1 AnchorSideTop.Control = tePath5 AnchorSideRight.Control = btnPath1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = tePath5 AnchorSideBottom.Side = asrBottom Left = 442 Height = 23 Top = 121 Width = 21 Anchors = [akTop, akLeft, akRight, akBottom] Caption = '...' OnClick = btnPathClick end object lblPath1: TLabel AnchorSideTop.Control = rbPath1 AnchorSideBottom.Control = rbPath1 AnchorSideBottom.Side = asrBottom Left = 5 Height = 20 Top = 6 Width = 6 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 5 BorderSpacing.Top = 1 BorderSpacing.Bottom = 2 Caption = '1' ParentColor = False end object lblPath2: TLabel AnchorSideTop.Control = rbPath2 AnchorSideBottom.Control = rbPath2 AnchorSideBottom.Side = asrBottom Left = 5 Height = 20 Top = 35 Width = 6 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Top = 1 BorderSpacing.Bottom = 2 Caption = '2' ParentColor = False end object lblPath3: TLabel AnchorSideTop.Control = rbPath3 AnchorSideBottom.Control = rbPath3 AnchorSideBottom.Side = asrBottom Left = 5 Height = 20 Top = 64 Width = 6 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Top = 1 BorderSpacing.Bottom = 2 Caption = '3' ParentColor = False end object lblPath4: TLabel AnchorSideTop.Control = rbPath4 AnchorSideBottom.Control = rbPath4 AnchorSideBottom.Side = asrBottom Left = 5 Height = 20 Top = 93 Width = 6 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Top = 1 BorderSpacing.Bottom = 2 Caption = '4' ParentColor = False end object lblPath5: TLabel AnchorSideTop.Control = rbPath5 AnchorSideBottom.Control = rbPath5 AnchorSideBottom.Side = asrBottom Left = 5 Height = 20 Top = 122 Width = 6 Alignment = taCenter Anchors = [akTop, akLeft, akBottom] BorderSpacing.Top = 1 BorderSpacing.Bottom = 2 Caption = '5' ParentColor = False end end object pnlSize: TPanel AnchorSideRight.Side = asrBottom Left = 0 Height = 273 Top = 0 Width = 468 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 6 ClientHeight = 273 ClientWidth = 468 TabOrder = 1 object lblHeight: TLabel AnchorSideTop.Control = teHeight AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 31 Width = 42 Caption = 'Height :' ParentColor = False end object lblWidth: TLabel AnchorSideTop.Control = teWidth AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 4 Width = 38 Caption = 'Width :' ParentColor = False end object teWidth: TEdit AnchorSideLeft.Control = lblWidth AnchorSideLeft.Side = asrBottom Left = 54 Height = 23 Top = 0 Width = 82 BorderSpacing.Left = 10 OnKeyPress = teWidthKeyPress OnKeyUp = teWidthKeyUp TabOrder = 0 Text = 'Width' end object teHeight: TEdit AnchorSideLeft.Control = teWidth AnchorSideTop.Control = teWidth AnchorSideTop.Side = asrBottom Left = 54 Height = 23 Top = 27 Width = 82 BorderSpacing.Top = 4 OnKeyPress = teHeightKeyPress OnKeyUp = teHeightKeyUp TabOrder = 1 Text = 'Height' end object btnProportion: TSpeedButton AnchorSideLeft.Control = teWidth AnchorSideLeft.Side = asrBottom Left = 142 Height = 32 Top = 8 Width = 26 AllowAllUp = True BorderSpacing.Left = 6 Down = True GroupIndex = 1 OnClick = btnProportionClick end end end object sddCopyMoveFile: TSelectDirectoryDialog Left = 288 Top = 40 end object ImageList: TImageList Height = 24 Width = 9 Left = 288 Top = 112 Bitmap = { 4C7A020000000900000018000000D70000000000000078DA6360A01E080E0F0D 03E2FF587018929AFF7DBDBDFF5FBE7801C713FAFAC0EA90D580C491CD80F171 A86120A4061B9F1C35AD5D1D38DD33B1BFFFBF9989DEFF37EFDE81D581F8686A 5C407C6435E8E10303C86A7085373E3578EC724176F3CC193350D44C9F3A15A7 DF41EAE815CEC4A8C19736E6CD9D8B92C676EDDC896C2E5169154F3A1F12F902 48335023EF10A386D6F902E406A03E06347350E202EA4E901A06A01A06A01AB8 1896BC035783277FE154438C5D2036307F31A0E52F743583369F1213EFD8D218 BA3E72F3293179070068D29CC0 } end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmodview.lrj�������������������������������������������������������������������0000644�0001750�0000144�00000003237�14743153644�015733� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":211134021,"name":"tfrmmodview.caption","sourcebytes":[78,101,119,32,83,105,122,101],"value":"New Size"}, {"hash":12558,"name":"tfrmmodview.btnpath1.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":12558,"name":"tfrmmodview.btnpath2.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":12558,"name":"tfrmmodview.btnpath3.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":12558,"name":"tfrmmodview.btnpath4.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":12558,"name":"tfrmmodview.btnpath5.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":49,"name":"tfrmmodview.lblpath1.caption","sourcebytes":[49],"value":"1"}, {"hash":50,"name":"tfrmmodview.lblpath2.caption","sourcebytes":[50],"value":"2"}, {"hash":51,"name":"tfrmmodview.lblpath3.caption","sourcebytes":[51],"value":"3"}, {"hash":52,"name":"tfrmmodview.lblpath4.caption","sourcebytes":[52],"value":"4"}, {"hash":53,"name":"tfrmmodview.lblpath5.caption","sourcebytes":[53],"value":"5"}, {"hash":201192154,"name":"tfrmmodview.lblheight.caption","sourcebytes":[72,101,105,103,104,116,32,58],"value":"Height :"}, {"hash":234596970,"name":"tfrmmodview.lblwidth.caption","sourcebytes":[87,105,100,116,104,32,58],"value":"Width :"}, {"hash":6159272,"name":"tfrmmodview.tewidth.text","sourcebytes":[87,105,100,116,104],"value":"Width"}, {"hash":82574836,"name":"tfrmmodview.teheight.text","sourcebytes":[72,101,105,103,104,116],"value":"Height"}, {"hash":219345735,"name":"tfrmmodview.lblquality.caption","sourcebytes":[81,117,97,108,105,116,121,32,111,102,32,99,111,109,112,114,101,115,115,32,116,111,32,74,112,103],"value":"Quality of compress to Jpg"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmodview.pas�������������������������������������������������������������������0000644�0001750�0000144�00000014370�14743153644�015727� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fModView; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, ButtonPanel, Spin, uOSForms; type { TfrmModView } TfrmModView = class(TModalForm) btnPath1: TSpeedButton; btnPath2: TSpeedButton; btnPath3: TSpeedButton; btnPath4: TSpeedButton; btnPath5: TSpeedButton; btnProportion: TSpeedButton; bplButtons: TButtonPanel; ImageList: TImageList; lblHeight: TLabel; lblPath1: TLabel; lblPath2: TLabel; lblPath3: TLabel; lblPath4: TLabel; lblPath5: TLabel; lblQuality: TLabel; lblWidth: TLabel; pnlMain: TPanel; pnlCopyMoveFile: TPanel; pnlQuality: TPanel; pnlSize: TPanel; rbPath1: TRadioButton; rbPath2: TRadioButton; rbPath3: TRadioButton; rbPath4: TRadioButton; rbPath5: TRadioButton; sddCopyMoveFile: TSelectDirectoryDialog; tbQuality: TTrackBar; teHeight: TEdit; tePath1: TEdit; tePath2: TEdit; tePath3: TEdit; tePath4: TEdit; tePath5: TEdit; teQuality: TSpinEdit; teWidth: TEdit; procedure btnCancelClick(Sender: TObject); procedure btnOkClick(Sender: TObject); procedure btnPathClick(Sender: TObject); procedure btnProportionClick(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: char); procedure FormShow(Sender: TObject); procedure tbQualityChange(Sender: TObject); procedure teHeightKeyPress(Sender: TObject; var Key: char); procedure teHeightKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure teQualityChange(Sender: TObject); procedure teWidthKeyPress(Sender: TObject; var Key: char); procedure teWidthKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); private { private declarations } prX, prY: integer; public Path : string; { public declarations } end; implementation {$R *.lfm} uses uGlobs; procedure TfrmModView.btnProportionClick(Sender: TObject); begin if btnProportion.Down then ImageList.GetBitmap(0, btnProportion.Glyph) else begin ImageList.GetBitmap(1, btnProportion.Glyph); end; end; procedure TfrmModView.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin gCopyMovePath1 := tePath1.Text; gCopyMovePath2 := tePath2.Text; gCopyMovePath3 := tePath3.Text; gCopyMovePath4 := tePath4.Text; gCopyMovePath5 := tePath5.Text; end; procedure TfrmModView.FormCreate(Sender: TObject); begin ImageList.GetBitmap(0, btnProportion.Glyph); end; procedure TfrmModView.FormKeyPress(Sender: TObject; var Key: char); begin if pnlCopyMoveFile.Visible then begin rbPath1.Checked:= false; rbPath2.Checked:= false; rbPath3.Checked:= false; rbPath4.Checked:= false; rbPath5.Checked:= false; case Key of '1': begin rbPath1.Checked:= true; Key := #0; btnOkClick(Sender); end; '2': begin rbPath2.Checked:= true; Key := #0; btnOkClick(Sender); end; '3': begin rbPath3.Checked:= true; Key := #0; btnOkClick(Sender); end; '4': begin rbPath4.Checked:= true; Key := #0; btnOkClick(Sender); end; '5': begin rbPath5.Checked:= true; Key := #0; btnOkClick(Sender); end; end; end; end; procedure TfrmModView.FormShow(Sender: TObject); begin if pnlSize.Visible then begin prX:=StrToInt(teWidth.Text); prY:=StrToInt(teHeight.Text); end; if pnlCopyMoveFile.Visible then begin rbPath1.SetFocus; tePath1.Text := gCopyMovePath1; tePath2.Text := gCopyMovePath2; tePath3.Text := gCopyMovePath3; tePath4.Text := gCopyMovePath4; tePath5.Text := gCopyMovePath5; end; if pnlQuality.Visible then begin tbQuality.Enabled:=true; lblQuality.Enabled:=True; tbQuality.Position:=gViewerJpegQuality; teQuality.Value:= gViewerJpegQuality; end; end; procedure TfrmModView.tbQualityChange(Sender: TObject); begin teQuality.Value:= tbQuality.Position; end; procedure TfrmModView.btnOkClick(Sender: TObject); begin if pnlCopyMoveFile.Visible then begin if rbPath1.Checked then Path:=tePath1.Text; if rbPath2.Checked then Path:=tePath2.Text; if rbPath3.Checked then Path:=tePath3.Text; if rbPath4.Checked then Path:=tePath4.Text; if rbPath5.Checked then Path:=tePath5.Text; end; ModalResult:= mrOk; end; procedure TfrmModView.btnPathClick(Sender: TObject); begin if sddCopyMoveFile.Execute then begin if sender=btnPath1 then begin tePath1.Text:= sddCopyMoveFile.Filename; rbPath1.Checked:=true; end; if sender=btnPath2 then begin tePath2.Text:= sddCopyMoveFile.Filename; rbPath2.Checked:=true; end; if sender=btnPath3 then begin tePath3.Text:= sddCopyMoveFile.Filename; rbPath3.Checked:=true; end; if sender=btnPath4 then begin tePath4.Text:= sddCopyMoveFile.Filename; rbPath4.Checked:=true; end; if sender=btnPath5 then begin tePath5.Text:= sddCopyMoveFile.Filename; rbPath5.Checked:=true; end; end; end; procedure TfrmModView.btnCancelClick(Sender: TObject); begin ModalResult:= mrCancel; end; procedure TfrmModView.teHeightKeyPress(Sender: TObject; var Key: char); begin if not (key in ['0'..'9', #8]) then key:=#0; end; procedure TfrmModView.teHeightKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if btnProportion.Down then begin teWidth.Text := IntToStr(Round(StrToInt(teHeight.Text) * prX / prY)); end; end; procedure TfrmModView.teQualityChange(Sender: TObject); begin tbQuality.Position:= teQuality.Value; end; procedure TfrmModView.teWidthKeyPress(Sender: TObject; var Key: char); begin if not (key in ['0'..'9', #8]) then key:=#0; end; procedure TfrmModView.teWidthKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if btnProportion.Down then begin teHeight.Text := IntToStr(Round(StrToInt(teWidth.Text) * prY / prX)); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmultirename.lfm���������������������������������������������������������������0000644�0001750�0000144�00000072021�14743153644�016567� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMultiRename: TfrmMultiRename Left = 492 Height = 624 Top = 132 Width = 788 ActiveControl = cbName Caption = 'Multi-Rename Tool' ClientHeight = 597 ClientWidth = 788 KeyPreview = True Menu = mmMainMenu OnClose = FormClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter SessionProperties = 'Height;Left;Top;Width;WindowState;pnlOptionsLeft.Width' ShowHint = True ShowInTaskBar = stAlways LCLVersion = '2.0.12.0' object StringGrid: TStringGrid Left = 6 Height = 261 Top = 6 Width = 776 Align = alClient AutoFillColumns = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 ColCount = 3 Columns = < item SizePriority = 0 Title.Caption = 'Old File Name' Width = 248 end item SizePriority = 0 Title.Caption = 'New File Name' Width = 249 end item Title.Caption = 'File Path' Width = 277 end> ExtendedSelect = False FixedCols = 0 MouseWheelOption = mwGrid Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goRowSelect, goSmoothScroll] ParentFont = False RowCount = 1 TabOrder = 2 TitleStyle = tsNative OnKeyDown = StringGridKeyDown OnMouseDown = StringGridMouseDown OnMouseUp = StringGridMouseUp OnResize = StringGridTopLeftChanged OnSelection = StringGridSelection OnTopLeftChanged = StringGridTopLeftChanged ColWidths = ( 248 249 277 ) end object pnlOptions: TPanel Left = 6 Height = 275 Top = 273 Width = 776 Align = alBottom AutoSize = True BorderSpacing.Around = 6 BevelOuter = bvNone ClientHeight = 275 ClientWidth = 776 ParentFont = False TabOrder = 0 object pnlOptionsLeft: TPanel AnchorSideRight.Side = asrBottom Left = 0 Height = 275 Top = 0 Width = 250 Align = alLeft BevelOuter = bvNone ClientHeight = 275 ClientWidth = 250 ParentFont = False TabOrder = 0 object gbMaska: TGroupBox AnchorSideLeft.Control = pnlOptionsLeft AnchorSideTop.Control = pnlOptionsLeft AnchorSideRight.Control = pnlOptionsLeft AnchorSideRight.Side = asrBottom Left = 0 Height = 210 Top = 0 Width = 250 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Mask' ChildSizing.LeftRightSpacing = 4 ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 2 ClientHeight = 190 ClientWidth = 248 ParentFont = False TabOrder = 0 object lbName: TLabel AnchorSideLeft.Control = gbMaska AnchorSideTop.Control = gbMaska AnchorSideBottom.Control = cbName Left = 4 Height = 17 Top = 0 Width = 61 Caption = 'File &Name' FocusControl = cbName ParentColor = False ParentFont = False end object lbExt: TLabel AnchorSideLeft.Control = gbMaska AnchorSideTop.Control = cbNameMaskStyle AnchorSideTop.Side = asrBottom Left = 4 Height = 17 Top = 95 Width = 60 Caption = '&Extension' FocusControl = cbExt ParentColor = False ParentFont = False end object cbNameMaskStyle: TComboBox AnchorSideLeft.Control = btnAnyNameMask AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMaska AnchorSideRight.Side = asrBottom Left = 29 Height = 35 Top = 56 Width = 215 Anchors = [akTop, akLeft, akRight] BorderSpacing.Bottom = 4 ItemHeight = 0 OnChange = cbNameStyleChange ParentFont = False Style = csDropDownList TabOrder = 2 end object cmbExtensionStyle: TComboBox AnchorSideLeft.Control = btnAnyExtMask AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbExt AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMaska AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 29 Height = 35 Top = 151 Width = 215 Anchors = [akTop, akLeft, akRight] BorderSpacing.Bottom = 4 ItemHeight = 0 OnChange = cbNameStyleChange ParentFont = False Style = csDropDownList TabOrder = 5 end object btnAnyNameMask: TKASButton AnchorSideLeft.Control = gbMaska AnchorSideTop.Control = cbNameMaskStyle AnchorSideBottom.Control = cbNameMaskStyle AnchorSideBottom.Side = asrBottom Left = 4 Height = 35 Top = 56 Width = 23 Anchors = [akTop, akLeft, akBottom] TabOrder = 1 TabStop = True end object btnAnyExtMask: TKASButton AnchorSideLeft.Control = gbMaska AnchorSideTop.Control = cmbExtensionStyle AnchorSideBottom.Control = cmbExtensionStyle AnchorSideBottom.Side = asrBottom Left = 4 Height = 35 Top = 151 Width = 23 Anchors = [akTop, akLeft, akBottom] TabOrder = 4 TabStop = True end object cbName: TComboBox AnchorSideLeft.Control = gbMaska AnchorSideTop.Control = lbName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMaska AnchorSideRight.Side = asrBottom Left = 4 Height = 35 Top = 19 Width = 240 Anchors = [akTop, akLeft, akRight] AutoSelect = False ItemHeight = 0 OnChange = cbNameStyleChange ParentFont = False TabOrder = 0 end object cbExt: TComboBox AnchorSideLeft.Control = gbMaska AnchorSideTop.Control = lbExt AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMaska AnchorSideRight.Side = asrBottom Left = 4 Height = 35 Top = 114 Width = 240 Anchors = [akTop, akLeft, akRight] AutoSelect = False ItemHeight = 0 OnChange = cbNameStyleChange ParentFont = False TabOrder = 3 end end object gbPresets: TGroupBox AnchorSideLeft.Control = pnlOptionsLeft AnchorSideTop.Control = gbMaska AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlOptionsLeft AnchorSideRight.Side = asrBottom Left = 0 Height = 59 Top = 216 Width = 250 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Presets' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 2 ChildSizing.HorizontalSpacing = 2 ClientHeight = 39 ClientWidth = 248 ParentColor = False ParentFont = False TabOrder = 1 object cbPresets: TComboBox AnchorSideLeft.Control = gbPresets AnchorSideTop.Control = gbPresets AnchorSideRight.Control = btnPresets AnchorSideBottom.Side = asrBottom Left = 4 Height = 35 Top = 2 Width = 222 Anchors = [akTop, akLeft, akRight] DropDownCount = 15 ItemHeight = 0 OnChange = cbPresetsChange OnCloseUp = cbPresetsCloseUp ParentFont = False Style = csDropDownList TabOrder = 1 end object btnPresets: TKASButton AnchorSideTop.Control = cbPresets AnchorSideRight.Control = gbPresets AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbPresets AnchorSideBottom.Side = asrBottom Left = 228 Height = 35 Top = 2 Width = 16 Anchors = [akTop, akRight, akBottom] AutoSize = True Constraints.MinWidth = 16 ParentBidiMode = False ParentFont = False TabOrder = 0 TabStop = True ShowCaption = False end end end object spltMainSplitter: TSplitter Left = 250 Height = 275 Top = 0 Width = 5 ResizeStyle = rsLine end object pnlOptionsRight: TKASToolPanel Left = 255 Height = 275 Top = 0 Width = 521 Align = alClient AutoSize = True ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 2 EdgeBorders = [ebBottom] TabOrder = 1 object gbFindReplace: TGroupBox AnchorSideLeft.Control = pnlOptionsRight AnchorSideTop.Control = pnlOptionsRight AnchorSideRight.Control = gbCounter Left = 0 Height = 184 Top = 0 Width = 318 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Right = 4 Caption = 'Find && Replace' ChildSizing.LeftRightSpacing = 4 ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 2 ClientHeight = 164 ClientWidth = 316 ParentFont = False TabOrder = 0 object lbFind: TLabel AnchorSideLeft.Control = gbFindReplace AnchorSideTop.Control = gbFindReplace Left = 4 Height = 17 Top = 0 Width = 38 Caption = '&Find...' FocusControl = edFind ParentColor = False ParentFont = False end object lbReplace: TLabel AnchorSideLeft.Control = gbFindReplace AnchorSideTop.Control = edFind AnchorSideTop.Side = asrBottom Left = 4 Height = 17 Top = 58 Width = 60 BorderSpacing.Top = 4 Caption = 'Re&place...' FocusControl = edReplace ParentColor = False ParentFont = False end object edFind: TEdit AnchorSideLeft.Control = gbFindReplace AnchorSideTop.Control = lbFind AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFindReplace AnchorSideRight.Side = asrBottom Left = 4 Height = 35 Top = 19 Width = 308 Anchors = [akTop, akLeft, akRight] AutoSelect = False OnChange = edFindChange ParentFont = False TabOrder = 0 end object edReplace: TEdit AnchorSideLeft.Control = gbFindReplace AnchorSideTop.Control = lbReplace AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFindReplace AnchorSideRight.Side = asrBottom Left = 4 Height = 35 Top = 77 Width = 308 Anchors = [akTop, akLeft, akRight] AutoSelect = False OnChange = edReplaceChange ParentFont = False TabOrder = 1 end object pnlFindReplace: TPanel AnchorSideLeft.Control = edReplace AnchorSideTop.Control = edReplace AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edReplace AnchorSideRight.Side = asrBottom Left = 4 Height = 46 Top = 86 Width = 318 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ChildSizing.TopBottomSpacing = 2 ChildSizing.HorizontalSpacing = 12 ChildSizing.VerticalSpacing = 2 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 46 ClientWidth = 318 TabOrder = 2 object cbRegExp: TCheckBox Left = 0 Height = 19 Top = 4 Width = 124 BorderSpacing.Top = 4 Caption = 'Regular e&xpressions' OnChange = cbRegExpChange ParentFont = False TabOrder = 0 end object cbCaseSens: TCheckBox Left = 136 Height = 19 Hint = 'Case sensitive' Top = 4 Width = 42 Caption = 'A≠a' OnChange = cbNameStyleChange TabOrder = 2 end object cbUseSubs: TCheckBox AnchorSideBottom.Side = asrBottom Left = 0 Height = 19 Top = 25 Width = 124 BorderSpacing.Top = 2 Caption = '&Use substitution' Enabled = False OnChange = cbNameStyleChange ParentFont = False TabOrder = 1 end object cbOnlyFirst: TCheckBox Left = 136 Height = 19 Hint = 'Replace only once per file' Top = 25 Width = 42 Caption = '1x' OnChange = cbNameStyleChange TabOrder = 3 end end end object btnEditor: TBitBtn AnchorSideLeft.Control = gbCounter AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbCounter AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gbFindReplace AnchorSideBottom.Side = asrBottom Left = 322 Height = 35 Top = 149 Width = 199 Action = actInvokeEditor Anchors = [akLeft, akRight, akBottom] AutoSize = True ParentFont = False TabOrder = 2 end object gbCounter: TGroupBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlOptionsRight AnchorSideRight.Control = pnlOptionsRight AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 322 Height = 135 Top = 0 Width = 199 Anchors = [akTop, akRight] AutoSize = True Caption = 'Counter' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 2 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ChildSizing.EnlargeHorizontal = crsScaleChilds ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 115 ClientWidth = 197 ParentFont = False TabOrder = 1 object lbStNb: TLabel Left = 4 Height = 17 Top = 11 Width = 85 BorderSpacing.CellAlignVertical = ccaCenter Caption = 'S&tart Number' FocusControl = edPoc ParentColor = False ParentFont = False end object edPoc: TEdit Left = 93 Height = 35 Top = 2 Width = 100 AutoSelect = False MaxLength = 10 OnChange = edPocChange ParentFont = False TabOrder = 0 Text = '1' end object lbInterval: TLabel Left = 4 Height = 17 Top = 50 Width = 85 BorderSpacing.CellAlignVertical = ccaCenter Caption = '&Interval' FocusControl = edInterval ParentColor = False ParentFont = False end object edInterval: TEdit Left = 93 Height = 35 Top = 41 Width = 100 AutoSelect = False MaxLength = 10 OnChange = edIntervalChange ParentFont = False TabOrder = 1 Text = '1' end object lbWidth: TLabel Left = 4 Height = 17 Top = 87 Width = 85 BorderSpacing.CellAlignVertical = ccaCenter Caption = '&Width' FocusControl = cmbxWidth ParentColor = False ParentFont = False end object cmbxWidth: TComboBox Left = 93 Height = 31 Top = 80 Width = 100 BorderSpacing.Bottom = 4 ItemHeight = 0 ItemIndex = 0 Items.Strings = ( '01' '02' '03' '04' '05' '06' '07' '08' '09' '10' ) OnChange = cbNameStyleChange ParentFont = False Style = csDropDownList TabOrder = 2 Text = '01' end end object cbLog: TCheckBox AnchorSideLeft.Control = fneRenameLogFileFilename AnchorSideTop.Control = cbLogAppend AnchorSideTop.Side = asrCenter Left = 5 Height = 23 Top = 190 Width = 87 BorderSpacing.Top = 2 Caption = '&Log result' OnClick = cbLogClick ParentFont = False TabOrder = 3 end object btnRelativeRenameLogFile: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneRenameLogFileFilename AnchorSideRight.Control = btnViewRenameLogFile AnchorSideBottom.Control = fneRenameLogFileFilename AnchorSideBottom.Side = asrBottom Left = 473 Height = 35 Top = 215 Width = 23 Anchors = [akTop, akRight, akBottom] ParentFont = False end object btnViewRenameLogFile: TSpeedButton AnchorSideTop.Control = fneRenameLogFileFilename AnchorSideRight.Control = pnlOptionsRight AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneRenameLogFileFilename AnchorSideBottom.Side = asrBottom Left = 498 Height = 35 Top = 215 Width = 23 Anchors = [akTop, akRight, akBottom] ParentFont = False end object fneRenameLogFileFilename: TFileNameEdit AnchorSideLeft.Control = gbFindReplace AnchorSideTop.Control = cbLog AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeRenameLogFile AnchorSideBottom.Side = asrBottom Left = 5 Height = 35 Top = 215 Width = 466 DialogTitle = 'Select target log filename' DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 5 MaxLength = 0 ParentFont = False TabOrder = 5 OnChange = cbNameStyleChange end object cbLogAppend: TCheckBox AnchorSideLeft.Control = cbLog AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbFindReplace AnchorSideTop.Side = asrBottom Left = 102 Height = 23 Top = 190 Width = 75 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = 'Append' OnClick = cbLogClick ParentFont = False TabOrder = 4 end end end object pnlButtons: TPanel Left = 0 Height = 43 Top = 554 Width = 788 Align = alBottom AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 4 ClientHeight = 43 ClientWidth = 788 TabOrder = 1 object btnClose: TBitBtn AnchorSideTop.Control = pnlButtons AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 702 Height = 35 Top = 4 Width = 80 Action = actClose Anchors = [akTop, akRight] AutoSize = True Constraints.MinWidth = 80 ParentFont = False TabOrder = 3 end object btnRestore: TBitBtn AnchorSideLeft.Control = btnConfig AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnClose AnchorSideTop.Side = asrCenter AnchorSideBottom.Side = asrBottom Left = 132 Height = 35 Top = 4 Width = 100 Action = actResetAll AutoSize = True BorderSpacing.Left = 6 Constraints.MinWidth = 100 ParentFont = False TabOrder = 1 end object btnRename: TBitBtn AnchorSideTop.Control = btnClose AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnClose Left = 629 Height = 35 Top = 4 Width = 67 Action = actRename Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 6 Default = True ParentFont = False TabOrder = 2 end object btnConfig: TBitBtn AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnRename AnchorSideTop.Side = asrCenter Left = 6 Height = 35 Top = 4 Width = 120 Action = actConfig AutoSize = True Constraints.MinWidth = 120 ParentFont = False TabOrder = 0 end end object pmEditDirect: TPopupMenu Images = dmComData.ilEditorImages Left = 504 Top = 160 object mnuLoadFromFile: TMenuItem Action = actLoadNamesFromFile end object mnuEditNames: TMenuItem Action = actEditNames end object mnuEditNewNames: TMenuItem Action = actEditNewNames end end object mmMainMenu: TMainMenu Images = dmComData.ilEditorImages Left = 96 Top = 40 object miActions: TMenuItem Caption = 'Actions' object miResetAll: TMenuItem Action = actResetAll end object miEditor: TMenuItem Caption = 'Editor' object miLoadNamesFromFile: TMenuItem Action = actLoadNamesFromFile end object miEditNames: TMenuItem Action = actEditNames end object miEditNewNames: TMenuItem Action = actEditNewNames end end object miSeparator1: TMenuItem Caption = '-' end object miConfiguration: TMenuItem Action = actConfig end object miSeparator2: TMenuItem Caption = '-' end object miRename: TMenuItem Action = actRename end object miClose: TMenuItem Action = actClose end end end object actList: TActionList Images = dmComData.ilEditorImages Left = 360 Top = 96 object actAnyNameMask: TAction Tag = 63 Category = 'Masks' Caption = 'Filename' ImageIndex = 20 OnExecute = actExecute end object actNameNameMask: TAction Tag = 1 Category = 'Masks' Caption = 'Filename' ImageIndex = 20 OnExecute = actExecute end object actExtNameMask: TAction Tag = 2 Category = 'Masks' Caption = 'Extension' ImageIndex = 21 OnExecute = actExecute end object actCtrNameMask: TAction Tag = 4 Category = 'Masks' Caption = 'Counter' ImageIndex = 22 OnExecute = actExecute end object actDateNameMask: TAction Tag = 8 Category = 'Masks' Caption = 'Date' ImageIndex = 23 OnExecute = actExecute end object actTimeNameMask: TAction Tag = 16 Category = 'Masks' Caption = 'Time' ImageIndex = 24 OnExecute = actExecute end object actPlgnNameMask: TAction Tag = 32 Category = 'Masks' Caption = 'Plugins' ImageIndex = 25 OnExecute = actExecute end object actResetAll: TAction Category = 'Generic' Caption = 'Reset &All' ImageIndex = 17 OnExecute = actExecute end object actClearNameMask: TAction Category = 'Masks' Caption = 'Clear' ImageIndex = 29 OnExecute = actExecute end object actAnyExtMask: TAction Category = 'Masks' Caption = 'Extension' ImageIndex = 21 OnExecute = actExecute end object actNameExtMask: TAction Category = 'Masks' Caption = 'Filename' ImageIndex = 20 OnExecute = actExecute end object actExtExtMask: TAction Category = 'Masks' Caption = 'Extension' ImageIndex = 21 OnExecute = actExecute end object actCtrExtMask: TAction Category = 'Masks' Caption = 'Counter' ImageIndex = 22 OnExecute = actExecute end object actDateExtMask: TAction Category = 'Masks' Caption = 'Date' ImageIndex = 23 OnExecute = actExecute end object actTimeExtMask: TAction Category = 'Masks' Caption = 'Time' ImageIndex = 24 OnExecute = actExecute end object actPlgnExtMask: TAction Category = 'Masks' Caption = 'Plugins' ImageIndex = 25 OnExecute = actExecute end object actClearExtMask: TAction Category = 'Masks' Caption = 'Clear' ImageIndex = 29 OnExecute = actExecute end object actInvokeEditor: TAction Category = 'Generic' Caption = 'Edit&or' ImageIndex = 19 OnExecute = actExecute end object actViewRenameLogFile: TAction Category = 'Log' Caption = 'View Rename Log File' ImageIndex = 26 OnExecute = actExecute end object actInvokeRelativePath: TAction Category = 'Log' Caption = 'Invoke Relative Path Menu' ImageIndex = 27 OnExecute = actInvokeRelativePathExecute end object actLoadNamesFromFile: TAction Category = 'Generic' Caption = 'Load Names from File...' OnExecute = actExecute end object actLoadNamesFromClipboard: TAction Category = 'Generic' Caption = 'Load Names from Clipboard' OnExecute = actExecute end object actEditNames: TAction Category = 'Generic' Caption = 'Edit Names...' OnExecute = actExecute end object actEditNewNames: TAction Category = 'Generic' Caption = 'Edit Current New Names...' OnExecute = actExecute end object actShowPresetsMenu: TAction Category = 'Presets' Caption = 'Show Preset Menu' ImageIndex = 30 OnExecute = actExecute end object actDropDownPresetList: TAction Category = 'Presets' Caption = 'Drop Down Presets List' ImageIndex = 33 OnExecute = actExecute end object actLoadLastPreset: TAction Category = 'Presets' Caption = 'Load Last Preset' OnExecute = actExecute end object actLoadPreset: TAction Category = 'Presets' Caption = 'Load Preset by Name or Index' OnExecute = actExecute end object actLoadPreset1: TAction Category = 'Presets' Caption = 'Load Preset 1' OnExecute = actExecute end object actLoadPreset2: TAction Category = 'Presets' Caption = 'Load Preset 2' OnExecute = actExecute end object actLoadPreset3: TAction Category = 'Presets' Caption = 'Load Preset 3' OnExecute = actExecute end object actLoadPreset4: TAction Category = 'Presets' Caption = 'Load Preset 4' OnExecute = actExecute end object actLoadPreset5: TAction Category = 'Presets' Caption = 'Load Preset 5' OnExecute = actExecute end object actLoadPreset6: TAction Category = 'Presets' Caption = 'Load Preset 6' OnExecute = actExecute end object actLoadPreset7: TAction Category = 'Presets' Caption = 'Load Preset 7' OnExecute = actExecute end object actLoadPreset8: TAction Category = 'Presets' Caption = 'Load Preset 8' OnExecute = actExecute end object actLoadPreset9: TAction Category = 'Presets' Caption = 'Load Preset 9' OnExecute = actExecute end object actSavePreset: TAction Category = 'Presets' Caption = 'Save' ImageIndex = 31 OnExecute = actExecute end object actSavePresetAs: TAction Category = 'Presets' Caption = 'Save As...' OnExecute = actExecute end object actRenamePreset: TAction Category = 'Presets' Caption = 'Rename' OnExecute = actExecute end object actDeletePreset: TAction Category = 'Presets' Caption = 'Delete' ImageIndex = 32 OnExecute = actExecute end object actSortPresets: TAction Category = 'Presets' Caption = 'Sort' OnExecute = actExecute end object actConfig: TAction Category = 'Generic' Caption = 'Confi&guration' ImageIndex = 18 OnExecute = actExecute end object actRename: TAction Category = 'Generic' Caption = '&Rename' ImageIndex = 28 OnExecute = actExecute end object actClose: TAction Category = 'Generic' Caption = '&Close' ImageIndex = 12 OnExecute = actExecute end end object pmDynamicMasks: TPopupMenu Images = dmComData.ilEditorImages Left = 96 Top = 152 end object pmPresets: TPopupMenu Images = dmComData.ilEditorImages Left = 120 Top = 376 end object pmFloatingMainMaskMenu: TPopupMenu Images = dmComData.ilEditorImages Left = 96 Top = 96 end object pmPathToBeRelativeToHelper: TPopupMenu Left = 648 Top = 160 end end���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmultirename.lrj���������������������������������������������������������������0000644�0001750�0000144�00000024020�14743153644�016574� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":252261308,"name":"tfrmmultirename.caption","sourcebytes":[77,117,108,116,105,45,82,101,110,97,109,101,32,84,111,111,108],"value":"Multi-Rename Tool"}, {"hash":72551557,"name":"tfrmmultirename.stringgrid.columns[0].title.caption","sourcebytes":[79,108,100,32,70,105,108,101,32,78,97,109,101],"value":"Old File Name"}, {"hash":113118341,"name":"tfrmmultirename.stringgrid.columns[1].title.caption","sourcebytes":[78,101,119,32,70,105,108,101,32,78,97,109,101],"value":"New File Name"}, {"hash":41231784,"name":"tfrmmultirename.stringgrid.columns[2].title.caption","sourcebytes":[70,105,108,101,32,80,97,116,104],"value":"File Path"}, {"hash":342171,"name":"tfrmmultirename.gbmaska.caption","sourcebytes":[77,97,115,107],"value":"Mask"}, {"hash":120559637,"name":"tfrmmultirename.lbname.caption","sourcebytes":[70,105,108,101,32,38,78,97,109,101],"value":"File &Name"}, {"hash":180827310,"name":"tfrmmultirename.lbext.caption","sourcebytes":[38,69,120,116,101,110,115,105,111,110],"value":"&Extension"}, {"hash":126655715,"name":"tfrmmultirename.gbpresets.caption","sourcebytes":[80,114,101,115,101,116,115],"value":"Presets"}, {"hash":212198085,"name":"tfrmmultirename.gbfindreplace.caption","sourcebytes":[70,105,110,100,32,38,38,32,82,101,112,108,97,99,101],"value":"Find && Replace"}, {"hash":218395566,"name":"tfrmmultirename.lbfind.caption","sourcebytes":[38,70,105,110,100,46,46,46],"value":"&Find..."}, {"hash":35724926,"name":"tfrmmultirename.lbreplace.caption","sourcebytes":[82,101,38,112,108,97,99,101,46,46,46],"value":"Re&place..."}, {"hash":20463635,"name":"tfrmmultirename.cbregexp.caption","sourcebytes":[82,101,103,117,108,97,114,32,101,38,120,112,114,101,115,115,105,111,110,115],"value":"Regular e&xpressions"}, {"hash":219672053,"name":"tfrmmultirename.cbcasesens.hint","sourcebytes":[67,97,115,101,32,115,101,110,115,105,116,105,118,101],"value":"Case sensitive"}, {"hash":5223265,"name":"tfrmmultirename.cbcasesens.caption","sourcebytes":[65,226,137,160,97],"value":"A\u2260a"}, {"hash":121437630,"name":"tfrmmultirename.cbusesubs.caption","sourcebytes":[38,85,115,101,32,115,117,98,115,116,105,116,117,116,105,111,110],"value":"&Use substitution"}, {"hash":54067429,"name":"tfrmmultirename.cbonlyfirst.hint","sourcebytes":[82,101,112,108,97,99,101,32,111,110,108,121,32,111,110,99,101,32,112,101,114,32,102,105,108,101],"value":"Replace only once per file"}, {"hash":904,"name":"tfrmmultirename.cbonlyfirst.caption","sourcebytes":[49,120],"value":"1x"}, {"hash":174873218,"name":"tfrmmultirename.gbcounter.caption","sourcebytes":[67,111,117,110,116,101,114],"value":"Counter"}, {"hash":42119666,"name":"tfrmmultirename.lbstnb.caption","sourcebytes":[83,38,116,97,114,116,32,78,117,109,98,101,114],"value":"S&tart Number"}, {"hash":49,"name":"tfrmmultirename.edpoc.text","sourcebytes":[49],"value":"1"}, {"hash":95205244,"name":"tfrmmultirename.lbinterval.caption","sourcebytes":[38,73,110,116,101,114,118,97,108],"value":"&Interval"}, {"hash":49,"name":"tfrmmultirename.edinterval.text","sourcebytes":[49],"value":"1"}, {"hash":46005160,"name":"tfrmmultirename.lbwidth.caption","sourcebytes":[38,87,105,100,116,104],"value":"&Width"}, {"hash":817,"name":"tfrmmultirename.cmbxwidth.text","sourcebytes":[48,49],"value":"01"}, {"hash":128425892,"name":"tfrmmultirename.cblog.caption","sourcebytes":[38,76,111,103,32,114,101,115,117,108,116],"value":"&Log result"}, {"hash":75983940,"name":"tfrmmultirename.cblogappend.caption","sourcebytes":[65,112,112,101,110,100],"value":"Append"}, {"hash":128648723,"name":"tfrmmultirename.miactions.caption","sourcebytes":[65,99,116,105,111,110,115],"value":"Actions"}, {"hash":79367010,"name":"tfrmmultirename.mieditor.caption","sourcebytes":[69,100,105,116,111,114],"value":"Editor"}, {"hash":2901221,"name":"tfrmmultirename.actanynamemask.caption","sourcebytes":[70,105,108,101,110,97,109,101],"value":"Filename"}, {"hash":2901221,"name":"tfrmmultirename.actnamenamemask.caption","sourcebytes":[70,105,108,101,110,97,109,101],"value":"Filename"}, {"hash":180737198,"name":"tfrmmultirename.actextnamemask.caption","sourcebytes":[69,120,116,101,110,115,105,111,110],"value":"Extension"}, {"hash":174873218,"name":"tfrmmultirename.actctrnamemask.caption","sourcebytes":[67,111,117,110,116,101,114],"value":"Counter"}, {"hash":305317,"name":"tfrmmultirename.actdatenamemask.caption","sourcebytes":[68,97,116,101],"value":"Date"}, {"hash":372789,"name":"tfrmmultirename.acttimenamemask.caption","sourcebytes":[84,105,109,101],"value":"Time"}, {"hash":121364483,"name":"tfrmmultirename.actplgnnamemask.caption","sourcebytes":[80,108,117,103,105,110,115],"value":"Plugins"}, {"hash":208088252,"name":"tfrmmultirename.actresetall.caption","sourcebytes":[82,101,115,101,116,32,38,65,108,108],"value":"Reset &All"}, {"hash":4860802,"name":"tfrmmultirename.actclearnamemask.caption","sourcebytes":[67,108,101,97,114],"value":"Clear"}, {"hash":180737198,"name":"tfrmmultirename.actanyextmask.caption","sourcebytes":[69,120,116,101,110,115,105,111,110],"value":"Extension"}, {"hash":2901221,"name":"tfrmmultirename.actnameextmask.caption","sourcebytes":[70,105,108,101,110,97,109,101],"value":"Filename"}, {"hash":180737198,"name":"tfrmmultirename.actextextmask.caption","sourcebytes":[69,120,116,101,110,115,105,111,110],"value":"Extension"}, {"hash":174873218,"name":"tfrmmultirename.actctrextmask.caption","sourcebytes":[67,111,117,110,116,101,114],"value":"Counter"}, {"hash":305317,"name":"tfrmmultirename.actdateextmask.caption","sourcebytes":[68,97,116,101],"value":"Date"}, {"hash":372789,"name":"tfrmmultirename.acttimeextmask.caption","sourcebytes":[84,105,109,101],"value":"Time"}, {"hash":121364483,"name":"tfrmmultirename.actplgnextmask.caption","sourcebytes":[80,108,117,103,105,110,115],"value":"Plugins"}, {"hash":4860802,"name":"tfrmmultirename.actclearextmask.caption","sourcebytes":[67,108,101,97,114],"value":"Clear"}, {"hash":196111650,"name":"tfrmmultirename.actinvokeeditor.caption","sourcebytes":[69,100,105,116,38,111,114],"value":"Edit&or"}, {"hash":241100437,"name":"tfrmmultirename.actviewrenamelogfile.caption","sourcebytes":[86,105,101,119,32,82,101,110,97,109,101,32,76,111,103,32,70,105,108,101],"value":"View Rename Log File"}, {"hash":263529797,"name":"tfrmmultirename.actinvokerelativepath.caption","sourcebytes":[73,110,118,111,107,101,32,82,101,108,97,116,105,118,101,32,80,97,116,104,32,77,101,110,117],"value":"Invoke Relative Path Menu"}, {"hash":256660862,"name":"tfrmmultirename.actloadnamesfromfile.caption","sourcebytes":[76,111,97,100,32,78,97,109,101,115,32,102,114,111,109,32,70,105,108,101,46,46,46],"value":"Load Names from File..."}, {"hash":227296782,"name":"tfrmmultirename.acteditnames.caption","sourcebytes":[69,100,105,116,32,78,97,109,101,115,46,46,46],"value":"Edit Names..."}, {"hash":72890318,"name":"tfrmmultirename.acteditnewnames.caption","sourcebytes":[69,100,105,116,32,67,117,114,114,101,110,116,32,78,101,119,32,78,97,109,101,115,46,46,46],"value":"Edit Current New Names..."}, {"hash":87501221,"name":"tfrmmultirename.actshowpresetsmenu.caption","sourcebytes":[83,104,111,119,32,80,114,101,115,101,116,32,77,101,110,117],"value":"Show Preset Menu"}, {"hash":207899652,"name":"tfrmmultirename.actdropdownpresetlist.caption","sourcebytes":[68,114,111,112,32,68,111,119,110,32,80,114,101,115,101,116,115,32,76,105,115,116],"value":"Drop Down Presets List"}, {"hash":53442260,"name":"tfrmmultirename.actloadlastpreset.caption","sourcebytes":[76,111,97,100,32,76,97,115,116,32,80,114,101,115,101,116],"value":"Load Last Preset"}, {"hash":169418520,"name":"tfrmmultirename.actloadpreset.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,98,121,32,78,97,109,101,32,111,114,32,73,110,100,101,120],"value":"Load Preset by Name or Index"}, {"hash":194945809,"name":"tfrmmultirename.actloadpreset1.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,49],"value":"Load Preset 1"}, {"hash":194945810,"name":"tfrmmultirename.actloadpreset2.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,50],"value":"Load Preset 2"}, {"hash":194945811,"name":"tfrmmultirename.actloadpreset3.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,51],"value":"Load Preset 3"}, {"hash":194945812,"name":"tfrmmultirename.actloadpreset4.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,52],"value":"Load Preset 4"}, {"hash":194945813,"name":"tfrmmultirename.actloadpreset5.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,53],"value":"Load Preset 5"}, {"hash":194945814,"name":"tfrmmultirename.actloadpreset6.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,54],"value":"Load Preset 6"}, {"hash":194945815,"name":"tfrmmultirename.actloadpreset7.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,55],"value":"Load Preset 7"}, {"hash":194945816,"name":"tfrmmultirename.actloadpreset8.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,56],"value":"Load Preset 8"}, {"hash":194945817,"name":"tfrmmultirename.actloadpreset9.caption","sourcebytes":[76,111,97,100,32,80,114,101,115,101,116,32,57],"value":"Load Preset 9"}, {"hash":366789,"name":"tfrmmultirename.actsavepreset.caption","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":122542542,"name":"tfrmmultirename.actsavepresetas.caption","sourcebytes":[83,97,118,101,32,65,115,46,46,46],"value":"Save As..."}, {"hash":93079605,"name":"tfrmmultirename.actrenamepreset.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, {"hash":78392485,"name":"tfrmmultirename.actdeletepreset.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":370324,"name":"tfrmmultirename.actsortpresets.caption","sourcebytes":[83,111,114,116],"value":"Sort"}, {"hash":180623390,"name":"tfrmmultirename.actconfig.caption","sourcebytes":[67,111,110,102,105,38,103,117,114,97,116,105,111,110],"value":"Confi&guration"}, {"hash":193742869,"name":"tfrmmultirename.actrename.caption","sourcebytes":[38,82,101,110,97,109,101],"value":"&Rename"}, {"hash":44709525,"name":"tfrmmultirename.actclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmultirename.pas���������������������������������������������������������������0000644�0001750�0000144�00000321071�14743153644�016576� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Multi-Rename Tool dialog window Copyright (C) 2007-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Original comment: ---------------------------- Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : Pavel Letko (letcuv@centrum.cz) Advanced multi rename tool contributors: Copyright (C) 2007-2018 Alexander Koblov (alexx2000@mail.ru) } unit fMultiRename; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. LazUtf8, SysUtils, Classes, Graphics, Forms, StdCtrls, Menus, Controls, LCLType, StringHashList, Grids, ExtCtrls, Buttons, ActnList, EditBtn, KASButton, KASToolPanel, //DC DCXmlConfig, uOSForms, uRegExprW, uFileProperty, uFormCommands, uFileSourceSetFilePropertyOperation, DCStringHashListUtf8, uClassesEx, uFile, uFileSource, DCClassesUtf8, uHotkeyManager; const HotkeysCategoryMultiRename = 'MultiRename'; // <--Not displayed to user, stored in .scf (Shortcut Configuration File) type { TMultiRenamePreset } TMultiRenamePreset = class(TObject) private FPresetName: string; FFileName: string; FExtension: string; FFileNameStyle: integer; FExtensionStyle: integer; FFind: string; FReplace: string; FRegExp: boolean; FUseSubs: boolean; FCaseSens: Boolean; FOnlyFirst: Boolean; FCounter: string; FInterval: string; FWidth: integer; FLog: boolean; FLogFile: string; FLogAppend: boolean; public property PresetName: string read FPresetName write FPresetName; property FileName: string read FFileName write FFileName; property Extension: string read FExtension write FExtension; property FileNameStyle: integer read FFileNameStyle write FFileNameStyle; property ExtensionStyle: integer read FExtensionStyle write FExtensionStyle; property Find: string read FFind write FFind; property Replace: string read FReplace write FReplace; property RegExp: boolean read FRegExp write FRegExp; property UseSubs: boolean read FUseSubs write FUseSubs; property CaseSens: Boolean read FCaseSens write FCaseSens; property OnlyFirst: Boolean read FOnlyFirst write FOnlyFirst; property Counter: string read FCounter write FCounter; property Interval: string read FInterval write FInterval; property Width: integer read FWidth write FWidth; property Log: boolean read FLog write FLog; property LogFile: string read FLogFile write FLogFile; property LogAppend: boolean read FLogAppend write FLogAppend; constructor Create; destructor Destroy; override; end; { TMultiRenamePresetList } TMultiRenamePresetList = class(TList) private function GetMultiRenamePreset(Index: integer): TMultiRenamePreset; public property MultiRenamePreset[Index: integer]: TMultiRenamePreset read GetMultiRenamePreset; procedure Delete(Index: integer); procedure Clear; override; function Find(sPresetName: string): integer; end; { tTargetForMask } //Used to indicate of a mask is used for the "Filename" or the "Extension". tTargetForMask = (tfmFilename, tfmExtension); { tRenameMaskToUse } //Used as a parameter type to indicate the kind of field the mask is related to. tRenameMaskToUse = (rmtuFilename, rmtuExtension, rmtuCounter, rmtuDate, rmtuTime, rmtuPlugins); { tSourceOfInformation } tSourceOfInformation = (soiFilename, soiExtension, soiCounter, soiGUID, soiVariable, soiDate, soiTime, soiPlugins, soiFullName, soiPath); { tMenuActionStyle } //Used to help to group common or similar action done for each mask. tMenuActionStyle = (masStraight, masXCharacters, masXYCharacters, masAskVariable, masDirectorySelector); { TfrmMultiRename } TfrmMultiRename = class(TAloneForm, IFormCommands) cbCaseSens: TCheckBox; cbRegExp: TCheckBox; cbUseSubs: TCheckBox; cbOnlyFirst: TCheckBox; pnlFindReplace: TPanel; pnlButtons: TPanel; StringGrid: TStringGrid; pnlOptions: TPanel; pnlOptionsLeft: TPanel; gbMaska: TGroupBox; lbName: TLabel; cbName: TComboBox; btnAnyNameMask: TKASButton; cbNameMaskStyle: TComboBox; lbExt: TLabel; cbExt: TComboBox; btnAnyExtMask: TKASButton; cmbExtensionStyle: TComboBox; gbPresets: TGroupBox; cbPresets: TComboBox; btnPresets: TKASButton; spltMainSplitter: TSplitter; pnlOptionsRight: TKASToolPanel; gbFindReplace: TGroupBox; lbFind: TLabel; edFind: TEdit; lbReplace: TLabel; edReplace: TEdit; gbCounter: TGroupBox; lbStNb: TLabel; edPoc: TEdit; lbInterval: TLabel; edInterval: TEdit; lbWidth: TLabel; cmbxWidth: TComboBox; btnRestore: TBitBtn; btnRename: TBitBtn; btnConfig: TBitBtn; btnEditor: TBitBtn; btnClose: TBitBtn; cbLog: TCheckBox; cbLogAppend: TCheckBox; fneRenameLogFileFilename: TFileNameEdit; btnRelativeRenameLogFile: TSpeedButton; btnViewRenameLogFile: TSpeedButton; mmMainMenu: TMainMenu; miActions: TMenuItem; miResetAll: TMenuItem; miEditor: TMenuItem; miLoadNamesFromFile: TMenuItem; miEditNames: TMenuItem; miEditNewNames: TMenuItem; miSeparator1: TMenuItem; miConfiguration: TMenuItem; miSeparator2: TMenuItem; miRename: TMenuItem; miClose: TMenuItem; pmPresets: TPopupMenu; pmFloatingMainMaskMenu: TPopupMenu; pmDynamicMasks: TPopupMenu; pmEditDirect: TPopupMenu; mnuLoadFromFile: TMenuItem; mnuEditNames: TMenuItem; mnuEditNewNames: TMenuItem; pmPathToBeRelativeToHelper: TPopupMenu; actList: TActionList; actResetAll: TAction; actInvokeEditor: TAction; actLoadNamesFromFile: TAction; actLoadNamesFromClipboard: TAction; actEditNames: TAction; actEditNewNames: TAction; actConfig: TAction; actRename: TAction; actClose: TAction; actShowPresetsMenu: TAction; actDropDownPresetList: TAction; actLoadLastPreset: TAction; actLoadPreset: TAction; actLoadPreset1: TAction; actLoadPreset2: TAction; actLoadPreset3: TAction; actLoadPreset4: TAction; actLoadPreset5: TAction; actLoadPreset6: TAction; actLoadPreset7: TAction; actLoadPreset8: TAction; actLoadPreset9: TAction; actSavePreset: TAction; actSavePresetAs: TAction; actRenamePreset: TAction; actDeletePreset: TAction; actSortPresets: TAction; actAnyNameMask: TAction; actNameNameMask: TAction; actExtNameMask: TAction; actDateNameMask: TAction; actTimeNameMask: TAction; actCtrNameMask: TAction; actPlgnNameMask: TAction; actClearNameMask: TAction; actAnyExtMask: TAction; actNameExtMask: TAction; actExtExtMask: TAction; actDateExtMask: TAction; actTimeExtMask: TAction; actCtrExtMask: TAction; actPlgnExtMask: TAction; actClearExtMask: TAction; actInvokeRelativePath: TAction; actViewRenameLogFile: TAction; procedure FormCreate({%H-}Sender: TObject); procedure FormCloseQuery({%H-}Sender: TObject; var CanClose: boolean); procedure FormClose({%H-}Sender: TObject; var CloseAction: TCloseAction); procedure FormShow(Sender: TObject); procedure StringGridKeyDown({%H-}Sender: TObject; var Key: word; Shift: TShiftState); procedure StringGridMouseDown({%H-}Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: integer); procedure StringGridMouseUp({%H-}Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: integer); procedure StringGridSelection({%H-}Sender: TObject; {%H-}aCol, aRow: integer); procedure StringGridTopLeftChanged({%H-}Sender: TObject); procedure cbNameStyleChange({%H-}Sender: TObject); procedure cbPresetsChange({%H-}Sender: TObject); procedure cbPresetsCloseUp({%H-}Sender: TObject); procedure edFindChange({%H-}Sender: TObject); procedure edReplaceChange({%H-}Sender: TObject); procedure cbRegExpChange({%H-}Sender: TObject); procedure edPocChange({%H-}Sender: TObject); procedure edIntervalChange({%H-}Sender: TObject); procedure cbLogClick({%H-}Sender: TObject); procedure actExecute(Sender: TObject); procedure actInvokeRelativePathExecute(Sender: TObject); private IniPropStorage: TIniPropStorageEx; FCommands: TFormCommands; FActuallyRenamingFile: boolean; FSourceRow: integer; FMoveRow: boolean; FFileSource: IFileSource; FFiles: TFiles; FNewNames: TStringHashListUtf8; FOldNames: TStringHashListUtf8; FNames: TStringList; FslVariableNames, FslVariableValues, FslVariableSuggestionName, FslVariableSuggestionValue: TStringList; FRegExp: TRegExprW; FFindText: TStringList; FReplaceText: TStringList; FPluginDispatcher: tTargetForMask; FMultiRenamePresetList: TMultiRenamePresetList; FParamPresetToLoadOnStart: string; FLastPreset: string; FbRememberLog, FbRememberAppend: boolean; FsRememberRenameLogFilename: string; FLog: TStringListEx; property Commands: TFormCommands read FCommands implements IFormCommands; procedure RestoreProperties(Sender: TObject); procedure SetConfigurationState(bConfigurationSaved: boolean); function GetPresetNameForCommand(const Params: array of string): string; procedure LoadPresetsXml(AConfig: TXmlConfig); function isOkToLosePresetModification: boolean; procedure SavePreset(PresetName: string); procedure SavePresetsXml(AConfig: TXmlConfig); procedure SavePresets; procedure DeletePreset(PresetName: string); procedure FillPresetsList(const WantedSelectedPresetName: string = ''); procedure RefreshActivePresetCommands; procedure InitializeMaskHelper; procedure PopulateMainMenu; procedure PopulateFilenameMenu(AMenuSomething: TComponent); procedure PopulateExtensionMenu(AMenuSomething: TComponent); procedure BuildMaskMenu(AMenuSomething: TComponent; iTarget: tTargetForMask; iMenuTypeMask: tRenameMaskToUse); procedure BuildPresetsMenu(AMenuSomething: TComponent); procedure BuildMenuAndPopup(iTarget: tTargetForMask; iMenuTypeMask: tRenameMaskToUse); function GetMaskCategoryName(aRenameMaskToUse: tRenameMaskToUse): string; function GetImageIndexCategoryName(aRenameMaskToUse: tRenameMaskToUse): integer; function GetCategoryAction(TargetForMask: tTargetForMask; aRenameMask: tRenameMaskToUse): TAction; function AppendSubMenuToThisMenu(ATargetMenu: TMenuItem; sCaption: string; iImageIndex: integer): TMenuItem; function AppendActionMenuToThisMenu(ATargetMenu: TMenuItem; paramAction: TAction): TMenuItem; procedure MenuItemXCharactersMaskClick(Sender: TObject); procedure MenuItemVariableMaskClick(Sender: TObject); procedure MenuItemStraightMaskClick(Sender: TObject); procedure MenuItemDirectorySelectorMaskClick(Sender: TObject); procedure PopupDynamicMenuAtThisControl(APopUpMenu: TPopupMenu; AControl: TControl); procedure miPluginClick(Sender: TObject); procedure InsertMask(const Mask: string; edChoose: TComboBox); procedure InsertMask(const Mask: string; TargetForMask: tTargetForMask); function sReplace(sMask: string; ItemNr: integer): string; function sReplaceXX(const sFormatStr, sOrig: string): string; function sReplaceVariable(const sFormatStr: string): string; function sReplaceBadChars(const sPath: string): string; function IsLetter(AChar: AnsiChar): boolean; function ApplyStyle(InputString: string; Style: integer): string; function FirstCharToUppercaseUTF8(InputString: string): string; function FirstCharOfFirstWordToUppercaseUTF8(InputString: string): string; function FirstCharOfEveryWordToUppercaseUTF8(InputString: string): string; procedure LoadNamesFromList(const AFileList: TStrings); procedure LoadNamesFromFile(const AFileName: string); function FreshText(ItemIndex: integer): string; function sHandleFormatString(const sFormatStr: string; ItemNr: integer): string; procedure SetFilePropertyResult(Index: integer; aFile: TFile; aTemplate: TFileProperty; Result: TSetFilePropertyResult); procedure SetOutputGlobalRenameLogFilename; public { Public declarations } constructor Create(TheOwner: TComponent); override; //Not used for actual renaming file. Present there just for the "TfrmOptionsHotkeys.FillCommandList" function who need to create the form in memory to extract internal commands from it. constructor Create(TheOwner: TComponent; aFileSource: IFileSource; var aFiles: TFiles; const paramPreset: string); reintroduce; destructor Destroy; override; published procedure cm_ResetAll(const Params: array of string); procedure cm_InvokeEditor(const {%H-}Params: array of string); procedure cm_LoadNamesFromFile(const {%H-}Params: array of string); procedure cm_LoadNamesFromClipboard(const {%H-}Params: array of string); procedure cm_EditNames(const {%H-}Params: array of string); procedure cm_EditNewNames(const {%H-}Params: array of string); procedure cm_Config(const {%H-}Params: array of string); procedure cm_Rename(const {%H-}Params: array of string); procedure cm_Close(const {%H-}Params: array of string); procedure cm_ShowPresetsMenu(const {%H-}Params: array of string); procedure cm_DropDownPresetList(const {%H-}Params: array of string); procedure cm_LoadPreset(const Params: array of string); procedure cm_LoadLastPreset(const {%H-}Params: array of string); procedure cm_LoadPreset1(const {%H-}Params: array of string); procedure cm_LoadPreset2(const {%H-}Params: array of string); procedure cm_LoadPreset3(const {%H-}Params: array of string); procedure cm_LoadPreset4(const {%H-}Params: array of string); procedure cm_LoadPreset5(const {%H-}Params: array of string); procedure cm_LoadPreset6(const {%H-}Params: array of string); procedure cm_LoadPreset7(const {%H-}Params: array of string); procedure cm_LoadPreset8(const {%H-}Params: array of string); procedure cm_LoadPreset9(const {%H-}Params: array of string); procedure cm_SavePreset(const Params: array of string); procedure cm_SavePresetAs(const Params: array of string); procedure cm_RenamePreset(const Params: array of string); procedure cm_DeletePreset(const Params: array of string); procedure cm_SortPresets(const Params: array of string); procedure cm_AnyNameMask(const {%H-}Params: array of string); procedure cm_NameNameMask(const {%H-}Params: array of string); procedure cm_ExtNameMask(const {%H-}Params: array of string); procedure cm_CtrNameMask(const {%H-}Params: array of string); procedure cm_DateNameMask(const {%H-}Params: array of string); procedure cm_TimeNameMask(const {%H-}Params: array of string); procedure cm_PlgnNameMask(const {%H-}Params: array of string); procedure cm_ClearNameMask(const {%H-}Params: array of string); procedure cm_AnyExtMask(const {%H-}Params: array of string); procedure cm_NameExtMask(const {%H-}Params: array of string); procedure cm_ExtExtMask(const {%H-}Params: array of string); procedure cm_CtrExtMask(const {%H-}Params: array of string); procedure cm_DateExtMask(const {%H-}Params: array of string); procedure cm_TimeExtMask(const {%H-}Params: array of string); procedure cm_PlgnExtMask(const {%H-}Params: array of string); procedure cm_ClearExtMask(const {%H-}Params: array of string); procedure cm_ViewRenameLogFile(const {%H-}Params: array of string); end; {initialization function} function ShowMultiRenameForm(aFileSource: IFileSource; var aFiles: TFiles; const PresetToLoad: string = ''): boolean; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Dialogs, Math, Clipbrd, //DC fMain, uFileSourceOperation, uOperationsManager, uOSUtils, uDCUtils, uDebug, DCOSUtils, DCStrUtils, uLng, uGlobs, uSpecialDir, uFileProcs, uShowForm, fSelectTextRange, fSelectPathRange, uShowMsg, uFileFunctions, dmCommonData, fMultiRenameWait, fSortAnything, DCConvertEncoding; type tMaskHelper = record sMenuItem: string; sKeyword: string; MenuActionStyle: tMenuActionStyle; iMenuType: tRenameMaskToUse; iSourceOfInformation: tSourceOfInformation; end; const sPresetsSection = 'MultiRenamePresets'; sLASTPRESET = '{BC322BF1-2185-47F6-9F99-D27ED1E23E53}'; sFRESHMASKS = '{40422152-9D05-469E-9B81-791AF8C369D8}'; iTARGETMASK = $00000001; sREFRESHCOMMANDS = 'refreshcommands'; sDEFAULTLOGFILENAME = 'default.log'; CONFIG_NOTSAVED = False; CONFIG_SAVED = True; NBMAXHELPERS = 30; var //Sequence of operation to add a new mask: // 1. Add its entry below in the "MaskHelpers" array. // 2. Go immediately set its translatable string for the user in the function "InitializeMaskHelper" and the text in unit "uLng". // 3. When editing "InitializeMaskHelper", make sure to update the TWO columns of indexes. // 4. In the procedure "BuildMaskMenu", there is good chance you need to associated to the "AMenuItem.OnClick" the correct function based on "MaskHelpers[iSeekIndex].MenuActionStyle". // 5. If it's a NEW procedure, you'll need to write it. You may check "MenuItemXCharactersMaskClick" for inspiration. // 6. There is good chance you need to edit "sHandleFormatString" to add your new mask and action to do with it. MaskHelpers: array[0..pred(NBMAXHELPERS)] of tMaskHelper = ( (sMenuItem: ''; sKeyword: '[N]'; MenuActionStyle: masStraight; iMenuType: rmtuFilename; iSourceOfInformation: soiFilename), (sMenuItem: ''; sKeyword: '[Nx]'; MenuActionStyle: masXCharacters; iMenuType: rmtuFilename; iSourceOfInformation: soiFilename), (sMenuItem: ''; sKeyword: '[Nx:y]'; MenuActionStyle: masXYCharacters; iMenuType: rmtuFilename; iSourceOfInformation: soiFilename), (sMenuItem: ''; sKeyword: '[A]'; MenuActionStyle: masStraight; iMenuType: rmtuFilename; iSourceOfInformation: soiFullName), (sMenuItem: ''; sKeyword: '[Ax:y]'; MenuActionStyle: masXYCharacters; iMenuType: rmtuFilename; iSourceOfInformation: soiFullName), (sMenuItem: ''; sKeyword: '[P]'; MenuActionStyle: masDirectorySelector; iMenuType: rmtuFilename; iSourceOfInformation: soiPath), (sMenuItem: ''; sKeyword: '[E]'; MenuActionStyle: masStraight; iMenuType: rmtuExtension; iSourceOfInformation: soiExtension), (sMenuItem: ''; sKeyword: '[Ex]'; MenuActionStyle: masXCharacters; iMenuType: rmtuExtension; iSourceOfInformation: soiExtension), (sMenuItem: ''; sKeyword: '[Ex:y]'; MenuActionStyle: masXYCharacters; iMenuType: rmtuExtension; iSourceOfInformation: soiExtension), (sMenuItem: ''; sKeyword: '[C]'; MenuActionStyle: masStraight; iMenuType: rmtuCounter; iSourceOfInformation: soiCounter), (sMenuItem: ''; sKeyword: '[G]'; MenuActionStyle: masStraight; iMenuType: rmtuCounter; iSourceOfInformation: soiGUID), (sMenuItem: ''; sKeyword: '[V:x]'; MenuActionStyle: masAskVariable; iMenuType: rmtuCounter; iSourceOfInformation: soiVariable), (sMenuItem: ''; sKeyword: '[Y]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[YYYY]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[M]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[MM]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[MMM]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[MMMM]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[D]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[DD]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[DDD]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[DDDD]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[YYYY]-[MM]-[DD]'; MenuActionStyle: masStraight; iMenuType: rmtuDate; iSourceOfInformation: soiDate), (sMenuItem: ''; sKeyword: '[h]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime), (sMenuItem: ''; sKeyword: '[hh]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime), (sMenuItem: ''; sKeyword: '[n]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime), (sMenuItem: ''; sKeyword: '[nn]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime), (sMenuItem: ''; sKeyword: '[s]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime), (sMenuItem: ''; sKeyword: '[ss]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime), (sMenuItem: ''; sKeyword: '[hh]-[nn]-[ss]'; MenuActionStyle: masStraight; iMenuType: rmtuTime; iSourceOfInformation: soiTime) ); { TMultiRenamePreset.Create } constructor TMultiRenamePreset.Create; begin FPresetName := ''; FFileName := '[N]'; FExtension := '[E]'; FFileNameStyle := 0; FExtensionStyle := 0; FFind := ''; FReplace := ''; FRegExp := False; FUseSubs := False; FCaseSens := False; FOnlyFirst := False; FCounter := '1'; FInterval := '1'; FWidth := 0; FLog := False; FLogFile := ''; FLogAppend := False; end; { TMultiRenamePreset.Destory } // Not so necessary, but useful with a breakpoint to validate object is really free from memory when deleting an element from the list of clearing that list. destructor TMultiRenamePreset.Destroy; begin inherited Destroy; end; { TMultiRenamePresetList.GetMultiRenamePreset } function TMultiRenamePresetList.GetMultiRenamePreset(Index: integer): TMultiRenamePreset; begin Result := TMultiRenamePreset(Items[Index]); end; { TMultiRenamePresetList.Delete } procedure TMultiRenamePresetList.Delete(Index: integer); begin TMultiRenamePreset(Items[Index]).Free; inherited Delete(Index); end; { TMultiRenamePresetList.Clear } procedure TMultiRenamePresetList.Clear; var Index: integer; begin for Index := pred(Count) downto 0 do TMultiRenamePreset(Items[Index]).Free; inherited Clear; end; { TMultiRenamePresetList.Find } function TMultiRenamePresetList.Find(sPresetName: string): integer; var iSeeker: integer = 0; begin Result := -1; while (Result = -1) and (iSeeker < Count) do if SameText(sPresetName, MultiRenamePreset[iSeeker].PresetName) then Result := iSeeker else Inc(iSeeker); end; { TfrmMultiRename.Create } //Not used for actual renaming file. //Present there just for the "TfrmOptionsHotkeys.FillCommandList" function who need to create the form in memory to extract internal commands from it. constructor TfrmMultiRename.Create(TheOwner: TComponent); var FDummyFiles: TFiles; begin FDummyFiles := TFiles.Create(''); //Will be self destroyed by the "TfrmMultiRename" object itself. Create(TheOwner, nil, FDummyFiles, ''); end; { TfrmMultiRename.Create } constructor TfrmMultiRename.Create(TheOwner: TComponent; aFileSource: IFileSource; var aFiles: TFiles; const paramPreset: string); begin FActuallyRenamingFile := False; FRegExp := TRegExprW.Create; FNames := TStringList.Create; FFindText := TStringList.Create; FFindText.StrictDelimiter := True; FFindText.Delimiter := '|'; FReplaceText := TStringList.Create; FReplaceText.StrictDelimiter := True; FReplaceText.Delimiter := '|'; FMultiRenamePresetList := TMultiRenamePresetList.Create; FNewNames := TStringHashListUtf8.Create(FileNameCaseSensitive); FOldNames := TStringHashListUtf8.Create(FileNameCaseSensitive); FslVariableNames := TStringList.Create; FslVariableValues := TStringList.Create; FslVariableSuggestionName := TStringList.Create; FslVariableSuggestionValue := TStringList.Create; FFileSource := aFileSource; FFiles := aFiles; aFiles := nil; FSourceRow := -1; FMoveRow := False; FParamPresetToLoadOnStart := paramPreset; inherited Create(TheOwner); FCommands := TFormCommands.Create(Self, actList); end; { TfrmMultiRename.Destroy } destructor TfrmMultiRename.Destroy; begin inherited Destroy; FMultiRenamePresetList.Clear; FreeAndNil(FMultiRenamePresetList); FreeAndNil(FNewNames); FreeAndNil(FOldNames); FreeAndNil(FslVariableNames); FreeAndNil(FslVariableValues); FreeAndNil(FslVariableSuggestionName); FreeAndNil(FslVariableSuggestionValue); FreeAndNil(FFiles); FreeAndNil(FNames); FreeAndNil(FRegExp); FreeAndNil(FFindText); FreeAndNil(FReplaceText); end; { TfrmMultiRename.FormCreate } procedure TfrmMultiRename.FormCreate({%H-}Sender: TObject); var HMMultiRename: THMForm; begin // Localize File name style ComboBox ParseLineToList(rsMulRenFileNameStyleList, cbNameMaskStyle.Items); ParseLineToList(rsMulRenFileNameStyleList, cmbExtensionStyle.Items); InitializeMaskHelper; // Set row count StringGrid.RowCount := FFiles.Count + 1; StringGrid.FocusRectVisible := False; // Initialize property storage IniPropStorage := InitPropStorage(Self); IniPropStorage.OnRestoreProperties := @RestoreProperties; IniPropStorage.StoredValues.Add.DisplayName := 'lsvwFile_Columns.Item0_Width'; IniPropStorage.StoredValues.Add.DisplayName := 'lsvwFile_Columns.Item1_Width'; IniPropStorage.StoredValues.Add.DisplayName := 'lsvwFile_Columns.Item2_Width'; if gMulRenShowMenuBarOnTop then Menu := mmMainMenu else Menu := nil; if not gIconsInMenus then begin mmMainMenu.Images := nil; pmDynamicMasks.Images := nil; pmEditDirect.Images := nil; pmPresets.Images := nil; end; HMMultiRename := HotMan.Register(Self, HotkeysCategoryMultiRename); HMMultiRename.RegisterActionList(actList); cbExt.Items.Assign(glsRenameExtMaskHistory); cbName.Items.Assign(glsRenameNameMaskHistory); // Set default values for controls. cm_ResetAll([sREFRESHCOMMANDS + '=0']); // Initialize presets. LoadPresetsXml(gConfig); if (FParamPresetToLoadOnStart <> '') and (FMultiRenamePresetList.Find(FParamPresetToLoadOnStart) <> -1) then begin FillPresetsList(FParamPresetToLoadOnStart); end else begin case gMulRenLaunchBehavior of mrlbLastMaskUnderLastOne: FillPresetsList(sLASTPRESET); mrlbLastPreset: FillPresetsList(FLastPreset); mrlbFreshNew: FillPresetsList(sFRESHMASKS); end; end; PopulateMainMenu; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathToBeRelativeToHelper, mp_PATHHELPER, nil); FPluginDispatcher := tfmFilename; end; { TfrmMultiRename.FormCloseQuery } procedure TfrmMultiRename.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin if not isOkToLosePresetModification then CanClose := False; end; { TfrmMultiRename.FormClose } procedure TfrmMultiRename.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin SavePreset(sLASTPRESET); glsRenameExtMaskHistory.Assign(cbExt.Items); glsRenameNameMaskHistory.Assign(cbName.Items); CloseAction := caFree; with StringGrid.Columns do begin IniPropStorage.StoredValue['lsvwFile_Columns.Item0_Width'] := IntToStr(Items[0].Width); IniPropStorage.StoredValue['lsvwFile_Columns.Item1_Width'] := IntToStr(Items[1].Width); IniPropStorage.StoredValue['lsvwFile_Columns.Item2_Width'] := IntToStr(Items[2].Width); end; end; procedure TfrmMultiRename.FormShow(Sender: TObject); var APoint: TPoint; begin {$IF DEFINED(LCLQT5)} gbPresets.Constraints.MaxHeight:= cbPresets.Height + (gbPresets.Height - gbPresets.ClientHeight) + gbPresets.ChildSizing.TopBottomSpacing * 2; {$ENDIF} APoint:= TPoint.Create(cbUseSubs.Left, 0); fneRenameLogFileFilename.BorderSpacing.Left:= gbFindReplace.ClientToParent(APoint, pnlOptionsRight).X; end; { TfrmMultiRename.StringGridKeyDown } procedure TfrmMultiRename.StringGridKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); var tmpFile: TFile; DestRow: integer; begin DestRow := StringGrid.Row; if (Shift = []) then begin if Key = VK_DELETE then begin FFiles.Delete(DestRow - 1); StringGrid.RowCount:= StringGrid.RowCount - 1; if FFiles.Count = 0 then begin OnCloseQuery:= nil; Close; end else begin StringGridTopLeftChanged(StringGrid); end; end; end; if (Shift = [ssShift]) then begin case Key of VK_UP: begin DestRow := StringGrid.Row - 1; end; VK_DOWN: begin DestRow := StringGrid.Row + 1; end; end; if (DestRow <> StringGrid.Row) and (0 < DestRow) and (DestRow < StringGrid.RowCount) then begin tmpFile := FFiles.Items[DestRow - 1]; FFiles.Items[DestRow - 1] := FFiles.Items[StringGrid.Row - 1]; FFiles.Items[StringGrid.Row - 1] := tmpFile; StringGridTopLeftChanged(StringGrid); end; end; end; { TfrmMultiRename.StringGridMouseDown } procedure TfrmMultiRename.StringGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); var SourceCol: integer = 0; begin if (Button = mbLeft) then begin StringGrid.MouseToCell(X, Y, SourceCol, FSourceRow); if (FSourceRow > 0) then begin FMoveRow := True; end; end; end; { TfrmMultiRename.StringGridMouseUp } procedure TfrmMultiRename.StringGridMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); begin if Button = mbLeft then begin FMoveRow := False; end; end; { TfrmMultiRename.StringGridSelection } procedure TfrmMultiRename.StringGridSelection(Sender: TObject; aCol, aRow: integer); var tmpFile: TFile; begin if FMoveRow and (aRow <> FSourceRow) then begin tmpFile := FFiles.Items[aRow - 1]; FFiles.Items[aRow - 1] := FFiles.Items[FSourceRow - 1]; FFiles.Items[FSourceRow - 1] := tmpFile; FSourceRow := aRow; StringGridTopLeftChanged(StringGrid); end; end; { TfrmMultiRename.StringGridTopLeftChanged } procedure TfrmMultiRename.StringGridTopLeftChanged(Sender: TObject); var I, iRowCount: integer; begin iRowCount := StringGrid.TopRow + StringGrid.VisibleRowCount; if iRowCount > FFiles.Count then iRowCount := FFiles.Count; for I := StringGrid.TopRow to iRowCount do begin StringGrid.Cells[0, I] := FFiles[I - 1].Name; StringGrid.Cells[1, I] := FreshText(I - 1); StringGrid.Cells[2, I] := FFiles[I - 1].Path; end; end; { TfrmMultiRename.cbNameStyleChange } procedure TfrmMultiRename.cbNameStyleChange(Sender: TObject); begin StringGridTopLeftChanged(StringGrid); if ActiveControl <> cbPresets then SetConfigurationState(CONFIG_NOTSAVED); end; { TfrmMultiRename.cbPresetsChange } procedure TfrmMultiRename.cbPresetsChange(Sender: TObject); begin if cbPresets.ItemIndex <> 0 then cm_LoadPreset(['name=' + cbPresets.Items.Strings[cbPresets.ItemIndex]]) else cm_LoadPreset(['name=' + sLASTPRESET]); RefreshActivePresetCommands; end; { TfrmMultiRename.cbPresetsCloseUp } procedure TfrmMultiRename.cbPresetsCloseUp(Sender: TObject); begin if cbName.Enabled and gbMaska.Enabled then ActiveControl := cbName; cbName.SelStart := UTF8Length(cbName.Text); end; { TfrmMultiRename.edFindChange } procedure TfrmMultiRename.edFindChange(Sender: TObject); begin if cbRegExp.Checked then FRegExp.Expression := CeUtf8ToUtf16(edFind.Text) else begin FFindText.DelimitedText := edFind.Text; end; SetConfigurationState(CONFIG_NOTSAVED); StringGridTopLeftChanged(StringGrid); end; { TfrmMultiRename.edReplaceChange } procedure TfrmMultiRename.edReplaceChange(Sender: TObject); begin if not cbRegExp.Checked then begin FReplaceText.DelimitedText := edReplace.Text; end; SetConfigurationState(CONFIG_NOTSAVED); StringGridTopLeftChanged(StringGrid); end; { TfrmMultiRename.cbRegExpChange } procedure TfrmMultiRename.cbRegExpChange(Sender: TObject); begin if cbRegExp.Checked then cbUseSubs.Checked := boolean(cbUseSubs.Tag) else begin cbUseSubs.Tag := integer(cbUseSubs.Checked); cbUseSubs.Checked := False; end; cbUseSubs.Enabled := cbRegExp.Checked; edFindChange(edFind); edReplaceChange(edReplace); end; { TfrmMultiRename.edPocChange } procedure TfrmMultiRename.edPocChange(Sender: TObject); var c: integer; begin c := StrToIntDef(edPoc.Text, maxint); if c = MaxInt then with edPoc do //editbox only for numbers begin Text := '1'; SelectAll; end; SetConfigurationState(CONFIG_NOTSAVED); StringGridTopLeftChanged(StringGrid); end; { TfrmMultiRename.edIntervalChange } procedure TfrmMultiRename.edIntervalChange(Sender: TObject); var c: integer; begin c := StrToIntDef(edInterval.Text, maxint); if c = MaxInt then with edInterval do //editbox only for numbers begin Text := '1'; SelectAll; end; SetConfigurationState(CONFIG_NOTSAVED); StringGridTopLeftChanged(StringGrid); end; { TfrmMultiRename.cbLogClick } procedure TfrmMultiRename.cbLogClick(Sender: TObject); begin fneRenameLogFileFilename.Enabled := cbLog.Checked; actInvokeRelativePath.Enabled := cbLog.Checked; actViewRenameLogFile.Enabled := cbLog.Checked; cbLogAppend.Enabled := cbLog.Checked; SetConfigurationState(CONFIG_NOTSAVED); end; { TfrmMultiRename.actExecute } procedure TfrmMultiRename.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; { TfrmMultiRename.actInvokeRelativePathExecute } procedure TfrmMultiRename.actInvokeRelativePathExecute(Sender: TObject); begin fneRenameLogFileFilename.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneRenameLogFileFilename, pfFILE); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmMultiRename.RestoreProperties } procedure TfrmMultiRename.RestoreProperties(Sender: TObject); begin with StringGrid.Columns do begin Items[0].Width := StrToIntDef(IniPropStorage.StoredValue['lsvwFile_Columns.Item0_Width'], Items[0].Width); Items[1].Width := StrToIntDef(IniPropStorage.StoredValue['lsvwFile_Columns.Item1_Width'], Items[1].Width); Items[2].Width := StrToIntDef(IniPropStorage.StoredValue['lsvwFile_Columns.Item2_Width'], Items[2].Width); end; end; { TfrmMultiRename.SetConfigurationState } procedure TfrmMultiRename.SetConfigurationState(bConfigurationSaved: boolean); begin if not cbPresets.DroppedDown then begin if bConfigurationSaved or (cbPresets.ItemIndex <> 0) then begin if cbPresets.Enabled <> bConfigurationSaved then begin cbPresets.Enabled := bConfigurationSaved; end; end; end; end; { TfrmMultiRename.GetPresetNameForCommand } // Wanted preset may be given via "name=presetname" or via "index=indexno". function TfrmMultiRename.GetPresetNameForCommand(const Params: array of string): string; var Param, sValue: string; iIndex: integer; begin Result := ''; for Param in Params do begin if GetParamValue(Param, 'name', sValue) then Result := sValue else if GetParamValue(Param, 'index', sValue) then begin iIndex := StrToIntDef(sValue, -1); if (iIndex >= 0) and (iIndex < cbPresets.items.Count) then if iIndex = 0 then Result := sLASTPRESET else Result := cbPresets.Items.Strings[iIndex]; end; end; end; { TfrmMultiRename.LoadPresetsXml } procedure TfrmMultiRename.LoadPresetsXml(AConfig: TXmlConfig); var PresetName: string; AMultiRenamePreset: TMultiRenamePreset; ANode: TXmlNode; PresetIndex: integer; begin FMultiRenamePresetList.Clear; ANode := AConfig.FindNode(AConfig.RootNode, sPresetsSection); FLastPreset := AConfig.GetValue(ANode, 'LastPreset', sLASTPRESET); ANode := AConfig.FindNode(ANode, 'Presets'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('Preset') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', PresetName) then begin if FMultiRenamePresetList.Find(PresetName) = -1 then //Make sure we don't load preset with the same name. begin AMultiRenamePreset := TMultiRenamePreset.Create; AMultiRenamePreset.PresetName := PresetName; FMultiRenamePresetList.Add(AMultiRenamePreset); AMultiRenamePreset.FileName := AConfig.GetValue(ANode, 'Filename', '[N]'); AMultiRenamePreset.Extension := AConfig.GetValue(ANode, 'Extension', '[E]'); AMultiRenamePreset.FileNameStyle := AConfig.GetValue(ANode, 'FilenameStyle', 0); AMultiRenamePreset.ExtensionStyle := AConfig.GetValue(ANode, 'ExtensionStyle', 0); AMultiRenamePreset.Find := AConfig.GetValue(ANode, 'Find', ''); AMultiRenamePreset.Replace := AConfig.GetValue(ANode, 'Replace', ''); AMultiRenamePreset.RegExp := AConfig.GetValue(ANode, 'RegExp', False); AMultiRenamePreset.UseSubs := AConfig.GetValue(ANode, 'UseSubs', False); AMultiRenamePreset.CaseSens := AConfig.GetValue(ANode, 'CaseSensitive', False); AMultiRenamePreset.OnlyFirst := AConfig.GetValue(ANode, 'OnlyFirst', False); AMultiRenamePreset.Counter := AConfig.GetValue(ANode, 'Counter', '1'); AMultiRenamePreset.Interval := AConfig.GetValue(ANode, 'Interval', '1'); AMultiRenamePreset.Width := AConfig.GetValue(ANode, 'Width', 0); AMultiRenamePreset.Log := AConfig.GetValue(ANode, 'Log/Enabled', False); AMultiRenamePreset.LogAppend := AConfig.GetValue(ANode, 'Log/Append', False); AMultiRenamePreset.LogFile := AConfig.GetValue(ANode, 'Log/File', ''); end; end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; end; //Make sure the "sLASTPRESET" is at position 0. PresetIndex := FMultiRenamePresetList.Find(sLASTPRESET); if PresetIndex <> 0 then begin if PresetIndex <> -1 then begin //If it's present but not at zero, move it to 0. FMultiRenamePresetList.Move(PresetIndex, 0); end else begin AMultiRenamePreset := TMultiRenamePreset.Create; AMultiRenamePreset.PresetName := sLASTPRESET; FMultiRenamePresetList.Insert(0, AMultiRenamePreset); end; end; end; { TfrmMultiRename.isOkToLosePresetModification } function TfrmMultiRename.isOkToLosePresetModification: boolean; var MyMsgResult: TMyMsgResult; begin Result := False; if (cbPresets.ItemIndex <= 0) or (cbPresets.Enabled) or (not Visible) then Result := True else begin case gMulRenExitModifiedPreset of mrempIgnoreSaveLast: begin Result := True; end; mrempSaveAutomatically: begin if cbPresets.ItemIndex > 0 then cm_SavePreset(['name=' + cbPresets.Items.Strings[cbPresets.ItemIndex]]); Result := True; end; mrempPromptUser: begin MyMsgResult := msgYesNoCancel(Format(rsMulRenSaveModifiedPreset, [cbPresets.Items.Strings[cbPresets.ItemIndex]]), msmbCancel); case MyMsgResult of mmrYes: begin cm_SavePreset([]); Result := True; end; mmrNo: Result := True; mmrCancel: ; end; end; end; end; end; { TfrmMultiRename.SavePreset } procedure TfrmMultiRename.SavePreset(PresetName: string); var PresetIndex: integer; AMultiRenamePresetObject: TMultiRenamePreset; begin if PresetName <> '' then begin PresetIndex := FMultiRenamePresetList.Find(PresetName); if PresetIndex = -1 then begin AMultiRenamePresetObject := TMultiRenamePreset.Create; AMultiRenamePresetObject.PresetName := PresetName; PresetIndex := FMultiRenamePresetList.Add(AMultiRenamePresetObject); end; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].FileName := cbName.Text; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Extension := cbExt.Text; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].FileNameStyle := cbNameMaskStyle.ItemIndex; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].ExtensionStyle := cmbExtensionStyle.ItemIndex; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Find := edFind.Text; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Replace := edReplace.Text; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].RegExp := cbRegExp.Checked; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].UseSubs := cbUseSubs.Checked; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].CaseSens := cbCaseSens.Checked; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].OnlyFirst := cbOnlyFirst.Checked; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Counter := edPoc.Text; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Interval := edInterval.Text; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Width := cmbxWidth.ItemIndex; case gMulRenSaveRenamingLog of mrsrlPerPreset: begin FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Log := cbLog.Checked; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogFile := fneRenameLogFileFilename.FileName; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogAppend := cbLogAppend.Checked; end; mrsrlAppendSameLog: begin FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Log := FbRememberLog; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogAppend := FbRememberAppend; FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogFile := FsRememberRenameLogFilename; end; end; SavePresets; end; end; { TfrmMultiRename.SavePresetsXml } procedure TfrmMultiRename.SavePresetsXml(AConfig: TXmlConfig); var i: integer; ANode, SubNode: TXmlNode; begin ANode := AConfig.FindNode(AConfig.RootNode, sPresetsSection, True); AConfig.ClearNode(ANode); if cbPresets.ItemIndex = 0 then AConfig.SetValue(ANode, 'LastPreset', sLASTPRESET) else AConfig.SetValue(ANode, 'LastPreset', cbPresets.Items.Strings[cbPresets.ItemIndex]); ANode := AConfig.FindNode(ANode, 'Presets', True); for i := 0 to pred(FMultiRenamePresetList.Count) do begin SubNode := AConfig.AddNode(ANode, 'Preset'); AConfig.AddValue(SubNode, 'Name', FMultiRenamePresetList.MultiRenamePreset[i].PresetName); AConfig.AddValue(SubNode, 'Filename', FMultiRenamePresetList.MultiRenamePreset[i].FileName); AConfig.AddValue(SubNode, 'Extension', FMultiRenamePresetList.MultiRenamePreset[i].Extension); AConfig.AddValue(SubNode, 'FilenameStyle', FMultiRenamePresetList.MultiRenamePreset[i].FileNameStyle); AConfig.AddValue(SubNode, 'ExtensionStyle', FMultiRenamePresetList.MultiRenamePreset[i].ExtensionStyle); AConfig.AddValue(SubNode, 'Find', FMultiRenamePresetList.MultiRenamePreset[i].Find); AConfig.AddValue(SubNode, 'Replace', FMultiRenamePresetList.MultiRenamePreset[i].Replace); AConfig.AddValue(SubNode, 'RegExp', FMultiRenamePresetList.MultiRenamePreset[i].RegExp); AConfig.AddValue(SubNode, 'UseSubs', FMultiRenamePresetList.MultiRenamePreset[i].UseSubs); AConfig.AddValue(SubNode, 'CaseSensitive', FMultiRenamePresetList.MultiRenamePreset[i].CaseSens); AConfig.AddValue(SubNode, 'OnlyFirst', FMultiRenamePresetList.MultiRenamePreset[i].OnlyFirst); AConfig.AddValue(SubNode, 'Counter', FMultiRenamePresetList.MultiRenamePreset[i].Counter); AConfig.AddValue(SubNode, 'Interval', FMultiRenamePresetList.MultiRenamePreset[i].Interval); AConfig.AddValue(SubNode, 'Width', FMultiRenamePresetList.MultiRenamePreset[i].Width); AConfig.SetValue(SubNode, 'Log/Enabled', FMultiRenamePresetList.MultiRenamePreset[i].Log); AConfig.SetValue(SubNode, 'Log/Append', FMultiRenamePresetList.MultiRenamePreset[i].LogAppend); AConfig.SetValue(SubNode, 'Log/File', FMultiRenamePresetList.MultiRenamePreset[i].LogFile); end; end; { TfrmMultiRename.SavePresets } procedure TfrmMultiRename.SavePresets; begin SavePresetsXml(gConfig); gConfig.Save; end; { TfrmMultiRename.DeletePreset } procedure TfrmMultiRename.DeletePreset(PresetName: string); var PresetIndex: integer; begin if PresetName <> '' then begin PresetIndex := FMultiRenamePresetList.Find(PresetName); if PresetIndex <> -1 then begin FMultiRenamePresetList.Delete(PresetIndex); SavePresets; end; end; end; { TfrmMultiRename.FillPresetsList } //We fill the preset drop list with the element in memory. //If it's specified when called, will attempt to load the specified preset in parameter. //If it's not specified, will attempt to re-select the one that was initially selected. //If nothing is still selected, we'll select the [Last One]. procedure TfrmMultiRename.FillPresetsList(const WantedSelectedPresetName: string = ''); var i: integer; sRememberSelection, PresetName: string; begin sRememberSelection := ''; if WantedSelectedPresetName <> '' then sRememberSelection := WantedSelectedPresetName; if sRememberSelection = '' then if cbPresets.ItemIndex <> -1 then if cbPresets.ItemIndex < cbPresets.Items.Count then sRememberSelection := cbPresets.Items.Strings[cbPresets.ItemIndex]; cbPresets.Clear; cbPresets.Items.Add(rsMulRenLastPreset); for i := 0 to pred(FMultiRenamePresetList.Count) do begin PresetName := FMultiRenamePresetList.MultiRenamePreset[i].PresetName; if (PresetName <> sLASTPRESET) then if cbPresets.Items.IndexOf(PresetName) = -1 then cbPresets.Items.Add(PresetName); end; if (WantedSelectedPresetName = sLASTPRESET) or (WantedSelectedPresetName = sFRESHMASKS) then cbPresets.ItemIndex := 0 else if sRememberSelection <> '' then if cbPresets.Items.IndexOf(sRememberSelection) <> -1 then cbPresets.ItemIndex := cbPresets.Items.IndexOf(sRememberSelection); if cbPresets.ItemIndex = -1 then if cbPresets.Items.Count > 0 then cbPresets.ItemIndex := 0; if WantedSelectedPresetName <> sFRESHMASKS then begin cbPresetsChange(cbPresets); RefreshActivePresetCommands; end; end; { TfrmMultiRename.RefreshActivePresetCommands } procedure TfrmMultiRename.RefreshActivePresetCommands; begin //"Load last preset" is always available since it's the [Last One]. actLoadPreset1.Enabled := (cbPresets.Items.Count > 1) and (cbPresets.Enabled); actLoadPreset2.Enabled := (cbPresets.Items.Count > 2) and (cbPresets.Enabled); actLoadPreset3.Enabled := (cbPresets.Items.Count > 3) and (cbPresets.Enabled); actLoadPreset4.Enabled := (cbPresets.Items.Count > 4) and (cbPresets.Enabled); actLoadPreset5.Enabled := (cbPresets.Items.Count > 5) and (cbPresets.Enabled); actLoadPreset6.Enabled := (cbPresets.Items.Count > 6) and (cbPresets.Enabled); actLoadPreset7.Enabled := (cbPresets.Items.Count > 7) and (cbPresets.Enabled); actLoadPreset8.Enabled := (cbPresets.Items.Count > 8) and (cbPresets.Enabled); actLoadPreset9.Enabled := (cbPresets.Items.Count > 9) and (cbPresets.Enabled); actSavePreset.Enabled := (cbPresets.ItemIndex > 0); //"Save as is always available so we may save the [Last One] actRenamePreset.Enabled := (cbPresets.ItemIndex > 0); actDeletePreset.Enabled := (cbPresets.ItemIndex > 0); end; { TfrmMultiRename.InitializeMaskHelper } procedure TfrmMultiRename.InitializeMaskHelper; begin if MaskHelpers[00].sMenuItem = '' then //"MaskHelpers" are no tin the object but generic, so we just need to initialize once. begin MaskHelpers[00].sMenuItem := MaskHelpers[00].sKeyword + ' ' + rsMulRenMaskName; MaskHelpers[01].sMenuItem := MaskHelpers[01].sKeyword + ' ' + rsMulRenMaskCharAtPosX; MaskHelpers[02].sMenuItem := MaskHelpers[02].sKeyword + ' ' + rsMulRenMaskCharAtPosXtoY; MaskHelpers[03].sMenuItem := MaskHelpers[03].sKeyword + ' ' + rsMulRenMaskFullName; MaskHelpers[04].sMenuItem := MaskHelpers[04].sKeyword + ' ' + rsMulRenMaskFullNameCharAtPosXtoY; MaskHelpers[05].sMenuItem := MaskHelpers[05].sKeyword + ' ' + rsMulRenMaskParent; MaskHelpers[06].sMenuItem := MaskHelpers[06].sKeyword + ' ' + rsMulRenMaskExtension; MaskHelpers[07].sMenuItem := MaskHelpers[07].sKeyword + ' ' + rsMulRenMaskCharAtPosX; MaskHelpers[08].sMenuItem := MaskHelpers[08].sKeyword + ' ' + rsMulRenMaskCharAtPosXtoY; MaskHelpers[09].sMenuItem := MaskHelpers[09].sKeyword + ' ' + rsMulRenMaskCounter; MaskHelpers[10].sMenuItem := MaskHelpers[10].sKeyword + ' ' + rsMulRenMaskGUID; MaskHelpers[11].sMenuItem := MaskHelpers[11].sKeyword + ' ' + rsMulRenMaskVarOnTheFly; MaskHelpers[12].sMenuItem := MaskHelpers[12].sKeyword + ' ' + rsMulRenMaskYear2Digits; MaskHelpers[13].sMenuItem := MaskHelpers[13].sKeyword + ' ' + rsMulRenMaskYear4Digits; MaskHelpers[14].sMenuItem := MaskHelpers[14].sKeyword + ' ' + rsMulRenMaskMonth; MaskHelpers[15].sMenuItem := MaskHelpers[15].sKeyword + ' ' + rsMulRenMaskMonth2Digits; MaskHelpers[16].sMenuItem := MaskHelpers[16].sKeyword + ' ' + rsMulRenMaskMonthAbrev; MaskHelpers[17].sMenuItem := MaskHelpers[17].sKeyword + ' ' + rsMulRenMaskMonthComplete; MaskHelpers[18].sMenuItem := MaskHelpers[18].sKeyword + ' ' + rsMulRenMaskDay; MaskHelpers[19].sMenuItem := MaskHelpers[19].sKeyword + ' ' + rsMulRenMaskDay2Digits; MaskHelpers[20].sMenuItem := MaskHelpers[20].sKeyword + ' ' + rsMulRenMaskDOWAbrev; MaskHelpers[21].sMenuItem := MaskHelpers[21].sKeyword + ' ' + rsMulRenMaskDOWComplete; MaskHelpers[22].sMenuItem := MaskHelpers[22].sKeyword + ' ' + rsMulRenMaskCompleteDate; MaskHelpers[23].sMenuItem := MaskHelpers[23].sKeyword + ' ' + rsMulRenMaskHour; MaskHelpers[24].sMenuItem := MaskHelpers[24].sKeyword + ' ' + rsMulRenMaskHour2Digits; MaskHelpers[25].sMenuItem := MaskHelpers[25].sKeyword + ' ' + rsMulRenMaskMin; MaskHelpers[26].sMenuItem := MaskHelpers[26].sKeyword + ' ' + rsMulRenMaskMin2Digits; MaskHelpers[27].sMenuItem := MaskHelpers[27].sKeyword + ' ' + rsMulRenMaskSec; MaskHelpers[28].sMenuItem := MaskHelpers[28].sKeyword + ' ' + rsMulRenMaskSec2Digits; MaskHelpers[29].sMenuItem := MaskHelpers[29].sKeyword + ' ' + rsMulRenMaskCompleteTime; end; end; { TfrmMultiRename.PopulateMainMenu } // This main menu is not essential. // But it does not occupy a lot of pixels and may benefit to user to help to both discover and remember the keyboard shortcut by visualizing them. // Also, we populate it run-time to save work to valuable translators so they won't have to re-translate the same strings or to validate copies. procedure TfrmMultiRename.PopulateMainMenu; var miPresets, miMasks, miSubMasks: TMenuItem; begin btnAnyNameMask.Action := actAnyNameMask; btnAnyNameMask.Caption := '...'; btnAnyNameMask.Width := fneRenameLogFileFilename.ButtonWidth; btnAnyExtMask.Action := actAnyExtMask; btnAnyExtMask.Caption := '...'; btnAnyExtMask.Width := fneRenameLogFileFilename.ButtonWidth; btnRelativeRenameLogFile.Action := actInvokeRelativePath; btnRelativeRenameLogFile.Caption := ''; btnRelativeRenameLogFile.Width := fneRenameLogFileFilename.ButtonWidth; btnRelativeRenameLogFile.Hint := actInvokeRelativePath.Caption; btnViewRenameLogFile.Action := actViewRenameLogFile; btnViewRenameLogFile.Caption := ''; btnViewRenameLogFile.Width := fneRenameLogFileFilename.ButtonWidth; btnViewRenameLogFile.Hint := actViewRenameLogFile.Caption; btnPresets.Action := actShowPresetsMenu; btnPresets.Caption := ''; btnPresets.Hint := actShowPresetsMenu.Caption; btnPresets.Constraints.MinWidth := fneRenameLogFileFilename.ButtonWidth; miPresets := TMenuItem.Create(mmMainMenu); miPresets.Caption := gbPresets.Caption; mmMainMenu.Items.Add(miPresets); BuildPresetsMenu(miPresets); BuildPresetsMenu(pmPresets); miMasks := TMenuItem.Create(mmMainMenu); miMasks.Caption := gbMaska.Caption; mmMainMenu.Items.Add(miMasks); //We add the sub-menu for the filename masks miSubMasks := TMenuItem.Create(miMasks); miSubMasks.Caption := lbName.Caption; miSubMasks.ImageIndex := GetImageIndexCategoryName(rmtuFilename); miMasks.Add(miSubMasks); PopulateFilenameMenu(miSubMasks); //We add the sub-menu for the filename masks miSubMasks := TMenuItem.Create(miMasks); miSubMasks.Caption := lbExt.Caption; miSubMasks.ImageIndex := GetImageIndexCategoryName(rmtuExtension); miMasks.Add(miSubMasks); PopulateExtensionMenu(miSubMasks); end; { TfrmMultiRename.PopulateFilenameMenu } procedure TfrmMultiRename.PopulateFilenameMenu(AMenuSomething: TComponent); var localMenuItem, miSubMenu, miMenuItem: TMenuItem; begin if AMenuSomething.ClassType = TPopupMenu then localMenuItem := TPopupMenu(AMenuSomething).Items else if AMenuSomething.ClassType = TMenuItem then begin localMenuItem := TMenuItem(AMenuSomething); miMenuItem := TMenuItem.Create(localMenuItem); miMenuItem.Action := actAnyNameMask; localMenuItem.Add(miMenuItem); miMenuItem := TMenuItem.Create(localMenuItem); miMenuItem.Caption := '-'; localMenuItem.Add(miMenuItem); end else exit; miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuFilename), GetImageIndexCategoryName(rmtuFilename)); BuildMaskMenu(miSubMenu, tfmFilename, rmtuFilename); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuExtension), GetImageIndexCategoryName(rmtuExtension)); BuildMaskMenu(miSubMenu, tfmFilename, rmtuExtension); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuCounter), GetImageIndexCategoryName(rmtuCounter)); BuildMaskMenu(miSubMenu, tfmFilename, rmtuCounter); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuDate), GetImageIndexCategoryName(rmtuDate)); BuildMaskMenu(miSubMenu, tfmFilename, rmtuDate); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuTime), GetImageIndexCategoryName(rmtuTime)); BuildMaskMenu(miSubMenu, tfmFilename, rmtuTime); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuPlugins), GetImageIndexCategoryName(rmtuPlugins)); BuildMaskMenu(miSubMenu, tfmFilename, rmtuPlugins); AppendSubMenuToThisMenu(localMenuItem, '-', -1); AppendActionMenuToThisMenu(localMenuItem, actClearNameMask); AppendActionMenuToThisMenu(localMenuItem, actResetAll); end; { TfrmMultiRename.PopulateExtensionMenu } procedure TfrmMultiRename.PopulateExtensionMenu(AMenuSomething: TComponent); var localMenuItem, miSubMenu, miMenuItem: TMenuItem; begin if AMenuSomething.ClassType = TPopupMenu then localMenuItem := TPopupMenu(AMenuSomething).Items else if AMenuSomething.ClassType = TMenuItem then begin localMenuItem := TMenuItem(AMenuSomething); miMenuItem := TMenuItem.Create(localMenuItem); miMenuItem.Action := actAnyExtMask; localMenuItem.Add(miMenuItem); miMenuItem := TMenuItem.Create(localMenuItem); miMenuItem.Caption := '-'; localMenuItem.Add(miMenuItem); end else exit; miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuFilename), GetImageIndexCategoryName(rmtuFilename)); BuildMaskMenu(miSubMenu, tfmExtension, rmtuFilename); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuExtension), GetImageIndexCategoryName(rmtuExtension)); BuildMaskMenu(miSubMenu, tfmExtension, rmtuExtension); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuCounter), GetImageIndexCategoryName(rmtuCounter)); BuildMaskMenu(miSubMenu, tfmExtension, rmtuCounter); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuDate), GetImageIndexCategoryName(rmtuDate)); BuildMaskMenu(miSubMenu, tfmExtension, rmtuDate); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuTime), GetImageIndexCategoryName(rmtuTime)); BuildMaskMenu(miSubMenu, tfmExtension, rmtuTime); miSubMenu := AppendSubMenuToThisMenu(localMenuItem, GetMaskCategoryName(rmtuPlugins), GetImageIndexCategoryName(rmtuPlugins)); BuildMaskMenu(miSubMenu, tfmExtension, rmtuPlugins); AppendSubMenuToThisMenu(localMenuItem, '-', -1); AppendActionMenuToThisMenu(localMenuItem, actClearExtMask); AppendActionMenuToThisMenu(localMenuItem, actResetAll); end; { TfrmMultiRename.BuildMaskMenu } procedure TfrmMultiRename.BuildMaskMenu(AMenuSomething: TComponent; iTarget: tTargetForMask; iMenuTypeMask: tRenameMaskToUse); var iSeekIndex: integer; AMenuItem, localMenuItem: TMenuItem; actCategoryActionToAdd: TAction = nil; begin if AMenuSomething.ClassType = TPopupMenu then localMenuItem := TPopupMenu(AMenuSomething).Items else if AMenuSomething.ClassType = TMenuItem then localMenuItem := TMenuItem(AMenuSomething) else exit; localMenuItem.Clear; if AMenuSomething.ClassType = TMenuItem then begin actCategoryActionToAdd := GetCategoryAction(iTarget, iMenuTypeMask); if actCategoryActionToAdd <> nil then begin AMenuItem := TMenuItem.Create(AMenuSomething); AMenuItem.Action := actCategoryActionToAdd; localMenuItem.Add(AMenuItem); AMenuItem := TMenuItem.Create(AMenuSomething); AMenuItem.Caption := '-'; localMenuItem.Add(AMenuItem); end; end; for iSeekIndex := 0 to pred(NBMAXHELPERS) do begin if MaskHelpers[iSeekIndex].iMenuType = iMenuTypeMask then begin AMenuItem := TMenuItem.Create(AMenuSomething); AMenuItem.Caption := MaskHelpers[iSeekIndex].sMenuItem; AMenuItem.Tag := (iSeekIndex shl 16) or Ord(iTarget); AMenuItem.Hint := MaskHelpers[iSeekIndex].sKeyword; AMenuItem.ImageIndex := GetImageIndexCategoryName(MaskHelpers[iSeekIndex].iMenuType); case MaskHelpers[iSeekIndex].MenuActionStyle of masStraight: AMenuItem.OnClick := @MenuItemStraightMaskClick; masXCharacters, masXYCharacters: AMenuItem.OnClick := @MenuItemXCharactersMaskClick; masAskVariable: AMenuItem.OnClick := @MenuItemVariableMaskClick; masDirectorySelector: AMenuItem.OnClick := @MenuItemDirectorySelectorMaskClick; end; localMenuItem.Add(AMenuItem); end; end; if rmtuPlugins = iMenuTypeMask then begin FPluginDispatcher := iTarget; FillContentFieldMenu(AMenuSomething, @miPluginClick); //No need to clear "pmDynamicMasks" because "FillContentFieldMenu" do it itself. if AMenuSomething.ClassType = TMenuItem then begin //We need to add the mask category menu item at the end since "FillContentFieldMenu" clears our "pmDynamicMasks". AMenuItem := TMenuItem.Create(AMenuSomething); AMenuItem.Caption := '-'; localMenuItem.Insert(0, AMenuItem); AMenuItem := TMenuItem.Create(AMenuSomething); AMenuItem.Action := actCategoryActionToAdd; localMenuItem.Insert(0, AMenuItem); end; end; end; { TfrmMultiRename.BuildPresetsMenu } procedure TfrmMultiRename.BuildPresetsMenu(AMenuSomething: TComponent); var localMenuItem: TMenuItem; begin if AMenuSomething.ClassType = TPopupMenu then localMenuItem := TPopupMenu(AMenuSomething).Items else if AMenuSomething.ClassType = TMenuItem then begin localMenuItem := TMenuItem(AMenuSomething); AppendActionMenuToThisMenu(localMenuItem, actShowPresetsMenu); AppendSubMenuToThisMenu(localMenuItem, '-', -1); end else exit; AppendActionMenuToThisMenu(localMenuItem, actDropDownPresetList); AppendSubMenuToThisMenu(localMenuItem, '-', -1); AppendActionMenuToThisMenu(localMenuItem, actLoadLastPreset); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset1); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset2); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset3); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset4); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset5); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset6); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset7); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset8); AppendActionMenuToThisMenu(localMenuItem, actLoadPreset9); AppendSubMenuToThisMenu(localMenuItem, '-', -1); AppendActionMenuToThisMenu(localMenuItem, actSavePreset); AppendActionMenuToThisMenu(localMenuItem, actSavePresetAs); AppendActionMenuToThisMenu(localMenuItem, actRenamePreset); AppendActionMenuToThisMenu(localMenuItem, actDeletePreset); AppendActionMenuToThisMenu(localMenuItem, actSortPresets); end; { TfrmMultiRename.BuildMenuAndPopup } procedure TfrmMultiRename.BuildMenuAndPopup(iTarget: tTargetForMask; iMenuTypeMask: tRenameMaskToUse); begin BuildMaskMenu(pmDynamicMasks, iTarget, iMenuTypeMask); case iTarget of tfmFilename: PopupDynamicMenuAtThisControl(pmDynamicMasks, cbName); tfmExtension: PopupDynamicMenuAtThisControl(pmDynamicMasks, cbExt); end; end; { TfrmMultiRename.GetMaskCategoryName } function TfrmMultiRename.GetMaskCategoryName(aRenameMaskToUse: tRenameMaskToUse): string; begin Result := ''; case aRenameMaskToUse of rmtuFilename: Result := rsMulRenFilename; rmtuExtension: Result := rsMulRenExtension; rmtuCounter: Result := rsMulRenCounter; rmtuDate: Result := rsMulRenDate; rmtuTime: Result := rsMulRenTime; rmtuPlugins: Result := rsMulRenPlugins; end; end; { TfrmMultiRename.GetImageIndexCategoryName } function TfrmMultiRename.GetImageIndexCategoryName(aRenameMaskToUse: tRenameMaskToUse): integer; begin Result := -1; case aRenameMaskToUse of rmtuFilename: Result := 20; rmtuExtension: Result := 21; rmtuCounter: Result := 22; rmtuDate: Result := 23; rmtuTime: Result := 24; rmtuPlugins: Result := 25; end; end; { TfrmMultiRename.GetCategoryAction } function TfrmMultiRename.GetCategoryAction(TargetForMask: tTargetForMask; aRenameMask: tRenameMaskToUse): TAction; begin Result := nil; case TargetForMask of tfmFilename: begin case aRenameMask of rmtuFilename: Result := actNameNameMask; rmtuExtension: Result := actExtNameMask; rmtuCounter: Result := actCtrNameMask; rmtuDate: Result := actDateNameMask; rmtuTime: Result := actTimeNameMask; rmtuPlugins: Result := actPlgnNameMask; end; end; tfmExtension: begin case aRenameMask of rmtuFilename: Result := actNameExtMask; rmtuExtension: Result := actExtExtMask; rmtuCounter: Result := actCtrExtMask; rmtuDate: Result := actDateExtMask; rmtuTime: Result := actTimeExtMask; rmtuPlugins: Result := actPlgnExtMask; end; end; end; end; { TfrmMultiRename.AppendSubMenuToThisMenu } function TfrmMultiRename.AppendSubMenuToThisMenu(ATargetMenu: TMenuItem; sCaption: string; iImageIndex: integer): TMenuItem; begin Result := TMenuItem.Create(ATargetMenu); Result.ImageIndex := iImageIndex; if sCaption <> '' then Result.Caption := sCaption; ATargetMenu.Add(Result); end; { TfrmMultiRename.AppendActionMenuToThisMenu } function TfrmMultiRename.AppendActionMenuToThisMenu(ATargetMenu: TMenuItem; paramAction: TAction): TMenuItem; begin Result := TMenuItem.Create(ATargetMenu); Result.Action := paramAction; ATargetMenu.Add(Result); end; { TfrmMultiRename.MenuItemXCharactersMaskClick } procedure TfrmMultiRename.MenuItemXCharactersMaskClick(Sender: TObject); var sSourceToSelectFromText, sPrefix: string; sResultingMaskValue: string = ''; iMaskHelperIndex: integer; begin iMaskHelperIndex := TMenuItem(Sender).Tag shr 16; if iMaskHelperIndex < length(MaskHelpers) then begin sSourceToSelectFromText := ''; case MaskHelpers[iMaskHelperIndex].iSourceOfInformation of soiFilename: begin sSourceToSelectFromText := FFiles[pred(StringGrid.Row)].NameNoExt; sPrefix := 'N'; end; soiExtension: begin sSourceToSelectFromText := FFiles[pred(StringGrid.Row)].Extension; sPrefix := 'E'; end; soiFullName: begin sSourceToSelectFromText := FFiles[pred(StringGrid.Row)].FullPath; sPrefix := 'A'; end; end; if ShowSelectTextRangeDlg(Self, Caption, sSourceToSelectFromText, sPrefix, sResultingMaskValue) then InsertMask(sResultingMaskValue, tTargetForMask(TMenuItem(Sender).Tag and iTARGETMASK)); end; end; { TfrmMultiRename.MenuItemDirectorySelectorMaskClick } procedure TfrmMultiRename.MenuItemDirectorySelectorMaskClick(Sender: TObject); var sSourceToSelectFromText, sPrefix: string; sResultingMaskValue: string = ''; iMaskHelperIndex: integer; begin iMaskHelperIndex := TMenuItem(Sender).Tag shr 16; if iMaskHelperIndex < length(MaskHelpers) then begin sSourceToSelectFromText := ''; case MaskHelpers[iMaskHelperIndex].iSourceOfInformation of soiPath: begin sSourceToSelectFromText := FFiles[pred(StringGrid.Row)].Path; sPrefix := 'P'; end; end; if ShowSelectPathRangeDlg(Self, Caption, sSourceToSelectFromText, sPrefix, sResultingMaskValue) then InsertMask(sResultingMaskValue, tTargetForMask(TMenuItem(Sender).Tag and iTARGETMASK)); end; end; { TfrmMultiRename.MenuItemVariableMaskClick } procedure TfrmMultiRename.MenuItemVariableMaskClick(Sender: TObject); var sVariableName: string; begin sVariableName := rsSimpleWordVariable; if InputQuery(rsMulRenDefineVariableName, rsMulRenEnterNameForVar, sVariableName) then begin if sVariableName = '' then sVariableName := rsSimpleWordVariable; InsertMask('[V:' + sVariableName + ']', tTargetForMask(TMenuItem(Sender).Tag and iTARGETMASK)); end; end; { TfrmMultiRename.MenuItemStraightMaskClick } procedure TfrmMultiRename.MenuItemStraightMaskClick(Sender: TObject); var sMaks: string; begin sMaks := TMenuItem(Sender).Hint; case tTargetForMask(TMenuItem(Sender).Tag and iTARGETMASK) of tfmFilename: begin InsertMask(sMaks, cbName); cbName.SetFocus; end; tfmExtension: begin InsertMask(sMaks, cbExt); cbExt.SetFocus; end; end; end; { TfrmMultiRename.PopupDynamicMenuAtThisControl } procedure TfrmMultiRename.PopupDynamicMenuAtThisControl(APopUpMenu: TPopupMenu; AControl: TControl); var PopupPoint: TPoint; begin PopupPoint := AControl.Parent.ClientToScreen(Point(AControl.Left + AControl.Width - 5, AControl.Top + AControl.Height - 5)); APopUpMenu.PopUp(PopupPoint.X, PopupPoint.Y); end; { TfrmMultiRename.miPluginClick } procedure TfrmMultiRename.miPluginClick(Sender: TObject); var sMask: string; MenuItem: TMenuItem absolute Sender; begin case MenuItem.Tag of 0: begin sMask := '[=DC().' + MenuItem.Hint + '{}]'; end; 1: begin sMask := '[=Plugin(' + MenuItem.Parent.Caption + ').' + MenuItem.Hint + '{}]'; end; 2: begin sMask := '[=Plugin(' + MenuItem.Parent.Parent.Caption + ').' + MenuItem.Parent.Hint + '{' + MenuItem.Hint + '}]'; end; 3: begin sMask := '[=DC().' + MenuItem.Parent.Hint + '{' + MenuItem.Hint + '}]'; end; end; case FPluginDispatcher of tfmFilename: begin InsertMask(sMask, cbName); cbName.SetFocus; end; tfmExtension: begin InsertMask(sMask, cbExt); cbExt.SetFocus; end; end; end; { TfrmMultiRename.InsertMask } procedure TfrmMultiRename.InsertMask(const Mask: string; edChoose: TComboBox); var sTmp, sInitialString: string; I: integer; begin sInitialString := edChoose.Text; if edChoose.SelLength > 0 then edChoose.SelText := Mask // Replace selected text else begin sTmp := edChoose.Text; I := edChoose.SelStart + 1; // Insert on current position UTF8Insert(Mask, sTmp, I); Inc(I, UTF8Length(Mask)); edChoose.Text := sTmp; edChoose.SelStart := I - 1; end; if sInitialString <> edChoose.Text then cbNameStyleChange(edChoose); end; { TfrmMultiRename.InsertMask } procedure TfrmMultiRename.InsertMask(const Mask: string; TargetForMask: tTargetForMask); begin case TargetForMask of tfmFilename: begin InsertMask(Mask, cbName); cbName.SetFocus; end; tfmExtension: begin InsertMask(Mask, cbExt); cbExt.SetFocus; end; end; end; {TfrmMultiRename.sReplace } function TfrmMultiRename.sReplace(sMask: string; ItemNr: integer): string; var iStart, iEnd: integer; begin Result := ''; while Length(sMask) > 0 do begin iStart := Pos('[', sMask); if iStart > 0 then begin iEnd := Pos(']', sMask, iStart + 1); if iEnd > 0 then begin Result := Result + Copy(sMask, 1, iStart - 1) + sHandleFormatString(Copy(sMask, iStart + 1, iEnd - iStart - 1), ItemNr); Delete(sMask, 1, iEnd); end else Break; end else Break; end; Result := Result + sMask; end; { TfrmMultiRename.sReplaceXX } function TfrmMultiRename.sReplaceXX(const sFormatStr, sOrig: string): string; var iFrom, iTo, iDelim: integer; begin if Length(sFormatStr) = 1 then Result := sOrig else begin iDelim := Pos(':', sFormatStr); if iDelim = 0 then begin iDelim := Pos(',', sFormatStr); // Not found if iDelim = 0 then begin iFrom := StrToIntDef(Copy(sFormatStr, 2, MaxInt), 1); if iFrom < 0 then iFrom := sOrig.Length + iFrom + 1; iTo := iFrom; end // Range e.g. N1,3 (from 1, 3 symbols) else begin iFrom := StrToIntDef(Copy(sFormatStr, 2, iDelim - 2), 1); iDelim := Abs(StrToIntDef(Copy(sFormatStr, iDelim + 1, MaxSmallint), MaxSmallint)); if iFrom >= 0 then iTo := iDelim + iFrom - 1 else begin iTo := sOrig.Length + iFrom + 1; iFrom := Max(iTo - iDelim + 1, 1); end; end; end // Range e.g. N1:2 (from 1 to 2) else begin iFrom := StrToIntDef(Copy(sFormatStr, 2, iDelim - 2), 1); if iFrom < 0 then iFrom := sOrig.Length + iFrom + 1; iTo := StrToIntDef(Copy(sFormatStr, iDelim + 1, MaxSmallint), MaxSmallint); if iTo < 0 then iTo := sOrig.Length + iTo + 1; ; if iTo < iFrom then begin iDelim := iTo; iTo := iFrom; iFrom := iDelim; end; end; Result := UTF8Copy(sOrig, iFrom, iTo - iFrom + 1); end; end; { TfrmMultiRename.sReplaceVariable } function TfrmMultiRename.sReplaceVariable(const sFormatStr: string): string; var iDelim, iVariableIndex, iVariableSuggestionIndex: integer; sVariableName: string = ''; sVariableValue: string = ''; begin Result := ''; iDelim := Pos(':', sFormatStr); if iDelim <> 0 then sVariableName := copy(sFormatStr, succ(iDelim), length(sFormatStr) - iDelim) else sVariableName := rsSimpleWordVariable; iVariableIndex := FslVariableNames.IndexOf(sVariableName); if iVariableIndex = -1 then begin iVariableSuggestionIndex := FslVariableSuggestionName.IndexOf(sVariableName); if iVariableSuggestionIndex <> -1 then sVariableValue := FslVariableSuggestionValue.Strings[iVariableSuggestionIndex] else sVariableValue := sVariableName; if InputQuery(rsMulRenDefineVariableValue, Format(rsMulRenEnterValueForVar, [sVariableName]), sVariableValue) then begin FslVariableNames.Add(sVariableName); iVariableIndex := FslVariableValues.Add(sVariableValue); if iVariableSuggestionIndex = -1 then begin FslVariableSuggestionName.Add(sVariableName); FslVariableSuggestionValue.Add(sVariableValue); end; end else begin FActuallyRenamingFile := False; exit; end; end; Result := FslVariableValues.Strings[iVariableIndex]; end; { TfrmMultiRename.sReplaceBadChars }//Replace bad path chars in string function TfrmMultiRename.sReplaceBadChars(const sPath: string): string; const {$IFDEF MSWINDOWS} ForbiddenChars: set of char = ['<', '>', ':', '"', '/', '\', '|', '?', '*']; {$ELSE} ForbiddenChars: set of char = ['/']; {$ENDIF} var Index: integer; begin Result := ''; for Index := 1 to Length(sPath) do if not (sPath[Index] in ForbiddenChars) then Result += sPath[Index] else Result += gMulRenInvalidCharReplacement; end; { TfrmMultiRename.IsLetter } function TfrmMultiRename.IsLetter(AChar: AnsiChar): boolean; begin Result := // Ascii letters ((AChar < #128) and (((AChar >= 'a') and (AChar <= 'z')) or ((AChar >= 'A') and (AChar <= 'Z')))) or // maybe Ansi or UTF8 (AChar >= #128); end; { TfrmMultiRename.ApplyStyle } // Applies style (uppercase, lowercase, etc.) to a string. function TfrmMultiRename.ApplyStyle(InputString: string; Style: integer): string; begin case Style of 1: Result := UTF8UpperCase(InputString); 2: Result := UTF8LowerCase(InputString); 3: Result := FirstCharOfFirstWordToUppercaseUTF8(InputString); 4: Result := FirstCharOfEveryWordToUppercaseUTF8(InputString); else Result := InputString; end; end; { TfrmMultiRename.FirstCharToUppercaseUTF8 } // Changes first char to uppercase and the rest to lowercase function TfrmMultiRename.FirstCharToUppercaseUTF8(InputString: string): string; var FirstChar: string; begin if UTF8Length(InputString) > 0 then begin Result := UTF8LowerCase(InputString); FirstChar := UTF8Copy(Result, 1, 1); UTF8Delete(Result, 1, 1); Result := UTF8UpperCase(FirstChar) + Result; end else Result := ''; end; { TfrmMultiRename.FirstCharOfFirstWordToUppercaseUTF8 } // Changes first char of first word to uppercase and the rest to lowercase function TfrmMultiRename.FirstCharOfFirstWordToUppercaseUTF8(InputString: string): string; var SeparatorPos: integer; begin InputString := UTF8LowerCase(InputString); Result := ''; // Search for first letter. for SeparatorPos := 1 to Length(InputString) do if IsLetter(InputString[SeparatorPos]) then break; Result := Copy(InputString, 1, SeparatorPos - 1) + FirstCharToUppercaseUTF8(Copy(InputString, SeparatorPos, Length(InputString) - SeparatorPos + 1)); end; { TfrmMultiRename.FirstCharOfEveryWordToUppercaseUTF8 } // Changes first char of every word to uppercase and the rest to lowercase function TfrmMultiRename.FirstCharOfEveryWordToUppercaseUTF8(InputString: string): string; var SeparatorPos: integer; begin InputString := UTF8LowerCase(InputString); Result := ''; while InputString <> '' do begin // Search for first non-letter (word separator). for SeparatorPos := 1 to Length(InputString) do if not IsLetter(InputString[SeparatorPos]) then break; Result := Result + FirstCharToUppercaseUTF8(Copy(InputString, 1, SeparatorPos)); Delete(InputString, 1, SeparatorPos); end; end; procedure TfrmMultiRename.LoadNamesFromList(const AFileList: TStrings); begin if AFileList.Count <> FFiles.Count then begin msgError(Format(rsMulRenWrongLinesNumber, [AFileList.Count, FFiles.Count])); end else begin FNames.Assign(AFileList); gbMaska.Enabled := False; gbPresets.Enabled := False; gbCounter.Enabled := False; StringGridTopLeftChanged(StringGrid); end; end; { TfrmMultiRename.LoadNamesFromFile } procedure TfrmMultiRename.LoadNamesFromFile(const AFileName: string); var AFileList: TStringListEx; begin AFileList := TStringListEx.Create; try AFileList.LoadFromFile(AFileName); LoadNamesFromList(AFileList); except on E: Exception do msgError(E.Message); end; AFileList.Free; end; { TfrmMultiRename.FreshText } function TfrmMultiRename.FreshText(ItemIndex: integer): string; var I: integer; bError: boolean; wsText: UnicodeString; wsReplace: UnicodeString; Flags: TReplaceFlags = []; sTmpName, sTmpExt: string; begin bError := False; if FNames.Count > 0 then Result := FNames[ItemIndex] else begin // Use mask sTmpName := sReplace(cbName.Text, ItemIndex); sTmpExt := sReplace(cbExt.Text, ItemIndex); // Join Result := sTmpName; if sTmpExt <> '' then Result := Result + '.' + sTmpExt; end; // Find and replace if (edFind.Text <> '') then begin if cbRegExp.Checked then try wsText:= CeUtf8ToUtf16(Result); wsReplace:= CeUtf8ToUtf16(edReplace.Text); FRegExp.ModifierI := not cbCaseSens.Checked; if not cbOnlyFirst.Checked then begin Result := CeUtf16ToUtf8(FRegExp.Replace(wsText, wsReplace, cbUseSubs.Checked)); end else if FRegExp.Exec(wsText) then begin Delete(wsText, FRegExp.MatchPos[0], FRegExp.MatchLen[0]); if cbUseSubs.Checked then Insert(FRegExp.Substitute(wsReplace), wsText, FRegExp.MatchPos[0]) else begin Insert(wsReplace, wsText, FRegExp.MatchPos[0]); end; Result:= CeUtf16ToUtf8(wsText); end; except Result := rsMsgErrRegExpSyntax; bError := True; end else begin if not cbOnlyFirst.Checked then Flags:= [rfReplaceAll]; if not cbCaseSens.Checked then Flags+= [rfIgnoreCase]; // Many at once, split find and replace by | if (FReplaceText.Count = 0) then FReplaceText.Add(''); for I := 0 to FFindText.Count - 1 do Result := UTF8StringReplace(Result, FFindText[I], FReplaceText[Min(I, FReplaceText.Count - 1)], Flags); end; end; // File name style sTmpExt := ExtractFileExt(Result); sTmpName := Copy(Result, 1, Length(Result) - Length(sTmpExt)); sTmpName := ApplyStyle(sTmpName, cbNameMaskStyle.ItemIndex); sTmpExt := ApplyStyle(sTmpExt, cmbExtensionStyle.ItemIndex); Result := sTmpName + sTmpExt; actRename.Enabled := not bError; if bError then begin edFind.Color := clRed; edFind.Font.Color := clWhite; end else begin edFind.Color := clWindow; edFind.Font.Color := clWindowText; end; end; { TfrmMultiRename.sHandleFormatString } function TfrmMultiRename.sHandleFormatString(const sFormatStr: string; ItemNr: integer): string; var aFile: TFile; Index: int64; Counter: int64; Dirs: TStringArray; begin Result := ''; if Length(sFormatStr) > 0 then begin aFile := FFiles[ItemNr]; case sFormatStr[1] of '[', ']': begin Result := sFormatStr; end; 'N': begin Result := sReplaceXX(sFormatStr, aFile.NameNoExt); end; 'E': begin Result := sReplaceXX(sFormatStr, aFile.Extension); end; 'A': begin Result := sReplaceBadChars(sReplaceXX(sFormatStr, aFile.FullPath)); end; 'G': begin Result := GuidToString(DCGetNewGUID); end; 'V': begin if FActuallyRenamingFile then Result := sReplaceVariable(sFormatStr) else Result := '[' + sFormatStr + ']'; end; 'C': begin // Check for start value after C, e.g. C12 if not TryStrToInt64(Copy(sFormatStr, 2, MaxInt), Index) then Index := StrToInt64Def(edPoc.Text, 1); Counter := Index + StrToInt64Def(edInterval.Text, 1) * ItemNr; Result := Format('%.' + cmbxWidth.Items[cmbxWidth.ItemIndex] + 'd', [Counter]); end; 'P': // sub path index begin Index := StrToIntDef(Copy(sFormatStr, 2, MaxInt), 0); Dirs := (aFile.Path + ' ').Split([PathDelim]); Dirs[High(Dirs)] := EmptyStr; if Index < 0 then Result := Dirs[Max(0, High(Dirs) + Index)] else Result := Dirs[Min(Index, High(Dirs))]; end; '=': begin Result := sReplaceBadChars(FormatFileFunction(UTF8Copy(sFormatStr, 2, UTF8Length(sFormatStr) - 1), FFiles.Items[ItemNr], FFileSource, True)); end; else begin // Assume it is date/time formatting string ([h][n][s][Y][M][D]). with FFiles.Items[ItemNr] do if fpModificationTime in SupportedProperties then try Result := SysToUTF8(FormatDateTime(sFormatStr, ModificationTime)); except Result := sFormatStr; end; end; end; end; end; { TfrmMultiRename.SetFilePropertyResult } procedure TfrmMultiRename.SetFilePropertyResult(Index: integer; aFile: TFile; aTemplate: TFileProperty; Result: TSetFilePropertyResult); var sFilenameForLog, S: string; begin with TFileNameProperty(aTemplate) do begin if cbLog.Checked then if gMulRenFilenameWithFullPathInLog then sFilenameForLog := aFile.FullPath else sFilenameForLog := aFile.Name; case Result of sfprSuccess: begin S := 'OK ' + sFilenameForLog + ' -> ' + Value; if Index < FFiles.Count then FFiles[Index].Name := Value // Write new name to the file object else begin Index := StrToInt(aFile.Extension); FFiles[Index].Name := Value; // Write new name to the file object end; end; sfprError: S := 'FAILED ' + sFilenameForLog + ' -> ' + Value; sfprSkipped: S := 'SKIPPED ' + sFilenameForLog + ' -> ' + Value; end; end; if cbLog.Checked then FLog.Add(S); end; { TfrmMultiRename.SetOutputGlobalRenameLogFilename } procedure TfrmMultiRename.SetOutputGlobalRenameLogFilename; begin if gMultRenDailyIndividualDirLog then fneRenameLogFileFilename.FileName := mbExpandFileName(ExtractFilePath(gMulRenLogFilename) + IncludeTrailingPathDelimiter(EnvVarTodaysDate) + ExtractFilename(gMulRenLogFilename)) else fneRenameLogFileFilename.FileName := gMulRenLogFilename; end; { TfrmMultiRename.cm_ResetAll } procedure TfrmMultiRename.cm_ResetAll(const Params: array of string); var Param: string; bNeedRefreshActivePresetCommands: boolean = True; begin for Param in Params do GetParamBoolValue(Param, sREFRESHCOMMANDS, bNeedRefreshActivePresetCommands); cbName.Text := '[N]'; cbName.SelStart := UTF8Length(cbName.Text); cbExt.Text := '[E]'; cbExt.SelStart := UTF8Length(cbExt.Text); edFind.Text := ''; edReplace.Text := ''; cbRegExp.Checked := False; cbUseSubs.Checked := False; cbCaseSens.Checked := False; cbOnlyFirst.Checked := False; cbNameMaskStyle.ItemIndex := 0; cmbExtensionStyle.ItemIndex := 0; edPoc.Text := '1'; edInterval.Text := '1'; cmbxWidth.ItemIndex := 0; case gMulRenSaveRenamingLog of mrsrlPerPreset: begin cbLog.Checked := False; cbLog.Enabled := True; cbLogAppend.Checked := False; fneRenameLogFileFilename.Enabled := cbLog.Checked; actInvokeRelativePath.Enabled := cbLog.Checked; actViewRenameLogFile.Enabled := cbLog.Checked; cbLogAppend.Enabled := cbLog.Checked; if (FFiles.Count > 0) then fneRenameLogFileFilename.FileName := FFiles[0].Path + sDEFAULTLOGFILENAME else fneRenameLogFileFilename.FileName := sDEFAULTLOGFILENAME; end; mrsrlAppendSameLog: begin cbLog.Checked := True; cbLog.Enabled := False; cbLogAppend.Checked := True; cbLogAppend.Enabled := False; fneRenameLogFileFilename.Enabled := False; SetOutputGlobalRenameLogFilename; actInvokeRelativePath.Enabled := False; actViewRenameLogFile.Enabled := cbLog.Checked; end; end; cbPresets.Text := ''; FNames.Clear; gbMaska.Enabled := True; gbPresets.Enabled := True; cbPresets.ItemIndex := 0; gbCounter.Enabled := True; StringGridTopLeftChanged(StringGrid); if bNeedRefreshActivePresetCommands then RefreshActivePresetCommands; end; { TfrmMultiRename.cm_InvokeEditor } procedure TfrmMultiRename.cm_InvokeEditor(const {%H-}Params: array of string); begin DCPlaceCursorNearControlIfNecessary(btnEditor); pmEditDirect.PopUp; end; { TfrmMultiRename.cm_LoadNamesFromFile } procedure TfrmMultiRename.cm_LoadNamesFromFile(const {%H-}Params: array of string); begin dmComData.OpenDialog.FileName := EmptyStr; dmComData.OpenDialog.Filter := AllFilesMask; if dmComData.OpenDialog.Execute then LoadNamesFromFile(dmComData.OpenDialog.FileName); end; procedure TfrmMultiRename.cm_LoadNamesFromClipboard( const Params: array of string); var AFileList: TStringListEx; begin AFileList := TStringListEx.Create; try AFileList.Text := Clipboard.AsText; LoadNamesFromList(AFileList); except on E: Exception do msgError(E.Message); end; AFileList.Free; end; { TfrmMultiRename.cm_EditNames } procedure TfrmMultiRename.cm_EditNames(const {%H-}Params: array of string); var I: integer; AFileName: string; AFileList: TStringListEx; begin AFileList := TStringListEx.Create; AFileName := GetTempFolderDeletableAtTheEnd; AFileName := GetTempName(AFileName, 'txt'); if FNames.Count > 0 then AFileList.Assign(FNames) else begin for I := 0 to FFiles.Count - 1 do AFileList.Add(FFiles[I].Name); end; try AFileList.SaveToFile(AFileName); try if ShowMultiRenameWaitForm(AFileName, Self) then LoadNamesFromFile(AFileName); finally mbDeleteFile(AFileName); end; except on E: Exception do msgError(E.Message); end; AFileList.Free; end; { TfrmMultiRename.cm_EditNewNames } procedure TfrmMultiRename.cm_EditNewNames(const {%H-}Params: array of string); var sFileName: string; iIndexFile: integer; AFileList: TStringListEx; begin AFileList := TStringListEx.Create; try for iIndexFile := 0 to pred(FFiles.Count) do AFileList.Add(FreshText(iIndexFile)); sFileName := GetTempName(GetTempFolderDeletableAtTheEnd, 'txt'); try AFileList.SaveToFile(sFileName); try if ShowMultiRenameWaitForm(sFileName, Self) then LoadNamesFromFile(sFileName); finally mbDeleteFile(sFileName); end; except on E: Exception do msgError(E.Message); end; finally AFileList.Free; end; end; { TfrmMultiRename.cm_Config } procedure TfrmMultiRename.cm_Config(const {%H-}Params: array of string); begin frmMain.Commands.cm_Options(['TfrmOptionsMultiRename']); end; { TfrmMultiRename.cm_Rename } procedure TfrmMultiRename.cm_Rename(const {%H-}Params: array of string); var AFile: TFile; NewName: string; I, J, K: integer; TempFiles: TStringList; OldFiles, NewFiles: TFiles; AutoRename: boolean = False; Operation: TFileSourceOperation; theNewProperties: TFileProperties; LogFileStream: TFileStream; begin FActuallyRenamingFile := True; try if cbLog.Checked then begin if fneRenameLogFileFilename.FileName = EmptyStr then fneRenameLogFileFilename.FileName := FFiles[0].Path + sDEFAULTLOGFILENAME; mbForceDirectory(ExtractFileDir(mbExpandFileName(fneRenameLogFileFilename.FileName))); FLog := TStringListEx.Create; if cbLogAppend.Checked then FLog.Add(';' + DateTimeToStr(Now) + ' - ' + rsMulRenLogStart); end; OldFiles := FFiles.Clone; TempFiles := TStringList.Create; NewFiles := TFiles.Create(EmptyStr); FslVariableNames.Clear; FslVariableValues.Clear; //We don't clear the "Suggestion" parts because we may re-use them as their original values if we ever re-do rename pass witht he same instance. // OldNames FOldNames.Clear; for I := 0 to OldFiles.Count - 1 do FOldNames.Add(OldFiles[I].Name, Pointer(PtrInt(I))); try FNewNames.Clear; for I := 0 to FFiles.Count - 1 do begin AFile := TFile.Create(EmptyStr); AFile.Name := FreshText(I); //In "FreshText", if there was a "Variable on the fly / [V:Hint]" and the user aborted it, the "FActuallyRenamingFile" will be cleared and so we abort the actual renaming process. if not FActuallyRenamingFile then Exit; // Checking duplicates NewName := FFiles[I].Path + AFile.Name; J := FNewNames.Find(NewName); if J < 0 then FNewNames.Add(NewName) else begin if not AutoRename then begin if MessageDlg(rsMulRenWarningDuplicate + LineEnding + NewName + LineEnding + LineEnding + rsMulRenAutoRename, mtWarning, [mbYes, mbAbort], 0, mbAbort) <> mrYes then Exit; AutoRename := True; end; K := 1; while J >= 0 do begin NewName := FFiles[I].Path + AFile.NameNoExt + ' (' + IntToStr(K) + ')'; if AFile.Extension <> '' then NewName := NewName + ExtensionSeparator + AFile.Extension; J := FNewNames.Find(NewName); Inc(K); end; FNewNames.Add(NewName); AFile.Name := ExtractFileName(NewName); end; // Avoid collisions with OldNames J := FOldNames.Find(AFile.Name); if (J >= 0) and (PtrUInt(FOldNames.List[J]^.Data) <> I) then begin NewName := AFile.Name; // Generate temp file name, save file index as extension AFile.FullPath := GetTempName(FFiles[I].Path, IntToStr(I)); TempFiles.AddObject(NewName, AFile.Clone); end; NewFiles.Add(AFile); end; // Rename temp files back if TempFiles.Count > 0 then begin for I := 0 to TempFiles.Count - 1 do begin // Temp file name OldFiles.Add(TFile(TempFiles.Objects[I])); // Real new file name AFile := TFile.Create(EmptyStr); AFile.Name := TempFiles[I]; NewFiles.Add(AFile); end; end; // Rename files FillChar({%H-}theNewProperties, SizeOf(TFileProperties), 0); Operation := FFileSource.CreateSetFilePropertyOperation(OldFiles, theNewProperties); if Assigned(Operation) then begin with Operation as TFileSourceSetFilePropertyOperation do begin SetTemplateFiles(NewFiles); OnSetFilePropertyResult := @SetFilePropertyResult; end; OperationsManager.AddOperationModal(Operation); end; InsertFirstItem(cbExt.Text, cbExt); InsertFirstItem(cbName.Text, cbName); finally if cbLog.Checked then begin try if (cbLogAppend.Checked) and (FileExists(mbExpandFileName(fneRenameLogFileFilename.FileName))) then begin LogFileStream := TFileStream.Create(mbExpandFileName(fneRenameLogFileFilename.FileName), fmOpenWrite); try LogFileStream.Seek(0, soEnd); FLog.SaveToStream(LogFileStream); finally LogFileStream.Free; end; end else begin FLog.SaveToFile(mbExpandFileName(fneRenameLogFileFilename.FileName)); end; except on E: Exception do msgError(E.Message); end; FLog.Free; end; OldFiles.Free; NewFiles.Free; TempFiles.Free; end; finally FActuallyRenamingFile := False; end; StringGridTopLeftChanged(StringGrid); end; { TfrmMultiRename.cm_Close } procedure TfrmMultiRename.cm_Close(const {%H-}Params: array of string); begin Close; end; { TfrmMultiRename.cm_ShowPresetsMenu } procedure TfrmMultiRename.cm_ShowPresetsMenu(const {%H-}Params: array of string); begin PopupDynamicMenuAtThisControl(pmPresets, btnPresets); end; { TfrmMultiRename.cm_DropDownPresetList } procedure TfrmMultiRename.cm_DropDownPresetList(const {%H-}Params: array of string); begin if (not cbPresets.CanFocus) and (not cbPresets.Enabled) then if isOkToLosePresetModification = True then cbPresets.Enabled := True; if cbPresets.CanFocus then begin cbPresets.SetFocus; cbPresets.DroppedDown := True; end; end; { TfrmMultiRename.cm_LoadPreset } procedure TfrmMultiRename.cm_LoadPreset(const Params: array of string); var sPresetName: string; PresetIndex: integer; begin if isOkToLosePresetModification then begin //1.Get the preset name from the parameters. sPresetName := GetPresetNameForCommand(Params); //2.Make sure we got something. if sPresetName <> '' then begin //3.Make sure it is in our list. PresetIndex := FMultiRenamePresetList.Find(sPresetName); if PresetIndex <> -1 then begin cbName.Text := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].FileName; cbName.SelStart := UTF8Length(cbName.Text); cbExt.Text := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Extension; cbExt.SelStart := UTF8Length(cbExt.Text); cbNameMaskStyle.ItemIndex := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].FileNameStyle; cmbExtensionStyle.ItemIndex := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].ExtensionStyle; edFind.Text := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Find; edReplace.Text := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Replace; cbRegExp.Checked := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].RegExp; cbUseSubs.Checked := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].UseSubs; cbCaseSens.Checked := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].CaseSens; cbOnlyFirst.Checked := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].OnlyFirst; edPoc.Text := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Counter; edInterval.Text := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Interval; cmbxWidth.ItemIndex := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Width; case gMulRenSaveRenamingLog of mrsrlPerPreset: begin cbLog.Checked := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Log; cbLogAppend.Checked := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogAppend; fneRenameLogFileFilename.FileName := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogFile; end; mrsrlAppendSameLog: begin FbRememberLog := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].Log; FbRememberAppend := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogAppend; FsRememberRenameLogFilename := FMultiRenamePresetList.MultiRenamePreset[PresetIndex].LogFile; SetOutputGlobalRenameLogFilename; end; end; //4.Preserved the last loaded setup. FLastPreset := sPresetName; //5.Refresh the whole thing. edFindChange(edFind); edReplaceChange(edReplace); //6.We might come here with parameter "index=x" so make sure we switch also the preset combo box to the same index. if PresetIndex >= cbPresets.Items.Count then PresetIndex := 0; if cbPresets.ItemIndex <> PresetIndex then cbPresets.ItemIndex := PresetIndex; //7.Since we've load the setup, activate things so we may change setup if necessary. SetConfigurationState(CONFIG_SAVED); //8. If we're from anything else the preset droplist itself, let's go to focus on the name ready to edit it if necessary.. if (ActiveControl <> cbPresets) and (ActiveControl <> cbName) and (cbName.Enabled and gbMaska.Enabled) then begin ActiveControl := cbName; cbName.SelStart := UTF8Length(cbName.Text); end; end; end; end; end; { TfrmMultiRename.cm_LoadLastPreset } procedure TfrmMultiRename.cm_LoadLastPreset(const Params: array of string); begin cm_LoadPreset(['index=0']); end; { TfrmMultiRename.cm_LoadPreset1 } procedure TfrmMultiRename.cm_LoadPreset1(const Params: array of string); begin cm_LoadPreset(['index=1']); end; { TfrmMultiRename.cm_LoadPreset2 } procedure TfrmMultiRename.cm_LoadPreset2(const Params: array of string); begin cm_LoadPreset(['index=2']); end; { TfrmMultiRename.cm_LoadPreset3 } procedure TfrmMultiRename.cm_LoadPreset3(const Params: array of string); begin cm_LoadPreset(['index=3']); end; { TfrmMultiRename.cm_LoadPreset4 } procedure TfrmMultiRename.cm_LoadPreset4(const Params: array of string); begin cm_LoadPreset(['index=4']); end; { TfrmMultiRename.cm_LoadPreset5 } procedure TfrmMultiRename.cm_LoadPreset5(const Params: array of string); begin cm_LoadPreset(['index=5']); end; { TfrmMultiRename.cm_LoadPreset6 } procedure TfrmMultiRename.cm_LoadPreset6(const Params: array of string); begin cm_LoadPreset(['index=6']); end; { TfrmMultiRename.cm_LoadPreset7 } procedure TfrmMultiRename.cm_LoadPreset7(const Params: array of string); begin cm_LoadPreset(['index=7']); end; { TfrmMultiRename.cm_LoadPreset8 } procedure TfrmMultiRename.cm_LoadPreset8(const Params: array of string); begin cm_LoadPreset(['index=8']); end; { TfrmMultiRename.cm_LoadPreset9 } procedure TfrmMultiRename.cm_LoadPreset9(const Params: array of string); begin cm_LoadPreset(['index=9']); end; { TfrmMultiRename.cm_SavePreset } procedure TfrmMultiRename.cm_SavePreset(const Params: array of string); begin if cbPresets.ItemIndex > 0 then begin SavePreset(cbPresets.Items.Strings[cbPresets.ItemIndex]); SetConfigurationState(CONFIG_SAVED); end; end; { TfrmMultiRename.cm_SavePresetAs } procedure TfrmMultiRename.cm_SavePresetAs(const Params: array of string); var sNameForPreset: string; bKeepGoing: boolean; begin sNameForPreset := GetPresetNameForCommand(Params); if sNameForPreset <> '' then begin bKeepGoing := True; end else begin if (FLastPreset = '') or (FLastPreset = sLASTPRESET) then sNameForPreset := rsMulRenDefaultPresetName else sNameForPreset := FLastPreset; bKeepGoing := InputQuery(Caption, rsMulRenPromptForSavedPresetName, sNameForPreset); if bKeepGoing then bKeepGoing := (sNameForPreset <> ''); end; if bKeepGoing and (sNameForPreset <> FLastPreset) then if FMultiRenamePresetList.Find(sNameForPreset) <> -1 then if not msgYesNo(Format(rsMsgPresetAlreadyExists, [sNameForPreset]), msmbNo) then bKeepGoing := False; if bKeepGoing then begin SavePreset(sNameForPreset); if cbPresets.Items.IndexOf(sNameForPreset) = -1 then begin cbPresets.Items.Add(sNameForPreset); end; if cbPresets.ItemIndex <> cbPresets.Items.IndexOf(sNameForPreset) then cbPresets.ItemIndex := cbPresets.Items.IndexOf(sNameForPreset); SetConfigurationState(CONFIG_SAVED); RefreshActivePresetCommands; end; end; { TfrmMultiRename.cm_RenamePreset } // It also allow the at the same time to rename for changing case like "audio files" to "Audio Files". procedure TfrmMultiRename.cm_RenamePreset(const Params: array of string); var sCurrentName, sNewName: string; PresetIndex: integer; bKeepGoing: boolean; begin sCurrentName := cbPresets.Items.Strings[cbPresets.ItemIndex]; sNewName := sCurrentName; bKeepGoing := InputQuery(Caption, rsMulRenPromptNewPresetName, sNewName); if bKeepGoing and (sNewName <> '') and (sCurrentName <> sNewName) then begin PresetIndex := FMultiRenamePresetList.Find(sNewName); if (PresetIndex = -1) or (SameText(sCurrentName, sNewName)) then begin if SameText(FMultiRenamePresetList.MultiRenamePreset[cbPresets.ItemIndex].PresetName, cbPresets.Items.Strings[cbPresets.ItemIndex]) then begin FMultiRenamePresetList.MultiRenamePreset[cbPresets.ItemIndex].PresetName := sNewName; cbPresets.Items.Strings[cbPresets.ItemIndex] := sNewName; end; end else begin if msgYesNo(rsMulRenPromptNewNameExists, msmbNo) then begin if SameText(FMultiRenamePresetList.MultiRenamePreset[PresetIndex].PresetName, cbPresets.Items.Strings[PresetIndex]) and SameText(FMultiRenamePresetList.MultiRenamePreset[cbPresets.ItemIndex].PresetName, cbPresets.Items.Strings[cbPresets.ItemIndex]) then begin FMultiRenamePresetList.MultiRenamePreset[cbPresets.ItemIndex].PresetName := sNewName; cbPresets.Items.Strings[cbPresets.ItemIndex] := sNewName; cbPresets.Items.Delete(PresetIndex); FMultiRenamePresetList.Delete(PresetIndex); end; end; end; end; end; { TfrmMultiRename.cm_DeletePreset } procedure TfrmMultiRename.cm_DeletePreset(const Params: array of string); var Index: integer; sPresetName: string; begin sPresetName := GetPresetNameForCommand(Params); if sPresetName = '' then if cbPresets.ItemIndex > 0 then sPresetName := cbPresets.Items.Strings[cbPresets.ItemIndex]; if sPresetName <> '' then begin if msgYesNo(Format(rsMsgPresetConfigDelete, [sPresetName]), msmbNo) then begin DeletePreset(sPresetName); Index := cbPresets.Items.IndexOf(sPresetName); if Index = cbPresets.ItemIndex then cbPresets.ItemIndex := 0; if Index <> -1 then cbPresets.Items.Delete(Index); FillPresetsList; end; end; end; { TfrmMultiRename.cm_SortPresets } procedure TfrmMultiRename.cm_SortPresets(const Params: array of string); var slLocalPresets: TStringList; iSeeker, iPresetIndex: integer; begin if isOkToLosePresetModification then begin if FMultiRenamePresetList.Count > 1 then begin slLocalPresets := TStringList.Create; try for iSeeker := 1 to pred(FMultiRenamePresetList.Count) do slLocalPresets.Add(FMultiRenamePresetList.MultiRenamePreset[iSeeker].PresetName); if HaveUserSortThisList(Self, rsMulRenSortingPresets, slLocalPresets) = mrOk then begin for iSeeker := 0 to pred(slLocalPresets.Count) do begin iPresetIndex := FMultiRenamePresetList.Find(slLocalPresets.Strings[iSeeker]); if succ(iSeeker) <> iPresetIndex then FMultiRenamePresetList.Move(iPresetIndex, succ(iSeeker)); end; FillPresetsList(cbPresets.Items.Strings[cbPresets.ItemIndex]); end; finally slLocalPresets.Free; end; end; end; end; { TfrmMultiRename.cm_AnyNameMask } procedure TfrmMultiRename.cm_AnyNameMask(const {%H-}Params: array of string); begin pmFloatingMainMaskMenu.Items.Clear; PopulateFilenameMenu(pmFloatingMainMaskMenu); PopupDynamicMenuAtThisControl(pmFloatingMainMaskMenu, btnAnyNameMask); end; { TfrmMultiRename.cm_NameNameMask } procedure TfrmMultiRename.cm_NameNameMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmFilename, rmtuFilename); end; { TfrmMultiRename.cm_ExtNameMask } procedure TfrmMultiRename.cm_ExtNameMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmFilename, rmtuExtension); end; { TfrmMultiRename.cm_CtrNameMask } procedure TfrmMultiRename.cm_CtrNameMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmFilename, rmtuCounter); end; { TfrmMultiRename.cm_DateNameMask } procedure TfrmMultiRename.cm_DateNameMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmFilename, rmtuDate); end; { TfrmMultiRename.cm_TimeNameMask } procedure TfrmMultiRename.cm_TimeNameMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmFilename, rmtuTime); end; { TfrmMultiRename.cm_PlgnNameMask } procedure TfrmMultiRename.cm_PlgnNameMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmFilename, rmtuPlugins); end; { TfrmMultiRename.cm_ClearNameMask } procedure TfrmMultiRename.cm_ClearNameMask(const {%H-}Params: array of string); begin cbName.Text := ''; cbNameStyleChange(cbExt); if cbName.CanFocus then cbName.SetFocus; end; { TfrmMultiRename.cm_AnyExtMask } procedure TfrmMultiRename.cm_AnyExtMask(const {%H-}Params: array of string); begin pmFloatingMainMaskMenu.Items.Clear; PopulateExtensionMenu(pmFloatingMainMaskMenu); PopupDynamicMenuAtThisControl(pmFloatingMainMaskMenu, btnAnyExtMask); end; { TfrmMultiRename.cm_NameExtMask } procedure TfrmMultiRename.cm_NameExtMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmExtension, rmtuFilename); end; { TfrmMultiRename.cm_ExtExtMask } procedure TfrmMultiRename.cm_ExtExtMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmExtension, rmtuExtension); end; { TfrmMultiRename.cm_CtrExtMask } procedure TfrmMultiRename.cm_CtrExtMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmExtension, rmtuCounter); end; { TfrmMultiRename.cm_DateExtMask } procedure TfrmMultiRename.cm_DateExtMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmExtension, rmtuDate); end; { TfrmMultiRename.cm_TimeExtMask } procedure TfrmMultiRename.cm_TimeExtMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmExtension, rmtuTime); end; { TfrmMultiRename.cm_PlgnExtMask } procedure TfrmMultiRename.cm_PlgnExtMask(const {%H-}Params: array of string); begin BuildMenuAndPopup(tfmExtension, rmtuPlugins); end; { TfrmMultiRename.cm_ClearExtMask } procedure TfrmMultiRename.cm_ClearExtMask(const {%H-}Params: array of string); begin cbExt.Text := ''; cbNameStyleChange(cbExt); if cbExt.CanFocus then cbExt.SetFocus; end; { TfrmMultiRename.cm_ViewRenameLogFile } procedure TfrmMultiRename.cm_ViewRenameLogFile(const {%H-}Params: array of string); var sRenameLogFilename: string; begin sRenameLogFilename := mbExpandFileName(fneRenameLogFileFilename.FileName); if FileExists(sRenameLogFilename) then ShowViewerByGlob(sRenameLogFilename) else MsgError(Format(rsMsgFileNotFound, [sRenameLogFilename])); end; { ShowMultiRenameForm } // Will be in fact the lone function called externally to launch a MultiRename dialog. function ShowMultiRenameForm(aFileSource: IFileSource; var aFiles: TFiles; const PresetToLoad: string = ''): boolean; begin Result := True; try with TfrmMultiRename.Create(Application, aFileSource, aFiles, PresetToLoad) do begin Show; end; except Result := False; end; end; initialization TFormCommands.RegisterCommandsForm(TfrmMultiRename, HotkeysCategoryMultiRename, @rsHotkeyCategoryMultiRename); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmultirenamewait.lfm�����������������������������������������������������������0000644�0001750�0000144�00000002600�14743153644�017450� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmMultiRenameWait: TfrmMultiRenameWait Left = 500 Height = 87 Top = 182 Width = 394 AutoSize = True BorderStyle = bsDialog Caption = 'Double Commander' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ClientHeight = 87 ClientWidth = 394 OnPaint = FormPaint Position = poOwnerFormCenter LCLVersion = '1.6.0.4' object lblMessage: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 12 Height = 15 Top = 12 Width = 369 Caption = 'Click OK when you have closed the editor to load the changed names!' ParentColor = False end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = lblMessage AnchorSideTop.Control = lblMessage AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblMessage AnchorSideRight.Side = asrBottom Left = 18 Height = 34 Top = 57 Width = 357 Align = alNone Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 24 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 0 ShowButtons = [pbOK, pbCancel] end end ��������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmultirenamewait.lrj�����������������������������������������������������������0000644�0001750�0000144�00000001124�14743153644�017461� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":185879090,"name":"tfrmmultirenamewait.caption","sourcebytes":[68,111,117,98,108,101,32,67,111,109,109,97,110,100,101,114],"value":"Double Commander"}, {"hash":58920577,"name":"tfrmmultirenamewait.lblmessage.caption","sourcebytes":[67,108,105,99,107,32,79,75,32,119,104,101,110,32,121,111,117,32,104,97,118,101,32,99,108,111,115,101,100,32,116,104,101,32,101,100,105,116,111,114,32,116,111,32,108,111,97,100,32,116,104,101,32,99,104,97,110,103,101,100,32,110,97,109,101,115,33],"value":"Click OK when you have closed the editor to load the changed names!"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fmultirenamewait.pas�����������������������������������������������������������0000644�0001750�0000144�00000001750�14743153644�017462� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fMultiRenameWait; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel, uOSForms; type { TfrmMultiRenameWait } TfrmMultiRenameWait = class(TModalDialog) ButtonPanel: TButtonPanel; lblMessage: TLabel; procedure FormPaint(Sender: TObject); private { private declarations } public { public declarations } end; function ShowMultiRenameWaitForm(const AFileName: String; TheOwner: TCustomForm): Boolean; implementation uses uShowForm; function ShowMultiRenameWaitForm(const AFileName: String; TheOwner: TCustomForm): Boolean; begin with TfrmMultiRenameWait.Create(TheOwner) do try Hint := AFileName; Result := (ShowModal = mrOK); finally Free; end; end; {$R *.lfm} { TfrmMultiRenameWait } procedure TfrmMultiRenameWait.FormPaint(Sender: TObject); begin OnPaint := nil; ShowEditorByGlob(Hint); end; end. ������������������������doublecmd-1.1.22/src/fopenwith.lfm������������������������������������������������������������������0000644�0001750�0000144�00000017202�14743153644�016102� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmOpenWith: TfrmOpenWith Left = 421 Height = 520 Top = 126 Width = 410 Caption = 'Choose an application' ClientHeight = 520 ClientWidth = 410 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy Position = poOwnerFormCenter LCLVersion = '1.8.2.0' object lblMimeType: TLabel Left = 6 Height = 18 Top = 6 Width = 404 Align = alTop BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'File type to be opened: %s' ParentColor = False end object pnlOpenWith: TPanel Left = 0 Height = 38 Top = 385 Width = 410 Align = alBottom AutoSize = True BevelOuter = bvNone ClientHeight = 38 ClientWidth = 410 Color = clForm Enabled = False ParentColor = False TabOrder = 0 object fneCommand: TFileNameEdit AnchorSideLeft.Control = pnlOpenWith AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnCommands AnchorSideBottom.Side = asrBottom Left = 6 Height = 26 Top = 6 Width = 378 DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 MaxLength = 0 TabOrder = 0 end object btnCommands: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneCommand AnchorSideRight.Control = pnlOpenWith AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneCommand AnchorSideBottom.Side = asrBottom Left = 384 Height = 26 Top = 6 Width = 20 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Right = 6 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534CCA46534FFA46534FFA465 34CC000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFD9AD86FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFD9AD86FFA465 34FF000000000000000000000000000000000000000000000000000000000000 0000A46534CCA46534FFA46534FFA46534FFA46534FFD9AD86FFD9AD86FFA465 34FFA46534FFA46534FFA46534FFA46534CC0000000000000000000000000000 0000A46534FFE5CCB4FFDBB795FFDBB694FFDAB492FFDAB390FFD9AD86FFD8AA 83FFD7A87FFFD7A67DFFE0BE9FFFA46534FF0000000000000000000000000000 0000A46534FFE8D3C0FFE7D1BBFFE7D1BCFFE6CEB7FFE6CEB7FFE6CEB7FFE6CE B7FFE6CDB6FFE6CCB5FFE6CCB6FFA46534FF0000000000000000000000000000 0000A46534CCA46534FFA46534FFA46534FFA46534FFE6CEB7FFE6CEB7FFA465 34FFA46534FFA46534FFA46534FFA46534CC0000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534CCA46534FFA46534FFA465 34CC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } OnClick = btnCommandsClick PopupMenu = pmFieldCodes end end object ButtonPanel: TButtonPanel Left = 6 Height = 37 Top = 477 Width = 398 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True OKButton.OnClick = OKButtonClick HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True CancelButton.OnClick = CancelButtonClick TabOrder = 1 ShowButtons = [pbOK, pbCancel] end object tvApplications: TTreeView Left = 0 Height = 293 Top = 30 Width = 410 Align = alClient BorderSpacing.Top = 6 Images = ImageList ReadOnly = True ScrollBars = ssAutoBoth TabOrder = 2 OnDeletion = tvApplicationsDeletion OnSelectionChanged = tvApplicationsSelectionChanged Options = [tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end object chkUseAsDefault: TCheckBox AnchorSideTop.Side = asrBottom Left = 6 Height = 24 Top = 447 Width = 404 Align = alBottom BorderSpacing.Left = 6 Caption = 'Set selected application as default action' Enabled = False TabOrder = 3 end object chkCustomCommand: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 24 Top = 361 Width = 398 Align = alBottom Anchors = [akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Right = 6 Caption = 'Custom command' OnChange = chkCustomCommandChange TabOrder = 4 end object chkSaveAssociation: TCheckBox Left = 6 Height = 24 Top = 423 Width = 404 Align = alBottom BorderSpacing.Left = 6 Caption = 'Save association' OnChange = chkSaveAssociationChange TabOrder = 5 end object pnlFilter: TPanel Left = 0 Height = 38 Top = 323 Width = 410 Align = alBottom AutoSize = True BevelOuter = bvNone ChildSizing.TopBottomSpacing = 6 ClientHeight = 38 ClientWidth = 410 Color = clForm ParentColor = False TabOrder = 6 object tfeApplications: TTreeFilterEdit AnchorSideLeft.Control = pnlFilter AnchorSideTop.Control = pnlFilter AnchorSideRight.Control = pnlFilter AnchorSideRight.Side = asrBottom Left = 6 Height = 26 Top = 6 Width = 398 ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Right = 6 MaxLength = 0 TabOrder = 0 FilteredTreeview = tvApplications end end object ImageList: TImageList left = 208 top = 136 end object pmFieldCodes: TPopupMenu left = 123 top = 135 object miSingleFileName: TMenuItem Caption = 'Single file name' Hint = '%f' OnClick = miFieldCodeClick end object miListOfFiles: TMenuItem Caption = 'Multiple file names' Hint = '%F' OnClick = miFieldCodeClick end object miSingleURL: TMenuItem Caption = 'Single URI' Hint = '%u' OnClick = miFieldCodeClick end object miListOfURLs: TMenuItem Caption = 'Multiple URIs' Hint = '%U' OnClick = miFieldCodeClick end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fopenwith.lrj������������������������������������������������������������������0000644�0001750�0000144�00000003773�14743153644�016123� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":161081070,"name":"tfrmopenwith.caption","sourcebytes":[67,104,111,111,115,101,32,97,110,32,97,112,112,108,105,99,97,116,105,111,110],"value":"Choose an application"}, {"hash":177247699,"name":"tfrmopenwith.lblmimetype.caption","sourcebytes":[70,105,108,101,32,116,121,112,101,32,116,111,32,98,101,32,111,112,101,110,101,100,58,32,37,115],"value":"File type to be opened: %s"}, {"hash":194162686,"name":"tfrmopenwith.chkuseasdefault.caption","sourcebytes":[83,101,116,32,115,101,108,101,99,116,101,100,32,97,112,112,108,105,99,97,116,105,111,110,32,97,115,32,100,101,102,97,117,108,116,32,97,99,116,105,111,110],"value":"Set selected application as default action"}, {"hash":118058372,"name":"tfrmopenwith.chkcustomcommand.caption","sourcebytes":[67,117,115,116,111,109,32,99,111,109,109,97,110,100],"value":"Custom command"}, {"hash":244686542,"name":"tfrmopenwith.chksaveassociation.caption","sourcebytes":[83,97,118,101,32,97,115,115,111,99,105,97,116,105,111,110],"value":"Save association"}, {"hash":206933237,"name":"tfrmopenwith.misinglefilename.caption","sourcebytes":[83,105,110,103,108,101,32,102,105,108,101,32,110,97,109,101],"value":"Single file name"}, {"hash":694,"name":"tfrmopenwith.misinglefilename.hint","sourcebytes":[37,102],"value":"%f"}, {"hash":31589283,"name":"tfrmopenwith.milistoffiles.caption","sourcebytes":[77,117,108,116,105,112,108,101,32,102,105,108,101,32,110,97,109,101,115],"value":"Multiple file names"}, {"hash":662,"name":"tfrmopenwith.milistoffiles.hint","sourcebytes":[37,70],"value":"%F"}, {"hash":237173289,"name":"tfrmopenwith.misingleurl.caption","sourcebytes":[83,105,110,103,108,101,32,85,82,73],"value":"Single URI"}, {"hash":709,"name":"tfrmopenwith.misingleurl.hint","sourcebytes":[37,117],"value":"%u"}, {"hash":112596803,"name":"tfrmopenwith.milistofurls.caption","sourcebytes":[77,117,108,116,105,112,108,101,32,85,82,73,115],"value":"Multiple URIs"}, {"hash":677,"name":"tfrmopenwith.milistofurls.hint","sourcebytes":[37,85],"value":"%U"} ]} �����doublecmd-1.1.22/src/fopenwith.pas������������������������������������������������������������������0000644�0001750�0000144�00000025335�14743153644�016115� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Open with other application dialog Copyright (C) 2012-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOpenWith; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, TreeFilterEdit, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, EditBtn, Buttons, ButtonPanel, ComCtrls, Menus, Types; type { TfrmOpenWith } TfrmOpenWith = class(TForm) btnCommands: TSpeedButton; ButtonPanel: TButtonPanel; chkSaveAssociation: TCheckBox; chkCustomCommand: TCheckBox; chkUseAsDefault: TCheckBox; fneCommand: TFileNameEdit; ImageList: TImageList; lblMimeType: TLabel; miListOfURLs: TMenuItem; miSingleURL: TMenuItem; miListOfFiles: TMenuItem; miSingleFileName: TMenuItem; pnlFilter: TPanel; pnlOpenWith: TPanel; pmFieldCodes: TPopupMenu; tfeApplications: TTreeFilterEdit; tvApplications: TTreeView; procedure btnCommandsClick(Sender: TObject); procedure CancelButtonClick(Sender: TObject); procedure chkCustomCommandChange(Sender: TObject); procedure chkSaveAssociationChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure miFieldCodeClick(Sender: TObject); procedure OKButtonClick(Sender: TObject); procedure tvApplicationsDeletion(Sender: TObject; Node: TTreeNode); procedure tvApplicationsSelectionChanged(Sender: TObject); private FMimeType: String; FFileList: TStringList; procedure LoadApplicationList; function TreeNodeCompare(Node1, Node2: TTreeNode): Integer; procedure LoadBitmap(ANode: TTreeNode; const AName: String); public constructor Create(TheOwner: TComponent; AFileList: TStringList); reintroduce; end; procedure ShowOpenWithDlg(TheOwner: TComponent; const FileList: TStringList); implementation {$R *.lfm} uses LCLProc, DCStrUtils, uOSUtils, uPixMapManager, uGlobs, uMimeActions, uMimeType, uLng, LazUTF8, Math, uXdg, uGraphics; const CATEGORY_OTHER = 11; // 'Other' category index const // See https://specifications.freedesktop.org/menu-spec/latest CATEGORIES: array[0..12] of String = ( 'AudioVideo', 'Audio', 'Video', 'Development', 'Education', 'Game', 'Graphics', 'Network', 'Office', 'Science', 'Settings', 'System', 'Utility' ); procedure ShowOpenWithDlg(TheOwner: TComponent; const FileList: TStringList); begin with TfrmOpenWith.Create(TheOwner, FileList) do begin Show; end; end; { TfrmOpenWith } constructor TfrmOpenWith.Create(TheOwner: TComponent; AFileList: TStringList); begin FFileList:= AFileList; inherited Create(TheOwner); InitPropStorage(Self); end; procedure TfrmOpenWith.FormCreate(Sender: TObject); begin ImageList.Width:= gIconsSize; ImageList.Height:= gIconsSize; FMimeType:= GetFileMimeType(FFileList[0]); lblMimeType.Caption:= Format(lblMimeType.Caption, [FMimeType]); with tvApplications do begin LoadBitmap(Items.AddChild(nil, rsOpenWithMultimedia), 'applications-multimedia'); LoadBitmap(Items.AddChild(nil, rsOpenWithDevelopment), 'applications-development'); LoadBitmap(Items.AddChild(nil, rsOpenWithEducation), 'applications-education'); LoadBitmap(Items.AddChild(nil, rsOpenWithGames), 'applications-games'); LoadBitmap(Items.AddChild(nil, rsOpenWithGraphics), 'applications-graphics'); LoadBitmap(Items.AddChild(nil, rsOpenWithNetwork), 'applications-internet'); LoadBitmap(Items.AddChild(nil, rsOpenWithOffice), 'applications-office'); LoadBitmap(Items.AddChild(nil, rsOpenWithScience), 'applications-science'); LoadBitmap(Items.AddChild(nil, rsOpenWithSettings), 'preferences-system'); LoadBitmap(Items.AddChild(nil, rsOpenWithSystem), 'applications-system'); LoadBitmap(Items.AddChild(nil, rsOpenWithUtility), 'applications-accessories'); LoadBitmap(Items.AddChild(nil, rsOpenWithOther), 'applications-other'); end; LoadApplicationList; tvApplications.CustomSort(@TreeNodeCompare); end; procedure TfrmOpenWith.chkCustomCommandChange(Sender: TObject); begin pnlOpenWith.Enabled:= chkCustomCommand.Checked; end; procedure TfrmOpenWith.chkSaveAssociationChange(Sender: TObject); begin chkUseAsDefault.Enabled:= chkSaveAssociation.Checked; end; procedure TfrmOpenWith.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; end; procedure TfrmOpenWith.btnCommandsClick(Sender: TObject); begin pmFieldCodes.PopUp(); end; procedure TfrmOpenWith.CancelButtonClick(Sender: TObject); begin Close; end; procedure TfrmOpenWith.FormDestroy(Sender: TObject); begin FFileList.Free; end; procedure TfrmOpenWith.miFieldCodeClick(Sender: TObject); begin fneCommand.Text:= fneCommand.Text + #32 + TMenuItem(Sender).Hint; fneCommand.SelStart:= UTF8Length(fneCommand.Text); end; procedure TfrmOpenWith.OKButtonClick(Sender: TObject); var DesktopEntry: TDesktopFileEntry; DesktopFile: PDesktopFileEntry = nil; begin if chkCustomCommand.Checked then begin DesktopFile:= @DesktopEntry; DesktopEntry.MimeType:= FMimeType; DesktopEntry.ExecWithParams:= fneCommand.Text; end else if tvApplications.SelectionCount > 0 then begin if Assigned(tvApplications.Selected.Data) then begin DesktopFile:= PDesktopFileEntry(tvApplications.Selected.Data); fneCommand.Text:= DesktopFile^.DesktopFilePath; end; end; if Assigned(DesktopFile) then begin if chkSaveAssociation.Checked then begin if not AddDesktopEntry(FMimeType, fneCommand.Text, chkUseAsDefault.Checked) then begin MessageDlg(rsMsgErrSaveAssociation, mtError, [mbOK], 0); end; end; fneCommand.Text:= TranslateAppExecToCmdLine(DesktopFile, FFileList); ExecCmdFork(fneCommand.Text); end; Close; end; procedure TfrmOpenWith.tvApplicationsDeletion(Sender: TObject; Node: TTreeNode); var DesktopFile: PDesktopFileEntry; begin if Assigned(Node.Data) then begin DesktopFile:= PDesktopFileEntry(Node.Data); Dispose(DesktopFile); end; end; procedure TfrmOpenWith.tvApplicationsSelectionChanged(Sender: TObject); var DesktopFile: PDesktopFileEntry; begin if tvApplications.SelectionCount > 0 then begin chkCustomCommand.Checked:= False; if (tvApplications.Selected.Data = nil) then begin DesktopFile:= nil; fneCommand.Text:= EmptyStr; end else begin DesktopFile:= PDesktopFileEntry(tvApplications.Selected.Data); fneCommand.Text:= DesktopFile^.ExecWithParams; end; end; end; procedure TfrmOpenWith.LoadApplicationList; const APPS = 'applications'; var Folder: String; I, J, K: Integer; TreeNode: TTreeNode; Index, Count: Integer; DataDirs: TStringArray; DesktopFile: PDesktopFileEntry; Applications, Folders: TStringList; function GetCategoryIndex(const Category: String): Integer; var Index: Integer; begin Result:= CATEGORY_OTHER; // Default 'other' category for Index:= Low(CATEGORIES) to High(CATEGORIES) do begin if SameText(CATEGORIES[Index], Category) then begin if Index < 3 then Result:= 0 else begin Result:= Index - 2; end; Break; end; end; end; begin Folders:= TStringList.Create; Folders.CaseSensitive:= True; // $XDG_DATA_HOME Folder:= IncludeTrailingBackslash(GetUserDataDir) + APPS; if (Folders.IndexOf(Folder) < 0) then Folders.Add(Folder); // $XDG_DATA_DIRS DataDirs:= GetSystemDataDirs; for I:= Low(DataDirs) to High(DataDirs) do begin Folder:= IncludeTrailingBackslash(DataDirs[I]) + APPS; if (Folders.IndexOf(Folder) < 0) then Folders.Add(Folder); end; for I:= 0 to Folders.Count - 1 do begin Applications:= FindAllFiles(Folders[I], '*.desktop', True); for J:= 0 to Applications.Count - 1 do begin DesktopFile:= GetDesktopEntry(Applications[J]); if Assigned(DesktopFile) then begin if DesktopFile^.Hidden or Contains(DesktopFile^.Categories, 'Screensaver') then begin Dispose(DesktopFile); Continue; end; with DesktopFile^ do begin DesktopFilePath:= ExtractDirLevel(Folders[I] + PathDelim, DesktopFilePath); DesktopFilePath:= StringReplace(DesktopFilePath, PathDelim, '-', [rfReplaceAll]); end; // Determine application category Count:= Min(3, Length(DesktopFile^.Categories)); if Count = 0 then Index:= CATEGORY_OTHER else begin for K:= 0 to Count - 1 do begin Index:= GetCategoryIndex(DesktopFile^.Categories[K]); if Index <> CATEGORY_OTHER then Break; end; end; TreeNode:= tvApplications.Items.TopLvlItems[Index]; TreeNode:= tvApplications.Items.AddChild(TreeNode, DesktopFile^.DisplayName); TreeNode.Data:= DesktopFile; LoadBitmap(TreeNode, DesktopFile^.IconName); end; end; Applications.Free; end; Folders.Free; // Hide empty categories for Index:= 0 to tvApplications.Items.TopLvlCount - 1 do begin if tvApplications.Items.TopLvlItems[Index].Count = 0 then tvApplications.Items.TopLvlItems[Index].Visible:= False; end; end; function TfrmOpenWith.TreeNodeCompare(Node1, Node2: TTreeNode): Integer; begin if SameText(Node1.Text, rsOpenWithOther) then Result:= +1 else if SameText(Node2.Text, rsOpenWithOther) then Result:= -1 else Result := LazUTF8.Utf8CompareStr(Node1.Text, Node2.Text); end; procedure TfrmOpenWith.LoadBitmap(ANode: TTreeNode; const AName: String); var Bitmap: TBitmap; ImageIndex: PtrInt; begin ImageIndex:= PixMapManager.GetIconByName(AName); if ImageIndex >= 0 then begin Bitmap:= PixMapManager.GetBitmap(ImageIndex); if Assigned(Bitmap) then begin BitmapCenter(Bitmap, ImageList.Width, ImageList.Height); ANode.ImageIndex:= ImageList.Add(Bitmap, nil); ANode.SelectedIndex:= ANode.ImageIndex; ANode.StateIndex:= ANode.ImageIndex; Bitmap.Free; end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/foptions.lfm�������������������������������������������������������������������0000644�0001750�0000144�00000132542�14743153644�015745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmOptions: TfrmOptions Left = 372 Height = 600 Top = 55 Width = 800 HelpType = htKeyword ActiveControl = tvTreeView Caption = 'Options' ClientHeight = 600 ClientWidth = 800 OnClose = FormClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy Position = poScreenCenter SessionProperties = 'Height;Left;Top;TreeFilterEdit.Width;tvTreeView.Width;Width;WindowState' ShowInTaskBar = stAlways LCLVersion = '2.2.5.0' object tvTreeView: TTreeView Left = 0 Height = 437 Top = 0 Width = 193 Align = alLeft AutoExpand = True Images = OptionsEditorsImageList ReadOnly = True RowSelect = True ScrollBars = ssAutoBoth TabOrder = 0 OnChange = tvTreeViewChange Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips] end object Panel3: TPanel Left = 196 Height = 437 Top = 0 Width = 444 Align = alClient BevelOuter = bvNone ClientHeight = 437 ClientWidth = 444 TabOrder = 1 object pnlCaption: TPanel Left = 0 Height = 23 Top = 0 Width = 444 Align = alTop Color = clActiveCaption Font.Color = clCaptionText Font.Style = [fsBold] ParentColor = False ParentFont = False TabOrder = 0 end object sboxOptionsEditor: TScrollBox Left = 0 Height = 414 Top = 23 Width = 444 HorzScrollBar.Increment = 40 HorzScrollBar.Page = 401 HorzScrollBar.Smooth = True HorzScrollBar.Tracking = True VertScrollBar.Increment = 2 VertScrollBar.Page = 25 VertScrollBar.Smooth = True VertScrollBar.Tracking = True Align = alClient BorderStyle = bsNone ClientHeight = 414 ClientWidth = 444 TabOrder = 1 object lblEmptyEditor: TLabel AnchorSideLeft.Control = sboxOptionsEditor AnchorSideTop.Control = sboxOptionsEditor Left = 10 Height = 15 Top = 10 Width = 391 BorderSpacing.Left = 10 BorderSpacing.Top = 10 Caption = 'Please select one of the subpages, this page does not contain any settings.' ParentColor = False Visible = False end end end object splOptionsSplitter: TSplitter Left = 193 Height = 437 Top = 0 Width = 3 OnMoved = splOptionsSplitterMoved end object pnlButtons: TKASButtonPanel Left = 0 Height = 43 Top = 437 Width = 640 Align = alBottom AutoSize = True ChildSizing.TopBottomSpacing = 4 ClientHeight = 50 ClientWidth = 640 FullRepaint = False TabOrder = 2 object btnHelp: TBitBtn AnchorSideLeft.Side = asrCenter AnchorSideLeft.Control = TreeFilterEdit AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnOK Left = 201 Height = 30 Top = 5 Width = 75 AutoSize = True BorderSpacing.Left = 8 BorderSpacing.Right = 16 BorderSpacing.InnerBorder = 2 Caption = '&Help' Kind = bkHelp OnClick = btnHelpClick TabOrder = 4 end object btnOK: TBitBtn AnchorSideRight.Control = btnCancel Left = 321 Height = 31 Top = 5 Width = 98 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 8 BorderSpacing.InnerBorder = 2 Caption = '&OK' Default = True Kind = bkOK ModalResult = 1 OnClick = btnOKClick TabOrder = 0 end object btnCancel: TBitBtn AnchorSideRight.Control = btnApply Left = 427 Height = 31 Top = 5 Width = 98 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 8 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Kind = bkCancel OnClick = btnCancelClick OnMouseDown = btnCancelMouseDown TabOrder = 1 end object btnApply: TBitBtn AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 533 Height = 31 Top = 5 Width = 98 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 8 BorderSpacing.InnerBorder = 2 Caption = '&Apply' OnClick = btnApplyClick TabOrder = 2 end object TreeFilterEdit: TTreeFilterEdit AnchorSideTop.Control = btnOK AnchorSideTop.Side = asrCenter Left = 9 Height = 23 Top = 9 Width = 184 OnFilterItem = TreeFilterEditFilterItem ButtonWidth = 23 BorderSpacing.Left = 8 NumGlyphs = 1 MaxLength = 0 TabOrder = 3 FilteredTreeview = tvTreeView end end object OptionsEditorsImageList: TImageList Left = 72 Top = 16 Bitmap = { 4C7A2B0000001000000010000000014900000000000078DAEDBD075C55C7B607 7CD27BDE7D37B7E4262FF7C698E426B9E946A3468D31C6D87BEFBD616F08222A 4A91A2802876446982F40E0AD28B34E9BDF7DEFBE1FFAD35878387A698DCF7FB DEFBBEB7F1EF9CBD67FEB3D6AC3D7DEF99BD65F1AF58BC7411B690AB3DFDFDA7 C6AA352B607AE59270A32D8E21D5E934A2CD951160B8166EC7A6C376EF6838EC 1F03E70363E17EE807F8AA4F41A0F602841BAD15FC356B57E2EA8DEBC28DB250 FFB7F2FD8C36E0FE851D08373B8CC0739BE07564D280FCCBD7AFF5E227D8EB20 D1D5180FAC4E20C2F20462EDF510EF6880882B7B106779AC1FDFF4CAE55EFCE2 87FE487237418C9D0EE29C0C1171F308A229AECC2007E1D7976F72C9B417BF28 F61EF263EE0A7EC8756544DE3A8AB83BA79119604F7E7EFDF846174C7AF17342 5D5092148204571384DE50451CE91F7B5B13D921CEC80E72ECC73F7BCEA89FFD B2298E7C929516E080547F3B6485B8E0A1AD26EE69CCE8C7D7373C3BA0FD1F7A 98E3A1E72DC4BA5CC73DDD65F0383C7E40FBEB18E8FDAEFB2FE79F9A31FCA9F3 AFA2FD366FDFEAB25969ABBDC0107E4BE850B4DF82258BDE943CE5A1683FC96F 38468C1821A1F4733C1292FFC26F8943535707BF0572EE6F3DE4F1F0515050F0 54904AA583F2434243616367DB0B7C6DA87C0E1F1A1686E2E26214971423343C 4C5C2B2A2C446141E1A0FC42F22F220E872D2B2D4359991CE5E25A4949A988B3 B0A8101D1D1DBDF8CC6559A5C4E3B0159515A8ACAC44655515A15276ADA25CC4 575C52D28FCFF1969596F64B775F54509CE514476B6B6B2F7E297139FE27F1AB ABAB51595189E6E6E65E7C4E23EBFB247E6D6D2DAA284D353535BDF8E524BB9A AE3F895F57578F9AEA9A7EFC8A8A0AA15B5474F4A0DC98D858343434A0A67620 7EB9E0D753FC4D4D4DC23E6CE3AEAE2E747676A2ADAD8DD2DC24E3D7F4E79797 57A0AABA8AF4AB43636323856D119C8EF60EB4B5B789F89A9A1A515F5F3F209F 650C84F6F6F61EB0CDE590F37F6FF9FD771F438977B0307CBD8CF2D6E3E260BF 6A85B40FE84F796C207FBE563B809FE239FF665B0FC6D7D6D7EDC76DA2FB71FB 8E9DE0B4B4B420BFA008B6F6F6A8A4FC3414BBB09F2C5F52D9204E3995230F6F 9F5EF7F769EBF0B887F1B86561F19BEFB5BBA797E0797A790F99AFD8AE6A9E3C 2A6C101E11897B7EFE4F8C833951BEF602AEE7D4647174EB9E9090F8D838386C 62F83D58181C16F0B334167C45DBE453BD1D181CDACF1E72B9CCBBA97B006EE7 557BE4F7B56F3CE91118143C20DFDAE828DC89EBA0B7AF1F57318EEBE637FAF1 595FAFAB5A028371FBDEE3C1ECFEBFB9FDB7B6B686868606BEFAEA2B01BE26DA 60053CAEFDCECFCF474646066262627AF8DCAE719BC92EE3717C676767C13B70 E08070E5ED3FBB45C5454F6CFF99939090007F7F7FF15BB1FD2F2B2B7D62FB2F 4F37C3CBDB0B3366CC10BFB9FDE736F749ED3FB7BFDCB6723BC6EDC3AFBFFE8A CF3FFF5CD4797CCED71FD7FECBDB650ECFEDD8D4A953F1FEFBEFE3BBEFBEE37B 8D679E7906EBD7AF176DD840EDBF9CCBFE5C9F319F79870E1D12D7366FDE2CCE D9CE03B5FF8A5C6E83A74D9B86175E78419C735BCAF796F96A6A6A03B6FFAC33 8795B5BFCD82FFE28B2F8AEB6C2FBE37727D066AFF59B69CCBF5F8F4E9D34578 15151571BE66CD1A716E4FF5DA40EDBF229FEDBB78F1627CF9E597F8E0830FF0 FCF3CF0BEEAC59B3445CFF53DA7F12DD8337522592E7E3DE92BCFE7024FE1CBF 086F271EC0DBC9FA782BF526DEC8F0C68B8569BDC22B626CD2F392F7E35EC1D8 94F1D85EAC069D065B5C680B86694702B45B32B0B52617EF9414E1D5A40ABCE0 DBD88BBB89E4CE4C7A1307F296C2BCF912AEC30A47E8FF3D702084410D05B044 3B2E367660516A13DEF06C83C4A053708F674B24CAE9AFC0247F097CDBAE4117 BBA08243D080294EC303DA78087554626747170E950257723AB1D0A7032F6934 B3D925177224921B79A3F1A0D994A4ED800554710D06B8825BF43B1837914331 5159A901762500874300E3904EFC69572324F36B252EC52F23B4620BB2881182 DD08823EFC600E6FB8E21E6209D5706A052E6503EA81C0865BC0F57BC0B293AD 786E543EA2CBDF446193068A889B4B9AE7E23C49744426A53B93CED2BADA1152 06584702DAB6C0363DD2E10CB05FAB032F7F90457D8537A97F698C76E946C211 B4492F92EB8EF6AE0402F5331B80B824C0D11530300276EC06B66C03344E76E0 9537D25097FE26506F4805783D5502878092730427AA50486051113AB3A5C80B 0502AD00F3539486CDC0A18D80CE9166BCF372129AFC5F4157D671E0E10E204C 89A009045F07EE9140FF3802F58729BAE40B80870A707E35D94299E46FAAC467 CFC7A1C34A02A9DF5A52F22A60B902B8B917B84C824CAF0066FE845C741977A0 440D8820D9367300BFF352EC9B988551922849BB8644D2AAF61A3ABCC928A6DB 01158A632FE971E834A0660F1C89A6F32AB46C00D2E603B1148FEBFE4A2C7B31 0A5388CF79A076B104B5CA93D169654CE1C940F39602CB49D9D5A4C3CABBC092 7460660BEA8E503A34EB60FA5D2CD649027BF26FC5AF1249FE671294CD9F8856 4DD2FD821970808CBDF632C1936E582A3A8D6B50BAB71C1EDF46E1B4E41E764A 627A9581A2BF4B2409CF4B90F8FCEBC89BB80CD51B4EA161BF396AF7BAA070B9 07E247B9C1EF5937D84B7C24A6DD7A0F8438C94B9220C97F49FC25DFC0EF99C9 F0952C87B7641FBC24BA92008963BFF0831DA7677D049D99C307C5E9391F0F4A D69BF729F273D25155538DDA7ABAFF34EE69A63AAF85C740547735501D99979E D82F0E791FE6CCE2AF514AF571727ABA400A213533432085909E9D2DFACA8AFD 1DC53ED099C5D47697962099DA8BF4DC2C64E6E720AB2017D98579F43B97E2C9 147D6C39BF6FFF89F9B905F9C8CECF13BCDC62EA5B50DD55505A446E2172A89F 5148FD82BE7CB92E06C4CFC8CE4409B5B379C42D2C2B464905F5412AA9EDAEA0 3E00B5B5D9B9393D9CD373FE09ED19C3081FD0B5613058F4155232D25043ED09 734B2BCB51515385AADA6A994B753FFB33FFF4DC4F10E06187A4B454B2551A1E C645E3ECB211F43B153575B568A576B32FCAA8AD94F35926F3523232845DE213 E27AF89E7EBE03C2DBFF6E3F7E21F53FE2521391909A00FD855F22E64108DDB7 D441111EE80D9DD91FF5F0794C97909E8C94EC0C789A1BE0CC926FA033EBC341 7176F977D09EF588CFED6D62462AD2E87EE7D07DE67B5542F62EAFAE10F6633B E61651FF302F5BE4CBCC9C1C8AE7119FDBDA26CAA39C4F9B292ECEAB2D6DADC2 5E2D0C3A6F16681161B3F3727BF1FD82031010163C24DC0F0D161C4E07DFBFFB 6E36C2DE7C6D684885BF9BB5E08AFC33F7D3A79EF7947307AA03C669C53A2DBE 980AC678ADD8EAC1CAF96075C8688D68A4539BC7E0DF4FCBFF728F8B9D61680D 1CB3DAF1AD6A70C693F8A4A3D37CD3542CBD922EC07ABB1674E22EB59BFC7BF9 D5742C94A5C56920FED893D1F0A7EE80772D7097105047BC073204D2EFFBF5E4 92FFD83E6951E47B90BF7335309738EFFB00FFBC2BC387BEC07B74EE4DEDF098 E35103F2C7A8DEBB37E7422AB6DAE7C389FA195FDC07BEA3BEC2A82099CBE72E A4C7049233F64454FC64FD784CD48EAD56B0DF709E0A9E4F69B726FD47517B3D 2E9CC213C61346D3F96AEA035C2FA7E631AC16B6EDE47F2A067DED3F8FF8D749 FE046AFA7FA674FC12054C264CA4DFAB53A85923FE21E29B137FBC02FF47ADD8 FB3349FFD5A4FF39D2EA17F29A164B8893B95308E76B65FA8F510BCE60EE8F9A D1753DF78FEC6A40F63B540C2C4DA32698FA696A65321C2901D665017A14FA87 63C27E9F715A9F79EEF9AF7BF827A27092EED1226AA6958A80D974AFE7D03D9F 43E959463A1D279D8E91FC712706B6FF0492AF46F25548865A13A54D769F4630 A65E48C19146D283FC270C72FF7F3C155D3F95F2DF7492C9EE8413E159F23063 55EFDEE36B5349A71F8EF8DD1F24FF7F2D97D78D7F29041BAE707DF840FCDF03 3E3CEEF9602818A80CF2F5A11E03C5C1D7788EF549F5158FB707E377507D6CB1 E9BBC782C77F83F1DB3BDAC5F892C1EDFED3D8835D6E7B64E3B2263CAD3D183C 1E6C68681463D7A7B50783C79DF231FFD3DA83514B3C1EBF969797A3AF3DDA44 9FA155A4B117E89A9C5F4DED69318D158A087DEDD1DC241BAF3635358B31BDCC 958DAF1FE92F9F93AFED678F4790CD0B34F0FC0085E73815EF812214ED3110D8 AF8EFAA583E507457BC8C1F32E3297CEBBE73A06E32BDA43CC1B15F507CFF30E C657B4876C4E4551FFDA9EDF8F2B9343CDBF83D50BE541D750EC7F0185BEC602 0F6FEC688ABBBEB339EAC29AF4609549EA2E5BC6BDF2B87AA5C88F067CE882B4 A18C508ECEFA52B4D714A0BDBE04E5BE3A88D55CE4EAB66DFCEB83F10B7DCFA1 ABA98AC69F21E8C80D435B66209A12DCD0D5D680F6FC6054069C43D0D1A9E706 E71BA3ABB9169DF9D1E82C88467B4E385AD2EEA2A92C0BED0D15E8686D40E4C9 055D8FE5B7D4A1B3281E9D850FD1911F85B6AC6034A7F8A2E1A123A5A51051DA 4BBBBE734B8B5B1D98D7BE3628BF076B0885BE34FE6BA94757499280B4E821DA 7323D1961D2CF490921DA2B497748D724D6F9552796745C881B40BE277A10FF3 A9D1626E4932A4C589A4078D970B1EA09D6CD1D5508A28ADC55D231DD36B5B3A BB70A6B01546D94D345C6EC29DBC66449EA2C12EE98F326A50CB33646E0935E2 941EE43F107E0F3417758DB24DAFAF6B97C284B8E7321BB1913A4D234DD29F88 8EE61A449D5CD435D22EBDBDB4B9037BEE9660916D3E6659E6C228A2826C5C43 699152823A05BA189DFC3C4D2AF835941F624E2CC6F756E9ED9CDE560ADA4C68 A2E00D949ECB858DB85CDC822BC5CDB856D484EB04B3A246A437B40ABEB4B11A 91C717B68D324F6F6BA6F02645AD38D70D237633CA702EA500E7E23361189302 FDF05868058422223559F0430E4C2E8D3CB6A06ED4E5F4D67A4E7F712B8C8967 48D02B6885567E0B8EE5B54039BB193B329BB13AAD1173921A1055DF21F8F27C 42BF5B6A28052CF72CDD83D3C4D5209E6A4E0BF612774B461356A43662566203 263EAC47641FFE8833691D99B5EDB848F7EC7C6E338C739A7186EEC5E9CC2668 A637E238C9554D69C00192BD27A11E81E5ADBDF89F6BA53EFC4227B5E50B6D82 CE13D01D86394F1AFFFF6F3BBC4F4D9EEA716262BBFBB109701B04ECC761386C 5FAE8FF61434253900D5D1543E3C8102AFDEE06BE4C76138AC621C1C677D820D 3AE24C50EFB212F5AEAB08ABFB6095F01361E26D841E3DCFDA482F94FAA3DE47 89B00BF5BEBB097BFA60B7CCCF5B89CA7310DCD5C74391DF99638BFA4015D407 1D21A80D8223224C67960DC22EADEAE1BB1D1D878E3C0744287F85E8C323D010 A533301E30B4D19E6189D00BCBE07572920DD90151377720EAD0D788349D8D28 8B3D48743C4E75C38F684DBD3A203A722C519F7805F74E4F838FE62F88561989 74E743883A3E0A11C6331073653A94177E4AF7EBC701E171FC47786A4C823771 234D97A332FE0EA24E4DE0F44C511AF9AE73CEAD59A84B71459F3EF5808856FE 0691863351186482409591DB4DB6EB62ECA57CCCBCDB8CE966B9432A2059770D 50EAB2192D99EEF8542F073FDDAE40D8BE7F342FA641E550F8F7367D5643CECA 26BA37515B3EC3BCE036FC625781A934A67ACA62B092F1EEF8B5BA3F1B3CC448 659FBA2711B80E08383A796DB8DE2CDF70FD39D58466428B80C19C960872C3F4 E6B4849C9E91187CE80723D7ADE35EECDB56066B4E0B6AA9AFAC6C6DACEE6C6D AC426B8302EA2BA919AC447D710AF25D8E22C3645393EBD61F5E52E487E8CC28 6F6FAEEF6CA776BE232F82DA5A426E38DA7242D09A1180C6642A7F1DD4DF7C10 88A596A9D074CEC0946B71F8D7F987AB991F7A7A66735B539D68E73B0A6208E4 521BD74671B472BF21D9078E057550F62B815B7C2D8A682C7E27BE0653F5C34A 65FC192D327E2C3AA88DED2C8C95F519F222459BEF181D811349D570296883DE FD123824342338B7139BCD125A7AF88DD4D7284E2024527B9D20EB33501C7E89 71389A588D606ADC7664356367641536DC4AC1C64BE15DF38C233F167C9DE9C4 AFA17E428AACADE7369FE2B9979C0495846A84B548B186DA8315D426A926D763 9E792EEC35D7B6C9ED17AA338DF855E82A4DED460A9C42A3A0FCA04470571377 39B5494712EB30E35206E273CA10AAF14B4B0FFFD4AF2D6D0D95C44B165C57E2 1EF24E4620E9BC81DAB155F9ADA4472DA65D4C477E5238F5E1CA117A7C520F3F 84E26AADAF20FD9361E5E10F558F24187A3EC4A28842ACC869C2E1B82ACCBB92 86BCE468D9FDA57E5188DA8F8FF814576B5D29BA8A92F0F3695BE4D2587EE1E5 54BCA3EA473243E83E05223D9EB8B9C4CD0B87B4BD0501877EE8E107AB4D6C69 A92D46ABDB227CB9590326616DD40769C34F9A11F878AB15E26D36A1C5651E61 8E40675B13FC778FEAE1071C1ED7D252550069E02EBC3D6909FEB54E1B334FDF C51E335714445C0692CF03492640E23974F86D22FD1BE1BBE59B1EBEFFDED14D 4D15395D52FFADE8BCB74584E9F4DB28C3BDF5E8B8B7011D77D7D1F95A74DE5D 0F6947ABD47BE3170D72FEDD6D23B25BEBCAEB5B2A73A4CD15D9682E67640A70 5F55806CDED9D2002A60D45D94D67AAEFD2C49CEF7DDFE9D92CFA6AFEFFA6EFE A6CA67F3D72D3DD8C4F8AAC57BD397326C14A8F15CFFF93DCFF55F6E18A0ECE3 69CA7DBFB2FF94E5BE5FD91FA4DC37A7BA21CF89E230DED8ECA634A1571CBDCB 7EFF724FB6A6324965B92802F91EA7E0AF32C9AA37FF51D9EF5BEE9BA99FDE58 9623D2D141B66FAA2943A0FA2F1DFDF8DD655FB1DCB7F7E840E3854477D4C5BB A295C2056B4C69E9C5EF55F665E5BEB3381E89A6BB9078FD08E22EEE45B28506 A2CF6C45B4E136C45D3E888797F6235C6F3DEC97BF3FAA77D94F1165505A9480 28834D68887692BD9B10E6DA6FEEA1DCDF1C11A7D742B1ECCBEA1E59FD13A6B5 0235F7AF8BB051E7763D227690FAAD752874D44798EE3A50D987BCECF7F08B93 10AEB30A352443DAD92EEBF74BA5620C20ED68A76B1DC8B2D144C0B105502CBB 2DEE0BC95D805697058824FDCBBD2E21CB521D5956C791714B0D693754092A48 353B8CD4EB87E17F6A1514CB2E5248DFE42BE45E4484DE3A14BB1B23DFFA04F2 08D9B78E22D3FC0832CC5490765D198997F7C3577D0914CBAE62B90D3EB110E5 1EA668A0B16B555D316A18A467555D111A685C9A7455054E7B26A357D95528B7 41C7E6A1C6E332CA699C36CFFF1476475CC4DE884B5848BF0B1BCB9075F5086C B78D459FB20B79B90D3DB90835313EC822936B5787E166630A6E36D338867EE7 D2B5AC9B9AB0DB3E01838D5F7DB68E08093AB514097A5B9177760F320D76205D 6F27527477215A6F07EC764E86D59A2F7BF8FF5BFA0003D505C6DA47FEA8BC73 3D0EEEDC84AC7077ECDEBC1A3BD62F1B525D7070C786FFB8A87FFCECD5B32731 7FE6AF78E0698D85B37E85A1A60A2EEB1F435356E863EB82F3A78FBEB779F5E2 06CDC3BB31FDA71F705E4B158BA74F84F1C90398F3EB4414C6FA3EB62E9830E6 3BCD150B67C1E98621B6AD9A07AD039BB061E96CD85ED4C1F279D3A1A9B28BEC 1185F69C30114773FA3DB201C5497546E8C9292D24BB66DBBAA5583C672A664D 9B02FDE3CA98F8C3F79832691CC68F1E81CF3FF9485627711C3C8F921524E269 A77BC47D004A7F6BB0B723AC2F1BE0B8EA7E2407B961C78695F075B480D5453D 2C983545D4271D62EE41A6477B4E684F1F60EFD635E2F9A3CA9ECD58BF72317C 6E5FC5AECDAB70CFD912EA07B663C497FF127CD681E7623AF21EF4EA036C58B1 50C8DEB365357EF9712CECAF1A61E5A2D9B8A07B0C9436BCFBB7B7BBB93184A8 7E7D8049E347A74D9D342E6DC6846FBA962E9C030FAD4918FFF5FBF869E487F8 FE5FEFE287CFFF8C16D7F9320CB10F80D41BBDEA12F1F2C2FF47FB00EE475E71 F1D2F82B3C4FFC99C6A47F22FCF909F89308CB1C19F72FA889BB8ECAE84BDDB8 FC04C8C23187B91EC7FE4065CC1399D7BE47E6F531C8341B8B0C720742A6FC37 85650E73DDD55EFBCDEF1F32D75DED15F1FBB8FA511CDABF0F2ACA87E0607F07 E9E96930BF6126909E9E0E73F31BB879D35CC0CCEC868C7FE41501D9FB7745A8 282F457959098A0AF3919F9783C2823C81827CD9EFE2A27C995F7E5E37FFE51E F97AA7754807359C3C710C3E3E9E282B2DC11D3B5BD8DFB113BFD97574B017BA D9D9D93DE213F8E0F7D69B797EBDB151CC17575755A2A6BA4A40FEBB8EAE3378 FEBB2FDFD8F02CB44E9E808ED6290407F8A3A1BE0EAE2E2E028DDDBFDDDDDC04 5C5CDCFAF13B79E2521C5D686F6F434B0BBF03D722207EB7B588EB0C7EA6DE97 7FE9C205E8E968E1ACBE2E2223C2D1497D045F5F5F01F9EF7BF7EE09F8DEF5EB C7FF2D879B82FD6F5CBB8EB367CFE29CB111E21FC68B6B01814184E0EEDFC108 0A0E15080C0EEBB9FF1EEA6FFE66F9CCB5DEFB7200BBAC470F482FB7EEB4F5FD 2DCF3372AE7C19D06F44FFE346F0BBCF9A87583C7F33A4FC59F36029E339FAFD 8C79F045F67BEC64C28DE08DCFDC08EEA86E6D476347270ADB6408AA6AC4DBB6 91EDE4DFCA6106E16E25E0646251574DA714312D9D706CECC46DC2D5DA76CC8E CAC6EA07391C07FAC5417A91DCCEA34945886E6E477987145E8D1D7027AE7D43 07AE56B7627E6C2EAC6B5AB12E3AB793C2B72BA685D276ED9D3B0FBA821B5AE1 50D3825CD2F95E431B1CEADA60419C33C5F558189F8780C636EC2EA8C15BB723 DA88AF2BE7BF702BB4D228BB02E74AEB615ED188680AE750DD0CF3CA265C286F C489FC1ACC8ECDC175F25B96598185D1B95DA46FBE9C4F36EEB228ADC3F1FC2A E815D5C2B0B80E862575D02BAE8546610D0EE45461477625366496E387F8424C 7C5800E24BE5FCE7CC837185C26E4E2FC5B68C32AC4C2BC1DCE462CC4B2EC11C 72272514E0DBE83C7C1A958B0F23B3F18FF02C083B3EB21F54B24A313C2C137F 0949C726E22F225BFE1A5F80D13179F824220B6F793E107E6F05A5E13F0353FB F1F5F22AF0CCDD043CEF97886F28FCCBFE4978C53F59807FBFE01422FC388CE8 74F6E147D4354397E29090FF072169C2ED05C760C1D5CE29EFC7E77B5FD0D88A 5B2535F0A96AC0A9EC721CCC28C18F94675E23D933E3727125AF1C11B5CD420E 877DC62CA85341BE2FC79755DF82730555B85C548D1BC535B02AAD855D791D1C 09CEDD2E87E9CE83768A59F0C59BC1317C7D79402AC2CAEB51DBD6017EAEC3E0 DF7C8DFD38CC7366F7C3072C03D703E63E73C537FA3F2D821B5FBA19DC49E9E2 FB8C97CD833BDF340F6878FE8A6FACE4A2CFF47FE7BCB9621FDC62D377EF596F 1B6B66BD7D6CB6E59651CDD6DBC614D1EFBB747D01E1853E6155087F78743E72 AED5D6D1CDF70DB7B627389D454EA00DB2036C90E87C0EDEDA6B1A2DB77C5F4B E1978AB09B476EEE7E0EFD1FDD717D6AB56D4C5382BD3E32EF5D43969F398A1E B8A12CC11FD55951A8CD4F4249BC3F1C956734915EF7EDF6FEDC427174128F2B 5F09E979E5BEE13669C8C57DB0511A07F203E9DDE9A9B9AA21CDD7BCABAE3095 C61E196828CD428CB58EB43C359CFDDB88FF06F349EF06BB3D3FE1F68E715D74 BD89AE1F24FC8DF08BD5B6D1D1DE3AEB9A2A32A2D154918FE6EA62010AD74EFE AF75A79D791D61465BAF513A8BE9FAF03EB65ACB3A95A584A12235144D9505B0 92F15FEDF6EF745599A91E7BEDD0BF7C4F2E798BCE9F55E03E4FFA05C7DD39DB DE5C5D22D2C1F289DF417EAF74877963B07120F9DD605BDB1FF8B5D55179668B C0E1992DDDF67FB93B0CDBA2AB1B52D687C0F17B739E20BC3D00FE4B41466753 55119A094D958548F1BC2AB5DAFA7DAE62FE9023C942FD9DE84BFBC674CB78BD 3B3F74729A2A5282519E16816E3DB6F749C76B969B4796459CDF61E0796C4160 B7FE224F92CDA5CC67BB365515A2383E004E2AB39AE8DE45529851DDFCEDB795 C65579A8CDE17BD765B9F5FB7679DC645F29E7914497F35D8D65B9229F546546 21DEFE6C97D3E1994D24B783F227085DB7778E075DE3386CE47C92DFE5796A45 0BE5CD4467D5D98D05916EA84C8F40C9C3BB28887042B6DF0DC4DBE920C65203 090E6740F2388F7DA6903610F75CF7EF85565BBEAF763FBEA821C6EA14523D4C 91E17D090977741168B2B393CB18D96B451FDBDC243CA370FE029759D2D18F6C 5046E1DBE977A1B5D20FB674FDC3DFF29E90CEF4F7B5B4A7BFDFA633635828B9 1FF5F527FDB5484E1BE9174A327AF9537825BDD9C31BCDD67D830B4B3F93EACC 783F8FAEBDD6A3EFE6914AB6BBC637865FD8069F930BA5565B46E5C9CB96903D E3FD2AB3B55FF7BCBBA23F67783DF16729C8AE0A3BBF05B166FB04EEEC99584F E16675CB7E9BF82D8AEFBE982CFEB493AE6B77DBEA6DE2B7C8B90CAFE3733B49 27ED6EFE2C83B91FD62AF22FAFFC02A7670C8BE8E6CFB2DF37A956911FA0BF1A D6DB464774F335589E22FFC6FA6FF81D9EE66EBE86D7F1799D8AFCC88B4AA03C D7DCCD57217EBB229F6DC13691D7C39EC7E6B62BF2C3CF6FE5FC54D5CD9F7766 EE47BDF4BFB4E273D6DFA79B3FCFF1C0E45EFAFBEBAE60FD7DBAF99F9E9E39AC 41917F6ED1276D745D555E77DB6C1FDBA0C8F7383A9BEB13D56EFE8B04E900EF 304DEEE6BFD85DE7F47D4769F2BFE3FDB66E1D0AFBC86EEF9577378F2CEC23BB 973FE779BEE7EC776DCD5764FB61798AFE9CE7EFEBAD12690F31DE48E5FBFBBC 3EF237EBCFF9B0F93A71CFCEFB88CAD0FBBA7DCAEF66CAB3CDA1E736C1E9E02F 6D74EF74FBF05FE67C446820EE0572FFD087FF32A54183D04065E7C240F56E77 3CCFFE16FB8584841C8C8A8ABA74F7EEDD7143E5ECDFBF7FDCBE7DFBB44C4D4D D3796D19AFC18A8D8D6DA1EBFA3B76EC18F704EE4AE266FAF8F820353555ACA9 E2F7DDF8FD2BD2014A4A4A99DBB76F5F3918FFE0C183A1C1C1C1C8C9C911EBC2 583EBF2FC6EBCBF83D2E1E3F930EA17D794E4E4ECFD8DBDB3F636E6E5E2F5FCB C6EBEAE46BEAF85DB8ACAC2C646767E3F4E9D3CD729EB3B3F3738E8E8E1FDCB9 7367DCEDDBB727513C5D0F1E3CE8794F4BBEAE4E0E2B2B2BE6F7CCBD12F733E2 5AD9D8D8145B5858D4937C787B7B232C2C0C7E7E7E623D218F7F030303C13609 0D0DC5A953A704DFC1C1E1754A8F474A4A8AD091DF91E3B5881E1E1E205D40F7 0DD1D1D1888C8C143CBECE505757177C5B5BDBF9010101422F7E2F4DBE8E8EE3 92C7C1F780D3131717876BD7AEC1DDDD5DAC891365C7D2D297D75D6666668A70 6C1F8E87E3635B6B69698175631D78FD1DE507B8B9B9893596A21B7FE3461CDB 98D3C8F127252589F9168E83DF173C7CF8B0D05BCE37323212EB0777EFDE2DF8 972F5F76E175817C8F3D3D3D7BD2CC71307FEFDEBD226ED6FFE1C387D0D7D707 D99BF390E09B98982CE7F4701E63991C1773197CFF77EDDAC5F916111111423F 9E23E07BC36B197BEA071D9D3B1C07DB9ED32CDF0B82ED676C6C2CE2E573CE37 898989A034F33ACA22395F4343E319353535075EFFCA72D98E9C5692D145E500 7BF6ECE1FC8AAD5BB762D3A64DEDC4CD5DB366CD5B7DF32FA5751585CBA77011 1B376EBCBB76EDDA754379FFF7DF72A87AA31F9E827BB9A64B80ED655AD9850B 84670E7B6028DC6BF55D02CC659BBFF9E69BB854DD858B84E7F6DBE3F9BDB678 6197255EDC7E032F6DB9829737993E1A3BAA7822A41534B6970A3EFF66BE752E 8D01D32A7025A90426B1053088CC817670264EF8A741D52709AFAD92ED03F0AC B21B829AA5B8DAD05BBE718514866552189448A15B28854EBE145AB9529CCC96 E290477C0FFF99832EF0E3390AD29FB9E27D22728D887BA6540AFD22294E1748 A19D27A571AD1427323BB1CF35B687FFDC0147F8D4B4E1725D9738671DD83524 AE417117F4BAB99A3952686449712C438A9D8ED18FF8641FF7CA665CACEDEAC9 AFEC9E21BDF50ABB703A5FC665D9C789AB9ED6896D760F7AF86C5BE7924698D6 F496AF5FD405DD822E05BD899F2E855AAA149B6CC27BF82FECB6867D613DCE57 497BC997DB8C659FCC92C93E9A26C591E44EACB5087DC4DF65019BDC1A98544A 7BC93FDD6DEF53D99D42F631E2AAA5744225A9132BCD831EF17798C322AB0AD7 534A611A5F0CC3E83CE88667E354603AD4EFA540D92B017B5DE2B0DD3E0A1BAD 23B0EA5630965C0BE8E1F3C1F9E9958D17F0F2C6F3786583095E596F4C30C2AB 6BCFE235C2ABAB0DF0DA6A3DBCBE5A17AFAF64E8FC8F7EF14E79C60F5ACAD3C7 E61D9E36BA5365FA68A9F28CB10587668E3778226FDAE8618767FE901F646F81 C69A2A483B3BD1D1D6829A927CF8595E86CAEC096587668DFF7830FEE159E38A 7393E2D0DEDA94D458536ADB509E6F515D9066539193E052959F9A961CEC8D23 F37EAA1D884BF19E61B9C44D6E69A8B9D1DED268D65C5B71B3BE34C7AA2A37D1 B63021D0BA282924C1EBAA0194E7FD7CB35F3532776215EBDC54537AA7BDA5C1 4CDAD97EADA5AED2BCBE24C7A2222BCEA2303EC032F8DA61DDBCF8101C5B34A5 B92F5F65FA18293FDBAE2FCBB56C6DA876E93BD79B121510E0ADB3EC4859460C 54678CE9DABB71DDB3BDE4CF18DB453AA32A2FD9BAAE24DB9A394DB5151195C5 B951F9E9F1E1D10E46461E1A0B8E962447C8F9AF29F2D517FED25855948BD2B4 07F6A529E1E2C17D41DC7DD3DC48F70BC9DED70C7D4EAF3C72F7CC5AFD8C3077 9C5C3AB5AD5FFA974CF7B967711195B98929A97E563C1645AA9FA549948DB6B6 F7E915AA2EEA338EA705D8263B1BA9E3E4DA85297DF9A4CFABC797FCDA9214E8 89C284A084906BCABA628EFCC47C751F83D50669F76F27873B5C81E6B269ED14 76C079E4FD4BE7CCA238DABCAEE823372E90D21285A2E430A487BAC3C5501D5A CBA777A8AD5FB6FD717990E27EEBE486A5592757CCE8BC78C70A17EDAD71D1D9 0EC7B7AE6E20BF7F0C25FF4F5AB6ECF509AB5723A0AA0291AD4DB0CBC9029F0F B5FC10FF250EBFF2F8719CB2B5C1663DDDA7E2F3C1E17D8A0BBA229A1BE09494 D0F51BF833478D19633965CA94CAAFBFFEFA369F0F146EDBE5AFF0D3F0E1BF09 A4907053CB2A7F137EABDC7E7AB4D60D8AC7F92BF2078B7320FF81F8BF573ECF C42AA21F5FD1F3BF413EF5067BFFF5E52B761BFF3BD2DFE7AF2F5FB1D3FADF92 FEDFC1FFDDF9B7FBE87BFEA4E3DF219BEB00DDB3064FBD77087314F70F7ADA83 F76CECCB6F91AFBB7E02787DDC60FCBEE5A82F9EC46FA431E3E3F024FEEFD5FF 49332BBC7FC26F91CFEBDA99CB69781ABE228FF76DE031EE63ED7F4CF258D4D5 D73F962F6410EA490E87ADADAB137B3DF0FE00BC668EC7E483F1FBEACA71F05A 409ECF107B2075C733189F79972E5D7A2C782E67303ECB54D495C3F29E4C3CA7 225F43C8FB2F0DC6E7EB4341DFF2C36591CF9F06BA67F4F1EF5A431C7165E308 39422FAE1F11747ECD88FBC62B47C8FD5D35E78E70383E73C4ED23BF8EB87568 D288EB7BC68FB8A8347A840217090E1A88BB731C31B78FE281D51184DE3800CF D30BBE703935E70BDFF3DBE165B21D6E869BE1A8B71E76DAAB61BCF15B5CDA31 6644E8A50D08BFBCA1D73E49BCFE342DD419CE276717DF519F5E9C12ECD86B3D 2B436FD5E730DD361ACC0F315D2B788AF3649C6FB252E351519423F67BE03925 9E03E2F74F987F6AC9C730DA3042F003CEAD147CF9DE8E7CAF791E8BE784780E 92E7A1380F725EE03920E61F9DFB3E74577F01B217EE9E592AF82C83E5878484 8879229E0FE2B920E6F3FC15CF07F23C20A74F79FA3B38B5F413049E5FCB7612 7C96C1798EF319F3799E51CE67BD381FF23C1DF3F74EFE338E2D180E3FA3956C 27A1933C8D2C9FE79FE47C9E1B93DB85E71F99AF34E10F509DF577F8182C85DD D169822F975F525222F896969662EE8FF93C9FC87691CBDF3CE6351C98FA0E3C 7416C252F9E7DEEB8DC99FE3E27934AE6FF85C7EBDAC7BEFB2F5235FC29EC97F 81D3C939A0FC04CA4F38B769040CD67E09EDE59F4263E187B0333C00DBB3FBB1 EF97BF60E7C4FFC4B6716F60D3E857B1EEBB17B1FA9BE7B0E3C73FC24E7D3A5C F5560D88A3F3864165E67B83FA6F1DF726283F0F2AFFDCD63130DC346A50F92B BE7C66D0F777896F7668DADFF2E83EE5D16F9F7FD7B39081101B1B3B75A35E20 A61DF6C327EBC4BAE05143C4FBC4FD92F24D6370582402C2A2F1CF355E83EE65 D6171CC7E1C3875F7476765EBB45DB1B5B2E87E09FABBDC4FA6F4570FEE53C24 0797335EBFCE7C45F9F749FEC72B3CFBF1E571C8C1798ACB4B2FF9273DB1F952 303E5EE6D9B3C63DCF521579B70E1394917BF310726F300E081DE4FC1EF9A1DD F217BBF7E463E696DFBF45B829DEB72FF7BB819CEB7B059F755294BF59C31D9B 2E04E1A3456E3DF598A2CC9CEBFB9179751F32AFEC96EFBF271D48FE47F35D84 6DE4F5A01CB235F5B2F690DB422A8F8DFC0E985CFEA663EED86812880FE7B9F4 7073CDF623EBDA5E645EDE85F44B4A48BBB81D89E7B68B72CC75593FF9A1D118 3EDB59F0E5E595E5F2B317C5FA9975E0B9F8E79E7B6EB45CFE4635576C300EC0 F019BDEB6AE6CAEF979CCB7514CFF7F7971F850FA639F46A07D8D6F2FDFF98CB F5183F6FE89BFF36A8B862DD597F7C30C5A1D77E7B2C5BFE5C45CEE5B8E4FCBE F287FD7C473CABE23072F95C27727BC075579FB97721FFC08103C33E9F618991 AB1C316C925DCFB314AEC3E3E3E385ADB83E6597DB016EA7B82D60BE3CAE3F7E B4F6C7B7BF513FF1D6C71B363E4DF9FDBD7587EDADEB9782FC7DDBC383FD111E E88790FB3E08F071C73D0F6778BBD8C1FD8E259CACCD6077E322ACAE18C3FCBC 1EAE9ED58489B65ABBFA7EA55DC4ED9A3E27017FB5CFC704A749C8CB487E3232 5350555E02BD23BBCE4504F9C3CBB70E2685CD702972435559F190D0D4580F2D E56D26ACEF37DF7C836FBFFD1623468C107B5D8E1C3912A3468DC2F7DF7F8F31 63C6E0871F7EC0B871E3307EFC78FCF8E38FF8E9A79FF0F3CF3FE3D89E8D2641 7EDE82C3FB640E1B364CECF5F8E1871FE2A38F3EC2C71F7F8C4F3EF9049F7DF6 99D887F38B2FBE10FB79B2BC2953A6E0ECB1FD266C2B399F9F33D9D8D80C994F E937F1F374113ACAC373FF829FAD0DC4E134CAD3C77B8B6A1EDA6AE2E37247A4 EBD34F3F15F98BF7B6E43D2BFB72E4F6183D7A34C68E1D8BD9B367437DF70613 0F076B4C9A344984FFFAEBAF05476E47E630E41CB623CB62CC9F3F1F8795D698 B8DC3617FB942A72E4769773D8F613264C10B69F3871A2B0FFA2458BB07FF30A 13078BAB222D2C43CE51BC57F2FBC53A32264F9E8C5F7EF9054B962CC1AE758B 4D6E9B5D106991EB259723E7F07D9673D8E60CDED774F9F2E5D8B66A81C9B573 BAF59C96050B1660E1C285422FDEF793E3672C5DBA14CB962D13E157AC588195 2B570AAC5AB50AEB16CFD4D738BC7BB791A65AFC394DB59CB31A8772F4D5F7E5 E8A8ECCC3975705BCEB13D9B725477AECB39B46D55CEDE8DCB7348DF1C9299B3 79F9BC9C758B66C62F9A3979E2BFAB0F40C77F75BF13FCC43A831F7B0DC01F41 F55D2DD57BD2C1DA7BAE0F4D4C4C8C068A83E3662ED7978A6D35D7DDF267C91C 07F72DCF9F3FDF2B0E7E8CC67CF6E7F686DB0D79BBCFF536B777DC66B13FD7E9 2C83C67246F2FA4FCEAFA9EDE8D5F6C8DB2E6E37B8EF3C50FF45CE7FE9D55193 366E6FC0FC05F5C26FF992466CDADA48E3BD965EFD7FD643B1FD61FEBB5FE4BE F5DD8482F80D9BEBB1784D377F4523B66E6DC006A5069496CBE2908F2FB83D91 F3DFFDAA72E9F459F52DEB37D561D1FA7A1494B40BBFC2E2762C59590FBE3E6B 411D6EBBD7F7B4671C8F9C3F657A5D9DD29E06FC3ABBBA333AA9A557FA62125B 317D5E0DB6ECAAC5F4653568686AEDD97F56CE7FEBBB92A593E7D6B6ACD8548B B99BAA905FDA26FC588F05EB6BC0D77F5D54051BEFFA5EFD7BC5F4BF3E2AF9AD 4F7E4D8F5FB4A91AB3B7CBEC3C7F630D9631F691CDAADB7AB5E97DF96CFF67DF FC76D292FDE598B25E769FA7ADAC12DCAADAB65E7D0F39FAF2E5F9A72FB81D1F 0883F0BB86DAF7254815DB6F3ABE23DB34F1F5A170296C03973905FE7B1CC753 B4FD5CD6DFFBEF1C573C0DD2D2D2B6507FA799DAC09AF0F0F0A2FBF7EFA77A7A 7A063938389CB3B0B0387AE5CA955D464646D3B4B5B59F1F70DFD3B8B856EA17 B60606066EF92DF2838383A577EFDE75737575FDC3D3F03AB3030A08F0F5F680 AB33F51D33FCD09AEA8BE6244F34C4BBA236C6015511B6280FB140C97D3314DC BD8C5CCFF3C872398B34075DC1ADC94FED41755E0AAA7393519D9388AAAC7854 663E44457A0CCA53A3509E1289D2A430942484A0E46120926C4E42CE17653EEA AE70F3223C859B13E424DC4CBFDBC24DF332176E4B432D8A62FCF0F0E651B467 FA0B79050F7C901FE185DC5037E4043B233BD01E99FEB648BF6B8534EF9B48F1 B88E64D7CB284B8E94956F0A1F734D59A4B52A3BB1276F66073A08378378ECA6 128FDD2427D35E79382FDC039197F6A129D183D21827BE4B94E56F878C7BD648 F3B985544F3324BB5D4592B329121C4CF0D0EE2CE26CF4116BA583E85B9AC80D 7145D8F95DA88F7316B6E138D37D2C9E58EEA2CC357A6C1362BC1DD50FECC8A6 E1284D249BC607A1282E40D8A6806C5910E94D36F1445E98BB90C776C90976A2 343A8A74061B6EE5FB5A31C07D45F26D4D24581E43DC8D2388BE7A48A435FCC2 2E849E5322DE36C12554FCBF5DEEFA1E77EEDC798F7096CA5CC9AD5BB71A08F5 0E4E8EBA7DC3393A3BCDB4B4B27219803FFD96C5AD4AF2176B93883BCFCCCC2C 91E22BB5B0B428A4F339DDFC04C289BEFC93274F9A181A19D59E3871A28860DE 27EE7F58595BC75B595B85DB3B3ADCE06BC74F9E3AA6A1A985933A5AE2B90471 C41C9DB9C52D689CD4905DD3D2C4318D9335274E695AF495774A5B87DBD32EEE 2370BB40F2C51C97ADADADF8CDD7B8DD4E4D4BEFE2B003F14B4A8A697C16DFC3 E7F7BBC86E3D7CF6E33043E133A88E13909F0F95CFEF99F56DE7F8DA50F972E4 E6CAE63C15AF3D8E9F9E968EE2A2E21EE4E5E5F53A677098C1F845E4FF30EEA1 187FF0DABB38FACDDF70888A8E42048DB9C3C2C3C43CEA20FC287EB72E263646 7CDF27262616D1CCED9E4BA5B6447CFBA99B1F3500FF16EBCBB2A3686CFDE001 F31E08B9E12497E73CA3E85A37FFCA00FC8DDE945FF8BD471EAFF3D89C65F2F8 9CE751395E7EA7D0CDDD9DF9CA03F0DFD4353813743F2040D82D373757D89FE5 31783C77CFDF1F97AF5D63FE5F06E0BF421846384F08631B0D805CC2BB8497FE 37EFFF33D83E2043D9FFE771FB803C69FF9F27ED03F2B8FD7F86B20FC860FBFF F03E208F5BFBFFB8FD7FE4FB80C8D7FE4FB1D9876FCC36F55AFB3FD8FE3F8AFB 80C8D7FEFF64A184E5AE27F0C9C5258FDDFF47CE1D6FB91B632D7663D4CD6DF8 F6FA062C725483D1035BCCB13B80778DA6227890FD7F581EE3FB5B4AB810E304 93687BC1337C608303770DA11B668E29965BF1AAF6483C73F28B67FAEEFFD3E2 B658EC23F28DD906C1DDED73064A5EA7B1D94313EB5C8F638BBB064E065EC4B8 1B2B2139F651DB606BFF3FBDB2028691B761106E09DD5073E8845CC7768A4323 D014532D37E33DD5E15D1295775F196CEDFF70D37978CF681AFE7AF667FCA7DE 0F186BB61AC7032E60CAADF5F8D2640ADC367DFE546BFFFFAC3F163F9BAFC1B7 26D3D1DAD1FAD46BFFDF3CF241D77347FE0E8F3EFBFFFC5EF89E5EAF541868D9 58E0731EA98E3A48B6D342E26DFE66A661A3D7A935B7F3EF9935E6B91920CF45 97FA9B6A88315346C4CD538D8E87172B897D36FDCCA455E1B75115662350196A 8DCA104B54065B20DFCB141541E6A8083043F9FD6B28F7BF8A723FEA83DEBB88 2093FD52E617789F4781B7090ABCCE21DFD388CAB621F2DDCF20CF551FB92433 D7F934721CB591E3A089EC3B1AC8B23B8EACDBEAB8AFBF45CCC5E67B180FFA8E 428EBDD6A07EBEA7D6097EAEDBD941C364DA6A0CBEF6FBD80AC1CF76D61F344C BA95FAA07ECECA8B053FE3313A269B1F1ED4CF7ECF7CC14FBB3DB88E09D7F60F EA67A3341BB2F57C6A838689BDB86B503F8B2DD3053FF6DAC141C3841B6E19D4 EFDADA5F04FF81E9DE41C3849CDE30A8DFA5553F0B7EB891D2A061024EAD1ED4 CF74F944C1B7DA39FBF67D9DF5B87B720DAC76CCC1CD6D3360B6691AAEAD9F82 AB6B7FC9F7565B02F7430BE1B26F1E2EAFFE19A62B26C174D944C6EDFF09E3EE DF7BDCDE3B4F29CBD9A031D3FA0832AD54916EA18AD49B2A48BA710889D70F22 9EF250ECE57D88B9B4070F2EEC4684C90E045F566D649ED83BF18EA6B4D4DB18 4F8B00C3DD62FDBB90FB1B705F4F7C8B4A9261A1FA9BF66EB8A7BD41F0D36EA9 C8F6C8EAEE6F727FB1ABBD45B64F85AFAF5893C2E7BC66C5C9C949CCAFF3E1A3 B956F0D956BFE5F03C217B1F94ED2CCA0AF53959F6FDFBF7853C1EC3787979C1 C5C5459CF3BA187E9F809FC98BF772D565DF9BE57BF4B4476279338E6B19E1EB EB09131E5E95D511BC368965F3DA1896C7EF3EB8BABA8AB5567C7EF3E64D5CBF 7E1DC76EDA4337A0040F0A5AB1F156627994E9EE21CB8DAC6AC5E5FC461C89A9 81964F110EDAA5DD8B3491D531BC4E8AD32C4F2FBB0E0E0E22BD7C7EF4869DE0 EECA6BC1EEF446AC3194ED7F1D6EBCE38972C3F3AA609A5CD6C33DE05684DB54 9EBBF3FFEDA0335B457EF2D3D9085FCD75F0A6BAC08DECEBA2B61CDA87B6E26A 583E665847637D44315619B883388CDB43295F6F2F3D745CDFAF12F32F24E3A3 DDCEFE4F5B3EDF9AB874E27B8B8F1EFF56DD4369B030A9A9A9BF262727BBD258 C5FFC18307FE346EF1277BFA7B7878F83B3A3AFA930D5D694CFBEB405CE2BD4D 631447C5BDD215F74CE77738786C44F9DEE9CC99336F0FC09F43E39E1A1EF7C8 9F7BF2B3521E4BB1CBE52A2D2D8DD7FD55137F6E5F7E4A4A8A07CFA7F31A341E 2BC9D76F713C0CE6B27C7E8E6A6868E8D1974FE3CC74F6E3FCEB26F6B67111E5 94F3CE9D3B7744B9E1732ECB2606DAFDEA202E733C56E5F24EF18BF569BC0685 5D3E279D4519E0758BC78F1FEF5707F1DA347E9ECD7997E5F1BC03CBE4776F2C 2C2C44B9E167825C96555555FBD54174BD8EE507050589B8580E97415E43C3E5 8FEB1D5EEFC6F510AFD9633F86BC0E22191BAF5DBB76FCFCF9F3C7F5F4F48EDB 1BAB8BB4B03C2EC36C0FE673BDC5D7F9D93643B10E523CE4F511AF2994974996 2D8F8BED2AAF03E57590E2A1581F29BEF32697CBE0B9093EB87CF5E5CBEB234E 23CBE4F4B33CB94DD99EBCBE920F27D5A5FDF8F2FA4851D640CF03F8B8737061 3FBEBC3EE2B4B25CBE777C1FCDCCCCC4DA49F97B847CD8EE5FD08F3F94FA487E C8EBA03EEDB1A88FFAD643CE4796C2416509EC48E7DB24B76F1DA463A0379550 6978FE5C52DF38E9BAA9BED1D9EA01F6EC59D5F3CD2FC333CD2D2D2D520AEB69 6C7AFE68CFB7B08C0C8BE312E2BB88EFDF873B5EECC3F34846575C623C7FF740 7AD6C4F88EF8AE96BEEE8FD6776C11141ECAEF1BB728703F7CEE6648FD73E621 8AEF403638B9BBF23BA05D14570AEB403AB547C444C1CED181F54AECE6FEE773 B7420B0EA65774FDC12ABC670F18923586DF8B4CCBCC601DBA28BE22572F0F3C 8889E6F725997F94B82F10377C494C41FBDD662914F9DD3AE4B978B88BE78657 CCAEC3957EBBFB783157CC9312D772AC5F5A8B7DA314CE4D52FC876558671F3B 8F603BE4E4E5C1F4EA6558DEB661D92D7CFDD99B21473E708D6BB2AEEBC0FAD2 365890FB661F7EB70EE69EBE3E52B61BA5BF8BD2654A7A2FF8834D64F3958A16 2815B760724E23AE56B7E10D8BDEFCB7DF7630F8EB5F6D5B5E7CD10ACF3E6B85 BFBD1386BFFEED4ED37F2CF1EAD029A8C781A2667C1F5F8E1FD3EB6052DE82D7 BBF97FFB9BC3D1975EBA2D7DFFFD78E9DFFF1ED3F5E67F784A9F7DDEBAEB9D77 22F08F6171F8C7FB0FF0EA6BB7F1F99944BC6C1D89B1C955D02B6EC46BB7C23A DF79C771E58B2FDA74FDE31F711DCF3D67E3F5A73FDF6F7DE6192B48E638BDF3 EEDFA3F0A7BFDDC73F27DDC37BEF47E3C517ADF1FA6A6F7C17578A53F9F578F5 5668E79FFE64573C7C789294B8AAE221D87B314DAFBE7ABBF3D99BA1FECF3D6F 837F7C1485710F4BF1CACABB1DFF783FAEEB8FC3ECF1D58322A86657E3959BA1 9D6FBC61D7F6DE7BB1221FBEF69ABBE1B06109D257DFBD53FDB16B5CF3B0EFBC 30FCC364FC617E90D8B7E7EF94963FBC65874F43F2B027AD022F13FFADB7EC72 FEF9CF0C29E94FF1C4485F7CE376DD9FF5835B55332BF1836D065E7DDB011F0C 4F24FD63F1DEDF63F0A7618EF828281B9B134B059FD3FFE69BB6257FF8835DE3 9FFF6AD7F69A5660AB12F929A75762674A39661925E0831FBCF09F140F73E7DF 49C7AAB822AC7F58849788AF5026BE20343E6F1ED2F9A66578F31B84D72D6478 4D01AF5A8409BC722BAC99F716FAF9627CCD7893388C358E15E0DF3F993E2CA4 EBFF9A7C31FE5BC2881E5C62247CAF9867387C2655C7A92D3264B40323CF4463 8C514C4F9C8AE0F0932EC697CBF93FD0B524E2AD7DD8867571AD70AB9022AD19 3DDF0F4B6FA338DB646E3AC59DD30511C72F971246CAF991147E5B521B7610B6 27B6611B837F27B74329B5034A699D504A97621B81FE61DCB9388C3A62FB95F8 D619F1EF3780EE6707F6A777E0801C191D38942DC59CDB9918A51789917A0FF0 1D61847E14BE378C113A908D1CC613DF8BF8CAA4D891DC2EA8E53180A3F9C07C BB2C2CF62E15E960DB44D5D198BC45860CB2D9048A63C2B958B890FEF3EE6463 A46E640F461156DCA33E27E9A594D28E2DF16DF8F24A3936927B32A713B679CD 18AB1B103EF17C1C0CB35A31F9462AB23A6536627B65937B806E8C7266070E67 7560B6571D8CCBBA30D5AD16B72A48BFFBC5F8F6E0AD3D932E3C8481C555685D BB88144F5DE8395BC1D0C512AA39521CCB9742A3B00B7BD89681F5E05D03B706 36E00CC539EB6A3CD7BD7FDCAD4D75A6B70152BDCE22C278A270337CCEE0B297 0D16FAD4E3DB2B65F8E252193CABBB60572515EE17948E6FAF964B479B575DDA 7EEC3842CE2FA2B1E11C5CBEAC8228D3D988B9BC18576CF5B13CA0098EA59DF0 6F04B4F2DBB186ECA059D08108B2A75369077E30CBF7CDF2388E42AF0338ACB6 1713E85EEC5153878FB516DC6F9DC68F676231E66A1E168634419D0CB232B155 B833E9867FA917E74EFA7FB877F64766B1A6D391E36F0CF3A3F3DCB75C0BC6B7 3484FA210018ABE51FF7C97A83ED7B29831DA29BB8F041138E64B6625B7803BA DF3F9138A98CDA5D784F132916AB80147DFCD9AAB3CBDCDA0CCA5A2733A779D7 E0D75B45A6CA49AD98605B856FF462EDD955A30C30E64685694F9DBDE6F3B3A6 5B479CA8765E8D0D7A969814D0865F7CAA304E2F3C78FAED2A8CBE5652FBD709 CBA751D07FFC85DC1F6F94D4FE625D8971B72A5E54288ACFF172E697BFDF3DEA D3E57ACBFFB9ECF4FCF726EDFCA5FB393FE77579D817BBCFF9FA33CB972E715E B66431962D5D727BF9B26592658CA5722C952C27B01F87E1B02B972F932882AF 87848661D1E22598B3703966CE5F8E19F39662C6DCC598397711E6CC5B84450B 1789301C9639AB562CEF019D63C9E2C598BB680570E303C07E0AE0B596069407 A8C06852C131C6DCF98BB164D122E662CDAA951245F035FEAEFBAC05C4B7FE81 3A5EEBD0E97F149DE16768E0A60B449FC2AC794B284C480F7FEDEA5592D52B57 08F9740E4A37C9A7FBE73C179DBE07D0EC73100DAE5BD1766731C53991FC6461 38ECBA35AB057FD58A15127D5D1DC93ABAC6712F5C4A7CF7058435E8F03B84F6 0035EA206FA48C3A158BC82F3028046B29EC7AE2AF21D9067AA7253A5AA724EB D7ACC1EA9514FF8AB598B36423A62DDC80A9F3D762EABC3598367F0D662F5A8B 65CB5763D58A95C45FC5909CD1D795E8EA6849B44E694836AE5B8380A0602C5F B98EECF71ED96F22E0BB1208DD0BC49C22FB1961E9B295F0F30FC0EA15CBA1AF AB2DB82C9BF99BD6AF03A507ABD6AC858DFE1E1C56D7C43E6535ECD873106735 55E81E9C24DD56E3F0A18338A5715CEC4FCAD03C79229120D9B2713D8D3BEEE3 A89A2A3C69CCC0DB80961497A0B0B008B676F6D0DFBB10BC8785178D47C41A9B BA3A949514C3C9E10ED4540F276EDDB4916D22F63EE5E3C4B1A3D84C71AAA9AA E0E811558AF7088E1D5523904B32B66EDE4479610132D2520567FB161A77D3B8 E7F0A103A8282B873A8551DAB2054ADBC4FE1CA8A47168617E1E8202FC457CBF 4EF965DB827973E1E2E448B2D4B161ED1AFF6D14E7817D7B505A5C24D2B863FB 562C5A309FD2791CAA879545DAF7EEDE25F28FD2B62D58387F1EEC6E5BD1B59D 907F9F6FC7F62D290E77EC90929488C0FBFE38A3AF871FC78FC3D75F7E513DF2 BB11D18B172E1069E374DBDA58C1D8D0002B962D95EE52DA2ED9BD530CCD3F5D B36A4596D2B6AD38B87F0FB651BABEF9EACB8ABFFEE52F93C9EFE3B1A347678E 1E3512DBB76EC1FAB56B3077F6ACCA7F7EFCD1AC3EDDBFCFFAECEFF925D7098F F17BE97FC2FEBFCD8AFBFF2AECF5CB7B01F73D7FB4FFAFC7BF61FFDF577BF67F 3D4A798CF300EFB39B4963806394B70EECDFDBEF9CF7E4E5352D8FF69F95F1F9 3B6F65A5C5282ACA177BFD96960C725E9827E629FAEEFFABA3AD497997C7E71E A8282F83AE8EA6C8CBFDCEBDDCC533FD9EFD6B15F6FF6D6CA817FBFBF25EBFBC 7F6F23AFA1EB735E5B235B87D3977FC6409FF2BB3A0228EF363536C090C6425C CEFB9EDFF7F713EF530ABE6AEFFD7FF97B5F627F5FFE462E7FEF6B80F3B6365E 63D9DCCD7FA9877FE19C89D87B38323C8CBF1A870BC646039F8785A2BD7BFCAD C8FF4DFBFF32BFDBFE572F5F8101D980DF43E0E3CAA58B039EF31E408FF60FFE 6FD8FFB7679FDFC79DFFFBF6FF556CFF079B1F74BD79AEDDFDA631DC6E9C85AB D959720DA97F750E5E56A6354369FF993BE01CB6E5050CA5FD7733374267475B 2FAECBBEE1F0B6BE84A1B4FFEE37CF51BB5309FB1DFF25BEADE7B07B188A5302 E06373094369FF3D6E99A0A230132D0D3570DAF3015A1A6B51599C032FD27F28 EDBFA7E57914A645233F350A056931C2E573E60FA5FD37D15117B6F2B038DF03 3EBF7D49EFDE50DAFF1933E7E0E2C5CB9831756ADF6F620DFF3DED3FE78DFF6B FF7F5FFBAF50CCFE5F69FFFFEFFB7FFFFFF9FEDF68B3F27EDFFFF3D69C6C23FF FE5FE3036DD937FE06F8F69F8E7B202E53B3AFE316D0EFFB7F85015AE8CCB319 F47B7F8CDD618DE05D44D8EDFBFD3F8A071EC727F6FBCEDF66933B1879BD1CDF 12BC6BBB70A74A2A5C3EE7EB5B2F383CF61B7FDF9F8B8F74ADE8444013A055D0 8135A9EDC28D6CA5AABEB403ECFF846CF5E1B7460FDD1786340E3A7F3084ACF9 FEDEC8A641E70F9E744CB7A934554E6C1960FEA0DC7448FCDB953C7F50D767FE A08EE70F9EA67C7D6DB40192ABEB20E17C737195CCB53E32781CBABF42407E9C FE05A78A72A09E9B02F59C2468E4A7C9E218E8D09A840325E90212AD9F1E8539 FE3D76E5C443E26E8A5DB909323D06E06E2C4981E4FE1548FCAF604349322427 A9AC68FC80F545BC97FC65487C2E637521C573A9CFF32BE2CE2F4B8424E41A24 A1D7210926045DC3DCE2580149D055D935F5EF30AD98E2BAB20E8ADC89157190 4410F78119585781480A1F76558608FA7DF45B19476334FDFED15BCEFDBA3A06 9298ABFC420C246ADF3E8A97C3C75C9741ED9BFEE93DFD2BFE5E1B85EF7C4FC2 45E3273C75FD777A0AC624DEC2EFA9FF5C4EFC88FFADDF3F1D6AFDF7B8EF9F0E A5FE7BDCF74F07ABFF86F2FDD3DFDB6E1A1B1BD79C397B96C6366764382373F5 0D0C0686BECCE5E7DA72AE7847C2D7199ED44FF61802C27C1C6463CE33323962 2C44D79B6ACAC53A50761F070ECB1FCBE6BD5CE57C1E230C952FC613D20E195F 5FC6A7F18CDB50F5E7B09D1D72BEBEF86EF7D34291CFFB2496EF9B27103EFEAF 03A2FCC00264A6A7F58039CCD563F95229EC46FE49A0E69CEA8060BFDCACCC1E C8EDA7A7A7277E976EFA49C079D49F0644E9969F519097D7835E7C3A6A6AEAA1 A97B06758DEDA8AA6B41654D232AAAEA515E5E85D29252EA5B17A3B4A8182545 4502CC67AE9C5F57570B2D6D1DB4B4778A772094959571E8D021B1FF6F5FF0DA 0AF1CD24053ECF5168135F5BEFACD8DB37393959BCC3207FDF4111DBB66DEBC7 6F6D69EE195BF2FB011C86C1FBEEF6C5952B577AF806DDF9EFB71CCCD5D2D2BA CFAEAEAE6E375827BEAF0632D06FBEF6C85F0639F7F78EFFFFAFFCFF5FF91F4A F91FE5B119555DCD62FEE4E5B894A72AFF9695FB710A1F601AEC3097FADE3FE7 03191D1852F9DF7F700782300C97B0082A08C609E2291500939201895ECA13CB FFB51409A2310AE9D889073087270D42D4E2BAF0AB3F609A2E7D62F98FDBF617 B45D9A832EF7A3287039895CDB3A9C716CC526832668DFAA7D62F9E7B549660B FE82BB877E04B6DBA06B5F1296AF05BE1F4558EA38A4F27F74ECAB305BF34760 9406302608F8DC0B1F7C98CFEBCB9E66FE6F55B2643E9225E7F127C99BBBE95C 3C3F3FA2A22C07F6EFDD8D9D4A94EECD9BC49CCCBAD5AB24EA6AAAFDFC36AC5D 838DEBD64A1872BEAACA21181AE8C3F08C3E366D5CC75CC13F7A4445A2A27C10 67F4746174D6005B376F1C902FF6A23978000F22C370E5F225AC273E3F2B3BAA AA22E1EB91E1A1B8687A413C43E3B08A7C95C3071DF6EEDA2974DB48713377E1 FC79B6475495259B36AC936CDFB6C576F70E25E1BF65E306F09C17E9E0C07C35 95C322FE7BBEDE88897A00CB5B37A1AE76443C2BE3746F5CBF162A870EE2AEAF 97F0B7B2B825BE15C87A501C9223879525CA07F6C3DBD31D1161A1B879C34CCC 33AD5CBA14CA07F661DD9A5510FE5E8FFC39FE1EBE8A8C7FD7C70BD10F227BE4 2F5BBC08C9490954C64E8BEF12DEF5F1445464042C6E9A0BFF352B5708FBA81E 3E84DD3B95B099E7F128CED52B9763F5F2E5983665CA9584F838E89ED6C6FA75 6BAEF09C16A557765FD7AC92DF1F1BD6313B2B0B151565C8A07A85BFBDE7EBE3 8D250B17C8E4EB9DC6C1FD7B294C66AF3077EFFA0A1B1D22BEAB93035D0B8393 BD3D8C0CCFE0205D5BB17489F06359228CB363EF3007F78B3428FA393B38E09C B121940F1DA0342C03A78DEDAF4C61070AC3E9ED15B7C323F9CC97E77D457E4F 9883FB847CF6E37D57D2529211171B23D6FC050504083E3FA7E5FCCF61E2060A 43E9671D4F507EB87AE9024E6B9EC4DEDD3BC4736ED68D203976F48864B0307C 0FF6EEDE799FD3B067E70EECDC4EE56BCB266CDEB01ECB972CBECF7C96FFB830 8F29FF7D8F01C3B8BA3AD73839D9C3C1E10EC1AE07F6DDAEA3A33D9C9C1CCA29 9CC4DDDD45E2E6ED2409D04994F8EBC64BEE1C8992B0FF930E7E0F98E2B77275 7592B8F6E1B35C3E7273B291C7C8CD112E9FF3616929EBEBF17E4F8E8E77AC5C BC1C24F77BF165DFC22C28C8A7BAB600854585C2E5733EACAD2D28DFCA9E7795 93EBEC617FF1BE7612FC7413C07CFB6E7E497121F5538BC5DC74594989E8AFCA DEEB8F848DB5256EDB58C99E13AA2B23CF39070F2E84C2E1680CECED657C7E46 5725BEB3598D869A1A3456D7A2ADB9B9971D8EABEC4759713E74F434E0A3EA81 8BDB227BF8CC498C8E434A5C22B21EA640B2E3EF68AF6F405B430DD0528DFFDA 138C3B69D530D23986007F2F28ABED12F95BCE6F6F6A8664F73094246741B2F7 23A0835AEAF616DC30D1C3C7078231311478DF1638E99402F5C37B05F7DAF658 89223F3D3611923DC39115974417F8794BB3E04E0E03FE45C1FE48DDDE4F379B 09AE8ACA6EC9E58D8FF86D2D2DFC10B0E71BA074057FDF1D8809C1C067B781B7 2E92BBEE3C42A89F78CFD743E243F0BAEBDAC3EFEAE84442542C52E312909B10 8FF1B6F5385D08A82700AF9F073E5C6928EB27BA3AC0C3DD55E2E1E12A71F778 C4178B7176BD8F92144AFFE17F62D9B11B386AE106EDD84EFC7DA9614F18CA43 707373A1BCEC2A20CF3F7CA4C52490ED3E44514A06A6ACD883D14B55314A3DA6 D73DE4F08A7C2E3B4F73707845BE85C5CDFB5C86B81C38129CE8B72873DD607D 1D14CA2287977319F2E70F4F81E18A95C2FF03529B5370 } end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/foptions.lrj�������������������������������������������������������������������0000644�0001750�0000144�00000001763�14743153644�015756� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":108725763,"name":"tfrmoptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, {"hash":80592254,"name":"tfrmoptions.lblemptyeditor.caption","sourcebytes":[80,108,101,97,115,101,32,115,101,108,101,99,116,32,111,110,101,32,111,102,32,116,104,101,32,115,117,98,112,97,103,101,115,44,32,116,104,105,115,32,112,97,103,101,32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,97,110,121,32,115,101,116,116,105,110,103,115,46],"value":"Please select one of the subpages, this page does not contain any settings."}, {"hash":2812976,"name":"tfrmoptions.btnhelp.caption","sourcebytes":[38,72,101,108,112],"value":"&Help"}, {"hash":11067,"name":"tfrmoptions.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmoptions.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":44595001,"name":"tfrmoptions.btnapply.caption","sourcebytes":[38,65,112,112,108,121],"value":"&Apply"} ]} �������������doublecmd-1.1.22/src/foptions.pas�������������������������������������������������������������������0000644�0001750�0000144�00000044030�14743153644�015744� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Implementing of Options dialog Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) contributors: Radek Cervinka <radek.cervinka@centrum.cz> 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, see <http://www.gnu.org/licenses/>. } unit fOptions; {$mode objfpc}{$H+} interface uses ActnList, SysUtils, Classes, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, Buttons, StdCtrls, LMessages, TreeFilterEdit, KASButtonPanel, fgl, uGlobs, fOptionsFrame, uDCUtils, EditBtn; type { TOptionsEditorView } TOptionsEditorView = class EditorClass: TOptionsEditorClass; Instance: TOptionsEditor; TreeNode: TTreeNode; LegacyOrderIndex: integer; end; TOptionsEditorViews = specialize TFPGObjectList<TOptionsEditorView>; { TfrmOptions } TfrmOptions = class(TForm, IOptionsDialog) btnHelp: TBitBtn; lblEmptyEditor: TLabel; OptionsEditorsImageList: TImageList; pnlButtons: TKASButtonPanel; Panel3: TPanel; pnlCaption: TPanel; btnOK: TBitBtn; btnApply: TBitBtn; btnCancel: TBitBtn; sboxOptionsEditor: TScrollBox; TreeFilterEdit: TTreeFilterEdit; tvTreeView: TTreeView; splOptionsSplitter: TSplitter; procedure btnCancelClick(Sender: TObject); procedure btnCancelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure btnHelpClick(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure btnApplyClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure splOptionsSplitterMoved(Sender: TObject); function TreeFilterEditFilterItem(ItemData: Pointer; out Done: Boolean): Boolean; procedure tvTreeViewChange(Sender: TObject; Node: TTreeNode); private FOptionsEditorList: TOptionsEditorViews; FOldEditor: TOptionsEditorView; function CreateEditor(EditorClass: TOptionsEditorClass): TOptionsEditor; procedure CreateOptionsEditorList; function GetEditor(EditorClass: TOptionsEditorClass): TOptionsEditor; procedure LoadSettings; procedure SelectEditor(EditorClassName: String); function CompareTwoNodeOfConfigurationOptionTree(Node1, Node2: TTreeNode): integer; function CycleThroughOptionEditors(bForceSaving:boolean):boolean; procedure MakeVisible(Data: PtrInt); protected procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public constructor Create(TheOwner: TComponent); override; constructor Create(TheOwner: TComponent; EditorClass: TOptionsEditorClass); overload; constructor Create(TheOwner: TComponent; EditorClassName: String); overload; procedure LoadConfig; procedure SaveConfig; end; function ShowOptions(EditorClass: TOptionsEditorClass = nil): IOptionsDialog; function ShowOptions(EditorClassName: String): IOptionsDialog; procedure SortConfigurationOptionsOnLeftTree; //If the var "frmOptions" would be in the interface section, we could have called directly "frmOptions.tvTreeView.CustomSort(@frmOptions.CompareTwoNodeOfConfigurationOptionTree);" //But it's not the case... Let's create this routine and respect the wish of original authors to have it there. Maybe there is a raison why so let's play safe. function GetOptionsForm: TfrmOptions; implementation {$R *.lfm} uses HelpIntfs, LCLProc, LCLVersion, LazUTF8, LResources, Menus, Translations, Graphics, DCStrUtils, uTranslator, uLng, uGlobsPaths, fMain; var LastOpenedEditor: TOptionsEditorClass = nil; OptionsSearchFile: TPOFile = nil; OptionsSearchCache: TList = nil; frmOptions: TfrmOptions = nil; procedure CreateSearchCache; var POFile: TPOFile; procedure FillCache(AList: TOptionsEditorClassList); var I, J: Integer; AClassName: String; PoFileItem: TPoFileItem; AEditor: TOptionsEditorRec; begin for I:= 0 to AList.Count - 1 do begin AEditor:= AList[I]; AClassName:= LowerCase(AEditor.EditorClass.ClassName); for J:= 0 to POFile.Count - 1 do begin PoFileItem:= POFile.PoItems[J]; if StrBegins(PoFileItem.IdentifierLow, AClassName) then begin OptionsSearchCache.Add(PoFileItem); end; end; if AEditor.HasChildren then FillCache(AEditor.Children); end; end; begin OptionsSearchCache:= TList.Create; try if Assigned(LRSTranslator) then POFile:= (LRSTranslator as TTranslator).POFile else begin POFile:= TPOFile.Create(gpLngDir + gPOFileName, True); OptionsSearchFile:= POFile; end; FillCache(OptionsEditorClassList); except // Skip end; end; { GetOptionsForm } // To get a point on the frmOptions. // Could have been simple to place "frmOptions" in the "interface" section but not sure why original author hide it under. Let's play safe. function GetOptionsForm: TfrmOptions; begin Result := frmOptions; end; function ShowOptions(EditorClass: TOptionsEditorClass): IOptionsDialog; begin Result := ShowOptions(EditorClass.ClassName); end; function ShowOptions(EditorClassName: String): IOptionsDialog; begin if (OptionsSearchCache = nil) then begin CreateSearchCache; end; if Assigned(frmOptions) then begin if frmOptions.WindowState = wsMinimized then frmOptions.WindowState:= wsNormal else frmOptions.BringToFront; frmOptions.SelectEditor(EditorClassName); end else begin if EditorClassName = '' then frmOptions := TfrmOptions.Create(Application) else frmOptions := TfrmOptions.Create(Application, EditorClassName); frmOptions.Show; end; Result := frmOptions; end; procedure SortConfigurationOptionsOnLeftTree; begin if frmOptions<>nil then frmOptions.tvTreeView.CustomSort(@frmOptions.CompareTwoNodeOfConfigurationOptionTree); end; { TfrmOptions } procedure TfrmOptions.FormCreate(Sender: TObject); begin // Initialize property storage InitPropStorage(Self); TreeFilterEdit.Visible:= (OptionsSearchCache.Count > 0); end; procedure TfrmOptions.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; frmOptions:= nil; end; procedure TfrmOptions.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin CanClose := (ModalResult in [mrOK, mrCancel]) or CycleThroughOptionEditors(False); end; procedure TfrmOptions.btnCancelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin // set ModalResult when mouse click, to pass FormCloseQuery ModalResult:= mrCancel; end; procedure TfrmOptions.btnCancelClick(Sender: TObject); begin // close window Close; end; procedure TfrmOptions.btnHelpClick(Sender: TObject); begin ShowHelpOrErrorForKeyword('', HelpKeyword); end; procedure TfrmOptions.btnOKClick(Sender: TObject); begin // save all configuration SaveConfig; // write to config file SaveGlobs; // close window Close; end; procedure TfrmOptions.btnApplyClick(Sender: TObject); begin // save all configuration SaveConfig; // write to config file SaveGlobs; end; procedure TfrmOptions.FormDestroy(Sender: TObject); begin FreeAndNil(FOptionsEditorList); end; procedure TfrmOptions.splOptionsSplitterMoved(Sender: TObject); var ARight, ADelta: Integer; begin ADelta:= ScaleX(8, DesignTimePPI) * 2 + btnHelp.Width; ARight:= splOptionsSplitter.Left; if (ARight > (btnOK.Left - ADelta)) then begin ARight:= btnOK.Left - ADelta; end; TreeFilterEdit.Width:= (ARight - TreeFilterEdit.Left); end; function TfrmOptions.TreeFilterEditFilterItem(ItemData: Pointer; out Done: Boolean): Boolean; var Index: Integer; AClassName: String; AFind, AText: String; POFileItem: TPOFileItem; aOptionsEditorView: TOptionsEditorView absolute ItemData; begin Done:= True; AFind:= TreeFilterEdit.Text; if Length(AFind) = 0 then Exit(True); AFind:= UTF8LowerCase(AFind); AClassName:= LowerCase(aOptionsEditorView.EditorClass.ClassName); for Index:= 0 to OptionsSearchCache.Count - 1 do begin POFileItem:= TPOFileItem(OptionsSearchCache[Index]); if Length(POFileItem.Translation) = 0 then AText:= POFileItem.Original else begin AText:= POFileItem.Translation; end; AText:= UTF8LowerCase(StripHotkey(AText)); if Pos(AFind, AText) > 0 then begin if StrBegins(POFileItem.IdentifierLow, AClassName) then begin // DebugLn(AClassName + ': ' + AText); Exit(True); end; end; end; Result:= False; end; function TfrmOptions.CompareTwoNodeOfConfigurationOptionTree(Node1, Node2: TTreeNode): integer; begin case gSortOrderOfConfigurationOptionsTree of scoClassicLegacy: begin if TOptionsEditorView(Node1.Data).LegacyOrderIndex < TOptionsEditorView(Node2.Data).LegacyOrderIndex then result:=-1 else result:=1; end; scoAlphabeticalButLanguage: begin if (TOptionsEditorView(Node1.Data).EditorClass.ClassName='TfrmOptionsLanguage') or (TOptionsEditorView(Node1.Data).EditorClass.ClassName='TfrmOptionsFilesViewsComplement') then result:=-1 else if (TOptionsEditorView(Node2.Data).EditorClass.ClassName='TfrmOptionsLanguage') or (TOptionsEditorView(Node1.Data).EditorClass.ClassName='TfrmOptionsFilesViewsComplement') then result:=1 else result:=CompareStrings(Node1.Text, Node2.Text, gSortNatural, gSortSpecial, gSortCaseSensitivity) end; end; end; procedure TfrmOptions.CreateOptionsEditorList; procedure AddEditors(EditorClassList: TOptionsEditorClassList; RootNode: TTreeNode); var I: LongInt; aOptionsEditorClass: TOptionsEditorClass; aOptionsEditorView: TOptionsEditorView; TreeNode: TTreeNode; IconIndex: Integer; begin for I:= 0 to EditorClassList.Count - 1 do begin aOptionsEditorClass := EditorClassList[I].EditorClass; aOptionsEditorView := TOptionsEditorView.Create; aOptionsEditorView.EditorClass := aOptionsEditorClass; aOptionsEditorView.Instance := nil; aOptionsEditorView.LegacyOrderIndex:=I; FOptionsEditorList.Add(aOptionsEditorView); TreeNode := tvTreeView.Items.AddChild(RootNode, {$IF lcl_fullversion >= 093100} aOptionsEditorClass.GetTitle {$ELSE} StringReplace(aOptionsEditorClass.GetTitle, '&', '&&', [rfReplaceAll]) {$ENDIF} ); if Assigned(TreeNode) then begin IconIndex := aOptionsEditorClass.GetIconIndex; TreeNode.ImageIndex := IconIndex; TreeNode.SelectedIndex := IconIndex; TreeNode.StateIndex := IconIndex; TreeNode.Data := aOptionsEditorView; end; aOptionsEditorView.TreeNode := TreeNode; if EditorClassList[I].HasChildren then AddEditors(EditorClassList[I].Children, TreeNode); end; //2014-08-12:Let's sort by alphabetical order this list. tvTreeView.CustomSort(@CompareTwoNodeOfConfigurationOptionTree); end; begin FOptionsEditorList:= TOptionsEditorViews.Create; AddEditors(OptionsEditorClassList, nil); case gCollapseConfigurationOptionsTree of ctsFullExpand: ; //By legacy, it was doing automaticall the tvTreeView.FullExpand; ctsFullCollapse: tvTreeView.FullCollapse; end; end; function TfrmOptions.GetEditor(EditorClass: TOptionsEditorClass): TOptionsEditor; var I: Integer; begin for I := 0 to FOptionsEditorList.Count - 1 do begin if FOptionsEditorList[I].EditorClass = EditorClass then begin if not Assigned(FOptionsEditorList[I].Instance) then FOptionsEditorList[I].Instance := CreateEditor(FOptionsEditorList[I].EditorClass); Result := FOptionsEditorList[I].Instance; Exit; end; end; Result := nil; end; procedure TfrmOptions.LoadSettings; begin LoadConfig; end; procedure TfrmOptions.SelectEditor(EditorClassName: String); var I: Integer; begin for I := 0 to FOptionsEditorList.Count - 1 do begin if (FOptionsEditorList[I].EditorClass.ClassName = EditorClassName) then if Assigned(FOptionsEditorList[I].TreeNode) then begin FOptionsEditorList[I].TreeNode.Selected := True; Application.QueueAsyncCall(@MakeVisible, PtrInt(FOptionsEditorList[I].TreeNode)); Break; end; end; end; constructor TfrmOptions.Create(TheOwner: TComponent); begin if not Assigned(LastOpenedEditor) and (OptionsEditorClassList.Count > 0) then LastOpenedEditor := OptionsEditorClassList[0].EditorClass; // Select first editor. Create(TheOwner, LastOpenedEditor); end; constructor TfrmOptions.Create(TheOwner: TComponent; EditorClass: TOptionsEditorClass); begin if Assigned(EditorClass) then Create(TheOwner, EditorClass.ClassName) else Create(TheOwner, ''); end; constructor TfrmOptions.Create(TheOwner: TComponent; EditorClassName: String); begin if (EditorClassName = '') and Assigned(LastOpenedEditor) then EditorClassName := LastOpenedEditor.ClassName; FOldEditor := nil; inherited Create(TheOwner); CreateOptionsEditorList; SelectEditor(EditorClassName); {$if lcl_fullversion >= 2030000} // Lazarus 2.3 workaround (fixes selection reset) TreeFilterEdit.IdleConnected := False; {$endif} end; procedure TfrmOptions.tvTreeViewChange(Sender: TObject; Node: TTreeNode); var SelectedEditorView: TOptionsEditorView; begin if (Node = nil) then Exit; SelectedEditorView := TOptionsEditorView(Node.Data); if Assigned(SelectedEditorView) and (FOldEditor <> SelectedEditorView) then begin if Assigned(FOldEditor) and Assigned(FOldEditor.Instance) then FOldEditor.Instance.Visible := False; if not Assigned(SelectedEditorView.Instance) then SelectedEditorView.Instance := CreateEditor(SelectedEditorView.EditorClass); if Assigned(SelectedEditorView.Instance) then SelectedEditorView.Instance.Visible := True; lblEmptyEditor.Visible := not Assigned(SelectedEditorView.Instance); FOldEditor := SelectedEditorView; LastOpenedEditor := SelectedEditorView.EditorClass; pnlCaption.Caption := SelectedEditorView.EditorClass.GetTitle; if Assigned(SelectedEditorView.Instance) then begin HelpKeyword:= SelectedEditorView.Instance.HelpKeyword; btnHelp.Visible := HelpKeyword <> ''; end else btnHelp.Visible:= False; end; end; function TfrmOptions.CreateEditor(EditorClass: TOptionsEditorClass): TOptionsEditor; begin if Assigned(EditorClass) and not EditorClass.IsEmpty then begin Result := EditorClass.Create(Self); Result.Align := alClient; Result.Visible := False; Result.Init(sboxOptionsEditor, Self, [oeifLoad]); end else Result := nil; end; procedure TfrmOptions.LoadConfig; var I: LongInt; begin { Load options to frames } for I:= 0 to FOptionsEditorList.Count - 1 do begin if Assigned(FOptionsEditorList[I].Instance) then FOptionsEditorList[I].Instance.LoadSettings; end; end; procedure TfrmOptions.SaveConfig; begin CycleThroughOptionEditors(True); end; { TfrmOptions.CycleThroughOptionEditors } // -Will cycle through all option editors to either: // >Prompt user to save change if any, discard change if any, etc. // >Force saving eventual modification without asking. // -In case we prompt user save changes or not, user may answer that he wants to // CANCEL exit. If so, that's the only case where the function will return FALSE. // -Could be call from a simple "APPLY" or "OK" from the main option window and // if so, will save any modification. // -Could be call from "CANCEL" or "Attempt to close with the 'x' of the window // and if so, will prompt user to save modifications, discard modification or // cancel exiting. function TfrmOptions.CycleThroughOptionEditors(bForceSaving: boolean): boolean; var I: integer; SaveFlags: TOptionsEditorSaveFlags = []; bNeedsRestart: boolean = False; begin Result := True; I := 0; while (I < FOptionsEditorList.Count) and (Result) do begin if Assigned(FOptionsEditorList[I].Instance) then begin try Result := FOptionsEditorList[I].Instance.CanWeClose(SaveFlags, bForceSaving); if oesfNeedsRestart in SaveFlags then bNeedsRestart := True; except on E: Exception do MessageDlg(FOptionsEditorList[I].Instance.GetTitle, E.Message, mtError, [mbOK], 0); end; end; Inc(I); end; if bNeedsRestart then MessageDlg(rsMsgRestartForApplyChanges, mtInformation, [mbOK], 0); frmMain.UpdateWindowView; // Let's refresh the views. // In fact, may settings would not really require it since they don't have an immediate visual impact. // But let's do it for two reasons: // 1st) Previously with "SaveConfig" it was updating it no matter what. // 2nd) The little delay and visual blink it gives to user is a good feedback to him confirming him he just saved settings. end; procedure TfrmOptions.MakeVisible(Data: PtrInt); var TreeNode: TTreeNode absolute Data; begin TreeNode.MakeVisible; TreeFilterEdit.StoreSelection; end; procedure TfrmOptions.CMThemeChanged(var Message: TLMessage); var Index: Integer; begin for Index:= 0 to FOptionsEditorList.Count - 1 do begin if Assigned(FOptionsEditorList[Index].Instance) then begin FOptionsEditorList[Index].Instance.Perform(CM_THEMECHANGED, 0, 0); end; end; end; finalization FreeAndNil(OptionsSearchCache); FreeAndNil(OptionsSearchFile); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/foptionshotkeysedithotkey.lfm��������������������������������������������������0000644�0001750�0000144�00000020624�14743153644�021443� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmEditHotkey: TfrmEditHotkey Left = 577 Height = 465 Top = 168 Width = 458 BorderIcons = [biSystemMenu] ClientHeight = 465 ClientWidth = 458 Constraints.MinHeight = 200 Constraints.MinWidth = 200 OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter ShowHint = True LCLVersion = '3.3.0.0' object lblShortcuts: TLabel AnchorSideLeft.Control = pnlShortcuts AnchorSideTop.Control = Owner AnchorSideBottom.Control = btnSelectFromList AnchorSideBottom.Side = asrBottom Left = 8 Height = 15 Top = 13 Width = 53 Anchors = [akLeft, akBottom] BorderSpacing.Top = 6 Caption = 'Shortcuts:' ParentColor = False end object pnlShortcuts: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = btnSelectFromList AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 0 Top = 28 Width = 442 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 8 BorderSpacing.Right = 8 BevelOuter = bvNone ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 TabOrder = 0 end object lblHotKeyConflict: TLabel AnchorSideLeft.Control = pnlShortcuts AnchorSideTop.Control = pnlShortcuts AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlShortcuts AnchorSideRight.Side = asrBottom Left = 8 Height = 1 Top = 32 Width = 442 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 BorderSpacing.Bottom = 4 Font.Style = [fsBold, fsUnderline] ParentColor = False ParentFont = False ParentShowHint = False ShowHint = True Visible = False WordWrap = True end object lblParameters: TLabel AnchorSideLeft.Control = pnlShortcuts AnchorSideTop.Control = lblHotKeyConflict AnchorSideTop.Side = asrBottom Left = 8 Height = 15 Top = 39 Width = 189 BorderSpacing.Top = 6 Caption = '&Parameters (each in a separate line):' FocusControl = edtParameters ParentColor = False end object edtParameters: TMemo AnchorSideLeft.Control = pnlShortcuts AnchorSideTop.Control = lblParameters AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlShortcuts AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnShowCommandHelp Left = 8 Height = 328 Top = 54 Width = 442 HelpType = htKeyword Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Bottom = 2 ScrollBars = ssAutoBoth TabOrder = 1 WordWrap = False end object btnShowCommandHelp: TButton AnchorSideLeft.Control = pnlShortcuts AnchorSideRight.Control = pnlShortcuts AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cgHKControls Left = 8 Height = 10 Top = 386 Width = 442 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Top = 4 TabOrder = 2 OnClick = btnShowCommandHelpClick end object cgHKControls: TCheckGroup AnchorSideLeft.Control = pnlShortcuts AnchorSideRight.Control = pnlShortcuts AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnOK Left = 8 Height = 19 Top = 396 Width = 442 Anchors = [akLeft, akRight, akBottom] AutoFill = True AutoSize = True Caption = 'Only for these controls' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 OnItemClick = cgHKControlsItemClick TabOrder = 3 Visible = False end object btnOK: TBitBtn AnchorSideLeft.Control = pnlShortcuts AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 8 Height = 40 Top = 419 Width = 120 Anchors = [akLeft, akBottom] AutoSize = True BorderSpacing.Top = 4 BorderSpacing.Bottom = 6 Caption = '&OK' Constraints.MinHeight = 40 Constraints.MinWidth = 120 Default = True Kind = bkOK ModalResult = 1 TabOrder = 4 end object btnCancel: TBitBtn AnchorSideRight.Control = pnlShortcuts AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 330 Height = 40 Top = 419 Width = 120 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.Bottom = 6 Cancel = True Caption = '&Cancel' Constraints.MinHeight = 40 Constraints.MinWidth = 120 Kind = bkCancel ModalResult = 2 TabOrder = 5 end object btnAddShortcut: TSpeedButton AnchorSideTop.Control = btnRemoveShortcut AnchorSideRight.Control = btnRemoveShortcut Left = 406 Height = 22 Hint = 'Add new shortcut to sequence' Top = 6 Width = 22 Anchors = [akTop, akRight] OnClick = btnAddShortcutClick ShowHint = True ParentShowHint = False end object btnRemoveShortcut: TSpeedButton AnchorSideTop.Control = Owner AnchorSideRight.Control = pnlShortcuts AnchorSideRight.Side = asrBottom Left = 428 Height = 22 Hint = 'Remove last shortcut from sequence' Top = 6 Width = 22 Anchors = [akTop, akRight] BorderSpacing.Top = 6 OnClick = btnRemoveShortcutClick ShowHint = True ParentShowHint = False end object btnSelectFromList: TSpeedButton AnchorSideTop.Control = btnRemoveShortcut AnchorSideRight.Control = btnAddShortcut Left = 382 Height = 22 Hint = 'Select shortcut from list of remaining free available keys' Top = 6 Width = 24 Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000140000 0033000000330000003300000033000000330000003300000033000000330000 00330000003300000033000000330000003300000014FFFFFF0073706F849390 8EFF93908EFF93908EFF93908EFF93908EFF93908EFF93908EFF93908EFF9390 8EFF93908EFF93908EFF93908EFF93908EFF73706F84FFFFFF00959290FFF1F2 F1FFD3D3D2FFD4D3D2FFD4D3D2FFD4D3D2FFD4D3D2FFD4D3D2FFD4D3D2FFD4D3 D2FFD4D3D2FFD4D3D2FFD3D3D2FFF1F1F0FF9A9796FFFFFFFF00969391FFF0F0 EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEFEEFFADAAA9FFFFFFFF00999694FFEFEF EFFFFFFFFFFFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFDFD FDFFFDFDFDFFFDFDFDFFFFFFFFFFE9E9E9FFAEABAAFFFFFFFF009C9996FFEAEA EAFFFFFFFFFFFAFAFAFFFAFAFAFFFAFAFAFFFAFAFAFFFAFAFAFFFAFAFAFFFAFA FAFFFAFAFAFFFAFAFAFFFFFFFFFFE4E4E4FFB0AEADFFFFFFFF009E9B99FFE5E6 E6FFFFFFFFFFFBFBFBFFF8F8F9FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7 F7FFF7F7F7FFF6F6F6FFFFFFFFFFE0E0DFFFB1B0AEFFFFFFFF00A09D9BFFE1E1 E1FFFFFFFFFF696969FFFAFAF9FFF4F4F3FFF4F4F3FFF4F4F3FF696969FF6969 69FF696969FFF3F3F2FFFFFFFFFFDBDBDBFFB4B2B0FFFFFFFF00A3A09EFFDCDC DCFFFFFFFFFF6F6F6FFFFEFEFCFFF6F6F5FFF2F2F1FFF1F1F0FFF1F1F0FF6F6F 6FFFF1F1F0FFF0F0EFFFFFFFFFFFD6D7D7FFB6B4B2FFFFFFFF00A5A3A1FFD9D8 D8FFFFFFFFFF727272FF727272FF6B6B6BFFF2F2F1FFEEEEEDFFEEEEEDFF7272 72FFEEEEEDFFEDEDECFFFFFFFFFFD3D2D2FFB7B6B4FFFFFFFF00A8A5A3FFD4D3 D2FFFFFFFFFF707070FFF7F7F6FFF0F1EFFFECECEBFFEBEBEAFFEBEBEAFF7070 70FFEBEBEAFFEAEAE9FFFFFFFFFFCECDCCFFBAB8B7FFFFFFFF00ABA8A6FFCFCE CDFFFFFFFFFF707070FFF4F3F3FFEEEDEDFFEDECECFFE9E8E8FFE8E7E7FF7070 70FFE8E7E7FFE7E5E5FFFFFFFFFFCAC9C8FFBCBAB8FFFFFFFF00ADABA9FFC9CA C9FFFFFFFFFF6D6D6DFF707070FF6F6F6FFF6A6A6AFFE7E6E5FF696969FF6D6D 6DFFE3E2E1FFE2E1E0FFFFFFFFFFC5C5C4FFBDBCBAFFFFFFFF00AFADABFFC2C1 C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFC0BFBEFFC0BEBDFFFFFFFF00B1AFADFFE4E4 E3FFF1F1F1FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFEFF0F0FFF1F1F1FFE3E4E3FFB5B3B1FFFFFFFF00B5B3B165B3B1 AFFFB2AFADFFB1AFADFFB1AFADFFB1AFADFFB1AFADFFB1AFADFFB1AFADFFB1AF ADFFB1AFADFFB1AFADFFB2AFADFFB3B1AEFFB4B2B065FFFFFF00 } OnClick = btnSelectFromListClick end object pmWithAllShortcuts: TPopupMenu Left = 310 Top = 13 end end ������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/foptionshotkeysedithotkey.lrj��������������������������������������������������0000644�0001750�0000144�00000003247�14743153644�021456� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":162485258,"name":"tfrmedithotkey.lblshortcuts.caption","sourcebytes":[83,104,111,114,116,99,117,116,115,58],"value":"Shortcuts:"}, {"hash":150847754,"name":"tfrmedithotkey.lblparameters.caption","sourcebytes":[38,80,97,114,97,109,101,116,101,114,115,32,40,101,97,99,104,32,105,110,32,97,32,115,101,112,97,114,97,116,101,32,108,105,110,101,41,58],"value":"&Parameters (each in a separate line):"}, {"hash":238221475,"name":"tfrmedithotkey.cghkcontrols.caption","sourcebytes":[79,110,108,121,32,102,111,114,32,116,104,101,115,101,32,99,111,110,116,114,111,108,115],"value":"Only for these controls"}, {"hash":11067,"name":"tfrmedithotkey.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmedithotkey.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":14152757,"name":"tfrmedithotkey.btnaddshortcut.hint","sourcebytes":[65,100,100,32,110,101,119,32,115,104,111,114,116,99,117,116,32,116,111,32,115,101,113,117,101,110,99,101],"value":"Add new shortcut to sequence"}, {"hash":68285637,"name":"tfrmedithotkey.btnremoveshortcut.hint","sourcebytes":[82,101,109,111,118,101,32,108,97,115,116,32,115,104,111,114,116,99,117,116,32,102,114,111,109,32,115,101,113,117,101,110,99,101],"value":"Remove last shortcut from sequence"}, {"hash":224712627,"name":"tfrmedithotkey.btnselectfromlist.hint","sourcebytes":[83,101,108,101,99,116,32,115,104,111,114,116,99,117,116,32,102,114,111,109,32,108,105,115,116,32,111,102,32,114,101,109,97,105,110,105,110,103,32,102,114,101,101,32,97,118,97,105,108,97,98,108,101,32,107,101,121,115],"value":"Select shortcut from list of remaining free available keys"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/foptionshotkeysedithotkey.pas��������������������������������������������������0000644�0001750�0000144�00000057232�14743153644�021455� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Editor for hotkeys Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) Copyright (C) 2016 Alexander Koblov (alexx2000@mail.ru) 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 } unit fOptionsHotkeysEditHotkey; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons, Menus, uHotkeyManager, DCBasicTypes; type TEditHotkeyOption = (ehoHideParams); TEditHotkeyOptions = set of TEditHotkeyOption; { TfrmEditHotkey } TfrmEditHotkey = class(TForm) btnOK: TBitBtn; btnCancel: TBitBtn; btnShowCommandHelp: TButton; cgHKControls: TCheckGroup; lblShortcuts: TLabel; lblHotKeyConflict: TLabel; lblParameters: TLabel; edtParameters: TMemo; pnlShortcuts: TPanel; btnAddShortcut: TSpeedButton; btnRemoveShortcut: TSpeedButton; pmWithAllShortcuts: TPopupMenu; btnSelectFromList: TSpeedButton; procedure btnAddShortcutClick(Sender: TObject); procedure btnRemoveShortcutClick(Sender: TObject); procedure btnShowCommandHelpClick(Sender: TObject); procedure cgHKControlsItemClick(Sender: TObject; {%H-}Index: integer); procedure edtShortcutKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState); procedure edtShortcutKeyPress(Sender: TObject; var Key: char); procedure edtShortcutKeyUp(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure ChangeEnterBehaviorClick(Sender: TObject); procedure ShortcutHelperClick(Sender: TObject); procedure PopulateHelperMenu; procedure btnSelectFromListClick(Sender: TObject); private FCommand: String; FEditMode: Boolean; FForm: String; FForms, FFormsTranslated: TStringList; FOldHotkey: THotkey; FOptions: TEditHotkeyOptions; function ApplyHotkey: Boolean; procedure AddShortcutEditor; {en Check if combination of pressed hotkey and checked controls are already in use. Conflicting hotkeys are deleted if DeleteConflicts parameter is true. } procedure CheckHotKeyConflicts(DeleteConflicts: Boolean = false); procedure CheckHotKeyConflicts(Key: Word; Shift: TShiftState); procedure FillHKControlList; function GetShortcutsEditorsCount: Integer; function GetParameters: TDynamicStringArray; function GetShortcuts: TDynamicStringArray; function GetTranslatedControlName(const AName: String): String; function GetTranslatedFormName(const AName: String): String; procedure RemoveLastShortcutEditor; procedure SetBitmapOrCaption(Button: TSpeedButton; const AIconName, ACaption: String); procedure SetCommand(NewCommand: String); procedure SetControls(const NewControls: TDynamicStringArray); procedure SetHotkey(Hotkey: THotkey); procedure SetParameters(const NewParameters: TDynamicStringArray); procedure SetShortcuts(const NewShortcuts: TDynamicStringArray); public destructor Destroy; override; function Execute(EditMode: Boolean; Form: String; Command: String; Hotkey: THotkey; AControls: TDynamicStringArray; Options: TEditHotkeyOptions = []): Boolean; function CloneNewHotkey: THotkey; end; implementation {$R *.lfm} uses LCLType, dmHelpManager, uKeyboard, uLng, uGlobs, uFormCommands, DCStrUtils, uPixMapManager; const MaxShortcutSequenceLength = 5; { TfrmEditHotkey } procedure TfrmEditHotkey.AddShortcutEditor; var EditControl: TEdit; begin if GetShortcutsEditorsCount < MaxShortcutSequenceLength then begin EditControl := TEdit.Create(Self); EditControl.Font.Color:=clRed; EditControl.Parent := pnlShortcuts; EditControl.OnKeyDown := @edtShortcutKeyDown; EditControl.OnKeyPress := @edtShortcutKeyPress; EditControl.OnKeyUp := @edtShortcutKeyUp; end; end; function TfrmEditHotkey.ApplyHotkey: Boolean; procedure UpdateHotkey(ShouldBePresent: Boolean; HotkeyOld, HotkeyNew: THotkey; Hotkeys: THotkeys); var hotkey: THotkey; begin if FEditMode then begin hotkey := Hotkeys.Find(HotkeyOld.Shortcuts); if Assigned(hotkey) and (hotkey.Command = FCommand) then begin if ShouldBePresent then begin hotkey.Assign(HotkeyNew); Hotkeys.UpdateHotkey(hotkey); end else if hotkey.SameParams(HotkeyOld.Params) then Hotkeys.Remove(hotkey); end else if ShouldBePresent then Hotkeys.Add(HotkeyNew.Shortcuts, HotkeyNew.Params, HotkeyNew.Command); end else if ShouldBePresent then begin // Overwrite old hotkey in Add mode too. hotkey := Hotkeys.Find(HotkeyNew.Shortcuts); if Assigned(hotkey) and (hotkey.Command = FCommand) then begin hotkey.Assign(HotkeyNew); Hotkeys.UpdateHotkey(hotkey); end else Hotkeys.Add(HotkeyNew.Shortcuts, HotkeyNew.Params, HotkeyNew.Command); end; end; var i: Integer; HMForm: THMForm; HMControl: THMControl; NewHotkey: THotkey; IsFormHotkey: Boolean; begin Result := False; NewHotkey := CloneNewHotkey; try // check for invalid hotkey if Length(NewHotkey.Shortcuts) = 0 then Exit; if (lblHotKeyConflict.Tag > 0) then begin if (MessageDlg(rsOptHotkeysShortCutUsed, Format(rsOptHotkeysShortCutUsedText1, [ShortcutsToText(NewHotkey.Shortcuts)]), mtWarning, [mbIgnore, mbCancel], 0) = mrCancel) then Exit; end else if (lblHotKeyConflict.Caption <> EmptyStr) then begin if (MessageDlg(rsOptHotkeysShortCutUsed, // delete command on assigned shortcut Format(rsOptHotkeysShortCutUsedText1, // if another was applied [ShortcutsToText(NewHotkey.Shortcuts)]) + LineEnding + Format(rsOptHotkeysShortCutUsedText2, [NewHotkey.Command]), mtConfirmation, mbYesNo, 0) = mrYes) then CheckHotKeyConflicts(True) else Exit; end; HMForm := HotMan.Forms.FindOrCreate(FForm); IsFormHotkey := True; for i := 0 to cgHKControls.Items.Count - 1 do begin HMControl := THMControl(cgHKControls.Items.Objects[i]); if Assigned(HMControl) then begin if cgHKControls.Checked[i] then IsFormHotkey := False; UpdateHotkey(cgHKControls.Checked[i], FOldHotkey, NewHotkey, HMControl.Hotkeys); end; end; UpdateHotkey(IsFormHotkey, FOldHotkey, NewHotkey, HMForm.Hotkeys); Result := True; finally NewHotkey.Free; end; end; procedure TfrmEditHotkey.btnAddShortcutClick(Sender: TObject); begin AddShortcutEditor; if TEdit(pnlShortcuts.Controls[pred(pnlShortcuts.ControlCount)]).CanFocus then TEdit(pnlShortcuts.Controls[pred(pnlShortcuts.ControlCount)]).SetFocus; end; procedure TfrmEditHotkey.btnRemoveShortcutClick(Sender: TObject); begin RemoveLastShortcutEditor; end; procedure TfrmEditHotkey.btnShowCommandHelpClick(Sender: TObject); begin ShowHelpForKeywordWithAnchor(edtParameters.HelpKeyword); end; procedure TfrmEditHotkey.cgHKControlsItemClick(Sender: TObject; Index: integer); begin CheckHotKeyConflicts; end; procedure TfrmEditHotkey.CheckHotKeyConflicts(DeleteConflicts: Boolean); var ConflictsCount: Integer; ShortConflicts, LongConflicts: String; procedure AddCommandConflict(Hotkey: THotkey; const AName: String); var sConflict: String; begin sConflict := Format(rsOptHotkeysUsedBy, [Hotkey.Command, AName]); AddStrWithSep(ShortConflicts, sConflict, LineEnding); AddStrWithSep(LongConflicts, sConflict, LineEnding); end; procedure AddParamsConflict(Hotkey: THotkey); var sConflict: String; Param: String; begin sConflict := rsOptHotkeysUsedWithDifferentParams; AddStrWithSep(ShortConflicts, sConflict, LineEnding); if Length(Hotkey.Params) > 0 then begin sConflict := sConflict + ':'; for Param in Hotkey.Params do AddStrWithSep(sConflict, ' ' + Param, LineEnding); end; AddStrWithSep(LongConflicts, sConflict, LineEnding); end; procedure CheckHotkey(Hotkeys: THotkeys; const AObjectName: String; HotkeyToSearch: THotkey); var Hotkey: THotkey; begin Hotkey := Hotkeys.Find(HotkeyToSearch.Shortcuts); if Assigned(Hotkey) then begin if Hotkey.Command <> FCommand then begin Inc(ConflictsCount); if DeleteConflicts then Hotkeys.Remove(Hotkey) else AddCommandConflict(Hotkey, GetTranslatedControlName(AObjectName)); end else if not Hotkey.SameParams(HotkeyToSearch.Params) then begin Inc(ConflictsCount); if DeleteConflicts then Hotkeys.Remove(Hotkey) else AddParamsConflict(Hotkey); end; end; end; var HMForm: THMForm; HMControl: THMControl; i: Integer; IsFormHotKey: Boolean; Hotkey: THotkey; begin lblHotKeyConflict.Caption := EmptyStr; lblHotKeyConflict.Hint := EmptyStr; HMForm := HotMan.Forms.Find(FForm); if not Assigned(HMForm) then Exit; Hotkey := CloneNewHotkey; try ConflictsCount := 0; if Length(Hotkey.Shortcuts) > 0 then begin IsFormHotKey := True; // search if any checked control has same hotkey assigned somewhere else for i := 0 to cgHKControls.Items.Count - 1 do begin if cgHKControls.Checked[i] then begin IsFormHotKey := False; HMControl := THMControl(cgHKControls.Items.Objects[i]); if Assigned(HMControl) then CheckHotkey(HMControl.Hotkeys, HMControl.Name, Hotkey); end; end; if IsFormHotKey then CheckHotkey(HMForm.Hotkeys, HMForm.Name, Hotkey); lblHotKeyConflict.Caption := ShortConflicts; lblHotKeyConflict.Hint := LongConflicts; end; lblHotKeyConflict.Visible := ConflictsCount > 0; finally Hotkey.Free; end; end; procedure TfrmEditHotkey.CheckHotKeyConflicts(Key: Word; Shift: TShiftState); var Index: Integer; sConflict: String; UTF8Char: TUTF8Char; OptLetters: TStringArray; SearchOrFilterModifiers: TShiftState; KeyTypingModifier: TKeyTypingModifier; begin lblHotKeyConflict.Tag:= 0; if (Key = VK_SPACE) then Exit; for KeyTypingModifier in TKeyTypingModifier do begin if gKeyTyping[KeyTypingModifier] <> ktaNone then begin SearchOrFilterModifiers := TKeyTypingModifierToShift[KeyTypingModifier]; if (Shift * KeyModifiersShortcutNoText = SearchOrFilterModifiers) then begin UTF8Char := VirtualKeyToUTF8Char(Key, Shift - SearchOrFilterModifiers); if (UTF8Char <> '') and (not ((Length(UTF8Char) = 1) and (UTF8Char[1] < #32))) then begin Index:= Ord(gKeyTyping[KeyTypingModifier]); OptLetters:= rsOptLetters.Split([';']); sConflict := Format(rsOptHotkeysUsedBy, [OptLetters[Index], rsOptionsEditorKeyboard]); lblHotKeyConflict.Caption:= sConflict; lblHotKeyConflict.Hint:= sConflict; lblHotKeyConflict.Visible:= True; lblHotKeyConflict.Tag:= 1; Break; end; end; end; end; end; function TfrmEditHotkey.CloneNewHotkey: THotkey; begin Result := THotkey.Create; Result.Shortcuts := GetShortcuts; Result.Params := GetParameters; Result.Command := FCommand; end; destructor TfrmEditHotkey.Destroy; begin inherited Destroy; FForms.Free; FFormsTranslated.Free; FOldHotkey.Free; end; procedure TfrmEditHotkey.edtShortcutKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var sShortCut: String; EditControl: TEdit; ShortCut: TShortCut; begin if (Key<>VK_RETURN) or (not gUseEnterToCloseHotKeyEditor) then begin ShortCut := KeyToShortCutEx(Key, GetKeyShiftStateEx); sShortCut := ShortCutToTextEx(ShortCut); EditControl := Sender as TEdit; // Allow closing the dialog if Escape pressed twice. if (ShortCut <> VK_ESCAPE) or (EditControl.Text <> sShortCut) then begin EditControl.Text := sShortCut; btnOK.Enabled := GetShortcuts <> nil; lblHotKeyConflict.Caption := ''; CheckHotKeyConflicts; if lblHotKeyConflict.Caption = EmptyStr then begin CheckHotKeyConflicts(Key, Shift); end; Key := 0; end; end; end; procedure TfrmEditHotkey.edtShortcutKeyPress(Sender: TObject; var Key: char); var EditControl: TEdit; begin if (Key <> Char(VK_RETURN)) or (not gUseEnterToCloseHotKeyEditor) then begin EditControl := Sender as TEdit; EditControl.Text := ''; btnOK.Enabled := GetShortcuts <> nil; Key := #0; end; end; procedure TfrmEditHotkey.edtShortcutKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); var ShortCut: TShortCut; sShortCut: String; EditControl: TEdit; begin if (Key <> VK_RETURN) or (not gUseEnterToCloseHotKeyEditor) then begin ShortCut := KeyToShortCutEx(Key, GetKeyShiftStateEx); sShortCut := ShortCutToTextEx(ShortCut); EditControl := Sender as TEdit; // Select next shortcut editor. if (ShortCut <> VK_ESCAPE) and (sShortCut <> '') and (EditControl.Text = sShortCut) then pnlShortcuts.SelectNext(EditControl, True, True); end; end; function TfrmEditHotkey.Execute( EditMode: Boolean; Form: String; Command: String; Hotkey: THotkey; AControls: TDynamicStringArray; Options: TEditHotkeyOptions = []): Boolean; begin FEditMode := EditMode; FForm := Form; FOptions := Options; SetHotkey(Hotkey); SetCommand(Command); SetControls(AControls); PopulateHelperMenu; if EditMode then Caption := Format(rsOptHotkeysEditHotkey, [Command]) else Caption := Format(rsOptHotkeysAddHotkey, [Command]); lblParameters.Visible := not (ehoHideParams in Options); edtParameters.Visible := not (ehoHideParams in Options); btnShowCommandHelp.Visible := not (ehoHideParams in Options); btnOK.Enabled := GetShortcuts <> nil; lblHotKeyConflict.Caption := ''; lblHotKeyConflict.Hint := ''; lblHotKeyConflict.Visible := False; if ShowModal = mrOK then Result := ApplyHotkey else Result := False; end; procedure TfrmEditHotkey.FillHKControlList; var HMForm: THMForm; i: Integer; ControlsList: TStringList; begin ControlsList := TStringList.Create; try HMForm := HotMan.Forms.Find(FForm); if Assigned(HMForm) then begin for i := 0 to HMForm.Controls.Count - 1 do ControlsList.AddObject(HMForm.Controls[i].Name, HMForm.Controls[i]); end; ControlsList.Sort; cgHKControls.Items.Assign(ControlsList); cgHKControls.Visible := cgHKControls.Items.Count <> 0; finally ControlsList.Free; end; end; procedure TfrmEditHotkey.FormCreate(Sender: TObject); begin FForms := TStringList.Create; FFormsTranslated := TStringList.Create; TFormCommands.GetCategoriesList(FForms, FFormsTranslated); SetBitmapOrCaption(btnAddShortcut, 'list-add', '+'); SetBitmapOrCaption(btnRemoveShortcut, 'list-remove', '-'); AddShortcutEditor; end; procedure TfrmEditHotkey.FormShow(Sender: TObject); var EditControl: TEdit; begin if pnlShortcuts.ControlCount > 0 then begin EditControl := pnlShortcuts.Controls[0] as TEdit; EditControl.SetFocus; EditControl.SelStart := Length(EditControl.Text); EditControl.SelLength := 0; end; end; function TfrmEditHotkey.GetParameters: TDynamicStringArray; begin Result := GetArrayFromStrings(edtParameters.Lines); end; function TfrmEditHotkey.GetShortcuts: TDynamicStringArray; var i: Integer; EditControl: TEdit; begin Result := nil; for i := 0 to pnlShortcuts.ControlCount - 1 do begin EditControl := pnlShortcuts.Controls[i] as TEdit; if EditControl.Text <> '' then AddString(Result, EditControl.Text); end; end; function TfrmEditHotkey.GetShortcutsEditorsCount: Integer; begin Result := pnlShortcuts.ControlCount; end; function TfrmEditHotkey.GetTranslatedControlName(const AName: String): String; begin // TODO: Translate controls names. Result := AName; end; function TfrmEditHotkey.GetTranslatedFormName(const AName: String): String; var i: Integer; begin i := FForms.IndexOf(AName); if i >= 0 then Result := FFormsTranslated.Strings[i] else Result := AName; end; procedure TfrmEditHotkey.RemoveLastShortcutEditor; begin if pnlShortcuts.ControlCount > 1 then pnlShortcuts.Controls[pnlShortcuts.ControlCount - 1].Free; end; procedure TfrmEditHotkey.SetBitmapOrCaption(Button: TSpeedButton; const AIconName, ACaption: String); var Bmp: TBitmap = nil; IconIndex: PtrInt; begin IconIndex := PixMapManager.GetIconByName(AIconName); if IconIndex <> -1 then Bmp := PixMapManager.GetBitmap(IconIndex); if Assigned(Bmp) then begin Button.Glyph := Bmp; Bmp.Free; end else begin Button.Caption := ACaption; end; end; procedure TfrmEditHotkey.SetCommand(NewCommand: String); begin FCommand := NewCommand; btnShowCommandHelp.Caption := Format(rsShowHelpFor, [FCommand]); edtParameters.HelpKeyword := '/cmds.html#' + FCommand; end; procedure TfrmEditHotkey.SetControls(const NewControls: TDynamicStringArray); var sControl: String; i: Integer; begin FillHKControlList; // Mark controls to which hotkey applies. for i := 0 to cgHKControls.Items.Count - 1 do begin cgHKControls.Checked[i] := False; for sControl in NewControls do if cgHKControls.Items[i] = sControl then begin cgHKControls.Checked[i] := True; Break; end; end; end; procedure TfrmEditHotkey.SetHotkey(Hotkey: THotkey); begin FreeAndNil(FOldHotkey); if Assigned(Hotkey) then begin FOldHotkey := Hotkey.Clone; SetShortcuts(Hotkey.Shortcuts); SetParameters(Hotkey.Params); end else begin SetShortcuts(nil); SetParameters(nil); end; end; procedure TfrmEditHotkey.SetParameters(const NewParameters: TDynamicStringArray); begin SetStringsFromArray(edtParameters.Lines, NewParameters); end; procedure TfrmEditHotkey.SetShortcuts(const NewShortcuts: TDynamicStringArray); var Index: Integer; EditControl: TEdit; Shortcut: String; begin if Assigned(NewShortcuts) then begin while pnlShortcuts.ControlCount < Length(NewShortcuts) do AddShortcutEditor; while pnlShortcuts.ControlCount > Length(NewShortcuts) do RemoveLastShortcutEditor; Index := 0; for Shortcut in NewShortcuts do begin EditControl := pnlShortcuts.Controls[Index] as TEdit; EditControl.Text := Shortcut; Inc(Index); end; end else begin while pnlShortcuts.ControlCount > 1 do RemoveLastShortcutEditor; if pnlShortcuts.ControlCount > 0 then begin EditControl := pnlShortcuts.Controls[0] as TEdit; EditControl.Clear; end; end; end; { TfrmEditHotkey.ShortcutHelperClick } procedure TfrmEditHotkey.ShortcutHelperClick(Sender: TObject); var EditControl:TEdit=nil; iSeeker:integer; begin for iSeeker:=0 to pred(pnlShortcuts.ControlCount) do if TEdit(pnlShortcuts.Controls[iSeeker]).Focused then EditControl:=TEdit(pnlShortcuts.Controls[iSeeker]); if (EditControl=nil) AND (pnlShortcuts.ControlCount>0) then EditControl:=TEdit(pnlShortcuts.Controls[pred(pnlShortcuts.ControlCount)]); if EditControl<>nil then begin EditControl.Text:=TMenuItem(Sender).Caption; btnOK.Enabled := GetShortcuts <> nil; lblHotKeyConflict.Caption := ''; CheckHotKeyConflicts; // Select next shortcut editor. pnlShortcuts.SelectNext(EditControl, True, True); end; end; { TfrmEditHotKey.PopulateHelperMenu } procedure TfrmEditHotkey.PopulateHelperMenu; const STD_PREFIX=6; CommandPrefix:array[0..pred(STD_PREFIX)] of string =('','Alt+','Ctrl+','Shift+','Ctrl+Shift+','Shift+Alt+'); var ASubMenu:TMenuItem; AMenuItem:TMenuItem; sMaybeSC:string; iPrefix,iFunction:integer; HMForm: THMForm; Hotkeys: THotkeys; i,j:integer; slAllShortcuts:TStringList; begin slAllShortcuts:=TStringList.Create; try slAllShortcuts.Sorted:=True; slAllShortcuts.Duplicates:=dupIgnore; //1. Clear any previous menu entries. pmWithAllShortcuts.Items.Clear; //2. Scan to get all the shortcuts in a TStringList HMForm := HotMan.Forms.Find(FForm); if not Assigned(HMForm) then Exit; Hotkeys := HMForm.Hotkeys; for i:=0 to pred(Hotkeys.Count) do for j:=0 to pred(length(Hotkeys.Items[i].Shortcuts)) do slAllShortcuts.Add(Hotkeys.Items[i].Shortcuts[j]); //3. Begin to populate menu with the "F" fonction keys for iPrefix:=0 to pred(STD_PREFIX) do begin ASubMenu:=TMenuItem.Create(pmWithAllshortcuts); ASubMenu.Caption := CommandPrefix[iPrefix]+'Fx...'; pmWithAllShortcuts.Items.Add(ASubMenu); for iFunction:=1 to 12 do begin sMaybeSC:=Format('%sF%d',[CommandPrefix[iPrefix],iFunction]); if slAllShortcuts.IndexOf(sMaybeSC)=-1 then begin AMenuItem:=TMenuItem.Create(pmWithAllShortcuts); AMenuItem.Caption:=sMaybeSC; AMenuItem.Enabled:=(slAllShortcuts.IndexOf(sMaybeSC)=-1); if AMenuItem.Enabled then AMenuItem.OnClick:=@ShortcutHelperClick; ASubMenu.Add(AMenuItem); end; end; end; //4. Then a little separator ASubMenu:=TMenuItem.Create(pmWithAllshortcuts); ASubMenu.Caption:='-'; pmWithAllShortcuts.Items.Add(ASubMenu); //5. Continue to populate with the "letter" fonction keys for iPrefix:=2 to pred(STD_PREFIX) do begin ASubMenu:=TMenuItem.Create(pmWithAllshortcuts); ASubMenu.Caption:=CommandPrefix[iPrefix]+rsSimpleWordLetter; pmWithAllShortcuts.Items.Add(ASubMenu); for iFunction:=0 to pred(26) do begin sMaybeSC:=Format('%s%s',[CommandPrefix[iPrefix],AnsiChar(ord('A')+iFunction)]); if slAllShortcuts.IndexOf(sMaybeSC)=-1 then begin AMenuItem:=TMenuItem.Create(pmWithAllShortcuts); AMenuItem.Caption:=sMaybeSC; AMenuItem.Enabled:=(slAllShortcuts.IndexOf(sMaybeSC)=-1); if AMenuItem.Enabled then AMenuItem.OnClick:=@ShortcutHelperClick; ASubMenu.Add(AMenuItem); end; end; end; //6. Little separator ASubMenu:=TMenuItem.Create(pmWithAllshortcuts); ASubMenu.Caption:='-'; pmWithAllShortcuts.Items.Add(ASubMenu); //7. Option for the "Enter" ASubMenu := TMenuItem.Create(pmWithAllshortcuts); ASubMenu.Caption := rsHotKeyNoSCEnter; ASubMenu.Checked := gUseEnterToCloseHotKeyEditor; ASubMenu.OnClick := @ChangeEnterBehaviorClick; pmWithAllShortcuts.Items.Add(ASubMenu); finally FreeAndNil(slAllShortcuts); end; end; procedure TfrmEditHotkey.btnSelectFromListClick(Sender: TObject); begin pmWithAllShortcuts.PopUp(Mouse.CursorPos.x, Mouse.CursorPos.y); end; { TfrmEditHotkey.ChangeEnterBehaviorClick } procedure TfrmEditHotkey.ChangeEnterBehaviorClick(Sender: TObject); begin TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked; gUseEnterToCloseHotKeyEditor := TMenuItem(Sender).Checked; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpackdlg.lfm�������������������������������������������������������������������0000644�0001750�0000144�00000015337�14743153644�015661� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmPackDlg: TfrmPackDlg Left = 338 Height = 272 Width = 540 HelpContext = 150 AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Pack files' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 272 ClientWidth = 540 Constraints.MinHeight = 236 Constraints.MinWidth = 482 OnShow = FormShow Position = poOwnerFormCenter inherited pnlContent: TPanel Height = 179 Width = 532 Align = alNone ClientHeight = 179 ClientWidth = 532 ParentColor = True object lblPrompt: TLabel[0] Left = 0 Height = 15 Top = 0 Width = 113 Caption = 'Pack file(s) to the file:' FocusControl = edtPackCmd ParentColor = False ShowAccelChar = False end object edtPackCmd: TDirectoryEdit[1] AnchorSideLeft.Control = lblPrompt AnchorSideTop.Control = lblPrompt AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlOptions AnchorSideRight.Side = asrBottom Left = 0 Height = 23 Top = 15 Width = 340 OnAcceptDirectory = edtPackCmdAcceptDirectory ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 0 end object rgPacker: TRadioGroup[2] AnchorSideLeft.Control = edtPackCmd AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblPrompt AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom Left = 372 Height = 100 Top = 0 Width = 148 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Left = 32 BorderSpacing.Right = 12 Caption = 'Packer' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.ShrinkHorizontal = crsHomogenousSpaceResize ChildSizing.ShrinkVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 3 Columns = 3 Constraints.MinHeight = 100 Constraints.MinWidth = 100 OnClick = arbChange TabOrder = 2 end object cbPackerList: TComboBox[3] AnchorSideLeft.Control = cbOtherPlugins AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rgPacker AnchorSideTop.Side = asrBottom AnchorSideRight.Control = rgPacker AnchorSideRight.Side = asrBottom Left = 414 Height = 23 Top = 106 Width = 100 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 6 Enabled = False ItemHeight = 15 OnChange = cbOtherPluginsChange ParentFont = False Style = csDropDownList TabOrder = 4 Visible = False end object btnConfig: TButton[4] AnchorSideLeft.Control = rgPacker AnchorSideTop.Control = cbPackerList AnchorSideTop.Side = asrBottom AnchorSideRight.Control = rgPacker AnchorSideRight.Side = asrBottom Left = 378 Height = 32 Top = 135 Width = 136 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 4 Caption = 'Con&figure' OnClick = btnConfigClick TabOrder = 5 end object cbOtherPlugins: TCheckBox[5] AnchorSideLeft.Control = rgPacker AnchorSideTop.Control = cbPackerList AnchorSideTop.Side = asrCenter Left = 378 Height = 19 Top = 108 Width = 36 BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = '=>' Enabled = False OnChange = cbOtherPluginsChange TabOrder = 3 Visible = False end object pnlOptions: TPanel[6] AnchorSideTop.Control = edtPackCmd AnchorSideTop.Side = asrBottom Left = 0 Height = 133 Top = 46 Width = 340 AutoSize = True BorderSpacing.Top = 8 BevelOuter = bvNone ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 133 ClientWidth = 340 Constraints.MinWidth = 340 TabOrder = 1 object cbStoreDir: TCheckBox Left = 0 Height = 19 Top = 0 Width = 277 Caption = 'Also &pack path names (only recursed)' Checked = True State = cbChecked TabOrder = 0 end object cbMultivolume: TCheckBox Left = 0 Height = 19 Top = 19 Width = 277 Caption = '&Multiple disk archive' TabOrder = 1 end object cbMoveToArchive: TCheckBox Left = 0 Height = 19 Top = 38 Width = 277 Caption = 'Mo&ve to archive' TabOrder = 2 end object cbCreateSFX: TCheckBox Left = 0 Height = 19 Top = 57 Width = 277 Caption = 'Create self e&xtracting archive' OnClick = cbCreateSFXClick TabOrder = 3 end object cbEncrypt: TCheckBox Left = 0 Height = 19 Top = 76 Width = 277 Caption = 'Encr&ypt' TabOrder = 4 end object cbPutInTarFirst: TCheckBox Left = 0 Height = 19 Top = 95 Width = 277 Caption = 'P&ut in the TAR archive first' OnChange = cbPutInTarFirstChange TabOrder = 5 end object cbCreateSeparateArchives: TCheckBox Left = 0 Height = 19 Top = 114 Width = 277 Caption = 'C&reate separate archives, one per selected file/dir' OnChange = cbCreateSeparateArchivesChange TabOrder = 6 end end end inherited pnlButtons: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = DividerBevel AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Top = 212 Width = 524 Align = alNone Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Top = 6 BorderSpacing.Right = 8 ClientWidth = 524 inherited btnCancel: TBitBtn Left = 342 end inherited btnOK: TBitBtn Left = 436 end end object DividerBevel: TDividerBevel[2] AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = pnlContent AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 8 Height = 15 Top = 191 Width = 524 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 Font.Style = [fsBold] ParentFont = False end inherited pmQueuePopup: TPopupMenu[3] left = 264 top = 216 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpackdlg.lrj�������������������������������������������������������������������0000644�0001750�0000144�00000004305�14743153644�015663� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":225027411,"name":"tfrmpackdlg.caption","sourcebytes":[80,97,99,107,32,102,105,108,101,115],"value":"Pack files"}, {"hash":157530954,"name":"tfrmpackdlg.lblprompt.caption","sourcebytes":[80,97,99,107,32,102,105,108,101,40,115,41,32,116,111,32,116,104,101,32,102,105,108,101,58],"value":"Pack file(s) to the file:"}, {"hash":90677698,"name":"tfrmpackdlg.rgpacker.caption","sourcebytes":[80,97,99,107,101,114],"value":"Packer"}, {"hash":214649477,"name":"tfrmpackdlg.btnconfig.caption","sourcebytes":[67,111,110,38,102,105,103,117,114,101],"value":"Con&figure"}, {"hash":1038,"name":"tfrmpackdlg.cbotherplugins.caption","sourcebytes":[61,62],"value":"=>"}, {"hash":148783881,"name":"tfrmpackdlg.cbstoredir.caption","sourcebytes":[65,108,115,111,32,38,112,97,99,107,32,112,97,116,104,32,110,97,109,101,115,32,40,111,110,108,121,32,114,101,99,117,114,115,101,100,41],"value":"Also &pack path names (only recursed)"}, {"hash":229354261,"name":"tfrmpackdlg.cbmultivolume.caption","sourcebytes":[38,77,117,108,116,105,112,108,101,32,100,105,115,107,32,97,114,99,104,105,118,101],"value":"&Multiple disk archive"}, {"hash":83566709,"name":"tfrmpackdlg.cbmovetoarchive.caption","sourcebytes":[77,111,38,118,101,32,116,111,32,97,114,99,104,105,118,101],"value":"Mo&ve to archive"}, {"hash":149668741,"name":"tfrmpackdlg.cbcreatesfx.caption","sourcebytes":[67,114,101,97,116,101,32,115,101,108,102,32,101,38,120,116,114,97,99,116,105,110,103,32,97,114,99,104,105,118,101],"value":"Create self e&xtracting archive"}, {"hash":77915316,"name":"tfrmpackdlg.cbencrypt.caption","sourcebytes":[69,110,99,114,38,121,112,116],"value":"Encr&ypt"}, {"hash":235944836,"name":"tfrmpackdlg.cbputintarfirst.caption","sourcebytes":[80,38,117,116,32,105,110,32,116,104,101,32,84,65,82,32,97,114,99,104,105,118,101,32,102,105,114,115,116],"value":"P&ut in the TAR archive first"}, {"hash":150077090,"name":"tfrmpackdlg.cbcreateseparatearchives.caption","sourcebytes":[67,38,114,101,97,116,101,32,115,101,112,97,114,97,116,101,32,97,114,99,104,105,118,101,115,44,32,111,110,101,32,112,101,114,32,115,101,108,101,99,116,101,100,32,102,105,108,101,47,100,105,114],"value":"C&reate separate archives, one per selected file/dir"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpackdlg.pas�������������������������������������������������������������������0000644�0001750�0000144�00000052657�14743153644�015674� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File packing window Copyright (C) 2007-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fPackDlg; {$mode objfpc}{$H+} interface uses SysUtils, Forms, Controls, Dialogs, StdCtrls, EditBtn, ExtCtrls, Buttons, Menus, DividerBevel, uWcxArchiveFileSource, uArchiveFileSource, uFile, uFileSource, Classes, fButtonForm, uFileSourceOperation; type { TfrmPackDlg } TfrmPackDlg = class(TfrmButtonForm) btnConfig: TButton; btnHelp: TButton; cbCreateSeparateArchives: TCheckBox; cbCreateSFX: TCheckBox; cbEncrypt: TCheckBox; cbMoveToArchive: TCheckBox; cbMultivolume: TCheckBox; cbPackerList: TComboBox; cbOtherPlugins: TCheckBox; cbPutInTarFirst: TCheckBox; DividerBevel: TDividerBevel; edtPackCmd: TDirectoryEdit; lblPrompt: TLabel; cbStoreDir: TCheckBox; rgPacker: TRadioGroup; pnlOptions: TPanel; procedure btnConfigClick(Sender: TObject); procedure cbCreateSeparateArchivesChange(Sender: TObject); procedure cbCreateSFXClick(Sender: TObject); procedure cbOtherPluginsChange(Sender: TObject); procedure cbPutInTarFirstChange(Sender: TObject); procedure edtPackCmdAcceptDirectory(Sender: TObject; var Value: String); procedure FormShow(Sender: TObject); procedure arbChange(Sender: TObject); private FArchiveExt, FArchiveName, FArchiveType: String; FArchiveTypeCount: Integer; FHasFolder, FNewArchive, FExistsArchive : Boolean; FSourceFileSource: IFileSource; FTargetFileSource: IArchiveFileSource; FCount: Integer; FPlugin: Boolean; FPassword: String; FVolumeSize: String; FCustomParams: String; FTargetPathInArchive: String; procedure SwitchOptions(ArcTypeChange: Boolean); procedure ChangeArchiveExt(const NewArcExt: String); procedure AddArchiveType(const FileExt, ArcType: String); procedure OnPackCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); procedure PackFiles(const SourceFileSource: IFileSource; var Files: TFiles); public { public declarations } end; // Frees 'Files'. procedure ShowPackDlg(TheOwner: TComponent; const SourceFileSource: IFileSource; const TargetFileSource: IArchiveFileSource; var Files: TFiles; TargetArchivePath: String; TargetPathInArchive: String; bNewArchive : Boolean = True); implementation {$R *.lfm} uses StrUtils, WcxPlugin, uGlobs, uDCUtils, uLng, uOSUtils, uOperationsManager, uArchiveFileSourceUtil, uMultiArchiveFileSource, uWcxArchiveCopyInOperation, uMultiArchiveCopyInOperation, uMasks, DCStrUtils, uMultiArc, uWcxModule, uTempFileSystemFileSource, uFileSourceCopyOperation, uShowForm, uShowMsg; procedure ShowPackDlg(TheOwner: TComponent; const SourceFileSource: IFileSource; const TargetFileSource: IArchiveFileSource; var Files: TFiles; TargetArchivePath: String; TargetPathInArchive: String; bNewArchive : Boolean = True); var I: Integer; PackDialog: TfrmPackDlg; begin PackDialog := TfrmPackDlg.Create(TheOwner); {$IF DEFINED(LCLGTK2)} // TRadioGroup.ItemIndex:= -1 will not work under Gtk2 // if items have been added dynamically, this workaround fixes it PackDialog.rgPacker.Items.Add(EmptyStr); PackDialog.rgPacker.Items.Clear; {$ENDIF} try with PackDialog do begin FCount:= Files.Count; FArchiveType:= 'none'; FNewArchive:= bNewArchive; FSourceFileSource:= SourceFileSource; FTargetFileSource:= TargetFileSource; FTargetPathInArchive:= TargetPathInArchive; FArchiveExt:= ExtensionSeparator + FArchiveType; if bNewArchive then // create new archive begin if Files.Count = 1 then // if one file selected begin FArchiveName:= Files[0].NameNoExt; FHasFolder:= Files[0].IsDirectory or Files[0].IsLinkToDirectory; edtPackCmd.Text := TargetArchivePath + FArchiveName + ExtensionSeparator + FArchiveType; end else // if some files selected begin FHasFolder:= False; for I:= 0 to Files.Count - 1 do begin if Files[I].IsDirectory or Files[I].IsLinkToDirectory then begin FHasFolder:= True; Break; end; end; FArchiveName:= MakeFileName(Files.Path, 'archive'); edtPackCmd.Text := TargetArchivePath + FArchiveName + ExtensionSeparator + FArchiveType; end end else // pack in exsists archive begin if Assigned(TargetFileSource) then edtPackCmd.Text := TargetFileSource.ArchiveFileName; end; if (ShowModal = mrOK) then begin case PrepareData(SourceFileSource, Files, @OnPackCopyOutStateChanged) of pdrInCallback: PackDialog:= nil; pdrSynchronous: PackFiles(SourceFileSource, Files); end; end; end; finally FreeAndNil(PackDialog); FreeAndNil(Files); end; end; const TAR_EXT = '.tar'; { TfrmPackDlg } procedure TfrmPackDlg.FormShow(Sender: TObject); var I, J : Integer; sExt : String; begin FArchiveTypeCount := 0; FExistsArchive := (FArchiveType <> 'none'); // WCX plugins for I:=0 to gWCXPlugins.Count - 1 do if gWCXPlugins.Enabled[I] then begin if (gWCXPlugins.Flags[I] and PK_CAPS_NEW) = PK_CAPS_NEW then begin AddArchiveType(FArchiveType, gWCXPlugins.Ext[I]); end; end; // MultiArc addons for I:= 0 to gMultiArcList.Count - 1 do if gMultiArcList[I].FEnabled and (gMultiArcList[I].FAdd <> EmptyStr) then begin J:= 1; repeat sExt:= ExtractDelimited(J, gMultiArcList[I].FExtension, [',']); if Length(sExt) = 0 then Break; AddArchiveType(FArchiveType, sExt); Inc(J); until False; end; if (rgPacker.Items.Count > 0) and (rgPacker.ItemIndex < 0) and (not cbOtherPlugins.Checked) then rgPacker.ItemIndex := 0; if cbPackerList.Items.Count > 0 then begin cbOtherPlugins.Visible := True; cbPackerList.Visible := True; if FExistsArchive then cbPackerList.Enabled:= False else cbOtherPlugins.Enabled := True; if cbPackerList.ItemIndex < 0 then cbPackerList.ItemIndex := 0; end else btnConfig.AnchorToCompanion(akTop, 6, rgPacker); end; procedure TfrmPackDlg.btnConfigClick(Sender: TObject); var WcxFileSource: IWcxArchiveFileSource; begin try WcxFileSource := TWcxArchiveFileSource.CreateByArchiveName(FSourceFileSource, edtPackCmd.Text, True); if Assigned(WcxFileSource) then // WCX plugin try WcxFileSource.WcxModule.VFSConfigure(Handle); finally WcxFileSource := nil; // free interface end else // MultiArc addon begin FCustomParams:= InputBox(Caption, rsMsgArchiverCustomParams, FCustomParams); end; except on e: Exception do MessageDlg(e.Message, mtError, [mbOK], 0); end; end; procedure TfrmPackDlg.cbCreateSeparateArchivesChange(Sender: TObject); begin if cbCreateSeparateArchives.Checked then edtPackCmd.Text:= ExtractFilePath(edtPackCmd.Text) + '*.*' + FArchiveExt else edtPackCmd.Text:= ExtractFilePath(edtPackCmd.Text) + FArchiveName + FArchiveExt; end; procedure TfrmPackDlg.cbCreateSFXClick(Sender: TObject); var State: Boolean; ANewExt: String; begin if cbCreateSFX.Tag = 0 then begin cbCreateSFX.Tag:= 1; // Save check box state State:= cbCreateSFX.Checked; if State then ANewExt:= GetSfxExt else begin ANewExt:= ExtensionSeparator + FArchiveType; end; ChangeArchiveExt(ANewExt); // Switch archiver options SwitchOptions(False); // Restore check box state cbCreateSFX.Checked:= State; cbCreateSFX.Tag:= 0; end; end; procedure TfrmPackDlg.cbOtherPluginsChange(Sender: TObject); begin if cbOtherPlugins.Checked then begin FArchiveType:= cbPackerList.Text; SwitchOptions(True); ChangeArchiveExt(FArchiveType); rgPacker.ItemIndex := -1; end else begin if rgPacker.ItemIndex = -1 then rgPacker.ItemIndex := 0; end; FCustomParams:= EmptyStr; cbPackerList.Enabled := cbOtherPlugins.Checked; end; procedure TfrmPackDlg.cbPutInTarFirstChange(Sender: TObject); begin if cbPutInTarFirst.Checked then ChangeArchiveExt(FArchiveExt) else if AnsiStartsText(TAR_EXT, FArchiveExt) then begin ChangeArchiveExt(Copy(FArchiveExt, Length(TAR_EXT) + 1, MaxInt)); end; end; procedure TfrmPackDlg.edtPackCmdAcceptDirectory(Sender: TObject; var Value: String); begin Value := IncludeTrailingPathDelimiter(Value) + ExtractFileName(edtPackCmd.Text); end; procedure TfrmPackDlg.arbChange(Sender: TObject); begin if rgPacker.ItemIndex >= 0 then begin FArchiveType:= rgPacker.Items[rgPacker.ItemIndex]; SwitchOptions(True); ChangeArchiveExt(FArchiveType); cbOtherPlugins.Checked := False; end; FCustomParams:= EmptyStr; end; procedure TfrmPackDlg.SwitchOptions(ArcTypeChange: Boolean); // Ugly but working var I: LongInt; sCmd: String; begin cbPutInTarFirst.OnChange:= nil; try if ArcTypeChange then begin // Reset some options cbCreateSFX.Checked:= False; end; // WCX plugins for I:= 0 to gWCXPlugins.Count - 1 do begin if gWCXPlugins.Enabled[I] and (gWCXPlugins.Ext[I] = FArchiveType) then begin // If plugin supports packing with password EnableControl(cbEncrypt, ((gWCXPlugins.Flags[I] and PK_CAPS_ENCRYPT) <> 0)); // If archive can not contain multiple files if ((gWCXPlugins.Flags[I] and PK_CAPS_MULTIPLE) = 0) then begin // If file list contain directory then // put to the tar archive first is needed if not FHasFolder then cbCreateSeparateArchives.Checked:= (FCount > 1) else begin cbPutInTarFirst.Checked:= True; EnableControl(cbPutInTarFirst, False); end; end else begin sCmd:= LowerCase(FArchiveType); cbPutInTarFirst.Checked:= False; EnableControl(cbPutInTarFirst, not ((sCmd = 'tar') or StrBegins(sCmd, 'tar.'))); cbCreateSeparateArchives.Checked:= False; end; FPlugin:= True; // Options that supported by plugins EnableControl(cbStoreDir, True); // Options that don't supported by plugins cbMultivolume.Checked:= False; EnableControl(cbMultivolume, False); Exit; end; end; // MultiArc addons for I := 0 to gMultiArcList.Count - 1 do begin with gMultiArcList.Items[I] do begin if FEnabled and MatchesMaskList(FArchiveType, FExtension, ',') then begin // Archive can contain multiple files cbCreateSeparateArchives.Checked:= False; // If addon supports create self extracting archive EnableControl(cbCreateSFX, (Length(FAddSelfExtract) <> 0)); if cbCreateSFX.Enabled and cbCreateSFX.Checked then sCmd:= FAddSelfExtract else sCmd:= FAdd; // If addon supports create multi volume archive EnableControl(cbMultivolume, (Pos('%V', sCmd) <> 0)); // If addon supports packing with password EnableControl(cbEncrypt, (Pos('%W', sCmd) <> 0)); // If archive can not contain multiple files if (mafFileNameList in FFlags) then begin // If file list contain directory then // put to the tar archive first is needed if not FHasFolder then cbCreateSeparateArchives.Checked:= (FCount > 1) else begin cbPutInTarFirst.Checked:= True; EnableControl(cbPutInTarFirst, False); end; end else begin sCmd:= LowerCase(FArchiveType); cbPutInTarFirst.Checked:= False; EnableControl(cbPutInTarFirst, not ((sCmd = 'tar') or StrBegins(sCmd, 'tar.'))); cbCreateSeparateArchives.Checked:= False; end; FPlugin:= False; // Options that don't supported by addons cbStoreDir.Checked:= True; EnableControl(cbStoreDir, False); Exit; end; end; end; finally cbPutInTarFirst.OnChange:= @cbPutInTarFirstChange; end; end; procedure TfrmPackDlg.ChangeArchiveExt(const NewArcExt: String); var AOldExt, ATarExt: String; begin AOldExt:= FArchiveExt; ATarExt:= IfThen(cbPutInTarFirst.Checked, TAR_EXT); if StrBegins(NewArcExt, ExtensionSeparator) then begin if AnsiStartsText(ATarExt, NewArcExt) then FArchiveExt:= NewArcExt else FArchiveExt:= ATarExt + NewArcExt; end else begin FArchiveExt:= ATarExt + ExtensionSeparator + NewArcExt; end; if AnsiEndsText(AOldExt, edtPackCmd.Text) then begin edtPackCmd.Text:= Copy(edtPackCmd.Text, 1, Length(edtPackCmd.Text) - Length(AOldExt)) + FArchiveExt; end; end; procedure TfrmPackDlg.AddArchiveType(const FileExt, ArcType: String); var iIndex: Integer; begin // First 9 plugins we display as RadioButtons if FArchiveTypeCount < 9 then begin iIndex := rgPacker.Items.Add(ArcType); if FExistsArchive then begin if (FileExt = ArcType) then rgPacker.ItemIndex := iIndex else rgPacker.Controls[iIndex + 1].Enabled := False; end else if (gLastUsedPacker = ArcType) then begin rgPacker.ItemIndex := iIndex; end; FArchiveTypeCount := FArchiveTypeCount + 1; end else // Other plugins we add in ComboBox begin iIndex := cbPackerList.Items.Add(ArcType); if (gLastUsedPacker = ArcType) or (FExistsArchive and (FileExt = ArcType)) then begin cbPackerList.ItemIndex := iIndex; cbOtherPlugins.Checked := True; end; end; end; procedure TfrmPackDlg.OnPackCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); var aFiles: TFiles; aFileSource: ITempFileSystemFileSource; aCopyOutOperation: TFileSourceCopyOperation absolute Operation; begin if (State = fsosStopped) then try if (Operation.Result = fsorFinished) then begin aFileSource := aCopyOutOperation.TargetFileSource as ITempFileSystemFileSource; aFiles := aCopyOutOperation.SourceFiles.Clone; ChangeFileListRoot(aFileSource.FileSystemRoot, aFiles); PackFiles(aFileSource, aFiles); end; finally Free; end; end; procedure TfrmPackDlg.PackFiles(const SourceFileSource: IFileSource; var Files: TFiles); var I: Integer; aFlags : PtrInt; aFile: TFile = nil; aFiles: TFiles = nil; Operation: TFileSourceOperation; NewTargetFileSource: IArchiveFileSource = nil; procedure Pack(var FilesToPack: TFiles; QueueId: TOperationsManagerQueueIdentifier); begin if Assigned(NewTargetFileSource) then begin // Set flags according to user selection in the pack dialog. aFlags := 0; if cbMoveToArchive.Checked then aFlags := aFlags or PK_PACK_MOVE_FILES; if cbStoreDir.Checked then aFlags := aFlags or PK_PACK_SAVE_PATHS; if cbEncrypt.Checked then aFlags := aFlags or PK_PACK_ENCRYPT; Operation := NewTargetFileSource.CreateCopyInOperation( SourceFileSource, FilesToPack, FTargetPathInArchive); if Assigned(Operation) then begin if NewTargetFileSource.IsInterface(IWcxArchiveFileSource) then begin with Operation as TWcxArchiveCopyInOperation do begin PackingFlags:= aFlags; CreateNew:= FNewArchive; TarBefore:= cbPutInTarFirst.Checked; end; end else if NewTargetFileSource.IsInterface(IMultiArchiveFileSource) then begin with Operation as TMultiArchiveCopyInOperation do begin if cbEncrypt.Checked then Password:= FPassword; if cbMultivolume.Checked then VolumeSize:= FVolumeSize; PackingFlags := aFlags; CreateNew:= FNewArchive; CustomParams:= FCustomParams; TarBefore:= cbPutInTarFirst.Checked; end; end; // Start operation. OperationsManager.AddOperation(Operation, QueueId, False, True); end; end; end; var sPassword, sPasswordTmp: String; QueueId: TOperationsManagerQueueIdentifier; begin if Assigned(FTargetFileSource) then begin // Already have a target file source. // It must be an archive file source. if not (FTargetFileSource.IsClass(TArchiveFileSource)) then raise Exception.Create('Invalid target file source type'); NewTargetFileSource := FTargetFileSource; end else // Create a new target file source. begin if not FPlugin then begin if cbEncrypt.Checked then begin sPassword:= EmptyStr; sPasswordTmp:= EmptyStr; repeat if not InputQuery(Caption, rsMsgPasswordEnter, True, sPassword) then Exit; if gRepeatPassword then begin if not InputQuery(Caption, rsMsgPasswordVerify, True, sPasswordTmp) then Exit; end else sPasswordTmp:= sPassword; if sPassword <> sPasswordTmp then ShowMessage(rsMsgPasswordDiff) else FPassword:= sPassword; until sPassword = sPasswordTmp; end; if cbMultivolume.Checked then begin if not ShowInputComboBox(Caption, rsMsgVolumeSizeEnter, glsVolumeSizeHistory, FVolumeSize) then Exit; end; end; // If create separate archives, one per selected file/dir if cbCreateSeparateArchives.Checked then begin // If files count > 1 then put to queue if (Files.Count > 1) and (QueueIdentifier = FreeOperationsQueueId) then QueueId := OperationsManager.GetNewQueueIdentifier else begin QueueId := QueueIdentifier; end; // Pack all selected files for I:= 0 to Files.Count - 1 do begin // Fill files to pack aFiles:= TFiles.Create(Files.Path); try aFiles.Add(Files[I].Clone); FArchiveName:= GetAbsoluteFileName(Files.Path, edtPackCmd.Text); try // Check if there is an ArchiveFileSource for possible archive. aFile := SourceFileSource.CreateFileObject(ExtractFilePath(FArchiveName)); try aFile.Name := Files[I].Name + FArchiveExt; NewTargetFileSource := GetArchiveFileSource(SourceFileSource, aFile, FArchiveType, False, True); finally FreeAndNil(aFile); end; except on E: Exception do begin if (E is EFileSourceException) or (E is EWcxModuleException) then begin if MessageDlg(E.Message, mtError, [mbIgnore, mbAbort], 0) = mrIgnore then Continue; Exit; end; raise; end; end; // Pack current item Pack(aFiles, QueueId); finally FreeAndNil(aFiles); end; end; // for end else begin FArchiveName:= GetAbsoluteFileName(Files.Path, edtPackCmd.Text); try // Check if there is an ArchiveFileSource for possible archive. aFile := SourceFileSource.CreateFileObject(ExtractFilePath(FArchiveName)); try aFile.Name := ExtractFileName(FArchiveName); NewTargetFileSource := GetArchiveFileSource(SourceFileSource, aFile, FArchiveType, False, True); finally FreeAndNil(aFile); end; except on E: Exception do begin if (E is EFileSourceException) or (E is EWcxModuleException) then begin MessageDlg(E.Message, mtError, [mbOK], 0); Exit; end; raise; end; end; // Pack files Pack(Files, QueueIdentifier); end; end; // Save last used packer gLastUsedPacker:= FArchiveType; end; end. ���������������������������������������������������������������������������������doublecmd-1.1.22/src/fpackinfodlg.lfm���������������������������������������������������������������0000644�0001750�0000144�00000021362�14743153644�016530� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmPackInfoDlg: TfrmPackInfoDlg Left = 525 Height = 400 Top = 83 Width = 284 ActiveControl = btnClose AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Properties of packed file' ClientHeight = 400 ClientWidth = 284 Position = poScreenCenter LCLVersion = '2.0.8.0' object pnlInfo: TPanel Left = 0 Height = 313 Top = 0 Width = 284 Align = alClient AutoSize = True BevelOuter = bvNone ClientHeight = 313 ClientWidth = 284 TabOrder = 0 object pnlInfoFile: TPanel AnchorSideLeft.Control = pnlInfo AnchorSideTop.Control = pnlInfo AnchorSideRight.Control = pnlInfo AnchorSideRight.Side = asrBottom Left = 15 Height = 38 Top = 0 Width = 254 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 15 BorderSpacing.Right = 15 BevelOuter = bvNone ClientHeight = 38 ClientWidth = 254 TabOrder = 1 object lblPackedFile: TLabel AnchorSideLeft.Control = pnlInfoFile AnchorSideTop.Control = edtPackedFile AnchorSideTop.Side = asrCenter Left = 0 Height = 18 Top = 15 Width = 28 BorderSpacing.Top = 10 Caption = 'File:' FocusControl = edtPackedFile ParentColor = False end object edtPackedFile: TEdit AnchorSideLeft.Control = lblPackedFile AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlInfoFile AnchorSideRight.Control = pnlInfoFile AnchorSideRight.Side = asrBottom Left = 43 Height = 28 Top = 10 Width = 211 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 15 BorderSpacing.Top = 10 Color = clBtnFace Constraints.MinWidth = 200 Font.Color = clBtnText ParentFont = False ReadOnly = True TabStop = False TabOrder = 0 end end object Bevel1: TBevel AnchorSideLeft.Control = pnlInfo AnchorSideTop.Control = pnlInfoFile AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlInfo AnchorSideRight.Side = asrBottom Left = 15 Height = 9 Top = 48 Width = 254 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 15 BorderSpacing.Top = 10 BorderSpacing.Right = 15 Shape = bsTopLine end object pnlInfoProperties: TPanel AnchorSideLeft.Control = pnlInfo AnchorSideTop.Control = Bevel1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlInfo AnchorSideRight.Side = asrBottom Left = 15 Height = 179 Top = 57 Width = 254 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 15 BorderSpacing.Right = 15 BevelOuter = bvNone ChildSizing.HorizontalSpacing = 30 ChildSizing.VerticalSpacing = 5 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.ShrinkVertical = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 155 ClientWidth = 254 TabOrder = 0 object lblPacker: TLabel Left = 0 Height = 15 Top = 0 Width = 162 Caption = 'Packer:' ParentColor = False end object lblPackedPacker: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 0 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblOriginalSize: TLabel Left = 0 Height = 15 Top = 20 Width = 162 Caption = 'Original size:' ParentColor = False end object lblPackedOrgSize: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 20 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblPackedSize: TLabel Left = 0 Height = 15 Top = 40 Width = 162 Caption = 'Packed size:' ParentColor = False end object lblPackedPackedSize: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 40 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblCompressionRatio: TLabel Left = 0 Height = 15 Top = 60 Width = 162 Caption = 'Compression ratio:' ParentColor = False end object lblPackedCompression: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 60 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblMethod: TLabel Left = 0 Height = 15 Top = 80 Width = 162 Caption = 'Method:' ParentColor = False end object lblPackedMethod: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 80 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblDate: TLabel Left = 0 Height = 15 Top = 100 Width = 162 Caption = 'Date:' ParentColor = False end object lblPackedDate: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 100 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblTime: TLabel Left = 0 Height = 15 Top = 120 Width = 162 Caption = 'Time:' ParentColor = False end object lblPackedTime: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 120 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object lblAttributes: TLabel Left = 0 Height = 15 Top = 140 Width = 162 Caption = 'Attributes:' ParentColor = False end object lblPackedAttr: TKASCDEdit Cursor = crIBeam Left = 192 Height = 15 Top = 140 Width = 62 DrawStyle = dsExtra1 ReadOnly = True TabStop = False end object Bevel2: TBevel AnchorSideLeft.Control = pnlInfoProperties AnchorSideRight.Control = pnlInfoProperties AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = lblDate Left = 0 Height = 4 Top = 91 Width = 254 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Bottom = 4 Shape = bsBottomLine end end end object pnlButtons: TPanel Left = 0 Height = 60 Top = 340 Width = 284 Align = alBottom AutoSize = True BorderSpacing.Top = 15 BevelOuter = bvNone ClientHeight = 60 ClientWidth = 284 TabOrder = 1 object btnClose: TButton AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = pnlButtons AnchorSideBottom.Control = btnUnpackAndExec AnchorSideBottom.Side = asrBottom Left = 10 Height = 25 Top = 0 Width = 55 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Left = 10 Cancel = True Caption = '&Close' Default = True ModalResult = 2 OnKeyUp = btnCloseKeyUp TabOrder = 0 end object btnUnpackAndExec: TButton AnchorSideLeft.Control = btnClose AnchorSideLeft.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnUnpackAllAndExec Left = 69 Height = 25 Top = 0 Width = 205 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Left = 4 BorderSpacing.Right = 10 BorderSpacing.Bottom = 4 Caption = '&Unpack and execute' ModalResult = 1 TabOrder = 1 end object btnUnpackAllAndExec: TButton AnchorSideLeft.Control = pnlButtons AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlButtons AnchorSideBottom.Side = asrBottom Left = 10 Height = 25 Top = 29 Width = 264 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Left = 10 BorderSpacing.Right = 10 BorderSpacing.Bottom = 6 Caption = 'Unpack &all and execute' ModalResult = 8 TabOrder = 2 end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpackinfodlg.lrj���������������������������������������������������������������0000644�0001750�0000144�00000003653�14743153644�016544� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":242912677,"name":"tfrmpackinfodlg.caption","sourcebytes":[80,114,111,112,101,114,116,105,101,115,32,111,102,32,112,97,99,107,101,100,32,102,105,108,101],"value":"Properties of packed file"}, {"hash":5046922,"name":"tfrmpackinfodlg.lblpackedfile.caption","sourcebytes":[70,105,108,101,58],"value":"File:"}, {"hash":108665866,"name":"tfrmpackinfodlg.lblpacker.caption","sourcebytes":[80,97,99,107,101,114,58],"value":"Packer:"}, {"hash":109580698,"name":"tfrmpackinfodlg.lbloriginalsize.caption","sourcebytes":[79,114,105,103,105,110,97,108,32,115,105,122,101,58],"value":"Original size:"}, {"hash":52408634,"name":"tfrmpackinfodlg.lblpackedsize.caption","sourcebytes":[80,97,99,107,101,100,32,115,105,122,101,58],"value":"Packed size:"}, {"hash":260533674,"name":"tfrmpackinfodlg.lblcompressionratio.caption","sourcebytes":[67,111,109,112,114,101,115,115,105,111,110,32,114,97,116,105,111,58],"value":"Compression ratio:"}, {"hash":63632682,"name":"tfrmpackinfodlg.lblmethod.caption","sourcebytes":[77,101,116,104,111,100,58],"value":"Method:"}, {"hash":4885130,"name":"tfrmpackinfodlg.lbldate.caption","sourcebytes":[68,97,116,101,58],"value":"Date:"}, {"hash":5964682,"name":"tfrmpackinfodlg.lbltime.caption","sourcebytes":[84,105,109,101,58],"value":"Time:"}, {"hash":265557994,"name":"tfrmpackinfodlg.lblattributes.caption","sourcebytes":[65,116,116,114,105,98,117,116,101,115,58],"value":"Attributes:"}, {"hash":44709525,"name":"tfrmpackinfodlg.btnclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"}, {"hash":172526965,"name":"tfrmpackinfodlg.btnunpackandexec.caption","sourcebytes":[38,85,110,112,97,99,107,32,97,110,100,32,101,120,101,99,117,116,101],"value":"&Unpack and execute"}, {"hash":184645781,"name":"tfrmpackinfodlg.btnunpackallandexec.caption","sourcebytes":[85,110,112,97,99,107,32,38,97,108,108,32,97,110,100,32,101,120,101,99,117,116,101],"value":"Unpack &all and execute"} ]} �������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpackinfodlg.pas���������������������������������������������������������������0000644�0001750�0000144�00000013471�14743153644�016537� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Packed file information window Copyright (C) 2008-2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fPackInfoDlg; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Forms, StdCtrls, ExtCtrls, Controls, uFile, KASCDEdit, uArchiveFileSource, uFileSourceExecuteOperation; type { TfrmPackInfoDlg } TfrmPackInfoDlg = class(TForm) Bevel1: TBevel; Bevel2: TBevel; btnClose: TButton; btnUnpackAllAndExec: TButton; btnUnpackAndExec: TButton; lblAttributes: TLabel; lblCompressionRatio: TLabel; lblDate: TLabel; lblMethod: TLabel; lblOriginalSize: TLabel; lblPackedFile: TLabel; lblPackedSize: TLabel; lblPacker: TLabel; lblTime: TLabel; lblPackedAttr: TKASCDEdit; lblPackedCompression: TKASCDEdit; lblPackedDate: TKASCDEdit; edtPackedFile: TEdit; lblPackedMethod: TKASCDEdit; lblPackedOrgSize: TKASCDEdit; lblPackedPackedSize: TKASCDEdit; lblPackedPacker: TKASCDEdit; lblPackedTime: TKASCDEdit; pnlInfoProperties: TPanel; pnlInfoFile: TPanel; pnlInfo: TPanel; pnlButtons: TPanel; procedure btnCloseKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); private { private declarations } public constructor Create(TheOwner: TComponent; aFileSource: IArchiveFileSource; aFile: TFile); reintroduce; end; function ShowPackInfoDlg(aFileSource: IArchiveFileSource; aFile: TFile): TFileSourceExecuteOperationResult; implementation {$R *.lfm} uses {$IF DEFINED(LCLGTK2)} LCLType, LCLVersion, {$ENDIF} uDCUtils, uFileSourceOperationTypes; function ShowPackInfoDlg(aFileSource: IArchiveFileSource; aFile: TFile): TFileSourceExecuteOperationResult; begin Result:= fseorSuccess; with TfrmPackInfoDlg.Create(Application, aFileSource, aFile) do begin case ShowModal of mrCancel: Result:= fseorCancelled; mrOK: Result:= fseorYourSelf; mrAll: Result:= fseorWithAll; end; Free; end; end; { TfrmPackInfoDlg } procedure TfrmPackInfoDlg.btnCloseKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin {$IF DEFINED(LCLGTK2) and (lcl_fullversion < 093100)} if Key = VK_RETURN then // Lazarus issue 0021483. ControlKeyUp not called after Enter pressed. Application.ControlKeyUp(btnClose, Key, Shift); {$ENDIF} end; constructor TfrmPackInfoDlg.Create(TheOwner: TComponent; aFileSource: IArchiveFileSource; aFile: TFile); var i: Integer; foundDividingControl: Boolean = False; upperInfoControls: array[0..4] of TControl; begin inherited Create(TheOwner); btnUnpackAndExec.Enabled:= (fsoCopyOut in aFileSource.GetOperationsTypes); btnUnpackAllAndExec.Enabled:= ([fsoList, fsoCopyOut] * aFileSource.GetOperationsTypes = [fsoList, fsoCopyOut]); edtPackedFile.Text:= aFile.FullPath; lblPackedPacker.Caption:= aFileSource.Packer; lblPackedOrgSize.Visible := not aFile.IsDirectory; lblPackedPackedSize.Visible := not aFile.IsDirectory; lblPackedCompression.Visible := False; lblPackedMethod.Visible := False; if not aFile.IsDirectory then begin lblPackedOrgSize.Caption := IntToStrTS(aFile.Size); lblPackedPackedSize.Caption := IntToStrTS(aFile.CompressedSize); lblPackedOrgSize.Visible := aFile.SizeProperty.IsValid; lblPackedPackedSize.Visible := aFile.CompressedSizeProperty.IsValid; if (aFile.Size > 0) and aFile.CompressedSizeProperty.IsValid then begin lblPackedCompression.Caption := IntToStr(100 - (aFile.CompressedSize * 100 div aFile.Size)) + '%'; lblPackedCompression.Visible := True; end; end; // DateTime and Attributes if not aFile.ModificationTimeProperty.IsValid then begin lblPackedDate.Visible:= False; lblPackedTime.Visible:= False; end else begin lblPackedDate.Caption:= DateToStr(aFile.ModificationTime); lblPackedTime.Caption:= TimeToStr(aFile.ModificationTime); end; lblPackedAttr.Caption:= aFile.AttributesProperty.AsString; // Hide labels for not visible values. lblOriginalSize.Visible := lblPackedOrgSize.Visible; lblPackedSize.Visible := lblPackedPackedSize.Visible; lblCompressionRatio.Visible := lblPackedCompression.Visible; lblMethod.Visible := lblPackedMethod.Visible; lblDate.Visible := lblPackedDate.Visible; lblTime.Visible := lblPackedTime.Visible; // Controls from the dividing line to top. upperInfoControls[0] := lblMethod; upperInfoControls[1] := lblCompressionRatio; upperInfoControls[2] := lblPackedSize; upperInfoControls[3] := lblOriginalSize; upperInfoControls[4] := lblPacker; // Make space for the dividing line. for i := Low(upperInfoControls) to High(upperInfoControls) do begin if foundDividingControl then upperInfoControls[i].BorderSpacing.Bottom := 0 else if upperInfoControls[i].Visible then begin foundDividingControl := True; upperInfoControls[i].BorderSpacing.Bottom := 12; end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fprintsetup.lfm����������������������������������������������������������������0000644�0001750�0000144�00000007311�14743153644�016462� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmPrintSetup: TfrmPrintSetup Left = 356 Height = 209 Top = 178 Width = 432 AutoSize = True BorderStyle = bsDialog Caption = 'Print configuration' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ClientHeight = 209 ClientWidth = 432 DesignTimePPI = 120 KeyPreview = True OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnKeyDown = FormKeyDown Position = poOwnerFormCenter LCLVersion = '2.0.2.0' object gbMargins: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 12 Height = 113 Top = 12 Width = 383 AutoSize = True Caption = 'Margins (mm)' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 10 ChildSizing.HorizontalSpacing = 8 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 88 ClientWidth = 379 ParentFont = False TabOrder = 0 object lblLeft: TLabel Left = 8 Height = 28 Top = 10 Width = 28 Caption = '&Left:' FocusControl = seeLeft ParentColor = False ParentFont = False end object seeLeft: TFloatSpinEditEx Left = 44 Height = 28 Top = 10 Width = 129 MaxLength = 0 ParentFont = False TabOrder = 0 DecimalPlaces = 1 MinValue = 0 NullValue = 0 Value = 0 end object lblRight: TLabel Left = 181 Height = 28 Top = 10 Width = 53 Caption = '&Right:' FocusControl = seeRight ParentColor = False ParentFont = False end object seeRight: TFloatSpinEditEx Left = 242 Height = 28 Top = 10 Width = 129 MaxLength = 0 ParentFont = False TabOrder = 1 DecimalPlaces = 1 MinValue = 0 NullValue = 0 Value = 0 end object lblTop: TLabel Left = 8 Height = 28 Top = 50 Width = 28 Caption = '&Top:' FocusControl = seeTop ParentColor = False ParentFont = False end object seeTop: TFloatSpinEditEx Left = 44 Height = 28 Top = 50 Width = 129 MaxLength = 0 ParentFont = False TabOrder = 2 DecimalPlaces = 1 MinValue = 0 NullValue = 0 Value = 0 end object lblBottom: TLabel Left = 181 Height = 28 Top = 50 Width = 53 Caption = '&Bottom:' FocusControl = seeBottom ParentColor = False ParentFont = False end object seeBottom: TFloatSpinEditEx Left = 242 Height = 28 Top = 50 Width = 129 MaxLength = 0 ParentFont = False TabOrder = 3 DecimalPlaces = 1 MinValue = 0 NullValue = 0 Value = 0 end end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = gbMargins AnchorSideTop.Control = gbMargins AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMargins AnchorSideRight.Side = asrBottom Left = 20 Height = 30 Top = 148 Width = 367 Align = alNone Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 15 BorderSpacing.Around = 8 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 1 ShowButtons = [pbOK, pbCancel] ShowBevel = False end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fprintsetup.lrj����������������������������������������������������������������0000644�0001750�0000144�00000001453�14743153644�016474� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":56375182,"name":"tfrmprintsetup.caption","sourcebytes":[80,114,105,110,116,32,99,111,110,102,105,103,117,114,97,116,105,111,110],"value":"Print configuration"}, {"hash":6979065,"name":"tfrmprintsetup.gbmargins.caption","sourcebytes":[77,97,114,103,105,110,115,32,40,109,109,41],"value":"Margins (mm)"}, {"hash":45268346,"name":"tfrmprintsetup.lblleft.caption","sourcebytes":[38,76,101,102,116,58],"value":"&Left:"}, {"hash":193978202,"name":"tfrmprintsetup.lblright.caption","sourcebytes":[38,82,105,103,104,116,58],"value":"&Right:"}, {"hash":2864698,"name":"tfrmprintsetup.lbltop.caption","sourcebytes":[38,84,111,112,58],"value":"&Top:"}, {"hash":158054570,"name":"tfrmprintsetup.lblbottom.caption","sourcebytes":[38,66,111,116,116,111,109,58],"value":"&Bottom:"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fprintsetup.pas����������������������������������������������������������������0000644�0001750�0000144�00000003106�14743153644�016465� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fPrintSetup; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel, SpinEx, uOSForms; type { TfrmPrintSetup } TfrmPrintSetup = class(TModalForm) ButtonPanel: TButtonPanel; gbMargins: TGroupBox; lblLeft: TLabel; lblRight: TLabel; lblTop: TLabel; lblBottom: TLabel; seeLeft: TFloatSpinEditEx; seeRight: TFloatSpinEditEx; seeTop: TFloatSpinEditEx; seeBottom: TFloatSpinEditEx; procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); private public end; implementation {$R *.lfm} uses LCLType, uGlobs; { TfrmPrintSetup } procedure TfrmPrintSetup.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin if ModalResult = mrOK then begin gPrintMargins.Left:= Round(seeLeft.Value * 10); gPrintMargins.Top:= Round(seeTop.Value * 10); gPrintMargins.Right:= Round(seeRight.Value * 10); gPrintMargins.Bottom:= Round(seeBottom.Value * 10); end; end; procedure TfrmPrintSetup.FormCreate(Sender: TObject); begin seeLeft.Value:= gPrintMargins.Left / 10; seeTop.Value:= gPrintMargins.Top / 10; seeRight.Value:= gPrintMargins.Right / 10; seeBottom.Value:= gPrintMargins.Bottom / 10; end; procedure TfrmPrintSetup.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then ModalResult:= mrCancel; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpscommon.pas������������������������������������������������������������������0000644�0001750�0000144�00000047500�14743153644�016111� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fpsCommon; {$mode objfpc}{$H+} interface uses Classes, SysUtils; const {@@ These are some basic rgb color volues. FPSpreadsheet will support only those built-in color constants originating in the EGA palette. } {@@ rgb value of @bold(black) color, BIFF2 palette index 0, BIFF8 index 8} scBlack = $00000000; {@@ rgb value of @bold(white) color, BIFF2 palette index 1, BIFF8 index 9 } scWhite = $00FFFFFF; {@@ rgb value of @bold(red) color, BIFF2 palette index 2, BIFF8 index 10 } scRed = $000000FF; {@@ rgb value of @bold(green) color, BIFF2 palette index 3, BIFF8 index 11 } scGreen = $0000FF00; {@@ rgb value of @bold(blue) color, BIFF2 palette index 4, BIFF8 indexes 12 and 39} scBlue = $00FF0000; {@@ rgb value of @bold(yellow) color, BIFF2 palette index 5, BIFF8 indexes 13 and 34} scYellow = $0000FFFF; {@@ rgb value of @bold(magenta) color, BIFF2 palette index 6, BIFF8 index 14 and 33} scMagenta = $00FF00FF; {@@ rgb value of @bold(cyan) color, BIFF2 palette index 7, BIFF8 indexes 15} scCyan = $00FFFF00; type {@@ Colors in fpspreadsheet are given as rgb values in little-endian notation (i.e. "r" is the low-value byte). The highest-value byte, if not zero, indicates special colors. @note(This byte order in TsColor is opposite to that in HTML colors.) } TsColor = DWord; {@@ Builtin number formats. Only uses a subset of the default formats, enough to be able to read/write date/time values. nfCustom allows to apply a format string directly. } TsNumberFormat = ( // general-purpose for all numbers nfGeneral, // numbers nfFixed, nfFixedTh, nfExp, nfPercentage, nfFraction, // currency nfCurrency, nfCurrencyRed, // dates and times nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfDayMonth, nfMonthYear, nfTimeInterval, // text nfText, // other (format string goes directly into the file) nfCustom); {@@ Ancestor of the fpSpreadsheet exceptions } EFpSpreadsheet = class(Exception); resourcestring // Format rsAmbiguousDecThouSeparator = 'Assuming usage of decimal separator in "%s".'; function Round(AValue: Double): Int64; procedure FloatToFraction(AValue: Double; AMaxDenominator: Int64; out ANumerator, ADenominator: Int64); function TryStrToFloatAuto(AText: String; out ANumber: Double; out ADecimalSeparator, AThousandSeparator: Char; out AWarning: String): Boolean; procedure AddBuiltinBiffFormats(AList: TStringList; AFormatSettings: TFormatSettings; ALastIndex: Integer); procedure RegisterCurrency(ACurrencySymbol: String); procedure RegisterCurrencies(AList: TStrings; AReplace: Boolean); procedure UnregisterCurrency(ACurrencySymbol: String); function CurrencyRegistered(ACurrencySymbol: String): Boolean; procedure GetRegisteredCurrencies(AList: TStrings); function IsNegative(var AText: String): Boolean; function RemoveCurrencySymbol(ACurrencySymbol: String; var AText: String): Boolean; function TryStrToCurrency(AText: String; out ANumber: Double; out ACurrencySymbol:String; const AFormatSettings: TFormatSettings): boolean; implementation uses Math, fpsNumFormat; {@@ ---------------------------------------------------------------------------- Special rounding function which avoids banker's rounding -------------------------------------------------------------------------------} function Round(AValue: Double): Int64; begin if AValue > 0 then Result := trunc(AValue + 0.5) else Result := trunc(AValue - 0.5); end; {@@ ---------------------------------------------------------------------------- Approximates a floating point value as a fraction and returns the values of numerator and denominator. @param AValue Floating point value to be analyzed @param AMaxDenominator Maximum value of the denominator allowed @param ANumerator (out) Numerator of the best approximating fraction @param ADenominator (out) Denominator of the best approximating fraction -------------------------------------------------------------------------------} procedure FloatToFraction(AValue: Double; AMaxDenominator: Int64; out ANumerator, ADenominator: Int64); // Uses method of continued fractions, adapted version from a function in // Bart Broersma's fractions.pp unit: // http://svn.code.sf.net/p/flyingsheep/code/trunk/ConsoleProjecten/fractions/ const MaxInt64 = High(Int64); MinInt64 = Low(Int64); var H1, H2, K1, K2, A, NewA, tmp, prevH1, prevK1: Int64; B, test, diff, prevdiff: Double; PendingOverflow: Boolean; i: Integer = 0; begin if (AValue > MaxInt64) or (AValue < MinInt64) then raise EFPSpreadsheet.Create('Range error'); if abs(AValue) < 0.5 / AMaxDenominator then begin ANumerator := 0; ADenominator := AMaxDenominator; exit; end; H1 := 1; H2 := 0; K1 := 0; K2 := 1; B := AValue; NewA := Round(Floor(B)); prevH1 := H1; prevK1 := K1; prevdiff := 1E308; repeat inc(i); A := NewA; tmp := H1; H1 := A * H1 + H2; H2 := tmp; tmp := K1; K1 := A * K1 + K2; K2 := tmp; test := H1/K1; diff := test - AValue; { Use the previous result if the denominator becomes larger than the allowed value, or if the difference becomes worse because the "best" result has been missed due to rounding error - this is more stable than using a predefined precision in comparing diff with zero. } if (abs(K1) >= AMaxDenominator) or (abs(diff) > abs(prevdiff)) then begin H1 := prevH1; K1 := prevK1; break; end; if (Abs(B - A) < 1E-30) then B := 1E30 //happens when H1/K1 exactly matches Value else B := 1 / (B - A); PendingOverFlow := (B * H1 + H2 > MaxInt64) or (B * K1 + K2 > MaxInt64) or (B > MaxInt64); if not PendingOverflow then NewA := Round(Floor(B)); prevH1 := H1; prevK1 := K1; prevdiff := diff; until PendingOverflow; ANumerator := H1; ADenominator := K1; end; {@@ ---------------------------------------------------------------------------- Converts a string to a floating point number. No assumption on decimal and thousand separator are made. Is needed for reading CSV files. -------------------------------------------------------------------------------} function TryStrToFloatAuto(AText: String; out ANumber: Double; out ADecimalSeparator, AThousandSeparator: Char; out AWarning: String): Boolean; var i: Integer; testSep: Char; testSepPos: Integer; lastDigitPos: Integer; isPercent: Boolean; fs: TFormatSettings; done: Boolean; begin Result := false; AWarning := ''; ADecimalSeparator := #0; AThousandSeparator := #0; if AText = '' then exit; fs := DefaultFormatSettings; // We scan the string starting from its end. If we find a point or a comma, // we have a candidate for the decimal or thousand separator. If we find // the same character again it was a thousand separator, if not it was // a decimal separator. // There is one amgiguity: Using a thousand separator for number < 1.000.000, // but no decimal separator misinterprets the thousand separator as a // decimal separator. done := false; // Indicates that both decimal and thousand separators are found testSep := #0; // Separator candidate to be tested testSepPos := 0; // Position of this separator candidate in the string lastDigitPos := 0; // Position of the last numerical digit isPercent := false; // Flag for percentage format i := Length(AText); // Start at end... while i >= 1 do // ...and search towards start begin case AText[i] of '0'..'9': if (lastDigitPos = 0) and (AText[i] in ['0'..'9']) then lastDigitPos := i; 'e', 'E': ; '%': begin isPercent := true; // There may be spaces before the % sign which we don't want dec(i); while (i >= 1) do if AText[i] = ' ' then dec(i) else begin inc(i); break; end; end; '+', '-': ; '.', ',': begin if testSep = #0 then begin testSep := AText[i]; testSepPos := i; end; // This is the right-most separator candidate in the text // It can be a decimal or a thousand separator. // Therefore, we continue searching from here. dec(i); while i >= 1 do begin if not (AText[i] in ['0'..'9', '+', '-', '.', ',']) then exit; // If we find the testSep character again it must be a thousand separator, // and there are no decimals. if (AText[i] = testSep) then begin // ... but only if there are 3 numerical digits in between if (testSepPos - i = 4) then begin fs.ThousandSeparator := testSep; // The decimal separator is the "other" character. if testSep = '.' then fs.DecimalSeparator := ',' else fs.DecimalSeparator := '.'; AThousandSeparator := fs.ThousandSeparator; ADecimalSeparator := #0; // this indicates that there are no decimals done := true; i := 0; end else begin Result := false; exit; end; end else // If we find the "other" separator character, then testSep was a // decimal separator and the current character is a thousand separator. // But there must be 3 digits in between. if AText[i] in ['.', ','] then begin if testSepPos - i <> 4 then // no 3 digits in between --> no number, maybe a date. exit; fs.DecimalSeparator := testSep; fs.ThousandSeparator := AText[i]; ADecimalSeparator := fs.DecimalSeparator; AThousandSeparator := fs.ThousandSeparator; done := true; i := 0; end; dec(i); end; end; else exit; // Non-numeric character found, no need to continue end; dec(i); end; // Only one separator candicate found, we assume it is a decimal separator if (testSep <> #0) and not done then begin // Warning in case of ambiguous detection of separator. If only one separator // type is found and it is at the third position from the string's end it // might by a thousand separator or a decimal separator. We assume the // latter case, but create a warning. if (lastDigitPos - testSepPos = 3) and not isPercent then AWarning := Format(rsAmbiguousDecThouSeparator, [AText]); fs.DecimalSeparator := testSep; ADecimalSeparator := fs.DecimalSeparator; // Make sure that the thousand separator is different from the decimal sep. if testSep = '.' then fs.ThousandSeparator := ',' else fs.ThousandSeparator := '.'; end; // Delete all thousand separators from the string - StrToFloat does not like them... AText := StringReplace(AText, fs.ThousandSeparator, '', [rfReplaceAll]); // Is the last character a percent sign? if isPercent then while (Length(AText) > 0) and (AText[Length(AText)] in ['%', ' ']) do Delete(AText, Length(AText), 1); // Try string-to-number conversion Result := TryStrToFloat(AText, ANumber, fs); // If successful ... if Result then begin // ... take care of the percentage sign if isPercent then ANumber := ANumber * 0.01; end; end; {@@ ---------------------------------------------------------------------------- These are the built-in number formats as expected in the biff spreadsheet file. In BIFF5+ they are not written to file but they are used for lookup of the number format that Excel used. -------------------------------------------------------------------------------} procedure AddBuiltinBiffFormats(AList: TStringList; AFormatSettings: TFormatSettings; ALastIndex: Integer); var fs: TFormatSettings absolute AFormatSettings; cs: String; i: Integer; begin cs := fs.CurrencyString; AList.Clear; AList.Add(''); // 0 AList.Add('0'); // 1 AList.Add('0.00'); // 2 AList.Add('#,##0'); // 3 AList.Add('#,##0.00'); // 4 AList.Add(BuildCurrencyFormatString(nfCurrency, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 5 AList.Add(BuildCurrencyFormatString(nfCurrencyRed, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 6 AList.Add(BuildCurrencyFormatString(nfCurrency, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 7 AList.Add(BuildCurrencyFormatString(nfCurrencyRed, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 8 AList.Add('0%'); // 9 AList.Add('0.00%'); // 10 AList.Add('0.00E+00'); // 11 AList.Add('# ?/?'); // 12 AList.Add('# ??/??'); // 13 AList.Add(BuildDateTimeFormatString(nfShortDate, fs)); // 14 AList.Add(BuildDateTimeFormatString(nfLongdate, fs)); // 15 AList.Add(BuildDateTimeFormatString(nfDayMonth, fs)); // 16: 'd/mmm' AList.Add(BuildDateTimeFormatString(nfMonthYear, fs)); // 17: 'mmm/yy' AList.Add(BuildDateTimeFormatString(nfShortTimeAM, fs)); // 18 AList.Add(BuildDateTimeFormatString(nfLongTimeAM, fs)); // 19 AList.Add(BuildDateTimeFormatString(nfShortTime, fs)); // 20 AList.Add(BuildDateTimeFormatString(nfLongTime, fs)); // 21 AList.Add(BuildDateTimeFormatString(nfShortDateTime, fs)); // 22 for i:=23 to 36 do AList.Add(''); // not supported AList.Add('_(#,##0_);(#,##0)'); // 37 AList.Add('_(#,##0_);[Red](#,##0)'); // 38 AList.Add('_(#,##0.00_);(#,##0.00)'); // 39 AList.Add('_(#,##0.00_);[Red](#,##0.00)'); // 40 AList.Add('_("'+cs+'"* #,##0_);_("'+cs+'"* (#,##0);_("'+cs+'"* "-"_);_(@_)'); // 41 AList.Add('_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)'); // 42 AList.Add('_("'+cs+'"* #,##0.00_);_("'+cs+'"* (#,##0.00);_("'+cs+'"* "-"??_);_(@_)'); // 43 AList.Add('_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)'); // 44 AList.Add('nn:ss'); // 45 AList.Add('[h]:nn:ss'); // 46 AList.Add('nn:ss.z'); // 47 AList.Add('##0.0E+00'); // 48 AList.Add('@'); // 49 "Text" format for i:=50 to ALastIndex do AList.Add(''); // not supported/used end; var CurrencyList: TStrings = nil; {@@ ---------------------------------------------------------------------------- Registers a currency symbol UTF8 string for usage by fpspreadsheet Currency symbols are the key for detection of currency values. In order to reckognize strings are currency symbols they have to be registered in the internal CurrencyList. Registration occurs automatically for USD, "$", the currencystring defined in the DefaultFormatSettings and for the currency symbols used explicitly when calling WriteCurrency or WriteNumerFormat. -------------------------------------------------------------------------------} procedure RegisterCurrency(ACurrencySymbol: String); begin if not CurrencyRegistered(ACurrencySymbol) and (ACurrencySymbol <> '') then CurrencyList.Add(ACurrencySymbol); end; {@@ RegisterCurrencies registers the currency strings contained in the string list If AReplace is true, the list replaces the currently registered list. -------------------------------------------------------------------------------} procedure RegisterCurrencies(AList: TStrings; AReplace: Boolean); var i: Integer; begin if AList = nil then exit; if AReplace then CurrencyList.Clear; for i:=0 to AList.Count-1 do RegisterCurrency(AList[i]); end; {@@ ---------------------------------------------------------------------------- Removes registration of a currency symbol string for usage by fpspreadsheet -------------------------------------------------------------------------------} procedure UnregisterCurrency(ACurrencySymbol: String); var i: Integer; begin i := CurrencyList.IndexOf(ACurrencySymbol); if i <> -1 then CurrencyList.Delete(i); end; {@@ ---------------------------------------------------------------------------- Checks whether a string is registered as valid currency symbol string -------------------------------------------------------------------------------} function CurrencyRegistered(ACurrencySymbol: String): Boolean; begin Result := CurrencyList.IndexOf(ACurrencySymbol) <> -1; end; {@@ ---------------------------------------------------------------------------- Writes all registered currency symbols to a string list -------------------------------------------------------------------------------} procedure GetRegisteredCurrencies(AList: TStrings); begin AList.Clear; AList.Assign(CurrencyList); end; {@@ ---------------------------------------------------------------------------- Checks whether the given number string is a negative value. In case of currency value, this can be indicated by brackets, or a minus sign at string start or end. -------------------------------------------------------------------------------} function IsNegative(var AText: String): Boolean; begin Result := false; if AText = '' then exit; if (AText[1] = '(') and (AText[Length(AText)] = ')') then begin Result := true; Delete(AText, 1, 1); Delete(AText, Length(AText), 1); AText := Trim(AText); end else if (AText[1] = '-') then begin Result := true; Delete(AText, 1, 1); AText := Trim(AText); end else if (AText[Length(AText)] = '-') then begin Result := true; Delete(AText, Length(AText), 1); AText := Trim(AText); end; end; {@@ ---------------------------------------------------------------------------- Checks wheter a specified currency symbol is contained in a string, removes the currency symbol and returns the remaining string. -------------------------------------------------------------------------------} function RemoveCurrencySymbol(ACurrencySymbol: String; var AText: String): Boolean; var p: Integer; begin p := pos(ACurrencySymbol, AText); if p > 0 then begin Delete(AText, p, Length(ACurrencySymbol)); AText := Trim(AText); Result := true; end else Result := false; end; {@@ ---------------------------------------------------------------------------- Checks whether a string is a number with attached currency symbol. Looks also for negative values in brackets. -------------------------------------------------------------------------------} function TryStrToCurrency(AText: String; out ANumber: Double; out ACurrencySymbol:String; const AFormatSettings: TFormatSettings): boolean; var i: Integer; s: String; isNeg: Boolean; begin Result := false; ANumber := 0.0; ACurrencySymbol := ''; // Check the text for the presence of each known curreny symbol for i:= 0 to CurrencyList.Count-1 do begin // Store string in temporary variable since it will be modified s := AText; // Check for this currency sign being contained in the string, remove it if found. if RemoveCurrencySymbol(CurrencyList[i], s) then begin // Check for negative signs and remove them, but keep this information isNeg := IsNegative(s); // Try to convert remaining string to number if TryStrToFloat(s, ANumber, AFormatSettings) then begin // if successful: take care of negative values if isNeg then ANumber := -ANumber; ACurrencySymbol := CurrencyList[i]; Result := true; exit; end; end; end; end; initialization // Known currency symbols CurrencyList := TStringList.Create; with TStringList(CurrencyList) do begin CaseSensitive := false; Duplicates := dupIgnore; end; RegisterCurrency('USD'); RegisterCurrency('$'); RegisterCurrency(AnsiToUTF8(DefaultFormatSettings.CurrencyString)); finalization FreeAndNil(CurrencyList); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fpsnumformat.pas���������������������������������������������������������������0000644�0001750�0000144�00000421670�14743153644�016635� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{@@ ---------------------------------------------------------------------------- Unit @bold(fpsNumFormat) contains classes and procedures to analyze and process @bold(number formats). AUTHORS: Werner Pamler LICENSE: See the file COPYING.modifiedLGPL.txt, included in the Lazarus distribution, for details about the license. -------------------------------------------------------------------------------} unit fpsNumFormat; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses Classes, SysUtils, fpscommon; const psOK = 0; psErrNoValidColorIndex = 1; psErrNoValidCompareNumber = 2; psErrUnknownInfoInBrackets = 3; psErrConditionalFormattingNotSupported = 4; psErrNoUsableFormat = 5; psErrNoValidNumberFormat = 6; psErrNoValidDateTimeFormat = 7; psErrQuoteExpected = 8; psErrMultipleCurrSymbols = 9; psErrMultipleFracSymbols = 10; psErrMultipleExpChars = 11; psErrGeneralExpected = 12; psAmbiguousSymbol = 13; psErrNoValidTextFormat = 14; type {@@ Set of characters } TsDecsChars = set of char; {@@ Tokens used by the elements of the number format parser. If, e.g. a format string is "0.000" then the number format parser detects the following three tokens - nftIntZeroDigit with integer value 1 (i.e. 1 zero-digit for the integer part) - nftDecSep (i.e. decimal separator) - ntZeroDecs with integer value 2 (i.e. 3 decimal places. } TsNumFormatToken = ( nftGeneral, // token for "general" number format nftText, // must be quoted, stored in TextValue nftThSep, // ',', replaced by FormatSettings.ThousandSeparator nftDecSep, // '.', replaced by FormatSettings.DecimalSeparator nftYear, // 'y' or 'Y', count stored in IntValue nftMonth, // 'm' or 'M', count stored in IntValue nftDay, // 'd' or 'D', count stored in IntValue nftHour, // 'h' or 'H', count stored in IntValue nftMinute, // 'n' or 'N' (or 'm'/'M'), count stored in IntValue nftSecond, // 's' or 'S', count stored in IntValue nftMilliseconds, // 'z', 'Z', '0', count stored in IntValue nftAMPM, // nftMonthMinute, // 'm'/'M' or 'n'/'N', meaning depending on context nftDateTimeSep, // '/' or ':', replaced by value from FormatSettings, stored in TextValue nftSign, // '+' or '-', stored in TextValue nftSignBracket, // '(' or ')' for negative values, stored in TextValue nftIntOptDigit, // '#', count stored in IntValue nftIntZeroDigit, // '0', count stored in IntValue nftIntSpaceDigit, // '?', count stored in IntValue nftIntTh, // '#,##0' sequence for nfFixed, count of 0 stored in IntValue nftZeroDecs, // '0' after dec sep, count stored in IntValue nftOptDecs, // '#' after dec sep, count stored in IntValue nftSpaceDecs, // '?' after dec sep, count stored in IntValue nftExpChar, // 'e' or 'E', stored in TextValue nftExpSign, // '+' or '-' in exponent nftExpDigits, // '0' digits in exponent, count stored in IntValue nftPercent, // '%' percent symbol nftFactor, // thousand separators at end of format string, each one divides value by 1000 nftFracSymbol, // '/' fraction symbol nftFracNumOptDigit, // '#' in numerator, count stored in IntValue nftFracNumSpaceDigit, // '?' in numerator, count stored in IntValue nftFracNumZeroDigit, // '0' in numerator, count stored in IntValue nftFracDenomOptDigit, // '#' in denominator, count stored in IntValue nftFracDenomSpaceDigit,// '?' in denominator, count stored in IntValue nftFracDenomZeroDigit, // '0' in denominator, count stored in IntValue nftFracDenom, // specified denominator, value stored in IntValue nftCurrSymbol, // e.g., '"€"' or '[$€]', stored in TextValue nftCountry, nftColor, // e.g., '[red]', Color in IntValue nftCompareOp, nftCompareValue, nftSpace, nftEscaped, // '\' nftRepeat, nftEmptyCharWidth, nftTextFormat // '@' ); {@@ Element of the parsed number format sequence. Each element is identified by a token and has optional parameters stored as integer, float, and/or text. @member Token Identifies the number format element @member IntValue Integer value associated with the number format element @member FloatValue Floating point value associated with the number format element @member TextValue String value associated with the number format element } TsNumFormatElement = record Token: TsNumFormatToken; IntValue: Integer; FloatValue: Double; TextValue: String; end; {@@ Array of parsed number format elements } TsNumFormatElements = array of TsNumFormatElement; {@@ Summary information classifying a number format section } TsNumFormatKind = (nfkPercent, nfkExp, nfkCurrency, nfkFraction, nfkDate, nfkTime, nfkTimeInterval, nfkText, nfkHasColor, nfkHasThSep, nfkHasFactor); {@@ Set of summary elements classifying and describing a number format section } TsNumFormatKinds = set of TsNumFormatKind; {@@ Number format string can be composed of several parts separated by a semicolon. The number format parser extracts the format information into individual sections for each part } TsNumFormatSection = record {@@ Parser number format elements used by this section } Elements: TsNumFormatElements; {@@ Summary information describing the section } Kind: TsNumFormatKinds; {@@ Reconstructed number format identifier for the built-in fps formats } NumFormat: TsNumberFormat; {@@ Number of decimal places used by the format string } Decimals: Byte; {@@ Minimum number of digits before the decimal separator } MinIntDigits: Byte; {@@ Factor by which a number will be multiplied before converting to string } Factor: Double; {@@ Digits to be used for the integer part of a fraction } FracInt: Integer; {@@ Digits to be used for the numerator part of a fraction } FracNumerator: Integer; {@@ Digits to be used for the denominator part of a fraction } FracDenominator: Integer; {@@ Currency string to be used in case of currency/accounting formats } CurrencySymbol: String; {@@ Color to be used when displaying the converted string } Color: TsColor; end; {@@ Pointer to a parsed number format section } PsNumFormatSection = ^TsNumFormatSection; {@@ Array of parsed number format sections } TsNumFormatSections = array of TsNumFormatSection; { TsNumFormatParams } {@@ Describes a parsed number format and provides all the information to convert a number value to a number or date/time string. These data are created by the number format parser from a format string. } TsNumFormatParams = class(TObject) private FAllowLocalizedAMPM: Boolean; protected function GetNumFormat: TsNumberFormat; virtual; function GetNumFormatStr: String; virtual; public {@@ Array of the format sections } Sections: TsNumFormatSections; constructor Create; procedure DeleteElement(ASectionIndex, AElementIndex: Integer); procedure InsertElement(ASectionIndex, AElementIndex: Integer; AToken: TsNumFormatToken); function SectionsEqualTo(ASections: TsNumFormatSections): Boolean; procedure SetCurrSymbol(AValue: String); procedure SetDecimals(AValue: Byte); procedure SetNegativeRed(AEnable: Boolean); procedure SetThousandSep(AEnable: Boolean); property AllowLocalizedAMPM: boolean read FAllowLocalizedAMPM write FAllowLocalizedAMPM; property NumFormat: TsNumberFormat read GetNumFormat; property NumFormatStr: String read GetNumFormatStr; end; { TsNumFormatList } {@@ Class of number format parameters } TsNumFormatParamsClass = class of TsNumFormatParams; {@@ List containing parsed number format parameters } TsNumFormatList = class(TFPList) { private } FOwnsData: Boolean; function GetItem(AIndex: Integer): TsNumFormatParams; procedure SetItem(AIndex: Integer; const AValue: TsNumFormatParams); protected FFormatSettings: TFormatSettings; FClass: TsNumFormatParamsClass; procedure AddBuiltinFormats; virtual; public constructor Create(AFormatSettings: TFormatSettings; AOwnsData: Boolean); destructor Destroy; override; function AddFormat(ASections: TsNumFormatSections): Integer; overload; function AddFormat(AFormatStr: String): Integer; overload; procedure Clear; procedure Delete(AIndex: Integer); function Find(ASections: TsNumFormatSections): Integer; overload; function Find(AFormatstr: String): Integer; overload; property Items[AIndex: Integer]: TsNumFormatParams read GetItem write SetItem; default; end; { TsNumFormatParser } TsNumFormatParser = class private FToken: Char; FCurrent: PChar; FStart: PChar; FEnd: PChar; FCurrSection: Integer; FStatus: Integer; function GetCurrencySymbol: String; function GetDecimals: byte; function GetFracDenominator: Integer; function GetFracInt: Integer; function GetFracNumerator: Integer; function GetFormatString: String; function GetNumFormat: TsNumberFormat; function GetParsedSectionCount: Integer; function GetParsedSections(AIndex: Integer): TsNumFormatSection; procedure SetDecimals(AValue: Byte); protected FFormatSettings: TFormatSettings; FSections: TsNumFormatSections; { Administration while scanning } procedure AddElement(AToken: TsNumFormatToken; AText: String); overload; procedure AddElement(AToken: TsNumFormatToken; AIntValue: Integer=0; AText: String = ''); overload; procedure AddElement(AToken: TsNumFormatToken; AFloatValue: Double); overload; procedure AddSection; procedure DeleteElement(ASection, AIndex: Integer); procedure InsertElement(ASection, AIndex: Integer; AToken: TsNumFormatToken; AText: String); overload; procedure InsertElement(ASection, AIndex: Integer; AToken: TsNumFormatToken; AIntValue: Integer); overload; procedure InsertElement(ASection, AIndex: Integer; AToken: TsNumFormatToken; AFloatValue: Double); overload; function NextToken: Char; function PrevToken: Char; { Scanning/parsing } procedure ScanAMPM; procedure ScanAndCount(ATestChar: Char; out ACount: Integer); procedure ScanBrackets; procedure ScanCondition(AFirstChar: Char); procedure ScanCurrSymbol; procedure ScanDateTime; procedure ScanFormat; procedure ScanGeneral; procedure ScanNumber; procedure ScanQuotedText; // Main scanner procedure Parse(const AFormatString: String); { Analysis while scanning } procedure AnalyzeColor(AValue: String); function AnalyzeCurrency(const AValue: String): Boolean; { Analysis after scanning } // General procedure CheckSections; procedure CheckSection(ASection: Integer); procedure FixMonthMinuteToken(var ASection: TsNumFormatSection); // Format string function BuildFormatString: String; virtual; public constructor Create(const AFormatString: String; const AFormatSettings: TFormatSettings); destructor Destroy; override; procedure ClearAll; function GetDateTimeCode(ASection: Integer): String; function IsDateTimeFormat: Boolean; function IsTimeFormat: Boolean; procedure LimitDecimals; property CurrencySymbol: String read GetCurrencySymbol; property Decimals: Byte read GetDecimals write SetDecimals; property FormatString: String read GetFormatString; property FracDenominator: Integer read GetFracDenominator; property FracInt: Integer read GetFracInt; property FracNumerator: Integer read GetFracNumerator; property NumFormat: TsNumberFormat read GetNumFormat; property ParsedSectionCount: Integer read GetParsedSectionCount; property ParsedSections[AIndex: Integer]: TsNumFormatSection read GetParsedSections; property Status: Integer read FStatus; end; { Utility functions } function AddAMPM(const ATimeFormatString: String; const AFormatSettings: TFormatSettings): String; function AddIntervalBrackets(AFormatString: String): String; procedure BuildCurrencyFormatList(AList: TStrings; APositive: Boolean; AValue: Double; const ACurrencySymbol: String); function BuildCurrencyFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; ADecimals, APosCurrFmt, ANegCurrFmt: Integer; ACurrencySymbol: String; Accounting: Boolean = false): String; function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; AFormatString: String = ''): String; function BuildFractionFormatString(AMixedFraction: Boolean; ANumeratorDigits, ADenominatorDigits: Integer): String; function BuildNumberFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; ADecimals: Integer = -1; AMinIntDigits: Integer = 1): String; function BuildFormatStringFromSection(const ASection: TsNumFormatSection; AllowLocalizedAMPM: Boolean = true): String; function ApplyTextFormat(AText: String; AParams: TsNumFormatParams): String; function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams; AFormatSettings: TFormatSettings): String; function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte; function GeneralFormatFloat(AValue: Double; AFormatSettings: TFormatSettings): String; inline; function IsBoolValue(const AText, ATrueText, AFalseText: String; out AValue: Boolean): Boolean; function IsCurrencyFormat(AFormat: TsNumberFormat): Boolean; overload; function IsCurrencyFormat(ANumFormat: TsNumFormatParams): Boolean; overload; function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean; overload; function IsDateTimeFormat(AFormatStr: String): Boolean; overload; function IsDateTimeFormat(ANumFormat: TsNumFormatParams): Boolean; overload; function IsDateTimeValue(AText: String; const AFormatSettings: TFormatSettings; out ADateTime: TDateTime; out ANumFormat: TsNumberFormat): Boolean; function IsDateFormat(ANumFormat: TsNumFormatParams): Boolean; function IsTimeFormat(AFormat: TsNumberFormat): Boolean; overload; function IsTimeFormat(AFormatStr: String): Boolean; overload; function IsTimeFormat(ANumFormat: TsNumFormatParams): Boolean; overload; function IsLongTimeFormat(AFormatStr: String; ATimeSeparator: char): Boolean; overload; function IsNumberValue(AText: String; AutoDetectNumberFormat: Boolean; const AFormatSettings: TFormatSettings; out ANumber: Double; out ANumFormat: TsNumberFormat; out ADecimals: Integer; out ACurrencySymbol, AWarning: String): Boolean; function IsTimeIntervalFormat(ANumFormat: TsNumFormatParams): Boolean; function IsTextFormat(ANumFormat: TsNumFormatParams): Boolean; function MakeLongDateFormat(ADateFormat: String): String; function MakeShortDateFormat(ADateFormat: String): String; procedure MakeTimeIntervalMask(Src: String; var Dest: String); function StripAMPM(const ATimeFormatString: String): String; procedure InitFormatSettings(out AFormatSettings: TFormatSettings); procedure ReplaceFormatSettings(var AFormatSettings: TFormatSettings; const ADefaultFormats: TFormatSettings); function CreateNumFormatParams(ANumFormatStr: String; const AFormatSettings: TFormatSettings): TsNumFormatParams; function ParamsOfNumFormatStr(ANumFormatStr: String; const AFormatSettings: TFormatSettings; var AResult: TsNumFormatParams): Integer; implementation uses StrUtils, Math, LazUTF8; const { Array of format strings identifying the order of number and currency symbol of a positive currency value. The number is expected at index 0, the currency symbol at index 1 of the parameter array used by the fpc Format() function. } POS_CURR_FMT: array[0..3] of string = ( ('%1:s%0:s'), // 0: $1 ('%0:s%1:s'), // 1: 1$ ('%1:s %0:s'), // 2: $ 1 ('%0:s %1:s') // 3: 1 $ ); { Array of format strings identifying the order of number and currency symbol of a negative currency value. The sign is shown as a dash character ("-") or by means of brackets. The number is expected at index 0, the currency symbol at index 1 of the parameter array for the fpc Format() function. } NEG_CURR_FMT: array[0..15] of string = ( ('(%1:s%0:s)'), // 0: ($1) ('-%1:s%0:s'), // 1: -$1 ('%1:s-%0:s'), // 2: $-1 ('%1:s%0:s-'), // 3: $1- ('(%0:s%1:s)'), // 4: (1$) ('-%0:s%1:s'), // 5: -1$ ('%0:s-%1:s'), // 6: 1-$ ('%0:s%1:s-'), // 7: 1$- ('-%0:s %1:s'), // 8: -1 $ ('-%1:s %0:s'), // 9: -$ 1 ('%0:s %1:s-'), // 10: 1 $- ('%1:s %0:s-'), // 11: $ 1- ('%1:s -%0:s'), // 12: $ -1 ('%0:s- %1:s'), // 13: 1- $ ('(%1:s %0:s)'), // 14: ($ 1) ('(%0:s %1:s)') // 15: (1 $) ); {==============================================================================} { Float-to-string conversion } {==============================================================================} type { Set of parsed number format tokens } TsNumFormatTokenSet = set of TsNumFormatToken; const { Set of tokens which terminate number information in a format string } TERMINATING_TOKENS: TsNumFormatTokenSet = [nftSpace, nftText, nftEscaped, nftPercent, nftCurrSymbol, nftSign, nftSignBracket]; { Set of tokens which describe the integer part of a number format } INT_TOKENS: TsNumFormatTokenSet = [nftIntOptDigit, nftIntZeroDigit, nftIntSpaceDigit]; { Set of tokens which describe the decimals of a number format } DECS_TOKENS: TsNumFormatTokenSet = [nftZeroDecs, nftOptDecs, nftSpaceDecs]; { Set of tokens which describe the numerator of a fraction format } FRACNUM_TOKENS: TsNumFormatTokenSet = [nftFracNumOptDigit, nftFracNumZeroDigit, nftFracNumSpaceDigit]; { Set of tokens which describe the denominator of a fraction format } FRACDENOM_TOKENS: TsNumFormatTokenSet = [nftFracDenomOptDigit, nftFracDenomZeroDigit, nftFracDenomSpaceDigit, nftFracDenom]; { Set of tokens which describe the exponent in exponential formatting of a number } EXP_TOKENS: TsNumFormatTokenSet = [nftExpDigits]; // todo: expand by optional digits (0.00E+#) { Helper function which checks whether a sequence of format tokens for exponential formatting begins at the specified index in the format elements } function CheckExp(const AElements: TsNumFormatElements; AIndex: Integer): Boolean; var numEl: Integer; i: Integer; begin numEl := Length(AElements); Result := (AIndex < numEl) and (AElements[AIndex].Token in INT_TOKENS); if not Result then exit; numEl := Length(AElements); i := AIndex + 1; while (i < numEl) and (AElements[i].Token in INT_TOKENS) do inc(i); // no decimal places if (i+2 < numEl) and (AElements[i].Token = nftExpChar) and (AElements[i+1].Token = nftExpSign) and (AElements[i+2].Token in EXP_TOKENS) then begin Result := true; exit; end; // with decimal places if (i < numEl) and (AElements[i].Token = nftDecSep) //and (AElements[i+1].Token in DECS_TOKENS) then begin inc(i); while (i < numEl) and (AElements[i].Token in DECS_TOKENS) do inc(i); if (i + 2 < numEl) and (AElements[i].Token = nftExpChar) and (AElements[i+1].Token = nftExpSign) and (AElements[i+2].Token in EXP_TOKENS) then begin Result := true; exit; end; end; Result := false; end; { Helper function which checks whether a sequence of format tokens for fraction formatting begins at the specified index in the format elements } function CheckFraction(const AElements: TsNumFormatElements; AIndex: Integer; out digits: Integer): Boolean; var numEl: Integer; i: Integer; begin digits := 0; numEl := Length(AElements); Result := (AIndex < numEl); if not Result then exit; i := AIndex; // Check for mixed fraction (integer split off, sample format "# ??/??" if (AElements[i].Token in (INT_TOKENS + [nftIntTh])) then begin inc(i); while (i < numEl) and (AElements[i].Token in (INT_TOKENS + [nftIntTh])) do inc(i); while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do inc(i); end; if (i = numEl) or not (AElements[i].Token in FRACNUM_TOKENS) then exit(false); // Here follows the ordinary fraction (no integer split off); sample format "??/??" while (i < numEl) and (AElements[i].Token in FRACNUM_TOKENS) do inc(i); while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do inc(i); if (i = numEl) or (AElements[i].Token <> nftFracSymbol) then exit(False); inc(i); while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do inc(i); if (i = numEl) or (not (AElements[i].Token in FRACDENOM_TOKENS)) then exit(false); while (i < numEL) and (AElements[i].Token in FRACDENOM_TOKENS) do begin case AElements[i].Token of nftFracDenomZeroDigit : inc(digits, AElements[i].IntValue); nftFracDenomSpaceDigit: inc(digits, AElements[i].IntValue); nftFracDenomOptDigit : inc(digits, AElements[i].IntValue); nftFracDenom : digits := -AElements[i].IntValue; // "-" indicates a literal denominator value! end; inc(i); end; Result := true; end; { Processes a sequence of #, 0, and ? tokens. Adds leading (GrowRight=false) or trailing (GrowRight=true) zeros and/or spaces as specified by the format elements to the number value string. On exit AIndex points to the first non-integer token. } function ProcessIntegerFormat(AValue: String; AFormatSettings: TFormatSettings; const AElements: TsNumFormatElements; var AIndex: Integer; ATokens: TsNumFormatTokenSet; GrowRight, UseThSep: Boolean): String; const OptTokens = [nftIntOptDigit, nftFracNumOptDigit, nftFracDenomOptDigit, nftOptDecs]; ZeroTokens = [nftIntZeroDigit, nftFracNumZeroDigit, nftFracDenomZeroDigit, nftZeroDecs, nftIntTh]; SpaceTokens = [nftIntSpaceDigit, nftFracNumSpaceDigit, nftFracDenomSpaceDigit, nftSpaceDecs]; AllOptTokens = OptTokens + SpaceTokens; var fs: TFormatSettings absolute AFormatSettings; i, j, L: Integer; numEl: Integer; begin Result := AValue; numEl := Length(AElements); if GrowRight then begin // This branch is intended for decimal places, i.e. there may be trailing zeros. i := AIndex; if (AValue = '0') and (AElements[i].Token in AllOptTokens) then Result := ''; // Remove trailing zeros while (Result <> '') and (Result[Length(Result)] = '0') do Delete(Result, Length(Result), 1); // Add trailing zeros or spaces as required by the elements. i := AIndex; L := 0; while (i < numEl) and (AElements[i].Token in ATokens) do begin if AElements[i].Token in ZeroTokens then begin inc(L, AElements[i].IntValue); while Length(Result) < L do Result := Result + '0' end else if AElements[i].Token in SpaceTokens then begin inc(L, AElements[i].IntValue); while Length(Result) < L do Result := Result + ' '; end; inc(i); end; if UseThSep then begin j := 2; while (j < Length(Result)) and (Result[j-1] <> ' ') and (Result[j] <> ' ') do begin Insert(fs.ThousandSeparator, Result, 1); inc(j, 3); end; end; AIndex := i; end else begin // This branch is intended for digits (or integer and numerator parts of fractions) // --> There are no leading zeros. // Find last digit token of the sequence i := AIndex; while (i < numEl) and (AElements[i].Token in ATokens) do inc(i); j := i; if i > 0 then dec(i); if (AValue = '0') and (AElements[i].Token in AllOptTokens) and (i = AIndex) then Result := ''; // From the end of the sequence, going backward, add leading zeros or spaces // as required by the elements of the format. L := 0; while (i >= AIndex) do begin if AElements[i].Token in ZeroTokens then begin inc(L, AElements[i].IntValue); while Length(Result) < L do Result := '0' + Result; end else if AElements[i].Token in SpaceTokens then begin inc(L, AElements[i].IntValue); while Length(Result) < L do Result := ' ' + Result; end; dec(i); end; AIndex := j; if UseThSep then begin // AIndex := j + 1; j := Length(Result) - 2; while (j > 1) and (Result[j-1] <> ' ') and (Result[j] <> ' ') do begin Insert(fs.ThousandSeparator, Result, j); dec(j, 3); end; end; end; end; { Converts the floating point number to an exponential number string according to the format specification in AElements. It must have been verified before, that the elements in fact are valid for an exponential format. } function ProcessExpFormat(AValue: Double; AFormatSettings: TFormatSettings; const AElements: TsNumFormatElements; var AIndex: Integer): String; var fs: TFormatSettings absolute AFormatSettings; expchar: String; expSign: String; se, si, sd: String; decs, expDigits: Integer; intZeroDigits, intOptDigits, intSpaceDigits: Integer; numStr: String; i, id, p: Integer; numEl: Integer; begin Result := ''; numEl := Length(AElements); // Determine digits of integer part of mantissa intZeroDigits := 0; intOptDigits := 0; intSpaceDigits := 0; i := AIndex; while (AElements[i].Token in INT_TOKENS) do begin case AElements[i].Token of nftIntZeroDigit : inc(intZeroDigits, AElements[i].IntValue); nftIntSpaceDigit: inc(intSpaceDigits, AElements[i].IntValue); nftIntOptDigit : inc(intOptDigits, AElements[i].IntValue); end; inc(i); end; // No decimal places if (i + 2 < numEl) and (AElements[i].Token = nftExpChar) then begin expChar := AElements[i].TextValue; expSign := AElements[i+1].TextValue; expDigits := 0; i := i+2; while (i < numEl) and (AElements[i].Token in EXP_TOKENS) do begin inc(expDigits, AElements[i].IntValue); // not exactly what Excel does... Rather exotic case... inc(i); end; numstr := FormatFloat('0'+expChar+expSign+DupeString('0', expDigits), AValue, fs); p := pos('e', Lowercase(numStr)); se := copy(numStr, p, Length(numStr)); // exp part of the number string, incl "E" numStr := copy(numstr, 1, p-1); // mantissa of the number string numStr := ProcessIntegerFormat(numStr, fs, AElements, AIndex, INT_TOKENS, false, false); Result := numStr + se; AIndex := i; end else // With decimal places if (i + 1 < numEl) and (AElements[i].Token = nftDecSep) then begin inc(i); id := i; // index of decimal elements decs := 0; while (i < numEl) and (AElements[i].Token in DECS_TOKENS) do begin case AElements[i].Token of nftZeroDecs, nftSpaceDecs: inc(decs, AElements[i].IntValue); end; inc(i); end; expChar := AElements[i].TextValue; expSign := AElements[i+1].TextValue; expDigits := 0; inc(i, 2); while (i < numEl) and (AElements[i].Token in EXP_TOKENS) do begin inc(expDigits, AElements[i].IntValue); inc(i); end; if decs=0 then numstr := FormatFloat('0'+expChar+expSign+DupeString('0', expDigits), AValue, fs) else numStr := FloatToStrF(AValue, ffExponent, decs+1, expDigits, fs); if (abs(AValue) >= 1.0) and (expSign = '-') then Delete(numStr, pos('+', numStr), 1); p := pos('e', Lowercase(numStr)); se := copy(numStr, p, Length(numStr)); // exp part of the number string, incl "E" numStr := copy(numStr, 1, p-1); // mantissa of the number string p := pos(fs.DecimalSeparator, numStr); if p = 0 then begin si := numstr; sd := ''; end else begin si := ProcessIntegerFormat(copy(numStr, 1, p-1), fs, AElements, AIndex, INT_TOKENS, false, false); // integer part of the mantissa sd := ProcessIntegerFormat(copy(numStr, p+1, Length(numStr)), fs, AElements, id, DECS_TOKENS, true, false); // fractional part of the mantissa end; // Put all parts together... Result := si + fs.DecimalSeparator + sd + se; AIndex := i; end; end; function ProcessFracFormat(AValue: Double; const AFormatSettings: TFormatSettings; ADigits: Integer; const AElements: TsNumFormatElements; var AIndex: Integer): String; var fs: TFormatSettings absolute AFormatSettings; frint, frnum, frdenom, maxdenom: Int64; sfrint, sfrnum, sfrdenom: String; sfrsym, sintnumspace, snumsymspace, ssymdenomspace: String; i, numEl: Integer; begin sintnumspace := ''; snumsymspace := ''; ssymdenomspace := ''; sfrsym := '/'; if ADigits >= 0 then maxDenom := Round(IntPower(10, ADigits)); numEl := Length(AElements); i := AIndex; if AElements[i].Token in (INT_TOKENS + [nftIntTh]) then begin // Split-off integer if (AValue >= 1) then begin frint := trunc(AValue); AValue := frac(AValue); end else frint := 0; if ADigits >= 0 then FloatToFraction(AValue, maxdenom, frnum, frdenom) else begin frdenom := -ADigits; frnum := round(AValue*frdenom); end; sfrint := ProcessIntegerFormat(IntToStr(frint), fs, AElements, i, INT_TOKENS + [nftIntTh], false, (AElements[i].Token = nftIntTh)); while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do begin sintnumspace := sintnumspace + AElements[i].TextValue; inc(i); end; end else begin // "normal" fraction sfrint := ''; if ADigits > 0 then FloatToFraction(AValue, maxdenom, frnum, frdenom) else begin frdenom := -ADigits; frnum := round(AValue*frdenom); end; sintnumspace := ''; end; // numerator and denominator sfrnum := ProcessIntegerFormat(IntToStr(frnum), fs, AElements, i, FRACNUM_TOKENS, false, false); while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do begin snumsymspace := snumsymspace + AElements[i].TextValue; inc(i); end; inc(i); // fraction symbol while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do begin ssymdenomspace := ssymdenomspace + AElements[i].TextValue; inc(i); end; sfrdenom := ProcessIntegerFormat(IntToStr(frdenom), fs, AElements, i, FRACDENOM_TOKENS, false, false); AIndex := i+1; // Special cases if (frnum = 0) then begin if sfrnum = '' then begin sintnumspace := ''; snumsymspace := ''; ssymdenomspace := ''; sfrdenom := ''; sfrsym := ''; end else if trim(sfrnum) = '' then begin sfrdenom := DupeString(' ', Length(sfrdenom)); sfrsym := ' '; end; end; if sfrint = '' then sintnumspace := ''; // Compose result string Result := sfrnum + snumsymspace + sfrsym + ssymdenomspace + sfrdenom; if (Trim(Result) = '') and (sfrint = '') then sfrint := '0'; if sfrint <> '' then Result := sfrint + sintnumSpace + result; end; function ProcessFloatFormat(AValue: Double; AFormatSettings: TFormatSettings; const AElements: TsNumFormatElements; var AIndex: Integer): String; var fs: TFormatSettings absolute AFormatSettings; // just to ease typing... numEl: Integer; numStr, s: String; p, i: Integer; decs: Integer; useThSep: Boolean; decsIndex: Integer; begin Result := ''; numEl := Length(AElements); useThSep := AElements[AIndex].Token = nftIntTh; // Find the element index of the decimal separator i := AIndex; while (i < numEl) and (AElements[i].Token <> nftDecSep) do inc(i); // No decimal separator --> format as integer if i >= numEl then begin // fpsUtils.Round() avoids Banker's rounding Result := ProcessIntegerFormat(IntToStr(fpsCommon.Round(AValue)), fs, AElements, AIndex, (INT_TOKENS + [nftIntTh]), false, useThSep); exit; end; // There is a decimal separator. Get the count of decimal places. decs := 0; inc(i); decsIndex := i; while (i < numEl) and (AElements[i].Token in DECS_TOKENS) do begin inc(decs, AElements[i].IntValue); inc(i); end; // Convert value to string; this will do some rounding if required. numstr := FloatToStrF(AValue, ffFixed, MaxInt, decs, fs); // Process the integer part of the rounded number string p := pos(fs.DecimalSeparator, numstr); if p > 0 then s := copy(numstr, 1, p-1) else s := numstr; Result := ProcessIntegerFormat(s, fs, AElements, AIndex, (INT_TOKENS + [nftIntTh]), false, UseThSep); // Process the fractional part of the rounded number string if p > 0 then begin s := Copy(numstr, p+1, Length(numstr)); AIndex := decsIndex; s := ProcessIntegerFormat(s, fs, AElements, AIndex, DECS_TOKENS, true, false); if s <> '' then Result := Result + fs.DecimalSeparator + s; end; end; {@@ ---------------------------------------------------------------------------- Converts a floating point number to a string as determined by the specified number format parameters @param AValue Value to be converted to a string @param AParams Number format parameters which will be applied in the conversion. The number format params are obtained by the number format parser from the number format string. @param AFormatSettings Format settings needed by the number format parser for the conversion @returns Converted string -------------------------------------------------------------------------------} function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams; AFormatSettings: TFormatSettings): String; { Returns true if s represent the value 0; it can be written in various ways: '0', '0.00', '0,000.0', '0.00E+10' etc. } function IsZeroStr(s: String): Boolean; var i: Integer; begin Result := false; for i:=1 to Length(s) do case s[i] of 'e', 'E': break; '1'..'9': exit; end; Result := true; end; var fs: TFormatSettings absolute AFormatSettings; sidx: Integer; section: TsNumFormatSection; i, el, numEl: Integer; isNeg: Boolean; yr, mon, day, hr, min, sec, ms: Word; s: String; digits: Integer; begin Result := ''; if IsNaN(AValue) then exit; if AParams = nil then begin Result := GeneralFormatFloat(AValue, fs); exit; end; sidx := 0; if (AValue < 0) and (Length(AParams.Sections) > 1) then sidx := 1; if (AValue = 0) and (Length(AParams.Sections) > 2) then sidx := 2; isNeg := (AValue < 0); AValue := abs(AValue); // section 0 adds the sign back, section 1 has the sign in the elements section := AParams.Sections[sidx]; numEl := Length(section.Elements); if nfkPercent in section.Kind then AValue := AValue * 100.0; if nfkHasFactor in section.Kind then AValue := AValue * section.Factor; if nfkTime in section.Kind then DecodeTime(AValue, hr, min, sec, ms); if nfkDate in section.Kind then DecodeDate(AValue, yr, mon, day); el := 0; while (el < numEl) do begin if section.Elements[el].Token = nftGeneral then begin s := GeneralFormatFloat(AValue, fs); if (sidx=0) and isNeg then s := '-' + s; Result := Result + s; end else // Integer token: can be the start of a number, exp, or mixed fraction format // Cases with thousand separator are handled here as well. if section.Elements[el].Token in (INT_TOKENS + [nftIntTh]) then begin // Check for exponential format if CheckExp(section.Elements, el) then s := ProcessExpFormat(AValue, fs, section.Elements, el) else // Check for fraction format if CheckFraction(section.Elements, el, digits) then s := ProcessFracFormat(AValue, fs, digits, section.Elements, el) else // Floating-point or integer s := ProcessFloatFormat(AValue, fs, section.Elements, el); if (sidx = 0) and isNeg and not IsZeroStr(s) then s := '-' + s; Result := Result + s; Continue; end else // Regular fraction (without integer being split off) if (section.Elements[el].Token in FRACNUM_TOKENS) and CheckFraction(section.Elements, el, digits) then begin s := ProcessFracFormat(AValue, fs, digits, section.Elements, el); if (sidx = 0) and isNeg then s := '-' + s; Result := Result + s; Continue; end else case section.Elements[el].Token of nftSpace, nftText, nftEscaped, nftCurrSymbol, nftSign, nftSignBracket, nftPercent: Result := Result + section.Elements[el].TextValue; nftEmptyCharWidth: Result := Result + ' '; nftDateTimeSep: case section.Elements[el].TextValue of '/': Result := Result + fs.DateSeparator; ':': Result := Result + fs.TimeSeparator; else Result := Result + section.Elements[el].TextValue; end; nftDecSep: Result := Result + fs.DecimalSeparator; nftThSep: Result := Result + fs.ThousandSeparator; nftYear: case section.Elements[el].IntValue of 1, 2: Result := Result + IfThen(yr mod 100 < 10, '0'+IntToStr(yr mod 100), IntToStr(yr mod 100)); 4: Result := Result + IntToStr(yr); end; nftMonth: case section.Elements[el].IntValue of 1: Result := Result + IntToStr(mon); 2: Result := Result + IfThen(mon < 10, '0'+IntToStr(mon), IntToStr(mon)); 3: Result := Result + fs.ShortMonthNames[mon]; 4: Result := Result + fs.LongMonthNames[mon]; end; nftDay: case section.Elements[el].IntValue of 1: result := result + IntToStr(day); 2: result := Result + IfThen(day < 10, '0'+IntToStr(day), IntToStr(day)); 3: Result := Result + fs.ShortDayNames[DayOfWeek(AValue)]; 4: Result := Result + fs.LongDayNames[DayOfWeek(AValue)]; end; nftHour: begin if section.Elements[el].IntValue < 0 then // This case is for nfTimeInterval s := IntToStr(Int64(hr) + trunc(AValue) * 24) else if section.Elements[el].TextValue = 'AM' then // This tag is set in case of AM/FM format begin hr := hr mod 12; if hr = 0 then hr := 12; s := IntToStr(hr) end else s := IntToStr(hr); if (abs(section.Elements[el].IntValue) = 2) and (Length(s) = 1) then s := '0' + s; Result := Result + s; end; nftMinute: begin if section.Elements[el].IntValue < 0 then // case for nfTimeInterval s := IntToStr(int64(min) + trunc(AValue) * 24 * 60) else s := IntToStr(min); if (abs(section.Elements[el].IntValue) = 2) and (Length(s) = 1) then s := '0' + s; Result := Result + s; end; nftSecond: begin if section.Elements[el].IntValue < 0 then // case for nfTimeInterval s := IntToStr(Int64(sec) + trunc(AValue) * 24 * 60 * 60) else s := IntToStr(sec); if (abs(section.Elements[el].IntValue) = 2) and (Length(s) = 1) then s := '0' + s; Result := Result + s; end; nftMilliseconds: case section.Elements[el].IntValue of 1: Result := Result + IntToStr(round(ms/100)); 2: Result := Result + Format('%.2d', [round(ms/10)]); 3: Result := Result + Format('%.3d', [ms]); end; nftAMPM: begin s := section.Elements[el].TextValue; if lowercase(s) = 'ampm' then s := IfThen(frac(AValue) < 0.5, fs.TimeAMString, fs.TimePMString) else begin i := pos('/', s); if i > 0 then s := IfThen(frac(AValue) < 0.5, copy(s, 1, i-1), copy(s, i+1, Length(s))) else s := IfThen(frac(AValue) < 0.5, 'AM', 'PM'); end; Result := Result + s; end; end; // case inc(el); end; // while end; function GeneralFormatFloat(AValue: Double; AFormatSettings: TFormatSettings): String; begin Result := FloatToStrF(AValue, ffGeneral, 15, 15, AFormatSettings); // 15 is for best rounding results. // Note: Still more than Excel whichrounds pi to 9 digits only. end; {==============================================================================} { Utility functions } {==============================================================================} {@@ ---------------------------------------------------------------------------- Adds an AM/PM format code to a pre-built time formatting string. Example: ATimeFormatString = 'hh:nn' ==> 'hh:nn AM/PM' @param ATimeFormatString String of time formatting codes (such as 'hh:nn') @param AFormatSettings FormatSettings for locale-dependent information @returns Formatting string with AM/PM option activated. -------------------------------------------------------------------------------} function AddAMPM(const ATimeFormatString: String; const AFormatSettings: TFormatSettings): String; begin Result := Format('%s AM/PM', [StripAMPM(ATimeFormatString)]); end; {@@ ---------------------------------------------------------------------------- The given format string is assumed to represent a time interval, i.e. its first time symbol must be enclosed by square brackets. Checks if this is true, and adds the brackes if not. @param AFormatString String with time formatting codes @returns Unchanged format string if its first time code is in square brackets (as in '[h]:nn:ss'). If not, the first time code is enclosed in square brackets. -------------------------------------------------------------------------------} function AddIntervalBrackets(AFormatString: String): String; var p: Integer; s1, s2: String; begin if AFormatString[1] = '[' then Result := AFormatString else begin p := pos(':', AFormatString); if p <> 0 then begin s1 := copy(AFormatString, 1, p-1); s2 := copy(AFormatString, p, Length(AFormatString)); Result := Format('[%s]%s', [s1, s2]); end else Result := Format('[%s]', [AFormatString]); end; end; {@@ ---------------------------------------------------------------------------- Builds a string list with samples of the predefined currency formats @param AList String list in which the format samples are stored @param APositive If @true, samples are built for positive currency values, otherwise for negative values @param AValue Currency value to be used when calculating the sample strings @param ACurrencySymbol Currency symbol string to be used in the samples -------------------------------------------------------------------------------} procedure BuildCurrencyFormatList(AList: TStrings; APositive: Boolean; AValue: Double; const ACurrencySymbol: String); var valueStr: String; i: Integer; begin valueStr := Format('%.0n', [AValue]); AList.BeginUpdate; try if AList.Count = 0 then begin if APositive then for i:=0 to High(POS_CURR_FMT) do AList.Add(Format(POS_CURR_FMT[i], [valueStr, ACurrencySymbol])) else for i:=0 to High(NEG_CURR_FMT) do AList.Add(Format(NEG_CURR_FMT[i], [valueStr, ACurrencySymbol])); end else begin if APositive then for i:=0 to High(POS_CURR_FMT) do AList[i] := Format(POS_CURR_FMT[i], [valueStr, ACurrencySymbol]) else for i:=0 to High(NEG_CURR_FMT) do AList[i] := Format(NEG_CURR_FMT[i], [valueStr, ACurrencySymbol]); end; finally AList.EndUpdate; end; end; {@@ ---------------------------------------------------------------------------- Builds a currency format string. The presentation of negative values (brackets, or minus signs) is taken from the provided format settings. The format string consists of three sections, separated by semicolons. Example: '"$"#,##0.00;("$"#,##0.00);"$"0.00' @param ANumberFormat Identifier of the built-in number format for which the format string is to be generated. @param AFormatSettings FormatSettings to be applied (used to extract default values for the parameters following) @param ADecimals number of decimal places. If < 0, the CurrencyDecimals of the FormatSettings is used. @param APosCurrFmt Identifier for the order of currency symbol, value and spaces of positive values - see pcfXXXX constants in fpsTypes.pas. If < 0, the CurrencyFormat of the FormatSettings is used. @param ANegCurrFmt Identifier for the order of currency symbol, value and spaces of negative values. Specifies also usage of (). - see ncfXXXX constants in fpsTypes.pas. If < 0, the NegCurrFormat of the FormatSettings is used. @param ACurrencySymbol String to identify the currency, like $ or USD. If ? the CurrencyString of the FormatSettings is used. @param Accounting If true, adds spaces for alignment of decimals @returns String of formatting codes -------------------------------------------------------------------------------} function BuildCurrencyFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; ADecimals, APosCurrFmt, ANegCurrFmt: Integer; ACurrencySymbol: String; Accounting: Boolean = false): String; var decs: String; pcf, ncf: Byte; p, n: String; negRed: Boolean; begin pcf := IfThen(APosCurrFmt < 0, AFormatSettings.CurrencyFormat, APosCurrFmt); ncf := IfThen(ANegCurrFmt < 0, AFormatSettings.NegCurrFormat, ANegCurrFmt); if (ADecimals < 0) then ADecimals := AFormatSettings.CurrencyDecimals; if ACurrencySymbol = '?' then ACurrencySymbol := AFormatSettings.CurrencyString; if ACurrencySymbol <> '' then ACurrencySymbol := '[$' + ACurrencySymbol + ']'; // ACurrencySymbol := '"' + ACurrencySymbol + '"'; // <-- not good for biff2 decs := DupeString('0', ADecimals); if ADecimals > 0 then decs := '.' + decs; negRed := (ANumberFormat = nfCurrencyRed); p := POS_CURR_FMT[pcf]; // Format mask for positive values n := NEG_CURR_FMT[ncf]; // Format mask for negative values // add extra space for the sign of the number for perfect alignment in Excel if Accounting then case ncf of 0, 14: p := p + '_)'; 3, 11: p := p + '_-'; 4, 15: p := '_(' + p; 5, 8 : p := '_-' + p; end; if ACurrencySymbol <> '' then begin Result := Format(p, ['#,##0' + decs, ACurrencySymbol]) + ';' + IfThen(negRed, '[red]', '') + Format(n, ['#,##0' + decs, ACurrencySymbol]) + ';' + Format(p, ['0'+decs, ACurrencySymbol]); end else begin Result := '#,##0' + decs; if negRed then Result := Result +';[red]' else Result := Result +';'; case ncf of 0, 14, 15 : Result := Result + '(#,##0' + decs + ')'; 1, 2, 5, 6, 8, 9, 12: Result := Result + '-#,##0' + decs; else Result := Result + '#,##0' + decs + '-'; end; Result := Result + ';0' + decs; end; end; {@@ ---------------------------------------------------------------------------- Builds a date/time format string from the number format code. @param ANumberFormat Built-in number format identifier @param AFormatSettings Format settings from which locale-dependent information like day-month-year order is taken. @param AFormatString Optional pre-built formatting string. It is used only for the format nfInterval where square brackets are added to the first time code field. @returns String of date/time formatting code constructed from the built-in format information. -------------------------------------------------------------------------------} function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; AFormatString: String = '') : string; var i, j: Integer; Unwanted: set of ansichar; begin case ANumberFormat of nfShortDateTime: Result := AFormatSettings.ShortDateFormat + ' ' + AFormatSettings.ShortTimeFormat; // In the DefaultFormatSettings this is: d/m/y hh:nn nfShortDate: Result := AFormatSettings.ShortDateFormat; // --> d/m/y nfLongDate: Result := AFormatSettings.LongDateFormat; // --> dd mm yyyy nfShortTime: Result := StripAMPM(AFormatSettings.ShortTimeFormat); // --> hh:nn nfLongTime: Result := StripAMPM(AFormatSettings.LongTimeFormat); // --> hh:nn:ss nfShortTimeAM: begin // --> hh:nn AM/PM Result := AFormatSettings.ShortTimeFormat; if (pos('a', lowercase(AFormatSettings.ShortTimeFormat)) = 0) then Result := AddAMPM(Result, AFormatSettings); end; nfLongTimeAM: // --> hh:nn:ss AM/PM begin Result := AFormatSettings.LongTimeFormat; if pos('a', lowercase(AFormatSettings.LongTimeFormat)) = 0 then Result := AddAMPM(Result, AFormatSettings); end; nfDayMonth, // --> dd/mmm nfMonthYear: // --> mmm/yy begin Result := AFormatSettings.ShortDateFormat; case ANumberFormat of nfDayMonth: unwanted := ['y', 'Y']; nfMonthYear: unwanted := ['d', 'D']; end; for i:=Length(Result) downto 1 do if Result[i] in unwanted then Delete(Result, i, 1); while not (Result[1] in (['m', 'M', 'd', 'D', 'y', 'Y'] - unwanted)) do Delete(Result, 1, 1); while not (Result[Length(Result)] in (['m', 'M', 'd', 'D', 'y', 'Y'] - unwanted)) do Delete(Result, Length(Result), 1); i := 1; while not (Result[i] in ['m', 'M']) do inc(i); j := i; while (j <= Length(Result)) and (Result[j] in ['m', 'M']) do inc(j); while (j - i < 3) do begin Insert(Result[i], Result, j); inc(j); end; end; nfTimeInterval: // --> [h]:nn:ss if AFormatString = '' then Result := '[h]:nn:ss' else Result := AddIntervalBrackets(AFormatString); end; end; {@@ ---------------------------------------------------------------------------- Builds a number format string for fraction formatting from the number format code and the count of numerator and denominator digits. @param AMixedFraction If @TRUE, fraction is presented as mixed fraction @param ANumeratorDigits Count of numerator digits @param ADenominatorDigits Count of denominator digits. If the value is negative then its absolute value is inserted literally as as denominator. @returns String of formatting code, here something like: '##/##' or '# ##/##' -------------------------------------------------------------------------------} function BuildFractionFormatString(AMixedFraction: Boolean; ANumeratorDigits, ADenominatorDigits: Integer): String; begin if ADenominatorDigits < 0 then // a negative value indicates a fixed denominator value Result := Format('%s/%d', [ DupeString('?', ANumeratorDigits), -ADenominatorDigits ]) else Result := Format('%s/%s', [ DupeString('?', ANumeratorDigits), DupeString('?', ADenominatorDigits) ]); if AMixedFraction then Result := '# ' + Result; end; {@@ ---------------------------------------------------------------------------- Builds a number format string from the number format code and the count of decimal places. Example: ANumberFormat = nfFixedTh, ADecimals = 2 --> '#,##0.00' @param ANumberFormat Identifier of the built-in numberformat for which a format string is to be generated @param AFormatSettings FormatSettings for default parameters @param ADecimals Number of decimal places. If < 0 the CurrencyDecimals value of the FormatSettings is used. In case of a fraction format "ADecimals" refers to the maximum count digits of the denominator. @param AMinIntDigits Minimum count of integer digits, i.e. count of '0' in the format string before the decimal separator @returns String of formatting codes -------------------------------------------------------------------------------} function BuildNumberFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; ADecimals: Integer = -1; AMinIntDigits: Integer = 1): String; var decdigits: String; intdigits: String; begin Result := ''; if AMinIntDigits > 0 then intdigits := DupeString('0', AMinIntDigits) else intdigits := '#'; if ADecimals = -1 then ADecimals := AFormatSettings.CurrencyDecimals; if ADecimals > 0 then decdigits := '.' + DupeString('0', ADecimals) else decdigits := ''; case ANumberFormat of nfText: Result := '@'; nfFixed: Result := intdigits + decdigits; nfFixedTh: begin while Length(IntDigits) < 4 do intDigits := '#' + intdigits; System.Insert(',', intdigits, Length(intdigits)-2); Result := intdigits + decdigits; end; nfExp: Result := intdigits + decdigits + 'E+00'; nfPercentage: Result := intdigits + decdigits + '%'; nfFraction: if ADecimals = 0 then // "ADecimals" has a different meaning here... Result := '# ??/??' // This is the default fraction format else begin decdigits := DupeString('?', ADecimals); Result := '# ' + decdigits + '/' + decdigits; end; nfCurrency, nfCurrencyRed: Result := BuildCurrencyFormatString(ANumberFormat, AFormatSettings, ADecimals, AFormatSettings.CurrencyFormat, AFormatSettings.NegCurrFormat, AFormatSettings.CurrencyString); nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfDayMonth, nfMonthYear, nfTimeInterval: raise EFPSpreadsheet.Create('BuildNumberFormatString: Use BuildDateTimeFormatSstring '+ 'to create a format string for date/time values.'); end; end; {@@ ---------------------------------------------------------------------------- Creates a format string for the specified parsed number format section. The format string is created according to Excel convention (which is understood by ODS as well). @param ASection Parsed section of number format elements as created by the number format parser @param AllowLocalizedAMPM Replaces "AMPM" in a time format string by "AM/PM". "AMPM" is allowed by FPS, but not by Excel. When converting a time to string it is replaced by the localized strings FormatSettings.TimeAMString/.TimePMString. @returns Excel-compatible format string -------------------------------------------------------------------------------} function BuildFormatStringFromSection(const ASection: TsNumFormatSection; AllowLocalizedAMPM: Boolean = true): String; var element: TsNumFormatElement; i, n: Integer; begin Result := ''; for i := 0 to High(ASection.Elements) do begin element := ASection.Elements[i]; case element.Token of nftGeneral: Result := Result + 'General'; nftIntOptDigit, nftOptDecs, nftFracNumOptDigit, nftFracDenomOptDigit: if element.IntValue > 0 then Result := Result + DupeString('#', element.IntValue); nftIntZeroDigit, nftZeroDecs, nftFracNumZeroDigit, nftFracDenomZeroDigit, nftExpDigits: if element.IntValue > 0 then Result := result + DupeString('0', element.IntValue); nftIntSpaceDigit, nftSpaceDecs, nftFracNumSpaceDigit, nftFracDenomSpaceDigit: if element.Intvalue > 0 then Result := result + DupeString('?', element.IntValue); nftFracDenom: Result := Result + IntToStr(element.IntValue); nftIntTh: case element.Intvalue of 0: Result := Result + '#,###'; 1: Result := Result + '#,##0'; 2: Result := Result + '#,#00'; 3: Result := Result + '#,000'; end; nftDecSep, nftThSep: Result := Result + element.TextValue; nftFracSymbol: Result := Result + '/'; nftPercent: Result := Result + '%'; nftFactor: if element.IntValue <> 0 then begin n := element.IntValue; while (n > 0) do begin Result := Result + element.TextValue; dec(n); end; end; nftSpace: Result := Result + ' '; nftText: if element.TextValue <> '' then result := Result + '"' + element.TextValue + '"'; nftYear: Result := Result + DupeString('y', element.IntValue); nftMonth: Result := Result + DupeString('m', element.IntValue); nftDay: Result := Result + DupeString('d', element.IntValue); nftHour: if element.IntValue < 0 then Result := Result + '[' + DupeString('h', -element.IntValue) + ']' else Result := Result + DupeString('h', element.IntValue); nftMinute: if element.IntValue < 0 then Result := result + '[' + DupeString('m', -element.IntValue) + ']' else Result := Result + DupeString('m', element.IntValue); nftSecond: if element.IntValue < 0 then Result := Result + '[' + DupeString('s', -element.IntValue) + ']' else Result := Result + DupeString('s', element.IntValue); nftMilliseconds: Result := Result + DupeString('0', element.IntValue); nftAMPM: if Lowercase(element.TextValue) = 'ampm' then Result := Result + 'AM/PM' else if element.TextValue <> '' then Result := Result + element.TextValue; nftSign, nftSignBracket, nftExpChar, nftExpSign, nftDateTimeSep: if element.TextValue <> '' then Result := Result + element.TextValue; nftCurrSymbol: if element.TextValue <> '' then Result := Result + '[$' + element.TextValue + ']'; nftEscaped: if element.TextValue <> '' then Result := Result + '\' + element.TextValue; nftRepeat: if element.TextValue <> '' then Result := Result + '*' + element.TextValue; nftColor: case element.IntValue of scBlack : Result := '[black]'; scWhite : Result := '[white]'; scRed : Result := '[red]'; scBlue : Result := '[blue]'; scGreen : Result := '[green]'; scYellow : Result := '[yellow]'; scMagenta: Result := '[magenta]'; scCyan : Result := '[cyan]'; else Result := Format('[Color%d]', [element.IntValue]); end; nftTextFormat: Result := '@'; end; end; end; {@@ ---------------------------------------------------------------------------- Counts how many decimal places are coded into a given number format string. @param AFormatString String with number format codes, such as '0.000' @param ADecChars Characters which are considered as symbols for decimals. For the fixed decimals, this is the '0'. Optional decimals are encoced as '#'. @returns Count of decimal places found -------------------------------------------------------------------------------} function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte; var i: Integer; begin Result := 0; i := 1; while (i <= Length(AFormatString)) do begin if AFormatString[i] = '.' then begin inc(i); while (i <= Length(AFormatString)) and (AFormatString[i] in ADecChars) do begin inc(i); inc(Result); end; exit; end else inc(i); end; end; {@@ ---------------------------------------------------------------------------- Applies a text format to a text. The text placeholder is @. Supports appending and prepending text. -------------------------------------------------------------------------------} function ApplyTextFormat(AText: String; AParams: TsNumFormatParams): String; var sct: TsNumFormatSection; element: TsNumFormatElement; i: Integer; begin Result := ''; for sct in AParams.Sections do for i := 0 to High(sct.Elements) do begin element := sct.Elements[i]; case element.Token of nftTextFormat: Result := Result + AText; nftText: Result := Result + element.TextValue; end; end; end; {@@ ---------------------------------------------------------------------------- Checks whether the specified text corresponds to a boolean value. For this, it must match the specified @TRUE and @FALSE text phrases. -------------------------------------------------------------------------------} function IsBoolValue(const AText, ATrueText, AFalseText: String; out AValue: Boolean): Boolean; begin if SameText(AText, ATrueText) then begin AValue := true; Result := true; end else if SameText(AText, AFalseText) then begin AValue := false; Result := true; end else Result := false; end; {@@ ---------------------------------------------------------------------------- Checks whether the given number format code is for currency, i.e. requires a currency symbol. @param AFormat Built-in number format identifier to be checked @returns @True if AFormat is nfCurrency or nfCurrencyRed, @false otherwise. -------------------------------------------------------------------------------} function IsCurrencyFormat(AFormat: TsNumberFormat): Boolean; begin Result := AFormat in [nfCurrency, nfCurrencyRed]; end; {@@ ---------------------------------------------------------------------------- Checks whether the specified number format parameters apply to currency values. @param ANumFormat Number format parameters @returns @True if Kind of the 1st format parameter section contains the nfkCurrency elements; @false otherwise -------------------------------------------------------------------------------} function IsCurrencyFormat(ANumFormat: TsNumFormatParams): Boolean; begin Result := (ANumFormat <> nil) and (ANumFormat.Sections[0].Kind * [nfkCurrency] <> []); end; {@@ ---------------------------------------------------------------------------- Checks whether the given number format code is for date/time values. @param AFormat Built-in number format identifier to be checked @returns @True if AFormat is a date/time format (such as nfShortTime), @false otherwise -------------------------------------------------------------------------------} function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean; begin Result := AFormat in [nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfDayMonth, nfMonthYear, nfTimeInterval]; end; {@@ ---------------------------------------------------------------------------- Checks whether the given string with formatting codes is for date/time values. @param AFormatStr String with formatting codes to be checked. @returns @True if AFormatStr is a date/time format string (such as 'hh:nn'), @false otherwise -------------------------------------------------------------------------------} function IsDateTimeFormat(AFormatStr: string): Boolean; var parser: TsNumFormatParser; begin parser := TsNumFormatParser.Create(AFormatStr, DefaultFormatSettings); try Result := parser.IsDateTimeFormat; finally parser.Free; end; end; {@@ ---------------------------------------------------------------------------- Checks whether the specified number format parameters apply to date/time values. @param ANumFormat Number format parameters @returns @True if Kind of the 1st format parameter section contains the nfkDate or nfkTime elements; @false otherwise -------------------------------------------------------------------------------} function IsDateTimeFormat(ANumFormat: TsNumFormatParams): Boolean; begin Result := (ANumFormat <> nil) and (ANumFormat.Sections[0].Kind * [nfkDate, nfkTime] <> []); end; {@@ ---------------------------------------------------------------------------- Checks whether the specified text corresponds to a date/time value and returns @true, its numerical value and its built-in numberformat if it is. -------------------------------------------------------------------------------} function IsDateTimeValue(AText: String; const AFormatSettings: TFormatSettings; out ADateTime: TDateTime; out ANumFormat: TsNumberFormat): Boolean; { Test whether the text is formatted according to a built-in date/time format. Converts the obtained date/time value back to a string and compares. } function TestFormat(lNumFmt: TsNumberFormat): Boolean; var fmt: string; begin fmt := BuildDateTimeFormatString(lNumFmt, AFormatSettings); Result := FormatDateTime(fmt, ADateTime, AFormatSettings) = AText; if Result then ANumFormat := lNumFmt; end; begin Result := TryStrToDateTime(AText, ADateTime, AFormatSettings); if Result then begin ANumFormat := nfCustom; if abs(ADateTime) > 1 then // this is most probably a date begin if TestFormat(nfShortDateTime) then exit; if TestFormat(nfLongDate) then exit; if TestFormat(nfShortDate) then exit; if TestFormat(nfMonthYear) then exit; if TestFormat(nfDayMonth) then exit; end else begin // this case is time-only if TestFormat(nfLongTimeAM) then exit; if TestFormat(nfLongTime) then exit; if TestFormat(nfShortTimeAM) then exit; if TestFormat(nfShortTime) then exit; end; end; end; {@@ ---------------------------------------------------------------------------- Checks whether the specified number format parameters apply to a date value. @param ANumFormat Number format parameters @returns @True if Kind of the 1st format parameter section contains the nfkDate, but no nfkTime tags; @false otherwise -------------------------------------------------------------------------------} function IsDateFormat(ANumFormat: TsNumFormatParams): Boolean; begin Result := (ANumFormat <> nil) and (ANumFormat.Sections[0].Kind * [nfkDate, nfkTime] = [nfkDate]); end; {@@ ---------------------------------------------------------------------------- Checks whether the given built-in number format code is for time values. @param AFormat Built-in number format identifier to be checked @returns @True if AFormat represents to a time-format, @false otherwise -------------------------------------------------------------------------------} function IsTimeFormat(AFormat: TsNumberFormat): boolean; begin Result := AFormat in [nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfTimeInterval]; end; {@@ ---------------------------------------------------------------------------- Checks whether the given string with formatting codes is for time values. @param AFormatStr String with formatting codes to be checked @return True if AFormatStr represents a time-format, false otherwise -------------------------------------------------------------------------------} function IsTimeFormat(AFormatStr: String): Boolean; var parser: TsNumFormatParser; begin parser := TsNumFormatParser.Create(AFormatStr, DefaultFormatSettings); try Result := parser.IsTimeFormat; finally parser.Free; end; end; {@@ ---------------------------------------------------------------------------- Checks whether the specified number format parameters apply to time values. @param ANumFormat Number format parameters @returns @True if Kind of the 1st format parameter section contains the nfkTime, but no nfkDate elements; @false otherwise -------------------------------------------------------------------------------} function IsTimeFormat(ANumFormat: TsNumFormatParams): Boolean; begin Result := (ANumFormat <> nil) and (ANumFormat.Sections[0].Kind * [nfkTime, nfkDate] = [nfkTime]); end; {@@ ---------------------------------------------------------------------------- Returns @TRUE if the specified format string represents a long time format, i.e. it contains two TimeSeparators. -------------------------------------------------------------------------------} function IsLongTimeFormat(AFormatStr: String; ATimeSeparator: Char): Boolean; var i, n: Integer; begin n := 0; for i:=1 to Length(AFormatStr) do if AFormatStr[i] = ATimeSeparator then inc(n); Result := (n=2); end; {@@ ---------------------------------------------------------------------------- Checks whether the specified text corresponds to a numerical value. If it is then the function result is @TRUE, and the number value and its formatting parameters are returned. -------------------------------------------------------------------------------} function IsNumberValue(AText: String; AutoDetectNumberFormat: Boolean; const AFormatSettings: TFormatSettings; out ANumber: Double; out ANumFormat: TsNumberFormat; out ADecimals: Integer; out ACurrencySymbol, AWarning: String): Boolean; var p: Integer; DecSep, ThousSep: Char; begin Result := false; AWarning := ''; // To detect whether the text is a currency value we look for the currency // string. If we find it, we delete it and convert the remaining string to // a number. ACurrencySymbol := AFormatSettings.CurrencyString; if RemoveCurrencySymbol(ACurrencySymbol, AText) then begin if IsNegative(AText) then begin if AText = '' then exit; AText := '-' + AText; end; end else ACurrencySymbol := ''; if AutoDetectNumberFormat then Result := TryStrToFloatAuto(AText, ANumber, DecSep, ThousSep, AWarning) else begin Result := TryStrToFloat(AText, ANumber, AFormatSettings); if Result then begin if pos(AFormatSettings.DecimalSeparator, AText) = 0 then DecSep := #0 else DecSep := AFormatSettings.DecimalSeparator; if pos(AFormatSettings.ThousandSeparator, AText) = 0 then ThousSep := #0 else ThousSep := AFormatSettings.ThousandSeparator; end; end; // Try to determine the number format if Result then begin if ThousSep <> #0 then ANumFormat := nfFixedTh else ANumFormat := nfGeneral; // count number of decimal places and try to catch special formats ADecimals := 0; if DecSep <> #0 then begin // Go to the decimal separator and search towards the end of the string p := pos(DecSep, AText) + 1; while (p <= Length(AText)) do begin // exponential format if AText[p] in ['+', '-', 'E', 'e'] then begin ANumFormat := nfExp; break; end else // percent format if AText[p] = '%' then begin ANumFormat := nfPercentage; break; end else begin inc(p); inc(ADecimals); end; end; if (ADecimals > 0) and (ADecimals < 9) and (ANumFormat = nfGeneral) then // "no formatting" assumed if there are "many" decimals ANumFormat := nfFixed; end else begin p := Length(AText); while (p > 0) do begin case AText[p] of '%' : ANumFormat := nfPercentage; 'e', 'E': ANumFormat := nfExp; else dec(p); end; break; end; end; end else ACurrencySymbol := ''; end; {@@ ---------------------------------------------------------------------------- Checks whether the specified number format parameters is a time interval format. @param ANumFormat Number format parameters @returns @True if Kind of the 1st format parameter section contains the nfkTimeInterval elements; @false otherwise -------------------------------------------------------------------------------} function IsTimeIntervalFormat(ANumFormat: TsNumFormatParams): Boolean; begin Result := (ANumFormat <> nil) and (ANumFormat.Sections[0].Kind * [nfkTimeInterval] <> []); end; function IsTextFormat(ANumFormat: TsNumFormatParams): Boolean; begin Result := (ANumFormat <> nil) and (ANumFormat.Sections[0].Kind = [nfkText]); end; {@@ ---------------------------------------------------------------------------- Creates a long date format string out of a short date format string. Retains the order of year-month-day and the separators, but uses 4 digits for year and 3 digits of month. @param ADateFormat String with date formatting code representing a "short" date, such as 'dd/mm/yy' @returns Format string modified to represent a "long" date, such as 'dd/mmm/yyyy' -------------------------------------------------------------------------------} function MakeLongDateFormat(ADateFormat: String): String; var i: Integer; begin Result := ''; i := 1; while i < Length(ADateFormat) do begin case ADateFormat[i] of 'y', 'Y': begin Result := Result + DupeString(ADateFormat[i], 4); while (i < Length(ADateFormat)) and (ADateFormat[i] in ['y','Y']) do inc(i); end; 'm', 'M': begin result := Result + DupeString(ADateFormat[i], 3); while (i < Length(ADateFormat)) and (ADateFormat[i] in ['m','M']) do inc(i); end; else Result := Result + ADateFormat[i]; inc(i); end; end; end; {@@ ---------------------------------------------------------------------------- Modifies the short date format such that it has a two-digit year and a two-digit month. Retains the order of year-month-day and the separators. @param ADateFormat String with date formatting codes representing a "long" date, such as 'dd/mmm/yyyy' @returns Format string modified to represent a "short" date, such as 'dd/mm/yy' -------------------------------------------------------------------------------} function MakeShortDateFormat(ADateFormat: String): String; var i: Integer; begin Result := ''; i := 1; while i < Length(ADateFormat) do begin case ADateFormat[i] of 'y', 'Y': begin Result := Result + DupeString(ADateFormat[i], 2); while (i < Length(ADateFormat)) and (ADateFormat[i] in ['y','Y']) do inc(i); end; 'm', 'M': begin result := Result + DupeString(ADateFormat[i], 2); while (i < Length(ADateFormat)) and (ADateFormat[i] in ['m','M']) do inc(i); end; else Result := Result + ADateFormat[i]; inc(i); end; end; end; {@@ ---------------------------------------------------------------------------- Creates a "time interval" format string having the first time code identifier in square brackets. @param Src Source format string, must be a time format string, like 'hh:nn' @param Dest Destination format string, will have the first time code element of the src format string in square brackets, like '[hh]:nn'. -------------------------------------------------------------------------------} procedure MakeTimeIntervalMask(Src: String; var Dest: String); var L: TStrings; begin L := TStringList.Create; try L.StrictDelimiter := true; L.Delimiter := ':'; L.DelimitedText := Src; if L[0][1] <> '[' then L[0] := '[' + L[0]; if L[0][Length(L[0])] <> ']' then L[0] := L[0] + ']'; Dest := L.DelimitedText; finally L.Free; end; end; {@@ ---------------------------------------------------------------------------- Removes an AM/PM formatting code from a given time formatting string. Variants of "AM/PM" are considered as well. The string is left unchanged if it does not contain AM/PM codes. @param ATimeFormatString String of time formatting codes (such as 'hh:nn AM/PM') @returns Formatting string with AM/PM being removed (--> 'hh:nn') -------------------------------------------------------------------------------} function StripAMPM(const ATimeFormatString: String): String; var i: Integer; begin Result := ''; i := 1; while i <= Length(ATimeFormatString) do begin if ATimeFormatString[i] in ['a', 'A'] then begin inc(i); while (i <= Length(ATimeFormatString)) and (ATimeFormatString[i] in ['p', 'P', 'm', 'M', '/']) do inc(i); end else Result := Result + ATimeFormatString[i]; inc(i); end; end; {@@ ---------------------------------------------------------------------------- Initializes the FormatSettings of file a import/export parameters record to default values which can be replaced by the FormatSettings of the workbook's FormatSettings -------------------------------------------------------------------------------} procedure InitFormatSettings(out AFormatSettings: TFormatSettings); var i: Integer; begin with AFormatSettings do begin CurrencyFormat := Byte(-1); NegCurrFormat := Byte(-1); ThousandSeparator := #0; DecimalSeparator := #0; CurrencyDecimals := Byte(-1); DateSeparator := #0; TimeSeparator := #0; ListSeparator := #0; CurrencyString := ''; ShortDateFormat := ''; LongDateFormat := ''; TimeAMString := ''; TimePMString := ''; ShortTimeFormat := ''; LongTimeFormat := ''; for i:=1 to 12 do begin ShortMonthNames[i] := ''; LongMonthNames[i] := ''; end; for i:=1 to 7 do begin ShortDayNames[i] := ''; LongDayNames[i] := ''; end; TwoDigitYearCenturyWindow := Word(-1); end; end; {@@ ---------------------------------------------------------------------------- Replaces in AFormatSettings all members marked as having default values (#0, -1, '') by the corresponding values of the ADefaultFormats record -------------------------------------------------------------------------------} procedure ReplaceFormatSettings(var AFormatSettings: TFormatSettings; const ADefaultFormats: TFormatSettings); var i: Integer; begin if AFormatSettings.CurrencyFormat = Byte(-1) then AFormatSettings.CurrencyFormat := ADefaultFormats.CurrencyFormat; if AFormatSettings.NegCurrFormat = Byte(-1) then AFormatSettings.NegCurrFormat := ADefaultFormats.NegCurrFormat; if AFormatSettings.ThousandSeparator = #0 then AFormatSettings.ThousandSeparator := ADefaultFormats.ThousandSeparator; if AFormatSettings.DecimalSeparator = #0 then AFormatSettings.DecimalSeparator := ADefaultFormats.DecimalSeparator; if AFormatSettings.CurrencyDecimals = Byte(-1) then AFormatSettings.CurrencyDecimals := ADefaultFormats.CurrencyDecimals; if AFormatSettings.DateSeparator = #0 then AFormatSettings.DateSeparator := ADefaultFormats.DateSeparator; if AFormatSettings.TimeSeparator = #0 then AFormatSettings.TimeSeparator := ADefaultFormats.TimeSeparator; if AFormatSettings.ListSeparator = #0 then AFormatSettings.ListSeparator := ADefaultFormats.ListSeparator; if AFormatSettings.CurrencyString = '' then AFormatSettings.CurrencyString := ADefaultFormats.CurrencyString; if AFormatSettings.ShortDateFormat = '' then AFormatSettings.ShortDateFormat := ADefaultFormats.ShortDateFormat; if AFormatSettings.LongDateFormat = '' then AFormatSettings.LongDateFormat := ADefaultFormats.LongDateFormat; if AFormatSettings.ShortTimeFormat = '' then AFormatSettings.ShortTimeFormat := ADefaultFormats.ShortTimeFormat; if AFormatSettings.LongTimeFormat = '' then AFormatSettings.LongTimeFormat := ADefaultFormats.LongTimeFormat; for i:=1 to 12 do begin if AFormatSettings.ShortMonthNames[i] = '' then AFormatSettings.ShortMonthNames[i] := ADefaultFormats.ShortMonthNames[i]; if AFormatSettings.LongMonthNames[i] = '' then AFormatSettings.LongMonthNames[i] := ADefaultFormats.LongMonthNames[i]; end; for i:=1 to 7 do begin if AFormatSettings.ShortDayNames[i] = '' then AFormatSettings.ShortDayNames[i] := ADefaultFormats.ShortDayNames[i]; if AFormatSettings.LongDayNames[i] = '' then AFormatSettings.LongDayNames[i] := ADefaultFormats.LongDayNames[i]; end; if AFormatSettings.TwoDigitYearCenturyWindow = Word(-1) then AFormatSettings.TwoDigitYearCenturyWindow := ADefaultFormats.TwoDigitYearCenturyWindow; end; function CreateNumFormatParams(ANumFormatStr: String; const AFormatSettings: TFormatSettings): TsNumFormatParams; begin Result := TsNumFormatParams.Create; ParamsOfNumFormatStr(ANumFormatStr, AFormatSettings, result); end; function ParamsOfNumFormatStr(ANumFormatStr: String; const AFormatSettings: TFormatSettings; var AResult: TsNumFormatParams): Integer; var parser: TsNumFormatParser; begin Assert(AResult <> nil); if ANumFormatstr = 'General' then ANumFormatStr := ''; parser := TsNumFormatParser.Create(ANumFormatStr, AFormatSettings); try Result := parser.Status; AResult.Sections := parser.FSections; finally parser.Free; end; end; {==============================================================================} { TsNumFormatParams } {==============================================================================} constructor TsNumFormatParams.Create; begin inherited; FAllowLocalizedAMPM := true; end; {@@ ---------------------------------------------------------------------------- Deletes a parsed number format element from the specified format section. @param ASectionIndex Index of the format section containing the element to be deleted @param AElementIndex Index of the format element to be deleted -------------------------------------------------------------------------------} procedure TsNumFormatParams.DeleteElement(ASectionIndex, AElementIndex: Integer); var i, n: Integer; begin with Sections[ASectionIndex] do begin n := Length(Elements); for i := AElementIndex+1 to n-1 do Elements[i-1] := Elements[i]; SetLength(Elements, n-1); end; end; {@@ ---------------------------------------------------------------------------- Creates the built-in number format identifier from the parsed number format sections and elements @returns Built-in number format identifer if the format is built into fpspreadsheet, or nfCustom otherwise @seeAlso TsNumberFormat -------------------------------------------------------------------------------} function TsNumFormatParams.GetNumFormat: TsNumberFormat; begin Result := nfCustom; case Length(Sections) of 0: Result := nfGeneral; 1: Result := Sections[0].NumFormat; 2: if (Sections[0].NumFormat = Sections[1].NumFormat) and (Sections[0].NumFormat in [nfCurrency, nfCurrencyRed]) then Result := Sections[0].NumFormat; 3: if (Sections[0].NumFormat = Sections[1].NumFormat) and (Sections[1].NumFormat = Sections[2].NumFormat) and (Sections[0].NumFormat in [nfCurrency, nfCurrencyRed]) then Result := Sections[0].NumFormat; end; end; {@@ ---------------------------------------------------------------------------- Constructs the number format string from the parsed sections and elements. The format symbols are selected according to Excel syntax. @returns Excel-compatible number format string. -------------------------------------------------------------------------------} function TsNumFormatParams.GetNumFormatStr: String; var i: Integer; begin if Length(Sections) > 0 then begin Result := BuildFormatStringFromSection(Sections[0]); for i := 1 to High(Sections) do Result := Result + ';' + BuildFormatStringFromSection(Sections[i], FAllowLocalizedAMPM); end else Result := ''; end; {@@ ---------------------------------------------------------------------------- Inserts a parsed format token into the specified format section before the specified element. @param ASectionIndex Index of the parsed format section into which the token is to be inserted @param AElementIndex Index of the format element before which the token is to be inserted @param AToken Parsed format token to be inserted @seeAlso TsNumFormatToken -------------------------------------------------------------------------------} procedure TsNumFormatParams.InsertElement(ASectionIndex, AElementIndex: Integer; AToken: TsNumFormatToken); var i, n: Integer; begin with Sections[ASectionIndex] do begin n := Length(Elements); SetLength(Elements, n+1); for i:=n-1 downto AElementIndex do Elements[i+1] := Elements[i]; Elements[AElementIndex].Token := AToken; end; end; {@@ ---------------------------------------------------------------------------- Checks whether the parsed format sections passed as a parameter are identical to the interal section array. @param ASections Array of parsed format sections to be compared with the internal format sections -------------------------------------------------------------------------------} function TsNumFormatParams.SectionsEqualTo(ASections: TsNumFormatSections): Boolean; var i, j: Integer; begin Result := false; if Length(ASections) <> Length(Sections) then exit; for i := 0 to High(Sections) do begin if Length(Sections[i].Elements) <> Length(ASections[i].Elements) then exit; for j:=0 to High(Sections[i].Elements) do begin if Sections[i].Elements[j].Token <> ASections[i].Elements[j].Token then exit; if Sections[i].NumFormat <> ASections[i].NumFormat then exit; if Sections[i].Decimals <> ASections[i].Decimals then exit; { if Sections[i].Factor <> ASections[i].Factor then exit; } if Sections[i].FracInt <> ASections[i].FracInt then exit; if Sections[i].FracNumerator <> ASections[i].FracNumerator then exit; if Sections[i].FracDenominator <> ASections[i].FracDenominator then exit; if Sections[i].CurrencySymbol <> ASections[i].CurrencySymbol then exit; if Sections[i].Color <> ASections[i].Color then exit; case Sections[i].Elements[j].Token of nftText, nftThSep, nftDecSep, nftDateTimeSep, nftAMPM, nftSign, nftSignBracket, nftExpChar, nftExpSign, nftPercent, nftFracSymbol, nftCurrSymbol, nftCountry, nftSpace, nftEscaped, nftRepeat, nftEmptyCharWidth, nftTextFormat: if Sections[i].Elements[j].TextValue <> ASections[i].Elements[j].TextValue then exit; nftYear, nftMonth, nftDay, nftHour, nftMinute, nftSecond, nftMilliseconds, nftMonthMinute, nftIntOptDigit, nftIntZeroDigit, nftIntSpaceDigit, nftIntTh, nftZeroDecs, nftOptDecs, nftSpaceDecs, nftExpDigits, nftFactor, nftFracNumOptDigit, nftFracNumSpaceDigit, nftFracNumZeroDigit, nftFracDenomOptDigit, nftFracDenomSpaceDigit, nftFracDenomZeroDigit, nftColor: if Sections[i].Elements[j].IntValue <> ASections[i].Elements[j].IntValue then exit; nftCompareOp, nftCompareValue: if Sections[i].Elements[j].FloatValue <> ASections[i].Elements[j].FloatValue then exit; end; end; end; Result := true; end; {@@ ---------------------------------------------------------------------------- Defines the currency symbol used in the format params sequence @param AValue String containing the currency symbol to be used in the converted numbers -------------------------------------------------------------------------------} procedure TsNumFormatParams.SetCurrSymbol(AValue: String); var section: TsNumFormatSection; s, el: Integer; begin for s:=0 to High(Sections) do begin section := Sections[s]; if (nfkCurrency in section.Kind) then begin section.CurrencySymbol := AValue; for el := 0 to High(section.Elements) do if section.Elements[el].Token = nftCurrSymbol then section.Elements[el].Textvalue := AValue; end; end; end; {@@ ---------------------------------------------------------------------------- Adds or modifies parsed format tokens such that the specified number of decimal places is displayed @param AValue Number of decimal places to be shown -------------------------------------------------------------------------------} procedure TsNumFormatParams.SetDecimals(AValue: byte); var section: TsNumFormatSection; s, el: Integer; begin for s := 0 to High(Sections) do begin section := Sections[s]; if section.Kind * [nfkFraction, nfkDate, nfkTime] <> [] then Continue; section.Decimals := AValue; for el := High(section.Elements) downto 0 do case section.Elements[el].Token of nftZeroDecs: section.Elements[el].Intvalue := AValue; nftOptDecs, nftSpaceDecs: DeleteElement(s, el); end; end; end; {@@ ---------------------------------------------------------------------------- If AEnable is true a format section for negative numbers is added (or an existing one is modified) such that negative numbers are displayed in red. If AEnable is false the format tokens are modified such that negative values are displayed in default color. @param AEnable The format tokens are modified such as to display negative values in red if AEnable is true. -------------------------------------------------------------------------------} procedure TsNumFormatParams.SetNegativeRed(AEnable: Boolean); var el: Integer; begin // Enable negative-value color if AEnable then begin if Length(Sections) = 1 then begin SetLength(Sections, 2); Sections[1] := Sections[0]; InsertElement(1, 0, nftColor); Sections[1].Elements[0].Intvalue := scRed; InsertElement(1, 1, nftSign); Sections[1].Elements[1].TextValue := '-'; end else begin if not (nfkHasColor in Sections[1].Kind) then InsertElement(1, 0, nftColor); for el := 0 to High(Sections[1].Elements) do if Sections[1].Elements[el].Token = nftColor then Sections[1].Elements[el].IntValue := scRed; end; Sections[1].Kind := Sections[1].Kind + [nfkHasColor]; Sections[1].Color := scRed; end else // Disable negative-value color if Length(Sections) >= 2 then begin Sections[1].Kind := Sections[1].Kind - [nfkHasColor]; Sections[1].Color := scBlack; for el := High(Sections[1].Elements) downto 0 do if Sections[1].Elements[el].Token = nftColor then DeleteElement(1, el); end; end; {@@ ---------------------------------------------------------------------------- Inserts a thousand separator token into the format elements at the appropriate position, or removes it @param AEnable A thousand separator is inserted if AEnable is @true, or else deleted. -------------------------------------------------------------------------------} procedure TsNumFormatParams.SetThousandSep(AEnable: Boolean); var section: TsNumFormatSection; s, el: Integer; replaced: Boolean; begin for s := 0 to High(Sections) do begin section := Sections[s]; replaced := false; for el := High(section.Elements) downto 0 do begin if AEnable then begin if section.Elements[el].Token in [nftIntOptDigit, nftIntSpaceDigit, nftIntZeroDigit] then begin if replaced then DeleteElement(s, el) else begin section.Elements[el].Token := nftIntTh; Include(section.Kind, nfkHasThSep); replaced := true; end; end; end else begin if section.Elements[el].Token = nftIntTh then begin section.Elements[el].Token := nftIntZeroDigit; Exclude(section.Kind, nfkHasThSep); break; end; end; end; end; end; {==============================================================================} { TsNumFormatList } {==============================================================================} {@@ ---------------------------------------------------------------------------- Constructor of the number format list class. @param AFormatSettings Format settings needed internally by the number format parser (currency symbol, etc.) @param AOwnsData If @true then the list is responsible to destroy the list items -------------------------------------------------------------------------------} constructor TsNumFormatList.Create(AFormatSettings: TFormatSettings; AOwnsData: Boolean); begin inherited Create; FClass := TsNumFormatParams; FFormatSettings := AFormatSettings; FOwnsData := AOwnsData; end; {@@ ---------------------------------------------------------------------------- Destructor of the number format list class. Clears the list items if the list "owns" the data. -------------------------------------------------------------------------------} destructor TsNumFormatList.Destroy; begin Clear; inherited; end; {@@ ---------------------------------------------------------------------------- Adds the specified sections of a parsed number format to the list. Duplicates are not checked before adding the format item. @param ASections Array of number format sections as obtained by the number format parser for a given format string @returns Index of the format item in the list. -------------------------------------------------------------------------------} function TsNumFormatList.AddFormat(ASections: TsNumFormatSections): Integer; var nfp: TsNumFormatParams; begin Result := Find(ASections); if Result = -1 then begin nfp := FClass.Create; nfp.Sections := ASections; Result := inherited Add(nfp); end; end; {@@ ---------------------------------------------------------------------------- Adds a number format as specified by a format string to the list Uses the number format parser to convert the format string to format sections and elements. Duplicates are not checked before adding the format item. @param AFormatStr Excel-like format string describing the format to be added @returns Index of the format item in the list -------------------------------------------------------------------------------} function TsNumFormatList.AddFormat(AFormatStr: String): Integer; var parser: TsNumFormatParser; newSections: TsNumFormatSections = nil; i: Integer; begin parser := TsNumFormatParser.Create(AFormatStr, FFormatSettings); try SetLength(newSections, parser.ParsedSectionCount); for i:=0 to High(newSections) do newSections[i] := parser.ParsedSections[i]; Result := AddFormat(newSections); finally parser.Free; end; end; {@@ ---------------------------------------------------------------------------- Adds the number formats to the list which are built into the file format. Does nothing here. Must be overridden by derived classes for each file format. -------------------------------------------------------------------------------} procedure TsNumFormatList.AddBuiltinFormats; begin end; {@@ ---------------------------------------------------------------------------- Clears the list. If the list "owns" the format items they are destroyed. @seeAlso TsNumFormatList.Create -------------------------------------------------------------------------------} procedure TsNumFormatList.Clear; var i: Integer; begin for i := Count-1 downto 0 do Delete(i); inherited; end; {@@ ---------------------------------------------------------------------------- Deletes the number format item having the specified index in the list. If the list "owns" the format items, the item is destroyed. @param AIndex Index of the format item to be deleted @seeAlso TsNumformatList.Create -------------------------------------------------------------------------------} procedure TsNumFormatList.Delete(AIndex: Integer); var p: TsNumFormatParams; begin if FOwnsData then begin p := GetItem(AIndex); if p <> nil then p.Free; end; inherited Delete(AIndex); end; {@@ ---------------------------------------------------------------------------- Checks whether a parsed format item having the specified format sections is contained in the list and returns its index if found, or -1 if not found. @param ASections Array of number format sections as obtained by the number format parser for a given format string @returns Index of the found format item, or -1 if not found -------------------------------------------------------------------------------} function TsNumFormatList.Find(ASections: TsNumFormatSections): Integer; var nfp: TsNumFormatParams; begin for Result := 0 to Count-1 do begin nfp := GetItem(Result); if nfp.SectionsEqualTo(ASections) then exit; end; Result := -1; end; {@@ ---------------------------------------------------------------------------- Checks whether a format item corresponding to the specified format string is contained in the list and returns its index if found, or -1 if not. Should be called before adding a format to the list to avoid duplicates. @param AFormatStr Number format string of the format item which is seeked @returns Index of the found format item, or -1 if not found @seeAlso TsNumFormatList.AddFormat -------------------------------------------------------------------------------} function TsNumFormatList.Find(AFormatStr: String): Integer; var nfp: TsNumFormatParams; begin nfp := CreateNumFormatParams(AFormatStr, FFormatSettings); if nfp = nil then Result := -1 else Result := Find(nfp.Sections); end; {@@ ---------------------------------------------------------------------------- Getter function returning the correct type of the list items (i.e., @link(TsNumFormatParams) which are parsed format descriptions). @param AIndex Index of the format item @returns Pointer to the list item at the specified index, cast to the type @link(TsNumFormatParams) -------------------------------------------------------------------------------} function TsNumFormatList.GetItem(AIndex: Integer): TsNumFormatParams; begin Result := TsNumFormatParams(inherited Items[AIndex]); end; {@@ ---------------------------------------------------------------------------- Setter function for the list items @param AIndex Index of the format item @param AValue Pointer to the parsed format description to be stored in the list at the specified index. -------------------------------------------------------------------------------} procedure TsNumFormatList.SetItem(AIndex: Integer; const AValue: TsNumFormatParams); begin inherited Items[AIndex] := AValue; end; {==============================================================================} { TsNumFormatParser } {==============================================================================} {@@ ---------------------------------------------------------------------------- Creates a number format parser for analyzing a formatstring that has been read from a spreadsheet file. If ALocalized is true then the formatstring contains localized decimal separator etc. -------------------------------------------------------------------------------} constructor TsNumFormatParser.Create(const AFormatString: String; const AFormatSettings: TFormatSettings); begin inherited Create; FFormatSettings := AFormatSettings; Parse(AFormatString); CheckSections; if AFormatString = '' then FSections[0].NumFormat := nfGeneral; end; destructor TsNumFormatParser.Destroy; begin FSections := nil; inherited Destroy; end; procedure TsNumFormatParser.AddElement(AToken: TsNumFormatToken; AText: String); var n: Integer; begin n := Length(FSections[FCurrSection].Elements); SetLength(FSections[FCurrSection].Elements, n+1); FSections[FCurrSection].Elements[n].Token := AToken; FSections[FCurrSection].Elements[n].TextValue := AText; end; procedure TsNumFormatParser.AddElement(AToken: TsNumFormatToken; AIntValue: Integer=0; AText: String = ''); var n: Integer; begin n := Length(FSections[FCurrSection].Elements); SetLength(FSections[FCurrSection].Elements, n+1); FSections[FCurrSection].Elements[n].Token := AToken; FSections[FCurrSection].Elements[n].IntValue := AIntValue; FSections[FCurrSection].Elements[n].TextValue := AText; end; procedure TsNumFormatParser.AddElement(AToken: TsNumFormatToken; AFloatValue: Double); overload; var n: Integer; begin n := Length(FSections[FCurrSection].Elements); SetLength(FSections[FCurrSection].Elements, n+1); FSections[FCurrSection].Elements[n].Token := AToken; FSections[FCurrSection].Elements[n].FloatValue := AFloatValue; end; procedure TsNumFormatParser.AddSection; begin FCurrSection := Length(FSections); SetLength(FSections, FCurrSection + 1); with FSections[FCurrSection] do SetLength(Elements, 0); end; procedure TsNumFormatParser.AnalyzeColor(AValue: String); var n: Integer; begin AValue := lowercase(AValue); // Colors if AValue = 'red' then AddElement(nftColor, ord(scRed)) else if AValue = 'black' then AddElement(nftColor, ord(scBlack)) else if AValue = 'blue' then AddElement(nftColor, ord(scBlue)) else if AValue = 'white' then AddElement(nftColor, ord(scWhite)) else if AValue = 'green' then AddElement(nftColor, ord(scGreen)) else if AValue = 'cyan' then AddElement(nftColor, ord(scCyan)) else if AValue = 'magenta' then AddElement(nftColor, ord(scMagenta)) else if copy(AValue, 1, 5) = 'color' then begin AValue := copy(AValue, 6, Length(AValue)); if not TryStrToInt(trim(AValue), n) then begin FStatus := psErrNoValidColorIndex; exit; end; AddElement(nftColor, n); end else FStatus := psErrUnknownInfoInBrackets; end; function TsNumFormatParser.AnalyzeCurrency(const AValue: String): Boolean; begin if (FFormatSettings.CurrencyString = '') then Result := false else Result := CurrencyRegistered(AValue); end; {@@ Creates a formatstring for all sections. @Note This implementation is only valid for the fpc and Excel dialects of format string. } function TsNumFormatParser.BuildFormatString: String; var i: Integer; begin if Length(FSections) > 0 then begin Result := BuildFormatStringFromSection(FSections[0]); for i:=1 to High(FSections) do Result := Result + ';' + BuildFormatStringFromSection(FSections[i]); end; end; procedure TsNumFormatParser.CheckSections; var i: Integer; begin for i:=0 to High(FSections) do CheckSection(i); if (Length(FSections) > 1) and (FSections[1].NumFormat = nfCurrencyRed) then for i:=0 to High(FSections) do if FSections[i].NumFormat = nfCurrency then FSections[i].NumFormat := nfCurrencyRed; end; procedure TsNumFormatParser.CheckSection(ASection: Integer); var el, i: Integer; section: PsNumFormatSection; nfs, nfsTest: String; nf: TsNumberFormat; formats: set of TsNumberFormat; isMonthMinute: Boolean; begin if FStatus <> psOK then exit; section := @FSections[ASection]; section^.Kind := []; if (ASection = 0) and (Length(FSections) = 1) and (Length(section^.Elements) = 1) and (section^.Elements[0].Token = nftGeneral) then begin section^.NumFormat := nfGeneral; exit; end; i := 0; isMonthMinute := false; for el := 0 to High(section^.Elements) do begin case section^.Elements[el].Token of nftZeroDecs: section^.Decimals := section^.Elements[el].IntValue; nftIntZeroDigit: begin section^.MinIntDigits := section^.Elements[el].IntValue; i := section^.Elements[el].IntValue; end; nftIntOptDigit, nftIntSpaceDigit: i := section^.Elements[el].IntValue; nftFracNumSpaceDigit, nftFracNumZeroDigit: section^.FracNumerator := section^.Elements[el].IntValue; nftFracDenomSpaceDigit, nftFracDenomZeroDigit: section^.FracDenominator := section^.Elements[el].IntValue; nftFracDenom: section^.FracDenominator := -section^.Elements[el].IntValue; nftPercent: section^.Kind := section^.Kind + [nfkPercent]; nftExpChar: if (nfkExp in section^.Kind) then FStatus := psErrMultipleExpChars else section^.Kind := section^.Kind + [nfkExp]; nftFactor: if section^.Elements[el].IntValue <> 0 then begin section^.Elements[el].FloatValue := IntPower(10, -3*section^.Elements[el].IntValue); section^.Factor := section^.Elements[el].FloatValue; section^.Kind := section^.Kind + [nfkHasFactor]; end; nftFracSymbol: if (nfkFraction in section^.Kind) then FStatus := psErrMultipleFracSymbols else begin section^.Kind := section^.Kind + [nfkFraction]; section^.FracInt := i; end; nftCurrSymbol: begin if (nfkCurrency in section^.Kind) then FStatus := psErrMultipleCurrSymbols else begin section^.Kind := section^.Kind + [nfkCurrency]; section^.CurrencySymbol := section^.Elements[el].TextValue; end; end; nftYear, nftMonth, nftDay: section^.Kind := section^.Kind + [nfkDate]; nftHour, nftMinute, nftSecond, nftMilliseconds: begin section^.Kind := section^.Kind + [nfkTime]; if section^.Elements[el].IntValue < 0 then section^.Kind := section^.Kind + [nfkTimeInterval]; if section^.Elements[el].Token = nftMilliseconds then section^.Decimals := section^.Elements[el].IntValue else section^.Decimals := 0; end; nftMonthMinute: isMonthMinute := true; nftColor: begin section^.Kind := section^.Kind + [nfkHasColor]; section^.Color := section^.Elements[el].IntValue; end; nftIntTh: section^.Kind := section^.Kind + [nfkHasThSep]; nftTextFormat: section^.Kind := section^.Kind + [nfkText]; end; end; // for if FStatus <> psOK then exit; if (section^.Kind * [nfkDate, nfkTime] <> []) and (section^.Kind * [nfkPercent, nfkExp, nfkCurrency, nfkFraction] <> []) then begin FStatus := psErrNoValidDateTimeFormat; exit; end; if (Length(FSections) = 1) and (section^.Kind = [nfkText]) then begin section^.NumFormat := nfText; exit; end; section^.NumFormat := nfCustom; if (section^.Kind * [nfkDate, nfkTime] <> []) or isMonthMinute then begin FixMonthMinuteToken(section^); nfs := GetFormatString; if (nfkTimeInterval in section^.Kind) then section^.NumFormat := nfTimeInterval else begin formats := [nfShortDateTime, nfLongDate, nfShortDate, nfLongTime, nfShortTime, nfLongTimeAM, nfShortTimeAM, nfDayMonth, nfMonthYear]; for nf in formats do begin nfsTest := BuildDateTimeFormatString(nf, FFormatSettings); if Length(nfsTest) = Length(nfs) then begin if SameText(nfs, nfsTest) then begin section^.NumFormat := nf; break; end; for i := 1 to Length(nfsTest) do case nfsTest[i] of '/': if not (nf in [nfLongTimeAM, nfShortTimeAM]) then nfsTest[i] := FFormatSettings.DateSeparator; ':': nfsTest[i] := FFormatSettings.TimeSeparator; 'n': nfsTest[i] := 'm'; end; if SameText(nfs, nfsTest) then begin section^.NumFormat := nf; break; end; end; end; end; end else begin nfs := GetFormatString; nfsTest := BuildFractionFormatString(section^.FracInt > 0, section^.FracNumerator, section^.FracDenominator); if sameText(nfs, nfsTest) then section^.NumFormat := nfFraction else begin formats := [nfFixed, nfFixedTh, nfPercentage, nfExp]; for nf in formats do begin nfsTest := BuildNumberFormatString(nf, FFormatSettings, section^.Decimals); if SameText(nfs, nfsTest) then begin section^.NumFormat := nf; break; end; end; end; if (section^.NumFormat = nfCustom) and (nfkCurrency in section^.Kind) then begin section^.NumFormat := nfCurrency; if section^.Color = scRed then section^.NumFormat := nfCurrencyRed; end; end; end; procedure TsNumFormatParser.ClearAll; var i, j: Integer; begin for i:=0 to Length(FSections)-1 do begin for j:=0 to Length(FSections[i].Elements) do if FSections[i].Elements <> nil then FSections[i].Elements[j].TextValue := ''; FSections[i].Elements := nil; FSections[i].CurrencySymbol := ''; end; FSections := nil; end; procedure TsNumFormatParser.DeleteElement(ASection, AIndex: Integer); var i, n: Integer; begin n := Length(FSections[ASection].Elements); for i:= AIndex+1 to n-1 do FSections[ASection].Elements[i-1] := FSections[ASection].Elements[i]; SetLength(FSections[ASection].Elements, n-1); end; {@@ Identify the ambiguous "m" token ("month" or "minute") } procedure TsNumFormatParser.FixMonthMinuteToken(var ASection: TsNumFormatSection); var i, j: Integer; // Finds the previous date/time element skipping spaces, date/time sep etc. function PrevDateTimeElement(j: Integer): Integer; begin Result := -1; dec(j); while (j >= 0) do begin with ASection.Elements[j] do if Token in [nftYear, nftMonth, nftDay, nftHour, nftMinute, nftSecond] then begin Result := j; exit; end; dec(j); end; end; // Finds the next date/time element skipping spaces, date/time sep etc. function NextDateTimeElement(j: Integer): Integer; begin Result := -1; inc(j); while (j < Length(ASection.Elements)) do begin with ASection.Elements[j] do if Token in [nftYear, nftMonth, nftDay, nftHour, nftMinute, nftSecond] then begin Result := j; exit; end; inc(j); end; end; begin for i:=0 to High(ASection.Elements) do begin // Find index of nftMonthMinute token... if ASection.Elements[i].Token = nftMonthMinute then begin // ... and, using its neighbors, decide whether it is a month or a minute. j := NextDateTimeElement(i); if j <> -1 then case ASection.Elements[j].Token of nftDay, nftYear: begin ASection.Elements[i].Token := nftMonth; Continue; end; nftSecond: begin ASection.Elements[i].Token := nftMinute; Continue; end; end; j := PrevDateTimeElement(i); if j <> -1 then case ASection.Elements[j].Token of nftDay, nftYear: begin ASection.Elements[i].Token := nftMonth; Continue; end; nftHour: begin ASection.Elements[i].Token := nftMinute; Continue; end; end; // If we get here the token is isolated. In this case we assume // that it is a month - that's the way Excel does it when reading files // (for editing of a worksheet, however, Excel distinguishes between // uppercase "M" for "month" and lowercase "m" for "minute".) ASection.Elements[i].Token := nftMonth; Include(ASection.Kind, nfkDate); end; end; end; procedure TsNumFormatParser.InsertElement(ASection, AIndex: Integer; AToken: TsNumFormatToken; AText: String); var i, n: Integer; begin n := Length(FSections[ASection].Elements); SetLength(FSections[ASection].Elements, n+1); for i:= n-1 downto AIndex+1 do FSections[ASection].Elements[i+1] := FSections[ASection].Elements[i]; FSections[ASection].Elements[AIndex+1].Token := AToken; FSections[ASection].Elements[AIndex+1].TextValue := AText; end; procedure TsNumFormatParser.InsertElement(ASection, AIndex: Integer; AToken: TsNumFormatToken; AIntValue: Integer); var i, n: Integer; begin n := Length(FSections[ASection].Elements); SetLength(FSections[ASection].Elements, n+1); for i:= n-1 downto AIndex+1 do FSections[ASection].Elements[i+1] := FSections[ASection].Elements[i]; FSections[ASection].Elements[AIndex+1].Token := AToken; FSections[ASection].Elements[AIndex+1].IntValue := AIntValue; end; procedure TsNumFormatParser.InsertElement(ASection, AIndex: Integer; AToken: TsNumFormatToken; AFloatValue: Double); var i, n: Integer; begin n := Length(FSections[ASection].Elements); SetLength(FSections[ASection].Elements, n+1); for i:= n-1 downto AIndex+1 do FSections[ASection].Elements[i+1] := FSections[ASection].Elements[i]; FSections[ASection].Elements[AIndex+1].Token := AToken; FSections[ASection].Elements[AIndex+1].FloatValue := AFloatValue; end; function TsNumFormatParser.GetFormatString: String; begin Result := BuildFormatString; end; {@@ Extracts the currency symbol form the formatting sections. It is assumed that all two or three sections of the currency/accounting format use the same currency symbol, otherwise it would be custom format anyway which ignores the currencysymbol value. } function TsNumFormatParser.GetCurrencySymbol: String; begin if Length(FSections) > 0 then Result := FSections[0].CurrencySymbol else Result := ''; end; {@@ Creates a string which summarizes the date/time formats in the given section. The string contains a 'y' for a nftYear, a 'm' for a nftMonth, a 'd' for a nftDay, a 'h' for a nftHour, a 'n' for a nftMinute, a 's' for a nftSeconds, and a 'z' for a nftMilliseconds token. The order is retained. Needed for biff2 } function TsNumFormatParser.GetDateTimeCode(ASection: Integer): String; var i: Integer; begin Result := ''; if ASection < Length(FSections) then with FSections[ASection] do begin i := 0; while i < Length(Elements) do begin case Elements[i].Token of nftYear : Result := Result + 'y'; nftMonth : Result := Result + 'm'; nftDay : Result := Result + 'd'; nftHour : Result := Result + 'h'; nftMinute : Result := Result + 'n'; nftSecond : Result := Result + 's'; nftMilliSeconds: Result := Result + 'z'; end; inc(i); end; end; end; {@@ Extracts the number of decimals from the sections. Since they are needed only for default formats having only a single section, only the first section is considered. In case of currency/accounting having two or three sections, it is assumed that all sections have the same decimals count, otherwise it would not be a standard format. } function TsNumFormatParser.GetDecimals: Byte; begin if Length(FSections) > 0 then Result := FSections[0].Decimals else Result := 0; end; function TsNumFormatParser.GetFracDenominator: Integer; begin if Length(FSections) > 0 then Result := FSections[0].FracDenominator else Result := 0; end; function TsNumFormatParser.GetFracInt: Integer; begin if Length(FSections) > 0 then Result := FSections[0].FracInt else Result := 0; end; function TsNumFormatParser.GetFracNumerator: Integer; begin if Length(FSections) > 0 then Result := FSections[0].FracNumerator else Result := 0; end; {@@ Tries to extract a common built-in number format from the sections. If there are multiple sections, it is always a custom format, except for Currency and Accounting. } function TsNumFormatParser.GetNumFormat: TsNumberFormat; begin if Length(FSections) = 0 then result := nfGeneral else begin Result := FSections[0].NumFormat; if (Result = nfCurrency) then begin if Length(FSections) = 2 then begin Result := FSections[1].NumFormat; if FSections[1].CurrencySymbol <> FSections[0].CurrencySymbol then begin Result := nfCustom; exit; end; if (FSections[0].NumFormat in [nfCurrency, nfCurrencyRed]) and (FSections[1].NumFormat in [nfCurrency, nfCurrencyRed]) then exit; end else if Length(FSections) = 3 then begin Result := FSections[1].NumFormat; if (FSections[0].CurrencySymbol <> FSections[1].CurrencySymbol) or (FSections[1].CurrencySymbol <> FSections[2].CurrencySymbol) then begin Result := nfCustom; exit; end; if (FSections[0].NumFormat in [nfCurrency, nfCurrencyRed]) and (FSections[1].NumFormat in [nfCurrency, nfCurrencyRed]) and (FSections[2].NumFormat in [nfCurrency, nfCurrencyRed]) then exit; end; Result := nfCustom; exit; end; if Length(FSections) > 1 then Result := nfCustom; end; end; function TsNumFormatParser.GetParsedSectionCount: Integer; begin Result := Length(FSections); end; function TsNumFormatParser.GetParsedSections(AIndex: Integer): TsNumFormatSection; begin Result := FSections[AIndex]; end; { function TsNumFormatParser.GetTokenIntValueAt(AToken: TsNumFormatToken; ASection, AIndex: Integer): Integer; begin if IsTokenAt(AToken, ASection, AIndex) then Result := FSections[ASection].Elements[AIndex].IntValue else Result := -1; end; } { Returns true if the format elements contain at least one date/time token } function TsNumFormatParser.IsDateTimeFormat: Boolean; var section: TsNumFormatSection; begin for section in FSections do if section.Kind * [nfkDate, nfkTime] <> [] then begin Result := true; exit; end; Result := false; end; { function TsNumFormatParser.IsNumberAt(ASection, AIndex: Integer; out ANumFormat: TsNumberFormat; out ADecimals: Byte; out ANextIndex: Integer): Boolean; var token: TsNumFormatToken; begin if (ASection > High(FSections)) or (AIndex > High(FSections[ASection].Elements)) then begin Result := false; ANextIndex := AIndex; exit; end; Result := true; ANumFormat := nfCustom; ADecimals := 0; token := FSections[ASection].Elements[AIndex].Token; if token in [nftFracNumOptDigit, nftFracNumZeroDigit, nftFracNumSpaceDigit, nftFracDenomOptDigit, nftFracDenomZeroDigit, nftFracDenomSpaceDigit] then begin ANumFormat := nfFraction; ANextIndex := AIndex + 1; exit; end; if (token = nftIntTh) and (FSections[ASection].Elements[AIndex].IntValue = 1) then // '#,##0' ANumFormat := nfFixedTh else if (token = nftIntZeroDigit) and (FSections[ASection].Elements[AIndex].IntValue = 1) then // '0' ANumFormat := nfFixed; if (token in [nftIntTh, nftIntZeroDigit, nftIntOptDigit, nftIntSpaceDigit]) then begin if IsTokenAt(nftDecSep, ASection, AIndex+1) then begin if AIndex + 2 < Length(FSections[ASection].Elements) then begin token := FSections[ASection].Elements[AIndex+2].Token; if (token in [nftZeroDecs, nftOptDecs, nftSpaceDecs]) then begin ANextIndex := AIndex + 3; ADecimals := FSections[ASection].Elements[AIndex+2].IntValue; if (token <> nftZeroDecs) then ANumFormat := nfCustom; exit; end; end; end else if IsTokenAt(nftSpace, ASection, AIndex+1) then begin ANumFormat := nfFraction; ANextIndex := AIndex + 1; exit; end else begin ANextIndex := AIndex + 1; exit; end; end; ANextIndex := AIndex; Result := false; end; function TsNumFormatParser.IsTextAt(AText: String; ASection, AIndex: Integer): Boolean; begin Result := IsTokenAt(nftText, ASection, AIndex) and (FSections[ASection].Elements[AIndex].TextValue = AText); end; } {@@ Returns @true if the format elements contain only time, no date tokens. } function TsNumFormatParser.IsTimeFormat: Boolean; var section: TsNumFormatSection; begin for section in FSections do if (nfkTime in section.Kind) then begin Result := true; exit; end; Result := false; end; { function TsNumFormatParser.IsTokenAt(AToken: TsNumFormatToken; ASection, AIndex: Integer): Boolean; begin Result := (ASection < Length(FSections)) and (AIndex < Length(FSections[ASection].Elements)) and (FSections[ASection].Elements[AIndex].Token = AToken); end; } {@@ Limits the decimals to 0 or 2, as required by Excel2. } procedure TsNumFormatParser.LimitDecimals; var i, j: Integer; begin for j:=0 to High(FSections) do for i:=0 to High(FSections[j].Elements) do if FSections[j].Elements[i].Token = nftZeroDecs then if FSections[j].Elements[i].IntValue > 0 then FSections[j].Elements[i].IntValue := 2; end; function TsNumFormatParser.NextToken: Char; begin if FCurrent < FEnd then begin inc(FCurrent); Result := FCurrent^; end else Result := #0; end; function TsNumFormatParser.PrevToken: Char; begin if FCurrent > nil then begin dec(FCurrent); Result := FCurrent^; end else Result := #0; end; procedure TsNumFormatParser.Parse(const AFormatString: String); begin FStatus := psOK; AddSection; if (AFormatString = '') then begin AddElement(nftGeneral); exit; end; FStart := @AFormatString[1]; FEnd := FStart + Length(AFormatString); FCurrent := FStart; FToken := FCurrent^; while (FCurrent < FEnd) and (FStatus = psOK) do begin case FToken of 'G','g': ScanGeneral; '[': ScanBrackets; '"': ScanQuotedText; ':': AddElement(nftDateTimeSep, ':'); ';': AddSection; else ScanFormat; end; FToken := NextToken; end; end; {@@ Scans an AM/PM sequence (or AMPM or A/P). At exit, cursor is a next character } procedure TsNumFormatParser.ScanAMPM; var s: String; el: Integer; begin s := ''; while (FCurrent < FEnd) do begin if (FToken in ['A', 'a', 'P', 'p', 'm', 'M', '/']) then s := s + FToken else break; FToken := NextToken; end; if s <> '' then begin AddElement(nftAMPM, s); // Tag the hour element for AM/PM format needed el := High(FSections[FCurrSection].Elements)-1; for el := High(FSections[FCurrSection].Elements)-1 downto 0 do if FSections[FCurrSection].Elements[el].Token = nftHour then begin FSections[FCurrSection].Elements[el].TextValue := 'AM'; break; end; end; end; {@@ Counts the number of characters equal to ATestChar. Stops at the next different character. This is also where the cursor is at exit. } procedure TsNumFormatParser.ScanAndCount(ATestChar: Char; out ACount: Integer); begin ACount := 0; if FToken <> ATestChar then exit; repeat inc(ACount); FToken := NextToken; until (FToken <> ATestChar) or (FCurrent >= FEnd); end; {@@ Extracts the text between square brackets. This can be - a time duration like [hh] - a condition, like [>= 2.0] - a currency symbol like [$€-409] - a color like [red] or [color25] The procedure is left with the cursor at ']' } procedure TsNumFormatParser.ScanBrackets; var s: String; n: Integer; prevtok: Char; isText: Boolean; begin s := ''; isText := false; FToken := NextToken; // Cursor was at '[' while (FCurrent < FEnd) and (FStatus = psOK) do begin case FToken of 'h', 'H', 'm', 'M', 'n', 'N', 's', 'S': if isText then s := s + FToken else begin prevtok := FToken; ScanAndCount(FToken, n); if (FToken in [']', #0]) then begin case prevtok of 'h', 'H' : AddElement(nftHour, -n); 'm', 'M', 'n', 'N': AddElement(nftMinute, -n); 's', 'S' : AddElement(nftSecond, -n); end; break; end else FStatus := psErrUnknownInfoInBrackets; end; '<', '>', '=': begin ScanCondition(FToken); if FToken = ']' then break else FStatus := psErrUnknownInfoInBrackets; end; '$': begin ScanCurrSymbol; if FToken = ']' then break else FStatus := psErrUnknownInfoInBrackets; end; ']': begin AnalyzeColor(s); break; end; else s := s + FToken; isText := true; end; FToken := NextToken; end; end; {@@ Scans a condition like [>=2.0]. Starts after the "[" and ends before at "]". Returns first character after the number (spaces allowed). } procedure TsNumFormatParser.ScanCondition(AFirstChar: Char); var s: String; // op: TsCompareOperation; value: Double; res: Integer; begin s := AFirstChar; FToken := NextToken; if FToken in ['>', '<', '='] then s := s + FToken else FToken := PrevToken; { if s = '=' then op := coEqual else if s = '<>' then op := coNotEqual else if s = '<' then op := coLess else if s = '>' then op := coGreater else if s = '<=' then op := coLessEqual else if s = '>=' then op := coGreaterEqual else begin FStatus := psErrUnknownInfoInBrackets; FToken := #0; exit; end; } while (FToken = ' ') and (FCurrent < FEnd) do FToken := NextToken; if FCurrent >= FEnd then begin FStatus := psErrUnknownInfoInBrackets; FToken := #0; exit; end; s := FToken; while (FCurrent < FEnd) and (FToken in ['+', '-', '.', '0'..'9']) do begin FToken := NextToken; s := s + FToken; end; val(s, value, res); if res <> 0 then begin FStatus := psErrUnknownInfoInBrackets; FToken := #0; exit; end; while (FCurrent < FEnd) and (FToken = ' ') do FToken := NextToken; if FToken = ']' then AddElement(nftCompareOp, value) else begin FStatus := psErrUnknownInfoInBrackets; FToken := #0; end; end; {@@ Scans to end of a symbol like [$EUR-409], starting after the $ and ending at the "]". After the "$" follows the currency symbol, after the "-" country information } procedure TsNumFormatParser.ScanCurrSymbol; var s: String; begin s := ''; FToken := NextToken; while (FCurrent < FEnd) and not (FToken in ['-', ']']) do begin s := s + FToken; FToken := NextToken; end; if s <> '' then AddElement(nftCurrSymbol, s); if FToken <> ']' then begin FToken := NextToken; while (FCurrent < FEnd) and (FToken <> ']') do begin s := s + FToken; FToken := NextToken; end; if s <> '' then AddElement(nftCountry, s); end; end; {@@ Scans a date/time format. Procedure is left with the cursor at the last char of the date/time format. } procedure TsNumFormatParser.ScanDateTime; var n: Integer; token: Char; begin while (FCurrent < FEnd) and (FStatus = psOK) do begin case FToken of '\': // means that the next character is taken literally begin FToken := NextToken; // skip the "\"... AddElement(nftEscaped, FToken); FToken := NextToken; end; 'Y', 'y': begin ScanAndCount(FToken, n); AddElement(nftYear, n); end; 'm', 'M', 'n', 'N': begin token := FToken; ScanAndCount(FToken, n); AddElement(nftMonthMinute, n, token); // Decide on minute or month later end; 'D', 'd': begin ScanAndCount(FToken, n); AddElement(nftDay, n); end; 'H', 'h': begin ScanAndCount(FToken, n); AddElement(nftHour, n); end; 'S', 's': begin ScanAndCount(FToken, n); AddElement(nftSecond, n); end; '/', ':': begin AddElement(nftDateTimeSep, FToken); FToken := NextToken; end; '.': begin { AddElement(nftDecSep, FToken); FToken := NextToken; if FToken in ['z', 'Z', '0'] then begin ScanAndCount(FToken, n); AddElement(nftMilliseconds, n); end; } token := NextToken; if token in ['z', 'Z', '0'] then begin AddElement(nftDecSep, FToken); FToken := NextToken; if FToken in ['z', 'Z', '0'] then ScanAndCount(FToken, n) else n := 0; AddElement(nftMilliseconds, n+1); end else begin AddElement(nftDateTimeSep, FToken); FToken := token; end; end; '[': begin ScanBrackets; FToken := NextToken; end; 'A', 'a': ScanAMPM; ',', '-': begin AddElement(nftText, FToken); FToken := NextToken; end else // char pointer must be at end of date/time mask. FToken := PrevToken; Exit; end; end; end; procedure TsNumFormatParser.ScanFormat; var done: Boolean; n: Integer; uch: Cardinal; begin done := false; while (FCurrent < FEnd) and (FStatus = psOK) and (not done) do begin case FToken of '\': // Excel: add next character literally begin FToken := NextToken; AddElement(nftText, FToken); end; '*': // Excel: repeat next character to fill cell. For accounting format. begin FToken := NextToken; AddElement(nftRepeat, FToken); end; '_': // Excel: Leave width of next character empty begin FToken := NextToken; uch := UTF8CodepointToUnicode(FCurrent, n); // wp: Why Unicode ??? if n > 1 then begin AddElement(nftEmptyCharWidth, UnicodeToUTF8(uch)); inc(FCurrent, n-1); FToken := NextToken; Continue; end else AddElement(nftEmptyCharWidth, FToken); end; '@': // Excel: Indicates text format begin AddElement(nftTextFormat, FToken); end; '"': ScanQuotedText; '(', ')': AddElement(nftSignBracket, FToken); '0', '#', '?', '.', ',', '-': ScanNumber; 'y', 'Y', 'm', 'M', 'd', 'D', 'h', 'H', 'N', 'n', 's': ScanDateTime; '[': ScanBrackets; '%': AddElement(nftPercent, FToken); ' ': AddElement(nftSpace, FToken); 'A', 'a': begin ScanAMPM; FToken := PrevToken; end; 'G', 'g': ScanGeneral; ';': // End of the section. Important: Cursor must stay on ';' begin AddSection; Exit; end; else uch := UTF8CodepointToUnicode(FCurrent, n); if n > 1 then begin AddElement(nftText, UnicodeToUTF8(uch)); inc(FCurrent, n-1); end else AddElement(nftText, FToken); end; FToken := NextToken; end; end; {@@ Scans for the word "General", it may be used like other tokens } procedure TsNumFormatParser.ScanGeneral; begin FStatus := psErrGeneralExpected; FToken := NextToken; if not (FToken in ['e', 'E']) then exit; FToken := NextToken; if not (FToken in ['n', 'N']) then exit; FToken := NextToken; if not (FToken in ['e', 'E']) then exit; FToken := NextToken; if not (FToken in ['r', 'R']) then exit; FToken := NextToken; if not (FToken in ['a', 'A']) then exit; FToken := NextToken; if not (FToken in ['l', 'L']) then exit; AddElement(nftGeneral); FStatus := psOK; end; {@@ Scans a floating point format. Procedure is left with the cursor at the last character of the format. } procedure TsNumFormatParser.ScanNumber; var hasDecSep: Boolean; isFrac: Boolean; n, m: Integer; el: Integer; savedCurrent: PChar; thSep: Char; begin hasDecSep := false; isFrac := false; thSep := ','; while (FCurrent < FEnd) and (FStatus = psOK) do begin case FToken of ',': AddElement(nftThSep, ','); '.': begin AddElement(nftDecSep, '.'); hasDecSep := true; end; '#': begin ScanAndCount('#', n); savedCurrent := FCurrent; if not (hasDecSep or isFrac) and (n = 1) and (FToken = thSep) then begin m := 0; FToken := NextToken; ScanAndCount('#', n); case n of 0: begin ScanAndCount('0', n); ScanAndCount(thSep, m); FToken := prevToken; if n = 3 then AddElement(nftIntTh, 3, ',') else FCurrent := savedCurrent; end; 1: begin ScanAndCount('0', n); ScanAndCount(thSep, m); FToken := prevToken; if n = 2 then AddElement(nftIntTh, 2, ',') else FCurrent := savedCurrent; end; 2: begin ScanAndCount('0', n); ScanAndCount(thSep, m); FToken := prevToken; if (n = 1) then AddElement(nftIntTh, 1, ',') else FCurrent := savedCurrent; end; end; if m > 0 then AddElement(nftFactor, m, thSep); end else begin FToken := PrevToken; if isFrac then AddElement(nftFracDenomOptDigit, n) else if hasDecSep then AddElement(nftOptDecs, n) else AddElement(nftIntOptDigit, n); end; end; '0': begin ScanAndCount('0', n); ScanAndCount(thSep, m); FToken := PrevToken; if hasDecSep then AddElement(nftZeroDecs, n) else if isFrac then AddElement(nftFracDenomZeroDigit, n) else AddElement(nftIntZeroDigit, n); if m > 0 then AddElement(nftFactor, m, thSep); end; '1'..'9': begin if isFrac then begin n := 0; while (FToken in ['1'..'9','0']) do begin n := n*10 + StrToInt(FToken); FToken := nextToken; end; AddElement(nftFracDenom, n); end else AddElement(nftText, FToken); end; '?': begin ScanAndCount('?', n); FToken := PrevToken; if hasDecSep then AddElement(nftSpaceDecs, n) else if isFrac then AddElement(nftFracDenomSpaceDigit, n) else AddElement(nftIntSpaceDigit, n); end; 'E', 'e': begin AddElement(nftExpChar, FToken); FToken := NextToken; if FToken in ['+', '-'] then AddElement(nftExpSign, FToken); FToken := NextToken; if FToken = '0' then begin ScanAndCount('0', n); FToken := PrevToken; AddElement(nftExpDigits, n); end; end; '+', '-': AddElement(nftSign, FToken); '%': AddElement(nftPercent, FToken); '/': begin isFrac := true; AddElement(nftFracSymbol, FToken); // go back and replace correct token for numerator el := High(FSections[FCurrSection].Elements); while el > 0 do begin dec(el); case FSections[FCurrSection].Elements[el].Token of nftIntOptDigit: begin FSections[FCurrSection].Elements[el].Token := nftFracNumOptDigit; break; end; nftIntSpaceDigit: begin FSections[FCurrSection].Elements[el].Token := nftFracNumSpaceDigit; break; end; nftIntZeroDigit: begin FSections[FCurrSection].Elements[el].Token := nftFracNumZeroDigit; break; end; end; end; end; 'G', 'g': ScanGeneral; else FToken := PrevToken; Exit; end; FToken := NextToken; end; end; {@@ Scans a text in quotation marks. Tries to interpret the text as a currency symbol (--> AnalyzeText). The procedure is entered and left with the cursor at a quotation mark. } procedure TsNumFormatParser.ScanQuotedText; var s: String; begin s := ''; FToken := NextToken; // Cursor war at '"' while (FCurrent < FEnd) and (FStatus = psOK) do begin if FToken = '"' then begin if AnalyzeCurrency(s) then AddElement(nftCurrSymbol, s) else AddElement(nftText, s); exit; end else begin s := s + FToken; FToken := NextToken; end; end; // When the procedure gets here the final quotation mark is missing FStatus := psErrQuoteExpected; end; procedure TsNumFormatParser.SetDecimals(AValue: Byte); var i, j, n: Integer; foundDecs: Boolean; begin foundDecs := false; for j := 0 to High(FSections) do begin n := Length(FSections[j].Elements); i := n-1; while (i > -1) do begin case FSections[j].Elements[i].Token of nftDecSep: // this happens, e.g., for "0.E+00" if (AValue > 0) and not foundDecs then begin InsertElement(j, i, nftZeroDecs, AValue); break; end; nftIntOptDigit, nftIntZeroDigit, nftIntSpaceDigit, nftIntTh: // no decimals so far --> add decimal separator and decimals element if (AValue > 0) then begin // Don't use "AddElements" because nfCurrency etc have elements after the number. InsertElement(j, i, nftDecSep, '.'); InsertElement(j, i+1, nftZeroDecs, AValue); break; end; nftZeroDecs, nftOptDecs, nftSpaceDecs: begin foundDecs := true; if AValue > 0 then begin // decimals are already used, just replace value of decimal places FSections[j].Elements[i].IntValue := AValue; FSections[j].Elements[i].Token := nftZeroDecs; break; end else begin // No decimals any more: delete decs and decsep elements DeleteElement(j, i); DeleteElement(j, i-1); break; end; end; end; dec(i); end; end; end; end. ������������������������������������������������������������������������doublecmd-1.1.22/src/frames/������������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�014652� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsarchivers.lfm���������������������������������������������������0000644�0001750�0000144�00000166340�14743153644�021134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsArchivers: TfrmOptionsArchivers Height = 642 Width = 923 HelpKeyword = '/multiarc.html' ClientHeight = 642 ClientWidth = 923 ParentShowHint = False ShowHint = True DesignLeft = 159 DesignTop = 215 object pnlArchiverListbox: TPanel[0] Left = 5 Height = 642 Top = 0 Width = 120 Align = alLeft BorderSpacing.Left = 5 BevelOuter = bvNone ClientHeight = 642 ClientWidth = 120 Constraints.MinWidth = 120 TabOrder = 0 object lblArchiverListBox: TLabel AnchorSideLeft.Control = pnlArchiverListbox AnchorSideTop.Control = pnlArchiverListbox Left = 3 Height = 18 Top = 3 Width = 114 Align = alTop BorderSpacing.Around = 3 Caption = 'Archi&vers:' FocusControl = lbxArchiver ParentColor = False end object lbxArchiver: TListBox Left = 0 Height = 618 Top = 24 Width = 120 Align = alClient DragMode = dmAutomatic ItemHeight = 0 OnDragDrop = lbxArchiverDragDrop OnDragOver = lbxArchiverDragOver OnSelectionChange = lbxArchiverSelectionChange TabOrder = 0 end end object splArchiver: TSplitter[1] Left = 125 Height = 642 Top = 0 Width = 5 end object pnlArchiverCommands: TPanel[2] Left = 130 Height = 642 Top = 0 Width = 793 Align = alClient BevelOuter = bvNone ClientHeight = 642 ClientWidth = 793 TabOrder = 2 object pnlArchiverButtons: TPanel Left = 0 Height = 38 Top = 0 Width = 793 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ClientHeight = 38 ClientWidth = 793 TabOrder = 0 object chkArchiverEnabled: TCheckBox AnchorSideLeft.Control = pnlArchiverButtons AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter Left = 10 Height = 24 Top = 7 Width = 75 BorderSpacing.Left = 10 Caption = 'E&nabled' OnChange = chkArchiverEnabledChange TabOrder = 0 end object btnArchiverApply: TBitBtn AnchorSideLeft.Control = chkArchiverEnabled AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 95 Height = 29 Top = 5 Width = 49 AutoSize = True BorderSpacing.Left = 10 Caption = 'A&pply' OnClick = btnArchiverApplyClick TabOrder = 1 end object btnArchiverAdd: TBitBtn AnchorSideLeft.Control = btnArchiverApply AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 147 Height = 29 Top = 5 Width = 39 AutoSize = True BorderSpacing.Left = 3 Caption = 'A&dd' OnClick = btnArchiverAddClick TabOrder = 2 end object btnArchiverCopy: TBitBtn AnchorSideLeft.Control = btnArchiverAdd AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 189 Height = 29 Top = 5 Width = 45 AutoSize = True BorderSpacing.Left = 3 Caption = 'Cop&y' OnClick = btnArchiverCopyClick TabOrder = 3 end object btnArchiverRename: TBitBtn AnchorSideLeft.Control = btnArchiverCopy AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 237 Height = 29 Top = 5 Width = 65 AutoSize = True BorderSpacing.Left = 3 Caption = '&Rename' OnClick = btnArchiverRenameClick TabOrder = 4 end object btnArchiverDelete: TBitBtn AnchorSideLeft.Control = btnArchiverRename AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 305 Height = 29 Top = 5 Width = 54 AutoSize = True BorderSpacing.Left = 3 Caption = 'Delete' OnClick = btnArchiverDeleteClick TabOrder = 5 end object btnArchiverOther: TBitBtn AnchorSideLeft.Control = btnArchiverDelete AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlArchiverButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 362 Height = 29 Top = 5 Width = 60 AutoSize = True BorderSpacing.Left = 3 Caption = 'Oth&er...' OnClick = btnArchiverOtherClick TabOrder = 6 end end object pcArchiverCommands: TPageControl Left = 0 Height = 604 Top = 38 Width = 793 ActivePage = tbArchiverGeneral Align = alClient TabIndex = 0 TabOrder = 1 object tbArchiverGeneral: TTabSheet Caption = 'General' ClientHeight = 569 ClientWidth = 789 object lblArchiverDescription: TLabel AnchorSideLeft.Control = tbArchiverGeneral AnchorSideTop.Control = tbArchiverGeneral AnchorSideRight.Control = tbArchiverGeneral AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 10 Width = 769 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Top = 10 BorderSpacing.Right = 10 Caption = 'De&scription:' FocusControl = edtArchiverDescription ParentColor = False end object edtArchiverDescription: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverDescription AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom Left = 10 Height = 26 Top = 28 Width = 769 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 0 end object lblArchiverArchiver: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = edtArchiverDescription AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 56 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 10 Caption = 'Arc&hiver:' FocusControl = edtArchiverArchiver ParentColor = False end object edtArchiverArchiver: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverArchiver AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverSelectFileArchiver Left = 10 Height = 26 Top = 74 Width = 713 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 2 OnChange = edtAnyChange TabOrder = 1 end object btnArchiverSelectFileArchiver: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverArchiver AnchorSideRight.Control = btnArchiverRelativer AnchorSideBottom.Control = edtArchiverArchiver AnchorSideBottom.Side = asrBottom Left = 725 Height = 26 Top = 74 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 8A040000424D8A040000000000008A0000007C00000010000000100000000100 20000300000000040000232E0000232E000000000000000000000000FF0000FF 0000FF000000000000FF42475273000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000200 000000000000000000000000000000FFFFFFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FFF1F1F1FFEFEFEFFFEEEEEEFFEDED EDFFEBEBEBFFEAEAEAFFE9E9E9FFE7E7E7FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFC87137FFC87137FFF3F3F3FFF1F1F1FFF0F0F0FFCD89 59FFCD8959FFCD8959FFCD8959FFCD8959FFCD8959FFCD8959FFCD8959FFE6E6 E6FFE6E6E6FFE6E6E6FFC87137FFC87137FFF4F4F4FFF3F3F3FFF2F2F2FFCD89 59FFFFF6D5FFFFF6D5FFFFF6D5FFFFF6D5FFFFF6D5FFFFF6D5FFCD8959FFE6E6 E6FFE6E6E6FFE6E6E6FFC87137FFC87137FFF6F6F6FFF5F5F5FFF3F3F3FFCD89 59FFFFF7DBFF918A6FFF918A6FFF918A6FFF918A6FFFFFF6D5FFCD8959FFE7E7 E7FFE6E6E6FFE6E6E6FFC87137FFC87137FFF8F8F8FFF6F6F6FFF5F5F5FFCD89 59FFFFF9E1FFFFF8DFFFFFF8DEFFFFF8DDFFFFF7DCFFFFF7DBFFCD8959FFE9E9 E9FFE8E8E8FFE7E7E7FFC87137FFC87137FFFAFAFAFFF8F8F8FFF7F7F7FFCD89 59FFFFFAE6FF918A6FFF918A6FFF918A6FFF918A6FFFFFF8E0FFCD8959FFEBEB EBFFEAEAEAFFE8E8E8FFC87137FFC87137FFFBFBFBFFFAFAFAFFF9F9F9FFCD89 59FFFFFBECFFFFFBEBFFFFFAEAFFFFFAE8FFFFFAE7FFFFFAE6FFCD8959FFEDED EDFFEBEBEBFFEAEAEAFFC87137FFC87137FFFDFDFDFFFCFCFCFFFAFAFAFFCD89 59FFFFFCF2FF918A6FFF918A6FFF918A6FFFFFFBEDFFFFFBECFFCD8959FFEEEE EEFFEDEDEDFFECECECFFC87137FFC87137FFFFFFFFFFFDFDFDFFFCFCFCFFCD89 59FFFFFDF8FFFFFDF6FFFFFDF5FFFFFDF4FFFFFCF3FFF2DFCBFFCF8E5FFFF0F0 F0FFEFEFEFFFEEEEEEFFC87137FFC87137FFFFFFFFFFFFFFFFFFFEFEFEFFCD89 59FFFFFFFDFFFFFEFCFFFFFEFBFFFFFEFAFFF3E2D3FFD19266FFE9D7CBFFF2F2 F2FFF4F4F4FFEFEFEFFFC87137FFC87137FFFFFFFFFFFFFFFFFFFFFFFFFFCD89 59FFCD8959FFCD8959FFCD8959FFCD8959FFCF8E60FFEBDACEFFF5F5F5FFF4F4 F4FFF2F2F2FFF1F1F1FFC87137FFC87137FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFDFDFDFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF5F5 F5FFF4F4F4FFF3F3F3FFC87137FFC87137FFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FF0000FFFFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC87137FFC871 37FFC87137FFC87137FFC87137FF } OnClick = btnArchiverSelectFileArchiverClick end object btnArchiverRelativer: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverArchiver AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverArchiver AnchorSideBottom.Side = asrBottom Left = 752 Height = 26 Hint = 'Some functions to select appropriate path' Top = 74 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnArchiverRelativerClick end object lblArchiverExtension: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = edtArchiverArchiver AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 102 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 10 Caption = 'E&xtension:' FocusControl = edtArchiverExtension ParentColor = False end object edtArchiverExtension: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverExtension AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom Left = 10 Height = 26 Top = 120 Width = 769 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 2 end object lblArchiverList: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = pnlFileNameOnlyList AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 151 Width = 25 BorderSpacing.Top = 2 BorderSpacing.Right = 10 Caption = '&List:' FocusControl = edtArchiverList ParentColor = False end object edtArchiverList: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = pnlFileNameOnlyList AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverListHelper Left = 10 Height = 26 Top = 172 Width = 739 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 OnChange = edtAnyChange TabOrder = 4 end object btnArchiverListHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverList AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverList AnchorSideBottom.Side = asrBottom Left = 752 Height = 26 Hint = 'Variable reminder helper' Top = 172 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object lblArchiverListStart: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = edtArchiverList AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 200 Width = 769 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'Listin&g start (optional):' FocusControl = edtArchiverListStart ParentColor = False end object edtArchiverListStart: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverListStart AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom Left = 10 Height = 26 Top = 218 Width = 769 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 5 end object lblArchiverListEnd: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = edtArchiverListStart AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 244 Width = 769 Anchors = [akTop, akLeft, akRight] Caption = 'Listing &finish (optional):' FocusControl = edtArchiverListEnd ParentColor = False end object edtArchiverListEnd: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverListEnd AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom Left = 10 Height = 26 Top = 262 Width = 769 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 6 end object lblArchiverListFormat: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = edtArchiverListEnd AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 290 Width = 763 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 10 Caption = 'Listing for&mat:' FocusControl = memArchiverListFormat ParentColor = False end object memArchiverListFormat: TMemo AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverListFormat AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 10 Height = 100 Top = 308 Width = 769 Anchors = [akTop, akLeft, akRight] Constraints.MaxHeight = 100 Lines.Strings = ( '' ) OnChange = edtAnyChange ScrollBars = ssAutoBoth TabOrder = 7 WordWrap = False end object lblArchiverExtract: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = memArchiverListFormat AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 410 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 10 Caption = 'Ex&tract:' FocusControl = edtArchiverExtract ParentColor = False end object edtArchiverExtract: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverExtract AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverExtractHelper AnchorSideBottom.Control = tbArchiverGeneral AnchorSideBottom.Side = asrBottom Left = 10 Height = 26 Top = 428 Width = 739 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 OnChange = edtAnyChange TabOrder = 8 end object btnArchiverExtractHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverExtract AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverExtract AnchorSideBottom.Side = asrBottom Left = 752 Height = 26 Hint = 'Variable reminder helper' Top = 428 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object lblArchiverAdd: TLabel AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = edtArchiverExtract AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 456 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 10 Caption = 'Add&ing:' FocusControl = edtArchiverAdd ParentColor = False end object edtArchiverAdd: TEdit AnchorSideLeft.Control = lblArchiverDescription AnchorSideTop.Control = lblArchiverAdd AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverAddHelper AnchorSideBottom.Side = asrBottom Left = 10 Height = 26 Top = 474 Width = 739 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 BorderSpacing.Bottom = 6 OnChange = edtAnyChange TabOrder = 9 end object btnArchiverAddHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverAdd AnchorSideRight.Control = lblArchiverDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverAdd AnchorSideBottom.Side = asrBottom Left = 752 Height = 26 Hint = 'Variable reminder helper' Top = 474 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object pnlFileNameOnlyList: TPanel AnchorSideLeft.Control = lblArchiverList AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverExtension AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtArchiverList AnchorSideRight.Side = asrBottom Left = 45 Height = 24 Top = 148 Width = 704 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 2 BevelOuter = bvNone ClientHeight = 24 ClientWidth = 704 TabOrder = 3 object chkFileNameOnlyList: TCheckBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 419 Height = 24 Top = 0 Width = 285 Anchors = [akTop, akRight] Caption = 'Use archive name without extension as list' OnChange = chkFileNameOnlyListChange ParentBidiMode = False TabOrder = 0 end end end object tbArchiverAdditional: TTabSheet Caption = 'Additional' ClientHeight = 580 ClientWidth = 785 object lblArchiverDelete: TLabel AnchorSideLeft.Control = tbArchiverAdditional AnchorSideTop.Control = tbArchiverAdditional AnchorSideRight.Control = tbArchiverAdditional AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 10 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Top = 10 BorderSpacing.Right = 10 Caption = 'De&lete:' FocusControl = edtArchiverDelete ParentColor = False end object edtArchiverDelete: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverDelete AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverDeleteHelper Left = 10 Height = 23 Top = 25 Width = 735 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 OnChange = edtAnyChange TabOrder = 0 end object btnArchiverDeleteHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverDelete AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverDelete AnchorSideBottom.Side = asrBottom Left = 748 Height = 23 Hint = 'Variable reminder helper' Top = 25 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object lblArchiverTest: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverDelete AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 50 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'Tes&t:' FocusControl = edtArchiverTest ParentColor = False end object edtArchiverTest: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverTest AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverTestHelper Left = 10 Height = 23 Top = 65 Width = 735 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 OnChange = edtAnyChange TabOrder = 1 end object btnArchiverTestHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverTest AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverTest AnchorSideBottom.Side = asrBottom Left = 748 Height = 23 Hint = 'Variable reminder helper' Top = 65 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object lblArchiverExtractWithoutPath: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverTest AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 90 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'Extract &without path:' FocusControl = edtArchiverExtractWithoutPath ParentColor = False end object edtArchiverExtractWithoutPath: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverExtractWithoutPath AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverExtractWithoutPathHelper Left = 10 Height = 23 Top = 105 Width = 735 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 OnChange = edtAnyChange TabOrder = 2 end object btnArchiverExtractWithoutPathHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverExtractWithoutPath AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverExtractWithoutPath AnchorSideBottom.Side = asrBottom Left = 748 Height = 23 Hint = 'Variable reminder helper' Top = 105 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object lblArchiverSelfExtract: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverExtractWithoutPath AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 130 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'Create self extractin&g archive:' FocusControl = edtArchiverSelfExtract ParentColor = False end object edtArchiverSelfExtract: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverSelfExtract AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnArchiverSelfExtractHelper Left = 10 Height = 23 Top = 145 Width = 735 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 3 OnChange = edtAnyChange TabOrder = 3 end object btnArchiverSelfExtractHelper: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtArchiverSelfExtract AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtArchiverSelfExtract AnchorSideBottom.Side = asrBottom Left = 748 Height = 23 Hint = 'Variable reminder helper' Top = 145 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnHelperClick end object lblArchiverPasswordQuery: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverSelfExtract AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 170 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'Password &query string:' FocusControl = edtArchiverPasswordQuery ParentColor = False end object edtArchiverPasswordQuery: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverPasswordQuery AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 185 Width = 765 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 4 end object bvlArchiverIds: TDividerBevel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverPasswordQuery AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 223 Width = 765 Caption = 'ID''s used with cm_OpenArchive to recognize archive by detecting its content and not via file extension:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 15 ParentFont = False end object lblArchiverIds: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = bvlArchiverIds AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 238 Width = 765 Anchors = [akTop, akLeft, akRight] Caption = '&ID:' FocusControl = edtArchiverId ParentColor = False end object edtArchiverId: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverIds AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 253 Width = 765 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 5 end object lblArchiverIdPosition: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverId AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 278 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'ID Po&sition:' FocusControl = edtArchiverIdPosition ParentColor = False end object edtArchiverIdPosition: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverIdPosition AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 293 Width = 765 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 6 end object lblArchiverIdSeekRange: TLabel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverIdPosition AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 318 Width = 765 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'ID See&k Range:' FocusControl = edtArchiverIdSeekRange ParentColor = False end object edtArchiverIdSeekRange: TEdit AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = lblArchiverIdSeekRange AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 333 Width = 765 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange TabOrder = 7 end object bvlArchiverParsingMode: TDividerBevel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = edtArchiverIdSeekRange AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 371 Width = 765 Caption = 'Format parsing mode:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 15 ParentFont = False end object ckbArchiverUnixPath: TCheckBox AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = bvlArchiverParsingMode AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 391 Width = 138 BorderSpacing.Top = 5 Caption = '&Unix path delimiter "/"' OnChange = ckbArchiverUnixPathChange TabOrder = 8 end object ckbArchiverWindowsPath: TCheckBox AnchorSideLeft.Control = ckbArchiverUnixPath AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ckbArchiverUnixPath Left = 158 Height = 19 Top = 391 Width = 164 BorderSpacing.Left = 10 Caption = 'Windows path deli&miter "\"' OnChange = ckbArchiverWindowsPathChange TabOrder = 9 end object ckbArchiverUnixFileAttributes: TCheckBox AnchorSideLeft.Control = ckbArchiverWindowsPath AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ckbArchiverUnixPath Left = 332 Height = 19 Top = 391 Width = 115 BorderSpacing.Left = 10 Caption = 'Uni&x file attributes' OnChange = ckbArchiverUnixFileAttributesChange TabOrder = 10 end object ckbArchiverWindowsFileAttributes: TCheckBox AnchorSideLeft.Control = ckbArchiverUnixFileAttributes AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ckbArchiverUnixPath Left = 457 Height = 19 Top = 391 Width = 141 BorderSpacing.Left = 10 Caption = 'Windows &file attributes' OnChange = ckbArchiverWindowsFileAttributesChange ParentBidiMode = False TabOrder = 11 end object bvlArchiverOptions: TDividerBevel AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = ckbArchiverUnixPath AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lblArchiverDelete AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 425 Width = 765 Caption = 'Options:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 15 ParentFont = False end object chkArchiverMultiArcOutput: TCheckBox AnchorSideLeft.Control = lblArchiverDelete AnchorSideTop.Control = bvlArchiverOptions AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 445 Width = 132 BorderSpacing.Top = 5 Caption = 'S&how console output' OnChange = edtAnyChange TabOrder = 12 end object chkArchiverMultiArcDebug: TCheckBox AnchorSideLeft.Control = chkArchiverMultiArcOutput AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = chkArchiverMultiArcOutput AnchorSideRight.Side = asrBottom Left = 152 Height = 19 Top = 445 Width = 89 BorderSpacing.Left = 10 Caption = 'De&bug mode' OnChange = edtAnyChange TabOrder = 13 end end end end object pmArchiverOther: TPopupMenu[3] left = 192 top = 552 object miArchiverAutoConfigure: TMenuItem Caption = 'Auto Configure' OnClick = miArchiverAutoConfigureClick end object miArchiverDiscardModification: TMenuItem Caption = 'Discard modifications' OnClick = miArchiverDiscardModificationClick end object miSeparator1: TMenuItem Caption = '-' end object miArchiverSortArchivers: TMenuItem Caption = 'Sort archivers' OnClick = miArchiverSortArchiversClick end object miArchiverDisableAll: TMenuItem Caption = 'Disable all' OnClick = miAdjustEnableAllClick end object miArchiverEnableAll: TMenuItem Tag = 1 Caption = 'Enable all' OnClick = miAdjustEnableAllClick end object miSeparator2: TMenuItem Caption = '-' end object miArchiverExport: TMenuItem Caption = 'Export...' OnClick = miArchiverExportClick end object miArchiverImport: TMenuItem Caption = 'Import...' OnClick = miArchiverImportClick end end object pmArchiverPathHelper: TPopupMenu[4] left = 320 top = 552 end object pmArchiverParamHelper: TPopupMenu[5] left = 456 top = 552 end object SaveArchiverDialog: TSaveDialog[6] DefaultExt = '.ini' Filter = 'Archiver configuration|*.ini' Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing, ofViewDetail] left = 600 top = 552 end object OpenArchiverDialog: TOpenDialog[7] DefaultExt = '.*.ini' Filter = 'Archiver config files|*.ini;*.addon|Any files|*.*' Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] left = 728 top = 552 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsarchivers.lrj���������������������������������������������������0000644�0001750�0000144�00000023213�14743153644�021134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":194265226,"name":"tfrmoptionsarchivers.lblarchiverlistbox.caption","sourcebytes":[65,114,99,104,105,38,118,101,114,115,58],"value":"Archi&vers:"}, {"hash":222795460,"name":"tfrmoptionsarchivers.chkarchiverenabled.caption","sourcebytes":[69,38,110,97,98,108,101,100],"value":"E&nabled"}, {"hash":71137081,"name":"tfrmoptionsarchivers.btnarchiverapply.caption","sourcebytes":[65,38,112,112,108,121],"value":"A&pply"}, {"hash":277668,"name":"tfrmoptionsarchivers.btnarchiveradd.caption","sourcebytes":[65,38,100,100],"value":"A&dd"}, {"hash":4874969,"name":"tfrmoptionsarchivers.btnarchivercopy.caption","sourcebytes":[67,111,112,38,121],"value":"Cop&y"}, {"hash":193742869,"name":"tfrmoptionsarchivers.btnarchiverrename.caption","sourcebytes":[38,82,101,110,97,109,101],"value":"&Rename"}, {"hash":78392485,"name":"tfrmoptionsarchivers.btnarchiverdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":181151662,"name":"tfrmoptionsarchivers.btnarchiverother.caption","sourcebytes":[79,116,104,38,101,114,46,46,46],"value":"Oth&er..."}, {"hash":231000124,"name":"tfrmoptionsarchivers.tbarchivergeneral.caption","sourcebytes":[71,101,110,101,114,97,108],"value":"General"}, {"hash":168263882,"name":"tfrmoptionsarchivers.lblarchiverdescription.caption","sourcebytes":[68,101,38,115,99,114,105,112,116,105,111,110,58],"value":"De&scription:"}, {"hash":217334794,"name":"tfrmoptionsarchivers.lblarchiverarchiver.caption","sourcebytes":[65,114,99,38,104,105,118,101,114,58],"value":"Arc&hiver:"}, {"hash":15252584,"name":"tfrmoptionsarchivers.btnarchiverrelativer.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":203307962,"name":"tfrmoptionsarchivers.lblarchiverextension.caption","sourcebytes":[69,38,120,116,101,110,115,105,111,110,58],"value":"E&xtension:"}, {"hash":45288058,"name":"tfrmoptionsarchivers.lblarchiverlist.caption","sourcebytes":[38,76,105,115,116,58],"value":"&List:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchiverlisthelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":6599722,"name":"tfrmoptionsarchivers.lblarchiverliststart.caption","sourcebytes":[76,105,115,116,105,110,38,103,32,115,116,97,114,116,32,40,111,112,116,105,111,110,97,108,41,58],"value":"Listin&g start (optional):"}, {"hash":84636634,"name":"tfrmoptionsarchivers.lblarchiverlistend.caption","sourcebytes":[76,105,115,116,105,110,103,32,38,102,105,110,105,115,104,32,40,111,112,116,105,111,110,97,108,41,58],"value":"Listing &finish (optional):"}, {"hash":223256074,"name":"tfrmoptionsarchivers.lblarchiverlistformat.caption","sourcebytes":[76,105,115,116,105,110,103,32,102,111,114,38,109,97,116,58],"value":"Listing for&mat:"}, {"hash":230176474,"name":"tfrmoptionsarchivers.lblarchiverextract.caption","sourcebytes":[69,120,38,116,114,97,99,116,58],"value":"Ex&tract:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchiverextracthelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":174915802,"name":"tfrmoptionsarchivers.lblarchiveradd.caption","sourcebytes":[65,100,100,38,105,110,103,58],"value":"Add&ing:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchiveraddhelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":160240324,"name":"tfrmoptionsarchivers.chkfilenameonlylist.caption","sourcebytes":[85,115,101,32,97,114,99,104,105,118,101,32,110,97,109,101,32,119,105,116,104,111,117,116,32,101,120,116,101,110,115,105,111,110,32,97,115,32,108,105,115,116],"value":"Use archive name without extension as list"}, {"hash":11288268,"name":"tfrmoptionsarchivers.tbarchiveradditional.caption","sourcebytes":[65,100,100,105,116,105,111,110,97,108],"value":"Additional"}, {"hash":131255850,"name":"tfrmoptionsarchivers.lblarchiverdelete.caption","sourcebytes":[68,101,38,108,101,116,101,58],"value":"De&lete:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchiverdeletehelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":95182202,"name":"tfrmoptionsarchivers.lblarchivertest.caption","sourcebytes":[84,101,115,38,116,58],"value":"Tes&t:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchivertesthelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":184602,"name":"tfrmoptionsarchivers.lblarchiverextractwithoutpath.caption","sourcebytes":[69,120,116,114,97,99,116,32,38,119,105,116,104,111,117,116,32,112,97,116,104,58],"value":"Extract &without path:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchiverextractwithoutpathhelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":171034042,"name":"tfrmoptionsarchivers.lblarchiverselfextract.caption","sourcebytes":[67,114,101,97,116,101,32,115,101,108,102,32,101,120,116,114,97,99,116,105,110,38,103,32,97,114,99,104,105,118,101,58],"value":"Create self extractin&g archive:"}, {"hash":197225810,"name":"tfrmoptionsarchivers.btnarchiverselfextracthelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":205166506,"name":"tfrmoptionsarchivers.lblarchiverpasswordquery.caption","sourcebytes":[80,97,115,115,119,111,114,100,32,38,113,117,101,114,121,32,115,116,114,105,110,103,58],"value":"Password &query string:"}, {"hash":215905370,"name":"tfrmoptionsarchivers.bvlarchiverids.caption","sourcebytes":[73,68,39,115,32,117,115,101,100,32,119,105,116,104,32,99,109,95,79,112,101,110,65,114,99,104,105,118,101,32,116,111,32,114,101,99,111,103,110,105,122,101,32,97,114,99,104,105,118,101,32,98,121,32,100,101,116,101,99,116,105,110,103,32,105,116,115,32,99,111,110,116,101,110,116,32,97,110,100,32,110,111,116,32,118,105,97,32,102,105,108,101,32,101,120,116,101,110,115,105,111,110,58],"value":"ID's used with cm_OpenArchive to recognize archive by detecting its content and not via file extension:"}, {"hash":175482,"name":"tfrmoptionsarchivers.lblarchiverids.caption","sourcebytes":[38,73,68,58],"value":"&ID:"}, {"hash":91198858,"name":"tfrmoptionsarchivers.lblarchiveridposition.caption","sourcebytes":[73,68,32,80,111,38,115,105,116,105,111,110,58],"value":"ID Po&sition:"}, {"hash":1932346,"name":"tfrmoptionsarchivers.lblarchiveridseekrange.caption","sourcebytes":[73,68,32,83,101,101,38,107,32,82,97,110,103,101,58],"value":"ID See&k Range:"}, {"hash":160056426,"name":"tfrmoptionsarchivers.bvlarchiverparsingmode.caption","sourcebytes":[70,111,114,109,97,116,32,112,97,114,115,105,110,103,32,109,111,100,101,58],"value":"Format parsing mode:"}, {"hash":95567826,"name":"tfrmoptionsarchivers.ckbarchiverunixpath.caption","sourcebytes":[38,85,110,105,120,32,112,97,116,104,32,100,101,108,105,109,105,116,101,114,32,34,47,34],"value":"&Unix path delimiter \"/\""}, {"hash":13879346,"name":"tfrmoptionsarchivers.ckbarchiverwindowspath.caption","sourcebytes":[87,105,110,100,111,119,115,32,112,97,116,104,32,100,101,108,105,38,109,105,116,101,114,32,34,92,34],"value":"Windows path deli&miter \"\\\""}, {"hash":22376883,"name":"tfrmoptionsarchivers.ckbarchiverunixfileattributes.caption","sourcebytes":[85,110,105,38,120,32,102,105,108,101,32,97,116,116,114,105,98,117,116,101,115],"value":"Uni&x file attributes"}, {"hash":20825811,"name":"tfrmoptionsarchivers.ckbarchiverwindowsfileattributes.caption","sourcebytes":[87,105,110,100,111,119,115,32,38,102,105,108,101,32,97,116,116,114,105,98,117,116,101,115],"value":"Windows &file attributes"}, {"hash":128999434,"name":"tfrmoptionsarchivers.bvlarchiveroptions.caption","sourcebytes":[79,112,116,105,111,110,115,58],"value":"Options:"}, {"hash":232547940,"name":"tfrmoptionsarchivers.chkarchivermultiarcoutput.caption","sourcebytes":[83,38,104,111,119,32,99,111,110,115,111,108,101,32,111,117,116,112,117,116],"value":"S&how console output"}, {"hash":199055669,"name":"tfrmoptionsarchivers.chkarchivermultiarcdebug.caption","sourcebytes":[68,101,38,98,117,103,32,109,111,100,101],"value":"De&bug mode"}, {"hash":142516837,"name":"tfrmoptionsarchivers.miarchiverautoconfigure.caption","sourcebytes":[65,117,116,111,32,67,111,110,102,105,103,117,114,101],"value":"Auto Configure"}, {"hash":38327763,"name":"tfrmoptionsarchivers.miarchiverdiscardmodification.caption","sourcebytes":[68,105,115,99,97,114,100,32,109,111,100,105,102,105,99,97,116,105,111,110,115],"value":"Discard modifications"}, {"hash":260481459,"name":"tfrmoptionsarchivers.miarchiversortarchivers.caption","sourcebytes":[83,111,114,116,32,97,114,99,104,105,118,101,114,115],"value":"Sort archivers"}, {"hash":158101340,"name":"tfrmoptionsarchivers.miarchiverdisableall.caption","sourcebytes":[68,105,115,97,98,108,101,32,97,108,108],"value":"Disable all"}, {"hash":153330780,"name":"tfrmoptionsarchivers.miarchiverenableall.caption","sourcebytes":[69,110,97,98,108,101,32,97,108,108],"value":"Enable all"}, {"hash":124337662,"name":"tfrmoptionsarchivers.miarchiverexport.caption","sourcebytes":[69,120,112,111,114,116,46,46,46],"value":"Export..."}, {"hash":124338510,"name":"tfrmoptionsarchivers.miarchiverimport.caption","sourcebytes":[73,109,112,111,114,116,46,46,46],"value":"Import..."} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsarchivers.pas���������������������������������������������������0000644�0001750�0000144�00000100650�14743153644�021131� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Archivers options page Copyright (C) 2006-2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsArchivers; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. DividerBevel, Classes, SysUtils, StdCtrls, ExtCtrls, ComCtrls, EditBtn, Buttons, Menus, Dialogs, //DC uMultiArc, fOptionsFrame, Controls; type { TfrmOptionsArchivers } TfrmOptionsArchivers = class(TOptionsEditor) chkFileNameOnlyList: TCheckBox; pnlFileNameOnlyList: TPanel; pnlArchiverListbox: TPanel; lblArchiverListBox: TLabel; lbxArchiver: TListBox; splArchiver: TSplitter; pnlArchiverCommands: TPanel; pnlArchiverButtons: TPanel; chkArchiverEnabled: TCheckBox; btnArchiverApply: TBitBtn; btnArchiverAdd: TBitBtn; btnArchiverCopy: TBitBtn; btnArchiverRename: TBitBtn; btnArchiverDelete: TBitBtn; btnArchiverOther: TBitBtn; pcArchiverCommands: TPageControl; tbArchiverGeneral: TTabSheet; lblArchiverDescription: TLabel; edtArchiverDescription: TEdit; lblArchiverArchiver: TLabel; edtArchiverArchiver: TEdit; btnArchiverSelectFileArchiver: TSpeedButton; btnArchiverRelativer: TSpeedButton; lblArchiverExtension: TLabel; edtArchiverExtension: TEdit; lblArchiverList: TLabel; edtArchiverList: TEdit; btnArchiverListHelper: TSpeedButton; lblArchiverListStart: TLabel; edtArchiverListStart: TEdit; lblArchiverListEnd: TLabel; edtArchiverListEnd: TEdit; lblArchiverListFormat: TLabel; memArchiverListFormat: TMemo; lblArchiverExtract: TLabel; edtArchiverExtract: TEdit; btnArchiverExtractHelper: TSpeedButton; lblArchiverAdd: TLabel; edtArchiverAdd: TEdit; btnArchiverAddHelper: TSpeedButton; tbArchiverAdditional: TTabSheet; lblArchiverDelete: TLabel; edtArchiverDelete: TEdit; btnArchiverDeleteHelper: TSpeedButton; lblArchiverTest: TLabel; edtArchiverTest: TEdit; btnArchiverTestHelper: TSpeedButton; lblArchiverExtractWithoutPath: TLabel; edtArchiverExtractWithoutPath: TEdit; btnArchiverExtractWithoutPathHelper: TSpeedButton; lblArchiverSelfExtract: TLabel; edtArchiverSelfExtract: TEdit; btnArchiverSelfExtractHelper: TSpeedButton; lblArchiverPasswordQuery: TLabel; edtArchiverPasswordQuery: TEdit; bvlArchiverIds: TDividerBevel; lblArchiverIds: TLabel; edtArchiverId: TEdit; lblArchiverIdPosition: TLabel; edtArchiverIdPosition: TEdit; lblArchiverIdSeekRange: TLabel; edtArchiverIdSeekRange: TEdit; bvlArchiverParsingMode: TDividerBevel; ckbArchiverUnixPath: TCheckBox; ckbArchiverWindowsPath: TCheckBox; ckbArchiverUnixFileAttributes: TCheckBox; ckbArchiverWindowsFileAttributes: TCheckBox; bvlArchiverOptions: TDividerBevel; chkArchiverMultiArcOutput: TCheckBox; chkArchiverMultiArcDebug: TCheckBox; pmArchiverOther: TPopupMenu; miArchiverAutoConfigure: TMenuItem; miArchiverDiscardModification: TMenuItem; miSeparator1: TMenuItem; miArchiverSortArchivers: TMenuItem; miArchiverDisableAll: TMenuItem; miArchiverEnableAll: TMenuItem; miSeparator2: TMenuItem; miArchiverExport: TMenuItem; miArchiverImport: TMenuItem; pmArchiverPathHelper: TPopupMenu; pmArchiverParamHelper: TPopupMenu; SaveArchiverDialog: TSaveDialog; OpenArchiverDialog: TOpenDialog; procedure chkFileNameOnlyListChange(Sender: TObject); procedure lbxArchiverSelectionChange(Sender: TObject; {%H-}User: boolean); procedure lbxArchiverDragOver(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure lbxArchiverDragDrop(Sender, {%H-}Source: TObject; {%H-}X, Y: integer); procedure edtAnyChange(Sender: TObject); procedure ckbArchiverUnixPathChange(Sender: TObject); procedure ckbArchiverWindowsPathChange(Sender: TObject); procedure ckbArchiverUnixFileAttributesChange(Sender: TObject); procedure ckbArchiverWindowsFileAttributesChange(Sender: TObject); procedure chkArchiverEnabledChange(Sender: TObject); procedure SetConfigurationState(bConfigurationSaved: boolean); procedure SetControlsState(bWantedState: boolean); procedure SetActiveButtonsBasedOnArchiversQuantity; procedure ActualSaveCurrentMultiArcItem; procedure btnArchiverApplyClick(Sender: TObject); procedure btnArchiverAddClick(Sender: TObject); procedure btnArchiverCopyClick(Sender: TObject); procedure btnArchiverRenameClick(Sender: TObject); procedure btnArchiverDeleteClick(Sender: TObject); procedure btnArchiverOtherClick(Sender: TObject); procedure miArchiverAutoConfigureClick(Sender: TObject); procedure miArchiverDiscardModificationClick(Sender: TObject); procedure miArchiverSortArchiversClick(Sender: TObject); procedure miAdjustEnableAllClick(Sender: TObject); procedure miArchiverExportClick(Sender: TObject); procedure miArchiverImportClick(Sender: TObject); procedure miHelperClick(Sender: TObject); procedure btnHelperClick(Sender: TObject); procedure btnArchiverSelectFileArchiverClick(Sender: TObject); procedure btnArchiverRelativerClick(Sender: TObject); procedure PopulateParamHelperMenu; private MultiArcListTemp: TMultiArcList; bCurrentlyFilling: boolean; bCurrentlyLoadingSettings: boolean; edtHelperRequested: TEdit; //Used as a kind of pointer of TEdit when it's time to use the % helper. procedure FillListBoxWithArchiverList; protected procedure Init; override; procedure Load; override; procedure Done; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. //DC DCStrUtils, uGlobs, uLng, uSpecialDir, uGlobsPaths, uShowMsg; const CONFIG_NOTSAVED = False; CONFIG_SAVED = True; var iLastDisplayedIndex: integer = -1; { TfrmOptionsArchivers } { TfrmOptionsArchivers.Init } procedure TfrmOptionsArchivers.Init; begin OpenArchiverDialog.Filter := ParseLineToFileFilter([rsFilterArchiverConfigFiles, '*.ini;*.addon', rsFilterAnyFiles, AllFilesMask]); SaveArchiverDialog.Filter := ParseLineToFileFilter([rsFilterArchiverConfigFiles, '*.ini', rsFilterAnyFiles, AllFilesMask]); end; { TfrmOptionsArchivers.Load } procedure TfrmOptionsArchivers.Load; begin bCurrentlyLoadingSettings := True; bCurrentlyFilling := True; btnArchiverSelectFileArchiver.Hint := rsOptArchiverArchiver; FreeAndNil(MultiArcListTemp); MultiArcListTemp := gMultiArcList.Clone; FillListBoxWithArchiverList; gSpecialDirList.PopulateMenuWithSpecialDir(pmArchiverPathHelper, mp_PATHHELPER, nil); PopulateParamHelperMenu; pcArchiverCommands.ActivePage := tbArchiverGeneral; end; { TfrmOptionsArchivers.Done } procedure TfrmOptionsArchivers.Done; begin if lbxArchiver.ItemIndex <> -1 then if lbxArchiver.ItemIndex < MultiArcListTemp.Count then iLastDisplayedIndex := lbxArchiver.ItemIndex; // Let's preserve the last item we were at to select it if we come back here in this session. FreeAndNil(MultiArcListTemp); end; { TfrmOptionsArchivers.Save } function TfrmOptionsArchivers.Save: TOptionsEditorSaveFlags; begin Result := []; if not lbxArchiver.Enabled then ActualSaveCurrentMultiArcItem; MultiArcListTemp.SaveToFile(gpCfgDir + sMULTIARC_FILENAME); FreeAndNil(gMultiArcList); gMultiArcList := MultiArcListTemp.Clone; LastLoadedOptionSignature := ComputeCompleteOptionsSignature; end; { TfrmOptionsArchivers.GetIconIndex } class function TfrmOptionsArchivers.GetIconIndex: integer; begin Result := 18; end; { TfrmOptionsArchivers.GetTitle } class function TfrmOptionsArchivers.GetTitle: string; begin Result := rsOptionsEditorArchivers; end; { TfrmOptionsArchivers.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsArchivers.IsSignatureComputedFromAllWindowComponents: boolean; begin Result := False; end; { TfrmOptionsArchivers.ExtraOptionsSignature } function TfrmOptionsArchivers.ExtraOptionsSignature(CurrentSignature: dword): dword; begin if not lbxArchiver.Enabled then //If currently our Listbox is disabled, it's because we did at least one modification... Result := (LastLoadedOptionSignature xor $01) //...so let's make sure the reported signature for the whole thing is affected. else Result := MultiArcListTemp.ComputeSignature(CurrentSignature); end; { TfrmOptionsArchivers.FillListBoxWithArchiverList } procedure TfrmOptionsArchivers.FillListBoxWithArchiverList; var I, iRememberIndex: integer; begin bCurrentlyFilling := True; iRememberIndex := lbxArchiver.ItemIndex; lbxArchiver.Clear; for I := 0 to MultiArcListTemp.Count - 1 do lbxArchiver.Items.AddObject(MultiArcListTemp.Names[I], MultiArcListTemp[I]); pcArchiverCommands.Enabled := (lbxArchiver.Items.Count <> 0); chkArchiverEnabled.Enabled := (lbxArchiver.Items.Count <> 0); if lbxArchiver.Items.Count > 0 then begin if (iRememberIndex <> -1) and (iRememberIndex < lbxArchiver.Items.Count) then lbxArchiver.ItemIndex := iRememberIndex else if (iLastDisplayedIndex <> -1) and (iLastDisplayedIndex < lbxArchiver.Items.Count) then lbxArchiver.ItemIndex := iLastDisplayedIndex else lbxArchiver.ItemIndex := 0; end; SetActiveButtonsBasedOnArchiversQuantity; btnArchiverApply.Enabled := False; bCurrentlyFilling := False; lbxArchiverSelectionChange(lbxArchiver, False); end; { TfrmOptionsArchivers.lbxArchiverSelectionChange } procedure TfrmOptionsArchivers.lbxArchiverSelectionChange(Sender: TObject; User: boolean); begin if not bCurrentlyFilling then begin bCurrentlyLoadingSettings := True; if lbxArchiver.ItemIndex < 0 then begin edtArchiverDescription.Text := EmptyStr; edtArchiverArchiver.Text := EmptyStr; edtArchiverExtension.Text := EmptyStr; edtArchiverList.Text := EmptyStr; edtArchiverListStart.Text := EmptyStr; edtArchiverListEnd.Text := EmptyStr; memArchiverListFormat.Lines.Clear; edtArchiverExtract.Text := EmptyStr; edtArchiverAdd.Text := EmptyStr; edtArchiverDelete.Text := EmptyStr; edtArchiverTest.Text := EmptyStr; edtArchiverExtractWithoutPath.Text := EmptyStr; edtArchiverSelfExtract.Text := EmptyStr; edtArchiverPasswordQuery.Text := EmptyStr; edtArchiverId.Text := EmptyStr; edtArchiverIdPosition.Text := EmptyStr; edtArchiverIdSeekRange.Text := EmptyStr; ckbArchiverUnixPath.Checked := False; ckbArchiverWindowsPath.Checked := False; ckbArchiverUnixFileAttributes.Checked := False; ckbArchiverWindowsFileAttributes.Checked := False; chkArchiverMultiArcOutput.Checked := False; chkArchiverMultiArcDebug.Checked := False; chkArchiverEnabled.Checked := False; pcArchiverCommands.Enabled := (lbxArchiver.Items.Count <> 0); chkArchiverEnabled.Enabled := (lbxArchiver.Items.Count <> 0); end else begin with TMultiArcItem(lbxArchiver.Items.Objects[lbxArchiver.ItemIndex]) do begin edtArchiverDescription.Text := FDescription; edtArchiverArchiver.Text := FArchiver; edtArchiverExtension.Text := FExtension; edtArchiverList.Text := FList; edtArchiverListStart.Text := FStart; edtArchiverListEnd.Text := FEnd; memArchiverListFormat.Lines.Assign(FFormat); edtArchiverExtract.Text := FExtract; edtArchiverAdd.Text := FAdd; edtArchiverDelete.Text := FDelete; edtArchiverTest.Text := FTest; edtArchiverExtractWithoutPath.Text := FExtractWithoutPath; edtArchiverSelfExtract.Text := FAddSelfExtract; edtArchiverPasswordQuery.Text := FPasswordQuery; edtArchiverId.Text := FID; edtArchiverIdPosition.Text := FIDPos; edtArchiverIdSeekRange.Text := FIDSeekRange; chkFileNameOnlyList.Checked:= mafFileNameList in FFlags; ckbArchiverUnixPath.Checked := (FFormMode and $01 <> $00); ckbArchiverWindowsPath.Checked := (FFormMode and $02 <> $00); ckbArchiverUnixFileAttributes.Checked := (FFormMode and $04 <> $00); ckbArchiverWindowsFileAttributes.Checked := (FFormMode and $08 <> $00); chkArchiverMultiArcOutput.Checked := FOutput; chkArchiverMultiArcDebug.Checked := FDebug; chkArchiverEnabled.Checked := FEnabled; end; end; chkFileNameOnlyListChange(chkFileNameOnlyList); SetControlsState(chkArchiverEnabled.Checked); SetConfigurationState(CONFIG_SAVED); bCurrentlyLoadingSettings := False; end; end; procedure TfrmOptionsArchivers.chkFileNameOnlyListChange(Sender: TObject); var AEnabled: Boolean; begin AEnabled:= (not chkFileNameOnlyList.Checked) and chkArchiverEnabled.Checked; edtArchiverList.Enabled:= AEnabled; btnArchiverListHelper.Enabled:= AEnabled; edtArchiverListStart.Enabled:= AEnabled; edtArchiverListEnd.Enabled:= AEnabled; memArchiverListFormat.Enabled:= AEnabled; edtAnyChange(Sender); end; { TfrmOptionsArchivers.lbxArchiverDragOver } procedure TfrmOptionsArchivers.lbxArchiverDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin Accept := True; end; { TfrmOptionsArchivers.lbxArchiverDragDrop } procedure TfrmOptionsArchivers.lbxArchiverDragDrop(Sender, Source: TObject; X, Y: integer); var SrcIndex, DestIndex: integer; begin SrcIndex := lbxArchiver.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lbxArchiver.GetIndexAtY(Y); if (DestIndex < 0) or (DestIndex >= lbxArchiver.Count) then DestIndex := lbxArchiver.Count - 1; lbxArchiver.Items.Move(SrcIndex, DestIndex); MultiArcListTemp.FList.Move(SrcIndex, DestIndex); lbxArchiver.ItemIndex := DestIndex; lbxArchiverSelectionChange(lbxArchiver, False); end; { TfrmOptionsArchivers.edtAnyChange } procedure TfrmOptionsArchivers.edtAnyChange(Sender: TObject); begin if not bCurrentlyLoadingSettings then if lbxArchiver.Enabled then SetConfigurationState(CONFIG_NOTSAVED); end; { TfrmOptionsArchivers.ckbArchiverUnixPathChange } procedure TfrmOptionsArchivers.ckbArchiverUnixPathChange(Sender: TObject); begin if TCheckBox(Sender).Checked then if ckbArchiverWindowsPath.Checked then ckbArchiverWindowsPath.Checked := False; edtAnyChange(Sender); end; { TfrmOptionsArchivers.ckbArchiverWindowsPathChange } procedure TfrmOptionsArchivers.ckbArchiverWindowsPathChange(Sender: TObject); begin if TCheckbox(Sender).Checked then if ckbArchiverUnixPath.Checked then ckbArchiverUnixPath.Checked := False; edtAnyChange(Sender); end; { TfrmOptionsArchivers.ckbArchiverUnixFileAttributesChange } procedure TfrmOptionsArchivers.ckbArchiverUnixFileAttributesChange(Sender: TObject); begin if TCheckBox(Sender).Checked then if ckbArchiverWindowsFileAttributes.Checked then ckbArchiverWindowsFileAttributes.Checked := False; edtAnyChange(Sender); end; { TfrmOptionsArchivers.ckbArchiverWindowsFileAttributesChange } procedure TfrmOptionsArchivers.ckbArchiverWindowsFileAttributesChange(Sender: TObject); begin if TCheckBox(Sender).Checked then if ckbArchiverUnixFileAttributes.Checked then ckbArchiverUnixFileAttributes.Checked := False; edtAnyChange(Sender); end; { TfrmOptionsArchivers.chkArchiverEnabledChange } procedure TfrmOptionsArchivers.chkArchiverEnabledChange(Sender: TObject); begin if not bCurrentlyLoadingSettings then begin SetControlsState(chkArchiverEnabled.Checked); edtAnyChange(Sender); end; end; { TfrmOptionsArchivers.SetConfigurationState } procedure TfrmOptionsArchivers.SetConfigurationState(bConfigurationSaved: boolean); begin if lbxArchiver.Enabled <> bConfigurationSaved then begin lbxArchiver.Enabled := bConfigurationSaved; btnArchiverApply.Enabled := not bConfigurationSaved; btnArchiverAdd.Enabled := bConfigurationSaved; btnArchiverCopy.Enabled := bConfigurationSaved; btnArchiverRename.Enabled := bConfigurationSaved; miArchiverImport.Enabled := bConfigurationSaved; miArchiverSortArchivers.Enabled := bConfigurationSaved; miArchiverExport.Enabled := bConfigurationSaved; miArchiverDiscardModification.Enabled := not bConfigurationSaved; miArchiverDisableAll.Enabled := bConfigurationSaved; miArchiverEnableAll.Enabled := bConfigurationSaved; if bConfigurationSaved = CONFIG_SAVED then lbxArchiver.Hint := '' else lbxArchiver.Hint := rsOptArchiveConfigureSaveToChange; end; end; { TfrmOptionsArchivers.SetControlsState } procedure TfrmOptionsArchivers.SetControlsState(bWantedState: boolean); var iComponentIndex: integer; begin if lbxArchiver.ItemIndex < 0 then Exit; TMultiArcItem(lbxArchiver.Items.Objects[lbxArchiver.ItemIndex]).FEnabled := bWantedState; if bWantedState <> edtArchiverDescription.Enabled then //Let's use "edtDescription" as a reference. for iComponentIndex := 0 to pred(ComponentCount) do if Components[iComponentIndex].Owner <> nil then if Components[iComponentIndex].InheritsFrom(TControl) then if (TControl(Components[iComponentIndex]).Parent = tbArchiverGeneral) or (TControl(Components[iComponentIndex]).Parent = tbArchiverAdditional) then if Components[iComponentIndex].Name <> chkArchiverEnabled.Name then TControl(Components[iComponentIndex]).Enabled := bWantedState; end; { TfrmOptionsArchivers.SetActiveButtonsBasedOnArchiversQuantity } procedure TfrmOptionsArchivers.SetActiveButtonsBasedOnArchiversQuantity; begin btnArchiverCopy.Enabled := ((lbxArchiver.Items.Count > 0) and (lbxArchiver.Enabled)); btnArchiverRename.Enabled := btnArchiverCopy.Enabled; btnArchiverDelete.Enabled := btnArchiverCopy.Enabled; miArchiverAutoConfigure.Enabled := btnArchiverCopy.Enabled; miArchiverSortArchivers.Enabled := ((lbxArchiver.Items.Count > 1) and (lbxArchiver.Enabled)); miArchiverExport.Enabled := btnArchiverCopy.Enabled; end; { TfrmOptionsArchivers.ActualSaveCurrentMultiArcItem } procedure TfrmOptionsArchivers.ActualSaveCurrentMultiArcItem; begin if lbxArchiver.ItemIndex < 0 then Exit; with TMultiArcItem(lbxArchiver.Items.Objects[lbxArchiver.ItemIndex]) do begin FPacker := lbxArchiver.Items[lbxArchiver.ItemIndex]; FDescription := edtArchiverDescription.Text; FArchiver := edtArchiverArchiver.Text; FExtension := edtArchiverExtension.Text; FList := edtArchiverList.Text; FStart := edtArchiverListStart.Text; FEnd := edtArchiverListEnd.Text; FFormat.Assign(memArchiverListFormat.Lines); FExtract := edtArchiverExtract.Text; FAdd := edtArchiverAdd.Text; FDelete := edtArchiverDelete.Text; FTest := edtArchiverTest.Text; FExtractWithoutPath := edtArchiverExtractWithoutPath.Text; FAddSelfExtract := edtArchiverSelfExtract.Text; FPasswordQuery := edtArchiverPasswordQuery.Text; FID := edtArchiverId.Text; FIDPos := edtArchiverIdPosition.Text; FIDSeekRange := edtArchiverIdSeekRange.Text; FFlags := []; if chkFileNameOnlyList.Checked then Include(FFlags, mafFileNameList); FFormMode := 0; if ckbArchiverUnixPath.Checked then FFormMode := FFormMode or $01; if ckbArchiverWindowsPath.Checked then FFormMode := FFormMode or $02; if ckbArchiverUnixFileAttributes.Checked then FFormMode := FFormMode or $04; if ckbArchiverWindowsFileAttributes.Checked then FFormMode := FFormMode or $08; FOutput := chkArchiverMultiArcOutput.Checked; FDebug := chkArchiverMultiArcDebug.Checked; SetConfigurationState(CONFIG_SAVED); end; end; { TfrmOptionsArchivers.btnArchiverApplyClick } procedure TfrmOptionsArchivers.btnArchiverApplyClick(Sender: TObject); begin Save; if lbxArchiver.CanFocus then lbxArchiver.SetFocus; end; { TfrmOptionsArchivers.btnArchiverAddClick } procedure TfrmOptionsArchivers.btnArchiverAddClick(Sender: TObject); var sName: string; MultiArcItem: TMultiArcItem; begin if InputQuery(Caption, rsOptArchiveTypeName, sName) then begin MultiArcItem := TMultiArcItem.Create; MultiArcItem.FEnabled:=True; lbxArchiver.Items.AddObject(sName, MultiArcItem); MultiArcListTemp.Add(sName, MultiArcItem); lbxArchiver.ItemIndex := lbxArchiver.Items.Count - 1; lbxArchiverSelectionChange(lbxArchiver, False); pcArchiverCommands.Enabled := (lbxArchiver.Items.Count <> 0); chkArchiverEnabled.Enabled := (lbxArchiver.Items.Count <> 0); SetActiveButtonsBasedOnArchiversQuantity; if pcArchiverCommands.ActivePage<>tbArchiverGeneral then pcArchiverCommands.ActivePage:=tbArchiverGeneral; if edtArchiverDescription.CanFocus then edtArchiverDescription.SetFocus; end; end; { TfrmOptionsArchivers.btnArchiverCopyClick } procedure TfrmOptionsArchivers.btnArchiverCopyClick(Sender: TObject); var ANewMultiArcItem: TMultiArcItem; sCurrentSelectedName, sNewName: string; iIndexCopy, iPosOpenPar, iNewInsertedPosition: integer; begin if lbxArchiver.ItemIndex < 0 then Exit; sCurrentSelectedName := lbxArchiver.Items.Strings[lbxArchiver.ItemIndex]; if LastDelimiter(')', sCurrentSelectedName) = length(sCurrentSelectedName) then begin iPosOpenPar := LastDelimiter('(', sCurrentSelectedName); if (iPosOpenPar > 0) and (iPosOpenPar > (length(sCurrentSelectedName) - 4)) then sCurrentSelectedName := LeftStr(sCurrentSelectedName, pred(pred(iPosOpenPar))); end; iIndexCopy := 2; while lbxArchiver.Items.IndexOf(Format('%s (%d)', [sCurrentSelectedName, iIndexCopy])) <> -1 do Inc(iIndexCopy); sNewName := Format('%s (%d)', [sCurrentSelectedName, iIndexCopy]); ANewMultiArcItem := TMultiArcItem(lbxArchiver.Items.Objects[lbxArchiver.ItemIndex]).Clone; //Let's place our copy right after the original one. iNewInsertedPosition := succ(lbxArchiver.ItemIndex); if iNewInsertedPosition < MultiArcListTemp.Count then begin lbxArchiver.Items.InsertObject(iNewInsertedPosition, sNewName, ANewMultiArcItem); MultiArcListTemp.Insert(iNewInsertedPosition, sNewName, aNewMultiArcItem); end else begin lbxArchiver.Items.AddObject(sNewName, ANewMultiArcItem); MultiArcListTemp.Add(sNewName, aNewMultiArcItem); end; lbxArchiver.ItemIndex := iNewInsertedPosition; SetActiveButtonsBasedOnArchiversQuantity; end; { TfrmOptionsArchivers.btnArchiverRenameClick } procedure TfrmOptionsArchivers.btnArchiverRenameClick(Sender: TObject); var sNewName: string; begin if lbxArchiver.ItemIndex < 0 then Exit; sNewName := lbxArchiver.Items[lbxArchiver.ItemIndex]; if InputQuery(Caption, rsOptArchiveTypeName, sNewName) then begin lbxArchiver.Items[lbxArchiver.ItemIndex] := sNewName; MultiArcListTemp.Names[lbxArchiver.ItemIndex] := sNewName; end; end; { TfrmOptionsArchivers.btnArchiverDeleteClick } procedure TfrmOptionsArchivers.btnArchiverDeleteClick(Sender: TObject); var iIndexDelete: integer; begin if lbxArchiver.ItemIndex < 0 then Exit; if MsgBox(Format(rsOptArchiverConfirmDelete, [lbxArchiver.Items.Strings[lbxArchiver.ItemIndex]]), [msmbYes, msmbCancel], msmbCancel, msmbCancel) = mmrYes then begin iIndexDelete := lbxArchiver.ItemIndex; lbxArchiver.Items.Delete(iIndexDelete); MultiArcListTemp.Delete(iIndexDelete); if iIndexDelete >= MultiArcListTemp.Count then lbxArchiver.ItemIndex := lbxArchiver.Items.Count - 1 else lbxArchiver.ItemIndex := iIndexDelete; pcArchiverCommands.Enabled := (lbxArchiver.Items.Count <> 0); chkArchiverEnabled.Enabled := (lbxArchiver.Items.Count <> 0); lbxArchiverSelectionChange(lbxArchiver, False); if lbxArchiver.CanFocus then lbxArchiver.SetFocus; end; SetActiveButtonsBasedOnArchiversQuantity; end; { TfrmOptionsArchivers.btnArchiverOtherClick } procedure TfrmOptionsArchivers.btnArchiverOtherClick(Sender: TObject); var pWantedPos: TPoint; begin pWantedPos := btnArchiverOther.ClientToScreen(Point(btnArchiverOther.Width div 2, btnArchiverOther.Height - 5)); // Position this way instead of using mouse cursor since it will work for keyboard user. pmArchiverOther.PopUp(pWantedPos.X, pWantedPos.Y); end; { TfrmOptionsArchivers.miArchiverAutoConfigureClick } procedure TfrmOptionsArchivers.miArchiverAutoConfigureClick(Sender: TObject); begin MultiArcListTemp.AutoConfigure; lbxArchiverSelectionChange(lbxArchiver, False); end; { TfrmOptionsArchivers.miArchiverDiscardModificationClick } procedure TfrmOptionsArchivers.miArchiverDiscardModificationClick(Sender: TObject); begin if MultiArcListTemp <> nil then MultiArcListTemp.Free; MultiArcListTemp := gMultiArcList.Clone; lbxArchiverSelectionChange(lbxArchiver, False); end; { TfrmOptionsArchivers.miArchiverSortArchiversClick } procedure TfrmOptionsArchivers.miArchiverSortArchiversClick(Sender: TObject); begin if MultiArcListTemp.Count > 0 then begin MultiArcListTemp.FList.Sort; FillListBoxWithArchiverList; lbxArchiver.ItemIndex := 0; lbxArchiverSelectionChange(lbxArchiver, False); end; end; { TfrmOptionsArchivers.miAdjustEnableAllClick } procedure TfrmOptionsArchivers.miAdjustEnableAllClick(Sender: TObject); var iIndex: integer; begin for iIndex := 0 to pred(MultiArcListTemp.Count) do MultiArcListTemp.Items[iIndex].FEnabled := (TComponent(Sender).Tag = 1); lbxArchiverSelectionChange(lbxArchiver, False); end; { TfrmOptionsArchivers.miArchiverExportClick } procedure TfrmOptionsArchivers.miArchiverExportClick(Sender: TObject); var slValueList, slOutputIndexSelected: TStringList; ExportedMultiArcList: TMultiArcList; iIndex, iExportedIndex: integer; begin if MultiArcListTemp.Count > 0 then begin slValueList := TStringList.Create; slOutputIndexSelected := TStringList.Create; try for iIndex := 0 to pred(MultiArcListTemp.Count) do slValueList.Add(MultiArcListTemp.FList.Strings[iIndex]); if ShowInputMultiSelectListBox(rsOptArchiverExportCaption, rsOptArchiverExportPrompt, slValueList, slOutputIndexSelected) then begin ExportedMultiArcList := TMultiArcList.Create; try for iIndex := 0 to pred(slOutputIndexSelected.Count) do begin iExportedIndex := StrToIntDef(slOutputIndexSelected.Strings[iIndex], -1); if iExportedIndex <> -1 then ExportedMultiArcList.Add(MultiArcListTemp.FList.Strings[iExportedIndex], MultiArcListTemp.Items[iExportedIndex].Clone); end; if ExportedMultiArcList.Count > 0 then begin SaveArchiverDialog.DefaultExt := '*.ini'; SaveArchiverDialog.FilterIndex := 1; SaveArchiverDialog.Title := rsOptArchiverWhereToSave; SaveArchiverDialog.FileName := rsOptArchiverDefaultExportFilename; if SaveArchiverDialog.Execute then begin ExportedMultiArcList.SaveToFile(SaveArchiverDialog.FileName); msgOK(Format(rsOptArchiverExportDone, [ExportedMultiArcList.Count, SaveArchiverDialog.FileName])); end; end; finally ExportedMultiArcList.Free; end; end; finally slOutputIndexSelected.Free; slValueList.Free; end; end; end; { TfrmOptionsArchivers.miArchiverImportClick } procedure TfrmOptionsArchivers.miArchiverImportClick(Sender: TObject); var ImportedMultiArcList: TMultiArcList; slValueList, slOutputIndexSelected: TStringList; iIndex, iImportedIndex, iNbImported: integer; begin OpenArchiverDialog.DefaultExt := '*.ini'; OpenArchiverDialog.FilterIndex := 1; OpenArchiverDialog.Title := rsOptArchiverImportFile; if OpenArchiverDialog.Execute then begin ImportedMultiArcList := TMultiArcList.Create; try ImportedMultiArcList.LoadFromFile(OpenArchiverDialog.FileName); if ImportedMultiArcList.Count > 0 then begin slValueList := TStringList.Create; slOutputIndexSelected := TStringList.Create; try for iIndex := 0 to pred(ImportedMultiArcList.Count) do slValueList.Add(ImportedMultiArcList.FList.Strings[iIndex]); if ShowInputMultiSelectListBox(rsOptArchiverImportCaption, rsOptArchiverImportPrompt, slValueList, slOutputIndexSelected) then begin iNbImported := 0; for iIndex := 0 to pred(slOutputIndexSelected.Count) do begin iImportedIndex := StrToIntDef(slOutputIndexSelected.Strings[iIndex], -1); if iImportedIndex <> -1 then begin MultiArcListTemp.Add(ImportedMultiArcList.FList.Strings[iImportedIndex], ImportedMultiArcList.Items[iImportedIndex].Clone); lbxArchiver.Items.AddObject(MultiArcListTemp.FList.Strings[pred(MultiArcListTemp.Count)], MultiArcListTemp.Items[pred(MultiArcListTemp.Count)]); MultiArcListTemp.Items[pred(MultiArcListTemp.Count)].FEnabled := True; //; Inc(iNbImported); end; end; lbxArchiver.ItemIndex := lbxArchiver.Items.Count - 1; if iNbImported > 0 then begin SetActiveButtonsBasedOnArchiversQuantity; msgOK(Format(rsOptArchiverImportDone, [iNbImported, OpenArchiverDialog.FileName])); end; end; finally slOutputIndexSelected.Free; slValueList.Free; end; end; finally ImportedMultiArcList.Free; end; end; end; { TfrmOptionsArchivers.miHelperClick } procedure TfrmOptionsArchivers.miHelperClick(Sender: TObject); begin if edtHelperRequested <> nil then edtHelperRequested.SelText := Trim(LeftStr(TMenuItem(Sender).Caption, pred(pos('-', TMenuItem(Sender).Caption)))); end; { TfrmOptionsArchivers.btnHelperClick } procedure TfrmOptionsArchivers.btnHelperClick(Sender: TObject); begin edtHelperRequested := TEdit(TSpeedButton(Sender).AnchorSideTop.Control); pmArchiverParamHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsArchivers.btnArchiverSlectFileArchiverClick } procedure TfrmOptionsArchivers.btnArchiverSelectFileArchiverClick(Sender: TObject); begin OpenArchiverDialog.DefaultExt := '*.*'; OpenArchiverDialog.FilterIndex := 2; OpenArchiverDialog.Title := rsOptArchiverArchiver; if OpenArchiverDialog.Execute then begin edtArchiverArchiver.Text := OpenArchiverDialog.FileName; end; end; { TfrmOptionsArchivers.btnArchiverRelativerClick } procedure TfrmOptionsArchivers.btnArchiverRelativerClick(Sender: TObject); begin if edtArchiverArchiver.CanFocus then edtArchiverArchiver.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edtArchiverArchiver, pfFILE); pmArchiverPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsArchivers.PopulateParamHelperMenu } procedure TfrmOptionsArchivers.PopulateParamHelperMenu; procedure AddThisItem(sParameter, sDescription: string); var AMenuItem: TMenuItem; begin AMenuItem := TMenuItem.Create(pmArchiverParamHelper); if sDescription <> '' then begin AMenuItem.Caption := Format('%s - %s', [sParameter, sDescription]); AMenuItem.OnClick := @miHelperClick; end else AMenuItem.Caption := sParameter; pmArchiverParamHelper.Items.Add(AMenuItem); end; begin pmArchiverParamHelper.Items.Clear; AddThisItem('%P', rsOptArchiverProgramL); AddThisItem('%p', rsOptArchiverProgramS); AddThisItem('%A', rsOptArchiverArchiveL); AddThisItem('%a', rsOptArchiverArchiveS); AddThisItem('%L', rsOptArchiverFileListL); AddThisItem('%l', rsOptArchiverFileListS); AddThisItem('%F', rsOptArchiverSingleFProcess); AddThisItem('%E', rsOptArchiverErrorLevel); AddThisItem('%O', rsOptArchiverChangeEncoding); AddThisItem('%R', rsOptArchiverTargetSubDir); AddThisItem('%S', rsOptArchiverAdditonalCmd); AddThisItem('{}', rsOptArchiverAddOnlyNotEmpty); AddThisItem('-', ''); AddThisItem('Q', rsOptArchiverQuoteWithSpace); AddThisItem('q', rsOptArchiverQuoteAll); AddThisItem('W', rsOptArchiverJustName); AddThisItem('P', rsOptArchiverJustPath); AddThisItem('A', rsOptArchiverUseAnsi); AddThisItem('U', rsOptArchiverUseUTF8); end; end. ����������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsautorefresh.lfm�������������������������������������������������0000644�0001750�0000144�00000005746�14743153644�021477� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsAutoRefresh: TfrmOptionsAutoRefresh Height = 228 Width = 501 HelpKeyword = '/configuration.html#ConfigRefresh' ClientHeight = 228 ClientWidth = 501 DesignTop = 27 object gbAutoRefreshEnable: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 82 Top = 6 Width = 489 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Refresh file list' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 5 ChildSizing.VerticalSpacing = 3 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 59 ClientWidth = 485 TabOrder = 0 object cbWatchFileNameChange: TCheckBox Left = 10 Height = 23 Top = 5 Width = 309 Caption = 'When &files are created, deleted or renamed' OnChange = OnAutoRefreshOptionChanged TabOrder = 0 end object cbWatchAttributesChange: TCheckBox Left = 10 Height = 23 Top = 31 Width = 309 Caption = 'When &size, date or attributes change' OnChange = OnAutoRefreshOptionChanged TabOrder = 1 end end object gbAutoRefreshDisable: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbAutoRefreshEnable AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 117 Top = 94 Width = 489 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Disable auto-refresh' ChildSizing.TopBottomSpacing = 5 ChildSizing.VerticalSpacing = 3 ClientHeight = 94 ClientWidth = 485 TabOrder = 1 object cbWatchOnlyForeground: TCheckBox AnchorSideLeft.Control = gbAutoRefreshDisable AnchorSideTop.Control = gbAutoRefreshDisable Left = 10 Height = 23 Top = 5 Width = 269 BorderSpacing.Left = 10 Caption = 'When application is in the &background' TabOrder = 0 end object cbWatchExcludeDirs: TCheckBox AnchorSideLeft.Control = cbWatchOnlyForeground AnchorSideTop.Control = cbWatchOnlyForeground AnchorSideTop.Side = asrBottom Left = 10 Height = 23 Top = 31 Width = 339 Caption = 'For the following &paths and their subdirectories:' OnChange = cbWatchExcludeDirsChange TabOrder = 1 end object edtWatchExcludeDirs: TEdit AnchorSideLeft.Control = cbWatchExcludeDirs AnchorSideTop.Control = cbWatchExcludeDirs AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbAutoRefreshDisable AnchorSideRight.Side = asrBottom Left = 30 Height = 28 Top = 57 Width = 447 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 20 BorderSpacing.Right = 8 BorderSpacing.Bottom = 15 TabOrder = 2 end end end ��������������������������doublecmd-1.1.22/src/frames/foptionsautorefresh.lrj�������������������������������������������������0000644�0001750�0000144�00000003160�14743153644�021474� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":246808868,"name":"tfrmoptionsautorefresh.gbautorefreshenable.caption","sourcebytes":[82,101,102,114,101,115,104,32,102,105,108,101,32,108,105,115,116],"value":"Refresh file list"}, {"hash":122958068,"name":"tfrmoptionsautorefresh.cbwatchfilenamechange.caption","sourcebytes":[87,104,101,110,32,38,102,105,108,101,115,32,97,114,101,32,99,114,101,97,116,101,100,44,32,100,101,108,101,116,101,100,32,111,114,32,114,101,110,97,109,101,100],"value":"When &files are created, deleted or renamed"}, {"hash":35420293,"name":"tfrmoptionsautorefresh.cbwatchattributeschange.caption","sourcebytes":[87,104,101,110,32,38,115,105,122,101,44,32,100,97,116,101,32,111,114,32,97,116,116,114,105,98,117,116,101,115,32,99,104,97,110,103,101],"value":"When &size, date or attributes change"}, {"hash":245810200,"name":"tfrmoptionsautorefresh.gbautorefreshdisable.caption","sourcebytes":[68,105,115,97,98,108,101,32,97,117,116,111,45,114,101,102,114,101,115,104],"value":"Disable auto-refresh"}, {"hash":126628980,"name":"tfrmoptionsautorefresh.cbwatchonlyforeground.caption","sourcebytes":[87,104,101,110,32,97,112,112,108,105,99,97,116,105,111,110,32,105,115,32,105,110,32,116,104,101,32,38,98,97,99,107,103,114,111,117,110,100],"value":"When application is in the &background"}, {"hash":105351658,"name":"tfrmoptionsautorefresh.cbwatchexcludedirs.caption","sourcebytes":[70,111,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,38,112,97,116,104,115,32,97,110,100,32,116,104,101,105,114,32,115,117,98,100,105,114,101,99,116,111,114,105,101,115,58],"value":"For the following &paths and their subdirectories:"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsautorefresh.pas�������������������������������������������������0000644�0001750�0000144�00000007036�14743153644�021476� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Auto-refresh options page Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsAutoRefresh; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, fOptionsFrame; type { TfrmOptionsAutoRefresh } TfrmOptionsAutoRefresh = class(TOptionsEditor) cbWatchAttributesChange: TCheckBox; cbWatchExcludeDirs: TCheckBox; cbWatchFileNameChange: TCheckBox; cbWatchOnlyForeground: TCheckBox; edtWatchExcludeDirs: TEdit; gbAutoRefreshDisable: TGroupBox; gbAutoRefreshEnable: TGroupBox; procedure cbWatchExcludeDirsChange(Sender: TObject); procedure OnAutoRefreshOptionChanged(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uFileSystemWatcher, uGlobs, uLng; { TfrmOptionsAutoRefresh } procedure TfrmOptionsAutoRefresh.cbWatchExcludeDirsChange(Sender: TObject); begin edtWatchExcludeDirs.Enabled := cbWatchExcludeDirs.Checked; end; procedure TfrmOptionsAutoRefresh.OnAutoRefreshOptionChanged(Sender: TObject); begin gbAutoRefreshDisable.Enabled := cbWatchFileNameChange.Checked or cbWatchAttributesChange.Checked; end; class function TfrmOptionsAutoRefresh.GetIconIndex: Integer; begin Result := 15; end; class function TfrmOptionsAutoRefresh.GetTitle: String; begin Result := rsOptionsEditorAutoRefresh; end; procedure TfrmOptionsAutoRefresh.Init; begin if not (wfAttributesChange in TFileSystemWatcher.AvailableWatchFilter) then cbWatchAttributesChange.Visible := False; end; procedure TfrmOptionsAutoRefresh.Load; begin cbWatchFileNameChange.Checked := (watch_file_name_change in gWatchDirs); cbWatchAttributesChange.Checked := (watch_attributes_change in gWatchDirs); cbWatchOnlyForeground.Checked := (watch_only_foreground in gWatchDirs); cbWatchExcludeDirs.Checked := (watch_exclude_dirs in gWatchDirs); edtWatchExcludeDirs.Text := gWatchDirsExclude; OnAutoRefreshOptionChanged(nil); cbWatchExcludeDirsChange(nil); end; function TfrmOptionsAutoRefresh.Save: TOptionsEditorSaveFlags; begin Result := []; gWatchDirs := []; // Reset watch options if cbWatchFileNameChange.Checked then Include(gWatchDirs, watch_file_name_change); if cbWatchAttributesChange.Checked then Include(gWatchDirs, watch_attributes_change); if cbWatchOnlyForeground.Checked then Include(gWatchDirs, watch_only_foreground); if cbWatchExcludeDirs.Checked then Include(gWatchDirs, watch_exclude_dirs); gWatchDirsExclude:= edtWatchExcludeDirs.Text; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsbehavior.lfm����������������������������������������������������0000644�0001750�0000144�00000007452�14743153644�020743� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsBehavior: TfrmOptionsBehavior Height = 276 Width = 666 HelpKeyword = '/configuration.html#ConfigBehaviors' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 276 ClientWidth = 666 object gbMisc1: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 93 Top = 6 Width = 654 Anchors = [akTop, akLeft, akRight] AutoSize = True ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 6 ClientHeight = 75 ClientWidth = 650 TabOrder = 0 object cbOnlyOnce: TCheckBox AnchorSideLeft.Control = gbMisc1 AnchorSideTop.Control = gbMisc1 AnchorSideRight.Control = gbMisc1 AnchorSideRight.Side = asrBottom Left = 8 Height = 17 Top = 6 Width = 634 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = 'A&llow only one copy of DC at a time' TabOrder = 0 end object cbMinimizeToTray: TCheckBox AnchorSideLeft.Control = gbMisc1 AnchorSideTop.Control = cbOnlyOnce AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMisc1 AnchorSideRight.Side = asrBottom Left = 8 Height = 17 Top = 29 Width = 634 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = 'Mo&ve icon to system tray when minimized' TabOrder = 1 end object cbAlwaysShowTrayIcon: TCheckBox AnchorSideLeft.Control = gbMisc1 AnchorSideTop.Control = cbMinimizeToTray AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMisc1 AnchorSideRight.Side = asrBottom Left = 8 Height = 17 Top = 52 Width = 634 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 Caption = 'Al&ways show tray icon' OnChange = cbAlwaysShowTrayIconChange TabOrder = 2 end end object gbMisc2: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbMisc1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 85 Top = 99 Width = 654 Anchors = [akTop, akLeft, akRight] AutoSize = True ClientHeight = 67 ClientWidth = 650 TabOrder = 1 object lblDrivesBlackList: TLabel AnchorSideLeft.Control = gbMisc2 AnchorSideTop.Control = gbMisc2 Left = 8 Height = 13 Top = 2 Width = 70 BorderSpacing.Left = 8 BorderSpacing.Top = 2 Caption = 'Drives &blacklist' FocusControl = edtDrivesBlackList ParentColor = False end object edtDrivesBlackList: TEdit AnchorSideLeft.Control = lblDrivesBlackList AnchorSideTop.Control = lblDrivesBlackList AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMisc2 AnchorSideRight.Side = asrBottom Left = 8 Height = 21 Hint = 'Here you can enter one or more drives or mount points, separated by ";".' Top = 21 Width = 634 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 8 BorderSpacing.Bottom = 4 ParentShowHint = False ShowHint = True TabOrder = 0 end object cbBlacklistUnmountedDevices: TCheckBox AnchorSideLeft.Control = edtDrivesBlackList AnchorSideTop.Control = edtDrivesBlackList AnchorSideTop.Side = asrBottom Left = 8 Height = 27 Top = 65 Width = 314 BorderSpacing.Bottom = 4 Caption = 'Automatically &hide unmounted devices' TabOrder = 1 end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsbehavior.lrj����������������������������������������������������0000644�0001750�0000144�00000003245�14743153644�020750� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":142894469,"name":"tfrmoptionsbehavior.cbonlyonce.caption","sourcebytes":[65,38,108,108,111,119,32,111,110,108,121,32,111,110,101,32,99,111,112,121,32,111,102,32,68,67,32,97,116,32,97,32,116,105,109,101],"value":"A&llow only one copy of DC at a time"}, {"hash":225240468,"name":"tfrmoptionsbehavior.cbminimizetotray.caption","sourcebytes":[77,111,38,118,101,32,105,99,111,110,32,116,111,32,115,121,115,116,101,109,32,116,114,97,121,32,119,104,101,110,32,109,105,110,105,109,105,122,101,100],"value":"Mo&ve icon to system tray when minimized"}, {"hash":206285982,"name":"tfrmoptionsbehavior.cbalwaysshowtrayicon.caption","sourcebytes":[65,108,38,119,97,121,115,32,115,104,111,119,32,116,114,97,121,32,105,99,111,110],"value":"Al&ways show tray icon"}, {"hash":194611524,"name":"tfrmoptionsbehavior.lbldrivesblacklist.caption","sourcebytes":[68,114,105,118,101,115,32,38,98,108,97,99,107,108,105,115,116],"value":"Drives &blacklist"}, {"hash":228532606,"name":"tfrmoptionsbehavior.edtdrivesblacklist.hint","sourcebytes":[72,101,114,101,32,121,111,117,32,99,97,110,32,101,110,116,101,114,32,111,110,101,32,111,114,32,109,111,114,101,32,100,114,105,118,101,115,32,111,114,32,109,111,117,110,116,32,112,111,105,110,116,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,34,59,34,46],"value":"Here you can enter one or more drives or mount points, separated by \";\"."}, {"hash":217108627,"name":"tfrmoptionsbehavior.cbblacklistunmounteddevices.caption","sourcebytes":[65,117,116,111,109,97,116,105,99,97,108,108,121,32,38,104,105,100,101,32,117,110,109,111,117,110,116,101,100,32,100,101,118,105,99,101,115],"value":"Automatically &hide unmounted devices"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsbehavior.pas����������������������������������������������������0000644�0001750�0000144�00000005532�14743153644�020745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Behavior options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsBehavior; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, ExtCtrls, fOptionsFrame; type { TfrmOptionsBehavior } TfrmOptionsBehavior = class(TOptionsEditor) cbAlwaysShowTrayIcon: TCheckBox; cbMinimizeToTray: TCheckBox; cbOnlyOnce: TCheckBox; cbBlacklistUnmountedDevices: TCheckBox; edtDrivesBlackList: TEdit; gbMisc1: TGroupBox; gbMisc2: TGroupBox; lblDrivesBlackList: TLabel; procedure cbAlwaysShowTrayIconChange(Sender: TObject); protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng; { TfrmOptionsBehavior } procedure TfrmOptionsBehavior.cbAlwaysShowTrayIconChange(Sender: TObject); begin // Force minimizing to tray when tray icon is always shown. cbMinimizeToTray.Enabled:= not cbAlwaysShowTrayIcon.Checked; end; class function TfrmOptionsBehavior.GetIconIndex: Integer; begin Result := 1; end; class function TfrmOptionsBehavior.GetTitle: String; begin Result := rsOptionsEditorBehavior; end; procedure TfrmOptionsBehavior.Load; begin cbOnlyOnce.Checked:= gOnlyOneAppInstance; cbMinimizeToTray.Checked:= gMinimizeToTray; cbMinimizeToTray.Enabled:= not gAlwaysShowTrayIcon; cbAlwaysShowTrayIcon.Checked:= gAlwaysShowTrayIcon; edtDrivesBlackList.Text:= gDriveBlackList; cbBlacklistUnmountedDevices.Checked:= gDriveBlackListUnmounted; end; function TfrmOptionsBehavior.Save: TOptionsEditorSaveFlags; begin Result := []; gOnlyOneAppInstance:=cbOnlyOnce.Checked; gMinimizeToTray:= cbMinimizeToTray.Checked; gAlwaysShowTrayIcon:= cbAlwaysShowTrayIcon.Checked; gDriveBlackList:= edtDrivesBlackList.Text; gDriveBlackListUnmounted:= cbBlacklistUnmountedDevices.Checked; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsbriefview.lfm���������������������������������������������������0000644�0001750�0000144�00000005775�14743153644�021134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsBriefView: TfrmOptionsBriefView Height = 289 Width = 519 HelpKeyword = '/configuration.html#ConfigViewBrief' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 289 ClientWidth = 519 DesignLeft = 497 DesignTop = 187 object gbShowFileExt: TGroupBox[0] Left = 6 Height = 62 Top = 6 Width = 507 Align = alTop AutoSize = True Caption = 'Show file extensions' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 2 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 42 ClientWidth = 503 TabOrder = 0 object rbDirectly: TRadioButton Left = 6 Height = 19 Top = 2 Width = 491 Caption = 'di&rectly after filename' Checked = True TabOrder = 1 TabStop = True end object rbAligned: TRadioButton Left = 6 Height = 19 Top = 21 Width = 491 Caption = 'ali&gned (with Tab)' TabOrder = 0 end end object gbColumns: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbShowFileExt AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbShowFileExt AnchorSideRight.Side = asrBottom Left = 6 Height = 89 Top = 68 Width = 507 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Columns size' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 2 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 69 ClientWidth = 503 TabOrder = 1 object rbUseAutoSize: TRadioButton Left = 6 Height = 19 Top = 2 Width = 130 Caption = 'Auto' Checked = True TabOrder = 0 TabStop = True end object lblStub: TLabel Left = 136 Height = 19 Top = 2 Width = 50 ParentColor = False end object rbUseFixedWidth: TRadioButton Left = 6 Height = 23 Top = 21 Width = 130 Caption = 'Fixed columns width' TabOrder = 1 end object speUseFixedWidth: TSpinEdit Left = 136 Height = 23 Top = 21 Width = 80 Constraints.MinWidth = 80 MaxValue = 1000 MinValue = 1 TabOrder = 2 Value = 1 end object rbUseFixedCount: TRadioButton Left = 6 Height = 23 Top = 44 Width = 130 Caption = 'Fixed columns count' TabOrder = 3 end object speUseFixedCount: TSpinEdit Left = 136 Height = 23 Top = 44 Width = 80 MinValue = 1 TabOrder = 4 Value = 1 end end end ���doublecmd-1.1.22/src/frames/foptionsbriefview.lrj���������������������������������������������������0000644�0001750�0000144�00000002364�14743153644�021134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":122053763,"name":"tfrmoptionsbriefview.gbshowfileext.caption","sourcebytes":[83,104,111,119,32,102,105,108,101,32,101,120,116,101,110,115,105,111,110,115],"value":"Show file extensions"}, {"hash":262172725,"name":"tfrmoptionsbriefview.rbdirectly.caption","sourcebytes":[100,105,38,114,101,99,116,108,121,32,97,102,116,101,114,32,102,105,108,101,110,97,109,101],"value":"di&rectly after filename"}, {"hash":166499177,"name":"tfrmoptionsbriefview.rbaligned.caption","sourcebytes":[97,108,105,38,103,110,101,100,32,40,119,105,116,104,32,84,97,98,41],"value":"ali&gned (with Tab)"}, {"hash":32619845,"name":"tfrmoptionsbriefview.gbcolumns.caption","sourcebytes":[67,111,108,117,109,110,115,32,115,105,122,101],"value":"Columns size"}, {"hash":298159,"name":"tfrmoptionsbriefview.rbuseautosize.caption","sourcebytes":[65,117,116,111],"value":"Auto"}, {"hash":1109464,"name":"tfrmoptionsbriefview.rbusefixedwidth.caption","sourcebytes":[70,105,120,101,100,32,99,111,108,117,109,110,115,32,119,105,100,116,104],"value":"Fixed columns width"}, {"hash":359972,"name":"tfrmoptionsbriefview.rbusefixedcount.caption","sourcebytes":[70,105,120,101,100,32,99,111,108,117,109,110,115,32,99,111,117,110,116],"value":"Fixed columns count"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsbriefview.pas���������������������������������������������������0000644�0001750�0000144�00000005422�14743153644�021126� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Brief view options page Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit fOptionsBriefView; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fOptionsFrame, StdCtrls, ExtCtrls, Spin; type { TfrmOptionsBriefView } TfrmOptionsBriefView = class(TOptionsEditor) gbShowFileExt: TGroupBox; gbColumns: TGroupBox; rbUseFixedWidth: TRadioButton; rbUseFixedCount: TRadioButton; rbUseAutoSize: TRadioButton; rbDirectly: TRadioButton; rbAligned: TRadioButton; speUseFixedWidth: TSpinEdit; speUseFixedCount: TSpinEdit; lblStub: TLabel; protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng; { TfrmOptionsBriefView } procedure TfrmOptionsBriefView.Load; begin rbAligned.Checked := gBriefViewFileExtAligned; speUseFixedWidth.Value := gBriefViewFixedWidth; speUseFixedCount.Value := gBriefViewFixedCount; rbUseAutoSize.Checked := gBriefViewMode = bvmAutoSize; rbUseFixedWidth.Checked := gBriefViewMode = bvmFixedWidth; rbUseFixedCount.Checked := gBriefViewMode = bvmFixedCount; end; function TfrmOptionsBriefView.Save: TOptionsEditorSaveFlags; begin gBriefViewFileExtAligned := rbAligned.Checked; gBriefViewFixedWidth := speUseFixedWidth.Value; gBriefViewFixedCount := speUseFixedCount.Value; if rbUseAutoSize.Checked then gBriefViewMode := bvmAutoSize; if rbUseFixedWidth.Checked then gBriefViewMode := bvmFixedWidth; if rbUseFixedCount.Checked then gBriefViewMode := bvmFixedCount; Result := []; end; class function TfrmOptionsBriefView.GetIconIndex: Integer; begin Result := 35; end; class function TfrmOptionsBriefView.GetTitle: String; begin Result := rsOptionsEditorBriefView; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscolors.lfm������������������������������������������������������0000644�0001750�0000144�00000030264�14743153644�020442� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsColors: TfrmOptionsColors Height = 451 Width = 579 HelpKeyword = '/configuration.html#ConfigColor' AutoSize = True ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 451 ClientWidth = 579 DesignLeft = 574 DesignTop = 216 object cmbGroup: TComboBox[0] AnchorSideLeft.Control = lblCategory AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Owner Left = 87 Height = 23 Top = 12 Width = 212 BorderSpacing.Left = 18 BorderSpacing.Top = 12 ItemHeight = 15 OnChange = cmbGroupChange Style = csDropDownList TabOrder = 0 end object nbColors: TNotebook[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = cmbGroup AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 115 Top = 45 Width = 567 PageIndex = 0 AutoSize = True Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 10 TabOrder = 1 object pgViewer: TPage ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ChildSizing.HorizontalSpacing = 8 ChildSizing.VerticalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 object dbBookMode: TDividerBevel Left = 12 Height = 15 Top = 12 Width = 240 Caption = 'Book Mode' ParentFont = False Style = gsHorLines end object DividerBevel9: TDividerBevel Left = 260 Height = 15 Top = 12 Width = 240 ParentFont = False Style = gsHorLines end object lblBookText: TLabel Left = 12 Height = 25 Top = 35 Width = 240 Caption = 'Text:' Layout = tlCenter end object cbBookText: TKASColorBoxButton Left = 260 Height = 25 Top = 35 Width = 240 TabOrder = 0 end object lblBookBackground: TLabel Left = 12 Height = 25 Top = 68 Width = 240 Caption = 'Background:' Layout = tlCenter end object cbBookBackground: TKASColorBoxButton Left = 260 Height = 25 Top = 68 Width = 240 TabOrder = 1 end object dbImageMode: TDividerBevel Left = 12 Height = 15 Top = 101 Width = 240 Caption = 'Image Mode' ParentFont = False Style = gsHorLines end object DividerBevel11: TDividerBevel Left = 260 Height = 15 Top = 101 Width = 240 ParentFont = False Style = gsHorLines end object lblImageBackground1: TLabel Left = 12 Height = 25 Top = 124 Width = 240 Caption = 'Background 1:' Layout = tlCenter end object cbImageBackground1: TKASColorBoxButton Left = 260 Height = 25 Top = 124 Width = 240 TabOrder = 2 end object lblImageBackground2: TLabel Left = 12 Height = 25 Top = 157 Width = 240 Caption = 'Background 2:' Layout = tlCenter end object cbImageBackground2: TKASColorBoxButton Left = 260 Height = 25 Top = 157 Width = 240 TabOrder = 3 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeDefault, cbPrettyNames] end end object pgDiffer: TPage ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ChildSizing.HorizontalSpacing = 8 ChildSizing.VerticalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 object dbTextMode: TDividerBevel Left = 12 Height = 15 Top = 12 Width = 240 Caption = 'Text Mode' ParentFont = False Style = gsHorLines end object DividerBevel4: TDividerBevel Left = 260 Height = 15 Top = 12 Width = 240 ParentFont = False Style = gsHorLines end object lblAdded: TLabel Left = 12 Height = 25 Top = 35 Width = 240 Caption = 'Added:' Layout = tlCenter end object cbAdded: TKASColorBoxButton Left = 260 Height = 25 Top = 35 Width = 240 TabOrder = 0 end object lblDeleted: TLabel Left = 12 Height = 25 Top = 68 Width = 240 Caption = 'Deleted:' Layout = tlCenter end object cbDeleted: TKASColorBoxButton Left = 260 Height = 25 Top = 68 Width = 240 TabOrder = 1 end object lblModified: TLabel Left = 12 Height = 25 Top = 101 Width = 240 Caption = 'Modified:' Layout = tlCenter end object cbModified: TKASColorBoxButton Left = 260 Height = 25 Top = 101 Width = 240 TabOrder = 2 end object dbBinaryMode: TDividerBevel Left = 12 Height = 15 Top = 134 Width = 240 Caption = 'Binary Mode' ParentFont = False Style = gsHorLines end object DividerBevel6: TDividerBevel Left = 260 Height = 15 Top = 134 Width = 240 ParentFont = False Style = gsHorLines end object lblModifiedBinary: TLabel Left = 12 Height = 25 Top = 157 Width = 240 Caption = 'Modified:' Layout = tlCenter end object cbModifiedBinary: TKASColorBoxButton Left = 260 Height = 25 Top = 157 Width = 240 TabOrder = 3 end end object pgLog: TPage ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ChildSizing.HorizontalSpacing = 8 ChildSizing.VerticalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 object lblInformation: TLabel Left = 12 Height = 25 Top = 12 Width = 66 Caption = 'Information:' Layout = tlCenter end object cbInformation: TKASColorBoxButton Left = 86 Height = 25 Top = 12 Width = 125 TabOrder = 0 end object lblSuccess: TLabel Left = 12 Height = 25 Top = 45 Width = 66 Caption = 'Success:' Layout = tlCenter end object cbSuccess: TKASColorBoxButton Left = 86 Height = 25 Top = 45 Width = 125 TabOrder = 1 end object lblError: TLabel Left = 12 Height = 25 Top = 78 Width = 66 Caption = 'Error:' Layout = tlCenter end object cbError: TKASColorBoxButton Left = 86 Height = 25 Top = 78 Width = 125 TabOrder = 2 end end object pgSyncDirs: TPage ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ChildSizing.HorizontalSpacing = 8 ChildSizing.VerticalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 object lblLeft: TLabel Left = 12 Height = 25 Top = 12 Width = 54 Caption = 'Left:' Layout = tlCenter end object cbLeft: TKASColorBoxButton Left = 74 Height = 25 Top = 12 Width = 125 TabOrder = 0 end object lblRight: TLabel Left = 12 Height = 25 Top = 45 Width = 54 Caption = 'Right:' Layout = tlCenter end object cbRight: TKASColorBoxButton Left = 74 Height = 25 Top = 45 Width = 125 TabOrder = 1 end object lblUnknown: TLabel Left = 12 Height = 25 Top = 78 Width = 54 Caption = 'Unknown:' Layout = tlCenter end object cbUnknown: TKASColorBoxButton Left = 74 Height = 25 Top = 78 Width = 125 TabOrder = 2 end end object pgDriveFreeInd: TPage ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ChildSizing.HorizontalSpacing = 8 ChildSizing.VerticalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 object cbbUseGradientInd: TCheckBox Left = 12 Height = 19 Top = 12 Width = 137 BorderSpacing.Top = 6 Caption = 'Use &Gradient Indicator' OnChange = cbbUseGradientIndChange TabOrder = 0 end object pbxFakeDrive: TPaintBox Tag = 83 Left = 157 Height = 19 Top = 12 Width = 125 Constraints.MaxHeight = 19 ParentShowHint = False ShowHint = True OnClick = pbxFakeDriveClick OnPaint = pbxFakeDrivePaint end object lblIndColor: TLabel Left = 12 Height = 25 Top = 39 Width = 137 Caption = '&Indicator Fore Color:' FocusControl = cbIndColor Layout = tlCenter ParentColor = False end object cbIndColor: TKASColorBoxButton Left = 157 Height = 25 Top = 39 Width = 125 TabOrder = 1 OnChange = cbIndColorChange end object lblIndThresholdColor: TLabel Left = 12 Height = 25 Top = 72 Width = 137 BorderSpacing.Right = 4 Caption = 'Indicator &Threshold Color:' FocusControl = cbIndThresholdColor Layout = tlCenter ParentColor = False end object cbIndThresholdColor: TKASColorBoxButton Left = 157 Height = 25 Top = 72 Width = 125 TabOrder = 2 OnChange = cbIndColorChange end object lblIndBackColor: TLabel AnchorSideRight.Side = asrBottom Left = 12 Height = 25 Top = 105 Width = 137 Caption = 'In&dicator Back Color:' FocusControl = cbIndBackColor Layout = tlCenter ParentColor = False end object cbIndBackColor: TKASColorBoxButton AnchorSideRight.Side = asrBottom Left = 157 Height = 25 Top = 105 Width = 125 TabOrder = 3 OnChange = cbIndColorChange end end object pgDarkMode: TPage ChildSizing.LeftRightSpacing = 12 object rgDarkMode: TRadioGroup AnchorSideRight.Side = asrBottom Left = 0 Height = 77 Top = 6 Width = 567 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'State' ChildSizing.LeftRightSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 57 ClientWidth = 563 ItemIndex = 0 Items.Strings = ( 'Auto' 'Enabled' 'Disabled' ) TabOrder = 0 end end end object lblCategory: TLabel[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = cmbGroup AnchorSideTop.Side = asrCenter Left = 18 Height = 15 Top = 16 Width = 51 BorderSpacing.Left = 18 Caption = 'Category:' end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscolors.lrj������������������������������������������������������0000644�0001750�0000144�00000006752�14743153644�020460� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":97881285,"name":"tfrmoptionscolors.dbbookmode.caption","sourcebytes":[66,111,111,107,32,77,111,100,101],"value":"Book Mode"}, {"hash":5951354,"name":"tfrmoptionscolors.lblbooktext.caption","sourcebytes":[84,101,120,116,58],"value":"Text:"}, {"hash":249486954,"name":"tfrmoptionscolors.lblbookbackground.caption","sourcebytes":[66,97,99,107,103,114,111,117,110,100,58],"value":"Background:"}, {"hash":225593045,"name":"tfrmoptionscolors.dbimagemode.caption","sourcebytes":[73,109,97,103,101,32,77,111,100,101],"value":"Image Mode"}, {"hash":249462170,"name":"tfrmoptionscolors.lblimagebackground1.caption","sourcebytes":[66,97,99,107,103,114,111,117,110,100,32,49,58],"value":"Background 1:"}, {"hash":249462154,"name":"tfrmoptionscolors.lblimagebackground2.caption","sourcebytes":[66,97,99,107,103,114,111,117,110,100,32,50,58],"value":"Background 2:"}, {"hash":258309989,"name":"tfrmoptionscolors.dbtextmode.caption","sourcebytes":[84,101,120,116,32,77,111,100,101],"value":"Text Mode"}, {"hash":75148154,"name":"tfrmoptionscolors.lbladded.caption","sourcebytes":[65,100,100,101,100,58],"value":"Added:"}, {"hash":204255194,"name":"tfrmoptionscolors.lbldeleted.caption","sourcebytes":[68,101,108,101,116,101,100,58],"value":"Deleted:"}, {"hash":184332074,"name":"tfrmoptionscolors.lblmodified.caption","sourcebytes":[77,111,100,105,102,105,101,100,58],"value":"Modified:"}, {"hash":167657765,"name":"tfrmoptionscolors.dbbinarymode.caption","sourcebytes":[66,105,110,97,114,121,32,77,111,100,101],"value":"Binary Mode"}, {"hash":184332074,"name":"tfrmoptionscolors.lblmodifiedbinary.caption","sourcebytes":[77,111,100,105,102,105,101,100,58],"value":"Modified:"}, {"hash":109982858,"name":"tfrmoptionscolors.lblinformation.caption","sourcebytes":[73,110,102,111,114,109,97,116,105,111,110,58],"value":"Information:"}, {"hash":194629578,"name":"tfrmoptionscolors.lblsuccess.caption","sourcebytes":[83,117,99,99,101,115,115,58],"value":"Success:"}, {"hash":80320090,"name":"tfrmoptionscolors.lblerror.caption","sourcebytes":[69,114,114,111,114,58],"value":"Error:"}, {"hash":5422458,"name":"tfrmoptionscolors.lblleft.caption","sourcebytes":[76,101,102,116,58],"value":"Left:"}, {"hash":93314938,"name":"tfrmoptionscolors.lblright.caption","sourcebytes":[82,105,103,104,116,58],"value":"Right:"}, {"hash":86338010,"name":"tfrmoptionscolors.lblunknown.caption","sourcebytes":[85,110,107,110,111,119,110,58],"value":"Unknown:"}, {"hash":135998194,"name":"tfrmoptionscolors.cbbusegradientind.caption","sourcebytes":[85,115,101,32,38,71,114,97,100,105,101,110,116,32,73,110,100,105,99,97,116,111,114],"value":"Use &Gradient Indicator"}, {"hash":171869450,"name":"tfrmoptionscolors.lblindcolor.caption","sourcebytes":[38,73,110,100,105,99,97,116,111,114,32,70,111,114,101,32,67,111,108,111,114,58],"value":"&Indicator Fore Color:"}, {"hash":115941530,"name":"tfrmoptionscolors.lblindthresholdcolor.caption","sourcebytes":[73,110,100,105,99,97,116,111,114,32,38,84,104,114,101,115,104,111,108,100,32,67,111,108,111,114,58],"value":"Indicator &Threshold Color:"}, {"hash":171107370,"name":"tfrmoptionscolors.lblindbackcolor.caption","sourcebytes":[73,110,38,100,105,99,97,116,111,114,32,66,97,99,107,32,67,111,108,111,114,58],"value":"In&dicator Back Color:"}, {"hash":5941413,"name":"tfrmoptionscolors.rgdarkmode.caption","sourcebytes":[83,116,97,116,101],"value":"State"}, {"hash":180232266,"name":"tfrmoptionscolors.lblcategory.caption","sourcebytes":[67,97,116,101,103,111,114,121,58],"value":"Category:"} ]} ����������������������doublecmd-1.1.22/src/frames/foptionscolors.pas������������������������������������������������������0000644�0001750�0000144�00000021213�14743153644�020441� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fOptionsColors; {$mode ObjFPC}{$H+} {$IF DEFINED(darwin)} {$DEFINE DARKWIN} {$ENDIF} interface uses Classes, SysUtils, Forms, Controls, ExtCtrls, Dialogs, StdCtrls, DividerBevel, fOptionsFrame, KASComboBox, LMessages; type { TfrmOptionsColors } TfrmOptionsColors = class(TOptionsEditor) cbAdded: TKASColorBoxButton; cbBookBackground: TKASColorBoxButton; cbBookText: TKASColorBoxButton; cbbUseGradientInd: TCheckBox; cbDeleted: TKASColorBoxButton; cbError: TKASColorBoxButton; cbImageBackground1: TKASColorBoxButton; cbImageBackground2: TKASColorBoxButton; cbIndBackColor: TKASColorBoxButton; cbIndColor: TKASColorBoxButton; cbIndThresholdColor: TKASColorBoxButton; cbInformation: TKASColorBoxButton; cbLeft: TKASColorBoxButton; cbModifiedBinary: TKASColorBoxButton; cbRight: TKASColorBoxButton; cbSuccess: TKASColorBoxButton; cbUnknown: TKASColorBoxButton; cmbGroup: TComboBox; cbModified: TKASColorBoxButton; dbBookMode: TDividerBevel; dbImageMode: TDividerBevel; DividerBevel11: TDividerBevel; dbTextMode: TDividerBevel; DividerBevel4: TDividerBevel; dbBinaryMode: TDividerBevel; DividerBevel6: TDividerBevel; DividerBevel9: TDividerBevel; lblCategory: TLabel; lblAdded: TLabel; lblBookBackground: TLabel; lblBookText: TLabel; lblDeleted: TLabel; lblError: TLabel; lblImageBackground1: TLabel; lblImageBackground2: TLabel; lblIndBackColor: TLabel; lblIndColor: TLabel; lblIndThresholdColor: TLabel; lblInformation: TLabel; lblLeft: TLabel; lblModified: TLabel; lblModifiedBinary: TLabel; lblRight: TLabel; lblSuccess: TLabel; lblUnknown: TLabel; nbColors: TNotebook; pgDriveFreeInd: TPage; pbxFakeDrive: TPaintBox; pgDarkMode: TPage; pgDiffer: TPage; pgLog: TPage; pgSyncDirs: TPage; pgViewer: TPage; rgDarkMode: TRadioGroup; procedure cbbUseGradientIndChange(Sender: TObject); procedure cbIndColorChange(Sender: TObject); procedure cmbGroupChange(Sender: TObject); procedure pbxFakeDriveClick(Sender: TObject); procedure pbxFakeDrivePaint(Sender: TObject); {$IF DEFINED(DARKWIN)} private FAppMode: Integer; {$ENDIF} protected procedure Init; override; procedure Load; override; procedure DoAutoSize; override; function Save: TOptionsEditorSaveFlags; override; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng, uDCUtils, fMain {$IF DEFINED(DARKWIN)} , DCStrUtils, uEarlyConfig {$IF not DEFINED(darwin)} , uDarkStyle {$ELSE} , uMyDarwin {$ENDIF} {$ENDIF} ; { TfrmOptionsColors } procedure TfrmOptionsColors.cmbGroupChange(Sender: TObject); begin nbColors.PageIndex:= cmbGroup.ItemIndex; end; procedure TfrmOptionsColors.pbxFakeDriveClick(Sender: TObject); begin pbxFakeDrive.Tag:= (pbxFakeDrive.ScreenToClient(Mouse.CursorPos).X * 100) div pbxFakeDrive.Width; pbxFakeDrive.Hint:= pbxFakeDrive.Tag.ToString + '%'; pbxFakeDrive.Repaint; end; procedure TfrmOptionsColors.cbbUseGradientIndChange(Sender: TObject); var vNoGradient: boolean; begin vNoGradient := not (cbbUseGradientInd.Checked); lblIndThresholdColor.Enabled := vNoGradient; lblIndColor.Enabled := vNoGradient; lblIndBackColor.Enabled := vNoGradient; cbIndThresholdColor.Enabled := vNoGradient; cbIndColor.Enabled := vNoGradient; cbIndBackColor.Enabled := vNoGradient; pbxFakeDrive.Repaint; end; procedure TfrmOptionsColors.cbIndColorChange(Sender: TObject); begin pbxFakeDrive.Repaint; end; procedure TfrmOptionsColors.pbxFakeDrivePaint(Sender: TObject); begin frmMain.PaintDriveFreeBar(pbxFakeDrive, cbbUseGradientInd.Checked, cbIndColor.Selected, cbIndThresholdColor.Selected, cbIndBackColor.Selected); end; procedure TfrmOptionsColors.Init; begin cmbGroup.Items.Add(rsToolViewer); cmbGroup.Items.Add(rsToolDiffer); cmbGroup.Items.Add(rsOptionsEditorLog); cmbGroup.Items.Add(rsHotkeyCategorySyncDirs); cmbGroup.Items.Add(rsDriveFreeSpaceIndicator); cmbGroup.ItemIndex:= 0; {$IF DEFINED(DARKWIN)} FAppMode:= gAppMode; {$IFDEF LCLWIN32}if g_darkModeSupported then{$ENDIF} begin ParseLineToList(rsDarkModeOptions, rgDarkMode.Items); cmbGroup.ItemIndex:= cmbGroup.Items.Add(rsDarkMode); nbColors.PageIndex:= cmbGroup.ItemIndex; end; {$ENDIF} end; procedure TfrmOptionsColors.Load; begin {$IF DEFINED(DARKWIN)} case FAppMode of 1: rgDarkMode.ItemIndex:= 0; 2: rgDarkMode.ItemIndex:= 1; 3: rgDarkMode.ItemIndex:= 2; end; {$ENDIF} with gColors.Viewer^ do begin cbBookText.Selected:= BookFontColor; cbBookBackground.Selected:= BookBackgroundColor; cbImageBackground1.Selected:= ImageBackColor1; cbImageBackground2.Selected:= ImageBackColor2; end; with gColors.Differ^ do begin cbAdded.Selected:= AddedColor; cbDeleted.Selected:= DeletedColor; cbModified.Selected:= ModifiedColor; cbModifiedBinary.Selected:= ModifiedBinaryColor; end; with gColors.Log^ do begin cbInformation.Selected:= InfoColor; cbSuccess.Selected:= SuccessColor; cbError.Selected:= ErrorColor; end; with gColors.SyncDirs^ do begin cbLeft.Selected:= LeftColor; cbRight.Selected:= RightColor; cbUnknown.Selected:= UnknownColor; end; with gColors.FreeSpaceInd^ do begin cbIndColor.Selected:= ForeColor; cbIndBackColor.Selected:= BackColor; cbIndThresholdColor.Selected:= ThresholdForeColor; end; cbbUseGradientInd.Checked:= gIndUseGradient; pbxFakeDrive.Hint:= pbxFakeDrive.Tag.ToString + '%'; end; procedure TfrmOptionsColors.DoAutoSize; var I, J: Integer; AControl: TControl; AMaxWidth: Integer = 0; begin inherited DoAutoSize; if csDesigning in ComponentState then Exit; pbxFakeDrive.Constraints.MaxHeight:= cbbUseGradientInd.Height; for I:= 0 to nbColors.PageCount - 1 do begin with nbColors.Page[I] do begin for J := 0 to ControlCount - 1 do begin AControl:= Controls[J]; if AControl is TLabel then begin if (AControl.Width > AMaxWidth) then AMaxWidth:= AControl.Width; end; end; end; end; for I:= 0 to nbColors.PageCount - 1 do begin with nbColors.Page[I] do begin for J := 0 to ControlCount - 1 do begin AControl:= Controls[J]; if AControl is TLabel then begin AControl.Constraints.MinWidth:= AMaxWidth; end; end; end; end; end; function TfrmOptionsColors.Save: TOptionsEditorSaveFlags; begin Result:= []; {$IF DEFINED(DARKWIN)} case rgDarkMode.ItemIndex of 0: gAppMode:= 1; 1: gAppMode:= 2; 2: gAppMode:= 3; end; if gAppMode <> FAppMode then try FAppMode:= gAppMode; {$IF not DEFINED(darwin)} if g_darkModeSupported then Result:= [oesfNeedsRestart]; {$ELSE} setMacOSAppearance( gAppMode ); {$ENDIF} SaveEarlyConfig; except on E: Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; {$ENDIF} with gColors.Viewer^ do begin BookFontColor:= cbBookText.Selected; BookBackgroundColor:= cbBookBackground.Selected; ImageBackColor1:= cbImageBackground1.Selected; ImageBackColor2:= cbImageBackground2.Selected; end; with gColors.Differ^ do begin AddedColor:= cbAdded.Selected; DeletedColor:= cbDeleted.Selected; ModifiedColor:= cbModified.Selected; ModifiedBinaryColor:= cbModifiedBinary.Selected; end; with gColors.Log^ do begin InfoColor:= cbInformation.Selected; SuccessColor:= cbSuccess.Selected; ErrorColor:= cbError.Selected; end; with gColors.SyncDirs^ do begin LeftColor:= cbLeft.Selected; RightColor:= cbRight.Selected; UnknownColor:= cbUnknown.Selected; end; gIndUseGradient:= cbbUseGradientInd.Checked; with gColors.FreeSpaceInd^ do begin ForeColor := cbIndColor.Selected; BackColor := cbIndBackColor.Selected; ThresholdForeColor := cbIndThresholdColor.Selected; end; end; procedure TfrmOptionsColors.CMThemeChanged(var Message: TLMessage); begin LoadSettings; end; class function TfrmOptionsColors.GetIconIndex: Integer; begin Result:= 4; end; class function TfrmOptionsColors.GetTitle: String; begin Result:= rsOptionsEditorColors; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscolumnsview.lfm�������������������������������������������������0000644�0001750�0000144�00000011077�14743153644�021515� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsColumnsView: TfrmOptionsColumnsView Height = 344 Width = 659 HelpKeyword = '/configuration.html#ConfigViewFull' ClientHeight = 344 ClientWidth = 659 DesignLeft = 419 DesignTop = 249 object grpAutosizeColumns: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbShowGrid AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 92 Top = 94 Width = 647 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Auto-size columns' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 6 ClientHeight = 74 ClientWidth = 645 TabOrder = 1 object chkAutoFillColumns: TCheckBox AnchorSideTop.Side = asrBottom Left = 12 Height = 23 Top = 6 Width = 138 Caption = 'A&uto fill columns' TabOrder = 0 end object lblAutoSizeColumn: TLabel AnchorSideLeft.Control = chkAutoFillColumns AnchorSideTop.Control = cmbAutoSizeColumn AnchorSideTop.Side = asrCenter Left = 12 Height = 17 Top = 45 Width = 118 Caption = 'Auto si&ze column:' FocusControl = cmbAutoSizeColumn ParentColor = False end object cmbAutoSizeColumn: TComboBox AnchorSideLeft.Control = lblAutoSizeColumn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = chkAutoFillColumns AnchorSideTop.Side = asrBottom AnchorSideRight.Control = grpAutosizeColumns AnchorSideRight.Side = asrBottom Left = 142 Height = 29 Top = 39 Width = 491 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 12 BorderSpacing.Top = 10 BorderSpacing.Right = 10 ItemHeight = 0 Items.Strings = ( 'First' 'Last' ) Style = csDropDownList TabOrder = 1 end end object gbShowGrid: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 82 Top = 6 Width = 647 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Show grid' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 6 ClientHeight = 64 ClientWidth = 645 TabOrder = 0 object cbGridVertLine: TCheckBox AnchorSideLeft.Control = gbShowGrid AnchorSideTop.Control = gbShowGrid Left = 12 Height = 23 Top = 6 Width = 112 Caption = '&Vertical lines' OnChange = cbGridVertLineChange TabOrder = 0 end object cbGridHorzLine: TCheckBox AnchorSideLeft.Control = gbShowGrid AnchorSideTop.Control = cbGridVertLine AnchorSideTop.Side = asrBottom Left = 12 Height = 23 Top = 35 Width = 131 BorderSpacing.Top = 6 Caption = '&Horizontal lines' TabOrder = 1 end end object grpMisc: TGroupBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = grpAutosizeColumns AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 95 Top = 192 Width = 647 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 6 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 93 ClientWidth = 645 TabOrder = 2 object cbCutTextToColWidth: TCheckBox AnchorSideLeft.Control = grpMisc AnchorSideTop.Control = cbColumnsTitleLikeValues AnchorSideTop.Side = asrBottom Left = 12 Height = 23 Top = 35 Width = 190 BorderSpacing.Top = 6 Caption = 'Cut &text to column width' TabOrder = 1 end object cbExtendCellWidth: TCheckBox AnchorSideLeft.Control = grpMisc AnchorSideTop.Control = cbCutTextToColWidth AnchorSideTop.Side = asrBottom Left = 12 Height = 23 Top = 64 Width = 349 BorderSpacing.Top = 6 Caption = '&Extend cell width if text is not fitting into column' OnChange = cbExtendCellWidthChange TabOrder = 2 end object cbColumnsTitleLikeValues: TCheckBox AnchorSideLeft.Control = grpMisc AnchorSideTop.Control = grpMisc Left = 12 Height = 23 Top = 6 Width = 256 Caption = 'Column titles alignment &like values' TabOrder = 0 end end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscolumnsview.lrj�������������������������������������������������0000644�0001750�0000144�00000003653�14743153644�021527� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":248156179,"name":"tfrmoptionscolumnsview.grpautosizecolumns.caption","sourcebytes":[65,117,116,111,45,115,105,122,101,32,99,111,108,117,109,110,115],"value":"Auto-size columns"}, {"hash":212887331,"name":"tfrmoptionscolumnsview.chkautofillcolumns.caption","sourcebytes":[65,38,117,116,111,32,102,105,108,108,32,99,111,108,117,109,110,115],"value":"A&uto fill columns"}, {"hash":91297290,"name":"tfrmoptionscolumnsview.lblautosizecolumn.caption","sourcebytes":[65,117,116,111,32,115,105,38,122,101,32,99,111,108,117,109,110,58],"value":"Auto si&ze column:"}, {"hash":110539012,"name":"tfrmoptionscolumnsview.gbshowgrid.caption","sourcebytes":[83,104,111,119,32,103,114,105,100],"value":"Show grid"}, {"hash":50869875,"name":"tfrmoptionscolumnsview.cbgridvertline.caption","sourcebytes":[38,86,101,114,116,105,99,97,108,32,108,105,110,101,115],"value":"&Vertical lines"}, {"hash":254961699,"name":"tfrmoptionscolumnsview.cbgridhorzline.caption","sourcebytes":[38,72,111,114,105,122,111,110,116,97,108,32,108,105,110,101,115],"value":"&Horizontal lines"}, {"hash":13344632,"name":"tfrmoptionscolumnsview.cbcuttexttocolwidth.caption","sourcebytes":[67,117,116,32,38,116,101,120,116,32,116,111,32,99,111,108,117,109,110,32,119,105,100,116,104],"value":"Cut &text to column width"}, {"hash":124929006,"name":"tfrmoptionscolumnsview.cbextendcellwidth.caption","sourcebytes":[38,69,120,116,101,110,100,32,99,101,108,108,32,119,105,100,116,104,32,105,102,32,116,101,120,116,32,105,115,32,110,111,116,32,102,105,116,116,105,110,103,32,105,110,116,111,32,99,111,108,117,109,110],"value":"&Extend cell width if text is not fitting into column"}, {"hash":65940035,"name":"tfrmoptionscolumnsview.cbcolumnstitlelikevalues.caption","sourcebytes":[67,111,108,117,109,110,32,116,105,116,108,101,115,32,97,108,105,103,110,109,101,110,116,32,38,108,105,107,101,32,118,97,108,117,101,115],"value":"Column titles alignment &like values"} ]} �������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscolumnsview.pas�������������������������������������������������0000644�0001750�0000144�00000006723�14743153644�021524� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Columns files view options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsColumnsView; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fOptionsFrame, StdCtrls; type { TfrmOptionsColumnsView } TfrmOptionsColumnsView = class(TOptionsEditor) cbCutTextToColWidth: TCheckBox; cbExtendCellWidth: TCheckBox; cbGridHorzLine: TCheckBox; cbGridVertLine: TCheckBox; cbColumnsTitleLikeValues: TCheckBox; chkAutoFillColumns: TCheckBox; cmbAutoSizeColumn: TComboBox; gbShowGrid: TGroupBox; grpMisc: TGroupBox; grpAutosizeColumns: TGroupBox; lblAutoSizeColumn: TLabel; procedure cbExtendCellWidthChange(Sender: TObject); procedure cbGridVertLineChange(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng; { TfrmOptionsColumnsView } procedure TfrmOptionsColumnsView.cbExtendCellWidthChange(Sender: TObject); begin if cbExtendCellWidth.Checked then cbGridVertLine.Checked:= False; end; procedure TfrmOptionsColumnsView.cbGridVertLineChange(Sender: TObject); begin if cbGridVertLine.Checked then cbExtendCellWidth.Checked:= False; end; procedure TfrmOptionsColumnsView.Init; begin ParseLineToList(rsOptAutoSizeColumn, cmbAutoSizeColumn.Items); end; procedure TfrmOptionsColumnsView.Load; begin cbGridVertLine.Checked := gGridVertLine; cbGridHorzLine.Checked := gGridHorzLine; chkAutoFillColumns.Checked := gAutoFillColumns; cmbAutoSizeColumn.ItemIndex := gAutoSizeColumn; cbColumnsTitleLikeValues.Checked := gColumnsTitleLikeValues; cbCutTextToColWidth.Checked := gCutTextToColWidth; cbExtendCellWidth.Checked := gExtendCellWidth; end; function TfrmOptionsColumnsView.Save: TOptionsEditorSaveFlags; begin gGridVertLine := cbGridVertLine.Checked; gGridHorzLine := cbGridHorzLine.Checked; gAutoFillColumns := chkAutoFillColumns.Checked; gAutoSizeColumn := cmbAutoSizeColumn.ItemIndex; gColumnsTitleLikeValues := cbColumnsTitleLikeValues.Checked; gCutTextToColWidth := cbCutTextToColWidth.Checked; gExtendCellWidth := cbExtendCellWidth.Checked; Result := []; end; class function TfrmOptionsColumnsView.GetIconIndex: Integer; begin Result := 13; end; class function TfrmOptionsColumnsView.GetTitle: String; begin Result := rsOptionsEditorColumnsView; end; end. ���������������������������������������������doublecmd-1.1.22/src/frames/foptionsconfiguration.lfm�����������������������������������������������0000644�0001750�0000144�00000022710�14743153644�022005� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsConfiguration: TfrmOptionsConfiguration Height = 595 Width = 626 HelpKeyword = '/configuration.html#ConfigDC' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 595 ClientWidth = 626 DesignLeft = 783 DesignTop = 152 object gbLocConfigFiles: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 93 Top = 6 Width = 614 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Location of configuration files' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 5 ChildSizing.VerticalSpacing = 5 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 73 ClientWidth = 610 TabOrder = 0 object rbProgramDir: TRadioButton Left = 10 Height = 19 Top = 5 Width = 212 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'P&rogram directory (portable version)' Checked = True TabOrder = 0 TabStop = True end object rbUserHomeDir: TRadioButton Left = 10 Height = 19 Top = 29 Width = 127 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = '&User home directory' TabOrder = 1 end object lblCmdLineConfigDir: TLabel Left = 10 Height = 15 Top = 53 Width = 113 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Set on command line' ParentColor = False Visible = False end end object gbSaveOnExit: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = btnConfigEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 175 Top = 141 Width = 614 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Save on exit' ChildSizing.TopBottomSpacing = 5 ClientHeight = 155 ClientWidth = 610 TabOrder = 3 object cbDirHistory: TCheckBox AnchorSideLeft.Control = chkSaveConfiguration AnchorSideTop.Control = chkSearchReplaceHistory AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 89 Width = 107 BorderSpacing.Top = 2 Caption = '&Directory history' TabOrder = 4 end object cbCmdLineHistory: TCheckBox AnchorSideLeft.Control = chkSaveConfiguration AnchorSideTop.Control = cbDirHistory AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 110 Width = 138 BorderSpacing.Top = 2 Caption = 'Co&mmand line history' TabOrder = 5 end object cbFileMaskHistory: TCheckBox AnchorSideLeft.Control = chkSaveConfiguration AnchorSideTop.Control = cbCmdLineHistory AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 131 Width = 108 BorderSpacing.Top = 2 Caption = '&File mask history' TabOrder = 6 end object chkSaveConfiguration: TCheckBox AnchorSideLeft.Control = gbSaveOnExit AnchorSideTop.Control = gbSaveOnExit Left = 10 Height = 19 Top = 5 Width = 119 BorderSpacing.Left = 10 Caption = 'Sa&ve configuration' OnChange = chkSaveConfigurationChange TabOrder = 0 end object chkSearchReplaceHistory: TCheckBox AnchorSideLeft.Control = chkSaveConfiguration AnchorSideTop.Control = chkFolderTabs AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 68 Width = 140 BorderSpacing.Top = 2 Caption = 'Searc&h/Replace history' TabOrder = 3 end object chkFolderTabs: TCheckBox AnchorSideLeft.Control = chkSaveConfiguration AnchorSideTop.Control = chkWindowState AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 47 Width = 78 BorderSpacing.Top = 2 Caption = 'Folder tabs' TabOrder = 2 end object chkWindowState: TCheckBox AnchorSideLeft.Control = chkSaveConfiguration AnchorSideTop.Control = chkSaveConfiguration AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 26 Width = 120 BorderSpacing.Top = 2 Caption = 'Main window state' TabOrder = 1 end end object btnConfigEdit: TBitBtn[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbLocConfigFiles AnchorSideTop.Side = asrBottom Left = 10 Height = 30 Top = 105 Width = 116 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = '&Edit' OnClick = btnConfigEditClick TabOrder = 1 end object btnConfigApply: TBitBtn[3] AnchorSideLeft.Control = btnConfigEdit AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbLocConfigFiles AnchorSideTop.Side = asrBottom Left = 136 Height = 30 Top = 105 Width = 116 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = 'A&pply' Enabled = False OnClick = btnConfigApplyClick TabOrder = 2 end object gbSortOrderConfigurationOption: TRadioGroup[4] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbSaveOnExit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 58 Top = 322 Width = 614 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Top = 6 Caption = 'Sort order of configuration order in left tree' ChildSizing.LeftRightSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 38 ClientWidth = 610 ItemIndex = 0 Items.Strings = ( 'Classic, legacy order' 'Alphabetic order (but language still first)' ) OnClick = gbSortOrderConfigurationOptionClick TabOrder = 4 end object gbDirectories: TGroupBox[5] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gpConfigurationTreeState AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 113 Top = 450 Width = 614 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Directories' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 93 ClientWidth = 610 TabOrder = 6 object lblThumbCache: TLabel AnchorSideTop.Control = edtThumbCache AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 10 Width = 100 Caption = 'Thumbnails cache:' ParentColor = False end object edtThumbCache: TEdit AnchorSideRight.Control = gbDirectories AnchorSideRight.Side = asrBottom Left = 197 Height = 23 Top = 6 Width = 407 Anchors = [akTop, akLeft, akRight] ReadOnly = True TabOrder = 0 end object lblIconThemes: TLabel AnchorSideTop.Control = edtIconThemes AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 39 Width = 68 Caption = 'Icon themes:' ParentColor = False end object edtIconThemes: TEdit AnchorSideTop.Control = edtThumbCache AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbDirectories AnchorSideRight.Side = asrBottom Left = 197 Height = 23 Top = 35 Width = 407 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ReadOnly = True TabOrder = 1 end object edtHighlighters: TEdit AnchorSideTop.Control = edtIconThemes AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbDirectories AnchorSideRight.Side = asrBottom Left = 197 Height = 23 Top = 64 Width = 407 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ReadOnly = True TabOrder = 2 end object lblHighlighters: TLabel AnchorSideTop.Control = edtHighlighters AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 68 Width = 68 Caption = 'Highlighters:' ParentColor = False end end object gpConfigurationTreeState: TRadioGroup[6] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbSortOrderConfigurationOption AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 58 Top = 386 Width = 614 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Top = 6 Caption = 'Tree state when entering in configuration page' ChildSizing.LeftRightSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 38 ClientWidth = 610 ItemIndex = 0 Items.Strings = ( 'Full expand' 'Full collapse' ) OnClick = gpConfigurationTreeStateClick TabOrder = 5 end end ��������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsconfiguration.lrj�����������������������������������������������0000644�0001750�0000144�00000007734�14743153644�022027� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":60838323,"name":"tfrmoptionsconfiguration.gblocconfigfiles.caption","sourcebytes":[76,111,99,97,116,105,111,110,32,111,102,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,102,105,108,101,115],"value":"Location of configuration files"}, {"hash":124099977,"name":"tfrmoptionsconfiguration.rbprogramdir.caption","sourcebytes":[80,38,114,111,103,114,97,109,32,100,105,114,101,99,116,111,114,121,32,40,112,111,114,116,97,98,108,101,32,118,101,114,115,105,111,110,41],"value":"P&rogram directory (portable version)"}, {"hash":34707961,"name":"tfrmoptionsconfiguration.rbuserhomedir.caption","sourcebytes":[38,85,115,101,114,32,104,111,109,101,32,100,105,114,101,99,116,111,114,121],"value":"&User home directory"}, {"hash":184777589,"name":"tfrmoptionsconfiguration.lblcmdlineconfigdir.caption","sourcebytes":[83,101,116,32,111,110,32,99,111,109,109,97,110,100,32,108,105,110,101],"value":"Set on command line"}, {"hash":27134580,"name":"tfrmoptionsconfiguration.gbsaveonexit.caption","sourcebytes":[83,97,118,101,32,111,110,32,101,120,105,116],"value":"Save on exit"}, {"hash":118965577,"name":"tfrmoptionsconfiguration.cbdirhistory.caption","sourcebytes":[38,68,105,114,101,99,116,111,114,121,32,104,105,115,116,111,114,121],"value":"&Directory history"}, {"hash":57130889,"name":"tfrmoptionsconfiguration.cbcmdlinehistory.caption","sourcebytes":[67,111,38,109,109,97,110,100,32,108,105,110,101,32,104,105,115,116,111,114,121],"value":"Co&mmand line history"}, {"hash":211765641,"name":"tfrmoptionsconfiguration.cbfilemaskhistory.caption","sourcebytes":[38,70,105,108,101,32,109,97,115,107,32,104,105,115,116,111,114,121],"value":"&File mask history"}, {"hash":233941134,"name":"tfrmoptionsconfiguration.chksaveconfiguration.caption","sourcebytes":[83,97,38,118,101,32,99,111,110,102,105,103,117,114,97,116,105,111,110],"value":"Sa&ve configuration"}, {"hash":196727225,"name":"tfrmoptionsconfiguration.chksearchreplacehistory.caption","sourcebytes":[83,101,97,114,99,38,104,47,82,101,112,108,97,99,101,32,104,105,115,116,111,114,121],"value":"Searc&h/Replace history"}, {"hash":202032435,"name":"tfrmoptionsconfiguration.chkfoldertabs.caption","sourcebytes":[70,111,108,100,101,114,32,116,97,98,115],"value":"Folder tabs"}, {"hash":251093957,"name":"tfrmoptionsconfiguration.chkwindowstate.caption","sourcebytes":[77,97,105,110,32,119,105,110,100,111,119,32,115,116,97,116,101],"value":"Main window state"}, {"hash":2800388,"name":"tfrmoptionsconfiguration.btnconfigedit.caption","sourcebytes":[38,69,100,105,116],"value":"&Edit"}, {"hash":71137081,"name":"tfrmoptionsconfiguration.btnconfigapply.caption","sourcebytes":[65,38,112,112,108,121],"value":"A&pply"}, {"hash":217003093,"name":"tfrmoptionsconfiguration.gbsortorderconfigurationoption.caption","sourcebytes":[83,111,114,116,32,111,114,100,101,114,32,111,102,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,111,114,100,101,114,32,105,110,32,108,101,102,116,32,116,114,101,101],"value":"Sort order of configuration order in left tree"}, {"hash":184387443,"name":"tfrmoptionsconfiguration.gbdirectories.caption","sourcebytes":[68,105,114,101,99,116,111,114,105,101,115],"value":"Directories"}, {"hash":260735466,"name":"tfrmoptionsconfiguration.lblthumbcache.caption","sourcebytes":[84,104,117,109,98,110,97,105,108,115,32,99,97,99,104,101,58],"value":"Thumbnails cache:"}, {"hash":236084250,"name":"tfrmoptionsconfiguration.lbliconthemes.caption","sourcebytes":[73,99,111,110,32,116,104,101,109,101,115,58],"value":"Icon themes:"}, {"hash":50805722,"name":"tfrmoptionsconfiguration.lblhighlighters.caption","sourcebytes":[72,105,103,104,108,105,103,104,116,101,114,115,58],"value":"Highlighters:"}, {"hash":149152117,"name":"tfrmoptionsconfiguration.gpconfigurationtreestate.caption","sourcebytes":[84,114,101,101,32,115,116,97,116,101,32,119,104,101,110,32,101,110,116,101,114,105,110,103,32,105,110,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,112,97,103,101],"value":"Tree state when entering in configuration page"} ]} ������������������������������������doublecmd-1.1.22/src/frames/foptionsconfiguration.pas�����������������������������������������������0000644�0001750�0000144�00000016465�14743153644�022024� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Configuration options page Copyright (C) 2006-2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsConfiguration; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fOptionsFrame, StdCtrls, Buttons, ExtCtrls; type { TfrmOptionsConfiguration } TfrmOptionsConfiguration = class(TOptionsEditor) btnConfigApply: TBitBtn; btnConfigEdit: TBitBtn; cbCmdLineHistory: TCheckBox; cbDirHistory: TCheckBox; cbFileMaskHistory: TCheckBox; chkWindowState: TCheckBox; chkFolderTabs: TCheckBox; chkSaveConfiguration: TCheckBox; chkSearchReplaceHistory: TCheckBox; edtHighlighters: TEdit; edtThumbCache: TEdit; edtIconThemes: TEdit; gbLocConfigFiles: TGroupBox; gbSaveOnExit: TGroupBox; gbDirectories: TGroupBox; lblIconThemes: TLabel; lblHighlighters: TLabel; lblThumbCache: TLabel; lblCmdLineConfigDir: TLabel; gbSortOrderConfigurationOption: TRadioGroup; gpConfigurationTreeState: TRadioGroup; rbProgramDir: TRadioButton; rbUserHomeDir: TRadioButton; procedure btnConfigApplyClick(Sender: TObject); procedure btnConfigEditClick(Sender: TObject); procedure chkSaveConfigurationChange(Sender: TObject); procedure gbSortOrderConfigurationOptionClick(Sender: TObject); procedure gpConfigurationTreeStateClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses Forms, DCStrUtils, uGlobs, uGlobsPaths, uShowForm, uOSUtils, uLng, fOptions, uSysFolders; { TfrmOptionsConfiguration } procedure TfrmOptionsConfiguration.btnConfigApplyClick(Sender: TObject); begin if LoadConfig then // force reloading config from file begin LoadGlobs; OptionsDialog.LoadSettings; btnConfigApply.Enabled:= False; end else begin gSaveConfiguration := False; Application.Terminate; end; end; procedure TfrmOptionsConfiguration.btnConfigEditClick(Sender: TObject); begin ShowEditorByGlob(gpCfgDir + 'doublecmd.xml'); btnConfigApply.Enabled:= True; end; procedure TfrmOptionsConfiguration.chkSaveConfigurationChange(Sender: TObject); begin chkWindowState.Enabled:= chkSaveConfiguration.Checked; chkFolderTabs.Enabled:= chkSaveConfiguration.Checked; cbDirHistory.Enabled:= chkSaveConfiguration.Checked; cbCmdLineHistory.Enabled:= chkSaveConfiguration.Checked; cbFileMaskHistory.Enabled:= chkSaveConfiguration.Checked; chkSearchReplaceHistory.Enabled := chkSaveConfiguration.Checked; end; procedure TfrmOptionsConfiguration.gbSortOrderConfigurationOptionClick(Sender: TObject); begin //Exceptionnally for THIS setting, let's apply it immediately, even before quiting since the effect is... in the configuration area, just where we are at this moment! gSortOrderOfConfigurationOptionsTree := TSortConfigurationOptions(gbSortOrderConfigurationOption.ItemIndex); SortConfigurationOptionsOnLeftTree; end; { TfrmOptionsConfiguration.gpConfigurationTreeStateClick } procedure TfrmOptionsConfiguration.gpConfigurationTreeStateClick(Sender: TObject); begin //Exceptionnally for THIS setting, let's apply it immediately, even before quiting since the effect is... in the configuration area, just where we are at this moment! gCollapseConfigurationOptionsTree := TConfigurationTreeState(gpConfigurationTreeState.ItemIndex); if GetOptionsForm<>nil then begin case gCollapseConfigurationOptionsTree of ctsFullExpand : GetOptionsForm.tvTreeView.FullExpand; ctsFullCollapse: GetOptionsForm.tvTreeView.FullCollapse; end; end; end; class function TfrmOptionsConfiguration.GetIconIndex: Integer; begin Result := 11; end; class function TfrmOptionsConfiguration.GetTitle: String; begin Result := rsOptionsEditorConfiguration; end; procedure TfrmOptionsConfiguration.Init; begin if gpCmdLineCfgDir = '' then begin rbProgramDir.Caption:= rbProgramDir.Caption + ' - [' + IncludeTrailingPathDelimiter(gpGlobalCfgDir) + ']'; rbUserHomeDir.Caption:= rbUserHomeDir.Caption + ' - [' + IncludeTrailingPathDelimiter(GetAppConfigDir) + ']'; end else begin rbProgramDir.Visible := False; rbProgramDir.Enabled := False; rbUserHomeDir.Visible := False; rbUserHomeDir.Enabled := False; lblCmdLineConfigDir.Visible := True; lblCmdLineConfigDir.Caption := lblCmdLineConfigDir.Caption + ' - [' + IncludeTrailingPathDelimiter(gpCmdLineCfgDir) + ']'; end; ParseLineToList(rsOptConfigSortOrder, gbSortOrderConfigurationOption.Items); ParseLineToList(rsOptConfigTreeState, gpConfigurationTreeState.Items); end; procedure TfrmOptionsConfiguration.Load; begin if gUseConfigInProgramDirNew then rbProgramDir.Checked := True else rbUserHomeDir.Checked := True; edtThumbCache.Text:= gpThumbCacheDir; edtIconThemes.Text:= EmptyStr; if not gUseConfigInProgramDir then begin edtIconThemes.Text:= IncludeTrailingBackslash(GetAppDataDir) + 'pixmaps' + PathSep; end; edtIconThemes.Text:= edtIconThemes.Text + ExcludeTrailingPathDelimiter(gpPixmapPath); edtHighlighters.Text:= EmptyStr; if not gUseConfigInProgramDir then begin edtHighlighters.Text:= IncludeTrailingBackslash(GetAppDataDir) + 'highlighters' + PathSep; end; edtHighlighters.Text:= edtHighlighters.Text + ExcludeTrailingPathDelimiter(gpHighPath); chkSaveConfiguration.Checked:= gSaveConfiguration; chkWindowState.Checked:= gSaveWindowState; chkFolderTabs.Checked:= gSaveFolderTabs; chkSearchReplaceHistory.Checked:= gSaveSearchReplaceHistory; cbDirHistory.Checked := gSaveDirHistory; cbCmdLineHistory.Checked := gSaveCmdLineHistory; cbFileMaskHistory.Checked := gSaveFileMaskHistory; gbSortOrderConfigurationOption.ItemIndex:=Integer(gSortOrderOfConfigurationOptionsTree); gpConfigurationTreeState.ItemIndex := Integer(gCollapseConfigurationOptionsTree); end; function TfrmOptionsConfiguration.Save: TOptionsEditorSaveFlags; begin Result := []; gUseConfigInProgramDirNew := rbProgramDir.Checked; gSaveConfiguration := chkSaveConfiguration.Checked; gSaveWindowState := chkWindowState.Checked; gSaveFolderTabs := chkFolderTabs.Checked; gSaveSearchReplaceHistory := chkSearchReplaceHistory.Checked; gSaveDirHistory := cbDirHistory.Checked; gSaveCmdLineHistory := cbCmdLineHistory.Checked; gSaveFileMaskHistory := cbFileMaskHistory.Checked; gSortOrderOfConfigurationOptionsTree := TSortConfigurationOptions(gbSortOrderConfigurationOption.ItemIndex); gCollapseConfigurationOptionsTree := TConfigurationTreeState(gpConfigurationTreeState.ItemIndex); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscustomcolumns.lfm�����������������������������������������������0000644�0001750�0000144�00000123251�14743153644�022053� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsCustomColumns: TfrmOptionsCustomColumns Height = 596 Width = 1070 HelpKeyword = '/configuration.html#ConfigColumns' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ClientHeight = 596 ClientWidth = 1070 ParentShowHint = False ShowHint = True DesignLeft = 328 DesignTop = 134 object pnlConfigColumns: TPanel[0] Left = 4 Height = 31 Top = 4 Width = 1062 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ClientHeight = 31 ClientWidth = 1062 TabOrder = 0 object lblConfigColumns: TLabel AnchorSideLeft.Control = cmbFileSystem AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbConfigColumns AnchorSideTop.Side = asrCenter Left = 177 Height = 15 Top = 8 Width = 78 BorderSpacing.Left = 6 BorderSpacing.Right = 2 Caption = '&Columns view:' FocusControl = cbConfigColumns ParentColor = False end object cbConfigColumns: TComboBox AnchorSideLeft.Control = lblConfigColumns AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlConfigColumns AnchorSideRight.Side = asrBottom Left = 261 Height = 23 Top = 4 Width = 317 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Right = 4 Constraints.MaxWidth = 440 Font.Style = [fsBold] ItemHeight = 15 ItemIndex = 0 Items.Strings = ( 'General' ) OnChange = cbConfigColumnsChange ParentFont = False Style = csDropDownList TabOrder = 1 Text = 'General' end object btnSaveConfigColumns: TButton Tag = 1 AnchorSideLeft.Control = cbConfigColumns AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbConfigColumns AnchorSideRight.Control = btnRenameConfigColumns AnchorSideBottom.Control = cbConfigColumns AnchorSideBottom.Side = asrBottom Left = 582 Height = 23 Top = 4 Width = 50 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Left = 4 Caption = 'Save' OnClick = btnSaveConfigColumnsClick TabOrder = 2 end object btnRenameConfigColumns: TButton Tag = 4 AnchorSideLeft.Control = btnNewConfig AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbConfigColumns AnchorSideBottom.Control = cbConfigColumns AnchorSideBottom.Side = asrBottom Left = 758 Height = 23 Top = 4 Width = 69 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Left = 4 Caption = 'Rename' OnClick = btnSaveConfigColumnsClick TabOrder = 5 end object btnSaveAsConfigColumns: TButton Tag = 2 AnchorSideLeft.Control = btnSaveConfigColumns AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbConfigColumns AnchorSideBottom.Control = cbConfigColumns AnchorSideBottom.Side = asrBottom Left = 636 Height = 23 Top = 4 Width = 64 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Left = 4 Caption = 'Save as' OnClick = btnSaveConfigColumnsClick TabOrder = 3 end object btnDeleteConfigColumns: TButton AnchorSideLeft.Control = btnRenameConfigColumns AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbConfigColumns AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbConfigColumns AnchorSideBottom.Side = asrBottom Left = 831 Height = 23 Top = 4 Width = 59 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Left = 4 Caption = '&Delete' OnClick = btnDeleteConfigColumnsClick TabOrder = 6 end object btnNewConfig: TButton Tag = 3 AnchorSideLeft.Control = btnSaveAsConfigColumns AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbConfigColumns AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbConfigColumns AnchorSideBottom.Side = asrBottom Left = 704 Height = 23 Top = 4 Width = 50 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Left = 4 Caption = 'New' OnClick = btnSaveConfigColumnsClick TabOrder = 4 end object cmbFileSystem: TComboBox AnchorSideLeft.Control = lblFileSystem AnchorSideLeft.Side = asrBottom Left = 71 Height = 23 Top = 4 Width = 100 BorderSpacing.Left = 6 ItemHeight = 15 OnChange = cmbFileSystemChange Style = csDropDownList TabOrder = 0 end object lblFileSystem: TLabel Left = 4 Height = 15 Top = 9 Width = 61 Caption = '&File system:' ParentColor = False end end object pnlActualCont: TPanel[1] Left = 4 Height = 557 Top = 35 Width = 1062 Align = alClient Anchors = [akTop, akLeft, akBottom] ClientHeight = 557 ClientWidth = 1062 TabOrder = 1 object pnlGeneralColumnsViewSettings: TPanel Left = 1 Height = 33 Top = 156 Width = 1060 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 4 ClientHeight = 33 ClientWidth = 1060 TabOrder = 2 object chkUseCustomView: TCheckBox AnchorSideLeft.Control = pnlGeneralColumnsViewSettings AnchorSideTop.Control = pnlCommon AnchorSideTop.Side = asrCenter Left = 8 Height = 19 Top = 9 Width = 239 Caption = 'Use custom font and color for this view' Font.Style = [fsBold] OnChange = chkUseCustomViewChange ParentFont = False TabOrder = 0 end object btnGotoSetDefault: TButton AnchorSideLeft.Control = pnlCommon AnchorSideLeft.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 806 Height = 25 Top = 4 Width = 113 AutoSize = True BorderSpacing.Left = 7 Caption = 'Go to set default' OnClick = btnGotoSetDefaultClick TabOrder = 1 Visible = False end object pnlCommon: TPanel AnchorSideLeft.Control = chkUseCustomView AnchorSideLeft.Side = asrBottom Left = 282 Height = 22 Top = 7 Width = 517 AutoSize = True BorderSpacing.Left = 35 BevelOuter = bvNone ClientHeight = 22 ClientWidth = 517 TabOrder = 2 object cbCursorBorder: TCheckBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCursorBorderColor AnchorSideTop.Side = asrCenter Left = 35 Height = 19 Top = 2 Width = 93 BorderSpacing.Left = 35 Caption = 'Cursor border' OnChange = cbCursorBorderChange TabOrder = 0 end object cbCursorBorderColor: TColorBox AnchorSideLeft.Control = cbCursorBorder AnchorSideLeft.Side = asrBottom Left = 128 Height = 22 Top = 0 Width = 144 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] ItemHeight = 16 OnChange = cbCursorBorderColorChange TabOrder = 1 end object btnCursorBorderColor: TButton AnchorSideLeft.Control = cbCursorBorderColor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCursorBorderColor AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbCursorBorderColor AnchorSideBottom.Side = asrBottom Left = 273 Height = 22 Top = 0 Width = 28 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 1 BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnCursorBorderColorClick TabOrder = 2 end object btnResetCursorBorder: TButton AnchorSideLeft.Control = btnCursorBorderColor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnCursorBorderColor AnchorSideBottom.Control = btnCursorBorderColor AnchorSideBottom.Side = asrBottom Left = 302 Height = 22 Hint = 'Reset to default' Top = 0 Width = 33 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 1 Caption = 'R' OnClick = btnResetCursorBorderClick TabOrder = 3 end object cbUseFrameCursor: TCheckBox AnchorSideLeft.Control = btnResetCursorBorder AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCursorBorderColor AnchorSideTop.Side = asrCenter Left = 370 Height = 19 Top = 2 Width = 113 BorderSpacing.Left = 35 Caption = 'Use Frame Cursor' OnChange = cbUseFrameCursorChange TabOrder = 4 end object btnResetFrameCursor: TButton AnchorSideLeft.Control = cbUseFrameCursor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnCursorBorderColor AnchorSideBottom.Control = btnCursorBorderColor AnchorSideBottom.Side = asrBottom Left = 484 Height = 22 Hint = 'Reset to default' Top = 0 Width = 33 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 1 Caption = 'R' OnClick = btnResetFrameCursorClick TabOrder = 5 end end end object stgColumns: TStringGrid Left = 1 Height = 140 Top = 1 Width = 1060 Align = alTop ColCount = 7 Constraints.MinHeight = 80 FixedCols = 0 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goEditing, goSmoothScroll] PopupMenu = pmStringGrid RowCount = 3 TabOrder = 0 OnEditingDone = stgColumnsEditingDone OnKeyDown = stgColumnsKeyDown OnMouseDown = stgColumnsMouseDown OnMouseMove = stgColumnsMouseMove OnSelectEditor = stgColumnsSelectEditor ColWidths = ( 67 129 64 61 457 38 72 ) Cells = ( 7 0 0 'Column' 1 0 'Caption' 2 0 'Width' 3 0 'Align' 4 0 'Field contents' 5 0 'Move' 6 0 'Delete' ) end object spGridArea: TSplitter Cursor = crVSplit Left = 1 Height = 15 Top = 141 Width = 1060 Align = alTop Beveled = True MinSize = 15 ResizeAnchor = akTop end object pnlCustomColumnsViewSettings: TPanel Left = 1 Height = 179 Top = 189 Width = 1060 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 8 ClientHeight = 179 ClientWidth = 1060 TabOrder = 3 Visible = False object btnPrev: TButton AnchorSideLeft.Control = pnlCustomColumnsViewSettings AnchorSideTop.Control = pnlCustomColumnsViewSettings AnchorSideRight.Control = btnAllCursorColor AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 8 Height = 25 Top = 0 Width = 71 Caption = 'Previous' OnClick = btnPrevClick TabOrder = 0 end object btnNext: TButton AnchorSideLeft.Control = btnPrev AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnPrev AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 79 Height = 25 Top = 0 Width = 50 AutoSize = True Caption = 'Next' OnClick = btnNextClick TabOrder = 1 end object lblFontName: TLabel AnchorSideTop.Control = edtFont AnchorSideTop.Side = asrCenter AnchorSideRight.Control = edtFont Left = 51 Height = 15 Top = 34 Width = 27 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'Font:' ParentColor = False end object edtFont: TEdit AnchorSideLeft.Control = btnNext AnchorSideTop.Control = btnNext AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnFont Left = 79 Height = 23 Top = 30 Width = 301 BorderSpacing.Top = 5 BorderSpacing.Right = 1 ReadOnly = True TabOrder = 3 end object btnFont: TBitBtn AnchorSideLeft.Control = edtFont AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtFont AnchorSideTop.Side = asrCenter AnchorSideBottom.Side = asrBottom Left = 381 Height = 22 Top = 30 Width = 40 BorderSpacing.Bottom = 2 Caption = '...' OnClick = btnFontClick TabOrder = 4 end object lblFontSize: TLabel AnchorSideLeft.Control = btnFont AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnFont AnchorSideTop.Side = asrCenter Left = 425 Height = 15 Top = 34 Width = 23 BorderSpacing.Left = 4 Caption = 'Size:' ParentColor = False end object sneFontSize: TSpinEdit AnchorSideLeft.Control = lblFontSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtFont AnchorSideTop.Side = asrCenter AnchorSideBottom.Side = asrBottom Left = 452 Height = 23 Top = 30 Width = 48 BorderSpacing.Left = 4 MaxValue = 25 MinValue = 8 OnChange = sneFontSizeChange TabOrder = 5 Value = 8 end object btnResetFont: TButton AnchorSideLeft.Control = sneFontSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtFont AnchorSideTop.Side = asrCenter AnchorSideBottom.Side = asrBottom Left = 501 Height = 22 Hint = 'Reset to default' Top = 30 Width = 33 BorderSpacing.Left = 1 Caption = 'R' OnClick = btnResetFontClick TabOrder = 6 end object btnAllFont: TButton AnchorSideLeft.Control = btnResetFont AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtFont AnchorSideTop.Side = asrCenter Left = 535 Height = 22 Hint = 'Apply modification to all columns' Top = 30 Width = 40 BorderSpacing.Left = 1 Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 7 end object cbAllowOverColor: TCheckBox Tag = 11 AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetAllowOverColor Left = 863 Height = 19 Top = 153 Width = 105 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'Allow Overcolor' OnChange = cbAllowOvercolorChange TabOrder = 46 end object lblForeColor: TLabel Tag = 1 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbForeColor Left = 105 Height = 15 Top = 59 Width = 56 Anchors = [akTop, akRight] BorderSpacing.Right = 6 Caption = 'Text Color:' ParentColor = False end object lblBackColor: TLabel Tag = 2 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblForeColor AnchorSideRight.Side = asrBottom Left = 93 Height = 15 Top = 83 Width = 68 Anchors = [akTop, akRight] Caption = 'BackGround:' ParentColor = False end object lblBackColor2: TLabel Tag = 3 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblForeColor AnchorSideRight.Side = asrBottom Left = 85 Height = 15 Top = 107 Width = 76 Anchors = [akTop, akRight] Caption = 'Background 2:' ParentColor = False end object lblMarkColor: TLabel Tag = 4 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblForeColor AnchorSideRight.Side = asrBottom Left = 99 Height = 15 Top = 131 Width = 62 Anchors = [akTop, akRight] Caption = 'Mark Color:' ParentColor = False end object cbMarkColor: TColorBox Tag = 4 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbForeColor AnchorSideRight.Side = asrBottom Left = 167 Height = 22 Top = 127 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] BorderSpacing.Top = 2 ItemHeight = 16 OnChange = cbMarkColorChange TabOrder = 20 end object cbBackColor2: TColorBox Tag = 3 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbForeColor AnchorSideRight.Side = asrBottom Left = 167 Height = 22 Top = 103 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] BorderSpacing.Top = 2 ItemHeight = 16 OnChange = cbBackColor2Change TabOrder = 16 end object cbBackColor: TColorBox Tag = 2 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbForeColor AnchorSideRight.Side = asrBottom Left = 167 Height = 22 Top = 79 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] BorderSpacing.Top = 2 ItemHeight = 16 OnChange = cbBackColorChange TabOrder = 12 end object cbForeColor: TColorBox Tag = 1 AnchorSideTop.Control = edtFont AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnForeColor Left = 167 Height = 22 Top = 55 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 1 ItemHeight = 16 OnChange = cbForeColorChange ParentFont = False TabOrder = 8 end object btnForeColor: TButton Tag = 1 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetForeColor Left = 318 Height = 22 Top = 55 Width = 28 Anchors = [akTop, akRight] BorderSpacing.Right = 1 BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnForeColorClick TabOrder = 9 end object btnBackColor: TButton Tag = 2 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnForeColor AnchorSideRight.Side = asrBottom Left = 318 Height = 22 Top = 79 Width = 28 Anchors = [akTop, akRight] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnBackColorClick TabOrder = 13 end object btnBackColor2: TButton Tag = 3 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnForeColor AnchorSideRight.Side = asrBottom Left = 318 Height = 22 Top = 103 Width = 28 Anchors = [akTop, akRight] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnBackColor2Click TabOrder = 17 end object btnMarkColor: TButton Tag = 4 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnForeColor AnchorSideRight.Side = asrBottom Left = 318 Height = 22 Top = 127 Width = 28 Anchors = [akTop, akRight] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnMarkColorClick TabOrder = 21 end object btnResetMarkColor: TButton Tag = 4 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetForeColor AnchorSideRight.Side = asrBottom Left = 347 Height = 22 Hint = 'Reset to default' Top = 127 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetMarkColorClick TabOrder = 22 end object btnResetBackColor2: TButton Tag = 3 AnchorSideTop.Control = cbBackColor2 AnchorSideRight.Control = btnResetForeColor AnchorSideRight.Side = asrBottom Left = 347 Height = 22 Hint = 'Reset to default' Top = 103 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetBackColor2Click TabOrder = 18 end object btnResetBackColor: TButton Tag = 2 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetForeColor AnchorSideRight.Side = asrBottom Left = 347 Height = 22 Hint = 'Reset to default' Top = 79 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetBackColorClick TabOrder = 14 end object btnResetForeColor: TButton Tag = 1 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllForeColor AnchorSideBottom.Side = asrBottom Left = 347 Height = 22 Hint = 'Reset to default' Top = 55 Width = 33 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'R' OnClick = btnResetForeColorClick TabOrder = 10 end object btnAllForeColor: TButton Tag = 1 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnFont AnchorSideRight.Side = asrBottom Left = 381 Height = 22 Hint = 'Apply modification to all columns' Top = 55 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 11 end object btnAllBackColor: TButton Tag = 2 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnFont AnchorSideRight.Side = asrBottom Left = 381 Height = 22 Hint = 'Apply modification to all columns' Top = 79 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 15 end object btnAllBackColor2: TButton Tag = 3 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnFont AnchorSideRight.Side = asrBottom Left = 381 Height = 22 Hint = 'Apply modification to all columns' Top = 103 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 19 end object btnAllMarkColor: TButton Tag = 4 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnFont AnchorSideRight.Side = asrBottom Left = 381 Height = 22 Hint = 'Apply modification to all columns' Top = 127 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 23 end object lblInactiveMarkColor: TLabel Tag = 8 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblCursorColor AnchorSideRight.Side = asrBottom Left = 676 Height = 15 Top = 131 Width = 106 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'Inactive Mark Color:' ParentColor = False end object lblInactiveCursorColor: TLabel Tag = 7 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblCursorColor AnchorSideRight.Side = asrBottom Left = 669 Height = 15 Top = 107 Width = 114 Anchors = [akTop, akRight] Caption = 'Inactive Cursor Color:' ParentColor = False end object lblCursorText: TLabel Tag = 6 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblCursorColor AnchorSideRight.Side = asrBottom Left = 721 Height = 15 Top = 83 Width = 62 Anchors = [akTop, akRight] Caption = 'Cursor Text:' ParentColor = False end object lblCursorColor: TLabel Tag = 5 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbCursorColor Left = 713 Height = 15 Top = 59 Width = 70 Anchors = [akTop, akRight] BorderSpacing.Right = 6 Caption = 'Cursor Color:' ParentColor = False end object cbCursorColor: TColorBox Tag = 5 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCursorColor Left = 789 Height = 22 Top = 55 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] BorderSpacing.Right = 1 ItemHeight = 16 OnChange = cbCursorColorChange TabOrder = 24 end object cbCursorText: TColorBox Tag = 6 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbCursorColor AnchorSideRight.Side = asrBottom Left = 789 Height = 22 Top = 79 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] ItemHeight = 16 OnChange = cbCursorTextChange TabOrder = 28 end object cbInactiveCursorColor: TColorBox Tag = 7 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbCursorColor AnchorSideRight.Side = asrBottom Left = 789 Height = 22 Top = 103 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] ItemHeight = 16 OnChange = cbInactiveCursorColorChange TabOrder = 32 end object cbInactiveMarkColor: TColorBox Tag = 8 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbCursorColor AnchorSideRight.Side = asrBottom Left = 789 Height = 22 Top = 127 Width = 150 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbPrettyNames] Anchors = [akTop, akRight] ItemHeight = 16 OnChange = cbInactiveMarkColorChange TabOrder = 36 end object btnInactiveMarkColor: TButton Tag = 8 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCursorColor AnchorSideRight.Side = asrBottom Left = 940 Height = 22 Top = 127 Width = 28 Anchors = [akTop, akRight] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnInactiveMarkColorClick TabOrder = 37 end object btnInactiveCursorColor: TButton Tag = 7 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCursorColor AnchorSideRight.Side = asrBottom Left = 940 Height = 22 Top = 103 Width = 28 Anchors = [akTop, akRight] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnInactiveCursorColorClick TabOrder = 33 end object btnCursorText: TButton Tag = 6 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCursorColor AnchorSideRight.Side = asrBottom Left = 940 Height = 22 Top = 79 Width = 28 Anchors = [akTop, akRight] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnCursorTextClick TabOrder = 29 end object btnCursorColor: TButton Tag = 5 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetCursorColor Left = 940 Height = 22 Top = 55 Width = 28 Anchors = [akTop, akRight] BorderSpacing.Right = 1 BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnCursorColorClick TabOrder = 25 end object btnResetInactiveCursorColor: TButton Tag = 7 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetCursorColor AnchorSideRight.Side = asrBottom Left = 969 Height = 22 Hint = 'Reset to default' Top = 103 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetInactiveCursorColorClick TabOrder = 34 end object btnResetCursorText: TButton Tag = 6 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetCursorColor AnchorSideRight.Side = asrBottom Left = 969 Height = 22 Hint = 'Reset to default' Top = 79 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetCursorTextClick TabOrder = 30 end object btnResetCursorColor: TButton Tag = 5 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllCursorColor Left = 969 Height = 22 Hint = 'Reset to default' Top = 55 Width = 33 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'R' OnClick = btnResetCursorColorClick TabOrder = 26 end object btnAllCursorColor: TButton Tag = 5 AnchorSideTop.Control = cbForeColor AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 1003 Height = 22 Hint = 'Apply modification to all columns' Top = 55 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 27 end object btnAllCursorText: TButton Tag = 6 AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllCursorColor AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 1003 Height = 22 Hint = 'Apply modification to all columns' Top = 79 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 31 end object btnAllInactiveCursorColor: TButton Tag = 7 AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllCursorColor AnchorSideRight.Side = asrBottom Left = 1003 Height = 22 Hint = 'Apply modification to all columns' Top = 103 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 35 end object btnAllInactiveMarkColor: TButton Tag = 8 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllCursorColor AnchorSideRight.Side = asrBottom Left = 1003 Height = 22 Hint = 'Apply modification to all columns' Top = 127 Width = 40 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 39 end object btnResetInactiveMarkColor: TButton Tag = 8 AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetCursorColor AnchorSideRight.Side = asrBottom Left = 969 Height = 22 Hint = 'Reset to default' Top = 127 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetInactiveMarkColorClick TabOrder = 38 end object cbUseInvertedSelection: TCheckBox Tag = 9 AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetUseInvertedSelection Left = 111 Height = 19 Top = 153 Width = 136 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'Use Inverted Selection' OnChange = cbUseInvertedSelectionChange TabOrder = 40 end object cbUseInactiveSelColor: TCheckBox Tag = 10 AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetUseInactiveSelColor Left = 582 Height = 19 Top = 153 Width = 166 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'Use Inactive Selection Color' OnChange = cbUseInactiveSelColorChange TabOrder = 43 end object btnAllUseInvertedSelection: TButton Tag = 9 AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbMarkColor AnchorSideRight.Side = asrBottom Left = 282 Height = 22 Hint = 'Apply modification to all columns' Top = 151 Width = 35 Anchors = [akTop, akRight] Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 42 end object btnAllUseInactiveSelColor: TButton Tag = 10 AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbAllowOverColor Left = 783 Height = 22 Hint = 'Apply modification to all columns' Top = 151 Width = 40 Anchors = [akTop, akRight] BorderSpacing.Right = 40 Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 45 end object btnAllAllowOverColor: TButton Tag = 11 AnchorSideTop.Control = btnAllInactiveMarkColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnAllCursorColor AnchorSideRight.Side = asrBottom Left = 1003 Height = 22 Hint = 'Apply modification to all columns' Top = 151 Width = 40 Anchors = [akTop, akRight] BorderSpacing.Top = 2 BorderSpacing.Bottom = 6 Caption = 'All' OnClick = btnAllForeColorClick TabOrder = 48 end object lblWorkingColumn: TLabel AnchorSideLeft.Control = btnNext AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnPrev AnchorSideTop.Side = asrCenter Left = 134 Height = 15 Top = 5 Width = 113 BorderSpacing.Left = 5 Caption = 'Settings for column:' Font.Style = [fsBold] ParentColor = False ParentFont = False end object lblCurrentColumn: TLabel AnchorSideLeft.Control = lblWorkingColumn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnPrev AnchorSideTop.Side = asrCenter Left = 250 Height = 15 Top = 5 Width = 132 BorderSpacing.Left = 3 Caption = '[Current Column Name]' Font.Style = [fsBold] ParentColor = False ParentFont = False end object btnResetAllowOverColor: TButton Tag = 11 AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnResetCursorColor AnchorSideRight.Side = asrBottom Left = 969 Height = 22 Hint = 'Reset to default' Top = 151 Width = 33 Anchors = [akTop, akRight] Caption = 'R' OnClick = btnResetAllowOverColorClick TabOrder = 47 end object btnResetUseInvertedSelection: TButton Tag = 9 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllUseInvertedSelection Left = 248 Height = 22 Hint = 'Reset to default' Top = 151 Width = 33 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'R' OnClick = btnResetUseInvertedSelectionClick TabOrder = 41 end object btnResetUseInactiveSelColor: TButton Tag = 10 AnchorSideLeft.Control = btnCursorColor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnAllAllowOverColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAllUseInactiveSelColor Left = 749 Height = 22 Hint = 'Reset to default' Top = 151 Width = 33 Anchors = [akTop, akRight] BorderSpacing.Right = 1 Caption = 'R' OnClick = btnResetUseInactiveSelColorClick TabOrder = 44 end object cbApplyChangeForAllColumns: TCheckBox AnchorSideLeft.Control = sneFontSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnPrev AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 500 Height = 19 Top = 3 Width = 338 Caption = 'When clicking to change something, change for all columns' OnChange = cbApplyChangeForAllColumnsChange TabOrder = 2 end end object pnlPreviewCont: TKASToolPanel Left = 1 Height = 188 Top = 368 Width = 1060 Align = alClient ChildSizing.LeftRightSpacing = 8 TabOrder = 4 object lblPreviewTop: TDividerBevel Left = 8 Height = 15 Top = 8 Width = 1044 Caption = 'Below is a preview. You may move cursor and select files to get immediately an actual look and feel of the various settings.' Align = alTop BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 Font.Style = [fsBold] ParentColor = False ParentFont = False Style = gsHorLines end object pnlLeft: TPanel Left = 8 Height = 165 Top = 15 Width = 437 Align = alLeft BorderSpacing.Bottom = 8 BevelOuter = bvNone Constraints.MinWidth = 50 ParentColor = False TabOrder = 0 OnEnter = pnlLeftEnter end object pnlRight: TPanel Left = 456 Height = 165 Top = 15 Width = 596 Align = alClient BorderSpacing.Bottom = 8 BevelOuter = bvNone Constraints.MinWidth = 50 ParentColor = False TabOrder = 2 OnEnter = pnlRightEnter end object spltBetweenPanels: TSplitter Left = 445 Height = 173 Top = 15 Width = 11 end end end object pmStringGrid: TPopupMenu[2] left = 48 top = 72 object miAddColumn: TMenuItem Caption = 'Add column' OnClick = miAddColumnClick end end object pmFields: TPopupMenu[3] left = 136 top = 72 end object dlgfont: TFontDialog[4] MinFontSize = 0 MaxFontSize = 0 left = 216 top = 72 end object dlgcolor: TColorDialog[5] Color = clBlack CustomColors.Strings = ( 'ColorA=000000' 'ColorB=000080' 'ColorC=008000' 'ColorD=008080' 'ColorE=800000' 'ColorF=800080' 'ColorG=808000' 'ColorH=808080' 'ColorI=C0C0C0' 'ColorJ=0000FF' 'ColorK=00FF00' 'ColorL=00FFFF' 'ColorM=FF0000' 'ColorN=FF00FF' 'ColorO=FFFF00' 'ColorP=FFFFFF' 'ColorQ=C0DCC0' 'ColorR=F0CAA6' 'ColorS=F0FBFF' 'ColorT=A4A0A0' ) left = 304 top = 72 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionscustomcolumns.lrj�����������������������������������������������0000644�0001750�0000144�00000036772�14743153644�022077� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":253705818,"name":"tfrmoptionscustomcolumns.lblconfigcolumns.caption","sourcebytes":[38,67,111,108,117,109,110,115,32,118,105,101,119,58],"value":"&Columns view:"}, {"hash":231000124,"name":"tfrmoptionscustomcolumns.cbconfigcolumns.text","sourcebytes":[71,101,110,101,114,97,108],"value":"General"}, {"hash":366789,"name":"tfrmoptionscustomcolumns.btnsaveconfigcolumns.caption","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":93079605,"name":"tfrmoptionscustomcolumns.btnrenameconfigcolumns.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, {"hash":160200403,"name":"tfrmoptionscustomcolumns.btnsaveasconfigcolumns.caption","sourcebytes":[83,97,118,101,32,97,115],"value":"Save as"}, {"hash":179055749,"name":"tfrmoptionscustomcolumns.btndeleteconfigcolumns.caption","sourcebytes":[38,68,101,108,101,116,101],"value":"&Delete"}, {"hash":21703,"name":"tfrmoptionscustomcolumns.btnnewconfig.caption","sourcebytes":[78,101,119],"value":"New"}, {"hash":31100250,"name":"tfrmoptionscustomcolumns.lblfilesystem.caption","sourcebytes":[38,70,105,108,101,32,115,121,115,116,101,109,58],"value":"&File system:"}, {"hash":59568839,"name":"tfrmoptionscustomcolumns.chkusecustomview.caption","sourcebytes":[85,115,101,32,99,117,115,116,111,109,32,102,111,110,116,32,97,110,100,32,99,111,108,111,114,32,102,111,114,32,116,104,105,115,32,118,105,101,119],"value":"Use custom font and color for this view"}, {"hash":193682404,"name":"tfrmoptionscustomcolumns.btngotosetdefault.caption","sourcebytes":[71,111,32,116,111,32,115,101,116,32,100,101,102,97,117,108,116],"value":"Go to set default"}, {"hash":207563970,"name":"tfrmoptionscustomcolumns.cbcursorborder.caption","sourcebytes":[67,117,114,115,111,114,32,98,111,114,100,101,114],"value":"Cursor border"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btncursorbordercolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetcursorborder.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetcursorborder.caption","sourcebytes":[82],"value":"R"}, {"hash":7427170,"name":"tfrmoptionscustomcolumns.cbuseframecursor.caption","sourcebytes":[85,115,101,32,70,114,97,109,101,32,67,117,114,115,111,114],"value":"Use Frame Cursor"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetframecursor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetframecursor.caption","sourcebytes":[82],"value":"R"}, {"hash":147653555,"name":"tfrmoptionscustomcolumns.btnprev.caption","sourcebytes":[80,114,101,118,105,111,117,115],"value":"Previous"}, {"hash":347380,"name":"tfrmoptionscustomcolumns.btnnext.caption","sourcebytes":[78,101,120,116],"value":"Next"}, {"hash":5072250,"name":"tfrmoptionscustomcolumns.lblfontname.caption","sourcebytes":[70,111,110,116,58],"value":"Font:"}, {"hash":12558,"name":"tfrmoptionscustomcolumns.btnfont.caption","sourcebytes":[46,46,46],"value":"..."}, {"hash":5902474,"name":"tfrmoptionscustomcolumns.lblfontsize.caption","sourcebytes":[83,105,122,101,58],"value":"Size:"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetfont.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetfont.caption","sourcebytes":[82],"value":"R"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallfont.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallfont.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":266427794,"name":"tfrmoptionscustomcolumns.cballowovercolor.caption","sourcebytes":[65,108,108,111,119,32,79,118,101,114,99,111,108,111,114],"value":"Allow Overcolor"}, {"hash":81852730,"name":"tfrmoptionscustomcolumns.lblforecolor.caption","sourcebytes":[84,101,120,116,32,67,111,108,111,114,58],"value":"Text Color:"}, {"hash":249486730,"name":"tfrmoptionscustomcolumns.lblbackcolor.caption","sourcebytes":[66,97,99,107,71,114,111,117,110,100,58],"value":"BackGround:"}, {"hash":249462154,"name":"tfrmoptionscustomcolumns.lblbackcolor2.caption","sourcebytes":[66,97,99,107,103,114,111,117,110,100,32,50,58],"value":"Background 2:"}, {"hash":81247882,"name":"tfrmoptionscustomcolumns.lblmarkcolor.caption","sourcebytes":[77,97,114,107,32,67,111,108,111,114,58],"value":"Mark Color:"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btnforecolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btnbackcolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btnbackcolor2.caption","sourcebytes":[62,62],"value":">>"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btnmarkcolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetmarkcolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetmarkcolor.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetbackcolor2.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetbackcolor2.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetbackcolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetbackcolor.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetforecolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetforecolor.caption","sourcebytes":[82],"value":"R"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallforecolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallforecolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallbackcolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallbackcolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallbackcolor2.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallbackcolor2.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallmarkcolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallmarkcolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":132983626,"name":"tfrmoptionscustomcolumns.lblinactivemarkcolor.caption","sourcebytes":[73,110,97,99,116,105,118,101,32,77,97,114,107,32,67,111,108,111,114,58],"value":"Inactive Mark Color:"}, {"hash":83514154,"name":"tfrmoptionscustomcolumns.lblinactivecursorcolor.caption","sourcebytes":[73,110,97,99,116,105,118,101,32,67,117,114,115,111,114,32,67,111,108,111,114,58],"value":"Inactive Cursor Color:"}, {"hash":16143642,"name":"tfrmoptionscustomcolumns.lblcursortext.caption","sourcebytes":[67,117,114,115,111,114,32,84,101,120,116,58],"value":"Cursor Text:"}, {"hash":242061402,"name":"tfrmoptionscustomcolumns.lblcursorcolor.caption","sourcebytes":[67,117,114,115,111,114,32,67,111,108,111,114,58],"value":"Cursor Color:"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btninactivemarkcolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btninactivecursorcolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btncursortext.caption","sourcebytes":[62,62],"value":">>"}, {"hash":1054,"name":"tfrmoptionscustomcolumns.btncursorcolor.caption","sourcebytes":[62,62],"value":">>"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetinactivecursorcolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetinactivecursorcolor.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetcursortext.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetcursortext.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetcursorcolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetcursorcolor.caption","sourcebytes":[82],"value":"R"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallcursorcolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallcursorcolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallcursortext.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallcursortext.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallinactivecursorcolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallinactivecursorcolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallinactivemarkcolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallinactivemarkcolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetinactivemarkcolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetinactivemarkcolor.caption","sourcebytes":[82],"value":"R"}, {"hash":218952766,"name":"tfrmoptionscustomcolumns.cbuseinvertedselection.caption","sourcebytes":[85,115,101,32,73,110,118,101,114,116,101,100,32,83,101,108,101,99,116,105,111,110],"value":"Use Inverted Selection"}, {"hash":120988962,"name":"tfrmoptionscustomcolumns.cbuseinactiveselcolor.caption","sourcebytes":[85,115,101,32,73,110,97,99,116,105,118,101,32,83,101,108,101,99,116,105,111,110,32,67,111,108,111,114],"value":"Use Inactive Selection Color"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnalluseinvertedselection.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnalluseinvertedselection.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnalluseinactiveselcolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnalluseinactiveselcolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":8810707,"name":"tfrmoptionscustomcolumns.btnallallowovercolor.hint","sourcebytes":[65,112,112,108,121,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,111,32,97,108,108,32,99,111,108,117,109,110,115],"value":"Apply modification to all columns"}, {"hash":18476,"name":"tfrmoptionscustomcolumns.btnallallowovercolor.caption","sourcebytes":[65,108,108],"value":"All"}, {"hash":26994442,"name":"tfrmoptionscustomcolumns.lblworkingcolumn.caption","sourcebytes":[83,101,116,116,105,110,103,115,32,102,111,114,32,99,111,108,117,109,110,58],"value":"Settings for column:"}, {"hash":141213869,"name":"tfrmoptionscustomcolumns.lblcurrentcolumn.caption","sourcebytes":[91,67,117,114,114,101,110,116,32,67,111,108,117,109,110,32,78,97,109,101,93],"value":"[Current Column Name]"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetallowovercolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetallowovercolor.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetuseinvertedselection.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetuseinvertedselection.caption","sourcebytes":[82],"value":"R"}, {"hash":115259332,"name":"tfrmoptionscustomcolumns.btnresetuseinactiveselcolor.hint","sourcebytes":[82,101,115,101,116,32,116,111,32,100,101,102,97,117,108,116],"value":"Reset to default"}, {"hash":82,"name":"tfrmoptionscustomcolumns.btnresetuseinactiveselcolor.caption","sourcebytes":[82],"value":"R"}, {"hash":187433363,"name":"tfrmoptionscustomcolumns.cbapplychangeforallcolumns.caption","sourcebytes":[87,104,101,110,32,99,108,105,99,107,105,110,103,32,116,111,32,99,104,97,110,103,101,32,115,111,109,101,116,104,105,110,103,44,32,99,104,97,110,103,101,32,102,111,114,32,97,108,108,32,99,111,108,117,109,110,115],"value":"When clicking to change something, change for all columns"}, {"hash":97427902,"name":"tfrmoptionscustomcolumns.lblpreviewtop.caption","sourcebytes":[66,101,108,111,119,32,105,115,32,97,32,112,114,101,118,105,101,119,46,32,89,111,117,32,109,97,121,32,109,111,118,101,32,99,117,114,115,111,114,32,97,110,100,32,115,101,108,101,99,116,32,102,105,108,101,115,32,116,111,32,103,101,116,32,105,109,109,101,100,105,97,116,101,108,121,32,97,110,32,97,99,116,117,97,108,32,108,111,111,107,32,97,110,100,32,102,101,101,108,32,111,102,32,116,104,101,32,118,97,114,105,111,117,115,32,115,101,116,116,105,110,103,115,46],"value":"Below is a preview. You may move cursor and select files to get immediately an actual look and feel of the various settings."}, {"hash":111297118,"name":"tfrmoptionscustomcolumns.miaddcolumn.caption","sourcebytes":[65,100,100,32,99,111,108,117,109,110],"value":"Add column"} ]} ������doublecmd-1.1.22/src/frames/foptionscustomcolumns.pas�����������������������������������������������0000644�0001750�0000144�00000161617�14743153644�022070� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Custom columns options page Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsCustomColumns; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. ComCtrls, Controls, Classes, SysUtils, StdCtrls, ExtCtrls, Forms, ColorBox, Buttons, Spin, Grids, Menus, Dialogs, LMessages, DividerBevel, //DC uColumns, KASToolPanel, fOptionsFrame, uColumnsFileView; type { TfrmOptionsCustomColumns } TfrmOptionsCustomColumns = class(TOptionsEditor) btnAllAllowOverColor: TButton; btnAllBackColor: TButton; btnAllBackColor2: TButton; btnAllCursorColor: TButton; btnAllCursorText: TButton; btnAllFont: TButton; btnAllForeColor: TButton; btnAllInactiveCursorColor: TButton; btnAllInactiveMarkColor: TButton; btnAllMarkColor: TButton; btnAllUseInactiveSelColor: TButton; btnAllUseInvertedSelection: TButton; btnBackColor: TButton; btnBackColor2: TButton; btnCursorBorderColor: TButton; btnGotoSetDefault: TButton; btnResetCursorBorder: TButton; btnResetFrameCursor: TButton; btnSaveAsConfigColumns: TButton; btnCursorColor: TButton; btnCursorText: TButton; btnDeleteConfigColumns: TButton; btnFont: TBitBtn; btnForeColor: TButton; btnInactiveCursorColor: TButton; btnInactiveMarkColor: TButton; btnMarkColor: TButton; btnNext: TButton; btnNewConfig: TButton; btnPrev: TButton; btnRenameConfigColumns: TButton; btnResetAllowOverColor: TButton; btnResetBackColor: TButton; btnResetBackColor2: TButton; btnResetCursorColor: TButton; btnResetCursorText: TButton; btnResetFont: TButton; btnResetForeColor: TButton; btnResetInactiveCursorColor: TButton; btnResetInactiveMarkColor: TButton; btnResetMarkColor: TButton; btnResetUseInactiveSelColor: TButton; btnResetUseInvertedSelection: TButton; btnSaveConfigColumns: TButton; cbAllowOverColor: TCheckBox; cbApplyChangeForAllColumns: TCheckBox; cbBackColor: TColorBox; cbBackColor2: TColorBox; cbConfigColumns: TComboBox; cbCursorBorder: TCheckBox; cbCursorBorderColor: TColorBox; cbCursorColor: TColorBox; cbCursorText: TColorBox; cbForeColor: TColorBox; cbInactiveCursorColor: TColorBox; cbInactiveMarkColor: TColorBox; cbMarkColor: TColorBox; cbUseFrameCursor: TCheckBox; cbUseInactiveSelColor: TCheckBox; cbUseInvertedSelection: TCheckBox; chkUseCustomView: TCheckBox; cmbFileSystem: TComboBox; dlgcolor: TColorDialog; dlgfont: TFontDialog; edtFont: TEdit; lblFileSystem: TLabel; lblBackColor: TLabel; lblBackColor2: TLabel; lblConfigColumns: TLabel; lblCurrentColumn: TLabel; lblCursorColor: TLabel; lblCursorText: TLabel; lblFontName: TLabel; lblFontSize: TLabel; lblForeColor: TLabel; lblInactiveCursorColor: TLabel; lblInactiveMarkColor: TLabel; lblMarkColor: TLabel; lblPreviewTop: TDividerBevel; lblWorkingColumn: TLabel; miAddColumn: TMenuItem; pnlCommon: TPanel; pnlCustomColumnsViewSettings: TPanel; pmFields: TPopupMenu; pmStringGrid: TPopupMenu; pnlActualCont: TPanel; pnlConfigColumns: TPanel; pnlGeneralColumnsViewSettings: TPanel; pnlLeft: TPanel; pnlPreviewCont: TKASToolPanel; pnlRight: TPanel; sneFontSize: TSpinEdit; spGridArea: TSplitter; spltBetweenPanels: TSplitter; stgColumns: TStringGrid; procedure btnGotoSetDefaultClick(Sender: TObject); procedure cmbFileSystemChange(Sender: TObject); procedure FillFileSystemList; procedure FillColumnsList; procedure cbConfigColumnsChange(Sender: TObject); procedure btnSaveConfigColumnsClick(Sender: TObject); procedure btnDeleteConfigColumnsClick(Sender: TObject); procedure UpdatePageInfoFromColumnClass; procedure UpdateColumnClass; procedure stgColumnsSelectEditor(Sender: TObject; aCol, aRow: integer; var Editor: TWinControl); procedure stgColumnsKeyDown(Sender: TObject; var Key: word; {%H-}Shift: TShiftState); procedure stgColumnsMouseDown(Sender: TObject; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: integer); procedure stgColumnsMouseMove(Sender: TObject; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: integer); procedure CreateEditingControls; procedure EditorKeyDown(Sender: TObject; var Key: word; {%H-}Shift: TShiftState); procedure AddNewField; procedure miAddColumnClick(Sender: TObject); procedure stgSetSelectionAsHintToUser; procedure stgColumnsEditingDone(Sender: TObject); procedure MenuFieldsClick(Sender: TObject); procedure EditorSaveResult(Sender: TObject); procedure CustomSomethingChanged(Sender: TObject); procedure LoadCustColumn(const Index: integer); procedure chkUseCustomViewChange(Sender: TObject); procedure cbCursorBorderChange(Sender: TObject); procedure cbCursorBorderColorChange(Sender: TObject); procedure btnCursorBorderColorClick(Sender: TObject); procedure btnResetCursorBorderClick(Sender: TObject); procedure cbUseFrameCursorChange(Sender: TObject); procedure btnResetFrameCursorClick(Sender: TObject); procedure btnPrevClick(Sender: TObject); procedure btnNextClick(Sender: TObject); procedure cbApplyChangeForAllColumnsChange(Sender: TObject); procedure btnFontClick(Sender: TObject); procedure sneFontSizeChange(Sender: TObject); procedure btnResetFontClick(Sender: TObject); procedure btnAllForeColorClick(Sender: TObject); procedure cbForeColorChange(Sender: TObject); procedure btnForeColorClick(Sender: TObject); procedure btnResetForeColorClick(Sender: TObject); procedure cbBackColorChange(Sender: TObject); procedure btnBackColorClick(Sender: TObject); procedure btnResetBackColorClick(Sender: TObject); procedure cbBackColor2Change(Sender: TObject); procedure btnBackColor2Click(Sender: TObject); procedure btnResetBackColor2Click(Sender: TObject); procedure cbMarkColorChange(Sender: TObject); procedure btnMarkColorClick(Sender: TObject); procedure btnResetMarkColorClick(Sender: TObject); procedure cbCursorColorChange(Sender: TObject); procedure btnCursorColorClick(Sender: TObject); procedure btnResetCursorColorClick(Sender: TObject); procedure cbCursorTextChange(Sender: TObject); procedure btnCursorTextClick(Sender: TObject); procedure btnResetCursorTextClick(Sender: TObject); procedure cbInactiveCursorColorChange(Sender: TObject); procedure btnInactiveCursorColorClick(Sender: TObject); procedure btnResetInactiveCursorColorClick(Sender: TObject); procedure cbInactiveMarkColorChange(Sender: TObject); procedure btnInactiveMarkColorClick(Sender: TObject); procedure btnResetInactiveMarkColorClick(Sender: TObject); procedure cbUseInvertedSelectionChange(Sender: TObject); procedure btnResetUseInvertedSelectionClick(Sender: TObject); procedure cbUseInactiveSelColorChange(Sender: TObject); procedure btnResetUseInactiveSelColorClick(Sender: TObject); procedure cbAllowOvercolorChange(Sender: TObject); procedure btnResetAllowOverColorClick(Sender: TObject); procedure pnlLeftEnter(Sender: TObject); procedure pnlRightEnter(Sender: TObject); procedure OnColumnResized(Sender: TObject; ColumnIndex: integer; ColumnNewsize: integer); {Editors} procedure SpinEditExit(Sender: TObject); procedure SpinEditChange(Sender: TObject); procedure EditExit(Sender: TObject); procedure BitBtnDeleteFieldClick(Sender: TObject); procedure btnAddClick(Sender: TObject); procedure ComboBoxXSelect(Sender: TObject); procedure UpDownXClick(Sender: TObject; {%H-}Button: TUDBtnType); procedure UpDownXChanging(Sender: TObject; var {%H-}AllowChange: boolean); private ColPrm: TColPrm; ColumnClass: TPanelColumnsClass; PreviewLeftPanel: TColumnsFileView; PreviewRightPanel: TColumnsFileView; updWidth: TSpinEdit; cbbAlign: TComboBox; edtField: TEdit; btnAdd: TButton; btnDel: TBitBtn; updMove: TUpDown; bColumnConfigLoaded: boolean; FUpdating: boolean; ColumnClassOwnership: boolean; IndexRaw: integer; FCellValue: string; protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure Done; override; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public class function GetIconIndex: integer; override; class function GetTitle: string; override; function IsSignatureComputedFromAllWindowComponents: Boolean; override; function ExtraOptionsSignature(CurrentSignature:dword):dword; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. strutils, Graphics, LCLType, //DC DCStrUtils, fOptions, uShowMsg, uDebug, uFileFunctions, DCOSUtils, uFileSystemFileSource, uDCUtils, uGlobs, uLng, fMain, fOptionsFilePanelsColors; { TfrmOptionsCustomColumns } type THackStringGrid = class(TCustomStringGrid) end; { TfrmOptionsCustomColumns.Load } procedure TfrmOptionsCustomColumns.Load; var Index: Integer; AColumnClass: TPanelColumnsClass; begin //1. Init some flags bColumnConfigLoaded := False; FUpdating := False; ColumnClassOwnership := True; //2. Create some objects we need for this page. ColPrm := nil; ColumnClass := TPanelColumnsClass.Create; lblPreviewTop.Caption := rsMsgPanelPreview; CreateEditingControls; //3. Load stuff for our preview lblWorkingColumn.Caption := rsConfCustHeader + ':'; PreviewLeftPanel := TColumnsFileView.Create(pnlLeft, TFileSystemFileSource.Create, mbGetCurrentDir); PreviewLeftPanel.OnColumnResized := @Self.OnColumnResized; PreviewLeftPanel.JustForColorPreviewSetActiveState(True); PreviewRightPanel := TColumnsFileView.Create(pnlRight, TFileSystemFileSource.Create, mbGetCurrentDir); PreviewRightPanel.OnColumnResized := @Self.OnColumnResized; PreviewRightPanel.JustForColorPreviewSetActiveState(False); //4. Load our list of columns set. FillFileSystemList; cmbFileSystemChange(cmbFileSystem); //5. Select the one we currently have in the active panel if possible. User won't be lost and it's the most pertinent thing to do. if frmMain.ActiveNotebook.ActiveView.ClassNameIs('TColumnsFileView') then begin AColumnClass:= ColSet.GetColumnSet(TColumnsFileView(frmMain.ActiveNotebook.ActiveView).ActiveColm); if Assigned(AColumnClass) then begin Index:= cmbFileSystem.Items.IndexOf(AColumnClass.FileSystem); if Index >= 0 then begin cmbFileSystem.ItemIndex:= Index; cmbFileSystemChange(cmbFileSystem); cbConfigColumns.ItemIndex := cbConfigColumns.Items.IndexOf(AColumnClass.Name); pnlLeft.Width := frmMain.ActiveNotebook.Width; end; end; end; if (cbConfigColumns.ItemIndex = -1) and (cbConfigColumns.Items.Count > 0) then cbConfigColumns.ItemIndex := 0; //6. We have mostly loaded what needed to be load. bColumnConfigLoaded := True; //7. Now let's show what we've got for that view. cbConfigColumnsChange(cbConfigColumns); //8. Local action cbApplyChangeForAllColumns.Checked := gCustomColumnsChangeAllColumns; end; { TfrmOptionsCustomColumns.Save } function TfrmOptionsCustomColumns.Save: TOptionsEditorSaveFlags; begin gCustomColumnsChangeAllColumns := cbApplyChangeForAllColumns.Checked; btnSaveConfigColumnsClick(btnSaveConfigColumns); Result := []; end; { TfrmOptionsCustomColumns.Done } procedure TfrmOptionsCustomColumns.Done; var i: integer; begin if Assigned(PreviewLeftPanel) then FreeAndNil(PreviewLeftPanel); if Assigned(PreviewRightPanel) then FreeAndNil(PreviewRightPanel); if (ColumnClassOwnership = True) and Assigned(ColumnClass) then FreeAndNil(ColumnClass); // Free TColPrm objects assigned to each row. for i := 0 to stgColumns.RowCount - 1 do begin if Assigned(stgColumns.Objects[6, i]) then begin (stgColumns.Objects[6, i] as TColPrm).Free; stgColumns.Objects[6, i] := nil; end; end; end; procedure TfrmOptionsCustomColumns.CMThemeChanged(var Message: TLMessage); begin cbConfigColumnsChange(cbConfigColumns); end; { TfrmOptionsCustomColumns.GetIconIndex } class function TfrmOptionsCustomColumns.GetIconIndex: integer; begin Result := 30; end; { TfrmOptionsCustomColumns.GetTitle } class function TfrmOptionsCustomColumns.GetTitle: string; begin Result := rsOptionsEditorCustomColumns; end; { TfrmOptionsCustomColumns.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsCustomColumns.IsSignatureComputedFromAllWindowComponents: Boolean; begin result := False; end; { TfrmOptionsCustomColumns.ExtraOptionsSignature } function TfrmOptionsCustomColumns.ExtraOptionsSignature(CurrentSignature:dword):dword; begin result := ColumnClass.GetSignature(CurrentSignature); end; { TfrmOptionsCustomColumns.FillColumnsList } procedure TfrmOptionsCustomColumns.FillColumnsList; var Index: Integer; begin cbConfigColumns.Clear; for Index:= 0 to ColSet.Items.Count - 1 do begin if SameText(TPanelColumnsClass(ColSet.Items.Objects[Index]).FileSystem, cmbFileSystem.Text) then begin cbConfigColumns.Items.AddObject(ColSet.Items[Index], TObject(PtrInt(Index))); end; end; end; { TfrmOptionsCustomColumns.btnGotoSetDefaultClick } procedure TfrmOptionsCustomColumns.btnGotoSetDefaultClick(Sender: TObject); begin ShowOptions(TfrmOptionsFilePanelsColors); end; procedure TfrmOptionsCustomColumns.cmbFileSystemChange(Sender: TObject); begin FillColumnsList; if cbConfigColumns.Items.Count > 0 then begin cbConfigColumns.ItemIndex:= 0; cbConfigColumnsChange(cbConfigColumns); end else begin stgColumns.RowCount:= 1; btnRenameConfigColumns.Enabled:= False; btnDeleteConfigColumns.Enabled:= False; end; pnlActualCont.Enabled:= cbConfigColumns.Items.Count > 0; btnSaveAsConfigColumns.Enabled:= pnlActualCont.Enabled; cbConfigColumns.Enabled:= pnlActualCont.Enabled; end; procedure TfrmOptionsCustomColumns.FillFileSystemList; var Index: Integer; begin cmbFileSystem.Clear; cmbFileSystem.Items.Add(FS_GENERAL); for Index:= 0 to gWFXPlugins.Count - 1 do begin cmbFileSystem.Items.Add(gWFXPlugins.Name[Index]); end; cmbFileSystem.ItemIndex:= 0; end; { TfrmOptionsCustomColumns.cbConfigColumnsChange } procedure TfrmOptionsCustomColumns.cbConfigColumnsChange(Sender: TObject); begin if bColumnConfigLoaded and (cbConfigColumns.ItemIndex >= 0) then begin ColumnClass.Assign(ColSet.GetColumnSet(PtrInt(cbConfigColumns.Items.Objects[cbConfigColumns.ItemIndex]))); LastLoadedOptionSignature := ComputeCompleteOptionsSignature; cbConfigColumns.Enabled := True; btnSaveConfigColumns.Enabled := False; btnRenameConfigColumns.Enabled := True; btnNewConfig.Enabled := True; UpdatePageInfoFromColumnClass; end; end; { TfrmOptionsCustomColumns.btnSaveConfigColumnsClick } procedure TfrmOptionsCustomColumns.btnSaveConfigColumnsClick(Sender: TObject); var Index: PtrInt = -1; SuggestedCustomColumnsName: String; ColumnClassForConfig: TPanelColumnsClass; begin // We won't free that one obviously because it's the one that will now be in global application system memory ColumnClassForConfig := TPanelColumnsClass.Create; if cbConfigColumns.Items.Count > 0 then begin UpdateColumnClass; ColumnClassForConfig.Assign(ColumnClass); Index:= PtrInt(cbConfigColumns.Items.Objects[cbConfigColumns.ItemIndex]); end; case TComponent(Sender).tag of 1: // Save. begin if Index < 0 then ColumnClassForConfig.Free else begin ColSet.DeleteColumnSet(Index); Colset.Insert(Index, ColumnClassForConfig); cbConfigColumnsChange(cbConfigColumns); end; end; 2: // Save as. begin SuggestedCustomColumnsName := ColumnClassForConfig.Name + '(' + GetDateTimeInStrEZSortable(now) + ')'; ShowInputQuery(rsOptionsEditorCustomColumns, rsMenuConfigureEnterCustomColumnName, SuggestedCustomColumnsName); if (SuggestedCustomColumnsName = '') or (cbConfigColumns.Items.indexof(SuggestedCustomColumnsName) <> -1) then SuggestedCustomColumnsName := ColumnClassForConfig.Name + '(' + GetDateTimeInStrEZSortable(now) + ')'; ColumnClassForConfig.Name := SuggestedCustomColumnsName; ColumnClassForConfig.Unique := EmptyStr; ColSet.Add(ColumnClassForConfig); FillColumnsList; cbConfigColumns.ItemIndex := cbConfigColumns.Items.IndexOf(ColumnClassForConfig.Name); cbConfigColumnsChange(cbConfigColumns); end; 3: // New. begin FreeAndNil(ColumnClassForConfig); ColumnClassForConfig := TPanelColumnsClass.Create; ColumnClassForConfig.AddDefaultEverything; ColumnClassForConfig.FileSystem := cmbFileSystem.Text; ColumnClassForConfig.Name := ColumnClassForConfig.Name + ' (' + GetDateTimeInStrEZSortable(now) + ')'; ColSet.Add(ColumnClassForConfig); cmbFileSystemChange(cmbFileSystem); cbConfigColumns.ItemIndex := cbConfigColumns.Items.IndexOf(ColumnClassForConfig.Name); cbConfigColumnsChange(cbConfigColumns); end; 4: // Rename. begin SuggestedCustomColumnsName := cbConfigColumns.Items.Strings[cbConfigColumns.ItemIndex]; if ShowInputQuery(rsOptionsEditorCustomColumns, rsMenuConfigureEnterCustomColumnName, SuggestedCustomColumnsName) then begin if (SuggestedCustomColumnsName <> '') then begin if Colset.Items.indexof(SuggestedCustomColumnsName) = -1 then begin ColumnClassForConfig.Name := SuggestedCustomColumnsName; ColSet.DeleteColumnSet(Index); Colset.Insert(Index, ColumnClassForConfig); FillColumnsList; cbConfigColumns.ItemIndex := cbConfigColumns.Items.IndexOf(ColumnClassForConfig.Name); cbConfigColumnsChange(cbConfigColumns); end else begin msgError(rsMenuConfigureColumnsAlreadyExists); end; end; end; end; end; end; { TfrmOptionsCustomColumns.btnDeleteConfigColumnsClick } procedure TfrmOptionsCustomColumns.btnDeleteConfigColumnsClick(Sender: TObject); begin if cbConfigColumns.ItemIndex = -1 then Exit; if (cbConfigColumns.Items.Count = 1) and (cmbFileSystem.ItemIndex = 0) then Exit; ColSet.DeleteColumnSet(PtrInt(cbConfigColumns.Items.Objects[cbConfigColumns.ItemIndex])); cmbFileSystemChange(cmbFileSystem); end; { TfrmOptionsCustomColumns.UpdatePageInfoFromColumnClass } // ***Important routine. // Take the initial info from the ColumnClass and organize the form's components to reflect that. procedure TfrmOptionsCustomColumns.UpdatePageInfoFromColumnClass; var I: integer; begin PreviewLeftPanel.ActiveColmSlave := ColumnClass; PreviewLeftPanel.isSlave := True; PreviewLeftPanel.Demo := True; PreviewRightPanel.ActiveColmSlave := ColumnClass; PreviewRightPanel.isSlave := True; PreviewRightPanel.Demo := True; if ColumnClass.ColumnsCount > 0 then begin stgColumns.RowCount := ColumnClass.ColumnsCount + 1; for i := 0 to ColumnClass.ColumnsCount - 1 do begin stgColumns.Cells[1, i + 1] := ColumnClass.GetColumnTitle(i); stgColumns.Cells[2, i + 1] := IntToStr(ColumnClass.GetColumnWidth(i)); stgColumns.Cells[3, i + 1] := ColumnClass.GetColumnAlignString(i); stgColumns.Cells[4, i + 1] := ColumnClass.GetColumnFuncString(i); stgColumns.Objects[5, i + 1] := ColumnClass.GetColumnItem(i); stgColumns.Objects[6, i + 1] := ColumnClass.GetColumnPrm(i); end; end else begin stgColumns.RowCount := 1; AddNewField; end; PreviewLeftPanel.UpdateColumnsView; PreviewRightPanel.UpdateColumnsView; FUpdating := True; chkUseCustomView.Checked := ColumnClass.CustomView; chkUseCustomViewChange(chkUseCustomView); cbCursorBorder.Checked := ColumnClass.UseCursorBorder; SetColorInColorBox(cbCursorBorderColor, ColumnClass.CursorBorderColor); cbUseFrameCursor.Checked := ColumnClass.UseFrameCursor; FUpdating := False; // Localize StringGrid header stgColumns.Cells[0, 0] := rsSimpleWordColumnSingular; stgColumns.Cells[1, 0] := rsConfColCaption; stgColumns.Cells[2, 0] := rsConfColWidth; stgColumns.Cells[3, 0] := rsConfColAlign; stgColumns.Cells[4, 0] := rsConfColFieldCont; stgColumns.Cells[5, 0] := rsConfColMove; stgColumns.Cells[6, 0] := rsConfColDelete; LoadCustColumn(0); end; { TfrmOptionsCustomColumns.UpdateColumnClass } // ***Important routine. Convert the current form components into the current working "ColumnClass". // ***It is not saved to file yet, but if we do, it will be that one! procedure TfrmOptionsCustomColumns.UpdateColumnClass; var Index: Integer; AItem: TPanelColumn; begin // Save fields for Index := 1 to stgColumns.RowCount - 1 do begin with stgColumns do begin AItem:= TPanelColumn(Objects[5, Index]); AItem.Title := Cells[1, Index]; AItem.Width := StrToInt(Cells[2, Index]); AItem.Align := StrToAlign(Cells[3, Index]); AItem.FuncString := Cells[4, Index]; end; if stgColumns.Objects[6, Index] <> nil then ColumnClass.SetColumnPrm(Index - 1, TColPrm(stgColumns.Objects[6, Index])); end; ColumnClass.FileSystem := cmbFileSystem.Text; ColumnClass.CustomView := chkUseCustomView.Checked; ColumnClass.UseCursorBorder := cbCursorBorder.Checked; ColumnClass.CursorBorderColor := cbCursorBorderColor.Selected; ColumnClass.UseFrameCursor := cbUseFrameCursor.Checked; ColumnClass.Name := cbConfigColumns.Items.Strings[cbConfigColumns.ItemIndex]; if LastLoadedOptionSignature = ComputeCompleteOptionsSignature then begin cbConfigColumns.Enabled := True; cbConfigColumns.Hint := ''; btnSaveConfigColumns.Enabled := False; btnRenameConfigColumns.Enabled := True; btnNewConfig.Enabled := True; end else begin cbConfigColumns.Enabled := False; cbConfigColumns.Hint := rsMenuConfigureColumnsSaveToChange; btnSaveConfigColumns.Enabled := True; btnRenameConfigColumns.Enabled := False; btnNewConfig.Enabled := False; end; PreviewLeftPanel.UpdateColumnsView; PreviewLeftPanel.Reload; PreviewRightPanel.UpdateColumnsView; PreviewRightPanel.Reload; end; { TfrmOptionsCustomColumns.stgColumnsSelectEditor } procedure TfrmOptionsCustomColumns.stgColumnsSelectEditor(Sender: TObject; aCol, aRow: integer; var Editor: TWinControl); begin // Hide '+' button in other columns than 4th (Field contents). if (aCol <> 4) and btnAdd.Visible then btnAdd.Hide; try FUpdating := True; case aCol of 0: // Just the arrow pointing the "active" columns begin Editor := nil; end; 2: // Width begin with updWidth do begin Left := (Sender as TStringGrid).CellRect(aCol, aRow).Left; Top := (Sender as TStringGrid).CellRect(aCol, aRow).Top; Height := (Sender as TStringGrid).RowHeights[aRow]; Width := (Sender as TStringGrid).ColWidths[aCol]; Value := StrToInt((Sender as TStringGrid).Cells[aCol, aRow]); end; Editor := updWidth; end; 3: // Columns alignment begin with cbbAlign do begin Width := (Sender as TStringGrid).ColWidths[aCol]; Left := (Sender as TStringGrid).CellRect(aCol, aRow).Left; Top := (Sender as TStringGrid).CellRect(aCol, aRow).Top; Height := (Sender as TStringGrid).RowHeights[aRow]; ItemIndex := Items.IndexOf((Sender as TStringGrid).Cells[aCol, aRow]); end; Editor := cbbAlign; end; 4: // Field contents begin with btnAdd do begin Width := 20; Left := (Sender as TStringGrid).CellRect(aCol, aRow).Right - Width; Top := (Sender as TStringGrid).CellRect(aCol, aRow).Top; Height := (Sender as TStringGrid).RowHeights[aRow]; Tag := aRow; Show; end; with edtField do begin Width := (Sender as TStringGrid).ColWidths[aCol]; Left := (Sender as TStringGrid).CellRect(aCol, aRow).Left; Top := (Sender as TStringGrid).CellRect(aCol, aRow).Top; Height := (Sender as TStringGrid).RowHeights[aRow]; Text := (Sender as TStringGrid).Cells[aCol, aRow]; end; Editor := edtField; end; 5: // Move columns begin with updMove do begin Height := stgColumns.RowHeights[aRow]; Width := stgColumns.ColWidths[aCol] - 2; Min := -((Sender as TStringGrid).RowCount - 1); Max := -1; Position := -aRow; Left := (Sender as TStringGrid).CellRect(aCol, aRow).Right - Width; Top := (Sender as TStringGrid).CellRect(aCol, aRow).Top; end; Editor := updMove; end; 6: // Delete columns begin // Only show delete button if there is more than one column. if (stgColumns.RowCount - stgColumns.FixedRows) > 1 then begin with btnDel do begin Height := stgColumns.RowHeights[aRow]; Width := stgColumns.ColWidths[aCol] - 2; Left := (Sender as TStringGrid).CellRect(aCol, aRow).Right - Width; Top := (Sender as TStringGrid).CellRect(aCol, aRow).Top; end; Editor := btnDel; end else Editor := nil; end; end; finally if Assigned(Editor) then begin Editor.Tag := aRow; Editor.Hint := IntToStr(aCol); if not stgColumns.EditorMode then FCellValue := stgColumns.Cells[aCol, aRow]; end; FUpdating := False; end; end; { TfrmOptionsCustomColumns.stgColumnsKeyDown } procedure TfrmOptionsCustomColumns.stgColumnsKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin case Key of VK_DOWN: if (stgColumns.Row = stgColumns.RowCount - 1) then begin AddNewField; end; VK_ESCAPE: if (stgColumns.EditorMode) then begin stgColumns.Cells[stgColumns.Col, stgColumns.Row] := FCellValue; stgColumns.EditorMode := False; Key := 0; end; end; end; { TfrmOptionsCustomColumns.stgColumnsMouseDown } procedure TfrmOptionsCustomColumns.stgColumnsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); var Col: integer = 0; Row: integer = 0; begin if Y < stgColumns.GridHeight then begin // Clicked on a cell, allow editing. stgColumns.Options := stgColumns.Options + [goEditing]; // Select clicked column in customize colors panel. stgColumns.MouseToCell(X, Y, Col, Row); LoadCustColumn(Row - stgColumns.FixedRows); end else begin // Clicked not on a cell, disable editing. stgColumns.Options := stgColumns.Options - [goEditing]; if btnAdd.Visible then btnAdd.Hide; end; end; { TfrmOptionsCustomColumns.stgColumnsMouseMove } procedure TfrmOptionsCustomColumns.stgColumnsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer); var iCol: integer; StringGrid: THackStringGrid absolute Sender; begin if (StringGrid.fGridState = gsColSizing) then begin if StringGrid.EditorMode then with StringGrid.Editor do begin iCol := StrToInt(Hint); Width := StringGrid.ColWidths[iCol]; Left := StringGrid.CellRect(iCol, StringGrid.Row).Left; end; if btnAdd.Visible then btnAdd.Left := StringGrid.CellRect(4, StringGrid.Row).Right - btnAdd.Width; end; end; { TfrmOptionsCustomColumns.CreateEditingControls } procedure TfrmOptionsCustomColumns.CreateEditingControls; begin // Editing controls are created with no parent-control. // TCustomGrid handles their visibility when they are assigned to Editor property. btnDel := TBitBtn.Create(Self); with btnDel do begin // Glyph.Assign(btnCancel.Glyph); Caption := rsConfColDelete; OnClick := @BitBtnDeleteFieldClick; end; cbbAlign := TComboBox.Create(Self); with cbbAlign do begin Style := csDropDownList; AddItem('<-', nil); AddItem('->', nil); AddItem('=', nil); OnSelect := @ComboBoxXSelect; OnKeyDown := @EditorKeyDown; end; edtField := TEdit.Create(Self); with edtField do begin OnExit := @EditExit; OnKeyDown := @EditorKeyDown; end; updMove := TUpDown.Create(Self); with updMove do begin OnChanging := @UpDownXChanging; OnClick := @UpDownXClick; end; updWidth := TSpinEdit.Create(Self); with updWidth do begin MinValue := 0; MaxValue := 1000; OnKeyDown := @EditorKeyDown; OnChange := @SpinEditChange; OnExit := @SpinEditExit; end; // Add button displayed in 'Field contents'. btnAdd := TButton.Create(Self); with btnAdd do begin Visible := False; Parent := stgColumns; // set Parent, because this control is shown manually in stgColumns Caption := '+'; OnClick := @btnAddClick; end; end; { TfrmOptionsCustomColumns.EditorKeyDown } procedure TfrmOptionsCustomColumns.EditorKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin case Key of VK_RETURN: begin EditorSaveResult(Sender); stgColumns.EditorMode := False; Key := 0; end; VK_ESCAPE: begin stgColumns.EditorMode := False; stgColumns.Cells[stgColumns.Col, stgColumns.Row] := FCellValue; UpdateColumnClass; Key := 0; end; end; end; { TfrmOptionsCustomColumns.AddNewField } procedure TfrmOptionsCustomColumns.AddNewField; var Index: Integer; AItem: TPanelColumn; begin Index:= stgColumns.RowCount; AItem:= TPanelColumn.CreateNew; stgColumns.RowCount := Index + 1; stgColumns.Cells[1, Index] := EmptyStr; stgColumns.Cells[2, Index] := '50'; stgColumns.Cells[3, Index] := '<-'; stgColumns.Cells[4, Index] := ''; stgColumns.Objects[5, Index] := AItem; stgColumns.Objects[6, Index] := TColPrm.Create; ColumnClass.Add(AItem); UpdateColumnClass; end; { TfrmOptionsCustomColumns.miAddColumnClick } procedure TfrmOptionsCustomColumns.miAddColumnClick(Sender: TObject); begin AddNewField; end; { TfrmOptionsCustomColumns.SpinEditExit } procedure TfrmOptionsCustomColumns.SpinEditExit(Sender: TObject); begin EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.SpinEditChange } procedure TfrmOptionsCustomColumns.SpinEditChange(Sender: TObject); begin EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.EditExit } procedure TfrmOptionsCustomColumns.EditExit(Sender: TObject); begin EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.BitBtnDeleteFieldClick } procedure TfrmOptionsCustomColumns.BitBtnDeleteFieldClick(Sender: TObject); var RowNr: integer; begin RowNr := (Sender as TBitBtn).Tag; // Free TColPrm object assigned to the row. if Assigned(stgColumns.Objects[6, RowNr]) then begin (stgColumns.Objects[6, RowNr] as TColPrm).Free; stgColumns.Objects[6, RowNr] := nil; end; ColumnClass.Delete(RowNr - 1); stgColumns.DeleteColRow(False, RowNr); EditorSaveResult(Sender); if RowNr = stgColumns.RowCount then // The last row was deleted, load previous column. LoadCustColumn(RowNr - stgColumns.FixedRows - 1) else // Load next column (RowNr will point to it after deleting). LoadCustColumn(RowNr - stgColumns.FixedRows); end; { TfrmOptionsCustomColumns.btnAddAddClick } procedure TfrmOptionsCustomColumns.btnAddClick(Sender: TObject); var Point: TPoint; begin // Fill column fields menu FillContentFieldMenu(pmFields.Items, @MenuFieldsClick, cmbFileSystem.Text); // Show popup menu Point.x := (Sender as TButton).Left - 25; Point.y := (Sender as TButton).Top + (Sender as TButton).Height + 40; Point := ClientToScreen(Point); pmFields.PopUp(Point.X, Point.Y); end; { TfrmOptionsCustomColumns.ComboBoxXSelect } procedure TfrmOptionsCustomColumns.ComboBoxXSelect(Sender: TObject); begin EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.UpDownXClick } procedure TfrmOptionsCustomColumns.UpDownXClick(Sender: TObject; Button: TUDBtnType); begin ColumnClass.Exchange(updMove.Tag - 1, abs(updMove.Position) - 1); stgColumns.ExchangeColRow(False, updMove.Tag, abs(updMove.Position)); with updMove do begin Left := stgColumns.CellRect(5, abs(updMove.Position)).Right - Width; Top := stgColumns.CellRect(5, abs(updMove.Position)).Top; end; EditorSaveResult(Sender); LoadCustColumn(abs(updMove.Position) - 1); end; { TfrmOptionsCustomColumns.UpDownXChanging } procedure TfrmOptionsCustomColumns.UpDownXChanging(Sender: TObject; var AllowChange: boolean); begin updMove.tag := abs(updMove.Position); EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.stgSetSelectionAsHintToUser } procedure TfrmOptionsCustomColumns.stgSetSelectionAsHintToUser; var CellToSelect: TGridRect; begin CellToSelect.Left := 1; // Column for the name. CellToSelect.Right := 1; CellToSelect.Top := IndexRaw + 1; // Actual column of the view. This will give a visual hint to current column edited. CellToSelect.Bottom := IndexRaw + 1; stgColumns.Options := stgColumns.Options + [goRangeSelect, goSelectionActive]; // So we can change current grid selection. stgColumns.Selection := CellToSelect; stgColumns.Options := stgColumns.Options - [goRangeSelect, goSelectionActive]; // To place it back like original author wanted. stgColumns.SetFocus; end; { TfrmOptionsCustomColumns.stgColumnsEditingDone } procedure TfrmOptionsCustomColumns.stgColumnsEditingDone(Sender: TObject); begin EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.MenuFieldsClick } procedure TfrmOptionsCustomColumns.MenuFieldsClick(Sender: TObject); var MenuItem: TMenuItem absolute Sender; procedure UpdateCell(const AText: String); begin if Length(stgColumns.Cells[4, btnAdd.Tag]) = 0 then stgColumns.Cells[4, btnAdd.Tag] := AText else begin if StrEnds(stgColumns.Cells[4, btnAdd.Tag], ' ') then stgColumns.Cells[4, btnAdd.Tag] := stgColumns.Cells[4, btnAdd.Tag] + AText else stgColumns.Cells[4, btnAdd.Tag] := stgColumns.Cells[4, btnAdd.Tag] + ' ' + AText; end; end; begin if Length(stgColumns.Cells[1, btnAdd.Tag]) = 0 then begin case MenuItem.Tag of 0: stgColumns.Cells[1, btnAdd.Tag] := Copy(MenuItem.Caption, 1, Pos('(', MenuItem.Caption) - 3); 3: stgColumns.Cells[1, btnAdd.Tag] := Copy(MenuItem.Parent.Caption, 1, Pos('(', MenuItem.Parent.Caption) - 3); else stgColumns.Cells[1, btnAdd.Tag] := MenuItem.Caption; end; end; case MenuItem.Tag of 0: UpdateCell('[DC().' + MenuItem.Hint + '{}]'); 1: UpdateCell('[Plugin(' + MenuItem.Parent.Caption + ').' + MenuItem.Hint + '{}]'); 2: UpdateCell('[Plugin(' + MenuItem.Parent.Parent.Caption + ').' + MenuItem.Parent.Hint + '{' + MenuItem.Hint + '}]'); 3: UpdateCell('[DC().' + MenuItem.Parent.Hint + '{' + MenuItem.Hint + '}]'); end; EditorSaveResult(Sender); end; { TfrmOptionsCustomColumns.EditorSaveResult } procedure TfrmOptionsCustomColumns.EditorSaveResult(Sender: TObject); begin if not FUpdating then begin if Sender is TSpinEdit then stgColumns.Cells[2, (Sender as TSpinEdit).Tag] := IntToStr(updWidth.Value); if Sender is TComboBox then stgColumns.Cells[3, (Sender as TComboBox).Tag] := (Sender as TComboBox).Text; if Sender is TEdit then stgColumns.Cells[4, (Sender as TEdit).Tag] := (Sender as TEdit).Text; UpdateColumnClass; end; end; { TfrmOptionsCustomColumns.CustomSomethingChanged } procedure TfrmOptionsCustomColumns.CustomSomethingChanged(Sender: TObject); begin if cbApplyChangeForAllColumns.Checked then btnAllForeColorClick(Sender) else EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.LoadCustColumn } procedure TfrmOptionsCustomColumns.LoadCustColumn(const Index: integer); var InnerUpdateStateToBeRestored: boolean; iRow: integer; begin if (Index >= stgColumns.RowCount - 1) or (Index < 0) then exit; IndexRaw := Index; ColPrm := TColPrm(stgColumns.Objects[6, IndexRaw + 1]); InnerUpdateStateToBeRestored := FUpdating; FUpdating := True; for iRow := 1 to pred(stgColumns.RowCount) do stgColumns.Cells[0, iRow] := strutils.ifthen(iRow = (IndexRaw + 1), '--->', EmptyStr); lblCurrentColumn.Caption := ColumnClass.GetColumnTitle(IndexRaw); edtFont.Text := ColumnClass.GetColumnFontName(IndexRaw); sneFontSize.Value := ColumnClass.GetColumnFontSize(IndexRaw); SetColorInColorBox(cbForeColor, ColumnClass.GetColumnTextColor(IndexRaw)); SetColorInColorBox(cbBackColor, ColumnClass.GetColumnBackground(IndexRaw)); SetColorInColorBox(cbBackColor2, ColumnClass.GetColumnBackground2(IndexRaw)); SetColorInColorBox(cbMarkColor, ColumnClass.GetColumnMarkColor(IndexRaw)); SetColorInColorBox(cbCursorColor, ColumnClass.GetColumnCursorColor(IndexRaw)); SetColorInColorBox(cbCursorText, ColumnClass.GetColumnCursorText(IndexRaw)); SetColorInColorBox(cbInactiveCursorColor, ColumnClass.GetColumnInactiveCursorColor(IndexRaw)); SetColorInColorBox(cbInactiveMarkColor, ColumnClass.GetColumnInactiveMarkColor(IndexRaw)); cbAllowOverColor.Checked := ColumnClass.GetColumnOvercolor(IndexRaw); cbUseInvertedSelection.Checked := ColumnClass.GetColumnUseInvertedSelection(IndexRaw); cbUseInactiveSelColor.Checked := ColumnClass.GetColumnUseInactiveSelColor(IndexRaw); FUpdating := InnerUpdateStateToBeRestored; end; { TfrmOptionsCustomColumns.chkUseCustomViewChange } procedure TfrmOptionsCustomColumns.chkUseCustomViewChange(Sender: TObject); begin pnlCommon.Visible:= chkUseCustomView.Checked; pnlCustomColumnsViewSettings.Visible := chkUseCustomView.Checked; btnGotoSetDefault.Visible := not chkUseCustomView.Checked; EditorSaveResult(nil); if chkUsecustomView.Checked then begin LoadCustColumn(0); cbCursorBorder.Checked:= gUseCursorBorder; cbCursorBorderChange(cbCursorBorder); SetColorInColorBox(cbCursorBorderColor, gColors.FilePanel^.CursorBorderColor); cbUseFrameCursor.Checked:= gUseFrameCursor; cbUseFrameCursorChange(cbUseFrameCursor); end; end; { TfrmOptionsCustomColumns.cbCursorBorderChange } procedure TfrmOptionsCustomColumns.cbCursorBorderChange(Sender: TObject); begin cbCursorBorderColor.Enabled := cbCursorBorder.Checked and cbCursorBorder.Enabled; btnCursorBorderColor.Enabled := cbCursorBorderColor.Enabled; btnResetCursorBorder.Enabled:= cbCursorBorderColor.Enabled; if cbCursorBorder.Checked and cbCursorBorder.Enabled then cbCursorBorderColor.Font.Color := clDefault else cbCursorBorderColor.Font.Color := clInactiveCaption; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbCursorBorderColorChange } procedure TfrmOptionsCustomColumns.cbCursorBorderColorChange(Sender: TObject); begin if Assigned(ColPrm) then begin EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnCursorBorderColorClick } procedure TfrmOptionsCustomColumns.btnCursorBorderColorClick(Sender: TObject); begin dlgcolor.Color := cbCursorBorderColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbCursorBorderColor, dlgcolor.Color); EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetCursorBorderClick } procedure TfrmOptionsCustomColumns.btnResetCursorBorderClick(Sender: TObject); begin cbCursorBorder.Checked := gUseCursorBorder; SetColorInColorBox(cbCursorBorderColor, gColors.FilePanel^.CursorBorderColor); EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbUseFrameCursorChange } procedure TfrmOptionsCustomColumns.cbUseFrameCursorChange(Sender: TObject); begin btnResetFrameCursor.Enabled := cbUseFrameCursor.Checked; cbCursorBorder.Enabled := not cbUseFrameCursor.Checked; lblCursorText.Enabled := not cbUseFrameCursor.Checked; cbCursorText.Enabled := not cbUseFrameCursor.Checked; btnCursorText.Enabled := not cbUseFrameCursor.Checked; btnResetCursorText.Enabled := not cbUseFrameCursor.Checked; btnAllCursorText.Enabled := not cbUseFrameCursor.Checked and not cbApplyChangeForAllColumns.Checked; btnResetCursorBorder.Enabled := not cbUseFrameCursor.Checked; if not cbUseFrameCursor.Checked then cbCursorText.Font.Color := clDefault else cbCursorText.Font.Color := clInactiveCaption; cbCursorBorderChange(cbCursorBorder); EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.btnResetFrameCursorClick } procedure TfrmOptionsCustomColumns.btnResetFrameCursorClick(Sender: TObject); begin cbUseFrameCursor.Checked := gUseFrameCursor; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.btnPrevClick } procedure TfrmOptionsCustomColumns.btnPrevClick(Sender: TObject); begin if IndexRaw > 0 then LoadCustColumn(IndexRaw - 1) else LoadCustColumn(stgColumns.RowCount - 2); stgSetSelectionAsHintToUser; end; { TfrmOptionsCustomColumns.btnNextClick } procedure TfrmOptionsCustomColumns.btnNextClick(Sender: TObject); begin if IndexRaw < (stgColumns.RowCount - 2) then LoadCustColumn(IndexRaw + 1) else LoadCustColumn(0); stgSetSelectionAsHintToUser; end; { TfrmOptionsCustomColumns.cbApplyChangeForAllColumnsChange } procedure TfrmOptionsCustomColumns.cbApplyChangeForAllColumnsChange(Sender: TObject); begin if cbApplyChangeForAllColumns.Checked then begin btnAllBackColor.Enabled := False; btnAllBackColor2.Enabled := False; btnAllCursorColor.Enabled := False; btnAllCursorText.Enabled := False; btnAllFont.Enabled := False; btnAllInactiveCursorColor.Enabled := False; btnAllInactiveMarkColor.Enabled := False; btnAllMarkColor.Enabled := False; btnAllForeColor.Enabled := False; btnAllAllowOverColor.Enabled := False; btnAllUseInvertedSelection.Enabled := False; btnAllUseInactiveSelColor.Enabled := False; end else begin btnAllBackColor.Enabled := True; btnAllBackColor2.Enabled := True; btnAllCursorColor.Enabled := True; btnAllCursorText.Enabled := True; btnAllFont.Enabled := True; btnAllMarkColor.Enabled := True; btnAllForeColor.Enabled := True; btnAllAllowOverColor.Enabled := True; btnAllUseInvertedSelection.Enabled := True; btnAllUseInactiveSelColor.Enabled := True; btnAllInactiveCursorColor.Enabled := cbUseInactiveSelColor.Checked; btnAllInactiveMarkColor.Enabled := cbUseInactiveSelColor.Checked; end; end; { TfrmOptionsCustomColumns.btnFontClick } procedure TfrmOptionsCustomColumns.btnFontClick(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin with TColPrm(stgColumns.Objects[6, IndexRaw + 1]) do begin dlgfont.Font.Name := FontName; dlgfont.Font.Size := FontSize; dlgfont.Font.Style := FontStyle; if dlgfont.Execute then begin edtFont.Text := dlgfont.Font.Name; sneFontSize.Value := dlgfont.Font.Size; FontName := dlgfont.Font.Name; FontSize := dlgfont.Font.Size; FontStyle := dlgfont.Font.Style; CustomSomethingChanged(Sender); end; end; end; end; { TfrmOptionsCustomColumns.sneFontSizeChange } procedure TfrmOptionsCustomColumns.sneFontSizeChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontSize := sneFontSize.Value; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnResetFontClick } procedure TfrmOptionsCustomColumns.btnResetFontClick(Sender: TObject); begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontName := gFonts[dcfMain].Name; TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontSize := gFonts[dcfMain].Size; TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontStyle := gFonts[dcfMain].Style; edtFont.Text := gFonts[dcfMain].Name; sneFontSize.Value := gFonts[dcfMain].Size; CustomSomethingChanged(Sender); end; { TfrmOptionsCustomColumns.btnAllForeColorClick } procedure TfrmOptionsCustomColumns.btnAllForeColorClick(Sender: TObject); var i: integer; begin for i := 1 to pred(stgColumns.RowCount) do case TComponent(Sender).tag of 0: begin TColPrm(stgColumns.Objects[6, i]).FontName := TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontName; TColPrm(stgColumns.Objects[6, i]).FontSize := TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontSize; TColPrm(stgColumns.Objects[6, i]).FontStyle := TColPrm(stgColumns.Objects[6, IndexRaw + 1]).FontStyle; end; 1: TColPrm(stgColumns.Objects[6, i]).TextColor := cbForeColor.Selected; 2: TColPrm(stgColumns.Objects[6, i]).Background := cbBackColor.Selected; 3: TColPrm(stgColumns.Objects[6, i]).Background2 := cbBackColor2.Selected; 4: TColPrm(stgColumns.Objects[6, i]).MarkColor := cbMarkColor.Selected; 5: TColPrm(stgColumns.Objects[6, i]).CursorColor := cbCursorColor.Selected; 6: TColPrm(stgColumns.Objects[6, i]).CursorText := cbCursorText.Selected; 7: TColPrm(stgColumns.Objects[6, i]).InactiveCursorColor := cbInactiveCursorColor.Selected; 8: TColPrm(stgColumns.Objects[6, i]).InactiveMarkColor := cbInactiveMarkColor.Selected; 9: TColPrm(stgColumns.Objects[6, i]).UseInvertedSelection := cbUseInvertedSelection.Checked; 10: TColPrm(stgColumns.Objects[6, i]).UseInactiveSelColor := cbUseInactiveSelColor.Checked; 11: TColPrm(stgColumns.Objects[6, i]).Overcolor := cbAllowOverColor.Checked; end; UpdateColumnClass; end; { TfrmOptionsCustomColumns.cbForeColorChange } procedure TfrmOptionsCustomColumns.cbForeColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.TextColor := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnForeColorClick } procedure TfrmOptionsCustomColumns.btnForeColorClick(Sender: TObject); begin dlgcolor.Color := cbForeColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbForeColor, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).TextColor := cbForeColor.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetForeColorClick } procedure TfrmOptionsCustomColumns.btnResetForeColorClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).TextColor := ForeColor; SetColorInColorBox(cbForeColor, ForeColor); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbBackColorChange } procedure TfrmOptionsCustomColumns.cbBackColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.Background := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnBackColorClick } procedure TfrmOptionsCustomColumns.btnBackColorClick(Sender: TObject); begin dlgcolor.Color := cbBackColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbBackColor, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).Background := cbBackColor.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetBackColorClick } procedure TfrmOptionsCustomColumns.btnResetBackColorClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).Background := BackColor; SetColorInColorBox(cbBackColor, BackColor); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbBackColor2Change } procedure TfrmOptionsCustomColumns.cbBackColor2Change(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.Background2 := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnBackColor2Click } procedure TfrmOptionsCustomColumns.btnBackColor2Click(Sender: TObject); begin dlgcolor.Color := cbBackColor2.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbBackColor2, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).Background2 := cbBackColor2.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetBackColor2Click } procedure TfrmOptionsCustomColumns.btnResetBackColor2Click(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).Background2 := BackColor2; SetColorInColorBox(cbBackColor2, BackColor2); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbMarkColorChange } procedure TfrmOptionsCustomColumns.cbMarkColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.MarkColor := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnMarkColorClick } procedure TfrmOptionsCustomColumns.btnMarkColorClick(Sender: TObject); begin dlgcolor.Color := cbMarkColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbMarkColor, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).MarkColor := cbMarkColor.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetMarkColorClick } procedure TfrmOptionsCustomColumns.btnResetMarkColorClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).MarkColor := MarkColor; SetColorInColorBox(cbMarkColor, MarkColor); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbCursorColorChange } procedure TfrmOptionsCustomColumns.cbCursorColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.CursorColor := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnCursorColorClick } procedure TfrmOptionsCustomColumns.btnCursorColorClick(Sender: TObject); begin dlgcolor.Color := cbCursorColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbCursorColor, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).CursorColor := cbCursorColor.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetCursorColorClick } procedure TfrmOptionsCustomColumns.btnResetCursorColorClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).CursorColor := CursorColor; SetColorInColorBox(cbCursorColor, CursorColor); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbCursorTextChange } procedure TfrmOptionsCustomColumns.cbCursorTextChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.CursorText := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnCursorTextClick } procedure TfrmOptionsCustomColumns.btnCursorTextClick(Sender: TObject); begin dlgcolor.Color := cbCursorText.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbCursorText, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).CursorText := cbCursorText.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetCursorTextClick } procedure TfrmOptionsCustomColumns.btnResetCursorTextClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).CursorText := CursorText; SetColorInColorBox(cbCursorText, CursorText); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbInactiveCursorColorChange } procedure TfrmOptionsCustomColumns.cbInactiveCursorColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.InactiveCursorColor := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnInactiveCursorColorClick } procedure TfrmOptionsCustomColumns.btnInactiveCursorColorClick(Sender: TObject); begin dlgcolor.Color := cbInactiveCursorColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbInactiveCursorColor, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).InactiveCursorColor := cbInactiveCursorColor.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetInactiveCursorColorClick } procedure TfrmOptionsCustomColumns.btnResetInactiveCursorColorClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).InactiveCursorColor := InactiveCursorColor; SetColorInColorBox(cbInactiveCursorColor, InactiveCursorColor); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbInactiveMarkColorChange } procedure TfrmOptionsCustomColumns.cbInactiveMarkColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin ColPrm.InactiveMarkColor := (Sender as TColorBox).Selected; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnInactiveMarkColorClick } procedure TfrmOptionsCustomColumns.btnInactiveMarkColorClick(Sender: TObject); begin dlgcolor.Color := cbInactiveMarkColor.Selected; if dlgcolor.Execute then begin SetColorInColorBox(cbInactiveMarkColor, dlgcolor.Color); TColPrm(stgColumns.Objects[6, IndexRaw + 1]).InactiveMarkColor := cbInactiveMarkColor.Selected; EditorSaveResult(nil); end; end; { TfrmOptionsCustomColumns.btnResetInactiveMarkColorClick } procedure TfrmOptionsCustomColumns.btnResetInactiveMarkColorClick(Sender: TObject); begin with gColors.FilePanel^ do begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).InactiveMarkColor := InactiveMarkColor; SetColorInColorBox(cbInactiveMarkColor, InactiveMarkColor); end; EditorSaveResult(nil); end; { TfrmOptionsCustomColumns.cbUseInvertedSelectionChange } procedure TfrmOptionsCustomColumns.cbUseInvertedSelectionChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).UseInvertedSelection := cbUseInvertedSelection.Checked; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnResetUseInvertedSelectionClick } procedure TfrmOptionsCustomColumns.btnResetUseInvertedSelectionClick(Sender: TObject); begin cbUseInvertedSelection.Checked := gUseInvertedSelection; cbUseInvertedSelectionChange(cbUseInvertedSelection); end; { TfrmOptionsCustomColumns.cbUseInactiveSelColorChange } procedure TfrmOptionsCustomColumns.cbUseInactiveSelColorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin lblInactiveCursorColor.Enabled := cbUseInactiveSelColor.Checked; cbInactiveCursorColor.Enabled := cbUseInactiveSelColor.Checked; btnInactiveCursorColor.Enabled := cbUseInactiveSelColor.Checked; btnResetInactiveCursorColor.Enabled := cbUseInactiveSelColor.Checked; btnAllInactiveCursorColor.Enabled := cbUseInactiveSelColor.Checked; lblInactiveMarkColor.Enabled := cbUseInactiveSelColor.Checked; cbInactiveMarkColor.Enabled := cbUseInactiveSelColor.Checked; btnInactiveMarkColor.Enabled := cbUseInactiveSelColor.Checked; btnResetInactiveMarkColor.Enabled := cbUseInactiveSelColor.Checked; btnAllInactiveMarkColor.Enabled := cbUseInactiveSelColor.Checked; TColPrm(stgColumns.Objects[6, IndexRaw + 1]).UseInactiveSelColor := cbUseInactiveSelColor.Checked; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnResetUseInactiveSelColorClick } procedure TfrmOptionsCustomColumns.btnResetUseInactiveSelColorClick(Sender: TObject); begin cbUseInactiveSelColor.Checked := gUSeInactiveSelColor; cbUseInactiveSelColorChange(cbUseInactiveSelColor); end; { TfrmOptionsCustomColumns.cbAllowOvercolorChange } procedure TfrmOptionsCustomColumns.cbAllowOvercolorChange(Sender: TObject); begin if Assigned(ColPrm) and (not FUpdating) then begin TColPrm(stgColumns.Objects[6, IndexRaw + 1]).Overcolor := cbAllowOverColor.Checked; CustomSomethingChanged(Sender); end; end; { TfrmOptionsCustomColumns.btnResetAllowOverColorClick } procedure TfrmOptionsCustomColumns.btnResetAllowOverColorClick(Sender: TObject); begin cbAllowOverColor.Checked := gAllowOverColor; cbAllowOvercolorChange(cbAllowOverColor); end; { TfrmOptionsCustomColumns.pnlLeftEnter } procedure TfrmOptionsCustomColumns.pnlLeftEnter(Sender: TObject); begin PreviewRightPanel.JustForColorPreviewSetActiveState(False); PreviewLeftPanel.JustForColorPreviewSetActiveState(True); end; { TfrmOptionsCustomColumns.pnlRightEnter } procedure TfrmOptionsCustomColumns.pnlRightEnter(Sender: TObject); begin PreviewLeftPanel.JustForColorPreviewSetActiveState(False); PreviewRightPanel.JustForColorPreviewSetActiveState(True); end; { TfrmOptionsCustomColumns.OnColumnResized } procedure TfrmOptionsCustomColumns.OnColumnResized(Sender: TObject; ColumnIndex: integer; ColumnNewsize: integer); begin if ColumnIndex < pred(stgColumns.RowCount) then begin stgColumns.Cells[2, 1 + ColumnIndex] := IntToStr(ColumnNewSize); EditorSaveResult(Sender); //To like everywhere here, but it's not absolutely necessary... end; end; end. �����������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdirectoryhotlist.lfm��������������������������������������������0000644�0001750�0000144�00000112342�14743153644�022552� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsDirectoryHotlist: TfrmOptionsDirectoryHotlist Height = 658 Width = 730 ClientHeight = 658 ClientWidth = 730 HelpKeyword = '/directoryhotlist.html' Constraints.MinHeight = 520 Constraints.MinWidth = 600 ParentShowHint = False ShowHint = True DesignLeft = 185 DesignTop = 243 object gbDirectoryHotlist: TGroupBox[0] Left = 6 Height = 646 Top = 6 Width = 718 Align = alClient BorderSpacing.Around = 6 Caption = 'Directory Hotlist (reorder by drag && drop)' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 626 ClientWidth = 714 Constraints.MinHeight = 460 Constraints.MinWidth = 548 TabOrder = 0 object pnlClient: TPanel AnchorSideLeft.Control = gbDirectoryHotlist AnchorSideTop.Control = gbDirectoryHotlist AnchorSideRight.Control = gbDirectoryHotlist AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlBottom Left = 6 Height = 524 Top = 6 Width = 702 Anchors = [akTop, akLeft, akRight, akBottom] BevelOuter = bvNone ClientHeight = 524 ClientWidth = 702 TabOrder = 0 object tvDirectoryHotlist: TTreeView AnchorSideLeft.Control = pnlClient AnchorSideTop.Control = pnlClient AnchorSideRight.Control = gbHotlistOtherOptions AnchorSideBottom.Control = pnlClient AnchorSideBottom.Side = asrBottom Left = 0 Height = 524 Top = 0 Width = 382 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Right = 6 BackgroundColor = clForm DragMode = dmAutomatic HotTrack = True MultiSelect = True MultiSelectStyle = [msControlSelect, msShiftSelect, msVisibleOnly, msSiblingOnly] ParentColor = True ReadOnly = True ScrollBars = ssAutoBoth SelectionColor = clBtnShadow TabOrder = 0 ToolTips = False OnDragDrop = tvDirectoryHotlistDragDrop OnDragOver = tvDirectoryHotlistDragOver OnEnter = tvDirectoryHotlistEnter OnExit = tvDirectoryHotlistExit OnSelectionChanged = tvDirectoryHotlistSelectionChanged Options = [tvoAllowMultiselect, tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot] end object pnlButtons: TPanel AnchorSideLeft.Control = gbHotlistOtherOptions AnchorSideTop.Control = pnlClient AnchorSideRight.Control = pnlClient AnchorSideRight.Side = asrBottom Left = 388 Height = 161 Top = 0 Width = 314 Anchors = [akTop, akLeft, akRight] BevelOuter = bvNone ClientHeight = 161 ClientWidth = 314 TabOrder = 1 OnResize = pnlButtonsResize object btnInsert: TBitBtn Tag = 1 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlButtons AnchorSideRight.Control = btnExport Left = 8 Height = 25 Top = 0 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Right = 6 Caption = '&Insert...' OnClick = btnActionClick TabOrder = 0 end object btnDelete: TBitBtn Tag = 3 AnchorSideTop.Control = btnAdd AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnBackup Left = 8 Height = 25 Top = 62 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = 'De&lete...' OnClick = btnActionClick TabOrder = 2 end object btnExport: TBitBtn Tag = 4 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlButtons AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 164 Height = 25 Top = 0 Width = 150 Anchors = [akTop, akRight] Caption = 'E&xport...' OnClick = btnActionClick TabOrder = 5 end object btnImport: TBitBtn Tag = 5 AnchorSideTop.Control = btnExport AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 164 Height = 25 Top = 31 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Top = 6 Caption = 'Impo&rt...' OnClick = btnActionClick TabOrder = 6 end object btnBackup: TBitBtn Tag = 6 AnchorSideTop.Control = btnImport AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 164 Height = 25 Top = 62 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Top = 6 Caption = 'Bac&kup...' OnClick = btnActionClick TabOrder = 7 end object btnMiscellaneous: TBitBtn Tag = 7 AnchorSideTop.Control = btnSort AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnBackup Left = 8 Height = 25 Top = 124 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = '&Miscellaneous...' OnClick = btnActionClick TabOrder = 4 end object btnAdd: TBitBtn Tag = 2 AnchorSideTop.Control = btnInsert AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnImport Left = 8 Height = 25 Top = 31 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = 'A&dd...' OnClick = btnActionClick TabOrder = 1 end object btnSort: TBitBtn Tag = 8 AnchorSideTop.Control = btnDelete AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnBackup Left = 8 Height = 25 Top = 93 Width = 150 Anchors = [akTop, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 6 Caption = '&Sort...' OnClick = btnActionClick TabOrder = 3 end end object rgWhereToAdd: TRadioGroup AnchorSideLeft.Control = gbHotlistOtherOptions AnchorSideTop.Control = pnlButtons AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlClient AnchorSideRight.Side = asrBottom Left = 388 Height = 89 Top = 164 Width = 314 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Top = 3 Caption = 'Addition from main panel' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 69 ClientWidth = 310 Items.Strings = ( 'Add at beginning' 'Add at the end' 'Smart add' ) TabOrder = 2 end object gbHotlistOtherOptions: TGroupBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rgWhereToAdd AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlClient AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 388 Height = 114 Top = 253 Width = 314 Anchors = [akTop, akRight] AutoSize = True Caption = 'Other options' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 94 ClientWidth = 310 Constraints.MinWidth = 314 TabOrder = 3 object cbAddTarget: TCheckBox Left = 6 Height = 19 Top = 6 Width = 225 Caption = '&When adding directory, add also target' TabOrder = 0 end object cbFullExpandTree: TCheckBox AnchorSideLeft.Control = cbAddTarget AnchorSideTop.Control = cbAddTarget AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 27 Width = 121 BorderSpacing.Top = 2 Caption = 'Alwa&ys expand tree' OnChange = cbFullExpandTreeChange TabOrder = 1 end object cbShowPathInPopup: TCheckBox AnchorSideLeft.Control = cbAddTarget AnchorSideTop.Control = cbFullExpandTree AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 48 Width = 161 BorderSpacing.Top = 2 Caption = 'In pop&up, show [path also]' TabOrder = 2 end object cbShowOnlyValidEnv: TCheckBox AnchorSideLeft.Control = cbAddTarget AnchorSideTop.Control = cbShowPathInPopup AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 69 Width = 223 BorderSpacing.Top = 2 Caption = 'Show only &valid environment variables' TabOrder = 3 end end end object pnlBottom: TPanel AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gbDirectoryHotlist AnchorSideBottom.Side = asrBottom Left = 6 Height = 90 Top = 530 Width = 702 Anchors = [akLeft, akRight, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 90 ClientWidth = 702 TabOrder = 1 object lbleditHotDirName: TLabeledEdit Tag = 1 AnchorSideTop.Control = pnlBottom Left = 104 Height = 23 Top = 9 Width = 598 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 9 BorderSpacing.Bottom = 6 EditLabel.AnchorSideTop.Control = lbleditHotDirName EditLabel.AnchorSideTop.Side = asrCenter EditLabel.AnchorSideRight.Control = lbleditHotDirName EditLabel.AnchorSideBottom.Side = asrBottom EditLabel.Left = 66 EditLabel.Height = 15 EditLabel.Top = 13 EditLabel.Width = 35 EditLabel.Caption = 'Name:' EditLabel.ParentColor = False EditLabel.ParentFont = False LabelPosition = lpLeft ParentFont = False TabOrder = 0 OnChange = lbleditHotDirNameChange end object lbleditHotDirPath: TLabeledEdit Tag = 2 AnchorSideTop.Control = cbSortHotDirPath AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnRelativePath Left = 104 Height = 23 Top = 38 Width = 449 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 2 EditLabel.Tag = 2 EditLabel.AnchorSideTop.Control = lbleditHotDirPath EditLabel.AnchorSideTop.Side = asrCenter EditLabel.AnchorSideRight.Control = lbleditHotDirPath EditLabel.AnchorSideBottom.Side = asrBottom EditLabel.Left = 74 EditLabel.Height = 15 EditLabel.Top = 42 EditLabel.Width = 27 EditLabel.Caption = 'Path:' EditLabel.ParentColor = False EditLabel.ParentFont = False EditLabel.OnClick = anyRelativeAbsolutePathClick LabelPosition = lpLeft ParentFont = False TabOrder = 1 OnChange = lbleditHotDirNameChange end object btnRelativePath: TSpeedButton Tag = 2 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbleditHotDirPath AnchorSideRight.Control = cbSortHotDirPath AnchorSideBottom.Control = lbleditHotDirPath AnchorSideBottom.Side = asrBottom Left = 555 Height = 23 Hint = 'Some functions to select appropriate path' Top = 38 Width = 23 Anchors = [akTop, akRight, akBottom] BorderSpacing.Right = 2 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = anyRelativeAbsolutePathClick ParentFont = False end object cbSortHotDirPath: TComboBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbleditHotDirName AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 580 Height = 23 Top = 38 Width = 122 Anchors = [akTop, akRight] BorderSpacing.Bottom = 6 DropDownCount = 10 ItemHeight = 15 ItemIndex = 1 Items.Strings = ( 'none' 'Name, a-z' 'Name, z-a' 'Ext, a-z' 'Ext, z-a' 'Size 9-0' 'Size 0-9' 'Date 9-0' 'Date 0-9' ) OnChange = cbSortHotDirPathChange ParentFont = False Style = csDropDownList TabOrder = 3 Text = 'Name, a-z' end object lbleditHotDirTarget: TLabeledEdit Tag = 3 AnchorSideTop.Control = cbSortHotDirTarget AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnRelativeTarget Left = 104 Height = 23 Top = 67 Width = 449 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 BorderSpacing.Right = 2 EditLabel.Tag = 3 EditLabel.AnchorSideTop.Control = lbleditHotDirTarget EditLabel.AnchorSideTop.Side = asrCenter EditLabel.AnchorSideRight.Control = lbleditHotDirTarget EditLabel.AnchorSideBottom.Side = asrBottom EditLabel.Left = 65 EditLabel.Height = 15 EditLabel.Top = 71 EditLabel.Width = 36 EditLabel.Caption = '&Target:' EditLabel.ParentColor = False EditLabel.ParentFont = False EditLabel.OnClick = anyRelativeAbsolutePathClick LabelPosition = lpLeft ParentFont = False TabOrder = 2 OnChange = lbleditHotDirNameChange end object btnRelativeTarget: TSpeedButton Tag = 3 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbleditHotDirTarget AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbSortHotDirTarget AnchorSideBottom.Side = asrBottom Left = 555 Height = 23 Hint = 'Some functions to select appropriate target' Top = 67 Width = 23 Anchors = [akTop, akRight] BorderSpacing.Right = 2 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = anyRelativeAbsolutePathClick ParentFont = False end object cbSortHotDirTarget: TComboBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbSortHotDirPath AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 580 Height = 23 Top = 67 Width = 122 Anchors = [akTop, akRight] DropDownCount = 10 ItemHeight = 15 ItemIndex = 1 Items.Strings = ( 'none' 'Name, a-z' 'Name, z-a' 'Ext, a-z' 'Ext, z-a' 'Size 9-0' 'Size 0-9' 'Date 9-0' 'Date 0-9' ) OnChange = cbSortHotDirTargetChange ParentFont = False Style = csDropDownList TabOrder = 4 Text = 'Name, a-z' end end end object actList: TActionList[1] left = 256 top = 336 object actInsertBrowsedDir: TAction Tag = 1 Category = 'Edition' Caption = 'Insert directory I will bro&wse to' OnExecute = actInsertOrAddSomethingExecute end object actInsertTypedDir: TAction Tag = 2 Category = 'Edition' Caption = 'Insert directory I will type' OnExecute = actInsertOrAddSomethingExecute ShortCut = 120 end object actInsertActiveFrameDir: TAction Tag = 3 Category = 'Edition' Caption = 'Insert directory of the &active frame' OnExecute = actInsertOrAddSomethingExecute end object actInsertBothFrameDir: TAction Tag = 4 Category = 'Edition' Caption = 'Insert &directories of the active && inactive frames' OnExecute = actInsertOrAddSomethingExecute end object actInsertSelectionsFromFrame: TAction Tag = 9 Category = 'Edition' Caption = 'Insert current &selected or active directories of active frame' OnExecute = actInsertOrAddSomethingExecute end object actInsertCopyOfEntry: TAction Tag = 7 Category = 'Edition' Caption = 'Insert a copy of the selected entry' OnExecute = actInsertOrAddSomethingExecute ShortCut = 116 end object actInsertSeparator: TAction Tag = 5 Category = 'Edition' Caption = 'Insert a separator' OnExecute = actInsertOrAddSomethingExecute ShortCut = 121 end object actInsertSubMenu: TAction Tag = 6 Category = 'Edition' Caption = 'Insert sub menu' OnExecute = actInsertOrAddSomethingExecute ShortCut = 118 end object actAddBrowsedDir: TAction Tag = 17 Category = 'Edition' Caption = 'Add directory I will bro&wse to' OnExecute = actInsertOrAddSomethingExecute end object actAddTypedDir: TAction Tag = 18 Category = 'Edition' Caption = 'Add directory I will type' OnExecute = actInsertOrAddSomethingExecute ShortCut = 16504 end object actAddActiveFrameDir: TAction Tag = 19 Category = 'Edition' Caption = 'Add directory of the &active frame' OnExecute = actInsertOrAddSomethingExecute end object actAddBothFrameDir: TAction Tag = 20 Category = 'Edition' Caption = 'Add &directories of the active && inactive frames' OnExecute = actInsertOrAddSomethingExecute end object actAddSelectionsFromFrame: TAction Tag = 25 Category = 'Edition' Caption = 'Add current &selected or active directories of active frame' OnExecute = actInsertOrAddSomethingExecute end object actAddCopyOfEntry: TAction Tag = 23 Category = 'Edition' Caption = 'Add a copy of the selected entry' OnExecute = actInsertOrAddSomethingExecute ShortCut = 16500 end object actAddSeparator: TAction Tag = 21 Category = 'Edition' Caption = 'Add a separator' OnExecute = actInsertOrAddSomethingExecute ShortCut = 16505 end object actAddSubMenu: TAction Tag = 22 Category = 'Edition' Caption = 'Add a sub menu' OnExecute = actInsertOrAddSomethingExecute ShortCut = 16502 end object actDeleteSelectedItem: TAction Tag = 1 Category = 'Edition' Caption = 'Delete selected item' OnExecute = actDeleteSomethingExecute ShortCut = 119 end object actDeleteSubMenuKeepElem: TAction Tag = 2 Category = 'Edition' Caption = 'Delete just sub-menu but keep elements' OnExecute = actDeleteSomethingExecute ShortCut = 16503 end object actDeleteSubMenuAndElem: TAction Tag = 3 Category = 'Edition' Caption = 'Delete sub-menu and all its elements' OnExecute = actDeleteSomethingExecute ShortCut = 24695 end object actDeleteAll: TAction Category = 'Edition' Caption = 'Delete all!' OnExecute = actDeleteAllExecute ShortCut = 57463 end object actMoveToPrevious: TAction Category = 'Edition' Caption = 'Move to previous' OnExecute = actMoveToPreviousExecute ShortCut = 16422 end object actMoveToNext: TAction Category = 'Edition' Caption = 'Move to next' OnExecute = actMoveToNextExecute ShortCut = 16424 end object actPaste: TAction Category = 'Edition' Caption = 'Paste what was cut' Enabled = False OnExecute = actPasteExecute ShortCut = 24662 end object actCut: TAction Category = 'Edition' Caption = 'Cut selection of entries' OnExecute = actCutExecute ShortCut = 24664 end object actSearchAndReplaceInPath: TAction Tag = 1 Category = 'Edition' Caption = 'Search && replace in &path' OnExecute = actSearchAndReplaceExecute end object actSearchAndReplaceInTargetPath: TAction Tag = 2 Category = 'Edition' Caption = 'Search && replace in &target path' OnExecute = actSearchAndReplaceExecute end object actSearchAndReplaceInPathAndTarget: TAction Tag = 3 Category = 'Edition' Caption = 'Search && replace in both path and target' OnExecute = actSearchAndReplaceExecute ShortCut = 32886 end object actFocusTreeWindow: TAction Category = 'Navigation' Caption = 'Focus tree window' OnExecute = actFocusTreeWindowExecute ShortCut = 113 end object actGotoFirstItem: TAction Category = 'Navigation' Caption = 'Goto first item' OnExecute = actGotoFirstItemExecute ShortCut = 16420 end object actGoToPreviousItem: TAction Category = 'Navigation' Caption = 'Go to previous item' OnExecute = actGoToPreviousItemExecute ShortCut = 38 end object actGoToNextItem: TAction Category = 'Navigation' Caption = 'Go to next item' OnExecute = actGoToNextItemExecute ShortCut = 40 end object actGotoLastItem: TAction Category = 'Navigation' Caption = 'Goto last item' OnExecute = actGotoLastItemExecute ShortCut = 16419 end object actExpandItem: TAction Category = 'Navigation' Caption = 'Expand item' OnExecute = actExpandItemExecute ShortCut = 16423 end object actOpenAllBranches: TAction Category = 'Navigation' Caption = 'Open all branches' OnExecute = actOpenAllBranchesExecute end object actCollapseItem: TAction Category = 'Navigation' Caption = 'Collapse item' OnExecute = actCollapseItemExecute ShortCut = 16421 end object actCollapseAll: TAction Category = 'Navigation' Caption = 'Collapse all' OnExecute = actCollapseAllExecute end object actTweakPath: TAction Tag = 2 Category = 'Edition' Caption = 'Tweak path' OnExecute = actTweakPathExecute ShortCut = 24656 end object actTweakTargetPath: TAction Tag = 3 Category = 'Edition' Caption = 'Tweak target path' OnExecute = actTweakPathExecute ShortCut = 24660 end end object pmInsertDirectoryHotlist: TPopupMenu[2] left = 80 top = 56 object miInsertBrowsedDir: TMenuItem Action = actInsertBrowsedDir end object miInsertTypedDir: TMenuItem Action = actInsertTypedDir end object miInsertActiveFrameDir: TMenuItem Action = actInsertActiveFrameDir end object miInsertBothFrameDir: TMenuItem Action = actInsertBothFrameDir end object miInsertSelectionsFromFrame: TMenuItem Action = actInsertSelectionsFromFrame end object miInsertCopyOfEntry: TMenuItem Action = actInsertCopyOfEntry end object miSeparator1: TMenuItem Caption = '-' end object miInsertSeparator: TMenuItem Action = actInsertSeparator end object miInsertSubMenu: TMenuItem Tag = 6 Action = actInsertSubMenu end end object pmAddDirectoryHotlist: TPopupMenu[3] left = 80 top = 112 object miAddBrowsedDir: TMenuItem Action = actAddBrowsedDir end object miAddTypedDir: TMenuItem Action = actAddTypedDir end object miAddActiveFrameDir: TMenuItem Action = actAddActiveFrameDir end object miAddBothFrameDir: TMenuItem Action = actAddBothFrameDir end object miAddSelectionsFromFrame: TMenuItem Action = actAddSelectionsFromFrame end object miAddCopyOfEntry: TMenuItem Action = actAddCopyOfEntry end object miSeparator2: TMenuItem Caption = '-' end object miAddSeparator: TMenuItem Action = actAddSeparator end object miAddSubMenu: TMenuItem Tag = 6 Action = actAddSubMenu end end object pmDeleteDirectoryHotlist: TPopupMenu[4] left = 80 top = 168 object miDeleteSelectedItem: TMenuItem Tag = 1 Action = actDeleteSelectedItem end object miSeparator3: TMenuItem Caption = '-' end object miDeleteSubMenuKeepElem: TMenuItem Tag = 2 Action = actDeleteSubMenuKeepElem end object miDeleteSubMenuAndElem: TMenuItem Tag = 3 Action = actDeleteSubMenuAndElem end object miSeparator4: TMenuItem Caption = '-' end object miDeleteAll: TMenuItem Action = actDeleteAll end end object pmSortDirectoryHotlist: TPopupMenu[5] left = 80 top = 224 object miSortSingleGroup: TMenuItem Tag = 1 Caption = '...single &group of item(s) only' OnClick = miSortDirectoryHotlistClick end object miCurrentLevelOfItemOnly: TMenuItem Tag = 2 Caption = '...current le&vel of item(s) selected only' OnClick = miSortDirectoryHotlistClick end object miSortSingleSubMenu: TMenuItem Tag = 3 Caption = '...&content of submenu(s) selected, no sublevel' OnClick = miSortDirectoryHotlistClick end object miSortSubMenuAndSubLevel: TMenuItem Tag = 4 Caption = '...content of submenu(s) selected and &all sublevels' OnClick = miSortDirectoryHotlistClick end object miSortEverything: TMenuItem Tag = 5 Caption = '...everything, from A to &Z!' OnClick = miSortDirectoryHotlistClick end end object pmMiscellaneousDirectoryHotlist: TPopupMenu[6] left = 80 top = 280 object miTestResultingHotlistMenu: TMenuItem Caption = 'Test resultin&g menu' OnClick = miTestResultingHotlistMenuClick end object miSeparator5: TMenuItem Caption = '-' end object miNavigate: TMenuItem Caption = '&Navigate...' object miFocusTreeWindow: TMenuItem Action = actFocusTreeWindow end object miSeparator10: TMenuItem Caption = '-' end object miGotoFirstItem: TMenuItem Action = actGotoFirstItem end object miGoToPreviousItem: TMenuItem Action = actGoToPreviousItem end object miGoToNextItem: TMenuItem Action = actGoToNextItem end object miGotoLastItem: TMenuItem Action = actGotoLastItem end object miSeparator11: TMenuItem Caption = '-' end object miExpandItem: TMenuItem Action = actExpandItem end object miOpenAllBranches: TMenuItem Action = actOpenAllBranches end object miCollapseItem: TMenuItem Action = actCollapseItem end object miCollapseAll: TMenuItem Action = actCollapseAll end object miSeparator12: TMenuItem Caption = '-' end object miMoveToPrevious: TMenuItem Action = actMoveToPrevious end object miMoveToNext: TMenuItem Action = actMoveToNext end end object miSeparator6: TMenuItem Caption = '-' end object miCut: TMenuItem Action = actCut end object miPaste: TMenuItem Action = actPaste end object miSeparator7: TMenuItem Caption = '-' end object miSearchAndReplace: TMenuItem Caption = 'Search and &replace...' object miSearchAndReplaceInPath: TMenuItem Action = actSearchAndReplaceInPath end object miSearchAndReplaceInTargetPath: TMenuItem Action = actSearchAndReplaceInTargetPath end object miSearchInReplaceInBothPaths: TMenuItem Action = actSearchAndReplaceInPathAndTarget end end object miSeparator8: TMenuItem Caption = '-' end object miTweakPath: TMenuItem Action = actTweakPath Caption = 'Tweak &path' end object miTweakTargetPath: TMenuItem Action = actTweakTargetPath Caption = 'Tweak &target path' end object miSeparator9: TMenuItem Caption = '-' end object miDetectIfPathExist: TMenuItem Tag = 1 Caption = 'Scan all &hotdir''s path to validate the ones that actually exist' OnClick = miDetectIfPathExistClick end object miDetectIfPathTargetExist: TMenuItem Tag = 2 Caption = '&Scan all hotdir''s path && target to validate the ones that actually exist' OnClick = miDetectIfPathExistClick end end object pmExportDirectoryHotlist: TPopupMenu[7] left = 256 top = 56 object miExportToHotlistFile: TMenuItem Tag = 1 Caption = 'to a Directory &Hotlist file (.hotlist)' OnClick = miExportToAnythingClick end object miSeparator13: TMenuItem Caption = '-' end object miExportToTotalCommanderk: TMenuItem Caption = 'to a "wincmd.ini" of TC (&keep existing)' OnClick = miExportToAnythingClick end object miExportToTotalCommandernk: TMenuItem Tag = 128 Caption = 'to a "wincmd.ini" of TC (&erase existing)' OnClick = miExportToAnythingClick end object miGotoConfigureTCInfo1: TMenuItem Caption = 'Go to &configure TC related info' OnClick = miGotoConfigureTCInfoClick end end object pmImportDirectoryHotlist: TPopupMenu[8] left = 256 top = 112 object miImportFromHotlistFile: TMenuItem Tag = 1 Caption = 'from a Directory &Hotlist file (.hotlist)' OnClick = miImportFromAnythingClick end object miSeparator14: TMenuItem Caption = '-' end object miImportTotalCommander: TMenuItem Caption = 'from "&wincmd.ini" of TC' OnClick = miImportFromAnythingClick end object miGotoConfigureTCInfo2: TMenuItem Caption = 'Go to &configure TC related info' OnClick = miGotoConfigureTCInfoClick end end object pmBackupDirectoryHotlist: TPopupMenu[9] left = 256 top = 168 object miSaveBackupHotlist: TMenuItem Tag = 2 Caption = '&Save a backup of current Directory Hotlist' OnClick = miExportToAnythingClick end object miRestoreBackupHotlist: TMenuItem Tag = 2 Caption = '&Restore a backup of Directory Hotlist' OnClick = miImportFromAnythingClick end end object pmHotDirTestMenu: TPopupMenu[10] left = 80 top = 336 object miHotDirTestMenu: TMenuItem Caption = 'HotDirTestMenu' end end object pmPathHelper: TPopupMenu[11] left = 256 top = 504 end object OpenDialog: TOpenDialog[12] DefaultExt = '.hotlist' Filter = 'Directory Hotlist files|*.hotlist|.xml Config files|*.xml|Any files|*.*' Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] left = 80 top = 504 end object SaveDialog: TSaveDialog[13] DefaultExt = '.hotlist' Filter = 'Directory Hotlist|*.hotlist' Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing, ofViewDetail] left = 80 top = 448 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdirectoryhotlist.lrj��������������������������������������������0000644�0001750�0000144�00000045317�14743153644�022572� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":149144793,"name":"tfrmoptionsdirectoryhotlist.gbdirectoryhotlist.caption","sourcebytes":[68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116,32,40,114,101,111,114,100,101,114,32,98,121,32,100,114,97,103,32,38,38,32,100,114,111,112,41],"value":"Directory Hotlist (reorder by drag && drop)"}, {"hash":164356446,"name":"tfrmoptionsdirectoryhotlist.btninsert.caption","sourcebytes":[38,73,110,115,101,114,116,46,46,46],"value":"&Insert..."}, {"hash":47114462,"name":"tfrmoptionsdirectoryhotlist.btndelete.caption","sourcebytes":[68,101,38,108,101,116,101,46,46,46],"value":"De&lete..."}, {"hash":124595966,"name":"tfrmoptionsdirectoryhotlist.btnexport.caption","sourcebytes":[69,38,120,112,111,114,116,46,46,46],"value":"E&xport..."}, {"hash":31225214,"name":"tfrmoptionsdirectoryhotlist.btnimport.caption","sourcebytes":[73,109,112,111,38,114,116,46,46,46],"value":"Impo&rt..."}, {"hash":220772446,"name":"tfrmoptionsdirectoryhotlist.btnbackup.caption","sourcebytes":[66,97,99,38,107,117,112,46,46,46],"value":"Bac&kup..."}, {"hash":63326686,"name":"tfrmoptionsdirectoryhotlist.btnmiscellaneous.caption","sourcebytes":[38,77,105,115,99,101,108,108,97,110,101,111,117,115,46,46,46],"value":"&Miscellaneous..."}, {"hash":63598926,"name":"tfrmoptionsdirectoryhotlist.btnadd.caption","sourcebytes":[65,38,100,100,46,46,46],"value":"A&dd..."}, {"hash":174683070,"name":"tfrmoptionsdirectoryhotlist.btnsort.caption","sourcebytes":[38,83,111,114,116,46,46,46],"value":"&Sort..."}, {"hash":163294828,"name":"tfrmoptionsdirectoryhotlist.rgwheretoadd.caption","sourcebytes":[65,100,100,105,116,105,111,110,32,102,114,111,109,32,109,97,105,110,32,112,97,110,101,108],"value":"Addition from main panel"}, {"hash":13910547,"name":"tfrmoptionsdirectoryhotlist.gbhotlistotheroptions.caption","sourcebytes":[79,116,104,101,114,32,111,112,116,105,111,110,115],"value":"Other options"}, {"hash":213892596,"name":"tfrmoptionsdirectoryhotlist.cbaddtarget.caption","sourcebytes":[38,87,104,101,110,32,97,100,100,105,110,103,32,100,105,114,101,99,116,111,114,121,44,32,97,100,100,32,97,108,115,111,32,116,97,114,103,101,116],"value":"&When adding directory, add also target"}, {"hash":154562805,"name":"tfrmoptionsdirectoryhotlist.cbfullexpandtree.caption","sourcebytes":[65,108,119,97,38,121,115,32,101,120,112,97,110,100,32,116,114,101,101],"value":"Alwa&ys expand tree"}, {"hash":112571981,"name":"tfrmoptionsdirectoryhotlist.cbshowpathinpopup.caption","sourcebytes":[73,110,32,112,111,112,38,117,112,44,32,115,104,111,119,32,91,112,97,116,104,32,97,108,115,111,93],"value":"In pop&up, show [path also]"}, {"hash":25651843,"name":"tfrmoptionsdirectoryhotlist.cbshowonlyvalidenv.caption","sourcebytes":[83,104,111,119,32,111,110,108,121,32,38,118,97,108,105,100,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,115],"value":"Show only &valid environment variables"}, {"hash":5538698,"name":"tfrmoptionsdirectoryhotlist.lbledithotdirname.editlabel.caption","sourcebytes":[78,97,109,101,58],"value":"Name:"}, {"hash":5671610,"name":"tfrmoptionsdirectoryhotlist.lbledithotdirpath.editlabel.caption","sourcebytes":[80,97,116,104,58],"value":"Path:"}, {"hash":15252584,"name":"tfrmoptionsdirectoryhotlist.btnrelativepath.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":58603722,"name":"tfrmoptionsdirectoryhotlist.cbsorthotdirpath.text","sourcebytes":[78,97,109,101,44,32,97,45,122],"value":"Name, a-z"}, {"hash":176742090,"name":"tfrmoptionsdirectoryhotlist.lbledithotdirtarget.editlabel.caption","sourcebytes":[38,84,97,114,103,101,116,58],"value":"&Target:"}, {"hash":142363940,"name":"tfrmoptionsdirectoryhotlist.btnrelativetarget.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,116,97,114,103,101,116],"value":"Some functions to select appropriate target"}, {"hash":58603722,"name":"tfrmoptionsdirectoryhotlist.cbsorthotdirtarget.text","sourcebytes":[78,97,109,101,44,32,97,45,122],"value":"Name, a-z"}, {"hash":7172799,"name":"tfrmoptionsdirectoryhotlist.actinsertbrowseddir.caption","sourcebytes":[73,110,115,101,114,116,32,100,105,114,101,99,116,111,114,121,32,73,32,119,105,108,108,32,98,114,111,38,119,115,101,32,116,111],"value":"Insert directory I will bro&wse to"}, {"hash":226835557,"name":"tfrmoptionsdirectoryhotlist.actinserttypeddir.caption","sourcebytes":[73,110,115,101,114,116,32,100,105,114,101,99,116,111,114,121,32,73,32,119,105,108,108,32,116,121,112,101],"value":"Insert directory I will type"}, {"hash":218973717,"name":"tfrmoptionsdirectoryhotlist.actinsertactiveframedir.caption","sourcebytes":[73,110,115,101,114,116,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,38,97,99,116,105,118,101,32,102,114,97,109,101],"value":"Insert directory of the &active frame"}, {"hash":146814867,"name":"tfrmoptionsdirectoryhotlist.actinsertbothframedir.caption","sourcebytes":[73,110,115,101,114,116,32,38,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,97,99,116,105,118,101,32,38,38,32,105,110,97,99,116,105,118,101,32,102,114,97,109,101,115],"value":"Insert &directories of the active && inactive frames"}, {"hash":37368773,"name":"tfrmoptionsdirectoryhotlist.actinsertselectionsfromframe.caption","sourcebytes":[73,110,115,101,114,116,32,99,117,114,114,101,110,116,32,38,115,101,108,101,99,116,101,100,32,111,114,32,97,99,116,105,118,101,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,97,99,116,105,118,101,32,102,114,97,109,101],"value":"Insert current &selected or active directories of active frame"}, {"hash":44342361,"name":"tfrmoptionsdirectoryhotlist.actinsertcopyofentry.caption","sourcebytes":[73,110,115,101,114,116,32,97,32,99,111,112,121,32,111,102,32,116,104,101,32,115,101,108,101,99,116,101,100,32,101,110,116,114,121],"value":"Insert a copy of the selected entry"}, {"hash":99512370,"name":"tfrmoptionsdirectoryhotlist.actinsertseparator.caption","sourcebytes":[73,110,115,101,114,116,32,97,32,115,101,112,97,114,97,116,111,114],"value":"Insert a separator"}, {"hash":42995109,"name":"tfrmoptionsdirectoryhotlist.actinsertsubmenu.caption","sourcebytes":[73,110,115,101,114,116,32,115,117,98,32,109,101,110,117],"value":"Insert sub menu"}, {"hash":190336655,"name":"tfrmoptionsdirectoryhotlist.actaddbrowseddir.caption","sourcebytes":[65,100,100,32,100,105,114,101,99,116,111,114,121,32,73,32,119,105,108,108,32,98,114,111,38,119,115,101,32,116,111],"value":"Add directory I will bro&wse to"}, {"hash":112205909,"name":"tfrmoptionsdirectoryhotlist.actaddtypeddir.caption","sourcebytes":[65,100,100,32,100,105,114,101,99,116,111,114,121,32,73,32,119,105,108,108,32,116,121,112,101],"value":"Add directory I will type"}, {"hash":246454597,"name":"tfrmoptionsdirectoryhotlist.actaddactiveframedir.caption","sourcebytes":[65,100,100,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,38,97,99,116,105,118,101,32,102,114,97,109,101],"value":"Add directory of the &active frame"}, {"hash":66664483,"name":"tfrmoptionsdirectoryhotlist.actaddbothframedir.caption","sourcebytes":[65,100,100,32,38,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,97,99,116,105,118,101,32,38,38,32,105,110,97,99,116,105,118,101,32,102,114,97,109,101,115],"value":"Add &directories of the active && inactive frames"}, {"hash":132163269,"name":"tfrmoptionsdirectoryhotlist.actaddselectionsfromframe.caption","sourcebytes":[65,100,100,32,99,117,114,114,101,110,116,32,38,115,101,108,101,99,116,101,100,32,111,114,32,97,99,116,105,118,101,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,97,99,116,105,118,101,32,102,114,97,109,101],"value":"Add current &selected or active directories of active frame"}, {"hash":133489097,"name":"tfrmoptionsdirectoryhotlist.actaddcopyofentry.caption","sourcebytes":[65,100,100,32,97,32,99,111,112,121,32,111,102,32,116,104,101,32,115,101,108,101,99,116,101,100,32,101,110,116,114,121],"value":"Add a copy of the selected entry"}, {"hash":15447298,"name":"tfrmoptionsdirectoryhotlist.actaddseparator.caption","sourcebytes":[65,100,100,32,97,32,115,101,112,97,114,97,116,111,114],"value":"Add a separator"}, {"hash":18942341,"name":"tfrmoptionsdirectoryhotlist.actaddsubmenu.caption","sourcebytes":[65,100,100,32,97,32,115,117,98,32,109,101,110,117],"value":"Add a sub menu"}, {"hash":248058829,"name":"tfrmoptionsdirectoryhotlist.actdeleteselecteditem.caption","sourcebytes":[68,101,108,101,116,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109],"value":"Delete selected item"}, {"hash":48325955,"name":"tfrmoptionsdirectoryhotlist.actdeletesubmenukeepelem.caption","sourcebytes":[68,101,108,101,116,101,32,106,117,115,116,32,115,117,98,45,109,101,110,117,32,98,117,116,32,107,101,101,112,32,101,108,101,109,101,110,116,115],"value":"Delete just sub-menu but keep elements"}, {"hash":29187699,"name":"tfrmoptionsdirectoryhotlist.actdeletesubmenuandelem.caption","sourcebytes":[68,101,108,101,116,101,32,115,117,98,45,109,101,110,117,32,97,110,100,32,97,108,108,32,105,116,115,32,101,108,101,109,101,110,116,115],"value":"Delete sub-menu and all its elements"}, {"hash":171753505,"name":"tfrmoptionsdirectoryhotlist.actdeleteall.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,33],"value":"Delete all!"}, {"hash":256685939,"name":"tfrmoptionsdirectoryhotlist.actmovetoprevious.caption","sourcebytes":[77,111,118,101,32,116,111,32,112,114,101,118,105,111,117,115],"value":"Move to previous"}, {"hash":5344116,"name":"tfrmoptionsdirectoryhotlist.actmovetonext.caption","sourcebytes":[77,111,118,101,32,116,111,32,110,101,120,116],"value":"Move to next"}, {"hash":255018692,"name":"tfrmoptionsdirectoryhotlist.actpaste.caption","sourcebytes":[80,97,115,116,101,32,119,104,97,116,32,119,97,115,32,99,117,116],"value":"Paste what was cut"}, {"hash":249109187,"name":"tfrmoptionsdirectoryhotlist.actcut.caption","sourcebytes":[67,117,116,32,115,101,108,101,99,116,105,111,110,32,111,102,32,101,110,116,114,105,101,115],"value":"Cut selection of entries"}, {"hash":22744456,"name":"tfrmoptionsdirectoryhotlist.actsearchandreplaceinpath.caption","sourcebytes":[83,101,97,114,99,104,32,38,38,32,114,101,112,108,97,99,101,32,105,110,32,38,112,97,116,104],"value":"Search && replace in &path"}, {"hash":165393000,"name":"tfrmoptionsdirectoryhotlist.actsearchandreplaceintargetpath.caption","sourcebytes":[83,101,97,114,99,104,32,38,38,32,114,101,112,108,97,99,101,32,105,110,32,38,116,97,114,103,101,116,32,112,97,116,104],"value":"Search && replace in &target path"}, {"hash":234270420,"name":"tfrmoptionsdirectoryhotlist.actsearchandreplaceinpathandtarget.caption","sourcebytes":[83,101,97,114,99,104,32,38,38,32,114,101,112,108,97,99,101,32,105,110,32,98,111,116,104,32,112,97,116,104,32,97,110,100,32,116,97,114,103,101,116],"value":"Search && replace in both path and target"}, {"hash":48930007,"name":"tfrmoptionsdirectoryhotlist.actfocustreewindow.caption","sourcebytes":[70,111,99,117,115,32,116,114,101,101,32,119,105,110,100,111,119],"value":"Focus tree window"}, {"hash":24220749,"name":"tfrmoptionsdirectoryhotlist.actgotofirstitem.caption","sourcebytes":[71,111,116,111,32,102,105,114,115,116,32,105,116,101,109],"value":"Goto first item"}, {"hash":97416685,"name":"tfrmoptionsdirectoryhotlist.actgotopreviousitem.caption","sourcebytes":[71,111,32,116,111,32,112,114,101,118,105,111,117,115,32,105,116,101,109],"value":"Go to previous item"}, {"hash":148385901,"name":"tfrmoptionsdirectoryhotlist.actgotonextitem.caption","sourcebytes":[71,111,32,116,111,32,110,101,120,116,32,105,116,101,109],"value":"Go to next item"}, {"hash":215514333,"name":"tfrmoptionsdirectoryhotlist.actgotolastitem.caption","sourcebytes":[71,111,116,111,32,108,97,115,116,32,105,116,101,109],"value":"Goto last item"}, {"hash":69991485,"name":"tfrmoptionsdirectoryhotlist.actexpanditem.caption","sourcebytes":[69,120,112,97,110,100,32,105,116,101,109],"value":"Expand item"}, {"hash":240129107,"name":"tfrmoptionsdirectoryhotlist.actopenallbranches.caption","sourcebytes":[79,112,101,110,32,97,108,108,32,98,114,97,110,99,104,101,115],"value":"Open all branches"}, {"hash":51782285,"name":"tfrmoptionsdirectoryhotlist.actcollapseitem.caption","sourcebytes":[67,111,108,108,97,112,115,101,32,105,116,101,109],"value":"Collapse item"}, {"hash":53565100,"name":"tfrmoptionsdirectoryhotlist.actcollapseall.caption","sourcebytes":[67,111,108,108,97,112,115,101,32,97,108,108],"value":"Collapse all"}, {"hash":131257624,"name":"tfrmoptionsdirectoryhotlist.acttweakpath.caption","sourcebytes":[84,119,101,97,107,32,112,97,116,104],"value":"Tweak path"}, {"hash":21379848,"name":"tfrmoptionsdirectoryhotlist.acttweaktargetpath.caption","sourcebytes":[84,119,101,97,107,32,116,97,114,103,101,116,32,112,97,116,104],"value":"Tweak target path"}, {"hash":22505513,"name":"tfrmoptionsdirectoryhotlist.misortsinglegroup.caption","sourcebytes":[46,46,46,115,105,110,103,108,101,32,38,103,114,111,117,112,32,111,102,32,105,116,101,109,40,115,41,32,111,110,108,121],"value":"...single &group of item(s) only"}, {"hash":90604313,"name":"tfrmoptionsdirectoryhotlist.micurrentlevelofitemonly.caption","sourcebytes":[46,46,46,99,117,114,114,101,110,116,32,108,101,38,118,101,108,32,111,102,32,105,116,101,109,40,115,41,32,115,101,108,101,99,116,101,100,32,111,110,108,121],"value":"...current le&vel of item(s) selected only"}, {"hash":265984124,"name":"tfrmoptionsdirectoryhotlist.misortsinglesubmenu.caption","sourcebytes":[46,46,46,38,99,111,110,116,101,110,116,32,111,102,32,115,117,98,109,101,110,117,40,115,41,32,115,101,108,101,99,116,101,100,44,32,110,111,32,115,117,98,108,101,118,101,108],"value":"...&content of submenu(s) selected, no sublevel"}, {"hash":88578467,"name":"tfrmoptionsdirectoryhotlist.misortsubmenuandsublevel.caption","sourcebytes":[46,46,46,99,111,110,116,101,110,116,32,111,102,32,115,117,98,109,101,110,117,40,115,41,32,115,101,108,101,99,116,101,100,32,97,110,100,32,38,97,108,108,32,115,117,98,108,101,118,101,108,115],"value":"...content of submenu(s) selected and &all sublevels"}, {"hash":143642737,"name":"tfrmoptionsdirectoryhotlist.misorteverything.caption","sourcebytes":[46,46,46,101,118,101,114,121,116,104,105,110,103,44,32,102,114,111,109,32,65,32,116,111,32,38,90,33],"value":"...everything, from A to &Z!"}, {"hash":179628341,"name":"tfrmoptionsdirectoryhotlist.mitestresultinghotlistmenu.caption","sourcebytes":[84,101,115,116,32,114,101,115,117,108,116,105,110,38,103,32,109,101,110,117],"value":"Test resultin&g menu"}, {"hash":255790590,"name":"tfrmoptionsdirectoryhotlist.minavigate.caption","sourcebytes":[38,78,97,118,105,103,97,116,101,46,46,46],"value":"&Navigate..."}, {"hash":214635198,"name":"tfrmoptionsdirectoryhotlist.misearchandreplace.caption","sourcebytes":[83,101,97,114,99,104,32,97,110,100,32,38,114,101,112,108,97,99,101,46,46,46],"value":"Search and &replace..."}, {"hash":225883096,"name":"tfrmoptionsdirectoryhotlist.mitweakpath.caption","sourcebytes":[84,119,101,97,107,32,38,112,97,116,104],"value":"Tweak &path"}, {"hash":184571816,"name":"tfrmoptionsdirectoryhotlist.mitweaktargetpath.caption","sourcebytes":[84,119,101,97,107,32,38,116,97,114,103,101,116,32,112,97,116,104],"value":"Tweak &target path"}, {"hash":144284980,"name":"tfrmoptionsdirectoryhotlist.midetectifpathexist.caption","sourcebytes":[83,99,97,110,32,97,108,108,32,38,104,111,116,100,105,114,39,115,32,112,97,116,104,32,116,111,32,118,97,108,105,100,97,116,101,32,116,104,101,32,111,110,101,115,32,116,104,97,116,32,97,99,116,117,97,108,108,121,32,101,120,105,115,116],"value":"Scan all &hotdir's path to validate the ones that actually exist"}, {"hash":178514500,"name":"tfrmoptionsdirectoryhotlist.midetectifpathtargetexist.caption","sourcebytes":[38,83,99,97,110,32,97,108,108,32,104,111,116,100,105,114,39,115,32,112,97,116,104,32,38,38,32,116,97,114,103,101,116,32,116,111,32,118,97,108,105,100,97,116,101,32,116,104,101,32,111,110,101,115,32,116,104,97,116,32,97,99,116,117,97,108,108,121,32,101,120,105,115,116],"value":"&Scan all hotdir's path && target to validate the ones that actually exist"}, {"hash":190135113,"name":"tfrmoptionsdirectoryhotlist.miexporttohotlistfile.caption","sourcebytes":[116,111,32,97,32,68,105,114,101,99,116,111,114,121,32,38,72,111,116,108,105,115,116,32,102,105,108,101,32,40,46,104,111,116,108,105,115,116,41],"value":"to a Directory &Hotlist file (.hotlist)"}, {"hash":56254025,"name":"tfrmoptionsdirectoryhotlist.miexporttototalcommanderk.caption","sourcebytes":[116,111,32,97,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,32,40,38,107,101,101,112,32,101,120,105,115,116,105,110,103,41],"value":"to a \"wincmd.ini\" of TC (&keep existing)"}, {"hash":185653097,"name":"tfrmoptionsdirectoryhotlist.miexporttototalcommandernk.caption","sourcebytes":[116,111,32,97,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,32,40,38,101,114,97,115,101,32,101,120,105,115,116,105,110,103,41],"value":"to a \"wincmd.ini\" of TC (&erase existing)"}, {"hash":156397055,"name":"tfrmoptionsdirectoryhotlist.migotoconfiguretcinfo1.caption","sourcebytes":[71,111,32,116,111,32,38,99,111,110,102,105,103,117,114,101,32,84,67,32,114,101,108,97,116,101,100,32,105,110,102,111],"value":"Go to &configure TC related info"}, {"hash":188656233,"name":"tfrmoptionsdirectoryhotlist.miimportfromhotlistfile.caption","sourcebytes":[102,114,111,109,32,97,32,68,105,114,101,99,116,111,114,121,32,38,72,111,116,108,105,115,116,32,102,105,108,101,32,40,46,104,111,116,108,105,115,116,41],"value":"from a Directory &Hotlist file (.hotlist)"}, {"hash":86366963,"name":"tfrmoptionsdirectoryhotlist.miimporttotalcommander.caption","sourcebytes":[102,114,111,109,32,34,38,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67],"value":"from \"&wincmd.ini\" of TC"}, {"hash":156397055,"name":"tfrmoptionsdirectoryhotlist.migotoconfiguretcinfo2.caption","sourcebytes":[71,111,32,116,111,32,38,99,111,110,102,105,103,117,114,101,32,84,67,32,114,101,108,97,116,101,100,32,105,110,102,111],"value":"Go to &configure TC related info"}, {"hash":241888772,"name":"tfrmoptionsdirectoryhotlist.misavebackuphotlist.caption","sourcebytes":[38,83,97,118,101,32,97,32,98,97,99,107,117,112,32,111,102,32,99,117,114,114,101,110,116,32,68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116],"value":"&Save a backup of current Directory Hotlist"}, {"hash":216881220,"name":"tfrmoptionsdirectoryhotlist.mirestorebackuphotlist.caption","sourcebytes":[38,82,101,115,116,111,114,101,32,97,32,98,97,99,107,117,112,32,111,102,32,68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116],"value":"&Restore a backup of Directory Hotlist"}, {"hash":170146053,"name":"tfrmoptionsdirectoryhotlist.mihotdirtestmenu.caption","sourcebytes":[72,111,116,68,105,114,84,101,115,116,77,101,110,117],"value":"HotDirTestMenu"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdirectoryhotlist.pas��������������������������������������������0000644�0001750�0000144�00000250032�14743153644�022556� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Configuration of HotDir Copyright (C) 2009-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit foptionsDirectoryHotlist; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. ActnList, SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, ExtCtrls, Menus, Dialogs, ComCtrls, types, //DC {$IFDEF MSWINDOWS} uTotalCommander, {$ENDIF} uGlobs, fOptionsFrame, uFile, uHotDir; type TProcedureWhenClickingAMenuItem = procedure(Sender: TObject) of object; { TfrmOptionsDirectoryHotlist } TfrmOptionsDirectoryHotlist = class(TOptionsEditor) actList: TActionList; actInsertBrowsedDir: TAction; actInsertTypedDir: TAction; actInsertActiveFrameDir: TAction; actInsertBothFrameDir: TAction; actInsertSelectionsFromFrame: TAction; actInsertCopyOfEntry: TAction; actInsertSeparator: TAction; actInsertSubMenu: TAction; actAddBrowsedDir: TAction; actAddTypedDir: TAction; actAddActiveFrameDir: TAction; actAddBothFrameDir: TAction; actAddSelectionsFromFrame: TAction; actAddCopyOfEntry: TAction; miSeparator2: TMenuItem; actAddSeparator: TAction; actAddSubMenu: TAction; actDeleteSelectedItem: TAction; actDeleteSubMenuKeepElem: TAction; actDeleteSubMenuAndElem: TAction; actDeleteAll: TAction; actMoveToPrevious: TAction; actMoveToNext: TAction; actCut: TAction; actPaste: TAction; actSearchAndReplaceInPath: TAction; actSearchAndReplaceInTargetPath: TAction; actSearchAndReplaceInPathAndTarget: TAction; actTweakPath: TAction; actTweakTargetPath: TAction; actFocusTreeWindow: TAction; actGotoFirstItem: TAction; actGoToPreviousItem: TAction; actGoToNextItem: TAction; actGotoLastItem: TAction; actExpandItem: TAction; actOpenAllBranches: TAction; actCollapseItem: TAction; actCollapseAll: TAction; pmInsertDirectoryHotlist: TPopupMenu; miInsertBrowsedDir: TMenuItem; miInsertTypedDir: TMenuItem; miInsertActiveFrameDir: TMenuItem; miInsertBothFrameDir: TMenuItem; miInsertSelectionsFromFrame: TMenuItem; miInsertCopyOfEntry: TMenuItem; miSeparator1: TMenuItem; miInsertSeparator: TMenuItem; miInsertSubMenu: TMenuItem; pmAddDirectoryHotlist: TPopupMenu; miAddBrowsedDir: TMenuItem; miAddTypedDir: TMenuItem; miAddActiveFrameDir: TMenuItem; miAddBothFrameDir: TMenuItem; miAddSelectionsFromFrame: TMenuItem; miAddCopyOfEntry: TMenuItem; miAddSeparator: TMenuItem; miAddSubMenu: TMenuItem; pmDeleteDirectoryHotlist: TPopupMenu; miDeleteSelectedItem: TMenuItem; miSeparator3: TMenuItem; miDeleteSubMenuKeepElem: TMenuItem; miDeleteSubMenuAndElem: TMenuItem; miSeparator4: TMenuItem; miDeleteAll: TMenuItem; pmSortDirectoryHotlist: TPopupMenu; miSortSingleGroup: TMenuItem; miCurrentLevelOfItemOnly: TMenuItem; miSortSingleSubMenu: TMenuItem; miSortSubMenuAndSubLevel: TMenuItem; miSortEverything: TMenuItem; pmMiscellaneousDirectoryHotlist: TPopupMenu; miTestResultingHotlistMenu: TMenuItem; miSeparator5: TMenuItem; miNavigate: TMenuItem; miFocusTreeWindow: TMenuItem; miSeparator10: TMenuItem; miGotoFirstItem: TMenuItem; miGoToPreviousItem: TMenuItem; miGoToNextItem: TMenuItem; miGotoLastItem: TMenuItem; miSeparator11: TMenuItem; miExpandItem: TMenuItem; miOpenAllBranches: TMenuItem; miCollapseItem: TMenuItem; miCollapseAll: TMenuItem; miSeparator12: TMenuItem; miMoveToPrevious: TMenuItem; miMoveToNext: TMenuItem; miSeparator6: TMenuItem; miCut: TMenuItem; miPaste: TMenuItem; miSeparator7: TMenuItem; miSearchAndReplace: TMenuItem; miSearchAndReplaceInPath: TMenuItem; miSearchAndReplaceInTargetPath: TMenuItem; miSearchInReplaceInBothPaths: TMenuItem; miSeparator8: TMenuItem; miTweakPath: TMenuItem; miTweakTargetPath: TMenuItem; miSeparator9: TMenuItem; miDetectIfPathExist: TMenuItem; miDetectIfPathTargetExist: TMenuItem; pmExportDirectoryHotlist: TPopupMenu; miExportToHotlistFile: TMenuItem; miSeparator13: TMenuItem; miExportToTotalCommanderk: TMenuItem; miExportToTotalCommandernk: TMenuItem; miGotoConfigureTCInfo1: TMenuItem; pmImportDirectoryHotlist: TPopupMenu; miImportFromHotlistFile: TMenuItem; miSeparator14: TMenuItem; miImportTotalCommander: TMenuItem; miGotoConfigureTCInfo2: TMenuItem; pmBackupDirectoryHotlist: TPopupMenu; miSaveBackupHotlist: TMenuItem; miRestoreBackupHotlist: TMenuItem; pmHotDirTestMenu: TPopupMenu; miHotDirTestMenu: TMenuItem; gbDirectoryHotlist: TGroupBox; pnlClient: TPanel; tvDirectoryHotlist: TTreeView; pnlButtons: TPanel; btnInsert: TBitBtn; btnAdd: TBitBtn; btnDelete: TBitBtn; btnSort: TBitBtn; btnMiscellaneous: TBitBtn; btnExport: TBitBtn; btnImport: TBitBtn; btnBackup: TBitBtn; pnlBottom: TPanel; rgWhereToAdd: TRadioGroup; gbHotlistOtherOptions: TGroupBox; cbAddTarget: TCheckBox; cbFullExpandTree: TCheckBox; cbShowPathInPopup: TCheckBox; cbShowOnlyValidEnv: TCheckBox; lbleditHotDirName: TLabeledEdit; lbleditHotDirPath: TLabeledEdit; btnRelativePath: TSpeedButton; cbSortHotDirPath: TComboBox; lbleditHotDirTarget: TLabeledEdit; btnRelativeTarget: TSpeedButton; cbSortHotDirTarget: TComboBox; pmPathHelper: TPopupMenu; OpenDialog: TOpenDialog; SaveDialog: TSaveDialog; procedure actInsertOrAddSomethingExecute(Sender: TObject); procedure actDeleteSomethingExecute(Sender: TObject); procedure actDeleteAllExecute(Sender: TObject); procedure actMoveToPreviousExecute(Sender: TObject); procedure actMoveToNextExecute(Sender: TObject); procedure actCutExecute(Sender: TObject); procedure actPasteExecute(Sender: TObject); procedure actSearchAndReplaceExecute(Sender: TObject); procedure actTweakPathExecute(Sender: TObject); procedure actFocusTreeWindowExecute(Sender: TObject); procedure actGotoFirstItemExecute(Sender: TObject); procedure actGoToPreviousItemExecute(Sender: TObject); procedure actGoToNextItemExecute(Sender: TObject); procedure actGotoLastItemExecute(Sender: TObject); procedure actExpandItemExecute(Sender: TObject); procedure actOpenAllBranchesExecute(Sender: TObject); procedure actCollapseItemExecute(Sender: TObject); procedure actCollapseAllExecute(Sender: TObject); procedure miSortDirectoryHotlistClick(Sender: TObject); procedure miTestResultingHotlistMenuClick(Sender: TObject); procedure miDetectIfPathExistClick(Sender: TObject); procedure miExportToAnythingClick(Sender: TObject); procedure miImportFromAnythingClick(Sender: TObject); procedure miGotoConfigureTCInfoClick(Sender: TObject); procedure btnActionClick(Sender: TObject); procedure cbFullExpandTreeChange(Sender: TObject); procedure lbleditHotDirNameChange(Sender: TObject); procedure anyRelativeAbsolutePathClick(Sender: TObject); procedure cbSortHotDirPathChange(Sender: TObject); procedure cbSortHotDirTargetChange(Sender: TObject); procedure pnlButtonsResize(Sender: TObject); procedure tvDirectoryHotlistDragDrop(Sender, {%H-}Source: TObject; X, Y: integer); procedure tvDirectoryHotlistDragOver(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure tvDirectoryHotlistEnter(Sender: TObject); procedure tvDirectoryHotlistExit(Sender: TObject); procedure tvDirectoryHotlistSelectionChanged(Sender: TObject); procedure RefreshTreeView(NodeToSelect: TTreeNode); procedure PopulatePopupMenuWithCommands(pmMenuToPopulate: TPopupMenu); procedure miShowWhereItWouldGo(Sender: TObject); procedure miSimplyCopyCaption(Sender: TObject); procedure ClearCutAndPasteList; function ActualAddDirectories(ParamDispatcher: TKindOfHotDirEntry; sName, sPath, sTarget: string; InsertOrAdd: integer): TTreeNode; function TryToGetCloserHotDir(sDirToFindAPlaceFor: string; var TypeOfAddition: integer): TTreeNode; function TryToGetExactHotDir(const index: integer): TTreeNode; procedure RecursiveSetGroupNumbers(ParamNode: TTreeNode; ParamGroupNumber: integer; DoRecursion, StopAtFirstGroup: boolean); procedure RefreshExistingProperty(ScanMode: integer); procedure SetNormalIconsInTreeView; function MySortViaGroup(Node1, Node2: TTreeNode): integer; procedure CopyTTreeViewToAnother(tvSource, tvDestination: TTreeView); function GetNextGroupNumber: integer; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; private { Private declarations } pmCommandHelper: TPopupMenu; DirectoryHotlistTemp: TDirectoryHotlist; CutAndPasteIndexList: TStringList; GlobalGroupNumber: integer; public { Public declarations } class function GetIconIndex: integer; override; class function GetTitle: string; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; destructor Destroy; override; procedure SubmitToAddOrConfigToHotDirDlg(paramActionDispatcher: integer; paramPath, paramTarget: string; paramOptionalIndex: integer); procedure ScanHotDirForFilenameAndPath; function GetHotDirFilenameToSave(AHotDirPathModifierElement: tHotDirPathModifierElement; sParamFilename: string): string; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Graphics, LCLType, LazUTF8, LCLIntf, LCLMessageGlue, helpintfs, //DC fEditSearch, fOptionsMisc, DCStrUtils, uLng, uDCUtils, fmain, uFormCommands, uFileProcs, uShowMsg, DCOSUtils, uSpecialDir, fhotdirexportimport, uComponentsSignature; { Constants used with export/import } const MASK_ACTION_WITH_WHAT = $03; MASK_FLUSHORNOT_EXISTING = $80; ACTION_WITH_WINCMDINI = $00; ACTION_WITH_HOTLISTFILE = $01; ACTION_WITH_BACKUP = $02; ACTION_ERASEEXISTING = $80; { Constant used with various action } ACTION_INSERTHOTDIR = 1; ACTION_ADDHOTDIR = 2; { TfrmOptionsDirectoryHotlist.Init } procedure TfrmOptionsDirectoryHotlist.Init; begin pnlBottom.Constraints.MinHeight := pnlBottom.Height; ParseLineToList(rsOptAddFromMainPanel, rgWhereToAdd.Items); ParseLineToList(rsHotDirForceSortingOrderChoices, cbSortHotDirPath.Items); ParseLineToList(rsHotDirForceSortingOrderChoices, cbSortHotDirTarget.Items); OpenDialog.Filter := ParseLineToFileFilter([rsFilterDirectoryHotListFiles, '*.hotlist', rsFilterXmlConfigFiles, '*.xml', rsFilterAnyFiles, AllFilesMask]); SaveDialog.Filter := ParseLineToFileFilter([rsFilterDirectoryHotListFiles, '*.hotlist']); end; { TfrmOptionsDirectoryHotlist.Load } procedure TfrmOptionsDirectoryHotlist.Load; begin gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper, mp_PATHHELPER, nil); pmCommandHelper := TPopupMenu.Create(Self); PopulatePopupMenuWithCommands(pmCommandHelper); btnRelativePath.Hint := rsMsgHotDirTipSpecialDirBut; btnRelativeTarget.Hint := rsMsgHotDirTipSpecialDirBut; cbSortHotDirPath.Hint := rsMsgHotDirTipOrderPath; cbSortHotDirTarget.Hint := rsMsgHotDirTipOrderTarget; cbAddTarget.Checked := gHotDirAddTargetOrNot; cbFullExpandTree.Checked := gHotDirFullExpandOrNot; cbShowPathInPopup.Checked := gShowPathInPopup; cbShowOnlyValidEnv.Checked := gShowOnlyValidEnv; rgWhereToAdd.ItemIndex := integer(gWhereToAddNewHotDir); CutAndPasteIndexList := TStringList.Create; CutAndPasteIndexList.Sorted := True; CutAndPasteIndexList.Duplicates := dupAccept; {$IFNDEF MSWINDOWS} miExportToTotalCommanderk.Free; miExportToTotalCommandernk.Free; miGotoConfigureTCInfo1.Free; miImportTotalCommander.Free; miGotoConfigureTCInfo2.Free; miSeparator13.Free; miSeparator14.Free; {$ENDIF} if DirectoryHotlistTemp = nil then begin DirectoryHotlistTemp := TDirectoryHotlist.Create; gDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist(DirectoryHotlistTemp); end; tvDirectoryHotlist.Images := frmMain.imgLstDirectoryHotlist; DirectoryHotlistTemp.LoadTTreeView(tvDirectoryHotlist, -1); cbFullExpandTreeChange(cbFullExpandTree); if tvDirectoryHotlist.Items.Count > 0 then tvDirectoryHotlist.Items[0].Selected := True //Select at least first one by default else RefreshTreeView(nil); //If zero hot directory we will hide the directory path, disable export button, etc. end; { TfrmOptionsDirectoryHotlist.Save } function TfrmOptionsDirectoryHotlist.Save: TOptionsEditorSaveFlags; begin Result := []; DirectoryHotlistTemp.RefreshFromTTreeView(tvDirectoryHotlist); DirectoryHotlistTemp.CopyDirectoryHotlistToDirectoryHotlist(gDirectoryHotlist); gHotDirAddTargetOrNot := cbAddTarget.Checked; gHotDirFullExpandOrNot := cbFullExpandTree.Checked; if gShowPathInPopup <> cbShowPathInPopup.Checked then begin gShowPathInPopup := cbShowPathInPopup.Checked; pmPathHelper.Items.Clear; //Let' re-populate it since option for environment variable path has changed... gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper, mp_PATHHELPER, nil); end; if gShowOnlyValidEnv <> cbShowOnlyValidEnv.Checked then begin gShowOnlyValidEnv := cbShowOnlyValidEnv.Checked; LoadWindowsSpecialDir; pmPathHelper.Items.Clear; //Let' re-populate it since option for environment variabel path has changed... gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper, mp_PATHHELPER, nil); end; gWhereToAddNewHotDir := TPositionWhereToAddHotDir(rgWhereToAdd.ItemIndex); cbFullExpandTreeChange(cbFullExpandTree); end; { TfrmOptionsDirectoryHotlist.GetIconIndex } class function TfrmOptionsDirectoryHotlist.GetIconIndex: integer; begin Result := 33; end; { TfrmOptionsDirectoryHotlist.GetTitle } class function TfrmOptionsDirectoryHotlist.GetTitle: string; begin Result := rsOptionsEditorDirectoryHotlist; end; { TfrmOptionsDirectoryHotlist.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsDirectoryHotlist.IsSignatureComputedFromAllWindowComponents: boolean; begin Result := False; end; { TfrmOptionsDirectoryHotlist.ExtraOptionsSignature } function TfrmOptionsDirectoryHotlist.ExtraOptionsSignature(CurrentSignature: dword): dword; begin DirectoryHotlistTemp.RefreshFromTTreeView(tvDirectoryHotlist); Result := DirectoryHotlistTemp.ComputeSignature(CurrentSignature); Result := ComputeSignatureSingleComponent(rgWhereToAdd, Result); Result := ComputeSignatureSingleComponent(cbAddTarget, Result); Result := ComputeSignatureSingleComponent(cbFullExpandTree, Result); Result := ComputeSignatureSingleComponent(cbShowPathInPopup, Result); Result := ComputeSignatureSingleComponent(cbShowOnlyValidEnv, Result); end; { TfrmOptionsDirectoryHotlist.Destroy } destructor TfrmOptionsDirectoryHotlist.Destroy; begin pmCommandHelper.Free; CutAndPasteIndexList.Free; inherited Destroy; end; { TfrmOptionsDirectoryHotlist.SubmitToAddOrConfigToHotDirDlg } procedure TfrmOptionsDirectoryHotlist.SubmitToAddOrConfigToHotDirDlg(paramActionDispatcher: integer; paramPath, paramTarget: string; paramOptionalIndex: integer); var TypeOfAddition, IndexFile: longint; sTempo: string; NodeToSelect: TTreeNode = nil; SelectedOrActiveDirectories: TFiles; procedure AddThisSubmittedDirectory(DirectoryPath: string); begin if ((paramActionDispatcher = ACTION_ADDTOHOTLIST) and (cbAddTarget.Checked)) or (paramActionDispatcher = ACTION_ADDBOTHTOHOTLIST) then sTempo := IncludeTrailingPathDelimiter(paramTarget) else sTempo := ''; if gWhereToAddNewHotDir = ahdLast then TypeOfAddition := ACTION_ADDHOTDIR else TypeOfAddition := ACTION_INSERTHOTDIR; NodeToSelect := nil; if (tvDirectoryHotlist.Items.Count > 0) then begin case gWhereToAddNewHotDir of ahdFirst: NodeToSelect := tvDirectoryHotlist.Items.Item[0]; ahdLast: NodeToSelect := tvDirectoryHotlist.Items.Item[pred(tvDirectoryHotlist.Items.Count)]; ahdSmart: NodeToSelect := TryToGetCloserHotDir(DirectoryPath, TypeOfAddition); else NodeToSelect := tvDirectoryHotlist.Items.Item[0]; end; if NodeToSelect <> nil then NodeToSelect.Selected := True; end; NodeToSelect := ActualAddDirectories(hd_CHANGEPATH, GetLastDir(DirectoryPath).Replace('&','&&'), DirectoryPath, sTempo, TypeOfAddition); end; begin case paramActionDispatcher of ACTION_ADDTOHOTLIST, ACTION_ADDJUSTSOURCETOHOTLIST, ACTION_ADDBOTHTOHOTLIST: begin AddThisSubmittedDirectory(paramPath); end; ACTION_CONFIGTOHOTLIST: begin NodeToSelect := TryToGetCloserHotDir(paramPath, TypeOfAddition); end; ACTION_JUSTSHOWCONFIGHOTLIST: begin if tvDirectoryHotlist.Items.Count > 0 then NodeToSelect := tvDirectoryHotlist.Items.Item[0]; end; ACTION_ADDSELECTEDDIR: begin SelectedOrActiveDirectories := frmMain.ActiveFrame.CloneSelectedOrActiveDirectories; try if SelectedOrActiveDirectories.Count > 0 then begin for IndexFile := 0 to pred(SelectedOrActiveDirectories.Count) do AddThisSubmittedDirectory(ExcludeTrailingPathDelimiter(SelectedOrActiveDirectories[IndexFile].FullPath)); end; finally FreeAndNil(SelectedOrActiveDirectories); end; end; ACTION_DIRECTLYCONFIGENTRY: begin NodeToSelect := TryToGetExactHotDir(paramOptionalIndex); end end; if (NodeToSelect = nil) and (tvDirectoryHotlist.Items.Count > 0) then NodeToSelect := tvDirectoryHotlist.Items.Item[0]; RefreshTreeView(NodeToSelect); //2014-08-27: These lines are a workaround a problem present at this moment in Lazarus regarding TSpeedButton present inside a TGroupBox. //See on the web if the following case is solved prior to remove these lines: http://bugs.freepascal.org/view.php?id=26638 {$IFDEF MSWINDOWS} if tvDirectoryHotlist.CanFocus then begin LCLSendMouseDownMsg(Self, 1, 1, mbLeft, []); LCLSendMouseUpMsg(Self, 1, 1, mbLeft, []); end; {$ENDIF MSWINDOWS} if not tvDirectoryHotlist.Focused then if tvDirectoryHotlist.CanFocus then tvDirectoryHotlist.SetFocus; if not lbleditHotDirName.Focused then if lbleditHotDirName.CanFocus then lbleditHotDirName.SetFocus; end; { TfrmOptionsDirectoryHotlist.actInsertOrAddSomethingExecute } procedure TfrmOptionsDirectoryHotlist.actInsertOrAddSomethingExecute(Sender: TObject); var sPath, initialPath, stempo: string; AddOrInsertDispatcher, Dispatcher, Index: integer; MaybeNodeAfterAddition: TTreeNode = nil; NodeAfterAddition: TTreeNode = nil; SelectedOrActiveDirectories: TFiles; begin Dispatcher := (TComponent(Sender).tag and $0F); AddOrInsertDispatcher := ((TComponent(Sender).tag and $F0) shr 4) + 1; sPath := ''; case Dispatcher of 1: //Directory I will browse to begin initialPath := ''; if (tvDirectoryHotlist.Items.Count > 0) then begin if THotDir(tvDirectoryHotlist.Selected.Data).Dispatcher = hd_CHANGEPATH then initialPath := mbExpandFileName(THotDir(tvDirectoryHotlist.Selected.Data).HotDirPath); end; if initialPath = '' then initialPath := frmMain.ActiveFrame.CurrentPath; if SelectDirectory(rsSelectDir, initialPath, sPath, False) then begin NodeAfterAddition := ActualAddDirectories(hd_CHANGEPATH, GetLastDir(sPath), sPath, '', AddOrInsertDispatcher); end; end; 2: //Directory I will type begin if cbAddTarget.Checked then sTempo := rsMsgHotDirTarget else sTempo := ''; NodeAfterAddition := ActualAddDirectories(hd_CHANGEPATH, rsMsgHotDirName, rsMsgHotDirPath, sTempo, AddOrInsertDispatcher); end; 3: //Directory of the active frame begin NodeAfterAddition := ActualAddDirectories(hd_CHANGEPATH, GetLastDir(frmMain.ActiveFrame.CurrentLocation), frmMain.ActiveFrame.CurrentLocation, '', AddOrInsertDispatcher); end; 4: //Directory of the active AND inactive frames begin NodeAfterAddition := ActualAddDirectories(hd_CHANGEPATH, GetLastDir(frmMain.ActiveFrame.CurrentLocation), frmMain.ActiveFrame.CurrentLocation, frmMain.NotActiveFrame.CurrentLocation, AddOrInsertDispatcher); end; 5: //Separator begin NodeAfterAddition := ActualAddDirectories(hd_SEPARATOR, HOTLIST_SEPARATORSTRING, '', '', AddOrInsertDispatcher); end; 6: //SubMenu, a new branch begin NodeAfterAddition := ActualAddDirectories(hd_STARTMENU, rsMsgHotDirSubMenuName, '', '', AddOrInsertDispatcher); tvDirectoryHotlist.ClearSelection(True); NodeAfterAddition.Selected := True; ActualAddDirectories(hd_CHANGEPATH, rsMsgHotDirName, rsMsgHotDirPath, sTempo, 3); NodeAfterAddition.Expand(False); tvDirectoryHotlist.SetFocus; //The fact to set momentary the focus here, even if we will lose it later on in the function is good anyway. Why? Because when focus will be given to the TLabeledEdit later, the whole content will be selected at that moment instead of just having the cursor flashing on start. That's good because 99.9% of the time, we'll need to rename the submenu anyway. end; 7: //Copy of entry begin NodeAfterAddition := ActualAddDirectories(THotDir(tvDirectoryHotlist.Selected.Data).Dispatcher, THotDir(tvDirectoryHotlist.Selected.Data).HotDirName, THotDir(tvDirectoryHotlist.Selected.Data).HotDirPath, THotDir(tvDirectoryHotlist.Selected.Data).HotDirTarget, AddOrInsertDispatcher); end; 8: //A command begin NodeAfterAddition := ActualAddDirectories(hd_COMMAND, rsMsgHotDirCommandName, rsMsgHotDirCommandSample, '', AddOrInsertDispatcher); end; 9: //Current selected directories of active frame begin SelectedOrActiveDirectories := frmMain.ActiveFrame.CloneSelectedOrActiveDirectories; try if SelectedOrActiveDirectories.Count > 0 then begin if AddOrInsertDispatcher = 1 then begin //When we INSERT, which mean BEFORE the selection, let's do it this way so last insert will be just above the previous selection AND ready to edit for Index := 0 to pred(SelectedOrActiveDirectories.Count) do begin MaybeNodeAfterAddition := ActualAddDirectories(hd_CHANGEPATH, GetLastDir(ExcludeTrailingPathDelimiter(SelectedOrActiveDirectories[Index].FullPath)), ExcludeTrailingPathDelimiter(SelectedOrActiveDirectories[Index].FullPath), '', AddOrInsertDispatcher); if NodeAfterAddition = nil then NodeAfterAddition := MaybeNodeAfterAddition; end; end else begin //When we ADD, which mean AFTER the selection, let's do it this way so last addition will be just below the previous selection AND will be the first one that selected in active frame for Index := pred(SelectedOrActiveDirectories.Count) downto 0 do begin NodeAfterAddition := ActualAddDirectories(hd_CHANGEPATH, GetLastDir(ExcludeTrailingPathDelimiter(SelectedOrActiveDirectories[Index].FullPath)), ExcludeTrailingPathDelimiter(SelectedOrActiveDirectories[Index].FullPath), '', AddOrInsertDispatcher); end; end; end; finally FreeAndNil(SelectedOrActiveDirectories); end; end; end; if NodeAfterAddition <> nil then begin tvDirectoryHotlist.ClearSelection(True); tvDirectoryHotlist.Select(NodeAfterAddition); if lbleditHotDirName.CanFocus then lbleditHotDirName.SetFocus; end; end; { TfrmOptionsDirectoryHotlist.actDeleteSomethingExecute } procedure TfrmOptionsDirectoryHotlist.actDeleteSomethingExecute(Sender: TObject); var DeleteDispatcher: integer; FlagQuitDeleting: boolean; Answer: TMyMsgResult; NodeAfterDeletion: TTreeNode = nil; isTreeHadFocus: boolean = False; procedure DeleteSelectionAndSetNodeAfterDeletion; begin if tvDirectoryHotList.Selections[0].GetNextSibling <> nil then NodeAfterDeletion := tvDirectoryHotList.Selections[0].GetNextSibling else if tvDirectoryHotList.Selections[0].GetPrevSibling <> nil then NodeAfterDeletion := tvDirectoryHotList.Selections[0].GetPrevSibling else if tvDirectoryHotList.Selections[0].Parent <> nil then NodeAfterDeletion := tvDirectoryHotList.Selections[0].Parent else NodeAfterDeletion := nil; tvDirectoryHotList.Selections[0].Delete; ClearCutAndPasteList; end; begin if tvDirectoryHotlist.SelectionCount > 0 then begin isTreeHadFocus := tvDirectoryHotlist.Focused; tvDirectoryHotlist.Enabled := False; try with Sender as TComponent do DeleteDispatcher := tag; FlagQuitDeleting := False; //It's funny but as long we have something selected, we delete it and it will be index 0 since when //deleting something, the "Selections" array is updated! while (tvDirectoryHotList.SelectionCount > 0) and (not FlagQuitDeleting) do begin if tvDirectoryHotList.Selections[0].GetFirstChild = nil then begin DeleteSelectionAndSetNodeAfterDeletion; end else begin case DeleteDispatcher of 1: Answer := MsgBox(Format(rsMsgHotDirWhatToDelete, [tvDirectoryHotList.Selections[0].Text]), [msmbAll, msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); 2: Answer := mmrNo; 3: Answer := mmrYes; else Answer := mmrCancel; //Should not happen, but just in case end; case Answer of mmrAll: begin DeleteDispatcher := 3; DeleteSelectionAndSetNodeAfterDeletion; end; mmrYes: DeleteSelectionAndSetNodeAfterDeletion; mmrNo: begin NodeAfterDeletion := tvDirectoryHotList.Selections[0].GetFirstChild; repeat tvDirectoryHotList.Selections[0].GetFirstChild.MoveTo(tvDirectoryHotList.Selections[0].GetFirstChild.Parent, naInsert); until tvDirectoryHotList.Selections[0].GetFirstChild = nil; tvDirectoryHotList.Selections[0].Delete; ClearCutAndPasteList; end; else FlagQuitDeleting := True; end; end; end; if (NodeAfterDeletion = nil) and (FlagQuitDeleting = False) and (tvDirectoryHotList.Items.Count > 0) then NodeAfterDeletion := tvDirectoryHotList.Items.Item[0]; if (NodeAfterDeletion <> nil) and (FlagQuitDeleting = False) then NodeAfterDeletion.Selected := True; finally tvDirectoryHotlist.Enabled := True; if isTreeHadFocus and tvDirectoryHotlist.CanFocus then tvDirectoryHotlist.SetFocus; end; end; end; { TfrmOptionsDirectoryHotlist.actDeleteAllExecute } procedure TfrmOptionsDirectoryHotlist.actDeleteAllExecute(Sender: TObject); begin if MsgBox(rsMsgHotDirDeleteAllEntries, [msmbYes, msmbNo], msmbNo, msmbNo) = mmrYes then begin tvDirectoryHotlist.Items.Clear; lbleditHotDirName.Text := ''; lbleditHotDirPath.Text := ''; lbleditHotDirTarget.Text := ''; ClearCutAndPasteList; end; end; { TfrmOptionsDirectoryHotlist.actMoveToPreviousExecute } procedure TfrmOptionsDirectoryHotlist.actMoveToPreviousExecute(Sender: TObject); var AOriginalSelectedNode, AAboveNode: TTreeNode; begin AOriginalSelectedNode := tvDirectoryHotlist.Selected; if AOriginalSelectedNode <> nil then begin tvDirectoryHotlist.MoveToPrevNode(False); AAboveNode := tvDirectoryHotlist.Selected; if AOriginalSelectedNode <> AAboveNode then begin AOriginalSelectedNode.MoveTo(AAboveNode, naInsert); tvDirectoryHotlist.Select(AOriginalSelectedNode); end; end; end; { TfrmOptionsDirectoryHotlist.actMoveToNextExecute } procedure TfrmOptionsDirectoryHotlist.actMoveToNextExecute(Sender: TObject); var AOriginalSelectedNode, ABelowNode: TTreeNode; begin AOriginalSelectedNode := tvDirectoryHotlist.Selected; if AOriginalSelectedNode <> nil then begin tvDirectoryHotlist.MoveToNextNode(False); ABelowNode := tvDirectoryHotlist.Selected; if AOriginalSelectedNode <> ABelowNode then begin AOriginalSelectedNode.MoveTo(ABelowNode, naInsertBehind); tvDirectoryHotlist.Select(AOriginalSelectedNode); end; end; end; { TfrmOptionsDirectoryHotlist.actCutExecute } procedure TfrmOptionsDirectoryHotlist.actCutExecute(Sender: TObject); var Index: integer; begin if tvDirectoryHotlist.SelectionCount > 0 then begin for Index := 0 to pred(tvDirectoryHotlist.SelectionCount) do begin CutAndPasteIndexList.Add(IntToStr(tvDirectoryHotlist.Selections[Index].AbsoluteIndex)); end; actPaste.Enabled := True; end; end; { TfrmOptionsDirectoryHotlist.actPasteExecute } procedure TfrmOptionsDirectoryHotlist.actPasteExecute(Sender: TObject); var DestinationNode: TTreeNode; Index: longint; begin if CutAndPasteIndexList.Count > 0 then begin DestinationNode := tvDirectoryHotlist.Selected; if DestinationNode <> nil then begin tvDirectoryHotlist.ClearSelection(False); for Index := 0 to pred(CutAndPasteIndexList.Count) do begin tvDirectoryHotlist.Items.Item[StrToInt(CutAndPasteIndexList.Strings[Index])].Selected := True; end; for Index := 0 to pred(tvDirectoryHotlist.SelectionCount) do begin tvDirectoryHotlist.Selections[Index].MoveTo(DestinationNode, naInsert); end; ClearCutAndPasteList; end; end; end; { TfrmOptionsDirectoryHotlist.actSearchAndReplaceExecute } procedure TfrmOptionsDirectoryHotlist.actSearchAndReplaceExecute(Sender: TObject); var NbOfReplacement: longint; sSearchText, sReplaceText: string; ReplaceFlags: TReplaceFlags; function ReplaceIfNecessary(sWorkingText: string): string; begin Result := UTF8StringReplace(sWorkingText, sSearchText, sReplaceText, ReplaceFlags); if Result <> sWorkingText then Inc(NbOfReplacement); end; var Index, ActionDispatcher: integer; EditSearchOptionToOffer: TEditSearchDialogOption; EditSearchOptionReturned: TEditSearchDialogOption = []; CaseSensitive: array[Boolean] of TEditSearchDialogOption = ([eswoCaseSensitiveUnchecked], [eswoCaseSensitiveChecked]); begin with Sender as TComponent do ActionDispatcher := tag; if ((ActionDispatcher and $01) <> 0) and (lbleditHotDirPath.Text <> '') then sSearchText := lbleditHotDirPath.Text else if ((ActionDispatcher and $02) <> 0) and (lbleditHotDirTarget.Text <> '') then sSearchText := lbleditHotDirTarget.Text else sSearchText := ''; sReplaceText := sSearchText; EditSearchOptionToOffer := CaseSensitive[FileNameCaseSensitive]; if GetSimpleSearchAndReplaceString(self, EditSearchOptionToOffer, sSearchText, sReplaceText, EditSearchOptionReturned, glsSearchPathHistory, glsReplacePathHistory) then begin NbOfReplacement := 0; ReplaceFlags := [rfReplaceAll]; if eswoCaseSensitiveUnchecked in EditSearchOptionReturned then ReplaceFlags := ReplaceFlags + [rfIgnoreCase]; for Index := 0 to pred(gDirectoryHotlist.Count) do begin case DirectoryHotlistTemp.HotDir[Index].Dispatcher of hd_CHANGEPATH: begin if (ActionDispatcher and $01) <> 0 then DirectoryHotlistTemp.HotDir[Index].HotDirPath := ReplaceIfNecessary(DirectoryHotlistTemp.HotDir[Index].HotDirPath); if (ActionDispatcher and $02) <> 0 then DirectoryHotlistTemp.HotDir[Index].HotDirTarget := ReplaceIfNecessary(DirectoryHotlistTemp.HotDir[Index].HotDirTarget); end; end; end; if NbOfReplacement = 0 then begin msgOk(rsZeroReplacement); end else begin tvDirectoryHotlistSelectionChanged(tvDirectoryHotlist); msgOk(format(rsXReplacements, [NbOfReplacement])); end; end; end; { TfrmOptionsDirectoryHotlist.actTweakPathExecute } procedure TfrmOptionsDirectoryHotlist.actTweakPathExecute(Sender: TObject); procedure ShowPopupMenu(APopupMenu: TPopupMenu; ASpeedButton: TSpeedButton); var ptPopupLocation: TPoint; begin APopupMenu.tag := ASpeedButton.tag; ptPopupLocation := ASpeedButton.ClientToScreen(Point(ASpeedButton.Width - 10, ASpeedButton.Height - 10)); Mouse.CursorPos := Point(ptPopupLocation.x + 8, ptPopupLocation.y + 8); APopupMenu.PopUp(ptPopupLocation.x, ptPopupLocation.y); end; begin with Sender as TComponent do begin case tag of 2: begin lbleditHotDirPath.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(lbleditHotDirPath, pfPATH); ShowPopupMenu(pmPathHelper,btnRelativePath); end; 3: begin lbleditHotDirTarget.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(lbleditHotDirTarget, pfPATH); ShowPopupMenu(pmPathHelper,btnRelativeTarget); end; end; end; end; { TfrmOptionsDirectoryHotlist.actFocusTreeWindowExecute } procedure TfrmOptionsDirectoryHotlist.actFocusTreeWindowExecute(Sender: TObject); begin if tvDirectoryHotlist.CanSetFocus then tvDirectoryHotlist.SetFocus; end; { TfrmOptionsDirectoryHotlist.actGotoFirstItemExecute } procedure TfrmOptionsDirectoryHotlist.actGotoFirstItemExecute(Sender: TObject); begin if tvDirectoryHotlist.Items.Count > 0 then tvDirectoryHotlist.Select(tvDirectoryHotlist.Items[0]); end; { TfrmOptionsDirectoryHotlist.actGoToPreviousItemExecute } procedure TfrmOptionsDirectoryHotlist.actGoToPreviousItemExecute(Sender: TObject); begin tvDirectoryHotlist.MoveToPrevNode(False); end; { TfrmOptionsDirectoryHotlist.actGoToNextItemExecute } procedure TfrmOptionsDirectoryHotlist.actGoToNextItemExecute(Sender: TObject); begin tvDirectoryHotlist.MoveToNextNode(False); end; { TfrmOptionsDirectoryHotlist.actGotoLastItemExecute } // Go to the last item that is displayable *without* opening a branche that is not already open. procedure TfrmOptionsDirectoryHotlist.actGotoLastItemExecute(Sender: TObject); var SeekingNode: TTreeNode; LastGoodNode: TTreeNode = nil; begin if tvDirectoryHotlist.Items.Count > 0 then begin SeekingNode := tvDirectoryHotlist.Items[0]; while SeekingNode <> nil do begin SeekingNode := SeekingNode.GetNextSibling; if SeekingNode <> nil then begin LastGoodNode := SeekingNode; end else begin if LastGoodNode.Expanded then SeekingNode := LastGoodNode.Items[0]; end; end; end; if LastGoodNode <> nil then tvDirectoryHotlist.Select(LastGoodNode); end; { TfrmOptionsDirectoryHotlist.actExpandItemExecute } procedure TfrmOptionsDirectoryHotlist.actExpandItemExecute(Sender: TObject); begin if tvDirectoryHotlist.Selected <> nil then if tvDirectoryHotlist.Selected.TreeNodes.Count > 0 then tvDirectoryHotlist.Selected.Expand(False); end; { TfrmOptionsDirectoryHotlist.actOpenAllBranchesExecute } procedure TfrmOptionsDirectoryHotlist.actOpenAllBranchesExecute(Sender: TObject); begin tvDirectoryHotlist.FullExpand; if tvDirectoryHotlist.Selected <> nil then tvDirectoryHotlist.Selected.MakeVisible; end; { TfrmOptionsDirectoryHotlist.actCollapseItemExecute } procedure TfrmOptionsDirectoryHotlist.actCollapseItemExecute(Sender: TObject); begin if tvDirectoryHotlist.Selected <> nil then if tvDirectoryHotlist.Selected.TreeNodes.Count > 0 then tvDirectoryHotlist.Selected.Collapse(True); end; { TfrmOptionsDirectoryHotlist.actCollapseAllExecute } procedure TfrmOptionsDirectoryHotlist.actCollapseAllExecute(Sender: TObject); begin tvDirectoryHotlist.FullCollapse; if tvDirectoryHotlist.Selected <> nil then tvDirectoryHotlist.Selected.MakeVisible; end; { TfrmOptionsDirectoryHotlist.miSortDirectoryHotlistClick } //The trick here is that a "group number" identical has been assigned to the sibling between separator and then we sort //Teh sort has been arrange in such way that item from different group won't be mixed. procedure TfrmOptionsDirectoryHotlist.miSortDirectoryHotlistClick(Sender: TObject); var Dispatcher, Index: integer; StartingNode: TTreeNode; FlagKeepGoingBack: boolean; begin with Sender as TComponent do Dispatcher := tag; for Index := 0 to pred(tvDirectoryHotlist.Items.Count) do THotDir(tvDirectoryHotlist.Items.Item[Index].Data).GroupNumber := 0; GlobalGroupNumber := 0; if tvDirectoryHotlist.SelectionCount > 0 then begin case Dispatcher of 1, 2: //current group only or current level begin for Index := 0 to pred(tvDirectoryHotlist.SelectionCount) do begin if THotDir(tvDirectoryHotlist.Selections[Index].Data).GroupNumber = 0 then begin StartingNode := tvDirectoryHotlist.Selections[Index]; case Dispatcher of 1: //We just need to make sure we start from first item of current level so we search the first one OR a separator begin FlagKeepGoingBack := True; while FlagKeepGoingBack do begin if StartingNode.GetPrevSibling <> nil then begin if THotDir(StartingNode.GetPrevSibling.Data).Dispatcher <> hd_SEPARATOR then StartingNode := StartingNode.GetPrevSibling else FlagKeepGoingBack := False; end else begin FlagKeepGoingBack := False; end; end; end; 2: //We need to make sure we start from the first itm of current level begin while StartingNode.GetPrevSibling <> nil do StartingNode := StartingNode.GetPrevSibling; end; end; RecursiveSetGroupNumbers(StartingNode, GetNextGroupNumber, False, (Dispatcher = 1)); end; end; end; 3, 4: //submenu only, recusive or not begin for Index := 0 to pred(tvDirectoryHotlist.SelectionCount) do begin StartingNode := tvDirectoryHotlist.Selections[Index].GetFirstChild; if StartingNode <> nil then begin if THotDir(StartingNode.Data).GroupNumber = 0 then begin RecursiveSetGroupNumbers(StartingNode, GetNextGroupNumber, (Dispatcher = 4), False); end; end; end; end; end; end; if Dispatcher = 5 then //We start from the very first one, the top one. begin StartingNode := tvDirectoryHotlist.Items.Item[0]; RecursiveSetGroupNumbers(StartingNode, GetNextGroupNumber, True, False); end; //... and the finale! tvDirectoryHotlist.CustomSort(@MySortViaGroup); ClearCutAndPasteList; end; { TfrmOptionsDirectoryHotlist.miTestResultingHotlistMenuClick } procedure TfrmOptionsDirectoryHotlist.miTestResultingHotlistMenuClick(Sender: TObject); var p: TPoint; begin DirectoryHotlistTemp.RefreshFromTTreeView(tvDirectoryHotlist); //We need to refresh our temporary Directory Hotlist in case user played with the tree and added/removed/moved item(s). DirectoryHotlistTemp.PopulateMenuWithHotDir(pmHotDirTestMenu, @miShowWhereItWouldGo, nil, mpJUSTHOTDIRS, 0); p := tvDirectoryHotlist.ClientToScreen(Classes.Point(0, 0)); p.x := p.x + tvDirectoryHotlist.Width; pmHotDirTestMenu.PopUp(p.X, p.Y); end; { TfrmOptionsDirectoryHotlist.miDetectIfPathExistClick } procedure TfrmOptionsDirectoryHotlist.miDetectIfPathExistClick(Sender: TObject); var iNodeIndex: integer; NodeToFocus: TTreeNode = nil; OriginalNode: TTreeNode; begin OriginalNode := tvDirectoryHotlist.Selected; lbleditHotDirName.Text := ''; lbleditHotDirName.Enabled := False; lbleditHotDirPath.Visible := False; cbSortHotDirPath.Visible := False; cbSortHotDirTarget.Visible := False; lbleditHotDirTarget.Visible := False; btnRelativePath.Visible := False; btnRelativeTarget.Visible := False; Application.ProcessMessages; try RefreshExistingProperty(TComponent(Sender).tag); finally lbleditHotDirName.Enabled := True; iNodeIndex := 0; while (iNodeIndex < tvDirectoryHotlist.Items.Count) and (NodeToFocus = nil) do if (THotDir(tvDirectoryHotlist.Items[iNodeIndex].Data).HotDirExisting = DirNotExist) and (tvDirectoryHotlist.Items[iNodeIndex].Count = 0) then NodeToFocus := tvDirectoryHotlist.Items[iNodeIndex] else Inc(iNodeIndex); if NodeToFocus <> nil then tvDirectoryHotlist.Select(NodeToFocus) else if OriginalNode <> nil then tvDirectoryHotlist.Select(OriginalNode); if lbleditHotDirName.CanSetFocus then lbleditHotDirName.SetFocus; end; end; { TfrmOptionsDirectoryHotlist.miExportToAnythingClick } //We could export to a few ways: // 0x00:To TC and keeping existing hotlist // 0x80:To TC after erasing existing Directory Hotlist // 0x01:To a Directory Hotlist file (.hotlist) // 0x02:To a backup file (all of them, to a "BACKUP_YYYY-MM-DD-HH-MM-SS.hotlist" file) // With the backup, we don't ask what to output, we output everything! procedure TfrmOptionsDirectoryHotlist.miExportToAnythingClick(Sender: TObject); var FlagKeepGoing: boolean = False; ActionDispatcher: integer; BackupPath: string; WorkingDirectoryHotlist: TDirectoryHotlist; Answer: integer; begin WorkingDirectoryHotlist := TDirectoryHotlist.Create; try with Sender as TComponent do ActionDispatcher := tag; case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI: begin if areWeInSituationToPlayWithTCFiles then begin OpenDialog.Filename := gTotalCommanderConfigFilename; FlagKeepGoing := True; end; end; {$ENDIF} ACTION_WITH_HOTLISTFILE: begin SaveDialog.DefaultExt := '*.hotlist'; SaveDialog.FilterIndex := 1; SaveDialog.Title := rsMsgHotDirWhereToSave; SaveDialog.FileName := 'New Directory Hotlist'; FlagKeepGoing := SaveDialog.Execute; end; ACTION_WITH_BACKUP: begin BackupPath := IncludeTrailingPathDelimiter(mbExpandFileName(EnvVarConfigPath)) + 'Backup'; if mbForceDirectory(BackupPath) then begin SaveDialog.Filename := BackupPath + DirectorySeparator + 'Backup_' + GetDateTimeInStrEZSortable(now) + '.hotlist'; if gDirectoryHotlist.ExportDoubleCommander(SaveDialog.FileName, True) then msgOK(Format(rsMsgHotDirTotalBackuped, [gDirectoryHotlist.Count, SaveDialog.Filename])) else msgError(rsMsgHotDirErrorBackuping); end; Exit; end; end; //User select what to export if FlagKeepGoing then begin with Tfrmhotdirexportimport.Create(Application) do begin try CopyTTreeViewToAnother(tvDirectoryHotlist, tvDirectoryHotlistToExportImport); btnSelectAll.Caption := rsMsgHotDirExportall; btnSelectionDone.Caption := rsMsgHotDirExportSel; Caption := rsMsgHotDirExportHotlist; Answer := ShowModal; if ((Answer = mrOk) and (tvDirectoryHotlistToExportImport.SelectionCount > 0)) or ((Answer = mrAll) and (tvDirectoryHotlistToExportImport.Items.Count > 0)) then begin WorkingDirectoryHotlist.AddFromAnotherTTreeViewTheSelected(nil, tvDirectoryHotlistToExportImport, (Answer = mrAll)); if WorkingDirectoryHotlist.Count > 0 then begin case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI: if WorkingDirectoryHotlist.ExportTotalCommander(OpenDialog.FileName, ((ActionDispatcher and MASK_FLUSHORNOT_EXISTING) = ACTION_ERASEEXISTING)) then msgOK(rsMsgHotDirTotalExported + IntToStr(WorkingDirectoryHotlist.Count)) else msgError(rsMsgHotDirErrorExporting); {$ENDIF} ACTION_WITH_HOTLISTFILE: if WorkingDirectoryHotlist.ExportDoubleCommander(SaveDialog.FileName, True) then msgOK(rsMsgHotDirTotalExported + IntToStr(WorkingDirectoryHotlist.Count)) else msgError(rsMsgHotDirErrorExporting); end; end else begin msgOK(rsMsgHotDirNothingToExport); end; end; //If user confirmed OK and have selected something... finally Free; end; end; end; finally WorkingDirectoryHotlist.Free; end; end; { TfrmOptionsDirectoryHotlist.miImportFromAnythingClick } //We could import from a few ways: // 0x00:From TC // 0x01:From a Directory Hotlist file (.hotlist) // 0x02:From a backup file (all of them, to a "BACKUP_YYYY-MM-DD-HH-MM-SS.hotlist" file) // With the backup, we erase existing ones procedure TfrmOptionsDirectoryHotlist.miImportFromAnythingClick(Sender: TObject); var WorkingDirectoryList: TDirectoryHotlist; Answer, NbOfAdditional, ActionDispatcher: longint; FlagKeepGoing: boolean = False; BackupPath: string; begin with Sender as TComponent do ActionDispatcher := tag; case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of ACTION_WITH_HOTLISTFILE: begin OpenDialog.DefaultExt := '*.hotlist'; OpenDialog.FilterIndex := 1; OpenDialog.Title := rsMsgHotDirLocateHotlistFile; FlagKeepGoing := OpenDialog.Execute; end; ACTION_WITH_BACKUP: begin BackupPath := IncludeTrailingPathDelimiter(mbExpandFileName(EnvVarConfigPath)) + 'Backup'; if mbForceDirectory(BackupPath) then begin OpenDialog.DefaultExt := '*.hotlist'; OpenDialog.FilterIndex := 1; OpenDialog.Title := rsMsgHotDirRestoreWhat; OpenDialog.InitialDir := ExcludeTrailingPathDelimiter(BackupPath); FlagKeepGoing := OpenDialog.Execute; end; end; {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI: begin if areWeInSituationToPlayWithTCFiles then begin OpenDialog.FileName := gTotalCommanderConfigFilename; FlagKeepGoing := True; end; end; {$ENDIF} end; if FlagKeepGoing then begin WorkingDirectoryList := TDirectoryHotlist.Create; try case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI: WorkingDirectoryList.ImportTotalCommander(string(OpenDialog.Filename)); {$ENDIF} ACTION_WITH_HOTLISTFILE: WorkingDirectoryList.ImportDoubleCommander(string(OpenDialog.Filename)); ACTION_WITH_BACKUP: WorkingDirectoryList.ImportDoubleCommander(string(OpenDialog.Filename)); end; with Tfrmhotdirexportimport.Create(Application) do begin try WorkingDirectoryList.LoadTTreeView(tvDirectoryHotlistToExportImport, -1); btnSelectAll.Caption := rsMsgHotDirImportall; btnSelectionDone.Caption := rsMsgHotDirImportSel; Caption := rsMsgHotDirImportHotlist; case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of ACTION_WITH_HOTLISTFILE: Answer := ShowModal; ACTION_WITH_BACKUP: begin if MsgBox(rsHotDirWarningAbortRestoreBackup, [msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel) = mmrYes then Answer := mrAll else Exit; end; ACTION_WITH_WINCMDINI: Answer := ShowModal; end; if ((Answer = mrOk) and (tvDirectoryHotlistToExportImport.SelectionCount > 0)) or ((Answer = mrAll) and (tvDirectoryHotlistToExportImport.Items.Count > 0)) then begin ClearCutAndPasteList; if ((ActionDispatcher and MASK_ACTION_WITH_WHAT) = ACTION_WITH_BACKUP) and (Answer = mrAll) then begin DirectoryHotlistTemp.Clear; tvDirectoryHotlist.Items.Clear; end; NbOfAdditional := DirectoryHotlistTemp.AddFromAnotherTTreeViewTheSelected(tvDirectoryHotlist, tvDirectoryHotlistToExportImport, (Answer = mrAll)); if NbOfAdditional > 0 then begin //DirectoryHotlistTemp.LoadTTreeView(tvDirectoryHotlist,-1); tvDirectoryHotlist.ClearSelection(True); if tvDirectoryHotlist.Items.Count > 0 then tvDirectoryHotlist.Select(tvDirectoryHotlist.Items[pred(tvDirectoryHotlist.Items.Count)]); if lbleditHotDirName.CanFocus then lbleditHotDirName.SetFocus; msgOK(format(rsMsgHotDirNbNewEntries, [NbOfAdditional])); end; end; //If user confirmed OK and have selected something... finally Free; end; end; finally WorkingDirectoryList.Free; end; end; end; { TfrmOptionsDirectoryHotlist.miGotoConfigureTCInfoClick } procedure TfrmOptionsDirectoryHotlist.miGotoConfigureTCInfoClick(Sender: TObject); begin BringUsToTCConfigurationPage; end; { TfrmOptionsDirectoryHotlist.btnActionClick } procedure TfrmOptionsDirectoryHotlist.btnActionClick(Sender: TObject); begin case TComponent(Sender).tag of 1: pmInsertDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 2: pmAddDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 3: pmDeleteDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 4: pmExportDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 5: pmImportDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 6: pmBackupDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 7: pmMiscellaneousDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 8: pmSortDirectoryHotlist.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; end; { TfrmOptionsDirectoryHotlist.cbFullExpandTreeChange } procedure TfrmOptionsDirectoryHotlist.cbFullExpandTreeChange(Sender: TObject); begin if cbFullExpandTree.Checked then tvDirectoryHotlist.FullExpand else tvDirectoryHotlist.FullCollapse; end; procedure TfrmOptionsDirectoryHotlist.lbleditHotDirNameChange(Sender: TObject); begin //If nothing currently selected, no need to update anything here. if (tvDirectoryHotlist.Selected <> nil) and (TLabeledEdit(Sender).Enabled) then begin case TLabeledEdit(Sender).tag of 1: //Hot dir name begin try //Make sure we actually have something, not an attempt of submenu or end of menu if (TLabeledEdit(Sender).Text <> '') and (TLabeledEdit(Sender).Text[1] <> '-') and (THotDir(tvDirectoryHotlist.Selected.Data).Dispatcher <> hd_SEPARATOR) then begin //Make sure it's different than what it was if THotDir(tvDirectoryHotlist.Selected.Data).HotDirName <> TLabeledEdit(Sender).Text then begin THotDir(tvDirectoryHotlist.Selected.Data).HotDirName := TLabeledEdit(Sender).Text; tvDirectoryHotlist.Selected.Text := TLabeledEdit(Sender).Text; end; end; except //Just in case the "Text" is empty to don't show error with Text[1] check. end; end; 2: //Hot dir path begin try //if (TLabeledEdit(Sender).Text <> '') and (THotDir(tvDirectoryHotlist.Selected.Data).Dispatcher = hd_CHANGEPATH) then // TLabeledEdit(Sender).Text := IncludeTrailingPathDelimiter(TLabeledEdit(Sender).Text); //Make sure it's different than what it was if THotDir(tvDirectoryHotlist.Selected.Data).HotDirPath <> TLabeledEdit(Sender).Text then begin THotDir(tvDirectoryHotlist.Selected.Data).HotDirPath := TLabeledEdit(Sender).Text; THotDir(tvDirectoryHotlist.Selected.Data).HotDirExisting := DirExistUnknown; end; except //Just in case we have an empty list so "DirectoryHotlistTemp.HotDir[tvDirectoryHotlist.Selected.ImageIndex]" will not caused an error (since ItemIndex=-1 at this moment); end; end; 3: //Hot dir target begin try //if (TLabeledEdit(Sender).Text <> '') and (THotDir(tvDirectoryHotlist.Selected.Data).Dispatcher =hd_CHANGEPATH) then // TLabeledEdit(Sender).Text := IncludeTrailingPathDelimiter(TLabeledEdit(Sender).Text); //Make sure it's different than what it was if THotDir(tvDirectoryHotlist.Selected.Data).HotDirTarget <> TLabeledEdit(Sender).Text then begin THotDir(tvDirectoryHotlist.Selected.Data).HotDirTarget := TLabeledEdit(Sender).Text; end; except //Just in case we have an empty list so "DirectoryHotlistTemp.HotDir[tvDirectoryHotlist.Selected.ImageIndex]" will not caused an error (since ItemIndex=-1 at this moment); end; end; end; end; end; { TfrmOptionsDirectoryHotlist.anyRelativeAbsolutePathClick } procedure TfrmOptionsDirectoryHotlist.anyRelativeAbsolutePathClick(Sender: TObject); begin if tvDirectoryHotlist.Selected<>nil then //Should not happen, but if it happens, will avoid an error. begin case TComponent(Sender).tag of 2: begin lbleditHotDirPath.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(lbleditHotDirPath, pfPATH); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); if THotDir(tvDirectoryHotlist.Selected.Data).HotDirPath <> lbleditHotDirPath.Text then THotDir(tvDirectoryHotlist.Selected.Data).HotDirPath := lbleditHotDirPath.Text; end; 3: begin lbleditHotDirTarget.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(lbleditHotDirTarget, pfPATH); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); if THotDir(tvDirectoryHotlist.Selected.Data).HotDirTarget <> lbleditHotDirTarget.Text then THotDir(tvDirectoryHotlist.Selected.Data).HotDirTarget := lbleditHotDirTarget.Text; end; end; end; end; { TfrmOptionsDirectoryHotlist.cbSortHotDirPathChange } procedure TfrmOptionsDirectoryHotlist.cbSortHotDirPathChange(Sender: TObject); begin if Assigned(tvDirectoryHotlist.Selected) then THotDir(tvDirectoryHotlist.Selected.Data).HotDirPathSort := cbSortHotDirPath.ItemIndex; end; { TfrmOptionsDirectoryHotlist.cbSortHotDirTargetChange } procedure TfrmOptionsDirectoryHotlist.cbSortHotDirTargetChange(Sender: TObject); begin if Assigned(tvDirectoryHotlist.Selected) then THotDir(tvDirectoryHotlist.Selected.Data).HotDirTargetSort := cbSortHotDirTarget.ItemIndex; end; { TfrmOptionsDirectoryHotlist.pnlButtonsResize } procedure TfrmOptionsDirectoryHotlist.pnlButtonsResize(Sender: TObject); var I: integer; begin for I := 0 to pnlButtons.ControlCount - 1 do begin pnlButtons.Controls[I].Width := pnlButtons.ClientWidth div 2 - 3; end; end; { TfrmOptionsDirectoryHotlist.tvDirectoryHotlistDragDrop } procedure TfrmOptionsDirectoryHotlist.tvDirectoryHotlistDragDrop(Sender, Source: TObject; X, Y: integer); var Index: longint; ANode: TTreeNode; DestinationNode: TTreeNode; begin DestinationNode := tvDirectoryHotlist.GetNodeAt(X, Y); if Assigned(DestinationNode) and (tvDirectoryHotlist.SelectionCount > 0) then begin tvDirectoryHotlist.BeginUpdate; try ANode := tvDirectoryHotlist.Selected; //If we move toward the end, we place the moved item *after* the destination. //If we move toward the beginning, we place the moved item *before* the destination. if tvDirectoryHotlist.Selections[pred(tvDirectoryHotlist.SelectionCount)].AbsoluteIndex > DestinationNode.AbsoluteIndex then begin for Index := 0 to pred(tvDirectoryHotlist.SelectionCount) do begin tvDirectoryHotlist.Selections[Index].MoveTo(DestinationNode, naInsert); end; end else begin for Index := 0 to pred(tvDirectoryHotlist.SelectionCount) do begin tvDirectoryHotlist.Selections[Index].MoveTo(DestinationNode, naInsertBehind); end; end; tvDirectoryHotlist.Selected := ANode; finally tvDirectoryHotlist.EndUpdate; end; ClearCutAndPasteList; end; actPaste.Enabled := False; end; { TfrmOptionsDirectoryHotlist.tvDirectoryHotlistDragOver } procedure TfrmOptionsDirectoryHotlist.tvDirectoryHotlistDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin Accept := True; end; { TfrmOptionsDirectoryHotlist.tvDirectoryHotlistEnter } // To help to catch eye's attention, let's change color of selection when tree get/lose the focus procedure TfrmOptionsDirectoryHotlist.tvDirectoryHotlistEnter(Sender: TObject); begin tvDirectoryHotlist.SelectionColor := clHighlight; end; { TfrmOptionsDirectoryHotlist.tvDirectoryHotlistExit } // To help to catch eye's attention, let's change color of selection when tree get/lose the focus procedure TfrmOptionsDirectoryHotlist.tvDirectoryHotlistExit(Sender: TObject); begin tvDirectoryHotlist.SelectionColor := clBtnShadow; end; { TfrmOptionsDirectoryHotlist.tvDirectoryHotlistSelectionChanged } procedure TfrmOptionsDirectoryHotlist.tvDirectoryHotlistSelectionChanged(Sender: TObject); var WorkingPointer: Pointer; begin if tvDirectoryHotlist.Selected <> nil then begin btnAdd.Enabled := True; btnInsert.Enabled := True; btnMiscellaneous.Enabled := True; WorkingPointer := tvDirectoryHotlist.Selected.Data; case THotDir(WorkingPointer).Dispatcher of hd_NULL: begin end; hd_CHANGEPATH: begin lbleditHotDirName.EditLabel.Caption := rsMsgHotDirSimpleName; lbleditHotDirName.Text := THotDir(WorkingPointer).HotDirName; lbleditHotDirName.ReadOnly := False; lbleditHotDirPath.EditLabel.Caption := rsMsgHotDirJustPath; lbleditHotDirPath.Text := THotDir(WorkingPointer).HotDirPath; //DirectoryHotlistTemp.HotDir[IndexInHotlist].HotDirPath; lbleditHotDirPath.Hint := mbExpandFileName(lbleditHotDirPath.Text); cbSortHotDirPath.ItemIndex := THotDir(WorkingPointer).HotDirPathSort; lbleditHotDirPath.Visible := True; btnRelativePath.Tag := 2; lbleditHotDirTarget.Text := THotDir(WorkingPointer).HotDirTarget; lbleditHotDirTarget.Hint := mbExpandFileName(lbleditHotDirTarget.Text); cbSortHotDirTarget.ItemIndex := THotDir(WorkingPointer).HotDirTargetSort; lbleditHotDirTarget.Visible := True; end; hd_COMMAND: begin lbleditHotDirName.EditLabel.Caption := rsMsgHotDirSimpleName; lbleditHotDirName.Text := THotDir(WorkingPointer).HotDirName; lbleditHotDirName.ReadOnly := False; lbleditHotDirPath.EditLabel.Caption := rsMsgHotDirSimpleCommand; lbleditHotDirPath.Text := THotDir(WorkingPointer).HotDirPath; lbleditHotDirPath.Hint := ''; lbleditHotDirPath.Visible := True; btnRelativePath.Tag := 4; lbleditHotDirTarget.Visible := False; end; hd_SEPARATOR: begin lbleditHotDirName.EditLabel.Caption := ''; lbleditHotDirName.Text := rsMsgHotDirSimpleSeparator; lbleditHotDirName.ReadOnly := True; lbleditHotDirPath.Visible := False; lbleditHotDirTarget.Visible := False; end; hd_STARTMENU: begin lbleditHotDirName.EditLabel.Caption := rsMsgHotDirSimpleMenu; lbleditHotDirName.Text := THotDir(WorkingPointer).HotDirName; lbleditHotDirName.ReadOnly := False; lbleditHotDirPath.Visible := False; lbleditHotDirTarget.Visible := False; end; hd_ENDMENU: begin lbleditHotDirName.EditLabel.Caption := ''; lbleditHotDirName.Text := rsMsgHotDirSimpleEndOfMenu; lbleditHotDirName.ReadOnly := True; lbleditHotDirPath.Visible := False; lbleditHotDirTarget.Visible := False; end; end; //case THotDir(WorkingPointer).Dispatcher of actDeleteSelectedItem.Enabled := not (THotDir(WorkingPointer).Dispatcher = hd_STARTMENU); actDeleteSubMenuKeepElem.Enabled := (THotDir(WorkingPointer).Dispatcher = hd_STARTMENU); actDeleteSubMenuAndElem.Enabled := (THotDir(WorkingPointer).Dispatcher = hd_STARTMENU); actAddCopyOfEntry.Enabled := ((THotDir(WorkingPointer).Dispatcher <> hd_STARTMENU) and (THotDir(WorkingPointer).Dispatcher <> hd_ENDMENU)); actInsertCopyOfEntry.Enabled := actAddCopyOfEntry.Enabled; miSortSingleSubMenu.Enabled := (THotDir(WorkingPointer).Dispatcher = hd_STARTMENU); miSortSubMenuAndSubLevel.Enabled := (THotDir(WorkingPointer).Dispatcher = hd_STARTMENU); actDeleteSelectedItem.Enabled := (THotDir(WorkingPointer).Dispatcher <> hd_ENDMENU); end //if tvDirectoryHotlist.Selected<>nil then else begin btnAdd.Enabled := (tvDirectoryHotlist.Items.Count = 0); btnInsert.Enabled := btnAdd.Enabled; btnMiscellaneous.Enabled := btnAdd.Enabled; lbleditHotDirName.EditLabel.Caption := ''; lbleditHotDirName.Text := ''; lbleditHotDirName.ReadOnly := True; lbleditHotDirName.Text := 'Nothing...'; lbleditHotDirPath.Visible := False; lbleditHotDirTarget.Visible := False; end; btnRelativePath.Visible := lbleditHotDirPath.Visible; cbSortHotDirPath.Visible := lbleditHotDirPath.Visible and (THotDir(WorkingPointer).Dispatcher <> hd_COMMAND); btnRelativeTarget.Visible := lbleditHotDirTarget.Visible; cbSortHotDirTarget.Visible := lbleditHotDirTarget.Visible; if Assigned(TForm(Self.Parent.Parent.Parent).ActiveControl) then begin if TForm(Self.Parent.Parent.Parent).ActiveControl.Name = 'tvTreeView' then if lbleditHotDirName.CanFocus then TForm(Self.Parent.Parent.Parent).ActiveControl := lbleditHotDirName; end; end; { TfrmOptionsDirectoryHotlist.RefreshTreeView } procedure TfrmOptionsDirectoryHotlist.RefreshTreeView(NodeToSelect: TTreeNode); begin if NodeToSelect <> nil then begin tvDirectoryHotlist.ClearSelection(False); NodeToSelect.Selected := True; end else begin tvDirectoryHotlistSelectionChanged(tvDirectoryHotlist); //At least to hide path, target, etc. end; btnExport.Enabled := (tvDirectoryHotlist.Items.Count > 0); miSaveBackupHotlist.Enabled := (tvDirectoryHotlist.Items.Count > 0); end; { TfrmOptionsDirectoryHotlist.PopulatePopupMenuWithCommands } procedure TfrmOptionsDirectoryHotlist.PopulatePopupMenuWithCommands(pmMenuToPopulate: TPopupMenu); var FFormCommands: IFormCommands; LocalDummyComboBox: TComboBox; miMainTree: TMenuItem; IndexCommand: longint; procedure LocalPopulateUntil(ParamMenuItem: TMenuItem; LetterUpTo: char); var LocalMenuItem: TMenuItem; MaybeItemName: string; begin MaybeItemName := '0000'; while (IndexCommand < LocalDummyComboBox.Items.Count) and (MaybeItemName[4] <> LetterUpTo) do begin MaybeItemName := LocalDummyComboBox.Items.Strings[IndexCommand]; if MaybeItemName[4] <> LetterUpTo then begin LocalMenuItem := TMenuItem.Create(ParamMenuItem); LocalMenuItem.Caption := MaybeItemName; LocalMenuItem.OnClick := @miSimplyCopyCaption; ParamMenuItem.Add(LocalMenuItem); Inc(IndexCommand); end; end; end; begin LocalDummyComboBox := TComboBox.Create(Self); try LocalDummyComboBox.Clear; FFormCommands := frmMain as IFormCommands; FFormCommands.GetCommandsList(LocalDummyComboBox.Items); LocalDummyComboBox.Sorted := True; IndexCommand := 0; miMainTree := TMenuItem.Create(pmMenuToPopulate); miMainTree.Caption := 'cm_A..cm_C'; pmMenuToPopulate.Items.Add(miMainTree); LocalPopulateUntil(miMainTree, 'D'); miMainTree := TMenuItem.Create(pmMenuToPopulate); miMainTree.Caption := 'cm_D..cm_L'; pmMenuToPopulate.Items.Add(miMainTree); LocalPopulateUntil(miMainTree, 'M'); miMainTree := TMenuItem.Create(pmMenuToPopulate); miMainTree.Caption := 'cm_M..cm_R'; pmMenuToPopulate.Items.Add(miMainTree); LocalPopulateUntil(miMainTree, 'S'); miMainTree := TMenuItem.Create(pmMenuToPopulate); miMainTree.Caption := 'cm_S..cm_Z'; pmMenuToPopulate.Items.Add(miMainTree); LocalPopulateUntil(miMainTree, 'A'); finally LocalDummyComboBox.Free; end; end; { TfrmOptionsDirectoryHotlist.miShowWhereItWouldGo } procedure TfrmOptionsDirectoryHotlist.miShowWhereItWouldGo(Sender: TObject); var StringToShow: string; begin with Sender as TComponent do begin StringToShow := rsMsgHotDirDemoName + '"' + DirectoryHotlistTemp.HotDir[tag].HotDirName + '"'; case DirectoryHotlistTemp.HotDir[tag].Dispatcher of hd_CHANGEPATH: begin StringToShow := StringToShow + #$0D + #$0A + #$0D + #$0A + rsMsgHotDirDemoPath; StringToShow := StringToShow + #$0D + #$0A + mbExpandFileName(DirectoryHotlistTemp.HotDir[tag].HotDirPath); if DirectoryHotlistTemp.HotDir[tag].HotDirTarget <> '' then begin StringToShow := StringToShow + #$0D + #$0A + #$0D + #$0A + rsMsgHotDirDemoTarget; StringToShow := StringToShow + #$0D + #$0A + mbExpandFileName(DirectoryHotlistTemp.HotDir[tag].HotDirTarget); end; end; hd_COMMAND: begin StringToShow := StringToShow + #$0D + #$0A + #$0D + #$0A + rsMsgHotDirDemoCommand; StringToShow := StringToShow + #$0D + #$0A + mbExpandFileName(DirectoryHotlistTemp.HotDir[tag].HotDirPath); end; end; msgOK(StringToShow); end; end; { TfrmOptionsDirectoryHotlist.miSimplyCopyCaption } procedure TfrmOptionsDirectoryHotlist.miSimplyCopyCaption(Sender: TObject); begin with Sender as TMenuItem do begin if lbleditHotDirPath.Text = '' then lbleditHotDirPath.Text := Caption else lbleditHotDirPath.Text := Caption + ' ' + lbleditHotDirPath.Text; end; end; { TfrmOptionsDirectoryHotlist.ClearCutAndPasteList } procedure TfrmOptionsDirectoryHotlist.ClearCutAndPasteList; begin CutAndPasteIndexList.Clear; actPaste.Enabled := True; end; { TfrmOptionsDirectoryHotlist.ActualAddDirectories } function TfrmOptionsDirectoryHotlist.ActualAddDirectories(ParamDispatcher: TKindOfHotDirEntry; sName, sPath, sTarget: string; InsertOrAdd: integer): TTreeNode; var LocalHotDir: THotDir; WorkingTreeNode: TTreeNode; const SelectedNoAttachedMode: array[1..3] of TNodeAttachMode = (naInsert, naInsertBehind, naAddChildFirst); begin ClearCutAndPasteList; LocalHotDir := THotDir.Create; LocalHotDir.Dispatcher := ParamDispatcher; LocalHotDir.HotDirName := sName; LocalHotDir.HotDirPath := IncludeTrailingPathDelimiter(GetHotDirFilenameToSave(hdpmSource, sPath)); if sTarget <> '' then LocalHotDir.HotDirTarget := IncludeTrailingPathDelimiter(GetHotDirFilenameToSave(hdpmTarget, sTarget)); DirectoryHotlistTemp.Add(LocalHotDir); WorkingTreeNode := tvDirectoryHotlist.Selected; if WorkingTreeNode <> nil then Result := tvDirectoryHotlist.Items.AddNode(nil, WorkingTreeNode, sName, LocalHotDir, SelectedNoAttachedMode[InsertOrAdd]) else Result := tvDirectoryHotlist.Items.AddNode(nil, nil, sName, LocalHotDir, naAddFirst); case ParamDispatcher of hd_STARTMENU: begin Result.ImageIndex := ICONINDEX_SUBMENU; Result.SelectedIndex := ICONINDEX_SUBMENU; Result.StateIndex := ICONINDEX_SUBMENU; end; hd_CHANGEPATH: begin Result.ImageIndex := ICONINDEX_NEWADDEDDIRECTORY; Result.SelectedIndex := ICONINDEX_NEWADDEDDIRECTORY; Result.StateIndex := ICONINDEX_NEWADDEDDIRECTORY; end; end; end; function CompareStringsFromTStringList(List: TStringList; Index1, Index2: integer): integer; begin Result := CompareStrings(List.Strings[Index1], List.Strings[Index2], gSortNatural, gSortSpecial, gSortCaseSensitivity); end; { TfrmOptionsDirectoryHotlist.TryToGetCloserHotDir } //This routine "tries" to find the best place to eventually add a new directory in the tree accoring to directory names and ones alreayd in the tree. //ALSO, it will set the flag "bShouldBeAfter" to indicate if it should be "BEFORE" or "AFTER" what is returned. //"PerfectMatchIndex" is when the directory is found *exactly* in the tree as is. In other words, already there. //"SecondAlternative" is when the directory is not there, but one close to it is function TfrmOptionsDirectoryHotlist.TryToGetCloserHotDir(sDirToFindAPlaceFor: string; var TypeOfAddition: integer): TTreeNode; var BestOne, I: integer; localDirToFindAPlaceFor: string; sRepresentantString, sUnderPart, sOverPart: string; MagickSortedList: TStringList; function GetNumberOfIdenticalStartChars(A: string): longint; var I: integer; begin Result := 0; I := 1; while (I < UTF8Length(A)) and (I < UTF8Length(localDirToFindAPlaceFor)) do begin if A[I] = localDirToFindAPlaceFor[I] then Inc(Result) else I := UTF8Length(A); Inc(I); end; end; function GetBestDir(DirA, DirB: string): integer; var lengthA, lengthB: integer; begin lengthA := GetNumberOfIdenticalStartChars(DirA); lengthB := GetNumberOfIdenticalStartChars(DirB); if (lengthA = 0) and (lengthB = 0) then begin Result := 0; end else begin if lengthA > lengthB then Result := -1 else Result := 1; end; end; begin Result := nil; TypeOfAddition := ACTION_ADDHOTDIR; localDirToFindAPlaceFor := UTF8LowerCase(IncludeTrailingPathDelimiter(sDirToFindAPlaceFor)); //1st, let's try to see if we have an entry with the same *exact* directory I := 0; while (Result = nil) and (I < tvDirectoryHotlist.Items.Count) do begin if THotDir(tvDirectoryHotlist.Items.Item[I].Data).Dispatcher = hd_CHANGEPATH then begin if localDirToFindAPlaceFor = UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(THotDir(tvDirectoryHotlist.Items.Item[I].Data).HotDirPath))) then Result := tvDirectoryHotlist.Items.Item[I]; end; Inc(I); end; //2nd, if nothing found, here is the "lazy-but-probably-easiest-to-write-method" if Result = nil then begin MagickSortedList := TStringList.Create; try MagickSortedList.Clear; for I := 0 to pred(tvDirectoryHotlist.Items.Count) do begin if THotDir(tvDirectoryHotlist.Items.Item[I].Data).Dispatcher = hd_CHANGEPATH then begin sRepresentantString := UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(THotDir(tvDirectoryHotlist.Items.Item[I].Data).HotDirPath))) + IntToStr(I); MagickSortedList.Add(sRepresentantString); end; end; MagickSortedList.Add(localDirToFindAPlaceFor); //We call a custom sort to make sure sort order will make the sequence "école - Eric - Érika" MagickSortedList.CustomSort(@CompareStringsFromTStringList); I := MagickSortedList.IndexOf(localDirToFindAPlaceFor); if I = 0 then sUnderPart := '' else sUnderPart := UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(THotDir(tvDirectoryHotlist.Items.Item[StrToInt(GetLastDir(MagickSortedList.Strings[I - 1]))].Data).HotDirPath))); if I = pred(MagickSortedList.Count) then sOverPart := '' else sOverPart := UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(THotDir(tvDirectoryHotlist.Items.Item[StrToInt(GetLastDir(MagickSortedList.Strings[I + 1]))].Data).HotDirPath))); BestOne := GetBestDir(sUnderPart, sOverPart); case BestOne of -1: Result := tvDirectoryHotlist.Items.Item[StrToInt(GetLastDir(MagickSortedList.Strings[I - 1]))]; 1: Result := tvDirectoryHotlist.Items.Item[StrToInt(GetLastDir(MagickSortedList.Strings[I + 1]))]; end; if Result <> nil then begin if CompareStrings(localDirToFindAPlaceFor, UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(tHotDir(Result.Data).HotDirPath))), gSortNatural, gSortSpecial, gSortCaseSensitivity) = -1 then TypeOfAddition := ACTION_INSERTHOTDIR; end; finally MagickSortedList.Free; end; end; end; { TfrmOptionsDirectoryHotlist.TryToGetExactHotDir } function TfrmOptionsDirectoryHotlist.TryToGetExactHotDir(const index: integer): TTreeNode; var SearchingtvIndex: integer; begin Result := nil; SearchingtvIndex := 0; while (SearchingtvIndex < pred(tvDirectoryHotlist.Items.Count)) and (Result = nil) do begin if tvDirectoryHotlist.Items[SearchingtvIndex].Data = DirectoryHotlistTemp.Items[Index] then Result := tvDirectoryHotlist.Items[SearchingtvIndex] else Inc(SearchingtvIndex); end; end; { TfrmOptionsDirectoryHotlist.RecursiveSetGroupNumbers } procedure TfrmOptionsDirectoryHotlist.RecursiveSetGroupNumbers(ParamNode: TTreeNode; ParamGroupNumber: integer; DoRecursion, StopAtFirstGroup: boolean); var MaybeChild: TTreeNode; begin repeat if DoRecursion then begin MaybeChild := ParamNode.GetFirstChild; if MaybeChild <> nil then RecursiveSetGroupNumbers(MaybeChild, GetNextGroupNumber, DoRecursion, StopAtFirstGroup); end; if THotDir(ParamNode.Data).Dispatcher <> hd_SEPARATOR then begin THotDir(ParamNode.Data).GroupNumber := ParamGroupNumber; end else begin ParamGroupNumber := GetNextGroupNumber; if StopAtFirstGroup then while ParamNode <> nil do ParamNode := ParamNode.GetNextSibling; //To exit the loop! end; if ParamNode <> nil then ParamNode := ParamNode.GetNextSibling; until ParamNode = nil; end; { TfrmOptionsDirectoryHotlist.RefreshExistingProperty } procedure TfrmOptionsDirectoryHotlist.RefreshExistingProperty(ScanMode: integer); var Index, LocalThreadCount: longint; ListOfAlreadyCheckDrive, ListOfNonExistingDrive: TStringList; FreezeTime: dword; procedure StartThreadToSeeIfThisDriveExists(const sDrive: string); begin TCheckDrivePresenceThread.Create(sDrive, ListOfNonExistingDrive, LocalThreadCount); end; //Since we do that for both "Path" and "Target", it was useful to place in a routine so we can call two times the same routine procedure ScanForThisDir(DirToScan: string); var localPath, localDrive: string; begin localPath := ExcludeTrailingPathDelimiter(mbExpandFileName(DirToScan)); localDrive := UpperCase(ExtractFileDrive(localPath)); if ListOfAlreadyCheckDrive.IndexOf(localDrive) = -1 then begin Inc(LocalThreadCount); StartThreadToSeeIfThisDriveExists(localDrive); ListOfAlreadyCheckDrive.Add(localDrive); end; end; procedure RecursivelySetIconFolderNotPresent(WorkingTreeNode: TTreeNode); begin if WorkingTreeNode.Parent <> nil then begin if WorkingTreeNode.Parent.ImageIndex <> ICONINDEX_SUBMENUWITHMISSING then begin THotDir(WorkingTreeNode.Parent.Data).HotDirExisting := DirNotExist; WorkingTreeNode.Parent.ImageIndex := ICONINDEX_SUBMENUWITHMISSING; WorkingTreeNode.Parent.SelectedIndex := ICONINDEX_SUBMENUWITHMISSING; WorkingTreeNode.Parent.StateIndex := ICONINDEX_SUBMENUWITHMISSING; RecursivelySetIconFolderNotPresent(WorkingTreeNode.Parent); end; end; end; //Since we do that for both "Path" and "Target", it was useful to place in a routine so we can call two times the same routine function CheckIfThisDirectoryExists(RequestedDirectoryToCheck: string): boolean; var localPath, localDrive: string; begin if RequestedDirectoryToCheck <> '' then begin Result := False; localPath := ExcludeTrailingPathDelimiter(mbExpandFileName(RequestedDirectoryToCheck)); localDrive := UpperCase(ExtractFileDrive(localPath)); lbleditHotDirName.Text := localPath; Application.ProcessMessages; if ListOfNonExistingDrive.IndexOf(localDrive) = -1 then begin Result := mbDirectoryExists(localPath); end; if not Result then begin THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirExisting := DirNotExist; tvDirectoryHotlist.Items.Item[Index].ImageIndex := ICONINDEX_DIRECTORYNOTPRESENTHERE; tvDirectoryHotlist.Items.Item[Index].SelectedIndex := ICONINDEX_DIRECTORYNOTPRESENTHERE; tvDirectoryHotlist.Items.Item[Index].StateIndex := ICONINDEX_DIRECTORYNOTPRESENTHERE; RecursivelySetIconFolderNotPresent(tvDirectoryHotlist.Items.Item[Index]); end; end else begin Result := True; end; end; begin SetNormalIconsInTreeView; try Screen.BeginWaitCursor; ListOfAlreadyCheckDrive := TStringList.Create; ListOfAlreadyCheckDrive.Sorted := False; ListOfAlreadyCheckDrive.Clear; ListOfNonExistingDrive := TStringList.Create; ListOfNonExistingDrive.Sorted := False; ListOfNonExistingDrive.Clear; try LocalThreadCount := 0; //First, let's build a list of the "\\ServerName" that exists and let's check them in MultiThread //We scan only once each drive and "\\ServerName" //"\\ServerName" have a long timeout so that's why we check them this way for Index := 0 to pred(tvDirectoryHotlist.Items.Count) do begin case THotDir(tvDirectoryHotlist.Items.Item[Index].Data).Dispatcher of hd_CHANGEPATH: begin ScanForThisDir(THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirPath); if ScanMode = 2 then ScanForThisDir(THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirTarget); end; end; end; //Let's wait all the threads to complete //10 seconds timeout in case it never ends for whatever reason FreezeTime := GetTickCount; while (LocalThreadCount <> 0) and ((FreezeTime + 10000) > FreezeTime) do begin lbleditHotDirName.Text := IntToStr(LocalThreadCount); Application.ProcessMessages; if LocalThreadCount = 0 then Sleep(100); end; //Second, now let's scan if the director exists! for Index := 0 to pred(tvDirectoryHotlist.Items.Count) do begin case THotDir(tvDirectoryHotlist.Items.Item[Index].Data).Dispatcher of hd_CHANGEPATH: begin if CheckIfThisDirectoryExists(THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirPath) then begin case ScanMode of 1: begin THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirExisting := DirExist; end; 2: begin if CheckIfThisDirectoryExists(THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirTarget) then begin THotDir(tvDirectoryHotlist.Items.Item[Index].Data).HotDirExisting := DirExist; end; end; end; //case ScanMode end; end; //hd_CHANGEPATH: end; //case THotDir(tvDirectoryHotlist.Items.Item[Index].Data).Dispatcher of end; finally ListOfAlreadyCheckDrive.Free; ListOfNonExistingDrive.Free; lbleditHotDirName.Enabled := True; end; finally Screen.EndWaitCursor; end; tvDirectoryHotlist.Refresh; end; { TfrmOptionsDirectoryHotlist.SetNormalIconsInTreeView } procedure TfrmOptionsDirectoryHotlist.SetNormalIconsInTreeView; var Index: integer; begin for Index := 0 to pred(tvDirectoryHotlist.Items.Count) do begin if tvDirectoryHotlist.Items.Item[Index].GetFirstChild = nil then begin tvDirectoryHotlist.Items.Item[Index].ImageIndex := -1; tvDirectoryHotlist.Items.Item[Index].SelectedIndex := -1; tvDirectoryHotlist.Items.Item[Index].StateIndex := -1; end else begin tvDirectoryHotlist.Items.Item[Index].ImageIndex := ICONINDEX_SUBMENU; tvDirectoryHotlist.Items.Item[Index].SelectedIndex := ICONINDEX_SUBMENU; tvDirectoryHotlist.Items.Item[Index].StateIndex := ICONINDEX_SUBMENU; end; end; end; { TfrmOptionsDirectoryHotlist.MySortViaGroup } function TfrmOptionsDirectoryHotlist.MySortViaGroup(Node1, Node2: TTreeNode): integer; begin if (THotdir(Node1.Data).GroupNumber = THotDir(Node2.Data).GroupNumber) and (THotdir(Node1.Data).GroupNumber <> 0) then begin Result := CompareStrings(THotdir(Node1.Data).HotDirName, THotDir(Node2.Data).HotDirName, gSortNatural, gSortSpecial, gSortCaseSensitivity); end else begin if Node1.AbsoluteIndex < Node2.AbsoluteIndex then Result := -1 else Result := 1; end; end; { TfrmOptionsDirectoryHotlist.CopyTTreeViewToAnother } procedure TfrmOptionsDirectoryHotlist.CopyTTreeViewToAnother(tvSource, tvDestination: TTreeView); procedure RecursiveNodeCopy(SourceNode, DestNode: TTreeNode); var NewNode: TTreeNode; begin repeat NewNode := tvDestination.Items.AddChild(DestNode, SourceNode.Text); NewNode.Assign(SourceNode); if SourceNode.GetFirstChild <> nil then begin RecursiveNodeCopy(SourceNode.GetFirstChild, NewNode); end; SourceNode := SourceNode.GetNextSibling; until SourceNode = nil; end; begin if tvSource.Items.GetFirstNode <> nil then RecursiveNodeCopy(tvSource.Items.GetFirstNode, nil); end; { TfrmOptionsDirectoryHotlist.GetNextGroupNumber } function TfrmOptionsDirectoryHotlist.GetNextGroupNumber: integer; begin GlobalGroupNumber := GlobalGroupNumber + 1; Result := GlobalGroupNumber; end; procedure TfrmOptionsDirectoryHotlist.ScanHotDirForFilenameAndPath; var Index: integer; begin for Index := 0 to pred(DirectoryHotlistTemp.Count) do begin case THotDir(DirectoryHotlistTemp.HotDir[Index]).Dispatcher of hd_CHANGEPATH: begin DirectoryHotlistTemp.HotDir[Index].HotDirPath := GetHotDirFilenameToSave(hdpmSource ,DirectoryHotlistTemp.HotDir[Index].HotDirPath); if DirectoryHotlistTemp.HotDir[Index].HotDirTarget <> '' then DirectoryHotlistTemp.HotDir[Index].HotDirTarget := GetHotDirFilenameToSave(hdpmTarget, DirectoryHotlistTemp.HotDir[Index].HotDirTarget); end; end; end; tvDirectoryHotlistSelectionChanged(tvDirectoryHotlist); end; function TfrmOptionsDirectoryHotlist.GetHotDirFilenameToSave(AHotDirPathModifierElement: tHotDirPathModifierElement; sParamFilename: string): string; var sMaybeBasePath, SubWorkingPath, MaybeSubstitionPossible: string; begin sParamFilename := mbExpandFileName(sParamFilename); Result := sParamFilename; if AHotDirPathModifierElement in gHotDirPathModifierElements then begin if gHotDirFilenameStyle = pfsRelativeToDC then sMaybeBasePath := EnvVarCommanderPath else sMaybeBasePath := gHotDirPathToBeRelativeTo; case gHotDirFilenameStyle of pfsAbsolutePath: ; pfsRelativeToDC, pfsRelativeToFollowingPath: begin SubWorkingPath := IncludeTrailingPathDelimiter(mbExpandFileName(sMaybeBasePath)); MaybeSubstitionPossible := ExtractRelativePath(IncludeTrailingPathDelimiter(SubWorkingPath), sParamFilename); if MaybeSubstitionPossible <> sParamFilename then Result := IncludeTrailingPathDelimiter(sMaybeBasePath) + MaybeSubstitionPossible; end; end; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdirectoryhotlistextra.lfm���������������������������������������0000644�0001750�0000144�00000016330�14743153644�023616� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsDirectoryHotlistExtra: TfrmOptionsDirectoryHotlistExtra Height = 573 Width = 850 HelpKeyword = '/configuration.html#ConfigDirHotlistEx' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 573 ClientWidth = 850 DesignLeft = 79 DesignTop = 199 object gbDirectoryHotlistOptionsExtra: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 161 Top = 6 Width = 838 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Paths' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 6 ClientHeight = 141 ClientWidth = 834 TabOrder = 0 object lbDirectoryHotlistFilenameStyle: TLabel AnchorSideLeft.Control = gbDirectoryHotlistOptionsExtra AnchorSideTop.Control = gbDirectoryHotlistOptionsExtra Left = 6 Height = 15 Top = 6 Width = 193 Caption = 'Way to set paths when adding them:' ParentColor = False end object cbDirectoryHotlistFilenameStyle: TComboBox AnchorSideLeft.Control = lbDirectoryHotlistFilenameStyle AnchorSideTop.Control = lbDirectoryHotlistFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbDirectoryHotlistOptionsExtra AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 27 Width = 822 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 OnChange = cbDirectoryHotlistFilenameStyleChange Style = csDropDownList TabOrder = 0 end object btnPathToBeRelativeToHelper: TSpeedButton AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideRight.Control = cbDirectoryHotlistFilenameStyle AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = dePathToBeRelativeTo AnchorSideBottom.Side = asrBottom Left = 805 Height = 23 Top = 56 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnPathToBeRelativeToHelperClick end object dePathToBeRelativeTo: TDirectoryEdit AnchorSideLeft.Control = lbPathToBeRelativeTo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbDirectoryHotlistFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnPathToBeRelativeToHelper Left = 120 Height = 23 Top = 56 Width = 683 ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 1 MaxLength = 0 TabOrder = 1 end object lbPathToBeRelativeTo: TLabel AnchorSideLeft.Control = lbDirectoryHotlistFilenameStyle AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 60 Width = 112 Caption = 'Path to be relative to:' ParentColor = False end object btnPathToBeRelativeToAll: TButton AnchorSideLeft.Control = lbDirectoryHotlistFilenameStyle AnchorSideTop.Control = ckbDirectoryHotlistSource AnchorSideTop.Side = asrBottom Left = 6 Height = 25 Top = 110 Width = 242 AutoSize = True Caption = 'Apply current settings to directory hotlist' OnClick = btnPathToBeRelativeToAllClick TabOrder = 2 end object ckbDirectoryHotlistSource: TCheckBox AnchorSideLeft.Control = lblApplySettingsFor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 116 Height = 19 Top = 85 Width = 56 BorderSpacing.Left = 6 Caption = 'Source' TabOrder = 3 end object lblApplySettingsFor: TLabel AnchorSideLeft.Control = lbDirectoryHotlistFilenameStyle AnchorSideTop.Control = ckbDirectoryHotlistSource AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 87 Width = 104 Caption = 'Do this for paths of:' ParentColor = False end object ckbDirectoryHotlistTarget: TCheckBox AnchorSideLeft.Control = ckbDirectoryHotlistSource AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 178 Height = 19 Top = 85 Width = 54 BorderSpacing.Left = 6 Caption = 'Target' TabOrder = 4 end end object pmPathToBeRelativeToHelper: TPopupMenu[1] left = 568 top = 112 end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdirectoryhotlistextra.lrj���������������������������������������0000644�0001750�0000144�00000003005�14743153644�023622� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":5671667,"name":"tfrmoptionsdirectoryhotlistextra.gbdirectoryhotlistoptionsextra.caption","sourcebytes":[80,97,116,104,115],"value":"Paths"}, {"hash":197101002,"name":"tfrmoptionsdirectoryhotlistextra.lbdirectoryhotlistfilenamestyle.caption","sourcebytes":[87,97,121,32,116,111,32,115,101,116,32,112,97,116,104,115,32,119,104,101,110,32,97,100,100,105,110,103,32,116,104,101,109,58],"value":"Way to set paths when adding them:"}, {"hash":256553386,"name":"tfrmoptionsdirectoryhotlistextra.lbpathtoberelativeto.caption","sourcebytes":[80,97,116,104,32,116,111,32,98,101,32,114,101,108,97,116,105,118,101,32,116,111,58],"value":"Path to be relative to:"}, {"hash":171552500,"name":"tfrmoptionsdirectoryhotlistextra.btnpathtoberelativetoall.caption","sourcebytes":[65,112,112,108,121,32,99,117,114,114,101,110,116,32,115,101,116,116,105,110,103,115,32,116,111,32,100,105,114,101,99,116,111,114,121,32,104,111,116,108,105,115,116],"value":"Apply current settings to directory hotlist"}, {"hash":94816405,"name":"tfrmoptionsdirectoryhotlistextra.ckbdirectoryhotlistsource.caption","sourcebytes":[83,111,117,114,99,101],"value":"Source"}, {"hash":104754538,"name":"tfrmoptionsdirectoryhotlistextra.lblapplysettingsfor.caption","sourcebytes":[68,111,32,116,104,105,115,32,102,111,114,32,112,97,116,104,115,32,111,102,58],"value":"Do this for paths of:"}, {"hash":94932420,"name":"tfrmoptionsdirectoryhotlistextra.ckbdirectoryhotlisttarget.caption","sourcebytes":[84,97,114,103,101,116],"value":"Target"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdirectoryhotlistextra.pas���������������������������������������0000644�0001750�0000144�00000011731�14743153644�023623� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- DirectoryHotlist configuration for extra options page Copyright (C) 2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsDirectoryHotlistExtra; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Buttons, Menus, EditBtn, //DC fOptionsFrame; type { TfrmOptionsDirectoryHotlistExtra } TfrmOptionsDirectoryHotlistExtra = class(TOptionsEditor) btnPathToBeRelativeToAll: TButton; btnPathToBeRelativeToHelper: TSpeedButton; cbDirectoryHotlistFilenameStyle: TComboBox; ckbDirectoryHotlistSource: TCheckBox; ckbDirectoryHotlistTarget: TCheckBox; dePathToBeRelativeTo: TDirectoryEdit; gbDirectoryHotlistOptionsExtra: TGroupBox; lblApplySettingsFor: TLabel; lbPathToBeRelativeTo: TLabel; lbDirectoryHotlistFilenameStyle: TLabel; pmPathToBeRelativeToHelper: TPopupMenu; procedure btnPathToBeRelativeToAllClick(Sender: TObject); procedure btnPathToBeRelativeToHelperClick(Sender: TObject); procedure cbDirectoryHotlistFilenameStyleChange(Sender: TObject); private protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. //DC uGlobs, uLng, DCStrUtils, fOptions, fOptionsDirectoryHotlist, uSpecialDir; procedure TfrmOptionsDirectoryHotlistExtra.Init; begin ParseLineToList(rsPluginFilenameStyleList, cbDirectoryHotlistFilenameStyle.Items); end; procedure TfrmOptionsDirectoryHotlistExtra.Load; begin cbDirectoryHotlistFilenameStyle.ItemIndex := integer(gHotDirFilenameStyle); cbDirectoryHotlistFilenameStyleChange(cbDirectoryHotlistFilenameStyle); dePathToBeRelativeTo.Text := gHotDirPathToBeRelativeTo; ckbDirectoryHotlistSource.Checked := hdpmSource in gHotDirPathModifierElements; ckbDirectoryHotlistTarget.Checked := hdpmTarget in gHotDirPathModifierElements; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathToBeRelativeToHelper, mp_PATHHELPER, nil); end; function TfrmOptionsDirectoryHotlistExtra.Save: TOptionsEditorSaveFlags; begin gHotDirFilenameStyle := TConfigFilenameStyle(cbDirectoryHotlistFilenameStyle.ItemIndex); gHotDirPathToBeRelativeTo := dePathToBeRelativeTo.Text; gHotDirPathModifierElements := []; if ckbDirectoryHotlistSource.Checked then gHotDirPathModifierElements := gHotDirPathModifierElements + [hdpmSource]; if ckbDirectoryHotlistTarget.Checked then gHotDirPathModifierElements := gHotDirPathModifierElements + [hdpmTarget]; Result := []; end; class function TfrmOptionsDirectoryHotlistExtra.GetIconIndex: integer; begin Result := 33; end; class function TfrmOptionsDirectoryHotlistExtra.GetTitle: string; begin Result := rsOptionsEditorDirectoryHotlistExtra; end; procedure TfrmOptionsDirectoryHotlistExtra.cbDirectoryHotlistFilenameStyleChange(Sender: TObject); begin lbPathToBeRelativeTo.Visible := (TConfigFilenameStyle(cbDirectoryHotlistFilenameStyle.ItemIndex) = TConfigFilenameStyle.pfsRelativeToFollowingPath); dePathToBeRelativeTo.Visible := lbPathToBeRelativeTo.Visible; btnPathToBeRelativeToHelper.Visible := lbPathToBeRelativeTo.Visible; end; procedure TfrmOptionsDirectoryHotlistExtra.btnPathToBeRelativeToAllClick(Sender: TObject); var Options: IOptionsDialog; Editor: TOptionsEditor; begin Self.SaveSettings; //Call "SaveSettings" instead of just "Save" to get option signature set right away do we don't bother user for that page when close. Options := ShowOptions(TfrmOptionsDirectoryHotlist); Editor := Options.GetEditor(TfrmOptionsDirectoryHotlist); TfrmOptionsDirectoryHotlist(Editor).ScanHotDirForFilenameAndPath; ShowOptions(TfrmOptionsDirectoryHotlist); end; procedure TfrmOptionsDirectoryHotlistExtra.btnPathToBeRelativeToHelperClick(Sender: TObject); begin dePathToBeRelativeTo.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(dePathToBeRelativeTo, pfPATH); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; end. ���������������������������������������doublecmd-1.1.22/src/frames/foptionsdragdrop.lfm����������������������������������������������������0000644�0001750�0000144�00000007265�14743153644�020750� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsDragDrop: TfrmOptionsDragDrop Height = 467 Width = 845 HelpKeyword = '/configuration.html#ConfigMouseDD' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 467 ClientWidth = 845 DesignLeft = 65 DesignTop = 245 object cbShowConfirmationDialog: TCheckBox[0] Left = 8 Height = 19 Top = 8 Width = 212 Caption = '&Show confirmation dialog after drop' TabOrder = 0 end object gbTextDragAndDropRelatedOptions: TGroupBox[1] AnchorSideLeft.Control = cbShowConfirmationDialog AnchorSideTop.Control = cbShowConfirmationDialog AnchorSideTop.Side = asrBottom Left = 8 Height = 218 Top = 39 Width = 488 AutoSize = True BorderSpacing.Top = 12 Caption = 'When drag && dropping text into panels:' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 198 ClientWidth = 484 TabOrder = 1 Visible = False object lblMostDesiredTextFormat1: TLabel Left = 6 Height = 15 Top = 6 Width = 324 Caption = 'Place the most desired format on top of list (use dag && drop):' ParentColor = False end object lblMostDesiredTextFormat2: TLabel AnchorSideLeft.Control = lblMostDesiredTextFormat1 AnchorSideTop.Control = lblMostDesiredTextFormat1 AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 21 Width = 354 Caption = '(if the most desired is not present, we''ll take second one and so on)' ParentColor = False end object lbMostDesiredTextFormat: TListBox AnchorSideLeft.Control = lblMostDesiredTextFormat1 AnchorSideTop.Control = lblMostDesiredTextFormat2 AnchorSideTop.Side = asrBottom Left = 6 Height = 72 Top = 36 Width = 208 DragMode = dmAutomatic Items.Strings = ( 'Rich test' 'HTML text' 'Unicode text' 'ANSI text' ) ItemHeight = 15 OnDragDrop = lbMostDesiredTextFormatDragDrop OnDragOver = lbMostDesiredTextFormatDragOver ScrollWidth = 190 TabOrder = 0 end object cbDragAndDropAskFormatEachTime: TCheckBox AnchorSideLeft.Control = lblMostDesiredTextFormat1 AnchorSideTop.Control = lbMostDesiredTextFormat AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 108 Width = 358 Caption = 'From all the supported formats, ask which one to use every time' TabOrder = 1 end object cbDragAndDropTextAutoFilename: TCheckBox AnchorSideLeft.Control = lblMostDesiredTextFormat1 AnchorSideTop.Control = lblWarningForAskFormat AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 154 Width = 472 BorderSpacing.Top = 12 Caption = 'When dropping text, generate filename automatically (otherwise will prompt the user)' TabOrder = 2 end object cbDragAndDropSaveUnicodeTextInUFT8: TCheckBox AnchorSideLeft.Control = lblMostDesiredTextFormat1 AnchorSideTop.Control = cbDragAndDropTextAutoFilename AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 173 Width = 413 Caption = 'When saving Unicode text, save it in UTF8 format (will be UTF16 otherwise)' TabOrder = 3 end object lblWarningForAskFormat: TLabel AnchorSideLeft.Control = lblMostDesiredTextFormat1 AnchorSideTop.Control = cbDragAndDropAskFormatEachTime AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 127 Width = 389 Caption = '(will not work with some source application, so try to uncheck if problem)' ParentColor = False end end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdragdrop.lrj����������������������������������������������������0000644�0001750�0000144�00000006332�14743153644�020753� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":79635136,"name":"tfrmoptionsdragdrop.cbshowconfirmationdialog.caption","sourcebytes":[38,83,104,111,119,32,99,111,110,102,105,114,109,97,116,105,111,110,32,100,105,97,108,111,103,32,97,102,116,101,114,32,100,114,111,112],"value":"&Show confirmation dialog after drop"}, {"hash":129159194,"name":"tfrmoptionsdragdrop.gbtextdraganddroprelatedoptions.caption","sourcebytes":[87,104,101,110,32,100,114,97,103,32,38,38,32,100,114,111,112,112,105,110,103,32,116,101,120,116,32,105,110,116,111,32,112,97,110,101,108,115,58],"value":"When drag && dropping text into panels:"}, {"hash":244618154,"name":"tfrmoptionsdragdrop.lblmostdesiredtextformat1.caption","sourcebytes":[80,108,97,99,101,32,116,104,101,32,109,111,115,116,32,100,101,115,105,114,101,100,32,102,111,114,109,97,116,32,111,110,32,116,111,112,32,111,102,32,108,105,115,116,32,40,117,115,101,32,100,97,103,32,38,38,32,100,114,111,112,41,58],"value":"Place the most desired format on top of list (use dag && drop):"}, {"hash":95597433,"name":"tfrmoptionsdragdrop.lblmostdesiredtextformat2.caption","sourcebytes":[40,105,102,32,116,104,101,32,109,111,115,116,32,100,101,115,105,114,101,100,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,44,32,119,101,39,108,108,32,116,97,107,101,32,115,101,99,111,110,100,32,111,110,101,32,97,110,100,32,115,111,32,111,110,41],"value":"(if the most desired is not present, we'll take second one and so on)"}, {"hash":100764917,"name":"tfrmoptionsdragdrop.cbdraganddropaskformateachtime.caption","sourcebytes":[70,114,111,109,32,97,108,108,32,116,104,101,32,115,117,112,112,111,114,116,101,100,32,102,111,114,109,97,116,115,44,32,97,115,107,32,119,104,105,99,104,32,111,110,101,32,116,111,32,117,115,101,32,101,118,101,114,121,32,116,105,109,101],"value":"From all the supported formats, ask which one to use every time"}, {"hash":184179561,"name":"tfrmoptionsdragdrop.cbdraganddroptextautofilename.caption","sourcebytes":[87,104,101,110,32,100,114,111,112,112,105,110,103,32,116,101,120,116,44,32,103,101,110,101,114,97,116,101,32,102,105,108,101,110,97,109,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,40,111,116,104,101,114,119,105,115,101,32,119,105,108,108,32,112,114,111,109,112,116,32,116,104,101,32,117,115,101,114,41],"value":"When dropping text, generate filename automatically (otherwise will prompt the user)"}, {"hash":88623065,"name":"tfrmoptionsdragdrop.cbdraganddropsaveunicodetextinuft8.caption","sourcebytes":[87,104,101,110,32,115,97,118,105,110,103,32,85,110,105,99,111,100,101,32,116,101,120,116,44,32,115,97,118,101,32,105,116,32,105,110,32,85,84,70,56,32,102,111,114,109,97,116,32,40,119,105,108,108,32,98,101,32,85,84,70,49,54,32,111,116,104,101,114,119,105,115,101,41],"value":"When saving Unicode text, save it in UTF8 format (will be UTF16 otherwise)"}, {"hash":105947385,"name":"tfrmoptionsdragdrop.lblwarningforaskformat.caption","sourcebytes":[40,119,105,108,108,32,110,111,116,32,119,111,114,107,32,119,105,116,104,32,115,111,109,101,32,115,111,117,114,99,101,32,97,112,112,108,105,99,97,116,105,111,110,44,32,115,111,32,116,114,121,32,116,111,32,117,110,99,104,101,99,107,32,105,102,32,112,114,111,98,108,101,109,41],"value":"(will not work with some source application, so try to uncheck if problem)"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdragdrop.pas����������������������������������������������������0000644�0001750�0000144�00000022520�14743153644�020744� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Drag&drop options page Copyright (C) 2006-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsDragDrop; {$mode objfpc}{$H+} interface uses Controls, Classes, SysUtils, StdCtrls, fOptionsFrame, Types; type { TfrmOptionsDragDrop } TfrmOptionsDragDrop = class(TOptionsEditor) cbShowConfirmationDialog: TCheckBox; cbDragAndDropAskFormatEachTime: TCheckBox; cbDragAndDropSaveUnicodeTextInUFT8: TCheckBox; cbDragAndDropTextAutoFilename: TCheckBox; gbTextDragAndDropRelatedOptions: TGroupBox; lblMostDesiredTextFormat1: TLabel; lblMostDesiredTextFormat2: TLabel; lblWarningForAskFormat: TLabel; lbMostDesiredTextFormat: TListBox; procedure lbMostDesiredTextFormatDragOver(Sender, Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure lbMostDesiredTextFormatDragDrop(Sender, {%H-}Source: TObject; {%H-}X, Y: integer); protected slUserLanguageName, slLegacyName: TStringList; procedure Init; override; procedure Done; override; procedure Load; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; function Save: TOptionsEditorSaveFlags; override; function GetUserNameFromLegacyName(sLegacyName: string): string; procedure LoadDesiredOrderTextFormatList; procedure SaveDesiredOrderTextFormatList; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; procedure SortThisListAccordingToDragAndDropDesiredFormat(ListToSort: TStringList); implementation {$R *.lfm} uses DCStrUtils, crc, uGlobs, uLng; { TfrmOptionsDragDrop } { TfrmOptionsDragDrop.Init } procedure TfrmOptionsDragDrop.Init; var iFormat: integer; begin slUserLanguageName := TStringList.Create; ParseLineToList(rsDragAndDropTextFormat, slUserLanguageName); slLegacyName := TStringList.Create; for iFormat := 0 to pred(NbOfDropTextFormat) do slLegacyName.Add(gDragAndDropDesiredTextFormat[iFormat].Name); end; { TfrmOptionsDragDrop.Done } procedure TfrmOptionsDragDrop.Done; begin FreeAndNil(slUserLanguageName); FreeAndNil(slLegacyName); end; { TfrmOptionsDragDrop.GetUserNameFromLegacyName } function TfrmOptionsDragDrop.GetUserNameFromLegacyName(sLegacyName: string): string; var iPos: integer; begin Result := '???'; iPos := slLegacyName.indexof(sLegacyName); if (iPos >= 0) and (iPos < NbOfDropTextFormat) then Result := slUserLanguageName.Strings[iPos]; end; { TfrmOptionsDragDrop.Load } procedure TfrmOptionsDragDrop.Load; begin cbShowConfirmationDialog.Checked := gShowDialogOnDragDrop; {$IFDEF MSWINDOWS} gbTextDragAndDropRelatedOptions.Visible := True; LoadDesiredOrderTextFormatList; cbDragAndDropAskFormatEachTime.Checked := gDragAndDropAskFormatEachTime; cbDragAndDropTextAutoFilename.Checked := gDragAndDropTextAutoFilename; cbDragAndDropSaveUnicodeTextInUFT8.Checked := gDragAndDropSaveUnicodeTextInUFT8; {$ENDIF} end; { TfrmOptionsDragDrop.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsDragDrop.IsSignatureComputedFromAllWindowComponents: boolean; begin lbMostDesiredTextFormat.ItemIndex := -1; // Tricky pass but nothing was selected when we initially did the signature so let's unselect them all. Result := True; end; { TfrmOptionsDragDrop.ExtraOptionsSignature } function TfrmOptionsDragDrop.ExtraOptionsSignature(CurrentSignature: dword): dword; var iFormat: integer; begin Result := CurrentSignature; for iFormat := 0 to pred(lbMostDesiredTextFormat.Items.Count) do Result := crc32(Result, @lbMostDesiredTextFormat.Items.Strings[iFormat][1], length(lbMostDesiredTextFormat.Items.Strings[iFormat])); end; { TfrmOptionsDragDrop.Save } function TfrmOptionsDragDrop.Save: TOptionsEditorSaveFlags; begin gShowDialogOnDragDrop := cbShowConfirmationDialog.Checked; {$IFDEF MSWINDOWS} SaveDesiredOrderTextFormatList; gDragAndDropAskFormatEachTime := cbDragAndDropAskFormatEachTime.Checked; gDragAndDropTextAutoFilename := cbDragAndDropTextAutoFilename.Checked; gDragAndDropSaveUnicodeTextInUFT8 := cbDragAndDropSaveUnicodeTextInUFT8.Checked; {$ENDIF} Result := []; end; class function TfrmOptionsDragDrop.GetIconIndex: integer; begin Result := 28; end; class function TfrmOptionsDragDrop.GetTitle: string; begin Result := rsOptionsEditorDragAndDrop; end; procedure TfrmOptionsDragDrop.lbMostDesiredTextFormatDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin Accept := (Source = lbMostDesiredTextFormat) and (lbMostDesiredTextFormat.ItemIndex <> -1); end; procedure TfrmOptionsDragDrop.lbMostDesiredTextFormatDragDrop(Sender, Source: TObject; X, Y: integer); var SrcIndex, DestIndex: integer; begin SrcIndex := lbMostDesiredTextFormat.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lbMostDesiredTextFormat.GetIndexAtY(Y); if (DestIndex < 0) or (DestIndex >= lbMostDesiredTextFormat.Count) then DestIndex := lbMostDesiredTextFormat.Count - 1; lbMostDesiredTextFormat.Items.Move(SrcIndex, DestIndex); lbMostDesiredTextFormat.ItemIndex := DestIndex; end; { TfrmOptionsDragDrop.LoadDesiredOrderTextFormatList } procedure TfrmOptionsDragDrop.LoadDesiredOrderTextFormatList; var IndexDropTextFormat, ExpectedPosition, ActualPosition: integer; TempoString: string; begin lbMostDesiredTextFormat.Clear; for IndexDropTextFormat := 0 to pred(NbOfDropTextFormat) do lbMostDesiredTextFormat.Items.Add(gDragAndDropDesiredTextFormat[IndexDropTextFormat].Name); for IndexDropTextFormat := 0 to pred(NbOfDropTextFormat) do begin ExpectedPosition := gDragAndDropDesiredTextFormat[IndexDropTextFormat].DesireLevel; if (ExpectedPosition < 0) or (ExpectedPosition > pred(NbOfDropTextFormat)) then ExpectedPosition := pred(NbOfDropTextFormat); ActualPosition := lbMostDesiredTextFormat.Items.IndexOf(gDragAndDropDesiredTextFormat[IndexDropTextFormat].Name); if (ActualPosition <> -1) and (ExpectedPosition <> ActualPosition) then begin TempoString := lbMostDesiredTextFormat.Items.Strings[ActualPosition]; lbMostDesiredTextFormat.Items.Strings[ActualPosition] := lbMostDesiredTextFormat.Items.Strings[ExpectedPosition]; lbMostDesiredTextFormat.Items.Strings[ExpectedPosition] := TempoString; end; end; // At the last minutes, we translate to user's language the format names for ActualPosition := 0 to pred(lbMostDesiredTextFormat.Items.Count) do lbMostDesiredTextFormat.Items.Strings[ActualPosition] := GetUserNameFromLegacyName(lbMostDesiredTextFormat.Items.Strings[ActualPosition]); lbMostDesiredTextFormat.ItemIndex := -1; end; procedure TfrmOptionsDragDrop.SaveDesiredOrderTextFormatList; var IndexDropTextFormat, ActualPosition: integer; begin for IndexDropTextFormat := 0 to pred(NbOfDropTextFormat) do begin ActualPosition := lbMostDesiredTextFormat.Items.IndexOf(GetUserNameFromLegacyName(gDragAndDropDesiredTextFormat[IndexDropTextFormat].Name)); if (ActualPosition <> -1) then gDragAndDropDesiredTextFormat[IndexDropTextFormat].DesireLevel := ActualPosition; end; end; // Arrange the list in such way that the most desired format is on top. // This routine is also used in "uOleDragDrop" for offering user's suggestion so the list is arranged according to user's desire procedure SortThisListAccordingToDragAndDropDesiredFormat(ListToSort: TStringList); function GetDesireLevel(SearchingText: string): integer; var SearchingIndex: integer; begin Result := -1; SearchingIndex := 0; while (SearchingIndex < NbOfDropTextFormat) and (Result = -1) do begin if gDragAndDropDesiredTextFormat[SearchingIndex].Name = SearchingText then Result := gDragAndDropDesiredTextFormat[SearchingIndex].DesireLevel; Inc(SearchingIndex); end; end; var Index, InnerIndex, DesireLevelIndex, DesireLevelInnerIndex: integer; TempoString: string; begin //It's a poor sort... But we don't have too many so we keep it simple. for Index := 0 to (ListToSort.Count - 2) do begin for InnerIndex := Index + 1 to pred(ListToSort.Count) do begin DesireLevelIndex := GetDesireLevel(ListToSort.Strings[Index]); DesireLevelInnerIndex := GetDesireLevel(ListToSort.Strings[InnerIndex]); if (DesireLevelIndex > DesireLevelInnerIndex) and (DesireLevelIndex <> -1) and (DesireLevelInnerIndex <> -1) then begin TempoString := ListToSort.Strings[Index]; ListToSort.Strings[Index] := ListToSort.Strings[InnerIndex]; ListToSort.Strings[InnerIndex] := TempoString; end; end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdriveslistbutton.lfm��������������������������������������������0000644�0001750�0000144�00000002370�14743153644�022562� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsDrivesListButton: TfrmOptionsDrivesListButton HelpKeyword = '/configuration.html#ConfigDrivesList' object gbDrivesList: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 85 Top = 6 Width = 308 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Drives list' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 4 ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 67 ClientWidth = 304 TabOrder = 0 object cbShowLabel: TCheckBox Left = 10 Height = 17 Top = 4 Width = 98 Caption = 'Show &label' TabOrder = 0 end object cbShowFileSystem: TCheckBox AnchorSideTop.Side = asrBottom Left = 10 Height = 17 Top = 25 Width = 98 Caption = 'Show &file system' TabOrder = 1 end object cbShowFreeSpace: TCheckBox Left = 10 Height = 17 Top = 46 Width = 98 Caption = 'Show fr&ee space' TabOrder = 2 end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdriveslistbutton.lrj��������������������������������������������0000644�0001750�0000144�00000001313�14743153644�022567� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":203341924,"name":"tfrmoptionsdriveslistbutton.gbdriveslist.caption","sourcebytes":[68,114,105,118,101,115,32,108,105,115,116],"value":"Drives list"}, {"hash":44797484,"name":"tfrmoptionsdriveslistbutton.cbshowlabel.caption","sourcebytes":[83,104,111,119,32,38,108,97,98,101,108],"value":"Show &label"}, {"hash":88456797,"name":"tfrmoptionsdriveslistbutton.cbshowfilesystem.caption","sourcebytes":[83,104,111,119,32,38,102,105,108,101,32,115,121,115,116,101,109],"value":"Show &file system"}, {"hash":236106821,"name":"tfrmoptionsdriveslistbutton.cbshowfreespace.caption","sourcebytes":[83,104,111,119,32,102,114,38,101,101,32,115,112,97,99,101],"value":"Show fr&ee space"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsdriveslistbutton.pas��������������������������������������������0000644�0001750�0000144�00000004610�14743153644�022566� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Drives list button options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsDrivesListButton; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, fOptionsFrame; type { TfrmOptionsDrivesListButton } TfrmOptionsDrivesListButton = class(TOptionsEditor) cbShowLabel: TCheckBox; cbShowFileSystem: TCheckBox; cbShowFreeSpace: TCheckBox; gbDrivesList: TGroupBox; protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng; { TfrmOptionsDrivesListButton } procedure TfrmOptionsDrivesListButton.Load; begin cbShowLabel.Checked := dlbShowLabel in gDrivesListButtonOptions; cbShowFileSystem.Checked := dlbShowFileSystem in gDrivesListButtonOptions; cbShowFreeSpace.Checked := dlbShowFreeSpace in gDrivesListButtonOptions; end; function TfrmOptionsDrivesListButton.Save: TOptionsEditorSaveFlags; begin gDrivesListButtonOptions := []; if cbShowLabel.Checked then Include(gDrivesListButtonOptions, dlbShowLabel); if cbShowFileSystem.Checked then Include(gDrivesListButtonOptions, dlbShowFileSystem); if cbShowFreeSpace.Checked then Include(gDrivesListButtonOptions, dlbShowFreeSpace); Result := []; end; class function TfrmOptionsDrivesListButton.GetIconIndex: Integer; begin Result := 31; end; class function TfrmOptionsDrivesListButton.GetTitle: String; begin Result := rsOptionsEditorDrivesListButton; end; end. ������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionseditorcolors.lfm������������������������������������������������0000644�0001750�0000144�00000106541�14743153644�021653� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsEditorColors: TfrmOptionsEditorColors Height = 357 Width = 680 HelpKeyword = '/configuration.html#ConfigToolsEditorHL' ClientHeight = 357 ClientWidth = 680 DesignLeft = 322 DesignTop = 122 object pnlTop: TPanel[0] Left = 0 Height = 26 Top = 0 Width = 680 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 3 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 26 ClientWidth = 680 Constraints.MaxWidth = 1000 ParentShowHint = False ShowHint = True TabOrder = 0 object cmbLanguage: TComboBox AnchorSideTop.Side = asrBottom Left = 0 Height = 23 Top = 3 Width = 326 BorderSpacing.Top = 3 ItemHeight = 15 OnChange = cmbLanguageChange Style = csDropDownList TabOrder = 0 end object pnlFileExtensions: TPanel AnchorSideBottom.Side = asrBottom Left = 329 Height = 23 Top = 3 Width = 351 AutoSize = True BevelOuter = bvNone ClientHeight = 23 ClientWidth = 351 TabOrder = 1 object edtFileExtensions: TEdit Left = 0 Height = 23 Top = 0 Width = 305 Align = alClient TabOrder = 0 end object btnResetMask: TSpeedButton Left = 328 Height = 23 Hint = 'Reset' Top = 0 Width = 23 Align = alRight Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 000200000008000000120000001D000000271212126315151575151515751515 157515151575151515751515157515151575151515751212125E000000000000 000100000004000000090000000F0000001438383871ECECECFFE8E8E8FFE8E8 E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFECECECFF38383871000000000000 0000000000000000000000000000373737004949496EEAEAEAFFCBCBCBFFCBCB CBFFCBCBCBFFCBCBCBFFEAEAEAFF666666FFEAEAEAFF4949496E0B0B0B000404 040000000000000000003E3E3E00525252005252526DEEEEEEFFC8C8C8FFFFFF FFFFFFFFFFFFC8C8C8FFF1F1F1FFEDEDEDFFEEEEEEFF5252526D151515000D0D 0D00191919581515157515151575151515752D2D2DAF8C8C8CFF747474FF9494 94FF949494FF7C7C7CFFC4C4C4FFC4C4C4FFF1F1F1FF5C5C5C6C151515000D0D 0D0038383871ECECECFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 E8FFECECECFFD8D8D8FFFFFFFFFFC0C0C0FFF6F6F6FF6464646A191919581515 1575353535B1EAEAEAFF262626FF262626FF262626FF262626FFEAEAEAFF6666 66FFEAEAEAFFD8D8D8FFFFFFFFFFBBBBBBFFF9F9F9FF6C6C6C6938383871ECEC ECFFA8A8A8FFEEEEEEFF2A2A2AFF3C3C3CFF3C3C3CFF2A2A2AFFF1F1F1FFEDED EDFFEEEEEEFF9F9F9FFFADADADFFADADADFFFDFDFDFF747474684949496EEAEA EAFFADA639FFF1F1F1FF2E2E2EFF424242FF424242FF343434FF2E2E2EFF2E2E 2EFFF1F1F1FFD8D8D8FFFFFFFFFFFFFFFFFFFFFFFFFF7A7A7A675252526DEEEE EEFFB2AB3CFFF6F6F6FF333333FF4A4A4AFF4A4A4AFF4A4A4AFF4A4A4AFF3333 33FFF6F6F6FF7F7F7F947F7F7F667F7F7F667F7F7F667F7F7F4D5C5C5C6CF1F1 F1FFB6AE3FFFF9F9F9FF383838FF505050FF505050FF505050FF505050FF3838 38FFF9F9F9FF7F7F7F4D8080800080808000808080007F7F7F006464646AF6F6 F6FFB9B242FFFDFDFDFF3B3B3BFF3B3B3BFF3B3B3BFF3B3B3BFF3B3B3BFF3B3B 3BFFFDFDFDFF747474688080800080808000808080007F7F7F006C6C6C69F9F9 F9FFBCB544FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF7A7A7A677C7C7C0080808000808080007F7F7F0074747468FDFD FDFFC9C13CFFBFB745FFBFB745FFBFB745FFBFB745FFBFB745FFCBCBCBFF7B7B 7BA47F7F7F667F7F7F4D747474007E7E7E00808080007F7F7F007A7A7A67FFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A7A 7A677A7A7A007A7A7A007A7A7A007A7A7A007F7F7F007F7F7F007F7F7F4D7F7F 7F667F7F7F667F7F7F667F7F7F667F7F7F667F7F7F667F7F7F667F7F7F667F7F 7F4D7E7E7E007E7E7E007E7E7E005F5F5F000000000000000000 } OnClick = btnResetMaskClick end object btnSaveMask: TSpeedButton Left = 305 Height = 23 Hint = 'Save' Top = 0 Width = 23 Align = alRight Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000BA6A368FB969 35B5B86935EEB76835FFB56835FFB46734FFB26634FFB06533FFAE6433FFAC63 32FFAA6232FFA96132FFA86031FFA76031FEA66031F1A86131C4BA6A35DEEBC6 ADFFEAC5ADFFFEFBF8FFFEFBF8FFFEFBF8FFFEFBF8FFFEFBF8FFFEFBF8FFFEFB F8FFFEFBF8FFFEFBF8FFFEFBF8FFC89A7CFFC79879FFA76031EDBA6B37FEEDCA B3FFE0A27AFFFEFAF7FF62C088FF62C088FF62C088FF62C088FF62C088FF62C0 88FF62C088FF62C088FFFDF9F6FFCA8D65FFC99B7CFFA76031FEBB6C38FFEECC B6FFE1A27AFFFEFAF7FFBFDCC2FFBFDCC2FFBFDCC2FFBFDCC2FFBFDCC2FFBFDC C2FFBFDCC2FFBFDCC2FFFDF9F6FFCD9068FFCC9E81FFA86132FFBB6B38FFEFCE B8FFE1A279FFFEFAF7FF62C088FF62C088FF62C088FF62C088FF62C088FF62C0 88FF62C088FF62C088FFFDF9F6FFCF936AFFCEA384FFAA6132FFBA6A36FFEFD0 BBFFE2A27AFFFEFBF8FFFEFBF8FFFEFBF8FFFEFBF8FFFEFBF8FFFEFBF8FFFEFB F8FFFEFBF8FFFEFBF8FFFEFBF8FFD3966DFFD2A78AFFAB6232FFBB6A36FFF0D2 BEFFE2A37AFFE2A37AFFE1A37AFFE2A37BFFE1A37BFFE0A178FFDE9F77FFDD9F 76FFDC9D74FFD99B72FFD89971FFD69970FFD5AB8EFFAD6333FFBB6A36FFF2D5 C2FFE3A37AFFE3A37AFFE2A37BFFE2A37BFFE2A47BFFE1A279FFE0A178FFDEA0 77FFDE9E75FFDC9D74FFDA9B73FFD99B73FFDAB095FFAF6433FFBB6A36FFF2D8 C5FFE3A47BFFE3A37AFFE3A47AFFE2A47BFFE2A37BFFE1A37BFFE1A279FFDFA0 77FFDE9F76FFDD9E74FFDB9C72FFDC9D74FFDDB59AFFB16534FFBB6B36FFF4D9 C7FFE6A67DFFC88C64FFC98D65FFC98E67FFCB926CFFCB926DFFCA9069FFC88C 65FFC88C64FFC88C64FFC88C64FFDA9C74FFE1BA9FFFB36634FFBB6B36FEF4DC C9FFE7A77DFFF9ECE1FFF9ECE1FFF9EDE3FFFCF4EEFFFDFAF7FFFDF7F3FFFAED E5FFF7E7DBFFF7E5D9FFF6E5D8FFDEA077FFE4BEA4FFB46734FFBC6B36FAF5DD CCFFE7A87EFFFAF0E8FFFAF0E8FFC98D66FFFAF0E9FFFDF8F3FFFEFAF8FFFCF4 EFFFF9E9DFFFF7E7DBFFF7E5D9FFE0A278FFE7C2A9FFB66835FFBC6B36F0F6DF D0FFE8A87EFFFCF6F1FFFCF6F1FFC88C64FFFAF1E9FFFBF4EEFFFDFAF7FFFDF9 F6FFFAF0E8FFF8E8DDFFF7E6DBFFE1A37AFFEFD5C3FFB76935FEBC6B36D8F6DF D1FFE9AA80FFFEFAF6FFFDFAF6FFC88C64FFFBF3EEFFFBF1EAFFFCF6F2FFFEFB F8FFFCF6F1FFF9ECE2FFF8E7DBFFEED0BAFFECD0BDFFBB703EF8BC6B369BF6E0 D1FFF7E0D1FFFEFBF8FFFEFBF7FFFDF9F6FFFCF5F0FFFAF0EAFFFBF2EDFFFDF9 F6FFFDFAF7FFFBF1EBFFF8E9DFFEECD0BDFBC9895EECB5693563BC6B3671BC6B 3690BC6B36CCBC6B36EEBC6B36FABB6B36FEBB6B36FFBB6A36FFBB6A36FFBC6C 39FFBD6E3BFFBB6D3AFFBB6B38EFBB703ECBB6693554FFFFFF00 } OnClick = btnSaveMaskClick end end end object PnlTop2: TPanel[1] Left = 0 Height = 131 Top = 26 Width = 680 Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] BevelOuter = bvNone ClientHeight = 131 ClientWidth = 680 TabOrder = 1 inline ColorPreview: TSynEdit Left = 211 Height = 130 Top = 1 Width = 469 Align = alClient BorderSpacing.Left = 1 BorderSpacing.Top = 1 Font.Height = -16 Font.Name = 'courier' Font.Pitch = fpFixed Font.Quality = fqNonAntialiased ParentColor = False ParentFont = False TabOrder = 0 TabStop = False BookMarkOptions.Xoffset = 30 Gutter.Width = 59 Gutter.MouseActions = <> RightGutter.Width = 0 RightGutter.MouseActions = <> Keystrokes = < item Command = ecUp ShortCut = 38 end item Command = ecSelUp ShortCut = 8230 end item Command = ecScrollUp ShortCut = 16422 end item Command = ecDown ShortCut = 40 end item Command = ecSelDown ShortCut = 8232 end item Command = ecScrollDown ShortCut = 16424 end item Command = ecLeft ShortCut = 37 end item Command = ecSelLeft ShortCut = 8229 end item Command = ecWordLeft ShortCut = 16421 end item Command = ecSelWordLeft ShortCut = 24613 end item Command = ecRight ShortCut = 39 end item Command = ecSelRight ShortCut = 8231 end item Command = ecWordRight ShortCut = 16423 end item Command = ecSelWordRight ShortCut = 24615 end item Command = ecPageDown ShortCut = 34 end item Command = ecSelPageDown ShortCut = 8226 end item Command = ecPageBottom ShortCut = 16418 end item Command = ecSelPageBottom ShortCut = 24610 end item Command = ecPageUp ShortCut = 33 end item Command = ecSelPageUp ShortCut = 8225 end item Command = ecPageTop ShortCut = 16417 end item Command = ecSelPageTop ShortCut = 24609 end item Command = ecLineStart ShortCut = 36 end item Command = ecSelLineStart ShortCut = 8228 end item Command = ecEditorTop ShortCut = 16420 end item Command = ecSelEditorTop ShortCut = 24612 end item Command = ecLineEnd ShortCut = 35 end item Command = ecSelLineEnd ShortCut = 8227 end item Command = ecEditorBottom ShortCut = 16419 end item Command = ecSelEditorBottom ShortCut = 24611 end item Command = ecToggleMode ShortCut = 45 end item Command = ecCopy ShortCut = 16429 end item Command = ecPaste ShortCut = 8237 end item Command = ecDeleteChar ShortCut = 46 end item Command = ecCut ShortCut = 8238 end item Command = ecDeleteLastChar ShortCut = 8 end item Command = ecDeleteLastChar ShortCut = 8200 end item Command = ecDeleteLastWord ShortCut = 16392 end item Command = ecUndo ShortCut = 32776 end item Command = ecRedo ShortCut = 40968 end item Command = ecLineBreak ShortCut = 13 end item Command = ecSelectAll ShortCut = 16449 end item Command = ecCopy ShortCut = 16451 end item Command = ecBlockIndent ShortCut = 24649 end item Command = ecLineBreak ShortCut = 16461 end item Command = ecInsertLine ShortCut = 16462 end item Command = ecDeleteWord ShortCut = 16468 end item Command = ecBlockUnindent ShortCut = 24661 end item Command = ecPaste ShortCut = 16470 end item Command = ecCut ShortCut = 16472 end item Command = ecDeleteLine ShortCut = 16473 end item Command = ecDeleteEOL ShortCut = 24665 end item Command = ecUndo ShortCut = 16474 end item Command = ecRedo ShortCut = 24666 end item Command = ecGotoMarker0 ShortCut = 16432 end item Command = ecGotoMarker1 ShortCut = 16433 end item Command = ecGotoMarker2 ShortCut = 16434 end item Command = ecGotoMarker3 ShortCut = 16435 end item Command = ecGotoMarker4 ShortCut = 16436 end item Command = ecGotoMarker5 ShortCut = 16437 end item Command = ecGotoMarker6 ShortCut = 16438 end item Command = ecGotoMarker7 ShortCut = 16439 end item Command = ecGotoMarker8 ShortCut = 16440 end item Command = ecGotoMarker9 ShortCut = 16441 end item Command = ecSetMarker0 ShortCut = 24624 end item Command = ecSetMarker1 ShortCut = 24625 end item Command = ecSetMarker2 ShortCut = 24626 end item Command = ecSetMarker3 ShortCut = 24627 end item Command = ecSetMarker4 ShortCut = 24628 end item Command = ecSetMarker5 ShortCut = 24629 end item Command = ecSetMarker6 ShortCut = 24630 end item Command = ecSetMarker7 ShortCut = 24631 end item Command = ecSetMarker8 ShortCut = 24632 end item Command = ecSetMarker9 ShortCut = 24633 end item Command = ecNormalSelect ShortCut = 24654 end item Command = ecColumnSelect ShortCut = 24643 end item Command = ecLineSelect ShortCut = 24652 end item Command = ecTab ShortCut = 9 end item Command = ecShiftTab ShortCut = 8201 end item Command = ecMatchBracket ShortCut = 24642 end> MouseActions = <> MouseTextActions = <> MouseSelActions = <> Lines.Strings = ( 'ColorPreview' ) VisibleSpecialChars = [vscSpace, vscTabAtLast] SelectedColor.BackPriority = 50 SelectedColor.ForePriority = 50 SelectedColor.FramePriority = 50 SelectedColor.BoldPriority = 50 SelectedColor.ItalicPriority = 50 SelectedColor.UnderlinePriority = 50 SelectedColor.StrikeOutPriority = 50 BracketHighlightStyle = sbhsBoth BracketMatchColor.Background = clNone BracketMatchColor.Foreground = clNone BracketMatchColor.Style = [fsBold] FoldedCodeColor.Background = clNone FoldedCodeColor.Foreground = clGray FoldedCodeColor.FrameColor = clGray MouseLinkColor.Background = clNone MouseLinkColor.Foreground = clBlue LineHighlightColor.Background = clNone LineHighlightColor.Foreground = clNone inline TSynGutterPartList object TSynGutterMarks Width = 24 MouseActions = <> end object TSynGutterLineNumber Width = 19 MouseActions = <> MarkupInfo.Background = clBtnFace MarkupInfo.Foreground = clBtnText DigitCount = 2 ShowOnlyLineNumbersMultiplesOf = 1 ZeroStart = False LeadingZeros = False end object TSynGutterChanges Width = 4 MouseActions = <> ModifiedColor = 59900 SavedColor = clGreen end object TSynGutterSeparator Width = 2 MouseActions = <> MarkupInfo.Background = clWindow MarkupInfo.Foreground = clGrayText end object TSynGutterCodeFolding MouseActions = <> MarkupInfo.Background = clNone MarkupInfo.Foreground = clGray MouseActionsExpanded = <> MouseActionsCollapsed = <> end end end object Splitter1: TSplitter Left = 205 Height = 131 Top = 0 Width = 5 end object ColorElementTree: TTreeView Left = 0 Height = 131 Top = 0 Width = 205 Align = alLeft DefaultItemHeight = 18 ReadOnly = True RowSelect = True ScrollBars = ssAutoBoth ShowButtons = False ShowRoot = False TabOrder = 2 OnAdvancedCustomDrawItem = ColorElementTreeAdvancedCustomDrawItem OnChange = ColorElementTreeChange Options = [tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowLines, tvoToolTips, tvoThemedDraw] end end object pnlElementAttributes: TPanel[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = PnlTop2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 0 Height = 200 Top = 157 Width = 680 Anchors = [akLeft, akRight, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 200 ClientWidth = 680 Constraints.MinHeight = 200 TabOrder = 2 OnResize = pnlElementAttributesResize object ForeGroundLabel: TLabel AnchorSideLeft.Control = pnlElementAttributes AnchorSideTop.Control = ForegroundColorBox AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 46 Width = 62 BorderSpacing.Left = 6 Caption = 'Fo®round' FocusControl = ForegroundColorBox ParentColor = False Visible = False end object BackGroundLabel: TLabel AnchorSideLeft.Control = pnlElementAttributes AnchorSideTop.Control = BackGroundColorBox AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 71 Width = 64 BorderSpacing.Left = 6 Caption = 'Bac&kground' FocusControl = BackGroundColorBox ParentColor = False Visible = False end object ForeGroundUseDefaultCheckBox: TCheckBox AnchorSideLeft.Control = pnlElementAttributes AnchorSideTop.Control = ForegroundColorBox AnchorSideTop.Side = asrCenter Left = 6 Height = 19 Top = 44 Width = 82 BorderSpacing.Left = 6 Caption = 'Fo®round' OnChange = GeneralCheckBoxOnChange TabOrder = 0 end object ForegroundColorBox: TColorBox AnchorSideLeft.Control = ColumnPosBevel AnchorSideTop.Control = ToolBar1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlElementAttributes AnchorSideRight.Side = asrBottom Left = 94 Height = 22 Top = 42 Width = 200 DefaultColorColor = clWhite Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeDefault, cbCustomColor, cbPrettyNames, cbCustomColors] Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 3 Constraints.MaxWidth = 200 ItemHeight = 16 OnChange = ForegroundColorBoxChange TabOrder = 1 end object BackGroundColorBox: TColorBox AnchorSideLeft.Control = ColumnPosBevel AnchorSideTop.Control = ForegroundColorBox AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlElementAttributes AnchorSideRight.Side = asrBottom Left = 94 Height = 22 Top = 67 Width = 200 DefaultColorColor = clWhite Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeDefault, cbCustomColor, cbPrettyNames, cbCustomColors] Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 3 Constraints.MaxWidth = 200 ItemHeight = 16 OnChange = ForegroundColorBoxChange TabOrder = 3 end object BackGroundUseDefaultCheckBox: TCheckBox AnchorSideLeft.Control = pnlElementAttributes AnchorSideTop.Control = BackGroundColorBox AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 6 Height = 19 Top = 69 Width = 84 BorderSpacing.Left = 6 Caption = 'Bac&kground' OnChange = GeneralCheckBoxOnChange TabOrder = 2 end object FrameColorBox: TColorBox AnchorSideLeft.Control = ColumnPosBevel AnchorSideTop.Control = BackGroundColorBox AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlElementAttributes AnchorSideRight.Side = asrBottom Left = 94 Height = 22 Top = 92 Width = 200 DefaultColorColor = clWhite Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeDefault, cbCustomColor, cbPrettyNames, cbCustomColors] Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 3 Constraints.MaxWidth = 200 ItemHeight = 16 OnChange = ForegroundColorBoxChange TabOrder = 5 end object FrameColorUseDefaultCheckBox: TCheckBox AnchorSideLeft.Control = pnlElementAttributes AnchorSideTop.Control = FrameColorBox AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 6 Height = 19 Top = 94 Width = 74 BorderSpacing.Left = 6 Caption = '&Text-mark' OnChange = GeneralCheckBoxOnChange TabOrder = 4 end object bvlAttributeSection: TDividerBevel Left = 0 Height = 15 Top = 0 Width = 680 Caption = 'Element Attributes' Align = alTop Font.Style = [fsBold] ParentFont = False end object pnlUnderline: TPanel AnchorSideLeft.Control = pnlElementAttributes AnchorSideTop.Control = FrameEdgesBox AnchorSideTop.Side = asrBottom Left = 6 Height = 40 Top = 141 Width = 134 AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 3 BevelOuter = bvNone ClientHeight = 40 ClientWidth = 134 TabOrder = 6 object TextUnderlineRadioPanel: TPanel AnchorSideLeft.Control = TextUnderlineCheckBox AnchorSideTop.Control = TextUnderlineCheckBox AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 21 Top = 19 Width = 134 AutoSize = True BevelInner = bvLowered BevelOuter = bvNone ClientHeight = 21 ClientWidth = 134 TabOrder = 0 object TextUnderlineRadioOn: TRadioButton Tag = 3 AnchorSideLeft.Control = TextUnderlineRadioPanel AnchorSideTop.Control = TextUnderlineRadioPanel AnchorSideRight.Control = TextUnderlineRadioOff Left = 4 Height = 19 Top = 1 Width = 36 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&n' Checked = True OnChange = TextStyleRadioOnChange TabOrder = 0 TabStop = True end object TextUnderlineRadioOff: TRadioButton Tag = 3 AnchorSideLeft.Control = TextUnderlineRadioOn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextUnderlineRadioOn AnchorSideRight.Control = TextUnderlineRadioInvert Left = 43 Height = 19 Top = 1 Width = 37 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&ff' OnChange = TextStyleRadioOnChange TabOrder = 1 end object TextUnderlineRadioInvert: TRadioButton Tag = 3 AnchorSideLeft.Control = TextUnderlineRadioOff AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextUnderlineRadioPanel AnchorSideRight.Control = TextUnderlineRadioPanel AnchorSideRight.Side = asrBottom Left = 83 Height = 19 Top = 1 Width = 50 BorderSpacing.Left = 3 Caption = 'In&vert' OnChange = TextStyleRadioOnChange TabOrder = 2 end end object TextUnderlineCheckBox: TCheckBox AnchorSideLeft.Control = pnlUnderline AnchorSideTop.Control = pnlUnderline Left = 0 Height = 19 Top = 0 Width = 71 Caption = '&Underline' OnChange = GeneralCheckBoxOnChange TabOrder = 1 end end object pnlBold: TPanel AnchorSideLeft.Control = pnlUnderline AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlUnderline Left = 146 Height = 40 Top = 141 Width = 134 AutoSize = True BorderSpacing.Left = 6 BevelOuter = bvNone ClientHeight = 40 ClientWidth = 134 TabOrder = 7 object TextBoldRadioPanel: TPanel AnchorSideLeft.Control = TextBoldCheckBox AnchorSideTop.Control = TextBoldCheckBox AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 21 Top = 19 Width = 134 AutoSize = True BevelInner = bvLowered BevelOuter = bvNone ClientHeight = 21 ClientWidth = 134 TabOrder = 0 object TextBoldRadioInvert: TRadioButton Tag = 2 AnchorSideLeft.Control = TextBoldRadioOff AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextBoldRadioPanel AnchorSideRight.Control = TextBoldRadioPanel AnchorSideRight.Side = asrBottom Left = 83 Height = 19 Top = 1 Width = 50 BorderSpacing.Left = 3 Caption = 'In&vert' OnChange = TextStyleRadioOnChange TabOrder = 2 end object TextBoldRadioOn: TRadioButton Tag = 2 AnchorSideLeft.Control = TextBoldRadioPanel AnchorSideTop.Control = TextBoldRadioPanel AnchorSideRight.Control = TextBoldRadioOff Left = 4 Height = 19 Top = 1 Width = 36 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&n' Checked = True OnChange = TextStyleRadioOnChange TabOrder = 0 TabStop = True end object TextBoldRadioOff: TRadioButton Tag = 2 AnchorSideLeft.Control = TextBoldRadioOn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextBoldRadioPanel AnchorSideRight.Control = TextBoldRadioInvert Left = 43 Height = 19 Top = 1 Width = 37 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&ff' OnChange = TextStyleRadioOnChange TabOrder = 1 end end object TextBoldCheckBox: TCheckBox AnchorSideLeft.Control = pnlBold AnchorSideTop.Control = pnlBold Left = 0 Height = 19 Top = 0 Width = 44 Caption = '&Bold' OnChange = GeneralCheckBoxOnChange TabOrder = 1 end end object pnlItalic: TPanel AnchorSideLeft.Control = pnlBold AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlUnderline Left = 286 Height = 40 Top = 141 Width = 134 AutoSize = True BorderSpacing.Left = 6 BevelOuter = bvNone ClientHeight = 40 ClientWidth = 134 TabOrder = 8 object TextItalicRadioPanel: TPanel AnchorSideLeft.Control = TextItalicCheckBox AnchorSideTop.Control = TextItalicCheckBox AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 21 Top = 19 Width = 134 AutoSize = True BevelInner = bvLowered BevelOuter = bvNone ClientHeight = 21 ClientWidth = 134 TabOrder = 0 object TextItalicRadioInvert: TRadioButton Tag = 2 AnchorSideLeft.Control = TextItalicRadioOff AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextItalicRadioPanel AnchorSideRight.Control = TextItalicRadioPanel AnchorSideRight.Side = asrBottom Left = 83 Height = 19 Top = 1 Width = 50 BorderSpacing.Left = 3 Caption = 'In&vert' OnChange = TextStyleRadioOnChange TabOrder = 2 end object TextItalicRadioOn: TRadioButton Tag = 2 AnchorSideLeft.Control = TextItalicRadioPanel AnchorSideTop.Control = TextItalicRadioPanel AnchorSideRight.Control = TextItalicRadioOff Left = 4 Height = 19 Top = 1 Width = 36 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&n' Checked = True OnChange = TextStyleRadioOnChange TabOrder = 0 TabStop = True end object TextItalicRadioOff: TRadioButton Tag = 2 AnchorSideLeft.Control = TextItalicRadioOn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextItalicRadioPanel AnchorSideRight.Control = TextItalicRadioInvert Left = 43 Height = 19 Top = 1 Width = 37 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&ff' OnChange = TextStyleRadioOnChange TabOrder = 1 end end object TextItalicCheckBox: TCheckBox AnchorSideLeft.Control = pnlItalic AnchorSideTop.Control = pnlItalic Left = 0 Height = 19 Top = 0 Width = 45 Caption = '&Italic' OnChange = GeneralCheckBoxOnChange TabOrder = 1 end end object FrameStyleBox: TComboBox AnchorSideLeft.Control = FrameEdgesBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = FrameEdgesBox Left = 197 Height = 21 Top = 117 Width = 97 BorderSpacing.Left = 6 ItemHeight = 15 Items.Strings = ( 'slsSolid' 'slsDashed' 'slsDotted' 'slsWaved' ) OnChange = ForegroundColorBoxChange OnDrawItem = FrameStyleBoxDrawItem ReadOnly = True Style = csOwnerDrawFixed TabOrder = 9 end object FrameEdgesBox: TComboBox AnchorSideLeft.Control = FrameColorBox AnchorSideTop.Control = FrameColorBox AnchorSideTop.Side = asrBottom Left = 94 Height = 21 Top = 117 Width = 97 BorderSpacing.Top = 3 ItemHeight = 15 Items.Strings = ( 'Around' 'Bottom' 'Left' ) OnChange = ForegroundColorBoxChange OnDrawItem = FrameEdgesBoxDrawItem ReadOnly = True Style = csOwnerDrawFixed TabOrder = 10 end object ColumnPosBevel: TPanel AnchorSideLeft.Control = ForeGroundUseDefaultCheckBox AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlUnderline AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = pnlElementAttributes AnchorSideBottom.Side = asrBottom Left = 94 Height = 1 Top = 181 Width = 50 AutoSize = True BorderSpacing.Left = 6 BevelOuter = bvNone Constraints.MinHeight = 1 Constraints.MinWidth = 50 TabOrder = 11 end object pnlStrikeOut: TPanel AnchorSideLeft.Control = pnlItalic AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlUnderline Left = 426 Height = 40 Top = 141 Width = 134 AutoSize = True BorderSpacing.Left = 6 BevelOuter = bvNone ClientHeight = 40 ClientWidth = 134 TabOrder = 12 object TextStrikeOutRadioPanel: TPanel AnchorSideLeft.Control = TextStrikeOutCheckBox AnchorSideTop.Control = TextStrikeOutCheckBox AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 21 Top = 19 Width = 134 AutoSize = True BevelInner = bvLowered BevelOuter = bvNone ClientHeight = 21 ClientWidth = 134 TabOrder = 0 object TextStrikeOutRadioInvert: TRadioButton Tag = 2 AnchorSideLeft.Control = TextStrikeOutRadioOff AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextStrikeOutRadioPanel AnchorSideRight.Control = TextStrikeOutRadioPanel AnchorSideRight.Side = asrBottom Left = 83 Height = 19 Top = 1 Width = 50 BorderSpacing.Left = 3 Caption = 'In&vert' OnChange = TextStyleRadioOnChange TabOrder = 2 end object TextStrikeOutRadioOn: TRadioButton Tag = 2 AnchorSideLeft.Control = TextStrikeOutRadioPanel AnchorSideTop.Control = TextStrikeOutRadioPanel AnchorSideRight.Control = TextStrikeOutRadioOff Left = 4 Height = 19 Top = 1 Width = 36 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&n' Checked = True OnChange = TextStyleRadioOnChange TabOrder = 0 TabStop = True end object TextStrikeOutRadioOff: TRadioButton Tag = 2 AnchorSideLeft.Control = TextStrikeOutRadioOn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TextStrikeOutRadioPanel AnchorSideRight.Control = TextStrikeOutRadioInvert Left = 43 Height = 19 Top = 1 Width = 37 BorderSpacing.Left = 3 BorderSpacing.Right = 3 Caption = 'O&ff' OnChange = TextStyleRadioOnChange TabOrder = 1 end end object TextStrikeOutCheckBox: TCheckBox AnchorSideLeft.Control = pnlStrikeOut AnchorSideTop.Control = pnlStrikeOut Left = 0 Height = 19 Top = 0 Width = 72 Caption = '&Strike Out' OnChange = GeneralCheckBoxOnChange TabOrder = 1 end end object ToolBar1: TToolBar Left = 3 Height = 24 Top = 15 Width = 674 AutoSize = True BorderSpacing.Left = 3 BorderSpacing.Right = 3 EdgeBorders = [ebBottom] ParentShowHint = False ShowCaptions = True ShowHint = True TabOrder = 13 object tbtnGlobal: TToolButton Tag = 1 Left = 1 Top = 0 AutoSize = True Caption = 'Use (and edit) &global scheme settings' Down = True Grouped = True OnClick = tbtnGlobalClick Style = tbsCheck end object tbtnLocal: TToolButton Tag = 1 Left = 216 Top = 0 AutoSize = True Caption = 'Use &local scheme settings' Grouped = True OnClick = tbtnGlobalClick Style = tbsCheck end object ToolButton3: TToolButton Left = 206 Height = 22 Top = 0 Width = 10 Style = tbsSeparator end end end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionseditorcolors.lrj������������������������������������������������0000644�0001750�0000144�00000007460�14743153644�021664� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":5818820,"name":"tfrmoptionseditorcolors.btnresetmask.hint","sourcebytes":[82,101,115,101,116],"value":"Reset"}, {"hash":366789,"name":"tfrmoptionseditorcolors.btnsavemask.hint","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":195459012,"name":"tfrmoptionseditorcolors.foregroundlabel.caption","sourcebytes":[70,111,38,114,101,103,114,111,117,110,100],"value":"Fo®round"}, {"hash":27336596,"name":"tfrmoptionseditorcolors.backgroundlabel.caption","sourcebytes":[66,97,99,38,107,103,114,111,117,110,100],"value":"Bac&kground"}, {"hash":195459012,"name":"tfrmoptionseditorcolors.foregroundusedefaultcheckbox.caption","sourcebytes":[70,111,38,114,101,103,114,111,117,110,100],"value":"Fo®round"}, {"hash":27336596,"name":"tfrmoptionseditorcolors.backgroundusedefaultcheckbox.caption","sourcebytes":[66,97,99,38,107,103,114,111,117,110,100],"value":"Bac&kground"}, {"hash":259162699,"name":"tfrmoptionseditorcolors.framecolorusedefaultcheckbox.caption","sourcebytes":[38,84,101,120,116,45,109,97,114,107],"value":"&Text-mark"}, {"hash":157254323,"name":"tfrmoptionseditorcolors.bvlattributesection.caption","sourcebytes":[69,108,101,109,101,110,116,32,65,116,116,114,105,98,117,116,101,115],"value":"Element Attributes"}, {"hash":20942,"name":"tfrmoptionseditorcolors.textunderlineradioon.caption","sourcebytes":[79,38,110],"value":"O&n"}, {"hash":335046,"name":"tfrmoptionseditorcolors.textunderlineradiooff.caption","sourcebytes":[79,38,102,102],"value":"O&ff"}, {"hash":904388,"name":"tfrmoptionseditorcolors.textunderlineradioinvert.caption","sourcebytes":[73,110,38,118,101,114,116],"value":"In&vert"}, {"hash":181113861,"name":"tfrmoptionseditorcolors.textunderlinecheckbox.caption","sourcebytes":[38,85,110,100,101,114,108,105,110,101],"value":"&Underline"}, {"hash":904388,"name":"tfrmoptionseditorcolors.textboldradioinvert.caption","sourcebytes":[73,110,38,118,101,114,116],"value":"In&vert"}, {"hash":20942,"name":"tfrmoptionseditorcolors.textboldradioon.caption","sourcebytes":[79,38,110],"value":"O&n"}, {"hash":335046,"name":"tfrmoptionseditorcolors.textboldradiooff.caption","sourcebytes":[79,38,102,102],"value":"O&ff"}, {"hash":2790948,"name":"tfrmoptionseditorcolors.textboldcheckbox.caption","sourcebytes":[38,66,111,108,100],"value":"&Bold"}, {"hash":904388,"name":"tfrmoptionseditorcolors.textitalicradioinvert.caption","sourcebytes":[73,110,38,118,101,114,116],"value":"In&vert"}, {"hash":20942,"name":"tfrmoptionseditorcolors.textitalicradioon.caption","sourcebytes":[79,38,110],"value":"O&n"}, {"hash":335046,"name":"tfrmoptionseditorcolors.textitalicradiooff.caption","sourcebytes":[79,38,102,102],"value":"O&ff"}, {"hash":185238227,"name":"tfrmoptionseditorcolors.textitaliccheckbox.caption","sourcebytes":[38,73,116,97,108,105,99],"value":"&Italic"}, {"hash":904388,"name":"tfrmoptionseditorcolors.textstrikeoutradioinvert.caption","sourcebytes":[73,110,38,118,101,114,116],"value":"In&vert"}, {"hash":20942,"name":"tfrmoptionseditorcolors.textstrikeoutradioon.caption","sourcebytes":[79,38,110],"value":"O&n"}, {"hash":335046,"name":"tfrmoptionseditorcolors.textstrikeoutradiooff.caption","sourcebytes":[79,38,102,102],"value":"O&ff"}, {"hash":3997012,"name":"tfrmoptionseditorcolors.textstrikeoutcheckbox.caption","sourcebytes":[38,83,116,114,105,107,101,32,79,117,116],"value":"&Strike Out"}, {"hash":263354451,"name":"tfrmoptionseditorcolors.tbtnglobal.caption","sourcebytes":[85,115,101,32,40,97,110,100,32,101,100,105,116,41,32,38,103,108,111,98,97,108,32,115,99,104,101,109,101,32,115,101,116,116,105,110,103,115],"value":"Use (and edit) &global scheme settings"}, {"hash":41235059,"name":"tfrmoptionseditorcolors.tbtnlocal.caption","sourcebytes":[85,115,101,32,38,108,111,99,97,108,32,115,99,104,101,109,101,32,115,101,116,116,105,110,103,115],"value":"Use &local scheme settings"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionseditorcolors.pas������������������������������������������������0000644�0001750�0000144�00000076071�14743153644�021664� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Internal editor highlighters configuration frame Copyright (C) 2012-2023 Alexander Koblov (alexx2000@mail.ru) Based on Lazarus IDE editor configuration frame (Editor/Display/Colors) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsEditorColors; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, SynEdit, Forms, Controls, StdCtrls, ExtCtrls, ColorBox, ComCtrls, Dialogs, Menus, Buttons, fOptionsFrame, DividerBevel, types, LMessages, Graphics, SynEditHighlighter, SynUniClasses, SynUniRules, dmHigh; type { TfrmOptionsEditorColors } TfrmOptionsEditorColors = class(TOptionsEditor) BackGroundColorBox: TColorBox; BackGroundLabel: TLabel; BackGroundUseDefaultCheckBox: TCheckBox; bvlAttributeSection: TDividerBevel; cmbLanguage: TComboBox; ColorPreview: TSynEdit; ColumnPosBevel: TPanel; edtFileExtensions: TEdit; ForegroundColorBox: TColorBox; ForeGroundLabel: TLabel; ForeGroundUseDefaultCheckBox: TCheckBox; FrameColorBox: TColorBox; FrameColorUseDefaultCheckBox: TCheckBox; FrameEdgesBox: TComboBox; FrameStyleBox: TComboBox; ColorElementTree: TTreeView; pnlBold: TPanel; pnlElementAttributes: TPanel; pnlItalic: TPanel; pnlStrikeOut: TPanel; pnlTop: TPanel; PnlTop2: TPanel; pnlUnderline: TPanel; btnSaveMask: TSpeedButton; btnResetMask: TSpeedButton; Splitter1: TSplitter; pnlFileExtensions: TPanel; tbtnGlobal: TToolButton; tbtnLocal: TToolButton; TextBoldCheckBox: TCheckBox; TextBoldRadioInvert: TRadioButton; TextBoldRadioOff: TRadioButton; TextBoldRadioOn: TRadioButton; TextBoldRadioPanel: TPanel; TextItalicCheckBox: TCheckBox; TextStrikeOutCheckBox: TCheckBox; TextItalicRadioInvert: TRadioButton; TextStrikeOutRadioInvert: TRadioButton; TextItalicRadioOff: TRadioButton; TextStrikeOutRadioOff: TRadioButton; TextItalicRadioOn: TRadioButton; TextStrikeOutRadioOn: TRadioButton; TextItalicRadioPanel: TPanel; TextStrikeOutRadioPanel: TPanel; TextUnderlineCheckBox: TCheckBox; TextUnderlineRadioInvert: TRadioButton; TextUnderlineRadioOff: TRadioButton; TextUnderlineRadioOn: TRadioButton; TextUnderlineRadioPanel: TPanel; ToolBar1: TToolBar; ToolButton3: TToolButton; procedure btnResetMaskClick(Sender: TObject); procedure btnSaveMaskClick(Sender: TObject); procedure FrameStyleBoxDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; {%H-}State: TOwnerDrawState); procedure cmbLanguageChange(Sender: TObject); procedure ForegroundColorBoxChange(Sender: TObject); procedure FrameEdgesBoxDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; {%H-}State: TOwnerDrawState); procedure ColorElementTreeAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; {%H-}Stage: TCustomDrawStage; var {%H-}PaintImages, {%H-}DefaultDraw: Boolean); procedure ColorElementTreeChange(Sender: TObject; {%H-}Node: TTreeNode); procedure GeneralCheckBoxOnChange(Sender: TObject); procedure pnlElementAttributesResize(Sender: TObject); procedure tbtnGlobalClick(Sender: TObject); procedure TextStyleRadioOnChange(Sender: TObject); procedure SynPlainTextHighlighterChange(Sender: TObject); private FHighl: TdmHighl; FDefHighlightElement, FCurHighlightElement: TSynHighlighterAttributes; FCurrentHighlighter: TSynCustomHighlighter; FCurHighlightRule: TSynRule; FIsEditingDefaults: Boolean; UpdatingColor: Boolean; procedure UpdateCurrentScheme; function TreeAddSet(Node: TTreeNode; SymbSet: TSynSet): TTreeNode; function TreeAddRange(Node: TTreeNode; Range: TSynRange): TTreeNode; function TreeAddKeyList(Node: TTreeNode; KeyList: TSynKeyList): TTreeNode; function SynAttributeSortCompare(Node1, Node2: TTreeNode): Integer; protected procedure Init; override; procedure Done; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; function IsSignatureComputedFromAllWindowComponents: Boolean; override; end; implementation {$R *.lfm} uses LCLType, LCLIntf, SynEditTypes, SynUniHighlighter, GraphUtil, uLng, uGlobs, uHighlighters; const COLOR_NODE_PREFIX = ' abc '; function DefaultToNone(AColor: TColor): TColor; begin if AColor = clDefault then Result := clNone else Result := AColor; end; function NoneToDefault(AColor: TColor): TColor; begin if AColor = clNone then Result := clDefault else Result := AColor; end; { TfrmOptionsEditorColors } function TfrmOptionsEditorColors.SynAttributeSortCompare(Node1, Node2: TTreeNode): Integer; begin if CompareStr(Node1.Text, rsSynDefaultText) = 0 then Result:= -1 else if CompareStr(Node2.Text, rsSynDefaultText) = 0 then Result:= 1 else Result:= CompareStr(Node1.Text, Node2.Text); end; procedure TfrmOptionsEditorColors.FrameEdgesBoxDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); //+++ var r: TRect; PCol: Integer; begin if Index < 0 then exit;; r.top := ARect.top + 3; r.bottom := ARect.bottom - 3; r.left := ARect.left + 5; r.right := ARect.Right - 5; with TCustomComboBox(Control).Canvas do begin FillRect(ARect); Pen.Width := 1; PCol := pen.Color; Pen.Color := clGray; Pen.Style := psDot; Pen.EndCap := pecFlat; Rectangle(r); Pen.Width := 2; pen.Color := PCol; Pen.Style := psSolid; case Index of ord(sfeAround): Rectangle(r); ord(sfeBottom): begin MoveTo(r.Left, r.Bottom); LineTo(r.Right-1, r.Bottom); end; ord(sfeLeft): begin MoveTo(r.Left, r.Top); LineTo(r.Left, r.Bottom-1); end; end; end; end; procedure TfrmOptionsEditorColors.FrameStyleBoxDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); //++ var p: TPoint; begin if Index < 0 then exit;; with TCustomComboBox(Control).Canvas do begin FillRect(ARect); Pen.Width := 2; pen.EndCap := pecFlat; case Index of 0: Pen.Style := psSolid; 1: Pen.Style := psDash; 2: Pen.Style := psDot; 3: Pen.Style := psSolid; end; if Index = 3 then begin MoveToEx(Handle, ARect.Left + 5, (ARect.Top + ARect.Bottom) div 2 - 2, @p); WaveTo(Handle, ARect.Right - 5, (ARect.Top + ARect.Bottom) div 2 - 2, 4); end else begin MoveTo(ARect.Left + 5, (ARect.Top + ARect.Bottom) div 2); LineTo(ARect.Right - 5, (ARect.Top + ARect.Bottom) div 2); end; end; end; procedure TfrmOptionsEditorColors.btnSaveMaskClick(Sender: TObject); begin FCurrentHighlighter.DefaultFilter:= FCurrentHighlighter.LanguageName + ' (' + edtFileExtensions.Text + ')|' + edtFileExtensions.Text; end; procedure TfrmOptionsEditorColors.btnResetMaskClick(Sender: TObject); begin with TSynCustomHighlighterClass(FCurrentHighlighter.ClassType).Create(nil) do begin FCurrentHighlighter.DefaultFilter:= DefaultFilter; edtFileExtensions.Text:= Copy(FCurrentHighlighter.DefaultFilter, Pos('|', FCurrentHighlighter.DefaultFilter) + 1, MaxInt); Free; end; end; procedure TfrmOptionsEditorColors.cmbLanguageChange(Sender: TObject); var I: LongInt; ANode: TTreeNode; SynUniSyn: Boolean; begin if (cmbLanguage.ItemIndex < 0) then Exit; FCurrentHighlighter:= TSynCustomHighlighter(cmbLanguage.Items.Objects[cmbLanguage.ItemIndex]); pnlFileExtensions.Enabled:= not (FCurrentHighlighter is TSynPlainTextHighlighter); edtFileExtensions.Text:= Copy(FCurrentHighlighter.DefaultFilter, Pos('|', FCurrentHighlighter.DefaultFilter) + 1, MaxInt); try ColorPreview.Lines.Text:= FCurrentHighlighter.SampleSource; except ColorPreview.Lines.Text:= EmptyStr; end; FHighl.SetHighlighter(ColorPreview, FCurrentHighlighter); SynUniSyn:= (FCurrentHighlighter is TSynUniSyn); ColorElementTree.ShowButtons:= SynUniSyn; ColorElementTree.ShowRoot:= SynUniSyn; btnResetMask.Enabled:= not SynUniSyn; ColorElementTree.Items.Clear; if SynUniSyn then begin ANode:= TreeAddRange(nil, TSynUniSyn(FCurrentHighlighter).MainRules); ANode.Expand(False); end else if (FCurrentHighlighter.AttrCount > 0) then begin for I:= 0 to FCurrentHighlighter.AttrCount - 1 do begin ANode:= ColorElementTree.Items.Add(nil, FCurrentHighlighter.Attribute[I].Name); ANode.Data:= FCurrentHighlighter.Attribute[I]; end; ColorElementTree.CustomSort(@SynAttributeSortCompare); end; if ColorElementTree.Items.GetFirstNode <> nil then begin ColorElementTree.Items.GetFirstNode.Selected := True; ColorElementTreeChange(ColorElementTree, ColorElementTree.Items.GetFirstNode); end; end; procedure TfrmOptionsEditorColors.ForegroundColorBoxChange(Sender: TObject); //+++ var AttrToEdit: TSynHighlighterAttributes; begin if (FCurHighlightElement = nil) or UpdatingColor then Exit; UpdatingColor := True; if FIsEditingDefaults then AttrToEdit := FHighl.SynPlainTextHighlighter.Attribute[FHighl.SynPlainTextHighlighter.AttrCount-1] else AttrToEdit := FCurHighlightElement; if Sender = ForegroundColorBox then begin AttrToEdit.Foreground := DefaultToNone(ForeGroundColorBox.Selected); ForeGroundUseDefaultCheckBox.Checked := ForeGroundColorBox.Selected <> clDefault; end; if Sender = BackGroundColorBox then begin AttrToEdit.Background := DefaultToNone(BackGroundColorBox.Selected); BackGroundUseDefaultCheckBox.Checked := BackGroundColorBox.Selected <> clDefault; end; if Sender = FrameColorBox then begin AttrToEdit.FrameColor := DefaultToNone(FrameColorBox.Selected); FrameColorUseDefaultCheckBox.Checked := FrameColorBox.Selected <> clDefault; FrameEdgesBox.Enabled := FrameColorBox.Selected <> clDefault; FrameStyleBox.Enabled := FrameColorBox.Selected <> clDefault; end; if Sender = FrameEdgesBox then begin AttrToEdit.FrameEdges := TSynFrameEdges(FrameEdgesBox.ItemIndex); end; if Sender = FrameStyleBox then begin AttrToEdit.FrameStyle := TSynLineStyle(FrameStyleBox.ItemIndex); end; if AttrToEdit is TSynAttributes then begin if FCurHighlightRule is TSynRange then TSynRange(FCurHighlightRule).SetColorForChilds(); end; UpdatingColor := False; UpdateCurrentScheme; end; procedure TfrmOptionsEditorColors.ColorElementTreeAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean); //+++ var NodeRect: TRect; FullAbcWidth, AbcWidth: Integer; Attri: TSynHighlighterAttributes; TextY: Integer; AText: String; c: TColor; s: String; begin if not (TObject(Node.Data) is TSynHighlighterAttributes) then begin AText:= TSynRule(Node.Data).Name; Attri := TSynRule(Node.Data).Attribs; end else begin if (ColorElementTree.Items.GetFirstNode = Node) and FIsEditingDefaults then Attri := FDefHighlightElement else begin Attri := TSynHighlighterAttributes(Node.Data); end; AText:= Attri.Name; end; if (Attri = nil) then Exit; // Draw node background and name if cdsSelected in State then begin ColorElementTree.Canvas.Brush.Color := ColorElementTree.SelectionColor; ColorElementTree.Canvas.Font.Color := InvertColor(ColorElementTree.SelectionColor); end else begin ColorElementTree.Canvas.Brush.Color := ColorElementTree.Color; ColorElementTree.Canvas.Font.Color := Font.Color; end; NodeRect := Node.DisplayRect(True); FullAbcWidth := ColorElementTree.Canvas.TextExtent(COLOR_NODE_PREFIX).cx; TextY := (NodeRect.Top + NodeRect.Bottom - ColorElementTree.Canvas.TextHeight(Node.Text)) div 2; NodeRect.Right+= FullAbcWidth; ColorElementTree.Canvas.FillRect(NodeRect); ColorElementTree.Canvas.TextOut(NodeRect.Left+FullAbcWidth, TextY, AText); // Draw preview box - Background c := clNone; if (hafBackColor in Attri.Features) then c := Attri.Background; // Fallback Background-color for text if (c = clNone) or (c = clDefault) then c := ColorPreview.Color; ColorElementTree.Canvas.Brush.Color := c; ColorElementTree.Canvas.FillRect(NodeRect.Left+2, NodeRect.Top+2, NodeRect.Left+FullAbcWidth-2, NodeRect.Bottom-2); // Draw preview Frame ColorElementTree.Canvas.Pen.Color := Attri.FrameColor; if (hafFrameColor in Attri.Features) and (Attri.FrameColor <> clDefault) and (Attri.FrameColor <> clNone) then ColorElementTree.Canvas.Rectangle(NodeRect.Left+2, NodeRect.Top+2, NodeRect.Left+FullAbcWidth-2, NodeRect.Bottom-2); // Draw preview ForeGround if (hafForeColor in Attri.Features) //and //(ahaSupportedFeatures[TAdditionalHilightAttribute(AttriIdx)].BG) ) // if no BG, then FG was used then begin c := Attri.Foreground; if (c = clNone) or (c = clDefault) then c := ColorPreview.Font.Color; begin s := 'abc'; ColorElementTree.Canvas.Font.Color := c; ColorElementTree.Canvas.Font.Style := Attri.Style; ColorElementTree.Canvas.Font.Height := -(NodeRect.Bottom - NodeRect.Top - 7); TextY := (NodeRect.Top + NodeRect.Bottom - canvas.TextHeight(s)) div 2; AbcWidth := ColorElementTree.Canvas.TextExtent(s).cx; SetBkMode(ColorElementTree.Canvas.Handle, TRANSPARENT); ColorElementTree.Canvas.TextOut(NodeRect.Left+(FullAbcWidth - AbcWidth) div 2, TextY, s); SetBkMode(ColorElementTree.Canvas.Handle, OPAQUE); ColorElementTree.Canvas.Font.Height := Font.Height; ColorElementTree.Canvas.Font.Style := []; end; end; end; procedure TfrmOptionsEditorColors.SynPlainTextHighlighterChange(Sender: TObject); var SynPlainTextHighlighter: TSynHighlighterAttributes absolute Sender; begin ColorPreview.Color:= SynPlainTextHighlighter.Background; ColorPreview.Font.Color:= SynPlainTextHighlighter.Foreground; end; procedure TfrmOptionsEditorColors.ColorElementTreeChange(Sender: TObject; Node: TTreeNode); //+++ var ParentFore, ParentBack: Boolean; AttrToShow: TSynHighlighterAttributes; IsDefault, CanGlobal: Boolean; begin if UpdatingColor or (ColorElementTree.Selected = nil) or (ColorElementTree.Selected.Data = nil) then Exit; if (TObject(ColorElementTree.Selected.Data) is TSynHighlighterAttributes) then begin FCurHighlightElement:= TSynHighlighterAttributes(ColorElementTree.Selected.Data); IsDefault := SameText(rsSynDefaultText, FCurHighlightElement.Name); CanGlobal := (cmbLanguage.ItemIndex > 0) and IsDefault; ParentFore:= False; ParentBack:= False; end else begin FCurHighlightRule:= TSynRule(ColorElementTree.Selected.Data); ParentFore:= FCurHighlightRule.Attribs.ParentForeground; ParentBack:= FCurHighlightRule.Attribs.ParentBackground; FCurHighlightElement:= FCurHighlightRule.Attribs; IsDefault := (Node.Level = 0); CanGlobal := False; end; UpdatingColor := True; DisableAlign; try FDefHighlightElement:= FHighl.SynPlainTextHighlighter.Attribute[FHighl.SynPlainTextHighlighter.AttrCount - 1]; FIsEditingDefaults:= CanGlobal and (FCurrentHighlighter.Tag = 1); tbtnGlobal.Enabled := CanGlobal; tbtnLocal.Enabled := CanGlobal; tbtnGlobal.AllowAllUp := not CanGlobal; tbtnLocal.AllowAllUp := not CanGlobal; tbtnGlobal.Down := (FCurrentHighlighter.Tag = 1) and CanGlobal; tbtnLocal.Down := (FCurrentHighlighter.Tag = 0) and CanGlobal; if FIsEditingDefaults then AttrToShow := FDefHighlightElement else AttrToShow := FCurHighlightElement; ForegroundColorBox.Style := ForegroundColorBox.Style + [cbIncludeDefault]; BackGroundColorBox.Style := BackGroundColorBox.Style + [cbIncludeDefault]; // Foreground ForeGroundLabel.Visible := (hafForeColor in AttrToShow.Features) and (IsDefault = True); ForeGroundUseDefaultCheckBox.Visible := (hafForeColor in AttrToShow.Features) and (IsDefault = False); ForegroundColorBox.Visible := (hafForeColor in AttrToShow.Features); ForegroundColorBox.Selected := NoneToDefault(AttrToShow.Foreground); if ForegroundColorBox.Selected = clDefault then ForegroundColorBox.Tag := ForegroundColorBox.DefaultColorColor else ForegroundColorBox.Tag := ForegroundColorBox.Selected; ForeGroundUseDefaultCheckBox.Checked := (ForegroundColorBox.Selected <> clDefault) and (ParentFore = False); // BackGround BackGroundLabel.Visible := (hafBackColor in AttrToShow.Features) and (IsDefault = True); BackGroundUseDefaultCheckBox.Visible := (hafBackColor in AttrToShow.Features) and (IsDefault = False); BackGroundColorBox.Visible := (hafBackColor in AttrToShow.Features); BackGroundColorBox.Selected := NoneToDefault(AttrToShow.Background); if BackGroundColorBox.Selected = clDefault then BackGroundColorBox.Tag := BackGroundColorBox.DefaultColorColor else BackGroundColorBox.Tag := BackGroundColorBox.Selected; BackGroundUseDefaultCheckBox.Checked := (BackGroundColorBox.Selected <> clDefault) and (ParentBack = False); // Frame FrameColorUseDefaultCheckBox.Visible := hafFrameColor in AttrToShow.Features; FrameColorBox.Visible := hafFrameColor in AttrToShow.Features; FrameEdgesBox.Visible := hafFrameEdges in AttrToShow.Features; FrameStyleBox.Visible := hafFrameStyle in AttrToShow.Features; FrameColorBox.Selected := NoneToDefault(AttrToShow.FrameColor); if FrameColorBox.Selected = clDefault then FrameColorBox.Tag := FrameColorBox.DefaultColorColor else FrameColorBox.Tag := FrameColorBox.Selected; FrameColorUseDefaultCheckBox.Checked := FrameColorBox.Selected <> clDefault; FrameEdgesBox.ItemIndex := integer(AttrToShow.FrameEdges); FrameStyleBox.ItemIndex := integer(AttrToShow.FrameStyle); FrameEdgesBox.Enabled := FrameColorUseDefaultCheckBox.Checked; FrameStyleBox.Enabled := FrameColorUseDefaultCheckBox.Checked; // Styles TextBoldCheckBox.Visible := hafStyle in AttrToShow.Features; TextItalicCheckBox.Visible := hafStyle in AttrToShow.Features; TextUnderlineCheckBox.Visible := hafStyle in AttrToShow.Features; TextStrikeOutCheckBox.Visible := hafStyle in AttrToShow.Features; TextBoldRadioPanel.Visible := hafStyleMask in AttrToShow.Features; TextItalicRadioPanel.Visible := hafStyleMask in AttrToShow.Features; TextUnderlineRadioPanel.Visible := hafStyleMask in AttrToShow.Features; TextStrikeOutRadioPanel.Visible := hafStyleMask in AttrToShow.Features; if hafStyleMask in AttrToShow.Features then begin TextBoldCheckBox.Checked := (fsBold in AttrToShow.Style) or (fsBold in AttrToShow.StyleMask); TextBoldRadioPanel.Enabled := TextBoldCheckBox.Checked; if not(fsBold in AttrToShow.StyleMask) then TextBoldRadioInvert.Checked := True else if fsBold in AttrToShow.Style then TextBoldRadioOn.Checked := True else TextBoldRadioOff.Checked := True; TextItalicCheckBox.Checked := (fsItalic in AttrToShow.Style) or (fsItalic in AttrToShow.StyleMask); TextItalicRadioPanel.Enabled := TextItalicCheckBox.Checked; if not(fsItalic in AttrToShow.StyleMask) then TextItalicRadioInvert.Checked := True else if fsItalic in AttrToShow.Style then TextItalicRadioOn.Checked := True else TextItalicRadioOff.Checked := True; TextUnderlineCheckBox.Checked := (fsUnderline in AttrToShow.Style) or (fsUnderline in AttrToShow.StyleMask); TextUnderlineRadioPanel.Enabled := TextUnderlineCheckBox.Checked; if not(fsUnderline in AttrToShow.StyleMask) then TextUnderlineRadioInvert.Checked := True else if fsUnderline in AttrToShow.Style then TextUnderlineRadioOn.Checked := True else TextUnderlineRadioOff.Checked := True; TextStrikeOutCheckBox.Checked := (fsStrikeOut in AttrToShow.Style) or (fsStrikeOut in AttrToShow.StyleMask); TextStrikeOutRadioPanel.Enabled := TextStrikeOutCheckBox.Checked; if not(fsStrikeOut in AttrToShow.StyleMask) then TextStrikeOutRadioInvert.Checked := True else if fsStrikeOut in AttrToShow.Style then TextStrikeOutRadioOn.Checked := True else TextStrikeOutRadioOff.Checked := True; end else begin TextBoldCheckBox.Checked := fsBold in AttrToShow.Style; TextItalicCheckBox.Checked := fsItalic in AttrToShow.Style; TextUnderlineCheckBox.Checked := fsUnderline in AttrToShow.Style; TextStrikeOutCheckBox.Checked := fsStrikeOut in AttrToShow.Style; end; if IsDefault then begin AttrToShow.OnChange:= @SynPlainTextHighlighterChange; end; UpdatingColor := False; finally EnableAlign; end; pnlElementAttributesResize(nil); end; procedure TfrmOptionsEditorColors.GeneralCheckBoxOnChange(Sender: TObject); var TheColorBox: TColorBox; AttrToEdit: TSynHighlighterAttributes; procedure SetCheckBoxStyle(CheckBox: TCheckBox; style: TFontStyle); begin if hafStyleMask in AttrToEdit.Features then TextStyleRadioOnChange(Sender) else if CheckBox.Checked xor (style in AttrToEdit.Style) then begin if CheckBox.Checked then AttrToEdit.Style := AttrToEdit.Style + [style] else AttrToEdit.Style := AttrToEdit.Style - [style]; UpdateCurrentScheme; end; end; begin if FCurHighlightElement = nil then Exit; if FIsEditingDefaults then AttrToEdit := FDefHighlightElement else AttrToEdit := FCurHighlightElement; if UpdatingColor = False then begin UpdatingColor := True; TheColorBox := nil; if Sender = ForeGroundUseDefaultCheckBox then TheColorBox := ForegroundColorBox; if Sender = BackGroundUseDefaultCheckBox then TheColorBox := BackGroundColorBox; if Sender = FrameColorUseDefaultCheckBox then TheColorBox := FrameColorBox; if Assigned(TheColorBox) then begin if TCheckBox(Sender).Checked then begin TheColorBox.Selected := TheColorBox.Tag; if (AttrToEdit is TSynAttributes) then begin if (Sender = ForeGroundUseDefaultCheckBox) then begin TSynAttributes(AttrToEdit).ParentForeground:= False; end else if (Sender = BackGroundUseDefaultCheckBox) then begin TSynAttributes(AttrToEdit).ParentBackground:= False; end; end; end else begin TheColorBox.Tag := TheColorBox.Selected; if not (AttrToEdit is TSynAttributes) then TheColorBox.Selected := clDefault else if Assigned(ColorElementTree.Selected) and Assigned(ColorElementTree.Selected.Parent) then begin if (Sender = ForeGroundUseDefaultCheckBox) then begin TSynAttributes(AttrToEdit).ParentForeground:= True; TheColorBox.Selected := TSynRange(ColorElementTree.Selected.Parent.Data).Attribs.Foreground end else if (Sender = BackGroundUseDefaultCheckBox) then begin TSynAttributes(AttrToEdit).ParentBackground:= True; TheColorBox.Selected := TSynRange(ColorElementTree.Selected.Parent.Data).Attribs.Background; end; end; end; if (Sender = ForeGroundUseDefaultCheckBox) and (DefaultToNone(ForegroundColorBox.Selected) <> AttrToEdit.Foreground) then begin AttrToEdit.Foreground := DefaultToNone(ForegroundColorBox.Selected); UpdateCurrentScheme; end; if (Sender = BackGroundUseDefaultCheckBox) and (DefaultToNone(BackGroundColorBox.Selected) <> AttrToEdit.Background) then begin AttrToEdit.Background := DefaultToNone(BackGroundColorBox.Selected); UpdateCurrentScheme; end; if (Sender = FrameColorUseDefaultCheckBox) and (DefaultToNone(FrameColorBox.Selected) <> AttrToEdit.FrameColor) then begin AttrToEdit.FrameColor := DefaultToNone(FrameColorBox.Selected); FrameEdgesBox.Enabled := TCheckBox(Sender).Checked; FrameStyleBox.Enabled := TCheckBox(Sender).Checked; UpdateCurrentScheme; end; end; UpdatingColor := False; end; if Sender = TextBoldCheckBox then SetCheckBoxStyle(TextBoldCheckBox, fsBold); if Sender = TextItalicCheckBox then SetCheckBoxStyle(TextItalicCheckBox, fsItalic); if Sender = TextUnderlineCheckBox then SetCheckBoxStyle(TextUnderlineCheckBox, fsUnderline); if Sender = TextStrikeOutCheckBox then SetCheckBoxStyle(TextStrikeOutCheckBox, fsStrikeOut); end; procedure TfrmOptionsEditorColors.pnlElementAttributesResize(Sender: TObject); //+++ var MinAnchor: TControl; MinWidth: Integer; procedure CheckControl(Other: TControl); var w: Integer = 0; h: Integer = 0; begin if not Other.Visible then exit; Other.GetPreferredSize(w,h); if w <= MinWidth then exit; MinAnchor := Other; MinWidth := w; end; begin MinWidth := -1; MinAnchor := ForeGroundLabel; CheckControl(ForeGroundLabel); CheckControl(BackGroundLabel); CheckControl(ForeGroundUseDefaultCheckBox); CheckControl(BackGroundUseDefaultCheckBox); CheckControl(FrameColorUseDefaultCheckBox); ColumnPosBevel.AnchorSide[akLeft].Control := MinAnchor; end; procedure TfrmOptionsEditorColors.tbtnGlobalClick(Sender: TObject); begin if (FCurHighlightElement = nil) or UpdatingColor then Exit; FCurrentHighlighter.Tag := PtrInt(tbtnGlobal.Down); ColorElementTreeChange(ColorElementTree, nil); UpdateCurrentScheme; end; procedure TfrmOptionsEditorColors.TextStyleRadioOnChange(Sender: TObject); //+++ var AttrToEdit: TSynHighlighterAttributes; procedure CalcNewStyle(CheckBox: TCheckBox; RadioOn, RadioOff, RadioInvert: TRadioButton; fs : TFontStyle; Panel: TPanel); begin if CheckBox.Checked then begin Panel.Enabled := True; if RadioInvert.Checked then begin AttrToEdit.Style := AttrToEdit.Style + [fs]; AttrToEdit.StyleMask := AttrToEdit.StyleMask - [fs]; end else if RadioOn.Checked then begin AttrToEdit.Style := AttrToEdit.Style + [fs]; AttrToEdit.StyleMask := AttrToEdit.StyleMask + [fs]; end else if RadioOff.Checked then begin AttrToEdit.Style := AttrToEdit.Style - [fs]; AttrToEdit.StyleMask := AttrToEdit.StyleMask + [fs]; end end else begin Panel.Enabled := False; AttrToEdit.Style := AttrToEdit.Style - [fs]; AttrToEdit.StyleMask := AttrToEdit.StyleMask - [fs]; end; end; begin if UpdatingColor or not (hafStyleMask in FCurHighlightElement.Features) then Exit; if FIsEditingDefaults then AttrToEdit := FDefHighlightElement else AttrToEdit := FCurHighlightElement; if (Sender = TextBoldCheckBox) or (Sender = TextBoldRadioOn) or (Sender = TextBoldRadioOff) or (Sender = TextBoldRadioInvert) then CalcNewStyle(TextBoldCheckBox, TextBoldRadioOn, TextBoldRadioOff, TextBoldRadioInvert, fsBold, TextBoldRadioPanel); if (Sender = TextItalicCheckBox) or (Sender = TextItalicRadioOn) or (Sender = TextItalicRadioOff) or (Sender = TextItalicRadioInvert) then CalcNewStyle(TextItalicCheckBox, TextItalicRadioOn, TextItalicRadioOff, TextItalicRadioInvert, fsItalic, TextItalicRadioPanel); if (Sender = TextUnderlineCheckBox) or (Sender = TextUnderlineRadioOn) or (Sender = TextUnderlineRadioOff) or (Sender = TextUnderlineRadioInvert) then CalcNewStyle(TextUnderlineCheckBox, TextUnderlineRadioOn, TextUnderlineRadioOff, TextUnderlineRadioInvert, fsUnderline, TextUnderlineRadioPanel); if (Sender = TextStrikeOutCheckBox) or (Sender = TextStrikeOutRadioOn) or (Sender = TextStrikeOutRadioOff) or (Sender = TextStrikeOutRadioInvert) then CalcNewStyle(TextStrikeOutCheckBox, TextStrikeOutRadioOn, TextStrikeOutRadioOff, TextStrikeOutRadioInvert, fsStrikeOut, TextStrikeOutRadioPanel); end; procedure TfrmOptionsEditorColors.UpdateCurrentScheme; begin ColorPreview.Invalidate; ColorElementTree.Invalidate; end; function TfrmOptionsEditorColors.TreeAddSet(Node: TTreeNode; SymbSet: TSynSet ): TTreeNode; begin Result:= ColorElementTree.Items.AddChild(Node, SymbSet.Name); Result.Data:= SymbSet; end; function TfrmOptionsEditorColors.TreeAddRange(Node: TTreeNode; Range: TSynRange ): TTreeNode; var Index: Integer; begin if (Node = nil) then Result:= ColorElementTree.Items.Add(nil, Range.Name) else begin Result:= ColorElementTree.Items.AddChild(Node, Range.Name); end; Result.Data:= Range; for Index := 0 to Range.SetCount - 1 do TreeAddSet(Result, Range.Sets[Index]); for Index := 0 to Range.RangeCount - 1 do TreeAddRange(Result, Range.Ranges[Index]); for Index := 0 to Range.KeyListCount - 1 do TreeAddKeyList(Result, Range.KeyLists[Index]); end; function TfrmOptionsEditorColors.TreeAddKeyList(Node: TTreeNode; KeyList: TSynKeyList): TTreeNode; begin Result:= ColorElementTree.Items.AddChild(Node, KeyList.Name); Result.Data:= KeyList; end; procedure TfrmOptionsEditorColors.Init; begin inherited Init; FontOptionsToFont(gFonts[dcfEditor], ColorPreview.Font); end; procedure TfrmOptionsEditorColors.Done; begin FHighl.Free; inherited Done; end; procedure TfrmOptionsEditorColors.Load; begin if (FHighl = nil) then FHighl:= dmHighl.Clone else begin FHighl.Assign(dmHighl); end; cmbLanguage.Items.Assign(FHighl.SynHighlighterList); cmbLanguage.ItemIndex:= 0; cmbLanguageChange(nil); end; function TfrmOptionsEditorColors.Save: TOptionsEditorSaveFlags; begin Result:= []; dmHighl.Assign(FHighl); end; procedure TfrmOptionsEditorColors.CMThemeChanged(var Message: TLMessage); begin Load; end; class function TfrmOptionsEditorColors.GetIconIndex: Integer; begin Result:= 21; end; class function TfrmOptionsEditorColors.GetTitle: String; begin Result:= rsOptionsEditorHighlighters; end; { TfrmOptionsEditorColors.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsEditorColors.IsSignatureComputedFromAllWindowComponents: Boolean; begin Result := False; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfavoritetabs.lfm������������������������������������������������0000644�0001750�0000144�00000045537�14743153644�021643� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFavoriteTabs: TfrmOptionsFavoriteTabs Height = 604 Width = 584 HelpKeyword = '/configuration.html#ConfigFavoriteTabs' AutoSize = True ClientHeight = 604 ClientWidth = 584 Constraints.MinHeight = 400 Constraints.MinWidth = 500 OnEnter = FrameEnter ParentShowHint = False PopupMenu = pmTreeView ShowHint = True DesignLeft = 190 DesignTop = 277 object gbFavoriteTabs: TGroupBox[0] Left = 6 Height = 592 Top = 6 Width = 572 Align = alClient AutoSize = True BorderSpacing.Around = 6 Caption = 'Favorite Tabs list (reorder by drag && drop)' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 572 ClientWidth = 568 TabOrder = 0 object pnlClient: TPanel AnchorSideLeft.Control = gbFavoriteTabs AnchorSideTop.Control = gbFavoriteTabs AnchorSideRight.Control = gbFavoriteTabs AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gpSavedTabsRestorationAction Left = 6 Height = 418 Top = 6 Width = 556 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 418 ClientWidth = 556 TabOrder = 0 object tvFavoriteTabs: TTreeView AnchorSideLeft.Control = pnlClient AnchorSideTop.Control = pnlClient AnchorSideRight.Control = pnlButtons AnchorSideBottom.Control = pnlClient AnchorSideBottom.Side = asrBottom Left = 0 Height = 418 Top = 0 Width = 401 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Right = 6 DefaultItemHeight = 18 DragMode = dmAutomatic HotTrack = True MultiSelect = True MultiSelectStyle = [msControlSelect, msShiftSelect, msVisibleOnly, msSiblingOnly] ParentColor = True PopupMenu = pmTreeView ReadOnly = True ScrollBars = ssAutoBoth SelectionColor = clBtnShadow TabOrder = 0 ToolTips = False OnDblClick = btnRenameClick OnDragDrop = tvFavoriteTabsDragDrop OnDragOver = tvFavoriteTabsDragOver OnEnter = tvFavoriteTabsEnter OnExit = tvFavoriteTabsExit OnSelectionChanged = tvFavoriteTabsSelectionChanged Options = [tvoAllowMultiselect, tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot] end object pnlButtons: TPanel AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlClient AnchorSideRight.Control = pnlClient AnchorSideRight.Side = asrBottom Left = 407 Height = 249 Top = 0 Width = 149 Anchors = [akTop, akRight] AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 249 ClientWidth = 149 TabOrder = 1 object btnInsert: TBitBtn Tag = 1 AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnRename AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 37 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Insert...' OnClick = btnActionClick TabOrder = 1 end object btnDelete: TBitBtn Tag = 3 AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnAdd AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 99 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Delete...' OnClick = btnActionClick TabOrder = 3 end object btnImportExport: TBitBtn Tag = 7 AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnSort AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 161 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Import/Export' OnClick = btnActionClick TabOrder = 5 end object btnAdd: TBitBtn Tag = 2 AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnInsert AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 68 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Add...' OnClick = btnActionClick TabOrder = 2 end object btnSort: TBitBtn Tag = 8 AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnDelete AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 130 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Sort...' OnClick = btnActionClick TabOrder = 4 end object btnRename: TBitBtn Tag = 1 AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = pnlButtons AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 6 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Rename' OnClick = btnRenameClick TabOrder = 0 end object gbFavoriteTabsOtherOptions: TGroupBox AnchorSideLeft.Control = pnlButtons AnchorSideTop.Control = btnImportExport AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 51 Top = 192 Width = 137 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 6 Caption = 'Other options' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 31 ClientWidth = 133 TabOrder = 6 object cbFullExpandTree: TCheckBox AnchorSideLeft.Control = gbFavoriteTabsOtherOptions AnchorSideTop.Control = gbFavoriteTabsOtherOptions Left = 6 Height = 19 Top = 6 Width = 121 Caption = 'Always expand tree' OnChange = cbFullExpandTreeChange TabOrder = 0 end end end end object gpSavedTabsRestorationAction: TGroupBox AnchorSideLeft.Control = gbFavoriteTabs AnchorSideRight.Control = gbFavoriteTabs AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gbFavoriteTabs AnchorSideBottom.Side = asrBottom Left = 6 Height = 142 Top = 424 Width = 556 Anchors = [akLeft, akRight, akBottom] AutoSize = True Caption = 'What to restore where for the selected entry:' ChildSizing.TopBottomSpacing = 6 ClientHeight = 122 ClientWidth = 552 TabOrder = 1 object lblTargetPanelLeftSavedTabs: TLabel AnchorSideTop.Control = cbTargetPanelLeftSavedTabs AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTargetPanelRightSavedTabs AnchorSideRight.Side = asrBottom Left = 159 Height = 15 Top = 10 Width = 187 Anchors = [akTop, akRight] Caption = 'Tabs saved on left to be restored to:' ParentColor = False end object lblTargetPanelRightSavedTabs: TLabel AnchorSideTop.Control = cbTargetPanelRightSavedTabs AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbTargetPanelRightSavedTabs Left = 151 Height = 15 Top = 39 Width = 195 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Tabs saved on right to be restored to:' ParentColor = False end object lblExistingTabsToKeep: TLabel AnchorSideTop.Control = cbExistingTabsToKeep AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbExistingTabsToKeep Left = 236 Height = 15 Top = 68 Width = 110 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Existing tabs to keep:' ParentColor = False end object cbExistingTabsToKeep: TComboBox Tag = 3 AnchorSideLeft.Control = cbTargetPanelLeftSavedTabs AnchorSideTop.Control = cbTargetPanelRightSavedTabs AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTargetPanelLeftSavedTabs AnchorSideRight.Side = asrBottom Left = 350 Height = 23 Top = 64 Width = 192 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ItemHeight = 15 ItemIndex = 5 Items.Strings = ( 'Left' 'Right' 'Active' 'Inactive' 'Both' 'None' ) OnChange = cbTabsConfigChange Style = csDropDownList TabOrder = 2 Text = 'None' end object cbTargetPanelRightSavedTabs: TComboBox Tag = 2 AnchorSideLeft.Control = cbTargetPanelLeftSavedTabs AnchorSideTop.Control = cbTargetPanelLeftSavedTabs AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTargetPanelLeftSavedTabs AnchorSideRight.Side = asrBottom Left = 350 Height = 23 Top = 35 Width = 192 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ItemHeight = 15 ItemIndex = 1 Items.Strings = ( 'Left' 'Right' 'Active' 'Inactive' 'Both' 'None' ) OnChange = cbTabsConfigChange Style = csDropDownList TabOrder = 1 Text = 'Right' end object cbTargetPanelLeftSavedTabs: TComboBox Tag = 1 AnchorSideLeft.Control = gpSavedTabsRestorationAction AnchorSideTop.Control = gpSavedTabsRestorationAction AnchorSideRight.Control = gpSavedTabsRestorationAction AnchorSideRight.Side = asrBottom Left = 350 Height = 23 Top = 6 Width = 192 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 350 BorderSpacing.Top = 6 BorderSpacing.Right = 10 ItemHeight = 15 ItemIndex = 0 Items.Strings = ( 'Left' 'Right' 'Active' 'Inactive' 'Both' 'None' ) OnChange = cbTabsConfigChange Style = csDropDownList TabOrder = 0 Text = 'Left' end object cbSaveDirHistory: TComboBox Tag = 4 AnchorSideLeft.Control = cbTargetPanelLeftSavedTabs AnchorSideTop.Control = cbExistingTabsToKeep AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTargetPanelLeftSavedTabs AnchorSideRight.Side = asrBottom Left = 350 Height = 23 Top = 93 Width = 192 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 ItemHeight = 15 ItemIndex = 0 Items.Strings = ( 'No' 'Yes' ) OnChange = cbTabsConfigChange Style = csDropDownList TabOrder = 3 Text = 'No' end object lblSaveDirHistory: TLabel AnchorSideTop.Control = cbSaveDirHistory AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbExistingTabsToKeep Left = 263 Height = 15 Top = 97 Width = 83 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Save dir history:' ParentColor = False end end end object pmFavoriteTabsTestMenu: TPopupMenu[1] left = 96 top = 336 object miFavoriteTabsTestMenu: TMenuItem Caption = 'FavoriteTabsTestMenu' end end object pmTreeView: TPopupMenu[2] left = 96 top = 272 object miRename: TMenuItem Caption = 'Rename' ShortCut = 117 OnClick = btnRenameClick end object MenuItem1: TMenuItem Caption = '-' end object miInsertSeparator: TMenuItem Tag = 17 Caption = 'Insert separator' ShortCut = 8313 OnClick = miInsertAddFavoriteTabsClick end object miAddSeparator2: TMenuItem Tag = 33 Caption = 'Add separator' ShortCut = 121 OnClick = miInsertAddFavoriteTabsClick end object MenuItem2: TMenuItem Caption = '-' end object miInsertSubMenu: TMenuItem Tag = 18 Caption = 'Insert sub-menu' ShortCut = 8310 OnClick = miInsertAddFavoriteTabsClick end object miAddSubmenu2: TMenuItem Tag = 34 Caption = 'Add sub-menu' ShortCut = 118 OnClick = miInsertAddFavoriteTabsClick end object miSeparator7: TMenuItem Caption = '-' end object miDeleteSelectedEntry2: TMenuItem Tag = 1 Caption = 'Delete selected item' ShortCut = 46 OnClick = miDeleteSelectedEntryClick end object miSeparator8: TMenuItem Caption = '-' end object miSortSingleGroup2: TMenuItem Tag = 1 Caption = 'Sort single group of item(s) only' ShortCut = 113 OnClick = miSortFavoriteTabsClick end object miSeparator9: TMenuItem Caption = '-' end object miCutSelection: TMenuItem Caption = 'Cut' ShortCut = 16472 OnClick = miCutSelectionClick end object miPasteSelection: TMenuItem Caption = 'Paste' Enabled = False ShortCut = 16470 OnClick = miPasteSelectionClick end object miSeparator1: TMenuItem Caption = '-' end object miImportLegacyTabFilesAtPos1: TMenuItem Tag = 1 Caption = 'Import legacy .tab file(s) at selected position' OnClick = miImportLegacyTabFilesClick end end object pmInsertAddToFavoriteTabs: TPopupMenu[3] left = 96 top = 40 object miAddSeparator: TMenuItem Tag = 1 Caption = 'a separator' ShortCut = 121 OnClick = miInsertAddFavoriteTabsClick end object miAddSubmenu: TMenuItem Tag = 2 Caption = 'sub-menu' ShortCut = 118 OnClick = miInsertAddFavoriteTabsClick end end object pmDeleteFavoriteTabs: TPopupMenu[4] left = 96 top = 96 object miDeleteSelectedEntry: TMenuItem Tag = 1 Caption = 'selected item' ShortCut = 119 OnClick = miDeleteSelectedEntryClick end object miSeparator2: TMenuItem Caption = '-' end object miDeleteJustSubMenu: TMenuItem Tag = 2 Caption = 'just sub-menu but keep elements' OnClick = miDeleteSelectedEntryClick end object miDeleteCompleteSubMenu: TMenuItem Tag = 3 Caption = 'sub-menu and all its elements' OnClick = miDeleteSelectedEntryClick end object miSeparator3: TMenuItem Caption = '-' end object miDeleteAllFavoriteTabs: TMenuItem Caption = 'delete all!' OnClick = miDeleteAllFavoriteTabsClick end end object pmImportExport: TPopupMenu[5] left = 96 top = 216 object miImportLegacyTabFilesAtPos: TMenuItem Tag = 1 Caption = 'Import legacy .tab file(s) at selected position' OnClick = miImportLegacyTabFilesClick end object miImportLegacyTabFilesAccSetting: TMenuItem Caption = 'Import legacy .tab file(s) according to default setting' OnClick = miImportLegacyTabFilesClick end object miImportLegacyTabFilesInSubAtPos: TMenuItem Tag = 2 Caption = 'Import legacy .tab file(s) at selected position in a sub menu' OnClick = miImportLegacyTabFilesClick end object miExportToLegacyTabsFile: TMenuItem Caption = 'Export selection to legacy .tab file(s)' OnClick = miExportToLegacyTabsFileClick end object miSeparator10: TMenuItem Caption = '-' end object miTestResultingFavoriteTabsMenu: TMenuItem Caption = 'Test resulting menu' OnClick = miTestResultingFavoriteTabsMenuClick end object miSeparator11: TMenuItem Caption = '-' end object miOpenAllBranches: TMenuItem Caption = 'Open all branches' OnClick = miOpenAllBranchesClick end object miCollapseAll: TMenuItem Caption = 'Collapse all' OnClick = miCollapseAllClick end end object pmSortFavoriteTabsList: TPopupMenu[6] left = 96 top = 152 object miSortSingleGroup: TMenuItem Tag = 1 Caption = '...single group of item(s) only' OnClick = miSortFavoriteTabsClick end object miCurrentLevelOfItemOnly: TMenuItem Tag = 2 Caption = '...current level of item(s) selected only' OnClick = miSortFavoriteTabsClick end object miSortSingleSubMenu: TMenuItem Tag = 3 Caption = '...content of submenu(s) selected, no sublevel' OnClick = miSortFavoriteTabsClick end object miSortSubMenuAndSubLevel: TMenuItem Tag = 4 Caption = '...content of submenu(s) selected and all sublevels' OnClick = miSortFavoriteTabsClick end object miSortEverything: TMenuItem Tag = 5 Caption = '...everything, from A to Z!' OnClick = miSortFavoriteTabsClick end end object OpenDialog: TOpenDialog[7] Filter = 'Legacy DC .tab files|*.tab|Any files|*.*' FilterIndex = 0 Options = [ofAllowMultiSelect, ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] left = 96 top = 392 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfavoritetabs.lrj������������������������������������������������0000644�0001750�0000144�00000023355�14743153644�021646� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":177388665,"name":"tfrmoptionsfavoritetabs.gbfavoritetabs.caption","sourcebytes":[70,97,118,111,114,105,116,101,32,84,97,98,115,32,108,105,115,116,32,40,114,101,111,114,100,101,114,32,98,121,32,100,114,97,103,32,38,38,32,100,114,111,112,41],"value":"Favorite Tabs list (reorder by drag && drop)"}, {"hash":164184414,"name":"tfrmoptionsfavoritetabs.btninsert.caption","sourcebytes":[73,110,115,101,114,116,46,46,46],"value":"Insert..."}, {"hash":46812110,"name":"tfrmoptionsfavoritetabs.btndelete.caption","sourcebytes":[68,101,108,101,116,101,46,46,46],"value":"Delete..."}, {"hash":59252692,"name":"tfrmoptionsfavoritetabs.btnimportexport.caption","sourcebytes":[73,109,112,111,114,116,47,69,120,112,111,114,116],"value":"Import/Export"}, {"hash":75133198,"name":"tfrmoptionsfavoritetabs.btnadd.caption","sourcebytes":[65,100,100,46,46,46],"value":"Add..."}, {"hash":174682462,"name":"tfrmoptionsfavoritetabs.btnsort.caption","sourcebytes":[83,111,114,116,46,46,46],"value":"Sort..."}, {"hash":93079605,"name":"tfrmoptionsfavoritetabs.btnrename.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, {"hash":13910547,"name":"tfrmoptionsfavoritetabs.gbfavoritetabsotheroptions.caption","sourcebytes":[79,116,104,101,114,32,111,112,116,105,111,110,115],"value":"Other options"}, {"hash":92837685,"name":"tfrmoptionsfavoritetabs.cbfullexpandtree.caption","sourcebytes":[65,108,119,97,121,115,32,101,120,112,97,110,100,32,116,114,101,101],"value":"Always expand tree"}, {"hash":241981898,"name":"tfrmoptionsfavoritetabs.gpsavedtabsrestorationaction.caption","sourcebytes":[87,104,97,116,32,116,111,32,114,101,115,116,111,114,101,32,119,104,101,114,101,32,102,111,114,32,116,104,101,32,115,101,108,101,99,116,101,100,32,101,110,116,114,121,58],"value":"What to restore where for the selected entry:"}, {"hash":174798330,"name":"tfrmoptionsfavoritetabs.lbltargetpanelleftsavedtabs.caption","sourcebytes":[84,97,98,115,32,115,97,118,101,100,32,111,110,32,108,101,102,116,32,116,111,32,98,101,32,114,101,115,116,111,114,101,100,32,116,111,58],"value":"Tabs saved on left to be restored to:"}, {"hash":69682042,"name":"tfrmoptionsfavoritetabs.lbltargetpanelrightsavedtabs.caption","sourcebytes":[84,97,98,115,32,115,97,118,101,100,32,111,110,32,114,105,103,104,116,32,116,111,32,98,101,32,114,101,115,116,111,114,101,100,32,116,111,58],"value":"Tabs saved on right to be restored to:"}, {"hash":29650394,"name":"tfrmoptionsfavoritetabs.lblexistingtabstokeep.caption","sourcebytes":[69,120,105,115,116,105,110,103,32,116,97,98,115,32,116,111,32,107,101,101,112,58],"value":"Existing tabs to keep:"}, {"hash":349765,"name":"tfrmoptionsfavoritetabs.cbexistingtabstokeep.text","sourcebytes":[78,111,110,101],"value":"None"}, {"hash":5832180,"name":"tfrmoptionsfavoritetabs.cbtargetpanelrightsavedtabs.text","sourcebytes":[82,105,103,104,116],"value":"Right"}, {"hash":338900,"name":"tfrmoptionsfavoritetabs.cbtargetpanelleftsavedtabs.text","sourcebytes":[76,101,102,116],"value":"Left"}, {"hash":1359,"name":"tfrmoptionsfavoritetabs.cbsavedirhistory.text","sourcebytes":[78,111],"value":"No"}, {"hash":128230250,"name":"tfrmoptionsfavoritetabs.lblsavedirhistory.caption","sourcebytes":[83,97,118,101,32,100,105,114,32,104,105,115,116,111,114,121,58],"value":"Save dir history:"}, {"hash":249182357,"name":"tfrmoptionsfavoritetabs.mifavoritetabstestmenu.caption","sourcebytes":[70,97,118,111,114,105,116,101,84,97,98,115,84,101,115,116,77,101,110,117],"value":"FavoriteTabsTestMenu"}, {"hash":93079605,"name":"tfrmoptionsfavoritetabs.mirename.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, {"hash":169604914,"name":"tfrmoptionsfavoritetabs.miinsertseparator.caption","sourcebytes":[73,110,115,101,114,116,32,115,101,112,97,114,97,116,111,114],"value":"Insert separator"}, {"hash":19854562,"name":"tfrmoptionsfavoritetabs.miaddseparator2.caption","sourcebytes":[65,100,100,32,115,101,112,97,114,97,116,111,114],"value":"Add separator"}, {"hash":43716005,"name":"tfrmoptionsfavoritetabs.miinsertsubmenu.caption","sourcebytes":[73,110,115,101,114,116,32,115,117,98,45,109,101,110,117],"value":"Insert sub-menu"}, {"hash":256531957,"name":"tfrmoptionsfavoritetabs.miaddsubmenu2.caption","sourcebytes":[65,100,100,32,115,117,98,45,109,101,110,117],"value":"Add sub-menu"}, {"hash":248058829,"name":"tfrmoptionsfavoritetabs.mideleteselectedentry2.caption","sourcebytes":[68,101,108,101,116,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109],"value":"Delete selected item"}, {"hash":54478841,"name":"tfrmoptionsfavoritetabs.misortsinglegroup2.caption","sourcebytes":[83,111,114,116,32,115,105,110,103,108,101,32,103,114,111,117,112,32,111,102,32,105,116,101,109,40,115,41,32,111,110,108,121],"value":"Sort single group of item(s) only"}, {"hash":19140,"name":"tfrmoptionsfavoritetabs.micutselection.caption","sourcebytes":[67,117,116],"value":"Cut"}, {"hash":5671589,"name":"tfrmoptionsfavoritetabs.mipasteselection.caption","sourcebytes":[80,97,115,116,101],"value":"Paste"}, {"hash":75328558,"name":"tfrmoptionsfavoritetabs.miimportlegacytabfilesatpos1.caption","sourcebytes":[73,109,112,111,114,116,32,108,101,103,97,99,121,32,46,116,97,98,32,102,105,108,101,40,115,41,32,97,116,32,115,101,108,101,99,116,101,100,32,112,111,115,105,116,105,111,110],"value":"Import legacy .tab file(s) at selected position"}, {"hash":116126882,"name":"tfrmoptionsfavoritetabs.miaddseparator.caption","sourcebytes":[97,32,115,101,112,97,114,97,116,111,114],"value":"a separator"}, {"hash":190070261,"name":"tfrmoptionsfavoritetabs.miaddsubmenu.caption","sourcebytes":[115,117,98,45,109,101,110,117],"value":"sub-menu"}, {"hash":44413037,"name":"tfrmoptionsfavoritetabs.mideleteselectedentry.caption","sourcebytes":[115,101,108,101,99,116,101,100,32,105,116,101,109],"value":"selected item"}, {"hash":252451043,"name":"tfrmoptionsfavoritetabs.mideletejustsubmenu.caption","sourcebytes":[106,117,115,116,32,115,117,98,45,109,101,110,117,32,98,117,116,32,107,101,101,112,32,101,108,101,109,101,110,116,115],"value":"just sub-menu but keep elements"}, {"hash":1127059,"name":"tfrmoptionsfavoritetabs.mideletecompletesubmenu.caption","sourcebytes":[115,117,98,45,109,101,110,117,32,97,110,100,32,97,108,108,32,105,116,115,32,101,108,101,109,101,110,116,115],"value":"sub-menu and all its elements"}, {"hash":169656353,"name":"tfrmoptionsfavoritetabs.mideleteallfavoritetabs.caption","sourcebytes":[100,101,108,101,116,101,32,97,108,108,33],"value":"delete all!"}, {"hash":75328558,"name":"tfrmoptionsfavoritetabs.miimportlegacytabfilesatpos.caption","sourcebytes":[73,109,112,111,114,116,32,108,101,103,97,99,121,32,46,116,97,98,32,102,105,108,101,40,115,41,32,97,116,32,115,101,108,101,99,116,101,100,32,112,111,115,105,116,105,111,110],"value":"Import legacy .tab file(s) at selected position"}, {"hash":190394839,"name":"tfrmoptionsfavoritetabs.miimportlegacytabfilesaccsetting.caption","sourcebytes":[73,109,112,111,114,116,32,108,101,103,97,99,121,32,46,116,97,98,32,102,105,108,101,40,115,41,32,97,99,99,111,114,100,105,110,103,32,116,111,32,100,101,102,97,117,108,116,32,115,101,116,116,105,110,103],"value":"Import legacy .tab file(s) according to default setting"}, {"hash":137181669,"name":"tfrmoptionsfavoritetabs.miimportlegacytabfilesinsubatpos.caption","sourcebytes":[73,109,112,111,114,116,32,108,101,103,97,99,121,32,46,116,97,98,32,102,105,108,101,40,115,41,32,97,116,32,115,101,108,101,99,116,101,100,32,112,111,115,105,116,105,111,110,32,105,110,32,97,32,115,117,98,32,109,101,110,117],"value":"Import legacy .tab file(s) at selected position in a sub menu"}, {"hash":106971481,"name":"tfrmoptionsfavoritetabs.miexporttolegacytabsfile.caption","sourcebytes":[69,120,112,111,114,116,32,115,101,108,101,99,116,105,111,110,32,116,111,32,108,101,103,97,99,121,32,46,116,97,98,32,102,105,108,101,40,115,41],"value":"Export selection to legacy .tab file(s)"}, {"hash":49637221,"name":"tfrmoptionsfavoritetabs.mitestresultingfavoritetabsmenu.caption","sourcebytes":[84,101,115,116,32,114,101,115,117,108,116,105,110,103,32,109,101,110,117],"value":"Test resulting menu"}, {"hash":240129107,"name":"tfrmoptionsfavoritetabs.miopenallbranches.caption","sourcebytes":[79,112,101,110,32,97,108,108,32,98,114,97,110,99,104,101,115],"value":"Open all branches"}, {"hash":53565100,"name":"tfrmoptionsfavoritetabs.micollapseall.caption","sourcebytes":[67,111,108,108,97,112,115,101,32,97,108,108],"value":"Collapse all"}, {"hash":189620809,"name":"tfrmoptionsfavoritetabs.misortsinglegroup.caption","sourcebytes":[46,46,46,115,105,110,103,108,101,32,103,114,111,117,112,32,111,102,32,105,116,101,109,40,115,41,32,111,110,108,121],"value":"...single group of item(s) only"}, {"hash":130527337,"name":"tfrmoptionsfavoritetabs.micurrentlevelofitemonly.caption","sourcebytes":[46,46,46,99,117,114,114,101,110,116,32,108,101,118,101,108,32,111,102,32,105,116,101,109,40,115,41,32,115,101,108,101,99,116,101,100,32,111,110,108,121],"value":"...current level of item(s) selected only"}, {"hash":264540412,"name":"tfrmoptionsfavoritetabs.misortsinglesubmenu.caption","sourcebytes":[46,46,46,99,111,110,116,101,110,116,32,111,102,32,115,117,98,109,101,110,117,40,115,41,32,115,101,108,101,99,116,101,100,44,32,110,111,32,115,117,98,108,101,118,101,108],"value":"...content of submenu(s) selected, no sublevel"}, {"hash":63366227,"name":"tfrmoptionsfavoritetabs.misortsubmenuandsublevel.caption","sourcebytes":[46,46,46,99,111,110,116,101,110,116,32,111,102,32,115,117,98,109,101,110,117,40,115,41,32,115,101,108,101,99,116,101,100,32,97,110,100,32,97,108,108,32,115,117,98,108,101,118,101,108,115],"value":"...content of submenu(s) selected and all sublevels"}, {"hash":193526385,"name":"tfrmoptionsfavoritetabs.misorteverything.caption","sourcebytes":[46,46,46,101,118,101,114,121,116,104,105,110,103,44,32,102,114,111,109,32,65,32,116,111,32,90,33],"value":"...everything, from A to Z!"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfavoritetabs.pas������������������������������������������������0000644�0001750�0000144�00000125172�14743153644�021642� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Configuration of Favorite Tabs Copyright (C) 2016-2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFavoriteTabs; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, ExtCtrls, Menus, Dialogs, ComCtrls, uFavoriteTabs, types, fOptionsFrame; type { TfrmOptionsFavoriteTabs } TfrmOptionsFavoriteTabs = class(TOptionsEditor) btnRename: TBitBtn; cbExistingTabsToKeep: TComboBox; cbFullExpandTree: TCheckBox; cbSaveDirHistory: TComboBox; cbTargetPanelLeftSavedTabs: TComboBox; cbTargetPanelRightSavedTabs: TComboBox; gbFavoriteTabs: TGroupBox; gbFavoriteTabsOtherOptions: TGroupBox; gpSavedTabsRestorationAction: TGroupBox; lblExistingTabsToKeep: TLabel; lblSaveDirHistory: TLabel; lblTargetPanelLeftSavedTabs: TLabel; lblTargetPanelRightSavedTabs: TLabel; MenuItem1: TMenuItem; miImportLegacyTabFilesAtPos1: TMenuItem; miImportLegacyTabFilesInSubAtPos: TMenuItem; miImportLegacyTabFilesAccSetting: TMenuItem; miSeparator1: TMenuItem; miSeparator11: TMenuItem; miExportToLegacyTabsFile: TMenuItem; miImportLegacyTabFilesAtPos: TMenuItem; miRename: TMenuItem; miInsertSeparator: TMenuItem; MenuItem2: TMenuItem; miInsertSubMenu: TMenuItem; OpenDialog: TOpenDialog; pnlClient: TPanel; tvFavoriteTabs: TTreeView; pnlButtons: TPanel; btnInsert: TBitBtn; btnDelete: TBitBtn; btnImportExport: TBitBtn; btnAdd: TBitBtn; btnSort: TBitBtn; pmFavoriteTabsTestMenu: TPopupMenu; miFavoriteTabsTestMenu: TMenuItem; pmTreeView: TPopupMenu; miAddSeparator2: TMenuItem; miAddSubmenu2: TMenuItem; miSeparator7: TMenuItem; miDeleteSelectedEntry2: TMenuItem; miSeparator8: TMenuItem; miSortSingleGroup2: TMenuItem; miSeparator9: TMenuItem; miCutSelection: TMenuItem; miPasteSelection: TMenuItem; pmInsertAddToFavoriteTabs: TPopupMenu; miAddSeparator: TMenuItem; miAddSubmenu: TMenuItem; pmDeleteFavoriteTabs: TPopupMenu; miDeleteSelectedEntry: TMenuItem; miSeparator2: TMenuItem; miDeleteJustSubMenu: TMenuItem; miDeleteCompleteSubMenu: TMenuItem; miSeparator3: TMenuItem; miDeleteAllFavoriteTabs: TMenuItem; pmImportExport: TPopupMenu; miTestResultingFavoriteTabsMenu: TMenuItem; miSeparator10: TMenuItem; miOpenAllBranches: TMenuItem; miCollapseAll: TMenuItem; pmSortFavoriteTabsList: TPopupMenu; miSortSingleGroup: TMenuItem; miCurrentLevelOfItemOnly: TMenuItem; miSortSingleSubMenu: TMenuItem; miSortSubMenuAndSubLevel: TMenuItem; miSortEverything: TMenuItem; procedure btnRenameClick(Sender: TObject); procedure FrameEnter(Sender: TObject); function ActualAddFavoriteTabs(ParamDispatcher: TKindOfFavoriteTabsEntry; sFavoriteTabsName: string; InsertOrAdd: TNodeAttachMode): TTreeNode; function MySortViaGroup(Node1, Node2: TTreeNode): integer; procedure RecursiveSetGroupNumbers(ParamNode: TTreeNode; ParamGroupNumber: integer; DoRecursion, StopAtFirstGroup: boolean); function GetNextGroupNumber: integer; procedure ClearCutAndPasteList; function TryToGetExactFavoriteTabs(const index: integer): TTreeNode; procedure RefreshTreeView(NodeToSelect: TTreeNode); procedure tvFavoriteTabsDragDrop(Sender, {%H-}Source: TObject; X, Y: integer); procedure tvFavoriteTabsDragOver(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure tvFavoriteTabsEnter(Sender: TObject); procedure tvFavoriteTabsExit(Sender: TObject); procedure tvFavoriteTabsSelectionChanged(Sender: TObject); procedure btnActionClick(Sender: TObject); procedure cbFullExpandTreeChange(Sender: TObject); procedure cbTabsConfigChange(Sender: TObject); procedure lbleditFavoriteTabsEnter(Sender: TObject); procedure lbleditFavoriteTabsExit(Sender: TObject); procedure lbleditFavoriteTabsKeyPress(Sender: TObject; var Key: char); procedure miInsertAddFavoriteTabsClick(Sender: TObject); procedure miDeleteSelectedEntryClick(Sender: TObject); procedure miDeleteAllFavoriteTabsClick(Sender: TObject); procedure miSortFavoriteTabsClick(Sender: TObject); function MakeUsUpToDatePriorImportExport: boolean; procedure miExportToLegacyTabsFileClick(Sender: TObject); procedure miImportLegacyTabFilesClick(Sender: TObject); procedure miTestResultingFavoriteTabsMenuClick(Sender: TObject); procedure miShowWhereItWouldGo(Sender: TObject); procedure miOpenAllBranchesClick(Sender: TObject); procedure miCollapseAllClick(Sender: TObject); procedure miCutSelectionClick(Sender: TObject); procedure miPasteSelectionClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; private { Private declarations } FavoriteTabsListTemp: TFavoriteTabsList; CutAndPasteIndexList: TStringList; GlobalGroupNumber: integer; public { Public declarations } class function GetIconIndex: integer; override; class function GetTitle: string; override; destructor Destroy; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; function ExtraOptionsSignature(CurrentSignature:dword):dword; override; procedure MakeUsInPositionToWorkWithActiveFavoriteTabs; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Graphics, LCLType, LCLProc, LCLIntf, //DC DCStrUtils, uGlobs, uLng, uDCUtils, uDebug, fmain, uShowMsg, DCOSUtils, uComponentsSignature; { TfrmOptionsFavoriteTabs.Init } procedure TfrmOptionsFavoriteTabs.Init; begin ParseLineToList(rsFavTabsPanelSideSelection, cbTargetPanelLeftSavedTabs.Items); ParseLineToList(rsFavTabsPanelSideSelection, cbTargetPanelRightSavedTabs.Items); ParseLineToList(rsFavTabsPanelSideSelection, cbExistingTabsToKeep.Items); ParseLineToList(rsFavTabsSaveDirHistory, cbSaveDirHistory.Items); OpenDialog.Filter := ParseLineToFileFilter([rsFilterLegacyTabFiles, '*.tab', rsFilterAnyFiles, AllFilesMask]); end; { TfrmOptionsFavoriteTabs.Load } procedure TfrmOptionsFavoriteTabs.Load; begin gpSavedTabsRestorationAction.Visible := gFavoriteTabsUseRestoreExtraOptions; cbFullExpandTree.Checked := gFavoriteTabsFullExpandOrNot; CutAndPasteIndexList := TStringList.Create; CutAndPasteIndexList.Sorted := True; CutAndPasteIndexList.Duplicates := dupAccept; if FavoriteTabsListTemp = nil then begin FavoriteTabsListTemp := TFavoriteTabsList.Create; gFavoriteTabsList.CopyFavoriteTabsListToFavoriteTabsList(FavoriteTabsListTemp); end; tvFavoriteTabs.Images := frmMain.imgLstDirectoryHotlist; FavoriteTabsListTemp.LoadTTreeView(tvFavoriteTabs); cbFullExpandTreeChange(cbFullExpandTree); if tvFavoriteTabs.Items.Count > 0 then tvFavoriteTabs.Items[0].Selected := True; //Select at least first one by default end; { TfrmOptionsFavoriteTabs.Save } function TfrmOptionsFavoriteTabs.Save: TOptionsEditorSaveFlags; begin Result := []; FavoriteTabsListTemp.RefreshFromTTreeView(tvFavoriteTabs); FavoriteTabsListTemp.CopyFavoriteTabsListToFavoriteTabsList(gFavoriteTabsList); gFavoriteTabsList.RefreshXmlFavoriteTabsListSection; gFavoriteTabsList.RefreshAssociatedMainMenu; gFavoriteTabsFullExpandOrNot := cbFullExpandTree.Checked; cbFullExpandTreeChange(cbFullExpandTree); end; { TfrmOptionsFavoriteTabs.GetIconIndex } class function TfrmOptionsFavoriteTabs.GetIconIndex: integer; begin Result := 37; end; { TfrmOptionsFavoriteTabs.GetTitle } class function TfrmOptionsFavoriteTabs.GetTitle: string; begin Result := rsOptionsEditorFavoriteTabs; end; { TfrmOptionsFavoriteTabs.Destroy } destructor TfrmOptionsFavoriteTabs.Destroy; begin CutAndPasteIndexList.Free; inherited Destroy; end; { TfrmOptionsFavoriteTabs.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsFavoriteTabs.IsSignatureComputedFromAllWindowComponents: boolean; begin result := False; end; { TfrmOptionsFavoriteTabs.ExtraOptionsSignature } function TfrmOptionsFavoriteTabs.ExtraOptionsSignature(CurrentSignature:dword):dword; begin FavoriteTabsListTemp.RefreshFromTTreeView(tvFavoriteTabs); result := FavoriteTabsListTemp.ComputeSignature(CurrentSignature); result := ComputeSignatureSingleComponent(cbFullExpandTree, result); end; { TfrmOptionsFavoriteTabs.MakeUsInPositionToWorkWithActiveFavoriteTabs } procedure TfrmOptionsFavoriteTabs.MakeUsInPositionToWorkWithActiveFavoriteTabs; var NodeToSelect: TTreeNode = nil; begin NodeToSelect := TryToGetExactFavoriteTabs(FavoriteTabsListTemp.GetIndexLastFavoriteTabsLoaded); if (NodeToSelect = nil) and (tvFavoriteTabs.Items.Count > 0) then NodeToSelect := tvFavoriteTabs.Items.Item[0]; RefreshTreeView(NodeToSelect); if not tvFavoriteTabs.Focused then if tvFavoriteTabs.CanFocus then tvFavoriteTabs.SetFocus; end; function CompareStringsFromTStringList(List: TStringList; Index1, Index2: integer): integer; begin Result := CompareStrings(List.Strings[Index1], List.Strings[Index2], gSortNatural, gSortSpecial, gSortCaseSensitivity); end; { TfrmOptionsFavoriteTabs.btnRenameClick } procedure TfrmOptionsFavoriteTabs.btnRenameClick(Sender: TObject); var sInputText: string; FlagDoModif: boolean; begin if tvFavoriteTabs.Selected <> nil then begin if TFavoriteTabs(tvFavoriteTabs.Selected.Data).Dispatcher in [fte_ACTUALFAVTABS, fte_STARTMENU] then begin sInputText := TFavoriteTabs(tvFavoriteTabs.Selected.Data).FavoriteTabsName; case TFavoriteTabs(tvFavoriteTabs.Selected.Data).Dispatcher of fte_ACTUALFAVTABS: FlagDoModif := InputQuery(rsTitleRenameFavTabs, rsMsgRenameFavTabs, sInputText); fte_STARTMENU: FlagDoModif := InputQuery(rsTitleRenameFavTabsMenu, rsMsgRenameFavTabsMenu, sInputText); end; sInputText := Trim(sInputText); if FlagDoModif and (length(sInputText) > 0) then begin TFavoriteTabs(tvFavoriteTabs.Selected.Data).FavoriteTabsName := sInputText; tvFavoriteTabs.Selected.Text := sInputText; end; end; end; end; { TfrmOptionsFavoriteTabs.FrameEnter } procedure TfrmOptionsFavoriteTabs.FrameEnter(Sender: TObject); begin if gpSavedTabsRestorationAction.Visible <> gFavoriteTabsUseRestoreExtraOptions then gpSavedTabsRestorationAction.Visible := gFavoriteTabsUseRestoreExtraOptions; end; { TfrmOptionsFavoriteTabs.ActualAddFavoriteTabs } function TfrmOptionsFavoriteTabs.ActualAddFavoriteTabs(ParamDispatcher: TKindOfFavoriteTabsEntry; sFavoriteTabsName: string; InsertOrAdd: TNodeAttachMode): TTreeNode; var LocalFavoriteTabs: TFavoriteTabs; WorkingTreeNode: TTreeNode; begin ClearCutAndPasteList; LocalFavoriteTabs := TFavoriteTabs.Create; LocalFavoriteTabs.Dispatcher := ParamDispatcher; LocalFavoriteTabs.FavoriteTabsName := sFavoriteTabsName; LocalFavoriteTabs.DestinationForSavedLeftTabs := gDefaultTargetPanelLeftSaved; LocalFavoriteTabs.DestinationForSavedRightTabs := gDefaultTargetPanelRightSaved; LocalFavoriteTabs.ExistingTabsToKeep := gDefaultExistingTabsToKeep; FavoriteTabsListTemp.Add(LocalFavoriteTabs); WorkingTreeNode := tvFavoriteTabs.Selected; if WorkingTreeNode <> nil then Result := tvFavoriteTabs.Items.AddNode(nil, WorkingTreeNode, sFavoriteTabsName, LocalFavoriteTabs, InsertOrAdd) else Result := tvFavoriteTabs.Items.AddNode(nil, nil, sFavoriteTabsName, LocalFavoriteTabs, naAddFirst); end; { TfrmOptionsFavoriteTabs.MySortViaGroup } function TfrmOptionsFavoriteTabs.MySortViaGroup(Node1, Node2: TTreeNode): integer; begin if (TFavoriteTabs(Node1.Data).GroupNumber = TFavoriteTabs(Node2.Data).GroupNumber) and (TFavoriteTabs(Node1.Data).GroupNumber <> 0) then begin Result := CompareStrings(TFavoriteTabs(Node1.Data).FavoriteTabsName, TFavoriteTabs(Node2.Data).FavoriteTabsName, gSortNatural, gSortSpecial, gSortCaseSensitivity); end else begin if Node1.AbsoluteIndex < Node2.AbsoluteIndex then Result := -1 else Result := 1; end; end; { TfrmOptionsFavoriteTabs.RecursiveSetGroupNumbers } // WARNING! This procedure calls itself. procedure TfrmOptionsFavoriteTabs.RecursiveSetGroupNumbers(ParamNode: TTreeNode; ParamGroupNumber: integer; DoRecursion, StopAtFirstGroup: boolean); var MaybeChild: TTreeNode; begin repeat if DoRecursion then begin MaybeChild := ParamNode.GetFirstChild; if MaybeChild <> nil then RecursiveSetGroupNumbers(MaybeChild, GetNextGroupNumber, DoRecursion, StopAtFirstGroup); end; if TFavoriteTabs(ParamNode.Data).Dispatcher <> fte_SEPARATOR then begin TFavoriteTabs(ParamNode.Data).GroupNumber := ParamGroupNumber; end else begin ParamGroupNumber := GetNextGroupNumber; if StopAtFirstGroup then while ParamNode <> nil do ParamNode := ParamNode.GetNextSibling; //To exit the loop! end; if ParamNode <> nil then ParamNode := ParamNode.GetNextSibling; until ParamNode = nil; end; { TfrmOptionsFavoriteTabs.GetNextGroupNumber } function TfrmOptionsFavoriteTabs.GetNextGroupNumber: integer; begin GlobalGroupNumber := GlobalGroupNumber + 1; Result := GlobalGroupNumber; end; { TfrmOptionsFavoriteTabs.ClearCutAndPasteList } procedure TfrmOptionsFavoriteTabs.ClearCutAndPasteList; begin CutAndPasteIndexList.Clear; miPasteSelection.Enabled := True; end; { TfrmOptionsFavoriteTabs.TryToGetExactFavoriteTabs } function TfrmOptionsFavoriteTabs.TryToGetExactFavoriteTabs(const index: integer): TTreeNode; var SearchingtvIndex: integer; begin Result := nil; if (index >= 0) and (index < FavoriteTabsListTemp.Count) then begin SearchingtvIndex := 0; while (SearchingtvIndex < tvFavoriteTabs.Items.Count) and (Result = nil) do begin if tvFavoriteTabs.Items[SearchingtvIndex].Data = FavoriteTabsListTemp.Items[Index] then Result := tvFavoriteTabs.Items[SearchingtvIndex] else Inc(SearchingtvIndex); end; end; end; { TfrmOptionsFavoriteTabs.RefreshTreeView } procedure TfrmOptionsFavoriteTabs.RefreshTreeView(NodeToSelect: TTreeNode); begin if NodeToSelect <> nil then begin tvFavoriteTabs.ClearSelection(False); NodeToSelect.Selected := True; end else begin tvFavoriteTabsSelectionChanged(tvFavoriteTabs); //At least to hide path, target, etc. end; end; { TfrmOptionsFavoriteTabs.tvFavoriteTabsDragDrop } procedure TfrmOptionsFavoriteTabs.tvFavoriteTabsDragDrop(Sender, Source: TObject; X, Y: integer); var Index: longint; DestinationNode: TTreeNode; begin DestinationNode := tvFavoriteTabs.GetNodeAt(X, Y); if Assigned(DestinationNode) and (tvFavoriteTabs.SelectionCount > 0) then begin //If we move toward the end, we place the moved item *after* the destination. //If we move toward the beginning, we place the moved item *before* the destination. if tvFavoriteTabs.Selections[pred(tvFavoriteTabs.SelectionCount)].AbsoluteIndex > DestinationNode.AbsoluteIndex then begin for Index := 0 to pred(tvFavoriteTabs.SelectionCount) do begin tvFavoriteTabs.Selections[Index].MoveTo(DestinationNode, naInsert); end; end else begin for Index := 0 to pred(tvFavoriteTabs.SelectionCount) do begin tvFavoriteTabs.Selections[Index].MoveTo(DestinationNode, naInsertBehind); end; end; ClearCutAndPasteList; end; miPasteSelection.Enabled := False; end; { TfrmOptionsFavoriteTabs.tvFavoriteTabsDragOver } procedure TfrmOptionsFavoriteTabs.tvFavoriteTabsDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin Accept := True; end; { TfrmOptionsFavoriteTabs.tvFavoriteTabsEnter } // To help to catch eye's attention, let's change color of selection when tree get/lose the focus procedure TfrmOptionsFavoriteTabs.tvFavoriteTabsEnter(Sender: TObject); begin tvFavoriteTabs.SelectionColor := clHighlight; end; { TfrmOptionsFavoriteTabs.tvFavoriteTabsExit } // To help to catch eye's attention, let's change color of selection when tree get/lose the focus procedure TfrmOptionsFavoriteTabs.tvFavoriteTabsExit(Sender: TObject); begin tvFavoriteTabs.SelectionColor := clBtnShadow; end; { TfrmOptionsFavoriteTabs.tvFavoriteTabsSelectionChanged } procedure TfrmOptionsFavoriteTabs.tvFavoriteTabsSelectionChanged(Sender: TObject); var WorkingPointer: Pointer; begin if tvFavoriteTabs.Selected <> nil then begin WorkingPointer := tvFavoriteTabs.Selected.Data; if TFavoriteTabs(WorkingPointer).Dispatcher = fte_ACTUALFAVTABS then begin cbTargetPanelLeftSavedTabs.ItemIndex := integer(TFavoriteTabs(WorkingPointer).DestinationForSavedLeftTabs); cbTargetPanelRightSavedTabs.ItemIndex := integer(TFavoriteTabs(WorkingPointer).DestinationForSavedRightTabs); cbExistingTabsToKeep.ItemIndex := integer(TFavoriteTabs(WorkingPointer).ExistingTabsToKeep); if TFavoriteTabs(WorkingPointer).SaveDirHistory then cbSaveDirHistory.ItemIndex := 1 else cbSaveDirHistory.ItemIndex := 0; gpSavedTabsRestorationAction.Enabled := True; end else begin gpSavedTabsRestorationAction.Enabled := False; end; miDeleteSelectedEntry.Enabled := not (TFavoriteTabs(WorkingPointer).Dispatcher = fte_STARTMENU); miDeleteJustSubMenu.Enabled := (TFavoriteTabs(WorkingPointer).Dispatcher = fte_STARTMENU); miDeleteCompleteSubMenu.Enabled := (TFavoriteTabs(WorkingPointer).Dispatcher = fte_STARTMENU); miSortSingleSubMenu.Enabled := (TFavoriteTabs(WorkingPointer).Dispatcher = fte_STARTMENU); miSortSubMenuAndSubLevel.Enabled := (TFavoriteTabs(WorkingPointer).Dispatcher = fte_STARTMENU); miDeleteSelectedEntry.Enabled := (TFavoriteTabs(WorkingPointer).Dispatcher <> fte_ENDMENU); miDeleteSelectedEntry2.Enabled := miDeleteSelectedEntry.Enabled; end //if tvFavoriteTabs.Selected<>nil then else begin gpSavedTabsRestorationAction.Enabled := False; end; end; { TfrmOptionsFavoriteTabs.btnActionClick } procedure TfrmOptionsFavoriteTabs.btnActionClick(Sender: TObject); var Dispatcher: integer; begin with Sender as TComponent do Dispatcher := tag; case Dispatcher of 1, 2: pmInsertAddToFavoriteTabs.Tag := Dispatcher; //To help in routine to determine if it's a "Insert" or a "Add" end; case Dispatcher of 1, 2: pmInsertAddToFavoriteTabs.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 3: pmDeleteFavoriteTabs.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 7: pmImportExport.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 8: pmSortFavoriteTabsList.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; end; { TfrmOptionsFavoriteTabs.cbFullExpandTreeChange } procedure TfrmOptionsFavoriteTabs.cbFullExpandTreeChange(Sender: TObject); begin if cbFullExpandTree.Checked then tvFavoriteTabs.FullExpand else tvFavoriteTabs.FullCollapse; end; { TfrmOptionsFavoriteTabs.cbTabsConfigChange } procedure TfrmOptionsFavoriteTabs.cbTabsConfigChange(Sender: TObject); begin if tvFavoriteTabs.Selected <> nil then begin if TFavoriteTabs(tvFavoriteTabs.Selected.Data).Dispatcher = fte_ACTUALFAVTABS then begin case TComponent(Sender).tag of 1: TFavoriteTabs(tvFavoriteTabs.Selected.Data).DestinationForSavedLeftTabs := TTabsConfigLocation(cbTargetPanelLeftSavedTabs.ItemIndex); 2: TFavoriteTabs(tvFavoriteTabs.Selected.Data).DestinationForSavedRightTabs := TTabsConfigLocation(cbTargetPanelRightSavedTabs.ItemIndex); 3: TFavoriteTabs(tvFavoriteTabs.Selected.Data).ExistingTabsToKeep := TTabsConfigLocation(cbExistingTabsToKeep.ItemIndex); 4: TFavoriteTabs(tvFavoriteTabs.Selected.Data).SaveDirHistory := (cbSaveDirHistory.ItemIndex = 1); end; end; end; end; { TfrmOptionsFavoriteTabs.lblediTFavoriteTabsEnter } procedure TfrmOptionsFavoriteTabs.lbleditFavoriteTabsEnter(Sender: TObject); begin with Sender as TLabeledEdit do begin Font.Style := [fsBold]; EditLabel.Font.Style := [fsBold]; end; end; { TfrmOptionsFavoriteTabs.lblediTFavoriteTabsExit } procedure TfrmOptionsFavoriteTabs.lbleditFavoriteTabsExit(Sender: TObject); begin //If nothing currently selected, no need to update anything here. if tvFavoriteTabs.Selected <> nil then begin with Sender as TLabeledEdit do begin Font.Style := []; EditLabel.Font.Style := []; //Text not in bold anymore case tag of 1: // Favorite Tabs name begin try //Make sure we actually have something, not an attempt of submenu or end of menu if (Text <> '') and (Text[1] <> '-') then begin //Make sure it's different than what it was if TFavoriteTabs(tvFavoriteTabs.Selected.Data).FavoriteTabsName <> Text then begin TFavoriteTabs(tvFavoriteTabs.Selected.Data).FavoriteTabsName := Text; tvFavoriteTabs.Selected.Text := Text; end; end; except //Just in case the "Text" is empty to don't show error with Text[1] check. end; end; end; end; end; end; { TfrmOptionsFavoriteTabs.lblediTFavoriteTabsKeyPress } procedure TfrmOptionsFavoriteTabs.lbleditFavoriteTabsKeyPress(Sender: TObject; var Key: char); begin case Ord(Key) of $0D: //Enter? Let's save the field and we'll exit begin lblediTFavoriteTabsExit(Sender); //Doing this will SAVE the new typed text if it's different than what we have in memory for the entry. Then we could attempt to quit. end; $1B: //Escape? Place back the fields like they were begin with Sender as TLabeledEdit do begin //If typed text has been changed, yes we will restore it but if it was not change, we will quit so user won't have to press two times escape case tag of 1: if Text <> TFavoriteTabs(tvFavoriteTabs.Selected.Data).FavoriteTabsName then Key := #$00; end; case tag of 1: tvFavoriteTabsSelectionChanged(tvFavoriteTabs); end; end; if key <> #$1B then tvFavoriteTabs.SetFocus; end; end; Application.ProcessMessages; end; { TfrmOptionsFavoriteTabs.miInsertAddFavoriteTabsClick } // Regarding the tag... // bit 0 = Separator. // bit 1 = Sub menu. // bit 2 = Reserved. // bit 3 = Reserved. // bit 4 = Insert something. (Before index). // bit 5 = Add something. (At index). // bit 6 = Reserved... // bit 7 = Reserved... // bit 8 = Special function. procedure TfrmOptionsFavoriteTabs.miInsertAddFavoriteTabsClick(Sender: TObject); var Dispatcher: integer; NodeAfterAddition: TTreeNode = nil; SubNodeAfterAddition: TTreeNode = nil; //For fake submenu item, at the end of the add, focus will be in the menu name. localFavoriteTabs: TFavoriteTabs; begin Dispatcher := (TMenuItem(Sender).GetParentComponent.Tag shl 4) or TComponent(Sender).Tag; case Dispatcher of $011: NodeAfterAddition := ActualAddFavoriteTabs(fte_SEPARATOR, FAVORITETABS_SEPARATORSTRING, naInsert); $021: NodeAfterAddition := ActualAddFavoriteTabs(fte_SEPARATOR, FAVORITETABS_SEPARATORSTRING, naInsertBehind); $012, $022: begin case Dispatcher of $12: NodeAfterAddition := ActualAddFavoriteTabs(fte_STARTMENU, rsMsgFavoriteTabsSubMenuName, naInsert); $22: NodeAfterAddition := ActualAddFavoriteTabs(fte_STARTMENU, rsMsgFavoriteTabsSubMenuName, naInsertBehind); end; tvFavoriteTabs.ClearSelection(True); NodeAfterAddition.Selected := True; SubNodeAfterAddition := ActualAddFavoriteTabs(fte_ACTUALFAVTABS, rsMsgFavoriteTabsDragHereEntry, naAddChildFirst); SubNodeAfterAddition.Selected := True; SubNodeAfterAddition.Expand(True); end; $100: // Note. It is true that the new added TFavoriteTemp will be at the end of the list and not just after where we might "think" we add it. But we don't care! What we do is setting up our tree the way we need and then at the end the tree will be translated back to our valid list and that's it! begin localFavoriteTabs := TFavoriteTabs.Create; TFavoriteTabs(tvFavoriteTabs.Selected.Data).CopyToFavoriteTabs(localFavoriteTabs, False); FavoriteTabsListTemp.Add(localFavoriteTabs); NodeAfterAddition := tvFavoriteTabs.Items.InsertObjectBehind(tvFavoriteTabs.Selected, TFavoriteTabs(FavoriteTabsListTemp[pred(FavoriteTabsListTemp.Count)]).FavoriteTabsName, FavoriteTabsListTemp[pred(FavoriteTabsListTemp.Count)]); end; end; if NodeAfterAddition <> nil then begin tvFavoriteTabs.ClearSelection(True); NodeAfterAddition.Selected := True; case Dispatcher of $012, $022: btnRenameClick(btnRename); end; end; end; { TfrmOptionsFavoriteTabs.miDeleteSelectedEntryClick } procedure TfrmOptionsFavoriteTabs.miDeleteSelectedEntryClick(Sender: TObject); var DeleteDispatcher: integer; FlagQuitDeleting: boolean; Answer: TMyMsgResult; NodeAfterDeletion: TTreeNode = nil; isTreeHadFocus: boolean = False; procedure DeleteSelectionAndSetNodeAfterDeletion; begin if tvFavoriteTabs.Selections[0].GetNextSibling <> nil then NodeAfterDeletion := tvFavoriteTabs.Selections[0].GetNextSibling else if tvFavoriteTabs.Selections[0].GetPrevSibling <> nil then NodeAfterDeletion := tvFavoriteTabs.Selections[0].GetPrevSibling else if tvFavoriteTabs.Selections[0].Parent <> nil then NodeAfterDeletion := tvFavoriteTabs.Selections[0].Parent else NodeAfterDeletion := nil; tvFavoriteTabs.Selections[0].Delete; ClearCutAndPasteList; end; begin if tvFavoriteTabs.SelectionCount > 0 then begin isTreeHadFocus := tvFavoriteTabs.Focused; tvFavoriteTabs.Enabled := False; try with Sender as TComponent do DeleteDispatcher := tag; FlagQuitDeleting := False; //It's funny but as long we have something selected, we delete it and it will be index 0 since when //deleting something, the "Selections" array is updated! while (tvFavoriteTabs.SelectionCount > 0) and (not FlagQuitDeleting) do begin if tvFavoriteTabs.Selections[0].GetFirstChild = nil then begin DeleteSelectionAndSetNodeAfterDeletion; end else begin case DeleteDispatcher of 1: Answer := MsgBox(Format(rsMsgHotDirWhatToDelete, [tvFavoriteTabs.Selections[0].Text]), [msmbAll, msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); 2: Answer := mmrNo; 3: Answer := mmrYes; else Answer := mmrCancel; //Should not happen, but just in case end; case Answer of mmrAll: begin DeleteDispatcher := 3; DeleteSelectionAndSetNodeAfterDeletion; end; mmrYes: DeleteSelectionAndSetNodeAfterDeletion; mmrNo: begin NodeAfterDeletion := tvFavoriteTabs.Selections[0].GetFirstChild; repeat tvFavoriteTabs.Selections[0].GetFirstChild.MoveTo(tvFavoriteTabs.Selections[0].GetFirstChild.Parent, naInsert); until tvFavoriteTabs.Selections[0].GetFirstChild = nil; tvFavoriteTabs.Selections[0].Delete; ClearCutAndPasteList; end; else FlagQuitDeleting := True; end; end; end; if (NodeAfterDeletion = nil) and (FlagQuitDeleting = False) and (tvFavoriteTabs.Items.Count > 0) then NodeAfterDeletion := tvFavoriteTabs.Items.Item[0]; if (NodeAfterDeletion <> nil) and (FlagQuitDeleting = False) then NodeAfterDeletion.Selected := True; finally tvFavoriteTabs.Enabled := True; if isTreeHadFocus and tvFavoriteTabs.CanFocus then tvFavoriteTabs.SetFocus; end; end; end; { TfrmOptionsFavoriteTabs.miDeleteAllFavoriteTabsClick } procedure TfrmOptionsFavoriteTabs.miDeleteAllFavoriteTabsClick(Sender: TObject); begin if MsgBox(rsMsgFavoriteTabsDeleteAllEntries, [msmbYes, msmbNo], msmbNo, msmbNo) = mmrYes then begin tvFavoriteTabs.Items.Clear; gpSavedTabsRestorationAction.Enabled := False; ClearCutAndPasteList; end; end; { TfrmOptionsFavoriteTabs.miSortFavoriteTabsClick } //The trick here is that a "group number" identical has been assigned to the sibling between separator and then we sort //Teh sort has been arrange in such way that item from different group won't be mixed. procedure TfrmOptionsFavoriteTabs.miSortFavoriteTabsClick(Sender: TObject); var Dispatcher, Index: integer; StartingNode: TTreeNode; FlagKeepGoingBack: boolean; begin with Sender as TComponent do Dispatcher := tag; for Index := 0 to pred(tvFavoriteTabs.Items.Count) do TFavoriteTabs(tvFavoriteTabs.Items.Item[Index].Data).GroupNumber := 0; GlobalGroupNumber := 0; if tvFavoriteTabs.SelectionCount > 0 then begin case Dispatcher of 1, 2: //current group only or current level begin for Index := 0 to pred(tvFavoriteTabs.SelectionCount) do begin if TFavoriteTabs(tvFavoriteTabs.Selections[Index].Data).GroupNumber = 0 then begin StartingNode := tvFavoriteTabs.Selections[Index]; case Dispatcher of 1: //We just need to make sure we start from first item of current level so we search the first one OR a separator begin FlagKeepGoingBack := True; while FlagKeepGoingBack do begin if StartingNode.GetPrevSibling <> nil then begin if TFavoriteTabs(StartingNode.GetPrevSibling.Data).Dispatcher <> fte_SEPARATOR then StartingNode := StartingNode.GetPrevSibling else FlagKeepGoingBack := False; end else begin FlagKeepGoingBack := False; end; end; end; 2: //We need to make sure we start from the first itm of current level begin while StartingNode.GetPrevSibling <> nil do StartingNode := StartingNode.GetPrevSibling; end; end; RecursiveSetGroupNumbers(StartingNode, GetNextGroupNumber, False, (Dispatcher = 1)); end; end; end; 3, 4: //submenu only, recusive or not begin for Index := 0 to pred(tvFavoriteTabs.SelectionCount) do begin StartingNode := tvFavoriteTabs.Selections[Index].GetFirstChild; if StartingNode <> nil then begin if TFavoriteTabs(StartingNode.Data).GroupNumber = 0 then begin RecursiveSetGroupNumbers(StartingNode, GetNextGroupNumber, (Dispatcher = 4), False); end; end; end; end; end; end; if Dispatcher = 5 then //We start from the very first one, the top one. begin StartingNode := tvFavoriteTabs.Items.Item[0]; RecursiveSetGroupNumbers(StartingNode, GetNextGroupNumber, True, False); end; //... and the finale! tvFavoriteTabs.CustomSort(@MySortViaGroup); ClearCutAndPasteList; end; { TfrmOptionsFavoriteTabs.MakeUsUpToDatePriorImportExport } function TfrmOptionsFavoriteTabs.MakeUsUpToDatePriorImportExport: boolean; var iIndex: integer; Answer: TMyMsgResult; slRememberCurrentSelections: TStringList; begin FavoriteTabsListTemp.RefreshFromTTreeView(tvFavoriteTabs); Result := (LastLoadedOptionSignature = ComputeCompleteOptionsSignature); if not Result then begin Answer := MsgBox(rsMsgFavoriteTabsModifiedNoImport, [msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); case Answer of mmrYes: begin Save; Result := True; end; mmrNo: begin slRememberCurrentSelections := TStringList.Create; try // Saving a trace of what is selected right now. for iIndex := 0 to pred(tvFavoriteTabs.Items.Count) do if tvFavoriteTabs.Items[iIndex].Selected then if TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then slRememberCurrentSelections.Add(GUIDtoString(TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).UniqueID)); gFavoriteTabsList.CopyFavoriteTabsListToFavoriteTabsList(FavoriteTabsListTemp); FavoriteTabsListTemp.LoadTTreeView(tvFavoriteTabs); Result := True; // Restoring what was selected. tvFavoriteTabs.ClearSelection(False); for iIndex := 0 to pred(tvFavoriteTabs.Items.Count) do if TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then tvFavoriteTabs.Items[iIndex].Selected := (slRememberCurrentSelections.IndexOf(GUIDtoString(TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).UniqueID)) <> -1); finally FreeAndNil(slRememberCurrentSelections); end; end; end; end; end; { TfrmOptionsFavoriteTabs.miExportToLegacyTabsFileClick } // We will not annoy user nad even if nothing has been saved yet, even if he might have move entries from a place to another, // we will accept to export selection anyway. But because of this, we will do it from the "Temp" list AND // it will be based from "UniqueID" of each. procedure TfrmOptionsFavoriteTabs.miExportToLegacyTabsFileClick(Sender: TObject); var iIndex, iFileExportedSuccessfully, iMaybeExportedIndex, iSelectionMade: integer; sTargetDirectory, sUserMessage: string; begin if MakeUsUpToDatePriorImportExport then begin if SelectDirectory(rsSelectDir, '', sTargetDirectory, False) then begin iFileExportedSuccessfully := 0; iSelectionMade := 0; gFavoriteTabsList.LastImportationStringUniqueId.Clear; for iIndex := 0 to pred(tvFavoriteTabs.Items.Count) do begin if tvFavoriteTabs.Items[iIndex].Selected then begin Inc(iSelectionMade); if TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then begin iMaybeExportedIndex := gFavoriteTabsList.GetIndexForSuchUniqueID(TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).UniqueID); if iMaybeExportedIndex <> -1 then if gFavoriteTabsList.ExportToLegacyTabsFile(iMaybeExportedIndex, sTargetDirectory) then Inc(iFileExportedSuccessfully); end; end; end; sUserMessage := ''; for iIndex := 0 to pred(gFavoriteTabsList.LastImportationStringUniqueId.Count) do sUserMessage := sUserMessage + #$0A + gFavoriteTabsList.LastImportationStringUniqueId.Strings[iIndex]; msgOk(Format(rsMsgFavoriteTabsExportedSuccessfully, [iFileExportedSuccessfully, iSelectionMade]) + #$0A + sUserMessage); end; end; end; { TfrmOptionsFavoriteTabs.miImportLegacyTabFilesClick } procedure TfrmOptionsFavoriteTabs.miImportLegacyTabFilesClick(Sender: TObject); var iIndex, iFileImportedSuccessfully: integer; iPositionToInsert: integer = -1; NodeAfterAddition: TTreeNode; RememberUniqueIdToRemove: TGUID; begin if MakeUsUpToDatePriorImportExport then begin // 1. If we need to create a sub menu, let's create it first if TComponent(Sender).Tag = 2 then begin NodeAfterAddition := ActualAddFavoriteTabs(fte_STARTMENU, rsMsgFavoriteTabsImportSubMenuName, naInsert); tvFavoriteTabs.ClearSelection(True); NodeAfterAddition.Selected := True; NodeAfterAddition := ActualAddFavoriteTabs(fte_ACTUALFAVTABS, rsMsgFavoriteTabsDragHereEntry, naAddChildFirst); NodeAfterAddition.Selected := True; NodeAfterAddition.Expand(True); RememberUniqueIdToRemove := TFavoriteTabs(tvFavoriteTabs.Selected.Data).UniqueID; FavoriteTabsListTemp.RefreshFromTTreeView(tvFavoriteTabs); Save; end; // 3. Prompt user for which file to import. OpenDialog.FilterIndex := 1; OpenDialog.Title := rsMsgFavoriteTabsImportTitle; if OpenDialog.Execute then begin // 4. Now let's import them one by one. if tvFavoriteTabs.Selected <> nil then if (TComponent(Sender).Tag = 1) or (TComponent(Sender).Tag = 2) then iPositionToInsert := gFavoriteTabsList.GetIndexForSuchUniqueID(TFavoriteTabs(tvFavoriteTabs.Selected.Data).UniqueID); gFavoriteTabsList.LastImportationStringUniqueId.Clear; iIndex := 0; iFileImportedSuccessfully := 0; while iIndex < OpenDialog.Files.Count do begin if gFavoriteTabsList.ImportFromLegacyTabsFile(OpenDialog.Files.Strings[iIndex], iPositionToInsert) then begin Inc(iFileImportedSuccessfully); if iPositionToInsert <> -1 then Inc(iPositionToInsert); end; Inc(iIndex); end; // 5. Before we forget, let's update our mainmenu regarding Favorite Tabs we offer. gFavoriteTabsList.RefreshAssociatedMainMenu; // 6. Refresh what we see here in our Favorite Tabs configurations screen. gFavoriteTabsList.CopyFavoriteTabsListToFavoriteTabsList(FavoriteTabsListTemp); FavoriteTabsListTemp.LoadTTreeView(tvFavoriteTabs); cbFullExpandTreeChange(cbFullExpandTree); if TComponent(Sender).Tag = 2 then begin for iIndex := pred(tvFavoriteTabs.Items.Count) downto 0 do // We go back since we're deleting something in a list. if TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then if IsEqualGUID(TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).UniqueID, RememberUniqueIdToRemove) then tvFavoriteTabs.Items[iIndex].Delete; FavoriteTabsListTemp.RefreshFromTTreeView(tvFavoriteTabs); Save; end; // 7. Let's higlight in our trees the one(s) that have been imported so it will give feeback to user. tvFavoriteTabs.ClearSelection(False); for iIndex := 0 to pred(tvFavoriteTabs.Items.Count) do begin if TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then begin if gFavoriteTabsList.LastImportationStringUniqueId.IndexOf(GUIDToString(TFavoriteTabs(tvFavoriteTabs.Items[iIndex].Data).UniqueID)) <> -1 then tvFavoriteTabs.Items[iIndex].Selected := True; end; end; // 7. Refresh our last signature since what we have is up to date. LastLoadedOptionSignature := ComputeCompleteOptionsSignature; // 8. Finally, let's inform our user we've complete importation. msgOk(Format(rsMsgFavoriteTabsImportedSuccessfully, [iFileImportedSuccessfully, OpenDialog.Files.Count])); if not tvFavoriteTabs.Focused then if tvFavoriteTabs.CanFocus then tvFavoriteTabs.SetFocus; end; end; end; { TfrmOptionsFavoriteTabs.miTestResultingFavoriteTabsMenuClick } procedure TfrmOptionsFavoriteTabs.miTestResultingFavoriteTabsMenuClick(Sender: TObject); var p: TPoint; begin FavoriteTabsListTemp.RefreshFromTTreeView(tvFavoriteTabs); //We need to refresh our temporary Directory Hotlist in case user played with the tree and added/removed/moved item(s). FavoriteTabsListTemp.PopulateMenuWithFavoriteTabs(pmFavoriteTabsTestMenu, @miShowWhereItWouldGo, ftmp_JUSTFAVTABS); p := tvFavoriteTabs.ClientToScreen(Classes.Point(0, 0)); p.x := p.x + tvFavoriteTabs.Width; pmFavoriteTabsTestMenu.PopUp(p.X, p.Y); end; { TfrmOptionsFavoriteTabs.miShowWhereItWouldGo } procedure TfrmOptionsFavoriteTabs.miShowWhereItWouldGo(Sender: TObject); begin if FavoriteTabsListTemp.FavoriteTabs[tag].Dispatcher = fte_ACTUALFAVTABS then msgOK(Format(rsMsgFavoriteTabsThisWillLoadFavTabs, [FavoriteTabsListTemp.FavoriteTabs[TComponent(Sender).tag].FavoriteTabsName])); end; { TfrmOptionsFavoriteTabs.miOpenAllBranchesClick } procedure TfrmOptionsFavoriteTabs.miOpenAllBranchesClick(Sender: TObject); begin tvFavoriteTabs.FullExpand; if tvFavoriteTabs.Selected <> nil then begin tvFavoriteTabs.Selected.MakeVisible; if tvFavoriteTabs.CanFocus then tvFavoriteTabs.SetFocus; end; end; { TfrmOptionsFavoriteTabs.miCollapseAllClick } procedure TfrmOptionsFavoriteTabs.miCollapseAllClick(Sender: TObject); begin tvFavoriteTabs.FullCollapse; if tvFavoriteTabs.Selected <> nil then begin tvFavoriteTabs.Selected.MakeVisible; if tvFavoriteTabs.CanFocus then tvFavoriteTabs.SetFocus; end; end; { TfrmOptionsFavoriteTabs.miCutSelectionClick } procedure TfrmOptionsFavoriteTabs.miCutSelectionClick(Sender: TObject); var Index: integer; begin if tvFavoriteTabs.SelectionCount > 0 then begin for Index := 0 to pred(tvFavoriteTabs.SelectionCount) do begin CutAndPasteIndexList.Add(IntToStr(tvFavoriteTabs.Selections[Index].AbsoluteIndex)); end; miPasteSelection.Enabled := True; end; end; { TfrmOptionsFavoriteTabs.miPasteSelectionClick } procedure TfrmOptionsFavoriteTabs.miPasteSelectionClick(Sender: TObject); var DestinationNode: TTreeNode; Index: longint; begin if CutAndPasteIndexList.Count > 0 then begin DestinationNode := tvFavoriteTabs.Selected; if DestinationNode <> nil then begin tvFavoriteTabs.ClearSelection(False); for Index := 0 to pred(CutAndPasteIndexList.Count) do begin tvFavoriteTabs.Items.Item[StrToInt(CutAndPasteIndexList.Strings[Index])].Selected := True; end; for Index := 0 to pred(tvFavoriteTabs.SelectionCount) do begin tvFavoriteTabs.Selections[Index].MoveTo(DestinationNode, naInsert); end; ClearCutAndPasteList; end; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileassoc.lfm���������������������������������������������������0000644�0001750�0000144�00000127363�14743153644�021120� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFileAssoc: TfrmOptionsFileAssoc Height = 585 Width = 568 HelpKeyword = '/configuration.html#ConfigAssociations' ClientHeight = 585 ClientWidth = 568 Constraints.MinHeight = 300 OnResize = FrameResize ParentShowHint = False ShowHint = True DesignLeft = 100 DesignTop = 118 object pnlSettings: TPanel[0] Left = 0 Height = 585 Top = 0 Width = 568 Align = alClient AutoSize = True BevelOuter = bvNone ClientHeight = 585 ClientWidth = 568 TabOrder = 0 OnResize = pnlSettingsResize object pnlRightSettings: TPanel AnchorSideLeft.Control = pnlLeftSettings AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlSettings AnchorSideRight.Control = pnlSettings AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlBottomSettings Left = 266 Height = 437 Top = 6 Width = 292 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 4 BorderSpacing.Right = 4 BorderSpacing.Around = 6 BevelOuter = bvNone ClientHeight = 437 ClientWidth = 292 Constraints.MinWidth = 200 TabOrder = 1 OnResize = pnlRightSettingsResize object gbActions: TGroupBox AnchorSideLeft.Control = pnlRightSettings AnchorSideTop.Control = gbExts AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlRightSettings AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlRightSettings AnchorSideBottom.Side = asrBottom Left = 0 Height = 213 Top = 224 Width = 292 Anchors = [akTop, akLeft, akRight, akBottom] Caption = 'Actions' ClientHeight = 193 ClientWidth = 288 TabOrder = 2 object lbActions: TListBox Left = 6 Height = 181 Hint = 'Actions may be sorted by drag & drop' Top = 6 Width = 197 Align = alClient BorderSpacing.Around = 6 DragMode = dmAutomatic ItemHeight = 0 OnDragDrop = lbActionsDragDrop OnDragOver = lbGenericDragOver OnDrawItem = lbGenericListDrawItem OnSelectionChange = lbActionsSelectionChange ScrollWidth = 198 Style = lbOwnerDrawFixed TabOrder = 0 end object pnlActsButtons: TPanel Left = 209 Height = 181 Top = 6 Width = 73 Align = alRight AutoSize = True BorderSpacing.Around = 6 BevelOuter = bvNone ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 181 ClientWidth = 73 TabOrder = 1 object btnUpAct: TButton Left = 0 Height = 29 Top = 0 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = '&Up' OnClick = btnUpActClick TabOrder = 0 end object btnDownAct: TButton Left = 0 Height = 29 Top = 29 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Do&wn' OnClick = btnDownActClick TabOrder = 1 end object btnInsertAct: TButton Tag = 32 Left = 0 Height = 29 Top = 58 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Insert' OnClick = btnInsertAddActClick TabOrder = 2 end object btnAddAct: TButton Left = 0 Height = 29 Top = 87 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Add' OnClick = btnInsertAddActClick TabOrder = 3 end object btnCloneAct: TButton Left = 0 Height = 29 Top = 116 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'C&lone' OnClick = btnCloneActClick TabOrder = 4 end object btnRemoveAct: TButton Left = 0 Height = 29 Top = 145 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Remo&ve' OnClick = btnRemoveActClick TabOrder = 5 end end object pnlActsEdits: TPanel Left = 0 Height = 0 Top = 193 Width = 288 Align = alBottom AutoSize = True BevelOuter = bvNone TabOrder = 2 end end object gbIcon: TGroupBox AnchorSideLeft.Control = pnlRightSettings AnchorSideTop.Control = pnlRightSettings AnchorSideRight.Control = pnlRightSettings AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlRightSettings AnchorSideBottom.Side = asrBottom Left = 0 Height = 64 Top = 0 Width = 292 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Icon' ChildSizing.LeftRightSpacing = 6 ClientHeight = 44 ClientWidth = 288 TabOrder = 0 object sbtnIcon: TSpeedButton AnchorSideLeft.Control = gbIcon AnchorSideTop.Control = gbIcon Left = 6 Height = 38 Hint = 'Click me to change icon!' Top = 2 Width = 38 BorderSpacing.Top = 2 BorderSpacing.Bottom = 4 OnClick = sbtnIconClick end object btnRelativePathIcon: TSpeedButton AnchorSideTop.Control = sbtnIcon AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbIcon AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 259 Height = 23 Top = 10 Width = 23 Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativePathIconClick end object btnIconSelectFilename: TSpeedButton AnchorSideTop.Control = sbtnIcon AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnRelativePathIcon AnchorSideBottom.Side = asrBottom Left = 236 Height = 23 Top = 10 Width = 23 Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 200000000000000400006400000064000000000000000000000000000000328B D83F328BD83F328BD83F328BD83F328BD83F328BD83F328BD83F328BD83F328B D83F328BD83F328BD83F328BD83F328BD83F328BD83F000000004994D7FF328B D8FF328AD8FF328BD8FF328BD8FF328BD8FF328BD8FF328BD8FF328BD8FF328B D8FF328BD8FF328AD8FF328BD8FF4994D7FF328BD83F00000000358FD8FFDCF0 FAFF98E1F6FF95E0F6FF92DFF6FF8EDEF5FF89DCF5FF85DAF4FF80D9F4FF79D7 F3FF73D5F3FF6FD3F2FFC2EAF8FF3494DAFF328BD83F000000003A96DAFFEFFA FEFF93E5F8FF8FE4F8FF89E3F8FF82E1F7FF79DFF7FF70DEF6FF66DBF5FF5AD8 F4FF4CD4F3FF3FD1F2FFCAF2FBFF3494DAFF328BD83F000000003A9CDAFFF2FA FDFF94E6F8FF92E5F8FF90E5F8FF8BE3F8FF86E2F7FF7EE1F7FF76DEF6FF6BDC F6FF5DD9F4FF4ED5F3FFCCF2FBFF3494DAFF328BD83F0000000039A2DAFFF6FC FEFF94E5F8FF93E5F8FF93E5F8FF91E5F8FF86E2F7FF7EE1F7FF76DEF6FF6BDC F6FF5DD9F4FF4ED5F3FFCCF2FBFF3494DAFF328BD83F0000000039A7D9FFFEFF FFFFF8FDFFFFF6FDFFFFF5FCFFFFF3FCFEFF9AE4F4FF9AE6F7FF9BE6F6FF3176 B3FF2F72B1FF2D71B2FF2B72B6FF2C73B9FF1C476DFF0000000037ABD9FFE8F6 FBFF6FBCE7FF54AAE2FF4CA5E0FF91C9EBFFFDFEFDFFFDFEFDFFFFFDFCFF2F72 B1FF6FD1F6FF6ACEF8FF84BFB3FFA0AC64FF3684C7FF193D5EFF3EACDAFFF1FA FDFF94DEF5FF93DCF4FF63BCE9FF3494DAFF3494DAFF3494DAFF3494DAFF2E70 AFFF65C4EDFF5FBFF1FF9DA461FFDD8A00FF5BBCF3FF2E6FAEFF3FB3DBFFF7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFACE1F6FF1E486EFF3075B1FF3075AFFF4492 C6FF5FBAE6FF5DB5E9FF40C0D7FF20CCBFFF66BDF1FF2E72B2FF3AB4DAFFFDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFF2F74B2FF6EC1E5FF2F6EEDFF4791 E5FF5CB0DEFF5CABE1FF24C3B0FF00DF7CFF83C3F0FF2D71B1FF56BFDDFF60C3 E1FF62C4E2FF62C4E2FF62C4E2FF61C4E2FF2C72B0FFA2DAEDFF001AF4FF126C F1FF24B9EEFF3DBAE4FF22D3F3FF58A2DFFFACD4F0FF2C71B1FF000000000000 0000000000000000000000000000000000002C71AEFFA4CFE7FF87ACEEFF25B0 F5FF00C5FFFF2AD6EEFF00FFFFFFB8D5F0FF73A7D2FF1E4D77FF000000000000 000000000000000000000000000000000000000000003378B3FF84B5D8FFBCDB EFFFBDD8EDFFBDD6EEFFABCAE7FF699CCCFF27659FFF00000000000000000000 0000000000000000000000000000000000000000000000000000215583FF2A70 B0FF2A6FAFFF2A6FB0FF2B70B0FF1F4D77FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } OnClick = sbtnIconClick end object edIconFileName: TEdit AnchorSideLeft.Control = sbtnIcon AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbtnIcon AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnIconSelectFilename Left = 44 Height = 23 Top = 10 Width = 192 Anchors = [akTop, akLeft, akRight] OnChange = edIconFileNameChange TabOrder = 0 end end object gbExts: TGroupBox AnchorSideLeft.Control = pnlRightSettings AnchorSideTop.Control = gbIcon AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlRightSettings AnchorSideRight.Side = asrBottom Left = 0 Height = 160 Hint = 'Can be sorted by drag & drop' Top = 64 Width = 292 Anchors = [akTop, akLeft, akRight] BorderSpacing.InnerBorder = 20 Caption = 'Extensions' ClientHeight = 140 ClientWidth = 288 Constraints.MinHeight = 160 TabOrder = 1 object lbExts: TListBox Left = 6 Height = 128 Hint = 'Extensions may be sorted by drag & drop' Top = 6 Width = 197 Align = alClient BorderSpacing.Around = 6 DragMode = dmAutomatic ItemHeight = 0 OnDragDrop = lbExtsDragDrop OnDragOver = lbGenericDragOver OnDrawItem = lbGenericListDrawItem OnSelectionChange = lbExtsSelectionChange ScrollWidth = 198 Style = lbOwnerDrawFixed TabOrder = 0 end object pnlExtsButtons: TPanel Left = 209 Height = 128 Top = 6 Width = 73 Align = alRight AutoSize = True BorderSpacing.Around = 6 BevelOuter = bvNone ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 128 ClientWidth = 73 TabOrder = 1 object btnEditExt: TButton Left = 0 Height = 29 Top = 0 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Edi&t' OnClick = btnEditExtClick TabOrder = 0 end object btnInsertExt: TButton Tag = 1 Left = 0 Height = 29 Top = 29 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = '&Insert' OnClick = btnInsertAddExtClick TabOrder = 1 end object btnAddExt: TButton Left = 0 Height = 29 Top = 58 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Add' OnClick = btnInsertAddExtClick TabOrder = 2 end object btnRemoveExt: TButton Left = 0 Height = 29 Top = 87 Width = 73 AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'Re&move' OnClick = btnRemoveExtClick TabOrder = 3 end end end end object pnlLeftSettings: TPanel AnchorSideLeft.Control = pnlSettings AnchorSideTop.Control = pnlSettings AnchorSideBottom.Control = pnlBottomSettings Left = 6 Height = 437 Top = 6 Width = 250 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Around = 6 BevelOuter = bvNone ClientHeight = 437 ClientWidth = 250 TabOrder = 0 object gbFileTypes: TGroupBox AnchorSideBottom.Side = asrBottom Left = 0 Height = 437 Top = 0 Width = 250 Align = alClient Caption = 'File types' ClientHeight = 417 ClientWidth = 246 TabOrder = 0 object lbFileTypes: TListBox AnchorSideLeft.Control = gbFileTypes AnchorSideTop.Control = gbFileTypes AnchorSideRight.Control = gbFileTypes AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnAddNewType Left = 6 Height = 339 Hint = 'File types may be sorted by drag & drop' Top = 6 Width = 234 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Around = 6 DragMode = dmAutomatic ItemHeight = 20 OnDragDrop = lbFileTypesDragDrop OnDragOver = lbGenericDragOver OnDrawItem = lbFileTypesDrawItem OnSelectionChange = lbFileTypesSelectionChange ScrollWidth = 232 Style = lbOwnerDrawFixed TabOrder = 0 end object btnAddNewType: TButton AnchorSideLeft.Control = gbFileTypes AnchorSideTop.Control = lbFileTypes AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFileTypes AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnRemoveType Left = 6 Height = 29 Top = 351 Width = 234 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 2 BorderSpacing.InnerBorder = 2 Caption = 'A&dd' OnClick = btnAddNewTypeClick TabOrder = 1 end object btnRemoveType: TButton AnchorSideLeft.Control = btnAddNewType Left = 6 Height = 29 Top = 382 Width = 73 Anchors = [akLeft, akBottom] AutoSize = True BorderSpacing.InnerBorder = 2 Caption = '&Remove' OnClick = btnRemoveTypeClick OnResize = btnRemoveTypeResize TabOrder = 2 end object btnRenameType: TButton AnchorSideRight.Control = btnAddNewType AnchorSideRight.Side = asrBottom Left = 167 Height = 29 Top = 382 Width = 73 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.InnerBorder = 2 Caption = 'R&ename' OnClick = btnRenameTypeClick OnResize = btnRenameTypeResize TabOrder = 3 end end end object pnlBottomSettings: TPanel AnchorSideLeft.Control = pnlSettings AnchorSideRight.Control = pnlSettings AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlSettings AnchorSideBottom.Side = asrBottom Left = 10 Height = 130 Top = 449 Width = 548 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Left = 4 BorderSpacing.Right = 4 BorderSpacing.Around = 6 BevelOuter = bvNone ClientHeight = 130 ClientWidth = 548 TabOrder = 2 object gbActionDescription: TGroupBox AnchorSideLeft.Control = pnlBottomSettings AnchorSideTop.Control = pnlBottomSettings AnchorSideRight.Control = pnlBottomSettings AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlBottomSettings AnchorSideBottom.Side = asrBottom Left = 0 Height = 126 Top = 2 Width = 548 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Top = 2 BorderSpacing.Bottom = 2 Caption = 'Action description' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 10 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 106 ClientWidth = 544 TabOrder = 0 object edbActionName: TEditButton AnchorSideLeft.Control = lblAction AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblAction AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbActionDescription AnchorSideRight.Side = asrBottom Left = 79 Height = 23 Hint = 'Name of the action. It is never passed to the system, it''s just a mnemonic name chosen by you, for you' Top = 2 Width = 459 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534CCA46534FFA46534FFA465 34CC000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFD9AD86FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFD9AD86FFA465 34FF000000000000000000000000000000000000000000000000000000000000 0000A46534CCA46534FFA46534FFA46534FFA46534FFD9AD86FFD9AD86FFA465 34FFA46534FFA46534FFA46534FFA46534CC0000000000000000000000000000 0000A46534FFE5CCB4FFDBB795FFDBB694FFDAB492FFDAB390FFD9AD86FFD8AA 83FFD7A87FFFD7A67DFFE0BE9FFFA46534FF0000000000000000000000000000 0000A46534FFE8D3C0FFE7D1BBFFE7D1BCFFE6CEB7FFE6CEB7FFE6CEB7FFE6CE B7FFE6CDB6FFE6CCB5FFE6CCB6FFA46534FF0000000000000000000000000000 0000A46534CCA46534FFA46534FFA46534FFA46534FFE6CEB7FFE6CEB7FFA465 34FFA46534FFA46534FFA46534FFA46534CC0000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534CCA46534FFA46534FFA465 34CC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } MaxLength = 0 NumGlyphs = 1 OnButtonClick = btnActionsClick OnChange = edbActionNameChange PasswordChar = #0 TabOrder = 0 end object lblAction: TLabel AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 6 Width = 71 Alignment = taRightJustify Caption = 'Action &name:' FocusControl = edbActionName ParentColor = False end object fneCommand: TFileNameEdit AnchorSideLeft.Control = lblCommand AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblCommand AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCommands Left = 79 Height = 23 Hint = 'Command to execute. Never quote this string.' Top = 27 Width = 413 OnAcceptFileName = fneCommandAcceptFileName DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 0 TabOrder = 1 OnChange = fneCommandChange end object btnCommands: TSpeedButton AnchorSideTop.Control = fneCommand AnchorSideRight.Control = btnRelativeCommand AnchorSideBottom.Control = fneCommand AnchorSideBottom.Side = asrBottom Left = 492 Height = 23 Hint = 'Select your internal command' Top = 27 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534CCA46534FFA46534FFA465 34CC000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFD9AD86FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFD9AD86FFA465 34FF000000000000000000000000000000000000000000000000000000000000 0000A46534CCA46534FFA46534FFA46534FFA46534FFD9AD86FFD9AD86FFA465 34FFA46534FFA46534FFA46534FFA46534CC0000000000000000000000000000 0000A46534FFE5CCB4FFDBB795FFDBB694FFDAB492FFDAB390FFD9AD86FFD8AA 83FFD7A87FFFD7A67DFFE0BE9FFFA46534FF0000000000000000000000000000 0000A46534FFE8D3C0FFE7D1BBFFE7D1BCFFE6CEB7FFE6CEB7FFE6CEB7FFE6CE B7FFE6CDB6FFE6CCB5FFE6CCB6FFA46534FF0000000000000000000000000000 0000A46534CCA46534FFA46534FFA46534FFA46534FFE6CEB7FFE6CEB7FFA465 34FFA46534FFA46534FFA46534FFA46534CC0000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534FFE6CEB7FFE6CEB7FFA465 34FF000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A46534CCA46534FFA46534FFA465 34CC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } OnClick = btnCommandsClick end object btnRelativeCommand: TSpeedButton AnchorSideTop.Control = fneCommand AnchorSideRight.Control = gbActionDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneCommand AnchorSideBottom.Side = asrBottom Left = 515 Height = 23 Hint = 'Some functions to select appropriate path' Top = 27 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeCommandClick end object btnParametersHelper: TSpeedButton AnchorSideTop.Control = edtParams AnchorSideRight.Control = gbActionDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtParams AnchorSideBottom.Side = asrBottom Left = 515 Height = 23 Hint = 'Variable reminder helper' Top = 52 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnParametersHelperClick end object lblCommand: TLabel AnchorSideTop.Side = asrCenter AnchorSideRight.Control = fneCommand Left = 6 Height = 15 Top = 31 Width = 71 Alignment = taRightJustify Caption = 'Command:' ParentColor = False end object edtParams: TEdit AnchorSideLeft.Control = lblExternalParameters AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblExternalParameters AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnParametersHelper Left = 79 Height = 23 Hint = 'Parameter to pass to the command. Long filename with spaces should be quoted (manually entering).' Top = 52 Width = 436 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 259 OnChange = edtParamsChange TabOrder = 2 end object lblExternalParameters: TLabel AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 56 Width = 71 Alignment = taRightJustify Caption = 'Parameter&s:' FocusControl = edtParams ParentColor = False end object deStartPath: TDirectoryEdit AnchorSideLeft.Control = lblStartPath AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblStartPath AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnStartPathPathHelper Left = 79 Height = 23 Hint = 'Starting path of the command. Never quote this string.' Top = 77 Width = 413 OnAcceptDirectory = deStartPathAcceptDirectory ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 0 TabOrder = 3 OnChange = deStartPathChange end object btnStartPathVarHelper: TSpeedButton AnchorSideTop.Control = deStartPath AnchorSideRight.Control = gbActionDescription AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = deStartPath AnchorSideBottom.Side = asrBottom Left = 515 Height = 23 Hint = 'Variable reminder helper' Top = 77 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } OnClick = btnStartPathVarHelperClick end object btnStartPathPathHelper: TSpeedButton AnchorSideTop.Control = deStartPath AnchorSideRight.Control = btnStartPathVarHelper AnchorSideBottom.Control = deStartPath AnchorSideBottom.Side = asrBottom Left = 492 Height = 23 Hint = 'Some functions to select appropriate path' Top = 77 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnStartPathPathHelperClick end object lblStartPath: TLabel AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 81 Width = 71 Alignment = taRightJustify Caption = 'Start pat&h:' FocusControl = deStartPath ParentColor = False end end end end object OpenPictureDialog: TOpenPictureDialog[1] left = 65 top = 124 end object pmActions: TPopupMenu[2] left = 175 top = 60 object miOpen: TMenuItem Caption = 'Open' OnClick = miActionsClick end object miView: TMenuItem Tag = 1 Caption = 'View' OnClick = miActionsClick end object miEdit: TMenuItem Tag = 2 Caption = 'Edit' OnClick = miActionsClick end object miCustom: TMenuItem Tag = 3 Caption = 'Custom' OnClick = miActionsClick end object MenuItem1: TMenuItem Caption = '-' end object miOpenWith: TMenuItem Tag = 16 Caption = 'Open with...' OnClick = miActionsClick end object miViewWith: TMenuItem Tag = 17 Caption = 'View with...' OnClick = miActionsClick end object miEditWith: TMenuItem Tag = 18 Caption = 'Edit with...' OnClick = miActionsClick end object MenuItem3: TMenuItem Tag = 19 Caption = 'Custom with...' OnClick = miActionsClick end end object pmCommands: TPopupMenu[3] left = 175 top = 124 object miViewer: TMenuItem Tag = 2 Caption = 'Open in Viewer' OnClick = miCommandsClick end object miInternalViewer: TMenuItem Tag = 3 Caption = 'Open in Internal Viewer' OnClick = miCommandsClick end object miEditor: TMenuItem Tag = 4 Caption = 'Open in Editor' OnClick = miCommandsClick end object miInternalEditor: TMenuItem Tag = 5 Caption = 'Open in Internal Editor' OnClick = miCommandsClick end object miSeparator: TMenuItem Caption = '-' end object miShell: TMenuItem Tag = 6 Caption = 'Run in terminal' OnClick = miCommandsClick end object miGetOutputFromCommand: TMenuItem Tag = 7 Caption = 'Get output from command' OnClick = miCommandsClick end end object OpenDialog: TOpenDialog[4] Filter = 'Executables|*.exe;*.com;*.bat|Any files|*.*' Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] left = 65 top = 60 end object pmPathHelper: TPopupMenu[5] left = 65 top = 187 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileassoc.lrj���������������������������������������������������0000644�0001750�0000144�00000022230�14743153644�021114� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":128648723,"name":"tfrmoptionsfileassoc.gbactions.caption","sourcebytes":[65,99,116,105,111,110,115],"value":"Actions"}, {"hash":132951248,"name":"tfrmoptionsfileassoc.lbactions.hint","sourcebytes":[65,99,116,105,111,110,115,32,109,97,121,32,98,101,32,115,111,114,116,101,100,32,98,121,32,100,114,97,103,32,38,32,100,114,111,112],"value":"Actions may be sorted by drag & drop"}, {"hash":11200,"name":"tfrmoptionsfileassoc.btnupact.caption","sourcebytes":[38,85,112],"value":"&Up"}, {"hash":4922846,"name":"tfrmoptionsfileassoc.btndownact.caption","sourcebytes":[68,111,38,119,110],"value":"Do&wn"}, {"hash":84253844,"name":"tfrmoptionsfileassoc.btninsertact.caption","sourcebytes":[73,110,115,101,114,116],"value":"Insert"}, {"hash":18340,"name":"tfrmoptionsfileassoc.btnaddact.caption","sourcebytes":[65,100,100],"value":"Add"}, {"hash":73217605,"name":"tfrmoptionsfileassoc.btncloneact.caption","sourcebytes":[67,38,108,111,110,101],"value":"C&lone"}, {"hash":147070357,"name":"tfrmoptionsfileassoc.btnremoveact.caption","sourcebytes":[82,101,109,111,38,118,101],"value":"Remo&ve"}, {"hash":326238,"name":"tfrmoptionsfileassoc.gbicon.caption","sourcebytes":[73,99,111,110],"value":"Icon"}, {"hash":40085009,"name":"tfrmoptionsfileassoc.sbtnicon.hint","sourcebytes":[67,108,105,99,107,32,109,101,32,116,111,32,99,104,97,110,103,101,32,105,99,111,110,33],"value":"Click me to change icon!"}, {"hash":113622016,"name":"tfrmoptionsfileassoc.gbexts.hint","sourcebytes":[67,97,110,32,98,101,32,115,111,114,116,101,100,32,98,121,32,100,114,97,103,32,38,32,100,114,111,112],"value":"Can be sorted by drag & drop"}, {"hash":207440883,"name":"tfrmoptionsfileassoc.gbexts.caption","sourcebytes":[69,120,116,101,110,115,105,111,110,115],"value":"Extensions"}, {"hash":156618752,"name":"tfrmoptionsfileassoc.lbexts.hint","sourcebytes":[69,120,116,101,110,115,105,111,110,115,32,109,97,121,32,98,101,32,115,111,114,116,101,100,32,98,121,32,100,114,97,103,32,38,32,100,114,111,112],"value":"Extensions may be sorted by drag & drop"}, {"hash":4959188,"name":"tfrmoptionsfileassoc.btneditext.caption","sourcebytes":[69,100,105,38,116],"value":"Edi&t"}, {"hash":184917172,"name":"tfrmoptionsfileassoc.btninsertext.caption","sourcebytes":[38,73,110,115,101,114,116],"value":"&Insert"}, {"hash":18340,"name":"tfrmoptionsfileassoc.btnaddext.caption","sourcebytes":[65,100,100],"value":"Add"}, {"hash":142427797,"name":"tfrmoptionsfileassoc.btnremoveext.caption","sourcebytes":[82,101,38,109,111,118,101],"value":"Re&move"}, {"hash":125884131,"name":"tfrmoptionsfileassoc.gbfiletypes.caption","sourcebytes":[70,105,108,101,32,116,121,112,101,115],"value":"File types"}, {"hash":149820880,"name":"tfrmoptionsfileassoc.lbfiletypes.hint","sourcebytes":[70,105,108,101,32,116,121,112,101,115,32,109,97,121,32,98,101,32,115,111,114,116,101,100,32,98,121,32,100,114,97,103,32,38,32,100,114,111,112],"value":"File types may be sorted by drag & drop"}, {"hash":277668,"name":"tfrmoptionsfileassoc.btnaddnewtype.caption","sourcebytes":[65,38,100,100],"value":"A&dd"}, {"hash":193742565,"name":"tfrmoptionsfileassoc.btnremovetype.caption","sourcebytes":[38,82,101,109,111,118,101],"value":"&Remove"}, {"hash":80496741,"name":"tfrmoptionsfileassoc.btnrenametype.caption","sourcebytes":[82,38,101,110,97,109,101],"value":"R&ename"}, {"hash":219666334,"name":"tfrmoptionsfileassoc.gbactiondescription.caption","sourcebytes":[65,99,116,105,111,110,32,100,101,115,99,114,105,112,116,105,111,110],"value":"Action description"}, {"hash":39517605,"name":"tfrmoptionsfileassoc.edbactionname.hint","sourcebytes":[78,97,109,101,32,111,102,32,116,104,101,32,97,99,116,105,111,110,46,32,73,116,32,105,115,32,110,101,118,101,114,32,112,97,115,115,101,100,32,116,111,32,116,104,101,32,115,121,115,116,101,109,44,32,105,116,39,115,32,106,117,115,116,32,97,32,109,110,101,109,111,110,105,99,32,110,97,109,101,32,99,104,111,115,101,110,32,98,121,32,121,111,117,44,32,102,111,114,32,121,111,117],"value":"Name of the action. It is never passed to the system, it's just a mnemonic name chosen by you, for you"}, {"hash":92243402,"name":"tfrmoptionsfileassoc.lblaction.caption","sourcebytes":[65,99,116,105,111,110,32,38,110,97,109,101,58],"value":"Action &name:"}, {"hash":93137918,"name":"tfrmoptionsfileassoc.fnecommand.hint","sourcebytes":[67,111,109,109,97,110,100,32,116,111,32,101,120,101,99,117,116,101,46,32,78,101,118,101,114,32,113,117,111,116,101,32,116,104,105,115,32,115,116,114,105,110,103,46],"value":"Command to execute. Never quote this string."}, {"hash":53701060,"name":"tfrmoptionsfileassoc.btncommands.hint","sourcebytes":[83,101,108,101,99,116,32,121,111,117,114,32,105,110,116,101,114,110,97,108,32,99,111,109,109,97,110,100],"value":"Select your internal command"}, {"hash":15252584,"name":"tfrmoptionsfileassoc.btnrelativecommand.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":197225810,"name":"tfrmoptionsfileassoc.btnparametershelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":105087194,"name":"tfrmoptionsfileassoc.lblcommand.caption","sourcebytes":[67,111,109,109,97,110,100,58],"value":"Command:"}, {"hash":230939086,"name":"tfrmoptionsfileassoc.edtparams.hint","sourcebytes":[80,97,114,97,109,101,116,101,114,32,116,111,32,112,97,115,115,32,116,111,32,116,104,101,32,99,111,109,109,97,110,100,46,32,76,111,110,103,32,102,105,108,101,110,97,109,101,32,119,105,116,104,32,115,112,97,99,101,115,32,115,104,111,117,108,100,32,98,101,32,113,117,111,116,101,100,32,40,109,97,110,117,97,108,108,121,32,101,110,116,101,114,105,110,103,41,46],"value":"Parameter to pass to the command. Long filename with spaces should be quoted (manually entering)."}, {"hash":163890522,"name":"tfrmoptionsfileassoc.lblexternalparameters.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,38,115,58],"value":"Parameter&s:"}, {"hash":96005582,"name":"tfrmoptionsfileassoc.destartpath.hint","sourcebytes":[83,116,97,114,116,105,110,103,32,112,97,116,104,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,46,32,78,101,118,101,114,32,113,117,111,116,101,32,116,104,105,115,32,115,116,114,105,110,103,46],"value":"Starting path of the command. Never quote this string."}, {"hash":197225810,"name":"tfrmoptionsfileassoc.btnstartpathvarhelper.hint","sourcebytes":[86,97,114,105,97,98,108,101,32,114,101,109,105,110,100,101,114,32,104,101,108,112,101,114],"value":"Variable reminder helper"}, {"hash":15252584,"name":"tfrmoptionsfileassoc.btnstartpathpathhelper.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":46327258,"name":"tfrmoptionsfileassoc.lblstartpath.caption","sourcebytes":[83,116,97,114,116,32,112,97,116,38,104,58],"value":"Start pat&h:"}, {"hash":353982,"name":"tfrmoptionsfileassoc.miopen.caption","sourcebytes":[79,112,101,110],"value":"Open"}, {"hash":380871,"name":"tfrmoptionsfileassoc.miview.caption","sourcebytes":[86,105,101,119],"value":"View"}, {"hash":310020,"name":"tfrmoptionsfileassoc.miedit.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, {"hash":78424925,"name":"tfrmoptionsfileassoc.micustom.caption","sourcebytes":[67,117,115,116,111,109],"value":"Custom"}, {"hash":158101886,"name":"tfrmoptionsfileassoc.miopenwith.caption","sourcebytes":[79,112,101,110,32,119,105,116,104,46,46,46],"value":"Open with..."}, {"hash":163936894,"name":"tfrmoptionsfileassoc.miviewwith.caption","sourcebytes":[86,105,101,119,32,119,105,116,104,46,46,46],"value":"View with..."}, {"hash":179419006,"name":"tfrmoptionsfileassoc.mieditwith.caption","sourcebytes":[69,100,105,116,32,119,105,116,104,46,46,46],"value":"Edit with..."}, {"hash":44174558,"name":"tfrmoptionsfileassoc.menuitem3.caption","sourcebytes":[67,117,115,116,111,109,32,119,105,116,104,46,46,46],"value":"Custom with..."}, {"hash":51357346,"name":"tfrmoptionsfileassoc.miviewer.caption","sourcebytes":[79,112,101,110,32,105,110,32,86,105,101,119,101,114],"value":"Open in Viewer"}, {"hash":162573938,"name":"tfrmoptionsfileassoc.miinternalviewer.caption","sourcebytes":[79,112,101,110,32,105,110,32,73,110,116,101,114,110,97,108,32,86,105,101,119,101,114],"value":"Open in Internal Viewer"}, {"hash":41640450,"name":"tfrmoptionsfileassoc.mieditor.caption","sourcebytes":[79,112,101,110,32,105,110,32,69,100,105,116,111,114],"value":"Open in Editor"}, {"hash":147221202,"name":"tfrmoptionsfileassoc.miinternaleditor.caption","sourcebytes":[79,112,101,110,32,105,110,32,73,110,116,101,114,110,97,108,32,69,100,105,116,111,114],"value":"Open in Internal Editor"}, {"hash":218348060,"name":"tfrmoptionsfileassoc.mishell.caption","sourcebytes":[82,117,110,32,105,110,32,116,101,114,109,105,110,97,108],"value":"Run in terminal"}, {"hash":169726772,"name":"tfrmoptionsfileassoc.migetoutputfromcommand.caption","sourcebytes":[71,101,116,32,111,117,116,112,117,116,32,102,114,111,109,32,99,111,109,109,97,110,100],"value":"Get output from command"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileassoc.pas���������������������������������������������������0000644�0001750�0000144�00000144574�14743153644�021130� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File associations configuration Copyright (C) 2008-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFileAssoc; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, ExtCtrls, EditBtn, ExtDlgs, Menus, ActnList, Types, //DC uGlobs, uExts, fOptionsFrame; type { TfrmOptionsFileAssoc } TfrmOptionsFileAssoc = class(TOptionsEditor) btnAddAct: TButton; btnCloneAct: TButton; btnCommands: TSpeedButton; btnInsertExt: TButton; btnInsertAct: TButton; btnAddExt: TButton; btnAddNewType: TButton; btnDownAct: TButton; btnEditExt: TButton; btnParametersHelper: TSpeedButton; btnRelativePathIcon: TSpeedButton; btnIconSelectFilename: TSpeedButton; btnStartPathVarHelper: TSpeedButton; btnRelativeCommand: TSpeedButton; btnStartPathPathHelper: TSpeedButton; btnUpAct: TButton; btnRemoveAct: TButton; btnRemoveExt: TButton; btnRemoveType: TButton; btnRenameType: TButton; deStartPath: TDirectoryEdit; edbActionName: TEditButton; edIconFileName: TEdit; edtParams: TEdit; fneCommand: TFileNameEdit; gbActionDescription: TGroupBox; gbFileTypes: TGroupBox; gbIcon: TGroupBox; gbExts: TGroupBox; gbActions: TGroupBox; lbActions: TListBox; lbExts: TListBox; lbFileTypes: TListBox; lblAction: TLabel; lblCommand: TLabel; lblExternalParameters: TLabel; lblStartPath: TLabel; MenuItem1: TMenuItem; miInternalViewer: TMenuItem; miInternalEditor: TMenuItem; miSeparator: TMenuItem; miCustom: TMenuItem; MenuItem3: TMenuItem; miOpenWith: TMenuItem; miViewWith: TMenuItem; miEditWith: TMenuItem; miGetOutputFromCommand: TMenuItem; miShell: TMenuItem; miViewer: TMenuItem; miEditor: TMenuItem; miEdit: TMenuItem; miView: TMenuItem; miOpen: TMenuItem; OpenDialog: TOpenDialog; OpenPictureDialog: TOpenPictureDialog; pnlBottomSettings: TPanel; pmPathHelper: TPopupMenu; pnlLeftSettings: TPanel; pnlActsEdits: TPanel; pnlActsButtons: TPanel; pnlExtsButtons: TPanel; pnlRightSettings: TPanel; pnlSettings: TPanel; pmActions: TPopupMenu; pmCommands: TPopupMenu; sbtnIcon: TSpeedButton; procedure btnActionsClick(Sender: TObject); procedure btnCloneActClick(Sender: TObject); procedure btnInsertAddActClick(Sender: TObject); procedure btnInsertAddExtClick(Sender: TObject); procedure btnParametersHelperClick(Sender: TObject); procedure btnRelativeCommandClick(Sender: TObject); procedure btnRelativePathIconClick(Sender: TObject); procedure btnStartPathPathHelperClick(Sender: TObject); procedure btnStartPathVarHelperClick(Sender: TObject); procedure deStartPathAcceptDirectory(Sender: TObject; var Value: String); procedure deStartPathChange(Sender: TObject); procedure edtParamsChange(Sender: TObject); procedure edIconFileNameChange(Sender: TObject); procedure fneCommandAcceptFileName(Sender: TObject; var Value: String); procedure FrameResize(Sender: TObject); function InsertAddSingleExtensionToLists(sExt: string; iInsertPosition: integer): boolean; procedure InsertAddExtensionToLists(sParamExt: string; iPositionToInsert: integer); procedure btnAddNewTypeClick(Sender: TObject); procedure btnCommandsClick(Sender: TObject); procedure btnDownActClick(Sender: TObject); procedure btnEditExtClick(Sender: TObject); procedure btnRemoveActClick(Sender: TObject); procedure btnRemoveExtClick(Sender: TObject); procedure btnRemoveTypeClick(Sender: TObject); procedure btnRemoveTypeResize(Sender: TObject); procedure btnRenameTypeClick(Sender: TObject); procedure btnRenameTypeResize(Sender: TObject); procedure btnUpActClick(Sender: TObject); procedure lbActionsDragDrop(Sender, {%H-}Source: TObject; {%H-}X, Y: integer); procedure lbActionsSelectionChange(Sender: TObject; {%H-}User: boolean); procedure lbExtsDragDrop(Sender, {%H-}Source: TObject; X, Y: integer); procedure lbGenericListDrawItem(Control: TWinControl; Index: integer; ARect: TRect; State: TOwnerDrawState); procedure lbExtsSelectionChange(Sender: TObject; {%H-}User: boolean); procedure lbFileTypesDragDrop(Sender, {%H-}Source: TObject; {%H-}X, Y: integer); procedure lbGenericDragOver(Sender, Source: TObject; {%H-}X, Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure lbFileTypesDrawItem(Control: TWinControl; Index: integer; ARect: TRect; State: TOwnerDrawState); procedure lbFileTypesSelectionChange(Sender: TObject; {%H-}User: boolean); procedure edbActionNameChange(Sender: TObject); procedure fneCommandChange(Sender: TObject); procedure miActionsClick(Sender: TObject); procedure miCommandsClick(Sender: TObject); procedure pnlRightSettingsResize(Sender: TObject); procedure pnlSettingsResize(Sender: TObject); procedure sbtnIconClick(Sender: TObject); procedure MakeUsInPositionToWorkWithActiveFile; procedure actSelectFileTypeExecute(Sender: TObject); procedure actSelectIconExecute(Sender: TObject); procedure actSelectExtensionsExecute(Sender: TObject); procedure actSelectActionsExecute(Sender: TObject); procedure actSelectActionDescriptionExecute(Sender: TObject); private Exts: TExts; FUpdatingControls: boolean; liveActionList: TActionList; actSelectFileType: TAction; actSelectIcon: TAction; actSelectExtensions: TAction; actSelectActions: TAction; actSelectActionDescription: TAction; procedure UpdateEnabledButtons; {en Frees icon cached in lbFileTypes.Items.Objects[Index]. } procedure FreeIcon(iIndex: integer); procedure SetIconFileName(const sFileName: string); procedure SetMinimumSize; protected procedure Init; override; procedure Done; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; procedure ScanFileAssocForFilenameAndPath; function GetFileAssocFilenameToSave(AFileAssocPathModifierElement: tFileAssocPathModifierElement; sParamFilename: string): string; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. LCLProc, Math, LCLType, LazUTF8, //DC uVariableMenuSupport, DCStrUtils, uOSForms, fMain, uFile, uPixMapManager, uLng, uDCUtils, DCOSUtils, uShowMsg, uSpecialDir; const ACTUAL_ADD_ACTION = 1; SET_ACTION_WORD = 2; { TfrmOptionsFileAssoc } { TfrmOptionsFileAssoc.Init } procedure TfrmOptionsFileAssoc.Init; begin inherited Init; Exts := TExts.Create; FUpdatingControls := False; btnIconSelectFilename.Hint := sbtnIcon.Hint; OpenDialog.Filter := ParseLineToFileFilter([rsFilterExecutableFiles, '*.exe;*.com;*.bat', rsFilterAnyFiles, AllFilesMask]); // The following section is to help to speed up the the user with keyboard to pass to a section to another. // Each TGroupBox has their caption with 1, 2, 3... with underscore under each digit. // This suggest to user keyboard accelerator shortcut so he will type Alt+1, Alt+2, etc to pass to a section to another. // Unfortunately, at this moment in Windows at least, even if we have underscore, it does not work as keyboard accelerator... // It does not switch focus to the proper TGroupbox... // So what we will do is to mimic that. // We will display the caption of the TGroupBox with underscore to suggest the Alt+1, Alt+2, etc. // And we will add in our TActionList function to set the focus on proper TGroupBox and set the keyboard shortcut to Alt+1, Alt+2, etc. // So at the end it does the job. // If we defined that run-time here instead of having it in the form itself it's to avoid to have annoying empty caption yo appear in the languages files. liveActionList := TActionList.Create(Self); actSelectFileType := TAction.Create(nil); actSelectFileType.OnExecute := @actSelectFileTypeExecute; actSelectFileType.ShortCut := 32817; //Alt+1 actSelectFileType.ActionList := liveActionList; actSelectIcon := TAction.Create(nil); actSelectIcon.OnExecute := @actSelectIconExecute; actSelectIcon.ShortCut := 32818; //Alt+2 actSelectIcon.ActionList := liveActionList; actSelectExtensions := TAction.Create(nil); actSelectExtensions.OnExecute := @actSelectExtensionsExecute; actSelectExtensions.ShortCut := 32819; //Alt+3 actSelectExtensions.ActionList := liveActionList; actSelectActions := TAction.Create(nil); actSelectActions.OnExecute := @actSelectActionsExecute; actSelectActions.ShortCut := 32820; //Alt-4 actSelectActions.ActionList := liveActionList; actSelectActionDescription := TAction.Create(nil); actSelectActionDescription.OnExecute := @actSelectActionDescriptionExecute; actSelectActionDescription.ShortCut := 32821; //Alt-5 actSelectActionDescription.ActionList := liveActionList; end; { TfrmOptionsFileAssoc.Done } procedure TfrmOptionsFileAssoc.Done; var I: integer; begin for I := 0 to lbFileTypes.Items.Count - 1 do FreeIcon(I); FreeAndNil(Exts); FreeAndNil(actSelectActionDescription); FreeAndNil(actSelectActions); FreeAndNil(actSelectExtensions); FreeAndNil(actSelectIcon); FreeAndNil(actSelectFileType); FreeAndNil(liveActionList); inherited Done; end; { TfrmOptionsFileAssoc.Load } procedure TfrmOptionsFileAssoc.Load; var I: integer; sName: string; Bitmap: TBitmap; begin //Let's preserve the precious legacy .po translated groupbox name that we will re-use with dialog window concerning them gbFileTypes.hint := gbFileTypes.Caption; gbIcon.hint := gbIcon.Caption; gbExts.hint := gbExts.Caption; gbActions.hint := gbActions.Caption; gbActionDescription.hint := gbActionDescription.Caption; // Give some numerical step number to help user without losing legacy .po translated groubox name gbFileTypes.Caption := '&1 - ' + gbFileTypes.Caption; gbIcon.Caption := '&2 - ' + gbIcon.Caption; gbExts.Caption := '&3 - ' + gbExts.Caption; gbActions.Caption := '&4 - ' + gbActions.Caption; gbActionDescription.Caption := '&5 - ' + gbActionDescription.Caption; // load extension file Exts.Load; //'Pp'! A letter with the upper part and a letter with the lower part! This should give us approximation of highest room required! :-) lbFileTypes.ItemHeight := Max(gIconsSize, lbFileTypes.Canvas.TextHeight('Pp')) + 4; // fill file types list box for I := 0 to Exts.Count - 1 do begin sName := Exts.Items[I].Name; // load icon for use in OnDrawItem procedure Bitmap := PixMapManager.LoadBitmapEnhanced(Exts.Items[I].Icon, gIconsSize, True, lbFileTypes.Color); lbFileTypes.Items.AddObject(sName, Bitmap); end; if Exts.Count > 0 then lbFileTypes.ItemIndex := 0; UpdateEnabledButtons; // Populate helper menu gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper, mp_PATHHELPER, nil); inherited Load; end; { TfrmOptionsFileAssoc.Save } function TfrmOptionsFileAssoc.Save: TOptionsEditorSaveFlags; var iExt: integer; begin Exts.SaveXMLFile; gExts.Clear; gExts.Load; // The "gExts.Clear" has flush the "IconIndex" that have been set via "Load" of PixMapManager. // Since it has been lost AND PixMapManager.Load won't set again our iconindex, let's do manually here. // It is required so the icon next to our actions in SheelContextMenu will be the correct ones. for iExt := 0 to pred(gExts.Count) do TExtAction(gExts.Items[iExt]).IconIndex := PixMapManager.GetIconByName(TExtAction(gExts.Items[iExt]).Icon); Result := inherited Save; end; { TfrmOptionsFileAssoc.GetIconIndex } class function TfrmOptionsFileAssoc.GetIconIndex: integer; begin Result := 34; end; { TfrmOptionsFileAssoc.GetTitle } class function TfrmOptionsFileAssoc.GetTitle: string; begin Result := rsOptionsEditorFileAssoc; end; { TfrmOptionsFileAssoc.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsFileAssoc.IsSignatureComputedFromAllWindowComponents: boolean; begin Result := False; end; { TfrmOptionsFileAssoc.ExtraOptionsSignature } function TfrmOptionsFileAssoc.ExtraOptionsSignature(CurrentSignature: dword): dword; begin Result := Exts.ComputeSignature(CurrentSignature); end; { TfrmOptionsFileAssoc.UpdateEnabledButtons } procedure TfrmOptionsFileAssoc.UpdateEnabledButtons; begin if (lbFileTypes.Items.Count = 0) or (lbFileTypes.ItemIndex = -1) then begin sbtnIcon.Enabled := False; btnInsertExt.Enabled := False; btnAddExt.Enabled := False; btnInsertAct.Enabled := False; btnAddAct.Enabled := False; end else begin btnInsertExt.Enabled := (lbExts.Items.Count > 0); btnAddExt.Enabled := True; btnInsertAct.Enabled := (lbExts.Items.Count > 0) and (lbActions.ItemIndex <> -1); btnAddAct.Enabled := btnInsertExt.Enabled; sbtnIcon.Enabled := btnInsertExt.Enabled; end; btnRemoveExt.Enabled := ((lbExts.Items.Count <> 0) and (lbExts.ItemIndex <> -1)); btnEditExt.Enabled := btnRemoveExt.Enabled; if (lbActions.Items.Count = 0) or (lbActions.ItemIndex = -1) then begin btnUpAct.Enabled := False; btnDownAct.Enabled := False; btnRemoveAct.Enabled := False; edbActionName.Enabled := False; fneCommand.Enabled := False; edtParams.Enabled := False; deStartPath.Enabled := False; btnCommands.Enabled := False; btnRelativeCommand.Enabled := False; btnParametersHelper.Enabled := False; btnStartPathPathHelper.Enabled := False; btnStartPathVarHelper.Enabled := False; edbActionName.Text := ''; fneCommand.FileName := ''; edtParams.Text := ''; deStartPath.Text := ''; end else begin btnUpAct.Enabled := (lbActions.ItemIndex > 0); btnDownAct.Enabled := (lbActions.ItemIndex < lbActions.Items.Count - 1); btnRemoveAct.Enabled := True; edbActionName.Enabled := True; fneCommand.Enabled := True; btnRelativeCommand.Enabled := True; btnParametersHelper.Enabled := True; btnStartPathPathHelper.Enabled := True; btnStartPathVarHelper.Enabled := True; edtParams.Enabled := True; deStartPath.Enabled := True; btnCommands.Enabled := True; end; btnCloneAct.Enabled := btnRemoveAct.Enabled; end; { TfrmOptionsFileAssoc.btnAddNewTypeClick } procedure TfrmOptionsFileAssoc.btnAddNewTypeClick(Sender: TObject); var ExtAction: TExtAction; s: string; begin s := InputBox(GetTitle + ' - ' + gbFileTypes.Hint, rsMsgEnterName, ''); if s = '' then exit; ExtAction := TExtAction.Create; ExtAction.IconIndex := -1; with lbFileTypes do begin ExtAction.Name := s; Items.AddObject(ExtAction.Name, nil); // add file type to TExts object Exts.AddItem(ExtAction); ItemIndex := Items.Count - 1; end; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.btnRemoveTypeClick } procedure TfrmOptionsFileAssoc.btnRemoveTypeClick(Sender: TObject); var iIndex: integer; begin with lbFileTypes do begin iIndex := ItemIndex; if iIndex < 0 then Exit; FreeIcon(iIndex); Items.Delete(iIndex); Exts.DeleteItem(iIndex); if Items.Count = 0 then begin lbExts.Clear; lbActions.Clear; end else begin if iIndex = 0 then ItemIndex := 0 else ItemIndex := iIndex - 1; end; end; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.btnRemoveTypeResize } procedure TfrmOptionsFileAssoc.btnRemoveTypeResize(Sender: TObject); begin SetMinimumSize; end; { TfrmOptionsFileAssoc.btnRenameTypeClick } procedure TfrmOptionsFileAssoc.btnRenameTypeClick(Sender: TObject); var iIndex: integer; sName: string; begin iIndex := lbFileTypes.ItemIndex; if iIndex < 0 then Exit; sName := lbFileTypes.Items[iIndex]; sName := InputBox(GetTitle + ' - ' + gbFileTypes.Hint, rsMsgEnterName, sName); lbFileTypes.Items[iIndex] := sName; // rename file type in TExts object Exts.Items[iIndex].Name := sName; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.btnRenameTypeResize } procedure TfrmOptionsFileAssoc.btnRenameTypeResize(Sender: TObject); begin SetMinimumSize; end; { TfrmOptionsFileAssoc.lbActionsSelectionChange } procedure TfrmOptionsFileAssoc.lbActionsSelectionChange(Sender: TObject; User: boolean); var iIndex: integer; begin iIndex := lbActions.ItemIndex; if (iIndex < 0) or (lbActions.Tag = 1) then Exit; edbActionName.Tag := 1; edbActionName.Text := TExtActionCommand(lbActions.Items.Objects[iIndex]).ActionName; fneCommand.FileName := TExtActionCommand(lbActions.Items.Objects[iIndex]).CommandName; edtParams.Text := TExtActionCommand(lbActions.Items.Objects[iIndex]).Params; deStartPath.Text := TExtActionCommand(lbActions.Items.Objects[iIndex]).StartPath; edbActionName.Tag := 0; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.lbExtsDragDrop } procedure TfrmOptionsFileAssoc.lbExtsDragDrop(Sender, Source: TObject; X, Y: integer); var SrcIndex, DestIndex: integer; begin // exchange positions in extensions listbox SrcIndex := lbExts.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lbExts.GetIndexAtXY(X, Y); if (DestIndex < 0) or (DestIndex >= lbExts.Count) then DestIndex := lbExts.Count - 1; lbExts.Items.Move(SrcIndex, DestIndex); lbExts.ItemIndex := DestIndex; // change extension in TExts object Exts.Items[lbFileTypes.ItemIndex].Extensions.Move(SrcIndex, DestIndex); end; procedure TfrmOptionsFileAssoc.lbGenericListDrawItem(Control: TWinControl; Index: integer; ARect: TRect; State: TOwnerDrawState); begin with (Control as TListBox) do begin if (odSelected in State) then begin if focused then begin Canvas.Font.Color := clHighlightText; Canvas.Brush.Color := clHighlight; end else begin Canvas.Font.Color := clWindowText; Canvas.Brush.Color := clGradientActiveCaption; end; end else begin Canvas.Font.Color := Font.Color; Canvas.Brush.Color := Color; end; Canvas.FillRect(ARect); Canvas.TextOut(ARect.Left, ARect.Top, Items[Index]); end; end; { TfrmOptionsFileAssoc.lbExtsSelectionChange } procedure TfrmOptionsFileAssoc.lbExtsSelectionChange(Sender: TObject; User: boolean); begin if (lbExts.ItemIndex < 0) then Exit; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.lbFileTypesDragDrop } procedure TfrmOptionsFileAssoc.lbFileTypesDragDrop(Sender, Source: TObject; X, Y: integer); var SrcIndex, DestIndex: integer; begin // Validate if the move is okay SrcIndex := lbFileTypes.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lbFileTypes.GetIndexAtY(Y); if (DestIndex < 0) or (DestIndex >= lbFileTypes.Count) then DestIndex := lbFileTypes.Count - 1; // exchange positions in actions listbox lbActions.Tag := 1; // start moving try lbFileTypes.Items.Move(SrcIndex, DestIndex); lbFileTypes.ItemIndex := DestIndex; // exchange actions in TExts object Exts.MoveItem(SrcIndex, DestIndex); finally lbActions.Tag := 0; // end moving end; // trig the "SelectionChange" event to refresh extension and action lists lbFileTypesSelectionChange(lbFileTypes, False); UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.lbGenericDragOver } procedure TfrmOptionsFileAssoc.lbGenericDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin //Accept if it's coming from the same ListBox Accept := (Source is TListBox) and (TListBox(Source).Name = TListBox(Sender).Name); //Let's scroll up/down if user is dragging near the top/bottom if Y > (TListBox(Sender).Height - 15) then TListBox(Sender).TopIndex := TListBox(Sender).TopIndex + 1 else if Y < 15 then TListBox(Sender).TopIndex := TListBox(Sender).TopIndex - 1; end; { TfrmOptionsFileAssoc.lbFileTypesDrawItem } procedure TfrmOptionsFileAssoc.lbFileTypesDrawItem(Control: TWinControl; Index: integer; ARect: TRect; State: TOwnerDrawState); var iDrawTop: integer; begin with (Control as TListBox) do begin if odSelected in State then begin if focused then begin Canvas.Font.Color := clHighlightText; Canvas.Brush.Color := clHighlight; end else begin Canvas.Font.Color := clWindowText; Canvas.Brush.Color := clGradientActiveCaption; end; Canvas.FillRect(ARect); end else begin Canvas.Font.Color := Font.Color; Canvas.Brush.Color := Color; Canvas.FillRect(ARect); end; if (Canvas.Locked = False) and (Assigned(Items.Objects[Index])) then begin iDrawTop := ARect.Top + ((lbFileTypes.ItemHeight - gIconsSize) div 2); Canvas.Draw(ARect.Left + 2, iDrawTop, TBitmap(Items.Objects[Index])); end; iDrawTop := ARect.Top + ((lbFileTypes.ItemHeight - Canvas.TextHeight(Items[Index])) div 2); Canvas.TextOut(ARect.Left + gIconsSize + 6, iDrawTop, Items[Index]); end; end; { TfrmOptionsFileAssoc.lbFileTypesSelectionChange } procedure TfrmOptionsFileAssoc.lbFileTypesSelectionChange(Sender: TObject; User: boolean); var ExtCommand: TExtAction; I: integer; bmpTemp: TBitmap = nil; begin if (lbFileTypes.ItemIndex >= 0) and (lbFileTypes.ItemIndex < Exts.Count) then begin lbActions.Items.Clear; Application.ProcessMessages; lbExts.Items.Clear; Application.ProcessMessages; ExtCommand := Exts.Items[lbFileTypes.ItemIndex]; lbExts.Items.Assign(ExtCommand.Extensions); if lbExts.Count > 0 then lbExts.ItemIndex := 0; for I := 0 to pred(ExtCommand.ActionList.Count) do begin lbActions.Items.AddObject(ExtCommand.ActionList.ExtActionCommand[I].ActionName, ExtCommand.ActionList.ExtActionCommand[I]); end; if lbActions.Count > 0 then lbActions.ItemIndex := 0; bmpTemp := PixMapManager.LoadBitmapEnhanced(ExtCommand.Icon, 32, True, sbtnIcon.Color); try sbtnIcon.Glyph := bmpTemp; finally if Assigned(bmpTemp) then FreeAndNil(bmpTemp); end; FUpdatingControls := True; // Don't trigger OnChange edIconFileName.Text := ExtCommand.Icon; FUpdatingControls := False; end else begin lbExts.Items.Clear; lbActions.Items.Clear; sbtnIcon.Glyph.Clear; edIconFileName.Text := ''; end; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.edbActionChange } procedure TfrmOptionsFileAssoc.edbActionNameChange(Sender: TObject); var iIndex: integer; begin if edbActionName.Tag = 1 then exit; iIndex := lbActions.ItemIndex; if (iIndex < 0) or (edbActionName.Text = '') then Exit; TExtActionCommand(lbActions.Items.Objects[iIndex]).ActionName := edbActionName.Text; lbActions.Items[iIndex] := edbActionName.Text; end; { TfrmOptionsFileAssoc.fneCommandChange } procedure TfrmOptionsFileAssoc.fneCommandChange(Sender: TObject); var iIndex: integer; begin iIndex := lbActions.ItemIndex; if (edbActionName.Tag = 1) or (iIndex < 0) then Exit; TExtActionCommand(lbActions.Items.Objects[iIndex]).CommandName := fneCommand.Text; if fneCommand.InitialDir <> ExtractFilePath(fneCommand.Text) then fneCommand.InitialDir := ExtractFilePath(fneCommand.Text); end; { TfrmOptionsFileAssoc.edtExternalParametersChange } procedure TfrmOptionsFileAssoc.edtParamsChange(Sender: TObject); var iIndex: integer; begin iIndex := lbActions.ItemIndex; if (edbActionName.Tag = 1) or (iIndex < 0) then Exit; TExtActionCommand(lbActions.Items.Objects[iIndex]).Params := edtParams.Text; end; { TfrmOptionsFileAssoc.deStartPathChange } procedure TfrmOptionsFileAssoc.deStartPathChange(Sender: TObject); var iIndex: integer; begin iIndex := lbActions.ItemIndex; if (edbActionName.Tag = 1) or (iIndex < 0) then Exit; TExtActionCommand(lbActions.Items.Objects[iIndex]).StartPath := deStartPath.Text; if deStartPath.Directory <> deStartPath.Text then deStartPath.Directory := deStartPath.Text; end; { TfrmOptionsFileAssoc.miActionsClick } // The "tag" of the menu item calling this will give us information about the task to do. // xxxx xx10 : Bit 1 & 0 indicate if user wants "Open", "View", "Edit" or "Custom action". // xxx4 xxxx : Bit 4 indicates if user wants to specify immediately a .exe file for the command. (0=no, 1=yes). // xx5x xxxx : Bit 5 indicates if user wants to "Add" or "Insert" action in the current list. (0=add, 1=insert). procedure TfrmOptionsFileAssoc.miActionsClick(Sender: TObject); var miMenuItem: TMenuItem absolute Sender; I, iDispatcher: integer; ExtAction: TExtAction; sActionWords: string = ''; sCommandFilename: string = ''; begin with Sender as TComponent do iDispatcher := tag; // Transform the task in "add" if currently there is no action, nothing selected, any incoherence. if (Exts.Items[lbFileTypes.ItemIndex].ActionList.Count = 0) or (lbActions.Items.Count = 0) or (lbActions.ItemIndex = -1) then iDispatcher := (iDispatcher and $DF); if iDispatcher and $03 = $03 then gFileAssociationLastCustomAction := InputBox(GetTitle + ' - ' + gbActions.Hint, rsMsgEnterCustomAction, gFileAssociationLastCustomAction); case (iDispatcher and $DF) of $00: sActionWords := 'Open'; $01: sActionWords := 'View'; $02: sActionWords := 'Edit'; $03: sActionWords := gFileAssociationLastCustomAction; $10: OpenDialog.Title := rsMsgSelectExecutableFile + ' "Open"...'; $11: OpenDialog.Title := rsMsgSelectExecutableFile + ' "View"...'; $12: OpenDialog.Title := rsMsgSelectExecutableFile + ' "Edit"...'; $13: OpenDialog.Title := rsMsgSelectExecutableFile + ' "' + gFileAssociationLastCustomAction + '"...'; end; case iDispatcher and $10 of $10: begin if OpenDialog.Execute then begin sCommandFilename := GetFileAssocFilenameToSave(fameCommand, OpenDialog.Filename); case (iDispatcher and $03) of $00: sActionWords := 'Open ' + rsMsgWithActionWith + ' ' + ExtractFilename(OpenDialog.Filename); $01: sActionWords := 'View ' + rsMsgWithActionWith + ' ' + ExtractFilename(OpenDialog.Filename); $02: sActionWords := 'Edit ' + rsMsgWithActionWith + ' ' + ExtractFilename(OpenDialog.Filename); $03: sActionWords := gFileAssociationLastCustomAction + ' ' + rsMsgWithActionWith + ' ' + ExtractFilename(OpenDialog.Filename); end; end; end; end; case pmActions.Tag of ACTUAL_ADD_ACTION: begin ExtAction := Exts.Items[lbFileTypes.ItemIndex]; // insert/add action to TExts object case iDispatcher and $20 of $20: // it is an "insert" begin I := lbActions.ItemIndex; case (iDispatcher and $DF) of $00, $01, $02, $03: ExtAction.ActionList.Insert(I, TExtActionCommand.Create(sActionWords, '', '', '')); $10, $11, $12, $13: ExtAction.ActionList.Insert(I, TExtActionCommand.Create(sActionWords, sCommandFilename, '%p', '')); end; // add action to actions listbox lbActions.Items.InsertObject(I, '', ExtAction.ActionList.ExtActionCommand[I]); end else begin // it is a "add" case (iDispatcher and $DF) of $00, $01, $02, $03: I := ExtAction.ActionList.Add(TExtActionCommand.Create(sActionWords, '', '', '')); $10, $11, $12, $13: I := ExtAction.ActionList.Add(TExtActionCommand.Create(sActionWords, sCommandFilename, '%p', '')); end; // add action to actions listbox lbActions.Items.AddObject(ExtAction.ActionList.ExtActionCommand[I].ActionName, ExtAction.ActionList.ExtActionCommand[I]); end; end; lbActions.ItemIndex := I; edbActionNameChange(edbActionName); //<--Trig this event to force redraw of lbActions current selected element because in case of switch from "open" to identical "open" for exemple, "edbActionChange" is not trig and so our element in the list is not drawn! // Update icon if possible, if necessary case (iDispatcher and $10) of $10: if Exts.Items[lbFileTypes.ItemIndex].Icon = '' then edIconFileName.Text := GetFileAssocFilenameToSave(fameIcon, OpenDialog.FileName); //No quote required here! So "sCommandFilename" is not used. end; UpdateEnabledButtons; if edbActionName.CanFocus then begin edbActionName.SetFocus; edbActionName.SelStart := UTF8Length(edbActionName.Text); end; end; SET_ACTION_WORD: begin case (iDispatcher and $DF) of $00, $01, $02, $03: edbActionName.Text := sActionWords; $10, $11, $12, $13: begin edbActionName.Text := sActionWords; fneCommand.Text := sCommandFilename; edtParams.Text := '%p'; end; end; end; else begin if miMenuItem.Name = 'miOpen' then edbActionName.Text := 'Open' else if miMenuItem.Name = 'miView' then edbActionName.Text := 'View' else if miMenuItem.Name = 'miEdit' then edbActionName.Text := 'Edit'; end; end; end; { TfrmOptionsFileAssoc.miCommandsClick } procedure TfrmOptionsFileAssoc.miCommandsClick(Sender: TObject); begin with Sender as TComponent do begin case tag of 2: fneCommand.SelText := '{!VIEWER}'; 3: fneCommand.SelText := '{!DC-VIEWER}'; 4: fneCommand.SelText := '{!EDITOR}'; 5: fneCommand.SelText := '{!DC-EDITOR}'; 6: fneCommand.SelText := '{!SHELL}'; 7: begin fneCommand.SelText := fneCommand.Text + '<??>'; fneCommand.SetFocus; fneCommand.SelStart := Pos('?>', fneCommand.Text) - 1; end; end; end; end; { TfrmOptionsFileAssoc.pnlRightSettingsResize } procedure TfrmOptionsFileAssoc.pnlRightSettingsResize(Sender: TObject); begin gbExts.Height := pnlRightSettings.ClientHeight div 4; end; { TfrmOptionsFileAssoc.pnlSettingsResize } procedure TfrmOptionsFileAssoc.pnlSettingsResize(Sender: TObject); begin pnlLeftSettings.Width := pnlSettings.ClientWidth div 3; end; { TfrmOptionsFileAssoc.sbtnIconClick } procedure TfrmOptionsFileAssoc.sbtnIconClick(Sender: TObject); var sFileName: string; begin sFileName := mbExpandFileName(edIconFileName.Text); if ShowOpenIconDialog(Self, sFileName) then edIconFileName.Text := GetFileAssocFilenameToSave(fameIcon, sFileName); end; { TfrmOptionsFileAssoc.InsertAddSingleExtensionToLists } function TfrmOptionsFileAssoc.InsertAddSingleExtensionToLists(sExt: string; iInsertPosition: integer): boolean; begin Result := False; if (sExt <> '') then begin if Exts.Items[lbFileTypes.ItemIndex].Extensions.IndexOf(sExt) = -1 then begin if iInsertPosition = -1 then iInsertPosition := lbExts.Items.Add(sExt) else lbExts.Items.Insert(iInsertPosition, sExt); lbExts.ItemIndex := iInsertPosition; //add extension in TExts object Exts.Items[lbFileTypes.ItemIndex].Extensions.Insert(iInsertPosition, sExt); Result := True; end else begin lbExts.ItemIndex := Exts.Items[lbFileTypes.ItemIndex].Extensions.IndexOf(sExt); end; UpdateEnabledButtons; end; end; { TfrmOptionsFileAssoc.InsertAddExtensionToLists } procedure TfrmOptionsFileAssoc.InsertAddExtensionToLists(sParamExt: string; iPositionToInsert: integer); var iIndex: integer; sExt: string; begin sParamExt := sParamExt + '|'; while Pos('|', sParamExt) <> 0 do begin iIndex := Pos('|', sParamExt); sExt := Copy(sParamExt, 1, iIndex - 1); Delete(sParamExt, 1, iIndex); if InsertAddSingleExtensionToLists(sExt, iPositionToInsert) then if iPositionToInsert <> -1 then Inc(iPositionToInsert); end; end; { TfrmOptionsFileAssoc.btnInsertAddExtClick } procedure TfrmOptionsFileAssoc.btnInsertAddExtClick(Sender: TObject); var sExt: string; Dispatcher: integer; begin with Sender as TComponent do Dispatcher := tag; if (lbExts.Items.Count = 0) or (lbExts.ItemIndex = -1) then Dispatcher := 0; sExt := InputBox(GetTitle + ' - ' + gbExts.Hint, rsMsgEnterFileExt, ''); InsertAddExtensionToLists(sExt, ifthen((Dispatcher = 0), -1, lbExts.ItemIndex)); if lbExts.CanFocus then lbExts.SetFocus; end; { TfrmOptionsFileAssoc.btnParametersHelperClick } procedure TfrmOptionsFileAssoc.btnParametersHelperClick(Sender: TObject); begin BringPercentVariablePopupMenu(edtParams); end; { TfrmOptionsFileAssoc.btnRelativeCommandClick } procedure TfrmOptionsFileAssoc.btnRelativeCommandClick(Sender: TObject); begin fneCommand.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneCommand, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsFileAssoc.btnRelativePathIconClick } procedure TfrmOptionsFileAssoc.btnRelativePathIconClick(Sender: TObject); begin edIconFileName.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edIconFileName, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsFileAssoc.btnStartPathPathHelperClick } procedure TfrmOptionsFileAssoc.btnStartPathPathHelperClick(Sender: TObject); begin deStartPath.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(deStartPath, pfPATH); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsFileAssoc.btnStartPathVarHelperClick } procedure TfrmOptionsFileAssoc.btnStartPathVarHelperClick(Sender: TObject); begin BringPercentVariablePopupMenu(deStartPath); end; procedure TfrmOptionsFileAssoc.deStartPathAcceptDirectory(Sender: TObject; var Value: String); begin Value := GetFileAssocFilenameToSave(fameStartingPath, Value); end; { TfrmOptionsFileAssoc.edIconFileNameChange } procedure TfrmOptionsFileAssoc.edIconFileNameChange(Sender: TObject); begin if not FUpdatingControls then SetIconFileName(edIconFileName.Text); end; procedure TfrmOptionsFileAssoc.fneCommandAcceptFileName(Sender: TObject; var Value: String); begin Value := GetFileAssocFilenameToSave(fameCommand, Value); end; { TfrmOptionsFileAssoc.FrameResize } procedure TfrmOptionsFileAssoc.FrameResize(Sender: TObject); begin lbExts.Columns := (lbExts.Width div 120); end; { TfrmOptionsFileAssoc.btnRemoveExtClick } procedure TfrmOptionsFileAssoc.btnRemoveExtClick(Sender: TObject); var I: integer; begin // remove extension from extensions listbox with lbExts do begin I := ItemIndex; if I < 0 then Exit; Items.Delete(I); if I < Items.Count then ItemIndex := I else if (I - 1) < Items.Count then ItemIndex := (I - 1); end; // remove extension from TExts object Exts.Items[lbFileTypes.ItemIndex].Extensions.Delete(I); UpdateEnabledButtons; if lbExts.CanFocus then lbExts.SetFocus; end; { TfrmOptionsFileAssoc.btnUpActClick } procedure TfrmOptionsFileAssoc.btnUpActClick(Sender: TObject); var I: integer; begin // move action in actions listbox with lbActions do begin Tag := 1; // start moving I := ItemIndex; if I = -1 then exit; if I > 0 then begin Items.Move(I, I - 1); ItemIndex := I - 1; end; end; // move action in TExts object with lbFileTypes do begin Exts.Items[ItemIndex].ActionList.Move(I, I - 1); end; lbActions.Tag := 0; // end moving UpdateEnabledButtons; if lbActions.CanFocus then lbActions.SetFocus; end; { TfrmOptionsFileAssoc.lbActionsDragDrop } procedure TfrmOptionsFileAssoc.lbActionsDragDrop(Sender, Source: TObject; X, Y: integer); var SrcIndex, DestIndex: integer; begin // Validate if the move is okay SrcIndex := lbActions.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lbActions.GetIndexAtY(Y); if (DestIndex < 0) or (DestIndex >= lbActions.Count) then DestIndex := lbActions.Count - 1; // exchange positions in actions listbox lbActions.Tag := 1; // start moving try lbActions.Items.Move(SrcIndex, DestIndex); lbActions.ItemIndex := DestIndex; // exchange actions in TExts object Exts.Items[lbFileTypes.ItemIndex].ActionList.Move(SrcIndex, DestIndex); finally lbActions.Tag := 0; // end moving end; UpdateEnabledButtons; end; { TfrmOptionsFileAssoc.btnDownActClick } procedure TfrmOptionsFileAssoc.btnDownActClick(Sender: TObject); var I: integer; begin // move action in actions listbox with lbActions do begin Tag := 1; // start moving I := ItemIndex; if I = -1 then exit; if (I < Items.Count - 1) and (I > -1) then begin Items.Move(I, I + 1); ItemIndex := I + 1; end; end; // move action in TExts object with lbFileTypes do begin Exts.Items[ItemIndex].ActionList.Move(I, I + 1); end; lbActions.Tag := 0; // end moving UpdateEnabledButtons; if lbActions.CanFocus then lbActions.SetFocus; end; { TfrmOptionsFileAssoc.btnEditExtClick } procedure TfrmOptionsFileAssoc.btnEditExtClick(Sender: TObject); var iRememberIndex: integer; sExt: string; begin iRememberIndex := lbExts.ItemIndex; if iRememberIndex < 0 then Exit; // change extension from extensions listbox sExt := InputBox(GetTitle + ' - ' + gbExts.Hint, rsMsgEnterFileExt, lbExts.Items[iRememberIndex]); if sExt <> lbExts.Items[iRememberIndex] then begin btnRemoveExtClick(btnRemoveExt); //We remove the old value if iRememberIndex >= lbExts.Items.Count then iRememberIndex := -1; InsertAddExtensionToLists(sExt, iRememberIndex); //We may add new one, maybe not, maybe bunch of them, etc. end; if lbExts.CanFocus then lbExts.SetFocus; end; { TfrmOptionsFileAssoc.btnInsertAddActClick } procedure TfrmOptionsFileAssoc.btnInsertAddActClick(Sender: TObject); var iSubMenu: integer; begin pmActions.Tag := ACTUAL_ADD_ACTION; for iSubMenu := 0 to pred(pmActions.Items.Count) do with pmActions.Items[iSubMenu] do Tag := ifthen((TComponent(Sender).Tag = $20), (Tag or $20), (Tag and $DF)); pmActions.PopUp(); end; { TfrmOptionsFileAssoc.btnActionsClick } procedure TfrmOptionsFileAssoc.btnActionsClick(Sender: TObject); begin pmActions.tag := SET_ACTION_WORD; pmActions.PopUp(); end; { TfrmOptionsFileAssoc.btnCloneActClick } procedure TfrmOptionsFileAssoc.btnCloneActClick(Sender: TObject); var ExtAction: TExtAction; I: integer; begin ExtAction := Exts.Items[lbFileTypes.ItemIndex]; I := lbActions.ItemIndex; if (I + 1) <= pred(ExtAction.ActionList.Count) then begin ExtAction.ActionList.Insert(I + 1, ExtAction.ActionList.ExtActionCommand[I].CloneExtAction); // add action to TExtAction lbActions.Items.InsertObject(I + 1, '', ExtAction.ActionList.ExtActionCommand[I + 1]); // add action to actions listbox end else begin ExtAction.ActionList.Add(ExtAction.ActionList.ExtActionCommand[I].CloneExtAction); // add action to TExtAction lbActions.Items.AddObject(ExtAction.ActionList.ExtActionCommand[I + 1].ActionName, ExtAction.ActionList.ExtActionCommand[I + 1]); // add action to actions listbox end; lbActions.ItemIndex := I + 1; edbActionNameChange(edbActionName); //<--Trig this event to force redraw of lbActions current selected element because in case of switch from "open" to identical "open" for exemple, "edbActionChange" is not trig and so our element in the list is not drawn! UpdateEnabledButtons; if edbActionName.CanFocus then begin edbActionName.SetFocus; edbActionName.SelStart := UTF8Length(edbActionName.Text); end; end; { TfrmOptionsFileAssoc.btnRemoveActClick } procedure TfrmOptionsFileAssoc.btnRemoveActClick(Sender: TObject); var I: integer; begin // remove action from actions listbox with lbActions do begin I := ItemIndex; if I < 0 then Exit; Items.Delete(I); if I < Items.Count then ItemIndex := I else if (I - 1) < Items.Count then ItemIndex := (I - 1); end; // remove action from TExts object with lbFileTypes do begin Exts.Items[ItemIndex].ActionList.Delete(I); end; UpdateEnabledButtons; if lbActions.CanFocus then lbActions.SetFocus; end; { TfrmOptionsFileAssoc.btnCommandsClick } procedure TfrmOptionsFileAssoc.btnCommandsClick(Sender: TObject); begin pmCommands.PopUp(); end; { TfrmOptionsFileAssoc.FreeIcon } procedure TfrmOptionsFileAssoc.FreeIcon(iIndex: integer); begin with lbFileTypes do begin Canvas.Lock; try if Assigned(Items.Objects[iIndex]) then begin Items.Objects[iIndex].Free; Items.Objects[iIndex] := nil; end; finally Canvas.Unlock; end; end; end; { TfrmOptionsFileAssoc.SetIconFileName } procedure TfrmOptionsFileAssoc.SetIconFileName(const sFileName: string); var bmpTemp: TBitmap; Index: integer; begin if sFileName <> EmptyStr then begin bmpTemp := PixMapManager.LoadBitmapEnhanced(sFileName, 32, True, sbtnIcon.Color); if Assigned(bmpTemp) then begin sbtnIcon.Glyph.Assign(bmpTemp); FreeAndNil(bmpTemp); end else sbtnIcon.Glyph.Clear; end else sbtnIcon.Glyph.Clear; Index := lbFileTypes.ItemIndex; if (Index >= 0) and (Index < Exts.Count) then begin FreeIcon(Index); // save icon for use in OnDrawItem procedure if sFileName <> EmptyStr then lbFileTypes.Items.Objects[Index] := PixMapManager.LoadBitmapEnhanced(sFileName, gIconsSize, True, Color); lbFileTypes.Repaint; Exts.Items[Index].Icon := sFileName; Exts.Items[Index].IconIndex := -1; end; end; { TfrmOptionsFileAssoc.SetMinimumSize } procedure TfrmOptionsFileAssoc.SetMinimumSize; begin gbFileTypes.Constraints.MinWidth := gbFileTypes.BorderSpacing.Left + btnRemoveType.Left + btnRemoveType.Width + 5 + // space between btnRenameType.Width + gbFileTypes.Width - (btnRenameType.Left + btnRenameType.Width) + gbFileTypes.BorderSpacing.Right; pnlLeftSettings.Constraints.MinWidth := gbFileTypes.Constraints.MinWidth + gbFileTypes.BorderSpacing.Around; Constraints.MinWidth := pnlLeftSettings.Constraints.MinWidth + pnlLeftSettings.BorderSpacing.Left + pnlLeftSettings.BorderSpacing.Right + pnlLeftSettings.BorderSpacing.Around + pnlRightSettings.Constraints.MinWidth + pnlRightSettings.BorderSpacing.Left + pnlRightSettings.BorderSpacing.Right + pnlRightSettings.BorderSpacing.Around; end; { TfrmOptionsFileAssoc.MakeUsInPositionToWorkWithActiveFile } procedure TfrmOptionsFileAssoc.MakeUsInPositionToWorkWithActiveFile; var aFile: TFile; InnerActionList: TExtActionList; IndexOfFirstPossibleFileType: integer; sFileType, sDummy: string; ExtAction: TExtAction; iInsertPosition: integer; iSelectedFileType: integer = -1; InnerFileTypeNameList: TStringList; begin aFile := frmMain.ActiveFrame.CloneActiveFile; if Assigned(aFile) then begin if (not aFile.IsDirectory) and (not aFile.IsLink) and (not (aFile.Extension = '')) then begin InnerActionList := TExtActionList.Create; try if gExts.GetExtActions(aFile, InnerActionList, @IndexOfFirstPossibleFileType) then begin if (IndexOfFirstPossibleFileType <> -1) and (lbFileTypes.Items.Count > IndexOfFirstPossibleFileType) then //Double verification, but unnecessary. begin lbFileTypes.ItemIndex := IndexOfFirstPossibleFileType; lbFileTypesSelectionChange(lbFileTypes, False); lbExts.ItemIndex := lbExts.Items.IndexOf(aFile.Extension); if (lbExts.ItemIndex = -1) and (lbExts.Items.Count > 0) then lbExts.ItemIndex := 0; end; end else begin // Extension of current selected file is not in our file associations list. if gOfferToAddToFileAssociations then begin InnerFileTypeNameList := TStringList.Create; try InnerFileTypeNameList.Assign(lbFileTypes.Items); InnerFileTypeNameList.Insert(0, Format(rsMsgCreateANewFileType, [UpperCase(aFile.Extension)])); if ShowInputListBox(rsMsgTitleExtNotInFileType, Format(rsMsgSekectFileType, [aFile.Extension]), InnerFileTypeNameList, sDummy, iSelectedFileType) then begin if iSelectedFileType <> -1 then begin if iSelectedFileType <> 0 then begin Dec(iSelectedFileType); //1. Select the specified file type lbFileTypes.ItemIndex := iSelectedFileType; lbFileTypesSelectionChange(lbFileTypes, False); //2. Add the extension to listbox AND structure iInsertPosition := lbExts.Items.Add(aFile.Extension); lbExts.ItemIndex := iInsertPosition; Exts.Items[lbFileTypes.ItemIndex].Extensions.Add(aFile.Extension); end else begin sFileType := UpperCase(aFile.Extension) + ' ' + rsSimpleWordFiles; if InputQuery(rsMsgTitleExtNotInFileType, Format(rsMsgEnterNewFileTypeName, [aFile.Extension]), sFileType) then begin //1. Create the file type ExtAction := TExtAction.Create; ExtAction.IconIndex := -1; ExtAction.Name := sFileType; lbFileTypes.Items.AddObject(ExtAction.Name, nil); //2. Add it to our structure AND listbox Exts.AddItem(ExtAction); lbFileTypes.ItemIndex := pred(lbFileTypes.Items.Count); //3. Add the extension to listbox AND structure iInsertPosition := lbExts.Items.Add(aFile.Extension); lbExts.ItemIndex := iInsertPosition; Exts.Items[lbFileTypes.ItemIndex].Extensions.Add(aFile.Extension); //4. Select an action for "open" pmActions.tag := ACTUAL_ADD_ACTION; miActionsClick(miOpenWith); //5. Refresh display to have appropriate button shown. UpdateEnabledButtons; end; end; end; end; finally FreeAndNil(InnerFileTypeNameList); end; end; end; finally FreeAndNil(InnerActionList); end; FreeAndNil(aFile); end; end; if lbFileTypes.CanFocus then lbFileTypes.SetFocus; end; procedure TfrmOptionsFileAssoc.actSelectFileTypeExecute(Sender: TObject); begin if lbFileTypes.CanFocus then lbFileTypes.SetFocus; end; procedure TfrmOptionsFileAssoc.actSelectIconExecute(Sender: TObject); begin if edIconFileName.CanFocus then edIconFileName.SetFocus; end; procedure TfrmOptionsFileAssoc.actSelectExtensionsExecute(Sender: TObject); begin if lbExts.CanFocus then lbExts.SetFocus; end; procedure TfrmOptionsFileAssoc.actSelectActionsExecute(Sender: TObject); begin if lbActions.CanFocus then lbActions.SetFocus; end; procedure TfrmOptionsFileAssoc.actSelectActionDescriptionExecute(Sender: TObject); begin if edbActionName.CanFocus then edbActionName.SetFocus; end; { TfrmOptionsFileAssoc.GetFileAssocFilenameToSave } function TfrmOptionsFileAssoc.GetFileAssocFilenameToSave(AFileAssocPathModifierElement:tFileAssocPathModifierElement; sParamFilename: string): string; var sMaybeBasePath, SubWorkingPath, MaybeSubstitionPossible: string; begin sParamFilename := mbExpandFileName(sParamFilename); Result := sParamFilename; if AFileAssocPathModifierElement in gFileAssocPathModifierElements then begin if gFileAssocFilenameStyle = pfsRelativeToDC then sMaybeBasePath := EnvVarCommanderPath else sMaybeBasePath := gFileAssocPathToBeRelativeTo; case gFileAssocFilenameStyle of pfsAbsolutePath: ; pfsRelativeToDC, pfsRelativeToFollowingPath: begin SubWorkingPath := IncludeTrailingPathDelimiter(mbExpandFileName(sMaybeBasePath)); MaybeSubstitionPossible := ExtractRelativePath(IncludeTrailingPathDelimiter(SubWorkingPath), sParamFilename); if MaybeSubstitionPossible <> sParamFilename then Result := IncludeTrailingPathDelimiter(sMaybeBasePath) + MaybeSubstitionPossible; end; end; end; end; { TfrmOptionsFileAssoc.ScanFileAssocForFilenameAndPath } procedure TfrmOptionsFileAssoc.ScanFileAssocForFilenameAndPath; var ActionList: TExtActionList; iFileType, iAction: Integer; begin for iFileType := 0 to Pred(Exts.Count) do begin Exts.FileType[iFileType].Icon := GetFileAssocFilenameToSave(fameIcon, Exts.FileType[iFileType].Icon); ActionList := Exts.FileType[iFileType].ActionList; for iAction := 0 to Pred(ActionList.Count) do begin ActionList.ExtActionCommand[iAction].CommandName := GetFileAssocFilenameToSave(fameCommand, ActionList.ExtActionCommand[iAction].CommandName); ActionList.ExtActionCommand[iAction].StartPath := GetFileAssocFilenameToSave(fameStartingPath, ActionList.ExtActionCommand[iAction].StartPath); end; end; //Kind of refresh of what might be displayed. if lbFileTypes.ItemIndex <> -1 then lbFileTypesSelectionChange(lbFileTypes, True); end; end. ������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileassocextra.lfm����������������������������������������������0000644�0001750�0000144�00000025407�14743153644�022160� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFileAssocExtra: TfrmOptionsFileAssocExtra Height = 508 Width = 937 HelpKeyword = '/configuration.html#ConfigAssocEx' AutoSize = True BorderSpacing.Around = 6 ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 508 ClientWidth = 937 ParentShowHint = False ShowHint = True DesignLeft = 141 DesignTop = 288 object cbOfferToAddToFileAssociations: TCheckBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 6 Height = 19 Hint = 'When accessing file association, offer to add current selected file if not already included in a configured file type' Top = 6 Width = 372 Caption = 'Offer to add selection to file association when not included already' TabOrder = 0 end object gbExtendedContextMenuOptions: TGroupBox[1] AnchorSideLeft.Control = cbOfferToAddToFileAssociations AnchorSideTop.Control = cbExtendedContextMenu AnchorSideTop.Side = asrBottom Left = 6 Height = 147 Top = 58 Width = 223 AutoSize = True BorderSpacing.Top = 4 Caption = 'Extended options items:' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ClientHeight = 127 ClientWidth = 219 TabOrder = 1 object cbDefaultContextActions: TCheckBox AnchorSideLeft.Control = gbExtendedContextMenuOptions AnchorSideTop.Control = gbExtendedContextMenuOptions Left = 8 Height = 19 Top = 8 Width = 203 BorderSpacing.Top = 4 Caption = 'Default context actions (View/Edit)' TabOrder = 0 end object cbExecuteViaShell: TCheckBox AnchorSideLeft.Control = cbDefaultContextActions AnchorSideTop.Control = cbDefaultContextActions AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 31 Width = 106 BorderSpacing.Top = 4 Caption = 'Execute via shell' TabOrder = 1 end object cbOpenSystemWithTerminalClose: TCheckBox AnchorSideLeft.Control = cbExecuteViaShell AnchorSideTop.Control = cbExecuteViaShell AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 54 Width = 179 BorderSpacing.Top = 4 Caption = 'Execute via terminal and close' TabOrder = 2 end object cbOpenSystemWithTerminalStayOpen: TCheckBox AnchorSideLeft.Control = cbExecuteViaShell AnchorSideTop.Control = cbOpenSystemWithTerminalClose AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 77 Width = 203 BorderSpacing.Top = 4 Caption = 'Execute via terminal and stay open' TabOrder = 3 end object cbIncludeConfigFileAssoc: TCheckBox AnchorSideLeft.Control = cbExecuteViaShell AnchorSideTop.Control = cbOpenSystemWithTerminalStayOpen AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 100 Width = 175 BorderSpacing.Top = 4 Caption = 'File association configuration' TabOrder = 4 end end object cbExtendedContextMenu: TCheckBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = cbOfferToAddToFileAssociations AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 35 Width = 146 BorderSpacing.Top = 10 Caption = 'Extended context menu' OnChange = cbExtendedContextMenuChange TabOrder = 2 end object gbToolbarOptionsExtra: TGroupBox[3] AnchorSideLeft.Control = cbOfferToAddToFileAssociations AnchorSideTop.Control = gbExtendedContextMenuOptions AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 161 Top = 205 Width = 925 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Paths' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 6 ClientHeight = 141 ClientWidth = 921 TabOrder = 3 object lbFileAssocFilenameStyle: TLabel AnchorSideLeft.Control = gbToolbarOptionsExtra AnchorSideTop.Control = gbToolbarOptionsExtra Left = 6 Height = 15 Top = 6 Width = 426 Caption = 'Way to set paths when adding elements for icons, commands and starting paths:' ParentColor = False end object cbFileAssocFilenameStyle: TComboBox AnchorSideLeft.Control = lbFileAssocFilenameStyle AnchorSideTop.Control = lbFileAssocFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbToolbarOptionsExtra AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 27 Width = 909 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 OnChange = cbFileAssocFilenameStyleChange Style = csDropDownList TabOrder = 0 end object btnPathToBeRelativeToHelper: TSpeedButton AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideRight.Control = cbFileAssocFilenameStyle AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = dePathToBeRelativeTo AnchorSideBottom.Side = asrBottom Left = 892 Height = 23 Top = 56 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnPathToBeRelativeToHelperClick end object dePathToBeRelativeTo: TDirectoryEdit AnchorSideLeft.Control = lbPathToBeRelativeTo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbFileAssocFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnPathToBeRelativeToHelper Left = 120 Height = 23 Top = 56 Width = 770 ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 1 MaxLength = 0 TabOrder = 1 end object lbPathToBeRelativeTo: TLabel AnchorSideLeft.Control = lbFileAssocFilenameStyle AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 60 Width = 112 Caption = 'Path to be relative to:' ParentColor = False end object btnPathToBeRelativeToAll: TButton AnchorSideLeft.Control = lbFileAssocFilenameStyle AnchorSideTop.Control = ckbFileAssocIcons AnchorSideTop.Side = asrBottom Left = 6 Height = 25 Top = 110 Width = 382 AutoSize = True Caption = 'Apply current settings to all current configured filenames and paths' OnClick = btnPathToBeRelativeToAllClick TabOrder = 2 end object ckbFileAssocIcons: TCheckBox AnchorSideLeft.Control = lblApplySettingsFor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 162 Height = 19 Top = 85 Width = 48 BorderSpacing.Left = 6 Caption = 'Icons' TabOrder = 3 end object lblApplySettingsFor: TLabel AnchorSideLeft.Control = lbFileAssocFilenameStyle AnchorSideTop.Control = ckbFileAssocIcons AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 87 Width = 150 Caption = 'Do this for files and path for:' ParentColor = False end object ckbFileAssocCommand: TCheckBox AnchorSideLeft.Control = ckbFileAssocIcons AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 216 Height = 19 Top = 85 Width = 82 BorderSpacing.Left = 6 Caption = 'Commands' TabOrder = 4 end object ckbFileAssocStartPath: TCheckBox AnchorSideLeft.Control = ckbFileAssocCommand AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 304 Height = 19 Top = 85 Width = 93 BorderSpacing.Left = 6 Caption = 'Starting paths' TabOrder = 5 end end object pmPathToBeRelativeToHelper: TPopupMenu[4] Left = 596 Top = 140 end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileassocextra.lrj����������������������������������������������0000644�0001750�0000144�00000011337�14743153644�022166� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":161997381,"name":"tfrmoptionsfileassocextra.cboffertoaddtofileassociations.hint","sourcebytes":[87,104,101,110,32,97,99,99,101,115,115,105,110,103,32,102,105,108,101,32,97,115,115,111,99,105,97,116,105,111,110,44,32,111,102,102,101,114,32,116,111,32,97,100,100,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,101,100,32,102,105,108,101,32,105,102,32,110,111,116,32,97,108,114,101,97,100,121,32,105,110,99,108,117,100,101,100,32,105,110,32,97,32,99,111,110,102,105,103,117,114,101,100,32,102,105,108,101,32,116,121,112,101],"value":"When accessing file association, offer to add current selected file if not already included in a configured file type"}, {"hash":105904681,"name":"tfrmoptionsfileassocextra.cboffertoaddtofileassociations.caption","sourcebytes":[79,102,102,101,114,32,116,111,32,97,100,100,32,115,101,108,101,99,116,105,111,110,32,116,111,32,102,105,108,101,32,97,115,115,111,99,105,97,116,105,111,110,32,119,104,101,110,32,110,111,116,32,105,110,99,108,117,100,101,100,32,97,108,114,101,97,100,121],"value":"Offer to add selection to file association when not included already"}, {"hash":105086106,"name":"tfrmoptionsfileassocextra.gbextendedcontextmenuoptions.caption","sourcebytes":[69,120,116,101,110,100,101,100,32,111,112,116,105,111,110,115,32,105,116,101,109,115,58],"value":"Extended options items:"}, {"hash":57448825,"name":"tfrmoptionsfileassocextra.cbdefaultcontextactions.caption","sourcebytes":[68,101,102,97,117,108,116,32,99,111,110,116,101,120,116,32,97,99,116,105,111,110,115,32,40,86,105,101,119,47,69,100,105,116,41],"value":"Default context actions (View/Edit)"}, {"hash":261258620,"name":"tfrmoptionsfileassocextra.cbexecuteviashell.caption","sourcebytes":[69,120,101,99,117,116,101,32,118,105,97,32,115,104,101,108,108],"value":"Execute via shell"}, {"hash":184702149,"name":"tfrmoptionsfileassocextra.cbopensystemwithterminalclose.caption","sourcebytes":[69,120,101,99,117,116,101,32,118,105,97,32,116,101,114,109,105,110,97,108,32,97,110,100,32,99,108,111,115,101],"value":"Execute via terminal and close"}, {"hash":183399550,"name":"tfrmoptionsfileassocextra.cbopensystemwithterminalstayopen.caption","sourcebytes":[69,120,101,99,117,116,101,32,118,105,97,32,116,101,114,109,105,110,97,108,32,97,110,100,32,115,116,97,121,32,111,112,101,110],"value":"Execute via terminal and stay open"}, {"hash":35282766,"name":"tfrmoptionsfileassocextra.cbincludeconfigfileassoc.caption","sourcebytes":[70,105,108,101,32,97,115,115,111,99,105,97,116,105,111,110,32,99,111,110,102,105,103,117,114,97,116,105,111,110],"value":"File association configuration"}, {"hash":50693893,"name":"tfrmoptionsfileassocextra.cbextendedcontextmenu.caption","sourcebytes":[69,120,116,101,110,100,101,100,32,99,111,110,116,101,120,116,32,109,101,110,117],"value":"Extended context menu"}, {"hash":5671667,"name":"tfrmoptionsfileassocextra.gbtoolbaroptionsextra.caption","sourcebytes":[80,97,116,104,115],"value":"Paths"}, {"hash":75021338,"name":"tfrmoptionsfileassocextra.lbfileassocfilenamestyle.caption","sourcebytes":[87,97,121,32,116,111,32,115,101,116,32,112,97,116,104,115,32,119,104,101,110,32,97,100,100,105,110,103,32,101,108,101,109,101,110,116,115,32,102,111,114,32,105,99,111,110,115,44,32,99,111,109,109,97,110,100,115,32,97,110,100,32,115,116,97,114,116,105,110,103,32,112,97,116,104,115,58],"value":"Way to set paths when adding elements for icons, commands and starting paths:"}, {"hash":256553386,"name":"tfrmoptionsfileassocextra.lbpathtoberelativeto.caption","sourcebytes":[80,97,116,104,32,116,111,32,98,101,32,114,101,108,97,116,105,118,101,32,116,111,58],"value":"Path to be relative to:"}, {"hash":49744051,"name":"tfrmoptionsfileassocextra.btnpathtoberelativetoall.caption","sourcebytes":[65,112,112,108,121,32,99,117,114,114,101,110,116,32,115,101,116,116,105,110,103,115,32,116,111,32,97,108,108,32,99,117,114,114,101,110,116,32,99,111,110,102,105,103,117,114,101,100,32,102,105,108,101,110,97,109,101,115,32,97,110,100,32,112,97,116,104,115],"value":"Apply current settings to all current configured filenames and paths"}, {"hash":5219923,"name":"tfrmoptionsfileassocextra.ckbfileassocicons.caption","sourcebytes":[73,99,111,110,115],"value":"Icons"}, {"hash":209637018,"name":"tfrmoptionsfileassocextra.lblapplysettingsfor.caption","sourcebytes":[68,111,32,116,104,105,115,32,102,111,114,32,102,105,108,101,115,32,97,110,100,32,112,97,116,104,32,102,111,114,58],"value":"Do this for files and path for:"}, {"hash":105086995,"name":"tfrmoptionsfileassocextra.ckbfileassoccommand.caption","sourcebytes":[67,111,109,109,97,110,100,115],"value":"Commands"}, {"hash":67051795,"name":"tfrmoptionsfileassocextra.ckbfileassocstartpath.caption","sourcebytes":[83,116,97,114,116,105,110,103,32,112,97,116,104,115],"value":"Starting paths"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileassocextra.pas����������������������������������������������0000644�0001750�0000144�00000015567�14743153644�022173� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Extra File Associations Configuration Copyright (C) 2016-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFileAssocExtra; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fOptionsFrame, StdCtrls, ExtCtrls, Buttons, EditBtn, Menus; type { TfrmOptionsFileAssocExtra } TfrmOptionsFileAssocExtra = class(TOptionsEditor) btnPathToBeRelativeToAll: TButton; btnPathToBeRelativeToHelper: TSpeedButton; cbOfferToAddToFileAssociations: TCheckBox; cbDefaultContextActions: TCheckBox; cbExecuteViaShell: TCheckBox; cbExtendedContextMenu: TCheckBox; cbOpenSystemWithTerminalClose: TCheckBox; cbOpenSystemWithTerminalStayOpen: TCheckBox; cbIncludeConfigFileAssoc: TCheckBox; cbFileAssocFilenameStyle: TComboBox; ckbFileAssocCommand: TCheckBox; ckbFileAssocIcons: TCheckBox; ckbFileAssocStartPath: TCheckBox; dePathToBeRelativeTo: TDirectoryEdit; gbExtendedContextMenuOptions: TGroupBox; gbToolbarOptionsExtra: TGroupBox; lblApplySettingsFor: TLabel; lbPathToBeRelativeTo: TLabel; lbFileAssocFilenameStyle: TLabel; pmPathToBeRelativeToHelper: TPopupMenu; procedure btnPathToBeRelativeToAllClick(Sender: TObject); procedure btnPathToBeRelativeToHelperClick(Sender: TObject); procedure cbExtendedContextMenuChange(Sender: TObject); procedure cbFileAssocFilenameStyleChange(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetTitle: string; override; class function GetIconIndex: integer; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Controls, //DC DCStrUtils, uGlobs, uLng, uSpecialDir, fOptions, fOptionsFileAssoc; {TfrmOptionsFileAssocExtra} procedure TfrmOptionsFileAssocExtra.Init; begin ParseLineToList(rsPluginFilenameStyleList, cbFileAssocFilenameStyle.Items); end; { TfrmOptionsFileAssocExtra.GetTitle } class function TfrmOptionsFileAssocExtra.GetTitle: string; begin Result := rsOptionsEditorFileAssicExtra; end; { TfrmOptionsFileAssocExtra.GetIconIndex } class function TfrmOptionsFileAssocExtra.GetIconIndex: integer; begin Result := 36; end; { TfrmOptionsFileAssocExtra.cbExtendedContextMenuChange } procedure TfrmOptionsFileAssocExtra.cbExtendedContextMenuChange(Sender: TObject); begin gbExtendedContextMenuOptions.Enabled := TCheckbox(Sender).Checked; end; { TfrmOptionsFileAssocExtra.Load } procedure TfrmOptionsFileAssocExtra.Load; begin cbOfferToAddToFileAssociations.Checked := gOfferToAddToFileAssociations; cbExtendedContextMenu.Checked := gExtendedContextMenu; cbOpenSystemWithTerminalStayOpen.Checked := gExecuteViaTerminalStayOpen; cbOpenSystemWithTerminalClose.Checked := gExecuteViaTerminalClose; cbDefaultContextActions.Checked := gDefaultContextActions; cbExecuteViaShell.Checked := gOpenExecuteViaShell; cbIncludeConfigFileAssoc.Checked := gIncludeFileAssociation; cbExtendedContextMenuChange(cbExtendedContextMenu); cbFileAssocFilenameStyle.ItemIndex := integer(gFileAssocFilenameStyle); cbFileAssocFilenameStyleChange(cbFileAssocFilenameStyle); dePathToBeRelativeTo.Text := gFileAssocPathToBeRelativeTo; ckbFileAssocIcons.Checked := fameIcon in gFileAssocPathModifierElements; ckbFileAssocCommand.Checked := fameCommand in gFileAssocPathModifierElements; ckbFileAssocStartPath.Checked := fameStartingPath in gFileAssocPathModifierElements; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathToBeRelativeToHelper, mp_PATHHELPER, nil); end; { TfrmOptionsFileAssocExtra.Save } function TfrmOptionsFileAssocExtra.Save: TOptionsEditorSaveFlags; begin gOfferToAddToFileAssociations := cbOfferToAddToFileAssociations.Checked; gExtendedContextMenu := cbExtendedContextMenu.Checked; gExecuteViaTerminalStayOpen := cbOpenSystemWithTerminalStayOpen.Checked; gExecuteViaTerminalClose := cbOpenSystemWithTerminalClose.Checked; gDefaultContextActions := cbDefaultContextActions.Checked; gOpenExecuteViaShell := cbExecuteViaShell.Checked; gIncludeFileAssociation := cbIncludeConfigFileAssoc.Checked; gFileAssocFilenameStyle := TConfigFilenameStyle(cbFileAssocFilenameStyle.ItemIndex); gFileAssocPathToBeRelativeTo := dePathToBeRelativeTo.Text; gFileAssocPathModifierElements := []; if ckbFileAssocIcons.Checked then gFileAssocPathModifierElements := gFileAssocPathModifierElements + [fameIcon]; if ckbFileAssocCommand.Checked then gFileAssocPathModifierElements := gFileAssocPathModifierElements + [fameCommand]; if ckbFileAssocStartPath.Checked then gFileAssocPathModifierElements := gFileAssocPathModifierElements + [fameStartingPath]; Result := []; end; { TfrmOptionsFileAssocExtra.btnPathToBeRelativeToHelperClick } procedure TfrmOptionsFileAssocExtra.btnPathToBeRelativeToHelperClick(Sender: TObject); begin dePathToBeRelativeTo.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(dePathToBeRelativeTo, pfPATH); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsFileAssocExtra.cbFileAssocFilenameStyleChange } procedure TfrmOptionsFileAssocExtra.cbFileAssocFilenameStyleChange(Sender: TObject); begin lbPathToBeRelativeTo.Visible := (TConfigFilenameStyle(cbFileAssocFilenameStyle.ItemIndex) = TConfigFilenameStyle.pfsRelativeToFollowingPath); dePathToBeRelativeTo.Visible := lbPathToBeRelativeTo.Visible; btnPathToBeRelativeToHelper.Visible := lbPathToBeRelativeTo.Visible; end; { TfrmOptionsFileAssocExtra.btnPathToBeRelativeToAllClick } procedure TfrmOptionsFileAssocExtra.btnPathToBeRelativeToAllClick(Sender: TObject); var Options: IOptionsDialog; Editor: TOptionsEditor; begin Self.SaveSettings; //Call "SaveSettings" instead of just "Save" to get option signature set right away do we don't bother user for that page when close. Options := ShowOptions(TfrmOptionsFileAssoc); Editor := Options.GetEditor(TfrmOptionsFileAssoc); TfrmOptionsFileAssoc(Editor).ScanFileAssocForFilenameAndPath; ShowOptions(TfrmOptionsFileAssoc); end; end. �����������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileoperations.lfm����������������������������������������������0000644�0001750�0000144�00000023302�14743153644�022157� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFileOperations: TfrmOptionsFileOperations Height = 649 Width = 734 HelpKeyword = '/configuration.html#ConfigOperations' ChildSizing.LeftRightSpacing = 6 ClientHeight = 649 ClientWidth = 734 DesignLeft = 608 DesignTop = 181 object gbUserInterface: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = gbExecutingOperations AnchorSideRight.Side = asrBottom Left = 6 Height = 357 Top = 0 Width = 722 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'User interface' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 332 ClientWidth = 718 TabOrder = 0 object lblProgressKind: TLabel AnchorSideLeft.Control = gbUserInterface AnchorSideTop.Control = cbProgressKind AnchorSideTop.Side = asrCenter Left = 10 Height = 20 Top = 14 Width = 240 BorderSpacing.Bottom = 10 Caption = 'Show operations progress &initially in' FocusControl = cbProgressKind ParentColor = False end object cbProgressKind: TComboBoxAutoWidth AnchorSideLeft.Control = lblProgressKind AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbUserInterface AnchorSideRight.Side = asrBottom Left = 254 Height = 28 Top = 10 Width = 100 ItemHeight = 20 Style = csDropDownList TabOrder = 0 end object cbDropReadOnlyFlag: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbProgressKind AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 42 Width = 150 Caption = 'D&rop readonly flag' TabOrder = 1 end object cbRenameSelOnlyName: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbDropReadOnlyFlag AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 70 Width = 357 Caption = 'Select &file name without extension when renaming' TabOrder = 2 end object cbShowCopyTabSelectPanel: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbRenameSelOnlyName AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 98 Width = 311 Caption = 'Sho&w tab select panel in copy/move dialog' TabOrder = 3 end object cbDeleteToTrash: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbShowCopyTabSelectPanel AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 126 Width = 364 Caption = 'Dele&te to recycle bin (Shift key reverses this setting)' OnChange = cbDeleteToTrashChange TabOrder = 4 end object cbCopyConfirmation: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = bvlConfirmations AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 186 Width = 127 Caption = 'Cop&y operation' TabOrder = 5 end object cbMoveConfirmation: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbCopyConfirmation AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 214 Width = 130 Caption = '&Move operation' TabOrder = 6 end object cbDeleteConfirmation: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbMoveConfirmation AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 242 Width = 137 Caption = '&Delete operation' TabOrder = 7 end object cbDeleteToTrashConfirmation: TCheckBox AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbDeleteConfirmation AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 270 Width = 191 Caption = 'D&elete to trash operation' TabOrder = 8 end object bvlConfirmations: TDividerBevel AnchorSideLeft.Control = lblProgressKind AnchorSideTop.Control = cbDeleteToTrash AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbUserInterface AnchorSideRight.Side = asrBottom Left = 10 Height = 20 Top = 162 Width = 698 Caption = 'Show confirmation window for:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 12 ParentFont = False end object cbVerifyChecksumConfirmation: TCheckBox AnchorSideLeft.Control = cbDeleteToTrashConfirmation AnchorSideTop.Control = cbDeleteToTrashConfirmation AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 298 Width = 199 Caption = 'Verify checksum operation' TabOrder = 9 end object cbTestArchiveConfirmation: TCheckBox AnchorSideLeft.Control = cbVerifyChecksumConfirmation AnchorSideTop.Control = cbVerifyChecksumConfirmation AnchorSideTop.Side = asrBottom Left = 10 Height = 23 Top = 323 Width = 161 Caption = 'Test archive operation' TabOrder = 10 end end object gbExecutingOperations: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbUserInterface AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 225 Top = 363 Width = 722 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Executing operations' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 200 ClientWidth = 718 TabOrder = 1 object lblBufferSize: TLabel AnchorSideLeft.Control = gbExecutingOperations AnchorSideTop.Control = edtBufferSize AnchorSideTop.Side = asrCenter Left = 10 Height = 20 Top = 14 Width = 243 BorderSpacing.Bottom = 10 Caption = '&Buffer size for file operations (in KB):' FocusControl = edtBufferSize ParentColor = False end object edtBufferSize: TEdit AnchorSideLeft.Control = lblBufferSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbExecutingOperations AnchorSideBottom.Side = asrCenter Left = 257 Height = 28 Top = 10 Width = 80 TabOrder = 0 end object lblWipePassNumber: TLabel AnchorSideLeft.Control = lblBufferSize AnchorSideTop.Control = seWipePassNumber AnchorSideTop.Side = asrCenter AnchorSideBottom.Side = asrBottom Left = 10 Height = 20 Top = 78 Width = 158 BorderSpacing.Bottom = 10 Caption = '&Number of wipe passes:' FocusControl = seWipePassNumber ParentColor = False end object seWipePassNumber: TSpinEdit AnchorSideLeft.Control = lblWipePassNumber AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtHashBufferSize AnchorSideTop.Side = asrBottom Left = 172 Height = 28 Top = 74 Width = 50 TabOrder = 2 end object cbProcessComments: TCheckBox AnchorSideLeft.Control = lblBufferSize AnchorSideTop.Control = seWipePassNumber AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 106 Width = 261 Caption = '&Process comments with files/folders' TabOrder = 3 end object cbSkipFileOpError: TCheckBox AnchorSideLeft.Control = lblBufferSize AnchorSideTop.Control = cbProcessComments AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 134 Width = 398 Caption = 'S&kip file operations errors and write them to log window' TabOrder = 4 end object lblTypeOfDuplicatedRename: TLabel AnchorSideLeft.Control = cbSkipFileOpError AnchorSideTop.Control = cmbTypeOfDuplicatedRename AnchorSideTop.Side = asrCenter Left = 10 Height = 20 Top = 166 Width = 241 Caption = 'Duplicated name auto-rename style:' ParentColor = False end object cmbTypeOfDuplicatedRename: TComboBoxAutoWidth AnchorSideLeft.Control = lblTypeOfDuplicatedRename AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbSkipFileOpError AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 255 Height = 28 Top = 162 Width = 100 BorderSpacing.Top = 4 ItemHeight = 20 Items.Strings = ( 'DC legacy - Copy (x) filename.ext' 'Windows - filename (x).ext' 'Other - filename(x).ext' ) Style = csDropDownList TabOrder = 5 end object edtHashBufferSize: TEdit AnchorSideLeft.Control = lblHashBufferSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtBufferSize AnchorSideTop.Side = asrBottom AnchorSideBottom.Side = asrCenter Left = 267 Height = 28 Top = 42 Width = 80 TabOrder = 1 end object lblHashBufferSize: TLabel AnchorSideLeft.Control = gbExecutingOperations AnchorSideTop.Control = edtHashBufferSize AnchorSideTop.Side = asrCenter Left = 10 Height = 20 Top = 46 Width = 253 BorderSpacing.Bottom = 10 Caption = 'Buffer size for &hash calculation (in KB):' FocusControl = edtHashBufferSize ParentColor = False end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileoperations.lrj����������������������������������������������0000644�0001750�0000144�00000012036�14743153644�022172� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":51162117,"name":"tfrmoptionsfileoperations.gbuserinterface.caption","sourcebytes":[85,115,101,114,32,105,110,116,101,114,102,97,99,101],"value":"User interface"}, {"hash":84721614,"name":"tfrmoptionsfileoperations.lblprogresskind.caption","sourcebytes":[83,104,111,119,32,111,112,101,114,97,116,105,111,110,115,32,112,114,111,103,114,101,115,115,32,38,105,110,105,116,105,97,108,108,121,32,105,110],"value":"Show operations progress &initially in"}, {"hash":232270583,"name":"tfrmoptionsfileoperations.cbdropreadonlyflag.caption","sourcebytes":[68,38,114,111,112,32,114,101,97,100,111,110,108,121,32,102,108,97,103],"value":"D&rop readonly flag"}, {"hash":36207847,"name":"tfrmoptionsfileoperations.cbrenameselonlyname.caption","sourcebytes":[83,101,108,101,99,116,32,38,102,105,108,101,32,110,97,109,101,32,119,105,116,104,111,117,116,32,101,120,116,101,110,115,105,111,110,32,119,104,101,110,32,114,101,110,97,109,105,110,103],"value":"Select &file name without extension when renaming"}, {"hash":110955351,"name":"tfrmoptionsfileoperations.cbshowcopytabselectpanel.caption","sourcebytes":[83,104,111,38,119,32,116,97,98,32,115,101,108,101,99,116,32,112,97,110,101,108,32,105,110,32,99,111,112,121,47,109,111,118,101,32,100,105,97,108,111,103],"value":"Sho&w tab select panel in copy/move dialog"}, {"hash":17379641,"name":"tfrmoptionsfileoperations.cbdeletetotrash.caption","sourcebytes":[68,101,108,101,38,116,101,32,116,111,32,114,101,99,121,99,108,101,32,98,105,110,32,40,83,104,105,102,116,32,107,101,121,32,114,101,118,101,114,115,101,115,32,116,104,105,115,32,115,101,116,116,105,110,103,41],"value":"Dele&te to recycle bin (Shift key reverses this setting)"}, {"hash":240358494,"name":"tfrmoptionsfileoperations.cbcopyconfirmation.caption","sourcebytes":[67,111,112,38,121,32,111,112,101,114,97,116,105,111,110],"value":"Cop&y operation"}, {"hash":173011838,"name":"tfrmoptionsfileoperations.cbmoveconfirmation.caption","sourcebytes":[38,77,111,118,101,32,111,112,101,114,97,116,105,111,110],"value":"&Move operation"}, {"hash":357918,"name":"tfrmoptionsfileoperations.cbdeleteconfirmation.caption","sourcebytes":[38,68,101,108,101,116,101,32,111,112,101,114,97,116,105,111,110],"value":"&Delete operation"}, {"hash":258035118,"name":"tfrmoptionsfileoperations.cbdeletetotrashconfirmation.caption","sourcebytes":[68,38,101,108,101,116,101,32,116,111,32,116,114,97,115,104,32,111,112,101,114,97,116,105,111,110],"value":"D&elete to trash operation"}, {"hash":151930842,"name":"tfrmoptionsfileoperations.bvlconfirmations.caption","sourcebytes":[83,104,111,119,32,99,111,110,102,105,114,109,97,116,105,111,110,32,119,105,110,100,111,119,32,102,111,114,58],"value":"Show confirmation window for:"}, {"hash":207724030,"name":"tfrmoptionsfileoperations.cbverifychecksumconfirmation.caption","sourcebytes":[86,101,114,105,102,121,32,99,104,101,99,107,115,117,109,32,111,112,101,114,97,116,105,111,110],"value":"Verify checksum operation"}, {"hash":170065262,"name":"tfrmoptionsfileoperations.cbtestarchiveconfirmation.caption","sourcebytes":[84,101,115,116,32,97,114,99,104,105,118,101,32,111,112,101,114,97,116,105,111,110],"value":"Test archive operation"}, {"hash":44527315,"name":"tfrmoptionsfileoperations.gbexecutingoperations.caption","sourcebytes":[69,120,101,99,117,116,105,110,103,32,111,112,101,114,97,116,105,111,110,115],"value":"Executing operations"}, {"hash":209010058,"name":"tfrmoptionsfileoperations.lblbuffersize.caption","sourcebytes":[38,66,117,102,102,101,114,32,115,105,122,101,32,102,111,114,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,40,105,110,32,75,66,41,58],"value":"&Buffer size for file operations (in KB):"}, {"hash":163951274,"name":"tfrmoptionsfileoperations.lblwipepassnumber.caption","sourcebytes":[38,78,117,109,98,101,114,32,111,102,32,119,105,112,101,32,112,97,115,115,101,115,58],"value":"&Number of wipe passes:"}, {"hash":208299555,"name":"tfrmoptionsfileoperations.cbprocesscomments.caption","sourcebytes":[38,80,114,111,99,101,115,115,32,99,111,109,109,101,110,116,115,32,119,105,116,104,32,102,105,108,101,115,47,102,111,108,100,101,114,115],"value":"&Process comments with files/folders"}, {"hash":138955607,"name":"tfrmoptionsfileoperations.cbskipfileoperror.caption","sourcebytes":[83,38,107,105,112,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,101,114,114,111,114,115,32,97,110,100,32,119,114,105,116,101,32,116,104,101,109,32,116,111,32,108,111,103,32,119,105,110,100,111,119],"value":"S&kip file operations errors and write them to log window"}, {"hash":218727434,"name":"tfrmoptionsfileoperations.lbltypeofduplicatedrename.caption","sourcebytes":[68,117,112,108,105,99,97,116,101,100,32,110,97,109,101,32,97,117,116,111,45,114,101,110,97,109,101,32,115,116,121,108,101,58],"value":"Duplicated name auto-rename style:"}, {"hash":108031066,"name":"tfrmoptionsfileoperations.lblhashbuffersize.caption","sourcebytes":[66,117,102,102,101,114,32,115,105,122,101,32,102,111,114,32,38,104,97,115,104,32,99,97,108,99,117,108,97,116,105,111,110,32,40,105,110,32,75,66,41,58],"value":"Buffer size for &hash calculation (in KB):"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfileoperations.pas����������������������������������������������0000644�0001750�0000144�00000014541�14743153644�022171� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File operations options page Copyright (C) 2006-2021 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFileOperations; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, Spin, ExtCtrls, KASComboBox, DividerBevel, fOptionsFrame; type { TfrmOptionsFileOperations } TfrmOptionsFileOperations = class(TOptionsEditor) bvlConfirmations: TDividerBevel; cbDeleteToTrash: TCheckBox; cbDropReadOnlyFlag: TCheckBox; cbProcessComments: TCheckBox; cbRenameSelOnlyName: TCheckBox; cbShowCopyTabSelectPanel: TCheckBox; cbSkipFileOpError: TCheckBox; cbProgressKind: TComboBoxAutoWidth; cbCopyConfirmation: TCheckBox; cbMoveConfirmation: TCheckBox; cbDeleteConfirmation: TCheckBox; cbDeleteToTrashConfirmation: TCheckBox; cbVerifyChecksumConfirmation: TCheckBox; cbTestArchiveConfirmation: TCheckBox; cmbTypeOfDuplicatedRename: TComboBoxAutoWidth; edtBufferSize: TEdit; edtHashBufferSize: TEdit; gbUserInterface: TGroupBox; gbExecutingOperations: TGroupBox; lblHashBufferSize: TLabel; lblTypeOfDuplicatedRename: TLabel; lblBufferSize: TLabel; lblProgressKind: TLabel; lblWipePassNumber: TLabel; seWipePassNumber: TSpinEdit; procedure cbDeleteToTrashChange(Sender: TObject); private FLoading: Boolean; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public constructor Create(TheOwner: TComponent); override; class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng, fOptionsHotkeys; { TfrmOptionsFileOperations } class function TfrmOptionsFileOperations.GetIconIndex: Integer; begin Result := 8; end; class function TfrmOptionsFileOperations.GetTitle: String; begin Result := rsOptionsEditorFileOperations; end; procedure TfrmOptionsFileOperations.Init; begin ParseLineToList(rsOptFileOperationsProgressKind, cbProgressKind.Items); ParseLineToList(rsOptTypeOfDuplicatedRename, cmbTypeOfDuplicatedRename.Items); end; procedure TfrmOptionsFileOperations.cbDeleteToTrashChange(Sender: TObject); var HotkeysEditor: TOptionsEditor; begin if not FLoading then begin HotkeysEditor := OptionsDialog.GetEditor(TfrmOptionsHotkeys); if Assigned(HotkeysEditor) then (HotkeysEditor as TfrmOptionsHotkeys).AddDeleteWithShiftHotkey(cbDeleteToTrash.Checked); end; end; procedure TfrmOptionsFileOperations.Load; begin FLoading := True; edtBufferSize.Text := IntToStr(gCopyBlockSize div 1024); edtHashBufferSize.Text := IntToStr(gHashBlockSize div 1024); cbSkipFileOpError.Checked := gSkipFileOpError; cbDropReadOnlyFlag.Checked := gDropReadOnlyFlag; seWipePassNumber.Value := gWipePassNumber; cbProcessComments.Checked := gProcessComments; cbShowCopyTabSelectPanel.Checked := gShowCopyTabSelectPanel; cbDeleteToTrash.Checked := gUseTrash; cbRenameSelOnlyName.Checked := gRenameSelOnlyName; case gFileOperationsProgressKind of fopkSeparateWindow: cbProgressKind.ItemIndex := 0; fopkSeparateWindowMinimized: cbProgressKind.ItemIndex := 1; fopkOperationsPanel: cbProgressKind.ItemIndex := 2; end; cbCopyConfirmation.Checked := focCopy in gFileOperationsConfirmations; cbMoveConfirmation.Checked := focMove in gFileOperationsConfirmations; cbDeleteConfirmation.Checked := focDelete in gFileOperationsConfirmations; cbTestArchiveConfirmation.Checked := focTestArchive in gFileOperationsConfirmations; cbDeleteToTrashConfirmation.Checked := focDeleteToTrash in gFileOperationsConfirmations; cbVerifyChecksumConfirmation.Checked := focVerifyChecksum in gFileOperationsConfirmations; cmbTypeOfDuplicatedRename.ItemIndex := Integer(gTypeOfDuplicatedRename); FLoading := False; end; function TfrmOptionsFileOperations.Save: TOptionsEditorSaveFlags; begin Result := []; gCopyBlockSize := StrToIntDef(edtBufferSize.Text, gCopyBlockSize div 1024) * 1024; gHashBlockSize := StrToIntDef(edtHashBufferSize.Text, gHashBlockSize div 1024) * 1024; gSkipFileOpError := cbSkipFileOpError.Checked; gDropReadOnlyFlag := cbDropReadOnlyFlag.Checked; gWipePassNumber := seWipePassNumber.Value; gProcessComments := cbProcessComments.Checked; gShowCopyTabSelectPanel := cbShowCopyTabSelectPanel.Checked; gUseTrash := cbDeleteToTrash.Checked; gRenameSelOnlyName := cbRenameSelOnlyName.Checked; case cbProgressKind.ItemIndex of 0: gFileOperationsProgressKind := fopkSeparateWindow; 1: gFileOperationsProgressKind := fopkSeparateWindowMinimized; 2: gFileOperationsProgressKind := fopkOperationsPanel; end; gFileOperationsConfirmations := []; if cbCopyConfirmation.Checked then Include(gFileOperationsConfirmations, focCopy); if cbMoveConfirmation.Checked then Include(gFileOperationsConfirmations, focMove); if cbDeleteConfirmation.Checked then Include(gFileOperationsConfirmations, focDelete); if cbTestArchiveConfirmation.Checked then Include(gFileOperationsConfirmations, focTestArchive); if cbDeleteToTrashConfirmation.Checked then Include(gFileOperationsConfirmations, focDeleteToTrash); if cbVerifyChecksumConfirmation.Checked then Include(gFileOperationsConfirmations, focVerifyChecksum); gTypeOfDuplicatedRename := tDuplicatedRename(cmbTypeOfDuplicatedRename.ItemIndex); end; constructor TfrmOptionsFileOperations.Create(TheOwner: TComponent); begin inherited Create(TheOwner); FLoading := False; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilepanelscolors.lfm��������������������������������������������0000644�0001750�0000144�00000041736�14743153644�022513� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFilePanelsColors: TfrmOptionsFilePanelsColors Height = 521 Width = 880 HelpKeyword = '/configuration.html#ConfigColorPanels' ClientHeight = 521 ClientWidth = 880 DesignLeft = 325 DesignTop = 153 object lblTextColor: TLabel[0] AnchorSideTop.Control = cbTextColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbTextColor Left = 100 Height = 15 Top = 13 Width = 56 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'T&ext Color:' FocusControl = cbTextColor ParentColor = False end object cbTextColor: TKASColorBoxButton[1] Left = 160 Height = 24 Top = 8 Width = 126 TabOrder = 0 Constraints.MinWidth = 100 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblBackgroundColor: TLabel[2] AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 89 Height = 15 Top = 41 Width = 67 Anchors = [akTop, akRight] Caption = 'Bac&kground:' FocusControl = cbBackColor ParentColor = False end object cbBackColor: TKASColorBoxButton[3] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbTextColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 36 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 1 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblBackgroundColor2: TLabel[4] AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 80 Height = 15 Top = 69 Width = 76 Anchors = [akTop, akRight] Caption = 'Backg&round 2:' FocusControl = cbBackColor2 ParentColor = False end object cbBackColor2: TKASColorBoxButton[5] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbBackColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 64 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 2 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblMarkColor: TLabel[6] AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 94 Height = 15 Top = 97 Width = 62 Anchors = [akTop, akRight] Caption = '&Mark Color:' FocusControl = cbMarkColor ParentColor = False end object cbMarkColor: TKASColorBoxButton[7] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbBackColor2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 92 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 3 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblCursorColor: TLabel[8] AnchorSideTop.Control = cbCursorColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 86 Height = 15 Top = 125 Width = 70 Anchors = [akTop, akRight] Caption = 'C&ursor Color:' FocusControl = cbCursorColor ParentColor = False end object cbCursorColor: TKASColorBoxButton[9] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 120 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 4 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblCursorText: TLabel[10] AnchorSideTop.Control = cbCursorText AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 94 Height = 15 Top = 153 Width = 62 Anchors = [akTop, akRight] Caption = 'Cursor Te&xt:' FocusControl = cbCursorText ParentColor = False end object cbCursorText: TKASColorBoxButton[11] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbCursorColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 148 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 5 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblInactiveCursorColor: TLabel[12] AnchorSideTop.Control = cbInactiveCursorColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 42 Height = 15 Top = 181 Width = 114 Anchors = [akTop, akRight] Caption = 'Inactive Cursor Color:' FocusControl = cbInactiveCursorColor ParentColor = False end object cbInactiveCursorColor: TKASColorBoxButton[13] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbCursorText AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 176 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 6 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object lblInactiveMarkColor: TLabel[14] AnchorSideTop.Control = cbInactiveMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblTextColor AnchorSideRight.Side = asrBottom Left = 50 Height = 15 Top = 209 Width = 106 Anchors = [akTop, akRight] Caption = 'Inactive Mark Color:' FocusControl = cbInactiveMarkColor ParentColor = False end object cbInactiveMarkColor: TKASColorBoxButton[15] AnchorSideLeft.Control = cbTextColor AnchorSideTop.Control = cbInactiveCursorColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbTextColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 204 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 7 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object dbOptionsVertical: TDividerBevel[16] AnchorSideLeft.Control = cbTextColor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTextColor AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbCursorBorderColor AnchorSideBottom.Side = asrBottom Left = 298 Height = 240 Top = 16 Width = 15 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 12 BorderSpacing.Top = 8 BorderSpacing.Right = 12 Font.Style = [fsBold] Orientation = trVertical ParentFont = False end object cbbUseInvertedSelection: TCheckBox[17] AnchorSideLeft.Control = dbOptionsVertical AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTextColor Left = 325 Height = 19 Top = 14 Width = 136 BorderSpacing.Top = 6 Caption = 'U&se Inverted Selection' OnChange = cbColorBoxChange TabOrder = 10 end object cbbUseInactiveSelColor: TCheckBox[18] AnchorSideLeft.Control = cbbUseInvertedSelection AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTextColor Left = 471 Height = 19 Top = 14 Width = 133 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = 'Use Inactive Sel Color' OnChange = cbbUseInactiveSelColorChange TabOrder = 11 end object cbbUseFrameCursor: TCheckBox[19] AnchorSideLeft.Control = cbbUseInvertedSelection AnchorSideTop.Control = cbbUseInvertedSelection AnchorSideTop.Side = asrBottom Left = 325 Height = 19 Top = 38 Width = 113 BorderSpacing.Top = 5 Caption = 'Use &Frame Cursor' OnChange = cbbUseFrameCursorChange TabOrder = 12 end object lblInactivePanelBrightness: TLabel[20] AnchorSideLeft.Control = cbbUseFrameCursor AnchorSideTop.Control = lblBackgroundColor2 AnchorSideTop.Side = asrCenter AnchorSideBottom.Control = tbInactivePanelBrightness Left = 325 Height = 15 Top = 69 Width = 175 BorderSpacing.Top = 6 Caption = '&Brightness level of inactive panel:' FocusControl = tbInactivePanelBrightness ParentColor = False end object tbInactivePanelBrightness: TTrackBar[21] AnchorSideLeft.Control = lblInactivePanelBrightness AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblInactivePanelBrightness AnchorSideRight.Control = cbPathActiveText AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = dbCurrentPath Left = 506 Height = 22 Top = 69 Width = 91 Max = 100 OnChange = tbInactivePanelBrightnessChange PageSize = 10 Position = 0 ScalePos = trRight TickStyle = tsNone Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Bottom = 6 TabOrder = 14 end object dbCurrentPath: TDividerBevel[22] AnchorSideLeft.Control = lblInactivePanelBrightness AnchorSideTop.Control = cbMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathInactiveText AnchorSideRight.Side = asrBottom Left = 325 Height = 15 Top = 97 Width = 272 Caption = 'Current Path' Anchors = [akTop, akLeft, akRight] Style = gsHorLines end object lblPathActiveBack: TLabel[23] AnchorSideLeft.Control = cbbUseInvertedSelection AnchorSideTop.Control = cbPathActiveBack AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathActiveBack Left = 400 Height = 15 Top = 153 Width = 67 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Background:' FocusControl = cbPathActiveBack ParentColor = False end object cbPathActiveBack: TKASColorBoxButton[24] AnchorSideLeft.Control = cbbUseInactiveSelColor AnchorSideTop.Control = cbCursorText AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathInactiveBack AnchorSideRight.Side = asrBottom Left = 471 Height = 24 Top = 148 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 16 OnChange = cbPathActiveBackChange ColorDialog = optColorDialog end object lblPathInactiveBack: TLabel[25] AnchorSideLeft.Control = cbbUseInvertedSelection AnchorSideTop.Control = cbPathInactiveBack AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblPathActiveBack AnchorSideRight.Side = asrBottom Left = 356 Height = 15 Top = 209 Width = 111 Anchors = [akTop, akRight] Caption = 'Inactive Background:' FocusControl = cbPathInactiveBack ParentColor = False end object cbPathInactiveBack: TKASColorBoxButton[26] AnchorSideLeft.Control = cbbUseInactiveSelColor AnchorSideTop.Control = cbInactiveMarkColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathActiveBack AnchorSideRight.Side = asrBottom Left = 471 Height = 24 Top = 204 Width = 126 TabOrder = 18 BorderSpacing.Top = 4 OnChange = cbPathInactiveBackChange ColorDialog = optColorDialog end object cbUseCursorBorder: TCheckBox[27] AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbCursorBorderColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbCursorBorderColor Left = 67 Height = 19 Top = 235 Width = 93 Anchors = [akTop, akRight] Caption = 'Cursor border' OnChange = cbUseCursorBorderChange TabOrder = 8 end object cbCursorBorderColor: TKASColorBoxButton[28] AnchorSideLeft.Control = cbInactiveMarkColor AnchorSideTop.Control = cbInactiveMarkColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbInactiveMarkColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 232 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 9 BorderSpacing.Top = 4 OnChange = cbColorBoxChange ColorDialog = optColorDialog end object btnResetToDCDefault: TButton[29] AnchorSideTop.Control = cbCursorBorderColor AnchorSideRight.Control = cbPathInactiveBack AnchorSideRight.Side = asrBottom Left = 470 Height = 25 Top = 232 Width = 127 Anchors = [akTop, akRight] AutoSize = True Caption = 'Reset to DC default' OnClick = btnResetToDCDefaultClick TabOrder = 19 end object cbAllowOverColor: TCheckBox[30] AnchorSideLeft.Control = cbbUseInactiveSelColor AnchorSideTop.Control = cbbUseFrameCursor AnchorSideTop.Side = asrCenter Left = 471 Height = 19 Top = 38 Width = 105 Caption = 'Allow Overcolor' OnChange = cbbUseInactiveSelColorChange TabOrder = 13 end object lblPathInactiveText: TLabel[31] AnchorSideLeft.Control = cbbUseInvertedSelection AnchorSideTop.Control = cbPathInactiveText AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathInactiveText Left = 367 Height = 15 Top = 181 Width = 100 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Inactive Text Color:' FocusControl = cbPathInactiveText ParentColor = False end object cbPathInactiveText: TKASColorBoxButton[32] AnchorSideLeft.Control = cbbUseInactiveSelColor AnchorSideTop.Control = cbInactiveCursorColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathInactiveBack AnchorSideRight.Side = asrBottom Left = 471 Height = 24 Top = 176 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 17 OnChange = cbPathInactiveTextChange ColorDialog = optColorDialog end object cbPathActiveText: TKASColorBoxButton[33] AnchorSideLeft.Control = cbbUseInactiveSelColor AnchorSideTop.Control = cbCursorColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathInactiveBack AnchorSideRight.Side = asrBottom Left = 471 Height = 24 Top = 120 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 15 OnChange = cbPathActiveTextChange ColorDialog = optColorDialog end object lblPathActiveText: TLabel[34] AnchorSideTop.Control = cbPathActiveText AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbPathInactiveText Left = 411 Height = 15 Top = 125 Width = 56 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Text Color:' FocusControl = cbPathInactiveText ParentColor = False end object pnlPreviewCont: TKASToolPanel[35] AnchorSideLeft.Control = Owner AnchorSideTop.Control = cbCursorBorderColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 0 Height = 259 Top = 262 Width = 880 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 6 ChildSizing.LeftRightSpacing = 8 TabOrder = 20 object pnlLeftPreview: TPanel Left = 8 Height = 222 Top = 29 Width = 439 Align = alClient Anchors = [] BorderSpacing.Bottom = 8 BevelOuter = bvNone ParentColor = False TabOrder = 0 TabStop = True OnEnter = pnlLeftPreviewEnter end object pnlRightPreview: TPanel Left = 457 Height = 222 Top = 29 Width = 415 Align = alRight Anchors = [] BorderSpacing.Bottom = 8 BevelOuter = bvNone ParentColor = False TabOrder = 1 TabStop = True OnEnter = pnlRightPreviewEnter end object spPanelSplitter: TSplitter Left = 447 Height = 230 Top = 29 Width = 10 Align = alRight Anchors = [akRight] ResizeAnchor = akRight end object lblPreview: TDividerBevel Left = 8 Height = 15 Top = 8 Width = 864 Caption = 'Below is a preview. You may move cursor, select file and get immediately an actual look and feel of the various settings.' Align = alTop BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 Font.Style = [fsBold] ParentColor = False ParentFont = False Style = gsHorLines end end object optColorDialog: TColorDialog[36] Color = clBlack CustomColors.Strings = ( 'ColorA=000000' 'ColorB=000080' 'ColorC=008000' 'ColorD=008080' 'ColorE=800000' 'ColorF=800080' 'ColorG=808000' 'ColorH=808080' 'ColorI=C0C0C0' 'ColorJ=0000FF' 'ColorK=00FF00' 'ColorL=00FFFF' 'ColorM=FF0000' 'ColorN=FF00FF' 'ColorO=FFFF00' 'ColorP=FFFFFF' 'ColorQ=C0DCC0' 'ColorR=F0CAA6' 'ColorS=F0FBFF' 'ColorT=A4A0A0' ) Left = 728 Top = 376 end end ����������������������������������doublecmd-1.1.22/src/frames/foptionsfilepanelscolors.lrj��������������������������������������������0000644�0001750�0000144�00000010617�14743153644�022516� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":34273594,"name":"tfrmoptionsfilepanelscolors.lbltextcolor.caption","sourcebytes":[84,38,101,120,116,32,67,111,108,111,114,58],"value":"T&ext Color:"}, {"hash":168950122,"name":"tfrmoptionsfilepanelscolors.lblbackgroundcolor.caption","sourcebytes":[66,97,99,38,107,103,114,111,117,110,100,58],"value":"Bac&kground:"}, {"hash":19266122,"name":"tfrmoptionsfilepanelscolors.lblbackgroundcolor2.caption","sourcebytes":[66,97,99,107,103,38,114,111,117,110,100,32,50,58],"value":"Backg&round 2:"}, {"hash":104316554,"name":"tfrmoptionsfilepanelscolors.lblmarkcolor.caption","sourcebytes":[38,77,97,114,107,32,67,111,108,111,114,58],"value":"&Mark Color:"}, {"hash":158176330,"name":"tfrmoptionsfilepanelscolors.lblcursorcolor.caption","sourcebytes":[67,38,117,114,115,111,114,32,67,111,108,111,114,58],"value":"C&ursor Color:"}, {"hash":258898298,"name":"tfrmoptionsfilepanelscolors.lblcursortext.caption","sourcebytes":[67,117,114,115,111,114,32,84,101,38,120,116,58],"value":"Cursor Te&xt:"}, {"hash":83514154,"name":"tfrmoptionsfilepanelscolors.lblinactivecursorcolor.caption","sourcebytes":[73,110,97,99,116,105,118,101,32,67,117,114,115,111,114,32,67,111,108,111,114,58],"value":"Inactive Cursor Color:"}, {"hash":132983626,"name":"tfrmoptionsfilepanelscolors.lblinactivemarkcolor.caption","sourcebytes":[73,110,97,99,116,105,118,101,32,77,97,114,107,32,67,111,108,111,114,58],"value":"Inactive Mark Color:"}, {"hash":213836862,"name":"tfrmoptionsfilepanelscolors.cbbuseinvertedselection.caption","sourcebytes":[85,38,115,101,32,73,110,118,101,114,116,101,100,32,83,101,108,101,99,116,105,111,110],"value":"U&se Inverted Selection"}, {"hash":194038066,"name":"tfrmoptionsfilepanelscolors.cbbuseinactiveselcolor.caption","sourcebytes":[85,115,101,32,73,110,97,99,116,105,118,101,32,83,101,108,32,67,111,108,111,114],"value":"Use Inactive Sel Color"}, {"hash":237530674,"name":"tfrmoptionsfilepanelscolors.cbbuseframecursor.caption","sourcebytes":[85,115,101,32,38,70,114,97,109,101,32,67,117,114,115,111,114],"value":"Use &Frame Cursor"}, {"hash":195339690,"name":"tfrmoptionsfilepanelscolors.lblinactivepanelbrightness.caption","sourcebytes":[38,66,114,105,103,104,116,110,101,115,115,32,108,101,118,101,108,32,111,102,32,105,110,97,99,116,105,118,101,32,112,97,110,101,108,58],"value":"&Brightness level of inactive panel:"}, {"hash":30011496,"name":"tfrmoptionsfilepanelscolors.dbcurrentpath.caption","sourcebytes":[67,117,114,114,101,110,116,32,80,97,116,104],"value":"Current Path"}, {"hash":249486954,"name":"tfrmoptionsfilepanelscolors.lblpathactiveback.caption","sourcebytes":[66,97,99,107,103,114,111,117,110,100,58],"value":"Background:"}, {"hash":230984106,"name":"tfrmoptionsfilepanelscolors.lblpathinactiveback.caption","sourcebytes":[73,110,97,99,116,105,118,101,32,66,97,99,107,103,114,111,117,110,100,58],"value":"Inactive Background:"}, {"hash":217190446,"name":"tfrmoptionsfilepanelscolors.lblpreview.caption","sourcebytes":[66,101,108,111,119,32,105,115,32,97,32,112,114,101,118,105,101,119,46,32,89,111,117,32,109,97,121,32,109,111,118,101,32,99,117,114,115,111,114,44,32,115,101,108,101,99,116,32,102,105,108,101,32,97,110,100,32,103,101,116,32,105,109,109,101,100,105,97,116,101,108,121,32,97,110,32,97,99,116,117,97,108,32,108,111,111,107,32,97,110,100,32,102,101,101,108,32,111,102,32,116,104,101,32,118,97,114,105,111,117,115,32,115,101,116,116,105,110,103,115,46],"value":"Below is a preview. You may move cursor, select file and get immediately an actual look and feel of the various settings."}, {"hash":207563970,"name":"tfrmoptionsfilepanelscolors.cbusecursorborder.caption","sourcebytes":[67,117,114,115,111,114,32,98,111,114,100,101,114],"value":"Cursor border"}, {"hash":157403508,"name":"tfrmoptionsfilepanelscolors.btnresettodcdefault.caption","sourcebytes":[82,101,115,101,116,32,116,111,32,68,67,32,100,101,102,97,117,108,116],"value":"Reset to DC default"}, {"hash":266427794,"name":"tfrmoptionsfilepanelscolors.cballowovercolor.caption","sourcebytes":[65,108,108,111,119,32,79,118,101,114,99,111,108,111,114],"value":"Allow Overcolor"}, {"hash":130444538,"name":"tfrmoptionsfilepanelscolors.lblpathinactivetext.caption","sourcebytes":[73,110,97,99,116,105,118,101,32,84,101,120,116,32,67,111,108,111,114,58],"value":"Inactive Text Color:"}, {"hash":81852730,"name":"tfrmoptionsfilepanelscolors.lblpathactivetext.caption","sourcebytes":[84,101,120,116,32,67,111,108,111,114,58],"value":"Text Color:"} ]} �����������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilepanelscolors.pas��������������������������������������������0000644�0001750�0000144�00000034731�14743153644�022515� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File panels colors options page Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsFilePanelsColors; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Graphics, Classes, SysUtils, ComCtrls, StdCtrls, ColorBox, ExtCtrls, Dialogs, DividerBevel, LMessages, KASComboBox, KASToolPanel, //DC uColumns, fOptionsFrame, uColumnsFileView, Controls; type { TfrmOptionsFilePanelsColors } TfrmOptionsFilePanelsColors = class(TOptionsEditor) btnResetToDCDefault: TButton; cbAllowOverColor: TCheckBox; cbPathActiveText: TKASColorBoxButton; cbPathInactiveText: TKASColorBoxButton; cbUseCursorBorder: TCheckBox; cbCursorBorderColor: TKASColorBoxButton; dbOptionsVertical: TDividerBevel; lblPathInactiveText: TLabel; lblPathActiveText: TLabel; lblPreview: TDividerBevel; lblTextColor: TLabel; cbTextColor: TKASColorBoxButton; lblBackgroundColor: TLabel; cbBackColor: TKASColorBoxButton; lblBackgroundColor2: TLabel; cbBackColor2: TKASColorBoxButton; lblMarkColor: TLabel; cbMarkColor: TKASColorBoxButton; lblCursorColor: TLabel; cbCursorColor: TKASColorBoxButton; lblCursorText: TLabel; cbCursorText: TKASColorBoxButton; lblInactiveCursorColor: TLabel; cbInactiveCursorColor: TKASColorBoxButton; lblInactiveMarkColor: TLabel; cbInactiveMarkColor: TKASColorBoxButton; cbbUseInvertedSelection: TCheckBox; cbbUseInactiveSelColor: TCheckBox; cbbUseFrameCursor: TCheckBox; lblInactivePanelBrightness: TLabel; pnlLeftPreview: TPanel; pnlPreviewCont: TKASToolPanel; pnlRightPreview: TPanel; spPanelSplitter: TSplitter; tbInactivePanelBrightness: TTrackBar; dbCurrentPath: TDividerBevel; lblPathActiveBack: TLabel; cbPathActiveBack: TKASColorBoxButton; lblPathInactiveBack: TLabel; cbPathInactiveBack: TKASColorBoxButton; optColorDialog: TColorDialog; procedure btnResetToDCDefaultClick(Sender: TObject); procedure cbbUseFrameCursorChange(Sender: TObject); procedure cbColorBoxChange(Sender: TObject); procedure cbbUseInactiveSelColorChange(Sender: TObject); procedure cbPathActiveTextChange(Sender: TObject); procedure cbPathInactiveBackChange(Sender: TObject); procedure cbPathInactiveTextChange(Sender: TObject); procedure cbUseCursorBorderChange(Sender: TObject); procedure tbInactivePanelBrightnessChange(Sender: TObject); procedure cbPathActiveBackChange(Sender: TObject); procedure RefreshPreviewPanel; procedure pnlLeftPreviewEnter(Sender: TObject); procedure pnlRightPreviewEnter(Sender: TObject); function JustForConfigDim(AColor: TColor): TColor; function JustForConfigNoDim(AColor: TColor): TColor; private bLoadCompleted: boolean; PreviewLeftPanel: TColumnsFileView; PreviewRightPanel: TColumnsFileView; ColumnClass: TPanelColumnsClass; ColPrm: TColPrm; protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Forms, //DC uSampleForConfigFileSource, uFileFunctions, fMain, uLng, uGlobs, uDCUtils; { TfrmOptionsFilePanelsColors } { TfrmOptionsFilePanelsColors.GetIconIndex } class function TfrmOptionsFilePanelsColors.GetIconIndex: integer; begin Result := 20; end; { TfrmOptionsFilePanelsColors.GetTitle } class function TfrmOptionsFilePanelsColors.GetTitle: string; begin Result := rsOptionsEditorFilePanels; end; { TfrmOptionsFilePanelsColors.Load } procedure TfrmOptionsFilePanelsColors.Load; begin bLoadCompleted := False; //1. Let's create the element we'll need. ColPrm := TColPrm.Create; ColumnClass := TPanelColumnsClass.Create; //2. Let's load the current settings to be shown on screen with gColors.FilePanel^ do begin cbTextColor.Selected := ForeColor; cbBackColor.Selected := BackColor; cbBackColor2.Selected := BackColor2; cbMarkColor.Selected := MarkColor; cbCursorColor.Selected := CursorColor; cbCursorText.Selected := CursorText; cbInactiveCursorColor.Selected := InactiveCursorColor; cbInactiveMarkColor.Selected := InactiveMarkColor; cbCursorBorderColor.Selected := CursorBorderColor; end; cbAllowOverColor.Checked := gAllowOverColor; cbbUseInvertedSelection.Checked := gUseInvertedSelection; cbbUseInactiveSelColor.Checked := gUseInactiveSelColor; cbbUseFrameCursor.Checked := gUseFrameCursor; cbUseCursorBorder.Checked := gUseCursorBorder; tbInactivePanelBrightness.Position := gInactivePanelBrightness; cbbUseFrameCursorChange(cbbUseFrameCursor); cbbUseInactiveSelColorChange(cbbUseInactiveSelColor); //3. Let's create our preview panels PreviewLeftPanel := TColumnsFileView.Create(pnlLeftPreview, TSampleForConfigFileSource.Create, SAMPLE_PATH); PreviewLeftPanel.JustForColorPreviewSetActiveState(True); PreviewLeftPanel.SetGridFunctionDim(@JustForConfigNoDim); PreviewRightPanel := TColumnsFileView.Create(pnlRightPreview, TSampleForConfigFileSource.Create, SAMPLE_PATH); PreviewRightPanel.JustForColorPreviewSetActiveState(False); PreviewRightPanel.SetGridFunctionDim(@JustForConfigDim); //4. Let's define which ColumnClass it's gonna follow PreviewLeftPanel.ActiveColmSlave := ColumnClass; PreviewLeftPanel.isSlave := True; PreviewLeftPanel.Demo := True; PreviewRightPanel.ActiveColmSlave := ColumnClass; PreviewRightPanel.isSlave := True; PreviewRightPanel.Demo := True; with gColors.Path^ do begin cbPathActiveText.Selected := ActiveFontColor; cbPathActiveBack.Selected := ActiveColor; cbPathInactiveText.Selected := InactiveFontColor; cbPathInactiveBack.Selected := InactiveColor; end; //5. Let's refresh the panel so we will show something RefreshPreviewPanel; //6. Good. Loading is completed. bLoadCompleted := True; end; { TfrmOptionsFilePanelsColors.Save } function TfrmOptionsFilePanelsColors.Save: TOptionsEditorSaveFlags; begin with gColors.FilePanel^ do begin ForeColor := cbTextColor.Selected; BackColor := cbBackColor.Selected; BackColor2 := cbBackColor2.Selected; MarkColor := cbMarkColor.Selected; CursorColor := cbCursorColor.Selected; CursorText := cbCursorText.Selected; InactiveCursorColor := cbInactiveCursorColor.Selected; InactiveMarkColor := cbInactiveMarkColor.Selected; CursorBorderColor := cbCursorBorderColor.Selected; end; gUseInvertedSelection := cbbUseInvertedSelection.Checked; gAllowOverColor := cbAllowOverColor.Checked; gUseInactiveSelColor := cbbUseInactiveSelColor.Checked; gUseFrameCursor := cbbUseFrameCursor.Checked; gUseCursorBorder := cbUseCursorBorder.Checked; gInactivePanelBrightness := tbInactivePanelBrightness.Position; with gColors.Path^ do begin ActiveFontColor:= cbPathActiveText.Selected; ActiveColor:= cbPathActiveBack.Selected; InactiveFontColor:= cbPathInactiveText.Selected; InactiveColor:= cbPathInactiveBack.Selected; end; Result := []; end; procedure TfrmOptionsFilePanelsColors.CMThemeChanged(var Message: TLMessage); begin LoadSettings; end; { TfrmOptionsFilePanelsColors.cbColorBoxChange } procedure TfrmOptionsFilePanelsColors.cbColorBoxChange(Sender: TObject); begin if bLoadCompleted then RefreshPreviewPanel; end; procedure TfrmOptionsFilePanelsColors.btnResetToDCDefaultClick(Sender: TObject); begin cbTextColor.Selected := clWindowText; cbBackColor.Selected := clWindow; cbBackColor2.Selected := clWindow; cbMarkColor.Selected := clRed; cbCursorColor.Selected := clHighlight; cbCursorText.Selected := clHighlightText; cbInactiveCursorColor.Selected := clInactiveCaption; cbInactiveMarkColor.Selected := clMaroon; cbAllowOverColor.Checked := True; cbbUseInvertedSelection.Checked := False; cbbUseInactiveSelColor.Checked := False; cbbUseFrameCursor.Checked := False; cbUseCursorBorder.Checked := False; cbCursorBorderColor.Selected := clHighlight; tbInactivePanelBrightness.Position := 100; cbPathActiveText.Selected := clHighlightText; cbPathActiveBack.Selected := clHighlight; cbPathInactiveText.Selected := clBtnText; cbPathInactiveBack.Selected := clBtnFace; cbbUseFrameCursorChange(cbbUseFrameCursor); end; procedure TfrmOptionsFilePanelsColors.cbbUseFrameCursorChange(Sender: TObject); begin cbUseCursorBorder.Enabled := not cbbUseFrameCursor.Checked; lblCursorText.Enabled := not cbbUseFrameCursor.Checked; cbCursorText.Enabled := not cbbUseFrameCursor.Checked; cbUseCursorBorderChange(cbUseCursorBorder); end; { TfrmOptionsFilePanelsColors.cbbUseInactiveSelColorChange } procedure TfrmOptionsFilePanelsColors.cbbUseInactiveSelColorChange(Sender: TObject); begin lblInactiveCursorColor.Enabled := cbbUseInactiveSelColor.Checked and cbbUseInactiveSelColor.Enabled; cbInactiveCursorColor.Enabled := cbbUseInactiveSelColor.Checked and cbbUseInactiveSelColor.Enabled; lblInactiveMarkColor.Enabled := cbbUseInactiveSelColor.Checked and cbbUseInactiveSelColor.Enabled; cbInactiveMarkColor.Enabled := cbbUseInactiveSelColor.Checked and cbbUseInactiveSelColor.Enabled; if bLoadCompleted then begin RefreshPreviewPanel; end; end; procedure TfrmOptionsFilePanelsColors.cbPathActiveTextChange(Sender: TObject); begin PreviewLeftPanel.Header.PathLabel.ActiveFontColor:= cbPathActiveText.Selected; PreviewRightPanel.Header.PathLabel.ActiveFontColor:= cbPathActiveText.Selected; end; { TfrmOptionsFilePanelsColors.cbIndColorChange } procedure TfrmOptionsFilePanelsColors.cbPathActiveBackChange(Sender: TObject); begin PreviewLeftPanel.Header.PathLabel.ActiveColor:= cbPathActiveBack.Selected; PreviewRightPanel.Header.PathLabel.ActiveColor:= cbPathActiveBack.Selected; end; procedure TfrmOptionsFilePanelsColors.cbPathInactiveBackChange(Sender: TObject); begin PreviewLeftPanel.Header.PathLabel.InactiveColor:= cbPathInactiveBack.Selected; PreviewRightPanel.Header.PathLabel.InactiveColor:= cbPathInactiveBack.Selected; end; procedure TfrmOptionsFilePanelsColors.cbPathInactiveTextChange(Sender: TObject); begin PreviewLeftPanel.Header.PathLabel.InactiveFontColor:= cbPathInactiveText.Selected; PreviewRightPanel.Header.PathLabel.InactiveFontColor:= cbPathInactiveText.Selected; end; procedure TfrmOptionsFilePanelsColors.cbUseCursorBorderChange(Sender: TObject); begin cbCursorBorderColor.Enabled := cbUseCursorBorder.Checked and cbUseCursorBorder.Enabled; if bLoadCompleted then RefreshPreviewPanel; end; { TfrmOptionsFilePanelsColors.tbInactivePanelBrightnessChange } procedure TfrmOptionsFilePanelsColors.tbInactivePanelBrightnessChange(Sender: TObject); begin if bLoadCompleted then begin PreviewLeftPanel.UpdateColumnsView; PreviewRightPanel.UpdateColumnsView; end; end; { TfrmOptionsFilePanelsColors.RefreshPreviewPanel } procedure TfrmOptionsFilePanelsColors.RefreshPreviewPanel; const DCFunc = '[DC().%s{}]'; var indx: integer; begin //Set color ColPrm.FontName := gFonts[dcfMain].Name; ColPrm.FontSize := gFonts[dcfMain].Size; ColPrm.FontStyle := gFonts[dcfMain].Style; ColPrm.Overcolor := cbAllowOverColor.Checked; ColPrm.UseInvertedSelection := cbbUseInvertedSelection.Checked; ColPrm.UseInactiveSelColor := cbbUseInactiveSelColor.Checked; ColPrm.TextColor := cbTextColor.Selected; ColPrm.Background := cbBackColor.Selected; ColPrm.Background2 := cbBackColor2.Selected; ColPrm.MarkColor := cbMarkColor.Selected; ColPrm.CursorColor := cbCursorColor.Selected; ColPrm.CursorText := cbCursorText.Selected; ColPrm.InactiveCursorColor := cbInactiveCursorColor.Selected; ColPrm.InactiveMarkColor := cbInactiveMarkColor.Selected; ColumnClass.Clear; ColumnClass.Add(rsColName, Format(DCFunc, [TFileFunctionStrings[fsfNameNoExtension]]), 200, taLeftJustify); ColumnClass.Add(rsColExt, Format(DCFunc, [TFileFunctionStrings[fsfExtension]]), 70, taLeftJustify); ColumnClass.Add(rsColSize, Format(DCFunc, [TFileFunctionStrings[fsfSize]]), 90, taRightJustify); for indx := 0 to pred(ColumnClass.Count) do ColumnClass.SetColumnPrm(Indx, ColPrm); ColumnClass.CustomView := True; ColumnClass.UseFrameCursor := cbbUseFrameCursor.Checked; ColumnClass.CursorBorderColor := clRed; ColumnClass.UseFrameCursor := cbbUseFrameCursor.Checked; ColumnClass.UseCursorBorder := cbUseCursorBorder.Checked; ColumnClass.CursorBorderColor := cbCursorBorderColor.Selected; ColumnClass.Name := 'JustForSetup'; PreviewLeftPanel.UpdateColumnsView; PreviewRightPanel.UpdateColumnsView; end; { TfrmOptionsFilePanelsColors.pnlLeftPreviewEnter } procedure TfrmOptionsFilePanelsColors.pnlLeftPreviewEnter(Sender: TObject); begin PreviewRightPanel.SetGridFunctionDim(@JustForConfigDim); PreviewRightPanel.JustForColorPreviewSetActiveState(False); PreviewLeftPanel.SetGridFunctionDim(@JustForConfigNoDim); PreviewLeftPanel.JustForColorPreviewSetActiveState(True); end; { TfrmOptionsFilePanelsColors.pnlRightPreviewEnter } procedure TfrmOptionsFilePanelsColors.pnlRightPreviewEnter(Sender: TObject); begin PreviewLeftPanel.SetGridFunctionDim(@JustForConfigDim); PreviewLeftPanel.JustForColorPreviewSetActiveState(False); PreviewRightPanel.SetGridFunctionDim(@JustForConfigNoDim); PreviewRightPanel.JustForColorPreviewSetActiveState(True); end; { TfrmOptionsFilePanelsColors.JustForConfigDim } function TfrmOptionsFilePanelsColors.JustForConfigDim(AColor: TColor): TColor; begin if (tbInactivePanelBrightness.Position < 100) then Result := ModColor(AColor, tbInactivePanelBrightness.Position) else Result := AColor; end; { TfrmOptionsFilePanelsColors.JustForConfigNoDim } function TfrmOptionsFilePanelsColors.JustForConfigNoDim(AColor: TColor): TColor; begin Result := AColor; end; end. ���������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesearch.lfm��������������������������������������������������0000644�0001750�0000144�00000010752�14743153644�021246� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFileSearch: TfrmOptionsFileSearch Height = 649 Width = 734 HelpKeyword = '/configuration.html#ConfigSearch' ChildSizing.LeftRightSpacing = 6 ClientHeight = 649 ClientWidth = 734 DesignLeft = 612 DesignTop = 188 object gbFileSearch: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 220 Top = 6 Width = 722 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'File search' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 200 ClientWidth = 718 TabOrder = 0 object cbPartialNameSearch: TCheckBox AnchorSideLeft.Control = rbUseStreamInSearch AnchorSideTop.Control = gbFileSearch Left = 10 Height = 19 Top = 6 Width = 163 BorderSpacing.Top = 6 Caption = '&Search for part of file name' TabOrder = 0 end object cbInitiallyClearFileMask: TCheckBox AnchorSideLeft.Control = rbUseStreamInSearch AnchorSideTop.Control = cbPartialNameSearch AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 31 Width = 271 BorderSpacing.Top = 6 Caption = 'When launching file search, clear file mask filter' TabOrder = 1 end object lblNewSearchFilters: TLabel AnchorSideTop.Control = cbNewSearchFilters AnchorSideTop.Side = asrCenter Left = 10 Height = 15 Top = 58 Width = 214 Caption = 'Current filters with "New search" button:' ParentColor = False end object cbNewSearchFilters: TComboBoxAutoWidth AnchorSideLeft.Control = lblNewSearchFilters AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbInitiallyClearFileMask AnchorSideTop.Side = asrBottom Left = 230 Height = 23 Top = 54 Width = 100 BorderSpacing.Left = 6 ItemHeight = 15 Style = csDropDownList TabOrder = 2 end object cbShowMenuBarInFindFiles: TCheckBox AnchorSideLeft.Control = rbUseStreamInSearch AnchorSideTop.Control = cbNewSearchFilters AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 83 Width = 176 BorderSpacing.Top = 6 Caption = 'Show menu bar in "Find files"' TabOrder = 3 end object lblSearchDefaultTemplate: TLabel AnchorSideLeft.Control = cbPartialNameSearch AnchorSideTop.Control = cbSearchDefaultTemplate AnchorSideTop.Side = asrCenter Left = 10 Height = 15 Top = 110 Width = 128 Caption = 'Default search template:' ParentColor = False end object cbSearchDefaultTemplate: TComboBoxAutoWidth AnchorSideLeft.Control = lblSearchDefaultTemplate AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbShowMenuBarInFindFiles AnchorSideTop.Side = asrBottom Left = 144 Height = 23 Top = 106 Width = 100 BorderSpacing.Left = 6 ItemHeight = 15 Style = csDropDownList TabOrder = 4 end object dbTextSearch: TDividerBevel AnchorSideLeft.Control = gbFileSearch AnchorSideTop.Control = cbSearchDefaultTemplate AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbFileSearch AnchorSideRight.Side = asrBottom Left = 10 Height = 15 Top = 133 Width = 698 Caption = 'Text search in files' Anchors = [akTop, akLeft, akRight] end object rbUseMmapInSearch: TRadioButton AnchorSideLeft.Control = gbFileSearch AnchorSideTop.Control = dbTextSearch AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 152 Width = 252 Caption = 'Use memory mapping for search te&xt in files' TabOrder = 5 end object rbUseStreamInSearch: TRadioButton AnchorSideLeft.Control = rbUseMmapInSearch AnchorSideTop.Control = rbUseMmapInSearch AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 177 Width = 192 BorderSpacing.Top = 6 Caption = '&Use stream for search text in files' Checked = True TabOrder = 6 TabStop = True end end end ����������������������doublecmd-1.1.22/src/frames/foptionsfilesearch.lrj��������������������������������������������������0000644�0001750�0000144�00000004422�14743153644�021254� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":131500776,"name":"tfrmoptionsfilesearch.gbfilesearch.caption","sourcebytes":[70,105,108,101,32,115,101,97,114,99,104],"value":"File search"}, {"hash":166353845,"name":"tfrmoptionsfilesearch.cbpartialnamesearch.caption","sourcebytes":[38,83,101,97,114,99,104,32,102,111,114,32,112,97,114,116,32,111,102,32,102,105,108,101,32,110,97,109,101],"value":"&Search for part of file name"}, {"hash":184749170,"name":"tfrmoptionsfilesearch.cbinitiallyclearfilemask.caption","sourcebytes":[87,104,101,110,32,108,97,117,110,99,104,105,110,103,32,102,105,108,101,32,115,101,97,114,99,104,44,32,99,108,101,97,114,32,102,105,108,101,32,109,97,115,107,32,102,105,108,116,101,114],"value":"When launching file search, clear file mask filter"}, {"hash":103938922,"name":"tfrmoptionsfilesearch.lblnewsearchfilters.caption","sourcebytes":[67,117,114,114,101,110,116,32,102,105,108,116,101,114,115,32,119,105,116,104,32,34,78,101,119,32,115,101,97,114,99,104,34,32,98,117,116,116,111,110,58],"value":"Current filters with \"New search\" button:"}, {"hash":189097922,"name":"tfrmoptionsfilesearch.cbshowmenubarinfindfiles.caption","sourcebytes":[83,104,111,119,32,109,101,110,117,32,98,97,114,32,105,110,32,34,70,105,110,100,32,102,105,108,101,115,34],"value":"Show menu bar in \"Find files\""}, {"hash":189046922,"name":"tfrmoptionsfilesearch.lblsearchdefaulttemplate.caption","sourcebytes":[68,101,102,97,117,108,116,32,115,101,97,114,99,104,32,116,101,109,112,108,97,116,101,58],"value":"Default search template:"}, {"hash":68368435,"name":"tfrmoptionsfilesearch.dbtextsearch.caption","sourcebytes":[84,101,120,116,32,115,101,97,114,99,104,32,105,110,32,102,105,108,101,115],"value":"Text search in files"}, {"hash":182075603,"name":"tfrmoptionsfilesearch.rbusemmapinsearch.caption","sourcebytes":[85,115,101,32,109,101,109,111,114,121,32,109,97,112,112,105,110,103,32,102,111,114,32,115,101,97,114,99,104,32,116,101,38,120,116,32,105,110,32,102,105,108,101,115],"value":"Use memory mapping for search te&xt in files"}, {"hash":268007779,"name":"tfrmoptionsfilesearch.rbusestreaminsearch.caption","sourcebytes":[38,85,115,101,32,115,116,114,101,97,109,32,102,111,114,32,115,101,97,114,99,104,32,116,101,120,116,32,105,110,32,102,105,108,101,115],"value":"&Use stream for search text in files"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesearch.pas��������������������������������������������������0000644�0001750�0000144�00000007714�14743153644�021257� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File search options page Copyright (C) 2006-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsFileSearch; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, Spin, ExtCtrls, KASComboBox, DividerBevel, fOptionsFrame; type { TfrmOptionsFileSearch } TfrmOptionsFileSearch = class(TOptionsEditor) cbInitiallyClearFileMask: TCheckBox; cbNewSearchFilters: TComboBoxAutoWidth; cbShowMenuBarInFindFiles: TCheckBox; cbPartialNameSearch: TCheckBox; cbSearchDefaultTemplate: TComboBoxAutoWidth; dbTextSearch: TDividerBevel; gbFileSearch: TGroupBox; lblNewSearchFilters: TLabel; lblSearchDefaultTemplate: TLabel; rbUseMmapInSearch: TRadioButton; rbUseStreamInSearch: TRadioButton; private FLoading: Boolean; procedure FillTemplatesList(ListItems: TStrings); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public constructor Create(TheOwner: TComponent); override; class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng; { TfrmOptionsFileSearch } class function TfrmOptionsFileSearch.GetIconIndex: Integer; begin Result := 41; end; class function TfrmOptionsFileSearch.GetTitle: String; begin Result := rsOptionsEditorFileSearch; end; procedure TfrmOptionsFileSearch.Init; begin FillTemplatesList(cbSearchDefaultTemplate.Items); ParseLineToList(rsNewSearchClearFilterOptions, cbNewSearchFilters.Items); end; procedure TfrmOptionsFileSearch.FillTemplatesList(ListItems: TStrings); begin gSearchTemplateList.LoadToStringList(ListItems); ListItems.Insert(0, rsOptHotkeysNoHotkey); end; procedure TfrmOptionsFileSearch.Load; begin FLoading := True; rbUseMmapInSearch.Checked := gUseMmapInSearch; cbPartialNameSearch.Checked := gPartialNameSearch; cbInitiallyClearFileMask.Checked := gInitiallyClearFileMask; cbNewSearchFilters.ItemIndex := integer(gNewSearchClearFiltersAction); cbShowMenuBarInFindFiles.Checked := gShowMenuBarInFindFiles; cbSearchDefaultTemplate.ItemIndex := cbSearchDefaultTemplate.Items.IndexOf(gSearchDefaultTemplate); if cbSearchDefaultTemplate.ItemIndex < 0 then cbSearchDefaultTemplate.ItemIndex := 0; FLoading := False; end; function TfrmOptionsFileSearch.Save: TOptionsEditorSaveFlags; begin Result := []; gUseMmapInSearch := rbUseMmapInSearch.Checked; gPartialNameSearch := cbPartialNameSearch.Checked; gInitiallyClearFileMask := cbInitiallyClearFileMask.Checked; gNewSearchClearFiltersAction := TFiltersOnNewSearch(cbNewSearchFilters.ItemIndex); gShowMenuBarInFindFiles := cbShowMenuBarInFindFiles.Checked; if cbSearchDefaultTemplate.ItemIndex > 0 then gSearchDefaultTemplate:= cbSearchDefaultTemplate.Text else begin gSearchDefaultTemplate:= EmptyStr; end; end; constructor TfrmOptionsFileSearch.Create(TheOwner: TComponent); begin inherited Create(TheOwner); FLoading := False; end; end. ����������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesviews.lfm��������������������������������������������������0000644�0001750�0000144�00000044766�14743153644�021335� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFilesViews: TfrmOptionsFilesViews Height = 550 Width = 640 HelpKeyword = '/configuration.html#ConfigView' ClientHeight = 550 ClientWidth = 640 DesignLeft = 200 DesignTop = 261 object gbSorting: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 163 Top = 6 Width = 628 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Sorting' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 6 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 143 ClientWidth = 624 TabOrder = 0 object lblSortMethod: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 8 Width = 104 Caption = '&Sort method:' FocusControl = cbSortMethod ParentColor = False end object cbSortMethod: TComboBox AnchorSideLeft.Control = lblSortMethod AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblSortMethod AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbSorting AnchorSideRight.Side = asrBottom Left = 126 Height = 23 Top = 4 Width = 486 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Items.Strings = ( 'Alphabetical, considering accents' 'Natural sorting: alphabetical and numbers' ) Style = csDropDownList TabOrder = 0 end object lblCaseSensitivity: TLabel Left = 12 Height = 15 Top = 35 Width = 104 Caption = 'Case s&ensitivity:' FocusControl = cbCaseSensitivity ParentColor = False end object cbCaseSensitivity: TComboBox AnchorSideLeft.Control = lblCaseSensitivity AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblCaseSensitivity AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbSorting AnchorSideRight.Side = asrBottom Left = 126 Height = 23 Top = 31 Width = 486 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Items.Strings = ( 'not case sensitive' 'according to locale settings (aAbBcC)' 'first upper then lower case (ABCabc)' ) Style = csDropDownList TabOrder = 1 end object lblSortFolderMode: TLabel Left = 12 Height = 15 Top = 62 Width = 104 Caption = 'So&rting directories:' FocusControl = cbSortFolderMode ParentColor = False end object cbSortFolderMode: TComboBox AnchorSideLeft.Control = lblSortFolderMode AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblSortFolderMode AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbSorting AnchorSideRight.Side = asrBottom Left = 126 Height = 23 Top = 58 Width = 486 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Items.Strings = ( 'sort by name and show first' 'sort like files and show first' 'sort like files' ) Style = csDropDownList TabOrder = 2 end object lblNewFilesPosition: TLabel Left = 12 Height = 15 Top = 89 Width = 104 Caption = '&Insert new files:' FocusControl = cbNewFilesPosition ParentColor = False end object cbNewFilesPosition: TComboBox AnchorSideLeft.Control = lblNewFilesPosition AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblNewFilesPosition AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbSorting AnchorSideRight.Side = asrBottom Left = 126 Height = 23 Top = 85 Width = 486 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Style = csDropDownList TabOrder = 3 end object lblUpdatedFilesPosition: TLabel Left = 12 Height = 15 Top = 116 Width = 104 Caption = '&Move updated files:' FocusControl = cbUpdatedFilesPosition ParentColor = False end object cbUpdatedFilesPosition: TComboBox AnchorSideLeft.Control = lblUpdatedFilesPosition AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblUpdatedFilesPosition AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbSorting AnchorSideRight.Side = asrBottom Left = 126 Height = 23 Top = 112 Width = 486 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Style = csDropDownList TabOrder = 4 end end object gbFormatting: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbSorting AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 136 Top = 175 Width = 628 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Formatting' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 6 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 116 ClientWidth = 624 TabOrder = 1 object lblDateTimeFormat: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 8 Width = 117 Caption = '&Date and time format:' FocusControl = cbDateTimeFormat ParentColor = False end object cbFileSizeFormat: TComboBox AnchorSideLeft.Control = lblFileSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblFileSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = speNumberOfDigitsFile Left = 139 Height = 23 Top = 31 Width = 379 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 DropDownCount = 12 ItemHeight = 15 OnChange = RefreshOurExamples Style = csDropDownList TabOrder = 1 end object lblFileSizeFormat: TLabel Left = 12 Height = 15 Top = 35 Width = 117 Caption = 'File si&ze format:' FocusControl = cbFileSizeFormat ParentColor = False end object pnlDateTime: TPanel AnchorSideLeft.Control = lblDateTimeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblDateTimeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbFormatting AnchorSideRight.Side = asrBottom Left = 139 Height = 23 Top = 4 Width = 473 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 10 BevelOuter = bvNone ClientHeight = 23 ClientWidth = 473 TabOrder = 0 object lblDateTimeExample: TLabel AnchorSideTop.Control = cbDateTimeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlDateTime AnchorSideRight.Side = asrBottom Left = 379 Height = 15 Top = 4 Width = 94 Anchors = [akTop, akRight] Caption = 'Incorrect format' Font.Style = [fsBold] ParentColor = False ParentFont = False end object cbDateTimeFormat: TComboBox AnchorSideRight.Control = lblDateTimeExample Left = 0 Height = 23 Top = 0 Width = 371 Align = alLeft Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Right = 8 ItemHeight = 15 Items.Strings = ( 'yyyy/mm/dd hh:mm:ss' 'yyyy/mm/dd hh:mm' 'yy/mm/dd hh:mm' 'dd/mm/yyyy hh:mm:ss' 'dd/mm/yyyy hh:mm' 'dd/mm/yy hh:mm' 'dd/mm/yyyy' 'dd/mm/yy' ) OnChange = cbDateTimeFormatChange TabOrder = 0 end end object speNumberOfDigitsFile: TSpinEdit AnchorSideLeft.Control = cbFileSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbFileSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblFileSizeExample Left = 524 Height = 23 Top = 31 Width = 50 Anchors = [akTop, akRight] MaxValue = 3 OnChange = RefreshOurExamples TabOrder = 2 end object lblHeaderSizeFormat: TLabel Left = 12 Height = 20 Top = 72 Width = 148 Caption = '&Header format:' FocusControl = cbHeaderSizeFormat ParentColor = False end object cbHeaderSizeFormat: TComboBox AnchorSideLeft.Control = lblHeaderSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblHeaderSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = speNumberOfDigitsHeader Left = 170 Height = 28 Top = 68 Width = 335 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 DropDownCount = 12 ItemHeight = 15 OnChange = RefreshOurExamples Style = csDropDownList TabOrder = 3 end object speNumberOfDigitsHeader: TSpinEdit AnchorSideLeft.Control = cbHeaderSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbHeaderSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblHeaderSizeExample Left = 511 Height = 28 Top = 68 Width = 63 Anchors = [akTop, akRight] MaxValue = 3 OnChange = RefreshOurExamples TabOrder = 4 end object lblHeaderSizeExample: TLabel AnchorSideTop.Control = cbHeaderSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbFormatting AnchorSideRight.Side = asrBottom Left = 580 Height = 12 Top = 63 Width = 32 Alignment = taRightJustify Anchors = [akTop, akRight] Constraints.MinHeight = 12 Constraints.MinWidth = 32 Font.Style = [fsBold] ParentColor = False ParentFont = False end object lblFooterSizeFormat: TLabel Left = 12 Height = 20 Top = 104 Width = 148 Caption = '&Footer format:' FocusControl = cbFooterSizeFormat ParentColor = False end object cbFooterSizeFormat: TComboBox AnchorSideLeft.Control = lblFooterSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblFooterSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = speNumberOfDigitsFooter Left = 170 Height = 28 Top = 100 Width = 335 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 DropDownCount = 12 ItemHeight = 20 OnChange = RefreshOurExamples Style = csDropDownList TabOrder = 5 end object speNumberOfDigitsFooter: TSpinEdit AnchorSideLeft.Control = cbFooterSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbFooterSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblFooterSizeExample Left = 511 Height = 28 Top = 100 Width = 63 Anchors = [akTop, akRight] MaxValue = 3 OnChange = RefreshOurExamples TabOrder = 6 end object lblFooterSizeExample: TLabel AnchorSideTop.Control = cbFooterSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbFormatting AnchorSideRight.Side = asrBottom Left = 580 Height = 12 Top = 108 Width = 32 Alignment = taRightJustify Anchors = [akTop, akRight] Constraints.MinHeight = 12 Constraints.MinWidth = 32 Font.Style = [fsBold] ParentColor = False ParentFont = False end object lblFileSizeExample: TLabel AnchorSideTop.Control = cbFileSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbFormatting AnchorSideRight.Side = asrBottom Left = 580 Height = 12 Top = 36 Width = 32 Alignment = taRightJustify Anchors = [akTop, akRight] Constraints.MinHeight = 12 Constraints.MinWidth = 32 Font.Style = [fsBold] ParentColor = False ParentFont = False end object lblOperationSizeExample: TLabel AnchorSideTop.Control = cbOperationSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbFormatting AnchorSideRight.Side = asrBottom Left = 580 Height = 12 Top = 90 Width = 32 Alignment = taRightJustify Anchors = [akTop, akRight] Constraints.MinHeight = 12 Constraints.MinWidth = 32 Font.Style = [fsBold] ParentColor = False ParentFont = False end object speNumberOfDigitsOperation: TSpinEdit AnchorSideLeft.Control = cbOperationSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbOperationSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblOperationSizeExample Left = 524 Height = 23 Top = 85 Width = 50 Anchors = [akTop, akRight] MaxValue = 3 OnChange = RefreshOurExamples TabOrder = 8 end object cbOperationSizeFormat: TComboBox AnchorSideLeft.Control = lblOperationSizeFormat AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblOperationSizeFormat AnchorSideTop.Side = asrCenter AnchorSideRight.Control = speNumberOfDigitsOperation Left = 139 Height = 23 Top = 85 Width = 379 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 DropDownCount = 12 ItemHeight = 15 OnChange = RefreshOurExamples Style = csDropDownList TabOrder = 7 end object lblOperationSizeFormat: TLabel Left = 12 Height = 15 Top = 89 Width = 117 Caption = 'O&peration size format:' FocusControl = cbOperationSizeFormat ParentColor = False end end object gbPersonalizedAbbreviationToUse: TGroupBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbFormatting AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 55 Top = 317 Width = 628 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Personalized abbreviations to use:' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 2 ClientHeight = 35 ClientWidth = 624 TabOrder = 2 object lblByte: TLabel AnchorSideLeft.Control = gbPersonalizedAbbreviationToUse AnchorSideTop.Control = gbPersonalizedAbbreviationToUse AnchorSideBottom.Side = asrBottom Left = 20 Height = 15 Top = 8 Width = 26 BorderSpacing.Left = 20 BorderSpacing.Top = 8 Caption = '&Byte:' FocusControl = edByte ParentColor = False end object edByte: TEdit AnchorSideLeft.Control = lblByte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 48 Height = 23 Top = 4 Width = 44 MaxLength = 10 OnChange = RefreshOurExamples TabOrder = 0 end object lblKilobyte: TLabel AnchorSideLeft.Control = edByte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblMegabyte AnchorSideTop.Side = asrCenter Left = 107 Height = 15 Top = 8 Width = 46 BorderSpacing.Left = 15 Caption = '&Kilobyte:' FocusControl = edKilo ParentColor = False end object edKilo: TEdit AnchorSideLeft.Control = lblKilobyte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 155 Height = 23 Top = 4 Width = 44 MaxLength = 10 OnChange = RefreshOurExamples TabOrder = 1 end object edMega: TEdit AnchorSideLeft.Control = lblMegabyte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 272 Height = 23 Top = 4 Width = 44 MaxLength = 10 OnChange = RefreshOurExamples TabOrder = 2 end object lblMegabyte: TLabel AnchorSideLeft.Control = edKilo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 214 Height = 15 Top = 8 Width = 56 BorderSpacing.Left = 15 Caption = 'Megab&yte:' FocusControl = edMega ParentColor = False end object lblGigabyte: TLabel AnchorSideLeft.Control = edMega AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 331 Height = 15 Top = 8 Width = 50 BorderSpacing.Left = 15 Caption = '&Gigabyte:' FocusControl = edGiga ParentColor = False end object edGiga: TEdit AnchorSideLeft.Control = lblGigabyte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 383 Height = 23 Top = 4 Width = 44 MaxLength = 10 OnChange = RefreshOurExamples TabOrder = 3 end object btnDefault: TButton AnchorSideLeft.Control = edTera AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 551 Height = 25 Top = 3 Width = 64 AutoSize = True BorderSpacing.Left = 15 Caption = 'De&fault' OnClick = btnDefaultClick TabOrder = 5 end object edTera: TEdit AnchorSideLeft.Control = lblTerabyte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 492 Height = 23 Top = 4 Width = 44 MaxLength = 10 OnChange = RefreshOurExamples TabOrder = 4 end object lblTerabyte: TLabel AnchorSideLeft.Control = edGiga AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblByte AnchorSideTop.Side = asrCenter Left = 442 Height = 15 Top = 8 Width = 48 BorderSpacing.Left = 15 Caption = '&Terabyte:' FocusControl = edTera ParentColor = False end end end����������doublecmd-1.1.22/src/frames/foptionsfilesviews.lrj��������������������������������������������������0000644�0001750�0000144�00000006670�14743153644�021336� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":174698519,"name":"tfrmoptionsfilesviews.gbsorting.caption","sourcebytes":[83,111,114,116,105,110,103],"value":"Sorting"}, {"hash":141329194,"name":"tfrmoptionsfilesviews.lblsortmethod.caption","sourcebytes":[38,83,111,114,116,32,109,101,116,104,111,100,58],"value":"&Sort method:"}, {"hash":207209658,"name":"tfrmoptionsfilesviews.lblcasesensitivity.caption","sourcebytes":[67,97,115,101,32,115,38,101,110,115,105,116,105,118,105,116,121,58],"value":"Case s&ensitivity:"}, {"hash":35834186,"name":"tfrmoptionsfilesviews.lblsortfoldermode.caption","sourcebytes":[83,111,38,114,116,105,110,103,32,100,105,114,101,99,116,111,114,105,101,115,58],"value":"So&rting directories:"}, {"hash":219756858,"name":"tfrmoptionsfilesviews.lblnewfilesposition.caption","sourcebytes":[38,73,110,115,101,114,116,32,110,101,119,32,102,105,108,101,115,58],"value":"&Insert new files:"}, {"hash":67957370,"name":"tfrmoptionsfilesviews.lblupdatedfilesposition.caption","sourcebytes":[38,77,111,118,101,32,117,112,100,97,116,101,100,32,102,105,108,101,115,58],"value":"&Move updated files:"}, {"hash":59734743,"name":"tfrmoptionsfilesviews.gbformatting.caption","sourcebytes":[70,111,114,109,97,116,116,105,110,103],"value":"Formatting"}, {"hash":45474298,"name":"tfrmoptionsfilesviews.lbldatetimeformat.caption","sourcebytes":[38,68,97,116,101,32,97,110,100,32,116,105,109,101,32,102,111,114,109,97,116,58],"value":"&Date and time format:"}, {"hash":34019434,"name":"tfrmoptionsfilesviews.lblfilesizeformat.caption","sourcebytes":[70,105,108,101,32,115,105,38,122,101,32,102,111,114,109,97,116,58],"value":"File si&ze format:"}, {"hash":7032132,"name":"tfrmoptionsfilesviews.lbldatetimeexample.caption","sourcebytes":[73,110,99,111,114,114,101,99,116,32,102,111,114,109,97,116],"value":"Incorrect format"}, {"hash":135517946,"name":"tfrmoptionsfilesviews.lblheadersizeformat.caption","sourcebytes":[38,72,101,97,100,101,114,32,102,111,114,109,97,116,58],"value":"&Header format:"}, {"hash":184800970,"name":"tfrmoptionsfilesviews.lblfootersizeformat.caption","sourcebytes":[38,70,111,111,116,101,114,32,102,111,114,109,97,116,58],"value":"&Footer format:"}, {"hash":70585306,"name":"tfrmoptionsfilesviews.lbloperationsizeformat.caption","sourcebytes":[79,38,112,101,114,97,116,105,111,110,32,115,105,122,101,32,102,111,114,109,97,116,58],"value":"O&peration size format:"}, {"hash":78125914,"name":"tfrmoptionsfilesviews.gbpersonalizedabbreviationtouse.caption","sourcebytes":[80,101,114,115,111,110,97,108,105,122,101,100,32,97,98,98,114,101,118,105,97,116,105,111,110,115,32,116,111,32,117,115,101,58],"value":"Personalized abbreviations to use:"}, {"hash":44698250,"name":"tfrmoptionsfilesviews.lblbyte.caption","sourcebytes":[38,66,121,116,101,58],"value":"&Byte:"}, {"hash":56408202,"name":"tfrmoptionsfilesviews.lblkilobyte.caption","sourcebytes":[38,75,105,108,111,98,121,116,101,58],"value":"&Kilobyte:"}, {"hash":122237274,"name":"tfrmoptionsfilesviews.lblmegabyte.caption","sourcebytes":[77,101,103,97,98,38,121,116,101,58],"value":"Megab&yte:"}, {"hash":226273146,"name":"tfrmoptionsfilesviews.lblgigabyte.caption","sourcebytes":[38,71,105,103,97,98,121,116,101,58],"value":"&Gigabyte:"}, {"hash":130846868,"name":"tfrmoptionsfilesviews.btndefault.caption","sourcebytes":[68,101,38,102,97,117,108,116],"value":"De&fault"}, {"hash":142389322,"name":"tfrmoptionsfilesviews.lblterabyte.caption","sourcebytes":[38,84,101,114,97,98,121,116,101,58],"value":"&Terabyte:"} ]} ������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesviews.pas��������������������������������������������������0000644�0001750�0000144�00000026241�14743153644�021326� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Files views options page Copyright (C) 2006-2021 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFilesViews; {$mode objfpc}{$H+} interface uses uTypes, Classes, SysUtils, StdCtrls, Graphics, ExtCtrls, Spin, fOptionsFrame; type { TfrmOptionsFilesViews } TfrmOptionsFilesViews = class(TOptionsEditor) btnDefault: TButton; cbDateTimeFormat: TComboBox; cbHeaderSizeFormat: TComboBox; cbFooterSizeFormat: TComboBox; cbOperationSizeFormat: TComboBox; cbUpdatedFilesPosition: TComboBox; cbNewFilesPosition: TComboBox; cbSortMethod: TComboBox; cbCaseSensitivity: TComboBox; cbSortFolderMode: TComboBox; cbFileSizeFormat: TComboBox; edByte: TEdit; edKilo: TEdit; edMega: TEdit; edGiga: TEdit; edTera: TEdit; gbFormatting: TGroupBox; gbSorting: TGroupBox; gbPersonalizedAbbreviationToUse: TGroupBox; lblByte: TLabel; lblKilobyte: TLabel; lblMegabyte: TLabel; lblGigabyte: TLabel; lblTerabyte: TLabel; lblHeaderSizeExample: TLabel; lblHeaderSizeFormat: TLabel; lblFooterSizeExample: TLabel; lblFooterSizeFormat: TLabel; lblOperationSizeExample: TLabel; lblOperationSizeFormat: TLabel; lblFileSizeExample: TLabel; lblDateTimeExample: TLabel; lblUpdatedFilesPosition: TLabel; lblSortFolderMode: TLabel; lblCaseSensitivity: TLabel; lblDateTimeFormat: TLabel; lblNewFilesPosition: TLabel; lblSortMethod: TLabel; lblFileSizeFormat: TLabel; pnlDateTime: TPanel; speNumberOfDigitsFile: TSpinEdit; speNumberOfDigitsHeader: TSpinEdit; speNumberOfDigitsFooter: TSpinEdit; speNumberOfDigitsOperation: TSpinEdit; procedure btnDefaultClick(Sender: TObject); procedure cbDateTimeFormatChange(Sender: TObject); procedure RefreshOurExamples(Sender: TObject); procedure TransferUnitsToOfficialUnits; private FIncorrectFormatMessage: string; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public procedure AfterConstruction; override; class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng, uDCUtils; const cFileSizeExample = 1335875825; { TfrmOptionsFilesViews } procedure TfrmOptionsFilesViews.cbDateTimeFormatChange(Sender: TObject); begin try lblDateTimeExample.Caption := FormatDateTime(cbDateTimeFormat.Text, Now); lblDateTimeExample.Font.Color := clDefault; except on E: EConvertError do begin lblDateTimeExample.Caption := FIncorrectFormatMessage; lblDateTimeExample.Font.Color := clRed; end; end; end; procedure TfrmOptionsFilesViews.RefreshOurExamples(Sender: TObject); var PreserveUnits: array[fsfPersonalizedByte .. fsfPersonalizedTera] of string; iFileSizeFormat: TFileSizeFormat; begin //We will temporary switch our units with official ones the time to show the preview. for iFileSizeFormat := fsfPersonalizedByte to fsfPersonalizedTera do PreserveUnits[iFileSizeFormat] := gSizeDisplayUnits[iFileSizeFormat]; try TransferUnitsToOfficialUnits; lblFileSizeExample.Caption := CnvFormatFileSize(cFileSizeExample, TFileSizeFormat(cbFileSizeFormat.ItemIndex), speNumberOfDigitsFile.Value); lblHeaderSizeExample.Caption := CnvFormatFileSize(cFileSizeExample, TFileSizeFormat(cbHeaderSizeFormat.ItemIndex), speNumberOfDigitsHeader.Value); lblFooterSizeExample.Caption := CnvFormatFileSize(cFileSizeExample, TFileSizeFormat(cbFooterSizeFormat.ItemIndex), speNumberOfDigitsFooter.Value); lblOperationSizeExample.Caption := CnvFormatFileSize(cFileSizeExample, TFileSizeFormat(cbOperationSizeFormat.ItemIndex), speNumberOfDigitsOperation.Value); finally //We restore the previous units. for iFileSizeFormat := fsfPersonalizedByte to fsfPersonalizedTera do gSizeDisplayUnits[iFileSizeFormat] := PreserveUnits[iFileSizeFormat]; end; end; procedure TfrmOptionsFilesViews.Init; begin ParseLineToList(rsOptSortMethod, cbSortMethod.Items); ParseLineToList(rsOptSortCaseSens, cbCaseSensitivity.Items); ParseLineToList(rsOptSortFolderMode, cbSortFolderMode.Items); ParseLineToList(rsOptNewFilesPosition, cbNewFilesPosition.Items); ParseLineToList(rsOptUpdatedFilesPosition, cbUpdatedFilesPosition.Items); ParseLineToList(rsOptFileSizeFloat + ';' + rsLegacyOperationByteSuffixLetter + ';' + rsLegacyDisplaySizeSingleLetterKilo + ';' + rsLegacyDisplaySizeSingleLetterMega + ';' + rsLegacyDisplaySizeSingleLetterGiga + ';' + rsLegacyDisplaySizeSingleLetterTera + ';' + rsOptPersonalizedFileSizeFormat, cbFileSizeFormat.Items); cbHeaderSizeFormat.Items.Assign(cbFileSizeFormat.Items); cbFooterSizeFormat.Items.Assign(cbFileSizeFormat.Items); cbOperationSizeFormat.Items.Assign(cbFileSizeFormat.Items); if cbDateTimeFormat.Items.IndexOf(DefaultDateTimeFormat) < 0 then begin cbDateTimeFormat.Items.Insert(0, DefaultDateTimeFormat); end; end; procedure TfrmOptionsFilesViews.Load; begin case gSortCaseSensitivity of cstNotSensitive: cbCaseSensitivity.ItemIndex := 0; cstLocale: cbCaseSensitivity.ItemIndex := 1; cstCharValue: cbCaseSensitivity.ItemIndex := 2; end; if not gSortNatural then cbSortMethod.ItemIndex := 0 else cbSortMethod.ItemIndex := 2; if gSortSpecial then cbSortMethod.ItemIndex := cbSortMethod.ItemIndex + 1; case gSortFolderMode of sfmSortNameShowFirst: cbSortFolderMode.ItemIndex := 0; sfmSortLikeFileShowFirst: cbSortFolderMode.ItemIndex := 1; sfmSortLikeFile: cbSortFolderMode.ItemIndex := 2; end; case gNewFilesPosition of nfpTop: cbNewFilesPosition.ItemIndex := 0; nfpTopAfterDirectories: cbNewFilesPosition.ItemIndex := 1; nfpSortedPosition: cbNewFilesPosition.ItemIndex := 2; nfpBottom: cbNewFilesPosition.ItemIndex := 3; end; case gUpdatedFilesPosition of ufpNoChange: cbUpdatedFilesPosition.ItemIndex := 0; ufpSameAsNewFiles: cbUpdatedFilesPosition.ItemIndex := 1; ufpSortedPosition: cbUpdatedFilesPosition.ItemIndex := 2; end; cbFileSizeFormat.ItemIndex := Ord(gFileSizeFormat); cbHeaderSizeFormat.ItemIndex := Ord(gHeaderSizeFormat); cbFooterSizeFormat.ItemIndex := Ord(gFooterSizeFormat); cbOperationSizeFormat.ItemIndex := Ord(gOperationSizeFormat); speNumberOfDigitsFile.Value := gFileSizeDigits; speNumberOfDigitsHeader.Value := gHeaderDigits; speNumberOfDigitsFooter.Value := gFooterDigits; speNumberOfDigitsOperation.Value := gOperationSizeDigits; edByte.Text := Trim(gSizeDisplayUnits[fsfPersonalizedByte]); edKilo.Text := Trim(gSizeDisplayUnits[fsfPersonalizedKilo]); edMega.Text := Trim(gSizeDisplayUnits[fsfPersonalizedMega]); edGiga.Text := Trim(gSizeDisplayUnits[fsfPersonalizedGiga]); edTera.Text := Trim(gSizeDisplayUnits[fsfPersonalizedTera]); cbDateTimeFormat.Text := gDateTimeFormat; lblDateTimeExample.Caption := FormatDateTime(cbDateTimeFormat.Text, Now); lblFileSizeExample.Constraints.MinWidth := lblFileSizeExample.Canvas.TextWidth(CnvFormatFileSize(cFileSizeExample, fsfKilo, speNumberOfDigitsFile.MaxValue) + 'WWW'); lblHeaderSizeExample.Constraints.MinWidth := lblHeaderSizeExample.Canvas.TextWidth(CnvFormatFileSize(cFileSizeExample, fsfKilo, speNumberOfDigitsHeader.MaxValue) + 'WWW'); lblFooterSizeExample.Constraints.MinWidth := lblFooterSizeExample.Canvas.TextWidth(CnvFormatFileSize(cFileSizeExample, fsfKilo, speNumberOfDigitsFooter.MaxValue) + 'WWW'); lblOperationSizeExample.Constraints.MinWidth := lblOperationSizeExample.Canvas.TextWidth(CnvFormatFileSize(cFileSizeExample, fsfKilo, speNumberOfDigitsOperation.MaxValue) + 'WWW'); Self.RefreshOurExamples(nil); end; function TfrmOptionsFilesViews.Save: TOptionsEditorSaveFlags; begin case cbCaseSensitivity.ItemIndex of 0: gSortCaseSensitivity := cstNotSensitive; 1: gSortCaseSensitivity := cstLocale; 2: gSortCaseSensitivity := cstCharValue; end; gSortNatural := (cbSortMethod.ItemIndex in [2,3]); gSortSpecial := (cbSortMethod.ItemIndex in [1,3]); case cbSortFolderMode.ItemIndex of 0: gSortFolderMode := sfmSortNameShowFirst; 1: gSortFolderMode := sfmSortLikeFileShowFirst; 2: gSortFolderMode := sfmSortLikeFile; end; case cbNewFilesPosition.ItemIndex of 0: gNewFilesPosition := nfpTop; 1: gNewFilesPosition := nfpTopAfterDirectories; 2: gNewFilesPosition := nfpSortedPosition; 3: gNewFilesPosition := nfpBottom; end; case cbUpdatedFilesPosition.ItemIndex of 0: gUpdatedFilesPosition := ufpNoChange; 1: gUpdatedFilesPosition := ufpSameAsNewFiles; 2: gUpdatedFilesPosition := ufpSortedPosition; end; gFileSizeFormat := TFileSizeFormat(cbFileSizeFormat.ItemIndex); gHeaderSizeFormat := TFileSizeFormat(cbHeaderSizeFormat.ItemIndex); gFooterSizeFormat := TFileSizeFormat(cbFooterSizeFormat.ItemIndex); gOperationSizeFormat := TFileSizeFormat(cbOperationSizeFormat.ItemIndex); gFileSizeDigits := speNumberOfDigitsFile.Value; gHeaderDigits := speNumberOfDigitsHeader.Value; gFooterDigits := speNumberOfDigitsFooter.Value; gOperationSizeDigits := speNumberOfDigitsOperation.Value; TransferUnitsToOfficialUnits; gDateTimeFormat := GetValidDateTimeFormat(cbDateTimeFormat.Text, gDateTimeFormat); Result := []; end; procedure TfrmOptionsFilesViews.AfterConstruction; begin inherited AfterConstruction; //save localized "Incorrect format" string FIncorrectFormatMessage := lblDateTimeExample.Caption; end; class function TfrmOptionsFilesViews.GetIconIndex: integer; begin Result := 29; end; class function TfrmOptionsFilesViews.GetTitle: string; begin Result := rsOptionsEditorFilesViews; end; procedure TfrmOptionsFilesViews.btnDefaultClick(Sender: TObject); begin Self.edByte.Text := Trim(rsDefaultPersonalizedAbbrevByte); Self.edKilo.Text := Trim(rsDefaultPersonalizedAbbrevKilo); Self.edMega.Text := Trim(rsDefaultPersonalizedAbbrevMega); Self.edGiga.Text := Trim(rsDefaultPersonalizedAbbrevGiga); Self.edTera.Text := Trim(rsDefaultPersonalizedAbbrevTera); end; procedure TfrmOptionsFilesViews.TransferUnitsToOfficialUnits; begin gSizeDisplayUnits[fsfPersonalizedByte] := Trim(edByte.Text); if gSizeDisplayUnits[fsfPersonalizedByte] <> '' then gSizeDisplayUnits[fsfPersonalizedByte] := ' ' + gSizeDisplayUnits[fsfPersonalizedByte]; gSizeDisplayUnits[fsfPersonalizedKilo] := ' ' + Trim(edKilo.Text); gSizeDisplayUnits[fsfPersonalizedMega] := ' ' + Trim(edMega.Text); gSizeDisplayUnits[fsfPersonalizedGiga] := ' ' + Trim(edGiga.Text); gSizeDisplayUnits[fsfPersonalizedTera] := ' ' + Trim(edTera.Text); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesviewscomplement.lfm����������������������������������������0000644�0001750�0000144�00000014722�14743153644�023406� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFilesViewsComplement: TfrmOptionsFilesViewsComplement Height = 550 Width = 640 HelpKeyword = '/configuration.html#ConfigViewEx' ClientHeight = 550 ClientWidth = 640 DesignLeft = 200 DesignTop = 261 object gbMisc: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbMarking AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 235 Top = 121 Width = 628 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 215 ClientWidth = 624 TabOrder = 1 object cbSpaceMovesDown: TCheckBox Left = 6 Height = 19 Top = 6 Width = 459 Caption = '&When selecting files with <SPACEBAR>, move down to next file (as with <INSERT>)' TabOrder = 0 end object cbDirBrackets: TCheckBox Left = 6 Height = 19 Top = 29 Width = 459 Caption = 'S&how square brackets around directories' TabOrder = 1 end object cbShowSystemFiles: TCheckBox Left = 6 Height = 19 Top = 52 Width = 459 Caption = 'Show s&ystem and hidden files' TabOrder = 2 end object cbListFilesInThread: TCheckBox Left = 6 Height = 19 Top = 75 Width = 459 Caption = 'Load &file list in separate thread' TabOrder = 3 end object cbLoadIconsSeparately: TCheckBox Left = 6 Height = 19 Top = 98 Width = 459 Caption = 'Load icons af&ter file list' TabOrder = 4 end object cbDelayLoadingTabs: TCheckBox Left = 6 Height = 19 Top = 121 Width = 459 Caption = 'Do&n''t load file list until a tab is activated' TabOrder = 5 end object cbHighlightUpdatedFiles: TCheckBox Left = 6 Height = 19 Top = 144 Width = 459 Caption = 'Hi&ghlight new and updated files' TabOrder = 6 end object cbInplaceRename: TCheckBox Left = 6 Height = 19 Top = 167 Width = 459 Caption = 'Enable inplace &renaming when clicking twice on a name' TabOrder = 7 end object cbDblClickToParent: TCheckBox Left = 6 Height = 19 Top = 190 Width = 459 Caption = 'Enable changing to &parent folder when double-clicking on empty part of file view' TabOrder = 8 end end object gbMarking: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 109 Top = 6 Width = 628 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Marking/Unmarking entries' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 6 ChildSizing.VerticalSpacing = 4 ClientHeight = 89 ClientWidth = 624 TabOrder = 0 object chkMarkMaskFilterWindows: TCheckBox AnchorSideLeft.Control = gbMarking AnchorSideTop.Control = gbMarking Left = 12 Height = 19 Top = 8 Width = 463 Caption = 'Windows style filter when marking files ("*.*" also select files without extension, etc.)' TabOrder = 0 end object pnlDefaultAttribute: TKASButtonPanel AnchorSideLeft.Control = chkMarkMaskFilterWindows AnchorSideTop.Control = chkMarkMaskFilterWindows AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMarking AnchorSideRight.Side = asrBottom Left = 12 Height = 27 Top = 31 Width = 600 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 3 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 27 ClientWidth = 600 TabOrder = 1 SameWidth = False object lbAttributeMask: TLabel AnchorSideLeft.Control = pnlDefaultAttribute AnchorSideTop.Control = edtDefaultAttribute AnchorSideTop.Side = asrCenter Left = 0 Height = 15 Top = 6 Width = 186 Caption = 'Default attribute mask value to use:' ParentColor = False end object edtDefaultAttribute: TEdit AnchorSideLeft.Control = lbAttributeMask AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnAddAttribute AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnAddAttribute AnchorSideBottom.Side = asrCenter Left = 189 Height = 27 Top = 0 Width = 304 HelpType = htKeyword HelpKeyword = '/findfiles.html#attributes' Anchors = [akTop, akLeft, akRight] TabOrder = 0 end object btnAttrsHelp: TButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btnAddAttribute AnchorSideRight.Control = pnlDefaultAttribute AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 547 Height = 27 Top = 0 Width = 53 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.InnerBorder = 1 Caption = '&Help' OnClick = btnAttrsHelpClick TabOrder = 2 end object btnAddAttribute: TButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlDefaultAttribute AnchorSideRight.Control = btnAttrsHelp Left = 496 Height = 26 Top = 0 Width = 48 Anchors = [akTop, akRight] AutoSize = True Caption = '&Add' OnClick = btnAddAttributeClick TabOrder = 1 end end object chkMarkMaskShowAttribute: TCheckBox AnchorSideLeft.Control = chkMarkMaskFilterWindows AnchorSideTop.Control = pnlDefaultAttribute AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 62 Width = 366 Caption = 'Use an independent attribute filter in mask input dialog each time' TabOrder = 2 end end end ����������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesviewscomplement.lrj����������������������������������������0000644�0001750�0000144�00000011251�14743153644�023411� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":103818425,"name":"tfrmoptionsfilesviewscomplement.cbspacemovesdown.caption","sourcebytes":[38,87,104,101,110,32,115,101,108,101,99,116,105,110,103,32,102,105,108,101,115,32,119,105,116,104,32,60,83,80,65,67,69,66,65,82,62,44,32,109,111,118,101,32,100,111,119,110,32,116,111,32,110,101,120,116,32,102,105,108,101,32,40,97,115,32,119,105,116,104,32,60,73,78,83,69,82,84,62,41],"value":"&When selecting files with <SPACEBAR>, move down to next file (as with <INSERT>)"}, {"hash":65976739,"name":"tfrmoptionsfilesviewscomplement.cbdirbrackets.caption","sourcebytes":[83,38,104,111,119,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,32,97,114,111,117,110,100,32,100,105,114,101,99,116,111,114,105,101,115],"value":"S&how square brackets around directories"}, {"hash":175165491,"name":"tfrmoptionsfilesviewscomplement.cbshowsystemfiles.caption","sourcebytes":[83,104,111,119,32,115,38,121,115,116,101,109,32,97,110,100,32,104,105,100,100,101,110,32,102,105,108,101,115],"value":"Show s&ystem and hidden files"}, {"hash":110856692,"name":"tfrmoptionsfilesviewscomplement.cblistfilesinthread.caption","sourcebytes":[76,111,97,100,32,38,102,105,108,101,32,108,105,115,116,32,105,110,32,115,101,112,97,114,97,116,101,32,116,104,114,101,97,100],"value":"Load &file list in separate thread"}, {"hash":176402404,"name":"tfrmoptionsfilesviewscomplement.cbloadiconsseparately.caption","sourcebytes":[76,111,97,100,32,105,99,111,110,115,32,97,102,38,116,101,114,32,102,105,108,101,32,108,105,115,116],"value":"Load icons af&ter file list"}, {"hash":57459572,"name":"tfrmoptionsfilesviewscomplement.cbdelayloadingtabs.caption","sourcebytes":[68,111,38,110,39,116,32,108,111,97,100,32,102,105,108,101,32,108,105,115,116,32,117,110,116,105,108,32,97,32,116,97,98,32,105,115,32,97,99,116,105,118,97,116,101,100],"value":"Do&n't load file list until a tab is activated"}, {"hash":89894099,"name":"tfrmoptionsfilesviewscomplement.cbhighlightupdatedfiles.caption","sourcebytes":[72,105,38,103,104,108,105,103,104,116,32,110,101,119,32,97,110,100,32,117,112,100,97,116,101,100,32,102,105,108,101,115],"value":"Hi&ghlight new and updated files"}, {"hash":139135013,"name":"tfrmoptionsfilesviewscomplement.cbinplacerename.caption","sourcebytes":[69,110,97,98,108,101,32,105,110,112,108,97,99,101,32,38,114,101,110,97,109,105,110,103,32,119,104,101,110,32,99,108,105,99,107,105,110,103,32,116,119,105,99,101,32,111,110,32,97,32,110,97,109,101],"value":"Enable inplace &renaming when clicking twice on a name"}, {"hash":165018039,"name":"tfrmoptionsfilesviewscomplement.cbdblclicktoparent.caption","sourcebytes":[69,110,97,98,108,101,32,99,104,97,110,103,105,110,103,32,116,111,32,38,112,97,114,101,110,116,32,102,111,108,100,101,114,32,119,104,101,110,32,100,111,117,98,108,101,45,99,108,105,99,107,105,110,103,32,111,110,32,101,109,112,116,121,32,112,97,114,116,32,111,102,32,102,105,108,101,32,118,105,101,119],"value":"Enable changing to &parent folder when double-clicking on empty part of file view"}, {"hash":8828099,"name":"tfrmoptionsfilesviewscomplement.gbmarking.caption","sourcebytes":[77,97,114,107,105,110,103,47,85,110,109,97,114,107,105,110,103,32,101,110,116,114,105,101,115],"value":"Marking/Unmarking entries"}, {"hash":245486841,"name":"tfrmoptionsfilesviewscomplement.chkmarkmaskfilterwindows.caption","sourcebytes":[87,105,110,100,111,119,115,32,115,116,121,108,101,32,102,105,108,116,101,114,32,119,104,101,110,32,109,97,114,107,105,110,103,32,102,105,108,101,115,32,40,34,42,46,42,34,32,97,108,115,111,32,115,101,108,101,99,116,32,102,105,108,101,115,32,119,105,116,104,111,117,116,32,101,120,116,101,110,115,105,111,110,44,32,101,116,99,46,41],"value":"Windows style filter when marking files (\"*.*\" also select files without extension, etc.)"}, {"hash":228092554,"name":"tfrmoptionsfilesviewscomplement.lbattributemask.caption","sourcebytes":[68,101,102,97,117,108,116,32,97,116,116,114,105,98,117,116,101,32,109,97,115,107,32,118,97,108,117,101,32,116,111,32,117,115,101,58],"value":"Default attribute mask value to use:"}, {"hash":2812976,"name":"tfrmoptionsfilesviewscomplement.btnattrshelp.caption","sourcebytes":[38,72,101,108,112],"value":"&Help"}, {"hash":173988,"name":"tfrmoptionsfilesviewscomplement.btnaddattribute.caption","sourcebytes":[38,65,100,100],"value":"&Add"}, {"hash":26924549,"name":"tfrmoptionsfilesviewscomplement.chkmarkmaskshowattribute.caption","sourcebytes":[85,115,101,32,97,110,32,105,110,100,101,112,101,110,100,101,110,116,32,97,116,116,114,105,98,117,116,101,32,102,105,108,116,101,114,32,105,110,32,109,97,115,107,32,105,110,112,117,116,32,100,105,97,108,111,103,32,101,97,99,104,32,116,105,109,101],"value":"Use an independent attribute filter in mask input dialog each time"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfilesviewscomplement.pas����������������������������������������0000644�0001750�0000144�00000012065�14743153644�023411� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Files views complement options page Copyright (C) 2018-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFilesViewsComplement; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, Graphics, ExtCtrls, KASButtonPanel, fOptionsFrame; type { TfrmOptionsFilesViewsComplement } TfrmOptionsFilesViewsComplement = class(TOptionsEditor) btnAddAttribute: TButton; btnAttrsHelp: TButton; cbDblClickToParent: TCheckBox; cbHighlightUpdatedFiles: TCheckBox; cbDirBrackets: TCheckBox; cbListFilesInThread: TCheckBox; cbLoadIconsSeparately: TCheckBox; cbDelayLoadingTabs: TCheckBox; cbShowSystemFiles: TCheckBox; cbSpaceMovesDown: TCheckBox; cbInplaceRename: TCheckBox; gbMisc: TGroupBox; pnlDefaultAttribute: TKASButtonPanel; chkMarkMaskFilterWindows: TCheckBox; gbMarking: TGroupBox; lbAttributeMask: TLabel; edtDefaultAttribute: TEdit; chkMarkMaskShowAttribute: TCheckBox; procedure btnAddAttributeClick(Sender: TObject); procedure btnAttrsHelpClick(Sender: TObject); private procedure OnAddAttribute(Sender: TObject); protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses HelpIntfs, fAttributesEdit, uGlobs, uLng; { TfrmOptionsFilesViewsComplement } procedure TfrmOptionsFilesViewsComplement.Load; begin cbSpaceMovesDown.Checked := gSpaceMovesDown; cbDirBrackets.Checked := gDirBrackets; cbShowSystemFiles.Checked:= gShowSystemFiles; {$IFDEF LCLCARBON} // Under Mac OS X loading file list in separate thread are very very slow // so disable and hide this option under Mac OS X Carbon cbListFilesInThread.Visible:= False; {$ELSE} cbListFilesInThread.Checked:= gListFilesInThread; {$ENDIF} cbLoadIconsSeparately.Checked:= gLoadIconsSeparately; cbDelayLoadingTabs.Checked:= gDelayLoadingTabs; cbHighlightUpdatedFiles.Checked:= gHighlightUpdatedFiles; cbInplaceRename.Checked := gInplaceRename; cbDblClickToParent.Checked := gDblClickToParent; chkMarkMaskFilterWindows.Checked := gMarkMaskFilterWindows; chkMarkMaskShowAttribute.Checked := gMarkShowWantedAttribute; edtDefaultAttribute.Text := gMarkDefaultWantedAttribute; end; function TfrmOptionsFilesViewsComplement.Save: TOptionsEditorSaveFlags; begin gSpaceMovesDown := cbSpaceMovesDown.Checked; gDirBrackets := cbDirBrackets.Checked; gShowSystemFiles:= cbShowSystemFiles.Checked; gListFilesInThread:= cbListFilesInThread.Checked; gLoadIconsSeparately:= cbLoadIconsSeparately.Checked; gDelayLoadingTabs := cbDelayLoadingTabs.Checked; gHighlightUpdatedFiles := cbHighlightUpdatedFiles.Checked; gInplaceRename := cbInplaceRename.Checked; gDblClickToParent := cbDblClickToParent.Checked; gMarkMaskFilterWindows := chkMarkMaskFilterWindows.Checked; gMarkShowWantedAttribute := chkMarkMaskShowAttribute.Checked; gMarkDefaultWantedAttribute := edtDefaultAttribute.Text; Result := []; end; class function TfrmOptionsFilesViewsComplement.GetIconIndex: Integer; begin Result := 29; end; class function TfrmOptionsFilesViewsComplement.GetTitle: String; begin Result := rsOptionsEditorFilesViewsComplement; end; procedure TfrmOptionsFilesViewsComplement.btnAddAttributeClick(Sender: TObject); var FFrmAttributesEdit: TfrmAttributesEdit; begin FFrmAttributesEdit := TfrmAttributesEdit.Create(Owner); try FFrmAttributesEdit.OnOk := @OnAddAttribute; FFrmAttributesEdit.Reset; FFrmAttributesEdit.ShowModal; finally FFrmAttributesEdit.Free; end; end; procedure TfrmOptionsFilesViewsComplement.btnAttrsHelpClick(Sender: TObject); begin ShowHelpOrErrorForKeyword('', edtDefaultAttribute.HelpKeyword); end; procedure TfrmOptionsFilesViewsComplement.OnAddAttribute(Sender: TObject); var sAttr: String; begin sAttr := edtDefaultAttribute.Text; if edtDefaultAttribute.SelStart > 0 then Insert((Sender as TfrmAttributesEdit).AttrsAsText, sAttr, edtDefaultAttribute.SelStart + 1) // Insert at caret position. else sAttr := sAttr + (Sender as TfrmAttributesEdit).AttrsAsText; edtDefaultAttribute.Text := sAttr; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfiletypescolors.lfm���������������������������������������������0000644�0001750�0000144�00000020600�14743153644�022360� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFileTypesColors: TfrmOptionsFileTypesColors Height = 356 Width = 759 HelpKeyword = '/configuration.html#ConfigColorFiles' AutoSize = True ClientHeight = 356 ClientWidth = 759 DesignLeft = 378 DesignTop = 92 object gbFileTypesColors: TGroupBox[0] AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 8 Height = 346 Top = 6 Width = 743 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Left = 8 BorderSpacing.Top = 6 BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 Caption = 'File types colors (sort by drag&&drop)' ChildSizing.LeftRightSpacing = 8 ClientHeight = 326 ClientWidth = 739 TabOrder = 0 object lblCategoryName: TLabel AnchorSideTop.Control = edtCategoryName AnchorSideTop.Side = asrCenter Left = 8 Height = 15 Top = 163 Width = 84 Caption = 'Category &name:' FocusControl = edtCategoryName ParentColor = False end object lblCategoryMask: TLabel AnchorSideTop.Control = edtCategoryMask AnchorSideTop.Side = asrCenter Left = 8 Height = 15 Top = 194 Width = 82 Caption = 'Category &mask:' FocusControl = edtCategoryMask ParentColor = False end object lblCategoryColor: TLabel AnchorSideTop.Control = cbCategoryColor AnchorSideTop.Side = asrCenter Left = 8 Height = 15 Top = 256 Width = 81 Caption = 'Category co&lor:' FocusControl = cbCategoryColor ParentColor = False end object lblCategoryAttr: TLabel AnchorSideTop.Control = edtCategoryAttr AnchorSideTop.Side = asrCenter Left = 8 Height = 15 Top = 225 Width = 104 Caption = 'Category a&ttributes:' FocusControl = edtCategoryAttr ParentColor = False end object edtCategoryName: TEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lbCategories AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtCategoryMask Left = 170 Height = 23 Top = 159 Width = 561 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Bottom = 8 TabOrder = 1 end object edtCategoryMask: TEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnSearchTemplate AnchorSideBottom.Control = edtCategoryAttr Left = 170 Height = 23 Top = 190 Width = 532 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Top = 8 BorderSpacing.Right = 6 BorderSpacing.Bottom = 8 TabOrder = 2 end object cbCategoryColor: TKASColorBoxButton AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtCategoryAttr AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btnApplyCategory Left = 170 Height = 25 Top = 249 Width = 561 Anchors = [akLeft, akRight, akBottom] TabOrder = 5 BorderSpacing.Bottom = 12 end object btnAddCategory: TBitBtn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnDeleteCategory AnchorSideBottom.Control = btnApplyCategory AnchorSideBottom.Side = asrBottom Left = 389 Height = 32 Top = 286 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Right = 6 Caption = 'A&dd' OnClick = btnAddCategoryClick TabOrder = 6 end object btnDeleteCategory: TBitBtn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnApplyCategory AnchorSideBottom.Control = btnApplyCategory AnchorSideBottom.Side = asrBottom Left = 505 Height = 32 Top = 286 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Right = 6 Caption = 'D&elete' OnClick = btnDeleteCategoryClick TabOrder = 7 end object lbCategories: TListBox AnchorSideTop.Control = gbFileTypesColors AnchorSideRight.Control = gbFileTypesColors AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtCategoryName Left = 8 Height = 141 Top = 6 Width = 723 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 6 BorderSpacing.Right = 8 BorderSpacing.Bottom = 12 DragMode = dmAutomatic ItemHeight = 0 OnClick = lbCategoriesClick OnDragDrop = lbCategoriesDragDrop OnDragOver = lbCategoriesDragOver OnDrawItem = lbCategoriesDrawItem Style = lbOwnerDrawFixed TabOrder = 0 end object btnApplyCategory: TBitBtn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lbCategories AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gbFileTypesColors AnchorSideBottom.Side = asrBottom Left = 621 Height = 32 Top = 286 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Bottom = 8 Caption = 'A&pply' OnClick = btnApplyCategoryClick TabOrder = 8 end object edtCategoryAttr: TEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lbCategories AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = cbCategoryColor Left = 170 Height = 23 Top = 221 Width = 561 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Bottom = 8 TabOrder = 4 end object btnSearchTemplate: TBitBtn AnchorSideTop.Control = edtCategoryMask AnchorSideRight.Control = lbCategories AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtCategoryMask AnchorSideBottom.Side = asrBottom Left = 708 Height = 23 Hint = 'Template...' Top = 190 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000009700 00FF000000000000000000000000000000FF00000000000000FFC2B5B3E30000 00FF000000000000000000000000000000000000000000000000000000000000 0000970000FF00000000000000000000000000000000C5B8B570E3DBD9FF8975 7375000000000000000000000000000000000000000000000000000000000000 000000000000970000FF000000000000000000000000C2B4B26FE1D9D7FF8571 6E75000000000000000000000000000000000000000000000000000000000000 0000970000FF00000000000000000000000000000000B3A4A26FD6C9C7FF705E 5B75000000000000000000000000000000000000000000000000000000009700 00FF0000000000000000000000000000000000000000A798967DD9CBCAFF7362 6184000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000005B494812D4C6C5FFD1C2C1FE8F7E 7DFF5B4B4E160000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000C2B3B3C0EEE2E2FED5C8C7FFD6C9 C8FE746363C60000000000000000000000000000000000000000000000000000 00000000000000000000000000009D8B8B5CF9EEEFFFEDE1E0FFDED1D1FFEADE DCFFB1A1A0FF645455630000000000000000000000000000000000000000D2C6 C36CEEE5E2C3BEADABB100000002D2C4C3FBFDF5F4FEE0D4D3FFDACCCBFFE8DD DBFFD2C4C2FE796868FD61525509000000000000000000000000000000008B78 754B00000000000000007C6B6BFCF7ECECFFFEF6F4FFCFC2C0FFD4C7C7FFEDE3 E1FFCDBDBBFF998887FE605151BC00000000000000000000000000000000806F 6D350000000062514F4CCEBEBEFFFBF2F0FFFBF6F5FFC7B9B7FFD0C3C3FFF8F0 EFFFC7B7B4FFA69593FF665555FF5545464D000000000000000000000000D8CF CE59D1C5C299978484FFF4EBEBFEFEFDFDFFF4EEEDFFC3B5B3FFD8CBC9FFFFFC FCFFD8CBC9FFB2A1A0FF867474FE524343FA0000000200000000000000000000 00007767669CE0D3D1FFFFFEFEFFFFFFFFFFEFE7E6FFAF9E9BFFD6C6C4FFFCF7 F7FFD8CACAFFAE9D9EFF827173FF5B4A4EFF67595C9F00000000000000000000 00008E7F7ED8E2D7D6FFCCC2C2FFCDC6C6FFD0C9C9FFD7D1D2FFD6D1D2FFCEC6 C6FFCBC5C5FFC7C0C0FFC2B8B8FFA39698FF726468DC00000000000000000000 0000ACA2A3DEAC9C99FFC9BCBBFFDBCDCAFFF3E6E2FEFFFFFEFFF5EEECFFB9A7 A3FFF3EDEBFEF7F3F3FFA99998FFA49695FFB1A6A7E700000000000000000000 0000000000005F5054459C919391B7ADAFB4BBB2B2C3C0B5B6CFC0B6B7D2BBB2 B3D0BCB2B3C3BBB3B4B59D929592615156460000000000000000 } GlyphShowMode = gsmAlways Layout = blGlyphRight OnClick = btnSearchTemplateClick ParentShowHint = False ShowHint = True TabOrder = 3 end end end ��������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfiletypescolors.lrj���������������������������������������������0000644�0001750�0000144�00000003116�14743153644�022374� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":239267657,"name":"tfrmoptionsfiletypescolors.gbfiletypescolors.caption","sourcebytes":[70,105,108,101,32,116,121,112,101,115,32,99,111,108,111,114,115,32,40,115,111,114,116,32,98,121,32,100,114,97,103,38,38,100,114,111,112,41],"value":"File types colors (sort by drag&&drop)"}, {"hash":143287226,"name":"tfrmoptionsfiletypescolors.lblcategoryname.caption","sourcebytes":[67,97,116,101,103,111,114,121,32,38,110,97,109,101,58],"value":"Category &name:"}, {"hash":143501786,"name":"tfrmoptionsfiletypescolors.lblcategorymask.caption","sourcebytes":[67,97,116,101,103,111,114,121,32,38,109,97,115,107,58],"value":"Category &mask:"}, {"hash":67057050,"name":"tfrmoptionsfiletypescolors.lblcategorycolor.caption","sourcebytes":[67,97,116,101,103,111,114,121,32,99,111,38,108,111,114,58],"value":"Category co&lor:"}, {"hash":52377562,"name":"tfrmoptionsfiletypescolors.lblcategoryattr.caption","sourcebytes":[67,97,116,101,103,111,114,121,32,97,38,116,116,114,105,98,117,116,101,115,58],"value":"Category a&ttributes:"}, {"hash":277668,"name":"tfrmoptionsfiletypescolors.btnaddcategory.caption","sourcebytes":[65,38,100,100],"value":"A&dd"}, {"hash":114044133,"name":"tfrmoptionsfiletypescolors.btndeletecategory.caption","sourcebytes":[68,38,101,108,101,116,101],"value":"D&elete"}, {"hash":71137081,"name":"tfrmoptionsfiletypescolors.btnapplycategory.caption","sourcebytes":[65,38,112,112,108,121],"value":"A&pply"}, {"hash":47236478,"name":"tfrmoptionsfiletypescolors.btnsearchtemplate.hint","sourcebytes":[84,101,109,112,108,97,116,101,46,46,46],"value":"Template..."} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfiletypescolors.pas���������������������������������������������0000644�0001750�0000144�00000022764�14743153644�022402� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- File types colors options page Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsFileTypesColors; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, StdCtrls, KASComboBox, Dialogs, Buttons, LMessages, fOptionsFrame; type { TfrmOptionsFileTypesColors } TfrmOptionsFileTypesColors = class(TOptionsEditor) btnAddCategory: TBitBtn; btnApplyCategory: TBitBtn; btnDeleteCategory: TBitBtn; btnSearchTemplate: TBitBtn; cbCategoryColor: TKASColorBoxButton; edtCategoryAttr: TEdit; edtCategoryMask: TEdit; edtCategoryName: TEdit; gbFileTypesColors: TGroupBox; lbCategories: TListBox; lblCategoryAttr: TLabel; lblCategoryColor: TLabel; lblCategoryMask: TLabel; lblCategoryName: TLabel; procedure lbCategoriesClick(Sender: TObject); procedure btnSearchTemplateClick(Sender: TObject); procedure btnAddCategoryClick(Sender: TObject); procedure btnApplyCategoryClick(Sender: TObject); procedure btnDeleteCategoryClick(Sender: TObject); procedure lbCategoriesDragDrop(Sender, {%H-}Source: TObject; {%H-}X, Y: Integer); procedure lbCategoriesDragOver(Sender, Source: TObject; {%H-}X, {%H-}Y: Integer; {%H-}State: TDragState; var Accept: Boolean); procedure lbCategoriesDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; {%H-}State: TOwnerDrawState); procedure Clear; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public destructor Destroy; override; class function GetIconIndex: Integer; override; class function GetTitle: String; override; function IsSignatureComputedFromAllWindowComponents: Boolean; override; end; implementation {$R *.lfm} uses Graphics, uLng, uGlobs, uColorExt, fMaskInputDlg, uSearchTemplate, uDCUtils; { TfrmOptionsFileTypesColors } procedure TfrmOptionsFileTypesColors.lbCategoriesClick(Sender: TObject); var MaskItem : TMaskItem; bEnabled: Boolean; begin if (lbCategories.ItemIndex <> -1) then begin MaskItem := TMaskItem(lbCategories.Items.Objects[lbCategories.ItemIndex]); edtCategoryName.Text := MaskItem.sName; edtCategoryMask.Text := MaskItem.sExt; cbCategoryColor.Selected := MaskItem.cColor; bEnabled:= (MaskItem.sExt = '') or (MaskItem.sExt[1] <> '>'); edtCategoryMask.Enabled:= bEnabled; edtCategoryAttr.Enabled:= bEnabled; edtCategoryAttr.Text := MaskItem.sModeStr; end else begin edtCategoryName.Text := ''; edtCategoryMask.Text := ''; edtCategoryAttr.Text := ''; cbCategoryColor.Selected := gColors.FilePanel^.ForeColor; end; end; procedure TfrmOptionsFileTypesColors.btnSearchTemplateClick(Sender: TObject); var sMask: String; bTemplate: Boolean; begin sMask:= edtCategoryMask.Text; if ShowMaskInputDlg(rsMarkPlus, rsMaskInput, glsMaskHistory, sMask) then begin bTemplate:= IsMaskSearchTemplate(sMask); edtCategoryMask.Text:= sMask; if bTemplate then edtCategoryAttr.Text:= EmptyStr; edtCategoryMask.Enabled:= not bTemplate; edtCategoryAttr.Enabled:= not bTemplate; end; end; procedure TfrmOptionsFileTypesColors.btnAddCategoryClick(Sender: TObject); var iIndex : Integer; MaskItem: TMaskItem; begin if lbCategories.Count = 0 then begin edtCategoryName.Enabled := True; edtCategoryMask.Enabled := True; edtCategoryAttr.Enabled := True; cbCategoryColor.Enabled := True; btnDeleteCategory.Enabled := True; btnApplyCategory.Enabled := True; end; MaskItem := TMaskItem.Create; try edtCategoryName.Text := rsOptionsEditorFileNewFileTypes; edtCategoryMask.Text := '*'; edtCategoryAttr.Text := ''; cbCategoryColor.Selected := gColors.FilePanel^.ForeColor; MaskItem.sName:= edtCategoryName.Text; MaskItem.sExt:= edtCategoryMask.Text; MaskItem.sModeStr:= edtCategoryAttr.Text; MaskItem.cColor:= clBlack; iIndex := lbCategories.Items.AddObject(MaskItem.sName, MaskItem); except FreeAndNil(MaskItem); raise; end; lbCategories.ItemIndex:= iIndex; edtCategoryName.SetFocus; end; procedure TfrmOptionsFileTypesColors.btnApplyCategoryClick(Sender: TObject); var MaskItem : TMaskItem; begin if (lbCategories.ItemIndex <> -1) then begin lbCategories.Items[lbCategories.ItemIndex] := edtCategoryName.Text; if edtCategoryMask.Text = '' then edtCategoryMask.Text := '*'; // because we load colors from ini by mask MaskItem := TMaskItem(lbCategories.Items.Objects[lbCategories.ItemIndex]); MaskItem.sName := edtCategoryName.Text; MaskItem.cColor := cbCategoryColor.Selected; MaskItem.sExt := edtCategoryMask.Text; MaskItem.sModeStr := edtCategoryAttr.Text; end; end; procedure TfrmOptionsFileTypesColors.btnDeleteCategoryClick(Sender: TObject); begin if (lbCategories.ItemIndex <> -1) then begin lbCategories.Items.Objects[lbCategories.ItemIndex].Free; lbCategories.Items.Delete(lbCategories.ItemIndex); if lbCategories.Count > 0 then lbCategories.ItemIndex := 0; lbCategoriesClick(lbCategories); end; end; procedure TfrmOptionsFileTypesColors.lbCategoriesDragDrop(Sender, Source: TObject; X, Y: Integer); var SrcIndex, DestIndex: Integer; begin SrcIndex := lbCategories.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lbCategories.GetIndexAtY(Y); if (DestIndex < 0) or (DestIndex >= lbCategories.Count) then DestIndex := lbCategories.Count - 1; lbCategories.Items.Move(SrcIndex, DestIndex); lbCategories.ItemIndex := DestIndex; end; procedure TfrmOptionsFileTypesColors.lbCategoriesDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := (Source = lbCategories) and (lbCategories.ItemIndex <> -1); end; procedure TfrmOptionsFileTypesColors.lbCategoriesDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); begin with (Control as TListBox), gColors.FilePanel^ do begin if (not Selected[Index]) and Assigned(Items.Objects[Index]) then begin Canvas.Brush.Color:= BackColor; Canvas.Font.Color:= TMaskItem(Items.Objects[Index]).cColor; end else begin Canvas.Brush.Color:= CursorColor; Canvas.Font.Color:= CursorText; end; Canvas.FillRect(ARect); Canvas.TextOut(ARect.Left+2,ARect.Top,Items[Index]); end; end; procedure TfrmOptionsFileTypesColors.Clear; var i: Integer; begin for i := lbCategories.Count - 1 downto 0 do lbCategories.Items.Objects[i].Free; lbCategories.Clear; end; procedure TfrmOptionsFileTypesColors.Init; begin lbCategories.Canvas.Font := lbCategories.Font; lbCategories.ItemHeight := lbCategories.Canvas.TextHeight('Wg'); end; class function TfrmOptionsFileTypesColors.GetIconIndex: Integer; begin Result := 21; end; class function TfrmOptionsFileTypesColors.GetTitle: String; begin Result := rsOptionsEditorFileTypes; end; function TfrmOptionsFileTypesColors.IsSignatureComputedFromAllWindowComponents: Boolean; begin Result := False; end; procedure TfrmOptionsFileTypesColors.Load; var I : Integer; MaskItem: TMaskItem; begin Clear; lbCategories.Color:= gColors.FilePanel^.BackColor; { File lbtypes category color } for I := 0 to gColorExt.Count - 1 do begin MaskItem := TMaskItem.Create; try MaskItem.Assign(gColorExt[I]); lbCategories.Items.AddObject(MaskItem.sName, MaskItem); except FreeAndNil(MaskItem); raise; end; end; // for if lbCategories.Count > 0 then lbCategories.ItemIndex := 0 else begin edtCategoryName.Enabled := False; edtCategoryMask.Enabled := False; edtCategoryAttr.Enabled := False; cbCategoryColor.Enabled := False; btnDeleteCategory.Enabled := False; btnApplyCategory.Enabled := False; end; lbCategoriesClick(lbCategories); end; function TfrmOptionsFileTypesColors.Save: TOptionsEditorSaveFlags; var i: Integer; MaskItem: TMaskItem; begin Result := []; gColorExt.Clear; for I := 0 to lbCategories.Count - 1 do //write new categories if Assigned(lbCategories.Items.Objects[I]) then begin MaskItem := TMaskItem.Create; try MaskItem.Assign(TMaskItem(lbCategories.Items.Objects[I])); gColorExt.Add(MaskItem); except FreeAndNil(MaskItem); raise; end; end; end; procedure TfrmOptionsFileTypesColors.CMThemeChanged(var Message: TLMessage); begin lbCategories.Color:= gColors.FilePanel^.BackColor; lbCategories.Repaint; end; destructor TfrmOptionsFileTypesColors.Destroy; begin Clear; inherited; end; end. ������������doublecmd-1.1.22/src/frames/foptionsfonts.lfm�������������������������������������������������������0000644�0001750�0000144�00000000673�14743153644�020273� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsFonts: TfrmOptionsFonts Height = 372 Hint = 'Fonts' Width = 601 HelpKeyword = '/configuration.html#ConfigFonts' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 2 DesignLeft = 804 DesignTop = 355 object dlgFnt: TFontDialog[0] MinFontSize = 0 MaxFontSize = 0 Options = [] left = 80 top = 40 end end ���������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfonts.lrj�������������������������������������������������������0000644�0001750�0000144�00000000202�14743153644�020270� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":5072307,"name":"tfrmoptionsfonts.hint","sourcebytes":[70,111,110,116,115],"value":"Fonts"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsfonts.pas�������������������������������������������������������0000644�0001750�0000144�00000021152�14743153644�020273� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Fonts options page Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFonts; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, StdCtrls, Spin, Dialogs, //DC fOptionsFrame, uGlobs; type { TVisualFontElements } TVisualFontElements = record FontEdit: TEdit; FontSpindEdit: TSpinEdit; end; { TSpinEdit } TSpinEdit = class(Spin.TSpinEdit) public function GetLimitedValue(const AValue: Double): Double; override; end; { TfrmOptionsFonts } TfrmOptionsFonts = class(TOptionsEditor) dlgFnt: TFontDialog; procedure edtFontExit(Sender: TObject); procedure edtMouseWheelDown(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var {%H-}Handled: boolean); procedure edtMouseWheelUp(Sender: TObject; Shift: TShiftState; {%H-}MousePos: TPoint; var {%H-}Handled: boolean); procedure edtFontSizeChange(Sender: TObject); procedure btnSelFontClick(Sender: TObject); private LocalVisualFontElements: array[0..pred(Length(TDCFontsOptions))] of TVisualFontElements; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Controls, //DC uLng; { TSpinEdit } function TSpinEdit.GetLimitedValue(const AValue: Double): Double; begin // Zero - default font size if (AValue = 0.0) then Exit(0); Result:= inherited GetLimitedValue(AValue); end; { TfrmOptionsFonts } { TfrmOptionsFonts.GetIconIndex } class function TfrmOptionsFonts.GetIconIndex: integer; begin Result := 3; end; { TfrmOptionsFonts.GetTitle } class function TfrmOptionsFonts.GetTitle: string; begin Result := rsOptionsEditorFonts; end; { TfrmOptionsFonts.Init } // We draw manually the whole thing from the gFont array instead of having designed the form at the conception time. // This way, we're sure to don't forget a font, for one, and second, if we ever add a font, no modification will be required here, in the configuration section. // ...or maybe just if the font has to be monospace. procedure TfrmOptionsFonts.Init; var ALabelFont: TLabel; AEditFont: TEdit; APreviousEditFont: TEdit = nil; ASpinEditFontSize: TSpinEdit; AButtonFont: TButton; iFontIndex: integer; begin for iFontIndex := 0 to pred(Length(TDCFontsOptions)) do begin ALabelFont := TLabel.Create(Self); ALabelFont.Parent := Self; ALabelFont.Caption := gFonts[TDCFont(iFontIndex)].Usage; AEditFont := TEdit.Create(Self); LocalVisualFontElements[iFontIndex].FontEdit := AEditFont; AEditFont.Parent := Self; AEditFont.Tag := iFontIndex; AEditFont.OnExit := @edtFontExit; AEditFont.OnMouseWheelDown := @edtMouseWheelDown; AEditFont.OnMouseWheelUp := @edtMouseWheelUp; AEditFont.Anchors := [akTop, akLeft, akRight]; ALabelFont.FocusControl := AEditFont; ASpinEditFontSize := TSpinEdit.Create(Self); LocalVisualFontElements[iFontIndex].FontSpindEdit := ASpinEditFontSize; ASpinEditFontSize.Tag := iFontIndex; ASpinEditFontSize.Parent := Self; ASpinEditFontSize.OnChange := @edtFontSizeChange; ASpinEditFontSize.MinValue := gFonts[TDCFont(iFontIndex)].MinValue; ASpinEditFontSize.MaxValue := gFonts[TDCFont(iFontIndex)].MaxValue; ASpinEditFontSize.Width := 55; ASpinEditFontSize.Anchors := [akTop, akRight]; AButtonFont := TButton.Create(Self); AButtonFont.Tag := iFontIndex; AButtonFont.Parent := Self;; AButtonFont.AutoSize := True; AButtonFont.Caption := '...'; AButtonFont.OnClick := @btnSelFontClick; AButtonFont.Anchors := [akTop, akRight]; ALabelFont.AnchorSideLeft.Control := Self; if APreviousEditFont <> nil then begin ALabelFont.AnchorSideTop.Control := APreviousEditFont; ALabelFont.AnchorSideTop.Side := asrBottom; ALabelFont.BorderSpacing.Top := 6; end else begin ALabelFont.AnchorSideTop.Control := Self; end; AEditFont.AnchorSideLeft.Control := ALabelFont; AEditFont.AnchorSideTop.Control := ALabelFont; AEditFont.AnchorSideTop.Side := asrBottom; AEditFont.AnchorSideRight.Control := ASpinEditFontSize; ASpinEditFontSize.AnchorSideTop.Control := AEditFont; ASpinEditFontSize.AnchorSideTop.Side := asrCenter; ASpinEditFontSize.AnchorSideRight.Control := AButtonFont; AButtonFont.AnchorSideTop.Control := AEditFont; AButtonFont.AnchorSideTop.Side := asrCenter; AButtonFont.AnchorSideRight.Control := Self; AButtonFont.AnchorSideRight.Side := asrBottom; AButtonFont.AnchorSideBottom.Side := asrBottom; APreviousEditFont := AEditFont; end; end; { TfrmOptionsFonts.Load } // The idea here is to take the general font style and apply them to TEdit in the page. // User plays with that to set the properties he wants. // Then at the end we recuperate the font from the TEdit's and store properties user set back to the general fonts. procedure TfrmOptionsFonts.Load; var iFontIndex: integer; begin for iFontIndex := 0 to pred(Length(TDCFontsOptions)) do begin LocalVisualFontElements[iFontIndex].FontEdit.Text := gFonts[TDCFont(iFontIndex)].Name; FontOptionsToFont(gFonts[TDCFont(iFontIndex)], LocalVisualFontElements[iFontIndex].FontEdit.Font); LocalVisualFontElements[iFontIndex].FontSpindEdit.Value := gFonts[TDCFont(iFontIndex)].Size; end; end; { TfrmOptionsFonts.Save } function TfrmOptionsFonts.Save: TOptionsEditorSaveFlags; var iFontIndex: integer; begin Result := []; for iFontIndex := 0 to pred(Length(TDCFontsOptions)) do FontToFontOptions(LocalVisualFontElements[iFontIndex].FontEdit.Font, gFonts[TDCFont(iFontIndex)]); end; { TfrmOptionsFonts.edtFontExit } procedure TfrmOptionsFonts.edtFontExit(Sender: TObject); begin TEdit(Sender).Font.Name := TEdit(Sender).Text; end; { TfrmOptionsFonts.edtMouseWheelDown } procedure TfrmOptionsFonts.edtMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: boolean); begin if (ssCtrl in Shift) and (LocalVisualFontElements[TEdit(Sender).Tag].FontSpindEdit.Value > gFonts[TDCFont(TEdit(Sender).Tag)].MinValue) then begin TEdit(Sender).Font.Size := TEdit(Sender).Font.Size - 1; LocalVisualFontElements[TEdit(Sender).Tag].FontSpindEdit.Value := TEdit(Sender).Font.Size; end; end; { TfrmOptionsFonts.edtMouseWheelUp } procedure TfrmOptionsFonts.edtMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: boolean); begin if (ssCtrl in Shift) and (LocalVisualFontElements[TEdit(Sender).Tag].FontSpindEdit.Value < gFonts[TDCFont(TEdit(Sender).Tag)].MaxValue) then begin TEdit(Sender).Font.Size := TEdit(Sender).Font.Size + 1; LocalVisualFontElements[TEdit(Sender).Tag].FontSpindEdit.Value := TEdit(Sender).Font.Size; end; end; { TfrmOptionsFonts.edtFontSizeChange } procedure TfrmOptionsFonts.edtFontSizeChange(Sender: TObject); begin if (LocalVisualFontElements[TSpinEdit(Sender).Tag].FontEdit.Font.Size <> TSpinEdit(Sender).Value) then LocalVisualFontElements[TSpinEdit(Sender).Tag].FontEdit.Font.Size := TSpinEdit(Sender).Value; end; { TfrmOptionsFonts.btnSelFontClick } procedure TfrmOptionsFonts.btnSelFontClick(Sender: TObject); const cMonoFonts = [dcfEditor, dcfViewer, dcfLog, dcfConsole]; begin begin dlgFnt.Font := LocalVisualFontElements[TButton(Sender).Tag].FontEdit.Font; if (TDCFont(TButton(Sender).Tag) in cMonoFonts) then dlgFnt.Options := dlgFnt.Options + [fdFixedPitchOnly, fdNoStyleSel] else dlgFnt.Options := dlgFnt.Options - [fdFixedPitchOnly, fdNoStyleSel]; if dlgFnt.Execute then begin LocalVisualFontElements[TButton(Sender).Tag].FontEdit.Font := dlgFnt.Font; LocalVisualFontElements[TButton(Sender).Tag].FontEdit.Text := dlgFnt.Font.Name; LocalVisualFontElements[TButton(Sender).Tag].FontSpindEdit.Value := dlgFnt.Font.Size; end; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsframe.lfm�������������������������������������������������������0000644�0001750�0000144�00000000277�14743153644�020234� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object OptionsEditor: TOptionsEditor Left = 0 Height = 240 Top = 0 Width = 320 HelpType = htKeyword LCLVersion = '1.4.4.0' TabOrder = 0 DesignLeft = 181 DesignTop = 138 end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsframe.pas�������������������������������������������������������0000644�0001750�0000144�00000031301�14743153644�020231� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Options frame page Copyright (C) 2006-2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsFrame; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, fgl; type TOptionsEditorInitFlag = (oeifLoad); TOptionsEditorInitFlags = set of TOptionsEditorInitFlag; TOptionsEditorSaveFlag = (oesfNeedsRestart); TOptionsEditorSaveFlags = set of TOptionsEditorSaveFlag; TOptionsEditor = class; TOptionsEditorClass = class of TOptionsEditor; TOptionsEditorClassList = class; { IOptionsDialog } {$interfaces corba} IOptionsDialog = interface ['{E62AAF5E-74ED-49AB-93F2-DBE210BF6723}'] procedure LoadSettings; function GetEditor(EditorClass: TOptionsEditorClass): TOptionsEditor; end; {$interfaces default} { TOptionsEditor } // Regarding warning to user when attempting to exit configuration window or "option editor" without having saved a modified setting: // 1o) Immediately after having load the options in "LoadSettings", we will compute a signature, // which is a CRC32 of the related settings and memorize it. // 2o) When will attempt to close options, we'll recalculate again this signature, if it is different, // we know user has change something and will prompt user to validate if he wants to save, discard or cancel quit. // 3o) For many option editors, signature may be computed simply by validating actual controls of the window like // checkboxes state, edit box, etc. // 4o) For others, we need to run specific computation like signature of list like hot directories list, favorites tabs list, etc. // 5o) For some computing the signature with controls should not be done. // 6o) Here is a list of function and procedure around that: // 7o) "IsSignatureComputedFromAllWindowComponents": Function that may be overloaded by specific option editor to indicate // if we may compute signature of controls of the editor or not. // By default, it is the case. // 8o) "ExtraOptionsSignature": Function that may overloaded by specifica option editor when signature must include extra element not present in controls of the editor like a list of structures, etc. // By default, nothing more is required. // 9o) "ComputeCompleteOptionsSignature": Will first compute signature based on controls >IF< "IsSignatureComputedFromAllWindowComponents" is not invalidated by specific option editor // Then will make progress that signature >IF< "ExtraOptionsSignature" has been overload by specific option editor. TOptionsEditor = class(TFrame) private FOptionsDialog: IOptionsDialog; FLastLoadedOptionSignature: dword; protected procedure Init; virtual; procedure Done; virtual; procedure Load; virtual; function Save: TOptionsEditorSaveFlags; virtual; property OptionsDialog: IOptionsDialog read FOptionsDialog; public property LastLoadedOptionSignature:dword read FLastLoadedOptionSignature write FLastLoadedOptionSignature; // Let it public so Options Forms will be able to know what was initial signature. destructor Destroy; override; class function GetIconIndex: Integer; virtual; abstract; class function GetTitle: String; virtual; abstract; class function IsEmpty: Boolean; virtual; function IsSignatureComputedFromAllWindowComponents: Boolean; virtual; function ComputeCompleteOptionsSignature: dword; function ExtraOptionsSignature(CurrentSignature:dword):dword; virtual; function CanWeClose(var SaveFlags:TOptionsEditorSaveFlags; bForceClose:boolean=false):boolean; virtual; procedure LoadSettings; function SaveSettings: TOptionsEditorSaveFlags; procedure Init(AParent: TWinControl; AOptionsDialog: IOptionsDialog; Flags: TOptionsEditorInitFlags); end; { TOptionsEditorRec } TOptionsEditorRec = class private FChildren: TOptionsEditorClassList; FEditorClass: TOptionsEditorClass; function GetChildren: TOptionsEditorClassList; public constructor Create; destructor Destroy; override; function Add(Editor: TOptionsEditorClass): TOptionsEditorRec; function HasChildren: Boolean; property Children: TOptionsEditorClassList read GetChildren; property EditorClass: TOptionsEditorClass read FEditorClass write FEditorClass; end; { TBaseOptionsEditorClassList } TBaseOptionsEditorClassList = specialize TFPGObjectList<TOptionsEditorRec>; { TOptionsEditorClassList } TOptionsEditorClassList = class(TBaseOptionsEditorClassList) public function Add(Editor: TOptionsEditorClass): TOptionsEditorRec; overload; end; var OptionsEditorClassList: TOptionsEditorClassList = nil; implementation uses uLng, uComponentsSignature, uShowMsg, fOptions, fOptionsArchivers, fOptionsAutoRefresh, fOptionsBehavior, fOptionsBriefView, fOptionsColumnsView, fOptionsConfiguration, fOptionsCustomColumns, fOptionsDragDrop, fOptionsDrivesListButton, fOptionsTreeViewMenu, fOptionsTreeViewMenuColor, fOptionsFileOperations, fOptionsFileSearch, fOptionsMultiRename, fOptionsFilePanelsColors, fOptionsFileTypesColors, fOptionsFilesViews, fOptionsFilesViewsComplement, fOptionsFonts, fOptionsGroups, fOptionsHotkeys, fOptionsIcons, fOptionsIgnoreList, fOptionsKeyboard, fOptionsLanguage, fOptionsLayout, fOptionsLog, fOptionsMisc, fOptionsMouse, fOptionsPluginsGroup, fOptionsPluginsDSX, fOptionsPluginsWCX, fOptionsPluginsWDX, fOptionsPluginsWFX, fOptionsPluginsWLX, fOptionsQuickSearchFilter, fOptionsTabs, fOptionsFavoriteTabs, fOptionsTabsExtra, fOptionsTerminal, fOptionsToolbar, fOptionsToolbarExtra, fOptionsToolbarMiddle, fOptionsTools, fOptionsToolsEditor, fOptionsToolsDiffer, fOptionsEditorColors, fOptionsToolTips, fOptionsFileAssoc, fOptionsFileAssocExtra, fOptionsDirectoryHotlist, fOptionsDirectoryHotlistExtra, fOptionsColors ; { TOptionsEditorRec } function TOptionsEditorRec.GetChildren: TOptionsEditorClassList; begin if not Assigned(FChildren) then FChildren := TOptionsEditorClassList.Create; Result := FChildren; end; constructor TOptionsEditorRec.Create; begin FChildren := nil; end; destructor TOptionsEditorRec.Destroy; begin inherited Destroy; FreeAndNil(FChildren); end; function TOptionsEditorRec.Add(Editor: TOptionsEditorClass): TOptionsEditorRec; begin Result := Children.Add(Editor); end; function TOptionsEditorRec.HasChildren: Boolean; begin Result := Assigned(FChildren) and (FChildren.Count > 0); end; { TOptionsEditorClassList } function TOptionsEditorClassList.Add(Editor: TOptionsEditorClass): TOptionsEditorRec; begin Result := TOptionsEditorRec.Create; Add(Result); Result.EditorClass:= Editor; end; { TOptionsEditor } procedure TOptionsEditor.Init; begin // Empty. end; { TOptionsEditor.ExtraOptionsSignature } function TOptionsEditor.ExtraOptionsSignature(CurrentSignature:dword):dword; begin result := CurrentSignature; end; { TOptionsEditor.ComputeCompleteOptionsSignature } function TOptionsEditor.ComputeCompleteOptionsSignature:dword; begin result := $000000; if IsSignatureComputedFromAllWindowComponents then result := ComputeSignatureBasedOnComponent(Self, result); result := ExtraOptionsSignature(result); end; { TOptionsEditor.CanWeClose } function TOptionsEditor.CanWeClose(var SaveFlags:TOptionsEditorSaveFlags; bForceClose:boolean=false):boolean; var Answer: TMyMsgResult; begin SaveFlags:=[]; if bForceClose then result:=True else result := (FLastLoadedOptionSignature = ComputeCompleteOptionsSignature); if (not result) OR bForceClose then begin if bForceClose then begin Answer:=mmrYes; end else begin ShowOptions(Self.ClassName); Answer := MsgBox(Format(rsOptionsEditorOptionsChanged, [GetTitle]), [msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); end; case Answer of mmrYes: begin SaveFlags := SaveSettings; result := True; end; mmrNo: result := True; else result := False; end; end; end; procedure TOptionsEditor.Done; begin // Empty. end; destructor TOptionsEditor.Destroy; begin Done; inherited Destroy; end; class function TOptionsEditor.IsEmpty: Boolean; begin Result := False; end; { TOptionsEditor.IsSignatureComputedFromAllWindowComponents } function TOptionsEditor.IsSignatureComputedFromAllWindowComponents: Boolean; begin Result := True; end; procedure TOptionsEditor.LoadSettings; begin DisableAutoSizing; try Load; FLastLoadedOptionSignature := ComputeCompleteOptionsSignature; finally EnableAutoSizing; end; end; function TOptionsEditor.SaveSettings: TOptionsEditorSaveFlags; begin Result := Save; FLastLoadedOptionSignature := ComputeCompleteOptionsSignature; end; procedure TOptionsEditor.Load; begin // Empty. end; function TOptionsEditor.Save: TOptionsEditorSaveFlags; begin Result := []; end; procedure TOptionsEditor.Init(AParent: TWinControl; AOptionsDialog: IOptionsDialog; Flags: TOptionsEditorInitFlags); begin DisableAutoSizing; try Parent := AParent; FOptionsDialog := AOptionsDialog; Init; if oeifLoad in Flags then LoadSettings; finally EnableAutoSizing; end; end; procedure MakeEditorsClassList; var Main: TOptionsEditorClassList absolute OptionsEditorClassList; Colors, ColumnsView, FilesViews, Keyboard, Layout, Mouse, Tools, Editor, FileAssoc, ToolbarConfig, FileOperation, FolderTabs, Plugins, DirectoryHotlistConfig: TOptionsEditorRec; begin Main.Add(TfrmOptionsLanguage); Main.Add(TfrmOptionsBehavior); Tools := Main.Add(TOptionsToolsGroup); Tools.Add(TfrmOptionsViewer); Editor:= Tools.Add(TfrmOptionsEditor); Editor.Add(TfrmOptionsEditorColors); Tools.Add(TfrmOptionsDiffer); Tools.Add(TfrmOptionsTerminal); Main.Add(TfrmOptionsFonts); Colors := Main.Add(TfrmOptionsColors); Colors.Add(TfrmOptionsFilePanelsColors); Colors.Add(TfrmOptionsFileTypesColors); Keyboard := Main.Add(TfrmOptionsKeyboard); Keyboard.Add(TfrmOptionsHotkeys); Mouse := Main.Add(TfrmOptionsMouse); Mouse.Add(TfrmOptionsDragDrop); FilesViews := Main.Add(TfrmOptionsFilesViews); FilesViews.Add(TfrmOptionsFilesViewsComplement); FilesViews.Add(TfrmOptionsBriefView); ColumnsView := FilesViews.Add(TfrmOptionsColumnsView); ColumnsView.Add(TfrmOptionsCustomColumns); Plugins := Main.Add(TfrmOptionsPluginsGroup); Plugins.Add(TfrmOptionsPluginsDSX); Plugins.Add(TfrmOptionsPluginsWCX); Plugins.Add(TfrmOptionsPluginsWDX); Plugins.Add(TfrmOptionsPluginsWFX); Plugins.Add(TfrmOptionsPluginsWLX); Layout := Main.Add(TfrmOptionsLayout); Layout.Add(TfrmOptionsDrivesListButton); Layout.Add(TfrmOptionsTreeViewMenu); Layout.Add(TfrmOptionsTreeViewMenuColor); ToolbarConfig := Main.Add(TfrmOptionsToolbar); ToolbarConfig.Add(TfrmOptionsToolbarMiddle); ToolbarConfig.Add(TfrmOptionsToolbarExtra); FileOperation := Main.Add(TfrmOptionsFileOperations); FileOperation.Add(TfrmOptionsFileSearch); FileOperation.Add(TfrmOptionsMultiRename); FolderTabs := Main.Add(TfrmOptionsTabs); FolderTabs.Add(TfrmOptionsFavoriteTabs); FolderTabs.Add(TfrmOptionsTabsExtra); Main.Add(TfrmOptionsLog); Main.Add(TfrmOptionsConfiguration); Main.Add(TfrmOptionsQuickSearchFilter); Main.Add(TfrmOptionsMisc); Main.Add(TfrmOptionsAutoRefresh); Main.Add(TfrmOptionsIcons); Main.Add(TfrmOptionsIgnoreList); Main.Add(TfrmOptionsArchivers); Main.Add(TfrmOptionsToolTips); FileAssoc := Main.Add(TfrmOptionsFileAssoc); FileAssoc.Add(TfrmOptionsFileAssocExtra); DirectoryHotlistConfig := Main.Add(TfrmOptionsDirectoryHotlist); DirectoryHotlistConfig.Add(TfrmOptionsDirectoryHotlistExtra); end; initialization OptionsEditorClassList:= TOptionsEditorClassList.Create; MakeEditorsClassList; finalization if Assigned(OptionsEditorClassList) then FreeAndNil(OptionsEditorClassList); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsgroups.pas������������������������������������������������������0000644�0001750�0000144�00000003173�14743153644�020464� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Options groups Copyright (C) 2006-2023 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsGroups; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, fOptionsFrame; type { TOptionsGroup } TOptionsGroup = class(TOptionsEditor) public class function IsEmpty: Boolean; override; end; { TOptionsToolsGroup } TOptionsToolsGroup = class(TOptionsGroup) public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation uses uLng; { TOptionsGroup } class function TOptionsGroup.IsEmpty: Boolean; begin Result := True; end; { TOptionsToolsGroup } class function TOptionsToolsGroup.GetIconIndex: Integer; begin Result := 2; end; class function TOptionsToolsGroup.GetTitle: String; begin Result := rsOptionsEditorTools; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionshotkeys.lfm�����������������������������������������������������0000644�0001750�0000144�00000033311�14743153644�020623� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsHotkeys: TfrmOptionsHotkeys Height = 513 Width = 808 HelpKeyword = '/configuration.html#ConfigHotKeys' ClientHeight = 513 ClientWidth = 808 ParentShowHint = False PopupMenu = pmShortcutMenu ShowHint = True DesignLeft = 451 DesignTop = 209 object lblCategories: TLabel[0] AnchorSideLeft.Control = lbxCategories AnchorSideTop.Control = Owner Left = 299 Height = 15 Top = 6 Width = 59 BorderSpacing.Top = 6 Caption = 'C&ategories:' FocusControl = lbxCategories ParentColor = False end object lbFilter: TLabel[1] AnchorSideLeft.Control = lbSCFilesList AnchorSideTop.Control = lbxCategories AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtFilter Left = 6 Height = 15 Top = 50 Width = 26 BorderSpacing.Top = 6 Caption = '&Filter' FocusControl = edtFilter ParentColor = False end object lbxCategories: TComboBox[2] AnchorSideLeft.Control = btnFileAction AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblCategories AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 299 Height = 23 Top = 21 Width = 503 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Right = 6 ItemHeight = 15 Style = csDropDownList TabOrder = 1 OnChange = lbxCategoriesChange end object edtFilter: TEdit[3] AnchorSideLeft.Control = lbSCFilesList AnchorSideTop.Control = lbFilter AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnFileAction AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 65 Width = 283 Anchors = [akTop, akLeft, akRight] BorderSpacing.Bottom = 4 TabOrder = 2 OnChange = edtFilterChange end object stgCommands: TStringGrid[4] AnchorSideLeft.Control = lbSCFilesList AnchorSideTop.Control = lblCommands AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 261 Top = 107 Width = 796 Anchors = [akTop, akLeft, akRight, akBottom] AutoFillColumns = True BorderSpacing.Right = 6 ColCount = 3 Columns = < item SizePriority = 0 Title.Caption = 'Command' Width = 265 end item SizePriority = 0 Title.Caption = 'Hotkeys' Width = 264 end item Title.Caption = 'Description' Width = 263 end> Constraints.MinHeight = 200 Constraints.MinWidth = 200 ExtendedSelect = False FixedCols = 0 MouseWheelOption = mwGrid Options = [goVertLine, goColSizing, goColMoving, goRowSelect, goThumbTracking, goDblClickAutoSize, goSmoothScroll] RowCount = 1 TabOrder = 4 TitleStyle = tsNative OnCompareCells = stgCommandsCompareCells OnDblClick = stgCommandsDblClick OnHeaderClick = stgCommandsHeaderClick OnPrepareCanvas = stgCommandsPrepareCanvas OnResize = stgCommandsResize OnSelectCell = stgCommandsSelectCell ColWidths = ( 265 264 263 ) end object stgHotkeys: TStringGrid[5] AnchorSideLeft.Control = stgCommands AnchorSideTop.Control = stgCommands AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlHotkeyButtons AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 137 Top = 372 Width = 682 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 4 BorderSpacing.Right = 8 BorderSpacing.Bottom = 4 ColCount = 3 Columns = < item Title.Caption = 'Hotkey' Width = 119 end item Title.Caption = 'Parameters' Width = 119 end item Title.Caption = 'Controls' Width = 120 end> Constraints.MinHeight = 100 Constraints.MinWidth = 100 FixedCols = 0 MouseWheelOption = mwGrid Options = [goFixedVertLine, goFixedHorzLine, goColSizing, goColMoving, goRowSelect, goThumbTracking, goDblClickAutoSize, goSmoothScroll] RowCount = 3 ScrollBars = ssAutoVertical TabOrder = 5 TitleStyle = tsNative OnDblClick = stgHotkeysDblClick OnKeyDown = stgHotkeysKeyDown OnResize = stgHotkeysResize OnSelectCell = stgHotkeysSelectCell ColWidths = ( 119 119 120 ) end object pnlHotkeyButtons: TPanel[6] AnchorSideTop.Control = stgHotkeys AnchorSideRight.Control = stgCommands AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = stgHotkeys AnchorSideBottom.Side = asrBottom Left = 696 Height = 137 Top = 372 Width = 106 Anchors = [akTop, akRight, akBottom] AutoSize = True BevelOuter = bvNone ChildSizing.VerticalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.ShrinkVertical = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 137 ClientWidth = 106 TabOrder = 6 object btnAddHotKey: TButton AnchorSideRight.Side = asrBottom Left = 0 Height = 42 Top = 0 Width = 106 Action = actAddHotKey AutoSize = True BorderSpacing.InnerBorder = 4 TabOrder = 0 end object btnEditHotkey: TButton Left = 0 Height = 42 Top = 48 Width = 106 Action = actEditHotKey AutoSize = True BorderSpacing.InnerBorder = 4 TabOrder = 1 end object btnDeleteHotKey: TButton AnchorSideRight.Side = asrBottom Left = 0 Height = 41 Top = 96 Width = 106 Action = actDeleteHotKey AutoSize = True BorderSpacing.InnerBorder = 4 TabOrder = 2 end end object lbSCFilesList: TComboBox[7] AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblSCFiles AnchorSideTop.Side = asrBottom Left = 6 Height = 23 Top = 21 Width = 258 BorderSpacing.Left = 6 ItemHeight = 15 Style = csDropDownList TabOrder = 0 OnChange = lbSCFilesListChange end object lblSCFiles: TLabel[8] AnchorSideLeft.Control = lbSCFilesList AnchorSideTop.Control = Owner Left = 6 Height = 15 Top = 6 Width = 72 BorderSpacing.Top = 6 Caption = '&Shortcut files:' FocusControl = lbSCFilesList ParentColor = False end object btnFileAction: TSpeedButton[9] AnchorSideLeft.Control = lbSCFilesList AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbSCFilesList AnchorSideTop.Side = asrCenter AnchorSideBottom.Control = lbSCFilesList AnchorSideBottom.Side = asrBottom Left = 266 Height = 23 Top = 21 Width = 23 Action = actPopupFileRelatedMenu BorderSpacing.Left = 2 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000300000 0033000000330000003300000033000000330000003300000033000000330000 00330000003300000033000000330000003300000033000000239E9688F29E96 88FF9D9587FF9D9587FF9D9487FF9D9486FF9D9486FF9D9486FF9D9486FF9D94 86FF9D9486FF9D9487FF9D9587FF9D9587FF9E9688FF938B7FC09E9688FFCAC5 C2FFC7C2BEFFC7C2BEFFC6C1BDFFC5C0BCFFC5C0BBFFC5C0BBFFC5C0BBFFC5C0 BBFFC5C0BCFFC6C1BDFFC7C2BEFFC7C2BEFFCAC5C2FF9E9688FF9D9487FFC9C6 C1FFF6F8FAFFAFA89DFFF5F6F9FFF3F4F6FFF3F4F6FFF3F4F6FFF3F4F6FFF3F4 F6FFF3F4F6FFF5F6F8FFAFA89DFFF6F8FAFFC9C6C1FF9D9487FF9D9487FFCDCA C4FFAAA497FFACA598FFACA599FFAAA497FFABA498FFAAA497FFABA498FFAAA4 97FFABA498FFAAA497FFAAA397FFAAA396FFCDC9C4FF9D9487FF9C9486FFCFCD C6FFF5F6F9FFF7F8FAFFA9A296FFF8FAFDFFA9A396FFF8FAFDFFA9A396FFF8FA FDFFA9A296FFF6F7FAFFF3F4F6FFF2F3F5FFCECBC4FF9C9486FF9C9486FFD3D2 CBFFA49C8EFFA69E91FFA7A092FFA7A092FFA7A092FFA7A092FFA7A092FFA7A0 92FFA7A092FFA59E90FFA2998BFFF1F2F4FFD1D0C8FF9C9386FF9C9386FFD6D5 CDFFF6F7FAFFA1998CFFF8FAFDFFA29A8DFFF8FAFDFFA29A8DFFF8FAFDFFA29A 8DFFF8FAFDFFA1998CFFF5F6F9FFDDD9D7FFD5D4CBFF9C9386FF9C9386FFDADA D1FFB6B0A4FFB8B1A6FFB8B1A5FFB8B2A6FFB8B1A5FFB8B2A6FFB8B1A5FFB8B2 A6FFB8B1A5FFB8B1A6FFB6B0A4FFB6AFA3FFDADAD1FF9C9386FF9D9487FFDFE1 D7FFDDDED4FFDDDED4FFDDDED5FFDDDED5FFDDDED5FFDDDED5FFDDDED5FFDDDE D5FFDDDED5FFDDDED5FFDDDED4FFDDDED4FFDFE1D7FF9D9487FF9F978AB09D95 87FF9C9386FF9C9386FF9C9386FF9C9386FF9C9386FF9C9386FF9C9386FF9C93 86FF9C9386FF9C9386FF9C9386FF9C9386FF9D9587FF9F978AB0A1998C00A098 8B00A0988B00A0988BFF0000003300000024A0988B00A0988B00A0988B00A098 8B00A0988B00A0988B00A0988B00A0988B00A0988B00A1998C00A1998C00A199 8C00A1998C00A1998CB5A1998CFF948D81C4A1998C00A1998C00A1998C00A199 8C00A1998C00A1998C00A1998C00A1998C00A1998C00A1998C00A1998C00A199 8C00A1998C00A1998C00A1998C00A1998CFFA1998C00A1998C00A1998C00A199 8C00A1998C00A1998C00A1998C00A1998C00A1998C00A1998C00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } end object lblSortOrder: TLabel[10] AnchorSideLeft.Control = lbxCategories AnchorSideTop.Control = lbxCategories AnchorSideTop.Side = asrBottom Left = 299 Height = 15 Top = 50 Width = 55 BorderSpacing.Top = 6 Caption = 'So&rt order:' FocusControl = cbCommandSortOrder ParentColor = False end object cbCommandSortOrder: TComboBox[11] AnchorSideLeft.Control = lbxCategories AnchorSideTop.Control = lblSortOrder AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lbxCategories AnchorSideRight.Side = asrBottom Left = 299 Height = 23 Top = 65 Width = 503 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 Style = csDropDownList TabOrder = 3 OnChange = cbCommandSortOrderChange end object lblCommands: TLabel[12] AnchorSideLeft.Control = lbSCFilesList AnchorSideTop.Control = edtFilter AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 92 Width = 65 Caption = 'Co&mmands:' FocusControl = stgCommands ParentColor = False end object alMainActionList: TActionList[13] Left = 680 Top = 240 object actSaveNow: TAction Caption = 'Save now' OnExecute = actSaveNowExecute ShortCut = 16467 end object actRename: TAction Tag = 1 Caption = 'Rename' OnExecute = actRenameExecute ShortCut = 8309 end object actCopy: TAction Caption = 'Copy' OnExecute = actCopyExecute ShortCut = 116 end object actDelete: TAction Caption = 'Delete' OnExecute = actDeleteExecute ShortCut = 119 end object actRestoreDefault: TAction Caption = 'Restore DC default' OnExecute = actRestoreDefaultExecute ShortCut = 24658 end object actAddHotKey: TAction Caption = 'Add &hotkey' OnExecute = actAddHotKeyExecute ShortCut = 118 end object actEditHotKey: TAction Caption = '&Edit hotkey' OnExecute = actEditHotKeyExecute ShortCut = 115 end object actDeleteHotKey: TAction Caption = '&Delete hotkey' OnExecute = actDeleteHotKeyExecute ShortCut = 46 end object actPreviousCategory: TAction Caption = 'Previous category' OnExecute = actPreviousCategoryExecute ShortCut = 109 end object actNextCategory: TAction Caption = 'Next category' OnExecute = actNextCategoryExecute ShortCut = 107 end object actSortByCommand: TAction Caption = 'Sort by command name' OnExecute = actAdjustSortOrderExecute ShortCut = 16498 end object actSortByHotKeysGrouped: TAction Tag = 1 Caption = 'Sort by hotkeys (grouped)' OnExecute = actAdjustSortOrderExecute ShortCut = 16499 end object actSortByHotKeysOnePerLine: TAction Tag = 2 Caption = 'Sort by hotkeys (one per row)' OnExecute = actAdjustSortOrderExecute ShortCut = 16500 end object actPopupFileRelatedMenu: TAction Caption = 'Make popup the file related menu' OnExecute = actPopupFileRelatedMenuExecute ShortCut = 120 end end object pmShortcutMenu: TPopupMenu[14] Left = 328 Top = 216 object miSaveNow: TMenuItem Action = actSaveNow end object miRename: TMenuItem Action = actRename end object miCopy: TMenuItem Action = actCopy end object miDelete: TMenuItem Action = actDelete end object miRestoreDefault: TMenuItem Action = actRestoreDefault end object miSeparator1: TMenuItem Caption = '-' end object miCategories: TMenuItem Caption = 'Categories' object miPreviousCategory: TMenuItem Action = actPreviousCategory end object miNextCategory: TMenuItem Action = actNextCategory end end object miSortOrder: TMenuItem Caption = 'Sort order' object miSortByCommand: TMenuItem Action = actSortByCommand end object miSortByHotKeysGrouped: TMenuItem Action = actSortByHotKeysGrouped end object miSortByHotKeysOnePerLine: TMenuItem Action = actSortByHotKeysOnePerLine end end object miCommands: TMenuItem Caption = 'Command' object miAddHotKey: TMenuItem Action = actAddHotKey end object miEditHotKey: TMenuItem Action = actEditHotKey end object miDeleteHotKey: TMenuItem Action = actDeleteHotKey end end end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionshotkeys.lrj�����������������������������������������������������0000644�0001750�0000144�00000010631�14743153644�020634� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":171210458,"name":"tfrmoptionshotkeys.lblcategories.caption","sourcebytes":[67,38,97,116,101,103,111,114,105,101,115,58],"value":"C&ategories:"}, {"hash":181418722,"name":"tfrmoptionshotkeys.lbfilter.caption","sourcebytes":[38,70,105,108,116,101,114],"value":"&Filter"}, {"hash":174340100,"name":"tfrmoptionshotkeys.stgcommands.columns[0].title.caption","sourcebytes":[67,111,109,109,97,110,100],"value":"Command"}, {"hash":258678083,"name":"tfrmoptionshotkeys.stgcommands.columns[1].title.caption","sourcebytes":[72,111,116,107,101,121,115],"value":"Hotkeys"}, {"hash":156067838,"name":"tfrmoptionshotkeys.stgcommands.columns[2].title.caption","sourcebytes":[68,101,115,99,114,105,112,116,105,111,110],"value":"Description"}, {"hash":83276233,"name":"tfrmoptionshotkeys.stghotkeys.columns[0].title.caption","sourcebytes":[72,111,116,107,101,121],"value":"Hotkey"}, {"hash":138003475,"name":"tfrmoptionshotkeys.stghotkeys.columns[1].title.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115],"value":"Parameters"}, {"hash":106664595,"name":"tfrmoptionshotkeys.stghotkeys.columns[2].title.caption","sourcebytes":[67,111,110,116,114,111,108,115],"value":"Controls"}, {"hash":5782010,"name":"tfrmoptionshotkeys.lblscfiles.caption","sourcebytes":[38,83,104,111,114,116,99,117,116,32,102,105,108,101,115,58],"value":"&Shortcut files:"}, {"hash":80311610,"name":"tfrmoptionshotkeys.lblsortorder.caption","sourcebytes":[83,111,38,114,116,32,111,114,100,101,114,58],"value":"So&rt order:"}, {"hash":70576826,"name":"tfrmoptionshotkeys.lblcommands.caption","sourcebytes":[67,111,38,109,109,97,110,100,115,58],"value":"Co&mmands:"}, {"hash":147288823,"name":"tfrmoptionshotkeys.actsavenow.caption","sourcebytes":[83,97,118,101,32,110,111,119],"value":"Save now"}, {"hash":93079605,"name":"tfrmoptionshotkeys.actrename.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, {"hash":304761,"name":"tfrmoptionshotkeys.actcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, {"hash":78392485,"name":"tfrmoptionshotkeys.actdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":121939508,"name":"tfrmoptionshotkeys.actrestoredefault.caption","sourcebytes":[82,101,115,116,111,114,101,32,68,67,32,100,101,102,97,117,108,116],"value":"Restore DC default"}, {"hash":212932585,"name":"tfrmoptionshotkeys.actaddhotkey.caption","sourcebytes":[65,100,100,32,38,104,111,116,107,101,121],"value":"Add &hotkey"}, {"hash":73212329,"name":"tfrmoptionshotkeys.actedithotkey.caption","sourcebytes":[38,69,100,105,116,32,104,111,116,107,101,121],"value":"&Edit hotkey"}, {"hash":204765465,"name":"tfrmoptionshotkeys.actdeletehotkey.caption","sourcebytes":[38,68,101,108,101,116,101,32,104,111,116,107,101,121],"value":"&Delete hotkey"}, {"hash":143662297,"name":"tfrmoptionshotkeys.actpreviouscategory.caption","sourcebytes":[80,114,101,118,105,111,117,115,32,99,97,116,101,103,111,114,121],"value":"Previous category"}, {"hash":207929433,"name":"tfrmoptionshotkeys.actnextcategory.caption","sourcebytes":[78,101,120,116,32,99,97,116,101,103,111,114,121],"value":"Next category"}, {"hash":74656069,"name":"tfrmoptionshotkeys.actsortbycommand.caption","sourcebytes":[83,111,114,116,32,98,121,32,99,111,109,109,97,110,100,32,110,97,109,101],"value":"Sort by command name"}, {"hash":123816025,"name":"tfrmoptionshotkeys.actsortbyhotkeysgrouped.caption","sourcebytes":[83,111,114,116,32,98,121,32,104,111,116,107,101,121,115,32,40,103,114,111,117,112,101,100,41],"value":"Sort by hotkeys (grouped)"}, {"hash":148770009,"name":"tfrmoptionshotkeys.actsortbyhotkeysoneperline.caption","sourcebytes":[83,111,114,116,32,98,121,32,104,111,116,107,101,121,115,32,40,111,110,101,32,112,101,114,32,114,111,119,41],"value":"Sort by hotkeys (one per row)"}, {"hash":72687669,"name":"tfrmoptionshotkeys.actpopupfilerelatedmenu.caption","sourcebytes":[77,97,107,101,32,112,111,112,117,112,32,116,104,101,32,102,105,108,101,32,114,101,108,97,116,101,100,32,109,101,110,117],"value":"Make popup the file related menu"}, {"hash":199366499,"name":"tfrmoptionshotkeys.micategories.caption","sourcebytes":[67,97,116,101,103,111,114,105,101,115],"value":"Categories"}, {"hash":108211282,"name":"tfrmoptionshotkeys.misortorder.caption","sourcebytes":[83,111,114,116,32,111,114,100,101,114],"value":"Sort order"}, {"hash":174340100,"name":"tfrmoptionshotkeys.micommands.caption","sourcebytes":[67,111,109,109,97,110,100],"value":"Command"} ]} �������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionshotkeys.pas�����������������������������������������������������0000644�0001750�0000144�00000143024�14743153644�020633� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Hotkeys options page Copyright (C) 2006-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsHotkeys; {$mode objfpc}{$H+} interface uses Classes, SysUtils, ExtCtrls, StdCtrls, Grids, fOptionsFrame, fOptionsHotkeysEditHotkey, uHotkeyManager, DCBasicTypes, Controls, Buttons, Menus, ActnList, uGlobs; type { TfrmOptionsHotkeys } TfrmOptionsHotkeys = class(TOptionsEditor) btnDeleteHotKey: TButton; btnAddHotKey: TButton; btnEditHotkey: TButton; edtFilter: TEdit; lblCommands: TLabel; lbFilter: TLabel; lblSCFiles: TLabel; lblCategories: TLabel; lbSCFilesList: TComboBox; lbxCategories: TComboBox; pnlHotkeyButtons: TPanel; stgCommands: TStringGrid; stgHotkeys: TStringGrid; btnFileAction: TSpeedButton; lblSortOrder: TLabel; cbCommandSortOrder: TComboBox; alMainActionList: TActionList; actAddHotKey: TAction; actEditHotKey: TAction; actDeleteHotKey: TAction; actPopupFileRelatedMenu: TAction; actSortByCommand: TAction; actSortByHotKeysGrouped: TAction; actSortByHotKeysOnePerLine: TAction; actPreviousCategory: TAction; actNextCategory: TAction; pmShortcutMenu: TPopupMenu; actSaveNow: TAction; actRename: TAction; actCopy: TAction; actDelete: TAction; actRestoreDefault: TAction; miSaveNow: TMenuItem; miCopy: TMenuItem; miRename: TMenuItem; miDelete: TMenuItem; miRestoreDefault: TMenuItem; miSeparator1: TMenuItem; miCategories: TMenuItem; miPreviousCategory: TMenuItem; miNextCategory: TMenuItem; miSortOrder: TMenuItem; miSortByCommand: TMenuItem; miSortByHotKeysOnePerLine: TMenuItem; miSortByHotKeysGrouped: TMenuItem; miCommands: TMenuItem; miAddHotKey: TMenuItem; miEditHotKey: TMenuItem; miDeleteHotKey: TMenuItem; procedure actRenameExecute(Sender: TObject); procedure edtFilterChange(Sender: TObject); procedure lbSCFilesListChange(Sender: TObject); procedure lbxCategoriesChange(Sender: TObject); procedure stgCommandsDblClick(Sender: TObject); procedure stgCommandsPrepareCanvas(Sender: TObject; aCol, aRow: Integer; aState: TGridDrawState); procedure stgCommandsResize(Sender: TObject); procedure stgCommandsSelectCell(Sender: TObject; {%H-}aCol, aRow: integer; var {%H-}CanSelect: boolean); procedure stgHotkeysDblClick(Sender: TObject); procedure stgHotkeysKeyDown(Sender: TObject; var Key: word; {%H-}Shift: TShiftState); procedure stgHotkeysResize(Sender: TObject); procedure stgHotkeysSelectCell(Sender: TObject; {%H-}aCol, aRow: integer; var {%H-}CanSelect: boolean); procedure stgCommandsCompareCells(Sender: TObject; ACol, ARow, BCol, BRow: integer; var Result: integer); procedure stgCommandsHeaderClick(Sender: TObject; IsColumn: boolean; Index: integer); procedure cbCommandSortOrderChange(Sender: TObject); function isOkToContinueRegardingModifiedOrNot: boolean; function GetANewSetupName(var ASetupName: string): boolean; procedure actAddHotKeyExecute(Sender: TObject); procedure actCopyExecute(Sender: TObject); procedure actDeleteExecute(Sender: TObject); procedure actDeleteHotKeyExecute(Sender: TObject); procedure actEditHotKeyExecute(Sender: TObject); procedure actNextCategoryExecute(Sender: TObject); procedure actPopupFileRelatedMenuExecute(Sender: TObject); procedure actPreviousCategoryExecute(Sender: TObject); procedure actRestoreDefaultExecute(Sender: TObject); procedure actSaveNowExecute(Sender: TObject); procedure actAdjustSortOrderExecute(Sender: TObject); private FEditForm: TfrmEditHotkey; FHotkeysAutoColWidths: array of integer; FHotkeysAutoGridWidth: integer; FHotkeysCategories: TStringList; // Untranslated FUpdatingShortcutsFiles: boolean; FModified: boolean; procedure AutoSizeCommandsGrid; procedure AutoSizeHotkeysGrid; procedure ClearHotkeysGrid; procedure DeleteHotkeyFromGrid(aHotkey: string); function GetSelectedCommand: string; {en Refreshes all hotkeys from the Commands grid } procedure UpdateHotkeys(HMForm: THMForm); procedure UpdateHotkeysForCommand(HMForm: THMForm; RowNr: integer); procedure FillSCFilesList; {en Return hotkeys assigned for command for the form and its controls. } procedure GetHotKeyList(HMForm: THMForm; Command: string; HotkeysList: THotkeys); {en Fill hotkey grid with all hotkeys assigned to a command } procedure FillHotkeyList(sCommand: string); {en Fill Commands grid with all commands available for the selected category. @param(Filter If not empty string then shows only commands containing Filter string.) } procedure FillCommandList(Filter: string); procedure FillCategoriesList; {en Retrieves untranslated form name. } function GetSelectedForm: string; procedure SelectHotkey(Hotkey: THotkey); procedure ShowEditHotkeyForm(EditMode: boolean; aHotkeyRow: integer); procedure ShowEditHotkeyForm(EditMode: boolean; const AForm: string; const ACommand: string; const AHotkey: THotkey; const AControls: TDynamicStringArray); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure AddDeleteWithShiftHotkey(UseTrash: boolean); class function GetIconIndex: integer; override; class function GetTitle: string; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; procedure DeleteHotkey; procedure DeleteAllHotkeys; procedure TryToSelectThatCategory(sCategory: string); end; function GetSortableShortcutName(sToSort: string): string; implementation {$R *.lfm} uses fMain, Graphics, Forms, LCLType, Dialogs, LazUTF8, LCLVersion, uFindEx, uGlobsPaths, uLng, uKeyboard, uFormCommands, DCStrUtils, DCOSUtils, uShowMsg; const stgCmdCommandIndex = 0; stgCmdHotkeysIndex = 1; stgCmdDescriptionIndex = 2; type PHotkeyItem = ^THotkeyItem; THotkeyItem = record Hotkey: THotkey; Controls: TDynamicStringArray; end; procedure DestroyHotkeyItem(HotkeyItem: PHotkeyItem); begin if Assigned(HotkeyItem) then begin HotkeyItem^.Hotkey.Free; Dispose(HotkeyItem); end; end; { MyStrcompare } // Used to help "HotkeysToString" function to have the returned shortcut strings // sorted in such way that "Fx" are first, "ALT-Fx" second, etc. when there are // more than one shortcut per command. function MyStrcompare(List: TStringList; Index1, Index2: integer): integer; begin Result := CompareText(GetSortableShortcutName(List.Strings[Index1]), GetSortableShortcutName(List.Strings[Index2])); end; { HotkeysToString } // Converts hotkeys list to string. function HotkeysToString(const Hotkeys: THotkeys): string; var sCurrent: string; i: integer; sList: TStringList; begin Result := ''; sList := TStringList.Create; try sList.CaseSensitive := True; for i := 0 to Hotkeys.Count - 1 do begin sCurrent := ShortcutsToText(Hotkeys[i].Shortcuts); if sList.IndexOf(sCurrent) < 0 then sList.Add(sCurrent); end; sList.CustomSort(@MyStrcompare); for i := 0 to pred(sList.Count) do AddStrWithSep(Result, sList.Strings[i], ';'); finally sList.Free; end; end; function CompareCategories(List: TStringList; Index1, Index2: integer): integer; begin {$IF LCL_FULLVERSION >= 093100} Result := UTF8CompareText(List.Strings[Index1], List.Strings[Index2]); {$ELSE} Result := WideCompareText(CeUtf8ToUtf16(List.Strings[Index1]), CeUtf8ToUtf16(List.Strings[Index2])); {$ENDIF} end; { TfrmOptionsHotkeys } { TfrmOptionsHotkeys.edtFilterChange } procedure TfrmOptionsHotkeys.edtFilterChange(Sender: TObject); {< filtering active commands list} begin if lbxCategories.ItemIndex = -1 then Exit; FillCommandList(edtFilter.Text); end; { TfrmOptionsHotkeys.lbSCFilesListChange } procedure TfrmOptionsHotkeys.lbSCFilesListChange(Sender: TObject); begin if not FUpdatingShortcutsFiles then begin if not isOkToContinueRegardingModifiedOrNot then begin if gNameSCFile <> lbSCFilesList.Items[lbSCFilesList.ItemIndex] then lbSCFilesList.ItemIndex := lbSCFilesList.Items.indexof(gNameSCFile); end else begin if (lbSCFilesList.ItemIndex >= 0) then begin gNameSCFile := lbSCFilesList.Items[lbSCFilesList.ItemIndex]; HotMan.Load(gpCfgDir + gNameSCFile); FModified := False; FillCategoriesList; lbxCategoriesChange(lbxCategories); end; end; end; end; { TfrmOptionsHotkeys.lbxCategoriesChange } procedure TfrmOptionsHotkeys.lbxCategoriesChange(Sender: TObject); begin if lbxCategories.ItemIndex = -1 then Exit; edtFilter.Clear; FillCommandList(''); end; { TfrmOptionsHotkeys.stgCommandsDblClick } procedure TfrmOptionsHotkeys.stgCommandsDblClick(Sender: TObject); begin // add hot key ShowEditHotkeyForm(False, GetSelectedForm, GetSelectedCommand, nil, nil); end; procedure TfrmOptionsHotkeys.stgCommandsPrepareCanvas(Sender: TObject; aCol, aRow: Integer; aState: TGridDrawState); begin if (aCol = stgCmdHotkeysIndex) and (aRow > 0) then begin with Sender as TStringGrid do begin if Cells[aCol, aRow] <> '' then begin if not (gdSelected in aState) then begin Canvas.Font.Color := clRed; end end; end; end; end; { TfrmOptionsHotkeys.stgCommandsResize } procedure TfrmOptionsHotkeys.stgCommandsResize(Sender: TObject); begin AutoSizeCommandsGrid; end; { TfrmOptionsHotkeys.stgCommandsSelectCell } procedure TfrmOptionsHotkeys.stgCommandsSelectCell(Sender: TObject; aCol, aRow: integer; var CanSelect: boolean); // < find hotkeys for command var sCommand: string; begin // clears all controls actAddHotKey.Enabled := False; actEditHotkey.Enabled := False; actDeleteHotKey.Enabled := False; ClearHotkeysGrid; if aRow >= stgCommands.FixedRows then begin sCommand := stgCommands.Cells[stgCmdCommandIndex, aRow]; FillHotkeyList(sCommand); actAddHotKey.Enabled := True; end; end; { TfrmOptionsHotkeys.stgHotkeysDblClick } procedure TfrmOptionsHotkeys.stgHotkeysDblClick(Sender: TObject); begin ShowEditHotkeyForm(True, stgHotkeys.Row); end; { TfrmOptionsHotkeys.stgHotkeysKeyDown } procedure TfrmOptionsHotkeys.stgHotkeysKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin if Key = VK_DELETE then DeleteHotkey; end; { TfrmOptionsHotkeys.stgHotkeysResize } procedure TfrmOptionsHotkeys.stgHotkeysResize(Sender: TObject); begin AutoSizeHotkeysGrid; end; { TfrmOptionsHotkeys.stgHotkeysSelectCell } procedure TfrmOptionsHotkeys.stgHotkeysSelectCell(Sender: TObject; aCol, aRow: integer; var CanSelect: boolean); var aEnabled: boolean; begin aEnabled := aRow >= stgHotkeys.FixedRows; actEditHotkey.Enabled := aEnabled; actDeleteHotKey.Enabled := aEnabled; end; { TfrmOptionsHotkeys.AutoSizeCommandsGrid } procedure TfrmOptionsHotkeys.AutoSizeCommandsGrid; begin stgCommands.AutoSizeColumns; end; { TfrmOptionsHotkeys.AutoSizeHotkeysGrid } procedure TfrmOptionsHotkeys.AutoSizeHotkeysGrid; var Diff: integer = 0; i: integer; begin with stgHotkeys do begin if Length(FHotkeysAutoColWidths) = ColCount then begin if ClientWidth > FHotkeysAutoGridWidth then Diff := (ClientWidth - FHotkeysAutoGridWidth) div 3; for i := 0 to ColCount - 1 do ColWidths[i] := FHotkeysAutoColWidths[i] + Diff; end; end; end; { TfrmOptionsHotkeys.actAddHotKeyExecute } procedure TfrmOptionsHotkeys.actAddHotKeyExecute(Sender: TObject); begin ShowEditHotkeyForm(False, GetSelectedForm, GetSelectedCommand, nil, nil); end; { TfrmOptionsHotkeys.DeleteHotkeyFromGrid } procedure TfrmOptionsHotkeys.DeleteHotkeyFromGrid(aHotkey: string); var i: integer; begin for i := stgHotkeys.FixedRows to stgHotkeys.RowCount - 1 do if stgHotkeys.Cells[0, i] = aHotkey then begin DestroyHotkeyItem(PHotkeyItem(stgHotkeys.Objects[0, i])); stgHotkeys.DeleteColRow(False, i); Break; end; end; { TfrmOptionsHotkeys.UpdateHotkeys } procedure TfrmOptionsHotkeys.UpdateHotkeys(HMForm: THMForm); var i: integer; begin if cbCommandSortOrder.ItemIndex = 0 then begin for i := Self.stgCommands.FixedRows to Self.stgCommands.RowCount - 1 do Self.UpdateHotkeysForCommand(HMForm, i); end else begin FillCommandList(edtFilter.Text); end; end; { TfrmOptionsHotkeys.UpdateHotkeysForCommand } procedure TfrmOptionsHotkeys.UpdateHotkeysForCommand(HMForm: THMForm; RowNr: integer); var Hotkeys: THotkeys; begin Hotkeys := THotkeys.Create(False); try GetHotKeyList(HMForm, stgCommands.Cells[stgCmdCommandIndex, RowNr], Hotkeys); stgCommands.Cells[stgCmdHotkeysIndex, RowNr] := HotkeysToString(Hotkeys); finally Hotkeys.Free; end; end; { TfrmOptionsHotkeys.FillSCFilesList } procedure TfrmOptionsHotkeys.FillSCFilesList; var SR: TSearchRecEx; Res, iItem: integer; slSCFileList: TStringList; begin FUpdatingShortcutsFiles := True; slSCFileList := TStringList.Create; try slSCFileList.Sorted := True; Res := FindFirstEx(gpCfgDir + '*.scf', 0, SR); try while Res = 0 do begin slSCFileList.Add(Sr.Name); Res := FindNextEx(SR); end; finally FindCloseEx(SR); end; lbSCFilesList.Items.Clear; for iItem := 0 to pred(slSCFileList.Count) do lbSCFilesList.Items.Add(slSCFileList.Strings[iItem]); iItem := lbSCFilesList.Items.IndexOf(gNameSCFile); if iItem <> -1 then lbSCFilesList.ItemIndex := iItem else if lbSCFilesList.Items.Count > 0 then lbSCFilesList.ItemIndex := 0; finally FreeAndNil(slSCFileList); end; FUpdatingShortcutsFiles := False; end; { TfrmOptionsHotkeys.GetHotKeyList } procedure TfrmOptionsHotkeys.GetHotKeyList(HMForm: THMForm; Command: string; HotkeysList: THotkeys); procedure AddHotkeys(hotkeys: THotkeys); var i: integer; begin for i := 0 to hotkeys.Count - 1 do begin if hotkeys[i].Command = Command then HotkeysList.Add(hotkeys[i]); end; end; var i: integer; begin AddHotkeys(HMForm.Hotkeys); for i := 0 to HMForm.Controls.Count - 1 do AddHotkeys(HMForm.Controls[i].Hotkeys); end; { TfrmOptionsHotkeys.ClearHotkeysGrid } procedure TfrmOptionsHotkeys.ClearHotkeysGrid; var i: integer; begin for i := stgHotkeys.FixedRows to stgHotkeys.RowCount - 1 do DestroyHotkeyItem(PHotkeyItem(stgHotkeys.Objects[0, i])); stgHotkeys.RowCount := stgHotkeys.FixedRows; end; { TfrmOptionsHotkeys.FillHotkeyList } procedure TfrmOptionsHotkeys.FillHotkeyList(sCommand: string); function SetObject(RowNr: integer; AHotkey: THotkey): PHotkeyItem; var HotkeyItem: PHotkeyItem; begin New(HotkeyItem); stgHotkeys.Objects[0, RowNr] := TObject(HotkeyItem); HotkeyItem^.Hotkey := AHotkey.Clone; Result := HotkeyItem; end; var HMForm: THMForm; HMControl: THMControl; iHotKey, iControl, iGrid: integer; hotkey: THotkey; found: boolean; HotkeyItem: PHotkeyItem; begin ClearHotkeysGrid; if (sCommand = EmptyStr) or (lbxCategories.ItemIndex = -1) then Exit; HMForm := HotMan.Forms.Find(GetSelectedForm); if not Assigned(HMForm) then Exit; stgHotkeys.BeginUpdate; try // add hotkeys from form for iHotKey := 0 to HMForm.Hotkeys.Count - 1 do begin hotkey := HMForm.Hotkeys[iHotKey]; if hotkey.Command <> sCommand then continue; stgHotkeys.RowCount := stgHotkeys.RowCount + 1; stgHotkeys.Cells[0, stgHotkeys.RowCount - 1] := ShortcutsToText(hotkey.Shortcuts); stgHotkeys.Cells[1, stgHotkeys.RowCount - 1] := ArrayToString(hotkey.Params); SetObject(stgHotkeys.RowCount - 1, hotkey); end; // add hotkeys from controls for iControl := 0 to HMForm.Controls.Count - 1 do begin HMControl := HMForm.Controls[iControl]; for iHotKey := 0 to HMControl.Hotkeys.Count - 1 do begin hotkey := HMControl.Hotkeys[iHotKey]; if hotkey.Command <> sCommand then continue; // search for hotkey in grid and add control name to list found := False; for iGrid := stgHotkeys.FixedRows to stgHotkeys.RowCount - 1 do begin HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, iGrid]); if HotkeyItem^.Hotkey.SameShortcuts(hotkey.Shortcuts) and HotkeyItem^.Hotkey.SameParams(hotkey.Params) then begin stgHotkeys.Cells[2, iGrid] := stgHotkeys.Cells[2, iGrid] + HMControl.Name + ';'; HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, iGrid]); AddString(HotkeyItem^.Controls, HMControl.Name); found := True; break; end; { if } end; { for } // add new row for hotkey if not found then begin stgHotkeys.RowCount := stgHotkeys.RowCount + 1; stgHotkeys.Cells[0, stgHotkeys.RowCount - 1] := ShortcutsToText(hotkey.Shortcuts); stgHotkeys.Cells[1, stgHotkeys.RowCount - 1] := ArrayToString(hotkey.Params); stgHotkeys.Cells[2, stgHotkeys.RowCount - 1] := HMControl.Name + ';'; HotkeyItem := SetObject(stgHotkeys.RowCount - 1, hotkey); AddString(HotkeyItem^.Controls, HMControl.Name); end; { if } end; { for } end; { for } finally stgHotkeys.EndUpdate; end; stgHotkeys.AutoSizeColumns; SetLength(FHotkeysAutoColWidths, stgHotkeys.ColCount); for iHotKey := 0 to stgHotkeys.ColCount - 1 do FHotkeysAutoColWidths[iHotKey] := stgHotkeys.ColWidths[iHotKey]; FHotkeysAutoGridWidth := stgHotkeys.GridWidth; AutoSizeHotkeysGrid; end; { TfrmOptionsHotkeys.FillCommandList } // We will scan the hotkeys and fill progressively the list "slCommandsForGrid", "slDescriptionsFroGrid" and "slHotKeyForGrid". // Then we output to actual grid the element of the list. // Then we sort the grid. // Fill stgCommands with commands and descriptions procedure TfrmOptionsHotkeys.FillCommandList(Filter: string); var lcFilter: string; FilterParts: TStringList; slCommandsForGrid, slDescriptionsForGrid, slHotKeyForGrid: TStringList; procedure AddOrFilterOut(const Command, HotKeys, Description: string); function CheckHotKeys: Boolean; var lcHotKeys: string; i: integer; begin lcHotKeys := UTF8LowerCase(HotKeys); for i := 0 to pred(FilterParts.Count) do // Get filter parts split by '+' character begin if FilterParts[i] = '' then Continue; if Length(FilterParts[i]) = 1 then // Heurstics to make filtering more handy begin if FilterParts[i][1] in ['c','s','a','m'] then // Ctrl Shift Alt Meta first letters Result := Pos('+' + FilterParts[i] + ';', '+' + lcHotKeys + ';') <> 0 else // other single letters Result := Pos('+' + FilterParts[i], '+' + lcHotKeys) <> 0; end else // plain substring search for two or more letters Result := Pos(FilterParts[i], lcHotKeys) <> 0; if not Result then Break; end; end; begin if (lcFilter = '') or (Pos(lcFilter, UTF8LowerCase(Command)) <> 0) or (Pos(lcFilter, UTF8LowerCase(Description)) <> 0) or ((HotKeys <> '') and CheckHotKeys) then begin slCommandsForGrid.Add(Command); slHotKeyForGrid.Add(HotKeys); slDescriptionsForGrid.Add(Description); end; end; var slTmp: THotkeys; slAllCommands: TStringList; i, j: integer; HMForm: THMForm; sForm: string; CommandsFormClass: TComponentClass; CommandsForm: TComponent = nil; CommandsFormCreated: boolean = False; CommandsIntf: IFormCommands; begin sForm := GetSelectedForm; CommandsFormClass := TFormCommands.GetCommandsForm(sForm); if not Assigned(CommandsFormClass) or not Supports(CommandsFormClass, IFormCommands) then begin stgCommands.Clean; Exit; end; // Find an instance of the form to retrieve action list (for descriptions). for i := 0 to Screen.CustomFormCount - 1 do if Screen.CustomForms[i].ClassType = CommandsFormClass then begin CommandsForm := Screen.CustomForms[i]; Break; end; // If not found create an instance temporarily. if not Assigned(CommandsForm) then begin CommandsForm := CommandsFormClass.Create(Application); CommandsFormCreated := True; end; CommandsIntf := CommandsForm as IFormCommands; slAllCommands := TStringList.Create; slCommandsForGrid := TStringList.Create; slHotKeyForGrid := TStringList.Create; slDescriptionsForGrid := TStringList.Create; slTmp := THotkeys.Create(False); HMForm := HotMan.Forms.Find(sForm); // 1. Get all the "cm_" commands and store them in our list "slAllCommands". CommandsIntf.GetCommandsList(slAllCommands); // 2. Prepare filter to use in the next step. lcFilter := UTF8LowerCase(Filter); FilterParts := TStringList.Create; FilterParts.Delimiter := '+'; FilterParts.DelimitedText := lcFilter; // 3. Based on all the commands we got, populate "equally" our three string list of commands, hotkeys and descrition used to fill our grid. for i := 0 to pred(slAllCommands.Count) do begin if Assigned(HMForm) then begin slTmp.Clear; GetHotKeyList(HMForm, slAllCommands.Strings[i], slTmp); if (THotKeySortOrder(cbCommandSortOrder.ItemIndex) = hksoByHotKeyOnePerRow) and (slTmp.Count > 0) then begin for j := 0 to pred(slTmp.Count) do begin AddOrFilterOut( slAllCommands.Strings[i], ShortcutsToText(slTmp[j].Shortcuts), CommandsIntf.GetCommandCaption(slAllCommands.Strings[i], cctLong)); end; end else begin AddOrFilterOut( slAllCommands.Strings[i], HotkeysToString(slTmp), CommandsIntf.GetCommandCaption(slAllCommands.Strings[i], cctLong)); end; end else begin AddOrFilterOut( slAllCommands.Strings[i], '', CommandsIntf.GetCommandCaption(slAllCommands.Strings[i], cctLong)); end; end; // 4. Add to list NAMES of columns. slCommandsForGrid.Insert(0, rsOptHotkeysCommand); slHotKeyForGrid.Insert(0, rsOptHotkeysHotkeys); slDescriptionsForGrid.Insert(0, rsOptHotkeysDescription); // 5. Set stringgrid rows count. stgCommands.RowCount := slCommandsForGrid.Count; // 6. Copy to grid our created list. stgCommands.BeginUpdate; stgCommands.Clean; stgCommands.Cols[stgCmdCommandIndex].Assign(slCommandsForGrid); stgCommands.Cols[stgCmdHotkeysIndex].Assign(slHotKeyForGrid); stgCommands.Cols[stgCmdDescriptionIndex].Assign(slDescriptionsForGrid); // 7. Sort our grid according to our wish case THotKeySortOrder(cbCommandSortOrder.ItemIndex) of hksoByCommand: stgCommands.SortColRow(True, stgCmdCommandIndex); hksoByHotKeyGrouped, hksoByHotKeyOnePerRow: stgCommands.SortColRow(True, stgCmdHotkeysIndex); end; // 8. We have finished playing in element of the grid. stgCommands.EndUpdate; // 9. Resize the columns to fit with the text now in all the cells. AutoSizeCommandsGrid; stgCommands.Row := 0; // needs for call select function for refresh hotkeylist slAllCommands.Free; slCommandsForGrid.Free; slHotKeyForGrid.Free; slDescriptionsForGrid.Free; slTmp.Free; FilterParts.Free; if CommandsFormCreated then Application.ReleaseComponent(CommandsForm); end; { TfrmOptionsHotkeys.FillCategoriesList } procedure TfrmOptionsHotkeys.FillCategoriesList; var i, MainIndex, Diff: integer; Translated: TStringList; begin Translated := TStringList.Create; try TFormCommands.GetCategoriesList(FHotkeysCategories, Translated); if FHotkeysCategories.Count > 0 then begin // Remove Main category so that it can be put to the top after sorting the rest. MainIndex := FHotkeysCategories.IndexOf('Main'); if (MainIndex >= 0) and (Translated[MainIndex] = rsHotkeyCategoryMain) then begin FHotkeysCategories.Delete(MainIndex); Translated.Delete(MainIndex); Diff := 1; // Account for Main category being at the top. end else begin MainIndex := -1; Diff := 0; end; // Assign indexes to FHotkeysCategories (untranslated). for i := 0 to Translated.Count - 1 do Translated.Objects[i] := TObject(i + Diff); Translated.CustomSort(@CompareCategories); if MainIndex >= 0 then begin FHotkeysCategories.InsertObject(0, 'Main', TObject(0)); Translated.InsertObject(0, rsHotkeyCategoryMain, TObject(0)); end; lbxCategories.Items.Assign(Translated); lbxCategories.ItemIndex := 0; end else lbxCategories.Items.Clear; finally Translated.Free; end; end; { TfrmOptionsHotkeys.GetSelectedForm } function TfrmOptionsHotkeys.GetSelectedForm: string; var Index: integer; begin Index := lbxCategories.ItemIndex; if (Index >= 0) and (Index < FHotkeysCategories.Count) then Result := FHotkeysCategories[PtrUInt(lbxCategories.Items.Objects[Index])] else Result := EmptyStr; end; { TfrmOptionsHotkeys.GetIconIndex } class function TfrmOptionsHotkeys.GetIconIndex: integer; begin Result := 5; end; { TfrmOptionsHotkeys.GetSelectedCommand } function TfrmOptionsHotkeys.GetSelectedCommand: string; begin if stgCommands.Row >= stgCommands.FixedRows then Result := stgCommands.Cells[stgCmdCommandIndex, stgCommands.Row] else Result := EmptyStr; end; { TfrmOptionsHotkeys.GetTitle } class function TfrmOptionsHotkeys.GetTitle: string; begin Result := rsOptionsEditorHotKeys; end; { TfrmOptionsHotkeys.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsHotkeys.IsSignatureComputedFromAllWindowComponents: boolean; begin Result := False; end; { TfrmOptionsHotkeys.DeleteAllHotkeys } // "ClearAllHotkeys" is a private procedure of "HotMan", so let's clear hotkeys manually by calling the same code procedure TfrmOptionsHotkeys.DeleteAllHotkeys; var iForm, iControl: integer; begin for iForm := 0 to pred(HotMan.Forms.Count) do begin HotMan.Forms[iForm].Hotkeys.Clear; for iControl := 0 to pred(HotMan.Forms[iForm].Controls.Count) do HotMan.Forms[iForm].Controls[iControl].Hotkeys.Clear; end; end; { TfrmOptionsHotkeys.DeleteHotkey } procedure TfrmOptionsHotkeys.DeleteHotkey; var i: integer; sCommand: string; HMForm: THMForm; HMControl: THMControl; hotkey: THotkey; HotkeyItem: PHotkeyItem; RememberSelectionGridRect: TGridRect; bCanSelect: boolean; begin if stgHotkeys.Row >= stgHotkeys.FixedRows then begin RememberSelectionGridRect := stgCommands.Selection; HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, stgHotkeys.Row]); sCommand := GetSelectedCommand; HMForm := HotMan.Forms.Find(GetSelectedForm); if Assigned(HMForm) then begin for i := 0 to HMForm.Controls.Count - 1 do begin HMControl := HMForm.Controls[i]; if Assigned(HMControl) then begin hotkey := HMControl.Hotkeys.FindByContents(HotkeyItem^.Hotkey); if Assigned(hotkey) then HMControl.Hotkeys.Remove(hotkey); end; end; hotkey := HMForm.Hotkeys.FindByContents(HotkeyItem^.Hotkey); if Assigned(hotkey) then HMForm.Hotkeys.Remove(hotkey); // refresh lists Self.UpdateHotkeys(HMForm); Self.FillHotkeyList(sCommand); FModified := True; if stgCommands.CanFocus then stgCommands.SetFocus; stgCommands.Row := RememberSelectionGridRect.Top; bCanSelect := True; stgCommandsSelectCell(stgCommands, stgCommands.Selection.Left, stgCommands.Selection.Top, bCanSelect); end; end; end; { TfrmOptionsHotkeys.Init } procedure TfrmOptionsHotkeys.Init; begin FModified := False; ParseLineToList(rsHotkeySortOrder, cbCommandSortOrder.Items); stgCommands.FocusRectVisible := False; stgCommands.SortOrder := soAscending; // Default initial sort ascending stgHotkeys.FocusRectVisible := False; // Localize Hotkeys. // stgCommands is localized in FillCommandList. stgHotkeys.Columns.Items[0].Title.Caption := rsOptHotkeysHotkey; stgHotkeys.Columns.Items[1].Title.Caption := rsOptHotkeysParameters; btnFileAction.Caption := ''; end; { TfrmOptionsHotkeys.Load } procedure TfrmOptionsHotkeys.Load; begin cbCommandSortOrder.ItemIndex := integer(gHotKeySortOrder); FillSCFilesList; FillCategoriesList; lbxCategoriesChange(lbxCategories); end; { TfrmOptionsHotkeys.Save } function TfrmOptionsHotkeys.Save: TOptionsEditorSaveFlags; begin Result := []; // Save hotkeys file name. if lbSCFilesList.ItemIndex >= 0 then gNameSCFile := lbSCFilesList.Items[lbSCFilesList.ItemIndex]; HotMan.Save(gpCfgDir + gNameSCFile); end; { TfrmOptionsHotkeys.SelectHotkey } procedure TfrmOptionsHotkeys.SelectHotkey(Hotkey: THotkey); var HotkeyItem: PHotkeyItem; i: integer; begin for i := stgHotkeys.FixedRows to stgHotkeys.RowCount - 1 do begin HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, i]); if Assigned(HotkeyItem) and HotkeyItem^.Hotkey.SameAs(Hotkey) then begin stgHotkeys.Row := i; Break; end; end; end; { TfrmOptionsHotkeys.ShowEditHotkeyForm } procedure TfrmOptionsHotkeys.ShowEditHotkeyForm(EditMode: boolean; aHotkeyRow: integer); var HotkeyItem: PHotkeyItem; begin HotkeyItem := PHotkeyItem(stgHotkeys.Objects[0, aHotkeyRow]); if Assigned(HotkeyItem) then ShowEditHotkeyForm(EditMode, GetSelectedForm, HotkeyItem^.Hotkey.Command, HotkeyItem^.Hotkey, HotkeyItem^.Controls); end; { TfrmOptionsHotkeys.ShowEditHotkeyForm } procedure TfrmOptionsHotkeys.ShowEditHotkeyForm(EditMode: boolean; const AForm: string; const ACommand: string; const AHotkey: THotkey; const AControls: TDynamicStringArray); var HMForm: THMForm; Hotkey: THotkey = nil; begin if AForm <> EmptyStr then begin if not Assigned(FEditForm) then FEditForm := TfrmEditHotkey.Create(Self); if FEditForm.Execute(EditMode, AForm, ACommand, AHotkey, AControls) then begin HMForm := HotMan.Forms.FindOrCreate(AForm); // refresh hotkey lists Self.UpdateHotkeys(HMForm); Self.FillHotkeyList(ACommand); Hotkey := FEditForm.CloneNewHotkey; try // Select the new shortcut in the hotkeys table. SelectHotkey(Hotkey); finally Hotkey.Free; end; FModified := True; end; end; end; { TfrmOptionsHotkeys.Create } constructor TfrmOptionsHotkeys.Create(TheOwner: TComponent); begin inherited Create(TheOwner); FHotkeysCategories := TStringList.Create; end; { TfrmOptionsHotkeys.Destroy } destructor TfrmOptionsHotkeys.Destroy; begin inherited Destroy; FHotkeysCategories.Free; end; { TfrmOptionsHotkeys.AddDeleteWithShiftHotkey } procedure TfrmOptionsHotkeys.AddDeleteWithShiftHotkey(UseTrash: boolean); procedure ReverseShift(Hotkey: THotkey; out Shortcut: TShortCut; out TextShortcut: string); var ShiftState: TShiftState; begin Shortcut := TextToShortCutEx(Hotkey.Shortcuts[0]); ShiftState := ShortcutToShiftEx(Shortcut); if ssShift in ShiftState then ShiftState := ShiftState - [ssShift] else ShiftState := ShiftState + [ssShift]; ShortCut := KeyToShortCutEx(Shortcut, ShiftState); TextShortcut := ShortCutToTextEx(Shortcut); end; function ConfirmFix({%H-}Hotkey: THotkey; const Msg: string): boolean; begin Result := QuestionDlg(rsOptHotkeysCannotSetShortcut, Msg, mtConfirmation, [mrYes, rsOptHotkeysFixParameter, 'isdefault', mrCancel], 0) = mrYes; end; function FixOverrides(Hotkey: THotkey; const OldTrashParam: string; NewTrashParam: boolean; ShouldUseTrash: boolean): boolean; begin if Contains(Hotkey.Params, OldTrashParam) or NewTrashParam then begin Result := ConfirmFix(Hotkey, Format(rsOptHotkeysDeleteTrashCanOverrides, [Hotkey.Shortcuts[0]])); if Result then begin DeleteString(Hotkey.Params, OldTrashParam); if ShouldUseTrash then SetValue(Hotkey.Params, 'trashcan', 'setting') else SetValue(Hotkey.Params, 'trashcan', 'reversesetting'); end; end else Result := True; end; procedure FixReversedShortcut(Hotkey: THotkey; NonReversedHotkey: THotkey; const ParamsToDelete: array of string; const AllowedOldParam: string; const NewTrashParam: string; HasTrashCan: boolean; TrashStr: string); var sDelete: string; begin if ContainsOneOf(Hotkey.Params, ParamsToDelete) or (HasTrashCan and (TrashStr <> NewTrashParam)) then if not ConfirmFix(Hotkey, Format(rsOptHotkeysDeleteTrashCanParameterExists, [Hotkey.Shortcuts[0], NonReversedHotkey.Shortcuts[0]])) then Exit; for sDelete in ParamsToDelete do DeleteString(Hotkey.Params, sDelete); if not Contains(Hotkey.Params, AllowedOldParam) then SetValue(Hotkey.Params, 'trashcan', NewTrashParam); end; procedure AddShiftShortcut(Hotkeys: THotkeys); var i, j: integer; Shortcut: TShortCut; TextShortcut: string; NewParams: array of string; HasTrashCan, HasTrashBool, NormalTrashSetting: boolean; TrashStr: string; TrashBoolValue: boolean; CheckedShortcuts: TDynamicStringArray; ReversedHotkey: THotkey; CountBeforeAdded: integer; SetShortcut: boolean; begin SetLength(CheckedShortcuts, 0); CountBeforeAdded := Hotkeys.Count; for i := 0 to CountBeforeAdded - 1 do begin if (Hotkeys[i].Command = 'cm_Delete') and (Length(Hotkeys[i].Shortcuts) > 0) then begin if Length(Hotkeys[i].Shortcuts) > 1 then begin MessageDlg(rsOptHotkeysCannotSetShortcut, Format(rsOptHotkeysShortcutForDeleteIsSequence, [ShortcutsToText(Hotkeys[i].Shortcuts)]), mtWarning, [mbOK], 0); Continue; end; if not Contains(CheckedShortcuts, Hotkeys[i].Shortcuts[0]) then begin ReversedHotkey := nil; SetShortcut := True; ReverseShift(Hotkeys[i], Shortcut, TextShortcut); AddString(CheckedShortcuts, TextShortcut); // Check if shortcut with reversed shift already exists. for j := 0 to CountBeforeAdded - 1 do begin if ArrBegins(Hotkeys[j].Shortcuts, [TextShortcut], False) then begin if Hotkeys[j].Command <> Hotkeys[i].Command then begin if QuestionDlg(rsOptHotkeysCannotSetShortcut, Format(rsOptHotkeysShortcutForDeleteAlreadyAssigned, [Hotkeys[i].Shortcuts[0], TextShortcut, Hotkeys[j].Command]), mtConfirmation, [mrYes, rsOptHotkeysChangeShortcut, 'isdefault', mrCancel], 0) = mrYes then begin Hotkeys[j].Command := Hotkeys[i].Command; end else SetShortcut := False; end; ReversedHotkey := Hotkeys[j]; Break; end; end; if not SetShortcut then Continue; // Fix parameters of original hotkey if needed. HasTrashCan := GetParamValue(Hotkeys[i].Params, 'trashcan', TrashStr); HasTrashBool := HasTrashCan and GetBoolValue(TrashStr, TrashBoolValue); if not FixOverrides(Hotkeys[i], 'recycle', HasTrashBool and TrashBoolValue, UseTrash) then Continue; if not FixOverrides(Hotkeys[i], 'norecycle', HasTrashBool and not TrashBoolValue, not UseTrash) then Continue; // Reverse trash setting for reversed hotkey. NewParams := Copy(Hotkeys[i].Params); HasTrashCan := GetParamValue(NewParams, 'trashcan', TrashStr); // Could have been added above so check again if Contains(NewParams, 'recyclesettingrev') then begin DeleteString(NewParams, 'recyclesettingrev'); NormalTrashSetting := True; end else if Contains(NewParams, 'recyclesetting') then begin DeleteString(NewParams, 'recyclesetting'); NormalTrashSetting := False; end else if HasTrashCan and (TrashStr = 'reversesetting') then NormalTrashSetting := True else NormalTrashSetting := False; if Assigned(ReversedHotkey) then begin HasTrashCan := GetParamValue(ReversedHotkey.Params, 'trashcan', TrashStr); if NormalTrashSetting then begin FixReversedShortcut(ReversedHotkey, Hotkeys[i], ['recyclesettingrev', 'recycle', 'norecycle'], 'recyclesetting', 'setting', HasTrashCan, TrashStr); end else begin FixReversedShortcut(ReversedHotkey, Hotkeys[i], ['recyclesetting', 'recycle', 'norecycle'], 'recyclesettingrev', 'reversesetting', HasTrashCan, TrashStr); end; end else if QuestionDlg(rsOptHotkeysSetDeleteShortcut, Format(rsOptHotkeysAddDeleteShortcutLong, [TextShortcut]), mtConfirmation, [mrYes, rsOptHotkeysAddShortcutButton, 'isdefault', mrCancel], 0) = mrYes then begin if NormalTrashSetting then TrashStr := 'setting' else TrashStr := 'reversesetting'; SetValue(NewParams, 'trashcan', TrashStr); Hotkeys.Add([TextShortcut], NewParams, Hotkeys[i].Command); end; end; end; end; end; var HMForm: THMForm; I: integer; begin HMForm := HotMan.Forms.Find('Main'); if Assigned(HMForm) then begin AddShiftShortcut(HMForm.Hotkeys); for I := 0 to HMForm.Controls.Count - 1 do AddShiftShortcut(HMForm.Controls[i].Hotkeys); // Refresh hotkeys list. if GetSelectedCommand = 'cm_Delete' then Self.FillHotkeyList('cm_Delete'); end; end; { TfrmOptionsHotkeys.TryToSelectThatCategory } procedure TfrmOptionsHotkeys.TryToSelectThatCategory(sCategory: string); var iCategoryIndex: integer; begin iCategoryIndex := lbxCategories.Items.IndexOf(sCategory); if iCategoryIndex <> -1 then begin lbxCategories.ItemIndex := iCategoryIndex; lbxCategoriesChange(lbxCategories); end; end; { TfrmOptionsHotkeys.cbCommandSortOrderChange } procedure TfrmOptionsHotkeys.cbCommandSortOrderChange(Sender: TObject); begin if THotKeySortOrder(cbCommandSortOrder.ItemIndex) <> gHotKeySortOrder then begin if (THotKeySortOrder(cbCommandSortOrder.ItemIndex) = hksoByHotKeyOnePerRow) or (gHotKeySortOrder = hksoByHotKeyOnePerRow) then FillCommandList(edtFilter.Text) else stgCommands.SortColRow(True, cbCommandSortOrder.ItemIndex); //hksoByCommand=0=column0=command hksoByHotKeyGrouped=1=column1=hotkey end; gHotKeySortOrder := THotKeySortOrder(cbCommandSortOrder.ItemIndex); end; { TfrmOptionsHotkeys.isOkToContinueRegardingModifiedOrNot } function TfrmOptionsHotkeys.isOkToContinueRegardingModifiedOrNot: boolean; var Answer: TMyMsgResult; begin Result := True; if FModified then begin Answer := MsgBox(Format(rsHotKeyFileSaveModified, [gNameSCFile]), [msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); case Answer of mmrYes: HotMan.Save(gpCfgDir + gNameSCFile); mmrCancel: Result := False; end; end; end; { TfrmOptionsHotkeys.GetANewSetupName } function TfrmOptionsHotkeys.GetANewSetupName(var ASetupName: string): boolean; var sSuggestedName: string; Answer: TMyMsgResult = mmrCancel; begin Result := False; repeat sSuggestedName := ASetupName; if InputQuery(rsHotKeyFileNewName, rsHotKeyFileInputNewName, sSuggestedName) then begin Result := not mbFileExists(gpCfgDir + sSuggestedName); if not Result then begin Answer := MsgBox(rsHotKeyFileAlreadyExists, [msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); Result := (Answer = mmrYes); end; end; until (Result) or (Answer = mmrCancel); if Result then ASetupName := sSuggestedName; end; { GetSortableShortcutName } // Will return a string representing the shortcut. // The string will have a prefix that it will help to sort it in such way that the shortcut will appear in this order, from the first to the last: // -:Fx (with F9 arranged to be shown prior F10) // -:ALT+Fx // -:CTRL+Fx // -:SHIFT+Fx // -:CTRL+SHIFT+Fx // -:Single letter stuff // -:CTRL+Letter // -:SHIFT+Letter // -:CTRL+SHIFT+Letter function GetSortableShortcutName(sToSort: string): string; var posSemiColon, i: integer; sFollowing: string; sAbsolute: string; sShifted: string; posPlus1, posPlus2: integer; icombine: integer = 0; isFxKey: boolean; iPrefix: word; begin if length(sToSort) > 1 then if sToSort[length(sToSort)] = '+' then sToSort[length(sToSort)] := ','; //1o) We get the first shortcut string in case there are many. posSemiColon := pos(';', sToSort); if posSemiColon <> 0 then sToSort := leftstr(sToSort, pred(posSemiColon)); //2o) Make sure we're in uppercase sToSort := UpperCase(sToSort); //3o) Let's arrange things so F9 will be coded F09 so it will easily be sortable prior F10 instead of being after. i := 1; while (i <= length(sToSort)) do begin if pos(sToSort[i], '0123456789') <> 0 then begin sFollowing := copy(sToSort, succ(i), 1); if pos(sFollowing, '0123456789') = 0 then sToSort := copy(sToSort, 1, pred(i)) + '0' + rightstr(sToSort, (length(sToSort) - pred(i))); Inc(i); end; Inc(i); end; //4o) Let's see if we have combined keys (CTRL+..., SHIFT+..., CTRL+SHIFT+....) posPlus1 := pos('+', sToSort); posPlus2 := UTF8Pos('+', sToSort, succ(PosPlus1)); if posPlus1 <> 0 then if posPlus2 = 0 then iCombine := 1 else iCombine := 2; //5o) Let's extract the unshifted absolute keys case iCombine of 0: sAbsolute := sToSort; 1: sAbsolute := copy(sToSort, succ(posPlus1), (length(sToSort) - posPlus1)); 2: sAbsolute := copy(sToSort, succ(posPlus2), (length(sToSort) - posPlus2)); end; case iCombine of 0: sShifted := ''; 1: sShifted := copy(sToSort, 1, pred(posPlus1)); 2: sShifted := copy(sToSort, 1, pred(posPlus2)); end; isFxKey := (pos('F', sAbsolute) = 1) and (length(sAbsolute) > 1); iPrefix := 0; if (not isFxKey) then iPrefix := iPrefix or $100; //Make sure if it's a "Fx" key, it appear FIRST if length(sAbsolute) > 1 then iPrefix := iPrefix or $01; case iCombine of 0: begin end; 1: begin if pos('ALT', sShifted) = 1 then iPrefix := (iPrefix or $02) else if pos('CTRL', sShifted) = 1 then iPrefix := (iPrefix or $04) else if pos('SHIFT', sShifted) = 1 then iPrefix := (iPrefix or $08); end; 2: begin if pos('CTRL+ALT', sShifted) = 1 then iPrefix := (iPrefix or $10) else if pos('CTRL+SHIFT', sShifted) = 1 then iPrefix := (iPrefix or $20) else if pos('SHIFT+ALT', sShifted) = 1 then iPrefix := (iPrefix or $40); end; end; Result := Format('%4.4d%s', [iPrefix, sAbsolute]); end; { TfrmOptionsHotkeys.stgCommandsCompareCells } // Add a word about "iSecondLevelSort" procedure TfrmOptionsHotkeys.stgCommandsCompareCells(Sender: TObject; ACol, ARow, BCol, BRow: integer; var Result: integer); var sText1, sText2: string; iSecondLevelSort: boolean = False; begin if ACol and $80 <> 0 then begin iSecondLevelSort := True; ACol := Acol and $7F; end; sText1 := TStringGrid(Sender).Cells[ACol, ARow]; sText2 := TStringGrid(Sender).Cells[BCol, BRow]; if aCol = stgCmdHotkeysIndex then begin if (sText1 = '') then begin if (sText2 = '') then begin if not iSecondLevelSort then stgCommandsCompareCells(Sender, stgCmdCommandIndex or $80, ARow, stgCmdCommandIndex, BRow, Result) else Result := 0; end else Result := 1; end else begin if (sText2 = '') then begin Result := -1; end else begin sText1 := GetSortableShortcutName(sText1); sText2 := GetSortableShortcutName(sText2); case TStringGrid(Sender).SortOrder of soAscending: Result := CompareText(sText1, sText2); soDescending: Result := CompareText(sText2, sText1); end; end; end; end else begin case TStringGrid(Sender).SortOrder of soAscending: Result := CompareText(sText1, sText2); soDescending: Result := CompareText(sText2, sText1); end; if (Result = 0) and (not iSecondLevelSort) then stgCommandsCompareCells(Sender, stgCmdHotkeysIndex or $80, ARow, stgCmdHotkeysIndex, BRow, Result); end; end; { TfrmOptionsHotkeys.stgCommandsHeaderClick } procedure TfrmOptionsHotkeys.stgCommandsHeaderClick(Sender: TObject; IsColumn: boolean; Index: integer); var iInitialIndex: integer; begin iInitialIndex := cbCommandSortOrder.ItemIndex; if (isColumn) then begin if (Index = stgCmdCommandIndex) and (THotKeySortOrder(cbCommandSortOrder.ItemIndex) <> hksoByCommand) then cbCommandSortOrder.ItemIndex := integer(hksoByCommand) else if (Index = stgCmdHotkeysIndex) then begin if (THotKeySortOrder(cbCommandSortOrder.ItemIndex) = hksoByCommand) then cbCommandSortOrder.ItemIndex := integer(hksoByHotKeyGrouped) else cbCommandSortOrder.ItemIndex := 3 - cbCommandSortOrder.ItemIndex; end; end; if iInitialIndex <> cbCommandSortOrder.ItemIndex then cbCommandSortOrderChange(cbCommandSortOrder); end; { TfrmOptionsHotkeys.actSaveNowExecute } procedure TfrmOptionsHotkeys.actSaveNowExecute(Sender: TObject); begin HotMan.Save(gpCfgDir + gNameSCFile); FModified := False; end; { TfrmOptionsHotkeys.actAdjustSortOrderExecute } procedure TfrmOptionsHotkeys.actAdjustSortOrderExecute(Sender: TObject); begin cbCommandSortOrder.ItemIndex := TComponent(Sender).Tag; cbCommandSortOrderChange(cbCommandSortOrder); end; { RemoveSCFextension } function RemoveSCFextension(sBaseName: string): string; begin Result := StringReplace(sBaseName, '.scf', '', [rfIgnoreCase, rfReplaceAll]); end; { TfrmOptionsHotkeys.actRenameExecute } procedure TfrmOptionsHotkeys.actRenameExecute(Sender: TObject); begin actCopyExecute(Sender); end; { TfrmOptionsHotkeys.actCopyExecute } procedure TfrmOptionsHotkeys.actCopyExecute(Sender: TObject); var sSetupName, sOldFilename: string; begin if isOkToContinueRegardingModifiedOrNot then begin sSetupName := RemoveSCFextension(Format(rsHotKeyFileCopyOf, [gNameSCFile])); if GetANewSetupName(sSetupName) then begin sOldFilename := gNameSCFile; gNameSCFile := RemoveSCFextension(sSetupName) + '.scf'; HotMan.Save(gpCfgDir + gNameSCFile); if TAction(Sender).Tag = 1 then mbDeletefile(gpCfgDir + sOldFilename); FillSCFilesList; FillCategoriesList; lbxCategoriesChange(lbxCategories); end; end; end; { TfrmOptionsHotkeys.actDeleteExecute } procedure TfrmOptionsHotkeys.actDeleteExecute(Sender: TObject); begin if lbSCFilesList.Items.Count > 1 then begin if MsgBox(Format(rsHotKeyFileConfirmErasure, [RemoveSCFextension(lbSCFilesList.Text)]), [msmbYes, msmbCancel], msmbCancel, msmbCancel) = mmrYes then begin if mbFileExists(gpCfgDir + lbSCFilesList.Items[lbSCFilesList.ItemIndex]) then mbDeleteFile(gpCfgDir + lbSCFilesList.Items[lbSCFilesList.ItemIndex]); FillSCFilesList; FillCategoriesList; lbxCategoriesChange(lbxCategories); end; end else begin MsgError(rsHotKeyFileMustKeepOne); end; end; { TfrmOptionsHotkeys.actRestoreDefaultExecute } procedure TfrmOptionsHotkeys.actRestoreDefaultExecute(Sender: TObject); begin if isOkToContinueRegardingModifiedOrNot then begin if MsgBox(rsHotKeyFileConfirmDefault, [msmbYes, msmbCancel], msmbCancel, msmbCancel) = mmrYes then begin DeleteAllHotkeys; LoadDefaultHotkeyBindings; HotMan.Save(gpCfgDir + gNameSCFile); HotMan.Load(gpCfgDir + gNameSCFile); FillCategoriesList; lbxCategoriesChange(lbxCategories); end; end; end; { TfrmOptionsHotkeys.actDeleteHotKeyExecute } procedure TfrmOptionsHotkeys.actDeleteHotKeyExecute(Sender: TObject); begin DeleteHotkey; end; { TfrmOptionsHotkeys.actEditHotKeyExecute } procedure TfrmOptionsHotkeys.actEditHotKeyExecute(Sender: TObject); begin ShowEditHotkeyForm(True, stgHotkeys.Row); end; { TfrmOptionsHotkeys.actNextCategoryExecute } procedure TfrmOptionsHotkeys.actNextCategoryExecute(Sender: TObject); begin if lbxCategories.ItemIndex < pred(lbxCategories.Items.Count) then lbxCategories.ItemIndex := lbxCategories.ItemIndex + 1 else lbxCategories.ItemIndex := 0; lbxCategoriesChange(lbxCategories); end; { TfrmOptionsHotkeys.actPopupFileRelatedMenuExecute } procedure TfrmOptionsHotkeys.actPopupFileRelatedMenuExecute(Sender: TObject); var TargetPopUpMenuPos: TPoint; begin TargetPopUpMenuPos := Self.ClientToScreen(Classes.Point(btnFileAction.Left + (btnFileAction.Width div 2), btnFileAction.Height + (btnFileAction.Height div 2))); pmShortCutMenu.PopUp(TargetPopUpMenuPos.x, TargetPopUpMenuPos.y); end; { TfrmOptionsHotkeys.actPreviousCategoryExecute } procedure TfrmOptionsHotkeys.actPreviousCategoryExecute(Sender: TObject); begin if lbxCategories.ItemIndex > 0 then lbxCategories.ItemIndex := lbxCategories.ItemIndex - 1 else lbxCategories.ItemIndex := pred(lbxCategories.Items.Count); lbxCategoriesChange(lbxCategories); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsicons.lfm�������������������������������������������������������0000644�0001750�0000144�00000024044�14743153644�020253� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsIcons: TfrmOptionsIcons Height = 590 Width = 478 HelpKeyword = '/configuration.html#ConfigIcons' ClientHeight = 590 ClientWidth = 478 DesignLeft = 397 DesignTop = 37 object gbShowIconsMode: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 219 Top = 6 Width = 466 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = ' Show icons to the left of the filename ' ChildSizing.TopBottomSpacing = 8 ClientHeight = 194 ClientWidth = 462 TabOrder = 0 object rbIconsShowAll: TRadioButton AnchorSideLeft.Control = gbShowIconsMode AnchorSideTop.Control = rbIconsShowAllAndExe AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 38 Width = 42 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = 'A&ll' Checked = True TabOrder = 1 TabStop = True end object rbIconsShowStandard: TRadioButton AnchorSideLeft.Control = gbShowIconsMode AnchorSideTop.Control = rbIconsShowAll AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 68 Width = 154 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = 'Only &standard icons' TabOrder = 2 end object rbIconsShowNone: TRadioButton AnchorSideLeft.Control = gbShowIconsMode AnchorSideTop.Control = rbIconsShowStandard AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 98 Width = 82 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = '&No icons' OnChange = rbIconsShowNoneChange TabOrder = 3 end object rbIconsShowAllAndExe: TRadioButton AnchorSideLeft.Control = gbShowIconsMode AnchorSideTop.Control = gbShowIconsMode Left = 10 Height = 24 Top = 8 Width = 236 BorderSpacing.Left = 10 Caption = 'All associated + &EXE/LNK (slow)' TabOrder = 0 end object cbIconsShowOverlay: TCheckBox AnchorSideLeft.Control = gbShowIconsMode AnchorSideTop.Control = rbIconsShowNone AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 130 Width = 236 BorderSpacing.Left = 10 BorderSpacing.Top = 8 Caption = 'Show o&verlay icons, e.g. for links' TabOrder = 4 end object chkShowHiddenDimmed: TCheckBox AnchorSideLeft.Control = cbIconsShowOverlay AnchorSideTop.Control = cbIconsShowOverlay AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 162 Width = 220 BorderSpacing.Top = 8 Caption = '&Dimmed hidden files (slower)' TabOrder = 5 end end object gbDisableSpecialIcons: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbShowIconsMode AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 100 Top = 231 Width = 466 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Disable special icons' ChildSizing.TopBottomSpacing = 8 ClientHeight = 75 ClientWidth = 462 TabOrder = 1 object edtIconsExcludeDirs: TEdit AnchorSideLeft.Control = cbIconsExclude AnchorSideTop.Control = cbIconsExclude AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbDisableSpecialIcons AnchorSideRight.Side = asrBottom Left = 30 Height = 28 Top = 32 Width = 424 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 20 BorderSpacing.Right = 8 BorderSpacing.Bottom = 15 TabOrder = 1 end object cbIconsExclude: TCheckBox AnchorSideLeft.Control = gbDisableSpecialIcons AnchorSideTop.Control = gbDisableSpecialIcons Left = 10 Height = 24 Top = 8 Width = 340 BorderSpacing.Left = 10 Caption = 'For the following &paths and their subdirectories:' OnChange = cbIconsExcludeChange TabOrder = 0 end end object gbShowIcons: TGroupBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbIconsSize AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 99 Top = 482 Width = 466 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Show icons' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 8 ClientHeight = 74 ClientWidth = 462 TabOrder = 2 object cbIconsOnButtons: TCheckBox AnchorSideLeft.Control = gbShowIcons AnchorSideTop.Control = gbShowIcons Left = 10 Height = 24 Top = 8 Width = 173 Caption = 'Show icons on buttons' TabOrder = 0 end object cbIconsInMenus: TCheckBox AnchorSideLeft.Control = gbShowIcons AnchorSideTop.Control = cbIconsInMenusSize AnchorSideTop.Side = asrCenter Left = 10 Height = 24 Top = 40 Width = 235 Caption = 'Show icons for actions in &menus' TabOrder = 1 end object cbIconsInMenusSize: TComboBox AnchorSideTop.Control = cbIconsOnButtons AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbShowIcons AnchorSideRight.Side = asrBottom Left = 321 Height = 28 Top = 38 Width = 131 Anchors = [akTop, akRight] BorderSpacing.Top = 6 ItemHeight = 20 ItemIndex = 0 Items.Strings = ( '16x16' '24x24' '32x32' ) OnChange = cbIconsSizeChange Style = csDropDownList TabOrder = 2 Text = '16x16' end end object gbIconsSize: TGroupBox[3] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbDisableSpecialIcons AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 139 Top = 337 Width = 466 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = ' Icon size ' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 3 ClientHeight = 114 ClientWidth = 462 TabOrder = 3 object pnlLabel: TPanel Left = 10 Height = 102 Top = 6 Width = 146 BevelOuter = bvNone ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ChildSizing.ControlsPerLine = 2 ClientHeight = 102 ClientWidth = 146 TabOrder = 0 object lblFilePanel: TLabel Left = 0 Height = 20 Top = 21 Width = 72 Caption = 'File panel:' Layout = tlCenter ParentColor = False end object lblDiskPanel: TLabel Left = 0 Height = 20 Top = 62 Width = 72 Caption = 'Disk panel:' Layout = tlCenter ParentColor = False end end object pnlComboBox: TPanel Left = 156 Height = 102 Top = 6 Width = 174 BevelOuter = bvNone ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ChildSizing.ControlsPerLine = 2 ClientHeight = 102 ClientWidth = 174 TabOrder = 1 object cbIconsSize: TComboBox AnchorSideTop.Side = asrCenter Left = 0 Height = 28 Top = 16 Width = 100 ItemHeight = 20 OnChange = cbIconsSizeChange Style = csDropDownList TabOrder = 0 end object cbDiskIconsSize: TComboBox AnchorSideTop.Side = asrCenter Left = 0 Height = 28 Top = 60 Width = 100 ItemHeight = 20 OnChange = cbDiskIconsSizeChange Style = csDropDownList TabOrder = 1 end end object pnlImage: TPanel Left = 330 Height = 102 Top = 6 Width = 122 BevelOuter = bvNone ChildSizing.VerticalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.EnlargeVertical = crsHomogenousSpaceResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ChildSizing.ControlsPerLine = 2 ClientHeight = 102 ClientWidth = 122 TabOrder = 2 object imgIconExample: TImage Left = 37 Height = 48 Top = 0 Width = 48 Center = True Constraints.MaxHeight = 48 Constraints.MaxWidth = 48 Constraints.MinHeight = 48 Constraints.MinWidth = 48 end object imgDiskIconExample: TImage Left = 37 Height = 48 Top = 54 Width = 48 Center = True Constraints.MaxHeight = 48 Constraints.MaxWidth = 48 Constraints.MinHeight = 48 Constraints.MinWidth = 48 end end end object gbIconTheme: TGroupBox[4] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbShowIcons AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 65 Top = 587 Width = 466 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Icon theme' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 40 ClientWidth = 462 TabOrder = 4 object cmbIconTheme: TComboBox AnchorSideLeft.Control = gbIconTheme AnchorSideTop.Control = gbIconTheme AnchorSideRight.Control = gbIconTheme AnchorSideRight.Side = asrBottom Left = 6 Height = 28 Top = 6 Width = 450 Anchors = [akTop, akLeft, akRight] ItemHeight = 20 Style = csDropDownList TabOrder = 0 end end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsicons.lrj�������������������������������������������������������0000644�0001750�0000144�00000006366�14743153644�020273� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":203478128,"name":"tfrmoptionsicons.gbshowiconsmode.caption","sourcebytes":[32,83,104,111,119,32,105,99,111,110,115,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32],"value":" Show icons to the left of the filename "}, {"hash":277804,"name":"tfrmoptionsicons.rbiconsshowall.caption","sourcebytes":[65,38,108,108],"value":"A&ll"}, {"hash":154150419,"name":"tfrmoptionsicons.rbiconsshowstandard.caption","sourcebytes":[79,110,108,121,32,38,115,116,97,110,100,97,114,100,32,105,99,111,110,115],"value":"Only &standard icons"}, {"hash":24104707,"name":"tfrmoptionsicons.rbiconsshownone.caption","sourcebytes":[38,78,111,32,105,99,111,110,115],"value":"&No icons"}, {"hash":264383097,"name":"tfrmoptionsicons.rbiconsshowallandexe.caption","sourcebytes":[65,108,108,32,97,115,115,111,99,105,97,116,101,100,32,43,32,38,69,88,69,47,76,78,75,32,40,115,108,111,119,41],"value":"All associated + &EXE/LNK (slow)"}, {"hash":25699715,"name":"tfrmoptionsicons.cbiconsshowoverlay.caption","sourcebytes":[83,104,111,119,32,111,38,118,101,114,108,97,121,32,105,99,111,110,115,44,32,101,46,103,46,32,102,111,114,32,108,105,110,107,115],"value":"Show o&verlay icons, e.g. for links"}, {"hash":256005833,"name":"tfrmoptionsicons.chkshowhiddendimmed.caption","sourcebytes":[38,68,105,109,109,101,100,32,104,105,100,100,101,110,32,102,105,108,101,115,32,40,115,108,111,119,101,114,41],"value":"&Dimmed hidden files (slower)"}, {"hash":226326355,"name":"tfrmoptionsicons.gbdisablespecialicons.caption","sourcebytes":[68,105,115,97,98,108,101,32,115,112,101,99,105,97,108,32,105,99,111,110,115],"value":"Disable special icons"}, {"hash":105351658,"name":"tfrmoptionsicons.cbiconsexclude.caption","sourcebytes":[70,111,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,38,112,97,116,104,115,32,97,110,100,32,116,104,101,105,114,32,115,117,98,100,105,114,101,99,116,111,114,105,101,115,58],"value":"For the following &paths and their subdirectories:"}, {"hash":157948723,"name":"tfrmoptionsicons.gbshowicons.caption","sourcebytes":[83,104,111,119,32,105,99,111,110,115],"value":"Show icons"}, {"hash":168408451,"name":"tfrmoptionsicons.cbiconsonbuttons.caption","sourcebytes":[83,104,111,119,32,105,99,111,110,115,32,111,110,32,98,117,116,116,111,110,115],"value":"Show icons on buttons"}, {"hash":165512787,"name":"tfrmoptionsicons.cbiconsinmenus.caption","sourcebytes":[83,104,111,119,32,105,99,111,110,115,32,102,111,114,32,97,99,116,105,111,110,115,32,105,110,32,38,109,101,110,117,115],"value":"Show icons for actions in &menus"}, {"hash":3464006,"name":"tfrmoptionsicons.cbiconsinmenussize.text","sourcebytes":[49,54,120,49,54],"value":"16x16"}, {"hash":6228496,"name":"tfrmoptionsicons.gbiconssize.caption","sourcebytes":[32,73,99,111,110,32,115,105,122,101,32],"value":" Icon size "}, {"hash":120277386,"name":"tfrmoptionsicons.lblfilepanel.caption","sourcebytes":[70,105,108,101,32,112,97,110,101,108,58],"value":"File panel:"}, {"hash":120406570,"name":"tfrmoptionsicons.lbldiskpanel.caption","sourcebytes":[68,105,115,107,32,112,97,110,101,108,58],"value":"Disk panel:"}, {"hash":8262229,"name":"tfrmoptionsicons.gbicontheme.caption","sourcebytes":[73,99,111,110,32,116,104,101,109,101],"value":"Icon theme"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsicons.pas�������������������������������������������������������0000644�0001750�0000144�00000020115�14743153644�020253� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Icons options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsIcons; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, ExtCtrls, fOptionsFrame; type { TfrmOptionsIcons } TfrmOptionsIcons = class(TOptionsEditor) cbDiskIconsSize: TComboBox; cbIconsOnButtons: TCheckBox; cbIconsShowOverlay: TCheckBox; cbIconsExclude: TCheckBox; cbIconsInMenusSize: TComboBox; cbIconsInMenus: TCheckBox; cbIconsSize: TComboBox; chkShowHiddenDimmed: TCheckBox; cmbIconTheme: TComboBox; edtIconsExcludeDirs: TEdit; gbIconsSize: TGroupBox; gbShowIconsMode: TGroupBox; gbDisableSpecialIcons: TGroupBox; gbShowIcons: TGroupBox; gbIconTheme: TGroupBox; imgDiskIconExample: TImage; imgIconExample: TImage; lblDiskPanel: TLabel; lblFilePanel: TLabel; pnlComboBox: TPanel; pnlImage: TPanel; pnlLabel: TPanel; rbIconsShowAll: TRadioButton; rbIconsShowAllAndExe: TRadioButton; rbIconsShowNone: TRadioButton; rbIconsShowStandard: TRadioButton; procedure cbDiskIconsSizeChange(Sender: TObject); procedure cbIconsExcludeChange(Sender: TObject); procedure cbIconsSizeChange(Sender: TObject); procedure rbIconsShowNoneChange(Sender: TObject); private procedure FillIconThemes(const Path: String); public class function GetIconIndex: Integer; override; class function GetTitle: String; override; procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; end; implementation {$R *.lfm} uses Forms, Graphics, FileUtil, DCOSUtils, uPixMapManager, uGlobs, uLng, uOSUtils, uGlobsPaths, uSysFolders; { TfrmOptionsIcons } procedure TfrmOptionsIcons.cbIconsSizeChange(Sender: TObject); var iSize: Integer; bmpTemp: TBitmap; begin if cbIconsSize.ItemIndex < 0 then Exit; iSize:= PtrInt(cbIconsSize.Items.Objects[cbIconsSize.ItemIndex]); bmpTemp:= PixmapManager.GetFolderIcon(iSize, pnlImage.Color); imgIconExample.Picture.Assign(bmpTemp); FreeAndNil(bmpTemp); end; procedure TfrmOptionsIcons.cbIconsExcludeChange(Sender: TObject); begin edtIconsExcludeDirs.Enabled:= cbIconsExclude.Checked; end; procedure TfrmOptionsIcons.cbDiskIconsSizeChange(Sender: TObject); var iSize: Integer; bmpTemp: TBitmap; begin if cbDiskIconsSize.ItemIndex < 0 then Exit; iSize:= PtrInt(cbDiskIconsSize.Items.Objects[cbDiskIconsSize.ItemIndex]); bmpTemp:= PixmapManager.GetDefaultDriveIcon(iSize, pnlImage.Color); imgDiskIconExample.Picture.Assign(bmpTemp); FreeAndNil(bmpTemp); end; procedure TfrmOptionsIcons.rbIconsShowNoneChange(Sender: TObject); begin cbIconsSize.Enabled := not rbIconsShowNone.Checked; cbIconsShowOverlay.Enabled := not rbIconsShowNone.Checked; chkShowHiddenDimmed.Enabled := not rbIconsShowNone.Checked; gbDisableSpecialIcons.Enabled := not rbIconsShowNone.Checked; end; procedure TfrmOptionsIcons.FillIconThemes(const Path: String); var I: Integer; ADirectories: TStringList; begin ADirectories:= FindAllDirectories(Path, False); for I:= 0 to ADirectories.Count - 1 do begin if mbFileExists(ADirectories[I] + PathDelim + 'index.theme') then cmbIconTheme.Items.Add(ExtractFileName(ADirectories[I])); end; ADirectories.Free; end; class function TfrmOptionsIcons.GetIconIndex: Integer; begin Result := 16; end; class function TfrmOptionsIcons.GetTitle: String; begin Result := rsOptionsEditorIcons; end; procedure TfrmOptionsIcons.Init; var I: Integer; AIconSize: String; begin inherited Init; for I:= Low(ICON_SIZES) to High(ICON_SIZES) do begin AIconSize:= IntToStr(ICON_SIZES[I]) + 'x' + IntToStr(ICON_SIZES[I]); cbIconsSize.Items.AddObject(AIconSize, TObject(PtrInt(ICON_SIZES[I]))); end; for I:= Low(ICON_SIZES) to High(ICON_SIZES) - 1 do begin AIconSize:= IntToStr(ICON_SIZES[I]) + 'x' + IntToStr(ICON_SIZES[I]); cbDiskIconsSize.Items.AddObject(AIconSize, TObject(PtrInt(ICON_SIZES[I]))); end; TStringList(cmbIconTheme.Items).Duplicates:= dupIgnore; if not gUseConfigInProgramDir then begin FillIconThemes(IncludeTrailingBackslash(GetAppDataDir) + 'pixmaps'); end; FillIconThemes(gpPixmapPath); end; procedure TfrmOptionsIcons.Load; begin case gShowIconsNew of sim_none: rbIconsShowNone.Checked:= True; sim_standart: rbIconsShowStandard.Checked:= True; sim_all: rbIconsShowAll.Checked:= True; sim_all_and_exe: rbIconsShowAllAndExe.Checked := True; end; cmbIconTheme.Text:= gIconTheme; chkShowHiddenDimmed.Checked:= gShowHiddenDimmed; cbIconsShowOverlay.Checked:= gIconOverlays; cbIconsExclude.Checked:= gIconsExclude; cbIconsInMenus.Checked := gIconsInMenus; edtIconsExcludeDirs.Text:= gIconsExcludeDirs; edtIconsExcludeDirs.Enabled:= gIconsExclude; cbIconsSize.Text := IntToStr(gIconsSizeNew) + 'x' + IntToStr(gIconsSizeNew); cbDiskIconsSize.Text := IntToStr(gDiskIconsSize) + 'x' + IntToStr(gDiskIconsSize); cbIconsInMenusSize.Text := IntToStr(gIconsInMenusSizeNew) + 'x' + IntToStr(gIconsInMenusSizeNew); cbIconsSizeChange(nil); cbDiskIconsSizeChange(nil); cbIconsOnButtons.Checked := Application.ShowButtonGlyphs = sbgAlways; end; function TfrmOptionsIcons.Save: TOptionsEditorSaveFlags; var SelectedShowIcons: TShowIconsMode = sim_none; SelectedIconsSize: Integer; SelectedDiskIconsSize: Integer; begin Result := []; if rbIconsShowNone.Checked then SelectedShowIcons := sim_none else if rbIconsShowStandard.Checked then SelectedShowIcons := sim_standart else if rbIconsShowAll.Checked then SelectedShowIcons := sim_all else if rbIconsShowAllAndExe.Checked then SelectedShowIcons := sim_all_and_exe; if cbIconsSize.ItemIndex < 0 then SelectedIconsSize := gIconsSizeNew else begin SelectedIconsSize := PtrInt(cbIconsSize.Items.Objects[cbIconsSize.ItemIndex]) end; if cbDiskIconsSize.ItemIndex < 0 then SelectedDiskIconsSize := gDiskIconsSize else begin SelectedDiskIconsSize := PtrInt(cbDiskIconsSize.Items.Objects[cbDiskIconsSize.ItemIndex]) end; case cbIconsInMenusSize.ItemIndex of 0: gIconsInMenusSizeNew := 16; 1: gIconsInMenusSizeNew := 24; 2: gIconsInMenusSizeNew := 32; end; if (gIconsSizeNew <> SelectedIconsSize) or (gShowIconsNew <> SelectedShowIcons) or (gIconsInMenusSizeNew <> gIconsInMenusSize) then begin Include(Result, oesfNeedsRestart); end; if cbIconsInMenus.Checked <> gIconsInMenus then Include(Result, oesfNeedsRestart); //Main page menu's are created only at startup so we need to restart. gIconsSizeNew := SelectedIconsSize; gShowIconsNew := SelectedShowIcons; gDiskIconsSize := SelectedDiskIconsSize; gIconOverlays := cbIconsShowOverlay.Checked; gIconsExclude := cbIconsExclude.Checked; gIconsExcludeDirs := edtIconsExcludeDirs.Text; gIconsInMenus := cbIconsInMenus.Checked; gShowHiddenDimmed := chkShowHiddenDimmed.Checked; if cbIconsOnButtons.Checked then begin if Application.ShowButtonGlyphs <> sbgAlways then Include(Result, oesfNeedsRestart); Application.ShowButtonGlyphs := sbgAlways; end else begin if Application.ShowButtonGlyphs <> sbgNever then Include(Result, oesfNeedsRestart); Application.ShowButtonGlyphs := sbgNever; end; if cmbIconTheme.Text <> gIconTheme then begin gIconTheme:= cmbIconTheme.Text; Include(Result, oesfNeedsRestart); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsignorelist.lfm��������������������������������������������������0000644�0001750�0000144�00000013670�14743153644�021322� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsIgnoreList: TfrmOptionsIgnoreList Height = 325 Width = 644 HelpKeyword = '/configuration.html#ConfigIgnore' ClientHeight = 325 ClientWidth = 644 DesignTop = 27 object lblSaveIn: TLabel[0] Tag = 304 AnchorSideLeft.Control = memIgnoreList AnchorSideTop.Control = fneSaveIn AnchorSideTop.Side = asrCenter Left = 10 Height = 15 Top = 256 Width = 40 Caption = '&Save in:' FocusControl = fneSaveIn ParentColor = False end object chkIgnoreEnable: TCheckBox[1] Tag = 301 AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 10 Height = 19 Top = 8 Width = 624 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Top = 8 BorderSpacing.Right = 10 Caption = '&Ignore (don''t show) the following files and folders:' OnChange = chkIgnoreEnableChange TabOrder = 0 end object memIgnoreList: TMemo[2] AnchorSideLeft.Control = chkIgnoreEnable AnchorSideTop.Control = chkIgnoreEnable AnchorSideTop.Side = asrBottom AnchorSideRight.Control = chkIgnoreEnable AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneSaveIn Left = 10 Height = 209 Top = 33 Width = 624 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 6 BorderSpacing.Bottom = 10 Lines.Strings = ( '' ) ParentFont = False ScrollBars = ssBoth TabOrder = 1 end object btnAddSel: TButton[3] Tag = 303 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = memIgnoreList AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 502 Height = 30 Top = 285 Width = 132 Anchors = [akRight, akBottom] AutoSize = True BorderSpacing.Bottom = 10 Caption = 'A&dd selected names' Constraints.MinHeight = 30 OnClick = btnAddSelClick TabOrder = 4 end object btnAddSelWithPath: TButton[4] Tag = 302 AnchorSideLeft.Control = memIgnoreList AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 10 Height = 30 Top = 285 Width = 205 Anchors = [akLeft, akBottom] AutoSize = True BorderSpacing.Bottom = 10 Caption = 'Add selected names with &full path' Constraints.MinHeight = 30 OnClick = btnAddSelWithPathClick TabOrder = 3 end object fneSaveIn: TFileNameEdit[5] AnchorSideLeft.Control = lblSaveIn AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeSaveIn AnchorSideBottom.Control = btnAddSel Left = 58 Height = 23 Top = 252 Width = 549 DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Left = 8 BorderSpacing.Bottom = 10 MaxLength = 0 TabOrder = 2 end object btnRelativeSaveIn: TSpeedButton[6] AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneSaveIn AnchorSideRight.Control = memIgnoreList AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneSaveIn AnchorSideBottom.Side = asrBottom Left = 607 Height = 23 Hint = 'Some functions to select appropriate path' Top = 252 Width = 27 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeSaveInClick end object pmPathHelper: TPopupMenu[7] left = 456 top = 280 end end ������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsignorelist.lrj��������������������������������������������������0000644�0001750�0000144�00000002362�14743153644�021327� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":147277194,"name":"tfrmoptionsignorelist.lblsavein.caption","sourcebytes":[38,83,97,118,101,32,105,110,58],"value":"&Save in:"}, {"hash":240235098,"name":"tfrmoptionsignorelist.chkignoreenable.caption","sourcebytes":[38,73,103,110,111,114,101,32,40,100,111,110,39,116,32,115,104,111,119,41,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,108,101,115,32,97,110,100,32,102,111,108,100,101,114,115,58],"value":"&Ignore (don't show) the following files and folders:"}, {"hash":261476003,"name":"tfrmoptionsignorelist.btnaddsel.caption","sourcebytes":[65,38,100,100,32,115,101,108,101,99,116,101,100,32,110,97,109,101,115],"value":"A&dd selected names"}, {"hash":110533672,"name":"tfrmoptionsignorelist.btnaddselwithpath.caption","sourcebytes":[65,100,100,32,115,101,108,101,99,116,101,100,32,110,97,109,101,115,32,119,105,116,104,32,38,102,117,108,108,32,112,97,116,104],"value":"Add selected names with &full path"}, {"hash":15252584,"name":"tfrmoptionsignorelist.btnrelativesavein.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsignorelist.pas��������������������������������������������������0000644�0001750�0000144�00000007600�14743153644�021323� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Ignore list options page Copyright (C) 2006-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsIgnoreList; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, EditBtn, Buttons, Menus, fOptionsFrame; type { TfrmOptionsIgnoreList } TfrmOptionsIgnoreList = class(TOptionsEditor) btnAddSel: TButton; btnAddSelWithPath: TButton; btnRelativeSaveIn: TSpeedButton; chkIgnoreEnable: TCheckBox; fneSaveIn: TFileNameEdit; lblSaveIn: TLabel; memIgnoreList: TMemo; pmPathHelper: TPopupMenu; procedure btnAddSelClick(Sender: TObject); procedure btnAddSelWithPathClick(Sender: TObject); procedure btnRelativeSaveInClick(Sender: TObject); procedure chkIgnoreEnableChange(Sender: TObject); private procedure FillIgnoreList(bWithFullPath: Boolean); public class function GetIconIndex: Integer; override; class function GetTitle: String; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; end; implementation {$R *.lfm} uses Controls, uGlobs, uFile, uLng, fMain, uSpecialDir; { TfrmOptionsIgnoreList } procedure TfrmOptionsIgnoreList.btnAddSelClick(Sender: TObject); begin FillIgnoreList(False); end; procedure TfrmOptionsIgnoreList.btnAddSelWithPathClick(Sender: TObject); begin FillIgnoreList(True); end; procedure TfrmOptionsIgnoreList.btnRelativeSaveInClick(Sender: TObject); begin fneSaveIn.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneSaveIn,pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsIgnoreList.chkIgnoreEnableChange(Sender: TObject); begin memIgnoreList.Enabled:= chkIgnoreEnable.Checked; lblSaveIn.Enabled:= chkIgnoreEnable.Checked; fneSaveIn.Enabled:= chkIgnoreEnable.Checked; btnAddSelWithPath.Enabled:= chkIgnoreEnable.Checked; btnAddSel.Enabled:= chkIgnoreEnable.Checked; btnRelativeSaveIn.Enabled:= chkIgnoreEnable.Checked; end; procedure TfrmOptionsIgnoreList.FillIgnoreList(bWithFullPath: Boolean); var I: Integer; SelectedFiles: TFiles; begin SelectedFiles := frmMain.ActiveFrame.CloneSelectedOrActiveFiles; try for I:= 0 to SelectedFiles.Count - 1 do if bWithFullPath then memIgnoreList.Lines.Add(SelectedFiles[I].FullPath) else memIgnoreList.Lines.Add(SelectedFiles[I].Name); finally FreeAndNil(SelectedFiles); end; end; class function TfrmOptionsIgnoreList.GetIconIndex: Integer; begin Result := 17; end; class function TfrmOptionsIgnoreList.GetTitle: String; begin Result := rsOptionsEditorIgnoreList; end; procedure TfrmOptionsIgnoreList.Load; begin chkIgnoreEnable.Checked:= gIgnoreListFileEnabled; fneSaveIn.FileName:= gIgnoreListFile; memIgnoreList.Lines.Assign(glsIgnoreList); chkIgnoreEnableChange(chkIgnoreEnable); gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper,mp_PATHHELPER,nil); end; function TfrmOptionsIgnoreList.Save: TOptionsEditorSaveFlags; begin Result := []; gIgnoreListFileEnabled:= chkIgnoreEnable.Checked; gIgnoreListFile:= fneSaveIn.FileName; glsIgnoreList.Assign(memIgnoreList.Lines); end; end. ��������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionskeyboard.lfm����������������������������������������������������0000644�0001750�0000144�00000006571�14743153644�020745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsKeyboard: TfrmOptionsKeyboard Height = 223 Width = 429 HelpKeyword = '/configuration.html#ConfigKeys' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 223 ClientWidth = 429 DesignTop = 20 object gbTyping: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 109 Top = 6 Width = 417 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Typing' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 89 ClientWidth = 413 TabOrder = 0 object lblNoModifier: TLabel Left = 8 Height = 15 Top = 8 Width = 88 Alignment = taRightJustify Caption = '&Letters:' FocusControl = cbNoModifier ParentColor = False end object cbNoModifier: TComboBox AnchorSideLeft.Control = lblNoModifier AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblNoModifier AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbTyping AnchorSideRight.Side = asrBottom Left = 106 Height = 23 Top = 4 Width = 299 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Items.Strings = ( 'None' 'Command Line' 'Quick Search' 'Quick Filter' ) Style = csDropDownList TabOrder = 0 end object lblAlt: TLabel Left = 8 Height = 15 Top = 35 Width = 88 Alignment = taRightJustify Caption = 'Alt+L&etters:' FocusControl = cbAlt ParentColor = False end object lblCtrlAlt: TLabel Left = 8 Height = 15 Top = 62 Width = 88 Alignment = taRightJustify Caption = 'Ctrl+Alt+Le&tters:' FocusControl = cbCtrlAlt ParentColor = False end object cbAlt: TComboBox AnchorSideLeft.Control = lblAlt AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblAlt AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbTyping AnchorSideRight.Side = asrBottom Left = 106 Height = 23 Top = 31 Width = 299 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Style = csDropDownList TabOrder = 1 end object cbCtrlAlt: TComboBox AnchorSideLeft.Control = lblCtrlAlt AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblCtrlAlt AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbTyping AnchorSideRight.Side = asrBottom Left = 106 Height = 23 Top = 58 Width = 299 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 ItemHeight = 15 Style = csDropDownList TabOrder = 2 end end object cbLynxLike: TCheckBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbTyping AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 19 Top = 123 Width = 323 BorderSpacing.Top = 8 Caption = 'Le&ft, Right arrows change directory (Lynx-like movement)' TabOrder = 1 end end ���������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionskeyboard.lrj����������������������������������������������������0000644�0001750�0000144�00000001730�14743153644�020746� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":96497735,"name":"tfrmoptionskeyboard.gbtyping.caption","sourcebytes":[84,121,112,105,110,103],"value":"Typing"}, {"hash":213574218,"name":"tfrmoptionskeyboard.lblnomodifier.caption","sourcebytes":[38,76,101,116,116,101,114,115,58],"value":"&Letters:"}, {"hash":76298218,"name":"tfrmoptionskeyboard.lblalt.caption","sourcebytes":[65,108,116,43,76,38,101,116,116,101,114,115,58],"value":"Alt+L&etters:"}, {"hash":153568746,"name":"tfrmoptionskeyboard.lblctrlalt.caption","sourcebytes":[67,116,114,108,43,65,108,116,43,76,101,38,116,116,101,114,115,58],"value":"Ctrl+Alt+Le&tters:"}, {"hash":20000009,"name":"tfrmoptionskeyboard.cblynxlike.caption","sourcebytes":[76,101,38,102,116,44,32,82,105,103,104,116,32,97,114,114,111,119,115,32,99,104,97,110,103,101,32,100,105,114,101,99,116,111,114,121,32,40,76,121,110,120,45,108,105,107,101,32,109,111,118,101,109,101,110,116,41],"value":"Le&ft, Right arrows change directory (Lynx-like movement)"} ]} ����������������������������������������doublecmd-1.1.22/src/frames/foptionskeyboard.pas����������������������������������������������������0000644�0001750�0000144�00000006771�14743153644�020754� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Keyboard options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsKeyboard; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, fOptionsFrame; type { TfrmOptionsKeyboard } TfrmOptionsKeyboard = class(TOptionsEditor) cbLynxLike: TCheckBox; cbNoModifier: TComboBox; cbAlt: TComboBox; cbCtrlAlt: TComboBox; gbTyping: TGroupBox; lblNoModifier: TLabel; lblAlt: TLabel; lblCtrlAlt: TLabel; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng; const KeyAction_None = 0; KeyAction_CommandLine = 1; KeyAction_QuickSearch = 2; KeyAction_QuickFilter = 3; { TfrmOptionsKeyboard } procedure TfrmOptionsKeyboard.Init; begin // Copy localized strings to each combo box. ParseLineToList(rsOptLetters, cbNoModifier.Items); cbAlt.Items.Assign(cbNoModifier.Items); cbCtrlAlt.Items.Assign(cbNoModifier.Items); end; procedure TfrmOptionsKeyboard.Load; procedure SetAction(ComboBox: TComboBox; KeyTypingAction: TKeyTypingAction); begin case KeyTypingAction of ktaNone: ComboBox.ItemIndex := KeyAction_None; ktaCommandLine: ComboBox.ItemIndex := KeyAction_CommandLine; ktaQuickSearch: ComboBox.ItemIndex := KeyAction_QuickSearch; ktaQuickFilter: ComboBox.ItemIndex := KeyAction_QuickFilter; else raise Exception.Create('Unknown TKeyTypingMode'); end; end; begin SetAction(cbNoModifier, gKeyTyping[ktmNone]); SetAction(cbAlt, gKeyTyping[ktmAlt]); SetAction(cbCtrlAlt, gKeyTyping[ktmCtrlAlt]); cbLynxLike.Checked := gLynxLike; end; function TfrmOptionsKeyboard.Save: TOptionsEditorSaveFlags; function GetAction(ComboBox: TComboBox): TKeyTypingAction; begin case ComboBox.ItemIndex of KeyAction_None: Result := ktaNone; KeyAction_CommandLine: Result := ktaCommandLine; KeyAction_QuickSearch: Result := ktaQuickSearch; KeyAction_QuickFilter: Result := ktaQuickFilter; else raise Exception.Create('Unknown action selected'); end; end; begin gKeyTyping[ktmNone] := GetAction(cbNoModifier); gKeyTyping[ktmAlt] := GetAction(cbAlt); gKeyTyping[ktmCtrlAlt] := GetAction(cbCtrlAlt); gLynxLike := cbLynxLike.Checked; Result := []; end; class function TfrmOptionsKeyboard.GetIconIndex: Integer; begin Result := 26; end; class function TfrmOptionsKeyboard.GetTitle: String; begin Result := rsOptionsEditorKeyboard; end; end. �������doublecmd-1.1.22/src/frames/foptionslanguage.lfm����������������������������������������������������0000644�0001750�0000144�00000000376�14743153644�020725� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsLanguage: TfrmOptionsLanguage HelpKeyword = '/configuration.html#ConfigLang' object lngList: TListBox[0] Left = 0 Height = 240 Top = 0 Width = 320 Align = alClient ItemHeight = 0 TabOrder = 0 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionslanguage.pas����������������������������������������������������0000644�0001750�0000144�00000006306�14743153644�020731� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Language options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsLanguage; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, fOptionsFrame; type { TfrmOptionsLanguage } TfrmOptionsLanguage = class(TOptionsEditor) lngList: TListBox; private procedure FillLngListBox; procedure LanguageListDblClick(Sender:TObject); protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses fOptions, DCClassesUtf8, uDebug, uFindEx, uGlobs, uGlobsPaths, uLng; { TfrmOptionsLanguage } procedure TfrmOptionsLanguage.FillLngListBox; var iIndex: Integer; fr: TSearchRecEx; sLangName: String; LanguageFileList: TStringListEx; begin LanguageFileList:= TStringListEx.Create; LanguageFileList.Sorted:= True; LanguageFileList.Duplicates:= dupAccept; try lngList.Clear; DCDebug('Language directory: ' + gpLngDir); if FindFirstEx(gpLngDir + '*.po*', 0, fr) = 0 then repeat sLangName := GetLanguageName(gpLngDir + fr.Name); LanguageFileList.Add(Format('%s = %s', [sLangName, fr.Name])); until FindNextEx(fr) <> 0; FindCloseEx(fr); for iIndex:= 0 to pred(LanguageFileList.Count) do begin lngList.Items.add(LanguageFileList.Strings[iIndex]); if (gPOFileName = Trim(lngList.Items.ValueFromIndex[iIndex])) then lngList.ItemIndex:= iIndex; end; finally LanguageFileList.Free; end; end; class function TfrmOptionsLanguage.GetIconIndex: Integer; begin Result := 0; end; class function TfrmOptionsLanguage.GetTitle: String; begin Result := rsOptionsEditorLanguage; end; procedure TfrmOptionsLanguage.Load; begin FillLngListBox; lngList.OnDblClick := @LanguageListDblClick; end; procedure TfrmOptionsLanguage.LanguageListDblClick(Sender:TObject); begin GetOptionsForm.btnOK.Click; end; function TfrmOptionsLanguage.Save: TOptionsEditorSaveFlags; var SelectedPOFileName: String; begin Result := []; if lngList.ItemIndex > -1 then begin SelectedPOFileName := Trim(lngList.Items.ValueFromIndex[lngList.ItemIndex]); if SelectedPOFileName <> gPOFileName then Include(Result, oesfNeedsRestart); gPOFileName := SelectedPOFileName; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionslayout.lfm������������������������������������������������������0000644�0001750�0000144�00000015463�14743153644�020462� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsLayout: TfrmOptionsLayout Height = 550 Width = 784 HelpKeyword = '/configuration.html#ConfigLayout' ClientHeight = 550 ClientWidth = 784 DesignLeft = 276 DesignTop = 44 object gbScreenLayout: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 530 Top = 6 Width = 772 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = ' Screen layout ' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 6 ClientHeight = 512 ClientWidth = 768 TabOrder = 0 object cbShowMainMenu: TCheckBox Left = 12 Height = 22 Top = 6 Width = 124 Caption = 'Show &main menu' TabOrder = 0 end object cbShowMainToolBar: TCheckBox AnchorSideTop.Control = cbShowMainMenu AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 30 Width = 99 BorderSpacing.Top = 2 Caption = 'Show tool&bar' TabOrder = 1 end object cbShowDiskPanel: TCheckBox AnchorSideTop.Control = chkShowMiddleToolBar AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 76 Width = 135 BorderSpacing.Top = 2 Caption = 'Show &drive buttons' OnChange = cbShowDiskPanelChange TabOrder = 3 end object cbShowDrivesListButton: TCheckBox AnchorSideTop.Control = cbFlatDiskPanel AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 148 Width = 156 BorderSpacing.Top = 2 Caption = 'Show drives list bu&tton' TabOrder = 6 end object cbShowCurDir: TCheckBox AnchorSideTop.Control = cbShowTabs AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 268 Width = 154 BorderSpacing.Top = 2 Caption = 'Show current director&y' TabOrder = 11 end object cbShowTabHeader: TCheckBox AnchorSideTop.Control = cbShowCurDir AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 292 Width = 146 BorderSpacing.Top = 2 Caption = 'S&how tabstop header' TabOrder = 12 end object cbShowStatusBar: TCheckBox AnchorSideTop.Control = cbShowTabHeader AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 316 Width = 118 BorderSpacing.Top = 2 Caption = 'Show &status bar' TabOrder = 13 end object cbShowCmdLine: TCheckBox AnchorSideTop.Control = cbShowStatusBar AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 340 Width = 141 BorderSpacing.Top = 2 Caption = 'Show command l&ine' TabOrder = 14 end object cbShowKeysPanel: TCheckBox AnchorSideTop.Control = cbShowCmdLine AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 364 Width = 178 BorderSpacing.Top = 2 Caption = 'Show function &key buttons' TabOrder = 15 end object cbFlatDiskPanel: TCheckBox AnchorSideLeft.Control = cbTwoDiskPanels AnchorSideTop.Control = cbTwoDiskPanels AnchorSideTop.Side = asrBottom Left = 28 Height = 22 Top = 124 Width = 93 BorderSpacing.Top = 2 Caption = '&Flat buttons' Enabled = False TabOrder = 5 end object cbTwoDiskPanels: TCheckBox AnchorSideLeft.Control = cbShowDiskPanel AnchorSideTop.Control = cbShowDiskPanel AnchorSideTop.Side = asrBottom Left = 28 Height = 22 Top = 100 Width = 372 BorderSpacing.Left = 16 BorderSpacing.Top = 2 Caption = 'Show two drive button bars (fi&xed width, above file windows)' Enabled = False TabOrder = 4 end object cbShowTabs: TCheckBox AnchorSideTop.Control = cbFreespaceInd AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 244 Width = 121 BorderSpacing.Top = 2 Caption = 'Sho&w folder tabs' TabOrder = 10 end object cbFlatInterface: TCheckBox AnchorSideTop.Control = cbShowKeysPanel AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 388 Width = 100 BorderSpacing.Top = 2 Caption = 'Flat i&nterface' TabOrder = 16 end object cbLogWindow: TCheckBox AnchorSideTop.Control = cbFlatInterface AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 412 Width = 123 BorderSpacing.Top = 2 Caption = 'Show lo&g window' TabOrder = 17 end object cbTermWindow: TCheckBox AnchorSideTop.Control = cbLogWindow AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 436 Width = 152 BorderSpacing.Top = 2 Caption = 'Show te&rminal window' TabOrder = 18 end object cbFreespaceInd: TCheckBox AnchorSideTop.Control = cbShowShortDriveFreeSpace AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 220 Width = 255 BorderSpacing.Top = 2 Caption = 'Show fr&ee space indicator on drive label' TabOrder = 9 end object cbProgInMenuBar: TCheckBox AnchorSideTop.Control = cbTermWindow AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 460 Width = 236 BorderSpacing.Top = 2 Caption = 'Show common progress in menu bar' TabOrder = 19 end object cbPanelOfOperations: TCheckBox AnchorSideTop.Control = cbProgInMenuBar AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 484 Width = 248 BorderSpacing.Top = 2 Caption = 'Show panel of operation in background' TabOrder = 20 end object cbShowDriveFreeSpace: TCheckBox AnchorSideTop.Control = cbShowDrivesListButton AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 172 Width = 152 BorderSpacing.Top = 2 Caption = 'Show free s&pace label' OnChange = cbShowDriveFreeSpaceChange TabOrder = 7 end object cbShowShortDriveFreeSpace: TCheckBox AnchorSideLeft.Control = cbFlatDiskPanel AnchorSideTop.Control = cbShowDriveFreeSpace AnchorSideTop.Side = asrBottom Left = 28 Height = 22 Top = 196 Width = 185 BorderSpacing.Top = 2 Caption = 'Show short free space &label' TabOrder = 8 end object chkShowMiddleToolBar: TCheckBox AnchorSideLeft.Control = cbShowMainToolBar AnchorSideTop.Control = cbShowMainToolBar AnchorSideTop.Side = asrBottom Left = 12 Height = 22 Top = 52 Width = 141 Caption = 'Show middle toolbar' TabOrder = 2 end end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionslayout.lrj������������������������������������������������������0000644�0001750�0000144�00000010744�14743153644�020470� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":134597216,"name":"tfrmoptionslayout.gbscreenlayout.caption","sourcebytes":[32,83,99,114,101,101,110,32,108,97,121,111,117,116,32],"value":" Screen layout "}, {"hash":177574613,"name":"tfrmoptionslayout.cbshowmainmenu.caption","sourcebytes":[83,104,111,119,32,38,109,97,105,110,32,109,101,110,117],"value":"Show &main menu"}, {"hash":229134466,"name":"tfrmoptionslayout.cbshowmaintoolbar.caption","sourcebytes":[83,104,111,119,32,116,111,111,108,38,98,97,114],"value":"Show tool&bar"}, {"hash":189661603,"name":"tfrmoptionslayout.cbshowdiskpanel.caption","sourcebytes":[83,104,111,119,32,38,100,114,105,118,101,32,98,117,116,116,111,110,115],"value":"Show &drive buttons"}, {"hash":6470158,"name":"tfrmoptionslayout.cbshowdriveslistbutton.caption","sourcebytes":[83,104,111,119,32,100,114,105,118,101,115,32,108,105,115,116,32,98,117,38,116,116,111,110],"value":"Show drives list bu&tton"}, {"hash":138066537,"name":"tfrmoptionslayout.cbshowcurdir.caption","sourcebytes":[83,104,111,119,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,38,121],"value":"Show current director&y"}, {"hash":226967058,"name":"tfrmoptionslayout.cbshowtabheader.caption","sourcebytes":[83,38,104,111,119,32,116,97,98,115,116,111,112,32,104,101,97,100,101,114],"value":"S&how tabstop header"}, {"hash":49110370,"name":"tfrmoptionslayout.cbshowstatusbar.caption","sourcebytes":[83,104,111,119,32,38,115,116,97,116,117,115,32,98,97,114],"value":"Show &status bar"}, {"hash":196317541,"name":"tfrmoptionslayout.cbshowcmdline.caption","sourcebytes":[83,104,111,119,32,99,111,109,109,97,110,100,32,108,38,105,110,101],"value":"Show command l&ine"}, {"hash":14274819,"name":"tfrmoptionslayout.cbshowkeyspanel.caption","sourcebytes":[83,104,111,119,32,102,117,110,99,116,105,111,110,32,38,107,101,121,32,98,117,116,116,111,110,115],"value":"Show function &key buttons"}, {"hash":51983379,"name":"tfrmoptionslayout.cbflatdiskpanel.caption","sourcebytes":[38,70,108,97,116,32,98,117,116,116,111,110,115],"value":"&Flat buttons"}, {"hash":216809273,"name":"tfrmoptionslayout.cbtwodiskpanels.caption","sourcebytes":[83,104,111,119,32,116,119,111,32,100,114,105,118,101,32,98,117,116,116,111,110,32,98,97,114,115,32,40,102,105,38,120,101,100,32,119,105,100,116,104,44,32,97,98,111,118,101,32,102,105,108,101,32,119,105,110,100,111,119,115,41],"value":"Show two drive button bars (fi&xed width, above file windows)"}, {"hash":91296995,"name":"tfrmoptionslayout.cbshowtabs.caption","sourcebytes":[83,104,111,38,119,32,102,111,108,100,101,114,32,116,97,98,115],"value":"Sho&w folder tabs"}, {"hash":44971493,"name":"tfrmoptionslayout.cbflatinterface.caption","sourcebytes":[70,108,97,116,32,105,38,110,116,101,114,102,97,99,101],"value":"Flat i&nterface"}, {"hash":245942935,"name":"tfrmoptionslayout.cblogwindow.caption","sourcebytes":[83,104,111,119,32,108,111,38,103,32,119,105,110,100,111,119],"value":"Show lo&g window"}, {"hash":142079143,"name":"tfrmoptionslayout.cbtermwindow.caption","sourcebytes":[83,104,111,119,32,116,101,38,114,109,105,110,97,108,32,119,105,110,100,111,119],"value":"Show te&rminal window"}, {"hash":140527132,"name":"tfrmoptionslayout.cbfreespaceind.caption","sourcebytes":[83,104,111,119,32,102,114,38,101,101,32,115,112,97,99,101,32,105,110,100,105,99,97,116,111,114,32,111,110,32,100,114,105,118,101,32,108,97,98,101,108],"value":"Show fr&ee space indicator on drive label"}, {"hash":151685554,"name":"tfrmoptionslayout.cbproginmenubar.caption","sourcebytes":[83,104,111,119,32,99,111,109,109,111,110,32,112,114,111,103,114,101,115,115,32,105,110,32,109,101,110,117,32,98,97,114],"value":"Show common progress in menu bar"}, {"hash":11318116,"name":"tfrmoptionslayout.cbpanelofoperations.caption","sourcebytes":[83,104,111,119,32,112,97,110,101,108,32,111,102,32,111,112,101,114,97,116,105,111,110,32,105,110,32,98,97,99,107,103,114,111,117,110,100],"value":"Show panel of operation in background"}, {"hash":157748028,"name":"tfrmoptionslayout.cbshowdrivefreespace.caption","sourcebytes":[83,104,111,119,32,102,114,101,101,32,115,38,112,97,99,101,32,108,97,98,101,108],"value":"Show free s&pace label"}, {"hash":176489292,"name":"tfrmoptionslayout.cbshowshortdrivefreespace.caption","sourcebytes":[83,104,111,119,32,115,104,111,114,116,32,102,114,101,101,32,115,112,97,99,101,32,38,108,97,98,101,108],"value":"Show short free space &label"}, {"hash":219781266,"name":"tfrmoptionslayout.chkshowmiddletoolbar.caption","sourcebytes":[83,104,111,119,32,109,105,100,100,108,101,32,116,111,111,108,98,97,114],"value":"Show middle toolbar"} ]} ����������������������������doublecmd-1.1.22/src/frames/foptionslayout.pas������������������������������������������������������0000644�0001750�0000144�00000011242�14743153644�020456� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Layout options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsLayout; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, fOptionsFrame; type { TfrmOptionsLayout } TfrmOptionsLayout = class(TOptionsEditor) cbFlatDiskPanel: TCheckBox; cbFlatInterface: TCheckBox; cbFreespaceInd: TCheckBox; cbLogWindow: TCheckBox; cbPanelOfOperations: TCheckBox; cbProgInMenuBar: TCheckBox; cbShowCmdLine: TCheckBox; cbShowCurDir: TCheckBox; cbShowDiskPanel: TCheckBox; cbShowDriveFreeSpace: TCheckBox; cbShowDrivesListButton: TCheckBox; cbShowKeysPanel: TCheckBox; cbShowMainMenu: TCheckBox; cbShowMainToolBar: TCheckBox; cbShowStatusBar: TCheckBox; cbShowTabHeader: TCheckBox; cbShowTabs: TCheckBox; cbTermWindow: TCheckBox; cbTwoDiskPanels: TCheckBox; cbShowShortDriveFreeSpace: TCheckBox; chkShowMiddleToolBar: TCheckBox; gbScreenLayout: TGroupBox; procedure cbShowDiskPanelChange(Sender: TObject); procedure cbShowDriveFreeSpaceChange(Sender: TObject); protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng; { TfrmOptionsLayout } procedure TfrmOptionsLayout.cbShowDiskPanelChange(Sender: TObject); begin cbTwoDiskPanels.Enabled := cbShowDiskPanel.Checked; cbFlatDiskPanel.Enabled := cbShowDiskPanel.Checked; end; procedure TfrmOptionsLayout.cbShowDriveFreeSpaceChange(Sender: TObject); begin cbShowShortDriveFreeSpace.Enabled:= cbShowDriveFreeSpace.Checked; if not(cbShowDriveFreeSpace.Checked) then cbShowShortDriveFreeSpace.Checked:= false; end; class function TfrmOptionsLayout.GetIconIndex: Integer; begin Result := 7; end; class function TfrmOptionsLayout.GetTitle: String; begin Result := rsOptionsEditorLayout; end; procedure TfrmOptionsLayout.Load; begin cbShowMainMenu.Checked := gMainMenu; cbShowMainToolBar.Checked := gButtonBar; chkShowMiddleToolBar.Checked := gMiddleToolBar; cbShowDiskPanel.Checked := gDriveBar1; cbTwoDiskPanels.Checked := gDriveBar2; cbFlatDiskPanel.Checked := gDriveBarFlat; cbShowDrivesListButton.Checked := gDrivesListButton; cbShowTabs.Checked := gDirectoryTabs; cbShowCurDir.Checked := gCurDir; cbShowTabHeader.Checked := gTabHeader; cbShowStatusBar.Checked := gStatusBar; cbShowCmdLine.Checked := gCmdLine; cbShowKeysPanel.Checked := gKeyButtons; cbFlatInterface.Checked := gInterfaceFlat; cbLogWindow.Checked := gLogWindow; cbTermWindow.Checked := gTermWindow; cbShowDriveFreeSpace.Checked := gDriveFreeSpace; cbFreespaceInd.Checked := gDriveInd; cbProgInMenuBar.Checked := gProgInMenuBar; cbPanelOfOperations.Checked := gPanelOfOp; cbShowShortDriveFreeSpace.Checked:= gShortFormatDriveInfo; end; function TfrmOptionsLayout.Save: TOptionsEditorSaveFlags; begin Result := []; gMainMenu := cbShowMainMenu.Checked; gButtonBar := cbShowMainToolBar.Checked; gMiddleToolBar := chkShowMiddleToolBar.Checked; gDriveBar1 := cbShowDiskPanel.Checked; gDriveBar2 := cbTwoDiskPanels.Checked; gDriveBarFlat := cbFlatDiskPanel.Checked; gDrivesListButton := cbShowDrivesListButton.Checked; gDirectoryTabs := cbShowTabs.Checked; gCurDir := cbShowCurDir.Checked; gTabHeader := cbShowTabHeader.Checked; gStatusBar := cbShowStatusBar.Checked; gCmdLine := cbShowCmdLine.Checked; gKeyButtons := cbShowKeysPanel.Checked; gInterfaceFlat := cbFlatInterface.Checked; gLogWindow := cbLogWindow.Checked; gTermWindow := cbTermWindow.Checked; gDriveFreeSpace := cbShowDriveFreeSpace.Checked; gDriveInd := cbFreespaceInd.Checked; gProgInMenuBar := cbProgInMenuBar.Checked; gPanelOfOp := cbPanelOfOperations.Checked; gShortFormatDriveInfo := cbShowShortDriveFreeSpace.Checked; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionslog.lfm���������������������������������������������������������0000644�0001750�0000144�00000027243�14743153644�017725� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsLog: TfrmOptionsLog Height = 522 Width = 528 HelpKeyword = '/configuration.html#ConfigLog' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 522 ClientWidth = 528 ParentShowHint = False ShowHint = True DesignLeft = 666 DesignTop = 236 object gbLogFile: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 125 Top = 6 Width = 516 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'File operation log file' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ClientHeight = 100 ClientWidth = 512 TabOrder = 0 object cbLogFile: TCheckBox AnchorSideTop.Control = fneLogFileName AnchorSideTop.Side = asrCenter Left = 10 Height = 24 Top = 8 Width = 133 Caption = 'C&reate a log file:' OnChange = cbLogFileChange TabOrder = 0 end object fneLogFileName: TFileNameEdit AnchorSideLeft.Control = cbLogFile AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbLogFile AnchorSideRight.Control = btnRelativeLogFile Left = 147 Height = 28 Top = 6 Width = 307 DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 4 BorderSpacing.Top = 4 BorderSpacing.Bottom = 4 MaxLength = 0 TabOrder = 1 end object cbIncludeDateInLogFilename: TCheckBox AnchorSideLeft.Control = cbLogFile AnchorSideTop.Control = fneLogFileName AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 38 Width = 210 BorderSpacing.Bottom = 4 Caption = 'Include date in log filename' OnChange = cbIncludeDateInLogFilenameChange TabOrder = 2 end object btnRelativeLogFile: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneLogFileName AnchorSideRight.Control = btnViewLogFile AnchorSideBottom.Control = fneLogFileName AnchorSideBottom.Side = asrBottom Left = 454 Height = 28 Hint = 'Some functions to select appropriate path' Top = 6 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeLogFileClick end object btnViewLogFile: TSpeedButton AnchorSideTop.Control = fneLogFileName AnchorSideRight.Control = gbLogFile AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneLogFileName AnchorSideBottom.Side = asrBottom Left = 478 Height = 28 Hint = 'View log file content' Top = 6 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36030000424D3603000000000000360000002800000010000000100000000100 18000000000000030000130B0000130B00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C17213B6E9E3A6EA000000000000000000000000000 00000000000000000000000000000000000000000000000000003A83CC44C8FF 29B2FF316DA70000000000000000000000000000000000000000000000000000 000000000000000000003881CC55DBFF3AC6FF82756C6F6C6B69696C68696F73 6F66CFAA61B87E0BB67D0AB67D0AB67C0AB67D0AB77F0F7F580A0000002980DB 9F928C7D7773E9D7A3FFF5B0FFEEA8E7CA94737379F6FBFFF2F7FFF2F7FFF2F6 FFF2F7FFF7FFFFB77F0F000000C98506828088E9D8A5FFF8BBFFEFB2FFE7A6FF E6A6E6C28984858AECECEDECECEDEAEBEEEAEBEEF5FBFFB67D0A000000C08511 7F8290FFF2AFFFEFB2FFE9ABFFE7B3FFEFCAFFE09C7B7B7EEAE9E8EAE9E8E6E6 E6E6E6E6F5FBFFB67C09000000BD8412868C9AFFEAA5FFE6A4FFE7B2FFEDC8FF F7E3FFDC96858689E5E4E3E5E4E3E0E0E1E0E0E1F5FBFFB67C09000000BB8210 9DA3B0ECCE97FFE4A3FFEEC9FFF7E3FFF3DAECBE8096979AE1E1E0DEDDDCDBDB DCDBDBDCF5FBFFB67C09000000B9800DDDE3EE9E9B9BEECA8FFFDD9AFFDA95EE C2829B9895D9D7D7D9D7D7D9D7D7D8D6D8D8D6D8F6FCFFB67C0A000000B77E0B F9FFFFC4C4C6A5A4A6A4A4A7A4A3A6B1AFB3D6D4D3D4D2D3D4D2D3D4D2D3D4D2 D3D4D2D3F6FCFFB67D0A000000B67D0AF7FDFFCFCED0CFCECECCCBCDCFCECECC CBCDCCCBCDCCCBCDCFCECECCCBCDCCCBCDCCCBCDF6FCFFB67D0A000000B67D0C F5FDFFF3F8FFF5F9FFF6FBFFF6FBFFF6FBFFF6FAFFF5FAFFF5F9FFF4F8FFF3F7 FFF3F7FFF4FDFFB67D0C000000B67F10F7E4C0DCAA4ADDAB4BDDAC4CDDAC4CDD AC4CDDAC4CDDAC4CDDAC4CDDAB4BDCAB4ADCAA4AF7E4C0B67F10000000B88216 EFD2A0EDCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF 9BEDCF9BEFD2A0B88216000000825D14B88217B78114B68114B68114B68114B6 8114B68114B68114B68114B68114B68114B78114B88217825D14 } OnClick = btnViewLogFileClick end object cbLogFileCount: TCheckBox AnchorSideLeft.Control = cbIncludeDateInLogFilename AnchorSideTop.Control = seLogFileCount AnchorSideTop.Side = asrCenter Left = 10 Height = 24 Top = 68 Width = 182 Caption = 'Maximum log file count' OnChange = cbLogFileCountChange TabOrder = 3 end object seLogFileCount: TSpinEditEx AnchorSideLeft.Control = cbLogFileCount AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbIncludeDateInLogFilename AnchorSideTop.Side = asrBottom Left = 204 Height = 28 Top = 66 Width = 80 BorderSpacing.Left = 12 MaxLength = 0 TabOrder = 4 end end object gbLogFileOp: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbLogFile AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 212 Top = 135 Width = 516 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 Caption = 'Log operations' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 4 ChildSizing.VerticalSpacing = 2 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 187 ClientWidth = 512 TabOrder = 1 object cbLogStartShutdown: TCheckBox AnchorSideLeft.Control = cbLogCpMvLn AnchorSideTop.Control = cbLogVFS AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 134 Width = 125 Caption = 'Start/shutdown' TabOrder = 5 end object cbLogCpMvLn: TCheckBox AnchorSideTop.Control = gbLogFileOp Left = 10 Height = 24 Top = 4 Width = 232 Caption = 'Cop&y/Move/Create link/symlink' TabOrder = 0 end object cbLogDelete: TCheckBox AnchorSideLeft.Control = cbLogCpMvLn AnchorSideTop.Control = cbLogCpMvLn AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 30 Width = 68 Caption = '&Delete' TabOrder = 1 end object cbLogDirOp: TCheckBox AnchorSideLeft.Control = cbLogCpMvLn AnchorSideTop.Control = cbLogDelete AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 56 Width = 191 Caption = 'Crea&te/Delete directories' TabOrder = 2 end object cbLogArcOp: TCheckBox AnchorSideLeft.Control = cbLogCpMvLn AnchorSideTop.Control = cbLogDirOp AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 82 Width = 109 Caption = '&Pack/Unpack' TabOrder = 3 end object cbLogVFS: TCheckBox AnchorSideLeft.Control = cbLogCpMvLn AnchorSideTop.Control = cbLogArcOp AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 108 Width = 148 Caption = '&File system plugins' TabOrder = 4 end object cbLogCommandLineExecution: TCheckBox AnchorSideLeft.Control = cbLogCpMvLn AnchorSideTop.Control = cbLogStartShutdown AnchorSideTop.Side = asrBottom Left = 10 Height = 24 Top = 160 Width = 244 BorderSpacing.Bottom = 15 Caption = 'External command line execution' TabOrder = 6 end end object gbLogFileStatus: TGroupBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbLogFileOp AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 109 Top = 351 Width = 516 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 Caption = 'Operation status' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 4 ChildSizing.VerticalSpacing = 2 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 84 ClientWidth = 512 TabOrder = 2 object cbLogSuccess: TCheckBox Left = 10 Height = 24 Top = 4 Width = 199 Caption = 'Log &successful operations' TabOrder = 0 end object cbLogErrors: TCheckBox Left = 10 Height = 24 Top = 30 Width = 199 Caption = 'Log &errors' TabOrder = 1 end object cbLogInfo: TCheckBox Left = 10 Height = 24 Top = 56 Width = 199 Caption = 'Log &information messages' TabOrder = 2 end end object pmPathHelper: TPopupMenu[3] Left = 440 Top = 64 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionslog.lrj���������������������������������������������������������0000644�0001750�0000144�00000006717�14743153644�017741� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":142148549,"name":"tfrmoptionslog.gblogfile.caption","sourcebytes":[70,105,108,101,32,111,112,101,114,97,116,105,111,110,32,108,111,103,32,102,105,108,101],"value":"File operation log file"}, {"hash":198650170,"name":"tfrmoptionslog.cblogfile.caption","sourcebytes":[67,38,114,101,97,116,101,32,97,32,108,111,103,32,102,105,108,101,58],"value":"C&reate a log file:"}, {"hash":40358133,"name":"tfrmoptionslog.cbincludedateinlogfilename.caption","sourcebytes":[73,110,99,108,117,100,101,32,100,97,116,101,32,105,110,32,108,111,103,32,102,105,108,101,110,97,109,101],"value":"Include date in log filename"}, {"hash":15252584,"name":"tfrmoptionslog.btnrelativelogfile.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":68945492,"name":"tfrmoptionslog.btnviewlogfile.hint","sourcebytes":[86,105,101,119,32,108,111,103,32,102,105,108,101,32,99,111,110,116,101,110,116],"value":"View log file content"}, {"hash":45247380,"name":"tfrmoptionslog.cblogfilecount.caption","sourcebytes":[77,97,120,105,109,117,109,32,108,111,103,32,102,105,108,101,32,99,111,117,110,116],"value":"Maximum log file count"}, {"hash":220047267,"name":"tfrmoptionslog.gblogfileop.caption","sourcebytes":[76,111,103,32,111,112,101,114,97,116,105,111,110,115],"value":"Log operations"}, {"hash":88335854,"name":"tfrmoptionslog.cblogstartshutdown.caption","sourcebytes":[83,116,97,114,116,47,115,104,117,116,100,111,119,110],"value":"Start/shutdown"}, {"hash":459707,"name":"tfrmoptionslog.cblogcpmvln.caption","sourcebytes":[67,111,112,38,121,47,77,111,118,101,47,67,114,101,97,116,101,32,108,105,110,107,47,115,121,109,108,105,110,107],"value":"Cop&y/Move/Create link/symlink"}, {"hash":179055749,"name":"tfrmoptionslog.cblogdelete.caption","sourcebytes":[38,68,101,108,101,116,101],"value":"&Delete"}, {"hash":115504435,"name":"tfrmoptionslog.cblogdirop.caption","sourcebytes":[67,114,101,97,38,116,101,47,68,101,108,101,116,101,32,100,105,114,101,99,116,111,114,105,101,115],"value":"Crea&te/Delete directories"}, {"hash":101916283,"name":"tfrmoptionslog.cblogarcop.caption","sourcebytes":[38,80,97,99,107,47,85,110,112,97,99,107],"value":"&Pack/Unpack"}, {"hash":210966067,"name":"tfrmoptionslog.cblogvfs.caption","sourcebytes":[38,70,105,108,101,32,115,121,115,116,101,109,32,112,108,117,103,105,110,115],"value":"&File system plugins"}, {"hash":60018910,"name":"tfrmoptionslog.cblogcommandlineexecution.caption","sourcebytes":[69,120,116,101,114,110,97,108,32,99,111,109,109,97,110,100,32,108,105,110,101,32,101,120,101,99,117,116,105,111,110],"value":"External command line execution"}, {"hash":254095107,"name":"tfrmoptionslog.gblogfilestatus.caption","sourcebytes":[79,112,101,114,97,116,105,111,110,32,115,116,97,116,117,115],"value":"Operation status"}, {"hash":258209475,"name":"tfrmoptionslog.cblogsuccess.caption","sourcebytes":[76,111,103,32,38,115,117,99,99,101,115,115,102,117,108,32,111,112,101,114,97,116,105,111,110,115],"value":"Log &successful operations"}, {"hash":211480499,"name":"tfrmoptionslog.cblogerrors.caption","sourcebytes":[76,111,103,32,38,101,114,114,111,114,115],"value":"Log &errors"}, {"hash":29542339,"name":"tfrmoptionslog.cbloginfo.caption","sourcebytes":[76,111,103,32,38,105,110,102,111,114,109,97,116,105,111,110,32,109,101,115,115,97,103,101,115],"value":"Log &information messages"} ]} �������������������������������������������������doublecmd-1.1.22/src/frames/foptionslog.pas���������������������������������������������������������0000644�0001750�0000144�00000012572�14743153644�017731� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Log options page Copyright (C) 2006-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsLog; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, StdCtrls, EditBtn, Buttons, Menus, SpinEx, fOptionsFrame; type { TfrmOptionsLog } TfrmOptionsLog = class(TOptionsEditor) cbLogArcOp: TCheckBox; cbLogCpMvLn: TCheckBox; cbLogDelete: TCheckBox; cbLogDirOp: TCheckBox; cbLogErrors: TCheckBox; cbLogFile: TCheckBox; cbIncludeDateInLogFilename: TCheckBox; cbLogInfo: TCheckBox; cbLogCommandLineExecution: TCheckBox; cbLogSuccess: TCheckBox; cbLogVFS: TCheckBox; cbLogStartShutdown: TCheckBox; cbLogFileCount: TCheckBox; fneLogFileName: TFileNameEdit; gbLogFile: TGroupBox; gbLogFileOp: TGroupBox; gbLogFileStatus: TGroupBox; btnRelativeLogFile: TSpeedButton; pmPathHelper: TPopupMenu; btnViewLogFile: TSpeedButton; seLogFileCount: TSpinEditEx; procedure btnRelativeLogFileClick(Sender: TObject); procedure cbIncludeDateInLogFilenameChange(Sender: TObject); procedure cbLogFileChange(Sender: TObject); procedure btnViewLogFileClick(Sender: TObject); procedure cbLogFileCountChange(Sender: TObject); protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses fMain, uGlobs, uLng, uSpecialDir; { TfrmOptionsLog } class function TfrmOptionsLog.GetIconIndex: integer; begin Result := 23; end; class function TfrmOptionsLog.GetTitle: string; begin Result := rsOptionsEditorLog; end; procedure TfrmOptionsLog.cbLogFileChange(Sender: TObject); begin cbIncludeDateInLogFilename.Enabled := cbLogFile.Checked; cbIncludeDateInLogFilenameChange(cbIncludeDateInLogFilename); end; procedure TfrmOptionsLog.btnViewLogFileClick(Sender: TObject); begin frmMain.Commands.cm_ViewLogFile([]); end; procedure TfrmOptionsLog.cbLogFileCountChange(Sender: TObject); begin if not cbLogFileCount.Checked then seLogFileCount.Value:= 0 else if seLogFileCount.Value = 0 then seLogFileCount.Value:= 7; end; procedure TfrmOptionsLog.btnRelativeLogFileClick(Sender: TObject); begin fneLogFileName.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneLogFileName, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsLog.cbIncludeDateInLogFilenameChange(Sender: TObject); begin cbLogFileCount.Enabled:= cbLogFile.Checked and cbIncludeDateInLogFilename.Checked; seLogFileCount.Enabled:= cbLogFileCount.Enabled; end; procedure TfrmOptionsLog.Load; begin seLogFileCount.Value:= gLogFileCount; cbLogFileCount.Checked:= gLogFileCount > 0; cbIncludeDateInLogFilename.Checked := gLogFileWithDateInName; cbLogFile.Checked := gLogFile; cbLogFileChange(cbLogFile); fneLogFileName.FileName := gLogFileName; cbLogCpMvLn.Checked := (log_cp_mv_ln in gLogOptions); cbLogDelete.Checked := (log_delete in gLogOptions); cbLogDirOp.Checked := (log_dir_op in gLogOptions); cbLogArcOp.Checked := (log_arc_op in gLogOptions); cbLogVFS.Checked := (log_vfs_op in gLogOptions); cbLogStartShutdown.Checked := (log_start_shutdown in gLogOptions); cbLogCommandLineExecution.Checked := (log_commandlineexecution in gLogOptions); cbLogSuccess.Checked := (log_success in gLogOptions); cbLogErrors.Checked := (log_errors in gLogOptions); cbLogInfo.Checked := (log_info in gLogOptions); gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper, mp_PATHHELPER, nil); end; function TfrmOptionsLog.Save: TOptionsEditorSaveFlags; begin Result := []; gLogFile := cbLogFile.Checked; gLogFileCount := seLogFileCount.Value; gLogFileWithDateInName := cbIncludeDateInLogFilename.Checked; gLogFileName := fneLogFileName.FileName; gLogOptions := []; // Reset log options if cbLogCpMvLn.Checked then Include(gLogOptions, log_cp_mv_ln); if cbLogDelete.Checked then Include(gLogOptions, log_delete); if cbLogDirOp.Checked then Include(gLogOptions, log_dir_op); if cbLogArcOp.Checked then Include(gLogOptions, log_arc_op); if cbLogVFS.Checked then Include(gLogOptions, log_vfs_op); if cbLogStartShutdown.Checked then Include(gLogOptions, log_start_shutdown); if cbLogCommandLineExecution.Checked then Include(gLogOptions, log_commandlineexecution); if cbLogSuccess.Checked then Include(gLogOptions, log_success); if cbLogErrors.Checked then Include(gLogOptions, log_errors); if cbLogInfo.Checked then Include(gLogOptions, log_info); end; end. ��������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsmisc.lfm��������������������������������������������������������0000644�0001750�0000144�00000053772�14743153644�020105� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsMisc: TfrmOptionsMisc Height = 572 Width = 719 HelpKeyword = '/configuration.html#ConfigMisc' HorzScrollBar.Page = 1 VertScrollBar.Page = 1 AutoScroll = True ClientHeight = 572 ClientWidth = 719 ParentShowHint = False ShowHint = True DesignLeft = 398 DesignTop = 42 object gbExtended: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 259 Top = 6 Width = 707 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 6 ClientHeight = 239 ClientWidth = 703 TabOrder = 0 object chkShowSplashForm: TCheckBox Left = 12 Height = 19 Top = 6 Width = 122 Caption = 'Show &splash screen' TabOrder = 0 end object chkShowWarningMessages: TCheckBox AnchorSideTop.Control = chkShowSplashForm AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 29 Width = 251 BorderSpacing.Top = 4 Caption = 'Show &warning messages ("OK" button only)' TabOrder = 1 end object chkThumbSave: TCheckBox AnchorSideTop.Control = dblThumbnails AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 154 Width = 154 BorderSpacing.Top = 4 Caption = '&Save thumbnails in cache' TabOrder = 5 end object lblThumbSize: TLabel AnchorSideTop.Control = speThumbWidth AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 183 Width = 82 Caption = '&Thumbnail size:' FocusControl = speThumbWidth ParentColor = False end object dblThumbnails: TDividerBevel AnchorSideLeft.Control = gbExtended AnchorSideTop.Control = cmbDefaultEncoding AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbExtended AnchorSideRight.Side = asrBottom Left = 12 Height = 15 Top = 135 Width = 679 Caption = 'Thumbnails' Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 12 ParentFont = False end object speThumbWidth: TSpinEdit AnchorSideLeft.Control = lblThumbSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = chkThumbSave AnchorSideTop.Side = asrBottom Left = 100 Height = 23 Top = 179 Width = 50 BorderSpacing.Left = 6 BorderSpacing.Top = 6 MaxValue = 512 MinValue = 16 TabOrder = 6 Value = 16 end object speThumbHeight: TSpinEdit AnchorSideLeft.Control = lblThumbSeparator AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = speThumbWidth Left = 169 Height = 23 Top = 179 Width = 50 BorderSpacing.Left = 6 MaxValue = 512 MinValue = 16 TabOrder = 7 Value = 16 end object lblThumbSeparator: TLabel AnchorSideLeft.Control = speThumbWidth AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = speThumbWidth AnchorSideTop.Side = asrCenter Left = 156 Height = 15 Top = 183 Width = 7 BorderSpacing.Left = 6 Caption = 'X' ParentColor = False end object lblThumbPixels: TLabel AnchorSideLeft.Control = speThumbHeight AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = speThumbWidth AnchorSideTop.Side = asrCenter Left = 225 Height = 15 Top = 183 Width = 30 BorderSpacing.Left = 6 Caption = 'pixels' ParentColor = False end object btnThumbCompactCache: TButton AnchorSideTop.Control = speThumbWidth AnchorSideTop.Side = asrBottom Left = 12 Height = 25 Top = 208 Width = 272 AutoSize = True BorderSpacing.Top = 6 Caption = '&Remove thumbnails for no longer existing files' OnClick = btnThumbCompactCacheClick TabOrder = 8 end object chkGoToRoot: TCheckBox AnchorSideTop.Control = chkShowWarningMessages AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 52 Width = 304 BorderSpacing.Top = 4 Caption = 'Always &go to the root of a drive when changing drives' TabOrder = 2 end object chkShowCurDirTitleBar: TCheckBox AnchorSideTop.Control = chkGoToRoot AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 75 Width = 291 BorderSpacing.Top = 4 Caption = 'Show ¤t directory in the main window title bar' TabOrder = 3 end object lblDefaultEncoding: TLabel AnchorSideLeft.Control = chkShowSplashForm AnchorSideTop.Control = cmbDefaultEncoding AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 104 Width = 179 Caption = '&Default single-byte text encoding:' FocusControl = cmbDefaultEncoding ParentColor = False end object cmbDefaultEncoding: TComboBox AnchorSideLeft.Control = lblDefaultEncoding AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = chkShowCurDirTitleBar AnchorSideTop.Side = asrBottom Left = 209 Height = 23 Top = 100 Width = 100 BorderSpacing.Left = 18 BorderSpacing.Top = 6 ItemHeight = 15 Style = csDropDownList TabOrder = 4 end end object gbTCExportImport: TGroupBox[1] AnchorSideLeft.Control = gbExtended AnchorSideTop.Control = gbFileComments AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbExtended AnchorSideRight.Side = asrBottom Left = 6 Height = 164 Top = 344 Width = 707 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 12 Caption = 'Regarding TC export/import:' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 2 ClientHeight = 144 ClientWidth = 703 TabOrder = 2 TabStop = True Visible = False object fneTCExecutableFilename: TFileNameEdit AnchorSideLeft.Control = gbTCExportImport AnchorSideTop.Control = lblTCExecutable AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeTCExecutableFile Left = 6 Height = 23 Top = 23 Width = 667 DialogOptions = [ofPathMustExist, ofFileMustExist] Filter = 'executables|*.exe|any files|*.*' FilterIndex = 1 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 0 end object btnRelativeTCExecutableFile: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneTCExecutableFilename AnchorSideRight.Control = gbTCExportImport AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneTCExecutableFilename AnchorSideBottom.Side = asrBottom Left = 673 Height = 23 Hint = 'Some functions to select appropriate path' Top = 23 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeTCExecutableFileClick end object lblTCExecutable: TLabel AnchorSideLeft.Control = gbTCExportImport AnchorSideTop.Control = gbTCExportImport AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 6 Width = 76 Alignment = taRightJustify Caption = 'TC executable:' ParentColor = False end object fneTCConfigFilename: TFileNameEdit AnchorSideLeft.Control = gbTCExportImport AnchorSideTop.Control = lblTCConfig AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeTCConfigFile Left = 6 Height = 23 Top = 69 Width = 643 DialogOptions = [ofPathMustExist, ofFileMustExist] Filter = 'ini configuration file|*.ini|any file|*.*' FilterIndex = 1 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 1 end object lblTCConfig: TLabel AnchorSideLeft.Control = gbTCExportImport AnchorSideTop.Control = fneTCExecutableFilename AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 52 Width = 96 BorderSpacing.Top = 6 Caption = 'Configuration file:' ParentColor = False end object btnRelativeTCConfigFile: TSpeedButton AnchorSideTop.Control = fneTCConfigFilename AnchorSideRight.Control = btnViewConfigFile AnchorSideBottom.Control = fneTCConfigFilename AnchorSideBottom.Side = asrBottom Left = 649 Height = 23 Hint = 'Some functions to select appropriate path' Top = 69 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeTCConfigFileClick end object btnViewConfigFile: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneTCConfigFilename AnchorSideRight.Control = gbTCExportImport AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneTCConfigFilename AnchorSideBottom.Side = asrBottom Left = 673 Height = 23 Hint = 'View configuration file content' Top = 69 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36030000424D3603000000000000360000002800000010000000100000000100 18000000000000030000130B0000130B00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C17213B6E9E3A6EA000000000000000000000000000 00000000000000000000000000000000000000000000000000003A83CC44C8FF 29B2FF316DA70000000000000000000000000000000000000000000000000000 000000000000000000003881CC55DBFF3AC6FF82756C6F6C6B69696C68696F73 6F66CFAA61B87E0BB67D0AB67D0AB67C0AB67D0AB77F0F7F580A0000002980DB 9F928C7D7773E9D7A3FFF5B0FFEEA8E7CA94737379F6FBFFF2F7FFF2F7FFF2F6 FFF2F7FFF7FFFFB77F0F000000C98506828088E9D8A5FFF8BBFFEFB2FFE7A6FF E6A6E6C28984858AECECEDECECEDEAEBEEEAEBEEF5FBFFB67D0A000000C08511 7F8290FFF2AFFFEFB2FFE9ABFFE7B3FFEFCAFFE09C7B7B7EEAE9E8EAE9E8E6E6 E6E6E6E6F5FBFFB67C09000000BD8412868C9AFFEAA5FFE6A4FFE7B2FFEDC8FF F7E3FFDC96858689E5E4E3E5E4E3E0E0E1E0E0E1F5FBFFB67C09000000BB8210 9DA3B0ECCE97FFE4A3FFEEC9FFF7E3FFF3DAECBE8096979AE1E1E0DEDDDCDBDB DCDBDBDCF5FBFFB67C09000000B9800DDDE3EE9E9B9BEECA8FFFDD9AFFDA95EE C2829B9895D9D7D7D9D7D7D9D7D7D8D6D8D8D6D8F6FCFFB67C0A000000B77E0B F9FFFFC4C4C6A5A4A6A4A4A7A4A3A6B1AFB3D6D4D3D4D2D3D4D2D3D4D2D3D4D2 D3D4D2D3F6FCFFB67D0A000000B67D0AF7FDFFCFCED0CFCECECCCBCDCFCECECC CBCDCCCBCDCCCBCDCFCECECCCBCDCCCBCDCCCBCDF6FCFFB67D0A000000B67D0C F5FDFFF3F8FFF5F9FFF6FBFFF6FBFFF6FBFFF6FAFFF5FAFFF5F9FFF4F8FFF3F7 FFF3F7FFF4FDFFB67D0C000000B67F10F7E4C0DCAA4ADDAB4BDDAC4CDDAC4CDD AC4CDDAC4CDDAC4CDDAC4CDDAB4BDCAB4ADCAA4AF7E4C0B67F10000000B88216 EFD2A0EDCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF 9BEDCF9BEFD2A0B88216000000825D14B88217B78114B68114B68114B68114B6 8114B68114B68114B68114B68114B68114B78114B88217825D14 } OnClick = btnViewConfigFileClick end object edOutputPathForToolbar: TEdit AnchorSideLeft.Control = gbTCExportImport AnchorSideTop.Control = lblTCPathForTool AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnOutputPathForToolbar Left = 6 Height = 23 Top = 115 Width = 643 Anchors = [akTop, akLeft, akRight] TabOrder = 2 end object lblTCPathForTool: TLabel AnchorSideLeft.Control = gbTCExportImport AnchorSideTop.Control = fneTCConfigFilename AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 98 Width = 108 BorderSpacing.Top = 6 Caption = 'Toolbar output path:' ParentColor = False end object btnOutputPathForToolbar: TButton AnchorSideTop.Control = edOutputPathForToolbar AnchorSideRight.Control = btnRelativeOutputPathForToolbar AnchorSideBottom.Control = edOutputPathForToolbar AnchorSideBottom.Side = asrBottom Left = 649 Height = 23 Top = 115 Width = 24 Anchors = [akTop, akRight, akBottom] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnOutputPathForToolbarClick TabOrder = 3 end object btnRelativeOutputPathForToolbar: TSpeedButton AnchorSideTop.Control = edOutputPathForToolbar AnchorSideRight.Control = gbTCExportImport AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edOutputPathForToolbar AnchorSideBottom.Side = asrBottom Left = 673 Height = 23 Hint = 'Some functions to select appropriate path' Top = 115 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeOutputPathForToolbarClick end end object gbFileComments: TGroupBox[2] AnchorSideLeft.Control = gbExtended AnchorSideTop.Control = gbExtended AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbExtended AnchorSideRight.Side = asrBottom Left = 6 Height = 55 Top = 277 Width = 707 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 12 Caption = 'File comments (descript.ion)' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 8 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 35 ClientWidth = 703 TabOrder = 1 object lblDescrDefaultEncoding: TLabel Left = 6 Height = 23 Top = 6 Width = 94 Caption = 'Default encoding:' Layout = tlCenter ParentColor = False end object cmbDescDefaultEncoding: TComboBox Left = 108 Height = 23 Top = 6 Width = 100 ItemHeight = 15 Items.Strings = ( 'OEM' 'ANSI' 'UTF8' ) Style = csDropDownList TabOrder = 0 end object chkDescCreateUnicode: TCheckBox Left = 216 Height = 23 Top = 6 Width = 181 Caption = 'Create new with the encoding:' OnChange = chkDescCreateUnicodeChange TabOrder = 1 end object cmbDescCreateEncoding: TComboBox Left = 405 Height = 23 Top = 6 Width = 100 ItemHeight = 15 Items.Strings = ( 'UTF8BOM' 'UTF16LE' 'UTF16BE' ) Style = csDropDownList TabOrder = 2 end end object pmPathHelper: TPopupMenu[3] Left = 656 Top = 32 end end ������doublecmd-1.1.22/src/frames/foptionsmisc.lrj��������������������������������������������������������0000644�0001750�0000144�00000012107�14743153644�020101� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":71209118,"name":"tfrmoptionsmisc.chkshowsplashform.caption","sourcebytes":[83,104,111,119,32,38,115,112,108,97,115,104,32,115,99,114,101,101,110],"value":"Show &splash screen"}, {"hash":1395673,"name":"tfrmoptionsmisc.chkshowwarningmessages.caption","sourcebytes":[83,104,111,119,32,38,119,97,114,110,105,110,103,32,109,101,115,115,97,103,101,115,32,40,34,79,75,34,32,98,117,116,116,111,110,32,111,110,108,121,41],"value":"Show &warning messages (\"OK\" button only)"}, {"hash":114241301,"name":"tfrmoptionsmisc.chkthumbsave.caption","sourcebytes":[38,83,97,118,101,32,116,104,117,109,98,110,97,105,108,115,32,105,110,32,99,97,99,104,101],"value":"&Save thumbnails in cache"}, {"hash":38014346,"name":"tfrmoptionsmisc.lblthumbsize.caption","sourcebytes":[38,84,104,117,109,98,110,97,105,108,32,115,105,122,101,58],"value":"&Thumbnail size:"}, {"hash":59888115,"name":"tfrmoptionsmisc.dblthumbnails.caption","sourcebytes":[84,104,117,109,98,110,97,105,108,115],"value":"Thumbnails"}, {"hash":88,"name":"tfrmoptionsmisc.lblthumbseparator.caption","sourcebytes":[88],"value":"X"}, {"hash":124841011,"name":"tfrmoptionsmisc.lblthumbpixels.caption","sourcebytes":[112,105,120,101,108,115],"value":"pixels"}, {"hash":241754643,"name":"tfrmoptionsmisc.btnthumbcompactcache.caption","sourcebytes":[38,82,101,109,111,118,101,32,116,104,117,109,98,110,97,105,108,115,32,102,111,114,32,110,111,32,108,111,110,103,101,114,32,101,120,105,115,116,105,110,103,32,102,105,108,101,115],"value":"&Remove thumbnails for no longer existing files"}, {"hash":158470307,"name":"tfrmoptionsmisc.chkgotoroot.caption","sourcebytes":[65,108,119,97,121,115,32,38,103,111,32,116,111,32,116,104,101,32,114,111,111,116,32,111,102,32,97,32,100,114,105,118,101,32,119,104,101,110,32,99,104,97,110,103,105,110,103,32,100,114,105,118,101,115],"value":"Always &go to the root of a drive when changing drives"}, {"hash":3256530,"name":"tfrmoptionsmisc.chkshowcurdirtitlebar.caption","sourcebytes":[83,104,111,119,32,38,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,32,105,110,32,116,104,101,32,109,97,105,110,32,119,105,110,100,111,119,32,116,105,116,108,101,32,98,97,114],"value":"Show ¤t directory in the main window title bar"}, {"hash":138614058,"name":"tfrmoptionsmisc.lbldefaultencoding.caption","sourcebytes":[38,68,101,102,97,117,108,116,32,115,105,110,103,108,101,45,98,121,116,101,32,116,101,120,116,32,101,110,99,111,100,105,110,103,58],"value":"&Default single-byte text encoding:"}, {"hash":92360730,"name":"tfrmoptionsmisc.gbtcexportimport.caption","sourcebytes":[82,101,103,97,114,100,105,110,103,32,84,67,32,101,120,112,111,114,116,47,105,109,112,111,114,116,58],"value":"Regarding TC export/import:"}, {"hash":15252584,"name":"tfrmoptionsmisc.btnrelativetcexecutablefile.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":164330666,"name":"tfrmoptionsmisc.lbltcexecutable.caption","sourcebytes":[84,67,32,101,120,101,99,117,116,97,98,108,101,58],"value":"TC executable:"}, {"hash":109093002,"name":"tfrmoptionsmisc.lbltcconfig.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,102,105,108,101,58],"value":"Configuration file:"}, {"hash":15252584,"name":"tfrmoptionsmisc.btnrelativetcconfigfile.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":246620964,"name":"tfrmoptionsmisc.btnviewconfigfile.hint","sourcebytes":[86,105,101,119,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,102,105,108,101,32,99,111,110,116,101,110,116],"value":"View configuration file content"}, {"hash":125350026,"name":"tfrmoptionsmisc.lbltcpathfortool.caption","sourcebytes":[84,111,111,108,98,97,114,32,111,117,116,112,117,116,32,112,97,116,104,58],"value":"Toolbar output path:"}, {"hash":1054,"name":"tfrmoptionsmisc.btnoutputpathfortoolbar.caption","sourcebytes":[62,62],"value":">>"}, {"hash":15252584,"name":"tfrmoptionsmisc.btnrelativeoutputpathfortoolbar.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":11054073,"name":"tfrmoptionsmisc.gbfilecomments.caption","sourcebytes":[70,105,108,101,32,99,111,109,109,101,110,116,115,32,40,100,101,115,99,114,105,112,116,46,105,111,110,41],"value":"File comments (descript.ion)"}, {"hash":103169130,"name":"tfrmoptionsmisc.lbldescrdefaultencoding.caption","sourcebytes":[68,101,102,97,117,108,116,32,101,110,99,111,100,105,110,103,58],"value":"Default encoding:"}, {"hash":255918986,"name":"tfrmoptionsmisc.chkdesccreateunicode.caption","sourcebytes":[67,114,101,97,116,101,32,110,101,119,32,119,105,116,104,32,116,104,101,32,101,110,99,111,100,105,110,103,58],"value":"Create new with the encoding:"} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsmisc.pas��������������������������������������������������������0000644�0001750�0000144�00000021741�14743153644�020101� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Miscellaneous options page Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsMisc; {$mode objfpc}{$H+} interface uses EditBtn, Buttons, Menus, Classes, SysUtils, StdCtrls, Spin, ExtCtrls, DividerBevel, fOptionsFrame; type { TfrmOptionsMisc } TfrmOptionsMisc = class(TOptionsEditor) btnThumbCompactCache: TButton; chkShowSplashForm: TCheckBox; chkDescCreateUnicode: TCheckBox; chkGoToRoot: TCheckBox; chkShowCurDirTitleBar: TCheckBox; chkThumbSave: TCheckBox; chkShowWarningMessages: TCheckBox; cmbDescDefaultEncoding: TComboBox; cmbDescCreateEncoding: TComboBox; cmbDefaultEncoding: TComboBox; dblThumbnails: TDividerBevel; gbExtended: TGroupBox; gbFileComments: TGroupBox; lblDefaultEncoding: TLabel; lblDescrDefaultEncoding: TLabel; lblThumbPixels: TLabel; lblThumbSize: TLabel; lblThumbSeparator: TLabel; speThumbWidth: TSpinEdit; speThumbHeight: TSpinEdit; gbTCExportImport: TGroupBox; lblTCExecutable: TLabel; fneTCExecutableFilename: TFileNameEdit; btnRelativeTCExecutableFile: TSpeedButton; lblTCConfig: TLabel; fneTCConfigFilename: TFileNameEdit; btnRelativeTCConfigFile: TSpeedButton; btnViewConfigFile: TSpeedButton; lblTCPathForTool: TLabel; edOutputPathForToolbar: TEdit; btnOutputPathForToolbar: TButton; btnRelativeOutputPathForToolbar: TSpeedButton; pmPathHelper: TPopupMenu; procedure btnThumbCompactCacheClick(Sender: TObject); procedure btnRelativeTCExecutableFileClick(Sender: TObject); procedure btnRelativeTCConfigFileClick(Sender: TObject); procedure btnViewConfigFileClick(Sender: TObject); procedure btnOutputPathForToolbarClick(Sender: TObject); procedure btnRelativeOutputPathForToolbarClick(Sender: TObject); procedure chkDescCreateUnicodeChange(Sender: TObject); private FSplashForm: Boolean; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; procedure BringUsToTCConfigurationPage; implementation {$R *.lfm} uses LConvEncoding, fOptions, Forms, Dialogs, fMain, Controls, DCStrUtils, uDCUtils, uSpecialDir, uShowForm, uGlobs, uLng, uThumbnails, uConvEncoding, uEarlyConfig; { TfrmOptionsMisc } class function TfrmOptionsMisc.GetIconIndex: Integer; begin Result := 14; end; class function TfrmOptionsMisc.GetTitle: String; begin Result := rsOptionsEditorMiscellaneous; end; procedure TfrmOptionsMisc.btnThumbCompactCacheClick(Sender: TObject); begin TThumbnailManager.CompactCache; end; procedure TfrmOptionsMisc.Init; var Index: Integer; begin FSplashForm:= gSplashForm; GetSupportedEncodings(cmbDefaultEncoding.Items); for Index:= cmbDefaultEncoding.Items.Count - 1 downto 0 do begin if (not SingleByteEncoding(cmbDefaultEncoding.Items[Index])) then cmbDefaultEncoding.Items.Delete(Index); end; cmbDefaultEncoding.Items.Insert(0, UpperCase(EncodingNone)); fneTCExecutableFilename.Filter := ParseLineToFileFilter([rsFilterExecutableFiles, '*.exe', rsFilterAnyFiles, AllFilesMask]); fneTCConfigFilename.Filter := ParseLineToFileFilter([rsFilterIniConfigFiles, '*.ini', rsFilterAnyFiles, AllFilesMask]); end; procedure TfrmOptionsMisc.Load; var Index: Integer; begin chkShowSplashForm.Checked := gSplashForm; chkShowWarningMessages.Checked := gShowWarningMessages; chkThumbSave.Checked := gThumbSave; speThumbWidth.Value := gThumbSize.cx; speThumbHeight.Value := gThumbSize.cy; chkGoToRoot.Checked := gGoToRoot; chkShowCurDirTitleBar.Checked := gShowCurDirTitleBar; Index:= cmbDefaultEncoding.Items.IndexOf(gDefaultTextEncoding); if (Index < 0) then cmbDefaultEncoding.ItemIndex:= 0 else begin cmbDefaultEncoding.ItemIndex:= Index; end; {$IFDEF MSWINDOWS} gbTCExportImport.Visible:=True; fneTCExecutableFilename.FileName := gTotalCommanderExecutableFilename; fneTCConfigFilename.FileName := gTotalCommanderConfigFilename; edOutputPathForToolbar.Text := gTotalCommanderToolbarPath; fneTCExecutableFilename.DialogTitle := rsMsgLocateTCExecutable; fneTCConfigFilename.DialogTitle := rsMsgLocateTCConfiguation; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper, mp_PATHHELPER, nil); {$ENDIF} case gDescReadEncoding of meOEM: cmbDescDefaultEncoding.ItemIndex:= 0; meANSI: cmbDescDefaultEncoding.ItemIndex:= 1; meUTF8: cmbDescDefaultEncoding.ItemIndex:= 2; else cmbDescDefaultEncoding.ItemIndex:= 2; end; case gDescWriteEncoding of meUTF8BOM: cmbDescCreateEncoding.ItemIndex:= 0; meUTF16LE: cmbDescCreateEncoding.ItemIndex:= 1; meUTF16BE: cmbDescCreateEncoding.ItemIndex:= 2; else cmbDescCreateEncoding.ItemIndex:= 0; end; chkDescCreateUnicode.Checked:= gDescCreateUnicode; chkDescCreateUnicodeChange(chkDescCreateUnicode); end; function TfrmOptionsMisc.Save: TOptionsEditorSaveFlags; begin Result := []; gSplashForm := chkShowSplashForm.Checked; gShowWarningMessages := chkShowWarningMessages.Checked; gThumbSave := chkThumbSave.Checked; gThumbSize.cx := speThumbWidth.Value; gThumbSize.cy := speThumbHeight.Value; gGoToRoot := chkGoToRoot.Checked; gShowCurDirTitleBar := chkShowCurDirTitleBar.Checked; gDefaultTextEncoding := NormalizeEncoding(cmbDefaultEncoding.Text); {$IFDEF MSWINDOWS} gTotalCommanderExecutableFilename := fneTCExecutableFilename.FileName; gTotalCommanderConfigFilename := fneTCConfigFilename.FileName; gTotalCommanderToolbarPath := edOutputPathForToolbar.Text; {$ENDIF} case cmbDescDefaultEncoding.ItemIndex of 0: gDescReadEncoding:= meOEM; 1: gDescReadEncoding:= meANSI; 2: gDescReadEncoding:= meUTF8; end; case cmbDescCreateEncoding.ItemIndex of 0: gDescWriteEncoding:= meUTF8BOM; 1: gDescWriteEncoding:= meUTF16LE; 2: gDescWriteEncoding:= meUTF16BE; end; gDescCreateUnicode:= chkDescCreateUnicode.Checked; if gSplashForm <> FSplashForm then try SaveEarlyConfig; except on E: Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; end; { TfrmOptionsMisc.btnRelativeTCExecutableFileClick } procedure TfrmOptionsMisc.btnRelativeTCExecutableFileClick(Sender: TObject); begin fneTCExecutableFilename.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneTCExecutableFilename, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsMisc.btnRelativeTCConfigFileClick } procedure TfrmOptionsMisc.btnRelativeTCConfigFileClick(Sender: TObject); begin fneTCConfigFilename.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneTCConfigFilename, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsMisc.btnViewConfigFileClick } procedure TfrmOptionsMisc.btnViewConfigFileClick(Sender: TObject); begin ShowViewerByGlob(mbExpandFileName(fneTCConfigFilename.FileName)); end; { TfrmOptionsMisc.btnOutputPathForToolbarClick } procedure TfrmOptionsMisc.btnOutputPathForToolbarClick(Sender: TObject); var MaybeResultingOutputPath: string; begin MaybeResultingOutputPath := edOutputPathForToolbar.Text; if MaybeResultingOutputPath = '' then MaybeResultingOutputPath := frmMain.ActiveFrame.CurrentPath; if SelectDirectory(rsSelectDir, MaybeResultingOutputPath, MaybeResultingOutputPath, False) then edOutputPathForToolbar.Text := MaybeResultingOutputPath; end; { TfrmOptionsMisc.btnRelativeOutputPathForToolbarClick } procedure TfrmOptionsMisc.btnRelativeOutputPathForToolbarClick(Sender: TObject); begin edOutputPathForToolbar.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edOutputPathForToolbar, pfPATH); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsMisc.chkDescCreateUnicodeChange(Sender: TObject); begin cmbDescCreateEncoding.Enabled:= chkDescCreateUnicode.Checked; end; procedure BringUsToTCConfigurationPage; var Editor: TOptionsEditor; Options: IOptionsDialog; begin Options := ShowOptions(TfrmOptionsMisc); Application.ProcessMessages; Editor := Options.GetEditor(TfrmOptionsMisc); Application.ProcessMessages; if Editor.CanFocus then Editor.SetFocus; end; end. �������������������������������doublecmd-1.1.22/src/frames/foptionsmouse.lfm�������������������������������������������������������0000644�0001750�0000144�00000013536�14743153644�020274� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsMouse: TfrmOptionsMouse Height = 385 Width = 488 HelpKeyword = '/configuration.html#ConfigMouse' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 385 ClientWidth = 488 DesignLeft = 380 DesignTop = 148 object gbSelection: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 89 Top = 6 Width = 476 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Selection' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 64 ClientWidth = 472 TabOrder = 0 object cbSelectionByMouse: TCheckBox AnchorSideRight.Side = asrBottom Left = 6 Height = 24 Top = 6 Width = 153 Caption = '&Selection by mouse' OnChange = cbSelectionByMouseChange TabOrder = 0 end object lblMouseMode: TLabel AnchorSideLeft.Control = cbSelectionByMouse AnchorSideTop.Control = cbMouseMode AnchorSideTop.Side = asrCenter Left = 6 Height = 20 Top = 34 Width = 42 Caption = '&Mode:' FocusControl = cbMouseMode ParentColor = False end object cbMouseMode: TComboBox AnchorSideLeft.Control = lblMouseMode AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbSelectionByMouse AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbSelection AnchorSideRight.Side = asrBottom Left = 56 Height = 28 Top = 30 Width = 408 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Right = 8 ItemHeight = 20 Style = csDropDownList TabOrder = 2 end object chkMouseSelectionIconClick: TCheckBox AnchorSideLeft.Control = cbSelectionByMouse AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbSelectionByMouse Left = 171 Height = 24 Top = 6 Width = 147 BorderSpacing.Left = 12 Caption = 'By clic&king on icon' TabOrder = 1 end end object gbScrolling: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbSelection AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 121 Top = 99 Width = 476 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 Caption = 'Scrolling' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 96 ClientWidth = 472 TabOrder = 1 object rbScrollLineByLineCursor: TRadioButton AnchorSideLeft.Control = gbScrolling AnchorSideTop.Control = gbScrolling AnchorSideRight.Control = gbScrolling AnchorSideRight.Side = asrBottom Left = 6 Height = 24 Top = 6 Width = 460 Anchors = [akTop, akLeft, akRight] Caption = 'Line by line &with cursor movement' Checked = True TabOrder = 0 TabStop = True end object rbScrollLineByLine: TRadioButton AnchorSideLeft.Control = gbScrolling AnchorSideTop.Control = seWheelScrollLines AnchorSideTop.Side = asrCenter Left = 6 Height = 24 Top = 36 Width = 99 BorderSpacing.Right = 6 Caption = '&Line by line' TabOrder = 1 end object rbScrollPageByPage: TRadioButton AnchorSideLeft.Control = gbScrolling AnchorSideTop.Control = seWheelScrollLines AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbScrolling AnchorSideRight.Side = asrBottom Left = 6 Height = 24 Top = 66 Width = 460 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 Caption = '&Page by page' TabOrder = 3 end object seWheelScrollLines: TSpinEdit AnchorSideLeft.Control = rbScrollLineByLine AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbScrollLineByLineCursor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbScrolling AnchorSideRight.Side = asrBottom Left = 123 Height = 28 Top = 34 Width = 341 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 18 BorderSpacing.Top = 4 BorderSpacing.Right = 8 MaxValue = 10 MinValue = 1 TabOrder = 2 Value = 1 end end object gbOpenWith: TGroupBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbScrolling AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 133 Top = 224 Width = 476 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 Caption = 'Open with' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 108 ClientWidth = 472 TabOrder = 2 object rbDoubleClick: TRadioButton Left = 6 Height = 24 Top = 6 Width = 358 Caption = 'Double click' OnChange = rbDoubleClickChange TabOrder = 0 end object rbSingleClickBoth: TRadioButton Left = 6 Height = 24 Top = 30 Width = 358 Caption = 'Single click (opens files and folders)' TabOrder = 1 end object rbSingleClickFolders: TRadioButton Left = 6 Height = 24 Top = 54 Width = 358 Caption = 'Single click (opens folders, double click for files)' TabOrder = 2 end object chkCursorNoFollow: TCheckBox Left = 6 Height = 24 Top = 78 Width = 358 Caption = 'The text cursor no longer follows the mouse cursor' TabOrder = 3 end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsmouse.lrj�������������������������������������������������������0000644�0001750�0000144�00000005127�14743153644�020302� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":45807518,"name":"tfrmoptionsmouse.gbselection.caption","sourcebytes":[83,101,108,101,99,116,105,111,110],"value":"Selection"}, {"hash":170541445,"name":"tfrmoptionsmouse.cbselectionbymouse.caption","sourcebytes":[38,83,101,108,101,99,116,105,111,110,32,98,121,32,109,111,117,115,101],"value":"&Selection by mouse"}, {"hash":45374090,"name":"tfrmoptionsmouse.lblmousemode.caption","sourcebytes":[38,77,111,100,101,58],"value":"&Mode:"}, {"hash":242261230,"name":"tfrmoptionsmouse.chkmouseselectioniconclick.caption","sourcebytes":[66,121,32,99,108,105,99,38,107,105,110,103,32,111,110,32,105,99,111,110],"value":"By clic&king on icon"}, {"hash":157513703,"name":"tfrmoptionsmouse.gbscrolling.caption","sourcebytes":[83,99,114,111,108,108,105,110,103],"value":"Scrolling"}, {"hash":116243732,"name":"tfrmoptionsmouse.rbscrolllinebylinecursor.caption","sourcebytes":[76,105,110,101,32,98,121,32,108,105,110,101,32,38,119,105,116,104,32,99,117,114,115,111,114,32,109,111,118,101,109,101,110,116],"value":"Line by line &with cursor movement"}, {"hash":42428677,"name":"tfrmoptionsmouse.rbscrolllinebyline.caption","sourcebytes":[38,76,105,110,101,32,98,121,32,108,105,110,101],"value":"&Line by line"}, {"hash":47231125,"name":"tfrmoptionsmouse.rbscrollpagebypage.caption","sourcebytes":[38,80,97,103,101,32,98,121,32,112,97,103,101],"value":"&Page by page"}, {"hash":201823944,"name":"tfrmoptionsmouse.gbopenwith.caption","sourcebytes":[79,112,101,110,32,119,105,116,104],"value":"Open with"}, {"hash":65050299,"name":"tfrmoptionsmouse.rbdoubleclick.caption","sourcebytes":[68,111,117,98,108,101,32,99,108,105,99,107],"value":"Double click"}, {"hash":31955305,"name":"tfrmoptionsmouse.rbsingleclickboth.caption","sourcebytes":[83,105,110,103,108,101,32,99,108,105,99,107,32,40,111,112,101,110,115,32,102,105,108,101,115,32,97,110,100,32,102,111,108,100,101,114,115,41],"value":"Single click (opens files and folders)"}, {"hash":3492345,"name":"tfrmoptionsmouse.rbsingleclickfolders.caption","sourcebytes":[83,105,110,103,108,101,32,99,108,105,99,107,32,40,111,112,101,110,115,32,102,111,108,100,101,114,115,44,32,100,111,117,98,108,101,32,99,108,105,99,107,32,102,111,114,32,102,105,108,101,115,41],"value":"Single click (opens folders, double click for files)"}, {"hash":36904834,"name":"tfrmoptionsmouse.chkcursornofollow.caption","sourcebytes":[84,104,101,32,116,101,120,116,32,99,117,114,115,111,114,32,110,111,32,108,111,110,103,101,114,32,102,111,108,108,111,119,115,32,116,104,101,32,109,111,117,115,101,32,99,117,114,115,111,114],"value":"The text cursor no longer follows the mouse cursor"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsmouse.pas�������������������������������������������������������0000644�0001750�0000144�00000011112�14743153644�020265� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Mouse options page Copyright (C) 2006-2018 Alexander Koblov (alexx2000@mail.ru) 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 } unit fOptionsMouse; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fOptionsFrame, StdCtrls, Spin, ExtCtrls; type { TfrmOptionsMouse } TfrmOptionsMouse = class(TOptionsEditor) cbMouseMode: TComboBox; cbSelectionByMouse: TCheckBox; chkCursorNoFollow: TCheckBox; chkMouseSelectionIconClick: TCheckBox; gbScrolling: TGroupBox; gbSelection: TGroupBox; gbOpenWith: TGroupBox; lblMouseMode: TLabel; rbDoubleClick: TRadioButton; rbSingleClickBoth: TRadioButton; rbSingleClickFolders: TRadioButton; rbScrollLineByLine: TRadioButton; rbScrollLineByLineCursor: TRadioButton; rbScrollPageByPage: TRadioButton; seWheelScrollLines: TSpinEdit; procedure cbSelectionByMouseChange(Sender: TObject); procedure rbDoubleClickChange(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng; { TfrmOptionsMouse } procedure TfrmOptionsMouse.cbSelectionByMouseChange(Sender: TObject); begin cbMouseMode.Enabled:= cbSelectionByMouse.Checked; chkMouseSelectionIconClick.Enabled:= cbSelectionByMouse.Checked; if not cbSelectionByMouse.Checked then chkMouseSelectionIconClick.Checked:= False; end; procedure TfrmOptionsMouse.rbDoubleClickChange(Sender: TObject); begin chkCursorNoFollow.Enabled:= not rbDoubleClick.Checked; if rbDoubleClick.Checked then chkCursorNoFollow.Checked:= False; end; procedure TfrmOptionsMouse.Init; begin ParseLineToList(rsOptMouseSelectionButton, cbMouseMode.Items); end; procedure TfrmOptionsMouse.Load; begin cbSelectionByMouse.Checked:=gMouseSelectionEnabled; cbMouseMode.ItemIndex := gMouseSelectionButton; seWheelScrollLines.Value:= gWheelScrollLines; chkMouseSelectionIconClick.Checked:= Boolean(gMouseSelectionIconClick); case gScrollMode of smLineByLineCursor: rbScrollLineByLineCursor.Checked:= True; smLineByLine: rbScrollLineByLine.Checked:= True; smPageByPage: rbScrollPageByPage.Checked:= True; else rbScrollLineByLine.Checked:= True; end; case gMouseSingleClickStart of 0: rbDoubleClick.Checked:= True; 1, 5: rbSingleClickBoth.Checked:= True; 2, 6: rbSingleClickFolders.Checked:= True; end; chkCursorNoFollow.Enabled:= gMouseSingleClickStart > 0; chkCursorNoFollow.Checked:= gMouseSingleClickStart > 4; cbSelectionByMouseChange(cbSelectionByMouse); end; function TfrmOptionsMouse.Save: TOptionsEditorSaveFlags; begin gMouseSelectionEnabled := cbSelectionByMouse.Checked; gMouseSelectionButton := cbMouseMode.ItemIndex; gWheelScrollLines:= seWheelScrollLines.Value; gMouseSelectionIconClick:= Integer(chkMouseSelectionIconClick.Checked); if rbScrollLineByLineCursor.Checked then gScrollMode:= smLineByLineCursor else if rbScrollLineByLine.Checked then gScrollMode:= smLineByLine else if rbScrollPageByPage.Checked then gScrollMode:= smPageByPage; if rbDoubleClick.Checked then gMouseSingleClickStart:= 0 else if rbSingleClickBoth.Checked then gMouseSingleClickStart:= 1 else if rbSingleClickFolders.Checked then gMouseSingleClickStart:= 2; if chkCursorNoFollow.Checked then gMouseSingleClickStart += 4; Result := []; end; class function TfrmOptionsMouse.GetIconIndex: Integer; begin Result := 27; end; class function TfrmOptionsMouse.GetTitle: String; begin Result := rsOptionsEditorMouse; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsmultirename.lfm�������������������������������������������������0000644�0001750�0000144�00000027047�14743153644�021470� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsMultiRename: TfrmOptionsMultiRename Height = 649 Width = 735 HelpKeyword = '/multirename.html#configuration' ChildSizing.LeftRightSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 6 ClientHeight = 649 ClientWidth = 735 DesignLeft = 753 DesignTop = 243 object ckbShowMenuBarOnTop: TCheckBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 6 Height = 19 Top = 6 Width = 144 BorderSpacing.Top = 6 Caption = 'Show menu bar on top ' TabOrder = 0 end object rgLaunchBehavior: TRadioGroup[1] AnchorSideLeft.Control = ckbShowMenuBarOnTop AnchorSideTop.Control = edInvalidCharReplacement AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 101 Top = 60 Width = 723 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'Preset at launch' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 81 ClientWidth = 719 ItemIndex = 0 Items.Strings = ( 'Last masks under [Last One] preset' 'Last preset' 'New fresh masks' ) TabOrder = 2 end object rgExitModifiedPreset: TRadioGroup[2] AnchorSideLeft.Control = ckbShowMenuBarOnTop AnchorSideTop.Control = rgLaunchBehavior AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 101 Top = 167 Width = 723 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'Exit with modified preset' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 81 ClientWidth = 719 ItemIndex = 0 Items.Strings = ( 'Ignore, just save as the [Last One]' 'Prompt user to confirm if we save it' 'Save automatically' ) TabOrder = 3 end object gbSaveRenamingLog: TGroupBox[3] AnchorSideLeft.Control = ckbShowMenuBarOnTop AnchorSideTop.Control = rgExitModifiedPreset AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 155 Top = 274 Width = 723 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Rename log' ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 6 ClientHeight = 135 ClientWidth = 719 TabOrder = 4 object rbRenamingLogPerPreset: TRadioButton AnchorSideLeft.Control = gbSaveRenamingLog AnchorSideTop.Control = gbSaveRenamingLog Left = 8 Height = 19 Top = 6 Width = 72 BorderSpacing.Left = 8 Caption = 'Per preset' Checked = True TabOrder = 2 TabStop = True end object rbRenamingLogAppendSameFile: TRadioButton AnchorSideLeft.Control = rbRenamingLogPerPreset AnchorSideTop.Control = rbRenamingLogPerPreset AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 31 Width = 208 BorderSpacing.Top = 6 Caption = 'Append in the same rename log file' OnChange = rbRenamingLogAppendSameFileChange TabOrder = 1 end object fneMulRenLogFilename: TFileNameEdit AnchorSideLeft.Control = rbRenamingLogPerPreset AnchorSideTop.Control = rbRenamingLogAppendSameFile AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnMulRenLogFilenameRelative Left = 8 Height = 23 Top = 56 Width = 655 DialogOptions = [] FilterIndex = 0 DefaultExt = 'log' HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 MaxLength = 0 TabOrder = 0 end object btnMulRenLogFilenameRelative: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneMulRenLogFilename AnchorSideRight.Control = btnMulRenLogFilenameView AnchorSideBottom.Control = fneMulRenLogFilename AnchorSideBottom.Side = asrBottom Left = 663 Height = 23 Hint = 'Some functions to select appropriate path' Top = 56 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnMulRenLogFilenameRelativeClick end object btnMulRenLogFilenameView: TSpeedButton AnchorSideTop.Control = fneMulRenLogFilename AnchorSideRight.Control = gbSaveRenamingLog AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneMulRenLogFilename AnchorSideBottom.Side = asrBottom Left = 687 Height = 23 Hint = 'View log file content' Top = 56 Width = 24 Anchors = [akTop, akRight, akBottom] BorderSpacing.Right = 8 Glyph.Data = { 36030000424D3603000000000000360000002800000010000000100000000100 18000000000000030000130B0000130B00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C17213B6E9E3A6EA000000000000000000000000000 00000000000000000000000000000000000000000000000000003A83CC44C8FF 29B2FF316DA70000000000000000000000000000000000000000000000000000 000000000000000000003881CC55DBFF3AC6FF82756C6F6C6B69696C68696F73 6F66CFAA61B87E0BB67D0AB67D0AB67C0AB67D0AB77F0F7F580A0000002980DB 9F928C7D7773E9D7A3FFF5B0FFEEA8E7CA94737379F6FBFFF2F7FFF2F7FFF2F6 FFF2F7FFF7FFFFB77F0F000000C98506828088E9D8A5FFF8BBFFEFB2FFE7A6FF E6A6E6C28984858AECECEDECECEDEAEBEEEAEBEEF5FBFFB67D0A000000C08511 7F8290FFF2AFFFEFB2FFE9ABFFE7B3FFEFCAFFE09C7B7B7EEAE9E8EAE9E8E6E6 E6E6E6E6F5FBFFB67C09000000BD8412868C9AFFEAA5FFE6A4FFE7B2FFEDC8FF F7E3FFDC96858689E5E4E3E5E4E3E0E0E1E0E0E1F5FBFFB67C09000000BB8210 9DA3B0ECCE97FFE4A3FFEEC9FFF7E3FFF3DAECBE8096979AE1E1E0DEDDDCDBDB DCDBDBDCF5FBFFB67C09000000B9800DDDE3EE9E9B9BEECA8FFFDD9AFFDA95EE C2829B9895D9D7D7D9D7D7D9D7D7D8D6D8D8D6D8F6FCFFB67C0A000000B77E0B F9FFFFC4C4C6A5A4A6A4A4A7A4A3A6B1AFB3D6D4D3D4D2D3D4D2D3D4D2D3D4D2 D3D4D2D3F6FCFFB67D0A000000B67D0AF7FDFFCFCED0CFCECECCCBCDCFCECECC CBCDCCCBCDCCCBCDCFCECECCCBCDCCCBCDCCCBCDF6FCFFB67D0A000000B67D0C F5FDFFF3F8FFF5F9FFF6FBFFF6FBFFF6FBFFF6FAFFF5FAFFF5F9FFF4F8FFF3F7 FFF3F7FFF4FDFFB67D0C000000B67F10F7E4C0DCAA4ADDAB4BDDAC4CDDAC4CDD AC4CDDAC4CDDAC4CDDAC4CDDAB4BDCAB4ADCAA4AF7E4C0B67F10000000B88216 EFD2A0EDCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF9BECCF 9BEDCF9BEFD2A0B88216000000825D14B88217B78114B68114B68114B68114B6 8114B68114B68114B68114B68114B68114B78114B88217825D14 } OnClick = btnMulRenLogFilenameViewClick end object ckbDailyIndividualDirMultRenLog: TCheckBox AnchorSideLeft.Control = rbRenamingLogPerPreset AnchorSideTop.Control = fneMulRenLogFilename AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 85 Width = 172 BorderSpacing.Bottom = 4 Caption = 'Individual directories per day' TabOrder = 3 end object ckbFilenameWithFullPathInLog: TCheckBox AnchorSideLeft.Control = rbRenamingLogPerPreset AnchorSideTop.Control = ckbDailyIndividualDirMultRenLog AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 110 Width = 167 BorderSpacing.Top = 6 Caption = 'Log filenames with full path' TabOrder = 4 end end object lbInvalidCharReplacement: TLabel[4] AnchorSideLeft.Control = ckbShowMenuBarOnTop AnchorSideTop.Control = edInvalidCharReplacement AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 35 Width = 196 Caption = 'Replace invalid filename character b&y' FocusControl = edInvalidCharReplacement ParentColor = False end object edInvalidCharReplacement: TEdit[5] AnchorSideLeft.Control = lbInvalidCharReplacement AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ckbShowMenuBarOnTop AnchorSideTop.Side = asrBottom Left = 205 Height = 23 Top = 31 Width = 112 TabOrder = 1 end object pmPathToBeRelativeToHelper: TPopupMenu[6] left = 452 top = 60 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsmultirename.lrj�������������������������������������������������0000644�0001750�0000144�00000004761�14743153644�021477� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":100159984,"name":"tfrmoptionsmultirename.ckbshowmenubarontop.caption","sourcebytes":[83,104,111,119,32,109,101,110,117,32,98,97,114,32,111,110,32,116,111,112,32],"value":"Show menu bar on top "}, {"hash":15447080,"name":"tfrmoptionsmultirename.rglaunchbehavior.caption","sourcebytes":[80,114,101,115,101,116,32,97,116,32,108,97,117,110,99,104],"value":"Preset at launch"}, {"hash":31336276,"name":"tfrmoptionsmultirename.rgexitmodifiedpreset.caption","sourcebytes":[69,120,105,116,32,119,105,116,104,32,109,111,100,105,102,105,101,100,32,112,114,101,115,101,116],"value":"Exit with modified preset"}, {"hash":137559831,"name":"tfrmoptionsmultirename.gbsaverenaminglog.caption","sourcebytes":[82,101,110,97,109,101,32,108,111,103],"value":"Rename log"}, {"hash":125674884,"name":"tfrmoptionsmultirename.rbrenaminglogperpreset.caption","sourcebytes":[80,101,114,32,112,114,101,115,101,116],"value":"Per preset"}, {"hash":204365733,"name":"tfrmoptionsmultirename.rbrenaminglogappendsamefile.caption","sourcebytes":[65,112,112,101,110,100,32,105,110,32,116,104,101,32,115,97,109,101,32,114,101,110,97,109,101,32,108,111,103,32,102,105,108,101],"value":"Append in the same rename log file"}, {"hash":15252584,"name":"tfrmoptionsmultirename.btnmulrenlogfilenamerelative.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":68945492,"name":"tfrmoptionsmultirename.btnmulrenlogfilenameview.hint","sourcebytes":[86,105,101,119,32,108,111,103,32,102,105,108,101,32,99,111,110,116,101,110,116],"value":"View log file content"}, {"hash":33348585,"name":"tfrmoptionsmultirename.ckbdailyindividualdirmultrenlog.caption","sourcebytes":[73,110,100,105,118,105,100,117,97,108,32,100,105,114,101,99,116,111,114,105,101,115,32,112,101,114,32,100,97,121],"value":"Individual directories per day"}, {"hash":12209432,"name":"tfrmoptionsmultirename.ckbfilenamewithfullpathinlog.caption","sourcebytes":[76,111,103,32,102,105,108,101,110,97,109,101,115,32,119,105,116,104,32,102,117,108,108,32,112,97,116,104],"value":"Log filenames with full path"}, {"hash":211525865,"name":"tfrmoptionsmultirename.lbinvalidcharreplacement.caption","sourcebytes":[82,101,112,108,97,99,101,32,105,110,118,97,108,105,100,32,102,105,108,101,110,97,109,101,32,99,104,97,114,97,99,116,101,114,32,98,38,121],"value":"Replace invalid filename character b&y"} ]} ���������������doublecmd-1.1.22/src/frames/foptionsmultirename.pas�������������������������������������������������0000644�0001750�0000144�00000014002�14743153644�021460� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Multi-Rename options page Copyright (C) 2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsMultiRename; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, StdCtrls, ExtCtrls, EditBtn, Buttons, Menus, //DC fOptionsFrame; type { TfrmOptionsMultiRename } TfrmOptionsMultiRename = class(TOptionsEditor) ckbShowMenuBarOnTop: TCheckBox; edInvalidCharReplacement: TEdit; lbInvalidCharReplacement: TLabel; rgLaunchBehavior: TRadioGroup; rgExitModifiedPreset: TRadioGroup; gbSaveRenamingLog: TGroupBox; rbRenamingLogPerPreset: TRadioButton; rbRenamingLogAppendSameFile: TRadioButton; fneMulRenLogFilename: TFileNameEdit; btnMulRenLogFilenameRelative: TSpeedButton; btnMulRenLogFilenameView: TSpeedButton; ckbDailyIndividualDirMultRenLog: TCheckBox; ckbFilenameWithFullPathInLog: TCheckBox; pmPathToBeRelativeToHelper: TPopupMenu; procedure rbRenamingLogAppendSameFileChange(Sender: TObject); procedure btnMulRenLogFilenameRelativeClick(Sender: TObject); procedure btnMulRenLogFilenameViewClick(Sender: TObject); private protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Controls, //DC uShowMsg, uShowForm, uDCUtils, uSpecialDir, DCStrUtils, uGlobs, uLng; { TfrmOptionsMultiRename } { TfrmOptionsMultiRename.GetIconIndex } class function TfrmOptionsMultiRename.GetIconIndex: integer; begin Result := 42; end; { TfrmOptionsMultiRename.GetTitle } class function TfrmOptionsMultiRename.GetTitle: string; begin Result := rsOptionsEditorMultiRename; end; { TfrmOptionsMultiRename.Init } procedure TfrmOptionsMultiRename.Init; begin ParseLineToList(rsMulRenExitModifiedPresetOptions, rgExitModifiedPreset.Items); ParseLineToList(rsMulRenLaunchBehaviorOptions, rgLaunchBehavior.Items); end; { TfrmOptionsMultiRename.Load } procedure TfrmOptionsMultiRename.Load; begin ckbShowMenuBarOnTop.Checked := gMulRenShowMenuBarOnTop; edInvalidCharReplacement.Text := gMulRenInvalidCharReplacement; rgLaunchBehavior.ItemIndex := integer(gMulRenLaunchBehavior); rgExitModifiedPreset.ItemIndex := integer(gMulRenExitModifiedPreset); case gMulRenSaveRenamingLog of mrsrlPerPreset: begin rbRenamingLogPerPreset.Checked := True; rbRenamingLogAppendSameFileChange(rbRenamingLogAppendSameFile); end; mrsrlAppendSameLog: rbRenamingLogAppendSameFile.Checked := True; end; fneMulRenLogFilename.FileName := gMulRenLogFilename; ckbDailyIndividualDirMultRenLog.Checked := gMultRenDailyIndividualDirLog; ckbFilenameWithFullPathInLog.Checked := gMulRenFilenameWithFullPathInLog; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathToBeRelativeToHelper, mp_PATHHELPER, nil); end; { TfrmOptionsMultiRename.Save } function TfrmOptionsMultiRename.Save: TOptionsEditorSaveFlags; begin Result := []; gMulRenShowMenuBarOnTop := ckbShowMenuBarOnTop.Checked; gMulRenInvalidCharReplacement := edInvalidCharReplacement.Text; gMulRenLaunchBehavior := TMulRenLaunchBehavior(rgLaunchBehavior.ItemIndex); gMulRenExitModifiedPreset := TMulRenExitModifiedPreset(rgExitModifiedPreset.ItemIndex); if rbRenamingLogPerPreset.Checked then gMulRenSaveRenamingLog := mrsrlPerPreset else gMulRenSaveRenamingLog := mrsrlAppendSameLog; gMulRenLogFilename := fneMulRenLogFilename.FileName; gMultRenDailyIndividualDirLog := ckbDailyIndividualDirMultRenLog.Checked; gMulRenFilenameWithFullPathInLog := ckbFilenameWithFullPathInLog.Checked; end; { TfrmOptionsMultiRename.rbRenamingLogAppendSameFileChange } procedure TfrmOptionsMultiRename.rbRenamingLogAppendSameFileChange(Sender: TObject); begin fneMulRenLogFilename.Enabled := rbRenamingLogAppendSameFile.Checked; btnMulRenLogFilenameRelative.Enabled := rbRenamingLogAppendSameFile.Checked; btnMulRenLogFilenameView.Enabled := rbRenamingLogAppendSameFile.Checked; ckbDailyIndividualDirMultRenLog.Enabled := rbRenamingLogAppendSameFile.Checked; end; { TfrmOptionsMultiRename.btnMulRenLogFilenameRelativeClick } procedure TfrmOptionsMultiRename.btnMulRenLogFilenameRelativeClick(Sender: TObject); begin fneMulRenLogFilename.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneMulRenLogFilename, pfFILE); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsMultiRename.btnMulRenLogFilenameViewClick } procedure TfrmOptionsMultiRename.btnMulRenLogFilenameViewClick(Sender: TObject); var sRenameLogFilename: string; begin if ckbDailyIndividualDirMultRenLog.Checked then sRenameLogFilename := mbExpandFileName(ExtractFilePath(fneMulRenLogFilename.FileName) + IncludeTrailingPathDelimiter(EnvVarTodaysDate) + ExtractFilename(fneMulRenLogFilename.FileName)) else sRenameLogFilename := mbExpandFileName(fneMulRenLogFilename.FileName); if FileExists(sRenameLogFilename) then ShowViewerByGlob(sRenameLogFilename) else MsgError(Format(rsMsgFileNotFound, [sRenameLogFilename])); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsbase.lfm�������������������������������������������������0000644�0001750�0000144�00000074447�14743153644�021470� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsBase: TfrmOptionsPluginsBase Height = 376 Width = 705 HelpKeyword = '/configuration.html#ConfigPlugins' ClientHeight = 376 ClientWidth = 705 ParentShowHint = False ShowHint = True DesignLeft = 291 DesignTop = 266 object stgPlugins: TStringGrid[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = pnlPlugIn AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlButton Left = 8 Height = 302 Top = 35 Width = 689 Anchors = [akTop, akLeft, akRight, akBottom] AutoAdvance = aaRightDown AutoFillColumns = True BorderSpacing.Left = 8 BorderSpacing.Right = 8 ColCount = 4 Columns = < item Alignment = taCenter MaxSize = 80 SizePriority = 0 Title.Caption = 'Active' Width = 161 end item SizePriority = 0 Title.Caption = 'Plugin' Width = 183 end item SizePriority = 0 Title.Caption = 'Registered for' Width = 277 end item SizePriority = 0 Title.Caption = 'File name' Width = 64 end> DragMode = dmAutomatic FixedCols = 0 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goRowSelect, goThumbTracking, goSmoothScroll, goHeaderHotTracking, goHeaderPushedLook, goCellHints] ParentShowHint = False RowCount = 1 ShowHint = True TabOrder = 0 TitleStyle = tsNative OnDragDrop = stgPluginsDragDrop OnDragOver = stgPluginsDragOver OnDblClick = stgPluginsDblClick OnGetCellHint = stgPluginsGetCellHint ColWidths = ( 161 183 277 64 ) end object pnlPlugIn: TPanel[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 35 Top = 0 Width = 689 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BevelOuter = bvNone ClientHeight = 35 ClientWidth = 689 TabOrder = 1 object lblPlugInDescription: TLabel AnchorSideLeft.Control = pnlPlugIn AnchorSideTop.Control = pnlPlugIn AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlPlugIn AnchorSideRight.Side = asrBottom Left = 5 Height = 15 Top = 10 Width = 679 Anchors = [akTop, akLeft, akRight] BorderSpacing.Around = 5 Caption = 'Description' FocusControl = stgPlugins ParentColor = False WordWrap = True end end object pnlButton: TPanel[2] AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 0 Height = 36 Top = 340 Width = 697 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Top = 3 BorderSpacing.Right = 8 BevelOuter = bvNone ChildSizing.TopBottomSpacing = 3 ClientHeight = 36 ClientWidth = 697 TabOrder = 2 object btnAddPlugin: TBitBtn AnchorSideRight.Control = btnEnablePlugin AnchorSideBottom.Control = pnlButton AnchorSideBottom.Side = asrBottom Left = 123 Height = 30 Top = 3 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Left = 6 Caption = 'A&dd' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000009E9E9EA38181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF9E9E9E950000000000000000818181FFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF818181FF0000000000000000818181FFFFFF FFFFEDEDEDFFEDEDEDFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0F0FFF0F0F0FFF1F1 F1FFF2F2F2FFF2F2F2FFFFFFFFFF818181FF0000000000000000818181FFFFFF FFFFEDEDEDFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFF0F0F0FFF0F0F0FFF1F1 F1FFF1F1F1FFF2F2F2FFFFFFFFFF818181FF0000000000000000818181FFFFFF FFFFECECECFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0F0FFF1F1 F1FFF1F1F1FFF1F1F1FFFFFFFFFF818181FF0000000000000000818181FFFFFF FFFFECECECFFECECECFFEDEDEDFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFEFEF EFFFF0F0F0FFF0F0F0FFFFFFFFFF818181FF0000000000000000818181FFFFFF FFFFECECECFFECECECFFEDEDEDFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFEFEF EFFFEFEFEFFFF0F0F0FFFFFFFFFF818181FF0000000000000000818181FFFFFF FFFFEBEBEBFFECECECFFECECECFFEDEDEDFFEDEDEDFFEEEEEEFFEEEEEEFFE2EE EEFFB1F0F3FF92F0F5FF9AF0F5FF779696FF0000000000000000818181FFFFFF FFFFEBEBEBFFEBEBEBFFECECECFFECECECFFEDEDEDFFEDEDEDFFE0EEEFFF96EF F4FF63F1F8FF46F3FBFF45F3FBFF5DEFF7FD36DDE67603F3FF01818181FFFFFF FFFFEBEBEBFFEBEBEBFFECECECFFECECECFFECECECFFEDEDEDFFB1EEF1FF67F1 F8FF40F4FDFF71F7FDFF72F7FDFF43F3FCFE24ECF6B60AF3FF25818181FFFFFF FFFFEAEAEAFFEBEBEBFFEBEBEBFFECECECFFECECECFFECECECFF9BEFF3FF4EF2 FAFF6AF6FDFFBBFAFEFFBFFBFEFF6EF6FDFF22F0FAD20DF3FF50818181FFFFFF FFFFEAEAEAFFEAEAEAFFEBEBEBFFEBEBEBFFECECECFFECECECFF9CEEF2FF4EF2 FAFF67F6FDFFB5FAFEFFB8FAFEFF6BF5FDFF22EFFAD10DF3FF5C818181FFFFFF FFFFECECECFFEAEAEAFFEAEAEAFFEBEBEBFFEBEBEBFFEBEBEBFFB4EDF0FF6AF0 F7FF3AF4FCFF68F6FDFF6AF6FDFF3CF2FBFD1EEFF9A909F3FF37818181FFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9BEE F2FF69F0F7FF4DF2FAFF46EFF7FA28EBF4B60DF3FF6102F3FF099E9E9EA38181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF7C8C 8CFF729F9FFF6AAEAFFF36E4ED8A09F3FF4502F3FF0F00000000 } OnClick = btnPluginsNotImplementedClick TabOrder = 0 end object btnEnablePlugin: TBitBtn AnchorSideRight.Control = btnRemovePlugin AnchorSideBottom.Control = pnlButton AnchorSideBottom.Side = asrBottom Left = 239 Height = 30 Top = 3 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Left = 6 Caption = 'E&nable' OnClick = btnPluginsNotImplementedClick TabOrder = 1 end object btnRemovePlugin: TBitBtn AnchorSideRight.Control = btnTweakPlugin AnchorSideBottom.Control = pnlButton AnchorSideBottom.Side = asrBottom Left = 355 Height = 30 Top = 3 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Left = 6 Caption = '&Remove' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00008B9C1F008C9DED008D9EEC008D 9E9E008B9C21FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00008B9C13008D9EE24FC3D2FD5BD3E1FF30B5 C6FA0890A1F6008D9FA9008B9C14FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00008E9FC536B5C5FA5FD8E7FF26CADFFF4ED4 E5FF6DD9E7FF32B4C5FB008D9EE6008B9C26FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00008B9C431A9BABF66CDAE8FF10C5DCFF03C2DAFF03C2 DAFF15C6DCFF5BD7E7FF56C8D6FE058FA0F1008B9C3FFFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00018EA0D45ECFDDFF46DAEDFF18D0E7FF11CBE3FF07C4 DCFF03C2DAFF03C2DAFF4CD3E4FF58CDDCFF048E9FF4008B9C1CFFFFFF00FFFF FF00FFFFFF00008B9C1A1194A5F78BEDFBFF3CE5FCFF37E4FBFF2FDEF6FF23D7 EEFF14CDE5FF04C3DBFF03C2DAFF56D6E6FF33B6C6FB008E9FA8FFFFFF00FFFF FF00FFFFFF00007F9C5F2FB0C0F58AEFFDFF5FEAFDFF61EBFDFF52E9FDFF3CE6 FDFF2ADBF3FF18D0E7FF10C6DCFF49D2E4FF67D4E2FF018D9FE9FFFFFF00FFFF FF00008B9C070024A1D71342ADFC84EAFBFF6BECFDFF84EFFDFF6DECFDFF52E9 FDFF44E5FBFF65E3F3FF77DDEBFF49C1CFFE1B9EAEF3008C9DEAFFFFFF00008B 9C5F008D9EEB29A5BBF6284ABBFF1D38B8FF61D8F6FF63EAFDFF6CEBFDFF7DEE FDFF88EAF8FF45BECDFA058F9FF7008E9FA3008B9C40008B9C02FFFFFF00008B 9C5A018D9EF64FC8D8FF68DCECFF336DC8FF0D1BABFF62B1D7FF72DCEAFF43BD CCF70990A2F6018E9F9F008B9C1BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000064878100889CFE41BDCDFF77DEEBFF1769B0F70036A0E4018FA0D2008C 9D77008B9C15FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000487802004A 7B95014E80F40B76B2FF0188A1FF32AEBEFE1DA0B1F2008B9C3DFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000049796F0352 86F40F7ABCFF107DC1FF015284F200859ACE008B9CFF008B9C29FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00004A7BED0C72 B2FF107DC1FF0A6BA9FF004A7BDA00698A02008B9C82008B9C13FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00004A7BE50A69 A6FF0B6DABFF004A7BF500487844FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000048783B004B 7CDA004A7BE300487847FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btnRemovePluginClick TabOrder = 2 end object btnConfigPlugin: TBitBtn AnchorSideRight.Control = pnlButton AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlButton AnchorSideBottom.Side = asrBottom Left = 587 Height = 30 Top = 3 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Left = 6 Caption = 'Con&figure' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 001F000000080000003300000033000000040000002400000000000000000000 0000000000000000000000000000000000330000003300000033000000332D73 BAAF1B3D60523F93D4FF3F93D4FF102438413578BAC300000024000000000000 0000000000230000002F00000000B88445FFC89451FFCE934AFF6D8192FF40A9 EAFF429EDDFF52D0F8FF52D0F8FF439EDCFF48AAE2FF3980C8B6000000000000 0023AA7A3EBFB68243ED00000033B58142FFF5C378FFFCC371FFAD7E49FF3B9E E3FF4ECFFBFF41B0EDFF42B1EDFF50CFFAFF439EDCFF1B3D5F5200000000AA7A 3FBED2A76FFFD7A561FFB88241FFD39F58FFEDB96BFFF7B962FF288DE3FF4CCF FCFF40B0EDFFC39F7BFF987653CB42B1EEFF52D0F9FF3F92D5FF00000000B984 43E9DDBB8CFFEEC486FFE8B466FFF1CC96FFF7DCB5FFFFDEADFF288CDFFF4CCE FBFF3FAFEDFFFAB66DFFC7751FCE41B1EFFF52D0F9FF3F92D5FF000000330000 0033B78242FFE4B163FFEBC68EFFEACFA9FFD1A774FFD9A970FFCCBBA4FF399C E1FF4CCEFBFF3FB0EEFF40B1EFFF4FCFFCFF429EDCFF16324E31B98545FFB782 42FFC8934EFFDFAB5EFFE4C494FFB68245DAB8813F3CBE823B2561809CFF37A8 EFFF399DE3FF4CCFFDFF4AC7F8FF3D9EE1FF45AAE4FF3982CB9FC38F4EFFE2B5 72FFDEB06AFFDBA658FFC59555FF926935300000000000000000AA7333436A83 99FFCD9F5FFF298DE2FF2B8FE1FFB48B5AFF3081D29100000000C5995FFFF1DC BBFFECD2ACFFD6A152FFC18C49FF70502A620000000C0000000C704F2861C88D 44FFDFA24CFFEACEA6FFF1D7B2FFD79A51FF0000000000000000B98442FFB680 3EFFCEA673FFDBAE6EFFCB954BFFB88344FF6E4F2A616E4F2A61B88344FFCD97 4AFFDCAE6DFFD0A772FFB9813CFFBE843FFF0000000000000000000000000000 002FBA8547FFCE9949FFDAB276FFC9944BFFBE8943FFBE8943FFC9944BFFDAB2 76FFCE9949FFBA8546FF0000002F00000000000000000000000000000000B782 42ECD3AE7CFFE7CBA4FFEAD4B2FFE8D0ADFFCF9D56FFCF9D56FFE8D0ADFFEAD4 B2FFE7CBA4FFD3AE7CFFB78242EC00000000000000000000000000000000B985 44AFCCA26CFFD4B080FFB98343FFCCA470FFC9984EFFC9984EFFCCA470FFB983 43FFD4B080FFCCA26CFFB98544AF000000000000000000000000000000000000 0000B98544AFB98443E900000000B78140FFE9D4B4FFE9D4B4FFB78140FF0000 0000B98443E9B98544AF00000000000000000000000000000000000000000000 0000000000000000000000000000BA8545FFB9843FFFB9843FFFBA8545FF0000 0000000000000000000000000000000000000000000000000000 } OnClick = btnPluginsNotImplementedClick TabOrder = 3 end object btnTweakPlugin: TBitBtn AnchorSideRight.Control = btnConfigPlugin AnchorSideBottom.Control = pnlButton AnchorSideBottom.Side = asrBottom Left = 471 Height = 30 Top = 3 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Left = 6 Caption = '&Tweak' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000009595 95B4818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF959595A800000000000000008181 81FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEDEDEDFFEDEDEDFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0F0FFF0F0 F0FFE0E0E0FFADADADFFBABABAFFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEDEDEDFFC6C6C6FFC7C7C7FFC7C7C7FFC8C8C8FFC8C8C8FFB5B5 B5FF929292FF9E9E9EFFABABABFFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFECECECFFEDEDEDFFEEEEEEFFEEEEEEFFEFEFEFFFD4D4D4FF7777 77FF858585FF909090FF9D9D9DFFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFECECECFFB0B0B0FF585858FF585858FF585858FF585858FF5959 59FF626262FF6C6C6CFFDCDCDCFFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFECECECFF696969FF696969FF696969FF6A6A6AFF6A6A6AFF6A6A 6AFF6A6A6AFFD6D6D6FFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEBEBEBFF585858FF585858FFB0B0B0FF585858FF6A6A6AFF6A6A 6AFFCCD2D2FFEEEEEEFFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEBEBEBFF696969FFD2D2D2FFECECECFFD2D2D2FF696969FF6669 69FFECECECFFEEEEEEFFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEBEBEBFFC5C5C5FFC6C6C6FFB0B0B0FF585858FF585858FF5858 58FFC6C6C6FFC7C7C7FFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEAEAEAFFEBEBEBFFEBEBEBFF696969FF696969FF696969FFD2D2 D2FFEDEDEDFFEEEEEEFFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFEAEAEAFFC4C4C4FFC5C5C5FFC5C5C5FFC6C6C6FFC6C6C6FFC6C6 C6FFC6C6C6FFC7C7C7FFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFECECECFFEAEAEAFFEAEAEAFFEBEBEBFFEBEBEBFFEBEBEBFFECEC ECFFECECECFFEDEDEDFFF0F0F0FFFFFFFFFF818181FF00000000000000008181 81FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF818181FF00000000000000009999 99AC818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF8181815600000000 } OnClick = btnTweakPluginClick TabOrder = 4 end object btnToggleOptionPlugins: TBitBtn AnchorSideRight.Control = btnAddPlugin AnchorSideBottom.Control = pnlButton AnchorSideBottom.Side = asrBottom Left = 7 Height = 30 Top = 3 Width = 110 Anchors = [akRight, akBottom] BorderSpacing.Left = 6 OnClick = btnPluginsNotImplementedClick TabOrder = 5 Visible = False end end object ImgSwitchEnable: TImage[3] Left = 16 Height = 16 Top = 16 Width = 16 Picture.Data = { 1754506F727461626C654E6574776F726B47726170686963B108000089504E47 0D0A1A0A0000000D49484452000000100000001008060000001FF3FF61000004 177A5458745261772070726F66696C6520747970652065786966000078DAAD56 6DB2EB260CFDCF2ABA04242104CBE173A63BE8F22BC026B9499CA4EFD64C2C06 84743847E098F6CFDFDDFCA50F4470C6B1041FBDB7FAB8E82226ED047B7BDA61 D7185837DFE703C71BCCCB09544B6A690D8A3B66E9183FFDFDB61AE8C504F0C3 02DA69F03EB1A4631C2DFE40D4D3CE71DBCEF1EBBD86DEDBDA5D725E69F06B53 2B8539C3A8635696682EF3DA447FAC7D992D6A0B36D902CE565B6CD656946404 B21D1C5403093A34A86A0B14C5E8B0A1A8452C48732C9060C4429680DC68D051 2852A54048051B113943B8B1C0CC1B67BE024133575057040D06BAE46D339F1C BE69BD17AB1C01E8EEE1E04A71210E1D60D048E3AD6E2A08F443379E049F6D3F E64E58520579D21C7483C9E6152233DC6A8B660190FAB1DA555F2075A886B34A 9CE6660503A412580FC4E0C10AA20038C2A00225458EE430AB02C08C5541A223 F2AA4DD03AD2DCBA4660FA22E31AD7A3A2FA307912D5265252B19C63AD1F7141 6B2831B16366CFC2812327E3C93BCFDE7BF1E3CC252171C2E2452448941428B8 C0C1070921C4902246D223C9D1478921C69892E64CCE244EBA3AA9474A193365 9739FB2C39E49853D1F229AE70F1454A28B1A48A95AAAB5C7D951A6AACA941D3 5232CD356EBE490B2DB6D4B5D63A75D7B9FB2E3DF4D8D356ED50F5A9FD07D5E0 500DA752C34FB66A3A2A3202CD1030EE191E9AA962E8401597A18016340ECD6C 00E770283734B311F554302A481EDA54B0C98057095D03E40E5BBB9B725FEB66 94EB4FBAE137CA9921DDFFA01C9A460FBABD50AD8E9BB04CC5D6291C9C5AD2D3 97B363703C2EB6B3F35BFB6D20C99167DFEA2D98F760A86BD0B2393BBFB51781 C6E5FB1E8BD47370CD1A56E26A7B8C13E3975BF6F10868F6DA023B47EAD30D21 36FC40923F1605535CC2903086A7DD95F02541A0D5B4547B9ECAB230592D452D 544D65FD05263E38B210D620C133E3027B8FE9201FEDDC817E7B0F4BA58E5466 E612BE8A95F946577E479791D51BA36FA031ED78A5BF846606368F270D29AFB5 C53DE95CD74CF012F2D6B7F189D204BF47CB4903819F91FDF349D12FFE8A67BB CFF790CC0FDAF880663B87ABAA38591B3BF13741CD2B457769867AC91A1D9BA2 0386B18F726E7C351E099FF92A75F3759E2E734FD83D5F74603951BDB8597690 B238524A4E6A1E6DF7B4F0BD2830DAF1FAE89809F065F1A77E1EC8E2AF98DF54 59E3E24FD25E70153E7265BBFE1B39B0C7D75C9DB7BBD656BAAAAD59A066FAEF 827874627FE481562FEFB689CB2C60F801176F0DFB4538F3DBEF902FFB3E6A2E EFA3FD1A0F9C789ADF9F044F3F239A3F8622B7EF4C72E755ABA8FA7B54E9EAD4 9DD6FCFED3B8CFDADDED770353FA099CFB45A59E76496EDE786C4FFEE4A0F7EA C951978DE5CFE837FFC35F1AA9BDCF2332FA5DFF4E45F32FD63F5DDF07C73A67 00000006624B474400FF00FF00FFA0BDA793000000097048597300002E230000 2E230178A53F760000000774494D4507E2090A022831FAF2E8C20000041B4944 41543811011004EFFB018D8D8DCF000000300000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000D07272723104000000307171710000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008F8F8F30000000000400000000FEFEFE00A8A9AA003C3C3C0000000000 EDEDED00000000000000000000000000000000001313130000000000C4C4C400 5857560000000000000000000400000000FDFEFE003A3A3A00FEFEFE00000000 00E1E2E3000000000000000000000000000000000011111100000000003A3A3A 00FDFEFE0000000000000000000400000000FEFDFE00FEFEFE00000000000000 0000E8E6E500555655000000000000000000B8B7B800FEFEFE00000000000000 0000FEFDFE0000000000000000000200000000FEFEFD00FEFEFE00FEFEFE00FE FEFE00EFEFEF00000000000000000000000000E2E2E200FEFEFE00FEFEFE00FE FEFE00FEFEFD0000000000000000000400000000FDFEFE00FEFEFE0000000000 00000000FBFCFB00000000000000000000000000FBFCFB00FEFEFE0000000000 00000000FDFEFE0000000000000000000400000000FEFDFE00FEFEFE00000000 0000000000F2F1F30087868800000000000000000000000000FEFEFE00000000 0000000000FEFDFE0000000000000000000400000000FDFEFE00FEFEFF000000 0000000000000000000000000000000000000000000000000000FEFEFF000000 000000000000FDFEFE0000000000000000000400000000FEFEFD00FEFEFE0000 00000000000000FBFCFB0005040500000000000000000000000000FEFEFE0000 00000000000000FEFEFD0000000000000000000400000000FEFEFE00FEFEFE00 0000000000000000FBFBFB00050405000000000000000000F6F7F600FEFEFE00 0000000000000000FEFEFE0000000000000000000400000000FDFDFE00FEFEFE 0000000000000000006666670000000000000000000000000000000000FEFEFE 000000000000000000FDFDFE0000000000000000000200000000FEFEFE00CDCD CD00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFE FE00FEFEFE00CDCDCD00FEFEFE0000000000000000000400000000FEFEFE0047 4746000000000000000000000000000000000000000000000000000000000000 0000000000000047474600FEFEFE00000000000000000004F1F1F1B3ABAAA94D 000000000000000000000000FBFBFB0000000000000000000000000000000000 05050500000000000000000000000000F7F7F7CD000000000100000020000000 1300000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000F3FFFFFFDA588BEB22DF1301 E30000000049454E44AE426082 } Visible = False end object ImgSwitchDisable: TImage[4] Left = 88 Height = 16 Top = 16 Width = 16 Picture.Data = { 1754506F727461626C654E6574776F726B47726170686963D508000089504E47 0D0A1A0A0000000D49484452000000100000001008060000001FF3FF61000004 3B7A5458745261772070726F66696C6520747970652065786966000078DAAD57 6D92EB280CFCCF29F6084842028EC367D5DE608FBF02639289E399BC9A672AC1 25CB52D32D4162DA7FFF76F38F5E10D11AC73E4814B17AB9E82226BD09F671B5 351F36B06E7E9F17AC6F306F1FA0CEA4331D46EFD6535AF6D35FF6AC81DE3C00 7E7981761A7C4EECD3B2A3C52F887ADF391ECB599FDE6BE8BD1DAB4B4E940639 1675A430671875CCCA12CDD74487D70FEBBD9F23EA0836D902CE565B6CD65120 0202D90E0EAA81041D1A549D0B14C5E8B0A1D719B1204D5B208F110B59027263 40474F912A05422AD888C819C28D0566DE38F315089AB982BA226830D057BE1D E627874F46EFC52A4700BA7A585C292EC4A1030C1A697CAB9B0A027DE9C693E0 73ECCB3C094BAA204F9A832E30D97C84C80C8FDAA25900A47EACF3515FE0EB50 0D679538CDCD0A064825B002C420603DA207708441054A8A1CC96156058019AB 82444724AA4DD03AD2DCFA8E87E98B8C875D5B45F56112F2AA4DA4A46239C75A 3FDE05ADA1C4C48E99853D078E9C8C90386111F1327A2E79F2CEB317EF7DF0D1 A740C1050E127C082186143192B62447893E8618634A9A33399338E9DB493D52 CA9829BBCC59B2CF21C79C8A964F71858B145F42892555AC545DE52AD5D75063 4D0D9A969269AE7193E65B68B1A5AEB5D6A9BBCE5DBAEFA1C79EB66A4BD5CBF8 03D560A98653A9E1E7B76A6AF57E049A2160EC333C3453C5D0812AEE87025AD0 3834B3019CC3A1DCD0CC46D4AE6054903CB4A960930151095D03E40E5BBB8772 1FEB6694EB9F74C34F943343BABFA01C9A462FBABD51AD8E9DB04CC58E2E1C9C 5AD2EECBD931381E1BDB79F3DBF9D3403E479EF75677C1BC8DA11E46CBE6BCF9 ED7C13686CBEDF63F1F5341E4F0D2B71B5FD1AD0C191D56ADD09529F591162C3 1F1892F552282E190C0963B8A468693CD0F3EC87798735AFF2483DD2043DAEF0 F0566C8D4F184136F67A1A45BB6D2EADB88BDA319D6B290F895F04A97EAF37FA BB3A927A3805F1216D0CEF812DD50E6437C01EFE226395497799171F96498009 F094E83B5CF97B5CA6ACC2D373FEC829D7F6089B305C37050F7C76CF66DD74F1 4BA20BA7F900A0FB68D9EBBB16969995B5CB311CF8E81AAED15A10BD2F29F330 508D2BE18574297573D5F82D57E6B4165A584E546FB6921DE44A51305F0D5DE8 962ADAF1FAD6F24195796AC2D477131EB571ED41DD34F249BDEED44FB8CC173C E0365F2EDD14C3E6CB76B48F6634EF8AEBDCD2B5B6EEC2F91837FF99EA907F2C E595BB0E61E78AF1AE22166BA3C04232B71536595B2D529CD0DD1E5068DE9981 2DE565BD422339A155E19BD696C26B69D05CDEFBEBDB96CC705659937D2A083D 453433247CB8C9C3E3643DA39DA78D5122DC4EECFAF7C0D25D2BEE730D227F78 E44A7ACFBA792E5A7A83A7F49313EEDF9D287A1CE9FF970FCF1EE47B077378E4 0DABFB8DE58F7E9298BFF29BE60CE4ABFE77B42712FD6115F5E4FC1F5116642E 95DC3D9600000006624B474400FF00FF00FFA0BDA79300000009704859730000 2E2300002E230178A53F760000000774494D4507E2090A02270955684C930000 041B494441543811011004EFFB018D8D8DCF0000003000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000D072727231040000003071717100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000008F8F8F30000000000400000000FEFEFE00A8A9AA003C3C3C00 0000000000000000000000000000000000000000000000000000000000000000 C4C4C4005857560000000000000000000400000000FDFEFE003A3A3A00FEFEFE 00000000000202020000000000000000000000000000000000FEFEFE00000000 003A3A3A00FDFEFE0000000000000000000400000000FEFDFE00FEFEFE000000 000000000000B3B3B400D2D2D20000000000000000002E2E2E004B4B4A000000 000000000000FEFDFE0000000000000000000200000000FEFEFD00FEFEFE00FE FEFE00FEFEFE00D7D7D6000F0E0E000F0E0E000F0E0E00D7D7D600FEFEFE00FE FEFE00FEFEFE00FEFEFD0000000000000000000400000000FDFEFE00FEFEFE00 0000000000000000050505000000000000000000000000000A090A00FEFEFE00 0000000000000000FDFEFE0000000000000000000400000000FEFDFE00FEFEFE 0000000000000000000504050000000000000000000000000000000000FEFEFE 000000000000000000FEFDFE0000000000000000000400000000FDFEFE00FEFE FF0000000000000000000000000000000000000000000000000000000000FEFE FF000000000000000000FDFEFE0000000000000000000400000000FEFEFD00FE FEFE0000000000000000000E0F0D006B6B6B00000000000000000095959500FE FEFE000000000000000000FEFEFD0000000000000000000400000000FEFEFE00 FEFEFE0000000000000000000504050000000000000000000000000005040500 FEFEFE000000000000000000FEFEFE0000000000000000000400000000FDFDFE 00FEFEFE000000000000000000111111000000000000000000000000001E1E1E 00FEFEFE000000000000000000FDFDFE0000000000000000000400000000FEFE FE00CDCDCD003131310000000000181A1B00C3C4C60000000000000000000B0D 0E00FEFEFE0000000000CFCFCF004949480000000000000000000400000000FE FEFE004747460000000000000000000101000000000000000000000000000000 000000151515000000000047474600FEFEFE00000000000000000004F1F1F1B3 ABAAA94D000000000000000000000000FBFBFB00000000000000000000000000 0000000005050500000000000000000000000000F7F7F7CD0000000001000000 2000000013000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000F3FFFFFFDA0D89BE DA0408C07B0000000049454E44AE426082 } Visible = False end object ImgByExtension: TImage[5] Left = 48 Height = 16 Top = 16 Width = 16 Picture.Data = { 1754506F727461626C654E6574776F726B477261706869638E04000089504E47 0D0A1A0A0000000D49484452000000100000001008060000001FF3FF61000000 06624B474400FF00FF00FFA0BDA793000000097048597300000B1300000B1301 009A9C180000000774494D4507E20A0B021E1F502469CD0000041B4944415438 11011004EFFB0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000001CECFD1FF000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000F1F1F1 0041403E00A1A2A3002D2D2E0002000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000200000000C7C7C7007978770064636200AF AEAD00FCFCFC00CCCBCB0032312F00DDDDDD00E4E3E3003A393700C9C8C800A0 9F9E00000000005F5E5D007574730001A9A9ABFF57575500B7B8B90002020300 474644009FA0A2002F2F2F00A8A8A700C1C1C0000C0B0C003232320058595A00 F2F2F20041403E00A1A2A3002D2D2E0004E5E5E5000000000049484700000000 0000000000EAE9E900000000004B4B4C0092919000F8F8F8007C7C7D00010101 0000000000000000000000000000000000041819190000000000B0B1B3001D1D 1D00010101000000000000000000B4B4B300393A3A0000000000AFB0AF005F5F 60000303030000000000F2F1F2000000000000000000FF959698FF4C4D4DFF19 1919FF373838FFA2A3A5FF979799FF080808FFB1B2B4FFB0B1B3FF000000FF93 9495FFCECFD1FF7B7C7DFF232324FF525353FF01000000FF00000000CECFD100 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000B36A77076CCD6E9C0000 000049454E44AE426082 } Visible = False end object ImgByPlugin: TImage[6] Left = 64 Height = 16 Top = 16 Width = 16 Picture.Data = { 1754506F727461626C654E6574776F726B477261706869639D02000089504E47 0D0A1A0A0000000D49484452000000100000001008060000001FF3FF61000000 1974455874536F6674776172650041646F626520496D616765526561647971C9 653C0000023F4944415478DA94534D681341187DB3BB894934B4066B69215E1A 8D17C160F18F4A6C4EDE22420F9E2C9EF52E1541457A2882A0288805152F1E3C C48B378B12A42069AA9556121BBD58B5084D5A6336C9FE8CDFCC6C4DA9ABE047 66F3CDEC7C6FBFF7DE0CE39C8331868D313B3E940BC7FAB3223757BE565363F9 187C42D4AAC7A698B97A98F366590E91E32F216A35BF174B2B8D27B5E233584B F3309BED45FC230CD5F2B15C787B4F56338272D1755C44E303D08361ECD89548 9427F772D76E139DE5A744E7E41F00AEE3649367CE03ED36CD74800580F26DB9 2179FA1CCD5DDAA9A178FD42D6B7031526215940E53E507D03685BD4F2EBB344 B6051C990477B93F859AC9A74A0FEE6622BD7D88674681B79714002389387DDD 6DC9C1F4000A578ECE05B746F639965DA5D218F36C1CA04977F9DEA9C2EE9111 60E10601083D84C65C75D6B507E8398ED5CA07741D486176E2265217F36C9D42 C533867E44C508291D9807C0758585260D47D105DBE842FA45B83B9A0EC5A2B4 F927AD8AF60DB547D2A6EABE4328DE7A0CB3652D469E4F2738D3D63A2ED86E3A 393A4C622C03DF5F01FD07A9D83B9D42B8C6179A37C06D0743D7A68513614367 8E35E601C8C3683780FA2760DB4E9472EFA0194C7E3D148B203E9CA4BC4E8D48 D005F1B01DDEA120EF82414AF726E85F47FDDB1C062FE707C5BBF7774E1410B4 240BC6347F1B09F947E96121AA053412DC85CDD8477125E4B1FEBC36C51ECD64 841EAB2DE7E56680751BF7AB23F83B84DCF35E2E2DF6F25AC731759998DF6DFC 9FF825C000F91FE26A96DA3C930000000049454E44AE426082 } Visible = False end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsbase.lrj�������������������������������������������������0000644�0001750�0000144�00000002717�14743153644�021470� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":75149509,"name":"tfrmoptionspluginsbase.stgplugins.columns[0].title.caption","sourcebytes":[65,99,116,105,118,101],"value":"Active"}, {"hash":91471358,"name":"tfrmoptionspluginsbase.stgplugins.columns[1].title.caption","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":56017954,"name":"tfrmoptionspluginsbase.stgplugins.columns[2].title.caption","sourcebytes":[82,101,103,105,115,116,101,114,101,100,32,102,111,114],"value":"Registered for"}, {"hash":41356085,"name":"tfrmoptionspluginsbase.stgplugins.columns[3].title.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":156067838,"name":"tfrmoptionspluginsbase.lblplugindescription.caption","sourcebytes":[68,101,115,99,114,105,112,116,105,111,110],"value":"Description"}, {"hash":277668,"name":"tfrmoptionspluginsbase.btnaddplugin.caption","sourcebytes":[65,38,100,100],"value":"A&dd"}, {"hash":131365221,"name":"tfrmoptionspluginsbase.btnenableplugin.caption","sourcebytes":[69,38,110,97,98,108,101],"value":"E&nable"}, {"hash":193742565,"name":"tfrmoptionspluginsbase.btnremoveplugin.caption","sourcebytes":[38,82,101,109,111,118,101],"value":"&Remove"}, {"hash":214649477,"name":"tfrmoptionspluginsbase.btnconfigplugin.caption","sourcebytes":[67,111,110,38,102,105,103,117,114,101],"value":"Con&figure"}, {"hash":45865851,"name":"tfrmoptionspluginsbase.btntweakplugin.caption","sourcebytes":[38,84,119,101,97,107],"value":"&Tweak"} ]} �������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsbase.pas�������������������������������������������������0000644�0001750�0000144�00000020556�14743153644�021465� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Plugins options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsBase; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, ComCtrls, StdCtrls, Grids, Buttons, Controls, ExtCtrls, //DC fOptionsFrame, uGlobs; type { TfrmOptionsPluginsBase } TfrmOptionsPluginsBase = class(TOptionsEditor) pnlPlugIn: TPanel; lblPlugInDescription: TLabel; stgPlugins: TStringGrid; pnlButton: TPanel; btnToggleOptionPlugins: TBitBtn; btnAddPlugin: TBitBtn; btnEnablePlugin: TBitBtn; btnRemovePlugin: TBitBtn; btnTweakPlugin: TBitBtn; btnConfigPlugin: TBitBtn; ImgSwitchEnable: TImage; ImgSwitchDisable: TImage; ImgByPlugin: TImage; ImgByExtension: TImage; procedure btnPluginsNotImplementedClick(Sender: TObject); procedure btnRemovePluginClick(Sender: TObject); procedure btnTweakPluginClick(Sender: TObject); procedure stgPluginsDblClick(Sender: TObject); procedure stgPluginsDragOver(Sender, {%H-}Source: TObject; X, Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure stgPluginsDragDrop(Sender, {%H-}Source: TObject; X, Y: integer); procedure stgPluginsGetCellHint(Sender: TObject; ACol, ARow: integer; var HintText: string); procedure stgPluginsShowHint(Sender: TObject; HintInfo: PHintInfo); procedure ActualAddPlugin({%H-}sPluginFilename: string); virtual; private FPluginType: TPluginType; protected property PluginType: TPluginType read FPluginType write FPluginType; procedure Init; override; procedure ShowPluginsTable; virtual; procedure stgPluginsOnSelection(Sender: TObject; {%H-}aCol, {%H-}aRow: integer); virtual; procedure ActualDeletePlugin({%H-}iIndex: integer); virtual; procedure ActualPluginsMove({%H-}iSource, {%H-}iDestination: integer); virtual; public class function GetIconIndex: integer; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; end; function GetPluginFilenameToSave(const Filename: string): string; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. StrUtils, LCLProc, Forms, Dialogs, //DC udcutils, uLng, uShowMsg, fTweakPlugin, uDefaultPlugins; { TfrmOptionsPluginsBase } { TfrmOptionsPluginsBase.Init } procedure TfrmOptionsPluginsBase.Init; begin // Localize plugins. stgPlugins.Columns.Items[0].Title.Caption := rsOptPluginsActive; stgPlugins.Columns.Items[1].Title.Caption := rsOptPluginsName; stgPlugins.Columns.Items[2].Title.Caption := rsOptPluginsRegisteredFor; stgPlugins.Columns.Items[3].Title.Caption := rsOptPluginsFileName; stgPlugins.OnSelection := @stgPluginsOnSelection; end; { TfrmOptionsPluginsBase } procedure TfrmOptionsPluginsBase.ShowPluginsTable; begin //empty end; { TfrmOptionsPluginsBase.stgPluginsOnSelection} procedure TfrmOptionsPluginsBase.stgPluginsOnSelection(Sender: TObject; aCol, aRow: integer); begin //empty end; { TfrmOptionsPluginsBase.ActualAddPlugin } procedure TfrmOptionsPluginsBase.ActualAddPlugin(sPluginFilename: string); begin //empty end; { TfrmOptionsPluginsBase.ActualDeletePlugin } procedure TfrmOptionsPluginsBase.ActualDeletePlugin(iIndex: integer); begin //empty end; { TfrmOptionsPluginsBase.ActualPluginsMove } procedure TfrmOptionsPluginsBase.ActualPluginsMove(iSource, iDestination: integer); begin //empty end; { TfrmOptionsPluginsBase.GetIconIndex } class function TfrmOptionsPluginsBase.GetIconIndex: integer; begin Result := 6; end; { TfrmOptionsPluginsBase.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsPluginsBase.IsSignatureComputedFromAllWindowComponents: boolean; begin Result := False; end; { TfrmOptionsPluginsBase.btnPluginsNotImplementedClick } procedure TfrmOptionsPluginsBase.btnPluginsNotImplementedClick(Sender: TObject); begin msgError(rsMsgNotImplemented); end; { TfrmOptionsPluginsBase.btnRemovePluginClick } procedure TfrmOptionsPluginsBase.btnRemovePluginClick(Sender: TObject); var iCurrentSelection: integer; begin iCurrentSelection := stgPlugins.Row; if iCurrentSelection < stgPlugins.FixedRows then Exit; self.ActualDeletePlugin(pred(iCurrentSelection)); stgPlugins.DeleteColRow(False, iCurrentSelection); if iCurrentSelection < stgPlugins.RowCount then stgPlugins.Row := iCurrentSelection else if stgPlugins.RowCount > 1 then stgPlugins.Row := pred(stgPlugins.RowCount) else stgPlugins.Row := -1; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsBase. } procedure TfrmOptionsPluginsBase.btnTweakPluginClick(Sender: TObject); var iPluginIndex: integer; begin iPluginIndex := stgPlugins.Row - stgPlugins.FixedRows; if iPluginIndex < 0 then Exit; if ShowTweakPluginDlg(PluginType, iPluginIndex) then ShowPluginsTable; end; { TfrmOptionsPluginsBase.stgPluginsDblClick } procedure TfrmOptionsPluginsBase.stgPluginsDblClick(Sender: TObject); begin if btnTweakPlugin.Enabled then btnTweakPlugin.Click; end; { TfrmOptionsPluginsBase.stgPluginsDragOver } procedure TfrmOptionsPluginsBase.stgPluginsDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); var iDestCol: integer = 0; iDestRow: integer = 0; begin stgPlugins.MouseToCell(X, Y, iDestCol, iDestRow); Accept := (iDestRow > 0); end; { TfrmOptionsPluginsBase.stgPluginsDragDrop } procedure TfrmOptionsPluginsBase.stgPluginsDragDrop(Sender, Source: TObject; X, Y: integer); var iDestCol, iDestRow, iSourceRow: integer; begin stgPlugins.MouseToCell(X, Y, {%H-}iDestCol, {%H-}iDestRow); if iDestRow > 0 then begin iSourceRow := stgPlugins.Row; //We need to that because after having done the following "MoveColRow", the "stgPlugins.Row" changed! So we need to remember original index. stgPlugins.MoveColRow(False, iSourceRow, iDestRow); ActualPluginsMove(pred(iSourceRow), pred(iDestRow)); end; end; { TfrmOptionsPluginsBase.stgPluginsGetCellHint } procedure TfrmOptionsPluginsBase.stgPluginsGetCellHint(Sender: TObject; ACol, ARow: integer; var HintText: string); var sMaybeHint: string; begin //The actual "pipe" symbol interfere when showing the hint. Let's replace it with a similar look-alike symbol. sMaybeHint := Stringreplace(stgPlugins.Cells[ACol, ARow], '|', '¦', [rfReplaceAll]); HintText := IfThen(((stgPlugins.Canvas.TextWidth(sMaybeHint) + 10) > stgPlugins.ColWidths[ACol]), sMaybeHint, ''); end; { TfrmOptionsPluginsWLX.stgPluginsShowHint } procedure TfrmOptionsPluginsBase.stgPluginsShowHint(Sender: TObject; HintInfo: PHintInfo); begin if gFileInfoToolTipValue[Ord(gToolTipHideTimeOut)] <> -1 then HintInfo^.HideTimeout := gFileInfoToolTipValue[Ord(gToolTipHideTimeOut)]; end; { GetPluginFilenameToSave } function GetPluginFilenameToSave(const Filename: string): string; var sMaybeBasePath, SubWorkingPath, MaybeSubstitionPossible: string; begin Result := Filename; sMaybeBasePath := IfThen((gPluginFilenameStyle = pfsRelativeToDC), EnvVarCommanderPath, gPluginPathToBeRelativeTo); case gPluginFilenameStyle of pfsAbsolutePath: ; pfsRelativeToDC, pfsRelativeToFollowingPath: begin SubWorkingPath := IncludeTrailingPathDelimiter(mbExpandFileName(sMaybeBasePath)); MaybeSubstitionPossible := ExtractRelativePath(IncludeTrailingPathDelimiter(SubWorkingPath), Filename); if MaybeSubstitionPossible <> Filename then Result := IncludeTrailingPathDelimiter(sMaybeBasePath) + MaybeSubstitionPossible; end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsdsx.lfm��������������������������������������������������0000644�0001750�0000144�00000001332�14743153644�021333� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsDSX: TfrmOptionsPluginsDSX DesignLeft = 291 DesignTop = 266 inherited stgPlugins: TStringGrid AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner end inherited pnlPlugIn: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner inherited lblPlugInDescription: TLabel Caption = 'Searc&h plugins allow one to use alternative search algorithms or external tools (like "locate", etc.)' end end inherited pnlButton: TPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideBottom.Control = Owner inherited btnAddPlugin: TBitBtn OnClick = btnAddPluginClick end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsdsx.lrj��������������������������������������������������0000644�0001750�0000144�00000002326�14743153644�021350� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":75149509,"name":"tfrmoptionspluginsdsx.stgplugins.columns[0].title.caption","sourcebytes":[65,99,116,105,118,101],"value":"Active"}, {"hash":91471358,"name":"tfrmoptionspluginsdsx.stgplugins.columns[1].title.caption","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":56017954,"name":"tfrmoptionspluginsdsx.stgplugins.columns[2].title.caption","sourcebytes":[82,101,103,105,115,116,101,114,101,100,32,102,111,114],"value":"Registered for"}, {"hash":41356085,"name":"tfrmoptionspluginsdsx.stgplugins.columns[3].title.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":216158153,"name":"tfrmoptionspluginsdsx.lblplugindescription.caption","sourcebytes":[83,101,97,114,99,38,104,32,112,108,117,103,105,110,115,32,97,108,108,111,119,32,111,110,101,32,116,111,32,117,115,101,32,97,108,116,101,114,110,97,116,105,118,101,32,115,101,97,114,99,104,32,97,108,103,111,114,105,116,104,109,115,32,111,114,32,101,120,116,101,114,110,97,108,32,116,111,111,108,115,32,40,108,105,107,101,32,34,108,111,99,97,116,101,34,44,32,101,116,99,46,41],"value":"Searc&h plugins allow one to use alternative search algorithms or external tools (like \"locate\", etc.)"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsdsx.pas��������������������������������������������������0000644�0001750�0000144�00000014537�14743153644�021353� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Plugins DSX options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsDSX; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, ComCtrls, Grids, Buttons, Controls, ExtCtrls, //DC fOptionsFrame, uDSXModule, foptionspluginsbase; type { TfrmOptionsPluginsDSX } TfrmOptionsPluginsDSX = class(TfrmOptionsPluginsBase) procedure btnAddPluginClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure Done; override; procedure stgPluginsOnSelection(Sender: TObject; {%H-}aCol, aRow: integer); override; procedure ActualAddPlugin(sPluginFilename: string); override; procedure ActualDeletePlugin(iIndex: integer); override; procedure ActualPluginsMove(iSource, iDestination: integer); override; public class function GetTitle: string; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; procedure ShowPluginsTable; override; end; var tmpDSXPlugins: TDSXModuleList; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. LCLProc, Forms, Dialogs, //DC uLng, uGlobs, dmCommonData, DCStrUtils, uDefaultPlugins; const COLNO_NAME = 0; COLNO_DESCRIPTION = 1; COLNO_FILENAME = 2; { TfrmOptionsPluginsDSX } { TfrmOptionsPluginsDSX.Init } procedure TfrmOptionsPluginsDSX.Init; begin PluginType := ptDSX; inherited Init; stgPlugins.Columns.Items[COLNO_NAME].Title.Caption := rsOptPluginsName; stgPlugins.Columns.Items[COLNO_NAME].Alignment := taLeftJustify; //Because from the "Base", it was centered. stgPlugins.Columns.Items[COLNO_DESCRIPTION].Title.Caption := rsOptPluginsDescription; stgPlugins.Columns.Items[COLNO_FILENAME].Title.Caption := rsOptPluginsFileName; stgPlugins.Columns.Delete(succ(COLNO_FILENAME)); //Because from the "Base" it has one column more than required. btnEnablePlugin.Visible := False; //Because with DSX there is no enable/disable. btnConfigPlugin.Visible := False; tmpDSXPlugins := TDSXModuleList.Create; end; { TfrmOptionsPluginsDSX.Load } procedure TfrmOptionsPluginsDSX.Load; begin tmpDSXPlugins.Assign(gDSXPlugins); ShowPluginsTable; end; { TfrmOptionsPluginsDSX.Save } function TfrmOptionsPluginsDSX.Save: TOptionsEditorSaveFlags; begin gDSXPlugins.Assign(tmpDSXPlugins); Result := []; end; { TfrmOptionsPluginsDSX.Done } procedure TfrmOptionsPluginsDSX.Done; begin FreeAndNil(tmpDSXPlugins); end; { TfrmOptionsPluginsDSX.GetTitle } class function TfrmOptionsPluginsDSX.GetTitle: string; begin Result := rsOptionsEditorPlugins + ' DSX'; end; { TfrmOptionsPluginsDSX.ExtraOptionsSignature } function TfrmOptionsPluginsDSX.ExtraOptionsSignature(CurrentSignature: dword): dword; begin Result := tmpDSXPlugins.ComputeSignature(CurrentSignature); end; { TfrmOptionsPluginsDSX.ShowPluginsTable } procedure TfrmOptionsPluginsDSX.ShowPluginsTable; var I: integer; begin stgPlugins.RowCount := tmpDSXPlugins.Count + stgPlugins.FixedRows; for i := 0 to pred(tmpDSXPlugins.Count) do begin stgPlugins.Cells[COLNO_NAME, I + stgPlugins.FixedRows] := tmpDSXPlugins.GetDsxModule(i).Name; stgPlugins.Cells[COLNO_DESCRIPTION, I + stgPlugins.FixedRows] := tmpDSXPlugins.GetDsxModule(i).Descr; stgPlugins.Cells[COLNO_FILENAME, I + stgPlugins.FixedRows] := tmpDSXPlugins.GetDsxModule(i).FileName; end; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsDSX.stgPluginsOnSelection } procedure TfrmOptionsPluginsDSX.stgPluginsOnSelection(Sender: TObject; aCol, aRow: integer); var bEnable: boolean = False; begin if (aRow > 0) and (aRow < stgPlugins.RowCount) then bEnable := True; btnRemovePlugin.Enabled := bEnable; btnTweakPlugin.Enabled := bEnable; btnConfigPlugin.Enabled := bEnable; end; { TfrmOptionsPluginsDSX.ActualDeletePlugin } procedure TfrmOptionsPluginsDSX.ActualDeletePlugin(iIndex: integer); begin tmpDSXPlugins.DeleteItem(iIndex); end; { TfrmOptionsPluginsDSX.ActualPluginsMove } procedure TfrmOptionsPluginsDSX.ActualPluginsMove(iSource, iDestination: integer); begin tmpDSXPlugins.Move(iSource, iDestination); end; { TfrmOptionsPluginsDSX.btnAddPluginClick } procedure TfrmOptionsPluginsDSX.btnAddPluginClick(Sender: TObject); begin dmComData.OpenDialog.Filter := 'Search plugins (*.dsx)|*.dsx'; if dmComData.OpenDialog.Execute then ActualAddPlugin(dmComData.OpenDialog.FileName); end; { TfrmOptionsPluginsDSX.ActualAddPlugin } procedure TfrmOptionsPluginsDSX.ActualAddPlugin(sPluginFilename: string); var I, J: integer; sPluginName: string; begin if not CheckPlugin(sPluginFilename) then Exit; sPluginName := ExtractOnlyFileName(sPluginFilename); I := tmpDSXPlugins.Add(sPluginName, GetPluginFilenameToSave(sPluginFilename), EmptyStr); if not tmpDSXPlugins.LoadModule(sPluginName) then begin MessageDlg(Application.Title, rsMsgInvalidPlugin, mtError, [mbOK], 0, mbOK); tmpDSXPlugins.DeleteItem(I); Exit; end; stgPlugins.RowCount := stgPlugins.RowCount + 1; J := stgPlugins.RowCount - stgPlugins.FixedRows; stgPlugins.Cells[COLNO_NAME, J] := tmpDSXPlugins.GetDsxModule(I).Name; stgPlugins.Cells[COLNO_DESCRIPTION, J] := tmpDSXPlugins.GetDsxModule(I).Descr; stgPlugins.Cells[COLNO_FILENAME, J] := tmpDSXPlugins.GetDsxModule(I).FileName; stgPlugins.Row := J; //This will trig automatically the "OnSelection" event. if gPluginInAutoTweak then btnTweakPlugin.click; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsgroup.lfm������������������������������������������������0000644�0001750�0000144�00000024501�14743153644�021674� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsGroup: TfrmOptionsPluginsGroup Height = 244 Width = 622 HelpKeyword = '/configuration.html#ConfigPlugins' ClientHeight = 244 ClientWidth = 622 OnExit = FrameExit DesignLeft = 134 DesignTop = 310 object gbConfiguration: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 200 Top = 6 Width = 610 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Configuration:' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 6 ClientHeight = 180 ClientWidth = 606 ParentShowHint = False ShowHint = True TabOrder = 0 object ckbAutoTweak: TCheckBox AnchorSideLeft.Control = gbConfiguration AnchorSideTop.Control = gbConfiguration Left = 6 Height = 19 Top = 6 Width = 349 Caption = 'When adding a new plugin, automatically go in tweak window' TabOrder = 0 end object lbPathToBeRelativeTo: TLabel AnchorSideLeft.Control = ckbAutoTweak AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 64 Width = 112 Caption = 'Path to be relative to:' ParentColor = False end object dePathToBeRelativeTo: TDirectoryEdit AnchorSideLeft.Control = lbPathToBeRelativeTo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbPluginFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnPathToBeRelativeToHelper Left = 120 Height = 23 Top = 60 Width = 455 ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 1 end object btnPathToBeRelativeToHelper: TSpeedButton AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideRight.Control = cbPluginFilenameStyle AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = dePathToBeRelativeTo AnchorSideBottom.Side = asrBottom Left = 577 Height = 23 Top = 60 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnPathToBeRelativeToHelperClick end object cbPluginFilenameStyle: TComboBox AnchorSideLeft.Control = lbPluginFilenameStyle AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ckbAutoTweak AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbConfiguration AnchorSideRight.Side = asrBottom Left = 265 Height = 23 Top = 31 Width = 335 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 3 ItemHeight = 15 OnChange = cbPluginFilenameStyleChange Style = csDropDownList TabOrder = 2 end object lbPluginFilenameStyle: TLabel AnchorSideLeft.Control = ckbAutoTweak AnchorSideTop.Control = cbPluginFilenameStyle AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 35 Width = 256 Caption = 'Plugin filename style when adding a new plugin:' ParentColor = False end object btnPathToBeRelativeToAll: TButton AnchorSideLeft.Control = ckbAutoTweak AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 6 Height = 25 Top = 89 Width = 315 AutoSize = True Caption = 'Apply current settings to all current configured plugins' OnClick = btnPathToBeRelativeToAllClick TabOrder = 3 end object fneLuaLibraryFilename: TFileNameEdit AnchorSideLeft.Control = ckbAutoTweak AnchorSideTop.Control = lblLuaLibraryFilename AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnLuaLibraryFilename Left = 6 Height = 23 Top = 151 Width = 569 OnAcceptFileName = fneLuaLibraryFilenameAcceptFileName DialogTitle = 'Select Lua library file' DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 TabOrder = 4 OnButtonClick = fneLuaLibraryFilenameButtonClick end object lblLuaLibraryFilename: TLabel AnchorSideLeft.Control = ckbAutoTweak AnchorSideTop.Control = btnPathToBeRelativeToAll AnchorSideTop.Side = asrBottom Left = 6 Height = 15 Top = 130 Width = 112 BorderSpacing.Top = 16 Caption = 'Lua library file to use:' ParentColor = False end object btnLuaLibraryFilename: TSpeedButton AnchorSideTop.Control = fneLuaLibraryFilename AnchorSideRight.Control = cbPluginFilenameStyle AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneLuaLibraryFilename AnchorSideBottom.Side = asrBottom Left = 577 Height = 23 Top = 151 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnLuaLibraryFilenameClick end end object pmPathToBeRelativeToHelper: TPopupMenu[1] left = 424 top = 32 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsgroup.lrj������������������������������������������������0000644�0001750�0000144�00000003275�14743153644�021712� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":247865466,"name":"tfrmoptionspluginsgroup.gbconfiguration.caption","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,58],"value":"Configuration:"}, {"hash":216983,"name":"tfrmoptionspluginsgroup.ckbautotweak.caption","sourcebytes":[87,104,101,110,32,97,100,100,105,110,103,32,97,32,110,101,119,32,112,108,117,103,105,110,44,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,103,111,32,105,110,32,116,119,101,97,107,32,119,105,110,100,111,119],"value":"When adding a new plugin, automatically go in tweak window"}, {"hash":256553386,"name":"tfrmoptionspluginsgroup.lbpathtoberelativeto.caption","sourcebytes":[80,97,116,104,32,116,111,32,98,101,32,114,101,108,97,116,105,118,101,32,116,111,58],"value":"Path to be relative to:"}, {"hash":94551482,"name":"tfrmoptionspluginsgroup.lbpluginfilenamestyle.caption","sourcebytes":[80,108,117,103,105,110,32,102,105,108,101,110,97,109,101,32,115,116,121,108,101,32,119,104,101,110,32,97,100,100,105,110,103,32,97,32,110,101,119,32,112,108,117,103,105,110,58],"value":"Plugin filename style when adding a new plugin:"}, {"hash":251510723,"name":"tfrmoptionspluginsgroup.btnpathtoberelativetoall.caption","sourcebytes":[65,112,112,108,121,32,99,117,114,114,101,110,116,32,115,101,116,116,105,110,103,115,32,116,111,32,97,108,108,32,99,117,114,114,101,110,116,32,99,111,110,102,105,103,117,114,101,100,32,112,108,117,103,105,110,115],"value":"Apply current settings to all current configured plugins"}, {"hash":125456490,"name":"tfrmoptionspluginsgroup.lbllualibraryfilename.caption","sourcebytes":[76,117,97,32,108,105,98,114,97,114,121,32,102,105,108,101,32,116,111,32,117,115,101,58],"value":"Lua library file to use:"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginsgroup.pas������������������������������������������������0000644�0001750�0000144�00000024607�14743153644�021710� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Options Plugins group Copyright (C) 2018-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsGroup; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, StdCtrls, Buttons, EditBtn, Menus, fOptionsFrame, //DC DCStrUtils; type { TfrmOptionsPluginsGroup } TfrmOptionsPluginsGroup = class(TOptionsEditor) gbConfiguration: TGroupBox; ckbAutoTweak: TCheckBox; lbPluginFilenameStyle: TLabel; cbPluginFilenameStyle: TComboBox; lbPathToBeRelativeTo: TLabel; dePathToBeRelativeTo: TDirectoryEdit; btnPathToBeRelativeToHelper: TSpeedButton; btnPathToBeRelativeToAll: TButton; pmPathToBeRelativeToHelper: TPopupMenu; lblLuaLibraryFilename: TLabel; fneLuaLibraryFilename: TFileNameEdit; btnLuaLibraryFilename: TSpeedButton; procedure cbPluginFilenameStyleChange(Sender: TObject); procedure btnPathToBeRelativeToHelperClick(Sender: TObject); procedure btnPathToBeRelativeToAllClick(Sender: TObject); procedure fneLuaLibraryFilenameAcceptFileName(Sender: TObject; var Value: String); procedure fneLuaLibraryFilenameButtonClick(Sender: TObject); procedure btnLuaLibraryFilenameClick(Sender: TObject); procedure FrameExit(Sender: TObject); private FResultForWhenWeExit: TOptionsEditorSaveFlags; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Controls, Forms, //DC uShowMsg, fOptionsPluginsBase, uDebug, lua, uWDXModule, uGlobs, uDCUtils, uSpecialDir, uLng, uDefaultPlugins, fOptions, fOptionsPluginsDSX, fOptionsPluginsWCX, fOptionsPluginsWDX, fOptionsPluginsWFX, fOptionsPluginsWLX; { TOptionsPluginsGroup } { TfrmOptionsPluginsGroup.Init } procedure TfrmOptionsPluginsGroup.Init; begin fneLuaLibraryFilename.DialogTitle := rsOptPluginsSelectLuaLibrary; ParseLineToList(rsPluginFilenameStyleList, cbPluginFilenameStyle.Items); {$IF DEFINED(MSWINDOWS)} fneLuaLibraryFilename.Filter := ParseLineToFileFilter([rsFilterLibraries, '*.dll', rsFilterAnyFiles, AllFilesMask]); {$ELSEIF DEFINED(DARWIN)} fneLuaLibraryFilename.Filter := ParseLineToFileFilter([rsFilterLibraries, '*.dylib', rsFilterAnyFiles, AllFilesMask]); {$ELSEIF DEFINED(UNIX)} fneLuaLibraryFilename.Filter := ParseLineToFileFilter([rsFilterLibraries, '*.so', rsFilterAnyFiles, AllFilesMask]); {$ELSE} fneLuaLibraryFilename.Filter := ParseLineToFileFilter([rsFilterLibraries, '*.dll;*.dylib;*.so', rsFilterAnyFiles, AllFilesMask]); {$ENDIF} FResultForWhenWeExit := []; end; { TfrmOptionsPluginsGroup.Load } procedure TfrmOptionsPluginsGroup.Load; begin ckbAutoTweak.Checked := gPluginInAutoTweak; cbPluginFilenameStyle.ItemIndex := integer(gPluginFilenameStyle); cbPluginFilenameStyleChange(cbPluginFilenameStyle); dePathToBeRelativeTo.Text := gPluginPathToBeRelativeTo; fneLuaLibraryFilename.FileName := gLuaLib; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathToBeRelativeToHelper, mp_PATHHELPER, nil); end; { TfrmOptionsPluginsGroup.Save } function TfrmOptionsPluginsGroup.Save: TOptionsEditorSaveFlags; var iIndexPlugin:integer; begin gPluginInAutoTweak := ckbAutoTweak.Checked; gPluginFilenameStyle := TConfigFilenameStyle(cbPluginFilenameStyle.ItemIndex); gPluginPathToBeRelativeTo := dePathToBeRelativeTo.Text; if gLuaLib <> fneLuaLibraryFilename.FileName then begin for iIndexPlugin:=0 to pred(gWDXPlugins.Count) do if gWDXPlugins.GetWdxModule(iIndexPlugin).ClassType = TLuaWdx then TLuaWdx(gWDXPlugins.GetWdxModule(iIndexPlugin)).UnloadModule; UnloadLuaLib; gLuaLib := fneLuaLibraryFilename.FileName; if not LoadLuaLib(mbExpandFileName(gLuaLib)) then MsgError(Format(rsMsgScriptCantFindLibrary, [gLuaLib])); Include(FResultForWhenWeExit, oesfNeedsRestart); end; Result := FResultForWhenWeExit; end; { TfrmOptionsPluginsGroup.GetIconIndex } class function TfrmOptionsPluginsGroup.GetIconIndex: integer; begin Result := 6; end; { TfrmOptionsPluginsGroup.GetTitle } class function TfrmOptionsPluginsGroup.GetTitle: string; begin Result := rsOptionsEditorPlugins; end; { TfrmOptionsPluginsGroup.cbPluginFilenameStyleChange } procedure TfrmOptionsPluginsGroup.cbPluginFilenameStyleChange(Sender: TObject); begin lbPathToBeRelativeTo.Visible := (TConfigFilenameStyle(cbPluginFilenameStyle.ItemIndex) = TConfigFilenameStyle.pfsRelativeToFollowingPath); dePathToBeRelativeTo.Visible := lbPathToBeRelativeTo.Visible; btnPathToBeRelativeToHelper.Visible := lbPathToBeRelativeTo.Visible; end; { TfrmOptionsPluginsGroup.btnPathToBeRelativeToHelperClick } procedure TfrmOptionsPluginsGroup.btnPathToBeRelativeToHelperClick(Sender: TObject); begin dePathToBeRelativeTo.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(dePathToBeRelativeTo, pfPATH); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsPluginsGroup.btnPathToBeRelativeToAllClick } // Let's don't apply the modification right away on "Global" plugin strutures. // Let's load the configuration page of each and do the modifications on temporary plugin structure. // If user is happy with what he sees, he will apply/save it. procedure TfrmOptionsPluginsGroup.btnPathToBeRelativeToAllClick(Sender: TObject); var iIndexPlugin: integer; Options: IOptionsDialog; Editor: TOptionsEditor; begin Self.SaveSettings; //Call "SaveSettings" instead of just "Save" to get option signature set right away do we don't bother user for that page when close. Options := ShowOptions(TfrmOptionsPluginsDSX); Editor := Options.GetEditor(TfrmOptionsPluginsDSX); for iIndexPlugin := 0 to pred(tmpDSXPlugins.Count) do tmpDSXPlugins.GetDSXModule(iIndexPlugin).FileName := GetPluginFilenameToSave(mbExpandFileName(tmpDSXPlugins.GetDSXModule(iIndexPlugin).FileName)); TfrmOptionsPluginsDSX(Editor).ShowPluginsTable; Options := ShowOptions(TfrmOptionsPluginsWCX); Editor := Options.GetEditor(TfrmOptionsPluginsWCX); for iIndexPlugin := 0 to pred(tmpWCXPlugins.Count) do tmpWCXPlugins.FileName[iIndexPlugin] := GetPluginFilenameToSave(mbExpandFileName(tmpWCXPlugins.FileName[iIndexPlugin])); TfrmOptionsPluginsWCX(Editor).ShowPluginsTable; Options := ShowOptions(TfrmOptionsPluginsWDX); Editor := Options.GetEditor(TfrmOptionsPluginsWDX); for iIndexPlugin := 0 to pred(tmpWDXPlugins.Count) do tmpWDXPlugins.GetWdxModule(iIndexPlugin).FileName := GetPluginFilenameToSave(mbExpandFileName(tmpWDXPlugins.GetWdxModule(iIndexPlugin).FileName)); TfrmOptionsPluginsWDX(Editor).ShowPluginsTable; Options := ShowOptions(TfrmOptionsPluginsWFX); Editor := Options.GetEditor(TfrmOptionsPluginsWFX); for iIndexPlugin := 0 to pred(tmpWFXPlugins.Count) do tmpWFXPlugins.FileName[iIndexPlugin] := GetPluginFilenameToSave(mbExpandFileName(tmpWFXPlugins.FileName[iIndexPlugin])); TfrmOptionsPluginsWFX(Editor).ShowPluginsTable; Options := ShowOptions(TfrmOptionsPluginsWLX); Editor := Options.GetEditor(TfrmOptionsPluginsWLX); for iIndexPlugin := 0 to pred(tmpWLXPlugins.Count) do tmpWLXPlugins.GetWlxModule(iIndexPlugin).FileName := GetPluginFilenameToSave(mbExpandFileName(tmpWLXPlugins.GetWlxModule(iIndexPlugin).FileName)); TfrmOptionsPluginsWLX(Editor).ShowPluginsTable; fneLuaLibraryFilename.FileName := GetPluginFilenameToSave(mbExpandFileName(fneLuaLibraryFilename.FileName)); //Let's switch to plugin configuration tab with at least one configure element. if tmpDSXPlugins.Count > 0 then ShowOptions(TfrmOptionsPluginsDSX) else if tmpWCXPlugins.Count > 0 then ShowOptions(TfrmOptionsPluginsWCX) else if tmpWDXPlugins.Count > 1 then //For the WDX one we validate more than the default embedded one. ShowOptions(TfrmOptionsPluginsWDX) else if tmpWFXPlugins.Count > 0 then ShowOptions(TfrmOptionsPluginsWFX) else if tmpWLXPlugins.Count > 0 then ShowOptions(TfrmOptionsPluginsWLX); end; { TfrmOptionsPluginsGroup.FrameExit } // When focus is lost, let's save the settings here immediately. // People will expect the settings here be effective right after changing them. // Still in configuration, when they go in specific plugin configuration, they want to see the effects immediately. procedure TfrmOptionsPluginsGroup.FrameExit(Sender: TObject); begin Self.SaveSettings; //Call "SaveSettings" instead of just "Save" to get option signature set right away do we don't bother user for that page when close. end; { TfrmOptionsPluginsGroup.btnLuaDllFilenameClick } procedure TfrmOptionsPluginsGroup.btnLuaLibraryFilenameClick(Sender: TObject); begin fneLuaLibraryFilename.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneLuaLibraryFilename, pfFILE); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsPluginsGroup.fneLuaDllFilenameButtonClick } procedure TfrmOptionsPluginsGroup.fneLuaLibraryFilenameButtonClick(Sender: TObject); var sInitialDirectory: string; begin sInitialDirectory := ExcludeTrailingPathDelimiter(ExtractFilePath(mbExpandFileName(fneLuaLibraryFilename.FileName))); if DirectoryExists(sInitialDirectory) then fneLuaLibraryFilename.InitialDir := sInitialDirectory; end; { TfrmOptionsPluginsGroup.fneLuaDllFilenameAcceptFileName } procedure TfrmOptionsPluginsGroup.fneLuaLibraryFilenameAcceptFileName(Sender: TObject; var Value: String); begin Value := GetPluginFilenameToSave(Value); end; end. �������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswcx.lfm��������������������������������������������������0000644�0001750�0000144�00000003345�14743153644�021344� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsWCX: TfrmOptionsPluginsWCX inherited stgPlugins: TStringGrid AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner Columns = < item Alignment = taCenter MaxSize = 80 PickList.Strings = ( ) SizePriority = 0 Title.Caption = 'Active' Width = 161 end item PickList.Strings = ( ) SizePriority = 0 Title.Caption = 'Plugin' Width = 183 end item PickList.Strings = ( ) SizePriority = 0 Title.Caption = 'Registered for' Width = 277 end item PickList.Strings = ( ) SizePriority = 0 Title.Caption = 'File name' Width = 64 end> ColWidths = ( 161 183 277 64 ) end inherited pnlPlugIn: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner inherited lblPlugInDescription: TLabel Caption = 'Pack&er plugins are used to work with archives' end end inherited pnlButton: TPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideBottom.Control = Owner inherited btnAddPlugin: TBitBtn OnClick = btnAddPluginClick end inherited btnEnablePlugin: TBitBtn OnClick = btnEnablePluginClick end inherited btnRemovePlugin: TBitBtn OnClick = btnRemovePluginClick end inherited btnConfigPlugin: TBitBtn OnClick = btnConfigPluginClick end end inherited ImgSwitchEnable: TImage Top = 20 end inherited ImgSwitchDisable: TImage Left = 16 Top = 20 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswcx.lrj��������������������������������������������������0000644�0001750�0000144�00000001717�14743153644�021356� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":75149509,"name":"tfrmoptionspluginswcx.stgplugins.columns[0].title.caption","sourcebytes":[65,99,116,105,118,101],"value":"Active"}, {"hash":91471358,"name":"tfrmoptionspluginswcx.stgplugins.columns[1].title.caption","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":56017954,"name":"tfrmoptionspluginswcx.stgplugins.columns[2].title.caption","sourcebytes":[82,101,103,105,115,116,101,114,101,100,32,102,111,114],"value":"Registered for"}, {"hash":41356085,"name":"tfrmoptionspluginswcx.stgplugins.columns[3].title.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":70897075,"name":"tfrmoptionspluginswcx.lblplugindescription.caption","sourcebytes":[80,97,99,107,38,101,114,32,112,108,117,103,105,110,115,32,97,114,101,32,117,115,101,100,32,116,111,32,119,111,114,107,32,119,105,116,104,32,97,114,99,104,105,118,101,115],"value":"Pack&er plugins are used to work with archives"} ]} �������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswcx.pas��������������������������������������������������0000644�0001750�0000144�00000032176�14743153644�021355� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Plugins WCX options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsWCX; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, ComCtrls, Grids, Buttons, Controls, ExtCtrls, //DC fOptionsFrame, uWCXModule, foptionspluginsbase; type { TfrmOptionsPluginsWCX } TfrmOptionsPluginsWCX = class(TfrmOptionsPluginsBase) procedure stgPluginsWCXDragDrop(Sender, {%H-}Source: TObject; X, Y: integer); procedure btnToggleViewClick(Sender: TObject); procedure btnAddPluginClick(Sender: TObject); procedure btnEnablePluginClick(Sender: TObject); procedure btnRemovePluginClick(Sender: TObject); procedure btnTweakPluginClick(Sender: TObject); procedure btnConfigPluginClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure Done; override; procedure stgPluginsOnSelection(Sender: TObject; {%H-}aCol, aRow: integer); override; procedure ActualAddPlugin(sPluginFilename: string); override; public class function GetTitle: string; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; procedure ShowPluginsTable; override; end; var tmpWCXPlugins: TWCXModuleList; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. StrUtils, LCLProc, Forms, Dialogs, //DC uLng, uGlobs, uShowMsg, fTweakPlugin, dmCommonData, DCStrUtils, uDefaultPlugins; const COLNO_ACTIVE = 0; COLNO_NAME = 1; COLNO_EXT = 2; COLNO_FILENAME = 3; { TfrmOptionsPluginsWCX } { TfrmOptionsPluginsWCX.Init } procedure TfrmOptionsPluginsWCX.Init; begin PluginType := ptWCX; inherited Init; tmpWCXPlugins := TWCXModuleList.Create; stgPlugins.OnDragDrop := @stgPluginsWCXDragDrop; btnToggleOptionPlugins.OnClick := @btnToggleViewClick; btnToggleOptionPlugins.Visible := True; end; { TfrmOptionsPluginsWCX.Load } procedure TfrmOptionsPluginsWCX.Load; begin tmpWCXPlugins.Assign(gWCXPlugins); ShowPluginsTable; end; { TfrmOptionsPluginsWCX.Save } function TfrmOptionsPluginsWCX.Save: TOptionsEditorSaveFlags; begin gWCXPlugins.Assign(tmpWCXPlugins); Result := []; end; { TfrmOptionsPluginsWCX.Done } procedure TfrmOptionsPluginsWCX.Done; begin FreeAndNil(tmpWCXPlugins); end; { TfrmOptionsPluginsWCX.GetTitle } class function TfrmOptionsPluginsWCX.GetTitle: string; begin Result := rsOptionsEditorPlugins + ' WCX'; end; { TfrmOptionsPluginsWCX.ExtraOptionsSignature } function TfrmOptionsPluginsWCX.ExtraOptionsSignature(CurrentSignature: dword): dword; begin Result := tmpWCXPlugins.ComputeSignature(CurrentSignature); end; { TfrmOptionsPluginsWCX.ShowPluginsTable } procedure TfrmOptionsPluginsWCX.ShowPluginsTable; var I, iIndex: integer; sFileName, sExt: string; iRememberOriginalRow, iRow: integer; begin iRememberOriginalRow := stgPlugins.Row; case gWCXConfigViewMode of wcvmByPlugin: begin btnToggleOptionPlugins.Caption := rsOptPluginShowByExtension; btnToggleOptionPlugins.Glyph.Assign(ImgByExtension.Picture.Bitmap); stgPlugins.RowCount := stgPlugins.FixedRows; end; wcvmByExtension: begin btnToggleOptionPlugins.Caption := rsOptPluginShowByPlugin; btnToggleOptionPlugins.Glyph.Assign(ImgByPlugin.Picture.Bitmap); stgPlugins.RowCount := succ(tmpWCXPlugins.Count); end; end; for I := 0 to pred(tmpWCXPlugins.Count) do begin // get associated extension sExt := tmpWCXPlugins.Ext[I]; //get file name sFileName := tmpWCXPlugins.FileName[I]; case gWCXConfigViewMode of wcvmByPlugin: begin iIndex := stgPlugins.Cols[COLNO_FILENAME].IndexOf(sFileName); if iIndex < 0 then begin stgPlugins.RowCount := stgPlugins.RowCount + 1; iRow := pred(stgPlugins.RowCount); stgPlugins.Cells[COLNO_ACTIVE, iRow] := IfThen(tmpWCXPlugins.Enabled[I], '+', '-'); stgPlugins.Cells[COLNO_NAME, iRow] := ExtractOnlyFileName(sFileName); stgPlugins.Cells[COLNO_EXT, iRow] := sExt + #32; stgPlugins.Cells[COLNO_FILENAME, iRow] := sFileName; end else begin stgPlugins.Cells[COLNO_EXT, iIndex] := stgPlugins.Cells[COLNO_EXT, iIndex] + sExt + #32; stgPlugins.Cells[COLNO_ACTIVE, iIndex] := stgPlugins.Cells[COLNO_ACTIVE, iIndex] + IfThen(tmpWCXPlugins.Enabled[I], '+', '-'); end; end; wcvmByExtension: begin stgPlugins.Cells[COLNO_ACTIVE, succ(I)] := IfThen(tmpWCXPlugins.Enabled[I], '+', '-'); stgPlugins.Cells[COLNO_NAME, succ(I)] := ExtractOnlyFileName(sFileName); stgPlugins.Cells[COLNO_EXT, succ(I)] := sExt; stgPlugins.Cells[COLNO_FILENAME, succ(I)] := sFileName; end; end; end; if iRememberOriginalRow <> -1 then stgPlugins.Row := iRememberOriginalRow; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsWCX.stgPluginsOnSelection } procedure TfrmOptionsPluginsWCX.stgPluginsOnSelection(Sender: TObject; aCol, aRow: integer); var bEnable: boolean = False; bEnabled: boolean; begin if (aRow > 0) and (aRow < stgPlugins.RowCount) then begin bEnabled := (stgPlugins.Cells[COLNO_ACTIVE, aRow][1] = '-'); btnEnablePlugin.Caption := IfThen(bEnabled, rsOptPluginEnable, rsOptPluginDisable); if bEnabled then btnEnablePlugin.Glyph.Assign(ImgSwitchDisable.Picture.Bitmap) else btnEnablePlugin.Glyph.Assign(ImgSwitchEnable.Picture.Bitmap); bEnable := True; end; btnEnablePlugin.Enabled := bEnable; btnRemovePlugin.Enabled := bEnable; btnTweakPlugin.Enabled := bEnable; btnConfigPlugin.Enabled := bEnable; end; { TfrmOptionsPluginsWCX.stgPluginsWCXDragDrop } procedure TfrmOptionsPluginsWCX.stgPluginsWCXDragDrop(Sender, Source: TObject; X, Y: integer); var iDestCol, iDestRow, iSourceRow: integer; begin case gWCXConfigViewMode of wcvmByPlugin: begin MsgError(rsOptPluginSortOnlyWhenByExtension); end; wcvmByExtension: begin stgPlugins.MouseToCell(X, Y, {%H-}iDestCol, {%H-}iDestRow); if iDestRow > 0 then begin iSourceRow := stgPlugins.Row; //We need to that because after having done the following "MoveColRow", the "stgPlugins.Row" changed! So we need to remember original index. stgPlugins.MoveColRow(False, iSourceRow, iDestRow); tmpWCXPlugins.Move(pred(iSourceRow), pred(iDestRow)); end; end; end; end; { TfrmOptionsPluginsWCX.btnToggleViewClick } procedure TfrmOptionsPluginsWCX.btnToggleViewClick(Sender: TObject); begin case gWCXConfigViewMode of wcvmByPlugin: gWCXConfigViewMode := wcvmByExtension; wcvmByExtension: gWCXConfigViewMode := wcvmByPlugin; end; ShowPluginsTable; end; { TfrmOptionsPluginsWCX.btnAddPluginClick } procedure TfrmOptionsPluginsWCX.btnAddPluginClick(Sender: TObject); begin dmComData.OpenDialog.Filter := Format('Archive plugins (%s)|%s', [WcxMask, WcxMask]); if dmComData.OpenDialog.Execute then ActualAddPlugin(dmComData.OpenDialog.FileName); end; { v.ActualAddPlugin } procedure TfrmOptionsPluginsWCX.ActualAddPlugin(sPluginFilename: string); var J, iPluginIndex, iFlags, iNbItemOnStart: integer; sExt: string; sExts: string; sExtsTemp: string; sPluginName: string; sAlreadyAssignedExts: string; WCXmodule: TWCXmodule; begin iNbItemOnStart := tmpWCXPlugins.Count; if not CheckPlugin(sPluginFilename) then Exit; sPluginFilename := GetPluginFilenameToSave(sPluginFilename); WCXmodule := gWCXPlugins.LoadModule(sPluginFilename); if not Assigned(WCXmodule) then begin MessageDlg(Application.Title, rsMsgInvalidPlugin, mtError, [mbOK], 0, mbOK); Exit; end; iFlags := WCXmodule.GetPluginCapabilities; sPluginName := sPluginFilename; sExts := ''; if InputQuery(rsOptEnterExt, Format(rsOptAssocPluginWith, [sPluginFilename]), sExts) then begin sExtsTemp := sExts; sExts := ''; sAlreadyAssignedExts := ''; sExt := Copy2SpaceDel(sExtsTemp); repeat iPluginIndex := tmpWCXPlugins.Find(sPluginName, sExt); if iPluginIndex <> -1 then begin AddStrWithSep(sAlreadyAssignedExts, sExt); end else begin tmpWCXPlugins.AddObject(sExt + '=' + IntToStr(iFlags) + ',' + sPluginName, TObject(True)); AddStrWithSep(sExts, sExt); end; sExt := Copy2SpaceDel(sExtsTemp); until sExt = ''; if sAlreadyAssignedExts <> '' then MessageDlg(Format(rsOptPluginAlreadyAssigned, [sPluginFilename]) + LineEnding + sAlreadyAssignedExts, mtWarning, [mbOK], 0); if iNbItemOnStart <> tmpWCXPlugins.Count then begin stgPlugins.RowCount := stgPlugins.RowCount + 1; // Add new row J := pred(stgPlugins.RowCount); stgPlugins.Cells[COLNO_ACTIVE, J] := '+'; // Enabled stgPlugins.Cells[COLNO_NAME, J] := ExtractOnlyFileName(sPluginFilename); stgPlugins.Cells[COLNO_EXT, J] := sExts; stgPlugins.Cells[COLNO_FILENAME, J] := sPluginName; stgPlugins.Row := J; //This will trig automatically the "OnSelection" event. if gPluginInAutoTweak then btnTweakPlugin.Click; end; end; end; { TfrmOptionsPluginsWCX.btnEnablePluginClick } procedure TfrmOptionsPluginsWCX.btnEnablePluginClick(Sender: TObject); var sExt, sExts, sFinalSigns: string; iPluginIndex: integer; bEnabled: boolean; begin if stgPlugins.Row < stgPlugins.FixedRows then Exit; case gWCXConfigViewMode of wcvmByExtension: begin tmpWCXPlugins.Enabled[pred(stgPlugins.Row)] := not tmpWCXPlugins.Enabled[pred(stgPlugins.Row)]; stgPlugins.Cells[COLNO_ACTIVE, stgPlugins.Row] := IfThen(tmpWCXPlugins.Enabled[pred(stgPlugins.Row)], '+', '-'); end; wcvmByPlugin: begin bEnabled := (stgPlugins.Cells[COLNO_ACTIVE, stgPlugins.Row][1] = '-'); sExts := stgPlugins.Cells[COLNO_EXT, stgPlugins.Row]; sExt := Copy2SpaceDel(sExts); sFinalSigns := ''; repeat iPluginIndex := tmpWCXPlugins.Find(stgPlugins.Cells[COLNO_FILENAME, stgPlugins.Row], sExt); if iPluginIndex <> -1 then tmpWCXPlugins.Enabled[iPluginIndex] := bEnabled; sExt := Copy2SpaceDel(sExts); sFinalSigns := sFinalSigns + IfThen(bEnabled, '+', '-'); until sExt = ''; stgPlugins.Cells[COLNO_ACTIVE, stgPlugins.Row] := sFinalSigns; end; end; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsWCX } procedure TfrmOptionsPluginsWCX.btnRemovePluginClick(Sender: TObject); var sExt, sExts: string; iPluginIndex: integer; begin if stgPlugins.Row < stgPlugins.FixedRows then Exit; case gWCXConfigViewMode of wcvmByPlugin: begin sExts := stgPlugins.Cells[COLNO_EXT, stgPlugins.Row]; sExt := Copy2SpaceDel(sExts); repeat iPluginIndex := tmpWCXPlugins.Find(stgPlugins.Cells[COLNO_FILENAME, stgPlugins.Row], sExt); if iPluginIndex <> -1 then tmpWCXPlugins.Delete(iPluginIndex); sExt := Copy2SpaceDel(sExts); until sExt = ''; end; wcvmByExtension: begin tmpWCXPlugins.Delete(pred(stgPlugins.Row)); end; end; ShowPluginsTable; end; { TfrmOptionsPluginsWCX.btnTweakPluginClick } procedure TfrmOptionsPluginsWCX.btnTweakPluginClick(Sender: TObject); var iPluginIndex: integer; begin iPluginIndex := tmpWCXPlugins.Find(stgPlugins.Cells[COLNO_FILENAME, stgPlugins.Row], Copy2Space(stgPlugins.Cells[COLNO_EXT, stgPlugins.Row])); if iPluginIndex < 0 then Exit; if ShowTweakPluginDlg(PluginType, iPluginIndex) then ShowPluginsTable; end; { TfrmOptionsPluginsWCX.btnConfigPluginClick } procedure TfrmOptionsPluginsWCX.btnConfigPluginClick(Sender: TObject); var WCXmodule: TWCXmodule; PluginFileName: string; begin if stgPlugins.Row < stgPlugins.FixedRows then Exit; // no plugins PluginFileName := stgPlugins.Cells[COLNO_FILENAME, stgPlugins.Row]; WCXmodule := gWCXPlugins.LoadModule(PluginFileName); if Assigned(WCXmodule) then begin WCXmodule.VFSConfigure(stgPlugins.Handle); end else begin msgError(rsMsgErrEOpen + ': ' + PluginFileName); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswdx.lfm��������������������������������������������������0000644�0001750�0000144�00000001345�14743153644�021343� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsWDX: TfrmOptionsPluginsWDX inherited stgPlugins: TStringGrid AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner end inherited pnlPlugIn: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner inherited lblPlugInDescription: TLabel Caption = 'Content plu&gins allow one to display extended file details like mp3 tags or image attributes in file lists, or use them in search and multi-rename tool' end end inherited pnlButton: TPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideBottom.Control = Owner inherited btnAddPlugin: TBitBtn OnClick = btnAddPluginClick end end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswdx.lrj��������������������������������������������������0000644�0001750�0000144�00000002705�14743153644�021355� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":75149509,"name":"tfrmoptionspluginswdx.stgplugins.columns[0].title.caption","sourcebytes":[65,99,116,105,118,101],"value":"Active"}, {"hash":91471358,"name":"tfrmoptionspluginswdx.stgplugins.columns[1].title.caption","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":56017954,"name":"tfrmoptionspluginswdx.stgplugins.columns[2].title.caption","sourcebytes":[82,101,103,105,115,116,101,114,101,100,32,102,111,114],"value":"Registered for"}, {"hash":41356085,"name":"tfrmoptionspluginswdx.stgplugins.columns[3].title.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":2805628,"name":"tfrmoptionspluginswdx.lblplugindescription.caption","sourcebytes":[67,111,110,116,101,110,116,32,112,108,117,38,103,105,110,115,32,97,108,108,111,119,32,111,110,101,32,116,111,32,100,105,115,112,108,97,121,32,101,120,116,101,110,100,101,100,32,102,105,108,101,32,100,101,116,97,105,108,115,32,108,105,107,101,32,109,112,51,32,116,97,103,115,32,111,114,32,105,109,97,103,101,32,97,116,116,114,105,98,117,116,101,115,32,105,110,32,102,105,108,101,32,108,105,115,116,115,44,32,111,114,32,117,115,101,32,116,104,101,109,32,105,110,32,115,101,97,114,99,104,32,97,110,100,32,109,117,108,116,105,45,114,101,110,97,109,101,32,116,111,111,108],"value":"Content plu&gins allow one to display extended file details like mp3 tags or image attributes in file lists, or use them in search and multi-rename tool"} ]} �����������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswdx.pas��������������������������������������������������0000644�0001750�0000144�00000016203�14743153644�021347� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Plugins WDX options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsWDX; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, ComCtrls, StdCtrls, Grids, Buttons, Controls, ExtCtrls, //DC fOptionsFrame, uWDXModule, foptionspluginsbase; type { TfrmOptionsPluginsWDX } TfrmOptionsPluginsWDX = class(TfrmOptionsPluginsBase) procedure btnAddPluginClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure Done; override; procedure stgPluginsOnSelection(Sender: TObject; {%H-}aCol, aRow: integer); override; procedure ActualAddPlugin(sPluginFilename: string); override; procedure ActualDeletePlugin(iIndex: integer); override; procedure ActualPluginsMove(iSource, iDestination: integer); override; public class function GetTitle: string; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; procedure ShowPluginsTable; override; end; var tmpWDXPlugins: TWDXModuleList; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. LCLProc, Forms, Dialogs, //DC uShowMsg, fOptions, lua, uLng, uGlobs, dmCommonData, DCStrUtils, uDefaultPlugins; const COLNO_NAME = 0; COLNO_EXT = 1; COLNO_FILENAME = 2; { TfrmOptionsPluginsWDX } { TfrmOptionsPluginsWDX.Init } procedure TfrmOptionsPluginsWDX.Init; begin PluginType := ptWDX; inherited Init; stgPlugins.Columns.Items[COLNO_NAME].Title.Caption := rsOptPluginsName; stgPlugins.Columns.Items[COLNO_NAME].Alignment := taLeftJustify; // Because from the "Base", it was centered. stgPlugins.Columns.Items[COLNO_NAME].Width := stgPlugins.Columns.Items[succ(COLNO_NAME)].Width; stgPlugins.Columns.Items[COLNO_EXT].Title.Caption := rsOptPluginsRegisteredFor; stgPlugins.Columns.Items[COLNO_EXT].Width := 183; stgPlugins.Columns.Items[COLNO_EXT].Width := stgPlugins.Columns.Items[succ(COLNO_EXT)].Width; stgPlugins.Columns.Items[COLNO_FILENAME].Title.Caption := rsOptPluginsFileName; stgPlugins.Columns.Delete(succ(COLNO_FILENAME)); btnEnablePlugin.Visible := False; //Because with WDX there is no enable/disable. btnConfigPlugin.Visible := False; tmpWDXPlugins := TWDXModuleList.Create; end; { TfrmOptionsPluginsWDX.Load } procedure TfrmOptionsPluginsWDX.Load; begin tmpWDXPlugins.Assign(gWDXPlugins); ShowPluginsTable; end; { TfrmOptionsPluginsWDX.Save } function TfrmOptionsPluginsWDX.Save: TOptionsEditorSaveFlags; begin gWDXPlugins.Assign(tmpWDXPlugins); Result := []; end; { TfrmOptionsPluginsWDX.Done } procedure TfrmOptionsPluginsWDX.Done; begin FreeAndNil(tmpWDXPlugins); end; { TfrmOptionsPluginsWDX.GetTitle } class function TfrmOptionsPluginsWDX.GetTitle: string; begin Result := rsOptionsEditorPlugins + ' WDX'; end; { TfrmOptionsPluginsWDX.ExtraOptionsSignature } function TfrmOptionsPluginsWDX.ExtraOptionsSignature(CurrentSignature: dword): dword; begin Result := tmpWDXPlugins.ComputeSignature(CurrentSignature); end; { TfrmOptionsPluginsWDX.ShowPluginsTable } procedure TfrmOptionsPluginsWDX.ShowPluginsTable; var I: integer; begin stgPlugins.RowCount := tmpWDXPlugins.Count + stgPlugins.FixedRows; for i := 0 to pred(tmpWDXPlugins.Count) do begin stgPlugins.Cells[COLNO_NAME, I + stgPlugins.FixedRows] := tmpWDXPlugins.GetWdxModule(i).Name; stgPlugins.Cells[COLNO_EXT, I + stgPlugins.FixedRows] := tmpWDXPlugins.GetWdxModule(i).DetectStr; stgPlugins.Cells[COLNO_FILENAME, I + stgPlugins.FixedRows] := tmpWDXPlugins.GetWdxModule(i).FileName; end; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsWDX.stgPluginsOnSelection } procedure TfrmOptionsPluginsWDX.stgPluginsOnSelection(Sender: TObject; aCol, aRow: integer); var bEnable: boolean = False; begin if (aRow > 0) and (aRow < stgPlugins.RowCount) then bEnable := not (tmpWDXPlugins.GetWdxModule(aRow - stgPlugins.FixedRows) is TEmbeddedWDX); btnRemovePlugin.Enabled := bEnable; btnTweakPlugin.Enabled := bEnable; btnConfigPlugin.Enabled := bEnable; end; { TfrmOptionsPluginsWDX.btnAddPluginClick } procedure TfrmOptionsPluginsWDX.btnAddPluginClick(Sender: TObject); begin dmComData.OpenDialog.Filter := Format('Content plugins (%s;*.lua)|%s;*.lua', [WdxMask, WdxMask]); if dmComData.OpenDialog.Execute then ActualAddPlugin(dmComData.OpenDialog.FileName); end; { TfrmOptionsPluginsWDX.ActualAddPlugin } procedure TfrmOptionsPluginsWDX.ActualAddPlugin(sPluginFilename: string); var I, J: integer; sPluginName: string; begin if not (StrEnds(sPluginFilename, '.lua') or CheckPlugin(sPluginFilename)) then Exit; sPluginName := ExtractOnlyFileName(sPluginFilename); I := tmpWDXPlugins.Add(sPluginName, GetPluginFilenameToSave(sPluginFilename), EmptyStr); if not tmpWDXPlugins.LoadModule(pred(tmpWDXPlugins.Count)) then begin if tmpWDXPlugins.GetWdxModule(pred(tmpWDXPlugins.Count)).ClassNameIs('TLuaWdx') and (not IsLuaLibLoaded) then begin if msgYesNo(Format(rsMsgScriptCantFindLibrary, [gLuaLib]) + #$0A + rsMsgWantToConfigureLibraryLocation) then ShowOptions('TfrmOptionsPluginsGroup'); end else MessageDlg(Application.Title, rsMsgInvalidPlugin, mtError, [mbOK], 0, mbOK); tmpWDXPlugins.DeleteItem(I); Exit; end; tmpWDXPlugins.GetWdxModule(pred(tmpWDXPlugins.Count)).DetectStr := tmpWDXPlugins.GetWdxModule(pred(tmpWDXPlugins.Count)).CallContentGetDetectString; stgPlugins.RowCount := stgPlugins.RowCount + 1; J := stgPlugins.RowCount - 1; stgPlugins.Cells[COLNO_NAME, J] := tmpWDXPlugins.GetWdxModule(I).Name; stgPlugins.Cells[COLNO_EXT, J] := tmpWDXPlugins.GetWdxModule(I).DetectStr; stgPlugins.Cells[COLNO_FILENAME, J] := tmpWDXPlugins.GetWdxModule(I).FileName; stgPlugins.Row := J; //This will trig automatically the "OnSelection" event. if gPluginInAutoTweak then btnTweakPlugin.Click; end; { TfrmOptionsPluginsWDX.ActualDeletePlugin } procedure TfrmOptionsPluginsWDX.ActualDeletePlugin(iIndex: integer); begin tmpWDXPlugins.DeleteItem(iIndex); end; { TfrmOptionsPluginsWDX.ActualPluginsMove } procedure TfrmOptionsPluginsWDX.ActualPluginsMove(iSource, iDestination: integer); begin tmpWDXPlugins.Move(iSource, iDestination); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswfx.lfm��������������������������������������������������0000644�0001750�0000144�00000001561�14743153644�021345� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsWFX: TfrmOptionsPluginsWFX inherited stgPlugins: TStringGrid AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner end inherited pnlPlugIn: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner inherited lblPlugInDescription: TLabel Caption = 'Fi&le system plugins allow access to disks inaccessible by operating system or to external devices like Palm/PocketPC.' end end inherited pnlButton: TPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideBottom.Control = Owner inherited btnAddPlugin: TBitBtn OnClick = btnAddPluginClick end inherited btnEnablePlugin: TBitBtn OnClick = btnEnablePluginClick end inherited btnConfigPlugin: TBitBtn OnClick = btnConfigPluginClick end end end �����������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswfx.lrj��������������������������������������������������0000644�0001750�0000144�00000002437�14743153644�021361� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":75149509,"name":"tfrmoptionspluginswfx.stgplugins.columns[0].title.caption","sourcebytes":[65,99,116,105,118,101],"value":"Active"}, {"hash":91471358,"name":"tfrmoptionspluginswfx.stgplugins.columns[1].title.caption","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":56017954,"name":"tfrmoptionspluginswfx.stgplugins.columns[2].title.caption","sourcebytes":[82,101,103,105,115,116,101,114,101,100,32,102,111,114],"value":"Registered for"}, {"hash":41356085,"name":"tfrmoptionspluginswfx.stgplugins.columns[3].title.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":49157102,"name":"tfrmoptionspluginswfx.lblplugindescription.caption","sourcebytes":[70,105,38,108,101,32,115,121,115,116,101,109,32,112,108,117,103,105,110,115,32,97,108,108,111,119,32,97,99,99,101,115,115,32,116,111,32,100,105,115,107,115,32,105,110,97,99,99,101,115,115,105,98,108,101,32,98,121,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,111,114,32,116,111,32,101,120,116,101,114,110,97,108,32,100,101,118,105,99,101,115,32,108,105,107,101,32,80,97,108,109,47,80,111,99,107,101,116,80,67,46],"value":"Fi&le system plugins allow access to disks inaccessible by operating system or to external devices like Palm/PocketPC."} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswfx.pas��������������������������������������������������0000644�0001750�0000144�00000017302�14743153644�021352� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Plugins WFX options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsWFX; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, ComCtrls, StdCtrls, Grids, Buttons, Controls, ExtCtrls, //DC uDCUtils, fOptionsFrame, uWFXModule, foptionspluginsbase; type { TfrmOptionsPluginsWFX } TfrmOptionsPluginsWFX = class(TfrmOptionsPluginsBase) procedure btnAddPluginClick(Sender: TObject); procedure btnEnablePluginClick(Sender: TObject); procedure btnConfigPluginClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure Done; override; procedure stgPluginsOnSelection(Sender: TObject; {%H-}aCol, aRow: integer); override; procedure ActualAddPlugin(sPluginFilename: string); override; procedure ActualDeletePlugin(iIndex: integer); override; procedure ActualPluginsMove(iSource, iDestination: integer); override; public class function GetTitle: string; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; procedure ShowPluginsTable; override; end; var tmpWFXPlugins: TWFXModuleList; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. StrUtils, LCLProc, Forms, Dialogs, //DC uLng, uGlobs, uShowMsg, dmCommonData, DCStrUtils, uDefaultPlugins; const COLNO_ACTIVE = 0; COLNO_NAME = 1; COLNO_FILENAME = 2; { TfrmOptionsPluginsWFX } { TfrmOptionsPluginsWFX.Init } procedure TfrmOptionsPluginsWFX.Init; begin PluginType := ptWFX; inherited Init; stgPlugins.Columns.Items[COLNO_FILENAME].Title.Caption := rsOptPluginsFileName; stgPlugins.Columns.Delete(succ(COLNO_FILENAME)); tmpWFXPlugins := TWFXModuleList.Create; end; { TfrmOptionsPluginsWFX.Load } procedure TfrmOptionsPluginsWFX.Load; begin tmpWFXPlugins.Assign(gWFXPlugins); ShowPluginsTable; end; { TfrmOptionsPluginsWFX.Save } function TfrmOptionsPluginsWFX.Save: TOptionsEditorSaveFlags; begin gWFXPlugins.Assign(tmpWFXPlugins); Result := []; end; { TfrmOptionsPluginsWFX.Done } procedure TfrmOptionsPluginsWFX.Done; begin FreeAndNil(tmpWFXPlugins); end; { TfrmOptionsPluginsWFX.GetTitle } class function TfrmOptionsPluginsWFX.GetTitle: string; begin Result := rsOptionsEditorPlugins + ' WFX'; end; { TfrmOptionsPluginsWFX.ExtraOptionsSignature } function TfrmOptionsPluginsWFX.ExtraOptionsSignature(CurrentSignature: dword): dword; begin Result := tmpWFXPlugins.ComputeSignature(CurrentSignature); end; { TfrmOptionsPluginsWFX.ShowPluginsTable } procedure TfrmOptionsPluginsWFX.ShowPluginsTable; var I, iRow: integer; begin stgPlugins.RowCount := tmpWFXPlugins.Count + stgPlugins.FixedRows; for I := 0 to pred(tmpWFXPlugins.Count) do begin iRow := I + stgPlugins.FixedRows; stgPlugins.Cells[COLNO_ACTIVE, iRow] := IfThen(tmpWFXPlugins.Enabled[I], '+', '-'); stgPlugins.Cells[COLNO_NAME, iRow] := tmpWFXPlugins.Name[I]; stgPlugins.Cells[COLNO_FILENAME, iRow] := tmpWFXPlugins.FileName[I]; end; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsWFX.stgPluginsOnSelection } procedure TfrmOptionsPluginsWFX.stgPluginsOnSelection(Sender: TObject; aCol, aRow: integer); var bEnable: boolean = False; bEnabled: boolean; begin if (aRow > 0) and (aRow < stgPlugins.RowCount) then begin bEnabled := (stgPlugins.Cells[COLNO_ACTIVE, aRow] = '-'); btnEnablePlugin.Caption := IfThen(bEnabled, rsOptPluginEnable, rsOptPluginDisable); if bEnabled then btnEnablePlugin.Glyph.Assign(ImgSwitchDisable.Picture.Bitmap) else btnEnablePlugin.Glyph.Assign(ImgSwitchEnable.Picture.Bitmap); bEnable := True; end; btnEnablePlugin.Enabled := bEnable; btnRemovePlugin.Enabled := bEnable; btnTweakPlugin.Enabled := bEnable; btnConfigPlugin.Enabled := bEnable; end; { TfrmOptionsPluginsWFX.btnAddPluginClick } procedure TfrmOptionsPluginsWFX.btnAddPluginClick(Sender: TObject); begin dmComData.OpenDialog.Filter := Format('File system plugins (%s)|%s', [WfxMask, WfxMask]); if dmComData.OpenDialog.Execute then ActualAddPlugin(dmComData.OpenDialog.FileName); end; { TfrmOptionsPluginsWFX.ActualAddPlugin } procedure TfrmOptionsPluginsWFX.ActualAddPlugin(sPluginFilename: string); var I, J: integer; WfxModule: TWFXmodule; sPluginName, sRootName: string; begin if not CheckPlugin(sPluginFilename) then Exit; sPluginFilename := GetPluginFilenameToSave(sPluginFilename); WfxModule := gWFXPlugins.LoadModule(sPluginFilename); try if not Assigned(WfxModule) then begin MessageDlg(Application.Title, rsMsgInvalidPlugin, mtError, [mbOK], 0, mbOK); Exit; end; sRootName := WfxModule.VFSRootName; if Length(sRootName) = 0 then begin sRootName := ExtractOnlyFileName(sPluginFilename); end; sPluginName := sRootName + '=' + sPluginFilename; I := tmpWFXPlugins.AddObject(sPluginName, TObject(True)); stgPlugins.RowCount := tmpWFXPlugins.Count + 1; J := stgPlugins.RowCount - 1; stgPlugins.Cells[COLNO_ACTIVE, J] := '+'; stgPlugins.Cells[COLNO_NAME, J] := tmpWFXPlugins.Name[I]; stgPlugins.Cells[COLNO_FILENAME, J] := tmpWFXPlugins.FileName[I]; stgPlugins.Row := J; //This will trig automatically the "OnSelection" event. if gPluginInAutoTweak then btnTweakPlugin.Click; finally end; end; { TfrmOptionsPluginsDSX.ActualDeletePlugin } procedure TfrmOptionsPluginsWFX.ActualDeletePlugin(iIndex: integer); begin tmpWFXPlugins.Delete(iIndex); end; { TfrmOptionsPluginsWFX.ActualPluginsMove } procedure TfrmOptionsPluginsWFX.ActualPluginsMove(iSource, iDestination: integer); begin tmpWFXPlugins.Move(iSource, iDestination); end; { TfrmOptionsPluginsWFX.btnEnablePluginClick } procedure TfrmOptionsPluginsWFX.btnEnablePluginClick(Sender: TObject); var bEnabled: boolean; begin if stgPlugins.Row < stgPlugins.FixedRows then Exit; bEnabled := not tmpWFXPlugins.Enabled[stgPlugins.Row - stgPlugins.FixedRows]; stgPlugins.Cells[COLNO_ACTIVE, stgPlugins.Row] := IfThen(bEnabled, '+', '-'); tmpWFXPlugins.Enabled[stgPlugins.Row - stgPlugins.FixedRows] := bEnabled; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsWFX.btnConfigPluginClick } procedure TfrmOptionsPluginsWFX.btnConfigPluginClick(Sender: TObject); var WFXmodule: TWFXmodule; PluginFileName: string; begin if stgPlugins.Row < stgPlugins.FixedRows then Exit; // no plugins PluginFileName := stgPlugins.Cells[COLNO_FILENAME, stgPlugins.Row]; WFXmodule := gWFXPlugins.LoadModule(PluginFileName); if Assigned(WFXmodule) then begin WfxModule.VFSInit; WFXmodule.VFSConfigure(stgPlugins.Handle); end else begin msgError(rsMsgErrEOpen + ': ' + PluginFileName); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswlx.lfm��������������������������������������������������0000644�0001750�0000144�00000001426�14743153644�021353� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsPluginsWLX: TfrmOptionsPluginsWLX inherited stgPlugins: TStringGrid AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner end inherited pnlPlugIn: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner inherited lblPlugInDescription: TLabel Caption = 'Vie&wer plugins allow one to display file formats like images, spreadsheets, databases etc. in Viewer (F3, Ctrl+Q)' end end inherited pnlButton: TPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideBottom.Control = Owner inherited btnAddPlugin: TBitBtn OnClick = btnAddPluginClick end inherited btnEnablePlugin: TBitBtn OnClick = btnEnablePluginClick end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswlx.lrj��������������������������������������������������0000644�0001750�0000144�00000002412�14743153644�021360� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":75149509,"name":"tfrmoptionspluginswlx.stgplugins.columns[0].title.caption","sourcebytes":[65,99,116,105,118,101],"value":"Active"}, {"hash":91471358,"name":"tfrmoptionspluginswlx.stgplugins.columns[1].title.caption","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":56017954,"name":"tfrmoptionspluginswlx.stgplugins.columns[2].title.caption","sourcebytes":[82,101,103,105,115,116,101,114,101,100,32,102,111,114],"value":"Registered for"}, {"hash":41356085,"name":"tfrmoptionspluginswlx.stgplugins.columns[3].title.caption","sourcebytes":[70,105,108,101,32,110,97,109,101],"value":"File name"}, {"hash":128139241,"name":"tfrmoptionspluginswlx.lblplugindescription.caption","sourcebytes":[86,105,101,38,119,101,114,32,112,108,117,103,105,110,115,32,97,108,108,111,119,32,111,110,101,32,116,111,32,100,105,115,112,108,97,121,32,102,105,108,101,32,102,111,114,109,97,116,115,32,108,105,107,101,32,105,109,97,103,101,115,44,32,115,112,114,101,97,100,115,104,101,101,116,115,44,32,100,97,116,97,98,97,115,101,115,32,101,116,99,46,32,105,110,32,86,105,101,119,101,114,32,40,70,51,44,32,67,116,114,108,43,81,41],"value":"Vie&wer plugins allow one to display file formats like images, spreadsheets, databases etc. in Viewer (F3, Ctrl+Q)"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionspluginswlx.pas��������������������������������������������������0000644�0001750�0000144�00000016367�14743153644�021372� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Plugins WLX options page Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsPluginsWLX; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, ComCtrls, StdCtrls, Grids, Buttons, Controls, ExtCtrls, //DC fOptionsFrame, uWLXModule, foptionspluginsbase; type { TfrmOptionsPluginsWLX } TfrmOptionsPluginsWLX = class(TfrmOptionsPluginsBase) procedure btnAddPluginClick(Sender: TObject); procedure btnEnablePluginClick(Sender: TObject); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure Done; override; procedure stgPluginsOnSelection(Sender: TObject; {%H-}aCol, aRow: integer); override; procedure ActualAddPlugin(sPluginFilename: string); override; procedure ActualDeletePlugin(iIndex: integer); override; procedure ActualPluginsMove(iSource, iDestination: integer); override; public class function GetTitle: string; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; procedure ShowPluginsTable; override; end; var tmpWLXPlugins: TWLXModuleList; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. StrUtils, LCLProc, Forms, Dialogs, DynLibs, //DC uLng, uGlobs, dmCommonData, DCStrUtils, DCConvertEncoding, uDefaultPlugins; const COLNO_ACTIVE = 0; COLNO_NAME = 1; COLNO_EXT = 2; COLNO_FILENAME = 3; { TfrmOptionsPluginsWLX } { TfrmOptionsPluginsWLX.Init } procedure TfrmOptionsPluginsWLX.Init; begin PluginType := ptWLX; inherited Init; btnConfigPlugin.Visible := False; tmpWLXPlugins := TWLXModuleList.Create; end; { TfrmOptionsPluginsWLX.Load } procedure TfrmOptionsPluginsWLX.Load; begin tmpWLXPlugins.Assign(gWLXPlugins); ShowPluginsTable; end; { TfrmOptionsPluginsWLX.Save } function TfrmOptionsPluginsWLX.Save: TOptionsEditorSaveFlags; begin gWLXPlugins.Assign(tmpWLXPlugins); Result := []; end; { TfrmOptionsPluginsWLX.Done } procedure TfrmOptionsPluginsWLX.Done; begin FreeAndNil(tmpWLXPlugins); end; { TfrmOptionsPluginsWLX.GetTitle } class function TfrmOptionsPluginsWLX.GetTitle: string; begin Result := rsOptionsEditorPlugins + ' WLX'; end; { TfrmOptionsPluginsWLX.ExtraOptionsSignature } function TfrmOptionsPluginsWLX.ExtraOptionsSignature(CurrentSignature: dword): dword; begin Result := tmpWLXPlugins.ComputeSignature(CurrentSignature); end; { TfrmOptionsPluginsWLX.ShowPluginsTable } procedure TfrmOptionsPluginsWLX.ShowPluginsTable; var I: integer; begin stgPlugins.RowCount := tmpWLXPlugins.Count + stgPlugins.FixedRows; for i := 0 to pred(tmpWLXPlugins.Count) do begin stgPlugins.Cells[COLNO_ACTIVE, I + stgPlugins.FixedRows] := IfThen(tmpWLXPlugins.GetWlxModule(i).Enabled, '+', '-'); stgPlugins.Cells[COLNO_NAME, I + stgPlugins.FixedRows] := tmpWLXPlugins.GetWlxModule(i).Name; stgPlugins.Cells[COLNO_EXT, I + stgPlugins.FixedRows] := tmpWLXPlugins.GetWlxModule(i).DetectStr; stgPlugins.Cells[COLNO_FILENAME, I + stgPlugins.FixedRows] := tmpWLXPlugins.GetWlxModule(i).FileName; end; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; { TfrmOptionsPluginsWLX.stgPluginsOnSelection } procedure TfrmOptionsPluginsWLX.stgPluginsOnSelection(Sender: TObject; aCol, aRow: integer); var bEnable: boolean = False; bEnabled: boolean; begin if (aRow > 0) and (aRow < stgPlugins.RowCount) then begin bEnabled := (stgPlugins.Cells[COLNO_ACTIVE, aRow] = '-'); btnEnablePlugin.Caption := IfThen(bEnabled, rsOptPluginEnable, rsOptPluginDisable); if bEnabled then btnEnablePlugin.Glyph.Assign(ImgSwitchDisable.Picture.Bitmap) else btnEnablePlugin.Glyph.Assign(ImgSwitchEnable.Picture.Bitmap); bEnable := True; end; btnEnablePlugin.Enabled := bEnable; btnRemovePlugin.Enabled := bEnable; btnTweakPlugin.Enabled := bEnable; btnConfigPlugin.Enabled := bEnable; end; { TfrmOptionsPluginsWFX.btnAddPluginClick } procedure TfrmOptionsPluginsWLX.btnAddPluginClick(Sender: TObject); begin dmComData.OpenDialog.Filter := Format('Viewer plugins (%s)|%s', [WlxMask, WlxMask]); if dmComData.OpenDialog.Execute then ActualAddPlugin(dmComData.OpenDialog.FileName); end; { TfrmOptionsPluginsWLX.ActualAddPlugin } procedure TfrmOptionsPluginsWLX.ActualAddPlugin(sPluginFilename: string); const cNextLine = LineEnding + LineEnding; var I, J: integer; sPluginName: string; begin if not CheckPlugin(sPluginFilename) then Exit; sPluginName := ExtractOnlyFileName(sPluginFilename); I := tmpWLXPlugins.Add(sPluginName, GetPluginFilenameToSave(sPluginFilename), EmptyStr); if not tmpWLXPlugins.LoadModule(pred(tmpWLXPlugins.Count)) then begin MessageDlg(Application.Title, rsMsgInvalidPlugin + cNextLine + CeSysToUtf8(GetLoadErrorStr), mtError, [mbOK], 0, mbOK); tmpWLXPlugins.DeleteItem(I); Exit; end; tmpWLXPlugins.GetWlxModule(pred(tmpWLXPlugins.Count)).DetectStr := tmpWLXPlugins.GetWlxModule(pred(tmpWLXPlugins.Count)).CallListGetDetectString; stgPlugins.RowCount := stgPlugins.RowCount + 1; J := pred(stgPlugins.RowCount); stgPlugins.Cells[COLNO_ACTIVE, J] := '+'; stgPlugins.Cells[COLNO_NAME, J] := tmpWLXPlugins.GetWlxModule(I).Name; stgPlugins.Cells[COLNO_EXT, J] := tmpWLXPlugins.GetWlxModule(I).DetectStr; stgPlugins.Cells[COLNO_FILENAME, J] := tmpWLXPlugins.GetWlxModule(I).FileName; stgPlugins.Row := J; //This will trig automatically the "OnSelection" event. if gPluginInAutoTweak then btnTweakPlugin.click; end; { TfrmOptionsPluginsWLX.ActualDeletePlugin } procedure TfrmOptionsPluginsWLX.ActualDeletePlugin(iIndex: integer); begin tmpWLXPlugins.DeleteItem(iIndex); end; { TfrmOptionsPluginsWLX.ActualPluginsMove } procedure TfrmOptionsPluginsWLX.ActualPluginsMove(iSource, iDestination: integer); begin tmpWLXPlugins.Move(iSource, iDestination); end; { TfrmOptionsPluginsWLX.btnEnablePluginClick } procedure TfrmOptionsPluginsWLX.btnEnablePluginClick(Sender: TObject); begin if stgPlugins.Row < stgPlugins.FixedRows then Exit; with tmpWLXPlugins.GetWlxModule(stgPlugins.Row - stgPlugins.FixedRows) do begin Enabled := not Enabled; stgPlugins.Cells[COLNO_ACTIVE, stgPlugins.Row] := IfThen(Enabled, '+', '-'); btnEnablePlugin.Caption := IfThen(Enabled, rsOptPluginDisable, rsOptPluginEnable); end; stgPluginsOnSelection(stgPlugins, 0, stgPlugins.Row); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsquicksearchfilter.lfm�������������������������������������������0000644�0001750�0000144�00000010651�14743153644�022647� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsQuickSearchFilter: TfrmOptionsQuickSearchFilter Height = 354 Width = 702 HelpKeyword = '/configuration.html#ConfigQuick' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 354 ClientWidth = 702 DesignLeft = 418 DesignTop = 232 object gbExactNameMatch: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 68 Top = 6 Width = 690 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Exact name match' ChildSizing.TopBottomSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 50 ClientWidth = 686 TabOrder = 0 object cbExactBeginning: TCheckBox AnchorSideLeft.Control = gbExactNameMatch AnchorSideTop.Control = gbExactNameMatch Left = 10 Height = 19 Top = 6 Width = 305 BorderSpacing.Left = 10 BorderSpacing.Top = 6 Caption = '&Beginning (name must start with first typed character)' TabOrder = 0 end object cbExactEnding: TCheckBox AnchorSideLeft.Control = cbExactBeginning AnchorSideTop.Control = cbExactBeginning AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = gbExactNameMatch AnchorSideBottom.Side = asrBottom Left = 10 Height = 15 Top = 29 Width = 311 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Bottom = 6 Caption = 'En&ding (last character before a typed dot . must match)' TabOrder = 1 end end object rgpSearchItems: TRadioGroup[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbExactNameMatch AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 87 Top = 74 Width = 690 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'Search for these items' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 69 ClientWidth = 686 Items.Strings = ( 'Files' 'Directories' 'Files and Directories' ) TabOrder = 1 end object rgpSearchCase: TRadioGroup[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = rgpSearchItems AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 68 Top = 161 Width = 690 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'Search case' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 50 ClientWidth = 686 Items.Strings = ( 'Sensitive' 'Insensitive' ) TabOrder = 2 end object cgpOptions: TCheckGroup[3] AnchorSideLeft.Control = Owner AnchorSideTop.Control = rgpSearchCase AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 68 Top = 229 Width = 690 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True Caption = 'Options' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 50 ClientWidth = 686 Items.Strings = ( 'Hide filter panel when not focused' 'Keep saving setting modifications for next session' ) TabOrder = 3 Data = { 020000000202 } end end ���������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsquicksearchfilter.lrj�������������������������������������������0000644�0001750�0000144�00000002657�14743153644�022667� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":219152600,"name":"tfrmoptionsquicksearchfilter.gbexactnamematch.caption","sourcebytes":[69,120,97,99,116,32,110,97,109,101,32,109,97,116,99,104],"value":"Exact name match"}, {"hash":216088953,"name":"tfrmoptionsquicksearchfilter.cbexactbeginning.caption","sourcebytes":[38,66,101,103,105,110,110,105,110,103,32,40,110,97,109,101,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,102,105,114,115,116,32,116,121,112,101,100,32,99,104,97,114,97,99,116,101,114,41],"value":"&Beginning (name must start with first typed character)"}, {"hash":126009481,"name":"tfrmoptionsquicksearchfilter.cbexactending.caption","sourcebytes":[69,110,38,100,105,110,103,32,40,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,98,101,102,111,114,101,32,97,32,116,121,112,101,100,32,100,111,116,32,46,32,109,117,115,116,32,109,97,116,99,104,41],"value":"En&ding (last character before a typed dot . must match)"}, {"hash":194363443,"name":"tfrmoptionsquicksearchfilter.rgpsearchitems.caption","sourcebytes":[83,101,97,114,99,104,32,102,111,114,32,116,104,101,115,101,32,105,116,101,109,115],"value":"Search for these items"}, {"hash":167714837,"name":"tfrmoptionsquicksearchfilter.rgpsearchcase.caption","sourcebytes":[83,101,97,114,99,104,32,99,97,115,101],"value":"Search case"}, {"hash":108725763,"name":"tfrmoptionsquicksearchfilter.cgpoptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"} ]} ���������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsquicksearchfilter.pas�������������������������������������������0000644�0001750�0000144�00000006607�14743153644�022662� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Quick search/filter options page Copyright (C) 2006-2011 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsQuickSearchFilter; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, ExtCtrls, fOptionsFrame; type { TfrmOptionsQuickSearchFilter } TfrmOptionsQuickSearchFilter = class(TOptionsEditor) cbExactBeginning: TCheckBox; cbExactEnding: TCheckBox; cgpOptions: TCheckGroup; gbExactNameMatch: TGroupBox; rgpSearchCase: TRadioGroup; rgpSearchItems: TRadioGroup; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng, fQuickSearch; const OPTION_AUTOHIDE_POSITION = 0; OPTION_SAVE_SESSION_MODIFICATIONS = 1; { TfrmOptionsQuickSearchFilter } class function TfrmOptionsQuickSearchFilter.GetIconIndex: Integer; begin Result := 12; end; class function TfrmOptionsQuickSearchFilter.GetTitle: String; begin Result := rsOptionsEditorQuickSearch; end; procedure TfrmOptionsQuickSearchFilter.Init; begin // Copy localized strings to each combo box. ParseLineToList(rsOptSearchItems, rgpSearchItems.Items); ParseLineToList(rsOptSearchCase, rgpSearchCase.Items); ParseLineToList(rsOptSearchOpt, cgpOptions.Items); end; procedure TfrmOptionsQuickSearchFilter.Load; begin cbExactBeginning.Checked := qsmBeginning in gQuickSearchOptions.Match; cbExactEnding.Checked := qsmEnding in gQuickSearchOptions.Match; rgpSearchItems.ItemIndex := Integer(gQuickSearchOptions.Items); rgpSearchCase.ItemIndex := Integer(gQuickSearchOptions.SearchCase); cgpOptions.Checked[OPTION_AUTOHIDE_POSITION] := gQuickFilterAutoHide; cgpOptions.Checked[OPTION_SAVE_SESSION_MODIFICATIONS] := gQuickFilterSaveSessionModifications; end; function TfrmOptionsQuickSearchFilter.Save: TOptionsEditorSaveFlags; begin Result := []; if cbExactBeginning.Checked then Include(gQuickSearchOptions.Match, qsmBeginning) else Exclude(gQuickSearchOptions.Match, qsmBeginning); if cbExactEnding.Checked then Include(gQuickSearchOptions.Match, qsmEnding) else Exclude(gQuickSearchOptions.Match, qsmEnding); gQuickSearchOptions.Items := TQuickSearchItems(rgpSearchItems.ItemIndex); gQuickSearchOptions.SearchCase := TQuickSearchCase(rgpSearchCase.ItemIndex); gQuickFilterAutoHide := cgpOptions.Checked[OPTION_AUTOHIDE_POSITION]; gQuickFilterSaveSessionModifications := cgpOptions.Checked[OPTION_SAVE_SESSION_MODIFICATIONS]; end; end. �������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstabs.lfm��������������������������������������������������������0000644�0001750�0000144�00000020357�14743153644�020074� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsTabs: TfrmOptionsTabs Height = 492 Width = 731 HelpKeyword = '/configuration.html#ConfigTabs' ClientHeight = 492 ClientWidth = 731 DesignLeft = 147 DesignTop = 342 object gbTabs: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 434 Top = 6 Width = 719 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 6 Caption = 'Folder tabs headers' ChildSizing.TopBottomSpacing = 6 ClientHeight = 414 ClientWidth = 715 TabOrder = 0 object lblChar: TLabel AnchorSideLeft.Control = edtTabsLimitLength AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtTabsLimitLength AnchorSideTop.Side = asrCenter Left = 239 Height = 15 Top = 58 Width = 54 BorderSpacing.Left = 6 Caption = 'characters' ParentColor = False end object lblTabsPosition: TLabel AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cmbTabsPosition AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 360 Width = 71 BorderSpacing.Top = 14 Caption = 'Ta&bs position' FocusControl = cmbTabsPosition ParentColor = False end object cbTabsAlwaysVisible: TCheckBox AnchorSideLeft.Control = gbTabs AnchorSideTop.Control = gbTabs Left = 12 Height = 19 Top = 6 Width = 274 BorderSpacing.Left = 12 BorderSpacing.Top = 6 Caption = '&Show tab header also when there is only one tab' TabOrder = 0 end object cbTabsMultiLines: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsAlwaysVisible AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 31 Width = 136 BorderSpacing.Top = 6 Caption = '&Tabs on multiple lines' TabOrder = 1 end object cbTabsLimitOption: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsMultiLines AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 56 Width = 141 BorderSpacing.Top = 6 Caption = '&Limit tab title length to' TabOrder = 2 end object edtTabsLimitLength: TEdit AnchorSideLeft.Control = cbTabsLimitOption AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTabsLimitOption AnchorSideTop.Side = asrCenter Left = 153 Height = 23 Top = 54 Width = 80 TabOrder = 3 end object cbTabsOpenForeground: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsCloseDuplicateWhenClosing AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 156 Width = 218 BorderSpacing.Top = 6 Caption = 'Ctrl+&Up opens new tab in foreground' TabOrder = 7 end object cbTabsConfirmCloseAll: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsConfirmCloseLocked AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 106 Width = 134 BorderSpacing.Top = 6 Caption = 'Con&firm close all tabs' TabOrder = 5 end object cbTabsLockedAsterisk: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsShowCloseButton AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 256 Width = 204 BorderSpacing.Top = 6 Caption = 'Show locked tabs &with an asterisk *' TabOrder = 11 end object cbTabsActivateOnClick: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbKeepRenamedNameBackToNormal AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 306 Width = 302 BorderSpacing.Top = 6 Caption = 'Activate target &panel when clicking on one of its Tabs' TabOrder = 13 end object cbTabsShowCloseButton: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsReuseTabWhenPossible AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 231 Width = 138 BorderSpacing.Top = 6 Caption = 'Show ta&b close button' TabOrder = 10 end object cmbTabsPosition: TComboBox AnchorSideLeft.Control = lblTabsPosition AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTabsShowDriveLetter AnchorSideTop.Side = asrBottom Left = 89 Height = 23 Top = 356 Width = 100 BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 ItemHeight = 15 Items.Strings = ( 'Top' 'Bottom' ) Style = csDropDownList TabOrder = 15 end object cbTabsOpenNearCurrent: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsOpenForeground AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 181 Width = 186 BorderSpacing.Top = 6 Caption = 'Open &new tabs near current tab' TabOrder = 8 end object cbTabsCloseDuplicateWhenClosing: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsConfirmCloseAll AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 131 Width = 261 BorderSpacing.Top = 6 Caption = 'Close duplicate tabs when closing application' TabOrder = 6 end object cbTabsShowDriveLetter: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsActivateOnClick AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 331 Width = 203 BorderSpacing.Top = 6 Caption = 'Always show drive letter in tab title' TabOrder = 14 Visible = False end object cbTabsReuseTabWhenPossible: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsOpenNearCurrent AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 206 Width = 192 BorderSpacing.Top = 6 Caption = 'Reuse existing tab when possible' TabOrder = 9 end object cbTabsConfirmCloseLocked: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsLimitOption AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 81 Width = 157 BorderSpacing.Top = 6 Caption = 'Confirm close locked tabs' TabOrder = 4 end object cbKeepRenamedNameBackToNormal: TCheckBox AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsLockedAsterisk AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 281 Width = 246 BorderSpacing.Top = 6 Caption = 'Keep renamed name when unlocking a tab' TabOrder = 12 end object lblTabsActionOnDoubleClick: TLabel AnchorSideLeft.Control = cbTabsAlwaysVisible AnchorSideTop.Control = cbTabsActionOnDoubleClick AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 389 Width = 214 Caption = 'Action to do when double click on a tab:' ParentColor = False end object cbTabsActionOnDoubleClick: TComboBox AnchorSideLeft.Control = lblTabsActionOnDoubleClick AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cmbTabsPosition AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbTabs AnchorSideRight.Side = asrBottom Left = 232 Height = 23 Top = 385 Width = 477 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 6 ItemHeight = 15 Items.Strings = ( 'Do nothing' 'Close tab' 'Access Favorite Tabs' 'Tabs popup menu' ) Style = csDropDownList TabOrder = 16 end end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstabs.lrj��������������������������������������������������������0000644�0001750�0000144�00000010561�14743153644�020101� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":74618355,"name":"tfrmoptionstabs.gbtabs.caption","sourcebytes":[70,111,108,100,101,114,32,116,97,98,115,32,104,101,97,100,101,114,115],"value":"Folder tabs headers"}, {"hash":142357011,"name":"tfrmoptionstabs.lblchar.caption","sourcebytes":[99,104,97,114,97,99,116,101,114,115],"value":"characters"}, {"hash":90832526,"name":"tfrmoptionstabs.lbltabsposition.caption","sourcebytes":[84,97,38,98,115,32,112,111,115,105,116,105,111,110],"value":"Ta&bs position"}, {"hash":192530514,"name":"tfrmoptionstabs.cbtabsalwaysvisible.caption","sourcebytes":[38,83,104,111,119,32,116,97,98,32,104,101,97,100,101,114,32,97,108,115,111,32,119,104,101,110,32,116,104,101,114,101,32,105,115,32,111,110,108,121,32,111,110,101,32,116,97,98],"value":"&Show tab header also when there is only one tab"}, {"hash":135553331,"name":"tfrmoptionstabs.cbtabsmultilines.caption","sourcebytes":[38,84,97,98,115,32,111,110,32,109,117,108,116,105,112,108,101,32,108,105,110,101,115],"value":"&Tabs on multiple lines"}, {"hash":12421679,"name":"tfrmoptionstabs.cbtabslimitoption.caption","sourcebytes":[38,76,105,109,105,116,32,116,97,98,32,116,105,116,108,101,32,108,101,110,103,116,104,32,116,111],"value":"&Limit tab title length to"}, {"hash":262751956,"name":"tfrmoptionstabs.cbtabsopenforeground.caption","sourcebytes":[67,116,114,108,43,38,85,112,32,111,112,101,110,115,32,110,101,119,32,116,97,98,32,105,110,32,102,111,114,101,103,114,111,117,110,100],"value":"Ctrl+&Up opens new tab in foreground"}, {"hash":46942083,"name":"tfrmoptionstabs.cbtabsconfirmcloseall.caption","sourcebytes":[67,111,110,38,102,105,114,109,32,99,108,111,115,101,32,97,108,108,32,116,97,98,115],"value":"Con&firm close all tabs"}, {"hash":173431514,"name":"tfrmoptionstabs.cbtabslockedasterisk.caption","sourcebytes":[83,104,111,119,32,108,111,99,107,101,100,32,116,97,98,115,32,38,119,105,116,104,32,97,110,32,97,115,116,101,114,105,115,107,32,42],"value":"Show locked tabs &with an asterisk *"}, {"hash":204561027,"name":"tfrmoptionstabs.cbtabsactivateonclick.caption","sourcebytes":[65,99,116,105,118,97,116,101,32,116,97,114,103,101,116,32,38,112,97,110,101,108,32,119,104,101,110,32,99,108,105,99,107,105,110,103,32,111,110,32,111,110,101,32,111,102,32,105,116,115,32,84,97,98,115],"value":"Activate target &panel when clicking on one of its Tabs"}, {"hash":157446414,"name":"tfrmoptionstabs.cbtabsshowclosebutton.caption","sourcebytes":[83,104,111,119,32,116,97,38,98,32,99,108,111,115,101,32,98,117,116,116,111,110],"value":"Show ta&b close button"}, {"hash":97026210,"name":"tfrmoptionstabs.cbtabsopennearcurrent.caption","sourcebytes":[79,112,101,110,32,38,110,101,119,32,116,97,98,115,32,110,101,97,114,32,99,117,114,114,101,110,116,32,116,97,98],"value":"Open &new tabs near current tab"}, {"hash":263911774,"name":"tfrmoptionstabs.cbtabscloseduplicatewhenclosing.caption","sourcebytes":[67,108,111,115,101,32,100,117,112,108,105,99,97,116,101,32,116,97,98,115,32,119,104,101,110,32,99,108,111,115,105,110,103,32,97,112,112,108,105,99,97,116,105,111,110],"value":"Close duplicate tabs when closing application"}, {"hash":73851701,"name":"tfrmoptionstabs.cbtabsshowdriveletter.caption","sourcebytes":[65,108,119,97,121,115,32,115,104,111,119,32,100,114,105,118,101,32,108,101,116,116,101,114,32,105,110,32,116,97,98,32,116,105,116,108,101],"value":"Always show drive letter in tab title"}, {"hash":33183493,"name":"tfrmoptionstabs.cbtabsreusetabwhenpossible.caption","sourcebytes":[82,101,117,115,101,32,101,120,105,115,116,105,110,103,32,116,97,98,32,119,104,101,110,32,112,111,115,115,105,98,108,101],"value":"Reuse existing tab when possible"}, {"hash":152684499,"name":"tfrmoptionstabs.cbtabsconfirmcloselocked.caption","sourcebytes":[67,111,110,102,105,114,109,32,99,108,111,115,101,32,108,111,99,107,101,100,32,116,97,98,115],"value":"Confirm close locked tabs"}, {"hash":29336242,"name":"tfrmoptionstabs.cbkeeprenamednamebacktonormal.caption","sourcebytes":[75,101,101,112,32,114,101,110,97,109,101,100,32,110,97,109,101,32,119,104,101,110,32,117,110,108,111,99,107,105,110,103,32,97,32,116,97,98],"value":"Keep renamed name when unlocking a tab"}, {"hash":241063306,"name":"tfrmoptionstabs.lbltabsactionondoubleclick.caption","sourcebytes":[65,99,116,105,111,110,32,116,111,32,100,111,32,119,104,101,110,32,100,111,117,98,108,101,32,99,108,105,99,107,32,111,110,32,97,32,116,97,98,58],"value":"Action to do when double click on a tab:"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstabs.pas��������������������������������������������������������0000644�0001750�0000144�00000015310�14743153644�020072� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Tabs options page Copyright (C) 2006-2016 Koblov Alexander (Alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsTabs; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, ComCtrls, ExtCtrls, fOptionsFrame; type { TfrmOptionsTabs } TfrmOptionsTabs = class(TOptionsEditor) cbTabsActivateOnClick: TCheckBox; cbTabsAlwaysVisible: TCheckBox; cbTabsConfirmCloseAll: TCheckBox; cbTabsLimitOption: TCheckBox; cbTabsLockedAsterisk: TCheckBox; cbTabsMultiLines: TCheckBox; cbTabsOpenForeground: TCheckBox; cbTabsOpenNearCurrent: TCheckBox; cbTabsShowCloseButton: TCheckBox; cmbTabsPosition: TComboBox; cbTabsActionOnDoubleClick: TComboBox; edtTabsLimitLength: TEdit; gbTabs: TGroupBox; lblTabsActionOnDoubleClick: TLabel; lblChar: TLabel; lblTabsPosition: TLabel; cbKeepRenamedNameBackToNormal: TCheckBox; cbTabsConfirmCloseLocked: TCheckBox; cbTabsReuseTabWhenPossible: TCheckBox; cbTabsShowDriveLetter: TCheckBox; cbTabsCloseDuplicateWhenClosing: TCheckBox; private FPageControl: TPageControl; // For checking Tabs capabilities protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses Forms, DCStrUtils, uLng, uGlobs; { TfrmOptionsTabs } procedure TfrmOptionsTabs.Init; begin ParseLineToList(rsOptTabsPosition, cmbTabsPosition.Items); ParseLineToList(rsTabsActionOnDoubleClickChoices, cbTabsActionOnDoubleClick.Items); FPageControl := TPageControl.Create(Self); end; class function TfrmOptionsTabs.GetIconIndex: integer; begin Result := 9; end; class function TfrmOptionsTabs.GetTitle: string; begin Result := rsOptionsEditorFolderTabs; end; procedure TfrmOptionsTabs.Load; begin {$IFDEF MSWINDOWS} cbTabsShowDriveLetter.Visible := True; {$ENDIF} cbTabsAlwaysVisible.Checked := (tb_always_visible in gDirTabOptions) and gDirectoryTabs; cbTabsLimitOption.Checked := tb_text_length_limit in gDirTabOptions; cbTabsConfirmCloseAll.Checked := tb_confirm_close_all in gDirTabOptions; cbTabsConfirmCloseLocked.Checked := tb_confirm_close_locked_tab in gDirTabOptions; cbTabsCloseDuplicateWhenClosing.Checked := tb_close_duplicate_when_closing in gDirTabOptions; cbTabsOpenForeground.Checked := tb_open_new_in_foreground in gDirTabOptions; cbTabsOpenNearCurrent.Checked := tb_open_new_near_current in gDirTabOptions; cbTabsReuseTabWhenPossible.Checked := tb_reusing_tab_when_possible in gDirTabOptions; cbTabsLockedAsterisk.Checked := tb_show_asterisk_for_locked in gDirTabOptions; cbKeepRenamedNameBackToNormal.Checked := tb_keep_renamed_when_back_normal in gDirTabOptions; cbTabsActivateOnClick.Checked := tb_activate_panel_on_click in gDirTabOptions; cbTabsShowDriveLetter.Checked := tb_show_drive_letter in gDirTabOptions; cbTabsActionOnDoubleClick.ItemIndex := integer(gDirTabActionOnDoubleClick); if cbTabsActionOnDoubleClick.ItemIndex = -1 then cbTabsActionOnDoubleClick.ItemIndex := 1; // Because with r6597 to r6599 we saved incorrect value for "gDirTabActionOnDoubleClick"... cbTabsActionOnDoubleClick.Refresh; cbTabsMultiLines.Visible := (nbcMultiline in FPageControl.GetCapabilities); if cbTabsMultiLines.Visible then cbTabsMultiLines.Checked := tb_multiple_lines in gDirTabOptions; cbTabsShowCloseButton.Visible := (nbcShowCloseButtons in FPageControl.GetCapabilities); if cbTabsShowCloseButton.Visible then cbTabsShowCloseButton.Checked := tb_show_close_button in gDirTabOptions; edtTabsLimitLength.Text := IntToStr(gDirTabLimit); case gDirTabPosition of tbpos_top: cmbTabsPosition.ItemIndex := 0; tbpos_bottom: cmbTabsPosition.ItemIndex := 1; else cmbTabsPosition.ItemIndex := 0; end; Application.ProcessMessages; end; function TfrmOptionsTabs.Save: TOptionsEditorSaveFlags; begin Result := []; gDirTabOptions := []; // Reset tab options if cbTabsAlwaysVisible.Checked then gDirTabOptions := gDirTabOptions + [tb_always_visible]; if cbTabsMultiLines.Checked then gDirTabOptions := gDirTabOptions + [tb_multiple_lines]; if cbTabsLimitOption.Checked then gDirTabOptions := gDirTabOptions + [tb_text_length_limit]; if cbTabsConfirmCloseAll.Checked then gDirTabOptions := gDirTabOptions + [tb_confirm_close_all]; if cbTabsConfirmCloseLocked.Checked then gDirTabOptions := gDirTabOptions + [tb_confirm_close_locked_tab]; if cbTabsCloseDuplicateWhenClosing.Checked then gDirTabOptions := gDirTabOptions + [tb_close_duplicate_when_closing]; if cbTabsOpenForeground.Checked then gDirTabOptions := gDirTabOptions + [tb_open_new_in_foreground]; if cbTabsOpenNearCurrent.Checked then gDirTabOptions := gDirTabOptions + [tb_open_new_near_current]; if cbTabsReuseTabWhenPossible.Checked then gDirTabOptions := gDirTabOptions + [tb_reusing_tab_when_possible]; if cbTabsLockedAsterisk.Checked then gDirTabOptions := gDirTabOptions + [tb_show_asterisk_for_locked]; if cbKeepRenamedNameBackToNormal.Checked then gDirTabOptions := gDirTabOptions + [tb_keep_renamed_when_back_normal]; if cbTabsActivateOnClick.Checked then gDirTabOptions := gDirTabOptions + [tb_activate_panel_on_click]; if cbTabsShowDriveLetter.Checked then gDirTabOptions := gDirTabOptions + [tb_show_drive_letter]; if cbTabsShowCloseButton.Checked then gDirTabOptions := gDirTabOptions + [tb_show_close_button]; gDirTabActionOnDoubleClick := TTabsOptionsDoubleClick(cbTabsActionOnDoubleClick.ItemIndex); gDirTabLimit := StrToIntDef(edtTabsLimitLength.Text, 32); case cmbTabsPosition.ItemIndex of 0: gDirTabPosition := tbpos_top; 1: gDirTabPosition := tbpos_bottom; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstabsextra.lfm���������������������������������������������������0000644�0001750�0000144�00000020164�14743153644�021134� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsTabsExtra: TfrmOptionsTabsExtra Height = 418 Width = 720 HelpKeyword = '/configuration.html#ConfigTabsEx' AutoSize = True ClientHeight = 418 ClientWidth = 720 DesignLeft = 140 DesignTop = 288 object gbTabs: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 474 Top = 6 Width = 708 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 6 Caption = 'Folder tabs headers extra' ChildSizing.TopBottomSpacing = 6 ClientHeight = 444 ClientWidth = 704 TabOrder = 0 object cbUseFavoriteTabsExtraOptions: TCheckBox AnchorSideLeft.Control = gbTabs AnchorSideTop.Control = gbTabs Left = 12 Height = 29 Top = 6 Width = 592 BorderSpacing.Left = 12 BorderSpacing.Top = 6 Caption = 'Enable Favorite Tabs extra options (select target side when restore, etc.)' OnChange = cbUseFavoriteTabsExtraOptionsChange TabOrder = 0 end object gbDefaultTabSavedRestoration: TGroupBox AnchorSideLeft.Control = cbUseFavoriteTabsExtraOptions AnchorSideTop.Control = cbUseFavoriteTabsExtraOptions AnchorSideTop.Side = asrBottom Left = 12 Height = 153 Top = 45 Width = 450 AutoSize = True BorderSpacing.Top = 10 Caption = 'Default extra settings when saving new Favorite Tabs:' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 123 ClientWidth = 446 TabOrder = 1 object cbDefaultTargetPanelLeftSaved: TComboBox AnchorSideTop.Control = gbDefaultTabSavedRestoration AnchorSideRight.Control = gbDefaultTabSavedRestoration AnchorSideRight.Side = asrBottom Left = 340 Height = 33 Top = 6 Width = 100 Anchors = [akTop, akRight] ItemHeight = 25 ItemIndex = 0 Items.Strings = ( 'Left' 'Right' 'Active' 'Inactive' 'Both' 'None' ) Style = csDropDownList TabOrder = 0 Text = 'Left' end object lblDefaultTargetPanelLeftSaved: TLabel AnchorSideTop.Control = cbDefaultTargetPanelLeftSaved AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbDefaultTargetPanelLeftSaved Left = 42 Height = 25 Top = 10 Width = 294 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Tabs saved on left will be restored to:' ParentColor = False end object cbDefaultTargetPanelRightSaved: TComboBox AnchorSideTop.Control = cbDefaultTargetPanelLeftSaved AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbDefaultTargetPanelLeftSaved AnchorSideRight.Side = asrBottom Left = 340 Height = 33 Top = 45 Width = 100 Anchors = [akTop, akRight] BorderSpacing.Top = 6 ItemHeight = 25 ItemIndex = 1 Items.Strings = ( 'Left' 'Right' 'Active' 'Inactive' 'Both' 'None' ) Style = csDropDownList TabOrder = 1 Text = 'Right' end object lblDefaultTargetPanelRightSaved: TLabel AnchorSideTop.Control = cbDefaultTargetPanelRightSaved AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbDefaultTargetPanelRightSaved Left = 30 Height = 25 Top = 49 Width = 306 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Tabs saved on right will be restored to:' ParentColor = False end object cbDefaultExistingTabsToKeep: TComboBox AnchorSideTop.Control = cbDefaultTargetPanelRightSaved AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbDefaultTargetPanelRightSaved AnchorSideRight.Side = asrBottom Left = 340 Height = 33 Top = 84 Width = 100 Anchors = [akTop, akRight] BorderSpacing.Top = 6 ItemHeight = 25 ItemIndex = 5 Items.Strings = ( 'Left' 'Right' 'Active' 'Inactive' 'Both' 'None' ) Style = csDropDownList TabOrder = 2 Text = 'None' end object lblDefaultExistingTabsToKeep: TLabel AnchorSideTop.Control = cbDefaultExistingTabsToKeep AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbDefaultExistingTabsToKeep Left = 6 Height = 25 Top = 88 Width = 330 Anchors = [akTop, akRight] BorderSpacing.Top = 6 BorderSpacing.Right = 4 Caption = 'When restoring tab, existing tabs to keep:' ParentColor = False end end object cbGoToConfigAfterSave: TCheckBox AnchorSideLeft.Control = cbUseFavoriteTabsExtraOptions AnchorSideTop.Control = rgWhereToAdd AnchorSideTop.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 12 Height = 29 Top = 380 Width = 499 BorderSpacing.Top = 10 Caption = 'Goto to Favorite Tabs Configuration after saving a new one' TabOrder = 4 end object cbGoToConfigAfterReSave: TCheckBox AnchorSideLeft.Control = gbDefaultTabSavedRestoration AnchorSideTop.Control = cbGoToConfigAfterSave AnchorSideTop.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 12 Height = 29 Top = 409 Width = 428 Caption = 'Goto to Favorite Tabs Configuration after resaving' TabOrder = 5 end object rgWhereToAdd: TRadioGroup AnchorSideLeft.Control = cbUseFavoriteTabsExtraOptions AnchorSideTop.Control = cbDefaultSaveDirHistory AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbDefaultTabSavedRestoration AnchorSideRight.Side = asrBottom Left = 12 Height = 129 Top = 241 Width = 450 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Top = 4 Caption = 'Default position in menu when saving a new Favorite Tabs:' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 99 ClientWidth = 446 Constraints.MinWidth = 200 Items.Strings = ( 'Add at beginning' 'Add at the end' 'Alphabetical order' ) TabOrder = 3 end object cbDefaultSaveDirHistory: TComboBox AnchorSideLeft.Control = lblFavoriteTabsSaveDirHistory AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbDefaultTabSavedRestoration AnchorSideTop.Side = asrBottom Left = 345 Height = 33 Top = 204 Width = 100 BorderSpacing.Top = 6 ItemHeight = 25 ItemIndex = 0 Items.Strings = ( 'No' 'Yes' ) Style = csDropDownList TabOrder = 2 Text = 'No' end object lblFavoriteTabsSaveDirHistory: TLabel AnchorSideLeft.Control = cbUseFavoriteTabsExtraOptions AnchorSideTop.Control = cbDefaultSaveDirHistory AnchorSideTop.Side = asrCenter Left = 12 Height = 25 Top = 208 Width = 329 BorderSpacing.Top = 6 BorderSpacing.Right = 4 Caption = 'Keep saving dir history with Favorite Tabs:' ParentColor = False end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstabsextra.lrj���������������������������������������������������0000644�0001750�0000144�00000007454�14743153644�021154� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":18771569,"name":"tfrmoptionstabsextra.gbtabs.caption","sourcebytes":[70,111,108,100,101,114,32,116,97,98,115,32,104,101,97,100,101,114,115,32,101,120,116,114,97],"value":"Folder tabs headers extra"}, {"hash":148591481,"name":"tfrmoptionstabsextra.cbusefavoritetabsextraoptions.caption","sourcebytes":[69,110,97,98,108,101,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,101,120,116,114,97,32,111,112,116,105,111,110,115,32,40,115,101,108,101,99,116,32,116,97,114,103,101,116,32,115,105,100,101,32,119,104,101,110,32,114,101,115,116,111,114,101,44,32,101,116,99,46,41],"value":"Enable Favorite Tabs extra options (select target side when restore, etc.)"}, {"hash":180600330,"name":"tfrmoptionstabsextra.gbdefaulttabsavedrestoration.caption","sourcebytes":[68,101,102,97,117,108,116,32,101,120,116,114,97,32,115,101,116,116,105,110,103,115,32,119,104,101,110,32,115,97,118,105,110,103,32,110,101,119,32,70,97,118,111,114,105,116,101,32,84,97,98,115,58],"value":"Default extra settings when saving new Favorite Tabs:"}, {"hash":338900,"name":"tfrmoptionstabsextra.cbdefaulttargetpanelleftsaved.text","sourcebytes":[76,101,102,116],"value":"Left"}, {"hash":261845882,"name":"tfrmoptionstabsextra.lbldefaulttargetpanelleftsaved.caption","sourcebytes":[84,97,98,115,32,115,97,118,101,100,32,111,110,32,108,101,102,116,32,119,105,108,108,32,98,101,32,114,101,115,116,111,114,101,100,32,116,111,58],"value":"Tabs saved on left will be restored to:"}, {"hash":5832180,"name":"tfrmoptionstabsextra.cbdefaulttargetpanelrightsaved.text","sourcebytes":[82,105,103,104,116],"value":"Right"}, {"hash":199356746,"name":"tfrmoptionstabsextra.lbldefaulttargetpanelrightsaved.caption","sourcebytes":[84,97,98,115,32,115,97,118,101,100,32,111,110,32,114,105,103,104,116,32,119,105,108,108,32,98,101,32,114,101,115,116,111,114,101,100,32,116,111,58],"value":"Tabs saved on right will be restored to:"}, {"hash":349765,"name":"tfrmoptionstabsextra.cbdefaultexistingtabstokeep.text","sourcebytes":[78,111,110,101],"value":"None"}, {"hash":102588762,"name":"tfrmoptionstabsextra.lbldefaultexistingtabstokeep.caption","sourcebytes":[87,104,101,110,32,114,101,115,116,111,114,105,110,103,32,116,97,98,44,32,101,120,105,115,116,105,110,103,32,116,97,98,115,32,116,111,32,107,101,101,112,58],"value":"When restoring tab, existing tabs to keep:"}, {"hash":102690789,"name":"tfrmoptionstabsextra.cbgotoconfigaftersave.caption","sourcebytes":[71,111,116,111,32,116,111,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,67,111,110,102,105,103,117,114,97,116,105,111,110,32,97,102,116,101,114,32,115,97,118,105,110,103,32,97,32,110,101,119,32,111,110,101],"value":"Goto to Favorite Tabs Configuration after saving a new one"}, {"hash":212226695,"name":"tfrmoptionstabsextra.cbgotoconfigafterresave.caption","sourcebytes":[71,111,116,111,32,116,111,32,70,97,118,111,114,105,116,101,32,84,97,98,115,32,67,111,110,102,105,103,117,114,97,116,105,111,110,32,97,102,116,101,114,32,114,101,115,97,118,105,110,103],"value":"Goto to Favorite Tabs Configuration after resaving"}, {"hash":115430234,"name":"tfrmoptionstabsextra.rgwheretoadd.caption","sourcebytes":[68,101,102,97,117,108,116,32,112,111,115,105,116,105,111,110,32,105,110,32,109,101,110,117,32,119,104,101,110,32,115,97,118,105,110,103,32,97,32,110,101,119,32,70,97,118,111,114,105,116,101,32,84,97,98,115,58],"value":"Default position in menu when saving a new Favorite Tabs:"}, {"hash":1359,"name":"tfrmoptionstabsextra.cbdefaultsavedirhistory.text","sourcebytes":[78,111],"value":"No"}, {"hash":190887898,"name":"tfrmoptionstabsextra.lblfavoritetabssavedirhistory.caption","sourcebytes":[75,101,101,112,32,115,97,118,105,110,103,32,100,105,114,32,104,105,115,116,111,114,121,32,119,105,116,104,32,70,97,118,111,114,105,116,101,32,84,97,98,115,58],"value":"Keep saving dir history with Favorite Tabs:"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstabsextra.pas���������������������������������������������������0000644�0001750�0000144�00000012720�14743153644�021140� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Tabs "Extra" options page Copyright (C) 2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsTabsExtra; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, ComCtrls, ExtCtrls, fOptionsFrame; type { TfrmOptionsTabsExtra } TfrmOptionsTabsExtra = class(TOptionsEditor) cbDefaultExistingTabsToKeep: TComboBox; cbDefaultSaveDirHistory: TComboBox; cbDefaultTargetPanelLeftSaved: TComboBox; cbDefaultTargetPanelRightSaved: TComboBox; cbGoToConfigAfterReSave: TCheckBox; cbGoToConfigAfterSave: TCheckBox; cbUseFavoriteTabsExtraOptions: TCheckBox; gbTabs: TGroupBox; gbDefaultTabSavedRestoration: TGroupBox; lblDefaultExistingTabsToKeep: TLabel; lblFavoriteTabsSaveDirHistory: TLabel; lblDefaultTargetPanelLeftSaved: TLabel; lblDefaultTargetPanelRightSaved: TLabel; rgWhereToAdd: TRadioGroup; procedure cbUseFavoriteTabsExtraOptionsChange(Sender: TObject); private FPageControl: TPageControl; // For checking Tabs capabilities protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Forms, //DC fOptions, DCStrUtils, uLng, uGlobs, ufavoritetabs, fOptionsFavoriteTabs; { TfrmOptionsTabsExtra } procedure TfrmOptionsTabsExtra.cbUseFavoriteTabsExtraOptionsChange(Sender: TObject); var Options: IOptionsDialog = nil; Editor: TOptionsEditor = nil; begin gFavoriteTabsUseRestoreExtraOptions := TCheckBox(Sender).Checked; gbDefaultTabSavedRestoration.Enabled := TCheckBox(Sender).Checked; if not TCheckBox(Sender).Checked then lblFavoriteTabsSaveDirHistory.Caption := rsMsgFavoriteTabsSimpleMode else lblFavoriteTabsSaveDirHistory.Caption := rsMsgFavoriteTabsExtraMode; // Le't be dynamic and update possible already displayed Favorite Tabs Configuration frame. Options := GetOptionsForm; if Options <> nil then // and it will be since we're here! :-) Editor := Options.GetEditor(TfrmOptionsFavoriteTabs); if Editor <> nil then TfrmOptionsFavoriteTabs(Editor).gpSavedTabsRestorationAction.Visible := gFavoriteTabsUseRestoreExtraOptions; end; { TfrmOptionsTabsExtra.Init } procedure TfrmOptionsTabsExtra.Init; begin FPageControl := TPageControl.Create(Self); ParseLineToList(rsOptFavoriteTabsWhereToAddInList, rgWhereToAdd.Items); ParseLineToList(rsFavTabsPanelSideSelection,cbDefaultTargetPanelLeftSaved.Items); ParseLineToList(rsFavTabsPanelSideSelection,cbDefaultTargetPanelRightSaved.Items); ParseLineToList(rsFavTabsPanelSideSelection,cbDefaultExistingTabsToKeep.Items); ParseLineToList(rsFavTabsSaveDirHistory,cbDefaultSaveDirHistory.Items); end; class function TfrmOptionsTabsExtra.GetIconIndex: integer; begin Result := 38; end; class function TfrmOptionsTabsExtra.GetTitle: string; begin Result := rsOptionsEditorFolderTabsExtra; end; procedure TfrmOptionsTabsExtra.Load; begin cbUseFavoriteTabsExtraOptions.Checked := gFavoriteTabsUseRestoreExtraOptions; cbUseFavoriteTabsExtraOptionsChange(cbUseFavoriteTabsExtraOptions); cbDefaultTargetPanelLeftSaved.ItemIndex := integer(gDefaultTargetPanelLeftSaved); cbDefaultTargetPanelRightSaved.ItemIndex := integer(gDefaultTargetPanelRightSaved); cbDefaultExistingTabsToKeep.ItemIndex := integer(gDefaultExistingTabsToKeep); if gFavoriteTabsSaveDirHistory then cbDefaultSaveDirHistory.ItemIndex := 1 else cbDefaultSaveDirHistory.ItemIndex := 0; rgWhereToAdd.ItemIndex := integer(gWhereToAddNewFavoriteTabs); cbGoToConfigAfterSave.Checked := gFavoriteTabsGoToConfigAfterSave; cbGoToConfigAfterReSave.Checked := gFavoriteTabsGoToConfigAfterReSave; Application.ProcessMessages; end; function TfrmOptionsTabsExtra.Save: TOptionsEditorSaveFlags; begin Result := []; gFavoriteTabsUseRestoreExtraOptions := cbUseFavoriteTabsExtraOptions.Checked; gDefaultTargetPanelLeftSaved := TTabsConfigLocation(cbDefaultTargetPanelLeftSaved.ItemIndex); gDefaultTargetPanelRightSaved := TTabsConfigLocation(cbDefaultTargetPanelRightSaved.ItemIndex); gDefaultExistingTabsToKeep := TTabsConfigLocation(cbDefaultExistingTabsToKeep.ItemIndex); gFavoriteTabsSaveDirHistory := (cbDefaultSaveDirHistory.ItemIndex = 1); gWhereToAddNewFavoriteTabs := TPositionWhereToAddFavoriteTabs(rgWhereToAdd.ItemIndex); gFavoriteTabsGoToConfigAfterSave := cbGoToConfigAfterSave.Checked; gFavoriteTabsGoToConfigAfterReSave := cbGoToConfigAfterReSave.Checked; end; end. ������������������������������������������������doublecmd-1.1.22/src/frames/foptionsterminal.lfm����������������������������������������������������0000644�0001750�0000144�00000015007�14743153644�020752� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsTerminal: TfrmOptionsTerminal Height = 324 Width = 519 HelpKeyword = '/configuration.html#ConfigToolsTerminal' AutoSize = True ClientHeight = 324 ClientWidth = 519 ParentShowHint = False ShowHint = True object gbRunInTerminalStayOpen: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 82 Top = 6 Width = 507 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Command for running a command in terminal and stay open:' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 62 ClientWidth = 503 TabOrder = 0 object lbRunInTermStayOpenCmd: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 8 Width = 62 Alignment = taRightJustify Caption = 'Command:' ParentColor = False end object edRunInTermStayOpenCmd: TEdit AnchorSideLeft.Control = lbRunInTermStayOpenCmd AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbRunInTermStayOpenCmd AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbRunInTerminalStayOpen AnchorSideRight.Side = asrBottom Left = 78 Height = 23 Top = 4 Width = 413 Anchors = [akTop, akLeft, akRight] TabOrder = 0 end object lbRunInTermStayOpenParams: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 35 Width = 62 Alignment = taRightJustify Caption = 'Parameters:' ParentColor = False end object edRunInTermStayOpenParams: TEdit AnchorSideLeft.Control = lbRunInTermStayOpenParams AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbRunInTermStayOpenParams AnchorSideTop.Side = asrCenter AnchorSideRight.Control = edRunInTermStayOpenCmd AnchorSideRight.Side = asrBottom Left = 78 Height = 23 Hint = '{command} should normally be present here to reflect the command to be run in terminal' Top = 31 Width = 413 Anchors = [akTop, akLeft, akRight] TabOrder = 1 end end object gbRunInTerminalClose: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbRunInTerminalStayOpen AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 82 Top = 94 Width = 507 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Command for running a command in terminal and close after:' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 62 ClientWidth = 503 TabOrder = 1 object edRunInTermCloseParams: TEdit AnchorSideLeft.Control = lbRunInTermCloseParams AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbRunInTermCloseParams AnchorSideTop.Side = asrCenter AnchorSideRight.Control = edRunInTermCloseCmd AnchorSideRight.Side = asrBottom Left = 78 Height = 23 Hint = '{command} should normally be present here to reflect the command to be run in terminal' Top = 31 Width = 413 Anchors = [akTop, akLeft, akRight] TabOrder = 1 end object edRunInTermCloseCmd: TEdit AnchorSideLeft.Control = lbRunInTermCloseCmd AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbRunInTermCloseCmd AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbRunInTerminalClose AnchorSideRight.Side = asrBottom Left = 78 Height = 23 Top = 4 Width = 413 Anchors = [akTop, akLeft, akRight] TabOrder = 0 end object lbRunInTermCloseCmd: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 8 Width = 62 Alignment = taRightJustify Caption = 'Command:' ParentColor = False end object lbRunInTermCloseParams: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 35 Width = 62 Alignment = taRightJustify Caption = 'Parameters:' ParentColor = False end end object gbJustRunTerminal: TGroupBox[2] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbRunInTerminalClose AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 82 Top = 182 Width = 507 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Command for just running terminal:' ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 62 ClientWidth = 503 TabOrder = 2 object lbRunTermCmd: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 8 Width = 62 Alignment = taRightJustify Caption = 'Command:' ParentColor = False end object edRunTermCmd: TEdit AnchorSideLeft.Control = lbRunTermCmd AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbRunTermCmd AnchorSideTop.Side = asrCenter AnchorSideRight.Control = gbJustRunTerminal AnchorSideRight.Side = asrBottom Left = 78 Height = 23 Top = 4 Width = 413 Anchors = [akTop, akLeft, akRight] TabOrder = 0 end object lbRunTermParams: TLabel AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 35 Width = 62 Alignment = taRightJustify Caption = 'Parameters:' ParentColor = False end object edRunTermParams: TEdit AnchorSideLeft.Control = lbRunTermParams AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lbRunTermParams AnchorSideTop.Side = asrCenter AnchorSideRight.Control = edRunTermCmd AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 78 Height = 23 Top = 31 Width = 413 Anchors = [akTop, akLeft, akRight] TabOrder = 1 end end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsterminal.lrj����������������������������������������������������0000644�0001750�0000144�00000005617�14743153644�020771� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":144666826,"name":"tfrmoptionsterminal.gbruninterminalstayopen.caption","sourcebytes":[67,111,109,109,97,110,100,32,102,111,114,32,114,117,110,110,105,110,103,32,97,32,99,111,109,109,97,110,100,32,105,110,32,116,101,114,109,105,110,97,108,32,97,110,100,32,115,116,97,121,32,111,112,101,110,58],"value":"Command for running a command in terminal and stay open:"}, {"hash":105087194,"name":"tfrmoptionsterminal.lbrunintermstayopencmd.caption","sourcebytes":[67,111,109,109,97,110,100,58],"value":"Command:"}, {"hash":60572138,"name":"tfrmoptionsterminal.lbrunintermstayopenparams.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115,58],"value":"Parameters:"}, {"hash":31240492,"name":"tfrmoptionsterminal.edrunintermstayopenparams.hint","sourcebytes":[123,99,111,109,109,97,110,100,125,32,115,104,111,117,108,100,32,110,111,114,109,97,108,108,121,32,98,101,32,112,114,101,115,101,110,116,32,104,101,114,101,32,116,111,32,114,101,102,108,101,99,116,32,116,104,101,32,99,111,109,109,97,110,100,32,116,111,32,98,101,32,114,117,110,32,105,110,32,116,101,114,109,105,110,97,108],"value":"{command} should normally be present here to reflect the command to be run in terminal"}, {"hash":238065354,"name":"tfrmoptionsterminal.gbruninterminalclose.caption","sourcebytes":[67,111,109,109,97,110,100,32,102,111,114,32,114,117,110,110,105,110,103,32,97,32,99,111,109,109,97,110,100,32,105,110,32,116,101,114,109,105,110,97,108,32,97,110,100,32,99,108,111,115,101,32,97,102,116,101,114,58],"value":"Command for running a command in terminal and close after:"}, {"hash":31240492,"name":"tfrmoptionsterminal.edrunintermcloseparams.hint","sourcebytes":[123,99,111,109,109,97,110,100,125,32,115,104,111,117,108,100,32,110,111,114,109,97,108,108,121,32,98,101,32,112,114,101,115,101,110,116,32,104,101,114,101,32,116,111,32,114,101,102,108,101,99,116,32,116,104,101,32,99,111,109,109,97,110,100,32,116,111,32,98,101,32,114,117,110,32,105,110,32,116,101,114,109,105,110,97,108],"value":"{command} should normally be present here to reflect the command to be run in terminal"}, {"hash":105087194,"name":"tfrmoptionsterminal.lbrunintermclosecmd.caption","sourcebytes":[67,111,109,109,97,110,100,58],"value":"Command:"}, {"hash":60572138,"name":"tfrmoptionsterminal.lbrunintermcloseparams.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115,58],"value":"Parameters:"}, {"hash":113853514,"name":"tfrmoptionsterminal.gbjustrunterminal.caption","sourcebytes":[67,111,109,109,97,110,100,32,102,111,114,32,106,117,115,116,32,114,117,110,110,105,110,103,32,116,101,114,109,105,110,97,108,58],"value":"Command for just running terminal:"}, {"hash":105087194,"name":"tfrmoptionsterminal.lbruntermcmd.caption","sourcebytes":[67,111,109,109,97,110,100,58],"value":"Command:"}, {"hash":60572138,"name":"tfrmoptionsterminal.lbruntermparams.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115,58],"value":"Parameters:"} ]} �����������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionsterminal.pas����������������������������������������������������0000644�0001750�0000144�00000005435�14743153644�020763� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Terminal options page Copyright (C) 2006-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsTerminal; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fOptionsFrame, StdCtrls, ExtCtrls, Buttons, Menus; type { TfrmOptionsTerminal } TfrmOptionsTerminal = class(TOptionsEditor) gbRunInTerminalStayOpen: TGroupBox; lbRunInTermStayOpenCmd: TLabel; edRunInTermStayOpenCmd: TEdit; lbRunInTermStayOpenParams: TLabel; edRunInTermStayOpenParams: TEdit; gbRunInTerminalClose: TGroupBox; lbRunInTermCloseCmd: TLabel; edRunInTermCloseCmd: TEdit; lbRunInTermCloseParams: TLabel; edRunInTermCloseParams: TEdit; gbJustRunTerminal: TGroupBox; lbRunTermCmd: TLabel; edRunTermCmd: TEdit; lbRunTermParams: TLabel; edRunTermParams: TEdit; protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng; { TfrmOptionsTerminal } procedure TfrmOptionsTerminal.Load; begin edRunInTermStayOpenCmd.Text := gRunInTermStayOpenCmd; edRunInTermStayOpenParams.Text := gRunInTermStayOpenParams; edRunInTermCloseCmd.Text := gRunInTermCloseCmd; edRunInTermCloseParams.Text := gRunInTermCloseParams; edRunTermCmd.Text := gRunTermCmd; edRunTermParams.Text := gRunTermParams; end; function TfrmOptionsTerminal.Save: TOptionsEditorSaveFlags; begin gRunInTermStayOpenCmd := edRunInTermStayOpenCmd.Text; gRunInTermStayOpenParams := edRunInTermStayOpenParams.Text; gRunInTermCloseCmd := edRunInTermCloseCmd.Text; gRunInTermCloseParams := edRunInTermCloseParams.Text; gRunTermCmd := edRunTermCmd.Text; gRunTermParams := edRunTermParams.Text; Result := []; end; class function TfrmOptionsTerminal.GetIconIndex: Integer; begin Result := 24; end; class function TfrmOptionsTerminal.GetTitle: String; begin Result := rsOptionsEditorTerminal; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbar.lfm�����������������������������������������������������0000644�0001750�0000144�00000000150�14743153644�020572� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsToolbar: TfrmOptionsToolbar HelpKeyword = '/configuration.html#ConfigToolbar' end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbar.pas�����������������������������������������������������0000644�0001750�0000144�00000006536�14743153644�020615� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Toolbar configuration options page Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsToolbar; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, fOptionsFrame, fOptionsToolbarBase; type { TfrmOptionsToolbar } TfrmOptionsToolbar = class(TfrmOptionsToolbarBase) protected procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public constructor Create(TheOwner: TComponent); override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses KASToolBar, DCXmlConfig, uGlobs, uGlobsPaths, uSpecialDir, uLng; { TfrmOptionsToolbar } class function TfrmOptionsToolbar.GetTitle: String; begin Result := rsOptionsEditorToolbar; end; procedure TfrmOptionsToolbar.Load; var ToolBarNode: TXmlNode; ToolBar: TKASToolBar; begin trbBarSize.Position := gToolBarButtonSize div 2; trbIconSize.Position := gToolBarIconSize div 2; cbFlatButtons.Checked := gToolBarFlat; cbShowCaptions.Checked := gToolBarShowCaptions; cbReportErrorWithCommands.Checked := gToolbarReportErrorWithCommands; lblBarSizeValue.Caption := IntToStr(trbBarSize.Position*2); lblIconSizeValue.Caption := IntToStr(trbIconSize.Position*2); FCurrentButton := nil; CloseToolbarsBelowCurrentButton; ToolBar := GetTopToolbar; ToolBarNode := gConfig.FindNode(gConfig.RootNode, GetNode, False); LoadToolbar(ToolBar, gConfig, ToolBarNode, tocl_FlushCurrentToolbarContent); if ToolBar.ButtonCount > 0 then PressButtonDown(ToolBar.Buttons[0]); gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper,mp_PATHHELPER,nil); FUpdateHotKey := False; end; function TfrmOptionsToolbar.Save: TOptionsEditorSaveFlags; var ToolBarNode: TXmlNode; ToolBar: TKASToolBar; begin ApplyEditControls; gToolBarFlat := cbFlatButtons.Checked; gToolBarShowCaptions := cbShowCaptions.Checked; gToolbarReportErrorWithCommands := cbReportErrorWithCommands.Checked; gToolBarButtonSize := trbBarSize.Position * 2; gToolBarIconSize := trbIconSize.Position * 2; ToolBar := GetTopToolbar; if Assigned(ToolBar) then begin ToolBarNode := gConfig.FindNode(gConfig.RootNode, GetNode, True); gConfig.ClearNode(ToolBarNode); Toolbar.SaveConfiguration(gConfig, ToolBarNode); end; if FUpdateHotKey then begin FUpdateHotKey := False; HotMan.Save(gpCfgDir + gNameSCFile); end; Result := []; end; constructor TfrmOptionsToolbar.Create(TheOwner: TComponent); begin inherited Create(TheOwner); Name := 'frmOptionsToolbar'; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarbase.lfm�������������������������������������������������0000644�0001750�0000144�00000146324�14743153644�021443� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsToolbarBase: TfrmOptionsToolbarBase Height = 573 Width = 850 ClientHeight = 573 ClientWidth = 850 OnEnter = FrameEnter DesignLeft = 440 DesignTop = 255 object gbGroupBox: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 111 Top = 0 Width = 838 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Right = 6 Caption = 'Appearance' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 4 ClientHeight = 86 ClientWidth = 834 TabOrder = 0 object lblBarSize: TLabel AnchorSideLeft.Control = gbGroupBox AnchorSideTop.Control = trbBarSize AnchorSideTop.Side = asrCenter Left = 8 Height = 20 Top = 17 Width = 54 Caption = '&Bar size:' FocusControl = trbBarSize ParentColor = False end object lblBarSizeValue: TLabel AnchorSideLeft.Control = lblBarSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = trbBarSize AnchorSideTop.Side = asrCenter Left = 64 Height = 1 Top = 27 Width = 1 BorderSpacing.Left = 2 ParentColor = False end object trbBarSize: TTrackBar AnchorSideLeft.Control = lblBarSizeValue AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbGroupBox Left = 68 Height = 46 Top = 4 Width = 150 Frequency = 4 Max = 40 Min = 10 OnChange = trbBarSizeChange Position = 18 ScalePos = trRight BorderSpacing.Around = 3 Constraints.MinWidth = 40 TabOrder = 0 end object lblIconSize: TLabel AnchorSideLeft.Control = trbBarSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = trbIconSize AnchorSideTop.Side = asrCenter Left = 233 Height = 20 Top = 17 Width = 60 BorderSpacing.Left = 15 Caption = 'Icon si&ze:' FocusControl = trbIconSize ParentColor = False end object lblIconSizeValue: TLabel AnchorSideLeft.Control = lblIconSize AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = trbIconSize AnchorSideTop.Side = asrCenter Left = 295 Height = 1 Top = 27 Width = 1 BorderSpacing.Left = 2 ParentColor = False end object trbIconSize: TTrackBar AnchorSideLeft.Control = lblIconSizeValue AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbGroupBox AnchorSideBottom.Side = asrBottom Left = 299 Height = 46 Top = 4 Width = 150 Frequency = 4 Max = 32 Min = 8 OnChange = trbIconSizeChange Position = 16 ScalePos = trRight BorderSpacing.Around = 3 Constraints.MinWidth = 40 ParentShowHint = False ShowHint = True TabOrder = 1 end object cbFlatButtons: TCheckBox AnchorSideLeft.Control = gbGroupBox AnchorSideTop.Control = trbIconSize AnchorSideTop.Side = asrBottom Left = 8 Height = 24 Top = 58 Width = 102 BorderSpacing.Top = 8 Caption = '&Flat buttons' Checked = True OnChange = cbFlatButtonsChange State = cbChecked TabOrder = 2 end object cbShowCaptions: TCheckBox AnchorSideLeft.Control = cbFlatButtons AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbFlatButtons Left = 122 Height = 24 Top = 58 Width = 120 BorderSpacing.Left = 12 Caption = 'Sho&w captions' TabOrder = 3 end object cbReportErrorWithCommands: TCheckBox AnchorSideLeft.Control = cbShowCaptions AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbFlatButtons Left = 254 Height = 24 Top = 58 Width = 220 BorderSpacing.Left = 12 Caption = 'Report errors with commands' TabOrder = 4 end end object pnlFullToolbarButtons: TPanel[1] AnchorSideLeft.Control = gbGroupBox AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbGroupBox AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlEditToolbar Left = 6 Height = 30 Top = 208 Width = 838 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Top = 2 BorderSpacing.Bottom = 2 BevelOuter = bvNone ClientHeight = 30 ClientWidth = 838 TabOrder = 1 object pnlToolbarButtons: TPanel AnchorSideLeft.Control = pnlFullToolbarButtons AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = pnlFullToolbarButtons AnchorSideBottom.Side = asrBottom Left = 181 Height = 30 Top = 0 Width = 476 AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 8 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsHomogenousChildResize ChildSizing.ShrinkVertical = crsHomogenousChildResize ChildSizing.Layout = cclTopToBottomThenLeftToRight ChildSizing.ControlsPerLine = 1 ClientHeight = 30 ClientWidth = 476 TabOrder = 0 object btnInsertButton: TButton Left = 0 Height = 30 Top = 0 Width = 141 AutoSize = True Caption = '&Insert new button' OnClick = btnInsertButtonClick TabOrder = 0 end object btnCloneButton: TButton Left = 149 Height = 30 Top = 0 Width = 112 AutoSize = True Caption = 'C&lone button' OnClick = btnCloneButtonClick TabOrder = 1 end object btnDeleteButton: TButton Left = 269 Height = 30 Top = 0 Width = 70 AutoSize = True Caption = '&Delete' OnClick = btnDeleteButtonClick TabOrder = 2 end object btnOther: TButton Left = 404 Height = 30 Top = 0 Width = 72 AutoSize = True BorderSpacing.Left = 65 Caption = 'Other...' OnClick = btnOtherClick TabOrder = 3 end end end object pnlEditToolbar: TPanel[2] AnchorSideLeft.Control = gbGroupBox AnchorSideRight.Control = gbGroupBox AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 327 Top = 240 Width = 838 Anchors = [akLeft, akRight, akBottom] AutoSize = True BorderSpacing.Bottom = 6 BevelOuter = bvNone ClientHeight = 327 ClientWidth = 838 TabOrder = 2 object rgToolItemType: TRadioGroup AnchorSideLeft.Control = pnlEditToolbar AnchorSideTop.Control = pnlEditToolbar AnchorSideBottom.Control = pnlEditToolbar AnchorSideBottom.Side = asrBottom Left = 0 Height = 327 Top = 0 Width = 96 Anchors = [akTop, akLeft, akBottom] AutoFill = True AutoSize = True Caption = 'Button type' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 TabOrder = 0 end object pnlEditControls: TPanel AnchorSideLeft.Control = rgToolItemType AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlEditToolbar AnchorSideRight.Control = pnlEditToolbar AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlEditToolbar AnchorSideBottom.Side = asrBottom Left = 102 Height = 327 Top = 0 Width = 730 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 6 BorderSpacing.Right = 6 BevelOuter = bvNone ChildSizing.TopBottomSpacing = 6 ChildSizing.VerticalSpacing = 10 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 327 ClientWidth = 730 TabOrder = 1 object lblIconFile: TLabel Left = 0 Height = 20 Top = 6 Width = 76 Alignment = taRightJustify Caption = 'Ico&n:' FocusControl = edtIconFileName ParentColor = False Visible = False end object edtIconFileName: TEdit AnchorSideLeft.Control = lblIconFile AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblIconFile AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnOpenIcon Left = 78 Height = 28 Top = 2 Width = 588 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 259 OnChange = edtIconFileNameChange TabOrder = 0 Visible = False end object btnOpenIcon: TSpeedButton AnchorSideTop.Control = edtIconFileName AnchorSideRight.Control = btnRelativeIconFileName AnchorSideBottom.Control = edtIconFileName AnchorSideBottom.Side = asrBottom Left = 666 Height = 28 Top = 2 Width = 32 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 200000000000000400006400000064000000000000000000000000000000328B D83F328BD83F328BD83F328BD83F328BD83F328BD83F328BD83F328BD83F328B D83F328BD83F328BD83F328BD83F328BD83F328BD83F000000004994D7FF328B D8FF328AD8FF328BD8FF328BD8FF328BD8FF328BD8FF328BD8FF328BD8FF328B D8FF328BD8FF328AD8FF328BD8FF4994D7FF328BD83F00000000358FD8FFDCF0 FAFF98E1F6FF95E0F6FF92DFF6FF8EDEF5FF89DCF5FF85DAF4FF80D9F4FF79D7 F3FF73D5F3FF6FD3F2FFC2EAF8FF3494DAFF328BD83F000000003A96DAFFEFFA FEFF93E5F8FF8FE4F8FF89E3F8FF82E1F7FF79DFF7FF70DEF6FF66DBF5FF5AD8 F4FF4CD4F3FF3FD1F2FFCAF2FBFF3494DAFF328BD83F000000003A9CDAFFF2FA FDFF94E6F8FF92E5F8FF90E5F8FF8BE3F8FF86E2F7FF7EE1F7FF76DEF6FF6BDC F6FF5DD9F4FF4ED5F3FFCCF2FBFF3494DAFF328BD83F0000000039A2DAFFF6FC FEFF94E5F8FF93E5F8FF93E5F8FF91E5F8FF86E2F7FF7EE1F7FF76DEF6FF6BDC F6FF5DD9F4FF4ED5F3FFCCF2FBFF3494DAFF328BD83F0000000039A7D9FFFEFF FFFFF8FDFFFFF6FDFFFFF5FCFFFFF3FCFEFF9AE4F4FF9AE6F7FF9BE6F6FF3176 B3FF2F72B1FF2D71B2FF2B72B6FF2C73B9FF1C476DFF0000000037ABD9FFE8F6 FBFF6FBCE7FF54AAE2FF4CA5E0FF91C9EBFFFDFEFDFFFDFEFDFFFFFDFCFF2F72 B1FF6FD1F6FF6ACEF8FF84BFB3FFA0AC64FF3684C7FF193D5EFF3EACDAFFF1FA FDFF94DEF5FF93DCF4FF63BCE9FF3494DAFF3494DAFF3494DAFF3494DAFF2E70 AFFF65C4EDFF5FBFF1FF9DA461FFDD8A00FF5BBCF3FF2E6FAEFF3FB3DBFFF7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFACE1F6FF1E486EFF3075B1FF3075AFFF4492 C6FF5FBAE6FF5DB5E9FF40C0D7FF20CCBFFF66BDF1FF2E72B2FF3AB4DAFFFDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFF2F74B2FF6EC1E5FF2F6EEDFF4791 E5FF5CB0DEFF5CABE1FF24C3B0FF00DF7CFF83C3F0FF2D71B1FF56BFDDFF60C3 E1FF62C4E2FF62C4E2FF62C4E2FF61C4E2FF2C72B0FFA2DAEDFF001AF4FF126C F1FF24B9EEFF3DBAE4FF22D3F3FF58A2DFFFACD4F0FF2C71B1FF000000000000 0000000000000000000000000000000000002C71AEFFA4CFE7FF87ACEEFF25B0 F5FF00C5FFFF2AD6EEFF00FFFFFFB8D5F0FF73A7D2FF1E4D77FF000000000000 000000000000000000000000000000000000000000003378B3FF84B5D8FFBCDB EFFFBDD8EDFFBDD6EEFFABCAE7FF699CCCFF27659FFF00000000000000000000 0000000000000000000000000000000000000000000000000000215583FF2A70 B0FF2A6FAFFF2A6FB0FF2B70B0FF1F4D77FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } Visible = False OnClick = btnOpenIconClick end object lblToolTip: TLabel AnchorSideTop.Side = asrCenter Left = 0 Height = 20 Top = 36 Width = 76 Alignment = taRightJustify Caption = '&Tooltip:' FocusControl = edtToolTip ParentColor = False Visible = False end object edtToolTip: TEdit AnchorSideLeft.Control = lblToolTip AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblToolTip AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnSuggestionTooltip Left = 78 Height = 28 Top = 32 Width = 562 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 259 TabOrder = 1 Visible = False end object lblInternalCommand: TLabel AnchorSideTop.Side = asrCenter Left = 0 Height = 20 Top = 66 Width = 76 Alignment = taRightJustify Caption = 'Co&mmand:' FocusControl = cbInternalCommand ParentColor = False Visible = False end object cbInternalCommand: TComboBox AnchorSideLeft.Control = lblInternalCommand AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblInternalCommand AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnOpenCmdDlg Left = 78 Height = 28 Top = 62 Width = 540 HelpType = htKeyword Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 DropDownCount = 20 ItemHeight = 20 OnSelect = cbInternalCommandSelect Style = csDropDownList TabOrder = 2 Visible = False end object lblInternalParameters: TLabel Left = 0 Height = 100 Top = 96 Width = 76 Alignment = taRightJustify Caption = '&Parameters:' Constraints.MinHeight = 100 FocusControl = edtInternalParameters ParentColor = False Visible = False end object edtInternalParameters: TMemo AnchorSideLeft.Control = lblInternalParameters AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblInternalParameters AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnInternalParametersHelper Left = 78 Height = 100 Hint = 'Enter command parameters, each in a separate line. Press F1 to see help on parameters.' Top = 96 Width = 617 HelpType = htKeyword Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 Constraints.MinWidth = 100 ParentShowHint = False ScrollBars = ssAutoBoth ShowHint = True TabOrder = 3 Visible = False WordWrap = False end object lblExternalCommand: TLabel AnchorSideTop.Side = asrBottom Left = 0 Height = 20 Top = 206 Width = 76 Alignment = taRightJustify Caption = 'Co&mmand:' FocusControl = edtExternalCommand ParentColor = False Visible = False end object edtExternalCommand: TEdit AnchorSideLeft.Control = lblExternalCommand AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblExternalCommand AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnOpenFile Left = 78 Height = 28 Top = 202 Width = 588 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 259 TabOrder = 4 Visible = False end object btnOpenFile: TButton AnchorSideTop.Control = edtExternalCommand AnchorSideRight.Control = btnRelativeExternalCommand AnchorSideBottom.Control = edtExternalCommand AnchorSideBottom.Side = asrBottom Left = 666 Height = 28 Top = 202 Width = 32 Anchors = [akTop, akRight, akBottom] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnOpenFileClick TabOrder = 5 Visible = False end object lblExternalParameters: TLabel AnchorSideTop.Side = asrCenter Left = 0 Height = 20 Top = 236 Width = 76 Alignment = taRightJustify Caption = 'Parameter&s:' FocusControl = edtExternalParameters ParentColor = False Visible = False end object edtExternalParameters: TEdit AnchorSideLeft.Control = lblExternalParameters AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblExternalParameters AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnParametersHelper Left = 78 Height = 28 Top = 232 Width = 620 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 259 TabOrder = 6 Visible = False end object lblStartPath: TLabel AnchorSideTop.Side = asrCenter Left = 0 Height = 20 Top = 266 Width = 76 Alignment = taRightJustify Caption = 'Start pat&h:' FocusControl = edtStartPath ParentColor = False Visible = False end object edtStartPath: TEdit AnchorSideLeft.Control = lblStartPath AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblStartPath AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnStartPath Left = 78 Height = 28 Top = 262 Width = 588 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 MaxLength = 259 TabOrder = 7 Visible = False end object lblHotkey: TLabel AnchorSideTop.Side = asrCenter Left = 0 Height = 20 Top = 296 Width = 76 Alignment = taRightJustify Caption = 'Hot key:' ParentColor = False Visible = False end object lblHotkeyValue: TLabel AnchorSideLeft.Control = lblHotkey AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblHotkey Left = 78 Height = 1 Top = 296 Width = 1 BorderSpacing.Left = 2 BorderSpacing.Right = 10 ParentColor = False Visible = False end object btnEditHotkey: TButton AnchorSideLeft.Control = lblHotkeyValue AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblHotkey AnchorSideTop.Side = asrCenter Left = 89 Height = 30 Top = 291 Width = 100 AutoSize = True BorderSpacing.Left = 2 Caption = 'Edit hot&key' OnClick = btnEditHotkeyClick TabOrder = 8 Visible = False end object btnRemoveHotkey: TButton AnchorSideLeft.Control = btnEditHotkey AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblHotkey AnchorSideTop.Side = asrCenter Left = 191 Height = 30 Top = 291 Width = 128 AutoSize = True BorderSpacing.Left = 2 Caption = 'Remove hotke&y' OnClick = btnRemoveHotKeyClick TabOrder = 9 Visible = False end object btnRelativeExternalCommand: TSpeedButton AnchorSideTop.Control = edtExternalCommand AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtExternalCommand AnchorSideBottom.Side = asrBottom Left = 698 Height = 28 Top = 202 Width = 32 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } Visible = False OnClick = btnRelativeExternalCommandClick end object btnRelativeIconFileName: TSpeedButton AnchorSideTop.Control = edtIconFileName AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtIconFileName AnchorSideBottom.Side = asrBottom Left = 698 Height = 28 Top = 2 Width = 32 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } Visible = False OnClick = btnRelativeIconFileNameClick end object btnStartPath: TButton AnchorSideTop.Control = edtStartPath AnchorSideRight.Control = btnRelativeStartPath AnchorSideBottom.Control = edtStartPath AnchorSideBottom.Side = asrBottom Left = 666 Height = 28 Top = 262 Width = 32 Anchors = [akTop, akRight, akBottom] BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnStartPathClick TabOrder = 10 Visible = False end object btnRelativeStartPath: TSpeedButton AnchorSideTop.Control = edtStartPath AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtStartPath AnchorSideBottom.Side = asrBottom Left = 698 Height = 28 Top = 262 Width = 32 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } Visible = False OnClick = btnRelativeStartPathClick end object btnOpenCmdDlg: TButton AnchorSideLeft.Control = cbInternalCommand AnchorSideTop.Control = cbInternalCommand AnchorSideRight.Control = lblHelpOnInternalCommand AnchorSideBottom.Control = cbInternalCommand AnchorSideBottom.Side = asrBottom Left = 621 Height = 28 Top = 62 Width = 74 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Left = 3 BorderSpacing.InnerBorder = 4 Caption = 'Select' OnClick = btnOpenCmdDlgClick TabOrder = 12 Visible = False end object lblHelpOnInternalCommand: TLabel AnchorSideTop.Control = lblInternalCommand AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom Cursor = crHandPoint Left = 698 Height = 20 Top = 66 Width = 32 Anchors = [akTop, akRight] BorderSpacing.Left = 3 Caption = 'Help' Font.Style = [fsUnderline] ParentColor = False ParentFont = False Visible = False OnClick = lblHelpOnInternalCommandClick end object btnSuggestionTooltip: TButton AnchorSideTop.Control = edtToolTip AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtToolTip AnchorSideBottom.Side = asrBottom Left = 643 Height = 28 Hint = 'Have DC suggest the tooltip based on button type, command and parameters' Top = 32 Width = 87 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Left = 3 BorderSpacing.InnerBorder = 4 Caption = 'Suggest' OnClick = btnSuggestionTooltipClick TabOrder = 11 Visible = False end object btnParametersHelper: TSpeedButton AnchorSideTop.Control = edtExternalParameters AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtExternalParameters AnchorSideBottom.Side = asrBottom Left = 698 Height = 28 Top = 232 Width = 32 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } Visible = False OnClick = btnParametersHelperClick end object btnInternalParametersHelper: TSpeedButton AnchorSideTop.Control = lblInternalParameters AnchorSideRight.Control = pnlEditControls AnchorSideRight.Side = asrBottom Left = 698 Height = 23 Top = 96 Width = 32 Anchors = [akTop, akRight] BorderSpacing.Left = 3 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 0033000000000000000000000000000000000000000000000000000000000000 00070000003300000033000000330000000700000000FFFFFF00FFFFFF00BB87 47FF000000330000000000000000000000000000000000000000000000005C43 2349BB8747FFBB8747FFBB8747FF5C43234900000000FFFFFF00FFFFFF00BB87 47FFBB8747FF000000330000000000000000000000000000000000000000B482 44DDBB8747FF00000000BB8747FFB48244DD00000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF0000003300000000000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 000000000000BB8747FFBB8747FF00000033000000000000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 00000000000000000000BB8747FFBB8747FF000000330000000000000000BB87 47FFBB8747FF00000000BB8747FFBB8747FF00000000FFFFFF00FFFFFF000000 0000000000000000000000000000BB8747FFBB8747FF0000003300000000BA86 47D4BB8747FF00000033BB8747FFBA8647D600000000FFFFFF00FFFFFF000000 000000000000000000000000000000000000BB8747FFBB8747FF00000033BB87 4719BB8747FFBB8747FFBB8747FFBB87472400000000FFFFFF00FFFFFF000000 00000000000700000033000000330000003300000005BB8747FFBB8747FF0000 00330000000000000000000000000000000000000000FFFFFF00FFFFFF000000 00005C432349BB8747FFBB8747FFBB8747FF4A351C3F00000000BB8747FFBB87 47FF0000003300000000000000000000000000000000FFFFFF00FFFFFF000000 0000B48244DDBB8747FF00000000BB8747FFB48244DC0000000000000000BB87 47FFBB8747FF00000033000000000000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 0000BB8747FFBB8747FF000000330000000000000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 000000000000BB8747FFBB8747FF0000003300000000FFFFFF00FFFFFF000000 0000BB8747FFBB8747FF00000000BB8747FFBB8747FF00000000000000000000 00000000000000000000BB8747FFBB8747FF00000033FFFFFF00FFFFFF000000 0000BA8647D6BB8747FF00000033BB8747FFBA8647D600000000000000000000 0000000000000000000000000000BB8747FFBB8747FFFFFFFF00FFFFFF000000 0000BB874724BB8747FFBB8747FFBB8747FFBB87472400000000000000000000 000000000000000000000000000000000000BB8747FFFFFFFF00 } Visible = False OnClick = btnInternalParametersHelperClick end object lblStyle: TLabel AnchorSideTop.Side = asrBottom Left = 12 Height = 20 Top = 328 Width = 76 BorderSpacing.Left = 12 BorderSpacing.Top = 12 Caption = 'Style:' ParentColor = False end object rbSeparator: TRadioButton AnchorSideLeft.Control = lblStyle AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblStyle AnchorSideTop.Side = asrCenter Left = 100 Height = 24 Top = 326 Width = 89 BorderSpacing.Left = 12 Caption = 'Separator' Checked = True TabOrder = 13 TabStop = True end object rbSpace: TRadioButton AnchorSideLeft.Control = rbSeparator AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbSeparator AnchorSideTop.Side = asrCenter Left = 201 Height = 24 Top = 326 Width = 64 BorderSpacing.Left = 12 Caption = 'Space' TabOrder = 14 end end end object pnToolbars: TPanel[3] AnchorSideLeft.Control = gbGroupBox AnchorSideTop.Control = gbGroupBox AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbGroupBox AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlFullToolbarButtons Left = 6 Height = 93 Top = 113 Width = 838 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 2 ParentColor = False TabOrder = 3 end object OpenDialog: TOpenDialog[4] Filter = 'DC Toolbar files|*.toolbar|.xml Config files|*.xml|TC Toolbar files|*.BAR|Any files|*.*' Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] left = 48 top = 104 end object pmPathHelper: TPopupMenu[5] left = 784 top = 216 end object pmInsertButtonMenu: TPopupMenu[6] left = 256 top = 176 object miAddSeparatorSubMenu: TMenuItem Caption = 'for a separator' object miSeparatorFirstItem: TMenuItem Tag = 17 Caption = 'as first element' OnClick = miInsertButtonClick end object miSeparatorPriorCurrent: TMenuItem Tag = 18 Caption = 'just prior current selection' OnClick = miInsertButtonClick end object miSeparatorAfterCurrent: TMenuItem Tag = 19 Caption = 'just after current selection' OnClick = miInsertButtonClick end object miSeparatorLastElement: TMenuItem Tag = 20 Caption = 'as last element' OnClick = miInsertButtonClick end end object miAddInternalCommandSubMenu: TMenuItem Caption = 'for an internal command' object miInternalCommandFirstElement: TMenuItem Tag = 33 Caption = 'as first element' OnClick = miInsertButtonClick end object miInternalCommandPriorCurrent: TMenuItem Tag = 34 Caption = 'just prior current selection' OnClick = miInsertButtonClick end object miInternalCommandAfterCurrent: TMenuItem Tag = 35 Caption = 'just after current selection' OnClick = miInsertButtonClick end object miInternalCommandLastElement: TMenuItem Tag = 36 Caption = 'as last element' OnClick = miInsertButtonClick end end object miAddExternalCommandSubMenu: TMenuItem Caption = 'for an external command' object miExternalCommandFirstElement: TMenuItem Tag = 49 Caption = 'as first element' OnClick = miInsertButtonClick end object miExternalCommandPriorCurrent: TMenuItem Tag = 50 Caption = 'just prior current selection' OnClick = miInsertButtonClick end object miExternalCommandAfterCurrent: TMenuItem Tag = 51 Caption = 'just after current selection' OnClick = miInsertButtonClick end object miExternalCommandLastElement: TMenuItem Tag = 52 Caption = 'as last element' OnClick = miInsertButtonClick end end object miAddSubToolBarSubMenu: TMenuItem Caption = 'for a sub-tool bar' object miSubToolBarFirstElement: TMenuItem Tag = 65 Caption = 'as first element' OnClick = miInsertButtonClick end object miSubToolBarPriorCurrent: TMenuItem Tag = 66 Caption = 'just prior current selection' OnClick = miInsertButtonClick end object miSubToolBarAfterCurrent: TMenuItem Tag = 67 Caption = 'just after current selection' OnClick = miInsertButtonClick end object miSubToolBarLastElement: TMenuItem Tag = 68 Caption = 'as last element' OnClick = miInsertButtonClick end end end object pmOtherClickToolbar: TPopupMenu[7] left = 592 top = 176 object miAddAllCmds: TMenuItem Caption = 'Add toolbar with ALL DC commands' OnClick = miAddAllCmdsClick end object miSearchAndReplace: TMenuItem Caption = 'Search and replace...' object miSrcRplIconNames: TMenuItem Tag = 1 Caption = 'in all icon names...' OnClick = miSrcRplClick end object miSrcRplCommands: TMenuItem Tag = 2 Caption = 'in all commands...' OnClick = miSrcRplClick end object miSrcRplParameters: TMenuItem Tag = 4 Caption = 'in all parameters...' OnClick = miSrcRplClick end object miSrcRplStartPath: TMenuItem Tag = 8 Caption = 'in all start path...' OnClick = miSrcRplClick end object miSrcRplClickSeparator: TMenuItem Caption = '-' end object miSrcRplAllOfAll: TMenuItem Tag = 15 Caption = 'in all of all the above...' OnClick = miSrcRplClick end end object miSeparator1: TMenuItem Caption = '-' end object miExport: TMenuItem Caption = 'Export...' object miExportTop: TMenuItem Caption = 'Top toolbar...' object miExportTopToDCBar: TMenuItem Tag = 2 Caption = 'to a Toolbar File (.toolbar)' OnClick = miExportToAnythingClick end object miExportSeparator1: TMenuItem Caption = '-' end object miExportTopToTCIniKeep: TMenuItem Caption = 'to a "wincmd.ini" of TC (keep existing)' OnClick = miExportToAnythingClick end object miExportTopToTCIniNoKeep: TMenuItem Tag = 128 Caption = 'to a "wincmd.ini" of TC (erase existing)' OnClick = miExportToAnythingClick end object miExportSeparator2: TMenuItem Caption = '-' end object miExportTopToTCBarKeep: TMenuItem Tag = 1 Caption = 'to a TC .BAR file (keep existing)' OnClick = miExportToAnythingClick end object miExportTopToTCBarNoKeep: TMenuItem Tag = 129 Caption = 'to a TC .BAR file (erase existing)' OnClick = miExportToAnythingClick end end object miExportCurrent: TMenuItem Caption = 'Current toolbar...' object miExportCurrentToDCBar: TMenuItem Tag = 34 Caption = 'to a Toolbar File (.toolbar)' OnClick = miExportToAnythingClick end object miExportSeparator3: TMenuItem Caption = '-' end object miExportCurrentToTCIniKeep: TMenuItem Tag = 32 Caption = 'to a "wincmd.ini" of TC (keep existing)' OnClick = miExportToAnythingClick end object miExportCurrentToTCIniNoKeep: TMenuItem Tag = 160 Caption = 'to a "wincmd.ini" of TC (erase existing)' OnClick = miExportToAnythingClick end object miExportSeparator4: TMenuItem Caption = '-' end object miExportCurrentToTCBarKeep: TMenuItem Tag = 33 Caption = 'to a TC .BAR file (keep existing)' OnClick = miExportToAnythingClick end object miExportCurrentToTCBarNoKeep: TMenuItem Tag = 161 Caption = 'to a TC .BAR file (erase existing)' OnClick = miExportToAnythingClick end end end object miImport: TMenuItem Caption = 'Import...' object miImportDCBAR: TMenuItem Caption = 'from a Toolbar File (.toolbar)' object miImportDCBARReplaceTop: TMenuItem Tag = 130 Caption = 'to replace top toolbar' OnClick = miImportFromAnythingClick end object miSeparator8: TMenuItem Caption = '-' end object miImportDCBARAddTop: TMenuItem Tag = 2 Caption = 'to add to top toolbar' OnClick = miImportFromAnythingClick end object miImportDCBARAddMenuTop: TMenuItem Tag = 18 Caption = 'to add to a new toolbar to top toolbar' OnClick = miImportFromAnythingClick end object miSeparator9: TMenuItem Caption = '-' end object miImportDCBARAddCurrent: TMenuItem Tag = 34 Caption = 'to add to current toolbar' OnClick = miImportFromAnythingClick end object miImportDCBARAddMenuCurrent: TMenuItem Tag = 50 Caption = 'to add to a new toolbar to current toolbar' OnClick = miImportFromAnythingClick end end object miImportSeparator: TMenuItem Caption = '-' end object miImportTCINI: TMenuItem Caption = 'from "wincmd.ini" of TC...' object miImportTCINIReplaceTop: TMenuItem Tag = 128 Caption = 'to replace top toolbar' OnClick = miImportFromAnythingClick end object miSeparator6: TMenuItem Caption = '-' end object miImportTCINIAddTop: TMenuItem Caption = 'to add to top toolbar' OnClick = miImportFromAnythingClick end object miImportTCINIAddMenuTop: TMenuItem Tag = 16 Caption = 'to add to a new toolbar to top toolbar' OnClick = miImportFromAnythingClick end object miSeparator7: TMenuItem Caption = '-' end object miImportTCINIAddCurrent: TMenuItem Tag = 32 Caption = 'to add to current toolbar' OnClick = miImportFromAnythingClick end object miImportTCINIAddMenuCurrent: TMenuItem Tag = 48 Caption = 'to add to a new toolbar to current toolbar' OnClick = miImportFromAnythingClick end end object miImportTCBAR: TMenuItem Caption = 'from a single TC .BAR file' object miImportTCBARReplaceTop: TMenuItem Tag = 129 Caption = 'to replace top toolbar' OnClick = miImportFromAnythingClick end object miSeparator10: TMenuItem Caption = '-' end object miImportTCBARAddTop: TMenuItem Tag = 1 Caption = 'to add to top toolbar' OnClick = miImportFromAnythingClick end object miImportTCBARAddMenuTop: TMenuItem Tag = 17 Caption = 'to add to a new toolbar to top toolbar' OnClick = miImportFromAnythingClick end object miSeparator11: TMenuItem Caption = '-' end object miImportTCBARAddCurrent: TMenuItem Tag = 33 Caption = 'to add to current toolbar' OnClick = miImportFromAnythingClick end object miImportTCBARAddMenuCurrent: TMenuItem Tag = 49 Caption = 'to add to a new toolbar to current toolbar' OnClick = miImportFromAnythingClick end end end object miSeparator2: TMenuItem Caption = '-' end object miBackup: TMenuItem Caption = 'Backup...' object miExportTopToBackup: TMenuItem Tag = 3 Caption = 'Save a backup of Toolbar' OnClick = miExportToAnythingClick end object miImportBackup: TMenuItem Caption = 'Restore a backup of Toolbar' object miImportBackupReplaceTop: TMenuItem Tag = 131 Caption = 'to replace top toolbar' OnClick = miImportFromAnythingClick end object miSeparator13: TMenuItem Caption = '-' end object miImportBackupAddTop: TMenuItem Tag = 3 Caption = 'to add to top toolbar' OnClick = miImportFromAnythingClick end object miImportBackupAddMenuTop: TMenuItem Tag = 19 Caption = 'to add to a new toolbar to top toolbar' OnClick = miImportFromAnythingClick end object miSeparator14: TMenuItem Caption = '-' end object miImportBackupAddCurrent: TMenuItem Tag = 35 Caption = 'to add to current toolbar' OnClick = miImportFromAnythingClick end object miImportBackupAddMenuCurrent: TMenuItem Tag = 51 Caption = 'to add to a new toolbar to current toolbar' OnClick = miImportFromAnythingClick end end end end object SaveDialog: TSaveDialog[8] DefaultExt = '.hotlist' Filter = 'DC Toolbar files|*.toolbar|TC Toolbar files|*.BAR|Any files|*.*' Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing, ofViewDetail] left = 152 top = 104 end object ReplaceDialog: TReplaceDialog[9] Options = [frHideWholeWord, frHideUpDown, frDisableUpDown, frDisableWholeWord, frHideEntireScope, frHidePromptOnReplace] left = 288 top = 112 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarbase.lrj�������������������������������������������������0000644�0001750�0000144�00000050221�14743153644�021442� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":193790965,"name":"tfrmoptionstoolbarbase.gbgroupbox.caption","sourcebytes":[65,112,112,101,97,114,97,110,99,101],"value":"Appearance"}, {"hash":75282442,"name":"tfrmoptionstoolbarbase.lblbarsize.caption","sourcebytes":[38,66,97,114,32,115,105,122,101,58],"value":"&Bar size:"}, {"hash":131368586,"name":"tfrmoptionstoolbarbase.lbliconsize.caption","sourcebytes":[73,99,111,110,32,115,105,38,122,101,58],"value":"Icon si&ze:"}, {"hash":51983379,"name":"tfrmoptionstoolbarbase.cbflatbuttons.caption","sourcebytes":[38,70,108,97,116,32,98,117,116,116,111,110,115],"value":"&Flat buttons"}, {"hash":124221267,"name":"tfrmoptionstoolbarbase.cbshowcaptions.caption","sourcebytes":[83,104,111,38,119,32,99,97,112,116,105,111,110,115],"value":"Sho&w captions"}, {"hash":47614275,"name":"tfrmoptionstoolbarbase.cbreporterrorwithcommands.caption","sourcebytes":[82,101,112,111,114,116,32,101,114,114,111,114,115,32,119,105,116,104,32,99,111,109,109,97,110,100,115],"value":"Report errors with commands"}, {"hash":223064078,"name":"tfrmoptionstoolbarbase.btninsertbutton.caption","sourcebytes":[38,73,110,115,101,114,116,32,110,101,119,32,98,117,116,116,111,110],"value":"&Insert new button"}, {"hash":55566190,"name":"tfrmoptionstoolbarbase.btnclonebutton.caption","sourcebytes":[67,38,108,111,110,101,32,98,117,116,116,111,110],"value":"C&lone button"}, {"hash":179055749,"name":"tfrmoptionstoolbarbase.btndeletebutton.caption","sourcebytes":[38,68,101,108,101,116,101],"value":"&Delete"}, {"hash":183260782,"name":"tfrmoptionstoolbarbase.btnother.caption","sourcebytes":[79,116,104,101,114,46,46,46],"value":"Other..."}, {"hash":105810901,"name":"tfrmoptionstoolbarbase.rgtoolitemtype.caption","sourcebytes":[66,117,116,116,111,110,32,116,121,112,101],"value":"Button type"}, {"hash":83500314,"name":"tfrmoptionstoolbarbase.lbliconfile.caption","sourcebytes":[73,99,111,38,110,58],"value":"Ico&n:"}, {"hash":107191178,"name":"tfrmoptionstoolbarbase.lbltooltip.caption","sourcebytes":[38,84,111,111,108,116,105,112,58],"value":"&Tooltip:"}, {"hash":222514794,"name":"tfrmoptionstoolbarbase.lblinternalcommand.caption","sourcebytes":[67,111,38,109,109,97,110,100,58],"value":"Co&mmand:"}, {"hash":24920554,"name":"tfrmoptionstoolbarbase.lblinternalparameters.caption","sourcebytes":[38,80,97,114,97,109,101,116,101,114,115,58],"value":"&Parameters:"}, {"hash":116981518,"name":"tfrmoptionstoolbarbase.edtinternalparameters.hint","sourcebytes":[69,110,116,101,114,32,99,111,109,109,97,110,100,32,112,97,114,97,109,101,116,101,114,115,44,32,101,97,99,104,32,105,110,32,97,32,115,101,112,97,114,97,116,101,32,108,105,110,101,46,32,80,114,101,115,115,32,70,49,32,116,111,32,115,101,101,32,104,101,108,112,32,111,110,32,112,97,114,97,109,101,116,101,114,115,46],"value":"Enter command parameters, each in a separate line. Press F1 to see help on parameters."}, {"hash":222514794,"name":"tfrmoptionstoolbarbase.lblexternalcommand.caption","sourcebytes":[67,111,38,109,109,97,110,100,58],"value":"Co&mmand:"}, {"hash":1054,"name":"tfrmoptionstoolbarbase.btnopenfile.caption","sourcebytes":[62,62],"value":">>"}, {"hash":163890522,"name":"tfrmoptionstoolbarbase.lblexternalparameters.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,38,115,58],"value":"Parameter&s:"}, {"hash":46327258,"name":"tfrmoptionstoolbarbase.lblstartpath.caption","sourcebytes":[83,116,97,114,116,32,112,97,116,38,104,58],"value":"Start pat&h:"}, {"hash":107419706,"name":"tfrmoptionstoolbarbase.lblhotkey.caption","sourcebytes":[72,111,116,32,107,101,121,58],"value":"Hot key:"}, {"hash":199088041,"name":"tfrmoptionstoolbarbase.btnedithotkey.caption","sourcebytes":[69,100,105,116,32,104,111,116,38,107,101,121],"value":"Edit hot&key"}, {"hash":53335353,"name":"tfrmoptionstoolbarbase.btnremovehotkey.caption","sourcebytes":[82,101,109,111,118,101,32,104,111,116,107,101,38,121],"value":"Remove hotke&y"}, {"hash":1054,"name":"tfrmoptionstoolbarbase.btnstartpath.caption","sourcebytes":[62,62],"value":">>"}, {"hash":94120868,"name":"tfrmoptionstoolbarbase.btnopencmddlg.caption","sourcebytes":[83,101,108,101,99,116],"value":"Select"}, {"hash":322608,"name":"tfrmoptionstoolbarbase.lblhelponinternalcommand.caption","sourcebytes":[72,101,108,112],"value":"Help"}, {"hash":113085971,"name":"tfrmoptionstoolbarbase.btnsuggestiontooltip.hint","sourcebytes":[72,97,118,101,32,68,67,32,115,117,103,103,101,115,116,32,116,104,101,32,116,111,111,108,116,105,112,32,98,97,115,101,100,32,111,110,32,98,117,116,116,111,110,32,116,121,112,101,44,32,99,111,109,109,97,110,100,32,97,110,100,32,112,97,114,97,109,101,116,101,114,115],"value":"Have DC suggest the tooltip based on button type, command and parameters"}, {"hash":180215028,"name":"tfrmoptionstoolbarbase.btnsuggestiontooltip.caption","sourcebytes":[83,117,103,103,101,115,116],"value":"Suggest"}, {"hash":109630626,"name":"tfrmoptionstoolbarbase.rbseparator.caption","sourcebytes":[83,101,112,97,114,97,116,111,114],"value":"Separator"}, {"hash":5924757,"name":"tfrmoptionstoolbarbase.rbspace.caption","sourcebytes":[83,112,97,99,101],"value":"Space"}, {"hash":95158922,"name":"tfrmoptionstoolbarbase.lblstyle.caption","sourcebytes":[83,116,121,108,101,58],"value":"Style:"}, {"hash":48996290,"name":"tfrmoptionstoolbarbase.miaddseparatorsubmenu.caption","sourcebytes":[102,111,114,32,97,32,115,101,112,97,114,97,116,111,114],"value":"for a separator"}, {"hash":119871828,"name":"tfrmoptionstoolbarbase.miseparatorfirstitem.caption","sourcebytes":[97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116],"value":"as first element"}, {"hash":150375262,"name":"tfrmoptionstoolbarbase.miseparatorpriorcurrent.caption","sourcebytes":[106,117,115,116,32,112,114,105,111,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just prior current selection"}, {"hash":149346878,"name":"tfrmoptionstoolbarbase.miseparatoraftercurrent.caption","sourcebytes":[106,117,115,116,32,97,102,116,101,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just after current selection"}, {"hash":218429028,"name":"tfrmoptionstoolbarbase.miseparatorlastelement.caption","sourcebytes":[97,115,32,108,97,115,116,32,101,108,101,109,101,110,116],"value":"as last element"}, {"hash":247327204,"name":"tfrmoptionstoolbarbase.miaddinternalcommandsubmenu.caption","sourcebytes":[102,111,114,32,97,110,32,105,110,116,101,114,110,97,108,32,99,111,109,109,97,110,100],"value":"for an internal command"}, {"hash":119871828,"name":"tfrmoptionstoolbarbase.miinternalcommandfirstelement.caption","sourcebytes":[97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116],"value":"as first element"}, {"hash":150375262,"name":"tfrmoptionstoolbarbase.miinternalcommandpriorcurrent.caption","sourcebytes":[106,117,115,116,32,112,114,105,111,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just prior current selection"}, {"hash":149346878,"name":"tfrmoptionstoolbarbase.miinternalcommandaftercurrent.caption","sourcebytes":[106,117,115,116,32,97,102,116,101,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just after current selection"}, {"hash":218429028,"name":"tfrmoptionstoolbarbase.miinternalcommandlastelement.caption","sourcebytes":[97,115,32,108,97,115,116,32,101,108,101,109,101,110,116],"value":"as last element"}, {"hash":247325668,"name":"tfrmoptionstoolbarbase.miaddexternalcommandsubmenu.caption","sourcebytes":[102,111,114,32,97,110,32,101,120,116,101,114,110,97,108,32,99,111,109,109,97,110,100],"value":"for an external command"}, {"hash":119871828,"name":"tfrmoptionstoolbarbase.miexternalcommandfirstelement.caption","sourcebytes":[97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116],"value":"as first element"}, {"hash":150375262,"name":"tfrmoptionstoolbarbase.miexternalcommandpriorcurrent.caption","sourcebytes":[106,117,115,116,32,112,114,105,111,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just prior current selection"}, {"hash":149346878,"name":"tfrmoptionstoolbarbase.miexternalcommandaftercurrent.caption","sourcebytes":[106,117,115,116,32,97,102,116,101,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just after current selection"}, {"hash":218429028,"name":"tfrmoptionstoolbarbase.miexternalcommandlastelement.caption","sourcebytes":[97,115,32,108,97,115,116,32,101,108,101,109,101,110,116],"value":"as last element"}, {"hash":86211106,"name":"tfrmoptionstoolbarbase.miaddsubtoolbarsubmenu.caption","sourcebytes":[102,111,114,32,97,32,115,117,98,45,116,111,111,108,32,98,97,114],"value":"for a sub-tool bar"}, {"hash":119871828,"name":"tfrmoptionstoolbarbase.misubtoolbarfirstelement.caption","sourcebytes":[97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116],"value":"as first element"}, {"hash":150375262,"name":"tfrmoptionstoolbarbase.misubtoolbarpriorcurrent.caption","sourcebytes":[106,117,115,116,32,112,114,105,111,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just prior current selection"}, {"hash":149346878,"name":"tfrmoptionstoolbarbase.misubtoolbaraftercurrent.caption","sourcebytes":[106,117,115,116,32,97,102,116,101,114,32,99,117,114,114,101,110,116,32,115,101,108,101,99,116,105,111,110],"value":"just after current selection"}, {"hash":218429028,"name":"tfrmoptionstoolbarbase.misubtoolbarlastelement.caption","sourcebytes":[97,115,32,108,97,115,116,32,101,108,101,109,101,110,116],"value":"as last element"}, {"hash":72262595,"name":"tfrmoptionstoolbarbase.miaddallcmds.caption","sourcebytes":[65,100,100,32,116,111,111,108,98,97,114,32,119,105,116,104,32,65,76,76,32,68,67,32,99,111,109,109,97,110,100,115],"value":"Add toolbar with ALL DC commands"}, {"hash":244782286,"name":"tfrmoptionstoolbarbase.misearchandreplace.caption","sourcebytes":[83,101,97,114,99,104,32,97,110,100,32,114,101,112,108,97,99,101,46,46,46],"value":"Search and replace..."}, {"hash":137523518,"name":"tfrmoptionstoolbarbase.misrcrpliconnames.caption","sourcebytes":[105,110,32,97,108,108,32,105,99,111,110,32,110,97,109,101,115,46,46,46],"value":"in all icon names..."}, {"hash":253832478,"name":"tfrmoptionstoolbarbase.misrcrplcommands.caption","sourcebytes":[105,110,32,97,108,108,32,99,111,109,109,97,110,100,115,46,46,46],"value":"in all commands..."}, {"hash":204032958,"name":"tfrmoptionstoolbarbase.misrcrplparameters.caption","sourcebytes":[105,110,32,97,108,108,32,112,97,114,97,109,101,116,101,114,115,46,46,46],"value":"in all parameters..."}, {"hash":206188558,"name":"tfrmoptionstoolbarbase.misrcrplstartpath.caption","sourcebytes":[105,110,32,97,108,108,32,115,116,97,114,116,32,112,97,116,104,46,46,46],"value":"in all start path..."}, {"hash":187465454,"name":"tfrmoptionstoolbarbase.misrcrplallofall.caption","sourcebytes":[105,110,32,97,108,108,32,111,102,32,97,108,108,32,116,104,101,32,97,98,111,118,101,46,46,46],"value":"in all of all the above..."}, {"hash":124337662,"name":"tfrmoptionstoolbarbase.miexport.caption","sourcebytes":[69,120,112,111,114,116,46,46,46],"value":"Export..."}, {"hash":78643966,"name":"tfrmoptionstoolbarbase.miexporttop.caption","sourcebytes":[84,111,112,32,116,111,111,108,98,97,114,46,46,46],"value":"Top toolbar..."}, {"hash":235578425,"name":"tfrmoptionstoolbarbase.miexporttoptodcbar.caption","sourcebytes":[116,111,32,97,32,84,111,111,108,98,97,114,32,70,105,108,101,32,40,46,116,111,111,108,98,97,114,41],"value":"to a Toolbar File (.toolbar)"}, {"hash":149668585,"name":"tfrmoptionstoolbarbase.miexporttoptotcinikeep.caption","sourcebytes":[116,111,32,97,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,32,40,107,101,101,112,32,101,120,105,115,116,105,110,103,41],"value":"to a \"wincmd.ini\" of TC (keep existing)"}, {"hash":990713,"name":"tfrmoptionstoolbarbase.miexporttoptotcininokeep.caption","sourcebytes":[116,111,32,97,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,32,40,101,114,97,115,101,32,101,120,105,115,116,105,110,103,41],"value":"to a \"wincmd.ini\" of TC (erase existing)"}, {"hash":119283481,"name":"tfrmoptionstoolbarbase.miexporttoptotcbarkeep.caption","sourcebytes":[116,111,32,97,32,84,67,32,46,66,65,82,32,102,105,108,101,32,40,107,101,101,112,32,101,120,105,115,116,105,110,103,41],"value":"to a TC .BAR file (keep existing)"}, {"hash":259329065,"name":"tfrmoptionstoolbarbase.miexporttoptotcbarnokeep.caption","sourcebytes":[116,111,32,97,32,84,67,32,46,66,65,82,32,102,105,108,101,32,40,101,114,97,115,101,32,101,120,105,115,116,105,110,103,41],"value":"to a TC .BAR file (erase existing)"}, {"hash":54730670,"name":"tfrmoptionstoolbarbase.miexportcurrent.caption","sourcebytes":[67,117,114,114,101,110,116,32,116,111,111,108,98,97,114,46,46,46],"value":"Current toolbar..."}, {"hash":235578425,"name":"tfrmoptionstoolbarbase.miexportcurrenttodcbar.caption","sourcebytes":[116,111,32,97,32,84,111,111,108,98,97,114,32,70,105,108,101,32,40,46,116,111,111,108,98,97,114,41],"value":"to a Toolbar File (.toolbar)"}, {"hash":149668585,"name":"tfrmoptionstoolbarbase.miexportcurrenttotcinikeep.caption","sourcebytes":[116,111,32,97,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,32,40,107,101,101,112,32,101,120,105,115,116,105,110,103,41],"value":"to a \"wincmd.ini\" of TC (keep existing)"}, {"hash":990713,"name":"tfrmoptionstoolbarbase.miexportcurrenttotcininokeep.caption","sourcebytes":[116,111,32,97,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,32,40,101,114,97,115,101,32,101,120,105,115,116,105,110,103,41],"value":"to a \"wincmd.ini\" of TC (erase existing)"}, {"hash":119283481,"name":"tfrmoptionstoolbarbase.miexportcurrenttotcbarkeep.caption","sourcebytes":[116,111,32,97,32,84,67,32,46,66,65,82,32,102,105,108,101,32,40,107,101,101,112,32,101,120,105,115,116,105,110,103,41],"value":"to a TC .BAR file (keep existing)"}, {"hash":259329065,"name":"tfrmoptionstoolbarbase.miexportcurrenttotcbarnokeep.caption","sourcebytes":[116,111,32,97,32,84,67,32,46,66,65,82,32,102,105,108,101,32,40,101,114,97,115,101,32,101,120,105,115,116,105,110,103,41],"value":"to a TC .BAR file (erase existing)"}, {"hash":124338510,"name":"tfrmoptionstoolbarbase.miimport.caption","sourcebytes":[73,109,112,111,114,116,46,46,46],"value":"Import..."}, {"hash":187796025,"name":"tfrmoptionstoolbarbase.miimportdcbar.caption","sourcebytes":[102,114,111,109,32,97,32,84,111,111,108,98,97,114,32,70,105,108,101,32,40,46,116,111,111,108,98,97,114,41],"value":"from a Toolbar File (.toolbar)"}, {"hash":117300242,"name":"tfrmoptionstoolbarbase.miimportdcbarreplacetop.caption","sourcebytes":[116,111,32,114,101,112,108,97,99,101,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to replace top toolbar"}, {"hash":241522226,"name":"tfrmoptionstoolbarbase.miimportdcbaraddtop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to top toolbar"}, {"hash":173097890,"name":"tfrmoptionstoolbarbase.miimportdcbaraddmenutop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to top toolbar"}, {"hash":2715186,"name":"tfrmoptionstoolbarbase.miimportdcbaraddcurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to current toolbar"}, {"hash":194869810,"name":"tfrmoptionstoolbarbase.miimportdcbaraddmenucurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to current toolbar"}, {"hash":17047070,"name":"tfrmoptionstoolbarbase.miimporttcini.caption","sourcebytes":[102,114,111,109,32,34,119,105,110,99,109,100,46,105,110,105,34,32,111,102,32,84,67,46,46,46],"value":"from \"wincmd.ini\" of TC..."}, {"hash":117300242,"name":"tfrmoptionstoolbarbase.miimporttcinireplacetop.caption","sourcebytes":[116,111,32,114,101,112,108,97,99,101,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to replace top toolbar"}, {"hash":241522226,"name":"tfrmoptionstoolbarbase.miimporttciniaddtop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to top toolbar"}, {"hash":173097890,"name":"tfrmoptionstoolbarbase.miimporttciniaddmenutop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to top toolbar"}, {"hash":2715186,"name":"tfrmoptionstoolbarbase.miimporttciniaddcurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to current toolbar"}, {"hash":194869810,"name":"tfrmoptionstoolbarbase.miimporttciniaddmenucurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to current toolbar"}, {"hash":58211221,"name":"tfrmoptionstoolbarbase.miimporttcbar.caption","sourcebytes":[102,114,111,109,32,97,32,115,105,110,103,108,101,32,84,67,32,46,66,65,82,32,102,105,108,101],"value":"from a single TC .BAR file"}, {"hash":117300242,"name":"tfrmoptionstoolbarbase.miimporttcbarreplacetop.caption","sourcebytes":[116,111,32,114,101,112,108,97,99,101,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to replace top toolbar"}, {"hash":241522226,"name":"tfrmoptionstoolbarbase.miimporttcbaraddtop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to top toolbar"}, {"hash":173097890,"name":"tfrmoptionstoolbarbase.miimporttcbaraddmenutop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to top toolbar"}, {"hash":2715186,"name":"tfrmoptionstoolbarbase.miimporttcbaraddcurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to current toolbar"}, {"hash":194869810,"name":"tfrmoptionstoolbarbase.miimporttcbaraddmenucurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to current toolbar"}, {"hash":170686846,"name":"tfrmoptionstoolbarbase.mibackup.caption","sourcebytes":[66,97,99,107,117,112,46,46,46],"value":"Backup..."}, {"hash":26464146,"name":"tfrmoptionstoolbarbase.miexporttoptobackup.caption","sourcebytes":[83,97,118,101,32,97,32,98,97,99,107,117,112,32,111,102,32,84,111,111,108,98,97,114],"value":"Save a backup of Toolbar"}, {"hash":12441442,"name":"tfrmoptionstoolbarbase.miimportbackup.caption","sourcebytes":[82,101,115,116,111,114,101,32,97,32,98,97,99,107,117,112,32,111,102,32,84,111,111,108,98,97,114],"value":"Restore a backup of Toolbar"}, {"hash":117300242,"name":"tfrmoptionstoolbarbase.miimportbackupreplacetop.caption","sourcebytes":[116,111,32,114,101,112,108,97,99,101,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to replace top toolbar"}, {"hash":241522226,"name":"tfrmoptionstoolbarbase.miimportbackupaddtop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to top toolbar"}, {"hash":173097890,"name":"tfrmoptionstoolbarbase.miimportbackupaddmenutop.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,116,111,112,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to top toolbar"}, {"hash":2715186,"name":"tfrmoptionstoolbarbase.miimportbackupaddcurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to current toolbar"}, {"hash":194869810,"name":"tfrmoptionstoolbarbase.miimportbackupaddmenucurrent.caption","sourcebytes":[116,111,32,97,100,100,32,116,111,32,97,32,110,101,119,32,116,111,111,108,98,97,114,32,116,111,32,99,117,114,114,101,110,116,32,116,111,111,108,98,97,114],"value":"to add to a new toolbar to current toolbar"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarbase.pas�������������������������������������������������0000644�0001750�0000144�00000215561�14743153644�021450� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Toolbar configuration options page Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsToolbarBase; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Buttons, Menus, //DC uGlobs, fOptionsFrame, KASToolBar, KASToolItems, uFormCommands, uHotkeyManager, DCBasicTypes, fOptionsHotkeysEditHotkey, DCXmlConfig; type { TfrmOptionsToolbarBase } TfrmOptionsToolbarBase = class(TOptionsEditor) btnInsertButton: TButton; btnCloneButton: TButton; btnDeleteButton: TButton; btnParametersHelper: TSpeedButton; btnInternalParametersHelper: TSpeedButton; btnSuggestionTooltip: TButton; btnOpenFile: TButton; btnEditHotkey: TButton; btnOpenCmdDlg: TButton; btnRelativeStartPath: TSpeedButton; btnStartPath: TButton; btnRelativeIconFileName: TSpeedButton; btnRemoveHotkey: TButton; cbInternalCommand: TComboBox; cbFlatButtons: TCheckBox; cbShowCaptions: TCheckBox; edtExternalParameters: TEdit; edtExternalCommand: TEdit; lblStyle: TLabel; lblHelpOnInternalCommand: TLabel; lblHotkeyValue: TLabel; edtStartPath: TEdit; edtToolTip: TEdit; gbGroupBox: TGroupBox; edtIconFileName: TEdit; lblInternalParameters: TLabel; lblBarSize: TLabel; lblBarSizeValue: TLabel; lblInternalCommand: TLabel; lblExternalCommand: TLabel; lblHotkey: TLabel; lblIconFile: TLabel; lblIconSize: TLabel; lblIconSizeValue: TLabel; lblExternalParameters: TLabel; lblStartPath: TLabel; lblToolTip: TLabel; edtInternalParameters: TMemo; miSrcRplIconNames: TMenuItem; miSrcRplCommands: TMenuItem; miSrcRplParameters: TMenuItem; miSrcRplStartPath: TMenuItem; miSrcRplClickSeparator: TMenuItem; miSrcRplAllOfAll: TMenuItem; miSearchAndReplace: TMenuItem; miExportCurrent: TMenuItem; miImportAllDCCommands: TMenuItem; miAddSeparatorSubMenu: TMenuItem; miExternalCommandFirstElement: TMenuItem; miSubToolBarFirstElement: TMenuItem; miInternalCommandPriorCurrent: TMenuItem; miExternalCommandPriorCurrent: TMenuItem; miSubToolBarPriorCurrent: TMenuItem; miInternalCommandAfterCurrent: TMenuItem; miExternalCommandAfterCurrent: TMenuItem; miSubToolBarAfterCurrent: TMenuItem; miInternalCommandLastElement: TMenuItem; miExternalCommandLastElement: TMenuItem; miAddInternalCommandSubMenu: TMenuItem; miSubToolBarLastElement: TMenuItem; miAddExternalCommandSubMenu: TMenuItem; miAddSubToolBarSubMenu: TMenuItem; miSeparatorFirstItem: TMenuItem; miSeparatorPriorCurrent: TMenuItem; miSeparatorAfterCurrent: TMenuItem; miSeparatorLastElement: TMenuItem; miInternalCommandFirstElement: TMenuItem; OpenDialog: TOpenDialog; pmPathHelper: TPopupMenu; pnlEditControls: TPanel; pnlFullToolbarButtons: TPanel; pnlEditToolbar: TPanel; pnlToolbarButtons: TPanel; pmInsertButtonMenu: TPopupMenu; rbSeparator: TRadioButton; rbSpace: TRadioButton; ReplaceDialog: TReplaceDialog; rgToolItemType: TRadioGroup; btnOpenIcon: TSpeedButton; pnToolbars: TPanel; btnRelativeExternalCommand: TSpeedButton; trbBarSize: TTrackBar; trbIconSize: TTrackBar; miImportSeparator: TMenuItem; SaveDialog: TSaveDialog; cbReportErrorWithCommands: TCheckBox; btnOther: TButton; pmOtherClickToolbar: TPopupMenu; miAddAllCmds: TMenuItem; miSeparator1: TMenuItem; miExport: TMenuItem; miExportTop: TMenuItem; miExportTopToDCBar: TMenuItem; miExportSeparator1: TMenuItem; miExportTopToTCIniKeep: TMenuItem; miExportTopToTCIniNoKeep: TMenuItem; miExportSeparator2: TMenuItem; miExportTopToTCBarKeep: TMenuItem; miExportTopToTCBarNoKeep: TMenuItem; miExportCurrentToDCBar: TMenuItem; miExportSeparator3: TMenuItem; miExportCurrentToTCIniKeep: TMenuItem; miExportCurrentToTCIniNoKeep: TMenuItem; miExportSeparator4: TMenuItem; miExportCurrentToTCBarKeep: TMenuItem; miExportCurrentToTCBarNoKeep: TMenuItem; miImport: TMenuItem; miImportDCBAR: TMenuItem; miImportDCBARReplaceTop: TMenuItem; miSeparator8: TMenuItem; miImportDCBARAddTop: TMenuItem; miImportDCBARAddMenuTop: TMenuItem; miSeparator9: TMenuItem; miImportDCBARAddCurrent: TMenuItem; miImportDCBARAddMenuCurrent: TMenuItem; miImportSeparator2: TMenuItem; miImportTCINI: TMenuItem; miImportTCINIReplaceTop: TMenuItem; miSeparator6: TMenuItem; miImportTCINIAddTop: TMenuItem; miImportTCINIAddMenuTop: TMenuItem; miSeparator7: TMenuItem; miImportTCINIAddCurrent: TMenuItem; miImportTCINIAddMenuCurrent: TMenuItem; miImportTCBAR: TMenuItem; miImportTCBARReplaceTop: TMenuItem; miSeparator10: TMenuItem; miImportTCBARAddTop: TMenuItem; miImportTCBARAddMenuTop: TMenuItem; miSeparator11: TMenuItem; miImportTCBARAddCurrent: TMenuItem; miImportTCBARAddMenuCurrent: TMenuItem; miSeparator2: TMenuItem; miBackup: TMenuItem; miExportTopToBackup: TMenuItem; miImportBackup: TMenuItem; miImportBackupReplaceTop: TMenuItem; miSeparator13: TMenuItem; miImportBackupAddTop: TMenuItem; miImportBackupAddMenuTop: TMenuItem; miSeparator14: TMenuItem; miImportBackupAddCurrent: TMenuItem; miImportBackupAddMenuCurrent: TMenuItem; procedure btnEditHotkeyClick(Sender: TObject); procedure btnInsertButtonClick(Sender: TObject); procedure btnInternalParametersHelperClick(Sender: TObject); procedure btnOpenCmdDlgClick(Sender: TObject); procedure btnParametersHelperClick(Sender: TObject); procedure btnRelativeExternalCommandClick(Sender: TObject); procedure btnRelativeIconFileNameClick(Sender: TObject); procedure btnRelativeStartPathClick(Sender: TObject); procedure btnRemoveHotKeyClick(Sender: TObject); procedure btnCloneButtonClick(Sender: TObject); procedure btnDeleteButtonClick(Sender: TObject); procedure btnOpenFileClick(Sender: TObject); procedure btnStartPathClick(Sender: TObject); procedure btnSuggestionTooltipClick(Sender: TObject); procedure cbInternalCommandSelect(Sender: TObject); procedure cbFlatButtonsChange(Sender: TObject); procedure edtIconFileNameChange(Sender: TObject); procedure lblHelpOnInternalCommandClick(Sender: TObject); procedure miAddAllCmdsClick(Sender: TObject); procedure miInsertButtonClick(Sender: TObject); procedure miSrcRplClick(Sender: TObject); procedure ToolbarDragOver(Sender, Source: TObject; {%H-}X, {%H-}Y: Integer; {%H-}State: TDragState; var Accept: Boolean); procedure ToolbarDragDrop(Sender, Source: TObject; {%H-}X, {%H-}Y: Integer); function ToolbarLoadButtonGlyph(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; function ToolbarLoadButtonOverlay(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; procedure ToolbarToolButtonClick(Sender: TObject); procedure ToolbarToolButtonDragDrop(Sender, Source: TObject; {%H-}X, {%H-}Y: Integer); procedure ToolbarToolButtonDragOver(Sender, Source: TObject; {%H-}X, {%H-}Y: Integer; {%H-}State: TDragState; var Accept: Boolean; {%H-}NumberOfButton: Integer); procedure ToolbarToolButtonMouseDown(Sender: TObject; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer); procedure ToolbarToolButtonMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; NumberOfButton: Integer); procedure ToolbarToolButtonMouseUp(Sender: TObject; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer); procedure btnOpenIconClick(Sender: TObject); function ToolbarToolItemShortcutsHint(Sender: TObject; ToolItem: TKASNormalItem): String; procedure rgToolItemTypeSelectionChanged(Sender: TObject); procedure trbBarSizeChange(Sender: TObject); procedure trbIconSizeChange(Sender: TObject); procedure FrameEnter(Sender: TObject); function ComputeToolbarsSignature(Seed:dword=$00000000): dword; procedure btnOtherClick(Sender: TObject); procedure miExportToAnythingClick(Sender: TObject); procedure miImportFromAnythingClick(Sender: TObject); protected FUpdateHotKey: Boolean; FCurrentButton: TKASToolButton; FEditForm: TfrmEditHotkey; FFormCommands: IFormCommands; FToolButtonMouseX, FToolButtonMouseY, FToolDragButtonNumber: Integer; // For dragging FUpdatingButtonType: Boolean; FUpdatingIconText: Boolean; bFirstTimeDrawn: boolean; function AddNewSubToolbar(ToolItem: TKASMenuItem; bIncludeButtonOnNewBar:boolean=True): TKASToolBar; procedure ApplyEditControls; procedure CloseToolbarsBelowCurrentButton; procedure CloseToolbar(Index: Integer); function CreateToolbar(Items: TKASToolBarItems): TKASToolBar; class function FindHotkey(NormalItem: TKASNormalItem; Hotkeys: THotkeys): THotkey; class function FindHotkey(NormalItem: TKASNormalItem): THotkey; function GetTopToolbar: TKASToolBar; procedure LoadCurrentButton; procedure LoadToolbar(ToolBar: TKASToolBar; Config: TXmlConfig; RootNode: TXmlNode; ConfigurationLoadType: TTypeOfConfigurationLoad); procedure PressButtonDown(Button: TKASToolButton); procedure UpdateIcon(Icon: String); procedure DisplayAppropriateControls(EnableNormal, EnableCommand, EnableProgram: boolean); class function GetNode: String; virtual; protected procedure Init; override; public property TopToolbar: TKASToolBar read GetTopToolbar; class function GetIconIndex: Integer; override; class function GetShortcuts(NormalItem: TKASNormalItem): TDynamicStringArray; function IsSignatureComputedFromAllWindowComponents: Boolean; override; function ExtraOptionsSignature(CurrentSignature:dword):dword; override; procedure SelectButton(ButtonNumber: Integer); procedure ScanToolbarForFilenameAndPath(Toolbar: TKASToolbar); procedure RefrechCurrentButton; end; function GetToolbarFilenameToSave(AToolbarPathModifierElement: tToolbarPathModifierElement; sParamFilename: string): string; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. StrUtils, crc, LazUTF8, LCLVersion, Toolwin, //DC {$IFDEF MSWINDOWS} uTotalCommander, {$ENDIF} uVariableMenuSupport, uComponentsSignature, fEditSearch, fMainCommandsDlg, uFileProcs, uDebug, DCOSUtils, uShowMsg, DCStrUtils, uLng, uOSForms, uDCUtils, uPixMapManager, uKASToolItemsExtended, fMain, uSpecialDir, dmHelpManager, uGlobsPaths; const cHotKeyCommand = 'cm_ExecuteToolbarItem'; { Constants used with export/import } MASK_ACTION_WITH_WHAT = $03; ACTION_WITH_WINCMDINI = $00; ACTION_WITH_TC_TOOLBARFILE = $01; ACTION_WITH_DC_TOOLBARFILE = $02; ACTION_WITH_BACKUP = $03; MASK_ACTION_TOOLBAR = $03; ACTION_WITH_MAIN_TOOLBAR = $0; IMPORT_IN_MAIN_TOOLBAR_TO_NEW_SUB_BAR = $1; ACTION_WITH_CURRENT_BAR = $2; IMPORT_IN_CURRENT_BAR_TO_NEW_SUB_BAR = $3; MASK_FLUSHORNOT_EXISTING = $80; ACTION_FLUSH_EXISTING = $80; MASK_IMPORT_DESTIONATION = $30; { TfrmOptionsToolbarBase } class function TfrmOptionsToolbarBase.GetIconIndex: Integer; begin Result := 32; end; class function TfrmOptionsToolbarBase.GetShortcuts(NormalItem: TKASNormalItem): TDynamicStringArray; var Hotkey: THotkey; begin Hotkey := FindHotkey(NormalItem); if Assigned(Hotkey) then Result := Hotkey.Shortcuts else Result := nil; end; { TfrmOptionsToolbarBase.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsToolbarBase.IsSignatureComputedFromAllWindowComponents: Boolean; begin Result := False; end; { TfrmOptionsToolbarBase.ExtraOptionsSignature } function TfrmOptionsToolbarBase.ExtraOptionsSignature(CurrentSignature:dword):dword; begin Result := ComputeToolbarsSignature(CurrentSignature); Result := ComputeSignatureSingleComponent(trbBarSize, Result); Result := ComputeSignatureSingleComponent(trbIconSize, Result); Result := ComputeSignatureSingleComponent(cbFlatButtons, Result); Result := ComputeSignatureSingleComponent(cbReportErrorWithCommands, Result); end; function TfrmOptionsToolbarBase.GetTopToolbar: TKASToolBar; begin if pnToolbars.ControlCount > 0 then Result := pnToolbars.Controls[0] as TKASToolBar else Result := nil; end; procedure TfrmOptionsToolbarBase.Init; var ToolBar: TKASToolBar; begin bFirstTimeDrawn := True; FFormCommands := frmMain as IFormCommands; FFormCommands.GetCommandsList(cbInternalCommand.Items); cbInternalCommand.Sorted := True; FUpdatingButtonType := True; ParseLineToList(rsOptToolbarButtonType, rgToolItemType.Items); OpenDialog.Filter := ParseLineToFileFilter([rsFilterToolbarFiles, '*.toolbar', rsFilterXmlConfigFiles, '*.xml', rsFilterTCToolbarFiles, '*.BAR', rsFilterAnyFiles, AllFilesMask]); SaveDialog.Filter := ParseLineToFileFilter([rsFilterToolbarFiles, '*.toolbar', rsFilterTCToolbarFiles, '*.BAR', rsFilterAnyFiles, AllFilesMask]); FUpdatingButtonType := False; FToolDragButtonNumber := -1; {$IF LCL_FULLVERSION >= 093100} rgToolItemType.OnSelectionChanged := @rgToolItemTypeSelectionChanged; {$ELSE} rgToolItemType.OnClick := @rgToolItemTypeSelectionChanged; {$ENDIF} ToolBar := CreateToolbar(nil); if Assigned(ToolBar) then // Put first one on top so that any other toolbars // created before Show are put below it. ToolBar.Top := 0; {$IFNDEF MSWINDOWS} miExportSeparator1.free; miExportTopToTCIniKeep.free; miExportTopToTCIniNoKeep.free; miExportSeparator2.free; miExportTopToTCBarKeep.free; miExportTopToTCBarNoKeep.free; miExportSeparator3.free; miExportCurrentToTCIniKeep.free; miExportCurrentToTCIniNoKeep.free; miExportSeparator4.free; miExportCurrentToTCBarKeep.free; miExportCurrentToTCBarNoKeep.free; miImportSeparator.free; miImportTCINI.free; miImportTCBAR.free; {$ENDIF} end; procedure TfrmOptionsToolbarBase.LoadCurrentButton; var ToolItem: TKASToolItem; NormalItem: TKASNormalItem; CommandItem: TKASCommandItem; ProgramItem: TKASProgramItem; EnableNormal, EnableCommand, EnableProgram: Boolean; ButtonTypeIndex: Integer = -1; ShortcutsHint: String; begin EnableNormal := False; EnableCommand := False; EnableProgram := False; DisableAutoSizing; try CloseToolbarsBelowCurrentButton; if Assigned(FCurrentButton) then begin ToolItem := FCurrentButton.ToolItem; if ToolItem is TKASSeparatorItem then begin ButtonTypeIndex := 0; if TKASSeparatorItem(ToolItem).Style then rbSpace.Checked := True else rbSeparator.Checked := True; end; if ToolItem is TKASNormalItem then begin EnableNormal := True; NormalItem := TKASNormalItem(ToolItem); FUpdatingIconText := True; edtIconFileName.Text := NormalItem.Icon; FUpdatingIconText := False; edtToolTip.Text:=StringReplace(NormalItem.Hint, #$0A, '\n', [rfReplaceAll]); ShortcutsHint := NormalItem.GetShortcutsHint; if ShortcutsHint = '' then lblHotkeyValue.Caption := rsOptHotkeysNoHotkey else lblHotkeyValue.Caption := ShortcutsHint; btnRemoveHotkey.Enabled := ShortcutsHint <> ''; end; if ToolItem is TKASCommandItem then begin ButtonTypeIndex := 1; EnableCommand := True; CommandItem := TKASCommandItem(ToolItem); cbInternalCommand.Text := CommandItem.Command; SetStringsFromArray(edtInternalParameters.Lines, CommandItem.Params); end; if ToolItem is TKASProgramItem then begin ButtonTypeIndex := 2; EnableProgram := True; ProgramItem := TKASProgramItem(ToolItem); edtExternalCommand.Text := ProgramItem.Command; edtExternalParameters.Text := ProgramItem.Params; edtStartPath.Text := ProgramItem.StartPath; end; if ToolItem is TKASMenuItem then begin ButtonTypeIndex := 3; AddNewSubToolbar(TKASMenuItem(ToolItem)); end; end; FUpdatingButtonType := True; rgToolItemType.ItemIndex := ButtonTypeIndex; FUpdatingButtonType := False; DisplayAppropriateControls(EnableNormal, EnableCommand, EnableProgram); finally EnableAutoSizing; end; //Let's display the menuitem related with a subtoolbar only if current selected toolbar is a subtoolbar. miExportCurrent.Enabled := Assigned(FCurrentButton) and (FCurrentButton.ToolBar.Tag > 1); {$IFDEF MSWINDOWS} miImportTCINIAddCurrent.Enabled := miExportCurrent.Enabled; miImportTCINIAddMenuCurrent.Enabled := miExportCurrent.Enabled; miImportTCBARAddCurrent.Enabled := miExportCurrent.Enabled; miImportTCBARAddMenuCurrent.Enabled := miExportCurrent.Enabled; {$ENDIF} miImportDCBARAddCurrent.Enabled := miExportCurrent.Enabled; miImportDCBARAddMenuCurrent.Enabled := miExportCurrent.Enabled; miImportBackupAddCurrent.Enabled := miExportCurrent.Enabled; miImportBackupAddMenuCurrent.Enabled := miExportCurrent.Enabled; end; procedure TfrmOptionsToolbarBase.RefrechCurrentButton; begin LoadCurrentButton; end; procedure TfrmOptionsToolbarBase.DisplayAppropriateControls(EnableNormal, EnableCommand, EnableProgram: boolean); begin lblIconFile.Visible := EnableNormal; edtIconFileName.Visible := EnableNormal; btnOpenIcon.Visible := EnableNormal; btnRelativeIconFileName.Visible := EnableNormal; lblToolTip.Visible := EnableNormal; edtToolTip.Visible := EnableNormal; btnSuggestionTooltip.Visible := EnableNormal; lblInternalCommand.Visible := EnableCommand; cbInternalCommand.Visible := EnableCommand; btnOpenCmdDlg.Visible := EnableCommand; lblHelpOnInternalCommand.Visible := EnableCommand; lblInternalParameters.Visible := EnableCommand; btnInternalParametersHelper.Visible := EnableCommand; edtInternalParameters.Visible := EnableCommand; lblExternalCommand.Visible := EnableProgram; edtExternalCommand.Visible := EnableProgram; lblExternalParameters.Visible := EnableProgram; edtExternalParameters.Visible := EnableProgram; btnParametersHelper.Visible := EnableProgram; lblStartPath.Visible := EnableProgram; edtStartPath.Visible := EnableProgram; btnOpenFile.Visible := EnableProgram; btnRelativeExternalCommand.Visible := EnableProgram; btnStartPath.Visible := EnableProgram; btnRelativeStartPath.Visible := EnableProgram; lblHotkey.Visible := EnableNormal; lblHotkeyValue.Visible := EnableNormal; btnEditHotkey.Visible := EnableNormal; btnRemoveHotkey.Visible := EnableNormal; btnCloneButton.Visible := Assigned(FCurrentButton); btnDeleteButton.Visible := Assigned(FCurrentButton); rgToolItemType.Visible := Assigned(FCurrentButton); lblStyle.Visible := not (EnableNormal or EnableCommand or EnableProgram); rbSeparator.Visible := lblStyle.Visible; rbSpace.Visible := lblStyle.Visible; end; class function TfrmOptionsToolbarBase.GetNode: String; begin Result:= 'Toolbars/MainToolbar'; end; procedure TfrmOptionsToolbarBase.LoadToolbar(ToolBar: TKASToolBar; Config: TXmlConfig; RootNode: TXmlNode; ConfigurationLoadType: TTypeOfConfigurationLoad); var ToolBarLoader: TKASToolBarExtendedLoader; begin ToolBarLoader := TKASToolBarExtendedLoader.Create(FFormCommands); try if Assigned(RootNode) then ToolBar.LoadConfiguration(Config, RootNode, ToolBarLoader, ConfigurationLoadType); finally ToolBarLoader.Free; end; end; procedure TfrmOptionsToolbarBase.PressButtonDown(Button: TKASToolButton); begin FUpdatingButtonType := True; Button.Click; FUpdatingButtonType := False; end; procedure TfrmOptionsToolbarBase.rgToolItemTypeSelectionChanged(Sender: TObject); var ToolBar: TKASToolBar; ToolItem: TKASToolItem = nil; NewButton: TKASToolButton; begin if not FUpdatingButtonType and Assigned(FCurrentButton) then begin case rgToolItemType.ItemIndex of 0: ToolItem := TKASSeparatorItem.Create; 1: ToolItem := TKASCommandItem.Create(FFormCommands); 2: ToolItem := TKASProgramItem.Create; 3: ToolItem := TKASMenuItem.Create; end; if Assigned(ToolItem) then begin ToolBar := FCurrentButton.ToolBar; // Copy what you can from previous button type. ToolItem.Assign(FCurrentButton.ToolItem); NewButton := ToolBar.InsertButton(FCurrentButton, ToolItem); ToolBar.RemoveButton(FCurrentButton); FCurrentButton := NewButton; PressButtonDown(NewButton); end; end; end; procedure TfrmOptionsToolbarBase.btnOpenIconClick(Sender: TObject); var sFileName: String; begin sFileName := GetCmdDirFromEnvVar(edtIconFileName.Text); if ShowOpenIconDialog(Self, sFileName) then edtIconFileName.Text := GetToolbarFilenameToSave(tpmeIcon, sFileName); end; function TfrmOptionsToolbarBase.CreateToolbar(Items: TKASToolBarItems): TKASToolBar; begin Result := TKASToolBar.Create(pnToolbars); Result.AutoSize := True; Result.Anchors := [akTop, akLeft, akRight]; Result.Constraints.MinHeight := 24; Result.Flat := cbFlatButtons.Checked; Result.GlyphSize := trbIconSize.Position * 2; Result.RadioToolBar := True; Result.SetButtonSize(trbBarSize.Position * 2, trbBarSize.Position * 2); Result.ShowDividerAsButton := True; Result.OnDragOver := @ToolbarDragOver; Result.OnDragDrop := @ToolbarDragDrop; Result.OnLoadButtonGlyph := @ToolbarLoadButtonGlyph; Result.OnToolButtonClick := @ToolbarToolButtonClick; Result.OnLoadButtonOverlay := @ToolbarLoadButtonOverlay; Result.OnToolButtonMouseDown := @ToolbarToolButtonMouseDown; Result.OnToolButtonMouseUp := @ToolbarToolButtonMouseUp; Result.OnToolButtonMouseMove := @ToolbarToolButtonMouseMove; Result.OnToolButtonDragDrop := @ToolbarToolButtonDragDrop; Result.OnToolButtonDragOver := @ToolbarToolButtonDragOver; Result.OnToolItemShortcutsHint := @ToolbarToolItemShortcutsHint; Result.BorderSpacing.Bottom := 2; Result.EdgeInner := esRaised; Result.EdgeOuter := esLowered; Result.EdgeBorders := [ebBottom]; Result.Top := MaxSmallInt; // So that it is put under all existing toolbars (because of Align=alTop). Result.UseItems(Items); Result.Parent := pnToolbars; Result.Tag := pnToolbars.ComponentCount; end; function TfrmOptionsToolbarBase.AddNewSubToolbar(ToolItem: TKASMenuItem; bIncludeButtonOnNewBar:boolean=True): TKASToolBar; begin Result := CreateToolbar(ToolItem.SubItems); if bIncludeButtonOnNewBar then if Result.ButtonCount = 0 then Result.AddButton(TKASCommandItem.Create(FFormCommands)); end; procedure TfrmOptionsToolbarBase.ApplyEditControls; var ToolItem: TKASToolItem; NormalItem: TKASNormalItem; CommandItem: TKASCommandItem; ProgramItem: TKASProgramItem; begin if Assigned(FCurrentButton) then begin ToolItem := FCurrentButton.ToolItem; if ToolItem is TKASSeparatorItem then begin TKASSeparatorItem(ToolItem).Style:= rbSpace.Checked; end; if ToolItem is TKASNormalItem then begin NormalItem := TKASNormalItem(ToolItem); NormalItem.Icon := edtIconFileName.Text; NormalItem.Hint := StringReplace(edtToolTip.Text, '\n', #$0A, [rfReplaceAll]); NormalItem.Text := EmptyStr; end; if ToolItem is TKASCommandItem then begin CommandItem := TKASCommandItem(ToolItem); CommandItem.Command := cbInternalCommand.Text; CommandItem.Params := GetArrayFromStrings(edtInternalParameters.Lines); end; if ToolItem is TKASProgramItem then begin ProgramItem := TKASProgramItem(ToolItem); ProgramItem.Command := edtExternalCommand.Text; ProgramItem.Params := edtExternalParameters.Text; ProgramItem.StartPath := edtStartPath.Text; end; end; end; (*Add new button on tool bar*) procedure TfrmOptionsToolbarBase.btnInsertButtonClick(Sender: TObject); begin pmInsertButtonMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsToolbarBase.btnInternalParametersHelperClick } procedure TfrmOptionsToolbarBase.btnInternalParametersHelperClick(Sender: TObject); begin BringPercentVariablePopupMenu(edtInternalParameters); end; { TfrmOptionsToolbarBase.btnParametersHelperClick } procedure TfrmOptionsToolbarBase.btnParametersHelperClick(Sender: TObject); begin BringPercentVariablePopupMenu(edtExternalParameters); end; { TfrmOptionsToolbarBase.btnOpenCmdDlgClick } procedure TfrmOptionsToolbarBase.btnOpenCmdDlgClick(Sender: TObject); var WantedCommand: String = ''; IndexMaybe:longint; begin if cbInternalCommand.ItemIndex=-1 then begin cbInternalCommand.ItemIndex:=0; cbInternalCommandSelect(cbInternalCommand); end; if ShowMainCommandDlgForm(cbInternalCommand.Items.Strings[cbInternalCommand.ItemIndex],WantedCommand) then begin IndexMaybe:=cbInternalCommand.Items.IndexOf(WantedCommand); if IndexMaybe<>-1 then begin cbInternalCommand.ItemIndex:=IndexMaybe; cbInternalCommandSelect(cbInternalCommand); end; end; end; procedure TfrmOptionsToolbarBase.miInsertButtonClick(Sender: TObject); var ToolBar: TKASToolBar; ToolItem: TKASToolItem = nil; WhereToAdd:longint; IndexWhereToAdd:longint; begin if Assigned(FCurrentButton) then begin ApplyEditControls; ToolBar := FCurrentButton.ToolBar; end else begin ToolBar := GetTopToolbar; end; if Assigned(ToolBar) then begin with Sender as TComponent do begin case ((tag shr 4) and $0F) of 1: ToolItem := TKASSeparatorItem.Create; 2: ToolItem := TKASCommandItem.Create(FFormCommands); 3: ToolItem := TKASProgramItem.Create; 4: ToolItem := TKASMenuItem.Create; end; WhereToAdd:=tag and $0F; end; IndexWhereToAdd:=0; if (ToolBar.ButtonCount=0) then IndexWhereToAdd:=-1; if (IndexWhereToAdd=0) AND (WhereToAdd=4) then IndexWhereToAdd:=-1; if Assigned(FCurrentButton) then begin if (IndexWhereToAdd=0) AND (WhereToAdd=3) AND (FCurrentButton.Tag=pred(ToolBar.ButtonCount)) then IndexWhereToAdd:=-1; if (IndexWhereToAdd=0) AND (WhereToAdd=3) then IndexWhereToAdd:=(FCurrentButton.Tag+1); if (IndexWhereToAdd=0) AND (WhereToAdd=2) then IndexWhereToAdd:=FCurrentButton.Tag; end; if IndexWhereToAdd=-1 then begin //We simply add the button at the end FCurrentButton := ToolBar.AddButton(ToolItem); end else begin //We add the button *after* the current selected button FCurrentButton := ToolBar.InsertButton(IndexWhereToAdd, ToolItem); end; PressButtonDown(FCurrentButton); //Let's speed up process if we can pre-open requester according to what was just inserted as new button with Sender as TComponent do begin case ((tag shr 4) and $0F) of 2: btnOpenCmdDlgClick(btnOpenCmdDlg); 3: btnOpenFileClick(btnOpenFile); end; end; end; end; { TfrmOptionsToolbarBase.miSrcRplClick } procedure TfrmOptionsToolbarBase.miSrcRplClick(Sender: TObject); const SaRMASK_ICON = $01; SaRMASK_COMMAND = $02; SaRMASK_PARAMS = $04; SaRMASK_STARTPATH = $08; var ActionDispatcher, NbOfReplacement:integer; sSearchText, sReplaceText:string; ReplaceFlags: TReplaceFlags; function ReplaceIfNecessary(sWorkingText:string):string; begin result := UTF8StringReplace(sWorkingText, sSearchText, sReplaceText, ReplaceFlags); if result<>sWorkingText then inc(NbOfReplacement); end; procedure PossiblyRecursiveSearchAndReplaceInThisButton(ToolItem: TKASToolItem); var IndexItem, IndexParam: integer; begin if ToolItem is TKASSeparatorItem then begin end; if ToolItem is TKASCommandItem then begin if (ActionDispatcher AND SaRMASK_ICON) <> 0 then TKASCommandItem(ToolItem).Icon:=ReplaceIfNecessary(TKASCommandItem(ToolItem).Icon); if (ActionDispatcher AND SaRMASK_PARAMS) <> 0 then for IndexParam:=0 to pred(length(TKASCommandItem(ToolItem).Params)) do TKASCommandItem(ToolItem).Params[IndexParam]:=ReplaceIfNecessary(TKASCommandItem(ToolItem).Params[IndexParam]); end; if ToolItem is TKASProgramItem then begin if (ActionDispatcher AND SaRMASK_ICON) <> 0 then TKASProgramItem(ToolItem).Icon:=ReplaceIfNecessary(TKASProgramItem(ToolItem).Icon); if (ActionDispatcher AND SaRMASK_COMMAND) <> 0 then TKASProgramItem(ToolItem).Command:=ReplaceIfNecessary(TKASProgramItem(ToolItem).Command); if (ActionDispatcher AND SaRMASK_STARTPATH) <> 0 then TKASProgramItem(ToolItem).StartPath:=ReplaceIfNecessary(TKASProgramItem(ToolItem).StartPath); if (ActionDispatcher AND SaRMASK_PARAMS) <> 0 then TKASProgramItem(ToolItem).Params:=ReplaceIfNecessary(TKASProgramItem(ToolItem).Params); end; if ToolItem is TKASMenuItem then begin if (ActionDispatcher AND SaRMASK_ICON) <> 0 then TKASMenuItem(ToolItem).Icon:=ReplaceIfNecessary(TKASMenuItem(ToolItem).Icon); for IndexItem := 0 to pred(TKASMenuItem(ToolItem).SubItems.Count) do PossiblyRecursiveSearchAndReplaceInThisButton(TKASMenuItem(ToolItem).SubItems[IndexItem]); end; end; var //Placed intentionnally *AFTER* above routine to make sure these variable names are not used in above possibly recursive routines. IndexButton: integer; Toolbar: TKASToolbar; EditSearchOptionToOffer: TEditSearchDialogOption = []; EditSearchOptionReturned: TEditSearchDialogOption = []; CaseSensitive: array[Boolean] of TEditSearchDialogOption = ([eswoCaseSensitiveUnchecked], [eswoCaseSensitiveChecked]); begin with Sender as TComponent do ActionDispatcher:=tag; ApplyEditControls; Application.ProcessMessages; if ((ActionDispatcher AND SaRMASK_ICON) <>0) AND (edtIconFileName.Visible) AND (edtIconFileName.Text<>'') then sSearchText:=edtIconFileName.Text else if ((ActionDispatcher AND SaRMASK_COMMAND) <>0) AND (edtExternalCommand.Visible) AND (edtExternalCommand.Text<>'') then sSearchText:=edtExternalCommand.Text else if ((ActionDispatcher AND SaRMASK_PARAMS) <>0) AND (edtExternalParameters.Visible) AND (edtExternalParameters.Text<>'') then sSearchText:=edtExternalParameters.Text else if ((ActionDispatcher AND SaRMASK_STARTPATH) <>0) AND (edtStartPath.Visible) AND (edtStartPath.Text<>'') then sSearchText:=edtStartPath.Text else if ((ActionDispatcher AND SaRMASK_PARAMS) <>0) AND (edtInternalParameters.Visible) AND (edtInternalParameters.Lines.Count>0) then sSearchText:=edtInternalParameters.Lines.Strings[0] else sSearchText:=''; sReplaceText:=sSearchText; EditSearchOptionToOffer:= CaseSensitive[FileNameCaseSensitive]; if GetSimpleSearchAndReplaceString(self, EditSearchOptionToOffer, sSearchText, sReplaceText, EditSearchOptionReturned, glsSearchPathHistory, glsReplacePathHistory) then begin NbOfReplacement:=0; ReplaceFlags:=[rfReplaceAll]; if eswoCaseSensitiveUnchecked in EditSearchOptionReturned then ReplaceFlags := ReplaceFlags + [rfIgnoreCase]; Toolbar := GetTopToolbar; //Let's scan the current bar! for IndexButton := 0 to pred(Toolbar.ButtonCount) do begin PossiblyRecursiveSearchAndReplaceInThisButton(Toolbar.Buttons[IndexButton].ToolItem); ToolBar.UpdateIcon(Toolbar.Buttons[IndexButton]); end; if NbOfReplacement=0 then begin msgOk(rsZeroReplacement); end else begin if ToolBar.ButtonCount > 0 then PressButtonDown(ToolBar.Buttons[0]); msgOk(format(rsXReplacements,[NbOfReplacement])); end; end; end; procedure TfrmOptionsToolbarBase.btnRelativeExternalCommandClick(Sender: TObject); begin edtExternalCommand.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edtExternalCommand,pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsToolbarBase.btnRelativeIconFileNameClick(Sender: TObject); begin edtIconFileName.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edtIconFileName,pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsToolbarBase.btnRelativeStartPathClick(Sender: TObject); begin edtStartPath.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edtStartPath,pfPATH); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsToolbarBase.btnRemoveHotKeyClick(Sender: TObject); procedure RemoveHotkey(Hotkeys: THotkeys; NormalItem: TKASNormalItem); var Hotkey: THotkey; begin Hotkey := FindHotkey(NormalItem, Hotkeys); Hotkeys.Remove(Hotkey); end; var HMForm: THMForm; ToolItem: TKASToolItem; NormalItem: TKASNormalItem; I: Integer; begin if Assigned(FCurrentButton) then begin ToolItem := FCurrentButton.ToolItem; if ToolItem is TKASNormalItem then begin NormalItem := TKASNormalItem(ToolItem); HMForm := HotMan.Forms.Find('Main'); if Assigned(HMForm) then begin RemoveHotkey(HMForm.Hotkeys, NormalItem); for I := 0 to HMForm.Controls.Count - 1 do RemoveHotkey(HMForm.Controls[I].Hotkeys, NormalItem); end; LoadCurrentButton; FUpdateHotKey:= True; end; end; end; (*Clone selected button on tool bar*) procedure TfrmOptionsToolbarBase.btnCloneButtonClick(Sender: TObject); var SourceItem: TKASToolItem; Button: TKASToolButton; begin if Assigned(FCurrentButton) then begin ApplyEditControls; SourceItem := FCurrentButton.ToolItem; if FCurrentButton.Tag < pred(FCurrentButton.ToolBar.ButtonCount) then Button := FCurrentButton.ToolBar.InsertButton((FCurrentButton.Tag + 1), SourceItem.Clone) else Button := FCurrentButton.ToolBar.AddButton(SourceItem.Clone); PressButtonDown(Button); end; end; (*Remove current button*) procedure TfrmOptionsToolbarBase.btnDeleteButtonClick(Sender: TObject); var NextButton: Integer; ToolBar: TKASToolBar; begin if Assigned(FCurrentButton) then begin ToolBar := FCurrentButton.ToolBar; NextButton := FCurrentButton.Tag; Toolbar.RemoveButton(FCurrentButton); FCurrentButton := nil; if Toolbar.ButtonCount > 0 then begin // Select next button or the last one. if NextButton >= Toolbar.ButtonCount then NextButton := Toolbar.ButtonCount - 1; PressButtonDown(Toolbar.Buttons[NextButton]); end else begin LoadCurrentButton; end; end; end; procedure TfrmOptionsToolbarBase.btnEditHotkeyClick(Sender: TObject); var HMForm: THMForm; TemplateHotkey, Hotkey: THotkey; ToolItem: TKASToolItem; NormalItem: TKASNormalItem; AControls: TDynamicStringArray = nil; I: Integer; begin if Assigned(FCurrentButton) then begin if not Assigned(FEditForm) then FEditForm := TfrmEditHotkey.Create(Self); ToolItem := FCurrentButton.ToolItem; if ToolItem is TKASNormalItem then begin NormalItem := TKASNormalItem(ToolItem); TemplateHotkey := THotkey.Create; try TemplateHotkey.Command := cHotKeyCommand; SetValue(TemplateHotkey.Params, 'ToolBarID', Self.ClassName); SetValue(TemplateHotkey.Params, 'ToolItemID', NormalItem.ID); HMForm := HotMan.Forms.Find('Main'); if Assigned(HMForm) then begin Hotkey := FindHotkey(NormalItem, HMForm.Hotkeys); if Assigned(Hotkey) then TemplateHotkey.Shortcuts := Hotkey.Shortcuts; for I := 0 to HMForm.Controls.Count - 1 do begin Hotkey := FindHotkey(NormalItem, HMForm.Controls[I].Hotkeys); if Assigned(Hotkey) then begin TemplateHotkey.Shortcuts := Hotkey.Shortcuts; AddString(AControls, HMForm.Controls[I].Name); end; end; end; if FEditForm.Execute(True, 'Main', cHotKeyCommand, TemplateHotkey, AControls, [ehoHideParams]) then begin LoadCurrentButton; FUpdateHotKey:= True; end; finally TemplateHotkey.Free; end; end; end; end; procedure TfrmOptionsToolbarBase.btnOpenFileClick(Sender: TObject); begin OpenDialog.DefaultExt:= EmptyStr; OpenDialog.Filter:= EmptyStr; if edtExternalCommand.Text<>'' then OpenDialog.InitialDir:=ExtractFilePath(edtExternalCommand.Text); if OpenDialog.Execute then begin edtExternalCommand.Text := GetToolbarFilenameToSave(tpmeIcon, OpenDialog.FileName); edtStartPath.Text := GetToolbarFilenameToSave(tpmeCommand, ExtractFilePath(OpenDialog.FileName)); edtIconFileName.Text := GetToolbarFilenameToSave(tpmeStartingPath, OpenDialog.FileName); edtToolTip.Text := ExtractOnlyFileName(OpenDialog.FileName); end; end; procedure TfrmOptionsToolbarBase.btnStartPathClick(Sender: TObject); var MaybeResultingOutputPath:string; begin MaybeResultingOutputPath := edtStartPath.Text; if MaybeResultingOutputPath = '' then MaybeResultingOutputPath := frmMain.ActiveFrame.CurrentPath; if SelectDirectory(rsSelectDir, MaybeResultingOutputPath, MaybeResultingOutputPath, False) then edtStartPath.Text := GetToolbarFilenameToSave(tpmeStartingPath, MaybeResultingOutputPath); end; { TfrmOptionsToolbarBase.btnSuggestionTooltipClick } procedure TfrmOptionsToolbarBase.btnSuggestionTooltipClick(Sender: TObject); var sSuggestion : string; iLineIndex, pOriginalSuggestion : integer; begin sSuggestion:=EmptyStr; case rgToolItemType.ItemIndex of 1: //Internal command: Idea is to keep the existing one for the single first line, then add systematically the parameters. begin pOriginalSuggestion:=pos('\n',edtToolTip.Text); if pOriginalSuggestion<>0 then sSuggestion:=leftstr(edtToolTip.Text,pred(pOriginalSuggestion))+'\n----' else sSuggestion:=edtToolTip.Text+'\n----'; if edtInternalParameters.Lines.Count>0 then begin for iLineIndex:=0 to pred(edtInternalParameters.Lines.Count) do sSuggestion:=sSuggestion+'\n'+edtInternalParameters.Lines.Strings[iLineIndex]; end; end; 2://External command: Idea is to keep the existing one for the first line, then add systematically command, parameters and start path, one per line. begin pOriginalSuggestion:=pos(('\n----\n'+StringReplace(lblExternalCommand.Caption, '&', '', [rfReplaceAll])),edtToolTip.Text); if pOriginalSuggestion<>0 then sSuggestion:=leftstr(edtToolTip.Text,pred(pOriginalSuggestion))+'\n----\n' else sSuggestion:=edtToolTip.Text+'\n----\n'; sSuggestion:=sSuggestion+StringReplace(lblExternalCommand.Caption, '&', '', [rfReplaceAll])+' '+edtExternalCommand.Text; if edtExternalParameters.Text<>EmptyStr then sSuggestion:=sSuggestion+'\n'+StringReplace(lblExternalParameters.Caption, '&', '', [rfReplaceAll])+' '+edtExternalParameters.Text; if edtStartPath.Text<>EmptyStr then sSuggestion:=sSuggestion+'\n'+StringReplace(lblStartPath.Caption, '&', '', [rfReplaceAll])+' '+edtStartPath.Text; end; end; if sSuggestion<>EmptyStr then edtToolTip.Text:=sSuggestion; end; procedure TfrmOptionsToolbarBase.cbInternalCommandSelect(Sender: TObject); var Command: String; begin Command := cbInternalCommand.Items[cbInternalCommand.ItemIndex]; edtToolTip.Text := FFormCommands.GetCommandCaption(Command, cctLong); edtIconFileName.Text := UTF8LowerCase(Command); end; procedure TfrmOptionsToolbarBase.CloseToolbarsBelowCurrentButton; var CloseFrom: Integer = 1; i: Integer; begin if Assigned(FCurrentButton) then begin for i := 0 to pnToolbars.ControlCount - 1 do if pnToolbars.Controls[i] = FCurrentButton.ToolBar then begin CloseFrom := i + 1; Break; end; end; for i := pnToolbars.ControlCount - 1 downto CloseFrom do CloseToolbar(i); end; procedure TfrmOptionsToolbarBase.CloseToolbar(Index: Integer); begin if Index > 0 then pnToolbars.Controls[Index].Free; end; procedure TfrmOptionsToolbarBase.cbFlatButtonsChange(Sender: TObject); var i: Integer; ToolBar: TKASToolBar; begin for i := 0 to pnToolbars.ControlCount - 1 do begin ToolBar := pnToolbars.Controls[i] as TKASToolBar; ToolBar.Flat := cbFlatButtons.Checked; end; end; procedure TfrmOptionsToolbarBase.edtIconFileNameChange(Sender: TObject); begin if not FUpdatingIconText then UpdateIcon(edtIconFileName.Text); end; procedure TfrmOptionsToolbarBase.lblHelpOnInternalCommandClick(Sender: TObject); begin ShowHelpForKeywordWithAnchor('/cmds.html#' + cbInternalCommand.Text); end; class function TfrmOptionsToolbarBase.FindHotkey(NormalItem: TKASNormalItem; Hotkeys: THotkeys): THotkey; var i: Integer; AToolBar: Boolean; ToolItemID, ToolBarID: String; begin for i := 0 to Hotkeys.Count - 1 do begin Result := Hotkeys.Items[i]; if (Result.Command = cHotKeyCommand) then begin AToolBar := not GetParamValue(Result.Params, 'ToolBarID', ToolBarID); if not AToolBar then AToolBar := (ToolBarID = Self.ClassName); if (AToolBar) and (GetParamValue(Result.Params, 'ToolItemID', ToolItemID)) and (ToolItemID = NormalItem.ID) then Exit; end; end; Result := nil; end; class function TfrmOptionsToolbarBase.FindHotkey(NormalItem: TKASNormalItem): THotkey; var HMForm: THMForm; i: Integer; begin HMForm := HotMan.Forms.Find('Main'); if Assigned(HMForm) then begin Result := FindHotkey(NormalItem, HMForm.Hotkeys); if not Assigned(Result) then begin for i := 0 to HMForm.Controls.Count - 1 do begin Result := FindHotkey(NormalItem, HMForm.Controls[i].Hotkeys); if Assigned(Result) then Break; end; end; end else Result := nil; end; procedure TfrmOptionsToolbarBase.trbBarSizeChange(Sender: TObject); var ToolBar: TKASToolBar; i: Integer; begin DisableAutoSizing; try lblBarSizeValue.Caption := IntToStr(trbBarSize.Position*2); trbIconSize.Position := trbBarSize.Position - (trbBarSize.Position div 5); for i := 0 to pnToolbars.ControlCount - 1 do begin ToolBar := pnToolbars.Controls[i] as TKASToolBar; ToolBar.SetButtonSize(trbBarSize.Position * 2, trbBarSize.Position * 2); end; finally EnableAutoSizing; end; end; procedure TfrmOptionsToolbarBase.trbIconSizeChange(Sender: TObject); var ToolBar: TKASToolBar; i: Integer; begin DisableAutoSizing; try lblIconSizeValue.Caption := IntToStr(trbIconSize.Position * 2); for i := 0 to pnToolbars.ControlCount - 1 do begin ToolBar := pnToolbars.Controls[i] as TKASToolBar; ToolBar.GlyphSize := trbIconSize.Position * 2; end; finally EnableAutoSizing; end; end; procedure TfrmOptionsToolbarBase.UpdateIcon(Icon: String); var ToolItem: TKASToolItem; NormalItem: TKASNormalItem; begin if Assigned(FCurrentButton) then begin // Refresh icon on the toolbar. ToolItem := FCurrentButton.ToolItem; if ToolItem is TKASNormalItem then begin NormalItem := TKASNormalItem(ToolItem); NormalItem.Icon := Icon; FCurrentButton.ToolBar.UpdateIcon(FCurrentButton); end; end; end; procedure TfrmOptionsToolbarBase.ToolbarDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin // Drag to a different toolbar. Accept := (Source is TKASToolButton) and (TKASToolButton(Source).ToolBar <> Sender); end; procedure TfrmOptionsToolbarBase.ToolbarDragDrop(Sender, Source: TObject; X, Y: Integer); var SourceButton: TKASToolButton; TargetToolbar: TKASToolBar; begin if Source is TKASToolButton then begin SourceButton := Source as TKASToolButton; TargetToolbar := Sender as TKASToolBar; if SourceButton.ToolBar <> TargetToolBar then begin if (SourceButton = FCurrentButton) then FCurrentButton := nil; SourceButton.ToolBar.MoveButton(SourceButton, TargetToolbar, nil); end; end; end; function TfrmOptionsToolbarBase.ToolbarLoadButtonGlyph(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; begin if ToolItem is TKASSeparatorItem then // Paint 'separator' icon begin Result := TBitmap.Create; Result.Transparent := True; Result.TransparentColor := clFuchsia; Result.SetSize(iIconSize, iIconSize); Result.Canvas.Brush.Color:= clFuchsia; Result.Canvas.FillRect(Rect(0,0,iIconSize,iIconSize)); Result.Canvas.Brush.Color:= clBtnText; Result.Canvas.RoundRect(Rect(Round(iIconSize * 0.4), 2, Round(iIconSize * 0.6), iIconSize - 2),iIconSize div 8,iIconSize div 4); end else if ToolItem is TKASNormalItem then Result := PixMapManager.LoadBitmapEnhanced(TKASNormalItem(ToolItem).Icon, iIconSize, True, clBackColor, nil) else Result := nil; end; function TfrmOptionsToolbarBase.ToolbarLoadButtonOverlay(ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap; begin if ToolItem is TKASMenuItem then Result := PixMapManager.LoadBitmapEnhanced('emblem-symbolic-link', iIconSize, True, clBackColor, nil) else Result := nil; end; (*Select button on panel*) procedure TfrmOptionsToolbarBase.ToolbarToolButtonClick(Sender: TObject); var ClickedButton: TKASToolButton; begin ClickedButton := Sender as TKASToolButton; if not FUpdatingButtonType then ApplyEditControls; if Assigned(FCurrentButton) then begin // If current toolbar has changed depress the previous button. if FCurrentButton.ToolBar <> ClickedButton.ToolBar then FCurrentButton.Down := False; end; FCurrentButton := ClickedButton; LoadCurrentButton; end; procedure TfrmOptionsToolbarBase.ToolbarToolButtonDragDrop(Sender, Source: TObject; X, Y: Integer); var SourceButton, TargetButton: TKASToolButton; begin if Source is TKASToolButton then begin SourceButton := Source as TKASToolButton; TargetButton := Sender as TKASToolButton; // Drop to a different toolbar. if SourceButton.ToolBar <> TargetButton.ToolBar then begin SourceButton.ToolBar.MoveButton(SourceButton, TargetButton.ToolBar, TargetButton); end; end; end; (* Move button if it is dragged*) procedure TfrmOptionsToolbarBase.ToolbarToolButtonDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean; NumberOfButton: Integer); var SourceButton, TargetButton: TKASToolButton; begin if Source is TKASToolButton then begin SourceButton := Source as TKASToolButton; TargetButton := Sender as TKASToolButton; // Move on the same toolbar. if SourceButton.ToolBar = TargetButton.ToolBar then begin if FToolDragButtonNumber <> TargetButton.Tag then begin SourceButton.ToolBar.MoveButton(SourceButton.Tag, TargetButton.Tag); FToolDragButtonNumber := TargetButton.Tag; Accept := True; end; end; end; end; (* Do not start drag in here, because oterwise button wouldn't be pushed down*) procedure TfrmOptionsToolbarBase.ToolbarToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FToolButtonMouseX := X; FToolButtonMouseY := Y; end; (* Start dragging only if mbLeft if pressed and mouse moved.*) procedure TfrmOptionsToolbarBase.ToolbarToolButtonMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; NumberOfButton: Integer); var Button: TKASToolButton; begin if Sender is TKASToolButton then begin if (ssLeft in Shift) and (FToolDragButtonNumber = -1) then if (abs(FToolButtonMouseX-X)>10) or (abs(FToolButtonMouseY-Y)>10) then begin Button := TKASToolButton(Sender); FToolDragButtonNumber := NumberOfButton; Button.Toolbar.Buttons[NumberOfButton].BeginDrag(False, 5); end; end; end; (* End button drag*) procedure TfrmOptionsToolbarBase.ToolbarToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FToolDragButtonNumber := -1; end; function TfrmOptionsToolbarBase.ToolbarToolItemShortcutsHint(Sender: TObject; ToolItem: TKASNormalItem): String; begin Result := ShortcutsToText(GetShortcuts(ToolItem)); end; procedure TfrmOptionsToolbarBase.SelectButton(ButtonNumber: Integer); var ToolBar: TKASToolBar; begin if pnToolbars.ControlCount > 0 then begin ToolBar := pnToolbars.Controls[0] as TKASToolBar; if (ButtonNumber >= 0) and (ButtonNumber < Toolbar.ButtonCount) then begin FCurrentButton := Toolbar.Buttons[ButtonNumber]; PressButtonDown(FCurrentButton); end; end; end; { TfrmOptionsToolbarBase.FrameEnter } procedure TfrmOptionsToolbarBase.FrameEnter(Sender: TObject); begin //Tricky pass to don't have the "pnlEditToolbar" being continously resized depending on the button task we're going through. //The idea is to have system arrange for the "CommandItem", which is the taller size one, then freeze size there and keep this way. if bFirstTimeDrawn then begin bFirstTimeDrawn := False; DisplayAppropriateControls(True, True, False); Application.ProcessMessages; pnlEditToolbar.AutoSize := False; LoadCurrentButton; end; end; { TfrmOptionsToolbarBase.ComputeToolbarsSignature } // Routine tries to pickup all char chain from element of toolbar toolbar and compute a unique CRC32. // This CRC32 will bea kind of signature of the toolbar. // We compute the CRC32 at the start of edition and at the end. // If they are different, it's a sign that toolbars have been modified. // It's not "perfect" since it might happen that two different combinaisons will // give the same CRC32 but odds are very good that it will be a different one. function TfrmOptionsToolbarBase.ComputeToolbarsSignature(Seed:dword): dword; const CONSTFORTOOLITEM: array[1..4] of byte = ($23, $35, $28, $DE); procedure RecursiveGetSignature(ToolItem: TKASToolItem; var Result: dword); var IndexToolItem: longint; sInnerParam: string; begin if ToolItem is TKASSeparatorItem then begin Result := crc32(Result, @CONSTFORTOOLITEM[1], 1); Result := crc32(Result, @TKASSeparatorItem(ToolItem).Style, SizeOf(TKASSeparatorItem(ToolItem).Style)); end; if ToolItem is TKASCommandItem then begin Result := crc32(Result, @CONSTFORTOOLITEM[2], 1); if length(TKASCommandItem(ToolItem).Icon) > 0 then Result := crc32(Result, @TKASCommandItem(ToolItem).Icon[1], length(TKASCommandItem(ToolItem).Icon)); if length(TKASCommandItem(ToolItem).Hint) > 0 then Result := crc32(Result, @TKASCommandItem(ToolItem).Hint[1], length(TKASCommandItem(ToolItem).Hint)); if length(TKASCommandItem(ToolItem).Command) > 0 then Result := crc32(Result, @TKASCommandItem(ToolItem).Command[1], length(TKASCommandItem(ToolItem).Command)); for sInnerParam in TKASCommandItem(ToolItem).Params do Result := crc32(Result, @sInnerParam[1], length(sInnerParam)); end; if ToolItem is TKASProgramItem then begin Result := crc32(Result, @CONSTFORTOOLITEM[3], 1); if length(TKASProgramItem(ToolItem).Icon) > 0 then Result := crc32(Result, @TKASProgramItem(ToolItem).Icon[1], length(TKASProgramItem(ToolItem).Icon)); if length(TKASProgramItem(ToolItem).Hint) > 0 then Result := crc32(Result, @TKASProgramItem(ToolItem).Hint[1], length(TKASProgramItem(ToolItem).Hint)); if length(TKASProgramItem(ToolItem).Command) > 0 then Result := crc32(Result, @TKASProgramItem(ToolItem).Command[1], length(TKASProgramItem(ToolItem).Command)); if length(TKASProgramItem(ToolItem).Params) > 0 then Result := crc32(Result, @TKASProgramItem(ToolItem).Params[1], length(TKASProgramItem(ToolItem).Params)); if length(TKASProgramItem(ToolItem).StartPath) > 0 then Result := crc32(Result, @TKASProgramItem(ToolItem).StartPath[1], length(TKASProgramItem(ToolItem).StartPath)); end; if ToolItem is TKASMenuItem then begin Result := crc32(Result, @CONSTFORTOOLITEM[4], 1); if length(TKASMenuItem(ToolItem).Icon) > 0 then Result := crc32(Result, @TKASMenuItem(ToolItem).Icon[1], length(TKASMenuItem(ToolItem).Icon)); if length(TKASMenuItem(ToolItem).Hint) > 0 then Result := crc32(Result, @TKASMenuItem(ToolItem).Hint[1], length(TKASMenuItem(ToolItem).Hint)); for IndexToolItem := 0 to pred(TKASMenuItem(ToolItem).SubItems.Count) do RecursiveGetSignature(TKASMenuItem(ToolItem).SubItems[IndexToolItem], Result); end; end; var IndexButton: longint; Toolbar: TKASToolBar; begin ApplyEditControls; Toolbar := GetTopToolbar; Result := Seed; for IndexButton := 0 to pred(Toolbar.ButtonCount) do RecursiveGetSignature(Toolbar.Buttons[IndexButton].ToolItem, Result); end; { TfrmOptionsToolbarBase.btnExportClick } procedure TfrmOptionsToolbarBase.btnOtherClick(Sender: TObject); begin pmOtherClickToolbar.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmOptionsToolbarBase.miImportAllDCCommandsClick } // Will add on the top toolbar a button giving access to a sub menu with ALL the internal DC internal commands. // This submenu will contain submenus entries, one per internal command category. // This is mainly to help to validate run-time that each command has its own icon and so on. procedure TfrmOptionsToolbarBase.miAddAllCmdsClick(Sender: TObject); var slListCommands: TStringList; AToolbarConfig: TXmlConfig; ToolBarNode, RowNode, AllDCCommandsSubMenuNode, SubMenuNode, CommandCategoryNode, CommandNode: TXmlNode; MenuItemsNode: TXmlNode = nil; // We should preinitialize that one. IndexCommand: integer; bFlagCategoryTitle: boolean = False; sCmdName, sHintName, sHotKey, sCategory: string; ATopToolBar: TKASToolBar; begin slListCommands := TStringList.Create; try // 1. Recuperate the list of all the DC internal commands. FFormCommands.GetCommandsListForACommandCategory(slListCommands, '(' + rsSimpleWordAll + ')', csLegacy); // 2. Create our XML structure to hold all our tree of sub menu and commands. AToolbarConfig := TXmlConfig.Create; try ToolBarNode := AToolbarConfig.FindNode(AToolbarConfig.RootNode, GetNode, True); AToolbarConfig.ClearNode(ToolBarNode); RowNode := AToolbarConfig.AddNode(ToolBarNode, 'Row'); AllDCCommandsSubMenuNode := AToolbarConfig.AddNode(RowNode, 'Menu'); AToolbarConfig.AddValue(AllDCCommandsSubMenuNode, 'ID', GuidToString(DCGetNewGUID)); AToolbarConfig.AddValue(AllDCCommandsSubMenuNode, 'Icon', 'cm_doanycmcommand'); AToolbarConfig.AddValue(AllDCCommandsSubMenuNode, 'Hint', rsMsgAllDCIntCmds); CommandCategoryNode := AToolbarConfig.AddNode(AllDCCommandsSubMenuNode, 'MenuItems'); for IndexCommand := 0 to pred(slListCommands.Count) do begin FFormCommands.ExtractCommandFields(slListCommands.Strings[IndexCommand], sCategory, sCmdName, sHintName, sHotKey, bFlagCategoryTitle); if not bFlagCategoryTitle then begin if MenuItemsNode <> nil then begin CommandNode := AToolbarConfig.AddNode(MenuItemsNode, 'Command'); AToolbarConfig.AddValue(CommandNode, 'ID', GuidToString(DCGetNewGUID)); AToolbarConfig.AddValue(CommandNode, 'Icon', UTF8LowerCase(sCmdName)); AToolbarConfig.AddValue(CommandNode, 'Command', sCmdName); AToolbarConfig.AddValue(CommandNode, 'Hint', sHintName); end; end else begin SubMenuNode := AToolbarConfig.AddNode(CommandCategoryNode, 'Menu'); AToolbarConfig.AddValue(SubMenuNode, 'ID', GuidToString(DCGetNewGUID)); AToolbarConfig.AddValue(SubMenuNode, 'Hint', sCmdName); //Let's take icon of first command of the category for the subtoolbar icon for this "new" category FFormCommands.ExtractCommandFields(slListCommands.Strings[IndexCommand + 1], sCategory, sCmdName, sHintName, sHotKey, bFlagCategoryTitle); AToolbarConfig.AddValue(SubMenuNode, 'Icon', UTF8LowerCase(sCmdName)); MenuItemsNode := AToolbarConfig.AddNode(SubMenuNode, 'MenuItems'); end; end; // 3. Now, we import our structure and at once, bang! we'll have added our bar and sub ones. ATopToolBar := GetTopToolbar; ToolBarNode := AToolbarConfig.FindNode(AToolbarConfig.RootNode, GetNode, False); if ToolBarNode <> nil then begin LoadToolbar(ATopToolBar, AToolbarConfig, ToolBarNode, tocl_AddToCurrentToolbarContent); if ATopToolBar.ButtonCount > 0 then PressButtonDown(ATopToolBar.Buttons[pred(ATopToolBar.ButtonCount)]); //Let's press the last added button since user might wants to complement what he just added end; finally FreeAndNil(AToolbarConfig); end; finally slListCommands.Free; end; end; { TfrmOptionsToolbarBase.miExportToAnythingClick } procedure TfrmOptionsToolbarBase.miExportToAnythingClick(Sender: TObject); var ToolbarConfig: TXmlConfig; FlagKeepGoing: boolean = False; BackupPath: string; ToolBarNode: TXmlNode; ToolBar: TKASToolBar; InnerResult: boolean = False; ActionDispatcher: integer; begin with Sender as TComponent do ActionDispatcher := tag; //1. Make we got an invalid name from the start SaveDialog.Filename := ''; //2. Let's determine from which which level of toolbar we need to export ToolBar := GetTopToolbar; if (ActionDispatcher and MASK_ACTION_TOOLBAR) = ACTION_WITH_CURRENT_BAR then begin if Assigned(FCurrentButton) then begin ApplyEditControls; ToolBar := FCurrentButton.ToolBar; end; end; if Assigned(ToolBar) then begin //3. Let's get a filename for the export case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of ACTION_WITH_DC_TOOLBARFILE: begin SaveDialog.DefaultExt := '*.toolbar'; SaveDialog.FilterIndex := 1; SaveDialog.Title := rsMsgDCToolbarWhereToSave; SaveDialog.FileName := 'New DC Toolbar filename'; FlagKeepGoing := SaveDialog.Execute; end; ACTION_WITH_BACKUP: begin BackupPath := IncludeTrailingPathDelimiter(mbExpandFileName(EnvVarConfigPath)) + 'Backup'; if mbForceDirectory(BackupPath) then begin SaveDialog.Filename := BackupPath + DirectorySeparator + 'Backup_' + GetDateTimeInStrEZSortable(now) + '.toolbar'; FlagKeepGoing := True; end; end; {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI: begin if areWeInSituationToPlayWithTCFiles then begin SaveDialog.Filename := sTotalCommanderMainbarFilename; FlagKeepGoing := True; end; end; ACTION_WITH_TC_TOOLBARFILE: begin SaveDialog.DefaultExt := '*.BAR'; SaveDialog.FilterIndex := 2; SaveDialog.Title := rsMsgTCToolbarWhereToSave; SaveDialog.FileName := 'New TC Toolbar filename'; SaveDialog.InitialDir := ExcludeTrailingPathDelimiter(mbExpandFilename(gTotalCommanderToolbarPath)); FlagKeepGoing := SaveDialog.Execute; if FlagKeepGoing then FlagKeepGoing := areWeInSituationToPlayWithTCFiles; end; {$ENDIF} end; //4. Let's do the actual exportation if FlagKeepGoing and (SaveDialog.Filename <> '') then begin case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of //If it's DC format, let's save the XML in regular fashion. ACTION_WITH_DC_TOOLBARFILE, ACTION_WITH_BACKUP: begin ToolbarConfig := TXmlConfig.Create(SaveDialog.Filename); try ToolBarNode := ToolbarConfig.FindNode(ToolbarConfig.RootNode, GetNode, True); ToolbarConfig.ClearNode(ToolBarNode); ToolBar.SaveConfiguration(ToolbarConfig, ToolBarNode); InnerResult := ToolbarConfig.Save; finally FreeAndNil(ToolbarConfig); end; end; {$IFDEF MSWINDOWS} //If it's TC format, we first create the necessary .BAR files. //If requested, we also update the Wincmd.ini file. ACTION_WITH_WINCMDINI, ACTION_WITH_TC_TOOLBARFILE: begin ExportDCToolbarsToTC(Toolbar,SaveDialog.Filename,((ActionDispatcher and MASK_FLUSHORNOT_EXISTING) = ACTION_FLUSH_EXISTING), ((actionDispatcher and MASK_ACTION_WITH_WHAT) = ACTION_WITH_WINCMDINI) ); InnerResult := True; end; {$ENDIF} end; end; if InnerResult then msgOK(Format(rsMsgToolbarSaved, [SaveDialog.Filename])); end; end; { TfrmOptionsToolbarBase.miImportFromAnythingClick } // We can import elements to DC toolbar... // FROM... // -a previously exported DC .toolbar file // -a previously backuped DC .toolbar file // -the TC toolbar and subtoolbar right from the main toolbar in TC // -a specified TC toolbar file // TO... // -replace the top toolbar in DC // -extend the top toolbar in DC // -a subtoolbar of the top toolbar in DC // -replace the current selected toolbar in DC // -extend the current selected toolbar in DC // -a subtoolbar of the current selected in DC procedure TfrmOptionsToolbarBase.miImportFromAnythingClick(Sender: TObject); var ActionDispatcher: longint; FlagKeepGoing: boolean = False; BackupPath, ImportedToolbarHint: string; ImportDestination: byte; ToolBar: TKASToolBar; LocalKASMenuItem: TKASMenuItem; ToolbarConfig: TXmlConfig; ToolBarNode: TXmlNode; begin with Sender as TComponent do ActionDispatcher := tag; //1o) Make sure we got the the filename to import into "OpenDialog.Filename" variable. case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI: begin if areWeInSituationToPlayWithTCFiles then begin OpenDialog.Filename := sTotalCommanderMainbarFilename; ImportedToolbarHint := rsDefaultImportedTCToolbarHint; FlagKeepGoing := True; end; end; ACTION_WITH_TC_TOOLBARFILE: begin if areWeInSituationToPlayWithTCFiles then begin OpenDialog.DefaultExt := '*.BAR'; OpenDialog.FilterIndex := 3; OpenDialog.Title := rsMsgToolbarLocateTCToolbarFile; ImportedToolbarHint := rsDefaultImportedTCToolbarHint; FlagKeepGoing := OpenDialog.Execute; end; end; {$ENDIF} ACTION_WITH_DC_TOOLBARFILE: begin OpenDialog.DefaultExt := '*.toolbar'; OpenDialog.FilterIndex := 1; OpenDialog.Title := rsMsgToolbarLocateDCToolbarFile; ImportedToolbarHint := rsDefaultImportedDCToolbarHint; FlagKeepGoing := OpenDialog.Execute; end; ACTION_WITH_BACKUP: begin BackupPath := IncludeTrailingPathDelimiter(mbExpandFileName(EnvVarConfigPath)) + 'Backup'; if mbForceDirectory(BackupPath) then begin OpenDialog.DefaultExt := '*.toolbar'; OpenDialog.FilterIndex := 1; OpenDialog.InitialDir := ExcludeTrailingPathDelimiter(BackupPath); OpenDialog.Title := rsMsgToolbarRestoreWhat; ImportedToolbarHint := rsDefaultImportedDCToolbarHint; FlagKeepGoing := OpenDialog.Execute; end; end; end; //2o) If we got something valid, let's attempt to import it! if FlagKeepGoing then begin //3o) Let's make "Toolbar" hold the toolbar where to import in. ImportDestination := (ActionDispatcher and MASK_IMPORT_DESTIONATION); ImportDestination := ImportDestination shr 4; case ImportDestination of ACTION_WITH_MAIN_TOOLBAR: begin ToolBar := GetTopToolbar; end; ACTION_WITH_CURRENT_BAR: begin if Assigned(FCurrentButton) then Toolbar := FCurrentButton.ToolBar; if Toolbar = nil then ToolBar := GetTopToolbar; end; IMPORT_IN_MAIN_TOOLBAR_TO_NEW_SUB_BAR, IMPORT_IN_CURRENT_BAR_TO_NEW_SUB_BAR: begin case ImportDestination of IMPORT_IN_MAIN_TOOLBAR_TO_NEW_SUB_BAR: begin FCurrentButton := nil; ToolBar := GetTopToolbar; CloseToolbarsBelowCurrentButton; end; IMPORT_IN_CURRENT_BAR_TO_NEW_SUB_BAR: begin if Assigned(FCurrentButton) then Toolbar := FCurrentButton.ToolBar; if Toolbar = nil then ToolBar := GetTopToolbar; end; end; if FCurrentButton <> nil then FCurrentButton.Down := False; LocalKASMenuItem := TKASMenuItem.Create; LocalKASMenuItem.Icon := 'cm_configtoolbars'; LocalKASMenuItem.Hint := ImportedToolbarHint; FCurrentButton := ToolBar.AddButton(LocalKASMenuItem); Toolbar := AddNewSubToolbar(LocalKASMenuItem, False); end; end; //4o) Let's attempt the actual import case (ActionDispatcher and MASK_ACTION_WITH_WHAT) of {$IFDEF MSWINDOWS} ACTION_WITH_WINCMDINI, ACTION_WITH_TC_TOOLBARFILE: begin ToolbarConfig := TXmlConfig.Create; try ConvertTCToolbarToDCXmlConfig(OpenDialog.FileName, ToolbarConfig); ToolBarNode := ToolbarConfig.FindNode(ToolbarConfig.RootNode, GetNode, False); if ToolBarNode <> nil then begin FCurrentButton := nil; if (ActionDispatcher and MASK_FLUSHORNOT_EXISTING) = ACTION_FLUSH_EXISTING then LoadToolbar(ToolBar, ToolbarConfig, ToolBarNode, tocl_FlushCurrentToolbarContent) else LoadToolbar(ToolBar, ToolbarConfig, ToolBarNode, tocl_AddToCurrentToolbarContent); if ToolBar.ButtonCount > 0 then PressButtonDown(ToolBar.Buttons[pred(ToolBar.ButtonCount)]); //Let's press the last added button since user might wants to complement what he just added end; finally FreeAndNil(ToolbarConfig); end; end; {$ENDIF} ACTION_WITH_DC_TOOLBARFILE, ACTION_WITH_BACKUP: begin ToolbarConfig := TXmlConfig.Create(OpenDialog.FileName, True); try ToolBarNode := ToolbarConfig.FindNode(ToolbarConfig.RootNode, GetNode, False); if ToolBarNode <> nil then begin FCurrentButton := nil; if (ActionDispatcher and MASK_FLUSHORNOT_EXISTING) = ACTION_FLUSH_EXISTING then LoadToolbar(ToolBar, ToolbarConfig, ToolBarNode, tocl_FlushCurrentToolbarContent) else LoadToolbar(ToolBar, ToolbarConfig, ToolBarNode, tocl_AddToCurrentToolbarContent); if ToolBar.ButtonCount > 0 then PressButtonDown(ToolBar.Buttons[pred(ToolBar.ButtonCount)]); //Let's press the last added button since user might wants to complement what he just added end; finally FreeAndNil(ToolbarConfig); end; end; end; end; end; procedure TfrmOptionsToolbarBase.ScanToolbarForFilenameAndPath(Toolbar: TKASToolbar); procedure PossiblyRecursiveAddThisToolItemToConfigFile(ToolItem: TKASToolItem); var IndexItem: integer; begin if ToolItem is TKASProgramItem then begin TKASProgramItem(ToolItem).Icon := GetToolbarFilenameToSave(tpmeIcon, TKASProgramItem(ToolItem).Icon); TKASProgramItem(ToolItem).Command := GetToolbarFilenameToSave(tpmeCommand, TKASProgramItem(ToolItem).Command); TKASProgramItem(ToolItem).StartPath := GetToolbarFilenameToSave(tpmeStartingPath, TKASProgramItem(ToolItem).StartPath); end else if ToolItem is TKASCommandItem then begin //In the rare unexpected case that someone would use internal command with an icon file from somewhere else... TKASCommandItem(ToolItem).Icon := GetToolbarFilenameToSave(tpmeIcon, TKASCommandItem(ToolItem).Icon); end else if ToolItem is TKASMenuItem then begin TKASMenuItem(ToolItem).Icon := GetToolbarFilenameToSave(tpmeIcon, TKASMenuItem(ToolItem).Icon); for IndexItem := 0 to pred(TKASMenuItem(ToolItem).SubItems.Count) do PossiblyRecursiveAddThisToolItemToConfigFile(TKASMenuItem(ToolItem).SubItems[IndexItem]); end else if ToolItem is TKASSeparatorItem then begin end; end; var //Placed intentionnally *AFTER* above routine to make sure these variable names are not used in above possibly recursive routines. IndexButton: integer; begin for IndexButton := 0 to pred(Toolbar.ButtonCount) do PossiblyRecursiveAddThisToolItemToConfigFile(Toolbar.Buttons[IndexButton].ToolItem); end; { GetToolbarFilenameToSave } function GetToolbarFilenameToSave(AToolbarPathModifierElement: tToolbarPathModifierElement; sParamFilename: string): string; var sMaybeBasePath, SubWorkingPath, MaybeSubstitionPossible: string; begin sParamFilename := mbExpandFileName(sParamFilename); Result := sParamFilename; if AToolbarPathModifierElement in gToolbarPathModifierElements then begin sMaybeBasePath := IfThen((gToolbarFilenameStyle = pfsRelativeToDC), EnvVarCommanderPath, gToolbarPathToBeRelativeTo); case gToolbarFilenameStyle of pfsAbsolutePath: ; pfsRelativeToDC, pfsRelativeToFollowingPath: begin SubWorkingPath := IncludeTrailingPathDelimiter(mbExpandFileName(sMaybeBasePath)); MaybeSubstitionPossible := ExtractRelativePath(IncludeTrailingPathDelimiter(SubWorkingPath), sParamFilename); if MaybeSubstitionPossible <> sParamFilename then Result := IncludeTrailingPathDelimiter(sMaybeBasePath) + MaybeSubstitionPossible; end; end; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarextra.lfm������������������������������������������������0000644�0001750�0000144�00000016740�14743153644�021652� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsToolbarExtra: TfrmOptionsToolbarExtra Height = 573 Width = 850 HelpKeyword = '/configuration.html#ConfigToolbarEx' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 573 ClientWidth = 850 DesignLeft = 221 DesignTop = 229 object gbToolbarOptionsExtra: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 161 Top = 6 Width = 838 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Paths' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 2 ChildSizing.VerticalSpacing = 6 ClientHeight = 141 ClientWidth = 834 TabOrder = 0 object lbToolbarFilenameStyle: TLabel AnchorSideLeft.Control = gbToolbarOptionsExtra AnchorSideTop.Control = gbToolbarOptionsExtra Left = 6 Height = 15 Top = 6 Width = 426 Caption = 'Way to set paths when adding elements for icons, commands and starting paths:' ParentColor = False end object cbToolbarFilenameStyle: TComboBox AnchorSideLeft.Control = lbToolbarFilenameStyle AnchorSideTop.Control = lbToolbarFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbToolbarOptionsExtra AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 27 Width = 822 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 OnChange = cbToolbarFilenameStyleChange Style = csDropDownList TabOrder = 0 end object btnPathToBeRelativeToHelper: TSpeedButton AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideRight.Control = cbToolbarFilenameStyle AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = dePathToBeRelativeTo AnchorSideBottom.Side = asrBottom Left = 805 Height = 23 Top = 56 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnPathToBeRelativeToHelperClick end object dePathToBeRelativeTo: TDirectoryEdit AnchorSideLeft.Control = lbPathToBeRelativeTo AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbToolbarFilenameStyle AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnPathToBeRelativeToHelper Left = 120 Height = 23 Top = 56 Width = 683 ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 1 MaxLength = 0 TabOrder = 1 end object lbPathToBeRelativeTo: TLabel AnchorSideLeft.Control = lbToolbarFilenameStyle AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 60 Width = 112 Caption = 'Path to be relative to:' ParentColor = False end object btnPathToBeRelativeToAll: TButton AnchorSideLeft.Control = lbToolbarFilenameStyle AnchorSideTop.Control = ckbToolbarIcons AnchorSideTop.Side = asrBottom Left = 6 Height = 25 Top = 110 Width = 341 AutoSize = True Caption = 'Apply current settings to all configured filenames and paths' OnClick = btnPathToBeRelativeToAllClick TabOrder = 2 end object ckbToolbarIcons: TCheckBox AnchorSideLeft.Control = lblApplySettingsFor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 167 Height = 19 Top = 85 Width = 48 BorderSpacing.Left = 6 Caption = 'Icons' TabOrder = 3 end object lblApplySettingsFor: TLabel AnchorSideLeft.Control = lbToolbarFilenameStyle AnchorSideTop.Control = ckbToolbarIcons AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 87 Width = 155 Caption = 'Do this for files and paths for:' ParentColor = False end object ckbToolbarCommand: TCheckBox AnchorSideLeft.Control = ckbToolbarIcons AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 221 Height = 19 Top = 85 Width = 82 BorderSpacing.Left = 6 Caption = 'Commands' TabOrder = 4 end object ckbToolbarStartPath: TCheckBox AnchorSideLeft.Control = ckbToolbarCommand AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = dePathToBeRelativeTo AnchorSideTop.Side = asrBottom Left = 309 Height = 19 Top = 85 Width = 93 BorderSpacing.Left = 6 Caption = 'Starting paths' TabOrder = 5 end end object pmPathToBeRelativeToHelper: TPopupMenu[1] left = 568 top = 112 end end ��������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarextra.lrj������������������������������������������������0000644�0001750�0000144�00000003637�14743153644�021664� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":5671667,"name":"tfrmoptionstoolbarextra.gbtoolbaroptionsextra.caption","sourcebytes":[80,97,116,104,115],"value":"Paths"}, {"hash":75021338,"name":"tfrmoptionstoolbarextra.lbtoolbarfilenamestyle.caption","sourcebytes":[87,97,121,32,116,111,32,115,101,116,32,112,97,116,104,115,32,119,104,101,110,32,97,100,100,105,110,103,32,101,108,101,109,101,110,116,115,32,102,111,114,32,105,99,111,110,115,44,32,99,111,109,109,97,110,100,115,32,97,110,100,32,115,116,97,114,116,105,110,103,32,112,97,116,104,115,58],"value":"Way to set paths when adding elements for icons, commands and starting paths:"}, {"hash":256553386,"name":"tfrmoptionstoolbarextra.lbpathtoberelativeto.caption","sourcebytes":[80,97,116,104,32,116,111,32,98,101,32,114,101,108,97,116,105,118,101,32,116,111,58],"value":"Path to be relative to:"}, {"hash":163913811,"name":"tfrmoptionstoolbarextra.btnpathtoberelativetoall.caption","sourcebytes":[65,112,112,108,121,32,99,117,114,114,101,110,116,32,115,101,116,116,105,110,103,115,32,116,111,32,97,108,108,32,99,111,110,102,105,103,117,114,101,100,32,102,105,108,101,110,97,109,101,115,32,97,110,100,32,112,97,116,104,115],"value":"Apply current settings to all configured filenames and paths"}, {"hash":5219923,"name":"tfrmoptionstoolbarextra.ckbtoolbaricons.caption","sourcebytes":[73,99,111,110,115],"value":"Icons"}, {"hash":47274650,"name":"tfrmoptionstoolbarextra.lblapplysettingsfor.caption","sourcebytes":[68,111,32,116,104,105,115,32,102,111,114,32,102,105,108,101,115,32,97,110,100,32,112,97,116,104,115,32,102,111,114,58],"value":"Do this for files and paths for:"}, {"hash":105086995,"name":"tfrmoptionstoolbarextra.ckbtoolbarcommand.caption","sourcebytes":[67,111,109,109,97,110,100,115],"value":"Commands"}, {"hash":67051795,"name":"tfrmoptionstoolbarextra.ckbtoolbarstartpath.caption","sourcebytes":[83,116,97,114,116,105,110,103,32,112,97,116,104,115],"value":"Starting paths"} ]} �������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarextra.pas������������������������������������������������0000644�0001750�0000144�00000011766�14743153644�021662� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Toolbar configuration for extra options page Copyright (C) 2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsToolbarExtra; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Buttons, Menus, EditBtn, //DC fOptionsFrame; type { TfrmOptionsToolbarExtra } TfrmOptionsToolbarExtra = class(TOptionsEditor) btnPathToBeRelativeToAll: TButton; btnPathToBeRelativeToHelper: TSpeedButton; cbToolbarFilenameStyle: TComboBox; ckbToolbarIcons: TCheckBox; ckbToolbarCommand: TCheckBox; ckbToolbarStartPath: TCheckBox; dePathToBeRelativeTo: TDirectoryEdit; gbToolbarOptionsExtra: TGroupBox; lblApplySettingsFor: TLabel; lbPathToBeRelativeTo: TLabel; lbToolbarFilenameStyle: TLabel; pmPathToBeRelativeToHelper: TPopupMenu; procedure btnPathToBeRelativeToAllClick(Sender: TObject); procedure btnPathToBeRelativeToHelperClick(Sender: TObject); procedure cbToolbarFilenameStyleChange(Sender: TObject); private protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. //DC uGlobs, uLng, DCStrUtils, fOptions, fOptionsToolbar, uSpecialDir; procedure TfrmOptionsToolbarExtra.Init; begin ParseLineToList(rsPluginFilenameStyleList, cbToolbarFilenameStyle.Items); end; procedure TfrmOptionsToolbarExtra.Load; begin cbToolbarFilenameStyle.ItemIndex := integer(gToolbarFilenameStyle); cbToolbarFilenameStyleChange(cbToolbarFilenameStyle); dePathToBeRelativeTo.Text := gToolbarPathToBeRelativeTo; ckbToolbarIcons.Checked := tpmeIcon in gToolbarPathModifierElements; ckbToolbarCommand.Checked := tpmeCommand in gToolbarPathModifierElements; ckbToolbarStartPath.Checked := tpmeStartingPath in gToolbarPathModifierElements; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathToBeRelativeToHelper, mp_PATHHELPER, nil); end; function TfrmOptionsToolbarExtra.Save: TOptionsEditorSaveFlags; begin gToolbarFilenameStyle := TConfigFilenameStyle(cbToolbarFilenameStyle.ItemIndex); gToolbarPathToBeRelativeTo := dePathToBeRelativeTo.Text; gToolbarPathModifierElements := []; if ckbToolbarIcons.Checked then gToolbarPathModifierElements := gToolbarPathModifierElements + [tpmeIcon]; if ckbToolbarCommand.Checked then gToolbarPathModifierElements := gToolbarPathModifierElements + [tpmeCommand]; if ckbToolbarStartPath.Checked then gToolbarPathModifierElements := gToolbarPathModifierElements + [tpmeStartingPath]; Result := []; end; class function TfrmOptionsToolbarExtra.GetIconIndex: integer; begin Result := 32; end; class function TfrmOptionsToolbarExtra.GetTitle: string; begin Result := rsOptionsEditorToolbarExtra; end; procedure TfrmOptionsToolbarExtra.cbToolbarFilenameStyleChange(Sender: TObject); begin lbPathToBeRelativeTo.Visible := (TConfigFilenameStyle(cbToolbarFilenameStyle.ItemIndex) = TConfigFilenameStyle.pfsRelativeToFollowingPath); dePathToBeRelativeTo.Visible := lbPathToBeRelativeTo.Visible; btnPathToBeRelativeToHelper.Visible := lbPathToBeRelativeTo.Visible; end; procedure TfrmOptionsToolbarExtra.btnPathToBeRelativeToAllClick(Sender: TObject); var Options: IOptionsDialog; Editor: TOptionsEditor; begin Self.SaveSettings; //Call "SaveSettings" instead of just "Save" to get option signature set right away do we don't bother user for that page when close. Options := ShowOptions(TfrmOptionsToolbar); Editor := Options.GetEditor(TfrmOptionsToolbar); TfrmOptionsToolbar(Editor).ScanToolbarForFilenameAndPath(TfrmOptionsToolbar(Editor).TopToolbar); TfrmOptionsToolbar(Editor).RefrechCurrentButton; ShowOptions(TfrmOptionsToolbar); end; procedure TfrmOptionsToolbarExtra.btnPathToBeRelativeToHelperClick(Sender: TObject); begin dePathToBeRelativeTo.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(dePathToBeRelativeTo, pfPATH); pmPathToBeRelativeToHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; end. ����������doublecmd-1.1.22/src/frames/foptionstoolbarmiddle.lfm�����������������������������������������������0000644�0001750�0000144�00000000167�14743153644�021761� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsToolbarMiddle: TfrmOptionsToolbarMiddle HelpKeyword = '/configuration.html#ConfigToolbar' end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbarmiddle.pas�����������������������������������������������0000644�0001750�0000144�00000005530�14743153644�021765� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fOptionsToolbarMiddle; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, fOptionsFrame, fOptionsToolbarBase; type { TfrmOptionsToolbarMiddle } TfrmOptionsToolbarMiddle = class(TfrmOptionsToolbarBase) private protected procedure Load; override; class function GetNode: String; override; function Save: TOptionsEditorSaveFlags; override; public constructor Create(TheOwner: TComponent); override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses KASToolBar, DCXmlConfig, uGlobs, uGlobsPaths, uSpecialDir, uLng; { TfrmOptionsToolbarMiddle } procedure TfrmOptionsToolbarMiddle.Load; var ToolBarNode: TXmlNode; ToolBar: TKASToolBar; begin trbBarSize.Position := gMiddleToolBarButtonSize div 2; trbIconSize.Position := gMiddleToolBarIconSize div 2; cbFlatButtons.Checked := gMiddleToolBarFlat; cbShowCaptions.Checked := gMiddleToolBarShowCaptions; cbReportErrorWithCommands.Checked := gMiddleToolbarReportErrorWithCommands; lblBarSizeValue.Caption := IntToStr(trbBarSize.Position*2); lblIconSizeValue.Caption := IntToStr(trbIconSize.Position*2); FCurrentButton := nil; CloseToolbarsBelowCurrentButton; ToolBar := GetTopToolbar; ToolBarNode := gConfig.FindNode(gConfig.RootNode, GetNode, False); LoadToolbar(ToolBar, gConfig, ToolBarNode, tocl_FlushCurrentToolbarContent); if ToolBar.ButtonCount > 0 then PressButtonDown(ToolBar.Buttons[0]); gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper,mp_PATHHELPER,nil); FUpdateHotKey := False; end; class function TfrmOptionsToolbarMiddle.GetNode: String; begin Result:= 'Toolbars/MiddleToolbar'; end; function TfrmOptionsToolbarMiddle.Save: TOptionsEditorSaveFlags; var ToolBarNode: TXmlNode; ToolBar: TKASToolBar; begin ApplyEditControls; gMiddleToolBarFlat := cbFlatButtons.Checked; gMiddleToolBarShowCaptions := cbShowCaptions.Checked; gMiddleToolbarReportErrorWithCommands := cbReportErrorWithCommands.Checked; gMiddleToolBarButtonSize := trbBarSize.Position * 2; gMiddleToolBarIconSize := trbIconSize.Position * 2; ToolBar := GetTopToolbar; if Assigned(ToolBar) then begin ToolBarNode := gConfig.FindNode(gConfig.RootNode, GetNode, True); gConfig.ClearNode(ToolBarNode); Toolbar.SaveConfiguration(gConfig, ToolBarNode); end; if FUpdateHotKey then begin FUpdateHotKey := False; HotMan.Save(gpCfgDir + gNameSCFile); end; Result := []; end; constructor TfrmOptionsToolbarMiddle.Create(TheOwner: TComponent); begin inherited Create(TheOwner); Name := 'frmOptionsToolbarMiddle'; end; class function TfrmOptionsToolbarMiddle.GetTitle: String; begin Result:= rsOptionsEditorToolbarMiddle; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbase.lfm����������������������������������������������������0000644�0001750�0000144�00000013404�14743153644�020746� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsToolBase: TfrmOptionsToolBase Height = 265 Width = 589 Anchors = [akTop] ClientHeight = 265 ClientWidth = 589 DesignLeft = 382 DesignTop = 371 object edtToolsParameters: TEdit[0] AnchorSideLeft.Control = lblToolsParameters AnchorSideTop.Control = lblToolsParameters AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeToolPath AnchorSideRight.Side = asrBottom Left = 8 Height = 23 Top = 113 Width = 571 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 OnChange = edtToolsParametersChange TabOrder = 2 end object fneToolsPath: TFileNameEdit[1] AnchorSideLeft.Control = lblToolsPath AnchorSideTop.Control = lblToolsPath AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeToolPath Left = 8 Height = 23 Top = 61 Width = 547 OnAcceptFileName = fneToolsPathAcceptFileName DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 MaxLength = 0 TabOrder = 1 OnChange = fneToolsPathChange end object lblToolsPath: TLabel[2] AnchorSideLeft.Control = cbToolsUseExternalProgram AnchorSideTop.Control = cbToolsUseExternalProgram AnchorSideTop.Side = asrBottom Left = 8 Height = 15 Top = 42 Width = 144 BorderSpacing.Top = 15 Caption = '&Path to program to execute' FocusControl = fneToolsPath ParentColor = False end object lblToolsParameters: TLabel[3] AnchorSideLeft.Control = cbToolsUseExternalProgram AnchorSideTop.Control = fneToolsPath AnchorSideTop.Side = asrBottom Left = 8 Height = 15 Top = 94 Width = 117 BorderSpacing.Top = 10 Caption = 'A&dditional parameters' FocusControl = edtToolsParameters ParentColor = False end object cbToolsKeepTerminalOpen: TCheckBox[4] AnchorSideLeft.Control = cbToolsRunInTerminal AnchorSideTop.Control = cbToolsRunInTerminal AnchorSideTop.Side = asrBottom Left = 23 Height = 19 Top = 169 Width = 298 BorderSpacing.Left = 15 BorderSpacing.Top = 2 Caption = '&Keep terminal window open after executing program' OnChange = cbToolsKeepTerminalOpenChange TabOrder = 4 end object cbToolsRunInTerminal: TCheckBox[5] AnchorSideLeft.Control = edtToolsParameters AnchorSideTop.Control = edtToolsParameters AnchorSideTop.Side = asrBottom Left = 8 Height = 19 Top = 148 Width = 120 BorderSpacing.Top = 12 Caption = '&Execute in terminal' OnChange = cbToolsRunInTerminalChange TabOrder = 3 end object cbToolsUseExternalProgram: TCheckBox[6] Left = 8 Height = 19 Top = 8 Width = 132 BorderSpacing.Top = 12 Caption = '&Use external program' OnChange = cbToolsUseExternalProgramChange TabOrder = 0 end object btnRelativeToolPath: TSpeedButton[7] AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fneToolsPath AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fneToolsPath AnchorSideBottom.Side = asrBottom Left = 555 Height = 23 Hint = 'Some functions to select appropriate path' Top = 61 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeToolPathClick end object pmPathHelper: TPopupMenu[8] left = 544 top = 88 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolbase.lrj����������������������������������������������������0000644�0001750�0000144�00000002747�14743153644�020767� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":80679221,"name":"tfrmoptionstoolbase.lbltoolspath.caption","sourcebytes":[38,80,97,116,104,32,116,111,32,112,114,111,103,114,97,109,32,116,111,32,101,120,101,99,117,116,101],"value":"&Path to program to execute"}, {"hash":215293683,"name":"tfrmoptionstoolbase.lbltoolsparameters.caption","sourcebytes":[65,38,100,100,105,116,105,111,110,97,108,32,112,97,114,97,109,101,116,101,114,115],"value":"A&dditional parameters"}, {"hash":177722141,"name":"tfrmoptionstoolbase.cbtoolskeepterminalopen.caption","sourcebytes":[38,75,101,101,112,32,116,101,114,109,105,110,97,108,32,119,105,110,100,111,119,32,111,112,101,110,32,97,102,116,101,114,32,101,120,101,99,117,116,105,110,103,32,112,114,111,103,114,97,109],"value":"&Keep terminal window open after executing program"}, {"hash":118910428,"name":"tfrmoptionstoolbase.cbtoolsruninterminal.caption","sourcebytes":[38,69,120,101,99,117,116,101,32,105,110,32,116,101,114,109,105,110,97,108],"value":"&Execute in terminal"}, {"hash":26702445,"name":"tfrmoptionstoolbase.cbtoolsuseexternalprogram.caption","sourcebytes":[38,85,115,101,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109],"value":"&Use external program"}, {"hash":15252584,"name":"tfrmoptionstoolbase.btnrelativetoolpath.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"} ]} �������������������������doublecmd-1.1.22/src/frames/foptionstoolbase.pas����������������������������������������������������0000644�0001750�0000144�00000013025�14743153644�020752� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Base options page for external tools (Viewer, Editor, Differ) Copyright (C) 2006-2015 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsToolBase; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, StdCtrls, EditBtn, Buttons, Menus, fOptionsFrame, uGlobs; type { TfrmOptionsToolBase } TfrmOptionsToolBase = class(TOptionsEditor) btnRelativeToolPath: TSpeedButton; cbToolsKeepTerminalOpen: TCheckBox; cbToolsRunInTerminal: TCheckBox; cbToolsUseExternalProgram: TCheckBox; edtToolsParameters: TEdit; fneToolsPath: TFileNameEdit; lblToolsParameters: TLabel; lblToolsPath: TLabel; pmPathHelper: TPopupMenu; procedure btnRelativeToolPathClick(Sender: TObject); procedure cbToolsKeepTerminalOpenChange(Sender: TObject); procedure cbToolsRunInTerminalChange(Sender: TObject); procedure cbToolsUseExternalProgramChange(Sender: TObject); procedure edtToolsParametersChange(Sender: TObject); procedure fneToolsPathAcceptFileName(Sender: TObject; var Value: String); procedure fneToolsPathChange(Sender: TObject); private FExternalTool: TExternalTool; FExternalToolOptions: TExternalToolOptions; FOnUseExternalProgramChange: TNotifyEvent; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; property ExternalTool: TExternalTool read FExternalTool write FExternalTool; property OnUseExternalProgramChange: TNotifyEvent read FOnUseExternalProgramChange write FOnUseExternalProgramChange; public constructor Create(TheOwner: TComponent); override; end; implementation {$R *.lfm} uses uDCUtils, uSpecialDir; { TfrmOptionsToolBase } procedure TfrmOptionsToolBase.cbToolsKeepTerminalOpenChange(Sender: TObject); begin FExternalToolOptions.KeepTerminalOpen := cbToolsKeepTerminalOpen.Checked; end; procedure TfrmOptionsToolBase.btnRelativeToolPathClick(Sender: TObject); begin fneToolsPath.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fneToolsPath,pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmOptionsToolBase.cbToolsRunInTerminalChange(Sender: TObject); begin cbToolsKeepTerminalOpen.Enabled := cbToolsRunInTerminal.Checked; FExternalToolOptions.RunInTerminal := cbToolsRunInTerminal.Checked; end; procedure TfrmOptionsToolBase.cbToolsUseExternalProgramChange(Sender: TObject); begin lblToolsPath.Enabled := cbToolsUseExternalProgram.Checked; fneToolsPath.Enabled := cbToolsUseExternalProgram.Checked; btnRelativeToolPath.Enabled := cbToolsUseExternalProgram.Checked; lblToolsParameters.Enabled := cbToolsUseExternalProgram.Checked; edtToolsParameters.Enabled := cbToolsUseExternalProgram.Checked; cbToolsRunInTerminal.Enabled := cbToolsUseExternalProgram.Checked; cbToolsKeepTerminalOpen.Enabled := cbToolsUseExternalProgram.Checked; FExternalToolOptions.Enabled := cbToolsUseExternalProgram.Checked; if Assigned(FOnUseExternalProgramChange) then FOnUseExternalProgramChange(Self); end; procedure TfrmOptionsToolBase.edtToolsParametersChange(Sender: TObject); begin FExternalToolOptions.Parameters := edtToolsParameters.Text; end; procedure TfrmOptionsToolBase.fneToolsPathAcceptFileName(Sender: TObject; var Value: String); begin Value := SetCmdDirAsEnvVar(Value); {$IF DEFINED(LCLCARBON)} // OnChange don't called under Carbon when choose file name // from open dialog so assign path in this event. FExternalToolOptions.Path := Value; {$ENDIF} end; procedure TfrmOptionsToolBase.fneToolsPathChange(Sender: TObject); begin FExternalToolOptions.Path := fneToolsPath.FileName; end; procedure TfrmOptionsToolBase.Init; begin // Enable/disable tools controls. cbToolsUseExternalProgramChange(nil); end; procedure TfrmOptionsToolBase.Load; begin FExternalToolOptions := gExternalTools[FExternalTool]; cbToolsUseExternalProgram.Checked := FExternalToolOptions.Enabled; fneToolsPath.FileName := FExternalToolOptions.Path; edtToolsParameters.Text := FExternalToolOptions.Parameters; cbToolsRunInTerminal.Checked := FExternalToolOptions.RunInTerminal; cbToolsKeepTerminalOpen.Checked := FExternalToolOptions.KeepTerminalOpen; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper,mp_PATHHELPER,nil); end; function TfrmOptionsToolBase.Save: TOptionsEditorSaveFlags; begin gExternalTools[FExternalTool] := FExternalToolOptions; Result := []; end; constructor TfrmOptionsToolBase.Create(TheOwner: TComponent); begin inherited Create(TheOwner); FOnUseExternalProgramChange := nil; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstools.lfm�������������������������������������������������������0000644�0001750�0000144�00000003557�14743153644�020306� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsViewer: TfrmOptionsViewer Height = 513 Width = 586 HelpKeyword = '/configuration.html#ConfigToolsViewer' ClientHeight = 513 ClientWidth = 586 DesignLeft = 384 DesignTop = 288 inherited lblToolsPath: TLabel Width = 145 end inherited cbToolsKeepTerminalOpen: TCheckBox Width = 297 end inherited cbToolsRunInTerminal: TCheckBox Width = 119 end inherited cbToolsUseExternalProgram: TCheckBox Width = 131 end object gbInternalViewer: TGroupBox[8] AnchorSideLeft.Control = fneToolsPath AnchorSideTop.Control = cbToolsKeepTerminalOpen AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtToolsParameters AnchorSideRight.Side = asrBottom Left = 8 Height = 55 Top = 200 Width = 571 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 12 BorderSpacing.Bottom = 10 Caption = 'Internal viewer options' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ClientHeight = 48 ClientWidth = 569 TabOrder = 5 object seNumberColumnsViewer: TSpinEdit AnchorSideLeft.Control = lblNumberColumnsViewer AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom Left = 211 Height = 23 Top = 6 Width = 50 BorderSpacing.Left = 12 BorderSpacing.Top = 5 MaxValue = 3 MinValue = 1 TabOrder = 0 Value = 1 end object lblNumberColumnsViewer: TLabel AnchorSideTop.Control = seNumberColumnsViewer AnchorSideTop.Side = asrCenter Left = 12 Height = 15 Top = 10 Width = 187 Caption = '&Number of columns in book viewer' FocusControl = seNumberColumnsViewer ParentColor = False end end inherited pmPathHelper: TPopupMenu[9] Left = 520 Top = 152 end end �������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstools.lrj�������������������������������������������������������0000644�0001750�0000144�00000000763�14743153644�020313� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":10525987,"name":"tfrmoptionsviewer.gbinternalviewer.caption","sourcebytes":[73,110,116,101,114,110,97,108,32,118,105,101,119,101,114,32,111,112,116,105,111,110,115],"value":"Internal viewer options"}, {"hash":70997378,"name":"tfrmoptionsviewer.lblnumbercolumnsviewer.caption","sourcebytes":[38,78,117,109,98,101,114,32,111,102,32,99,111,108,117,109,110,115,32,105,110,32,98,111,111,107,32,118,105,101,119,101,114],"value":"&Number of columns in book viewer"} ]} �������������doublecmd-1.1.22/src/frames/foptionstools.pas�������������������������������������������������������0000644�0001750�0000144�00000004053�14743153644�020303� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Tools options page Copyright (C) 2006-2023 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsTools; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, Spin, ExtCtrls, ColorBox, Dialogs, Types, fOptionsFrame, fOptionsToolBase; type { TfrmOptionsViewer } TfrmOptionsViewer = class(TfrmOptionsToolBase) gbInternalViewer: TGroupBox; lblNumberColumnsViewer: TLabel; seNumberColumnsViewer: TSpinEdit; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses uGlobs, uLng; { TfrmOptionsViewer } class function TfrmOptionsViewer.GetIconIndex: Integer; begin Result := 22; end; class function TfrmOptionsViewer.GetTitle: String; begin Result := rsToolViewer; end; procedure TfrmOptionsViewer.Init; begin ExternalTool := etViewer; inherited Init; end; procedure TfrmOptionsViewer.Load; begin inherited Load; seNumberColumnsViewer.Value := gColCount; end; function TfrmOptionsViewer.Save: TOptionsEditorSaveFlags; begin Result := inherited Save; gColCount := seNumberColumnsViewer.Value; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolsdiffer.lfm�������������������������������������������������0000644�0001750�0000144�00000002664�14743153644�021464� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsDiffer: TfrmOptionsDiffer Height = 478 Width = 586 HelpKeyword = '/configuration.html#ConfigToolsDiffer' ClientHeight = 478 ClientWidth = 586 DesignLeft = 377 DesignTop = 160 inherited btnRelativeToolPath: TSpeedButton Anchors = [akTop, akRight, akBottom] end object rgResultingFramePositionAfterCompare: TRadioGroup[8] AnchorSideLeft.Control = edtToolsParameters AnchorSideTop.Control = cbToolsKeepTerminalOpen AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtToolsParameters AnchorSideRight.Side = asrBottom Left = 8 Height = 58 Top = 200 Width = 571 Anchors = [akTop, akLeft, akRight] AutoFill = True AutoSize = True BorderSpacing.Top = 12 Caption = 'Position of frame panel after the comparison:' ChildSizing.LeftRightSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 38 ClientWidth = 567 ItemIndex = 0 Items.Strings = ( 'Active frame panel on left, inactive on right (legacy)' 'Left frame panel on left, right on right' ) TabOrder = 5 end inherited pmPathHelper: TPopupMenu[9] left = 464 top = 8 end end ����������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolsdiffer.lrj�������������������������������������������������0000644�0001750�0000144�00000000551�14743153644�021466� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":185038314,"name":"tfrmoptionsdiffer.rgresultingframepositionaftercompare.caption","sourcebytes":[80,111,115,105,116,105,111,110,32,111,102,32,102,114,97,109,101,32,112,97,110,101,108,32,97,102,116,101,114,32,116,104,101,32,99,111,109,112,97,114,105,115,111,110,58],"value":"Position of frame panel after the comparison:"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolsdiffer.pas�������������������������������������������������0000644�0001750�0000144�00000004342�14743153644�021464� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Tools options page for the differ tool Copyright (C) 2006-2016 Koblov Alexander (Alexx2000@mail.ru) 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 } unit fOptionsToolsDiffer; {$mode objfpc}{$H+} interface uses Classes, SysUtils, ExtCtrls, Dialogs, Buttons, Menus, fOptionsFrame, fOptionsToolBase; type { TfrmOptionsDiffer } TfrmOptionsDiffer = class(TfrmOptionsToolBase) rgResultingFramePositionAfterCompare: TRadioGroup; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses DCStrUtils, uGlobs, uLng; { TfrmOptionsDiffer } procedure TfrmOptionsDiffer.Init; begin ExternalTool := etDiffer; inherited Init; ParseLineToList(rsOptDifferFramePosition, rgResultingFramePositionAfterCompare.Items); end; procedure TfrmOptionsDiffer.Load; begin inherited; rgResultingFramePositionAfterCompare.ItemIndex := Integer(gResultingFramePositionAfterCompare); end; function TfrmOptionsDiffer.Save: TOptionsEditorSaveFlags; begin Result := inherited; gResultingFramePositionAfterCompare := TResultingFramePositionAfterCompare(rgResultingFramePositionAfterCompare.ItemIndex); end; class function TfrmOptionsDiffer.GetIconIndex: Integer; begin Result := 25; end; class function TfrmOptionsDiffer.GetTitle: String; begin Result := rsToolDiffer; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolseditor.lfm�������������������������������������������������0000644�0001750�0000144�00000014465�14743153644�021515� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsEditor: TfrmOptionsEditor Height = 513 Width = 586 HelpKeyword = '/configuration.html#ConfigToolsEditor' ClientHeight = 513 ClientWidth = 586 ParentShowHint = False ShowHint = True DesignLeft = 117 DesignTop = 255 object gbInternalEditor: TGroupBox[8] AnchorSideLeft.Control = fneToolsPath AnchorSideTop.Control = cbToolsKeepTerminalOpen AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtToolsParameters AnchorSideRight.Side = asrBottom Left = 8 Height = 176 Top = 235 Width = 571 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 12 BorderSpacing.Bottom = 10 Caption = 'Internal editor options' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.EnlargeHorizontal = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 151 ClientWidth = 567 TabOrder = 5 object pnlBooleanOptions: TPanel Left = 6 Height = 108 Top = 6 Width = 555 AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 12 ChildSizing.EnlargeHorizontal = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 108 ClientWidth = 555 TabOrder = 0 object chkAutoIndent: TCheckBox Left = 6 Height = 24 Hint = 'Allows to indent the caret, when new line is created with <Enter>, with the same amount of leading white space as the preceding line' Top = 6 Width = 306 Caption = 'Auto Indent' TabOrder = 0 end object chkTrimTrailingSpaces: TCheckBox Left = 324 Height = 24 Hint = 'Auto delete trailing spaces, this applies only to edited lines' Top = 6 Width = 225 Caption = 'Delete trailing spaces' TabOrder = 1 end object chkScrollPastEndLine: TCheckBox AnchorSideTop.Side = asrBottom Left = 6 Height = 24 Hint = 'Allows caret to go into empty space beyond end-of-line position' Top = 30 Width = 306 BorderSpacing.Left = 6 Caption = 'Caret past end of line' TabOrder = 2 end object chkShowSpecialChars: TCheckBox Left = 324 Height = 24 Hint = 'Shows special characters for spaces and tabulations' Top = 30 Width = 225 Caption = 'Show special characters' TabOrder = 3 end object chkTabsToSpaces: TCheckBox Left = 6 Height = 24 Hint = 'Converts tab characters to a specified number of space characters (when entering)' Top = 54 Width = 306 Caption = 'Use spaces instead tab characters' TabOrder = 4 end object chkTabIndent: TCheckBox Left = 324 Height = 24 Hint = 'When active <Tab> and <Shift+Tab> act as block indent, unindent when text is selected' Top = 54 Width = 225 Caption = 'Tab indents blocks' TabOrder = 5 end object chkSmartTabs: TCheckBox Left = 6 Height = 24 Hint = 'When using <Tab> key, caret will go to the next non-space character of the previous line' Top = 78 Width = 306 Caption = 'Smart Tabs' TabOrder = 6 end object chkGroupUndo: TCheckBox Left = 323 Height = 24 Hint = 'All continuous changes of the same type will be processed in one call instead of undoing/redoing each one' Top = 63 Width = 226 Caption = 'Group Undo' TabOrder = 7 end end object edTabWidth: TEdit AnchorSideLeft.Control = lblTabWidth AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlBooleanOptions AnchorSideTop.Side = asrBottom Left = 77 Height = 28 Hint = 'Please note that the "Smart Tabs" option takes precedence over the tabulation to be performed' Top = 117 Width = 100 BorderSpacing.Left = 4 BorderSpacing.Top = 3 TabOrder = 1 end object lblTabWidth: TLabel AnchorSideLeft.Control = pnlBooleanOptions AnchorSideTop.Control = edTabWidth AnchorSideTop.Side = asrCenter Left = 6 Height = 20 Hint = 'Please note that the "Smart Tabs" option takes precedence over the tabulation to be performed' Top = 121 Width = 67 Caption = 'Tab width:' FocusControl = edTabWidth ParentColor = False end object chkRightEdge: TCheckBox AnchorSideLeft.Control = seeBlockIndent AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblTabWidth AnchorSideTop.Side = asrCenter Left = 363 Height = 23 Top = 120 Width = 108 BorderSpacing.Left = 12 Caption = 'Right margin:' Color = clDefault ParentColor = False TabOrder = 3 end object seeRightEdge: TSpinEditEx AnchorSideLeft.Control = chkRightEdge AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edTabWidth AnchorSideTop.Side = asrCenter Left = 475 Height = 36 Top = 113 Width = 103 BorderSpacing.Left = 4 MaxLength = 0 TabOrder = 4 MaxValue = 512 MinValue = 16 NullValue = 0 Value = 80 end object lblBlockIndent: TLabel AnchorSideLeft.Control = edTabWidth AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblTabWidth AnchorSideTop.Side = asrCenter Left = 164 Height = 19 Top = 122 Width = 80 BorderSpacing.Left = 12 Caption = 'Block indent:' ParentColor = False end object seeBlockIndent: TSpinEditEx AnchorSideLeft.Control = lblBlockIndent AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edTabWidth AnchorSideTop.Side = asrCenter Left = 248 Height = 36 Top = 113 Width = 103 BorderSpacing.Left = 4 MaxLength = 0 TabOrder = 2 MaxValue = 20 NullValue = 0 Value = 0 end end inherited pmPathHelper: TPopupMenu[9] Left = 424 Top = 8 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolseditor.lrj�������������������������������������������������0000644�0001750�0000144�00000015670�14743153644�021525� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":40124019,"name":"tfrmoptionseditor.gbinternaleditor.caption","sourcebytes":[73,110,116,101,114,110,97,108,32,101,100,105,116,111,114,32,111,112,116,105,111,110,115],"value":"Internal editor options"}, {"hash":162766773,"name":"tfrmoptionseditor.chkautoindent.hint","sourcebytes":[65,108,108,111,119,115,32,116,111,32,105,110,100,101,110,116,32,116,104,101,32,99,97,114,101,116,44,32,119,104,101,110,32,110,101,119,32,108,105,110,101,32,105,115,32,99,114,101,97,116,101,100,32,119,105,116,104,32,60,69,110,116,101,114,62,44,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,97,109,111,117,110,116,32,111,102,32,108,101,97,100,105,110,103,32,119,104,105,116,101,32,115,112,97,99,101,32,97,115,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,108,105,110,101],"value":"Allows to indent the caret, when new line is created with <Enter>, with the same amount of leading white space as the preceding line"}, {"hash":80503108,"name":"tfrmoptionseditor.chkautoindent.caption","sourcebytes":[65,117,116,111,32,73,110,100,101,110,116],"value":"Auto Indent"}, {"hash":108628419,"name":"tfrmoptionseditor.chktrimtrailingspaces.hint","sourcebytes":[65,117,116,111,32,100,101,108,101,116,101,32,116,114,97,105,108,105,110,103,32,115,112,97,99,101,115,44,32,116,104,105,115,32,97,112,112,108,105,101,115,32,111,110,108,121,32,116,111,32,101,100,105,116,101,100,32,108,105,110,101,115],"value":"Auto delete trailing spaces, this applies only to edited lines"}, {"hash":214387443,"name":"tfrmoptionseditor.chktrimtrailingspaces.caption","sourcebytes":[68,101,108,101,116,101,32,116,114,97,105,108,105,110,103,32,115,112,97,99,101,115],"value":"Delete trailing spaces"}, {"hash":23065182,"name":"tfrmoptionseditor.chkscrollpastendline.hint","sourcebytes":[65,108,108,111,119,115,32,99,97,114,101,116,32,116,111,32,103,111,32,105,110,116,111,32,101,109,112,116,121,32,115,112,97,99,101,32,98,101,121,111,110,100,32,101,110,100,45,111,102,45,108,105,110,101,32,112,111,115,105,116,105,111,110],"value":"Allows caret to go into empty space beyond end-of-line position"}, {"hash":261134869,"name":"tfrmoptionseditor.chkscrollpastendline.caption","sourcebytes":[67,97,114,101,116,32,112,97,115,116,32,101,110,100,32,111,102,32,108,105,110,101],"value":"Caret past end of line"}, {"hash":86627171,"name":"tfrmoptionseditor.chkshowspecialchars.hint","sourcebytes":[83,104,111,119,115,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,115,32,102,111,114,32,115,112,97,99,101,115,32,97,110,100,32,116,97,98,117,108,97,116,105,111,110,115],"value":"Shows special characters for spaces and tabulations"}, {"hash":140737907,"name":"tfrmoptionseditor.chkshowspecialchars.caption","sourcebytes":[83,104,111,119,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,115],"value":"Show special characters"}, {"hash":245290889,"name":"tfrmoptionseditor.chktabstospaces.hint","sourcebytes":[67,111,110,118,101,114,116,115,32,116,97,98,32,99,104,97,114,97,99,116,101,114,115,32,116,111,32,97,32,115,112,101,99,105,102,105,101,100,32,110,117,109,98,101,114,32,111,102,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,40,119,104,101,110,32,101,110,116,101,114,105,110,103,41],"value":"Converts tab characters to a specified number of space characters (when entering)"}, {"hash":245861139,"name":"tfrmoptionseditor.chktabstospaces.caption","sourcebytes":[85,115,101,32,115,112,97,99,101,115,32,105,110,115,116,101,97,100,32,116,97,98,32,99,104,97,114,97,99,116,101,114,115],"value":"Use spaces instead tab characters"}, {"hash":253069796,"name":"tfrmoptionseditor.chktabindent.hint","sourcebytes":[87,104,101,110,32,97,99,116,105,118,101,32,60,84,97,98,62,32,97,110,100,32,60,83,104,105,102,116,43,84,97,98,62,32,97,99,116,32,97,115,32,98,108,111,99,107,32,105,110,100,101,110,116,44,32,117,110,105,110,100,101,110,116,32,119,104,101,110,32,116,101,120,116,32,105,115,32,115,101,108,101,99,116,101,100],"value":"When active <Tab> and <Shift+Tab> act as block indent, unindent when text is selected"}, {"hash":127944307,"name":"tfrmoptionseditor.chktabindent.caption","sourcebytes":[84,97,98,32,105,110,100,101,110,116,115,32,98,108,111,99,107,115],"value":"Tab indents blocks"}, {"hash":145722565,"name":"tfrmoptionseditor.chksmarttabs.hint","sourcebytes":[87,104,101,110,32,117,115,105,110,103,32,60,84,97,98,62,32,107,101,121,44,32,99,97,114,101,116,32,119,105,108,108,32,103,111,32,116,111,32,116,104,101,32,110,101,120,116,32,110,111,110,45,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,108,105,110,101],"value":"When using <Tab> key, caret will go to the next non-space character of the previous line"}, {"hash":157287443,"name":"tfrmoptionseditor.chksmarttabs.caption","sourcebytes":[83,109,97,114,116,32,84,97,98,115],"value":"Smart Tabs"}, {"hash":53591125,"name":"tfrmoptionseditor.chkgroupundo.hint","sourcebytes":[65,108,108,32,99,111,110,116,105,110,117,111,117,115,32,99,104,97,110,103,101,115,32,111,102,32,116,104,101,32,115,97,109,101,32,116,121,112,101,32,119,105,108,108,32,98,101,32,112,114,111,99,101,115,115,101,100,32,105,110,32,111,110,101,32,99,97,108,108,32,105,110,115,116,101,97,100,32,111,102,32,117,110,100,111,105,110,103,47,114,101,100,111,105,110,103,32,101,97,99,104,32,111,110,101],"value":"All continuous changes of the same type will be processed in one call instead of undoing/redoing each one"}, {"hash":203517391,"name":"tfrmoptionseditor.chkgroupundo.caption","sourcebytes":[71,114,111,117,112,32,85,110,100,111],"value":"Group Undo"}, {"hash":61127412,"name":"tfrmoptionseditor.edtabwidth.hint","sourcebytes":[80,108,101,97,115,101,32,110,111,116,101,32,116,104,97,116,32,116,104,101,32,34,83,109,97,114,116,32,84,97,98,115,34,32,111,112,116,105,111,110,32,116,97,107,101,115,32,112,114,101,99,101,100,101,110,99,101,32,111,118,101,114,32,116,104,101,32,116,97,98,117,108,97,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100],"value":"Please note that the \"Smart Tabs\" option takes precedence over the tabulation to be performed"}, {"hash":61127412,"name":"tfrmoptionseditor.lbltabwidth.hint","sourcebytes":[80,108,101,97,115,101,32,110,111,116,101,32,116,104,97,116,32,116,104,101,32,34,83,109,97,114,116,32,84,97,98,115,34,32,111,112,116,105,111,110,32,116,97,107,101,115,32,112,114,101,99,101,100,101,110,99,101,32,111,118,101,114,32,116,104,101,32,116,97,98,117,108,97,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100],"value":"Please note that the \"Smart Tabs\" option takes precedence over the tabulation to be performed"}, {"hash":131735034,"name":"tfrmoptionseditor.lbltabwidth.caption","sourcebytes":[84,97,98,32,119,105,100,116,104,58],"value":"Tab width:"}, {"hash":192227930,"name":"tfrmoptionseditor.chkrightedge.caption","sourcebytes":[82,105,103,104,116,32,109,97,114,103,105,110,58],"value":"Right margin:"}, {"hash":125778010,"name":"tfrmoptionseditor.lblblockindent.caption","sourcebytes":[66,108,111,99,107,32,105,110,100,101,110,116,58],"value":"Block indent:"} ]} ������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstoolseditor.pas�������������������������������������������������0000644�0001750�0000144�00000011114�14743153644�021506� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Tools options page for the editor tool Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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 } unit fOptionsToolsEditor; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, ExtCtrls, Dialogs, LCLVersion, Buttons, EditBtn, Menus, SpinEx, fOptionsFrame, fOptionsToolBase; type { TfrmOptionsEditor } TfrmOptionsEditor = class(TfrmOptionsToolBase) gbInternalEditor: TGroupBox; chkRightEdge: TCheckBox; lblBlockIndent: TLabel; pnlBooleanOptions: TPanel; chkAutoIndent: TCheckBox; chkTrimTrailingSpaces: TCheckBox; chkScrollPastEndLine: TCheckBox; chkShowSpecialChars: TCheckBox; chkTabsToSpaces: TCheckBox; chkTabIndent: TCheckBox; lblTabWidth: TLabel; edTabWidth: TEdit; chkSmartTabs: TCheckBox; chkGroupUndo: TCheckBox; seeRightEdge: TSpinEditEx; seeBlockIndent: TSpinEditEx; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public constructor Create(TheOwner: TComponent); override; class function GetIconIndex: Integer; override; class function GetTitle: String; override; end; implementation {$R *.lfm} uses {$if lcl_fullversion < 2010000} SynEdit {$else} SynEditTypes {$endif} , uGlobs, uLng, fEditor; { TfrmOptionsEditor } procedure TfrmOptionsEditor.Init; begin ExternalTool := etEditor; inherited Init; end; procedure TfrmOptionsEditor.Load; begin inherited Load; chkScrollPastEndLine.Checked := eoScrollPastEoL in gEditorSynEditOptions; chkShowSpecialChars.Checked := eoShowSpecialChars in gEditorSynEditOptions; chkTrimTrailingSpaces.Checked := eoTrimTrailingSpaces in gEditorSynEditOptions; chkTabsToSpaces.Checked := eoTabsToSpaces in gEditorSynEditOptions; chkAutoIndent.Checked := eoAutoIndent in gEditorSynEditOptions; chkTabIndent.Checked := eoTabIndent in gEditorSynEditOptions; chkSmartTabs.Checked := eoSmartTabs in gEditorSynEditOptions; chkRightEdge.Checked := not (eoHideRightMargin in gEditorSynEditOptions); chkGroupUndo.Checked := eoGroupUndo in gEditorSynEditOptions; edTabWidth.Text := IntToStr(gEditorSynEditTabWidth); seeBlockIndent.Value := gEditorSynEditBlockIndent; seeRightEdge.Value := gEditorSynEditRightEdge; end; function TfrmOptionsEditor.Save: TOptionsEditorSaveFlags; procedure UpdateOptionFromBool(AValue: Boolean; AnOption: TSynEditorOption); begin if AValue then gEditorSynEditOptions := gEditorSynEditOptions + [AnOption] else gEditorSynEditOptions := gEditorSynEditOptions - [AnOption]; end; begin Result:= inherited Save; UpdateOptionFromBool(not chkRightEdge.Checked, eoHideRightMargin); UpdateOptionFromBool(chkScrollPastEndLine.Checked, eoScrollPastEoL); UpdateOptionFromBool(chkShowSpecialChars.Checked, eoShowSpecialChars); UpdateOptionFromBool(chkTrimTrailingSpaces.Checked, eoTrimTrailingSpaces); UpdateOptionFromBool(chkTabsToSpaces.Checked, eoTabsToSpaces); UpdateOptionFromBool(chkAutoIndent.Checked, eoAutoIndent); UpdateOptionFromBool(chkTabIndent.Checked, eoTabIndent); UpdateOptionFromBool(chkSmartTabs.Checked, eoSmartTabs); UpdateOptionFromBool(chkGroupUndo.Checked, eoGroupUndo); edTabWidth.Text := IntToStr(StrToIntDef(edTabWidth.Text,8)); gEditorSynEditTabWidth := StrToIntDef(edTabWidth.Text,8); gEditorSynEditBlockIndent := seeBlockIndent.Value; gEditorSynEditRightEdge := seeRightEdge.Value; if LastEditorUsedForConfiguration<>nil then LastEditorUsedForConfiguration.LoadGlobalOptions; end; constructor TfrmOptionsEditor.Create(TheOwner: TComponent); begin inherited Create(TheOwner); Name := 'frmOptionsEditor'; end; class function TfrmOptionsEditor.GetIconIndex: Integer; begin Result := 10; end; class function TfrmOptionsEditor.GetTitle: String; begin Result := rsToolEditor; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstooltips.lfm����������������������������������������������������0000644�0001750�0000144�00000037773�14743153644�021032� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsToolTips: TfrmOptionsToolTips Height = 480 Width = 826 HelpKeyword = '/configuration.html#ConfigTooltips' AutoSize = True ClientHeight = 480 ClientWidth = 826 DesignLeft = 420 DesignTop = 145 object pnlToolTipsListbox: TPanel[0] Left = 5 Height = 441 Top = 39 Width = 120 Align = alLeft BorderSpacing.Left = 5 BevelOuter = bvNone ClientHeight = 441 ClientWidth = 120 Constraints.MinWidth = 120 TabOrder = 1 object lblToolTipsListBox: TLabel Left = 0 Height = 15 Top = 0 Width = 120 Align = alTop Caption = '&File types:' FocusControl = lsbCustomFields end object lsbCustomFields: TListBox Left = 0 Height = 421 Top = 15 Width = 120 Align = alClient BorderSpacing.Bottom = 5 DragMode = dmAutomatic ItemHeight = 0 OnDragDrop = lsbCustomFieldsDragDrop OnDragOver = lsbCustomFieldsDragOver OnSelectionChange = lsbCustomFieldsSelectionChange TabOrder = 0 end end object splToolTips: TSplitter[1] Left = 125 Height = 441 Top = 39 Width = 5 end object pnlConfigurationToolTips: TPanel[2] Left = 130 Height = 441 Top = 39 Width = 696 Align = alClient BevelOuter = bvNone ClientHeight = 441 ClientWidth = 696 TabOrder = 3 object pnlTooltipButtons: TPanel Left = 0 Height = 34 Top = 0 Width = 696 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ClientHeight = 34 ClientWidth = 696 TabOrder = 0 object btnApplyToolTipsFileType: TBitBtn AnchorSideLeft.Control = pnlTooltipButtons AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 5 Height = 25 Top = 5 Width = 57 AutoSize = True BorderSpacing.Left = 5 Caption = 'A&pply' OnClick = btnApplyToolTipsFileTypeClick TabOrder = 0 end object btnAddToolTipsFileType: TBitBtn AnchorSideLeft.Control = btnApplyToolTipsFileType AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 65 Height = 25 Top = 5 Width = 48 AutoSize = True BorderSpacing.Left = 3 Caption = 'A&dd' OnClick = btnAddToolTipsFileTypeClick TabOrder = 1 end object btnCopyToolTipsFileType: TBitBtn AnchorSideLeft.Control = btnAddToolTipsFileType AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 116 Height = 25 Top = 5 Width = 54 AutoSize = True BorderSpacing.Left = 3 Caption = 'Cop&y' OnClick = btnCopyToolTipsFileTypeClick TabOrder = 2 end object btnRenameToolTipsFileType: TBitBtn AnchorSideLeft.Control = btnCopyToolTipsFileType AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 173 Height = 25 Top = 5 Width = 69 AutoSize = True BorderSpacing.Left = 3 Caption = '&Rename' OnClick = btnRenameToolTipsFileTypeClick TabOrder = 3 end object btnDeleteToolTipsFileType: TBitBtn AnchorSideLeft.Control = btnRenameToolTipsFileType AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 245 Height = 25 Top = 5 Width = 59 AutoSize = True BorderSpacing.Left = 3 Caption = 'Delete' OnClick = btnDeleteToolTipsFileTypeClick TabOrder = 4 end object btnTooltipOther: TBitBtn AnchorSideLeft.Control = btnDeleteToolTipsFileType AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 307 Height = 25 Top = 5 Width = 65 AutoSize = True BorderSpacing.Left = 3 Caption = 'Oth&er...' OnClick = btnTooltipOtherClick TabOrder = 5 end end object pnlActualToolTipsConfiguration: TPanel AnchorSideLeft.Control = pnlConfigurationToolTips AnchorSideTop.Control = pnlTooltipButtons AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlConfigurationToolTips AnchorSideRight.Side = asrBottom Left = 0 Height = 271 Top = 34 Width = 696 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ClientHeight = 271 ClientWidth = 696 TabOrder = 1 object edtFieldsMask: TEdit AnchorSideLeft.Control = bvlToolTips1 AnchorSideTop.Control = lblFieldsMask AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnFieldsSearchTemplate Left = 5 Height = 23 Top = 45 Width = 656 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 2 OnChange = edtAnyChange TabOrder = 0 end object btnFieldsList: TButton AnchorSideLeft.Control = bvlToolTips1 AnchorSideTop.Control = memFieldsList AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 5 Height = 23 Top = 248 Width = 28 BorderSpacing.InnerBorder = 4 Caption = '>>' OnClick = btnFieldsListClick TabOrder = 3 end object btnFieldsSearchTemplate: TBitBtn AnchorSideTop.Control = edtFieldsMask AnchorSideRight.Control = bvlToolTips1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtFieldsMask AnchorSideBottom.Side = asrBottom Left = 663 Height = 23 Hint = 'Template...' Top = 45 Width = 23 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000009700 00FF000000000000000000000000000000FF00000000000000FFC2B5B3E30000 00FF000000000000000000000000000000000000000000000000000000000000 0000970000FF00000000000000000000000000000000C5B8B570E3DBD9FF8975 7375000000000000000000000000000000000000000000000000000000000000 000000000000970000FF000000000000000000000000C2B4B26FE1D9D7FF8571 6E75000000000000000000000000000000000000000000000000000000000000 0000970000FF00000000000000000000000000000000B3A4A26FD6C9C7FF705E 5B75000000000000000000000000000000000000000000000000000000009700 00FF0000000000000000000000000000000000000000A798967DD9CBCAFF7362 6184000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000005B494812D4C6C5FFD1C2C1FE8F7E 7DFF5B4B4E160000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000C2B3B3C0EEE2E2FED5C8C7FFD6C9 C8FE746363C60000000000000000000000000000000000000000000000000000 00000000000000000000000000009D8B8B5CF9EEEFFFEDE1E0FFDED1D1FFEADE DCFFB1A1A0FF645455630000000000000000000000000000000000000000D2C6 C36CEEE5E2C3BEADABB100000002D2C4C3FBFDF5F4FEE0D4D3FFDACCCBFFE8DD DBFFD2C4C2FE796868FD61525509000000000000000000000000000000008B78 754B00000000000000007C6B6BFCF7ECECFFFEF6F4FFCFC2C0FFD4C7C7FFEDE3 E1FFCDBDBBFF998887FE605151BC00000000000000000000000000000000806F 6D350000000062514F4CCEBEBEFFFBF2F0FFFBF6F5FFC7B9B7FFD0C3C3FFF8F0 EFFFC7B7B4FFA69593FF665555FF5545464D000000000000000000000000D8CF CE59D1C5C299978484FFF4EBEBFEFEFDFDFFF4EEEDFFC3B5B3FFD8CBC9FFFFFC FCFFD8CBC9FFB2A1A0FF867474FE524343FA0000000200000000000000000000 00007767669CE0D3D1FFFFFEFEFFFFFFFFFFEFE7E6FFAF9E9BFFD6C6C4FFFCF7 F7FFD8CACAFFAE9D9EFF827173FF5B4A4EFF67595C9F00000000000000000000 00008E7F7ED8E2D7D6FFCCC2C2FFCDC6C6FFD0C9C9FFD7D1D2FFD6D1D2FFCEC6 C6FFCBC5C5FFC7C0C0FFC2B8B8FFA39698FF726468DC00000000000000000000 0000ACA2A3DEAC9C99FFC9BCBBFFDBCDCAFFF3E6E2FEFFFFFEFFF5EEECFFB9A7 A3FFF3EDEBFEF7F3F3FFA99998FFA49695FFB1A6A7E700000000000000000000 0000000000005F5054459C919391B7ADAFB4BBB2B2C3C0B5B6CFC0B6B7D2BBB2 B3D0BCB2B3C3BBB3B4B59D929592615156460000000000000000 } Layout = blGlyphRight OnClick = btnFieldsSearchTemplateClick ParentShowHint = False ShowHint = True TabOrder = 1 end object lblFieldsList: TLabel AnchorSideLeft.Control = bvlToolTips1 AnchorSideTop.Control = edtFieldsMask AnchorSideTop.Side = asrBottom AnchorSideRight.Control = bvlToolTips1 AnchorSideRight.Side = asrBottom Left = 5 Height = 15 Top = 70 Width = 681 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 Caption = 'Category &hint:' FocusControl = memFieldsList end object lblFieldsMask: TLabel AnchorSideLeft.Control = bvlToolTips1 AnchorSideTop.Control = bvlToolTips1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlActualToolTipsConfiguration AnchorSideRight.Side = asrBottom Left = 5 Height = 15 Top = 30 Width = 681 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 5 BorderSpacing.Right = 10 Caption = 'Category &mask:' FocusControl = edtFieldsMask end object memFieldsList: TMemo AnchorSideLeft.Control = bvlToolTips1 AnchorSideTop.Control = lblFieldsList AnchorSideTop.Side = asrBottom AnchorSideRight.Control = bvlToolTips1 AnchorSideRight.Side = asrBottom Left = 5 Height = 163 Top = 85 Width = 681 Anchors = [akTop, akLeft, akRight] OnChange = edtAnyChange ScrollBars = ssBoth TabOrder = 2 WordWrap = False end object bvlToolTips1: TDividerBevel AnchorSideLeft.Control = pnlActualToolTipsConfiguration AnchorSideTop.Control = pnlActualToolTipsConfiguration AnchorSideRight.Control = pnlActualToolTipsConfiguration AnchorSideRight.Side = asrBottom Left = 5 Height = 15 Top = 10 Width = 681 Caption = 'Tooltip configuration for selected file type:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 5 BorderSpacing.Top = 10 BorderSpacing.Right = 10 ParentFont = False end end object pnlGeneralToolTipsOptions: TPanel AnchorSideLeft.Control = pnlConfigurationToolTips AnchorSideTop.Control = pnlActualToolTipsConfiguration AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlConfigurationToolTips AnchorSideRight.Side = asrBottom Left = 0 Height = 81 Top = 304 Width = 681 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ClientHeight = 81 ClientWidth = 681 TabOrder = 2 object bvlToolTips2: TDividerBevel AnchorSideLeft.Control = pnlGeneralToolTipsOptions AnchorSideTop.Control = pnlGeneralToolTipsOptions AnchorSideRight.Control = pnlGeneralToolTipsOptions AnchorSideRight.Side = asrBottom Left = 5 Height = 15 Top = 10 Width = 681 Caption = 'General options about tooltips:' Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 5 BorderSpacing.Top = 10 BorderSpacing.Right = 10 ParentFont = False end object lblTooltipShowingMode: TLabel AnchorSideLeft.Control = bvlToolTips2 AnchorSideTop.Control = cbTooltipShowingMode AnchorSideTop.Side = asrCenter Left = 5 Height = 15 Top = 34 Width = 121 Caption = 'Tooltip showing mode:' FocusControl = cbTooltipShowingMode end object cbTooltipShowingMode: TComboBox AnchorSideLeft.Control = lblTooltipShowingMode AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = bvlToolTips2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = bvlToolTips2 AnchorSideRight.Side = asrBottom Left = 131 Height = 23 Top = 30 Width = 555 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 5 BorderSpacing.Top = 5 ItemHeight = 15 Style = csDropDownList TabOrder = 0 end object lblTooltipHidingDelay: TLabel AnchorSideLeft.Control = bvlToolTips2 AnchorSideTop.Control = cbToolTipHideTimeOut AnchorSideTop.Side = asrCenter Left = 5 Height = 15 Top = 62 Width = 107 Caption = 'Tooltip hiding delay:' FocusControl = cbToolTipHideTimeOut end object cbToolTipHideTimeOut: TComboBox AnchorSideLeft.Control = lblTooltipHidingDelay AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTooltipShowingMode AnchorSideTop.Side = asrBottom AnchorSideRight.Control = bvlToolTips2 AnchorSideRight.Side = asrBottom Left = 117 Height = 23 Top = 58 Width = 569 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 5 BorderSpacing.Top = 5 ItemHeight = 15 Style = csDropDownList TabOrder = 1 end end end object pnlShowTooltip: TPanel[3] Left = 0 Height = 39 Top = 0 Width = 826 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 39 ClientWidth = 826 TabOrder = 0 object chkShowToolTip: TCheckBox Left = 10 Height = 19 Top = 10 Width = 213 BorderSpacing.Around = 10 Caption = '&Show tooltip for files in the file panel' OnChange = chkShowToolTipChange TabOrder = 0 end end object pmFields: TPopupMenu[4] left = 160 top = 256 end object pmTooltipOther: TPopupMenu[5] left = 536 top = 40 object miToolTipsFileTypeDiscardModification: TMenuItem Caption = 'Discard Modifications' Enabled = False OnClick = miToolTipsFileTypeDiscardModificationClick end object miSeparator1: TMenuItem Caption = '-' end object miToolTipsFileTypeSortFileType: TMenuItem Caption = 'Sort Tooltip File Types' OnClick = miToolTipsFileTypeSortFileTypeClick end object miSeparator2: TMenuItem Caption = '-' end object miToolTipsFileTypeExport: TMenuItem Caption = 'Export...' OnClick = miToolTipsFileTypeExportClick end object miToolTipsFileTypeImport: TMenuItem Caption = 'Import...' OnClick = miToolTipsFileTypeImportClick end end object SaveTooltipFileTypeDialog: TSaveDialog[6] DefaultExt = '.*.tooltip' Filter = 'DC Tooltip files|*.tooltip|Any files|*.*' Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing, ofViewDetail] left = 664 top = 32 end object OpenTooltipFileTypeDialog: TOpenDialog[7] DefaultExt = '.*.tooltip' Filter = 'DC Tooltip Files|*.tooltip|Any files|*.*' Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] left = 720 top = 136 end end �����doublecmd-1.1.22/src/frames/foptionstooltips.lrj����������������������������������������������������0000644�0001750�0000144�00000007027�14743153644�021030� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":86863386,"name":"tfrmoptionstooltips.lbltooltipslistbox.caption","sourcebytes":[38,70,105,108,101,32,116,121,112,101,115,58],"value":"&File types:"}, {"hash":71137081,"name":"tfrmoptionstooltips.btnapplytooltipsfiletype.caption","sourcebytes":[65,38,112,112,108,121],"value":"A&pply"}, {"hash":277668,"name":"tfrmoptionstooltips.btnaddtooltipsfiletype.caption","sourcebytes":[65,38,100,100],"value":"A&dd"}, {"hash":4874969,"name":"tfrmoptionstooltips.btncopytooltipsfiletype.caption","sourcebytes":[67,111,112,38,121],"value":"Cop&y"}, {"hash":193742869,"name":"tfrmoptionstooltips.btnrenametooltipsfiletype.caption","sourcebytes":[38,82,101,110,97,109,101],"value":"&Rename"}, {"hash":78392485,"name":"tfrmoptionstooltips.btndeletetooltipsfiletype.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":181151662,"name":"tfrmoptionstooltips.btntooltipother.caption","sourcebytes":[79,116,104,38,101,114,46,46,46],"value":"Oth&er..."}, {"hash":1054,"name":"tfrmoptionstooltips.btnfieldslist.caption","sourcebytes":[62,62],"value":">>"}, {"hash":47236478,"name":"tfrmoptionstooltips.btnfieldssearchtemplate.hint","sourcebytes":[84,101,109,112,108,97,116,101,46,46,46],"value":"Template..."}, {"hash":141616458,"name":"tfrmoptionstooltips.lblfieldslist.caption","sourcebytes":[67,97,116,101,103,111,114,121,32,38,104,105,110,116,58],"value":"Category &hint:"}, {"hash":143501786,"name":"tfrmoptionstooltips.lblfieldsmask.caption","sourcebytes":[67,97,116,101,103,111,114,121,32,38,109,97,115,107,58],"value":"Category &mask:"}, {"hash":153365194,"name":"tfrmoptionstooltips.bvltooltips1.caption","sourcebytes":[84,111,111,108,116,105,112,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,102,111,114,32,115,101,108,101,99,116,101,100,32,102,105,108,101,32,116,121,112,101,58],"value":"Tooltip configuration for selected file type:"}, {"hash":85767978,"name":"tfrmoptionstooltips.bvltooltips2.caption","sourcebytes":[71,101,110,101,114,97,108,32,111,112,116,105,111,110,115,32,97,98,111,117,116,32,116,111,111,108,116,105,112,115,58],"value":"General options about tooltips:"}, {"hash":111140314,"name":"tfrmoptionstooltips.lbltooltipshowingmode.caption","sourcebytes":[84,111,111,108,116,105,112,32,115,104,111,119,105,110,103,32,109,111,100,101,58],"value":"Tooltip showing mode:"}, {"hash":241931610,"name":"tfrmoptionstooltips.lbltooltiphidingdelay.caption","sourcebytes":[84,111,111,108,116,105,112,32,104,105,100,105,110,103,32,100,101,108,97,121,58],"value":"Tooltip hiding delay:"}, {"hash":206895052,"name":"tfrmoptionstooltips.chkshowtooltip.caption","sourcebytes":[38,83,104,111,119,32,116,111,111,108,116,105,112,32,102,111,114,32,102,105,108,101,115,32,105,110,32,116,104,101,32,102,105,108,101,32,112,97,110,101,108],"value":"&Show tooltip for files in the file panel"}, {"hash":38327795,"name":"tfrmoptionstooltips.mitooltipsfiletypediscardmodification.caption","sourcebytes":[68,105,115,99,97,114,100,32,77,111,100,105,102,105,99,97,116,105,111,110,115],"value":"Discard Modifications"}, {"hash":24150067,"name":"tfrmoptionstooltips.mitooltipsfiletypesortfiletype.caption","sourcebytes":[83,111,114,116,32,84,111,111,108,116,105,112,32,70,105,108,101,32,84,121,112,101,115],"value":"Sort Tooltip File Types"}, {"hash":124337662,"name":"tfrmoptionstooltips.mitooltipsfiletypeexport.caption","sourcebytes":[69,120,112,111,114,116,46,46,46],"value":"Export..."}, {"hash":124338510,"name":"tfrmoptionstooltips.mitooltipsfiletypeimport.caption","sourcebytes":[73,109,112,111,114,116,46,46,46],"value":"Import..."} ]} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstooltips.pas����������������������������������������������������0000644�0001750�0000144�00000063072�14743153644�021026� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Tooltips options page Copyright (C) 2011-2021 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsToolTips; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, DividerBevel, Forms, Controls, StdCtrls, Buttons, Menus, ExtCtrls, Dialogs, fOptionsFrame, uInfoToolTip; type { TfrmOptionsToolTips } TfrmOptionsToolTips = class(TOptionsEditor) pnlGeneralToolTipsOptions: TPanel; pnlShowTooltip: TPanel; chkShowToolTip: TCheckBox; pnlToolTipsListbox: TPanel; lblToolTipsListBox: TLabel; lsbCustomFields: TListBox; splToolTips: TSplitter; pnlConfigurationToolTips: TPanel; pnlTooltipButtons: TPanel; btnApplyToolTipsFileType: TBitBtn; btnAddToolTipsFileType: TBitBtn; btnCopyToolTipsFileType: TBitBtn; btnRenameToolTipsFileType: TBitBtn; btnDeleteToolTipsFileType: TBitBtn; btnTooltipOther: TBitBtn; pnlActualToolTipsConfiguration: TPanel; bvlToolTips1: TDividerBevel; lblFieldsMask: TLabel; edtFieldsMask: TEdit; btnFieldsSearchTemplate: TBitBtn; lblFieldsList: TLabel; memFieldsList: TMemo; btnFieldsList: TButton; pmFields: TPopupMenu; bvlToolTips2: TDividerBevel; lblTooltipShowingMode: TLabel; cbTooltipShowingMode: TComboBox; lblTooltipHidingDelay: TLabel; cbToolTipHideTimeOut: TComboBox; pmTooltipOther: TPopupMenu; miToolTipsFileTypeDiscardModification: TMenuItem; miSeparator1: TMenuItem; miToolTipsFileTypeSortFileType: TMenuItem; miSeparator2: TMenuItem; miToolTipsFileTypeExport: TMenuItem; miToolTipsFileTypeImport: TMenuItem; OpenTooltipFileTypeDialog: TOpenDialog; SaveTooltipFileTypeDialog: TSaveDialog; procedure FillListBoxWithToolTipsList; procedure SetActiveButtonsBasedOnToolTipsQuantity; procedure LoadMemoWithThisHint(sHint: string); procedure LoadThisHintWithThisMemo(var sHint: string); procedure ActualSaveCurrentToolTips; procedure edtAnyChange({%H-}Sender: TObject); procedure SetConfigurationState(bConfigurationSaved: boolean); procedure chkShowToolTipChange(Sender: TObject); procedure lsbCustomFieldsSelectionChange({%H-}Sender: TObject; {%H-}User: boolean); procedure lsbCustomFieldsDragOver({%H-}Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean); procedure lsbCustomFieldsDragDrop({%H-}Sender, {%H-}Source: TObject; {%H-}X, Y: integer); procedure btnApplyToolTipsFileTypeClick({%H-}Sender: TObject); procedure btnAddToolTipsFileTypeClick({%H-}Sender: TObject); procedure btnCopyToolTipsFileTypeClick({%H-}Sender: TObject); procedure btnRenameToolTipsFileTypeClick({%H-}Sender: TObject); procedure btnDeleteToolTipsFileTypeClick({%H-}Sender: TObject); procedure btnTooltipOtherClick({%H-}Sender: TObject); procedure miToolTipsFileTypeDiscardModificationClick({%H-}Sender: TObject); procedure miToolTipsFileTypeSortFileTypeClick({%H-}Sender: TObject); procedure miToolTipsFileTypeExportClick({%H-}Sender: TObject); procedure miToolTipsFileTypeImportClick({%H-}Sender: TObject); procedure miPluginClick(Sender: TObject); procedure btnFieldsListClick({%H-}Sender: TObject); procedure btnFieldsSearchTemplateClick({%H-}Sender: TObject); function isUniqueFileType(paramNewName: string): boolean; procedure ClearData; private bCurrentlyLoadingSettings, bCurrentlyFilling: boolean; FFileInfoToolTipTemp: TFileInfoToolTip; protected procedure Init; override; procedure Load; override; procedure Done; override; function Save: TOptionsEditorSaveFlags; override; public class function GetIconIndex: integer; override; class function GetTitle: string; override; function IsSignatureComputedFromAllWindowComponents: boolean; override; function ExtraOptionsSignature(CurrentSignature: dword): dword; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. StrUtils, LCLProc, //DC DCStrUtils, uShowMsg, uComponentsSignature, fMaskInputDlg, uLng, uGlobs, uSearchTemplate, uFileFunctions; const CONFIG_NOTSAVED = False; CONFIG_SAVED = True; var iLastDisplayedIndex: integer = -1; { TfrmOptionsToolTips } { TfrmOptionsToolTips.Init } procedure TfrmOptionsToolTips.Init; begin FFileInfoToolTipTemp := TFileInfoToolTip.Create; bCurrentlyLoadingSettings := True; bCurrentlyFilling := True; ParseLineToList(rsToolTipModeList, cbTooltipShowingMode.Items); ParseLineToList(rsToolTipHideTimeOutList, cbToolTipHideTimeOut.Items); OpenTooltipFileTypeDialog.Filter := ParseLineToFileFilter([rsFilterDCToolTipFiles, '*.tooltip', rsFilterAnyFiles, AllFilesMask]); SaveTooltipFileTypeDialog.Filter := OpenTooltipFileTypeDialog.Filter; end; { TfrmOptionsToolTips.Load } procedure TfrmOptionsToolTips.Load; begin bCurrentlyLoadingSettings := True; try chkShowToolTip.Checked := gShowToolTip; cbTooltipShowingMode.ItemIndex := integer(gShowToolTipMode); cbToolTipHideTimeOut.ItemIndex := integer(gToolTipHideTimeOut); FFileInfoToolTipTemp.Assign(gFileInfoToolTip); FillListBoxWithToolTipsList; finally bCurrentlyLoadingSettings := False; end; end; { TfrmOptionsToolTips.Done } procedure TfrmOptionsToolTips.Done; begin if lsbCustomFields.ItemIndex <> -1 then if lsbCustomFields.ItemIndex < FFileInfoToolTipTemp.HintItemList.Count then iLastDisplayedIndex := lsbCustomFields.ItemIndex; FreeAndNil(FFileInfoToolTipTemp); end; { TfrmOptionsToolTips.Save } function TfrmOptionsToolTips.Save: TOptionsEditorSaveFlags; begin Result := []; if not lsbCustomFields.Enabled then ActualSaveCurrentToolTips; gShowToolTip := chkShowToolTip.Checked; gShowToolTipMode := TToolTipMode(cbTooltipShowingMode.ItemIndex); gToolTipHideTimeOut := TToolTipHideTimeOut(cbToolTipHideTimeOut.ItemIndex); gFileInfoToolTip.Assign(FFileInfoToolTipTemp); SetConfigurationState(CONFIG_SAVED); LastLoadedOptionSignature := ComputeCompleteOptionsSignature; end; { TfrmOptionsToolTips.GetIconIndex } class function TfrmOptionsToolTips.GetIconIndex: integer; begin Result := 19; end; { TfrmOptionsToolTips.GetTitle } class function TfrmOptionsToolTips.GetTitle: string; begin Result := rsOptionsEditorTooltips; end; { TfrmOptionsToolTips.IsSignatureComputedFromAllWindowComponents } function TfrmOptionsToolTips.IsSignatureComputedFromAllWindowComponents: boolean; begin Result := False; end; { TfrmOptionsToolTips.ExtraOptionsSignature } function TfrmOptionsToolTips.ExtraOptionsSignature(CurrentSignature: dword): dword; begin if not lsbCustomFields.Enabled then //If currently our Listbox is disabled, it's because we did at least one modification... Result := (LastLoadedOptionSignature xor $01) //...so let's make sure the reported signature for the whole thing is affected. else begin CurrentSignature := ComputeSignatureSingleComponent(chkShowToolTip, CurrentSignature); CurrentSignature := ComputeSignatureSingleComponent(cbTooltipShowingMode, CurrentSignature); CurrentSignature := ComputeSignatureSingleComponent(cbToolTipHideTimeOut, CurrentSignature); Result := FFileInfoToolTipTemp.ComputeSignature(CurrentSignature); end; end; { TfrmOptionsToolTips.FillListBoxWithToolTipsList } procedure TfrmOptionsToolTips.FillListBoxWithToolTipsList; var I, iRememberIndex: integer; begin bCurrentlyFilling := True; try iRememberIndex := lsbCustomFields.ItemIndex; lsbCustomFields.Clear; for I := 0 to pred(FFileInfoToolTipTemp.HintItemList.Count) do lsbCustomFields.Items.Add(FFileInfoToolTipTemp.HintItemList[I].Name); if lsbCustomFields.Items.Count > 0 then begin if (iRememberIndex <> -1) and (iRememberIndex < lsbCustomFields.Items.Count) then lsbCustomFields.ItemIndex := iRememberIndex else if (iLastDisplayedIndex <> -1) and (iLastDisplayedIndex < lsbCustomFields.Items.Count) then lsbCustomFields.ItemIndex := iLastDisplayedIndex else lsbCustomFields.ItemIndex := 0; end; SetActiveButtonsBasedOnToolTipsQuantity; btnApplyToolTipsFileType.Enabled := False; lsbCustomFieldsSelectionChange(lsbCustomFields, False); finally bCurrentlyFilling := False; end; end; { TfrmOptionsToolTips.SetActiveButtonsBasedOnToolTipsQuantity } procedure TfrmOptionsToolTips.SetActiveButtonsBasedOnToolTipsQuantity; begin btnAddToolTipsFileType.Enabled := lsbCustomFields.Enabled; btnCopyToolTipsFileType.Enabled := ((lsbCustomFields.Items.Count > 0) and (lsbCustomFields.Enabled)); btnRenameToolTipsFileType.Enabled := btnCopyToolTipsFileType.Enabled; btnDeleteToolTipsFileType.Enabled := btnCopyToolTipsFileType.Enabled; miToolTipsFileTypeSortFileType.Enabled := ((lsbCustomFields.Items.Count > 1) and (lsbCustomFields.Enabled)); miToolTipsFileTypeExport.Enabled := btnCopyToolTipsFileType.Enabled; end; { TfrmOptionsToolTips.LoadMemoWithThisHint } //To be backward compatible with past versions and existing config, let's keep the "/n" separator for each line. //[Plugin(<Exif>).Width{}]\nGenre:[Plugin(audioinfo).Genre{}] procedure TfrmOptionsToolTips.LoadMemoWithThisHint(sHint: string); var iStartingPoint, iPosDelimiter: integer; begin memFieldsList.Clear; iStartingPoint := 1; repeat iPosDelimiter := PosEx('\n', LowerCase(sHint), iStartingPoint); if iPosDelimiter <> 0 then begin memFieldsList.Lines.Add(copy(sHint, iStartingPoint, (iPosDelimiter - iStartingPoint))); iStartingPoint := iPosDelimiter + 2; end; until iPosDelimiter = 0; if iStartingPoint < length(sHint) then memFieldsList.Lines.Add(RightStr(sHint, succ(length(sHint) - iStartingPoint))); memFieldsList.SelStart := 0; end; { TfrmOptionsToolTips.LoadThisHintWithThisMemo } procedure TfrmOptionsToolTips.LoadThisHintWithThisMemo(var sHint: string); var iIndexLine: integer; begin sHint := ''; for iIndexLine := 0 to pred(memFieldsList.Lines.Count) do sHint := sHint + memFieldsList.Lines.Strings[iIndexLine] + IfThen(iIndexLine < pred(memFieldsList.Lines.Count), '\n', ''); end; { TfrmOptionsToolTips.ActualSaveCurrentToolTips } procedure TfrmOptionsToolTips.ActualSaveCurrentToolTips; begin if lsbCustomFields.ItemIndex <> -1 then begin FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Name := lsbCustomFields.Items.Strings[lsbCustomFields.ItemIndex]; FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Mask := edtFieldsMask.Text; LoadThisHintWithThisMemo(FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Hint); end; end; { TfrmOptionsToolTips.edtAnyChange } procedure TfrmOptionsToolTips.edtAnyChange(Sender: TObject); begin if not bCurrentlyLoadingSettings then if lsbCustomFields.Enabled then SetConfigurationState(CONFIG_NOTSAVED); end; { TfrmOptionsToolTips.SetConfigurationState } procedure TfrmOptionsToolTips.SetConfigurationState(bConfigurationSaved: boolean); begin if lsbCustomFields.Enabled <> bConfigurationSaved then begin chkShowToolTip.Enabled := bConfigurationSaved; btnApplyToolTipsFileType.Enabled := not bConfigurationSaved; lsbCustomFields.Enabled := bConfigurationSaved; btnAddToolTipsFileType.Enabled := bConfigurationSaved; btnCopyToolTipsFileType.Enabled := bConfigurationSaved; btnRenameToolTipsFileType.Enabled := bConfigurationSaved; btnDeleteToolTipsFileType.Enabled := bConfigurationSaved; miToolTipsFileTypeDiscardModification.Enabled := not bConfigurationSaved; miToolTipsFileTypeSortFileType.Enabled := bConfigurationSaved; miToolTipsFileTypeExport.Enabled := bConfigurationSaved; miToolTipsFileTypeImport.Enabled := bConfigurationSaved; lsbCustomFields.Hint := IfThen(bConfigurationSaved = CONFIG_SAVED, EmptyStr, rsOptTooltipConfigureSaveToChange); end; end; { TfrmOptionsToolTips.chkShowToolTipChange } procedure TfrmOptionsToolTips.chkShowToolTipChange(Sender: TObject); begin pnlConfigurationToolTips.Enabled := TCheckBox(Sender).Checked; pnlToolTipsListbox.Enabled := pnlConfigurationToolTips.Enabled; end; { lsbCustomFieldsSelectionChange } procedure TfrmOptionsToolTips.lsbCustomFieldsSelectionChange(Sender: TObject; User: boolean); begin bCurrentlyLoadingSettings := True; pnlActualToolTipsConfiguration.Enabled:= lsbCustomFields.ItemIndex <> -1; if pnlActualToolTipsConfiguration.Enabled then begin edtFieldsMask.Text := FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Mask; LoadMemoWithThisHint(FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Hint); end; bCurrentlyLoadingSettings := False; end; { TfrmOptionsToolTips.lsbCustomFieldsDragOver } procedure TfrmOptionsToolTips.lsbCustomFieldsDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin Accept := True; end; { TfrmOptionsToolTips.lsbCustomFieldsDragDrop } procedure TfrmOptionsToolTips.lsbCustomFieldsDragDrop(Sender, Source: TObject; X, Y: integer); var SrcIndex, DestIndex: integer; begin SrcIndex := lsbCustomFields.ItemIndex; if SrcIndex = -1 then Exit; DestIndex := lsbCustomFields.GetIndexAtY(Y); if (DestIndex < 0) or (DestIndex >= lsbCustomFields.Count) then DestIndex := lsbCustomFields.Count - 1; lsbCustomFields.Items.Move(SrcIndex, DestIndex); FFileInfoToolTipTemp.HintItemList.Move(SrcIndex, DestIndex); lsbCustomFields.ItemIndex := DestIndex; lsbCustomFieldsSelectionChange(lsbCustomFields, False); end; { TfrmOptionsToolTips.btnApplyToolTipsFileTypeClick } procedure TfrmOptionsToolTips.btnApplyToolTipsFileTypeClick(Sender: TObject); begin Save; if lsbCustomFields.CanFocus then lsbCustomFields.SetFocus; end; {TfrmOptionsToolTips.btnCopyToolTipsFileTypeClick } procedure TfrmOptionsToolTips.btnCopyToolTipsFileTypeClick(Sender: TObject); var sCurrentSelectedName, sNewName: string; iIndexCopy, iPosOpenPar, iNewInsertedPosition: integer; ANewHintItem: THintItem; begin if lsbCustomFields.ItemIndex < 0 then Exit; sCurrentSelectedName := lsbCustomFields.Items.Strings[lsbCustomFields.ItemIndex]; if LastDelimiter(')', sCurrentSelectedName) = length(sCurrentSelectedName) then begin iPosOpenPar := LastDelimiter('(', sCurrentSelectedName); if (iPosOpenPar > 0) and (iPosOpenPar > (length(sCurrentSelectedName) - 4)) then sCurrentSelectedName := LeftStr(sCurrentSelectedName, pred(pred(iPosOpenPar))); end; iIndexCopy := 2; while lsbCustomFields.Items.IndexOf(Format('%s (%d)', [sCurrentSelectedName, iIndexCopy])) <> -1 do Inc(iIndexCopy); sNewName := Format('%s (%d)', [sCurrentSelectedName, iIndexCopy]); ANewHintItem := FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Clone; //Let's place our copy right after the original one. iNewInsertedPosition := succ(lsbCustomFields.ItemIndex); if iNewInsertedPosition < FFileInfoToolTipTemp.HintItemList.Count then begin lsbCustomFields.Items.Insert(iNewInsertedPosition, sNewName); FFileInfoToolTipTemp.HintItemList.Insert(iNewInsertedPosition, ANewHintItem); end else begin lsbCustomFields.Items.Add(sNewName); FFileInfoToolTipTemp.HintItemList.Add(ANewHintItem); end; lsbCustomFields.ItemIndex := iNewInsertedPosition; SetActiveButtonsBasedOnToolTipsQuantity; if edtFieldsMask.CanFocus then edtFieldsMask.SetFocus; end; { TfrmOptionsToolTips.btnAddToolTipsFileTypeClick } procedure TfrmOptionsToolTips.btnAddToolTipsFileTypeClick(Sender: TObject); var sName: string; ANewHintItem: THintItem; begin sName := EmptyStr; if InputQuery(rsOptAddingToolTipFileType, rsOptToolTipFileType, sName) then begin if sName <> EmptyStr then begin if isUniqueFileType(sName) then begin ANewHintItem := THintItem.Create; ANewHintItem.Name := sName; FFileInfoToolTipTemp.HintItemList.Add(ANewHintItem); lsbCustomFields.ItemIndex := lsbCustomFields.Items.Add(sName); lsbCustomFieldsSelectionChange(lsbCustomFields, False); ClearData; SetActiveButtonsBasedOnToolTipsQuantity; if edtFieldsMask.CanFocus then edtFieldsMask.SetFocus; end; end; end; end; { TfrmOptionsToolTips.btnRenameToolTipsFileTypeClick } procedure TfrmOptionsToolTips.btnRenameToolTipsFileTypeClick(Sender: TObject); var sNewName: string; begin if lsbCustomFields.ItemIndex < 0 then Exit; sNewName := lsbCustomFields.Items.Strings[lsbCustomFields.ItemIndex]; if InputQuery(rsOptRenamingToolTipFileType, rsOptToolTipsFileTypeName, sNewName) then begin if isUniqueFileType(sNewName) then if lsbCustomFields.Items.IndexOf(sNewName) = -1 then begin lsbCustomFields.Items.Strings[lsbCustomFields.ItemIndex] := sNewName; FFileInfoToolTipTemp.HintItemList[lsbCustomFields.ItemIndex].Name := sNewName; end else begin msgError(Format(rsOptToolTipFileTypeAlreadyExists, [sNewName])); end; end; end; { TfrmOptionsToolTips.btnDeleteToolTipsFileTypeClick } procedure TfrmOptionsToolTips.btnDeleteToolTipsFileTypeClick(Sender: TObject); var iIndexDelete: longint; begin iIndexDelete := lsbCustomFields.ItemIndex; if (iIndexDelete < 0) then Exit; if MsgBox(Format(rsOptToolTipFileTypeConfirmDelete, [lsbCustomFields.Items.Strings[lsbCustomFields.ItemIndex]]), [msmbYes, msmbCancel], msmbCancel, msmbCancel) = mmrYes then begin bCurrentlyFilling := True; try lsbCustomFields.Items.Delete(iIndexDelete); FFileInfoToolTipTemp.HintItemList.Delete(iIndexDelete); if lsbCustomFields.Items.Count > 0 then begin if iIndexDelete >= FFileInfoToolTipTemp.HintItemList.Count then lsbCustomFields.ItemIndex := pred(FFileInfoToolTipTemp.HintItemList.Count) else lsbCustomFields.ItemIndex := iIndexDelete; end else begin ClearData; end; lsbCustomFieldsSelectionChange(lsbCustomFields, False); SetActiveButtonsBasedOnToolTipsQuantity; if edtFieldsMask.CanFocus then edtFieldsMask.SetFocus; finally bCurrentlyFilling := False; end; end; end; { TfrmOptionsToolTips.btnTooltipOtherClick } procedure TfrmOptionsToolTips.btnTooltipOtherClick(Sender: TObject); var pWantedPos: TPoint; begin pWantedPos := btnTooltipOther.ClientToScreen(Point(btnTooltipOther.Width div 2, btnTooltipOther.Height - 5)); // Position this way instead of using mouse cursor since it will work for keyboard user. pmTooltipOther.PopUp(pWantedPos.X, pWantedPos.Y); end; { TfrmOptionsToolTips.miToolTipsFileTypeDiscardModificationClick } procedure TfrmOptionsToolTips.miToolTipsFileTypeDiscardModificationClick(Sender: TObject); begin FFileInfoToolTipTemp.Assign(gFileInfoToolTip); FillListBoxWithToolTipsList; SetConfigurationState(CONFIG_SAVED); SetActiveButtonsBasedOnToolTipsQuantity; end; { TfrmOptionsToolTips.miToolTipsFileTypeSortFileTypeClick } procedure TfrmOptionsToolTips.miToolTipsFileTypeSortFileTypeClick(Sender: TObject); begin if FFileInfoToolTipTemp.HintItemList.Count > 0 then begin FFileInfoToolTipTemp.Sort; FillListBoxWithToolTipsList; end; end; { TfrmOptionsToolTips.miToolTipsFileTypeExportClick } procedure TfrmOptionsToolTips.miToolTipsFileTypeExportClick(Sender: TObject); var slValueList, slOutputIndexSelected: TStringList; ExportedFileInfoToolTipTemp: TFileInfoToolTip; iIndex, iExportedIndex: integer; begin if FFileInfoToolTipTemp.HintItemList.Count > 0 then begin slValueList := TStringList.Create; slOutputIndexSelected := TStringList.Create; try for iIndex := 0 to pred(FFileInfoToolTipTemp.HintItemList.Count) do slValueList.Add(FFileInfoToolTipTemp.HintItemList[iIndex].Name); if ShowInputMultiSelectListBox(rsOptToolTipFileTypeExportCaption, rsOptToolTipFileTypeExportPrompt, slValueList, slOutputIndexSelected) then begin ExportedFileInfoToolTipTemp := TFileInfoToolTip.Create; try for iIndex := 0 to pred(slOutputIndexSelected.Count) do begin iExportedIndex := StrToIntDef(slOutputIndexSelected.Strings[iIndex], -1); if iExportedIndex <> -1 then ExportedFileInfoToolTipTemp.HintItemList.Add(FFileInfoToolTipTemp.HintItemList[iExportedIndex].Clone); end; if ExportedFileInfoToolTipTemp.HintItemList.Count > 0 then begin SaveTooltipFileTypeDialog.DefaultExt := '*.tooltip'; SaveTooltipFileTypeDialog.FilterIndex := 1; SaveTooltipFileTypeDialog.Title := rsOptToolTipFileTypeWhereToSave; SaveTooltipFileTypeDialog.FileName := rsOptToolTipFileTypeDefaultExportFilename; if SaveTooltipFileTypeDialog.Execute then begin ExportedFileInfoToolTipTemp.SaveToFile(SaveTooltipFileTypeDialog.FileName); msgOK(Format(rsOptToolTipFileTypeExportDone, [ExportedFileInfoToolTipTemp.HintItemList.Count, SaveTooltipFileTypeDialog.FileName])); end; end; finally ExportedFileInfoToolTipTemp.Free; end; end; finally slOutputIndexSelected.Free; slValueList.Free; end; end; end; { TfrmOptionsToolTips.miToolTipsFileTypeImportClick} procedure TfrmOptionsToolTips.miToolTipsFileTypeImportClick(Sender: TObject); var ImportedFileInfoToolTipTemp: TFileInfoToolTip; slValueList, slOutputIndexSelected: TStringList; iIndex, iImportedIndex, iNbImported: integer; begin OpenTooltipFileTypeDialog.DefaultExt := '*.tooltip'; OpenTooltipFileTypeDialog.FilterIndex := 1; OpenTooltipFileTypeDialog.Title := rsOptToolTipFileTypeImportFile; if OpenTooltipFileTypeDialog.Execute then begin ImportedFileInfoToolTipTemp := TFileInfoToolTip.Create; try ImportedFileInfoToolTipTemp.LoadFromFile(OpenTooltipFileTypeDialog.FileName); if ImportedFileInfoToolTipTemp.HintItemList.Count > 0 then begin slValueList := TStringList.Create; slOutputIndexSelected := TStringList.Create; try for iIndex := 0 to pred(ImportedFileInfoToolTipTemp.HintItemList.Count) do slValueList.Add(ImportedFileInfoToolTipTemp.HintItemList[iIndex].Name); if ShowInputMultiSelectListBox(rsOptToolTipFileTypeImportCaption, rsOptToolTipFileTypeImportPrompt, slValueList, slOutputIndexSelected) then begin iNbImported := 0; for iIndex := 0 to pred(slOutputIndexSelected.Count) do begin iImportedIndex := StrToIntDef(slOutputIndexSelected.Strings[iIndex], -1); if iImportedIndex <> -1 then begin FFileInfoToolTipTemp.HintItemList.Add(ImportedFileInfoToolTipTemp.HintItemList[iImportedIndex].Clone); lsbCustomFields.Items.add(FFileInfoToolTipTemp.HintItemList[pred(FFileInfoToolTipTemp.HintItemList.Count)].Name); Inc(iNbImported); end; end; lsbCustomFields.ItemIndex := lsbCustomFields.Items.Count - 1; if iNbImported > 0 then begin SetActiveButtonsBasedOnToolTipsQuantity; msgOK(Format(rsOptToolTipFileTypeImportDone, [iNbImported, OpenTooltipFileTypeDialog.FileName])); end; end; finally slOutputIndexSelected.Free; slValueList.Free; end; end; finally ImportedFileInfoToolTipTemp.Free; end; end; end; { TfrmOptionsToolTips.miPluginClick } procedure TfrmOptionsToolTips.miPluginClick(Sender: TObject); var sMask: string; MenuItem: TMenuItem absolute Sender; begin case MenuItem.Tag of 0: sMask := '[DC().' + MenuItem.Hint + '{}]'; 1: sMask := '[Plugin(' + MenuItem.Parent.Caption + ').' + MenuItem.Hint + '{}]'; 2: sMask := '[Plugin(' + MenuItem.Parent.Parent.Caption + ').' + MenuItem.Parent.Hint + '{' + MenuItem.Hint + '}]'; 3: sMask := '[DC().' + MenuItem.Parent.Hint + '{' + MenuItem.Hint + '}] '; else sMask := EmptyStr; end; if sMask <> EmptyStr then begin memFieldsList.SelText := sMask; if memFieldsList.CanFocus then memFieldsList.SetFocus; end; end; { TfrmOptionsToolTips.btnFieldsListClick } procedure TfrmOptionsToolTips.btnFieldsListClick(Sender: TObject); begin FillContentFieldMenu(pmFields.Items, @miPluginClick); pmFields.PopUp(Mouse.CursorPos.x, Mouse.CursorPos.y); end; { TfrmOptionsToolTips.btnFieldsSearchTemplateClick } procedure TfrmOptionsToolTips.btnFieldsSearchTemplateClick(Sender: TObject); var sMask: string; bTemplate: boolean; begin sMask := ''; if ShowMaskInputDlg(rsMarkPlus, rsMaskInput, glsMaskHistory, sMask) then begin bTemplate := IsMaskSearchTemplate(sMask); edtFieldsMask.Text := sMask; edtFieldsMask.Enabled := not bTemplate; end; end; { TfrmOptionsToolTips.isUniqueFileType } function TfrmOptionsToolTips.isUniqueFileType(paramNewName: string): boolean; begin Result := (lsbCustomFields.Items.IndexOf(paramNewName) = -1); if not Result then msgError(Format(rsOptToolTipFileTypeAlreadyExists, [paramNewName])); end; { TfrmOptionsToolTips.ClearData } procedure TfrmOptionsToolTips.ClearData; begin bCurrentlyLoadingSettings := True; edtFieldsMask.Text := EmptyStr; memFieldsList.Clear; bCurrentlyLoadingSettings := False; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstreeviewmenu.lfm������������������������������������������������0000644�0001750�0000144�00000017627�14743153644�021670� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsTreeViewMenu: TfrmOptionsTreeViewMenu Height = 415 Width = 590 HelpKeyword = '/configuration.html#ConfigTreeMenu' AutoSize = True ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 415 ClientWidth = 590 Constraints.MinHeight = 400 Constraints.MinWidth = 500 ParentShowHint = False ShowHint = True DesignLeft = 289 DesignTop = 231 object gbTreeViewMenuSettings: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 403 Top = 6 Width = 578 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True Caption = 'Tree View Menus related options:' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ClientHeight = 383 ClientWidth = 574 TabOrder = 0 object gbWhereToUseTreeViewMenu: TGroupBox AnchorSideLeft.Control = gbTreeViewMenuSettings AnchorSideTop.Control = gbTreeViewMenuSettings AnchorSideRight.Control = gbTreeViewMenuSettings AnchorSideRight.Side = asrBottom Left = 10 Height = 230 Top = 6 Width = 554 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Where to use Tree View Menus:' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ClientHeight = 210 ClientWidth = 550 TabOrder = 0 object lblUseInDirectoryHotlist: TLabel AnchorSideLeft.Control = gbWhereToUseTreeViewMenu AnchorSideTop.Control = gbWhereToUseTreeViewMenu Left = 10 Height = 15 Top = 6 Width = 117 Caption = 'With Directory Hotlist:' ParentColor = False end object ckbDirectoryHotlistFromMenuCommand: TCheckBox AnchorSideLeft.Control = lblUseInDirectoryHotlist AnchorSideTop.Control = lblUseInDirectoryHotlist AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 21 Width = 223 BorderSpacing.Left = 6 Caption = 'With the menu and internal command' TabOrder = 0 end object ckbDirectoryHotlistFromDoubleClick: TCheckBox AnchorSideLeft.Control = ckbDirectoryHotlistFromMenuCommand AnchorSideTop.Control = ckbDirectoryHotlistFromMenuCommand AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 40 Width = 283 Caption = 'With double-click on the bar on top of a file panel' TabOrder = 1 end object lblUseWithFavoriteTabs: TLabel AnchorSideLeft.Control = gbWhereToUseTreeViewMenu AnchorSideTop.Control = ckbDirectoryHotlistFromDoubleClick AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 69 Width = 100 BorderSpacing.Top = 10 Caption = 'With Favorite Tabs:' ParentColor = False end object ckbFavoritaTabsFromMenuCommand: TCheckBox AnchorSideLeft.Control = lblUseInDirectoryHotlist AnchorSideTop.Control = lblUseWithFavoriteTabs AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 84 Width = 223 BorderSpacing.Left = 6 Caption = 'With the menu and internal command' TabOrder = 2 end object ckbFavoriteTabsFromDoubleClick: TCheckBox AnchorSideLeft.Control = ckbDirectoryHotlistFromMenuCommand AnchorSideTop.Control = ckbFavoritaTabsFromMenuCommand AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 103 Width = 267 Caption = 'With double-click on a tab (if configured for it)' TabOrder = 3 end object lblUseWithHistory: TLabel AnchorSideLeft.Control = gbWhereToUseTreeViewMenu AnchorSideTop.Control = ckbFavoriteTabsFromDoubleClick AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 132 Width = 69 BorderSpacing.Top = 10 Caption = 'With History:' ParentColor = False end object ckbUseForDirHistory: TCheckBox AnchorSideLeft.Control = lblUseInDirectoryHotlist AnchorSideTop.Control = lblUseWithHistory AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 147 Width = 146 BorderSpacing.Left = 6 Caption = 'Use it for the Dir History' TabOrder = 4 end object ckbUseForViewHistory: TCheckBox AnchorSideLeft.Control = lblUseInDirectoryHotlist AnchorSideTop.Control = ckbUseForDirHistory AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 166 Width = 313 BorderSpacing.Left = 6 Caption = 'Use it for the View History (Visited paths for active view)' TabOrder = 5 end object ckbUseForCommandLineHistory: TCheckBox AnchorSideLeft.Control = lblUseInDirectoryHotlist AnchorSideTop.Control = ckbUseForViewHistory AnchorSideTop.Side = asrBottom Left = 16 Height = 19 Top = 185 Width = 193 BorderSpacing.Left = 6 Caption = 'Use it for Command Line History' TabOrder = 6 end end object gbBehavior: TGroupBox AnchorSideLeft.Control = gbWhereToUseTreeViewMenu AnchorSideTop.Control = gbWhereToUseTreeViewMenu AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbTreeViewMenuSettings AnchorSideRight.Side = asrBottom Left = 10 Height = 89 Top = 246 Width = 554 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 10 Caption = 'Behavior regarding selection:' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ClientHeight = 69 ClientWidth = 550 TabOrder = 1 object ckbShortcutSelectAndClose: TCheckBox AnchorSideLeft.Control = gbBehavior AnchorSideTop.Control = gbBehavior Left = 10 Height = 19 Top = 6 Width = 473 Caption = 'When using the keyboard shortcut, it will exit the window returning the current choice' TabOrder = 0 end object ckbSingleClickSelect: TCheckBox AnchorSideLeft.Control = ckbShortcutSelectAndClose AnchorSideTop.Control = ckbShortcutSelectAndClose AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 25 Width = 231 Caption = 'Single mouse click in tree select and exit' TabOrder = 1 end object ckbDoubleClickSelect: TCheckBox AnchorSideLeft.Control = ckbShortcutSelectAndClose AnchorSideTop.Control = ckbSingleClickSelect AnchorSideTop.Side = asrBottom Left = 10 Height = 19 Top = 44 Width = 198 Caption = 'Double click in tree select and exit' TabOrder = 2 end end object lblNote: TLabel AnchorSideLeft.Control = gbTreeViewMenuSettings AnchorSideTop.Control = gbBehavior AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbTreeViewMenuSettings AnchorSideRight.Side = asrBottom Left = 10 Height = 30 Top = 345 Width = 550 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 10 Caption = '*NOTE: Regarding the options like the case sensitivity, ignoring accents or not, these are saved and restored individually for each context from a usage and session to another.' Constraints.MaxWidth = 550 ParentColor = False WordWrap = True end end end ���������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstreeviewmenu.lrj������������������������������������������������0000644�0001750�0000144�00000012647�14743153644�021676� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":125359418,"name":"tfrmoptionstreeviewmenu.gbtreeviewmenusettings.caption","sourcebytes":[84,114,101,101,32,86,105,101,119,32,77,101,110,117,115,32,114,101,108,97,116,101,100,32,111,112,116,105,111,110,115,58],"value":"Tree View Menus related options:"}, {"hash":238805770,"name":"tfrmoptionstreeviewmenu.gbwheretousetreeviewmenu.caption","sourcebytes":[87,104,101,114,101,32,116,111,32,117,115,101,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117,115,58],"value":"Where to use Tree View Menus:"}, {"hash":114703482,"name":"tfrmoptionstreeviewmenu.lbluseindirectoryhotlist.caption","sourcebytes":[87,105,116,104,32,68,105,114,101,99,116,111,114,121,32,72,111,116,108,105,115,116,58],"value":"With Directory Hotlist:"}, {"hash":153935412,"name":"tfrmoptionstreeviewmenu.ckbdirectoryhotlistfrommenucommand.caption","sourcebytes":[87,105,116,104,32,116,104,101,32,109,101,110,117,32,97,110,100,32,105,110,116,101,114,110,97,108,32,99,111,109,109,97,110,100],"value":"With the menu and internal command"}, {"hash":198705532,"name":"tfrmoptionstreeviewmenu.ckbdirectoryhotlistfromdoubleclick.caption","sourcebytes":[87,105,116,104,32,100,111,117,98,108,101,45,99,108,105,99,107,32,111,110,32,116,104,101,32,98,97,114,32,111,110,32,116,111,112,32,111,102,32,97,32,102,105,108,101,32,112,97,110,101,108],"value":"With double-click on the bar on top of a file panel"}, {"hash":25578842,"name":"tfrmoptionstreeviewmenu.lblusewithfavoritetabs.caption","sourcebytes":[87,105,116,104,32,70,97,118,111,114,105,116,101,32,84,97,98,115,58],"value":"With Favorite Tabs:"}, {"hash":153935412,"name":"tfrmoptionstreeviewmenu.ckbfavoritatabsfrommenucommand.caption","sourcebytes":[87,105,116,104,32,116,104,101,32,109,101,110,117,32,97,110,100,32,105,110,116,101,114,110,97,108,32,99,111,109,109,97,110,100],"value":"With the menu and internal command"}, {"hash":217214649,"name":"tfrmoptionstreeviewmenu.ckbfavoritetabsfromdoubleclick.caption","sourcebytes":[87,105,116,104,32,100,111,117,98,108,101,45,99,108,105,99,107,32,111,110,32,97,32,116,97,98,32,40,105,102,32,99,111,110,102,105,103,117,114,101,100,32,102,111,114,32,105,116,41],"value":"With double-click on a tab (if configured for it)"}, {"hash":245484810,"name":"tfrmoptionstreeviewmenu.lblusewithhistory.caption","sourcebytes":[87,105,116,104,32,72,105,115,116,111,114,121,58],"value":"With History:"}, {"hash":5303177,"name":"tfrmoptionstreeviewmenu.ckbusefordirhistory.caption","sourcebytes":[85,115,101,32,105,116,32,102,111,114,32,116,104,101,32,68,105,114,32,72,105,115,116,111,114,121],"value":"Use it for the Dir History"}, {"hash":200045257,"name":"tfrmoptionstreeviewmenu.ckbuseforviewhistory.caption","sourcebytes":[85,115,101,32,105,116,32,102,111,114,32,116,104,101,32,86,105,101,119,32,72,105,115,116,111,114,121,32,40,86,105,115,105,116,101,100,32,112,97,116,104,115,32,102,111,114,32,97,99,116,105,118,101,32,118,105,101,119,41],"value":"Use it for the View History (Visited paths for active view)"}, {"hash":205832569,"name":"tfrmoptionstreeviewmenu.ckbuseforcommandlinehistory.caption","sourcebytes":[85,115,101,32,105,116,32,102,111,114,32,67,111,109,109,97,110,100,32,76,105,110,101,32,72,105,115,116,111,114,121],"value":"Use it for Command Line History"}, {"hash":137041466,"name":"tfrmoptionstreeviewmenu.gbbehavior.caption","sourcebytes":[66,101,104,97,118,105,111,114,32,114,101,103,97,114,100,105,110,103,32,115,101,108,101,99,116,105,111,110,58],"value":"Behavior regarding selection:"}, {"hash":131316693,"name":"tfrmoptionstreeviewmenu.ckbshortcutselectandclose.caption","sourcebytes":[87,104,101,110,32,117,115,105,110,103,32,116,104,101,32,107,101,121,98,111,97,114,100,32,115,104,111,114,116,99,117,116,44,32,105,116,32,119,105,108,108,32,101,120,105,116,32,116,104,101,32,119,105,110,100,111,119,32,114,101,116,117,114,110,105,110,103,32,116,104,101,32,99,117,114,114,101,110,116,32,99,104,111,105,99,101],"value":"When using the keyboard shortcut, it will exit the window returning the current choice"}, {"hash":112843860,"name":"tfrmoptionstreeviewmenu.ckbsingleclickselect.caption","sourcebytes":[83,105,110,103,108,101,32,109,111,117,115,101,32,99,108,105,99,107,32,105,110,32,116,114,101,101,32,115,101,108,101,99,116,32,97,110,100,32,101,120,105,116],"value":"Single mouse click in tree select and exit"}, {"hash":16466372,"name":"tfrmoptionstreeviewmenu.ckbdoubleclickselect.caption","sourcebytes":[68,111,117,98,108,101,32,99,108,105,99,107,32,105,110,32,116,114,101,101,32,115,101,108,101,99,116,32,97,110,100,32,101,120,105,116],"value":"Double click in tree select and exit"}, {"hash":7462014,"name":"tfrmoptionstreeviewmenu.lblnote.caption","sourcebytes":[42,78,79,84,69,58,32,82,101,103,97,114,100,105,110,103,32,116,104,101,32,111,112,116,105,111,110,115,32,108,105,107,101,32,116,104,101,32,99,97,115,101,32,115,101,110,115,105,116,105,118,105,116,121,44,32,105,103,110,111,114,105,110,103,32,97,99,99,101,110,116,115,32,111,114,32,110,111,116,44,32,116,104,101,115,101,32,97,114,101,32,115,97,118,101,100,32,97,110,100,32,114,101,115,116,111,114,101,100,32,105,110,100,105,118,105,100,117,97,108,108,121,32,102,111,114,32,101,97,99,104,32,99,111,110,116,101,120,116,32,102,114,111,109,32,97,32,117,115,97,103,101,32,97,110,100,32,115,101,115,115,105,111,110,32,116,111,32,97,110,111,116,104,101,114,46],"value":"*NOTE: Regarding the options like the case sensitivity, ignoring accents or not, these are saved and restored individually for each context from a usage and session to another."} ]} �����������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstreeviewmenu.pas������������������������������������������������0000644�0001750�0000144�00000011467�14743153644�021671� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Configuration of TreeView Menu behavior options. Copyright (C) 2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit fOptionsTreeViewMenu; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, ExtCtrls, Menus, Dialogs, //DC fOptionsFrame; type { TfrmOptionsTreeViewMenu } TfrmOptionsTreeViewMenu = class(TOptionsEditor) gbTreeViewMenuSettings: TGroupBox; gbWhereToUseTreeViewMenu: TGroupBox; lblUseInDirectoryHotlist: TLabel; ckbDirectoryHotlistFromMenuCommand: TCheckBox; ckbDirectoryHotlistFromDoubleClick: TCheckBox; lblUseWithFavoriteTabs: TLabel; ckbFavoritaTabsFromMenuCommand: TCheckBox; ckbFavoriteTabsFromDoubleClick: TCheckBox; lblUseWithHistory: TLabel; ckbUseForDirHistory: TCheckBox; ckbUseForViewHistory: TCheckBox; ckbUseForCommandLineHistory: TCheckBox; gbBehavior: TGroupBox; ckbShortcutSelectAndClose: TCheckBox; ckbSingleClickSelect: TCheckBox; ckbDoubleClickSelect: TCheckBox; lblNote: TLabel; protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; public { Public declarations } class function GetIconIndex: integer; override; class function GetTitle: string; override; destructor Destroy; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Graphics, LCLType, LCLProc, LCLIntf, //DC uGlobs, uLng, fmain, DCOSUtils; { TfrmOptionsTreeViewMenu.Init } procedure TfrmOptionsTreeViewMenu.Init; begin //Nothing here for the moment, but let's take the good habit to reserve the place to load eventual TComboBox and stuff like that with a ressource form the language file. end; { TfrmOptionsTreeViewMenu.Load } procedure TfrmOptionsTreeViewMenu.Load; begin ckbDirectoryHotlistFromMenuCommand.Checked := gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand; ckbDirectoryHotlistFromDoubleClick.Checked := gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick; ckbFavoritaTabsFromMenuCommand.Checked := gUseTreeViewMenuWithFavoriteTabsFromMenuCommand; ckbFavoriteTabsFromDoubleClick.Checked := gUseTreeViewMenuWithFavoriteTabsFromDoubleClick; ckbUseForDirHistory.Checked := gUseTreeViewMenuWithDirHistory; ckbUseForViewHistory.Checked := gUseTreeViewMenuWithViewHistory; ckbUseForCommandLineHistory.Checked := gUseTreeViewMenuWithCommandLineHistory; ckbShortcutSelectAndClose.Checked := gTreeViewMenuShortcutExit; ckbSingleClickSelect.Checked := gTreeViewMenuSingleClickExit; ckbDoubleClickSelect.Checked := gTreeViewMenuDoubleClickExit; end; { TfrmOptionsTreeViewMenu.Save } function TfrmOptionsTreeViewMenu.Save: TOptionsEditorSaveFlags; begin Result := []; gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand := ckbDirectoryHotlistFromMenuCommand.Checked; gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick := ckbDirectoryHotlistFromDoubleClick.Checked; gUseTreeViewMenuWithFavoriteTabsFromMenuCommand := ckbFavoritaTabsFromMenuCommand.Checked; gUseTreeViewMenuWithFavoriteTabsFromDoubleClick := ckbFavoriteTabsFromDoubleClick.Checked; gUseTreeViewMenuWithDirHistory := ckbUseForDirHistory.Checked; gUseTreeViewMenuWithViewHistory := ckbUseForViewHistory.Checked; gUseTreeViewMenuWithCommandLineHistory := ckbUseForCommandLineHistory.Checked; gTreeViewMenuShortcutExit := ckbShortcutSelectAndClose.Checked; gTreeViewMenuSingleClickExit := ckbSingleClickSelect.Checked; gTreeViewMenuDoubleClickExit := ckbDoubleClickSelect.Checked; end; { TfrmOptionsTreeViewMenu.GetIconIndex } class function TfrmOptionsTreeViewMenu.GetIconIndex: integer; begin Result := 39; end; { TfrmOptionsTreeViewMenu.GetTitle } class function TfrmOptionsTreeViewMenu.GetTitle: string; begin Result := rsOptionsEditorTreeViewMenu; end; { TfrmOptionsTreeViewMenu.Destroy } destructor TfrmOptionsTreeViewMenu.Destroy; begin inherited Destroy; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstreeviewmenucolor.lfm�������������������������������������������0000644�0001750�0000144�00000042424�14743153644�022720� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmOptionsTreeViewMenuColor: TfrmOptionsTreeViewMenuColor Height = 478 Width = 600 HelpKeyword = '/configuration.html#ConfigTreeMenuColor' AutoSize = True ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 478 ClientWidth = 600 Constraints.MinHeight = 400 Constraints.MinWidth = 500 ParentShowHint = False ShowHint = True DesignLeft = 418 DesignTop = 264 object gbLayoutAndColors: TGroupBox[0] AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 387 Top = 10 Width = 588 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 10 Caption = 'Layout and colors options:' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 6 ClientHeight = 367 ClientWidth = 584 TabOrder = 0 object cbkUsageKeyboardShortcut: TCheckBox AnchorSideLeft.Control = gbLayoutAndColors AnchorSideTop.Control = gbLayoutAndColors Left = 10 Height = 19 Top = 6 Width = 303 Caption = 'Use and display keyboard shortcut for choosing items' OnChange = RefreshColorOfOurSampleClick TabOrder = 0 end object lblBackgroundColor: TLabel Tag = 1 AnchorSideTop.Control = cbBackgroundColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 59 Height = 15 Top = 34 Width = 97 Anchors = [akTop, akRight] Caption = 'Background color:' FocusControl = cbBackgroundColor ParentColor = False end object cbBackgroundColor: TKASColorBoxButton Tag = 1 AnchorSideLeft.Control = gbLayoutAndColors AnchorSideTop.Control = cbkUsageKeyboardShortcut AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 29 Width = 126 TabOrder = 1 BorderSpacing.Left = 160 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblShortcutColor: TLabel Tag = 2 AnchorSideTop.Control = cbShortcutColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = cbShortcutColor Left = 78 Height = 15 Top = 62 Width = 78 Anchors = [akTop, akRight] BorderSpacing.Right = 4 Caption = 'Shortcut color:' FocusControl = cbShortcutColor ParentColor = False end object cbShortcutColor: TKASColorBoxButton Tag = 2 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbBackgroundColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 57 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 2 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblNormalTextColor: TLabel Tag = 3 AnchorSideTop.Control = cbNormalTextColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 60 Height = 15 Top = 90 Width = 96 Anchors = [akTop, akRight] Caption = 'Normal text color:' FocusControl = cbNormalTextColor ParentColor = False end object cbNormalTextColor: TKASColorBoxButton Tag = 3 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbShortcutColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 85 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 3 Constraints.MinWidth = 100 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblSecondaryTextColor: TLabel Tag = 4 AnchorSideTop.Control = cbSecondaryTextColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 45 Height = 15 Top = 118 Width = 111 Anchors = [akTop, akRight] Caption = 'Secondary text color:' FocusControl = cbSecondaryTextColor ParentColor = False end object cbSecondaryTextColor: TKASColorBoxButton Tag = 4 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbNormalTextColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 113 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 4 Constraints.MinWidth = 100 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblFoundTextColor: TLabel Tag = 5 AnchorSideTop.Control = cbFoundTextColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 66 Height = 15 Top = 146 Width = 90 Anchors = [akTop, akRight] Caption = 'Found text color:' FocusControl = cbFoundTextColor ParentColor = False end object cbFoundTextColor: TKASColorBoxButton Tag = 5 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbSecondaryTextColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 141 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 5 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblUnselectableTextColor: TLabel Tag = 6 AnchorSideTop.Control = cbUnselectableTextColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 33 Height = 15 Top = 174 Width = 123 Anchors = [akTop, akRight] Caption = 'Unselectable text color:' FocusControl = cbUnselectableTextColor ParentColor = False end object cbUnselectableTextColor: TKASColorBoxButton Tag = 6 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbFoundTextColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 169 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 6 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblCursorColor: TLabel Tag = 7 AnchorSideTop.Control = cbCursorColor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 88 Height = 15 Top = 202 Width = 68 Anchors = [akTop, akRight] Caption = 'Cursor color:' FocusControl = cbCursorColor ParentColor = False end object cbCursorColor: TKASColorBoxButton Tag = 7 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbUnselectableTextColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 197 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 7 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblShortcutUnderCursor: TLabel Tag = 8 AnchorSideTop.Control = cbShortcutUnderCursor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 38 Height = 15 Top = 230 Width = 118 Anchors = [akTop, akRight] Caption = 'Shortcut under cursor:' FocusControl = cbShortcutUnderCursor ParentColor = False end object cbShortcutUnderCursor: TKASColorBoxButton Tag = 8 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbCursorColor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 225 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 8 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblNormalTextUnderCursor: TLabel Tag = 9 AnchorSideTop.Control = cbNormalTextUnderCursor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 20 Height = 15 Top = 258 Width = 136 Anchors = [akTop, akRight] Caption = 'Normal text under cursor:' FocusControl = cbNormalTextUnderCursor ParentColor = False end object cbNormalTextUnderCursor: TKASColorBoxButton Tag = 9 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbShortcutUnderCursor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 253 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 9 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblSecondaryTextUnderCursor: TLabel Tag = 10 AnchorSideTop.Control = cbSecondaryTextUnderCursor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 5 Height = 15 Top = 286 Width = 151 Anchors = [akTop, akRight] Caption = 'Secondary text under cursor:' FocusControl = cbSecondaryTextUnderCursor ParentColor = False end object cbSecondaryTextUnderCursor: TKASColorBoxButton Tag = 10 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbNormalTextUnderCursor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 281 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 10 Constraints.MinWidth = 100 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblFoundTextUnderCursor: TLabel Tag = 11 AnchorSideTop.Control = cbFoundTextUnderCursor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 26 Height = 15 Top = 314 Width = 130 Anchors = [akTop, akRight] Caption = 'Found text under cursor:' FocusControl = cbFoundTextUnderCursor ParentColor = False end object cbFoundTextUnderCursor: TKASColorBoxButton Tag = 11 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbSecondaryTextUnderCursor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 309 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 11 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblUnselectableUnderCursor: TLabel Tag = 12 AnchorSideTop.Control = cbUnselectableUnderCursor AnchorSideTop.Side = asrCenter AnchorSideRight.Control = lblShortcutColor AnchorSideRight.Side = asrBottom Left = 16 Height = 15 Top = 342 Width = 140 Anchors = [akTop, akRight] Caption = 'Unselectable under cursor:' FocusControl = cbUnselectableUnderCursor ParentColor = False end object cbUnselectableUnderCursor: TKASColorBoxButton Tag = 12 AnchorSideLeft.Control = cbBackgroundColor AnchorSideTop.Control = cbFoundTextUnderCursor AnchorSideTop.Side = asrBottom AnchorSideRight.Control = cbBackgroundColor AnchorSideRight.Side = asrBottom Left = 160 Height = 24 Top = 337 Width = 126 Anchors = [akTop, akLeft, akRight] TabOrder = 12 BorderSpacing.Top = 4 OnChange = RefreshColorOfOurSampleClick ColorDialog = optColorDialog end object lblPreview: TLabel AnchorSideLeft.Control = TreeViewMenuSample AnchorSideTop.Control = cbkUsageKeyboardShortcut AnchorSideTop.Side = asrCenter AnchorSideRight.Control = TreeViewMenuSample AnchorSideRight.Side = asrBottom Left = 296 Height = 15 Top = 8 Width = 278 Alignment = taCenter Anchors = [akTop, akLeft, akRight] Caption = 'Tree View Menu Preview:' Color = clInactiveCaption ParentColor = False Transparent = False end object TreeViewMenuSample: TTreeView AnchorSideLeft.Control = cbNormalTextUnderCursor AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = lblPreview AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbLayoutAndColors AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = gbLayoutAndColors AnchorSideBottom.Side = asrBottom Left = 296 Height = 338 Hint = 'Change color on left and you''ll see here a preview of what your Tree View Menus will look likes with this sample.' Top = 23 Width = 278 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 10 BackgroundColor = clBtnFace Color = clBtnFace ReadOnly = True ScrollBars = ssNone TabOrder = 13 OnMouseWheelDown = TreeViewMenuSampleMouseWheelDown OnMouseWheelUp = TreeViewMenuSampleMouseWheelUp Options = [tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end end object gbFont: TGroupBox[1] AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbLayoutAndColors AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 55 Top = 397 Width = 588 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Font' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ClientHeight = 35 ClientWidth = 584 TabOrder = 1 object edFontName: TEdit AnchorSideLeft.Control = gbFont AnchorSideTop.Control = gbFont AnchorSideRight.Control = sedFont Left = 6 Height = 23 Top = 6 Width = 411 Anchors = [akTop, akLeft, akRight] Enabled = False ReadOnly = True TabOrder = 0 end object sedFont: TSpinEdit AnchorSideTop.Control = edFontName AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btFont Left = 420 Height = 23 Top = 6 Width = 120 Anchors = [akTop, akRight] OnChange = sedFontChange TabOrder = 1 Value = 12 end object btFont: TButton AnchorSideTop.Control = edFontName AnchorSideRight.Control = gbFont AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edFontName AnchorSideBottom.Side = asrBottom Left = 543 Height = 23 Top = 6 Width = 35 Anchors = [akTop, akRight, akBottom] AutoSize = True Caption = '...' OnClick = btFontClick TabOrder = 2 end end object optColorDialog: TColorDialog[2] Color = clBlack CustomColors.Strings = ( 'ColorA=000000' 'ColorB=000080' 'ColorC=008000' 'ColorD=008080' 'ColorE=800000' 'ColorF=800080' 'ColorG=808000' 'ColorH=808080' 'ColorI=C0C0C0' 'ColorJ=0000FF' 'ColorK=00FF00' 'ColorL=00FFFF' 'ColorM=FF0000' 'ColorN=FF00FF' 'ColorO=FFFF00' 'ColorP=FFFFFF' 'ColorQ=C0DCC0' 'ColorR=F0CAA6' 'ColorS=F0FBFF' 'ColorT=A4A0A0' ) Left = 488 Top = 288 end object dlgFnt: TFontDialog[3] MinFontSize = 0 MaxFontSize = 0 Options = [fdNoStyleSel] Left = 416 Top = 344 end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstreeviewmenucolor.lrj�������������������������������������������0000644�0001750�0000144�00000010250�14743153644�022721� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":159890218,"name":"tfrmoptionstreeviewmenucolor.gblayoutandcolors.caption","sourcebytes":[76,97,121,111,117,116,32,97,110,100,32,99,111,108,111,114,115,32,111,112,116,105,111,110,115,58],"value":"Layout and colors options:"}, {"hash":31991555,"name":"tfrmoptionstreeviewmenucolor.cbkusagekeyboardshortcut.caption","sourcebytes":[85,115,101,32,97,110,100,32,100,105,115,112,108,97,121,32,107,101,121,98,111,97,114,100,32,115,104,111,114,116,99,117,116,32,102,111,114,32,99,104,111,111,115,105,110,103,32,105,116,101,109,115],"value":"Use and display keyboard shortcut for choosing items"}, {"hash":140314666,"name":"tfrmoptionstreeviewmenucolor.lblbackgroundcolor.caption","sourcebytes":[66,97,99,107,103,114,111,117,110,100,32,99,111,108,111,114,58],"value":"Background color:"}, {"hash":2155466,"name":"tfrmoptionstreeviewmenucolor.lblshortcutcolor.caption","sourcebytes":[83,104,111,114,116,99,117,116,32,99,111,108,111,114,58],"value":"Shortcut color:"}, {"hash":231377482,"name":"tfrmoptionstreeviewmenucolor.lblnormaltextcolor.caption","sourcebytes":[78,111,114,109,97,108,32,116,101,120,116,32,99,111,108,111,114,58],"value":"Normal text color:"}, {"hash":127674394,"name":"tfrmoptionstreeviewmenucolor.lblsecondarytextcolor.caption","sourcebytes":[83,101,99,111,110,100,97,114,121,32,116,101,120,116,32,99,111,108,111,114,58],"value":"Secondary text color:"}, {"hash":11769210,"name":"tfrmoptionstreeviewmenucolor.lblfoundtextcolor.caption","sourcebytes":[70,111,117,110,100,32,116,101,120,116,32,99,111,108,111,114,58],"value":"Found text color:"}, {"hash":261168186,"name":"tfrmoptionstreeviewmenucolor.lblunselectabletextcolor.caption","sourcebytes":[85,110,115,101,108,101,99,116,97,98,108,101,32,116,101,120,116,32,99,111,108,111,114,58],"value":"Unselectable text color:"}, {"hash":208506970,"name":"tfrmoptionstreeviewmenucolor.lblcursorcolor.caption","sourcebytes":[67,117,114,115,111,114,32,99,111,108,111,114,58],"value":"Cursor color:"}, {"hash":153885482,"name":"tfrmoptionstreeviewmenucolor.lblshortcutundercursor.caption","sourcebytes":[83,104,111,114,116,99,117,116,32,117,110,100,101,114,32,99,117,114,115,111,114,58],"value":"Shortcut under cursor:"}, {"hash":4629498,"name":"tfrmoptionstreeviewmenucolor.lblnormaltextundercursor.caption","sourcebytes":[78,111,114,109,97,108,32,116,101,120,116,32,117,110,100,101,114,32,99,117,114,115,111,114,58],"value":"Normal text under cursor:"}, {"hash":23119450,"name":"tfrmoptionstreeviewmenucolor.lblsecondarytextundercursor.caption","sourcebytes":[83,101,99,111,110,100,97,114,121,32,116,101,120,116,32,117,110,100,101,114,32,99,117,114,115,111,114,58],"value":"Secondary text under cursor:"}, {"hash":66678826,"name":"tfrmoptionstreeviewmenucolor.lblfoundtextundercursor.caption","sourcebytes":[70,111,117,110,100,32,116,101,120,116,32,117,110,100,101,114,32,99,117,114,115,111,114,58],"value":"Found text under cursor:"}, {"hash":258370346,"name":"tfrmoptionstreeviewmenucolor.lblunselectableundercursor.caption","sourcebytes":[85,110,115,101,108,101,99,116,97,98,108,101,32,117,110,100,101,114,32,99,117,114,115,111,114,58],"value":"Unselectable under cursor:"}, {"hash":251513754,"name":"tfrmoptionstreeviewmenucolor.lblpreview.caption","sourcebytes":[84,114,101,101,32,86,105,101,119,32,77,101,110,117,32,80,114,101,118,105,101,119,58],"value":"Tree View Menu Preview:"}, {"hash":108342734,"name":"tfrmoptionstreeviewmenucolor.treeviewmenusample.hint","sourcebytes":[67,104,97,110,103,101,32,99,111,108,111,114,32,111,110,32,108,101,102,116,32,97,110,100,32,121,111,117,39,108,108,32,115,101,101,32,104,101,114,101,32,97,32,112,114,101,118,105,101,119,32,111,102,32,119,104,97,116,32,121,111,117,114,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117,115,32,119,105,108,108,32,108,111,111,107,32,108,105,107,101,115,32,119,105,116,104,32,116,104,105,115,32,115,97,109,112,108,101,46],"value":"Change color on left and you'll see here a preview of what your Tree View Menus will look likes with this sample."}, {"hash":317012,"name":"tfrmoptionstreeviewmenucolor.gbfont.caption","sourcebytes":[70,111,110,116],"value":"Font"}, {"hash":12558,"name":"tfrmoptionstreeviewmenucolor.btfont.caption","sourcebytes":[46,46,46],"value":"..."} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/foptionstreeviewmenucolor.pas�������������������������������������������0000644�0001750�0000144�00000033662�14743153644�022731� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Configuration of Tree View Menu Color and Layout. Copyright (C) 2016-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fOptionsTreeViewMenuColor; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. SysUtils, Classes, Controls, Forms, StdCtrls, Buttons, ExtCtrls, Menus, Dialogs, ComCtrls, KASComboBox, Spin, LMessages, //DC uGlobs, fOptionsFrame, fTreeViewMenu, Types; type { TfrmOptionsTreeViewMenuColor } TfrmOptionsTreeViewMenuColor = class(TOptionsEditor) btFont: TButton; dlgFnt: TFontDialog; edFontName: TEdit; sedFont: TSpinEdit; gbFont: TGroupBox; gbLayoutAndColors: TGroupBox; cbkUsageKeyboardShortcut: TCheckBox; lblBackgroundColor: TLabel; cbBackgroundColor: TKASColorBoxButton; lblShortcutColor: TLabel; cbShortcutColor: TKASColorBoxButton; lblNormalTextColor: TLabel; cbNormalTextColor: TKASColorBoxButton; lblSecondaryTextColor: TLabel; cbSecondaryTextColor: TKASColorBoxButton; lblFoundTextColor: TLabel; cbFoundTextColor: TKASColorBoxButton; lblUnselectableTextColor: TLabel; cbUnselectableTextColor: TKASColorBoxButton; lblCursorColor: TLabel; cbCursorColor: TKASColorBoxButton; lblShortcutUnderCursor: TLabel; cbShortcutUnderCursor: TKASColorBoxButton; lblNormalTextUnderCursor: TLabel; cbNormalTextUnderCursor: TKASColorBoxButton; lblSecondaryTextUnderCursor: TLabel; cbSecondaryTextUnderCursor: TKASColorBoxButton; lblFoundTextUnderCursor: TLabel; cbFoundTextUnderCursor: TKASColorBoxButton; lblUnselectableUnderCursor: TLabel; cbUnselectableUnderCursor: TKASColorBoxButton; lblPreview: TLabel; TreeViewMenuSample: TTreeView; optColorDialog: TColorDialog; procedure btFontClick(Sender: TObject); procedure RefreshColorOfOurSampleClick(Sender: TObject); procedure sedFontChange(Sender: TObject); procedure TreeViewMenuSampleMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure TreeViewMenuSampleMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); protected procedure Init; override; procedure Load; override; function Save: TOptionsEditorSaveFlags; override; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; private { Private declarations } TreeViewMenuGenericRoutineAndVarHolder: TTreeViewMenuGenericRoutineAndVarHolder; TempoFont: TDCFontOptions; procedure ApplyTempoFontToVisual; public { Public declarations } class function GetIconIndex: integer; override; class function GetTitle: string; override; destructor Destroy; override; end; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Graphics, LCLType, LCLProc, LCLIntf, //DC uLng, uDCUtils, fmain, DCOSUtils; { TfrmOptionsTreeViewMenuColor.Init } procedure TfrmOptionsTreeViewMenuColor.Init; var iLonguestName: integer = 150; BaseLevelNode, SubLevelNode: TTreeNode; procedure ProcessLabelLength(ALabel: TLabel); begin if ALabel.Canvas.TextWidth(ALabel.Caption) > iLonguestName then iLonguestName := ALabel.Canvas.TextWidth(ALabel.Caption); end; begin // All the combobox are referenced to "cbBackgroundColor". // Let's determine the longuest label and then we'll set the "cbBackgroundColor" to a location far enough on right so all labels will be visible correctly. ProcessLabelLength(lblBackgroundColor); ProcessLabelLength(lblShortcutColor); ProcessLabelLength(lblNormalTextColor); ProcessLabelLength(lblSecondaryTextColor); ProcessLabelLength(lblFoundTextColor); ProcessLabelLength(lblUnselectableTextColor); ProcessLabelLength(lblCursorColor); ProcessLabelLength(lblShortcutUnderCursor); ProcessLabelLength(lblNormalTextUnderCursor); ProcessLabelLength(lblSecondaryTextUnderCursor); ProcessLabelLength(lblFoundTextUnderCursor); ProcessLabelLength(lblUnselectableUnderCursor); cbBackgroundColor.Left := 10 + iLonguestName + 6 + 10; cbBackgroundColor.BorderSpacing.Left:=10 + iLonguestName + 6 + 10; TreeViewMenuGenericRoutineAndVarHolder := TTreeViewMenuGenericRoutineAndVarHolder.Create; TreeViewMenuGenericRoutineAndVarHolder.SearchingText := rsStrPreviewSearchingLetters; TreeViewMenuGenericRoutineAndVarHolder.CaseSensitive := False; TreeViewMenuGenericRoutineAndVarHolder.IgnoreAccents := True; TreeViewMenuGenericRoutineAndVarHolder.ShowWholeBranchIfMatch := True; TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode := False; TreeViewMenuGenericRoutineAndVarHolder.ShowShortcut := gTreeViewMenuUseKeyboardShortcut; with gColors.TreeViewMenu^ do begin TreeViewMenuGenericRoutineAndVarHolder.BackgroundColor := BackgroundColor; TreeViewMenuGenericRoutineAndVarHolder.ShortcutColor := ShortcutColor; TreeViewMenuGenericRoutineAndVarHolder.NormalTextColor := NormalTextColor; TreeViewMenuGenericRoutineAndVarHolder.SecondaryTextColor := SecondaryTextColor; TreeViewMenuGenericRoutineAndVarHolder.FoundTextColor := FoundTextColor; TreeViewMenuGenericRoutineAndVarHolder.UnselectableTextColor := UnselectableTextColor; TreeViewMenuGenericRoutineAndVarHolder.CursorColor := CursorColor; TreeViewMenuGenericRoutineAndVarHolder.ShortcutUnderCursor := ShortcutUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.NormalTextUnderCursor := NormalTextUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.SecondaryTextUnderCursor := SecondaryTextUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.FoundTextUnderCursor := FoundTextUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.UnselectableUnderCursor := UnselectableUnderCursor; end; TreeViewMenuSample.OnAdvancedCustomDrawItem := @TreeViewMenuGenericRoutineAndVarHolder.TreeViewMenuAdvancedCustomDrawItem; // Let's populate our treeview sample with at least an example of each. TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, nil, rsStrPreviewJustPreview); BaseLevelNode := TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, nil, 'Double Commander'); SubLevelNode := TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, BaseLevelNode, rsStrPreviewWordWithSearched1, rsStrPreviewSideNote); TTreeMenuItem(SubLevelNode.Data).KeyboardShortcut := '1'; SubLevelNode := TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, BaseLevelNode, rsStrPreviewWordWithSearched2, rsStrPreviewSideNote); TTreeMenuItem(SubLevelNode.Data).KeyboardShortcut := '2'; SubLevelNode := TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, BaseLevelNode, rsStrPreviewWordWithSearched3, rsStrPreviewSideNote); TTreeMenuItem(SubLevelNode.Data).KeyboardShortcut := '3'; BaseLevelNode := TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, nil, rsStrPreviewOthers); TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, BaseLevelNode, rsStrPreviewWordWithoutSearched1); TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, BaseLevelNode, rsStrPreviewWordWithoutSearched2); TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(TreeViewMenuSample, BaseLevelNode, rsStrPreviewWordWithoutSearched3); TreeViewMenuSample.FullExpand; TreeViewMenuSample.Items[0].Selected := True; end; { TfrmOptionsTreeViewMenuColor.Load } procedure TfrmOptionsTreeViewMenuColor.Load; begin cbkUsageKeyboardShortcut.Checked := gTreeViewMenuUseKeyboardShortcut; with gColors.TreeViewMenu^ do begin cbBackgroundColor.Selected := BackgroundColor; cbShortcutColor.Selected := ShortcutColor; cbNormalTextColor.Selected := NormalTextColor; cbSecondaryTextColor.Selected := SecondaryTextColor; cbFoundTextColor.Selected := FoundTextColor; cbUnselectableTextColor.Selected := UnselectableTextColor; cbCursorColor.Selected := CursorColor; cbShortcutUnderCursor.Selected := ShortcutUnderCursor; cbNormalTextUnderCursor.Selected := NormalTextUnderCursor; cbSecondaryTextUnderCursor.Selected := SecondaryTextUnderCursor; cbFoundTextUnderCursor.Selected := FoundTextUnderCursor; cbUnselectableUnderCursor.Selected := UnselectableUnderCursor; end; TempoFont := gFonts[dcfTreeViewMenu]; ApplyTempoFontToVisual; end; { TfrmOptionsTreeViewMenuColor.Save } function TfrmOptionsTreeViewMenuColor.Save: TOptionsEditorSaveFlags; begin Result := []; gTreeViewMenuUseKeyboardShortcut := cbkUsageKeyboardShortcut.Checked; with gColors.TreeViewMenu^ do begin BackgroundColor := cbBackgroundColor.Selected; ShortcutColor := cbShortcutColor.Selected; NormalTextColor := cbNormalTextColor.Selected; SecondaryTextColor := cbSecondaryTextColor.Selected; FoundTextColor := cbFoundTextColor.Selected; UnselectableTextColor := cbUnselectableTextColor.Selected; CursorColor := cbCursorColor.Selected; ShortcutUnderCursor := cbShortcutUnderCursor.Selected; NormalTextUnderCursor := cbNormalTextUnderCursor.Selected; SecondaryTextUnderCursor := cbSecondaryTextUnderCursor.Selected; FoundTextUnderCursor := cbFoundTextUnderCursor.Selected; UnselectableUnderCursor := cbUnselectableUnderCursor.Selected; end; gFonts[dcfTreeViewMenu] := TempoFont; end; procedure TfrmOptionsTreeViewMenuColor.CMThemeChanged(var Message: TLMessage); begin LoadSettings; RefreshColorOfOurSampleClick(Self); end; { TfrmOptionsTreeViewMenuColor.GetIconIndex } class function TfrmOptionsTreeViewMenuColor.GetIconIndex: integer; begin Result := 40; end; { TfrmOptionsTreeViewMenuColor.GetTitle } class function TfrmOptionsTreeViewMenuColor.GetTitle: string; begin Result := rsOptionsEditorTreeViewMenuColors; end; { TfrmOptionsTreeViewMenuColor.Destroy } destructor TfrmOptionsTreeViewMenuColor.Destroy; begin FreeAndNil(TreeViewMenuGenericRoutineAndVarHolder); inherited Destroy; end; { TfrmOptionsTreeViewMenuColor.RefreshColorOfOurSampleClick } procedure TfrmOptionsTreeViewMenuColor.RefreshColorOfOurSampleClick(Sender: TObject); begin TreeViewMenuGenericRoutineAndVarHolder.ShowShortcut := cbkUsageKeyboardShortcut.Checked; TreeViewMenuGenericRoutineAndVarHolder.BackgroundColor := cbBackgroundColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.ShortcutColor := cbShortcutColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.NormalTextColor := cbNormalTextColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.SecondaryTextColor := cbSecondaryTextColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.FoundTextColor := cbFoundTextColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.UnselectableTextColor := cbUnselectableTextColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.CursorColor := cbCursorColor.Selected; TreeViewMenuGenericRoutineAndVarHolder.ShortcutUnderCursor := cbShortcutUnderCursor.Selected; TreeViewMenuGenericRoutineAndVarHolder.NormalTextUnderCursor := cbNormalTextUnderCursor.Selected; TreeViewMenuGenericRoutineAndVarHolder.SecondaryTextUnderCursor := cbSecondaryTextUnderCursor.Selected; TreeViewMenuGenericRoutineAndVarHolder.FoundTextUnderCursor := cbFoundTextUnderCursor.Selected; TreeViewMenuGenericRoutineAndVarHolder.UnselectableUnderCursor := cbUnselectableUnderCursor.Selected; TreeViewMenuSample.Refresh; end; { TfrmOptionsTreeViewMenuColor.ApplyTempoFontToVisual } procedure TfrmOptionsTreeViewMenuColor.ApplyTempoFontToVisual; begin FontOptionsToFont(TempoFont, edFontName.Font); FontOptionsToFont(TempoFont, TreeViewMenuSample.Font); FontOptionsToFont(TempoFont, sedFont.Font); FontOptionsToFont(TempoFont, btFont.Font); edFontName.Text := TempoFont.Name; if sedFont.Value <> TempoFont.Size then sedFont.Value := TempoFont.Size; end; { TfrmOptionsTreeViewMenuColor.sedFontChange } procedure TfrmOptionsTreeViewMenuColor.sedFontChange(Sender: TObject); begin if TempoFont.Size <> TSpinEdit(Sender).Value then begin TempoFont.Size := TSpinEdit(Sender).Value; ApplyTempoFontToVisual; end; end; { TfrmOptionsTreeViewMenuColor.btFontClick } procedure TfrmOptionsTreeViewMenuColor.btFontClick(Sender: TObject); begin FontOptionsToFont(TempoFont, dlgFnt.Font); if dlgFnt.Execute then begin FontToFontOptions(dlgFnt.Font, TempoFont); ApplyTempoFontToVisual; end; end; { TfrmOptionsTreeViewMenuColor.TreeViewMenuSampleMouseWheelDown } procedure TfrmOptionsTreeViewMenuColor.TreeViewMenuSampleMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (Shift = [ssCtrl]) and (TempoFont.Size > TempoFont.MinValue) then begin dec(TempoFont.Size); ApplyTempoFontToVisual; Handled := True; end; end; { TfrmOptionsTreeViewMenuColor.TreeViewMenuSampleMouseWheelUp } procedure TfrmOptionsTreeViewMenuColor.TreeViewMenuSampleMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (Shift = [ssCtrl]) and (TempoFont.Size < TempoFont.MaxValue) then begin inc(TempoFont.Size); ApplyTempoFontToVisual; Handled := True; end; end; end. ������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/fquicksearch.lfm��������������������������������������������������������0000644�0001750�0000144�00000011603�14743153644�020023� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmQuickSearch: TfrmQuickSearch Left = 0 Height = 43 Top = 0 Width = 436 AutoSize = True ClientHeight = 43 ClientWidth = 436 OnExit = FrameExit TabOrder = 0 DesignLeft = 134 DesignTop = 120 object edtSearch: TEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = tglFilter Left = 2 Height = 23 Hint = 'Enter text to search for or filter by' Top = 2 Width = 211 Anchors = [akTop, akLeft, akRight] AutoSelect = False BorderSpacing.Around = 2 OnChange = edtSearchChange OnKeyDown = edtSearchKeyDown ParentShowHint = False ShowHint = True TabOrder = 0 end object tglFilter: TToggleBox AnchorSideTop.Control = edtSearch AnchorSideRight.Control = pnlOptions AnchorSideBottom.Control = edtSearch AnchorSideBottom.Side = asrBottom Left = 215 Height = 23 Hint = 'Toggle between search or filter' Top = 2 Width = 46 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Right = 2 Caption = 'Filter' OnChange = tglFilterChange OnMouseUp = btnMouseUp ParentShowHint = False ShowHint = True TabOrder = 1 TabStop = False end object btnCancel: TButton AnchorSideTop.Control = edtSearch AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edtSearch AnchorSideBottom.Side = asrBottom Left = 399 Height = 23 Hint = 'Close filter panel' Top = 2 Width = 33 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Right = 4 Caption = 'X' OnClick = btnCancelClick OnMouseUp = btnCancelMouseUp ParentShowHint = False ShowHint = True TabOrder = 3 TabStop = False end object pnlOptions: TPanel AnchorSideTop.Control = edtSearch AnchorSideRight.Control = btnCancel AnchorSideBottom.Control = edtSearch AnchorSideBottom.Side = asrBottom Left = 263 Height = 23 Top = 2 Width = 132 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Right = 4 BevelOuter = bvNone ClientHeight = 23 ClientWidth = 132 TabOrder = 2 object sbMatchBeginning: TSpeedButton AnchorSideLeft.Control = pnlOptions AnchorSideTop.Control = pnlOptions AnchorSideTop.Side = asrCenter Left = 0 Height = 24 Hint = 'Match Beginning' Top = -1 Width = 24 AllowAllUp = True Caption = '{' GroupIndex = 1 OnClick = sbMatchBeginningClick ShowHint = True ParentShowHint = False end object sbMatchEnding: TSpeedButton AnchorSideLeft.Control = sbMatchBeginning AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbMatchBeginning AnchorSideBottom.Control = sbMatchBeginning AnchorSideBottom.Side = asrBottom Left = 26 Height = 24 Hint = 'Match Ending' Top = -1 Width = 24 AllowAllUp = True Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 2 Caption = '}' GroupIndex = 2 OnClick = sbMatchEndingClick ShowHint = True ParentShowHint = False end object sbCaseSensitive: TSpeedButton AnchorSideLeft.Control = sbMatchEnding AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbMatchBeginning AnchorSideBottom.Control = sbMatchBeginning AnchorSideBottom.Side = asrBottom Left = 54 Height = 24 Hint = 'Case Sensitive' Top = -1 Width = 24 AllowAllUp = True Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 Caption = 'Aa' GroupIndex = 3 OnClick = sbCaseSensitiveClick ShowHint = True ParentShowHint = False end object sbFiles: TSpeedButton AnchorSideLeft.Control = sbCaseSensitive AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbMatchBeginning AnchorSideBottom.Control = sbMatchBeginning AnchorSideBottom.Side = asrBottom Left = 82 Height = 24 Hint = 'Files' Top = -1 Width = 24 AllowAllUp = True Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 Caption = 'F' GroupIndex = 4 OnClick = sbFilesAndDirectoriesClick ShowHint = True ParentShowHint = False end object sbDirectories: TSpeedButton AnchorSideLeft.Control = sbFiles AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbMatchBeginning AnchorSideBottom.Control = sbMatchBeginning AnchorSideBottom.Side = asrBottom Left = 108 Height = 24 Hint = 'Directories' Top = -1 Width = 24 AllowAllUp = True Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 2 Caption = 'D' GroupIndex = 5 OnClick = sbFilesAndDirectoriesClick ShowHint = True ParentShowHint = False end end end �����������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/fquicksearch.lrj��������������������������������������������������������0000644�0001750�0000144�00000004064�14743153644�020037� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":176342841,"name":"tfrmquicksearch.edtsearch.hint","sourcebytes":[69,110,116,101,114,32,116,101,120,116,32,116,111,32,115,101,97,114,99,104,32,102,111,114,32,111,114,32,102,105,108,116,101,114,32,98,121],"value":"Enter text to search for or filter by"}, {"hash":159680658,"name":"tfrmquicksearch.tglfilter.hint","sourcebytes":[84,111,103,103,108,101,32,98,101,116,119,101,101,110,32,115,101,97,114,99,104,32,111,114,32,102,105,108,116,101,114],"value":"Toggle between search or filter"}, {"hash":80755394,"name":"tfrmquicksearch.tglfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, {"hash":102446860,"name":"tfrmquicksearch.btncancel.hint","sourcebytes":[67,108,111,115,101,32,102,105,108,116,101,114,32,112,97,110,101,108],"value":"Close filter panel"}, {"hash":88,"name":"tfrmquicksearch.btncancel.caption","sourcebytes":[88],"value":"X"}, {"hash":125785463,"name":"tfrmquicksearch.sbmatchbeginning.hint","sourcebytes":[77,97,116,99,104,32,66,101,103,105,110,110,105,110,103],"value":"Match Beginning"}, {"hash":123,"name":"tfrmquicksearch.sbmatchbeginning.caption","sourcebytes":[123],"value":"{"}, {"hash":27002855,"name":"tfrmquicksearch.sbmatchending.hint","sourcebytes":[77,97,116,99,104,32,69,110,100,105,110,103],"value":"Match Ending"}, {"hash":125,"name":"tfrmquicksearch.sbmatchending.caption","sourcebytes":[125],"value":"}"}, {"hash":219680245,"name":"tfrmquicksearch.sbcasesensitive.hint","sourcebytes":[67,97,115,101,32,83,101,110,115,105,116,105,118,101],"value":"Case Sensitive"}, {"hash":1137,"name":"tfrmquicksearch.sbcasesensitive.caption","sourcebytes":[65,97],"value":"Aa"}, {"hash":5046979,"name":"tfrmquicksearch.sbfiles.hint","sourcebytes":[70,105,108,101,115],"value":"Files"}, {"hash":70,"name":"tfrmquicksearch.sbfiles.caption","sourcebytes":[70],"value":"F"}, {"hash":184387443,"name":"tfrmquicksearch.sbdirectories.hint","sourcebytes":[68,105,114,101,99,116,111,114,105,101,115],"value":"Directories"}, {"hash":68,"name":"tfrmquicksearch.sbdirectories.caption","sourcebytes":[68],"value":"D"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/fquicksearch.pas��������������������������������������������������������0000644�0001750�0000144�00000055540�14743153644�020040� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fQuickSearch; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, LCLType, ExtCtrls, Buttons; type TQuickSearchMode = (qsSearch, qsFilter, qsNone); TQuickSearchDirection = (qsdNone, qsdFirst, qsdLast, qsdNext, qsdPrevious); TQuickSearchMatch = (qsmBeginning, qsmEnding); TQuickSearchCase = (qscSensitive, qscInsensitive); TQuickSearchItems = (qsiFiles, qsiDirectories, qsiFilesAndDirectories); TQuickSearchCancelMode = (qscmNode, qscmAtLeastOneThenCancelIfNoFound, qscmCancelIfNoFound); TQuickSearchOptions = record Match: set of TQuickSearchMatch; SearchCase: TQuickSearchCase; Items: TQuickSearchItems; Direction: TQuickSearchDirection; LastSearchMode: TQuickSearchMode; CancelSearchMode: TQuickSearchCancelMode; end; TOnChangeSearch = procedure(Sender: TObject; ASearchText: String; const ASearchOptions: TQuickSearchOptions; InvertSelection: Boolean = False) of Object; TOnChangeFilter = procedure(Sender: TObject; AFilterText: String; const AFilterOptions: TQuickSearchOptions) of Object; TOnExecute = procedure(Sender: TObject) of Object; TOnHide = procedure(Sender: TObject) of Object; { TfrmQuickSearch } TfrmQuickSearch = class(TFrame) btnCancel: TButton; edtSearch: TEdit; pnlOptions: TPanel; sbMatchBeginning: TSpeedButton; sbMatchEnding: TSpeedButton; sbCaseSensitive: TSpeedButton; sbFiles: TSpeedButton; sbDirectories: TSpeedButton; tglFilter: TToggleBox; procedure btnCancelClick(Sender: TObject); procedure edtSearchChange(Sender: TObject); procedure edtSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FrameExit(Sender: TObject); procedure sbCaseSensitiveClick(Sender: TObject); procedure sbFilesAndDirectoriesClick(Sender: TObject); procedure sbMatchBeginningClick(Sender: TObject); procedure sbMatchEndingClick(Sender: TObject); procedure tglFilterChange(Sender: TObject); procedure btnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure btnCancelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private Options: TQuickSearchOptions; Mode: TQuickSearchMode; Active: Boolean; FilterOptions: TQuickSearchOptions; FilterText: String; Finalizing: Boolean; FUpdateCount: Integer; FNeedsChangeSearch: Boolean; FIntendedLeave: Boolean; procedure BeginUpdate; procedure CheckFilesOrDirectoriesDown; procedure EndUpdate; procedure DoHide; procedure DoOnChangeSearch; {en Loads control states from options values } procedure LoadControlStates; procedure PushFilter; procedure PopFilter; procedure ClearFilter; procedure CancelFilter; procedure SetFocus(Data: PtrInt); procedure ProcessParams(const SearchMode: TQuickSearchMode; const Params: array of String); public LimitedAutoHide: Boolean; OnChangeSearch: TOnChangeSearch; OnChangeFilter: TOnChangeFilter; OnExecute: TOnExecute; OnHide: TOnHide; constructor Create(TheOwner: TWinControl); reintroduce; destructor Destroy; override; procedure CloneTo(AQuickSearch: TfrmQuickSearch); procedure Execute(SearchMode: TQuickSearchMode; const Params: array of String; Char: TUTF8Char = #0); procedure Reset; procedure Finalize; function CheckSearchOrFilter(var Key: Word): Boolean; overload; function CheckSearchOrFilter(var UTF8Key: TUTF8Char): Boolean; overload; end; {en Allows to compare TQuickSearchOptions structures } operator = (qsOptions1, qsOptions2: TQuickSearchOptions) CompareResult: Boolean; implementation uses LazUTF8, uKeyboard, uGlobs, uFormCommands {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} , uFileView {$ENDIF} ; const { Parameters: "filter" - set filtering (on/off/toggle) "search" - set searching (on/off/cycle) "matchbeginning" - set match beginning option (on/off/toggle) "matchending" - set match ending option (on/off/toggle) "casesensitive" - set case sensitive searching (on/off/toggle) "files" - set filtering files (on/off/toggle) "directories" - set filtering directories (on/off/toggle) "filesdirectories" - toggle between files, directories and both (no value) "text"="<...>" - set <...> as new text to search/filter (string) 'toggle' switches between on and off 'cycle' goto to next, next, next and so one } // parameters for quick search / filter actions PARAMETER_FILTER = 'filter'; PARAMETER_SEARCH = 'search'; PARAMETER_DIRECTION = 'direction'; PARAMETER_MATCH_BEGINNING = 'matchbeginning'; PARAMETER_MATCH_ENDING = 'matchending'; PARAMETER_CASE_SENSITIVE = 'casesensitive'; PARAMETER_FILES = 'files'; PARAMETER_DIRECTORIES = 'directories'; PARAMETER_FILES_DIRECTORIES = 'filesdirectories'; PARAMETER_TEXT = 'text'; TOGGLE_VALUE = 'toggle'; CYCLE_VALUE = 'cycle'; FIRST_VALUE = 'first'; LAST_VALUE = 'last'; NEXT_VALUE = 'next'; {$R *.lfm} operator = (qsOptions1, qsOptions2: TQuickSearchOptions) CompareResult: Boolean; begin Result := True; if qsOptions1.Match <> qsOptions2.Match then Result := False; if qsOptions1.Items <> qsOptions2.Items then Result := False; if qsOptions1.SearchCase <> qsOptions2.SearchCase then Result := False; end; function GetBoolState(const Value: String; OldState: Boolean): Boolean; begin if Value = TOGGLE_VALUE then Result := not OldState else if not GetBoolValue(Value, Result) then Result := OldState; end; { TfrmQuickSearch } constructor TfrmQuickSearch.Create(TheOwner: TWinControl); begin inherited Create(TheOwner); Self.Parent := TheOwner; // load default options Options := gQuickSearchOptions; Options.LastSearchMode := qsNone; LoadControlStates; FilterOptions := gQuickSearchOptions; FilterText := EmptyStr; Finalizing := False; HotMan.Register(Self.edtSearch, 'Quick Search'); end; destructor TfrmQuickSearch.Destroy; begin if Assigned(HotMan) then HotMan.UnRegister(Self.edtSearch); inherited Destroy; end; procedure TfrmQuickSearch.CloneTo(AQuickSearch: TfrmQuickSearch); var TempEvent: TNotifyEvent; begin AQuickSearch.Active := Self.Active; AQuickSearch.Mode := Self.Mode; AQuickSearch.Options := Self.Options; AQuickSearch.LoadControlStates; AQuickSearch.FilterOptions := Self.FilterOptions; AQuickSearch.FilterText := Self.FilterText; TempEvent := AQuickSearch.edtSearch.OnChange; AQuickSearch.edtSearch.OnChange := nil; AQuickSearch.edtSearch.Text := Self.edtSearch.Text; AQuickSearch.edtSearch.SelStart := Self.edtSearch.SelStart; AQuickSearch.edtSearch.SelLength := Self.edtSearch.SelLength; AQuickSearch.edtSearch.OnChange := TempEvent; TempEvent := AQuickSearch.tglFilter.OnChange; AQuickSearch.tglFilter.OnChange := nil; AQuickSearch.tglFilter.Checked := Self.tglFilter.Checked; AQuickSearch.tglFilter.OnChange := TempEvent; AQuickSearch.Visible := Self.Visible; // Do not clone LimitedAutoHide but honor it instead, because it depends on the parent fileview if Self.Visible and not Self.edtSearch.Focused and Self.LimitedAutoHide and not AQuickSearch.LimitedAutoHide then AQuickSearch.FrameExit(nil); // do autohide if needed end; procedure TfrmQuickSearch.DoOnChangeSearch; begin if FUpdateCount > 0 then FNeedsChangeSearch := True else begin Options.LastSearchMode:=Self.Mode; case Self.Mode of qsSearch: if Assigned(Self.OnChangeSearch) then Self.OnChangeSearch(Self, edtSearch.Text, Options); qsFilter: if Assigned(Self.OnChangeFilter) then Self.OnChangeFilter(Self, edtSearch.Text, Options); end; FNeedsChangeSearch := False; end; end; procedure TfrmQuickSearch.Execute(SearchMode: TQuickSearchMode; const Params: array of String; Char: TUTF8Char = #0); begin Self.Visible := True; if not edtSearch.Focused then begin edtSearch.SetFocus; edtSearch.SelectAll; end; if Char <> #0 then edtSearch.SelText := Char; Self.Active := True; ProcessParams(SearchMode, Params); end; procedure TfrmQuickSearch.Reset; begin PopFilter; Options.LastSearchMode := qsNone; Options.Direction := qsdNone; Options.CancelSearchMode:=qscmNode; end; procedure TfrmQuickSearch.Finalize; begin Reset; Hide; end; { TfrmQuickSearch.ProcessParams } procedure TfrmQuickSearch.ProcessParams(const SearchMode: TQuickSearchMode; const Params: array of String); var Param: String; Value: String; bWeGotMainParam: boolean = False; bLegacyBehavior: boolean = False; begin BeginUpdate; try Options.Direction:=qsdNone; for Param in Params do begin if (SearchMode=qsFilter) AND (GetParamValue(Param, PARAMETER_FILTER, Value)) then begin if (Value <> TOGGLE_VALUE) then tglFilter.Checked := GetBoolState(Value, tglFilter.Checked) else tglFilter.Checked := (not tglFilter.Checked) OR (Options.LastSearchMode<>qsFilter); //With "toggle", if mode was not previously, we activate filter mode. bWeGotMainParam := True; end else if (SearchMode=qsSearch) AND (GetParamValue(Param, PARAMETER_FILTER, Value)) then //Legacy begin tglFilter.Checked := GetBoolState(Value, tglFilter.Checked); bWeGotMainParam := True; bLegacyBehavior:= True; end else if (SearchMode=qsSearch) AND (GetParamValue(Param, PARAMETER_SEARCH, Value)) then begin if (Value <> CYCLE_VALUE) then begin Options.CancelSearchMode:=qscmNode; if (Value <> TOGGLE_VALUE) then tglFilter.Checked := not (GetBoolState(Value, tglFilter.Checked)) else tglFilter.Checked := not((tglFilter.Checked) OR (Options.LastSearchMode<>qsSearch)); //With "toggle", if mode was not previously, we activate search mode. end else begin tglFilter.Checked:=FALSE; if Options.LastSearchMode<>qsSearch then begin Options.Direction:=qsdFirst; //With "cycle", if mode was not previously, we activate search mode AND do to first item Options.CancelSearchMode:=qscmAtLeastOneThenCancelIfNoFound; end else begin Options.Direction:=qsdNext; Options.CancelSearchMode:=qscmCancelIfNoFound; end; end; bWeGotMainParam := True; end else if (SearchMode=qsSearch) AND GetParamValue(Param, PARAMETER_DIRECTION, Value) then begin if Value = FIRST_VALUE then Options.Direction:=qsdFirst; if Value = LAST_VALUE then Options.Direction:=qsdLast; if Value = NEXT_VALUE then Options.Direction:=qsdNext; end else if GetParamValue(Param, PARAMETER_MATCH_BEGINNING, Value) then begin sbMatchBeginning.Down := GetBoolState(Value, sbMatchBeginning.Down); sbMatchBeginningClick(nil); end else if GetParamValue(Param, PARAMETER_MATCH_ENDING, Value) then begin sbMatchEnding.Down := GetBoolState(Value, sbMatchEnding.Down); sbMatchEndingClick(nil); end else if GetParamValue(Param, PARAMETER_CASE_SENSITIVE, Value) then begin sbCaseSensitive.Down := GetBoolState(Value, sbCaseSensitive.Down); sbCaseSensitiveClick(nil); end else if GetParamValue(Param, PARAMETER_FILES, Value) then begin sbFiles.Down := GetBoolState(Value, sbFiles.Down); sbFilesAndDirectoriesClick(nil); end else if GetParamValue(Param, PARAMETER_DIRECTORIES, Value) then begin sbDirectories.Down := GetBoolState(Value, sbDirectories.Down); sbFilesAndDirectoriesClick(nil); end else if Param = PARAMETER_FILES_DIRECTORIES then begin if sbFiles.Down and sbDirectories.Down then sbDirectories.Down := False else if sbFiles.Down then begin sbDirectories.Down := True; sbFiles.Down := False; end else if sbDirectories.Down then sbFiles.Down := True; sbFilesAndDirectoriesClick(nil); end else if GetParamValue(Param, PARAMETER_TEXT, Value) then begin edtSearch.Text := Value; edtSearch.SelectAll; end; end; CheckFilesOrDirectoriesDown; //If search or filter was called with no parameter... case SearchMode of qsSearch: if not bWeGotMainParam then tglFilter.Checked:=False; qsFilter: if not bWeGotMainParam then tglFilter.Checked:=True; end; if not bLegacyBehavior then begin case SearchMode of qsSearch: if tglFilter.Checked then CancelFilter; qsFilter: if not tglFilter.Checked then CancelFilter; end; end; finally EndUpdate; end; end; function TfrmQuickSearch.CheckSearchOrFilter(var Key: Word): Boolean; var ModifierKeys: TShiftState; SearchOrFilterModifiers: TShiftState; SearchMode: TQuickSearchMode; UTF8Char: TUTF8Char; KeyTypingModifier: TKeyTypingModifier; begin Result := False; ModifierKeys := GetKeyShiftStateEx; for KeyTypingModifier in TKeyTypingModifier do begin if gKeyTyping[KeyTypingModifier] in [ktaQuickSearch, ktaQuickFilter] then begin SearchOrFilterModifiers := TKeyTypingModifierToShift[KeyTypingModifier]; if ((SearchOrFilterModifiers <> []) and (ModifierKeys * KeyModifiersShortcutNoText = SearchOrFilterModifiers)) {$IFDEF MSWINDOWS} // Entering international characters with Ctrl+Alt on Windows. or (HasKeyboardAltGrKey and (SearchOrFilterModifiers = []) and (ModifierKeys * KeyModifiersShortcutNoText = [ssCtrl, ssAlt])) {$ENDIF} then begin if (Key <> VK_SPACE) or (edtSearch.Text <> '') then begin UTF8Char := VirtualKeyToUTF8Char(Key, ModifierKeys - SearchOrFilterModifiers); Result := (UTF8Char <> '') and (not ((Length(UTF8Char) = 1) and (UTF8Char[1] in [#0..#31]))); if Result then begin Key := 0; case gKeyTyping[KeyTypingModifier] of ktaQuickSearch: SearchMode := qsSearch; ktaQuickFilter: SearchMode := qsFilter; end; Self.Execute(SearchMode, [], UTF8Char); end; end; Exit; end; end; end; end; function TfrmQuickSearch.CheckSearchOrFilter(var UTF8Key: TUTF8Char): Boolean; var ModifierKeys: TShiftState; SearchMode: TQuickSearchMode; begin Result := False; // Check for certain Ascii keys. if (Length(UTF8Key) = 1) and (UTF8Key[1] in [#0..#32,'+','-','*']) then Exit; ModifierKeys := GetKeyShiftStateEx; if gKeyTyping[ktmNone] in [ktaQuickSearch, ktaQuickFilter] then begin if ModifierKeys * KeyModifiersShortcutNoText = TKeyTypingModifierToShift[ktmNone] then begin // Make upper case if either caps-lock is toggled or shift pressed. if (ssCaps in ModifierKeys) xor (ssShift in ModifierKeys) then UTF8Key := UTF8UpperCase(UTF8Key) else UTF8Key := UTF8LowerCase(UTF8Key); case gKeyTyping[ktmNone] of ktaQuickSearch: SearchMode := qsSearch; ktaQuickFilter: SearchMode := qsFilter; end; Self.Execute(SearchMode, [], UTF8Key); UTF8Key := ''; Result := True; Exit; end; end; end; procedure TfrmQuickSearch.LoadControlStates; begin sbDirectories.Down := (Options.Items = qsiDirectories) or (Options.Items = qsiFilesAndDirectories); sbFiles.Down := (Options.Items = qsiFiles) or (Options.Items = qsiFilesAndDirectories); sbCaseSensitive.Down := Options.SearchCase = qscSensitive; sbMatchBeginning.Down := qsmBeginning in Options.Match; sbMatchEnding.Down := qsmEnding in Options.Match; end; procedure TfrmQuickSearch.PushFilter; begin FilterText := edtSearch.Text; FilterOptions := Options; end; procedure TfrmQuickSearch.PopFilter; begin edtSearch.Text := FilterText; // there was no filter saved, do not continue loading if FilterText = EmptyStr then Exit; Options := FilterOptions; LoadControlStates; FilterText := EmptyStr; tglFilter.Checked := True; end; procedure TfrmQuickSearch.ClearFilter; begin FilterText := EmptyStr; FilterOptions := Options; if Assigned(Self.OnChangeFilter) then Self.OnChangeFilter(Self, EmptyStr, FilterOptions); end; procedure TfrmQuickSearch.CancelFilter; begin Finalize; {$IFDEF LCLGTK2} // On GTK2 OnExit for frame is not called when it is hidden, // but only when a control from outside of frame gains focus. FrameExit(nil); {$ENDIF} DoHide; end; procedure TfrmQuickSearch.SetFocus(Data: PtrInt); begin if edtSearch.CanFocus then edtSearch.SetFocus; end; procedure TfrmQuickSearch.CheckFilesOrDirectoriesDown; begin if not (sbFiles.Down or sbDirectories.Down) then begin // unchecking both should not be possible, so recheck last unchecked case Options.Items of qsiFiles: sbFiles.Down := True; qsiDirectories: sbDirectories.Down := True; end; end; end; procedure TfrmQuickSearch.edtSearchChange(Sender: TObject); begin Options.Direction := qsdNone; DoOnChangeSearch; end; procedure TfrmQuickSearch.BeginUpdate; begin Inc(FUpdateCount); end; procedure TfrmQuickSearch.btnCancelClick(Sender: TObject); begin CancelFilter; end; procedure TfrmQuickSearch.edtSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if CheckSearchOrFilter(Key) then Exit; case Key of VK_DOWN: begin Key := 0; if Assigned(Self.OnChangeSearch) then begin Options.Direction:=qsdNext; Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift); end; end; VK_UP: begin Key := 0; if Assigned(Self.OnChangeSearch) then begin Options.Direction:=qsdPrevious; Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift); end; end; // Request to have CTRL pressed at the same time. // VK_HOME alone reserved to get to start position of edtSearch. VK_HOME: begin if ssCtrl in Shift then begin Key := 0; if Assigned(Self.OnChangeSearch) then begin Options.Direction := qsdFirst; Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift); end; end; end; // Request to have CTRL pressed at the same time. // VK_END alone reserved to get to end position of edtSearch. VK_END: begin if ssCtrl in Shift then begin Key := 0; if Assigned(Self.OnChangeSearch) then begin Options.Direction := qsdLast; Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift); end; end; end; VK_INSERT: begin if Shift = [] then // no modifiers pressed, to not capture Ctrl+Insert and Shift+Insert begin Key := 0; if Assigned(Self.OnChangeSearch) then begin Options.Direction := qsdNext; Self.OnChangeSearch(Self, edtSearch.Text, Options, True); end; end; end; VK_RETURN, VK_SELECT: begin Key := 0; if Assigned(Self.OnExecute) then Self.OnExecute(Self); CancelFilter; end; VK_TAB: begin Key := 0; FIntendedLeave := True; DoHide; end; VK_ESCAPE: begin Key := 0; CancelFilter; end; end; end; procedure TfrmQuickSearch.EndUpdate; begin Dec(FUpdateCount); if FUpdateCount = 0 then begin if FNeedsChangeSearch then DoOnChangeSearch; end; end; procedure TfrmQuickSearch.DoHide; begin if Assigned(Self.OnHide) then Self.OnHide(Self); end; procedure TfrmQuickSearch.FrameExit(Sender: TObject); var DontHide: Boolean; begin {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} // Workaround: QuickSearch frame lose focus on SpeedButton click if Screen.ActiveControl is TFileView then edtSearch.SetFocus else {$ENDIF} if not Finalizing then begin Finalizing := True; Self.Active := False; if FIntendedLeave then begin FIntendedLeave := False; DontHide := False; end else DontHide := LimitedAutoHide; if (Mode = qsFilter) and (edtSearch.Text <> EmptyStr) then Self.Visible := DontHide or not gQuickFilterAutoHide else if DontHide then Reset else Finalize; Finalizing := False; end; end; procedure TfrmQuickSearch.sbCaseSensitiveClick(Sender: TObject); begin if sbCaseSensitive.Down then Options.SearchCase := qscSensitive else Options.SearchCase := qscInsensitive; if gQuickFilterSaveSessionModifications then gQuickSearchOptions.SearchCase := Options.SearchCase; Options.Direction := qsdNone; DoOnChangeSearch; end; procedure TfrmQuickSearch.sbFilesAndDirectoriesClick(Sender: TObject); begin if sbFiles.Down and sbDirectories.Down then Options.Items := qsiFilesAndDirectories else if sbFiles.Down then Options.Items := qsiFiles else if sbDirectories.Down then Options.Items := qsiDirectories else if FUpdateCount = 0 then begin CheckFilesOrDirectoriesDown; Exit; end; if gQuickFilterSaveSessionModifications then gQuickSearchOptions.Items := Options.Items; Options.Direction := qsdNone; DoOnChangeSearch; end; procedure TfrmQuickSearch.sbMatchBeginningClick(Sender: TObject); begin if sbMatchBeginning.Down then Include(Options.Match, qsmBeginning) else Exclude(Options.Match, qsmBeginning); if gQuickFilterSaveSessionModifications then gQuickSearchOptions.Match := Options.Match; Options.Direction := qsdNone; DoOnChangeSearch; end; procedure TfrmQuickSearch.sbMatchEndingClick(Sender: TObject); begin if sbMatchEnding.Down then Include(Options.Match, qsmEnding) else Exclude(Options.Match, qsmEnding); if gQuickFilterSaveSessionModifications then gQuickSearchOptions.Match := Options.Match; Options.Direction := qsdNone; DoOnChangeSearch; end; procedure TfrmQuickSearch.tglFilterChange(Sender: TObject); begin Options.LastSearchMode := qsNone; if tglFilter.Checked then Mode := qsFilter else Mode := qsSearch; // if a filter was set in background and a search is opened, the filter // will get pushed staying active. Otherwise the filter will be converted // in a search if not Active and (Mode = qsSearch) then PushFilter else if Active then ClearFilter; Options.Direction := qsdNone; DoOnChangeSearch; end; procedure TfrmQuickSearch.btnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Application.QueueAsyncCall(@SetFocus, 0); end; procedure TfrmQuickSearch.btnCancelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Self.Visible then Application.QueueAsyncCall(@SetFocus, 0); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/fsearchplugin.lfm�������������������������������������������������������0000644�0001750�0000144�00000006304�14743153644�020207� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSearchPlugin: TfrmSearchPlugin Left = 0 Height = 240 Top = 0 Width = 581 ClientHeight = 240 ClientWidth = 581 TabOrder = 0 DesignLeft = 573 DesignTop = 336 object pnlTable: TScrollBox Left = 0 Height = 125 Top = 65 Width = 581 HorzScrollBar.Page = 1 HorzScrollBar.Visible = False VertScrollBar.Page = 1 Align = alClient ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 Enabled = False TabOrder = 0 OnResize = pnlTableResize end object pnlButtons: TPanel Left = 0 Height = 50 Top = 190 Width = 581 Align = alBottom BevelOuter = bvNone ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ChildSizing.HorizontalSpacing = 12 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 ClientHeight = 50 ClientWidth = 581 Enabled = False TabOrder = 1 object btnAdd: TButton Left = 12 Height = 25 Top = 12 Width = 82 AutoSize = True Caption = '&More rules' OnClick = btnAddClick TabOrder = 0 end object btnDelete: TBitBtn Left = 106 Height = 25 Top = 12 Width = 76 Caption = 'L&ess rules' OnClick = btnDeleteClick TabOrder = 1 end end object HeaderControl: THeaderControl Left = 0 Height = 34 Top = 31 Width = 581 DragReorder = False Sections = < item Alignment = taLeftJustify Text = 'Plugin' Width = 30 Visible = True end item Alignment = taLeftJustify Text = 'Field' Width = 30 Visible = True end item Alignment = taLeftJustify Text = 'Operator' Width = 30 Visible = True end item Alignment = taLeftJustify Text = 'Value' Width = 30 Visible = True end item Alignment = taLeftJustify Width = 30 Visible = True end> Align = alTop Enabled = False end object pnlHeader: TPanel Left = 0 Height = 31 Top = 0 Width = 581 Align = alTop AutoSize = True BevelOuter = bvNone ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 31 ClientWidth = 581 TabOrder = 3 object chkUsePlugins: TCheckBox Left = 0 Height = 19 Top = 6 Width = 259 Caption = 'Use &content plugins, combine with:' OnChange = chkUsePluginsChange TabOrder = 0 end object rbAnd: TRadioButton Left = 265 Height = 19 Top = 6 Width = 157 Caption = '&AND (all match)' Checked = True Enabled = False TabOrder = 1 TabStop = True end object rbOr: TRadioButton Left = 428 Height = 19 Top = 6 Width = 153 Caption = '&OR (any match)' Enabled = False TabOrder = 2 end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/fsearchplugin.lrj�������������������������������������������������������0000644�0001750�0000144�00000002601�14743153644�020214� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":122881091,"name":"tfrmsearchplugin.btnadd.caption","sourcebytes":[38,77,111,114,101,32,114,117,108,101,115],"value":"&More rules"}, {"hash":87527011,"name":"tfrmsearchplugin.btndelete.caption","sourcebytes":[76,38,101,115,115,32,114,117,108,101,115],"value":"L&ess rules"}, {"hash":91471358,"name":"tfrmsearchplugin.headercontrol.sections[0].text","sourcebytes":[80,108,117,103,105,110],"value":"Plugin"}, {"hash":5045284,"name":"tfrmsearchplugin.headercontrol.sections[1].text","sourcebytes":[70,105,101,108,100],"value":"Field"}, {"hash":113807362,"name":"tfrmsearchplugin.headercontrol.sections[2].text","sourcebytes":[79,112,101,114,97,116,111,114],"value":"Operator"}, {"hash":6063029,"name":"tfrmsearchplugin.headercontrol.sections[3].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, {"hash":157776522,"name":"tfrmsearchplugin.chkuseplugins.caption","sourcebytes":[85,115,101,32,38,99,111,110,116,101,110,116,32,112,108,117,103,105,110,115,44,32,99,111,109,98,105,110,101,32,119,105,116,104,58],"value":"Use &content plugins, combine with:"}, {"hash":18107753,"name":"tfrmsearchplugin.rband.caption","sourcebytes":[38,65,78,68,32,40,97,108,108,32,109,97,116,99,104,41],"value":"&AND (all match)"}, {"hash":51824473,"name":"tfrmsearchplugin.rbor.caption","sourcebytes":[38,79,82,32,40,97,110,121,32,109,97,116,99,104,41],"value":"&OR (any match)"} ]} �������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/frames/fsearchplugin.pas�������������������������������������������������������0000644�0001750�0000144�00000010730�14743153644�020212� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Content plugins search frame Copyright (C) 2014-2016 Alexander Koblov (alexx2000@mail.ru) 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 } unit fSearchPlugin; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, ExtCtrls, StdCtrls, ComCtrls, Buttons, uFindFiles; type { TfrmSearchPlugin } TfrmSearchPlugin = class(TFrame) btnDelete: TBitBtn; btnAdd: TButton; chkUsePlugins: TCheckBox; HeaderControl: THeaderControl; pnlHeader: TPanel; pnlButtons: TPanel; pnlTable: TScrollBox; rbAnd: TRadioButton; rbOr: TRadioButton; procedure btnAddClick(Sender: TObject); procedure btnDeleteClick(Sender: TObject); procedure chkUsePluginsChange(Sender: TObject); procedure pnlTableResize(Sender: TObject); private { private declarations } public procedure Save(var SearchTemplate: TSearchTemplateRec); procedure Load(const SearchTemplate: TSearchTemplateRec); end; implementation {$R *.lfm} uses uSearchContent; { TfrmSearchPlugin } procedure TfrmSearchPlugin.Save(var SearchTemplate: TSearchTemplateRec); var I: Integer; Plugin: TPluginPanel; begin SearchTemplate.ContentPlugin:= chkUsePlugins.Checked; if not SearchTemplate.ContentPlugin then Exit; SearchTemplate.ContentPluginCombine:= rbAnd.Checked; SetLength(SearchTemplate.ContentPlugins, pnlTable.ControlCount); for I:= 0 to pnlTable.ControlCount - 1 do begin Plugin:= TPluginPanel(pnlTable.Controls[I]); SearchTemplate.ContentPlugins[I].Plugin:= Plugin.Plugin; SearchTemplate.ContentPlugins[I].FieldType:= Plugin.FieldType; SearchTemplate.ContentPlugins[I].Field:= Plugin.Field; SearchTemplate.ContentPlugins[I].Compare:= Plugin.Compare; SearchTemplate.ContentPlugins[I].Value:= Plugin.Value; SearchTemplate.ContentPlugins[I].UnitName:= Plugin.UnitName; //Set the unit *after* the field has been set so if we have error setting the unit, the error message gives the "field" has a hint. end; end; procedure TfrmSearchPlugin.Load(const SearchTemplate: TSearchTemplateRec); var I: Integer; Panel: TPluginPanel; begin chkUsePlugins.Checked:= SearchTemplate.ContentPlugin; if SearchTemplate.ContentPluginCombine then rbAnd.Checked:= True else begin rbOr.Checked:= True; end; for I:= pnlTable.ControlCount - 1 downto 0 do pnlTable.Controls[I].Free; for I:= Low(SearchTemplate.ContentPlugins) to High(SearchTemplate.ContentPlugins) do begin Panel:= TPluginPanel.Create(pnlTable); Panel.Parent:= pnlTable; Panel.Plugin:= SearchTemplate.ContentPlugins[I].Plugin; Panel.Field:= SearchTemplate.ContentPlugins[I].Field; Panel.Compare:= SearchTemplate.ContentPlugins[I].Compare; Panel.Value:= SearchTemplate.ContentPlugins[I].Value; Panel.UnitName:= SearchTemplate.ContentPlugins[I].UnitName; end; end; procedure TfrmSearchPlugin.btnAddClick(Sender: TObject); var Panel: TPluginPanel; begin Panel:= TPluginPanel.Create(pnlTable); Panel.Parent:= pnlTable; end; procedure TfrmSearchPlugin.btnDeleteClick(Sender: TObject); var Index: Integer; begin Index:= pnlTable.ControlCount - 1; if Index >= 0 then pnlTable.Controls[Index].Free; end; procedure TfrmSearchPlugin.chkUsePluginsChange(Sender: TObject); begin rbAnd.Enabled:= chkUsePlugins.Checked; rbOr.Enabled:= chkUsePlugins.Checked; HeaderControl.Enabled:= chkUsePlugins.Checked; pnlTable.Enabled:= chkUsePlugins.Checked; pnlButtons.Enabled:= chkUsePlugins.Checked; end; procedure TfrmSearchPlugin.pnlTableResize(Sender: TObject); var I, ColumnWidth: Integer; begin ColumnWidth:= pnlTable.ClientWidth div HeaderControl.Sections.Count; for I:= 0 to HeaderControl.Sections.Count - 1 do begin HeaderControl.Sections[I].Width:= ColumnWidth; end; end; end. ����������������������������������������doublecmd-1.1.22/src/frames/ucomponentssignature.pas������������������������������������������������0000644�0001750�0000144�00000014000�14743153644�021646� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Compute signature of a form, frame, etc. based on current options set Copyright (C) 2016-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uComponentsSignature; {$mode objfpc}{$H+} interface uses Classes, EditBtn; function ComputeSignatureBasedOnComponent(aComponent: TComponent; seed: dword): dword; function ComputeSignatureSingleComponent(aComponent: TComponent; seed: dword): dword; function ComputeSignatureString(seed: dword; sParamString: string): dword; function ComputeSignatureBoolean(seed: dword; bParamBoolean: boolean): dword; function ComputeSignaturePtrInt(seed: dword; iPtrInt: PtrInt): dword; implementation uses Graphics, ComCtrls, ColorBox, ExtCtrls, Spin, StdCtrls, Math, Dialogs, SysUtils, crc; const SAMPLEBYTES: array[0..1] of byte = ($23, $35); { ComputeSignatureSingleComponent } function ComputeSignatureSingleComponent(aComponent: TComponent; seed: dword): dword; var SampleValue: dword; iSampleValue, iIndex: integer; ColorSampleValue: TColor; begin Result := seed; case aComponent.ClassName of 'TCheckBox': Result := crc32(Result, @SAMPLEBYTES[ifthen(TCheckBox(aComponent).Checked, 1, 0)], 1); 'TRadioGroup': begin SampleValue := TRadioGroup(aComponent).ItemIndex; Result := crc32(Result, @SampleValue, sizeof(SampleValue)); end; 'TRadioButton': begin Result := crc32(Result, @SAMPLEBYTES[ifthen(TRadioButton(aComponent).Checked, 1, 0)], 1); end; 'TEdit': if length(TEdit(aComponent).Text) > 0 then Result := crc32(Result, @TEdit(aComponent).Text[1], length(TEdit(aComponent).Text)); 'TLabeledEdit': begin if length(TLabeledEdit(aComponent).Text) > 0 then Result := crc32(Result, @TLabeledEdit(aComponent).Text[1], length(TLabeledEdit(aComponent).Text)); end; 'TFileNameEdit': if length(TFileNameEdit(aComponent).FileName) > 0 then Result := crc32(Result, @TFileNameEdit(aComponent).FileName[1], length(TFileNameEdit(aComponent).FileName)); 'TDirectoryEdit': if length(TDirectoryEdit(aComponent).Text) > 0 then Result := crc32(Result, @TDirectoryEdit(aComponent).Text[1], length(TDirectoryEdit(aComponent).Text)); 'TComboBox', 'TComboBoxAutoWidth': begin if TComboBox(aComponent).ItemIndex <> -1 then begin SampleValue := TComboBox(aComponent).ItemIndex; Result := crc32(Result, @SampleValue, sizeof(SampleValue)); end; if TComboBox(aComponent).Style <> csDropDownList then begin if length(TComboBox(aComponent).Text) > 0 then Result := crc32(Result, @TComboBox(aComponent).Text[1], length(TComboBox(aComponent).Text)); end; end; 'TSpinEdit': begin SampleValue := TSpinEdit(aComponent).Value; Result := crc32(Result, @SampleValue, sizeof(SampleValue)); end; 'TColorBox', 'TKASColorBox': begin ColorSampleValue := TColorBox(aComponent).Selected; Result := crc32(Result, @ColorSampleValue, 4); end; 'TTrackBar': begin iSampleValue := TTrackBar(aComponent).Position; Result := crc32(Result, @iSampleValue, 4); end; 'TListBox': begin if not TListBox(aComponent).MultiSelect then begin iSampleValue := TListBox(aComponent).ItemIndex; Result := crc32(Result, @iSampleValue, sizeof(iSampleValue)); end; end; 'TMemo': begin SampleValue := TMemo(aComponent).Lines.Count; Result := crc32(Result, @SampleValue, sizeof(SampleValue)); for iIndex:=0 to pred(TMemo(aComponent).Lines.Count) do begin if length(TMemo(aComponent).Lines.Strings[iIndex]) > 0 then Result := crc32(Result, @TMemo(aComponent).Lines.Strings[iIndex][1], length(TMemo(aComponent).Lines.Strings[iIndex])); end; end; end; end; { ComputeSignatureBasedOnComponent } function ComputeSignatureBasedOnComponent(aComponent: TComponent; seed: dword): dword; var iComponent: integer; begin Result := ComputeSignatureSingleComponent(aComponent, seed); case aComponent.ClassName of 'TRadioGroup': begin end; // Nothing. Because if we go inside, we'll analyse *always* ALL unchecked "TRadioButton" after load but they're not when it's time to save them. else begin for iComponent := 0 to pred(aComponent.ComponentCount) do Result := ComputeSignatureBasedOnComponent(aComponent.Components[iComponent], Result) end; end; end; { ComputeSignatureString } function ComputeSignatureString(seed: dword; sParamString: string): dword; begin result := seed; if length(sParamString) > 0 then result := crc32(result, @sParamString[1], length(sParamString)); end; { ComputeSignatureBoolean } function ComputeSignatureBoolean(seed: dword; bParamBoolean: boolean): dword; const SAMPLEBYTES: array[0..1] of byte = ($23, $35); begin result := crc32(seed, @SAMPLEBYTES[ifthen(bParamBoolean, 1, 0)], 1); end; { ComputeSignaturePtrInt } function ComputeSignaturePtrInt(seed: dword; iPtrInt: PtrInt): dword; begin result := crc32(seed, @iPtrInt, sizeof(PtrInt)); end; end. doublecmd-1.1.22/src/fselectduplicates.lfm����������������������������������������������������������0000644�0001750�0000144�00000026405�14743153644�017607� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSelectDuplicates: TfrmSelectDuplicates Left = 509 Height = 252 Top = 205 Width = 526 AutoSize = True BorderStyle = bsDialog Caption = 'Select duplicate files' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 4 ClientHeight = 252 ClientWidth = 526 Constraints.MinWidth = 480 DesignTimePPI = 120 Position = poOwnerFormCenter LCLVersion = '2.0.10.0' object btnIncludeMask: TSpeedButton AnchorSideLeft.Control = cmbIncludeMask AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cmbIncludeMask AnchorSideBottom.Control = cmbIncludeMask AnchorSideBottom.Side = asrBottom Left = 490 Height = 28 Hint = 'Template...' Top = 24 Width = 29 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000330000 0033000000330000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000214F6B83FF4966 85FF5191D9FF0000003300000000000000000000000000000000000000000000 00000000000000000000000000000000000000000021B07836B75485ABFF7EA7 B8FF8FD5FFFF356A9CFF00000033000000000000000000000000000000000000 000000000000000000000000000000000022A7753BB9D49849FF3CB4FFFFA3F1 FFFF9CE0FEFF109BFFFF306BA2FF000000330000000A00000000000000000000 0000000000000000000000000000A7763BBDE9C590FFDFAA5CFFC87F2EFF287B D2FF3FC7FFFF20ACFFFF83B1D8FF807873FF413F3D5B00000000000000000000 0000000000000000000000000000B57F3DFFFFF1D0FFDAA85BFFC28236FF0000 00002C7DCFFFB3DEF2FF938881FFC2C0BAFF797B71FF00000033000000000000 0000000000000000000000000021B37C3AFFFFFFFAFFD6A559FFBA803BFF0000 0020000000008E8780FFDAD7D3FF8A8C84FFA27F9BFF9969CCFF000000000000 00000000000000000021AA7A3EB6DEAF68FFF3CB8AFFEEC684FFD8AA65FFAC79 3AB50000002100000000858884FFE3B3E3FFCB96C7FFAE7DCEFF000000000000 000000000021A9783CB9EDC385FFF9D292FFF3CD8BFFEDC380FFE8BE7CFFDDB3 74FFAA783BB70000002100000000C28BDCFFBF8AD4FF00000000000000000000 0021A77639B9EFCA96FFF8D59CFFF6CF8DFFEEC684FFE7BB77FFE0B26BFFE1BB 80FFDBB57FFFA87637B70000002100000000000000000000000000000022BB8D 4DB9F0D3ABFFFADFB1FFF5CC88FFEEC480FFE8BC76FFE1B36CFFDBAA61FFD4A1 55FFE0BC89FFDCBD8FFFAA7831B8000000220000000000000000A67437BDFFED CAFFFFF1D8FFFBE4BCFFFFF1D9FFFEF4E4FFF6E7CCFFF5E4CAFFF6E9D6FFEFDD C1FFE3C597FFECDABDFFE4CCA6FFA77636BD0000000000000000B57E3AFFFFFA E8FFF5E3C5FFE3C798FFD8B070FFD19E50FFD8A14DFFDCA553FFD19D4AFFD2A7 63FFD5AF74FFDDC194FFE9D2B3FFB7813DFF0000000000000000B57E3AFFFFFF FFFFA16100FFB17616FFBF852BFFCB933DFFD9A24FFFDDA755FFCF9A43FFC48B 32FFB87E1FFFAA6C08FFF7EDE0FFB7813EFF0000000000000000B67F3DFFFFF9 E2FFEBC992FFF3DBB5FFF5E2C0FFF5E1C0FFF6E2BFFFF5DFBDFFEFD9B5FFECD3 AFFFE4C9A0FFD4AD73FFE4C9A1FFB88241FF0000000000000000B8834238D19E 58A9C99753E0C69351FFC69453FFC5914FFFC6975EFFC49356FFBF8B48FFBF8A 46FFBD8946FFBE8844E0BD873FA9BA8545380000000000000000 } OnClick = btnIncludeMaskClick end object cmbIncludeMask: TComboBox AnchorSideLeft.Control = lblIncludeMask AnchorSideTop.Control = lblIncludeMask AnchorSideTop.Side = asrBottom Left = 8 Height = 28 Top = 24 Width = 478 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 ItemHeight = 20 ItemIndex = 0 Items.Strings = ( '*' ) ParentFont = False TabOrder = 0 Text = '*' end object lblIncludeMask: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 8 Height = 20 Top = 0 Width = 173 Caption = 'Select by &name/extension:' ParentColor = False end object lblExcludeMask: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = cmbIncludeMask AnchorSideTop.Side = asrBottom Left = 8 Height = 20 Top = 52 Width = 250 Caption = '&Remove selection by name/extension:' ParentColor = False end object cmbExcludeMask: TComboBox AnchorSideLeft.Control = lblExcludeMask AnchorSideTop.Control = lblExcludeMask AnchorSideTop.Side = asrBottom Left = 8 Height = 28 Top = 76 Width = 478 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 ItemHeight = 20 Items.Strings = ( '*' ) ParentFont = False TabOrder = 1 end object btnExcludeMask: TSpeedButton AnchorSideLeft.Control = cmbExcludeMask AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cmbExcludeMask AnchorSideBottom.Control = cmbExcludeMask AnchorSideBottom.Side = asrBottom Left = 490 Height = 28 Hint = 'Template...' Top = 76 Width = 29 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000330000 0033000000330000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000214F6B83FF4966 85FF5191D9FF0000003300000000000000000000000000000000000000000000 00000000000000000000000000000000000000000021B07836B75485ABFF7EA7 B8FF8FD5FFFF356A9CFF00000033000000000000000000000000000000000000 000000000000000000000000000000000022A7753BB9D49849FF3CB4FFFFA3F1 FFFF9CE0FEFF109BFFFF306BA2FF000000330000000A00000000000000000000 0000000000000000000000000000A7763BBDE9C590FFDFAA5CFFC87F2EFF287B D2FF3FC7FFFF20ACFFFF83B1D8FF807873FF413F3D5B00000000000000000000 0000000000000000000000000000B57F3DFFFFF1D0FFDAA85BFFC28236FF0000 00002C7DCFFFB3DEF2FF938881FFC2C0BAFF797B71FF00000033000000000000 0000000000000000000000000021B37C3AFFFFFFFAFFD6A559FFBA803BFF0000 0020000000008E8780FFDAD7D3FF8A8C84FFA27F9BFF9969CCFF000000000000 00000000000000000021AA7A3EB6DEAF68FFF3CB8AFFEEC684FFD8AA65FFAC79 3AB50000002100000000858884FFE3B3E3FFCB96C7FFAE7DCEFF000000000000 000000000021A9783CB9EDC385FFF9D292FFF3CD8BFFEDC380FFE8BE7CFFDDB3 74FFAA783BB70000002100000000C28BDCFFBF8AD4FF00000000000000000000 0021A77639B9EFCA96FFF8D59CFFF6CF8DFFEEC684FFE7BB77FFE0B26BFFE1BB 80FFDBB57FFFA87637B70000002100000000000000000000000000000022BB8D 4DB9F0D3ABFFFADFB1FFF5CC88FFEEC480FFE8BC76FFE1B36CFFDBAA61FFD4A1 55FFE0BC89FFDCBD8FFFAA7831B8000000220000000000000000A67437BDFFED CAFFFFF1D8FFFBE4BCFFFFF1D9FFFEF4E4FFF6E7CCFFF5E4CAFFF6E9D6FFEFDD C1FFE3C597FFECDABDFFE4CCA6FFA77636BD0000000000000000B57E3AFFFFFA E8FFF5E3C5FFE3C798FFD8B070FFD19E50FFD8A14DFFDCA553FFD19D4AFFD2A7 63FFD5AF74FFDDC194FFE9D2B3FFB7813DFF0000000000000000B57E3AFFFFFF FFFFA16100FFB17616FFBF852BFFCB933DFFD9A24FFFDDA755FFCF9A43FFC48B 32FFB87E1FFFAA6C08FFF7EDE0FFB7813EFF0000000000000000B67F3DFFFFF9 E2FFEBC992FFF3DBB5FFF5E2C0FFF5E1C0FFF6E2BFFFF5DFBDFFEFD9B5FFECD3 AFFFE4C9A0FFD4AD73FFE4C9A1FFB88241FF0000000000000000B8834238D19E 58A9C99753E0C69351FFC69453FFC5914FFFC6975EFFC49356FFBF8B48FFBF8A 46FFBD8946FFBE8844E0BD873FA9BA8545380000000000000000 } OnClick = btnIncludeMaskClick end object chkLeaveUnselected: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = cmbExcludeMask AnchorSideTop.Side = asrBottom Left = 8 Height = 24 Top = 116 Width = 341 BorderSpacing.Top = 12 Caption = '&Leave at least one file in each group unselected:' Checked = True State = cbChecked TabOrder = 2 OnChange = chkLeaveUnselectedChange end object pnlMethods: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = chkLeaveUnselected AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 63 Top = 146 Width = 510 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BevelOuter = bvNone ChildSizing.EnlargeHorizontal = crsHomogenousSpaceResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 63 ClientWidth = 510 TabOrder = 3 object lblFirstMethod: TLabel Left = 48 Height = 28 Top = 0 Width = 11 Caption = '&1.' FocusControl = cmbFirstMethod Layout = tlCenter ParentColor = False end object cmbFirstMethod: TComboBoxAutoWidth Left = 107 Height = 28 Top = 0 Width = 125 ItemHeight = 20 Items.Strings = ( 'Newest' 'Oldest' 'Largest' 'Smallest' 'First in group' 'Last in group' ) OnChange = cmbFirstMethodChange Style = csDropDownList TabOrder = 0 end object lblSecondMethod: TLabel Left = 280 Height = 28 Top = 0 Width = 11 Caption = '&2.' FocusControl = cmbSecondMethod Layout = tlCenter ParentColor = False end object cmbSecondMethod: TComboBoxAutoWidth Left = 339 Height = 28 Top = 0 Width = 125 ItemHeight = 20 Items.Strings = ( 'Newest' 'Oldest' 'Largest' 'Smallest' ) Style = csDropDownList TabOrder = 1 end end object pnlButtons: TKASButtonPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = pnlMethods AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 8 Height = 34 Top = 209 Width = 510 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ClientHeight = 34 ClientWidth = 510 FullRepaint = False ParentFont = False TabOrder = 4 object btnOK: TBitBtn AnchorSideRight.Control = btnCancel Left = 257 Height = 34 Top = 0 Width = 70 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 10 BorderSpacing.InnerBorder = 2 Caption = '&OK' Default = True Kind = bkOK ModalResult = 1 ParentFont = False TabOrder = 0 end object btnCancel: TBitBtn AnchorSideRight.Control = btnApply Left = 337 Height = 34 Top = 0 Width = 94 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 10 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Kind = bkCancel ModalResult = 2 ParentFont = False TabOrder = 1 end object btnApply: TBitBtn AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom Left = 441 Height = 34 Top = 0 Width = 69 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.InnerBorder = 2 Caption = '&Apply' OnClick = btnApplyClick ParentFont = False TabOrder = 2 end end end�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselectduplicates.lrj����������������������������������������������������������0000644�0001750�0000144�00000003726�14743153644�017621� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":165719427,"name":"tfrmselectduplicates.caption","sourcebytes":[83,101,108,101,99,116,32,100,117,112,108,105,99,97,116,101,32,102,105,108,101,115],"value":"Select duplicate files"}, {"hash":47236478,"name":"tfrmselectduplicates.btnincludemask.hint","sourcebytes":[84,101,109,112,108,97,116,101,46,46,46],"value":"Template..."}, {"hash":42,"name":"tfrmselectduplicates.cmbincludemask.text","sourcebytes":[42],"value":"*"}, {"hash":245718570,"name":"tfrmselectduplicates.lblincludemask.caption","sourcebytes":[83,101,108,101,99,116,32,98,121,32,38,110,97,109,101,47,101,120,116,101,110,115,105,111,110,58],"value":"Select by &name/extension:"}, {"hash":214104570,"name":"tfrmselectduplicates.lblexcludemask.caption","sourcebytes":[38,82,101,109,111,118,101,32,115,101,108,101,99,116,105,111,110,32,98,121,32,110,97,109,101,47,101,120,116,101,110,115,105,111,110,58],"value":"&Remove selection by name/extension:"}, {"hash":47236478,"name":"tfrmselectduplicates.btnexcludemask.hint","sourcebytes":[84,101,109,112,108,97,116,101,46,46,46],"value":"Template..."}, {"hash":14425802,"name":"tfrmselectduplicates.chkleaveunselected.caption","sourcebytes":[38,76,101,97,118,101,32,97,116,32,108,101,97,115,116,32,111,110,101,32,102,105,108,101,32,105,110,32,101,97,99,104,32,103,114,111,117,112,32,117,110,115,101,108,101,99,116,101,100,58],"value":"&Leave at least one file in each group unselected:"}, {"hash":10558,"name":"tfrmselectduplicates.lblfirstmethod.caption","sourcebytes":[38,49,46],"value":"&1."}, {"hash":10574,"name":"tfrmselectduplicates.lblsecondmethod.caption","sourcebytes":[38,50,46],"value":"&2."}, {"hash":11067,"name":"tfrmselectduplicates.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmselectduplicates.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":44595001,"name":"tfrmselectduplicates.btnapply.caption","sourcebytes":[38,65,112,112,108,121],"value":"&Apply"} ]} ������������������������������������������doublecmd-1.1.22/src/fselectduplicates.pas����������������������������������������������������������0000644�0001750�0000144�00000015111�14743153644�017604� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fSelectDuplicates; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, StdCtrls, ExtCtrls, KASComboBox, KASButtonPanel, uFileView; type { TfrmSelectDuplicates } TfrmSelectDuplicates = class(TForm) btnApply: TBitBtn; btnCancel: TBitBtn; btnOK: TBitBtn; btnIncludeMask: TSpeedButton; btnExcludeMask: TSpeedButton; cmbFirstMethod: TComboBoxAutoWidth; cmbIncludeMask: TComboBox; cmbExcludeMask: TComboBox; chkLeaveUnselected: TCheckBox; cmbSecondMethod: TComboBoxAutoWidth; lblIncludeMask: TLabel; lblExcludeMask: TLabel; lblFirstMethod: TLabel; lblSecondMethod: TLabel; pnlMethods: TPanel; pnlButtons: TKASButtonPanel; procedure btnApplyClick(Sender: TObject); procedure btnIncludeMaskClick(Sender: TObject); procedure chkLeaveUnselectedChange(Sender: TObject); procedure cmbFirstMethodChange(Sender: TObject); private FFileView: TFileView; end; procedure ShowSelectDuplicates(TheOwner: TCustomForm; AFileView: TFileView); implementation {$R *.lfm} uses uFile, uFileSorting, uFileFunctions, uDisplayFile, uFileProperty, uTypes, uGlobs, fMaskInputDlg, uLng, uSearchTemplate, DCStrUtils; procedure ShowSelectDuplicates(TheOwner: TCustomForm; AFileView: TFileView); begin with TfrmSelectDuplicates.Create(TheOwner) do begin FFileView:= AFileView; cmbFirstMethod.ItemIndex:= 0; cmbSecondMethod.ItemIndex:= 2; cmbIncludeMask.Items.Assign(glsMaskHistory); cmbExcludeMask.Items.Assign(glsMaskHistory); // Localize methods ParseLineToList(rsSelectDuplicateMethod, cmbFirstMethod.Items); ParseLineToList(rsSelectDuplicateMethod, cmbSecondMethod.Items); cmbSecondMethod.Items.Delete(cmbSecondMethod.Items.Count - 1); cmbSecondMethod.Items.Delete(cmbSecondMethod.Items.Count - 1); if ShowModal = mrOK then begin btnApplyClick(btnApply); end; Free; end; end; { TfrmSelectDuplicates } procedure TfrmSelectDuplicates.cmbFirstMethodChange(Sender: TObject); begin cmbSecondMethod.Enabled:= cmbFirstMethod.ItemIndex < 4; end; procedure TfrmSelectDuplicates.btnApplyClick(Sender: TObject); var ARange: TRange; AFinish: Integer; Index, J: Integer; ASelected: Integer; AFiles: TDisplayFiles; AGroup, AValue: Variant; NewSorting: TFileSortings = nil; begin FFileView.MarkGroup(cmbIncludeMask.Text, True); if Length(cmbExcludeMask.Text) > 0 then begin FFileView.MarkGroup(cmbExcludeMask.Text, False); end; if not chkLeaveUnselected.Checked then Exit; AFiles:= FFileView.DisplayFiles; // First sort by group SetLength(NewSorting, 1); SetLength(NewSorting[0].SortFunctions, 1); NewSorting[0].SortFunctions[0] := fsfVariant; NewSorting[0].SortDirection := sdAscending; case cmbFirstMethod.ItemIndex of 0, 1: // Newest/Oldest begin SetLength(NewSorting, 2); SetLength(NewSorting[1].SortFunctions, 1); NewSorting[1].SortFunctions[0] := fsfModificationTime; if (cmbFirstMethod.ItemIndex = 1) then // First item will be Oldest NewSorting[1].SortDirection := sdAscending else begin // First item will be Newest NewSorting[1].SortDirection := sdDescending; end; end; 2, 3: // Largest/Smallest begin SetLength(NewSorting, 2); SetLength(NewSorting[1].SortFunctions, 1); NewSorting[1].SortFunctions[0] := fsfSize; if (cmbFirstMethod.ItemIndex = 3) then // First item will be Smallest NewSorting[1].SortDirection := sdAscending else begin // First item will be Largest NewSorting[1].SortDirection := sdDescending; end; end; end; if cmbSecondMethod.Enabled then begin case cmbSecondMethod.ItemIndex of 0, 1: begin SetLength(NewSorting, 3); SetLength(NewSorting[2].SortFunctions, 1); NewSorting[2].SortFunctions[0] := fsfModificationTime; if (cmbSecondMethod.ItemIndex = 1) then NewSorting[2].SortDirection := sdAscending else begin NewSorting[2].SortDirection := sdDescending; end; end; 2, 3: begin SetLength(NewSorting, 3); SetLength(NewSorting[2].SortFunctions, 1); NewSorting[2].SortFunctions[0] := fsfSize; if (cmbSecondMethod.ItemIndex = 3) then NewSorting[2].SortDirection := sdAscending else begin NewSorting[2].SortDirection := sdDescending; end; end; end; end; FFileView.Sorting:= NewSorting; // Skip '..' item if AFiles[0].FSFile.IsNameValid then ARange.First:= 0 else begin ARange.First:= 1; end; AFinish:= AFiles.Count - 1; AGroup:= TFileVariantProperty(AFiles[ARange.First].FSFile.Properties[fpVariant]).Value; for Index:= ARange.First + 1 to AFinish do begin AValue:= TFileVariantProperty(AFiles[Index].FSFile.Properties[fpVariant]).Value; if (AValue <> AGroup) or (Index = AFinish) then begin if (AValue <> AGroup) then begin ASelected:= 0; ARange.Last:= Index - 1; end else begin ASelected:= -1; ARange.Last:= Index; end; for J:= ARange.First to ARange.Last do begin if AFiles[J].Selected then Inc(ASelected); end; // Selected all files in the group if ASelected = (Index - ARange.First) then begin if cmbFirstMethod.ItemIndex = 5 then AFiles[ARange.Last].Selected:= False else begin AFiles[ARange.First].Selected:= False; end; end; AGroup:= AValue; ARange.First:= Index; end; end; end; procedure TfrmSelectDuplicates.btnIncludeMaskClick(Sender: TObject); var sMask: String; bTemplate: Boolean; AComboBox: TComboBox; begin if Sender = btnIncludeMask then AComboBox:= cmbIncludeMask else begin AComboBox:= cmbExcludeMask; end; sMask:= AComboBox.Text; if ShowMaskInputDlg(rsMarkPlus, rsMaskInput, glsMaskHistory, sMask) then begin bTemplate:= IsMaskSearchTemplate(sMask); AComboBox.Enabled:= not bTemplate; AComboBox.Text:= sMask; end; end; procedure TfrmSelectDuplicates.chkLeaveUnselectedChange(Sender: TObject); begin cmbFirstMethod.Enabled:= chkLeaveUnselected.Checked; cmbSecondMethod.Enabled:= chkLeaveUnselected.Checked; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselectpathrange.lfm�����������������������������������������������������������0000644�0001750�0000144�00000012244�14743153644�017417� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSelectPathRange: TfrmSelectPathRange Left = 696 Height = 307 Top = 219 Width = 362 ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 307 ClientWidth = 362 OnCreate = FormCreate Position = poOwnerFormCenter SessionProperties = 'Left;Top;Width;rbFirstFromEnd.Checked;rbFirstFromStart.Checked' LCLVersion = '2.0.6.0' object lblSelectDirectories: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 6 Width = 326 Caption = '&Select the directories to insert (you may select more than one)' FocusControl = lbDirectories ParentColor = False end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 26 Top = 275 Width = 350 Align = alNone Anchors = [akLeft, akRight, akBottom] OKButton.Name = 'OKButton' OKButton.Caption = '&OK' OKButton.DefaultCaption = False HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.Caption = '&Cancel' CancelButton.DefaultCaption = False TabOrder = 2 ShowButtons = [pbOK, pbCancel] ShowBevel = False end object lblResult: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = lbDirectories AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = ButtonPanel Left = 6 Height = 15 Top = 254 Width = 35 Anchors = [akLeft, akBottom] Caption = 'Result:' ParentColor = False end object lblValueToReturn: TLabel AnchorSideLeft.Control = lblResult AnchorSideLeft.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = ButtonPanel Left = 44 Height = 15 Top = 254 Width = 312 Anchors = [akLeft, akRight, akBottom] AutoSize = False ParentColor = False end object lbDirectories: TListBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblSelectDirectories AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlChoices AnchorSideBottom.Control = lblResult Left = 6 Height = 227 Top = 24 Width = 247 Anchors = [akTop, akLeft, akRight, akBottom] ItemHeight = 0 MultiSelect = True OnSelectionChange = lbDirectoriesSelectionChange TabOrder = 0 end object pnlChoices: TPanel AnchorSideTop.Control = lblSelectDirectories AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = lblResult Left = 256 Height = 227 Top = 24 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True BevelOuter = bvNone ChildSizing.VerticalSpacing = 2 ClientHeight = 227 ClientWidth = 100 TabOrder = 1 object gbCountFrom: TGroupBox AnchorSideLeft.Control = pnlChoices AnchorSideTop.Control = pnlChoices AnchorSideRight.Control = pnlChoices AnchorSideRight.Side = asrBottom Left = 0 Height = 64 Top = 0 Width = 100 Anchors = [akTop, akLeft, akRight] AutoSize = True Caption = 'Count from' ChildSizing.LeftRightSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 44 ClientWidth = 96 TabOrder = 0 object rbFirstFromStart: TRadioButton AnchorSideLeft.Control = gbCountFrom AnchorSideTop.Control = gbCountFrom Left = 6 Height = 19 Top = 0 Width = 65 Caption = 'The sta&rt' Checked = True OnChange = SomethingChange TabOrder = 0 TabStop = True end object rbFirstFromEnd: TRadioButton AnchorSideLeft.Control = gbCountFrom AnchorSideTop.Control = rbFirstFromStart AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 22 Width = 62 BorderSpacing.Bottom = 3 Caption = 'The en&d' OnChange = SomethingChange TabOrder = 1 end end object edSeparator: TLabeledEdit AnchorSideLeft.Control = pnlChoices AnchorSideRight.Control = pnlChoices AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlChoices AnchorSideBottom.Side = asrBottom Left = 0 Height = 23 Top = 204 Width = 100 Anchors = [akLeft, akRight, akBottom] Constraints.MinWidth = 100 EditLabel.Height = 15 EditLabel.Width = 100 EditLabel.Caption = 'Sep&arator' EditLabel.ParentColor = False TabOrder = 1 OnChange = SomethingChange end end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselectpathrange.lrj�����������������������������������������������������������0000644�0001750�0000144�00000002571�14743153644�017432� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":136763673,"name":"tfrmselectpathrange.lblselectdirectories.caption","sourcebytes":[38,83,101,108,101,99,116,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,116,111,32,105,110,115,101,114,116,32,40,121,111,117,32,109,97,121,32,115,101,108,101,99,116,32,109,111,114,101,32,116,104,97,110,32,111,110,101,41],"value":"&Select the directories to insert (you may select more than one)"}, {"hash":11067,"name":"tfrmselectpathrange.buttonpanel.okbutton.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmselectpathrange.buttonpanel.cancelbutton.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":147505962,"name":"tfrmselectpathrange.lblresult.caption","sourcebytes":[82,101,115,117,108,116,58],"value":"Result:"}, {"hash":90341277,"name":"tfrmselectpathrange.gbcountfrom.caption","sourcebytes":[67,111,117,110,116,32,102,114,111,109],"value":"Count from"}, {"hash":128947172,"name":"tfrmselectpathrange.rbfirstfromstart.caption","sourcebytes":[84,104,101,32,115,116,97,38,114,116],"value":"The sta&rt"}, {"hash":242664804,"name":"tfrmselectpathrange.rbfirstfromend.caption","sourcebytes":[84,104,101,32,101,110,38,100],"value":"The en&d"}, {"hash":210573122,"name":"tfrmselectpathrange.edseparator.editlabel.caption","sourcebytes":[83,101,112,38,97,114,97,116,111,114],"value":"Sep&arator"} ]} ���������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselectpathrange.pas�����������������������������������������������������������0000644�0001750�0000144�00000011270�14743153644�017422� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Multi-Rename path range selector dialog window Copyright (C) 2007-2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fSelectPathRange; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel, Buttons, ExtCtrls, //DC uOSForms; type { TfrmSelectPathRange } TfrmSelectPathRange = class(TModalForm) lblSelectDirectories: TLabel; lbDirectories: TListBox; pnlChoices: TPanel; gbCountFrom: TGroupBox; rbFirstFromStart: TRadioButton; rbFirstFromEnd: TRadioButton; edSeparator: TLabeledEdit; lblResult: TLabel; lblValueToReturn: TLabel; ButtonPanel: TButtonPanel; procedure FormCreate(Sender: TObject); procedure edtSelectTextKeyUp(Sender: TObject; var {%H-}Key: word; {%H-}Shift: TShiftState); procedure edtSelectTextMouseUp(Sender: TObject; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: integer); procedure lbDirectoriesSelectionChange(Sender: TObject; {%H-}User: boolean); procedure SomethingChange(Sender: TObject); private FPrefix: string; procedure ResfreshHint; public property Prefix: string read FPrefix write FPrefix; end; function ShowSelectPathRangeDlg(TheOwner: TCustomForm; const ACaption, AText, sPrefix: string; var sResultingMaskValue: string): boolean; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. //DC uGlobs; { TfrmSelectPathRange } { TfrmSelectPathRange.FormCreate } procedure TfrmSelectPathRange.FormCreate(Sender: TObject); begin InitPropStorage(Self); end; { TfrmSelectPathRange.edtSelectTextKeyUp } procedure TfrmSelectPathRange.edtSelectTextKeyUp(Sender: TObject; var Key: word; Shift: TShiftState); begin SomethingChange(Sender); end; { TfrmSelectPathRange.edtSelectTextMouseUp } procedure TfrmSelectPathRange.edtSelectTextMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); begin SomethingChange(Sender); end; { TfrmSelectPathRange.lbDirectoriesSelectionChange } procedure TfrmSelectPathRange.lbDirectoriesSelectionChange(Sender: TObject; User: boolean); begin SomethingChange(Sender); end; { TfrmSelectPathRange.SomethingChange } procedure TfrmSelectPathRange.SomethingChange(Sender: TObject); begin ResfreshHint; end; { TfrmSelectPathRange.ResfreshHint } procedure TfrmSelectPathRange.ResfreshHint; var sTempo: string; iSeeker: integer; begin rbFirstFromEnd.Checked := not rbFirstFromStart.Checked; sTempo := ''; for iSeeker := 0 to pred(lbDirectories.Items.Count) do if lbDirectories.Selected[iSeeker] then begin if sTempo <> '' then sTempo += edSeparator.Text; if rbFirstFromStart.Checked then sTempo += '[' + Prefix + IntToStr(iSeeker) + ']' else sTempo += '[' + Prefix + '-' + IntToStr(lbDirectories.Items.Count - iSeeker) + ']'; end; lblValueToReturn.Caption := sTempo; end; { ShowSelectPathRangeDlg } function ShowSelectPathRangeDlg(TheOwner: TCustomForm; const ACaption, AText, sPrefix: string; var sResultingMaskValue: string): boolean; var Directories: TStringArray; sDirectory: string; begin with TfrmSelectPathRange.Create(TheOwner) do try Result := False; rbFirstFromEnd.Checked := not rbFirstFromStart.Checked; edSeparator.Text := gMulRenPathRangeSeparator; Caption := ACaption; Directories := (Trim(AText)).Split([PathDelim]); for sDirectory in Directories do lbDirectories.Items.Add(sDirectory); Prefix := sPrefix; if ShowModal = mrOk then begin if lblValueToReturn.Caption <> '' then begin gMulRenPathRangeSeparator := edSeparator.Text; sResultingMaskValue := lblValueToReturn.Caption; Result := True; end; end; finally Free; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselecttextrange.lfm�����������������������������������������������������������0000644�0001750�0000144�00000015002�14743153644�017442� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSelectTextRange: TfrmSelectTextRange Left = 693 Height = 215 Top = 288 Width = 518 AutoSize = True BorderStyle = bsDialog ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 215 ClientWidth = 518 OnCreate = FormCreate Position = poOwnerFormCenter SessionProperties = 'Width;Top;Left;rbDescriptionFirstLast.Checked;rbDescriptionFirstLength.Checked;rbFirstFromEnd.Checked;rbFirstFromStart.Checked;rbLastFromEnd.Checked;rbLastFromStart.Checked' LCLVersion = '2.0.6.0' object edtSelectText: TEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblSelectText AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 24 Width = 506 Anchors = [akTop, akLeft, akRight] AutoSelect = False Constraints.MinWidth = 300 HideSelection = False OnChange = SomethingChange OnKeyUp = edtSelectTextKeyUp OnMouseUp = edtSelectTextMouseUp TabOrder = 0 end object lblSelectText: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 6 Width = 157 Caption = '&Select the characters to insert:' FocusControl = edtSelectText ParentColor = False end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblResult AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 26 Top = 141 Width = 506 Align = alNone Anchors = [akTop, akLeft, akRight] OKButton.Name = 'OKButton' OKButton.Caption = '&OK' OKButton.DefaultCaption = False HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.Caption = '&Cancel' CancelButton.DefaultCaption = False TabOrder = 1 ShowButtons = [pbOK, pbCancel] ShowBevel = False end object gbRangeDescription: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = edtSelectText AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 64 Top = 53 Width = 114 AutoSize = True BorderSpacing.Top = 6 Caption = 'Range description' ChildSizing.LeftRightSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 44 ClientWidth = 110 TabOrder = 2 object rbDescriptionFirstLast: TRadioButton AnchorSideLeft.Control = gbRangeDescription AnchorSideTop.Control = gbRangeDescription Left = 6 Height = 19 Top = 0 Width = 74 Caption = '[&First:Last]' Checked = True OnChange = SomethingChange TabOrder = 0 TabStop = True end object rbDescriptionFirstLength: TRadioButton AnchorSideLeft.Control = gbRangeDescription AnchorSideTop.Control = rbDescriptionFirstLast AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 22 Width = 90 BorderSpacing.Bottom = 3 Caption = '[First,&Length]' OnChange = SomethingChange TabOrder = 1 end end object lblResult: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbRangeDescription AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 15 Top = 120 Width = 35 Caption = 'Result:' ParentColor = False end object gbCountFirstFrom: TGroupBox AnchorSideLeft.Control = gbRangeDescription AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtSelectText AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 126 Height = 64 Top = 53 Width = 104 AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Count first from' ChildSizing.LeftRightSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 44 ClientWidth = 100 TabOrder = 3 object rbFirstFromStart: TRadioButton AnchorSideLeft.Control = gbCountFirstFrom AnchorSideTop.Control = gbCountFirstFrom Left = 6 Height = 19 Top = 0 Width = 65 Caption = 'The sta&rt' Checked = True OnChange = SomethingChange TabOrder = 0 TabStop = True end object rbFirstFromEnd: TRadioButton AnchorSideLeft.Control = gbCountFirstFrom AnchorSideTop.Control = rbFirstFromStart AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 22 Width = 62 BorderSpacing.Bottom = 3 Caption = 'The en&d' OnChange = SomethingChange TabOrder = 1 end end object gbCountLastFrom: TGroupBox AnchorSideLeft.Control = gbCountFirstFrom AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edtSelectText AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 236 Height = 64 Top = 53 Width = 102 AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Count last from' ChildSizing.LeftRightSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 44 ClientWidth = 98 TabOrder = 4 object rbLastFromStart: TRadioButton AnchorSideLeft.Control = gbCountLastFrom AnchorSideTop.Control = gbCountLastFrom Left = 6 Height = 19 Top = 0 Width = 65 Caption = 'The s&tart' Checked = True OnChange = SomethingChange TabOrder = 0 TabStop = True end object rbLastFromEnd: TRadioButton AnchorSideLeft.Control = gbCountLastFrom AnchorSideTop.Control = rbLastFromStart AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 22 Width = 62 BorderSpacing.Bottom = 3 Caption = 'The &end' OnChange = SomethingChange TabOrder = 1 end end object lblValueToReturn: TLabel AnchorSideLeft.Control = lblResult AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbRangeDescription AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 44 Height = 15 Top = 120 Width = 468 Anchors = [akTop, akLeft, akRight] AutoSize = False ParentColor = False end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselecttextrange.lrj�����������������������������������������������������������0000644�0001750�0000144�00000004076�14743153644�017464� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":155530970,"name":"tfrmselecttextrange.lblselecttext.caption","sourcebytes":[38,83,101,108,101,99,116,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,111,32,105,110,115,101,114,116,58],"value":"&Select the characters to insert:"}, {"hash":11067,"name":"tfrmselecttextrange.buttonpanel.okbutton.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmselecttextrange.buttonpanel.cancelbutton.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":3531742,"name":"tfrmselecttextrange.gbrangedescription.caption","sourcebytes":[82,97,110,103,101,32,100,101,115,99,114,105,112,116,105,111,110],"value":"Range description"}, {"hash":174031725,"name":"tfrmselecttextrange.rbdescriptionfirstlast.caption","sourcebytes":[91,38,70,105,114,115,116,58,76,97,115,116,93],"value":"[&First:Last]"}, {"hash":37673821,"name":"tfrmselecttextrange.rbdescriptionfirstlength.caption","sourcebytes":[91,70,105,114,115,116,44,38,76,101,110,103,116,104,93],"value":"[First,&Length]"}, {"hash":147505962,"name":"tfrmselecttextrange.lblresult.caption","sourcebytes":[82,101,115,117,108,116,58],"value":"Result:"}, {"hash":251965197,"name":"tfrmselecttextrange.gbcountfirstfrom.caption","sourcebytes":[67,111,117,110,116,32,102,105,114,115,116,32,102,114,111,109],"value":"Count first from"}, {"hash":128947172,"name":"tfrmselecttextrange.rbfirstfromstart.caption","sourcebytes":[84,104,101,32,115,116,97,38,114,116],"value":"The sta&rt"}, {"hash":242664804,"name":"tfrmselecttextrange.rbfirstfromend.caption","sourcebytes":[84,104,101,32,101,110,38,100],"value":"The en&d"}, {"hash":103866813,"name":"tfrmselecttextrange.gbcountlastfrom.caption","sourcebytes":[67,111,117,110,116,32,108,97,115,116,32,102,114,111,109],"value":"Count last from"}, {"hash":123209444,"name":"tfrmselecttextrange.rblastfromstart.caption","sourcebytes":[84,104,101,32,115,38,116,97,114,116],"value":"The s&tart"}, {"hash":242405348,"name":"tfrmselecttextrange.rblastfromend.caption","sourcebytes":[84,104,101,32,38,101,110,100],"value":"The &end"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fselecttextrange.pas�����������������������������������������������������������0000644�0001750�0000144�00000013103�14743153644�017447� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Multi-Rename text range selector dialog window Copyright (C) 2007-2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fSelectTextRange; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel, Buttons, ExtCtrls, //DC uOSForms; type { TfrmSelectTextRange } TfrmSelectTextRange = class(TModalForm) ButtonPanel: TButtonPanel; edtSelectText: TEdit; gbRangeDescription: TGroupBox; gbCountFirstFrom: TGroupBox; gbCountLastFrom: TGroupBox; lblResult: TLabel; lblValueToReturn: TLabel; lblSelectText: TLabel; rbDescriptionFirstLast: TRadioButton; rbFirstFromStart: TRadioButton; rbLastFromStart: TRadioButton; rbDescriptionFirstLength: TRadioButton; rbFirstFromEnd: TRadioButton; rbLastFromEnd: TRadioButton; procedure edtSelectTextKeyUp(Sender: TObject; var {%H-}Key: word; {%H-}Shift: TShiftState); procedure edtSelectTextMouseUp(Sender: TObject; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: integer); procedure FormCreate(Sender: TObject); procedure SomethingChange(Sender: TObject); private FCanvaForAutosize: TControlCanvas; FSelStart, FSelFinish, FWholeLength: integer; FPrefix: string; procedure ResfreshHint; public property Prefix: string read FPrefix write FPrefix; end; function ShowSelectTextRangeDlg(TheOwner: TCustomForm; const ACaption, AText, sPrefix: string; var sResultingMaskValue: string): boolean; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. //DC uGlobs; function ShowSelectTextRangeDlg(TheOwner: TCustomForm; const ACaption, AText, sPrefix: string; var sResultingMaskValue: string): boolean; begin with TfrmSelectTextRange.Create(TheOwner) do try Result := False; Caption := ACaption; edtSelectText.Constraints.MinWidth := FCanvaForAutosize.TextWidth(AText) + 20; edtSelectText.Text := AText; Prefix := sPrefix; rbDescriptionFirstLength.Checked := not rbDescriptionFirstLast.Checked; rbFirstFromEnd.Checked := not rbFirstFromStart.Checked; rbLastFromEnd.Checked := not rbLastFromStart.Checked; if ShowModal = mrOk then begin if (FSelFinish >= FSelStart) and (lblValueToReturn.Caption <> '') then begin sResultingMaskValue := lblValueToReturn.Caption; Result := True; end; end; finally Free; end; end; { TfrmSelectTextRange } procedure TfrmSelectTextRange.SomethingChange(Sender: TObject); begin ResfreshHint; end; procedure TfrmSelectTextRange.edtSelectTextKeyUp(Sender: TObject; var Key: word; Shift: TShiftState); begin SomethingChange(Sender); end; procedure TfrmSelectTextRange.edtSelectTextMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer); begin SomethingChange(Sender); end; procedure TfrmSelectTextRange.FormCreate(Sender: TObject); begin InitPropStorage(Self); // TEdit "edtSelectText" does not have Canvas. // We will use "FCanvaForAutosize" to determine the required width to hold the whole text. // This way, we will see it all. FCanvaForAutosize := TControlCanvas.Create; FCanvaForAutosize.Control := edtSelectText; FCanvaForAutosize.Font.Assign(edtSelectText.Font); end; procedure TfrmSelectTextRange.ResfreshHint; var sTempo: string; begin gbCountLastFrom.Enabled := not rbDescriptionFirstLength.Checked; sTempo := ''; FSelStart := edtSelectText.SelStart + 1; FSelFinish := edtSelectText.SelStart + edtSelectText.SelLength; FWholeLength := length(edtSelectText.Text); if (FSelFinish >= FSelStart) and (FWholeLength > 0) then begin if rbFirstFromStart.Checked then begin if FSelFinish = FSelStart then sTempo := Format('%d', [FSelStart]) else begin if rbDescriptionFirstLength.Checked then sTempo := Format('%d,%d', [FSelStart, succ(FSelFinish - FSelStart)]) else if rbLastFromStart.Checked then sTempo := Format('%d:%d', [FSelStart, FSelFinish]) else sTempo := Format('%d:-%d', [FSelStart, succ(FWholeLength - FSelFinish)]); end; end else begin if FSelFinish = FSelStart then sTempo := Format('-%d', [succ(FWholeLength - FSelStart)]) else begin if rbDescriptionFirstLength.Checked then sTempo := Format('-%d,%d', [succ(FWholeLength - FSelFinish), succ(FSelFinish - FSelStart)]) else if rbLastFromStart.Checked then sTempo := Format('-%d:%d', [succ(FWholeLength - FSelStart), FSelFinish]) else sTempo := Format('-%d:-%d', [succ(FWholeLength - FSelStart), succ(FWholeLength - FSelFinish)]); end; end; lblValueToReturn.Caption := Format('[%s%s]', [Prefix, sTempo]); end else begin lblValueToReturn.Caption := ''; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsetfileproperties.lfm���������������������������������������������������������0000644�0001750�0000144�00000065333�14743153644�020025� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSetFileProperties: TfrmSetFileProperties Left = 477 Height = 593 Top = 127 Width = 309 AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Change attributes' ClientHeight = 593 ClientWidth = 309 OnCreate = FormCreate Position = poScreenCenter LCLVersion = '1.4.3.0' object btnOK: TBitBtn AnchorSideTop.Control = chkRecursive AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnCancel AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 95 Height = 26 Top = 518 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.Bottom = 10 Caption = '&OK' Constraints.MinWidth = 100 Default = True Kind = bkOK ModalResult = 1 OnClick = btnOKClick TabOrder = 4 end object btnCancel: TBitBtn AnchorSideTop.Control = btnOK AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 201 Height = 26 Top = 518 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 8 BorderSpacing.Bottom = 10 Cancel = True Caption = '&Cancel' Constraints.MinWidth = 100 Kind = bkCancel ModalResult = 2 TabOrder = 5 end object chkRecursive: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbUnixAttributes AnchorSideTop.Side = asrBottom Left = 12 Height = 19 Top = 493 Width = 128 BorderSpacing.Left = 12 BorderSpacing.Top = 8 Caption = 'Including subfolders' TabOrder = 3 end object gbTimeSamp: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 6 Height = 113 Top = 6 Width = 293 AutoSize = True BorderSpacing.Around = 6 Caption = 'Timestamp properties' ClientHeight = 93 ClientWidth = 289 TabOrder = 0 object DatesPanel: TPanel AnchorSideLeft.Control = ChecksPanel AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = gbTimeSamp AnchorSideRight.Control = gbTimeSamp AnchorSideRight.Side = asrBottom Left = 96 Height = 81 Top = 6 Width = 193 AutoSize = True BorderSpacing.Left = 6 BorderSpacing.Around = 6 BevelOuter = bvNone ClientHeight = 81 ClientWidth = 193 TabOrder = 1 object ZVCreationDateTime: TDateTimePicker AnchorSideLeft.Control = DatesPanel AnchorSideTop.Control = DatesPanel AnchorSideRight.Control = DatesPanel AnchorSideRight.Side = asrBottom Left = 0 Height = 23 Top = 0 Width = 154 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 0 Enabled = False TrailingSeparator = False TextForNullDate = ' ' LeadingZeros = True Kind = dtkDateTime TimeFormat = tf24 TimeDisplay = tdHMSMs DateMode = dmComboBox Date = 40608 Time = 0.0684693287039408 UseDefaultSeparators = True OnChange = ZVCreationDateTimeChange OnClick = ZVCreationDateTimeClick end object ZVLastWriteDateTime: TDateTimePicker AnchorSideLeft.Control = DatesPanel AnchorSideTop.Control = ZVCreationDateTime AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 23 Top = 29 Width = 154 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 1 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Enabled = False TrailingSeparator = False TextForNullDate = ' ' LeadingZeros = True Kind = dtkDateTime TimeFormat = tf24 TimeDisplay = tdHMSMs DateMode = dmComboBox Date = 40608 Time = 0.0684693287039408 UseDefaultSeparators = True OnChange = ZVLastWriteDateTimeChange OnClick = ZVLastWriteDateTimeClick end object ZVLastAccessDateTime: TDateTimePicker AnchorSideLeft.Control = DatesPanel AnchorSideTop.Control = ZVLastWriteDateTime AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 0 Height = 23 Top = 58 Width = 154 CenturyFrom = 1941 MaxDate = 2958465 MinDate = -53780 TabOrder = 2 BorderSpacing.Top = 6 Enabled = False TrailingSeparator = False TextForNullDate = ' ' LeadingZeros = True Kind = dtkDateTime TimeFormat = tf24 TimeDisplay = tdHMSMs DateMode = dmComboBox Date = 40608 Time = 0.0684693287039408 UseDefaultSeparators = True OnChange = ZVLastAccessDateTimeChange OnClick = ZVLastAccessDateTimeClick end object btnLastWriteTime: TSpeedButton AnchorSideLeft.Control = ZVLastWriteDateTime AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ZVLastWriteDateTime AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 160 Height = 21 Top = 30 Width = 23 BorderSpacing.Left = 6 BorderSpacing.Right = 10 Enabled = False Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000D5D5D40000000000FFFFFF00D1D5D4D7B2B2B3FFB3B4B4FFB3B4B4FFCACE CDFFC7C4C51900000000D4D4D400000000000000000000000000000000000000 000000000000E2E2E19D898B89D7A6A9A7FFCCCCCCFFD5DCDEFFCFD0CFFFB5B8 B7FE8E9291F9CCCCCDD900000000C0C1C1000000000000000000000000000000 0000CACAC964909392FFC2C5C3FFF4F6F6FFFAFEFEFFC27443FFFBFFFFFFF5F8 F9FFDDDFDEFF8B8E8CFDBBBCBCE6FFFFFF050000000000000000C3C3C3000000 0000A1A2A1FFCACCCCFEFCFEFFFFC98C64FFFDFFFFFFF3E5DCFFF8FCFEFFCB8E 67FFF0F8FAFFEAEAEAFF989A9AFF91939325C3C3C30100000000FFFFFF05BFBF BFE6A3A7A6FDFDFFFFFFD7CABEFFEDF6F7FFEDEFEEFFF1F3F2FFEDEFEEFFF4FC FEFFE7E6E1FFF7F4F1FFD0D1D0FEB1B2B1FFFFFFFF1900000000D0D1D1359395 94FFDDE0DFFFF0F4F3FFD3C7BBFFCDD1D0FFC9CECCFFE7EBE9FFECF0EEFFEBF0 EDFFEBEBE6FFE2E2DEFFF0F2F0FF949795FECECFCFD000000000CAC9C9338C90 8FFFEDEAE6FFD2C0B2FFC5CACAFFBFC4C2FFC4C8C8FFC3C6C5FF767778FF7677 78FFB6B9BAFFD4C9BDFFEADCD1FF969B99FFC8C7C8CB00000000CAC9C9338C90 8EFFECE9E6FFCABAACFFC1C7C6FFC5CBC9FFD2D8D6FF1C1D1DFF929495FF9C9F 9EFFCFD4D3FFD2C6BCFFECDED4FF959A98FFC8C8C8CB00000000D0D1D1359395 94FFE0E1E0FFE0E4E4FFC4B7ACFFBEC3C2FFCBCFCEFF1F1F1FFFB8BBBCFFCFD4 D3FFE5E3DFFFDFDEDAFFE6E9E9FF959796FECECFCFD000000000FFFFFF05BFBF BFE6A1A6A4FDF6F9FAFFCBBFB2FFC9D4D5FFC3C8C6FF1B1B1BFFBABCBDFFD6E0 E1FFDFDEDAFFF7F4F0FFD2D3D2FEB1B2B2FFFFFFFF1900000000C3C3C3000000 00009FA2A1FFD0D2D2FEF5F8F8FFCA8D66FFD8E3E4FF1A1D1EFFC4C8CAFFC68A 62FFEDF5F7FFE9EAEAFF979999FF92949325C3C3C30100000000000000000000 0000C9C9C964909392FFC0C2C1FFEFF3F3FFFCFEFFFFA0633BFFFAFFFFFFF2F5 F5FFDEDFDEFF919492FDBABBBAE6FFFFFF050000000000000000000000000000 000000000000E2E1E19D8E9090D7AAACABFFC6C9C8FFD2DADCFFCED0CEFFB6B9 B8FE909492F9CCCCCCD900000000C0C1C0000000000000000000000000000000 0000D5D4D40000000000FFFFFF00CFD2D1D7C0C5C3FFBFC4C2FF8D9390FFD2D5 D4FFC7C3C41900000000D4D4D400000000000000000000000000000000000000 0000000000000000000000000000E8ECEBCF777D7AFFC2C7C5FF7C827FFFCDD1 D0FF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000E8EBEB297E8481337B827E3383898633CED3 D137000000000000000000000000000000000000000000000000 } OnClick = btnLastWriteTimeClick end object btnCreationTime: TSpeedButton AnchorSideLeft.Control = ZVCreationDateTime AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ZVCreationDateTime AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 160 Height = 20 Top = 1 Width = 23 BorderSpacing.Left = 6 BorderSpacing.Right = 10 Enabled = False Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000D5D5D40000000000FFFFFF00D1D5D4D7B2B2B3FFB3B4B4FFB3B4B4FFCACE CDFFC7C4C51900000000D4D4D400000000000000000000000000000000000000 000000000000E2E2E19D898B89D7A6A9A7FFCCCCCCFFD5DCDEFFCFD0CFFFB5B8 B7FE8E9291F9CCCCCDD900000000C0C1C1000000000000000000000000000000 0000CACAC964909392FFC2C5C3FFF4F6F6FFFAFEFEFFC27443FFFBFFFFFFF5F8 F9FFDDDFDEFF8B8E8CFDBBBCBCE6FFFFFF050000000000000000C3C3C3000000 0000A1A2A1FFCACCCCFEFCFEFFFFC98C64FFFDFFFFFFF3E5DCFFF8FCFEFFCB8E 67FFF0F8FAFFEAEAEAFF989A9AFF91939325C3C3C30100000000FFFFFF05BFBF BFE6A3A7A6FDFDFFFFFFD7CABEFFEDF6F7FFEDEFEEFFF1F3F2FFEDEFEEFFF4FC FEFFE7E6E1FFF7F4F1FFD0D1D0FEB1B2B1FFFFFFFF1900000000D0D1D1359395 94FFDDE0DFFFF0F4F3FFD3C7BBFFCDD1D0FFC9CECCFFE7EBE9FFECF0EEFFEBF0 EDFFEBEBE6FFE2E2DEFFF0F2F0FF949795FECECFCFD000000000CAC9C9338C90 8FFFEDEAE6FFD2C0B2FFC5CACAFFBFC4C2FFC4C8C8FFC3C6C5FF767778FF7677 78FFB6B9BAFFD4C9BDFFEADCD1FF969B99FFC8C7C8CB00000000CAC9C9338C90 8EFFECE9E6FFCABAACFFC1C7C6FFC5CBC9FFD2D8D6FF1C1D1DFF929495FF9C9F 9EFFCFD4D3FFD2C6BCFFECDED4FF959A98FFC8C8C8CB00000000D0D1D1359395 94FFE0E1E0FFE0E4E4FFC4B7ACFFBEC3C2FFCBCFCEFF1F1F1FFFB8BBBCFFCFD4 D3FFE5E3DFFFDFDEDAFFE6E9E9FF959796FECECFCFD000000000FFFFFF05BFBF BFE6A1A6A4FDF6F9FAFFCBBFB2FFC9D4D5FFC3C8C6FF1B1B1BFFBABCBDFFD6E0 E1FFDFDEDAFFF7F4F0FFD2D3D2FEB1B2B2FFFFFFFF1900000000C3C3C3000000 00009FA2A1FFD0D2D2FEF5F8F8FFCA8D66FFD8E3E4FF1A1D1EFFC4C8CAFFC68A 62FFEDF5F7FFE9EAEAFF979999FF92949325C3C3C30100000000000000000000 0000C9C9C964909392FFC0C2C1FFEFF3F3FFFCFEFFFFA0633BFFFAFFFFFFF2F5 F5FFDEDFDEFF919492FDBABBBAE6FFFFFF050000000000000000000000000000 000000000000E2E1E19D8E9090D7AAACABFFC6C9C8FFD2DADCFFCED0CEFFB6B9 B8FE909492F9CCCCCCD900000000C0C1C0000000000000000000000000000000 0000D5D4D40000000000FFFFFF00CFD2D1D7C0C5C3FFBFC4C2FF8D9390FFD2D5 D4FFC7C3C41900000000D4D4D400000000000000000000000000000000000000 0000000000000000000000000000E8ECEBCF777D7AFFC2C7C5FF7C827FFFCDD1 D0FF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000E8EBEB297E8481337B827E3383898633CED3 D137000000000000000000000000000000000000000000000000 } OnClick = btnCreationTimeClick end object btnLastAccessTime: TSpeedButton AnchorSideLeft.Control = ZVLastAccessDateTime AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ZVLastAccessDateTime AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 160 Height = 21 Top = 59 Width = 23 BorderSpacing.Left = 6 BorderSpacing.Right = 10 Enabled = False Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000D5D5D40000000000FFFFFF00D1D5D4D7B2B2B3FFB3B4B4FFB3B4B4FFCACE CDFFC7C4C51900000000D4D4D400000000000000000000000000000000000000 000000000000E2E2E19D898B89D7A6A9A7FFCCCCCCFFD5DCDEFFCFD0CFFFB5B8 B7FE8E9291F9CCCCCDD900000000C0C1C1000000000000000000000000000000 0000CACAC964909392FFC2C5C3FFF4F6F6FFFAFEFEFFC27443FFFBFFFFFFF5F8 F9FFDDDFDEFF8B8E8CFDBBBCBCE6FFFFFF050000000000000000C3C3C3000000 0000A1A2A1FFCACCCCFEFCFEFFFFC98C64FFFDFFFFFFF3E5DCFFF8FCFEFFCB8E 67FFF0F8FAFFEAEAEAFF989A9AFF91939325C3C3C30100000000FFFFFF05BFBF BFE6A3A7A6FDFDFFFFFFD7CABEFFEDF6F7FFEDEFEEFFF1F3F2FFEDEFEEFFF4FC FEFFE7E6E1FFF7F4F1FFD0D1D0FEB1B2B1FFFFFFFF1900000000D0D1D1359395 94FFDDE0DFFFF0F4F3FFD3C7BBFFCDD1D0FFC9CECCFFE7EBE9FFECF0EEFFEBF0 EDFFEBEBE6FFE2E2DEFFF0F2F0FF949795FECECFCFD000000000CAC9C9338C90 8FFFEDEAE6FFD2C0B2FFC5CACAFFBFC4C2FFC4C8C8FFC3C6C5FF767778FF7677 78FFB6B9BAFFD4C9BDFFEADCD1FF969B99FFC8C7C8CB00000000CAC9C9338C90 8EFFECE9E6FFCABAACFFC1C7C6FFC5CBC9FFD2D8D6FF1C1D1DFF929495FF9C9F 9EFFCFD4D3FFD2C6BCFFECDED4FF959A98FFC8C8C8CB00000000D0D1D1359395 94FFE0E1E0FFE0E4E4FFC4B7ACFFBEC3C2FFCBCFCEFF1F1F1FFFB8BBBCFFCFD4 D3FFE5E3DFFFDFDEDAFFE6E9E9FF959796FECECFCFD000000000FFFFFF05BFBF BFE6A1A6A4FDF6F9FAFFCBBFB2FFC9D4D5FFC3C8C6FF1B1B1BFFBABCBDFFD6E0 E1FFDFDEDAFFF7F4F0FFD2D3D2FEB1B2B2FFFFFFFF1900000000C3C3C3000000 00009FA2A1FFD0D2D2FEF5F8F8FFCA8D66FFD8E3E4FF1A1D1EFFC4C8CAFFC68A 62FFEDF5F7FFE9EAEAFF979999FF92949325C3C3C30100000000000000000000 0000C9C9C964909392FFC0C2C1FFEFF3F3FFFCFEFFFFA0633BFFFAFFFFFFF2F5 F5FFDEDFDEFF919492FDBABBBAE6FFFFFF050000000000000000000000000000 000000000000E2E1E19D8E9090D7AAACABFFC6C9C8FFD2DADCFFCED0CEFFB6B9 B8FE909492F9CCCCCCD900000000C0C1C0000000000000000000000000000000 0000D5D4D40000000000FFFFFF00CFD2D1D7C0C5C3FFBFC4C2FF8D9390FFD2D5 D4FFC7C3C41900000000D4D4D400000000000000000000000000000000000000 0000000000000000000000000000E8ECEBCF777D7AFFC2C7C5FF7C827FFFCDD1 D0FF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000E8EBEB297E8481337B827E3383898633CED3 D137000000000000000000000000000000000000000000000000 } OnClick = btnLastAccessTimeClick end end object ChecksPanel: TPanel AnchorSideTop.Control = DatesPanel AnchorSideBottom.Control = DatesPanel AnchorSideBottom.Side = asrBottom Left = 6 Height = 81 Top = 6 Width = 78 Anchors = [akTop, akLeft, akBottom] AutoSize = True BevelOuter = bvNone ClientHeight = 81 ClientWidth = 78 TabOrder = 0 object chkCreationTime: TCheckBox AnchorSideLeft.Control = ChecksPanel AnchorSideTop.Control = ChecksPanel Left = 6 Height = 19 Top = 6 Width = 64 BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Created:' Enabled = False OnChange = chkCreationTimeChange TabOrder = 0 end object chkLastWriteTime: TCheckBox AnchorSideLeft.Control = ChecksPanel AnchorSideTop.Control = ChecksPanel AnchorSideTop.Side = asrCenter Left = 6 Height = 19 Top = 31 Width = 71 BorderSpacing.Left = 6 Caption = 'Modified:' Enabled = False OnChange = chkLastWriteTimeChange TabOrder = 1 end object chkLastAccessTime: TCheckBox AnchorSideLeft.Control = ChecksPanel AnchorSideTop.Side = asrCenter AnchorSideBottom.Control = ChecksPanel AnchorSideBottom.Side = asrBottom Left = 6 Height = 19 Top = 56 Width = 72 Anchors = [akLeft, akBottom] BorderSpacing.Left = 6 BorderSpacing.Bottom = 6 Caption = 'Accessed:' Enabled = False OnChange = chkLastAccessTimeChange TabOrder = 2 end end end object gbWinAttributes: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbTimeSamp AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 97 Top = 125 Width = 297 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Attributes' ClientHeight = 77 ClientWidth = 293 TabOrder = 1 Visible = False object chkSystem: TCheckBox AnchorSideLeft.Control = chkHidden AnchorSideTop.Control = chkReadOnly Left = 171 Height = 19 Top = 31 Width = 58 AllowGrayed = True BorderSpacing.Bottom = 6 Caption = 'System' OnClick = chkChangeAttrClick State = cbGrayed TabOrder = 3 end object chkHidden: TCheckBox AnchorSideTop.Control = chkArchive Left = 171 Height = 19 Top = 6 Width = 59 AllowGrayed = True Anchors = [akTop] Caption = 'Hidden' OnClick = chkChangeAttrClick State = cbGrayed TabOrder = 2 end object chkArchive: TCheckBox AnchorSideLeft.Control = gbWinAttributes AnchorSideTop.Control = gbWinAttributes Left = 6 Height = 19 Top = 6 Width = 60 AllowGrayed = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Archive' OnClick = chkChangeAttrClick State = cbGrayed TabOrder = 0 end object chkReadOnly: TCheckBox AnchorSideLeft.Control = chkArchive AnchorSideTop.Control = chkArchive AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 31 Width = 72 AllowGrayed = True BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 Caption = 'Read only' OnClick = chkChangeAttrClick State = cbGrayed TabOrder = 1 end object lblAttrInfo: TLabel AnchorSideLeft.Control = chkReadOnly AnchorSideTop.Control = chkReadOnly AnchorSideTop.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 6 Height = 17 Top = 56 Width = 189 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 Caption = '(gray field means unchanged value)' ParentColor = False end end object gbUnixAttributes: TGroupBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = gbWinAttributes AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 6 Height = 257 Top = 228 Width = 297 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Attributes' ClientHeight = 237 ClientWidth = 293 TabOrder = 2 Visible = False object lblRead: TLabel AnchorSideLeft.Control = cbReadOwner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = gbUnixAttributes Left = 94 Height = 15 Top = 0 Width = 26 Caption = 'Read' ParentColor = False end object lblWrite: TLabel AnchorSideLeft.Control = cbWriteOwner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = lblRead Left = 168 Height = 15 Top = 0 Width = 28 Caption = 'Write' ParentColor = False end object lblExec: TLabel AnchorSideLeft.Control = cbExecOwner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = lblRead Left = 235 Height = 15 Top = 0 Width = 40 Caption = 'Execute' ParentColor = False end object cbExecOwner: TCheckBox AnchorSideTop.Control = cbReadOwner Left = 245 Height = 19 Top = 21 Width = 20 AllowGrayed = True Anchors = [akTop] OnClick = cbChangeModeClick State = cbGrayed TabOrder = 2 end object cbWriteOwner: TCheckBox AnchorSideTop.Control = cbReadOwner Left = 172 Height = 19 Top = 21 Width = 20 AllowGrayed = True Anchors = [akTop] OnClick = cbChangeModeClick State = cbGrayed TabOrder = 1 end object cbReadOwner: TCheckBox AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = lblRead AnchorSideTop.Side = asrBottom Left = 97 Height = 19 Top = 21 Width = 20 AllowGrayed = True Anchors = [akTop] BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 0 end object lblAttrOwnerStr: TLabel AnchorSideLeft.Control = gbUnixAttributes AnchorSideTop.Control = cbReadOwner AnchorSideTop.Side = asrCenter Left = 7 Height = 15 Top = 23 Width = 35 BorderSpacing.Left = 7 Caption = 'Owner' ParentColor = False end object lblAttrGroupStr: TLabel AnchorSideLeft.Control = lblAttrOwnerStr AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrCenter Left = 7 Height = 15 Top = 48 Width = 33 Caption = 'Group' ParentColor = False end object cbReadGroup: TCheckBox AnchorSideLeft.Control = cbReadOwner AnchorSideTop.Control = cbReadOwner AnchorSideTop.Side = asrBottom Left = 97 Height = 19 Top = 46 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 3 end object cbWriteGroup: TCheckBox AnchorSideLeft.Control = cbWriteOwner AnchorSideTop.Control = cbReadGroup Left = 172 Height = 19 Top = 46 Width = 20 AllowGrayed = True OnClick = cbChangeModeClick State = cbGrayed TabOrder = 4 end object cbExecGroup: TCheckBox AnchorSideLeft.Control = cbExecOwner AnchorSideTop.Control = cbReadGroup Left = 245 Height = 19 Top = 46 Width = 20 AllowGrayed = True OnClick = cbChangeModeClick State = cbGrayed TabOrder = 5 end object lblAttrOtherStr: TLabel AnchorSideLeft.Control = lblAttrOwnerStr AnchorSideTop.Control = cbReadOther AnchorSideTop.Side = asrCenter Left = 7 Height = 15 Top = 73 Width = 30 Caption = 'Other' ParentColor = False end object cbReadOther: TCheckBox AnchorSideLeft.Control = cbReadOwner AnchorSideTop.Control = cbReadGroup AnchorSideTop.Side = asrBottom Left = 97 Height = 19 Top = 71 Width = 20 AllowGrayed = True BorderSpacing.Top = 6 OnClick = cbChangeModeClick State = cbGrayed TabOrder = 6 end object cbWriteOther: TCheckBox AnchorSideLeft.Control = cbWriteOwner AnchorSideTop.Control = cbReadOther Left = 172 Height = 19 Top = 71 Width = 20 AllowGrayed = True OnClick = cbChangeModeClick State = cbGrayed TabOrder = 7 end object cbExecOther: TCheckBox AnchorSideLeft.Control = cbExecOwner AnchorSideTop.Control = cbReadOther Left = 245 Height = 19 Top = 71 Width = 20 AllowGrayed = True OnClick = cbChangeModeClick State = cbGrayed TabOrder = 8 end object Bevel1: TBevel AnchorSideTop.Control = cbReadOther AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 4 Height = 4 Top = 96 Width = 289 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Shape = bsTopLine Style = bsRaised end object cbSticky: TCheckBox AnchorSideLeft.Control = cbSuid AnchorSideTop.Control = cbSuid AnchorSideTop.Side = asrBottom Left = 97 Height = 19 Top = 131 Width = 51 AllowGrayed = True BorderSpacing.Top = 6 Caption = 'Sticky' OnClick = cbChangeModeClick State = cbGrayed TabOrder = 11 end object cbSgid: TCheckBox AnchorSideLeft.Control = cbWriteOwner AnchorSideTop.Control = Bevel1 AnchorSideTop.Side = asrBottom Left = 172 Height = 19 Top = 106 Width = 45 AllowGrayed = True BorderSpacing.Top = 6 Caption = 'SGID' OnClick = cbChangeModeClick State = cbGrayed TabOrder = 10 end object cbSuid: TCheckBox AnchorSideLeft.Control = cbReadOwner AnchorSideTop.Control = Bevel1 AnchorSideTop.Side = asrBottom Left = 97 Height = 19 Top = 106 Width = 45 AllowGrayed = True BorderSpacing.Top = 6 Caption = 'SUID' OnClick = cbChangeModeClick State = cbGrayed TabOrder = 9 end object lblAttrBitsStr: TLabel AnchorSideLeft.Control = lblAttrOwnerStr AnchorSideTop.Control = cbSuid AnchorSideTop.Side = asrCenter Left = 7 Height = 15 Top = 108 Width = 22 Caption = 'Bits:' ParentColor = False end object Bevel2: TBevel AnchorSideTop.Control = lblModeInfo AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 4 Height = 4 Top = 177 Width = 289 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 BorderSpacing.Top = 6 BorderSpacing.Right = 6 Shape = bsTopLine Style = bsRaised end object lblOctal: TLabel AnchorSideLeft.Control = lblAttrOtherStr AnchorSideTop.Control = edtOctal AnchorSideTop.Side = asrCenter Left = 7 Height = 15 Top = 191 Width = 31 Caption = 'Octal:' FocusControl = edtOctal ParentColor = False end object edtOctal: TEdit AnchorSideLeft.Control = cbSuid AnchorSideTop.Control = Bevel2 AnchorSideTop.Side = asrBottom Left = 97 Height = 23 Top = 187 Width = 80 BorderSpacing.Top = 6 MaxLength = 4 OnKeyPress = edtOctalKeyPress OnKeyUp = edtOctalKeyUp TabOrder = 12 end object lblAttrTextStr: TLabel AnchorSideLeft.Control = lblAttrOtherStr AnchorSideTop.Control = edtOctal AnchorSideTop.Side = asrBottom Left = 7 Height = 15 Top = 216 Width = 24 BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 Caption = 'Text:' ParentColor = False end object lblAttrText: TLabel AnchorSideLeft.Control = edtOctal AnchorSideTop.Control = lblAttrTextStr AnchorSideTop.Side = asrCenter Left = 97 Height = 15 Top = 216 Width = 55 BorderSpacing.Bottom = 6 Caption = '-----------' ParentColor = False ParentFont = False end object lblModeInfo: TLabel AnchorSideLeft.Control = lblAttrBitsStr AnchorSideTop.Control = cbSticky AnchorSideTop.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 7 Height = 15 Top = 156 Width = 189 BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 Caption = '(gray field means unchanged value)' ParentColor = False end end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsetfileproperties.lrj���������������������������������������������������������0000644�0001750�0000144�00000010624�14743153644�020027� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":96905523,"name":"tfrmsetfileproperties.caption","sourcebytes":[67,104,97,110,103,101,32,97,116,116,114,105,98,117,116,101,115],"value":"Change attributes"}, {"hash":11067,"name":"tfrmsetfileproperties.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmsetfileproperties.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":225888019,"name":"tfrmsetfileproperties.chkrecursive.caption","sourcebytes":[73,110,99,108,117,100,105,110,103,32,115,117,98,102,111,108,100,101,114,115],"value":"Including subfolders"}, {"hash":47347571,"name":"tfrmsetfileproperties.gbtimesamp.caption","sourcebytes":[84,105,109,101,115,116,97,109,112,32,112,114,111,112,101,114,116,105,101,115],"value":"Timestamp properties"}, {"hash":32,"name":"tfrmsetfileproperties.zvcreationdatetime.textfornulldate","sourcebytes":[32],"value":" "}, {"hash":32,"name":"tfrmsetfileproperties.zvlastwritedatetime.textfornulldate","sourcebytes":[32],"value":" "}, {"hash":32,"name":"tfrmsetfileproperties.zvlastaccessdatetime.textfornulldate","sourcebytes":[32],"value":" "}, {"hash":146321370,"name":"tfrmsetfileproperties.chkcreationtime.caption","sourcebytes":[67,114,101,97,116,101,100,58],"value":"Created:"}, {"hash":184332074,"name":"tfrmsetfileproperties.chklastwritetime.caption","sourcebytes":[77,111,100,105,102,105,101,100,58],"value":"Modified:"}, {"hash":164289770,"name":"tfrmsetfileproperties.chklastaccesstime.caption","sourcebytes":[65,99,99,101,115,115,101,100,58],"value":"Accessed:"}, {"hash":150815091,"name":"tfrmsetfileproperties.gbwinattributes.caption","sourcebytes":[65,116,116,114,105,98,117,116,101,115],"value":"Attributes"}, {"hash":95464125,"name":"tfrmsetfileproperties.chksystem.caption","sourcebytes":[83,121,115,116,101,109],"value":"System"}, {"hash":82815678,"name":"tfrmsetfileproperties.chkhidden.caption","sourcebytes":[72,105,100,100,101,110],"value":"Hidden"}, {"hash":143257733,"name":"tfrmsetfileproperties.chkarchive.caption","sourcebytes":[65,114,99,104,105,118,101],"value":"Archive"}, {"hash":124198281,"name":"tfrmsetfileproperties.chkreadonly.caption","sourcebytes":[82,101,97,100,32,111,110,108,121],"value":"Read only"}, {"hash":97017545,"name":"tfrmsetfileproperties.lblattrinfo.caption","sourcebytes":[40,103,114,97,121,32,102,105,101,108,100,32,109,101,97,110,115,32,117,110,99,104,97,110,103,101,100,32,118,97,108,117,101,41],"value":"(gray field means unchanged value)"}, {"hash":150815091,"name":"tfrmsetfileproperties.gbunixattributes.caption","sourcebytes":[65,116,116,114,105,98,117,116,101,115],"value":"Attributes"}, {"hash":363380,"name":"tfrmsetfileproperties.lblread.caption","sourcebytes":[82,101,97,100],"value":"Read"}, {"hash":6197413,"name":"tfrmsetfileproperties.lblwrite.caption","sourcebytes":[87,114,105,116,101],"value":"Write"}, {"hash":216771813,"name":"tfrmsetfileproperties.lblexec.caption","sourcebytes":[69,120,101,99,117,116,101],"value":"Execute"}, {"hash":5694658,"name":"tfrmsetfileproperties.lblattrownerstr.caption","sourcebytes":[79,119,110,101,114],"value":"Owner"}, {"hash":5150400,"name":"tfrmsetfileproperties.lblattrgroupstr.caption","sourcebytes":[71,114,111,117,112],"value":"Group"}, {"hash":5680834,"name":"tfrmsetfileproperties.lblattrotherstr.caption","sourcebytes":[79,116,104,101,114],"value":"Other"}, {"hash":95091241,"name":"tfrmsetfileproperties.cbsticky.caption","sourcebytes":[83,116,105,99,107,121],"value":"Sticky"}, {"hash":359380,"name":"tfrmsetfileproperties.cbsgid.caption","sourcebytes":[83,71,73,68],"value":"SGID"}, {"hash":362964,"name":"tfrmsetfileproperties.cbsuid.caption","sourcebytes":[83,85,73,68],"value":"SUID"}, {"hash":4787050,"name":"tfrmsetfileproperties.lblattrbitsstr.caption","sourcebytes":[66,105,116,115,58],"value":"Bits:"}, {"hash":89827322,"name":"tfrmsetfileproperties.lbloctal.caption","sourcebytes":[79,99,116,97,108,58],"value":"Octal:"}, {"hash":5951354,"name":"tfrmsetfileproperties.lblattrtextstr.caption","sourcebytes":[84,101,120,116,58],"value":"Text:"}, {"hash":265289741,"name":"tfrmsetfileproperties.lblattrtext.caption","sourcebytes":[45,45,45,45,45,45,45,45,45,45,45],"value":"-----------"}, {"hash":97017545,"name":"tfrmsetfileproperties.lblmodeinfo.caption","sourcebytes":[40,103,114,97,121,32,102,105,101,108,100,32,109,101,97,110,115,32,117,110,99,104,97,110,103,101,100,32,118,97,108,117,101,41],"value":"(gray field means unchanged value)"} ]} ������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsetfileproperties.pas���������������������������������������������������������0000644�0001750�0000144�00000042135�14743153644�020025� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Change file properties dialog Copyright (C) 2009-2015 Alexander Koblov (alexx2000@mail.ru) 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 } unit fSetFileProperties; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, ExtCtrls, StdCtrls, Buttons, uFileSourceSetFilePropertyOperation, DCBasicTypes, DateTimePicker; type { TfrmSetFileProperties } TfrmSetFileProperties = class(TForm) Bevel2: TBevel; Bevel1: TBevel; btnCancel: TBitBtn; btnCreationTime: TSpeedButton; btnLastAccessTime: TSpeedButton; btnLastWriteTime: TSpeedButton; btnOK: TBitBtn; cbExecGroup: TCheckBox; cbExecOther: TCheckBox; cbExecOwner: TCheckBox; cbReadGroup: TCheckBox; cbReadOther: TCheckBox; cbReadOwner: TCheckBox; cbSgid: TCheckBox; cbSticky: TCheckBox; cbSuid: TCheckBox; cbWriteGroup: TCheckBox; cbWriteOther: TCheckBox; cbWriteOwner: TCheckBox; chkArchive: TCheckBox; chkCreationTime: TCheckBox; chkHidden: TCheckBox; chkLastAccessTime: TCheckBox; chkLastWriteTime: TCheckBox; chkReadOnly: TCheckBox; chkRecursive: TCheckBox; chkSystem: TCheckBox; edtOctal: TEdit; gbTimeSamp: TGroupBox; gbWinAttributes: TGroupBox; gbUnixAttributes: TGroupBox; lblAttrBitsStr: TLabel; lblAttrGroupStr: TLabel; lblAttrInfo: TLabel; lblModeInfo: TLabel; lblAttrOtherStr: TLabel; lblAttrOwnerStr: TLabel; lblAttrText: TLabel; lblAttrTextStr: TLabel; lblExec: TLabel; lblOctal: TLabel; lblRead: TLabel; lblWrite: TLabel; DatesPanel: TPanel; ChecksPanel: TPanel; ZVCreationDateTime: TDateTimePicker; ZVLastWriteDateTime: TDateTimePicker; ZVLastAccessDateTime: TDateTimePicker; procedure btnCreationTimeClick(Sender: TObject); procedure btnLastAccessTimeClick(Sender: TObject); procedure btnLastWriteTimeClick(Sender: TObject); procedure SetOtherDateLikeThis(ReferenceZVDateTimePicker:TDateTimePicker); procedure btnOKClick(Sender: TObject); procedure cbChangeModeClick(Sender: TObject); procedure chkChangeAttrClick(Sender: TObject); procedure chkCreationTimeChange(Sender: TObject); procedure chkLastAccessTimeChange(Sender: TObject); procedure chkLastWriteTimeChange(Sender: TObject); procedure edtOctalKeyPress(Sender: TObject; var Key: char); procedure edtOctalKeyUp(Sender: TObject; var {%H-}Key: Word; {%H-}Shift: TShiftState); procedure FormCreate(Sender: TObject); procedure ZVCreationDateTimeChange(Sender: TObject); procedure ZVLastAccessDateTimeChange(Sender: TObject); procedure ZVLastWriteDateTimeChange(Sender: TObject); procedure ZVCreationDateTimeClick(Sender: TObject); procedure ZVLastWriteDateTimeClick(Sender: TObject); procedure ZVLastAccessDateTimeClick(Sender: TObject); private FOperation: TFileSourceSetFilePropertyOperation; FChangeTriggersEnabled: Boolean; procedure ShowMode(Mode: TFileAttrs); procedure ShowAttr(Attr: TFileAttrs); procedure UpdateAllowGrayed(AllowGrayed: Boolean); function FormatUnixAttributesEx(iAttr: TFileAttrs): String; function GetModeFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs; function GetAttrFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs; public constructor Create(aOwner: TComponent; const aOperation: TFileSourceSetFilePropertyOperation); reintroduce; end; function ShowChangeFilePropertiesDialog(const aOperation: TFileSourceSetFilePropertyOperation): Boolean; implementation {$R *.lfm} uses LCLType, DCFileAttributes, DCStrUtils, uDCUtils, uFileProperty, uKeyboard; function ShowChangeFilePropertiesDialog(const aOperation: TFileSourceSetFilePropertyOperation): Boolean; begin with TfrmSetFileProperties.Create(Application, aOperation) do try Result:= (ShowModal = mrOK); finally Free; end; end; { TfrmSetFileProperties } procedure TfrmSetFileProperties.btnOKClick(Sender: TObject); var theNewProperties: TFileProperties; begin with FOperation do begin theNewProperties:= NewProperties; if fpAttributes in SupportedProperties then begin if theNewProperties[fpAttributes] is TNtfsFileAttributesProperty then IncludeAttributes:= GetAttrFromForm(ExcludeAttributes); if theNewProperties[fpAttributes] is TUnixFileAttributesProperty then IncludeAttributes:= GetModeFromForm(ExcludeAttributes); // Nothing changed, clear new property if (IncludeAttributes = 0) and (ExcludeAttributes = 0) then begin theNewProperties[fpAttributes].Free; theNewProperties[fpAttributes]:= nil; end; end; if chkCreationTime.Checked then (theNewProperties[fpCreationTime] as TFileCreationDateTimeProperty).Value:= ZVCreationDateTime.DateTime else begin theNewProperties[fpCreationTime].Free; theNewProperties[fpCreationTime]:= nil; end; if chkLastWriteTime.Checked then (theNewProperties[fpModificationTime] as TFileModificationDateTimeProperty).Value:= ZVLastWriteDateTime.DateTime else begin theNewProperties[fpModificationTime].Free; theNewProperties[fpModificationTime]:= nil; end; if chkLastAccessTime.Checked then (theNewProperties[fpLastAccessTime] as TFileLastAccessDateTimeProperty).Value:= ZVLastAccessDateTime.DateTime else begin theNewProperties[fpLastAccessTime].Free; theNewProperties[fpLastAccessTime]:= nil; end; NewProperties:= theNewProperties; Recursive:= chkRecursive.Checked; end; end; procedure TfrmSetFileProperties.cbChangeModeClick(Sender: TObject); var AMode, ExcludeAttrs: TFileAttrs; CheckBox: TCheckBox absolute Sender; begin if FChangeTriggersEnabled then begin FChangeTriggersEnabled := False; if CheckBox.State = cbGrayed then begin edtOctal.Text:= EmptyStr; lblAttrText.Caption:= EmptyStr; end else begin AMode:= GetModeFromForm(ExcludeAttrs); edtOctal.Text:= DecToOct(AMode); lblAttrText.Caption:= FormatUnixAttributesEx(AMode); end; FChangeTriggersEnabled := True; end; end; procedure TfrmSetFileProperties.chkChangeAttrClick(Sender: TObject); begin // Called after checking any windows-check end; procedure TfrmSetFileProperties.edtOctalKeyPress(Sender: TObject; var Key: char); begin if not ((Key in ['0'..'7']) or (Key = Chr(VK_BACK)) or (Key = Chr(VK_DELETE))) then Key:= #0; end; procedure TfrmSetFileProperties.edtOctalKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); var AMode: TFileAttrs; begin if FChangeTriggersEnabled then begin FChangeTriggersEnabled := False; AMode:= OctToDec(edtOctal.Text); lblAttrText.Caption:= FormatUnixAttributesEx(AMode); ShowMode(AMode); FChangeTriggersEnabled := True; end; end; procedure TfrmSetFileProperties.FormCreate(Sender: TObject); begin end; procedure TfrmSetFileProperties.ShowMode(Mode: TFileAttrs); begin cbReadOwner.Checked:= ((Mode and S_IRUSR) = S_IRUSR); cbWriteOwner.Checked:= ((Mode and S_IWUSR) = S_IWUSR); cbExecOwner.Checked:= ((Mode and S_IXUSR) = S_IXUSR); cbReadGroup.Checked:= ((Mode and S_IRGRP) = S_IRGRP); cbWriteGroup.Checked:= ((Mode and S_IWGRP) = S_IWGRP); cbExecGroup.Checked:= ((Mode and S_IXGRP) = S_IXGRP); cbReadOther.Checked:= ((Mode and S_IROTH) = S_IROTH); cbWriteOther.Checked:= ((Mode and S_IWOTH) = S_IWOTH); cbExecOther.Checked:= ((Mode and S_IXOTH) = S_IXOTH); cbSuid.Checked:= ((Mode and S_ISUID) = S_ISUID); cbSgid.Checked:= ((Mode and S_ISGID) = S_ISGID); cbSticky.Checked:= ((Mode and S_ISVTX) = S_ISVTX); end; procedure TfrmSetFileProperties.ShowAttr(Attr: TFileAttrs); begin chkArchive.Checked:= ((Attr and FILE_ATTRIBUTE_ARCHIVE) <> 0); chkReadOnly.Checked:= ((Attr and FILE_ATTRIBUTE_READONLY) <> 0); chkHidden.Checked:= ((Attr and FILE_ATTRIBUTE_HIDDEN) <> 0); chkSystem.Checked:= ((Attr and FILE_ATTRIBUTE_SYSTEM) <> 0); end; procedure TfrmSetFileProperties.UpdateAllowGrayed(AllowGrayed: Boolean); var Index: Integer; begin lblAttrInfo.Visible:= AllowGrayed; for Index:= 0 to gbWinAttributes.ControlCount - 1 do begin if gbWinAttributes.Controls[Index] is TCheckBox then TCheckBox(gbWinAttributes.Controls[Index]).AllowGrayed:= AllowGrayed; end; lblModeInfo.Visible:= AllowGrayed; for Index:= 0 to gbUnixAttributes.ControlCount - 1 do begin if gbUnixAttributes.Controls[Index] is TCheckBox then TCheckBox(gbUnixAttributes.Controls[Index]).AllowGrayed:= AllowGrayed; end; end; function TfrmSetFileProperties.FormatUnixAttributesEx(iAttr: TFileAttrs): String; begin Result:= Copy(FormatUnixAttributes(iAttr), 2, MaxInt); end; function TfrmSetFileProperties.GetModeFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs; begin Result:= 0; ExcludeAttrs:= 0; case cbReadOwner.State of cbChecked: Result:= (Result or S_IRUSR); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IRUSR; end; case cbWriteOwner.State of cbChecked: Result:= (Result or S_IWUSR); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWUSR; end; case cbExecOwner.State of cbChecked: Result:= (Result or S_IXUSR); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXUSR; end; case cbReadGroup.State of cbChecked: Result:= (Result or S_IRGRP); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IRGRP; end; case cbWriteGroup.State of cbChecked: Result:= (Result or S_IWGRP); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWGRP; end; case cbExecGroup.State of cbChecked: Result:= (Result or S_IXGRP); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXGRP; end; case cbReadOther.State of cbChecked: Result:= (Result or S_IROTH); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IROTH; end; case cbWriteOther.State of cbChecked: Result:= (Result or S_IWOTH); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IWOTH; end; case cbExecOther.State of cbChecked: Result:= (Result or S_IXOTH); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_IXOTH; end; case cbSuid.State of cbChecked: Result:= (Result or S_ISUID); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISUID; end; case cbSgid.State of cbChecked: Result:= (Result or S_ISGID); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISGID; end; case cbSticky.State of cbChecked: Result:= (Result or S_ISVTX); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or S_ISVTX; end; end; function TfrmSetFileProperties.GetAttrFromForm(out ExcludeAttrs: TFileAttrs): TFileAttrs; begin Result:= 0; ExcludeAttrs:= 0; case chkArchive.State of cbChecked: Result:= (Result or FILE_ATTRIBUTE_ARCHIVE); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or FILE_ATTRIBUTE_ARCHIVE; end; case chkReadOnly.State of cbChecked: Result:= (Result or FILE_ATTRIBUTE_READONLY); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or FILE_ATTRIBUTE_READONLY; end; case chkHidden.State of cbChecked: Result:= (Result or FILE_ATTRIBUTE_HIDDEN); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or FILE_ATTRIBUTE_HIDDEN; end; case chkSystem.State of cbChecked: Result:= (Result or FILE_ATTRIBUTE_SYSTEM); cbUnchecked: ExcludeAttrs:= ExcludeAttrs or FILE_ATTRIBUTE_SYSTEM; end; end; constructor TfrmSetFileProperties.Create(aOwner: TComponent; const aOperation: TFileSourceSetFilePropertyOperation); begin inherited Create(aOwner); FOperation:= aOperation; FChangeTriggersEnabled:= True; ZVCreationDateTime.DateTime:= NullDate; ZVLastWriteDateTime.DateTime:= NullDate; ZVLastAccessDateTime.DateTime:= NullDate; // Enable only supported file properties with FOperation do begin if fpAttributes in SupportedProperties then begin UpdateAllowGrayed((TargetFiles.Count > 1) or TargetFiles[0].IsDirectory); if NewProperties[fpAttributes] is TNtfsFileAttributesProperty then begin if TargetFiles.Count = 1 then ShowAttr((NewProperties[fpAttributes] as TNtfsFileAttributesProperty).Value); gbWinAttributes.Show; end; if NewProperties[fpAttributes] is TUnixFileAttributesProperty then begin if TargetFiles.Count = 1 then ShowMode((NewProperties[fpAttributes] as TUnixFileAttributesProperty).Value); gbUnixAttributes.Show; end; end; if (fpCreationTime in SupportedProperties) and Assigned(NewProperties[fpCreationTime]) then begin ZVCreationDateTime.DateTime:= (NewProperties[fpCreationTime] as TFileCreationDateTimeProperty).Value; ZVCreationDateTime.Enabled:= True; chkCreationTime.Enabled:= True; btnCreationTime.Enabled:= True; end; if (fpModificationTime in SupportedProperties) and Assigned(NewProperties[fpModificationTime]) then begin ZVLastWriteDateTime.DateTime:= (NewProperties[fpModificationTime] as TFileModificationDateTimeProperty).Value; ZVLastWriteDateTime.Enabled:= True; chkLastWriteTime.Enabled:= True; btnLastWriteTime.Enabled:= True; end; if (fpLastAccessTime in SupportedProperties) and Assigned(NewProperties[fpLastAccessTime]) then begin ZVLastAccessDateTime.DateTime:= (NewProperties[fpLastAccessTime] as TFileLastAccessDateTimeProperty).Value; ZVLastAccessDateTime.Enabled:= True; chkLastAccessTime.Enabled:= True; btnLastAccessTime.Enabled:= True; end; end; chkCreationTime.Checked:=False; chkLastWriteTime.Checked:=False; chkLastAccessTime.Checked:=False; end; procedure TfrmSetFileProperties.btnCreationTimeClick(Sender: TObject); begin ZVCreationDateTime.DateTime:= Now; if not chkCreationTime.Checked then chkCreationTime.Checked:=TRUE; if ssCtrl in GetKeyShiftStateEx then SetOtherDateLikeThis(ZVCreationDateTime); end; procedure TfrmSetFileProperties.btnLastWriteTimeClick(Sender: TObject); begin ZVLastWriteDateTime.DateTime:= Now; if not chkLastWriteTime.Checked then chkLastWriteTime.Checked:=TRUE; if ssCtrl in GetKeyShiftStateEx then SetOtherDateLikeThis(ZVLastWriteDateTime); end; procedure TfrmSetFileProperties.btnLastAccessTimeClick(Sender: TObject); begin ZVLastAccessDateTime.DateTime:= Now; if not chkLastAccessTime.Checked then chkLastAccessTime.Checked:=TRUE; if ssCtrl in GetKeyShiftStateEx then SetOtherDateLikeThis(ZVLastAccessDateTime); end; procedure TfrmSetFileProperties.SetOtherDateLikeThis(ReferenceZVDateTimePicker:TDateTimePicker); begin if ReferenceZVDateTimePicker<>ZVCreationDateTime then begin ZVCreationDateTime.DateTime:=ReferenceZVDateTimePicker.DateTime; chkCreationTime.Checked:=TRUE; end; if ReferenceZVDateTimePicker<>ZVLastWriteDateTime then begin ZVLastWriteDateTime.DateTime:=ReferenceZVDateTimePicker.DateTime; chkLastWriteTime.Checked:=TRUE; end; if ReferenceZVDateTimePicker<>ZVLastAccessDateTime then begin ZVLastAccessDateTime.DateTime:=ReferenceZVDateTimePicker.DateTime; chkLastAccessTime.Checked:=TRUE; end; ReferenceZVDateTimePicker.SetFocus; end; procedure TfrmSetFileProperties.chkCreationTimeChange(Sender: TObject); begin UpdateColor(ZVCreationDateTime, chkCreationTime.Checked); if (chkCreationTime.Checked and Visible) then ZVCreationDateTime.SetFocus; end; procedure TfrmSetFileProperties.chkLastAccessTimeChange(Sender: TObject); begin UpdateColor(ZVLastAccessDateTime, chkLastAccessTime.Checked); if (chkLastAccessTime.Checked and Visible) then ZVLastAccessDateTime.SetFocus; end; procedure TfrmSetFileProperties.chkLastWriteTimeChange(Sender: TObject); begin UpdateColor(ZVLastWriteDateTime, chkLastWriteTime.Checked); if (chkLastWriteTime.Checked and Visible) then ZVLastWriteDateTime.SetFocus; end; procedure TfrmSetFileProperties.ZVCreationDateTimeChange(Sender: TObject); begin chkCreationTime.Checked:=True; end; procedure TfrmSetFileProperties.ZVLastAccessDateTimeChange(Sender: TObject); begin chkLastAccessTime.Checked:=True; end; procedure TfrmSetFileProperties.ZVLastWriteDateTimeChange(Sender: TObject); begin chkLastWriteTime.Checked:=True; end; procedure TfrmSetFileProperties.ZVCreationDateTimeClick(Sender: TObject); begin if ssCtrl in GetKeyShiftStateEx then SetOtherDateLikeThis(ZVCreationDateTime); end; procedure TfrmSetFileProperties.ZVLastWriteDateTimeClick(Sender: TObject); begin if ssCtrl in GetKeyShiftStateEx then SetOtherDateLikeThis(ZVLastWriteDateTime); end; procedure TfrmSetFileProperties.ZVLastAccessDateTimeClick(Sender: TObject); begin if ssCtrl in GetKeyShiftStateEx then SetOtherDateLikeThis(ZVLastAccessDateTime); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsortanything.lfm��������������������������������������������������������������0000644�0001750�0000144�00000004561�14743153644�017002� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSortAnything: TfrmSortAnything Left = 571 Height = 375 Top = 241 Width = 397 Caption = 'frmSortAnything' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 3 ChildSizing.VerticalSpacing = 3 ClientHeight = 375 ClientWidth = 397 OnCreate = FormCreate SessionProperties = 'Height;Width;Left;Top' LCLVersion = '2.0.6.0' object lbSortAnything: TListBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblSortAnything AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = ButtonPanel Left = 6 Height = 313 Top = 24 Width = 389 Anchors = [akTop, akLeft, akBottom] DragMode = dmAutomatic ItemHeight = 0 MultiSelect = True OnDragDrop = lbSortAnythingDragDrop OnDragOver = lbSortAnythingDragOver TabOrder = 0 end object lblSortAnything: TLabel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner Left = 6 Height = 15 Top = 6 Width = 385 Align = alTop Caption = 'Drag and drop elements to sort them' ParentColor = False end object ButtonPanel: TButtonPanel AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 6 Height = 26 Top = 343 Width = 385 Align = alNone Anchors = [akLeft, akRight, akBottom] OKButton.Name = 'OKButton' OKButton.Caption = '&OK' OKButton.DefaultCaption = False HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.Caption = '&Cancel' CancelButton.DefaultCaption = False TabOrder = 1 ShowButtons = [pbOK, pbCancel] ShowBevel = False object btnSort: TBitBtn AnchorSideLeft.Control = ButtonPanel AnchorSideBottom.Side = asrBottom Left = 0 Height = 25 Top = 0 Width = 47 Anchors = [akTop, akLeft, akBottom] AutoSize = True Caption = '&Sort' OnClick = btnSortClick TabOrder = 4 end end end �����������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsortanything.lrj��������������������������������������������������������������0000644�0001750�0000144�00000001450�14743153644�017005� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":145497015,"name":"tfrmsortanything.caption","sourcebytes":[102,114,109,83,111,114,116,65,110,121,116,104,105,110,103],"value":"frmSortAnything"}, {"hash":195101837,"name":"tfrmsortanything.lblsortanything.caption","sourcebytes":[68,114,97,103,32,97,110,100,32,100,114,111,112,32,101,108,101,109,101,110,116,115,32,116,111,32,115,111,114,116,32,116,104,101,109],"value":"Drag and drop elements to sort them"}, {"hash":11067,"name":"tfrmsortanything.buttonpanel.okbutton.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmsortanything.buttonpanel.cancelbutton.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":2860692,"name":"tfrmsortanything.btnsort.caption","sourcebytes":[38,83,111,114,116],"value":"&Sort"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsortanything.pas��������������������������������������������������������������0000644�0001750�0000144�00000016110�14743153644�017000� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Form allowing user to sort a list of element via drag and drop Copyright (C) 2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fSortAnything; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons, ButtonPanel, //DC uOSForms, uClassesEx; type { TfrmSortAnything } TfrmSortAnything = class(TModalForm) ButtonPanel: TButtonPanel; btnSort: TBitBtn; lblSortAnything: TLabel; lbSortAnything: TListBox; procedure FormCreate(Sender: TObject); procedure btnSortClick(Sender: TObject); procedure lbSortAnythingDragDrop(Sender, {%H-}Source: TObject; X, Y: integer); procedure lbSortAnythingDragOver(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean); private IniPropStorage: TIniPropStorageEx; end; var frmSortAnything: TfrmSortAnything; function HaveUserSortThisList(TheOwner: TCustomForm; const ACaption: string; const slListToSort: TStringList): integer; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. //DC uGlobs; { TfrmSortAnything } { TfrmSortAnything.FormCreate } procedure TfrmSortAnything.FormCreate(Sender: TObject); begin IniPropStorage := InitPropStorage(Self); end; { TfrmSortAnything.btnSortClick } // Simply "lbSortAnything.Sorted" was working fine in Windows. // When tested under Ubuntu 64 with "LAZ 2.0.6/FPC 3.0.4 x86_64-linux-gtk2", it was not working correctly. // For example, if our list was like "D,A,C,B", it was sorted correctly. // But if list was like sorted in reverse, like "D,C,B,A", it did nothing. // If we set "D,C,A,B", or "C,D,B,A" or "D,B,C,A", it was working. // So it seems when it was pre-sorted reversed, it does not sort. // For the moment let's use a TStringList on-the-side for the job. procedure TfrmSortAnything.btnSortClick(Sender: TObject); var slJustForSort: TStringList; iIndex: integer; begin slJustForSort := TStringList.Create; try slJustForSort.Sorted := True; slJustForSort.Duplicates := dupAccept; slJustForSort.CaseSensitive := False; for iIndex := 0 to pred(lbSortAnything.items.Count) do slJustForSort.Add(lbSortAnything.Items.Strings[iIndex]); lbSortAnything.Items.BeginUpdate; try lbSortAnything.Items.Clear; for iIndex := 0 to pred(slJustForSort.Count) do lbSortAnything.Items.Add(slJustForSort.Strings[iIndex]); lbSortAnything.ItemIndex := 0; finally lbSortAnything.Items.EndUpdate; end; finally slJustForSort.Free; end; end; { TfrmSortAnything.lbSortAnythingDragOver } procedure TfrmSortAnything.lbSortAnythingDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean); begin Accept := True; end; { TfrmSortAnything.lbSortAnythingDragDrop } // Key prodecure here that will let user do the drag and drop in the list to move item in the order he wants. // Basically we first remove from the list the elements to be moved... // ... and then we place them back to the correct destination. // The key thing is to determine where will be this destination location based on current selection and target position. procedure TfrmSortAnything.lbSortAnythingDragDrop(Sender, Source: TObject; X, Y: integer); var iFirstSelection, iBeforeTarget, iSeeker, iDestIndex: integer; bMoveSelectionUp: boolean; slBuffer: TStringList; begin iDestIndex := lbSortAnything.GetIndexAtXY(X, Y); if (iDestIndex >= 0) and (iDestIndex < lbSortAnything.Items.Count) then //Don't laught, apparently it's possible to get a iDestIndex=-1 if we move totally on top. begin //1o) Let's determine in which direction the move is taken place with hint about down move. iFirstSelection := -1; iBeforeTarget := 0; iSeeker := 0; while (iSeeker < lbSortAnything.Count) do begin if lbSortAnything.Selected[iSeeker] then begin if iFirstSelection = -1 then iFirstSelection := iSeeker; if iSeeker < iDestIndex then Inc(iBeforeTarget); end; Inc(iSeeker); end; bMoveSelectionUp := (iDestIndex <= iFirstSelection); if (iFirstSelection >= 0) then begin lbSortAnything.Items.BeginUpdate; try slBuffer := TStringList.Create; try //2o) Let's remove from the list the element that will be relocated. for iSeeker := pred(lbSortAnything.Items.Count) downto 0 do begin if lbSortAnything.Selected[iSeeker] then begin slBuffer.Insert(0, lbSortAnything.Items[iSeeker]); lbSortAnything.Items.Delete(iSeeker); end; end; //3o) If we're moving down, we need to readjust destination based on elements seen prior the destination. if not bMoveSelectionUp then iDestIndex := iDestIndex - pred(iBeforeTarget); //4o) Putting back elements in the list after move. It could be "inserted" or "added at the end" based on the result of move. if iDestIndex < lbSortAnything.Items.Count then begin for iSeeker := pred(slBuffer.Count) downto 0 do begin lbSortAnything.Items.Insert(iDestIndex, slBuffer.Strings[iSeeker]); lbSortAnything.Selected[iDestIndex] := True; end; end else begin for iSeeker := 0 to pred(slBuffer.Count) do begin lbSortAnything.Items.Add(slBuffer.Strings[iSeeker]); lbSortAnything.Selected[pred(lbSortAnything.Items.Count)] := True; end; end; finally lbSortAnything.Items.EndUpdate; end; finally slBuffer.Free; end; end; end; end; { HaveUserSortThisList } function HaveUserSortThisList(TheOwner: TCustomForm; const ACaption: string; const slListToSort: TStringList): integer; begin Result := mrCancel; with TfrmSortAnything.Create(TheOwner) do begin try Caption := ACaption; lbSortAnything.Items.Assign(slListToSort); Result := ShowModal; if Result = mrOk then slListToSort.Assign(lbSortAnything.Items); finally Free; end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsplitter.lfm������������������������������������������������������������������0000644�0001750�0000144�00000021355�14743153644�016117� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������inherited frmSplitter: TfrmSplitter Left = 890 Height = 247 Top = 363 Width = 500 HorzScrollBar.Page = 464 HorzScrollBar.Range = 369 VertScrollBar.Page = 301 VertScrollBar.Range = 227 ActiveControl = cmbxSize AutoSize = True BorderIcons = [biSystemMenu] Caption = 'Splitter' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 247 ClientWidth = 500 Constraints.MinWidth = 500 OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnShow = FormShow Position = poOwnerFormCenter SessionProperties = 'cmbxSize.Text;rbtnByte.Checked;rbtnGigaB.Checked;rbtnKiloB.Checked;rbtnMegaB.Checked;teNumberParts.Text;Width;cbRequireACRC32VerificationFile.Checked' inherited pnlContent: TPanel Left = 6 Height = 197 Top = 6 Width = 488 ClientHeight = 197 ClientWidth = 488 object grbxSize: TGroupBox[0] AnchorSideLeft.Control = pnlContent AnchorSideTop.Control = edDirTarget AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom Left = 0 Height = 138 Top = 52 Width = 488 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 10 Caption = 'Size and number of parts' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 118 ClientWidth = 484 Constraints.MinWidth = 300 TabOrder = 1 object cmbxSize: TComboBoxAutoWidth AnchorSideLeft.Control = grbxSize AnchorSideTop.Control = grbxSize AnchorSideRight.Side = asrBottom Left = 6 Height = 23 Top = 6 Width = 272 DropDownCount = 16 ItemHeight = 15 Items.Strings = ( 'Automatic' '1457664B - 3.5" High Density 1.44M' '1213952B - 5.25" High Density 1.2M' '730112B - 3.5" Double Density 720K' '362496B - 5.25" Double Density 360K' '98078KB - ZIP 100MB' '650MB - CD 650MB' '700MB - CD 700MB' '4482MB - DVD+R' ) OnChange = cmbxSizeChange TabOrder = 0 Text = '1457664B - 3.5"' end object rbtnByte: TRadioButton AnchorSideLeft.Control = grbxSize AnchorSideTop.Control = cmbxSize AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 31 Width = 48 BorderSpacing.Top = 2 Caption = '&Bytes' Checked = True OnChange = rbtnByteChange TabOrder = 1 TabStop = True end object rbtnKiloB: TRadioButton AnchorSideLeft.Control = rbtnByte AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbtnByte Left = 56 Height = 19 Top = 31 Width = 68 BorderSpacing.Left = 2 Caption = '&Kilobytes' OnChange = rbtnByteChange TabOrder = 2 end object rbtnMegaB: TRadioButton AnchorSideLeft.Control = rbtnKiloB AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbtnKiloB Left = 126 Height = 19 Top = 31 Width = 78 BorderSpacing.Left = 2 Caption = '&Megabytes' OnChange = rbtnByteChange TabOrder = 3 end object teNumberParts: TEdit AnchorSideLeft.Control = lblNumberParts AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbtnKiloB AnchorSideTop.Side = asrBottom Left = 97 Height = 23 Top = 60 Width = 128 BorderSpacing.Left = 4 BorderSpacing.Top = 10 OnChange = teNumberPartsChange TabOrder = 5 end object lblNumberParts: TLabel AnchorSideLeft.Control = rbtnByte AnchorSideTop.Control = teNumberParts AnchorSideTop.Side = asrCenter Left = 6 Height = 15 Top = 64 Width = 87 Caption = '&Number of parts' FocusControl = teNumberParts ParentColor = False end object rbtnGigaB: TRadioButton AnchorSideLeft.Control = rbtnMegaB AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = rbtnKiloB Left = 206 Height = 19 Top = 31 Width = 72 BorderSpacing.Left = 2 Caption = '&Gigabytes' OnChange = rbtnByteChange TabOrder = 4 end object cbRequireACRC32VerificationFile: TCheckBox AnchorSideLeft.Control = cmbxSize AnchorSideTop.Control = teNumberParts AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 93 Width = 188 BorderSpacing.Top = 10 Caption = 'Require a CRC32 verification file' Checked = True State = cbChecked TabOrder = 6 end end object lbDirTarget: TLabel[1] AnchorSideTop.Control = pnlContent Left = 0 Height = 15 Top = 0 Width = 129 Caption = 'Split the file to directory:' FocusControl = edDirTarget ParentColor = False end object edDirTarget: TDirectoryEdit[2] AnchorSideTop.Control = lbDirTarget AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativeFTChoice Left = 0 Height = 23 Top = 19 Width = 462 ShowHidden = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 MaxLength = 0 TabOrder = 0 end object btnRelativeFTChoice: TSpeedButton[3] AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edDirTarget AnchorSideRight.Control = pnlContent AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edDirTarget AnchorSideBottom.Side = asrBottom Left = 462 Height = 23 Hint = 'Some functions to select appropriate path' Top = 19 Width = 26 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativeFTChoiceClick end end inherited pnlButtons: TPanel Left = 6 Top = 207 Width = 488 ClientWidth = 488 inherited btnCancel: TBitBtn Left = 306 end inherited btnOK: TBitBtn Left = 400 end end inherited pmQueuePopup: TPopupMenu left = 192 end object pmPathHelper: TPopupMenu[3] left = 368 top = 104 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsplitter.lrj������������������������������������������������������������������0000644�0001750�0000144�00000003632�14743153644�016126� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":120635234,"name":"tfrmsplitter.caption","sourcebytes":[83,112,108,105,116,116,101,114],"value":"Splitter"}, {"hash":136166403,"name":"tfrmsplitter.grbxsize.caption","sourcebytes":[83,105,122,101,32,97,110,100,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115],"value":"Size and number of parts"}, {"hash":173739330,"name":"tfrmsplitter.cmbxsize.text","sourcebytes":[49,52,53,55,54,54,52,66,32,45,32,51,46,53,34],"value":"1457664B - 3.5\""}, {"hash":44698307,"name":"tfrmsplitter.rbtnbyte.caption","sourcebytes":[38,66,121,116,101,115],"value":"&Bytes"}, {"hash":56408259,"name":"tfrmsplitter.rbtnkilob.caption","sourcebytes":[38,75,105,108,111,98,121,116,101,115],"value":"&Kilobytes"}, {"hash":226277747,"name":"tfrmsplitter.rbtnmegab.caption","sourcebytes":[38,77,101,103,97,98,121,116,101,115],"value":"&Megabytes"}, {"hash":200834339,"name":"tfrmsplitter.lblnumberparts.caption","sourcebytes":[38,78,117,109,98,101,114,32,111,102,32,112,97,114,116,115],"value":"&Number of parts"}, {"hash":226273075,"name":"tfrmsplitter.rbtngigab.caption","sourcebytes":[38,71,105,103,97,98,121,116,101,115],"value":"&Gigabytes"}, {"hash":118175221,"name":"tfrmsplitter.cbrequireacrc32verificationfile.caption","sourcebytes":[82,101,113,117,105,114,101,32,97,32,67,82,67,51,50,32,118,101,114,105,102,105,99,97,116,105,111,110,32,102,105,108,101],"value":"Require a CRC32 verification file"}, {"hash":101971834,"name":"tfrmsplitter.lbdirtarget.caption","sourcebytes":[83,112,108,105,116,32,116,104,101,32,102,105,108,101,32,116,111,32,100,105,114,101,99,116,111,114,121,58],"value":"Split the file to directory:"}, {"hash":15252584,"name":"tfrmsplitter.btnrelativeftchoice.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"} ]} ������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsplitter.pas������������������������������������������������������������������0000644�0001750�0000144�00000031115�14743153644�016117� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Take a single file and split it in part based on few parameters. Copyright (C) 2007-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fSplitter; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, Buttons, Menus, EditBtn, ExtCtrls, //DC fButtonForm, uFileSource, uFile, KASComboBox; type { TfrmSplitter } TfrmSplitter = class(TfrmButtonForm) btnRelativeFTChoice: TSpeedButton; edDirTarget: TDirectoryEdit; lbDirTarget: TLabel; teNumberParts: TEdit; lblNumberParts: TLabel; grbxSize: TGroupBox; cmbxSize: TComboBoxAutoWidth; rbtnKiloB: TRadioButton; rbtnMegaB: TRadioButton; rbtnGigaB: TRadioButton; rbtnByte: TRadioButton; cbRequireACRC32VerificationFile: TCheckBox; pmPathHelper: TPopupMenu; procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure SetNumberOfPart; procedure SetSizeOfPart; procedure cmbxSizeChange(Sender: TObject); procedure btnRelativeFTChoiceClick(Sender: TObject); procedure rbtnByteChange(Sender: TObject); procedure teNumberPartsChange(Sender: TObject); private FFileName: String; iVolumeSize: Int64; MyModalResult: integer; iVolumeNumber: Integer; function StrConvert(sExpression: String): Int64; public { Public declarations } end; { ShowSplitterFileForm: "TMainCommands.cm_FileSpliter" function from "uMainCommands.pas" is calling this routine.} function ShowSplitterFileForm(TheOwner: TComponent; aFileSource: IFileSource; var aFile: TFile; const TargetPath: String): Boolean; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. LazUTF8, LCLType, LCLProc, //DC uTypes, DCStrUtils, uLng, uFileProcs, uOperationsManager, uFileSourceSplitOperation, uShowMsg, DCOSUtils, uGlobs, uSpecialDir, uDCUtils; { ShowSplitterFileForm: "TMainCommands.cm_FileSpliter" function from "uMainCommands.pas" is calling this routine.} function ShowSplitterFileForm(TheOwner: TComponent; aFileSource: IFileSource; var aFile: TFile; const TargetPath: String): Boolean; var frmSplitter:TfrmSplitter; Operation: TFileSourceSplitOperation = nil; begin frmSplitter:=TfrmSplitter.Create(TheOwner); //Did not use the "with..." here to make absolutely sure of what is referenced in the following. try frmSplitter.FFileName:= aFile.FullPath; frmSplitter.edDirTarget.Text:= TargetPath; frmSplitter.SetNumberOfPart; // Show form Result:= (frmSplitter.ShowModal = mrOK); if Result then begin try Operation:= aFileSource.CreateSplitOperation(aFile, frmSplitter.edDirTarget.Text) as TFileSourceSplitOperation; if Assigned(Operation) then begin Operation.VolumeSize:= frmSplitter.iVolumeSize; Operation.VolumeNumber:= frmSplitter.iVolumeNumber; Operation.RequireACRC32VerificationFile:= frmSplitter.cbRequireACRC32VerificationFile.Checked; Operation.AutomaticSplitMode:=(frmSplitter.cmbxSize.ItemIndex=0); OperationsManager.AddOperation(Operation, frmSplitter.QueueIdentifier, False); end; finally FreeAndNil(aFile); end; end; finally frmSplitter.Free; end; end; { TfrmSplitter.SetNumberOfPart } procedure TfrmSplitter.SetNumberOfPart; begin if cmbxSize.ItemIndex<>0 then begin if StrConvert(cmbxSize.Text)>0 then begin if mbFileSize(FFileName) mod StrConvert(cmbxSize.Text)>0 then teNumberParts.Text:= IntToStr( (mbFileSize(FFileName) div StrConvert(cmbxSize.Text)) +1) else teNumberParts.Text:= IntToStr(mbFileSize(FFileName) div StrConvert(cmbxSize.Text)); end else begin teNumberParts.Text:=rsSimpleWordError; end; end else begin teNumberParts.Text:=rsMSgUndeterminedNumberOfFile; end; end; { TfrmSplitter.SetSizeOfPart } procedure TfrmSplitter.SetSizeOfPart; begin if StrToInt64Def(teNumberParts.Text,0)>0 then begin if mbFileSize(FFileName) mod StrToInt64Def(teNumberParts.Text,0)>0 then cmbxSize.Text := IntToStr(mbFileSize(FFileName) div StrToInt64Def(teNumberParts.Text, 0) + 1) else cmbxSize.Text := IntToStr(mbFileSize(FFileName) div StrToInt64Def(teNumberParts.Text, 0)); rbtnByte.Checked := True; rbtnByte.Enabled := True; rbtnKiloB.Enabled := True; rbtnMegaB.Enabled := True; rbtnGigaB.Enabled := True; end else begin cmbxSize.Text:=rsSimpleWordError; end; end; { TfrmSplitter.StrConvert } //Let's do a basic conversion that maybe is not a full idiot-proof, but versatile and simple enough to fit in a few lines. function TfrmSplitter.StrConvert(sExpression: String): Int64; var iMult: int64 = 1; bUseRadioButtons: boolean = True; procedure CheckIfMemSizeAndSetMultiplicator(sExpressionToCheck:string; iMultiplicatorToSetIfAny:int64); var iSeekPos: integer; begin iSeekPos := pos(UTF8LowerCase(sExpressionToCheck), sExpression); if iSeekPos <> 0 then begin iMult := iMultiplicatorToSetIfAny; sExpression := UTF8LeftStr(sExpression, pred(iSeekPos)); bUseRadioButtons := False; end; end; begin //1.Let's place string in lowercase to avoid any later problem. sExpression := UTF8LowerCase(sExpression); //2.Let's check first if we have the personalized unit in the expression. // We check first since they may include spaces and byte suffix. CheckIfMemSizeAndSetMultiplicator(gSizeDisplayUnits[fsfPersonalizedByte], 1); CheckIfMemSizeAndSetMultiplicator(gSizeDisplayUnits[fsfPersonalizedKilo], 1024); CheckIfMemSizeAndSetMultiplicator(gSizeDisplayUnits[fsfPersonalizedMega], 1024*1024); CheckIfMemSizeAndSetMultiplicator(gSizeDisplayUnits[fsfPersonalizedGiga], 1024*1024*1024); //4.Let's check if there are single letter multiplier or byte suffix. CheckIfMemSizeAndSetMultiplicator(rsLegacyOperationByteSuffixLetter, 1); CheckIfMemSizeAndSetMultiplicator(rsLegacyDisplaySizeSingleLetterKilo, 1024); CheckIfMemSizeAndSetMultiplicator(rsLegacyDisplaySizeSingleLetterMega, 1024*1024); CheckIfMemSizeAndSetMultiplicator(rsLegacyDisplaySizeSingleLetterGiga, 1024*1024*1024); //5. Well... It looks like the pre-defined disk size strings has not been translated in all languages so let's simplify with english values... //NO NEED TO TRANSLATE THESE ONES! Either translate all disk size strings and/or accept that english abbreviation always work here. CheckIfMemSizeAndSetMultiplicator('B', 1); CheckIfMemSizeAndSetMultiplicator('K', 1024); CheckIfMemSizeAndSetMultiplicator('M', 1024*1024); CheckIfMemSizeAndSetMultiplicator('G', 1024*1024*1024); //5.We remove the spaces since they are irrevelant. sExpression := UTF8StringReplace(sExpression, ' ', '', [rfReplaceAll]); //6.If we return a number here, let's disable the unit selector below. if cmbxSize.Focused then begin rbtnByte.Enabled := bUseRadioButtons; rbtnKiloB.Enabled := bUseRadioButtons; rbtnMegaB.Enabled := bUseRadioButtons; rbtnGigaB.Enabled := bUseRadioButtons; end; //7.If we return a number here, let's disable the unit selector below. if bUseRadioButtons then begin if rbtnKiloB.Checked then iMult:=1024; if rbtnMegaB.Checked then iMult:=1024*1024; if rbtnGigaB.Checked then iMult:=1024*1024*1024; end; //7.Since we're now supposed to have just numbers in our string, we should be ready to do our conversion. Result := StrToInt64Def(sExpression, 0) * iMult; end; { TfrmSplitter.FormCreate } procedure TfrmSplitter.FormCreate(Sender: TObject); begin InitPropStorage(Self); // Initialize property storage MyModalResult:=mrCancel; gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper,mp_PATHHELPER,nil); ParseLineToList(rsSplitPreDefinedSizes, cmbxSize.Items); end; procedure TfrmSplitter.FormShow(Sender: TObject); begin if (rbtnGigaB.Left + rbtnGigaB.Width > cmbxSize.Left + cmbxSize.Width) then begin cmbxSize.AnchorParallel(akRight, 0, rbtnGigaB); end; end; { TfrmSplitter.rbtnByteChange } procedure TfrmSplitter.rbtnByteChange(Sender: TObject); const sDigits:string='0123456789'; var iFirstNonDigit: integer = 0; iIndex: integer; sExpression, sSanitize: string; begin if rbtnByte.focused OR rbtnKiloB.focused OR rbtnMegaB.focused OR rbtnGigaB.focused then begin if TRadioButton(Sender).Checked then begin sExpression := UTF8StringReplace(cmbxSize.Text, ' ', '', [rfIgnoreCase , rfReplaceAll]); sSanitize := ''; iFirstNonDigit := 0; for iIndex := 1 to UTF8Length(sExpression) do begin if (UTF8Pos(UTF8Copy(sExpression, iIndex, 1), sDigits) = 0) then begin if iFirstNonDigit = 0 then iFirstNonDigit := iIndex; end else begin if iIndex=UTF8Length(sExpression) then iFirstNonDigit := succ(iIndex); end; end; if iFirstNonDigit <> 0 then sSanitize:=UTF8LeftStr(sExpression, pred(iFirstNonDigit)); cmbxSize.Text := sSanitize; SetNumberOfPart; end; end; end; { TfrmSplitter.btnRelativeFTChoiceClick } procedure TfrmSplitter.btnRelativeFTChoiceClick(Sender: TObject); begin edDirTarget.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(edDirTarget,pfPATH); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; { TfrmSplitter.cmbxSizeChange } procedure TfrmSplitter.cmbxSizeChange(Sender: TObject); begin if cmbxSize.Focused then //Do the function ONLY-IF it's the result of someone typing in the field begin if cmbxSize.ItemIndex<>0 then begin SetNumberOfPart; end else begin teNumberParts.Text:=''; if teNumberParts.CanFocus then teNumberParts.SetFocus; SetSizeOfPart; end; end; end; { TfrmSplitter.teNumberPartsChange } procedure TfrmSplitter.teNumberPartsChange(Sender: TObject); begin if teNumberParts.Focused then SetSizeOfPart; //Do the function ONLY-IF it's the result of someone typing in the field end; { TfrmSplitter.FormCloseQuery } procedure TfrmSplitter.FormCloseQuery(Sender: TObject; var CanClose: boolean); var isTooManyFiles: boolean; begin if (ModalResult <> mrCancel) then begin if cmbxSize.ItemIndex <> 0 then iVolumeSize:= StrConvert(cmbxSize.Text) else begin iVolumeSize:= 0; end; if (iVolumeSize <= 0) AND (cmbxSize.ItemIndex<>0) then begin ShowMessageBox(rsSplitErrFileSize, rsSimpleWordError+'!', MB_OK or MB_ICONERROR); //Incorrect file size format! (Used "ShowMessageBox" instead of "MsgError" 'cause with "MsgError", user can still click on the frmSplitter form and type in it). end else begin if not mbForceDirectory(IncludeTrailingPathDelimiter(mbExpandFileName(edDirTarget.Text))) then begin ShowMessageBox(rsSplitErrDirectory, rsSimpleWordError+'!', MB_OK or MB_ICONERROR); //Unable to create target directory! end else begin if teNumberParts.Text <> rsMSgUndeterminedNumberOfFile then iVolumeNumber := StrToInt(teNumberParts.Text) else iVolumeNumber := 0; if (iVolumeNumber < 1) AND (teNumberParts.Text <> rsMSgUndeterminedNumberOfFile) then begin ShowMessageBox(rsSplitErrSplitFile, rsSimpleWordError+'!', MB_OK or MB_ICONERROR); //Unable to split the file! end else begin isTooManyFiles:=(iVolumeNumber > 100); if isTooManyFiles then isTooManyFiles:=(MessageDlg(Caption, rsSplitMsgManyParts, mtWarning, mbYesNo, 0) <> mrYes); if not isTooManyFiles then begin MyModalResult:= mrOk; end; //if isTooManyFiles then end; //if (iVolumeNumber = 0) then end; //if not mbForceDirectory(edDirTarget.Text) then end; //if iVolumeSize <= 0 then CanClose:= (MyModalResult = mrOK); end; ModalResult := MyModalResult; // Don't save properties when cancel operation if ModalResult = mrCancel then SessionProperties:= EmptyStr; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fstartingsplash.lfm������������������������������������������������������������0000644�0001750�0000144�00000251326�14743153644�017322� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmStartingSplash: TfrmStartingSplash Left = 120 Height = 330 Top = 207 Width = 206 Anchors = [] AutoSize = True BorderIcons = [] BorderStyle = bsNone Caption = 'Double Commander' ClientHeight = 330 ClientWidth = 206 DefaultMonitor = dmPrimary FormStyle = fsSplash Icon.Data = { 267D000000000100040010100000010020006804000046000000202000000100 2000A8100000AE0400003030000001002000A825000056150000404000000100 200028420000FE3A000028000000100000002000000001002000000000004004 00000000000000000000000000000000000000000000BCA3A51A8182BB517E82 C1586E72B94F6D70B64F6C6DB34F6B6BB14F6A68AE4F6966AB4F6764A84F736D AB57837CB1677A72AB607B6D9E3EFEEDD506B7A4B60D4F6BDAE62653E6FE234B DEFE2046D7FE1D3FD1FE1A39CAFE1834C4FE142EBEFE1228B8FE0F23B2FE0D1C ABFE0A17A4FF06109EFE050C97FE594F997BCECFD296BEC6DBFEB1BAD9FE889A D9FF2F52D7FF193ED2FF1939CCFF1634C6FF132DBFFF1127B9FF0E22B3FF0314 AAFF444EB3FF9295C4FFB1B2CCFFC2C2CFF7D1D0D0ABD7D7D5FFD6D6D5FFD6D6 D5FFD9D9D4FF4963D0FF1738CCFF1634C6FF132DBFFF1127B9FF0E22B3FF848B C5FFDBDBD7FFD6D6D5FFD7D7D6FED7D7D6FFAFB5D15A6A87E1FB8B9DD6FFD9D7 D2FFD3D3D3FFD1D1D2FF3F58CBFF1634C6FF132DBFFF0B22B8FF9299C8FFD7D6 D4FFD3D3D3FFC1C2CEFF5D62B1FF6868B0D69AA7E3344B72EDF92C58E9FF375C DDFFBFC2D0FFD0D0D0FFAAB0CAFF0D2DC6FF132DBFFF3245BDFFCECECFFFD3D3 D1FF9A9DC2FF040F9EFF000697FF2B2DA1C3A3ADE1366D8CF0F9577AECFF3E62 E3FF6D83D6FFCECECCFFD7D6CCFF2741C3FF122CBFFF616FC0FFCDCDCCFFC4C4 CAFF0514A5FF0712A0FF070E9AFF3334A3C4A3ADE1366D8CF0F96988EEFF6482 E9FF6F86DEFFCDCCCAFFD1D0CAFF5C6DC7FF213AC4FF8991C4FFCBCBCAFF9EA2 C3FF1C29ADFF222CAAFF2B32A9FF5858B3C4A3ADE1366D8CF0F96888EEFF6684 EAFF7E92E0FFD8D7D5FFDCDBD6FF7686D1FF596CD3FF9DA4CEFFD6D6D6FFB8BB D0FF545EC1FF555DBDFF5359BAFF6B6CBCC4A3ADE1366D8CF0F96888EEFF6583 EAFFAFBAE1FFE5E5E5FFE6E5E1FF596FD7FF5C6FD3FF8690D2FFE5E5E5FFE9E8 E5FF5F69C0FF525ABDFF5157B9FF6B6BBBC498A4E72F6687F1F96887EBFFA7B4 E3FFE6E6E5FFE6E6E6FFA5AFDCFF5D72D8FF5D6FD3FF6371CEFFE0E0E3FFE6E6 E6FFDBDCE1FF7A7FC4FF484EB5FF605FB4C2D9D9DC9CD8DAE1FFEAE8E3FFE7E7 E6FFE7E7E6FFD5D7E2FF677BDBFF5F74D8FF5D6FD3FF5A69CFFF7681CBFFE6E6 E5FFE6E6E6FFEBEBE8FFE6E6E3FFD7D8DEF9E0E0E0ABE8E8E8FFE9E9E8FFEEED E9FFB6BFE0FF677FE0FF6076DCFF5F74D8FF5D6FD3FF5B6BCFFF5866CBFF6F79 C9FFDBDCE0FFEEEDEAFFE9E9E8FEE8E8E8FFCECCD36EAFBDE9FD9BADE7FE768F E6FF5F7AE5FF627BE0FF6176DCFF5F74D8FF5C6FD3FF5B6BCFFF5866CBFF5662 C6FF4F59C0FF777DC4FF9699CBFFB5B2CCDEFFF0D5098283BBCA718EEFFC6683 E8FB6A82E4FB687FE0FB667ADCFB6478D7FB6373D3FB6170CEFB5F6CCBFB5C66 C5FB5660C0FB555CBCFB6A6CBDF9998DB15200000000FFFFFF0399839924917C 962A907B962A8F7B942A8F7A942A8F79942A8E79942A8E78932A8E78922A8F77 922A8F77922A8E76912A9D83921F000000008000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF8001FFFF2800000020000000400000000100 2000000000008010000000000000000000000000000000000000000000000000 000000000000FFFFFF03FFFFFF07FFFFFF0BFFFFFF14FFFFFF09FFFFFF07FFFF FF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFF FF07FFFFFF07FFFFFF07FFFFFF07FFFFFF07FFFFFF0CFFFFFF1AFFFFFF1CFFFF FF1CFFFFFF17FFFFFF0AFFFFFF04000000000000000000000000000000000000 0000FFFFFF10E1D6D55362456CBA584273D6594374DD584175D3563F73D2563E 72D2553E71D2543D70D2543C70D2543B6ED2533B6ED2533A6DD2533A6DD25338 6BD252396BD252386AD252376AD2513669D253386AD5513262E6513262E85132 61E8503161E4533563CA89729187FFFFFF2BFCFCFC040000000000000000FFFF FF08948BB17F5263C1FF3E66E8FF315DEBFF2C58E7FF2B54E4FF2A51E1FF284E DDFF264BDAFF2448D7FF2345D4FF2242D0FF2140CDFF1F3DCAFF1E39C7FF1C36 C4FF1B33C1FF1A31BEFF192EBBFF172BB7FF1527B3FF1425B1FF1322AEFF121F ABFF101CA8FF141EA5FF191A92FF45357FE4FEF6EE3AFFFFFF0200000000FFFF FF22546BD1F12C5AEBFE2754E8FF224FE4FF224BE1FF2149DEFF1E45DAFF1D43 D6FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0C1FB0FF0A1CACFF0A19A9FF0816A5FF0613 A2FF040F9FFF010A9BFF020A98FF0B139DFF453075C7FFFFFF0ECACACA4EDBDB DBE7C5C9D8FFC0C5D7FFB7BED6FF8598D7FF395DDCFF1842DFFF1E45DAFF1D43 D6FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0C1FB0FF0A1CACFF0A19A9FF0615A5FF000C A0FF434BACFF9395C1FFB7B8CAFFBDBECFFFC7C6D1FDD6D6D6E3C8C8C858D7D7 D7FFD7D7D7FFD7D7D7FFD8D8D7FFDCDBD8FFE1DED5FFB3BAD4FF5873D6FF1940 D6FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0C1FB0FF081AABFF0F1DA8FF7077BCFFCECE D4FFE2E2DBFFDADAD8FFD8D8D7FFD7D7D7FFD7D7D7FFD4D4D4FFC8C8C858D5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD7D6D6FF9FA9 D1FF1B40D3FF1A3DD0FF183ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0D22B3FF0B1FB0FF2D3BB0FFD7D8D9FFD6D6D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD3D3D3FFC7C7C758D3D3 D3FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD8D7 D4FFBBBFD2FF1F40CFFF193ACDFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0F25B6FF0B20B3FF5662B9FFD4D4D5FFD4D4D4FFD4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD2D2D2FFC8C8C84BD1CF D0E9BBC3D9FFBDC2D4FFCCCDD1FFD8D7D3FFD4D3D3FFD3D3D3FFD3D3D3FFD3D3 D3FFD5D5D4FFB1B6CCFF193ACBFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0D24B6FF2E3FB6FFD3D4D5FFD2D3D3FFD3D3D3FFD3D3D3FFD3D3 D3FFD5D5D4FFD8D8D5FFC2C2CEFFB4B5CAFFB6B7CAFDD3D3D2DBFFFFFF05BAA4 AD75426DF1FF3461EBFF2E5AE8FF5874D4FFCECFD1FFD2D2D2FFD2D2D2FFD2D2 D2FFD2D2D2FFD3D2D2FF8491CAFF1736C9FF1634C6FF1431C3FF132EC0FF112B BDFF1128BAFF0A21B4FFCECFD2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD3D3 D2FFAAACC6FF1D259FFF070F9AFF030996FF181B9CF4FAEEE322FFFFFF04B9A2 AD734B75F2FF3B66ECFF315CE8FF2753E6FF2750DEFF96A3D1FFD1D1D0FFD0D0 D0FFD0D0D0FFD0D0D0FFCDCDCDFF2240C7FF1534C6FF1431C3FF132EC0FF112B BDFF1027BAFF737EC3FFD3D3D1FFD0D0D0FFD0D0D0FFD0D0D0FFD7D6D1FF5961 B3FF000B9DFF020C9CFF030B99FF000695FF161A9BF4FFF4E71FFFFFFF04B7A1 AD735F84F3FF4971EDFF3C65E9FF325BE5FF2B54E2FF2049DEFFB5BACEFFD0CF CEFFCECECEFFCECECEFFD2D2CFFF848FC1FF1130C7FF1431C3FF132EC0FF112B BDFF0F26B9FFB6B9CBFFCECECEFFCECECEFFCECECEFFD0CFCFFF6067B4FF0411 A2FF05109FFF030D9CFF030B99FF010795FF171A9BF4FFF4E71FFFFFFF04B7A0 AC736D8FF5FF6384EFFF5074EBFF4268E7FF365DE3FF2E55E0FF3256DAFFC8C9 CCFFCDCDCDFFCDCDCDFFCDCDCDFFC4C4C6FF1C39C5FF1532C3FF142FC0FF112A BDFF273BB8FFD4D3CDFFCDCDCDFFCDCDCDFFCECDCDFFBABBC6FF0412A4FF0714 A2FF06119FFF050E9CFF040C99FF030896FF191D9CF4FFF3E71FFFFFFF04B7A0 AC736D90F5FF6A8AF0FF6887EEFF5D7EEAFF4E71E6FF4164E2FF375ADDFFA7B0 D0FFCCCCCCFFCDCDCDFFCDCDCDFFCCCCCDFF364EC3FF1733C3FF152FC0FF1029 BDFF6A75BCFFD2D1CEFFCDCDCDFFCDCDCDFFD3D3CEFF444EAFFF0715A6FF0915 A4FF0914A0FF09129EFF0A119BFF0A1099FF2226A0F4FDF1E61FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF617EE7FF5372E3FF909D D3FFCCCCCAFFCACACAFFCACACAFFCACACAFF4B60C5FF213BC5FF1D37C2FF152E BFFF979DC1FFCDCDCBFFCACACAFFCACACAFFCCCCCAFF1626ACFF1220A9FF131F A7FF141EA5FF161FA2FF1920A2FF1D23A1FF3639A8F4F8ECE41FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF6580E5FF94A1 D6FFCCCCCAFFCACACAFFCACACAFFCACACAFF6778CBFF3850CCFF324AC8FF293F C4FFB0B3C5FFCCCBCBFFCACACAFFCACACAFFC1C2C9FF2A38B4FF2935B1FF2C36 B0FF3039AFFF353DAFFF3D44B0FF4448B1FF595CB7F4EFE3E01FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF647FE5FF9EA9 D6FFD3D3D2FFD2D2D2FFD2D2D2FFD1D2D2FF7988D1FF5C70D5FF586BD2FF5163 D0FFADB0C5FFD4D3D2FFD2D2D2FFD2D2D2FFCBCCCFFF515CC1FF505AC0FF525B BEFF535BBDFF535ABBFF5257B9FF5054B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF6580E5FFBAC0 D9FFD9D9D9FFD9D9D9FFD9D9D9FFD9D9D9FF7182D3FF5D71D6FF5D6FD3FF596B D2FF989EC6FFDDDCDAFFD9D9D9FFD9D9D9FFDDDCD9FF656FC2FF545EC2FF535C BFFF535BBDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF6682E8FF6781E3FFDBDC DEFFE2E2E2FFE2E2E2FFE2E2E2FFDDDDDDFF6175D5FF5D71D6FF5D6FD3FF5A6C D1FF737EC8FFE5E5E1FFE2E2E2FFE2E2E2FFE4E4E3FFB4B6CEFF4E59C0FF535C BFFF535BBDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6684EAFF637FE8FFB5BDD6FFE8E8 E7FFE6E6E6FFE6E6E6FFE8E8E7FFB5BAD4FF5B71D8FF5D71D6FF5D6FD3FF5B6D D1FF5A69CFFFD7D8DBFFE6E6E6FFE6E6E6FFE5E5E5FFEAE9E8FF737BC2FF535C BFFF535BBDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EEE1DF1FFFFFFF04B7A0 AC736D90F5FF6989F0FF6988EFFF6786ECFF6180EBFFA4B0DCFFE6E6E5FFE5E5 E6FFE6E6E6FFE6E6E6FFE7E6E3FF687BD7FF5E74D8FF5D71D6FF5D6FD3FF5B6D D1FF5B6ACFFFA6ACD1FFE7E7E6FFE5E5E5FFE6E6E6FFE5E5E5FFDDDEE1FF5E66 BAFF5159BDFF5258BAFF5257B9FF4F54B6FF5E61BAF4EFE3E11FFFFFFF01B29F BC6E6A8DF6FF6586F1FF6584EDFF8097E4FFBDC4DDFFEBEAE5FFE5E5E5FFE6E6 E6FFE5E5E5FFE7E7E6FFB3BADAFF5F74DBFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF6270C9FFE2E1DFFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E5 E4FF9296C9FF5D62B8FF4B51B6FF4A4FB4FF595BB8F4D3B9BA1BCDCDCC3CD2CF D6CFB5C0E0FFC2C8DCFFE0E0DFFFE7E7E6FFE6E6E5FFE6E6E6FFE5E5E5FFE5E5 E5FFE6E6E6FFDFDFDFFF6277D8FF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5968CDFF7681C9FFE5E5E4FFE5E6E6FFE5E5E5FFE5E5E5FFE5E5 E5FFE6E6E6FFEAE9E8FFD2D3D7FFB6B7CFFFB0B0CEFBD5D4D4B3D2D2D259E6E6 E6FFE8E8E6FEE8E7E7FFE7E7E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 E7FFE1E1E3FF7085DAFF6076DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF9299CBFFEEEEE8FFE6E6E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE7E7E7FFE8E8E7FFE8E8E7FFE2E2E2FFD2D2D258E6E6 E6FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE9E9E7FFD3D6 E0FF6D83D8FF6179DEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5360C9FF8B92C9FFE1E1E3FFE9E9E8FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE2E2E2FFD2D2D258E7E7 E7FFE8E8E8FFE8E8E8FFE7E7E7FFE7E7E7FFE8E8E8FFEAEAE6FF9BA8D8FF647E E2FF627CE0FF627ADEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5865C9FF5663C5FF5E68C4FFC0C2D3FFECEC EBFFE8E8E8FFE7E7E7FFE8E8E8FFE8E8E8FFE8E8E8FFE3E3E3FFCECECE57E1E1 E1FFE1E1E3FFDEDFE0FFCDD2E1FFB5BFE2FF93A6E4FF6C86E3FF627DE6FF647E E3FF627CE0FF627ADEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5865C9FF5663C5FF5660C4FF515BC0FF6B72 C1FF9498CAFFB8BAD2FFD1D1DAFFDEDFDFFEE1E1E2FFDBDBDBFC00000000EFE3 E3386779D2FF6385F2FE6485F0FF6585EDFF6684EAFF6682E8FF647FE5FF647D E3FF627CE0FF627ADEFF6077DCFF5F74DAFF5F74D8FF5D71D6FF5D6FD3FF5B6D D1FF5C6BCFFF5A69CDFF5867CBFF5865C9FF5663C5FF5761C4FF555FC1FF535C BFFF525ABDFF4F55BAFF4B51B7FF494FB7FF55468DEAFFFFFF0900000000FFFF FF1D837DAED37395F7FF6786EFFE6786ECFF6684EAFF6581E8FF647FE5FF637D E3FF627CE0FF6179DEFF6077DCFF5F74DAFF5E74D8FF5D71D6FF5C6ED3FF5B6D D1FF5B6ACEFF5969CDFF5867CBFF5764C9FF5662C5FF5761C4FF555FC1FF535C BFFF535BBDFF5157BAFF4E53B7FE6562ADFFA18DA574FFFFFF0400000000F6F5 F604CFC0C3428D85AFC27C84CAF46874C6FF6874C5FF6A74C4FF6C75C2FF6C74 C2FF6C73BFFF6B71BEFF6A6FBCFF696EBBFF696DB9FF686BB8FF676AB6FF6669 B5FF6667B3FF6566B2FF6464B1FF6462AEFF6261ACFF5C5AA9FF5B58A7FF5A57 A6FF5B56A4FF655EA5FF7F76ABEF95819C93FFFFFF1300000000000000000000 0000FBFAFB02FFFFFF11FFFFFF2AFFFFF937D4C5C340D4C5C340D4C5C340D4C5 C340D4C5C340D5C6C340D5C6C440D5C6C440D5C6C440D5C6C440D5C6C440D5C6 C440D5C6C440D5C6C440D5C6C440D5C6C440D5C6C540D5C6C440D5C7C540D5C7 C540D5C6C440EBE2DF3BFFFFFF2CFFFFFF0E0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E0000007C000 0001800000008000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000800000008000000080000001C0000003FFFFFFFF280000003000 0000600000000100200000000000802500000000000000000000000000000000 00000000000000000000000000000000000000000000FFFFFF01FFFFFF03FFFF FF04FFFFFF07FFFFFF0BFFFFFF08FFFFFF04FFFFFF03FFFFFF03FFFFFF03FFFF FF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFF FF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFFFF03FFFF FF03FFFFFF03FFFFFF05FFFFFF0BFFFFFF0FFFFFFF10FFFFFF10FFFFFF10FFFF FF0EFFFFFF09FFFFFF04FFFFFF02000000000000000000000000000000000000 0000000000000000000000000000FFFFFF01FFFFFF0AF0EBEC1FD4CAD332CCC3 D03BD4CDD947D9D3DD53D4CDD948CCC4D23BCAC1D039CAC1D039CAC1D039C9C1 D039C9C1D039C9C1CF39C9C0D039C9C1CF39C9C0CF39C9C0CF39C9C0CF39C9C0 CF39C9C0CF39C9C0CE39C9C0CE39C8C0CE39C9BFCE39C9BFCE39C9BFCE39C9BF CE39C9C0CE3ACEC6D340D8D1DB53DBD4DD61DCD5DE64DCD5DE64DCD5DE63DAD2 DC5DD3CBD64BCDC4D039D7CFD829FBFAF916FFFFFF0700000000000000000000 00000000000000000000FFFFFF02FFFFFE12D8CFD63F9B8CA88B675687CC5243 81E7514688EF504586F2504588EE4F4487EB4E4286EB4E4285EB4D4185EB4C40 84EB4C3F83EB4B3F82EB4B3E82EB4B3D80EB4B3C7FEB4A3C7FEB4A3B7EEB4A3A 7DEB49397CEB49397CEB49387AEB48387AEB48377AEB483679EB483578EB4835 77EB473476EB473476EC473274F2442C6CFA442C6CFA442C6BFA432B6AFB432A 6AFA442D6CF04B3370DE675284B6A394AE76E1D9DE37FFFFFF0EFFFFFF020000 00000000000000000000FFFFFF0BD1CAD545776FA3BB5157ABFF4F6EDEFF436C F0FF3963EEFF3661EBFF345EE9FF345BE7FF3359E4FF3158E2FF3056E0FF2F54 DEFF2E51DBFF2D4FDAFF2C4ED8FF2C4BD6FF2A49D3FF2A48D1FF2947D0FF2844 CDFF2742CBFF2640CAFF253FC8FF253CC5FF233BC3FF2239C2FF2237BFFF2135 BDFF2033BBFF1F31B9FF1E2FB7FF1D2EB5FF1C2CB4FF1B2AB1FF1B28AFFF1926 ADFF1C27ADFF232BA8FF292894FF362577FF715C8AADDAD1D83EFFFFFF0C0000 000000000000FFFFFF02DEDAE7237B7BB79D4D64CCFF3B6AF5FF2655EAFE2552 E6FF224FE3FF204CE1FF2049DFFF1F47DDFF1E45DBFF1C42D8FF1B41D5FF193F D3FF183DD1FF173BCFFF1638CDFF1636CBFF1534C9FF1433C6FF1331C4FF122F C2FF112DC0FF102ABEFF0F28BCFF0F26B9FF0E25B7FF0D23B5FF0B21B3FF0A1F B1FF091CAFFF081AACFF0818A9FF0716A7FF0615A5FF0513A3FF0411A1FF030E 9FFF010C9CFF00099AFF000699FE09129FFF271F83FF7664939CEDE9F024FFFF FF0100000000BAB9B309B2B6D9474D5FC2F14370F4FF2957EAFE2452E9FF1D4C E6FF1D4BE4FF1F4AE2FF214ADFFF2149DDFF1F46DBFF1E44D8FF1D43D6FF1C41 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0A1AAAFF0918A8FF0817A6FF0715A4FF0612A2FF010D 9FFF00079CFF000298FF000597FF000695FE09119CFF2C1F7AEFC4C1CF4DB0B0 AF0CB0B0B016D4D4D4A5D1D2DABD9DA8D5FF98A9E0FF92A4DCFF899CDCFF758D DCFF5876DBFF355ADDFF1B46DFFF1A44DEFF1E45DBFF1E44D8FF1D43D6FF1C41 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0A1AAAFF0918A8FF0716A6FF000EA2FF000C9FFF1E28 A3FF464DAEFF6469B5FF787CB9FF8285BCFF8184BBFE8E8BB7FFD3D3D6C4D1D1 D1A4B1B1B125D5D5D5FFD9D9D9FFDDDCD8FEDEDCD7FEDDDBD5FFDCDBD5FFD4D5 D6FFC4C8D7FFAEB7D7FF8A9BD7FF4C6AD6FF1B43DAFF1A41D8FF1C43D6FF1C41 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0A1AAAFF0414A7FF0615A4FF3F49ADFF8489C1FFABAE CBFFC2C3D1FFD4D5D5FFDDDDD8FFDFDFD9FFE0E0DBFEE0E1DCFEDADADAFFD4D4 D4FFB0B0B023D4D4D4FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD8D7 D7FFD9D9D7FFDBDAD7FFD5D5D5FFC3C8D7FF97A4D4FF3858D3FF173ED6FF1B40 D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF0A1CACFF0515A9FF2C38ACFF969AC6FFC5C6D3FFD7D7D6FFDDDC D9FFDAD9D8FFD8D8D7FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD7D7D7FFD4D4 D4FFB0B0B023D3D3D3FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6 D6FFD6D6D6FFD6D6D6FFD6D6D6FFD8D8D6FFD4D5D5FFC3C6D5FF687DCFFF183D D4FF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0D21 B2FF0B1EAFFF091AABFF636BB9FFC6C8D4FFD5D5D5FFD9D9D7FFD6D6D6FFD6D6 D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD6D6D6FFD3D3 D3FFB0B0B023D2D2D2FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD6D5D5FFD2D3D6FF8895 CCFF1A3ED1FF193CCFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0C20 B2FF0C1FAFFF888EC1FFD6D6D8FFD6D6D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD2D2 D2FFB0B0B023D2D2D2FFD4D4D4FFD3D3D3FFD3D3D3FFD4D4D4FFD4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D3FFD6D6 D6FF99A3CBFF1438CFFF183ACDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0E23B4FF0A1F B0FF989DC4FFD8D8D8FFD4D4D3FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD3D3D3FFD3D3D3FFD3D3D3FFD4D4D4FFD1D1 D1FFB0B0B023D4D4D4FFD5D5D5FDD3D4D6FFD3D3D5FFD1D2D3FFD2D3D3FFD3D3 D3FFD4D4D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3 D3FFD5D5D5FF818EC7FF1436CDFF1838CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0F25B6FF0A20B3FF828A C0FFDAD9D8FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FFD4D4 D3FFD4D4D4FFD3D3D3FFD2D2D3FFD3D3D4FFD2D3D4FFD2D2D4FFD5D5D5FCD4D4 D4FBB5B5B50CC5C4C469AAA6BDB46989E5FF6583E0FF728AD8FF909FD0FFB6BC CFFFCBCCD2FFD1D2D2FFD3D3D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2 D2FFD2D2D2FFD1D1D3FF5B6EC6FF1434CBFF1736C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF1027B8FF0B21B5FF5864BAFFD8D8 D7FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD3D3D3FFD2D2 D2FFCDCED3FFB4B5CBFF8084BAFF585CACFF3F43A3FF4144A3FFB1ACBF9DC1C1 C15B00000000FDF6F71A9B93BD914470F4FF3361EEFF2C5BECFF2453EBFF2651 E3FF5673D4FFA2ADD1FFCBCDD2FFD2D2D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1 D1FFD1D1D1FFD2D2D1FFBFC2CDFF2A46C7FF1434C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF0D25B8FF2135B6FFC6C8D2FFD1D1 D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1D1FFD2D2D2FFCDCED1FF9FA2 C5FF3F46A8FF000899FF000197FF000395FF000193FF060B97FFA59AC26CFFFF FF0AFFFFFF01F0EAEC209E96BD934F78F3FF3E69EEFF3763EBFF315CE9FF2C57 E7FF214EE6FF234EDEFF7389D5FFC1C4D0FFD1D1D0FFD0D0D0FFD0D0D0FFD0D0 D0FFD0D0D0FFD1D0D0FFCECED0FF8792C5FF1232C9FF1635C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF1128BAFF0921B7FF8B93C5FFD0D0D1FFD0D0 D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD2D2D1FFC4C5CDFF6A71B6FF0814 9EFF00069CFF020C9BFF030B99FF020997FF000694FF0A0F98FFA79CC270F9F8 F910FFFFFF01F0EAEC20A098BD935A81F3FF4770EEFF3F68ECFF3861E9FF315C E7FF2D57E4FF2751E3FF1C47DFFF667ED3FFC3C6CFFFD0D0CFFFCFCFCFFFCFCF CFFFCFCFCFFFCFCFCFFFD1D0CFFFBBBECBFF364FC4FF1232C7FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF0D25BAFF2F41B8FFC5C6CFFFD0D0CFFFCFCF CFFFCFCFCFFFCFCFCFFFCFCFCFFFD1D1CFFFC4C5CCFF5E65B4FF000D9FFF020E 9FFF040F9DFF030C9BFF020B99FF020997FF000694FF0B1098FFA79CC270F9F8 F910FFFFFF01EFEAEC20A39ABD93698CF5FF557BEFFF4A71EDFF4169EAFF3962 E8FF335BE5FF2E56E2FF2951E1FF1D46DDFF7D8FD1FFCBCCCFFFCECECEFFCECE CEFFCECECEFFCECECEFFCFCFCEFFC7C8CCFF7582C2FF0C2DC8FF1533C5FF1431 C3FF132EC0FF122CBEFF122ABCFF061EB9FF7A83C1FFCACBCEFFCECECEFFCECE CEFFCECECEFFCECECEFFCFCFCEFFCACACEFF747AB8FF020FA1FF0411A2FF0511 A0FF040F9DFF030D9BFF030B99FF020997FF000794FF0C1098FFA79CC270F9F8 F910FFFFFF01EFEAEC20A39BBD937092F5FF6587F1FF5B7EEEFF4F74EBFF446B E9FF3D63E6FF365CE3FF3057E1FF2950DFFF2E52D9FFACB3CEFFCCCCCDFFCDCD CDFFCDCDCDFFCDCDCDFFCDCDCDFFCECDCCFF9EA5C4FF1A37C5FF1432C5FF1531 C3FF132FC0FF122CBEFF112ABCFF0F27B8FFA9ADC7FFCECECDFFCDCDCDFFCDCD CDFFCDCDCDFFCDCDCDFFCDCDCDFFA7AAC4FF1421A6FF0412A3FF0713A2FF0611 9FFF050F9DFF040E9BFF040C9AFF040A98FF020895FF0D1299FFA79CC270F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8BF2FF6788F0FF6182EEFF5779 EBFF4C6FE8FF4267E5FF3B60E2FF355AE0FF284EDEFF6C81CFFFCACBCFFFCDCD CCFFCCCCCCFFCCCCCCFFCCCCCCFFCECECCFFB2B6C8FF3A52C1FF1230C5FF1631 C3FF152FC0FF132DBEFF0E27BCFF3547B8FFB9BCCAFFCECECDFFCCCCCCFFCCCC CCFFCCCCCCFFCDCDCDFFC5C6CBFF6269B4FF000EA5FF0916A4FF0814A2FF0712 A0FF06109EFF060F9CFF060E9AFF070D99FF060B96FF11179BFFA89DC270F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6685 EDFF6080EAFF5778E8FF4C6EE5FF4465E2FF3B5DDFFF3E5ED9FFC7C9CEFFCDCD CDFFCDCDCDFFCDCDCDFFCDCDCDFFCECECDFFBDBFC9FF586AC0FF1230C6FF1733 C3FF1631C0FF152EBFFF0D26BDFF5664BBFFBFC1CAFFCECDCDFFCDCDCDFFCDCD CDFFCDCDCDFFCDCDCDFFBDBECAFF1E2BA9FF0917A7FF0A17A6FF0A16A3FF0A15 A1FF0A149FFF0B139EFF0B139CFF0C129BFF0C1299FF191E9EFFA99EC370F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6988EFFF6887 EEFF6786EBFF6583EAFF617FE8FF5A78E6FF5170E2FF4163E0FFB1B7CEFFCBCB CBFFCBCBCBFFCBCBCBFFCBCBCBFFCCCCCBFFC1C2C8FF6B7AC1FF1835C8FF1E39 C4FF1C36C2FF1A33C0FF0F29BDFF717DBEFFC4C4C9FFCCCBCBFFCBCBCBFFCBCB CBFFCBCBCBFFCBCBCBFFABAFC4FF0617A9FF101EA9FF101DA7FF111DA5FF111C A4FF121BA3FF131CA1FF151CA0FF181E9FFF191F9FFF272BA4FFABA0C370F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6581E7FF637EE5FF5B77E4FFA7B0CFFFC8C8 C9FFC9C9C9FFC9C9C9FFC9C9C9FFC9C9C9FFC5C5C6FF838DC3FF243FCBFF2942 C8FF263FC5FF243CC3FF1831C1FF838BC0FFC5C5C7FFC9C9C9FFC9C9C9FFC9C9 C9FFC9C9C9FFC7C7C8FF8F95BFFF1221ADFF1B29ACFF1B28ABFF1D28AAFF1E29 A9FF202AA8FF232BA7FF262DA7FF2A31A8FF2F34A8FF3F44AEFFAEA3C570F9F8 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF6580E6FF607BE5FFAAB1D1FFCBCB CBFFCBCBCBFFCBCBCBFFCBCBCBFFCCCCCBFFC9C9CAFF8F99C8FF3952D0FF3D54 CCFF3950CAFF364CC7FF2A40C5FF949AC5FFCACACBFFCCCCCBFFCBCBCBFFCBCB CBFFCBCBCBFFC9CACBFF9398C2FF2533B4FF2E3BB4FF303BB3FF323CB2FF353E B2FF3941B2FF3D45B2FF4349B3FF484DB4FF4B4FB4FF5659B8FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF6580E6FF607AE5FFB1B7D2FFD0D0 D1FFD1D1D1FFD1D1D1FFD1D1D1FFD1D1D1FFCACBCEFF919BCAFF566BD7FF596C D4FF5668D2FF5265D0FF495CCEFF959CC6FFCDCDCEFFD1D1D1FFD1D1D1FFD1D1 D1FFD1D1D1FFCFCFD0FF9EA2C6FF444FBEFF4C57BFFF4E58BDFF5058BCFF5159 BCFF5259BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF6580E6FF617BE4FFC6C9D2FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD6D6D5FFCCCDD2FF8D99CEFF596FD8FF5D71 D6FF5D70D3FF5C6ED2FF5669D2FF939BC8FFCFCFD2FFD6D5D5FFD5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFBABCCEFF505BC3FF5660C2FF545EC0FF545CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF637FE7FF7689D8FFD7D8DBFFDBDB DBFFDBDBDBFFDBDBDBFFDBDBDBFFDCDCDBFFCBCDD7FF7E8CCFFF5A70D8FF5D71 D6FF5D6FD3FF5C6ED2FF5769D2FF818AC7FFCFD0D7FFDBDBDBFFDBDBDBFFDBDB DBFFDBDBDBFFDBDBDAFFCDCED6FF5F69C0FF545EC2FF545EC0FF535CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6583E9FF6681E7FF607CE6FFA5AFD7FFDEDEE0FFE0E0 E0FFE0E0E0FFE0E0E0FFE0E0E0FFE2E2E0FFC7CADAFF6A7BD0FF5C71D8FF5D71 D6FF5D6FD3FF5C6ED2FF596BD2FF6D78C7FFCDCED8FFE1E1E0FFE0E0E0FFE0E0 E0FFE0E0E0FFE1E1E0FFDADADEFF8C92C6FF4F5AC1FF545EC0FF535CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6683E9FF627FE8FF7389DDFFD6D8DFFFE5E5E5FFE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E3FFB7BDD7FF5A70D7FF5E72D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6CD1FF5969CDFFBDC1D2FFE4E4E4FFE5E5E5FFE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFC6C8D7FF5B65BFFF525CC0FF545CBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6684EAFF6381EAFF6781E2FFB5BDDAFFE4E5E5FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFDDDEE3FF919CD3FF5970D9FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5C6DD1FF5566D0FF969DC8FFE0E1E3FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE1E2E4FF9EA3CAFF525BBDFF525BBFFF535B BDFF5359BBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB1A6C670F9F7 F910FFFFFF01EFEAEC20A39BBD937092F6FF6A8AF2FF6989F0FF6888EFFF6887 EEFF6786EBFF6282EBFF6783E4FFA6B1DCFFE1E2E3FFE6E6E5FFE5E5E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E5FFCDD1DEFF6679D5FF5E73D9FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5A6ACFFF6572C8FFCFD1DAFFE5E5E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE5E5E6FFE7E7E6FFDBDCE0FF8F95C8FF515ABBFF5058 BDFF535ABBFF5258BAFF5257B9FF5156B7FF4F53B5FF575BB9FFB2A8C86FF9F8 F910FFFFFF01EFEAED20A39BC1937092F5FF6A8AF2FF6989F0FF6888EFFF6686 EFFF6081ECFF758DE1FFB1BADEFFE0E1E3FFE6E6E5FFE6E6E6FFE5E5E5FFE6E6 E6FFE5E5E5FFE6E6E6FFE2E3E5FF99A3D4FF5A70DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5666CDFF99A0C9FFE4E4E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE7E7E6FFDBDCE0FF9EA2CBFF5D64 BBFF4B52BAFF5056BAFF5157B9FF5156B7FF4F53B5FF575BB9FFA596B775F7F5 F71000000000FDF6FF159D99CE8E6B8FF6FF6487F4FF6284F2FF6283EEFF768F E3FFA1AFDDFFCCD0E0FFE4E4E4FFE7E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6 E6FFE6E6E6FFE5E5E5FFC5C8D9FF6277D9FF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5A6ACEFF5F6EC9FFC9CBD5FFE6E6 E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE7E7E6FFE2E2E3FFC3C5 D7FF9093C3FF5E63B5FF4A50B5FF484EB5FF484CB4FF5256B8FF9580A473FFFF FF05B4B4B413D7D6D793C3C2D6C9A3B4E5FFA7B5E0FFB2BCDEFFC5CBDEFFD5D9 E3FFE0E1E4FFE6E6E5FFE6E6E6FFE5E5E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5 E5FFE6E6E6FFDCDDDFFF7687D5FF5E74DCFF6074DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5867CDFF737EC7FFE1E1 E0FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE6E6E6FFE6E6 E5FFDFDFE3FFD3D3DEFFBEC0D2FFABADCBFF9B9DC7FF9799C8FFC3BDC8BDD4D3 D487B2B2B222E0E0E0FFE4E4E5FCE1E2E5FFE2E3E5FFE3E3E4FFE5E5E5FFE6E6 E5FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6 E6FFE4E4E2FF8897D4FF5F76DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5867CBFF888F C6FFE8E8E5FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5 E5FFE6E6E6FFE6E6E6FFE5E5E5FFE3E3E4FFE1E1E3FFE1E1E3FFE4E4E4FBDFDF DFF8B2B2B223E1E1E1FFE7E7E7FFE7E7E6FEE7E7E6FFE7E7E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE7E7E7FFE8E7 E5FF8E9CD5FF6079DEFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 C9FF8C93C8FFE8E8E4FFE7E7E7FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE7E7E6FFE7E7E6FFE7E7E6FEE7E7E7FFE1E1 E1FFB2B2B223E1E1E1FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE6E7E7FFE1E1E2FF8797 D5FF6079E0FF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF888EC5FFE3E3E2FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE1E1 E1FFB2B2B223E1E1E1FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E7FFE5E5E7FFC9CCDCFF788BDAFF617B E1FF627ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5562C5FF7179C3FFCBCCD9FFE6E6E7FFE8E8E7FFE8E8E8FFE8E8 E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE1E1 E1FFB2B2B223E2E2E2FFE8E8E8FFE8E8E8FEE8E8E8FFE8E8E8FFE8E8E8FFE9E9 E8FFE9E9E8FFE7E7E6FFE1E2E7FFD3D6E3FF99A7D9FF657EE1FF627CE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF545FC4FF5A64C2FF959AC9FFD0D1DCFFE1E1E5FFE7E7 E6FFE9E9E8FFE9E9E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FEE8E8E8FFE2E2 E2FFB2B2B223DFDFDFFFE5E5E5FEE4E5E6FFE5E5E5FEE2E3E4FFDEDFE5FFD9DC E6FFD0D5E5FFBDC6E2FF95A5DEFF6B84E2FF607CE6FF647DE4FF647EE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF5761C4FF555FC3FF505AC1FF5D66BFFF8C91C6FFB6B8 D2FFCACCDBFFD6D6DFFFDCDDE1FFE2E3E4FFE3E4E4FEE5E5E5FFE4E4E4FEDEDE DEFDB1B1B114D7D7D79CD3D1DAC0AAB1D5FFACBAE8FEA5B4E3FF97A9E3FF879C E2FF718BE3FF6180E9FF607FEAFF6480E7FF6580E6FF657EE4FF647EE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF5761C4FF5660C3FF555FC2FF525CC0FF4D56BEFF4F57 BBFF6268BAFF787CBEFF8B8EC3FF9A9DC9FF9B9ECAFEA09CBEFFD5D3D8BAD4D4 D4950000000000000000BBB4CF546367B2FF6D91FCFF6183F1FE6384F0FF6484 EFFF6585ECFF6684EAFF6683E9FF6681E7FF6580E6FF657EE4FF647EE3FF637D E1FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5E73D7FF5D71 D6FF5D6FD3FF5C6ED2FF5B6DD1FF5C6BCFFF5B6BCEFF5A69CDFF5968CCFF5966 CAFF5764C8FF5663C5FF5761C4FF5660C3FF555FC2FF545EC0FF545CBFFF535B BDFF5057BBFF4D54B9FF4B51B8FF474DB4FE4E54BBFF50418BF9D5CFE2450000 000000000000FFFFFF06D8D1DA3B7B6E9CCA7B8FE1FF6C8FF6FE6686EFFE6887 EEFF6786EBFF6684EAFF6583E9FF6581E7FF647FE6FF647DE4FF637DE2FF627C E0FF617ADFFF6179DDFF6077DCFF6076DBFF5F74DAFF5F74D8FF5D72D7FF5C70 D5FF5C6FD3FF5B6DD2FF5B6CD1FF5B6ACFFF5A6ACDFF5968CCFF5867CBFF5865 C9FF5764C8FF5663C5FF5661C4FF5660C3FF555FC2FF545EC0FF535CBFFF535B BDFF5259BBFF5056B9FF4D53B7FE585EBEFF6460ADFF7B6895AEE7E2E929FFFF FF0300000000FFFFFF02F8F4F419BBAEBE6A7E77A7E07B89D4FF7C9AF7FF6D8D F4FF6688F1FF6587F0FF6585EFFF6986EDFF6A88ECFF6A86EBFF6A85EAFF6984 E7FF6882E6FF6881E4FF677FE3FF667EE2FF667DE1FF657CDFFF657ADEFF6378 DCFF6377DAFF6276D9FF6275D7FF6273D6FF6172D4FF6071D3FF5F6FD2FF5F6D D0FF5E6CCFFF5C6BCCFF5A67CAFF5561C7FF5460C6FF535FC4FF525DC3FF525C C1FF565FC1FF6269C5FF7279CBFF6F6AADFF776491D3C4B8C650FCFAFA0E0000 00000000000000000000FFFFFF05F9F7F620BFB2C05D978DB2A47973A9DF6F6C ABFC6968AAFF6A68AAFF6967A9FF6B68A8FF6B68A7FF6B67A7FF6B66A7FF6B66 A5FF6A65A4FF6A65A4FF6A63A3FF6963A3FF6862A2FF6862A1FF6861A0FF6860 9FFF675F9EFF675F9EFF675E9DFF675D9CFF665D9CFF665C9BFF655B9AFF655A 99FF645A98FF645997FF635796FF615595FF615494FF605393FF605392FF6052 91FF625392FF65538DFF6F5B8BEA917F9EAEC0B2BF56FEFDFC17FFFFFF020000 0000000000000000000000000000FFFFFF04FFFFFF10DBD1D827C1B6C745C5BE D157B3A8BB62A696AA66A898AB66A797AB66A797AB66A797AA66A797AB66A797 AA66A796AA66A796AA66A796AA66A796AA66A696AA66A696A966A695A966A695 A966A695A966A695A866A695A866A694A866A694A866A694A866A694A866A694 A766A594A766A593A766A594A766A694A766A693A766A593A766A593A666A593 A666A593A665B5A7B95FC1B4C351DDD3D831FFFFFF11FFFFFF03000000000000 00000000000000000000000000000000000000000000FFFFFF02FFFFFF07FFFF FF0AFFFFFA0CF6EFEA0CF7F1EB0CF7F1EB0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1 EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F1EC0CF7F2EC0CF7F2 EC0CF7F2EC0CF7F2EC0CF7F2ED0CF7F2ED0CF7F2ED0CF7F2ED0CF7F2ED0CF7F2 ED0CF8F2ED0CF8F2ED0CF8F2ED0CF8F2ED0CF8F3ED0CF8F3ED0CF8F3EE0CF8F2 ED0CF8F3EE0CFFFFFF0BFFFFFF09FFFFFF05FFFFFF0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8000000001FFFFFE00000000007FFFFC00000000001FFFFC00000000001 FFFF800000000000FFFF800000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF800000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF800000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 FFFF000000000000FFFFC00000000001FFFF800000000000FFFF800000000001 FFFFC00000000001FFFFE00000000003FFFFF80000000007FFFFFFFFFFFFFFFF FFFF280000004000000080000000010020000000000000420000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F7F7FA01FBFBFC04FCFCFC05FBFB FD03F6F6F90100000000F7F6FA0100000000F6F6F901F6F6F901F6F6F901F7F6 F901F6F6F901F6F6F901F7F6F901F6F6F901F7F6F901F6F5F901F6F5F901F6F5 F801F6F6F901F6F6F901F6F6F901F5F5F801F6F5F801F6F5F801F6F6F901F6F6 F901F6F5F801F6F5F801F6F5F801F6F6F901F6F5F801F6F5F801FCFCFD04FCFC FD07FDFDFD08FCFCFD08FCFCFD08FDFDFD08FDFDFD08FCFCFC07FCFCFD04F5F4 F701000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FBFA FB01FBFBFC04FCFCFD0EFAF9F914F4F0F117F0EDF01BF4F1F325F4F1F32BF4F1 F324F1EDEF1BEEE9ED16EFEAED16EEEAED16EDE9EC15EFEAED16EDE9EC15EFEB ED16EFEAED16EFEBED16EFEAED16EEEAEC16EFEAED16EFEAED16EFEAED16EFEA ED16EFEAED16EFEAED16EEE9EC16EEEAED16EFEAED16EFEAED16EDE9EC15EFEA ED16EEEAED15EFEBEE16EFEBEE16EFEBED16EFEBEE17F2EEF01BF4F1F327F6F3 F533F5F3F438F5F3F438F5F3F438F5F3F438F5F3F438F4F2F333F4F2F326F4F1 F41AFBF9F913FCFCFC0DFBFBFB05F9F8F9020000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDFDFD02FBFB FC0CF8F7F822E9E5E83ED5C8C95AA289927090748A80977C908A93778A979980 92879073897E8D6F867A8D6F867A8D70867A8D6F867A8D70867A8D70867A8C70 86798D70867A8D7086798D70857A8D70857A8D7085798D70857A8E6F867A8E6F 867A8E6F867A8E70867A8D6F857A8D70867A8D70867A8C6F867A8D7086798D70 857A8C70867A8D7086798D71867A8D71867A8D70867A92768B80977B908E9477 89A094788AA795788BA794778AA794788AA795788AA6917486A194788C8EA48E A275D7CACD58E4DEE53DF4F2F428FBFBFC16FAFAFB0600000000000000000000 00000000000000000000000000000000000000000000FCFCFD02F9F9F912F1EF F234C6BCCB696A4E72C4412B68F63B2E74FD48448DFD484793FE474693FD4645 92FE454391FE454290FE444190FE44408FFE443F8DFE433E8DFE433E8CFE423D 8BFD423C8AFE423B8AFE413B88FD413A87FE413986FE403985FE403785FE3F37 84FE3F3683FE3F3582FE3E3481FE3D3480FE3D3380FE3D337FFE3C327EFD3C31 7DFE3C317CFE3B307BFE3B2F7BFE3B2E7AFD3A2D79FE3A2C79FE3A2B78FD392A 77FE392A77FE392976FE382875FE382874FE382773FE372771FE372672FE2F16 59FD2B0C52FD4A2B63D7AB9CB085E0DAE14DF7F7F921FCFCFC09000000000000 00000000000000000000000000000000000000000000FAFAFB0DEFEDF034A699 B084493B7BEF6C79C9FD4C6EE1FD3E67EAFD355EE8FE325CE6FE3059E4FD2E57 E2FE2E55E1FE2D53DFFE2C52DEFE2B51DCFE2A50DAFE294DD8FE284CD7FE284A D5FD2748D4FE2647D2FE2645D0FD2544CFFE2543CEFE2442CCFE2340CBFE233F C9FE223DC7FE213CC6FE203AC4FE1F38C2FE1F37C1FE1E35BFFE1E34BEFD1D33 BCFE1C31BBFE1B30B9FE1B2EB8FE1A2DB6FD192BB4FE192AB2FE1828B1FD1727 AFFE1726AEFE1625ACFE1523AAFE1522A9FE1420A7FE131FA6FD121DA4FE1923 A6FD1C219EFD34339BFD4C3A7DFD553563CACCC3D055F8F7F921FBFAFB060000 000000000000000000000000000000000000F7F7F904F6F5F71FBFB7CC694946 93F76A8BF0FD315DE9FD2B57E6FE2854E5FE2550E3FE234EE0FF224CDFFE2149 DDFF2047DCFF1F46DAFF1F44D8FF1D43D6FF1D41D4FF1C40D3FF1A3ED1FF1A3D CFFE193BCEFF183ACCFF1839CBFE1737C9FF1736C7FF1635C6FF1533C4FF1532 C3FF1430C1FF132EBFFF122CBDFF112ABBFF1129BAFF1027B8FF0F26B7FE0E25 B5FF0D23B3FF0D22B2FF0C20B0FF0B1FAFFE0B1DACFF0A1BAAFF0A1AA9FE0918 A7FF0817A6FF0816A4FF0614A2FF0613A1FF05119FFF04109EFF040E9CFF030C 9AFE030B99FE000695FE070F9BFC38318AFD4F3265CDDCD6DE4DFAFAFA16F5F5 F70200000000000000000000000000000000FAFBFC0BD8D5E33C4A4592D95B82 F2FD315EEAFD2D59E8FE2A56E6FE2753E5FE2451E3FE234FE1FE214CE0FE2049 DEFE2048DDFE1F47DBFE1E44D9FE1D43D7FE1C42D5FE1C41D4FE1A3FD2FE1A3D D0FE193CCFFE183ACDFE1839CCFE1737CAFE1736C8FE1635C7FE1533C5FE1532 C4FE1430C2FE132EC0FE122CBEFE112ABCFE1129BBFE1027B9FE0F26B8FE0E25 B6FE0D23B4FE0D22B3FE0C20B1FE0B1FB0FE0B1DADFE0A1BABFE0A1AAAFE0918 A8FE0817A7FE0816A5FE0614A3FE0613A2FE0511A0FE04109FFE040E9DFE030C 9BFE020B9AFE020A98FE010895FE050A96FC302A8EFDA395AF87F3F1F429F8F8 FA05000000000000000000000000B6B6B608E2E2E419C2C4E05D4B69D7F65278 EDFD315EE9FE2E5AE8FE2956E6FF2652E4FD2350E2FF224DE0FF214BDFFD204A DDFF2049DCFF1E46DAFF1E44D9FF1D43D7FF1C42D4FF1C40D3FF193FD1FF1A3D D0FD193BCEFF173ACCFF1839CCFD1736C9FF1735C8FF1534C6FF1533C5FF1532 C4FF132FC2FF122EBFFF112BBDFF112ABBFF1129BAFF1026B8FF0F26B8FD0E24 B5FF0C23B3FF0C22B2FF0B20B0FF0B1FB0FD0A1DACFF091AABFF0A1AAAFD0818 A8FF0817A6FF0816A4FF0614A3FF0613A2FF0511A0FF04109FFF040E9DFF040C 9BFF030C9AFE040C99FF060B97FE060894FE1F229EFD3C2369DFD8D5DB40D2D2 D312B2B2B20300000000A6A6A605BDBDBD60C8C8C872B2B4CDA98597D5FD6B87 DEFE6D87DFFE6985DEFF4A6EE2FE3F65E1FD3860E0FF3158DEFF2850DEFD214A DDFF1F48DDFF1E46DAFF1E44D8FF1D43D6FF1C42D4FF1C40D4FF1A3FD2FF1A3D D0FD193CCFFF183ACDFF1839CCFD1737CAFF1735C8FF1635C6FF1533C4FF1532 C4FF1430C2FF132EC0FF122CBEFF112ABBFF1128BBFF1027B9FF0F26B8FD0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0B1FB0FD0B1DADFF0A1AABFF0A1AAAFD0817 A8FF0817A7FF0816A5FF0614A3FF0512A1FF0814A0FF111BA0FF1821A2FF2027 A2FF252CA3FF3C42A8FE4F53ABFE4C4FA5FE5052A6FD564D8EFDC8C7C4A7C0C0 C07BB6B6B62D00000000A1A1A10CCFCFCFF7D8D8D8FCD8D8D6FCD8D8D7FED9D8 D6FED8D7D5FED9D8D6FED9D8D6FFD1D4D9FEBEC3D4FFA3ADD0FF7187D2FE3A5E DCFF274EDCFF2148DAFF1D44D9FF1D43D6FF1C42D4FF1B40D4FF1A3FD2FF193C CFFE193BCFFF1839CCFF1838CCFE1737CAFF1736C8FF1535C7FF1433C5FF1432 C4FF1330C1FF132EC0FF122BBEFF1129BCFF1128BBFF1027B9FF0E26B7FE0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0B1EB0FE0A1CADFF091BABFF0A1AA9FE0918 A8FF0817A6FF0917A5FF0C19A4FF161DA4FF3840AAFF7E82B9FFACAEC8FFC6C7 D4FFD6D7D6FFD8D8D5FFD8D9D7FFD9D9D8FEDADAD9FEDCDBD9FDD9D9D9FCD8D8 D8FDC0C0C07400000000A1A1A10CCFCFCFF3D6D6D6FCD5D5D5FDD6D6D6FED6D6 D7FED5D5D6FED6D6D7FED4D5D6FED4D5D6FDD5D6D7FED8D9D9FED9D9D7FDC7C9 D0FE8596D2FE4A67D6FE2C4FD7FE1E44D6FE1C42D4FE1C41D3FE1A3FD2FE1A3D D0FD193CCFFE183ACDFE1839CCFD1737CAFE1735C8FE1635C7FE1532C5FE1532 C4FE1430C2FE132EC0FE112CBEFE112ABCFE1129BBFE1027B9FE0F26B8FD0E25 B6FE0D22B4FE0D22B3FE0C20B1FE0B1FB0FD0B1DADFE0A1BABFE0A1AAAFD0919 A8FE0D1CA6FE2530AAFE4B54B2FE9FA3C3FED9D9D8FEDDDDDCFED6D7D7FED5D5 D6FED5D5D6FED5D5D6FED5D5D6FED5D5D6FED5D5D6FED5D5D6FED5D5D5FDD6D6 D6FDC0C0C07300000000A1A1A10DCFCFCFF5D5D5D5FDD5D5D5FDD6D6D6FED6D6 D6FED6D6D6FED6D6D6FED6D6D6FED6D6D6FDD6D6D6FED5D5D5FED5D5D6FDD4D4 D6FED4D5D6FECCCED6FE909DCCFE3C5CD5FE2549D4FE1C41D3FE1A3FD1FE193D D0FD193BCEFE1739CCFE1839CBFD1636CAFE1635C8FE1535C7FE1532C4FE1532 C3FE142FC2FE122DBFFE122BBDFE112ABCFE1128BAFE1027B9FE0F26B8FD0E25 B5FE0D22B4FE0D22B2FE0C20B1FE0B1EAFFD0B1DADFE0A1BABFE0B1BA9FD1826 AAFE4650AFFEACAEC9FED5D6D9FED5D5D7FED5D5D6FED5D5D5FED5D5D5FED5D5 D5FED6D6D6FED6D6D6FED6D6D6FED6D6D6FED6D6D6FED5D5D5FED5D5D5FDD5D5 D5FEC0C0C07400000000A1A1A10DCFCFCFF5D4D4D4FED4D4D4FED5D5D5FFD5D5 D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FED5D5D5FFD4D4D4FFD4D4D4FED5D5 D5FFD4D4D4FFD4D3D5FFD5D5D7FFB7BCD0FF6379CFFF294CD2FF1C40D2FF193D CFFE193CCEFF183ACDFF1839CCFE1737CAFF1736C8FF1635C7FF1533C5FF1532 C4FF1430C2FF132EC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0B1FB0FE0B1DADFF0E20ABFF2B38ADFE7F84 BEFFCBCCD4FFD7D7D7FFD3D3D4FFD4D4D4FFD5D5D5FFD4D4D4FFD5D5D5FFD4D4 D4FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD5D5D5FFD4D4D4FFD4D4D4FED4D4 D4FFC0C0C07400000000A1A1A10DCECECEF5D3D3D3FED3D3D3FED4D4D4FFD4D4 D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FED3D3D3FFD3D3D3FFD4D4D4FED4D4 D4FFD4D4D4FFD3D3D4FFD2D2D3FFD3D3D4FFC8CAD4FF8290CBFF3252D1FF1C3F CFFE193CCEFF1739CDFF1839CCFE1737CAFF1736C8FF1635C6FF1532C4FF1532 C3FF1430C2FF132EC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D23B4FF0D22B3FF0C20B1FF0C1FB0FE1324AEFF3B48B3FFA8ACCBFED4D4 D7FFD3D3D4FFD2D2D3FFD3D3D3FFD3D3D3FFD4D4D4FFD3D3D3FFD4D4D4FFD3D3 D3FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD4D4D4FFD3D3D3FED4D4 D4FFC0C0C07400000000A2A2A20CCDCDCDF4D2D3D2FDD2D2D2FDD3D3D4FED3D3 D4FED3D3D3FED4D4D3FED4D4D4FED4D4D4FED3D3D3FED3D3D3FED4D4D4FED4D4 D4FED4D4D4FED4D4D4FED3D3D3FED2D2D3FED2D2D3FECCCDD3FE939FCEFE3855 CEFE1C3DCEFE183ACCFE1839CCFE1737CAFE1736C8FE1635C7FE1533C5FE1532 C4FE1430C2FE132EC0FE122CBEFE112ABCFE1129BBFE1027B9FE0F25B8FE0E25 B6FE0D23B4FE0D22B2FE0D21B1FE1426B0FE4955B5FEB3B6CEFED3D4D5FED2D2 D2FED2D2D3FED3D3D3FED3D3D3FED3D3D3FED4D4D4FED3D3D3FED4D4D4FED3D3 D3FED4D4D4FED4D4D4FED4D4D4FED3D3D3FED3D3D3FED3D3D3FED2D2D2FDD3D3 D3FEBFBFBF7300000000A2A2A20CCECECEF3D3D3D3FDD2D2D2FDD3D3D3FED3D3 D3FED3D3D3FFD3D3D3FFD3D3D3FFD3D3D3FED2D2D2FFD2D2D2FFD3D3D3FED3D3 D3FFD3D3D3FFD3D3D3FFD2D2D2FFD3D3D3FFD3D3D3FFD2D3D4FFCFD0D2FF9AA3 CBFE3552CCFF193BCDFF1839CBFE1736CAFF1735C7FF1635C6FF1533C4FF1531 C3FF1330C2FF132EC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D23B4FF0E22B3FF1226B2FF4956B8FEB5B8CEFFD2D2D3FFD1D2D2FED3D3 D3FFD3D3D3FFD3D3D3FFD3D3D3FFD2D2D2FFD3D3D3FFD3D3D3FFD4D4D4FFD2D2 D2FFD3D3D3FFD3D3D3FFD2D2D3FFD2D2D3FFD2D2D3FED2D2D2FED2D2D2FDD3D3 D3FDBFBFBF7300000000A2A2A20CCCCCCCEFD1D1D1F9CFCFCFFCCFD0D3FECFD0 D3FED0D0D0FFD3D2D1FFD4D4D3FFD3D3D4FED2D2D2FFD2D2D2FFD3D3D3FED3D3 D3FFD3D3D3FFD3D3D3FFD2D2D2FFD2D2D2FFD3D3D3FFD2D2D2FFD1D1D2FFC7C9 CFFE8893C9FF2947CCFF193ACBFE1737C9FF1736C8FF1635C7FF1533C5FF1532 C4FF1430C2FF132EC0FF122CBDFF112ABCFF1129BBFF1027B9FF0F26B8FE0E25 B6FF0D24B4FF1124B2FF3C4BB6FFAAAECFFED1D2D5FFD2D2D2FFD3D3D3FED2D2 D2FFD3D3D3FFD3D3D3FFD3D3D3FFD2D2D2FFD3D3D3FFD2D2D2FFD2D2D3FFD2D2 D2FFD4D4D4FFD5D5D4FFD4D4D2FFCECED1FFCCCCD0FECDCDD0FED0D0D0FAD1D1 D1F9BEBEBE7100000000A4A4A408C7C7C7A9CFD0CFC0B7B4C0E8A1B0DAFE9EAD D9FEA2ADD2FEACB5D1FEB9BED1FEC6C8D0FECECED0FED0D1D1FED1D1D2FED1D1 D1FED2D2D2FED2D2D2FED2D2D2FED2D2D2FED2D2D2FED2D2D2FED1D1D1FED1D1 D2FEC1C4D0FE7181C7FE203FCAFE1837C9FE1736C8FE1635C7FE1433C5FE1432 C4FE1430C2FE132EC0FE122CBEFE1129BCFE1129BAFE1027B8FE0F26B7FE0E25 B6FE1025B5FE2B3CB4FE959BC6FECCCDD1FED0D0D1FED1D1D1FED1D1D1FED2D2 D2FED2D2D2FED2D2D2FED2D2D2FED1D1D1FED1D1D1FED1D1D2FED2D2D3FECECE D1FEC0C1CEFEAFB0C9FEA4A4C3FE9292BDFE8C8CBAFE9293BCFECAC8CBCDCDCC CDB4BDBDBD4F0000000000000000EFF0F109ECEAF03B7C6C9CBB3E6BF1FE3361 ECFE2F5DEBFF335CE2FF516FD3FF7D8FCDFE9EAAD1FFB3BAD1FFCCCDCFFED2D2 D2FFD1D1D1FFD2D2D1FFD1D1D1FFD1D1D1FFD2D2D2FFD1D1D1FFD1D1D1FFD0D0 D0FED0D0D0FFABB1CDFF4B61C7FE1A39C9FF1736C8FF1635C6FF1533C4FF1532 C4FF1430C2FF132DC0FF122CBEFF112ABCFF1129BBFF1027B9FF0F26B7FE0F26 B6FF182CB5FF7780C0FFC5C7D0FFD1D1D3FED1D1D1FFD1D1D1FFD1D1D1FED1D1 D1FFD2D2D2FFD1D1D1FFD1D1D2FFD0D0D1FFD3D3D3FFC4C5CDFFACAECAFF9194 C1FF5458A9FF1B219AFF030695FF020494FF020392FE15199CFEC3B5C864F1F0 F113C9C9CA010000000000000000F4F4F50EEDEBF03F7E709DBC4570F0FD3A66 ECFD3562EAFE315DE8FE2D59E7FE2955E5FD3259DEFE5471D6FE96A3CEFDC1C4 D2FED0D0D1FED0D0D1FED0D0D0FED1D1D1FED1D1D1FED1D1D1FED1D1D1FED0D0 D0FDCFD0D0FECDCDCFFE959FC9FD2F4AC6FE1836C8FE1635C7FE1533C4FE1532 C3FE142FC2FE122DBFFE122CBDFE112ABBFE1128BBFE1027B9FE1027B8FD1027 B6FE4555B9FEABB0CAFED0D0D1FECFCFD0FDD1D1D1FED0D0D0FED0D0D0FDD1D1 D1FED1D1D1FED0D0D0FED0D0D1FECDCED0FEBABCCCFE777BB6FE2C34A3FE0811 9BFE020A99FE020A98FE020A96FE020895FE010593FD171C9DFDC3B5C868F3F2 F318D7D7DA020000000000000000FCFDFD0BEFECF13D7E6F9CBB4A73F1FD3F69 EDFD3864ECFF345EE9FF305BE7FF2D57E5FD2A55E3FF2651E2FF2E55DDFD7388 CFFFB2B9CFFFCFCECEFFCFCFCFFFD0D0CFFFCFCFCFFFD0D0D0FFCFCFCFFFCFCF CFFDCFCFCFFFCECED0FFB8BBCBFD6173C5FF1837C8FF1735C6FF1533C5FF1532 C4FF1430C1FF132DC0FF122CBEFF112ABCFF1129BBFF1027B9FF1128B8FD1F34 B7FF9097C6FFCECFD0FFCECECFFFD0D0CFFDCFCFCFFFD0D0D0FFCFCFCFFDCFCF D0FFCFCFD0FFCECECFFFCCCCCFFFA3A6C7FF4E55ACFF0D169FFF050F9DFF040D 9BFF030C9AFF010A98FF010795FF000694FF000392FD161B9CFDC3B4C766F7F6 F715000000000000000000000000FCFDFD0CEFEDF23E80709DBC527AF2FD466E EEFD3F68EBFF3862EAFF345EE8FF2F5AE6FD2B56E3FF2853E1FF2851E0FD2C53 DCFF5A75D1FFB4BACDFFCECECFFFCECFCEFFCFCFCFFFCFCFCFFFCFCFCFFFCECE CEFDCECFCFFFCDCDCEFFCCCDCCFD949DC6FF2E49C5FF1635C6FF1533C5FF1431 C4FF1330C1FF132EC0FF112BBEFF112ABCFF1129BBFF1128B9FF0F26B8FD4E5C BCFFAEB2CAFFCECECFFFCECECEFFCFCFCFFDCFCFCFFFCFCFCFFFCECECEFDCFCF CFFFCDCDCFFFCBCBCEFFA2A4C4FF323BA9FF0A16A1FF06119FFF040E9DFF030C 9BFF010A99FF010998FF000896FF010795FF000493FD171C9DFDC3B5C867F8F6 F815F4F4F9010000000000000000FDFDFE0BEFEDF13E81729DBB5C82F2FD4E75 EEFD466FECFF3F69EAFF3962E8FF345EE7FD2F59E4FF2B55E2FF2952E0FD2750 DEFF2C52DCFF627BD2FFBEC1CDFFCDCECEFFCECECEFFCECECEFFCECECEFFCECE CEFDCECECEFFCDCDCDFFCDCECEFDB8BBC8FF6273C1FF1837C6FF1633C5FF1532 C3FF142FC1FF132EBFFF122CBDFF112ABBFF1129BAFF1129B9FF172CB8FD7D86 C2FFC6C7CBFFCCCDCDFFCDCDCEFFCECECDFDCECECEFFCECECEFFCDCDCDFDCDCD CDFFCCCCCFFFA6A9C4FF3A43ABFF0C18A2FF0611A0FF04109EFF030D9DFF030C 9BFF020B9AFF010A98FF010896FF010795FF000593FD171C9DFDC3B4C866F8F6 F816F4F4FA010000000000000000FDFDFE0CF0EDF23E83739DBC668AF3FE5A7E EFFE5076EDFF486FEBFF4168E9FF3B63E7FE355EE5FF3159E3FF2D55E1FE2A52 DFFF274FDDFF3255D9FF7C8ECCFFC8CACEFFCCCCCCFFCDCDCDFFCDCDCDFFCDCD CDFECDCDCDFFCDCDCDFFCCCCCDFEC6C7CBFF808CC6FF213EC5FF1634C5FF1431 C3FF1330C2FF132EC0FF122CBEFF112ABCFF1129BBFF1028B9FF3C4DB9FEA3A8 C6FFCECECDFFCCCDCDFFCDCDCDFFCECECEFECECECEFFCECECEFFCDCDCDFECCCC CDFFBDBECAFF4F58B0FF101EA4FF0713A2FF0511A0FF04109FFF040E9DFF030C 9BFF030B9AFF020B98FF020996FF020895FF000593FE171C9DFEC2B5C867F8F6 F816F4F4F9010000000000000000FDFEFE0BF0EDF23D83739DBC6C8DF3FD6587 F0FD5D80EEFF5479ECFF4B71EAFF456BE8FD3E65E6FF385FE3FF335AE2FD2F56 E0FF2C52DEFF2A4FDCFF4464D6FFA6AECCFFCDCCCEFFCBCCCCFFCCCCCCFFCCCC CCFDCCCCCCFFCCCCCCFFCBCCCCFDCACACBFF969EC7FF364FC3FF1634C5FF1531 C3FF1330C1FF132EC0FF122CBEFF112ABCFF122ABBFF1229BAFF6672BDFDBCBE C9FFCCCCCCFFCCCCCCFFCDCDCDFFCCCCCCFDCDCDCDFFCCCCCCFFCBCBCCFDCACB CCFF787DB7FF1A27A7FF0615A3FF0613A2FF0511A0FF04109EFF040F9DFF040D 9BFF030C9AFF030B98FF020996FF020896FF010694FD191E9EFDC2B4C766F8F6 F815F5F5FA010000000000000000FDFEFE0CF0EDF23D83739DBC6C8DF3FE698A F0FE6688EFFF6082EDFF597CEBFF5174E9FE496DE7FF4167E5FF3C61E2FE365C E1FF3157DFFF2E53DDFF3457D8FF6C81CFFFCCCCCCFFCACBCBFFCBCCCCFFCBCB CBFECCCCCCFFCCCCCBFFCBCBCBFECACACBFFB0B4C5FF5669C0FF1432C5FF1733 C3FF1430C2FF142FC0FF132DBEFF122BBCFF122BBBFF1930B9FF7D87C2FEC5C6 CBFFCACACBFFCBCBCBFFCCCCCCFFCBCBCBFECCCCCCFFCBCBCBFFCACACBFEB8B8 C6FF3642ADFF0A18A5FF0815A3FF0714A2FF0612A0FF05109EFF050F9DFF040E 9CFF040D9BFF030C99FF040B98FF040A96FF040994FE1C219FFEC2B4C767F8F6 F816F5F5FA010000000000000000FDFEFE0CF0EEF23E84749DBC6D8EF4FE6989 F0FE6888EFFF6787EEFF6484ECFF5F7EEBFE5678E9FF4E71E6FF476AE4FE4064 E2FF3B5FE0FF375ADEFF3155DBFF4B68D7FFB2B7CAFFCBCBCCFFCBCBCBFFCCCC CBFECBCBCBFFCBCBCBFFCBCBCBFECACACBFFC2C2C4FF727EBFFF1734C5FF1733 C3FF1430C2FF142FC0FF132DBEFF122CBCFF132CBBFF253ABAFF8B93C5FEC9CA CCFFCACBCBFFCBCBCCFFCCCCCCFFCBCBCBFECCCCCCFFCBCBCBFFCDCDCDFE8B8F BBFF2431A9FF0A18A6FF0815A4FF0714A3FF0713A1FF06129FFF06119EFF0710 9CFF060F9BFF060E9AFF070E98FF080E97FF090D96FE2026A0FEC2B4C767F7F6 F716F5F5FA010000000000000000FDFDFD0CEFEDF13D84739DBC6D8EF4FE6A8A F1FE6888F0FE6787EEFE6886EDFE6785ECFE6281EAFE5D7DE8FE5676E6FE4F6F E4FE486AE2FE4264E0FE3C5EDEFE4766DAFE8B99D0FECACACBFECACACBFECBCB CAFECBCBCBFECBCBCBFECACACAFEC9C9CAFEC7C7C5FE838DC0FE2540C5FE1A36 C4FE1733C2FE1631C1FE152FBFFE152DBDFE142CBCFE3347BAFE969CC3FEC9C9 CAFEC9CACAFECACACAFECBCBCBFECACACAFECBCBCBFEC9C9CAFED0D0CDFE5860 B3FE1422A8FE0C19A6FE0B17A5FE0A16A3FE0A15A2FE0A15A0FE0A149FFE0B14 9EFE0B139DFE0B139CFE0C139BFE0E149AFE0F1499FE272CA3FEC2B3C766F8F6 F815F5F5FA010000000000000000FDFEFE0CEFEDF13E84749DBC6C8DF4FE6989 F0FE6988F0FF6788EEFF6886EDFF6785ECFE6685EAFF6584E9FF6280E8FE5D7C E6FF5876E4FF5270E2FF4B6BE0FF4C6ADDFF798CD4FFC9CACBFFC8C9CAFFCACA CAFECACACAFFCACACAFFCACAC9FEC9C9CAFFC8C7C7FF8D96C1FF334CC4FF1F3B C5FF1C37C3FF1A35C1FF1933BFFF1832BEFF162FBDFF4455B9FFA1A5C3FEC9C9 C9FFC9C9C9FFCACACAFFCACACAFFCACACAFECACACAFFC8C8C9FFC6C6C8FE3D48 B1FF0F1EA9FF0F1DA7FF0E1BA6FF0F1BA5FF0F1BA3FF0F1AA2FF101AA1FF111A A0FF111AA0FF131B9FFF151B9EFF171D9EFF191E9DFE3135A8FEC1B3C767F7F6 F816F5F6FA010000000000000000FDFEFE0CF0EEF23E84749DBC6D8EF3FE6A8A F1FE6989F0FF6888EFFF6887EDFF6785ECFE6585EAFF6584E9FF6482E8FE6481 E7FF637FE6FF5F7CE5FF5C78E3FF5A75DFFF7C8FD6FFC8C9CCFFC7C8C9FFC9C9 C9FEC9C9C9FFC9C9C9FFC9C9C8FEC8C8C8FFC7C7C7FF989FC3FF445AC3FF2741 C7FF243EC5FF223BC3FF1F39C1FF1F37BFFF1B33BEFF5564BBFFACAFC2FEC8C8 C8FFC8C8C8FFC9C9C8FFC9C9C9FFC9C9C9FEC8C8C8FFC7C8C9FFACAFC2FE3441 B1FF1422ABFF1523AAFF1522A9FF1623A8FF1723A6FF1723A5FF1923A5FF1A24 A4FF1C24A4FF1F26A4FF2128A4FF2429A4FF282CA4FE4145AEFEC1B2C667F7F5 F815F6F6FB010000000000000000FDFEFE0CEFEEF13D84749CBB6C8EF3FE6A8A F0FE6988F0FE6787EFFE6987EEFE6785ECFE6684EBFE6684E9FE6582E8FE6481 E7FE6480E6FE647FE5FE647EE4FE657DE1FE8394D8FEC8C9CDFEC7C8C9FEC9C9 C9FEC9C9C9FEC9C9C9FEC8C8C8FEC8C8C8FEC7C7C7FEA3A9C4FE576AC6FE334C CAFE2F48C8FE2D45C6FE2A42C4FE2A40C2FE243CC1FE6572BDFEB4B7C3FEC8C8 C8FEC8C8C8FEC9C9C8FEC9C9C9FEC9C9C9FEC8C8C8FEC7C8C9FE9C9FBFFE3844 B3FE1F2DAFFE202EAEFE212DADFE222EACFE242EABFE242FAAFE2730AAFE2932 ABFE2C34ABFE2F36ABFE3339ABFE383CACFE3D40ACFE5357B6FEC0B2C667F7F5 F816F7F7FB010000000000000000FDFEFE0CEFEEF23E84749DBC6C8DF4FE6989 F0FE6989F0FF6888EFFF6987EEFF6785ECFE6685EBFF6684EAFF6583E8FE6482 E8FF6480E6FF647EE5FF647EE3FF667EE1FF8596D9FFCACBCEFFCACACBFFCBCB CBFECBCBCBFFCBCBCBFFCBCBCBFECACACAFFCBCBCAFFA8AEC8FF6375C8FF445B CEFF4057CCFF3D53CBFF3A50C8FF394EC6FF3348C5FF7480C1FFBCBDC6FECACA CBFFCACACAFFCBCBCBFFCBCBCBFFCBCBCBFECACACAFFCACACBFF9FA3C2FE4550 B8FF303CB5FF313EB4FF333DB3FF343EB2FF3740B2FF3942B2FF3C44B2FF3E46 B3FF4148B2FF444AB2FF474CB3FF4A4EB3FF4C4FB3FE5E62BBFEBFB1C667F7F5 F816F7F7FB010000000000000000FDFEFE0CF0EEF23E84749DBC6D8EF3FE6A8A F1FE6989F0FF6888EFFF6987EDFF6886EDFE6685EBFF6684EAFF6583E9FE6582 E8FF6581E6FF647FE5FF647EE4FF677FE1FF8899DAFFCECFD2FFCECECFFFCFCF D0FECFCFCFFFD0D0D0FFCFCFCFFECFCFCFFFCECECEFFA9AFCAFF6A7BCDFF576B D3FF5368D1FF5165D0FF4E62CDFF4E60CCFF495CCBFF7984C4FFBBBDC8FECECF CFFFCFCFCFFFD0D0CFFFD0D0D0FFD0D0CFFECFCFCFFFCFCECFFFA5A8C4FE5761 BDFF4550BDFF4752BCFF4851BBFF4952BAFF4A53B9FF4C54B9FF4D54B8FF4E54 B8FF4E54B7FF4F54B7FF4F54B6FF4F53B5FF4E52B4FE5F63BBFEBFB1C667F7F5 F716F7F7FB010000000000000000FDFDFD0CEFEEF13E84739DBC6D8EF4FE6A8A F1FE6989EFFE6888EEFE6987EEFE6886EDFE6685EBFE6684EAFE6683E9FE6582 E7FE6581E7FE657FE5FE647EE4FE6981E1FE909FDAFED1D2D3FED2D2D3FED2D2 D3FED3D3D3FED3D3D3FED2D2D2FED2D2D2FED0D0D0FEA7ADCCFE697BD0FE5E71 D5FE5C6FD3FE5B6ED2FE5A6DD1FE5A6CD0FE5869D0FE7B86C7FEB9BCCBFED2D2 D2FED2D2D2FED3D3D2FED3D3D3FED3D3D2FED2D2D2FED2D2D2FEB8BAC8FE6770 C3FE525CC2FE535DC0FE525CBFFE525BBEFE525BBCFE525ABBFE5158BAFE5157 B9FE5056B8FE4F55B7FE4F54B5FE4E53B5FE4E52B4FE5F62BBFEBFB1C667F7F5 F716F7F7FB010000000000000000FDFEFE0CEFEDF23E84749DBC6D8EF4FE6A8A F1FE6989F0FF6887EFFF6987EEFF6886EDFE6585EBFF6584E9FF6683E9FE6582 E7FF6580E7FF657FE5FF647EE3FF6D84E0FFA0ABD6FFD5D5D6FFD6D6D6FFD6D6 D6FED7D7D7FFD7D7D7FFD6D6D6FED6D6D6FFD2D2D1FFA3ABCDFF6578D4FF5E71 D5FF5C6FD4FF5B6ED2FF5B6DD1FF5B6DD0FF5B6BD0FF7681CAFFB6BACEFED5D5 D6FFD6D6D6FFD6D6D6FFD7D7D7FFD6D6D6FED6D6D6FFD5D5D6FFD0D0D0FE767E C5FF5560C2FF545EC0FF525CBEFF525BBDFF525ABCFF5259BBFF5158BAFF5157 B9FF5056B8FF4F55B7FF5055B6FF4F54B6FF4F53B5FE6063BCFEBFB0C667F7F5 F815F8F8FC010000000000000000FCFDFD0CF0EEF13E84749CBC6C8EF4FE6A8A F1FE6989F0FE6787EFFE6987EEFE6886ECFE6685EAFE6683EAFE6683E9FE6582 E8FE6581E7FE657FE5FE637EE4FE758BDEFEBDC1D0FED9D9DAFED9D9D9FEDADA DAFEDADADAFEDADADAFED9D9D9FED9D9DAFED1D1D2FE98A2CDFE5E73D7FE5E72 D6FE5C70D4FE5B6ED3FE5B6DD1FE5B6CD0FE5B6CCFFE6A77CBFEAEB3D0FED8D8 D9FED9D9D9FED9D9D9FEDADADAFED9D9D9FEDADADAFED9D9D9FEDBDBD9FE8E94 C5FE5C66C1FE555FC0FE535CBFFE535CBEFE535BBDFE535ABCFE5259BBFE5258 BAFE5157B9FE5056B8FE5055B6FE4E54B6FE4F52B5FE6062BCFEBFB1C667F7F5 F816F8F8FC010000000000000000FCFDFD0CF0EEF23E84749DBC6D8EF4FD6A8A F1FD6889F0FE6888EFFE6887EEFE6786EDFD6685EBFE6684E9FE6583E9FD6582 E7FE6580E7FE6580E5FE6881E1FE8D9CD8FEDAD9DAFEDEDEDEFEDFDFDFFEDFDF DFFDDFDFDFFEDFDFDEFEDEDEDEFDDDDEDEFEC9CBD4FE8894CEFE5D71D7FE5E72 D6FE5C70D4FE5C6ED3FE5C6ED1FE5B6DD1FE5C6CD0FE6371CCFEA7ADD1FDD9D9 DBFEDEDEDEFEDEDEDEFEDFDFDFFEDFDFDFFDDFDFDFFEDEDEDEFEDFDFDFFDB4B7 CFFE6971C4FE555FC1FE535DBEFE535CBEFE535BBCFE5359BCFE5259BBFE5258 BAFE5157B9FE5056B8FE5055B6FE4F53B6FE4F53B5FD6063BCFDBFB1C666F7F5 F816F8F8FC010000000000000000FCFDFD0CEFEEF23E84749DBC6C8EF3FE6989 F0FE6989F0FF6888EFFF6987EDFF6785ECFE6685EBFF6684EAFF6582E8FE6582 E8FF6581E6FF6580E5FF768CE0FFB8BFD8FFE3E3E4FFE2E2E2FFE3E3E3FFE3E3 E3FEE3E3E3FFE3E3E2FFE2E2E2FEE0E1E2FFBBC0D9FF7585D2FF5E73D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5C6CD0FF5E6ECEFF989FCBFED5D5 D9FFE2E2E3FFE2E2E2FFE3E3E3FFE3E3E3FEE3E3E3FFE2E2E2FFE1E1E2FED6D6 DBFF7D84C6FF5861C0FF535DBFFF525CBEFF535BBDFF535ABCFF5259BBFF5258 BAFF5157B9FF5056B8FF5055B6FF4F54B6FF4E52B4FE5F62BBFEBFB1C567F6F5 F816F8F8FC010000000000000000FDFEFE0CF0EEF23E84739DBC6D8EF4FE6A8A F1FE6888EFFF6888EFFF6887EEFF6886EDFE6685EBFF6683E9FF6583E9FE6581 E7FF6581E7FF6983E3FF92A1D8FFDADBE0FFE3E3E4FFE5E5E4FFE4E4E4FFE5E5 E5FEE5E5E5FFE4E4E4FFE4E4E4FEE0E0E2FFAEB6DAFF677AD4FF5E73D6FF5E72 D5FF5C6FD5FF5C6FD3FF5C6ED1FF5B6DD1FF5B6CD0FF5C6BCEFF828BC5FEC8C9 D5FFE3E3E4FFE4E4E4FFE4E4E4FFE4E4E4FEE5E5E5FFE5E5E5FFE4E4E4FEE3E3 E3FFB6B9D1FF6971C1FF545EBEFF535DBEFF535BBDFF535ABCFF5258BAFF5258 BAFF5157B8FF5056B8FF5055B6FF4F54B6FF4F53B4FE6063BCFEBFB1C667F6F5 F816F8F8FC010000000000000000FDFEFE0BF0EEF23D84739CBB6D8EF4FD698A F1FD6888EFFF6787EFFF6886EDFF6886EDFD6584EAFF6583EAFF6583E9FD6682 E7FF6883E6FF8296DDFFC8CCDAFFE3E4E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5 E5FDE5E5E5FFE4E4E4FFE5E4E5FDD6D7DDFF98A2D2FF6175D6FF5E73D6FF5E71 D5FF5D6FD5FF5B6ED2FF5B6DD1FF5B6DD1FF5B6CCFFF5C6BCEFF6774CAFDAEB3 D0FFDFDFDFFFE4E4E4FFE4E4E4FFE4E4E4FDE5E5E5FFE5E5E5FFE5E5E5FDE4E4 E4FFDEDEE0FF999EC8FF5D66BFFF535DBFFF535BBCFF525ABBFF5259BAFF5258 BAFF5056B9FF4F55B7FF4F55B5FF4F54B5FF4F53B5FD6063BCFDBEB0C567F6F4 F716F7F7FB010000000000000000FDFEFE0CF0EDF23E83749DBC6D8EF3FE6A8A F1FE6989F0FF6888EFFF6887EEFF6786ECFE6685EBFF6684E9FF6683E8FE6783 E7FF788EDFFFBCC3D8FFE2E2E2FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5 E5FEE5E5E5FFE4E4E4FFE4E3E4FEBEC3DAFF7585D3FF5F74D7FF5E72D6FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6BCEFF5B6ACDFE8E96 CBFFD0D1DAFFE4E4E4FFE4E4E4FFE5E5E5FEE5E5E5FFE5E5E5FFE5E5E5FEE5E5 E5FFE3E3E4FFD3D3DDFF8F94C4FF5B65BEFF545CBDFF535ABCFF5259BAFF5258 BAFF5157B9FF5056B8FF5055B6FF4F54B6FF4F53B5FE6063BCFEBEB0C567F6F4 F716F8F8FB010000000000000000FDFDFE0BEFEDF23D84749CBB6C8EF4FE6989 F1FE6888F0FE6787EFFE6886EDFE6886ECFE6685EAFE6684EAFE6784E8FE8195 DDFEBAC2DCFEE0E1E2FEE4E4E4FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5 E5FEE5E5E5FEE4E4E4FED7D9E0FE9DA7D7FE6276D8FE5F74D7FE5E72D6FE5D71 D6FE5D6FD5FE5C6FD2FE5C6ED1FE5B6CD0FE5B6CD0FE5B6ACEFE5B6ACDFE6D7A C8FEB8BCD4FEE2E2E2FEE4E4E4FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5E5FEE5E5 E5FEE5E5E5FEE4E4E4FED1D2DBFE9599C7FE5D65BCFE535BBCFE535ABBFE5258 B9FE5157B8FE4F55B7FE4F54B6FE4E53B6FE4E52B5FE5F63BCFEBAAABF68F6F4 F615000000000000000000000000F8F8F80DEFEDF33E8376AEBC6D8EF3FD6A8A F0FD6989EFFF6888EEFF6987EDFF6887ECFD6886EAFF6F8BE5FF96A5D8FDCBCF E1FFE0E0E2FFE5E5E6FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6E6FFE5E5E5FFE5E5 E5FDE4E4E4FFE4E4E4FFC0C6DEFD7888D4FF6074D9FF5F74D8FF5E72D6FF5D71 D6FF5D70D4FF5C6FD3FF5C6ED1FF5B6CD1FF5B6CD0FF5B6ACEFF5B6ACDFD5B6B CCFF9198C7FFD1D2D9FFE3E3E4FFE5E4E4FDE5E5E5FFE5E5E5FFE5E5E5FDE5E5 E5FFE5E5E5FFE5E5E5FFE4E4E5FFD4D5DEFFAFB1CEFF6B72BEFF565DBAFF5359 BAFF5258B9FF5157B8FF5055B6FF4F54B6FF4F53B5FD6165BCFDA892A86FF1ED F017E1E1E3010000000000000000F5F5F60BEEECF43D8278BCBB6D8EF3FD698A F2FE6888F1FE6586F0FF6686EDFF768FE0FD9AAADBFFB9C2E1FFD3D6DEFDE4E4 E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5 E5FDE4E4E4FFD1D4DDFF94A0D5FD6378D8FF6074D8FF5F74D8FF5E72D6FF5E71 D6FF5C70D5FF5B6FD3FF5B6ED2FF5B6CD1FF5B6CD0FF5B6ACEFF5A6ACDFD5969 CDFF6875C9FFAFB4D1FFDDDEE0FFE4E4E4FDE5E5E5FFE5E5E5FFE5E5E5FDE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E5FFDFDFE1FFC2C4D8FFA4A6CBFF7A7D B9FF5A5EB3FF4E54B7FF4E53B6FF4E53B6FE4F53B5FE6064BEFDA28AA171EFEB EE15D0D0D10100000000A7A7A704C9C9C957DBDBDB7C9F99C2D18CA3E5FE8EA1 DFFE96A6DCFFA2B0DBFFB6BEDAFFC9CFE1FED7D9E1FFE0E1E3FFE5E5E5FEE4E4 E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E4FFE4E4 E4FEDCDDE2FFACB4D8FF6A7FD8FE6075DAFF5F74D9FF5F74D8FF5D71D7FF5D71 D5FF5D6FD4FF5B6ED3FF5B6DD1FF5B6CD0FF5B6CCFFF5B6ACDFF5A6ACDFE5A6A CCFF5A6ACCFF7A85C6FFC5C8D7FFE4E3E3FEE4E4E4FFE5E5E5FFE5E5E5FEE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E4FFE5E5E5FFE4E4E4FFDBDBDFFFD0D0 DCFFBDBDD1FFA4A6C5FF9194BEFF8587BDFF797BBBFE8385C1FEB7ACB7A0D0D0 D062B9B9B927000000009F9F9F0BD7D7D7D1E2E2E2E1D6D5DCF4D0D5E3FED1D5 E2FED4D7E0FED9DADFFFE0E0DFFFE5E5E4FEE5E5E5FFE5E5E5FFE4E5E5FEE5E5 E5FFE5E5E5FFE6E6E6FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE4E4E4FFE0E0 E1FEBBC1D8FF7688D7FF6177DBFE6075D9FF5F74D8FF5F73D8FF5E72D7FF5E72 D6FF5D70D4FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6ACEFF5A6ACDFE5969 CDFF5868CBFF5D6CC8FF8991CAFFCDCFDCFEE3E3E4FFE5E4E4FFE6E6E6FEE5E5 E5FFE6E6E6FFE6E6E6FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E4FFE4E4E4FFE6E6 E6FFE4E4E3FFDCDCDEFFD5D5DBFFD1D1DBFECCCDDBFECDCEDBFEDCDADCE9E1E1 E1DCC4C4C462000000009E9E9E0CD8D8D8F3E5E5E5FDE3E3E4FDE4E4E5FEE4E4 E5FEE4E4E5FEE3E3E4FFE4E4E5FFE4E4E4FDE4E4E4FFE5E5E5FFE5E5E5FDE5E5 E5FFE5E5E5FFE4E4E4FFE5E5E5FFE5E5E5FFE4E4E4FFE3E3E4FFE2E2E3FFC6CA DBFD8292D5FF6279DBFF6077DAFD5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CCFFF5B6ACEFF5A6ACDFD5969 CDFF5868CBFF5968CAFF606DC8FF979ECBFDD5D6DDFFE3E4E4FFE4E4E4FDE5E5 E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE4E4E4FFE4E4 E4FFE4E4E4FFE4E4E4FFE4E4E4FFE4E4E5FEE4E4E5FEE4E4E4FEE4E4E4FDE5E5 E5FDC6C6C673000000009E9E9E0CD8D8D8F4E5E5E5FDE5E5E5FDE6E6E6FEE6E6 E6FEE6E6E6FFE5E5E5FFE5E5E5FFE6E6E6FEE6E6E6FFE6E6E6FFE6E6E6FEE6E6 E6FFE5E5E5FFE5E5E5FFE6E6E6FFE5E5E5FFE4E5E5FFE3E3E4FFC8CCDCFF8191 D5FE667CDBFF6078DCFF6077DBFE5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6DD2FF5B6DD1FF5B6CD0FF5B6ACEFF5A69CDFE5969 CDFF5868CBFF5867CAFF5966C9FF636FC8FE9A9FCBFFD6D6DEFFE4E4E5FEE5E5 E5FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6E6FFE5E5E5FFE6E6E6FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FEE5E5E5FEE5E5E5FDE5E5 E5FEC6C6C673000000009E9E9E0DD9D9D9F5E6E6E6FEE6E6E6FEE7E7E7FEE7E7 E7FEE7E7E7FEE6E6E6FEE6E6E6FEE7E7E7FEE7E7E7FEE6E6E6FEE7E7E7FEE6E6 E6FEE6E6E6FEE6E6E6FEE5E6E6FEE5E5E5FEE3E3E2FEC3C7D8FE8092D9FE647C DCFE6179DCFE6077DBFE6076DBFE5F74DAFE5F74D9FE5F74D7FE5E72D7FE5E72 D6FE5D70D5FE5C6FD3FE5C6ED2FE5B6DD1FE5B6BD0FE5B6ACEFE596ACDFE5869 CDFE5868CBFE5867CBFE5865C8FE5865C8FE636FC6FE9198C9FED4D5DFFEE5E5 E6FEE4E4E5FEE6E6E6FEE6E6E6FEE6E6E6FEE6E6E6FEE6E6E6FEE6E6E6FEE7E7 E7FEE7E7E7FEE7E7E7FEE7E7E7FEE7E7E7FEE7E7E7FEE6E6E6FEE6E6E6FEE6E6 E6FEC6C6C674000000009E9E9E0DD8D8D8F5E6E6E6FEE6E6E6FEE7E7E7FFE7E7 E7FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FEE6E6E6FFE6E6E6FFE7E7E7FEE7E7 E6FFE6E6E5FFE5E5E6FFE4E5E5FFDDDEE2FFB3BBDAFF798CDCFF647DDEFF617A DEFE6179DCFF6077DCFF6077DBFE5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6ACEFF5A6ACDFE5969 CDFF5868CBFF5867CAFF5865C9FF5864C7FE5764C6FF5E6AC5FF868CC4FEC7C8 D8FFE3E3E5FFE5E5E6FFE5E5E5FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7E7FFE6E6 E6FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7E7FFE7E7E7FFE6E6E6FFE6E6E6FEE6E6 E6FFC6C6C674000000009E9E9E0DD9D9D9F5E6E6E6FEE6E6E6FEE7E7E7FEE7E7 E7FFE7E7E7FEE6E6E6FFE7E7E7FFE7E7E7FEE7E7E7FFE6E6E6FFE7E7E7FEE6E6 E6FFE5E6E6FFE6E6E6FFCFD2DDFF919FD9FF7187DFFF647CE0FF627BDFFF617A DDFE6178DCFF6077DCFF5F77DAFE5F74D9FF5F74D8FF5F74D8FF5E72D6FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6CD1FF5B6CD0FF5B6ACDFF5A6ACCFE5969 CDFF5868CBFF5866CBFF5865C8FF5764C8FE5764C6FF5662C5FF5C67C2FE7078 C6FFA4A8C8FFDCDDE0FFE6E6E6FFE4E5E6FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7 E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FEE7E7E7FFE6E6E6FEE6E6E6FEE6E6 E6FFC7C7C774000000009E9E9E0CD8D8D8F4E6E6E6FDE6E6E6FDE7E7E7FEE7E7 E7FEE6E6E7FFE6E6E6FFE6E6E7FFE6E6E7FEE6E6E7FFE5E6E6FFE8E8E8FEE7E6 E7FFCDD0DCFFA4B1DCFF798EDDFF6780E1FF637DE1FF637CE0FF617BDEFF6079 DEFE6179DDFF6077DCFF5F76DBFE5F75DAFF5F74D9FF5F74D8FF5E72D7FF5E72 D6FF5D70D5FF5C6FD3FF5C6ED2FF5B6DD1FF5B6CD0FF5B6ACEFF5969CCFE5969 CDFF5868CBFF5867CBFF5865C9FF5864C8FE5764C6FF5662C4FF5661C4FE5761 C3FF5E68C2FF7D84C4FFB0B2CFFFD7D7DBFFE8E8E7FFE7E7E8FFE6E6E7FFE6E6 E6FFE6E6E6FFE7E7E7FFE6E6E6FFE7E7E7FFE7E7E7FEE6E6E6FEE6E6E6FDE6E6 E6FEC6C6C673000000009E9E9E0CD9D9D9F3E7E7E7FCE6E6E6FDE7E7E7FEE6E6 E7FEE6E7E7FEE6E6E7FEE5E6E7FEE6E7E7FDE6E7E9FEDEDFE3FEC3C8D6FD90A0 D8FE748DE4FE6C85E4FE657EE3FE647EE3FE637DE1FE637CE0FE617BDFFE617A DDFD6179DCFE5F77DBFE6076DBFD5E74D9FE5E73D8FE5E73D7FE5D72D6FE5D72 D5FE5D70D5FE5B6ED3FE5B6DD2FE5A6CD0FE5A6BCFFE5A69CDFE5A6ACDFD5869 CCFE5767CAFE5766CAFE5765C8FE5864C8FD5763C5FE5662C5FE5661C4FD5660 C3FE545FC2FE5862C0FE5F68C0FE6F76C4FE9DA0C5FEC7C8D1FEDCDCDFFEE4E4 E5FEE4E5E5FEE5E5E5FEE5E5E6FEE5E5E6FEE5E6E6FEE5E5E6FEE6E6E7FCE7E7 E7FDC7C7C77300000000A4A4A40CC6C6C6D8DADADAE6D2D1D6F2C9CCD7FDCCD0 DCFEC6CAD7FEB7BFD7FFAEB8D9FF9CACE0FD8A9EE3FF7C95E3FF718BE5FD6884 E6FF6481E7FF647FE5FF647EE3FF647EE2FF637CE1FF637CE1FF617BDFFF6179 DEFD6179DDFF6077DCFF6076DAFD5F75DAFF5F73D8FF5F73D7FF5E71D6FF5E71 D6FF5D70D5FF5B6FD3FF5B6ED2FF5B6DD1FF5B6BCFFF5B6ACDFF596ACCFD5969 CDFF5867CBFF5866CBFF5865C9FF5763C7FD5764C6FF5662C4FF5561C4FD5660 C3FF555FC2FF555FC1FF535DBFFF545DBEFF5A61BDFF646BBEFF7277C0FF8186 C3FF989AC7FFADAECAFFC1C2CFFFC0C0CCFEC7C8D3FEC7C6CFFDD0D0D1EBD2D2 D2E3BFBFBF6600000000A4A4A401C3C3C31CE0DFE235A599B894889AE0FD708F EFFE708EEEFE6F8CEDFF6E8BEBFE6C89EBFE6986E9FF6784E9FF6683E9FE6582 E8FF6581E6FF647FE4FF647EE3FF637DE3FF627CE2FF627CE1FF607BDFFF617A DEFE6078DDFF6077DCFF6077DBFE5F74D9FF5F73D9FF5F73D8FF5E72D7FF5E72 D5FF5D70D5FF5C6FD3FF5C6ED2FF5B6CD1FF5B6CD0FF5B6ACEFF5A6ACDFE5969 CDFF5868CBFF5867CBFF5865C9FF5864C8FE5764C5FF5762C5FF5661C5FE5660 C3FF545EC2FF555FC0FF535DBFFF535CBEFF535BBDFF535ABCFF545BBBFF565C BAFF575BBAFF585DB9FE595DB8FF585BB7FE5E63BBFE503C7CFDDCDAE05FD5D5 D523BEBEBE0D0000000000000000F2F2F402F7F5F81BC3BBCF6B696FB8FA7D9A F5FD6888F0FE6788EFFE6887EEFF6886ECFD6685EAFF6684E9FF6683E8FD6582 E7FF6481E7FF647EE5FF647EE4FF637DE3FF627CE2FF627CE1FF617BDEFF6179 DEFD6178DDFF6076DCFF6076DBFD5F74DAFF5F74D9FF5E73D8FF5D72D6FF5D71 D6FF5C70D5FF5C6FD3FF5B6ED2FF5B6DD1FF5A6CD0FF5A69CEFF5A6ACDFD5869 CDFF5868CAFF5867CAFF5765C9FF5764C8FD5663C6FF5662C4FF5661C5FD5560 C3FF555FC2FF555FC1FF525CBFFF535CBEFF535BBDFF535ABCFF5259BBFF5258 BAFF5156B9FF4F55B8FF4F54B6FE4D51B4FE5D5FB5FD593E75D8E6E1EA3BFCFC FD0C000000000000000000000000E9E8EA01FAFAFB13DBD4DD4D5C4678E08AA0 EDFD6786EEFD6889EEFE6887EEFE6886EDFD6685EAFE6584EAFE6582E9FD6481 E8FE6480E7FE657FE5FE657EE4FE647EE3FE637DE2FE637CE1FE617BDFFE617A DEFD6179DDFE6077DCFE6077DBFD5F75DAFE5F74D9FE5F74D8FE5E72D7FE5E72 D6FE5D70D5FE5C6FD3FE5C6ED2FE5B6DD1FE5B6CD0FE5B6ACEFE5A6ACDFD5969 CDFE5868CBFE5867CBFE5865C9FE5864C8FD5764C6FE5762C5FE5661C5FD5560 C3FE545EC2FE545EC1FE525CBFFE525BBEFE525ABDFE5259BCFE5259BBFE5258 BAFE5157B9FE5157B8FE4F54B5FE656AC0FC645B9EFDA99AB580F3F1F425F9F9 FA0600000000000000000000000000000000FBFBFC09F3F0F12EAD9BAA85645B 94FA93A8EFFD6989EEFD6787EDFE6785ECFD6684EAFE6683E9FE6682E8FD6581 E7FE6580E6FE647EE4FE647DE3FE637DE2FE627CE1FE627BE0FE617ADEFE6179 DDFD6178DCFE6076DBFE6076DAFD5F74D9FE5F73D8FE5E73D7FE5D71D5FE5D71 D5FE5C6FD4FE5C6ED2FE5B6DD1FE5B6CD0FE5A6BCFFE5A69CDFE5A69CCFD5968 CCFE5867CAFE5867CAFE5765C8FE5764C7FD5663C5FE5662C4FE5661C4FD5560 C2FE555FC1FE555FC0FE535DBEFE535CBDFE535BBCFE535ABBFE5259BAFE5258 B9FE5156B8FE5156B7FE6266BDFD7A74B2FD5D406CCFDCD6DF46FBFAFB100000 000000000000000000000000000000000000FBFAFB01FAFAFA14EBE7EA40A392 A791645388F48B97D7FD93ACF9FD7492F1FD6686ECFD6484EBFE6382EAFD6381 E9FE6581E9FE6D88E9FE6F89E8FE6F88E7FE6F88E6FE6F87E5FE6E86E3FE6E85 E2FD6D84E1FE6D82E0FE6C82DFFD6C81DEFE6C80DDFE6B7FDCFE6A7EDBFE6A7D DAFE697CD9FE687BD8FE687AD7FE6879D6FE6778D5FE6776D4FE6776D3FD6675 D2FE6574D1FE6573D0FE6471CEFE6470CDFD636FCCFE636ECBFE5E6AC8FD5560 C4FE535EC2FE525DC1FE515BBFFE505ABEFE515ABDFE5058BCFE5A61BFFE686E C4FE8186CFFE9297D5FD70649CFD6F5379CBCFC5CF5CF8F6F81FFBFAFB040000 00000000000000000000000000000000000000000000FDFCFD05FAF9FA16F0EE F137CFC7D560725A7FB365578BE5776EA0F47677B2FA7776B1F97775B2FA7775 B1FA7674B0FA7674AFFA7673AFFA7673AEFA7572AEFA7572ADFA7571ABFA7471 ABFA7571AAFA7470A9FA7470A9FA746FA9FA746EA8FA736EA8FA736DA7FA736D A7FA726DA6FA726CA6FA726BA5FA726BA4FA716AA4FA716AA3FA7169A3FA7168 A2FA7167A2FA7067A1FA7066A1FA7066A0FA7065A0FA70659FFA6F659EFA6F64 9DFA6F649DFA6F639CFA6E639CFA6D629BF96D629BFA6D619AFA6D6198F96C5F 97FA675384F6593B69E381647DA9D7CED753F8F6F824FBFBFB09000000000000 0000000000000000000000000000000000000000000000000000FBFBFB03FCFB FC0EF9F8FA1DE3DDE432DAD5DE4AD7D1DD5CCDC6D365A28D9C76A28D9C76A28D 9C76A18C9C77A28C9B77A18C9B77A28C9B76A28C9A77A28C9B77A18C9A77A28C 9B76A28C9B77A28C9A77A28C9A77A28C9A77A28C9A77A28C9A76A28B9A77A28C 9A77A18B9A76A18B9A77A28B9A77A28B9977A28A9977A28B9977A18A9977A28B 9877A28A9877A18B9876A18B9977A18B9976A18B9976A18A9877A18B9977A18B 9976A18B9977A18B9977A18B9976A18B9976A08A9877A18A9876A0899776B09E AB6FCFC6D161DCD5DD52EAE5E937FAF9FA1AFBFAFB09FCFCFC01000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F7F7F903FCFCFC08FBFBFC10FAF9FA17F7F6F718EEEAED18EEEAEC19EEE9 EC18EFEBED19EFEBED19EFEBED19EEEAEC19EFEBED19EFEBED19EFEBED19EEEA ED18EFEBED19EFEBED19EDE9EB18EFEBED19EFEBED19EFEBED19EFEBED19EFEB ED19EFEBED19EFEBED19EFEBED19EEEAEC18EFEBED19EFEBED19EEEAEC19EEEA EC19EEEAEC18EEEAEC19EFEBED19EEEAEC18EFEBED19EFEBED19EFEBED19EEEA EC19EFEBED19EFEBED19EEEAEC19EFEBED19EEEAEC19EEEAEC19EEEAEC19F2F0 F119F9F8F918FBFBFC14FDFCFD0BFAF9FA030000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F6F6F901F6F6F901F6F5 F801F7F6F901F6F6F901F6F6F901F6F5F801F6F6F901F6F6F901F6F6F901F6F6 F901F6F6F901F6F5F801F6F6F901F6F6F901F6F6F901F6F5F801F6F6F901F6F6 F901F6F6F901F6F6F901F6F6F901F6F6F901F6F5F801F6F5F801F6F5F801F6F5 F801F5F5F801F6F5F801F6F5F801F6F5F801F6F6F901F6F5F801F6F5F801F6F5 F801F6F6F801F6F5F801F6F5F801F6F5F801F6F5F801F6F5F801F6F5F801F6F5 F801000000000000000000000000000000000000000000000000000000000000 00000000000000000000FFFFFFFFFFFFFFFFFFC14000000003FFF80000000000 003FF00000000000001FE00000000000000FE000000000000007C00000000000 0003C00000000000000380000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001800000000000000180000000000000018000000000000003800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0001800000000000000180000000000000018000000000000001800000000000 0003800000000000000180000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001000000000000000100000000000000010000000000000001000000000000 0001000000000000000180000000000000038000000000000003C00000000000 0007C000000000000007E00000000000000FF00000000000000FFC0000000000 003FFFE00000000003FF } OnCreate = FormCreate Position = poScreenCenter LCLVersion = '2.0.12.0' OnClose = FormClose OnCreate = FormCreate OnHide = FormHide object pnlInfo: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 11 Height = 302 Top = 11 Width = 196 AutoSize = True BorderSpacing.Around = 11 BevelInner = bvRaised BevelOuter = bvLowered BevelWidth = 2 ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 302 ClientWidth = 196 ParentColor = False ParentFont = False TabOrder = 0 object lblTitle: TLabel AnchorSideLeft.Control = pnlInfo AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = imgLogo AnchorSideTop.Side = asrBottom Left = 43 Height = 15 Top = 96 Width = 111 BorderSpacing.Top = 6 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Double Commander' Font.Color = clRed Font.Style = [fsBold] ParentColor = False ParentFont = False end object pnlVersionInfos: TPanel AnchorSideLeft.Control = pnlInfo AnchorSideTop.Control = lblTitle AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlInfo AnchorSideBottom.Side = asrBottom Left = 24 Height = 187 Top = 111 Width = 104 AutoSize = True BorderSpacing.Left = 20 BorderSpacing.Right = 20 BevelOuter = bvNone ChildSizing.TopBottomSpacing = 10 ClientHeight = 187 ClientWidth = 104 ParentFont = False TabOrder = 0 object lblVersion: TLabel AnchorSideLeft.Control = pnlVersionInfos AnchorSideTop.Control = pnlVersionInfos Left = 0 Height = 15 Top = 10 Width = 38 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Version' ParentColor = False ParentFont = False end object lblRevision: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblVersion AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 29 Width = 44 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Revision' ParentColor = False ParentFont = False end object lblCommit: TLabel AnchorSideTop.Control = lblRevision AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 48 Width = 44 BorderSpacing.Top = 4 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Commit' ParentColor = False end object lblBuild: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblCommit AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 67 Width = 27 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Build' ParentColor = False ParentFont = False end object lblLazarusVer: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblBuild AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 86 Width = 39 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Lazarus' ParentColor = False ParentFont = False end object lblFreePascalVer: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblLazarusVer AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 105 Width = 58 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Free Pascal' ParentColor = False ParentFont = False end object lblPlatform: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblFreePascalVer AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 124 Width = 46 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Platform' ParentColor = False ParentFont = False end object lblOperatingSystem: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblPlatform AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 143 Width = 94 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'Operating System' ParentColor = False ParentFont = False end object lblWidgetsetVer: TLabel AnchorSideLeft.Control = lblVersion AnchorSideTop.Control = lblOperatingSystem AnchorSideTop.Side = asrBottom Left = 0 Height = 15 Top = 162 Width = 69 BorderSpacing.Top = 4 BorderSpacing.Right = 10 BorderSpacing.CellAlignHorizontal = ccaLeftTop Caption = 'WidgetsetVer' ParentColor = False ParentFont = False end end object imgLogo: TImage AnchorSideLeft.Control = pnlInfo AnchorSideTop.Control = pnlInfo AnchorSideRight.Control = pnlInfo AnchorSideRight.Side = asrBottom Left = 66 Height = 64 Top = 26 Width = 64 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 62 BorderSpacing.Top = 22 BorderSpacing.Right = 62 Center = True Picture.Data = { 1754506F727461626C654E6574776F726B47726170686963D610000089504E47 0D0A1A0A0000000D4948445200000040000000400806000000AA6971DE000000 0970485973000013AF000013AF0163E68EC30000001974455874536F66747761 7265007777772E696E6B73636170652E6F72679BEE3C1A000010634944415478 9CED9B79901F4775C73F6FAEDFB99776B52BAD2DAD8D2C5F088BD896B108B688 8B0470C58194A99429822109458070958D2988932A02A6A89439420C011C0713 A8C4260125E13038408C1593C3088365CB8714C992AD952CEDFDDBDF3DD3FDF2 C7CCFCF4DB43BBABDD35B8125ED5ECFC76A6FB75BF6FBF7EFD5ECF6BF825FDFF 2639D58B7B7F6353BF35FCB68B7D998A9CA18A6754C18255050503A805551BFF 56C5C6AF500BD66AEBBD45514D9EA34449216B897929287179AB8A85989749EA ABB6BD074BF2DCC4FC503036EEBB5145AD4691B1C30DB50FB8C6DF795BB93CB2 2400765F72893FBD76E2532ADE1B7BBABA0BF942D195A4582AB85A4D3A10FF51 55688191084A0C46DC5B8D416903416DFC3F8930315F1BD7C1C6E514B0F1BDD5 9E8DDB8BEB26F56D1B78D07ADE88229E9D98320726262B4D6BBEDC9CACDD703B 84A704E09E579F93C93BEE7F7477F76C5DDBD7EFBA9EAB204967B4EDAE2D015A A39A76CA265AD02ADF5627014FD1B69157D15490F672ED3C12A16D0232AA49D9 A44C0A70AB6CAC15621557958C55F61C3D66F68D8E3E2C53B597DE068D5466A7 1D80A2E7FEDDDADEB55B07D6AD7383C057115960923CFF498987BB24C2858383 EE85FD035BB5A7F895F6322D0076FDD6791705BEFFAA356B7B5DCFF3F4E7DDD9 E79A2AC0F9EBFADD9CE75FFDD69EC28BD2E72900629CCC0DDD3D7D791547436B 89AC1259C524EA16AB788CEAF395D2FEA553C86ADCFFF49AB6CA796BFB0A819F B99144B7BDE4875F6D345F5E735C31F550554112C32622382A88802B820BC433 439E1760A4425B558C85C8248387C51AC5A8C5D89306BB98CFD268863B001F08 3D40EEBFFFFEDB326347078362012F08926156A2CA34CDC951EA4F3D49F3F0FF E0DB888C2304AE832F0E9E1303F18B3014E9481B552263695A4BC3581A91C178 011D176CA1EFFC17925FDB4FA6B32B19AC78ADEC2895CEF8DDB3CEBE6DC78E1D 6FF7003CCFBBB6B0798BBFA6AF8F5C2E37AF34AA4A657C8CD281C774F4DEAFE3 8C0C93F75DB2AE8B2F0E223F3F109458F0A6B5D42343358CF0360CB1F977DEC0 C00B2FA2A3AFEF94FDA9D56A644747FD52A9742D1003B01412118ABD7D147BAF 94F5DBAEA03236C2F03DFFA0D30FDE47D1F3C9780EBE2B33979555A654D59BC6 528D22CA61C4DAAB5EC9B6EBDE4867FFC0B20661C900B4938850ECEBE7BCEBDF 29956B5ECFC1BFFD4BADECDF4B47C623E73C37DAA080B14ADD18CACD90EC8B2E E6AAF7DC44714DEF8AF82E0B80762AF4F4B2E53D1F92137B7EA2CFDCFE31BA5C 879CE7E139AB07820291B554224329522EFAE047D870E965AB02F4AA68AC8830 B0F552B9F0A37748A9D84BA919D234B1FFBE52B2AA84D6321D46347A07F8B53B FE9E8DDB5EB222E113CFD4C22A019052BEBB878B3EF469696E3887E9664898B8 A8CBA578E4957218618736B1E3139FA3D0DDB3B4BA895B6DAD9D711963D2BB81 550600C00F326CB9E12352EBDF40B919121ABB2C1052B52F4711E6CCB3B9E2A3 9F22C8665BEFDB3560B6B0C698D6FFB39FB78131038086908497D660AD694578 CB21CFF7B9E8FD1F934AA19B6A14614E53135283578D0C8DAE35BCF4C3B7E2B8 EE0C61A228C218D3BAB78D2CAA3AE37F6B0C61B349D46C629A4D6C1401948196 1793FDA7579E7B7470C3C66E713DB556314671FB06710737D275C99574BEE07C C9168AA705C4F4C871F6DEFC365D1378E45C27F61E97100D1AAB5443C35833E2 B24FDE4EE7C0FA189834EC56454466FC9FDE637F659C138FFC8C23BBEEA7FACC D3948F0EE320A04A9708DFDB7F60F2CEA9F22050F712C09B9D8167FBF3595CDF 8BE36BAB44B531A2FDA3541FDBCD6818A95C70311B5FF71629ACE95B12001D6B 0738E3FA7732FAE5CFE0657CFC25AC0CAD791F459CF5E67750E8EB2799AE33C8 5A3B437880C9679EE6913B3E4769CFC3048EE02364816C2668F9CC5D0219110B 34014D9741E3BB42D677F17C2F0E268CC5AA83058CA7140297DA813D3CF5676F D7DC8E6B38FB356F10C775E70A306B54062FDF21C7BEF375AD8F1FC7F5177794 ACC66BBDF60FB2F1CAAB5AA33A9B77BB06448D060F7FF10B8CDDF73D72E2D013 F8B82238C97B9B6EAEA812D05AFB671A41997539223822B82278AE43CE73E9CA F8F4E533D807BECD639FFA536DD4AA8B1A1F0586AEFF232987D1A2065181D05A 2AA1E19CDF7B0788CC305CEDBCD3E7E5B1517E74F3FB98DEF503BA7D9F82EF91 755C5C27EEFF6CB966EBE09256811410D771C8FB2EDD599FFCD1833C76CB7BB5 5E29CF5E5EE680D13DB4095D3F446311DF2075736570033D9BCE9D97673B20F5 A929FEFBE6F7E10C3F4D87EF91755D5C114E671FE7B496C11488C075E8C8F874 D4A6D87FC7AD1A369BF3AEB52D0B6D2D03575F2BB5C8109D6245482D7F2D320C FEE6B5F3ADDB335680B05E67F7ADB790999EA4E87B04E29C96E0CB02A0554904 DF118A818777F07186EFFFAEB67778F648596BE9DEFC42EA2A44890ACF0120F1 F81A38ACB9E045F33A30E9A5AAECDBF955F4D0010A9E9744A3CB9164058ED049 4DF098BAE7ABD44B5373E66AFBC83941407EEB36423BBF1D88E7BF52DC7A294E 90990362FBFC2F1F3FC6F17BBF49C177F11D59B6F02B0200621032AE4B4194A3 DFFF173D9573925EB9CD174A1A23B48390C6F7A1B514365F30EFC8B7F37EEA1B 3B298810AC42E4B9220004701D21E7B9941FDC8509C3793520BDF2679E45D3C6 8ECE6CB2C906477168D3BCF33EE5699A4D2677FF2719D7890DDE4A0460156201 4704DF75C88475A60EED5FD0170FBAD6101A1B7FB969B303E917A5D05AFCEE9E 05A7D2E8DE3D045184BF4AFB0E2BDE0F00F01C21E33A940F3EA9858D9B049823 A088204180143B50DB98C3C3AAE2143B7132D996E7379FB19CDAF704BE138FFE AAF47DA50C0470105C47A84F8CB4466EB6AFDE122657C096EB73F85855245B68 B9B8A7A2E6D4049E7372AD5FE98EC3AA6800124F857062AC0500CC1D415545FC 8039036B0CA65EC7E6E7FAFCB3A97AE800C1D123B89E87E37A88E781E723AE8F 93C99C76D7570780843431760B910D9B98D2048D6613AD5509EB754C18528D94 2673638BD964AA551A1363B802927C8CB536FD200BE20538D91C4E368B9B2FE0 E5F2E09C9AEFEA009084B26E67D7A2451B870FD01819C611109DA925B65A5DB4 7ED0DB474822EC9C7E28A65127AAD7E3A536F13A9D4C0EAFD841D0D505B342FA 1503107FC18E973629742E5ADE94A7E65DBA1CC096A716AD1FF4AEA5AE27BF08 2DDE4125AA56092B15AACF1EC3F53C8C755B6ABA2A5B629155EA8D3AD9C1A105 4D73549986E9A9791B15013B394E54292FD856F796AD849AC4B2CB208D22D446 2DEC5606802A616982CAD307983E364C71F396058B579F39842F12ABFFAC772E E0895079E6D0823CFA2FB98C289325D2956DB8A6B43C005431D393D40FEDA336 7C984AB98CB7F5729C2058B05AF9F13DF88EE0CEA327AE08BE03938FFE6CE10E 0719BAB75F4943D3B49A95D1E901602D66EC388D838F111E7B1AD368D0B04A59 85B5AF79E3A29E4975EF4FD497D86F682F9C6E54F822941EDEBD6837365DFF16 EA8E43C8CAB5606900A862A6C6691E7A8268EC386A4CE2BA2AE5C8125C7135D9 75672EC8A239394EF3893D04327FF4E608F802F5471FA23939B120AFE28621FA 5EF55AAA16C2156AC1A200D8CA34E1D3FB884E1C41E3EDE4587855CAC6521B18 A2FF757FB0E8E88F3DF07DB258BC05362D3C81AC5A9EBDEFDE453B7EFE1FBE0B 1D7A01358D33CE960BC229015013119D384274F410DA8C7DF724498BA655A643 CB445064DD3B3F2C6E36B760236A224AF7EED49C23A78CE0047011B28E70E25B FF889A68419E5EBEC0C51FFD24D58E2E2AAA2D4D385D20E605C04E8D111EDE87 2DC5AA980A6E54A919CB546899EA59C7C04D9F90A06F60D146467EF85DFC8913 044EBC029CB233028180377A9C63F7FDEBA27CF3EB07D9F6E9BF261ADC485995 BA26E9742C1D8816000AD828223A769868E4283699E7469375DE584AA165B469 A85EB08DF51FF8B464D76F58B481A85A66FC6B776AC115FC45E277215E0AF38E 30FCE5CF13562A8BF2EF183A9BCB3FFF2532DBAF60CA2A15255E21980946FBD5 4EA993ECBE61D39A9BB2532772A6D9A06995A6551A261EF17268990C2D9581B3 295EFF3E5973F5EB65B1252FA5E1AF7C56FDFD7B28BAB1FAA73D483D60E564B2 51DA3901C25A9572B942EFB6972EDA869BC970C62B5E4561CB56460E1EA03C36 4AA48A49073001C400017000A7FA50643F49F2614480A054ABDB11C7E2781E56 21B2600B5D68773FFE792FA678D176C96E3C674942A734FEE02E1AF77F9B1ED7 C19399429E8ADAB560FC3B3B39F12BDBE8DF7EE592DA1BD87639FD97BE84C97D 4F7074D70F19F9AF1F517BF6188DD1712449AC74804622335017C0B9FBEEBBBF D953CCBFBAA7B35332994C2B809079BEFC2C95AACF3CC5F02DEFD5EEB04A4E04 8759599F49046754A595DD990430E9125B892CA56C812D1FBF9DE2C6B396DD17 1B454449A0D56C34182F9574BA5EFFCE75D75D778D03608C29E2674472059C7C 11375F5C91F0CDB1130C7FFC83DA1956C9269EDFE9ECDF08E00AE41CA150ABF0 E8CDEFA536727CD9FD713C8FA0B393A0B313AFA3032F9713634C119E83FC80C6 F1A31CF9F39BB4737A8CA21B7F3F58CEE6553C1520EF08D9F1133C7CE3DB281F 39BCDADD5D5D00A6F73EC4F02DEFD2E2F8313A3C27DEBA5A01BFD83D86822364 479FE56737BC95D19FFE78B5BA0BAC1200360C39BEF34E1DFF8B3FD69E46990E CFC177562765AE1D8462798AC73FF86EF6DDF9056C182E5A7729B4E20D91E947 7ECCF85D7FA5C1E8517A3D212312873A2BCC0F6AA7743A14447051C6EEFA2223 BBBECFE677DC48FFB6CB57C47B79005843E9E107297DF76E750F3F49B713E716 F8719E4D6B7F6E3529FE300BD944B36AC38779FC03EFE6C0055B18BAEE4DACDF FEB26519EE250360EA55AAFB1EA5BE77B7361EDA45A652A2DB814CE0B632AE9F 2BE1538AB7E06377D949F60F1A8F3FC2937F72234F74ADA1EFAA5FA7FFB2EDF4 BDF8E278337409E401D4EBF5BBAA0F7CEB52CF957C2DF05AC72F4CB58C4E8D63 4F0CA363CF12584BDE113A05FCC0C5174D322F92BDFFE748F0D9946A4346E28F 32BE42581AA7B4F36E46BE7617A1B8F8EB07C96D1822E8EDC32F76A089390E8C E5B048B577FBAFDE95F212C0FFC62BCEDEBBCE89CE0982405BD14F5A40C14171 547013A1D31DDDF4F84CEBB84B7A642675784EF57B014768CEEF567D6D9D4BB2 6DEDDAA44DAB4A686217384C9E1BD5245D3EE6D109FC086FFF97EAE116927479 05C2BCE3FC20E7BB9BBAFC58D1D2465049CE012927CF2969BB2FFF0BA5564A4F F2BF2FB15AFB809524204AEE1E30AD0E3EFC1BF1691A4DEBA9EFE9674BD62DAB 31E2398227F1E54AAC6EE946E6EA6500AF7E42F59C3C27E2682FBD77014FB9CE B4F5E4332463D75AAA77DC73F011A3FAED89081385E1CFFF04C4734C9DC04171 A3BA956FFC4DB9F968FA7C86AF5216E7CD13D6F9E96853C3B0D114350B7FA87C BE930364811EE0A038E1219187C66ACDDF6F2F3367A4775F72893FB566E25641 DFD4E950CCAAF544ED496304ADD3A369EE9DD1C438B41F60D4F4A0651C94A7B6 A375A6D040726E1293FC5063139E497B4A62F45223462BD33435B8A95D6A378A 24A731EBAA8C5A273A02E5267267FF74E3FD1F8268410052FAE6CBCFEDF39DF0 B5225C61D59E292A9E898F681225C2C6C765693BD498E4F0A5C6B2758832CE0B B26DC244C9014843DC5F63419313A3D628B605561B9FD6FBF424699C72DB3A3A 9B5864632D6A3532702454FE3DB4FE3FDF3E3D3DBA1C2DFA25FD5FA7FF05C879 747F48E5EE350000000049454E44AE426082 } Proportional = True end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fstartingsplash.lrj������������������������������������������������������������0000644�0001750�0000144�00000003105�14743153644�017321� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":185879090,"name":"tfrmstartingsplash.caption","sourcebytes":[68,111,117,98,108,101,32,67,111,109,109,97,110,100,101,114],"value":"Double Commander"}, {"hash":185879090,"name":"tfrmstartingsplash.lbltitle.caption","sourcebytes":[68,111,117,98,108,101,32,67,111,109,109,97,110,100,101,114],"value":"Double Commander"}, {"hash":214540302,"name":"tfrmstartingsplash.lblversion.caption","sourcebytes":[86,101,114,115,105,111,110],"value":"Version"}, {"hash":214997982,"name":"tfrmstartingsplash.lblrevision.caption","sourcebytes":[82,101,118,105,115,105,111,110],"value":"Revision"}, {"hash":4833316,"name":"tfrmstartingsplash.lblbuild.caption","sourcebytes":[66,117,105,108,100],"value":"Build"}, {"hash":43026835,"name":"tfrmstartingsplash.lbllazarusver.caption","sourcebytes":[76,97,122,97,114,117,115],"value":"Lazarus"}, {"hash":86315532,"name":"tfrmstartingsplash.lblfreepascalver.caption","sourcebytes":[70,114,101,101,32,80,97,115,99,97,108],"value":"Free Pascal"}, {"hash":42652669,"name":"tfrmstartingsplash.lblplatform.caption","sourcebytes":[80,108,97,116,102,111,114,109],"value":"Platform"}, {"hash":222234861,"name":"tfrmstartingsplash.lbloperatingsystem.caption","sourcebytes":[79,112,101,114,97,116,105,110,103,32,83,121,115,116,101,109],"value":"Operating System"}, {"hash":239284482,"name":"tfrmstartingsplash.lblwidgetsetver.caption","sourcebytes":[87,105,100,103,101,116,115,101,116,86,101,114],"value":"WidgetsetVer"}, {"hash":78005252,"name":"tfrmstartingsplash.lblcommit.caption","sourcebytes":[67,111,109,109,105,116],"value":"Commit"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fstartingsplash.pas������������������������������������������������������������0000644�0001750�0000144�00000003501�14743153644�017315� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fstartingsplash; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls; type { TfrmStartingSplash } TfrmStartingSplash = class(TForm) imgLogo: TImage; lblBuild: TLabel; lblCommit: TLabel; lblFreePascalVer: TLabel; lblLazarusVer: TLabel; lblOperatingSystem: TLabel; lblPlatform: TLabel; lblRevision: TLabel; lblTitle: TLabel; lblVersion: TLabel; lblWidgetsetVer: TLabel; pnlVersionInfos: TPanel; pnlInfo: TPanel; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormHide(Sender: TObject); private { private declarations } public { public declarations } end; var frmStartingSplash: TfrmStartingSplash; implementation {$R *.lfm} uses uDCVersion; { TfrmStartingSplash } procedure TfrmStartingSplash.FormCreate(Sender: TObject); begin lblVersion.Caption := lblVersion.Caption + #32 + dcVersion; lblRevision.Caption := lblRevision.Caption + #32 + dcRevision; lblCommit.Caption := lblCommit.Caption + #32 + dcCommit; lblBuild.Caption := lblBuild.Caption + #32 + dcBuildDate; lblLazarusVer.Caption := lblLazarusVer.Caption + #32 + lazVersion; lblFreePascalVer.Caption := lblFreePascalVer.Caption + #32 + fpcVersion; lblPlatform.Caption := TargetCPU + '-' + TargetOS + '-' + TargetWS; lblOperatingSystem.Caption := OSVersion; lblWidgetsetVer.Caption := WSVersion; end; procedure TfrmStartingSplash.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:= caFree; end; procedure TfrmStartingSplash.FormHide(Sender: TObject); begin close(); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsymlink.lfm�������������������������������������������������������������������0000644�0001750�0000144�00000005766�14743153644�015747� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSymLink: TfrmSymLink Left = 320 Height = 177 Top = 320 Width = 512 ActiveControl = edtLinkToCreate AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Create symbolic link' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ClientHeight = 177 ClientWidth = 512 KeyPreview = True OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '1.8.4.0' object lblExistingFile: TLabel AnchorSideLeft.Control = edtExistingFile AnchorSideTop.Control = edtLinkToCreate AnchorSideTop.Side = asrBottom Left = 6 Height = 16 Top = 59 Width = 240 BorderSpacing.Top = 6 Caption = '&Destination that the link will point to' FocusControl = edtExistingFile ParentColor = False end object lblLinkToCreate: TLabel AnchorSideLeft.Control = edtLinkToCreate AnchorSideTop.Control = Owner Left = 6 Height = 16 Top = 6 Width = 69 Caption = '&Link name' FocusControl = edtLinkToCreate ParentColor = False end object edtExistingFile: TEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblExistingFile AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 81 Width = 500 BorderSpacing.Top = 6 Constraints.MinWidth = 400 TabOrder = 1 end object edtLinkToCreate: TEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = lblLinkToCreate AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 25 Top = 28 Width = 500 BorderSpacing.Top = 6 Constraints.MinWidth = 400 TabOrder = 0 end object chkUseRelativePath: TCheckBox AnchorSideLeft.Control = edtExistingFile AnchorSideTop.Control = edtExistingFile AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 6 Height = 24 Top = 118 Width = 219 BorderSpacing.Top = 6 Caption = 'Use &relative path when possible' TabOrder = 2 end object btnOK: TBitBtn AnchorSideTop.Control = chkUseRelativePath AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnCancel Left = 390 Height = 33 Top = 148 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 6 BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 2 Caption = '&OK' Constraints.MinWidth = 100 Default = True Kind = bkOK ModalResult = 1 OnClick = btnOKClick TabOrder = 3 end object btnCancel: TBitBtn AnchorSideTop.Control = chkUseRelativePath AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtExistingFile AnchorSideRight.Side = asrBottom Left = 496 Height = 33 Top = 148 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Top = 6 BorderSpacing.InnerBorder = 2 Cancel = True Caption = '&Cancel' Constraints.MinWidth = 100 Kind = bkCancel ModalResult = 2 TabOrder = 4 end end ����������doublecmd-1.1.22/src/fsymlink.lrj�������������������������������������������������������������������0000644�0001750�0000144�00000002064�14743153644�015744� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":219027899,"name":"tfrmsymlink.caption","sourcebytes":[67,114,101,97,116,101,32,115,121,109,98,111,108,105,99,32,108,105,110,107],"value":"Create symbolic link"}, {"hash":37813087,"name":"tfrmsymlink.lblexistingfile.caption","sourcebytes":[38,68,101,115,116,105,110,97,116,105,111,110,32,116,104,97,116,32,116,104,101,32,108,105,110,107,32,119,105,108,108,32,112,111,105,110,116,32,116,111],"value":"&Destination that the link will point to"}, {"hash":81130805,"name":"tfrmsymlink.lbllinktocreate.caption","sourcebytes":[38,76,105,110,107,32,110,97,109,101],"value":"&Link name"}, {"hash":11067,"name":"tfrmsymlink.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmsymlink.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"}, {"hash":131237333,"name":"tfrmsymlink.chkuserelativepath.caption","sourcebytes":[85,115,101,32,38,114,101,108,97,116,105,118,101,32,112,97,116,104,32,119,104,101,110,32,112,111,115,115,105,98,108,101],"value":"Use &relative path when possible"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsymlink.pas�������������������������������������������������������������������0000644�0001750�0000144�00000005132�14743153644�015737� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fSymLink; interface uses SysUtils, Classes, Controls, Forms, StdCtrls, Buttons; type { TfrmSymLink } TfrmSymLink = class(TForm) chkUseRelativePath: TCheckBox; lblExistingFile: TLabel; lblLinkToCreate: TLabel; edtExistingFile: TEdit; edtLinkToCreate: TEdit; btnOK: TBitBtn; btnCancel: TBitBtn; procedure btnOKClick(Sender: TObject); procedure FormShow(Sender: TObject); private FCurrentPath: String; public constructor Create(TheOwner: TComponent; CurrentPath: String); reintroduce; end; function ShowSymLinkForm(TheOwner: TComponent; const sExistingFile, sLinkToCreate, CurrentPath: String): Boolean; implementation {$R *.lfm} uses LazFileUtils, uLng, uGlobs, uLog, uShowMsg, DCStrUtils, DCOSUtils, uAdministrator; function ShowSymLinkForm(TheOwner: TComponent; const sExistingFile, sLinkToCreate, CurrentPath: String): Boolean; begin with TfrmSymLink.Create(TheOwner, CurrentPath) do begin try edtLinkToCreate.Text := sLinkToCreate; edtExistingFile.Text := sExistingFile; Result:= (ShowModal = mrOK); finally Free; end; end; end; constructor TfrmSymLink.Create(TheOwner: TComponent; CurrentPath: String); begin inherited Create(TheOwner); FCurrentPath := CurrentPath; end; procedure TfrmSymLink.btnOKClick(Sender: TObject); var sSrc, sDst, Message: String; AElevate: TDuplicates = dupIgnore; begin sSrc:=edtExistingFile.Text; sDst:=edtLinkToCreate.Text; if CompareFilenames(sSrc, sDst) = 0 then Exit; sDst := GetAbsoluteFileName(FCurrentPath, sDst); if chkUseRelativePath.Checked then begin sSrc:= CreateRelativePath(sSrc, ExtractFileDir(sDst)); end; PushPop(AElevate); try if CreateSymbolicLinkUAC(sSrc, sDst) then begin // write log if (log_cp_mv_ln in gLogOptions) and (log_success in gLogOptions) then logWrite(Format(rsMsgLogSuccess+rsMsgLogSymLink,[sSrc+' -> '+sDst]), lmtSuccess); end else begin Message:= mbSysErrorMessage; // write log if (log_cp_mv_ln in gLogOptions) and (log_errors in gLogOptions) then logWrite(Format(rsMsgLogError+rsMsgLogSymLink,[sSrc+' -> '+sDst]), lmtError); // Standart error modal dialog MsgError(rsSymErrCreate + LineEnding + LineEnding + Message); end; finally PushPop(AElevate); end; end; procedure TfrmSymLink.FormShow(Sender: TObject); begin edtLinkToCreate.SelectAll; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsyncdirsdlg.lfm���������������������������������������������������������������0000644�0001750�0000144�00000056304�14743153644�016600� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSyncDirsDlg: TfrmSyncDirsDlg Left = 553 Height = 445 Top = 163 Width = 763 Caption = 'Synchronize directories' ClientHeight = 445 ClientWidth = 763 KeyPreview = True OnClose = FormClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnKeyDown = FormKeyDown OnResize = FormResize Position = poScreenCenter SessionProperties = 'Height;Left;Top;Width;WindowState' ShowInTaskBar = stAlways LCLVersion = '2.2.0.4' object edPath1: TDirectoryEdit AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = pnlFilter Left = 3 Height = 23 Top = 3 Width = 307 OnAcceptDirectory = edPath1AcceptDirectory ShowHidden = False ButtonWidth = 18 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Around = 3 MaxLength = 0 ParentFont = False TabOrder = 1 end object pnlFilter: TPanel AnchorSideLeft.Control = Owner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = Owner AnchorSideRight.Control = edPath2 Left = 313 Height = 26 Top = 0 Width = 137 AutoSize = True BevelOuter = bvNone ClientHeight = 26 ClientWidth = 137 TabOrder = 2 object cbExtFilter: TComboBox Left = 0 Height = 23 Top = 3 Width = 111 BorderSpacing.Top = 3 ItemHeight = 15 ItemIndex = 0 Items.Strings = ( '*' ) ParentFont = False TabOrder = 0 Text = '*' end object btnSearchTemplate: TSpeedButton AnchorSideLeft.Control = cbExtFilter AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbExtFilter AnchorSideBottom.Control = cbExtFilter AnchorSideBottom.Side = asrBottom Left = 114 Height = 23 Hint = 'Template...' Top = 3 Width = 23 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 3 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000330000 0033000000330000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000214F6B83FF4966 85FF5191D9FF0000003300000000000000000000000000000000000000000000 00000000000000000000000000000000000000000021B07836B75485ABFF7EA7 B8FF8FD5FFFF356A9CFF00000033000000000000000000000000000000000000 000000000000000000000000000000000022A7753BB9D49849FF3CB4FFFFA3F1 FFFF9CE0FEFF109BFFFF306BA2FF000000330000000A00000000000000000000 0000000000000000000000000000A7763BBDE9C590FFDFAA5CFFC87F2EFF287B D2FF3FC7FFFF20ACFFFF83B1D8FF807873FF413F3D5B00000000000000000000 0000000000000000000000000000B57F3DFFFFF1D0FFDAA85BFFC28236FF0000 00002C7DCFFFB3DEF2FF938881FFC2C0BAFF797B71FF00000033000000000000 0000000000000000000000000021B37C3AFFFFFFFAFFD6A559FFBA803BFF0000 0020000000008E8780FFDAD7D3FF8A8C84FFA27F9BFF9969CCFF000000000000 00000000000000000021AA7A3EB6DEAF68FFF3CB8AFFEEC684FFD8AA65FFAC79 3AB50000002100000000858884FFE3B3E3FFCB96C7FFAE7DCEFF000000000000 000000000021A9783CB9EDC385FFF9D292FFF3CD8BFFEDC380FFE8BE7CFFDDB3 74FFAA783BB70000002100000000C28BDCFFBF8AD4FF00000000000000000000 0021A77639B9EFCA96FFF8D59CFFF6CF8DFFEEC684FFE7BB77FFE0B26BFFE1BB 80FFDBB57FFFA87637B70000002100000000000000000000000000000022BB8D 4DB9F0D3ABFFFADFB1FFF5CC88FFEEC480FFE8BC76FFE1B36CFFDBAA61FFD4A1 55FFE0BC89FFDCBD8FFFAA7831B8000000220000000000000000A67437BDFFED CAFFFFF1D8FFFBE4BCFFFFF1D9FFFEF4E4FFF6E7CCFFF5E4CAFFF6E9D6FFEFDD C1FFE3C597FFECDABDFFE4CCA6FFA77636BD0000000000000000B57E3AFFFFFA E8FFF5E3C5FFE3C798FFD8B070FFD19E50FFD8A14DFFDCA553FFD19D4AFFD2A7 63FFD5AF74FFDDC194FFE9D2B3FFB7813DFF0000000000000000B57E3AFFFFFF FFFFA16100FFB17616FFBF852BFFCB933DFFD9A24FFFDDA755FFCF9A43FFC48B 32FFB87E1FFFAA6C08FFF7EDE0FFB7813EFF0000000000000000B67F3DFFFFF9 E2FFEBC992FFF3DBB5FFF5E2C0FFF5E1C0FFF6E2BFFFF5DFBDFFEFD9B5FFECD3 AFFFE4C9A0FFD4AD73FFE4C9A1FFB88241FF0000000000000000B8834238D19E 58A9C99753E0C69351FFC69453FFC5914FFFC6975EFFC49356FFBF8B48FFBF8A 46FFBD8946FFBE8844E0BD873FA9BA8545380000000000000000 } OnClick = btnSearchTemplateClick end end object edPath2: TDirectoryEdit AnchorSideLeft.Control = pnlFilter AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 453 Height = 23 Top = 3 Width = 307 OnAcceptDirectory = edPath1AcceptDirectory ShowHidden = False ButtonWidth = 18 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Around = 3 MaxLength = 0 ParentFont = False TabOrder = 3 end object TopPanel: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = edPath1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 0 Height = 78 Top = 29 Width = 763 Anchors = [akTop, akLeft, akRight] AutoSize = True ClientHeight = 78 ClientWidth = 763 ParentFont = False TabOrder = 0 object LeftPanel1: TPanel AnchorSideLeft.Control = TopPanel AnchorSideTop.Control = TopPanel Left = 1 Height = 68 Top = 1 Width = 95 AutoSize = True BevelOuter = bvNone ClientHeight = 68 ClientWidth = 95 ParentFont = False TabOrder = 0 object btnCompare: TButton AnchorSideLeft.Control = LeftPanel1 AnchorSideTop.Control = LeftPanel1 Left = 3 Height = 25 Top = 3 Width = 75 AutoSize = True BorderSpacing.Around = 3 Caption = 'Compare' Default = True OnClick = btnCompareClick ParentFont = False TabOrder = 0 end object chkOnlySelected: TCheckBox AnchorSideLeft.Control = LeftPanel1 AnchorSideTop.Control = btnCompare AnchorSideTop.Side = asrBottom Left = 3 Height = 19 Top = 31 Width = 89 BorderSpacing.Around = 3 Caption = 'only selected' Enabled = False ParentFont = False TabOrder = 1 end object Label1: TLabel AnchorSideLeft.Control = chkOnlySelected AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = chkOnlySelected AnchorSideTop.Side = asrBottom Left = 1 Height = 15 Top = 53 Width = 93 Caption = '(in main window)' Enabled = False ParentFont = False end end object LeftPanel2: TPanel AnchorSideLeft.Control = LeftPanel1 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TopPanel Left = 101 Height = 76 Top = 1 Width = 82 AutoSize = True BorderSpacing.Left = 5 BevelOuter = bvNone ClientHeight = 76 ClientWidth = 82 ParentFont = False TabOrder = 1 object chkAsymmetric: TCheckBox AnchorSideLeft.Control = LeftPanel2 AnchorSideTop.Control = LeftPanel2 Left = 0 Height = 19 Top = 0 Width = 82 Caption = 'asymmetric' Enabled = False ParentFont = False TabOrder = 0 end object chkSubDirs: TCheckBox AnchorSideLeft.Control = LeftPanel2 AnchorSideTop.Control = chkAsymmetric AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 19 Width = 59 Caption = 'Subdirs' ParentFont = False TabOrder = 1 end object chkByContent: TCheckBox AnchorSideLeft.Control = LeftPanel2 AnchorSideTop.Control = chkSubDirs AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 38 Width = 77 Caption = 'by content' ParentFont = False TabOrder = 2 end object chkIgnoreDate: TCheckBox AnchorSideLeft.Control = LeftPanel2 AnchorSideTop.Control = chkByContent AnchorSideTop.Side = asrBottom Left = 0 Height = 19 Top = 57 Width = 80 Caption = 'ignore date' ParentFont = False TabOrder = 3 end end object GroupBox1: TGroupBox AnchorSideLeft.Control = LeftPanel2 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = TopPanel Left = 188 Height = 65 Top = 1 Width = 228 AutoSize = True BorderSpacing.Left = 5 Caption = 'Show:' ClientHeight = 45 ClientWidth = 198 ParentFont = False TabOrder = 2 object sbCopyRight: TSpeedButton AnchorSideLeft.Control = GroupBox1 AnchorSideTop.Control = GroupBox1 Left = 6 Height = 24 Top = 6 Width = 24 AllowAllUp = True BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = '>' Down = True GroupIndex = 1 OnClick = FilterSpeedButtonClick ParentFont = False end object sbEqual: TSpeedButton AnchorSideLeft.Control = sbCopyRight AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbCopyRight Left = 32 Height = 24 Top = 6 Width = 24 AllowAllUp = True BorderSpacing.Left = 2 Caption = '=' Down = True GroupIndex = 2 OnClick = FilterSpeedButtonClick ParentFont = False end object sbNotEqual: TSpeedButton AnchorSideLeft.Control = sbEqual AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbCopyRight Left = 58 Height = 24 Top = 6 Width = 24 AllowAllUp = True BorderSpacing.Left = 2 Caption = '!=' Down = True GroupIndex = 3 OnClick = FilterSpeedButtonClick ParentFont = False end object sbUnknown: TSpeedButton AnchorSideLeft.Control = sbNotEqual AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbCopyRight Left = 84 Height = 24 Top = 6 Width = 24 AllowAllUp = True BorderSpacing.Left = 2 Caption = '?' Down = True GroupIndex = 4 OnClick = FilterSpeedButtonClick ParentFont = False end object sbCopyLeft: TSpeedButton AnchorSideLeft.Control = sbUnknown AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbCopyRight Left = 110 Height = 24 Top = 6 Width = 24 AllowAllUp = True BorderSpacing.Left = 2 Caption = '<' Down = True GroupIndex = 5 OnClick = FilterSpeedButtonClick ParentFont = False end object sbDuplicates: TSpeedButton AnchorSideLeft.Control = sbCopyLeft AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = GroupBox1 Left = 138 Height = 18 Top = 0 Width = 80 AllowAllUp = True BorderSpacing.Left = 4 BorderSpacing.Right = 6 Caption = 'duplicates' Down = True GroupIndex = 6 OnClick = FilterSpeedButtonClick ParentFont = False end object sbSingles: TSpeedButton AnchorSideLeft.Control = sbCopyLeft AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = sbDuplicates AnchorSideTop.Side = asrBottom Left = 138 Height = 18 Top = 21 Width = 80 AllowAllUp = True BorderSpacing.Left = 4 BorderSpacing.Top = 3 BorderSpacing.Bottom = 6 Caption = 'singles' Down = True GroupIndex = 7 OnClick = FilterSpeedButtonClick ParentFont = False end end object btnSynchronize: TButton AnchorSideTop.Control = TopPanel AnchorSideRight.Control = TopPanel AnchorSideRight.Side = asrBottom Left = 666 Height = 25 Top = 7 Width = 90 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Around = 6 Caption = 'Synchronize' Enabled = False OnClick = btnSynchronizeClick ParentFont = False TabOrder = 3 end object btnClose: TButton AnchorSideLeft.Control = btnSynchronize AnchorSideTop.Control = btnSynchronize AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnSynchronize AnchorSideRight.Side = asrBottom Left = 666 Height = 25 Top = 38 Width = 90 Anchors = [akTop, akLeft, akRight] AutoSize = True Cancel = True Caption = 'Close' OnClick = btnCloseClick ParentFont = False TabOrder = 4 end end object StatusBar1: TStatusBar Left = 0 Height = 23 Top = 422 Width = 763 Panels = < item Text = 'Please press "Compare" to start' Width = 50 end> ParentFont = False SimplePanel = False end object HeaderDG: TDrawGrid AnchorSideLeft.Control = Owner AnchorSideTop.Control = TopPanel AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 0 Height = 20 Top = 107 Width = 763 Anchors = [akTop, akLeft, akRight] AutoFillColumns = True BorderStyle = bsNone ColCount = 7 Columns = < item MinSize = 10 MaxSize = 200 SizePriority = 0 Title.Caption = 'Name' Width = 250 end item MinSize = 10 MaxSize = 200 SizePriority = 0 Title.Caption = 'Size' Width = 150 end item MinSize = 10 MaxSize = 200 SizePriority = 0 Title.Caption = 'Date' Width = 170 end item MinSize = 10 MaxSize = 200 SizePriority = 0 Title.Caption = '<=>' Width = 30 end item MinSize = 10 MaxSize = 200 SizePriority = 0 Title.Caption = 'Date' Width = 170 end item MinSize = 10 MaxSize = 200 SizePriority = 0 Title.Caption = 'Size' Width = 120 end item MinSize = 10 MaxSize = 200 Title.Caption = 'Name' Width = 0 end> ExtendedSelect = False FixedCols = 0 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goSmoothScroll, goHeaderPushedLook] ParentFont = False RowCount = 1 ScrollBars = ssNone TabOrder = 5 TabStop = False OnHeaderClick = HeaderDGHeaderClick OnHeaderSizing = HeaderDGHeaderSizing ColWidths = ( 250 150 170 30 170 120 0 ) end object MainDrawGrid: TDrawGrid AnchorSideLeft.Control = Owner AnchorSideTop.Control = HeaderDG AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = StatusBar1 Left = 0 Height = 295 Top = 127 Width = 763 Anchors = [akTop, akLeft, akRight, akBottom] AutoFillColumns = True ColCount = 0 ExtendedSelect = False FixedCols = 0 FixedRows = 0 MouseWheelOption = mwGrid Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSelect, goThumbTracking, goSmoothScroll, goHeaderPushedLook, goDontScrollPartCell, goRowHighlight] ParentFont = False PopupMenu = pmGridMenu RangeSelectMode = rsmMulti RowCount = 0 ScrollBars = ssAutoVertical TabOrder = 6 OnDblClick = MainDrawGridDblClick OnDrawCell = MainDrawGridDrawCell OnKeyDown = MainDrawGridKeyDown OnMouseDown = MainDrawGridMouseDown end object pnlProgress: TPanel AnchorSideLeft.Control = Owner AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = Owner AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 253 Height = 154 Top = 145 Width = 256 AutoSize = True ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ChildSizing.VerticalSpacing = 8 ClientHeight = 154 ClientWidth = 256 Constraints.MinWidth = 240 ParentBackground = False ParentColor = False ParentFont = False TabOrder = 7 Visible = False object pnlCopyProgress: TPanel AnchorSideLeft.Control = pnlProgress AnchorSideTop.Control = pnlProgress Left = 9 Height = 47 Top = 9 Width = 238 AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ChildSizing.VerticalSpacing = 8 ClientHeight = 47 ClientWidth = 238 TabOrder = 0 object lblProgress: TLabel AnchorSideLeft.Control = pnlCopyProgress AnchorSideTop.Control = pnlCopyProgress AnchorSideRight.Control = pnlCopyProgress AnchorSideRight.Side = asrBottom Left = 8 Height = 1 Top = 8 Width = 222 Alignment = taCenter Anchors = [akTop, akLeft, akRight] ParentFont = False end object ProgressBar: TKASProgressBar AnchorSideLeft.Control = pnlCopyProgress AnchorSideTop.Control = lblProgress AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlCopyProgress AnchorSideRight.Side = asrBottom Left = 8 Height = 22 Top = 17 Width = 222 Max = 222 ParentFont = False TabOrder = 0 BarShowText = True end end object pnlDeleteProgress: TPanel AnchorSideLeft.Control = pnlCopyProgress AnchorSideTop.Control = pnlCopyProgress AnchorSideTop.Side = asrBottom Left = 9 Height = 47 Top = 64 Width = 238 AutoSize = True BevelOuter = bvNone ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 ChildSizing.VerticalSpacing = 8 ClientHeight = 47 ClientWidth = 238 TabOrder = 1 object lblProgressDelete: TLabel AnchorSideLeft.Control = pnlDeleteProgress AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlDeleteProgress AnchorSideRight.Side = asrBottom Left = 8 Height = 1 Top = 8 Width = 222 Alignment = taCenter Anchors = [akTop, akLeft, akRight] ParentFont = False end object ProgressBarDelete: TKASProgressBar AnchorSideLeft.Control = pnlDeleteProgress AnchorSideTop.Control = lblProgressDelete AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlDeleteProgress AnchorSideRight.Side = asrBottom Left = 8 Height = 22 Top = 17 Width = 222 Max = 222 ParentFont = False TabOrder = 0 BarShowText = True end end object btnAbort: TBitBtn AnchorSideLeft.Control = pnlProgress AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = pnlDeleteProgress AnchorSideTop.Side = asrBottom Left = 79 Height = 26 Top = 119 Width = 98 AutoSize = True DefaultCaption = True Kind = bkAbort ModalResult = 3 OnClick = btnAbortClick ParentFont = False TabOrder = 2 end end object ImageList1: TImageList Left = 56 Top = 152 Bitmap = { 4C7A0900000010000000100000002D0100000000000078DAED98CD0DC2300C85 B3042766415C198D0B53E5CA260C012A52A580FC13FBD5A5348E64A9B2F225B6 9BD7BAADB53E2B68A51497B5BC6748FCA15C3FCCC27F33DC1A14CFCDA5FC113C 3710DE927F2FDBC34BEC1A3C72FED68C1FB11CDB19966767049FF98F37EA4EDF FF517C298FB779F896E5F8798E66517C4FDC96FA71EC96F39762EE8D7FCDF3FB 6B1B49FF16FE7E39BBF989F5F233CB99C46BACC6A3FB2F91FF12F5FFA7F397FA DF367FBA1D619E5A83E2E7B99CA17CBB46C4FE68FE11F54FFD8FA37FEEAC79F4 23F9A4F87BB4A3E5AFB1913C123F5A3FF4FEA5FEF7AE7FADFFA5FB46AA1FD5FA 67C9E7E99F3DDF0F521F1DC523F1A3F5E3F6B2D43FF53FEEFB7FBAA496A3FC12 DFCEA57CF2FF27DA2CF96B6C248FC48FD60FBD7FA9FFFCFE4F3EF951F4FF023D 7775DA } end object pmGridMenu: TPopupMenu OnPopup = pmGridMenuPopup Left = 121 Top = 217 object miSelectCopyDefault: TMenuItem Action = actSelectCopyDefault end object miSelectClear: TMenuItem Action = actSelectClear end object miSelectCopyLeftToRight: TMenuItem Action = actSelectCopyLeftToRight end object miSelectCopyRightToLeft: TMenuItem Action = actSelectCopyRightToLeft end object miSelectCopyReverse: TMenuItem Action = actSelectCopyReverse end object miSeparator1: TMenuItem Caption = '-' end object MenuItemViewLeft: TMenuItem Caption = 'View left' ShortCut = 114 OnClick = MenuItemViewClick end object MenuItemViewRight: TMenuItem Caption = 'View right' ShortCut = 8306 OnClick = MenuItemViewClick end object MenuItemCompare: TMenuItem Caption = 'Compare' ShortCut = 16498 OnClick = MainDrawGridDblClick end object miSeparator2: TMenuItem Caption = '-' end object miSelectDeleteLeft: TMenuItem Action = actSelectDeleteLeft end object miSelectDeleteRight: TMenuItem Action = actSelectDeleteRight end object miSelectDeleteBoth: TMenuItem Action = actSelectDeleteBoth end object miSeparator3: TMenuItem Caption = '-' end object miDeleteLeft: TMenuItem Action = actDeleteLeft end object miDeleteRight: TMenuItem Action = actDeleteRight end object miDeleteBoth: TMenuItem Action = actDeleteBoth end end object ActionList: TActionList Left = 528 Top = 192 object actSelectCopyLeftToRight: TAction Caption = 'Select for copying -> (left to right)' OnExecute = actExecute end object actSelectCopyRightToLeft: TAction Caption = 'Select for copying <- (right to left)' OnExecute = actExecute end object actSelectCopyDefault: TAction Caption = 'Select for copying (default direction)' OnExecute = actExecute end object actSelectClear: TAction Caption = 'Remove selection' OnExecute = actExecute end object actSelectCopyReverse: TAction Caption = 'Reverse copy direction' OnExecute = actExecute end object actSelectDeleteLeft: TAction Caption = 'Select for deleting <- (left)' OnExecute = actExecute end object actSelectDeleteRight: TAction Caption = 'Select for deleting -> (right)' OnExecute = actExecute end object actSelectDeleteBoth: TAction Caption = 'Select for deleting <-> (both)' OnExecute = actExecute end object actDeleteLeft: TAction Caption = '<- Delete left' OnExecute = actExecute end object actDeleteRight: TAction Caption = '-> Delete right' OnExecute = actExecute end object actDeleteBoth: TAction Caption = 'Delete on both sides' OnExecute = actExecute end end object Timer: TTimer Enabled = False Interval = 200 OnTimer = TimerTimer Left = 123 Top = 297 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsyncdirsdlg.lrj���������������������������������������������������������������0000644�0001750�0000144�00000014406�14743153644�016606� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":36754147,"name":"tfrmsyncdirsdlg.caption","sourcebytes":[83,121,110,99,104,114,111,110,105,122,101,32,100,105,114,101,99,116,111,114,105,101,115],"value":"Synchronize directories"}, {"hash":42,"name":"tfrmsyncdirsdlg.cbextfilter.text","sourcebytes":[42],"value":"*"}, {"hash":47236478,"name":"tfrmsyncdirsdlg.btnsearchtemplate.hint","sourcebytes":[84,101,109,112,108,97,116,101,46,46,46],"value":"Template..."}, {"hash":174352581,"name":"tfrmsyncdirsdlg.btncompare.caption","sourcebytes":[67,111,109,112,97,114,101],"value":"Compare"}, {"hash":242752852,"name":"tfrmsyncdirsdlg.chkonlyselected.caption","sourcebytes":[111,110,108,121,32,115,101,108,101,99,116,101,100],"value":"only selected"}, {"hash":181520105,"name":"tfrmsyncdirsdlg.label1.caption","sourcebytes":[40,105,110,32,109,97,105,110,32,119,105,110,100,111,119,41],"value":"(in main window)"}, {"hash":70923251,"name":"tfrmsyncdirsdlg.chkasymmetric.caption","sourcebytes":[97,115,121,109,109,101,116,114,105,99],"value":"asymmetric"}, {"hash":179876035,"name":"tfrmsyncdirsdlg.chksubdirs.caption","sourcebytes":[83,117,98,100,105,114,115],"value":"Subdirs"}, {"hash":174272820,"name":"tfrmsyncdirsdlg.chkbycontent.caption","sourcebytes":[98,121,32,99,111,110,116,101,110,116],"value":"by content"}, {"hash":135876037,"name":"tfrmsyncdirsdlg.chkignoredate.caption","sourcebytes":[105,103,110,111,114,101,32,100,97,116,101],"value":"ignore date"}, {"hash":5895850,"name":"tfrmsyncdirsdlg.groupbox1.caption","sourcebytes":[83,104,111,119,58],"value":"Show:"}, {"hash":62,"name":"tfrmsyncdirsdlg.sbcopyright.caption","sourcebytes":[62],"value":">"}, {"hash":61,"name":"tfrmsyncdirsdlg.sbequal.caption","sourcebytes":[61],"value":"="}, {"hash":589,"name":"tfrmsyncdirsdlg.sbnotequal.caption","sourcebytes":[33,61],"value":"!="}, {"hash":60,"name":"tfrmsyncdirsdlg.sbcopyleft.caption","sourcebytes":[60],"value":"<"}, {"hash":50280115,"name":"tfrmsyncdirsdlg.sbduplicates.caption","sourcebytes":[100,117,112,108,105,99,97,116,101,115],"value":"duplicates"}, {"hash":168092339,"name":"tfrmsyncdirsdlg.sbsingles.caption","sourcebytes":[115,105,110,103,108,101,115],"value":"singles"}, {"hash":267343253,"name":"tfrmsyncdirsdlg.btnsynchronize.caption","sourcebytes":[83,121,110,99,104,114,111,110,105,122,101],"value":"Synchronize"}, {"hash":4863637,"name":"tfrmsyncdirsdlg.btnclose.caption","sourcebytes":[67,108,111,115,101],"value":"Close"}, {"hash":197576788,"name":"tfrmsyncdirsdlg.statusbar1.panels[0].text","sourcebytes":[80,108,101,97,115,101,32,112,114,101,115,115,32,34,67,111,109,112,97,114,101,34,32,116,111,32,115,116,97,114,116],"value":"Please press \"Compare\" to start"}, {"hash":346165,"name":"tfrmsyncdirsdlg.headerdg.columns[0].title.caption","sourcebytes":[78,97,109,101],"value":"Name"}, {"hash":368901,"name":"tfrmsyncdirsdlg.headerdg.columns[1].title.caption","sourcebytes":[83,105,122,101],"value":"Size"}, {"hash":305317,"name":"tfrmsyncdirsdlg.headerdg.columns[2].title.caption","sourcebytes":[68,97,116,101],"value":"Date"}, {"hash":16398,"name":"tfrmsyncdirsdlg.headerdg.columns[3].title.caption","sourcebytes":[60,61,62],"value":"<=>"}, {"hash":305317,"name":"tfrmsyncdirsdlg.headerdg.columns[4].title.caption","sourcebytes":[68,97,116,101],"value":"Date"}, {"hash":368901,"name":"tfrmsyncdirsdlg.headerdg.columns[5].title.caption","sourcebytes":[83,105,122,101],"value":"Size"}, {"hash":346165,"name":"tfrmsyncdirsdlg.headerdg.columns[6].title.caption","sourcebytes":[78,97,109,101],"value":"Name"}, {"hash":211253028,"name":"tfrmsyncdirsdlg.menuitemviewleft.caption","sourcebytes":[86,105,101,119,32,108,101,102,116],"value":"View left"}, {"hash":159199796,"name":"tfrmsyncdirsdlg.menuitemviewright.caption","sourcebytes":[86,105,101,119,32,114,105,103,104,116],"value":"View right"}, {"hash":174352581,"name":"tfrmsyncdirsdlg.menuitemcompare.caption","sourcebytes":[67,111,109,112,97,114,101],"value":"Compare"}, {"hash":2265465,"name":"tfrmsyncdirsdlg.actselectcopylefttoright.caption","sourcebytes":[83,101,108,101,99,116,32,102,111,114,32,99,111,112,121,105,110,103,32,45,62,32,40,108,101,102,116,32,116,111,32,114,105,103,104,116,41],"value":"Select for copying -> (left to right)"}, {"hash":71953785,"name":"tfrmsyncdirsdlg.actselectcopyrighttoleft.caption","sourcebytes":[83,101,108,101,99,116,32,102,111,114,32,99,111,112,121,105,110,103,32,60,45,32,40,114,105,103,104,116,32,116,111,32,108,101,102,116,41],"value":"Select for copying <- (right to left)"}, {"hash":14033049,"name":"tfrmsyncdirsdlg.actselectcopydefault.caption","sourcebytes":[83,101,108,101,99,116,32,102,111,114,32,99,111,112,121,105,110,103,32,40,100,101,102,97,117,108,116,32,100,105,114,101,99,116,105,111,110,41],"value":"Select for copying (default direction)"}, {"hash":74996318,"name":"tfrmsyncdirsdlg.actselectclear.caption","sourcebytes":[82,101,109,111,118,101,32,115,101,108,101,99,116,105,111,110],"value":"Remove selection"}, {"hash":39665470,"name":"tfrmsyncdirsdlg.actselectcopyreverse.caption","sourcebytes":[82,101,118,101,114,115,101,32,99,111,112,121,32,100,105,114,101,99,116,105,111,110],"value":"Reverse copy direction"}, {"hash":105823177,"name":"tfrmsyncdirsdlg.actselectdeleteleft.caption","sourcebytes":[83,101,108,101,99,116,32,102,111,114,32,100,101,108,101,116,105,110,103,32,60,45,32,40,108,101,102,116,41],"value":"Select for deleting <- (left)"}, {"hash":38619657,"name":"tfrmsyncdirsdlg.actselectdeleteright.caption","sourcebytes":[83,101,108,101,99,116,32,102,111,114,32,100,101,108,101,116,105,110,103,32,45,62,32,40,114,105,103,104,116,41],"value":"Select for deleting -> (right)"}, {"hash":254352617,"name":"tfrmsyncdirsdlg.actselectdeleteboth.caption","sourcebytes":[83,101,108,101,99,116,32,102,111,114,32,100,101,108,101,116,105,110,103,32,60,45,62,32,40,98,111,116,104,41],"value":"Select for deleting <-> (both)"}, {"hash":87943924,"name":"tfrmsyncdirsdlg.actdeleteleft.caption","sourcebytes":[60,45,32,68,101,108,101,116,101,32,108,101,102,116],"value":"<- Delete left"}, {"hash":64282708,"name":"tfrmsyncdirsdlg.actdeleteright.caption","sourcebytes":[45,62,32,68,101,108,101,116,101,32,114,105,103,104,116],"value":"-> Delete right"}, {"hash":5492659,"name":"tfrmsyncdirsdlg.actdeleteboth.caption","sourcebytes":[68,101,108,101,116,101,32,111,110,32,98,111,116,104,32,115,105,100,101,115],"value":"Delete on both sides"} ]} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsyncdirsdlg.pas���������������������������������������������������������������0000644�0001750�0000144�00000174714�14743153644�016613� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Directories synchronization utility (specially for DC) Copyright (C) 2013 Anton Panferov (ast.a_s@mail.ru) Copyright (C) 2014-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit fSyncDirsDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons, ComCtrls, Grids, Menus, ActnList, EditBtn, DCClassesUtf8, uFileView, uFileSource, uFileSourceCopyOperation, uFile, uFileSourceOperation, uFileSourceOperationMessageBoxesUI, uFormCommands, uHotkeyManager, uClassesEx, uFileSourceDeleteOperation, KASProgressBar; const HotkeysCategory = 'Synchronize Directories'; type TSyncRecState = (srsUnknown, srsEqual, srsNotEq, srsCopyLeft, srsCopyRight, srsDeleteLeft, srsDeleteRight, srsDeleteBoth, srsDoNothing); { TDrawGrid } TDrawGrid = class(Grids.TDrawGrid) protected procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; end; { TfrmSyncDirsDlg } TfrmSyncDirsDlg = class(TForm, IFormCommands) actDeleteLeft: TAction; actDeleteRight: TAction; actDeleteBoth: TAction; actSelectDeleteLeft: TAction; actSelectDeleteRight: TAction; actSelectDeleteBoth: TAction; actSelectCopyReverse: TAction; actSelectClear: TAction; actSelectCopyLeftToRight: TAction; actSelectCopyRightToLeft: TAction; actSelectCopyDefault: TAction; ActionList: TActionList; btnAbort: TBitBtn; btnCompare: TButton; btnSynchronize: TButton; btnClose: TButton; chkAsymmetric: TCheckBox; chkSubDirs: TCheckBox; chkByContent: TCheckBox; chkIgnoreDate: TCheckBox; chkOnlySelected: TCheckBox; cbExtFilter: TComboBox; edPath1: TDirectoryEdit; edPath2: TDirectoryEdit; HeaderDG: TDrawGrid; lblProgress: TLabel; lblProgressDelete: TLabel; MainDrawGrid: TDrawGrid; GroupBox1: TGroupBox; ImageList1: TImageList; Label1: TLabel; LeftPanel1: TPanel; LeftPanel2: TPanel; miDeleteBoth: TMenuItem; miDeleteRight: TMenuItem; miDeleteLeft: TMenuItem; miSeparator3: TMenuItem; miSelectDeleteLeft: TMenuItem; miSelectDeleteRight: TMenuItem; miSelectDeleteBoth: TMenuItem; miSeparator2: TMenuItem; miSelectCopyReverse: TMenuItem; miSeparator1: TMenuItem; miSelectCopyLeftToRight: TMenuItem; miSelectCopyRightToLeft: TMenuItem; miSelectCopyDefault: TMenuItem; miSelectClear: TMenuItem; MenuItemCompare: TMenuItem; MenuItemViewRight: TMenuItem; MenuItemViewLeft: TMenuItem; pnlFilter: TPanel; pnlProgress: TPanel; pnlCopyProgress: TPanel; pnlDeleteProgress: TPanel; pmGridMenu: TPopupMenu; ProgressBar: TKASProgressBar; ProgressBarDelete: TKASProgressBar; sbCopyRight: TSpeedButton; sbEqual: TSpeedButton; sbNotEqual: TSpeedButton; sbUnknown: TSpeedButton; sbCopyLeft: TSpeedButton; sbDuplicates: TSpeedButton; sbSingles: TSpeedButton; btnSearchTemplate: TSpeedButton; StatusBar1: TStatusBar; Timer: TTimer; TopPanel: TPanel; procedure actExecute(Sender: TObject); procedure btnAbortClick(Sender: TObject); procedure btnCloseClick(Sender: TObject); procedure btnSearchTemplateClick(Sender: TObject); procedure btnCompareClick(Sender: TObject); procedure btnSynchronizeClick(Sender: TObject); procedure edPath1AcceptDirectory(Sender: TObject; var Value: String); procedure RestoreProperties(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure MainDrawGridDblClick(Sender: TObject); procedure MainDrawGridDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); procedure MainDrawGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure MainDrawGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure HeaderDGHeaderClick(Sender: TObject; IsColumn: Boolean; Index: Integer); procedure HeaderDGHeaderSizing(sender: TObject; const IsColumn: boolean; const aIndex, aSize: Integer); procedure FilterSpeedButtonClick(Sender: TObject); procedure MenuItemViewClick(Sender: TObject); procedure pmGridMenuPopup(Sender: TObject); procedure TimerTimer(Sender: TObject); private FCommands: TFormCommands; FIniPropStorage: TIniPropStorageEx; private { private declarations } FCancel: Boolean; FScanning: Boolean; FComparing: Boolean; FFoundItems: TStringListEx; FVisibleItems: TStringListEx; FSortIndex: Integer; FSortDesc: Boolean; FNtfsShift: Boolean; FFileExists: TSyncRecState; FSelectedItems: TStringListEx; FFileSourceL, FFileSourceR: IFileSource; FCmpFileSourceL, FCmpFileSourceR: IFileSource; FCmpFilePathL, FCmpFilePathR: string; FAddressL, FAddressR: string; hCols: array [0..6] of record Left, Width: Integer end; CheckContentThread: TObject; Ftotal, Fequal, Fnoneq, FuniqueL, FuniqueR: Integer; FOperation: TFileSourceOperation; FCopyStatistics: TFileSourceCopyOperationStatistics; FDeleteStatistics: TFileSourceDeleteOperationStatistics; FFileSourceOperationMessageBoxesUI: TFileSourceOperationMessageBoxesUI; procedure ClearFoundItems; procedure Compare; procedure FillFoundItemsDG; procedure InitVisibleItems; procedure RecalcHeaderCols; procedure ScanDirs; procedure SetSortIndex(AValue: Integer); procedure SortFoundItems; procedure SortFoundItems(sl: TStringList); procedure UpdateStatusBar; procedure StopCheckContentThread; procedure UpdateSelection(R: Integer); procedure EnableControls(AEnabled: Boolean); procedure SetSyncRecState(AState: TSyncRecState); procedure DeleteFiles(ALeft, ARight: Boolean); function DeleteFiles(FileSource: IFileSource; var Files: TFiles): Boolean; procedure UpdateList(ALeft, ARight: TFiles; ARemoveLeft, ARemoveRight: Boolean); procedure SetProgressBytes(AProgressBar: TKASProgressBar; CurrentBytes: Int64; TotalBytes: Int64); procedure SetProgressFiles(AProgressBar: TKASProgressBar; CurrentFiles: Int64; TotalFiles: Int64); private property SortIndex: Integer read FSortIndex write SetSortIndex; property Commands: TFormCommands read FCommands implements IFormCommands; protected procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; public { public declarations } constructor Create(AOwner: TComponent; FileView1, FileView2: TFileView); reintroduce; destructor Destroy; override; public procedure CopyToClipboard; published procedure cm_SelectClear(const {%H-}Params:array of string); procedure cm_SelectDeleteLeft(const {%H-}Params:array of string); procedure cm_SelectDeleteRight(const {%H-}Params:array of string); procedure cm_SelectDeleteBoth(const {%H-}Params:array of string); procedure cm_SelectCopyDefault(const {%H-}Params:array of string); procedure cm_SelectCopyReverse(const {%H-}Params:array of string); procedure cm_SelectCopyLeftToRight(const {%H-}Params:array of string); procedure cm_SelectCopyRightToLeft(const {%H-}Params:array of string); procedure cm_DeleteLeft(const {%H-}Params:array of string); procedure cm_DeleteRight(const {%H-}Params:array of string); procedure cm_DeleteBoth(const {%H-}Params:array of string); end; resourcestring rsComparingPercent = 'Comparing... %d%% (ESC to cancel)'; rsLeftToRightCopy = 'Left to Right: Copy %d files, total size: %s (%s)'; rsRightToLeftCopy = 'Right to Left: Copy %d files, total size: %s (%s)'; rsDeleteLeft = 'Left: Delete %d file(s)'; rsDeleteRight = 'Right: Delete %d file(s)'; rsFilesFound = 'Files found: %d (Identical: %d, Different: %d, ' + 'Unique left: %d, Unique right: %d)'; procedure ShowSyncDirsDlg(FileView1, FileView2: TFileView); implementation uses fMain, uDebug, fDiffer, fSyncDirsPerformDlg, uGlobs, LCLType, LazUTF8, LazFileUtils, uFileSystemFileSource, uFileSourceOperationOptions, DCDateTimeUtils, uDCUtils, uFileSourceUtil, uFileSourceOperationTypes, uShowForm, uAdministrator, uOSUtils, uLng, uMasks, Math, uClipboard, IntegerList, fMaskInputDlg, uSearchTemplate, StrUtils, DCStrUtils, uTypes, uFileSystemDeleteOperation, uFindFiles; {$R *.lfm} const GRID_COLUMN_FMT = 'HeaderDG_Column%d_Width'; type { TFileSyncRec } TFileSyncRec = class private FRelPath: string; FState: TSyncRecState; FAction: TSyncRecState; FFileR, FFileL: TFile; FForm: TfrmSyncDirsDlg; public constructor Create(AForm: TfrmSyncDirsDlg; RelPath: string); destructor Destroy; override; procedure UpdateState(ignoreDate: Boolean); end; { TCheckContentThread } TCheckContentThread = class(TThread) private FDone: Boolean; FOwner: TfrmSyncDirsDlg; private procedure DoStart; procedure DoFinish; procedure UpdateGrid; procedure ReapplyFilter; protected procedure Execute; override; public constructor Create(Owner: TfrmSyncDirsDlg); property Done: Boolean read FDone; end; procedure ShowSyncDirsDlg(FileView1, FileView2: TFileView); begin if not Assigned(FileView1) then raise Exception.Create('ShowSyncDirsDlg: FileView1=nil'); if not Assigned(FileView2) then raise Exception.Create('ShowSyncDirsDlg: FileView2=nil'); with TfrmSyncDirsDlg.Create(Application, FileView1, FileView2) do Show; end; { TDrawGrid } procedure TDrawGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var C, R: Integer; begin if Button <> mbRight then inherited MouseDown(Button, Shift, X, Y) else begin MouseToCell(X, Y, {%H-}C, {%H-}R); if (R >= 0) and (R < RowCount) then begin if not IsCellSelected[Col, R] then MoveExtend(False, Col, R, False) else begin C:= Row; PInteger(@Row)^:= R; InvalidateRow(C); InvalidateRow(R); end; end; end; end; { TCheckContentThread } procedure TCheckContentThread.DoStart; begin FOwner.HeaderDG.Enabled:= False; FOwner.GroupBox1.Enabled:= False; end; procedure TCheckContentThread.DoFinish; begin FOwner.FComparing:= False; FOwner.HeaderDG.Enabled:= True; FOwner.TopPanel.Enabled:= True; FOwner.GroupBox1.Enabled:= True; end; procedure TCheckContentThread.UpdateGrid; begin FOwner.MainDrawGrid.Invalidate; FOwner.UpdateStatusBar; end; procedure TCheckContentThread.ReapplyFilter; begin FOwner.FillFoundItemsDG; FOwner.UpdateStatusBar; end; procedure TCheckContentThread.Execute; function CompareFiles(fn1, fn2: String; len: Int64): Boolean; const BUFLEN = 1024 * 32; var fs1, fs2: TFileStreamEx; buf1, buf2: array [1..BUFLEN] of Byte; i, j: Int64; begin fs1 := TFileStreamEx.Create(fn1, fmOpenRead or fmShareDenyWrite); try fs2 := TFileStreamEx.Create(fn2, fmOpenRead or fmShareDenyWrite); try i := 0; repeat if len - i <= BUFLEN then j := len - i else j := BUFLEN; fs1.Read(buf1, j); fs2.Read(buf2, j); i := i + j; Result := CompareMem(@buf1, @buf2, j); until Terminated or not Result or (i >= len); finally fs2.Free; end; finally fs1.Free; end; end; var B: Boolean; i, j: Integer; r: TFileSyncRec; begin Synchronize(@DoStart); try with FOwner do for i := 0 to FFoundItems.Count - 1 do begin for j := 0 to TStringList(FFoundItems.Objects[i]).Count - 1 do begin if Terminated then Exit; r := TFileSyncRec(TStringList(FFoundItems.Objects[i]).Objects[j]); if Assigned(r) and (r.FState = srsUnknown) then begin try B:= CompareFiles(r.FFileL.FullPath, r.FFileR.FullPath, r.FFileL.Size); if Terminated then Exit; if B then begin Inc(Fequal); Dec(Fnoneq); r.FState := srsEqual end else r.FState := srsNotEq; if r.FAction = srsUnknown then r.FAction := r.FState; if j mod 20 = 0 then Synchronize(@UpdateGrid); except on e: Exception do DCDebug('[SyncDirs::CmpContentThread] ' + e.Message); end; end; end; end; FDone := True; Synchronize(@ReapplyFilter); finally Synchronize(@DoFinish); end; end; constructor TCheckContentThread.Create(Owner: TfrmSyncDirsDlg); begin FOwner := Owner; inherited Create(False); end; constructor TFileSyncRec.Create(AForm: TfrmSyncDirsDlg; RelPath: string); begin FForm:= AForm; FRelPath := RelPath; end; destructor TFileSyncRec.Destroy; begin FreeAndNil(FFileL); FreeAndNil(FFileR); inherited Destroy; end; procedure TFileSyncRec.UpdateState(ignoreDate: Boolean); var FileTimeDiff: Integer; begin FState := srsNotEq; if Assigned(FFileR) and not Assigned(FFileL) then FState := FForm.FFileExists else if not Assigned(FFileR) and Assigned(FFileL) then FState := srsCopyRight else begin FileTimeDiff := FileTimeCompare(FFileL.ModificationTime, FFileR.ModificationTime, FForm.FNtfsShift); if ((FileTimeDiff = 0) or ignoreDate) and (FFileL.Size = FFileR.Size) then FState := srsEqual else if not ignoreDate then if FileTimeDiff > 0 then FState := srsCopyRight else if FileTimeDiff < 0 then FState := srsCopyLeft; end; if FForm.chkAsymmetric.Checked and (FState = srsCopyLeft) then FAction := srsDoNothing else begin FAction := FState; end; end; { TfrmSyncDirsDlg } procedure TfrmSyncDirsDlg.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; procedure TfrmSyncDirsDlg.btnCloseClick(Sender: TObject); begin Close end; procedure TfrmSyncDirsDlg.btnSearchTemplateClick(Sender: TObject); var sMask: String; bTemplate: Boolean; begin sMask:= cbExtFilter.Text; if ShowMaskInputDlg(rsMarkPlus, rsMaskInput, glsMaskHistory, sMask) then begin bTemplate:= IsMaskSearchTemplate(sMask); cbExtFilter.Enabled:= not bTemplate; cbExtFilter.Text:= sMask; end; end; procedure TfrmSyncDirsDlg.btnAbortClick(Sender: TObject); begin if Assigned(FOperation) then FOperation.Stop else begin pnlProgress.Hide; end; end; procedure TfrmSyncDirsDlg.btnCompareClick(Sender: TObject); begin if not IsMaskSearchTemplate(cbExtFilter.Text) then InsertFirstItem(Trim(cbExtFilter.Text), cbExtFilter); StatusBar1.Panels[0].Text := Format(rsComparingPercent, [0]); StopCheckContentThread; Compare; end; procedure TfrmSyncDirsDlg.btnSynchronizeClick(Sender: TObject); var OperationType: TFileSourceOperationType; FileExistsOption: TFileSourceOperationOptionFileExists; SymLinkOption: TFileSourceOperationOptionSymLink = fsooslNone; function CopyFiles(src, dst: IFileSource; fs: TFiles; Dest: string): Boolean; begin if not GetCopyOperationType(Src, Dst, OperationType) then begin MessageDlg(rsMsgErrNotSupported, mtError, [mbOK], 0); Exit(False); end else begin Fs.Path:= fs[0].Path; // Create destination directory Dst.CreateDirectory(ExcludeBackPathDelimiter(Dest)); // Determine operation type case OperationType of fsoCopy: begin // Copy within the same file source. FOperation := Src.CreateCopyOperation( Fs, Dest) as TFileSourceCopyOperation; end; fsoCopyOut: begin // CopyOut to filesystem. FOperation := Src.CreateCopyOutOperation( Dst, Fs, Dest) as TFileSourceCopyOperation; end; fsoCopyIn: begin // CopyIn from filesystem. FOperation := Dst.CreateCopyInOperation( Src, Fs, Dest) as TFileSourceCopyOperation; end; end; if not Assigned(FOperation) then begin MessageDlg(rsMsgErrNotSupported, mtError, [mbOK], 0); Exit(False); end; FOperation.Elevate:= ElevateAction; TFileSourceCopyOperation(FOperation).SymLinkOption := SymLinkOption; TFileSourceCopyOperation(FOperation).FileExistsOption := FileExistsOption; FOperation.AddUserInterface(FFileSourceOperationMessageBoxesUI); try FOperation.Execute; Result := FOperation.Result = fsorFinished; SymLinkOption := TFileSourceCopyOperation(FOperation).SymLinkOption; FileExistsOption := TFileSourceCopyOperation(FOperation).FileExistsOption; FCopyStatistics.DoneBytes+= TFileSourceCopyOperation(FOperation).RetrieveStatistics.TotalBytes; SetProgressBytes(ProgressBar, FCopyStatistics.DoneBytes, FCopyStatistics.TotalBytes); finally FreeAndNil(FOperation); end; end; end; var i, DeleteLeftCount, DeleteRightCount, CopyLeftCount, CopyRightCount: Integer; CopyLeftSize, CopyRightSize: Int64; fsr: TFileSyncRec; DeleteLeft, DeleteRight, CopyLeft, CopyRight: Boolean; DeleteLeftFiles, DeleteRightFiles, CopyLeftFiles, CopyRightFiles: TFiles; Dest: string; begin DeleteLeftCount := 0; DeleteRightCount := 0; CopyLeftCount := 0; CopyRightCount := 0; CopyLeftSize := 0; CopyRightSize := 0; for i := 0 to FVisibleItems.Count - 1 do if Assigned(FVisibleItems.Objects[i]) then begin fsr := TFileSyncRec(FVisibleItems.Objects[i]); case fsr.FAction of srsCopyLeft: begin Inc(CopyLeftCount); Inc(CopyLeftSize, fsr.FFileR.Size); end; srsCopyRight: begin Inc(CopyRightCount); Inc(CopyRightSize, fsr.FFileL.Size); end; srsDeleteLeft: begin Inc(DeleteLeftCount); end; srsDeleteRight: begin Inc(DeleteRightCount); end; srsDeleteBoth: begin Inc(DeleteLeftCount); Inc(DeleteRightCount); end; end; end; FCopyStatistics.DoneBytes:= 0; FDeleteStatistics.DoneFiles:= 0; FCopyStatistics.TotalBytes:= CopyLeftSize + CopyRightSize; FDeleteStatistics.TotalFiles:= DeleteLeftCount + DeleteRightCount; with TfrmSyncDirsPerformDlg.Create(Self) do try edLeftPath.Text := FCmpFileSourceL.CurrentAddress + FCmpFilePathL; edRightPath.Text := FCmpFileSourceR.CurrentAddress + FCmpFilePathR; if (CopyLeftCount > 0) and GetCopyOperationType(FFileSourceR, FFileSourceL, OperationType) then begin chkRightToLeft.Enabled := True; chkRightToLeft.Checked := True; edLeftPath.Enabled := True; end; if (CopyRightCount > 0) and GetCopyOperationType(FFileSourceL, FFileSourceR, OperationType) then begin chkLeftToRight.Enabled := True; chkLeftToRight.Checked := True; edRightPath.Enabled := True; end; chkDeleteLeft.Enabled := DeleteLeftCount > 0; chkDeleteLeft.Checked := chkDeleteLeft.Enabled; chkDeleteRight.Enabled := DeleteRightCount > 0; chkDeleteRight.Checked := chkDeleteRight.Enabled; chkDeleteLeft.Caption := Format(rsDeleteLeft, [DeleteLeftCount]); chkDeleteRight.Caption := Format(rsDeleteRight, [DeleteRightCount]); chkLeftToRight.Caption := Format(rsLeftToRightCopy, [CopyRightCount, cnvFormatFileSize(CopyRightSize, fsfFloat, gFileSizeDigits), IntToStrTS(CopyRightSize)]); chkRightToLeft.Caption := Format(rsRightToLeftCopy, [CopyLeftCount, cnvFormatFileSize(CopyLeftSize, fsfFloat, gFileSizeDigits), IntToStrTS(CopyLeftSize)]); if ShowModal = mrOk then begin EnableControls(False); if chkConfirmOverwrites.Checked then FileExistsOption := fsoofeNone else begin FileExistsOption := fsoofeOverwrite; end; CopyLeft := chkRightToLeft.Checked; CopyRight := chkLeftToRight.Checked; DeleteLeft := chkDeleteLeft.Checked; DeleteRight := chkDeleteRight.Checked; lblProgress.Caption := rsOperCopying; lblProgressDelete.Caption := rsOperDeleting; ProgressBar.Position:=0; ProgressBarDelete.Position:=0; pnlCopyProgress.Visible:= CopyLeft or CopyRight; pnlDeleteProgress.Visible:= DeleteLeft or DeleteRight; i := 0; while i < FVisibleItems.Count do begin CopyLeftFiles := TFiles.Create(''); CopyRightFiles := TFiles.Create(''); DeleteLeftFiles := TFiles.Create(''); DeleteRightFiles := TFiles.Create(''); if FVisibleItems.Objects[i] <> nil then repeat fsr := TFileSyncRec(FVisibleItems.Objects[i]); Dest := fsr.FRelPath; case fsr.FAction of srsCopyRight: if CopyRight then CopyRightFiles.Add(fsr.FFileL.Clone); srsCopyLeft: if CopyLeft then CopyLeftFiles.Add(fsr.FFileR.Clone); srsDeleteRight: if DeleteRight then DeleteRightFiles.Add(fsr.FFileR.Clone); srsDeleteLeft: if DeleteLeft then DeleteLeftFiles.Add(fsr.FFileL.Clone); srsDeleteBoth: begin if DeleteRight then DeleteRightFiles.Add(fsr.FFileR.Clone); if DeleteLeft then DeleteLeftFiles.Add(fsr.FFileL.Clone); end; end; i := i + 1; until (i = FVisibleItems.Count) or (FVisibleItems.Objects[i] = nil); i := i + 1; if CopyLeftFiles.Count > 0 then begin if not CopyFiles(FCmpFileSourceR, FCmpFileSourceL, CopyLeftFiles, FCmpFilePathL + Dest) then Break; end else CopyLeftFiles.Free; if CopyRightFiles.Count > 0 then begin if not CopyFiles(FCmpFileSourceL, FCmpFileSourceR, CopyRightFiles, FCmpFilePathR + Dest) then Break; end else CopyRightFiles.Free; if DeleteLeftFiles.Count > 0 then begin if not DeleteFiles(FCmpFileSourceL, DeleteLeftFiles) then Break; end else DeleteLeftFiles.Free; if DeleteRightFiles.Count > 0 then begin if not DeleteFiles(FCmpFileSourceR, DeleteRightFiles) then Break; end else DeleteRightFiles.Free; if not pnlProgress.Visible then Break; end; EnableControls(True); btnCompare.Click; end; finally Free; end; end; procedure TfrmSyncDirsDlg.edPath1AcceptDirectory(Sender: TObject; var Value: String); begin if Sender = edPath1 then begin FFileSourceL := TFileSystemFileSource.GetFileSource; FAddressL := ''; end else if Sender = edPath2 then begin FFileSourceR := TFileSystemFileSource.GetFileSource; FAddressR := ''; end; end; procedure TfrmSyncDirsDlg.RestoreProperties(Sender: TObject); var Index: Integer; begin with HeaderDG.Columns do begin for Index := 0 to Count - 1 do Items[Index].Width:= StrToIntDef(FIniPropStorage.StoredValue[Format(GRID_COLUMN_FMT, [Index])], Items[Index].Width); end; RecalcHeaderCols; end; procedure TfrmSyncDirsDlg.FormClose(Sender: TObject; var CloseAction: TCloseAction); var Index: Integer; begin StopCheckContentThread; CloseAction := caFree; { settings } gSyncDirsSubdirs := chkSubDirs.Checked; gSyncDirsAsymmetric := chkAsymmetric.Checked and gSyncDirsAsymmetricSave; gSyncDirsIgnoreDate := chkIgnoreDate.Checked; gSyncDirsShowFilterCopyRight := sbCopyRight.Down; gSyncDirsShowFilterEqual := sbEqual.Down; gSyncDirsShowFilterNotEqual := sbNotEqual.Down; gSyncDirsShowFilterUnknown := sbUnknown.Down; gSyncDirsShowFilterCopyLeft := sbCopyLeft.Down; gSyncDirsShowFilterDuplicates := sbDuplicates.Down; gSyncDirsShowFilterSingles := sbSingles.Down; if gSyncDirsFileMaskSave = True then begin if not IsMaskSearchTemplate(cbExtFilter.Text) then gSyncDirsFileMask := cbExtFilter.Text; end; if chkByContent.Enabled then gSyncDirsByContent := chkByContent.Checked; glsMaskHistory.Assign(cbExtFilter.Items); with HeaderDG.Columns do begin for Index := 0 to Count - 1 do FIniPropStorage.StoredValue[Format(GRID_COLUMN_FMT, [Index])]:= IntToStr(Items[Index].Width); end; end; procedure TfrmSyncDirsDlg.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin if Assigned(FOperation) then begin FOperation.Stop; CanClose := False; end else if FScanning then begin FCancel := True; CanClose := False; end else if FComparing then begin CanClose := False; StopCheckContentThread; end; end; procedure TfrmSyncDirsDlg.FormCreate(Sender: TObject); var Index: Integer; HMSync: THMForm; begin // Initialize property storage FIniPropStorage := InitPropStorage(Self); FIniPropStorage.OnRestoreProperties:= @RestoreProperties; for Index := 0 to HeaderDG.Columns.Count - 1 do begin FIniPropStorage.StoredValues.Add.DisplayName:= Format(GRID_COLUMN_FMT, [Index]); end; {$IFDEF LCLCOCOA} pnlProgress.Color:=clBtnHighlight; {$ENDIF} lblProgress.Caption := rsOperCopying; lblProgressDelete.Caption := rsOperDeleting; { settings } chkSubDirs.Checked := gSyncDirsSubdirs; chkAsymmetric.Checked := gSyncDirsAsymmetric; chkByContent.Checked := gSyncDirsByContent and chkByContent.Enabled; chkIgnoreDate.Checked := gSyncDirsIgnoreDate; sbCopyRight.Down := gSyncDirsShowFilterCopyRight; sbEqual.Down := gSyncDirsShowFilterEqual; sbNotEqual.Down := gSyncDirsShowFilterNotEqual; sbUnknown.Down := gSyncDirsShowFilterUnknown; sbCopyLeft.Down := gSyncDirsShowFilterCopyLeft; sbDuplicates.Down := gSyncDirsShowFilterDuplicates; sbSingles.Down := gSyncDirsShowFilterSingles; if gSyncDirsFileMaskSave = False then begin Index := glsMaskHistory.IndexOf(gSyncDirsFileMask); if Index <> -1 then glsMaskHistory.Move(Index, 0) else glsMaskHistory.Insert(0, gSyncDirsFileMask); end; cbExtFilter.Items.Assign(glsMaskHistory); cbExtFilter.Text := gSyncDirsFileMask; HMSync := HotMan.Register(Self, HotkeysCategory); HMSync.RegisterActionList(ActionList); FCommands := TFormCommands.Create(Self, ActionList); end; procedure TfrmSyncDirsDlg.FormResize(Sender: TObject); begin ProgressBar.Width:= ClientWidth div 3; ProgressBarDelete.Width:= ProgressBar.Width; end; procedure TfrmSyncDirsDlg.MainDrawGridDblClick(Sender: TObject); var r, x: Integer; sr: TFileSyncRec; begin r := MainDrawGrid.Row; if (r < 0) or (r >= FVisibleItems.Count) then Exit; x := MainDrawGrid.ScreenToClient(Mouse.CursorPos).X; if (x > hCols[3].Left) and (x < hCols[3].Left + hCols[3].Width) then Exit; sr := TFileSyncRec(FVisibleItems.Objects[r]); if not Assigned(sr) or not Assigned(sr.FFileR) or not Assigned(sr.FFileL) or (sr.FState = srsEqual) then Exit; PrepareToolData(FFileSourceL, sr.FFileL, FFileSourceR, sr.FFileR, @ShowDifferByGlobList); end; procedure TfrmSyncDirsDlg.MainDrawGridDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var r: TFileSyncRec; x: Integer; s: string; begin if (FVisibleItems = nil) or (aRow >= FVisibleItems.Count) then Exit; with MainDrawGrid.Canvas do begin r := TFileSyncRec(FVisibleItems.Objects[aRow]); if r = nil then begin Brush.Color := clBtnFace; FillRect(aRect); Font.Bold := True; Font.Color := clWindowText; with hCols[0] do TextRect(Rect(Left, aRect.Top, Left + Width, aRect.Bottom), Left + 2, aRect.Top + 2, FVisibleItems[aRow]); end else begin with gColors.SyncDirs^ do begin case r.FState of srsNotEq: Font.Color := UnknownColor; srsCopyLeft: Font.Color := RightColor; srsCopyRight: Font.Color := LeftColor; srsDeleteLeft: Font.Color := LeftColor; srsDeleteRight: Font.Color := RightColor; else Font.Color := clWindowText; end; end; if Assigned(r.FFileL) then begin with hCols[0] do TextRect(Rect(Left, aRect.Top, Left + Width, aRect.Bottom), Left + 2, aRect.Top + 2, FVisibleItems[aRow]); s := IntToStrTS(r.FFileL.Size); with hCols[1] do begin x := Left + Width - 8 - TextWidth(s); TextRect(Rect(Left, aRect.Top, Left + Width, aRect.Bottom), x, aRect.Top + 2, s); end; s := FormatDateTime(gDateTimeFormatSync, r.FFileL.ModificationTime); with hCols[2] do TextRect(Rect(Left, aRect.Top, Left + Width, aRect.Bottom), Left + 2, aRect.Top + 2, s) end; if Assigned(r.FFileR) then begin TextOut(hCols[6].Left + 2, aRect.Top + 2, FVisibleItems[aRow]); s := IntToStrTS(r.FFileR.Size); with hCols[5] do begin x := Left + Width - 8 - TextWidth(s); TextRect(Rect(Left, aRect.Top, Left + Width, aRect.Bottom), x, aRect.Top + 2, s); end; s := FormatDateTime(gDateTimeFormatSync, r.FFileR.ModificationTime); with hCols[4] do TextRect(Rect(Left, aRect.Top, Left + Width, aRect.Bottom), Left + 2, aRect.Top + 2, s) end; ImageList1.Draw(MainDrawGrid.Canvas, hCols[3].Left + (hCols[3].Width - ImageList1.Width) div 2 - 2, (aRect.Top + aRect.Bottom - ImageList1.Height - 1) div 2, Ord(r.FAction)); end; end; end; procedure TfrmSyncDirsDlg.MainDrawGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var ASelection: TGridRect; begin case Key of VK_SPACE: UpdateSelection(MainDrawGrid.Row); VK_A: begin if (Shift = [ssModifier]) then begin ASelection.Top:= 0; ASelection.Left:= 0; ASelection.Right:= MainDrawGrid.ColCount - 1; ASelection.Bottom:= MainDrawGrid.RowCount - 1; MainDrawGrid.Selection:= ASelection; end; end; VK_C: if (Shift = [ssModifier]) then begin CopyToClipboard; end; VK_INSERT: if (Shift = [ssModifier]) then begin CopyToClipboard; end; end; end; procedure TfrmSyncDirsDlg.MainDrawGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var c, r: Integer; begin MainDrawGrid.MouseToCell(X, Y, c, r); if (r < 0) or (r >= FVisibleItems.Count) or (x - 2 < hCols[3].Left) or (x - 2 > hCols[3].Left + hCols[3].Width) then Exit; UpdateSelection(R); end; procedure TfrmSyncDirsDlg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then begin Key := 0; if FScanning then FCancel := True else if FComparing then StopCheckContentThread else Close; end; end; procedure TfrmSyncDirsDlg.HeaderDGHeaderClick(Sender: TObject; IsColumn: Boolean; Index: Integer); begin if (Index <> 3) and (Index <= 6) then SortIndex := Index; end; procedure TfrmSyncDirsDlg.HeaderDGHeaderSizing(sender: TObject; const IsColumn: boolean; const aIndex, aSize: Integer); begin RecalcHeaderCols; MainDrawGrid.Invalidate; end; procedure TfrmSyncDirsDlg.FilterSpeedButtonClick(Sender: TObject); begin FillFoundItemsDG end; procedure TfrmSyncDirsDlg.MenuItemViewClick(Sender: TObject); var r: Integer; f: TFile = nil; sr: TFileSyncRec; begin r := MainDrawGrid.Row; if (r < 0) or (r >= FVisibleItems.Count) then Exit; sr := TFileSyncRec(FVisibleItems.Objects[r]); if Assigned(sr) then begin if Sender = MenuItemViewLeft then f := sr.FFileL else if Sender = MenuItemViewRight then begin f := sr.FFileR; end; if Assigned(f) then ShowViewerByGlob(f.FullPath); end; end; procedure TfrmSyncDirsDlg.pmGridMenuPopup(Sender: TObject); begin miSelectDeleteLeft.Visible := not chkAsymmetric.Checked; miSelectDeleteBoth.Visible := not chkAsymmetric.Checked; end; procedure TfrmSyncDirsDlg.TimerTimer(Sender: TObject); var CopyStatistics: TFileSourceCopyOperationStatistics; DeleteStatistics: TFileSourceDeleteOperationStatistics; begin if Assigned(FOperation) then begin if (FOperation is TFileSourceCopyOperation) then begin CopyStatistics:= TFileSourceCopyOperation(FOperation).RetrieveStatistics; SetProgressBytes(ProgressBar, FCopyStatistics.DoneBytes + CopyStatistics.DoneBytes, FCopyStatistics.TotalBytes); end else if (FOperation is TFileSourceDeleteOperation) then begin DeleteStatistics:= TFileSourceDeleteOperation(FOperation).RetrieveStatistics; SetProgressFiles(ProgressBarDelete, FDeleteStatistics.DoneFiles + DeleteStatistics.DoneFiles, FDeleteStatistics.TotalFiles); end; end; end; procedure TfrmSyncDirsDlg.SetSortIndex(AValue: Integer); var s: string; begin if AValue = FSortIndex then begin s := HeaderDG.Columns[AValue].Title.Caption; UTF8Delete(s, 1, 1); FSortDesc := not FSortDesc; if FSortDesc then s := '↑' + s else s := '↓' + s; HeaderDG.Columns[AValue].Title.Caption := s; SortFoundItems; FillFoundItemsDG; end else begin if FSortIndex >= 0 then begin s := HeaderDG.Columns[FSortIndex].Title.Caption; UTF8Delete(s, 1, 1); HeaderDG.Columns[FSortIndex].Title.Caption := s; end; FSortIndex := AValue; FSortDesc := False; with HeaderDG.Columns[FSortIndex].Title do Caption := '↓' + Caption; SortFoundItems; FillFoundItemsDG; end; end; procedure TfrmSyncDirsDlg.ClearFoundItems; var i, j: Integer; begin for i := 0 to FFoundItems.Count - 1 do with TStringList(FFoundItems.Objects[i]) do begin for j := 0 to Count - 1 do Objects[j].Free; Clear; end; FFoundItems.Clear; end; procedure TfrmSyncDirsDlg.Compare; begin TopPanel.Enabled := False; try ClearFoundItems; MainDrawGrid.RowCount := 0; ScanDirs; MainDrawGrid.SetFocus; finally TopPanel.Enabled := not FComparing; end; end; procedure TfrmSyncDirsDlg.FillFoundItemsDG; procedure CalcStat; var i: Integer; r: TFileSyncRec; begin Ftotal := 0; Fequal := 0; Fnoneq := 0; FuniqueL := 0; FuniqueR := 0; for i := 0 to FVisibleItems.Count - 1 do begin r := TFileSyncRec(FVisibleItems.Objects[i]); if Assigned(r) then begin Inc(Ftotal); if Assigned(r.FFileL) and not Assigned(r.FFileR) then Inc(FuniqueL) else if Assigned(r.FFileR) and not Assigned(r.FFileL) then Inc(FuniqueR); if r.FState = srsEqual then Inc(Fequal) else if r.FState = srsNotEq then Inc(Fnoneq) else if Assigned(r.FFileL) and Assigned(r.FFileR) then Inc(Fnoneq); end; end; end; begin InitVisibleItems; MainDrawGrid.ColCount := 1; MainDrawGrid.RowCount := FVisibleItems.Count; MainDrawGrid.Invalidate; CalcStat; UpdateStatusBar; if FVisibleItems.Count > 0 then begin btnCompare.Default := False; btnSynchronize.Enabled := True; btnSynchronize.Default := True; end else begin btnCompare.Default := True; btnSynchronize.Enabled := False; btnSynchronize.Default := False; end; end; procedure TfrmSyncDirsDlg.InitVisibleItems; var i, j: Integer; AFilter: record copyLeft, copyRight, eq, neq, unkn: Boolean; dup, single: Boolean; end; r: TFileSyncRec; begin if Assigned(FVisibleItems) then FVisibleItems.Clear else begin FVisibleItems := TStringListEx.Create; FVisibleItems.CaseSensitive := FileNameCaseSensitive; end; { init filter } with AFilter do begin copyLeft := sbCopyLeft.Down; copyRight := sbCopyRight.Down; eq := sbEqual.Down; neq := sbNotEqual.Down; unkn := sbUnknown.Down; dup := sbDuplicates.Down; single := sbSingles.Down; end; for i := 0 to FFoundItems.Count - 1 do begin if FFoundItems[i] <> '' then FVisibleItems.Add(AppendPathDelim(FFoundItems[i])); with TStringList(FFoundItems.Objects[i]) do for j := 0 to Count - 1 do begin { check filter } r := TFileSyncRec(Objects[j]); if ((Assigned(r.FFileL) <> Assigned(r.FFileR)) and AFilter.single or (Assigned(r.FFileL) = Assigned(r.FFileR)) and AFilter.dup) and ((r.FState = srsCopyLeft) and AFilter.copyLeft or (r.FState = srsCopyRight) and AFilter.copyRight or (r.FState = srsDeleteLeft) and AFilter.copyRight or (r.FState = srsDeleteRight) and AFilter.copyLeft or (r.FState = srsEqual) and AFilter.eq or (r.FState = srsNotEq) and AFilter.neq or (r.FState = srsUnknown) and AFilter.unkn) then FVisibleItems.AddObject(Strings[j], Objects[j]); end; end; { remove empty dirs after filtering } for i := FVisibleItems.Count - 1 downto 0 do if (FVisibleItems.Objects[i] = nil) and ((i + 1 >= FVisibleItems.Count) or (FVisibleItems.Objects[i + 1] = nil)) then FVisibleItems.Delete(i); end; procedure TfrmSyncDirsDlg.RecalcHeaderCols; var i, l: Integer; begin l := 0; for i := 0 to 6 do with hCols[i] do begin Left := l; Width := HeaderDG.Columns[i].Width; l := l + Width; end; end; procedure TfrmSyncDirsDlg.ScanDirs; var MaskList: TMaskList; Template: TSearchTemplate; LeftFirst: Boolean = True; RightFirst: Boolean = True; BaseDirL, BaseDirR: string; ignoreDate, Subdirs, ByContent: Boolean; procedure ScanDir(dir: string); procedure ProcessOneSide(it, dirs: TStringList; var ASide: Boolean; sideLeft: Boolean); var fs: TFiles; i, j: Integer; f: TFile; r: TFileSyncRec; begin if sideLeft then fs := FFileSourceL.GetFiles(BaseDirL + dir) else begin fs := FFileSourceR.GetFiles(BaseDirR + dir); end; if chkOnlySelected.Checked and ASide then begin ASide:= False; for I:= fs.Count - 1 downto 0 do begin if FSelectedItems.IndexOf(fs[I].Name) < 0 then fs.Delete(I); end; end; try for i := 0 to fs.Count - 1 do begin f := fs.Items[i]; if f.IsDirectory or f.IsLinkToDirectory then begin if (f.NameNoExt <> '.') and (f.NameNoExt <> '..') then begin if (Template = nil) or (CheckDirectoryName(Template.FileChecks, f.Name)) then dirs.Add(f.Name); end; end else if (Template = nil) or Template.CheckFile(f) then begin if ((MaskList = nil) or MaskList.Matches(f.Name)) then begin j := it.IndexOf(f.Name); if j < 0 then r := TFileSyncRec.Create(Self, dir) else r := TFileSyncRec(it.Objects[j]); if sideLeft then begin r.FFileL := f.Clone; r.UpdateState(ignoreDate); end else begin r.FFileR := f.Clone; r.UpdateState(ignoreDate); if ByContent and (r.FState = srsEqual) and (r.FFileR.Size > 0) then begin r.FAction := srsUnknown; r.FState := srsUnknown; end; end; it.AddObject(f.Name, r); end; end; end; finally fs.Free; end; end; var i, j, tot: Integer; it: TStringList; dirsLeft, dirsRight: TStringListEx; d: string; begin i := FFoundItems.IndexOf(dir); if i < 0 then begin it := TStringListEx.Create; it.CaseSensitive := FileNameCaseSensitive; it.Sorted := True; FFoundItems.AddObject(dir, it); end else it := TStringList(FFoundItems.Objects[i]); if dir <> '' then dir := AppendPathDelim(dir); dirsLeft := TStringListEx.Create; dirsLeft.CaseSensitive := FileNameCaseSensitive; dirsLeft.Sorted := True; dirsRight := TStringListEx.Create; dirsRight.CaseSensitive := FileNameCaseSensitive; dirsRight.Sorted := True; try Application.ProcessMessages; if FCancel then Exit; ProcessOneSide(it, dirsLeft, LeftFirst, True); ProcessOneSide(it, dirsRight, RightFirst, False); SortFoundItems(it); if not Subdirs then Exit; tot := dirsLeft.Count + dirsRight.Count; for i := 0 to dirsLeft.Count - 1 do begin if dir = '' then StatusBar1.Panels[0].Text := Format(rsComparingPercent, [i * 100 div tot]); d := dirsLeft[i]; ScanDir(dir + d); if FCancel then Exit; j := dirsRight.IndexOf(d); if j >= 0 then begin dirsRight.Delete(j); Dec(tot); end end; for i := 0 to dirsRight.Count - 1 do begin if dir = '' then StatusBar1.Panels[0].Text := Format(rsComparingPercent, [(dirsLeft.Count + i) * 100 div tot]); d := dirsRight[i]; ScanDir(dir + d); if FCancel then Exit; end; finally dirsLeft.Free; dirsRight.Free; end; end; begin FScanning := True; try FCancel := False; FCmpFileSourceL := FFileSourceL; FCmpFileSourceR := FFileSourceR; BaseDirL := AppendPathDelim(edPath1.Text); if IsMaskSearchTemplate(cbExtFilter.Text) then begin MaskList := nil; Template:= gSearchTemplateList.TemplateByName[cbExtFilter.Text]; end else begin Template := nil; MaskList := TMaskList.Create(cbExtFilter.Text); end; if (FAddressL <> '') and (Copy(BaseDirL, 1, Length(FAddressL)) = FAddressL) then Delete(BaseDirL, 1, Length(FAddressL)); BaseDirR := AppendPathDelim(edPath2.Text); if (FAddressR <> '') and (Copy(BaseDirR, 1, Length(FAddressR)) = FAddressR) then Delete(BaseDirR, 1, Length(FAddressR)); FCmpFilePathL := BaseDirL; FCmpFilePathR := BaseDirR; ignoreDate := chkIgnoreDate.Checked; Subdirs := chkSubDirs.Checked; ByContent := chkByContent.Checked; if chkAsymmetric.Checked then FFileExists:= srsDeleteRight else begin FFileExists:= srsCopyLeft; end; ScanDir(''); MaskList.Free; FillFoundItemsDG; if FCancel then Exit; if (FFoundItems.Count > 0) and chkByContent.Checked then begin CheckContentThread := TCheckContentThread.Create(Self); FComparing := True; end; finally FScanning := False; end; end; procedure TfrmSyncDirsDlg.SortFoundItems; var i: Integer; begin if FSortIndex < 0 then Exit; for i := 0 to FFoundItems.Count - 1 do SortFoundItems(TStringList(FFoundItems.Objects[i])); end; procedure TfrmSyncDirsDlg.SortFoundItems(sl: TStringList); function CompareFn(sl: TStringList; i, j: Integer): Integer; var r1, r2: TFileSyncRec; begin if FSortIndex in [1..5] then begin r1 := TFileSyncRec(sl.Objects[i]); r2 := TFileSyncRec(sl.Objects[j]); end; case FSortIndex of 0: Result := UTF8CompareStr(sl[i], sl[j]); 1: if (Assigned(r1.FFileL) < Assigned(r2.FFileL)) or Assigned(r2.FFileL) and (r1.FFileL.Size < r2.FFileL.Size) then Result := -1 else if (Assigned(r1.FFileL) > Assigned(r2.FFileL)) or Assigned(r1.FFileL) and (r1.FFileL.Size > r2.FFileL.Size) then Result := 1 else Result := 0; 2: if (Assigned(r1.FFileL) < Assigned(r2.FFileL)) or Assigned(r2.FFileL) and (r1.FFileL.ModificationTime < r2.FFileL.ModificationTime) then Result := -1 else if (Assigned(r1.FFileL) > Assigned(r2.FFileL)) or Assigned(r1.FFileL) and (r1.FFileL.ModificationTime > r2.FFileL.ModificationTime) then Result := 1 else Result := 0; 4: if (Assigned(r1.FFileR) < Assigned(r2.FFileR)) or Assigned(r2.FFileR) and (r1.FFileR.ModificationTime < r2.FFileR.ModificationTime) then Result := -1 else if (Assigned(r1.FFileR) > Assigned(r2.FFileR)) or Assigned(r1.FFileR) and (r1.FFileR.ModificationTime > r2.FFileR.ModificationTime) then Result := 1 else Result := 0; 5: if (Assigned(r1.FFileR) < Assigned(r2.FFileR)) or Assigned(r2.FFileR) and (r1.FFileR.Size < r2.FFileR.Size) then Result := -1 else if (Assigned(r1.FFileR) > Assigned(r2.FFileR)) or Assigned(r1.FFileR) and (r1.FFileR.Size > r2.FFileR.Size) then Result := 1 else Result := 0; 6: Result := UTF8CompareStr(sl[i], sl[j]); end; if FSortDesc then Result := -Result; end; procedure QuickSort(L, R: Integer; sl: TStringList); var Pivot, vL, vR: Integer; begin if R - L <= 1 then begin // a little bit of time saver if L < R then if CompareFn(sl, L, R) > 0 then sl.Exchange(L, R); Exit; end; vL := L; vR := R; Pivot := L + Random(R - L); // they say random is best while vL < vR do begin while (vL < Pivot) and (CompareFn(sl, vL, Pivot) <= 0) do Inc(vL); while (vR > Pivot) and (CompareFn(sl, vR, Pivot) > 0) do Dec(vR); sl.Exchange(vL, vR); if Pivot = vL then // swap pivot if we just hit it from one side Pivot := vR else if Pivot = vR then Pivot := vL; end; if Pivot - 1 >= L then QuickSort(L, Pivot - 1, sl); if Pivot + 1 <= R then QuickSort(Pivot + 1, R, sl); end; begin QuickSort(0, sl.Count - 1, sl); end; procedure TfrmSyncDirsDlg.UpdateStatusBar; var s: string; begin s := Format(rsFilesFound, [Ftotal, Fequal, Fnoneq, FuniqueL, FuniqueR]); if Assigned(CheckContentThread) and not TCheckContentThread(CheckContentThread).Done then s := s + ' ...'; StatusBar1.Panels[0].Text := s; end; procedure TfrmSyncDirsDlg.StopCheckContentThread; begin if Assigned(CheckContentThread) then begin with TCheckContentThread(CheckContentThread) do begin Terminate; WaitFor; end; FreeAndNil(CheckContentThread); end; end; procedure TfrmSyncDirsDlg.UpdateSelection(R: Integer); var sr: TFileSyncRec; ca: TSyncRecState; begin sr := TFileSyncRec(FVisibleItems.Objects[r]); if not Assigned(sr) or (sr.FState = srsEqual) then Exit; ca := sr.FAction; case ca of srsNotEq: ca := srsCopyRight; srsCopyRight: if Assigned(sr.FFileR) then ca := srsCopyLeft else ca := srsDoNothing; srsCopyLeft: if Assigned(sr.FFileL) then ca := srsNotEq else ca := srsDoNothing; srsDeleteRight: if not chkAsymmetric.Checked then ca := sr.FState else ca := srsDoNothing; srsDeleteLeft: ca := sr.FState; srsDeleteBoth: ca := sr.FState; srsDoNothing: if Assigned(sr.FFileL) then ca := srsCopyRight else ca := FFileExists; end; sr.FAction := ca; MainDrawGrid.InvalidateRow(r); end; procedure TfrmSyncDirsDlg.EnableControls(AEnabled: Boolean); begin edPath1.Enabled:= AEnabled; edPath2.Enabled:= AEnabled; TopPanel.Enabled:= AEnabled; HeaderDG.Enabled:= AEnabled; pnlFilter.Enabled:= AEnabled; MainDrawGrid.Enabled:= AEnabled; pnlProgress.Visible:= not AEnabled; Timer.Enabled:= not AEnabled; end; procedure TfrmSyncDirsDlg.SetSyncRecState(AState: TSyncRecState); var R, Y: Integer; Selection: TGridRect; SyncRec: TFileSyncRec; procedure UpdateAction(NewAction: TSyncRecState); begin case NewAction of srsUnknown: NewAction:= SyncRec.FState; srsNotEq: begin if (SyncRec.FAction = srsCopyLeft) and Assigned(SyncRec.FFileL) then NewAction:= srsCopyRight else if (SyncRec.FAction = srsCopyRight) and Assigned(SyncRec.FFileR) then NewAction:= srsCopyLeft else NewAction:= SyncRec.FAction end; srsCopyLeft: begin if not Assigned(SyncRec.FFileR) then NewAction:= srsDoNothing; end; srsCopyRight: begin if not Assigned(SyncRec.FFileL) then NewAction:= srsDoNothing; end; srsDeleteLeft: begin if not Assigned(SyncRec.FFileL) then NewAction:= srsDoNothing; end; srsDeleteRight: begin if not Assigned(SyncRec.FFileR) then NewAction:= srsDoNothing; end; srsDeleteBoth: begin if not Assigned(SyncRec.FFileL) then NewAction:= srsDeleteRight; if not Assigned(SyncRec.FFileR) then NewAction:= srsDeleteLeft; end; end; SyncRec.FAction:= NewAction; MainDrawGrid.InvalidateRow(R); end; begin Selection:= MainDrawGrid.Selection; if (MainDrawGrid.HasMultiSelection) or (Selection.Bottom <> Selection.Top) then begin for Y:= 0 to MainDrawGrid.SelectedRangeCount - 1 do begin Selection:= MainDrawGrid.SelectedRange[Y]; for R := Selection.Top to Selection.Bottom do begin SyncRec := TFileSyncRec(FVisibleItems.Objects[R]); if Assigned(SyncRec) then UpdateAction(AState); end; end; Exit; end; R := MainDrawGrid.Row; if (R < 0) or (R >= FVisibleItems.Count) then Exit; SyncRec := TFileSyncRec(FVisibleItems.Objects[r]); if Assigned(SyncRec) then begin UpdateAction(AState); end else begin Inc(R); while R < FVisibleItems.Count do begin SyncRec := TFileSyncRec(FVisibleItems.Objects[R]); if (SyncRec = nil) then Break; UpdateAction(AState); Inc(R); end; end; end; procedure TfrmSyncDirsDlg.DeleteFiles(ALeft, ARight: Boolean); var Message: String; ALeftList: TFiles; ARightList: TFiles; begin if not ALeft then ALeftList:= nil else begin ALeftList:= TFiles.Create(EmptyStr); end; if not ARight then ARightList:= nil else begin ARightList:= TFiles.Create(EmptyStr); end; try Message:= EmptyStr; UpdateList(ALeftList, ARightList, False, False); ALeft:= ALeft and (ALeftList.Count > 0); ARight:= ARight and (ARightList.Count > 0); if (ALeft = False) and (ARight = False) then Exit; FDeleteStatistics.DoneFiles:= 0; FDeleteStatistics.TotalFiles:= 0; if ALeft then begin FDeleteStatistics.TotalFiles+= ALeftList.Count; Message:= Format(rsVarLeftPanel + ': ' + rsMsgDelFlDr, [ALeftList.Count]) + LineEnding; end; if ARight then begin FDeleteStatistics.TotalFiles+= ARightList.Count; Message+= Format(rsVarRightPanel + ': ' + rsMsgDelFlDr, [ARightList.Count]) + LineEnding; end; if MessageDlg(Message, mtWarning, [mbYes, mbNo], 0, mbYes) = mrYes then begin EnableControls(False); pnlCopyProgress.Visible:= False; pnlDeleteProgress.Visible:= True; if ALeft then DeleteFiles(FCmpFileSourceL, ALeftList); if ARight then DeleteFiles(FCmpFileSourceR, ARightList); UpdateList(nil, nil, ALeft, ARight); EnableControls(True); end; finally ALeftList.Free; ARightList.Free; end; end; function TfrmSyncDirsDlg.DeleteFiles(FileSource: IFileSource; var Files: TFiles): Boolean; begin Files.Path := Files[0].Path; FOperation:= FileSource.CreateDeleteOperation(Files); if not Assigned(FOperation) then begin MessageDlg(rsMsgErrNotSupported, mtError, [mbOK], 0); Exit(False); end; if (FOperation is TFileSystemDeleteOperation) then begin TFileSystemDeleteOperation(FOperation).Recycle:= gUseTrash; end; FOperation.Elevate:= ElevateAction; FOperation.AddUserInterface(FFileSourceOperationMessageBoxesUI); try FOperation.Execute; Result := FOperation.Result = fsorFinished; FDeleteStatistics.DoneFiles+= TFileSourceDeleteOperation(FOperation).RetrieveStatistics.TotalFiles; SetProgressFiles(ProgressBarDelete, FDeleteStatistics.DoneFiles, FDeleteStatistics.TotalFiles); finally FreeAndNil(FOperation); end; end; procedure TfrmSyncDirsDlg.UpdateList(ALeft, ARight: TFiles; ARemoveLeft, ARemoveRight: Boolean); var R, Y: Integer; ARemove: Boolean; Selection: TGridRect; SyncRec: TFileSyncRec; procedure AddRemoveItem; begin if Assigned(ALeft) and Assigned(SyncRec.FFileL) then ALeft.Add(SyncRec.FFileL.Clone); if Assigned(ARight) and Assigned(SyncRec.FFileR) then ARight.Add(SyncRec.FFileR.Clone); if ARemove then begin if ARemoveLeft and Assigned(SyncRec.FFileL) then FreeAndNil(SyncRec.FFileL); if ARemoveRight and Assigned(SyncRec.FFileR) then FreeAndNil(SyncRec.FFileR); if Assigned(SyncRec.FFileL) or Assigned(SyncRec.FFileR) then SyncRec.UpdateState(chkIgnoreDate.Checked) else begin MainDrawGrid.DeleteRow(R); FVisibleItems.Delete(R); end; end; end; begin Selection:= MainDrawGrid.Selection; ARemove:= ARemoveLeft or ARemoveRight; if (MainDrawGrid.HasMultiSelection) or (Selection.Bottom <> Selection.Top) then begin if ARemove then MainDrawGrid.BeginUpdate; for Y:= 0 to MainDrawGrid.SelectedRangeCount - 1 do begin Selection:= MainDrawGrid.SelectedRange[Y]; for R := Selection.Bottom downto Selection.Top do begin SyncRec := TFileSyncRec(FVisibleItems.Objects[R]); if Assigned(SyncRec) then AddRemoveItem; end; end; if ARemove then MainDrawGrid.EndUpdate; Exit; end; R := MainDrawGrid.Row; if (R < 0) or (R >= FVisibleItems.Count) then Exit; SyncRec := TFileSyncRec(FVisibleItems.Objects[r]); if ARemove then MainDrawGrid.BeginUpdate; if Assigned(SyncRec) then begin AddRemoveItem; end else begin Y:= R; Inc(R); while R < FVisibleItems.Count do begin if (FVisibleItems.Objects[R] = nil) then Break; Inc(R); end; Dec(R); while R > Y do begin SyncRec := TFileSyncRec(FVisibleItems.Objects[R]); AddRemoveItem; Dec(R); end; end; if ARemove then MainDrawGrid.EndUpdate; end; procedure TfrmSyncDirsDlg.SetProgressBytes(AProgressBar: TKASProgressBar; CurrentBytes: Int64; TotalBytes: Int64); var BarText : String; CaptionText : String; begin BarText := cnvFormatFileSize(CurrentBytes, uoscOperation) + '/' + cnvFormatFileSize(TotalBytes, uoscOperation); AProgressBar.SetProgress(CurrentBytes, TotalBytes, BarText ); {$IFDEF LCLCOCOA} if TotalBytes > 0 then CaptionText := rsOperCopying + ': ' + BarText + ' (' + FloatToStrF((CurrentBytes / TotalBytes) * 100, ffFixed, 0, 0) + '%)' else CaptionText := rsOperCopying; lblProgress.Caption := CaptionText; {$ENDIF} end; procedure TfrmSyncDirsDlg.SetProgressFiles(AProgressBar: TKASProgressBar; CurrentFiles: Int64; TotalFiles: Int64); var BarText : String; CaptionText : String; begin BarText := IntToStrTS(CurrentFiles) + '/' + IntToStrTS(TotalFiles); AProgressBar.SetProgress(CurrentFiles, TotalFiles, BarText ); {$IFDEF LCLCOCOA} if TotalFiles > 0 then CaptionText := rsOperDeleting + ': ' + BarText + ' (' + FloatToStrF((CurrentFiles / TotalFiles) * 100, ffFixed, 0, 0) + '%)' else CaptionText := rsOperDeleting; lblProgressDelete.Caption := CaptionText; {$ENDIF} end; procedure TfrmSyncDirsDlg.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); begin inherited DoAutoAdjustLayout(AMode, AXProportion, AYProportion); RecalcHeaderCols; end; constructor TfrmSyncDirsDlg.Create(AOwner: TComponent; FileView1, FileView2: TFileView); var Index: Integer; AFiles: TFiles; begin inherited Create(AOwner); FFoundItems := TStringListEx.Create; FFoundItems.CaseSensitive := FileNameCaseSensitive; FFoundItems.Sorted := True; FFileSourceL := FileView1.FileSource; FFileSourceR := FileView2.FileSource; FAddressL := FileView1.CurrentAddress; FAddressR := FileView2.CurrentAddress; with FileView1 do edPath1.Text := FAddressL + CurrentPath; with FileView2 do edPath2.Text := FAddressR + CurrentPath; RecalcHeaderCols; MainDrawGrid.DoubleBuffered := True; MainDrawGrid.Font.Bold := True; FSortIndex := -1; SortIndex := 0; FScanning := False; FSortDesc := False; MainDrawGrid.RowCount := 0; // --------------------------------------------------------------------------- FSelectedItems := TStringListEx.Create; FSelectedItems.Sorted := True; FSelectedItems.Duplicates := dupIgnore; FSelectedItems.CaseSensitive := FileNameCaseSensitive; // Get selected items from active panel AFiles := FileView1.CloneSelectedFiles; for Index := 0 to AFiles.Count - 1 do begin FSelectedItems.Add(AFiles[Index].Name); end; AFiles.Free; // Get selected items from passive panel AFiles := FileView2.CloneSelectedFiles; for Index := 0 to AFiles.Count - 1 do begin FSelectedItems.Add(AFiles[Index].Name); end; AFiles.Free; // --------------------------------------------------------------------------- chkOnlySelected.Enabled := (FSelectedItems.Count > 0) and (FileView1.FlatView = False) and (FileView2.FlatView = False); chkOnlySelected.Checked := chkOnlySelected.Enabled; // --------------------------------------------------------------------------- chkByContent.Enabled := FFileSourceL.IsClass(TFileSystemFileSource) and FFileSourceR.IsClass(TFileSystemFileSource); chkAsymmetric.Enabled := fsoDelete in FileView2.FileSource.GetOperationsTypes; // --------------------------------------------------------------------------- actDeleteLeft.Enabled := fsoDelete in FileView1.FileSource.GetOperationsTypes; actDeleteRight.Enabled := fsoDelete in FileView2.FileSource.GetOperationsTypes; actDeleteBoth.Enabled := actDeleteLeft.Enabled and actDeleteRight.Enabled; // --------------------------------------------------------------------------- FFileSourceOperationMessageBoxesUI := TFileSourceOperationMessageBoxesUI.Create; if (FFileSourceL.IsClass(TFileSystemFileSource)) and (FFileSourceR.IsClass(TFileSystemFileSource)) then begin FNtfsShift := gNtfsHourTimeDelay and NtfsHourTimeDelay(FileView1.CurrentPath, FileView2.CurrentPath); end; end; destructor TfrmSyncDirsDlg.Destroy; begin HotMan.UnRegister(Self); FFileSourceOperationMessageBoxesUI.Free; FVisibleItems.Free; FSelectedItems.Free; if Assigned(FFoundItems) then begin ClearFoundItems; FFoundItems.Free; end; inherited Destroy; end; procedure TfrmSyncDirsDlg.CopyToClipboard; var sl: TStringList; RowList: TIntegerList; I: Integer; procedure FillRowList(RowList: TIntegerList); var R, Y: Integer; Selection: TGridRect; begin Selection := MainDrawGrid.Selection; if (MainDrawGrid.HasMultiSelection) or (Selection.Bottom <> Selection.Top) then begin for Y:= 0 to MainDrawGrid.SelectedRangeCount - 1 do begin Selection:= MainDrawGrid.SelectedRange[Y]; for R := Selection.Top to Selection.Bottom do begin if RowList.IndexOf(R) = -1 then begin RowList.Add(R); end; end; end; end else begin R := MainDrawGrid.Row; if RowList.IndexOf(R) = -1 then begin RowList.Add(R); end; end; RowList.Sort; end; procedure PrintRow(R: Integer); var s: string; SyncRec: TFileSyncRec; begin s := ''; SyncRec := TFileSyncRec(FVisibleItems.Objects[R]); if not Assigned(SyncRec) then begin s := s + FVisibleItems[R]; end else begin if Assigned(SyncRec.FFileL) then begin s := s + FVisibleItems[R]; s := s + #9; s := s + IntToStrTS(SyncRec.FFileL.Size); s := s + #9; s := s + FormatDateTime(gDateTimeFormatSync, SyncRec.FFileL.ModificationTime); end; if Length(s) <> 0 then s := s + #9; case SyncRec.FState of srsUnknown: s := s + '?'; srsEqual: s := s + '='; srsNotEq: s := s + '!='; srsCopyLeft: s := s + '<-'; srsCopyRight: s := s + '->'; end; if Length(s) <> 0 then s := s + #9; if Assigned(SyncRec.FFileR) then begin s := s + FormatDateTime(gDateTimeFormatSync, SyncRec.FFileR.ModificationTime); s := s + #9; s := s + IntToStrTS(SyncRec.FFileR.Size); s := s + #9; s := s + FVisibleItems[R]; end; end; sl.Add(s); end; begin sl := TStringList.Create; RowList := TIntegerList.Create; try FillRowList(RowList); for I := 0 to RowList.Count - 1 do begin PrintRow(RowList[I]); end; ClipboardSetText(sl.Text); finally FreeAndNil(sl); FreeAndNil(RowList); end; end; procedure TfrmSyncDirsDlg.cm_SelectClear(const Params: array of string); begin SetSyncRecState(srsDoNothing); end; procedure TfrmSyncDirsDlg.cm_SelectDeleteLeft(const Params: array of string); begin SetSyncRecState(srsDeleteLeft); end; procedure TfrmSyncDirsDlg.cm_SelectDeleteRight(const Params: array of string); begin SetSyncRecState(srsDeleteRight); end; procedure TfrmSyncDirsDlg.cm_SelectDeleteBoth(const Params: array of string); begin SetSyncRecState(srsDeleteBoth); end; procedure TfrmSyncDirsDlg.cm_SelectCopyDefault(const Params: array of string); begin SetSyncRecState(srsUnknown); end; procedure TfrmSyncDirsDlg.cm_SelectCopyReverse(const Params: array of string); begin SetSyncRecState(srsNotEq); end; procedure TfrmSyncDirsDlg.cm_SelectCopyLeftToRight(const Params: array of string); begin SetSyncRecState(srsCopyRight); end; procedure TfrmSyncDirsDlg.cm_SelectCopyRightToLeft(const Params: array of string); begin SetSyncRecState(srsCopyLeft); end; procedure TfrmSyncDirsDlg.cm_DeleteLeft(const Params: array of string); begin DeleteFiles(True, False); end; procedure TfrmSyncDirsDlg.cm_DeleteRight(const Params: array of string); begin DeleteFiles(False, True); end; procedure TfrmSyncDirsDlg.cm_DeleteBoth(const Params: array of string); begin DeleteFiles(True, True); end; initialization TFormCommands.RegisterCommandsForm(TfrmSyncDirsDlg, HotkeysCategory, @rsHotkeyCategorySyncDirs); end. ����������������������������������������������������doublecmd-1.1.22/src/fsyncdirsperformdlg.lfm��������������������������������������������������������0000644�0001750�0000144�00000006634�14743153644�020174� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmSyncDirsPerformDlg: TfrmSyncDirsPerformDlg Left = 234 Height = 219 Top = 137 Width = 326 AutoSize = True BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Synchronize' ClientHeight = 200 ClientWidth = 326 Position = poOwnerFormCenter LCLVersion = '1.4.0.4' object chkLeftToRight: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 6 Height = 19 Top = 3 Width = 20 BorderSpacing.Left = 6 BorderSpacing.Top = 3 Enabled = False ParentBidiMode = False TabOrder = 0 end object edRightPath: TEdit AnchorSideLeft.Control = chkLeftToRight AnchorSideTop.Control = chkLeftToRight AnchorSideTop.Side = asrBottom Left = 22 Height = 23 Top = 22 Width = 270 BorderSpacing.Left = 16 BorderSpacing.Right = 6 Enabled = False ReadOnly = True TabOrder = 1 end object chkRightToLeft: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = edRightPath AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 51 Width = 20 BorderSpacing.Left = 6 BorderSpacing.Top = 6 Enabled = False ParentBidiMode = False TabOrder = 2 end object edLeftPath: TEdit AnchorSideLeft.Control = chkRightToLeft AnchorSideTop.Control = chkRightToLeft AnchorSideTop.Side = asrBottom Left = 22 Height = 23 Top = 70 Width = 270 BorderSpacing.Left = 16 Enabled = False ReadOnly = True TabOrder = 3 end object Bevel1: TBevel AnchorSideLeft.Control = Owner AnchorSideTop.Control = chkDeleteRight AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 0 Height = 6 Top = 140 Width = 326 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 3 Shape = bsBottomLine end object chkConfirmOverwrites: TCheckBox AnchorSideLeft.Control = Owner AnchorSideTop.Control = Bevel1 AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 152 Width = 121 BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Confirm overwrites' Checked = True State = cbChecked TabOrder = 5 end object ButtonPanel1: TButtonPanel AnchorSideTop.Control = chkConfirmOverwrites AnchorSideTop.Side = asrBottom Left = 6 Height = 26 Top = 177 Width = 314 Align = alNone Anchors = [akTop, akLeft, akRight] OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 6 ShowButtons = [pbOK, pbCancel] ShowBevel = False end object chkDeleteLeft: TCheckBox AnchorSideLeft.Control = chkLeftToRight AnchorSideTop.Control = edLeftPath AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 99 Width = 20 BorderSpacing.Top = 6 TabOrder = 4 end object chkDeleteRight: TCheckBox AnchorSideLeft.Control = chkLeftToRight AnchorSideTop.Control = chkDeleteLeft AnchorSideTop.Side = asrBottom Left = 6 Height = 19 Top = 118 Width = 20 BorderSpacing.Top = 6 TabOrder = 4 end end ����������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsyncdirsperformdlg.lrj��������������������������������������������������������0000644�0001750�0000144�00000000556�14743153644�020202� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":267343253,"name":"tfrmsyncdirsperformdlg.caption","sourcebytes":[83,121,110,99,104,114,111,110,105,122,101],"value":"Synchronize"}, {"hash":96086787,"name":"tfrmsyncdirsperformdlg.chkconfirmoverwrites.caption","sourcebytes":[67,111,110,102,105,114,109,32,111,118,101,114,119,114,105,116,101,115],"value":"Confirm overwrites"} ]} ��������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fsyncdirsperformdlg.pas��������������������������������������������������������0000644�0001750�0000144�00000001302�14743153644�020164� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fSyncDirsPerformDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, ButtonPanel; type { TfrmSyncDirsPerformDlg } TfrmSyncDirsPerformDlg = class(TForm) Bevel1: TBevel; ButtonPanel1: TButtonPanel; chkDeleteLeft: TCheckBox; chkDeleteRight: TCheckBox; chkConfirmOverwrites: TCheckBox; chkLeftToRight: TCheckBox; chkRightToLeft: TCheckBox; edRightPath: TEdit; edLeftPath: TEdit; private { private declarations } public { public declarations } end; var frmSyncDirsPerformDlg: TfrmSyncDirsPerformDlg; implementation {$R *.lfm} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ftreeviewmenu.lfm��������������������������������������������������������������0000644�0001750�0000144�00000152524�14743153644�016773� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmTreeViewMenu: TfrmTreeViewMenu Left = 338 Height = 787 Top = 184 Width = 524 BorderIcons = [biSystemMenu] Caption = 'Tree View Menu' ClientHeight = 787 ClientWidth = 524 Font.CharSet = ANSI_CHARSET Font.Height = -13 Font.Name = 'Arial' Font.Pitch = fpVariable Font.Quality = fqDraft KeyPreview = True OnClose = FormClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnKeyDown = FormKeyDown ShowHint = True LCLVersion = '1.6.0.4' object pnlAll: TPanel AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 0 Height = 787 Top = 0 Width = 524 Anchors = [akTop, akLeft, akRight, akBottom] BevelOuter = bvNone BorderWidth = 1 BorderStyle = bsSingle ClientHeight = 783 ClientWidth = 520 TabOrder = 0 object tvMainMenu: TTreeView AnchorSideLeft.Control = pnlAll AnchorSideTop.Control = edSearchingEntry AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlAll AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlAll AnchorSideBottom.Side = asrBottom Left = 1 Height = 717 Top = 65 Width = 518 Anchors = [akTop, akLeft, akRight, akBottom] AutoExpand = True BackgroundColor = clBtnFace Color = clBtnFace DefaultItemHeight = 18 Font.CharSet = ANSI_CHARSET Font.Color = clBlack Font.Height = -13 Font.Name = 'Arial' Font.Pitch = fpVariable Font.Quality = fqDraft HotTrack = True ParentFont = False ReadOnly = True TabOrder = 0 OnClick = tvMainMenuClick OnCollapsed = tvMainMenuExpandOrCollapseClick OnDblClick = tvMainMenuDblClick OnEnter = tvMainMenuEnter OnExpanded = tvMainMenuExpandOrCollapseClick OnMouseMove = tvMainMenuMouseMove OnMouseWheelDown = tvMainMenuMouseWheelDown OnMouseWheelUp = tvMainMenuMouseWheelUp OnSelectionChanged = tvMainMenuSelectionChanged Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end object edSearchingEntry: TEdit AnchorSideLeft.Control = pnlAll AnchorSideTop.Control = lblSearchingEntry AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlAll AnchorSideRight.Side = asrBottom Left = 1 Height = 24 Top = 41 Width = 518 Anchors = [akTop, akLeft, akRight] OnChange = edSearchingEntryChange TabStop = False TabOrder = 1 end object lblSearchingEntry: TLabel AnchorSideLeft.Control = pnlAll AnchorSideTop.Control = tbOptions AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlAll AnchorSideRight.Side = asrBottom Left = 1 Height = 18 Top = 23 Width = 518 Anchors = [akTop, akLeft, akRight] Caption = 'Select your hot directory:' FocusControl = edSearchingEntry Font.CharSet = ANSI_CHARSET Font.Height = -15 Font.Name = 'Arial' Font.Pitch = fpVariable Font.Quality = fqDraft Font.Style = [fsBold] ParentColor = False ParentFont = False end object tbOptions: TToolBar AnchorSideLeft.Control = pnlAll AnchorSideTop.Control = pnlAll AnchorSideRight.Control = tbClose AnchorSideBottom.Side = asrBottom Left = 1 Height = 22 Top = 1 Width = 457 Align = alNone Anchors = [akTop, akLeft, akRight] ButtonHeight = 20 ButtonWidth = 20 EdgeBorders = [] Images = imgListButton TabOrder = 2 object tbCaseSensitive: TToolButton Left = 1 Top = 0 DropdownMenu = pmCaseSensitiveOrNot ImageIndex = 0 OnClick = tbCaseSensitiveClick Style = tbsDropDown end object tbShowWholeBranchOrNot: TToolButton Left = 70 Top = 0 DropdownMenu = pmShowWholeBranchIfMatchOrNot ImageIndex = 5 OnClick = tbShowWholeBranchOrNotClick Style = tbsDropDown end object tbDivider: TToolButton Left = 65 Height = 20 Top = 0 Width = 5 Style = tbsDivider end object tbIgnoreAccents: TToolButton Left = 33 Top = 0 DropdownMenu = pmIgnoreAccentsOrNot ImageIndex = 2 OnClick = tbIgnoreAccentsClick Style = tbsDropDown end object tbFullExpandOrNot: TToolButton Left = 102 Top = 0 DropdownMenu = pmFullExpandOrNot ImageIndex = 9 OnClick = tbFullExpandOrNotClick Style = tbsDropDown end end object tbClose: TToolBar AnchorSideTop.Control = pnlAll AnchorSideRight.Control = pnlAll AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 458 Height = 20 Top = 1 Width = 61 Align = alNone Anchors = [akTop, akRight] AutoSize = True ButtonHeight = 20 ButtonWidth = 20 EdgeBorders = [] Images = imgListButton TabOrder = 3 object tbCancelAndQuit: TToolButton Left = 41 Hint = 'Close Tree View Menu' Top = 0 ImageIndex = 6 OnClick = tbCancelAndQuitClick end object tbConfigurationTreeViewMenus: TToolButton Left = 1 Hint = 'Configuration of Tree View Menu' Top = 0 ImageIndex = 7 OnClick = tbConfigurationTreeViewMenusClick end object tbConfigurationTreeViewMenusColors: TToolButton Left = 21 Hint = 'Configuration of Tree View Menu Colors' Top = 0 ImageIndex = 8 OnClick = tbConfigurationTreeViewMenusColorsClick end end end object imgListButton: TImageList left = 208 top = 112 Bitmap = { 4C690B0000001000000010000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF007F00FF007F00FF007F00FF007F00FF007F00FFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF007F00FF007F00FF007F00FF007F00FF007F00FFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F9F5FF098309FF007F 00FF098309FFF5F9F5FFFFFFFFFFFFFFFFFFDDEDDDFF46A146FF0E850EFF0983 09FF359935FFC9E3C9FFFFFFFFFFFFFFFFFFFFFFFFFFAED5AEFF007F00FF007F 00FF007F00FFAFD6AFFFFFFFFFFFFFFFFFFF389A38FF007F00FF007F00FF007F 00FF007F00FF2C942CFFFFFFFFFFFFFFFFFFFFFFFFFF5DAD5DFF007F00FF51A7 51FF007F00FF5EAD5EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFDFDFFCCE4 CCFF007F00FF078207FFFFFFFFFFFFFFFFFFFBFCFBFF118711FF078207FFE6F1 E6FF088208FF128712FFFBFCFBFFFFFFFFFFFFFFFFFFC2DFC2FF72B772FF2C94 2CFF007F00FF007F00FFFFFFFFFFFFFFFFFFBBDCBBFF007F00FF4AA34AFFFFFF FFFF4FA64FFF007F00FFBCDCBCFFFFFFFFFF96C996FF007F00FF74B874FFCFE6 CFFF007F00FF007F00FFFFFFFFFFFFFFFFFF6BB46BFF007F00FF9BCC9BFFFFFF FFFFA2CFA2FF007F00FF6BB46BFFFFFFFFFF108610FF007F00FFD0E6D0FFA9D3 A9FF007F00FF007F00FFFDFDFDFFFEFEFEFF1B8C1BFF007F00FF007F00FF007F 00FF007F00FF007F00FF1C8C1CFFFEFEFEFF279227FF007F00FF007F00FF007F 00FF0E850EFF007F00FFE5F1E5FFC9E3C9FF007F00FF007F00FF007F00FF007F 00FF007F00FF007F00FF007F00FFCAE3CAFFC7E2C7FF2E952EFF088208FF46A1 46FFCBE4CBFF007F00FF6BB46BFF78BA78FF007F00FF88C288FFFFFFFFFFFFFF FFFFFFFFFFFF83C083FF007F00FF79BB79FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF279227FF007F00FFD2E7D2FFFFFFFFFFFFFF FFFFFFFFFFFFD3E8D3FF007F00FF289228FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF21007EFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF21007FFF21007FFF21007FFF21007FFF21007FFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF21007EFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF21007FFF21007FFF21007FFF21007FFF21007FFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF21007EFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF01F5F9FF1F0983FF2100 7FFF1F0983FF01F5F9FF00FFFFFF00FFFFFF04DDEDFF1746A1FF1F0E85FF1F09 83FF1A3599FF06C9E3FF00FFFFFF00FFFFFF00FFFFFF0AAED5FF21007FFF2100 7FFF21007FFF0AAFD6FF00FFFFFF00FFFFFF19389AFF21007FFF21007FFF2100 7FFF21007FFF1B2C94FF00FFFFFF00FFFFFF00FFFFFF145DADFF21007FFF1651 A7FF21007FFF145EADFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FDFDFF06CC E4FF21007FFF200782FF00FFFFFF00FFFFFF00FBFCFF1E1187FF200782FF03E6 F1FF1F0882FF1E1287FF00FBFCFF00FFFFFF00FFFFFF07C2DFFF1272B7FF1B2C 94FF21007FFF21007FFF00FFFFFF00FFFFFF08BBDCFF21007FFF174AA3FF00FF FFFF164FA6FF21007FFF08BCDCFF00FFFFFF0D96C9FF21007FFF1174B8FF06CF E6FF21007FFF21007FFF00FFFFFF00FFFFFF136BB4FF21007FFF0C9BCCFF00FF FFFF0BA2CFFF21007FFF136BB4FF00FFFFFF1E1086FF21007FFF05D0E6FF0BA9 D3FF21007FFF21007FFF00FDFDFF00FEFEFF1D1B8CFF21007FFF21007FFF2100 7FFF21007FFF21007FFF1D1C8CFF00FEFEFF1B2792FF21007FFF21007FFF2100 7FFF1F0E85FF21007FFF03E5F1FF06C9E3FF21007FFF21007FFF21007FFF2100 7FFF21007FFF21007FFF21007FFF06CAE3FF07C7E2FF1B2E95FF1F0882FF1746 A1FF06CBE4FF21007FFF136BB4FF1178BAFF21007FFF0E88C2FF00FFFFFF00FF FFFF00FFFFFF1083C0FF21007FFF1179BBFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF1B2792FF21007FFF05D2E7FF00FFFFFF00FF FFFF00FFFFFF05D3E8FF21007FFF1B2892FF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF007F00FF007F 00FF007F00FF007F00FF007F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF007F00FF007F 00FF007F00FF007F00FF007F00FFFFFFFFFFFFFFFFFFFFFFFFFFBFDEBFFF007F 00FF7FBE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F9E3FFF7FBE 7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4D0A4FF269126FF068106FF2C94 2CFFB1D7B1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4D0A4FF269126FF0681 06FF2C942CFFB1D7B1FFFFFFFFFFBADBBAFF007F00FF007F00FF007F00FF007F 00FF038003FFC2DFC2FFFFFFFFFFFFFFFFFFBADBBAFF007F00FF007F00FF007F 00FF007F00FF038003FFC2DFC2FF3F9E3FFF007F00FFA7D2A7FFF8FAF8FFB0D6 B0FF007F00FF4FA64FFFFFFFFFFFFFFFFFFF3F9E3FFF007F00FFA7D2A7FFF8FA F8FFB0D6B0FF007F00FF4FA64FFF138813FF007F00FF007F00FF007F00FF007F 00FF007F00FF188A18FFFFFFFFFFFFFFFFFF138813FF007F00FF007F00FF007F 00FF007F00FF007F00FF188A18FF0E850EFF007F00FF007F00FF007F00FF007F 00FF007F00FF048004FFFFFFFFFFFFFFFFFF0E850EFF007F00FF007F00FF007F 00FF007F00FF007F00FF048004FF399B39FF007F00FFA8D2A8FFF9FBF9FFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF399B39FF007F00FFA8D2A8FFF9FB F9FFFFFFFFFFFFFFFFFFFFFFFFFFACD4ACFF007F00FF007F00FF007F00FF007F 00FF007F00FF4BA44BFFFFFFFFFFFFFFFFFFACD4ACFF007F00FF007F00FF007F 00FF007F00FF007F00FF4BA44BFFFFFFFFFF9ECD9EFF299329FF068106FF178A 17FF67B267FFF3F8F3FFFFFFFFFFFFFFFFFFFFFFFFFF9ECD9EFF299329FF0681 06FF178A17FF67B267FFF3F8F3FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF21007EFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF21007FFF2100 7FFF21007FFF21007FFF21007FFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF21007EFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF21007FFF2100 7FFF21007FFF21007FFF21007FFF00FFFFFF00FFFFFF00FFFFFF05BFDEFF1500 7FFF0A7FBEFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF2100 7EFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0F3F9EFF0A7F BEFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF07A4D0FF112691FF140681FF112C 94FF06B1D7FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF07A4D0FF112691FF1406 81FF112C94FF06B1D7FF00FFFFFF05BADBFF15007FFF15007FFF15007FFF1500 7FFF140380FF05C2DFFF00FFFFFF00FFFFFF05BADBFF15007FFF15007FFF1500 7FFF15007FFF140380FF05C2DFFF0F3F9EFF15007FFF07A7D2FF00F8FAFF06B0 D6FF15007FFF0E4FA6FF00FFFFFF00FFFFFF0F3F9EFF15007FFF07A7D2FF00F8 FAFF06B0D6FF15007FFF0E4FA6FF131388FF15007FFF15007FFF15007FFF1500 7FFF15007FFF13188AFF00FFFFFF00FFFFFF131388FF15007FFF15007FFF1500 7FFF15007FFF15007FFF13188AFF130E85FF15007FFF15007FFF15007FFF1500 7FFF15007FFF140480FF00FFFFFF00FFFFFF130E85FF15007FFF15007FFF1500 7FFF15007FFF15007FFF140480FF10399BFF15007FFF07A8D2FF00F9FBFF00FF FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF10399BFF15007FFF07A8D2FF00F9 FBFF00FFFFFF00FFFFFF00FFFFFF06ACD4FF15007FFF15007FFF15007FFF1500 7FFF15007FFF0E4BA4FF00FFFFFF00FFFFFF06ACD4FF15007FFF15007FFF1500 7FFF15007FFF15007FFF0E4BA4FF00FFFFFF079ECDFF112993FF140681FF1317 8AFF0C67B2FF00F3F8FF00FFFFFF00FFFFFF00FFFFFF079ECDFF112993FF1406 81FF13178AFF0C67B2FF00F3F8FF000000000000000000000000008A47FF008A 47FF000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000008742FF9AE0D3FF9AE0 D3FF008742FF0000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000008844FF8EDBCBFF00B99DFF00B9 9DFF8EDBCBFF008844FF00000000000000000000000000000000000000000000 0000000000000000000000000000008C4AFF82DCCAFF00C1A0FF00BE9BFF00BE 9BFF00C1A0FF83DCCAFF008C4AFF000000000000000000000000000000000000 0000000000000000000000000000008B4BF2008946FF00AE7FFF00C39EFF00C3 9EFF00AE80FF008946FF008B4BF2000000000000000000000000000000000000 00000000000000000000000000000000003000000033008742FF6AE2CCFF00C9 A1FF008744FF0000003300000030000000000000000000000000464646B14646 46FF0000000000000000000000000000000000000000008844FF59E1C8FF00CB A2FF008846FF0000000000000000000000000000000000000000444444FFC4C4 C4FF434343FF00000000000000000000000000000000008845FF4BE0C1FF00CF A0FF068144FF00000000444444A7444444FF434343FF434343FF555555FF6060 60FFBDBDBDFF434343FF000000000000000000000000008845FF3EDFBCFF00D1 9FFF04803FFF545454CF8A8A8AFF8D8D8DFF8D8D8DFF8D8D8DFF626262FF6262 62FF626262FFB2B2B2FF454545FF0000000000000000008846FF30DFB6FF00D1 9DFF1CAB7AFF8D8D8DFF787878FF686868FF686868FF676767FF666666FF6565 65FF666666FFA7A7A7FF454545FF0000000000000000008746FF23DFB1FF00D3 9CFF20D5ADFF6B6B6BFF555555FF434343FF444444FF434343FF5C5C5CFF6C6C 6CFF9E9E9EFF434343FF000000330000000000000000008747FF16DFABFF00D8 9EFF00C890FF4B4B4BFF3E3E3EB6000000330000003300000033444444FF9797 97FF434343FF00000033000000000000000000000000008847FF08E1A6FF00DF A1FF008544FF3E3E3EB500000021000000000000000000000000404040C14646 46FF0000003300000000000000000000000000000000008949FF00E7A7FF00E7 A7FF008949FF2F2F2F4C00000000000000000000000000000000000000230000 00330000000000000000000000000000000000000000008B4CF2008A4AFF008A 4AFF008B4CF10000000A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000030000000330000 00330000002F0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008A47FF008A 47FF000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000008742FF9AE0D3FF9AE0 D3FF008742FF0000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000008844FF8EDBCBFF00B99DFF00B9 9DFF8EDBCBFF008844FF00000000000000000000000000000000000000000000 0000000000000000000000000000008C4AFF82DCCAFF00C1A0FF00BE9BFF00BE 9BFF00C1A0FF83DCCAFF008C4AFF000000000000000000000000000000000000 0000000000000000000000000000008B4BF2008946FF00AE7FFF00C39EFF00C3 9EFF00AE80FF008946FF008B4BF2000000000000000000000000000000000000 00000000000000000000000000000000003000000033008742FF6AE2CCFF00C9 A1FF008744FF0000003300000030000000000000000000000000008D4CB1008C 49FF0000000000000000000000000000000000000000008844FF59E1C8FF00CB A2FF008846FF0000000000000000000000000000000000000000008945FFA4E4 D9FF008743FF00000000000000000000000000000000008845FF4BE0C1FF00CF A0FF008744FF00000000008946A7008845FF008744FF008641FF00AB7DFF00C0 9EFF9BE0D0FF008743FF000000000000000000000000008845FF3EDFBCFF00D1 9FFF00843FFF0F9960CF4ACBB0FF42D9BEFF42D9BEFF42D9BEFF00C49AFF00C4 9AFF00C59CFF86DEC8FF008A48FF0000000000000000008846FF30DFB6FF00D1 9DFF1CAB7AFF42D9BEFF20D1B0FF00D09FFF00D0A0FF00CF9FFF00CD9CFF00CB 9AFF00CD9CFF74DABDFF008A48FF0000000000000000008746FF23DFB1FF00D3 9CFF20D5ADFF04D3A5FF00AB73FF008744FF008846FF008644FF00B97FFF00D8 A0FF65D7B3FF008744FF000000330000000000000000008747FF16DFABFF00D8 9EFF00C890FF009657FF007C42B6000000330000003300000033008847FF54DA B0FF008746FF00000033000000000000000000000000008847FF08E1A6FF00DF A1FF008544FF007D43B500000021000000000000000000000000008147C1008C 4BFF0000003300000000000000000000000000000000008949FF00E7A7FF00E7 A7FF008949FF005E334C00000000000000000000000000000000000000230000 00330000000000000000000000000000000000000000008B4CF2008A4AFF008A 4AFF008B4CF10000000A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000030000000330000 00330000002F0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000C7C9DBFF2D2DB4FF0303A5FF0000 A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000A4FF0202 A4FF1B1FA4FF798B98FC00000000000000003636B8FF3434C8FF6464DFFF6666 E0FF6666E0FF6666E0FF6666E0FF6666E0FF6666E0FF6666E0FF6666E0FF6464 DFFF3333C9FE0101A7C700000000000000000303A5FF6464DFFF0505CDFF0000 CCFF0000CCFF0000CCFF0000CCFF0000CCFF0000CCFF0000CCFF0000CCFF0505 CDFF6464DFFF0000A5FC00000000000000000000A4FF6666E0FF0000CCFF0404 CDFF3C3CD8FF0000CCFF0000CCFF0000CCFF0000CCFF4040D9FF0404CDFF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF3636 D7FFFFFFFFFF8F8FE9FF0000CCFF0000CCFF8F8FE9FFFFFFFFFF3434D6FF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF0000 CCFF8F8FE9FFFFFFFFFF8F8FE9FF8F8FE9FFFFFFFFFF8F8FE9FF0000CCFF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF0000 CCFF0000CCFF8F8FE9FFFFFFFFFFFFFFFFFF8F8FE9FF0000CCFF0000CCFF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF0000 CCFF0000CCFF8F8FE9FFFFFFFFFFFFFFFFFF8F8FE9FF0000CCFF0000CCFF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF0000 CCFF8F8FE9FFFFFFFFFF8F8FE9FF8F8FE9FFFFFFFFFF8F8FE9FF0000CCFF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF3434 D6FFFFFFFFFF8F8FE9FF0000CCFF0000CCFF8F8FE9FFFFFFFFFF3636D7FF0000 CCFF6666E0FF0000A4FF00000000000000000000A4FF6666E0FF0000CCFF0404 CDFF4040D9FF0000CCFF0000CCFF0000CCFF0000CCFF3C3CD8FF0404CDFF0000 CCFF6666E0FF0000A4FF00000000000000000102A4FF6464DFFF0505CDFF0000 CCFF0000CCFF0000CCFF0000CCFF0000CCFF0000CCFF0000CCFF0000CCFF0505 CDFF6464DFFF0000A5FC00000000000000000607A3D53333C8FF6464DFFF6666 E0FF6666E0FF6666E0FF6666E0FF6666E0FF6666E0FF6666E0FF6666E0FF6464 DFFF3232C9FD0000A7C60000000000000000000092230202A6D30000A5FC0000 A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000A4FF0000 A5FC0000A6CE0000A51F00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BA8545FFB9843FFFB9843FFFBA8545FF0000000000000000000000000000 00000000000000000000000000000000000000000000B98544AFB98443E90000 0000B78140FFE9D4B4FFE9D4B4FFB78140FF00000000B98443E9B98544AF0000 000000000000000000000000000000000000B98544AFCCA26CFFD4B080FFB983 43FFCCA470FFC9984EFFC9984EFFCCA470FFB98343FFD4B080FFCCA26CFFB985 44AF00000000000000000000000000000000B78242ECD3AE7CFFE7CBA4FFEAD4 B2FFE8D0ADFFCF9D56FFCF9D56FFE8D0ADFFEAD4B2FFE7CBA4FFD3AE7CFFB782 42EC000000000000000000000000000000000000002FBA8547FFCE9949FFDAB2 76FFC9944BFFBE8943FFBE8943FFC9944BFFDAB276FFCE9949FFBA8546FF0000 002F000000000000000000000000B98442FFB6803EFFCEA673FFDBAE6EFFCB95 4BFFB88344FF6E4F2A616E4F2A61B88344FFCD974AFFDCAE6DFFD0A772FFB981 3CFFBE843FFF0000000000000000C5995FFFF1DCBBFFECD2ACFFD6A152FFC18C 49FF70502A620000000C0000000C704F2861C88D44FFDFA24CFFEACEA6FFF1D7 B2FFD79A51FF0000000000000000C38F4EFFE2B572FFDEB06AFFDBA658FFC595 55FF926935300000000000000000AA7333436A8399FFCD9F5FFF298DE2FF2B8F E1FFB48B5AFF3081D29100000000B98545FFB78242FFC8934EFFDFAB5EFFE4C4 94FFB68245DAB8813F3CBE823B2561809CFF37A8EFFF399DE3FF4CCFFDFF4AC7 F8FF3D9EE1FF45AAE4FF3982CB9F0000003300000033B78242FFE4B163FFEBC6 8EFFEACFA9FFD1A774FFD9A970FFCCBBA4FF399CE1FF4CCEFBFF3FB0EEFF40B1 EFFF4FCFFCFF429EDCFF16324E3100000000B98443E9DDBB8CFFEEC486FFE8B4 66FFF1CC96FFF7DCB5FFFFDEADFF288CDFFF4CCEFBFF3FAFEDFFFAB66DFFC775 1FCE41B1EFFF52D0F9FF3F92D5FF00000000AA7A3FBED2A76FFFD7A561FFB882 41FFD39F58FFEDB96BFFF7B962FF288DE3FF4CCFFCFF40B0EDFFC39F7BFF9876 53CB42B1EEFF52D0F9FF3F92D5FF0000000000000023AA7A3EBFB68243ED0000 0033B58142FFF5C378FFFCC371FFAD7E49FF3B9EE3FF4ECFFBFF41B0EDFF42B1 EDFF50CFFAFF439EDCFF1B3D5F520000000000000000000000230000002F0000 0000B88445FFC89451FFCE934AFF6D8192FF40A9EAFF429EDDFF52D0F8FF52D0 F8FF439EDCFF48AAE2FF3980C8B6000000000000000000000000000000000000 0000000000330000003300000033000000332D73BAAF1B3D60523F93D4FF3F93 D4FF102438413578BAC300000024000000000000000000000000000000000000 0000000000000000000000000000000000000000001F00000008000000330000 00330000000400000024000000000000000000000000000000000000000000D7 769500D66FF700D66BFF01D2A3FF00CDD8FF00CDD5F700CFD695000000000000 00000000000000000000FFFFFF00000000000000000057D7004659D500FF95EC B5FFFCFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEFEFF91E6EBFF03ACD6FF04B1 D7460000000000000000FFFFFF00000000004ED8004659D801FFEAF9D7FFFDFF EAFF7BFFCBFF49FFAAFF37FCD0FF50F9FFFF82FDFFFFF3FDFFFFDCF3F9FF10B4 D8FF05B6D84600000000FFFFFF00000000004AD600FFDAF8C9FFE5FFD0FF8EFF 33FF61FF86FF52FFB1FF5FFCDAFF5AFAFFFF50F0FEFF4ADEFFFFD5FAFFFFCDF1 F8FF07B4D6FF00000000FFFFFF00A1D70095C1E86DFFE2FFCEFF88FF3BFF94FF 49FFA4FF60FF72FFBDFF7CFCE1FF79FAFFFF74E4FFFF5CE1FFFF4BE1FFFFD3F9 FFFF71C3E8FF0088D795FFFFFF009CD600F8EAF9B4FFDEFF66FFBAFF46FFA2FF 64FFAEFF75FFA1FFA7FF92FFEAFF95F4FFFF89E9FFFF75E6FFFF4FCBFFFF6AC9 FFFFB5E0F9FF0088D5F8FFFFFF009BDB00FFECFFBBFFCEFF40FFD4FF50FFDBFF 6EFFCCFF8AFFC3FF99FFB1FFEAFFAFF2FFFF94E3FFFF74CFFEFF54C5FFFF44C1 FFFFBCEBFFFF008BD6FFFFFFFF00B7A10CFFF2E8B1FFE4CF44FFE9D664FFEFDD 80FFF5E499FFF5E9ACFFE7E6D9FFB3D9FFFF9DCDFCFF86C0FBFF6CB3FBFF4DA2 FBFFB6D8FDFF1670D0FFFFFFFF00D2651AFFFCC5A5FFFF9D5CFFFFA76CFFFFB3 85FFF0B48BFFEABA88FFFFB5DBFFBCAAFFFF98A9FEFF8CABF7FF779AF5FF698E F5FFACBEF6FF2A51CAFFFFFFFF00CF6817F9F3B481FFFFAD6AFFE69557FFC98C 59FFD29C67FFF09C9AFFFF98D4FFFC97E6FF7A85FFFF7074FFFF6882F9FF769D F7FF8BA7EDFF2852C8F9FFFFFF00BB5F15A9CF8246FFCB9366FFB26B32FFBD7D 43FFC88E58FFFF76A9FFFF7EC5FFFF7BD8FFAD74EFFF5661FFFF4B4BFFFF777B FFFF546FD9FF244DB3A9FFFFFF000000001E732C00FFA36A3DFFBC7F4DFFB273 2FFFE96178FFFF5999FFFF62B7FFFF5DD1FFFF56CBFF4A51FFFF5C63FFFF4E4E ECFF0A06D8FF0000001EFFFFFF00000000004D1F006B7D3600FF9C6128FFC071 49FFFF3D92FFFF4189FFFF45AAFFFF43CAFFFF44C4FFBA51E0FF3243EDFF0D12 D7FF02018F6B00000000FFFFFF00000000000000000E5124006B753C00FFCC23 54FFF42677FFF9317AFFF8369FFFF931BEFFF429B1FFEF1B9AFF1811D4FF0006 8F6B0000000E00000000FFFFFF0000000000000000000000000E00000033C100 4CAAD60051F9D60551FFD60972FFD60297FFD60092F9C5007FAA000000330000 000E0000000000000000FFFFFF00000000000000000000000000000000000000 001E00000031000000330000003300000033000000310000001E000000000000 00000000000000000000FFFFFF00929292EF8E8F8FFF8D8D8EFF8D8D8EFF8D8E 8EFF8D8D8EFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D8DFF8C8C 8DFF8C8D8DFF8E8E8EFF929292EF8E8F8FFFFFFFFFFFF7F7FAFFF7F9FDFFF7F9 FEFFF7F7FAFFF5F4F5FFF5F3F3FFF5F3F3FFF5F3F3FFF5F3F3FFF5F2F2FFF4F2 F2FFF4F2F2FFFFFFFFFF8E8E8EFF8C8D8DFFFFFFFFFFC4A47FFFAE7A41FFAF7B 41FFC5A581FFE2E2E3FFE2E0E0FFE2E0DFFFE1DFDEFFE0DEDDFFDEDCDBFFDDDB D9FFDCDAD9FFFFFEFEFF8C8C8CFF8C8D8DFFFFFFFFFF9F6931FFF0DABCFFE2BE 91FFA06A33FFE8E9ECFF626364FFA2A3A3FFA1A1A1FF9E9F9FFFE2E0DFFFE0DE DDFFE0DDDCFFFCFDFBFF8C8C8CFF8C8C8DFFFFFFFFFFBC9C7AFFA36E37FFA26D 36FFBC9C7BFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFCFBFBFF8C8C8CFF8C8C8CFFFEFEFFFFEFEFF2FF858A8EFFF1F4 FAFFEDF1F7FFECEFF4FFEBEDF2FFEAEAEDFFE8E7E8FFE8E6E6FFE8E5E6FFE7E5 E5FFE7E5E5FFFCFBFBFF8C8C8CFF8C8C8CFFFDFCFCFFF1F1F0FF868788FFF7FA FCFFCBAB89FFAE7A40FFAD7A40FFC8A885FFEFF1F2FFEFEFEEFFEFEEEDFFEFEE ECFFEEEDECFFFDFCFCFF8C8C8CFF8B8C8CFFFEFDFDFFF5F4F3FF878788FF878B 8FFFA26C34FFF0DABCFFE1BD90FF9E6931FFF5F8FBFF5F6061FFA0A0A0FF9E9F 9FFF9C9D9DFFFFFEFEFF8C8C8CFF8B8B8BFFFFFEFEFFF8F7F6FF858585FFFFFF FFFFC2A280FF9F6A34FF9F6A34FFC0A07EFFF5F7F9FFF6F5F4FFF5F4F3FFF5F4 F2FFF4F3F2FFFFFEFEFF8C8C8CFF8B8B8BFFFFFFFFFFFAFAFAFF838383FFFDFF FFFFFAFFFFFFFCFFFFFFFCFFFFFFF9FEFFFFF4F7F9FFF4F4F4FFF3F4F4FFF3F3 F3FFF4F4F4FFFFFEFEFF8B8B8BFF8B8B8BFFFFFFFFFFFEFEFEFF838384FFFFFF FFFFCFB08CFFAD7941FFAD7941FFCCAD8AFFFBFEFFFFFBFCFCFFFBFBFBFFFAFA FAFFFAFAFAFFFFFFFFFF8B8B8BFF8B8B8BFFFFFFFFFFFFFFFFFF808182FF8387 8AFFA16A32FFF0D9BBFFE0BC8FFF9D672FFFFFFFFFFF5C5D5DFF9E9E9EFF9C9C 9CFF9A9A9AFFFFFFFFFF8B8B8BFF8B8B8BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFC6A584FF9E6932FF9E6932FFC4A482FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8B8B8BFF8D8D8DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8D8D8DFF868686C08D8D8DFF8A8A8AFF8A8A8AFF8A8A 8BFF8B8B8CFF8B8C8DFF8B8C8DFF8B8B8CFF8A8A8BFF8A8A8AFF8A8A8AFF8A8A 8AFF8A8A8AFF8D8D8DFF868686C0000000000000003300000033000000330000 0033000000330000003300000033000000330000003300000033000000330000 0033000000330000003300000000929292EF8E8F8FFF8D8D8EFF8D8D8EFF8D8E 8EFF8D8D8EFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D8DFF8C8C 8DFF8C8D8DFF8E8E8EFF929292EF8E8F8FFFFFFFFFFFF7F7FAFFF7F9FDFFF7F9 FEFFF7F7FAFFF5F4F5FFF5F3F3FFF5F3F3FFF5F3F3FFF5F3F3FFF5F2F2FFF4F2 F2FFF4F2F2FFFFFFFFFF8E8E8EFF8C8D8DFFFFFFFFFFC4A47FFFAE7A41FFAF7B 41FFC5A581FFE2E2E3FFE2E0E0FFE2E0DFFFE1DFDEFFE0DEDDFFDEDCDBFFDDDB D9FFDCDAD9FFFFFEFEFF8C8C8CFF8C8D8DFFFFFFFFFF9F6931FFF0DABCFFE2BE 91FFA06A33FFE8E9ECFF626364FFA2A3A3FFA1A1A1FF9E9F9FFFE2E0DFFFE0DE DDFFE0DDDCFFFCFDFBFF8C8C8CFF8C8C8DFFFFFFFFFFBC9C7AFFA36E37FFA26D 36FFBC9C7BFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFCFBFBFF8C8C8CFF8C8C8CFFFEFEFFFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFCFBFBFF8C8C8CFF8C8C8CFFFDFCFCFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFDFCFCFF8C8C8CFF8B8C8CFFFEFDFDFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFFFEFEFF8C8C8CFF8B8B8BFFFFFEFEFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFFFEFEFF8C8C8CFF8B8B8BFFFFFFFFFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFFFEFEFF8B8B8BFF8B8B8BFFFFFFFFFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFFFFFFFF8B8B8BFF8B8B8BFFFFFFFFFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFFFFFFFF8B8B8BFF8B8B8BFFFFFFFFFFE9EAEEFFE9E8E9FFE9E7 E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFE6E4E4FFE4E2E3FFE3E1 E1FFE3E1E1FFFFFFFFFF8B8B8BFF8D8D8DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8D8D8DFF868686C08D8D8DFF8A8A8AFF8A8A8AFF8A8A 8BFF8B8B8CFF8B8C8DFF8B8C8DFF8B8B8CFF8A8A8BFF8A8A8AFF8A8A8AFF8A8A 8AFF8A8A8AFF8D8D8DFF868686C0000000000000003300000033000000330000 0033000000330000003300000033000000330000003300000033000000330000 0033000000330000003300000000 } end object pmCaseSensitiveOrNot: TPopupMenu Images = imgListButton left = 80 top = 104 object pmiNotCaseSensitive: TMenuItem AutoCheck = True Caption = 'Search is not case sensitive' Checked = True Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BDECBDFF00000000000000000000000000000000000000000000000054CF 54FF114011FF227922FF00000000000000001C671CFF114011FF33B833FF1C67 1CFF114011FF114011FF165116FF114011FFBDECBDFF0000000000000000D3F2 D3FF114011FF114011FF114011FF114011FF114011FF114011FF68D568FF1140 11FF1C671CFF93E093FF114011FF114011FF00000000000000000000000054CF 5400227922FF114011FF114011FF114011FF114011FF1C671CFF33B83300288F 28FF114011FF165116FF114011FF114011FFBDECBD000E0E890000000000D3F2 D30068D568FF114011FF33B833FF2DA42DFF114011FF40C940FFD3F2D3FF54CF 54FF33B833FF68D568FF114011FF114011FF9090F3000C0C7700000000000000 0000D3F2D3FF114011FF165116FF165116FF114011FFBDECBDFF0C0C77001C67 1CFF114011FF114011FF114011FF227922FF0E0E89000C0C7700000000000000 000068D56800227922FF114011FF114011FF1C671CFF40C94000D3F2D30054CF 540093E093FF54CF54FF93E093FF114011006464EF000C0C7700000000000000 0000D3F2D30068D568FF114011FF114011FF68D568FFBDECBD000E0E89001C67 1C00114011001140110011401100227922000C0C77000C0C7700000000000000 00000000000022792200A7E6A7FFA7E6A7FF1C671C000C0C77000C0C77001010 9F0093E0930054CF540093E093009090F3005050ED009090F300000000000000 00000000000068D56800114011001140110068D568000C0C77000C0C77006464 EF0054CF54FF54CF54FF54CF54FF54CF54FF54CF54FF00000000000000000000 00000000000000000000A7E6A700A7E6A70000000000A4A4F500A4A4F5001140 11FF114011FF114011FF114011FF114011FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054CF54FF54CF54FF54CF54FF54CF54FF54CF54FF00000000000000000000 0000000000000000000000000000000000000000000000000000000000001140 11FF114011FF114011FF114011FF114011FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } GroupIndex = 1 ImageIndex = 0 RadioItem = True OnClick = pmiCaseSensitiveOrNotClick end object pmiCaseSensitive: TMenuItem AutoCheck = True Caption = 'Search is case sensitive' Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BBBBF8FF0000000000000000000000000000000000000000000000005050 EDFF0C0C77FF1212B3FF000000000000000010109FFF0C0C77FF2323E8FF1010 9FFF0C0C77FF0C0C77FF0E0E89FF0C0C77FFBBBBF8FF0000000000000000D1D1 FAFF0C0C77FF0C0C77FF0C0C77FF0C0C77FF0C0C77FF0C0C77FF6464EFFF0C0C 77FF10109FFF9090F3FF0C0C77FF0C0C77FF0000000000000000000000000000 00001212B3FF0C0C77FF0C0C77FF0C0C77FF0C0C77FF10109FFF000000001414 C9FF0C0C77FF0E0E89FF0C0C77FF0C0C77FF0000000000000000000000000000 00006464EFFF0C0C77FF2323E8FF1616DDFF0C0C77FF3A3AEBFFD1D1FAFF5050 EDFF2323E8FF6464EFFF0C0C77FF0C0C77FF0000000000000000000000000000 0000D1D1FAFF0C0C77FF0E0E89FF0E0E89FF0C0C77FFBBBBF8FF000000001010 9FFF0C0C77FF0C0C77FF0C0C77FF1212B3FF0000000000000000000000000000 0000000000001212B3FF0C0C77FF0C0C77FF10109FFF00000000000000000000 00009090F3FF5050EDFF9090F3FF000000000000000000000000000000000000 0000000000006464EFFF0C0C77FF0C0C77FF6464EFFF00000000000000000000 00000000000000000000000000005050EDFF0000000000000000000000000000 00000000000000000000A4A4F5FFA4A4F5FF0000000000000000000000000000 000000000000000000000C0C77FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000005050EDFF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C0C77FF5050EDFF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C0C77FF5050EDFF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C0C77FF5050EDFF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C0C77FF5050EDFF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000C0C77FF000000000000000000000000 } GroupIndex = 1 ImageIndex = 1 RadioItem = True OnClick = pmiCaseSensitiveOrNotClick end end object pmShowWholeBranchIfMatchOrNot: TPopupMenu Images = imgListButton left = 104 top = 264 object pmiShowWholeBranchIfMatch: TMenuItem AutoCheck = True Caption = 'If searched string is found in a branch name, show the whole branch even if elements don''t match' Checked = True Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 00000000003000000033000000330000002F0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008B4CF2008A4AFF008A4AFF008B4CF10000000A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008949FF00E7A7FF00E7A7FF008949FF005E334C00000000000000000000 0000000000000000002300000033000000000000000000000000000000000000 0000008847FF08E1A6FF00DFA1FF008544FF007D43B500000021000000000000 000000000000008147C1008C4BFF000000330000000000000000000000000000 0000008747FF16DFABFF00D89EFF00C890FF009657FF007C42B6000000330000 003300000033008847FF54DAB0FF008746FF0000003300000000000000000000 0000008746FF23DFB1FF00D39CFF20D5ADFF04D3A5FF00AB73FF008744FF0088 46FF008644FF00B97FFF00D8A0FF65D7B3FF008744FF00000033000000000000 0000008846FF30DFB6FF00D19DFF1CAB7AFF42D9BEFF20D1B0FF00D09FFF00D0 A0FF00CF9FFF00CD9CFF00CB9AFF00CD9CFF74DABDFF008A48FF000000000000 0000008845FF3EDFBCFF00D19FFF00843FFF0F9960CF4ACBB0FF42D9BEFF42D9 BEFF42D9BEFF00C49AFF00C49AFF00C59CFF86DEC8FF008A48FF000000000000 0000008845FF4BE0C1FF00CFA0FF008744FF00000000008946A7008845FF0087 44FF008641FF00AB7DFF00C09EFF9BE0D0FF008743FF00000000000000000000 0000008844FF59E1C8FF00CBA2FF008846FF0000000000000000000000000000 000000000000008945FFA4E4D9FF008743FF0000000000000000000000300000 0033008742FF6AE2CCFF00C9A1FF008744FF0000003300000030000000000000 000000000000008D4CB1008C49FF000000000000000000000000008B4BF20089 46FF00AE7FFF00C39EFF00C39EFF00AE80FF008946FF008B4BF2000000000000 0000000000000000000000000000000000000000000000000000008C4AFF82DC CAFF00C1A0FF00BE9BFF00BE9BFF00C1A0FF83DCCAFF008C4AFF000000000000 0000000000000000000000000000000000000000000000000000000000000088 44FF8EDBCBFF00B99DFF00B99DFF8EDBCBFF008844FF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008742FF9AE0D3FF9AE0D3FF008742FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000008A47FF008A47FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } GroupIndex = 3 ImageIndex = 5 RadioItem = True OnClick = pmiShowWholeBranchIfMatchOrNotClick end object pmiNotShowWholeBranchIfMatch: TMenuItem AutoCheck = True Caption = 'Don''t show the branch content "just" because the searched string is found in the branche name' Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 00000000003000000033000000330000002F0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008B4CF2008A4AFF008A4AFF008B4CF10000000A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008949FF00E7A7FF00E7A7FF008949FF2F2F2F4C00000000000000000000 0000000000000000002300000033000000000000000000000000000000000000 0000008847FF08E1A6FF00DFA1FF008544FF3E3E3EB500000021000000000000 000000000000404040C1464646FF000000330000000000000000000000000000 0000008747FF16DFABFF00D89EFF00C890FF4B4B4BFF3E3E3EB6000000330000 003300000033444444FF979797FF434343FF0000003300000000000000000000 0000008746FF23DFB1FF00D39CFF20D5ADFF6B6B6BFF555555FF434343FF4444 44FF434343FF5C5C5CFF6C6C6CFF9E9E9EFF434343FF00000033000000000000 0000008846FF30DFB6FF00D19DFF1CAB7AFF8D8D8DFF787878FF686868FF6868 68FF676767FF666666FF656565FF666666FFA7A7A7FF454545FF000000000000 0000008845FF3EDFBCFF00D19FFF04803FFF545454CF8A8A8AFF8D8D8DFF8D8D 8DFF8D8D8DFF626262FF626262FF626262FFB2B2B2FF454545FF000000000000 0000008845FF4BE0C1FF00CFA0FF068144FF00000000444444A7444444FF4343 43FF434343FF555555FF606060FFBDBDBDFF434343FF00000000000000000000 0000008844FF59E1C8FF00CBA2FF008846FF0000000000000000000000000000 000000000000444444FFC4C4C4FF434343FF0000000000000000000000300000 0033008742FF6AE2CCFF00C9A1FF008744FF0000003300000030000000000000 000000000000464646B1464646FF000000000000000000000000008B4BF20089 46FF00AE7FFF00C39EFF00C39EFF00AE80FF008946FF008B4BF2000000000000 0000000000000000000000000000000000000000000000000000008C4AFF82DC CAFF00C1A0FF00BE9BFF00BE9BFF00C1A0FF83DCCAFF008C4AFF000000000000 0000000000000000000000000000000000000000000000000000000000000088 44FF8EDBCBFF00B99DFF00B99DFF8EDBCBFF008844FF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000008742FF9AE0D3FF9AE0D3FF008742FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000008A47FF008A47FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } GroupIndex = 3 ImageIndex = 4 RadioItem = True OnClick = pmiShowWholeBranchIfMatchOrNotClick end end object pmIgnoreAccentsOrNot: TPopupMenu Images = imgListButton left = 80 top = 168 object pmiIgnoreAccents: TMenuItem AutoCheck = True Caption = 'Search ignore accents and ligatures' Checked = True Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 200000000000000400006400000064000000000000000000000022C7220023C8 23E923C823FF23C823E923C8236C23C923FF23C723910000000022C7220023C8 23E923C823FF23C823E923C8236C23C923FF23C723910000000023C823F023C9 23EF23C8239623C823B123C823F623C923FF25BE251726DE260723C823F023C9 23EF23C8239623C823B123C823F623C923FF25BE25170000000022C822FF23C9 23D922C8224223C8231C23C923C723C923FF28C9280926DE260822C822FF23C9 23D922C8224223C8231C23C923C723C923FF28C928090000000022C8228923C8 23FF23C823EE23C823CC23C823EE23C923FF24D2240925D9250322C8228923C8 23FF23C823EE23C823CC23C823EE23C923FF24D22409000000000000000021C5 213023C8238422C822CE23C823FA23C823FF24CE2409000000000000000021C5 213023C8238422C822CE23C823FA23C823FF24CE24090000000022C822F123C8 23CD23C8232224C8240B23C923C922C922FF26DE260823D0230822C822F123C8 23CD23C8232224C8240B23C923C922C922FF26DE26080000000022C8229C23C8 23FF23C823FF23C823FF23C823FF23C823C928E328062AF82A0422C8229C23C8 23FF23C823FF23C823FF23C823FF23C823C928E328060000000028BD280923C8 238422C822CD22C722D422C822A622C82220000000000000000028BD280923C8 238422C822CB22C722D122C822A622C822200000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000022C922272AFF2A01000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000025CF250423C8 233E22C822B422C822CB23CA23270000000000000000000000000000000023C8 23FF23C823FF23C823FF23C823FF23C823FF000000000000000026D8260422C8 223E22C9227923C7233C23B523020000000000000000000000000000000023C8 238422C822CD22C722D422C822A6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000023C8 23FF23C823FF23C823FF23C823FF23C823FF0000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000023C8 238422C822CD22C722D422C822A6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } GroupIndex = 2 ImageIndex = 2 RadioItem = True OnClick = pmiIgnoreAccentsOrNotClick end object pmiNotIgnoreAccents: TMenuItem AutoCheck = True Caption = 'Search is strict regarding accents and ligatures' Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000081BED00081B EFE9081BEFFF081BEFE9081BEF6C081BEFFF081BED9100000000081BED00081B EFE9081BEFFF081BEFE9081BEF6C081BEFFF081BED9100000000081BEFF0081B EFEF081BEF96081BEFB1081BEFF6081BEFFF081AE3171B2DF607081BEFF0081B EFEF081BEF96081BEFB1081BEFF6081BEFFF081AE31700000000081BEFFF081B EFD9081BEF42081BEF1C081BEFC7081BEFFF091BF0091B2DF608081BEFFF081B EFD9081BEF42081BEF1C081BEFC7081BEFFF091BF00900000000081BEF89081B EFFF081BEFEE081BEFCC081BEFEE081BEFFF0E20F5091527F603081BEF89081B EFFF081BEFEE081BEFCC081BEFEE081BEFFF0E20F5090000000000000000081B EB30081BEF84081BEFCE081BEFFA081BEFFF091CF4090000000000000000081B EB30081BEF84081BEFCE081BEFFA081BEFFF091CF40900000000081BEFF1081B EFCD081BEF22081BEF0B081BEFC9081BEFFF1B2DF6080A1DF508081BEFF1081B EFCD081BEF22081BEF0B081BEFC9081BEFFF1B2DF60800000000081BEF9C081B EFFF081BEFFF081BEFFF081BEFFF081BEFC92334F6063C4BF704081BEF9C081B EFFF081BEFFF081BEFFF081BEFFF081BEFC92334F60600000000081AE309081B EF84081BEFCD081BEDD4081BEFA6081BEF200000000000000000081AE309081B EF84081BEFCB081BEDD1081BEFA6081BEF200000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000081BEF274352F801000000000000000000000000000000000000 000000000000081BEF3E081BEFFF0000000000000000000000000A1DF504081B EF3E081BEFB4081BEFCB091BF027000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000001527F604081B EF3E081BEF79081BED3C0819D902000000000000000000000000000000000000 000000000000081BEF3E081BEFFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000081BEF3E081BEFFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000081BEF3E081BEFFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000081BEF3E081BEFFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } GroupIndex = 2 ImageIndex = 3 RadioItem = True OnClick = pmiIgnoreAccentsOrNotClick end end object pmFullExpandOrNot: TPopupMenu Images = imgListButton left = 112 top = 344 object pmiFullExpand: TMenuItem AutoCheck = True Caption = 'Full expand' Checked = True Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0033000000330000003300000033000000330000003300000033000000330000 0033000000330000003300000033000000330000003300000000868686C08D8D 8DFF8A8A8AFF8A8A8AFF8A8A8BFF8B8B8CFF8B8C8DFF8B8C8DFF8B8B8CFF8A8A 8BFF8A8A8AFF8A8A8AFF8A8A8AFF8A8A8AFF8D8D8DFF868686C08D8D8DFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D8D8DFF8B8B8BFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFC6A584FF9E6932FF9E6932FFC4A482FFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B8B8BFF8B8B8BFFFFFF FFFFFFFFFFFF808182FF83878AFFA16A32FFF0D9BBFFE0BC8FFF9D672FFFFFFF FFFF5C5D5DFF9E9E9EFF9C9C9CFF9A9A9AFFFFFFFFFF8B8B8BFF8B8B8BFFFFFF FFFFFEFEFEFF838384FFFFFFFFFFCFB08CFFAD7941FFAD7941FFCCAD8AFFFBFE FFFFFBFCFCFFFBFBFBFFFAFAFAFFFAFAFAFFFFFFFFFF8B8B8BFF8B8B8BFFFFFF FFFFFAFAFAFF838383FFFDFFFFFFFAFFFFFFFCFFFFFFFCFFFFFFF9FEFFFFF4F7 F9FFF4F4F4FFF3F4F4FFF3F3F3FFF4F4F4FFFFFEFEFF8B8B8BFF8B8B8BFFFFFE FEFFF8F7F6FF858585FFFFFFFFFFC2A280FF9F6A34FF9F6A34FFC0A07EFFF5F7 F9FFF6F5F4FFF5F4F3FFF5F4F2FFF4F3F2FFFFFEFEFF8C8C8CFF8B8C8CFFFEFD FDFFF5F4F3FF878788FF878B8FFFA26C34FFF0DABCFFE1BD90FF9E6931FFF5F8 FBFF5F6061FFA0A0A0FF9E9F9FFF9C9D9DFFFFFEFEFF8C8C8CFF8C8C8CFFFDFC FCFFF1F1F0FF868788FFF7FAFCFFCBAB89FFAE7A40FFAD7A40FFC8A885FFEFF1 F2FFEFEFEEFFEFEEEDFFEFEEECFFEEEDECFFFDFCFCFF8C8C8CFF8C8C8CFFFEFE FFFFEFEFF2FF858A8EFFF1F4FAFFEDF1F7FFECEFF4FFEBEDF2FFEAEAEDFFE8E7 E8FFE8E6E6FFE8E5E6FFE7E5E5FFE7E5E5FFFCFBFBFF8C8C8CFF8C8C8DFFFFFF FFFFBC9C7AFFA36E37FFA26D36FFBC9C7BFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6 E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFCFBFBFF8C8C8CFF8C8D8DFFFFFF FFFF9F6931FFF0DABCFFE2BE91FFA06A33FFE8E9ECFF626364FFA2A3A3FFA1A1 A1FF9E9F9FFFE2E0DFFFE0DEDDFFE0DDDCFFFCFDFBFF8C8C8CFF8C8D8DFFFFFF FFFFC4A47FFFAE7A41FFAF7B41FFC5A581FFE2E2E3FFE2E0E0FFE2E0DFFFE1DF DEFFE0DEDDFFDEDCDBFFDDDBD9FFDCDAD9FFFFFEFEFF8C8C8CFF8E8F8FFFFFFF FFFFF7F7FAFFF7F9FDFFF7F9FEFFF7F7FAFFF5F4F5FFF5F3F3FFF5F3F3FFF5F3 F3FFF5F3F3FFF5F2F2FFF4F2F2FFF4F2F2FFFFFFFFFF8E8E8EFF929292EF8E8F 8FFF8D8D8EFF8D8D8EFF8D8E8EFF8D8D8EFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D 8DFF8C8D8DFF8C8D8DFF8C8C8DFF8C8D8DFF8E8E8EFF929292EF } GroupIndex = 4 ImageIndex = 9 RadioItem = True OnClick = pmiFullExpandOrNotClick end object pmiFullCollapse: TMenuItem AutoCheck = True Caption = 'Full collapse' Bitmap.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 0033000000330000003300000033000000330000003300000033000000330000 0033000000330000003300000033000000330000003300000000868686C08D8D 8DFF8A8A8AFF8A8A8AFF8A8A8BFF8B8B8CFF8B8C8DFF8B8C8DFF8B8B8CFF8A8A 8BFF8A8A8AFF8A8A8AFF8A8A8AFF8A8A8AFF8D8D8DFF868686C08D8D8DFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D8D8DFF8B8B8BFFFFFF FFFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFFFFFFFF8B8B8BFF8B8B8BFFFFFF FFFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFFFFFFFF8B8B8BFF8B8B8BFFFFFF FFFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFFFFFFFF8B8B8BFF8B8B8BFFFFFF FFFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFFFEFEFF8B8B8BFF8B8B8BFFFFFE FEFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFFFEFEFF8C8C8CFF8B8C8CFFFEFD FDFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFFFEFEFF8C8C8CFF8C8C8CFFFDFC FCFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFDFCFCFF8C8C8CFF8C8C8CFFFEFE FFFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1 E1FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFCFBFBFF8C8C8CFF8C8C8DFFFFFF FFFFBC9C7AFFA36E37FFA26D36FFBC9C7BFFE9EAEEFFE9E8E9FFE9E7E7FFE8E6 E6FFE6E4E4FFE4E2E3FFE3E1E1FFE3E1E1FFFCFBFBFF8C8C8CFF8C8D8DFFFFFF FFFF9F6931FFF0DABCFFE2BE91FFA06A33FFE8E9ECFF626364FFA2A3A3FFA1A1 A1FF9E9F9FFFE2E0DFFFE0DEDDFFE0DDDCFFFCFDFBFF8C8C8CFF8C8D8DFFFFFF FFFFC4A47FFFAE7A41FFAF7B41FFC5A581FFE2E2E3FFE2E0E0FFE2E0DFFFE1DF DEFFE0DEDDFFDEDCDBFFDDDBD9FFDCDAD9FFFFFEFEFF8C8C8CFF8E8F8FFFFFFF FFFFF7F7FAFFF7F9FDFFF7F9FEFFF7F7FAFFF5F4F5FFF5F3F3FFF5F3F3FFF5F3 F3FFF5F3F3FFF5F2F2FFF4F2F2FFF4F2F2FFFFFFFFFF8E8E8EFF929292EF8E8F 8FFF8D8D8EFF8D8D8EFF8D8E8EFF8D8D8EFF8C8D8DFF8C8D8DFF8C8D8DFF8C8D 8DFF8C8D8DFF8C8D8DFF8C8C8DFF8C8D8DFF8E8E8EFF929292EF } GroupIndex = 4 ImageIndex = 10 RadioItem = True OnClick = pmiFullExpandOrNotClick end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ftreeviewmenu.lrj��������������������������������������������������������������0000644�0001750�0000144�00000006762�14743153644�017006� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":69493525,"name":"tfrmtreeviewmenu.caption","sourcebytes":[84,114,101,101,32,86,105,101,119,32,77,101,110,117],"value":"Tree View Menu"}, {"hash":160185434,"name":"tfrmtreeviewmenu.lblsearchingentry.caption","sourcebytes":[83,101,108,101,99,116,32,121,111,117,114,32,104,111,116,32,100,105,114,101,99,116,111,114,121,58],"value":"Select your hot directory:"}, {"hash":122361781,"name":"tfrmtreeviewmenu.tbcancelandquit.hint","sourcebytes":[67,108,111,115,101,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117],"value":"Close Tree View Menu"}, {"hash":45842709,"name":"tfrmtreeviewmenu.tbconfigurationtreeviewmenus.hint","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117],"value":"Configuration of Tree View Menu"}, {"hash":255739843,"name":"tfrmtreeviewmenu.tbconfigurationtreeviewmenuscolors.hint","sourcebytes":[67,111,110,102,105,103,117,114,97,116,105,111,110,32,111,102,32,84,114,101,101,32,86,105,101,119,32,77,101,110,117,32,67,111,108,111,114,115],"value":"Configuration of Tree View Menu Colors"}, {"hash":50447813,"name":"tfrmtreeviewmenu.pminotcasesensitive.caption","sourcebytes":[83,101,97,114,99,104,32,105,115,32,110,111,116,32,99,97,115,101,32,115,101,110,115,105,116,105,118,101],"value":"Search is not case sensitive"}, {"hash":219944789,"name":"tfrmtreeviewmenu.pmicasesensitive.caption","sourcebytes":[83,101,97,114,99,104,32,105,115,32,99,97,115,101,32,115,101,110,115,105,116,105,118,101],"value":"Search is case sensitive"}, {"hash":62671032,"name":"tfrmtreeviewmenu.pmishowwholebranchifmatch.caption","sourcebytes":[73,102,32,115,101,97,114,99,104,101,100,32,115,116,114,105,110,103,32,105,115,32,102,111,117,110,100,32,105,110,32,97,32,98,114,97,110,99,104,32,110,97,109,101,44,32,115,104,111,119,32,116,104,101,32,119,104,111,108,101,32,98,114,97,110,99,104,32,101,118,101,110,32,105,102,32,101,108,101,109,101,110,116,115,32,100,111,110,39,116,32,109,97,116,99,104],"value":"If searched string is found in a branch name, show the whole branch even if elements don't match"}, {"hash":12232485,"name":"tfrmtreeviewmenu.pminotshowwholebranchifmatch.caption","sourcebytes":[68,111,110,39,116,32,115,104,111,119,32,116,104,101,32,98,114,97,110,99,104,32,99,111,110,116,101,110,116,32,34,106,117,115,116,34,32,98,101,99,97,117,115,101,32,116,104,101,32,115,101,97,114,99,104,101,100,32,115,116,114,105,110,103,32,105,115,32,102,111,117,110,100,32,105,110,32,116,104,101,32,98,114,97,110,99,104,101,32,110,97,109,101],"value":"Don't show the branch content \"just\" because the searched string is found in the branche name"}, {"hash":253218323,"name":"tfrmtreeviewmenu.pmiignoreaccents.caption","sourcebytes":[83,101,97,114,99,104,32,105,103,110,111,114,101,32,97,99,99,101,110,116,115,32,97,110,100,32,108,105,103,97,116,117,114,101,115],"value":"Search ignore accents and ligatures"}, {"hash":152606995,"name":"tfrmtreeviewmenu.pminotignoreaccents.caption","sourcebytes":[83,101,97,114,99,104,32,105,115,32,115,116,114,105,99,116,32,114,101,103,97,114,100,105,110,103,32,97,99,99,101,110,116,115,32,97,110,100,32,108,105,103,97,116,117,114,101,115],"value":"Search is strict regarding accents and ligatures"}, {"hash":109225636,"name":"tfrmtreeviewmenu.pmifullexpand.caption","sourcebytes":[70,117,108,108,32,101,120,112,97,110,100],"value":"Full expand"}, {"hash":166748533,"name":"tfrmtreeviewmenu.pmifullcollapse.caption","sourcebytes":[70,117,108,108,32,99,111,108,108,97,112,115,101],"value":"Full collapse"} ]} ��������������doublecmd-1.1.22/src/ftreeviewmenu.pas��������������������������������������������������������������0000644�0001750�0000144�00000153550�14743153644�017000� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Menu offered to user via a Tree View look where user might type sequence of letters Copyright (C) 2016-2020 Alexander Koblov (alexx2000@mail.ru) 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 } unit fTreeViewMenu; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, StdCtrls, ExtCtrls, Menus, Types, LMessages, //DC kastoolitems, KASToolBar, uKASToolItemsExtended; type // *IMPORTANT: "tvmcLASTONE" always must be the last one as it is used to give the number of element here. tvmContextMode = (tvmcHotDirectory, tvmcFavoriteTabs, tvmcDirHistory, tvmcViewHistory, tvmcKASToolBar, tvmcMainMenu, tvmcCommandLineHistory, tvmcFileSelectAssistant, tvmcLASTONE); TTreeViewMenuOptions = record CaseSensitive: boolean; IgnoreAccents: boolean; ShowWholeBranchIfMatch: boolean; end; { TTreeMenuItem } // In out TreeView, the "pointer" will actually point this type of element where the "FPointerSourceData" might actually point the actual vital items user actually choose. TTreeMenuItem = class private FPointerSourceData: Pointer; FTypeDispatcher: integer; FSecondaryText: string; FKeyboardShortcut: char; public constructor Create(PointerSourceData: Pointer); property PointerSourceData: Pointer read FPointerSourceData; property KeyboardShortcut: char read FKeyboardShortcut write FKeyboardShortcut; property SecondaryText: string read FSecondaryText write FSecondaryText; property TypeDispatcher: integer read FTypeDispatcher write FTypeDispatcher; end; { TTreeViewMenuGenericRoutineAndVarHolder } // Everything could have been placed into the "TfrmTreeViewMenu" form. // But this "sub-object" exists just to allow the configuration form to use the *same* routine to draw the tree so the test color could be tested this way. TTreeViewMenuGenericRoutineAndVarHolder = class(TObject) private FContextMode: tvmContextMode; FCaseSensitive: boolean; FIgnoreAccents: boolean; FShowWholeBranchIfMatch: boolean; FSearchingText: string; FShowShortcut: boolean; FMayStopOnNode: boolean; FBackgroundColor: TColor; FShortcutColor: TColor; FNormalTextColor: TColor; FSecondaryTextColor: TColor; FFoundTextColor: TColor; FUnselectableTextColor: TColor; FCursorColor: TColor; FShortcutUnderCursor: TColor; FNormalTextUnderCursor: TColor; FSecondaryTextUnderCursor: TColor; FFoundTextUnderCursor: TColor; FUnselectableUnderCursor: TColor; public function AddTreeViewMenuItem(ATreeView: TTreeView; ParentNode: TTreeNode; const S: string; const SecondaryText: string = ''; TypeDispatcher: integer = 0; Data: Pointer = nil): TTreeNode; procedure TreeViewMenuAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var {%H-}PaintImages, DefaultDraw: boolean); property ContextMode: tvmContextMode read FContextMode write FContextMode; property CaseSensitive: boolean read FCaseSensitive write FCaseSensitive; property IgnoreAccents: boolean read FIgnoreAccents write FIgnoreAccents; property ShowWholeBranchIfMatch: boolean read FShowWholeBranchIfMatch write FShowWholeBranchIfMatch; property SearchingText: string read FSearchingText write FSearchingText; property ShowShortcut: boolean read FShowShortcut write FShowShortcut; property MayStopOnNode: boolean read FMayStopOnNode write FMayStopOnNode; property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor; property ShortcutColor: TColor read FShortcutColor write FShortcutColor; property NormalTextColor: TColor read FNormalTextColor write FNormalTextColor; property SecondaryTextColor: TColor read FSecondaryTextColor write FSecondaryTextColor; property FoundTextColor: TColor read FFoundTextColor write FFoundTextColor; property UnselectableTextColor: TColor read FUnselectableTextColor write FUnselectableTextColor; property CursorColor: TColor read FCursorColor write FCursorColor; property ShortcutUnderCursor: TColor read FShortcutUnderCursor write FShortcutUnderCursor; property NormalTextUnderCursor: TColor read FNormalTextUnderCursor write FNormalTextUnderCursor; property SecondaryTextUnderCursor: TColor read FSecondaryTextUnderCursor write FSecondaryTextUnderCursor; property FoundTextUnderCursor: TColor read FFoundTextUnderCursor write FFoundTextUnderCursor; property UnselectableUnderCursor: TColor read FUnselectableUnderCursor write FUnselectableUnderCursor; end; { TfrmTreeViewMenu } TfrmTreeViewMenu = class(TForm) pnlAll: TPanel; lblSearchingEntry: TLabel; edSearchingEntry: TEdit; tvMainMenu: TTreeView; tbOptions: TToolBar; tbCaseSensitive: TToolButton; tbIgnoreAccents: TToolButton; tbShowWholeBranchOrNot: TToolButton; tbDivider: TToolButton; tbFullExpandOrNot: TToolButton; tbClose: TToolBar; tbConfigurationTreeViewMenus: TToolButton; tbConfigurationTreeViewMenusColors: TToolButton; tbCancelAndQuit: TToolButton; pmCaseSensitiveOrNot: TPopupMenu; pmiCaseSensitive: TMenuItem; pmiNotCaseSensitive: TMenuItem; pmIgnoreAccentsOrNot: TPopupMenu; pmiIgnoreAccents: TMenuItem; pmiNotIgnoreAccents: TMenuItem; pmShowWholeBranchIfMatchOrNot: TPopupMenu; pmiShowWholeBranchIfMatch: TMenuItem; pmiNotShowWholeBranchIfMatch: TMenuItem; pmFullExpandOrNot: TPopupMenu; pmiFullExpand: TMenuItem; pmiFullCollapse: TMenuItem; imgListButton: TImageList; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction); procedure FormCloseQuery(Sender: TObject; var {%H-}CanClose: boolean); procedure FormDestroy(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); procedure tbCaseSensitiveClick(Sender: TObject); procedure pmiCaseSensitiveOrNotClick(Sender: TObject); procedure tbIgnoreAccentsClick(Sender: TObject); procedure pmiIgnoreAccentsOrNotClick(Sender: TObject); procedure tbShowWholeBranchOrNotClick(Sender: TObject); procedure pmiShowWholeBranchIfMatchOrNotClick(Sender: TObject); procedure tbFullExpandOrNotClick(Sender: TObject); procedure pmiFullExpandOrNotClick(Sender: TObject); procedure tbConfigurationTreeViewMenusClick(Sender: TObject); procedure tbConfigurationTreeViewMenusColorsClick(Sender: TObject); procedure tbCancelAndQuitClick(Sender: TObject); procedure edSearchingEntryChange(Sender: TObject); procedure tvMainMenuClick(Sender: TObject); procedure tvMainMenuDblClick(Sender: TObject); procedure tvMainMenuEnter(Sender: TObject); procedure tvMainMenuMouseMove(Sender: TObject; {%H-}Shift: TShiftState; X, Y: integer); procedure tvMainMenuMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure tvMainMenuMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure tvMainMenuSelectionChanged(Sender: TObject); procedure tvMainMenuExpandOrCollapseClick(Sender: TObject; {%H-}Node: TTreeNode); function isAtLeastOneItemVisibleAndSelectable: boolean; procedure SelectNextVisibleItem; procedure SelectPreviousVisibleItem; procedure SelectFirstVisibleItem; procedure SelectLastVisibleItem; procedure SetShortcuts; function WasAbleToSelectShortCutLetter(SearchKey: char): boolean; function AttemptToExitWithCurrentSelection: boolean; procedure SetSizeToLargestElement; private { private declarations } bTargetFixedWidth: boolean; LastMousePos: TPoint; protected procedure UpdateColors; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public { public declarations } iFinalSelectedIndex: integer; TreeViewMenuGenericRoutineAndVarHolder: TTreeViewMenuGenericRoutineAndVarHolder; procedure SetContextMode(WantedContextMode: tvmContextMode; WantedPosX, WantedPosY: integer; WantedWidth: integer = 0; WantedHeight: integer = 0); procedure HideUnmatchingNode; end; // Actual routine called from the outside to help user to quickly select something using the "Tree View Menu" concept. function GetUserChoiceFromTStrings(ATStrings: TStrings; ContextMode: tvmContextMode; WantedPosX, WantedPosY: integer; WantedWidth: integer = 0; WantedHeight: integer = 0): string; function GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(pmAnyMenu: TMenu; ContextMode: tvmContextMode; WantedPosX, WantedPosY: integer; WantedWidth: integer = 0; WantedHeight: integer = 0): TMenuItem; function GetUserChoiceFromKASToolBar(AKASToolBar: TKASToolBar; ContextMode: tvmContextMode; WantedPosX, WantedPosY, WantedWidth, WantedHeight: integer; var ReturnedTypeDispatcher: integer): Pointer; var frmTreeViewMenu: TfrmTreeViewMenu; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. LCLType, LCLIntf, LazUTF8, //DC uLng, fMain, uGlobs, uAccentsUtils; const CONST_CANCEL_ACTION = -1; CONST_CONFIG_ACTION = -2; CONST_CONFIG_COLOR_ACTION = -3; var sTreeViewMenuShortcutString: string = '0123456789abcdefghijklmnopqrstuvwxyz'; { TTreeMenuItem.Create } constructor TTreeMenuItem.Create(PointerSourceData: Pointer); begin FPointerSourceData := PointerSourceData; FTypeDispatcher := 0; FSecondaryText := ''; FKeyboardShortcut := ' '; end; { TTreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem } function TTreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(ATreeView: TTreeView; ParentNode: TTreeNode; const S: string; const SecondaryText: string = ''; TypeDispatcher: integer = 0; Data: Pointer = nil): TTreeNode; var ATreeMenuItem: TTreeMenuItem; begin ATreeMenuItem := TTreeMenuItem.Create(Data); ATreeMenuItem.TypeDispatcher := TypeDispatcher; ATreeMenuItem.KeyboardShortcut := ' '; ATreeMenuItem.SecondaryText := SecondaryText; Result := ATreeView.Items.AddChildObject(ParentNode, S, ATreeMenuItem); end; { TTreeViewMenuGenericRoutineAndVarHolder.TreeViewMenuAdvancedCustomDrawItem } procedure TTreeViewMenuGenericRoutineAndVarHolder.TreeViewMenuAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, DefaultDraw: boolean); var NodeRect: TRect; sPart, sStringToShow: string; iRenduX: integer; iPosNormal: integer = 0; iMatchingLengthInSource: integer = 0; iTotalWidth: integer; local_TextColor: TColor; local_ShortcutColor: TColor; local_SecondaryTextColor: TColor; local_FoundTextColor: TColor; begin if TCustomTreeView(Sender).BackgroundColor <> BackgroundColor then TCustomTreeView(Sender).BackgroundColor := BackgroundColor; if TCustomTreeView(Sender).Color <> BackgroundColor then TCustomTreeView(Sender).Color := BackgroundColor; if Stage = cdPostPaint then begin if Node <> nil then begin NodeRect := Node.DisplayRect(True); iTotalWidth := ((TCustomTreeView(Sender).Width - Node.DisplayTextLeft) - 25); NodeRect.Right := NodeRect.Left + iTotalWidth; if cdsSelected in State then begin // Draw something under selection. TTreeView(Sender).Canvas.Brush.Color := CursorColor; local_ShortcutColor := ShortcutUnderCursor; local_SecondaryTextColor := SecondaryTextUnderCursor; if (Node.Count = 0) or (FMayStopOnNode) then local_TextColor := NormalTextUnderCursor else local_TextColor := UnselectableUnderCursor; local_FoundTextColor := FoundTextUnderCursor; end else begin // Draw something unselected. TTreeView(Sender).Canvas.Brush.Color := BackgroundColor; local_ShortcutColor := ShortcutColor; local_SecondaryTextColor := SecondaryTextColor; if (Node.Count = 0) or (FMayStopOnNode) then local_TextColor := NormalTextColor else local_TextColor := UnselectableTextColor; local_FoundTextColor := FoundTextColor; end; TTreeView(Sender).Canvas.Brush.Style := bsSolid; TTreeView(Sender).Canvas.FillRect(NodeRect); TTreeView(Sender).Canvas.Brush.Style := bsClear; sStringToShow := Node.Text; iRenduX := NodeRect.Left + 3; // Short the shortcut name if config wants it AND if we have one to give. if (FShowShortcut) and (TTreeMenuItem(Node.Data).KeyboardShortcut <> ' ') then begin TTreeView(Sender).Canvas.Font.Color := local_ShortcutColor; sPart := '[' + TTreeMenuItem(Node.Data).KeyboardShortcut + '] '; TTreeView(Sender).Canvas.TextOut(iRenduX, NodeRect.Top + 1, sPart); iRenduX := iRenduX + TTreeView(Sender).Canvas.TextWidth(sPart); end; if (Node.Count = 0) or (FMayStopOnNode or ShowWholeBranchIfMatch) then begin while sStringToShow <> '' do begin iPosNormal := PosOfSubstrWithVersatileOptions(FSearchingText, sStringToShow, CaseSensitive, IgnoreAccents, iMatchingLengthInSource); if iPosNormal > 0 then begin if iPosNormal > 1 then begin // What we have in black prior the red... TTreeView(Sender).Canvas.Font.Color := local_TextColor; sPart := UTF8LeftStr(sStringToShow, pred(iPosNormal)); TTreeView(Sender).Canvas.TextOut(iRenduX, NodeRect.Top + 1, sPart); iRenduX := iRenduX + TTreeView(Sender).Canvas.TextWidth(sPart); sStringToShow := UTF8RightStr(sStringToShow, ((UTF8Length(sStringToShow) - iPosNormal) + 1)); end; // What we have in red... TTreeView(Sender).Canvas.Font.Style := TTreeView(Sender).Canvas.Font.Style + [fsUnderline, fsBold]; TTreeView(Sender).Canvas.Font.Color := local_FoundTextColor; sPart := UTF8Copy(sStringToShow, 1, iMatchingLengthInSource); TTreeView(Sender).Canvas.TextOut(iRenduX, NodeRect.Top + 1, sPart); iRenduX := iRenduX + TTreeView(Sender).Canvas.TextWidth(sPart); TTreeView(Sender).Canvas.Font.Style := TTreeView(Sender).Canvas.Font.Style - [fsUnderline, fsBold]; sStringToShow := UTF8RightStr(sStringToShow, ((UTF8Length(sStringToShow) - iMatchingLengthInSource))); end else begin TTreeView(Sender).Canvas.Font.Color := local_TextColor; TTreeView(Sender).Canvas.TextOut(iRenduX, NodeRect.Top + 1, sStringToShow); iRenduX := iRenduX + TTreeView(Sender).Canvas.TextWidth(sStringToShow); sStringToShow := ''; end; end; end else begin TTreeView(Sender).Canvas.Font.Color := local_TextColor; TTreeView(Sender).Canvas.TextOut(iRenduX, NodeRect.Top + 1, sStringToShow); iRenduX := iRenduX + TTreeView(Sender).Canvas.TextWidth(sStringToShow); end; if TTreeMenuItem(Node.Data).SecondaryText <> '' then begin TTreeView(Sender).Canvas.Font.Color := local_SecondaryTextColor; TTreeView(Sender).Canvas.Font.Style := TTreeView(Sender).Canvas.Font.Style + [fsItalic]; TTreeView(Sender).Canvas.TextOut(iRenduX + 4, NodeRect.Top + 1 + 1, TTreeMenuItem(Node.Data).SecondaryText); //If we ever add something else after one day: iRenduX := iRenduX+4 + TTreeView(Sender).Canvas.TextWidth(TTreeMenuItem(Node.Data).SecondaryText); TTreeView(Sender).Canvas.Font.Style := TTreeView(Sender).Canvas.Font.Style - [fsItalic]; end; DefaultDraw := False; end; end; end; { TfrmTreeViewMenu.FormCreate } procedure TfrmTreeViewMenu.FormCreate(Sender: TObject); begin bTargetFixedWidth := False; LastMousePos.x := -1; LastMousePos.y := -1; iFinalSelectedIndex := CONST_CANCEL_ACTION; FontOptionsToFont(gFonts[dcfTreeViewMenu], tvMainMenu.Font); TreeViewMenuGenericRoutineAndVarHolder := TTreeViewMenuGenericRoutineAndVarHolder.Create; UpdateColors; tvMainMenu.OnAdvancedCustomDrawItem := @TreeViewMenuGenericRoutineAndVarHolder.TreeViewMenuAdvancedCustomDrawItem; edSearchingEntryChange(nil); end; { TfrmTreeViewMenu.FormClose } procedure TfrmTreeViewMenu.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin case iFinalSelectedIndex of CONST_CANCEL_ACTION: ModalResult := mrCancel; CONST_CONFIG_ACTION: ModalResult := mrYes; CONST_CONFIG_COLOR_ACTION: ModalResult := mrAll; else ModalResult := mrOk; end; end; { TfrmTreeViewMenu.FormCloseQuery } procedure TfrmTreeViewMenu.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin tvMainMenu.OnExpanded := nil; tvMainMenu.OnCollapsed := nil; tvMainMenu.OnSelectionChanged := nil; Application.ProcessMessages; //We saved our options. We're aware it will save it even if user CANCEL the action but after a few test, the author of these lines feels it is better this way. gTreeViewMenuOptions[Ord(TreeViewMenuGenericRoutineAndVarHolder.ContextMode)].CaseSensitive := TreeViewMenuGenericRoutineAndVarHolder.CaseSensitive; gTreeViewMenuOptions[Ord(TreeViewMenuGenericRoutineAndVarHolder.ContextMode)].IgnoreAccents := TreeViewMenuGenericRoutineAndVarHolder.IgnoreAccents; gTreeViewMenuOptions[Ord(TreeViewMenuGenericRoutineAndVarHolder.ContextMode)].ShowWholeBranchIfMatch := TreeViewMenuGenericRoutineAndVarHolder.ShowWholeBranchIfMatch; end; { TfrmTreeViewMenu.FormDestroy } procedure TfrmTreeViewMenu.FormDestroy(Sender: TObject); begin FreeAndNil(TreeViewMenuGenericRoutineAndVarHolder); inherited; end; { TfrmTreeViewMenu.FormKeyDown } procedure TfrmTreeViewMenu.FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); var ChoiceNode: TTreeNode; begin if edSearchingEntry.Focused then begin case Key of VK_HOME: // Home Key begin if SSCTRL in Shift then begin SelectFirstVisibleItem; Key := 0; end; end; VK_END: // End Key begin if SSCTRL in Shift then begin SelectLastVisibleItem; Key := 0; end; end; end; end; if ssALT in Shift then begin case Key of VK_0..VK_9, VK_A..VK_Z: if WasAbleToSelectShortCutLetter(char(Key)) then Key := 0; end; if (Key = 0) and gTreeViewMenuShortcutExit then AttemptToExitWithCurrentSelection; end; case Key of VK_UP: // Up Arrow Key begin SelectPreviousVisibleItem; Key := 0; end; VK_DOWN: // Down Arrow Key begin SelectNextVisibleItem; Key := 0; end; VK_END: // End Key - Let's play tricky: if cursor is at the end into the edit box, let's assume user pressed the "end" key to go to the end in the list. begin if edSearchingEntry.SelStart >= utf8Length(edSearchingEntry.Text) then begin SelectLastVisibleItem; Key := 0; end; end; VK_HOME: // Home Key - Let's play tricky: if cursor is at the beginning into the edit box, let's assume user pressed the "home" key to go to the first in the list. begin if edSearchingEntry.SelStart = 0 then begin SelectFirstVisibleItem; Key := 0; end; end; VK_RETURN: // Enter key begin ChoiceNode := tvMainMenu.Selected; if ChoiceNode <> nil then begin if (TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode) or (ChoiceNode.Count = 0) then begin Key := 0; AttemptToExitWithCurrentSelection; end; end; end; VK_ESCAPE: // Escape key begin Key := 0; Close; end; end; end; { TfrmTreeViewMenu.tbCaseSensitiveClick } procedure TfrmTreeViewMenu.tbCaseSensitiveClick(Sender: TObject); var pmiToSwitchTo: TMenuItem = nil; begin if pmiNotCaseSensitive.Checked then pmiToSwitchTo := pmiCaseSensitive else if pmiCaseSensitive.Checked then pmiToSwitchTo := pmiNotCaseSensitive; if pmiToSwitchTo <> nil then begin pmiToSwitchTo.Checked := True; pmiCaseSensitiveOrNotClick(pmiToSwitchTo); end; end; { TfrmTreeViewMenu.pmiCaseSensitiveOrNotClick } procedure TfrmTreeViewMenu.pmiCaseSensitiveOrNotClick(Sender: TObject); begin begin with Sender as TMenuItem do begin tbCaseSensitive.ImageIndex := ImageIndex; tbCaseSensitive.Hint := Caption; end; edSearchingEntryChange(edSearchingEntry); end; end; { TfrmTreeViewMenu.tbIgnoreAccentsClick } procedure TfrmTreeViewMenu.tbIgnoreAccentsClick(Sender: TObject); var pmiToSwitchTo: TMenuItem = nil; begin if pmiIgnoreAccents.Checked then pmiToSwitchTo := pmiNotIgnoreAccents else if pmiNotIgnoreAccents.Checked then pmiToSwitchTo := pmiIgnoreAccents; if pmiToSwitchTo <> nil then begin pmiToSwitchTo.Checked := True; pmiIgnoreAccentsOrNotClick(pmiToSwitchTo); end; end; { TfrmTreeViewMenu.pmiIgnoreAccentsOrNotClick } procedure TfrmTreeViewMenu.pmiIgnoreAccentsOrNotClick(Sender: TObject); begin with Sender as TMenuItem do begin tbIgnoreAccents.ImageIndex := ImageIndex; tbIgnoreAccents.Hint := Caption; end; edSearchingEntryChange(edSearchingEntry); end; { TfrmTreeViewMenu.tbShowWholeBranchOrNotClick } procedure TfrmTreeViewMenu.tbShowWholeBranchOrNotClick(Sender: TObject); var pmiToSwitchTo: TMenuItem = nil; begin if pmiShowWholeBranchIfMatch.Checked then pmiToSwitchTo := pmiNotShowWholeBranchIfMatch else if pmiNotShowWholeBranchIfMatch.Checked then pmiToSwitchTo := pmiShowWholeBranchIfMatch; if pmiToSwitchTo <> nil then begin pmiToSwitchTo.Checked := True; pmiShowWholeBranchIfMatchOrNotClick(pmiToSwitchTo); end; end; { TfrmTreeViewMenu.pmiShowWholeBranchIfMatchOrNotClick } procedure TfrmTreeViewMenu.pmiShowWholeBranchIfMatchOrNotClick(Sender: TObject); begin with Sender as TMenuItem do begin tbShowWholeBranchOrNot.ImageIndex := ImageIndex; tbShowWholeBranchOrNot.Hint := Caption; end; edSearchingEntryChange(edSearchingEntry); end; { TfrmTreeViewMenu.tbFullExpandOrNotClick } procedure TfrmTreeViewMenu.tbFullExpandOrNotClick(Sender: TObject); var pmiToSwitchTo: TMenuItem = nil; begin if pmiFullExpand.Checked then pmiToSwitchTo := pmiFullCollapse else if pmiFullCollapse.Checked then pmiToSwitchTo := pmiFullExpand; if pmiToSwitchTo <> nil then begin pmiToSwitchTo.Checked := True; pmiFullExpandOrNotClick(pmiToSwitchTo); end; end; { TfrmTreeViewMenu.pmiFullExpandOrNotClick } procedure TfrmTreeViewMenu.pmiFullExpandOrNotClick(Sender: TObject); begin with Sender as TMenuItem do begin tbFullExpandOrNot.ImageIndex := ImageIndex; tbFullExpandOrNot.Hint := Caption; end; if pmiFullExpand.Checked then tvMainMenu.FullExpand else tvMainMenu.FullCollapse; end; { TfrmTreeViewMenu.tbConfigurationTreeViewMenusClick } procedure TfrmTreeViewMenu.tbConfigurationTreeViewMenusClick(Sender: TObject); begin iFinalSelectedIndex := CONST_CONFIG_ACTION; Close; end; { TfrmTreeViewMenu.tbConfigurationTreeViewMenusColorsClick } procedure TfrmTreeViewMenu.tbConfigurationTreeViewMenusColorsClick(Sender: TObject); begin iFinalSelectedIndex := CONST_CONFIG_COLOR_ACTION; Close; end; { TfrmTreeViewMenu.tbCancelAndQuitClick } procedure TfrmTreeViewMenu.tbCancelAndQuitClick(Sender: TObject); begin Close; end; { TfrmTreeViewMenu.edSearchingEntryChange } procedure TfrmTreeViewMenu.edSearchingEntryChange(Sender: TObject); begin TreeViewMenuGenericRoutineAndVarHolder.CaseSensitive := pmiCaseSensitive.Checked; TreeViewMenuGenericRoutineAndVarHolder.IgnoreAccents := pmiIgnoreAccents.Checked; TreeViewMenuGenericRoutineAndVarHolder.ShowWholeBranchIfMatch := pmiShowWholeBranchIfMatch.Checked; TreeViewMenuGenericRoutineAndVarHolder.SearchingText := edSearchingEntry.Text; TreeViewMenuGenericRoutineAndVarHolder.ShowShortcut := gTreeViewMenuUseKeyboardShortcut; if pmiIgnoreAccents.Checked then TreeViewMenuGenericRoutineAndVarHolder.SearchingText := NormalizeAccentedChar(TreeViewMenuGenericRoutineAndVarHolder.SearchingText); if not pmiCaseSensitive.Checked then TreeViewMenuGenericRoutineAndVarHolder.SearchingText := UTF8UpperCase(TreeViewMenuGenericRoutineAndVarHolder.SearchingText); HideUnmatchingNode; end; { TfrmTreeViewMenu.tvMainMenuClick } procedure TfrmTreeViewMenu.tvMainMenuClick(Sender: TObject); begin if gTreeViewMenuSingleClickExit then AttemptToExitWithCurrentSelection; end; { TfrmTreeViewMenu.tvMainMenuDblClick } procedure TfrmTreeViewMenu.tvMainMenuDblClick(Sender: TObject); begin if gTreeViewMenuDoubleClickExit then AttemptToExitWithCurrentSelection; end; { TfrmTreeViewMenu.tvMainMenuEnter } procedure TfrmTreeViewMenu.tvMainMenuEnter(Sender: TObject); begin if edSearchingEntry.CanFocus then edSearchingEntry.SetFocus; end; { TfrmTreeViewMenu.tvMainMenuMouseMove } procedure TfrmTreeViewMenu.tvMainMenuMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer); var ANode: TTreeNode; begin if (LastMousePos.x <> -1) and (LastMousePos.y <> -1) then begin ANode := tvMainMenu.GetNodeAt(X, Y); if ANode <> nil then if not ANode.Selected then ANode.Selected := True; end; LastMousePos.x := X; LastMousePos.y := Y; end; { TfrmTreeViewMenu.tvMainMenuMouseWheelDown } procedure TfrmTreeViewMenu.tvMainMenuMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (Shift = [ssCtrl]) and (gFonts[dcfTreeViewMenu].Size > gFonts[dcfTreeViewMenu].MinValue) then begin dec(gFonts[dcfTreeViewMenu].Size); tvMainMenu.Font.Size := gFonts[dcfTreeViewMenu].Size; Handled := True; end; end; { TfrmTreeViewMenu.tvMainMenuMouseWheelUp } procedure TfrmTreeViewMenu.tvMainMenuMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (Shift = [ssCtrl]) and (gFonts[dcfTreeViewMenu].Size < gFonts[dcfTreeViewMenu].MaxValue) then begin inc(gFonts[dcfTreeViewMenu].Size); tvMainMenu.Font.Size := gFonts[dcfTreeViewMenu].Size; Handled := True; end; end; { TfrmTreeViewMenu.tvMainMenuSelectionChanged } procedure TfrmTreeViewMenu.tvMainMenuSelectionChanged(Sender: TObject); begin tvMainMenu.BeginUpdate; SetShortcuts; tvMainMenu.EndUpdate; end; { TfrmTreeViewMenu.ExpandOrCollapseClick } procedure TfrmTreeViewMenu.tvMainMenuExpandOrCollapseClick(Sender: TObject; Node: TTreeNode); begin if edSearchingEntry.Text = '' then begin tvMainMenu.BeginUpdate; SetShortcuts; tvMainMenu.EndUpdate; end; end; { TfrmTreeViewMenu.isAtLeastOneItemVisibleAndSelectable } function TfrmTreeViewMenu.isAtLeastOneItemVisibleAndSelectable: boolean; var iSearchIndex: integer; begin Result := False; if tvMainMenu.Items.Count > 0 then begin iSearchIndex := 0; while (not Result) and (iSearchIndex < tvMainMenu.Items.Count) do begin if tvMainMenu.Items[iSearchIndex].Visible then Result := ((tvMainMenu.Items[iSearchIndex].Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode); Inc(iSearchIndeX); end; end; end; { TfrmTreeViewMenu.SelectNextVisibleItem } procedure TfrmTreeViewMenu.SelectNextVisibleItem; var iCurrentIndex: integer; begin if isAtLeastOneItemVisibleAndSelectable then begin if tvMainMenu.Selected = nil then iCurrentIndex := -1 else iCurrentIndex := tvMainMenu.Selected.AbsoluteIndex; begin repeat iCurrentIndex := ((iCurrentIndex + 1) mod tvMainMenu.Items.Count); until (tvMainMenu.Items[iCurrentIndex].Visible and ((tvMainMenu.Items[iCurrentIndex].Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode)); tvMainMenu.Items[iCurrentIndex].Selected := True; end; end; end; { TfrmTreeViewMenu.SelectPreviousVisibleItem } procedure TfrmTreeViewMenu.SelectPreviousVisibleItem; var iCurrentIndex: integer; begin if isAtLeastOneItemVisibleAndSelectable then begin if tvMainMenu.Selected = nil then iCurrentIndex := -1 else iCurrentIndex := tvMainMenu.Selected.AbsoluteIndex; begin repeat if iCurrentIndex = 0 then iCurrentIndex := pred(tvMainMenu.Items.Count) else Dec(iCurrentIndex); until (tvMainMenu.Items[iCurrentIndex].Visible and ((tvMainMenu.Items[iCurrentIndex].Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode)); tvMainMenu.Items[iCurrentIndex].Selected := True; end; end; end; { TfrmTreeViewMenu.SelectFirstVisibleItem } procedure TfrmTreeViewMenu.SelectFirstVisibleItem; var iCurrentIndex: integer; begin if isAtLeastOneItemVisibleAndSelectable then begin iCurrentIndex := -1; repeat iCurrentIndex := ((iCurrentIndex + 1) mod tvMainMenu.Items.Count); until (tvMainMenu.Items[iCurrentIndex].Visible and ((tvMainMenu.Items[iCurrentIndex].Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode)); tvMainMenu.Items[iCurrentIndex].Selected := True; end; end; { TfrmTreeViewMenu.SelectLastVisibleItem } procedure TfrmTreeViewMenu.SelectLastVisibleItem; var iCurrentIndex: integer; begin if isAtLeastOneItemVisibleAndSelectable then begin iCurrentIndex := tvMainMenu.Items.Count; repeat if iCurrentIndex = 0 then iCurrentIndex := pred(tvMainMenu.Items.Count) else Dec(iCurrentIndex); until (tvMainMenu.Items[iCurrentIndex].Visible and ((tvMainMenu.Items[iCurrentIndex].Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode)); tvMainMenu.Items[iCurrentIndex].Selected := True; end; end; { TfrmTreeViewMenu.SetShortcuts } procedure TfrmTreeViewMenu.SetShortcuts; var iCurrentShortcut: integer = 1; function GetCurrentShortcutLetter: char; begin if iCurrentShortcut > 0 then begin Result := sTreeViewMenuShortcutString[iCurrentShortcut]; Inc(iCurrentShortcut); if iCurrentShortcut > length(sTreeViewMenuShortcutString) then iCurrentShortcut := 0; end else begin Result := ' '; end; end; function GetShortcutLetterForThisNode(paramNode: TTreeNode): char; begin Result := ' '; if paramNode.Visible then if (paramNode.Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode then Result := GetCurrentShortcutLetter; end; var iNode, iNbOfVisibleNode: integer; ANode: TTreeNode; begin for iNode := 0 to pred(tvMainMenu.Items.Count) do TTreeMenuItem(tvMainMenu.Items[iNode].Data).KeyboardShortcut := ' '; iNbOfVisibleNode := tvMainMenu.Height div tvMainMenu.DefaultItemHeight; iNode := 0; while iNode < iNbOfVisibleNode do begin ANode := tvMainMenu.GetNodeAt(100, (iNode * tvMainMenu.DefaultItemHeight)); if ANode <> nil then begin if (ANode.Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode then TTreeMenuItem(ANode.Data).KeyboardShortcut := GetShortcutLetterForThisNode(ANode); end; Inc(iNode); end; end; { TfrmTreeViewMenu.WasAbleToSelectShortCutLetter } function TfrmTreeViewMenu.WasAbleToSelectShortCutLetter(SearchKey: char): boolean; var iSearchIndex: integer; begin Result := False; if tvMainMenu.Items.Count > 0 then begin iSearchIndex := 0; while (not Result) and (iSearchIndex < tvMainMenu.Items.Count) do begin if (LowerCase(TTreeMenuItem(tvMainMenu.Items[iSearchIndex].Data).KeyboardShortcut) = LowerCase(SearchKey)) and (tvMainMenu.Items[iSearchIndex].Visible) then Result := True else Inc(iSearchIndeX); end; end; if Result then tvMainMenu.Items[iSearchIndex].Selected := True; end; { TfrmTreeViewMenu.AttemptToExitWithCurrentSelection } function TfrmTreeViewMenu.AttemptToExitWithCurrentSelection: boolean; begin Result := False; if tvMainMenu.Selected <> nil then if (TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode) or (tvMainMenu.Selected.Count = 0) then begin Result := True; iFinalSelectedIndex := tvMainMenu.Selected.AbsoluteIndex; Close; end; end; { TfrmTreeViewMenu.SetSizeToLargestElement } procedure TfrmTreeViewMenu.SetSizeToLargestElement; var iNode, iLargest: integer; mntrWhereToShowForm: TMonitor; begin iLargest := 0; for iNode := 0 to pred(tvMainMenu.Items.Count) do if tvMainMenu.Items[iNode].DisplayRect(True).Right > iLargest then iLargest := tvMainMenu.Items[iNode].DisplayRect(True).Right; Width := iLargest + 50; mntrWhereToShowForm := Screen.MonitorFromPoint(Mouse.CursorPos); if (Mouse.CursorPos.x + Width) > (mntrWhereToShowForm.Left + mntrWhereToShowForm.Width) then begin Left := ((mntrWhereToShowForm.Left + mntrWhereToShowForm.Width) - Width); end else Left := Mouse.CursorPos.x; end; procedure TfrmTreeViewMenu.UpdateColors; begin with gColors.TreeViewMenu^ do begin TreeViewMenuGenericRoutineAndVarHolder.BackgroundColor := BackgroundColor; TreeViewMenuGenericRoutineAndVarHolder.ShortcutColor := ShortcutColor; TreeViewMenuGenericRoutineAndVarHolder.NormalTextColor := NormalTextColor; TreeViewMenuGenericRoutineAndVarHolder.SecondaryTextColor := SecondaryTextColor; TreeViewMenuGenericRoutineAndVarHolder.FoundTextColor := FoundTextColor; TreeViewMenuGenericRoutineAndVarHolder.UnselectableTextColor := UnselectableTextColor; TreeViewMenuGenericRoutineAndVarHolder.CursorColor := CursorColor; TreeViewMenuGenericRoutineAndVarHolder.ShortcutUnderCursor := ShortcutUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.NormalTextUnderCursor := NormalTextUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.SecondaryTextUnderCursor := SecondaryTextUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.FoundTextUnderCursor := FoundTextUnderCursor; TreeViewMenuGenericRoutineAndVarHolder.UnselectableUnderCursor := UnselectableUnderCursor; tvMainMenu.BackgroundColor := BackgroundColor; tvMainMenu.Color := BackgroundColor; end; end; procedure TfrmTreeViewMenu.CMThemeChanged(var Message: TLMessage); begin UpdateColors; tvMainMenu.Repaint; end; { TfrmTreeViewMenu.SetContextMode } procedure TfrmTreeViewMenu.SetContextMode(WantedContextMode: tvmContextMode; WantedPosX, WantedPosY: integer; WantedWidth: integer = 0; WantedHeight: integer = 0); var ARect: TRect; APoint: TPoint; pmiToSwitchTo: TMenuItem = nil; mntrWhereToShowForm: TMonitor; begin TreeViewMenuGenericRoutineAndVarHolder.ContextMode := WantedContextMode; // Let's set our option checked menu item AND our internal options according to settings saved previously for that context. if gTreeViewMenuOptions[Ord(TreeViewMenuGenericRoutineAndVarHolder.ContextMode)].CaseSensitive then pmiToSwitchTo := pmiCaseSensitive else pmiToSwitchTo := pmiNotCaseSensitive; pmiToSwitchTo.Checked := True; pmiCaseSensitiveOrNotClick(pmiToSwitchTo); if gTreeViewMenuOptions[Ord(TreeViewMenuGenericRoutineAndVarHolder.ContextMode)].IgnoreAccents then pmiToSwitchTo := pmiIgnoreAccents else pmiToSwitchTo := pmiNotIgnoreAccents; pmiToSwitchTo.Checked := True; pmiIgnoreAccentsOrNotClick(pmiToSwitchTo); if gTreeViewMenuOptions[Ord(TreeViewMenuGenericRoutineAndVarHolder.ContextMode)].ShowWholeBranchIfMatch then pmiToSwitchTo := pmiShowWholeBranchIfMatch else pmiToSwitchTo := pmiNotShowWholeBranchIfMatch; pmiToSwitchTo.Checked := True; pmiShowWholeBranchIfMatchOrNotClick(pmiToSwitchTo); // We set the appropriate title to give feedback to user. case TreeViewMenuGenericRoutineAndVarHolder.ContextMode of tvmcHotDirectory: lblSearchingEntry.Caption := rsStrTVMChooseHotDirectory; tvmcFavoriteTabs: lblSearchingEntry.Caption := rsStrTVMChooseFavoriteTabs; tvmcDirHistory: lblSearchingEntry.Caption := rsStrTVMChooseDirHistory; tvmcViewHistory: lblSearchingEntry.Caption := rsStrTVMChooseViewHistory; tvmcKASToolBar: lblSearchingEntry.Caption := rsStrTVMChooseFromToolbar; tvmcMainMenu: lblSearchingEntry.Caption := rsStrTVMChooseFromMainMenu; tvmcCommandLineHistory: lblSearchingEntry.Caption := rsStrTVMChooseFromCmdLineHistory; tvmcFileSelectAssistant: lblSearchingEntry.Caption := rsStrTVMChooseYourFileOrDir; else raise Exception.Create(rsMsgUnexpectedUsageTreeViewMenu); end; // We set the "look and feel" of the form for the user. case TreeViewMenuGenericRoutineAndVarHolder.ContextMode of tvmcHotDirectory, tvmcFavoriteTabs, tvmcKASToolBar, tvmcMainMenu: TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode := False; tvmcDirHistory, tvmcViewHistory, tvmcCommandLineHistory: TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode := False; tvmcFileSelectAssistant: TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode := True; // But on first revision, won't happen else raise Exception.Create(rsMsgUnexpectedUsageTreeViewMenu); end; case TreeViewMenuGenericRoutineAndVarHolder.ContextMode of tvmcHotDirectory, tvmcFavoriteTabs, tvmcDirHistory, tvmcViewHistory, tvmcKASToolBar, tvmcMainMenu, tvmcCommandLineHistory, tvmcFileSelectAssistant: begin if WantedHeight <> 0 then begin bTargetFixedWidth := True; Left := WantedPosX; Top := WantedPosY; Width := WantedWidth; Height := WantedHeight; end else begin APoint := Mouse.CursorPos; mntrWhereToShowForm := Screen.MonitorFromPoint(APoint); ARect := mntrWhereToShowForm.WorkareaRect; if (APoint.X + Width) > ARect.Right then Left := (ARect.Right - Width) else begin Left := APoint.X; end; if Abs(APoint.Y - ARect.Bottom) > Abs(APoint.Y - ARect.Top) then begin Top := APoint.Y; Height := ARect.Bottom - APoint.Y; end else begin Top := ARect.Top; Height := APoint.Y - ARect.Top; end; end; BorderStyle := bsNone; end; else begin raise Exception.Create(rsMsgUnexpectedUsageTreeViewMenu); end; end; end; { TfrmTreeViewMenu.HideUnmatchingNode } // The *key* routine off all this. // Routine will make visible in tree view the items that match with what the user has typed. // Eliminating from the view the non matching item helps user to quickly see what he was looking for. // So choosing it through a lot of data speed up things. procedure TfrmTreeViewMenu.HideUnmatchingNode; var iDummy: integer = 0; iNode: integer; nFirstMatchingNode: TTreeNode = nil; //WARNING: The following procedure is recursive and so may call itself back! procedure KeepMeThisWholeBranch(paramNode: TTreeNode); begin while paramNode <> nil do begin paramNode.Visible := True; if paramNode.Count > 0 then KeepMeThisWholeBranch(paramNode.Items[0]); paramNode := paramNode.GetNextSibling; end; end; //WARNING: The following procedure is recursive and so may call itself back! function UpdateVisibilityAccordingToSearchingString(paramNode: TTreeNode): boolean; begin Result := False; while paramNode <> nil do begin if paramNode.Count = 0 then begin paramNode.Visible := (PosOfSubstrWithVersatileOptions(TreeViewMenuGenericRoutineAndVarHolder.SearchingText, paramNode.Text, pmiCaseSensitive.Checked, pmiIgnoreAccents.Checked, iDummy) <> 0); end else begin if pmiShowWholeBranchIfMatch.Checked then begin paramNode.Visible := (PosOfSubstrWithVersatileOptions(TreeViewMenuGenericRoutineAndVarHolder.SearchingText, paramNode.Text, pmiCaseSensitive.Checked, pmiIgnoreAccents.Checked, iDummy) <> 0); if paramNode.Visible then begin KeepMeThisWholeBranch(paramNode); end else begin paramNode.Visible := UpdateVisibilityAccordingToSearchingString(paramNode.Items[0]); end; end else begin paramNode.Visible := UpdateVisibilityAccordingToSearchingString(paramNode.Items[0]); if not paramNode.Visible then begin if TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode then paramNode.Visible := (PosOfSubstrWithVersatileOptions(TreeViewMenuGenericRoutineAndVarHolder.SearchingText, paramNode.Text, pmiCaseSensitive.Checked, pmiIgnoreAccents.Checked, iDummy) <> 0); end; end; end; if paramNode.Visible then begin Result := True; if nFirstMatchingNode = nil then if (paramNode.Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode then nFirstMatchingNode := paramNode; end; paramNode := paramNode.GetNextSibling; end; end; begin tbFullExpandOrNot.Visible := (TreeViewMenuGenericRoutineAndVarHolder.SearchingText = ''); if tvMainMenu.Items.Count > 0 then begin tvMainMenu.BeginUpdate; try if TreeViewMenuGenericRoutineAndVarHolder.SearchingText <> '' then begin UpdateVisibilityAccordingToSearchingString(tvMainMenu.Items.Item[0]); end else begin for iNode := 0 to pred(tvMainMenu.Items.Count) do begin tvMainMenu.Items.Item[iNode].Visible := True; if nFirstMatchingNode = nil then if (tvMainMenu.Items.Item[iNode].Count = 0) or TreeViewMenuGenericRoutineAndVarHolder.MayStopOnNode then nFirstMatchingNode := tvMainMenu.Items.Item[iNode]; end; end; if TreeViewMenuGenericRoutineAndVarHolder.SearchingText <> '' then begin for iNode := pred(tvMainMenu.Items.Count) downto 0 do tvMainMenu.Items.Item[iNode].MakeVisible; end else begin pmiFullExpand.Checked := True; pmiFullExpandOrNotClick(pmiFullExpand); end; // It might happen we hit no direct found BUT we're still displaying item because of branch name matching. If so, let's select the first item of a branch matching name. if nFirstMatchingNode=nil then begin iNode:=0; while (iNode<tvMainMenu.Items.Count) AND (nFirstMatchingNode=nil) do if (tvMainMenu.Items[iNode].Visible) AND (tvMainMenu.Items[iNode].Count=0) then nFirstMatchingNode:=tvMainMenu.Items[iNode] else inc(iNode); end; if nFirstMatchingNode <> nil then nFirstMatchingNode.Selected := True; SetShortcuts; finally tvMainMenu.EndUpdate; end; end; end; { GetUserChoiceFromTStrings } // We provide a "TStrings" for input. // Function will show strings into a ttreeview. // User select the one he wants. // Function returns the chosen string. // If user cancel action, returned string is empty. function GetUserChoiceFromTStrings(ATStrings: TStrings; ContextMode: tvmContextMode; WantedPosX, WantedPosY: integer; WantedWidth: integer = 0; WantedHeight: integer = 0): string; var iIndex: integer; local_Result: integer; begin Result := ''; if ATStrings.Count > 0 then begin frmTreeViewMenu := TfrmTreeViewMenu.Create(frmMain); try frmTreeViewMenu.SetContextMode(ContextMode, WantedPosX, WantedPosY, WantedWidth, WantedHeight); frmTreeViewMenu.tvMainMenu.BeginUpdate; for iIndex := 0 to pred(ATStrings.Count) do frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, nil, ATStrings.Strings[iIndex], '', 0, nil); frmTreeViewMenu.HideUnmatchingNode; if not frmTreeViewMenu.bTargetFixedWidth then frmTreeViewMenu.SetSizeToLargestElement; frmTreeViewMenu.tvMainMenu.EndUpdate; local_Result := frmTreeViewMenu.ShowModal; case local_Result of mrOk: Result := frmTreeViewMenu.tvMainMenu.Items[frmTreeViewMenu.iFinalSelectedIndex].Text; mrYes: frmMain.Commands.cm_ConfigTreeViewMenus([]); mrAll: frmMain.Commands.cm_ConfigTreeViewMenusColors([]); end; finally FreeAndNil(frmTreeViewMenu); end; end; end; { GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu } // We provide a "TMenu" for input (either a popup menu or a mainmenu). // Function will show items into a ttreeview. // User select the one he wants. // Function returns the chosen TMenuItem. // If user cancel action, returned TMenuItem is nil. function GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(pmAnyMenu: TMenu; ContextMode: tvmContextMode; WantedPosX, WantedPosY: integer; WantedWidth: integer = 0; WantedHeight: integer = 0): TMenuItem; var RootNode: TTreeNode; iMenuItem: integer; local_Result: integer; function NormalizeMenuCaption(sMenuCaption: string): string; var iChar: integer; begin if Pos('&', sMenuCaption) = 0 then begin Result := sMenuCaption; end else begin Result := ''; iChar := 1; while iChar <= Length(sMenuCaption) do begin if sMenuCaption[iChar] <> '&' then Result := Result + sMenuCaption[iChar] else begin if iChar < Length(sMenuCaption) then begin if sMenuCaption[iChar + 1] = '&' then begin Result := Result + '&'; Inc(iChar); end; end; end; Inc(iChar); end; end; end; //WARNING: This procedure is recursive and may call itself! procedure RecursiveAddMenuBranch(AMenuItem: TMenuItem; ANode: TTreeNode); var iIndexSubMenuItem: integer; ASubNode: TTreeNode; begin for iIndexSubMenuItem := 0 to pred(AMenuItem.Count) do begin if AMenuItem.Items[iIndexSubMenuItem].Caption <> '-' then begin if (AMenuItem.Items[iIndexSubMenuItem].Enabled) and (AMenuItem.Items[iIndexSubMenuItem].Visible) then begin ASubNode := frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, ANode, NormalizeMenuCaption(AMenuItem.Items[iIndexSubMenuItem].Caption), '', 0, AMenuItem.Items[iIndexSubMenuItem]); if AMenuItem.Items[iIndexSubMenuItem].Count > 0 then RecursiveAddMenuBranch(AMenuItem.Items[iIndexSubMenuItem], ASubNode); end; end; end; end; begin Result := nil; frmTreeViewMenu := TfrmTreeViewMenu.Create(frmMain); try frmTreeViewMenu.SetContextMode(ContextMode, WantedPosX, WantedPosY, WantedWidth, WantedHeight); frmTreeViewMenu.tvMainMenu.BeginUpdate; for iMenuItem := 0 to pred(pmAnyMenu.Items.Count) do begin if pmAnyMenu.Items[iMenuItem].Caption <> '-' then begin if (pmAnyMenu.Items[iMenuItem].Enabled) and (pmAnyMenu.Items[iMenuItem].Visible) then begin RootNode := frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, nil, NormalizeMenuCaption(pmAnyMenu.Items[iMenuItem].Caption), '', 0, pmAnyMenu.Items[iMenuItem]); if pmAnyMenu.Items[iMenuItem].Count > 0 then RecursiveAddMenuBranch(pmAnyMenu.Items[iMenuItem], RootNode); end; end; end; frmTreeViewMenu.HideUnmatchingNode; if not frmTreeViewMenu.bTargetFixedWidth then frmTreeViewMenu.SetSizeToLargestElement; frmTreeViewMenu.tvMainMenu.EndUpdate; local_Result := frmTreeViewMenu.ShowModal; case local_Result of mrOk: Result := TMenuItem(TTreeMenuItem(frmTreeViewMenu.tvMainMenu.Items[frmTreeViewMenu.iFinalSelectedIndex].Data).PointerSourceData); mrYes: frmMain.Commands.cm_ConfigTreeViewMenus([]); mrAll: frmMain.Commands.cm_ConfigTreeViewMenusColors([]); end; finally FreeAndNil(frmTreeViewMenu); end; end; { GetUserChoiceFromKASToolBar } function GetUserChoiceFromKASToolBar(AKASToolBar: TKASToolBar; ContextMode: tvmContextMode; WantedPosX, WantedPosY, WantedWidth, WantedHeight: integer; var ReturnedTypeDispatcher: integer): Pointer; var frmTreeViewMenu: TfrmTreeViewMenu; sSimiliCaptionToAddToMenu: string; sSecondaryText: string; procedure AddToSecondyText(sInfo: string); begin if sInfo <> '' then begin if sSecondaryText <> '' then sSecondaryText := sSecondaryText + ' / '; sSecondaryText := sSecondaryText + sInfo; end; end; //WARNING: This procedure is recursive and may call itself! procedure RecursiveAddTheseTKASToolItems(AKASMenuItem: TKASMenuItem; ANode: TTreeNode); var ASubNode: TTreeNode; iIndexKASMenuItem: integer; AKASToolItem: TKASToolItem; begin for iIndexKASMenuItem := 0 to pred(AKASMenuItem.SubItems.Count) do begin sSimiliCaptionToAddToMenu := ''; sSecondaryText := ''; AKASToolItem := AKASMenuItem.SubItems.Items[iIndexKASMenuItem]; if AKASToolItem is TKASNormalItem then sSimiliCaptionToAddToMenu := TKASNormalItem(AKASToolItem).Hint; if AKASToolItem is TKASCommandItem then begin AddToSecondyText(TKASCommandItem(AKASToolItem).Command); frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, ANode, sSimiliCaptionToAddToMenu, sSecondaryText, 2, AKASToolItem); end else begin if AKASToolItem is TKASProgramItem then begin AddToSecondyText(TKASProgramItem(AKASToolItem).Command); frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem( frmTreeViewMenu.tvMainMenu, ANode, sSimiliCaptionToAddToMenu, sSecondaryText, 2, AKASToolItem); end else begin if AKASToolItem is TKASMenuItem then begin if TKASMenuItem(AKASToolItem).SubItems.Count > 0 then begin ASubNode := frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, ANode, sSimiliCaptionToAddToMenu, sSecondaryText, 0, nil); RecursiveAddTheseTKASToolItems(TKASMenuItem(AKASToolItem), ASubNode); end; end; end; end; end; end; var // Variables declared *afer* the recursive block to make sure we won't use it. RootNode: TTreeNode; iKASToolButton: integer; local_Result: integer; AKASToolButton: TKASToolButton; begin Result := nil; ReturnedTypeDispatcher := -1; frmTreeViewMenu := TfrmTreeViewMenu.Create(frmMain); try frmTreeViewMenu.SetContextMode(ContextMode, WantedPosX, WantedPosY, WantedWidth, WantedHeight); frmTreeViewMenu.tvMainMenu.BeginUpdate; for iKASToolButton := 0 to pred(AKASToolBar.ButtonList.Count) do begin sSimiliCaptionToAddToMenu := ''; sSecondaryText := ''; AKASToolButton := TKASToolButton(AKASToolBar.ButtonList.Items[iKASToolButton]); if AKASToolButton.ToolItem is TKASNormalItem then sSimiliCaptionToAddToMenu := TKASNormalItem(AKASToolButton.ToolItem).Hint; if AKASToolButton.ToolItem is TKASCommandItem then begin AddToSecondyText(TKASCommandItem(AKASToolButton.ToolItem).Command); frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, nil, sSimiliCaptionToAddToMenu, sSecondaryText, 1, AKASToolButton); end else begin if AKASToolButton.ToolItem is TKASProgramItem then begin AddToSecondyText(TKASProgramItem(AKASToolButton.ToolItem).Command); frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, nil, sSimiliCaptionToAddToMenu, sSecondaryText, 1, AKASToolButton); end else begin if AKASToolButton.ToolItem is TKASMenuItem then begin if TKASMenuItem(AKASToolButton.ToolItem).SubItems.Count > 0 then begin RootNode := frmTreeViewMenu.TreeViewMenuGenericRoutineAndVarHolder.AddTreeViewMenuItem(frmTreeViewMenu.tvMainMenu, nil, sSimiliCaptionToAddToMenu, sSecondaryText, 0, nil); RecursiveAddTheseTKASToolItems(TKASMenuItem(AKASToolButton.ToolItem), RootNode); end; end; end; end; end; frmTreeViewMenu.HideUnmatchingNode; if not frmTreeViewMenu.bTargetFixedWidth then frmTreeViewMenu.SetSizeToLargestElement; frmTreeViewMenu.tvMainMenu.EndUpdate; local_Result := frmTreeViewMenu.ShowModal; case local_Result of mrOk: begin ReturnedTypeDispatcher := TTreeMenuItem(frmTreeViewMenu.tvMainMenu.Items[frmTreeViewMenu.iFinalSelectedIndex].Data).TypeDispatcher; Result := TTreeMenuItem(frmTreeViewMenu.tvMainMenu.Items[frmTreeViewMenu.iFinalSelectedIndex].Data).PointerSourceData; end; mrYes: frmMain.Commands.cm_ConfigTreeViewMenus([]); mrAll: frmMain.Commands.cm_ConfigTreeViewMenusColors([]); end; finally FreeAndNil(frmTreeViewMenu); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ftweakplugin.lfm���������������������������������������������������������������0000644�0001750�0000144�00000047435�14743153644�016612� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmTweakPlugin: TfrmTweakPlugin Left = 297 Height = 703 Top = 155 Width = 533 AutoSize = True Caption = 'Tweak plugin' ClientHeight = 703 ClientWidth = 533 OnCreate = FormCreate Position = poScreenCenter ShowInTaskBar = stNever LCLVersion = '2.2.7.0' object nbTweakAll: TNotebook Left = 0 Height = 664 Top = 0 Width = 533 PageIndex = 0 Align = alClient AutoSize = True TabOrder = 0 TabStop = True object pgTweakPacker: TPage object pnlTweak: TPanel Left = 6 Height = 652 Top = 6 Width = 521 Align = alClient BorderSpacing.Around = 6 BevelOuter = bvNone BorderStyle = bsSingle ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 8 ClientHeight = 648 ClientWidth = 517 TabOrder = 0 object lblFlagsValue: TLabel AnchorSideLeft.Control = lblFlags AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = lblFlags AnchorSideTop.Side = asrBottom Left = 25 Height = 1 Top = 87 Width = 1 ParentColor = False end object lblPlugin: TLabel AnchorSideLeft.Control = pnlTweak AnchorSideTop.Control = fnePlugin1 AnchorSideTop.Side = asrCenter Left = 10 Height = 15 Top = 12 Width = 37 BorderSpacing.Top = 12 Caption = '&Plugin:' ParentColor = False end object lblExtension: TLabel AnchorSideLeft.Control = lblPlugin AnchorSideTop.Control = pnlPackerExtsButtons AnchorSideTop.Side = asrCenter Left = 10 Height = 15 Top = 44 Width = 54 BorderSpacing.Top = 12 Caption = '&Extension:' FocusControl = cbExt ParentColor = False end object lblFlags: TLabel AnchorSideLeft.Control = lblExtension AnchorSideTop.Control = pnlPackerExtsButtons AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 72 Width = 30 BorderSpacing.Top = 8 Caption = 'Flags:' ParentColor = False end object pnlPackerExtsButtons: TPanel AnchorSideLeft.Control = lblExtension AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fnePlugin1 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativePlugin1 AnchorSideRight.Side = asrBottom Left = 76 Height = 25 Top = 39 Width = 431 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 12 BevelOuter = bvNone ChildSizing.EnlargeHorizontal = crsScaleChilds ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.Layout = cclTopToBottomThenLeftToRight ClientHeight = 25 ClientWidth = 431 TabOrder = 0 object cbExt: TComboBox Left = 0 Height = 23 Top = 0 Width = 128 Constraints.MinWidth = 80 ItemHeight = 15 OnChange = cbExtChange Style = csDropDownList TabOrder = 0 end object btnRemove: TButton Left = 128 Height = 25 Top = 0 Width = 101 AutoSize = True Caption = '&Remove' Constraints.MinWidth = 80 OnClick = btnRemoveClick TabOrder = 1 end object btnAdd: TButton Left = 229 Height = 25 Top = 0 Width = 101 AutoSize = True Caption = 'A&dd new' Constraints.MinWidth = 80 OnClick = btnAddClick TabOrder = 2 end object btnChange: TButton Left = 330 Height = 25 Top = 0 Width = 101 AutoSize = True Caption = 'C&hange' Constraints.MinWidth = 80 OnClick = btnChangeClick TabOrder = 3 end end object pnlFlags: TPanel AnchorSideLeft.Control = pnlPackerExtsButtons AnchorSideTop.Control = lblFlags AnchorSideRight.Control = pnlTweak AnchorSideRight.Side = asrBottom Left = 76 Height = 221 Top = 72 Width = 226 AutoSize = True BevelOuter = bvNone ChildSizing.Layout = cclLeftToRightThenTopToBottom ClientHeight = 221 ClientWidth = 226 TabOrder = 1 object cbPK_CAPS_NEW: TCheckBox Left = 0 Height = 19 Top = 0 Width = 226 Caption = 'Can create new archi&ves' OnClick = cbPackerFlagsClick TabOrder = 0 end object cbPK_CAPS_MODIFY: TCheckBox Left = 0 Height = 19 Top = 19 Width = 226 Caption = 'Can &modify existing archives' OnClick = cbPackerFlagsClick TabOrder = 1 end object cbPK_CAPS_MULTIPLE: TCheckBox Left = 0 Height = 19 Top = 38 Width = 226 Caption = '&Archive can contain multiple files' OnClick = cbPackerFlagsClick TabOrder = 2 end object cbPK_CAPS_DELETE: TCheckBox Left = 0 Height = 19 Top = 57 Width = 226 Caption = 'Can de&lete files' OnClick = cbPackerFlagsClick TabOrder = 3 end object cbPK_CAPS_OPTIONS: TCheckBox Left = 0 Height = 19 Top = 76 Width = 226 Caption = 'S&upports the options dialogbox' OnClick = cbPackerFlagsClick TabOrder = 4 end object cbPK_CAPS_MEMPACK: TCheckBox Left = 0 Height = 19 Top = 95 Width = 226 Caption = 'Supports pac&king in memory' OnClick = cbPackerFlagsClick TabOrder = 5 end object cbPK_CAPS_BY_CONTENT: TCheckBox Left = 0 Height = 19 Top = 114 Width = 226 Caption = 'De&tect archive type by content' OnClick = cbPackerFlagsClick TabOrder = 6 end object cbPK_CAPS_SEARCHTEXT: TCheckBox Left = 0 Height = 19 Top = 133 Width = 226 Caption = 'Allow searchin&g for text in archives' OnClick = cbPackerFlagsClick TabOrder = 7 end object cbPK_CAPS_HIDE: TCheckBox Left = 0 Height = 19 Top = 152 Width = 226 Caption = 'Sho&w as normal files (hide packer icon)' OnClick = cbPackerFlagsClick TabOrder = 8 end object cbPK_CAPS_ENCRYPT: TCheckBox Left = 0 Height = 19 Top = 171 Width = 226 Caption = 'Supports e&ncryption' OnClick = cbPackerFlagsClick TabOrder = 9 end object btnDefault: TButton AnchorSideLeft.Control = cbPK_CAPS_ENCRYPT AnchorSideTop.Control = cbPK_CAPS_ENCRYPT AnchorSideTop.Side = asrBottom Left = 0 Height = 25 Top = 196 Width = 100 AutoSize = True BorderSpacing.Top = 6 Caption = 'De&fault' Constraints.MinWidth = 100 OnClick = btnDefaultClick TabOrder = 10 end end object fnePlugin1: TFileNameEdit AnchorSideLeft.Control = lblPlugin2 AnchorSideTop.Control = pnlTweak AnchorSideRight.Control = btnRelativePlugin1 Left = 71 Height = 23 Top = 8 Width = 412 DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Bottom = 8 MaxLength = 0 TabOrder = 2 end object btnRelativePlugin1: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fnePlugin1 AnchorSideRight.Control = pnlTweak AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fnePlugin1 AnchorSideBottom.Side = asrBottom Left = 483 Height = 23 Hint = 'Some functions to select appropriate path' Top = 8 Width = 24 Anchors = [akTop, akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativePlugin1Click end end end object pgTweakOther: TPage object pnlTweakOther: TPanel Left = 6 Height = 652 Top = 6 Width = 521 Align = alClient Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Around = 6 BevelOuter = bvNone BorderStyle = bsSingle ClientHeight = 648 ClientWidth = 517 TabOrder = 0 object lblName: TLabel AnchorSideLeft.Control = lblPlugin2 AnchorSideTop.Control = fnePlugin2 AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 60 Width = 35 Caption = '&Name:' FocusControl = edtName ParentColor = False end object lblDetectStr: TLabel AnchorSideLeft.Control = lblName AnchorSideTop.Control = edtName AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 112 Width = 70 Caption = 'D&etect string:' FocusControl = edtDetectStr ParentColor = False end object lblDescription: TLabel AnchorSideLeft.Control = lblDetectStr AnchorSideTop.Control = edtDetectStr AnchorSideTop.Side = asrBottom Left = 10 Height = 15 Top = 164 Width = 63 Caption = '&Description:' FocusControl = edtDescription ParentColor = False end object edtName: TEdit AnchorSideLeft.Control = lblName AnchorSideTop.Control = lblName AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativePlugin2 AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 81 Width = 497 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Bottom = 8 TabOrder = 1 end object edtDetectStr: TEdit AnchorSideTop.Control = lblDetectStr AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativePlugin2 AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 133 Width = 497 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Bottom = 8 TabOrder = 2 end object edtDescription: TEdit AnchorSideTop.Control = lblDescription AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativePlugin2 AnchorSideRight.Side = asrBottom Left = 10 Height = 23 Top = 185 Width = 497 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Bottom = 8 TabOrder = 3 end object lblPlugin2: TLabel AnchorSideLeft.Control = pnlTweakOther AnchorSideTop.Control = pnlTweakOther Left = 10 Height = 15 Top = 8 Width = 37 BorderSpacing.Left = 10 BorderSpacing.Top = 8 Caption = '&Plugin:' FocusControl = fnePlugin2 ParentColor = False end object fnePlugin2: TFileNameEdit AnchorSideLeft.Control = lblPlugin2 AnchorSideTop.Control = lblPlugin2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = btnRelativePlugin2 Left = 10 Height = 23 Top = 29 Width = 473 DialogOptions = [] FilterIndex = 0 HideDirectories = False ButtonWidth = 23 Constraints.MinWidth = 350 NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 6 BorderSpacing.Bottom = 8 MaxLength = 0 TabOrder = 0 end object btnRelativePlugin2: TSpeedButton AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = fnePlugin2 AnchorSideRight.Control = pnlTweakOther AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = fnePlugin2 AnchorSideBottom.Side = asrBottom Left = 483 Height = 23 Hint = 'Some functions to select appropriate path' Top = 29 Width = 24 Anchors = [akTop, akRight, akBottom] BorderSpacing.Right = 10 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000002C86D8702D88 D8A62D87D8EA2D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88D8F72D88 D8F72D88D8F72D87D8F72D88D8F12C86D893FFFFFF00FFFFFF00338ED9E6DCF0 FAF0A7DDF4FD9EDBF4FF96DAF3FF8ED8F3FF86D7F3FF7FD4F2FF79D3F2FF72D2 F1FF6CD0F1FF69CFF1FFC2EAF8FE338ED9F0FFFFFF00FFFFFF003594DAF7EFFA FEFFA1E9F9FF91E5F8FF81E1F7FF72DEF6FF63DAF5FF54D7F4FF47D3F3FF39D0 F2FF2ECDF1FF26CBF0FFCAF2FBFF3594DAF7FFFFFF00FFFFFF00369ADAF8F2FA FDFFB3EDFAFFA4E9F9FF95E6F8FF85E2F7FF81E1F7FF7AE0F7FF7CE0F7FF62DA F5FF54D6F3FF47D3F2FFE8F9FDFF3594DAFFFFFFFF00FFFFFF0036A1DAF9F6FC FEFFC8F2FCFFB9EFFBFF94DFEFFF8CE4F8FF99CED3FF91D0D8FF82E1F7FF6DDD F6FF61DAF5FF57D7F4FFE7F8FDFF3594DAFFFFFFFF00FFFFFF0037A6DAFAFEFF FFFFF8FDFFFFF6FDFFFFF4F4F2FFE8FAFEFFB6D7D8FFAAC7C5FF92D8E4FF7DE0 F7FF72DDF6FF68DBF5FFE9F9FDFF3594DAFFFFFFFF00FFFFFF0035ABDAFAE8F6 FBFF7EC5EAFF4AA3DFFF5E97C2FF4DA3DEFFF2F1EDFFF3EFECFFEDE5DFFFEDEB E8FFF1F9FDFFF0F9FDFFFFFFFFFF3594DAFFFFFFFF00FFFFFF0036AADAF2F1FA FDFF94DEF5FF93DCF4FFACBFBFFFBC9F90FF64A1CFFF3594DAFF3594DAFF3594 DAFF3594DAFF3594DAFF3594DAFF3594DAFFFFFFFF00FFFFFF0035AFDAF0F7FC FEFF8EE4F8FF91DEF5FF9FE0F5FFC5C7C2FFDFA583FFEDC8B3FFEDCDB8FFE9BE A3FFD58E64FFEEFBFEFFFAFDFFF936AFDAD4FFFFFF00FFFFFF0036B3DAF8FDFE FEFFFEFFFFFFFEFEFFFFFDFEFFFFFEFFFFFFE7D6C9FFE0A987FFEBC7B0FFDDA1 7CFFBCA595FF839DA5FC7BAEBEEC6395A58E81818117FFFFFF0034B4D9D05EC2 E1FA60C3E2FA60C3E2FA60C3E2FA5FC3E2FA3CB6DBDDD5B1968CDDAB8DF9C4AF A3FFD5D5D5FFBBBBBBFFA6A6A6FFA0A0A0FF848484E482828262FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00969696029494 94C5CBCBCBFFD2D2D2FFC9C9C9FFD2D2D2FFC6C6C6FF858585E8FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009898 9855B2B2B2FFD6D6D6FF919191DA8E8E8EF5C0C0C0FF898989FDFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009B9B 9B54B5B5B5FFE6E6E6FF949494EF929292AF8F8F8FA68D8D8D90FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009E9E 9E1B9C9C9CE4E1E1E1FFD2D2D2FF969696ABFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF009E9E9E629D9D9DE89B9B9BF999999992FFFFFF00FFFFFF00 } OnClick = btnRelativePlugin2Click end end end end object pnlButtons: TPanel Left = 0 Height = 39 Top = 664 Width = 533 Align = alBottom AutoSize = True BevelOuter = bvNone ClientHeight = 39 ClientWidth = 533 TabOrder = 1 object btnOK: TButton AnchorSideTop.Control = btnCancel AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btnCancel Left = 318 Height = 25 Top = 7 Width = 100 Anchors = [akTop, akRight] AutoSize = True BorderSpacing.Right = 8 Caption = '&OK' Constraints.MinWidth = 100 Default = True ModalResult = 1 TabOrder = 0 end object btnCancel: TButton AnchorSideTop.Control = pnlButtons AnchorSideRight.Control = pnlButtons AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlButtons AnchorSideBottom.Side = asrBottom Left = 426 Height = 25 Top = 7 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True BorderSpacing.Around = 7 Cancel = True Caption = '&Cancel' Constraints.MinWidth = 100 ModalResult = 2 TabOrder = 1 end end object pmPathHelper: TPopupMenu Left = 224 Top = 600 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ftweakplugin.lrj���������������������������������������������������������������0000644�0001750�0000144�00000011237�14743153644�016612� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":49154606,"name":"tfrmtweakplugin.caption","sourcebytes":[84,119,101,97,107,32,112,108,117,103,105,110],"value":"Tweak plugin"}, {"hash":121364138,"name":"tfrmtweakplugin.lblplugin.caption","sourcebytes":[38,80,108,117,103,105,110,58],"value":"&Plugin:"}, {"hash":208882618,"name":"tfrmtweakplugin.lblextension.caption","sourcebytes":[38,69,120,116,101,110,115,105,111,110,58],"value":"&Extension:"}, {"hash":80903786,"name":"tfrmtweakplugin.lblflags.caption","sourcebytes":[70,108,97,103,115,58],"value":"Flags:"}, {"hash":193742565,"name":"tfrmtweakplugin.btnremove.caption","sourcebytes":[38,82,101,109,111,118,101],"value":"&Remove"}, {"hash":212234487,"name":"tfrmtweakplugin.btnadd.caption","sourcebytes":[65,38,100,100,32,110,101,119],"value":"A&dd new"}, {"hash":97420437,"name":"tfrmtweakplugin.btnchange.caption","sourcebytes":[67,38,104,97,110,103,101],"value":"C&hange"}, {"hash":16913811,"name":"tfrmtweakplugin.cbpk_caps_new.caption","sourcebytes":[67,97,110,32,99,114,101,97,116,101,32,110,101,119,32,97,114,99,104,105,38,118,101,115],"value":"Can create new archi&ves"}, {"hash":79381779,"name":"tfrmtweakplugin.cbpk_caps_modify.caption","sourcebytes":[67,97,110,32,38,109,111,100,105,102,121,32,101,120,105,115,116,105,110,103,32,97,114,99,104,105,118,101,115],"value":"Can &modify existing archives"}, {"hash":238525683,"name":"tfrmtweakplugin.cbpk_caps_multiple.caption","sourcebytes":[38,65,114,99,104,105,118,101,32,99,97,110,32,99,111,110,116,97,105,110,32,109,117,108,116,105,112,108,101,32,102,105,108,101,115],"value":"&Archive can contain multiple files"}, {"hash":224030211,"name":"tfrmtweakplugin.cbpk_caps_delete.caption","sourcebytes":[67,97,110,32,100,101,38,108,101,116,101,32,102,105,108,101,115],"value":"Can de&lete files"}, {"hash":159368872,"name":"tfrmtweakplugin.cbpk_caps_options.caption","sourcebytes":[83,38,117,112,112,111,114,116,115,32,116,104,101,32,111,112,116,105,111,110,115,32,100,105,97,108,111,103,98,111,120],"value":"S&upports the options dialogbox"}, {"hash":124048393,"name":"tfrmtweakplugin.cbpk_caps_mempack.caption","sourcebytes":[83,117,112,112,111,114,116,115,32,112,97,99,38,107,105,110,103,32,105,110,32,109,101,109,111,114,121],"value":"Supports pac&king in memory"}, {"hash":83979044,"name":"tfrmtweakplugin.cbpk_caps_by_content.caption","sourcebytes":[68,101,38,116,101,99,116,32,97,114,99,104,105,118,101,32,116,121,112,101,32,98,121,32,99,111,110,116,101,110,116],"value":"De&tect archive type by content"}, {"hash":120574099,"name":"tfrmtweakplugin.cbpk_caps_searchtext.caption","sourcebytes":[65,108,108,111,119,32,115,101,97,114,99,104,105,110,38,103,32,102,111,114,32,116,101,120,116,32,105,110,32,97,114,99,104,105,118,101,115],"value":"Allow searchin&g for text in archives"}, {"hash":231932041,"name":"tfrmtweakplugin.cbpk_caps_hide.caption","sourcebytes":[83,104,111,38,119,32,97,115,32,110,111,114,109,97,108,32,102,105,108,101,115,32,40,104,105,100,101,32,112,97,99,107,101,114,32,105,99,111,110,41],"value":"Sho&w as normal files (hide packer icon)"}, {"hash":18290926,"name":"tfrmtweakplugin.cbpk_caps_encrypt.caption","sourcebytes":[83,117,112,112,111,114,116,115,32,101,38,110,99,114,121,112,116,105,111,110],"value":"Supports e&ncryption"}, {"hash":130846868,"name":"tfrmtweakplugin.btndefault.caption","sourcebytes":[68,101,38,102,97,117,108,116],"value":"De&fault"}, {"hash":15252584,"name":"tfrmtweakplugin.btnrelativeplugin1.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":45384586,"name":"tfrmtweakplugin.lblname.caption","sourcebytes":[38,78,97,109,101,58],"value":"&Name:"}, {"hash":101917722,"name":"tfrmtweakplugin.lbldetectstr.caption","sourcebytes":[68,38,101,116,101,99,116,32,115,116,114,105,110,103,58],"value":"D&etect string:"}, {"hash":181829802,"name":"tfrmtweakplugin.lbldescription.caption","sourcebytes":[38,68,101,115,99,114,105,112,116,105,111,110,58],"value":"&Description:"}, {"hash":121364138,"name":"tfrmtweakplugin.lblplugin2.caption","sourcebytes":[38,80,108,117,103,105,110,58],"value":"&Plugin:"}, {"hash":15252584,"name":"tfrmtweakplugin.btnrelativeplugin2.hint","sourcebytes":[83,111,109,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,115,101,108,101,99,116,32,97,112,112,114,111,112,114,105,97,116,101,32,112,97,116,104],"value":"Some functions to select appropriate path"}, {"hash":11067,"name":"tfrmtweakplugin.btnok.caption","sourcebytes":[38,79,75],"value":"&OK"}, {"hash":177752476,"name":"tfrmtweakplugin.btncancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ftweakplugin.pas���������������������������������������������������������������0000644�0001750�0000144�00000032446�14743153644�016613� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Plugin tweak window Copyright (C) 2008-2018 Alexander Koblov (alexx2000@mail.ru) 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 } unit fTweakPlugin; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, ExtCtrls, StdCtrls, EditBtn, Buttons, Menus, uWCXModule, uGlobs; type { TfrmTweakPlugin } TfrmTweakPlugin = class(TForm) btnAdd: TButton; btnCancel: TButton; btnChange: TButton; btnDefault: TButton; btnOK: TButton; btnRelativePlugin2: TSpeedButton; btnRelativePlugin1: TSpeedButton; btnRemove: TButton; cbExt: TComboBox; cbPK_CAPS_BY_CONTENT: TCheckBox; cbPK_CAPS_DELETE: TCheckBox; cbPK_CAPS_ENCRYPT: TCheckBox; cbPK_CAPS_HIDE: TCheckBox; cbPK_CAPS_MEMPACK: TCheckBox; cbPK_CAPS_MODIFY: TCheckBox; cbPK_CAPS_MULTIPLE: TCheckBox; cbPK_CAPS_NEW: TCheckBox; cbPK_CAPS_OPTIONS: TCheckBox; cbPK_CAPS_SEARCHTEXT: TCheckBox; edtDescription: TEdit; edtDetectStr: TEdit; edtName: TEdit; fnePlugin2: TFileNameEdit; fnePlugin1: TFileNameEdit; pmPathHelper: TPopupMenu; pnlTweakOther: TPanel; lblDescription: TLabel; lblDetectStr: TLabel; lblName: TLabel; lblExtension: TLabel; lblFlags: TLabel; lblFlagsValue: TLabel; lblPlugin2: TLabel; lblPackerPlugin: TLabel; lblPlugin: TLabel; nbTweakAll: TNotebook; pnlButtons: TPanel; pnlFlags: TPanel; pnlPackerExtsButtons: TPanel; pgTweakPacker: TPage; pgTweakOther: TPage; pnlTweak: TPanel; procedure btnAddClick(Sender: TObject); procedure btnChangeClick(Sender: TObject); procedure btnDefaultClick(Sender: TObject); procedure btnRelativePlugin1Click(Sender: TObject); procedure btnRelativePlugin2Click(Sender: TObject); procedure btnRemoveClick(Sender: TObject); procedure cbExtChange(Sender: TObject); procedure cbPackerFlagsClick(Sender: TObject); procedure FormCreate(Sender: TObject); private FWCXPlugins: TWCXModuleList; FPluginFileName: String; iPrevIndex: Integer; function GetDefaultFlags(PluginFileName: String): PtrInt; public constructor Create(TheOwner: TComponent); override; procedure LoadConfiguration(PluginIndex:integer); procedure SaveConfiguration(PluginIndex:integer); destructor Destroy; override; end; function ShowTweakPluginDlg(PluginType: TPluginType; PluginIndex: Integer): Boolean; implementation {$R *.lfm} uses //Lazarus, Free-Pascal, etc. Math, Dialogs, LCLVersion, //DC fOptionsPluginsDSX, fOptionsPluginsWCX, fOptionsPluginsWDX, fOptionsPluginsWFX, fOptionsPluginsWLX, WcxPlugin, uDCUtils, uLng, uSpecialDir, uWfxPluginUtil; function ShowTweakPluginDlg(PluginType: TPluginType; PluginIndex: Integer): Boolean; var I, iIndex: Integer; begin with TfrmTweakPlugin.Create(Application) do try case PluginType of ptDSX: begin nbTweakAll.PageIndex:= 1; fnePlugin2.Text:= tmpDSXPlugins.GetDsxModule(PluginIndex).FileName; edtDescription.Text:= tmpDSXPlugins.GetDsxModule(PluginIndex).Descr; edtName.Text:= tmpDSXPlugins.GetDsxModule(PluginIndex).Name; lblDetectStr.Visible:= False; edtDetectStr.Visible:= False; ActiveControl:=fnePlugin2; end; ptWCX: begin nbTweakAll.PageIndex:= 0; FWCXPlugins:= TWCXModuleList.Create; FWCXPlugins.Assign(tmpWCXPlugins); FPluginFileName := FWCXPlugins.FileName[PluginIndex]; fnePlugin1.FileName:= FPluginFileName; for I:= 0 to FWCXPlugins.Count - 1 do if FWCXPlugins.FileName[I] = fnePlugin1.FileName then begin if cbExt.Items.Count=0 then lblPlugin.Tag:=IfThen(FWCXPlugins.Enabled[I],1,0); cbExt.Items.AddObject(FWCXPlugins.Ext[I], TObject(FWCXPlugins.Flags[I])); end; iPrevIndex:= -1; cbExt.ItemIndex := cbExt.Items.IndexOf(FWCXPlugins.Ext[PluginIndex]); if (cbExt.ItemIndex = -1) then cbExt.ItemIndex := 0; cbExtChange(cbExt); btnRemove.Enabled:= (cbExt.Items.Count > 1); end; ptWDX: begin nbTweakAll.PageIndex:= 1; fnePlugin2.Text:= tmpWDXPlugins.GetWdxModule(PluginIndex).FileName; edtDetectStr.Text:= tmpWDXPlugins.GetWdxModule(PluginIndex).DetectStr; edtName.Text:= tmpWDXPlugins.GetWdxModule(PluginIndex).Name; lblDescription.Visible:= False; edtDescription.Visible:= False; ActiveControl:=fnePlugin2; end; ptWFX: begin nbTweakAll.PageIndex:= 1; fnePlugin2.Text:= tmpWFXPlugins.FileName[PluginIndex]; edtName.Text:= tmpWFXPlugins.Name[PluginIndex]; lblDetectStr.Visible:= False; edtDetectStr.Visible:= False; lblDescription.Visible:= False; edtDescription.Visible:= False; ActiveControl:=fnePlugin2; end; ptWLX: begin nbTweakAll.PageIndex:= 1; fnePlugin2.Text:= tmpWLXPlugins.GetWlxModule(PluginIndex).FileName; edtDetectStr.Text:= tmpWLXPlugins.GetWlxModule(PluginIndex).DetectStr; edtName.Text:= tmpWLXPlugins.GetWlxModule(PluginIndex).Name; lblDescription.Visible:= False; edtDescription.Visible:= False; ActiveControl:=fnePlugin2; end; end; LoadConfiguration(ord(PluginType)); gSpecialDirList.PopulateMenuWithSpecialDir(pmPathHelper,mp_PATHHELPER,nil); Result:= (ShowModal = mrOK); if Result then case PluginType of ptDSX: begin tmpDSXPlugins.GetDsxModule(PluginIndex).FileName:= fnePlugin2.Text; tmpDSXPlugins.GetDsxModule(PluginIndex).Descr := edtDescription.Text; tmpDSXPlugins.GetDsxModule(PluginIndex).Name:= edtName.Text; end; ptWCX: begin for I:= 0 to cbExt.Items.Count - 1 do begin iIndex:= FWCXPlugins.Find(FPluginFileName, cbExt.Items[I]); if iIndex >= 0 then begin FWCXPlugins.FileName[iIndex]:= fnePlugin1.FileName; FWCXPlugins.Flags[iIndex]:= PtrInt(cbExt.Items.Objects[I]); end; end; tmpWCXPlugins.Assign(FWCXPlugins); end; ptWDX: begin tmpWDXPlugins.GetWdxModule(PluginIndex).FileName:= fnePlugin2.Text; tmpWDXPlugins.GetWdxModule(PluginIndex).DetectStr:= edtDetectStr.Text; tmpWDXPlugins.GetWdxModule(PluginIndex).Name:= edtName.Text; end; ptWFX: begin tmpWFXPlugins.FileName[PluginIndex]:= fnePlugin2.Text; tmpWFXPlugins.Name[PluginIndex]:= RepairPluginName(edtName.Text); end; ptWLX: begin tmpWLXPlugins.GetWlxModule(PluginIndex).FileName:= fnePlugin2.Text; tmpWLXPlugins.GetWlxModule(PluginIndex).DetectStr:= edtDetectStr.Text; tmpWLXPlugins.GetWlxModule(PluginIndex).Name:= edtName.Text; end; end; SaveConfiguration(ord(PluginType)); finally Free; end; end; { TfrmTweakPlugin } constructor TfrmTweakPlugin.Create(TheOwner: TComponent); begin iPrevIndex := -1; inherited Create(TheOwner); pgTweakOther.AutoSize:= True; pgTweakPacker.AutoSize:= True; end; { TfrmTweakPlugin.LoadConfiguration } // Just to save width. // Firt time it opens according to "autosize" system will determine, then when we exit it will be saved and then it will be restore to next session. procedure TfrmTweakPlugin.LoadConfiguration(PluginIndex:integer); begin if (gTweakPluginWidth[PluginIndex]<>0) AND (gTweakPluginHeight[PluginIndex]<>0) then begin AutoSize:=False; width := gTweakPluginWidth[PluginIndex]; height := gTweakPluginHeight[PluginIndex]; end; end; procedure TfrmTweakPlugin.SaveConfiguration(PluginIndex:integer); begin gTweakPluginWidth[PluginIndex] := width; gTweakPluginHeight[PluginIndex] := height; end; destructor TfrmTweakPlugin.Destroy; begin inherited; if Assigned(FWCXPlugins) then FreeAndNil(FWCXPlugins); end; procedure TfrmTweakPlugin.cbExtChange(Sender: TObject); var iFlags: PtrInt; begin iPrevIndex:= cbExt.ItemIndex; iFlags:= PtrInt(cbExt.Items.Objects[cbExt.ItemIndex]); lblFlagsValue.Caption:= '('+IntToStr(iFlags)+')'; cbPK_CAPS_NEW.Checked := (iFlags and PK_CAPS_NEW) <> 0; cbPK_CAPS_MODIFY.Checked := (iFlags and PK_CAPS_MODIFY) <> 0; cbPK_CAPS_MULTIPLE.Checked := (iFlags and PK_CAPS_MULTIPLE) <> 0; cbPK_CAPS_DELETE.Checked := (iFlags and PK_CAPS_DELETE) <> 0; cbPK_CAPS_OPTIONS.Checked := (iFlags and PK_CAPS_OPTIONS) <> 0; cbPK_CAPS_MEMPACK.Checked := (iFlags and PK_CAPS_MEMPACK) <> 0; cbPK_CAPS_BY_CONTENT.Checked := (iFlags and PK_CAPS_BY_CONTENT) <> 0; cbPK_CAPS_SEARCHTEXT.Checked := (iFlags and PK_CAPS_SEARCHTEXT) <> 0; cbPK_CAPS_HIDE.Checked := (iFlags and PK_CAPS_HIDE) <> 0; cbPK_CAPS_ENCRYPT.Checked := (iFlags and PK_CAPS_ENCRYPT) <> 0; end; procedure TfrmTweakPlugin.cbPackerFlagsClick(Sender: TObject); var iFlags: PtrInt; begin if iPrevIndex >= 0 then // save new flags begin iFlags:= 0; if cbPK_CAPS_NEW.Checked then iFlags:= iFlags or PK_CAPS_NEW; if cbPK_CAPS_MODIFY.Checked then iFlags:= iFlags or PK_CAPS_MODIFY; if cbPK_CAPS_MULTIPLE.Checked then iFlags:= iFlags or PK_CAPS_MULTIPLE; if cbPK_CAPS_DELETE.Checked then iFlags:= iFlags or PK_CAPS_DELETE; if cbPK_CAPS_OPTIONS.Checked then iFlags:= iFlags or PK_CAPS_OPTIONS; if cbPK_CAPS_MEMPACK.Checked then iFlags:= iFlags or PK_CAPS_MEMPACK; if cbPK_CAPS_BY_CONTENT.Checked then iFlags:= iFlags or PK_CAPS_BY_CONTENT; if cbPK_CAPS_SEARCHTEXT.Checked then iFlags:= iFlags or PK_CAPS_SEARCHTEXT; if cbPK_CAPS_HIDE.Checked then iFlags:= iFlags or PK_CAPS_HIDE; if cbPK_CAPS_ENCRYPT.Checked then iFlags:= iFlags or PK_CAPS_ENCRYPT; cbExt.Items.Objects[iPrevIndex]:= TObject(iFlags); lblFlagsValue.Caption:= '('+IntToStr(iFlags)+')'; end; end; procedure TfrmTweakPlugin.FormCreate(Sender: TObject); begin {$if not declared(lcl_fullversion) or (lcl_fullversion < 093100)} nbTweakAll.ShowTabs := False; nbTweakAll.TabStop := True; {$endif} end; procedure TfrmTweakPlugin.btnDefaultClick(Sender: TObject); begin cbExt.Items.Objects[cbExt.ItemIndex]:= TObject(GetDefaultFlags(fnePlugin1.FileName)); iPrevIndex:= -1; cbExtChange(cbExt); end; procedure TfrmTweakPlugin.btnRelativePlugin1Click(Sender: TObject); begin fnePlugin1.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fnePlugin1, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmTweakPlugin.btnRelativePlugin2Click(Sender: TObject); begin fnePlugin2.SetFocus; gSpecialDirList.SetSpecialDirRecipientAndItsType(fnePlugin2, pfFILE); pmPathHelper.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); end; procedure TfrmTweakPlugin.btnRemoveClick(Sender: TObject); var I, OldIndex: Integer; begin iPrevIndex:= -1; // Must be before cbExt.Items.Delete, because it may trigger cbExtChange. OldIndex := cbExt.ItemIndex; I:= FWCXPlugins.Find(FPluginFileName, cbExt.Text); if I >= 0 then FWCXPlugins.Delete(I); cbExt.Items.Delete(cbExt.ItemIndex); if OldIndex >= cbExt.Items.Count then OldIndex := OldIndex - 1; cbExt.ItemIndex := OldIndex; if iPrevIndex = -1 then // Call only if not already triggerred. cbExtChange(cbExt); btnRemove.Enabled:= (cbExt.Items.Count > 1); end; procedure TfrmTweakPlugin.btnAddClick(Sender: TObject); var sExt: String = ''; iFlags: PtrInt; I: Integer; begin if InputQuery(rsOptEnterExt,Format(rsOptAssocPluginWith, [fnePlugin1.FileName]), sExt) then begin iFlags:= GetDefaultFlags(fnePlugin1.FileName); cbExt.ItemIndex:= cbExt.Items.AddObject(sExt, TObject(iFlags)); I := FWCXPlugins.Add(cbExt.Items[cbExt.ItemIndex], iFlags, FPluginFileName); FWCXPlugins.Enabled[I] := (lblPlugin.Tag=1); iPrevIndex:= -1; cbExtChange(cbExt); btnRemove.Enabled:= (cbExt.Items.Count > 1); end; end; procedure TfrmTweakPlugin.btnChangeClick(Sender: TObject); var I: Integer; sExt: String; begin sExt:= cbExt.Items[cbExt.ItemIndex]; I:= FWCXPlugins.Find(FPluginFileName, sExt); if (I >= 0) and InputQuery(rsOptEnterExt,Format(rsOptAssocPluginWith, [fnePlugin1.FileName]), sExt) then begin FWCXPlugins.Ext[I]:= sExt; cbExt.Items[cbExt.ItemIndex]:= sExt; end; end; function TfrmTweakPlugin.GetDefaultFlags(PluginFileName: String): PtrInt; var WcxModule: TWcxModule; begin WcxModule := gWCXPlugins.LoadModule(PluginFileName); if not Assigned(WcxModule) then Exit(0); Result := WcxModule.GetPluginCapabilities; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fviewer.lfm��������������������������������������������������������������������0000755�0001750�0000144�00000226473�14743153644�015565� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmViewer: TfrmViewer Left = 930 Height = 366 Top = 427 Width = 521 HorzScrollBar.Page = 951 VertScrollBar.Page = 491 Caption = 'Viewer' ClientHeight = 366 ClientWidth = 521 Constraints.MinHeight = 100 Constraints.MinWidth = 200 Icon.Data = { CE1E000000000100030010100000010020006804000036000000181800000100 2000880900009E0400002020000001002000A8100000260E0000280000001000 0000200000000100200000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000959595B4818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF959595A8000000000000 0000818181FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEDEDEDFFEDEDEDFFEEEEEEFFEFEFEFFFEFEFEFFFF0F0 F0FFF0F0F0FFF1F1F1FFF2F2F2FFF2F2F2FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEDEDEDFFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F 72FFCF9F72FFCF9F72FFCF9F72FFF2F2F2FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFECECECFFCF9F72FF927A6DFF927B6EFF937B6EFF8F79 6DFF867469FF847368FFCF9F72FFF1F1F1FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFECECECFFCF9F72FFAD9889FFAE9989FFAF9A8AFF948C 86FF948C86FFA29489FFCF9F72FFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFECECECFFCF9F72FFCCC2A8FFD6F1EDFFC4D4C0FFD8B8 9AFFD8B89AFFD8B89AFFCF9F72FFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEBEBEBFFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F 72FFCF9F72FFCF9F72FFCF9F72FFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEBEBEBFFEBEBEBFFECECECFFECECECFFEDEDEDFFEDED EDFFE5EDEDFFECECECFFEEEEEEFFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEBEBEBFFC5C5C5FFC6C6C6FFC6C6C6FFC6C6C6FFC6C6 C6FFC6C6C6FFC6C6C6FFC7C7C7FFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEAEAEAFFEBEBEBFFEBEBEBFFECECECFFECECECFFECEC ECFFEDEDEDFFEDEDEDFFEEEEEEFFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFEAEAEAFFC4C4C4FFC5C5C5FFC5C5C5FFC6C6C6FFC6C6 C6FFC6C6C6FFC6C6C6FFC7C7C7FFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFECECECFFEAEAEAFFEAEAEAFFEBEBEBFFEBEBEBFFEBEB EBFFECECECFFECECECFFEDEDEDFFF0F0F0FFFFFFFFFF818181FF000000000000 0000818181FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF818181FF000000000000 0000999999AC818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF81818156000000000000 0000FFFF00000003000000030000000300000003000000030000000300000003 0000000300000003000000030000000300000003000000030000000300000003 0000280000001800000030000000010020000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0004000000100000001D0000002A000000360000004100000043000000460000 0045000000400000003700000026000000180000000D00000004000000010000 0000000000000000000000000000000000000000000083888683858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF696C6B620000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE8E8 E8FFEBEBEBFFE9E9E9FFEBEAEAFFECECECFFEDEDECFFEDEEEEFFEFEEEFFFF0F0 F0FFF1F2F1FFF2F2F3FFF3F4F3FFF4F5F5FFF5F6F5FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE8E8 E8FFEBEBEBFFE9E9E9FFE9E9E9FFEBEAEAFFEBEBEBFFECEDECFFEEEDEDFFEEEF EEFFF0F0F0FFF2F2F2FFF3F3F3FFF4F4F4FFF5F4F5FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE8E8 E8FFEAEAEAFFE8E8E9FFA9ACAAFFA9ACABFFAAADACFFAAADACFFABAEACFFABAE ADFFABAFADFFACAFADFFF2F2F2FFF3F3F3FFF4F4F3FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE8E8 E8FFEAEAEAFFE8E8E8FFE8E9E9FFEAEAE9FFEBEBEBFFECECECFFEDEDEDFFEDEE EEFFEFEEEFFFF0F0F0FFF0F1F0FFF2F2F2FFF3F3F2FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE7E7 E7FFFFFFFFFFE8E8E9FFA9ACAAFFA9ACABFFAAACACFFAAADACFFAAAEACFFAAAE ACFFABAEADFFABAEADFFABAFADFFABAFADFFF1F1F1FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFADAF AEFFE9E9E9FFE8E8E8FFE8E8E8FFE9E9E9FFEAEAEAFFEAEBEBFFEBECECFFECEC ECFFEDEDEDFFEEEEEEFFEEEEEEFFF0F0F0FFF0F0EFFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE6E6 E6FFE9E9E9FFE7E8E7FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F 72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFEFEEEFFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE6E6 E6FFE8E8E8FFE6E6E7FFCF9F72FF927A6DFF927B6EFF937B6EFF937C6EFF937C 6FFF8F796DFF867469FF847368FFCF9F72FFEEEEEEFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE5E5 E5FFE7E7E7FFE5E6E6FFCF9F72FFAD9889FFAE9989FFAF9A8AFFAF9A8AFFAC99 8AFF948C86FF948C86FFA29489FFCF9F72FFEDEDEDFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE4E4 E4FFFFFFFFFFE5E5E5FFCF9F72FFD8B89AFFCFBFA3FFD8B89AFFD9B99BFFD9B9 9BFFB8A492FFA79A8EFFAB9D8FFFCF9F72FFEBEBEBFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFACAF ADFFE6E6E6FFE4E4E5FFCF9F72FFC7C8B1FFE4F5F4FFC3DFD1FFD8B89AFFD8B8 9AFFD9B99BFFAF9F90FFCDB298FFCF9F72FFEAEBEAFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE2E2 E2FFE6E6E6FFE4E4E3FFCF9F72FFCCC2A8FFD6F1EDFFC4D4C0FFD8B89AFFD8B8 9AFFD8B89AFFD8B89AFFD8B89AFFCF9F72FFE9E9E9FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE1E1 E1FFE4E4E4FFE3E3E3FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFCF9F 72FFCF9F72FFCF9F72FFCF9F72FFCF9F72FFE8E8E8FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFE0E0 E0FFE3E3E3FFE2E2E2FFE2E2E2FFE3E3E4FFE4E4E5FFE4E4E4FFE4E4E4FFE5E6 E6FFE6E6E6FFE7E6E6FFE7E6E7FFE7E7E6FFE7E7E7FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFDFDF DFFFE2E2E2FFE1E1E1FFA6A9A8FFA6A9A8FFA6A9A8FFA6A9A8FFA6AAA8FFA7AA A9FFA7AAA9FFA7AAA9FFA7AAA9FFA7AAA9FFE5E5E5FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFDEDE DEFFE1E1E1FFE0E0E0FFE1E0E1FFE2E1E1FFE2E2E2FFE2E2E2FFE3E3E3FFE3E4 E4FFE4E4E4FFE4E4E4FFE5E5E4FFE5E5E5FFE4E4E4FFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A88FFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF858A88FF0000 00000000000000000000000000000000000000000000858A8882858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88FF858A88FF848987820000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FFFFFF00F8000700E0000700E0000700E0000700E000 0700E0000700E0000700E0000700E0000700E0000700E0000700E0000700E000 0700E0000700E0000700E0000700E0000700E0000700E0000700E0000700E000 0700FFFFFF00FFFFFF0028000000200000004000000001002000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000070000000F00000015000000160000001600000016000000160000 0016000000160000001600000016000000160000001600000016000000160000 00160000001600000016000000160000001600000016000000140000000F0000 0008000000010000000000000000000000000000000000000000000000060000 001D0000003000000040000000470000004A0000004A0000004A0000004A0000 004A0000004A0000004A0000004A0000004A0000004A0000004A0000004A0000 004A0000004A0000004A0000004A0000004A0000004A00000042000000460000 003B000000290000000C000000000000000000000000000000000000000D0000 002237373778565656F6565656FF565656FF565656FF565656FF565656FF5656 56FF565656FF565656FF565656FF565656FF565656FF565656FF565656FF5656 56FF565656FF565656FF565656FF565656FF565656FF565656FF575757F73333 3381000000310000001B00000002000000000000000000000000000000000000 000D515151F1F7F7F7FFF6F6F6FFF6F6F6FFF3F3F3FFF8F8F8FFF7F7F7FFF7F7 F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7 F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FF5151 51F2000000180000000700000000000000000000000000000000000000000000 00004F4F4FFFF8F8F8FFE6E6E6FFE8E8E8FFE4E4E4FFEEEEEEFFEBEBEBFFECEC ECFFEDEDEDFFEEEEEEFFEFEFEFFFF0F0F0FFF2F2F2FFF3F3F3FFF4F4F4FFF5F5 F5FFF5F5F5FFF6F6F6FFF6F6F6FFF6F6F6FFF5F5F5FFF4F4F4FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 0000535353FFF8F8F8FFE6E6E6FFE8E8E8FFE4E4E4FFEEEEEEFFEBEBEBFFECEC ECFFEDEDEDFFEEEEEEFFF0F0F0FFF1F1F1FFF2F2F2FFF3F3F3FFF4F4F4FFF5F5 F5FFF6F6F6FFF7F7F7FFF7F7F7FFF6F6F6FFF5F5F5FFF4F4F4FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 0000565656FFF8F8F8FFE7E7E7FFE8E8E8FFE4E4E4FFEEEEEEFFEBEBEBFFC3C3 C3FFC0C0C0FFC1C1C1FFC1C1C1FFC2C2C2FFC2C2C2FFC3C3C3FFC3C3C3FFC7C7 C7FFF7F7F7FFF8F8F8FFF8F8F8FFF7F7F7FFF6F6F6FFF5F5F5FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 0000595959FFF9F9F9FFE7E7E7FFE8E8E8FFE4E4E4FFEEEEEEFFEBEBEBFFECEC ECFFEDEDEDFFEFEFEFFFF0F0F0FFF1F1F1FFF2F2F2FFF3F3F3FFF4F4F4FFF5F5 F5FFF6F6F6FFF7F7F7FFF8F8F8FFF7F7F7FFF6F6F6FFF5F5F5FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 00005D5D5DFFF9F9F9FFE6E6E6FFE8E8E8FFE4E4E4FFEEEEEEFFEBEBEBFFC3C3 C3FFC0C0C0FFC0C0C0FFC1C1C1FFC2C2C2FFC2C2C2FFC3C3C3FFC3C3C3FFC3C3 C3FFC4C4C4FFC4C4C4FFC4C4C4FFC8C8C8FFF5F5F5FFF4F4F4FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 0000606060FFF9F9F9FFE6E6E6FFE7E7E7FFE4E4E4FFEEEEEEFFEBEBEBFFECEC ECFFEDEDEDFFEEEEEEFFEFEFEFFFF0F0F0FFF1F1F1FFF2F2F2FFF3F3F3FFF4F4 F4FFF5F5F5FFF6F6F6FFF6F6F6FFF5F5F5FFF5F5F5FFF4F4F4FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 0000636363FFFAFAFAFFE6E6E6FFEAEAEAFFE3E3E3FFEDEDEDFFEBEBEBFFC3C3 C3FFC0C0C0FFC0C0C0FFC1C1C1FFC1C1C1FFC2C2C2FFC2C2C2FFC3C3C3FFC3C3 C3FFC3C3C3FFC3C3C3FFC3C3C3FFC7C7C7FFF4F4F4FFF3F3F3FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 0000666666FFFAFAFAFFE6E6E6FFB1B1B1FFE5E5E5FFEDEDEDFFEAEAEAFFEBEB EBFFECECECFFEDEDEDFFEEEEEEFFEFEFEFFFF0F0F0FFF1F1F1FFF2F2F2FFF3F3 F3FFF3F3F3FFF4F4F4FFF4F4F4FFF3F3F3FFF3F3F3FFF2F2F2FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 00006A6A6AFFFAFAFAFFE6E6E6FFE7E7E7FFE3E3E3FFEDEDEDFFEAEAEAFFB7B7 B7FFB8B8B8FFB8B8B8FFB8B8B8FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFBABA BAFFBABABAFFBABABAFFBABABAFFBABABAFFF2F2F2FFF1F1F1FFF7F7F7FF4B4B 4BFF000000000000000000000000000000000000000000000000000000000000 00006D6D6DFFFBFBFBFFE5E5E5FFE6E6E6FFE2E2E2FFEDEDEDFFE9E9E9FFB7B6 B6FF9B8579FF9C867AFF9C867AFF9C867AFF9D877BFF9D877BFF9D877BFF9D87 7BFF9D877BFF998378FF958177FFB9B9B9FFF1F1F1FFF0F0F0FFF7F7F7FF4C4C 4CFF000000000000000000000000000000000000000000000000000000000000 0000707070FFFBFBFBFFE5E5E5FFE6E6E6FFE2E2E2FFEDEDEDFFE9E9E9FFB8B7 B6FFA99184FFAA9285FFAA9285FFAA9285FFAA9285FFAB9386FFAB9386FFA78F 83FF97847BFF9B877DFF98857BFFB9B9B9FFF0F0F0FFF0F0F0FFF7F7F7FF4E4E 4EFF000000000000000000000000000000000000000000000000000000000000 0000737373FFFBFBFBFFE4E4E4FFE5E5E5FFE1E1E1FFECECECFFE8E8E8FFB8B7 B6FFB99F94FFB99F94FFBAA095FFBAA095FFBAA095FFBAA095FFAA988FFF9F90 8AFF9D8F8AFF9F9189FFB9A195FFB9B9B9FFEFEFEFFFEFEFEFFFF8F8F8FF5050 50FF000000000000000000000000000000000000000000000000000000000000 0000777777FFFBFBFBFFE4E4E4FFE5E5E5FFE1E1E1FFECECECFFE8E8E8FFB9B8 B7FFDAC2AEFFDBC3AFFFDBC3AFFFDCC4B0FFDCC4B0FFDCC4B0FFCCB8A9FF8B8A 89FFAEA39AFF96928EFFDDC5B1FFB8B8B8FFEEEEEEFFEEEEEEFFF8F8F8FF5252 52FF000000000000000000000000000000000000000000000000000000000000 00007A7A7AFFFCFCFCFFE3E3E3FFE4E4E4FFE1E1E1FFEBEBEBFFE7E7E7FFB9B8 B7FFD8B89AFFD5BA9DFFD1BCA0FFD7B79AFFD9B99BFFD9B99BFFD9B99BFFA89A 8EFFAC9D8FFF858585FFD4B69AFFB8B8B8FFEDEDEDFFEDEDEDFFF8F8F8FF5454 54FF000000000000000000000000000000000000000000000000000000000000 00007D7D7DFFFCFCFCFFE3E3E3FFE4E4E4FFE1E1E1FFEAEAEAFFE6E6E6FFB9B8 B7FFD2BA9CFFC5E9DFFFD2F1ECFFC5C9B3FFD8B89AFFD8B89AFFD8B89AFFD4B6 9AFFA89B8EFFA0968CFFD9B99BFFB8B8B8FFECECECFFECECECFFF8F8F8FF5555 55FF000000000000000000000000000000000000000000000000000000000000 0000808080FFFCFCFCFFE2E2E2FFE6E6E6FFE0E0E0FFEAEAEAFFE6E6E6FFB8B7 B6FFCAC0A7FFE4F5F3FFF2F7F6FFBDDCCFFFD8B89AFFD8B89AFFD8B89AFFD8B8 9AFFC6AD95FFD4B699FFD8B89AFFB7B7B7FFEBEBEBFFEBEBEBFFF8F8F8FF5757 57FF000000000000000000000000000000000000000000000000000000000000 0000838383FFFDFDFDFFE1E1E1FFB0B0B0FFE1E1E1FFEAEAEAFFE5E5E5FFB8B7 B6FFD3B99CFFBEDFD4FFC8ECE5FFC7C4AAFFD8B89AFFD8B89AFFD8B89AFFD8B8 9AFFD8B89AFFD8B89AFFD8B89AFFB7B7B7FFEAEAEAFFEAEAEAFFF8F8F8FF5858 58FF000000000000000000000000000000000000000000000000000000000000 0000868686FFFDFDFDFFE1E1E1FFE2E2E2FFDEDEDEFFE9E9E9FFE4E4E4FFB5B5 B5FFB5B5B5FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB7B7 B7FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7B7FFE9E9E9FFE9E9E9FFF8F8F8FF5959 59FF000000000000000000000000000000000000000000000000000000000000 0000898989FFFDFDFDFFE0E0E0FFE1E1E1FFDEDEDEFFE8E8E8FFE3E3E3FFE4E4 E4FFE5E5E5FFE5E5E5FFE6E6E6FFE6E6E6FFE7E7E7FFE7E7E7FFE7E7E7FFE8E8 E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFF8F8F8FF5A5A 5AFF000000000000000000000000000000000000000000000000000000000000 00008B8B8BFFFDFDFDFFDFDFDFFFE0E0E0FFDDDDDDFFE8E8E8FFE2E2E2FFBEBE BEFFBCBCBCFFBCBCBCFFBCBCBCFFBCBCBCFFBDBDBDFFBDBDBDFFBDBDBDFFC0C0 C0FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE6E6E6FFF8F8F8FF5B5B 5BFF000000000000000000000000000000000000000000000000000000000000 00008E8E8EFFFDFDFDFFDFDFDFFFDFDFDFFFDCDCDCFFE7E7E7FFE2E2E2FFE2E2 E2FFE3E3E3FFE3E3E3FFE4E4E4FFE4E4E4FFE5E5E5FFE5E5E5FFE5E5E5FFE6E6 E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE5E5E5FFF8F8F8FF5C5C 5CFF000000000000000000000000000000000000000000000000000000000000 0000909090FFFEFEFEFFDEDEDEFFDFDFDFFFDBDBDBFFE6E6E6FFE1E1E1FFBDBD BDFFBBBBBBFFBBBBBBFFBBBBBBFFBBBBBBFFBCBCBCFFBCBCBCFFBCBCBCFFBCBC BCFFBCBCBCFFBCBCBCFFBCBCBCFFBFBFBFFFE5E5E5FFE4E4E4FFF8F8F8FF5C5C 5CFF000000000000000000000000000000000000000000000000000000000000 0000929292FFFEFEFEFFDDDDDDFFDEDEDEFFDADADAFFE6E6E6FFE0E0E0FFE0E0 E0FFE1E1E1FFE1E1E1FFE2E2E2FFE2E2E2FFE3E3E3FFE3E3E3FFE3E3E3FFE4E4 E4FFE4E4E4FFE4E4E4FFE4E4E4FFE4E4E4FFE4E4E4FFE3E3E3FFF8F8F8FF5D5D 5DFF000000000000000000000000000000000000000000000000000000000000 0000939393FFFDFDFDFFDCDCDCFFDDDDDDFFDADADAFFE5E5E5FFDFDFDFFFDFDF DFFFE0E0E0FFE1E1E1FFE1E1E1FFE1E1E1FFE2E2E2FFE2E2E2FFE2E2E2FFE2E2 E2FFE3E3E3FFE3E3E3FFE3E3E3FFE3E3E3FFE3E3E3FFE2E2E2FFF8F8F8FF5D5D 5DFF000000000000000000000000000000000000000000000000000000000000 0000969696EFFDFDFDFFFDFDFDFFFEFEFEFFFAFAFAFFFEFEFEFFFDFDFDFFFDFD FDFFFDFDFDFFFDFDFDFFFCFCFCFFFCFCFCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFB FBFFFAFAFAFFFAFAFAFFFAFAFAFFF9F9F9FFF9F9F9FFF9F9F9FFF8F8F8FF6363 63EF000000000000000000000000000000000000000000000000000000000000 000095959552999999F2999999FF9C9C9CFF9E9E9EFF9C9C9CFF999999FF9696 96FF939393FF8F8F8FFF8C8C8CFF888888FF848484FF818181FF7D7D7DFF7A7A 7AFF767676FF727272FF6F6F6FFF6B6B6BFF686868FF646464FF646464F26060 6052000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F0000007C0000003C0000001E000 0003F000000FF000000FF000000FF000000FF000000FF000000FF000000FF000 000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000 000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000 000FF000000FF000000FFFFFFFFFFFFFFFFF } KeyPreview = True OnClose = frmViewerClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnKeyPress = FormKeyPress OnResize = FormResize OnShow = FormShow SessionProperties = 'Height;Width;Left;Top;WindowState' ShowHint = True ShowInTaskBar = stAlways LCLVersion = '2.2.7.0' object pnlFolder: TPanel Left = 179 Height = 343 Top = 0 Width = 342 Align = alClient BevelOuter = bvNone ClientHeight = 343 ClientWidth = 342 ParentFont = False TabOrder = 0 Visible = False object memFolder: TMemo Left = 0 Height = 343 Top = 0 Width = 342 Align = alClient BorderStyle = bsNone ParentFont = False ReadOnly = True TabOrder = 0 end end object Status: TKASStatusBar Left = 0 Height = 23 Top = 343 Width = 521 Panels = < item Width = 50 end item Width = 50 end item Width = 100 end item Width = 100 end item Width = 200 end> ParentFont = False SimplePanel = False end object pnlText: TPanel Left = 179 Height = 343 Top = 0 Width = 342 Align = alClient BevelOuter = bvNone ClientHeight = 343 ClientWidth = 342 ParentFont = False TabOrder = 2 Visible = False OnMouseWheelUp = pnlTextMouseWheelUp object ViewerControl: TViewerControl Left = 0 Height = 343 Top = 0 Width = 342 Mode = vcmText OnPositionChanged = ViewerPositionChanged ShowCaret = False OnMouseUp = ViewerControlMouseUp OnMouseWheelUp = ViewerControlMouseWheelUp OnMouseWheelDown = ViewerControlMouseWheelDown Align = alClient Color = clWindow Font.Color = clWindowText end end object pnlCode: TPanel Left = 179 Height = 343 Top = 0 Width = 342 Align = alClient BevelOuter = bvNone ParentFont = False TabOrder = 4 Visible = False end object pnlImage: TPanel Left = 179 Height = 343 Top = 0 Width = 342 Align = alClient BevelOuter = bvNone ClientHeight = 343 ClientWidth = 342 ParentFont = False TabOrder = 3 Visible = False OnResize = pnlImageResize object sboxImage: TScrollBox Left = 0 Height = 307 Top = 36 Width = 342 HorzScrollBar.Page = 321 VertScrollBar.Page = 286 Align = alClient ClientHeight = 286 ClientWidth = 321 Color = clWindow ParentColor = False ParentFont = False TabOrder = 0 OnMouseEnter = sboxImageMouseEnter OnMouseLeave = sboxImageMouseLeave OnMouseMove = sboxImageMouseMove object Image: TImage Left = 56 Height = 288 Top = 96 Width = 376 AntialiasingMode = amOn Align = alCustom BorderSpacing.CellAlignHorizontal = ccaCenter BorderSpacing.CellAlignVertical = ccaCenter OnMouseDown = ImageMouseDown OnMouseEnter = ImageMouseEnter OnMouseLeave = ImageMouseLeave OnMouseMove = ImageMouseMove OnMouseUp = ImageMouseUp OnMouseWheelDown = ImageMouseWheelDown OnMouseWheelUp = ImageMouseWheelUp Proportional = True end object GifAnim: TGifAnim Left = 0 Height = 90 Top = 0 Width = 106 AutoSize = False OnMouseDown = GifAnimMouseDown OnMouseEnter = GifAnimMouseEnter end end object ToolBar1: TToolBar AnchorSideLeft.Control = pnlImage AnchorSideTop.Control = pnlImage AnchorSideRight.Control = pnlImage AnchorSideBottom.Control = sboxImage Left = 0 Height = 34 Top = 0 Width = 342 AutoSize = True ButtonHeight = 32 ButtonWidth = 32 Images = dmComData.ilViewerImages List = True ParentFont = False ShowCaptions = True TabOrder = 1 object btnReload: TToolButton Left = 1 Top = 2 Action = actReload ShowCaption = False end object btnPrev: TToolButton Left = 33 Top = 2 Action = actLoadPrevFile ShowCaption = False end object btnNext: TToolButton Left = 65 Top = 2 Action = actLoadNextFile ShowCaption = False end object btnCopyFile: TToolButton Left = 97 Top = 2 Action = actCopyFile ShowCaption = False end object btnMoveFile: TToolButton Left = 129 Top = 2 Action = actMoveFile ShowCaption = False end object btnDeleteFile: TToolButton Left = 161 Top = 2 Action = actDeleteFile ShowCaption = False end object btnZoomSeparator: TToolButton Left = 193 Height = 32 Top = 2 Style = tbsSeparator end object btnZoomIn: TToolButton Left = 199 Top = 2 Action = actZoomIn ShowCaption = False end object btnZoomOut: TToolButton Left = 231 Top = 2 Action = actZoomOut ShowCaption = False end object btn270: TToolButton Left = 263 Top = 2 Action = actRotate270 ShowCaption = False end object btn90: TToolButton Left = 295 Top = 2 Action = actRotate90 ShowCaption = False end object btnMirror: TToolButton Left = 1 Top = 34 Action = actMirrorHorz ShowCaption = False end object btnGifSeparator: TToolButton Left = 33 Height = 32 Top = 34 Style = tbsSeparator end object btnGifMove: TToolButton Left = 39 Top = 34 ImageIndex = 11 OnClick = btnGifMoveClick ShowCaption = False end object btnPrevGifFrame: TToolButton Left = 71 Hint = 'Previous Frame' Top = 34 ImageIndex = 13 OnClick = btnPrevGifFrameClick ShowCaption = False end object btnNextGifFrame: TToolButton Left = 103 Hint = 'Next Frame' Top = 34 ImageIndex = 14 OnClick = btnNextGifFrameClick ShowCaption = False end object btnGifToBmp: TToolButton Left = 135 Hint = 'Export Frame' Top = 34 ImageIndex = 26 OnClick = btnGifToBmpClick ShowCaption = False end object btnHightlightSeparator: TToolButton Left = 167 Height = 32 Top = 34 Style = tbsSeparator end object btnHightlight: TToolButton Left = 173 Hint = 'Highlight' Top = 34 AllowAllUp = True Grouped = True ImageIndex = 23 OnClick = btnPaintHightlight ShowCaption = False Style = tbsCheck end object btnCutTuImage: TToolButton Left = 205 Hint = 'Crop' Top = 34 Enabled = False ImageIndex = 15 OnClick = btnCutTuImageClick ShowCaption = False end object btnRedEye: TToolButton Left = 237 Hint = 'Red Eyes' Top = 34 Enabled = False ImageIndex = 16 OnClick = btnRedEyeClick ShowCaption = False end object btnPaintSeparator: TToolButton Left = 269 Height = 32 Top = 34 Style = tbsSeparator end object btnPaint: TToolButton Left = 275 Hint = 'Paint' Top = 34 AllowAllUp = True Grouped = True ImageIndex = 21 OnClick = btnPaintHightlight ShowCaption = False Style = tbsCheck end object btnUndo: TToolButton Left = 307 Top = 34 Action = actUndo ShowCaption = False end object btnPenMode: TToolButton Left = 1 Top = 66 AllowAllUp = True DropdownMenu = pmPenTools Enabled = False Grouped = True ImageIndex = 17 OnClick = btnPenModeClick ShowCaption = False Style = tbsDropDown end object btnPenWidth: TToolButton Left = 45 Top = 66 Caption = '1' DropdownMenu = pmPenWidth Enabled = False Style = tbsButtonDrop end object btnPenColor: TColorButton Left = 87 Height = 32 Top = 66 Width = 75 BorderWidth = 2 ButtonColorSize = 16 ButtonColor = clRed Enabled = False ParentFont = False end object btnSeparator: TToolButton Left = 162 Height = 32 Top = 66 Style = tbsSeparator end object btnResize: TToolButton Left = 168 Hint = 'Resize' Top = 66 ImageIndex = 24 OnClick = btnResizeClick ShowCaption = False end object btnFullScreen: TToolButton Left = 200 Hint = 'Full Screen' Top = 66 Action = actFullscreen ShowCaption = False end object btnSlideShow: TToolButton Tag = 1 Left = 232 Top = 66 Caption = 'Slide Show' DropdownMenu = pmTimeShow OnClick = btnSlideShowClick Style = tbsDropDown Visible = False end end end object Splitter: TSplitter Left = 170 Height = 343 Top = 0 Width = 9 AutoSnap = False MinSize = 160 OnChangeBounds = SplitterChangeBounds Visible = False end object pnlPreview: TPanel Left = 0 Height = 343 Top = 0 Width = 170 Align = alLeft BevelOuter = bvNone ClientHeight = 343 ClientWidth = 170 ParentFont = False TabOrder = 5 Visible = False object pnlEditFile: TPanel Left = 0 Height = 30 Top = 0 Width = 170 Align = alTop Alignment = taLeftJustify ClientHeight = 30 ClientWidth = 170 ParentFont = False TabOrder = 0 object btnReload1: TSpeedButton AnchorSideBottom.Control = btnPrev1 Left = 1 Height = 28 Top = 1 Width = 32 Action = actReload Align = alLeft Glyph.Data = { 36090000424D3609000000000000360000002800000018000000180000000100 2000000000000009000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000005B0007004E006C0050 01AB095E12DB015B01F5005D00F7095F11E2015102BA004F007F004A00110000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000050004C075D0DEB076B0DFF0A92 30FF15B125FF0AD113FF06E60BFF0DD317FF17B12CFF06790BFF05580AEE004E 006D004E00090000000000000000000000000000000000000000000000000000 00000000000000000000004E0009015002BB0B6515FD159227FF18A72DFF1AB1 31FF14C226FF0FD11DFF0CDA17FF0CDA17FF0FD11DFF14C226FF21AD3EFF1274 22F2005001C2004A001B00000000000000000000000000000000000000000000 00000000000000000000025003B80F721DFF0A9513FF0F9D1DFF15A427FF1AAA 31FF18B52FFF15C027FF12C723FF12C723FF14C027FF18B52EFF1AAA32F016A5 2ACD137923C0004F00A700550008000000000000000000000000000000000000 0000000000000051005C085B0FFE028D05FF07940DFF0C9A17FF119F20FF16A5 29FF19A931FF1BAE33FF19B330FF19B330FF1AAE33FF1AA931EF16A529D1119F 21AD0F9C1C8D0B68139B00540030000000000000000000000000000000000000 0000004D000F045108F505750AFF008C01FF049108FF08950FFF0D9A18FF17A2 2AFF0D7B19FF0B6A14FD0A6413FD0D7019FF189F2EEB14A326D3119F20B10D9A 1890089510730B95155809651137000000000000000000000000000000000000 00000255057B06530CFF007000FF008100FF018D02FF049109FF0F8E1CFF075F 0EF00253048F004C0041004E003B02500474045208D70D8019B00B99167E0895 0F6305910949018D02350D731824046A07020000000000000000000000000000 0000035306C1045109FF006300FF007300FF008300FF068E0AFF05590AF5004D 014F00000000000000000000000000000000004C0026025004B106880B490490 0730018D02230083001709770F0D05620B020000000000000000000000000000 0000045108E8014D01FF005500FF006400FF007300FF06660CFF015103AB0000 00000000000000000000000000000000000000000000004E01290A6211160263 040F02540609044F07050A5B140100000000000000000000000000000000004D 0001054D07F9085508FF0B570BFF0A5D0AFF006200FF055207FE014F015A0000 0000000000000000000000000000000000000000000000000000065210050957 1303000000000000000000000000000000000000000000000000000000000000 0000065108FB267026FF287228FF277127FF005000FF034B06FE014D015A0000 00000000000000000000004D0004125E1BEC025C03FF045C04FF045B05FF0459 06FF015503FF025304FF025405FF07600DA90000000000000000000000000000 000008550CE62B752BFF357E35FF357E35FF085408FF034B06FF035306870000 00000000000000000000004D0008024E04D1028004FF13C813FF2DC72DFF35BD 35FF34AF34FF249824FF127B12FF055A08FF0000000000000000000000000000 0000095B10BE266E27FF418A41FF418A41FF266F26FF014C01FF045107F30351 0311000000000000000000000000004D0033034F07E2027704FF019601FF20A1 20FF41AD41FF41A641FF419D41FF0B5F0EFF0000000000000000000000000000 000007610F7D1C641DFF4F964FFF4F964FFF4F964FFF166016FF014E03FF044F 08F30758105900802B030064140605540A6B034D05F7016A02FF017A01FF3CA2 3CFF4FAB4FFF4FA64FFF4FA24FFF0C610FFF0000000000000000000000000000 00000057000A09560BF4498F49FF5BA15BFF5BA15BFF549A54FF1B641BFF014D 01FF024C03FF024B04FE044C06FE024C03FF015401FF086508FF3F963FFF5BAC 5BFF5BAB5BFF5BA95BFF5BA75BFF0D610FFF0000000000000000000000000000 000000000000045C0852155F17FE66AA66FF68AD68FF68AD68FF69AE69FF468B 46FF226A22FF085408FF045004FF176017FF307930FF5FA75FFF68B068FF68B0 68FF68B068FF68AF68FF68AF68FF0E6210FF0000000000000000000000000000 00000000000000000000035A06BB337933FF70B570FF74B974FF74B974FF74B9 74FF74B974FF77BA77FF75B875FF74B974FF74B974FF74B974FF74B974FF76BA 76FF61A361FF539A55FF75B975FF0F6311FF0000000000000000000000000000 0000000000000000000000540007035D05B71C691DFE65A865FF81C581FF81C5 81FF81C581FF81C581FF81C581FF81C581FF81C581FF81C581FF80BF80FF367E 38FE025703D5015903D7479147FF116612FF0000000000000000000000000000 0000000000000000000000000000000000000060024D0E620EF1347C34FF5799 57FF74B474FF7FC47FFF84C984FF80BF80FF6EAA6EFF4A8E4AFF0D5E0DF40056 018C004D0010004D001F005C01B8458E45E60000000000000000000000000000 00000000000000000000000000000000000000000000006000080063007A0160 01B5216F21E6337633FD347634FE2D732DEF166816CA015C0194005000290000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ShowCaption = False ParentFont = False end object btnPrev1: TSpeedButton Left = 33 Height = 28 Top = 1 Width = 24 Action = actLoadPrevFile Align = alLeft Glyph.Data = { 36090000424D3609000000000000360000002800000018000000180000000100 2000000000000009000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000383004F189514EB048A 008D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000048200841D9819FB2CA92AFF048B 00BC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000520005058501B5219E1EFE07A707FE18AF17FE048A 00BB000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000072001E0C8708DB1D9E1BFF01A701FF00B500FF16BE15FD0388 00B9000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000372004A10870DF1149413FE009E00FF00AF00FF00BF00FF13C712FD0384 00B7000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000026F 007D128310FA0B850BFE008F00FF009F00FF00B000FF00C000FF11C610FF0381 00B5000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000660004037100AE026C 00FE057005FE007D00FF008D00FF009C00FF00AB00FF00B800FF0EBB0DFF037D 00B3000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000006A001C076C05D510650FFF005A 00FF006900FF007900FF008700FF009500FF00A200FF00AC00FF0CAD0BFF017A 00B1000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000590018086406EE094B09FE004700FF0357 03FF076807FF057505FF018001FF008C00FF009600FF009E00FF08A008FF0176 00AF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000005D00170B610AED316F31FE347434FF327E 32FF2E842EFF2D8C2DFF2B942BFF2A9A2AFF28A128FF26A426FF2CA62CFF0171 00AE000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000052001B045E03D02D722DFF4388 43FF408E40FF3D933DFF399739FF369B36FF329E32FF2FA12FFF319F31FF016D 00AC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000260004005600A52671 25FE519651FE4F9B4FFF4B9E4BFF48A048FF44A244FF41A341FF3D9F3DFF0069 00AA000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000051 00711C671CFA5A9F5AFE5EA75EFF5AA85AFF57A857FF53A753FF499F49FF0061 00A9000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000004B0041105910EB5DA05DFE6CB16CFF69B169FF65AF65FF56A256FE005A 00A9000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000055001A085208D0579657FF7CBC7CFF78BA78FF65A765FD0052 00A9000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000260004004D00A4478447FE8AC78AFF71AE71FE004E 00A9000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000004C0070347234FA7AAF7AFF0451 04AA000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000004C0040115811E3447D 4493000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ShowCaption = False ParentFont = False end object btnNext1: TSpeedButton Left = 57 Height = 28 Top = 1 Width = 24 Action = actLoadNextFile Align = alLeft Glyph.Data = { 36090000424D3609000000000000360000002800000018000000180000000100 2000000000000009000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000012950ED0169618D60078 0018000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000001F9C1BF31EA41DFF1492 0FEF047B00400000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000001B9C18F200AE00FF11AE 11FE199715FA027E007400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000199C16F100C200FF00BD 00FF08B308FE1D9C1AFE037D00A8008000010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000169B13EF00D600FF00CA 00FF00BA00FF01A901FF028E00FF0A8006D2006B001600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000149911EF00D200FF00CA 00FF00BB00FF00AB00FF009A00FF129111FE0D7F0AEC046A003C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000011930EEF00C300FF00BF 00FF00B400FF00A600FF009700FF008800FF0A7F0AFD0F7C0DF8026B006D0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000E8D0CEE00B300FF00B1 00FF00A900FF009E00FF009100FF008300FF007400FF056905FE10720EFE0266 00A0008000010000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000B8709ED00A400FF00A2 00FF009C00FF009300FF028902FF067F06FF057105FF026102FF015101FF0D5E 0CFF046303BC0000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000188917ED23A723FF26A7 26FF28A428FF2BA12BFF2B9B2BFF2C922CFF2F8C2FFF338433FF377E37FF2770 27FF046003BA0000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000188418EC2DA22DFF30A3 30FF34A234FF37A037FF3A9C3AFF3D983DFF419441FF448D44FE217120FE0258 009B008000010000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000177C17EB3FA33FFF42A5 42FF46A546FF49A449FF4CA34CFF4FA04FFF4A964AFE166615F7005200650000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000177417EB51A751FF54A9 54FF58AB58FF5BAB5BFF5EAB5EFF4D964DFE0C5B0CE600500035000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000176C17EA63AE63FF67B1 67FF6AB36AFF6EB46EFF468B46FF025102C50045001300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000186518EB75B875FF79BC 79FF7BBB7BFF387B38FE004D0098008000010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000001A601AEB87C587FF80BC 80FE286B28F7004D006300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000001C601CEC86B986FF165E 16E8004E00350000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000B550BC61E611EC80045 0013000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000001000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ShowCaption = False ParentFont = False end object btnCopyFile1: TSpeedButton Left = 81 Height = 28 Top = 1 Width = 32 Action = actCopyFile Align = alLeft Glyph.Data = { 36090000424D3609000000000000360000002800000018000000180000000100 2000000000000009000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008A8F8DAE868B 89FF868B89FF858A88FF858A88FF858A88FF858A88FF858A88FF848A87FF848A 86FD858A88C3848A860A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000868B89FCF2F2 F2FFF2F2F2FFF1F1F1FFF0F0F0FFF1F1F1FFF4F4F4FFF7F7F7FFF6F6F6FF858A 86FFB9BBBAFF858A88FF868C8861000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000868B89FCF7F7 F7FFEAEAEAFFE9E9E9FFEDEEEEFFF1F1F1FFF1F1F1FFF3F3F3FFF4F4F4FF878D 89FFCFCFCFFFB4B5B4FF858A88FF8F9490920000000000000000000000000000 0000000000000000000000000000000000000000000000000000868B89FCFAFA FAFFEAEBEBFFEAEAEAFFE9EAEAFFECECECFFEFEFEFFFEFEFEFFFF1F1F1FF848A 86FFCFCFCFFFCFCFCFFFB9BBBAFF858A88FF858B876400000000000000008B90 8D57858A887F858A887F858A887F858A887F858A887F858A8883868B89FDFDFD FDFFEBECECFFEBEBEBFFEAEBEBFFEAEAEAFFECECECFFF0F0F0FFEEEEEEFF858A 88FF858A88FF858A88FF858A88FF858A88FF858A88CC0000000000000000858A 887EF2F2F27FF3F3F37FF1F1F17FF0F0F07FF1F1F17FEDEDED83878C8AFDFFFF FFFFECEDEDFFECECECFFEBECECFFEAEBEBFFEAEAEAFFEEEFEFFFF0F0F0FFEFEF EFFFF1F1F1FFF2F2F2FFF1F1F1FFBBBEBDFF868B89FC0000000000000000868B 897EF7F7F77FEAEAEA7FE9E9E97FE8E9E97FE8E8E87FE2E3E383878C8AFDFFFF FFFFEDEEEEFFEBECECFFEBEBEBFFEAEBEBFFEAEAEAFFE9EAEAFFECECECFFEFEF EFFFEDEDEDFFEFEFEFFFF2F2F2FFF7F7F7FF888D8BFC0000000000000000868B 897EFAFAFA7FEAEBEB7FEAEAEA7FE9EAEA7FE9E9E97FE1E2E283878C8AFDFFFF FFFFEEEFEFFFC5C5C5FFC5C5C5FFC4C5C5FFC4C4C4FFC3C4C4FFC3C3C3FFCDCD CDFFDCDCDCFFDCDCDCFFF2F2F2FFF9F9F9FF888D8BFC0000000000000000868B 897EFDFDFD7FEBECEC7FEBEBEB7FEAEBEB7FEAEAEA7FE2E3E383878C8AFDFFFF FFFFEFF0F0FFEEEFEFFFEEEEEEFFEDEEEEFFECEDEDFFECEDEDFFEBECECFFEBEB EBFFEFEFEFFFF2F2F2FFEFEFEFFFFCFCFCFF898E8CFC0000000000000000868B 897EFFFFFF7FECEDED7FC7C7C77FC6C7C77FC5C6C67FC1C1C183868B89FDFFFF FFFFEFF0F0FFC7C8C8FFC6C7C7FFC6C7C7FFC5C6C6FFC5C6C6FFC5C5C5FFC5C5 C5FFEDEEEEFFEDEDEDFFF4F4F4FFFEFEFEFF898E8CFC0000000000000000868B 897EFFFFFF7FEDEEEE7FECEDED7FECECEC7FEBECEC7FE4E5E483878C8AFDFFFF FFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEEEFEFFFEEEFEFFFEDEEEEFFEDED EDFFECEDEDFFEDEEEEFFEDEDEDFFFEFEFEFF898E8CFC0000000000000000868C 8A7EFFFFFF7FEEEFEF7FC8C9C97FC8C8C87FC7C8C87FC2C3C383868B89FDFFFF FFFFEFF0F0FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC5C6C6FFC5C5 C5FFC5C5C5FFC4C5C5FFEEEEEEFFFEFEFEFF898E8CFC0000000000000000868C 8A7EFFFFFF7FEFF0F07FEEEFEF7FEEEEEE7FEDEEEE7FE5E6E683878C8AFDFFFF FFFFEFF0F0FFEEEFEFFFEEEFEFFFEEEFEFFFEEEFEFFFEEEFEFFFEEEFEFFFEDEE EEFFEDEEEEFFECEDEDFFEDEDEDFFFEFEFEFF898E8CFC0000000000000000868C 8A7EFFFFFF7FEFF0F07FCACACA7FC9CACA7FC9CACA7FC3C5C583868B89FDFFFF FFFFEFF0F0FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7C7FFC6C7 C7FFC6C7C7FFC5C6C6FFEEEEEEFFFEFEFEFF898E8CFC0000000000000000868C 8A7EFFFFFF7FEFF0F07FEFF0F07FEFF0F07FEFF0F07FE7E8E883878C8AFDFFFF FFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFEFF0F0FFEEEFEFFFFEFEFEFF898E8CFC0000000000000000868C 8A7EFFFFFF7FEFF0F07FCACACA7FCACACA7FCACACA7FC5C6C583868B89FDFFFF FFFFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0F0FFEFF0 F0FFEFF0F0FFEFF0F0FFEFF0F0FFFEFEFEFF898E8CFC0000000000000000868C 8A7EFFFFFF7FEFF0F07FEFF0F07FEFF0F07FEFF0F07FE8E9E983868B89FEFFFF FFFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFE FEFFFEFEFEFFFEFEFEFFFEFEFEFFFFFFFFFF898E8CFD0000000000000000868C 8A7EFFFFFF7FEFF0F07FCACACA7FCACACA7FCACACA7FC9C9C980959997DA898E 8CFE898E8CFD898E8CFD898E8CFD8A8E8CFD8A8F8DFD898E8CFD898E8CFC898E 8CFC898E8CFC898E8CFC898E8CFC898E8CFD8A8F8DB40000000000000000868C 8A7EFFFFFF7FEFF0F07FEFF0F07FEFF0F07FEFF0F07FEFF0F07FEEEFEF80E8E9 E983E8E9E983E8E9E983E8E9E983E7E8E883F6F6F6838D919082000000000000 000000000000000000000000000000000000000000000000000000000000868C 8A7EFFFFFF7FEFF0F07FEFF0F07FEFF0F07FEFF0F07FEFF0F07FEFF0F07FEFF0 F07FEFF0F07FEFF0F07FEFF0F07FEFF0F07FFEFEFE7F8E92917E000000000000 000000000000000000000000000000000000000000000000000000000000858A 887EFFFFFF7FFFFFFF7FFFFFFF7FFFFFFF7FFFFFFF7FFFFFFF7FFFFFFF7FFFFF FF7FFFFFFF7FFFFFFF7FFFFFFF7FFFFFFF7FFFFFFF7F8D91907E000000000000 0000000000000000000000000000000000000000000000000000000000008B90 8D57898E8C7F898E8C7F898E8C7F898E8C7F898E8C7F898E8C7F898E8C7F898E 8C7F898E8C7F898E8C7F898E8C7F898E8C7F898E8C7F8B908D57000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ShowCaption = False ParentFont = False end object btnMoveFile1: TSpeedButton Left = 145 Height = 28 Top = 1 Width = 31 Action = actMoveFile Align = alLeft Glyph.Data = { 36090000424D3609000000000000360000002800000018000000180000000100 2000000000000009000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000010000000200000004000000060000000A0000000F0000 001000000010000000100000001200000013000000110000000D0000000A0000 0006000000030000000300000002000000000000000000000000000000000000 000000000003000000070808AC7D0707AEC00606ACC10505937D0000002B0000 002E0000002C0000002C00000030000000300000002C04048F810606A9C40707 ADC10808A6810000000D00000009000000040000000100000000000000000000 0001000000040C0CB58A1212C5FF1A1AD8FF1818D0FF0A0AB6FF0808A0AF0000 00390000003700000036000000390000003908089FB00A0AB6FF1818D0FF1A1A D8FF1212C5FF0C0CAD9000000010000000070000000200000000000000000000 0000000000020808AFE82121E1FF1515CCFB1111C7FF2323E3FF0909B2EA0404 948E0000002500000024000000240404958D0909B3E92323E3FF1111C7FF1515 CCFB2121E1FF0808AFE800000009000000040000000100000000000000000000 0000000000000C0DAECC2929EFFF0D0DBEFB020299480707B1EA2222E2FF0808 B3E40000000A00000008000000070808B3E42222E2FF0707B1EA020299480D0D BEFB2929EFFF0B0CADCD00000001000000000000000000000000000000000000 0000000000001112AEA82525E7FF1313C9FF0505AE960303AA831C1CD7FF0707 B1FF0000A257000000000000A4560707B1FF1C1CD7FF0303AA830505AE961313 C9FF2525E7FF1112AEA800000000000000000000000000000000000000000000 0000000000001B1CAE440505ADDF1E1EDCFF1111C4EC0606B0EE1717CEFF1515 CBFF0000A4875558AE990000A4871515CBFF1717CEFF0606B0EE1111C4EC1E1E DCFF0505ADDF1B1CAE4400000000000000000000000000000000000000000000 000000000000000000000606B0680909B5E61A1AD4FF1F1FDCFF2121E1FF2121 E1FF0303AAFE0303AAFF0303AAFE2121E1FF2121E1FF1F1FDCFF1A1AD4FF0909 B5E60606B0680000000000000000000000000000000000000000000000000000 00000000000000000000000000000000A4200808B3A10909B5F60505AEFE3031 DAFF393AC7FF0303AAFF393AC7FF3031DAFF0505AEFE0909B5F60808B3A10000 A420000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000606B0816B6F 94FFB1B3B6FF00000000B1B3B6FF6B6F94FF0606B08100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000858A88878B8F 9BFFE2E2E2FFD8D8D8FFBEC0BFFF9295A9FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000858A881F878C8AFCDEE0 DFFFDADADAFFD8D8D8FFB1B4B3FFBABCBAFF989C9BD500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000858A88C0ABAEADFDDFDF DFFFDBDBDBFFAFB2B0FFBDBFBEFFDCDCDCFF959997FF858A883C000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000858A8857878C8AFFE9EAEAFFDCDC DCFFD6D6D6FFA7ABA9FFC1C3C1FFDBDBDBFFDDDEDEFF929795F9000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000858A88EFC0C3C2FEE0E0E0FFDDDD DDFF9A9E9DFF9A9E9C90A2A5A4FFDCDCDCFFDCDCDCFFB0B2B1FF909593A80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000858A889C8D9290FEEBEBEBFFDFDFDFFFC8C9 C9FFA8ABAAD900000000919694F1D3D5D4FFDDDDDDFFE2E2E2FF898E8CFF858A 881F000000000000000000000000000000000000000000000000000000000000 00000000000000000000858A881F858A88FEDFE0E0FFE0E0E0FFE0E0E0FF959A 98FF0000000000000000858A883C8F9492FFE1E1E1FFDEDEDEFFCBCCCBFF8F93 91EF000000000000000000000000000000000000000000000000000000000000 00000000000000000000858A88CF9A9E9DFDE8E8E8FFE1E1E1FFB1B3B2FFA2A6 A4BE000000000000000000000000929795CFC3C6C5FFDFDFDFFFE2E2E2FF959A 98FF858A88700000000000000000000000000000000000000000000000000000 000000000000000000008C918FF5EBEBEBFFE2E2E2FFDCDDDCFF989C9BFC0000 0000000000000000000000000000858A881F898E8CFFE2E3E3FFE0E0E0FFD8D9 D8FF929795F90000000000000000000000000000000000000000000000000000 00000000000000000000909593DAD6D8D7FFE2E2E2FF9C9F9FFF989C9B810000 000000000000000000000000000000000000909593A8A8ACABFFE3E3E3FFD0D1 D0FF9DA1A0DC0000000000000000000000000000000000000000000000000000 00000000000000000000858A88708E9391FEC1C4C2FF999D9CF7000000000000 000000000000000000000000000000000000000000008D9290FBD1D3D2FF9094 92FF858A88AF0000000000000000000000000000000000000000000000000000 00000000000000000000000000008C918FC78A8F8DFF858A883C000000000000 00000000000000000000000000000000000000000000858A8870858A88FF8E92 90E4000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ShowCaption = False ParentFont = False end object btnDeleteFile1: TSpeedButton Left = 113 Height = 28 Top = 1 Width = 32 Action = actDeleteFile Align = alLeft Glyph.Data = { 36090000424D3609000000000000360000002800000018000000180000000100 2000000000000009000064000000640000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000972000009BC000009720000000000000 0000000000000000000000000000000000000000000000000000000097200000 9BC0000097200000000000000000000000000000000000000000000000000000 0000000000000000000000009F2001019DE02E2EB4FF05059FE000009F200000 0000000000000000000000000000000000000000000000009F2000009DE02525 B3FF01019EE100009F2000000000000000000000000000000000000000000000 00000000000000009F200101A1E03E3EBFFF2424C1FF4242C5FF0303A2E00000 9F200000000000000000000000000000000000009F200000A1E03838C4FF2C2C C9FF4242C4FF0101A2E100009F20000000000000000000000000000000000000 000000009F200101A3E04242C0FF1A1ABEFF0808C0FF1313C9FF4343CCFF0303 A4E000009F20000000000000000000009F200000A3E03A3ACBFF1C1CD1FF0707 C6FF1717C4FF4444C5FF0101A4E000009F200000000000000000000000000000 00000000A6C02525B5FF3232C3FF0808BEFF0707C4FF0606CCFF1313D4FF4444 D3FF0202A7E00000A7200000A7200101A6E03F3FD2FF1C1CDCFF0606D2FF0606 CCFF0707C4FF2424C5FF3636BDFF0000A6C00000000000000000000000000000 00000000A7200000A8E03D3DC4FF1F1FC7FF0606C8FF0606CFFF0505D7FF1414 E0FF4444D9FF0202A9E00101A8E04242D9FF1A1AE7FF0404DEFF0505D7FF0606 CFFF1313CBFF4848CBFF0505AAE00000A7200000000000000000000000000000 0000000000000000A7200000ABE03F3FCCFF1D1DD0FF0606D2FF0404DAFF0303 E1FF1414EAFF4545DFFF4444DFFF1818F1FF0202E8FF0303E1FF0404DAFF1515 D5FF4B4BD3FF0303ADE10000A720000000000000000000000000000000000000 000000000000000000000000AF200000AFE14343D2FF1C1CD8FF0404DCFF0303 E3FF0202E9FF1313F1FF1414F4FF0101F0FF0202E9FF0303E3FF1414DEFF4C4C DAFF0303B1E10000AF2000000000000000000000000000000000000000000000 00000000000000000000000000000000AF200000B1E14545D8FF1818DEFF0303 E1FF0202E7FF0202EBFF0101EDFF0202EBFF0202E7FF1515E3FF4D4DDFFF0303 B2E10000AF200000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000AF200101B4E14B4BDEFF4646 E6FF5858EDFF6162F0FF6465F1FF6666EFFF6C6CEEFF8080EAFF0303B6E20000 AF20000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000B7200606B9E19899EBFF7D7E EDFF5D5EE9FF5555EAFF4E4EEAFF4748E9FF5151E8FF9191ECFF0707B9E20000 B720000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000B7200202BAE09495E9FF8082E9FF696B E8FF6465E8FF5B5CEAFF5555E7FF4F4FE7FF4748E4FF5555E4FF8B8BE7FF0404 BCE10000B7200000000000000000000000000000000000000000000000000000 000000000000000000000000BF200101BBE08F8FE4FF8C8EEAFF797AE7FF7273 E6FF6A6CE7FF7374E9FF6E6EE8FF5656E3FF5050E1FF4849DFFF5556DFFF8484 E2FF0202BCE10000BF2000000000000000000000000000000000000000000000 0000000000000000BF200000BFE08989E0FF989AE9FF8687E7FF7F81E6FF797A E7FF7F81E7FF8B8BE7FF8585E5FF6F6FE5FF5757DFFF5050DDFF4949D9FF5758 D9FF7C7CDDFF0101BFE10000BF20000000000000000000000000000000000000 00000000BF200000C2E08182DEFFA3A4EBFF9596E8FF8E8FE7FF8687E6FF898B E8FF8B8BE5FF0303C4E00202C3E08282E4FF6F6FE1FF5757DAFF5050D8FF4949 D3FF595AD4FF7676D9FF0202C0E10000BF200000000000000000000000000000 00000000C5C0B6B6EDFFB3B5EEFFA1A3EAFF9B9CE8FF9596E8FF9596E8FF8B8C E5FF0404C6E00000C7200000C7200303C5E08182E1FF6D6DDDFF5858D6FF5252 D2FF4A4ACDFF6D6ED4FF5353D2FF0000C5C00000000000000000000000000000 00000000C7202A2ACDE4ABACEFFFAEB0EEFFA1A3EAFFA1A3E9FF8C8CE2FF0606 C4E00000C72000000000000000000000C7200303C5E07F7FDFFF6B6CDAFF5959 D1FF6666D3FF7D7EDEFF0808C6E10000C7200000000000000000000000000000 0000000000000000C7201212C8E2A9ABEDFFB3B4EFFF8C8CE1FF0505C4E00000 C720000000000000000000000000000000000000C7200505C5E07D7EDEFF7E7F DBFF8081DDFF0606C6E10000C720000000000000000000000000000000000000 000000000000000000000000C7201D1DCAE3C3C3F1FF0606C4E10000C7200000 000000000000000000000000000000000000000000000000C7200505C5E0AAAB EAFF2525CCE30000C72000000000000000000000000000000000000000000000 00000000000000000000000000000000C7200000C5C00000C720000000000000 00000000000000000000000000000000000000000000000000000000C7200000 C5C00000C7200000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000 } ShowCaption = False ParentFont = False end end object DrawPreview: TDrawGrid Left = 0 Height = 313 Top = 30 Width = 170 Align = alClient AutoAdvance = aaNone AutoFillColumns = True BorderSpacing.CellAlignHorizontal = ccaCenter BorderSpacing.CellAlignVertical = ccaCenter BorderStyle = bsNone ColCount = 1 DefaultColWidth = 150 DefaultRowHeight = 140 ExtendedSelect = False FixedColor = clAppWorkspace FixedCols = 0 FixedRows = 0 Font.Style = [fsItalic] MouseWheelOption = mwGrid Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goSmoothScroll] ParentFont = False RowCount = 1 ScrollBars = ssAutoVertical TabOrder = 1 TitleStyle = tsNative OnDrawCell = DrawPreviewDrawCell OnSelection = DrawPreviewSelection OnTopleftChanged = DrawPreviewTopleftChanged ColWidths = ( 170 ) end end object MainMenu: TMainMenu ParentBidiMode = False Left = 80 Top = 64 object miFile: TMenuItem Caption = '&File' object miPrev: TMenuItem Action = actLoadPrevFile end object miNext: TMenuItem Action = actLoadNextFile end object miSave: TMenuItem Action = actSave end object miSaveAs: TMenuItem Action = actSaveAs end object miPrint: TMenuItem Action = actPrint end object miPrintSetup: TMenuItem Action = actPrintSetup end object miReload: TMenuItem Action = actReload end object miAutoReload: TMenuItem Action = actAutoReload end object miSeparator: TMenuItem Caption = '-' end object miExit: TMenuItem Action = actExitViewer end end object miEdit: TMenuItem Caption = '&Edit' object miCopyToClipboard: TMenuItem Action = actCopyToClipboard end object miSelectAll: TMenuItem Action = actSelectAll end object miDiv3: TMenuItem Caption = '-' end object miSearch: TMenuItem Action = actFind end object miSearchNext: TMenuItem Action = actFindNext end object miSearchPrev: TMenuItem Action = actFindPrev end object miGotoLine: TMenuItem Action = actGotoLine end end object miView: TMenuItem Caption = '&View' object miPreview: TMenuItem Action = actPreview end object miDiv4: TMenuItem Caption = '-' end object miText: TMenuItem Action = actShowAsText GroupIndex = 1 RadioItem = True end object miBin: TMenuItem Action = actShowAsBin GroupIndex = 1 RadioItem = True end object miHex: TMenuItem Action = actShowAsHex GroupIndex = 1 RadioItem = True end object miDec: TMenuItem Action = actShowAsDec GroupIndex = 1 RadioItem = True end object miLookBook: TMenuItem Action = actShowAsBook GroupIndex = 1 RadioItem = True end object miDiv2: TMenuItem Caption = '-' end object miGraphics: TMenuItem Action = actShowGraphics GroupIndex = 1 RadioItem = True end object miPlugins: TMenuItem Action = actShowPlugins GroupIndex = 1 RadioItem = True end object miOffice: TMenuItem Action = actShowOffice GroupIndex = 1 RadioItem = True end object miCode: TMenuItem Action = actShowCode GroupIndex = 1 RadioItem = True end object miDiv1: TMenuItem Caption = '-' end object miWrapText: TMenuItem Action = actWrapText end object miShowCaret: TMenuItem Action = actShowCaret end end object mnuPlugins: TMenuItem Caption = 'Plugins' end object miEncoding: TMenuItem Caption = 'En&coding' end object miImage: TMenuItem Caption = '&Image' object miStretch: TMenuItem Action = actStretchImage end object miStretchOnlyLarge: TMenuItem Action = actStretchOnlyLarge end object miCenter: TMenuItem Action = actImageCenter end object miShowTransparency: TMenuItem Action = actShowTransparency end object miRotate: TMenuItem Caption = 'Rotate' object mi90: TMenuItem Action = actRotate90 end object mi180: TMenuItem Action = actRotate180 end object mi270: TMenuItem Action = actRotate270 end object miMirror: TMenuItem Action = actMirrorHorz end object MenuItem2: TMenuItem Action = actMirrorVert end end object miZoomIn: TMenuItem Action = actZoomIn end object miZoomOut: TMenuItem Action = actZoomOut end object miFullScreen: TMenuItem Action = actFullscreen end object miScreenshot: TMenuItem Caption = 'Screenshot' object miScreenshotImmediately: TMenuItem Action = actScreenshot end object miScreenshot3sec: TMenuItem Action = actScreenShotDelay3Sec end object miScreenshot5sec: TMenuItem Action = actScreenShotDelay5sec end end end object miAbout: TMenuItem Caption = 'About' object miAbout2: TMenuItem Action = actAbout end end end object pmEditMenu: TPopupMenu OnPopup = pmEditMenuPopup Left = 152 Top = 64 object pmiCopy: TMenuItem Action = actCopyToClipboard end object pmiCopyFormatted: TMenuItem Action = actCopyToClipboardFormatted end object miDiv5: TMenuItem Caption = '-' end object pmiSelectAll: TMenuItem Action = actSelectAll end end object SavePictureDialog: TSavePictureDialog Left = 768 Top = 296 end object TimerViewer: TTimer Enabled = False Interval = 10 OnTimer = TimerViewerTimer Left = 752 Top = 240 end object actionList: TActionList Images = dmComData.ilViewerImages Left = 408 Top = 144 object actAbout: TAction Category = 'Help' Caption = 'About Viewer...' Hint = 'Displays the About message' OnExecute = actExecute end object actReload: TAction Category = 'File' Caption = 'Reload' Hint = 'Reload current file' ImageIndex = 0 OnExecute = actExecute end object actLoadNextFile: TAction Category = 'File' Caption = '&Next' Hint = 'Load Next File' ImageIndex = 2 OnExecute = actExecute end object actLoadPrevFile: TAction Category = 'File' Caption = '&Previous' Hint = 'Load Previous File' ImageIndex = 1 OnExecute = actExecute end object actMoveFile: TAction Category = 'File' Caption = 'Move File' Hint = 'Move File' ImageIndex = 4 OnExecute = actExecute end object actCopyFile: TAction Category = 'File' Caption = 'Copy File' Hint = 'Copy File' ImageIndex = 3 OnExecute = actExecute end object actDeleteFile: TAction Category = 'File' Caption = 'Delete File' Hint = 'Delete File' ImageIndex = 5 OnExecute = actExecute end object actStretchImage: TAction Category = 'Image' Caption = 'Stretch' Hint = 'Stretch Image' OnExecute = actExecute end object actSaveAs: TAction Category = 'File' Caption = 'Save As...' Hint = 'Save File As...' OnExecute = actExecute end object actRotate90: TAction Category = 'Image' Caption = '+ 90' Hint = 'Rotate +90 degrees' ImageIndex = 9 OnExecute = actExecute end object actRotate180: TAction Category = 'Image' Caption = '+ 180' Hint = 'Rotate 180 degrees' OnExecute = actExecute end object actRotate270: TAction Category = 'Image' Caption = '- 90' Hint = 'Rotate -90 degrees' ImageIndex = 8 OnExecute = actExecute end object actMirrorHorz: TAction Category = 'Image' Caption = 'Mirror Horizontally' Hint = 'Mirror' ImageIndex = 10 OnExecute = actExecute end object actPreview: TAction Category = 'View' Caption = 'Preview' OnExecute = actExecute end object actShowAsText: TAction Category = 'View' Caption = 'Show as &Text' GroupIndex = 1 OnExecute = actExecute end object actShowAsBin: TAction Category = 'View' Caption = 'Show as &Bin' GroupIndex = 1 OnExecute = actExecute end object actShowAsHex: TAction Category = 'View' Caption = 'Show as &Hex' GroupIndex = 1 OnExecute = actExecute end object actSave: TAction Category = 'File' Caption = 'Save' OnExecute = actExecute end object actMirrorVert: TAction Category = 'Image' Caption = 'Mirror Vertically' OnExecute = actExecute end object actExitViewer: TAction Category = 'File' Caption = 'E&xit' OnExecute = actExecute end object actStretchOnlyLarge: TAction Category = 'Image' Caption = 'Stretch only large' OnExecute = actExecute end object actImageCenter: TAction Category = 'Image' Caption = 'Center' OnExecute = actExecute end object actZoom: TAction Category = 'Image' Caption = 'Zoom' end object actZoomIn: TAction Category = 'Image' Caption = 'Zoom In' Hint = 'Zoom In' ImageIndex = 6 OnExecute = actExecute end object actZoomOut: TAction Category = 'Image' Caption = 'Zoom Out' Hint = 'Zoom Out' ImageIndex = 7 OnExecute = actExecute end object actFullscreen: TAction Category = 'Image' Caption = 'Full Screen' ImageIndex = 22 OnExecute = actExecute end object actScreenshot: TAction Category = 'Image' Caption = 'Screenshot' OnExecute = actExecute end object actScreenShotDelay3Sec: TAction Category = 'Image' Caption = 'Delay 3 sec' OnExecute = actExecute end object actScreenShotDelay5sec: TAction Category = 'Image' Caption = 'Delay 5 sec' OnExecute = actExecute end object actShowAsDec: TAction Category = 'View' Caption = 'Show as &Dec' GroupIndex = 1 OnExecute = actExecute end object actShowAsWrapText: TAction Category = 'View' Caption = 'Show as &Wrap text' GroupIndex = 1 OnExecute = actExecute end object actShowAsBook: TAction Category = 'View' Caption = 'Show as B&ook' GroupIndex = 1 OnExecute = actExecute end object actShowGraphics: TAction Category = 'View' Caption = 'Graphics' GroupIndex = 1 OnExecute = actExecute end object actShowOffice: TAction Category = 'View' Caption = 'Office XML (text only)' GroupIndex = 1 OnExecute = actExecute end object actShowPlugins: TAction Category = 'View' Caption = 'Plugins' GroupIndex = 1 OnExecute = actExecute end object actCopyToClipboard: TAction Category = 'Edit' Caption = 'Copy To Clipboard' OnExecute = actExecute end object actCopyToClipboardFormatted: TAction Category = 'Edit' Caption = 'Copy To Clipboard Formatted' OnExecute = actExecute end object actSelectAll: TAction Category = 'Edit' Caption = 'Select All' OnExecute = actExecute end object actFind: TAction Category = 'Edit' Caption = 'Find' OnExecute = actExecute end object actFindNext: TAction Category = 'Edit' Caption = 'Find next' OnExecute = actExecute end object actFindPrev: TAction Category = 'Edit' Caption = 'Find previous' OnExecute = actExecute end object actGotoLine: TAction Category = 'Edit' Caption = 'Goto Line...' Hint = 'Goto Line' OnExecute = actExecute end object actChangeEncoding: TAction Caption = 'Change encoding' OnExecute = actExecute end object actAutoReload: TAction Category = 'File' Caption = 'Auto Reload' OnExecute = actExecute end object actPrintSetup: TAction Category = 'File' Caption = 'Print &setup...' Enabled = False OnExecute = actExecute Visible = False end object actPrint: TAction Category = 'File' Caption = 'P&rint...' Enabled = False OnExecute = actExecute Visible = False end object actShowCaret: TAction Category = 'View' Caption = 'Show text c&ursor' OnExecute = actExecute end object actWrapText: TAction Category = 'View' Caption = '&Wrap text' OnExecute = actExecute end object actShowTransparency: TAction Category = 'Image' Caption = 'Show transparenc&y' OnExecute = actExecute end object actUndo: TAction Category = 'Edit' Caption = 'Undo' Enabled = False Hint = 'Undo' ImageIndex = 20 OnExecute = actExecute end object actShowCode: TAction Category = 'View' Caption = 'Code' GroupIndex = 1 OnExecute = actExecute end end object TimerScreenshot: TTimer Enabled = False OnTimer = TimerScreenshotTimer Left = 196 Top = 165 end object TimerReload: TTimer Enabled = False Interval = 2000 OnTimer = TimerReloadTimer Left = 592 Top = 80 end object pmPenTools: TPopupMenu Images = dmComData.ilViewerImages Left = 903 Top = 249 object miPen: TMenuItem Caption = 'Pen' ImageIndex = 17 OnClick = miPenClick end object miRect: TMenuItem Tag = 1 Caption = 'Rect' ImageIndex = 18 OnClick = miPenClick end object miEllipse: TMenuItem Tag = 2 Caption = 'Ellipse' ImageIndex = 19 OnClick = miPenClick end end object pmPenWidth: TPopupMenu Tag = 1 Left = 996 Top = 249 end object pmTimeShow: TPopupMenu Left = 1088 Top = 248 end object pmStatusBar: TPopupMenu Left = 80 Top = 211 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fviewer.lrj��������������������������������������������������������������������0000644�0001750�0000144�00000030076�14743153644�015563� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":97504706,"name":"tfrmviewer.caption","sourcebytes":[86,105,101,119,101,114],"value":"Viewer"}, {"hash":226526597,"name":"tfrmviewer.btnprevgifframe.hint","sourcebytes":[80,114,101,118,105,111,117,115,32,70,114,97,109,101],"value":"Previous Frame"}, {"hash":105434309,"name":"tfrmviewer.btnnextgifframe.hint","sourcebytes":[78,101,120,116,32,70,114,97,109,101],"value":"Next Frame"}, {"hash":42136229,"name":"tfrmviewer.btngiftobmp.hint","sourcebytes":[69,120,112,111,114,116,32,70,114,97,109,101],"value":"Export Frame"}, {"hash":234009348,"name":"tfrmviewer.btnhightlight.hint","sourcebytes":[72,105,103,104,108,105,103,104,116],"value":"Highlight"}, {"hash":305504,"name":"tfrmviewer.btncuttuimage.hint","sourcebytes":[67,114,111,112],"value":"Crop"}, {"hash":191154755,"name":"tfrmviewer.btnredeye.hint","sourcebytes":[82,101,100,32,69,121,101,115],"value":"Red Eyes"}, {"hash":5668948,"name":"tfrmviewer.btnpaint.hint","sourcebytes":[80,97,105,110,116],"value":"Paint"}, {"hash":49,"name":"tfrmviewer.btnpenwidth.caption","sourcebytes":[49],"value":"1"}, {"hash":93102341,"name":"tfrmviewer.btnresize.hint","sourcebytes":[82,101,115,105,122,101],"value":"Resize"}, {"hash":97995102,"name":"tfrmviewer.btnfullscreen.hint","sourcebytes":[70,117,108,108,32,83,99,114,101,101,110],"value":"Full Screen"}, {"hash":175127959,"name":"tfrmviewer.btnslideshow.caption","sourcebytes":[83,108,105,100,101,32,83,104,111,119],"value":"Slide Show"}, {"hash":2805797,"name":"tfrmviewer.mifile.caption","sourcebytes":[38,70,105,108,101],"value":"&File"}, {"hash":2800388,"name":"tfrmviewer.miedit.caption","sourcebytes":[38,69,100,105,116],"value":"&Edit"}, {"hash":2871239,"name":"tfrmviewer.miview.caption","sourcebytes":[38,86,105,101,119],"value":"&View"}, {"hash":121364483,"name":"tfrmviewer.mnuplugins.caption","sourcebytes":[80,108,117,103,105,110,115],"value":"Plugins"}, {"hash":212198471,"name":"tfrmviewer.miencoding.caption","sourcebytes":[69,110,38,99,111,100,105,110,103],"value":"En&coding"}, {"hash":45103061,"name":"tfrmviewer.miimage.caption","sourcebytes":[38,73,109,97,103,101],"value":"&Image"}, {"hash":93759653,"name":"tfrmviewer.mirotate.caption","sourcebytes":[82,111,116,97,116,101],"value":"Rotate"}, {"hash":197133796,"name":"tfrmviewer.miscreenshot.caption","sourcebytes":[83,99,114,101,101,110,115,104,111,116],"value":"Screenshot"}, {"hash":4691652,"name":"tfrmviewer.miabout.caption","sourcebytes":[65,98,111,117,116],"value":"About"}, {"hash":169503854,"name":"tfrmviewer.actabout.caption","sourcebytes":[65,98,111,117,116,32,86,105,101,119,101,114,46,46,46],"value":"About Viewer..."}, {"hash":27368309,"name":"tfrmviewer.actabout.hint","sourcebytes":[68,105,115,112,108,97,121,115,32,116,104,101,32,65,98,111,117,116,32,109,101,115,115,97,103,101],"value":"Displays the About message"}, {"hash":93074804,"name":"tfrmviewer.actreload.caption","sourcebytes":[82,101,108,111,97,100],"value":"Reload"}, {"hash":185139637,"name":"tfrmviewer.actreload.hint","sourcebytes":[82,101,108,111,97,100,32,99,117,114,114,101,110,116,32,102,105,108,101],"value":"Reload current file"}, {"hash":2837748,"name":"tfrmviewer.actloadnextfile.caption","sourcebytes":[38,78,101,120,116],"value":"&Next"}, {"hash":168992725,"name":"tfrmviewer.actloadnextfile.hint","sourcebytes":[76,111,97,100,32,78,101,120,116,32,70,105,108,101],"value":"Load Next File"}, {"hash":147647923,"name":"tfrmviewer.actloadprevfile.caption","sourcebytes":[38,80,114,101,118,105,111,117,115],"value":"&Previous"}, {"hash":250443285,"name":"tfrmviewer.actloadprevfile.hint","sourcebytes":[76,111,97,100,32,80,114,101,118,105,111,117,115,32,70,105,108,101],"value":"Load Previous File"}, {"hash":208968773,"name":"tfrmviewer.actmovefile.caption","sourcebytes":[77,111,118,101,32,70,105,108,101],"value":"Move File"}, {"hash":208968773,"name":"tfrmviewer.actmovefile.hint","sourcebytes":[77,111,118,101,32,70,105,108,101],"value":"Move File"}, {"hash":129271365,"name":"tfrmviewer.actcopyfile.caption","sourcebytes":[67,111,112,121,32,70,105,108,101],"value":"Copy File"}, {"hash":129271365,"name":"tfrmviewer.actcopyfile.hint","sourcebytes":[67,111,112,121,32,70,105,108,101],"value":"Copy File"}, {"hash":171839205,"name":"tfrmviewer.actdeletefile.caption","sourcebytes":[68,101,108,101,116,101,32,70,105,108,101],"value":"Delete File"}, {"hash":171839205,"name":"tfrmviewer.actdeletefile.hint","sourcebytes":[68,101,108,101,116,101,32,70,105,108,101],"value":"Delete File"}, {"hash":179882696,"name":"tfrmviewer.actstretchimage.caption","sourcebytes":[83,116,114,101,116,99,104],"value":"Stretch"}, {"hash":16317717,"name":"tfrmviewer.actstretchimage.hint","sourcebytes":[83,116,114,101,116,99,104,32,73,109,97,103,101],"value":"Stretch Image"}, {"hash":122542542,"name":"tfrmviewer.actsaveas.caption","sourcebytes":[83,97,118,101,32,65,115,46,46,46],"value":"Save As..."}, {"hash":188537006,"name":"tfrmviewer.actsaveas.hint","sourcebytes":[83,97,118,101,32,70,105,108,101,32,65,115,46,46,46],"value":"Save File As..."}, {"hash":185280,"name":"tfrmviewer.actrotate90.caption","sourcebytes":[43,32,57,48],"value":"+ 90"}, {"hash":134668547,"name":"tfrmviewer.actrotate90.hint","sourcebytes":[82,111,116,97,116,101,32,43,57,48,32,100,101,103,114,101,101,115],"value":"Rotate +90 degrees"}, {"hash":2962608,"name":"tfrmviewer.actrotate180.caption","sourcebytes":[43,32,49,56,48],"value":"+ 180"}, {"hash":136089859,"name":"tfrmviewer.actrotate180.hint","sourcebytes":[82,111,116,97,116,101,32,49,56,48,32,100,101,103,114,101,101,115],"value":"Rotate 180 degrees"}, {"hash":193472,"name":"tfrmviewer.actrotate270.caption","sourcebytes":[45,32,57,48],"value":"- 90"}, {"hash":142139651,"name":"tfrmviewer.actrotate270.hint","sourcebytes":[82,111,116,97,116,101,32,45,57,48,32,100,101,103,114,101,101,115],"value":"Rotate -90 degrees"}, {"hash":111502873,"name":"tfrmviewer.actmirrorhorz.caption","sourcebytes":[77,105,114,114,111,114,32,72,111,114,105,122,111,110,116,97,108,108,121],"value":"Mirror Horizontally"}, {"hash":88119650,"name":"tfrmviewer.actmirrorhorz.hint","sourcebytes":[77,105,114,114,111,114],"value":"Mirror"}, {"hash":126668695,"name":"tfrmviewer.actpreview.caption","sourcebytes":[80,114,101,118,105,101,119],"value":"Preview"}, {"hash":215824932,"name":"tfrmviewer.actshowastext.caption","sourcebytes":[83,104,111,119,32,97,115,32,38,84,101,120,116],"value":"Show as &Text"}, {"hash":231588254,"name":"tfrmviewer.actshowasbin.caption","sourcebytes":[83,104,111,119,32,97,115,32,38,66,105,110],"value":"Show as &Bin"}, {"hash":231589800,"name":"tfrmviewer.actshowashex.caption","sourcebytes":[83,104,111,119,32,97,115,32,38,72,101,120],"value":"Show as &Hex"}, {"hash":366789,"name":"tfrmviewer.actsave.caption","sourcebytes":[83,97,118,101],"value":"Save"}, {"hash":216582201,"name":"tfrmviewer.actmirrorvert.caption","sourcebytes":[77,105,114,114,111,114,32,86,101,114,116,105,99,97,108,108,121],"value":"Mirror Vertically"}, {"hash":4710148,"name":"tfrmviewer.actexitviewer.caption","sourcebytes":[69,38,120,105,116],"value":"E&xit"}, {"hash":125591877,"name":"tfrmviewer.actstretchonlylarge.caption","sourcebytes":[83,116,114,101,116,99,104,32,111,110,108,121,32,108,97,114,103,101],"value":"Stretch only large"}, {"hash":77355714,"name":"tfrmviewer.actimagecenter.caption","sourcebytes":[67,101,110,116,101,114],"value":"Center"}, {"hash":398941,"name":"tfrmviewer.actzoom.caption","sourcebytes":[90,111,111,109],"value":"Zoom"}, {"hash":23458974,"name":"tfrmviewer.actzoomin.caption","sourcebytes":[90,111,111,109,32,73,110],"value":"Zoom In"}, {"hash":23458974,"name":"tfrmviewer.actzoomin.hint","sourcebytes":[90,111,111,109,32,73,110],"value":"Zoom In"}, {"hash":106909908,"name":"tfrmviewer.actzoomout.caption","sourcebytes":[90,111,111,109,32,79,117,116],"value":"Zoom Out"}, {"hash":106909908,"name":"tfrmviewer.actzoomout.hint","sourcebytes":[90,111,111,109,32,79,117,116],"value":"Zoom Out"}, {"hash":97995102,"name":"tfrmviewer.actfullscreen.caption","sourcebytes":[70,117,108,108,32,83,99,114,101,101,110],"value":"Full Screen"}, {"hash":197133796,"name":"tfrmviewer.actscreenshot.caption","sourcebytes":[83,99,114,101,101,110,115,104,111,116],"value":"Screenshot"}, {"hash":192920371,"name":"tfrmviewer.actscreenshotdelay3sec.caption","sourcebytes":[68,101,108,97,121,32,51,32,115,101,99],"value":"Delay 3 sec"}, {"hash":192789299,"name":"tfrmviewer.actscreenshotdelay5sec.caption","sourcebytes":[68,101,108,97,121,32,53,32,115,101,99],"value":"Delay 5 sec"}, {"hash":231588819,"name":"tfrmviewer.actshowasdec.caption","sourcebytes":[83,104,111,119,32,97,115,32,38,68,101,99],"value":"Show as &Dec"}, {"hash":99253012,"name":"tfrmviewer.actshowaswraptext.caption","sourcebytes":[83,104,111,119,32,97,115,32,38,87,114,97,112,32,116,101,120,116],"value":"Show as &Wrap text"}, {"hash":213017739,"name":"tfrmviewer.actshowasbook.caption","sourcebytes":[83,104,111,119,32,97,115,32,66,38,111,111,107],"value":"Show as B&ook"}, {"hash":143059779,"name":"tfrmviewer.actshowgraphics.caption","sourcebytes":[71,114,97,112,104,105,99,115],"value":"Graphics"}, {"hash":132775577,"name":"tfrmviewer.actshowoffice.caption","sourcebytes":[79,102,102,105,99,101,32,88,77,76,32,40,116,101,120,116,32,111,110,108,121,41],"value":"Office XML (text only)"}, {"hash":121364483,"name":"tfrmviewer.actshowplugins.caption","sourcebytes":[80,108,117,103,105,110,115],"value":"Plugins"}, {"hash":93615908,"name":"tfrmviewer.actcopytoclipboard.caption","sourcebytes":[67,111,112,121,32,84,111,32,67,108,105,112,98,111,97,114,100],"value":"Copy To Clipboard"}, {"hash":1794964,"name":"tfrmviewer.actcopytoclipboardformatted.caption","sourcebytes":[67,111,112,121,32,84,111,32,67,108,105,112,98,111,97,114,100,32,70,111,114,109,97,116,116,101,100],"value":"Copy To Clipboard Formatted"}, {"hash":195288076,"name":"tfrmviewer.actselectall.caption","sourcebytes":[83,101,108,101,99,116,32,65,108,108],"value":"Select All"}, {"hash":315460,"name":"tfrmviewer.actfind.caption","sourcebytes":[70,105,110,100],"value":"Find"}, {"hash":73859572,"name":"tfrmviewer.actfindnext.caption","sourcebytes":[70,105,110,100,32,110,101,120,116],"value":"Find next"}, {"hash":97034739,"name":"tfrmviewer.actfindprev.caption","sourcebytes":[70,105,110,100,32,112,114,101,118,105,111,117,115],"value":"Find previous"}, {"hash":102945374,"name":"tfrmviewer.actgotoline.caption","sourcebytes":[71,111,116,111,32,76,105,110,101,46,46,46],"value":"Goto Line..."}, {"hash":185950757,"name":"tfrmviewer.actgotoline.hint","sourcebytes":[71,111,116,111,32,76,105,110,101],"value":"Goto Line"}, {"hash":216568103,"name":"tfrmviewer.actchangeencoding.caption","sourcebytes":[67,104,97,110,103,101,32,101,110,99,111,100,105,110,103],"value":"Change encoding"}, {"hash":96796260,"name":"tfrmviewer.actautoreload.caption","sourcebytes":[65,117,116,111,32,82,101,108,111,97,100],"value":"Auto Reload"}, {"hash":216689422,"name":"tfrmviewer.actprintsetup.caption","sourcebytes":[80,114,105,110,116,32,38,115,101,116,117,112,46,46,46],"value":"Print &setup..."}, {"hash":151339998,"name":"tfrmviewer.actprint.caption","sourcebytes":[80,38,114,105,110,116,46,46,46],"value":"P&rint..."}, {"hash":36280978,"name":"tfrmviewer.actshowcaret.caption","sourcebytes":[83,104,111,119,32,116,101,120,116,32,99,38,117,114,115,111,114],"value":"Show text c&ursor"}, {"hash":136647284,"name":"tfrmviewer.actwraptext.caption","sourcebytes":[38,87,114,97,112,32,116,101,120,116],"value":"&Wrap text"}, {"hash":110327497,"name":"tfrmviewer.actshowtransparency.caption","sourcebytes":[83,104,111,119,32,116,114,97,110,115,112,97,114,101,110,99,38,121],"value":"Show transparenc&y"}, {"hash":378031,"name":"tfrmviewer.actundo.caption","sourcebytes":[85,110,100,111],"value":"Undo"}, {"hash":378031,"name":"tfrmviewer.actundo.hint","sourcebytes":[85,110,100,111],"value":"Undo"}, {"hash":304549,"name":"tfrmviewer.actshowcode.caption","sourcebytes":[67,111,100,101],"value":"Code"}, {"hash":22206,"name":"tfrmviewer.mipen.caption","sourcebytes":[80,101,110],"value":"Pen"}, {"hash":363428,"name":"tfrmviewer.mirect.caption","sourcebytes":[82,101,99,116],"value":"Rect"}, {"hash":204670933,"name":"tfrmviewer.miellipse.caption","sourcebytes":[69,108,108,105,112,115,101],"value":"Ellipse"} ]} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fviewer.pas��������������������������������������������������������������������0000755�0001750�0000144�00000341377�14743153644�015573� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Build-in File Viewer. Copyright (C) 2007-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Legacy comment from its origin: ------------------------------------------------------------------------- Seksi Commander Integrated viewer form Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz contributors: Radek Polak ported to lazarus: changes: 23.7. - fixed: scroll bar had wrong max value until user pressed key (by Radek Polak) - fixed: wrong scrolling with scroll bar - now look at ScrollBarVertScroll (by Radek Polak) Dmitry Kolomiets 15.03.08 changes: - Added WLX api support (TC WLX api v 1.8) Rustem Rakhimov 25.04.10 changes: - fullscreen - function for edit image - slide show - some Viwer function } unit fViewer; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls, ComCtrls, LMessages, LCLProc, Menus, Dialogs, ExtDlgs, StdCtrls, Buttons, SynEditHighlighter, Grids, ActnList, viewercontrol, GifAnim, fFindView, WLXPlugin, uWLXModule, uFileSource, fModView, Types, uThumbnails, uFormCommands, uOSForms,Clipbrd, uExifReader, KASStatusBar, SynEdit, uShowForm, uRegExpr, uRegExprU, Messages, fEditSearch, uMasks, uSearchTemplate; type TEncodingMenu = (emViewer, emPlugin, emEditor); TViewerCopyMoveAction=(vcmaCopy,vcmaMove); { TDrawGrid } TDrawGrid = class(Grids.TDrawGrid) private FMutex: Integer; private function GetIndex: Integer; procedure SetIndex(AValue: Integer); protected procedure MoveSelection; override; public property Index: Integer read GetIndex write SetIndex; end; { TfrmViewer } TfrmViewer = class(TAloneForm, IFormCommands) actAbout: TAction; actCopyFile: TAction; actDeleteFile: TAction; actCopyToClipboard: TAction; actImageCenter: TAction; actFullscreen: TAction; actCopyToClipboardFormatted: TAction; actChangeEncoding: TAction; actAutoReload: TAction; actShowCode: TAction; actUndo: TAction; actShowTransparency: TAction; actWrapText: TAction; actShowCaret: TAction; actPrint: TAction; actPrintSetup: TAction; actShowAsDec: TAction; actScreenShotDelay5sec: TAction; actScreenShotDelay3Sec: TAction; actScreenshot: TAction; actZoomOut: TAction; actZoomIn: TAction; actZoom: TAction; actStretchOnlyLarge: TAction; actFindNext: TAction; actShowGraphics: TAction; actExitViewer: TAction; actMirrorVert: TAction; actSave: TAction; actShowOffice: TAction; actShowPlugins: TAction; actShowAsBook: TAction; actShowAsWrapText: TAction; actShowAsHex: TAction; actShowAsBin: TAction; actShowAsText: TAction; actPreview: TAction; actGotoLine: TAction; actFindPrev: TAction; actFind: TAction; actSelectAll: TAction; actMirrorHorz: TAction; actRotate270: TAction; actRotate180: TAction; actRotate90: TAction; actSaveAs: TAction; actStretchImage: TAction; actMoveFile: TAction; actLoadPrevFile: TAction; actLoadNextFile: TAction; actReload: TAction; actionList: TActionList; btnCopyFile1: TSpeedButton; btnDeleteFile1: TSpeedButton; btnMoveFile1: TSpeedButton; btnNext1: TSpeedButton; btnPenColor: TColorButton; btnPrev1: TSpeedButton; btnReload1: TSpeedButton; DrawPreview: TDrawGrid; GifAnim: TGifAnim; memFolder: TMemo; mnuPlugins: TMenuItem; miCode: TMenuItem; miShowTransparency: TMenuItem; miWrapText: TMenuItem; miPen: TMenuItem; miRect: TMenuItem; miEllipse: TMenuItem; miShowCaret: TMenuItem; miPrintSetup: TMenuItem; miAutoReload: TMenuItem; pmiCopyFormatted: TMenuItem; miDec: TMenuItem; MenuItem2: TMenuItem; miScreenshot5sec: TMenuItem; miScreenshot3sec: TMenuItem; miScreenshotImmediately: TMenuItem; miReload: TMenuItem; miLookBook: TMenuItem; miDiv4: TMenuItem; miPreview: TMenuItem; miScreenshot: TMenuItem; miFullScreen: TMenuItem; miSave: TMenuItem; miSaveAs: TMenuItem; Image: TImage; miZoomOut: TMenuItem; miZoomIn: TMenuItem; miRotate: TMenuItem; miMirror: TMenuItem; mi270: TMenuItem; mi180: TMenuItem; mi90: TMenuItem; miGotoLine: TMenuItem; miSearchPrev: TMenuItem; miPrint: TMenuItem; miSearchNext: TMenuItem; pnlFolder: TPanel; pnlPreview: TPanel; pnlEditFile: TPanel; pmiSelectAll: TMenuItem; miDiv5: TMenuItem; pmiCopy: TMenuItem; pnlImage: TPanel; pnlText: TPanel; pnlCode: TPanel; pmStatusBar: TPopupMenu; SynEdit: TSynEdit; miDiv3: TMenuItem; miOffice: TMenuItem; miEncoding: TMenuItem; miPlugins: TMenuItem; miSeparator: TMenuItem; pmEditMenu: TPopupMenu; pmPenTools: TPopupMenu; pmPenWidth: TPopupMenu; pmTimeShow: TPopupMenu; SavePictureDialog: TSavePictureDialog; sboxImage: TScrollBox; Splitter: TSplitter; Status: TKASStatusBar; MainMenu: TMainMenu; miFile: TMenuItem; miPrev: TMenuItem; miNext: TMenuItem; miView: TMenuItem; miExit: TMenuItem; miImage: TMenuItem; miStretch: TMenuItem; miStretchOnlyLarge: TMenuItem; miCenter: TMenuItem; miText: TMenuItem; miBin: TMenuItem; miHex: TMenuItem; miAbout: TMenuItem; miAbout2: TMenuItem; miDiv1: TMenuItem; miSearch: TMenuItem; miDiv2: TMenuItem; miGraphics: TMenuItem; miEdit: TMenuItem; miSelectAll: TMenuItem; miCopyToClipboard: TMenuItem; TimerReload: TTimer; TimerScreenshot: TTimer; TimerViewer: TTimer; ToolBar1: TToolBar; btnReload: TToolButton; btn270: TToolButton; btn90: TToolButton; btnMirror: TToolButton; btnCutTuImage: TToolButton; btnRedEye: TToolButton; btnPaintSeparator: TToolButton; btnUndo: TToolButton; btnPenMode: TToolButton; btnGifSeparator: TToolButton; btnGifMove: TToolButton; btnPrevGifFrame: TToolButton; btnNextGifFrame: TToolButton; btnGifToBmp: TToolButton; btnPenWidth: TToolButton; btnPrev: TToolButton; btnNext: TToolButton; btnCopyFile: TToolButton; btnMoveFile: TToolButton; btnDeleteFile: TToolButton; btnSeparator: TToolButton; btnSlideShow: TToolButton; btnFullScreen: TToolButton; btnResize: TToolButton; btnPaint: TToolButton; btnZoomSeparator: TToolButton; btnZoomIn: TToolButton; btnZoomOut: TToolButton; btnHightlightSeparator: TToolButton; btnHightlight: TToolButton; ViewerControl: TViewerControl; procedure actExecute(Sender: TObject); procedure btnCutTuImageClick(Sender: TObject); procedure btnFullScreenClick(Sender: TObject); procedure btnGifMoveClick(Sender: TObject); procedure btnGifToBmpClick(Sender: TObject); procedure btnPaintHightlight(Sender: TObject); procedure btnPenModeClick(Sender: TObject); procedure btnPrevGifFrameClick(Sender: TObject); procedure btnRedEyeClick(Sender: TObject); procedure btnResizeClick(Sender: TObject); procedure btnSlideShowClick(Sender: TObject); procedure DrawPreviewDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); procedure DrawPreviewSelection(Sender: TObject; aCol, aRow: Integer); procedure DrawPreviewTopleftChanged(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender : TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); procedure FormResize(Sender: TObject); procedure FormShow(Sender: TObject); procedure GifAnimMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure GifAnimMouseEnter(Sender: TObject); procedure ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure ImageMouseEnter(Sender: TObject); procedure ImageMouseLeave(Sender: TObject); procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer ); procedure ImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure ImageMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure ImageMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure miPenClick(Sender: TObject); procedure miLookBookClick(Sender: TObject); procedure pmEditMenuPopup(Sender: TObject); procedure pnlImageResize(Sender: TObject); procedure miPluginsClick(Sender: TObject); procedure pnlTextMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure sboxImageMouseEnter(Sender: TObject); procedure sboxImageMouseLeave(Sender: TObject); procedure sboxImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure btnNextGifFrameClick(Sender: TObject); procedure SplitterChangeBounds; procedure TimerReloadTimer(Sender: TObject); procedure TimerScreenshotTimer(Sender: TObject); procedure TimerViewerTimer(Sender: TObject); procedure ViewerControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure frmViewerClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormDestroy(Sender: TObject); procedure miPaintClick(Sender:TObject); procedure miChangeEncodingClick(Sender:TObject); procedure SynEditStatusChange(Sender: TObject; Changes: TSynStatusChanges); procedure SynEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure SynEditMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure ViewerControlMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure ViewerControlMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure ViewerPositionChanged(Sender:TObject); function PluginShowFlags : Integer; procedure UpdateImagePlacement; private FFileName: String; FileList: TStringList; iActiveFile, tmpX, tmpY, startX, startY, endX, endY, UndoSX, UndoSY, UndoEX, UndoEY, cas, i_timer:Integer; bAnimation, bImage, bPlugin, bQuickView, MDFlag, ImgEdit: Boolean; FThumbSize: TSize; FFindDialog:TfrmFindView; FWaitData: TWaitData; FLastSearchPos: PtrInt; FLastMatchLength: IntPtr; tmp_all: TCustomBitmap; FModSizeDialog: TfrmModView; FThumbnailManager: TThumbnailManager; FCommands: TFormCommands; FZoomFactor: Integer; FExif: TExifReader; FWindowState: TWindowState; FElevate: TDuplicates; {$IF DEFINED(LCLWIN32)} FWindowBounds: TRect; {$ENDIF} FThread: TThread; FMode: Integer; FRegExp: TRegExprEx; FPluginEncoding: Integer; //--------------------- FSynEditOriginalText: String; FSearchOptions: TEditSearchOptions; FHighlighter: TSynCustomHighlighter; //--------------------- WlxPlugins: TWLXModuleList; FWlxModule: TWlxModule; ActivePlugin: Integer; //--------------------- function GetListerRect: TRect; function CheckOffice(const sFileName: String): Boolean; function CheckSynEdit(const sFileName: String; bForce: Boolean = False): Boolean; function CheckPlugins(const sFileName: String; bForce: Boolean = False): Boolean; function CheckGraphics(const sFileName:String):Boolean; function LoadGraphics(const sFileName:String): Boolean; function LoadSynEdit(const sFileName: String): Boolean; function LoadPlugin(const sFileName: String; Index, ShowFlags: Integer): Boolean; procedure AdjustImageSize; procedure DoSearchCode(bQuickSearch: Boolean; bSearchBackwards: Boolean); procedure DoSearch(bQuickSearch: Boolean; bSearchBackwards: Boolean); procedure UpdateTextEncodingsMenu(AType: TEncodingMenu); procedure MakeTextEncodingsMenu; procedure ActivatePanel(Panel: TPanel); procedure ReopenAsTextIfNeeded; procedure UpdatePluginsMenu; procedure MakePluginsMenu; procedure CheckXY; procedure UndoTmp; procedure CreateTmp; procedure CutToImage; procedure Res(W, H: integer); procedure RedEyes; procedure SynEditCaret; procedure ExitPluginMode; procedure DeleteCurrentFile; procedure EnablePrint(AEnabled: Boolean); procedure EnableActions(AEnabled: Boolean); procedure SavingProperties(Sender: TObject); procedure SetFileName(const AValue: String); procedure SaveImageAs (Var sExt: String; senderSave: boolean; Quality: integer); procedure ImagePaintBackground(ASender: TObject; ACanvas: TCanvas; ARect: TRect); procedure CreatePreview(FullPathToFile:string; index:integer; delete: boolean = false); property Commands: TFormCommands read FCommands implements IFormCommands; property FileName: String write SetFileName; protected procedure WMCommand(var Message: TLMCommand); message LM_COMMAND; procedure WMSetFocus(var Message: TLMSetFocus); message LM_SETFOCUS; procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED; public constructor Create(TheOwner: TComponent; aWaitData: TWaitData; aQuickView: Boolean = False); overload; constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure AfterConstruction; override; procedure LoadFile(iIndex: Integer); procedure LoadFile(const aFileName: String); procedure LoadNextFile(Index: Integer); procedure LoadNextFile(const aFileName: String); procedure ExitQuickView; procedure ShowTextViewer(AMode: TViewerControlMode); procedure CopyMoveFile(AViewerAction:TViewerCopyMoveAction); procedure ZoomImage(ADelta: Double); procedure RotateImage(AGradus:integer); procedure MirrorImage(AVertically:boolean=False); published // Commands for hotkey manager procedure cm_About(const Params: array of string); procedure cm_Reload(const Params: array of string); procedure cm_AutoReload(const Params: array of string); procedure cm_LoadNextFile(const Params: array of string); procedure cm_LoadPrevFile(const Params: array of string); procedure cm_MoveFile(const Params: array of string); procedure cm_CopyFile(const Params: array of string); procedure cm_DeleteFile(const Params: array of string); procedure cm_StretchImage(const Params: array of string); procedure cm_StretchOnlyLarge(const Params: array of string); procedure cm_ShowTransparency(const Params: array of string); procedure cm_Save(const Params:array of string); procedure cm_Undo(const Params: array of string); procedure cm_SaveAs(const Params: array of string); procedure cm_Rotate90(const Params: array of string); procedure cm_Rotate180(const Params: array of string); procedure cm_Rotate270(const Params: array of string); procedure cm_MirrorHorz(const Params: array of string); procedure cm_MirrorVert(const Params: array of string); procedure cm_ImageCenter(const Params: array of string); procedure cm_Zoom(const Params: array of string); procedure cm_ZoomIn(const Params: array of string); procedure cm_ZoomOut(const Params: array of string); procedure cm_Fullscreen(const Params: array of string); procedure cm_Screenshot(const Params: array of string); procedure cm_ScreenshotWithDelay(const Params: array of string); procedure cm_ScreenshotDelay3sec(const Params: array of string); procedure cm_ScreenshotDelay5sec(const Params: array of string); procedure cm_ChangeEncoding(const Params: array of string); procedure cm_CopyToClipboard (const Params: array of string); procedure cm_CopyToClipboardFormatted (const Params: array of string); procedure cm_SelectAll (const Params: array of string); procedure cm_Find (const Params: array of string); procedure cm_FindNext (const Params: array of string); procedure cm_FindPrev (const Params: array of string); procedure cm_GotoLine (const Params: array of string); procedure cm_Preview (const Params: array of string); procedure cm_ShowAsText (const Params: array of string); procedure cm_ShowAsBin (const Params: array of string); procedure cm_ShowAsHex (const Params: array of string); procedure cm_ShowAsDec (const Params: array of string); procedure cm_ShowAsWrapText (const Params: array of string); procedure cm_ShowAsBook (const Params: array of string); procedure cm_ShowGraphics (const Params: array of string); procedure cm_ShowPlugins (const Params: array of string); procedure cm_ShowOffice (const Params: array of string); procedure cm_ShowCode (const Params: array of string); procedure cm_ExitViewer (const Params: array of string); procedure cm_Print(const Params:array of string); procedure cm_PrintSetup(const Params:array of string); procedure cm_ShowCaret(const Params: array of string); procedure cm_WrapText(const Params: array of string); end; procedure ShowViewer(const FilesToView: TStringList; WaitData: TWaitData = nil); overload; procedure ShowViewer(const FilesToView: TStringList; AMode: Integer; WaitData: TWaitData = nil); overload; implementation {$R *.lfm} uses FileUtil, IntfGraphics, Math, uLng, uShowMsg, uGlobs, LCLType, LConvEncoding, DCClassesUtf8, uFindMmap, DCStrUtils, uDCUtils, LCLIntf, uDebug, uHotkeyManager, uConvEncoding, DCBasicTypes, DCOSUtils, uOSUtils, uFindByrMr, uFileViewWithGrid, fPrintSetup, uFindFiles, uAdministrator, uOfficeXML, uHighlighterProcs, dmHigh, SynEditTypes, uFile, uFileSystemFileSource, uFileProcs {$IFDEF LCLGTK2} , uGraphics {$ENDIF} ; const HotkeysCategory = 'Viewer'; // Status bar panels indexes. sbpFileName = 4; sbpFileNr = 0; // Text sbpPosition = 1; sbpFileSize = 2; sbpTextEncoding = 3; // WLX sbpPluginName = 1; // Graphics sbpCurrentResolution = 1; sbpFullResolution = 2; sbpImageSelection = 3; const WRAP_MODE: array[Boolean] of TViewerControlMode = (vcmText, vcmWrap); type { TThumbThread } TThumbThread = class(TThread) private FOwner: TfrmViewer; procedure ClearList; procedure DoOnTerminate(Sender: TObject); protected procedure Execute; override; public constructor Create(Owner: TfrmViewer); class procedure Finish(var Thread: TThread); end; procedure ShowViewer(const FilesToView: TStringList; WaitData: TWaitData); begin ShowViewer(FilesToView, 0, WaitData); end; procedure ShowViewer(const FilesToView: TStringList; AMode: Integer; WaitData: TWaitData); var Viewer: TfrmViewer; begin //DCDebug('ShowViewer - Using Internal'); Viewer := TfrmViewer.Create(Application, WaitData); Viewer.FileList.Assign(FilesToView);// Make a copy of the list Viewer.DrawPreview.RowCount:= Viewer.FileList.Count; Viewer.actMoveFile.Enabled := FilesToView.Count > 1; Viewer.actDeleteFile.Enabled := FilesToView.Count > 1; with Viewer.ViewerControl do begin if (AMode = 0) then AMode:= gViewerMode else begin Viewer.FMode:= AMode; end; case AMode of 1: Mode:= WRAP_MODE[gViewerWrapText]; 2: Mode:= vcmBin; 3: Mode:= vcmHex; 6: Mode:= vcmDec; end; end; Viewer.LoadFile(0); if (WaitData = nil) then Viewer.ShowOnTop else begin WaitData.ShowOnTop(Viewer); end; end; { TDrawGrid } function TDrawGrid.GetIndex: Integer; begin Result:= Row * ColCount + Col; end; procedure TDrawGrid.SetIndex(AValue: Integer); begin if (FMutex = 0) then try Inc(FMutex); MoveExtend(False, AValue mod ColCount, AValue div ColCount); finally Dec(FMutex) end; end; procedure TDrawGrid.MoveSelection; begin if (FMutex = 0) then try Inc(FMutex); inherited MoveSelection; finally Dec(FMutex) end; end; { TThumbThread } procedure TThumbThread.ClearList; var Index: Integer; begin for Index:= 0 to FOwner.FileList.Count - 1 do begin FOwner.FileList.Objects[Index].Free; FOwner.FileList.Objects[Index]:= nil; end; end; procedure TThumbThread.DoOnTerminate(Sender: TObject); begin FOwner.EnableActions(True); FOwner := nil; end; procedure TThumbThread.Execute; var I: Integer = 0; begin while (not Terminated) and (I < FOwner.FileList.Count) do begin FOwner.CreatePreview(FOwner.FileList.Strings[I], I); if (I mod 3 = 0) then Synchronize(@FOwner.DrawPreview.Invalidate); Inc(I); end; Synchronize(@FOwner.DrawPreview.Invalidate); end; constructor TThumbThread.Create(Owner: TfrmViewer); begin inherited Create(True); Owner.EnableActions(False); OnTerminate := @DoOnTerminate; FOwner := Owner; ClearList; Start; end; class procedure TThumbThread.Finish(var Thread: TThread); begin if Assigned(Thread) then begin Thread.Terminate; Thread.WaitFor; FreeAndNil(Thread); end; end; constructor TfrmViewer.Create(TheOwner: TComponent; aWaitData: TWaitData; aQuickView: Boolean); begin bQuickView:= aQuickView; inherited Create(TheOwner); FWaitData := aWaitData; FLastSearchPos := -1; FZoomFactor := 100; ActivePlugin := -1; FThumbnailManager:= nil; FExif:= TExifReader.Create; FRegExp:= TRegExprEx.Create; if not bQuickView then Menu:= MainMenu; FCommands := TFormCommands.Create(Self, actionList); FontOptionsToFont(gFonts[dcfMain], memFolder.Font); memFolder.Color:= gColors.FilePanel^.BackColor; actShowCaret.Checked := gShowCaret; actWrapText.Checked := gViewerWrapText; ViewerControl.ShowCaret := gShowCaret; ViewerControl.TabSpaces := gTabSpaces; ViewerControl.AutoCopy := gViewerAutoCopy; ViewerControl.MaxTextWidth := gMaxTextWidth; ViewerControl.LeftMargin := gViewerLeftMargin; ViewerControl.ExtraLineSpacing := gViewerLineSpacing; if gViewerWrapText then ViewerControl.Mode:= vcmWrap; end; constructor TfrmViewer.Create(TheOwner: TComponent); begin Create(TheOwner, nil); end; destructor TfrmViewer.Destroy; begin FExif.Free; FreeAndNil(FRegExp); FreeAndNil(FileList); FreeAndNil(FThumbnailManager); inherited Destroy; FreeAndNil(WlxPlugins); FWaitData.Free; // If this is temp file source, the files will be deleted. tmp_all.Free; end; procedure TfrmViewer.AfterConstruction; begin inherited AfterConstruction; ToolBar1.ImagesWidth:= gToolIconsSize; ToolBar1.SetButtonSize(gToolIconsSize + ScaleX(6, 96), gToolIconsSize + ScaleY(6, 96)); end; procedure TfrmViewer.LoadFile(const aFileName: String); var i: Integer; aName: String; dwFileAttributes: TFileAttrs; begin FLastSearchPos := -1; Caption := ReplaceHome(aFileName); ViewerControl.FileName := EmptyStr; // Clear text on status bar. for i := 0 to Status.Panels.Count - 1 do Status.Panels[i].Text := ''; dwFileAttributes := mbFileGetAttr(aFileName); if FPS_ISLNK(dwFileAttributes) then begin dwFileAttributes := mbFileGetAttrNoLinks(aFileName); end; if dwFileAttributes = faInvalidAttributes then begin ActivatePanel(pnlFolder); ExitPluginMode; memFolder.Font.Color:= clRed; memFolder.Lines.Text:= rsMsgErrNoFiles; Exit; end; if bQuickView then begin iActiveFile := 0; FileList.Text := aFileName; end; Screen.BeginWaitCursor; try if FPS_ISDIR(dwFileAttributes) then aName:= IncludeTrailingPathDelimiter(aFileName) else begin aName:= aFileName; end; if (FMode > 0) then begin ViewerControl.FileName := aFileName; ActivatePanel(pnlText); FMode:= 0; end else if CheckPlugins(aName) then ActivatePanel(nil) else if FPS_ISDIR(dwFileAttributes) then begin ActivatePanel(pnlFolder); memFolder.Clear; memFolder.Font.Color:= gColors.FilePanel^.ForeColor; memFolder.Lines.Add(rsPropsFolder + ': '); memFolder.Lines.Add(aFileName); memFolder.Lines.Add(''); end else if CheckGraphics(aFileName) and LoadGraphics(aFileName) then ActivatePanel(pnlImage) else if CheckOffice(aFileName) then begin ActivatePanel(pnlText); miOffice.Checked:= True; end else if CheckSynEdit(aFileName) and LoadSynEdit(aFileName) then begin ActivatePanel(pnlCode); end else begin ViewerControl.FileName := aFileName; ActivatePanel(pnlText) end; FileName:= aFileName; finally Screen.EndWaitCursor; end; end; procedure TfrmViewer.LoadNextFile(Index: Integer); begin try if bPlugin and FWlxModule.FileParamVSDetectStr(FileList[Index], False) then begin if (FWlxModule.CallListLoadNext(Self.Handle, FileList[Index], PluginShowFlags) <> LISTPLUGIN_ERROR) then begin Status.Panels[sbpFileNr].Text:= Format('%d/%d', [Index + 1, FileList.Count]); FileName:= FileList[Index]; Caption:= ReplaceHome(FFileName); iActiveFile := Index; Exit; end; end; ExitPluginMode; LoadFile(Index); finally if pnlPreview.Visible then DrawPreview.Index:= iActiveFile; end; end; procedure TfrmViewer.LoadNextFile(const aFileName: String); begin if bPlugin and FWlxModule.FileParamVSDetectStr(aFileName, False) then begin if FWlxModule.CallListLoadNext(Self.Handle, aFileName, PluginShowFlags) <> LISTPLUGIN_ERROR then begin Self.FileName:= aFileName; Exit; end; end; ExitPluginMode; ViewerControl.ResetEncoding; LoadFile(aFileName); if ViewerControl.IsFileOpen then begin ViewerControl.GoHome; if (ViewerControl.Mode = vcmText) then ViewerControl.HGoHome; end; if actAutoReload.Checked then cm_AutoReload([]); end; procedure TfrmViewer.LoadFile(iIndex: Integer); var ANewFile: Boolean; begin ANewFile:= iActiveFile <> iIndex; iActiveFile := iIndex; LoadFile(FileList.Strings[iIndex]); btnPaint.Down:= False; btnHightlight.Down:= False; Status.Panels[sbpFileNr].Text:= Format('%d/%d', [iIndex + 1, FileList.Count]); if ANewFile then begin if ViewerControl.IsFileOpen then begin ViewerControl.GoHome; if (ViewerControl.Mode = vcmText) then ViewerControl.HGoHome; end; if actAutoReload.Checked then cm_AutoReload([]); end; end; procedure TfrmViewer.FormResize(Sender: TObject); begin if bPlugin then FWlxModule.ResizeWindow(GetListerRect); end; procedure TfrmViewer.FormShow(Sender: TObject); begin {$IF DEFINED(LCLGTK2)} if not pnlPreview.Visible then begin pnlPreview.Visible:= True; pnlPreview.Visible:= False; end; {$ENDIF} // Was not supposed to be necessary, but this fix a problem with old "hpg_ed" plugin // that needed a resize to be spotted in correct position. Through 27 plugins tried, was the only one required that. :-( FormResize(Self); if miPreview.Checked then begin miPreview.Checked := not (miPreview.Checked); cm_Preview(['']); end; end; procedure TfrmViewer.GifAnimMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button=mbRight then begin pmEditMenu.PopUp; end; end; procedure TfrmViewer.GifAnimMouseEnter(Sender: TObject); begin if miFullScreen.Checked then TimerViewer.Enabled:=true; end; procedure TfrmViewer.ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin MDFlag := true; X:=round(X*Image.Picture.Width/Image.Width); // for correct paint after zoom Y:=round(Y*Image.Picture.Height/Image.Height); cas:=0; if (button = mbLeft) and btnHightlight.Down then begin if (X>StartX) and (X<=StartX+10) then begin if (Y>StartY) and (Y<=StartY+10) then begin cas:=1; tmpX:=X-StartX; tmpY:=Y-StartY; end; if (Y>StartY+10) and (Y<=EndY-10) then begin cas:=2; tmpX:=X-StartX; end; if (Y>EndY-9) and (Y<=EndY) then begin cas:=3; tmpX:=X-StartX; tmpY:=EndY-Y; end; if (Y<StartY) or (Y>EndY) then cas:=0; end; if (X>StartX+10) and (X<=EndX-10) then begin if (Y>StartY) and (Y<=StartY+10) then begin cas:=4; tmpY:=Y-StartY; end; if (Y>StartY+10) and (Y<=EndY-10)then begin cas:=5; tmpX:=X-StartX; tmpY:=Y-StartY; end; if (Y>EndY-9) and (Y<=EndY) then begin cas:=6; tmpY:=EndY-Y; end; If (Y<StartY) or (Y>EndY) then cas:=0; end; if (X>EndX-10) and (X<=EndX) then begin if (Y>StartY) and (Y<=StartY+10) then begin cas:=7; tmpX := EndX-X; tmpY:=StartY-Y; end; if (Y>StartY+10) and (Y<=EndY-10) then begin cas:=8; tmpX := EndX-X; end; if (Y>EndY-9) and (Y<=EndY) then begin cas:=9; tmpX := EndX-X; tmpY:=EndY-Y; end; If (Y<StartY) or (Y>EndY) then cas:=0; end; if (X<StartX) or (X>EndX) then cas:=0; end; if Button=mbRight then begin pmEditMenu.PopUp; end; if cas=0 then begin StartX := X; StartY := Y; end; if btnPaint.Down then begin CreateTmp; Image.Picture.Bitmap.Canvas.MoveTo (x,y); end; if not (btnHightlight.Down) and not (btnPaint.Down) then begin tmpX:=x; tmpY:=y; Image.Cursor:=crHandPoint; end; end; procedure TfrmViewer.ImageMouseEnter(Sender: TObject); begin if miFullScreen.Checked then TimerViewer.Enabled:=true; end; procedure TfrmViewer.ImageMouseLeave(Sender: TObject); begin if miFullScreen.Checked then TimerViewer.Enabled:=false; end; procedure TfrmViewer.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var tmp: integer; begin if btnHightlight.Down then Image.Cursor:=crCross; if miFullScreen.Checked then begin sboxImage.Cursor:=crDefault; Image.Cursor:=crDefault; i_timer:=0; end; X:=round(X*Image.Picture.Width/Image.Width); // for correct paint after zoom Y:=round(Y*Image.Picture.Height/Image.Height); if MDFlag then begin if btnHightlight.Down then begin if cas=0 then begin EndX:=X; EndY:=Y; end; if cas=1 then begin StartX:= X-tmpX; StartY:=Y-tmpY; end; if cas=2 then StartX:= X-tmpX; if cas=3then begin StartX:= X-tmpX; EndY:=Y+tmpY; end; if cas=4 then StartY:=Y-tmpY; if cas=5 then begin tmp:=EndX-StartX; StartX:= X-tmpX; EndX:=StartX+tmp; tmp:=EndY-StartY; StartY:= Y-tmpY; EndY:=StartY+tmp; end; if cas=6 then EndY:=Y+tmpY; if cas=7 then begin EndX:=X+tmpX; StartY:=Y-tmpY; end; if cas=8 then endX:=X+tmpX; if cas=9 then begin EndX:=X+tmpX; EndY:=Y+tmpY; end; if StartX<0 then begin StartX:=0; EndX:= UndoEX; end; if StartY<0 then begin StartY:=0; EndY:= UndoEY; end; if endX> Image.Picture.Width then endX:=Image.Picture.Width; if endY> Image.Picture.Height then endY:=Image.Picture.Height; with Image.Picture.Bitmap.Canvas do begin DrawFocusRect(Rect(UndoSX,UndoSY,UndoEX,UndoEY)); DrawFocusRect(Rect(UndoSX+10,UndoSY+10,UndoEX-10,UndoEY-10)); DrawFocusRect(Rect(StartX,StartY,EndX,EndY)); DrawFocusRect(Rect(StartX+10,StartY+10,EndX-10,EndY-10));//Pen.Mode := pmNotXor; Status.Panels[sbpImageSelection].Text := IntToStr(EndX-StartX)+'x'+IntToStr(EndY-StartY); UndoSX:=StartX; UndoSY:=StartY; UndoEX:=EndX; UndoEY:=EndY; end; end; if btnPaint.Down then begin with Image.Picture.Bitmap.Canvas do begin Brush.Style:= bsClear; Pen.Width := btnPenWidth.Tag; Pen.Color := btnPenColor.ButtonColor; Pen.Style := psSolid; tmp:= Pen.Width+10; case TViewerPaintTool(btnPenMode.Tag) of vptPen: LineTo (x,y); vptRectangle, vptEllipse: begin if (startX>x) and (startY<y) then CopyRect (Rect(UndoSX+tmp,UndoSY-tmp,UndoEX-tmp,UndoEY+tmp), tmp_all.canvas,Rect(UndoSX+tmp,UndoSY-tmp,UndoEX-tmp,UndoEY+tmp)); if (startX<x) and (startY>y) then CopyRect (Rect(UndoSX-tmp,UndoSY+tmp,UndoEX+tmp,UndoEY-tmp), tmp_all.canvas,Rect(UndoSX-tmp,UndoSY+tmp,UndoEX+tmp,UndoEY-tmp)); if (startX>x) and (startY>y) then CopyRect (Rect(UndoSX+tmp,UndoSY+tmp,UndoEX-tmp,UndoEY-tmp), tmp_all.canvas,Rect(UndoSX+tmp,UndoSY+tmp,UndoEX-tmp,UndoEY-tmp)) else CopyRect (Rect(UndoSX-tmp,UndoSY-tmp,UndoEX+tmp,UndoEY+tmp), tmp_all.canvas,Rect(UndoSX-tmp,UndoSY-tmp,UndoEX+tmp,UndoEY+tmp));//UndoTmp; case TViewerPaintTool(btnPenMode.Tag) of vptRectangle: Rectangle(Rect(StartX,StartY,X,Y)); vptEllipse:Ellipse(StartX,StartY,X,Y); end; end; end; UndoSX:=StartX; UndoSY:=StartY; UndoEX:=X; UndoEY:=Y; end; end; if not (btnHightlight.Down) and not (btnPaint.Down) then begin sboxImage.VertScrollBar.Position:=sboxImage.VertScrollBar.Position+tmpY-y; sboxImage.HorzScrollBar.Position:=sboxImage.HorzScrollBar.Position+tmpX-x; end; end; end; procedure TfrmViewer.ImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin X:=round(X*Image.Picture.Width/Image.Width); // for correct paint after zoom Y:=round(Y*Image.Picture.Height/Image.Height); MDFlag:=false; if ToolBar1.Visible then begin if (button = mbLeft) and btnHightlight.Down then begin UndoTmp; CheckXY; with Image.Picture.Bitmap.Canvas do begin Brush.Style := bsClear; Pen.Style := psDot; Pen.Color := clHighlight; DrawFocusRect(Rect(StartX,StartY,EndX,EndY)); DrawFocusRect(Rect(StartX+10,StartY+10,EndX-10,EndY-10)); Status.Panels[sbpImageSelection].Text := IntToStr(EndX-StartX)+'x'+IntToStr(EndY-StartY); end; end; end; Image.Cursor:=crDefault; end; procedure TfrmViewer.ImageMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if ssCtrl in Shift then ZoomImage(0.9); end; procedure TfrmViewer.ImageMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if ssCtrl in Shift then ZoomImage(1.1); end; procedure TfrmViewer.miPenClick(Sender: TObject); begin btnPenMode.Tag:= TMenuItem(Sender).Tag; btnPenMode.ImageIndex:= TMenuItem(Sender).ImageIndex; end; procedure TfrmViewer.miLookBookClick(Sender: TObject); begin cm_ShowAsBook(['']); // miLookBook.Checked:=not miLookBook.Checked; end; procedure TfrmViewer.pmEditMenuPopup(Sender: TObject); begin pmiCopyFormatted.Visible:= ViewerControl.Mode in [vcmHex, vcmDec]; end; procedure TfrmViewer.CreatePreview(FullPathToFile: string; index: integer; delete: boolean); var bmpThumb : TBitmap = nil; begin if pnlPreview.Visible or delete then begin if not Assigned(FThumbnailManager) then FThumbnailManager:= TThumbnailManager.Create(DrawPreview.Canvas.Brush.Color); if delete then begin FThumbnailManager.RemovePreview(FullPathToFile); // delete thumb if need if pnlPreview.Visible then begin FileList.Objects[Index].Free; FileList.Objects[Index]:= nil; end; end else begin bmpThumb:= FThumbnailManager.CreatePreview(FullPathToFile); // Insert to the BitmapList FileList.Objects[Index]:= bmpThumb; end; end; end; procedure TfrmViewer.WMCommand(var Message: TLMCommand); var Index: Integer; begin case Message.NotifyCode of itm_center: miCenter.Checked:= Boolean(Message.ItemID); itm_next: begin if Message.ItemID = 0 then cm_LoadNextFile([]); end; itm_wrap: begin gViewerWrapText:= Boolean(Message.ItemID); actWrapText.Checked:= gViewerWrapText; end; itm_fit: begin case Message.ItemID of 0: begin miStretch.Checked:= False; miStretchOnlyLarge.Checked:= False; end; 2, 3: begin miStretch.Checked:= (Message.ItemID = 2); miStretchOnlyLarge.Checked:= (Message.ItemID = 3); end; end; end; itm_fontstyle: begin case Message.ItemID of lcp_ansi: begin FPluginEncoding:= lcp_ansi; Index:= miEncoding.IndexOfCaption(ViewerEncodingsNames[veAnsi]); end; lcp_ascii: begin FPluginEncoding:= lcp_ascii; Index:= miEncoding.IndexOfCaption(ViewerEncodingsNames[veOem]); end; else begin Index:= 0; FPluginEncoding:= 0; end; miEncoding.Items[Index].Checked:= True; ViewerControl.Encoding:= TViewerEncoding(Index); Status.Panels[sbpTextEncoding].Text := rsViewEncoding + ': ' + ViewerControl.EncodingName; end; end; end; end; procedure TfrmViewer.WMSetFocus(var Message: TLMSetFocus); begin if bPlugin then FWlxModule.SetFocus; end; procedure TfrmViewer.CMThemeChanged(var Message: TLMessage); var Highlighter: TSynCustomHighlighter; begin if miCode.Checked then begin Highlighter:= TSynCustomHighlighter(dmHighl.SynHighlighterHashList.Data[SynEdit.Highlighter.LanguageName]); if Assigned(Highlighter) then dmHighl.SetHighlighter(SynEdit, Highlighter); end; end; procedure TfrmViewer.RedEyes; var tmp:TBitMap; x,y,r,g,b: integer; col: TColor; begin if (EndX=StartX) or (EndY=StartY) then Exit; UndoTmp; tmp:=TBitMap.Create; tmp.Width:= EndX-StartX; tmp.Height:= EndY-StartY; for x:=0 to (EndX-StartX) div 2 do begin for y:=0 to (EndY-StartY) div 2 do begin if y<round(sqrt((1-(sqr(x)/sqr((EndX-StartX)/2)))*sqr((EndY-StartY)/2))) then begin col:=Image.Picture.Bitmap.Canvas.Pixels[x+StartX+(EndX-StartX) div 2,y+StartY+(EndY-StartY) div 2]; r:=GetRValue(col); g:=GetGValue(col); b:=GetBValue(col); if (r>100) and (g<100) and (b<100) then r:=b; tmp.Canvas.Pixels[x+(EndX-StartX) div 2,y+(EndY-StartY) div 2]:= rgb(r,g,b); col:=Image.Picture.Bitmap.Canvas.Pixels[StartX-x+(EndX-StartX) div 2,y+StartY+(EndY-StartY) div 2]; r:=GetRValue(col); g:=GetGValue(col); b:=GetBValue(col); if (r>100) and (g<100) and (b<100) then r:=b; tmp.Canvas.Pixels[(EndX-StartX) div 2-x,y+(EndY-StartY) div 2]:= rgb(r,g,b); col:=Image.Picture.Bitmap.Canvas.Pixels[StartX+x+(EndX-StartX) div 2,StartY-y+(EndY-StartY) div 2]; r:=GetRValue(col); g:=GetGValue(col); b:=GetBValue(col); if (r>100) and (g<100) and (b<100) then r:=b; tmp.Canvas.Pixels[(EndX-StartX) div 2+x,(EndY-StartY) div 2-y]:= rgb(r,g,b); col:=Image.Picture.Bitmap.Canvas.Pixels[StartX-x+(EndX-StartX) div 2,StartY-y+(EndY-StartY) div 2]; r:=GetRValue(col); g:=GetGValue(col); b:=GetBValue(col); if (r>100) and (g<100) and (b<100) then r:=b; tmp.Canvas.Pixels[(EndX-StartX) div 2-x,(EndY-StartY) div 2-y]:= rgb(r,g,b); end else begin col:=Image.Picture.Bitmap.Canvas.Pixels[x+StartX+(EndX-StartX) div 2,y+StartY+(EndY-StartY) div 2]; tmp.Canvas.Pixels[x+(EndX-StartX) div 2,y+(EndY-StartY) div 2]:= col; col:=Image.Picture.Bitmap.Canvas.Pixels[StartX-x+(EndX-StartX) div 2,y+StartY+(EndY-StartY) div 2]; tmp.Canvas.Pixels[(EndX-StartX) div 2-x,y+(EndY-StartY) div 2]:= col; col:=Image.Picture.Bitmap.Canvas.Pixels[StartX+x+(EndX-StartX) div 2,StartY-y+(EndY-StartY) div 2]; tmp.Canvas.Pixels[(EndX-StartX) div 2+x,(EndY-StartY) div 2-y]:= col; col:=Image.Picture.Bitmap.Canvas.Pixels[StartX-x+(EndX-StartX) div 2,StartY-y+(EndY-StartY) div 2]; tmp.Canvas.Pixels[(EndX-StartX) div 2-x,(EndY-StartY) div 2-y]:= col; end; end; end; Image.Picture.Bitmap.Canvas.Draw (StartX,StartY,tmp); CreateTmp; tmp.Free; end; procedure TfrmViewer.SynEditCaret; begin if gShowCaret then SynEdit.Options:= SynEdit.Options - [eoNoCaret] else begin SynEdit.Options:= SynEdit.Options + [eoNoCaret]; end; end; procedure TfrmViewer.DeleteCurrentFile; var OldIndex, NewIndex: Integer; begin if (iActiveFile + 1) < FileList.Count then NewIndex := iActiveFile + 1 else begin NewIndex := iActiveFile - 1; end; OldIndex:= iActiveFile; LoadNextFile(NewIndex); CreatePreview(FileList.Strings[OldIndex], OldIndex, True); mbDeleteFile(FileList.Strings[OldIndex]); FileList.Delete(OldIndex); if OldIndex < FileList.Count then iActiveFile := OldIndex else begin iActiveFile := FileList.Count - 1; end; if pnlPreview.Visible then DrawPreview.Index := iActiveFile; actMoveFile.Enabled := FileList.Count > 1; actDeleteFile.Enabled := FileList.Count > 1; DrawPreview.Repaint; SplitterChangeBounds; end; procedure TfrmViewer.EnablePrint(AEnabled: Boolean); begin actPrint.Enabled:= AEnabled; actPrint.Visible:= AEnabled; actPrintSetup.Enabled:= AEnabled; actPrintSetup.Visible:= AEnabled; end; procedure TfrmViewer.EnableActions(AEnabled: Boolean); begin actSave.Enabled:= AEnabled; actCopyFile.Enabled:= AEnabled; actMoveFile.Enabled:= AEnabled and (FileList.Count > 1); actDeleteFile.Enabled:= AEnabled and (FileList.Count > 1); end; procedure TfrmViewer.SavingProperties(Sender: TObject); begin if miFullScreen.Checked then SessionProperties:= EmptyStr; end; procedure TfrmViewer.SetFileName(const AValue: String); begin if actAutoReload.Checked then Status.Panels[sbpFileName].Text:= '* ' + AValue else begin Status.Panels[sbpFileName].Text:= AValue; end; if FFileName <> AValue then begin FFileName:= AValue; MakePluginsMenu; end; UpdatePluginsMenu; end; procedure TfrmViewer.CutToImage; var w,h:integer; begin UndoTmp; with Image.Picture.Bitmap do begin w:=EndX-StartX; h:=EndY-StartY; Canvas.CopyRect(rect(0,0,w,h), Image.Picture.Bitmap.Canvas, rect(startX,StartY,EndX,EndY)); SetSize (w,h); end; Image.Width:=w; Image.Height:=h; CreateTmp; StartX:=0;StartY:=0;EndX:=0;EndY:=0; end; procedure TfrmViewer.UndoTmp; begin Image.Picture.Bitmap.Canvas.Clear; Image.Picture.Bitmap.Canvas.Draw(0,0,tmp_all); end; procedure TfrmViewer.CreateTmp; begin tmp_all.Free; tmp_all:= TBitmap.Create; tmp_all.Assign(Image.Picture.Graphic); end; procedure TfrmViewer.CheckXY; var tmp: integer; begin if EndX<StartX then begin tmp:=StartX; StartX:=EndX; EndX:=tmp end; if EndY<StartY then begin tmp:=StartY; StartY:=EndY; EndY:=tmp end; end; procedure TfrmViewer.Res (W, H: integer); var tmp: TCustomBitmap; r: TRect; begin if btnHightlight.Down then UndoTmp; tmp:= TBitmap.Create; tmp.Assign(Image.Picture.Graphic); r := Rect(0, 0, W, H); Image.Picture.Bitmap.SetSize(W,H); Image.Picture.Bitmap.Canvas.Clear; Image.Picture.Bitmap.Canvas.StretchDraw(r, tmp); tmp.free; CreateTmp; StartX:=0; StartY:=0; EndX:=0; EndY:=0; end; function TfrmViewer.PluginShowFlags : Integer; begin Result:= FPluginEncoding or IfThen(miWrapText.Checked, lcp_wraptext, 0) or IfThen(miStretch.Checked, lcp_fittowindow, 0) or IfThen(miCenter.Checked, lcp_center, 0) or IfThen(miStretchOnlyLarge.Checked, lcp_fittowindow or lcp_fitlargeronly, 0) end; function TfrmViewer.CheckPlugins(const sFileName: String; bForce: Boolean = False): Boolean; var I, J: Integer; AFileName: String; ShowFlags: Integer; Start, Finish: Integer; begin AFileName:= ExcludeTrailingBackslash(sFileName); ShowFlags:= IfThen(bForce, lcp_forceshow, 0) or PluginShowFlags; // DCDebug('WlXPlugins.Count = ' + IntToStr(WlxPlugins.Count)); for J := 1 to 2 do begin // Find after active plugin if (J = 1) then begin Start := ActivePlugin + 1; Finish := WlxPlugins.Count - 1; end // Find before active plugin else begin Start := 0; Finish := ActivePlugin; end; for I:= Start to Finish do begin if WlxPlugins.GetWlxModule(I).FileParamVSDetectStr(AFileName, bForce) then begin if LoadPlugin(AFileName, I, ShowFlags) then Exit(True); end; end; end; // Plugin not found ActivePlugin:= -1; FWlxModule:= nil; Result:= False; end; procedure TfrmViewer.ExitPluginMode; begin if Assigned(FWlxModule) then begin FWlxModule.CallListCloseWindow; end; bPlugin:= False; FWlxModule:= nil; ActivePlugin:= -1; UpdatePluginsMenu; EnablePrint(False); end; procedure TfrmViewer.ExitQuickView; begin ExitPluginMode; gImageStretch:= miStretch.Checked; gImageStretchOnlyLarge:= miStretchOnlyLarge.Checked; gImageCenter:= miCenter.Checked; end; procedure TfrmViewer.ShowTextViewer(AMode: TViewerControlMode); begin ExitPluginMode; ReopenAsTextIfNeeded; ViewerControl.Mode:= AMode; if ViewerControl.Mode = vcmBook then begin with ViewerControl, gColors.Viewer^ do begin Color:= BookBackgroundColor; Font.Color:= BookFontColor; ColCount:= gColCount; Position:= gTextPosition; end; FontOptionsToFont(gFonts[dcfViewerBook], ViewerControl.Font); end else begin with ViewerControl do begin Color:= clWindow; Font.Color:= clWindowText; ColCount:= 1; end; FontOptionsToFont(gFonts[dcfViewer], ViewerControl.Font); end; ActivatePanel(pnlText); end; procedure TfrmViewer.CopyMoveFile(AViewerAction: TViewerCopyMoveAction); begin FModSizeDialog:= TfrmModView.Create(Self); try FModSizeDialog.pnlQuality.Visible:= False; FModSizeDialog.pnlSize.Visible:= False; FModSizeDialog.pnlCopyMoveFile.Visible:= True; if AViewerAction = vcmaMove then FModSizeDialog.Caption:= rsDlgMv else FModSizeDialog.Caption:= rsDlgCp; if FModSizeDialog.ShowModal = mrOk then begin if FModSizeDialog.Path = '' then msgError(rsMsgInvalidPath) else begin CopyFile(FileList.Strings[iActiveFile],FModSizeDialog.Path+PathDelim+ExtractFileName(FileList.Strings[iActiveFile])); if AViewerAction = vcmaMove then begin DeleteCurrentFile; end; end; end; finally FreeAndNil(FModSizeDialog); end; end; procedure TfrmViewer.ZoomImage(ADelta: Double); begin FZoomFactor := Round(FZoomFactor * ADelta); AdjustImageSize; end; procedure TfrmViewer.RotateImage(AGradus: integer); // AGradus now supported only 90,180,270 values var x, y: Integer; xWidth, yHeight: Integer; SourceImg: TLazIntfImage = nil; TargetImg: TLazIntfImage = nil; begin TargetImg:= TLazIntfImage.Create(0, 0); SourceImg:= Image.Picture.Bitmap.CreateIntfImage; TargetImg.DataDescription:= SourceImg.DataDescription; // use the same image format xWidth:= Image.Picture.Bitmap.Width - 1; yHeight:= Image.Picture.Bitmap.Height - 1; if AGradus = 90 then begin TargetImg.SetSize(yHeight + 1, xWidth + 1); for y:= 0 to xWidth do begin for x:= 0 to yHeight do begin TargetImg.Colors[x, y]:= SourceImg.Colors[y, yHeight - x]; end; end; x:= Image.Width; Image.Width:= Image.Height; Image.Height:= x; end; if AGradus = 180 then begin TargetImg.SetSize(xWidth + 1, yHeight + 1); for y:= 0 to yHeight do begin for x:= 0 to xWidth do begin TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - x, yHeight - y]; end; end; end; if AGradus = 270 then begin TargetImg.SetSize(yHeight + 1, xWidth + 1); for y:= 0 to xWidth do begin for x:= 0 to yHeight do begin TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - y, x]; end; end; x:= Image.Width; Image.Width:= Image.Height; Image.Height:= x; end; Image.Picture.Bitmap.LoadFromIntfImage(TargetImg); FreeAndNil(SourceImg); FreeAndNil(TargetImg); AdjustImageSize; CreateTmp; end; procedure TfrmViewer.MirrorImage(AVertically:boolean); var x, y: Integer; xWidth, yHeight: Integer; SourceImg: TLazIntfImage = nil; TargetImg: TLazIntfImage = nil; begin TargetImg:= TLazIntfImage.Create(0, 0); SourceImg:= Image.Picture.Bitmap.CreateIntfImage; TargetImg.DataDescription:= SourceImg.DataDescription; // use the same image format xWidth:= Image.Picture.Bitmap.Width - 1; yHeight:= Image.Picture.Bitmap.Height - 1; TargetImg.SetSize(xWidth + 1, yHeight + 1); if not AVertically then for y:= 0 to yHeight do begin for x:= 0 to xWidth do begin TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - x, y]; end; end else for y:= 0 to yHeight do begin for x:= 0 to xWidth do begin TargetImg.Colors[x, y]:= SourceImg.Colors[ x,yHeight - y]; end; end; Image.Picture.Bitmap.LoadFromIntfImage(TargetImg); FreeAndNil(SourceImg); FreeAndNil(TargetImg); AdjustImageSize; CreateTmp; end; procedure TfrmViewer.SaveImageAs(var sExt: String; senderSave: boolean; Quality: integer); var sFileName: String; fsFileStream: TFileStreamEx; begin if senderSave then begin sExt:= LowerCase(sExt); sFileName:= FileList.Strings[iActiveFile]; end else begin with SavePictureDialog do begin FileName:= EmptyStr; InitialDir:= ExtractFileDir(FileList.Strings[iActiveFile]); if not Execute then Exit; sExt:= ExtensionSeparator + GetFilterExt; sFileName:= ChangeFileExt(FileName, sExt); end; if (sExt = '.jpg') or (sExt = '.jpeg') then begin FModSizeDialog:= TfrmModView.Create(Self); try FModSizeDialog.pnlSize.Visible:= False; FModSizeDialog.pnlCopyMoveFile.Visible:= False; FModSizeDialog.pnlQuality.Visible:= True; FModSizeDialog.Caption:= SavePictureDialog.Title; if FModSizeDialog.ShowModal <> mrOk then Exit; Quality:= FModSizeDialog.teQuality.Value; finally FreeAndNil(FModSizeDialog); end; end; end; try fsFileStream:= TFileStreamEx.Create(sFileName, fmCreate); try if (sExt = '.jpg') or (sExt = '.jpeg') then begin with TJpegImage.Create do try // Special case if Image.Picture.Graphic is TJPEGImage then begin LoadFromRawImage(Image.Picture.Jpeg.RawImage, False); end else begin Assign(Image.Picture.Graphic); end; CompressionQuality := Quality; SaveToStream(fsFileStream); finally Free; end; end else if sExt = '.ico' then begin with TIcon.Create do try Assign(Image.Picture.Graphic); SaveToStream(fsFileStream); finally Free; end; end else begin Image.Picture.SaveToStreamWithFileExt(fsFileStream, sExt); end; finally FreeAndNil(fsFileStream); end; except on E: Exception do msgError(E.Message); end; end; procedure TfrmViewer.ImagePaintBackground(ASender: TObject; ACanvas: TCanvas; ARect: TRect); const CELL_SIZE = 8; var X, Y: Integer; begin with gColors.Viewer^ do begin if ImageBackColor2 = clDefault then ACanvas.Brush.Color:= ContrastColor(sboxImage.Color, 30) else begin ACanvas.Brush.Color:= ImageBackColor2; end; end; for Y:= 0 to (ARect.Height div CELL_SIZE) + 1 do begin for X:= 0 to (ARect.Width div CELL_SIZE) + 1 do begin if Odd(X) <> Odd(Y) then begin ACanvas.FillRect(X * CELL_SIZE, Y * CELL_SIZE, (X + 1) * CELL_SIZE, (Y + 1) * CELL_SIZE); end; end; end; end; procedure TfrmViewer.pnlImageResize(Sender: TObject); begin if bImage then AdjustImageSize; end; procedure TfrmViewer.miPluginsClick(Sender: TObject); var ShowFlags: Integer; MenuItem: TMenuItem absolute Sender; begin ExitPluginMode; ShowFlags:= PluginShowFlags or lcp_forceshow; if LoadPlugin(FFileName, MenuItem.Tag, ShowFlags) then begin ActivatePanel(nil); end else begin LoadFile(FFileName); end; end; procedure TfrmViewer.pnlTextMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if Shift=[ssCtrl] then begin gFonts[dcfMain].Size:=gFonts[dcfMain].Size+1; pnlText.Font.Size:=gFonts[dcfMain].Size; pnlText.Repaint; Handled:=True; Exit; end; end; procedure TfrmViewer.sboxImageMouseEnter(Sender: TObject); begin if miFullScreen.Checked then TimerViewer.Enabled:=true; end; procedure TfrmViewer.sboxImageMouseLeave(Sender: TObject); begin if miFullScreen.Checked then TimerViewer.Enabled:=false; end; procedure TfrmViewer.sboxImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if miFullScreen.Checked then begin sboxImage.Cursor:=crDefault; Image.Cursor:=crDefault; i_timer:=0; end; end; procedure TfrmViewer.btnNextGifFrameClick(Sender: TObject); begin GifAnim.Animate:=false; GifAnim.NextFrame; end; procedure TfrmViewer.SplitterChangeBounds; begin if DrawPreview.Width div (DrawPreview.DefaultColWidth+6)>0 then DrawPreview.ColCount:= DrawPreview.Width div (DrawPreview.DefaultColWidth + 6); if FileList.Count mod DrawPreview.ColCount > 0 then DrawPreview.RowCount:= FileList.Count div DrawPreview.ColCount + 1 else DrawPreview.RowCount:= FileList.Count div DrawPreview.ColCount; if bPlugin then FWlxModule.ResizeWindow(GetListerRect); end; procedure TfrmViewer.TimerReloadTimer(Sender: TObject); var NewSize: Int64; begin if ViewerControl.IsFileOpen then begin if ViewerControl.FileHandle <> 0 then NewSize:= FileGetSize(ViewerControl.FileHandle) else begin NewSize:= mbFileSize(ViewerControl.FileName); end; if (NewSize <> ViewerControl.FileSize) then begin Screen.BeginWaitCursor; try ViewerControl.FileName := ViewerControl.FileName; ViewerControl.Enabled := Self.Active; try ActivatePanel(pnlText); finally ViewerControl.Enabled := True; end; FLastSearchPos := -1; ViewerControl.GoEnd; finally Screen.EndWaitCursor; end; end; end; end; procedure TfrmViewer.TimerScreenshotTimer(Sender: TObject); begin cm_Screenshot(['']); TimerScreenshot.Enabled:=False; Application.Restore; Self.BringToFront; end; procedure TfrmViewer.DrawPreviewDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var ATextSize: TSize; sFileName: String; bmpThumb: TBitmap; Index, X, Y: Integer; begin LCLIntf.InflateRect(aRect, -2, -2); // Calculate FileList index Index:= (aRow * DrawPreview.ColCount) + aCol; if (Index >= 0) and (Index < FileList.Count) then begin DrawPreview.Canvas.FillRect(aRect); bmpThumb:= TBitmap(FileList.Objects[Index]); sFileName:= ExtractFileName(FileList.Strings[Index]); sFileName:= FitOtherCellText(sFileName, DrawPreview.Canvas, aRect.Width); ATextSize:= DrawPreview.Canvas.TextExtent(sFileName); if Assigned(bmpThumb) then begin // Draw thumbnail at center X:= aRect.Left + (aRect.Width - bmpThumb.Width) div 2; Y:= aRect.Top + (aRect.Height - bmpThumb.Height - ATextSize.Height - 4) div 2; DrawPreview.Canvas.Draw(X, Y, bmpThumb); end; // Draw file name at center Y:= (aRect.Bottom - ATextSize.Height) - 2; X:= aRect.Left + (aRect.Width - ATextSize.Width) div 2; DrawPreview.Canvas.TextOut(X, Y, sFileName); end; end; procedure TfrmViewer.DrawPreviewSelection(Sender: TObject; aCol, aRow: Integer); begin LoadNextFile(DrawPreview.Index); end; procedure TfrmViewer.DrawPreviewTopleftChanged(Sender: TObject); begin DrawPreview.LeftCol:= 0; end; procedure TfrmViewer.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin TThumbThread.Finish(FThread); end; procedure TfrmViewer.TimerViewerTimer(Sender: TObject); begin if (miFullScreen.Checked) then begin if (ToolBar1.Visible) and (i_timer > 60) and (not ToolBar1.MouseInClient) then begin ToolBar1.Visible:= False; AdjustImageSize; end else if (not ToolBar1.Visible) and (sboxImage.ScreenToClient(Mouse.CursorPos).Y < ToolBar1.Height div 2) then begin ToolBar1.Visible:= True; AdjustImageSize; end; end; Inc(i_timer); if (btnSlideShow.Down) and (i_timer = 60 * btnSlideShow.Tag) then begin if (ToolBar1.Visible) and (not ToolBar1.MouseInClient) then begin ToolBar1.Visible:= False; AdjustImageSize; end; cm_LoadNextFile([]); i_timer:= 0; end; if i_timer = 180 then begin sboxImage.Cursor:= crNone; Image.Cursor:= crNone; end; end; procedure TfrmViewer.ViewerControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbRight then pmEditMenu.PopUp(); end; procedure TfrmViewer.frmViewerClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction:=caFree; gImageStretch:= miStretch.Checked; gImageStretchOnlyLarge:= miStretchOnlyLarge.Checked; gImageShowTransparency:= actShowTransparency.Checked; gImageCenter:= miCenter.Checked; gPreviewVisible := miPreview.Checked; gImagePaintMode := TViewerPaintTool(btnPenMode.Tag); gImagePaintWidth := btnPenWidth.Tag; gImagePaintColor := btnPenColor.ButtonColor; case ViewerControl.Mode of vcmText: gViewerMode := 1; vcmWrap: gViewerMode := 1; vcmBin : gViewerMode := 2; vcmHex : gViewerMode := 3; vcmDec : gViewerMode := 6; vcmBook: gTextPosition := ViewerControl.Position; end; if Assigned(WlxPlugins) then ExitPluginMode; {$IF NOT DEFINED(LCLWIN32)} if WindowState = wsFullScreen then WindowState:= wsNormal; {$ENDIF} end; procedure TfrmViewer.UpdateImagePlacement; begin if bPlugin then FWlxModule.CallListSendCommand(lc_newparams , PluginShowFlags) else if bImage then begin if btnHightlight.Down then begin btnPaint.Down:=false; btnHightlight.Down:=false; //gboxView.Visible:=true; UndoTmp; end; AdjustImageSize; end; end; procedure TfrmViewer.FormCreate(Sender: TObject); var Index: Integer; HMViewer: THMForm; MenuItem: TMenuItem; begin if not bQuickView then begin with InitPropStorage(Self) do OnSavingProperties:= @SavingProperties; end else begin miDiv4.Visible:= False; actPreview.Enabled:= False; actPreview.Visible:= False; actScreenshot.Enabled:= False; actFullscreen.Enabled:= False; actScreenShotDelay3Sec.Enabled:= False; actScreenShotDelay5Sec.Enabled:= False; Status.PopupMenu:= pmStatusBar; MainMenu.Items.Remove(miView); MainMenu.Items.Remove(mnuPlugins); MainMenu.Items.Remove(miEncoding); MainMenu.Items.Remove(miImage); pmStatusBar.Items.Add(miView); pmStatusBar.Items.Add(mnuPlugins); pmStatusBar.Items.Add(miEncoding); pmStatusBar.Items.Add(miImage); end; actExitViewer.Enabled:= not bQuickView; HMViewer := HotMan.Register(Self, HotkeysCategory); HMViewer.RegisterActionList(actionList); ViewerControl.OnFileOpen:= @FileOpenUAC; ViewerControl.OnGuessEncoding:= @DetectEncoding; FontOptionsToFont(gFonts[dcfViewer], ViewerControl.Font); FileList := TStringList.Create; FileList.OwnsObjects:= True; WlxPlugins:=TWLXModuleList.Create; WlxPlugins.Assign(gWLXPlugins); FFindDialog:= nil; // dialog is created in first use sboxImage.DoubleBuffered := True; miStretch.Checked := gImageStretch; sboxImage.Color := gColors.Viewer^.ImageBackColor1; miStretchOnlyLarge.Checked := gImageStretchOnlyLarge; miCenter.Checked := gImageCenter; miPreview.Checked := gPreviewVisible; btnPenMode.Tag := Integer(gImagePaintMode); btnPenWidth.Tag := gImagePaintWidth; btnPenColor.ButtonColor := gImagePaintColor; if gImageShowTransparency then begin Image.OnPaintBackground:= @ImagePaintBackground; actShowTransparency.Checked := gImageShowTransparency; end; Image.Stretch:= True; Image.AutoSize:= False; Image.Proportional:= False; Image.SetBounds(0, 0, sboxImage.ClientWidth, sboxImage.ClientHeight); FThumbSize := gThumbSize; DrawPreview.DefaultColWidth := FThumbSize.cx + 4; DrawPreview.DefaultRowHeight := FThumbSize.cy + DrawPreview.Canvas.TextHeight('Pp') + 6; MakeTextEncodingsMenu; Status.Panels[sbpFileNr].Alignment := taRightJustify; Status.Panels[sbpPosition].Alignment := taRightJustify; Status.Panels[sbpFileSize].Alignment := taRightJustify; ViewerPositionChanged(Self); FixFormIcon(Handle); GifAnim.Align:=alClient; for Index:= 1 to 25 do begin MenuItem:= TMenuItem.Create(btnPenWidth); MenuItem.Caption:= IntToStr(Index); MenuItem.OnClick:= @miPaintClick; MenuItem.Tag:= Index; pmPenWidth.Items.Add(MenuItem); MenuItem:= TMenuItem.Create(btnSlideShow); MenuItem.Caption:= IntToStr(Index); MenuItem.OnClick:= @miPaintClick; MenuItem.Tag:= Index; pmTimeShow.Items.Add(MenuItem); end; // SynEdit FSearchOptions.Flags := [ssoEntireScope]; HotMan.Register(pnlText ,'Text files'); HotMan.Register(pnlImage,'Image files'); SavePictureDialog.Filter:= GraphicFilter(TPortableNetworkGraphic) + '|' + GraphicFilter(TBitmap) + '|' + GraphicFilter(TJPEGImage) + '|' + GraphicFilter(TIcon) + '|' + GraphicFilter(TPortableAnyMapGraphic); end; procedure TfrmViewer.FormKeyPress(Sender: TObject; var Key: Char); begin // The following keys work only in QuickView mode because there is no menu there. // Otherwise this function is never called for those keys // because the menu shortcuts are automatically used. if bQuickView then case Key of 'N', 'n': begin cm_LoadNextFile([]); Key := #0; end; 'P', 'p': begin cm_LoadPrevFile([]); Key := #0; end; '1': begin cm_ShowAsText(['']); Key := #0; end; '2': begin cm_ShowAsBin(['']); Key := #0; end; '3': begin cm_ShowAsHex(['']); Key := #0; end; '4': begin cm_ShowAsDec(['']); Key := #0; end; '6': begin cm_ShowGraphics(['']); Key := #0; end; '7': begin cm_ShowPlugins(['']); Key := #0; end; '8': begin cm_ShowOffice(['']); Key := #0; end; end; end; procedure TfrmViewer.btnCutTuImageClick(Sender: TObject); begin CutToImage; end; procedure TfrmViewer.actExecute(Sender: TObject); var cmd: string; begin cmd := (Sender as TAction).Name; cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3); Commands.ExecuteCommand(cmd, []); end; procedure TfrmViewer.btnFullScreenClick(Sender: TObject); begin cm_Fullscreen(['']); end; procedure TfrmViewer.btnGifMoveClick(Sender: TObject); begin GifAnim.Animate:=not GifAnim.Animate; btnNextGifFrame.Enabled:= not GifAnim.Animate; btnPrevGifFrame.Enabled:= not GifAnim.Animate; if GifAnim.Animate then btnGifMove.ImageIndex:= 11 else begin btnGifMove.ImageIndex:= 12 end; end; procedure TfrmViewer.btnGifToBmpClick(Sender: TObject); begin GifAnim.Animate:=False; Image.Picture.Bitmap.Create; Image.Picture.Bitmap.Width := GifAnim.Width; Image.Picture.Bitmap.Height := GifAnim.Height; Image.Picture.Bitmap.Canvas.CopyRect(Rect(0,0,GifAnim.Width,GifAnim.Height),GifAnim.Canvas,Rect(0,0,GifAnim.Width,GifAnim.Height)); cm_SaveAs(['']); end; procedure TfrmViewer.btnPaintHightlight(Sender: TObject); var bmp: TCustomBitmap = nil; GraphicClass: TGraphicClass; sExt: String; fsFileStream: TFileStreamEx = nil; begin if not ImgEdit then begin try sExt:= ExtractFileExt(FileList.Strings[iActiveFile]); fsFileStream:= TFileStreamEx.Create(FileList.Strings[iActiveFile], fmOpenRead or fmShareDenyNone); GraphicClass := GetGraphicClassForFileExtension(sExt); if (GraphicClass <> nil) and (GraphicClass.InheritsFrom(TCustomBitmap)) then begin Image.DisableAutoSizing; bmp := TCustomBitmap(GraphicClass.Create); bmp.LoadFromStream(fsFileStream); Image.Picture.Bitmap := TBitmap.Create; Image.Picture.Bitmap.Height:= bmp.Height; Image.Picture.Bitmap.Width:= bmp.Width; Image.Picture.Bitmap.Canvas.Draw(0, 0, bmp); Image.EnableAutoSizing; end; finally FreeAndNil(bmp); FreeAndNil(fsFileStream); end; {miStretch.Checked:= False; Image.Stretch:= miStretch.Checked; Image.Proportional:= Image.Stretch; Image.Autosize:= not(miStretch.Checked); AdjustImageSize; } end; if Sender = btnHightlight then begin //btnHightlight.Down := not (btnHightlight.Down); btnPaint.Down:= False; if not btnHightlight.Down then UndoTmp; end else begin if btnHightlight.Down then UndoTmp; // btnPaint.Down:= not (btnPaint.Down); btnHightlight.Down:= False; end; btnCutTuImage.Enabled:= btnHightlight.Down; btnRedEye.Enabled:= btnHightlight.Down; actUndo.Enabled:= btnPaint.Down; btnPenMode.Enabled:= btnPaint.Down; btnPenWidth.Enabled:= btnPaint.Down; btnPenColor.Enabled:= btnPaint.Down; ImgEdit:= True; CreateTmp; end; procedure TfrmViewer.btnPenModeClick(Sender: TObject); begin btnPenMode.Down:= not btnPenMode.Down; end; procedure TfrmViewer.btnPrevGifFrameClick(Sender: TObject); begin GifAnim.Animate:=False; GifAnim.PriorFrame; end; procedure TfrmViewer.btnRedEyeClick(Sender: TObject); begin RedEyes; end; procedure TfrmViewer.btnResizeClick(Sender: TObject); begin FModSizeDialog:= TfrmModView.Create(Self); try FModSizeDialog.pnlQuality.Visible:=false; FModSizeDialog.pnlCopyMoveFile.Visible :=false; FModSizeDialog.pnlSize.Visible:=true; FModSizeDialog.teHeight.Text:= IntToStr(Image.Picture.Bitmap.Height); FModSizeDialog.teWidth.Text := IntToStr(Image.Picture.Bitmap.Width); FModSizeDialog.Caption:= rsViewNewSize; if FModSizeDialog.ShowModal = mrOk then begin Res(StrToInt(FModSizeDialog.teWidth.Text), StrToInt(FModSizeDialog.teHeight.Text)); AdjustImageSize; end; finally FreeAndNil(FModSizeDialog); end; end; procedure TfrmViewer.btnSlideShowClick(Sender: TObject); begin btnSlideShow.Down:= not btnSlideShow.Down; end; procedure TfrmViewer.FormDestroy(Sender: TObject); begin if Assigned(HotMan) then begin HotMan.UnRegister(pnlText); HotMan.UnRegister(pnlImage); end; FreeAndNil(FFindDialog); HotMan.UnRegister(Self); end; procedure TfrmViewer.miPaintClick(Sender: TObject); var MenuItem: TMenuItem absolute Sender; begin MenuItem.Owner.Tag:= MenuItem.Tag; TToolButton(MenuItem.Owner).Caption:= MenuItem.Caption; end; procedure TfrmViewer.ReopenAsTextIfNeeded; begin if bImage or bAnimation or bPlugin or miPlugins.Checked or miOffice.Checked or miCode.Checked then begin Image.Picture := nil; ViewerControl.FileName := FileList.Strings[iActiveFile]; ActivatePanel(pnlText); end; end; procedure TfrmViewer.UpdatePluginsMenu; var I: Integer; begin for I:= mnuPlugins.Count - 1 downto 0 do begin if mnuPlugins.Items[I].Tag = ActivePlugin then begin mnuPlugins.Items[I].Checked:= True; Exit; end; end; end; procedure TfrmViewer.MakePluginsMenu; var I, J: Integer; MenuItem: TMenuItem; WlxModule: TWlxModule; begin J:= 1; mnuPlugins.Clear; MenuItem:= TMenuItem.Create(mnuPlugins); MenuItem.Caption:= rsDlgButtonNone; MenuItem.RadioItem:= True; MenuItem.Enabled:= False; MenuItem.Checked:= True; MenuItem.GroupIndex:= 2; MenuItem.Tag:= -1; mnuPlugins.Add(MenuItem); for I:= 0 to WlxPlugins.Count - 1 do begin WlxModule:= WlxPlugins.GetWlxModule(I); if not WlxModule.Enabled then Continue; MenuItem:= TMenuItem.Create(mnuPlugins); MenuItem.RadioItem:= True; MenuItem.GroupIndex:= 2; MenuItem.Tag:= I; MenuItem.OnClick:= @miPluginsClick; MenuItem.Caption:= ExtractOnlyFileName(WlxModule.FileName); if WlxModule.FileParamVSDetectStr(FFileName, True) then begin mnuPlugins.Insert(J, MenuItem); Inc(J); end else begin mnuPlugins.Add(MenuItem); end; if ActivePlugin = I then begin MenuItem.Checked:= True; end; end; if (J > 1) and (J < mnuPlugins.Count) then begin MenuItem:= TMenuItem.Create(mnuPlugins); MenuItem.Caption:= '-'; mnuPlugins.Insert(J, MenuItem); end; mnuPlugins.Visible:= (mnuPlugins.Count > 1); end; procedure TfrmViewer.miChangeEncodingClick(Sender: TObject); begin cm_ChangeEncoding([(Sender as TMenuItem).Caption]); end; procedure TfrmViewer.SynEditStatusChange(Sender: TObject; Changes: TSynStatusChanges); begin Status.Panels[sbpPosition].Text:= Format('%d:%d', [SynEdit.CaretX, SynEdit.CaretY]); end; procedure TfrmViewer.SynEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (not gShowCaret) and (Key in [VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_LEFT, VK_RIGHT]) then begin case Key of VK_UP: SynEdit.Perform(WM_VSCROLL, SB_LINEUP, 0); VK_DOWN: SynEdit.Perform(WM_VSCROLL, SB_LINEDOWN, 0); VK_PRIOR: SynEdit.Perform(WM_VSCROLL, SB_PAGEUP, 0); VK_NEXT: SynEdit.Perform(WM_VSCROLL, SB_PAGEDOWN, 0); VK_LEFT: SynEdit.Perform(WM_HSCROLL, SB_LINELEFT, 0); VK_RIGHT: SynEdit.Perform(WM_HSCROLL, SB_LINERIGHT, 0); end; Key:= 0; end; end; procedure TfrmViewer.SynEditMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); var ALine: Integer; begin if (Shift = [ssCtrl]) then begin if (WheelDelta > 0) and (gFonts[dcfViewer].Size < gFonts[dcfViewer].MaxValue) then begin Handled:= True; Inc(gFonts[dcfViewer].Size); end else if (WheelDelta < 0) and (gFonts[dcfViewer].Size > gFonts[dcfViewer].MinValue) then begin Handled:= True; Dec(gFonts[dcfViewer].Size); end; if Handled then begin ALine:= SynEdit.TopLine; FontOptionsToFont(gFonts[dcfViewer], SynEdit.Font); SynEdit.TopLine:= ALine; SynEdit.Refresh; end; end; end; procedure TfrmViewer.ViewerControlMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (Shift=[ssCtrl])and(gFonts[dcfViewer].Size > gFonts[dcfViewer].MinValue) then begin gFonts[dcfViewer].Size:=gFonts[dcfViewer].Size-1; ViewerControl.Font.Size:=gFonts[dcfViewer].Size; ViewerControl.Repaint; Handled:=True; Exit; end; end; procedure TfrmViewer.ViewerControlMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin if (Shift=[ssCtrl])and(gFonts[dcfViewer].Size < gFonts[dcfViewer].MaxValue) then begin gFonts[dcfViewer].Size:=gFonts[dcfViewer].Size+1; ViewerControl.Font.Size:=gFonts[dcfViewer].Size; ViewerControl.Repaint; Handled:=True; Exit; end; end; function TfrmViewer.CheckGraphics(const sFileName:String):Boolean; var sExt: String; begin sExt:= LowerCase(ExtractFileExt(sFileName)); Result:= Image.Picture.FindGraphicClassWithFileExt(sExt, False) <> nil; end; // Adjust Image size (width and height) to sboxImage size procedure TfrmViewer.AdjustImageSize; const fmtImageInfo = '%dx%d (%.0f %%)'; var dScaleFactor : Double; iLeft, iTop, iWidth, iHeight : Integer; begin if (Image.Picture = nil) then Exit; if (Image.Picture.Width = 0) or (Image.Picture.Height = 0) then Exit; dScaleFactor:= FZoomFactor / 100; // Place and resize image if (FZoomFactor = 100) and (miStretch.Checked or miStretchOnlyLarge.Checked) then begin dScaleFactor:= Min(sboxImage.ClientWidth / Image.Picture.Width ,sboxImage.ClientHeight / Image.Picture.Height); dScaleFactor:= IfThen((miStretchOnlyLarge.Checked) and (dScaleFactor > 1.0), 1.0, dScaleFactor); end; iWidth:= Trunc(Image.Picture.Width * dScaleFactor); iHeight:= Trunc(Image.Picture.Height * dScaleFactor); if (miCenter.Checked) then begin iLeft:= (sboxImage.ClientWidth - iWidth) div 2; iTop:= (sboxImage.ClientHeight - iHeight) div 2; end else begin iLeft:= 0; iTop:= 0; end; Image.SetBounds(Max(iLeft,0), Max(iTop,0), iWidth , iHeight); // Update scrollbars // TODO: fix - calculations are correct but it seems like scroll bars // are being updated only after a second call to Form.Resize if sboxImage.HandleAllocated then begin if (iLeft < 0) then sboxImage.HorzScrollBar.Position:= -iLeft; if (iTop < 0) then sboxImage.VertScrollBar.Position:= -iTop; end; // Update status bar Status.Panels[sbpCurrentResolution].Text:= Format(fmtImageInfo, [iWidth,iHeight, 100.0 * dScaleFactor]); Status.Panels[sbpFullResolution].Text:= Format(fmtImageInfo, [Image.Picture.Width,Image.Picture.Height, 100.0]); end; function TfrmViewer.GetListerRect: TRect; begin Result:= ClientRect; Dec(Result.Bottom, Status.Height); if Splitter.Visible then begin Inc(Result.Left, Splitter.Left + Splitter.Width); end; end; function TfrmViewer.CheckOffice(const sFileName: String): Boolean; var AText: String; begin Result:= OfficeMask.Matches(sFileName) and LoadFromOffice(sFileName, AText); if Result then begin ViewerControl.Text:= AText; ViewerControl.Mode:= WRAP_MODE[gViewerWrapText]; ViewerControl.Encoding:= veUtf8; end; end; function TfrmViewer.CheckSynEdit(const sFileName: String; bForce: Boolean = False): Boolean; var AFile: TFile; ATemplate: TSearchTemplate; begin if bForce then Result:= True else if (Length(gViewerSynEditMask) = 0) then Result:= False else if not IsMaskSearchTemplate(gViewerSynEditMask) then begin Result:= MatchesMaskList(sFileName, gViewerSynEditMask); end else try ATemplate:= gSearchTemplateList.TemplateByName[gViewerSynEditMask]; if (ATemplate = nil) then Result:= False else begin AFile:= TFileSystemFileSource.CreateFileFromFile(sFileName); try Result:= ATemplate.CheckFile(AFile); finally AFile.Free; end; end; except Exit(False); end; if Result and not bForce then begin if (mbFileSize(sFileName) > (gMaxCodeSize * $100000)) then Exit(False); end; if Result then begin FHighlighter:= GetHighlighterFromFileExt(dmHighl.SynHighlighterList, ExtractFileExt(sFileName)); Result:= Assigned(FHighlighter); end; if Result and not bForce then begin PushPop(FElevate); try Result:= mbFileIsText(sFileName); finally PushPop(FElevate); end; end; end; function TfrmViewer.LoadGraphics(const sFileName:String): Boolean; procedure UpdateToolbar(bImage: Boolean); begin btnHightlight.Enabled:= bImage and (not miFullScreen.Checked); btnPaint.Enabled:= bImage and (not miFullScreen.Checked); btnResize.Enabled:= bImage and (not miFullScreen.Checked); miImage.Visible:= bImage; btnZoomIn.Enabled:= bImage; btnZoomOut.Enabled:= bImage; btn270.Enabled:= bImage; btn90.Enabled:= bImage; btnMirror.Enabled:= bImage; btnZoomSeparator.Enabled:= bImage; btnGifMove.Enabled:= not bImage; btnGifToBmp.Enabled:= not bImage; btnGifSeparator.Enabled:= not bImage; btnNextGifFrame.Enabled:= not bImage; btnPrevGifFrame.Enabled:= not bImage; end; var sExt: String; fsFileHandle: System.THandle; fsFileStream: TFileStreamEx = nil; gifHeader: array[0..5] of AnsiChar; begin Result:= True; FZoomFactor:= 100; sExt:= ExtractOnlyFileExt(sFilename); if SameText(sExt, 'gif') then begin fsFileHandle:= mbFileOpen(sFileName, fmOpenRead or fmShareDenyNone); if (fsFileHandle = feInvalidHandle) then Exit(False); FileRead(fsFileHandle, gifHeader, SizeOf(gifHeader)); FileClose(fsFileHandle); end; // GifAnim supports only GIF89a if gifHeader <> 'GIF89a' then begin Image.Visible:= True; GifAnim.Visible:= False; try fsFileStream:= TFileStreamEx.Create(sFileName, fmOpenRead or fmShareDenyNone); try Image.Picture.LoadFromStreamWithFileExt(fsFileStream, sExt); {$IF DEFINED(LCLGTK2)} // TImage crash on displaying monochrome bitmap on Linux/GTK2 // https://doublecmd.sourceforge.io/mantisbt/view.php?id=2474 // http://bugs.freepascal.org/view.php?id=12362 if Image.Picture.Graphic is TRasterImage then begin if TRasterImage(Image.Picture.Graphic).RawImage.Description.BitsPerPixel = 1 then begin BitmapConvert(TRasterImage(Image.Picture.Graphic)); end; end; {$ENDIF} UpdateToolbar(True); finally FreeAndNil(fsFileStream); end; if gImageExifRotate and SameText(sExt, 'jpg') then begin if FExif.LoadFromFile(sFileName) then begin bImage:= True; case FExif.Orientation of 2: cm_MirrorHorz([]); 3: cm_Rotate180([]); 4: cm_MirrorVert([]); 6: cm_Rotate90([]); 8: cm_Rotate270([]); end; end; end; AdjustImageSize; except on E: Exception do begin DCDebug(E.Message); Exit(False); end; end; end else begin GifAnim.Visible:= True; Image.Visible:= False; try GifAnim.FileName:= sFileName; UpdateToolbar(False); except on E: Exception do begin DCDebug(E.Message); Exit(False); end; end; end; ImgEdit:= False; end; function TfrmViewer.LoadSynEdit(const sFileName: String): Boolean; var Index: Integer; sEncoding: String; Buffer: AnsiString; Reader: TFileStreamUAC; begin if (SynEdit = nil) then begin SynEdit:= TSynEdit.Create(pnlCode); SynEdit.Parent:= pnlCode; SynEdit.Align:= alClient; SynEdit.ReadOnly:= True; SynEdit.PopupMenu:= pmEditMenu; with SynEdit.Gutter.SeparatorPart() do begin MarkupInfo.Background:= clWindow; MarkupInfo.Foreground:= clGrayText; end; with SynEdit.Gutter.LineNumberPart() do begin MarkupInfo.Background:= clBtnFace; MarkupInfo.Foreground:= clBtnText; end; SynEdit.Options:= gEditorSynEditOptions; SynEdit.TabWidth := gEditorSynEditTabWidth; SynEdit.RightEdge := gEditorSynEditRightEdge; FontOptionsToFont(gFonts[dcfViewer], SynEdit.Font); SynEdit.OnKeyDown:= @SynEditKeyDown; SynEdit.OnMouseWheel:= @SynEditMouseWheel; SynEdit.OnStatusChange:= @SynEditStatusChange; SynEditCaret; end; dmHighl.SetHighlighter(SynEdit, FHighlighter); PushPop(FElevate); try Result := False; try Reader := TFileStreamUAC.Create(sFileName, fmOpenRead or fmShareDenyNone); try SetLength(FSynEditOriginalText, Reader.Size); Reader.Read(Pointer(FSynEditOriginalText)^, Length(FSynEditOriginalText)); finally Reader.Free; end; Status.Panels[sbpTextEncoding].Text:= EmptyStr; // Try to detect encoding by first 4 kb of text Buffer := Copy(FSynEditOriginalText, 1, 4096); sEncoding := NormalizeEncoding(DetectEncoding(Buffer)); for Index:= 0 to miEncoding.Count - 1 do begin if SameStr(miEncoding.Items[Index].Hint, sEncoding) then begin miEncoding.Items[Index].Checked:= True; Status.Panels[sbpTextEncoding].Text := rsViewEncoding + ': ' + miEncoding.Items[Index].Caption; Break; end; end; // Convert encoding if needed if sEncoding = EncodingUTF8 then Buffer := FSynEditOriginalText else begin if (sEncoding = EncodingUTF16LE) or (sEncoding = EncodingUTF16BE) then begin FSynEditOriginalText := Copy(FSynEditOriginalText, 3, MaxInt); // Skip BOM end; Buffer := ConvertEncoding(FSynEditOriginalText, sEncoding, EncodingUTF8); end; // Load text into editor SynEdit.Lines.Text := Buffer; // Add empty line if needed if (Length(Buffer) > 0) and (Buffer[Length(Buffer)] in [#10, #13]) then SynEdit.Lines.Add(EmptyStr); Result := True; except // Ignore end; finally PushPop(FElevate); end; end; function TfrmViewer.LoadPlugin(const sFileName: String; Index, ShowFlags: Integer): Boolean; var WlxModule: TWlxModule; begin if not WlxPlugins.LoadModule(Index) then Exit(False); WlxModule:= WlxPlugins.GetWlxModule(Index); WlxModule.QuickView:= bQuickView; if WlxModule.CallListLoad(Self.Handle, sFileName, ShowFlags) = 0 then begin WlxModule.UnloadModule; Exit(False); end; ActivePlugin:= Index; FWlxModule:= WlxModule; WlxModule.ResizeWindow(GetListerRect); EnablePrint(WlxModule.CanPrint); // Set focus to plugin window if not bQuickView then WlxModule.SetFocus; UpdatePluginsMenu; Result:= True; end; procedure TfrmViewer.DoSearchCode(bQuickSearch: Boolean; bSearchBackwards: Boolean); var Index: Integer; Options: TTextSearchOptions; begin for Index:= 0 to glsSearchHistory.Count - 1 do begin Options:= TTextSearchOptions(UInt32(UIntPtr(glsSearchHistory.Objects[Index]))); if (tsoHex in Options) then Continue; if (tsoMatchCase in Options) then FSearchOptions.Flags += [ssoMatchCase]; if (tsoRegExpr in Options) then FSearchOptions.Flags += [ssoRegExpr]; FSearchOptions.SearchText:= glsSearchHistory[Index]; Break; end; if (bQuickSearch and gFirstTextSearch) or (not bQuickSearch) then begin if bQuickSearch then begin if bSearchBackwards then FSearchOptions.Flags += [ssoBackwards] else begin FSearchOptions.Flags -= [ssoBackwards]; end; end; ShowSearchReplaceDialog(Self, SynEdit, cbGrayed, FSearchOptions); end else begin if bSearchBackwards then begin SynEdit.SelEnd := SynEdit.SelStart; end; DoSearchReplaceText(SynEdit, False, bSearchBackwards, FSearchOptions); FSearchOptions.Flags -= [ssoEntireScope]; end; end; procedure TfrmViewer.DoSearch(bQuickSearch: Boolean; bSearchBackwards: Boolean); const bNewSearch: Boolean = False; var T: QWord; PAdr: PtrInt; PAnsiAddr: PByte; bTextFound: Boolean; sSearchTextU: String; sSearchTextA: AnsiString; RecodeTable: TRecodeTable; Options: TTextSearchOptions; iSearchParameter: Integer = 0; begin // in first use create dialog if not Assigned(FFindDialog) then FFindDialog:= TfrmFindView.Create(Self); if glsSearchHistory.Count > 0 then begin Options:= TTextSearchOptions(UInt32(UIntPtr(glsSearchHistory.Objects[0]))); if (tsoMatchCase in Options) then FFindDialog.cbCaseSens.Checked:= True; if (tsoRegExpr in Options) then FFindDialog.cbRegExp.Checked:= True; if (tsoHex in Options) then FFindDialog.chkHex.Checked:= True; end; if (bQuickSearch and gFirstTextSearch) or (not bQuickSearch) or (bPlugin and FFindDialog.chkHex.Checked) then begin if bPlugin then begin FFindDialog.chkHex.Checked:= False; // if plugin has specific search dialog if FWlxModule.CallListSearchDialog(0) = LISTPLUGIN_OK then Exit; iSearchParameter:= iSearchParameter or lcs_findfirst; end; FFindDialog.chkHex.Visible:= not bPlugin; FFindDialog.cbRegExp.Visible:= (not bPlugin) and (ViewerControl.FileSize < High(IntPtr)) and ( (ViewerControl.Encoding = veUtf16le) or (not (ViewerControl.Encoding in ViewerEncodingMultiByte)) or (TRegExprU.Available and (ViewerControl.Encoding in [veUtf8, veUtf8bom])) ); if not FFindDialog.cbRegExp.Visible then FFindDialog.cbRegExp.Checked:= False; if FFindDialog.cbRegExp.Checked then bSearchBackwards:= False; FFindDialog.cbBackwards.Checked:= bSearchBackwards; // Load search history FFindDialog.cbDataToFind.Items.Assign(glsSearchHistory); sSearchTextU:= ViewerControl.Selection; if Length(sSearchTextU) > 0 then FFindDialog.cbDataToFind.Text:= sSearchTextU; if FFindDialog.ShowModal <> mrOK then Exit; if FFindDialog.cbDataToFind.Text = '' then Exit; sSearchTextU:= FFindDialog.cbDataToFind.Text; bSearchBackwards:= FFindDialog.cbBackwards.Checked; // Save search history glsSearchHistory.Assign(FFindDialog.cbDataToFind.Items); gFirstTextSearch:= False; end else begin if bPlugin then begin // if plugin has specific search dialog if FWlxModule.CallListSearchDialog(1) = LISTPLUGIN_OK then Exit; end; if glsSearchHistory.Count > 0 then sSearchTextU:= glsSearchHistory[0]; FFindDialog.cbBackwards.Checked:= bSearchBackwards; end; if FFindDialog.cbRegExp.Checked then begin FRegExp.SetInputString(ViewerControl.GetDataAdr, ViewerControl.FileSize) end; if bPlugin then begin if bSearchBackwards then iSearchParameter:= iSearchParameter or lcs_backwards; if FFindDialog.cbCaseSens.Checked then iSearchParameter:= iSearchParameter or lcs_matchcase; FWlxModule.CallListSearchText(sSearchTextU, iSearchParameter); end else if ViewerControl.IsFileOpen then begin T:= GetTickCount64; if bSearchBackwards and FFindDialog.cbRegExp.Checked then begin msgError(rsMsgErrNotSupported); Exit; end; if not FFindDialog.cbRegExp.Checked then begin if not FFindDialog.chkHex.Checked then sSearchTextA:= ViewerControl.ConvertFromUTF8(sSearchTextU) else try sSearchTextA:= HexToBin(sSearchTextU); except on E: EConvertError do begin msgError(E.Message); Exit; end; end; end; // Choose search start position. if FLastSearchPos <> ViewerControl.CaretPos then begin FLastMatchLength := 0; FLastSearchPos := ViewerControl.CaretPos end else if FFindDialog.cbRegExp.Checked then begin if bNewSearch then begin FLastSearchPos := 0; FLastMatchLength := 0; end; end else if not bSearchBackwards then begin iSearchParameter:= Length(sSearchTextA); if bNewSearch then FLastSearchPos := 0 else if FLastSearchPos < ViewerControl.FileSize - iSearchParameter then FLastSearchPos := FLastSearchPos + iSearchParameter; end else begin iSearchParameter:= IfThen(ViewerControl.Encoding in ViewerEncodingDoubleByte, 2, 1); if bNewSearch then FLastSearchPos := ViewerControl.FileSize - 1 else if FLastSearchPos >= iSearchParameter then FLastSearchPos := FLastSearchPos - iSearchParameter; end; bNewSearch := False; if FFindDialog.cbRegExp.Checked then begin FRegExp.ModifierI:= not FFindDialog.cbCaseSens.Checked; FRegExp.Expression:= sSearchTextU; bTextFound:= FRegExp.Exec(FLastSearchPos + FLastMatchLength + 1); if bTextFound then begin FLastMatchLength:= FRegExp.MatchLen[0]; FLastSearchPos:= FRegExp.MatchPos[0] - 1; end; end else begin // Using standard search algorithm if hex or case sensitive and multibyte if FFindDialog.chkHex.Checked or (FFindDialog.cbCaseSens.Checked and (ViewerControl.Encoding in ViewerEncodingMultiByte)) then begin PAnsiAddr := PosMem(ViewerControl.GetDataAdr, ViewerControl.FileSize, FLastSearchPos, sSearchTextA, FFindDialog.cbCaseSens.Checked, bSearchBackwards); bTextFound := (PAnsiAddr <> Pointer(-1)); if bTextFound then FLastSearchPos := PAnsiAddr - ViewerControl.GetDataAdr; end // Using special case insensitive UTF-8 search algorithm else if (ViewerControl.Encoding in [veUtf8, veUtf8bom]) then begin PAnsiAddr := PosMemU(ViewerControl.GetDataAdr, ViewerControl.FileSize, FLastSearchPos, sSearchTextA, bSearchBackwards); bTextFound := (PAnsiAddr <> Pointer(-1)); if bTextFound then FLastSearchPos := PAnsiAddr - ViewerControl.GetDataAdr; end // Using special case insensitive UTF-16 search algorithm else if (ViewerControl.Encoding in [veUtf16le, veUtf16be, veUcs2le, veUcs2be]) then begin PAnsiAddr := PosMemW(ViewerControl.GetDataAdr, ViewerControl.FileSize, FLastSearchPos, sSearchTextA, bSearchBackwards, ViewerControl.Encoding in [veUtf16le, veUcs2le]); bTextFound := (PAnsiAddr <> Pointer(-1)); if bTextFound then FLastSearchPos := PAnsiAddr - ViewerControl.GetDataAdr; end // Using very slow search algorithm else if (ViewerControl.Encoding in [veUtf32le, veUtf32be]) then begin PAdr := ViewerControl.FindUtf8Text(FLastSearchPos, sSearchTextU, FFindDialog.cbCaseSens.Checked, bSearchBackwards); bTextFound := (PAdr <> PtrInt(-1)); if bTextFound then FLastSearchPos := PAdr; end // Using special case insensitive single byte encoding search algorithm else if bSearchBackwards then begin RecodeTable:= InitRecodeTable(ViewerControl.EncodingName, FFindDialog.cbCaseSens.Checked); PAnsiAddr := PosMemA(ViewerControl.GetDataAdr, ViewerControl.FileSize, FLastSearchPos, sSearchTextA, FFindDialog.cbCaseSens.Checked, bSearchBackwards, RecodeTable); bTextFound := (PAnsiAddr <> Pointer(-1)); if bTextFound then FLastSearchPos := PAnsiAddr - ViewerControl.GetDataAdr; end // Using very fast Boyer–Moore search algorithm else begin RecodeTable:= InitRecodeTable(ViewerControl.EncodingName, FFindDialog.cbCaseSens.Checked); PAdr := PosMemBoyerMur(ViewerControl.GetDataAdr + FLastSearchPos, ViewerControl.FileSize - FLastSearchPos, sSearchTextA, RecodeTable); bTextFound := (PAdr <> PtrInt(-1)); if bTextFound then FLastSearchPos := PAdr + FLastSearchPos; end; FLastMatchLength:= Length(sSearchTextA); end; if bTextFound then begin DCDebug('Search time: ' + IntToStr(GetTickCount64 - T)); // Text found, show it in ViewerControl if not visible ViewerControl.MakeVisible(FLastSearchPos); // Select found text. ViewerControl.CaretPos := FLastSearchPos; ViewerControl.SelectText(FLastSearchPos, FLastSearchPos + FLastMatchLength); end else begin msgOK(Format(rsViewNotFound, ['"' + sSearchTextU + '"'])); if (ViewerControl.Selection <> sSearchTextU) then begin ViewerControl.SelectText(0, 0); end; bNewSearch := True; FLastMatchLength := 0; FLastSearchPos := ViewerControl.CaretPos; end; end; end; procedure TfrmViewer.MakeTextEncodingsMenu; var I: Integer; mi: TMenuItem; EncodingsList: TStringList; begin miEncoding.Clear; EncodingsList := TStringList.Create; try ViewerControl.GetSupportedEncodings(EncodingsList); for I:= 0 to EncodingsList.Count - 1 do begin mi:= TMenuItem.Create(miEncoding); mi.Caption:= EncodingsList[I]; mi.Hint:= NormalizeEncoding(mi.Caption); mi.AutoCheck:= True; mi.RadioItem:= True; mi.GroupIndex:= 1; mi.Tag:= I; mi.OnClick:= @miChangeEncodingClick; if ViewerControl.EncodingName = EncodingsList[I] then mi.Checked := True; miEncoding.Add(mi); end; finally FreeAndNil(EncodingsList); end; end; procedure TfrmViewer.UpdateTextEncodingsMenu(AType: TEncodingMenu); var I: Integer; Encoding: TViewerEncoding; begin if AType = emViewer then begin for I:= 0 to miEncoding.Count - 1 do begin miEncoding.Items[I].Visible:= True; end; end else if AType = emEditor then begin for I:= 0 to miEncoding.Count - 1 do begin Encoding:= TViewerEncoding(I); miEncoding.Items[I].Visible:= not (Encoding in [veAutoDetect, veUcs2le, veUcs2be, veUtf32le, veUtf32be]); end; end else begin for I:= 0 to miEncoding.Count - 1 do begin Encoding:= TViewerEncoding(I); miEncoding.Items[I].Visible:= Encoding in [veAutoDetect, veAnsi, veOem]; end; end; end; procedure TfrmViewer.ViewerPositionChanged(Sender:TObject); begin if ViewerControl.FileSize > 0 then begin Status.Panels[sbpPosition].Text := cnvFormatFileSize(ViewerControl.Position) + ' (' + IntToStr(ViewerControl.Percent) + ' %)'; end else Status.Panels[sbpPosition].Text:= cnvFormatFileSize(0) + ' (0 %)'; end; procedure TfrmViewer.ActivatePanel(Panel: TPanel); begin bPlugin := (Panel = nil); bAnimation := (Panel = pnlImage) and (GifAnim.Visible); bImage := (Panel = pnlImage) and (bAnimation = False); if Panel <> pnlText then pnlText.Hide; if Panel <> pnlCode then pnlCode.Hide; if Panel <> pnlImage then pnlImage.Hide; if Panel <> pnlFolder then pnlFolder.Hide; if Assigned(Panel) then Panel.Visible := True; if Panel = nil then begin Status.Panels[sbpFileSize].Text:= EmptyStr; Status.Panels[sbpPluginName].Text:= FWlxModule.Name; UpdateTextEncodingsMenu(emPlugin); Status.Panels[sbpTextEncoding].Text := rsViewEncoding + ': ' + ViewerControl.EncodingName; end else if Panel = pnlCode then begin miCode.Checked:= True; UpdateTextEncodingsMenu(emEditor); if (not bQuickView) and CanFocus and SynEdit.CanFocus then SynEdit.SetFocus; Status.Panels[sbpFileSize].Text:= IntToStr(SynEdit.Lines.Count); end else if Panel = pnlText then begin if (not bQuickView) and CanFocus and ViewerControl.CanFocus then ViewerControl.SetFocus; case ViewerControl.Mode of vcmText: miText.Checked := True; vcmWrap: miText.Checked := True; vcmBin: miBin.Checked := True; vcmHex: miHex.Checked := True; vcmDec: miDec.Checked := True; vcmBook: miLookBook.Checked := True; end; UpdateTextEncodingsMenu(emViewer); FRegExp.ChangeEncoding(ViewerControl.EncodingName); Status.Panels[sbpFileSize].Text:= cnvFormatFileSize(ViewerControl.FileSize) + ' (100 %)'; Status.Panels[sbpTextEncoding].Text := rsViewEncoding + ': ' + ViewerControl.EncodingName; end else if Panel = pnlImage then begin pnlImage.TabStop:= True; Status.Panels[sbpTextEncoding].Text:= EmptyStr; if (not bQuickView) and CanFocus and pnlImage.CanFocus then pnlImage.SetFocus; ToolBar1.Visible:= not (bQuickView or (miFullScreen.Checked and not ToolBar1.MouseInClient)); end; miPlugins.Checked := (Panel = nil); miGraphics.Checked := (Panel = pnlImage); miEncoding.Visible := (Panel = nil) or (Panel = pnlText) or (Panel = pnlCode); miAutoReload.Visible := (Panel = pnlText); miEdit.Visible := (Panel = pnlText) or (Panel = pnlCode) or (Panel = nil); miImage.Visible := (bImage or bPlugin); miRotate.Visible := bImage; miZoomIn.Visible := bImage; miZoomOut.Visible := bImage; miFullScreen.Visible := (bImage and not bQuickView); miScreenshot.Visible := (bImage and not bQuickView); miSave.Visible := bImage; miSaveAs.Visible := bImage; miShowTransparency.Visible := bImage; actGotoLine.Enabled := (Panel = pnlCode); actShowCaret.Enabled := (Panel = pnlText) or (Panel = pnlCode); actWrapText.Enabled := bPlugin or ((Panel = pnlText) and (ViewerControl.Mode in [vcmText, vcmWrap])); miGotoLine.Visible := (Panel = pnlCode); miDiv5.Visible := (Panel = pnlText) or (Panel = pnlCode); pmiSelectAll.Visible := (Panel = pnlText) or (Panel = pnlCode); pmiCopyFormatted.Visible := (Panel = pnlText); if (Panel <> pnlText) and actAutoReload.Checked then cm_AutoReload([]); end; procedure TfrmViewer.cm_About(const Params: array of string); begin MsgOK(rsViewAboutText); end; procedure TfrmViewer.cm_Reload(const Params: array of string); begin ExitPluginMode; LoadFile(iActiveFile); end; procedure TfrmViewer.cm_AutoReload(const Params: array of string); begin actAutoReload.Checked := not actAutoReload.Checked; if actAutoReload.Checked then ViewerControl.GoEnd; TimerReload.Enabled := actAutoReload.Checked; FileName:= FFileName; end; procedure TfrmViewer.cm_LoadNextFile(const Params: array of string); var Index : Integer; begin if not bQuickView then begin Index:= iActiveFile + 1; if Index >= FileList.Count then Index:= 0; LoadNextFile(Index); end; end; procedure TfrmViewer.cm_LoadPrevFile(const Params: array of string); var Index: Integer; begin if not bQuickView then begin Index:= iActiveFile - 1; if Index < 0 then Index:= FileList.Count - 1; LoadNextFile(Index); end; end; procedure TfrmViewer.cm_MoveFile(const Params: array of string); begin if actMoveFile.Enabled then CopyMoveFile(vcmaMove); end; procedure TfrmViewer.cm_CopyFile(const Params: array of string); begin if actCopyFile.Enabled then CopyMoveFile(vcmaCopy); end; procedure TfrmViewer.cm_DeleteFile(const Params: array of string); begin if actDeleteFile.Enabled and msgYesNo(Format(rsMsgDelSel, [FileList.Strings[iActiveFile]])) then begin DeleteCurrentFile; end; end; procedure TfrmViewer.cm_StretchImage(const Params: array of string); begin miStretch.Checked:= not miStretch.Checked; if miStretch.Checked then begin FZoomFactor:= 100; miStretchOnlyLarge.Checked:= False end; UpdateImagePlacement; end; procedure TfrmViewer.cm_StretchOnlyLarge(const Params: array of string); begin miStretchOnlyLarge.Checked:= not miStretchOnlyLarge.Checked; if miStretchOnlyLarge.Checked then miStretch.Checked:= False; UpdateImagePlacement; end; procedure TfrmViewer.cm_ShowTransparency(const Params: array of string); begin gImageShowTransparency:= not gImageShowTransparency; actShowTransparency.Checked:= gImageShowTransparency; if actShowTransparency.Checked then Image.OnPaintBackground:= @ImagePaintBackground else begin Image.OnPaintBackground:= nil; end; Image.Repaint; end; procedure TfrmViewer.cm_Save(const Params: array of string); var sExt: String; begin if actSave.Enabled then begin DrawPreview.BeginUpdate; try CreatePreview(FileList.Strings[iActiveFile], iActiveFile, True); sExt:= ExtractFileExt(FileList.Strings[iActiveFile]); SaveImageAs(sExt, True, gViewerJpegQuality); CreatePreview(FileList.Strings[iActiveFile], iActiveFile); finally DrawPreview.EndUpdate; end; end; end; procedure TfrmViewer.cm_Undo(const Params: array of string); begin if bImage then UndoTmp; end; procedure TfrmViewer.cm_SaveAs(const Params: array of string); var sExt: String; begin if bAnimation or bImage then begin sExt:= EmptyStr; SaveImageAs(sExt, False, gViewerJpegQuality); end; end; procedure TfrmViewer.cm_Rotate90(const Params: array of string); begin if bImage then RotateImage(90); end; procedure TfrmViewer.cm_Rotate180(const Params: array of string); begin if bImage then RotateImage(180); end; procedure TfrmViewer.cm_Rotate270(const Params: array of string); begin if bImage then RotateImage(270); end; procedure TfrmViewer.cm_MirrorHorz(const Params: array of string); begin if bImage then MirrorImage; end; procedure TfrmViewer.cm_MirrorVert(const Params: array of string); begin if bImage then MirrorImage(True); end; procedure TfrmViewer.cm_ImageCenter(const Params: array of string); begin miCenter.Checked:= not miCenter.Checked; UpdateImagePlacement; end; procedure TfrmViewer.cm_Zoom(const Params: array of string); begin if miGraphics.Checked then try ZoomImage(StrToFloat(Params[0])); except // Exit end; end; procedure TfrmViewer.cm_ZoomIn(const Params: array of string); begin if miGraphics.Checked then ZoomImage(1.1) else begin gFonts[dcfViewer].Size:=gFonts[dcfViewer].Size+1; ViewerControl.Font.Size:=gFonts[dcfViewer].Size; ViewerControl.Repaint; end; end; procedure TfrmViewer.cm_ZoomOut(const Params: array of string); begin if miGraphics.Checked then ZoomImage(0.9) else begin gFonts[dcfViewer].Size:=gFonts[dcfViewer].Size-1; ViewerControl.Font.Size:=gFonts[dcfViewer].Size; ViewerControl.Repaint; end; end; procedure TfrmViewer.cm_Fullscreen(const Params: array of string); begin miFullScreen.Checked:= not (miFullScreen.Checked); if miFullScreen.Checked then begin FWindowState:= WindowState; {$IF DEFINED(LCLWIN32)} FWindowBounds.Top:= Top; FWindowBounds.Left:= Left; FWindowBounds.Right:= Width; FWindowBounds.Bottom:= Height; BorderStyle:= bsNone; {$ENDIF} WindowState:= wsFullScreen; Self.Menu:= nil; btnPaint.Down:= false; btnHightlight.Down:=false; ToolBar1.Visible:= False; miStretch.Checked:= True; miStretchOnlyLarge.Checked:= False; if miPreview.Checked then cm_Preview(['']); actFullscreen.ImageIndex:= 25; end else begin Self.Menu:= MainMenu; {$IFDEF LCLGTK2} WindowState:= wsFullScreen; {$ENDIF} WindowState:= FWindowState; {$IF DEFINED(LCLWIN32)} BorderStyle:= bsSizeable; SetBounds(FWindowBounds.Left, FWindowBounds.Top, FWindowBounds.Right, FWindowBounds.Bottom); {$ENDIF} ToolBar1.Visible:= True; actFullscreen.ImageIndex:= 22; end; if ExtractOnlyFileExt(FileList.Strings[iActiveFile]) <> 'gif' then begin btnHightlight.Enabled:= not (miFullScreen.Checked); btnPaint.Enabled:= not (miFullScreen.Checked); btnResize.Enabled:= not (miFullScreen.Checked); end; sboxImage.HorzScrollBar.Visible:= not(miFullScreen.Checked); sboxImage.VertScrollBar.Visible:= not(miFullScreen.Checked); TimerViewer.Enabled:=miFullScreen.Checked; btnReload.Enabled:=not(miFullScreen.Checked); Status.Visible:=not(miFullScreen.Checked); btnSlideShow.Visible:=miFullScreen.Checked; AdjustImageSize; ShowOnTop; end; procedure TfrmViewer.cm_Screenshot(const Params: array of string); var ScreenDC: HDC; bmp: TCustomBitmap; begin Visible:= False; Application.ProcessMessages; // Hide viewer window bmp := TBitmap.Create; ScreenDC := GetDC(0); bmp.LoadFromDevice(ScreenDC); ReleaseDC(0, ScreenDC); Image.Picture.Bitmap.Height:= bmp.Height; Image.Picture.Bitmap.Width:= bmp.Width; Image.Picture.Bitmap.Canvas.Draw(0, 0, bmp); CreateTmp; bmp.Free; Visible:= True; ImgEdit:= True; end; procedure TfrmViewer.cm_ScreenshotWithDelay(const Params: array of string); var i:integer; begin i:=StrToInt(Params[0]); i:=i*1000; TimerScreenshot.Interval:=i; TimerScreenshot.Enabled:=True; end; procedure TfrmViewer.cm_ScreenshotDelay3sec(const Params: array of string); begin cm_ScreenshotWithDelay(['3']); end; procedure TfrmViewer.cm_ScreenshotDelay5sec(const Params: array of string); begin cm_ScreenshotWithDelay(['5']); end; procedure TfrmViewer.cm_ChangeEncoding(const Params: array of string); var Encoding: String; MenuItem: TMenuItem; begin if miEncoding.Visible and (Length(Params) > 0) then begin MenuItem:= miEncoding.Find(Params[0]); if Assigned(MenuItem) then begin MenuItem.Checked := True; Encoding:= NormalizeEncoding(Params[0]); if miCode.Checked then begin SynEdit.Lines.Text:= ConvertEncoding(FSynEditOriginalText, Encoding, EncodingUTF8); Status.Panels[sbpTextEncoding].Text := rsViewEncoding + ': ' + MenuItem.Caption; end else begin if bPlugin then begin if (Encoding = EncodingAnsi) then FPluginEncoding:= lcp_ansi else if (Encoding = EncodingOem) then FPluginEncoding:= lcp_ascii else begin FPluginEncoding:= 0; end; FWlxModule.CallListSendCommand(lc_newparams, PluginShowFlags); end; FRegExp.ChangeEncoding(Encoding); ViewerControl.EncodingName := Encoding; Status.Panels[sbpTextEncoding].Text := rsViewEncoding + ': ' + ViewerControl.EncodingName; end; end; end; end; procedure TfrmViewer.cm_CopyToClipboard(const Params: array of string); begin if miCode.Checked then SynEdit.CopyToClipboard else if bPlugin then FWlxModule.CallListSendCommand(lc_copy, 0) else begin if (miGraphics.Checked)and(Image.Picture<>nil)and(Image.Picture.Bitmap<>nil)then begin if not bAnimation then Clipboard.Assign(Image.Picture) else Clipboard.Assign(GifAnim.GifBitmaps[GifAnim.GifIndex].Bitmap); end else ViewerControl.CopyToClipboard; end; end; procedure TfrmViewer.cm_CopyToClipboardFormatted(const Params: array of string); begin if ViewerControl.Mode in [vcmHex, vcmDec] then ViewerControl.CopyToClipboardF; end; procedure TfrmViewer.cm_SelectAll(const Params: array of string); begin if miCode.Checked then SynEdit.SelectAll else if bPlugin then FWlxModule.CallListSendCommand(lc_selectall, 0) else begin ViewerControl.SelectAll; end; end; procedure TfrmViewer.cm_Find(const Params: array of string); var bSearchBackwards: Boolean; begin if miCode.Checked then begin DoSearchCode(False, ssoBackwards in FSearchOptions.Flags); end else if not miGraphics.Checked then begin if (FFindDialog = nil) then bSearchBackwards:= False else begin bSearchBackwards:= FFindDialog.cbBackwards.Checked; end; DoSearch(False, bSearchBackwards); end; end; procedure TfrmViewer.cm_FindNext(const Params: array of string); begin if miCode.Checked then begin DoSearchCode(True, False); end else if not miGraphics.Checked then begin DoSearch(True, False); end; end; procedure TfrmViewer.cm_FindPrev(const Params: array of string); begin if miCode.Checked then begin DoSearchCode(True, True); end else if not miGraphics.Checked then begin DoSearch(True, True); end; end; procedure TfrmViewer.cm_GotoLine(const Params: array of string); var P: TPoint; Value: String; NewTopLine: Integer; begin if ShowInputQuery(rsEditGotoLineTitle, rsEditGotoLineQuery, Value) then begin P.X := 1; P.Y := StrToIntDef(Value, 1); NewTopLine := P.Y - (SynEdit.LinesInWindow div 2); if NewTopLine < 1 then NewTopLine:= 1; SynEdit.CaretXY := P; SynEdit.TopLine := NewTopLine; SynEdit.SetFocus; end; end; procedure TfrmViewer.cm_Preview(const Params: array of string); begin miPreview.Checked:= not (miPreview.Checked); pnlPreview.Visible := miPreview.Checked; Splitter.Visible := pnlPreview.Visible; if miPreview.Checked then FThread:= TThumbThread.Create(Self) else begin TThumbThread.Finish(FThread); end; if bPlugin then FWlxModule.ResizeWindow(GetListerRect); end; procedure TfrmViewer.cm_ShowAsText(const Params: array of string); begin ShowTextViewer(WRAP_MODE[gViewerWrapText]); end; procedure TfrmViewer.cm_ShowAsBin(const Params: array of string); begin ShowTextViewer(vcmBin); end; procedure TfrmViewer.cm_ShowAsHex(const Params: array of string); begin ShowTextViewer(vcmHex); end; procedure TfrmViewer.cm_ShowAsDec(const Params: array of string); begin ShowTextViewer(vcmDec); end; procedure TfrmViewer.cm_ShowAsWrapText(const Params: array of string); begin gViewerWrapText:= True; actWrapText.Checked:= True; ShowTextViewer(vcmWrap); end; procedure TfrmViewer.cm_ShowAsBook(const Params: array of string); begin ShowTextViewer(vcmBook); end; procedure TfrmViewer.cm_ShowGraphics(const Params: array of string); begin if CheckGraphics(FileList.Strings[iActiveFile]) then begin ExitPluginMode; ViewerControl.FileName := ''; // unload current file if any is loaded if LoadGraphics(FileList.Strings[iActiveFile]) then ActivatePanel(pnlImage) else begin ViewerControl.FileName := FileList.Strings[iActiveFile]; ActivatePanel(pnlText); end; end; end; procedure TfrmViewer.cm_ShowPlugins(const Params: array of string); var Index: Integer; begin Index := ActivePlugin; ExitPluginMode; ActivePlugin := Index; bPlugin:= CheckPlugins(FileList.Strings[iActiveFile], True); if bPlugin then begin ViewerControl.FileName := ''; // unload current file if any is loaded ActivatePanel(nil); end; end; procedure TfrmViewer.cm_ShowOffice(const Params: array of string); begin if CheckOffice(FileList.Strings[iActiveFile]) then begin ExitPluginMode; ActivatePanel(pnlText); miOffice.Checked:= True; end; end; procedure TfrmViewer.cm_ShowCode(const Params: array of string); begin if CheckSynEdit(FileList.Strings[iActiveFile], True) then begin ExitPluginMode; ViewerControl.FileName := ''; // unload current file if any is loaded if LoadSynEdit(FileList.Strings[iActiveFile]) then ActivatePanel(pnlCode) else begin ViewerControl.FileName := FileList.Strings[iActiveFile]; ActivatePanel(pnlText); end; end; end; procedure TfrmViewer.cm_ExitViewer(const Params: array of string); begin if not bQuickView then Close; end; procedure TfrmViewer.cm_Print(const Params: array of string); begin if bPlugin and actPrint.Enabled then FWlxModule.CallListPrint(ExtractFileName(FileList.Strings[iActiveFile]), '', 0, gPrintMargins); end; procedure TfrmViewer.cm_PrintSetup(const Params: array of string); begin if bPlugin and actPrintSetup.Enabled then begin with TfrmPrintSetup.Create(Self) do try ShowModal; finally Free; end; end; end; procedure TfrmViewer.cm_ShowCaret(const Params: array of string); begin if not miGraphics.Checked then begin gShowCaret:= not gShowCaret; actShowCaret.Checked:= gShowCaret; ViewerControl.ShowCaret:= gShowCaret; if Assigned(SynEdit) then SynEditCaret; end; end; procedure TfrmViewer.cm_WrapText(const Params: array of string); begin gViewerWrapText:= not gViewerWrapText; actWrapText.Checked:= gViewerWrapText; if bPlugin then FWlxModule.CallListSendCommand(lc_newparams, PluginShowFlags) else if not miGraphics.Checked then begin if ViewerControl.Mode in [vcmText, vcmWrap] then begin ViewerControl.Mode:= WRAP_MODE[gViewerWrapText]; end; end; end; initialization TFormCommands.RegisterCommandsForm(TfrmViewer, HotkeysCategory, @rsHotkeyCategoryViewer); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fviewoperations.lfm������������������������������������������������������������0000644�0001750�0000144�00000015035�14743153644�017325� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmViewOperations: TfrmViewOperations Left = 18 Height = 353 Top = 117 Width = 507 ActiveControl = tvOperations Caption = 'File operations' ClientHeight = 353 ClientWidth = 507 Constraints.MinHeight = 100 Constraints.MinWidth = 300 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy Position = poScreenCenter SessionProperties = 'Height;Left;Top;Width;WindowState;cbAlwaysOnTop.Checked' LCLVersion = '1.1' object pnlHeader: TPanel Left = 0 Height = 64 Top = 0 Width = 507 Align = alTop AutoSize = True BevelOuter = bvNone ClientHeight = 64 ClientWidth = 507 TabOrder = 0 object pnlTopHeader: TPanel AnchorSideLeft.Control = pnlHeader AnchorSideTop.Control = pnlHeader AnchorSideRight.Control = pnlHeader AnchorSideRight.Side = asrBottom Left = 0 Height = 40 Top = 0 Width = 507 Anchors = [akTop, akLeft, akRight] AutoSize = True BevelOuter = bvNone ClientHeight = 40 ClientWidth = 507 TabOrder = 0 object tbPauseAll: TToggleBox AnchorSideLeft.Control = pnlTopHeader AnchorSideTop.Control = pnlTopHeader AnchorSideBottom.Control = pnlTopHeader AnchorSideBottom.Side = asrBottom Left = 0 Height = 40 Top = 0 Width = 70 Anchors = [akTop, akLeft, akBottom] AutoSize = True BorderSpacing.Right = 40 Caption = '&Pause all' OnChange = tbPauseAllChange TabOrder = 0 end object btnStop: TBitBtn AnchorSideLeft.Control = tbPauseAll AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTopHeader AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 110 Height = 40 Top = 0 Width = 80 AutoSize = True Caption = 'S&top' Constraints.MinHeight = 40 Constraints.MinWidth = 80 Enabled = False OnClick = btnStopClick TabOrder = 1 end object btnStartPause: TBitBtn AnchorSideLeft.Control = btnStop AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlTopHeader AnchorSideBottom.Side = asrBottom Left = 200 Height = 40 Top = 0 Width = 80 AutoSize = True BorderSpacing.Left = 10 Caption = '&Start' Constraints.MinHeight = 40 Constraints.MinWidth = 80 Enabled = False OnClick = btnStartPauseClick TabOrder = 2 end end object lblUseDragDrop: TLabel AnchorSideLeft.Control = pnlHeader AnchorSideTop.Control = pnlTopHeader AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlHeader AnchorSideRight.Side = asrBottom Left = 10 Height = 18 Top = 43 Width = 487 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 10 BorderSpacing.Top = 3 BorderSpacing.Right = 10 BorderSpacing.Bottom = 3 Caption = '&Use "drag && drop" to move operations between queues' FocusControl = tvOperations ParentColor = False end object cbAlwaysOnTop: TCheckBox AnchorSideTop.Control = pnlTopHeader AnchorSideTop.Side = asrCenter AnchorSideRight.Control = pnlTopHeader AnchorSideRight.Side = asrBottom Left = 391 Height = 23 Top = 9 Width = 116 Anchors = [akTop, akRight] Caption = 'Always on top' OnChange = cbAlwaysOnTopChange TabOrder = 1 end end object tvOperations: TTreeView AnchorSideLeft.Control = Owner AnchorSideTop.Control = pnlHeader AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom Left = 0 Height = 289 Top = 64 Width = 507 Anchors = [akTop, akLeft, akRight, akBottom] AutoExpand = True DefaultItemHeight = 24 DragMode = dmAutomatic ExpandSignType = tvestArrow MultiSelect = True MultiSelectStyle = [msControlSelect, msShiftSelect] ReadOnly = True RowSelect = True ScrollBars = ssAutoVertical ShowLines = False TabOrder = 1 OnCustomDrawItem = tvOperationsCustomDrawItem OnDeletion = tvOperationsDeletion OnDragDrop = tvOperationsDragDrop OnDragOver = tvOperationsDragOver OnKeyDown = tvOperationsKeyDown OnMouseDown = tvOperationsMouseDown OnSelectionChanged = tvOperationsSelectionChanged Options = [tvoAllowMultiselect, tvoAutoExpand, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowButtons, tvoShowRoot, tvoShowSeparators, tvoToolTips, tvoNoDoubleClickExpand, tvoThemedDraw] end object UpdateTimer: TTimer Interval = 100 OnTimer = OnUpdateTimer left = 112 top = 136 end object pmOperationPopup: TPopupMenu left = 224 top = 136 object mnuQueue: TMenuItem Caption = 'Queue' object mnuQueue0: TMenuItem Caption = 'Out of queue' OnClick = mnuQueueNumberClick end object mnuQueue1: TMenuItem Caption = 'Queue 1' OnClick = mnuQueueNumberClick end object mnuQueue2: TMenuItem Caption = 'Queue 2' OnClick = mnuQueueNumberClick end object mnuQueue3: TMenuItem Caption = 'Queue 3' OnClick = mnuQueueNumberClick end object mnuQueue4: TMenuItem Caption = 'Queue 4' OnClick = mnuQueueNumberClick end object mnuQueue5: TMenuItem Caption = 'Queue 5' OnClick = mnuQueueNumberClick end object mnuNewQueue: TMenuItem Caption = 'New queue' OnClick = mnuNewQueueClick end end object mnuOperationShowDetached: TMenuItem Caption = 'Show in detached window' OnClick = mnuOperationShowDetachedClick end object mnuPutFirstInQueue: TMenuItem Caption = 'Put first in queue' OnClick = mnuPutFirstInQueueClick end object mnuPutLastInQueue: TMenuItem Caption = 'Put last in queue' OnClick = mnuPutLastInQueueClick end object mnuCancelOperation: TMenuItem Caption = 'Cancel' OnClick = mnuCancelOperationClick end end object pmQueuePopup: TPopupMenu left = 224 top = 208 object mnuQueueShowDetached: TMenuItem Caption = 'Show in detached window' OnClick = mnuQueueShowDetachedClick end object mnuCancelQueue: TMenuItem Caption = 'Cancel' OnClick = mnuCancelQueueClick end end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fviewoperations.lrj������������������������������������������������������������0000644�0001750�0000144�00000006127�14743153644�017340� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":184414099,"name":"tfrmviewoperations.caption","sourcebytes":[70,105,108,101,32,111,112,101,114,97,116,105,111,110,115],"value":"File operations"}, {"hash":211145388,"name":"tfrmviewoperations.tbpauseall.caption","sourcebytes":[38,80,97,117,115,101,32,97,108,108],"value":"&Pause all"}, {"hash":5626720,"name":"tfrmviewoperations.btnstop.caption","sourcebytes":[83,38,116,111,112],"value":"S&top"}, {"hash":45787284,"name":"tfrmviewoperations.btnstartpause.caption","sourcebytes":[38,83,116,97,114,116],"value":"&Start"}, {"hash":45418739,"name":"tfrmviewoperations.lblusedragdrop.caption","sourcebytes":[38,85,115,101,32,34,100,114,97,103,32,38,38,32,100,114,111,112,34,32,116,111,32,109,111,118,101,32,111,112,101,114,97,116,105,111,110,115,32,98,101,116,119,101,101,110,32,113,117,101,117,101,115],"value":"&Use \"drag && drop\" to move operations between queues"}, {"hash":259910512,"name":"tfrmviewoperations.cbalwaysontop.caption","sourcebytes":[65,108,119,97,121,115,32,111,110,32,116,111,112],"value":"Always on top"}, {"hash":5815477,"name":"tfrmviewoperations.mnuqueue.caption","sourcebytes":[81,117,101,117,101],"value":"Queue"}, {"hash":219470821,"name":"tfrmviewoperations.mnuqueue0.caption","sourcebytes":[79,117,116,32,111,102,32,113,117,101,117,101],"value":"Out of queue"}, {"hash":146585441,"name":"tfrmviewoperations.mnuqueue1.caption","sourcebytes":[81,117,101,117,101,32,49],"value":"Queue 1"}, {"hash":146585442,"name":"tfrmviewoperations.mnuqueue2.caption","sourcebytes":[81,117,101,117,101,32,50],"value":"Queue 2"}, {"hash":146585443,"name":"tfrmviewoperations.mnuqueue3.caption","sourcebytes":[81,117,101,117,101,32,51],"value":"Queue 3"}, {"hash":146585444,"name":"tfrmviewoperations.mnuqueue4.caption","sourcebytes":[81,117,101,117,101,32,52],"value":"Queue 4"}, {"hash":146585445,"name":"tfrmviewoperations.mnuqueue5.caption","sourcebytes":[81,117,101,117,101,32,53],"value":"Queue 5"}, {"hash":158918773,"name":"tfrmviewoperations.mnunewqueue.caption","sourcebytes":[78,101,119,32,113,117,101,117,101],"value":"New queue"}, {"hash":186662487,"name":"tfrmviewoperations.mnuoperationshowdetached.caption","sourcebytes":[83,104,111,119,32,105,110,32,100,101,116,97,99,104,101,100,32,119,105,110,100,111,119],"value":"Show in detached window"}, {"hash":94289029,"name":"tfrmviewoperations.mnuputfirstinqueue.caption","sourcebytes":[80,117,116,32,102,105,114,115,116,32,105,110,32,113,117,101,117,101],"value":"Put first in queue"}, {"hash":44375077,"name":"tfrmviewoperations.mnuputlastinqueue.caption","sourcebytes":[80,117,116,32,108,97,115,116,32,105,110,32,113,117,101,117,101],"value":"Put last in queue"}, {"hash":77089212,"name":"tfrmviewoperations.mnucanceloperation.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"}, {"hash":186662487,"name":"tfrmviewoperations.mnuqueueshowdetached.caption","sourcebytes":[83,104,111,119,32,105,110,32,100,101,116,97,99,104,101,100,32,119,105,110,100,111,119],"value":"Show in detached window"}, {"hash":77089212,"name":"tfrmviewoperations.mnucancelqueue.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"} ]} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/fviewoperations.pas������������������������������������������������������������0000644�0001750�0000144�00000107460�14743153644�017336� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fViewOperations; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, StdCtrls, ExtCtrls, LCLType, ComCtrls, Buttons, LCLIntf, Menus, uFileSourceOperation, uOperationsManager, Themes; type TViewBaseItem = class; TViewBaseItemClick = procedure(Item: TViewBaseItem; Button: TMouseButton; Shift: TShiftState; const Pt: TPoint) of object; TViewBaseItemContextMenu = procedure(Item: TViewBaseItem; const Point: TPoint) of object; TViewBaseItemSelected = procedure(Item: TViewBaseItem) of object; TViewOperationsStatusIcon = (vosiPlay, vosiPause, vosiHourglass); { TViewBaseItem } TViewBaseItem = class private FOnClick: TViewBaseItemClick; FOnContextMenu: TViewBaseItemContextMenu; FOnSelected: TViewBaseItemSelected; FTreeNode: TTreeNode; FText: String; FTextRect: TRect; procedure CalculateSizes(Canvas: TCanvas; NeedsStatusIcon, NeedsProgress: Boolean); procedure DrawProgress(Canvas: TCanvas; NodeRect: TRect; Progress: Double); procedure DrawStatusIcon(Canvas: TCanvas; NodeRect: TRect; Icon: TViewOperationsStatusIcon); procedure DrawThemedBackground(Canvas: TCanvas; Element: TThemedTreeview; ARect: TRect); procedure DrawThemedText(Canvas: TCanvas; Element: TThemedTreeview; NodeRect: TRect; Center: Boolean; AText: String); function GetStatusIconRect(NodeRect: TRect): TRect; function GetTextIndent: Integer; virtual; abstract; procedure UpdateView(Canvas: TCanvas); virtual; abstract; public constructor Create(ANode: TTreeNode); virtual; procedure Click(const Pt: TPoint; Button: TMouseButton; Shift: TShiftState); virtual; procedure Draw(Canvas: TCanvas; NodeRect: TRect); virtual; abstract; function GetBackgroundColor: TColor; virtual; abstract; procedure KeyDown(var Key: Word; Shift: TShiftState); virtual; procedure Selected; virtual; procedure StartPause; virtual; abstract; procedure Stop; virtual; abstract; property OnClick: TViewBaseItemClick read FOnClick write FOnClick; property OnContextMenu: TViewBaseItemContextMenu read FOnContextMenu write FOnContextMenu; property OnSelected: TViewBaseItemSelected read FOnSelected write FOnSelected; end; { TViewQueueItem } TViewQueueItem = class(TViewBaseItem) private FQueueIdentifier: TOperationsManagerQueueIdentifier; function GetTextIndent: Integer; override; procedure UpdateView(Canvas: TCanvas); override; public constructor Create(ANode: TTreeNode; AQueueId: TOperationsManagerQueueIdentifier); reintroduce; procedure Click(const Pt: TPoint; Button: TMouseButton; Shift: TShiftState); override; procedure Draw(Canvas: TCanvas; NodeRect: TRect); override; function GetBackgroundColor: TColor; override; procedure StartPause; override; procedure Stop; override; end; TViewOperationItem = class; { TViewOperationItem } TViewOperationItem = class(TViewBaseItem) private FOperationHandle: TOperationHandle; FProgress: Double; function GetTextIndent: Integer; override; procedure UpdateView(Canvas: TCanvas); override; public constructor Create(ANode: TTreeNode; AOperationHandle: TOperationHandle); reintroduce; procedure Click(const Pt: TPoint; Button: TMouseButton; Shift: TShiftState); override; procedure Draw(Canvas: TCanvas; NodeRect: TRect); override; function GetBackgroundColor: TColor; override; procedure StartPause; override; procedure Stop; override; end; { TfrmViewOperations } TfrmViewOperations = class(TForm) btnStop: TBitBtn; btnStartPause: TBitBtn; cbAlwaysOnTop: TCheckBox; lblUseDragDrop: TLabel; mnuCancelQueue: TMenuItem; mnuNewQueue: TMenuItem; mnuCancelOperation: TMenuItem; mnuPutFirstInQueue: TMenuItem; mnuPutLastInQueue: TMenuItem; mnuOperationShowDetached: TMenuItem; mnuQueue2: TMenuItem; mnuQueue3: TMenuItem; mnuQueue5: TMenuItem; mnuQueue4: TMenuItem; mnuQueue1: TMenuItem; mnuQueue0: TMenuItem; mnuQueue: TMenuItem; mnuQueueShowDetached: TMenuItem; pnlHeader: TPanel; pmQueuePopup: TPopupMenu; pnlTopHeader: TPanel; pmOperationPopup: TPopupMenu; tbPauseAll: TToggleBox; tvOperations: TTreeView; UpdateTimer: TTimer; procedure btnStopClick(Sender: TObject); procedure cbAlwaysOnTopChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure mnuCancelOperationClick(Sender: TObject); procedure mnuCancelQueueClick(Sender: TObject); procedure mnuNewQueueClick(Sender: TObject); procedure mnuPutFirstInQueueClick(Sender: TObject); procedure mnuPutLastInQueueClick(Sender: TObject); procedure mnuOperationShowDetachedClick(Sender: TObject); procedure mnuQueueShowDetachedClick(Sender: TObject); procedure OnOperationItemContextMenu(Item: TViewBaseItem; const Point: TPoint); procedure OnOperationItemSelected(Item: TViewBaseItem); procedure OnQueueContextMenu(Item: TViewBaseItem; const Point: TPoint); procedure OnQueueItemSelected(Item: TViewBaseItem); procedure OnUpdateTimer(Sender: TObject); procedure btnStartPauseClick(Sender: TObject); procedure mnuQueueNumberClick(Sender: TObject); procedure tbPauseAllChange(Sender: TObject); procedure tvOperationsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); procedure tvOperationsDeletion(Sender: TObject; Node: TTreeNode); procedure tvOperationsDragDrop(Sender, Source: TObject; X, Y: Integer); procedure tvOperationsDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure tvOperationsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure tvOperationsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure tvOperationsResize(Sender: TObject); procedure tvOperationsSelectionChanged(Sender: TObject); private FDraggedOperation: TOperationHandle; FMenuOperation: TOperationHandle; FMenuQueueIdentifier: TOperationsManagerQueueIdentifier; procedure CreateNodes; function GetFocusedItem: TViewBaseItem; procedure MoveWithinQueue(MoveToTop: Boolean); procedure SetFocusItem(AOperationHandle: TOperationHandle); procedure SetFocusItem(AQueueIdentifier: TOperationsManagerQueueIdentifier); procedure SetNewQueue(Item: TViewOperationItem; NewQueue: TOperationsManagerQueueIdentifier); procedure SetStartPauseCaption(SetPause: Boolean); procedure UpdateView(Item: TOperationsManagerItem; Event: TOperationManagerEvent); procedure UpdateSizes; end; procedure ShowOperationsViewer; procedure ShowOperationsViewer(AOperationHandle: TOperationHandle); procedure ShowOperationsViewer(AQueueIdentifier: TOperationsManagerQueueIdentifier); implementation {$R *.lfm} uses GraphMath, GraphType, Math, fFileOpDlg, uLng, uGlobs, uFileSourceOperationMisc; const ExpandSignSize = 9; StatusIconPlay: array[0..2] of TPoint = ((x: 5; y: 1), (x: 13; y: 9), (x: 5; y: 17)); StatusIconPause1: array[0..3] of TPoint = ((x: 3; y: 2), (x: 3; y: 16), (x: 7; y: 16), (x: 7; y: 2)); StatusIconPause2: array[0..3] of TPoint = ((x: 10; y: 2), (x: 10; y: 16), (x: 14; y: 16), (x: 14; y: 2)); StatusIconHourglass1: array[0..2] of TPoint = ((x: 3; y: 4), (x: 13; y: 4), (x: 8; y: 10)); StatusIconHourglass2: array[0..2] of TPoint = ((x: 8; y: 10), (x: 13; y: 15), (x: 3; y: 15)); StatusIconFrame: TRect = (Left: 0; Top: 0; Right: 18; Bottom: 19); StatusIconRightMargin = 5; ProgressHeight = 16; ProgressWidth = 150; ProgressHorizontalMargin = 5; FreeOperationTextIndent = 3; MarginTopBottom = 2; var frmViewOperations: TfrmViewOperations = nil; ProgressRight: Integer; procedure ShowOperationsViewer; begin if not Assigned(frmViewOperations) then frmViewOperations := TfrmViewOperations.Create(Application); frmViewOperations.ShowOnTop; end; procedure ShowOperationsViewer(AOperationHandle: TOperationHandle); begin ShowOperationsViewer; if AOperationHandle <> InvalidOperationHandle then frmViewOperations.SetFocusItem(AOperationHandle); end; procedure ShowOperationsViewer(AQueueIdentifier: TOperationsManagerQueueIdentifier); begin ShowOperationsViewer; frmViewOperations.SetFocusItem(AQueueIdentifier); end; procedure ApplyProgress(var ARect: TRect; Progress: Double); begin ARect.Right := ARect.Left + Round((ARect.Right - ARect.Left) * Progress); end; function MoveRect(aRect: TRect; DeltaX, DeltaY: Integer): TRect; begin Result.Left := aRect.Left + DeltaX; Result.Right := aRect.Right + DeltaX; Result.Top := aRect.Top + DeltaY; Result.Bottom := aRect.Bottom + DeltaY; end; procedure DrawMovePolygon(Canvas: TCanvas; const Points: array of TPoint; DeltaX, DeltaY: Integer); var CopyPoints: PPoint; i: Integer; begin CopyPoints := GetMem(SizeOf(TPoint) * Length(Points)); for i := 0 to Length(Points) - 1 do begin CopyPoints[i].x := Points[i].x + DeltaX; CopyPoints[i].y := Points[i].y + DeltaY; end; Canvas.Polygon(CopyPoints, Length(Points), True); FreeMem(CopyPoints); end; { TViewBaseItem } procedure TViewBaseItem.DrawThemedBackground(Canvas: TCanvas; Element: TThemedTreeview; ARect: TRect); var Details: TThemedElementDetails; begin Details := ThemeServices.GetElementDetails(Element); if ThemeServices.HasTransparentParts(Details) then begin Canvas.Brush.Color := GetBackgroundColor; Canvas.FillRect(ARect); end; ThemeServices.DrawElement(Canvas.Handle, Details, ARect, nil); end; procedure TViewBaseItem.DrawProgress(Canvas: TCanvas; NodeRect: TRect; Progress: Double); var Details: TThemedElementDetails; begin if Progress > 0 then begin NodeRect.Right := NodeRect.Right - ProgressRight; NodeRect.Left := NodeRect.Right - ProgressWidth; NodeRect.Top := NodeRect.Top + (NodeRect.Bottom - NodeRect.Top - ProgressHeight) div 2; NodeRect.Bottom := NodeRect.Top + ProgressHeight; if ThemeServices.ThemesEnabled then begin Details := ThemeServices.GetElementDetails(tpBar); ThemeServices.DrawElement(Canvas.Handle, Details, NodeRect, nil); Details := ThemeServices.GetElementDetails(tpChunk); InflateRect(NodeRect, -2, -2); ApplyProgress(NodeRect, Progress); ThemeServices.DrawElement(Canvas.Handle, Details, NodeRect, nil); end else begin Canvas.Pen.Color := clWindowText; Canvas.Brush.Color := clForm; Canvas.RoundRect(NodeRect, 3, 3); Canvas.Brush.Color := clHighlight; ApplyProgress(NodeRect, Progress); Canvas.RoundRect(NodeRect, 3, 3); end; end; end; procedure TViewBaseItem.DrawStatusIcon(Canvas: TCanvas; NodeRect: TRect; Icon: TViewOperationsStatusIcon); var IconRect: TRect; begin Canvas.Brush.Color := GetBackgroundColor; Canvas.Pen.Color := clWindowText; IconRect := MoveRect(GetStatusIconRect(NodeRect), NodeRect.Left, NodeRect.Top); Canvas.Rectangle(IconRect); case Icon of vosiPlay: // Paint "Play" triangle begin Canvas.Brush.Color := RGBToColor(0, 200, 0); DrawMovePolygon(Canvas, StatusIconPlay, IconRect.Left, IconRect.Top); end; vosiPause: // Paint "Pause" double line begin Canvas.Brush.Color := RGBToColor(0, 0, 200); DrawMovePolygon(Canvas, StatusIconPause1, IconRect.Left, IconRect.Top); DrawMovePolygon(Canvas, StatusIconPause2, IconRect.Left, IconRect.Top); end; else // Paint "Hourglass" begin Canvas.Brush.Color := RGBToColor(255, 255, 255); DrawMovePolygon(Canvas, StatusIconHourglass1, IconRect.Left, IconRect.Top); DrawMovePolygon(Canvas, StatusIconHourglass2, IconRect.Left, IconRect.Top); end; end; end; procedure TViewBaseItem.DrawThemedText(Canvas: TCanvas; Element: TThemedTreeview; NodeRect: TRect; Center: Boolean; AText: String); var Details: TThemedElementDetails; Flags: Cardinal = DT_WORDBREAK or DT_NOPREFIX; begin Details := ThemeServices.GetElementDetails(Element); if Center then Flags := Flags + DT_VCENTER; ThemeServices.DrawText(Canvas, Details, AText, NodeRect, Flags, 0); end; function TViewBaseItem.GetStatusIconRect(NodeRect: TRect): TRect; begin Result := MoveRect(StatusIconFrame, (NodeRect.Right - NodeRect.Left) - (StatusIconFrame.Right - StatusIconFrame.Left) - StatusIconRightMargin, ((NodeRect.Bottom - NodeRect.Top) - (StatusIconFrame.Bottom - StatusIconFrame.Top)) div 2); end; constructor TViewBaseItem.Create(ANode: TTreeNode); begin FTreeNode := ANode; end; procedure TViewBaseItem.CalculateSizes(Canvas: TCanvas; NeedsStatusIcon, NeedsProgress: Boolean); var NodeRect: TRect; NeededHeight: Integer; begin // Calculate available width for text. NodeRect := FTreeNode.DisplayRect(False); FTextRect := Rect(0, 0, 0, 0); FTextRect.Right := (NodeRect.Right - NodeRect.Left) - GetTextIndent - (ProgressRight + ProgressWidth + ProgressHorizontalMargin); // Calculate text height. DrawText(Canvas.Handle, PChar(FText), Length(FText), FTextRect, DT_NOPREFIX + DT_CALCRECT + DT_WORDBREAK); // Take max of text, progress and status icon. NeededHeight := FTextRect.Bottom - FTextRect.Top; if NeedsProgress then NeededHeight := Max(NeededHeight, ProgressHeight); if NeedsStatusIcon then NeededHeight := Max(NeededHeight, StatusIconFrame.Bottom - StatusIconFrame.Top); Inc(NeededHeight, 2 * MarginTopBottom); FTextRect := MoveRect(FTextRect, NodeRect.Left + GetTextIndent, NodeRect.Top); FTreeNode.Height := NeededHeight; end; procedure TViewBaseItem.Click(const Pt: TPoint; Button: TMouseButton; Shift: TShiftState); var Handled: Boolean = False; begin case Button of mbRight: if Assigned(FOnContextMenu) then begin OnContextMenu(Self, Pt); Handled := True; end; end; if not Handled and Assigned(FOnClick) then FOnClick(Self, Button, Shift, Pt); end; procedure TViewBaseItem.KeyDown(var Key: Word; Shift: TShiftState); var Rect: TRect; Point: TPoint; begin case Key of VK_APPS: if Assigned(FOnContextMenu) then begin Rect := FTreeNode.DisplayRect(False); Point.x := Rect.Left + (Rect.Right - Rect.Left) div 2; Point.y := Rect.Top + (Rect.Bottom - Rect.Top) div 2; OnContextMenu(Self, Point); Key := 0; end; VK_SPACE: begin StartPause; Key := 0; end; VK_DELETE, VK_BACK: begin Stop; Key := 0; end; end; end; procedure TViewBaseItem.Selected; begin if Assigned(FOnSelected) then FOnSelected(Self); end; { TViewOperationItem } constructor TViewOperationItem.Create(ANode: TTreeNode; AOperationHandle: TOperationHandle); begin FOperationHandle := AOperationHandle; inherited Create(ANode); end; procedure TViewOperationItem.Click(const Pt: TPoint; Button: TMouseButton; Shift: TShiftState); var Handled: Boolean = False; OpManItem: TOperationsManagerItem; NodeRect: TRect; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then begin case Button of mbLeft: if OpManItem.Queue.IsFree then begin NodeRect := FTreeNode.DisplayRect(False); if ((ssDouble in Shift) or PtInRect(GetStatusIconRect(NodeRect), Pt)) then begin StartPause; Handled := True; end; end; end; end; if not Handled then inherited Click(Pt, Button, Shift); end; procedure TViewOperationItem.Draw(Canvas: TCanvas; NodeRect: TRect); var OpManItem: TOperationsManagerItem; Element: TThemedTreeview; Icon: TViewOperationsStatusIcon; begin if FTreeNode.Selected then Element := ttItemSelected else Element := ttItemNormal; DrawThemedBackground(Canvas, Element, NodeRect); OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then begin DrawThemedText(Canvas, Element, FTextRect, True, FText); if OpManItem.Queue.IsFree then begin case OpManItem.Operation.State of fsosRunning: Icon := vosiPlay; fsosPaused: Icon := vosiPause; else Icon := vosiHourglass; end; DrawStatusIcon(Canvas, NodeRect, Icon); end; DrawProgress(Canvas, NodeRect, FProgress); end; end; function TViewOperationItem.GetBackgroundColor: TColor; begin Result := FTreeNode.TreeView.BackgroundColor; end; procedure TViewOperationItem.StartPause; var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) and OpManItem.Queue.IsFree then OpManItem.Operation.TogglePause; end; procedure TViewOperationItem.Stop; var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then OpManItem.Operation.Stop; end; procedure TViewOperationItem.UpdateView(Canvas: TCanvas); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FOperationHandle); if Assigned(OpManItem) then begin FText := IntToStr(OpManItem.Handle) + ': ' + OpManItem.Operation.GetDescription(fsoddJobAndTarget); FProgress := OpManItem.Operation.Progress; if FProgress > 0 then FText := FText + ' - ' + GetProgressString(FProgress); FText := FText + GetOperationStateString(OpManItem.Operation.State); CalculateSizes(Canvas, OpManItem.Queue.IsFree, FProgress > 0); end else begin FText := ''; FProgress := 0; FTreeNode.Height := 10; end; end; function TViewOperationItem.GetTextIndent: Integer; begin Result := FTreeNode.DisplayExpandSignLeft; if FTreeNode.Level = 0 then Inc(Result, FreeOperationTextIndent) else Dec(Result, TTreeView(FTreeNode.TreeView).Indent * (FTreeNode.Level - 1)); end; { TViewQueueItem } procedure TViewQueueItem.Click(const Pt: TPoint; Button: TMouseButton; Shift: TShiftState); var Handled: Boolean = False; NodeRect: TRect; begin case Button of mbLeft: begin NodeRect := FTreeNode.DisplayRect(False); if (ssDouble in Shift) or PtInRect(GetStatusIconRect(NodeRect), Pt) then begin StartPause; Handled := True; end; end; end; if not Handled then inherited Click(Pt, Button, Shift); end; constructor TViewQueueItem.Create(ANode: TTreeNode; AQueueId: TOperationsManagerQueueIdentifier); begin FQueueIdentifier := AQueueId; inherited Create(ANode); end; procedure TViewQueueItem.Draw(Canvas: TCanvas; NodeRect: TRect); var Element: TThemedTreeview; Queue: TOperationsManagerQueue; Icon: TViewOperationsStatusIcon; begin if FTreeNode.Selected then Element := ttItemSelected else Element := ttItemSelectedNotFocus; DrawThemedBackground(Canvas, Element, NodeRect); Queue := OperationsManager.QueueByIdentifier[FQueueIdentifier]; if Assigned(Queue) then begin DrawThemedText(Canvas, Element, FTextRect, True, FText); if Queue.Paused then Icon := vosiPause else Icon := vosiPlay; DrawStatusIcon(Canvas, NodeRect, Icon); end; end; function TViewQueueItem.GetBackgroundColor: TColor; begin Result := FTreeNode.TreeView.BackgroundColor; end; function TViewQueueItem.GetTextIndent: Integer; var ATreeView: TCustomTreeView; begin Result := FTreeNode.DisplayExpandSignLeft; ATreeView := FTreeNode.TreeView; if ATreeView is TTreeView then Inc(Result, TTreeView(ATreeView).Indent); end; procedure TViewQueueItem.StartPause; var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[FQueueIdentifier]; if Assigned(Queue) then Queue.TogglePause; end; procedure TViewQueueItem.Stop; var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[FQueueIdentifier]; if Assigned(Queue) then begin Queue.Stop; end; end; procedure TViewQueueItem.UpdateView(Canvas: TCanvas); var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[FQueueIdentifier]; if Assigned(Queue) then begin FText := Queue.GetDescription(False); if Queue.Paused then FText := FText + GetOperationStateString(fsosPaused); CalculateSizes(Canvas, True, False); end else begin FText := ''; FTreeNode.Height := 10; end; end; { TfrmViewOperations } procedure TfrmViewOperations.FormCreate(Sender: TObject); begin InitPropStorage(Self); cbAlwaysOnTopChange(nil); FMenuOperation := InvalidOperationHandle; tvOperations.DoubleBuffered := True; DoubleBuffered := True; CreateNodes; OperationsManager.AddEventsListener( [omevOperationAdded, omevOperationRemoved, omevOperationMoved], @UpdateView); tvOperations.OnResize := @tvOperationsResize; end; procedure TfrmViewOperations.btnStopClick(Sender: TObject); var Item: TViewBaseItem; begin Item := GetFocusedItem; if Assigned(Item) then Item.Stop; end; procedure TfrmViewOperations.cbAlwaysOnTopChange(Sender: TObject); begin if cbAlwaysOnTop.Checked then begin FormStyle := fsStayOnTop; ShowInTaskBar := stDefault; end else begin FormStyle := fsNormal; ShowInTaskBar := stAlways; end; end; procedure TfrmViewOperations.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction := caFree; frmViewOperations := nil; end; procedure TfrmViewOperations.FormDestroy(Sender: TObject); begin OperationsManager.RemoveEventsListener( [omevOperationAdded, omevOperationRemoved, omevOperationMoved], @UpdateView); end; procedure TfrmViewOperations.mnuNewQueueClick(Sender: TObject); var Item: TViewBaseItem; OpManItem: TOperationsManagerItem; begin Item := GetFocusedItem; if Assigned(Item) and (Item is TViewOperationItem) then begin OpManItem := OperationsManager.GetItemByHandle(TViewOperationItem(Item).FOperationHandle); if Assigned(OpManItem) then OpManItem.MoveToNewQueue; end; end; procedure TfrmViewOperations.mnuPutFirstInQueueClick(Sender: TObject); begin MoveWithinQueue(True); end; procedure TfrmViewOperations.mnuPutLastInQueueClick(Sender: TObject); begin MoveWithinQueue(False); end; procedure TfrmViewOperations.mnuOperationShowDetachedClick(Sender: TObject); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FMenuOperation); if Assigned(OpManItem) and OpManItem.Queue.IsFree then TfrmFileOp.ShowFor(OpManItem.Handle, [opwoIfExistsBringToFront]); end; procedure TfrmViewOperations.OnOperationItemContextMenu(Item: TViewBaseItem; const Point: TPoint); var i: Integer; PopupPoint: TPoint; OpManItem: TOperationsManagerItem; begin FMenuOperation := (Item as TViewOperationItem).FOperationHandle; OpManItem := OperationsManager.GetItemByHandle(FMenuOperation); if Assigned(OpManItem) then begin for i := 0 to mnuQueue.Count - 1 do if i = OpManItem.Queue.Identifier then mnuQueue.Items[i].Checked := True else mnuQueue.Items[i].Checked := False; mnuOperationShowDetached.Enabled := OpManItem.Queue.IsFree; PopupPoint := tvOperations.ClientToScreen(Point); pmOperationPopup.PopUp(PopupPoint.x, PopupPoint.y); end; end; procedure TfrmViewOperations.OnOperationItemSelected(Item: TViewBaseItem); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(TViewOperationItem(Item).FOperationHandle); if Assigned(OpManItem) then begin SetStartPauseCaption(OpManItem.Operation.State in [fsosStarting, fsosRunning, fsosWaitingForConnection]); btnStartPause.Enabled := OpManItem.Queue.IsFree; btnStop.Enabled := True; end else begin btnStartPause.Enabled := False; btnStop.Enabled := False; end; end; procedure TfrmViewOperations.OnQueueContextMenu(Item: TViewBaseItem; const Point: TPoint); var PopupPoint: TPoint; begin FMenuQueueIdentifier := (Item as TViewQueueItem).FQueueIdentifier; PopupPoint := tvOperations.ClientToScreen(Point); pmQueuePopup.PopUp(PopupPoint.x, PopupPoint.y); end; procedure TfrmViewOperations.OnQueueItemSelected(Item: TViewBaseItem); var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[TViewQueueItem(Item).FQueueIdentifier]; if Assigned(Queue) then begin SetStartPauseCaption(not Queue.Paused); btnStartPause.Enabled := True; end else begin btnStartPause.Enabled := False; end; btnStop.Enabled := btnStartPause.Enabled; end; procedure TfrmViewOperations.OnUpdateTimer(Sender: TObject); begin UpdateSizes; tvOperationsSelectionChanged(tvOperations); tvOperations.Invalidate; end; procedure TfrmViewOperations.mnuQueueNumberClick(Sender: TObject); var NewQueueNumber: integer; Item: TViewBaseItem; begin if TryStrToInt(Copy((Sender as TMenuItem).Name, 9, 1), NewQueueNumber) then begin Item := GetFocusedItem; if Assigned(Item) and (Item is TViewOperationItem) then SetNewQueue(TViewOperationItem(Item), NewQueueNumber); end; end; procedure TfrmViewOperations.mnuQueueShowDetachedClick(Sender: TObject); var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[FMenuQueueIdentifier]; if Assigned(Queue) then TfrmFileOp.ShowFor(Queue.Identifier, [opwoIfExistsBringToFront]); end; procedure TfrmViewOperations.tbPauseAllChange(Sender: TObject); begin if tbPauseAll.State = cbChecked then OperationsManager.PauseAll else OperationsManager.UnPauseAll; end; procedure TfrmViewOperations.tvOperationsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); var Item: TViewBaseItem; NodeRect: TRect; procedure DrawExpandSign(MidX, MidY: integer; CollapseSign: boolean); const ExpandSignColor = clWindowText; var HalfSize, ALeft, ATop, ARight, ABottom: integer; Points: array [0..2] of TPoint; R: TRect; begin with Sender.Canvas do begin Brush.Color := clWindow; Pen.Color := ExpandSignColor; Pen.Style := psSolid; HalfSize := ExpandSignSize shr 1; if not Odd(ExpandSignSize) then dec(HalfSize); ALeft := MidX - HalfSize; ATop := MidY - HalfSize; ARight := ALeft + ExpandSignSize; ABottom := ATop + ExpandSignSize; // draw an arrow. down for collapse and right for expand R := Rect(ALeft, ATop, ARight, ABottom); if CollapseSign then begin // draw an arrow down Points[0] := Point(R.Left, MidY); Points[1] := Point(R.Right - 1, MidY); Points[2] := Point(MidX, R.Bottom - 1); end else begin // draw an arrow right Points[0] := Point(MidX - 1, ATop); Points[1] := Point(R.Right - 2, MidY); Points[2] := Point(MidX - 1, R.Bottom - 1); end; Polygon(Points, False); end; end; var VertMid: Integer; begin if not Assigned(Node.Data) then Exit; Item := TViewBaseItem(Node.Data); NodeRect := Node.DisplayRect(False); Item.Draw(Sender.Canvas, NodeRect); if tvOperations.ShowButtons and Node.HasChildren and ((tvoShowRoot in tvOperations.Options) or (Node.Parent <> nil)) then begin VertMid := (NodeRect.Top + NodeRect.Bottom) div 2; DrawExpandSign(Node.DisplayExpandSignLeft + tvOperations.Indent shr 1, VertMid, Node.Expanded); end; // draw separator if (tvoShowSeparators in tvOperations.Options) then begin Sender.Canvas.Pen.Color:=tvOperations.SeparatorColor; Sender.Canvas.MoveTo(NodeRect.Left,NodeRect.Bottom-1); Sender.Canvas.LineTo(NodeRect.Right,NodeRect.Bottom-1); end; DefaultDraw := False; end; procedure TfrmViewOperations.tvOperationsDeletion(Sender: TObject; Node: TTreeNode); var Item: TViewBaseItem; begin Item := TViewBaseItem(Node.Data); Node.Data := nil; Item.Free; end; procedure TfrmViewOperations.tvOperationsDragDrop(Sender, Source: TObject; X, Y: Integer); var TargetNode: TTreeNode; NodeRect: TRect; TargetItem: TViewBaseItem; QueueItem: TViewQueueItem; OperItem: TViewOperationItem; SourceOpManItem, TargetOpManItem: TOperationsManagerItem; TargetQueue: TOperationsManagerQueue; TargetQueueId: TOperationsManagerQueueIdentifier; HitTopPart: Boolean; begin if Source = tvOperations then begin SourceOpManItem := OperationsManager.GetItemByHandle(FDraggedOperation); if Assigned(SourceOpManItem) then begin TargetNode := tvOperations.GetNodeAt(X, Y); if not Assigned(TargetNode) then begin SourceOpManItem.MoveToNewQueue; end else begin NodeRect := TargetNode.DisplayRect(False); TargetItem := TViewBaseItem(TargetNode.Data); HitTopPart := Y - NodeRect.Top < (NodeRect.Bottom - NodeRect.Top) div 2; if TargetItem is TViewQueueItem then begin QueueItem := TViewQueueItem(TargetItem); if HitTopPart and (TargetNode = tvOperations.Items.GetFirstNode) and (QueueItem.FQueueIdentifier <> FreeOperationsQueueId) then begin // There are no free operations and item was dropped at the top of the list // on some queue. Create a free operations queue and move to it. TargetQueueId := FreeOperationsQueueId; TargetQueue := OperationsManager.GetOrCreateQueue(TargetQueueId); end else begin TargetQueueId := QueueItem.FQueueIdentifier; TargetQueue := OperationsManager.QueueByIdentifier[TargetQueueId]; end; SourceOpManItem.SetQueue(TargetQueue); end else if (TargetItem is TViewOperationItem) and (FDraggedOperation <> TViewOperationItem(TargetItem).FOperationHandle) then begin OperItem := TViewOperationItem(TargetItem); TargetOpManItem := OperationsManager.GetItemByHandle(OperItem.FOperationHandle); if Assigned(TargetOpManItem) then SourceOpManItem.Move(TargetOpManItem.Handle, HitTopPart); end; end; end; end; end; procedure TfrmViewOperations.tvOperationsDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := True; end; procedure TfrmViewOperations.tvOperationsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var Item: TViewBaseItem; begin Item := GetFocusedItem; if Assigned(Item) then Item.KeyDown(Key, Shift); end; procedure TfrmViewOperations.tvOperationsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Node: TTreeNode; NodeRect: TRect; begin FDraggedOperation := InvalidOperationHandle; Node := tvOperations.GetNodeAt(X, Y); if Assigned(Node) then begin NodeRect := Node.DisplayRect(False); TViewBaseItem(Node.Data).Click(Point(X - NodeRect.Left, Y - NodeRect.Top), Button, Shift); if TViewBaseItem(Node.Data) is TViewOperationItem then FDraggedOperation := TViewOperationItem(Node.Data).FOperationHandle; end; end; procedure TfrmViewOperations.tvOperationsResize(Sender: TObject); begin UpdateSizes; end; procedure TfrmViewOperations.tvOperationsSelectionChanged(Sender: TObject); var Node: TTreeNode; begin Node := tvOperations.Selected; if Assigned(Node) then TViewBaseItem(Node.Data).Selected; end; function TfrmViewOperations.GetFocusedItem: TViewBaseItem; var Node: TTreeNode; begin Node := tvOperations.Selected; if Assigned(Node) then Result := TViewBaseItem(Node.Data) else Result := nil; end; procedure TfrmViewOperations.mnuCancelOperationClick(Sender: TObject); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(FMenuOperation); if Assigned(OpManItem) then OpManItem.Operation.Stop; end; procedure TfrmViewOperations.mnuCancelQueueClick(Sender: TObject); var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[FMenuQueueIdentifier]; if Assigned(Queue) then Queue.Stop; end; procedure TfrmViewOperations.MoveWithinQueue(MoveToTop: Boolean); var Item: TViewBaseItem; OpManItem: TOperationsManagerItem; begin Item := GetFocusedItem; if Assigned(Item) and (Item is TViewOperationItem) then begin OpManItem := OperationsManager.GetItemByHandle(TViewOperationItem(Item).FOperationHandle); if Assigned(OpManItem) then begin if OpManItem.Queue.Identifier <> FreeOperationsQueueId then begin if MoveToTop then OpManItem.MoveToTop else OpManItem.MoveToBottom; end; end; end; end; procedure TfrmViewOperations.SetFocusItem(AOperationHandle: TOperationHandle); var Node: TTreeNode; begin for Node in tvOperations.Items do begin if (TViewBaseItem(Node.Data) is TViewOperationItem) and (TViewOperationItem(Node.Data).FOperationHandle = AOperationHandle) then begin Node.Selected := True; Exit; end; end; end; procedure TfrmViewOperations.SetFocusItem(AQueueIdentifier: TOperationsManagerQueueIdentifier); var Node: TTreeNode; begin for Node in tvOperations.Items do begin if (TViewBaseItem(Node.Data) is TViewQueueItem) and (TViewQueueItem(Node.Data).FQueueIdentifier = AQueueIdentifier) then begin Node.Selected := True; Exit; end; end; end; procedure TfrmViewOperations.SetNewQueue(Item: TViewOperationItem; NewQueue: TOperationsManagerQueueIdentifier); var OpManItem: TOperationsManagerItem; begin OpManItem := OperationsManager.GetItemByHandle(Item.FOperationHandle); if Assigned(OpManItem) then OpManItem.SetQueue(OperationsManager.GetOrCreateQueue(NewQueue)); end; procedure TfrmViewOperations.SetStartPauseCaption(SetPause: Boolean); begin if SetPause then btnStartPause.Caption := rsDlgOpPause else btnStartPause.Caption := rsDlgOpStart; end; procedure TfrmViewOperations.btnStartPauseClick(Sender: TObject); var Item: TViewBaseItem; begin Item := GetFocusedItem; if Assigned(Item) then Item.StartPause; end; procedure TfrmViewOperations.CreateNodes; procedure AddOperations(Queue: TOperationsManagerQueue; QueueNode: TTreeNode); var OperIndex: Integer; OpManItem: TOperationsManagerItem; OperNode: TTreeNode; Item: TViewBaseItem; begin for OperIndex := 0 to Queue.Count - 1 do begin OpManItem := Queue.Items[OperIndex]; OperNode := tvOperations.Items.AddChild(QueueNode, ''); Item := TViewOperationItem.Create(OperNode, OpManItem.Handle); OperNode.Data := Item; Item.UpdateView(tvOperations.Canvas); Item.OnContextMenu := @OnOperationItemContextMenu; Item.OnSelected := @OnOperationItemSelected; end; end; var QueueIndex: Integer; Queue: TOperationsManagerQueue; QueueNode: TTreeNode; Item: TViewBaseItem; begin tvOperations.Items.Clear; // First add all free operations. Queue := OperationsManager.QueueByIdentifier[FreeOperationsQueueId]; if Assigned(Queue) then AddOperations(Queue, nil); for QueueIndex := 0 to OperationsManager.QueuesCount - 1 do begin Queue := OperationsManager.QueueByIndex[QueueIndex]; if Queue.Identifier <> FreeOperationsQueueId then begin QueueNode := tvOperations.Items.AddChild(nil, ''); Item := TViewQueueItem.Create(QueueNode, Queue.Identifier); QueueNode.Data := Item; Item.UpdateView(tvOperations.Canvas); Item.OnContextMenu := @OnQueueContextMenu; Item.OnSelected := @OnQueueItemSelected; AddOperations(Queue, QueueNode); end; end; end; procedure TfrmViewOperations.UpdateSizes; var Node: TTreeNode; begin Node := tvOperations.Items.GetFirstNode; while Assigned(Node) do begin if Assigned(Node.Data) then TViewBaseItem(Node.Data).UpdateView(tvOperations.Canvas); Node := Node.GetNext; end; end; procedure TfrmViewOperations.UpdateView(Item: TOperationsManagerItem; Event: TOperationManagerEvent); begin CreateNodes; tvOperations.Invalidate; end; initialization ProgressRight := ProgressHorizontalMargin + StatusIconRightMargin + (StatusIconFrame.Right - StatusIconFrame.Left); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/����������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015221� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/git2revisioninc.cmd���������������������������������������������������0000755�0001750�0000144�00000000754�14743153644�021035� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh mkdir -p $1 export REVISION_INC=$1/dcrevision.inc rm -f $REVISION_INC cp ../units/dcrevision.inc $REVISION_INC export REVISION=$(git -C $1 rev-list --count 3e11343..HEAD) export COMMIT=$(git -C $1 rev-parse --short HEAD) if [ $REVISION ] && [ $COMMIT ]; then echo "// Created by Git2RevisionInc" > $REVISION_INC echo "const dcRevision = '$REVISION';" >> $REVISION_INC echo "const dcCommit = '$COMMIT';" >> $REVISION_INC fi echo "Git revision" $REVISION $COMMIT ��������������������doublecmd-1.1.22/src/platform/git2revisioninc.exe.cmd�����������������������������������������������0000644�0001750�0000144�00000001365�14743153644�021611� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@echo off if not exist "%1" ( md "%1" ) set REVISION_TXT="%1\revision.txt" set REVISION_INC="%1\dcrevision.inc" del /Q %REVISION_TXT% 2> nul del /Q %REVISION_INC% 2> nul copy ..\units\dcrevision.inc %REVISION_INC% > nul git -C %1 rev-list --count 3e11343..HEAD > %REVISION_TXT% IF ERRORLEVEL 1 goto EXIT set /P REVISION=<%REVISION_TXT% echo %REVISION% | find "fatal:" > nul IF NOT ERRORLEVEL 1 goto EXIT git -C %1 rev-parse --short HEAD > %REVISION_TXT% IF ERRORLEVEL 1 goto EXIT set /P COMMIT=<%REVISION_TXT% echo // Created by Git2RevisionInc> %REVISION_INC% echo const dcRevision = '%REVISION%';>> %REVISION_INC% echo const dcCommit = '%COMMIT%';>> %REVISION_INC% :EXIT echo Git revision %REVISION% %COMMIT%���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/lua.pas���������������������������������������������������������������0000644�0001750�0000144�00000135462�14743153644�016522� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* * A Pascal wrapper for Lua 5.1-5.4 library. * * Created by Geo Massar, 2006 * Distributed as free/open source. * 2008 Added dynamically library loading by Dmitry Kolomiets (B4rr4cuda@rambler.ru) * 2018-2023 Added Lua 5.2 - 5.4 library support by Alexander Koblov (alexx2000@mail.ru) *) unit lua; {$mode delphi} interface uses DynLibs; type size_t = SizeUInt; Psize_t = ^size_t; lua_State = record end; Plua_State = ^lua_State; const {$IF DEFINED(MSWINDOWS)} LuaDLL = 'lua5.1.dll'; {$ELSEIF DEFINED(DARWIN)} LuaDLL = 'liblua5.1.dylib'; {$ELSEIF DEFINED(UNIX)} LuaDLL = 'liblua5.1.so.0'; {$ENDIF} (* formats for Lua numbers *) {$IFNDEF LUA_NUMBER_SCAN} const LUA_NUMBER_SCAN = '%lf'; {$ENDIF} {$IFNDEF LUA_NUMBER_FMT} const LUA_NUMBER_FMT = '%.14g'; {$ENDIF} {$IFNDEF LUA_INTEGER_FMT} const LUA_INTEGER_FMT = '%d'; {$ENDIF} function LoadLuaLib(FileName: String): Boolean; procedure UnloadLuaLib; function IsLuaLibLoaded: Boolean; (*****************************************************************************) (* luaconfig.h *) (*****************************************************************************) (* ** $Id: luaconf.h,v 1.81 2006/02/10 17:44:06 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h *) (* ** {================================================================== @@ LUA_NUMBER is the type of numbers in Lua. ** CHANGE the following definitions only if you want to build Lua ** with a number type different from double. You may also need to ** change lua_number2int & lua_number2integer. ** =================================================================== *) type LUA_NUMBER_ = type Double; // ending underscore is needed in Pascal LUA_INTEGER_ = type Int64; (* @@ LUA_IDSIZE gives the maximum size for the description of the source @* of a function in debug information. ** CHANGE it if you want a different size. *) const LUA_IDSIZE = 60; (* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. *) var LUAL_BUFFERSIZE: Integer; (* @@ LUA_PROMPT is the default prompt used by stand-alone Lua. @@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. ** CHANGE them if you want different prompts. (You can also change the ** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) *) const LUA_PROMPT = '> '; LUA_PROMPT2 = '>> '; (* @@ lua_readline defines how to show a prompt and then read a line from @* the standard input. @@ lua_saveline defines how to "save" a read line in a "history". @@ lua_freeline defines how to free a line read by lua_readline. ** CHANGE them if you want to improve this functionality (e.g., by using ** GNU readline and history facilities). *) function lua_readline(L : Plua_State; var b : PChar; p : PChar): Boolean; procedure lua_saveline(L : Plua_State; idx : Integer); procedure lua_freeline(L : Plua_State; b : PChar); (* @@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that @* is, whether we're running lua interactively). ** CHANGE it if you have a better definition for non-POSIX/non-Windows ** systems. */ #include <io.h> #include <stdio.h> #define lua_stdin_is_tty() _isatty(_fileno(stdin)) *) const lua_stdin_is_tty = TRUE; (*****************************************************************************) (* lua.h *) (*****************************************************************************) (* ** $Id: lua.h,v 1.216 2006/01/10 12:50:13 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file *) const LUA_VERSION_ = 'Lua 5.1'; LUA_VERSION_NUM = 501; LUA_COPYRIGHT = 'Copyright (C) 1994-2006 Tecgraf, PUC-Rio'; LUA_AUTHORS = 'R. Ierusalimschy, L. H. de Figueiredo & W. Celes'; (* mark for precompiled code (`<esc>Lua') *) LUA_SIGNATURE = #27'Lua'; (* option for multiple returns in `lua_pcall' and `lua_call' *) LUA_MULTRET = -1; var (* ** pseudo-indices *) LUA_REGISTRYINDEX: Integer; function lua_upvalueindex(idx : Integer) : Integer; // a marco const (* thread status; 0 is OK *) LUA_YIELD_ = 1; // Note: the ending underscore is needed in Pascal LUA_ERRRUN = 2; LUA_ERRSYNTAX = 3; LUA_ERRMEM = 4; LUA_ERRERR = 5; type // Type for continuation-function contexts lua_KContext = Pointer; // Type for continuation functions lua_KFunction = function(L : Plua_State; status: Integer; ctx: lua_KContext): Integer; cdecl; // Type for C functions registered with Lua lua_CFunction = function(L : Plua_State) : Integer; cdecl; (* ** functions that read/write blocks when loading/dumping Lua chunks *) lua_Reader = function (L : Plua_State; ud : Pointer; sz : Psize_t) : PChar; cdecl; lua_Writer = function (L : Plua_State; const p : Pointer; sz : size_t; ud : Pointer) : Integer; cdecl; (* ** prototype for memory-allocation functions *) lua_Alloc = function (ud, ptr : Pointer; osize, nsize : size_t) : Pointer; cdecl; const (* ** basic types *) LUA_TNONE = -1; LUA_TNIL = 0; LUA_TBOOLEAN = 1; LUA_TLIGHTUSERDATA = 2; LUA_TNUMBER = 3; LUA_TSTRING = 4; LUA_TTABLE = 5; LUA_TFUNCTION = 6; LUA_TUSERDATA = 7; LUA_TTHREAD = 8; (* minimum Lua stack available to a C function *) LUA_MINSTACK = 20; type (* type of numbers in Lua *) lua_Number = LUA_NUMBER_; Plua_Number = ^lua_Number; (* type for integer functions *) lua_Integer = LUA_INTEGER_; (* ** state manipulation *) var lua_newstate: function (f : lua_Alloc; ud : Pointer) : Plua_State; cdecl; lua_close: procedure (L: Plua_State); cdecl; lua_newthread: function (L : Plua_State) : Plua_State; cdecl; lua_atpanic: function (L : Plua_State; panicf : lua_CFunction) : lua_CFunction; cdecl; (* ** basic stack manipulation *) var lua_gettop: function (L : Plua_State) : Integer; cdecl; lua_settop: procedure (L : Plua_State; idx : Integer); cdecl; lua_pushvalue: procedure (L : Plua_State; idx : Integer); cdecl; lua_rotate: procedure (L : Plua_State; idx, n: Integer); cdecl; lua_remove: procedure (L : Plua_State; idx : Integer); cdecl; lua_insert: procedure (L : Plua_State; idx : Integer); cdecl; lua_replace: procedure (L : Plua_State; idx : Integer); cdecl; lua_copy: procedure (L : Plua_State; fromidx, toidx: Integer); cdecl; lua_checkstack: function (L : Plua_State; sz : Integer) : LongBool; cdecl; lua_xmove: procedure (src, dest : Plua_State; n : Integer); cdecl; (* ** access functions (stack -> C) *) lua_isnumber: function (L : Plua_State; idx : Integer) : LongBool; cdecl; lua_isstring: function (L : Plua_State; idx : Integer) : LongBool; cdecl; lua_iscfunction: function (L : Plua_State; idx : Integer) : LongBool; cdecl; lua_isinteger: function (L: Plua_State; idx: Integer) : LongBool; cdecl; lua_isuserdata: function (L : Plua_State; idx : Integer) : LongBool; cdecl; lua_type: function (L : Plua_State; idx : Integer) : Integer; cdecl; lua_typename: function (L : Plua_State; tp : Integer) : PChar; cdecl; lua_equal: function (L : Plua_State; idx1, idx2 : Integer) : LongBool; cdecl; lua_rawequal: function (L : Plua_State; idx1, idx2 : Integer) : LongBool; cdecl; lua_lessthan: function (L : Plua_State; idx1, idx2 : Integer) : LongBool; cdecl; lua_toboolean: function (L : Plua_State; idx : Integer) : LongBool; cdecl; lua_tolstring: function (L : Plua_State; idx : Integer; len : Psize_t) : PChar; cdecl; lua_tocfunction: function (L : Plua_State; idx : Integer) : lua_CFunction; cdecl; lua_touserdata: function (L : Plua_State; idx : Integer) : Pointer; cdecl; lua_tothread: function (L : Plua_State; idx : Integer) : Plua_State; cdecl; lua_topointer: function (L : Plua_State; idx : Integer) : Pointer; cdecl; function lua_tonumber(L : Plua_State; idx : Integer) : lua_Number; function lua_tointeger(L : Plua_State; idx : Integer) : lua_Integer; function lua_objlen(L : Plua_State; idx : Integer) : size_t; (* ** push functions (C -> stack) *) var lua_pushnil: procedure (L : Plua_State); cdecl; lua_pushnumber: procedure (L : Plua_State; n : lua_Number); cdecl; lua_pushlstring: procedure (L : Plua_State; const s : PChar; ls : size_t); cdecl; lua_pushvfstring: function (L : Plua_State; const fmt : PChar; argp : Pointer) : PChar; cdecl; lua_pushfstring: function (L : Plua_State; const fmt : PChar) : PChar; varargs; cdecl; lua_pushcclosure: procedure (L : Plua_State; fn : lua_CFunction; n : Integer); cdecl; lua_pushboolean: procedure (L : Plua_State; b : LongBool); cdecl; lua_pushlightuserdata: procedure (L : Plua_State; p : Pointer); cdecl; lua_pushthread: function (L : Plua_state) : Cardinal; cdecl; procedure lua_pushinteger(L : Plua_State; n : lua_Integer); var (* ** get functions (Lua -> stack) *) lua_gettable: procedure (L : Plua_State ; idx : Integer); cdecl; lua_getfield: procedure (L : Plua_State; idx : Integer; k : PChar); cdecl; lua_rawget: procedure (L : Plua_State; idx : Integer); cdecl; lua_rawgeti: procedure (L : Plua_State; idx, n : Integer); cdecl; lua_createtable: procedure (L : Plua_State; narr, nrec : Integer); cdecl; lua_getmetatable: function (L : Plua_State; objindex : Integer) : LongBool; cdecl; lua_getfenv: procedure (L : Plua_State; idx : Integer); cdecl; (* ** set functions (stack -> Lua) *) lua_settable: procedure (L : Plua_State; idx : Integer); cdecl; lua_setfield: procedure (L : Plua_State; idx : Integer; const k : PChar); cdecl; lua_rawset: procedure (L : Plua_State; idx : Integer); cdecl; lua_rawseti: procedure (L : Plua_State; idx , n: Integer); cdecl; lua_setmetatable: function (L : Plua_State; objindex : Integer): LongBool; cdecl; lua_setfenv: function (L : Plua_State; idx : Integer): LongBool; cdecl; procedure lua_setglobal(L: Plua_State; const name : PAnsiChar); procedure lua_getglobal(L: Plua_State; const name : PAnsiChar); function lua_newuserdata(L : Plua_State; sz : size_t) : Pointer; (* ** `load' and `call' functions (load and run Lua code) *) var lua_call: procedure (L : Plua_State; nargs, nresults : Integer); cdecl; lua_cpcall: function (L : Plua_State; func : lua_CFunction; ud : Pointer) : Integer; cdecl; lua_load: function (L : Plua_State; reader : lua_Reader; dt : Pointer; const chunkname : PChar) : Integer; cdecl; lua_dump: function (L : Plua_State; writer : lua_Writer; data: Pointer) : Integer; cdecl; function lua_pcall(L : Plua_State; nargs, nresults, errfunc : Integer) : Integer; (* ** coroutine functions *) var lua_yield: function (L : Plua_State; nresults : Integer) : Integer; cdecl; lua_status: function (L : Plua_State) : Integer; cdecl; function lua_resume(L : Plua_State; narg : Integer; nresults : PInteger) : Integer; (* ** garbage-collection functions and options *) const LUA_GCSTOP = 0; LUA_GCRESTART = 1; LUA_GCCOLLECT = 2; LUA_GCCOUNT = 3; LUA_GCCOUNTB = 4; LUA_GCSTEP = 5; LUA_GCSETPAUSE = 6; LUA_GCSETSTEPMUL = 7; var lua_gc: function(L : Plua_State; what, data : Integer):Integer; cdecl; (* ** miscellaneous functions *) var lua_error: function (L : Plua_State) : Integer; cdecl; lua_next: function (L : Plua_State; idx : Integer) : Integer; cdecl; lua_concat: procedure (L : Plua_State; n : Integer); cdecl; lua_getallocf: function (L : Plua_State; ud : PPointer) : lua_Alloc; cdecl; lua_setallocf: procedure (L : Plua_State; f : lua_Alloc; ud : Pointer); cdecl; (* ** =============================================================== ** some useful macros ** =============================================================== *) procedure lua_pop(L : Plua_State; n : Integer); procedure lua_newtable(L : Plua_State); procedure lua_register(L : Plua_State; n : PChar; f : lua_CFunction); procedure lua_pushcfunction(L : Plua_State; f : lua_CFunction); function lua_strlen(L : Plua_State; idx : Integer) : Integer; function lua_isfunction(L : Plua_State; n : Integer) : Boolean; function lua_istable(L : Plua_State; n : Integer) : Boolean; function lua_islightuserdata(L : Plua_State; n : Integer) : Boolean; function lua_isnil(L : Plua_State; n : Integer) : Boolean; function lua_isboolean(L : Plua_State; n : Integer) : Boolean; function lua_isthread(L : Plua_State; n : Integer) : Boolean; function lua_isnone(L : Plua_State; n : Integer) : Boolean; function lua_isnoneornil(L : Plua_State; n : Integer) : Boolean; procedure lua_pushliteral(L : Plua_State; s : PChar); procedure lua_pushstring(L : Plua_State; const S : PChar); overload; procedure lua_pushstring(L : Plua_State; const S : String); overload; function lua_tostring(L : Plua_State; idx : Integer) : String; function lua_tocstring(L : Plua_State; idx : Integer) : PAnsiChar; (* ** compatibility macros and functions *) function lua_open : Plua_State; procedure lua_getregistry(L : Plua_State); function lua_getgccount(L : Plua_State) : Integer; type lua_Chuckreader = type lua_Reader; lua_Chuckwriter = type lua_Writer; (* ====================================================================== *) (* ** {====================================================================== ** Debug API ** ======================================================================= *) (* ** Event codes *) const LUA_HOOKCALL = 0; LUA_HOOKRET = 1; LUA_HOOKLINE = 2; LUA_HOOKCOUNT = 3; LUA_HOOKTAILRET = 4; (* ** Event masks *) LUA_MASKCALL = 1 shl LUA_HOOKCALL; LUA_MASKRET = 1 shl LUA_HOOKRET; LUA_MASKLINE = 1 shl LUA_HOOKLINE; LUA_MASKCOUNT = 1 shl LUA_HOOKCOUNT; type lua_Debug = packed record event : Integer; name : PChar; (* (n) *) namewhat : PChar; (* (n) `global', `local', `field', `method' *) what : PChar; (* (S) `Lua', `C', `main', `tail' *) source : PChar; (* (S) *) currentline : Integer; (* (l) *) nups : Integer; (* (u) number of upvalues *) linedefined : Integer; (* (S) *) short_src : array [0..LUA_IDSIZE-1] of Char; (* (S) *) (* private part *) i_ci : Integer; (* active function *) end; Plua_Debug = ^lua_Debug; (* Functions to be called by the debuger in specific events *) lua_Hook = procedure (L : Plua_State; ar : Plua_Debug); cdecl; var lua_getstack: function (L : Plua_State; level : Integer; ar : Plua_Debug) : Integer; cdecl; lua_getinfo: function (L : Plua_State; const what : PChar; ar: Plua_Debug): Integer; cdecl; lua_getlocal: function (L : Plua_State; ar : Plua_Debug; n : Integer) : PChar; cdecl; lua_setlocal: function (L : Plua_State; ar : Plua_Debug; n : Integer) : PChar; cdecl; lua_getupvalue: function (L : Plua_State; funcindex, n : Integer) : PChar; cdecl; lua_setupvalue: function (L : Plua_State; funcindex, n : Integer) : PChar; cdecl; lua_sethook: function (L : Plua_State; func : lua_Hook; mask, count: Integer): Integer; cdecl; {function lua_gethook(L : Plua_State) : lua_Hook; cdecl;} lua_gethookmask: function (L : Plua_State) : Integer; cdecl; lua_gethookcount: function (L : Plua_State) : Integer; cdecl; (*****************************************************************************) (* lualib.h *) (*****************************************************************************) (* ** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ ** Lua standard libraries ** See Copyright Notice at the end of this file *) const (* Key to file-handle type *) LUA_FILEHANDLE = 'FILE*'; LUA_COLIBNAME = 'coroutine'; LUA_TABLIBNAME = 'table'; LUA_IOLIBNAME = 'io'; LUA_OSLIBNAME = 'os'; LUA_STRLIBNAME = 'string'; LUA_MATHLIBNAME = 'math'; LUA_DBLIBNAME = 'debug'; LUA_LOADLIBNAME = 'package'; var luaopen_base: function (L : Plua_State) : Integer; cdecl; luaopen_table: function (L : Plua_State) : Integer; cdecl; luaopen_io: function (L : Plua_State) : Integer; cdecl; luaopen_os: function (L : Plua_State) : Integer; cdecl; luaopen_string: function (L : Plua_State) : Integer; cdecl; luaopen_math: function (L : Plua_State) : Integer; cdecl; luaopen_debug: function (L : Plua_State) : Integer; cdecl; luaopen_package: function (L : Plua_State) : Integer; cdecl; luaL_openlibs: procedure (L : Plua_State); cdecl; procedure lua_assert(x : Boolean); // a macro (*****************************************************************************) (* lauxlib.h *) (*****************************************************************************) (* ** $Id: lauxlib.h,v 1.87 2005/12/29 15:32:11 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice at the end of this file. *) // not compatibility with the behavior of setn/getn in Lua 5.0 function luaL_getn(L : Plua_State; idx : Integer) : Integer; procedure luaL_setn(L : Plua_State; i, j : Integer); const LUA_ERRFILE = LUA_ERRERR + 1; type luaL_Reg = packed record name : PChar; func : lua_CFunction; end; PluaL_Reg = ^luaL_Reg; var luaL_openlib: procedure (L : Plua_State; const libname : PChar; const lr : PluaL_Reg; nup : Integer); cdecl; luaL_register: procedure (L : Plua_State; const libname : PChar; const lr : PluaL_Reg); cdecl; luaL_getmetafield: function (L : Plua_State; obj : Integer; const e : PChar) : Integer; cdecl; luaL_callmeta: function (L : Plua_State; obj : Integer; const e : PChar) : Integer; cdecl; luaL_typerror: function (L : Plua_State; narg : Integer; const tname : PChar) : Integer; cdecl; luaL_argerror: function (L : Plua_State; numarg : Integer; const extramsg : PChar) : Integer; cdecl; luaL_checklstring: function (L : Plua_State; numArg : Integer; ls : Psize_t) : PChar; cdecl; luaL_optlstring: function (L : Plua_State; numArg : Integer; const def: PChar; ls: Psize_t) : PChar; cdecl; luaL_checknumber: function (L : Plua_State; numArg : Integer) : lua_Number; cdecl; luaL_optnumber: function (L : Plua_State; nArg : Integer; def : lua_Number) : lua_Number; cdecl; luaL_checkstack: procedure (L : Plua_State; sz : Integer; const msg : PChar); cdecl; luaL_checktype: procedure (L : Plua_State; narg, t : Integer); cdecl; luaL_checkany: procedure (L : Plua_State; narg : Integer); cdecl; luaL_newmetatable: function (L : Plua_State; const tname : PChar) : Integer; cdecl; luaL_checkudata: function (L : Plua_State; ud : Integer; const tname : PChar) : Pointer; cdecl; luaL_where: procedure (L : Plua_State; lvl : Integer); cdecl; luaL_error: function (L : Plua_State; const fmt : PChar) : Integer; varargs; cdecl; luaL_checkoption: function (L : Plua_State; narg : Integer; const def : PChar; const lst : array of PChar) : Integer; cdecl; luaL_ref: function (L : Plua_State; t : Integer) : Integer; cdecl; luaL_unref: procedure (L : Plua_State; t, ref : Integer); cdecl; luaL_loadfilex : function (L: Plua_State; const filename, mode: PAnsiChar): Integer; cdecl; luaL_loadbuffer: function (L : Plua_State; const buff : PChar; sz : size_t; const name: PChar) : Integer; cdecl; luaL_loadstring: function (L : Plua_State; const s : Pchar) : Integer; cdecl; luaL_newstate: function : Plua_State; cdecl; luaL_gsub: function (L : Plua_State; const s, p, r : PChar) : PChar; cdecl; luaL_findtable: function (L : Plua_State; idx : Integer; const fname : PChar; szhint : Integer) : PChar; cdecl; luaL_execresult: function (L: Plua_State; stat: Integer): Integer; cdecl; function luaL_loadfile(L: Plua_State; const filename: PAnsiChar): Integer; function luaL_checkinteger(L : Plua_State; numArg : Integer) : lua_Integer; function luaL_optinteger(L : Plua_State; nArg : Integer; def : lua_Integer) : lua_Integer; (* ** =============================================================== ** some useful macros ** =============================================================== *) function luaL_argcheck(L : Plua_State; cond : Boolean; numarg : Integer; extramsg : PChar): Integer; function luaL_checkstring(L : Plua_State; n : Integer) : PChar; function luaL_optstring(L : Plua_State; n : Integer; d : PChar) : PChar; function luaL_checkint(L : Plua_State; n : Integer) : Integer; function luaL_optint(L : Plua_State; n, d : Integer): Integer; function luaL_checklong(L : Plua_State; n : LongInt) : LongInt; function luaL_optlong(L : Plua_State; n : Integer; d : LongInt) : LongInt; function luaL_typename(L : Plua_State; idx : Integer) : PChar; function luaL_dofile(L : Plua_State; fn : PChar) : Integer; function luaL_dostring(L : Plua_State; s : PChar) : Integer; procedure luaL_getmetatable(L : Plua_State; n : PChar); (* not implemented yet #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) *) (* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= *) const LUAL_BUFFERSIZE_OLD = 1024; // Lua 5.1, LuaJIT LUAL_BUFFERSIZE_NEW = 8192; // Lua 5.2, Lua 5.3 type luaL_Buffer = packed record case Boolean of False: ( p : PAnsiChar; (* current position in buffer *) lvl : Integer; (* number of strings in the stack (level) *) L : Plua_State; buffer : array [0..(LUAL_BUFFERSIZE_OLD - 1)] of AnsiChar; ); True: ( b: PAnsiChar; //* buffer address */ size: size_t; //* buffer size */ n: size_t; //* number of characters in buffer */ LL: Plua_State; initb: array[0..(LUAL_BUFFERSIZE_NEW - 1)] of AnsiChar; //* initial buffer */ ); end; PluaL_Buffer = ^luaL_Buffer; procedure luaL_addchar(B : PluaL_Buffer; c : Char); procedure luaL_addsize(B : PluaL_Buffer; n : Integer); var luaL_buffinit: procedure (L : Plua_State; B : PluaL_Buffer); cdecl; luaL_addlstring: procedure (B : PluaL_Buffer; const s : PChar; ls : size_t); cdecl; luaL_addstring: procedure (B : PluaL_Buffer; const s : PChar); cdecl; luaL_addvalue: procedure (B : PluaL_Buffer); cdecl; luaL_pushresult: procedure (B : PluaL_Buffer); cdecl; function luaL_prepbuffer(B: PluaL_Buffer): PAnsiChar; cdecl; (* ====================================================== *) (* compatibility with ref system *) (* pre-defined references *) const LUA_NOREF = -2; LUA_REFNIL = -1; function lua_ref(L : Plua_State; lock : Boolean) : Integer; procedure lua_unref(L : Plua_State; ref : Integer); procedure lua_getref(L : Plua_State; ref : Integer); (******************************************************************************) (******************************************************************************) (******************************************************************************) var LuaLibD: TLibHandle = NilHandle; luaJIT: Boolean; implementation uses SysUtils {$IFDEF UNIX} , dl {$ENDIF} ; const (* ** pseudo-indices *) LUA_GLOBALSINDEX = -10002; var LUA_UPVALUEINDEX_: Integer; var LUA_VERSION_DYN: Integer; var lua_version: function (L: Plua_State): Plua_Number; cdecl; luaL_prepbuffer_: function (B : PluaL_Buffer) : PAnsiChar; cdecl; lua_rawlen: function (L : Plua_State; idx : Integer): size_t; cdecl; lua_pushstring_: procedure (L : Plua_State; const s : PChar); cdecl; lua_objlen_: function (L : Plua_State; idx : Integer) : size_t; cdecl; lua_setglobal_: procedure (L: Plua_State; const name: PAnsiChar); cdecl; lua_newuserdata_: function (L : Plua_State; sz : size_t) : Pointer; cdecl; luaL_prepbuffsize: function (B: PluaL_Buffer; sz: size_t): PAnsiChar; cdecl; lua_getglobal_: function (L: Plua_State; const name: PAnsiChar): Integer; cdecl; lua_tonumber_: function (L : Plua_State; idx : Integer) : lua_Number; cdecl; luaL_loadfile_: function (L: Plua_State; const filename: PAnsiChar): Integer; cdecl; lua_newuserdatauv: function(L: Plua_State; sz: size_t; nuvalue: Integer): Pointer; cdecl; lua_tonumberx: function(L: Plua_State; idx: Integer; isnum: PLongBool): lua_Number; cdecl; luaL_loadfilex_: function (L: Plua_State; const filename, mode: PAnsiChar): Integer; cdecl; lua_pcall_: function (L : Plua_State; nargs, nresults, errfunc : Integer) : Integer; cdecl; lua_pcallk: function(L: Plua_State; nargs, nresults, errfunc: Integer; ctx: lua_KContext; k: lua_KFunction): Integer; cdecl; var lua_tointeger_: function (L : Plua_State; idx : Integer) : IntPtr; cdecl; lua_tointegerx64: function(L: Plua_State; idx: Integer; isnum: PLongBool): Int64; cdecl; lua_tointegerxPtr: function(L: Plua_State; idx: Integer; isnum: PLongBool): IntPtr; cdecl; lua_pushinteger64: procedure (L : Plua_State; n : Int64); cdecl; lua_pushintegerPtr: procedure (L : Plua_State; n : IntPtr); cdecl; luaL_checkinteger64: function (L : Plua_State; numArg : Integer) : Int64; cdecl; luaL_checkintegerPtr: function (L : Plua_State; numArg : Integer) : IntPtr; cdecl; luaL_optinteger64: function (L : Plua_State; nArg : Integer; def : Int64) : Int64; cdecl; luaL_optintegerPtr: function (L : Plua_State; nArg : Integer; def : IntPtr) : IntPtr; cdecl; lua_resume51: function (L : Plua_State; narg : Integer) : Integer; cdecl; lua_resume54: function (L : Plua_State; narg : Integer; nresults : PInteger) : Integer; cdecl; procedure lua_insert53(L : Plua_State; idx : Integer); cdecl; begin lua_rotate(L, idx, 1); end; procedure lua_remove53(L : Plua_State; idx : Integer); cdecl; begin lua_rotate(L, idx, -1); lua_pop(L, 1); end; procedure lua_replace53(L : Plua_State; idx : Integer); cdecl; begin lua_copy(L, -1, idx); lua_pop(L, 1); end; procedure UnloadLuaLib; begin if LuaLibD <> NilHandle then begin FreeLibrary(LuaLibD); LuaLibD := NilHandle; end; end; function IsLuaLibLoaded: Boolean; begin Result:= (LuaLibD <> NilHandle); end; function LuaVersion: Integer; var lua_version_ex: function(L: Plua_State): lua_Number; cdecl; begin // Lua 5.1 if (@lua_version = nil) then Result:= LUA_VERSION_NUM else begin // Lua 5.2 - 5.3 if (@lua_newuserdatauv = nil) then begin Result:= Trunc(lua_version(nil)^); end // Lua >= 5.4 else begin @lua_version_ex:= @lua_version; Result:= Trunc(lua_version_ex(nil)); end; end; end; function LoadLuaLib(FileName: String): Boolean; const LUA_REGISTRYINDEX_OLD = -10000; // Lua 5.1, LuaJIT LUA_REGISTRYINDEX_NEW = -1001000; // Lua 5.2, Lua 5.3 begin {$IF DEFINED(UNIX)} LuaLibD:= TLibHandle(dlopen(PAnsiChar(FileName), RTLD_NOW or RTLD_GLOBAL)); {$ELSE} LuaLibD:= LoadLibrary(FileName); {$ENDIF} Result:= (LuaLibD <> NilHandle); if not Result then Exit; @lua_newstate := GetProcAddress(LuaLibD, 'lua_newstate'); @lua_close := GetProcAddress(LuaLibD, 'lua_close'); @lua_newthread := GetProcAddress(LuaLibD, 'lua_newthread'); @lua_atpanic := GetProcAddress(LuaLibD, 'lua_atpanic'); @luaL_buffinit := GetProcAddress(LuaLibD, 'luaL_buffinit'); @luaL_prepbuffer_ := GetProcAddress(LuaLibD, 'luaL_prepbuffer'); @luaL_addlstring := GetProcAddress(LuaLibD, 'luaL_addlstring'); @luaL_addstring := GetProcAddress(LuaLibD, 'luaL_addstring'); @luaL_addvalue := GetProcAddress(LuaLibD, 'luaL_addvalue'); @luaL_pushresult := GetProcAddress(LuaLibD, 'luaL_pushresult'); @luaL_openlib := GetProcAddress(LuaLibD, 'luaL_openlib'); @luaL_register := GetProcAddress(LuaLibD, 'luaL_register'); @luaL_getmetafield := GetProcAddress(LuaLibD, 'luaL_getmetafield'); @luaL_callmeta := GetProcAddress(LuaLibD, 'luaL_callmeta'); @luaL_typerror := GetProcAddress(LuaLibD, 'luaL_typerror'); @luaL_argerror := GetProcAddress(LuaLibD, 'luaL_argerror'); @luaL_checklstring := GetProcAddress(LuaLibD, 'luaL_checklstring'); @luaL_optlstring := GetProcAddress(LuaLibD, 'luaL_optlstring'); @luaL_checknumber := GetProcAddress(LuaLibD, 'luaL_checknumber'); @luaL_optnumber := GetProcAddress(LuaLibD, 'luaL_optnumber'); @luaL_checkstack := GetProcAddress(LuaLibD, 'luaL_checkstack'); @luaL_checktype := GetProcAddress(LuaLibD, 'luaL_checktype'); @luaL_checkany := GetProcAddress(LuaLibD, 'luaL_checkany'); @luaL_newmetatable := GetProcAddress(LuaLibD, 'luaL_newmetatable'); @luaL_checkudata := GetProcAddress(LuaLibD, 'luaL_checkudata'); @luaL_where := GetProcAddress(LuaLibD, 'luaL_where'); @luaL_error := GetProcAddress(LuaLibD, 'luaL_error'); @luaL_checkoption := GetProcAddress(LuaLibD, 'luaL_checkoption'); @luaL_ref := GetProcAddress(LuaLibD, 'luaL_ref'); @luaL_unref := GetProcAddress(LuaLibD, 'luaL_unref'); @luaL_loadfile_ := GetProcAddress(LuaLibD, 'luaL_loadfile'); @luaL_loadbuffer := GetProcAddress(LuaLibD, 'luaL_loadbuffer'); @luaL_loadstring := GetProcAddress(LuaLibD, 'luaL_loadstring'); @luaL_newstate := GetProcAddress(LuaLibD, 'luaL_newstate'); @luaL_gsub := GetProcAddress(LuaLibD, 'luaL_gsub'); @luaL_findtable := GetProcAddress(LuaLibD, 'luaL_findtable'); @luaL_execresult := GetProcAddress(LuaLibD, 'luaL_execresult'); @luaopen_base := GetProcAddress(LuaLibD, 'luaopen_base'); @luaopen_table := GetProcAddress(LuaLibD, 'luaopen_table'); @luaopen_io := GetProcAddress(LuaLibD, 'luaopen_io'); @luaopen_os := GetProcAddress(LuaLibD, 'luaopen_os'); @luaopen_string := GetProcAddress(LuaLibD, 'luaopen_string'); @luaopen_math := GetProcAddress(LuaLibD, 'luaopen_math'); @luaopen_debug := GetProcAddress(LuaLibD, 'luaopen_debug'); @luaopen_package := GetProcAddress(LuaLibD, 'luaopen_package'); @luaL_openlibs := GetProcAddress(LuaLibD, 'luaL_openlibs'); @lua_getstack := GetProcAddress(LuaLibD, 'lua_getstack'); @lua_getinfo := GetProcAddress(LuaLibD, 'lua_getinfo'); @lua_getlocal := GetProcAddress(LuaLibD, 'lua_getlocal'); @lua_setlocal := GetProcAddress(LuaLibD, 'lua_setlocal'); @lua_getupvalue := GetProcAddress(LuaLibD, 'lua_getupvalue'); @lua_setupvalue := GetProcAddress(LuaLibD, 'lua_setupvalue'); @lua_sethook := GetProcAddress(LuaLibD, 'lua_sethook'); // function lua_gethook(L : Plua_State) : lua_Hook; cdecl; @lua_gethookmask := GetProcAddress(LuaLibD, 'lua_gethookmask'); @lua_gethookcount := GetProcAddress(LuaLibD, 'lua_gethookcount'); @lua_error := GetProcAddress(LuaLibD, 'lua_error'); @lua_next := GetProcAddress(LuaLibD, 'lua_next'); @lua_concat := GetProcAddress(LuaLibD, 'lua_concat'); @lua_getallocf := GetProcAddress(LuaLibD, 'lua_getallocf'); @lua_setallocf := GetProcAddress(LuaLibD, 'lua_setallocf'); @lua_gc := GetProcAddress(LuaLibD, 'lua_gc'); @lua_yield := GetProcAddress(LuaLibD, 'lua_yield'); @lua_status := GetProcAddress(LuaLibD, 'lua_status'); @lua_call := GetProcAddress(LuaLibD, 'lua_call'); @lua_pcall_ := GetProcAddress(LuaLibD, 'lua_pcall'); @lua_cpcall := GetProcAddress(LuaLibD, 'lua_cpcall'); @lua_load := GetProcAddress(LuaLibD, 'lua_load'); @lua_dump := GetProcAddress(LuaLibD, 'lua_dump'); @lua_settable := GetProcAddress(LuaLibD, 'lua_settable'); @lua_setfield := GetProcAddress(LuaLibD, 'lua_setfield'); @lua_rawset := GetProcAddress(LuaLibD, 'lua_rawset'); @lua_rawseti := GetProcAddress(LuaLibD, 'lua_rawseti'); @lua_setmetatable := GetProcAddress(LuaLibD, 'lua_setmetatable'); @lua_setfenv := GetProcAddress(LuaLibD, 'lua_setfenv'); @lua_gettable := GetProcAddress(LuaLibD, 'lua_gettable'); @lua_getfield := GetProcAddress(LuaLibD, 'lua_getfield'); @lua_rawget := GetProcAddress(LuaLibD, 'lua_rawget'); @lua_rawgeti := GetProcAddress(LuaLibD, 'lua_rawgeti'); @lua_createtable := GetProcAddress(LuaLibD, 'lua_createtable'); @lua_newuserdata_ := GetProcAddress(LuaLibD, 'lua_newuserdata'); @lua_getmetatable := GetProcAddress(LuaLibD, 'lua_getmetatable'); @lua_getfenv := GetProcAddress(LuaLibD, 'lua_getfenv'); @lua_pushnil := GetProcAddress(LuaLibD, 'lua_pushnil'); @lua_pushnumber := GetProcAddress(LuaLibD, 'lua_pushnumber'); @lua_pushlstring := GetProcAddress(LuaLibD, 'lua_pushlstring'); @lua_pushstring_ := GetProcAddress(LuaLibD, 'lua_pushstring'); @lua_pushvfstring := GetProcAddress(LuaLibD, 'lua_pushvfstring'); @lua_pushfstring := GetProcAddress(LuaLibD, 'lua_pushfstring'); @lua_pushcclosure := GetProcAddress(LuaLibD, 'lua_pushcclosure'); @lua_pushboolean := GetProcAddress(LuaLibD, 'lua_pushboolean'); @lua_pushlightuserdata := GetProcAddress(LuaLibD, 'lua_pushlightuserdata'); @lua_pushthread := GetProcAddress(LuaLibD, 'lua_pushthread'); @lua_isnumber := GetProcAddress(LuaLibD, 'lua_isnumber'); @lua_isstring := GetProcAddress(LuaLibD, 'lua_isstring'); @lua_iscfunction := GetProcAddress(LuaLibD, 'lua_iscfunction'); @lua_isinteger :=GetProcAddress(LuaLibD, 'lua_isinteger'); @lua_isuserdata := GetProcAddress(LuaLibD, 'lua_isuserdata'); @lua_type := GetProcAddress(LuaLibD, 'lua_type'); @lua_typename := GetProcAddress(LuaLibD, 'lua_typename'); @lua_equal := GetProcAddress(LuaLibD, 'lua_equal'); @lua_rawequal := GetProcAddress(LuaLibD, 'lua_rawequal'); @lua_lessthan := GetProcAddress(LuaLibD, 'lua_lessthan'); @lua_tonumber_ := GetProcAddress(LuaLibD, 'lua_tonumber'); @lua_tointeger_ := GetProcAddress(LuaLibD, 'lua_tointeger'); @lua_toboolean := GetProcAddress(LuaLibD, 'lua_toboolean'); @lua_tolstring := GetProcAddress(LuaLibD, 'lua_tolstring'); @lua_objlen_ := GetProcAddress(LuaLibD, 'lua_objlen'); @lua_tocfunction := GetProcAddress(LuaLibD, 'lua_tocfunction'); @lua_touserdata := GetProcAddress(LuaLibD, 'lua_touserdata'); @lua_tothread := GetProcAddress(LuaLibD, 'lua_tothread'); @lua_topointer := GetProcAddress(LuaLibD, 'lua_topointer'); @lua_gettop := GetProcAddress(LuaLibD, 'lua_gettop'); @lua_settop := GetProcAddress(LuaLibD, 'lua_settop'); @lua_pushvalue := GetProcAddress(LuaLibD, 'lua_pushvalue'); @lua_checkstack := GetProcAddress(LuaLibD, 'lua_checkstack'); @lua_xmove := GetProcAddress(LuaLibD, 'lua_xmove'); // Lua 5.2 - 5.4 specific stuff @lua_rawlen := GetProcAddress(LuaLibD, 'lua_rawlen'); @lua_pcallk := GetProcAddress(LuaLibD, 'lua_pcallk'); @lua_version := GetProcAddress(LuaLibD, 'lua_version'); @lua_tonumberx := GetProcAddress(LuaLibD, 'lua_tonumberx'); @lua_setglobal_ := GetProcAddress(LuaLibD, 'lua_setglobal'); @lua_getglobal_ := GetProcAddress(LuaLibD, 'lua_getglobal'); @luaL_loadfilex_ := GetProcAddress(LuaLibD, 'luaL_loadfilex'); @luaL_prepbuffsize := GetProcAddress(LuaLibD, 'luaL_prepbuffsize'); @lua_newuserdatauv := GetProcAddress(LuaLibD, 'lua_newuserdatauv'); // luaJIT specific stuff luaJIT := GetProcAddress(LuaLibD, 'luaJIT_setmode') <> nil; LUA_VERSION_DYN:= LuaVersion; // Determine pseudo-indices values if (LUA_VERSION_DYN > LUA_VERSION_NUM) then begin LUAL_BUFFERSIZE := LUAL_BUFFERSIZE_NEW; LUA_UPVALUEINDEX_:= LUA_REGISTRYINDEX_NEW; LUA_REGISTRYINDEX:= LUA_REGISTRYINDEX_NEW; end else begin LUAL_BUFFERSIZE := LUAL_BUFFERSIZE_OLD; LUA_UPVALUEINDEX_:= LUA_GLOBALSINDEX; LUA_REGISTRYINDEX:= LUA_REGISTRYINDEX_OLD; end; if (LUA_VERSION_DYN >= 502) then begin @lua_copy := GetProcAddress(LuaLibD, 'lua_copy'); end; if (LUA_VERSION_DYN >= 503) then begin @lua_insert := @lua_insert53; @lua_remove := @lua_remove53; @lua_replace := @lua_replace53; @lua_rotate := GetProcAddress(LuaLibD, 'lua_rotate'); end else begin @lua_remove := GetProcAddress(LuaLibD, 'lua_remove'); @lua_insert := GetProcAddress(LuaLibD, 'lua_insert'); @lua_replace := GetProcAddress(LuaLibD, 'lua_replace'); end; // Determine integer type if (LUA_VERSION_DYN >= 503) then begin @lua_pushinteger64 := GetProcAddress(LuaLibD, 'lua_pushinteger'); @luaL_checkinteger64 := GetProcAddress(LuaLibD, 'luaL_checkinteger'); @luaL_optinteger64 := GetProcAddress(LuaLibD, 'luaL_optinteger'); @lua_tointegerx64 := GetProcAddress(LuaLibD, 'lua_tointegerx'); end else begin @lua_pushintegerPtr := GetProcAddress(LuaLibD, 'lua_pushinteger'); @luaL_checkintegerPtr := GetProcAddress(LuaLibD, 'luaL_checkinteger'); @luaL_optintegerPtr := GetProcAddress(LuaLibD, 'luaL_optinteger'); @lua_tointegerxPtr := GetProcAddress(LuaLibD, 'lua_tointegerx'); end; if (LUA_VERSION_DYN >= 504) then @lua_resume54 := GetProcAddress(LuaLibD, 'lua_resume') else begin @lua_resume51 := GetProcAddress(LuaLibD, 'lua_resume'); end; end; (*****************************************************************************) (* luaconfig.h *) (*****************************************************************************) function lua_readline(L : Plua_State; var b : PChar; p : PChar): Boolean; var s : AnsiString; begin Write(p); // show prompt ReadLn(s); // get line b := PChar(s); // and return it lua_readline := (b[0] <> #4); // test for ctrl-D end; procedure lua_saveline(L : Plua_State; idx : Integer); begin end; procedure lua_freeline(L : Plua_State; b : PChar); begin end; (*****************************************************************************) (* lua.h *) (*****************************************************************************) function lua_upvalueindex(idx : Integer) : Integer; begin lua_upvalueindex := LUA_UPVALUEINDEX_ - idx; end; procedure lua_pop(L : Plua_State; n : Integer); begin lua_settop(L, -n - 1); end; procedure lua_newtable(L : Plua_State); begin lua_createtable(L, 0, 0); end; procedure lua_register(L : Plua_State; n : PChar; f : lua_CFunction); begin lua_pushcfunction(L, f); lua_setglobal(L, n); end; procedure lua_pushcfunction(L : Plua_State; f : lua_CFunction); begin lua_pushcclosure(L, f, 0); end; function lua_strlen(L : Plua_State; idx : Integer) : Integer; begin lua_strlen := lua_objlen(L, idx); end; function lua_isfunction(L : Plua_State; n : Integer) : Boolean; begin lua_isfunction := lua_type(L, n) = LUA_TFUNCTION; end; function lua_istable(L : Plua_State; n : Integer) : Boolean; begin lua_istable := lua_type(L, n) = LUA_TTABLE; end; function lua_islightuserdata(L : Plua_State; n : Integer) : Boolean; begin lua_islightuserdata := lua_type(L, n) = LUA_TLIGHTUSERDATA; end; function lua_isnil(L : Plua_State; n : Integer) : Boolean; begin lua_isnil := lua_type(L, n) = LUA_TNIL; end; function lua_isboolean(L : Plua_State; n : Integer) : Boolean; begin lua_isboolean := lua_type(L, n) = LUA_TBOOLEAN; end; function lua_isthread(L : Plua_State; n : Integer) : Boolean; begin lua_isthread := lua_type(L, n) = LUA_TTHREAD; end; function lua_isnone(L : Plua_State; n : Integer) : Boolean; begin lua_isnone := lua_type(L, n) = LUA_TNONE; end; function lua_isnoneornil(L : Plua_State; n : Integer) : Boolean; begin lua_isnoneornil := lua_type(L, n) <= 0; end; procedure lua_pushliteral(L : Plua_State; s : PChar); begin lua_pushlstring(L, s, StrLen(s)); end; procedure lua_pushstring(L: Plua_State; const S: PChar); inline; begin lua_pushstring_(L, S); end; procedure lua_pushstring(L: Plua_State; const S: String); inline; begin lua_pushlstring(L, PAnsiChar(S), Length(S)); end; function lua_tonumber(L: Plua_State; idx: Integer): lua_Number; begin if Assigned(lua_tonumberx) then Result:= lua_tonumberx(L, idx, nil) else Result:= lua_tonumber_(L, idx); end; function lua_tointeger(L: Plua_State; idx: Integer): lua_Integer; begin if Assigned(lua_tointegerx64) then Result:= lua_tointegerx64(L, idx, nil) else if Assigned(lua_tointegerxPtr) then Result:= lua_tointegerxPtr(L, idx, nil) else Result:= lua_tointeger_(L, idx); end; function lua_objlen(L: Plua_State; idx: Integer): size_t; begin if Assigned(lua_rawlen) then Result:= lua_rawlen(L, idx) else Result:= lua_objlen_(L, idx); end; procedure lua_pushinteger(L: Plua_State; n: lua_Integer); begin if Assigned(lua_pushinteger64) then lua_pushinteger64(L, n) else lua_pushintegerPtr(L, IntPtr(n)); end; procedure lua_setglobal(L: Plua_State; const name: PAnsiChar); begin if Assigned(lua_setglobal_) then lua_setglobal_(L, name) else lua_setfield(L, LUA_GLOBALSINDEX, name); end; procedure lua_getglobal(L: Plua_State; const name: PAnsiChar); begin if Assigned(lua_getglobal_) then lua_getglobal_(L, name) else lua_getfield(L, LUA_GLOBALSINDEX, name); end; function lua_newuserdata(L : Plua_State; sz : size_t) : Pointer; begin if Assigned(lua_newuserdatauv) then Result:= lua_newuserdatauv(L, sz, 1) else begin Result:= lua_newuserdata_(L, sz); end; end; function lua_tostring(L : Plua_State; idx : Integer) : String; var N: size_t; begin SetString(Result, lua_tolstring(L, idx, @N), N); end; function lua_tocstring(L : Plua_State; idx : Integer) : PAnsiChar; begin lua_tocstring := lua_tolstring(L, idx, nil); end; function lua_open : Plua_State; begin lua_open := luaL_newstate(); end; procedure lua_getregistry(L : Plua_State); begin lua_pushvalue(L, LUA_REGISTRYINDEX); end; function lua_getgccount(L : Plua_State) : Integer; begin lua_getgccount := lua_gc(L, LUA_GCCOUNT, 0); end; function lua_pcall(L: Plua_State; nargs, nresults, errfunc: Integer): Integer; begin if Assigned(lua_pcallk) then Result:= lua_pcallk(L, nargs, nresults, errfunc, nil, nil) else Result:= lua_pcall_(L, nargs, nresults, errfunc); end; function lua_resume(L: Plua_State; narg: Integer; nresults: PInteger): Integer; begin if Assigned(lua_resume54) then Result:= lua_resume54(L, narg, nresults) else begin nresults := nil; Result:= lua_resume51(L, narg); end; end; (*****************************************************************************) (* lualib.h *) (*****************************************************************************) procedure lua_assert(x : Boolean); begin end; (*****************************************************************************) (* lauxlib.h n *) (*****************************************************************************) function luaL_getn(L : Plua_State; idx : Integer) : Integer; begin luaL_getn := lua_objlen(L, idx); end; procedure luaL_setn(L: Plua_State; i, j: Integer); begin (* no op *) end; function luaL_argcheck(L : Plua_State; cond : Boolean; numarg : Integer; extramsg : PChar): Integer; begin if not cond then luaL_argcheck := luaL_argerror(L, numarg, extramsg) else luaL_argcheck := 0; end; function luaL_checkstring(L : Plua_State; n : Integer) : PChar; begin luaL_checkstring := luaL_checklstring(L, n, nil); end; function luaL_optstring(L : Plua_State; n : Integer; d : PChar) : PChar; begin luaL_optstring := luaL_optlstring(L, n, d, nil); end; function luaL_checkint(L : Plua_State; n : Integer) : Integer; begin luaL_checkint := luaL_checkinteger(L, n); end; function luaL_optint(L : Plua_State; n, d : Integer): Integer; begin luaL_optint := luaL_optinteger(L, n, d); end; function luaL_checklong(L : Plua_State; n : LongInt) : LongInt; begin luaL_checklong := luaL_checkinteger(L, n); end; function luaL_optlong(L : Plua_State; n : Integer; d : LongInt) : LongInt; begin luaL_optlong := luaL_optinteger(L, n, d); end; function luaL_typename(L : Plua_State; idx : Integer) : PChar; begin luaL_typename := lua_typename( L, lua_type(L, idx) ); end; function luaL_loadfile(L: Plua_State; const filename: PAnsiChar): Integer; begin if Assigned(luaL_loadfilex_) then Result:= luaL_loadfilex_(L, filename, nil) else Result:= luaL_loadfile_(L, filename); end; function luaL_checkinteger(L: Plua_State; numArg: Integer): lua_Integer; begin if Assigned(luaL_checkinteger64) then Result:= luaL_checkinteger64(L, numArg) else Result:= luaL_checkintegerPtr(L, numArg); end; function luaL_optinteger(L: Plua_State; nArg: Integer; def: lua_Integer): lua_Integer; begin if Assigned(luaL_optinteger64) then Result:= luaL_optinteger64(L, nArg, def) else Result:= luaL_optintegerPtr(L, nArg, IntPtr(def)); end; function luaL_dofile(L : Plua_State; fn : PChar) : Integer; Var Res : Integer; begin // WC 2007\03\22 - Updated for Delphi Res := luaL_loadfile(L, fn); if Res = 0 then Res := lua_pcall(L, 0, 0, 0); Result := Res; end; function luaL_dostring(L : Plua_State; s : PChar) : Integer; Var Res : Integer; begin // WC 2007\03\22 - Updated for Delphi Res := luaL_loadstring(L, s); if Res = 0 then Res := lua_pcall(L, 0, 0, 0); Result := Res; end; procedure luaL_getmetatable(L : Plua_State; n : PChar); begin lua_getfield(L, LUA_REGISTRYINDEX, n); end; procedure luaL_addchar(B : PluaL_Buffer; c : Char); begin if LUA_VERSION_DYN > LUA_VERSION_NUM then begin if not (B^.n < B^.size) then luaL_prepbuffsize(B, 1); B^.b[B^.n] := c; Inc(B^.n); end else begin if not (B^.p < B^.buffer + LUAL_BUFFERSIZE) then luaL_prepbuffer_(B); B^.p^ := c; Inc(B^.p); end; end; procedure luaL_addsize(B : PluaL_Buffer; n : Integer); begin if LUA_VERSION_DYN > LUA_VERSION_NUM then Inc(B^.n, n) else begin Inc(B^.p, n); end; end; function luaL_prepbuffer(B: PluaL_Buffer): PAnsiChar; cdecl; begin if Assigned(luaL_prepbuffsize) then Result := luaL_prepbuffsize(B, LUAL_BUFFERSIZE) else Result := luaL_prepbuffer_(B); end; function lua_ref(L : Plua_State; lock : Boolean) : Integer; begin if lock then lua_ref := luaL_ref(L, LUA_REGISTRYINDEX) else begin lua_pushstring(L, 'unlocked references are obsolete'); lua_error(L); lua_ref := 0; end; end; procedure lua_unref(L : Plua_State; ref : Integer); begin luaL_unref(L, LUA_REGISTRYINDEX, ref); end; procedure lua_getref(L : Plua_State; ref : Integer); begin lua_rawgeti(L, LUA_REGISTRYINDEX, ref); end; (****************************************************************************** * Original copyright for the lua source and headers: * 1994-2004 Tecgraf, PUC-Rio. * www.lua.org. * * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************) end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uClipboard.pas��������������������������������������������������������0000644�0001750�0000144�00000053276�14743153644�020027� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uClipboard; {$mode objfpc}{$H+} {$IFDEF DARWIN} {$modeswitch objectivec1} {$ENDIF} {$IF DEFINED(UNIX) and not DEFINED(DARWIN)} {$Define UNIX_not_DARWIN} {$ENDIF} interface uses Classes, SysUtils, LCLType; type TClipboardOperation = ( ClipboardCopy, ClipboardCut ); function CopyToClipboard(const filenames:TStringList):Boolean; function CutToClipboard(const filenames:TStringList):Boolean; function PasteFromClipboard(out ClipboardOp: TClipboardOperation; out filenames:TStringList):Boolean; function URIDecode(encodedUri: String): String; function URIEncode(path: String): String; {$IF DEFINED(UNIX_not_DARWIN)} function ExtractFilenames(uriList: String): TStringList; function FileNameToURI(const FileName: String): String; function FormatUriList(FileNames: TStringList): String; function FormatTextPlain(FileNames: TStringList): String; {$ENDIF} procedure ClearClipboard; procedure ClipboardSetText(AText: String); const fileScheme = 'file:'; // for URI {$IF DEFINED(MSWINDOWS)} CFSTR_PREFERRED_DROPEFFECT = 'Preferred DropEffect'; CFSTR_FILENAME = 'FileName'; CFSTR_FILENAMEW = 'FileNameW'; CFSTR_UNIFORM_RESOURCE_LOCATOR = 'UniformResourceLocator'; CFSTR_UNIFORM_RESOURCE_LOCATORW = 'UniformResourceLocatorW'; CFSTR_SHELL_IDLIST_ARRAY = 'Shell IDList Array'; CFSTR_FILEDESCRIPTOR = 'FileGroupDescriptor'; CFSTR_FILEDESCRIPTORW = 'FileGroupDescriptorW'; CFSTR_FILECONTENTS = 'FileContents'; CFSTR_HTMLFORMAT = 'HTML Format'; CFSTR_RICHTEXTFORMAT = 'Rich Text Format'; {$ELSEIF DEFINED(UNIX_not_DARWIN)} // General MIME uriListMime = 'text/uri-list'; textPlainMime = 'text/plain'; // Gnome cutText = 'cut'; copyText = 'copy'; gnomeClipboardMime = 'x-special/gnome-copied-files'; // Kde kdeClipboardMime = 'application/x-kde-cutselection'; {$ELSEIF DEFINED(DARWIN)} TClipboardOperationName : array[TClipboardOperation] of string = ( 'copy', 'cut' ); darwinPasteboardOpMime = 'application/x-darwin-doublecmd-PbOp'; {$ENDIF} {$IF DEFINED(MSWINDOWS)} var CFU_PREFERRED_DROPEFFECT, CFU_FILENAME, CFU_FILENAMEW, CFU_UNIFORM_RESOURCE_LOCATOR, CFU_UNIFORM_RESOURCE_LOCATORW, CFU_SHELL_IDLIST_ARRAY, CFU_FILECONTENTS, CFU_FILEGROUPDESCRIPTOR, CFU_FILEGROUPDESCRIPTORW, CFU_HTML, CFU_RICHTEXT: TClipboardFormat; {$ELSEIF DEFINED(UNIX_not_DARWIN)} var CFU_KDE_CUT_SELECTION, CFU_GNOME_COPIED_FILES, CFU_TEXT_PLAIN, CFU_URI_LIST: TClipboardFormat; {$ENDIF} implementation uses {$IF DEFINED(MSWINDOWS)} Clipbrd, Windows, ActiveX, uOleDragDrop, fMain, uShellContextMenu, uOSForms {$ELSEIF DEFINED(UNIX_not_DARWIN)} Clipbrd, LCLIntf {$ELSEIF DEFINED(DARWIN)} DCStrUtils, CocoaAll, CocoaUtils, uMyDarwin {$ENDIF} ; procedure RegisterUserFormats; begin {$IF DEFINED(MSWINDOWS)} CFU_PREFERRED_DROPEFFECT := RegisterClipboardFormat(CFSTR_PREFERRED_DROPEFFECT); CFU_FILENAME := RegisterClipboardFormat(CFSTR_FILENAME); CFU_FILENAMEW := RegisterClipboardFormat(CFSTR_FILENAMEW); CFU_UNIFORM_RESOURCE_LOCATOR := RegisterClipboardFormat(CFSTR_UNIFORM_RESOURCE_LOCATOR); CFU_UNIFORM_RESOURCE_LOCATORW := RegisterClipboardFormat(CFSTR_UNIFORM_RESOURCE_LOCATORW); CFU_SHELL_IDLIST_ARRAY := RegisterClipboardFormat(CFSTR_SHELL_IDLIST_ARRAY); CFU_FILECONTENTS := $8000 OR RegisterClipboardFormat(CFSTR_FILECONTENTS) And $7FFF; CFU_FILEGROUPDESCRIPTOR := $8000 OR RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR) And $7FFF; CFU_FILEGROUPDESCRIPTORW := $8000 OR RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW) And $7FFF; CFU_HTML := $8000 OR RegisterClipboardFormat(CFSTR_HTMLFORMAT) And $7FFF; CFU_RICHTEXT := $8000 OR RegisterClipboardFormat(CFSTR_RICHTEXTFORMAT) And $7FFF; {$ELSEIF DEFINED(UNIX_not_DARWIN)} CFU_GNOME_COPIED_FILES := RegisterClipboardFormat(gnomeClipboardMime); CFU_KDE_CUT_SELECTION := RegisterClipboardFormat(kdeClipboardMime); CFU_TEXT_PLAIN := RegisterClipboardFormat(textPlainMime); CFU_URI_LIST := RegisterClipboardFormat(uriListMime); {$ENDIF} end; { Changes all '%XX' to bytes (XX is a hex number). } function URIDecode(encodedUri: String): String; var i, oldIndex: Integer; len: Integer; begin len := Length(encodedUri); Result := ''; oldIndex := 1; i := 1; while i <= len-2 do // must be at least 2 more characters after '%' begin if encodedUri[i] = '%' then begin Result := Result + Copy(encodedUri, oldIndex, i-oldIndex) + Chr(StrToInt('$' + Copy(encodedUri, i+1, 2))); i := i + 3; oldIndex := i; end else Inc(i); end; Result := Result + Copy(encodedUri, oldIndex, len - oldIndex + 1 ); end; { Escapes forbidden characters to '%XX' (XX is a hex number). } function URIEncode(path: String): String; const { Per RFC-3986, what's allowed in uri-encoded path. path-absolute = "/" [ segment-nz *( "/" segment ) ] segment = *pchar segment-nz = 1*pchar pchar = unreserved / pct-encoded / sub-delims / ":" / "@" <-- pct-encoded = "%" HEXDIG HEXDIG unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" reserved = gen-delims / sub-delims gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" We'll also allow "/" in pchar, because it happens to also be the OS path delimiter. } allowed : set of char = [ '-', '.', '_', '~', // 'A'..'Z', 'a'..'z', '0'..'9', '!', '$', '&', #39 {'}, '(', ')', '*', '+', ',', ';', '=', ':', '@', '/' ]; var i, oldIndex: Integer; len: Integer; begin len := Length(path); Result := ''; oldIndex := 1; i := 1; for i := 1 to len do begin if not ((path[i] >= 'a') and (path[i] <= 'z')) and not ((path[i] >= 'A') and (path[i] <= 'Z')) and not ((path[i] >= '0') and (path[i] <= '9')) and not (path[i] in allowed) then begin Result := Result + Copy(path, oldIndex, i-oldIndex) + '%' + Format('%2x', [Ord(path[i])]); oldIndex := i + 1; end; end; Result := Result + Copy(path, oldIndex, len - oldIndex + 1 ); end; {$IFDEF UNIX_not_DARWIN} { Extracts a path from URI } function ExtractPath(uri: String): String; var len: Integer; i, j: Integer; begin len := Length(uri); if (len >= Length(fileScheme)) and (CompareChar(uri[1], fileScheme, Length(fileScheme)) = 0) then begin i := 1 + Length(fileScheme); // Omit case where we would have a root-less path - it is useless to us. if (i <= len) and (uri[i] = '/') then begin // Check if we have a: - "//" authority - part. if (i+1 <= len) and (uri[i+1] = '/') then begin // Authority (usually a hostname) may be empty. for j := i + 2 to len do if uri[j] = '/' then begin Result := Copy(uri, j, len - j + 1); Break; end; end else begin // We have only a path. Result := Copy(uri, i, len - i + 1); end; end; end else Result := ''; end; { Retrieves file names delimited by line ending characters. } function ExtractFilenames(uriList: String): TStringList; var i, oldIndex: Integer; len: Integer; path: String; begin // Format should be: file://hostname/path/to/file // Hostname may be empty. len := Length(uriList); Result := TStringList.Create; // For compatibility with apps that end the string with zero. while (len > 0) and (uriList[len] = #0) do Dec(len); if len = 0 then Exit; oldIndex := 1; for i := 1 to len do begin // Search for the end of line. if uriList[i] in [ #10, #13 ] then begin if i > oldIndex then begin path := ExtractPath(Copy(uriList, oldIndex, i - oldIndex)); if Length(path) > 0 then Result.Add(path); end; oldIndex := i + 1; end end; if i >= oldIndex then begin // copy including 'i'th character path := ExtractPath(Copy(uriList, oldIndex, i - oldIndex + 1)); if Length(path) > 0 then Result.Add(path); end; end; function FileNameToURI(const FileName: String): String; begin Result := fileScheme + '//' + URIEncode(FileName); end; function FormatUriList(FileNames: TStringList): String; var i : integer; begin Result := ''; for i := 0 to filenames.Count-1 do begin // Separate previous uris with line endings, // but do not end the whole string with it. if i > 0 then Result := Result + LineEnding; Result := Result + fileScheme + '//' { don't put hostname } + URIEncode(filenames[i]); end; end; function FormatTextPlain(FileNames: TStringList): String; var i : integer; begin Result := ''; for i := 0 to filenames.Count-1 do begin if i > 0 then Result := Result + LineEnding; Result := Result + fileScheme + '//' { don't put hostname } + filenames[i]; end; end; function GetClipboardFormatAsString(formatId: TClipboardFormat): String; var PBuffer: PChar = nil; stream: TMemoryStream; begin Result := ''; stream := TMemoryStream.Create; if stream <> nil then try Clipboard.GetFormat(formatId, stream); stream.Seek(0, soFromBeginning); PBuffer := AllocMem(stream.Size); if PBuffer <> nil then begin stream.Read(PBuffer^, stream.Size); SetString(Result, PBuffer, stream.Size); end; finally if PBuffer <> nil then begin FreeMem(PBuffer); PBuffer := nil; end; FreeAndNil(stream); end; end; function GetClipboardFormatAsString(formatName: String): String; var formatId: Integer; begin formatId := Clipboard.FindFormatID(formatName); if formatId <> 0 then Result := GetClipboardFormatAsString(formatId) else Result := ''; end; {$ENDIF} {$IFDEF MSWINDOWS} function SendToClipboard(const filenames:TStringList; ClipboardOp: TClipboardOperation):Boolean; var DragDropInfo: TDragDropInfo; i: Integer; hGlobalBuffer: HGLOBAL; PreferredEffect: DWORD = DROPEFFECT_COPY; formatEtc: TFormatEtc = (CfFormat: 0; Ptd: nil; dwAspect: 0; lindex: 0; tymed: TYMED_HGLOBAL); begin Result := False; if filenames.Count = 0 then Exit; if OpenClipboard(GetWindowHandle(frmMain)) = False then Exit; // Empty clipboard, freeing handles to data inside it. // Assign ownership of clipboard to self (frmMain.Handle). EmptyClipboard; { Create a helper object. } DragDropInfo := TDragDropInfo.Create(PreferredEffect); try for i := 0 to filenames.Count - 1 do DragDropInfo.Add(filenames[i]); { Now, set preferred effect. } if CFU_PREFERRED_DROPEFFECT <> 0 then begin if ClipboardOp = ClipboardCopy then PreferredEffect := DROPEFFECT_COPY else if ClipboardOp = ClipboardCut then PreferredEffect := DROPEFFECT_MOVE; hGlobalBuffer := DragDropInfo.CreatePreferredDropEffect(PreferredEffect); if hGlobalBuffer <> 0 then begin if SetClipboardData(CFU_PREFERRED_DROPEFFECT, hGlobalBuffer) = 0 then begin // Failed. GlobalFree(hGlobalBuffer); CloseClipboard; Exit; end // else SetClipboardData succeeded, // so hGlobalBuffer is now owned by the operating system. end else begin CloseClipboard; Exit; end; end; { Now, set clipboard data. } formatEtc.CfFormat := CF_HDROP; hGlobalBuffer := DragDropInfo.MakeDataInFormat(formatEtc); if SetClipboardData(CF_HDROP, hGlobalBuffer) = 0 then GlobalFree(hGlobalBuffer); formatEtc.CfFormat := CFU_SHELL_IDLIST_ARRAY; hGlobalBuffer := DragDropInfo.MakeDataInFormat(formatEtc); if SetClipboardData(CFU_SHELL_IDLIST_ARRAY, hGlobalBuffer) = 0 then GlobalFree(hGlobalBuffer); CloseClipboard; Result := True; finally FreeAndNil(DragDropInfo); end; end; {$ENDIF} {$IFDEF UNIX_not_DARWIN} function SendToClipboard(const filenames:TStringList; ClipboardOp: TClipboardOperation):Boolean; var s: String; uriList: String; plainList: String; begin Result := False; if filenames.Count = 0 then Exit; // Prepare filenames list. uriList := FormatUriList(filenames); plainList := FormatTextPlain(filenames); Clipboard.Open; Clipboard.Clear; { Gnome } if CFU_GNOME_COPIED_FILES <> 0 then begin case ClipboardOp of ClipboardCopy: s := copyText; ClipboardCut: s := cutText; else // unsupported operation s := ''; end; if s <> '' then begin s := s + LineEnding + uriList; Clipboard.AddFormat(CFU_GNOME_COPIED_FILES, s[1], Length(s)); end; end; { KDE } if CFU_KDE_CUT_SELECTION <> 0 then begin case ClipboardOp of ClipboardCopy: s := '0'; ClipboardCut: s := '1'; else // unsupported operation s := ''; end; if s <> '' then Clipboard.AddFormat(CFU_KDE_CUT_SELECTION, s[1], Length(s)); end; // Common to all, plain text. Clipboard.AddFormat(PredefinedClipboardFormat(pcfText), plainList[1], Length(plainList)); // Send also as URI-list. if CFU_URI_LIST <> 0 then Clipboard.AddFormat(CFU_URI_LIST, uriList[1], Length(uriList)); Clipboard.Close; Result := True; end; {$ENDIF} // MacOs 10.5 compatibility {$IFDEF DARWIN} function FilenamesToString(const filenames:TStringList): String; begin Result := TrimRightLineEnding( filenames.Text, filenames.TextLineBreakStyle); end; procedure NSPasteboardAddFiles(const filenames:TStringList; pb:NSPasteboard); begin pb.addTypes_owner(NSArray.arrayWithObject(NSFileNamesPboardType), nil); pb.setPropertyList_forType(ListToNSArray(filenames), NSFileNamesPboardType); end; procedure NSPasteboardAddFiles(const filenames:TStringList); begin NSPasteboardAddFiles( filenames, NSPasteboard.generalPasteboard ); end; procedure NSPasteboardAddString(const value:String; const pbType:NSString ); var pb: NSPasteboard; begin pb:= NSPasteboard.generalPasteboard; pb.addTypes_owner(NSArray.arrayWithObject(pbType), nil); pb.setString_forType(StringToNSString(value), pbType); end; procedure NSPasteboardAddString(const value:String); begin NSPasteboardAddString( value , NSStringPboardType ); end; function SendToClipboard(const filenames:TStringList; ClipboardOp: TClipboardOperation):Boolean; var s : string; begin Result := false; if filenames.Count = 0 then Exit; ClearClipboard; NSPasteboardAddFiles( filenames ); NSPasteboardAddString( FilenamesToString(filenames) ); NSPasteboardAddString( TClipboardOperationName[ClipboardOp] , StringToNSString(darwinPasteboardOpMime) ); Result := true; end; {$ENDIF} function CopyToClipboard(const filenames:TStringList):Boolean; begin Result := SendToClipboard(filenames, ClipboardCopy); end; function CutToClipboard(const filenames:TStringList):Boolean; begin Result := SendToClipboard(filenames, ClipboardCut); end; {$IFDEF MSWINDOWS} function PasteFromClipboard(out ClipboardOp: TClipboardOperation; out filenames:TStringList):Boolean; var hGlobalBuffer: HGLOBAL; pBuffer: LPVOID; PreferredEffect: DWORD; begin filenames := nil; Result := False; // Default to 'copy' if effect hasn't been given. ClipboardOp := ClipboardCopy; if OpenClipboard(0) = False then Exit; if CFU_PREFERRED_DROPEFFECT <> 0 then begin hGlobalBuffer := GetClipboardData(CFU_PREFERRED_DROPEFFECT); if hGlobalBuffer <> 0 then begin pBuffer := GlobalLock(hGlobalBuffer); if pBuffer <> nil then begin PreferredEffect := PDWORD(pBuffer)^; if PreferredEffect = DROPEFFECT_COPY then ClipboardOp := ClipboardCopy else if PreferredEffect = DROPEFFECT_MOVE then ClipboardOp := ClipboardCut; GlobalUnlock(hGlobalBuffer); end; end; end; { Now, retrieve file names. } hGlobalBuffer := GetClipboardData(CF_HDROP); if hGlobalBuffer = 0 then begin with frmMain do begin CloseClipboard; uShellContextMenu.PasteFromClipboard(Handle, ActiveFrame.CurrentPath); Exit(False); end; end; filenames := uOleDragDrop.TFileDropTarget.GetDropFilenames(hGlobalBuffer); if Assigned(filenames) then Result := True; CloseClipboard; end; {$ENDIF} {$IFDEF UNIX_not_DARWIN} function PasteFromClipboard(out ClipboardOp: TClipboardOperation; out filenames:TStringList):Boolean; var formatId: TClipboardFormat; uriList: String; s: String; begin filenames := nil; Result := False; // Default to 'copy' if effect hasn't been given. ClipboardOp := ClipboardCopy; uriList := ''; // Check if clipboard is not empty. if Clipboard.FormatCount = 0 then Exit; { Gnome } formatId := Clipboard.FindFormatID(gnomeClipboardMime); if formatId <> 0 then begin s := GetClipboardFormatAsString(formatId); { Format is: 'cut' or 'copy' + line ending character, followed by an URI-list delimited with line ending characters. Filenames may be UTF-8 encoded. e.g. cut#10file://host/path/to/file/name%C4%85%C3%B3%C5%9B%C5%BA%C4%87 } { Check operation } if (Length(s) >= Length(CutText)) and (CompareChar(s[1], CutText, Length(CutText)) = 0) then begin ClipboardOp := ClipboardCut; uriList := Copy(s, 1 + Length(CutText), Length(s)-Length(CutText)); end else if (Length(s) >= Length(CopyText)) and (CompareChar(s[1], CopyText, Length(CopyText)) = 0) then begin ClipboardOp := ClipboardCopy; uriList := Copy(s, 1 + Length(CopyText), Length(s)-Length(CopyText)); end; if Length(uriList) > 0 then uriList := URIDecode(Trim(uriList)); end else { KDE } begin formatId := Clipboard.FindFormatID(kdeClipboardMime); if formatId <> 0 then begin s := GetClipboardFormatAsString(formatId); { We should have a single char: '1' if 'cut', '0' if 'copy'. } { No uri-list in this target. } if Length(s) > 0 then begin if s[1] = '1' then ClipboardOp := ClipboardCut else ClipboardOp := ClipboardCopy; end; end; end; { Common formats } if uriList = '' then begin // Try to read one of the text formats. // The URIs in targets like STRING, UTF8_STRING, etc. are not encoded. // First try default target choosing behaviour. // Some buggy apps, however, supply UTF8_STRING or other targets // with 0 size and it's not detected by this function under gtk. uriList := Clipboard.AsText; // Next, try URI encoded list. if uriList = '' then begin uriList := GetClipboardFormatAsString(uriListMime); if Length(uriList) > 0 then uriList := URIDecode(Trim(uriList)); end; // Try plain texts now. // On non-UTF8 systems these should be encoded in system locale, // and may be displayed badly, but will be copied successfully. if uriList = '' then begin uriList := GetClipboardFormatAsString('STRING'); end; if uriList = '' then begin uriList := GetClipboardFormatAsString(textPlainMime); end; // If still nothing, then maybe the clipboard has no data in text format. if uriList = '' then Exit; end; filenames := ExtractFilenames(uriList); if (filenames <> nil) and (filenames.Count > 0) then Result := True; end; {$ENDIF} // MacOs 10.5 compatibility {$IFDEF DARWIN} function getStringFromPasteboard( pbType : NSString ) : String; var pb : NSPasteboard; begin pb := NSPasteboard.generalPasteboard; Result := NSStringToString( pb.stringForType( pbType ) ); end; function getOpFromPasteboard() : TClipboardOperation; var opString : String; begin Result := ClipboardCopy; opString := getStringFromPasteboard( StringToNSString(darwinPasteboardOpMime) ); if TClipboardOperationName[ClipboardCut].CompareTo(opString) = 0 then Result := ClipboardCut; end; function getFilenamesFromPasteboard() : TStringList; var pb : NSPasteboard; filenameArray{, lClasses}: NSArray; begin Result := nil; pb := NSPasteboard.generalPasteboard; filenameArray := pb.propertyListForType(NSFilenamesPboardType); if filenameArray <> nil then Result := NSArrayToList( filenameArray ); end; function PasteFromClipboard(out ClipboardOp: TClipboardOperation; out filenames:TStringList):Boolean; begin Result := false; ClipboardOp := ClipboardCopy; filenames := getFilenamesFromPasteboard(); if filenames <> nil then begin ClipboardOp := getOpFromPasteboard(); Result := true; end; end; {$ENDIF} {$IFDEF MSWINDOWS} procedure ClearClipboard; begin if OpenClipboard(0) then begin EmptyClipboard; CloseClipboard; end; end; {$ENDIF} {$IFDEF UNIX_not_DARWIN} procedure ClearClipboard; begin Clipboard.Open; Clipboard.AsText := ''; Clipboard.Close; end; {$ENDIF} // MacOs 10.5 compatibility {$IFDEF DARWIN} procedure ClearClipboard( pb:NSPasteboard ); begin pb.clearContents; end; procedure ClearClipboard; begin ClearClipboard( NSPasteboard.generalPasteboard ); end; {$ENDIF} {$IF DEFINED(MSWINDOWS)} procedure ClipboardSetText(AText: String); begin Clipboard.AsText := AText; end; {$ENDIF} {$IF DEFINED(UNIX_not_DARWIN)} procedure ClipboardSetText(AText: String); begin {$IFNDEF LCLGTK2} Clipboard.AsText := AText; {$ELSE} // Workaround for Lazarus bug #0021453. LCL adds trailing zero to clipboard in Clipboard.AsText. if Length(AText) = 0 then Clipboard.AsText := '' else begin Clipboard.Clear; Clipboard.AddFormat(PredefinedClipboardFormat(pcfText), AText[1], Length(AText)); end; {$ENDIF} end; {$ENDIF} // MacOs 10.5 compatibility {$IFDEF DARWIN} procedure ClipboardSetText(AText: String); begin ClearClipboard; NSPasteboardAddString(AText); end; {$ENDIF} initialization RegisterUserFormats; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uOSUtils.pas����������������������������������������������������������0000644�0001750�0000144�00000063731�14743153644�017467� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains platform depended functions. Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uOSUtils; {$mode delphi} {$IFDEF DARWIN} {$modeswitch objectivec1} {$ENDIF} interface uses SysUtils, Classes, LCLType, uDrive, DCBasicTypes, uFindEx {$IF DEFINED(UNIX)} , DCFileAttributes {$IFDEF DARWIN} , MacOSAll {$ENDIF} {$ENDIF} ; const CnstUserCommand = '{command}'; {$IF DEFINED(MSWINDOWS)} faFolder = faDirectory; ReversePathDelim = '/'; RunTermCmd = 'cmd.exe'; // default terminal RunTermParams = ''; RunInTermStayOpenCmd = 'cmd.exe'; // default run in terminal command AND Stay open after command RunInTermStayOpenParams = '/K {command}'; RunInTermCloseCmd = 'cmd.exe'; // default run in terminal command AND Close after command RunInTermCloseParams = '/C {command}'; fmtCommandPath = '%s>'; MonoSpaceFont = 'Courier New'; {$ELSEIF DEFINED(UNIX)} faFolder = S_IFDIR; ReversePathDelim = '\'; {$IF DEFINED(DARWIN)} RunTermCmd: String = '/Applications/Utilities/Terminal.app'; // default terminal RunTermParams = '%D'; RunInTermStayOpenCmd = '%COMMANDER_PATH%/scripts/terminal.sh'; // default run in terminal command AND Stay open after command RunInTermStayOpenParams = '''{command}'''; RunInTermCloseCmd = ''; // default run in terminal command AND Close after command RunInTermCloseParams = ''; MonoSpaceFont = 'Monaco'; {$ELSEIF DEFINED(HAIKU)} RunTermCmd: String = 'Terminal'; // default terminal RunTermParams: String = '-w %D'; RunInTermStayOpenCmd: String = ''; // default run in terminal command AND Stay open after command RunInTermStayOpenParams: String = ''; RunInTermCloseCmd: String = ''; // default run in terminal command AND Close after command RunInTermCloseParams: String = ''; MonoSpaceFont = 'Noto Sans Mono'; {$ELSE} RunTermCmd: String = 'xterm'; // default terminal RunTermParams: String = ''; RunInTermStayOpenCmd: String = 'xterm'; // default run in terminal command AND Stay open after command RunInTermStayOpenParams: String = '-e sh -c ''{command}; echo -n Press ENTER to exit... ; read a'''; RunInTermCloseCmd: String = 'xterm'; // default run in terminal command AND Close after command RunInTermCloseParams: String = '-e sh -c ''{command}'''; MonoSpaceFont: String = 'Monospace'; {$ENDIF} fmtCommandPath = '[%s]$:'; {$ENDIF} termStayOpen=True; termClose=False; type tTerminalEndindMode = boolean; EInvalidCommandLine = class(Exception); EInvalidQuoting = class(EInvalidCommandLine) constructor Create; reintroduce; end; {$IF DEFINED(MSWINDOWS) and DEFINED(FPC_HAS_CPSTRING)} NativeString = UnicodeString; {$ELSE} NativeString = String; {$ENDIF} function NtfsHourTimeDelay(const SourceName, TargetName: String): Boolean; function FileIsLinkToFolder(const FileName: String; out LinkTarget: String): Boolean; function FileIsLinkToDirectory(const FileName: String; Attr: TFileAttrs): Boolean; {en Execute command line } function ExecCmdFork(sCmd: String): Boolean; {en Execute external commands @param(sCmd The executable) @param(sParams The optional parameters) @param(sStartPath The initial working directory) @param(bShowCommandLinePriorToExecute Flag indicating if we want the user to be prompted at the very last seconds prior to launch execution by offering a dialog window where he can adjust/confirm the three above parameters.) @param(bTerm Flag indicating if it should be launch through terminal) @param(bKeepTerminalOpen Value indicating the type of terminal to use (closed at the end, remain opened, etc.)) } function ExecCmdFork(sCmd: String; sParams: String; sStartPath: String = ''; bShowCommandLinePriorToExecute: Boolean = False; bTerm: Boolean = False; bKeepTerminalOpen: tTerminalEndindMode = termStayOpen): Boolean; {en Opens a file or URL in the user's preferred application @param(URL File name or URL) @returns(The function returns @true if successful, @false otherwise) } function ShellExecute(URL: String): Boolean; function GetDiskFreeSpace(const Path : String; out FreeSize, TotalSize : Int64) : Boolean; {en Get maximum file size for a mounted file system @param(Path The pathname of any file within the mounted file system) @returns(The maximum file size for a mounted file system) } function GetDiskMaxFileSize(const Path : String) : Int64; function GetTempFolder: String; { Similar to "GetTempFolder" but that we can unilaterally delete at the end when closin application} function GetTempFolderDeletableAtTheEnd: String; procedure DeleteTempFolderDeletableAtTheEnd; {en Get the system specific self extracting archive extension @returns(Self extracting archive extension) } function GetSfxExt: String; function IsAvailable(Drive: PDrive; TryMount: Boolean = True) : Boolean; function GetShell : String; {en Formats a string which will execute Command via shell. } function FormatShell(const Command: String): String; {en Formats a string which will execute Command in a terminal. } procedure FormatTerminal(var sCmd: String; var sParams: String; bKeepTerminalOpen: tTerminalEndindMode); {en Convert file name to system encoding, if name can not be represented in current locale then use short file name under Windows. } function mbFileNameToSysEnc(const LongPath: String): String; {en Converts file name to native representation } function mbFileNameToNative(const FileName: String): NativeString; inline; function AccessDenied(LastError: Integer): Boolean; inline; procedure FixFormIcon(Handle: LCLType.HWND); procedure HideConsoleWindow; procedure FixDateNamesToUTF8; function ParamStrU(Param: Integer): String; overload; function ParamStrU(const Param: String): String; overload; {en Get the current username of the current session } function GetCurrentUserName : String; {en Get the current machine name } function GetComputerNetName: String; implementation uses StrUtils, uFileProcs, FileUtil, uDCUtils, DCOSUtils, DCStrUtils, uGlobs, uLng, fConfirmCommandLine, uLog, DCConvertEncoding, LazUTF8 {$IF DEFINED(MSWINDOWS)} , Windows, Shlwapi, WinRT.Classes, uMyWindows, JwaWinNetWk, uShlObjAdditional, DCWindows, uNetworkThread, uClipboard {$ENDIF} {$IF DEFINED(UNIX)} , BaseUnix, Unix, uMyUnix, dl {$IF DEFINED(DARWIN)} , CocoaAll, uMyDarwin {$ELSEIF NOT DEFINED(HAIKU)} , uGio, uClipboard, uXdg, uKde {$ENDIF} {$IF DEFINED(LINUX)} , DCUnix, uMyLinux, uFlatpak {$ENDIF} {$ENDIF} ; function FileIsLinkToFolder(const FileName: String; out LinkTarget: String): Boolean; {$IF DEFINED(MSWINDOWS)} begin Result:= False; if LowerCase(ExtractOnlyFileExt(FileName)) = 'lnk' then Result:= SHFileIsLinkToFolder(FileName, LinkTarget); end; {$ELSEIF DEFINED(UNIX)} begin Result:= False; if LowerCase(ExtractOnlyFileExt(FileName)) = 'desktop' then Result:= uMyUnix.FileIsLinkToFolder(FileName, LinkTarget); end; {$ENDIF} function ExecCmdFork(sCmd, sParams, sStartPath:String; bShowCommandLinePriorToExecute, bTerm : Boolean; bKeepTerminalOpen: tTerminalEndindMode) : Boolean; {$IFDEF UNIX} var Args : TDynamicStringArray; bFlagKeepGoing: boolean = True; begin result:=False; if bTerm then FormatTerminal(sCmd, sParams, bKeepTerminalOpen); if bShowCommandLinePriorToExecute then bFlagKeepGoing:= ConfirmCommandLine(sCmd, sParams, sStartPath); if bFlagKeepGoing then begin if (log_commandlineexecution in gLogOptions) then logWrite(rsMsgLogExtCmdLaunch+': '+rsSimpleWordFilename+'='+sCmd+' / '+rsSimpleWordParameter+'='+sParams+' / '+rsSimpleWordWorkDir+'='+sStartPath); if sCmd = EmptyStr then Exit(False); sCmd := UTF8ToSys(sCmd); SplitCommandArgs(UTF8ToSys(sParams), Args); Result := ExecuteCommand(sCmd, Args, sStartPath); if (log_commandlineexecution in gLogOptions) then begin if Result then logWrite(rsMsgLogExtCmdResult + ': ' + rsSimpleWordResult + '=' + rsSimpleWordSuccessExcla + ' / ' + rsSimpleWordFilename + '=' + sCmd + ' / ' + rsSimpleWordParameter + '=' + sParams + ' / ' + rsSimpleWordWorkDir + '=' + sStartPath) else logWrite(rsMsgLogExtCmdResult + ': ' + rsSimpleWordResult + '=' + rsSimpleWordFailedExcla + ' / ' + rsSimpleWordFilename + '=' + sCmd + ' / ' + rsSimpleWordParameter + '=' + sParams + ' / ' + rsSimpleWordWorkDir + '=' + sStartPath); end; end else begin Result := True; end; end; {$ELSE} var wFileName, wParams, wStartPath: WideString; bFlagKeepGoing: boolean = True; ExecutionResult:HINST; begin sStartPath:=RemoveQuotation(sStartPath); if sStartPath='' then sStartPath:=mbGetCurrentDir; sCmd:= NormalizePathDelimiters(sCmd); if bTerm then begin sCmd := ConcatenateStrWithSpace(sCmd,sParams); if bKeepTerminalOpen = termStayOpen then begin sParams:=StringReplace(gRunInTermStayOpenParams, '{command}', QuoteFilenameIfNecessary(sCmd) , [rfIgnoreCase]); sCmd := gRunInTermStayOpenCmd; end else begin sParams:=StringReplace(gRunInTermCloseParams, '{command}', QuoteFilenameIfNecessary(sCmd) , [rfIgnoreCase]); sCmd := gRunInTermCloseCmd; end; end; if bShowCommandLinePriorToExecute then bFlagKeepGoing:= ConfirmCommandLine(sCmd, sParams, sStartPath); if bFlagKeepGoing then begin wFileName:= CeUtf8ToUtf16(sCmd); wParams:= CeUtf8ToUtf16(sParams); wStartPath:= CeUtf8ToUtf16(sStartPath); if (log_commandlineexecution in gLogOptions) then logWrite(rsMsgLogExtCmdLaunch+': '+rsSimpleWordFilename+'='+sCmd+' / '+rsSimpleWordParameter+'='+sParams+' / '+rsSimpleWordWorkDir+'='+sStartPath); ExecutionResult:=ShellExecuteW(0, nil, PWChar(wFileName), PWChar(wParams), PWChar(wStartPath), SW_SHOW); if (log_commandlineexecution in gLogOptions) then logWrite(rsMsgLogExtCmdResult + ': ' + rsSimpleWordResult + '=' + ifThen((ExecutionResult > 32), rsSimpleWordSuccessExcla, IntToStr(ExecutionResult) + ':' + SysErrorMessage(ExecutionResult)) + ' / ' + rsSimpleWordFilename + '=' + sCmd + ' / ' + rsSimpleWordParameter + '=' + sParams + ' / ' + rsSimpleWordWorkDir + '=' + sStartPath); Result := (ExecutionResult > 32); end else begin result:=True; //User abort, so let's fake all things completed. end; end; {$ENDIF} function FileIsLinkToDirectory(const FileName: String; Attr: TFileAttrs): Boolean; {$IFDEF UNIX} var Info: BaseUnix.Stat; begin Result:= FPS_ISLNK(Attr) and (fpStat(UTF8ToSys(FileName), Info) >= 0) and FPS_ISDIR(Info.st_mode); end; {$ELSE} begin Result:= FPS_ISLNK(Attr) and FPS_ISDIR(Attr); end; {$ENDIF} function ExecCmdFork(sCmd: String): Boolean; {$IFDEF UNIX} var Command: String; Args : TDynamicStringArray; begin SplitCmdLine(sCmd, Command, Args); if (log_commandlineexecution in gLogOptions) then logWrite(rsMsgLogExtCmdLaunch + ': ' + rsSimpleWordCommand + '=' + sCmd); Result:= ExecuteCommand(Command, Args, EmptyStr); if (log_commandlineexecution in gLogOptions) then begin if Result then logWrite(rsMsgLogExtCmdResult + ': ' + rsSimpleWordResult + '=' + rsSimpleWordSuccessExcla + ' / ' + rsSimpleWordCommand + '=' + sCmd) else logWrite(rsMsgLogExtCmdResult + ': ' + rsSimpleWordResult + '=' + rsSimpleWordFailedExcla + ' / ' + rsSimpleWordCommand + '=' + sCmd); end; end; {$ELSE} var sFileName, sParams: String; ExecutionResult: HINST; wsStartPath: UnicodeString; begin SplitCmdLine(sCmd, sFileName, sParams); wsStartPath:= CeUtf8ToUtf16(mbGetCurrentDir()); sFileName:= NormalizePathDelimiters(sFileName); if (log_commandlineexecution in gLogOptions) then logWrite(rsMsgLogExtCmdLaunch + ': ' + rsSimpleWordFilename + '=' + sCmd + ' / ' + rsSimpleWordParameter + '=' + sParams); ExecutionResult := ShellExecuteW(0, nil, PWideChar(CeUtf8ToUtf16(sFileName)), PWideChar(CeUtf8ToUtf16(sParams)), PWideChar(wsStartPath), SW_SHOW); if (log_commandlineexecution in gLogOptions) then begin logWrite(rsMsgLogExtCmdResult + ': ' + rsSimpleWordResult + '=' + IfThen((ExecutionResult > 32), rsSimpleWordSuccessExcla, IntToStr(ExecutionResult) + ':' + SysErrorMessage(ExecutionResult)) + ' / ' + rsSimpleWordFilename + '=' + sCmd + ' / ' + rsSimpleWordParameter + '=' + sParams); end; Result := (ExecutionResult > 32); end; {$ENDIF} function ShellExecute(URL: String): Boolean; {$IF DEFINED(MSWINDOWS)} var cchOut: DWORD; Return: HINST; wsFileName: UnicodeString; wsStartPath: UnicodeString; AppID, FileExt: UnicodeString; begin cchOut:= MAX_PATH; SetLength(AppID, cchOut); URL:= NormalizePathDelimiters(URL); FileExt:= CeUtf8ToUtf16(ExtractFileExt(URL)); if CheckWin32Version(10) then begin if (AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_APPID, PWideChar(FileExt), nil, PWideChar(AppID), @cchOut) = S_OK) then begin if cchOut > 0 then begin SetLength(AppID, cchOut - 1); // Special case Microsoft Photos if (AppID = 'Microsoft.Windows.Photos_8wekyb3d8bbwe!App') then begin if CheckPhotosVersion then begin URL:= URIEncode(URL); URL:= 'ms-photos:viewer?fileName=' + StringReplace(URL, '%5C', '\', [rfReplaceAll]); end // Microsoft Photos does not work correct // when process has administrator rights else if (IsUserAdmin <> dupAccept) then begin TLauncherThread.LaunchFileAsync(URL); Exit(True); end; end; end; end; end; wsFileName:= CeUtf8ToUtf16(URL); wsStartPath:= CeUtf8ToUtf16(mbGetCurrentDir()); Return:= ShellExecuteW(0, nil, PWideChar(wsFileName), nil, PWideChar(wsStartPath), SW_SHOWNORMAL); if Return = SE_ERR_NOASSOC then Result:= ExecCmdFork('rundll32 shell32.dll OpenAs_RunDLL ' + QuoteDouble(URL)) else begin Result:= Return > 32; end; end; {$ELSEIF DEFINED(DARWIN)} var theFileNameCFRef: CFStringRef = nil; theFileNameUrlRef: CFURLRef = nil; theFileNameFSRef: FSRef; begin Result:= False; try theFileNameCFRef:= CFStringCreateWithFileSystemRepresentation(nil, PAnsiChar(URL)); theFileNameUrlRef:= CFURLCreateWithFileSystemPath(nil, theFileNameCFRef, kCFURLPOSIXPathStyle, False); if (CFURLGetFSRef(theFileNameUrlRef, theFileNameFSRef)) then begin Result:= (LSOpenFSRef(theFileNameFSRef, nil) = noErr); end; finally if Assigned(theFileNameCFRef) then CFRelease(theFileNameCFRef); if Assigned(theFileNameUrlRef) then CFRelease(theFileNameUrlRef); end; end; {$ELSE} var sCmdLine: String; begin Result:= False; if GetPathType(URL) = ptAbsolute then sCmdLine:= URL else begin sCmdLine:= IncludeTrailingPathDelimiter(mbGetCurrentDir); sCmdLine:= GetAbsoluteFileName(sCmdLine, URL) end; if FileIsUnixExecutable(sCmdLine) then begin Result:= ExecuteCommand(sCmdLine, [], mbGetCurrentDir); end else begin {$IF DEFINED(LINUX)} if (DesktopEnv = DE_FLATPAK) then Result:= FlatpakOpen(sCmdLine, False) else {$ENDIF} {$IF NOT DEFINED(HAIKU)} if (DesktopEnv = DE_KDE) and (HasKdeOpen = True) then Result:= KioOpen(sCmdLine) // Under KDE use "kioclient" to open files else if HasGio and (DesktopEnv <> DE_XFCE) then Result:= GioOpen(sCmdLine) // Under GNOME, Unity and LXDE use "GIO" to open files else {$ENDIF} begin sCmdLine:= GetDefaultAppCmd(sCmdLine); if Length(sCmdLine) > 0 then begin Result:= ExecCmdFork(sCmdLine); end; end; end; end; {$ENDIF} (* Get Disk Free Space *) function GetDiskFreeSpace(const Path : String; out FreeSize, TotalSize : Int64) : Boolean; {$IFDEF UNIX} var sbfs: TStatFS; begin Result:= (fpStatFS(PAnsiChar(CeUtf8ToSys(Path)), @sbfs) = 0); if not Result then Exit; {$IFDEF LINUX} if (sbfs.fstype = RAMFS_MAGIC) then begin Exit(GetFreeMem(FreeSize, TotalSize)); end; {$ENDIF} if (sbfs.blocks = 0) then Exit(False); FreeSize := (Int64(sbfs.bavail) * sbfs.bsize); TotalSize := (Int64(sbfs.blocks) * sbfs.bsize); end; {$ELSE} var wPath: UnicodeString; begin FreeSize := 0; TotalSize := 0; wPath:= UTF16LongName(Path); Result:= GetDiskFreeSpaceExW(PWideChar(wPath), FreeSize, TotalSize, nil); end; {$ENDIF} function GetDiskMaxFileSize(const Path: String): Int64; {$IFDEF UNIX} const MSDOS_SUPER_MAGIC = $4d44; var sbfs: TStatFS; begin Result := High(Int64); {$IF NOT DEFINED(HAIKU)} if (fpStatFS(PAnsiChar(CeUtf8ToSys(Path)), @sbfs) = 0) then begin {$IFDEF BSD} if (sbfs.ftype = MSDOS_SUPER_MAGIC) then {$ELSE} if (sbfs.fstype = MSDOS_SUPER_MAGIC) then {$ENDIF} Result:= $FFFFFFFF; // 4 Gb end; {$ENDIF} end; {$ELSE} var lpVolumeNameBuffer, lpFileSystemNameBuffer: array [0..255] of WideChar; lpMaximumComponentLength: DWORD = 0; lpFileSystemFlags: DWORD = 0; begin Result := High(Int64); if GetVolumeInformationW(PWideChar(CeUtf8ToUtf16(ExtractFileDrive(Path)) + PathDelim), lpVolumeNameBuffer, SizeOf(lpVolumeNameBuffer), nil, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, SizeOf(lpFileSystemNameBuffer)) then begin if SameText(lpFileSystemNameBuffer, 'FAT') then Result:= $80000000 // 2 Gb else if SameText(lpFileSystemNameBuffer, 'FAT32') then Result:= $FFFFFFFF; // 4 Gb end; end; {$ENDIF} function NtfsHourTimeDelay(const SourceName, TargetName: String): Boolean; {$IFDEF MSWINDOWS} var lpDummy: DWORD = 0; lpSourceFileSystem, lpTargetFileSystem: array [0..MAX_PATH] of WideChar; begin Result:= False; if GetVolumeInformationW(PWideChar(CeUtf8ToUtf16(ExtractFileDrive(SourceName)) + PathDelim), nil, 0, nil, lpDummy, lpDummy, lpSourceFileSystem, MAX_PATH) and GetVolumeInformationW(PWideChar(CeUtf8ToUtf16(ExtractFileDrive(TargetName)) + PathDelim), nil, 0, nil, lpDummy, lpDummy, lpTargetFileSystem, MAX_PATH) then begin Result:= (SameText(lpSourceFileSystem, 'FAT32') and SameText(lpTargetFileSystem, 'NTFS')) or (SameText(lpTargetFileSystem, 'FAT32') and SameText(lpSourceFileSystem, 'NTFS')) end; end; {$ELSE} begin Result:= False; end; {$ENDIF} function GetShell : String; {$IFDEF MSWINDOWS} begin Result:= mbGetEnvironmentVariable('ComSpec'); end; {$ELSE} begin Result:= SysToUTF8(GetEnvironmentVariable('SHELL')); end; {$ENDIF} function FormatShell(const Command: String): String; begin {$IF DEFINED(UNIX)} Result := Format('%s -c %s', [GetShell, QuoteSingle(Command)]); {$ELSEIF DEFINED(MSWINDOWS)} Result := Format('%s /C %s', [GetShell, QuoteDouble(Command)]); {$ENDIF} end; procedure FormatTerminal(var sCmd: String; var sParams: String; bKeepTerminalOpen: tTerminalEndindMode); var sConfigParam:string; begin {$IF DEFINED(UNIX)} sParams := ConcatenateStrWithSpace(sCmd, sParams); if bKeepTerminalOpen = termStayOpen then begin sCmd := gRunInTermStayOpenCmd; sConfigParam := gRunInTermStayOpenParams; end else begin sCmd := gRunInTermCloseCmd; sConfigParam := gRunInTermCloseParams; end; sCmd := ReplaceEnvVars(sCmd); if Pos(CnstUserCommand, sConfigParam) <> 0 then sParams := StringReplace(sConfigParam, CnstUserCommand, sParams , [rfIgnoreCase]) else sParams := ConcatenateStrWithSpace(sConfigParam, sParams); {$ELSEIF DEFINED(MSWINDOWS)} // if bKeepTerminalOpen then // Result := Format('%s %s', [gRunInTermStayOpenCmd, QuoteDouble(Command)]) // else // Result := Format('%s %s', [gRunInTermCloseCmd, QuoteDouble(Command)]); sParams := ConcatenateStrWithSpace(sCmd, sParams); if bKeepTerminalOpen = termStayOpen then begin sCmd := gRunInTermStayOpenCmd; sConfigParam := gRunInTermStayOpenParams; end else begin sCmd := gRunInTermCloseCmd; sConfigParam := gRunInTermCloseParams; end; if pos(CnstUserCommand,sConfigParam)<>0 then sParams := StringReplace(sConfigParam, CnstUserCommand, sParams , [rfIgnoreCase]) else sParams:=ConcatenateStrWithSpace(sConfigParam, sParams); {$ENDIF} end; function GetTempFolder: String; begin Result:= GetTempDir + '_dc'; if not mbDirectoryExists(Result) then mbCreateDir(Result); Result:= Result + PathDelim; end; function GetTempFolderDeletableAtTheEnd: String; begin Result:= GetTempDir + '_dc~~~'; if not mbDirectoryExists(Result) then mbCreateDir(Result); Result:= Result + PathDelim; end; procedure DeleteTempFolderDeletableAtTheEnd; var TempFolderName:string; begin TempFolderName:= GetTempDir + '_dc~~~'; if mbDirectoryExists(TempFolderName) then DelTree(TempFolderName); end; function GetSfxExt: String; {$IFDEF MSWINDOWS} begin Result:= '.exe'; end; {$ELSE} begin Result:= '.run'; end; {$ENDIF} function IsAvailable(Drive: PDrive; TryMount: Boolean): Boolean; {$IF DEFINED(MSWINDOWS)} var Drv: String; DriveLabel: String; wsLocalName, wsRemoteName: WideString; begin Drv:= ExtractFileDrive(Drive^.Path) + PathDelim; // Try to close CD/DVD drive if (Drive^.DriveType = dtOptical) and TryMount and (not mbDriveReady(Drv)) then begin DriveLabel:= mbGetVolumeLabel(Drv, False); mbCloseCD(Drv); if mbDriveReady(Drv) then mbWaitLabelChange(Drv, DriveLabel); end // Try to connect to mapped network drive else if (Drive^.DriveType = dtNetwork) and TryMount and (not mbDriveReady(Drv)) then begin wsLocalName := CeUtf8ToUtf16(ExtractFileDrive(Drive^.Path)); wsRemoteName := CeUtf8ToUtf16(Drive^.DriveLabel); TNetworkThread.Connect(PWideChar(wsLocalName), PWideChar(wsRemoteName), RESOURCETYPE_DISK); end // Try to unlock BitLocker Drive else if TryMount then begin mbDriveUnlock(Drive^.Path); end; Result:= mbDriveReady(Drv); end; {$ELSEIF DEFINED(DARWIN)} begin // Because we show under Mac OS X only mounted volumes Result:= True; end; {$ELSEIF DEFINED(LINUX)} var mtab: PIOFile; pme: PMountEntry; begin Result:= False; mtab:= setmntent(_PATH_MOUNTED,'r'); if not Assigned(mtab) then exit; pme:= getmntent(mtab); while (pme <> nil) do begin if CeSysToUtf8(pme.mnt_dir) = Drive^.Path then begin Result:= True; Break; end; pme:= getmntent(mtab); end; endmntent(mtab); if not Result and TryMount then Result := MountDrive(Drive); end; {$ELSE} begin Result:= True; end; {$ENDIF} function mbFileNameToSysEnc(const LongPath: String): String; {$IFDEF MSWINDOWS} begin Result:= CeUtf8ToSys(LongPath); if Pos('?', Result) <> 0 then mbGetShortPathName(LongPath, Result); end; {$ELSE} begin Result:= CeUtf8ToSys(LongPath); end; {$ENDIF} function AccessDenied(LastError: Integer): Boolean; {$IF DEFINED(MSWINDOWS)} begin Result:= (LastError = ERROR_ACCESS_DENIED); end; {$ELSE} begin Result:= (LastError = ESysEPERM) or (LastError = ESysEACCES); end; {$ENDIF} procedure FixFormIcon(Handle: LCLType.HWND); begin // Workaround for Lazarus issue 0018484. // Any form that sets its own icon should call this in FormCreate. {$IFDEF WINDOWS} Windows.SetClassLong(Handle, GCL_HICONSM, 0); Windows.SetClassLong(Handle, GCL_HICON, 0); {$ENDIF} end; procedure HideConsoleWindow; begin {$IFDEF WINDOWS} if isConsole then ShowWindow(GetConsoleWindow, SW_HIDE); {$ENDIF} end; procedure FixDateNamesToUTF8; var i: Integer; begin with DefaultFormatSettings do begin for i := Low(ShortMonthNames) to High(ShortMonthNames) do ShortMonthNames[i] := SysToUTF8(ShortMonthNames[i]); for i := Low(ShortDayNames) to High(ShortDayNames) do ShortDayNames[i] := SysToUTF8(ShortDayNames[i]); for i := Low(LongMonthNames) to High(LongMonthNames) do LongMonthNames[i] := SysToUTF8(LongMonthNames[i]); for i := Low(LongDayNames) to High(LongDayNames) do LongDayNames[i] := SysToUTF8(LongDayNames[i]); end; end; function ParamStrU(Param: Integer): String; {$IFDEF UNIX} begin Result:= SysToUTF8(ObjPas.ParamStr(Param)); end; {$ELSE} begin if (Param >= 0) and (Param < argc) then Result:= StrPas(argv[Param]) else Result:= EmptyStr; end; {$ENDIF} function ParamStrU(const Param: String): String; {$IFDEF UNIX} begin Result:= SysToUTF8(Param); end; {$ELSE} begin Result:= Param; end; {$ENDIF} { EInvalidQuoting } constructor EInvalidQuoting.Create; begin inherited Create(rsMsgInvalidQuoting); end; { GetCurrentUserName } function GetCurrentUserName : String; {$IF DEFINED(MSWINDOWS)} var wsUserName : UnicodeString; dwUserNameLen : DWORD = UNLEN + 1; begin SetLength(wsUserName, dwUserNameLen); if GetUserNameW(PWideChar(wsUserName), dwUserNameLen) then begin SetLength(wsUserName, dwUserNameLen - 1); Result := UTF16ToUTF8(wsUserName); end else Result := 'Unknown'; end; {$ELSEIF DEFINED(UNIX)} begin Result:= SysToUTF8(GetEnvironmentVariable('USER')); end; {$ENDIF} { GetComputerNetName } function GetComputerNetName: String; {$IF DEFINED(MSWINDOWS)} var Size: DWORD = MAX_PATH; Buffer: array[0..Pred(MAX_PATH)] of WideChar; begin if GetComputerNameW(Buffer, Size) then Result := UTF16ToUTF8(UnicodeString(Buffer)) else Result := '' end; {$ELSEIF DEFINED(UNIX)} begin Result:= SysToUTF8(GetHostName); end; {$ENDIF} function mbFileNameToNative(const FileName: String): NativeString; {$IF DEFINED(MSWINDOWS) and DEFINED(FPC_HAS_CPSTRING)} begin Result:= UTF16LongName(FileName); end; {$ELSE} begin Result:= Utf8ToSys(FileName); end; {$ENDIF} end. ���������������������������������������doublecmd-1.1.22/src/platform/uOleDragDrop.pas������������������������������������������������������0000644�0001750�0000144�00000146141�14743153644�020264� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ DRAGDROP.PAS -- simple realization of OLE drag and drop. Author: Jim Mischel Last modification date: 30/05/97 Add some changes for compatibility with FPC/Lazarus Copyright (C) 2009 Alexander Koblov (Alexx2000@mail.ru) Some inspiration for drag-and-drop using CF_FILEGROUPDESCRIPTORW and CFU_FILECONTENTS: -http://msdn.microsoft.com/en-us/library/windows/desktop/bb776904%28v=vs.85%29.aspx#filecontents -http://www.unitoops.com/uoole/examples/outlooktest.htm } unit uOleDragDrop; {$mode delphi}{$H+} interface uses DCBasicTypes, Windows, ActiveX, Classes, Controls, ShlObj, uDragDropEx; type { IEnumFormatEtc } TEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc) private FIndex: Integer; public constructor Create(Index: Integer = 0); function Next(celt: LongWord; out elt: FormatEtc; pceltFetched: pULong): HResult; stdcall; function Skip(celt: LongWord): HResult; stdcall; function Reset: HResult; stdcall; function Clone(out enum: IEnumFormatEtc): HResult; stdcall; end; { TDragDropInfo } TDragDropInfo = class(TObject) private FFileList: TStringList; FPreferredWinDropEffect: DWORD; function CreateHDrop(bUnicode: Boolean): HGlobal; function CreateFileNames(bUnicode: Boolean): HGlobal; function CreateURIs(bUnicode: Boolean): HGlobal; function CreateShellIdListArray: HGlobal; function MakeHGlobal(ptr: Pointer; Size: LongWord): HGlobal; public constructor Create(PreferredWinDropEffect: DWORD); destructor Destroy; override; procedure Add(const s: string); function MakeDataInFormat(const formatEtc: TFormatEtc): HGlobal; function CreatePreferredDropEffect(WinDropEffect: DWORD): HGlobal; property Files: TStringList Read FFileList; end; TDragDropTargetWindows = class; // forward declaration { TFileDropTarget знает, как принимать сброшенные файлы } TFileDropTarget = class(TInterfacedObject, IDropTarget) private FHandle: HWND; FReleased: Boolean; FDragDropTarget: TDragDropTargetWindows; protected function GetFiles(const dataObj: IDataObject; ChosenFormat: TFormatETC; out FileNames: TStringList; out Medium: TSTGMedium): HRESULT; public constructor Create(DragDropTarget: TDragDropTargetWindows); {en Unregisters drag&drop target and releases the object (it is destroyed). This is the function that should be called to cleanup the object instead of Free. Do not use the object after calling it. } procedure FinalRelease; function DragEnter(const {%H-}dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall; function DragOver(grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall; function DragLeave: HResult; stdcall; function Drop(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall; {en Retrieves the filenames from the HDROP format as a list of UTF-8 strings. @returns(List of filenames or nil in case of an error.) } class function GetDropFilenames(hDropData: HDROP): TStringList; {en Retrieves the filenames from the CFU_FILEGROUPDESCRIPTORW/CFU_FILEGROUPDESCRIPTOR format as a list of UTF-8 strings. @returns(List of filenames or nil in case of an error.) } function GetDropFileGroupFilenames(const dataObj: IDataObject; var Medium: TSTGMedium; Format: TFormatETC): TStringList; function SaveCfuContentToFile(const dataObj:IDataObject; Index:Integer; WantedFilename:String; FileInfo: PFileDescriptorW):boolean; {en Retrieves the text from the CF_UNICODETEXT/CF_TEXT format, will store this in a single file return filename as a list of a single UTF-8 string. @returns(List of filenames or nil in case of an error.) } function GetDropTextCreatedFilenames(var Medium: TSTGMedium; Format: TFormatETC): TStringList; end; { TFileDropSource - источник для перетаскивания файлов } TFileDropSource = class(TInterfacedObject, IDropSource) public constructor Create; function QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: DWORD): HResult; stdcall; function GiveFeedback(dwEffect: DWORD): HResult; stdcall; end; { THDropDataObject - объект данных с информацией о перетаскиваемых файлах } THDropDataObject = class(TInterfacedObject, IDataObject) private FDropInfo: TDragDropInfo; public constructor Create(PreferredWinDropEffect: DWORD); destructor Destroy; override; procedure Add(const s: string); { из IDataObject } function GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; stdcall; function GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult; stdcall; function QueryGetData(const formatetc: TFormatEtc): HResult; stdcall; function GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult; stdcall; function SetData(const formatetc: TFormatEtc; {$IF FPC_FULLVERSION < 30200}const{$ELSE}var{$ENDIF} medium: TStgMedium; fRelease: BOOL): HResult; stdcall; function EnumFormatEtc(dwDirection: LongWord; out enumFormatEtc: IEnumFormatEtc): HResult; stdcall; function DAdvise(const formatetc: TFormatEtc; advf: LongWord; const advSink: IAdviseSink; out dwConnection: LongWord): HResult; stdcall; function DUnadvise(dwConnection: LongWord): HResult; stdcall; function EnumDAdvise(out enumAdvise: IEnumStatData): HResult; stdcall; end; TDragDropSourceWindows = class(TDragDropSource) public function RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent;// not handled in Windows DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; override; function DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint ): Boolean; override; end; TDragDropTargetWindows = class(TDragDropTarget) public constructor Create(Control: TWinControl); override; destructor Destroy; override; function RegisterEvents(DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; override; procedure UnregisterEvents; override; private FDragDropTarget: TFileDropTarget; end; function GetEffectByKeyState(grfKeyState: LongWord) : Integer; { These functions convert Windows-specific effect value to { TDropEffect values and vice-versa. } function WinEffectToDropEffect(dwEffect: LongWord): TDropEffect; function DropEffectToWinEffect(DropEffect: TDropEffect): LongWord; { Query DROPFILES structure for [BOOL fWide] parameter } function DragQueryWide( hGlobalDropInfo: HDROP ): boolean; implementation uses //Lazarus, Free-Pascal, etc. LazUTF8, SysUtils, ShellAPI, LCLIntf, ComObj, IntegerList, DCDateTimeUtils, Forms, DCConvertEncoding, //DC uOSUtils, fOptionsDragDrop, uShowMsg, UGlobs, DCStrUtils, DCOSUtils, uClipboard, uLng, uDebug, uShlObjAdditional, uOSForms; var // Supported formats by the source. DataFormats: TList = nil; // of TFormatEtc procedure InitDataFormats; procedure AddFormat(FormatId: Word); var FormatEtc: PFormatEtc; begin if FormatId > 0 then begin New(FormatEtc); if Assigned(FormatEtc) then begin DataFormats.Add(FormatEtc); with FormatEtc^ do begin CfFormat := FormatId; Ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := -1; tymed := TYMED_HGLOBAL; end; end; end; end; begin DataFormats := TList.Create; AddFormat(CF_HDROP); AddFormat(CFU_PREFERRED_DROPEFFECT); AddFormat(CFU_FILENAME); AddFormat(CFU_FILENAMEW); // URIs disabled for now. This implementation does not work correct. // See bug http://doublecmd.sourceforge.net/mantisbt/view.php?id=692 { AddFormat(CFU_UNIFORM_RESOURCE_LOCATOR); AddFormat(CFU_UNIFORM_RESOURCE_LOCATORW); } AddFormat(CFU_SHELL_IDLIST_ARRAY); end; procedure DestroyDataFormats; var i : Integer; begin if Assigned(DataFormats) then begin for i := 0 to DataFormats.Count - 1 do if Assigned(DataFormats.Items[i]) then Dispose(PFormatEtc(DataFormats.Items[i])); FreeAndNil(DataFormats); end; end; { TEnumFormatEtc.Create } constructor TEnumFormatEtc.Create(Index: Integer); begin inherited Create; FIndex := Index; end; { TEnumFormatEtc.Next извлекает заданное количество структур TFormatEtc в передаваемый массив elt. Извлекается celt элементов, начиная с текущей позиции в списке. } function TEnumFormatEtc.Next(celt: LongWord; out elt: FormatEtc; pceltFetched: pULong): HResult; var i: Integer; eltout: PFormatEtc; begin // Support returning only 1 format at a time. if celt > 1 then celt := 1; eltout := @elt; i := 0; while (i < celt) and (FIndex < DataFormats.Count) do begin (eltout + i)^ := PFormatEtc(DataFormats.Items[FIndex])^; Inc(FIndex); Inc(i); end; if (pceltFetched <> nil) then pceltFetched^ := i; if (I = celt) then Result := S_OK else Result := S_FALSE; end; { TEnumFormatEtc.Skip пропускает celt элементов списка, устанавливая текущую позицию на (CurrentPointer + celt) или на конец списка в случае переполнения. } function TEnumFormatEtc.Skip(celt: LongWord): HResult; begin if (celt <= DataFormats.Count - FIndex) then begin FIndex := FIndex + celt; Result := S_OK; end else begin FIndex := DataFormats.Count; Result := S_FALSE; end; end; { TEnumFormatEtc.Reset устанавливает указатель текущей позиции на начало списка } function TEnumFormatEtc.Reset: HResult; begin FIndex := 0; Result := S_OK; end; { TEnumFormatEtc.Clone копирует список структур } function TEnumFormatEtc.Clone(out enum: IEnumFormatEtc): HResult; begin enum := TEnumFormatEtc.Create(FIndex); Result := S_OK; end; { TDragDropInfo.Create } constructor TDragDropInfo.Create(PreferredWinDropEffect: DWORD); begin inherited Create; FFileList := TStringList.Create; FPreferredWinDropEffect := PreferredWinDropEffect; end; { TDragDropInfo.Destroy } destructor TDragDropInfo.Destroy; begin FFileList.Free; inherited Destroy; end; { TDragDropInfo.Add } procedure TDragDropInfo.Add(const s: string); begin Files.Add(s); end; { TDragDropInfo.MakeDataInFormat } function TDragDropInfo.MakeDataInFormat(const formatEtc: TFormatEtc): HGlobal; begin Result := 0; if (formatEtc.tymed = DWORD(-1)) or // Transport medium not specified. (Boolean(formatEtc.tymed and TYMED_HGLOBAL)) // Support only HGLOBAL medium. then begin if formatEtc.CfFormat = CF_HDROP then begin Result := CreateHDrop(Win32Platform = VER_PLATFORM_WIN32_NT) end else if formatEtc.CfFormat = CFU_PREFERRED_DROPEFFECT then begin Result := CreatePreferredDropEffect(FPreferredWinDropEffect); end else if (formatEtc.CfFormat = CFU_FILENAME) then begin Result := CreateFileNames(False); end else if (formatEtc.CfFormat = CFU_FILENAMEW) then begin Result := CreateFileNames(True); end // URIs disabled for now. This implementation does not work correct. // See bug http://doublecmd.sourceforge.net/mantisbt/view.php?id=692 { else if (formatEtc.CfFormat = CFU_UNIFORM_RESOURCE_LOCATOR) then begin Result := CreateURIs(False); end else if (formatEtc.CfFormat = CFU_UNIFORM_RESOURCE_LOCATORW) then begin Result := CreateURIs(True); end } else if (formatEtc.CfFormat = CFU_SHELL_IDLIST_ARRAY) then begin Result := CreateShellIdListArray; end; end; end; { TDragDropInfo.CreateFileNames } function TDragDropInfo.CreateFileNames(bUnicode: Boolean): HGlobal; var FileList: AnsiString; wsFileList: WideString; begin if Files.Count = 0 then Exit; if bUnicode then begin wsFileList := CeUtf8ToUtf16(Self.Files[0]) + #0; Result := MakeHGlobal(PWideChar(wsFileList), Length(wsFileList) * SizeOf(WideChar)); end else begin FileList := CeUtf8ToAnsi(Self.Files[0]) + #0; Result := MakeHGlobal(PAnsiChar(FileList), Length(FileList) * SizeOf(AnsiChar)); end; end; { TDragDropInfo.CreateURIs } function TDragDropInfo.CreateURIs(bUnicode: Boolean): HGlobal; var UriList: AnsiString; wsUriList: WideString; I: Integer; begin wsUriList := ''; for I := 0 to Self.Files.Count - 1 do begin if I > 0 then wsUriList := wsUriList + LineEnding; wsUriList := wsUriList + fileScheme + '//' { don't put hostname } + CeUtf8ToUtf16(URIEncode(StringReplace(Files[I], '\', '/', [rfReplaceAll] ))); end; wsUriList := wsUriList + #0; if bUnicode then Result := MakeHGlobal(PWideChar(wsUriList), Length(wsUriList) * SizeOf(WideChar)) else begin // Wide to Ansi UriList := CeUtf8ToAnsi(UTF16ToUTF8(wsUriList)); Result := MakeHGlobal(PAnsiChar(UriList), Length(UriList) * SizeOf(AnsiChar)); end; end; { TDragDropInfo.CreateShellIdListArray } function TDragDropInfo.CreateShellIdListArray: HGlobal; var pidl: LPITEMIDLIST; pidlSize: Integer; pIdA: LPIDA = nil; // ShellIdListArray structure ShellDesktop: IShellFolder = nil; CurPosition: UINT; dwTotalSizeToAllocate: DWORD; I: Integer; function GetPidlFromPath(ShellFolder: IShellFolder; Path: WideString): LPITEMIDLIST; var chEaten: ULONG = 0; dwAttributes: ULONG = 0; begin if ShellFolder.ParseDisplayName(0, nil, PWideChar(Path), chEaten, Result, dwAttributes) <> S_OK then begin Result := nil; end; end; function GetPidlSize(Pidl: LPITEMIDLIST): Integer; var pidlTmp: LPITEMIDLIST; begin Result := 0; pidlTmp := pidl; while pidlTmp^.mkid.cb <> 0 do begin Result := Result + pidlTmp^.mkid.cb; pidlTmp := LPITEMIDLIST(LPBYTE(pidlTmp) + PtrInt(pidlTmp^.mkid.cb)); // Next Item. end; Inc(Result, SizeOf(BYTE) * 2); // PIDL ends with two zeros. end; begin Result := 0; // Get Desktop shell interface. if SHGetDesktopFolder(ShellDesktop) = S_OK then begin // Get Desktop PIDL, which will be the root PIDL for the files' PIDLs. if SHGetFolderLocation(0, CSIDL_DESKTOP, 0, 0, pidl) = S_OK then begin pidlSize := GetPidlSize(pidl); // How much memory to allocate for the whole structure. // We don't know how much memory each PIDL takes yet // (estimate using desktop pidl size). dwTotalSizeToAllocate := SizeOf(_IDA.cidl) + SizeOf(UINT) * (Files.Count + 1) // PIDLs' offsets + pidlSize * (Files.Count + 1); // PIDLs pIda := AllocMem(dwTotalSizeToAllocate); // Number of files PIDLs (without root). pIdA^.cidl := Files.Count; // Calculate offset for the first pidl (root). CurPosition := SizeOf(_IDA.cidl) + SizeOf(UINT) * (Files.Count + 1); // Write first PIDL. pIdA^.aoffset[0] := CurPosition; CopyMemory(LPBYTE(pIda) + PtrInt(CurPosition), pidl, pidlSize); Inc(CurPosition, pidlSize); CoTaskMemFree(pidl); for I := 0 to Self.Files.Count - 1 do begin // Get PIDL for each file (if Desktop is the root, then // absolute paths are acceptable). pidl := GetPidlFromPath(ShellDesktop, CeUtf8ToUtf16(Files[i])); if pidl <> nil then begin pidlSize := GetPidlSize(pidl); // If not enough memory then reallocate. if dwTotalSizeToAllocate < CurPosition + pidlSize then begin // Estimate using current PIDL's size. Inc(dwTotalSizeToAllocate, (Files.Count - i) * pidlSize); pIdA := ReAllocMem(pIda, dwTotalSizeToAllocate); if not Assigned(pIda) then Break; end; // Write PIDL. {$R-} pIdA^.aoffset[i + 1] := CurPosition; {$R+} CopyMemory(LPBYTE(pIdA) + PtrInt(CurPosition), pidl, pidlSize); Inc(CurPosition, pidlSize); CoTaskMemFree(pidl); end; end; if Assigned(pIda) then begin // Current position it at the end of the structure. Result := MakeHGlobal(pIdA, CurPosition); Freemem(pIda); end; end; // SHGetSpecialFolderLocation ShellDesktop := nil; end; // SHGetDesktopFolder end; { TDragDropInfo.CreatePreferredDropEffect } function TDragDropInfo.CreatePreferredDropEffect(WinDropEffect: DWORD) : HGlobal; begin Result := MakeHGlobal(@WinDropEffect, SizeOf(WinDropEffect)); end; { TDragDropInfo.MakeHGlobal } function TDragDropInfo.MakeHGlobal(ptr: Pointer; Size: LongWord): HGlobal; var DataPointer : Pointer; DataHandle : HGLOBAL; begin Result := 0; if Assigned(ptr) then begin DataHandle := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT, Size); if (DataHandle <> 0) then begin DataPointer := GlobalLock(DataHandle); if Assigned(DataPointer) then begin CopyMemory(DataPointer, ptr, Size); GlobalUnlock(DataHandle); Result := DataHandle; end else begin GlobalFree(DataHandle); end; end; end; end; { TDragDropInfo.CreateHDrop } function TDragDropInfo.CreateHDrop(bUnicode: Boolean): HGlobal; var RequiredSize: Integer; I: Integer; hGlobalDropInfo: HGlobal; DropFiles: PDropFiles; FileList: AnsiString = ''; wsFileList: WideString = ''; begin { Построим структуру TDropFiles в памяти, выделенной через GlobalAlloc. Область памяти сделаем глобальной и совместной, поскольку она, вероятно, будет передаваться другому процессу. Bring the filenames in a form, separated by #0 and ending with a double #0#0 } if bUnicode then begin for I := 0 to Self.Files.Count - 1 do wsFileList := wsFileList + CeUtf8ToUtf16(Self.Files[I]) + #0; wsFileList := wsFileList + #0; { Определяем необходимый размер структуры } RequiredSize := SizeOf(TDropFiles) + Length(wsFileList) * SizeOf(WChar); end else begin for I := 0 to Self.Files.Count - 1 do FileList := FileList + CeUtf8ToAnsi(Self.Files[I]) + #0; FileList := FileList + #0; { Определяем необходимый размер структуры } RequiredSize := SizeOf(TDropFiles) + Length(FileList) * SizeOf(AnsiChar); end; hGlobalDropInfo := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT, RequiredSize); if (hGlobalDropInfo <> 0) then begin { Заблокируем область памяти, чтобы к ней можно было обратиться } DropFiles := GlobalLock(hGlobalDropInfo); { Заполним поля структуры DropFiles pFiles -- смещение от начала структуры до первого байта массива с именами файлов. } DropFiles.pFiles := SizeOf(TDropFiles); DropFiles.fWide := bUnicode; { Копируем имена файлов в буфер. Буфер начинается со смещения DropFiles + DropFiles.pFiles, то есть после последнего поля структуры. The pointer should be aligned nicely, because the TDropFiles record is not packed. } DropFiles := Pointer(DropFiles) + DropFiles.pFiles; if bUnicode then CopyMemory(DropFiles, PWideChar(wsFileList), Length(wsFileList) * SizeOf(WChar)) else CopyMemory(DropFiles, PAnsiChar(FileList), Length(FileList) * SizeOf(AnsiChar)); { Снимаем блокировку } GlobalUnlock(hGlobalDropInfo); end; Result := hGlobalDropInfo; end; function TFileDropTarget.GetFiles(const dataObj: IDataObject; ChosenFormat: TFormatETC; out FileNames: TStringList; out Medium: TSTGMedium): HRESULT; begin ChosenFormat.ptd := nil; ChosenFormat.dwAspect := DVASPECT_CONTENT; ChosenFormat.lindex := -1; ChosenFormat.tymed := TYMED_HGLOBAL; Result:= dataObj.GetData(ChosenFormat, Medium); if Result = S_OK then begin if Medium.Tymed = TYMED_HGLOBAL then begin case ChosenFormat.CfFormat of CF_HDROP: FileNames := GetDropFilenames(Medium.hGlobal); CF_UNICODETEXT, CF_TEXT: FileNames := GetDropTextCreatedFilenames(Medium, ChosenFormat); else begin if (ChosenFormat.CfFormat = CFU_FILEGROUPDESCRIPTORW) or (ChosenFormat.CfFormat = CFU_FILEGROUPDESCRIPTOR) then FileNames := GetDropFileGroupFilenames(dataObj, Medium, ChosenFormat) else if (ChosenFormat.CfFormat = CFU_HTML) or (ChosenFormat.CfFormat = CFU_RICHTEXT) then FileNames := GetDropTextCreatedFilenames(Medium, ChosenFormat) end; end; end; end; end; { TFileDropTarget.Create } constructor TFileDropTarget.Create(DragDropTarget: TDragDropTargetWindows); begin inherited Create; // Here RefCount is 1 - as set in TInterfacedObject.NewInstance, // but it's decremented back in TInterfacedObject.AfterConstruction // (when this constructor finishes). So we must manually again increase it. _AddRef; FReleased := False; FDragDropTarget := DragDropTarget; // Increases RefCount. ActiveX.CoLockObjectExternal(Self, True, False); // Increases RefCount. FHandle:= GetControlHandle(DragDropTarget.GetControl); if ActiveX.RegisterDragDrop(FHandle, Self) <> S_OK then FHandle := 0; end; { TFileDropTarget.FinalRelease } procedure TFileDropTarget.FinalRelease; begin if not FReleased then begin FReleased := True; // Decreases reference count. ActiveX.CoLockObjectExternal(Self, False, True); // Check if window was not already destroyed. if (FHandle <> 0) and (IsWindow(FHandle)) then begin // Decreases reference count. ActiveX.RevokeDragDrop(FHandle); FHandle := 0; end else _Release; // Cannot revoke - just release reference. _Release; // For _AddRef in Create. end; end; function TFileDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall; var DropEffect: TDropEffect; begin // dwEffect parameter states which effects are allowed by the source. dwEffect := dwEffect and GetEffectByKeyState(grfKeyState); if Assigned(FDragDropTarget.GetDragEnterEvent) then begin DropEffect := WinEffectToDropEffect(dwEffect); if FDragDropTarget.GetDragEnterEvent()(DropEffect, pt) = True then begin dwEffect := DropEffectToWinEffect(DropEffect); Result := S_OK end else Result := S_FALSE; end else Result := S_OK; end; { TFileDropTarget.DragOver } function TFileDropTarget.DragOver(grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall; var DropEffect: TDropEffect; begin // dwEffect parameter states which effects are allowed by the source. dwEffect := dwEffect and GetEffectByKeyState(grfKeyState); if Assigned(FDragDropTarget.GetDragOverEvent) then begin DropEffect := WinEffectToDropEffect(dwEffect); if FDragDropTarget.GetDragOverEvent()(DropEffect, pt) = True then begin dwEffect := DropEffectToWinEffect(DropEffect); Result := S_OK end else Result := S_FALSE; end else Result := S_OK; end; { TFileDropTarget.DragLeave } function TFileDropTarget.DragLeave: HResult; stdcall; begin if Assigned(FDragDropTarget.GetDragLeaveEvent) then begin if FDragDropTarget.GetDragLeaveEvent() = True then Result := S_OK else Result := S_FALSE; end else Result := S_OK; end; { Обработка сброшенных данных. } { TFileDropTarget.Drop } function TFileDropTarget.Drop(const dataObj: IDataObject; grfKeyState: LongWord; pt: TPoint; var dwEffect: LongWord): HResult; stdcall; var Medium: TSTGMedium; CyclingThroughFormat, ChosenFormat: TFormatETC; i: Integer; DropInfo: TDragDropInfo; FileNames, DragTextModeOfferedList: TStringList; SelectedFormatName:String; DropEffect: TDropEffect; Enum: IEnumFormatEtc; DragAndDropSupportedFormatList: TWordList; UnusedInteger : integer; begin DragAndDropSupportedFormatList:= TWordList.Create; try FileNames:=nil; UnusedInteger:=0; dataObj._AddRef; { Получаем данные. Структура TFormatETC сообщает dataObj.GetData, как получить данные и в каком формате они должны храниться (эта информация содержится в структуре TSTGMedium). } //1. Let's build as quick list of the supported formats of what we've just been dropped. // We scan through all because sometimes the best one is not the first compatible one. OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); while Enum.Next(1, CyclingThroughFormat, nil) = S_OK do begin DragAndDropSupportedFormatList.Add(CyclingThroughFormat.CfFormat); end; //2. Let's determine our best guess. // The order for this will be: // 1nd) CFU_FILEGROUPDESCRIPTORW + CFU_FILECONTENTS (Outlook 2010 / Windows Live Mail, etc.) // 2rd) CFU_FILEGROUPDESCRIPTOR + CFU_FILECONTENTS (Outlook 2010 / Windows Live Mail, etc.) // 3st) CF_HDROP (for legacy purpose, since DC was using it first). // 4th) We'll see if user would like to create a new text file from possible selected text dropped on the panel // CF_UNICODETEXT (Notepad++ / Wordpad / Firefox) // CF_TEXT (Notepad / Wordpad / Firefox) // CFU_HTML (Firefox) // Rich Text (Wordpad / Microsoft Word) Result:= S_FALSE; ChosenFormat.CfFormat:= 0; if (DragAndDropSupportedFormatList.IndexOf(CFU_FILECONTENTS) > -1) then begin if (DragAndDropSupportedFormatList.IndexOf(CFU_FILEGROUPDESCRIPTORW) > -1) then begin ChosenFormat.CfFormat:= CFU_FILEGROUPDESCRIPTORW; Result:= GetFiles(dataObj, ChosenFormat, FileNames, Medium); end; if (Result <> S_OK) AND (DragAndDropSupportedFormatList.IndexOf(CFU_FILEGROUPDESCRIPTOR) > -1) then begin ChosenFormat.CfFormat:= CFU_FILEGROUPDESCRIPTOR; Result:= GetFiles(dataObj, ChosenFormat, FileNames, Medium); end; end; if (Result <> S_OK) AND (DragAndDropSupportedFormatList.IndexOf(CF_HDROP) > -1) then begin ChosenFormat.CfFormat:= CF_HDROP; Result:= GetFiles(dataObj, ChosenFormat, FileNames, Medium); end; // If we have no chosen format yet, let's attempt for text ones... if (Result <> S_OK) then begin ChosenFormat.CfFormat:= 0; DragTextModeOfferedList:= TStringList.Create; try if (DragAndDropSupportedFormatList.IndexOf(CFU_RICHTEXT) > -1) then DragTextModeOfferedList.Add(gDragAndDropDesiredTextFormat[DropTextRichText_Index].Name); if (DragAndDropSupportedFormatList.IndexOf(CFU_HTML) > -1) then DragTextModeOfferedList.Add(gDragAndDropDesiredTextFormat[DropTextHtml_Index].Name); if (DragAndDropSupportedFormatList.IndexOf(CF_UNICODETEXT) > -1) then DragTextModeOfferedList.Add(gDragAndDropDesiredTextFormat[DropTextUnicode_Index].Name); if (DragAndDropSupportedFormatList.IndexOf(CF_TEXT) > -1) then DragTextModeOfferedList.Add(gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].Name); SortThisListAccordingToDragAndDropDesiredFormat(DragTextModeOfferedList); if DragTextModeOfferedList.Count>0 then SelectedFormatName:=DragTextModeOfferedList.Strings[0] else SelectedFormatName:=''; if (DragTextModeOfferedList.Count>1) AND (gDragAndDropAskFormatEachTime) then if not ShowInputListBox(rsCaptionForTextFormatToImport,rsMsgForTextFormatToImport,DragTextModeOfferedList,SelectedFormatName,UnusedInteger) then SelectedFormatName:=''; if SelectedFormatName<>'' then begin if SelectedFormatName=gDragAndDropDesiredTextFormat[DropTextRichText_Index].Name then ChosenFormat.CfFormat:=CFU_RICHTEXT; if SelectedFormatName=gDragAndDropDesiredTextFormat[DropTextHtml_Index].Name then ChosenFormat.CfFormat:=CFU_HTML; if SelectedFormatName=gDragAndDropDesiredTextFormat[DropTextUnicode_Index].Name then ChosenFormat.CfFormat:=CF_UNICODETEXT; if SelectedFormatName=gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].Name then ChosenFormat.CfFormat:=CF_TEXT; end; finally DragTextModeOfferedList.Free; end; if ChosenFormat.CfFormat <> 0 then begin Result:= GetFiles(dataObj, ChosenFormat, FileNames, Medium); end; end; //3. If we have some filenames in our list, continue to process the actual "Drop" of files if (Result = S_OK) then begin { Создаем объект TDragDropInfo } DropInfo := TDragDropInfo.Create(dwEffect); if Assigned(FileNames) then begin for i := 0 to FileNames.Count - 1 do DropInfo.Add(FileNames[i]); FreeAndNil(FileNames); end; { Если указан обработчик, вызываем его } if (Assigned(FDragDropTarget.GetDropEvent)) then begin // Set default effect by examining keyboard keys, taking into // consideration effects allowed by the source (dwEffect parameter). dwEffect := dwEffect and GetEffectByKeyState(grfKeyState); DropEffect := WinEffectToDropEffect(dwEffect); FDragDropTarget.GetDropEvent()(DropInfo.Files, DropEffect, pt); dwEffect := DropEffectToWinEffect(DropEffect); end; DropInfo.Free; if (Medium.PUnkForRelease = nil) then // Drop target must release the medium allocated by GetData. // This does the same as DragFinish(Medium.hGlobal) in this case, // but can support other media. ReleaseStgMedium(@Medium) else // Drop source is responsible for releasing medium via this object. IUnknown(Medium.PUnkForRelease)._Release; end; dataObj._Release; finally DragAndDropSupportedFormatList.Free; end; end; { TFileDropTarget.GetDropFilenames } class function TFileDropTarget.GetDropFilenames(hDropData: HDROP): TStringList; var NumFiles: Integer; i: Integer; wszFilename: PWideChar; FileName: WideString; RequiredSize: Cardinal; begin Result := nil; if hDropData <> 0 then begin Result := TStringList.Create; try NumFiles := DragQueryFileW(hDropData, $FFFFFFFF, nil, 0); for i := 0 to NumFiles - 1 do begin RequiredSize := DragQueryFileW(hDropData, i, nil, 0) + 1; // + 1 = terminating zero wszFilename := GetMem(RequiredSize * SizeOf(WideChar)); if Assigned(wszFilename) then try if DragQueryFileW(hDropData, i, wszFilename, RequiredSize) > 0 then begin FileName := wszFilename; // Windows inserts '?' character where Wide->Ansi conversion // of a character was not possible, in which case filename is invalid. // This may happen if a non-Unicode application was the source. if Pos('?', FileName) = 0 then Result.Add(UTF16ToUTF8(FileName)) else raise Exception.Create(rsMsgInvalidFilename + ': ' + LineEnding + UTF16ToUTF8(FileName)); end; finally FreeMem(wszFilename); end; end; except FreeAndNil(Result); raise; end; end; end; { TFileDropTarget.SaveCfuContentToFile } function TFileDropTarget.SaveCfuContentToFile(const dataObj: IDataObject; Index: Integer; WantedFilename: String; FileInfo: PFileDescriptorW): boolean; const TEMPFILENAME='CfuContentFile.bin'; var Format : TFORMATETC; Medium : TSTGMedium; Ifile, iStg : IStorage; tIID : PGuid; hFile: THandle; pvStrm: IStream; statstg: TStatStg; dwSize: LongInt; AnyPointer: PAnsiChar; InnerFilename: String; StgDocFile: WideString; msStream: TMemoryStream; i64Size, i64Move: {$IF FPC_FULLVERSION < 030002}Int64{$ELSE}QWord{$ENDIF}; begin result:=FALSE; InnerFilename:= ExtractFilepath(WantedFilename) + TEMPFILENAME; Format.cfFormat := CFU_FILECONTENTS; Format.dwAspect := DVASPECT_CONTENT; Format.lindex := Index; Format.ptd := nil; Format.TYMED := TYMED_ISTREAM OR TYMED_ISTORAGE or TYMED_HGLOBAL; if dataObj.GetData(Format, Medium) = S_OK then begin if Medium.TYMED = TYMED_ISTORAGE then begin iStg := IStorage(Medium.pstg); StgDocFile := CeUtf8ToUtf16(InnerFilename); StgCreateDocfile(PWideChar(StgDocFile), STGM_CREATE Or STGM_READWRITE Or STGM_SHARE_EXCLUSIVE, 0, iFile); tIID:=nil; iStg.CopyTo(0, tIID, nil, iFile); iFile.Commit(0); iFile := nil; iStg := nil; end else if Medium.Tymed = TYMED_HGLOBAL then begin AnyPointer := GlobalLock(Medium.HGLOBAL); try hFile := mbFileCreate(InnerFilename); if hFile <> feInvalidHandle then begin FileWrite(hFile, AnyPointer^, GlobalSize(Medium.HGLOBAL)); FileClose(hFile); end; finally GlobalUnlock(Medium.HGLOBAL); end; if Medium.PUnkForRelease = nil then GlobalFree(Medium.HGLOBAL); end else begin pvStrm:= IStream(Medium.pstm); // Figure out how large the data is if (FileInfo^.dwFlags and FD_FILESIZE <> 0) then i64Size:= Int64(FileInfo.nFileSizeLow) or (Int64(FileInfo.nFileSizeHigh) shl 32) else if (pvStrm.Stat(statstg, STATFLAG_DEFAULT) = S_OK) then i64Size:= statstg.cbSize else if (pvStrm.Seek(0, STREAM_SEEK_END, i64Size) = S_OK) then // Seek back to start of stream pvStrm.Seek(0, STREAM_SEEK_SET, i64Move) else begin Exit; end; // Create memory stream to convert to msStream:= TMemoryStream.Create; // Allocate size msStream.Size:= i64Size; // Read from the IStream into the memory for the TMemoryStream if pvStrm.Read(msStream.Memory, i64Size, @dwSize) = S_OK then msStream.Size:= dwSize else msStream.Size:= 0; // Release interface pvStrm:=nil; msStream.Position:=0; msStream.SaveToFile(UTF8ToSys(InnerFilename)); msStream.Free; end; end; if mbFileExists(InnerFilename) then begin if mbRenameFile(InnerFilename, WantedFilename) then begin if (FileInfo^.dwFlags and FD_CREATETIME = 0) then TWinFileTime(FileInfo^.ftCreationTime):= 0; if (FileInfo^.dwFlags and FD_WRITESTIME = 0) then TWinFileTime(FileInfo^.ftLastWriteTime):= 0; if (FileInfo^.dwFlags and FD_ACCESSTIME = 0) then TWinFileTime(FileInfo^.ftLastAccessTime):= 0; Result:= mbFileSetTime(WantedFilename, TWinFileTime(FileInfo^.ftLastWriteTime), TWinFileTime(FileInfo^.ftCreationTime), TWinFileTime(FileInfo^.ftLastAccessTime)); end; end; end; { TFileDropTarget.GetDropFileGroupFilenames } function TFileDropTarget.GetDropFileGroupFilenames(const dataObj: IDataObject; var Medium: TSTGMedium; Format: TFormatETC): TStringList; var SuffixStr: String; AnyPointer: Pointer; DC_FileDescriptorW: PFILEDESCRIPTORW; ActualFilename, DroppedTextFilename: String; NumberOfFiles, CopyNumber, IndexFile: Integer; DC_FileDescriptorA: PFILEDESCRIPTORA absolute DC_FileDescriptorW; DC_FileGroupeDescriptorW: PFILEGROUPDESCRIPTORW absolute AnyPointer; begin Result := nil; AnyPointer := GlobalLock(Medium.HGLOBAL); try NumberOfFiles:= DC_FileGroupeDescriptorW.cItems; // Return the number of messages if NumberOfFiles > 0 then begin DC_FileDescriptorW:= AnyPointer + SizeOf(FILEGROUPDESCRIPTORW.cItems); Result:= TStringList.Create; for IndexFile:= 0 to Pred(NumberOfFiles) do begin if Format.CfFormat = CFU_FILEGROUPDESCRIPTORW then ActualFilename:= UTF16ToUTF8(UnicodeString(DC_FileDescriptorW^.cFileName)) else begin ActualFilename:= CeSysToUTF8(AnsiString(DC_FileDescriptorA^.cFileName)); end; DroppedTextFilename := GetTempFolderDeletableAtTheEnd + ActualFilename; if Result.IndexOf(DroppedTextFilename) <> -1 then begin CopyNumber := 2; repeat case gTypeOfDuplicatedRename of drLikeWindows7: SuffixStr:=' ('+IntToStr(CopyNumber)+')'; drLikeTC: SuffixStr:='('+IntToStr(CopyNumber)+')'; end; case gTypeOfDuplicatedRename of drLegacyWithCopy: DroppedTextFilename := GetTempFolderDeletableAtTheEnd+SysUtils.Format(rsCopyNameTemplate, [CopyNumber, ActualFilename]); drLikeWindows7, drLikeTC: DroppedTextFilename := GetTempFolderDeletableAtTheEnd+RemoveFileExt(ActualFilename) + SuffixStr + ExtractFileExt(ActualFilename); end; Inc(CopyNumber); until Result.IndexOf(DroppedTextFilename) = -1; end; if SaveCfuContentToFile(dataObj, IndexFile, DroppedTextFilename, DC_FileDescriptorW) then Result.Add(DroppedTextFilename); if Format.CfFormat = CFU_FILEGROUPDESCRIPTORW then Inc(DC_FileDescriptorW) else begin Inc(DC_FileDescriptorA); end; end; end; finally // Release the pointer GlobalUnlock(Medium.HGLOBAL); end; end; { TFileDropTarget.GetDropTextCreatedFilenames } function TFileDropTarget.GetDropTextCreatedFilenames(var Medium: TSTGMedium; Format: TFormatETC): TStringList; var hFile: THandle; AnyPointer: Pointer; MyUtf8String: String; FlagKeepGoing: Boolean; DroppedTextFilename: String; procedure SetDefaultFilename; begin DroppedTextFilename:=GetDateTimeInStrEZSortable(now)+rsDefaultSuffixDroppedText+'.txt'; if Format.CfFormat=CFU_RICHTEXT then DroppedTextFilename:=GetDateTimeInStrEZSortable(now)+rsDefaultSuffixDroppedTextRichtextFilename+'.rtf'; if Format.CfFormat=CFU_HTML then DroppedTextFilename:=GetDateTimeInStrEZSortable(now)+rsDefaultSuffixDroppedTextHTMLFilename+'.html'; if (Format.CfFormat=CF_UNICODETEXT) AND not gDragAndDropSaveUnicodeTextInUFT8 then DroppedTextFilename:=GetDateTimeInStrEZSortable(now)+rsDefaultSuffixDroppedTextUnicodeUTF16Filename+'.txt'; if (Format.CfFormat=CF_UNICODETEXT) AND gDragAndDropSaveUnicodeTextInUFT8 then DroppedTextFilename:=GetDateTimeInStrEZSortable(now)+rsDefaultSuffixDroppedTextUnicodeUTF8Filename+'.txt'; if Format.CfFormat=CF_TEXT then DroppedTextFilename:=GetDateTimeInStrEZSortable(now)+rsDefaultSuffixDroppedTextSimpleFilename+'.txt'; end; begin Result:= nil; FlagKeepGoing:=TRUE; SetDefaultFilename; if not gDragAndDropTextAutoFilename then FlagKeepGoing:=ShowInputQuery(rsCaptionForAskingFilename, rsMsgPromptAskingFilename, DroppedTextFilename); if FlagKeepGoing then begin if DroppedTextFilename='' then SetDefaultFilename; //Just minimal idot-proof... DroppedTextFilename:=GetTempFolderDeletableAtTheEnd+DroppedTextFilename; AnyPointer := GlobalLock(Medium.hGlobal); try hFile:= mbFileCreate(DroppedTextFilename); try case Format.CfFormat of CF_TEXT: begin FileWrite(hFile, AnyPointer^, StrLen(PAnsiChar(AnyPointer))); end; CF_UNICODETEXT: begin if gDragAndDropSaveUnicodeTextInUFT8 then begin MyUtf8String:= CeUtf16toUtf8(PUnicodeChar(AnyPointer)); // Adding Byte Order Mark for UTF8 FileWrite(hFile, PAnsiChar(#$EF#$BB#$BF)[0], 3); FileWrite(hFile, Pointer(MyUtf8String)^, Length(MyUtf8String)); end else begin // Adding Byte Order Mark for UTF16LE FileWrite(hFile, PAnsiChar(#$FF#$FE)[0], 2); FileWrite(hFile, AnyPointer^, StrLen(PUnicodeChar(AnyPointer)) * SizeOf(WideChar)); end; end; else begin if (Format.CfFormat = CFU_HTML) or (Format.CfFormat = CFU_RICHTEXT) then begin FileWrite(hFile, AnyPointer^, StrLen(PAnsiChar(AnyPointer))); end; end; end; finally FileClose(hFile); end; result:=TStringList.Create; result.Add(DroppedTextFilename); finally GlobalUnlock(Medium.hGlobal); end; end; end; { TFileDropSource.Create } constructor TFileDropSource.Create; begin inherited Create; _AddRef; end; { TFileDropSource.QueryContinueDrag } function TFileDropSource.QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: DWORD): HResult; var Point:TPoint; begin if (fEscapePressed) then begin Result := DRAGDROP_S_CANCEL; // Set flag to notify that dragging was canceled by the user. uDragDropEx.TransformDragging := False; end else if ((grfKeyState and (MK_LBUTTON or MK_MBUTTON or MK_RBUTTON)) = 0) then begin Result := DRAGDROP_S_DROP; end else begin if uDragDropEx.AllowTransformToInternal then begin GetCursorPos(Point); // Call LCL function, not the Windows one. // LCL version will return 0 if mouse is over a window belonging to another process. if LCLIntf.WindowFromPoint(Point) <> 0 then begin // Mouse cursor has been moved back into the application window. // Cancel external dragging. Result := DRAGDROP_S_CANCEL; // Set flag to notify that dragging has not finished, // but rather it is to be transformed into internal dragging. uDragDropEx.TransformDragging := True; end else Result := S_OK; // Continue dragging end else Result := S_OK; // Continue dragging end; end; function TFileDropSource.GiveFeedback(dwEffect: DWORD): HResult; begin Result := DRAGDROP_S_USEDEFAULTCURSORS; end; { THDropDataObject.Create } constructor THDropDataObject.Create(PreferredWinDropEffect: DWORD); begin inherited Create; _AddRef; FDropInfo := TDragDropInfo.Create(PreferredWinDropEffect); end; { THDropDataObject.Destroy } destructor THDropDataObject.Destroy; begin if (FDropInfo <> nil) then FDropInfo.Free; inherited Destroy; end; { THDropDataObject.Add } procedure THDropDataObject.Add(const s: string); begin FDropInfo.Add(s); end; { THDropDataObject.GetData } function THDropDataObject.GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; begin Result := DV_E_FORMATETC; { Необходимо обнулить все поля medium на случай ошибки } medium.tymed := 0; medium.hGlobal := 0; medium.PUnkForRelease := nil; { Если формат поддерживается, создаем и возвращаем данные } if (QueryGetData(formatetcIn) = S_OK) then begin if (FDropInfo <> nil) then begin { Create data in specified format. } { The hGlobal will be released by the caller of GetData. } medium.hGlobal := FDropInfo.MakeDataInFormat(formatetcIn); if medium.hGlobal <> 0 then begin medium.tymed := TYMED_HGLOBAL; Result := S_OK; end; end; end; end; { THDropDataObject.GetDataHere } function THDropDataObject.GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult; begin Result := DV_E_FORMATETC; { К сожалению, не поддерживается } end; { THDropDataObject.QueryGetData } function THDropDataObject.QueryGetData(const formatetc: TFormatEtc): HResult; var i:Integer; begin with formatetc do if dwAspect = DVASPECT_CONTENT then begin Result := DV_E_FORMATETC; // begin with 'format not supported' // See if the queried format is supported. for i := 0 to DataFormats.Count - 1 do begin if Assigned(DataFormats[i]) then begin if cfFormat = PFormatEtc(DataFormats[i])^.CfFormat then begin // Format found, see if transport medium is supported. if (tymed = DWORD(-1)) or (Boolean(tymed and PFormatEtc(DataFormats[i])^.tymed)) then begin Result := S_OK; end else Result := DV_E_TYMED; // transport medium not supported Exit; // exit if format found (regardless of transport medium) end end end end else Result := DV_E_DVASPECT; // aspect not supported end; { THDropDataObject.GetCanonicalFormatEtc } function THDropDataObject.GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult; begin formatetcOut.ptd := nil; Result := E_NOTIMPL; end; { THDropDataObject.SetData } function THDropDataObject.SetData(const formatetc: TFormatEtc; {$IF FPC_FULLVERSION < 30200}const{$ELSE}var{$ENDIF} medium: TStgMedium; fRelease: BOOL): HResult; begin Result := E_NOTIMPL; end; { THDropDataObject.EnumFormatEtc возвращает список поддерживаемых форматов} function THDropDataObject.EnumFormatEtc(dwDirection: LongWord; out enumFormatEtc: IEnumFormatEtc): HResult; begin { Поддерживается только Get. Задать содержимое данных нельзя } if dwDirection = DATADIR_GET then begin enumFormatEtc := TEnumFormatEtc.Create; Result := S_OK; end else begin enumFormatEtc := nil; Result := E_NOTIMPL; end; end; { THDropDataObject.DAdviseDAdvise не поддерживаются} function THDropDataObject.DAdvise(const formatetc: TFormatEtc; advf: LongWord; const advSink: IAdviseSink; out dwConnection: LongWord): HResult; begin Result := OLE_E_ADVISENOTSUPPORTED; end; { THDropDataObject.DUnadvise } function THDropDataObject.DUnadvise(dwConnection: LongWord): HResult; begin Result := OLE_E_ADVISENOTSUPPORTED; end; { THDropDataObject.EnumDAdvise } function THDropDataObject.EnumDAdvise(out enumAdvise: IEnumStatData): HResult; begin Result := OLE_E_ADVISENOTSUPPORTED; end; function GetEffectByKeyState(grfKeyState: LongWord): Integer; begin Result := DROPEFFECT_COPY; { default effect } if (grfKeyState and MK_CONTROL) > 0 then begin if (grfKeyState and MK_SHIFT) > 0 then Result := DROPEFFECT_LINK else Result := DROPEFFECT_COPY; end else if (grfKeyState and MK_SHIFT) > 0 then Result := DROPEFFECT_MOVE; end; function WinEffectToDropEffect(dwEffect: LongWord): TDropEffect; begin case dwEffect of DROPEFFECT_COPY: Result := DropCopyEffect; DROPEFFECT_MOVE: Result := DropMoveEffect; DROPEFFECT_LINK: Result := DropLinkEffect; else Result := DropNoEffect; end; end; function DropEffectToWinEffect(DropEffect: TDropEffect): LongWord; begin case DropEffect of DropCopyEffect: Result := DROPEFFECT_COPY; DropMoveEffect: Result := DROPEFFECT_MOVE; DropLinkEffect: Result := DROPEFFECT_LINK; else Result := DROPEFFECT_NONE; end; end; function DragQueryWide( hGlobalDropInfo: HDROP ): boolean; var DropFiles: PDropFiles; begin DropFiles := GlobalLock( hGlobalDropInfo ); Result := DropFiles^.fWide; GlobalUnlock( hGlobalDropInfo ); end; { ---------------------------------------------------------} { TDragDropSourceWindows } function TDragDropSourceWindows.RegisterEvents( DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; // not Handled in Windows DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; begin inherited; // RequestDataEvent is not handled, because the system has control of all data transfer. Result := True; // confirm that events are registered end; function TDragDropSourceWindows.DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; var DropSource: TFileDropSource; DropData: THDropDataObject; Rslt: HRESULT; dwEffect: LongWord; I: Integer; begin // Simulate drag-begin event. if Assigned(GetDragBeginEvent) then begin Result := GetDragBeginEvent()(); if Result = False then Exit; end; // Create source-object DropSource:= TFileDropSource.Create; // and data object DropData:= THDropDataObject.Create(DROPEFFECT_COPY { default effect } ); for I:= 0 to FileNamesList.Count - 1 do DropData.Add (FileNamesList[i]); // Start OLE Drag&Drop Rslt:= ActiveX.DoDragDrop(DropData, DropSource, DROPEFFECT_MOVE or DROPEFFECT_COPY or DROPEFFECT_LINK, // Allowed effects @dwEffect); case Rslt of DRAGDROP_S_DROP: begin FLastStatus := DragDropSuccessful; Result := True; end; DRAGDROP_S_CANCEL: begin FLastStatus := DragDropAborted; Result := False; end; else begin MessageBox(0, PAnsiChar(SysErrorMessage(Rslt)), nil, MB_OK or MB_ICONERROR); FLastStatus := DragDropError; Result := False; end; end; // Simulate drag-end event. This must be called here, // after DoDragDrop returns from the system. if Assigned(GetDragEndEvent) then begin if Result = True then Result := GetDragEndEvent()() else GetDragEndEvent()() end; // Release created objects. DropSource._Release; DropData._Release; end; { ---------------------------------------------------------} { TDragDropTargetWindows } constructor TDragDropTargetWindows.Create(Control: TWinControl); begin FDragDropTarget := nil; inherited Create(Control); end; destructor TDragDropTargetWindows.Destroy; begin inherited Destroy; if Assigned(FDragDropTarget) then begin FDragDropTarget.FinalRelease; FDragDropTarget := nil; end; end; function TDragDropTargetWindows.RegisterEvents( DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; begin // Unregister if registered before. UnregisterEvents; inherited; // Call inherited Register now. GetControl.HandleNeeded; // force creation of the handle if GetControl.HandleAllocated = True then begin FDragDropTarget := TFileDropTarget.Create(Self); Result := True; end; end; procedure TDragDropTargetWindows.UnregisterEvents; begin inherited; if Assigned(FDragDropTarget) then begin FDragDropTarget.FinalRelease; // Releasing will unregister events FDragDropTarget := nil; end; end; initialization OleInitialize(nil); InitDataFormats; finalization OleUninitialize; DestroyDataFormats; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udcreadheif.pas�������������������������������������������������������0000644�0001750�0000144�00000025206�14743153644�020176� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- High Efficiency Image reader implementation (via libheif) Copyright (C) 2021-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } unit uDCReadHEIF; {$mode delphi} {$packrecords c} {$packenum 4} interface uses Classes, SysUtils, Graphics, FPImage; type { TDCReaderHEIF } TDCReaderHEIF = class (TFPCustomImageReader) private FContext: Pointer; protected function InternalCheck (Stream: TStream): boolean;override; procedure InternalRead({%H-}Stream: TStream; Img: TFPCustomImage);override; public constructor Create; override; destructor Destroy; override; end; { THighEfficiencyImage } THighEfficiencyImage = class(TFPImageBitmap) protected class function GetReaderClass: TFPCustomImageReaderClass; override; class function GetSharedImageClass: TSharedRasterImageClass; override; public class function GetFileExtensions: string; override; end; implementation uses DynLibs, IntfGraphics, GraphType, Types, CTypes, LazUTF8, DCOSUtils, uDebug; const HEIF_EXT = 'heif;heic;avif'; type Theif_error_code = ( heif_error_Ok = 0, heif_error_Input_does_not_exist = 1, heif_error_Invalid_input = 2, heif_error_Unsupported_filetype = 3, heif_error_Unsupported_feature = 4, heif_error_Usage_error = 5, heif_error_Memory_allocation_error = 6, heif_error_Decoder_plugin_error = 7, heif_error_Encoder_plugin_error = 8, heif_error_Encoding_error = 9, heif_error_Color_profile_does_not_exist = 10 ); Theif_colorspace = ( heif_colorspace_YCbCr = 0, heif_colorspace_RGB = 1, heif_colorspace_monochrome = 2, heif_colorspace_undefined = 99 ); Theif_channel = ( heif_channel_Y = 0, heif_channel_Cb = 1, heif_channel_Cr = 2, heif_channel_R = 3, heif_channel_G = 4, heif_channel_B = 5, heif_channel_Alpha = 6, heif_channel_interleaved = 10 ); Theif_chroma = ( heif_chroma_monochrome = 0, heif_chroma_420 = 1, heif_chroma_422 = 2, heif_chroma_444 = 3, heif_chroma_interleaved_RGB = 10, heif_chroma_interleaved_RGBA = 11, heif_chroma_interleaved_RRGGBB_BE = 12, heif_chroma_interleaved_RRGGBBAA_BE = 13, heif_chroma_interleaved_RRGGBB_LE = 14, heif_chroma_interleaved_RRGGBBAA_LE = 15, heif_chroma_undefined = 99 ); Theif_context = record end; Pheif_context = ^Theif_context; Theif_error = record code: Theif_error_code; subcode: UInt32; message: PAnsiChar; end; Pheif_decoding_options = ^Theif_decoding_options; Theif_decoding_options = record version: cuint8; ignore_transformations: cuint8; start_progress: pointer; on_progress: pointer; end_progress: pointer; progress_user_data: pointer; // version 2 options convert_hdr_to_8bit: cuint8; end; var heif_context_alloc: function(): Pheif_context; cdecl; heif_context_free: procedure(context: Pheif_context); cdecl; heif_decoding_options_alloc: function(): Pheif_decoding_options; cdecl; heif_decoding_options_free: procedure(options: Pheif_decoding_options); cdecl; heif_context_read_from_memory_without_copy: function(context: Pheif_context; mem: Pointer; size: csize_t; options: Pointer): Theif_error; cdecl; heif_context_get_primary_image_handle: function(ctx: Pheif_context; image_handle: PPointer): Theif_error; cdecl; heif_image_handle_release: procedure(heif_image_handle: Pointer); cdecl; heif_image_handle_has_alpha_channel: function(image_handle: Pointer): cint; cdecl; heif_decode_image: function(in_handle: Pointer; out_img: PPointer; colorspace: Theif_colorspace; chroma: Theif_chroma; options: Pointer): Theif_error; cdecl; heif_image_release: procedure(heif_image: Pointer); cdecl; heif_image_get_width: function(heif_image: Pointer; channel: Theif_channel): cint; cdecl; heif_image_get_height: function(heif_image: Pointer; channel: Theif_channel): cint; cdecl; heif_image_get_plane_readonly: function(heif_image: Pointer; channel: Theif_channel; out_stride: pcint): pcuint8; cdecl; { THighEfficiencyImage } class function THighEfficiencyImage.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TDCReaderHEIF; end; class function THighEfficiencyImage.GetSharedImageClass: TSharedRasterImageClass; begin Result:= TSharedBitmap; end; class function THighEfficiencyImage.GetFileExtensions: string; begin Result:= HEIF_EXT; end; { TDCReaderHEIF } function TDCReaderHEIF.InternalCheck(Stream: TStream): boolean; var Err: Theif_error; MemoryStream: TMemoryStream; begin Result:= Stream is TMemoryStream; if Result then begin MemoryStream:= TMemoryStream(Stream); Err:= heif_context_read_from_memory_without_copy(FContext, MemoryStream.Memory, MemoryStream.Size, nil); Result:= (Err.code = heif_error_Ok); end; end; procedure TDCReaderHEIF.InternalRead(Stream: TStream; Img: TFPCustomImage); var Y: cint; Alpha: cint; ASize: cint; AData: PByte; ADelta: cint; AStride: cint; ATarget: PByte; Err: Theif_error; Chroma: Theif_chroma; AWidth, AHeight: cint; AImage: Pointer = nil; AHandle: Pointer = nil; AOptions: Pheif_decoding_options; Description: TRawImageDescription; begin Err:= heif_context_get_primary_image_handle(FContext, @AHandle); if (Err.code <> heif_error_Ok) then raise Exception.Create(Err.message); try // Library works wrong with some images from // https://github.com/link-u/avif-sample-images // when decode image into RGB, but it works fine with RGBA Alpha:= 1; // heif_image_handle_has_alpha_channel(AHandle); if (Alpha <> 0) then Chroma:= heif_chroma_interleaved_RGBA else begin Chroma:= heif_chroma_interleaved_RGB; end; AOptions:= heif_decoding_options_alloc(); try if AOptions^.version > 1 then begin AOptions^.convert_hdr_to_8bit:= 1; end; Err:= heif_decode_image(AHandle, @AImage, heif_colorspace_RGB, Chroma, AOptions); finally heif_decoding_options_free(AOptions); end; if (Err.code <> heif_error_Ok) then raise Exception.Create(Err.message); try AWidth:= heif_image_get_width(AImage, heif_channel_interleaved); AHeight:= heif_image_get_height(AImage, heif_channel_interleaved); AData:= heif_image_get_plane_readonly(AImage, heif_channel_interleaved, @AStride); if (AData = nil) then raise Exception.Create(EmptyStr); if (Alpha <> 0) then begin ASize:= 4; Description.Init_BPP32_R8G8B8A8_BIO_TTB(AWidth, AHeight) end else begin ASize:= 3; Description.Init_BPP24_R8G8B8_BIO_TTB(AWidth, AHeight); end; ADelta:= AStride - AWidth * ASize; TLazIntfImage(Img).DataDescription:= Description; if ADelta = 0 then // We can transfer the whole image at once Move(AData^, TLazIntfImage(Img).PixelData^, AStride * AHeight) else begin AStride:= AWidth * ASize; ATarget:= TLazIntfImage(Img).PixelData; // Stride has some padding, we have to send the image line by line for Y:= 0 to AHeight - 1 do begin Move(AData^, ATarget[Y * AStride], AStride); Inc(AData, AStride + ADelta) end; end; finally heif_image_release(AImage); end; finally heif_image_handle_release(AHandle); end; end; constructor TDCReaderHEIF.Create; begin inherited Create; FContext:= heif_context_alloc(); end; destructor TDCReaderHEIF.Destroy; begin inherited Destroy; if Assigned(FContext) then heif_context_free(FContext); end; const {$IF DEFINED(UNIX)} heiflib = 'libheif.so.1'; {$ELSEIF DEFINED(MSWINDOWS)} heiflib = 'libheif.dll'; {$ENDIF} var libheif: TLibHandle; procedure Initialize; var AVersion: cint; AOptions: Pheif_decoding_options; begin libheif:= mbLoadLibraryEx(heiflib); if (libheif <> NilHandle) then try @heif_context_alloc:= SafeGetProcAddress(libheif, 'heif_context_alloc'); @heif_context_free:= SafeGetProcAddress(libheif, 'heif_context_free'); @heif_decode_image:= SafeGetProcAddress(libheif, 'heif_decode_image'); @heif_image_release:= SafeGetProcAddress(libheif, 'heif_image_release'); @heif_image_get_width:= SafeGetProcAddress(libheif, 'heif_image_get_width'); @heif_image_get_height:= SafeGetProcAddress(libheif, 'heif_image_get_height'); @heif_image_handle_release:= SafeGetProcAddress(libheif, 'heif_image_handle_release'); @heif_decoding_options_free:= SafeGetProcAddress(libheif, 'heif_decoding_options_free'); @heif_decoding_options_alloc:= SafeGetProcAddress(libheif, 'heif_decoding_options_alloc'); @heif_image_get_plane_readonly:= SafeGetProcAddress(libheif, 'heif_image_get_plane_readonly'); @heif_image_handle_has_alpha_channel:= SafeGetProcAddress(libheif, 'heif_image_handle_has_alpha_channel'); @heif_context_get_primary_image_handle:= SafeGetProcAddress(libheif, 'heif_context_get_primary_image_handle'); @heif_context_read_from_memory_without_copy:= SafeGetProcAddress(libheif, 'heif_context_read_from_memory_without_copy'); AOptions:= heif_decoding_options_alloc(); AVersion:= AOptions^.version; heif_decoding_options_free(AOptions); if (AVersion < 2) then raise Exception.Create('HEIF: Old version'); // Register image handler and format ImageHandlers.RegisterImageReader ('High Efficiency Image', HEIF_EXT, TDCReaderHEIF); TPicture.RegisterFileFormat(HEIF_EXT, 'High Efficiency Image', THighEfficiencyImage); except on E: Exception do begin DCDebug(E.Message); FreeLibrary(libheif); libheif:= NilHandle; end; end; end; procedure Finalize; begin if (libheif <> NilHandle) then FreeLibrary(libheif); end; initialization Initialize; finalization Finalize; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udcreadrsvg.pas�������������������������������������������������������0000644�0001750�0000144�00000024723�14743153644�020247� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Scalable Vector Graphics reader implementation (via rsvg and cairo) Copyright (C) 2012-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uDCReadRSVG; {$mode delphi} interface uses Classes, SysUtils, Graphics, FPImage, uVectorImage; type { TDCReaderRSVG } TDCReaderRSVG = class (TVectorReader) private FRsvgHandle: Pointer; protected function InternalCheck (Stream: TStream): Boolean; override; procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override; public class function CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; override; end; implementation uses DynLibs, IntfGraphics, GraphType, Types, CTypes, LazUTF8, DCOSUtils, uThumbnails, uIconTheme, uGraphics; type cairo_format_t = ( CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_RGB24, CAIRO_FORMAT_A8, CAIRO_FORMAT_A1 ); type Pcairo_surface_t = Pointer; Pcairo_t = Pointer; PRsvgHandle = Pointer; PPGError = Pointer; type PRsvgDimensionData = ^TRsvgDimensionData; TRsvgDimensionData = record width: cint; height: cint; em: cdouble; ex: cdouble; end; var cairo_image_surface_create: function(format: cairo_format_t; width, height: LongInt): Pcairo_surface_t; cdecl; cairo_surface_destroy: procedure(surface: Pcairo_surface_t); cdecl; cairo_image_surface_get_data: function(surface: Pcairo_surface_t): PByte; cdecl; cairo_create: function(target: Pcairo_surface_t): Pcairo_t; cdecl; cairo_destroy: procedure (cr: Pcairo_t); cdecl; cairo_scale: procedure(cr: Pcairo_t; sx, sy: cdouble); cdecl; rsvg_handle_new_from_file: function(const file_name: PAnsiChar; error: PPGError): PRsvgHandle; cdecl; rsvg_handle_new_from_data: function(data: PByte; data_len: SizeUInt; error: PPGError): PRsvgHandle; cdecl; rsvg_handle_get_dimensions: procedure(handle: PRsvgHandle; dimension_data: PRsvgDimensionData); cdecl; rsvg_handle_render_cairo: function(handle: PRsvgHandle; cr: Pcairo_t): LongBool; cdecl; g_type_init: procedure; cdecl; g_object_unref: procedure(anObject: Pointer); cdecl; type PBGRA = ^TBGRA; TBGRA = packed record Blue, Green, Red, Alpha: Byte; end; procedure RsvgHandleRender(RsvgHandle: Pointer; CairoSurface: Pcairo_surface_t; Cairo: Pcairo_t; Img: TFPCustomImage); var ImageData: PBGRA; Desc: TRawImageDescription; begin try // Draws a SVG to a Cairo surface if rsvg_handle_render_cairo(RsvgHandle, Cairo) then begin // Get a pointer to the data of the image surface, for direct access ImageData:= PBGRA(cairo_image_surface_get_data(CairoSurface)); // Initialize image description Desc.Init_BPP32_B8G8R8A8_BIO_TTB(Img.Width, Img.Height); TLazIntfImage(Img).DataDescription:= Desc; // Copy image data Move(ImageData^, TLazIntfImage(Img).PixelData^, Img.Width * Img.Height * SizeOf(TBGRA)); end; finally g_object_unref(RsvgHandle); cairo_destroy(Cairo); cairo_surface_destroy(CairoSurface); end; end; function BitmapLoadFromScalable(const FileName: String; AWidth, AHeight: Integer): TBitmap; var Cairo: Pcairo_t; RsvgHandle: Pointer; Image: TLazIntfImage; CairoSurface: Pcairo_surface_t; RsvgDimensionData: TRsvgDimensionData; begin Result:= nil; RsvgHandle:= rsvg_handle_new_from_file(PAnsiChar(UTF8ToSys(FileName)), nil); if Assigned(RsvgHandle) then begin Image:= TLazIntfImage.Create(AWidth, AHeight); try // Get the SVG's size rsvg_handle_get_dimensions(RsvgHandle, @RsvgDimensionData); // Creates an image surface of the specified format and dimensions CairoSurface:= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, Image.Width, Image.Height); Cairo:= cairo_create(CairoSurface); // Scale image if needed if (Image.Width <> RsvgDimensionData.width) or (Image.Height <> RsvgDimensionData.height) then begin cairo_scale(Cairo, Image.Width / RsvgDimensionData.width, Image.Height / RsvgDimensionData.height); end; RsvgHandleRender(RsvgHandle, CairoSurface, Cairo, Image); Result:= TBitmap.Create; BitmapAssign(Result, Image); finally Image.Free; end; end; end; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var Scale: Boolean; Cairo: Pcairo_t; RsvgHandle: Pointer; Image: TLazIntfImage; CairoSurface: Pcairo_surface_t; RsvgDimensionData: TRsvgDimensionData; begin Result:= nil; if TScalableVectorGraphics.IsFileExtensionSupported(ExtractFileExt(aFileName)) then begin RsvgHandle:= rsvg_handle_new_from_file(PAnsiChar(UTF8ToSys(aFileName)), nil); if Assigned(RsvgHandle) then begin Result:= TBitmap.Create; // Get the SVG's size rsvg_handle_get_dimensions(RsvgHandle, @RsvgDimensionData); Scale:= (RsvgDimensionData.width > aSize.cx) or (RsvgDimensionData.height > aSize.cy); if Scale then begin // Calculate aspect width and height of thumb aSize:= TThumbnailManager.GetPreviewScaleSize(RsvgDimensionData.width, RsvgDimensionData.height); end else begin aSize.cx:= RsvgDimensionData.width; aSize.cy:= RsvgDimensionData.height; end; // Creates an image surface of the specified format and dimensions CairoSurface:= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, aSize.cx, aSize.cy); Cairo:= cairo_create(CairoSurface); // Scale image if needed if Scale then begin cairo_scale(Cairo, aSize.cx / RsvgDimensionData.width, aSize.cy / RsvgDimensionData.height); end; Image:= TLazIntfImage.Create(aSize.cx, aSize.cy); try RsvgHandleRender(RsvgHandle, CairoSurface, Cairo, Image); BitmapAssign(Result, Image); finally Image.Free; end; end; end; end; { TDCReaderRSVG } function TDCReaderRSVG.InternalCheck(Stream: TStream): boolean; var MemoryStream: TMemoryStream; begin Result:= Stream is TMemoryStream; if Result then begin MemoryStream:= TMemoryStream(Stream); FRsvgHandle:= rsvg_handle_new_from_data(MemoryStream.Memory, MemoryStream.Size, nil); Result:= Assigned(FRsvgHandle); end; end; procedure TDCReaderRSVG.InternalRead(Stream: TStream; Img: TFPCustomImage); var Cairo: Pcairo_t; CairoSurface: Pcairo_surface_t; RsvgDimensionData: TRsvgDimensionData; begin // Get the SVG's size rsvg_handle_get_dimensions(FRsvgHandle, @RsvgDimensionData); // Set output image size Img.SetSize(RsvgDimensionData.width, RsvgDimensionData.height); // Creates an image surface of the specified format and dimensions CairoSurface:= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, RsvgDimensionData.width, RsvgDimensionData.height); Cairo:= cairo_create(CairoSurface); // Render vector graphics to raster image RsvgHandleRender(FRsvgHandle, CairoSurface, Cairo, Img); end; class function TDCReaderRSVG.CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; begin Result:= BitmapLoadFromScalable(FileName, AWidth, AHeight); end; const {$IF DEFINED(UNIX)} cairolib = 'libcairo.so.2'; rsvglib = 'librsvg-2.so.2'; gobjectlib = 'libgobject-2.0.so.0'; {$ELSEIF DEFINED(MSWINDOWS)} cairolib = 'libcairo-2.dll'; rsvglib = 'librsvg-2-2.dll'; gobjectlib = 'libgobject-2.0-0.dll'; {$ENDIF} var libcairo, librsvg, libgobject: TLibHandle; procedure LoadLibraries; {$IF DEFINED(UNIX)} begin libcairo:= LoadLibrary(cairolib); librsvg:= LoadLibrary(rsvglib); libgobject:= LoadLibrary(gobjectlib); end; {$ELSEIF DEFINED(MSWINDOWS)} var I: Integer; Path, FullName: String; Value: TStringArray; begin Path:= GetEnvironmentVariable('PATH'); Value:= Path.Split([PathSeparator], TStringSplitOptions.ExcludeEmpty); for I:= Low(Value) to High(Value) do begin Path:= IncludeTrailingPathDelimiter(Value[I]); FullName:= Path + rsvglib; if mbFileExists(FullName)then begin librsvg:= mbLoadLibraryEx(FullName); libcairo:= mbLoadLibraryEx(Path + cairolib); libgobject:= mbLoadLibraryEx(Path + gobjectlib); Break; end; end; end; {$ENDIF} procedure Initialize; begin LoadLibraries; if (libcairo <> NilHandle) and (librsvg <> NilHandle) and (libgobject <> NilHandle) then try @cairo_image_surface_create:= SafeGetProcAddress(libcairo, 'cairo_image_surface_create'); @cairo_surface_destroy:= SafeGetProcAddress(libcairo, 'cairo_surface_destroy'); @cairo_image_surface_get_data:= SafeGetProcAddress(libcairo, 'cairo_image_surface_get_data'); @cairo_create:= SafeGetProcAddress(libcairo, 'cairo_create'); @cairo_destroy:= SafeGetProcAddress(libcairo, 'cairo_destroy'); @cairo_scale:= SafeGetProcAddress(libcairo, 'cairo_scale'); @rsvg_handle_new_from_file:= SafeGetProcAddress(librsvg, 'rsvg_handle_new_from_file'); @rsvg_handle_new_from_data:= SafeGetProcAddress(librsvg, 'rsvg_handle_new_from_data'); @rsvg_handle_get_dimensions:= SafeGetProcAddress(librsvg, 'rsvg_handle_get_dimensions'); @rsvg_handle_render_cairo:= SafeGetProcAddress(librsvg, 'rsvg_handle_render_cairo'); @g_type_init:= SafeGetProcAddress(libgobject, 'g_type_init'); @g_object_unref:= SafeGetProcAddress(libgobject, 'g_object_unref'); g_type_init(); // Register image handler and format TThumbnailManager.RegisterProvider(@GetThumbnail); TScalableVectorGraphics.RegisterReaderClass(TDCReaderRSVG); ImageHandlers.RegisterImageReader('Scalable Vector Graphics', 'SVG;SVGZ', TDCReaderRSVG); except // Ignore end; end; procedure Finalize; begin if (libcairo <> NilHandle) then FreeLibrary(libcairo); if (librsvg <> NilHandle) then FreeLibrary(librsvg); if (libgobject <> NilHandle) then FreeLibrary(libgobject); end; initialization Initialize; finalization Finalize; end. ���������������������������������������������doublecmd-1.1.22/src/platform/udcreadsvg.pas��������������������������������������������������������0000644�0001750�0000144�00000015566�14743153644�020072� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Scalable Vector Graphics reader implementation (via Image32 library) Copyright (C) 2022 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uDCReadSVG; {$mode delphi} interface uses Classes, SysUtils, Graphics, FPImage, ZStream, Img32.SVG.Reader, uVectorImage; type { TSvgReaderEx } TSvgReaderEx = class(TSvgReader) public function LoadFromStream(Stream: TStream): Boolean; function LoadFromFile(const FileName: String): Boolean; end; { TDCReaderSVG } TDCReaderSVG = class(TVectorReader) private FSvgReader: TSvgReaderEx; protected function InternalCheck(Stream: TStream): Boolean; override; procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override; public constructor Create; override; destructor Destroy; override; public class function CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; override; end; implementation uses IntfGraphics, GraphType, Types, LazUTF8, DCClassesUtf8, Img32, Img32.Text, Img32.Vector, Img32.Fmt.SVG, uThumbnails, uGraphics; const HEAD_CRC = $02; { bit 1 set: header CRC present } EXTRA_FIELD = $04; { bit 2 set: extra field present } ORIG_NAME = $08; { bit 3 set: original file name present } COMMENT = $10; { bit 4 set: file comment present } type TGzHeader = packed record ID1 : Byte; ID2 : Byte; Method : Byte; Flags : Byte; ModTime : UInt32; XtraFlags : Byte; OS : Byte; end; function CheckGzipHeader(ASource: TStream): Boolean; var ALength: Integer; AHeader: TGzHeader; begin ASource.ReadBuffer(AHeader, SizeOf(TGzHeader)); Result:= (AHeader.ID1 = $1F) and (AHeader.ID2 = $8B) and (AHeader.Method = 8); if Result then begin // Skip the extra field if (AHeader.Flags and EXTRA_FIELD <> 0) then begin ALength:= ASource.ReadWord; while ALength > 0 do begin ASource.ReadByte; Dec(ALength); end; end; // Skip the original file name if (AHeader.Flags and ORIG_NAME <> 0) then begin while (ASource.ReadByte > 0) do; end; // Skip the .gz file comment if (AHeader.Flags and COMMENT <> 0) then begin while (ASource.ReadByte > 0) do; end; // Skip the header crc if (AHeader.Flags and HEAD_CRC <> 0) then begin ASource.ReadWord; end; end; end; function BitmapLoadFromScalable(const FileName: String; AWidth, AHeight: Integer): TBitmap; var Image32: TImage32; Image: TLazIntfImage; SvgReader: TSvgReaderEx; Description: TRawImageDescription; begin Result:= nil; SvgReader:= TSvgReaderEx.Create; try if SvgReader.LoadFromFile(FileName) then begin Image32:= TImage32.Create(AWidth, AHeight); try SvgReader.DrawImage(Image32, True); AWidth:= Image32.Width; AHeight:= Image32.Height; Image:= TLazIntfImage.Create(AWidth, AHeight); try Description.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight); Image.DataDescription:= Description; Move(Image32.PixelBase^, Image.PixelData^, AWidth * AHeight * SizeOf(TColor32)); Result:= TBitmap.Create; BitmapAssign(Result, Image); finally Image.Free; end; finally Image32.Free; end; end; finally SvgReader.Free; end; end; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; begin Result:= nil; if TScalableVectorGraphics.IsFileExtensionSupported(ExtractFileExt(aFileName)) then begin Result:= BitmapLoadFromScalable(aFileName, aSize.cx, aSize.cy); end; end; { TSvgReaderEx } function TSvgReaderEx.LoadFromStream(Stream: TStream): Boolean; var MemoryStream: TMemoryStream; GzipStream: TDecompressionStream; begin if not CheckGzipHeader(Stream) then Result:= inherited LoadFromStream(Stream) else begin MemoryStream:= TMemoryStream.Create; try GzipStream:= TDecompressionStream.Create(Stream, True); try MemoryStream.CopyFrom(GzipStream, 0); Result:= inherited LoadFromStream(MemoryStream); finally GzipStream.Free; end; finally MemoryStream.Free; end; end; end; function TSvgReaderEx.LoadFromFile(const FileName: String): Boolean; var AStream: TFileStreamEx; begin try AStream:= TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try Result:= LoadFromStream(AStream); finally AStream.Free; end; except Result:= False; end; end; { TDCReaderSVG } function TDCReaderSVG.InternalCheck(Stream: TStream): Boolean; begin Result:= FSvgReader.LoadFromStream(Stream) end; procedure TDCReaderSVG.InternalRead(Stream: TStream; Img: TFPCustomImage); var Image32: TImage32; Description: TRawImageDescription; begin Image32:= TImage32.Create(0, 0); try FSvgReader.DrawImage(Image32, False); Description.Init_BPP32_B8G8R8A8_BIO_TTB(Image32.Width, Image32.Height); TLazIntfImage(Img).DataDescription:= Description; Move(Image32.PixelBase^, TLazIntfImage(Img).PixelData^, Img.Width * Img.Height * SizeOf(TColor32)); finally Image32.Free; end; end; constructor TDCReaderSVG.Create; begin inherited Create; FSvgReader:= TSvgReaderEx.Create; end; destructor TDCReaderSVG.Destroy; begin inherited Destroy; FSvgReader.Free; end; class function TDCReaderSVG.CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; begin Result:= BitmapLoadFromScalable(FileName, AWidth, AHeight); end; procedure Initialize; begin if (TScalableVectorGraphics.GetReaderClass = nil) then begin {$IF DEFINED(MSWINDOWS)} FontManager.Load('Times New Roman'); FontManager.Load('Times New Roman Bold'); FontManager.Load('Times New Roman Italic'); FontManager.Load('Times New Roman Bold Italic'); {$ENDIF} // Register image handler and format TThumbnailManager.RegisterProvider(@GetThumbnail); TScalableVectorGraphics.RegisterReaderClass(TDCReaderSVG); ImageHandlers.RegisterImageReader('Scalable Vector Graphics', 'SVG;SVGZ', TDCReaderSVG); end; end; initialization Initialize; end. ������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udcversion.pas��������������������������������������������������������0000644�0001750�0000144�00000036060�14743153644�020114� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Version information about DC, building tools and running environment. Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2010 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uDCVersion; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLVersion; {$I dcrevision.inc} // Double Commander revision number const dcBuildDate = {$I %DATE%}; lazVersion = lcl_version; // Lazarus version (major.minor.micro) fpcVersion = {$I %FPCVERSION%}; // FPC version (major.minor.micro) TargetCPU = {$I %FPCTARGETCPU%}; // Target CPU of FPC TargetOS = {$I %FPCTARGETOS%}; // Target Operating System of FPC var DCVersion, // Double Commander version TargetWS, // Target WidgetSet of Lazarus OSVersion, // Operating System where DC is run WSVersion, // WidgetSet library version where DC is run Copyright : String; procedure InitializeVersionInfo; implementation uses InterfaceBase, FileInfo, VersionConsts {$IF DEFINED(UNIX)} , BaseUnix, DCOSUtils, uDCUtils, DCClassesUtf8 {$IFDEF DARWIN} , MacOSAll {$ENDIF} {$ENDIF} {$IFDEF LCLQT} , qt4 {$ENDIF} {$IFDEF LCLQT5} , qt5 {$ENDIF} {$IFDEF LCLQT6} , qt6 {$ENDIF} {$IFDEF LCLGTK2} , gtk2 {$ENDIF} {$IFDEF LCLGTK3} , LazGtk3 {$ENDIF} {$IFDEF MSWINDOWS} , Windows, JwaNative, JwaNtStatus, JwaWinType, uMyWindows {$ENDIF} {$if lcl_fullversion >= 1070000} , LCLPlatformDef {$endif} ; {$IF DEFINED(UNIX)} {en Reads file into strings. Returns @false if file not found or cannot be read. } function GetStringsFromFile(FileName: String; out sl: TStringListEx): Boolean; begin Result := False; sl := nil; if mbFileAccess(FileName, fmOpenRead) then begin sl := TStringListEx.Create; try sl.LoadFromFile(FileName); Result := True; except on EStreamError do sl.Free; end; end; end; {en Reads first line of file into a string. Returns @false if file not found or cannot be read. } function GetStringFromFile(FileName: String; out str: String): Boolean; var sl: TStringListEx; begin str := EmptyStr; Result := GetStringsFromFile(FileName, sl); if Result then try if sl.Count > 0 then str := sl.Strings[0]; finally sl.Free; end; end; function GetOsFromLsbRelease: String; var sl: TStringListEx; begin Result := EmptyStr; if GetStringsFromFile('/etc/lsb-release', sl) then try if sl.Count > 0 then begin Result := sl.Values['DISTRIB_DESCRIPTION']; if Result <> EmptyStr then Result := TrimQuotes(Result) else Result := sl.Values['DISTRIB_ID'] + ' ' + sl.Values['DISTRIB_RELEASE'] + ' ' + sl.Values['DISTRIB_CODENAME']; end; finally sl.Free; end; end; function GetOsFromOsRelease: String; var sl: TStringListEx; begin Result := EmptyStr; if GetStringsFromFile('/etc/os-release', sl) then try if sl.Count > 0 then begin Result := sl.Values['PRETTY_NAME']; if Result <> EmptyStr then Result := TrimQuotes(Result) else Result := sl.Values['NAME'] + ' ' + sl.Values['VERSION'] + ' ' + sl.Values['ID']; end; finally sl.Free; end; end; function GetOsFromProcVersion: String; var i: Integer; s: String; begin Result := EmptyStr; if GetStringFromFile('/proc/version', s) then begin // Get first three strings separated by space. i := Pos(' ', s); if i > 0 then Result := Result + Copy(s, 1, i); Delete(s, 1, i); i := Pos(' ', s); if i > 0 then Result := Result + Copy(s, 1, i); Delete(s, 1, i); i := Pos(' ', s); if i > 0 then Result := Result + Copy(s, 1, i - 1); Delete(s, 1, i); end; end; function GetOsFromIssue: String; begin if not GetStringFromFile('/etc/issue', Result) then Result := EmptyStr; end; function GetDebianVersion: String; var s: String; begin if GetStringFromFile('/etc/debian_version', s) then begin Result := 'Debian'; if s <> EmptyStr then Result := Result + ' ' + s; end else Result := EmptyStr; end; function GetSuseVersion: String; begin if GetStringFromFile('/etc/SuSE-release', Result) or GetStringFromFile('/etc/suse-release', Result) then begin if Result = EmptyStr then Result := 'Suse'; end else Result := EmptyStr; end; function GetRedHatVersion: String; begin if GetStringFromFile('/etc/redhat-release', Result) then begin if Result = EmptyStr then Result := 'RedHat'; end else Result := EmptyStr; end; function GetMandrakeVersion: String; begin if GetStringFromFile('/etc/mandrake-release', Result) then begin if Result = EmptyStr then Result := 'Mandrake'; end else Result := EmptyStr; end; function GetVersionNumber: String; var Info: utsname; I: Integer = 1; begin FillChar(Info, SizeOf(Info), 0); fpUname(Info); Result := Info.release; while (I <= Length(Result)) and (Result[I] in ['0'..'9', '.']) do Inc(I); Result := Copy(Result, 1, I - 1); end; {$IFDEF DARWIN} function GetMacOSXVersion: String; var versionMajor, versionMinor, versionBugFix: SInt32; begin Result:= EmptyStr; if (Gestalt(gestaltSystemVersionMajor, versionMajor) <> noErr) then Exit; if (Gestalt(gestaltSystemVersionMinor, versionMinor) <> noErr) then Exit; if (Gestalt(gestaltSystemVersionBugFix, versionBugFix) <> noErr) then Exit; Result:= Format('Mac OS X %d.%d.%d', [versionMajor, versionMinor, versionBugFix]); end; {$ENDIF} {$ENDIF} {$IF DEFINED(MSWINDOWS)} procedure TryGetNativeSystemInfo(var SystemInfo: TSystemInfo); type TGetNativeSystemInfo = procedure (var lpSystemInfo: TSystemInfo); stdcall; var hLib: HANDLE; GetNativeSystemInfoProc: TGetNativeSystemInfo; begin hLib := LoadLibrary(LPCTSTR('kernel32.dll')); if hLib <> 0 then begin try GetNativeSystemInfoProc := TGetNativeSystemInfo(GetProcAddress(hLib, 'GetNativeSystemInfo')); if Assigned(GetNativeSystemInfoProc) then GetNativeSystemInfoProc(SystemInfo) else GetSystemInfo(SystemInfo); finally FreeLibrary(hLib); end; end else GetSystemInfo(SystemInfo); end; {$ENDIF} procedure InitializeVersionInfo; {$IF DEFINED(MSWINDOWS)} const PROCESSOR_ARCHITECTURE_AMD64 = 9; CURRENT_VERSION = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion'; var si: SYSTEM_INFO; osvi: TOsVersionInfoExW; ReleaseId: UnicodeString; {$ENDIF} begin with TVersionInfo.Create do begin Load(HINSTANCE); Copyright:= StringFileInfo.Items[0].Values['LegalCopyright']; DCVersion:= Format('%d.%d.%.d', [FixedInfo.FileVersion[0], FixedInfo.FileVersion[1], FixedInfo.FileVersion[2]]); if (FixedInfo.FileFlags and VS_FF_PRERELEASE <> 0) then begin if (FixedInfo.FileFlags and VS_FF_PRIVATEBUILD <> 0) then DCVersion+= ' alpha' else begin DCVersion+= ' gamma'; end; end; Free; end; TargetWS := LCLPlatformDirNames[WidgetSet.LCLPlatform]; {$IF DEFINED(MSWINDOWS)} OSVersion := 'Windows'; ZeroMemory(@osvi, SizeOf(TOsVersionInfoExW)); osvi.dwOSVersionInfoSize := SizeOf(TOsVersionInfoExW); if (RtlGetVersion(@osvi) = STATUS_SUCCESS) or GetVersionExW(@osvi) then begin ZeroMemory(@si, SizeOf(si)); TryGetNativeSystemInfo(si); case osvi.dwPlatformId of VER_PLATFORM_WIN32_WINDOWS: case osvi.dwMajorVersion of 4: case osvi.dwMinorVersion of 0: OSVersion := OSVersion + ' 95'; 10: OSVersion := OSVersion + ' 98'; 90: OSVersion := OSVersion + ' ME'; end; end; VER_PLATFORM_WIN32_NT: begin case osvi.dwMajorVersion of 3: OSVersion := OSVersion + ' NT 3.5'; 4: OSVersion := OSVersion + ' NT 4'; 5: case osvi.dwMinorVersion of 0: OSVersion := OSVersion + ' 2000'; 1: begin OSVersion := OSVersion + ' XP'; if osvi.wSuiteMask = $0000 then OSVersion := OSVersion + ' Home' else if osvi.wSuiteMask = $0200 then OSVersion := OSVersion + ' Professional'; end; 2: if (osvi.wProductType = VER_NT_WORKSTATION) and (si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64) then begin OSVersion := OSVersion + ' XP Professional x64' end else if (osvi.wProductType = VER_NT_SERVER) then begin if osvi.wSuiteMask = $8000 then OSVersion := OSVersion + ' Home Server' else OSVersion := OSVersion + ' Server 2003'; end; end; 6: case osvi.dwMinorVersion of 0: if (osvi.wProductType = VER_NT_WORKSTATION) then begin OSVersion := OSVersion + ' Vista'; if osvi.wSuiteMask = $0000 then OSVersion := OSVersion + ' Ultimate' else if osvi.wSuiteMask = $0200 then OSVersion := OSVersion + ' Home'; end else if (osvi.wProductType = VER_NT_SERVER) then OSVersion := OSVersion + ' Server 2008'; 1: if (osvi.wProductType = VER_NT_WORKSTATION) then OSVersion := OSVersion + ' 7' else if (osvi.wProductType = VER_NT_SERVER) then OSVersion := OSVersion + ' Server 2008 R2'; 2: if (osvi.wProductType = VER_NT_WORKSTATION) then OSVersion := OSVersion + ' 8' else if (osvi.wProductType = VER_NT_SERVER) then OSVersion := OSVersion + ' Server 2012'; 3: if (osvi.wProductType = VER_NT_WORKSTATION) then OSVersion := OSVersion + ' 8.1' else if (osvi.wProductType = VER_NT_SERVER) then OSVersion := OSVersion + ' Server 2012 R2'; end; 10: case osvi.dwMinorVersion of 0: if (osvi.wProductType = VER_NT_WORKSTATION) then begin if (osvi.dwBuildNumber >= 22000) then OSVersion := OSVersion + ' 11' else begin OSVersion := OSVersion + ' 10'; end; if (osvi.wSuiteMask and VER_SUITE_PERSONAL <> 0) then OSVersion := OSVersion + ' Home'; if ((osvi.dwBuildNumber >= 19042) and RegReadKey(HKEY_LOCAL_MACHINE, CURRENT_VERSION, 'DisplayVersion', ReleaseId)) or RegReadKey(HKEY_LOCAL_MACHINE, CURRENT_VERSION, 'ReleaseId', ReleaseId) then begin OSVersion := OSVersion + ' ' + String(ReleaseId); end; end else if (osvi.wProductType = VER_NT_SERVER) then begin OSVersion += ' Server '; case osvi.dwBuildNumber of 14393: OSVersion += '2016'; 17763: OSVersion += '2019'; 18363: OSVersion += '1909'; 19041: OSVersion += '2004'; 19042: OSVersion += '20H2'; 20348: OSVersion += '2022'; else OSVersion += '10.0.' + IntToStr(osvi.dwBuildNumber); end; end; end; end; end; end; // If something detected then add service pack number and architecture. if OSVersion <> 'Windows' then begin if osvi.wServicePackMajor > 0 then begin OSVersion := OSVersion + ' SP' + IntToStr(osvi.wServicePackMajor); if osvi.wServicePackMinor > 0 then OSVersion := OSVersion + '.' + IntToStr(osvi.wServicePackMinor); end; if si.wProcessorArchitecture in [PROCESSOR_ARCHITECTURE_AMD64] then OSVersion := OSVersion + ' x86_64' else OSVersion := OSVersion + ' i386'; end else OSVersion := OSVersion + ' Build ' + IntToStr(osvi.dwBuildNumber); end; {$ELSEIF DEFINED(UNIX)} // Try using linux standard base. OSVersion := GetOsFromLsbRelease; // Try some distribution-specific files. if OSVersion = EmptyStr then OSVersion := GetDebianVersion; if OSVersion = EmptyStr then OSVersion := GetRedHatVersion; if OSVersion = EmptyStr then OSVersion := GetSuseVersion; if OSVersion = EmptyStr then OSVersion := GetMandrakeVersion; {$IFDEF DARWIN} if OSVersion = EmptyStr then OSVersion := GetMacOSXVersion; {$ENDIF} // Try using linux systemd base. if OSVersion = EmptyStr then OSVersion := GetOsFromOsRelease; // Other methods. if OSVersion = EmptyStr then OSVersion := GetOsFromProcVersion; if OSVersion = EmptyStr then OSVersion := GetOsFromIssue; // Set default names. if OSVersion = EmptyStr then begin {$IF DEFINED(LINUX)} OSVersion := 'Linux'; {$ELSEIF DEFINED(DARWIN)} OSVersion := 'Darwin'; // MacOS {$ELSEIF DEFINED(FREEBSD)} OSVersion := 'FreeBSD'; {$ELSEIF DEFINED(BSD)} OSVersion := 'BSD'; {$ELSEIF DEFINED(HAIKU)} OSVersion := 'Haiku'; {$ELSE} OSVersion := 'Unix'; {$ENDIF} OSVersion += ' ' + GetVersionNumber; end; {$ENDIF} {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} WSVersion := 'Qt ' + QtVersion; {$ELSEIF DEFINED(LCLGTK2)} WSVersion := 'GTK ' + IntToStr(gtk_major_version) + '.' + IntToStr(gtk_minor_version) + '.' + IntToStr(gtk_micro_version); {$ELSEIF DEFINED(LCLGTK3)} WSVersion := 'GTK ' + IntToStr(gtk_get_major_version) + '.' + IntToStr(gtk_get_minor_version) + '.' + IntToStr(gtk_get_micro_version); {$ENDIF} end; procedure Initialize; begin LCLPlatformDirNames[lpQT]:= 'qt4'; LCLPlatformDirNames[lpWin32]:= 'win32/win64'; end; initialization Initialize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udefaultplugins.pas���������������������������������������������������0000644�0001750�0000144�00000030506�14743153644�021145� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Some useful functions to work with plugins Copyright (C) 2011-2021 Alexander Koblov (alexx2000@mail.ru) 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 } unit uDefaultPlugins; {$mode objfpc}{$H+} interface uses Classes, SysUtils; const WcxMask = '*.wcx'{$IFDEF CPU64} + ';*.wcx64'{$ENDIF}; WdxMask = '*.wdx'{$IFDEF CPU64} + ';*.wdx64'{$ENDIF}; WfxMask = '*.wfx'{$IFDEF CPU64} + ';*.wfx64'{$ENDIF}; WlxMask = '*.wlx'{$IFDEF CPU64} + ';*.wlx64'{$ENDIF}; type TBinaryType = (btUnknown, btPe32, btPe64, btElf32, btElf64, btMacho32, btMacho64); const PluginBinaryType = {$IF DEFINED(WIN32)} btPe32 {$ELSEIF DEFINED(WIN64)} btPe64 {$ELSEIF DEFINED(DARWIN) AND DEFINED(CPU32)} btMacho32 {$ELSEIF DEFINED(DARWIN) AND DEFINED(CPU64)} btMacho64 {$ELSEIF DEFINED(UNIX) AND DEFINED(CPU32)} btElf32 {$ELSEIF DEFINED(UNIX) AND DEFINED(CPU64)} btElf64 {$ELSE} btUnknown {$ENDIF} ; PluginBinaryTypeString: array[TBinaryType] of String = ( 'Unknown', 'Windows 32 bit', 'Windows 64 bit', 'Unix 32 bit', 'Unix 64 bit', 'Mac OS X 32 bit', 'Mac OS X 64 bit' ); procedure UpdatePlugins; function CheckPlugin(var FileName: String): Boolean; function GetPluginBinaryType(const FileName: String): TBinaryType; implementation uses //Lazarus, Free-Pascal, etc. Forms, Dialogs, //DC {$IF DEFINED(CPU64)} DCStrUtils, {$ENDIF} DCOSUtils, DCClassesUtf8, uGlobs, uLng, uDCUtils; procedure UpdatePlugins; var I: Integer; Folder: String; begin // Wcx plugins Folder:= '%commander_path%' + PathDelim + 'plugins' + PathDelim + 'wcx' + PathDelim; I:= gWCXPlugins.IndexOfName('zip'); if I < 0 then gWCXPlugins.Add('zip', 735, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 735; I:= gWCXPlugins.IndexOfName('jar'); if I < 0 then gWCXPlugins.Add('jar', 990, Folder + 'zip' + PathDelim + 'zip.wcx'); {$IF DEFINED(MSWINDOWS)} I:= gWCXPlugins.IndexOfName('7z'); if I < 0 then gWCXPlugins.Add('7z', 607, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); {$ENDIF} I:= gWCXPlugins.IndexOfName('tar'); if I < 0 then gWCXPlugins.Add('tar', 223, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 223; I:= gWCXPlugins.IndexOfName('bz2'); if I < 0 then gWCXPlugins.Add('bz2', 91, Folder + 'zip' + PathDelim + 'zip.wcx') else begin gWCXPlugins.Flags[I]:= 91; // For bz2 used another plugin, so update path too gWCXPlugins.FileName[I]:= Folder + 'zip' + PathDelim + 'zip.wcx'; end; I:= gWCXPlugins.IndexOfName('tbz'); if I < 0 then gWCXPlugins.Add('tbz', 95, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 95; I:= gWCXPlugins.IndexOfName('gz'); if I < 0 then gWCXPlugins.Add('gz', 91, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 91; I:= gWCXPlugins.IndexOfName('tgz'); if I < 0 then gWCXPlugins.Add('tgz', 95, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 95; I:= gWCXPlugins.IndexOfName('lzma'); if I < 0 then gWCXPlugins.Add('lzma', 1, Folder + 'zip' + PathDelim + 'zip.wcx') else begin gWCXPlugins.Flags[I]:= 1; // For lzma used another plugin, so update path too gWCXPlugins.FileName[I]:= Folder + 'zip' + PathDelim + 'zip.wcx'; end; I:= gWCXPlugins.IndexOfName('tlz'); if I < 0 then gWCXPlugins.Add('tlz', 95, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 95; {$IF NOT DEFINED(DARWIN)} I:= gWCXPlugins.IndexOfName('xz'); if I < 0 then gWCXPlugins.Add('xz', 91, Folder + 'zip' + PathDelim + 'zip.wcx'); I:= gWCXPlugins.IndexOfName('zst'); if I < 0 then gWCXPlugins.Add('zst', 91, Folder + 'zip' + PathDelim + 'zip.wcx'); I:= gWCXPlugins.IndexOfName('txz'); if I < 0 then gWCXPlugins.Add('txz', 95, Folder + 'zip' + PathDelim + 'zip.wcx'); I:= gWCXPlugins.IndexOfName('zipx'); if I < 0 then gWCXPlugins.Add('zipx', 223, Folder + 'zip' + PathDelim + 'zip.wcx') else gWCXPlugins.Flags[I]:= 223; {$ENDIF} {$IF DEFINED(MSWINDOWS)} I:= gWCXPlugins.IndexOfName('cpio'); if I < 0 then gWCXPlugins.Add('cpio', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx') else begin gWCXPlugins.Flags[I]:= 4; // For cpio used another plugin, so update path too gWCXPlugins.FileName[I]:= Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'; end; I:= gWCXPlugins.IndexOfName('deb'); if I < 0 then gWCXPlugins.Add('deb', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx') else begin gWCXPlugins.Flags[I]:= 4; // For deb used another plugin, so update path too gWCXPlugins.FileName[I]:= Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'; end; I:= gWCXPlugins.IndexOfName('arj'); if I < 0 then gWCXPlugins.Add('arj', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('cab'); if I < 0 then gWCXPlugins.Add('cab', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('cramfs'); if I < 0 then gWCXPlugins.Add('cramfs', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('dmg'); if I < 0 then gWCXPlugins.Add('dmg', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('fat'); if I < 0 then gWCXPlugins.Add('fat', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('hfs'); if I < 0 then gWCXPlugins.Add('hfs', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('iso'); if I < 0 then gWCXPlugins.Add('iso', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('lha'); if I < 0 then gWCXPlugins.Add('lha', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('lzh'); if I < 0 then gWCXPlugins.Add('lzh', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('ntfs'); if I < 0 then gWCXPlugins.Add('ntfs', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('squashfs'); if I < 0 then gWCXPlugins.Add('squashfs', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('taz'); if I < 0 then gWCXPlugins.Add('taz', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('vhd'); if I < 0 then gWCXPlugins.Add('vhd', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('wim'); if I < 0 then gWCXPlugins.Add('wim', 85, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('xar'); if I < 0 then gWCXPlugins.Add('xar', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); I:= gWCXPlugins.IndexOfName('z'); if I < 0 then gWCXPlugins.Add('z', 4, Folder + 'sevenzip' + PathDelim + 'sevenzip.wcx'); {$ELSE} I:= gWCXPlugins.IndexOfName('cpio'); if I < 0 then gWCXPlugins.Add('cpio', 4, Folder + 'cpio' + PathDelim + 'cpio.wcx') else gWCXPlugins.Flags[I]:= 4; I:= gWCXPlugins.IndexOfName('deb'); if I < 0 then gWCXPlugins.Add('deb', 4, Folder + 'deb' + PathDelim + 'deb.wcx') else gWCXPlugins.Flags[I]:= 4; {$ENDIF} I:= gWCXPlugins.IndexOfName('rpm'); if I < 0 then gWCXPlugins.Add('rpm', 4, Folder + 'rpm' + PathDelim + 'rpm.wcx') else gWCXPlugins.Flags[I]:= 4; I:= gWCXPlugins.IndexOfName('rar'); if I < 0 then gWCXPlugins.Add('rar', 607, Folder + 'unrar' + PathDelim + 'unrar.wcx') else gWCXPlugins.Flags[I]:= 607; I:= gWCXPlugins.IndexOfName('b64'); if I < 0 then gWCXPlugins.Add('b64', 1, Folder + 'base64' + PathDelim + 'base64.wcx'); // Wdx plugins Folder:= '%commander_path%' + PathDelim + 'plugins' + PathDelim + 'wdx' + PathDelim; if gWdxPlugins.IndexOfName('deb_wdx') < 0 then begin gWdxPlugins.Add('deb_wdx', Folder + 'deb_wdx' + PathDelim + 'deb_wdx.wdx', 'EXT="DEB"'); end; if gWdxPlugins.IndexOfName('rpm_wdx') < 0 then begin gWdxPlugins.Add('rpm_wdx', Folder + 'rpm_wdx' + PathDelim + 'rpm_wdx.wdx', 'EXT="RPM"'); end; if gWdxPlugins.IndexOfName('audioinfo') < 0 then begin gWdxPlugins.Add(Folder + 'audioinfo' + PathDelim + 'audioinfo.wdx'); end; // Wfx plugins Folder:= '%commander_path%' + PathDelim + 'plugins' + PathDelim + 'wfx' + PathDelim; if gWFXPlugins.IndexOfName('FTP') < 0 then begin gWFXPlugins.Add('FTP', Folder + 'ftp' + PathDelim + 'ftp.wfx'); end; {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)} I:= gWFXPlugins.IndexOfName('Windows Network'); if I >= 0 then gWFXPlugins.Enabled[I]:= False; {$ENDIF} // Wlx plugins Folder:= '%commander_path%' + PathDelim + 'plugins' + PathDelim + 'wlx' + PathDelim; {$IF DEFINED(LINUX)} I:= gWlxPlugins.IndexOfName('wlxMplayer'); if I >= 0 then begin gWlxPlugins.GetWlxModule(I).FileName:= Folder + 'wlxmplayer' + PathDelim + 'wlxmplayer.wlx'; end; {$ENDIF} {$IF DEFINED(MSWINDOWS)} if gWlxPlugins.IndexOfName('richview') < 0 then begin gWlxPlugins.Add(Folder + 'richview' + PathDelim + 'richview.wlx'); end; if gWlxPlugins.IndexOfName('preview') < 0 then begin gWlxPlugins.Add(Folder + 'preview' + PathDelim + 'preview.wlx'); end; if gWlxPlugins.IndexOfName('wmp') < 0 then begin gWlxPlugins.Add(Folder + 'wmp' + PathDelim + 'wmp.wlx'); end; {$ENDIF} {$IF DEFINED(DARWIN)} if gWlxPlugins.IndexOfName('MacPreview') < 0 then begin gWlxPlugins.Add(Folder + 'MacPreview' + PathDelim + 'MacPreview.wlx'); end; {$ENDIF} end; function CheckPlugin(var FileName: String): Boolean; var PluginType: TBinaryType; begin {$IF DEFINED(CPU64)} if (StrEnds(FileName, '64') = False) and mbFileExists(FileName + '64') then begin FileName:= FileName + '64'; end; {$ENDIF} PluginType:= GetPluginBinaryType(FileName); case PluginType of PluginBinaryType: Exit(True); btUnknown: MessageDlg(Application.Title, rsMsgInvalidPlugin, mtError, [mbOK], 0, mbOK); else MessageDlg(Application.Title, Format(rsMsgInvalidPluginArchitecture, [ PluginBinaryTypeString[PluginType], LineEnding, PluginBinaryTypeString[PluginBinaryType] ]), mtError, [mbOK], 0, mbOK); end; Result:= False; end; function GetPluginBinaryType(const FileName: String): TBinaryType; var fsFileStream: TFileStreamEx; begin try fsFileStream:= TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try // Check Windows executable if fsFileStream.ReadWord = $5A4D then // 'MZ' begin fsFileStream.Seek(60, soBeginning); fsFileStream.Seek(fsFileStream.ReadDWord, soBeginning); if fsFileStream.ReadDWord = $4550 then // 'PE' begin fsFileStream.Seek(20, soCurrent); case fsFileStream.ReadWord of $10B: Exit(btPe32); // 32 bit $20B: Exit(btPe64); // 64 bit end; end; end; fsFileStream.Seek(0, soBeginning); // Check Unix executable if fsFileStream.ReadDWord = $464C457F then // 'ELF' begin case fsFileStream.ReadByte of 1: Exit(btElf32); // 32 bit 2: Exit(btElf64); // 64 bit end; end; fsFileStream.Seek(0, soBeginning); // Check Darwin executable case fsFileStream.ReadDWord of $feedface, $cefaedfe: Exit(btMacho32); // 32 bit $feedfacf, $cffaedfe: Exit(btMacho64); // 64 bit end; Result:= btUnknown; finally fsFileStream.Free; end; except Result:= btUnknown; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udragdropcocoa.pas����������������������������������������������������0000644�0001750�0000144�00000006641�14743153644�020731� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Drag&Drop operations for Cocoa. Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) 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 } unit uDragDropCocoa; {$mode objfpc}{$H+} {$modeswitch objectivec1} interface uses Classes, SysUtils, Controls, uDragDropEx; type TDragDropSourceCocoa = class(TDragDropSource) function RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; override; function DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; override; end; implementation uses CocoaAll, uMyDarwin; { ---------- TDragDropSourceCocoa ---------- } function TDragDropSourceCocoa.RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; begin inherited; // RequestDataEvent is not handled in Cocoa. Result := True; end; function TDragDropSourceCocoa.DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; var I: Integer; Window: NSWindow; DragIcon: NSImage; DragPoint: NSPoint; FileList: NSMutableArray; PasteBoard: NSPasteboard; begin Result := False; // Simulate drag-begin event. if Assigned(GetDragBeginEvent) then begin Result := GetDragBeginEvent()(); if Result = False then Exit; end; FileList:= NSMutableArray.arrayWithCapacity(FileNamesList.Count); for I:= 0 to FileNamesList.Count - 1 do begin FileList.addObject(StringToNSString(FileNamesList[I])); end; DragPoint.x:= ScreenStartPoint.X; DragPoint.y:= ScreenStartPoint.Y; Window:= NSApplication.sharedApplication.keyWindow; PasteBoard:= NSPasteboard.pasteboardWithName(NSDragPboard); PasteBoard.declareTypes_owner(NSArray.arrayWithObject(NSFileNamesPboardType), nil); PasteBoard.setPropertyList_forType(FileList, NSFileNamesPboardType); DragIcon:= NSWorkspace.sharedWorkspace.iconForFile(StringToNSString(FileNamesList[0])); Window.dragImage_at_offset_event_pasteboard_source_slideBack(DragIcon, DragPoint, NSZeroSize, nil, PasteBoard, Window, True); // Simulate drag-end event. if Assigned(GetDragEndEvent) then begin if Result = True then Result := GetDragEndEvent()() else GetDragEndEvent()() end; end; end. �����������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udragdropex.pas�������������������������������������������������������0000644�0001750�0000144�00000031615�14743153644�020260� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Interface unit for Drag&Drop to external applications. Copyright (C) 2009-2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } {en Be aware that raw HWND handles are used to register controls for drag&drop in the system. Some LCL's functions may destroy a control's handle and create a new one during the lifetime of that control, making drag&drop invalid. Override TWinControl.InitializeWnd and TWinControl.FinalizeWnd to handle registration/unregistration in each control. } unit uDragDropEx; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls; type TDropEffect = (DropNoEffect, DropCopyEffect, DropMoveEffect, DropLinkEffect, DropAskEffect); TDragDropStatus = (DragDropAborted, DragDropSuccessful, DragDropError); { Source events } { Dragging has started } TDragBeginEvent = function:Boolean of object; { Drag destination has requested data } TRequestDataEvent = function( // This is the same as given to DoDragDrop. const FileNamesList: TStringList; // MIME-type format in which target requested data, e.g. text/plain. MimeType: string; // Effect chosen by target (may not be final). DropEffect: TDropEffect):string of object; { Dragging has ended } TDragEndEvent = function:Boolean of object; { Target events } { Mouse entered into the control when dragging something } TDragEnterEvent = function( // Proposed drop effect by the source (can be changed by the target to inform the source). var DropEffect: TDropEffect; // Screen coordinates of mouse cursor. ScreenPoint: TPoint):Boolean of object; { Mouse moved inside the control when dragging something } TDragOverEvent = function( // Proposed drop effect by the source (can be changed by the target to inform the source). var DropEffect: TDropEffect; // Screen coordinates of mouse cursor. ScreenPoint: TPoint):Boolean of object; { Mouse button has been lifted causing a drop event } TDropEvent = function( // List of filenames given by the source. const FileNamesList: TStringList; // Drop effect chosen by the source. DropEffect: TDropEffect; // Screen coordinates of mouse cursor. ScreenPoint: TPoint):Boolean of object; { Mouse has left the control when dragging something } TDragLeaveEvent = function:Boolean of object; { Base class for external source } TDragDropSource = class(TObject) public constructor Create(SourceControl: TWinControl); virtual; destructor Destroy; override; function RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; virtual; procedure UnregisterEvents; virtual; function DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; // button that initiated dragging ScreenStartPoint: TPoint // mouse position in screen coords ): Boolean; virtual; function GetLastStatus: TDragDropStatus; function GetFileNamesList: TStringList; function GetDragBeginEvent : TDragBeginEvent; function GetRequestDataEvent: TRequestDataEvent; function GetDragEndEvent : TDragEndEvent; private FDragDropControl: TWinControl; FDragBeginEvent : TDragBeginEvent; FRequestDataEvent : TRequestDataEvent; FDragEndEvent : TDragEndEvent; protected FLastStatus: TDragDropStatus; FFileNamesList: TStringList; function GetControl: TWinControl; end; { Base class for external target } TDragDropTarget = class(TObject) public constructor Create(TargetControl: TWinControl); virtual; destructor Destroy; override; function RegisterEvents(DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; virtual; procedure UnregisterEvents; virtual; function GetDragEnterEvent: TDragEnterEvent; function GetDragOverEvent : TDragOverEvent; function GetDropEvent : TDropEvent; function GetDragLeaveEvent: TDragLeaveEvent; private FDragDropControl: TWinControl; FDragEnterEvent: TDragEnterEvent; FDragOverEvent : TDragOverEvent; FDropEvent : TDropEvent; FDragLeaveEvent: TDragLeaveEvent; protected function GetControl: TWinControl; end; { These functions return system-appropriate DragDrop... object. } function CreateDragDropSource(Control: TWinControl): TDragDropSource; function CreateDragDropTarget(Control: TWinControl): TDragDropTarget; { Returns True if external dragging is supported based on operating system and LCLWidgetType (compile-time) } function IsExternalDraggingSupported: Boolean; { Analyzes keyboard modifier keys (Shift, Ctrl, etc.) and mouse button nr and returns the appropriate drop effect. } function GetDropEffectByKeyAndMouse(ShiftState: TShiftState; MouseButton: TMouseButton; DefaultEffect: Boolean): TDropEffect; function GetDropEffectByKey(ShiftState: TShiftState; DefaultEffect: Boolean): TDropEffect; var { If set to True, then dragging is being transformed: internal to external or vice-versa. } TransformDragging : Boolean = False; { If set to True, then transforming from external back to internal dragging is enabled. } AllowTransformToInternal : Boolean = True; implementation {$IF DEFINED(MSWINDOWS)} uses uOleDragDrop; {$ELSEIF DEFINED(LCLCOCOA)} uses uDragDropCocoa; {$ELSEIF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} uses uDragDropGtk; {$ELSEIF DEFINED(LCLQT) and DEFINED(DARWIN)} uses uDragDropQt, uDragDropCocoa; {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6)} uses uDragDropQt; {$ENDIF} const DropDefaultEffect: array[Boolean] of TDropEffect = (DropMoveEffect, DropCopyEffect); { ---------- TDragDropSource ---------- } constructor TDragDropSource.Create(SourceControl: TWinControl); begin FDragDropControl := SourceControl; FDragBeginEvent := nil; FRequestDataEvent := nil; FDragEndEvent := nil; FFileNamesList := TStringList.Create; FLastStatus := DragDropSuccessful; end; destructor TDragDropSource.Destroy; begin UnregisterEvents; FDragDropControl := nil; if Assigned(FFileNamesList) then FreeAndNil(FFileNamesList); end; function TDragDropSource.GetControl:TWinControl; begin Result := FDragDropControl; end; function TDragDropSource.GetFileNamesList: TStringList; begin Result := FFileNamesList; end; function TDragDropSource.GetLastStatus: TDragDropStatus; begin Result := FLastStatus; end; function TDragDropSource.GetDragBeginEvent: TDragBeginEvent; begin Result := FDragBeginEvent; end; function TDragDropSource.GetRequestDataEvent: TRequestDataEvent; begin Result := FRequestDataEvent; end; function TDragDropSource.GetDragEndEvent: TDragEndEvent; begin Result := FDragEndEvent; end; function TDragDropSource.RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; begin FDragBeginEvent := DragBeginEvent; FRequestDataEvent := RequestDataEvent; FDragEndEvent := DragEndEvent; Result := False; end; procedure TDragDropSource.UnregisterEvents; begin FDragBeginEvent := nil; FRequestDataEvent := nil; FDragEndEvent := nil; end; function TDragDropSource.DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; begin FLastStatus := DragDropError; Result := False; end; { ---------- TDragDropTarget ---------- } constructor TDragDropTarget.Create(TargetControl: TWinControl); begin FDragDropControl := TargetControl; FDragEnterEvent := nil; FDragOverEvent := nil; FDropEvent := nil; FDragLeaveEvent := nil; end; destructor TDragDropTarget.Destroy; begin UnregisterEvents; FDragDropControl := nil; end; function TDragDropTarget.GetControl:TWinControl; begin Result := FDragDropControl; end; function TDragDropTarget.GetDragEnterEvent: TDragEnterEvent; begin Result := FDragEnterEvent; end; function TDragDropTarget.GetDragOverEvent: TDragOverEvent; begin Result := FDragOverEvent; end; function TDragDropTarget.GetDropEvent: TDropEvent; begin Result := FDropEvent; end; function TDragDropTarget.GetDragLeaveEvent: TDragLeaveEvent; begin Result := FDragLeaveEvent; end; function TDragDropTarget.RegisterEvents(DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; begin FDragEnterEvent := DragEnterEvent; FDragOverEvent := DragOverEvent; FDropEvent := DropEvent; FDragLeaveEvent := DragLeaveEvent; Result := False; end; procedure TDragDropTarget.UnregisterEvents; begin FDragEnterEvent := nil; FDragOverEvent := nil; FDropEvent := nil; FDragLeaveEvent := nil; end; { --------------------------------------------------------------------------- } function IsExternalDraggingSupported: Boolean; begin {$IF DEFINED(MSWINDOWS)} Result := True; {$ELSEIF DEFINED(LCLCOCOA)} Result := True; {$ELSEIF DEFINED(LCLGTK) OR DEFINED(LCLGTK2)} Result := True; {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6)} Result := True; {$ELSE} Result := False; {$ENDIF} end; function CreateDragDropSource(Control: TWinControl): TDragDropSource; begin {$IF DEFINED(MSWINDOWS)} Result := TDragDropSourceWindows.Create(Control); {$ELSEIF DEFINED(LCLCOCOA)} Result := TDragDropSourceCocoa.Create(Control); {$ELSEIF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} Result := TDragDropSourceGTK.Create(Control); {$ELSEIF DEFINED(LCLQT) and DEFINED(DARWIN)} Result := TDragDropSourceCocoa.Create(Control); {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6)} Result := TDragDropSourceQT.Create(Control); {$ELSE} Result := TDragDropSource.Create(Control); // Dummy {$ENDIF} end; function CreateDragDropTarget(Control: TWinControl): TDragDropTarget; begin {$IF DEFINED(MSWINDOWS)} Result := TDragDropTargetWindows.Create(Control); {$ELSEIF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} Result := TDragDropTargetGTK.Create(Control); {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6)} Result := TDragDropTargetQT.Create(Control); {$ELSE} Result := TDragDropTarget.Create(Control); // Dummy {$ENDIF} end; function GetDropEffectByKey(ShiftState: TShiftState; DefaultEffect: Boolean): TDropEffect; const ssBoth = [ssLeft, ssRight]; begin if (ssBoth * ShiftState = ssBoth) then Exit(DropDefaultEffect[not DefaultEffect]); ShiftState := [ssModifier, ssShift, ssAlt] * ShiftState; if ShiftState = [] then Result := DropDefaultEffect[DefaultEffect] // default to Copy when no keys pressed else if ShiftState = [ssShift] then Result := DropDefaultEffect[not DefaultEffect] else if ShiftState = [ssModifier] then Result := DropDefaultEffect[not DefaultEffect] else if ShiftState = [ssAlt] then Result := DropAskEffect else if ShiftState = [ssModifier, ssShift] then Result := DropLinkEffect else Result := DropNoEffect; // some other key combination pressed end; function GetDropEffectByKeyAndMouse(ShiftState: TShiftState; MouseButton: TMouseButton; DefaultEffect: Boolean): TDropEffect; begin case MouseButton of mbLeft: begin if ShiftState = [ssRight] then Result := DropDefaultEffect[not DefaultEffect] else Result := GetDropEffectByKey(ShiftState, DefaultEffect); end; mbMiddle: Result := DropAskEffect; mbRight: Result := DropAskEffect; end; end; end. �������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udragdropgtk.pas������������������������������������������������������0000644�0001750�0000144�00000036334�14743153644�020434� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Drag&Drop operations for GTK. } unit uDragDropGtk; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, uDragDropEx {$IF DEFINED(LCLGTK)} ,GLib, Gtk, Gdk {$ELSEIF DEFINED(LCLGTK2)} ,GLib2, Gtk2, Gdk2 {$ENDIF} ; type TDragDropSourceGTK = class(TDragDropSource) constructor Create(TargetControl: TWinControl); override; destructor Destroy; override; function RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; override; procedure UnregisterEvents; override; function DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; override; private procedure ConnectSignal(name: pgChar; func: Pointer); procedure DisconnectSignal(func: Pointer); end; TDragDropTargetGTK = class(TDragDropTarget) public constructor Create(TargetControl: TWinControl); override; destructor Destroy; override; function RegisterEvents(DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; override; procedure UnregisterEvents; override; private procedure ConnectSignal(name: pgChar; func: Pointer); procedure DisconnectSignal(func: Pointer); end; { Source events } function OnDragBegin(widget: PGtkWidget; context: PGdkDragContext; param: gPointer): GBoolean; cdecl; function OnDragDataGet(widget: PGtkWidget; context: PGdkDragContext; selection: PGtkSelectionData; info, time: guint; param: gPointer): GBoolean; cdecl; function OnDragDataDelete(widget: PGtkWidget; context: PGdkDragContext; param: gPointer): GBoolean; cdecl; function OnDragEnd(widget: PGtkWidget; context: PGdkDragContext; param: gPointer): GBoolean; cdecl; { Target events } function OnDragMotion(widget: PGtkWidget; context: PGdkDragContext; x, y: gint; time: guint; param: gPointer): GBoolean; cdecl; function OnDrop(widget: PGtkWidget; context: PGdkDragContext; x, y: gint; time: guint; param: gPointer): GBoolean; cdecl; function OnDataReceived(widget: PGtkWidget; context: PGdkDragContext; x, y: gint; selection: PGtkSelectionData; info, time: guint; param: gPointer): GBoolean; cdecl; function OnDragLeave(widget: PGtkWidget; context: PGdkDragContext; time: guint; param: gPointer): GBoolean; cdecl; function GtkActionToDropEffect(Action: TGdkDragAction):TDropEffect; function DropEffectToGtkAction(DropEffect: TDropEffect):TGdkDragAction; implementation uses uClipboard; // URI handling type // Order of these should be the same as in Targets array. TTargetId = (tidTextUriList, tidTextPlain); var Targets: array [0..1] of TGtkTargetEntry // 'info' field is a unique target id // Uri-list should be first so it can be catched before other targets, if available. = ((target: uriListMime ; flags: 0; info:LongWord(tidTextUriList)), (target: textPlainMime; flags: 0; info:LongWord(tidTextPlain))); // True, if the user is already dragging inside the target control. // Used to simulate drag-enter event in drag-motion handler. DragEntered: Boolean = False; { ---------- TDragDropSourceGTK ---------- } constructor TDragDropSourceGTK.Create(TargetControl: TWinControl); begin inherited Create(TargetControl); end; destructor TDragDropSourceGTK.Destroy; begin inherited; end; procedure TDragDropSourceGTK.ConnectSignal(name: pgChar; func: Pointer); begin gtk_signal_connect(PGtkObject(GetControl.Handle), name, TGtkSignalFunc(func), gPointer(Self)); // Pointer to class instance end; procedure TDragDropSourceGTK.DisconnectSignal(func: Pointer); begin gtk_signal_disconnect_by_func(PGtkObject(GetControl.Handle), TGtkSignalFunc(func), gPointer(Self)); end; function TDragDropSourceGTK.RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; begin inherited; GetControl.HandleNeeded; if GetControl.HandleAllocated = True then begin // We don't set up as a drag source here, as we handle it manually. ConnectSignal('drag_begin', @OnDragBegin); ConnectSignal('drag_data_get', @OnDragDataGet); ConnectSignal('drag_data_delete', @OnDragDataDelete); ConnectSignal('drag_end', @OnDragEnd); //'drag-failed'(widget, context, result:guint); Result := True; end; end; procedure TDragDropSourceGTK.UnregisterEvents; begin DisconnectSignal(@OnDragBegin); DisconnectSignal(@OnDragDataGet); DisconnectSignal(@OnDragDataDelete); DisconnectSignal(@OnDragEnd); inherited; end; function TDragDropSourceGTK.DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; var PList: PGtkTargetList; context: PGdkDragContext; ButtonNr: Integer; begin Result := False; FFileNamesList.Assign(FileNamesList); case MouseButton of mbLeft : ButtonNr := 1; mbMiddle: ButtonNr := 2; mbRight : ButtonNr := 3; else Exit; end; PList := gtk_target_list_new(@Targets[0], Length(Targets)); // Will be freed by GTK if Assigned(PList) then begin context := gtk_drag_begin( PGtkWidget(GetControl.Handle), PList, // Allowed effects GDK_ACTION_COPY or GDK_ACTION_MOVE or GDK_ACTION_LINK or GDK_ACTION_ASK, ButtonNr, nil // no event - we're starting manually ); if Assigned(context) then Result:=True; end; end; { ---------- TDragDropTargetGTK ---------- } constructor TDragDropTargetGTK.Create(TargetControl: TWinControl); begin inherited Create(TargetControl); end; destructor TDragDropTargetGTK.Destroy; begin inherited; end; procedure TDragDropTargetGTK.ConnectSignal(name: pgChar; func: Pointer); begin gtk_signal_connect(PGtkObject(GetControl.Handle), name, TGtkSignalFunc(func), gPointer(Self)); // Pointer to class instance end; procedure TDragDropTargetGTK.DisconnectSignal(func: Pointer); begin gtk_signal_disconnect_by_func(PGtkObject(GetControl.Handle), TGtkSignalFunc(func), gPointer(Self)); end; function TDragDropTargetGTK.RegisterEvents( DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; begin inherited; GetControl.HandleNeeded; if GetControl.HandleAllocated = True then begin // Set up as drag target. gtk_drag_dest_set( PGtkWidget(GetControl.Handle), // default handling of some signals GTK_DEST_DEFAULT_ALL, // What targets the drag source promises to supply. @Targets[0], Length(Targets), // Effects that target supports GDK_ACTION_COPY or GDK_ACTION_MOVE or GDK_ACTION_LINK or GDK_ACTION_ASK ); ConnectSignal('drag_motion', @OnDragMotion); ConnectSignal('drag_drop', @OnDrop); ConnectSignal('drag_data_received', @OnDataReceived); ConnectSignal('drag_leave', @OnDragLeave); Result := True; end; end; procedure TDragDropTargetGTK.UnregisterEvents; begin DisconnectSignal(@OnDragMotion); DisconnectSignal(@OnDrop); DisconnectSignal(@OnDataReceived); DisconnectSignal(@OnDragLeave); if GetControl.HandleAllocated = True then gtk_drag_dest_unset(PGtkWidget(GetControl.Handle)); inherited; end; { ---------- Source events ---------- } function OnDragBegin(widget: PGtkWidget; context: PGdkDragContext; param: gPointer): GBoolean; cdecl; var DragDropSource: TDragDropSourceGTK; begin DragDropSource := TDragDropSourceGTK(param); if Assigned(DragDropSource.GetDragBeginEvent) then Result := DragDropSource.GetDragBeginEvent()() else Result := True; end; function OnDragDataGet(widget: PGtkWidget; context: PGdkDragContext; selection: PGtkSelectionData; info, time: guint; param: gPointer): GBoolean; cdecl; var DragDropSource: TDragDropSourceGTK; dataString: string; begin DragDropSource := TDragDropSourceGTK(param); if (info < Low(Targets)) or (info > High(Targets)) then begin // Should not happen, as we didn't promise other targets in gtk_drag_begin. Result := False; Exit; end; if Assigned(DragDropSource.GetRequestDataEvent) then begin // Event has a handler assigned, so ask the control for data string. dataString := DragDropSource.GetRequestDataEvent()( DragDropSource.GetFileNamesList, Targets[info].target, // context^.action - the action chosen by the destination GtkActionToDropEffect(context^.action)); end else case TTargetId(info) of tidTextUriList: dataString := FormatUriList(DragDropSource.GetFileNamesList); tidTextPlain: dataString := FormatTextPlain(DragDropSource.GetFileNamesList); end; // gtk_selection_data_set makes a copy of passed data and zero-terminates it. gtk_selection_data_set(selection, gdk_atom_intern(Targets[info].target, gtk_true), Sizeof(dataString[1]) * 8, // nr of bits per unit (char) pguchar(@dataString[1]), Length(dataString)); Result := True; end; function OnDragDataDelete(widget: PGtkWidget; context: PGdkDragContext; param: gPointer): GBoolean; cdecl; var DragDropSource: TDragDropSourceGTK; begin DragDropSource := TDragDropSourceGTK(param); Result := True; end; function OnDragEnd(widget: PGtkWidget; context: PGdkDragContext; param: gPointer): GBoolean; cdecl; var DragDropSource: TDragDropSourceGTK; begin DragDropSource := TDragDropSourceGTK(param); if Assigned(DragDropSource.GetDragEndEvent) then Result := DragDropSource.GetDragEndEvent()() else Result := True; end; { ---------- Target events ---------- } function OnDragMotion(widget: PGtkWidget; context: PGdkDragContext; x, y: gint; time: guint; param: gPointer): GBoolean; cdecl; var DropEffect: TDropEffect; Action: TGdkDragAction; CursorPosition: TPoint; DragDropTarget: TDragDropTargetGTK; begin DragDropTarget := TDragDropTargetGTK(param); Result := True; // default to accepting drag movement // context^.suggested_action - the action suggested by the source // context^.actions - a bitmask of actions proposed by the source // when suggested_action is GDK_ACTION_ASK. DropEffect := GtkActionToDropEffect(context^.suggested_action); CursorPosition := DragDropTarget.GetControl.ClientToScreen(Point(X, Y)); if DragEntered = False then begin // This is the first time a cursor is moving inside the window // (possibly after a previous drag-leave event). DragEntered := True; if Assigned(DragDropTarget.GetDragEnterEvent) then Result := DragDropTarget.GetDragEnterEvent()(DropEffect, CursorPosition); end else begin if Assigned(DragDropTarget.GetDragOverEvent) then Result := DragDropTarget.GetDragOverEvent()(DropEffect, CursorPosition); end; if Result = True then Action := DropEffectToGtkAction(DropEffect) else Action := 0; // don't accept dragging // Reply with appropriate 'action'. gdk_drag_status(context, Action, time); end; function OnDataReceived(widget: PGtkWidget; context: PGdkDragContext; x, y: gint; selection: PGtkSelectionData; info, time: guint; param: gPointer): GBoolean; cdecl; var DragDropTarget: TDragDropTargetGTK; DropEffect: TDropEffect; FileNamesList: TStringList = nil; CursorPosition: TPoint; uriList: string; begin DragDropTarget := TDragDropTargetGTK(param); DropEffect := GtkActionToDropEffect(context^.suggested_action); CursorPosition := DragDropTarget.GetControl.ClientToScreen(Point(X, Y)); Result := False; if Assigned(DragDropTarget.GetDropEvent) and Assigned(selection) and Assigned(selection^.data) and (selection^.length > 0) // if selection length < 0 data is invalid then begin SetString(uriList, PChar(selection^.data), selection^.length); // 'info' denotes which target was matched by gtk_drag_get_data case TTargetId(info) of tidTextUriList: uriList := URIDecode(Trim(uriList)); tidTextPlain: // try decoding, as text/plain may also be percent-encoded uriList := URIDecode(Trim(uriList)); else Exit; // not what we hoped for end; try FileNamesList := ExtractFilenames(uriList); if Assigned(FileNamesList) and (FileNamesList.Count > 0) then Result := DragDropTarget.GetDropEvent()(FileNamesList, DropEffect, CursorPosition); finally if Assigned(FileNamesList) then FreeAndNil(FileNamesList); end; end; // gtk_drag_finish is called automatically, because // GTK_DEST_DEFAULT_DROP flag was passed to gtk_drag_dest_set. end; function OnDrop(widget: PGtkWidget; context: PGdkDragContext; x, y: gint; time: guint; param: gPointer): GBoolean; cdecl; var DragDropTarget: TDragDropTargetGTK; begin DragDropTarget := TDragDropTargetGTK(param); Result := True; end; function OnDragLeave(widget: PGtkWidget; context: PGdkDragContext; time: guint; param: gPointer): GBoolean; cdecl; var DragDropTarget: TDragDropTargetGTK; begin DragDropTarget := TDragDropTargetGTK(param); DragEntered := False; if Assigned(DragDropTarget.GetDragLeaveEvent) then Result := DragDropTarget.GetDragLeaveEvent()() else Result:= True; end; { ---------------------------------------------------------------------------- } function GtkActionToDropEffect(Action: TGdkDragAction):TDropEffect; begin case Action of GDK_ACTION_COPY: Result := DropCopyEffect; GDK_ACTION_MOVE: Result := DropMoveEffect; GDK_ACTION_LINK: Result := DropLinkEffect; GDK_ACTION_ASK : Result := DropAskEffect; else Result := DropNoEffect; end; end; function DropEffectToGtkAction(DropEffect: TDropEffect):TGdkDragAction; begin case DropEffect of DropCopyEffect: Result := GDK_ACTION_COPY; DropMoveEffect: Result := GDK_ACTION_MOVE; DropLinkEffect: Result := GDK_ACTION_LINK; DropAskEffect : Result := GDK_ACTION_ASK; else Result := 0; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udragdropqt.pas�������������������������������������������������������0000644�0001750�0000144�00000031037�14743153644�020266� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Drag&Drop operations for QT. } unit uDragDropQt; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, uDragDropEx, qtwidgets {$IF DEFINED(LCLQT)} , qt4 {$ELSEIF DEFINED(LCLQT5)} , qt5 {$ELSEIF DEFINED(LCLQT6)} , qt6 {$ENDIF} ; type TDragDropSourceQT = class(TDragDropSource) function RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; override; function DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; override; private function GetWidget: QWidgetH; end; TDragDropTargetQT = class(TDragDropTarget) public constructor Create(TargetControl: TWinControl); override; function RegisterEvents(DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; override; procedure UnregisterEvents; override; private FEventHook : QObject_hookH; function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; // called by QT function GetWidget: QWidgetH; function HasSupportedFormat(DropEvent: QDropEventH): Boolean; function OnDragEnter(DragEnterEvent: QDragEnterEventH): Boolean; function OnDragOver(DragMoveEvent: QDragMoveEventH): Boolean; function OnDrop(DropEvent: QDropEventH): Boolean; function OnDragLeave(DragLeaveEvent: QDragLeaveEventH): Boolean; end; function QtActionToDropEffect(Action: QtDropAction): TDropEffect; function DropEffectToQtAction(DropEffect: TDropEffect): QtDropAction; function QtDropEventPointToLCLPoint(const PDropEventPoint: PQtPoint): TPoint; implementation uses uClipboard, LCLIntf; const uriListMimeW : WideString = uriListMime; textPlainMimeW : WideString = textPlainMime; {$IF DEFINED(LCLQT5) or DEFINED(LCLQT6)} function QDropEvent_pos(handle: QDropEventH): PQtPoint; overload; const retval: TQtPoint = (x: 0; y: 0); begin Result:= @retval; QDropEvent_pos(handle, Result); end; {$ENDIF} function GetWidgetFromLCLControl(AWinControl: TWinControl): QWidgetH; inline; begin // Custom controls (TQtCustomControl) are created by LCL as // QAbstractScrollArea with a viewport (and two scrollbars). // We want the viewport to be the source/target of drag&drop, so we use // GetContainerWidget which returns the viewport widget for custom controls // and regular widget handle for others. Result := TQtWidget(AWinControl.Handle).GetContainerWidget; end; { ---------- TDragDropSourceQT ---------- } function TDragDropSourceQT.RegisterEvents(DragBeginEvent : uDragDropEx.TDragBeginEvent; RequestDataEvent: uDragDropEx.TRequestDataEvent; DragEndEvent : uDragDropEx.TDragEndEvent): Boolean; begin inherited; // RequestDataEvent is not handled in QT. Result := True; end; function TDragDropSourceQT.DoDragDrop(const FileNamesList: TStringList; MouseButton: TMouseButton; ScreenStartPoint: TPoint): Boolean; procedure SetMimeDataInFormat(MimeData: QMimeDataH; MimeType: WideString; DataString: AnsiString); var ByteArray: QByteArrayH; begin ByteArray := QByteArray_create(PAnsiChar(DataString)); try QMimeData_setData(MimeData, @MimeType, ByteArray); finally QByteArray_destroy(ByteArray); end; end; var DragObject: QDragH = nil; MimeData: QMimeDataH = nil; begin Result := False; // Simulate drag-begin event. if Assigned(GetDragBeginEvent) then begin Result := GetDragBeginEvent()(); if Result = False then Exit; end; DragObject := QDrag_create(GetWidget); // deleted automatically by QT try MimeData := QMimeData_create; QDrag_setMimeData(DragObject, MimeData); // MimeData owned by DragObject after this SetMimeDataInFormat(MimeData, uriListMimeW, FormatUriList(FileNamesList)); SetMimeDataInFormat(MimeData, textPlainMimeW, FormatTextPlain(FileNamesList)); except QDrag_destroy(DragObject); raise; end; // Start drag&drop operation (default to Copy action). QDrag_exec(DragObject, QtCopyAction or QtLinkAction or QtMoveAction, qtCopyAction); // Simulate drag-end event. if Assigned(GetDragEndEvent) then begin if Result = True then Result := GetDragEndEvent()() else GetDragEndEvent()() end; end; function TDragDropSourceQT.GetWidget: QWidgetH; begin Result := GetWidgetFromLCLControl(GetControl); end; { ---------- TDragDropTargetQT ---------- } constructor TDragDropTargetQT.Create(TargetControl: TWinControl); begin inherited; FEventHook := nil; end; function TDragDropTargetQT.RegisterEvents(DragEnterEvent: uDragDropEx.TDragEnterEvent; DragOverEvent : uDragDropEx.TDragOverEvent; DropEvent : uDragDropEx.TDropEvent; DragLeaveEvent: uDragDropEx.TDragLeaveEvent): Boolean; begin inherited; QWidget_setAcceptDrops(GetWidget, True); if Assigned(FEventHook) then QObject_hook_destroy(FEventHook); // Tap into target widget's events. FEventHook := QObject_hook_create(GetWidget); QObject_hook_hook_events(FEventHook, @EventFilter); Result := True; end; procedure TDragDropTargetQT.UnregisterEvents; begin QWidget_setAcceptDrops(GetWidget, False); if Assigned(FEventHook) then begin QObject_hook_destroy(FEventHook); FEventHook := nil; end; inherited; end; function TDragDropTargetQT.GetWidget: QWidgetH; begin Result := GetWidgetFromLCLControl(GetControl); end; function TDragDropTargetQT.HasSupportedFormat(DropEvent: QDropEventH): Boolean; var MimeData: QMimeDataH; begin MimeData := QDropEvent_mimeData(DropEvent); if Assigned(MimeData) then begin if QMimeData_hasFormat(mimedata, @urilistmimew) or QMimeData_hasFormat(mimedata, @textPlainMimeW) then Exit(True); end; Result := False; end; function TDragDropTargetQT.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; begin Result := False; // False means the event is not filtered out. case QEvent_type(Event) of QEventDragEnter: begin QEvent_accept(Event); OnDragEnter(QDragEnterEventH(Event)); end; QEventDragMove: begin QEvent_accept(Event); OnDragOver(QDragMoveEventH(Event)); end; QEventDrop: begin QEvent_accept(Event); OnDrop(QDropEventH(Event)); end; QEventDragLeave: begin QEvent_accept(Event); OnDragLeave(QDragLeaveEventH(Event)); end; // QEventDragResponse - used internally by QT end; end; function TDragDropTargetQT.OnDragEnter(DragEnterEvent: QDragEnterEventH): Boolean; var CursorPosition: TPoint; DropEffect: TDropEffect; DropEvent: QDropEventH; QtAction: QtDropAction; begin // QDragEnterEvent inherits from QDragMoveEvent, which inherits from QDropEvent. DropEvent := QDropEventH(DragEnterEvent); if not HasSupportedFormat(DropEvent) then begin QDropEvent_setDropAction(DropEvent, QtIgnoreAction); Result := False; end else if Assigned(GetDragEnterEvent) then begin DropEffect := QtActionToDropEffect(QDropEvent_proposedAction(DropEvent)); CursorPosition := QtDropEventPointToLCLPoint(QDropEvent_pos(DropEvent)); CursorPosition := GetControl.ClientToScreen(CursorPosition); Result := GetDragEnterEvent()(DropEffect, CursorPosition); if Result then QtAction := DropEffectToQtAction(DropEffect) else QtAction := QtIgnoreAction; QDropEvent_setDropAction(DropEvent, QtAction); end else begin QDropEvent_acceptProposedAction(DropEvent); Result := True; end; end; function TDragDropTargetQT.OnDragOver(DragMoveEvent: QDragMoveEventH): Boolean; var CursorPosition: TPoint; DropEffect: TDropEffect; DropEvent: QDropEventH; QtAction: QtDropAction; begin // QDragMoveEvent inherits from QDropEvent. DropEvent := QDropEventH(DragMoveEvent); if not HasSupportedFormat(DropEvent) then begin QDropEvent_setDropAction(DropEvent, QtIgnoreAction); Result := False; end else if Assigned(GetDragOverEvent) then begin DropEffect := QtActionToDropEffect(QDropEvent_proposedAction(DropEvent)); CursorPosition := QtDropEventPointToLCLPoint(QDropEvent_pos(DropEvent)); CursorPosition := GetControl.ClientToScreen(CursorPosition); Result := GetDragOverEvent()(DropEffect, CursorPosition); if Result then QtAction := DropEffectToQtAction(DropEffect) else QtAction := QtIgnoreAction; QDropEvent_setDropAction(DropEvent, QtAction); end else begin QDropEvent_acceptProposedAction(DropEvent); Result := True; end; end; function TDragDropTargetQT.OnDrop(DropEvent: QDropEventH): Boolean; function GetMimeDataInFormat(MimeData: QMimeDataH; MimeType: WideString): AnsiString; var ByteArray: QByteArrayH; Size: Integer; Data: PAnsiChar; begin if QMimeData_hasFormat(MimeData, @MimeType) then begin ByteArray := QByteArray_create(); try QMimeData_data(MimeData, ByteArray, @MimeType); Size := QByteArray_size(ByteArray); Data := QByteArray_data(ByteArray); if (Size > 0) and Assigned(Data) then SetString(Result, Data, Size); finally QByteArray_destroy(ByteArray); end; end else Result := ''; end; var DropAction: QtDropAction; DropEffect: TDropEffect; CursorPosition: TPoint; uriList: String; FileNamesList: TStringList = nil; MimeData: QMimeDataH; begin Result := False; // QDropEvent_possibleActions() returns all actions allowed by the source. // QDropEvent_proposedAction() is the action proposed by the source. DropAction := QDropEvent_dropAction(DropEvent); // action to be performed by the target DropEffect := QtActionToDropEffect(DropAction); CursorPosition := QtDropEventPointToLCLPoint(QDropEvent_pos(dropEvent)); CursorPosition := GetControl.ClientToScreen(CursorPosition); QDropEvent_setDropAction(DropEvent, QtIgnoreAction); // default to ignoring the drop MimeData := QDropEvent_mimeData(DropEvent); if Assigned(GetDropEvent) and Assigned(MimeData) then begin if QMimeData_hasFormat(MimeData, @uriListMimeW) then uriList := URIDecode(Trim(GetMimeDataInFormat(MimeData, uriListMimeW))) else if QMimeData_hasFormat(MimeData, @textPlainMimeW) then // try decoding, as text/plain may also be percent-encoded uriList := URIDecode(Trim(GetMimeDataInFormat(MimeData, textPlainMimeW))) else Exit; // reject the drop try FileNamesList := ExtractFilenames(uriList); if Assigned(FileNamesList) and (FileNamesList.Count > 0) then Result := GetDropEvent()(FileNamesList, DropEffect, CursorPosition); finally if Assigned(FileNamesList) then FreeAndNil(FileNamesList); end; QDropEvent_setDropAction(DropEvent, DropAction); // accept the drop end; end; function TDragDropTargetQT.OnDragLeave(DragLeaveEvent: QDragLeaveEventH): Boolean; begin if Assigned(GetDragLeaveEvent) then Result := GetDragLeaveEvent()() else Result := True; end; { ---------------------------------------------------------------------------- } function QtActionToDropEffect(Action: QtDropAction): TDropEffect; begin case Action of QtCopyAction: Result := DropCopyEffect; QtMoveAction: Result := DropMoveEffect; QtTargetMoveAction: Result := DropMoveEffect; QtLinkAction: Result := DropLinkEffect; else Result := DropNoEffect; end; end; function DropEffectToQtAction(DropEffect: TDropEffect): QtDropAction; begin case DropEffect of DropCopyEffect: Result := QtCopyAction; DropMoveEffect: Result := QtMoveAction; DropLinkEffect: Result := QtLinkAction; else Result := QtIgnoreAction; end; end; function QtDropEventPointToLCLPoint(const PDropEventPoint: PQtPoint): TPoint; begin if Assigned(PDropEventPoint) then begin if (PDropEventPoint^.x <> 0) or (PDropEventPoint^.y <> 0) then begin Result.X := PDropEventPoint^.x; Result.Y := PDropEventPoint^.y; Exit; end; end; GetCursorPos(Result); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/udrivewatcher.pas�����������������������������������������������������0000644�0001750�0000144�00000134235�14743153644�020612� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Enumerating and monitoring drives in the system. Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2010 Przemyslaw Nagay (cobines@gmail.com) 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, see <http://www.gnu.org/licenses/>. } unit uDriveWatcher; {$mode objfpc}{$H+} {$IFDEF BSD} {$IF not DEFINED(DARWIN)} {$DEFINE BSD_not_DARWIN} {$ENDIF} {$ENDIF} interface uses Classes, SysUtils, fgl, LCLType, uDrive; type TDriveWatcherEvent = (dweDriveAdded, dweDriveRemoved, dweDriveChanged); TDriveWatcherEventNotify = procedure(EventType: TDriveWatcherEvent; const ADrive: PDrive) of object; TDriveWatcherObserverList = specialize TFPGList<TDriveWatcherEventNotify>; TDriveWatcher = class class procedure Initialize(Handle: HWND); class procedure Finalize; class procedure AddObserver(Func: TDriveWatcherEventNotify); class procedure RemoveObserver(Func: TDriveWatcherEventNotify); class function GetDrivesList: TDrivesList; end; implementation uses {$IFDEF UNIX} Unix, DCConvertEncoding, uMyUnix, uDebug {$IFDEF BSD_not_DARWIN} , BSD, BaseUnix, StrUtils, FileUtil {$ENDIF} {$IFDEF LINUX} , uUDisks, uUDev, uMountWatcher, DCStrUtils, uOSUtils, FileUtil, uGVolume, DCOSUtils {$ENDIF} {$IFDEF DARWIN} , StrUtils, uMyDarwin, uDarwinFSWatch {$ENDIF} {$IFDEF HAIKU} , BaseUnix, DCHaiku {$ENDIF} {$ENDIF} {$IFDEF MSWINDOWS} uMyWindows, Windows, JwaDbt, LazUTF8, JwaWinNetWk, ShlObj, DCOSUtils, uDebug, uShlObjAdditional, JwaNative, uGlobs {$ENDIF} ; {$IFDEF LINUX} type { TFakeClass } TFakeClass = class public procedure OnMountWatcherNotify(Sender: TObject); procedure OnGVolumeNotify(Signal: TGVolumeSignal; ADrive: PDrive); procedure OnUDisksNotify(Reason: TUDisksMethod; const ObjectPath: String); end; {$ENDIF} {$IFDEF DARWIN} // Workarounds for FPC RTL Bug type TFixedStatfs = TDarwinStatfs; const MNT_DONTBROWSE = $00100000; type { TDarwinDriverWatcher } TDarwinDriverWatcher = class private _monitor: TSimpleDarwinFSWatcher; procedure handleEvent( event:TDarwinFSWatchEvent ); public constructor Create; destructor Destroy; override; end; {$ENDIF} {$IFDEF BSD_not_DARWIN} type TFixedStatfs = TStatFs; const {$warning Remove this two constants when they are added to FreePascal} NOTE_MOUNTED = $0008; NOTE_UMOUNTED = $0010; type TKQueueDriveEvent = procedure(Event: TDriveWatcherEvent); TKQueueDriveEventWatcher = class(TThread) private kq: Longint; Event: TDriveWatcherEvent; FErrorMsg: String; FOnError: TNotifyEvent; FOnDriveEvent: TKQueueDriveEvent; FFinished: Boolean; procedure RaiseErrorEvent; procedure RaiseDriveEvent; protected procedure Execute; override; procedure DoTerminate; override; public property ErrorMsg: String read FErrorMsg; property OnError: TNotifyEvent read FOnError write FOnError; property OnDriveEvent: TKQueueDriveEvent read FOnDriveEvent write FOnDriveEvent; constructor Create(); destructor Destroy; override; end; {$ENDIF} {$IFDEF HAIKU} type TMountPoint = class Path: String; Device: dev_t; Root: ino_t; end; TMountPoints = specialize TFPGObjectList<TMountPoint>; {$ENDIF} var FObservers: TDriveWatcherObserverList = nil; InitializeCounter: Integer = 0; {$IFDEF LINUX} FakeClass: TFakeClass = nil; MountWatcher: TMountWatcher = nil; {$ENDIF} {$IFDEF MSWINDOWS} OldWProc: WNDPROC; {$ENDIF} {$IFDEF DARWIN} DarwinDriverWatcher: TDarwinDriverWatcher; {$ENDIF} {$IFDEF BSD_not_DARWIN} KQueueDriveWatcher: TKQueueDriveEventWatcher; {$ENDIF} procedure DoDriveAdded(const ADrive: PDrive); var i: Integer; begin if Assigned(FObservers) then begin for i := 0 to FObservers.Count - 1 do FObservers[i](dweDriveAdded, ADrive); end; end; procedure DoDriveRemoved(const ADrive: PDrive); var i: Integer; begin if Assigned(FObservers) then begin for i := 0 to FObservers.Count - 1 do FObservers[i](dweDriveRemoved, ADrive); end; end; procedure DoDriveChanged(const ADrive: PDrive); var i: Integer; begin if Assigned(FObservers) then begin for i := 0 to FObservers.Count - 1 do FObservers[i](dweDriveChanged, ADrive); end; end; {$IFDEF DARWIN} { TDarwinDriverWatcher } procedure TDarwinDriverWatcher.handleEvent( event:TDarwinFSWatchEvent ); var drive: TDrive; begin Sleep( 1*1000 ); // wait so drive gets available in MacOSX drive.Path:= event.fullPath; if ecCreated in event.categories then begin DoDriveAdded( @drive ); end else if ecRemoved in event.categories then begin DoDriveRemoved( @drive ); end else if not event.fullPath.IsEmpty then begin DoDriveChanged( @drive ); end; end; constructor TDarwinDriverWatcher.Create; const VOLUME_PATH = '/Volumes'; begin Inherited; _monitor:= TSimpleDarwinFSWatcher.Create( VOLUME_PATH , @handleEvent ); end; destructor TDarwinDriverWatcher.Destroy; begin FreeAndNil( _monitor ); inherited Destroy; end; {$ENDIF} {$IFDEF MSWINDOWS} const WM_USER_MEDIACHANGED = WM_USER + 200; var SHChangeNotifyRegister: function(hwnd: HWND; fSources: Longint; fEvents: LONG; wMsg: UINT; cEntries: Longint; pshcne: PSHChangeNotifyEntry): ULONG; stdcall; function MyWndProc(hWnd: HWND; uiMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var ADrive: TDrive; AName: array[0..MAX_PATH] of WideChar; rgpidl: PLPITEMIDLIST absolute wParam; lpdb: PDEV_BROADCAST_HDR absolute lParam; lpdbv: PDEV_BROADCAST_VOLUME absolute lpdb; function GetDrivePath(UnitMask: ULONG): String; var DriveNum: Byte; DriveLetterOffset: Integer; begin if (gUpperCaseDriveLetter) then DriveLetterOffset := Ord('A') else begin DriveLetterOffset := Ord('a') end; for DriveNum:= 0 to 25 do begin if ((UnitMask shr DriveNum) and $01) <> 0 then Exit(AnsiChar(DriveNum + DriveLetterOffset) + ':\'); end; end; begin case uiMsg of WM_DEVICECHANGE: begin case wParam of DBT_DEVICEARRIVAL: begin if (lpdb^.dbch_devicetype <> DBT_DEVTYP_VOLUME) then DoDriveAdded(nil) else begin ADrive.Path:= GetDrivePath(lpdbv^.dbcv_unitmask); DoDriveAdded(@ADrive); end; end; DBT_DEVICEREMOVECOMPLETE: begin if (lpdb^.dbch_devicetype <> DBT_DEVTYP_VOLUME) then DoDriveRemoved(nil) else begin ADrive.Path:= GetDrivePath(lpdbv^.dbcv_unitmask); DoDriveRemoved(@ADrive); end; end; DBT_DEVNODES_CHANGED: begin if (lParam = 0) then DoDriveChanged(nil); end; end; end; WM_USER_MEDIACHANGED: begin case lParam of SHCNE_MEDIAINSERTED: begin if not SHGetPathFromIDListW(rgpidl^, AName) then DoDriveAdded(nil) else begin ADrive.Path:= UTF16ToUTF8(UnicodeString(AName)); DoDriveAdded(@ADrive); end; end; SHCNE_MEDIAREMOVED: begin if not SHGetPathFromIDListW(rgpidl^, AName) then DoDriveRemoved(nil) else begin ADrive.Path:= UTF16ToUTF8(UnicodeString(AName)); DoDriveRemoved(@ADrive); end; end; end; end; end; // case Result := CallWindowProc(OldWProc, hWnd, uiMsg, wParam, lParam); end; procedure SetMyWndProc(Handle : HWND); const SHCNRF_InterruptLevel = $0001; SHCNRF_ShellLevel = $0002; SHCNRF_RecursiveInterrupt = $1000; var AEntries: TSHChangeNotifyEntry; begin {$PUSH}{$HINTS OFF} OldWProc := WNDPROC(SetWindowLongPtrW(Handle, GWL_WNDPROC, LONG_PTR(@MyWndProc))); {$POP} if Assigned(SHChangeNotifyRegister) then begin if Succeeded(SHGetFolderLocation(Handle, CSIDL_DRIVES, 0, 0, AEntries.pidl)) then begin AEntries.fRecursive:= False; SHChangeNotifyRegister(Handle, SHCNRF_InterruptLevel or SHCNRF_ShellLevel or SHCNRF_RecursiveInterrupt, SHCNE_MEDIAINSERTED or SHCNE_MEDIAREMOVED, WM_USER_MEDIACHANGED, 1, @AEntries); end; end; end; {$ENDIF} {$IFDEF BSD_not_DARWIN} procedure KQueueDriveWatcher_OnDriveEvent(Event: TDriveWatcherEvent); begin case Event of dweDriveAdded: DoDriveAdded(nil); dweDriveRemoved: DoDriveRemoved(nil); end; { case } end; {$ENDIF} class procedure TDriveWatcher.Initialize(Handle: HWND); begin Inc(InitializeCounter); if InitializeCounter > 1 then // Already initialized. Exit; FObservers := TDriveWatcherObserverList.Create; {$IFDEF LINUX} FakeClass := TFakeClass.Create; if HasUdev then begin if uUDev.Initialize then uUDev.AddObserver(@FakeClass.OnUDisksNotify); end; DCDebug('Detecting mounts through /proc/self/mounts'); MountWatcher:= TMountWatcher.Create; MountWatcher.OnMountEvent:= @FakeClass.OnMountWatcherNotify; MountWatcher.Start; uGVolume.Initialize; uGVolume.AddObserver(@FakeClass.OnGVolumeNotify); {$ENDIF} {$IFDEF MSWINDOWS} SetMyWndProc(Handle); {$ENDIF} {$IFDEF DARWIN} DarwinDriverWatcher := TDarwinDriverWatcher.Create; {$ENDIF} {$IFDEF BSD_not_DARWIN} KQueueDriveWatcher := TKQueueDriveEventWatcher.Create(); KQueueDriveWatcher.OnDriveEvent := @KQueueDriveWatcher_OnDriveEvent; KQueueDriveWatcher.Start; {$ENDIF} end; class procedure TDriveWatcher.Finalize; begin Dec(InitializeCounter); if InitializeCounter <> 0 then // Don't finalize yet. Exit; {$IFDEF LINUX} if HasUdev then begin uUDev.RemoveObserver(@FakeClass.OnUDisksNotify); uUDev.Finalize; end; uGVolume.RemoveObserver(@FakeClass.OnGVolumeNotify); uGVolume.Finalize; FreeAndNil(MountWatcher); if Assigned(FakeClass) then FreeAndNil(FakeClass); {$ENDIF} {$IFDEF DARWIN} FreeAndNil( DarwinDriverWatcher ); {$ENDIF} {$IFDEF BSD_not_DARWIN} KQueueDriveWatcher.Terminate; FreeAndNil(KQueueDriveWatcher); {$ENDIF} if Assigned(FObservers) then FreeAndNil(FObservers); end; class procedure TDriveWatcher.AddObserver(Func: TDriveWatcherEventNotify); begin if FObservers.IndexOf(Func) < 0 then FObservers.Add(Func); end; class procedure TDriveWatcher.RemoveObserver(Func: TDriveWatcherEventNotify); begin FObservers.Remove(Func); end; {$IFDEF LINUX} function BeginsWithString(const patterns: array of string; const strings: array of string): Boolean; var i, j: Integer; begin for i := Low(strings) to High(strings) do begin for j := Low(patterns) to High(patterns) do if StrBegins(strings[i], patterns[j]) then Exit(True); end; Result := False; end; function IsPartOfString(const patterns: array of string; const str: string): Boolean; var I: Integer; begin for I := Low(patterns) to High(patterns) do if Pos(patterns[I], str) > 0 then Exit(True); Result := False; end; function UDisksGetDeviceInfo(const DeviceObjectPath: String; const Devices: TUDisksDevicesInfos; out DeviceInfo: TUDisksDeviceInfo): Boolean; var i: Integer; begin if Assigned(Devices) then begin for i := Low(Devices) to High(Devices) do begin if Devices[i].DeviceObjectPath = DeviceObjectPath then begin DeviceInfo := Devices[i]; Exit(True); end; end; Result := False; end else begin // Devices not supplied, retrieve info from UDev. Result := uUDev.GetDeviceInfo(DeviceObjectPath, DeviceInfo); end; end; procedure UDisksDeviceToDrive(const Devices: TUDisksDevicesInfos; const DeviceInfo: TUDisksDeviceInfo; out Drive: PDrive); var OwnerDevice: TUDisksDeviceInfo; begin New(Drive); with DeviceInfo do begin Drive^.DeviceId := DeviceFile; Drive^.DisplayName := DevicePresentationName; if DeviceIsMounted and (Length(DeviceMountPaths) > 0) then begin Drive^.Path := DeviceMountPaths[0]; if Drive^.DisplayName = EmptyStr then begin if Drive^.Path <> PathDelim then Drive^.DisplayName := ExtractFileName(Drive^.Path) else Drive^.DisplayName := PathDelim; end; if Drive^.DisplayName = IdUuid then begin Drive^.DisplayName := ExtractFileName(DeviceFile); end; end else begin Drive^.Path := EmptyStr; if Drive^.DisplayName = EmptyStr then begin if (IdLabel <> EmptyStr) then Drive^.DisplayName := IdLabel else Drive^.DisplayName := ExtractFileName(DeviceFile); end; end; Drive^.DriveLabel := IdLabel; Drive^.FileSystem := IdType; Drive^.DriveSize := StrToInt64Def(DeviceSize, 0) * 512; if DeviceIsPartition then begin if UDisksGetDeviceInfo(PartitionSlave, Devices, OwnerDevice) and OwnerDevice.DeviceIsRemovable then begin // Removable partition usually means pen-drive type. if BeginsWithString(['usb'], OwnerDevice.DriveConnectionInterface) then Drive^.DriveType := dtRemovableUsb else Drive^.DriveType := dtRemovable; end else Drive^.DriveType := dtHardDisk; end else if DeviceIsDrive then begin if BeginsWithString(['flash'], DriveMediaCompatibility) then Drive^.DriveType := dtFlash else if BeginsWithString(['floppy'], DriveMediaCompatibility) then Drive^.DriveType := dtFloppy else if BeginsWithString(['optical'], DriveMediaCompatibility) then Drive^.DriveType := dtOptical else if BeginsWithString(['usb'], DriveConnectionInterface) then Drive^.DriveType := dtRemovableUsb else Drive^.DriveType := dtUnknown; end else if DeviceIsSystemInternal then Drive^.DriveType := dtHardDisk else Drive^.DriveType := dtUnknown; Drive^.IsMediaAvailable := DeviceIsMediaAvailable; Drive^.IsMediaEjectable := DriveIsMediaEjectable; Drive^.IsMediaRemovable := DeviceIsRemovable; Drive^.IsMounted := DeviceIsMounted; Drive^.AutoMount := (DeviceAutomountHint = EmptyStr) or (DeviceAutomountHint = 'always'); end; // DriveSize is not correct when Optical drive isn't mounted (at least in Linux) with Drive^ do if (DriveType = dtOptical) and not IsMounted then DriveSize := 0; end; {$ENDIF} class function TDriveWatcher.GetDrivesList: TDrivesList; {$IF DEFINED(MSWINDOWS)} var Key: HKEY = 0; Drive : PDrive; dwResult: DWORD; DriveBits: DWORD; DriveNum: Integer; DrivePath: String; WinDriveType: UINT; nFile: TNetResourceW; OptionalColon: String; DriveLetter: AnsiChar; NetworkPathSize: DWORD; lpBuffer: Pointer = nil; nFileList: PNetResourceW; DriveLetterOffset: Integer; RegDrivePath: UnicodeString; dwCount, dwBufferSize: DWORD; hEnum: THandle = INVALID_HANDLE_VALUE; NetworkPath: array[0..MAX_PATH] of WideChar; begin if gUpperCaseDriveLetter then DriveLetterOffset := Ord('A') else begin DriveLetterOffset := Ord('a'); end; if gShowColonAfterDrive then OptionalColon := ':' else begin OptionalColon := EmptyStr; end; Result := TDrivesList.Create; { fill list } DriveBits := GetLogicalDrives; for DriveNum := 0 to 25 do begin if ((DriveBits shr DriveNum) and $1) = 0 then begin // Try to find in mapped network drives DriveLetter := AnsiChar(DriveNum + DriveLetterOffset); RegDrivePath := 'Network' + PathDelim + WideChar(DriveLetter); if RegOpenKeyExW(HKEY_CURRENT_USER, PWideChar(RegDrivePath), 0, KEY_READ, Key) = ERROR_SUCCESS then begin NetworkPathSize := MAX_PATH * SizeOf(WideChar); if RegQueryValueExW(Key, 'RemotePath', nil, nil, @NetworkPath, @NetworkPathSize) = ERROR_SUCCESS then begin New(Drive); Result.Add(Drive); ZeroMemory(Drive, SizeOf(TDrive)); with Drive^ do begin Path := DriveLetter + ':\'; DisplayName := DriveLetter + OptionalColon; DriveLabel := UTF16ToUTF8(UnicodeString(NetworkPath)); DriveType := dtNetwork; AutoMount := True; end; end; RegCloseKey(Key); end; Continue; end; DriveLetter := AnsiChar(DriveNum + DriveLetterOffset); DrivePath := DriveLetter + ':\'; WinDriveType := GetDriveType(PChar(DrivePath)); if WinDriveType = DRIVE_NO_ROOT_DIR then Continue; New(Drive); Result.Add(Drive); ZeroMemory(Drive, SizeOf(TDrive)); with Drive^ do begin DeviceId := EmptyStr; Path := DrivePath; DisplayName := DriveLetter + OptionalColon; DriveLabel := EmptyStr; FileSystem := EmptyStr; IsMediaAvailable := True; IsMediaEjectable := False; IsMediaRemovable := False; IsMounted := True; AutoMount := True; case WinDriveType of DRIVE_REMOVABLE: begin WinDriveType:= mbGetDriveType(DriveLetter); if (WinDriveType and FILE_FLOPPY_DISKETTE <> 0) then DriveType := dtFloppy else begin DriveType := dtFlash; IsMounted := mbDriveReady(DrivePath); end; IsMediaEjectable := True; IsMediaRemovable := True; end; DRIVE_FIXED: DriveType := dtHardDisk; DRIVE_REMOTE: DriveType := dtNetwork; DRIVE_CDROM: begin DriveType := dtOptical; IsMediaEjectable := True; IsMediaRemovable := True; end; DRIVE_RAMDISK: DriveType := dtRamDisk; else DriveType := dtUnknown; end; if IsMediaAvailable then begin case DriveType of dtFloppy: ; // Don't retrieve, it's slow. dtFlash, dtHardDisk: begin DriveLabel := mbGetVolumeLabel(Path, True); FileSystem := mbGetFileSystem(DrivePath); end; dtNetwork: DriveLabel := mbGetRemoteFileName(Path); else DriveLabel := mbGetVolumeLabel(Path, True); end; if DriveType in [dtFlash, dtHardDisk] then begin case mbDriveBusType(DriveLetter) of BusTypeUsb: DriveType := dtRemovableUsb; BusTypeSd, BusTypeMmc: DriveType := dtFlash; end; end; end; end; end; // Enumerate Terminal Services Disks if RemoteSession then try ZeroMemory(@nFile, SizeOf(TNetResourceW)); nFile.dwScope := RESOURCE_GLOBALNET; nFile.dwType := RESOURCETYPE_DISK; nFile.dwDisplayType := RESOURCEDISPLAYTYPE_SERVER; nFile.dwUsage := RESOURCEUSAGE_CONTAINER; nFile.lpRemoteName := '\\tsclient'; dwResult := WNetOpenEnumW(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, @nFile, hEnum); if (dwResult <> NO_ERROR) then Exit; dwCount := DWORD(-1); // 512 Kb must be enough dwBufferSize:= $80000; // Allocate output buffer GetMem(lpBuffer, dwBufferSize); // Enumerate all resources dwResult := WNetEnumResourceW(hEnum, dwCount, lpBuffer, dwBufferSize); if dwResult = ERROR_NO_MORE_ITEMS then Exit; if (dwResult <> NO_ERROR) then Exit; nFileList:= PNetResourceW(lpBuffer); for DriveNum := 0 to Int64(dwCount) - 1 do begin New(Drive); Result.Add(Drive); ZeroMemory(Drive, SizeOf(TDrive)); with Drive^ do begin Path := UTF16ToUTF8(UnicodeString(nFileList^.lpRemoteName)); DriveLabel := ExcludeTrailingBackslash(Path); DisplayName := PathDelim + UTF8LowerCase(ExtractFileName(DriveLabel)); DriveType := dtNetwork; IsMediaAvailable := True; IsMounted := True; AutoMount := True; end; Inc(nFileList); end; finally if (hEnum <> INVALID_HANDLE_VALUE) then dwResult := WNetCloseEnum(hEnum); if (dwResult <> NO_ERROR) and (dwResult <> ERROR_NO_MORE_ITEMS) then DCDebug(mbSysErrorMessage(dwResult)); if Assigned(lpBuffer) then FreeMem(lpBuffer); end; end; {$ELSEIF DEFINED(LINUX)} function CheckMountEntry(MountEntry: PMountEntry): Boolean; begin Result:= False; with MountEntry^ do begin if DesktopEnv = DE_FLATPAK then begin if (not StrBegins(mnt_dir, '/mnt/')) and (not StrBegins(mnt_dir, '/media/')) and (not StrBegins(mnt_dir, '/run/user/')) and (not StrBegins(mnt_dir, '/run/media/')) and (not StrBegins(mnt_dir, '/var/run/user/')) and (not StrBegins(mnt_dir, '/var/run/media/')) then Exit; end; // check filesystem if (mnt_fsname = 'proc') then Exit; // check mount dir if (mnt_dir = '') or (mnt_dir = '/') or (mnt_dir = 'none') or (mnt_dir = '/proc') or (StrBegins(mnt_dir, '/dev/')) or (StrBegins(mnt_dir, '/sys/')) or (StrBegins(mnt_dir, '/proc/')) or (StrBegins(mnt_dir, '/snap/')) or (StrPos(mnt_dir, '/snapd/') <> nil) or (StrBegins(ExtractFileName(mnt_dir), '.')) then Exit; // check file system type if (mnt_type = 'ignore') or (mnt_type = 'none') or (mnt_type = 'cgroup') or (mnt_type = 'cpuset') or (mnt_type = 'ramfs') or (mnt_type = 'tmpfs') or (mnt_type = 'proc') or (mnt_type = 'swap') or (mnt_type = 'sysfs') or (mnt_type = 'debugfs') or (mnt_type = 'devtmpfs') or (mnt_type = 'devpts') or (mnt_type = 'fusectl') or (mnt_type = 'securityfs') or (mnt_type = 'binfmt_misc') or (mnt_type = 'fuse.portal') or (mnt_type = 'fuse.gvfsd-fuse') or (mnt_type = 'fuse.gvfs-fuse-daemon') or (mnt_type = 'fuse.truecrypt') or (mnt_type = 'nfsd') or (mnt_type = 'usbfs') or (mnt_type = 'mqueue') or (mnt_type = 'configfs') or (mnt_type = 'hugetlbfs') or (mnt_type = 'selinuxfs') or (mnt_type = 'rpc_pipefs') then Exit; // check mount options if (StrPos(mnt_opts, 'bind') <> nil) or (StrPos(mnt_opts, 'x-gvfs-hide') <> nil) then Exit; end; Result:= True; end; function UDisksGetDeviceObjectByUUID(const UUID: String; const Devices: TUDisksDevicesInfos): String; var i: Integer; begin for i := Low(Devices) to High(Devices) do if Devices[i].IdUuid = UUID then Exit(Devices[i].DeviceObjectPath); Result := EmptyStr; end; function UDisksGetDeviceObjectByLabel(const DriveLabel: String; const Devices: TUDisksDevicesInfos): String; var i: Integer; begin for i := Low(Devices) to High(Devices) do if Devices[i].IdLabel = DriveLabel then Exit(Devices[i].DeviceObjectPath); Result := EmptyStr; end; function UDisksGetDeviceObjectByDeviceFile(const DeviceFile: String; const Devices: TUDisksDevicesInfos): String; var i: Integer; begin for i := Low(Devices) to High(Devices) do if Devices[i].DeviceFile = DeviceFile then Exit(Devices[i].DeviceObjectPath); Result := EmptyStr; end; var AddedDevices: TStringList = nil; AddedMountPoints: TStringList = nil; HaveUDisksDevices: Boolean = False; function CheckDevice(const Device: String): Boolean; begin // If UDisks is available name=value pair should have been handled, // so we are free to check the device name. Otherwise don't check it // if it is a known name=value pair. Result := HaveUDisksDevices or not (StrBegins(Device, 'UUID=') or StrBegins(Device, 'LABEL=')); end; // Checks if device on some mount point hasn't been added yet. function CanAddDevice(const Device, MountPoint: String): Boolean; var Idx: Integer; begin Idx := AddedMountPoints.IndexOf(MountPoint); Result := (Idx < 0) or (CheckDevice(Device) and CheckDevice(AddedDevices[Idx]) and (AddedDevices[Idx] <> Device)); end; function GetDrive(const DrivesList: TDrivesList; const Device, MountPoint: String): PDrive; var K: Integer; begin for K := 0 to DrivesList.Count - 1 do begin if (DrivesList[K]^.Path = MountPoint) or (DrivesList[K]^.DeviceId = Device) then Exit(DrivesList[K]); end; Result := nil; end; function GetStrMaybeQuoted(const s: string): string; var i: Integer; begin Result := ''; if Length(s) > 0 then begin if s[1] in ['"', ''''] then begin for i := Length(s) downto 2 do begin if s[i] = s[1] then Exit(Copy(s, 2, i-2)); end; end else Result := s; end; end; function IsDeviceMountedAtRoot(const UDisksDevice: TUDisksDeviceInfo): Boolean; var i: Integer; begin if UDisksDevice.DeviceIsMounted then begin for i := Low(UDisksDevice.DeviceMountPaths) to High(UDisksDevice.DeviceMountPaths) do if UDisksDevice.DeviceMountPaths[i] = PathDelim then Exit(True); end; Result := False; end; function UDisksGetDevice(const UDisksDevices: TUDisksDevicesInfos; var DeviceFile: String; out UDisksDeviceObject: String): Boolean; begin // Handle "/dev/", "UUID=" and "LABEL=" through UDisks if available. if StrBegins(DeviceFile, 'UUID=') then begin UDisksDeviceObject := UDisksGetDeviceObjectByUUID( GetStrMaybeQuoted(Copy(DeviceFile, 6, MaxInt)), UDisksDevices); if UDisksDeviceObject <> EmptyStr then DeviceFile := '/dev/' + ExtractFileName(UDisksDeviceObject); Result := True; end else if StrBegins(DeviceFile, 'LABEL=') then begin UDisksDeviceObject := UDisksGetDeviceObjectByLabel( GetStrMaybeQuoted(Copy(DeviceFile, 7, MaxInt)), UDisksDevices); if UDisksDeviceObject <> EmptyStr then DeviceFile := '/dev/' + ExtractFileName(UDisksDeviceObject); Result := True; end else if StrBegins(DeviceFile, 'PARTUUID=') then begin DeviceFile := mbReadAllLinks('/dev/disk/by-partuuid/' + GetStrMaybeQuoted(Copy(DeviceFile, 10, MaxInt))); if Length(DeviceFile) > 0 then UDisksDeviceObject := UDisksGetDeviceObjectByDeviceFile(DeviceFile, UDisksDevices); Result := True; end else if StrBegins(DeviceFile, 'PARTLABEL=') then begin DeviceFile := mbReadAllLinks('/dev/disk/by-partlabel/' + GetStrMaybeQuoted(Copy(DeviceFile, 11, MaxInt))); if Length(DeviceFile) > 0 then UDisksDeviceObject := UDisksGetDeviceObjectByDeviceFile(DeviceFile, UDisksDevices); Result := True; end else if StrBegins(DeviceFile, '/dev/') then begin DeviceFile := mbCheckReadLinks(DeviceFile); UDisksDeviceObject := UDisksGetDeviceObjectByDeviceFile(DeviceFile, UDisksDevices); Result := True; end else Result := False; end; const MntEntFileList: array[1..2] of PChar = (_PATH_MOUNTED, _PATH_FSTAB); var Drive : PDrive = nil; fstab: PIOFile; pme: PMountEntry; I: Integer; UpdateDrive: Boolean; UDisksDevices: TUDisksDevicesInfos; UDisksDevice: TUDisksDeviceInfo; UDisksDeviceObject: String; DeviceFile: String; MountPoint: String; HandledByUDisks: Boolean = False; begin Result := TDrivesList.Create; try AddedDevices := TStringList.Create; AddedMountPoints := TStringList.Create; if HasUdev then HaveUDisksDevices := uUDev.EnumerateDevices(UDisksDevices); // Storage devices have to be in mtab or fstab and reported by UDisks. for I:= Low(MntEntFileList) to High(MntEntFileList) do begin fstab:= setmntent(MntEntFileList[I],'r'); if not Assigned(fstab) then Continue; pme:= getmntent(fstab); while (pme <> nil) do begin if CheckMountEntry(pme) then begin DeviceFile := StrPas(pme^.mnt_fsname); MountPoint := CeSysToUtf8(StrPas(pme^.mnt_dir)); if MountPoint <> PathDelim then MountPoint := ExcludeTrailingPathDelimiter(MountPoint); if HaveUDisksDevices then begin HandledByUDisks := UDisksGetDevice(UDisksDevices, DeviceFile, UDisksDeviceObject); if HandledByUDisks then begin if CanAddDevice(DeviceFile, MountPoint) and UDisksGetDeviceInfo(UDisksDeviceObject, UDisksDevices, UDisksDevice) then begin if not UDisksDevice.DevicePresentationHide then begin UDisksDevice.DeviceIsMounted:= (I = 1); AddString(UDisksDevice.DeviceMountPaths, MountPoint); UDisksDeviceToDrive(UDisksDevices, UDisksDevice, Drive); end; end // Even if mounted device is not listed by UDisks add it anyway the standard way. else if I = 1 then // MntEntFileList[1] = _PATH_MOUNTED HandledByUDisks := False; // Else don't add the device if it's not listed by UDisks. end; end; // Add by entry in fstab/mtab. if not HandledByUDisks then begin DeviceFile := mbCheckReadLinks(DeviceFile); Drive := GetDrive(Result, DeviceFile, MountPoint); if (Drive = nil) then begin New(Drive); FillChar(Drive^, SizeOf(TDrive), 0); UpdateDrive := False; end else begin UpdateDrive := (Drive^.FileSystem = 'autofs'); if not UpdateDrive then Drive:= nil; end; if Assigned(Drive) then begin with Drive^ do begin DeviceId := DeviceFile; Path := MountPoint; if MountPoint <> PathDelim then DisplayName := ExtractFileName(Path) else DisplayName := PathDelim; DriveLabel := Path; FileSystem := StrPas(pme^.mnt_type); if IsPartOfString(['ISO9660', 'CDROM', 'CDRW', 'DVD', 'UDF'], UpperCase(FileSystem)) then // for external usb cdrom and dvd DriveType := dtOptical else if IsPartOfString(['ISO9660', 'CDROM', 'CDRW', 'DVD'], UpperCase(DeviceFile)) then DriveType := dtOptical else if IsPartOfString(['FLOPPY'], UpperCase(FileSystem)) then DriveType := dtFloppy else if IsPartOfString(['FLOPPY', '/DEV/FD'], UpperCase(DeviceFile)) then DriveType := dtFloppy else if IsPartOfString(['ZIP', 'USB', 'CAMERA'], UpperCase(FileSystem)) then DriveType := dtFlash else if IsPartOfString(['/MEDIA/', '/RUN/MEDIA/'], UpperCase(MountPoint)) then DriveType := dtFlash else if IsPartOfString(['NFS', 'SMB', 'NETW', 'CIFS'], UpperCase(FileSystem)) then DriveType := dtNetwork else DriveType := dtHardDisk; IsMediaAvailable:= True; IsMediaEjectable:= (DriveType = dtOptical); IsMediaRemovable:= DriveType in [dtFloppy, dtOptical, dtFlash]; // If drive from /etc/mtab then it is mounted IsMounted:= (MntEntFileList[I] = _PATH_MOUNTED); AutoMount:= True; end; if UpdateDrive then Drive:= nil; end; end; // If drive object has been created add it to the list. if Assigned(Drive) then begin Result.Add(Drive); Drive := nil; AddedDevices.Add(DeviceFile); AddedMountPoints.Add(MountPoint); {$IFDEF DEBUG} DCDebug('Adding drive "' + DeviceFile + '" with mount point "' + MountPoint + '"'); {$ENDIF} end; end // Add root drive in added list to skip it later else if HasUdev and (pme^.mnt_dir = PathDelim) then begin DeviceFile := StrPas(pme^.mnt_fsname); UDisksGetDevice(UDisksDevices, DeviceFile, UDisksDeviceObject); AddedDevices.Add(DeviceFile); AddedMountPoints.Add(PathDelim); end; pme:= getmntent(fstab); end; endmntent(fstab); end; if HaveUDisksDevices then begin for i := Low(UDisksDevices) to High(UDisksDevices) do begin // Add drives not having a partition table which are usually devices // with removable media like CDROM, floppy - they can be mounted. // Don't add drives with partition table because they cannot be mounted. // Don't add drives with ram and loop device because they cannot be mounted. // Add devices reported as "filesystem". if ((UDisksDevices[i].DeviceIsDrive and (not UDisksDevices[i].DeviceIsPartitionTable) and (BeginsWithString(['floppy', 'optical'], UDisksDevices[i].DriveMediaCompatibility)) and (UDisksDevices[i].IdType <> 'swap')) or (UDisksDevices[i].IdUsage = 'filesystem')) and (StrBegins(UDisksDevices[i].DeviceFile, '/dev/ram') = False) and (StrBegins(UDisksDevices[i].DeviceFile, '/dev/zram') = False) and (StrBegins(UDisksDevices[i].DeviceFile, '/dev/loop') = False) and (not UDisksDevices[i].DevicePresentationHide) then begin if (AddedDevices.IndexOf(UDisksDevices[i].DeviceFile) < 0) and (not IsDeviceMountedAtRoot(UDisksDevices[i])) then begin UDisksDeviceToDrive(UDisksDevices, UDisksDevices[i], Drive); Result.Add(Drive); Drive := nil; AddedDevices.Add(UDisksDevices[i].DeviceFile); AddedMountPoints.Add(EmptyStr); {$IFDEF DEBUG} DCDebug('Adding UDisks drive "' + UDisksDevices[i].DeviceFile + '"'); {$ENDIF} end; end; end; end; EnumerateVolumes(Result); finally if Assigned(AddedDevices) then AddedDevices.Free; if Assigned(AddedMountPoints) then AddedMountPoints.Free; if Assigned(Drive) then Dispose(Drive); end; end; {$ELSEIF DEFINED(BSD)} function GetDriveTypeFromDeviceOrFSType(const DeviceId, FSType: String): TDriveType; begin // using filesystem type if FSType = 'swap' then Result := dtUnknown else if FSType = 'zfs' then Result := dtHardDisk else if FSType = 'nfs' then Result := dtNetwork else if FSType = 'smbfs' then Result := dtNetwork else if FSType = 'cifs' then Result := dtNetwork {$IF DEFINED(DARWIN)} else if FSType = 'hfs' then Result := dtHardDisk else if FSType = 'apfs' then Result := dtHardDisk else if FSType = 'ntfs' then Result := dtHardDisk else if FSType = 'msdos' then Result := dtHardDisk else if FSType = 'exfat' then Result := dtHardDisk else if FSType = 'lifs' then Result := dtHardDisk else if FSType = 'macfuse' then Result := dtHardDisk else if FSType = 'ufsd_NTFS' then Result := dtHardDisk else if FSType = 'tuxera_ntfs' then Result := dtHardDisk else if FSType = 'fusefs_txantfs' then Result := dtHardDisk else if FSType = 'udf' then Result := dtOptical else if FSType = 'cd9660' then Result := dtOptical else if FSType = 'cddafs' then Result := dtOptical else if FSType = 'afpfs' then Result := dtNetwork else if FSType = 'webdav' then Result := dtNetwork {$ENDIF} // using device name else if AnsiStartsStr('/dev/ad', DeviceId) then Result := dtHardDisk else if AnsiStartsStr('/dev/acd', DeviceId) then Result := dtOptical // CD-ROM (IDE) else if AnsiStartsStr('/dev/da', DeviceId) then Result := dtFlash // USB else if AnsiStartsStr('/dev/cd', DeviceId) then Result := dtOptical // CD-ROM (SCSI) else if AnsiStartsStr('/dev/mcd', DeviceId) then Result := dtOptical // CD-ROM (other) else if AnsiStartsStr('/dev/fd', DeviceId) then Result := dtFloppy else if AnsiStartsStr('/dev/sa', DeviceId) then Result := dtUnknown // Tape (SCSI) else if AnsiStartsStr('/dev/ast', DeviceId) then Result := dtUnknown // Tape (IDE) else if AnsiStartsStr('/dev/fla', DeviceId) then Result := dtHardDisk // Flash drive else if AnsiStartsStr('/dev/aacd', DeviceId) or AnsiStartsStr('/dev/mlxd', DeviceId) or AnsiStartsStr('/dev/mlyd', DeviceId) or AnsiStartsStr('/dev/amrd', DeviceId) or AnsiStartsStr('/dev/idad', DeviceId) or AnsiStartsStr('/dev/idad', DeviceId) or AnsiStartsStr('/dev/twed', DeviceId) then Result := dtHardDisk else Result := dtUnknown; // devfs, nullfs, procfs, etc. end; const MAX_FS = 128; var drive: PDrive; fstab: PFSTab; fs: TFixedStatfs; fsList: array[0..MAX_FS] of TFixedStatfs; iMounted, iAdded, count: Integer; found: boolean; dtype: TDriveType; begin Result := TDrivesList.Create; fstab := getfsent(); while fstab <> nil do begin dtype := GetDriveTypeFromDeviceOrFSType(fstab^.fs_spec, fstab^.fs_vfstype); // only add known drive types and skip root directory if (dtype = dtUnknown) or (fstab^.fs_file = PathDelim) then begin fstab := getfsent(); Continue; end; { if } New(drive); Result.Add(drive); with drive^ do begin Path := CeSysToUtf8(fstab^.fs_file); DisplayName := ExtractFileName(Path); DriveLabel := Path; FileSystem := fstab^.fs_vfstype; DeviceId := fstab^.fs_spec; DriveType := dtype; IsMediaAvailable := false; IsMediaEjectable := false; IsMediaRemovable := false; IsMounted := false; AutoMount := true; end; { with } fstab := getfsent(); end; { while } endfsent(); count := getfsstat(@fsList, SizeOf(fsList), MNT_WAIT); for iMounted := 0 to count - 1 do begin fs := fsList[iMounted]; {$IF DEFINED(DARWIN)} if (fs.fflags and MNT_DONTBROWSE <> 0) then Continue; {$ENDIF} // check if already added using fstab found := false; for iAdded := 0 to Result.Count - 1 do begin if Result[iAdded]^.Path = fs.mountpoint then begin drive := Result[iAdded]; with drive^ do begin IsMounted := true; IsMediaAvailable := true; end; found := true; break; end; { if } end; { for } if found then continue; dtype := GetDriveTypeFromDeviceOrFSType( {$IF DEFINED(DARWIN)} fs.mntfromname {$ELSE} fs.mnfromname {$ENDIF}, fs.fstypename ); // only add known drive types and skip root directory if (dtype = dtUnknown) {$IFNDEF DARWIN}or (fs.mountpoint = PathDelim){$ENDIF} then Continue; New(drive); Result.Add(drive); with drive^ do begin Path := CeSysToUtf8(fs.mountpoint); DisplayName := ExtractFileName(Path); DriveLabel := Path; FileSystem := fs.fstypename; DeviceId := {$IF DEFINED(DARWIN)}fs.mntfromname{$ELSE}fs.mnfromname{$ENDIF}; DriveType := dtype; IsMediaAvailable := true; IsMediaEjectable := false; IsMediaRemovable := false; IsMounted := true; AutoMount := true; end; { with } {$IF DEFINED(DARWIN)} if (fs.mountpoint = PathDelim) then begin Drive^.DisplayName:= GetVolumeName(fs.mntfromname); if Length(Drive^.DisplayName) = 0 then Drive^.DisplayName:= 'System'; end; {$ENDIF} end; { for } end; {$ELSEIF DEFINED(HAIKU)} var dev: dev_t; DirPtr: pDir; Drive: PDrive; APath: String; APos: cint = 0; Index: Integer; fs_info: Tfs_info; PtrDirEnt: pDirent; Info: BaseUnix.Stat; MountPoint: TMountPoint; MountPoints: TMountPoints; begin Result := TDrivesList.Create; MountPoints:= TMountPoints.Create(True); // Haiku mounts drives to root directory DirPtr:= fpOpenDir(PAnsiChar('/')); if Assigned(DirPtr) then try PtrDirEnt:= fpReadDir(DirPtr^); while PtrDirEnt <> nil do begin if (PtrDirEnt^.d_name <> '..') and (PtrDirEnt^.d_name <> '.') then begin APath:= PathDelim + PtrDirEnt^.d_name; if fpLStat(APath, Info) = 0 then begin if fpS_ISDIR(Info.st_mode) then begin MountPoint:= TMountPoint.Create; MountPoint.Path:= APath; MountPoint.Device:= Info.st_dev; MountPoint.Root:= Info.st_ino; MountPoints.Add(MountPoint); end; end; end; PtrDirEnt:= fpReadDir(DirPtr^); end; finally fpCloseDir(DirPtr^); end; dev:= next_dev(@APos); while (dev >= 0) do begin if (fs_stat_dev(dev, @fs_info) >= 0) then begin if (fs_info.fsh_name <> 'devfs') then begin for Index:= 0 to MountPoints.Count - 1 do begin MountPoint:= MountPoints[Index]; if (MountPoint.Device = fs_info.dev) and (MountPoint.Root = fs_info.root) then begin New(Drive); Result.Add(Drive); with Drive^ do begin DeviceId := fs_info.device_name; Path := MountPoint.Path; DisplayName := ExtractFilename(Path); DriveLabel := fs_info.volume_name; FileSystem := fs_info.fsh_name; IsMediaAvailable := True; IsMediaEjectable := False; IsMediaRemovable := (fs_info.flags and B_FS_IS_REMOVABLE <> 0); IsMounted := True; AutoMount := True; end; Break; end; end; end; end; dev:= next_dev(@APos) end; MountPoints.Free; end; {$ELSE} begin Result := TDrivesList.Create; end; {$ENDIF} {$IFDEF LINUX} procedure TFakeClass.OnMountWatcherNotify(Sender: TObject); var ADrive: PDrive = nil; begin DoDriveChanged(ADrive); end; procedure TFakeClass.OnGVolumeNotify(Signal: TGVolumeSignal; ADrive: PDrive); begin try case Signal of GVolume_Added: DoDriveAdded(ADrive); GVolume_Removed: DoDriveRemoved(ADrive); GVolume_Changed: DoDriveChanged(ADrive); end; finally if Assigned(ADrive) then Dispose(ADrive); end; end; procedure TFakeClass.OnUDisksNotify(Reason: TUDisksMethod; const ObjectPath: String); var Result: Boolean; ADrive: PDrive = nil; DeviceInfo: TUDisksDeviceInfo; begin Result:= uUDev.GetDeviceInfo(ObjectPath, DeviceInfo); if Result then UDisksDeviceToDrive(nil, DeviceInfo, ADrive); try case Reason of UDisks_DeviceAdded: DoDriveAdded(ADrive); UDisks_DeviceRemoved: DoDriveRemoved(ADrive); UDisks_DeviceChanged: DoDriveChanged(ADrive); end; finally if Assigned(ADrive) then Dispose(ADrive); end; end; {$ENDIF} {$IFDEF BSD_not_DARWIN} { TKQueueDriveEventWatcher } procedure TKQueueDriveEventWatcher.RaiseErrorEvent; begin DCDebug(Self.ErrorMsg); if Assigned(Self.FOnError) then Self.FOnError(Self); end; procedure TKQueueDriveEventWatcher.RaiseDriveEvent; begin if Assigned(Self.FOnDriveEvent) then Self.FOnDriveEvent(Self.Event); end; procedure TKQueueDriveEventWatcher.Execute; const KQUEUE_ERROR = -1; var ke: TKEvent; begin try Self.kq := kqueue(); if Self.kq = KQUEUE_ERROR then begin Self.FErrorMsg := 'ERROR: kqueue()'; Synchronize(@Self.RaiseErrorEvent); exit; end; { if } try FillByte(ke, SizeOf(ke), 0); EV_SET(@ke, 1, EVFILT_FS, EV_ADD, 0, 0, nil); if kevent(kq, @ke, 1, nil, 0, nil) = KQUEUE_ERROR then begin Self.FErrorMsg := 'ERROR: kevent()'; Synchronize(@Self.RaiseErrorEvent); exit; end; { if } while not Terminated do begin FillByte(ke, SizeOf(ke), 0); if kevent(kq, nil, 0, @ke, 1, nil) = KQUEUE_ERROR then break; case ke.Filter of EVFILT_TIMER: // user triggered continue; EVFILT_FS: begin if (ke.FFlags and NOTE_MOUNTED <> 0) then begin Self.Event := dweDriveAdded; Synchronize(@Self.RaiseDriveEvent); end { if } else if (ke.FFlags and NOTE_UMOUNTED <> 0) then begin Self.Event := dweDriveRemoved; Synchronize(@Self.RaiseDriveEvent); end; { else if } end; end; { case } end; { while } finally FileClose(Self.kq); end; { try - finally } finally FFinished := True; end; { try - finally } end; procedure TKQueueDriveEventWatcher.DoTerminate; var ke: TKEvent; begin inherited DoTerminate; if Self.kq = -1 then Exit; FillByte(ke, SizeOf(ke), 0); EV_SET(@ke, 0, EVFILT_TIMER, EV_ADD or EV_ONESHOT, 0, 0, nil); kevent(Self.kq, @ke, 1, nil, 0, nil); end; constructor TKQueueDriveEventWatcher.Create(); begin Self.FreeOnTerminate := true; Self.FFinished := false; inherited Create(true); end; destructor TKQueueDriveEventWatcher.Destroy; begin if not Terminated then begin Self.Terminate; {$IF (fpc_version<2) or ((fpc_version=2) and (fpc_release<5))} If (MainThreadID=GetCurrentThreadID) then while not FFinished do CheckSynchronize(100); {$ENDIF} WaitFor; end; { if } end; {$ENDIF} {$IF DEFINED(MSWINDOWS)} initialization Pointer(SHChangeNotifyRegister):= GetProcAddress(GetModuleHandle('shell32.dll'), 'SHChangeNotifyRegister'); {$ENDIF} end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uearlyconfig.pas������������������������������������������������������0000644�0001750�0000144�00000003374�14743153644�020424� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uEarlyConfig; {$mode objfpc}{$H+} {$IF DEFINED(darwin)} {$DEFINE DARKWIN} {$ENDIF} interface uses Classes, SysUtils; var {$IFDEF DARKWIN} gAppMode: Integer = 1; {$ENDIF} gSplashForm: Boolean = True; procedure SaveEarlyConfig; implementation uses DCOSUtils, DCStrUtils, DCClassesUtf8, uSysFolders, uGlobsPaths; var AConfig: String; function GetEarlyConfig: String; var Index: Integer; begin for Index:= 1 to ParamCount do begin if StrBegins(ParamStr(Index), '--config-dir=') then begin Result:= Copy(ParamStr(Index), 14, MaxInt); Result:= IncludeTrailingBackslash(Result) + ApplicationName + ConfigExtension; Exit; end; end; if mbFileExists(gpGlobalCfgDir + ApplicationName + '.inf') then Result:= gpGlobalCfgDir + ApplicationName + ConfigExtension else begin Result:= IncludeTrailingBackslash(GetAppConfigDir) + ApplicationName + ConfigExtension; end; end; procedure Initialize; begin AConfig:= GetEarlyConfig; if mbFileExists(AConfig) then try with TStringListEx.Create do try LoadFromFile(AConfig); gSplashForm:= StrToBoolDef(Values['SplashForm'], gSplashForm); {$IFDEF DARKWIN} gAppMode:= StrToIntDef(Values['DarkMode'], gAppMode); {$ENDIF} finally Free; end; except // Skip end; end; procedure SaveEarlyConfig; begin AConfig:= GetEarlyConfig; ForceDirectories(ExtractFileDir(AConfig)); with TStringListEx.Create do try Add('SplashForm' + NameValueSeparator + BoolToStr(gSplashForm)); {$IFDEF DARKWIN} AddPair('DarkMode', IntToStr(gAppMode)); {$ENDIF} SaveToFile(AConfig); finally Free; end; end; initialization Initialize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/ufilecopyex.pas�������������������������������������������������������0000644�0001750�0000144�00000003650�14743153644�020266� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileCopyEx; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCOSUtils; const FILE_COPY_NO_BUFFERING = $01; type TFileCopyProgress = function(TotalBytes, DoneBytes: Int64; UserData: Pointer): LongBool; TFileCopyEx = function(const Source, Target: String; Options: UInt32; UpdateProgress: TFileCopyProgress; UserData: Pointer): LongBool; var FileCopyEx: TFileCopyEx = nil; CopyAttributesOptionEx: TCopyAttributesOptions = []; implementation {$IF DEFINED(MSWINDOWS)} uses Windows, DCWindows; type TCopyInfo = class UserData: Pointer; UpdateProgress: TFileCopyProgress; end; function Progress(TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred: LARGE_INTEGER; dwStreamNumber, dwCallbackReason: DWord; hSourceFile, hDestinationFile: THandle; lpdata: pointer): Dword; Stdcall; var ACopyInfo: TCopyInfo absolute lpData; begin if ACopyInfo.UpdateProgress(TotalFileSize.QuadPart, TotalBytesTransferred.QuadPart, ACopyInfo.UserData) then Result:= PROGRESS_CONTINUE else begin Result:= PROGRESS_CANCEL; end; end; function CopyFile(const Source, Target: String; Options: UInt32; UpdateProgress: TFileCopyProgress; UserData: Pointer): LongBool; var ACopyInfo: TCopyInfo; dwCopyFlags: DWORD = COPY_FILE_ALLOW_DECRYPTED_DESTINATION; begin ACopyInfo:= TCopyInfo.Create; ACopyInfo.UserData:= UserData; ACopyInfo.UpdateProgress:= UpdateProgress; if (Options and FILE_COPY_NO_BUFFERING <> 0) then begin if (Win32MajorVersion > 5) then dwCopyFlags:= dwCopyFlags or COPY_FILE_NO_BUFFERING; end; Result:= CopyFileExW(PWideChar(UTF16LongName(Source)), PWideChar(UTF16LongName(Target)), @Progress, ACopyInfo, nil, dwCopyFlags) <> 0; ACopyInfo.Free; end; initialization FileCopyEx:= @CopyFile; CopyAttributesOptionEx:= [caoCopyTimeEx, caoCopyAttrEx]; {$ENDIF} end. ����������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/ufilesystemwatcher.pas������������������������������������������������0000644�0001750�0000144�00000151315�14743153644�021663� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This is a thread-component sends an event when a change in the file system occurs. Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2011 Przemyslaw Nagay (cobines@gmail.com) 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, see <http://www.gnu.org/licenses/>. } unit uFileSystemWatcher; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLVersion {$IFDEF DARWIN} , uDarwinFSWatch {$ENDIF} ; //{$DEFINE DEBUG_WATCHER} type TFSWatchFilter = set of (wfFileNameChange, wfAttributesChange); TFSWatcherEventType = (fswFileCreated, fswFileChanged, fswFileDeleted, fswFileRenamed, fswSelfDeleted, fswUnknownChange); TFSWatcherEventTypes = set of TFSWatcherEventType; TFSFeatures = set of (fsfFlatView); TFSWatcherEventData = record Path: String; EventType: TFSWatcherEventType; FileName: String; // Valid for fswFileCreated, fswFileChanged, fswFileDeleted, fswFileRenamed NewFileName: String; // Valid for fswFileRenamed UserData: Pointer; {$IFDEF DARWIN} OriginalEvent: TDarwinFSWatchEvent; {$ENDIF} end; PFSWatcherEventData = ^TFSWatcherEventData; TFSWatcherEvent = procedure(const EventData: TFSWatcherEventData) of object; { TFileSystemWatcher } TFileSystemWatcher = class private class procedure CreateFileSystemWatcher; class procedure DestroyFileSystemWatcher; public {en Returns @true if watch has been successfully added or already exists. } class function AddWatch(aWatchPath: String; aWatchFilter: TFSWatchFilter; aWatcherEvent: TFSWatcherEvent; UserData: Pointer = nil): Boolean; class procedure RemoveWatch(aWatchPath: String; aWatcherEvent: TFSWatcherEvent); class procedure RemoveWatch(aWatcherEvent: TFSWatcherEvent); {$IFDEF DARWIN} class procedure UpdateWatch; {$ENDIF} class function CanWatch(const WatchPaths: array of String): Boolean; class function AvailableWatchFilter: TFSWatchFilter; class function Features: TFSFeatures; end; implementation uses LCLProc, LazUTF8, LazMethodList, uDebug, uExceptions, syncobjs, fgl, Forms {$IF DEFINED(MSWINDOWS)} , Windows, JwaWinNT, JwaWinBase, DCWindows, DCStrUtils, uGlobs, DCOSUtils, DCConvertEncoding {$ELSEIF DEFINED(LINUX)} , inotify, BaseUnix, FileUtil, DCConvertEncoding, DCUnix {$ELSEIF DEFINED(DARWIN)} , uFileView, uGlobs {$ELSEIF DEFINED(BSD)} , BSD, Unix, BaseUnix, UnixType, FileUtil, DCOSUtils {$ELSEIF DEFINED(HAIKU)} , DCConvertEncoding {$IF DEFINED(LCLQT5)} , Qt5 {$ELSEIF DEFINED(LCLQT6)} , Qt6 {$ENDIF} {$ENDIF}; {$IF DEFINED(UNIX) AND not DEFINED(DARWIN)} {$DEFINE UNIX_butnot_DARWIN} {$ENDIF} {$IF DEFINED(HAIKU) AND (DEFINED(LCLQT5) OR DEFINED(LCLQT6))} {$DEFINE HAIKUQT} {$ENDIF} {$if lcl_fullversion < 2030000} {$macro on} {$define SameMethod:= CompareMethods} {$endif} {$IF DEFINED(UNIX_butnot_DARWIN)} type {$IF DEFINED(HAIKUQT)} TNotifyHandle = QFileSystemWatcherH; {$ELSE} TNotifyHandle = THandle; {$ENDIF} {$ENDIF} {$IF DEFINED(MSWINDOWS)} const // For each outstanding ReadDirectoryW a buffer of this size will be allocated // by kernel, so this value should be rather small. READDIRECTORYCHANGESW_BUFFERSIZE = 4096; READDIRECTORYCHANGESW_DRIVE_BUFFERSIZE = 32768; var VAR_READDIRECTORYCHANGESW_BUFFERSIZE: DWORD = READDIRECTORYCHANGESW_BUFFERSIZE; CREATEFILEW_SHAREMODE: DWORD = FILE_SHARE_READ or FILE_SHARE_WRITE; type TOverlappedEx = packed record Overlapped: TOverlapped; OSWatch: Pointer; end; POverlappedEx = ^TOverlappedEx; function GetTargetPath(const Path: String): String; begin Result := mbReadAllLinks(Path); if Result = EmptyStr then Result := Path; end; function GetDriveOfPath(const Path: String): String; begin Result := ExtractFileDrive(GetTargetPath(Path)) + PathDelim; end; {$ENDIF} type TOSWatchObserver = class UserData: Pointer; WatcherEvent: TFSWatcherEvent; WatchFilter: TFSWatchFilter; {$IF DEFINED(MSWINDOWS)} RegisteredWatchPath: String; // Path that was registered to watch (for watching whole drive mode). TargetWatchPath: String; // What path is actually to be watched (for watching whole drive mode). {$ENDIF} end; TOSWatchObservers = specialize TFPGObjectList<TOSWatchObserver>; TOSWatch = class private {$IF NOT DEFINED(DARWIN)} FHandle: THandle; {$ENDIF} FObservers: TOSWatchObservers; FWatchFilter: TFSWatchFilter; FWatchPath: String; {$IF DEFINED(MSWINDOWS)} FOverlapped: TOverlappedEx; FBuffer: PByte; FNotifyFilter: DWORD; FReferenceCount: LongInt; FOldFileName: String; // for FILE_ACTION_RENAMED_OLD_NAME action {$ENDIF} {$IF DEFINED(UNIX_butnot_DARWIN)} FNotifyHandle: TNotifyHandle; {$ENDIF} {$IF NOT DEFINED(DARWIN)} procedure CreateHandle; procedure DestroyHandle; {$ENDIF} {$IF DEFINED(MSWINDOWS)} procedure QueueCancelRead; procedure QueueRead; procedure SetFilter(aWatchFilter: TFSWatchFilter); {$ENDIF} public constructor Create(const aWatchPath: String {$IFDEF UNIX_butnot_DARWIN}; aNotifyHandle: TNotifyHandle{$ENDIF}); reintroduce; destructor Destroy; override; {$IF not DEFINED(DARWIN)} procedure UpdateFilter; {$ENDIF} {$IF DEFINED(MSWINDOWS)} procedure Reference{$IFDEF DEBUG_WATCHER}(s: String){$ENDIF}; procedure Dereference{$IFDEF DEBUG_WATCHER}(s: String){$ENDIF}; {$ENDIF} {$IF not DEFINED(DARWIN)} property Handle: THandle read FHandle; {$ENDIF} property Observers: TOSWatchObservers read FObservers; property WatchPath: String read FWatchPath; end; TOSWatchs = specialize TFPGObjectList<TOSWatch>; { TFileSystemWatcherImpl } TFileSystemWatcherImpl = class(TThread) private FWatcherLock: syncobjs.TCriticalSection; FOSWatchers: TOSWatchs; {$IF DEFINED(UNIX_butnot_DARWIN)} FNotifyHandle: TNotifyHandle; {$ENDIF} {$IF DEFINED(DARWIN)} FDarwinFSWatcher: TDarwinFSWatcher; FWatcherSubdirs: TStringList; {$ENDIF} {$IF DEFINED(LINUX)} FEventPipe: TFilDes; {$ENDIF} FCurrentEventData: TFSWatcherEventData; FFinished: Boolean; {$IF DEFINED(HAIKUQT)} FFinishEvent: TSimpleEvent; FHook: QFileSystemWatcher_hookH; procedure DirectoryChanged(Path: PWideString); cdecl; {$ENDIF} {$IF DEFINED(DARWIN)} procedure handleFSEvent(event:TDarwinFSWatchEvent); {$ENDIF} procedure DoWatcherEvent; function GetWatchersCount: Integer; function GetWatchPath(var aWatchPath: String): Boolean; {$IF DEFINED(MSWINDOWS)} function IsPathObserved(Watch: TOSWatch; FileName: String): Boolean; {$ENDIF} {en Call only under FWatcherLock. } procedure RemoveObserverLocked(OSWatcherIndex: Integer; aWatcherEvent: TFSWatcherEvent); {en Call only under FWatcherLock. } procedure RemoveOSWatchLocked(Index: Integer); procedure RemoveOSWatch(Watch: TOSWatch); procedure TriggerTerminateEvent; protected procedure Execute; override; procedure ExecuteWatcher; {$IFDEF DARWIN} function isWatchSubdir(const path: String): Boolean; {$ENDIF} public constructor Create; destructor Destroy; override; procedure Terminate; function AddWatch(aWatchPath: String; aWatchFilter: TFSWatchFilter; aWatcherEvent: TFSWatcherEvent; UserData: Pointer = nil): Boolean; procedure RemoveWatch(aWatchPath: String; aWatcherEvent: TFSWatcherEvent); procedure RemoveWatch(aWatcherEvent: TFSWatcherEvent); {$IFDEF DARWIN} procedure UpdateWatch; {$ENDIF} property WatchersCount: Integer read GetWatchersCount; end; var FileSystemWatcher: TFileSystemWatcherImpl = nil; procedure SyncDoWatcherEvent; inline; begin // if Main Thread terminated, Synchronize() will never return if not Application.Terminated then FileSystemWatcher.Synchronize( @FileSystemWatcher.DoWatcherEvent ); end; { TFileSystemWatcher } class procedure TFileSystemWatcher.CreateFileSystemWatcher; begin if Assigned(FileSystemWatcher) and FileSystemWatcher.FFinished then // Thread finished prematurely maybe because of an error. // Destroy and recreate below. DestroyFileSystemWatcher; if not Assigned(FileSystemWatcher) then FileSystemWatcher := TFileSystemWatcherImpl.Create; end; class procedure TFileSystemWatcher.DestroyFileSystemWatcher; begin if Assigned(FileSystemWatcher) then begin DCDebug('Waiting for FileSystemWatcher thread'); FileSystemWatcher.Terminate; FileSystemWatcher.WaitFor; FreeAndNil(FileSystemWatcher); end; end; class function TFileSystemWatcher.AddWatch(aWatchPath: String; aWatchFilter: TFSWatchFilter; aWatcherEvent: TFSWatcherEvent; UserData: Pointer = nil): Boolean; begin CreateFileSystemWatcher; if Assigned(FileSystemWatcher) then Result := FileSystemWatcher.AddWatch(aWatchPath, aWatchFilter, aWatcherEvent, UserData) else Result := False; end; class procedure TFileSystemWatcher.RemoveWatch(aWatchPath: String; aWatcherEvent: TFSWatcherEvent); begin if Assigned(FileSystemWatcher) then begin FileSystemWatcher.RemoveWatch(aWatchPath, aWatcherEvent); if FileSystemWatcher.WatchersCount = 0 then DestroyFileSystemWatcher; end; end; class procedure TFileSystemWatcher.RemoveWatch(aWatcherEvent: TFSWatcherEvent); begin if Assigned(FileSystemWatcher) then begin FileSystemWatcher.RemoveWatch(aWatcherEvent); if FileSystemWatcher.WatchersCount = 0 then DestroyFileSystemWatcher; end; end; {$IFDEF DARWIN} class procedure TFileSystemWatcher.UpdateWatch; begin if Assigned(FileSystemWatcher) then begin FileSystemWatcher.UpdateWatch; end; end; {$ENDIF} class function TFileSystemWatcher.CanWatch(const WatchPaths: array of String): Boolean; {$IF DEFINED(MSWINDOWS)} var Index: Integer; DrivePath: UnicodeString; begin for Index:= Low(WatchPaths) to High(WatchPaths) do begin if (Pos('\\', WatchPaths[Index]) = 1) then Exit(False); DrivePath:= UnicodeString(Copy(WatchPaths[Index], 1, 3)); if GetDriveTypeW(PWideChar(DrivePath)) = DRIVE_REMOTE then Exit(False); end; Result:= True; end; {$ELSE} begin Result:= True; end; {$ENDIF} class function TFileSystemWatcher.AvailableWatchFilter: TFSWatchFilter; begin Result := [wfFileNameChange {$IF NOT DEFINED(HAIKUQT)} , wfAttributesChange {$ENDIF} ]; end; class function TFileSystemWatcher.Features: TFSFeatures; begin Result := [ {$IF DEFINED(DARWIN)} fsfFlatView {$ENDIF} ]; end; // ---------------------------------------------------------------------------- procedure ShowError(const sErrMsg: String); begin DCDebug('FSWatcher: ' + sErrMsg + ': (' + IntToStr(GetLastOSError) + ') ' + SysErrorMessage(GetLastOSError)); end; {$IF DEFINED(MSWINDOWS)} procedure NotifyRoutine(dwErrorCode: DWORD; dwNumberOfBytes: DWORD; Overlapped: LPOVERLAPPED); stdcall; forward; function StartReadDirectoryChanges(Watch: TOSWatch): Boolean; begin {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: ReadChanges for ', Watch.FWatchPath); {$ENDIF} if Watch.Handle <> feInvalidHandle then begin Result := ReadDirectoryChangesW( Watch.Handle, Watch.FBuffer, VAR_READDIRECTORYCHANGESW_BUFFERSIZE, gWatcherMode = fswmWholeDrive, Watch.FNotifyFilter, nil, LPOVERLAPPED(@Watch.FOverlapped), @NotifyRoutine) or // ERROR_IO_PENDING is a confirmation that the I/O operation has started. (GetLastError = ERROR_IO_PENDING); if Result then Watch.Reference{$IFDEF DEBUG_WATCHER}('StartReadDirectoryChanges'){$ENDIF} else begin // ERROR_INVALID_HANDLE will be when handle was destroyed // just before the call to ReadDirectoryChangesW. if GetLastError <> ERROR_INVALID_HANDLE then ShowError('ReadDirectoryChangesW error'); end; end else Result := False; end; procedure ProcessFileNotifyInfo(Watch: TOSWatch; dwBytesReceived: DWORD); var wFilename: Widestring; fnInfo: PFILE_NOTIFY_INFORMATION; begin with FileSystemWatcher do begin FCurrentEventData.Path := Watch.WatchPath; if dwBytesReceived = 0 then begin {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Process watch ', hexStr(Watch), ': Buffer overflowed. Some events happened though.'); {$ENDIF} // Buffer was not large enough to store all events. In this case it is only // known that something has changed but all specific events have been lost. FCurrentEventData.EventType := fswUnknownChange; FCurrentEventData.FileName := EmptyStr; FCurrentEventData.NewFileName := EmptyStr; SyncDoWatcherEvent; Exit; end; fnInfo := @Watch.FBuffer[0]; // FCurrentEventData can be accessed safely because only one ProcessFileNotifyInfo // is called at a time due to completion routines being in a queue. while True do begin SetString(wFilename, PWideChar(@fnInfo^.FileName), fnInfo^.FileNameLength div SizeOf(WideChar)); FCurrentEventData.NewFileName := EmptyStr; case fnInfo^.Action of FILE_ACTION_ADDED: begin FCurrentEventData.FileName := UTF16ToUTF8(wFilename); FCurrentEventData.EventType := fswFileCreated; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Process watch ', hexStr(Watch), ': Created file ', IncludeTrailingPathDelimiter(Watch.WatchPath) + FCurrentEventData.FileName); {$ENDIF} end; FILE_ACTION_REMOVED: begin FCurrentEventData.FileName := UTF16ToUTF8(wFilename); FCurrentEventData.EventType := fswFileDeleted; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Process watch ', hexStr(Watch), ': Deleted file ', IncludeTrailingPathDelimiter(Watch.WatchPath) + FCurrentEventData.FileName); {$ENDIF} end; FILE_ACTION_MODIFIED: begin FCurrentEventData.FileName := UTF16ToUTF8(wFilename); FCurrentEventData.EventType := fswFileChanged; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Process watch ', hexStr(Watch), ': Modified file ', IncludeTrailingPathDelimiter(Watch.WatchPath) + FCurrentEventData.FileName); {$ENDIF} end; FILE_ACTION_RENAMED_OLD_NAME: begin Watch.FOldFileName := UTF16ToUTF8(wFilename); {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Process watch ', hexStr(Watch), ': Rename from ', IncludeTrailingPathDelimiter(Watch.WatchPath) + FCurrentEventData.FileName); {$ENDIF} end; FILE_ACTION_RENAMED_NEW_NAME: begin FCurrentEventData.FileName := Watch.FOldFileName; FCurrentEventData.NewFileName := UTF16ToUTF8(wFilename); FCurrentEventData.EventType := fswFileRenamed; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Process watch ', hexStr(Watch), ': Rename to ', IncludeTrailingPathDelimiter(Watch.WatchPath) + FCurrentEventData.FileName); {$ENDIF} end; else begin FCurrentEventData.EventType := fswUnknownChange; FCurrentEventData.FileName := EmptyStr; {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: Process watch ', hexStr(Watch), ': Action ', fnInfo^.Action, ' for ', IncludeTrailingPathDelimiter(Watch.WatchPath) + FCurrentEventData.FileName]); {$ENDIF} end; end; if (fnInfo^.Action <> FILE_ACTION_RENAMED_OLD_NAME) and ((gWatcherMode <> fswmWholeDrive) or IsPathObserved(Watch, FCurrentEventData.FileName)) then SyncDoWatcherEvent; if fnInfo^.NextEntryOffset = 0 then Break else fnInfo := PFILE_NOTIFY_INFORMATION(PByte(fnInfo) + fnInfo^.NextEntryOffset); end; end; end; procedure NotifyRoutine(dwErrorCode: DWORD; dwNumberOfBytes: DWORD; Overlapped: LPOVERLAPPED); stdcall; var Watch: TOSWatch; bReadStarted: Boolean = False; begin Watch := TOSWatch(POverlappedEx(Overlapped)^.OSWatch); {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: NotifyRoutine for watch ', hexStr(Watch), ' bytes=', dwNumberOfBytes, ' code=', dwErrorCode, ' handle=', Integer(Watch.Handle)]); {$ENDIF} case dwErrorCode of ERROR_SUCCESS: begin if Watch.FHandle <> feInvalidHandle then begin ProcessFileNotifyInfo(Watch, dwNumberOfBytes); bReadStarted := StartReadDirectoryChanges(Watch); end else begin {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: NotifyRoutine Handle destroyed, not starting Read'); {$ENDIF}; end; end; ERROR_OPERATION_ABORTED: begin // I/O operation has been cancelled to change parameters. {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: NotifyRoutine aborted, will restart'); {$ENDIF} bReadStarted := StartReadDirectoryChanges(Watch); end; ERROR_ACCESS_DENIED: begin // Most probably handle has been closed or become invalid. {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: NotifyRoutine ERROR_ACCESS_DENIED watch=', hexStr(Watch)]); {$ENDIF} end; else begin DCDebug(['FSWatcher: NotifyRoutine error=', dwErrorCode]); end; end; if not bReadStarted then begin if Watch.Handle <> feInvalidHandle then // This will destroy the handle. FileSystemWatcher.RemoveOSWatch(Watch); // If Handle = feInvalidHandle that means Watch has already been // removed from FileSystemWatcher by main thread. end; Watch.Dereference{$IFDEF DEBUG_WATCHER}('NotifyRoutine'){$ENDIF}; {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: NotifyRoutine for watch ', hexStr(Watch), ' done']); {$ENDIF} end; procedure ReadChangesProc(dwParam: ULONG_PTR); stdcall; var Watch: TOSWatch absolute dwParam; begin {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: ReadChangesProc for watch ', hexStr(Watch)); {$ENDIF} if not StartReadDirectoryChanges(Watch) then begin if Watch.Handle <> feInvalidHandle then FileSystemWatcher.RemoveOSWatch(Watch); end; Watch.Dereference{$IFDEF DEBUG_WATCHER}('ReadChangesProc'){$ENDIF}; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: ReadChangesProc done for watch ', hexStr(Watch)); {$ENDIF} end; procedure CancelReadChangesProc(dwParam: ULONG_PTR); stdcall; var Watch: TOSWatch absolute dwParam; begin {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: CancelReadChangesProc for watch ', hexStr(Watch), ' handle ', Integer(Watch.Handle)]); {$ENDIF} // CancelIo will cause the completion routine to be called with ERROR_OPERATION_ABORTED. // Must be called from the same thread which started the I/O operation. if CancelIo(Watch.Handle) = False then begin if GetLastOSError <> ERROR_INVALID_HANDLE then ShowError('CancelReadChangesProc: CancelIo error'); end; Watch.Dereference{$IFDEF DEBUG_WATCHER}('CancelReadChangesProc'){$ENDIF}; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: CancelReadChangesProc done for watch ', hexStr(Watch)); {$ENDIF} end; procedure TerminateProc(dwParam: ULONG_PTR); stdcall; begin // This procedure does nothing. Simply queueing and executing it will cause // SleepEx to exit if there were no other APCs in the queue. end; {$ENDIF} { TFileSystemWatcherImpl } procedure TFileSystemWatcherImpl.Execute; begin DCDebug('FileSystemWatcher thread starting'); try try ExecuteWatcher; except on e: Exception do HandleException(e, Self); end; finally FFinished := True; DCDebug('FileSystemWatcher thread finished'); end; end; procedure TFileSystemWatcherImpl.ExecuteWatcher; {$IF DEFINED(MSWINDOWS)} begin while not Terminated do begin {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: SleepEx (', FOSWatchers.Count, ' watches)']); {$ENDIF} // Contrary to documentation: // SleepEx does not return until all APCs (including I/O completion routines) // in queue are called. Then it returns with WAIT_IO_COMPLETION. // Therefore there is no need to artificially flush queue. SleepEx(INFINITE, True); end; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: SleepEx loop done'); {$ENDIF} end; {$ELSEIF DEFINED(LINUX)} const // Buffer size passed to read() must be at least the size of the first event // to be read from the file descriptor, otherwise Invalid Parameter is returned. // Event record size is variable, we use maximum possible for a single event. // Usually it is big enough so that multiple events can be read with single read(). // The 'name' field is always padded up to multiple of 16 bytes with NULLs. buffer_size = (sizeof(inotify_event) + MAX_PATH) * 8; var bytes_to_parse, p, k, i: Integer; buf: PChar = nil; ev, v: pinotify_event; fds: array[0..1] of tpollfd; ret: cint; begin if (FNotifyHandle = feInvalidHandle) or (FEventPipe[0] = -1) or (FEventPipe[1] = -1) then Exit; try buf := GetMem(buffer_size); // set file descriptors fds[0].fd:= FEventPipe[0]; fds[0].events:= POLLIN; fds[1].fd:= FNotifyHandle; fds[1].events:= POLLIN; while not Terminated do begin // wait for events repeat ret:= fpPoll(@fds[0], Length(fds), -1); until (ret <> -1) or (fpGetErrNo <> ESysEINTR); if ret = -1 then begin ShowError('fpPoll() failed'); Exit; end; { if } if (fds[0].revents and POLLIN <> 0) then begin // clear pipe while FileRead(FEventPipe[0], buf^, 1) <> -1 do; end; { if } if (fds[1].revents and POLLIN = 0) then // inotify handle didn't change, so user triggered Continue; // Read events. bytes_to_parse := FileRead(FNotifyHandle, buf^, buffer_size); if bytes_to_parse = -1 then begin ShowError('read(): failed'); Continue; end; { if } // parse events and print them p := 0; while p < bytes_to_parse do begin ev := pinotify_event(buf + p); {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Read event, mask %s, name %s', [HexStr(ev^.mask, 8), StrPas(PChar(@ev^.name))]); {$ENDIF}; for i := 0 to FOSWatchers.Count - 1 do begin if ev^.wd = FOSWatchers[i].Handle then begin with FCurrentEventData do begin Path := FOSWatchers[i].WatchPath; FileName := StrPas(PChar(@ev^.name)); NewFileName := EmptyStr; // IN_MOVED_FROM is converted to FileDelete. // IN_MOVED_TO is converted to FileCreate. // There is no guarantee we will receive as sequence of // IN_MOVED_FROM, IN_MOVED_TO as the events are only sent // if the source and destination directories respectively // are being watched. if (ev^.mask and (IN_IGNORED or IN_Q_OVERFLOW)) <> 0 then begin // Ignore this event. Break; end else if (ev^.mask and (IN_ACCESS or IN_MODIFY or IN_ATTRIB or IN_CLOSE or IN_OPEN or IN_CLOSE_WRITE or IN_CLOSE_NOWRITE)) <> 0 then begin EventType := fswFileChanged; end else if (ev^.mask and IN_CREATE) <> 0 then begin EventType := fswFileCreated; end else if (ev^.mask and IN_DELETE) <> 0 then begin EventType := fswFileDeleted; end else if (ev^.mask and IN_MOVED_FROM) <> 0 then begin EventType := fswFileDeleted; // Try to find related event k := p + sizeof(inotify_event) + ev^.len; while (k < bytes_to_parse) do begin v := pinotify_event(buf + k); if (v^.mask and IN_MOVED_TO) <> 0 then begin // Same cookie and path if (v^.cookie = ev^.cookie) and (v^.wd = ev^.wd) then begin v^.mask := IN_IGNORED; EventType := fswFileRenamed; NewFileName := StrPas(PChar(@v^.name)); Break; end; end; k := k + sizeof(inotify_event) + v^.len; end; end else if (ev^.mask and IN_MOVED_TO) <> 0 then begin EventType := fswFileCreated end else if (ev^.mask and (IN_DELETE_SELF or IN_MOVE_SELF)) <> 0 then begin // Watched file/directory was deleted or moved. EventType := fswSelfDeleted; end else begin EventType := fswUnknownChange; end; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Send event, Path %s, FileName %s, EventType %d', [Path, FileName, EventType]); {$ENDIF}; end; // call event handler SyncDoWatcherEvent; Break; end; { if } end; { for } p := p + sizeof(inotify_event) + ev^.len; end; { while } end; { while } finally if Assigned(buf) then FreeMem(buf); end; { try - finally } end; {$ELSEIF DEFINED(DARWIN)} begin FDarwinFSWatcher.start; end; {$ELSEIF DEFINED(BSD)} var ret: cint; ke: TKEvent; begin if FNotifyHandle = feInvalidHandle then exit; while not Terminated do begin FillByte(ke, SizeOf(ke), 0); // Wait for events repeat ret:= kevent(FNotifyHandle, nil, 0, @ke, 1, nil); until (ret <> -1) or (fpGetErrNo <> ESysEINTR); if ret = -1 then begin ShowError('kevent() failed'); Break; end; { if } case ke.Filter of EVFILT_TIMER: // user triggered Continue; EVFILT_VNODE: begin with FCurrentEventData do begin Path := TOSWatch(ke.uData).WatchPath; EventType := fswUnknownChange; FileName := EmptyStr; NewFileName := EmptyStr; end; SyncDoWatcherEvent; end; end; { case } end; { while } end; {$ELSEIF DEFINED(HAIKUQT)} begin while not Terminated do begin FFinishEvent.WaitFor(INFINITE); end; end; {$ELSE} begin end; {$ENDIF} {$IF DEFINED(DARWIN)} function TFileSystemWatcherImpl.isWatchSubdir(const path: String): Boolean; begin FWatcherLock.Acquire; try Result:= FWatcherSubdirs.IndexOf(path) >= 0; finally FWatcherLock.Release; end; end; procedure TFileSystemWatcherImpl.handleFSEvent(event:TDarwinFSWatchEvent); begin if [watch_file_name_change, watch_attributes_change] * gWatchDirs = [] then exit; if event.isDropabled then exit; if (ecChildChanged in event.categories) and (not isWatchSubdir(event.watchPath) ) then exit; FCurrentEventData.Path := event.watchPath; FCurrentEventData.FileName := EmptyStr; FCurrentEventData.NewFileName := EmptyStr; FCurrentEventData.OriginalEvent := event; FCurrentEventData.EventType := fswUnknownChange; if TDarwinFSWatchEventCategory.ecRootChanged in event.categories then begin FCurrentEventData.EventType := fswSelfDeleted; end else if event.fullPath.Length >= event.watchPath.Length+2 then begin // 1. file-level update only valid if there is a FileName, // otherwise keep directory-level update // 2. the order of the following judgment conditions must be preserved if (not (watch_file_name_change in gWatchDirs)) and ([ecStructChanged, ecAttribChanged] * event.categories = [ecStructChanged]) then exit; if (not (watch_attributes_change in gWatchDirs)) and ([ecStructChanged, ecAttribChanged] * event.categories = [ecAttribChanged]) then exit; FCurrentEventData.FileName := ExtractFileName( event.fullPath ); if TDarwinFSWatchEventCategory.ecRemoved in event.categories then FCurrentEventData.EventType := fswFileDeleted else if TDarwinFSWatchEventCategory.ecRenamed in event.categories then begin if ExtractFilePath(event.fullPath)=ExtractFilePath(event.renamedPath) then begin // fswFileRenamed only when FileName and NewFileName in the same dir // otherwise keep fswUnknownChange FCurrentEventData.EventType := fswFileRenamed; FCurrentEventData.NewFileName := ExtractFileName( event.renamedPath ); end; end else if TDarwinFSWatchEventCategory.ecCreated in event.categories then FCurrentEventData.EventType := fswFileCreated else if TDarwinFSWatchEventCategory.ecCoreAttribChanged in event.categories then FCurrentEventData.EventType := fswFileChanged else exit; end; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Send event, Path %s', [FCurrentEventData.Path]); {$ENDIF}; SyncDoWatcherEvent; FCurrentEventData.OriginalEvent := nil; end; {$ENDIF} {$IF DEFINED(HAIKUQT)} procedure TFileSystemWatcherImpl.DirectoryChanged(Path: PWideString); cdecl; begin FCurrentEventData.Path := CeUtf16ToUtf8(Path^); FCurrentEventData.EventType := fswUnknownChange; FCurrentEventData.FileName := EmptyStr; FCurrentEventData.NewFileName := EmptyStr; {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Send event, Path %s', [FCurrentEventData.Path]); {$ENDIF}; SyncDoWatcherEvent; end; {$ENDIF} procedure TFileSystemWatcherImpl.DoWatcherEvent; var i, j: Integer; AWatchPath: String; begin if not Terminated then begin AWatchPath := FCurrentEventData.Path; try FWatcherLock.Acquire; try for i := 0 to FOSWatchers.Count - 1 do begin if FOSWatchers[i].WatchPath = AWatchPath then begin for j := 0 to FOSWatchers[i].Observers.Count - 1 do begin // TODO: Check filter. // Can be called under the lock because this function is run from // the main thread and the watcher thread is suspended anyway because // it's waiting until Synchronize call (thus this function) finishes. with FOSWatchers[i].Observers[j] do begin if Assigned(WatcherEvent) {$IFDEF MSWINDOWS} and ((gWatcherMode <> fswmWholeDrive) or IsInPath(TargetWatchPath, UTF8UpperCase(FOSWatchers[i].WatchPath + FCurrentEventData.FileName), False, False)) {$ENDIF} then begin FCurrentEventData.UserData := UserData; {$IFDEF MSWINDOWS} if gWatcherMode = fswmWholeDrive then FCurrentEventData.Path := RegisteredWatchPath; {$ENDIF} {$IFDEF DARWIN} // FlatView Watch is supported on MacOS // FCurrentEventData.Path contains WatchPath // so in FlatView Mode, Path need to be adjusted to the Real Path if TFileView(UserData).FlatView then begin if ecDir in FCurrentEventData.OriginalEvent.categories then begin // in FlatView Mode, when receiving events about subdirectories, // WatchPath reload should be used instead of partial update FCurrentEventData.EventType:= fswUnknownChange; FCurrentEventData.Path := AWatchPath; end else begin FCurrentEventData.Path := ExcludeTrailingPathDelimiter(ExtractFilePath(FCurrentEventData.OriginalEvent.fullPath)); end; end else begin if TDarwinFSWatchEventCategory.ecChildChanged in FCurrentEventData.OriginalEvent.categories then // not watching SubDir, then SubDir event should be discarded continue; FCurrentEventData.Path := AWatchPath; end; {$ENDIF} WatcherEvent(FCurrentEventData); end; end; end; Break; end; { if } end; { for } finally FWatcherLock.Release; end; { try - finally } except on e: Exception do HandleException(e, Self); end; end; { if } end; function TFileSystemWatcherImpl.GetWatchersCount: Integer; begin FWatcherLock.Acquire; try Result := FOSWatchers.Count; finally FWatcherLock.Release; end; { try - finally } end; function TFileSystemWatcherImpl.GetWatchPath(var aWatchPath: String): Boolean; begin Result := True; {$IFDEF UNIX} if aWatchPath <> PathDelim then {$ENDIF} aWatchPath := ExcludeTrailingPathDelimiter(aWatchPath); {$IFDEF MSWINDOWS} // Special check for network path if (Pos(PathDelim, aWatchPath) = 1) and (NumCountChars(PathDelim, aWatchPath) < 3) then Exit(False); // Special check for drive root if (Length(aWatchPath) = 2) and (aWatchPath[2] = ':') then aWatchPath := aWatchPath + PathDelim; {$ENDIF} end; {$IF DEFINED(MSWINDOWS)} function TFileSystemWatcherImpl.IsPathObserved(Watch: TOSWatch; FileName: String): Boolean; var j: Integer; Path: String; begin Path := UTF8UpperCase(Watch.WatchPath + FileName); FWatcherLock.Acquire; try for j := 0 to Watch.Observers.Count - 1 do begin if IsInPath(Watch.Observers[j].TargetWatchPath, Path, False, False) then Exit(True); end; finally FWatcherLock.Release; end; { try - finally } Result := False; end; {$ENDIF} constructor TFileSystemWatcherImpl.Create; begin FOSWatchers := TOSWatchs.Create({$IFDEF MSWINDOWS}False{$ELSE}True{$ENDIF}); FWatcherLock := syncobjs.TCriticalSection.Create; {$IFDEF DARWIN} FWatcherSubdirs := TStringList.Create; FWatcherSubdirs.Sorted := true; FWatcherSubdirs.Duplicates := dupIgnore; {$ENDIF} FFinished := False; {$IF DEFINED(MSWINDOWS)} case gWatcherMode of fswmPreventDelete: VAR_READDIRECTORYCHANGESW_BUFFERSIZE := READDIRECTORYCHANGESW_BUFFERSIZE; fswmAllowDelete: begin VAR_READDIRECTORYCHANGESW_BUFFERSIZE := READDIRECTORYCHANGESW_BUFFERSIZE; CREATEFILEW_SHAREMODE := CREATEFILEW_SHAREMODE or FILE_SHARE_DELETE; end; fswmWholeDrive: begin VAR_READDIRECTORYCHANGESW_BUFFERSIZE := READDIRECTORYCHANGESW_DRIVE_BUFFERSIZE; CREATEFILEW_SHAREMODE := CREATEFILEW_SHAREMODE or FILE_SHARE_DELETE; end; end; {$ELSEIF DEFINED(LINUX)} // create inotify instance FNotifyHandle := fpinotify_init(); if FNotifyHandle < 0 then ShowError('inotify_init() failed'); // create pipe for user triggered fake event FEventPipe[0] := -1; FEventPipe[1] := -1; if FpPipe(FEventPipe) = 0 then begin // set both ends of pipe non blocking FileCloseOnExec(FEventPipe[0]); FileCloseOnExec(FEventPipe[1]); FpFcntl(FEventPipe[0], F_SetFl, FpFcntl(FEventPipe[0], F_GetFl) or O_NONBLOCK); FpFcntl(FEventPipe[1], F_SetFl, FpFcntl(FEventPipe[1], F_GetFl) or O_NONBLOCK); end else ShowError('pipe() failed'); {$ELSEIF DEFINED(DARWIN)} FDarwinFSWatcher := TDarwinFSWatcher.create(@handleFSEvent); {$ELSEIF DEFINED(BSD)} FNotifyHandle := kqueue(); if FNotifyHandle = feInvalidHandle then ShowError('kqueue() failed'); {$ELSEIF DEFINED(HAIKUQT)} FFinishEvent:= TSimpleEvent.Create; FNotifyHandle:= QFileSystemWatcher_Create(); FHook:= QFileSystemWatcher_hook_Create(FNotifyHandle); QFileSystemWatcher_hook_hook_directoryChanged(FHook, @DirectoryChanged); {$ELSEIF DEFINED(UNIX)} FNotifyHandle := feInvalidHandle; {$ENDIF} inherited Create(False); FreeOnTerminate := False; end; destructor TFileSystemWatcherImpl.Destroy; begin {$IF DEFINED(LINUX)} // close both ends of pipe if FEventPipe[0] <> -1 then begin FileClose(FEventPipe[0]); FEventPipe[0] := -1; end; if FEventPipe[1] <> -1 then begin FileClose(FEventPipe[1]); FEventPipe[1] := -1; end; if FNotifyHandle <> feInvalidHandle then begin FileClose(FNotifyHandle); FNotifyHandle := feInvalidHandle; end; {$ELSEIF DEFINED(DARWIN)} FreeAndNil(FDarwinFSWatcher); {$ELSEIF DEFINED(BSD)} if FNotifyHandle <> feInvalidHandle then begin FileClose(FNotifyHandle); FNotifyHandle := feInvalidHandle; end; {$ELSEIF DEFINED(HAIKUQT)} QFileSystemWatcher_hook_hook_directoryChanged(FHook, nil); QFileSystemWatcher_hook_Destroy(FHook); QFileSystemWatcher_Destroy(FNotifyHandle); FreeAndNil(FFinishEvent); {$ENDIF} if Assigned(FOSWatchers) then FreeAndNil(FOSWatchers); if Assigned(FWatcherLock) then FreeAndNil(FWatcherLock); {$IFDEF DARWIN} if Assigned(FWatcherSubdirs) then FreeAndNil(FWatcherSubdirs); {$ENDIF} inherited Destroy; end; procedure TFileSystemWatcherImpl.Terminate; begin {$IF DEFINED(MSWINDOWS)} // Remove leftover watchers before queueing TerminateProc. // Their handles will be destroyed which will cause completion routines // to be called before Terminate is set and SleepEx loop breaks. while FOSWatchers.Count > 0 do RemoveOSWatch(FOSWatchers[0]); // Then queue TerminateProc in TriggerTerminateEvent. {$ENDIF} inherited Terminate; TriggerTerminateEvent; end; function TFileSystemWatcherImpl.AddWatch(aWatchPath: String; aWatchFilter: TFSWatchFilter; aWatcherEvent: TFSWatcherEvent; UserData: Pointer): Boolean; var OSWatcher: TOSWatch = nil; OSWatcherCreated: Boolean = False; Observer: TOSWatchObserver; i, j: Integer; WatcherIndex: Integer = -1; {$IFDEF MSWINDOWS} RegisteredPath: String; {$ENDIF} begin if (aWatchPath = '') or (aWatcherEvent = nil) then Exit(False); if not GetWatchPath(aWatchPath) then Exit(False); {$IFDEF MSWINDOWS} if gWatcherMode = fswmWholeDrive then begin RegisteredPath := aWatchPath; aWatchPath := GetDriveOfPath(aWatchPath); end; {$ENDIF} // Check if the path is not already watched. FWatcherLock.Acquire; try for i := 0 to FOSWatchers.Count - 1 do if FOSWatchers[i].WatchPath = aWatchPath then begin OSWatcher := FOSWatchers[i]; WatcherIndex := i; // Check if the observer is not already registered. for j := 0 to OSWatcher.Observers.Count - 1 do begin if SameMethod(TMethod(OSWatcher.Observers[j].WatcherEvent), TMethod(aWatcherEvent)) then Exit(True); end; Break; end; finally FWatcherLock.Release; end; if not Assigned(OSWatcher) then begin OSWatcher := TOSWatch.Create(aWatchPath {$IFDEF UNIX_butnot_DARWIN}, FNotifyHandle {$ENDIF}); {$IF DEFINED(MSWINDOWS)} OSWatcher.Reference{$IFDEF DEBUG_WATCHER}('AddWatch'){$ENDIF}; // For usage by FileSystemWatcher (main thread) {$ELSEIF DEFINED(DARWIN)} FDarwinFSWatcher.addPath(aWatchPath); {$ENDIF} OSWatcherCreated := True; end; Observer := TOSWatchObserver.Create; Observer.WatchFilter := aWatchFilter; Observer.WatcherEvent := aWatcherEvent; Observer.UserData := UserData; {$IFDEF MSWINDOWS} if gWatcherMode = fswmWholeDrive then begin Observer.RegisteredWatchPath := RegisteredPath; Observer.TargetWatchPath := UTF8UpperCase(GetTargetPath(RegisteredPath)); end; {$ENDIF} FWatcherLock.Acquire; try if OSWatcherCreated then WatcherIndex := FOSWatchers.Add(OSWatcher); OSWatcher.Observers.Add(Observer); {$IF DEFINED(DARWIN)} Result:= true; {$ELSE} OSWatcher.UpdateFilter; // This creates or recreates handle. Result := OSWatcher.Handle <> feInvalidHandle; {$ENDIF} // Remove watcher if could not create notification handle. if not Result then RemoveOSWatchLocked(WatcherIndex); {$IFDEF DARWIN} UpdateWatch; {$ENDIF} finally FWatcherLock.Release; end; end; procedure TFileSystemWatcherImpl.RemoveWatch(aWatchPath: String; aWatcherEvent: TFSWatcherEvent); var i: Integer; begin if not GetWatchPath(aWatchPath) then Exit; {$IFDEF MSWINDOWS} if gWatcherMode = fswmWholeDrive then aWatchPath := GetDriveOfPath(aWatchPath); {$ENDIF} FWatcherLock.Acquire; try for i := 0 to FOSWatchers.Count - 1 do begin if FOSWatchers[i].WatchPath = aWatchPath then begin RemoveObserverLocked(i, aWatcherEvent); Break; end; end; {$IFDEF DARWIN} UpdateWatch; {$ENDIF} finally FWatcherLock.Release; end; end; procedure TFileSystemWatcherImpl.RemoveWatch(aWatcherEvent: TFSWatcherEvent); var i: Integer; begin FWatcherLock.Acquire; try for i := 0 to FOSWatchers.Count - 1 do begin RemoveObserverLocked(i, aWatcherEvent); end; {$IFDEF DARWIN} UpdateWatch; {$ENDIF} finally FWatcherLock.Release; end; end; {$IFDEF DARWIN} // udpate FWatcherSubdirs List, in order to facilitate the processing of // subsequent subdirectory events in isWatchSubdir() procedure TFileSystemWatcherImpl.UpdateWatch; var i, j: Integer; watch: TOSWatch; observer: TOSWatchObserver; begin FWatcherLock.Acquire; try FWatcherSubdirs.Clear; for i := 0 to FOSWatchers.Count - 1 do begin watch := FOSWatchers[i]; for j := 0 to watch.Observers.Count - 1 do begin observer := watch.Observers[j]; if TFileView(observer.UserData).FlatView then FWatcherSubdirs.Add(watch.WatchPath); end; end; FDarwinFSWatcher.watchSubtree:= (FWatcherSubdirs.Count>0); finally FWatcherLock.Release; end; end; {$ENDIF} procedure TFileSystemWatcherImpl.RemoveObserverLocked(OSWatcherIndex: Integer; aWatcherEvent: TFSWatcherEvent); var j: Integer; begin for j := 0 to FOSWatchers[OSWatcherIndex].Observers.Count - 1 do begin if SameMethod(TMethod(FOSWatchers[OSWatcherIndex].Observers[j].WatcherEvent), TMethod(aWatcherEvent)) then begin FOSWatchers[OSWatcherIndex].Observers.Delete(j); if FOSWatchers[OSWatcherIndex].Observers.Count = 0 then RemoveOSWatchLocked(OSWatcherIndex) {$IF NOT DEFINED(DARWIN)} else FOSWatchers[OSWatcherIndex].UpdateFilter {$ENDIF}; Break; end; end; end; procedure TFileSystemWatcherImpl.RemoveOSWatchLocked(Index: Integer); begin {$IF DEFINED(MSWINDOWS)} with FOSWatchers[Index] do begin DestroyHandle; Dereference{$IFDEF DEBUG_WATCHER}('RemoveOSWatchLocked'){$ENDIF}; // Not using anymore by FileSystemWatcher from main thread end; {$ENDIF} {$IF DEFINED(DARWIN)} FDarwinFSWatcher.removePath(FOSWatchers[Index].WatchPath); {$ENDIF} FOSWatchers.Delete(Index); end; procedure TFileSystemWatcherImpl.RemoveOSWatch(Watch: TOSWatch); var i: Integer; begin FWatcherLock.Acquire; try for i := 0 to FOSWatchers.Count - 1 do begin if FOSWatchers[i] = Watch then begin RemoveOSWatchLocked(i); Break; end; end; finally FWatcherLock.Release; end; end; procedure TFileSystemWatcherImpl.TriggerTerminateEvent; {$IF DEFINED(MSWINDOWS)} begin QueueUserAPC(@TerminateProc, Self.Handle, ULONG_PTR(Self)); end; {$ELSEIF DEFINED(LINUX)} var buf: Char; begin // check if thread has been started if Self.FNotifyHandle <> feInvalidHandle then begin buf := #0; FileWrite(FEventPipe[1], buf, 1); end; { if } end; {$ELSEIF DEFINED(DARWIN)} begin FDarwinFSWatcher.terminate; end; {$ELSEIF DEFINED(BSD)} var ke: TKEvent; begin // check if thread has been started if Self.FNotifyHandle <> feInvalidHandle then begin FillByte(ke, SizeOf(ke), 0); EV_SET(@ke, 0, EVFILT_TIMER, EV_ADD or EV_ONESHOT, 0, 0, nil); if kevent(FNotifyHandle, @ke, 1, nil, 0, nil) = -1 then begin ShowError('ERROR: kevent()'); end; { if } end; { if } end; {$ELSEIF DEFINED(HAIKUQT)} begin FFinishEvent.SetEvent; end; {$ELSE} begin end; {$ENDIF} // ---------------------------------------------------------------------------- { TOSWatch } constructor TOSWatch.Create(const aWatchPath: String {$IFDEF UNIX_butnot_DARWIN}; aNotifyHandle: TNotifyHandle{$ENDIF}); begin FObservers := TOSWatchObservers.Create(True); FWatchFilter := []; FWatchPath := aWatchPath; {$IFDEF UNIX_butnot_DARWIN} FNotifyHandle := aNotifyHandle; {$ENDIF} {$IF DEFINED(MSWINDOWS)} FReferenceCount := 0; FBuffer := GetMem(VAR_READDIRECTORYCHANGESW_BUFFERSIZE); {$ENDIF} {$IF not DEFINED(DARWIN)} FHandle := feInvalidHandle; {$ENDIF} end; destructor TOSWatch.Destroy; begin {$IF not DEFINED(DARWIN)} DestroyHandle; {$ENDIF} inherited; {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: Destroying watch ', hexStr(Self)]); {$ENDIF} FObservers.Free; {$IF DEFINED(MSWINDOWS)} Freemem(FBuffer); {$ENDIF} end; {$IF not DEFINED(DARWIN)} procedure TOSWatch.UpdateFilter; var i: Integer; NewFilter: TFSWatchFilter = []; begin for i := 0 to Observers.Count - 1 do NewFilter := NewFilter + Observers[i].WatchFilter; if FWatchFilter <> NewFilter then begin FWatchFilter := NewFilter; // Change watcher filter or recreate watcher. {$IF DEFINED(MSWINDOWS)} SetFilter(FWatchFilter); if FHandle = feInvalidHandle then CreateHandle else QueueCancelRead; // Will cancel and restart Read {$ELSE} DestroyHandle; CreateHandle; {$ENDIF} end; end; {$ENDIF} {$IF DEFINED(MSWINDOWS)} procedure TOSWatch.Reference{$IFDEF DEBUG_WATCHER}(s: String){$ENDIF}; {$IFDEF DEBUG_WATCHER} var CurrentRefCount: LongInt; {$ENDIF} begin {$IFDEF DEBUG_WATCHER} CurrentRefCount := {$ENDIF} System.InterlockedIncrement(FReferenceCount); {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: Watch ', hexStr(Self), ' ++ref=', CurrentRefCount, ' ', s]); {$ENDIF} end; procedure TOSWatch.Dereference{$IFDEF DEBUG_WATCHER}(s: String){$ENDIF}; {$IFDEF DEBUG_WATCHER} var CurrentRefCount: LongInt; {$ENDIF} begin {$IFDEF DEBUG_WATCHER} CurrentRefCount := System.InterlockedDecrement(FReferenceCount); DCDebug(['FSWatcher: Watch ', hexStr(Self), ' --ref=', CurrentRefCount, ' ', s]); if CurrentRefCount = 0 then {$ELSE} if System.InterlockedDecrement(FReferenceCount) = 0 then {$ENDIF} Free; end; {$ENDIF} {$IF not DEFINED(DARWIN)} procedure TOSWatch.CreateHandle; {$IF DEFINED(MSWINDOWS)} begin FHandle := CreateFileW(PWideChar(UTF16LongName(FWatchPath)), FILE_LIST_DIRECTORY, CREATEFILEW_SHAREMODE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0); if FHandle = INVALID_HANDLE_VALUE then begin FHandle := CreateFileW(PWideChar(CeUtf8ToUtf16(FWatchPath)), FILE_LIST_DIRECTORY, CREATEFILEW_SHAREMODE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0); end; if FHandle = INVALID_HANDLE_VALUE then begin FHandle := feInvalidHandle; ShowError('CreateFileW failed for ' + FWatchPath); end else begin FillChar(FOverlapped, SizeOf(FOverlapped), 0); // Pass pointer to watcher to the notify routine FOverlapped.OSWatch := Self; QueueRead; end; end; {$ELSEIF DEFINED(LINUX)} var hNotifyFilter: cuint32 = IN_DELETE_SELF or IN_MOVE_SELF; begin if wfFileNameChange in FWatchFilter then hNotifyFilter := hNotifyFilter or IN_CREATE or IN_DELETE or IN_MOVE; if wfAttributesChange in FWatchFilter then hNotifyFilter := hNotifyFilter or IN_ATTRIB or IN_MODIFY; FHandle := fpinotify_add_watch(FNotifyHandle, FWatchPath, hNotifyFilter); if FHandle < 0 then begin FHandle := feInvalidHandle; ShowError('inotify_add_watch() failed for ' + FWatchPath); end; end; {$ELSEIF DEFINED(BSD)} var ke: TKEvent; hNotifyFilter: cuint = 0; begin if wfFileNameChange in FWatchFilter then hNotifyFilter := hNotifyFilter or NOTE_DELETE or NOTE_WRITE or NOTE_EXTEND or NOTE_RENAME; if wfAttributesChange in FWatchFilter then hNotifyFilter := hNotifyFilter or NOTE_ATTRIB or NOTE_REVOKE; FHandle := mbFileOpen(FWatchPath, fmOpenRead); if FHandle < 0 then begin FHandle := feInvalidHandle; ShowError('failed to open file ' + FWatchPath); end else begin FillByte(ke, SizeOf(ke), 0); EV_SET(@ke, FHandle, EVFILT_VNODE, EV_ADD or EV_CLEAR, hNotifyFilter, 0, Self); if kevent(FNotifyHandle, @ke, 1, nil, 0, nil) = -1 then begin DestroyHandle; ShowError('kevent failed'); end; { if } end; end; {$ELSEIF DEFINED(HAIKUQT)} var APath: WideString; begin FHandle := 1; APath := CeUtf8ToUtf16(FWatchPath); {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Add watch ', FWatchPath); {$ENDIF} QFileSystemWatcher_addPath(FNotifyHandle, @APath); end; {$ELSE} begin FHandle := feInvalidHandle; end; {$ENDIF} procedure TOSWatch.DestroyHandle; {$IF DEFINED(MSWINDOWS)} var tmpHandle: THandle; {$ELSEIF DEFINED(HAIKUQT)} var APath: WideString; {$ENDIF} begin if FHandle <> feInvalidHandle then begin {$IF DEFINED(LINUX)} fpinotify_rm_watch(FNotifyHandle, FHandle); {$ENDIF} {$IF DEFINED(BSD)} FileClose(FHandle); {$ENDIF} {$IF DEFINED(MSWINDOWS)} // If there are outstanding I/O operations on the handle calling CloseHandle // will fail those operations and cause completion routines to be called // but with ErrorCode = 0. Clearing FHandle before the call allows to know // that handle has been destroyed and to not schedule new Reads. {$IFDEF DEBUG_WATCHER} DCDebug(['FSWatcher: Watch ', hexStr(Self),' DestroyHandle ', Integer(FHandle), ' done']); {$ENDIF} tmpHandle := FHandle; FHandle := feInvalidHandle; CloseHandle(tmpHandle); {$ELSEIF DEFINED(HAIKUQT)} FHandle := feInvalidHandle; APath := CeUtf8ToUtf16(FWatchPath); {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: Remove watch ', FWatchPath); {$ENDIF} QFileSystemWatcher_removePath(FNotifyHandle, @APath); {$ELSE} FHandle := feInvalidHandle; {$ENDIF} end; end; {$ENDIF} {$IF DEFINED(MSWINDOWS)} procedure TOSWatch.QueueCancelRead; begin {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: QueueCancelRead: Queueing Cancel APC'); {$ENDIF} Reference{$IFDEF DEBUG_WATCHER}('QueueCancelRead'){$ENDIF}; // For use by CancelReadChangesProc. QueueUserAPC(@CancelReadChangesProc, FileSystemWatcher.Handle, ULONG_PTR(Self)); {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: QueueCancelRead: Queueing Cancel APC done'); {$ENDIF} end; procedure TOSWatch.QueueRead; begin {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: QueueRead: Queueing Read APC'); {$ENDIF} Reference{$IFDEF DEBUG_WATCHER}('QueueRead'){$ENDIF}; // For use by ReadChangesProc. QueueUserAPC(@ReadChangesProc, FileSystemWatcher.Handle, ULONG_PTR(Self)); {$IFDEF DEBUG_WATCHER} DCDebug('FSWatcher: QueueRead: Queueing Read APC done'); {$ENDIF} end; procedure TOSWatch.SetFilter(aWatchFilter: TFSWatchFilter); var // Use temp variable so that assigning FNotifyFilter is coherent. dwFilter: DWORD = 0; begin if wfFileNameChange in aWatchFilter then dwFilter := dwFilter or FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME; if wfAttributesChange in aWatchFilter then dwFilter := dwFilter or FILE_NOTIFY_CHANGE_ATTRIBUTES or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE; FNotifyFilter := dwFilter; end; {$ENDIF} finalization TFileSystemWatcher.DestroyFileSystemWatcher; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/ufindex.pas�����������������������������������������������������������0000644�0001750�0000144�00000017737�14743153644�017407� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains UTF-8 versions of Find(First, Next, Close) functions Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uFindEx; {$macro on} {$mode objfpc}{$H+} {$modeswitch advancedrecords} interface uses SysUtils, DCBasicTypes {$IFDEF UNIX} , BaseUnix, DCUnix, uMasks {$ENDIF} {$IFDEF MSWINDOWS} , Windows {$ENDIF} {$IFDEF DARWIN} , MacOSAll {$ENDIF} ; const fffPortable = $80000000; fffElevated = $40000000; type {$IFDEF UNIX} TUnixFindHandle = record DirPtr: PDir; //en> directory pointer for reading directory FindPath: String; //en> file name path Mask: TMask; //en> object that will check mask end; PUnixFindHandle = ^TUnixFindHandle; {$ENDIF} PSearchRecEx = ^TSearchRecEx; TSearchRecEx = record Time : DCBasicTypes.TFileTime; // modification time Size : Int64; Attr : TFileAttrs; Name : String; Flags : UInt32; {$IF DEFINED(MSWINDOWS)} FindHandle : THandle; FindData : Windows.TWin32FindDataW; property PlatformTime: TFileTime read FindData.ftCreationTime; property LastAccessTime: TFileTime read FindData.ftLastAccessTime; {$ELSE} FindHandle : Pointer; FindData : TDCStat; property PlatformTime: TUnixTime read FindData.st_ctime; property LastAccessTime: TUnixTime read FindData.st_atime; {$IF DEFINED(DARWIN)} property BirthdayTime: TUnixTime read FindData.st_birthtime; property BirthdayTimensec: clong read FindData.st_birthtimensec; {$ENDIF} {$ENDIF} end; function FindFirstEx(const Path: String; Flags: UInt32; out SearchRec: TSearchRecEx): Integer; function FindNextEx(var SearchRec: TSearchRecEx): Integer; procedure FindCloseEx(var SearchRec: TSearchRecEx); implementation uses LazUTF8, uDebug {$IFDEF MSWINDOWS} , DCWindows, DCDateTimeUtils, uMyWindows {$ENDIF} {$IFDEF UNIX} , InitC, Unix, DCOSUtils, DCFileAttributes, DCConvertEncoding {$ENDIF}; {$IF DEFINED(LINUX)} {$define fpgeterrno:= fpgetCerrno} function fpOpenDir(dirname: PAnsiChar): pDir; cdecl; external clib name 'opendir'; function fpReadDir(var dirp: TDir): pDirent; cdecl; external clib name 'readdir64'; function fpCloseDir(var dirp: TDir): cInt; cdecl; external clib name 'closedir'; {$ENDIF} function mbFindMatchingFile(var SearchRec: TSearchRecEx): Integer; {$IFDEF MSWINDOWS} begin with SearchRec do begin if (Flags and fffPortable = 0) then Time:= TWinFileTime(FindData.ftLastWriteTime) else begin Time:= WinFileTimeToUnixTime(TWinFileTime(FindData.ftLastWriteTime)); end; FindData.dwFileAttributes:= ExtractFileAttributes(FindData); Size:= (Int64(FindData.nFileSizeHigh) shl 32) + FindData.nFileSizeLow; Name:= UTF16ToUTF8(UnicodeString(FindData.cFileName)); Attr:= FindData.dwFileAttributes; end; Result:= 0; end; {$ELSE} var UnixFindHandle: PUnixFindHandle absolute SearchRec.FindHandle; begin Result:= -1; if UnixFindHandle = nil then Exit; if (UnixFindHandle^.Mask = nil) or UnixFindHandle^.Mask.Matches(SearchRec.Name) then begin if DC_fpLStat(UTF8ToSys(UnixFindHandle^.FindPath + SearchRec.Name), SearchRec.FindData) >= 0 then begin with SearchRec.FindData do begin // On Unix a size for directory entry on filesystem is returned in StatInfo. // We don't want to use it. if fpS_ISDIR(st_mode) then SearchRec.Size:= 0 else begin SearchRec.Size:= Int64(st_size); end; SearchRec.Time:= DCBasicTypes.TFileTime(st_mtime); if (SearchRec.Flags and fffPortable = 0) then SearchRec.Attr:= DCBasicTypes.TFileAttrs(st_mode) else begin SearchRec.Attr:= UnixToWinFileAttr(SearchRec.Name, TFileAttrs(st_mode)); end; end; Result:= 0; end; end; end; {$ENDIF} function FindFirstEx(const Path: String; Flags: UInt32; out SearchRec: TSearchRecEx): Integer; {$IFDEF MSWINDOWS} var wsPath: UnicodeString; fInfoLevelId: FINDEX_INFO_LEVELS; begin SearchRec.Flags:= Flags; wsPath:= UTF16LongName(Path); if CheckWin32Version(6, 1) then begin fInfoLevelId:= FindExInfoBasic; Flags:= FIND_FIRST_EX_LARGE_FETCH; end else begin Flags:= 0; fInfoLevelId:= FindExInfoStandard; end; SearchRec.FindHandle:= FindFirstFileExW(PWideChar(wsPath), fInfoLevelId, @SearchRec.FindData, FindExSearchNameMatch, nil, Flags); if SearchRec.FindHandle = INVALID_HANDLE_VALUE then Result:= GetLastError else begin Result:= mbFindMatchingFile(SearchRec); end; end; {$ELSE} var UnixFindHandle: PUnixFindHandle; begin New(UnixFindHandle); SearchRec.Flags:= Flags; SearchRec.FindHandle:= UnixFindHandle; FillChar(UnixFindHandle^, SizeOf(TUnixFindHandle), 0); with UnixFindHandle^ do begin FindPath:= ExtractFileDir(Path); if FindPath = '' then begin FindPath := mbGetCurrentDir; end; FindPath:= IncludeTrailingBackSlash(FindPath); // Assignment of SearchRec.Name also needed if the path points to a specific // file and only a single mbFindMatchingFile() check needs to be done below. SearchRec.Name:= ExtractFileName(Path); // Check if searching for all files. If yes don't need to use Mask. if (SearchRec.Name <> '*') and (SearchRec.Name <> '') then // '*.*' searches for files with a dot in name so mask needs to be checked. begin // If searching for single specific file, just check if it exists and exit. if (Pos('?', SearchRec.Name) = 0) and (Pos('*', SearchRec.Name) = 0) then begin if mbFileSystemEntryExists(Path) and (mbFindMatchingFile(SearchRec) = 0) then Exit(0) else Exit(-1); end; Mask := TMask.Create(SearchRec.Name); end; DirPtr:= fpOpenDir(PAnsiChar(CeUtf8ToSys(FindPath))); if (DirPtr = nil) then Exit(fpgeterrno); end; Result:= FindNextEx(SearchRec); end; {$ENDIF} function FindNextEx(var SearchRec: TSearchRecEx): Integer; {$IFDEF MSWINDOWS} begin if FindNextFileW(SearchRec.FindHandle, SearchRec.FindData) then Result:= mbFindMatchingFile(SearchRec) else begin Result:= GetLastError; end; end; {$ELSE} var PtrDirEnt: pDirent; UnixFindHandle: PUnixFindHandle absolute SearchRec.FindHandle; begin Result:= -1; if UnixFindHandle = nil then Exit; if UnixFindHandle^.DirPtr = nil then Exit; PtrDirEnt:= fpReadDir(UnixFindHandle^.DirPtr^); while PtrDirEnt <> nil do begin SearchRec.Name:= CeSysToUtf8(PtrDirEnt^.d_name); Result:= mbFindMatchingFile(SearchRec); if Result = 0 then // if found then exit Exit else // else read next PtrDirEnt:= fpReadDir(UnixFindHandle^.DirPtr^); end; end; {$ENDIF} procedure FindCloseEx(var SearchRec: TSearchRecEx); {$IFDEF MSWINDOWS} begin if SearchRec.FindHandle <> INVALID_HANDLE_VALUE then Windows.FindClose(SearchRec.FindHandle); end; {$ELSE} var UnixFindHandle: PUnixFindHandle absolute SearchRec.FindHandle; begin if UnixFindHandle = nil then Exit; if UnixFindHandle^.DirPtr <> nil then fpCloseDir(UnixFindHandle^.DirPtr^); if Assigned(UnixFindHandle^.Mask) then UnixFindHandle^.Mask.Free; Dispose(UnixFindHandle); SearchRec.FindHandle:= nil; end; {$ENDIF} end. ���������������������������������doublecmd-1.1.22/src/platform/uicontheme.pas��������������������������������������������������������0000644�0001750�0000144�00000036377�14743153644�020106� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple implementation of Icon Theme based on FreeDesktop.org specification (http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html) Copyright (C) 2009-2024 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uIconTheme; {$mode objfpc}{$H+} interface uses SysUtils, Classes, DCStringHashListUtf8, DCClassesUtf8; type TIconType = (itFixed, itScalable, itThreshold); TIconDirInfo = record IconSize: Integer; IconScale: Integer; //IconContext: String; // currently not used IconType: TIconType; IconMaxSize, IconMinSize, IconThreshold: Integer; FileListCache: array of TStringHashListUtf8; end; PIconDirInfo = ^TIconDirInfo; { TIconDirList } TIconDirList = class (TStringList) private function GetIconDir(Index: Integer): PIconDirInfo; public destructor Destroy; override; function Add(IconDirName: String; IconDirInfo: PIconDirInfo): Integer; reintroduce; property Items[Index: Integer]: PIconDirInfo read GetIconDir; end; { TIconTheme } TIconTheme = class protected FTheme, FThemeName: String; FComment: String; FDefaultTheme: String; FInherits: TStringList; FOwnsInheritsObject: Boolean; FDirectories: TIconDirList; FBaseDirList: array of String; //en> List of directories that have this theme's icons. FBaseDirListAtCreate: array of String; //en> Base dir list passed to Create function LoadIconDirInfo(const IniFile: TIniFileEx; const sIconDirName: String): PIconDirInfo; function FindIconHelper(aIconName: String; AIconSize, AIconScale: Integer): String; function LoadThemeWithInherited(AInherits: TStringList): Boolean; procedure LoadParentTheme(AThemeName: String); procedure CacheDirectoryFiles(SubDirIndex: Integer; BaseDirIndex: Integer); protected function LookupIcon(AIconName: String; AIconSize, AIconScale: Integer): String; function CreateParentTheme(const sThemeName: String): TIconTheme; virtual; public constructor Create(sThemeName: String; var BaseDirList: array of String; ADefaultTheme: String = ''); virtual; destructor Destroy; override; function Load: Boolean; virtual; function FindIcon(AIconName: String; AIconSize: Integer; AIconScale: Integer = 1): String; function DirectoryMatchesSize(SubDirIndex: Integer; AIconSize, AIconScale: Integer): Boolean; function DirectorySizeDistance(SubDirIndex: Integer; AIconSize, AIconScale: Integer): Integer; class function CutTrailingExtension(const AIconName: String): String; class procedure RegisterExtension(const AExtension: String); property ThemeName: String read FThemeName; property Directories: TIconDirList read FDirectories; property DefaultTheme: String read FDefaultTheme write FDefaultTheme; end; implementation uses LCLProc, StrUtils, uDebug, uFindEx, DCBasicTypes, DCOSUtils, DCStrUtils; var IconExtensionList: TDynamicStringArray; { TIconTheme } function LookupFallbackIcon (AIconName: String): String; begin (* for each directory in $(basename list) { for extension in ("png", "svg", "xpm") { if exists directory/iconname.extension return directory/iconname.extension } } *) Result := EmptyStr; end; function TIconTheme.DirectoryMatchesSize(SubDirIndex: Integer; AIconSize, AIconScale: Integer): Boolean; begin Result:= False; // read Type and Size data from subdir if SubDirIndex < 0 then Exit; with FDirectories.Items[SubDirIndex]^ do begin if (IconScale <> AIconScale) then Exit; case IconType of itFixed: Result:= (IconSize = AIconSize); itScalable: Result:= (IconMinSize <= AIconSize) and (AIconSize <= IconMaxSize); itThreshold: Result:= ((IconSize - IconThreshold) <= AIconSize) and (AIconSize <= (IconSize + IconThreshold)); end; end; end; function TIconTheme.DirectorySizeDistance(SubDirIndex: Integer; AIconSize, AIconScale: Integer): Integer; begin Result:= 0; // read Type and Size data from subdir if SubDirIndex < 0 then Exit; with FDirectories.Items[SubDirIndex]^ do case IconType of itFixed: Result:= abs(IconSize * IconScale - AIconSize * AIconScale); itScalable: begin if AIconSize * AIconScale < IconMinSize * IconScale then Result:= IconMinSize * IconScale - AIconSize * AIconScale; if AIconSize * AIconScale > IconMaxSize * IconScale then Result:= AIconSize * AIconScale - IconMaxSize * IconScale; end; itThreshold: begin if AIconSize * AIconScale < (IconSize - IconThreshold) * IconScale then Result:= IconMinSize * IconScale - AIconSize * AIconScale; if AIconSize * AIconScale > (IconSize + IconThreshold) * IconScale then Result:= AIconSize * AIconScale - IconMaxSize * IconScale; end; end; end; constructor TIconTheme.Create(sThemeName: String; var BaseDirList: array of String; ADefaultTheme: String); var I, J: Integer; sElement: String; begin FTheme:= sThemeName; FDefaultTheme:= ADefaultTheme; FOwnsInheritsObject:= False; FDirectories:= nil; J:= 0; SetLength(FBaseDirList, Length(BaseDirList)); SetLength(FBaseDirListAtCreate, Length(BaseDirList)); for I:= Low(BaseDirList) to High(BaseDirList) do begin sElement:= BaseDirList[I]; // use only directories that has this theme if mbDirectoryExists(sElement + PathDelim + FTheme) then begin FBaseDirList[J]:= sElement; Inc(J); end; FBaseDirListAtCreate[I] := sElement; // Remember full base dir list. end; SetLength(FBaseDirList, J); end; destructor TIconTheme.Destroy; begin if FOwnsInheritsObject then begin FInherits.Free; end; FreeAndNil(FDirectories); inherited Destroy; end; function TIconTheme.Load: Boolean; var ADefault: String; ADefaultArray: TDynamicStringArray; begin Result := LoadThemeWithInherited(FInherits); if Result and FOwnsInheritsObject then begin ADefaultArray:= SplitString(FDefaultTheme, PathSeparator); for ADefault in ADefaultArray do LoadParentTheme(ADefault); end; end; function TIconTheme.LoadThemeWithInherited(AInherits: TStringList): Boolean; var I: Integer; sValue: String; sElement: String; sThemeName: String; IniFile: TIniFileEx = nil; IconDirInfo: PIconDirInfo = nil; begin Result:= False; for I:= Low(FBaseDirList) to High(FBaseDirList) do begin sElement:= FBaseDirList[I] + PathDelim + FTheme + PathDelim + 'index.theme'; if mbFileExists(sElement) then begin sThemeName:= sElement; Result:= True; Break; end; end; // theme not found if Result = False then begin DCDebug('Theme ', FTheme, ' not found.'); Exit; end; FDirectories:= TIconDirList.Create; // list of parent themes if Assigned(AInherits) then // if this theme is child FInherits:= AInherits else // new theme begin FInherits:= TStringList.Create; FInherits.OwnsObjects:= True; FOwnsInheritsObject:= True; end; // load theme from file IniFile:= TIniFileEx.Create(sThemeName, fmOpenRead); try FThemeName:= IniFile.ReadString('Icon Theme', 'Name', EmptyStr); FComment:= IniFile.ReadString('Icon Theme', 'Comment', EmptyStr); DCDebug('Loading icon theme ', FThemeName); // read theme directories sValue:= IniFile.ReadString('Icon Theme', 'Directories', EmptyStr); repeat sElement:= Copy2SymbDel(sValue, ','); IconDirInfo:= LoadIconDirInfo(IniFile, sElement); if Assigned(IconDirInfo) then FDirectories.Add(sElement, IconDirInfo); until sValue = EmptyStr; // read parent themes sValue:= IniFile.ReadString('Icon Theme', 'Inherits', EmptyStr); if sValue <> EmptyStr then repeat sElement:= Copy2SymbDel(sValue, ','); LoadParentTheme(sElement); until sValue = EmptyStr; finally FreeAndNil(IniFile); end; end; procedure TIconTheme.LoadParentTheme(AThemeName: String); var Index: Integer; ATheme: TIconTheme; begin if (FTheme <> AThemeName) and (FInherits.IndexOf(AThemeName) < 0) then begin ATheme:= CreateParentTheme(AThemeName); Index:= FInherits.AddObject(AThemeName, ATheme); if not ATheme.LoadThemeWithInherited(FInherits) then begin FInherits.Delete(Index); end; end; end; function TIconTheme.FindIcon(AIconName: String; AIconSize: Integer; AIconScale: Integer): String; begin Result:= FindIconHelper(AIconName, AIconSize, AIconScale); { if Result = EmptyStr then Result:= LookupFallbackIcon(AIconName); } end; function TIconTheme.LookupIcon(AIconName: String; AIconSize, AIconScale: Integer): String; var I, J, FoundIndex: Integer; MinimalSize, NewSize: Integer; procedure MakeResult; inline; begin Result:= FBaseDirList[J] + PathDelim + FTheme + PathDelim + FDirectories.Strings[I] + PathDelim + AIconName + '.' + IconExtensionList[PtrInt(FDirectories.Items[I]^.FileListCache[J].List[FoundIndex]^.Data)]; end; begin Result:= EmptyStr; if not Assigned(FDirectories) then Exit; { This is a slightly more optimized version of the original algorithm from freedesktop.org. } MinimalSize:= MaxInt; for J:= Low(FBaseDirList) to High(FBaseDirList) do begin for I:= 0 to FDirectories.Count - 1 do begin NewSize:= DirectorySizeDistance(I, AIconSize, AIconScale); if (NewSize < MinimalSize) or (NewSize = 0) then begin if not Assigned(FDirectories.Items[I]^.FileListCache[J]) then CacheDirectoryFiles(I, J); FoundIndex:= FDirectories.Items[I]^.FileListCache[J].Find(AIconName); if FoundIndex >= 0 then begin MakeResult; // Exact match if (NewSize = 0) and (AIconScale = FDirectories.Items[I]^.IconScale) then Exit else MinimalSize:= NewSize; end; end; end; end; end; function TIconTheme.CreateParentTheme(const sThemeName: String): TIconTheme; begin Result:= TIconTheme.Create(sThemeName, FBaseDirListAtCreate); end; function TIconTheme.LoadIconDirInfo(const IniFile: TIniFileEx; const sIconDirName: String): PIconDirInfo; var IconTypeStr: String; I: Integer; begin New(Result); with Result^ do begin IconSize:= IniFile.ReadInteger(sIconDirName, 'Size', 48); IconScale:= IniFile.ReadInteger(sIconDirName, 'Scale', 1); //IconContext:= IniFile.ReadString(sIconDirName, 'Context', EmptyStr); // currently not used IconTypeStr:= IniFile.ReadString(sIconDirName, 'Type', 'Threshold'); IconMaxSize:= IniFile.ReadInteger(sIconDirName, 'MaxSize', IconSize); IconMinSize:= IniFile.ReadInteger(sIconDirName, 'MinSize', IconSize); IconThreshold:= IniFile.ReadInteger(sIconDirName, 'Threshold', 2); if SameText(IconTypeStr, 'Fixed') then IconType:= itFixed else if SameText(IconTypeStr, 'Scalable') then IconType:= itScalable else if SameText(IconTypeStr, 'Threshold') then IconType:= itThreshold else begin Dispose(Result); DCDebug('Theme directory "%s" has unsupported icon type "%s"', [sIconDirName, IconTypeStr]); Exit(nil); end; SetLength(FileListCache, Length(FBaseDirList)); for I:= 0 to Length(FBaseDirList) - 1 do FileListCache[I]:= nil; end; end; function TIconTheme.FindIconHelper(aIconName: String; AIconSize, AIconScale: Integer): String; var I: Integer; begin Result:= LookupIcon(AIconName, AIconSize, AIconScale); if Result <> EmptyStr then Exit; if Assigned(FInherits) then begin // find in parent themes for I:= 0 to FInherits.Count - 1 do begin Result:= TIconTheme(FInherits.Objects[I]).LookupIcon(aIconName, AIconSize, AIconScale); if Result <> EmptyStr then Exit; end; end; Result:= EmptyStr; end; procedure TIconTheme.CacheDirectoryFiles(SubDirIndex: Integer; BaseDirIndex: Integer); var SearchDir, FoundName, FoundExt: String; SearchRec: TSearchRecEx; DirList: TStringHashListUtf8; I: Integer; begin DirList:= TStringHashListUtf8.Create(True); FDirectories.Items[SubDirIndex]^.FileListCache[BaseDirIndex]:= DirList; SearchDir := FBaseDirList[BaseDirIndex] + PathDelim + FTheme + PathDelim + FDirectories.Strings[SubDirIndex]; if FindFirstEx(SearchDir + PathDelim + '*', 0, SearchRec) = 0 then repeat if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin FoundExt := ExtractFileExt(SearchRec.Name); if Length(FoundExt) > 0 then begin FoundName := Copy(SearchRec.Name, 1, Length(SearchRec.Name) - Length(FoundExt)); Delete(FoundExt, 1, 1); // remove the dot // Add only files with supported extensions. for I:= Low(IconExtensionList) to High(IconExtensionList) do if IconExtensionList[I] = FoundExt then begin DirList.Add(FoundName, Pointer(PtrInt(I))); break; end; end; end; until FindNextEx(SearchRec) <> 0; FindCloseEx(SearchRec); end; class function TIconTheme.CutTrailingExtension(const AIconName: String): String; var I: Integer; begin for I:= Low(IconExtensionList) to High(IconExtensionList) do if StrEnds(AIconName, '.' + IconExtensionList[I]) then Exit(Copy(AIconName, 1, Length(AIconName) - Length(IconExtensionList[I]) - 1)); Result := AIconName; end; class procedure TIconTheme.RegisterExtension(const AExtension: String); var I: Integer; ExtList: TDynamicStringArray; begin ExtList:= SplitString(AExtension, ';'); for I:= Low(ExtList) to High(ExtList) do begin AddString(IconExtensionList, ExtList[I]); end; end; { TIconDirList } function TIconDirList.Add(IconDirName: String; IconDirInfo: PIconDirInfo): Integer; begin Result:= AddObject(IconDirName, TObject(IconDirInfo)); end; function TIconDirList.GetIconDir(Index: Integer): PIconDirInfo; begin Result:= PIconDirInfo(Objects[Index]); end; destructor TIconDirList.Destroy; var I, J: Integer; IconDirInfo: PIconDirInfo; begin for I:= Count - 1 downto 0 do begin if Assigned(Objects[I]) then begin IconDirInfo:= PIconDirInfo(Objects[I]); for J := 0 to Length(IconDirInfo^.FileListCache) - 1 do IconDirInfo^.FileListCache[J].Free; Dispose(IconDirInfo); end; end; inherited Destroy; end; initialization AddString(IconExtensionList, 'png'); AddString(IconExtensionList, 'xpm'); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uinfotooltip.pas������������������������������������������������������0000644�0001750�0000144�00000023361�14743153644�020466� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains TFileInfoToolTip class and functions. Copyright (C) 2018 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uInfoToolTip; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fgl, DCXmlConfig, uFile, uFileSource; type { THintItem } THintItem = class Name: String; Mask: String; Hint: String; function Clone: THintItem; end; { THintItemList } THintItemList = specialize TFPGObjectList<THintItem>; { TFileInfoToolTip } TFileInfoToolTip = class(TPersistent) protected FHintItemList: THintItemList; public constructor Create; destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure Clear; function GetFileInfoToolTip(aFileSource: IFileSource; const aFile: TFile): String; procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); procedure LoadFromFile(const FileName: String); procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); procedure SaveToFile(const FileName: String); function ComputeSignature(Seed: dword = $00000000): dword; procedure Sort; property HintItemList: THintItemList read FHintItemList; end; function GetFileInfoToolTip(aFileSource: IFileSource; const aFile: TFile): String; implementation uses crc, LCLProc, StrUtils, uMasks, uDebug, uGlobs, uFileProperty, uFileFunctions, uSearchTemplate, uFileSourceProperty {$IF DEFINED(MSWINDOWS)} , uShlObjAdditional {$ENDIF} ,DCClassesUtf8; function GetFileInfoToolTip(aFileSource: IFileSource; const aFile: TFile): String; function GetDefaultToolTip(const Hint: String): String; begin Result:= Hint; if (fpModificationTime in aFile.SupportedProperties) and aFile.ModificationTimeProperty.IsValid then with (aFile.Properties[fpModificationTime] as TFileModificationDateTimeProperty) do Result:= IfThen(Result = EmptyStr, EmptyStr, Result + LineEnding) + GetDescription + #58#32 + AsString; if (fpSize in aFile.SupportedProperties) and aFile.SizeProperty.IsValid then with (aFile.Properties[fpSize] as TFileSizeProperty) do Result:= IfThen(Result = EmptyStr, EmptyStr, Result + LineEnding) + GetDescription + #58#32 + AsString; if (fpCompressedSize in aFile.SupportedProperties) and aFile.CompressedSizeProperty.IsValid then with (aFile.Properties[fpCompressedSize] as TFileCompressedSizeProperty) do Result:= IfThen(Result = EmptyStr, EmptyStr, Result + LineEnding) + GetDescription + #58#32 + AsString; end; begin Result:= EmptyStr; if fspDirectAccess in aFileSource.Properties then begin case gShowToolTipMode of tttmCombineDcSystem, tttmDcSystemCombine, tttmDcIfPossThenSystem, tttmDcOnly: Result := StringReplace(gFileInfoToolTip.GetFileInfoToolTip(aFileSource, aFile), '\n', LineEnding, [rfReplaceAll]); tttmSystemOnly: Result := EmptyStr; end; {$IF DEFINED(MSWINDOWS)} case gShowToolTipMode of tttmCombineDcSystem: Result := IfThen(Result = EmptyStr, EmptyStr, Result + LineEnding) + SHGetInfoTip(aFile.Path, aFile.Name); tttmDcSystemCombine: Result := SHGetInfoTip(aFile.Path, aFile.Name) + IfThen(Result = EmptyStr, EmptyStr, LineEnding + Result); tttmDcIfPossThenSystem: if Result = EmptyStr then Result := SHGetInfoTip(aFile.Path, aFile.Name); tttmDcOnly: ; tttmSystemOnly: Result := SHGetInfoTip(aFile.Path, aFile.Name); end; {$ELSE} case gShowToolTipMode of tttmCombineDcSystem: Result := IfThen(Result = EmptyStr, EmptyStr, Result + LineEnding) + GetDefaultToolTip(EmptyStr); tttmDcSystemCombine: Result := GetDefaultToolTip(EmptyStr) + IfThen(Result = EmptyStr, EmptyStr, LineEnding + Result); tttmDcIfPossThenSystem: if Result = EmptyStr then Result := GetDefaultToolTip(EmptyStr); tttmDcOnly: ; tttmSystemOnly: Result := GetDefaultToolTip(Result); end; {$ENDIF} end else begin Result:= GetDefaultToolTip(Result); end; end; { THintItem } function THintItem.Clone: THintItem; begin Result:= THintItem.Create; Result.Name:= Name; Result.Mask:= Mask; Result.Hint:= Hint; end; { TFileInfoToolTip } constructor TFileInfoToolTip.Create; begin FHintItemList:= THintItemList.Create(True); end; destructor TFileInfoToolTip.Destroy; begin FreeAndNil(FHintItemList); inherited Destroy; end; procedure TFileInfoToolTip.Clear; begin begin while FHintItemList.Count > 0 do begin //FHintItemList[0].Free; FHintItemList.Delete(0); end; end; end; procedure TFileInfoToolTip.Assign(Source: TPersistent); var I: LongInt; From: TFileInfoToolTip; begin Clear; From:= Source as TFileInfoToolTip; for I:= 0 to From.FHintItemList.Count - 1 do FHintItemList.Add(From.FHintItemList[I].Clone); end; function TFileInfoToolTip.GetFileInfoToolTip(aFileSource: IFileSource; const aFile: TFile): String; var I, J: Integer; HintItem: THintItem; begin Result:= EmptyStr; for I:= 0 to FHintItemList.Count - 1 do begin HintItem:= FHintItemList[I]; // Get hint by search template if IsMaskSearchTemplate(HintItem.Mask) then for J:= 0 to gSearchTemplateList.Count - 1 do with gSearchTemplateList do begin if (Templates[J].TemplateName = PChar(HintItem.Mask)+1) and Templates[J].CheckFile(AFile) then begin Result:= FormatFileFunctions(HintItem.Hint, aFile, aFileSource); Exit; end; end; // Get hint by file mask if MatchesMaskList(AFile.Name, HintItem.Mask) then begin Result:= FormatFileFunctions(HintItem.Hint, aFile, aFileSource); Exit; end; end; end; procedure TFileInfoToolTip.Load(AConfig: TXmlConfig; ANode: TXmlNode); var sMask, sName, sHint: String; MaskItem: THintItem; begin Clear; ANode := ANode.FindNode('CustomFields'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('CustomField') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', sName) and AConfig.TryGetValue(ANode, 'Mask', sMask) and AConfig.TryGetValue(ANode, 'Hint', sHint) then begin MaskItem:= THintItem.Create; MaskItem.Name := sName; MaskItem.Mask := sMask; MaskItem.Hint := sHint; FHintItemList.Add(MaskItem); end else begin DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; end; ANode := ANode.NextSibling; end; end; end; { TFileInfoToolTip.LoadFromFile } procedure TFileInfoToolTip.LoadFromFile(const FileName: String); var TooltipConfig: TXmlConfig = nil; Root, Node: TXmlNode; begin TooltipConfig := TXmlConfig.Create(FileName); try if TooltipConfig.Load then begin Root := TooltipConfig.RootNode; Node := Root.FindNode('ToolTips'); if Assigned(Node) then Load(TooltipConfig, Node); end; finally TooltipConfig.Free; end; end; procedure TFileInfoToolTip.Save(AConfig: TXmlConfig; ANode: TXmlNode); var I : Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'CustomFields', True); AConfig.ClearNode(ANode); for I:=0 to FHintItemList.Count - 1 do begin SubNode := AConfig.AddNode(ANode, 'CustomField'); AConfig.AddValue(SubNode, 'Name', FHintItemList[I].Name); AConfig.AddValue(SubNode, 'Mask', FHintItemList[I].Mask); AConfig.AddValue(SubNode, 'Hint', FHintItemList[I].Hint); end; end; { TFileInfoToolTip.SaveToFile } procedure TFileInfoToolTip.SaveToFile(const FileName: String); var TooltipConfig: TXmlConfig = nil; Root, Node: TXmlNode; begin TooltipConfig := TXmlConfig.Create(FileName); try Root := TooltipConfig.RootNode; Node := TooltipConfig.FindNode(Root, 'ToolTips', True); Save(TooltipConfig, Node); TooltipConfig.Save; finally TooltipConfig.Free; end; end; { TFileInfoToolTip.ComputeSignature } function TFileInfoToolTip.ComputeSignature(Seed: dword): dword; procedure UpdateSignature(sInfo: string); begin if length(sInfo) > 0 then Result := crc32(Result, @sInfo[1], length(sInfo)); end; var Index: integer; begin Result := Seed; for Index := 0 to pred(FHintItemList.Count) do begin UpdateSignature(FHintItemList[Index].Name); UpdateSignature(FHintItemList[Index].Mask); UpdateSignature(FHintItemList[Index].Hint); end; end; { MyHintCompare } function MyHintCompare(const Item1, Item2: THintItem): integer; begin Result := CompareStr(Item1.Name, Item2.Name); end; { TFileInfoToolTip.Sort } procedure TFileInfoToolTip.Sort; begin Self.HintItemList.Sort(@MyHintCompare); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/ukeyboard.pas���������������������������������������������������������0000644�0001750�0000144�00000112550�14743153644�017717� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This unit handles anything regarding keyboard and keys. It is heavily dependent on operating system and widget set. For MSWINDOWS and Unix GTK1/2, QT. } unit uKeyboard; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLType; type TMenuKeyCap = (mkcClear, mkcBkSp, mkcTab, mkcEsc, mkcEnter, mkcSpace, mkcPgUp, mkcPgDn, mkcEnd, mkcHome, mkcLeft, mkcUp, mkcRight, mkcDown, mkcIns, mkcDel, mkcShift, mkcCtrl, mkcAlt, mkcMeta, mkcNumDivide, mkcNumMultiply, mkcNumAdd, mkcNumSubstract); const SmkcClear = 'Clear'; SmkcBkSp = 'BkSp'; SmkcTab = 'Tab'; SmkcEsc = 'Esc'; SmkcEnter = 'Enter'; SmkcSpace = 'Space'; SmkcPgUp = 'PgUp'; SmkcPgDn = 'PgDn'; SmkcEnd = 'End'; SmkcHome = 'Home'; SmkcLeft = 'Left'; SmkcUp = 'Up'; SmkcRight = 'Right'; SmkcDown = 'Down'; SmkcIns = 'Ins'; SmkcDel = 'Del'; SmkcShift = 'Shift+'; SmkcCtrl = 'Ctrl+'; SmkcAlt = 'Alt+'; SmkcCmd = 'Cmd+'; SmkcWin = 'WinKey+'; SmkcNumDivide = 'Num/'; SmkcNumMultiply = 'Num*'; SmkcNumAdd = 'Num+'; SmkcNumSubstract = 'Num-'; SmkcAtem = {$IF DEFINED(DARWIN)}SmkcWin{$ELSE}SmkcCmd{$ENDIF}; SmkcMeta = {$IF DEFINED(DARWIN)}SmkcCmd{$ELSE}SmkcWin{$ENDIF}; SmkcSuper = {$IF DEFINED(DARWIN)}SmkcCmd{$ELSE}SmkcCtrl{$ENDIF}; MenuKeyCaps: array[TMenuKeyCap] of string = ( SmkcClear, SmkcBkSp, SmkcTab, SmkcEsc, SmkcEnter, SmkcSpace, SmkcPgUp, SmkcPgDn, SmkcEnd, SmkcHome, SmkcLeft, SmkcUp, SmkcRight, SmkcDown, SmkcIns, SmkcDel, SmkcShift, SmkcCtrl, SmkcAlt, SmkcMeta, SmkcNumDivide, SmkcNumMultiply, SmkcNumAdd, SmkcNumSubstract); // Modifiers that can be used for shortcuts (non-toggable). KeyModifiersShortcut = [ssShift, ssAlt, ssCtrl, ssMeta, ssSuper, ssHyper, ssAltGr]; // Modifiers that change meaning of entered text (case, non-ASCII characters). KeyModifiersText = [ssShift, ssAltGr, ssCaps]; // Modifiers that can be used for shortcuts without taking into account text modifiers. KeyModifiersShortcutNoText = KeyModifiersShortcut - KeyModifiersText; {en Retrieves current modifiers state of the keyboard. } function GetKeyShiftStateEx: TShiftState; function KeyToShortCutEx(Key: Word; Shift: TShiftState): TShortCut; function ModifiersTextToShortcutEx(const ModifiersText: String; out ModLength: Integer): TShortCut; {en Changes order of modifiers in text to always be the same. } function NormalizeModifiers(ShortCutText: String): String; function ShiftToShortcutEx(ShiftState: TShiftState): TShortCut; function ShiftToTextEx(ShiftState: TShiftState): String; function ShortcutToShiftEx(Shortcut: TShortCut): TShiftState; function ShortCutToTextEx(ShortCut: TShortCut): String; function TextToShortCutEx(const ShortCutText: String): TShortCut; {en Tries to translate virtual key (VK_..) into a valid UTF8 character, taking into account modifiers state. @param(Key Virtual key code.) @param(ShiftState Keyboard modifiers that should be taken into account when determining the character.) } function VirtualKeyToUTF8Char(Key: Byte; ShiftState: TShiftState = []): TUTF8Char; {en Returns text description of a virtual key trying to take into account given modifiers state. For keys that have characters assigned it usually returns that character, for others some textual description. @param(Key Virtual key code.) @param(ShiftState Keyboard modifiers that should be taken into account when determining the description.) @return(UTF8 character assigned to Key or an empty string.) } function VirtualKeyToText(Key: Byte; ShiftState: TShiftState = []): string; {$IFDEF MSWINDOWS} {en If a virtual key with any modifiers produces valid ANSI or UNICODE character, that character is returned in UTF8 encoding. @param(Key Virtual key code.) @param(ExcludeShiftState Which modifiers should not be taken into account when determining possible character.) @return(UTF8 character assigned to Key or an empty string.) } function GetInternationalCharacter(Key: Word; ExcludeShiftState: TShiftState = []): TUTF8Char; {$ENDIF} function IsShortcutConflictingWithOS(Shortcut: String): Boolean; {en Initializes keyboard module. Should be called after Application.Initialize. } procedure InitializeKeyboard; procedure CleanupKeyboard; {en Should be called after main form has been created. } procedure HookKeyboardLayoutChanged; {en Should be called whenever a keyboard layout modification is detected. } procedure OnKeyboardLayoutChanged; {$IFDEF MSWINDOWS} var // True, if the current keyboard layout's right Alt key is mapped as AltGr. HasKeyboardAltGrKey : Boolean = False; {$ENDIF} implementation {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} {$DEFINE X11} {$ENDIF} uses LCLProc, LCLIntf, LazUTF8 {$IF DEFINED(MSWINDOWS)} , Windows {$ENDIF} {$IF DEFINED(LCLGTK)} , Gdk, GLib , GtkProc , XLib, X {$ENDIF} {$IF DEFINED(LCLGTK2)} , Gdk2, GLib2, Gtk2Extra , Gtk2Proc {$ENDIF} {$IF DEFINED(LCLGTK3)} , LazGdk3, LazGLib2, LazGObject2 {$ENDIF} {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} {$IF DEFINED(LCLQT)} , qt4, qtwidgets, qtint {$ELSEIF DEFINED(LCLQT5)} , qt5, qtwidgets, qtint {$ELSEIF DEFINED(LCLQT6)} , qt6, qtwidgets, qtint {$ENDIF} , XLib, X , xutil, KeySym , Forms // for Application.MainForm {$ENDIF} ; type TModifiersMap = record Shift: TShiftStateEnum; Shortcut: TShortCut; Text: TMenuKeyCap; end; const ModifiersMap: array [0..3] of TModifiersMap = ((Shift: ssCtrl; Shortcut: scCtrl; Text: mkcCtrl), (Shift: ssShift; Shortcut: scShift; Text: mkcShift), (Shift: ssAlt; Shortcut: scAlt; Text: mkcAlt), (Shift: ssMeta; Shortcut: scMeta; Text: mkcMeta) ); {$IF DEFINED(X11)} var {$IF DEFINED(LCLGTK)} XDisplay: PDisplay = nil; {$ELSEIF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} XDisplay: PGdkDisplay = nil; {$ELSEIF (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} XDisplay: PDisplay = nil; {$ENDIF} {$ENDIF} {$IF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2) or DEFINED(LCLGTK3))} var {$IF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} // This is set to a virtual key number that AltGr is mapped on. VK_ALTGR: Byte = VK_UNDEFINED; {$ENDIF} {$IF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} KeysChangesSignalHandlerId : gulong = 0; {$ENDIF} {$ENDIF} {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} type TKeyboardLayoutChangedHook = class private EventHook: QObject_hookH; function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; // called by QT public constructor Create(QObject: QObjectH); destructor Destroy; override; end; var // Used to catch "keyboard layout modified" event. KeyboardLayoutChangedHook: TKeyboardLayoutChangedHook = nil; ShiftMask : Cardinal = 0; AltGrMask : Cardinal = 0; {$ENDIF} var VKToCharArray: array[Low(Byte)..High(Byte)] of String; {$IF DEFINED(LCLGTK)} function XKeycodeToKeysym(para1:PDisplay; para2:TKeyCode; index:integer):TKeySym;cdecl;external libX11; {$ENDIF} procedure CacheVKToChar; var Key: Byte; begin for Key := Low(VKToCharArray) to High(VKToCharArray) do case Key of VK_BACK: VKToCharArray[Key] := MenuKeyCaps[mkcBkSp]; VK_TAB: VKToCharArray[Key] := MenuKeyCaps[mkcTab]; VK_CLEAR: VKToCharArray[Key] := MenuKeyCaps[mkcClear]; VK_RETURN: VKToCharArray[Key] := MenuKeyCaps[mkcEnter]; VK_ESCAPE: VKToCharArray[Key] := MenuKeyCaps[mkcEsc]; VK_SPACE..VK_DOWN: VKToCharArray[Key] := MenuKeyCaps[TMenuKeyCap(Ord(mkcSpace) + Key - VK_SPACE)]; VK_INSERT: VKToCharArray[Key] := MenuKeyCaps[mkcIns]; VK_DELETE: VKToCharArray[Key] := MenuKeyCaps[mkcDel]; VK_0..VK_9: VKToCharArray[Key] := Chr(Key - VK_0 + Ord('0')); VK_A..VK_Z: VKToCharArray[Key] := Chr(Key - VK_A + Ord('A')); VK_NUMPAD0..VK_NUMPAD9: VKToCharArray[Key] := Chr(Key - VK_NUMPAD0 + Ord('0')); VK_DIVIDE: VKToCharArray[Key] := MenuKeyCaps[mkcNumDivide]; VK_MULTIPLY: VKToCharArray[Key] := MenuKeyCaps[mkcNumMultiply]; VK_SUBTRACT: VKToCharArray[Key] := MenuKeyCaps[mkcNumSubstract]; VK_ADD: VKToCharArray[Key] := MenuKeyCaps[mkcNumAdd]; VK_F1..VK_F24: VKToCharArray[Key] := 'F' + IntToStr(Key - VK_F1 + 1); VK_LCL_MINUS: VKToCharArray[Key] := '-'; VK_LCL_EQUAL: VKToCharArray[Key] := '='; VK_LCL_OPEN_BRACKET: VKToCharArray[Key] := '['; VK_LCL_CLOSE_BRACKET: VKToCharArray[Key] := ']'; VK_LCL_BACKSLASH: VKToCharArray[Key] := '\'; VK_LCL_SEMI_COMMA: VKToCharArray[Key] := ';'; VK_LCL_QUOTE: VKToCharArray[Key] := ''''; VK_LCL_COMMA: VKToCharArray[Key] := ','; VK_LCL_POINT: VKToCharArray[Key] := '.'; VK_LCL_SLASH: VKToCharArray[Key] := '/'; VK_LCL_TILDE: VKToCharArray[Key] := '`'; else VKToCharArray[Key] := VirtualKeyToUTF8Char(Key, []); end; end; {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} {en Retrieves the character and respective modifiers state for the given keysym and given level. } procedure XKeysymToUTF8Char(XKeysym: TKeySym; ShiftLevel: Cardinal; out ShiftState: TShiftState; out KeyChar: TUTF8Char); var XKeycode: TKeyCode; XKeyEvent: TXKeyEvent; KeySymChars: array[0..16] of Char; KeySymCharLen: Integer; Level: Integer; begin KeyChar := ''; ShiftState := []; XKeycode := XKeysymToKeycode(XDisplay, XKeysym); if XKeycode <> 0 then begin // 4 levels - two groups of two characters each (unshifted/shifted). // AltGr is usually the group switch. for Level := 0 to 3 do begin if XKeysym = XKeycodeToKeysym(XDisplay, XKeyCode, Level) then begin // Init dummy XEvent to retrieve the char corresponding to the keycode. FillChar(XKeyEvent, SizeOf(XKeyEvent), 0); XKeyEvent._Type := KeyPress; XKeyEvent.Display := XDisplay; XKeyEvent.Same_Screen := TBool(1); // True XKeyEvent.KeyCode := XKeyCode; case ShiftLevel of 0: XKeyEvent.State := 0; // 1st group 1: XKeyEvent.State := ShiftMask; // 1st group 2: XKeyEvent.State := AltGrMask; // 2nd group 3: XKeyEvent.State := AltGrMask or ShiftMask; // 2nd group else XKeyEvent.State := 0; end; // Retrieve the character for this KeySym. KeySymCharLen := XLookupString(@XKeyEvent, KeySymChars, SizeOf(KeySymChars), nil, nil); // Delete ending zero. if (KeySymCharLen > 0) and (KeySymChars[KeySymCharLen - 1] = #0) then Dec(KeySymCharLen); if KeySymCharLen > 0 then begin SetString(KeyChar, KeySymChars, KeySymCharLen); // Get modifier keys of the found keysym. case Level of 0: ShiftState := []; 1: ShiftState := [ssShift]; 2: ShiftState := [ssAltGr]; 3: ShiftState := [ssShift, ssAltGr]; end; end; Exit; end end; end; end; {$ENDIF} function GetKeyShiftStateEx: TShiftState; {$IF DEFINED(LCLGTK2) and DEFINED(X11)} function GetKeyState(nVirtKey: Integer): Smallint; var Mask, State: TGdkModifierType; begin Result := LCLIntf.GetKeyState(nVirtKey); case nVirtKey of VK_SHIFT, VK_LSHIFT, VK_RSHIFT : Mask := GDK_SHIFT_MASK; VK_CONTROL, VK_LCONTROL, VK_RCONTROL : Mask := GDK_CONTROL_MASK; else Exit; end; State := -1; gdk_window_get_pointer(nil, nil, nil, @State); if (State <> -1) and (State and Mask = 0) then Result := 0; end; {$ENDIF} function IsKeyDown(Key: Integer): Boolean; begin Result := (GetKeyState(Key) and $8000) <> 0; end; procedure GetMouseButtonState; var bSwapButton: Boolean; begin bSwapButton:= GetSystemMetrics(SM_SWAPBUTTON) <> 0; if IsKeyDown(VK_LBUTTON) then begin if bSwapButton then Include(Result, ssRight) else Include(Result, ssLeft); end; if IsKeyDown(VK_RBUTTON) then begin if bSwapButton then Include(Result, ssLeft) else Include(Result, ssRight); end; end; begin Result:=[]; GetMouseButtonState; {$IFDEF MSWINDOWS} if HasKeyboardAltGrKey then begin // Windows maps AltGr as Ctrl+Alt combination, so if AltGr is pressed, // it cannot be detected if Ctrl is pressed too. Therefore if AltGr // is pressed we don't include Ctrl in the result. Unless Left Alt is also // pressed - then we do include it under the assumption that the user // pressed Ctrl+Left Alt. The limitation is that a combination of // LeftAlt + AltGr is reported as [ssCtrl, ssAlt, ssAltGr]. if IsKeyDown(VK_LCONTROL) and ((not IsKeyDown(VK_RMENU)) or IsKeyDown(VK_LMENU)) then Include(Result,ssCtrl); if IsKeyDown(VK_RMENU) then Include(Result,ssAltGr); end else {$ENDIF} begin if IsKeyDown(VK_RMENU) or IsKeyDown(VK_MENU) then Include(Result,ssAlt); if IsKeyDown(VK_LCONTROL) or IsKeyDown(VK_CONTROL) then Include(Result,ssCtrl); end; {$IF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2))} if (VK_ALTGR <> VK_UNDEFINED) and IsKeyDown(VK_ALTGR) then Include(Result,ssAltGr); {$ENDIF} {$IF DEFINED(X11) and DEFINED(LCLQT)} // QtGroupSwitchModifier is only recognized on X11. if (QApplication_keyboardModifiers and QtGroupSwitchModifier) > 0 then Include(Result,ssAltGr); {$ENDIF} if IsKeyDown(VK_RCONTROL) then Include(Result, ssCtrl); if IsKeyDown(VK_LMENU) then Include(Result, ssAlt); if IsKeyDown(VK_SHIFT) then Include(Result, ssShift); if IsKeyDown(VK_LWIN) or IsKeyDown(VK_RWIN) then Include(Result, ssMeta); if (GetKeyState(VK_CAPITAL) and $1) <> 0 then // Caps-lock toggled Include(Result, ssCaps); end; function KeyToShortCutEx(Key: Word; Shift: TShiftState): TShortCut; begin Result := (Key and $FF) or ShiftToShortcutEx(Shift); end; function ModifiersTextToShortcutEx(const ModifiersText: String; out ModLength: Integer): TShortCut; var StartPos: Integer; i: Integer = 0; Found: Boolean = True; function CompareFront(const Front: String): Boolean; begin if (Front <> '') and (StartPos + length(Front) - 1 <= length(ModifiersText)) and (AnsiStrLIComp(@ModifiersText[StartPos], PChar(Front), Length(Front)) = 0) then begin Result := True; Inc(StartPos, length(Front)); end else Result := False; end; begin Result := 0; StartPos := 1; while Found do begin Found := False; for i := Low(ModifiersMap) to High(ModifiersMap) do begin if CompareFront(MenuKeyCaps[ModifiersMap[i].Text]) then begin Result := Result or ModifiersMap[i].Shortcut; Found := True; Break; end; end; // Special case if not Found then begin if CompareFront(SmkcAtem) then begin Result := Result or scMeta; Found := True; end; end; end; ModLength := StartPos - 1; end; function NormalizeModifiers(ShortCutText: String): String; var ModLength: Integer; Shortcut: TShortCut; begin Shortcut := ModifiersTextToShortcutEx(ShortCutText, ModLength); Result := ShiftToTextEx(ShortcutToShiftEx(Shortcut)) + Copy(ShortCutText, ModLength + 1, MaxInt); end; function ShiftToShortcutEx(ShiftState: TShiftState): TShortCut; var i: Integer; begin Result := 0; for i := Low(ModifiersMap) to High(ModifiersMap) do begin if ModifiersMap[i].Shift in ShiftState then Inc(Result, ModifiersMap[i].Shortcut); end; end; function ShiftToTextEx(ShiftState: TShiftState): String; var i: Integer; begin Result := EmptyStr; for i := Low(ModifiersMap) to High(ModifiersMap) do begin if ModifiersMap[i].Shift in ShiftState then Result := Result + MenuKeyCaps[ModifiersMap[i].Text]; end; end; function ShortcutToShiftEx(Shortcut: TShortCut): TShiftState; var i: Integer; begin Result := []; for i := Low(ModifiersMap) to High(ModifiersMap) do begin if Shortcut and ModifiersMap[i].Shortcut <> 0 then Include(Result, ModifiersMap[i].Shift); end; end; function ShortCutToTextEx(ShortCut: TShortCut): String; begin Result := VirtualKeyToText(Byte(ShortCut and $FF), ShortcutToShiftEx(ShortCut)); end; function TextToShortCutEx(const ShortCutText: String): TShortCut; var Key: TShortCut; Shift: TShortCut; Name: String; StartPos: Integer; begin Result := 0; Shift := ModifiersTextToShortcutEx(ShortCutText, StartPos); Inc(StartPos); // Get text for the key if anything left in the string. if StartPos <= Length(ShortCutText) then begin { Copy range from table in ShortCutToText } for Key := $08 to $FF do begin Name := VirtualKeyToText(Key); if (Name <> '') and (length(Name) = length(ShortCutText) - StartPos + 1) and (AnsiStrLIComp(@ShortCutText[StartPos], PChar(Name), length(Name)) = 0) then begin Exit(Key or Shift); end; end; end; end; function VirtualKeyToUTF8Char(Key: Byte; ShiftState: TShiftState): TUTF8Char; {$IF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} function ShiftStateToXModifierLevel(ShiftState: TShiftState): Cardinal; begin Result := 0; if ssShift in ShiftState then Result := Result or 1; if ssAltGr in ShiftState then Result := Result or 2; end; {$ENDIF} var {$IF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2))} KeyInfo: TVKeyInfo; {$ENDIF} ShiftedChar: Boolean; {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} KeyChar:TUTF8Char; KeySym: TKeySym; TempShiftState: TShiftState; {$ENDIF} begin Result := ''; // Upper case if either caps-lock is toggled or shift pressed. ShiftedChar := (ssCaps in ShiftState) xor (ssShift in ShiftState); {$IF DEFINED(MSWINDOWS)} Result := GetInternationalCharacter(Key, GetKeyShiftStateEx - ShiftState); {$ELSEIF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2))} KeyInfo := GetVKeyInfo(Key); // KeyInfo.KeyChar contains characters according to modifiers: // [0] - unshifted [2] - unshifted + AltGr // [1] - shifted [3] - shifted + AltGr // Caps-lock is handled below with ShiftedChar variable. Result := KeyInfo.KeyChar[ShiftStateToXModifierLevel(ShiftState)]; {$ELSEIF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} if (XDisplay = nil) then Exit; // For QT we'll use Xlib to get text for a key. KeySym := 0; case Key of VK_0..VK_9: Result := Char(Ord('0') + Key - VK_0); VK_A..VK_Z: Result := Char(Ord('A') + Key - VK_A); VK_NUMPAD0.. VK_NUMPAD9: Result := Char(Ord('0') + Key - VK_NUMPAD0); VK_MULTIPLY: KeySym := XK_KP_Multiply; VK_ADD: KeySym := XK_KP_Add; VK_SUBTRACT: KeySym := XK_KP_Subtract; VK_DIVIDE: KeySym := XK_KP_Divide; // These VKs might only work for US-layout keyboards. VK_OEM_PLUS: KeySym := XK_plus; VK_OEM_MINUS: KeySym := XK_minus; VK_OEM_COMMA: KeySym := XK_comma; VK_OEM_PERIOD: KeySym := XK_period; VK_SEPARATOR: KeySym := XK_comma; VK_DECIMAL: KeySym := XK_period; VK_OEM_1: KeySym := XK_semicolon; VK_OEM_3: KeySym := XK_quoteleft; VK_OEM_4: KeySym := XK_bracketleft; VK_OEM_5: KeySym := XK_backslash; VK_OEM_6: KeySym := XK_bracketright; VK_OEM_7: KeySym := XK_apostrophe; // Some additional keys for QT not mapped in TQtWidget.QtKeyToLCLKey. // Based on QT sources: src/gui/kernel/qkeymapper_x11.cpp. QtKey_Bar: KeySym := XK_bar; QtKey_Underscore: KeySym := XK_underscore; QtKey_Question: KeySym := XK_question; QtKey_AsciiCircum: KeySym := XK_asciicircum; // $C1 - $DA not used VK space // Some of these keys (not translated in QtKeyToLCLKey) are on international keyboards. QtKey_Aacute: KeySym := XK_aacute; QtKey_Acircumflex: KeySym := XK_acircumflex; QtKey_Atilde: KeySym := XK_atilde; QtKey_Adiaeresis: KeySym := XK_adiaeresis; QtKey_Aring: KeySym := XK_aring; QtKey_AE: KeySym := XK_ae; QtKey_Ccedilla: KeySym := XK_ccedilla; QtKey_Egrave: KeySym := XK_egrave; QtKey_Eacute: KeySym := XK_eacute; QtKey_Ecircumflex: KeySym := XK_ecircumflex; QtKey_Ediaeresis: KeySym := XK_ediaeresis; QtKey_Igrave: KeySym := XK_igrave; QtKey_Iacute: KeySym := XK_iacute; QtKey_Icircumflex: KeySym := XK_icircumflex; QtKey_Idiaeresis: KeySym := XK_idiaeresis; QtKey_ETH: KeySym := XK_eth; QtKey_Ntilde: KeySym := XK_ntilde; QtKey_Ograve: KeySym := XK_ograve; QtKey_Oacute: KeySym := XK_oacute; QtKey_Ocircumflex: KeySym := XK_ocircumflex; QtKey_Otilde: KeySym := XK_otilde; QtKey_Odiaeresis: KeySym := XK_odiaeresis; QtKey_multiply: KeySym := XK_multiply; QtKey_Ooblique: KeySym := XK_ooblique; QtKey_Ugrave: KeySym := XK_ugrave; QtKey_Uacute: KeySym := XK_uacute; end; if KeySym <> 0 then begin // Get character for a key with the given keysym // and with given modifiers applied. // Don't care about modifiers state, because we already have it. XKeysymToUTF8Char(KeySym, ShiftStateToXModifierLevel(ShiftState), TempShiftState, KeyChar); Result := KeyChar; end; {$ELSE} {$ENDIF} // Make upper case if either caps-lock is toggled or shift pressed. if Result <> '' then begin if ShiftedChar then Result := UTF8UpperCase(Result) else Result := UTF8LowerCase(Result); end; end; function VirtualKeyToText(Key: Byte; ShiftState: TShiftState): string; var Name: string; {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} KeyChar: TUTF8Char; KeySym: TKeySym; TempShiftState: TShiftState; {$ENDIF} begin {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} // Overwrite behaviour for some keys in QT. case Key of QtKey_Bar: KeySym := XK_bar; // VK_F13 QtKey_Underscore: KeySym := XK_underscore; // VK_SLEEP QtKey_QuoteLeft: KeySym := XK_quoteleft; else KeySym := 0; end; if (KeySym <> 0) and Assigned(XDisplay) then begin // Get base character for a key with the given keysym. // Don't care about modifiers state, because we already have it. XKeysymToUTF8Char(KeySym, 0, TempShiftState, KeyChar); Name := KeyChar; end else {$ENDIF} Name := VKToCharArray[Key]; if Name <> '' then Result := ShiftToTextEx(ShiftState) + Name else Result := ''; end; {$IF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2))} procedure UpdateGtkAltGrVirtualKeyCode; var VKNr: Byte; KeyInfo: TVKeyInfo; {$IFDEF LCLGTK2} GdkKey: TGdkKeymapKey = (KeyCode: 0; Group: 0; Level: 0); {$ENDIF} KeyVal: guint; begin VK_ALTGR := VK_UNDEFINED; // Search all virtual keys for a scancode of AltGraph. for VKNr := Low(Byte) to High(Byte) do begin KeyInfo := GetVKeyInfo(VKNr); if (KeyInfo.KeyCode[True] = 0) and // not extended (KeyInfo.KeyCode[False] <> 0) then begin {$IFDEF LCLGTK} KeyVal := XKeycodetoKeysym(XDisplay, KeyInfo.KeyCode[False], 0); if KeyVal = GDK_ISO_Level3_Shift then // AltGraph {$ELSE} GdkKey.keycode := KeyInfo.keycode[False]; KeyVal := gdk_keymap_lookup_key( gdk_keymap_get_for_display(XDisplay), @GdkKey); if KeyVal = GDK_KEY_ISO_Level3_Shift then // AltGraph {$ENDIF} begin VK_ALTGR := VKNr; Exit; end; end; end; end; {$ENDIF} {$IFDEF MSWINDOWS} function GetInternationalCharacter(Key: Word; ExcludeShiftState: TShiftState): TUTF8Char; var KeyboardState: array [0..255] of byte; wideChars: widestring; asciiChar: AnsiChar; IntResult: LongInt; function IsKeyDown(Key: Byte): Boolean; begin Result := (KeyboardState[Key] and $80)<>0; end; begin Result := ''; SetLength(wideChars, 16); // should be enough Windows.GetKeyboardState(KeyboardState); // Exclude not wanted modifiers. if ssCtrl in ExcludeShiftState then begin KeyboardState[VK_RCONTROL] := 0; if (not HasKeyboardAltGrKey) or (ssAltGr in ExcludeShiftState) or (not IsKeyDown(VK_RMENU)) // if AltGr not pressed then KeyboardState[VK_LCONTROL] := 0; end; if ssAlt in ExcludeShiftState then begin KeyboardState[VK_LMENU] := 0; if (not HasKeyboardAltGrKey) then KeyboardState[VK_RMENU] := 0; end; if ssAltGr in ExcludeShiftState then begin KeyboardState[VK_RMENU] := 0; if not IsKeyDown(VK_LMENU) then // if Left Alt not pressed KeyboardState[VK_LCONTROL] := 0; end; if ssCaps in ExcludeShiftState then KeyboardState[VK_CAPITAL] := 0; if ssShift in ExcludeShiftState then begin KeyboardState[VK_LSHIFT] := 0; KeyboardState[VK_RSHIFT] := 0; KeyboardState[VK_SHIFT] := 0; end; if (not IsKeyDown(VK_LCONTROL)) and (not IsKeyDown(VK_RCONTROL)) then KeyboardState[VK_CONTROL] := 0; if (not IsKeyDown(VK_LMENU)) and (not IsKeyDown(VK_RMENU)) then KeyboardState[VK_MENU] := 0; if (Win32Platform = VER_PLATFORM_WIN32_NT) then begin IntResult := Windows.ToUnicode(Key, 0, @KeyboardState, PWChar(wideChars), Length(wideChars), 0); if IntResult = 1 then Result := UTF8Copy(UTF16ToUTF8(wideChars), 1, 1); end else begin IntResult := Windows.ToAscii(Key, 0, @KeyboardState, @asciiChar, 0); if IntResult = 1 then Result := AnsiToUtf8(string(asciiChar)); end; end; procedure UpdateKeyboardLayoutAltGrFlag; type PKBDTABLES = ^KBDTABLES; KBDTABLES = record // not packed pCharModifers: Pointer; pVkToWCharTable: Pointer; pDeadKey: Pointer; pKeyNames: Pointer; pKeyNamesExt: Pointer; pKeyNamesDead: Pointer; pUsVscToVk: Pointer; MaxVscToVk: Byte; pVSCToVk_E0: Pointer; pVSCToVk_E1: Pointer; LocalFlags: DWORD; // <-- we only need this LgMaxD: Byte; cbLgEntry: Byte; pLigature: Pointer; end; const KBDTABLE_VERSION = 1; // Flags KLLF_ALTGR = 1; //KLLF_SHIFTLOCK = 2; //KLLF_LRM_RLM = 4; function GetKeyboardLayoutFileName: WideString; var KeyHandle: HKEY; KeyboardLayoutName: array [0..KL_NAMELENGTH-1] of WChar; RegistryKey : WideString = 'SYSTEM\CurrentControlSet\Control\Keyboard Layouts\'; RegistryValue: WideString = 'Layout File'; BytesNeeded: DWORD; begin Result := ''; // Get current keyboard layout ID. if GetKeyboardLayoutNameW(KeyboardLayoutName) then begin RegistryKey := RegistryKey + PWChar(KeyboardLayoutName); // Read corresponding layout dll name from registry. if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, PWChar(RegistryKey), 0, KEY_QUERY_VALUE, @KeyHandle) = ERROR_SUCCESS) and (KeyHandle <> 0) then begin if RegQueryValueExW(KeyHandle, PWChar(RegistryValue), nil, nil, nil, @BytesNeeded) = ERROR_SUCCESS then begin SetLength(Result, BytesNeeded div SizeOf(WChar)); if RegQueryValueExW(KeyHandle, PWChar(RegistryValue), nil, nil, PByte(PWChar(Result)), @BytesNeeded) = ERROR_SUCCESS then begin Result := Result + #0; // end with zero to be sure end; end; RegCloseKey(KeyHandle); end; end; end; function GetKeyboardLayoutAltGrFlag(LayoutDllFileName: WideString): Boolean; type TKbdLayerDescriptor = function: PKBDTABLES; stdcall; var Handle: HMODULE; KbdLayerDescriptor: TKbdLayerDescriptor; Tables: PKBDTABLES; begin Result := False; // Load the keyboard layout dll. Handle := LoadLibraryW(PWChar(LayoutDllFileName)); if Handle <> 0 then begin KbdLayerDescriptor := TKbdLayerDescriptor(GetProcAddress(Handle, 'KbdLayerDescriptor')); if Assigned(KbdLayerDescriptor) then begin // Get the layout tables. Tables := KbdLayerDescriptor(); if Assigned(Tables) and (HIWORD(Tables^.LocalFlags) = KBDTABLE_VERSION) then begin // Read AltGr flag. Result := Boolean(Tables^.LocalFlags and KLLF_ALTGR); end; end; FreeLibrary(Handle); end; end; var FileName: WideString; begin HasKeyboardAltGrKey := False; FileName := GetKeyboardLayoutFileName; if FileName <> '' then HasKeyboardAltGrKey := GetKeyboardLayoutAltGrFlag(FileName); end; {$ENDIF} {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} procedure UpdateModifiersMasks; var Map: PXModifierKeymap; KeyCode: PKeyCode; KeySym: TKeySym; ModifierNr, l, Level: Integer; begin ShiftMask := 0; AltGrMask := 0; if Assigned(XDisplay) then begin Map := XGetModifierMapping(XDisplay); if Assigned(Map) then begin KeyCode := Map^.modifiermap; for ModifierNr := 0 to 7 do // Xlib uses up to 8 modifiers. begin // Scan through possible keycodes for each modifier. // We're looking for the keycodes assigned to Shift and AltGr. for l := 1 to Map^.max_keypermod do begin if KeyCode^ <> 0 then // Omit zero keycodes. begin for Level := 0 to 3 do // Check group 1 and group 2 (each has 2 keysyms) begin // Translate each keycode to keysym and check // if this is the modifier we are looking for. KeySym := XKeycodeToKeysym(XDisplay, KeyCode^, Level); // If found, assign mask according the the modifier number // (Shift by default should be the first modifier). case KeySym of XK_Mode_switch: AltGrMask := 1 shl ModifierNr; XK_Shift_L, XK_Shift_R: ShiftMask := 1 shl ModifierNr; end; end; end; Inc(KeyCode); end; end; XFreeModifiermap(Map); end; end; end; {$ENDIF} procedure OnKeyboardLayoutChanged; begin {$IFDEF MSWINDOWS} UpdateKeyboardLayoutAltGrFlag; {$ENDIF} {$IF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2))} UpdateGtkAltGrVirtualKeyCode; {$ENDIF} {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} UpdateModifiersMasks; {$ENDIF} CacheVKToChar; end; {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} constructor TKeyboardLayoutChangedHook.Create(QObject: QObjectH); begin EventHook := QObject_hook_create(QObject); if Assigned(EventHook) then begin QObject_hook_hook_events(EventHook, @EventFilter); end; end; destructor TKeyboardLayoutChangedHook.Destroy; begin if Assigned(EventHook) then begin QObject_hook_destroy(EventHook); EventHook := nil; end; end; function TKeyboardLayoutChangedHook.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; begin Result := False; // Don't filter any events. // Somehow this event won't be sent to the window, // unless the user first presses a key inside it. if QEvent_type(Event) = QEventKeyboardLayoutChange then begin OnKeyboardLayoutChanged; end; end; {$ENDIF} {$IF DEFINED(UNIX)} {$IF DEFINED(LCLGTK)} function EventHandler(GdkXEvent: PGdkXEvent; GdkEvent: PGdkEvent; Data: gpointer): TGdkFilterReturn; cdecl; var XEvent: xlib.PXEvent; XMappingEvent: PXMappingEvent; begin Result := GDK_FILTER_CONTINUE; // Don't filter any events. XEvent := xlib.PXEvent(GdkXEvent); case XEvent^._type of MappingNotify{, 112}: begin XMappingEvent := PXMappingEvent(XEvent); case XMappingEvent^.request of MappingModifier, MappingKeyboard: begin XRefreshKeyboardMapping(XMappingEvent); OnKeyboardLayoutChanged; end; // Don't care about MappingPointer. end; end; end; end; {$ELSEIF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} procedure KeysChangedSignalHandler(keymap: PGdkKeymap; Data: gpointer); cdecl; begin OnKeyboardLayoutChanged; end; {$ENDIF} {$ENDIF} procedure UnhookKeyboardLayoutChanged; begin {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} if Assigned(KeyboardLayoutChangedHook) then FreeAndNil(KeyboardLayoutChangedHook); {$ELSEIF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2) or DEFINED(LCLGTK3))} {$IF DEFINED(LCLGTK)} gdk_window_remove_filter(nil, @EventHandler, nil); {$ELSEIF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} if (KeysChangesSignalHandlerId <> 0) and g_signal_handler_is_connected(gdk_keymap_get_for_display(XDisplay), KeysChangesSignalHandlerId) then begin g_signal_handler_disconnect(gdk_keymap_get_for_display(XDisplay), KeysChangesSignalHandlerId); KeysChangesSignalHandlerId := 0; end; {$ENDIF} {$ENDIF} end; procedure HookKeyboardLayoutChanged; begin UnhookKeyboardLayoutChanged; // On Unix (X server) the event for changing keyboard layout // is sent twice (on QT, GTK1 and GTK2). {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} KeyboardLayoutChangedHook := KeyboardLayoutChangedHook.Create( TQtWidget(Application.MainForm.Handle).TheObject); {$ELSEIF DEFINED(UNIX) and (DEFINED(LCLGTK) or DEFINED(LCLGTK2) or DEFINED(LCLGTK3))} // On GTK1 XLib's MappingNotify event is used to detect keyboard mapping changes. // On GTK2 however (at least on my system), an event of type 112 instead of 34 // (which is a correct value for MappingNotify) is received, yet max value for // an event is 35. So, on GTK2 a GdkKeymap signal is used instead. {$IF DEFINED(LCLGTK)} gdk_window_add_filter(nil, @EventHandler, nil); // Filter events for all windows. {$ELSEIF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} // Connect to GdkKeymap object for the given display. KeysChangesSignalHandlerId := g_signal_connect_data(gdk_keymap_get_for_display(XDisplay), 'keys-changed', TGCallback(@KeysChangedSignalHandler), nil, nil, {$IFDEF LCLGTK2}0{$ELSE}[]{$ENDIF}); {$ENDIF} {$ENDIF} end; function IsShortcutConflictingWithOS(Shortcut: String): Boolean; const KEY_HIGH = {$IF DEFINED(DARWIN)}28{$ELSE}27{$ENDIF}; const ConflictingShortcuts: array [0..KEY_HIGH] of String = (SmkcBkSp, // Delete previous character SmkcDel, // Delete next character SmkcLeft, // Move cursor left SmkcRight, // Move cursor right SmkcSpace, // Space {$IF DEFINED(DARWIN)} SmkcCmd + SmkcSpace, // Spotlight (Mac OS X) {$ENDIF DARWIN} SmkcWin, // Context menu SmkcShift + 'F10', // Context menu SmkcShift + SmkcDel, // Cut text SmkcShift + SmkcIns, // Paste text SmkcShift + SmkcHome, // Select to beginning SmkcShift + SmkcEnd, // Select to end SmkcShift + SmkcLeft, // Select previous character SmkcShift + SmkcRight, // Select next character SmkcSuper + 'A', // Select all SmkcSuper + 'C', // Copy text SmkcSuper + 'V', // Paste text SmkcSuper + 'X', // Cut text SmkcSuper + 'Z', // Undo SmkcSuper + SmkcBkSp, // Delete previous word SmkcSuper + SmkcDel, // Delete next word SmkcSuper + SmkcIns, // Copy text SmkcSuper + SmkcHome, // Move to beginning SmkcSuper + SmkcEnd, // Move to end SmkcSuper + SmkcLeft, // Move to beginning of word SmkcSuper + SmkcRight, // Move to end of word SmkcSuper + SmkcShift + 'Z', // Redo SmkcSuper + SmkcShift + SmkcLeft, // Select to beginning of word SmkcSuper + SmkcShift + SmkcRight); // Select to end of word var i: Integer; begin for i := Low(ConflictingShortcuts) to High(ConflictingShortcuts) do if Shortcut = ConflictingShortcuts[i] then Exit(True); Result := False; end; procedure InitializeKeyboard; begin OnKeyboardLayoutChanged; end; procedure CleanupKeyboard; begin UnhookKeyboardLayoutChanged; end; {$IF DEFINED(X11)} initialization // Get connection to X server. {$IF DEFINED(LCLGTK)} XDisplay := gdk_display; {$ELSEIF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} XDisplay := gdk_display_get_default; {$ELSEIF (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} if not IsWayland then XDisplay := XOpenDisplay(nil); {$ENDIF} {$ENDIF} {$IF DEFINED(X11) and (DEFINED(LCLQT) or DEFINED(LCLQT5) OR DEFINED(LCLQT6))} finalization if Assigned(XDisplay) then XCloseDisplay(XDisplay); {$ENDIF} end. ��������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/umicrolibc.pas��������������������������������������������������������0000644�0001750�0000144�00000012072�14743153644�020060� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Some standard C library functions Copyright (C) 2017-2018 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uMicroLibC; {$mode objfpc}{$H+} interface uses SysUtils, CTypes {$IF DEFINED(UNIX)} , InitC {$ENDIF} ; {$IF DEFINED(MSWINDOWS)} const clib = 'msvcrt.dll'; const _IOFBF = $0000; _IONBF = $0004; _IOLBF = $0040; function fpgetCerrno: cint; procedure fpsetCerrno(err: cint); {$ELSE} const _IOFBF = 0; //* Fully buffered. */ _IOLBF = 1; //* Line buffered. */ _IONBF = 2; //* No buffering. */ function fpgetCerrno: cint; inline; {$ENDIF} function csystem(const command: String): cint; function cfopen(const path, mode: String): Pointer; function cpopen(const command, mode: String): Pointer; function cstrerror(errnum: cint): PAnsiChar; cdecl; external clib name 'strerror'; {$IF DEFINED(MSWINDOWS)} function cpclose(stream: Pointer): cint; cdecl; external clib name '_pclose'; {$ELSE} function cpclose(stream: Pointer): cint; cdecl; external clib name 'pclose'; {$ENDIF} function cftell(stream: Pointer): cuint32; cdecl; external clib name 'ftell'; function cfseek(stream: Pointer; offset: clong; origin: cint): cint; cdecl; external clib name 'fseek'; procedure cclearerr(stream: Pointer); cdecl; external clib name 'clearerr'; function cferror(stream: Pointer): cint; cdecl; external clib name 'ferror'; function csetvbuf(stream: Pointer; buffer: PAnsiChar; mode: cint; size: csize_t): cint; cdecl; external clib name 'setvbuf'; function cgetc(stream: Pointer): cint; cdecl; external clib name 'getc'; function cungetc(c: cint; stream: Pointer): cint; cdecl; external clib name 'ungetc'; function cfgets(str: PAnsiChar; n: cint; stream: Pointer): PAnsiChar; cdecl; external clib name 'fgets'; function cfread(buffer: Pointer; size, count: csize_t; stream: Pointer): csize_t; cdecl; external clib name 'fread'; function cfwrite(buffer: Pointer; size, count: csize_t; stream: Pointer): csize_t; cdecl; external clib name 'fwrite'; function cfflush(stream: Pointer): cint; cdecl; external clib name 'fflush'; function ctmpfile(): Pointer; cdecl; external clib name 'tmpfile'; function cfclose(stream: Pointer): cint; cdecl; external clib name 'fclose'; function cfprintf(stream: Pointer; format: PAnsiChar): cint; cdecl; varargs; external clib name 'fprintf'; function cfscanf(stream: Pointer; format: PAnsiChar; argument: Pointer): cint; cdecl; external clib name 'fscanf'; property cerrno: cint read fpgetCerrno write fpsetcerrno; implementation uses {$IF DEFINED(MSWINDOWS)} LazUTF8, DCWindows; {$ELSE} DCConvertEncoding; {$ENDIF} {$IF DEFINED(MSWINDOWS)} function _wsystem(const command: pwidechar): cint; cdecl; external clib; function _wfopen(const filename, mode: pwidechar): Pointer; cdecl; external clib; function _wpopen(const command, mode: pwidechar): Pointer; cdecl; external clib; function geterrnolocation: pcint; cdecl; external clib name '_errno'; function fpgetCerrno:cint; begin fpgetCerrno:= geterrnolocation^; end; procedure fpsetCerrno(err:cint); begin geterrnolocation^:= err; end; {$ELSE} function system(const command: PAnsiChar): cint; cdecl; external clib; function popen(const command, mode: PAnsiChar): Pointer; cdecl; external clib; function fopen(const filename, mode: PAnsiChar): Pointer; cdecl; external clib; function fpgetCerrno: cint; inline; begin Result:= InitC.fpgetCerrno; end; {$ENDIF} function cfopen(const path, mode: String): Pointer; {$IF DEFINED(MSWINDOWS)} begin Result:= _wfopen(PWideChar(UTF16LongName(path)), PWideChar(UnicodeString(mode))); end; {$ELSE} begin Result:= fopen(PAnsiChar(CeUtf8ToSys(path)), PAnsiChar(mode)); end; {$ENDIF} function cpopen(const command, mode: String): Pointer; {$IF DEFINED(MSWINDOWS)} begin Result:= _wpopen(PWideChar(UTF8ToUTF16(command)), PWideChar(UnicodeString(mode))); end; {$ELSE} begin cfflush(nil); Result:= popen(PAnsiChar(CeUtf8ToSys(command)), PAnsiChar(mode)); end; {$ENDIF} function csystem(const command: String): cint; {$IF DEFINED(MSWINDOWS)} begin Result:= _wsystem(PWideChar(UTF8ToUTF16(command))); end; {$ELSE} begin Result:= system(PAnsiChar(CeUtf8ToSys(command))); end; {$ENDIF} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/�����������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016204� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/darwin/����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017470� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/darwin/uapplemagnifiedmodefix.pas��������������������������������0000644�0001750�0000144�00000002424�14743153644�024705� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uAppleMagnifiedModeFix; {$mode objfpc}{$H+} {$modeswitch objectivec1} interface implementation uses BaseUnix, CocoaAll; const SecondStart = 'SecondStart'; AppleMagnifiedMode = 'AppleMagnifiedMode'; var UserDefaults: NSUserDefaults; function setenv(const name, value: pchar; overwrite: longint): longint; cdecl; external 'c' name 'setenv'; procedure ExportLanguage; var CurrentLocale: NSLocale; Language, Country: String; begin if fpGetEnv(PAnsiChar('LANG')) = '' then begin CurrentLocale:= NSLocale.currentLocale(); Country:= NSString(CurrentLocale.objectForKey(NSLocaleCountryCode)).UTF8String; Language:= NSString(CurrentLocale.objectForKey(NSLocaleLanguageCode)).UTF8String; if (Length(Language) > 0) and (Length(Country) > 0) then begin Language:= Language + '_' + Country + '.UTF-8'; setenv('LANG', PAnsiChar(Language), 1); WriteLn('Export LANG=' + Language); end; end; end; initialization {$IFDEF LCLQT} ExportLanguage; {$ENDIF} UserDefaults:= NSUserDefaults.standardUserDefaults; if not UserDefaults.boolForKey(NSSTR(SecondStart)) then begin UserDefaults.setBool_forKey(True, NSSTR(SecondStart)); UserDefaults.setBool_forKey(False, NSSTR(AppleMagnifiedMode)); UserDefaults.synchronize; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/darwin/udarwinfswatch.pas����������������������������������������0000644�0001750�0000144�00000055007�14743153644�023235� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains specific DARWIN FSEvent functions. Copyright (C) 2023 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2023 Rich Chang (rich2014.git@outlook.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Notes: 1. multiple directories can be monitored at the same time. DC generally monitors more than 2 directories (possibly much more than 2), just one TDarwinFSWatcher needed. 2. subdirectories monitor supported. 3. file attributes monitoring is supported, and monitoring of adding files, renaming files, deleting files is also supported. for comparison, file attributes monitoring is missing with kqueue/kevent. 4. Renamed Event fully supported from MacOS 10.13 5. CFRunLoop is used in TDarwinFSWatcher. because in DC a separate thread has been opened (in uFileSystemWatcher), it is more appropriate to use CFRunLoop than DispatchQueue. } unit uDarwinFSWatch; {$mode delphi} {$modeswitch objectivec2} interface uses Classes, SysUtils, Contnrs, SyncObjs, MacOSAll, CocoaAll, BaseUnix; type TDarwinFSWatchEventCategory = ( ecAttribChanged, ecCoreAttribChanged, ecXattrChanged, ecStructChanged, ecCreated, ecRemoved, ecRenamed, ecRootChanged, ecChildChanged, ecFile, ecDir, ecDropabled ); type TDarwinFSWatchEventCategories = set of TDarwinFSWatchEventCategory; type TInternalEvent = class private path: String; renamedPath: String; // only for Ranamed Event flags: FSEventStreamEventFlags; iNode: UInt64; private function deepCopy(): TInternalEvent; end; type TDarwinFSWatchEventSession = class private _list: TObjectList; public constructor create; overload; constructor create( const amount:size_t; eventPaths:CFArrayRef; flags:FSEventStreamEventFlagsPtr ); destructor destroy; override; private function deepCopy(): TDarwinFSWatchEventSession; function count(): Integer; function getItem( index:Integer ): TInternalEvent; procedure adjustSymlinkIfNecessary( index:Integer; watchPath:String; watchRealPath:String ); procedure adjustRenamedEventIfNecessary( index:Integer ); function isRenamed( event:TInternalEvent ): Boolean; property items[index: Integer]: TInternalEvent read getItem; default; end; type TDarwinFSWatchEvent = class private _categories: TDarwinFSWatchEventCategories; _watchPath: String; _fullPath: String; _renamedPath: String; _rawEventFlags: UInt32; _rawINode: UInt64; private procedure createCategories; {%H-}constructor create( const aWatchPath:String; const internalEvent:TInternalEvent ); public function isDropabled(): Boolean; function categoriesToStr(): String; function rawEventFlagsToStr(): String; public property categories: TDarwinFSWatchEventCategories read _categories; property watchPath: String read _watchPath; property fullPath: String read _fullPath; property renamedPath: String read _renamedPath; property rawEventFlags: UInt32 read _rawEventFlags; property rawINode: UInt64 read _rawINode; end; type TDarwinFSWatchCallBack = Procedure( event:TDarwinFSWatchEvent ) of object; type TDarwinFSWatcher = class private _watchPaths: NSMutableArray; _watchRealPaths: NSMutableArray; _streamPaths: NSArray; _callback: TDarwinFSWatchCallBack; _latency: Integer; _stream: FSEventStreamRef; _streamContext: FSEventStreamContext; _lastEventId: FSEventStreamEventId; _running: Boolean; _runLoop: CFRunLoopRef; _thread: TThread; _lockObject: TCriticalSection; _pathsSyncObject: TEventObject; public watchSubtree: Boolean; private procedure handleEvents( const originalSession:TDarwinFSWatchEventSession ); procedure doCallback( const watchPath:String; const internalEvent:TInternalEvent ); procedure updateStream; procedure closeStream; procedure waitPath; procedure notifyPath; procedure interrupt; public constructor create( const callback:TDarwinFSWatchCallBack; const latency:Integer=300 ); destructor destroy; override; procedure start; procedure terminate; procedure addPath( path:String ); procedure removePath( path:String ); procedure clearPath; end; implementation const kFSEventStreamCreateFlagUseExtendedData = $00000040; kFSEventStreamEventFlagItemIsHardlink = $00100000; kFSEventStreamEventFlagItemIsLastHardlink = $00200000; kFSEventStreamEventFlagItemCloned = $00400000; CREATE_FLAGS= kFSEventStreamCreateFlagFileEvents or kFSEventStreamCreateFlagWatchRoot or kFSEventStreamCreateFlagNoDefer or kFSEventStreamCreateFlagUseCFTypes or kFSEventStreamCreateFlagUseExtendedData; NSAppKitVersionNumber10_13 = 1561; var kFSEventStreamEventExtendedDataPathKey: CFStringRef; kFSEventStreamEventExtendedFileIDKey: CFStringRef; isFlagUseExtendedDataSupported: Boolean; function StringToNSString(const S: String): NSString; begin Result:= NSString(NSString.stringWithUTF8String(PAnsiChar(S))); end; constructor TDarwinFSWatchEvent.create( const aWatchPath:String; const internalEvent:TInternalEvent ); begin Inherited Create; _watchPath:= aWatchPath; _fullPath:= internalEvent.path; _renamedPath:= internalEvent.renamedPath; _rawEventFlags:= internalEvent.flags; _rawINode:= internalEvent.iNode; createCategories; end; procedure TDarwinFSWatchEvent.createCategories; begin _categories:= []; if (_rawEventFlags and ( kFSEventStreamEventFlagItemModified or kFSEventStreamEventFlagItemChangeOwner or kFSEventStreamEventFlagItemInodeMetaMod )) <> 0 then _categories += [ecAttribChanged, ecCoreAttribChanged]; if (_rawEventFlags and ( kFSEventStreamEventFlagItemFinderInfoMod or kFSEventStreamEventFlagItemXattrMod )) <> 0 then _categories += [ecAttribChanged, ecXattrChanged]; if (_rawEventFlags and kFSEventStreamEventFlagItemCreated)<>0 then _categories += [ecStructChanged, ecCreated]; if (_rawEventFlags and kFSEventStreamEventFlagItemRemoved)<>0 then _categories += [ecStructChanged, ecRemoved]; if (_rawEventFlags and kFSEventStreamEventFlagItemRenamed)<>0 then _categories += [ecStructChanged, ecRenamed]; if (_rawEventFlags and kFSEventStreamEventFlagRootChanged)<>0 then begin _categories += [ecRootChanged]; end else begin if (_fullPath<>watchPath) and (_fullPath.CountChar(PathDelim)<>_watchPath.CountChar(PathDelim)+1) then begin if (_renamedPath.IsEmpty) or ((_renamedPath<>watchPath) and (_renamedPath.CountChar(PathDelim)<>_watchPath.CountChar(PathDelim)+1)) then _categories += [ecChildChanged]; end; end; if (_rawEventFlags and kFSEventStreamEventFlagItemIsFile)<>0 then _categories += [ecFile]; if (_rawEventFlags and kFSEventStreamEventFlagItemIsDir)<>0 then _categories += [ecDir]; if _categories * [ecAttribChanged,ecStructChanged,ecRootChanged] = [] then _categories:= [ecDropabled]; end; function TDarwinFSWatchEvent.isDropabled(): Boolean; begin Result:= _categories = [ecDropabled]; end; function TDarwinFSWatchEvent.categoriesToStr(): String; begin Result:= EmptyStr; if ecAttribChanged in _categories then Result += '|Attrib'; if ecCoreAttribChanged in _categories then Result += '|CoreAttrib'; if ecXattrChanged in _categories then Result += '|Xattr'; if ecStructChanged in _categories then Result += '|Struct'; if ecCreated in _categories then Result += '|Created'; if ecRemoved in _categories then Result += '|Removed'; if ecRenamed in _categories then Result += '|Renamed'; if ecRootChanged in _categories then Result += '|Root'; if ecChildChanged in _categories then Result += '|Child'; if ecDropabled in _categories then Result += '|Dropabled'; Result:= Result.TrimLeft( '|' ); end; function TDarwinFSWatchEvent.rawEventFlagsToStr(): String; begin Result:= EmptyStr; if (_rawEventFlags and kFSEventStreamEventFlagItemModified)<>0 then Result += '|Modified'; if (_rawEventFlags and kFSEventStreamEventFlagItemChangeOwner)<>0 then Result += '|ChangeOwner'; if (_rawEventFlags and kFSEventStreamEventFlagItemInodeMetaMod)<>0 then Result += '|InodeMetaMod'; if (_rawEventFlags and kFSEventStreamEventFlagItemFinderInfoMod)<>0 then Result += '|FinderInfoMod'; if (_rawEventFlags and kFSEventStreamEventFlagItemXattrMod)<>0 then Result += '|XattrMod'; if (_rawEventFlags and kFSEventStreamEventFlagItemCreated)<>0 then Result += '|Created'; if (_rawEventFlags and kFSEventStreamEventFlagItemRemoved)<>0 then Result += '|Removed'; if (_rawEventFlags and kFSEventStreamEventFlagItemRenamed)<>0 then Result += '|Renamed'; if (_rawEventFlags and kFSEventStreamEventFlagRootChanged)<>0 then Result += '|RootChanged'; if (_rawEventFlags and kFSEventStreamEventFlagItemIsFile)<>0 then Result += '|IsFile'; if (_rawEventFlags and kFSEventStreamEventFlagItemIsDir)<>0 then Result += '|IsDir'; if (_rawEventFlags and kFSEventStreamEventFlagItemIsSymlink)<>0 then Result += '|IsSymlink'; if (_rawEventFlags and kFSEventStreamEventFlagItemIsHardlink)<>0 then Result += '|IsHardLink'; if (_rawEventFlags and kFSEventStreamEventFlagItemIsLastHardlink)<>0 then Result += '|IsLastHardLink'; if (_rawEventFlags and kFSEventStreamEventFlagMustScanSubDirs)<>0 then Result += '|ScanSubDirs'; if (_rawEventFlags and kFSEventStreamEventFlagUserDropped)<>0 then Result += '|UserDropped'; if (_rawEventFlags and kFSEventStreamEventFlagKernelDropped)<>0 then Result += '|KernelDropped'; if (_rawEventFlags and kFSEventStreamEventFlagEventIdsWrapped)<>0 then Result += '|IdsWrapped'; if (_rawEventFlags and kFSEventStreamEventFlagHistoryDone)<>0 then Result += '|HistoryDone'; if (_rawEventFlags and kFSEventStreamEventFlagMount)<>0 then Result += '|Mount'; if (_rawEventFlags and kFSEventStreamEventFlagUnmount)<>0 then Result += '|Unmount'; if (_rawEventFlags and kFSEventStreamEventFlagOwnEvent)<>0 then Result += '|OwnEvent'; if (_rawEventFlags and kFSEventStreamEventFlagItemCloned)<>0 then Result += '|Cloned'; if (_rawEventFlags and $FF800000)<>0 then Result:= '|*UnkownFlags:' + IntToHex(_rawEventFlags) + '*' + Result; if Result.IsEmpty then Result:= '*NoneFlag*' else Result:= Result.TrimLeft( '|' ); end; // Note: try to avoid string copy function isMatchWatchPath( const internalEvent:TInternalEvent; const watchPath:String; const watchSubtree:Boolean ): Boolean; var fullPath: String; fullPathDeep: Integer; watchPathDeep: Integer; begin fullPath:= internalEvent.path;; // detect if fullPath=watchPath if (internalEvent.flags and (kFSEventStreamEventFlagItemIsDir or kFSEventStreamEventFlagRootChanged)) <> 0 then begin Result:= watchPath.Equals( fullPath ); if Result then exit; // fullPath=watchPath, matched end; // detect if fullPath startsWith watchPath Result:= fullPath.StartsWith(watchPath); if watchSubtree then exit; // not watchSubtree // not startsWith watchPath, not match if not Result then exit; // not watchSubtree, and startsWith watchPath // detect if fullPath and watchPath in the same level fullPathDeep:= fullPath.CountChar(PathDelim); watchPathDeep:= watchPath.CountChar(PathDelim)+1; Result:= fullPathDeep=watchPathDeep; end; function TInternalEvent.deepCopy(): TInternalEvent; begin Result:= TInternalEvent.Create; Result.path:= self.path; Result.renamedPath:= self.renamedPath; Result.flags:= self.flags; Result.iNode:= self.iNode; end; function TDarwinFSWatchEventSession.deepCopy(): TDarwinFSWatchEventSession; var list: TObjectList; i: Integer; begin list:= TObjectList.Create; for i:=0 to count-1 do begin list.Add( Items[i].deepCopy() ); end; Result:= TDarwinFSWatchEventSession.create; Result._list:= list; end; constructor TDarwinFSWatchEventSession.create(); begin Inherited; end; constructor TDarwinFSWatchEventSession.create( const amount:size_t; eventPaths:CFArrayRef; flags:FSEventStreamEventFlagsPtr ); var i: size_t; event: TInternalEvent; infoDict: CFDictionaryRef; nsPath: NSString; nsNode: CFNumberRef; begin _list:= TObjectList.Create; for i:=0 to amount-1 do begin event:= TInternalEvent.Create; if isFlagUseExtendedDataSupported then begin infoDict:= CFArrayGetValueAtIndex( eventPaths, i ); nsPath:= CFDictionaryGetValue( infoDict, kFSEventStreamEventExtendedDataPathKey ); nsNode:= CFDictionaryGetValue( infoDict, kFSEventStreamEventExtendedFileIDKey ); if Assigned(nsNode) then CFNumberGetValue( nsNode, kCFNumberLongLongType, @(event.iNode) ); end else begin nsPath:= CFArrayGetValueAtIndex( eventPaths, i ); end; event.path:= nsPath.UTF8String; event.flags:= flags^; _list.Add( event ); inc(flags); end; end; destructor TDarwinFSWatchEventSession.destroy; begin FreeAndNil( _list ); end; function TDarwinFSWatchEventSession.count: Integer; begin Result:= _list.Count; end; function TDarwinFSWatchEventSession.getItem( index:Integer ): TInternalEvent; begin Result:= TInternalEvent( _list[index] ); end; function TDarwinFSWatchEventSession.isRenamed( event:TInternalEvent ): Boolean; begin Result:= event.flags and (kFSEventStreamEventFlagItemRenamed or kFSEventStreamEventFlagItemCreated or kFSEventStreamEventFlagItemRemoved) = kFSEventStreamEventFlagItemRenamed; end; procedure TDarwinFSWatchEventSession.adjustRenamedEventIfNecessary( index:Integer ); var currentEvent: TInternalEvent; nextEvent: TInternalEvent; i: Integer; begin currentEvent:= Items[index]; if not isRenamed(currentEvent) then exit; // find all related Renamed Event, and try to build a complete Renamed Event with NewPath if (currentEvent.iNode<>0) and isFlagUseExtendedDataSupported then begin i:= index + 1; while i < count do begin nextEvent:= Items[i]; if isRenamed(nextEvent) and (nextEvent.iNode=currentEvent.iNode) then begin if currentEvent.path<>nextEvent.path then currentEvent.renamedPath:= nextEvent.path; _list.Delete( i ); end else begin inc( i ); end; end; end; // got the complete Renamed Event, then exit if not currentEvent.renamedPath.IsEmpty then exit; // got the incomplete Renamed Event, change to Created or Removed Event currentEvent.flags:= currentEvent.flags and (not kFSEventStreamEventFlagItemRenamed); if FpAccess(currentEvent.path, F_OK) = 0 then begin currentEvent.flags:= currentEvent.flags or kFSEventStreamEventFlagItemCreated; end else begin currentEvent.flags:= currentEvent.flags or kFSEventStreamEventFlagItemRemoved; end; end; procedure TDarwinFSWatchEventSession.adjustSymlinkIfNecessary( index:Integer; watchPath:String; watchRealPath:String ); var currentEvent: TInternalEvent; begin if watchPath=watchRealPath then exit; currentEvent:= Items[index]; currentEvent.path:= watchPath + currentEvent.path.Substring(watchRealPath.Length); if currentEvent.renamedPath.IsEmpty then exit; if not currentEvent.renamedPath.StartsWith(watchRealPath) then exit; currentEvent.renamedPath:= watchPath + currentEvent.renamedPath.Substring(watchRealPath.Length); end; constructor TDarwinFSWatcher.create( const callback:TDarwinFSWatchCallBack; const latency:Integer ); begin Inherited Create; _watchPaths:= NSMutableArray.alloc.initWithCapacity( 16 ); _watchRealPaths:= NSMutableArray.alloc.initWithCapacity( 16 ); _callback:= callback; _latency:= latency; _streamContext.info:= self; _lastEventId:= FSEventStreamEventId(kFSEventStreamEventIdSinceNow); _running:= false; _lockObject:= TCriticalSection.Create; _pathsSyncObject:= TSimpleEvent.Create; end; destructor TDarwinFSWatcher.destroy; begin _pathsSyncObject.SetEvent; FreeAndNil( _lockObject ); FreeAndNil( _pathsSyncObject ); _watchPaths.release; _watchPaths:= nil; _watchRealPaths.release; _watchRealPaths:= nil; _streamPaths.release; _streamPaths:= nil; Inherited; end; procedure cdeclFSEventsCallback( {%H-}streamRef: ConstFSEventStreamRef; clientCallBackInfo: UnivPtr; numEvents: size_t; eventPaths: UnivPtr; eventFlags: FSEventStreamEventFlagsPtr; {%H-}eventIds: FSEventStreamEventIdPtr ); cdecl; var pool: NSAutoReleasePool; watcher: TDarwinFSWatcher absolute clientCallBackInfo; session: TDarwinFSWatchEventSession; begin pool:= NSAutoreleasePool.alloc.init; session:= TDarwinFSWatchEventSession.create( numEvents, eventPaths, eventFlags ); watcher.handleEvents( session ); pool.release; // seesion released in handleEvents() end; procedure TDarwinFSWatcher.handleEvents( const originalSession:TDarwinFSWatchEventSession ); var tempWatchPaths: NSArray; tempWatchRealPaths: NSArray; watchPath: String; watchRealPath: String; event: TInternalEvent; pathIndex: Integer; i: Integer; session: TDarwinFSWatchEventSession; currentWatchSubtree: Boolean; begin // for multithread currentWatchSubtree:= watchSubtree; try _lockObject.Acquire; try tempWatchPaths:= _watchPaths.copy; tempWatchRealPaths:= _watchRealPaths.copy; finally _lockObject.Release; end; if tempWatchPaths.count=0 then begin originalSession.Free; exit; end; for pathIndex:=0 to tempWatchPaths.count-1 do begin watchPath:= NSString(tempWatchPaths.objectAtIndex(pathIndex)).UTF8String; watchRealPath:= NSString(tempWatchRealPaths.objectAtIndex(pathIndex)).UTF8String; if pathIndex=tempWatchPaths.count-1 then session:= originalSession else session:= originalSession.deepCopy(); i:= 0; while i < session.count do begin event:= session[i]; if isMatchWatchPath(event, watchRealPath, currentWatchSubtree) then begin session.adjustRenamedEventIfNecessary( i ); session.adjustSymlinkIfNecessary( i, watchPath, watchRealPath ); doCallback( watchPath, event ); end; inc( i ); end; session.Free; end; finally tempWatchPaths.Release; tempWatchRealPaths.Release; end; end; procedure TDarwinFSWatcher.doCallback( const watchPath:String; const internalEvent:TInternalEvent ); var event: TDarwinFSWatchEvent; begin event:= TDarwinFSWatchEvent.create( watchPath, internalEvent ); _callback( event ); event.Free; end; procedure TDarwinFSWatcher.updateStream; begin if _watchPaths.isEqualToArray(_streamPaths) then exit; closeStream; _streamPaths.release; _streamPaths:= NSArray.alloc.initWithArray( _watchPaths ); if _watchPaths.count = 0 then begin _lastEventId:= FSEventStreamEventId(kFSEventStreamEventIdSinceNow); exit; end; _stream:= FSEventStreamCreate( nil, @cdeclFSEventsCallback, @_streamContext, CFArrayRef(_watchPaths), _lastEventId, _latency/1000, CREATE_FLAGS ); FSEventStreamScheduleWithRunLoop( _stream, _runLoop, kCFRunLoopDefaultMode ); FSEventStreamStart( _stream ); end; procedure TDarwinFSWatcher.closeStream; begin if Assigned(_stream) then begin _lastEventId:= FSEventsGetCurrentEventId(); FSEventStreamFlushSync( _stream ); FSEventStreamStop( _stream ); FSEventStreamInvalidate( _stream ); FSEventStreamRelease( _stream ); _stream:= nil; end; end; procedure TDarwinFSWatcher.start; var pool: NSAutoReleasePool; begin _running:= true; _runLoop:= CFRunLoopGetCurrent(); _thread:= TThread.CurrentThread; repeat pool:= NSAutoreleasePool.alloc.init; _lockObject.Acquire; try updateStream; finally _lockObject.Release; end; if Assigned(_stream) then CFRunLoopRun else waitPath; pool.release; until not _running; end; procedure TDarwinFSWatcher.terminate; begin _lockObject.Acquire; try _running:= false; interrupt; finally _lockObject.Release; end; if Assigned(_thread) then _thread.WaitFor; closeStream; end; procedure TDarwinFSWatcher.interrupt; begin Sleep( 20 ); if Assigned(_stream) then CFRunLoopStop( _runLoop ) else notifyPath; end; function realpath(__name:Pchar; __resolved:Pchar):Pchar;cdecl;external clib name 'realpath'; function toRealPath( path:String ): String; var buf: array[0..PATH_MAX] of char; resolvedPath: pchar; begin resolvedPath:= realpath( pchar(path), buf ); if resolvedPath<>nil then Result:= resolvedPath else Result:= path; end; procedure TDarwinFSWatcher.addPath( path:String ); var nsPath: NSString; nsRealPath: NSString; begin _lockObject.Acquire; try if path<>PathDelim then path:= ExcludeTrailingPathDelimiter(path); nsPath:= StringToNSString( path ); if _watchPaths.containsObject(nsPath) then exit; _watchPaths.addObject( nsPath ); nsRealPath:= StringToNSString( toRealPath(path) ); _watchRealPaths.addObject( nsRealPath ); interrupt; finally _lockObject.Release; end; end; procedure TDarwinFSWatcher.removePath( path:String ); var index: NSInteger; nsPath: NSString; begin _lockObject.Acquire; try if path<>PathDelim then path:= ExcludeTrailingPathDelimiter(path); nsPath:= StringToNSString( path ); index:= _watchPaths.indexOfObject( nsPath ); if index = NSNotFound then exit; _watchPaths.removeObjectAtIndex( index ); _watchRealPaths.removeObjectAtIndex( index ); interrupt; finally _lockObject.Release; end; end; procedure TDarwinFSWatcher.clearPath; begin _lockObject.Acquire; try if _watchPaths.count = 0 then exit; _watchPaths.removeAllObjects; _watchRealPaths.removeAllObjects; interrupt; finally _lockObject.Release; end; end; procedure TDarwinFSWatcher.waitPath; begin _pathsSyncObject.WaitFor( INFINITE ); _pathsSyncObject.ResetEvent; end; procedure TDarwinFSWatcher.notifyPath; begin _pathsSyncObject.SetEvent; end; initialization kFSEventStreamEventExtendedDataPathKey:= CFSTR('path'); kFSEventStreamEventExtendedFileIDKey:= CFSTR('fileID'); isFlagUseExtendedDataSupported:= (NSAppKitVersionNumber>=NSAppKitVersionNumber10_13); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/darwin/umydarwin.pas���������������������������������������������0000644�0001750�0000144�00000043306�14743153644�022222� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains specific DARWIN functions. Copyright (C) 2016-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Notes: 1. TDarwinAarch64Statfs is the workaround for the bug of FPC. TDarwinAarch64Statfs and the related codes can be removed after FPC 3.3.1 see also: https://gitlab.com/freepascal.org/fpc/source/-/issues/39873 } unit uMyDarwin; {$mode delphi} {$modeswitch objectivec1} {$linkframework DiskArbitration} interface uses Classes, SysUtils, UnixType, Cocoa_Extra, MacOSAll, CocoaAll, CocoaUtils, CocoaInt, CocoaConst, CocoaMenus, InterfaceBase, Menus, Controls, Forms, uDarwinFSWatch; // Darwin Util Function function StringToNSString(const S: String): NSString; function StringToCFStringRef(const S: String): CFStringRef; function NSArrayToList(const theArray:NSArray): TStringList; function ListToNSArray(const list:TStrings): NSArray; function ListToNSUrlArray(const list:TStrings): NSArray; procedure setMacOSAppearance( mode:Integer ); function getMacOSDefaultTerminal(): String; procedure FixMacFormatSettings; function NSGetTempPath: String; function NSGetFolderPath(Folder: NSSearchPathDirectory): String; function GetFileDescription(const FileName: String): String; function MountNetworkDrive(const serverAddress: String): Boolean; function GetVolumeName(const Device: String): String; function unmountAndEject(const path: String): Boolean; // Workarounds for FPC RTL Bug // copied from ptypes.inc and modified fstypename only {$if defined(cpuarm) or defined(cpuaarch64) or defined(iphonesim)} { structure used on iPhoneOS and available on Mac OS X 10.6 and later } const MFSTYPENAMELEN = 16; type TDarwinAarch64Statfs = record bsize : cuint32; iosize : cint32; blocks : cuint64; bfree : cuint64; bavail : cuint64; files : cuint64; ffree : cuint64; fsid : fsid_t; owner : uid_t; ftype : cuint32; fflags : cuint32; fssubtype : cuint32; fstypename : array[0..(MFSTYPENAMELEN)-1] of char; mountpoint : array[0..(PATH_MAX)-1] of char; mntfromname : array[0..(PATH_MAX)-1] of char; reserved: array[0..7] of cuint32; end; type TDarwinStatfs = TDarwinAarch64Statfs; {$else} type TDarwinStatfs = TStatFs; {$endif} // MacOS Simple File Sytem Watcher (only one watchPath) { TSimpleDarwinFSWatcher } TSimpleDarwinFSWatcher = class( TThread ) private _monitor: TDarwinFSWatcher; _callback: TDarwinFSWatchCallBack; _event: TDarwinFSWatchEvent; protected procedure Execute; override; procedure handleEvent( event:TDarwinFSWatchEvent ); procedure doSyncCallback; public procedure stop(); constructor Create( const path:String; const callback:TDarwinFSWatchCallBack ); destructor Destroy; override; end; // MacOS Service Integration type TNSServiceProviderCallBack = Procedure( filenames:TStringList ) of object; type TNSServiceMenuIsReady = Function(): Boolean of object; type TNSServiceMenuGetFilenames = Function(): TStringList of object; type TDCCocoaApplication = objcclass(TCocoaApplication) function validRequestorForSendType_returnType (sendType: NSString; returnType: NSString): id; override; function writeSelectionToPasteboard_types (pboard: NSPasteboard; types: NSArray): ObjCBOOL; message 'writeSelectionToPasteboard:types:'; procedure observeValueForKeyPath_ofObject_change_context( keyPath: NSString; object_: id; change: NSDictionary; context: pointer); override; public serviceMenuIsReady: TNSServiceMenuIsReady; serviceMenuGetFilenames: TNSServiceMenuGetFilenames; end; type TNSServiceProvider = objcclass(NSObject) private onOpenWithNewTab: TNSServiceProviderCallBack; public procedure openWithNewTab( pboard:NSPasteboard; userData:NSString; error:NSStringPtr ); message 'openWithNewTab:userData:error:'; end; type TMacosServiceMenuHelper = class private oldMenuPopupHandler: TNotifyEvent; serviceSubMenuCaption: String; procedure attachServicesMenu( Sender:TObject); public procedure PopUp( menu:TPopupMenu; caption:String ); end; procedure InitNSServiceProvider( serveCallback: TNSServiceProviderCallBack; isReadyFunc: TNSServiceMenuIsReady; getFilenamesFunc: TNSServiceMenuGetFilenames ); // MacOS Sharing procedure showMacOSSharingServiceMenu; // MacOS Theme type TNSThemeChangedHandler = Procedure() of object; procedure InitNSThemeChangedObserver( handler: TNSThemeChangedHandler ); var HasMountURL: Boolean = False; NSServiceProvider: TNSServiceProvider; MacosServiceMenuHelper: TMacosServiceMenuHelper; NSThemeChangedHandler: TNSThemeChangedHandler; implementation uses DynLibs; { TSimpleDarwinFSWatcher } procedure TSimpleDarwinFSWatcher.Execute; begin _monitor.start(); end; procedure TSimpleDarwinFSWatcher.handleEvent( event:TDarwinFSWatchEvent ); begin _event:= event; Synchronize( doSyncCallback ); end; procedure TSimpleDarwinFSWatcher.doSyncCallback; begin _callback( _event ); _event:= nil; end; procedure TSimpleDarwinFSWatcher.stop(); begin _monitor.terminate(); end; constructor TSimpleDarwinFSWatcher.Create( const path:String; const callback:TDarwinFSWatchCallBack ); begin Inherited Create( false ); _callback:= callback; _monitor:= TDarwinFSWatcher.create( handleEvent ); _monitor.addPath( path ); end; destructor TSimpleDarwinFSWatcher.Destroy; begin _monitor.terminate; FreeAndNil( _monitor ); inherited; end; procedure setMacOSAppearance( mode:Integer ); var appearance: NSAppearance; begin if not NSApp.respondsToSelector( ObjCSelector('appearance') ) then exit; case mode of 0,1: appearance:= nil; 2: appearance:= NSAppearance.appearanceNamed( NSSTR_DARK_NAME ); 3: appearance:= NSAppearance.appearanceNamed( NSAppearanceNameAqua ); end; NSApp.setAppearance( appearance ); NSAppearance.setCurrentAppearance( appearance ); end; procedure TMacosServiceMenuHelper.attachServicesMenu( Sender:TObject); var servicesItem: TMenuItem; subMenu: TCocoaMenu; begin // call the previous OnMenuPopupHandler and restore it if Assigned(oldMenuPopupHandler) then oldMenuPopupHandler( Sender ); OnMenuPopupHandler:= oldMenuPopupHandler; oldMenuPopupHandler:= nil; // attach the Services Sub Menu by calling NSApplication.setServicesMenu() servicesItem:= TPopupMenu(Sender).Items.Find(serviceSubMenuCaption); if servicesItem<>nil then begin subMenu:= TCocoaMenu.alloc.initWithTitle(NSString.string_); TCocoaMenuItem(servicesItem.Handle).setSubmenu( subMenu ); NSApp.setServicesMenu( NSMenu(servicesItem.Handle) ); end; end; procedure TMacosServiceMenuHelper.PopUp( menu:TPopupMenu; caption:String ); begin // because the menu item handle will be destroyed in TPopupMenu.PopUp() // we can only call NSApplication.setServicesMenu() in OnMenuPopupHandler() oldMenuPopupHandler:= OnMenuPopupHandler; OnMenuPopupHandler:= attachServicesMenu; serviceSubMenuCaption:= caption; menu.PopUp(); end; procedure InitNSServiceProvider( serveCallback: TNSServiceProviderCallBack; isReadyFunc: TNSServiceMenuIsReady; getFilenamesFunc: TNSServiceMenuGetFilenames ); var DCApp: TDCCocoaApplication; sendTypes: NSArray; returnTypes: NSArray; begin DCApp:= TDCCocoaApplication( NSApp ); // MacOS Service menu incoming setup if not Assigned(NSServiceProvider) then begin NSServiceProvider:= TNSServiceProvider.alloc.init; DCApp.setServicesProvider( NSServiceProvider ); NSUpdateDynamicServices; end; NSServiceProvider.onOpenWithNewTab:= serveCallback; // MacOS Service menu outgoing setup sendTypes:= NSArray.arrayWithObject(NSFilenamesPboardType); returnTypes:= nil; DCApp.serviceMenuIsReady:= isReadyFunc; DCApp.serviceMenuGetFilenames:= getFilenamesFunc; DCApp.registerServicesMenuSendTypes_returnTypes( sendTypes, returnTypes ); end; procedure TNSServiceProvider.openWithNewTab( pboard:NSPasteboard; userData:NSString; error:NSStringPtr ); var filenameArray{, lClasses}: NSArray; filenameList: TStringList; begin filenameArray := pboard.propertyListForType(NSFilenamesPboardType); if filenameArray <> nil then begin if Assigned(onOpenWithNewTab) then begin filenameList:= NSArrayToList( filenameArray ); onOpenWithNewTab( filenameList ); FreeAndNil( filenameList ); end; end; end; function TDCCocoaApplication.validRequestorForSendType_returnType (sendType: NSString; returnType: NSString): id; var isSendTypeMatch: ObjcBool; isReturnTypeMatch: ObjcBool; begin Result:= nil; if not NSFilenamesPboardType.isEqualToString(sendType) then exit; if returnType<>nil then exit; if self.serviceMenuIsReady() then Result:=self; end; function TDCCocoaApplication.writeSelectionToPasteboard_types( pboard: NSPasteboard; types: NSArray): ObjCBOOL; var filenameList: TStringList; filenameArray: NSArray; begin Result:= false; filenameList:= self.serviceMenuGetFilenames(); if filenameList=nil then exit; filenameArray:= ListToNSArray( filenameList ); pboard.declareTypes_owner( NSArray.arrayWithObject(NSFileNamesPboardType), nil ); pboard.setPropertyList_forType( filenameArray, NSFileNamesPboardType ); Result:= true; FreeAndNil( filenameList ); end; procedure showMacOSSharingServiceMenu; var picker: NSSharingServicePicker; filenameArray: NSArray; filenameList: TStringList; point: TPoint; popupNSRect: NSRect; control: TWinControl; begin if not TDCCocoaApplication(NSApp).serviceMenuIsReady then exit; filenameList:= TDCCocoaApplication(NSApp).serviceMenuGetFilenames; if filenameList=nil then exit; filenameArray:= ListToNSUrlArray( filenameList ); FreeAndNil( filenameList ); control:= Screen.ActiveControl; point:= control.ScreenToClient( Mouse.CursorPos ); popupNSRect.origin.x:= point.X; popupNSRect.origin.y:= point.Y; popupNSRect.size:= NSZeroSize; picker:= NSSharingServicePicker.alloc.initWithItems( filenameArray ); picker.showRelativeToRect_ofView_preferredEdge( popupNSRect, NSView(control.handle) , NSMinYEdge ); picker.release; end; procedure TDCCocoaApplication.observeValueForKeyPath_ofObject_change_context( keyPath: NSString; object_: id; change: NSDictionary; context: pointer); begin Inherited observeValueForKeyPath_ofObject_change_context( keyPath, object_, change, context ); if keyPath.isEqualToString(NSSTR('effectiveAppearance')) then begin NSAppearance.setCurrentAppearance( self.appearance ); if Assigned(NSThemeChangedHandler) then NSThemeChangedHandler; end; end; procedure InitNSThemeChangedObserver( handler: TNSThemeChangedHandler ); begin if Assigned(NSThemeChangedHandler) then exit; NSApp.addObserver_forKeyPath_options_context( NSApp, NSSTR('effectiveAppearance'), 0, nil ); NSThemeChangedHandler:= handler; end; function NSArrayToList(const theArray:NSArray): TStringList; var i: Integer; list : TStringList; begin list := TStringList.Create; for i := 0 to theArray.Count-1 do begin list.Add( NSStringToString( theArray.objectAtIndex(i) ) ); end; Result := list; end; function ListToNSArray(const list:TStrings): NSArray; var theArray: NSMutableArray; item: String; begin theArray := NSMutableArray.arrayWithCapacity( list.Count ); for item in list do begin theArray.addObject( StringToNSString(item) ); end; Result := theArray; end; function ListToNSUrlArray(const list:TStrings): NSArray; var theArray: NSMutableArray; item: String; url: NSUrl; begin theArray:= NSMutableArray.arrayWithCapacity( list.Count ); for item in list do begin url:= NSUrl.fileURLWithPath( StringToNSString(item) ); theArray.addObject( url ); end; Result:= theArray; end; function CFStringToStr(AString: CFStringRef): String; var Str: Pointer; StrSize: CFIndex; StrRange: CFRange; begin if AString = nil then begin Result:= EmptyStr; Exit; end; // Try the quick way first Str:= CFStringGetCStringPtr(AString, kCFStringEncodingUTF8); if Str <> nil then Result:= PAnsiChar(Str) else begin // if that doesn't work this will StrRange.location:= 0; StrRange.length:= CFStringGetLength(AString); CFStringGetBytes(AString, StrRange, kCFStringEncodingUTF8, Ord('?'), False, nil, 0, StrSize{%H-}); SetLength(Result, StrSize); if StrSize > 0 then begin CFStringGetBytes(AString, StrRange, kCFStringEncodingUTF8, Ord('?'), False, @Result[1], StrSize, StrSize); end; end; end; procedure FixMacFormatSettings; var S: String; ALocale: CFLocaleRef; begin ALocale:= CFLocaleCopyCurrent; if Assigned(ALocale) then begin S:= CFStringToStr(CFLocaleGetValue(ALocale, kCFLocaleGroupingSeparator)); if Length(S) = 0 then begin DefaultFormatSettings.ThousandSeparator:= #0; end; CFRelease(ALocale); end; end; function NSGetTempPath: String; begin Result:= IncludeTrailingBackslash(NSTemporaryDirectory.UTF8String); end; function getMacOSDefaultTerminal(): String; begin Result:= NSStringToString( NSWorkspace.sharedWorkspace.fullPathForApplication( NSStr('terminal') ) ); end; function StringToNSString(const S: String): NSString; begin Result:= NSString(NSString.stringWithUTF8String(PAnsiChar(S))); end; function StringToCFStringRef(const S: String): CFStringRef; begin Result:= CFStringCreateWithCString(nil, PAnsiChar(S), kCFStringEncodingUTF8); end; function NSGetFolderPath(Folder: NSSearchPathDirectory): String; var Path: NSArray; begin Path:= NSFileManager.defaultManager.URLsForDirectory_inDomains(Folder, NSUserDomainMask); if Path.count > 0 then begin Result:= IncludeTrailingBackslash(NSURL(Path.objectAtIndex(0)).path.UTF8String) + ApplicationName; end; end; function GetFileDescription(const FileName: String): String; var Error: NSError; WS: NSWorkspace; FileType: NSString; FileNameRef: CFStringRef; begin WS:= NSWorkspace.sharedWorkspace; FileNameRef:= StringToCFStringRef(FileName); if (FileNameRef = nil) then Exit(EmptyStr); FileType:= WS.typeOfFile_error(NSString(FileNameRef), @Error); if (FileType = nil) then Result:= Error.localizedDescription.UTF8String else begin Result:= WS.localizedDescriptionForType(FileType).UTF8String; end; CFRelease(FileNameRef); end; function GetVolumeName(const Device: String): String; var ADisk: DADiskRef; AName: CFStringRef; ASession: DASessionRef; ADescription: CFDictionaryRef; begin Result:= EmptyStr; ASession:= DASessionCreate(kCFAllocatorDefault); if Assigned(ASession) then begin ADisk:= DADiskCreateFromBSDName(kCFAllocatorDefault, ASession, PAnsiChar(Device)); if Assigned(ADisk) then begin ADescription:= DADiskCopyDescription(ADisk); if Assigned(ADescription) then begin AName:= CFDictionaryGetValue(ADescription, kDADiskDescriptionVolumeNameKey); if (AName = nil) then AName:= CFDictionaryGetValue(ADescription, kDADiskDescriptionMediaNameKey); if Assigned(AName) then begin Result:= CFStringToStr(AName); end; CFRelease(ADescription); end; CFRelease(ADisk); end; CFRelease(ASession); end; end; function unmountAndEject(const path: String): Boolean; begin Result:= NSWorkspace.sharedWorkspace.unmountAndEjectDeviceAtPath( StringToNSString(path) ); end; var NetFS: TLibHandle = NilHandle; CoreServices: TLibHandle = NilHandle; var FSMountServerVolumeSync: function(url: CFURLRef; mountDir: CFURLRef; user: CFStringRef; password: CFStringRef; mountedVolumeRefNum: FSVolumeRefNumPtr; flags: OptionBits): OSStatus; stdcall; NetFSMountURLSync: function(_url: CFURLRef; _mountpath: CFURLRef; _user: CFStringRef; _passwd: CFStringRef; _open_options: CFMutableDictionaryRef; _mount_options: CFMutableDictionaryRef; _mountpoints: CFArrayRefPtr): Int32; cdecl; function MountNetworkDrive(const serverAddress: String): Boolean; var sharePath: NSURL; mountPoints: CFArrayRef = nil; begin sharePath:= NSURL.URLWithString(StringToNSString(serverAddress)); if Assigned(NetFSMountURLSync) then Result:= NetFSMountURLSync(CFURLRef(sharePath), nil, nil, nil, nil, nil, @mountPoints) = 0 else begin Result:= FSMountServerVolumeSync(CFURLRef(sharePath), nil, nil, nil, nil, 0) = noErr; end; end; procedure Initialize; begin NetFS:= LoadLibrary('/System/Library/Frameworks/NetFS.framework/NetFS'); if (NetFS <> NilHandle) then begin @NetFSMountURLSync:= GetProcAddress(NetFS, 'NetFSMountURLSync'); end; CoreServices:= LoadLibrary('/System/Library/Frameworks/CoreServices.framework/CoreServices'); if (CoreServices <> NilHandle) then begin @FSMountServerVolumeSync:= GetProcAddress(CoreServices, 'FSMountServerVolumeSync'); end; HasMountURL:= Assigned(NetFSMountURLSync) or Assigned(FSMountServerVolumeSync); MacosServiceMenuHelper:= TMacosServiceMenuHelper.Create; end; procedure Finalize; begin if (NetFS <> NilHandle) then FreeLibrary(NetFS); if (CoreServices <> NilHandle) then FreeLibrary(CoreServices); FreeAndNil( MacosServiceMenuHelper ); end; initialization Initialize; finalization Finalize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/darwin/uquicklook.pas��������������������������������������������0000644�0001750�0000144�00000007151�14743153644�022367� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Quick Look thumbnail provider Copyright (C) 2015-2019 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uQuickLook; {$mode objfpc}{$H+} {$modeswitch objectivec1} interface uses Classes, SysUtils; implementation uses DynLibs, FileUtil, Types, Graphics, MacOSAll, CocoaAll, uThumbnails, uDebug, uClassesEx, uGraphics; const libQuickLook = '/System/Library/Frameworks/QuickLook.framework/Versions/Current/QuickLook'; var QuickLook: TLibHandle = NilHandle; var QLThumbnailImageCreate: function(allocator: CFAllocatorRef; url: CFURLRef; maxThumbnailSize: CGSize; options: CFDictionaryRef): CGImageRef; cdecl; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var ImageRef: CGImageRef; WorkStream: TBlobStream; maxThumbnailSize: CGSize; ImageData: CFMutableDataRef; theFileNameUrlRef: CFURLRef; theFileNameCFRef: CFStringRef; Bitmap: TPortableNetworkGraphic; ImageDest: CGImageDestinationRef; begin theFileNameCFRef:= CFStringCreateWithFileSystemRepresentation(nil, PAnsiChar(aFileName)); theFileNameUrlRef:= CFURLCreateWithFileSystemPath(nil, theFileNameCFRef, kCFURLPOSIXPathStyle, False); try maxThumbnailSize.width:= aSize.cx; maxThumbnailSize.height:= aSize.cy; ImageRef:= QLThumbnailImageCreate(kCFAllocatorDefault, theFileNameUrlRef, maxThumbnailSize, nil); if ImageRef = nil then Exit(nil); ImageData:= CFDataCreateMutable(nil, 0); // Get image data in PNG format ImageDest:= CGImageDestinationCreateWithData(ImageData, kUTTypePNG, 1, nil); CGImageDestinationAddImage(ImageDest, ImageRef, nil); if (CGImageDestinationFinalize(ImageDest) = 0) then Result:= nil else begin Bitmap:= TPortableNetworkGraphic.Create; WorkStream:= TBlobStream.Create(CFDataGetBytePtr(ImageData), CFDataGetLength(ImageData)); try Result:= TBitmap.Create; try Bitmap.LoadFromStream(WorkStream); BitmapAssign(Result, Bitmap); except FreeAndNil(Result); end; finally Bitmap.Free; WorkStream.Free; end; end; CFRelease(ImageRef); CFRelease(ImageData); CFRelease(ImageDest); finally CFRelease(theFileNameCFRef); CFRelease(theFileNameUrlRef); end; end; procedure Initialize; begin QuickLook:= LoadLibrary(libQuickLook); if (QuickLook <> NilHandle) then begin Pointer(QLThumbnailImageCreate):= GetProcAddress(QuickLook, 'QLThumbnailImageCreate'); if Assigned(QLThumbnailImageCreate) then begin // Register thumbnail provider TThumbnailManager.RegisterProvider(@GetThumbnail); DCDebug('Initialize QuickLook: Success'); end; end; end; procedure Finalize; begin if (QuickLook <> NilHandle) then FreeLibrary(QuickLook); end; initialization Initialize; finalization Finalize; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/glib/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017121� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/glib/ugio2.pas���������������������������������������������������0000644�0001750�0000144�00002022142�14743153644�020656� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an autogenerated unit using gobject introspection (gir2pascal). Do not Edit. } unit uGio2; {$MODE OBJFPC}{$H+} {$PACKRECORDS C} {$MODESWITCH DUPLICATELOCALS+} interface uses CTypes, uGObject2, uGLib2; const DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME = 'gio-desktop-app-info-lookup'; FILE_ATTRIBUTE_ACCESS_CAN_DELETE = 'access::can-delete'; FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE = 'access::can-execute'; FILE_ATTRIBUTE_ACCESS_CAN_READ = 'access::can-read'; FILE_ATTRIBUTE_ACCESS_CAN_RENAME = 'access::can-rename'; FILE_ATTRIBUTE_ACCESS_CAN_TRASH = 'access::can-trash'; FILE_ATTRIBUTE_ACCESS_CAN_WRITE = 'access::can-write'; FILE_ATTRIBUTE_DOS_IS_ARCHIVE = 'dos::is-archive'; FILE_ATTRIBUTE_DOS_IS_SYSTEM = 'dos::is-system'; FILE_ATTRIBUTE_ETAG_VALUE = 'etag::value'; FILE_ATTRIBUTE_FILESYSTEM_FREE = 'filesystem::free'; FILE_ATTRIBUTE_FILESYSTEM_READONLY = 'filesystem::readonly'; FILE_ATTRIBUTE_FILESYSTEM_SIZE = 'filesystem::size'; FILE_ATTRIBUTE_FILESYSTEM_TYPE = 'filesystem::type'; FILE_ATTRIBUTE_FILESYSTEM_USED = 'filesystem::used'; FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW = 'filesystem::use-preview'; FILE_ATTRIBUTE_GVFS_BACKEND = 'gvfs::backend'; FILE_ATTRIBUTE_ID_FILE = 'id::file'; FILE_ATTRIBUTE_ID_FILESYSTEM = 'id::filesystem'; FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT = 'mountable::can-eject'; FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT = 'mountable::can-mount'; FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL = 'mountable::can-poll'; FILE_ATTRIBUTE_MOUNTABLE_CAN_START = 'mountable::can-start'; FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED = 'mountable::can-start-degraded'; FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP = 'mountable::can-stop'; FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT = 'mountable::can-unmount'; FILE_ATTRIBUTE_MOUNTABLE_HAL_UDI = 'mountable::hal-udi'; FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC = 'mountable::is-media-check-automatic'; FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE = 'mountable::start-stop-type'; FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE = 'mountable::unix-device'; FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE = 'mountable::unix-device-file'; FILE_ATTRIBUTE_OWNER_GROUP = 'owner::group'; FILE_ATTRIBUTE_OWNER_USER = 'owner::user'; FILE_ATTRIBUTE_OWNER_USER_REAL = 'owner::user-real'; FILE_ATTRIBUTE_PREVIEW_ICON = 'preview::icon'; FILE_ATTRIBUTE_SELINUX_CONTEXT = 'selinux::context'; FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE = 'standard::allocated-size'; FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE = 'standard::content-type'; FILE_ATTRIBUTE_STANDARD_COPY_NAME = 'standard::copy-name'; FILE_ATTRIBUTE_STANDARD_DESCRIPTION = 'standard::description'; FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME = 'standard::display-name'; FILE_ATTRIBUTE_STANDARD_EDIT_NAME = 'standard::edit-name'; FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE = 'standard::fast-content-type'; FILE_ATTRIBUTE_STANDARD_ICON = 'standard::icon'; FILE_ATTRIBUTE_STANDARD_IS_BACKUP = 'standard::is-backup'; FILE_ATTRIBUTE_STANDARD_IS_HIDDEN = 'standard::is-hidden'; FILE_ATTRIBUTE_STANDARD_IS_SYMLINK = 'standard::is-symlink'; FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL = 'standard::is-virtual'; FILE_ATTRIBUTE_STANDARD_NAME = 'standard::name'; FILE_ATTRIBUTE_STANDARD_SIZE = 'standard::size'; FILE_ATTRIBUTE_STANDARD_SORT_ORDER = 'standard::sort-order'; FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON = 'standard::symbolic-icon'; FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET = 'standard::symlink-target'; FILE_ATTRIBUTE_STANDARD_TARGET_URI = 'standard::target-uri'; FILE_ATTRIBUTE_STANDARD_TYPE = 'standard::type'; FILE_ATTRIBUTE_THUMBNAILING_FAILED = 'thumbnail::failed'; FILE_ATTRIBUTE_THUMBNAIL_PATH = 'thumbnail::path'; FILE_ATTRIBUTE_TIME_ACCESS = 'time::access'; FILE_ATTRIBUTE_TIME_ACCESS_USEC = 'time::access-usec'; FILE_ATTRIBUTE_TIME_CHANGED = 'time::changed'; FILE_ATTRIBUTE_TIME_CHANGED_USEC = 'time::changed-usec'; FILE_ATTRIBUTE_TIME_CREATED = 'time::created'; FILE_ATTRIBUTE_TIME_CREATED_USEC = 'time::created-usec'; FILE_ATTRIBUTE_TIME_MODIFIED = 'time::modified'; FILE_ATTRIBUTE_TIME_MODIFIED_USEC = 'time::modified-usec'; FILE_ATTRIBUTE_TRASH_DELETION_DATE = 'trash::deletion-date'; FILE_ATTRIBUTE_TRASH_ITEM_COUNT = 'trash::item-count'; FILE_ATTRIBUTE_TRASH_ORIG_PATH = 'trash::orig-path'; FILE_ATTRIBUTE_UNIX_BLOCKS = 'unix::blocks'; FILE_ATTRIBUTE_UNIX_BLOCK_SIZE = 'unix::block-size'; FILE_ATTRIBUTE_UNIX_DEVICE = 'unix::device'; FILE_ATTRIBUTE_UNIX_GID = 'unix::gid'; FILE_ATTRIBUTE_UNIX_INODE = 'unix::inode'; FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT = 'unix::is-mountpoint'; FILE_ATTRIBUTE_UNIX_MODE = 'unix::mode'; FILE_ATTRIBUTE_UNIX_NLINK = 'unix::nlink'; FILE_ATTRIBUTE_UNIX_RDEV = 'unix::rdev'; FILE_ATTRIBUTE_UNIX_UID = 'unix::uid'; MENU_ATTRIBUTE_ACTION = 'action'; MENU_ATTRIBUTE_ACTION_NAMESPACE = 'action-namespace'; MENU_ATTRIBUTE_LABEL = 'label'; MENU_ATTRIBUTE_TARGET = 'target'; MENU_LINK_SECTION = 'section'; MENU_LINK_SUBMENU = 'submenu'; NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME = 'gio-native-volume-monitor'; NETWORK_MONITOR_EXTENSION_POINT_NAME = 'gio-network-monitor'; PROXY_EXTENSION_POINT_NAME = 'gio-proxy'; PROXY_RESOLVER_EXTENSION_POINT_NAME = 'gio-proxy-resolver'; TLS_BACKEND_EXTENSION_POINT_NAME = 'gio-tls-backend'; TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT = '1.3.6.1.5.5.7.3.2'; TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER = '1.3.6.1.5.5.7.3.1'; VFS_EXTENSION_POINT_NAME = 'gio-vfs'; VOLUME_IDENTIFIER_KIND_CLASS = 'class'; VOLUME_IDENTIFIER_KIND_HAL_UDI = 'hal-udi'; VOLUME_IDENTIFIER_KIND_LABEL = 'label'; VOLUME_IDENTIFIER_KIND_NFS_MOUNT = 'nfs-mount'; VOLUME_IDENTIFIER_KIND_UNIX_DEVICE = 'unix-device'; VOLUME_IDENTIFIER_KIND_UUID = 'uuid'; VOLUME_MONITOR_EXTENSION_POINT_NAME = 'gio-volume-monitor'; type TGAppInfoCreateFlags = Integer; const { GAppInfoCreateFlags } G_APP_INFO_CREATE_NONE: TGAppInfoCreateFlags = 0; G_APP_INFO_CREATE_NEEDS_TERMINAL: TGAppInfoCreateFlags = 1; G_APP_INFO_CREATE_SUPPORTS_URIS: TGAppInfoCreateFlags = 2; G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION: TGAppInfoCreateFlags = 4; type TGApplicationFlags = Integer; const { GApplicationFlags } G_APPLICATION_FLAGS_NONE: TGApplicationFlags = 0; G_APPLICATION_IS_SERVICE: TGApplicationFlags = 1; G_APPLICATION_IS_LAUNCHER: TGApplicationFlags = 2; G_APPLICATION_HANDLES_OPEN: TGApplicationFlags = 4; G_APPLICATION_HANDLES_COMMAND_LINE: TGApplicationFlags = 8; G_APPLICATION_SEND_ENVIRONMENT: TGApplicationFlags = 16; G_APPLICATION_NON_UNIQUE: TGApplicationFlags = 32; type TGDBusConnectionFlags = Integer; const { GDBusConnectionFlags } G_DBUS_CONNECTION_FLAGS_NONE: TGDBusConnectionFlags = 0; G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT: TGDBusConnectionFlags = 1; G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER: TGDBusConnectionFlags = 2; G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS: TGDBusConnectionFlags = 4; G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION: TGDBusConnectionFlags = 8; G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING: TGDBusConnectionFlags = 16; type TGDBusCallFlags = Integer; const { GDBusCallFlags } G_DBUS_CALL_FLAGS_NONE: TGDBusCallFlags = 0; G_DBUS_CALL_FLAGS_NO_AUTO_START: TGDBusCallFlags = 1; type TGDBusCapabilityFlags = Integer; const { GDBusCapabilityFlags } G_DBUS_CAPABILITY_FLAGS_NONE: TGDBusCapabilityFlags = 0; G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING: TGDBusCapabilityFlags = 1; type TGDBusSubtreeFlags = Integer; const { GDBusSubtreeFlags } G_DBUS_SUBTREE_FLAGS_NONE: TGDBusSubtreeFlags = 0; G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES: TGDBusSubtreeFlags = 1; type TGDBusSendMessageFlags = Integer; const { GDBusSendMessageFlags } G_DBUS_SEND_MESSAGE_FLAGS_NONE: TGDBusSendMessageFlags = 0; G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL: TGDBusSendMessageFlags = 1; type TGDBusSignalFlags = Integer; const { GDBusSignalFlags } G_DBUS_SIGNAL_FLAGS_NONE: TGDBusSignalFlags = 0; G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE: TGDBusSignalFlags = 1; type TGFileCreateFlags = Integer; const { GFileCreateFlags } G_FILE_CREATE_NONE: TGFileCreateFlags = 0; G_FILE_CREATE_PRIVATE: TGFileCreateFlags = 1; G_FILE_CREATE_REPLACE_DESTINATION: TGFileCreateFlags = 2; type TGFileCopyFlags = Integer; const { GFileCopyFlags } G_FILE_COPY_NONE: TGFileCopyFlags = 0; G_FILE_COPY_OVERWRITE: TGFileCopyFlags = 1; G_FILE_COPY_BACKUP: TGFileCopyFlags = 2; G_FILE_COPY_NOFOLLOW_SYMLINKS: TGFileCopyFlags = 4; G_FILE_COPY_ALL_METADATA: TGFileCopyFlags = 8; G_FILE_COPY_NO_FALLBACK_FOR_MOVE: TGFileCopyFlags = 16; G_FILE_COPY_TARGET_DEFAULT_PERMS: TGFileCopyFlags = 32; type TGMountUnmountFlags = Integer; const { GMountUnmountFlags } G_MOUNT_UNMOUNT_NONE: TGMountUnmountFlags = 0; G_MOUNT_UNMOUNT_FORCE: TGMountUnmountFlags = 1; type TGFileQueryInfoFlags = Integer; const { GFileQueryInfoFlags } G_FILE_QUERY_INFO_NONE: TGFileQueryInfoFlags = 0; G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS: TGFileQueryInfoFlags = 1; type TGFileMonitorFlags = Integer; const { GFileMonitorFlags } G_FILE_MONITOR_NONE: TGFileMonitorFlags = 0; G_FILE_MONITOR_WATCH_MOUNTS: TGFileMonitorFlags = 1; G_FILE_MONITOR_SEND_MOVED: TGFileMonitorFlags = 2; G_FILE_MONITOR_WATCH_HARD_LINKS: TGFileMonitorFlags = 4; type TGMountMountFlags = Integer; const { GMountMountFlags } G_MOUNT_MOUNT_NONE: TGMountMountFlags = 0; type TGFileAttributeType = Integer; const { GFileAttributeType } G_FILE_ATTRIBUTE_TYPE_INVALID: TGFileAttributeType = 0; G_FILE_ATTRIBUTE_TYPE_STRING: TGFileAttributeType = 1; G_FILE_ATTRIBUTE_TYPE_BYTE_STRING: TGFileAttributeType = 2; G_FILE_ATTRIBUTE_TYPE_BOOLEAN: TGFileAttributeType = 3; G_FILE_ATTRIBUTE_TYPE_UINT32: TGFileAttributeType = 4; G_FILE_ATTRIBUTE_TYPE_INT32: TGFileAttributeType = 5; G_FILE_ATTRIBUTE_TYPE_UINT64: TGFileAttributeType = 6; G_FILE_ATTRIBUTE_TYPE_INT64: TGFileAttributeType = 7; G_FILE_ATTRIBUTE_TYPE_OBJECT: TGFileAttributeType = 8; G_FILE_ATTRIBUTE_TYPE_STRINGV: TGFileAttributeType = 9; type TGDriveStartFlags = Integer; const { GDriveStartFlags } G_DRIVE_START_NONE: TGDriveStartFlags = 0; type TGAskPasswordFlags = Integer; const { GAskPasswordFlags } G_ASK_PASSWORD_NEED_PASSWORD: TGAskPasswordFlags = 1; G_ASK_PASSWORD_NEED_USERNAME: TGAskPasswordFlags = 2; G_ASK_PASSWORD_NEED_DOMAIN: TGAskPasswordFlags = 4; G_ASK_PASSWORD_SAVING_SUPPORTED: TGAskPasswordFlags = 8; G_ASK_PASSWORD_ANONYMOUS_SUPPORTED: TGAskPasswordFlags = 16; type TGOutputStreamSpliceFlags = Integer; const { GOutputStreamSpliceFlags } G_OUTPUT_STREAM_SPLICE_NONE: TGOutputStreamSpliceFlags = 0; G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE: TGOutputStreamSpliceFlags = 1; G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET: TGOutputStreamSpliceFlags = 2; type TGBusNameOwnerFlags = Integer; const { GBusNameOwnerFlags } G_BUS_NAME_OWNER_FLAGS_NONE: TGBusNameOwnerFlags = 0; G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT: TGBusNameOwnerFlags = 1; G_BUS_NAME_OWNER_FLAGS_REPLACE: TGBusNameOwnerFlags = 2; type TGBusNameWatcherFlags = Integer; const { GBusNameWatcherFlags } G_BUS_NAME_WATCHER_FLAGS_NONE: TGBusNameWatcherFlags = 0; G_BUS_NAME_WATCHER_FLAGS_AUTO_START: TGBusNameWatcherFlags = 1; type TGBusType = Integer; const { GBusType } G_BUS_TYPE_STARTER: TGBusType = -1; G_BUS_TYPE_NONE: TGBusType = 0; G_BUS_TYPE_SYSTEM: TGBusType = 1; G_BUS_TYPE_SESSION: TGBusType = 2; type TGConverterFlags = Integer; const { GConverterFlags } G_CONVERTER_NO_FLAGS: TGConverterFlags = 0; G_CONVERTER_INPUT_AT_END: TGConverterFlags = 1; G_CONVERTER_FLUSH: TGConverterFlags = 2; type TGConverterResult = Integer; const { GConverterResult } G_CONVERTER_ERROR: TGConverterResult = 0; G_CONVERTER_CONVERTED: TGConverterResult = 1; G_CONVERTER_FINISHED: TGConverterResult = 2; G_CONVERTER_FLUSHED: TGConverterResult = 3; type TGCredentialsType = Integer; const { GCredentialsType } G_CREDENTIALS_TYPE_INVALID: TGCredentialsType = 0; G_CREDENTIALS_TYPE_LINUX_UCRED: TGCredentialsType = 1; G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED: TGCredentialsType = 2; G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED: TGCredentialsType = 3; type TGIOStreamSpliceFlags = Integer; const { GIOStreamSpliceFlags } G_IO_STREAM_SPLICE_NONE: TGIOStreamSpliceFlags = 0; G_IO_STREAM_SPLICE_CLOSE_STREAM1: TGIOStreamSpliceFlags = 1; G_IO_STREAM_SPLICE_CLOSE_STREAM2: TGIOStreamSpliceFlags = 2; G_IO_STREAM_SPLICE_WAIT_FOR_BOTH: TGIOStreamSpliceFlags = 4; type TGDBusMessageFlags = Integer; const { GDBusMessageFlags } G_DBUS_MESSAGE_FLAGS_NONE: TGDBusMessageFlags = 0; G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED: TGDBusMessageFlags = 1; G_DBUS_MESSAGE_FLAGS_NO_AUTO_START: TGDBusMessageFlags = 2; type TGDBusMessageHeaderField = Integer; const { GDBusMessageHeaderField } G_DBUS_MESSAGE_HEADER_FIELD_INVALID: TGDBusMessageHeaderField = 0; G_DBUS_MESSAGE_HEADER_FIELD_PATH: TGDBusMessageHeaderField = 1; G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE: TGDBusMessageHeaderField = 2; G_DBUS_MESSAGE_HEADER_FIELD_MEMBER: TGDBusMessageHeaderField = 3; G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME: TGDBusMessageHeaderField = 4; G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL: TGDBusMessageHeaderField = 5; G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION: TGDBusMessageHeaderField = 6; G_DBUS_MESSAGE_HEADER_FIELD_SENDER: TGDBusMessageHeaderField = 7; G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE: TGDBusMessageHeaderField = 8; G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS: TGDBusMessageHeaderField = 9; type TGDBusMessageByteOrder = Integer; const { GDBusMessageByteOrder } G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN: TGDBusMessageByteOrder = 66; G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN: TGDBusMessageByteOrder = 108; type TGDBusMessageType = Integer; const { GDBusMessageType } G_DBUS_MESSAGE_TYPE_INVALID: TGDBusMessageType = 0; G_DBUS_MESSAGE_TYPE_METHOD_CALL: TGDBusMessageType = 1; G_DBUS_MESSAGE_TYPE_METHOD_RETURN: TGDBusMessageType = 2; G_DBUS_MESSAGE_TYPE_ERROR: TGDBusMessageType = 3; G_DBUS_MESSAGE_TYPE_SIGNAL: TGDBusMessageType = 4; type TGDBusError = Integer; const { GDBusError } G_DBUS_ERROR_FAILED: TGDBusError = 0; G_DBUS_ERROR_NO_MEMORY: TGDBusError = 1; G_DBUS_ERROR_SERVICE_UNKNOWN: TGDBusError = 2; G_DBUS_ERROR_NAME_HAS_NO_OWNER: TGDBusError = 3; G_DBUS_ERROR_NO_REPLY: TGDBusError = 4; G_DBUS_ERROR_IO_ERROR: TGDBusError = 5; G_DBUS_ERROR_BAD_ADDRESS: TGDBusError = 6; G_DBUS_ERROR_NOT_SUPPORTED: TGDBusError = 7; G_DBUS_ERROR_LIMITS_EXCEEDED: TGDBusError = 8; G_DBUS_ERROR_ACCESS_DENIED: TGDBusError = 9; G_DBUS_ERROR_AUTH_FAILED: TGDBusError = 10; G_DBUS_ERROR_NO_SERVER: TGDBusError = 11; G_DBUS_ERROR_TIMEOUT: TGDBusError = 12; G_DBUS_ERROR_NO_NETWORK: TGDBusError = 13; G_DBUS_ERROR_ADDRESS_IN_USE: TGDBusError = 14; G_DBUS_ERROR_DISCONNECTED: TGDBusError = 15; G_DBUS_ERROR_INVALID_ARGS: TGDBusError = 16; G_DBUS_ERROR_FILE_NOT_FOUND: TGDBusError = 17; G_DBUS_ERROR_FILE_EXISTS: TGDBusError = 18; G_DBUS_ERROR_UNKNOWN_METHOD: TGDBusError = 19; G_DBUS_ERROR_TIMED_OUT: TGDBusError = 20; G_DBUS_ERROR_MATCH_RULE_NOT_FOUND: TGDBusError = 21; G_DBUS_ERROR_MATCH_RULE_INVALID: TGDBusError = 22; G_DBUS_ERROR_SPAWN_EXEC_FAILED: TGDBusError = 23; G_DBUS_ERROR_SPAWN_FORK_FAILED: TGDBusError = 24; G_DBUS_ERROR_SPAWN_CHILD_EXITED: TGDBusError = 25; G_DBUS_ERROR_SPAWN_CHILD_SIGNALED: TGDBusError = 26; G_DBUS_ERROR_SPAWN_FAILED: TGDBusError = 27; G_DBUS_ERROR_SPAWN_SETUP_FAILED: TGDBusError = 28; G_DBUS_ERROR_SPAWN_CONFIG_INVALID: TGDBusError = 29; G_DBUS_ERROR_SPAWN_SERVICE_INVALID: TGDBusError = 30; G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND: TGDBusError = 31; G_DBUS_ERROR_SPAWN_PERMISSIONS_INVALID: TGDBusError = 32; G_DBUS_ERROR_SPAWN_FILE_INVALID: TGDBusError = 33; G_DBUS_ERROR_SPAWN_NO_MEMORY: TGDBusError = 34; G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN: TGDBusError = 35; G_DBUS_ERROR_INVALID_SIGNATURE: TGDBusError = 36; G_DBUS_ERROR_INVALID_FILE_CONTENT: TGDBusError = 37; G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN: TGDBusError = 38; G_DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN: TGDBusError = 39; G_DBUS_ERROR_OBJECT_PATH_IN_USE: TGDBusError = 40; type TGDBusPropertyInfoFlags = Integer; const { GDBusPropertyInfoFlags } G_DBUS_PROPERTY_INFO_FLAGS_NONE: TGDBusPropertyInfoFlags = 0; G_DBUS_PROPERTY_INFO_FLAGS_READABLE: TGDBusPropertyInfoFlags = 1; G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE: TGDBusPropertyInfoFlags = 2; type TGDBusInterfaceSkeletonFlags = Integer; const { GDBusInterfaceSkeletonFlags } G_DBUS_INTERFACE_SKELETON_FLAGS_NONE: TGDBusInterfaceSkeletonFlags = 0; G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD: TGDBusInterfaceSkeletonFlags = 1; type TGDBusObjectManagerClientFlags = Integer; const { GDBusObjectManagerClientFlags } G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE: TGDBusObjectManagerClientFlags = 0; G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START: TGDBusObjectManagerClientFlags = 1; type TGDBusProxyFlags = Integer; const { GDBusProxyFlags } G_DBUS_PROXY_FLAGS_NONE: TGDBusProxyFlags = 0; G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES: TGDBusProxyFlags = 1; G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS: TGDBusProxyFlags = 2; G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START: TGDBusProxyFlags = 4; G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES: TGDBusProxyFlags = 8; type TGDBusServerFlags = Integer; const { GDBusServerFlags } G_DBUS_SERVER_FLAGS_NONE: TGDBusServerFlags = 0; G_DBUS_SERVER_FLAGS_RUN_IN_THREAD: TGDBusServerFlags = 1; G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS: TGDBusServerFlags = 2; type TGDataStreamByteOrder = Integer; const { GDataStreamByteOrder } G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: TGDataStreamByteOrder = 0; G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: TGDataStreamByteOrder = 1; G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: TGDataStreamByteOrder = 2; type TGDataStreamNewlineType = Integer; const { GDataStreamNewlineType } G_DATA_STREAM_NEWLINE_TYPE_LF: TGDataStreamNewlineType = 0; G_DATA_STREAM_NEWLINE_TYPE_CR: TGDataStreamNewlineType = 1; G_DATA_STREAM_NEWLINE_TYPE_CR_LF: TGDataStreamNewlineType = 2; G_DATA_STREAM_NEWLINE_TYPE_ANY: TGDataStreamNewlineType = 3; type TGMountOperationResult = Integer; const { GMountOperationResult } G_MOUNT_OPERATION_HANDLED: TGMountOperationResult = 0; G_MOUNT_OPERATION_ABORTED: TGMountOperationResult = 1; G_MOUNT_OPERATION_UNHANDLED: TGMountOperationResult = 2; type TGPasswordSave = Integer; const { GPasswordSave } G_PASSWORD_SAVE_NEVER: TGPasswordSave = 0; G_PASSWORD_SAVE_FOR_SESSION: TGPasswordSave = 1; G_PASSWORD_SAVE_PERMANENTLY: TGPasswordSave = 2; type TGDriveStartStopType = Integer; const { GDriveStartStopType } G_DRIVE_START_STOP_TYPE_UNKNOWN: TGDriveStartStopType = 0; G_DRIVE_START_STOP_TYPE_SHUTDOWN: TGDriveStartStopType = 1; G_DRIVE_START_STOP_TYPE_NETWORK: TGDriveStartStopType = 2; G_DRIVE_START_STOP_TYPE_MULTIDISK: TGDriveStartStopType = 3; G_DRIVE_START_STOP_TYPE_PASSWORD: TGDriveStartStopType = 4; type TGEmblemOrigin = Integer; const { GEmblemOrigin } G_EMBLEM_ORIGIN_UNKNOWN: TGEmblemOrigin = 0; G_EMBLEM_ORIGIN_DEVICE: TGEmblemOrigin = 1; G_EMBLEM_ORIGIN_LIVEMETADATA: TGEmblemOrigin = 2; G_EMBLEM_ORIGIN_TAG: TGEmblemOrigin = 3; type TGFileMonitorEvent = Integer; const { GFileMonitorEvent } G_FILE_MONITOR_EVENT_CHANGED: TGFileMonitorEvent = 0; G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: TGFileMonitorEvent = 1; G_FILE_MONITOR_EVENT_DELETED: TGFileMonitorEvent = 2; G_FILE_MONITOR_EVENT_CREATED: TGFileMonitorEvent = 3; G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: TGFileMonitorEvent = 4; G_FILE_MONITOR_EVENT_PRE_UNMOUNT: TGFileMonitorEvent = 5; G_FILE_MONITOR_EVENT_UNMOUNTED: TGFileMonitorEvent = 6; G_FILE_MONITOR_EVENT_MOVED: TGFileMonitorEvent = 7; type TGFileAttributeStatus = Integer; const { GFileAttributeStatus } G_FILE_ATTRIBUTE_STATUS_UNSET: TGFileAttributeStatus = 0; G_FILE_ATTRIBUTE_STATUS_SET: TGFileAttributeStatus = 1; G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING: TGFileAttributeStatus = 2; type TGFileType = Integer; const { GFileType } G_FILE_TYPE_UNKNOWN: TGFileType = 0; G_FILE_TYPE_REGULAR: TGFileType = 1; G_FILE_TYPE_DIRECTORY: TGFileType = 2; G_FILE_TYPE_SYMBOLIC_LINK: TGFileType = 3; G_FILE_TYPE_SPECIAL: TGFileType = 4; G_FILE_TYPE_SHORTCUT: TGFileType = 5; G_FILE_TYPE_MOUNTABLE: TGFileType = 6; type TGFileAttributeInfoFlags = Integer; const { GFileAttributeInfoFlags } G_FILE_ATTRIBUTE_INFO_NONE: TGFileAttributeInfoFlags = 0; G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE: TGFileAttributeInfoFlags = 1; G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED: TGFileAttributeInfoFlags = 2; type TGFilesystemPreviewType = Integer; const { GFilesystemPreviewType } G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS: TGFilesystemPreviewType = 0; G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL: TGFilesystemPreviewType = 1; G_FILESYSTEM_PREVIEW_TYPE_NEVER: TGFilesystemPreviewType = 2; type TGIOErrorEnum = Integer; const { GIOErrorEnum } G_IO_ERROR_FAILED: TGIOErrorEnum = 0; G_IO_ERROR_NOT_FOUND: TGIOErrorEnum = 1; G_IO_ERROR_EXISTS: TGIOErrorEnum = 2; G_IO_ERROR_IS_DIRECTORY: TGIOErrorEnum = 3; G_IO_ERROR_NOT_DIRECTORY: TGIOErrorEnum = 4; G_IO_ERROR_NOT_EMPTY: TGIOErrorEnum = 5; G_IO_ERROR_NOT_REGULAR_FILE: TGIOErrorEnum = 6; G_IO_ERROR_NOT_SYMBOLIC_LINK: TGIOErrorEnum = 7; G_IO_ERROR_NOT_MOUNTABLE_FILE: TGIOErrorEnum = 8; G_IO_ERROR_FILENAME_TOO_LONG: TGIOErrorEnum = 9; G_IO_ERROR_INVALID_FILENAME: TGIOErrorEnum = 10; G_IO_ERROR_TOO_MANY_LINKS: TGIOErrorEnum = 11; G_IO_ERROR_NO_SPACE: TGIOErrorEnum = 12; G_IO_ERROR_INVALID_ARGUMENT: TGIOErrorEnum = 13; G_IO_ERROR_PERMISSION_DENIED: TGIOErrorEnum = 14; G_IO_ERROR_NOT_SUPPORTED: TGIOErrorEnum = 15; G_IO_ERROR_NOT_MOUNTED: TGIOErrorEnum = 16; G_IO_ERROR_ALREADY_MOUNTED: TGIOErrorEnum = 17; G_IO_ERROR_CLOSED: TGIOErrorEnum = 18; G_IO_ERROR_CANCELLED: TGIOErrorEnum = 19; G_IO_ERROR_PENDING: TGIOErrorEnum = 20; G_IO_ERROR_READ_ONLY: TGIOErrorEnum = 21; G_IO_ERROR_CANT_CREATE_BACKUP: TGIOErrorEnum = 22; G_IO_ERROR_WRONG_ETAG: TGIOErrorEnum = 23; G_IO_ERROR_TIMED_OUT: TGIOErrorEnum = 24; G_IO_ERROR_WOULD_RECURSE: TGIOErrorEnum = 25; G_IO_ERROR_BUSY: TGIOErrorEnum = 26; G_IO_ERROR_WOULD_BLOCK: TGIOErrorEnum = 27; G_IO_ERROR_HOST_NOT_FOUND: TGIOErrorEnum = 28; G_IO_ERROR_WOULD_MERGE: TGIOErrorEnum = 29; G_IO_ERROR_FAILED_HANDLED: TGIOErrorEnum = 30; G_IO_ERROR_TOO_MANY_OPEN_FILES: TGIOErrorEnum = 31; G_IO_ERROR_NOT_INITIALIZED: TGIOErrorEnum = 32; G_IO_ERROR_ADDRESS_IN_USE: TGIOErrorEnum = 33; G_IO_ERROR_PARTIAL_INPUT: TGIOErrorEnum = 34; G_IO_ERROR_INVALID_DATA: TGIOErrorEnum = 35; G_IO_ERROR_DBUS_ERROR: TGIOErrorEnum = 36; G_IO_ERROR_HOST_UNREACHABLE: TGIOErrorEnum = 37; G_IO_ERROR_NETWORK_UNREACHABLE: TGIOErrorEnum = 38; G_IO_ERROR_CONNECTION_REFUSED: TGIOErrorEnum = 39; G_IO_ERROR_PROXY_FAILED: TGIOErrorEnum = 40; G_IO_ERROR_PROXY_AUTH_FAILED: TGIOErrorEnum = 41; G_IO_ERROR_PROXY_NEED_AUTH: TGIOErrorEnum = 42; G_IO_ERROR_PROXY_NOT_ALLOWED: TGIOErrorEnum = 43; G_IO_ERROR_BROKEN_PIPE: TGIOErrorEnum = 44; type TGIOModuleScopeFlags = Integer; const { GIOModuleScopeFlags } G_IO_MODULE_SCOPE_NONE: TGIOModuleScopeFlags = 0; G_IO_MODULE_SCOPE_BLOCK_DUPLICATES: TGIOModuleScopeFlags = 1; type TGSocketFamily = Integer; const { GSocketFamily } G_SOCKET_FAMILY_INVALID: TGSocketFamily = 0; G_SOCKET_FAMILY_UNIX: TGSocketFamily = 1; G_SOCKET_FAMILY_IPV4: TGSocketFamily = 2; G_SOCKET_FAMILY_IPV6: TGSocketFamily = 10; type TGResolverRecordType = Integer; const { GResolverRecordType } G_RESOLVER_RECORD_SRV: TGResolverRecordType = 1; G_RESOLVER_RECORD_MX: TGResolverRecordType = 2; G_RESOLVER_RECORD_TXT: TGResolverRecordType = 3; G_RESOLVER_RECORD_SOA: TGResolverRecordType = 4; G_RESOLVER_RECORD_NS: TGResolverRecordType = 5; type TGResolverError = Integer; const { GResolverError } G_RESOLVER_ERROR_NOT_FOUND: TGResolverError = 0; G_RESOLVER_ERROR_TEMPORARY_FAILURE: TGResolverError = 1; G_RESOLVER_ERROR_INTERNAL: TGResolverError = 2; type TGResourceLookupFlags = Integer; const { GResourceLookupFlags } G_RESOURCE_LOOKUP_FLAGS_NONE: TGResourceLookupFlags = 0; type TGResourceError = Integer; const { GResourceError } G_RESOURCE_ERROR_NOT_FOUND: TGResourceError = 0; G_RESOURCE_ERROR_INTERNAL: TGResourceError = 1; type TGResourceFlags = Integer; const { GResourceFlags } G_RESOURCE_FLAGS_NONE: TGResourceFlags = 0; G_RESOURCE_FLAGS_COMPRESSED: TGResourceFlags = 1; type TGSettingsBindFlags = Integer; const { GSettingsBindFlags } G_SETTINGS_BIND_DEFAULT: TGSettingsBindFlags = 0; G_SETTINGS_BIND_GET: TGSettingsBindFlags = 1; G_SETTINGS_BIND_SET: TGSettingsBindFlags = 2; G_SETTINGS_BIND_NO_SENSITIVITY: TGSettingsBindFlags = 4; G_SETTINGS_BIND_GET_NO_CHANGES: TGSettingsBindFlags = 8; G_SETTINGS_BIND_INVERT_BOOLEAN: TGSettingsBindFlags = 16; type TGSocketType = Integer; const { GSocketType } G_SOCKET_TYPE_INVALID: TGSocketType = 0; G_SOCKET_TYPE_STREAM: TGSocketType = 1; G_SOCKET_TYPE_DATAGRAM: TGSocketType = 2; G_SOCKET_TYPE_SEQPACKET: TGSocketType = 3; type TGSocketProtocol = Integer; const { GSocketProtocol } G_SOCKET_PROTOCOL_UNKNOWN: TGSocketProtocol = -1; G_SOCKET_PROTOCOL_DEFAULT: TGSocketProtocol = 0; G_SOCKET_PROTOCOL_TCP: TGSocketProtocol = 6; G_SOCKET_PROTOCOL_UDP: TGSocketProtocol = 17; G_SOCKET_PROTOCOL_SCTP: TGSocketProtocol = 132; type TGTlsCertificateFlags = Integer; const { GTlsCertificateFlags } G_TLS_CERTIFICATE_UNKNOWN_CA: TGTlsCertificateFlags = 1; G_TLS_CERTIFICATE_BAD_IDENTITY: TGTlsCertificateFlags = 2; G_TLS_CERTIFICATE_NOT_ACTIVATED: TGTlsCertificateFlags = 4; G_TLS_CERTIFICATE_EXPIRED: TGTlsCertificateFlags = 8; G_TLS_CERTIFICATE_REVOKED: TGTlsCertificateFlags = 16; G_TLS_CERTIFICATE_INSECURE: TGTlsCertificateFlags = 32; G_TLS_CERTIFICATE_GENERIC_ERROR: TGTlsCertificateFlags = 64; G_TLS_CERTIFICATE_VALIDATE_ALL: TGTlsCertificateFlags = 127; type TGSocketClientEvent = Integer; const { GSocketClientEvent } G_SOCKET_CLIENT_RESOLVING: TGSocketClientEvent = 0; G_SOCKET_CLIENT_RESOLVED: TGSocketClientEvent = 1; G_SOCKET_CLIENT_CONNECTING: TGSocketClientEvent = 2; G_SOCKET_CLIENT_CONNECTED: TGSocketClientEvent = 3; G_SOCKET_CLIENT_PROXY_NEGOTIATING: TGSocketClientEvent = 4; G_SOCKET_CLIENT_PROXY_NEGOTIATED: TGSocketClientEvent = 5; G_SOCKET_CLIENT_TLS_HANDSHAKING: TGSocketClientEvent = 6; G_SOCKET_CLIENT_TLS_HANDSHAKED: TGSocketClientEvent = 7; G_SOCKET_CLIENT_COMPLETE: TGSocketClientEvent = 8; type TGSocketMsgFlags = Integer; const { GSocketMsgFlags } G_SOCKET_MSG_NONE: TGSocketMsgFlags = 0; G_SOCKET_MSG_OOB: TGSocketMsgFlags = 1; G_SOCKET_MSG_PEEK: TGSocketMsgFlags = 2; G_SOCKET_MSG_DONTROUTE: TGSocketMsgFlags = 4; type TGTestDBusFlags = Integer; const { GTestDBusFlags } G_TEST_DBUS_NONE: TGTestDBusFlags = 0; type TGTlsAuthenticationMode = Integer; const { GTlsAuthenticationMode } G_TLS_AUTHENTICATION_NONE: TGTlsAuthenticationMode = 0; G_TLS_AUTHENTICATION_REQUESTED: TGTlsAuthenticationMode = 1; G_TLS_AUTHENTICATION_REQUIRED: TGTlsAuthenticationMode = 2; type TGTlsDatabaseLookupFlags = Integer; const { GTlsDatabaseLookupFlags } G_TLS_DATABASE_LOOKUP_NONE: TGTlsDatabaseLookupFlags = 0; G_TLS_DATABASE_LOOKUP_KEYPAIR: TGTlsDatabaseLookupFlags = 1; type TGTlsDatabaseVerifyFlags = Integer; const { GTlsDatabaseVerifyFlags } G_TLS_DATABASE_VERIFY_NONE: TGTlsDatabaseVerifyFlags = 0; type TGTlsRehandshakeMode = Integer; const { GTlsRehandshakeMode } G_TLS_REHANDSHAKE_NEVER: TGTlsRehandshakeMode = 0; G_TLS_REHANDSHAKE_SAFELY: TGTlsRehandshakeMode = 1; G_TLS_REHANDSHAKE_UNSAFELY: TGTlsRehandshakeMode = 2; type TGTlsError = Integer; const { GTlsError } G_TLS_ERROR_UNAVAILABLE: TGTlsError = 0; G_TLS_ERROR_MISC: TGTlsError = 1; G_TLS_ERROR_BAD_CERTIFICATE: TGTlsError = 2; G_TLS_ERROR_NOT_TLS: TGTlsError = 3; G_TLS_ERROR_HANDSHAKE: TGTlsError = 4; G_TLS_ERROR_CERTIFICATE_REQUIRED: TGTlsError = 5; G_TLS_ERROR_EOF: TGTlsError = 6; type TGTlsInteractionResult = Integer; const { GTlsInteractionResult } G_TLS_INTERACTION_UNHANDLED: TGTlsInteractionResult = 0; G_TLS_INTERACTION_HANDLED: TGTlsInteractionResult = 1; G_TLS_INTERACTION_FAILED: TGTlsInteractionResult = 2; type TGTlsPasswordFlags = Integer; const { GTlsPasswordFlags } G_TLS_PASSWORD_NONE: TGTlsPasswordFlags = 0; G_TLS_PASSWORD_RETRY: TGTlsPasswordFlags = 2; G_TLS_PASSWORD_MANY_TRIES: TGTlsPasswordFlags = 4; G_TLS_PASSWORD_FINAL_TRY: TGTlsPasswordFlags = 8; type TGUnixSocketAddressType = Integer; const { GUnixSocketAddressType } G_UNIX_SOCKET_ADDRESS_INVALID: TGUnixSocketAddressType = 0; G_UNIX_SOCKET_ADDRESS_ANONYMOUS: TGUnixSocketAddressType = 1; G_UNIX_SOCKET_ADDRESS_PATH: TGUnixSocketAddressType = 2; G_UNIX_SOCKET_ADDRESS_ABSTRACT: TGUnixSocketAddressType = 3; G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED: TGUnixSocketAddressType = 4; type TGZlibCompressorFormat = Integer; const { GZlibCompressorFormat } G_ZLIB_COMPRESSOR_FORMAT_ZLIB: TGZlibCompressorFormat = 0; G_ZLIB_COMPRESSOR_FORMAT_GZIP: TGZlibCompressorFormat = 1; G_ZLIB_COMPRESSOR_FORMAT_RAW: TGZlibCompressorFormat = 2; type PPGAction = ^PGAction; PGAction = ^TGAction; TGAction = object end; PPGSimpleAction = ^PGSimpleAction; PGSimpleAction = ^TGSimpleAction; TGSimpleAction = object(TGObject) end; PPGActionEntry = ^PGActionEntry; PGActionEntry = ^TGActionEntry; TGActionEntry = record name: Pgchar; activate: procedure(action: PGSimpleAction; parameter: PGVariant; user_data: gpointer); cdecl; parameter_type: Pgchar; state: Pgchar; change_state: procedure(action: PGSimpleAction; value: PGVariant; user_data: gpointer); cdecl; padding: array [0..2] of gsize; end; PPGActionGroup = ^PGActionGroup; PGActionGroup = ^TGActionGroup; TGActionGroup = object action_added1: procedure(action_name: Pgchar); cdecl; action_enabled_changed1: procedure(action_name: Pgchar; enabled: gboolean); cdecl; action_removed1: procedure(action_name: Pgchar); cdecl; action_state_changed1: procedure(action_name: Pgchar; value: TGVariant); cdecl; end; PPGActionGroupInterface = ^PGActionGroupInterface; PGActionGroupInterface = ^TGActionGroupInterface; TGActionGroupInterface = object g_iface: TGTypeInterface; has_action: function(action_group: PGActionGroup; action_name: Pgchar): gboolean; cdecl; list_actions: function(action_group: PGActionGroup): PPgchar; cdecl; get_action_enabled: function(action_group: PGActionGroup; action_name: Pgchar): gboolean; cdecl; get_action_parameter_type: function(action_group: PGActionGroup; action_name: Pgchar): PGVariantType; cdecl; get_action_state_type: function(action_group: PGActionGroup; action_name: Pgchar): PGVariantType; cdecl; get_action_state_hint: function(action_group: PGActionGroup; action_name: Pgchar): PGVariant; cdecl; get_action_state: function(action_group: PGActionGroup; action_name: Pgchar): PGVariant; cdecl; change_action_state: procedure(action_group: PGActionGroup; action_name: Pgchar; value: PGVariant); cdecl; activate_action: procedure(action_group: PGActionGroup; action_name: Pgchar; parameter: PGVariant); cdecl; action_added: procedure(action_group: PGActionGroup; action_name: Pgchar); cdecl; action_removed: procedure(action_group: PGActionGroup; action_name: Pgchar); cdecl; action_enabled_changed: procedure(action_group: PGActionGroup; action_name: Pgchar; enabled: gboolean); cdecl; action_state_changed: procedure(action_group: PGActionGroup; action_name: Pgchar; state: PGVariant); cdecl; query_action: function(action_group: PGActionGroup; action_name: Pgchar; enabled: Pgboolean; parameter_type: PPGVariantType; state_type: PPGVariantType; state_hint: PPGVariant; state: PPGVariant): gboolean; cdecl; end; PPGActionInterface = ^PGActionInterface; PGActionInterface = ^TGActionInterface; TGActionInterface = object g_iface: TGTypeInterface; get_name: function(action: PGAction): Pgchar; cdecl; get_parameter_type: function(action: PGAction): PGVariantType; cdecl; get_state_type: function(action: PGAction): PGVariantType; cdecl; get_state_hint: function(action: PGAction): PGVariant; cdecl; get_enabled: function(action: PGAction): gboolean; cdecl; get_state: function(action: PGAction): PGVariant; cdecl; change_state: procedure(action: PGAction; value: PGVariant); cdecl; activate: procedure(action: PGAction; parameter: PGVariant); cdecl; end; PPGActionMap = ^PGActionMap; PGActionMap = ^TGActionMap; TGActionMap = object end; PPGActionMapInterface = ^PGActionMapInterface; PGActionMapInterface = ^TGActionMapInterface; TGActionMapInterface = object g_iface: TGTypeInterface; lookup_action: function(action_map: PGActionMap; action_name: Pgchar): PGAction; cdecl; add_action: procedure(action_map: PGActionMap; action: PGAction); cdecl; remove_action: procedure(action_map: PGActionMap; action_name: Pgchar); cdecl; end; PPGAppInfo = ^PGAppInfo; PGAppInfo = ^TGAppInfo; PPGAppInfoCreateFlags = ^PGAppInfoCreateFlags; PGAppInfoCreateFlags = ^TGAppInfoCreateFlags; PPGAppLaunchContext = ^PGAppLaunchContext; PGAppLaunchContext = ^TGAppLaunchContext; PPGIcon = ^PGIcon; PGIcon = ^TGIcon; TGAppInfo = object end; PPGAppLaunchContextPrivate = ^PGAppLaunchContextPrivate; PGAppLaunchContextPrivate = ^TGAppLaunchContextPrivate; TGAppLaunchContext = object(TGObject) priv: PGAppLaunchContextPrivate; end; TGIcon = object end; PPGAppInfoIface = ^PGAppInfoIface; PGAppInfoIface = ^TGAppInfoIface; TGAppInfoIface = object g_iface: TGTypeInterface; dup: function(appinfo: PGAppInfo): PGAppInfo; cdecl; equal: function(appinfo1: PGAppInfo; appinfo2: PGAppInfo): gboolean; cdecl; get_id: function(appinfo: PGAppInfo): Pgchar; cdecl; get_name: function(appinfo: PGAppInfo): Pgchar; cdecl; get_description: function(appinfo: PGAppInfo): Pgchar; cdecl; get_executable: function(appinfo: PGAppInfo): Pgchar; cdecl; get_icon: function(appinfo: PGAppInfo): PGIcon; cdecl; launch: function(appinfo: PGAppInfo; files: PGList; launch_context: PGAppLaunchContext; error: PPGError): gboolean; cdecl; supports_uris: function(appinfo: PGAppInfo): gboolean; cdecl; supports_files: function(appinfo: PGAppInfo): gboolean; cdecl; launch_uris: function(appinfo: PGAppInfo; uris: PGList; launch_context: PGAppLaunchContext; error: PPGError): gboolean; cdecl; should_show: function(appinfo: PGAppInfo): gboolean; cdecl; set_as_default_for_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; set_as_default_for_extension: function(appinfo: PGAppInfo; extension: Pgchar; error: PPGError): gboolean; cdecl; add_supports_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; can_remove_supports_type: function(appinfo: PGAppInfo): gboolean; cdecl; remove_supports_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; can_delete: function(appinfo: PGAppInfo): gboolean; cdecl; do_delete: function(appinfo: PGAppInfo): gboolean; cdecl; get_commandline: function(appinfo: PGAppInfo): Pgchar; cdecl; get_display_name: function(appinfo: PGAppInfo): Pgchar; cdecl; set_as_last_used_for_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; get_supported_types: function(appinfo: PGAppInfo): PPgchar; cdecl; end; TGAppLaunchContextPrivate = record end; PPGAppLaunchContextClass = ^PGAppLaunchContextClass; PGAppLaunchContextClass = ^TGAppLaunchContextClass; TGAppLaunchContextClass = object parent_class: TGObjectClass; get_display: function(context: PGAppLaunchContext; info: PGAppInfo; files: PGList): Pgchar; cdecl; get_startup_notify_id: function(context: PGAppLaunchContext; info: PGAppInfo; files: PGList): Pgchar; cdecl; launch_failed: procedure(context: PGAppLaunchContext; startup_notify_id: Pgchar); cdecl; launched: procedure(context: PGAppLaunchContext; info: PGAppInfo; platform_data: PGVariant); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; end; PPGApplication = ^PGApplication; PGApplication = ^TGApplication; PPGApplicationFlags = ^PGApplicationFlags; PGApplicationFlags = ^TGApplicationFlags; PPGDBusConnection = ^PGDBusConnection; PGDBusConnection = ^TGDBusConnection; PPGFile = ^PGFile; PGFile = ^TGFile; PPGCancellable = ^PGCancellable; PGCancellable = ^TGCancellable; PPGApplicationPrivate = ^PGApplicationPrivate; PGApplicationPrivate = ^TGApplicationPrivate; TGApplication = object(TGObject) priv: PGApplicationPrivate; end; PPGApplicationCommandLine = ^PGApplicationCommandLine; PGApplicationCommandLine = ^TGApplicationCommandLine; PPGInputStream = ^PGInputStream; PGInputStream = ^TGInputStream; PPGApplicationCommandLinePrivate = ^PGApplicationCommandLinePrivate; PGApplicationCommandLinePrivate = ^TGApplicationCommandLinePrivate; TGApplicationCommandLine = object(TGObject) priv: PGApplicationCommandLinePrivate; end; PPGAsyncResult = ^PGAsyncResult; PGAsyncResult = ^TGAsyncResult; PPGDBusConnectionFlags = ^PGDBusConnectionFlags; PGDBusConnectionFlags = ^TGDBusConnectionFlags; PPGDBusAuthObserver = ^PGDBusAuthObserver; PGDBusAuthObserver = ^TGDBusAuthObserver; PPGIOStream = ^PGIOStream; PGIOStream = ^TGIOStream; PPGAsyncReadyCallback = ^PGAsyncReadyCallback; PGAsyncReadyCallback = ^TGAsyncReadyCallback; TGAsyncReadyCallback = procedure(source_object: PGObject; res: PGAsyncResult; user_data: gpointer); cdecl; PPGDBusMessageFilterFunction = ^PGDBusMessageFilterFunction; PGDBusMessageFilterFunction = ^TGDBusMessageFilterFunction; PPGDBusMessage = ^PGDBusMessage; PGDBusMessage = ^TGDBusMessage; TGDBusMessageFilterFunction = function(connection: PGDBusConnection; message: PGDBusMessage; incoming: gboolean; user_data: gpointer): PGDBusMessage; cdecl; PPGDBusCallFlags = ^PGDBusCallFlags; PGDBusCallFlags = ^TGDBusCallFlags; PPGUnixFDList = ^PGUnixFDList; PGUnixFDList = ^TGUnixFDList; PPGMenuModel = ^PGMenuModel; PGMenuModel = ^TGMenuModel; PPGDBusCapabilityFlags = ^PGDBusCapabilityFlags; PGDBusCapabilityFlags = ^TGDBusCapabilityFlags; PPGCredentials = ^PGCredentials; PGCredentials = ^TGCredentials; PPGDBusInterfaceInfo = ^PGDBusInterfaceInfo; PGDBusInterfaceInfo = ^TGDBusInterfaceInfo; PPGDBusInterfaceVTable = ^PGDBusInterfaceVTable; PGDBusInterfaceVTable = ^TGDBusInterfaceVTable; PPGDBusSubtreeVTable = ^PGDBusSubtreeVTable; PGDBusSubtreeVTable = ^TGDBusSubtreeVTable; PPGDBusSubtreeFlags = ^PGDBusSubtreeFlags; PGDBusSubtreeFlags = ^TGDBusSubtreeFlags; PPGDBusSendMessageFlags = ^PGDBusSendMessageFlags; PGDBusSendMessageFlags = ^TGDBusSendMessageFlags; PPGDBusSignalFlags = ^PGDBusSignalFlags; PGDBusSignalFlags = ^TGDBusSignalFlags; PPGDBusSignalCallback = ^PGDBusSignalCallback; PGDBusSignalCallback = ^TGDBusSignalCallback; TGDBusSignalCallback = procedure(connection: PGDBusConnection; sender_name: Pgchar; object_path: Pgchar; interface_name: Pgchar; signal_name: Pgchar; parameters: PGVariant; user_data: gpointer); cdecl; TGDBusConnection = object(TGObject) end; PPGFileIOStream = ^PGFileIOStream; PGFileIOStream = ^TGFileIOStream; PPGFileOutputStream = ^PGFileOutputStream; PGFileOutputStream = ^TGFileOutputStream; PPGFileCreateFlags = ^PGFileCreateFlags; PGFileCreateFlags = ^TGFileCreateFlags; PPGFileCopyFlags = ^PGFileCopyFlags; PGFileCopyFlags = ^TGFileCopyFlags; PPGFileProgressCallback = ^PGFileProgressCallback; PGFileProgressCallback = ^TGFileProgressCallback; TGFileProgressCallback = procedure(current_num_bytes: gint64; total_num_bytes: gint64; user_data: gpointer); cdecl; PPGMountUnmountFlags = ^PGMountUnmountFlags; PGMountUnmountFlags = ^TGMountUnmountFlags; PPGMountOperation = ^PGMountOperation; PGMountOperation = ^TGMountOperation; PPGFileEnumerator = ^PGFileEnumerator; PGFileEnumerator = ^TGFileEnumerator; PPGFileQueryInfoFlags = ^PGFileQueryInfoFlags; PGFileQueryInfoFlags = ^TGFileQueryInfoFlags; PPGMount = ^PGMount; PGMount = ^TGMount; PPGFileReadMoreCallback = ^PGFileReadMoreCallback; PGFileReadMoreCallback = ^TGFileReadMoreCallback; TGFileReadMoreCallback = function(file_contents: Pgchar; file_size: gint64; callback_data: gpointer): gboolean; cdecl; PPGFileMonitor = ^PGFileMonitor; PGFileMonitor = ^TGFileMonitor; PPGFileMonitorFlags = ^PGFileMonitorFlags; PGFileMonitorFlags = ^TGFileMonitorFlags; PPGMountMountFlags = ^PGMountMountFlags; PGMountMountFlags = ^TGMountMountFlags; PPGFileType = ^PGFileType; PGFileType = ^TGFileType; PPGFileInfo = ^PGFileInfo; PGFileInfo = ^TGFileInfo; PPGFileAttributeInfoList = ^PGFileAttributeInfoList; PGFileAttributeInfoList = ^TGFileAttributeInfoList; PPGFileInputStream = ^PGFileInputStream; PGFileInputStream = ^TGFileInputStream; PPGFileAttributeType = ^PGFileAttributeType; PGFileAttributeType = ^TGFileAttributeType; PPGDriveStartFlags = ^PGDriveStartFlags; PGDriveStartFlags = ^TGDriveStartFlags; TGFile = object end; PPGCancellablePrivate = ^PGCancellablePrivate; PGCancellablePrivate = ^TGCancellablePrivate; TGCancellable = object(TGObject) priv: PGCancellablePrivate; end; TGApplicationPrivate = record end; PPGApplicationClass = ^PGApplicationClass; PGApplicationClass = ^TGApplicationClass; TGApplicationClass = object parent_class: TGObjectClass; startup: procedure(application: PGApplication); cdecl; activate: procedure(application: PGApplication); cdecl; open: procedure(application: PGApplication; files: PPGFile; n_files: gint; hint: Pgchar); cdecl; command_line: function(application: PGApplication; command_line: PGApplicationCommandLine): gint; cdecl; local_command_line: function(application: PGApplication; arguments: PPPgchar; exit_status: Pgint): gboolean; cdecl; before_emit: procedure(application: PGApplication; platform_data: PGVariant); cdecl; after_emit: procedure(application: PGApplication; platform_data: PGVariant); cdecl; add_platform_data: procedure(application: PGApplication; builder: PGVariantBuilder); cdecl; quit_mainloop: procedure(application: PGApplication); cdecl; run_mainloop: procedure(application: PGApplication); cdecl; shutdown: procedure(application: PGApplication); cdecl; dbus_register: function(application: PGApplication; connection: PGDBusConnection; object_path: Pgchar; error: PPGError): gboolean; cdecl; dbus_unregister: procedure(application: PGApplication; connection: PGDBusConnection; object_path: Pgchar); cdecl; padding: array [0..8] of gpointer; end; PPGInputStreamPrivate = ^PGInputStreamPrivate; PGInputStreamPrivate = ^TGInputStreamPrivate; TGInputStream = object(TGObject) priv: PGInputStreamPrivate; end; TGApplicationCommandLinePrivate = record end; PPGApplicationCommandLineClass = ^PGApplicationCommandLineClass; PGApplicationCommandLineClass = ^TGApplicationCommandLineClass; TGApplicationCommandLineClass = object parent_class: TGObjectClass; print_literal: procedure(cmdline: PGApplicationCommandLine; message: Pgchar); cdecl; printerr_literal: procedure(cmdline: PGApplicationCommandLine; message: Pgchar); cdecl; get_stdin: function(cmdline: PGApplicationCommandLine): PGInputStream; cdecl; padding: array [0..10] of gpointer; end; PPGAskPasswordFlags = ^PGAskPasswordFlags; PGAskPasswordFlags = ^TGAskPasswordFlags; PPGAsyncInitable = ^PGAsyncInitable; PGAsyncInitable = ^TGAsyncInitable; TGAsyncInitable = object end; TGAsyncResult = object end; PPGAsyncInitableIface = ^PGAsyncInitableIface; PGAsyncInitableIface = ^TGAsyncInitableIface; TGAsyncInitableIface = object g_iface: TGTypeInterface; init_async: procedure(initable: PGAsyncInitable; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; init_finish: function(initable: PGAsyncInitable; res: PGAsyncResult; error: PPGError): gboolean; cdecl; end; PPGAsyncResultIface = ^PGAsyncResultIface; PGAsyncResultIface = ^TGAsyncResultIface; TGAsyncResultIface = object g_iface: TGTypeInterface; get_user_data: function(res: PGAsyncResult): gpointer; cdecl; get_source_object: function(res: PGAsyncResult): PGObject; cdecl; is_tagged: function(res: PGAsyncResult; source_tag: gpointer): gboolean; cdecl; end; PPGSeekable = ^PGSeekable; PGSeekable = ^TGSeekable; TGSeekable = object end; PPGBufferedInputStream = ^PGBufferedInputStream; PGBufferedInputStream = ^TGBufferedInputStream; PPGFilterInputStream = ^PGFilterInputStream; PGFilterInputStream = ^TGFilterInputStream; TGFilterInputStream = object(TGInputStream) base_stream: PGInputStream; end; PPGBufferedInputStreamPrivate = ^PGBufferedInputStreamPrivate; PGBufferedInputStreamPrivate = ^TGBufferedInputStreamPrivate; TGBufferedInputStream = object(TGFilterInputStream) priv1: PGBufferedInputStreamPrivate; end; TGBufferedInputStreamPrivate = record end; PPGFilterInputStreamClass = ^PGFilterInputStreamClass; PGFilterInputStreamClass = ^TGFilterInputStreamClass; PPGInputStreamClass = ^PGInputStreamClass; PGInputStreamClass = ^TGInputStreamClass; TGInputStreamClass = object parent_class: TGObjectClass; read_fn: function(stream: PGInputStream; buffer: Pgpointer; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; skip: function(stream: PGInputStream; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; close_fn: function(stream: PGInputStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; read_async: procedure(stream: PGInputStream; buffer: Pguint8; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; read_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; skip_async: procedure(stream: PGInputStream; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; skip_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; close_async: procedure(stream: PGInputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; close_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; TGFilterInputStreamClass = object parent_class: TGInputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; end; PPGBufferedInputStreamClass = ^PGBufferedInputStreamClass; PGBufferedInputStreamClass = ^TGBufferedInputStreamClass; TGBufferedInputStreamClass = object parent_class: TGFilterInputStreamClass; fill: function(stream: PGBufferedInputStream; count: gssize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; fill_async: procedure(stream: PGBufferedInputStream; count: gssize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; fill_finish: function(stream: PGBufferedInputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGOutputStream = ^PGOutputStream; PGOutputStream = ^TGOutputStream; PPGOutputStreamSpliceFlags = ^PGOutputStreamSpliceFlags; PGOutputStreamSpliceFlags = ^TGOutputStreamSpliceFlags; PPGOutputStreamPrivate = ^PGOutputStreamPrivate; PGOutputStreamPrivate = ^TGOutputStreamPrivate; TGOutputStream = object(TGObject) priv: PGOutputStreamPrivate; end; PPGBufferedOutputStream = ^PGBufferedOutputStream; PGBufferedOutputStream = ^TGBufferedOutputStream; PPGFilterOutputStream = ^PGFilterOutputStream; PGFilterOutputStream = ^TGFilterOutputStream; TGFilterOutputStream = object(TGOutputStream) base_stream: PGOutputStream; end; PPGBufferedOutputStreamPrivate = ^PGBufferedOutputStreamPrivate; PGBufferedOutputStreamPrivate = ^TGBufferedOutputStreamPrivate; TGBufferedOutputStream = object(TGFilterOutputStream) priv1: PGBufferedOutputStreamPrivate; end; TGBufferedOutputStreamPrivate = record end; PPGFilterOutputStreamClass = ^PGFilterOutputStreamClass; PGFilterOutputStreamClass = ^TGFilterOutputStreamClass; PPGOutputStreamClass = ^PGOutputStreamClass; PGOutputStreamClass = ^TGOutputStreamClass; TGOutputStreamClass = object parent_class: TGObjectClass; write_fn: function(stream: PGOutputStream; buffer: Pguint8; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; splice: function(stream: PGOutputStream; source: PGInputStream; flags: TGOutputStreamSpliceFlags; cancellable: PGCancellable; error: PPGError): gssize; cdecl; flush: function(stream: PGOutputStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; close_fn: function(stream: PGOutputStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; write_async: procedure(stream: PGOutputStream; buffer: Pguint8; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; write_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; splice_async: procedure(stream: PGOutputStream; source: PGInputStream; flags: TGOutputStreamSpliceFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; splice_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; flush_async: procedure(stream: PGOutputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; flush_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; close_async: procedure(stream: PGOutputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; close_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; _g_reserved8: procedure; cdecl; end; TGFilterOutputStreamClass = object parent_class: TGOutputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; end; PPGBufferedOutputStreamClass = ^PGBufferedOutputStreamClass; PGBufferedOutputStreamClass = ^TGBufferedOutputStreamClass; TGBufferedOutputStreamClass = object parent_class: TGFilterOutputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; end; TGBusAcquiredCallback = procedure(connection: PGDBusConnection; name: Pgchar; user_data: gpointer); cdecl; TGBusNameAcquiredCallback = procedure(connection: PGDBusConnection; name: Pgchar; user_data: gpointer); cdecl; TGBusNameAppearedCallback = procedure(connection: PGDBusConnection; name: Pgchar; name_owner: Pgchar; user_data: gpointer); cdecl; TGBusNameLostCallback = procedure(connection: PGDBusConnection; name: Pgchar; user_data: gpointer); cdecl; PPGBusNameOwnerFlags = ^PGBusNameOwnerFlags; PGBusNameOwnerFlags = ^TGBusNameOwnerFlags; TGBusNameVanishedCallback = procedure(connection: PGDBusConnection; name: Pgchar; user_data: gpointer); cdecl; PPGBusNameWatcherFlags = ^PGBusNameWatcherFlags; PGBusNameWatcherFlags = ^TGBusNameWatcherFlags; PPGBusType = ^PGBusType; PGBusType = ^TGBusType; TGCancellablePrivate = record end; PPGCancellableClass = ^PGCancellableClass; PGCancellableClass = ^TGCancellableClass; TGCancellableClass = object parent_class: TGObjectClass; cancelled: procedure(cancellable: PGCancellable); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; TGCancellableSourceFunc = function(cancellable: PGCancellable; user_data: gpointer): gboolean; cdecl; PPGConverter = ^PGConverter; PGConverter = ^TGConverter; PPGConverterResult = ^PGConverterResult; PGConverterResult = ^TGConverterResult; PPGConverterFlags = ^PGConverterFlags; PGConverterFlags = ^TGConverterFlags; TGConverter = object end; PPGInitable = ^PGInitable; PGInitable = ^TGInitable; TGInitable = object end; PPGCharsetConverter = ^PGCharsetConverter; PGCharsetConverter = ^TGCharsetConverter; TGCharsetConverter = object(TGObject) end; PPGCharsetConverterClass = ^PGCharsetConverterClass; PGCharsetConverterClass = ^TGCharsetConverterClass; TGCharsetConverterClass = object parent_class: TGObjectClass; end; PPGConverterIface = ^PGConverterIface; PGConverterIface = ^TGConverterIface; TGConverterIface = object g_iface: TGTypeInterface; convert: function(converter: PGConverter; inbuf: Pguint8; inbuf_size: gsize; outbuf: Pgpointer; outbuf_size: gsize; flags: TGConverterFlags; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): TGConverterResult; cdecl; reset: procedure(converter: PGConverter); cdecl; end; PPGPollableInputStream = ^PGPollableInputStream; PGPollableInputStream = ^TGPollableInputStream; TGPollableInputStream = object end; PPGConverterInputStream = ^PGConverterInputStream; PGConverterInputStream = ^TGConverterInputStream; PPGConverterInputStreamPrivate = ^PGConverterInputStreamPrivate; PGConverterInputStreamPrivate = ^TGConverterInputStreamPrivate; TGConverterInputStream = object(TGFilterInputStream) priv1: PGConverterInputStreamPrivate; end; TGConverterInputStreamPrivate = record end; PPGConverterInputStreamClass = ^PGConverterInputStreamClass; PGConverterInputStreamClass = ^TGConverterInputStreamClass; TGConverterInputStreamClass = object parent_class: TGFilterInputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGPollableOutputStream = ^PGPollableOutputStream; PGPollableOutputStream = ^TGPollableOutputStream; TGPollableOutputStream = object end; PPGConverterOutputStream = ^PGConverterOutputStream; PGConverterOutputStream = ^TGConverterOutputStream; PPGConverterOutputStreamPrivate = ^PGConverterOutputStreamPrivate; PGConverterOutputStreamPrivate = ^TGConverterOutputStreamPrivate; TGConverterOutputStream = object(TGFilterOutputStream) priv1: PGConverterOutputStreamPrivate; end; TGConverterOutputStreamPrivate = record end; PPGConverterOutputStreamClass = ^PGConverterOutputStreamClass; PGConverterOutputStreamClass = ^TGConverterOutputStreamClass; TGConverterOutputStreamClass = object parent_class: TGFilterOutputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGCredentialsType = ^PGCredentialsType; PGCredentialsType = ^TGCredentialsType; TGCredentials = object(TGObject) end; PPGCredentialsClass = ^PGCredentialsClass; PGCredentialsClass = ^TGCredentialsClass; TGCredentialsClass = object end; PPGRemoteActionGroup = ^PGRemoteActionGroup; PGRemoteActionGroup = ^TGRemoteActionGroup; TGRemoteActionGroup = object end; PPGDBusActionGroup = ^PGDBusActionGroup; PGDBusActionGroup = ^TGDBusActionGroup; TGDBusActionGroup = object(TGObject) end; PPGDBusAnnotationInfo = ^PGDBusAnnotationInfo; PGDBusAnnotationInfo = ^TGDBusAnnotationInfo; TGDBusAnnotationInfo = object ref_count: gint; key: Pgchar; value: Pgchar; annotations: PGDBusAnnotationInfo; end; PPGDBusArgInfo = ^PGDBusArgInfo; PGDBusArgInfo = ^TGDBusArgInfo; TGDBusArgInfo = object ref_count: gint; name: Pgchar; signature: Pgchar; annotations: PGDBusAnnotationInfo; end; TGDBusAuthObserver = object(TGObject) end; PPGIOStreamSpliceFlags = ^PGIOStreamSpliceFlags; PGIOStreamSpliceFlags = ^TGIOStreamSpliceFlags; PPGIOStreamPrivate = ^PGIOStreamPrivate; PGIOStreamPrivate = ^TGIOStreamPrivate; TGIOStream = object(TGObject) priv: PGIOStreamPrivate; end; PPGUnixFDListPrivate = ^PGUnixFDListPrivate; PGUnixFDListPrivate = ^TGUnixFDListPrivate; TGUnixFDList = object(TGObject) priv: PGUnixFDListPrivate; end; PPGMenuAttributeIter = ^PGMenuAttributeIter; PGMenuAttributeIter = ^TGMenuAttributeIter; PPGMenuLinkIter = ^PGMenuLinkIter; PGMenuLinkIter = ^TGMenuLinkIter; PPGMenuModelPrivate = ^PGMenuModelPrivate; PGMenuModelPrivate = ^TGMenuModelPrivate; TGMenuModel = object(TGObject) priv: PGMenuModelPrivate; end; PPGDBusMethodInfo = ^PGDBusMethodInfo; PGDBusMethodInfo = ^TGDBusMethodInfo; PPGDBusPropertyInfo = ^PGDBusPropertyInfo; PGDBusPropertyInfo = ^TGDBusPropertyInfo; PPGDBusSignalInfo = ^PGDBusSignalInfo; PGDBusSignalInfo = ^TGDBusSignalInfo; TGDBusInterfaceInfo = object ref_count: gint; name: Pgchar; methods: PGDBusMethodInfo; signals: PGDBusSignalInfo; properties: PGDBusPropertyInfo; annotations: PGDBusAnnotationInfo; end; PPGDBusInterfaceMethodCallFunc = ^PGDBusInterfaceMethodCallFunc; PGDBusInterfaceMethodCallFunc = ^TGDBusInterfaceMethodCallFunc; PPGDBusMethodInvocation = ^PGDBusMethodInvocation; PGDBusMethodInvocation = ^TGDBusMethodInvocation; TGDBusInterfaceMethodCallFunc = procedure(connection: PGDBusConnection; sender: Pgchar; object_path: Pgchar; interface_name: Pgchar; method_name: Pgchar; parameters: PGVariant; invocation: PGDBusMethodInvocation; user_data: gpointer); cdecl; PPGDBusInterfaceGetPropertyFunc = ^PGDBusInterfaceGetPropertyFunc; PGDBusInterfaceGetPropertyFunc = ^TGDBusInterfaceGetPropertyFunc; TGDBusInterfaceGetPropertyFunc = function(connection: PGDBusConnection; sender: Pgchar; object_path: Pgchar; interface_name: Pgchar; property_name: Pgchar; error: PPGError; user_data: gpointer): PGVariant; cdecl; PPGDBusInterfaceSetPropertyFunc = ^PGDBusInterfaceSetPropertyFunc; PGDBusInterfaceSetPropertyFunc = ^TGDBusInterfaceSetPropertyFunc; TGDBusInterfaceSetPropertyFunc = function(connection: PGDBusConnection; sender: Pgchar; object_path: Pgchar; interface_name: Pgchar; property_name: Pgchar; value: PGVariant; error: PPGError; user_data: gpointer): gboolean; cdecl; TGDBusInterfaceVTable = record method_call: TGDBusInterfaceMethodCallFunc; get_property: TGDBusInterfaceGetPropertyFunc; set_property: TGDBusInterfaceSetPropertyFunc; padding: array [0..7] of gpointer; end; PPGDBusSubtreeEnumerateFunc = ^PGDBusSubtreeEnumerateFunc; PGDBusSubtreeEnumerateFunc = ^TGDBusSubtreeEnumerateFunc; TGDBusSubtreeEnumerateFunc = function(connection: PGDBusConnection; sender: Pgchar; object_path: Pgchar; user_data: gpointer): PPgchar; cdecl; PPGDBusSubtreeIntrospectFunc = ^PGDBusSubtreeIntrospectFunc; PGDBusSubtreeIntrospectFunc = ^TGDBusSubtreeIntrospectFunc; TGDBusSubtreeIntrospectFunc = function(connection: PGDBusConnection; sender: Pgchar; object_path: Pgchar; node: Pgchar; user_data: gpointer): PPGDBusInterfaceInfo; cdecl; PPGDBusSubtreeDispatchFunc = ^PGDBusSubtreeDispatchFunc; PGDBusSubtreeDispatchFunc = ^TGDBusSubtreeDispatchFunc; TGDBusSubtreeDispatchFunc = function(connection: PGDBusConnection; sender: Pgchar; object_path: Pgchar; interface_name: Pgchar; node: Pgchar; out_user_data: Pgpointer; user_data: gpointer): PGDBusInterfaceVTable; cdecl; TGDBusSubtreeVTable = record enumerate: TGDBusSubtreeEnumerateFunc; introspect: TGDBusSubtreeIntrospectFunc; dispatch: TGDBusSubtreeDispatchFunc; padding: array [0..7] of gpointer; end; PPGDBusMessageByteOrder = ^PGDBusMessageByteOrder; PGDBusMessageByteOrder = ^TGDBusMessageByteOrder; PPGDBusMessageFlags = ^PGDBusMessageFlags; PGDBusMessageFlags = ^TGDBusMessageFlags; PPGDBusMessageHeaderField = ^PGDBusMessageHeaderField; PGDBusMessageHeaderField = ^TGDBusMessageHeaderField; PPGDBusMessageType = ^PGDBusMessageType; PGDBusMessageType = ^TGDBusMessageType; TGDBusMessage = object(TGObject) end; PPGDBusErrorEntry = ^PGDBusErrorEntry; PGDBusErrorEntry = ^TGDBusErrorEntry; TGDBusErrorEntry = record error_code: gint; dbus_error_name: Pgchar; end; PPGDBusError = ^PGDBusError; PGDBusError = ^TGDBusError; PPGDBusObject = ^PGDBusObject; PGDBusObject = ^TGDBusObject; PPGDBusInterface = ^PGDBusInterface; PGDBusInterface = ^TGDBusInterface; TGDBusInterface = object end; TGDBusObject = object interface_added: procedure(interface_: TGDBusInterface); cdecl; interface_removed: procedure(interface_: TGDBusInterface); cdecl; end; PPGDBusInterfaceIface = ^PGDBusInterfaceIface; PGDBusInterfaceIface = ^TGDBusInterfaceIface; TGDBusInterfaceIface = object parent_iface: TGTypeInterface; get_info: function(interface_: PGDBusInterface): PGDBusInterfaceInfo; cdecl; get_object: function(interface_: PGDBusInterface): PGDBusObject; cdecl; set_object: procedure(interface_: PGDBusInterface; object_: PGDBusObject); cdecl; dup_object: function(interface_: PGDBusInterface): PGDBusObject; cdecl; end; TGDBusMethodInfo = object ref_count: gint; name: Pgchar; in_args: PGDBusArgInfo; out_args: PGDBusArgInfo; annotations: PGDBusAnnotationInfo; end; TGDBusSignalInfo = object ref_count: gint; name: Pgchar; args: PGDBusArgInfo; annotations: PGDBusAnnotationInfo; end; PPGDBusPropertyInfoFlags = ^PGDBusPropertyInfoFlags; PGDBusPropertyInfoFlags = ^TGDBusPropertyInfoFlags; TGDBusPropertyInfo = object ref_count: gint; name: Pgchar; signature: Pgchar; flags: TGDBusPropertyInfoFlags; annotations: PGDBusAnnotationInfo; end; TGDBusMethodInvocation = object(TGObject) end; PPGDBusInterfaceSkeleton = ^PGDBusInterfaceSkeleton; PGDBusInterfaceSkeleton = ^TGDBusInterfaceSkeleton; PPGDBusInterfaceSkeletonFlags = ^PGDBusInterfaceSkeletonFlags; PGDBusInterfaceSkeletonFlags = ^TGDBusInterfaceSkeletonFlags; PPGDBusInterfaceSkeletonPrivate = ^PGDBusInterfaceSkeletonPrivate; PGDBusInterfaceSkeletonPrivate = ^TGDBusInterfaceSkeletonPrivate; TGDBusInterfaceSkeleton = object(TGObject) priv: PGDBusInterfaceSkeletonPrivate; end; TGDBusInterfaceSkeletonPrivate = record end; PPGDBusInterfaceSkeletonClass = ^PGDBusInterfaceSkeletonClass; PGDBusInterfaceSkeletonClass = ^TGDBusInterfaceSkeletonClass; TGDBusInterfaceSkeletonClass = object parent_class: TGObjectClass; get_info: function(interface_: PGDBusInterfaceSkeleton): PGDBusInterfaceInfo; cdecl; get_vtable: function(interface_: PGDBusInterfaceSkeleton): PGDBusInterfaceVTable; cdecl; get_properties: function(interface_: PGDBusInterfaceSkeleton): PGVariant; cdecl; flush: procedure(interface_: PGDBusInterfaceSkeleton); cdecl; vfunc_padding: array [0..7] of gpointer; g_authorize_method: function(interface_: PGDBusInterfaceSkeleton; invocation: PGDBusMethodInvocation): gboolean; cdecl; signal_padding: array [0..7] of gpointer; end; PPGDBusMenuModel = ^PGDBusMenuModel; PGDBusMenuModel = ^TGDBusMenuModel; TGDBusMenuModel = object(TGMenuModel) end; PPGDBusNodeInfo = ^PGDBusNodeInfo; PGDBusNodeInfo = ^TGDBusNodeInfo; TGDBusNodeInfo = object ref_count: gint; path: Pgchar; interfaces: PGDBusInterfaceInfo; nodes: PGDBusNodeInfo; annotations: PGDBusAnnotationInfo; end; PPGDBusObjectIface = ^PGDBusObjectIface; PGDBusObjectIface = ^TGDBusObjectIface; TGDBusObjectIface = object parent_iface: TGTypeInterface; get_object_path: function(object_: PGDBusObject): Pgchar; cdecl; get_interfaces: function(object_: PGDBusObject): PGList; cdecl; get_interface: function(object_: PGDBusObject; interface_name: Pgchar): PGDBusInterface; cdecl; interface_added: procedure(object_: PGDBusObject; interface_: PGDBusInterface); cdecl; interface_removed: procedure(object_: PGDBusObject; interface_: PGDBusInterface); cdecl; end; PPGDBusObjectManager = ^PGDBusObjectManager; PGDBusObjectManager = ^TGDBusObjectManager; TGDBusObjectManager = object interface_added: procedure(object_: TGDBusObject; interface_: TGDBusInterface); cdecl; interface_removed: procedure(object_: TGDBusObject; interface_: TGDBusInterface); cdecl; object_added: procedure(object_: TGDBusObject); cdecl; object_removed: procedure(object_: TGDBusObject); cdecl; end; PPGDBusObjectManagerClient = ^PGDBusObjectManagerClient; PGDBusObjectManagerClient = ^TGDBusObjectManagerClient; PPGDBusObjectManagerClientFlags = ^PGDBusObjectManagerClientFlags; PGDBusObjectManagerClientFlags = ^TGDBusObjectManagerClientFlags; PPGDBusProxyTypeFunc = ^PGDBusProxyTypeFunc; PGDBusProxyTypeFunc = ^TGDBusProxyTypeFunc; TGDBusProxyTypeFunc = function(manager: PGDBusObjectManagerClient; object_path: Pgchar; interface_name: Pgchar; user_data: gpointer): TGType; cdecl; PPGDBusObjectManagerClientPrivate = ^PGDBusObjectManagerClientPrivate; PGDBusObjectManagerClientPrivate = ^TGDBusObjectManagerClientPrivate; TGDBusObjectManagerClient = object(TGObject) priv: PGDBusObjectManagerClientPrivate; end; PPGDBusObjectProxy = ^PGDBusObjectProxy; PGDBusObjectProxy = ^TGDBusObjectProxy; PPGDBusObjectProxyPrivate = ^PGDBusObjectProxyPrivate; PGDBusObjectProxyPrivate = ^TGDBusObjectProxyPrivate; TGDBusObjectProxy = object(TGObject) priv: PGDBusObjectProxyPrivate; end; PPGDBusProxy = ^PGDBusProxy; PGDBusProxy = ^TGDBusProxy; PPGDBusProxyFlags = ^PGDBusProxyFlags; PGDBusProxyFlags = ^TGDBusProxyFlags; PPGDBusProxyPrivate = ^PGDBusProxyPrivate; PGDBusProxyPrivate = ^TGDBusProxyPrivate; TGDBusProxy = object(TGObject) priv: PGDBusProxyPrivate; end; TGDBusObjectManagerClientPrivate = record end; PPGDBusObjectManagerClientClass = ^PGDBusObjectManagerClientClass; PGDBusObjectManagerClientClass = ^TGDBusObjectManagerClientClass; TGDBusObjectManagerClientClass = object parent_class: TGObjectClass; interface_proxy_signal: procedure(manager: PGDBusObjectManagerClient; object_proxy: PGDBusObjectProxy; interface_proxy: PGDBusProxy; sender_name: Pgchar; signal_name: Pgchar; parameters: PGVariant); cdecl; interface_proxy_properties_changed: procedure(manager: PGDBusObjectManagerClient; object_proxy: PGDBusObjectProxy; interface_proxy: PGDBusProxy; changed_properties: PGVariant; invalidated_properties: PPgchar); cdecl; padding: array [0..7] of gpointer; end; PPGDBusObjectManagerIface = ^PGDBusObjectManagerIface; PGDBusObjectManagerIface = ^TGDBusObjectManagerIface; TGDBusObjectManagerIface = object parent_iface: TGTypeInterface; get_object_path: function(manager: PGDBusObjectManager): Pgchar; cdecl; get_objects: function(manager: PGDBusObjectManager): PGList; cdecl; get_object: function(manager: PGDBusObjectManager; object_path: Pgchar): PGDBusObject; cdecl; get_interface: function(manager: PGDBusObjectManager; object_path: Pgchar; interface_name: Pgchar): PGDBusInterface; cdecl; object_added: procedure(manager: PGDBusObjectManager; object_: PGDBusObject); cdecl; object_removed: procedure(manager: PGDBusObjectManager; object_: PGDBusObject); cdecl; interface_added: procedure(manager: PGDBusObjectManager; object_: PGDBusObject; interface_: PGDBusInterface); cdecl; interface_removed: procedure(manager: PGDBusObjectManager; object_: PGDBusObject; interface_: PGDBusInterface); cdecl; end; PPGDBusObjectManagerServer = ^PGDBusObjectManagerServer; PGDBusObjectManagerServer = ^TGDBusObjectManagerServer; PPGDBusObjectSkeleton = ^PGDBusObjectSkeleton; PGDBusObjectSkeleton = ^TGDBusObjectSkeleton; PPGDBusObjectManagerServerPrivate = ^PGDBusObjectManagerServerPrivate; PGDBusObjectManagerServerPrivate = ^TGDBusObjectManagerServerPrivate; TGDBusObjectManagerServer = object(TGObject) priv: PGDBusObjectManagerServerPrivate; end; PPGDBusObjectSkeletonPrivate = ^PGDBusObjectSkeletonPrivate; PGDBusObjectSkeletonPrivate = ^TGDBusObjectSkeletonPrivate; TGDBusObjectSkeleton = object(TGObject) priv: PGDBusObjectSkeletonPrivate; end; TGDBusObjectManagerServerPrivate = record end; PPGDBusObjectManagerServerClass = ^PGDBusObjectManagerServerClass; PGDBusObjectManagerServerClass = ^TGDBusObjectManagerServerClass; TGDBusObjectManagerServerClass = object parent_class: TGObjectClass; padding: array [0..7] of gpointer; end; TGDBusObjectProxyPrivate = record end; PPGDBusObjectProxyClass = ^PGDBusObjectProxyClass; PGDBusObjectProxyClass = ^TGDBusObjectProxyClass; TGDBusObjectProxyClass = object parent_class: TGObjectClass; padding: array [0..7] of gpointer; end; TGDBusObjectSkeletonPrivate = record end; PPGDBusObjectSkeletonClass = ^PGDBusObjectSkeletonClass; PGDBusObjectSkeletonClass = ^TGDBusObjectSkeletonClass; TGDBusObjectSkeletonClass = object parent_class: TGObjectClass; authorize_method: function(object_: PGDBusObjectSkeleton; interface_: PGDBusInterfaceSkeleton; invocation: PGDBusMethodInvocation): gboolean; cdecl; padding: array [0..7] of gpointer; end; TGDBusProxyPrivate = record end; PPGDBusProxyClass = ^PGDBusProxyClass; PGDBusProxyClass = ^TGDBusProxyClass; TGDBusProxyClass = object parent_class: TGObjectClass; g_properties_changed: procedure(proxy: PGDBusProxy; changed_properties: PGVariant; invalidated_properties: PPgchar); cdecl; g_signal: procedure(proxy: PGDBusProxy; sender_name: Pgchar; signal_name: Pgchar; parameters: PGVariant); cdecl; padding: array [0..31] of gpointer; end; PPGDBusServer = ^PGDBusServer; PGDBusServer = ^TGDBusServer; PPGDBusServerFlags = ^PGDBusServerFlags; PGDBusServerFlags = ^TGDBusServerFlags; TGDBusServer = object(TGObject) end; PPGDataInputStream = ^PGDataInputStream; PGDataInputStream = ^TGDataInputStream; PPGDataStreamByteOrder = ^PGDataStreamByteOrder; PGDataStreamByteOrder = ^TGDataStreamByteOrder; PPGDataStreamNewlineType = ^PGDataStreamNewlineType; PGDataStreamNewlineType = ^TGDataStreamNewlineType; PPGDataInputStreamPrivate = ^PGDataInputStreamPrivate; PGDataInputStreamPrivate = ^TGDataInputStreamPrivate; TGDataInputStream = object(TGBufferedInputStream) priv2: PGDataInputStreamPrivate; end; TGDataInputStreamPrivate = record end; PPGDataInputStreamClass = ^PGDataInputStreamClass; PGDataInputStreamClass = ^TGDataInputStreamClass; TGDataInputStreamClass = object parent_class: TGBufferedInputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGDataOutputStream = ^PGDataOutputStream; PGDataOutputStream = ^TGDataOutputStream; PPGDataOutputStreamPrivate = ^PGDataOutputStreamPrivate; PGDataOutputStreamPrivate = ^TGDataOutputStreamPrivate; TGDataOutputStream = object(TGFilterOutputStream) priv1: PGDataOutputStreamPrivate; end; TGDataOutputStreamPrivate = record end; PPGDataOutputStreamClass = ^PGDataOutputStreamClass; PGDataOutputStreamClass = ^TGDataOutputStreamClass; TGDataOutputStreamClass = object parent_class: TGFilterOutputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGDesktopAppInfo = ^PGDesktopAppInfo; PGDesktopAppInfo = ^TGDesktopAppInfo; PPGDesktopAppLaunchCallback = ^PGDesktopAppLaunchCallback; PGDesktopAppLaunchCallback = ^TGDesktopAppLaunchCallback; TGDesktopAppLaunchCallback = procedure(appinfo: PGDesktopAppInfo; pid: TGPid; user_data: gpointer); cdecl; TGDesktopAppInfo = object(TGObject) end; PPGDesktopAppInfoClass = ^PGDesktopAppInfoClass; PGDesktopAppInfoClass = ^TGDesktopAppInfoClass; TGDesktopAppInfoClass = object parent_class: TGObjectClass; end; PPGDesktopAppInfoLookup = ^PGDesktopAppInfoLookup; PGDesktopAppInfoLookup = ^TGDesktopAppInfoLookup; TGDesktopAppInfoLookup = object end; PPGDesktopAppInfoLookupIface = ^PGDesktopAppInfoLookupIface; PGDesktopAppInfoLookupIface = ^TGDesktopAppInfoLookupIface; TGDesktopAppInfoLookupIface = object g_iface: TGTypeInterface; get_default_for_uri_scheme: function(lookup: PGDesktopAppInfoLookup; uri_scheme: Pgchar): PGAppInfo; cdecl; end; PPGDrive = ^PGDrive; PGDrive = ^TGDrive; PPGDriveStartStopType = ^PGDriveStartStopType; PGDriveStartStopType = ^TGDriveStartStopType; TGDrive = object changed: procedure; cdecl; disconnected: procedure; cdecl; eject_button: procedure; cdecl; stop_button: procedure; cdecl; end; PPGPasswordSave = ^PGPasswordSave; PGPasswordSave = ^TGPasswordSave; PPGMountOperationResult = ^PGMountOperationResult; PGMountOperationResult = ^TGMountOperationResult; PPGMountOperationPrivate = ^PGMountOperationPrivate; PGMountOperationPrivate = ^TGMountOperationPrivate; TGMountOperation = object(TGObject) priv: PGMountOperationPrivate; end; PPGDriveIface = ^PGDriveIface; PGDriveIface = ^TGDriveIface; TGDriveIface = object g_iface: TGTypeInterface; changed: procedure(drive: PGDrive); cdecl; disconnected: procedure(drive: PGDrive); cdecl; eject_button: procedure(drive: PGDrive); cdecl; get_name: function(drive: PGDrive): Pgchar; cdecl; get_icon: function(drive: PGDrive): PGIcon; cdecl; has_volumes: function(drive: PGDrive): gboolean; cdecl; get_volumes: function(drive: PGDrive): PGList; cdecl; is_media_removable: function(drive: PGDrive): gboolean; cdecl; has_media: function(drive: PGDrive): gboolean; cdecl; is_media_check_automatic: function(drive: PGDrive): gboolean; cdecl; can_eject: function(drive: PGDrive): gboolean; cdecl; can_poll_for_media: function(drive: PGDrive): gboolean; cdecl; eject: procedure(drive: PGDrive; flags: TGMountUnmountFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; poll_for_media: procedure(drive: PGDrive; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; poll_for_media_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; get_identifier: function(drive: PGDrive; kind: Pgchar): Pgchar; cdecl; enumerate_identifiers: function(drive: PGDrive): PPgchar; cdecl; get_start_stop_type: function(drive: PGDrive): TGDriveStartStopType; cdecl; can_start: function(drive: PGDrive): gboolean; cdecl; can_start_degraded: function(drive: PGDrive): gboolean; cdecl; start: procedure(drive: PGDrive; flags: TGDriveStartFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; start_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; can_stop: function(drive: PGDrive): gboolean; cdecl; stop: procedure(drive: PGDrive; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; stop_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; stop_button: procedure(drive: PGDrive); cdecl; eject_with_operation: procedure(drive: PGDrive; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_with_operation_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; get_sort_key: function(drive: PGDrive): Pgchar; cdecl; get_symbolic_icon: function(drive: PGDrive): PGIcon; cdecl; end; PPGEmblem = ^PGEmblem; PGEmblem = ^TGEmblem; PPGEmblemOrigin = ^PGEmblemOrigin; PGEmblemOrigin = ^TGEmblemOrigin; TGEmblem = object(TGObject) end; PPGEmblemClass = ^PGEmblemClass; PGEmblemClass = ^TGEmblemClass; TGEmblemClass = object end; PPGEmblemedIcon = ^PGEmblemedIcon; PGEmblemedIcon = ^TGEmblemedIcon; PPGEmblemedIconPrivate = ^PGEmblemedIconPrivate; PGEmblemedIconPrivate = ^TGEmblemedIconPrivate; TGEmblemedIcon = object(TGObject) priv: PGEmblemedIconPrivate; end; TGEmblemedIconPrivate = record end; PPGEmblemedIconClass = ^PGEmblemedIconClass; PGEmblemedIconClass = ^TGEmblemedIconClass; TGEmblemedIconClass = object parent_class: TGObjectClass; end; PPGFileIOStreamPrivate = ^PGFileIOStreamPrivate; PGFileIOStreamPrivate = ^TGFileIOStreamPrivate; TGFileIOStream = object(TGIOStream) priv1: PGFileIOStreamPrivate; end; PPGFileOutputStreamPrivate = ^PGFileOutputStreamPrivate; PGFileOutputStreamPrivate = ^TGFileOutputStreamPrivate; TGFileOutputStream = object(TGOutputStream) priv1: PGFileOutputStreamPrivate; end; PPGFileEnumeratorPrivate = ^PGFileEnumeratorPrivate; PGFileEnumeratorPrivate = ^TGFileEnumeratorPrivate; TGFileEnumerator = object(TGObject) priv: PGFileEnumeratorPrivate; end; PPGVolume = ^PGVolume; PGVolume = ^TGVolume; TGMount = object changed: procedure; cdecl; pre_unmount: procedure; cdecl; unmounted: procedure; cdecl; end; PPGFileMonitorEvent = ^PGFileMonitorEvent; PGFileMonitorEvent = ^TGFileMonitorEvent; PPGFileMonitorPrivate = ^PGFileMonitorPrivate; PGFileMonitorPrivate = ^TGFileMonitorPrivate; TGFileMonitor = object(TGObject) priv: PGFileMonitorPrivate; end; PPGFileAttributeStatus = ^PGFileAttributeStatus; PGFileAttributeStatus = ^TGFileAttributeStatus; PPGFileAttributeMatcher = ^PGFileAttributeMatcher; PGFileAttributeMatcher = ^TGFileAttributeMatcher; TGFileInfo = object(TGObject) end; PPGFileAttributeInfoFlags = ^PGFileAttributeInfoFlags; PGFileAttributeInfoFlags = ^TGFileAttributeInfoFlags; PPGFileAttributeInfo = ^PGFileAttributeInfo; PGFileAttributeInfo = ^TGFileAttributeInfo; TGFileAttributeInfoList = object infos: PGFileAttributeInfo; n_infos: gint; end; PPGFileInputStreamPrivate = ^PGFileInputStreamPrivate; PGFileInputStreamPrivate = ^TGFileInputStreamPrivate; TGFileInputStream = object(TGInputStream) priv1: PGFileInputStreamPrivate; end; TGFileAttributeInfo = record name: Pgchar; type_: TGFileAttributeType; flags: TGFileAttributeInfoFlags; end; TGFileAttributeMatcher = object end; PPGFileDescriptorBased = ^PGFileDescriptorBased; PGFileDescriptorBased = ^TGFileDescriptorBased; TGFileDescriptorBased = object end; PPGFileDescriptorBasedIface = ^PGFileDescriptorBasedIface; PGFileDescriptorBasedIface = ^TGFileDescriptorBasedIface; TGFileDescriptorBasedIface = object g_iface: TGTypeInterface; get_fd: function(fd_based: PGFileDescriptorBased): gint; cdecl; end; TGFileEnumeratorPrivate = record end; PPGFileEnumeratorClass = ^PGFileEnumeratorClass; PGFileEnumeratorClass = ^TGFileEnumeratorClass; TGFileEnumeratorClass = object parent_class: TGObjectClass; next_file: function(enumerator: PGFileEnumerator; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; close_fn: function(enumerator: PGFileEnumerator; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; next_files_async: procedure(enumerator: PGFileEnumerator; num_files: gint; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; next_files_finish: function(enumerator: PGFileEnumerator; result_: PGAsyncResult; error: PPGError): PGList; cdecl; close_async: procedure(enumerator: PGFileEnumerator; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; close_finish: function(enumerator: PGFileEnumerator; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; end; TGFileIOStreamPrivate = record end; PPGIOStreamClass = ^PGIOStreamClass; PGIOStreamClass = ^TGIOStreamClass; TGIOStreamClass = object parent_class: TGObjectClass; get_input_stream: function(stream: PGIOStream): PGInputStream; cdecl; get_output_stream: function(stream: PGIOStream): PGOutputStream; cdecl; close_fn: function(stream: PGIOStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; close_async: procedure(stream: PGIOStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; close_finish: function(stream: PGIOStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; _g_reserved8: procedure; cdecl; _g_reserved9: procedure; cdecl; _g_reserved10: procedure; cdecl; end; PPGFileIOStreamClass = ^PGFileIOStreamClass; PGFileIOStreamClass = ^TGFileIOStreamClass; TGFileIOStreamClass = object parent_class: TGIOStreamClass; tell: function(stream: PGFileIOStream): gint64; cdecl; can_seek: function(stream: PGFileIOStream): gboolean; cdecl; seek: function(stream: PGFileIOStream; offset: gint64; type_: TGSeekType; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; can_truncate: function(stream: PGFileIOStream): gboolean; cdecl; truncate_fn: function(stream: PGFileIOStream; size: gint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; query_info: function(stream: PGFileIOStream; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; query_info_async: procedure(stream: PGFileIOStream; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; query_info_finish: function(stream: PGFileIOStream; result_: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; get_etag: function(stream: PGFileIOStream): Pgchar; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGLoadableIcon = ^PGLoadableIcon; PGLoadableIcon = ^TGLoadableIcon; TGLoadableIcon = object end; PPGFileIcon = ^PGFileIcon; PGFileIcon = ^TGFileIcon; TGFileIcon = object(TGObject) end; PPGFileIconClass = ^PGFileIconClass; PGFileIconClass = ^TGFileIconClass; TGFileIconClass = object end; PPGFileIface = ^PGFileIface; PGFileIface = ^TGFileIface; TGFileIface = object g_iface: TGTypeInterface; dup: function(file_: PGFile): PGFile; cdecl; hash: function(file_: PGFile): guint; cdecl; equal: function(file1: PGFile; file2: PGFile): gboolean; cdecl; is_native: function(file_: PGFile): gboolean; cdecl; has_uri_scheme: function(file_: PGFile; uri_scheme: Pgchar): gboolean; cdecl; get_uri_scheme: function(file_: PGFile): Pgchar; cdecl; get_basename: function(file_: PGFile): Pgchar; cdecl; get_path: function(file_: PGFile): Pgchar; cdecl; get_uri: function(file_: PGFile): Pgchar; cdecl; get_parse_name: function(file_: PGFile): Pgchar; cdecl; get_parent: function(file_: PGFile): PGFile; cdecl; prefix_matches: function(prefix: PGFile; file_: PGFile): gboolean; cdecl; get_relative_path: function(parent: PGFile; descendant: PGFile): Pgchar; cdecl; resolve_relative_path: function(file_: PGFile; relative_path: Pgchar): PGFile; cdecl; get_child_for_display_name: function(file_: PGFile; display_name: Pgchar; error: PPGError): PGFile; cdecl; enumerate_children: function(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): PGFileEnumerator; cdecl; enumerate_children_async: procedure(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; enumerate_children_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileEnumerator; cdecl; query_info: function(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; query_info_async: procedure(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; query_info_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; query_filesystem_info: function(file_: PGFile; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; query_filesystem_info_async: procedure(file_: PGFile; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; query_filesystem_info_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; find_enclosing_mount: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGMount; cdecl; find_enclosing_mount_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; find_enclosing_mount_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGMount; cdecl; set_display_name: function(file_: PGFile; display_name: Pgchar; cancellable: PGCancellable; error: PPGError): PGFile; cdecl; set_display_name_async: procedure(file_: PGFile; display_name: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; set_display_name_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFile; cdecl; query_settable_attributes: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileAttributeInfoList; cdecl; _query_settable_attributes_async: procedure; cdecl; _query_settable_attributes_finish: procedure; cdecl; query_writable_namespaces: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileAttributeInfoList; cdecl; _query_writable_namespaces_async: procedure; cdecl; _query_writable_namespaces_finish: procedure; cdecl; set_attribute: function(file_: PGFile; attribute: Pgchar; type_: TGFileAttributeType; value_p: gpointer; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; set_attributes_from_info: function(file_: PGFile; info: PGFileInfo; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; set_attributes_async: procedure(file_: PGFile; info: PGFileInfo; flags: TGFileQueryInfoFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; set_attributes_finish: function(file_: PGFile; result_: PGAsyncResult; info: PPGFileInfo; error: PPGError): gboolean; cdecl; read_fn: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileInputStream; cdecl; read_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; read_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileInputStream; cdecl; append_to: function(file_: PGFile; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileOutputStream; cdecl; append_to_async: procedure(file_: PGFile; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; append_to_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileOutputStream; cdecl; create: function(file_: PGFile; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileOutputStream; cdecl; create_async: procedure(file_: PGFile; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; create_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileOutputStream; cdecl; replace: function(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileOutputStream; cdecl; replace_async: procedure(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; replace_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileOutputStream; cdecl; delete_file: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; delete_file_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; delete_file_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; trash: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; _trash_async: procedure; cdecl; _trash_finish: procedure; cdecl; make_directory: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; _make_directory_async: procedure; cdecl; _make_directory_finish: procedure; cdecl; make_symbolic_link: function(file_: PGFile; symlink_value: Pgchar; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; _make_symbolic_link_async: procedure; cdecl; _make_symbolic_link_finish: procedure; cdecl; copy: function(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; error: PPGError): gboolean; cdecl; copy_async: procedure(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; io_priority: gint; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; copy_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): gboolean; cdecl; move: function(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; error: PPGError): gboolean; cdecl; _move_async: procedure; cdecl; _move_finish: procedure; cdecl; mount_mountable: procedure(file_: PGFile; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; mount_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): PGFile; cdecl; unmount_mountable: procedure(file_: PGFile; flags: TGMountUnmountFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; unmount_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; eject_mountable: procedure(file_: PGFile; flags: TGMountUnmountFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; mount_enclosing_volume: procedure(location: PGFile; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; mount_enclosing_volume_finish: function(location: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; monitor_dir: function(file_: PGFile; flags: TGFileMonitorFlags; cancellable: PGCancellable; error: PPGError): PGFileMonitor; cdecl; monitor_file: function(file_: PGFile; flags: TGFileMonitorFlags; cancellable: PGCancellable; error: PPGError): PGFileMonitor; cdecl; open_readwrite: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileIOStream; cdecl; open_readwrite_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; open_readwrite_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileIOStream; cdecl; create_readwrite: function(file_: PGFile; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileIOStream; cdecl; create_readwrite_async: procedure(file_: PGFile; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; create_readwrite_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileIOStream; cdecl; replace_readwrite: function(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileIOStream; cdecl; replace_readwrite_async: procedure(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; replace_readwrite_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileIOStream; cdecl; start_mountable: procedure(file_: PGFile; flags: TGDriveStartFlags; start_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; start_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; stop_mountable: procedure(file_: PGFile; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; stop_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; supports_thread_contexts: gboolean; unmount_mountable_with_operation: procedure(file_: PGFile; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; unmount_mountable_with_operation_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; eject_mountable_with_operation: procedure(file_: PGFile; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_mountable_with_operation_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; poll_mountable: procedure(file_: PGFile; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; poll_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; end; PPGFileInfoClass = ^PGFileInfoClass; PGFileInfoClass = ^TGFileInfoClass; TGFileInfoClass = object end; TGFileInputStreamPrivate = record end; PPGFileInputStreamClass = ^PGFileInputStreamClass; PGFileInputStreamClass = ^TGFileInputStreamClass; TGFileInputStreamClass = object parent_class: TGInputStreamClass; tell: function(stream: PGFileInputStream): gint64; cdecl; can_seek: function(stream: PGFileInputStream): gboolean; cdecl; seek: function(stream: PGFileInputStream; offset: gint64; type_: TGSeekType; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; query_info: function(stream: PGFileInputStream; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; query_info_async: procedure(stream: PGFileInputStream; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; query_info_finish: function(stream: PGFileInputStream; result_: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; TGFileMonitorPrivate = record end; PPGFileMonitorClass = ^PGFileMonitorClass; PGFileMonitorClass = ^TGFileMonitorClass; TGFileMonitorClass = object parent_class: TGObjectClass; changed: procedure(monitor: PGFileMonitor; file_: PGFile; other_file: PGFile; event_type: TGFileMonitorEvent); cdecl; cancel: function(monitor: PGFileMonitor): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; TGFileOutputStreamPrivate = record end; PPGFileOutputStreamClass = ^PGFileOutputStreamClass; PGFileOutputStreamClass = ^TGFileOutputStreamClass; TGFileOutputStreamClass = object parent_class: TGOutputStreamClass; tell: function(stream: PGFileOutputStream): gint64; cdecl; can_seek: function(stream: PGFileOutputStream): gboolean; cdecl; seek: function(stream: PGFileOutputStream; offset: gint64; type_: TGSeekType; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; can_truncate: function(stream: PGFileOutputStream): gboolean; cdecl; truncate_fn: function(stream: PGFileOutputStream; size: gint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; query_info: function(stream: PGFileOutputStream; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; query_info_async: procedure(stream: PGFileOutputStream; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; query_info_finish: function(stream: PGFileOutputStream; result_: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; get_etag: function(stream: PGFileOutputStream): Pgchar; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGFilenameCompleter = ^PGFilenameCompleter; PGFilenameCompleter = ^TGFilenameCompleter; TGFilenameCompleter = object(TGObject) end; PPGFilenameCompleterClass = ^PGFilenameCompleterClass; PGFilenameCompleterClass = ^TGFilenameCompleterClass; TGFilenameCompleterClass = object parent_class: TGObjectClass; got_completion_data: procedure(filename_completer: PGFilenameCompleter); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; end; PPGFilesystemPreviewType = ^PGFilesystemPreviewType; PGFilesystemPreviewType = ^TGFilesystemPreviewType; PPGIOErrorEnum = ^PGIOErrorEnum; PGIOErrorEnum = ^TGIOErrorEnum; PPGIOExtension = ^PGIOExtension; PGIOExtension = ^TGIOExtension; TGIOExtension = object end; PPGIOExtensionPoint = ^PGIOExtensionPoint; PGIOExtensionPoint = ^TGIOExtensionPoint; TGIOExtensionPoint = object end; PPGIOModule = ^PGIOModule; PGIOModule = ^TGIOModule; TGIOModule = object(TGTypeModule) end; PPGIOModuleClass = ^PGIOModuleClass; PGIOModuleClass = ^TGIOModuleClass; TGIOModuleClass = object end; PPGIOModuleScope = ^PGIOModuleScope; PGIOModuleScope = ^TGIOModuleScope; PPGIOModuleScopeFlags = ^PGIOModuleScopeFlags; PGIOModuleScopeFlags = ^TGIOModuleScopeFlags; TGIOModuleScope = object end; PPGIOSchedulerJob = ^PGIOSchedulerJob; PGIOSchedulerJob = ^TGIOSchedulerJob; TGIOSchedulerJob = object end; TGIOSchedulerJobFunc = function(job: PGIOSchedulerJob; cancellable: PGCancellable; user_data: gpointer): gboolean; cdecl; TGIOStreamPrivate = record end; PPGIOStreamAdapter = ^PGIOStreamAdapter; PGIOStreamAdapter = ^TGIOStreamAdapter; TGIOStreamAdapter = record end; PPGIconIface = ^PGIconIface; PGIconIface = ^TGIconIface; TGIconIface = object g_iface: TGTypeInterface; hash: function(icon: PGIcon): guint; cdecl; equal: function(icon1: PGIcon; icon2: PGIcon): gboolean; cdecl; to_tokens: function(icon: PGIcon; tokens: Pgpointer; out_version: Pgint): gboolean; cdecl; from_tokens: function(tokens: PPgchar; num_tokens: gint; version: gint; error: PPGError): PGIcon; cdecl; end; PPGInetAddress = ^PGInetAddress; PGInetAddress = ^TGInetAddress; PPGSocketFamily = ^PGSocketFamily; PGSocketFamily = ^TGSocketFamily; PPGInetAddressPrivate = ^PGInetAddressPrivate; PGInetAddressPrivate = ^TGInetAddressPrivate; TGInetAddress = object(TGObject) priv: PGInetAddressPrivate; end; TGInetAddressPrivate = record end; PPGInetAddressClass = ^PGInetAddressClass; PGInetAddressClass = ^TGInetAddressClass; TGInetAddressClass = object parent_class: TGObjectClass; to_string: function(address: PGInetAddress): Pgchar; cdecl; to_bytes: function(address: PGInetAddress): Pguint8; cdecl; end; PPGInetAddressMask = ^PGInetAddressMask; PGInetAddressMask = ^TGInetAddressMask; PPGInetAddressMaskPrivate = ^PGInetAddressMaskPrivate; PGInetAddressMaskPrivate = ^TGInetAddressMaskPrivate; TGInetAddressMask = object(TGObject) priv: PGInetAddressMaskPrivate; end; TGInetAddressMaskPrivate = record end; PPGInetAddressMaskClass = ^PGInetAddressMaskClass; PGInetAddressMaskClass = ^TGInetAddressMaskClass; TGInetAddressMaskClass = object parent_class: TGObjectClass; end; PPGSocketConnectable = ^PGSocketConnectable; PGSocketConnectable = ^TGSocketConnectable; PPGSocketAddressEnumerator = ^PGSocketAddressEnumerator; PGSocketAddressEnumerator = ^TGSocketAddressEnumerator; TGSocketConnectable = object end; PPGSocketAddress = ^PGSocketAddress; PGSocketAddress = ^TGSocketAddress; TGSocketAddress = object(TGObject) end; PPGInetSocketAddress = ^PGInetSocketAddress; PGInetSocketAddress = ^TGInetSocketAddress; PPGInetSocketAddressPrivate = ^PGInetSocketAddressPrivate; PGInetSocketAddressPrivate = ^TGInetSocketAddressPrivate; TGInetSocketAddress = object(TGSocketAddress) priv: PGInetSocketAddressPrivate; end; TGInetSocketAddressPrivate = record end; PPGSocketAddressClass = ^PGSocketAddressClass; PGSocketAddressClass = ^TGSocketAddressClass; TGSocketAddressClass = object parent_class: TGObjectClass; get_family: function(address: PGSocketAddress): TGSocketFamily; cdecl; get_native_size: function(address: PGSocketAddress): gssize; cdecl; to_native: function(address: PGSocketAddress; dest: gpointer; destlen: gsize; error: PPGError): gboolean; cdecl; end; PPGInetSocketAddressClass = ^PGInetSocketAddressClass; PGInetSocketAddressClass = ^TGInetSocketAddressClass; TGInetSocketAddressClass = object parent_class: TGSocketAddressClass; end; PPGInitableIface = ^PGInitableIface; PGInitableIface = ^TGInitableIface; TGInitableIface = object g_iface: TGTypeInterface; init: function(initable: PGInitable; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; end; TGInputStreamPrivate = record end; PPGInputVector = ^PGInputVector; PGInputVector = ^TGInputVector; TGInputVector = record buffer: gpointer; size: gsize; end; PPGLoadableIconIface = ^PGLoadableIconIface; PGLoadableIconIface = ^TGLoadableIconIface; TGLoadableIconIface = object g_iface: TGTypeInterface; load: function(icon: PGLoadableIcon; size: gint; type_: PPgchar; cancellable: PGCancellable; error: PPGError): PGInputStream; cdecl; load_async: procedure(icon: PGLoadableIcon; size: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; load_finish: function(icon: PGLoadableIcon; res: PGAsyncResult; type_: PPgchar; error: PPGError): PGInputStream; cdecl; end; PPGMemoryInputStream = ^PGMemoryInputStream; PGMemoryInputStream = ^TGMemoryInputStream; PPGMemoryInputStreamPrivate = ^PGMemoryInputStreamPrivate; PGMemoryInputStreamPrivate = ^TGMemoryInputStreamPrivate; TGMemoryInputStream = object(TGInputStream) priv1: PGMemoryInputStreamPrivate; end; TGMemoryInputStreamPrivate = record end; PPGMemoryInputStreamClass = ^PGMemoryInputStreamClass; PGMemoryInputStreamClass = ^TGMemoryInputStreamClass; TGMemoryInputStreamClass = object parent_class: TGInputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; TGReallocFunc = function(data: gpointer; size: gsize): gpointer; cdecl; PPGMemoryOutputStream = ^PGMemoryOutputStream; PGMemoryOutputStream = ^TGMemoryOutputStream; PPGReallocFunc = ^PGReallocFunc; PGReallocFunc = ^TGReallocFunc; PPGMemoryOutputStreamPrivate = ^PGMemoryOutputStreamPrivate; PGMemoryOutputStreamPrivate = ^TGMemoryOutputStreamPrivate; TGMemoryOutputStream = object(TGOutputStream) priv1: PGMemoryOutputStreamPrivate; end; TGMemoryOutputStreamPrivate = record end; PPGMemoryOutputStreamClass = ^PGMemoryOutputStreamClass; PGMemoryOutputStreamClass = ^TGMemoryOutputStreamClass; TGMemoryOutputStreamClass = object parent_class: TGOutputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGMenu = ^PGMenu; PGMenu = ^TGMenu; PPGMenuItem = ^PGMenuItem; PGMenuItem = ^TGMenuItem; TGMenu = object(TGMenuModel) end; TGMenuItem = object(TGObject) end; PPGMenuAttributeIterPrivate = ^PGMenuAttributeIterPrivate; PGMenuAttributeIterPrivate = ^TGMenuAttributeIterPrivate; TGMenuAttributeIter = object(TGObject) priv: PGMenuAttributeIterPrivate; end; TGMenuAttributeIterPrivate = record end; PPGMenuAttributeIterClass = ^PGMenuAttributeIterClass; PGMenuAttributeIterClass = ^TGMenuAttributeIterClass; TGMenuAttributeIterClass = object parent_class: TGObjectClass; get_next: function(iter: PGMenuAttributeIter; out_name: PPgchar; value: PPGVariant): gboolean; cdecl; end; PPGMenuLinkIterPrivate = ^PGMenuLinkIterPrivate; PGMenuLinkIterPrivate = ^TGMenuLinkIterPrivate; TGMenuLinkIter = object(TGObject) priv: PGMenuLinkIterPrivate; end; TGMenuLinkIterPrivate = record end; PPGMenuLinkIterClass = ^PGMenuLinkIterClass; PGMenuLinkIterClass = ^TGMenuLinkIterClass; TGMenuLinkIterClass = object parent_class: TGObjectClass; get_next: function(iter: PGMenuLinkIter; out_link: PPgchar; value: PPGMenuModel): gboolean; cdecl; end; TGMenuModelPrivate = record end; PPGMenuModelClass = ^PGMenuModelClass; PGMenuModelClass = ^TGMenuModelClass; TGMenuModelClass = object parent_class: TGObjectClass; is_mutable: function(model: PGMenuModel): gboolean; cdecl; get_n_items: function(model: PGMenuModel): gint; cdecl; get_item_attributes: procedure(model: PGMenuModel; item_index: gint; attributes: PPGHashTable); cdecl; iterate_item_attributes: function(model: PGMenuModel; item_index: gint): PGMenuAttributeIter; cdecl; get_item_attribute_value: function(model: PGMenuModel; item_index: gint; attribute: Pgchar; expected_type: PGVariantType): PGVariant; cdecl; get_item_links: procedure(model: PGMenuModel; item_index: gint; links: PPGHashTable); cdecl; iterate_item_links: function(model: PGMenuModel; item_index: gint): PGMenuLinkIter; cdecl; get_item_link: function(model: PGMenuModel; item_index: gint; link: Pgchar): PGMenuModel; cdecl; end; TGVolume = object changed: procedure; cdecl; removed: procedure; cdecl; end; PPGMountIface = ^PGMountIface; PGMountIface = ^TGMountIface; TGMountIface = object g_iface: TGTypeInterface; changed: procedure(mount: PGMount); cdecl; unmounted: procedure(mount: PGMount); cdecl; get_root: function(mount: PGMount): PGFile; cdecl; get_name: function(mount: PGMount): Pgchar; cdecl; get_icon: function(mount: PGMount): PGIcon; cdecl; get_uuid: function(mount: PGMount): Pgchar; cdecl; get_volume: function(mount: PGMount): PGVolume; cdecl; get_drive: function(mount: PGMount): PGDrive; cdecl; can_unmount: function(mount: PGMount): gboolean; cdecl; can_eject: function(mount: PGMount): gboolean; cdecl; unmount: procedure(mount: PGMount; flags: TGMountUnmountFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; unmount_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; eject: procedure(mount: PGMount; flags: TGMountUnmountFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; remount: procedure(mount: PGMount; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; remount_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; guess_content_type: procedure(mount: PGMount; force_rescan: gboolean; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; guess_content_type_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): PPgchar; cdecl; guess_content_type_sync: function(mount: PGMount; force_rescan: gboolean; cancellable: PGCancellable; error: PPGError): PPgchar; cdecl; pre_unmount: procedure(mount: PGMount); cdecl; unmount_with_operation: procedure(mount: PGMount; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; unmount_with_operation_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; eject_with_operation: procedure(mount: PGMount; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_with_operation_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; get_default_location: function(mount: PGMount): PGFile; cdecl; get_sort_key: function(mount: PGMount): Pgchar; cdecl; get_symbolic_icon: function(mount: PGMount): PGIcon; cdecl; end; TGMountOperationPrivate = record end; PPGMountOperationClass = ^PGMountOperationClass; PGMountOperationClass = ^TGMountOperationClass; TGMountOperationClass = object parent_class: TGObjectClass; ask_password: procedure(op: PGMountOperation; message: Pgchar; default_user: Pgchar; default_domain: Pgchar; flags: TGAskPasswordFlags); cdecl; ask_question: procedure(op: PGMountOperation; message: Pgchar; choices: Pgchar); cdecl; reply: procedure(op: PGMountOperation; result_: TGMountOperationResult); cdecl; aborted: procedure(op: PGMountOperation); cdecl; show_processes: procedure(op: PGMountOperation; message: Pgchar; processes: Pgpointer; choices: Pgchar); cdecl; show_unmount_progress: procedure(op: PGMountOperation; message: Pgchar; time_left: gint64; bytes_left: gint64); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; _g_reserved8: procedure; cdecl; _g_reserved9: procedure; cdecl; end; PPGVolumeMonitor = ^PGVolumeMonitor; PGVolumeMonitor = ^TGVolumeMonitor; TGVolumeMonitor = object(TGObject) priv: gpointer; end; PPGNativeVolumeMonitor = ^PGNativeVolumeMonitor; PGNativeVolumeMonitor = ^TGNativeVolumeMonitor; TGNativeVolumeMonitor = object(TGVolumeMonitor) end; PPGVolumeMonitorClass = ^PGVolumeMonitorClass; PGVolumeMonitorClass = ^TGVolumeMonitorClass; TGVolumeMonitorClass = object parent_class: TGObjectClass; volume_added: procedure(volume_monitor: PGVolumeMonitor; volume: PGVolume); cdecl; volume_removed: procedure(volume_monitor: PGVolumeMonitor; volume: PGVolume); cdecl; volume_changed: procedure(volume_monitor: PGVolumeMonitor; volume: PGVolume); cdecl; mount_added: procedure(volume_monitor: PGVolumeMonitor; mount: PGMount); cdecl; mount_removed: procedure(volume_monitor: PGVolumeMonitor; mount: PGMount); cdecl; mount_pre_unmount: procedure(volume_monitor: PGVolumeMonitor; mount: PGMount); cdecl; mount_changed: procedure(volume_monitor: PGVolumeMonitor; mount: PGMount); cdecl; drive_connected: procedure(volume_monitor: PGVolumeMonitor; drive: PGDrive); cdecl; drive_disconnected: procedure(volume_monitor: PGVolumeMonitor; drive: PGDrive); cdecl; drive_changed: procedure(volume_monitor: PGVolumeMonitor; drive: PGDrive); cdecl; is_supported: function: gboolean; cdecl; get_connected_drives: function(volume_monitor: PGVolumeMonitor): PGList; cdecl; get_volumes: function(volume_monitor: PGVolumeMonitor): PGList; cdecl; get_mounts: function(volume_monitor: PGVolumeMonitor): PGList; cdecl; get_volume_for_uuid: function(volume_monitor: PGVolumeMonitor; uuid: Pgchar): PGVolume; cdecl; get_mount_for_uuid: function(volume_monitor: PGVolumeMonitor; uuid: Pgchar): PGMount; cdecl; adopt_orphan_mount: function(mount: PGMount; volume_monitor: PGVolumeMonitor): PGVolume; cdecl; drive_eject_button: procedure(volume_monitor: PGVolumeMonitor; drive: PGDrive); cdecl; drive_stop_button: procedure(volume_monitor: PGVolumeMonitor; drive: PGDrive); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; end; PPGNativeVolumeMonitorClass = ^PGNativeVolumeMonitorClass; PGNativeVolumeMonitorClass = ^TGNativeVolumeMonitorClass; TGNativeVolumeMonitorClass = object parent_class: TGVolumeMonitorClass; get_mount_for_mount_path: function(mount_path: Pgchar; cancellable: PGCancellable): PGMount; cdecl; end; PPGNetworkAddress = ^PGNetworkAddress; PGNetworkAddress = ^TGNetworkAddress; PPGNetworkAddressPrivate = ^PGNetworkAddressPrivate; PGNetworkAddressPrivate = ^TGNetworkAddressPrivate; TGNetworkAddress = object(TGObject) priv: PGNetworkAddressPrivate; end; TGNetworkAddressPrivate = record end; PPGNetworkAddressClass = ^PGNetworkAddressClass; PGNetworkAddressClass = ^TGNetworkAddressClass; TGNetworkAddressClass = object parent_class: TGObjectClass; end; PPGNetworkMonitor = ^PGNetworkMonitor; PGNetworkMonitor = ^TGNetworkMonitor; TGNetworkMonitor = object network_changed: procedure(available: gboolean); cdecl; end; PPGNetworkMonitorInterface = ^PGNetworkMonitorInterface; PGNetworkMonitorInterface = ^TGNetworkMonitorInterface; TGNetworkMonitorInterface = object g_iface: TGTypeInterface; network_changed: procedure(monitor: PGNetworkMonitor; available: gboolean); cdecl; can_reach: function(monitor: PGNetworkMonitor; connectable: PGSocketConnectable; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; can_reach_async: procedure(monitor: PGNetworkMonitor; connectable: PGSocketConnectable; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; can_reach_finish: function(monitor: PGNetworkMonitor; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; end; PPGNetworkService = ^PGNetworkService; PGNetworkService = ^TGNetworkService; PPGNetworkServicePrivate = ^PGNetworkServicePrivate; PGNetworkServicePrivate = ^TGNetworkServicePrivate; TGNetworkService = object(TGObject) priv: PGNetworkServicePrivate; end; TGNetworkServicePrivate = record end; PPGNetworkServiceClass = ^PGNetworkServiceClass; PGNetworkServiceClass = ^TGNetworkServiceClass; TGNetworkServiceClass = object parent_class: TGObjectClass; end; TGOutputStreamPrivate = record end; PPGOutputVector = ^PGOutputVector; PGOutputVector = ^TGOutputVector; TGOutputVector = record buffer: Pgpointer; size: gsize; end; PPGPermission = ^PGPermission; PGPermission = ^TGPermission; PPGPermissionPrivate = ^PGPermissionPrivate; PGPermissionPrivate = ^TGPermissionPrivate; TGPermission = object(TGObject) priv: PGPermissionPrivate; end; TGPermissionPrivate = record end; PPGPermissionClass = ^PGPermissionClass; PGPermissionClass = ^TGPermissionClass; TGPermissionClass = object parent_class: TGObjectClass; acquire: function(permission: PGPermission; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; acquire_async: procedure(permission: PGPermission; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; acquire_finish: function(permission: PGPermission; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; release: function(permission: PGPermission; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; release_async: procedure(permission: PGPermission; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; release_finish: function(permission: PGPermission; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; reserved: array [0..15] of gpointer; end; PPGPollableInputStreamInterface = ^PGPollableInputStreamInterface; PGPollableInputStreamInterface = ^TGPollableInputStreamInterface; TGPollableInputStreamInterface = object g_iface: TGTypeInterface; can_poll: function(stream: PGPollableInputStream): gboolean; cdecl; is_readable: function(stream: PGPollableInputStream): gboolean; cdecl; create_source: function(stream: PGPollableInputStream; cancellable: PGCancellable): PGSource; cdecl; read_nonblocking: function(stream: PGPollableInputStream; buffer: Pgpointer; count: gsize; error: PPGError): gssize; cdecl; end; PPGPollableOutputStreamInterface = ^PGPollableOutputStreamInterface; PGPollableOutputStreamInterface = ^TGPollableOutputStreamInterface; TGPollableOutputStreamInterface = object g_iface: TGTypeInterface; can_poll: function(stream: PGPollableOutputStream): gboolean; cdecl; is_writable: function(stream: PGPollableOutputStream): gboolean; cdecl; create_source: function(stream: PGPollableOutputStream; cancellable: PGCancellable): PGSource; cdecl; write_nonblocking: function(stream: PGPollableOutputStream; buffer: Pguint8; count: gsize; error: PPGError): gssize; cdecl; end; TGPollableSourceFunc = function(pollable_stream: PGObject; user_data: gpointer): gboolean; cdecl; PPGProxy = ^PGProxy; PGProxy = ^TGProxy; PPGProxyAddress = ^PGProxyAddress; PGProxyAddress = ^TGProxyAddress; TGProxy = object end; PPGProxyAddressPrivate = ^PGProxyAddressPrivate; PGProxyAddressPrivate = ^TGProxyAddressPrivate; TGProxyAddress = object(TGInetSocketAddress) priv1: PGProxyAddressPrivate; end; TGProxyAddressPrivate = record end; PPGProxyAddressClass = ^PGProxyAddressClass; PGProxyAddressClass = ^TGProxyAddressClass; TGProxyAddressClass = object parent_class: TGInetSocketAddressClass; end; PPGProxyResolver = ^PGProxyResolver; PGProxyResolver = ^TGProxyResolver; TGProxyResolver = object end; TGSocketAddressEnumerator = object(TGObject) end; PPGProxyAddressEnumeratorPrivate = ^PGProxyAddressEnumeratorPrivate; PGProxyAddressEnumeratorPrivate = ^TGProxyAddressEnumeratorPrivate; TGProxyAddressEnumeratorPrivate = record end; PPGProxyAddressEnumerator = ^PGProxyAddressEnumerator; PGProxyAddressEnumerator = ^TGProxyAddressEnumerator; TGProxyAddressEnumerator = object(TGSocketAddressEnumerator) priv: PGProxyAddressEnumeratorPrivate; end; PPGSocketAddressEnumeratorClass = ^PGSocketAddressEnumeratorClass; PGSocketAddressEnumeratorClass = ^TGSocketAddressEnumeratorClass; TGSocketAddressEnumeratorClass = object parent_class: TGObjectClass; next: function(enumerator: PGSocketAddressEnumerator; cancellable: PGCancellable; error: PPGError): PGSocketAddress; cdecl; next_async: procedure(enumerator: PGSocketAddressEnumerator; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; next_finish: function(enumerator: PGSocketAddressEnumerator; result_: PGAsyncResult; error: PPGError): PGSocketAddress; cdecl; end; PPGProxyAddressEnumeratorClass = ^PGProxyAddressEnumeratorClass; PGProxyAddressEnumeratorClass = ^TGProxyAddressEnumeratorClass; TGProxyAddressEnumeratorClass = object parent_class: TGSocketAddressEnumeratorClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; end; PPGProxyInterface = ^PGProxyInterface; PGProxyInterface = ^TGProxyInterface; TGProxyInterface = object g_iface: TGTypeInterface; connect: function(proxy: PGProxy; connection: PGIOStream; proxy_address: PGProxyAddress; cancellable: PGCancellable; error: PPGError): PGIOStream; cdecl; connect_async: procedure(proxy: PGProxy; connection: PGIOStream; proxy_address: PGProxyAddress; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; connect_finish: function(proxy: PGProxy; result_: PGAsyncResult; error: PPGError): PGIOStream; cdecl; supports_hostname: function(proxy: PGProxy): gboolean; cdecl; end; PPGProxyResolverInterface = ^PGProxyResolverInterface; PGProxyResolverInterface = ^TGProxyResolverInterface; TGProxyResolverInterface = object g_iface: TGTypeInterface; is_supported: function(resolver: PGProxyResolver): gboolean; cdecl; lookup: function(resolver: PGProxyResolver; uri: Pgchar; cancellable: PGCancellable; error: PPGError): PPgchar; cdecl; lookup_async: procedure(resolver: PGProxyResolver; uri: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_finish: function(resolver: PGProxyResolver; result_: PGAsyncResult; error: PPGError): PPgchar; cdecl; end; PPGRemoteActionGroupInterface = ^PGRemoteActionGroupInterface; PGRemoteActionGroupInterface = ^TGRemoteActionGroupInterface; TGRemoteActionGroupInterface = object g_iface: TGTypeInterface; activate_action_full: procedure(remote: PGRemoteActionGroup; action_name: Pgchar; parameter: PGVariant; platform_data: PGVariant); cdecl; change_action_state_full: procedure(remote: PGRemoteActionGroup; action_name: Pgchar; value: PGVariant; platform_data: PGVariant); cdecl; end; PPGResolver = ^PGResolver; PGResolver = ^TGResolver; PPGResolverRecordType = ^PGResolverRecordType; PGResolverRecordType = ^TGResolverRecordType; PPGResolverPrivate = ^PGResolverPrivate; PGResolverPrivate = ^TGResolverPrivate; TGResolver = object(TGObject) priv: PGResolverPrivate; end; TGResolverPrivate = record end; PPGResolverClass = ^PGResolverClass; PGResolverClass = ^TGResolverClass; TGResolverClass = object parent_class: TGObjectClass; reload: procedure(resolver: PGResolver); cdecl; lookup_by_name: function(resolver: PGResolver; hostname: Pgchar; cancellable: PGCancellable; error: PPGError): PGList; cdecl; lookup_by_name_async: procedure(resolver: PGResolver; hostname: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_by_name_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): PGList; cdecl; lookup_by_address: function(resolver: PGResolver; address: PGInetAddress; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; lookup_by_address_async: procedure(resolver: PGResolver; address: PGInetAddress; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_by_address_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): Pgchar; cdecl; lookup_service: function(resolver: PGResolver; rrname: Pgchar; cancellable: PGCancellable; error: PPGError): PGList; cdecl; lookup_service_async: procedure(resolver: PGResolver; rrname: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_service_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): PGList; cdecl; lookup_records: function(resolver: PGResolver; rrname: Pgchar; record_type: TGResolverRecordType; cancellable: PGCancellable; error: PPGError): PGList; cdecl; lookup_records_async: procedure(resolver: PGResolver; rrname: Pgchar; record_type: TGResolverRecordType; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_records_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): PGList; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; end; PPGResolverError = ^PGResolverError; PGResolverError = ^TGResolverError; PPGResource = ^PGResource; PGResource = ^TGResource; PPGResourceLookupFlags = ^PGResourceLookupFlags; PGResourceLookupFlags = ^TGResourceLookupFlags; TGResource = object end; PPGResourceError = ^PGResourceError; PGResourceError = ^TGResourceError; PPGResourceFlags = ^PGResourceFlags; PGResourceFlags = ^TGResourceFlags; PPGSeekableIface = ^PGSeekableIface; PGSeekableIface = ^TGSeekableIface; TGSeekableIface = object g_iface: TGTypeInterface; tell: function(seekable: PGSeekable): gint64; cdecl; can_seek: function(seekable: PGSeekable): gboolean; cdecl; seek: function(seekable: PGSeekable; offset: gint64; type_: TGSeekType; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; can_truncate: function(seekable: PGSeekable): gboolean; cdecl; truncate_fn: function(seekable: PGSeekable; offset: gint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; end; PPGSettings = ^PGSettings; PGSettings = ^TGSettings; PPGSettingsSchema = ^PGSettingsSchema; PGSettingsSchema = ^TGSettingsSchema; PPGSettingsBackend = ^PGSettingsBackend; PGSettingsBackend = ^TGSettingsBackend; PPGSettingsBindFlags = ^PGSettingsBindFlags; PGSettingsBindFlags = ^TGSettingsBindFlags; PPGSettingsBindGetMapping = ^PGSettingsBindGetMapping; PGSettingsBindGetMapping = ^TGSettingsBindGetMapping; TGSettingsBindGetMapping = function(value: PGValue; variant: PGVariant; user_data: gpointer): gboolean; cdecl; PPGSettingsBindSetMapping = ^PGSettingsBindSetMapping; PGSettingsBindSetMapping = ^TGSettingsBindSetMapping; TGSettingsBindSetMapping = function(value: PGValue; expected_type: PGVariantType; user_data: gpointer): PGVariant; cdecl; PPGSettingsGetMapping = ^PGSettingsGetMapping; PGSettingsGetMapping = ^TGSettingsGetMapping; TGSettingsGetMapping = function(value: PGVariant; result_: Pgpointer; user_data: gpointer): gboolean; cdecl; PPGSettingsPrivate = ^PGSettingsPrivate; PGSettingsPrivate = ^TGSettingsPrivate; TGSettings = object(TGObject) priv: PGSettingsPrivate; end; TGSettingsSchema = object end; TGSettingsBackend = record end; TGSettingsPrivate = record end; PPGSettingsClass = ^PGSettingsClass; PGSettingsClass = ^TGSettingsClass; TGSettingsClass = object parent_class: TGObjectClass; writable_changed: procedure(settings: PGSettings; key: Pgchar); cdecl; changed: procedure(settings: PGSettings; key: Pgchar); cdecl; writable_change_event: function(settings: PGSettings; key: TGQuark): gboolean; cdecl; change_event: function(settings: PGSettings; keys: PGQuark; n_keys: gint): gboolean; cdecl; padding: array [0..19] of gpointer; end; PPGSettingsSchemaSource = ^PGSettingsSchemaSource; PGSettingsSchemaSource = ^TGSettingsSchemaSource; TGSettingsSchemaSource = object end; PPGSimpleActionGroup = ^PGSimpleActionGroup; PGSimpleActionGroup = ^TGSimpleActionGroup; PPGSimpleActionGroupPrivate = ^PGSimpleActionGroupPrivate; PGSimpleActionGroupPrivate = ^TGSimpleActionGroupPrivate; TGSimpleActionGroup = object(TGObject) priv: PGSimpleActionGroupPrivate; end; TGSimpleActionGroupPrivate = record end; PPGSimpleActionGroupClass = ^PGSimpleActionGroupClass; PGSimpleActionGroupClass = ^TGSimpleActionGroupClass; TGSimpleActionGroupClass = object parent_class: TGObjectClass; padding: array [0..11] of gpointer; end; PPGSimpleAsyncResult = ^PGSimpleAsyncResult; PGSimpleAsyncResult = ^TGSimpleAsyncResult; PPGSimpleAsyncThreadFunc = ^PGSimpleAsyncThreadFunc; PGSimpleAsyncThreadFunc = ^TGSimpleAsyncThreadFunc; TGSimpleAsyncThreadFunc = procedure(res: PGSimpleAsyncResult; object_: PGObject; cancellable: PGCancellable); cdecl; TGSimpleAsyncResult = object(TGObject) end; PPGSimpleAsyncResultClass = ^PGSimpleAsyncResultClass; PGSimpleAsyncResultClass = ^TGSimpleAsyncResultClass; TGSimpleAsyncResultClass = object end; PPGSimplePermission = ^PGSimplePermission; PGSimplePermission = ^TGSimplePermission; TGSimplePermission = object(TGPermission) end; PPGSimpleProxyResolver = ^PGSimpleProxyResolver; PGSimpleProxyResolver = ^TGSimpleProxyResolver; PPGSimpleProxyResolverPrivate = ^PGSimpleProxyResolverPrivate; PGSimpleProxyResolverPrivate = ^TGSimpleProxyResolverPrivate; TGSimpleProxyResolver = object(TGObject) priv: PGSimpleProxyResolverPrivate; end; TGSimpleProxyResolverPrivate = record end; PPGSimpleProxyResolverClass = ^PGSimpleProxyResolverClass; PGSimpleProxyResolverClass = ^TGSimpleProxyResolverClass; TGSimpleProxyResolverClass = object parent_class: TGObjectClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGSocket = ^PGSocket; PGSocket = ^TGSocket; PPGSocketType = ^PGSocketType; PGSocketType = ^TGSocketType; PPGSocketProtocol = ^PGSocketProtocol; PGSocketProtocol = ^TGSocketProtocol; PPGSocketConnection = ^PGSocketConnection; PGSocketConnection = ^TGSocketConnection; PPPGSocketControlMessage = ^PPGSocketControlMessage; PPGSocketControlMessage = ^PGSocketControlMessage; PGSocketControlMessage = ^TGSocketControlMessage; PPGSocketPrivate = ^PGSocketPrivate; PGSocketPrivate = ^TGSocketPrivate; TGSocket = object(TGObject) priv: PGSocketPrivate; end; PPGSocketConnectionPrivate = ^PGSocketConnectionPrivate; PGSocketConnectionPrivate = ^TGSocketConnectionPrivate; TGSocketConnection = object(TGIOStream) priv1: PGSocketConnectionPrivate; end; PPGSocketControlMessagePrivate = ^PGSocketControlMessagePrivate; PGSocketControlMessagePrivate = ^TGSocketControlMessagePrivate; TGSocketControlMessage = object(TGObject) priv: PGSocketControlMessagePrivate; end; TGSocketPrivate = record end; PPGSocketClass = ^PGSocketClass; PGSocketClass = ^TGSocketClass; TGSocketClass = object parent_class: TGObjectClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; _g_reserved8: procedure; cdecl; _g_reserved9: procedure; cdecl; _g_reserved10: procedure; cdecl; end; PPGSocketClient = ^PGSocketClient; PGSocketClient = ^TGSocketClient; PPGTlsCertificateFlags = ^PGTlsCertificateFlags; PGTlsCertificateFlags = ^TGTlsCertificateFlags; PPGSocketClientPrivate = ^PGSocketClientPrivate; PGSocketClientPrivate = ^TGSocketClientPrivate; TGSocketClient = object(TGObject) priv: PGSocketClientPrivate; end; PPGSocketClientEvent = ^PGSocketClientEvent; PGSocketClientEvent = ^TGSocketClientEvent; TGSocketClientPrivate = record end; PPGSocketClientClass = ^PGSocketClientClass; PGSocketClientClass = ^TGSocketClientClass; TGSocketClientClass = object parent_class: TGObjectClass; event: procedure(client: PGSocketClient; event: TGSocketClientEvent; connectable: PGSocketConnectable; connection: PGIOStream); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; end; PPGSocketConnectableIface = ^PGSocketConnectableIface; PGSocketConnectableIface = ^TGSocketConnectableIface; TGSocketConnectableIface = object g_iface: TGTypeInterface; enumerate: function(connectable: PGSocketConnectable): PGSocketAddressEnumerator; cdecl; proxy_enumerate: function(connectable: PGSocketConnectable): PGSocketAddressEnumerator; cdecl; end; TGSocketConnectionPrivate = record end; PPGSocketConnectionClass = ^PGSocketConnectionClass; PGSocketConnectionClass = ^TGSocketConnectionClass; TGSocketConnectionClass = object parent_class: TGIOStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; end; TGSocketControlMessagePrivate = record end; PPGSocketControlMessageClass = ^PGSocketControlMessageClass; PGSocketControlMessageClass = ^TGSocketControlMessageClass; TGSocketControlMessageClass = object parent_class: TGObjectClass; get_size: function(message: PGSocketControlMessage): gsize; cdecl; get_level: function(message: PGSocketControlMessage): gint; cdecl; get_type: function(message: PGSocketControlMessage): gint; cdecl; serialize: procedure(message: PGSocketControlMessage; data: gpointer); cdecl; deserialize: function(level: gint; type_: gint; size: gsize; data: gpointer): PGSocketControlMessage; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGSocketListener = ^PGSocketListener; PGSocketListener = ^TGSocketListener; PPGSocketListenerPrivate = ^PGSocketListenerPrivate; PGSocketListenerPrivate = ^TGSocketListenerPrivate; TGSocketListener = object(TGObject) priv: PGSocketListenerPrivate; end; TGSocketListenerPrivate = record end; PPGSocketListenerClass = ^PGSocketListenerClass; PGSocketListenerClass = ^TGSocketListenerClass; TGSocketListenerClass = object parent_class: TGObjectClass; changed: procedure(listener: PGSocketListener); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; end; PPGSocketMsgFlags = ^PGSocketMsgFlags; PGSocketMsgFlags = ^TGSocketMsgFlags; PPGSocketService = ^PGSocketService; PGSocketService = ^TGSocketService; PPGSocketServicePrivate = ^PGSocketServicePrivate; PGSocketServicePrivate = ^TGSocketServicePrivate; TGSocketService = object(TGSocketListener) priv1: PGSocketServicePrivate; end; TGSocketServicePrivate = record end; PPGSocketServiceClass = ^PGSocketServiceClass; PGSocketServiceClass = ^TGSocketServiceClass; TGSocketServiceClass = object parent_class: TGSocketListenerClass; incoming: function(service: PGSocketService; connection: PGSocketConnection; source_object: PGObject): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; end; TGSocketSourceFunc = function(socket: PGSocket; condition: TGIOCondition; user_data: gpointer): gboolean; cdecl; PPGSrvTarget = ^PGSrvTarget; PGSrvTarget = ^TGSrvTarget; TGSrvTarget = object end; PPGStaticResource = ^PGStaticResource; PGStaticResource = ^TGStaticResource; TGStaticResource = object data: Pguint8; data_len: gsize; resource: PGResource; next: PGStaticResource; padding: gpointer; end; PPGTask = ^PGTask; PGTask = ^TGTask; PPGTaskThreadFunc = ^PGTaskThreadFunc; PGTaskThreadFunc = ^TGTaskThreadFunc; TGTaskThreadFunc = procedure(task: PGTask; source_object: PGObject; task_data: gpointer; cancellable: PGCancellable); cdecl; TGTask = object(TGObject) end; PPGTaskClass = ^PGTaskClass; PGTaskClass = ^TGTaskClass; TGTaskClass = object end; PPGTcpConnection = ^PGTcpConnection; PGTcpConnection = ^TGTcpConnection; PPGTcpConnectionPrivate = ^PGTcpConnectionPrivate; PGTcpConnectionPrivate = ^TGTcpConnectionPrivate; TGTcpConnection = object(TGSocketConnection) priv2: PGTcpConnectionPrivate; end; TGTcpConnectionPrivate = record end; PPGTcpConnectionClass = ^PGTcpConnectionClass; PGTcpConnectionClass = ^TGTcpConnectionClass; TGTcpConnectionClass = object parent_class: TGSocketConnectionClass; end; PPGTcpWrapperConnection = ^PGTcpWrapperConnection; PGTcpWrapperConnection = ^TGTcpWrapperConnection; PPGTcpWrapperConnectionPrivate = ^PGTcpWrapperConnectionPrivate; PGTcpWrapperConnectionPrivate = ^TGTcpWrapperConnectionPrivate; TGTcpWrapperConnection = object(TGTcpConnection) priv3: PGTcpWrapperConnectionPrivate; end; TGTcpWrapperConnectionPrivate = record end; PPGTcpWrapperConnectionClass = ^PGTcpWrapperConnectionClass; PGTcpWrapperConnectionClass = ^TGTcpWrapperConnectionClass; TGTcpWrapperConnectionClass = object parent_class: TGTcpConnectionClass; end; PPGTestDBus = ^PGTestDBus; PGTestDBus = ^TGTestDBus; PPGTestDBusFlags = ^PGTestDBusFlags; PGTestDBusFlags = ^TGTestDBusFlags; TGTestDBus = object(TGObject) end; PPGThemedIcon = ^PGThemedIcon; PGThemedIcon = ^TGThemedIcon; TGThemedIcon = object(TGObject) end; PPGThemedIconClass = ^PGThemedIconClass; PGThemedIconClass = ^TGThemedIconClass; TGThemedIconClass = object end; PPGThreadedSocketService = ^PGThreadedSocketService; PGThreadedSocketService = ^TGThreadedSocketService; PPGThreadedSocketServicePrivate = ^PGThreadedSocketServicePrivate; PGThreadedSocketServicePrivate = ^TGThreadedSocketServicePrivate; TGThreadedSocketService = object(TGSocketService) priv2: PGThreadedSocketServicePrivate; end; TGThreadedSocketServicePrivate = record end; PPGThreadedSocketServiceClass = ^PGThreadedSocketServiceClass; PGThreadedSocketServiceClass = ^TGThreadedSocketServiceClass; TGThreadedSocketServiceClass = object parent_class: TGSocketServiceClass; run: function(service: PGThreadedSocketService; connection: PGSocketConnection; source_object: PGObject): gboolean; cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGTlsAuthenticationMode = ^PGTlsAuthenticationMode; PGTlsAuthenticationMode = ^TGTlsAuthenticationMode; PPGTlsBackend = ^PGTlsBackend; PGTlsBackend = ^TGTlsBackend; PPGTlsDatabase = ^PGTlsDatabase; PGTlsDatabase = ^TGTlsDatabase; TGTlsBackend = object end; PPGTlsCertificate = ^PGTlsCertificate; PGTlsCertificate = ^TGTlsCertificate; PPGTlsInteraction = ^PGTlsInteraction; PGTlsInteraction = ^TGTlsInteraction; PPGTlsDatabaseLookupFlags = ^PGTlsDatabaseLookupFlags; PGTlsDatabaseLookupFlags = ^TGTlsDatabaseLookupFlags; PPGTlsDatabaseVerifyFlags = ^PGTlsDatabaseVerifyFlags; PGTlsDatabaseVerifyFlags = ^TGTlsDatabaseVerifyFlags; PPGTlsDatabasePrivate = ^PGTlsDatabasePrivate; PGTlsDatabasePrivate = ^TGTlsDatabasePrivate; TGTlsDatabase = object(TGObject) priv: PGTlsDatabasePrivate; end; PPGTlsBackendInterface = ^PGTlsBackendInterface; PGTlsBackendInterface = ^TGTlsBackendInterface; TGTlsBackendInterface = object g_iface: TGTypeInterface; supports_tls: function(backend: PGTlsBackend): gboolean; cdecl; get_certificate_type: function: TGType; cdecl; get_client_connection_type: function: TGType; cdecl; get_server_connection_type: function: TGType; cdecl; get_file_database_type: function: TGType; cdecl; get_default_database: function(backend: PGTlsBackend): PGTlsDatabase; cdecl; end; PPGTlsCertificatePrivate = ^PGTlsCertificatePrivate; PGTlsCertificatePrivate = ^TGTlsCertificatePrivate; TGTlsCertificate = object(TGObject) priv: PGTlsCertificatePrivate; end; TGTlsCertificatePrivate = record end; PPGTlsCertificateClass = ^PGTlsCertificateClass; PGTlsCertificateClass = ^TGTlsCertificateClass; TGTlsCertificateClass = object parent_class: TGObjectClass; verify: function(cert: PGTlsCertificate; identity: PGSocketConnectable; trusted_ca: PGTlsCertificate): TGTlsCertificateFlags; cdecl; padding: array [0..7] of gpointer; end; PPGTlsClientConnection = ^PGTlsClientConnection; PGTlsClientConnection = ^TGTlsClientConnection; TGTlsClientConnection = object end; PPGTlsClientConnectionInterface = ^PGTlsClientConnectionInterface; PGTlsClientConnectionInterface = ^TGTlsClientConnectionInterface; TGTlsClientConnectionInterface = object g_iface: TGTypeInterface; end; PPGTlsConnection = ^PGTlsConnection; PGTlsConnection = ^TGTlsConnection; PPGTlsRehandshakeMode = ^PGTlsRehandshakeMode; PGTlsRehandshakeMode = ^TGTlsRehandshakeMode; PPGTlsConnectionPrivate = ^PGTlsConnectionPrivate; PGTlsConnectionPrivate = ^TGTlsConnectionPrivate; TGTlsConnection = object(TGIOStream) priv1: PGTlsConnectionPrivate; end; PPGTlsInteractionResult = ^PGTlsInteractionResult; PGTlsInteractionResult = ^TGTlsInteractionResult; PPGTlsPassword = ^PGTlsPassword; PGTlsPassword = ^TGTlsPassword; PPGTlsInteractionPrivate = ^PGTlsInteractionPrivate; PGTlsInteractionPrivate = ^TGTlsInteractionPrivate; TGTlsInteraction = object(TGObject) priv: PGTlsInteractionPrivate; end; TGTlsConnectionPrivate = record end; PPGTlsConnectionClass = ^PGTlsConnectionClass; PGTlsConnectionClass = ^TGTlsConnectionClass; TGTlsConnectionClass = object parent_class: TGIOStreamClass; accept_certificate: function(connection: PGTlsConnection; peer_cert: PGTlsCertificate; errors: TGTlsCertificateFlags): gboolean; cdecl; handshake: function(conn: PGTlsConnection; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; handshake_async: procedure(conn: PGTlsConnection; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; handshake_finish: function(conn: PGTlsConnection; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; padding: array [0..7] of gpointer; end; TGTlsDatabasePrivate = record end; PPGTlsDatabaseClass = ^PGTlsDatabaseClass; PGTlsDatabaseClass = ^TGTlsDatabaseClass; TGTlsDatabaseClass = object parent_class: TGObjectClass; verify_chain: function(self: PGTlsDatabase; chain: PGTlsCertificate; purpose: Pgchar; identity: PGSocketConnectable; interaction: PGTlsInteraction; flags: TGTlsDatabaseVerifyFlags; cancellable: PGCancellable; error: PPGError): TGTlsCertificateFlags; cdecl; verify_chain_async: procedure(self: PGTlsDatabase; chain: PGTlsCertificate; purpose: Pgchar; identity: PGSocketConnectable; interaction: PGTlsInteraction; flags: TGTlsDatabaseVerifyFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; verify_chain_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): TGTlsCertificateFlags; cdecl; create_certificate_handle: function(self: PGTlsDatabase; certificate: PGTlsCertificate): Pgchar; cdecl; lookup_certificate_for_handle: function(self: PGTlsDatabase; handle: Pgchar; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; error: PPGError): PGTlsCertificate; cdecl; lookup_certificate_for_handle_async: procedure(self: PGTlsDatabase; handle: Pgchar; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_certificate_for_handle_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): PGTlsCertificate; cdecl; lookup_certificate_issuer: function(self: PGTlsDatabase; certificate: PGTlsCertificate; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; error: PPGError): PGTlsCertificate; cdecl; lookup_certificate_issuer_async: procedure(self: PGTlsDatabase; certificate: PGTlsCertificate; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_certificate_issuer_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): PGTlsCertificate; cdecl; lookup_certificates_issued_by: function(self: PGTlsDatabase; issuer_raw_dn: Pguint8; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; error: PPGError): PGList; cdecl; lookup_certificates_issued_by_async: procedure(self: PGTlsDatabase; issuer_raw_dn: Pguint8; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; lookup_certificates_issued_by_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): PGList; cdecl; padding: array [0..15] of gpointer; end; PPGTlsError = ^PGTlsError; PGTlsError = ^TGTlsError; PPGTlsFileDatabase = ^PGTlsFileDatabase; PGTlsFileDatabase = ^TGTlsFileDatabase; TGTlsFileDatabase = object end; PPGTlsFileDatabaseInterface = ^PGTlsFileDatabaseInterface; PGTlsFileDatabaseInterface = ^TGTlsFileDatabaseInterface; TGTlsFileDatabaseInterface = object g_iface: TGTypeInterface; padding: array [0..7] of gpointer; end; PPGTlsPasswordFlags = ^PGTlsPasswordFlags; PGTlsPasswordFlags = ^TGTlsPasswordFlags; PPGTlsPasswordPrivate = ^PGTlsPasswordPrivate; PGTlsPasswordPrivate = ^TGTlsPasswordPrivate; TGTlsPassword = object(TGObject) priv: PGTlsPasswordPrivate; end; TGTlsInteractionPrivate = record end; PPGTlsInteractionClass = ^PGTlsInteractionClass; PGTlsInteractionClass = ^TGTlsInteractionClass; TGTlsInteractionClass = object parent_class: TGObjectClass; ask_password: function(interaction: PGTlsInteraction; password: PGTlsPassword; cancellable: PGCancellable; error: PPGError): TGTlsInteractionResult; cdecl; ask_password_async: procedure(interaction: PGTlsInteraction; password: PGTlsPassword; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; ask_password_finish: function(interaction: PGTlsInteraction; result_: PGAsyncResult; error: PPGError): TGTlsInteractionResult; cdecl; padding: array [0..23] of gpointer; end; TGTlsPasswordPrivate = record end; PPGTlsPasswordClass = ^PGTlsPasswordClass; PGTlsPasswordClass = ^TGTlsPasswordClass; TGTlsPasswordClass = object parent_class: TGObjectClass; get_value: function(password: PGTlsPassword; length: Pgsize): Pguint8; cdecl; set_value: procedure(password: PGTlsPassword; value: Pguint8; length: gssize; destroy_: TGDestroyNotify); cdecl; get_default_warning: function(password: PGTlsPassword): Pgchar; cdecl; padding: array [0..3] of gpointer; end; PPGTlsServerConnection = ^PGTlsServerConnection; PGTlsServerConnection = ^TGTlsServerConnection; TGTlsServerConnection = object end; PPGTlsServerConnectionInterface = ^PGTlsServerConnectionInterface; PGTlsServerConnectionInterface = ^TGTlsServerConnectionInterface; TGTlsServerConnectionInterface = object g_iface: TGTypeInterface; end; PPGUnixConnection = ^PGUnixConnection; PGUnixConnection = ^TGUnixConnection; PPGUnixConnectionPrivate = ^PGUnixConnectionPrivate; PGUnixConnectionPrivate = ^TGUnixConnectionPrivate; TGUnixConnection = object(TGSocketConnection) priv2: PGUnixConnectionPrivate; end; TGUnixConnectionPrivate = record end; PPGUnixConnectionClass = ^PGUnixConnectionClass; PGUnixConnectionClass = ^TGUnixConnectionClass; TGUnixConnectionClass = object parent_class: TGSocketConnectionClass; end; PPGUnixCredentialsMessage = ^PGUnixCredentialsMessage; PGUnixCredentialsMessage = ^TGUnixCredentialsMessage; PPGUnixCredentialsMessagePrivate = ^PGUnixCredentialsMessagePrivate; PGUnixCredentialsMessagePrivate = ^TGUnixCredentialsMessagePrivate; TGUnixCredentialsMessage = object(TGSocketControlMessage) priv1: PGUnixCredentialsMessagePrivate; end; TGUnixCredentialsMessagePrivate = record end; PPGUnixCredentialsMessageClass = ^PGUnixCredentialsMessageClass; PGUnixCredentialsMessageClass = ^TGUnixCredentialsMessageClass; TGUnixCredentialsMessageClass = object parent_class: TGSocketControlMessageClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; end; TGUnixFDListPrivate = record end; PPGUnixFDListClass = ^PGUnixFDListClass; PGUnixFDListClass = ^TGUnixFDListClass; TGUnixFDListClass = object parent_class: TGObjectClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGUnixFDMessage = ^PGUnixFDMessage; PGUnixFDMessage = ^TGUnixFDMessage; PPGUnixFDMessagePrivate = ^PGUnixFDMessagePrivate; PGUnixFDMessagePrivate = ^TGUnixFDMessagePrivate; TGUnixFDMessage = object(TGSocketControlMessage) priv1: PGUnixFDMessagePrivate; end; TGUnixFDMessagePrivate = record end; PPGUnixFDMessageClass = ^PGUnixFDMessageClass; PGUnixFDMessageClass = ^TGUnixFDMessageClass; TGUnixFDMessageClass = object parent_class: TGSocketControlMessageClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; end; PPGUnixInputStream = ^PGUnixInputStream; PGUnixInputStream = ^TGUnixInputStream; PPGUnixInputStreamPrivate = ^PGUnixInputStreamPrivate; PGUnixInputStreamPrivate = ^TGUnixInputStreamPrivate; TGUnixInputStream = object(TGInputStream) priv1: PGUnixInputStreamPrivate; end; TGUnixInputStreamPrivate = record end; PPGUnixInputStreamClass = ^PGUnixInputStreamClass; PGUnixInputStreamClass = ^TGUnixInputStreamClass; TGUnixInputStreamClass = object parent_class: TGInputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGUnixMountEntry = ^PGUnixMountEntry; PGUnixMountEntry = ^TGUnixMountEntry; TGUnixMountEntry = record end; PPGUnixMountMonitor = ^PGUnixMountMonitor; PGUnixMountMonitor = ^TGUnixMountMonitor; TGUnixMountMonitor = object(TGObject) end; PPGUnixMountMonitorClass = ^PGUnixMountMonitorClass; PGUnixMountMonitorClass = ^TGUnixMountMonitorClass; TGUnixMountMonitorClass = object end; PPGUnixMountPoint = ^PGUnixMountPoint; PGUnixMountPoint = ^TGUnixMountPoint; TGUnixMountPoint = object end; PPGUnixOutputStream = ^PGUnixOutputStream; PGUnixOutputStream = ^TGUnixOutputStream; PPGUnixOutputStreamPrivate = ^PGUnixOutputStreamPrivate; PGUnixOutputStreamPrivate = ^TGUnixOutputStreamPrivate; TGUnixOutputStream = object(TGOutputStream) priv1: PGUnixOutputStreamPrivate; end; TGUnixOutputStreamPrivate = record end; PPGUnixOutputStreamClass = ^PGUnixOutputStreamClass; PGUnixOutputStreamClass = ^TGUnixOutputStreamClass; TGUnixOutputStreamClass = object parent_class: TGOutputStreamClass; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; end; PPGUnixSocketAddressType = ^PGUnixSocketAddressType; PGUnixSocketAddressType = ^TGUnixSocketAddressType; PPGUnixSocketAddress = ^PGUnixSocketAddress; PGUnixSocketAddress = ^TGUnixSocketAddress; PPGUnixSocketAddressPrivate = ^PGUnixSocketAddressPrivate; PGUnixSocketAddressPrivate = ^TGUnixSocketAddressPrivate; TGUnixSocketAddress = object(TGSocketAddress) priv: PGUnixSocketAddressPrivate; end; TGUnixSocketAddressPrivate = record end; PPGUnixSocketAddressClass = ^PGUnixSocketAddressClass; PGUnixSocketAddressClass = ^TGUnixSocketAddressClass; TGUnixSocketAddressClass = object parent_class: TGSocketAddressClass; end; PPGVfs = ^PGVfs; PGVfs = ^TGVfs; TGVfs = object(TGObject) end; PPGVfsClass = ^PGVfsClass; PGVfsClass = ^TGVfsClass; TGVfsClass = object parent_class: TGObjectClass; is_active: function(vfs: PGVfs): gboolean; cdecl; get_file_for_path: function(vfs: PGVfs; path: Pgchar): PGFile; cdecl; get_file_for_uri: function(vfs: PGVfs; uri: Pgchar): PGFile; cdecl; get_supported_uri_schemes: function(vfs: PGVfs): PPgchar; cdecl; parse_name: function(vfs: PGVfs; parse_name: Pgchar): PGFile; cdecl; local_file_add_info: procedure(vfs: PGVfs; filename: Pgchar; device: guint64; attribute_matcher: PGFileAttributeMatcher; info: PGFileInfo; cancellable: PGCancellable; extra_data: Pgpointer; free_extra_data: PGDestroyNotify); cdecl; add_writable_namespaces: procedure(vfs: PGVfs; list: PGFileAttributeInfoList); cdecl; local_file_set_attributes: function(vfs: PGVfs; filename: Pgchar; info: PGFileInfo; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; local_file_removed: procedure(vfs: PGVfs; filename: Pgchar); cdecl; local_file_moved: procedure(vfs: PGVfs; source: Pgchar; dest: Pgchar); cdecl; _g_reserved1: procedure; cdecl; _g_reserved2: procedure; cdecl; _g_reserved3: procedure; cdecl; _g_reserved4: procedure; cdecl; _g_reserved5: procedure; cdecl; _g_reserved6: procedure; cdecl; _g_reserved7: procedure; cdecl; end; PPGVolumeIface = ^PGVolumeIface; PGVolumeIface = ^TGVolumeIface; TGVolumeIface = object g_iface: TGTypeInterface; changed: procedure(volume: PGVolume); cdecl; removed: procedure(volume: PGVolume); cdecl; get_name: function(volume: PGVolume): Pgchar; cdecl; get_icon: function(volume: PGVolume): PGIcon; cdecl; get_uuid: function(volume: PGVolume): Pgchar; cdecl; get_drive: function(volume: PGVolume): PGDrive; cdecl; get_mount: function(volume: PGVolume): PGMount; cdecl; can_mount: function(volume: PGVolume): gboolean; cdecl; can_eject: function(volume: PGVolume): gboolean; cdecl; mount_fn: procedure(volume: PGVolume; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; mount_finish: function(volume: PGVolume; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; eject: procedure(volume: PGVolume; flags: TGMountUnmountFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_finish: function(volume: PGVolume; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; get_identifier: function(volume: PGVolume; kind: Pgchar): Pgchar; cdecl; enumerate_identifiers: function(volume: PGVolume): PPgchar; cdecl; should_automount: function(volume: PGVolume): gboolean; cdecl; get_activation_root: function(volume: PGVolume): PGFile; cdecl; eject_with_operation: procedure(volume: PGVolume; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; eject_with_operation_finish: function(volume: PGVolume; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; get_sort_key: function(volume: PGVolume): Pgchar; cdecl; get_symbolic_icon: function(volume: PGVolume): PGIcon; cdecl; end; PPGZlibCompressor = ^PGZlibCompressor; PGZlibCompressor = ^TGZlibCompressor; PPGZlibCompressorFormat = ^PGZlibCompressorFormat; PGZlibCompressorFormat = ^TGZlibCompressorFormat; TGZlibCompressor = object(TGObject) end; PPGZlibCompressorClass = ^PGZlibCompressorClass; PGZlibCompressorClass = ^TGZlibCompressorClass; TGZlibCompressorClass = object parent_class: TGObjectClass; end; PPGZlibDecompressor = ^PGZlibDecompressor; PGZlibDecompressor = ^TGZlibDecompressor; TGZlibDecompressor = object(TGObject) end; PPGZlibDecompressorClass = ^PGZlibDecompressorClass; PGZlibDecompressorClass = ^TGZlibDecompressorClass; TGZlibDecompressorClass = object parent_class: TGObjectClass; end; var g_action_activate: procedure(action: PGAction; parameter: PGVariant); cdecl; g_action_change_state: procedure(action: PGAction; value: PGVariant); cdecl; g_action_get_enabled: function(action: PGAction): gboolean; cdecl; g_action_get_name: function(action: PGAction): Pgchar; cdecl; g_action_get_parameter_type: function(action: PGAction): PGVariantType; cdecl; g_action_get_state: function(action: PGAction): PGVariant; cdecl; g_action_get_state_hint: function(action: PGAction): PGVariant; cdecl; g_action_get_state_type: function(action: PGAction): PGVariantType; cdecl; g_action_get_type: function:TGType; cdecl; g_action_group_action_added: procedure(action_group: PGActionGroup; action_name: Pgchar); cdecl; g_action_group_action_enabled_changed: procedure(action_group: PGActionGroup; action_name: Pgchar; enabled: gboolean); cdecl; g_action_group_action_removed: procedure(action_group: PGActionGroup; action_name: Pgchar); cdecl; g_action_group_action_state_changed: procedure(action_group: PGActionGroup; action_name: Pgchar; state: PGVariant); cdecl; g_action_group_activate_action: procedure(action_group: PGActionGroup; action_name: Pgchar; parameter: PGVariant); cdecl; g_action_group_change_action_state: procedure(action_group: PGActionGroup; action_name: Pgchar; value: PGVariant); cdecl; g_action_group_get_action_enabled: function(action_group: PGActionGroup; action_name: Pgchar): gboolean; cdecl; g_action_group_get_action_parameter_type: function(action_group: PGActionGroup; action_name: Pgchar): PGVariantType; cdecl; g_action_group_get_action_state: function(action_group: PGActionGroup; action_name: Pgchar): PGVariant; cdecl; g_action_group_get_action_state_hint: function(action_group: PGActionGroup; action_name: Pgchar): PGVariant; cdecl; g_action_group_get_action_state_type: function(action_group: PGActionGroup; action_name: Pgchar): PGVariantType; cdecl; g_action_group_get_type: function:TGType; cdecl; g_action_group_has_action: function(action_group: PGActionGroup; action_name: Pgchar): gboolean; cdecl; g_action_group_list_actions: function(action_group: PGActionGroup): PPgchar; cdecl; g_action_group_query_action: function(action_group: PGActionGroup; action_name: Pgchar; enabled: Pgboolean; parameter_type: PPGVariantType; state_type: PPGVariantType; state_hint: PPGVariant; state: PPGVariant): gboolean; cdecl; g_action_map_add_action: procedure(action_map: PGActionMap; action: PGAction); cdecl; g_action_map_add_action_entries: procedure(action_map: PGActionMap; entries: PGActionEntry; n_entries: gint; user_data: gpointer); cdecl; g_action_map_get_type: function:TGType; cdecl; g_action_map_lookup_action: function(action_map: PGActionMap; action_name: Pgchar): PGAction; cdecl; g_action_map_remove_action: procedure(action_map: PGActionMap; action_name: Pgchar); cdecl; g_app_info_add_supports_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; g_app_info_can_delete: function(appinfo: PGAppInfo): gboolean; cdecl; g_app_info_can_remove_supports_type: function(appinfo: PGAppInfo): gboolean; cdecl; g_app_info_create_from_commandline: function(commandline: Pgchar; application_name: Pgchar; flags: TGAppInfoCreateFlags; error: PPGError): PGAppInfo; cdecl; g_app_info_delete: function(appinfo: PGAppInfo): gboolean; cdecl; g_app_info_dup: function(appinfo: PGAppInfo): PGAppInfo; cdecl; g_app_info_equal: function(appinfo1: PGAppInfo; appinfo2: PGAppInfo): gboolean; cdecl; g_app_info_get_all: function: PGList; cdecl; g_app_info_get_all_for_type: function(content_type: Pgchar): PGList; cdecl; g_app_info_get_commandline: function(appinfo: PGAppInfo): Pgchar; cdecl; g_app_info_get_default_for_type: function(content_type: Pgchar; must_support_uris: gboolean): PGAppInfo; cdecl; g_app_info_get_default_for_uri_scheme: function(uri_scheme: Pgchar): PGAppInfo; cdecl; g_app_info_get_description: function(appinfo: PGAppInfo): Pgchar; cdecl; g_app_info_get_display_name: function(appinfo: PGAppInfo): Pgchar; cdecl; g_app_info_get_executable: function(appinfo: PGAppInfo): Pgchar; cdecl; g_app_info_get_fallback_for_type: function(content_type: Pgchar): PGList; cdecl; g_app_info_get_icon: function(appinfo: PGAppInfo): PGIcon; cdecl; g_app_info_get_id: function(appinfo: PGAppInfo): Pgchar; cdecl; g_app_info_get_name: function(appinfo: PGAppInfo): Pgchar; cdecl; g_app_info_get_recommended_for_type: function(content_type: Pgchar): PGList; cdecl; g_app_info_get_supported_types: function(appinfo: PGAppInfo): PPgchar; cdecl; g_app_info_get_type: function:TGType; cdecl; g_app_info_launch: function(appinfo: PGAppInfo; files: PGList; launch_context: PGAppLaunchContext; error: PPGError): gboolean; cdecl; g_app_info_launch_default_for_uri: function(uri: Pgchar; launch_context: PGAppLaunchContext; error: PPGError): gboolean; cdecl; g_app_info_launch_uris: function(appinfo: PGAppInfo; uris: PGList; launch_context: PGAppLaunchContext; error: PPGError): gboolean; cdecl; g_app_info_remove_supports_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; g_app_info_reset_type_associations: procedure(content_type: Pgchar); cdecl; g_app_info_set_as_default_for_extension: function(appinfo: PGAppInfo; extension: Pgchar; error: PPGError): gboolean; cdecl; g_app_info_set_as_default_for_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; g_app_info_set_as_last_used_for_type: function(appinfo: PGAppInfo; content_type: Pgchar; error: PPGError): gboolean; cdecl; g_app_info_should_show: function(appinfo: PGAppInfo): gboolean; cdecl; g_app_info_supports_files: function(appinfo: PGAppInfo): gboolean; cdecl; g_app_info_supports_uris: function(appinfo: PGAppInfo): gboolean; cdecl; g_app_launch_context_get_display: function(context: PGAppLaunchContext; info: PGAppInfo; files: PGList): Pgchar; cdecl; g_app_launch_context_get_environment: function(context: PGAppLaunchContext): PPgchar; cdecl; g_app_launch_context_get_startup_notify_id: function(context: PGAppLaunchContext; info: PGAppInfo; files: PGList): Pgchar; cdecl; g_app_launch_context_get_type: function:TGType; cdecl; g_app_launch_context_launch_failed: procedure(context: PGAppLaunchContext; startup_notify_id: Pgchar); cdecl; g_app_launch_context_new: function: PGAppLaunchContext; cdecl; g_app_launch_context_setenv: procedure(context: PGAppLaunchContext; variable: Pgchar; value: Pgchar); cdecl; g_app_launch_context_unsetenv: procedure(context: PGAppLaunchContext; variable: Pgchar); cdecl; g_application_activate: procedure(application: PGApplication); cdecl; g_application_command_line_create_file_for_arg: function(cmdline: PGApplicationCommandLine; arg: Pgchar): PGFile; cdecl; g_application_command_line_get_arguments: function(cmdline: PGApplicationCommandLine; argc: Pgint): PPgchar; cdecl; g_application_command_line_get_cwd: function(cmdline: PGApplicationCommandLine): Pgchar; cdecl; g_application_command_line_get_environ: function(cmdline: PGApplicationCommandLine): PPgchar; cdecl; g_application_command_line_get_exit_status: function(cmdline: PGApplicationCommandLine): gint; cdecl; g_application_command_line_get_is_remote: function(cmdline: PGApplicationCommandLine): gboolean; cdecl; g_application_command_line_get_platform_data: function(cmdline: PGApplicationCommandLine): PGVariant; cdecl; g_application_command_line_get_stdin: function(cmdline: PGApplicationCommandLine): PGInputStream; cdecl; g_application_command_line_get_type: function:TGType; cdecl; g_application_command_line_getenv: function(cmdline: PGApplicationCommandLine; name: Pgchar): Pgchar; cdecl; g_application_command_line_print: procedure(cmdline: PGApplicationCommandLine; format: Pgchar; args: array of const); cdecl; g_application_command_line_printerr: procedure(cmdline: PGApplicationCommandLine; format: Pgchar; args: array of const); cdecl; g_application_command_line_set_exit_status: procedure(cmdline: PGApplicationCommandLine; exit_status: gint); cdecl; g_application_get_application_id: function(application: PGApplication): Pgchar; cdecl; g_application_get_dbus_connection: function(application: PGApplication): PGDBusConnection; cdecl; g_application_get_dbus_object_path: function(application: PGApplication): Pgchar; cdecl; g_application_get_default: function: PGApplication; cdecl; g_application_get_flags: function(application: PGApplication): TGApplicationFlags; cdecl; g_application_get_inactivity_timeout: function(application: PGApplication): guint; cdecl; g_application_get_is_registered: function(application: PGApplication): gboolean; cdecl; g_application_get_is_remote: function(application: PGApplication): gboolean; cdecl; g_application_get_type: function:TGType; cdecl; g_application_hold: procedure(application: PGApplication); cdecl; g_application_id_is_valid: function(application_id: Pgchar): gboolean; cdecl; g_application_new: function(application_id: Pgchar; flags: TGApplicationFlags): PGApplication; cdecl; g_application_open: procedure(application: PGApplication; files: PPGFile; n_files: gint; hint: Pgchar); cdecl; g_application_quit: procedure(application: PGApplication); cdecl; g_application_register: function(application: PGApplication; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_application_release: procedure(application: PGApplication); cdecl; g_application_run: function(application: PGApplication; argc: gint; argv: PPgchar): gint; cdecl; g_application_set_application_id: procedure(application: PGApplication; application_id: Pgchar); cdecl; g_application_set_default: procedure(application: PGApplication); cdecl; g_application_set_flags: procedure(application: PGApplication; flags: TGApplicationFlags); cdecl; g_application_set_inactivity_timeout: procedure(application: PGApplication; inactivity_timeout: guint); cdecl; g_async_initable_get_type: function:TGType; cdecl; g_async_initable_init_async: procedure(initable: PGAsyncInitable; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_async_initable_init_finish: function(initable: PGAsyncInitable; res: PGAsyncResult; error: PPGError): gboolean; cdecl; g_async_initable_new_async: procedure(object_type: TGType; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer; first_property_name: Pgchar; args: array of const); cdecl; g_async_initable_new_finish: function(initable: PGAsyncInitable; res: PGAsyncResult; error: PPGError): PGObject; cdecl; g_async_initable_new_valist_async: procedure(object_type: TGType; first_property_name: Pgchar; var_args: Tva_list; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_async_initable_newv_async: procedure(object_type: TGType; n_parameters: guint; parameters: PGParameter; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_async_result_get_source_object: function(res: PGAsyncResult): PGObject; cdecl; g_async_result_get_type: function:TGType; cdecl; g_async_result_get_user_data: function(res: PGAsyncResult): gpointer; cdecl; g_async_result_is_tagged: function(res: PGAsyncResult; source_tag: gpointer): gboolean; cdecl; g_async_result_legacy_propagate_error: function(res: PGAsyncResult; error: PPGError): gboolean; cdecl; g_buffered_input_stream_fill: function(stream: PGBufferedInputStream; count: gssize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_buffered_input_stream_fill_async: procedure(stream: PGBufferedInputStream; count: gssize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_buffered_input_stream_fill_finish: function(stream: PGBufferedInputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; g_buffered_input_stream_get_available: function(stream: PGBufferedInputStream): gsize; cdecl; g_buffered_input_stream_get_buffer_size: function(stream: PGBufferedInputStream): gsize; cdecl; g_buffered_input_stream_get_type: function:TGType; cdecl; g_buffered_input_stream_new: function(base_stream: PGInputStream): PGBufferedInputStream; cdecl; g_buffered_input_stream_new_sized: function(base_stream: PGInputStream; size: gsize): PGBufferedInputStream; cdecl; g_buffered_input_stream_peek: function(stream: PGBufferedInputStream; buffer: Pguint8; offset: gsize; count: gsize): gsize; cdecl; g_buffered_input_stream_peek_buffer: function(stream: PGBufferedInputStream; count: Pgsize): Pguint8; cdecl; g_buffered_input_stream_read_byte: function(stream: PGBufferedInputStream; cancellable: PGCancellable; error: PPGError): gint; cdecl; g_buffered_input_stream_set_buffer_size: procedure(stream: PGBufferedInputStream; size: gsize); cdecl; g_buffered_output_stream_get_auto_grow: function(stream: PGBufferedOutputStream): gboolean; cdecl; g_buffered_output_stream_get_buffer_size: function(stream: PGBufferedOutputStream): gsize; cdecl; g_buffered_output_stream_get_type: function:TGType; cdecl; g_buffered_output_stream_new: function(base_stream: PGOutputStream): PGBufferedOutputStream; cdecl; g_buffered_output_stream_new_sized: function(base_stream: PGOutputStream; size: gsize): PGBufferedOutputStream; cdecl; g_buffered_output_stream_set_auto_grow: procedure(stream: PGBufferedOutputStream; auto_grow: gboolean); cdecl; g_buffered_output_stream_set_buffer_size: procedure(stream: PGBufferedOutputStream; size: gsize); cdecl; g_bus_get: procedure(bus_type: TGBusType; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_bus_get_finish: function(res: PGAsyncResult; error: PPGError): PGDBusConnection; cdecl; g_bus_get_sync: function(bus_type: TGBusType; cancellable: PGCancellable; error: PPGError): PGDBusConnection; cdecl; g_bus_own_name: function(bus_type: TGBusType; name: Pgchar; flags: TGBusNameOwnerFlags; bus_acquired_handler: TGBusAcquiredCallback; name_acquired_handler: TGBusNameAcquiredCallback; name_lost_handler: TGBusNameLostCallback; user_data: gpointer; user_data_free_func: TGDestroyNotify): guint; cdecl; g_bus_own_name_on_connection: function(connection: PGDBusConnection; name: Pgchar; flags: TGBusNameOwnerFlags; name_acquired_handler: TGBusNameAcquiredCallback; name_lost_handler: TGBusNameLostCallback; user_data: gpointer; user_data_free_func: TGDestroyNotify): guint; cdecl; g_bus_own_name_on_connection_with_closures: function(connection: PGDBusConnection; name: Pgchar; flags: TGBusNameOwnerFlags; name_acquired_closure: PGClosure; name_lost_closure: PGClosure): guint; cdecl; g_bus_own_name_with_closures: function(bus_type: TGBusType; name: Pgchar; flags: TGBusNameOwnerFlags; bus_acquired_closure: PGClosure; name_acquired_closure: PGClosure; name_lost_closure: PGClosure): guint; cdecl; g_bus_unown_name: procedure(owner_id: guint); cdecl; g_bus_unwatch_name: procedure(watcher_id: guint); cdecl; g_bus_watch_name: function(bus_type: TGBusType; name: Pgchar; flags: TGBusNameWatcherFlags; name_appeared_handler: TGBusNameAppearedCallback; name_vanished_handler: TGBusNameVanishedCallback; user_data: gpointer; user_data_free_func: TGDestroyNotify): guint; cdecl; g_bus_watch_name_on_connection: function(connection: PGDBusConnection; name: Pgchar; flags: TGBusNameWatcherFlags; name_appeared_handler: TGBusNameAppearedCallback; name_vanished_handler: TGBusNameVanishedCallback; user_data: gpointer; user_data_free_func: TGDestroyNotify): guint; cdecl; g_bus_watch_name_on_connection_with_closures: function(connection: PGDBusConnection; name: Pgchar; flags: TGBusNameWatcherFlags; name_appeared_closure: PGClosure; name_vanished_closure: PGClosure): guint; cdecl; g_bus_watch_name_with_closures: function(bus_type: TGBusType; name: Pgchar; flags: TGBusNameWatcherFlags; name_appeared_closure: PGClosure; name_vanished_closure: PGClosure): guint; cdecl; g_cancellable_cancel: procedure(cancellable: PGCancellable); cdecl; g_cancellable_connect: function(cancellable: PGCancellable; callback: TGCallback; data: gpointer; data_destroy_func: TGDestroyNotify): gulong; cdecl; g_cancellable_disconnect: procedure(cancellable: PGCancellable; handler_id: gulong); cdecl; g_cancellable_get_current: function: PGCancellable; cdecl; g_cancellable_get_fd: function(cancellable: PGCancellable): gint; cdecl; g_cancellable_get_type: function:TGType; cdecl; g_cancellable_is_cancelled: function(cancellable: PGCancellable): gboolean; cdecl; g_cancellable_make_pollfd: function(cancellable: PGCancellable; pollfd: PGPollFD): gboolean; cdecl; g_cancellable_new: function: PGCancellable; cdecl; g_cancellable_pop_current: procedure(cancellable: PGCancellable); cdecl; g_cancellable_push_current: procedure(cancellable: PGCancellable); cdecl; g_cancellable_release_fd: procedure(cancellable: PGCancellable); cdecl; g_cancellable_reset: procedure(cancellable: PGCancellable); cdecl; g_cancellable_set_error_if_cancelled: function(cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_cancellable_source_new: function(cancellable: PGCancellable): PGSource; cdecl; g_charset_converter_get_num_fallbacks: function(converter: PGCharsetConverter): guint; cdecl; g_charset_converter_get_type: function:TGType; cdecl; g_charset_converter_get_use_fallback: function(converter: PGCharsetConverter): gboolean; cdecl; g_charset_converter_new: function(to_charset: Pgchar; from_charset: Pgchar; error: PPGError): PGCharsetConverter; cdecl; g_charset_converter_set_use_fallback: procedure(converter: PGCharsetConverter; use_fallback: gboolean); cdecl; g_content_type_can_be_executable: function(type_: Pgchar): gboolean; cdecl; g_content_type_equals: function(type1: Pgchar; type2: Pgchar): gboolean; cdecl; g_content_type_from_mime_type: function(mime_type: Pgchar): Pgchar; cdecl; g_content_type_get_description: function(type_: Pgchar): Pgchar; cdecl; g_content_type_get_generic_icon_name: function(type_: Pgchar): Pgchar; cdecl; g_content_type_get_icon: function(type_: Pgchar): PGIcon; cdecl; g_content_type_get_mime_type: function(type_: Pgchar): Pgchar; cdecl; g_content_type_get_symbolic_icon: function(type_: Pgchar): PGIcon; cdecl; g_content_type_guess: function(filename: Pgchar; data: Pguint8; data_size: gsize; result_uncertain: Pgboolean): Pgchar; cdecl; g_content_type_guess_for_tree: function(root: PGFile): PPgchar; cdecl; g_content_type_is_a: function(type_: Pgchar; supertype: Pgchar): gboolean; cdecl; g_content_type_is_unknown: function(type_: Pgchar): gboolean; cdecl; g_content_types_get_registered: function: PGList; cdecl; g_converter_convert: function(converter: PGConverter; inbuf: Pguint8; inbuf_size: gsize; outbuf: Pgpointer; outbuf_size: gsize; flags: TGConverterFlags; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): TGConverterResult; cdecl; g_converter_get_type: function:TGType; cdecl; g_converter_input_stream_get_converter: function(converter_stream: PGConverterInputStream): PGConverter; cdecl; g_converter_input_stream_get_type: function:TGType; cdecl; g_converter_input_stream_new: function(base_stream: PGInputStream; converter: PGConverter): PGConverterInputStream; cdecl; g_converter_output_stream_get_converter: function(converter_stream: PGConverterOutputStream): PGConverter; cdecl; g_converter_output_stream_get_type: function:TGType; cdecl; g_converter_output_stream_new: function(base_stream: PGOutputStream; converter: PGConverter): PGConverterOutputStream; cdecl; g_converter_reset: procedure(converter: PGConverter); cdecl; g_credentials_get_native: function(credentials: PGCredentials; native_type: TGCredentialsType): gpointer; cdecl; g_credentials_get_type: function:TGType; cdecl; g_credentials_get_unix_pid: function(credentials: PGCredentials; error: PPGError): gint; cdecl; g_credentials_get_unix_user: function(credentials: PGCredentials; error: PPGError): guint; cdecl; g_credentials_is_same_user: function(credentials: PGCredentials; other_credentials: PGCredentials; error: PPGError): gboolean; cdecl; g_credentials_new: function: PGCredentials; cdecl; g_credentials_set_native: procedure(credentials: PGCredentials; native_type: TGCredentialsType; native: gpointer); cdecl; g_credentials_set_unix_user: function(credentials: PGCredentials; uid: guint; error: PPGError): gboolean; cdecl; g_credentials_to_string: function(credentials: PGCredentials): Pgchar; cdecl; g_data_input_stream_get_byte_order: function(stream: PGDataInputStream): TGDataStreamByteOrder; cdecl; g_data_input_stream_get_newline_type: function(stream: PGDataInputStream): TGDataStreamNewlineType; cdecl; g_data_input_stream_get_type: function:TGType; cdecl; g_data_input_stream_new: function(base_stream: PGInputStream): PGDataInputStream; cdecl; g_data_input_stream_read_byte: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): guint8; cdecl; g_data_input_stream_read_int16: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): gint16; cdecl; g_data_input_stream_read_int32: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): gint32; cdecl; g_data_input_stream_read_int64: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): gint64; cdecl; g_data_input_stream_read_line: function(stream: PGDataInputStream; length: Pgsize; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_line_async: procedure(stream: PGDataInputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_data_input_stream_read_line_finish: function(stream: PGDataInputStream; result_: PGAsyncResult; length: Pgsize; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_line_finish_utf8: function(stream: PGDataInputStream; result_: PGAsyncResult; length: Pgsize; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_line_utf8: function(stream: PGDataInputStream; length: Pgsize; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_uint16: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): guint16; cdecl; g_data_input_stream_read_uint32: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): guint32; cdecl; g_data_input_stream_read_uint64: function(stream: PGDataInputStream; cancellable: PGCancellable; error: PPGError): guint64; cdecl; g_data_input_stream_read_until: function(stream: PGDataInputStream; stop_chars: Pgchar; length: Pgsize; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_until_async: procedure(stream: PGDataInputStream; stop_chars: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_data_input_stream_read_until_finish: function(stream: PGDataInputStream; result_: PGAsyncResult; length: Pgsize; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_upto: function(stream: PGDataInputStream; stop_chars: Pgchar; stop_chars_len: gssize; length: Pgsize; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; g_data_input_stream_read_upto_async: procedure(stream: PGDataInputStream; stop_chars: Pgchar; stop_chars_len: gssize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_data_input_stream_read_upto_finish: function(stream: PGDataInputStream; result_: PGAsyncResult; length: Pgsize; error: PPGError): Pgchar; cdecl; g_data_input_stream_set_byte_order: procedure(stream: PGDataInputStream; order: TGDataStreamByteOrder); cdecl; g_data_input_stream_set_newline_type: procedure(stream: PGDataInputStream; type_: TGDataStreamNewlineType); cdecl; g_data_output_stream_get_byte_order: function(stream: PGDataOutputStream): TGDataStreamByteOrder; cdecl; g_data_output_stream_get_type: function:TGType; cdecl; g_data_output_stream_new: function(base_stream: PGOutputStream): PGDataOutputStream; cdecl; g_data_output_stream_put_byte: function(stream: PGDataOutputStream; data: guint8; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_int16: function(stream: PGDataOutputStream; data: gint16; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_int32: function(stream: PGDataOutputStream; data: gint32; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_int64: function(stream: PGDataOutputStream; data: gint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_string: function(stream: PGDataOutputStream; str: Pgchar; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_uint16: function(stream: PGDataOutputStream; data: guint16; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_uint32: function(stream: PGDataOutputStream; data: guint32; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_put_uint64: function(stream: PGDataOutputStream; data: guint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_data_output_stream_set_byte_order: procedure(stream: PGDataOutputStream; order: TGDataStreamByteOrder); cdecl; g_dbus_action_group_get: function(connection: PGDBusConnection; bus_name: Pgchar; object_path: Pgchar): PGDBusActionGroup; cdecl; g_dbus_action_group_get_type: function:TGType; cdecl; g_dbus_address_escape_value: function(string_: Pgchar): Pgchar; cdecl; g_dbus_address_get_for_bus_sync: function(bus_type: TGBusType; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; g_dbus_address_get_stream: procedure(address: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_address_get_stream_finish: function(res: PGAsyncResult; out_guid: PPgchar; error: PPGError): PGIOStream; cdecl; g_dbus_address_get_stream_sync: function(address: Pgchar; out_guid: PPgchar; cancellable: PGCancellable; error: PPGError): PGIOStream; cdecl; g_dbus_annotation_info_get_type: function:TGType; cdecl; g_dbus_annotation_info_lookup: function(annotations: PPGDBusAnnotationInfo; name: Pgchar): Pgchar; cdecl; g_dbus_annotation_info_ref: function(info: PGDBusAnnotationInfo): PGDBusAnnotationInfo; cdecl; g_dbus_annotation_info_unref: procedure(info: PGDBusAnnotationInfo); cdecl; g_dbus_arg_info_get_type: function:TGType; cdecl; g_dbus_arg_info_ref: function(info: PGDBusArgInfo): PGDBusArgInfo; cdecl; g_dbus_arg_info_unref: procedure(info: PGDBusArgInfo); cdecl; g_dbus_auth_observer_allow_mechanism: function(observer: PGDBusAuthObserver; mechanism: Pgchar): gboolean; cdecl; g_dbus_auth_observer_authorize_authenticated_peer: function(observer: PGDBusAuthObserver; stream: PGIOStream; credentials: PGCredentials): gboolean; cdecl; g_dbus_auth_observer_get_type: function:TGType; cdecl; g_dbus_auth_observer_new: function: PGDBusAuthObserver; cdecl; g_dbus_connection_add_filter: function(connection: PGDBusConnection; filter_function: TGDBusMessageFilterFunction; user_data: gpointer; user_data_free_func: TGDestroyNotify): guint; cdecl; g_dbus_connection_call: procedure(connection: PGDBusConnection; bus_name: Pgchar; object_path: Pgchar; interface_name: Pgchar; method_name: Pgchar; parameters: PGVariant; reply_type: PGVariantType; flags: TGDBusCallFlags; timeout_msec: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_call_finish: function(connection: PGDBusConnection; res: PGAsyncResult; error: PPGError): PGVariant; cdecl; g_dbus_connection_call_sync: function(connection: PGDBusConnection; bus_name: Pgchar; object_path: Pgchar; interface_name: Pgchar; method_name: Pgchar; parameters: PGVariant; reply_type: PGVariantType; flags: TGDBusCallFlags; timeout_msec: gint; cancellable: PGCancellable; error: PPGError): PGVariant; cdecl; g_dbus_connection_call_with_unix_fd_list: procedure(connection: PGDBusConnection; bus_name: Pgchar; object_path: Pgchar; interface_name: Pgchar; method_name: Pgchar; parameters: PGVariant; reply_type: PGVariantType; flags: TGDBusCallFlags; timeout_msec: gint; fd_list: PGUnixFDList; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_call_with_unix_fd_list_finish: function(connection: PGDBusConnection; out_fd_list: PPGUnixFDList; res: PGAsyncResult; error: PPGError): PGVariant; cdecl; g_dbus_connection_call_with_unix_fd_list_sync: function(connection: PGDBusConnection; bus_name: Pgchar; object_path: Pgchar; interface_name: Pgchar; method_name: Pgchar; parameters: PGVariant; reply_type: PGVariantType; flags: TGDBusCallFlags; timeout_msec: gint; fd_list: PGUnixFDList; out_fd_list: PPGUnixFDList; cancellable: PGCancellable; error: PPGError): PGVariant; cdecl; g_dbus_connection_close: procedure(connection: PGDBusConnection; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_close_finish: function(connection: PGDBusConnection; res: PGAsyncResult; error: PPGError): gboolean; cdecl; g_dbus_connection_close_sync: function(connection: PGDBusConnection; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_dbus_connection_emit_signal: function(connection: PGDBusConnection; destination_bus_name: Pgchar; object_path: Pgchar; interface_name: Pgchar; signal_name: Pgchar; parameters: PGVariant; error: PPGError): gboolean; cdecl; g_dbus_connection_export_action_group: function(connection: PGDBusConnection; object_path: Pgchar; action_group: PGActionGroup; error: PPGError): guint; cdecl; g_dbus_connection_export_menu_model: function(connection: PGDBusConnection; object_path: Pgchar; menu: PGMenuModel; error: PPGError): guint; cdecl; g_dbus_connection_flush: procedure(connection: PGDBusConnection; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_flush_finish: function(connection: PGDBusConnection; res: PGAsyncResult; error: PPGError): gboolean; cdecl; g_dbus_connection_flush_sync: function(connection: PGDBusConnection; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_dbus_connection_get_capabilities: function(connection: PGDBusConnection): TGDBusCapabilityFlags; cdecl; g_dbus_connection_get_exit_on_close: function(connection: PGDBusConnection): gboolean; cdecl; g_dbus_connection_get_guid: function(connection: PGDBusConnection): Pgchar; cdecl; g_dbus_connection_get_last_serial: function(connection: PGDBusConnection): guint32; cdecl; g_dbus_connection_get_peer_credentials: function(connection: PGDBusConnection): PGCredentials; cdecl; g_dbus_connection_get_stream: function(connection: PGDBusConnection): PGIOStream; cdecl; g_dbus_connection_get_type: function:TGType; cdecl; g_dbus_connection_get_unique_name: function(connection: PGDBusConnection): Pgchar; cdecl; g_dbus_connection_is_closed: function(connection: PGDBusConnection): gboolean; cdecl; g_dbus_connection_new: procedure(stream: PGIOStream; guid: Pgchar; flags: TGDBusConnectionFlags; observer: PGDBusAuthObserver; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_new_finish: function(res: PGAsyncResult; error: PPGError): PGDBusConnection; cdecl; g_dbus_connection_new_for_address: procedure(address: Pgchar; flags: TGDBusConnectionFlags; observer: PGDBusAuthObserver; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_new_for_address_finish: function(res: PGAsyncResult; error: PPGError): PGDBusConnection; cdecl; g_dbus_connection_new_for_address_sync: function(address: Pgchar; flags: TGDBusConnectionFlags; observer: PGDBusAuthObserver; cancellable: PGCancellable; error: PPGError): PGDBusConnection; cdecl; g_dbus_connection_new_sync: function(stream: PGIOStream; guid: Pgchar; flags: TGDBusConnectionFlags; observer: PGDBusAuthObserver; cancellable: PGCancellable; error: PPGError): PGDBusConnection; cdecl; g_dbus_connection_register_object: function(connection: PGDBusConnection; object_path: Pgchar; interface_info: PGDBusInterfaceInfo; vtable: PGDBusInterfaceVTable; user_data: gpointer; user_data_free_func: TGDestroyNotify; error: PPGError): guint; cdecl; g_dbus_connection_register_subtree: function(connection: PGDBusConnection; object_path: Pgchar; vtable: PGDBusSubtreeVTable; flags: TGDBusSubtreeFlags; user_data: gpointer; user_data_free_func: TGDestroyNotify; error: PPGError): guint; cdecl; g_dbus_connection_remove_filter: procedure(connection: PGDBusConnection; filter_id: guint); cdecl; g_dbus_connection_send_message: function(connection: PGDBusConnection; message: PGDBusMessage; flags: TGDBusSendMessageFlags; out_serial: Pguint32; error: PPGError): gboolean; cdecl; g_dbus_connection_send_message_with_reply: procedure(connection: PGDBusConnection; message: PGDBusMessage; flags: TGDBusSendMessageFlags; timeout_msec: gint; out_serial: Pguint32; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_connection_send_message_with_reply_finish: function(connection: PGDBusConnection; res: PGAsyncResult; error: PPGError): PGDBusMessage; cdecl; g_dbus_connection_send_message_with_reply_sync: function(connection: PGDBusConnection; message: PGDBusMessage; flags: TGDBusSendMessageFlags; timeout_msec: gint; out_serial: Pguint32; cancellable: PGCancellable; error: PPGError): PGDBusMessage; cdecl; g_dbus_connection_set_exit_on_close: procedure(connection: PGDBusConnection; exit_on_close: gboolean); cdecl; g_dbus_connection_signal_subscribe: function(connection: PGDBusConnection; sender: Pgchar; interface_name: Pgchar; member: Pgchar; object_path: Pgchar; arg0: Pgchar; flags: TGDBusSignalFlags; callback: TGDBusSignalCallback; user_data: gpointer; user_data_free_func: TGDestroyNotify): guint; cdecl; g_dbus_connection_signal_unsubscribe: procedure(connection: PGDBusConnection; subscription_id: guint); cdecl; g_dbus_connection_start_message_processing: procedure(connection: PGDBusConnection); cdecl; g_dbus_connection_unexport_action_group: procedure(connection: PGDBusConnection; export_id: guint); cdecl; g_dbus_connection_unexport_menu_model: procedure(connection: PGDBusConnection; export_id: guint); cdecl; g_dbus_connection_unregister_object: function(connection: PGDBusConnection; registration_id: guint): gboolean; cdecl; g_dbus_connection_unregister_subtree: function(connection: PGDBusConnection; registration_id: guint): gboolean; cdecl; g_dbus_error_encode_gerror: function(error: PGError): Pgchar; cdecl; g_dbus_error_get_remote_error: function(error: PGError): Pgchar; cdecl; g_dbus_error_is_remote_error: function(error: PGError): gboolean; cdecl; g_dbus_error_new_for_dbus_error: function(dbus_error_name: Pgchar; dbus_error_message: Pgchar): PGError; cdecl; g_dbus_error_quark: function: TGQuark; cdecl; g_dbus_error_register_error: function(error_domain: TGQuark; error_code: gint; dbus_error_name: Pgchar): gboolean; cdecl; g_dbus_error_register_error_domain: procedure(error_domain_quark_name: Pgchar; quark_volatile: Pgsize; entries: PGDBusErrorEntry; num_entries: guint); cdecl; g_dbus_error_set_dbus_error: procedure(error: PPGError; dbus_error_name: Pgchar; dbus_error_message: Pgchar; format: Pgchar; args: array of const); cdecl; g_dbus_error_set_dbus_error_valist: procedure(error: PPGError; dbus_error_name: Pgchar; dbus_error_message: Pgchar; format: Pgchar; var_args: Tva_list); cdecl; g_dbus_error_strip_remote_error: function(error: PGError): gboolean; cdecl; g_dbus_error_unregister_error: function(error_domain: TGQuark; error_code: gint; dbus_error_name: Pgchar): gboolean; cdecl; g_dbus_generate_guid: function: Pgchar; cdecl; g_dbus_gvalue_to_gvariant: function(gvalue: PGValue; type_: PGVariantType): PGVariant; cdecl; g_dbus_gvariant_to_gvalue: procedure(value: PGVariant; out_gvalue: PGValue); cdecl; g_dbus_interface_dup_object: function(interface_: PGDBusInterface): PGDBusObject; cdecl; g_dbus_interface_get_info: function(interface_: PGDBusInterface): PGDBusInterfaceInfo; cdecl; g_dbus_interface_get_object: function(interface_: PGDBusInterface): PGDBusObject; cdecl; g_dbus_interface_get_type: function:TGType; cdecl; g_dbus_interface_info_cache_build: procedure(info: PGDBusInterfaceInfo); cdecl; g_dbus_interface_info_cache_release: procedure(info: PGDBusInterfaceInfo); cdecl; g_dbus_interface_info_generate_xml: procedure(info: PGDBusInterfaceInfo; indent: guint; string_builder: PGString); cdecl; g_dbus_interface_info_get_type: function:TGType; cdecl; g_dbus_interface_info_lookup_method: function(info: PGDBusInterfaceInfo; name: Pgchar): PGDBusMethodInfo; cdecl; g_dbus_interface_info_lookup_property: function(info: PGDBusInterfaceInfo; name: Pgchar): PGDBusPropertyInfo; cdecl; g_dbus_interface_info_lookup_signal: function(info: PGDBusInterfaceInfo; name: Pgchar): PGDBusSignalInfo; cdecl; g_dbus_interface_info_ref: function(info: PGDBusInterfaceInfo): PGDBusInterfaceInfo; cdecl; g_dbus_interface_info_unref: procedure(info: PGDBusInterfaceInfo); cdecl; g_dbus_interface_set_object: procedure(interface_: PGDBusInterface; object_: PGDBusObject); cdecl; g_dbus_interface_skeleton_export: function(interface_: PGDBusInterfaceSkeleton; connection: PGDBusConnection; object_path: Pgchar; error: PPGError): gboolean; cdecl; g_dbus_interface_skeleton_flush: procedure(interface_: PGDBusInterfaceSkeleton); cdecl; g_dbus_interface_skeleton_get_connection: function(interface_: PGDBusInterfaceSkeleton): PGDBusConnection; cdecl; g_dbus_interface_skeleton_get_connections: function(interface_: PGDBusInterfaceSkeleton): PGList; cdecl; g_dbus_interface_skeleton_get_flags: function(interface_: PGDBusInterfaceSkeleton): TGDBusInterfaceSkeletonFlags; cdecl; g_dbus_interface_skeleton_get_info: function(interface_: PGDBusInterfaceSkeleton): PGDBusInterfaceInfo; cdecl; g_dbus_interface_skeleton_get_object_path: function(interface_: PGDBusInterfaceSkeleton): Pgchar; cdecl; g_dbus_interface_skeleton_get_properties: function(interface_: PGDBusInterfaceSkeleton): PGVariant; cdecl; g_dbus_interface_skeleton_get_type: function:TGType; cdecl; g_dbus_interface_skeleton_get_vtable: function(interface_: PGDBusInterfaceSkeleton): PGDBusInterfaceVTable; cdecl; g_dbus_interface_skeleton_has_connection: function(interface_: PGDBusInterfaceSkeleton; connection: PGDBusConnection): gboolean; cdecl; g_dbus_interface_skeleton_set_flags: procedure(interface_: PGDBusInterfaceSkeleton; flags: TGDBusInterfaceSkeletonFlags); cdecl; g_dbus_interface_skeleton_unexport: procedure(interface_: PGDBusInterfaceSkeleton); cdecl; g_dbus_interface_skeleton_unexport_from_connection: procedure(interface_: PGDBusInterfaceSkeleton; connection: PGDBusConnection); cdecl; g_dbus_is_address: function(string_: Pgchar): gboolean; cdecl; g_dbus_is_guid: function(string_: Pgchar): gboolean; cdecl; g_dbus_is_interface_name: function(string_: Pgchar): gboolean; cdecl; g_dbus_is_member_name: function(string_: Pgchar): gboolean; cdecl; g_dbus_is_name: function(string_: Pgchar): gboolean; cdecl; g_dbus_is_supported_address: function(string_: Pgchar; error: PPGError): gboolean; cdecl; g_dbus_is_unique_name: function(string_: Pgchar): gboolean; cdecl; g_dbus_menu_model_get: function(connection: PGDBusConnection; bus_name: Pgchar; object_path: Pgchar): PGDBusMenuModel; cdecl; g_dbus_menu_model_get_type: function:TGType; cdecl; g_dbus_message_bytes_needed: function(blob: Pguint8; blob_len: gsize; error: PPGError): gssize; cdecl; g_dbus_message_copy: function(message: PGDBusMessage; error: PPGError): PGDBusMessage; cdecl; g_dbus_message_get_arg0: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_body: function(message: PGDBusMessage): PGVariant; cdecl; g_dbus_message_get_byte_order: function(message: PGDBusMessage): TGDBusMessageByteOrder; cdecl; g_dbus_message_get_destination: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_error_name: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_flags: function(message: PGDBusMessage): TGDBusMessageFlags; cdecl; g_dbus_message_get_header: function(message: PGDBusMessage; header_field: TGDBusMessageHeaderField): PGVariant; cdecl; g_dbus_message_get_header_fields: function(message: PGDBusMessage): Pguint8; cdecl; g_dbus_message_get_interface: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_locked: function(message: PGDBusMessage): gboolean; cdecl; g_dbus_message_get_member: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_message_type: function(message: PGDBusMessage): TGDBusMessageType; cdecl; g_dbus_message_get_num_unix_fds: function(message: PGDBusMessage): guint32; cdecl; g_dbus_message_get_path: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_reply_serial: function(message: PGDBusMessage): guint32; cdecl; g_dbus_message_get_sender: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_serial: function(message: PGDBusMessage): guint32; cdecl; g_dbus_message_get_signature: function(message: PGDBusMessage): Pgchar; cdecl; g_dbus_message_get_type: function:TGType; cdecl; g_dbus_message_get_unix_fd_list: function(message: PGDBusMessage): PGUnixFDList; cdecl; g_dbus_message_lock: procedure(message: PGDBusMessage); cdecl; g_dbus_message_new: function: PGDBusMessage; cdecl; g_dbus_message_new_from_blob: function(blob: Pguint8; blob_len: gsize; capabilities: TGDBusCapabilityFlags; error: PPGError): PGDBusMessage; cdecl; g_dbus_message_new_method_call: function(name: Pgchar; path: Pgchar; interface_: Pgchar; method: Pgchar): PGDBusMessage; cdecl; g_dbus_message_new_method_error: function(method_call_message: PGDBusMessage; error_name: Pgchar; error_message_format: Pgchar; args: array of const): PGDBusMessage; cdecl; g_dbus_message_new_method_error_literal: function(method_call_message: PGDBusMessage; error_name: Pgchar; error_message: Pgchar): PGDBusMessage; cdecl; g_dbus_message_new_method_error_valist: function(method_call_message: PGDBusMessage; error_name: Pgchar; error_message_format: Pgchar; var_args: Tva_list): PGDBusMessage; cdecl; g_dbus_message_new_method_reply: function(method_call_message: PGDBusMessage): PGDBusMessage; cdecl; g_dbus_message_new_signal: function(path: Pgchar; interface_: Pgchar; signal: Pgchar): PGDBusMessage; cdecl; g_dbus_message_print: function(message: PGDBusMessage; indent: guint): Pgchar; cdecl; g_dbus_message_set_body: procedure(message: PGDBusMessage; body: PGVariant); cdecl; g_dbus_message_set_byte_order: procedure(message: PGDBusMessage; byte_order: TGDBusMessageByteOrder); cdecl; g_dbus_message_set_destination: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_error_name: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_flags: procedure(message: PGDBusMessage; flags: TGDBusMessageFlags); cdecl; g_dbus_message_set_header: procedure(message: PGDBusMessage; header_field: TGDBusMessageHeaderField; value: PGVariant); cdecl; g_dbus_message_set_interface: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_member: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_message_type: procedure(message: PGDBusMessage; type_: TGDBusMessageType); cdecl; g_dbus_message_set_num_unix_fds: procedure(message: PGDBusMessage; value: guint32); cdecl; g_dbus_message_set_path: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_reply_serial: procedure(message: PGDBusMessage; value: guint32); cdecl; g_dbus_message_set_sender: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_serial: procedure(message: PGDBusMessage; serial: guint32); cdecl; g_dbus_message_set_signature: procedure(message: PGDBusMessage; value: Pgchar); cdecl; g_dbus_message_set_unix_fd_list: procedure(message: PGDBusMessage; fd_list: PGUnixFDList); cdecl; g_dbus_message_to_blob: function(message: PGDBusMessage; out_size: Pgsize; capabilities: TGDBusCapabilityFlags; error: PPGError): Pguint8; cdecl; g_dbus_message_to_gerror: function(message: PGDBusMessage; error: PPGError): gboolean; cdecl; g_dbus_method_info_get_type: function:TGType; cdecl; g_dbus_method_info_ref: function(info: PGDBusMethodInfo): PGDBusMethodInfo; cdecl; g_dbus_method_info_unref: procedure(info: PGDBusMethodInfo); cdecl; g_dbus_method_invocation_get_connection: function(invocation: PGDBusMethodInvocation): PGDBusConnection; cdecl; g_dbus_method_invocation_get_interface_name: function(invocation: PGDBusMethodInvocation): Pgchar; cdecl; g_dbus_method_invocation_get_message: function(invocation: PGDBusMethodInvocation): PGDBusMessage; cdecl; g_dbus_method_invocation_get_method_info: function(invocation: PGDBusMethodInvocation): PGDBusMethodInfo; cdecl; g_dbus_method_invocation_get_method_name: function(invocation: PGDBusMethodInvocation): Pgchar; cdecl; g_dbus_method_invocation_get_object_path: function(invocation: PGDBusMethodInvocation): Pgchar; cdecl; g_dbus_method_invocation_get_parameters: function(invocation: PGDBusMethodInvocation): PGVariant; cdecl; g_dbus_method_invocation_get_sender: function(invocation: PGDBusMethodInvocation): Pgchar; cdecl; g_dbus_method_invocation_get_type: function:TGType; cdecl; g_dbus_method_invocation_get_user_data: function(invocation: PGDBusMethodInvocation): gpointer; cdecl; g_dbus_method_invocation_return_dbus_error: procedure(invocation: PGDBusMethodInvocation; error_name: Pgchar; error_message: Pgchar); cdecl; g_dbus_method_invocation_return_error: procedure(invocation: PGDBusMethodInvocation; domain: TGQuark; code: gint; format: Pgchar; args: array of const); cdecl; g_dbus_method_invocation_return_error_literal: procedure(invocation: PGDBusMethodInvocation; domain: TGQuark; code: gint; message: Pgchar); cdecl; g_dbus_method_invocation_return_error_valist: procedure(invocation: PGDBusMethodInvocation; domain: TGQuark; code: gint; format: Pgchar; var_args: Tva_list); cdecl; g_dbus_method_invocation_return_gerror: procedure(invocation: PGDBusMethodInvocation; error: PGError); cdecl; g_dbus_method_invocation_return_value: procedure(invocation: PGDBusMethodInvocation; parameters: PGVariant); cdecl; g_dbus_method_invocation_return_value_with_unix_fd_list: procedure(invocation: PGDBusMethodInvocation; parameters: PGVariant; fd_list: PGUnixFDList); cdecl; g_dbus_method_invocation_take_error: procedure(invocation: PGDBusMethodInvocation; error: PGError); cdecl; g_dbus_node_info_generate_xml: procedure(info: PGDBusNodeInfo; indent: guint; string_builder: PGString); cdecl; g_dbus_node_info_get_type: function:TGType; cdecl; g_dbus_node_info_lookup_interface: function(info: PGDBusNodeInfo; name: Pgchar): PGDBusInterfaceInfo; cdecl; g_dbus_node_info_new_for_xml: function(xml_data: Pgchar; error: PPGError): PGDBusNodeInfo; cdecl; g_dbus_node_info_ref: function(info: PGDBusNodeInfo): PGDBusNodeInfo; cdecl; g_dbus_node_info_unref: procedure(info: PGDBusNodeInfo); cdecl; g_dbus_object_get_interface: function(object_: PGDBusObject; interface_name: Pgchar): PGDBusInterface; cdecl; g_dbus_object_get_interfaces: function(object_: PGDBusObject): PGList; cdecl; g_dbus_object_get_object_path: function(object_: PGDBusObject): Pgchar; cdecl; g_dbus_object_get_type: function:TGType; cdecl; g_dbus_object_manager_client_get_connection: function(manager: PGDBusObjectManagerClient): PGDBusConnection; cdecl; g_dbus_object_manager_client_get_flags: function(manager: PGDBusObjectManagerClient): TGDBusObjectManagerClientFlags; cdecl; g_dbus_object_manager_client_get_name: function(manager: PGDBusObjectManagerClient): Pgchar; cdecl; g_dbus_object_manager_client_get_name_owner: function(manager: PGDBusObjectManagerClient): Pgchar; cdecl; g_dbus_object_manager_client_get_type: function:TGType; cdecl; g_dbus_object_manager_client_new: procedure(connection: PGDBusConnection; flags: TGDBusObjectManagerClientFlags; name: Pgchar; object_path: Pgchar; get_proxy_type_func: TGDBusProxyTypeFunc; get_proxy_type_user_data: gpointer; get_proxy_type_destroy_notify: TGDestroyNotify; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_object_manager_client_new_finish: function(res: PGAsyncResult; error: PPGError): PGDBusObjectManagerClient; cdecl; g_dbus_object_manager_client_new_for_bus: procedure(bus_type: TGBusType; flags: TGDBusObjectManagerClientFlags; name: Pgchar; object_path: Pgchar; get_proxy_type_func: TGDBusProxyTypeFunc; get_proxy_type_user_data: gpointer; get_proxy_type_destroy_notify: TGDestroyNotify; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_object_manager_client_new_for_bus_finish: function(res: PGAsyncResult; error: PPGError): PGDBusObjectManagerClient; cdecl; g_dbus_object_manager_client_new_for_bus_sync: function(bus_type: TGBusType; flags: TGDBusObjectManagerClientFlags; name: Pgchar; object_path: Pgchar; get_proxy_type_func: TGDBusProxyTypeFunc; get_proxy_type_user_data: gpointer; get_proxy_type_destroy_notify: TGDestroyNotify; cancellable: PGCancellable; error: PPGError): PGDBusObjectManagerClient; cdecl; g_dbus_object_manager_client_new_sync: function(connection: PGDBusConnection; flags: TGDBusObjectManagerClientFlags; name: Pgchar; object_path: Pgchar; get_proxy_type_func: TGDBusProxyTypeFunc; get_proxy_type_user_data: gpointer; get_proxy_type_destroy_notify: TGDestroyNotify; cancellable: PGCancellable; error: PPGError): PGDBusObjectManagerClient; cdecl; g_dbus_object_manager_get_interface: function(manager: PGDBusObjectManager; object_path: Pgchar; interface_name: Pgchar): PGDBusInterface; cdecl; g_dbus_object_manager_get_object: function(manager: PGDBusObjectManager; object_path: Pgchar): PGDBusObject; cdecl; g_dbus_object_manager_get_object_path: function(manager: PGDBusObjectManager): Pgchar; cdecl; g_dbus_object_manager_get_objects: function(manager: PGDBusObjectManager): PGList; cdecl; g_dbus_object_manager_get_type: function:TGType; cdecl; g_dbus_object_manager_server_export: procedure(manager: PGDBusObjectManagerServer; object_: PGDBusObjectSkeleton); cdecl; g_dbus_object_manager_server_export_uniquely: procedure(manager: PGDBusObjectManagerServer; object_: PGDBusObjectSkeleton); cdecl; g_dbus_object_manager_server_get_connection: function(manager: PGDBusObjectManagerServer): PGDBusConnection; cdecl; g_dbus_object_manager_server_get_type: function:TGType; cdecl; g_dbus_object_manager_server_is_exported: function(manager: PGDBusObjectManagerServer; object_: PGDBusObjectSkeleton): gboolean; cdecl; g_dbus_object_manager_server_new: function(object_path: Pgchar): PGDBusObjectManagerServer; cdecl; g_dbus_object_manager_server_set_connection: procedure(manager: PGDBusObjectManagerServer; connection: PGDBusConnection); cdecl; g_dbus_object_manager_server_unexport: function(manager: PGDBusObjectManagerServer; object_path: Pgchar): gboolean; cdecl; g_dbus_object_proxy_get_connection: function(proxy: PGDBusObjectProxy): PGDBusConnection; cdecl; g_dbus_object_proxy_get_type: function:TGType; cdecl; g_dbus_object_proxy_new: function(connection: PGDBusConnection; object_path: Pgchar): PGDBusObjectProxy; cdecl; g_dbus_object_skeleton_add_interface: procedure(object_: PGDBusObjectSkeleton; interface_: PGDBusInterfaceSkeleton); cdecl; g_dbus_object_skeleton_flush: procedure(object_: PGDBusObjectSkeleton); cdecl; g_dbus_object_skeleton_get_type: function:TGType; cdecl; g_dbus_object_skeleton_new: function(object_path: Pgchar): PGDBusObjectSkeleton; cdecl; g_dbus_object_skeleton_remove_interface: procedure(object_: PGDBusObjectSkeleton; interface_: PGDBusInterfaceSkeleton); cdecl; g_dbus_object_skeleton_remove_interface_by_name: procedure(object_: PGDBusObjectSkeleton; interface_name: Pgchar); cdecl; g_dbus_object_skeleton_set_object_path: procedure(object_: PGDBusObjectSkeleton; object_path: Pgchar); cdecl; g_dbus_property_info_get_type: function:TGType; cdecl; g_dbus_property_info_ref: function(info: PGDBusPropertyInfo): PGDBusPropertyInfo; cdecl; g_dbus_property_info_unref: procedure(info: PGDBusPropertyInfo); cdecl; g_dbus_proxy_call: procedure(proxy: PGDBusProxy; method_name: Pgchar; parameters: PGVariant; flags: TGDBusCallFlags; timeout_msec: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_proxy_call_finish: function(proxy: PGDBusProxy; res: PGAsyncResult; error: PPGError): PGVariant; cdecl; g_dbus_proxy_call_sync: function(proxy: PGDBusProxy; method_name: Pgchar; parameters: PGVariant; flags: TGDBusCallFlags; timeout_msec: gint; cancellable: PGCancellable; error: PPGError): PGVariant; cdecl; g_dbus_proxy_call_with_unix_fd_list: procedure(proxy: PGDBusProxy; method_name: Pgchar; parameters: PGVariant; flags: TGDBusCallFlags; timeout_msec: gint; fd_list: PGUnixFDList; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_proxy_call_with_unix_fd_list_finish: function(proxy: PGDBusProxy; out_fd_list: PPGUnixFDList; res: PGAsyncResult; error: PPGError): PGVariant; cdecl; g_dbus_proxy_call_with_unix_fd_list_sync: function(proxy: PGDBusProxy; method_name: Pgchar; parameters: PGVariant; flags: TGDBusCallFlags; timeout_msec: gint; fd_list: PGUnixFDList; out_fd_list: PPGUnixFDList; cancellable: PGCancellable; error: PPGError): PGVariant; cdecl; g_dbus_proxy_get_cached_property: function(proxy: PGDBusProxy; property_name: Pgchar): PGVariant; cdecl; g_dbus_proxy_get_cached_property_names: function(proxy: PGDBusProxy): PPgchar; cdecl; g_dbus_proxy_get_connection: function(proxy: PGDBusProxy): PGDBusConnection; cdecl; g_dbus_proxy_get_default_timeout: function(proxy: PGDBusProxy): gint; cdecl; g_dbus_proxy_get_flags: function(proxy: PGDBusProxy): TGDBusProxyFlags; cdecl; g_dbus_proxy_get_interface_info: function(proxy: PGDBusProxy): PGDBusInterfaceInfo; cdecl; g_dbus_proxy_get_interface_name: function(proxy: PGDBusProxy): Pgchar; cdecl; g_dbus_proxy_get_name: function(proxy: PGDBusProxy): Pgchar; cdecl; g_dbus_proxy_get_name_owner: function(proxy: PGDBusProxy): Pgchar; cdecl; g_dbus_proxy_get_object_path: function(proxy: PGDBusProxy): Pgchar; cdecl; g_dbus_proxy_get_type: function:TGType; cdecl; g_dbus_proxy_new: procedure(connection: PGDBusConnection; flags: TGDBusProxyFlags; info: PGDBusInterfaceInfo; name: Pgchar; object_path: Pgchar; interface_name: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_proxy_new_finish: function(res: PGAsyncResult; error: PPGError): PGDBusProxy; cdecl; g_dbus_proxy_new_for_bus: procedure(bus_type: TGBusType; flags: TGDBusProxyFlags; info: PGDBusInterfaceInfo; name: Pgchar; object_path: Pgchar; interface_name: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_dbus_proxy_new_for_bus_finish: function(res: PGAsyncResult; error: PPGError): PGDBusProxy; cdecl; g_dbus_proxy_new_for_bus_sync: function(bus_type: TGBusType; flags: TGDBusProxyFlags; info: PGDBusInterfaceInfo; name: Pgchar; object_path: Pgchar; interface_name: Pgchar; cancellable: PGCancellable; error: PPGError): PGDBusProxy; cdecl; g_dbus_proxy_new_sync: function(connection: PGDBusConnection; flags: TGDBusProxyFlags; info: PGDBusInterfaceInfo; name: Pgchar; object_path: Pgchar; interface_name: Pgchar; cancellable: PGCancellable; error: PPGError): PGDBusProxy; cdecl; g_dbus_proxy_set_cached_property: procedure(proxy: PGDBusProxy; property_name: Pgchar; value: PGVariant); cdecl; g_dbus_proxy_set_default_timeout: procedure(proxy: PGDBusProxy; timeout_msec: gint); cdecl; g_dbus_proxy_set_interface_info: procedure(proxy: PGDBusProxy; info: PGDBusInterfaceInfo); cdecl; g_dbus_server_get_client_address: function(server: PGDBusServer): Pgchar; cdecl; g_dbus_server_get_flags: function(server: PGDBusServer): TGDBusServerFlags; cdecl; g_dbus_server_get_guid: function(server: PGDBusServer): Pgchar; cdecl; g_dbus_server_get_type: function:TGType; cdecl; g_dbus_server_is_active: function(server: PGDBusServer): gboolean; cdecl; g_dbus_server_new_sync: function(address: Pgchar; flags: TGDBusServerFlags; guid: Pgchar; observer: PGDBusAuthObserver; cancellable: PGCancellable; error: PPGError): PGDBusServer; cdecl; g_dbus_server_start: procedure(server: PGDBusServer); cdecl; g_dbus_server_stop: procedure(server: PGDBusServer); cdecl; g_dbus_signal_info_get_type: function:TGType; cdecl; g_dbus_signal_info_ref: function(info: PGDBusSignalInfo): PGDBusSignalInfo; cdecl; g_dbus_signal_info_unref: procedure(info: PGDBusSignalInfo); cdecl; g_desktop_app_info_get_boolean: function(info: PGDesktopAppInfo; key: Pgchar): gboolean; cdecl; g_desktop_app_info_get_categories: function(info: PGDesktopAppInfo): Pgchar; cdecl; g_desktop_app_info_get_filename: function(info: PGDesktopAppInfo): Pgchar; cdecl; g_desktop_app_info_get_generic_name: function(info: PGDesktopAppInfo): Pgchar; cdecl; g_desktop_app_info_get_is_hidden: function(info: PGDesktopAppInfo): gboolean; cdecl; g_desktop_app_info_get_keywords: function(info: PGDesktopAppInfo): PPgchar; cdecl; g_desktop_app_info_get_nodisplay: function(info: PGDesktopAppInfo): gboolean; cdecl; g_desktop_app_info_get_show_in: function(info: PGDesktopAppInfo; desktop_env: Pgchar): gboolean; cdecl; g_desktop_app_info_get_startup_wm_class: function(info: PGDesktopAppInfo): Pgchar; cdecl; g_desktop_app_info_get_string: function(info: PGDesktopAppInfo; key: Pgchar): Pgchar; cdecl; g_desktop_app_info_get_type: function:TGType; cdecl; g_desktop_app_info_has_key: function(info: PGDesktopAppInfo; key: Pgchar): gboolean; cdecl; g_desktop_app_info_launch_uris_as_manager: function(appinfo: PGDesktopAppInfo; uris: PGList; launch_context: PGAppLaunchContext; spawn_flags: TGSpawnFlags; user_setup: TGSpawnChildSetupFunc; user_setup_data: gpointer; pid_callback: TGDesktopAppLaunchCallback; pid_callback_data: gpointer; error: PPGError): gboolean; cdecl; g_desktop_app_info_lookup_get_type: function:TGType; cdecl; g_desktop_app_info_new: function(desktop_id: Pgchar): PGDesktopAppInfo; cdecl; g_desktop_app_info_new_from_filename: function(filename: Pgchar): PGDesktopAppInfo; cdecl; g_desktop_app_info_new_from_keyfile: function(key_file: PGKeyFile): PGDesktopAppInfo; cdecl; g_desktop_app_info_set_desktop_env: procedure(desktop_env: Pgchar); cdecl; g_drive_can_eject: function(drive: PGDrive): gboolean; cdecl; g_drive_can_poll_for_media: function(drive: PGDrive): gboolean; cdecl; g_drive_can_start: function(drive: PGDrive): gboolean; cdecl; g_drive_can_start_degraded: function(drive: PGDrive): gboolean; cdecl; g_drive_can_stop: function(drive: PGDrive): gboolean; cdecl; g_drive_eject_with_operation: procedure(drive: PGDrive; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_drive_eject_with_operation_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_drive_enumerate_identifiers: function(drive: PGDrive): PPgchar; cdecl; g_drive_get_icon: function(drive: PGDrive): PGIcon; cdecl; g_drive_get_identifier: function(drive: PGDrive; kind: Pgchar): Pgchar; cdecl; g_drive_get_name: function(drive: PGDrive): Pgchar; cdecl; g_drive_get_sort_key: function(drive: PGDrive): Pgchar; cdecl; g_drive_get_start_stop_type: function(drive: PGDrive): TGDriveStartStopType; cdecl; g_drive_get_symbolic_icon: function(drive: PGDrive): PGIcon; cdecl; g_drive_get_type: function:TGType; cdecl; g_drive_get_volumes: function(drive: PGDrive): PGList; cdecl; g_drive_has_media: function(drive: PGDrive): gboolean; cdecl; g_drive_has_volumes: function(drive: PGDrive): gboolean; cdecl; g_drive_is_media_check_automatic: function(drive: PGDrive): gboolean; cdecl; g_drive_is_media_removable: function(drive: PGDrive): gboolean; cdecl; g_drive_poll_for_media: procedure(drive: PGDrive; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_drive_poll_for_media_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_drive_start: procedure(drive: PGDrive; flags: TGDriveStartFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_drive_start_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_drive_stop: procedure(drive: PGDrive; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_drive_stop_finish: function(drive: PGDrive; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_emblem_get_icon: function(emblem: PGEmblem): PGIcon; cdecl; g_emblem_get_origin: function(emblem: PGEmblem): TGEmblemOrigin; cdecl; g_emblem_get_type: function:TGType; cdecl; g_emblem_new: function(icon: PGIcon): PGEmblem; cdecl; g_emblem_new_with_origin: function(icon: PGIcon; origin: TGEmblemOrigin): PGEmblem; cdecl; g_emblemed_icon_add_emblem: procedure(emblemed: PGEmblemedIcon; emblem: PGEmblem); cdecl; g_emblemed_icon_clear_emblems: procedure(emblemed: PGEmblemedIcon); cdecl; g_emblemed_icon_get_emblems: function(emblemed: PGEmblemedIcon): PGList; cdecl; g_emblemed_icon_get_icon: function(emblemed: PGEmblemedIcon): PGIcon; cdecl; g_emblemed_icon_get_type: function:TGType; cdecl; g_emblemed_icon_new: function(icon: PGIcon; emblem: PGEmblem): PGEmblemedIcon; cdecl; g_file_append_to: function(file_: PGFile; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileOutputStream; cdecl; g_file_append_to_async: procedure(file_: PGFile; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_append_to_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileOutputStream; cdecl; g_file_attribute_info_list_add: procedure(list: PGFileAttributeInfoList; name: Pgchar; type_: TGFileAttributeType; flags: TGFileAttributeInfoFlags); cdecl; g_file_attribute_info_list_dup: function(list: PGFileAttributeInfoList): PGFileAttributeInfoList; cdecl; g_file_attribute_info_list_get_type: function:TGType; cdecl; g_file_attribute_info_list_lookup: function(list: PGFileAttributeInfoList; name: Pgchar): PGFileAttributeInfo; cdecl; g_file_attribute_info_list_new: function: PGFileAttributeInfoList; cdecl; g_file_attribute_info_list_ref: function(list: PGFileAttributeInfoList): PGFileAttributeInfoList; cdecl; g_file_attribute_info_list_unref: procedure(list: PGFileAttributeInfoList); cdecl; g_file_attribute_matcher_enumerate_namespace: function(matcher: PGFileAttributeMatcher; ns: Pgchar): gboolean; cdecl; g_file_attribute_matcher_enumerate_next: function(matcher: PGFileAttributeMatcher): Pgchar; cdecl; g_file_attribute_matcher_get_type: function:TGType; cdecl; g_file_attribute_matcher_matches: function(matcher: PGFileAttributeMatcher; attribute: Pgchar): gboolean; cdecl; g_file_attribute_matcher_matches_only: function(matcher: PGFileAttributeMatcher; attribute: Pgchar): gboolean; cdecl; g_file_attribute_matcher_new: function(attributes: Pgchar): PGFileAttributeMatcher; cdecl; g_file_attribute_matcher_ref: function(matcher: PGFileAttributeMatcher): PGFileAttributeMatcher; cdecl; g_file_attribute_matcher_subtract: function(matcher: PGFileAttributeMatcher; subtract: PGFileAttributeMatcher): PGFileAttributeMatcher; cdecl; g_file_attribute_matcher_to_string: function(matcher: PGFileAttributeMatcher): Pgchar; cdecl; g_file_attribute_matcher_unref: procedure(matcher: PGFileAttributeMatcher); cdecl; g_file_copy: function(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; error: PPGError): gboolean; cdecl; g_file_copy_async: procedure(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; io_priority: gint; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_copy_attributes: function(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_copy_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_create: function(file_: PGFile; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileOutputStream; cdecl; g_file_create_async: procedure(file_: PGFile; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_create_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileOutputStream; cdecl; g_file_create_readwrite: function(file_: PGFile; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileIOStream; cdecl; g_file_create_readwrite_async: procedure(file_: PGFile; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_create_readwrite_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileIOStream; cdecl; g_file_delete: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_delete_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_delete_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_descriptor_based_get_fd: function(fd_based: PGFileDescriptorBased): gint; cdecl; g_file_descriptor_based_get_type: function:TGType; cdecl; g_file_dup: function(file_: PGFile): PGFile; cdecl; g_file_eject_mountable_with_operation: procedure(file_: PGFile; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_eject_mountable_with_operation_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_enumerate_children: function(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): PGFileEnumerator; cdecl; g_file_enumerate_children_async: procedure(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_enumerate_children_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileEnumerator; cdecl; g_file_enumerator_close: function(enumerator: PGFileEnumerator; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_enumerator_close_async: procedure(enumerator: PGFileEnumerator; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_enumerator_close_finish: function(enumerator: PGFileEnumerator; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_enumerator_get_child: function(enumerator: PGFileEnumerator; info: PGFileInfo): PGFile; cdecl; g_file_enumerator_get_container: function(enumerator: PGFileEnumerator): PGFile; cdecl; g_file_enumerator_get_type: function:TGType; cdecl; g_file_enumerator_has_pending: function(enumerator: PGFileEnumerator): gboolean; cdecl; g_file_enumerator_is_closed: function(enumerator: PGFileEnumerator): gboolean; cdecl; g_file_enumerator_next_file: function(enumerator: PGFileEnumerator; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; g_file_enumerator_next_files_async: procedure(enumerator: PGFileEnumerator; num_files: gint; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_enumerator_next_files_finish: function(enumerator: PGFileEnumerator; result_: PGAsyncResult; error: PPGError): PGList; cdecl; g_file_enumerator_set_pending: procedure(enumerator: PGFileEnumerator; pending: gboolean); cdecl; g_file_equal: function(file1: PGFile; file2: PGFile): gboolean; cdecl; g_file_find_enclosing_mount: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGMount; cdecl; g_file_find_enclosing_mount_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_find_enclosing_mount_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGMount; cdecl; g_file_get_basename: function(file_: PGFile): Pgchar; cdecl; g_file_get_child: function(file_: PGFile; name: Pgchar): PGFile; cdecl; g_file_get_child_for_display_name: function(file_: PGFile; display_name: Pgchar; error: PPGError): PGFile; cdecl; g_file_get_parent: function(file_: PGFile): PGFile; cdecl; g_file_get_parse_name: function(file_: PGFile): Pgchar; cdecl; g_file_get_path: function(file_: PGFile): Pgchar; cdecl; g_file_get_relative_path: function(parent: PGFile; descendant: PGFile): Pgchar; cdecl; g_file_get_type: function:TGType; cdecl; g_file_get_uri: function(file_: PGFile): Pgchar; cdecl; g_file_get_uri_scheme: function(file_: PGFile): Pgchar; cdecl; g_file_has_parent: function(file_: PGFile; parent: PGFile): gboolean; cdecl; g_file_has_prefix: function(file_: PGFile; prefix: PGFile): gboolean; cdecl; g_file_has_uri_scheme: function(file_: PGFile; uri_scheme: Pgchar): gboolean; cdecl; g_file_hash: function(file_: PGFile): guint; cdecl; g_file_icon_get_file: function(icon: PGFileIcon): PGFile; cdecl; g_file_icon_get_type: function:TGType; cdecl; g_file_icon_new: function(file_: PGFile): PGFileIcon; cdecl; g_file_info_clear_status: procedure(info: PGFileInfo); cdecl; g_file_info_copy_into: procedure(src_info: PGFileInfo; dest_info: PGFileInfo); cdecl; g_file_info_dup: function(other: PGFileInfo): PGFileInfo; cdecl; g_file_info_get_attribute_as_string: function(info: PGFileInfo; attribute: Pgchar): Pgchar; cdecl; g_file_info_get_attribute_boolean: function(info: PGFileInfo; attribute: Pgchar): gboolean; cdecl; g_file_info_get_attribute_byte_string: function(info: PGFileInfo; attribute: Pgchar): Pgchar; cdecl; g_file_info_get_attribute_data: function(info: PGFileInfo; attribute: Pgchar; type_: PGFileAttributeType; value_pp: Pgpointer; status: PGFileAttributeStatus): gboolean; cdecl; g_file_info_get_attribute_int32: function(info: PGFileInfo; attribute: Pgchar): gint32; cdecl; g_file_info_get_attribute_int64: function(info: PGFileInfo; attribute: Pgchar): gint64; cdecl; g_file_info_get_attribute_object: function(info: PGFileInfo; attribute: Pgchar): PGObject; cdecl; g_file_info_get_attribute_status: function(info: PGFileInfo; attribute: Pgchar): TGFileAttributeStatus; cdecl; g_file_info_get_attribute_string: function(info: PGFileInfo; attribute: Pgchar): Pgchar; cdecl; g_file_info_get_attribute_stringv: function(info: PGFileInfo; attribute: Pgchar): PPgchar; cdecl; g_file_info_get_attribute_type: function(info: PGFileInfo; attribute: Pgchar): TGFileAttributeType; cdecl; g_file_info_get_attribute_uint32: function(info: PGFileInfo; attribute: Pgchar): guint32; cdecl; g_file_info_get_attribute_uint64: function(info: PGFileInfo; attribute: Pgchar): guint64; cdecl; g_file_info_get_content_type: function(info: PGFileInfo): Pgchar; cdecl; g_file_info_get_deletion_date: function(info: PGFileInfo): PGDateTime; cdecl; g_file_info_get_display_name: function(info: PGFileInfo): Pgchar; cdecl; g_file_info_get_edit_name: function(info: PGFileInfo): Pgchar; cdecl; g_file_info_get_etag: function(info: PGFileInfo): Pgchar; cdecl; g_file_info_get_file_type: function(info: PGFileInfo): TGFileType; cdecl; g_file_info_get_icon: function(info: PGFileInfo): PGIcon; cdecl; g_file_info_get_is_backup: function(info: PGFileInfo): gboolean; cdecl; g_file_info_get_is_hidden: function(info: PGFileInfo): gboolean; cdecl; g_file_info_get_is_symlink: function(info: PGFileInfo): gboolean; cdecl; g_file_info_get_modification_time: procedure(info: PGFileInfo; result_: PGTimeVal); cdecl; g_file_info_get_name: function(info: PGFileInfo): Pgchar; cdecl; g_file_info_get_size: function(info: PGFileInfo): gint64; cdecl; g_file_info_get_sort_order: function(info: PGFileInfo): gint32; cdecl; g_file_info_get_symbolic_icon: function(info: PGFileInfo): PGIcon; cdecl; g_file_info_get_symlink_target: function(info: PGFileInfo): Pgchar; cdecl; g_file_info_get_type: function:TGType; cdecl; g_file_info_has_attribute: function(info: PGFileInfo; attribute: Pgchar): gboolean; cdecl; g_file_info_has_namespace: function(info: PGFileInfo; name_space: Pgchar): gboolean; cdecl; g_file_info_list_attributes: function(info: PGFileInfo; name_space: Pgchar): PPgchar; cdecl; g_file_info_new: function: PGFileInfo; cdecl; g_file_info_remove_attribute: procedure(info: PGFileInfo; attribute: Pgchar); cdecl; g_file_info_set_attribute: procedure(info: PGFileInfo; attribute: Pgchar; type_: TGFileAttributeType; value_p: gpointer); cdecl; g_file_info_set_attribute_boolean: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: gboolean); cdecl; g_file_info_set_attribute_byte_string: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: Pgchar); cdecl; g_file_info_set_attribute_int32: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: gint32); cdecl; g_file_info_set_attribute_int64: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: gint64); cdecl; g_file_info_set_attribute_mask: procedure(info: PGFileInfo; mask: PGFileAttributeMatcher); cdecl; g_file_info_set_attribute_object: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: PGObject); cdecl; g_file_info_set_attribute_status: function(info: PGFileInfo; attribute: Pgchar; status: TGFileAttributeStatus): gboolean; cdecl; g_file_info_set_attribute_string: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: Pgchar); cdecl; g_file_info_set_attribute_stringv: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: PPgchar); cdecl; g_file_info_set_attribute_uint32: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: guint32); cdecl; g_file_info_set_attribute_uint64: procedure(info: PGFileInfo; attribute: Pgchar; attr_value: guint64); cdecl; g_file_info_set_content_type: procedure(info: PGFileInfo; content_type: Pgchar); cdecl; g_file_info_set_display_name: procedure(info: PGFileInfo; display_name: Pgchar); cdecl; g_file_info_set_edit_name: procedure(info: PGFileInfo; edit_name: Pgchar); cdecl; g_file_info_set_file_type: procedure(info: PGFileInfo; type_: TGFileType); cdecl; g_file_info_set_icon: procedure(info: PGFileInfo; icon: PGIcon); cdecl; g_file_info_set_is_hidden: procedure(info: PGFileInfo; is_hidden: gboolean); cdecl; g_file_info_set_is_symlink: procedure(info: PGFileInfo; is_symlink: gboolean); cdecl; g_file_info_set_modification_time: procedure(info: PGFileInfo; mtime: PGTimeVal); cdecl; g_file_info_set_name: procedure(info: PGFileInfo; name: Pgchar); cdecl; g_file_info_set_size: procedure(info: PGFileInfo; size: gint64); cdecl; g_file_info_set_sort_order: procedure(info: PGFileInfo; sort_order: gint32); cdecl; g_file_info_set_symbolic_icon: procedure(info: PGFileInfo; icon: PGIcon); cdecl; g_file_info_set_symlink_target: procedure(info: PGFileInfo; symlink_target: Pgchar); cdecl; g_file_info_unset_attribute_mask: procedure(info: PGFileInfo); cdecl; g_file_input_stream_get_type: function:TGType; cdecl; g_file_input_stream_query_info: function(stream: PGFileInputStream; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; g_file_input_stream_query_info_async: procedure(stream: PGFileInputStream; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_input_stream_query_info_finish: function(stream: PGFileInputStream; result_: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; g_file_io_stream_get_etag: function(stream: PGFileIOStream): Pgchar; cdecl; g_file_io_stream_get_type: function:TGType; cdecl; g_file_io_stream_query_info: function(stream: PGFileIOStream; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; g_file_io_stream_query_info_async: procedure(stream: PGFileIOStream; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_io_stream_query_info_finish: function(stream: PGFileIOStream; result_: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; g_file_is_native: function(file_: PGFile): gboolean; cdecl; g_file_load_contents: function(file_: PGFile; cancellable: PGCancellable; contents: PPgchar; length: Pgsize; etag_out: PPgchar; error: PPGError): gboolean; cdecl; g_file_load_contents_async: procedure(file_: PGFile; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_load_contents_finish: function(file_: PGFile; res: PGAsyncResult; contents: PPgchar; length: Pgsize; etag_out: PPgchar; error: PPGError): gboolean; cdecl; g_file_load_partial_contents_async: procedure(file_: PGFile; cancellable: PGCancellable; read_more_callback: TGFileReadMoreCallback; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_load_partial_contents_finish: function(file_: PGFile; res: PGAsyncResult; contents: PPgchar; length: Pgsize; etag_out: PPgchar; error: PPGError): gboolean; cdecl; g_file_make_directory: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_make_directory_with_parents: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_make_symbolic_link: function(file_: PGFile; symlink_value: Pgchar; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_monitor: function(file_: PGFile; flags: TGFileMonitorFlags; cancellable: PGCancellable; error: PPGError): PGFileMonitor; cdecl; g_file_monitor_cancel: function(monitor: PGFileMonitor): gboolean; cdecl; g_file_monitor_directory: function(file_: PGFile; flags: TGFileMonitorFlags; cancellable: PGCancellable; error: PPGError): PGFileMonitor; cdecl; g_file_monitor_emit_event: procedure(monitor: PGFileMonitor; child: PGFile; other_file: PGFile; event_type: TGFileMonitorEvent); cdecl; g_file_monitor_file: function(file_: PGFile; flags: TGFileMonitorFlags; cancellable: PGCancellable; error: PPGError): PGFileMonitor; cdecl; g_file_monitor_get_type: function:TGType; cdecl; g_file_monitor_is_cancelled: function(monitor: PGFileMonitor): gboolean; cdecl; g_file_monitor_set_rate_limit: procedure(monitor: PGFileMonitor; limit_msecs: gint); cdecl; g_file_mount_enclosing_volume: procedure(location: PGFile; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_mount_enclosing_volume_finish: function(location: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_mount_mountable: procedure(file_: PGFile; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_mount_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): PGFile; cdecl; g_file_move: function(source: PGFile; destination: PGFile; flags: TGFileCopyFlags; cancellable: PGCancellable; progress_callback: TGFileProgressCallback; progress_callback_data: gpointer; error: PPGError): gboolean; cdecl; g_file_new_for_commandline_arg: function(arg: Pgchar): PGFile; cdecl; g_file_new_for_commandline_arg_and_cwd: function(arg: Pgchar; cwd: Pgchar): PGFile; cdecl; g_file_new_for_path: function(path: Pgchar): PGFile; cdecl; g_file_new_for_uri: function(uri: Pgchar): PGFile; cdecl; g_file_new_tmp: function(tmpl: Pgchar; iostream: PPGFileIOStream; error: PPGError): PGFile; cdecl; g_file_open_readwrite: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileIOStream; cdecl; g_file_open_readwrite_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_open_readwrite_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileIOStream; cdecl; g_file_output_stream_get_etag: function(stream: PGFileOutputStream): Pgchar; cdecl; g_file_output_stream_get_type: function:TGType; cdecl; g_file_output_stream_query_info: function(stream: PGFileOutputStream; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; g_file_output_stream_query_info_async: procedure(stream: PGFileOutputStream; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_output_stream_query_info_finish: function(stream: PGFileOutputStream; result_: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; g_file_parse_name: function(parse_name: Pgchar): PGFile; cdecl; g_file_poll_mountable: procedure(file_: PGFile; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_poll_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_query_default_handler: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGAppInfo; cdecl; g_file_query_exists: function(file_: PGFile; cancellable: PGCancellable): gboolean; cdecl; g_file_query_file_type: function(file_: PGFile; flags: TGFileQueryInfoFlags; cancellable: PGCancellable): TGFileType; cdecl; g_file_query_filesystem_info: function(file_: PGFile; attributes: Pgchar; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; g_file_query_filesystem_info_async: procedure(file_: PGFile; attributes: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_query_filesystem_info_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; g_file_query_info: function(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): PGFileInfo; cdecl; g_file_query_info_async: procedure(file_: PGFile; attributes: Pgchar; flags: TGFileQueryInfoFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_query_info_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileInfo; cdecl; g_file_query_settable_attributes: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileAttributeInfoList; cdecl; g_file_query_writable_namespaces: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileAttributeInfoList; cdecl; g_file_read: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): PGFileInputStream; cdecl; g_file_read_async: procedure(file_: PGFile; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_read_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileInputStream; cdecl; g_file_replace: function(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileOutputStream; cdecl; g_file_replace_async: procedure(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_replace_contents: function(file_: PGFile; contents: Pgchar; length: gsize; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; new_etag: PPgchar; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_replace_contents_async: procedure(file_: PGFile; contents: Pgchar; length: gsize; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_replace_contents_finish: function(file_: PGFile; res: PGAsyncResult; new_etag: PPgchar; error: PPGError): gboolean; cdecl; g_file_replace_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileOutputStream; cdecl; g_file_replace_readwrite: function(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; cancellable: PGCancellable; error: PPGError): PGFileIOStream; cdecl; g_file_replace_readwrite_async: procedure(file_: PGFile; etag: Pgchar; make_backup: gboolean; flags: TGFileCreateFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_replace_readwrite_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFileIOStream; cdecl; g_file_resolve_relative_path: function(file_: PGFile; relative_path: Pgchar): PGFile; cdecl; g_file_set_attribute: function(file_: PGFile; attribute: Pgchar; type_: TGFileAttributeType; value_p: gpointer; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attribute_byte_string: function(file_: PGFile; attribute: Pgchar; value: Pgchar; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attribute_int32: function(file_: PGFile; attribute: Pgchar; value: gint32; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attribute_int64: function(file_: PGFile; attribute: Pgchar; value: gint64; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attribute_string: function(file_: PGFile; attribute: Pgchar; value: Pgchar; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attribute_uint32: function(file_: PGFile; attribute: Pgchar; value: guint32; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attribute_uint64: function(file_: PGFile; attribute: Pgchar; value: guint64; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_attributes_async: procedure(file_: PGFile; info: PGFileInfo; flags: TGFileQueryInfoFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_set_attributes_finish: function(file_: PGFile; result_: PGAsyncResult; info: PPGFileInfo; error: PPGError): gboolean; cdecl; g_file_set_attributes_from_info: function(file_: PGFile; info: PGFileInfo; flags: TGFileQueryInfoFlags; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_set_display_name: function(file_: PGFile; display_name: Pgchar; cancellable: PGCancellable; error: PPGError): PGFile; cdecl; g_file_set_display_name_async: procedure(file_: PGFile; display_name: Pgchar; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_set_display_name_finish: function(file_: PGFile; res: PGAsyncResult; error: PPGError): PGFile; cdecl; g_file_start_mountable: procedure(file_: PGFile; flags: TGDriveStartFlags; start_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_start_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_stop_mountable: procedure(file_: PGFile; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_stop_mountable_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_file_supports_thread_contexts: function(file_: PGFile): gboolean; cdecl; g_file_trash: function(file_: PGFile; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_file_unmount_mountable_with_operation: procedure(file_: PGFile; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_file_unmount_mountable_with_operation_finish: function(file_: PGFile; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_filename_completer_get_completion_suffix: function(completer: PGFilenameCompleter; initial_text: Pgchar): Pgchar; cdecl; g_filename_completer_get_completions: function(completer: PGFilenameCompleter; initial_text: Pgchar): PPgchar; cdecl; g_filename_completer_get_type: function:TGType; cdecl; g_filename_completer_new: function: PGFilenameCompleter; cdecl; g_filename_completer_set_dirs_only: procedure(completer: PGFilenameCompleter; dirs_only: gboolean); cdecl; g_filter_input_stream_get_base_stream: function(stream: PGFilterInputStream): PGInputStream; cdecl; g_filter_input_stream_get_close_base_stream: function(stream: PGFilterInputStream): gboolean; cdecl; g_filter_input_stream_get_type: function:TGType; cdecl; g_filter_input_stream_set_close_base_stream: procedure(stream: PGFilterInputStream; close_base: gboolean); cdecl; g_filter_output_stream_get_base_stream: function(stream: PGFilterOutputStream): PGOutputStream; cdecl; g_filter_output_stream_get_close_base_stream: function(stream: PGFilterOutputStream): gboolean; cdecl; g_filter_output_stream_get_type: function:TGType; cdecl; g_filter_output_stream_set_close_base_stream: procedure(stream: PGFilterOutputStream; close_base: gboolean); cdecl; g_icon_equal: function(icon1: PGIcon; icon2: PGIcon): gboolean; cdecl; g_icon_get_type: function:TGType; cdecl; g_icon_hash: function(icon: Pgpointer): guint; cdecl; g_icon_new_for_string: function(str: Pgchar; error: PPGError): PGIcon; cdecl; g_icon_to_string: function(icon: PGIcon): Pgchar; cdecl; g_inet_address_equal: function(address: PGInetAddress; other_address: PGInetAddress): gboolean; cdecl; g_inet_address_get_family: function(address: PGInetAddress): TGSocketFamily; cdecl; g_inet_address_get_is_any: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_link_local: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_loopback: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_mc_global: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_mc_link_local: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_mc_node_local: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_mc_org_local: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_mc_site_local: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_multicast: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_is_site_local: function(address: PGInetAddress): gboolean; cdecl; g_inet_address_get_native_size: function(address: PGInetAddress): gsize; cdecl; g_inet_address_get_type: function:TGType; cdecl; g_inet_address_mask_equal: function(mask: PGInetAddressMask; mask2: PGInetAddressMask): gboolean; cdecl; g_inet_address_mask_get_address: function(mask: PGInetAddressMask): PGInetAddress; cdecl; g_inet_address_mask_get_family: function(mask: PGInetAddressMask): TGSocketFamily; cdecl; g_inet_address_mask_get_length: function(mask: PGInetAddressMask): guint; cdecl; g_inet_address_mask_get_type: function:TGType; cdecl; g_inet_address_mask_matches: function(mask: PGInetAddressMask; address: PGInetAddress): gboolean; cdecl; g_inet_address_mask_new: function(addr: PGInetAddress; length: guint; error: PPGError): PGInetAddressMask; cdecl; g_inet_address_mask_new_from_string: function(mask_string: Pgchar; error: PPGError): PGInetAddressMask; cdecl; g_inet_address_mask_to_string: function(mask: PGInetAddressMask): Pgchar; cdecl; g_inet_address_new_any: function(family: TGSocketFamily): PGInetAddress; cdecl; g_inet_address_new_from_bytes: function(bytes: Pguint8; family: TGSocketFamily): PGInetAddress; cdecl; g_inet_address_new_from_string: function(string_: Pgchar): PGInetAddress; cdecl; g_inet_address_new_loopback: function(family: TGSocketFamily): PGInetAddress; cdecl; g_inet_address_to_bytes: function(address: PGInetAddress): Pguint8; cdecl; g_inet_address_to_string: function(address: PGInetAddress): Pgchar; cdecl; g_inet_socket_address_get_address: function(address: PGInetSocketAddress): PGInetAddress; cdecl; g_inet_socket_address_get_flowinfo: function(address: PGInetSocketAddress): guint32; cdecl; g_inet_socket_address_get_port: function(address: PGInetSocketAddress): guint16; cdecl; g_inet_socket_address_get_scope_id: function(address: PGInetSocketAddress): guint32; cdecl; g_inet_socket_address_get_type: function:TGType; cdecl; g_inet_socket_address_new: function(address: PGInetAddress; port: guint16): PGInetSocketAddress; cdecl; g_initable_get_type: function:TGType; cdecl; g_initable_init: function(initable: PGInitable; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_initable_new: function(object_type: TGType; cancellable: PGCancellable; error: PPGError; first_property_name: Pgchar; args: array of const): PGObject; cdecl; g_initable_new_valist: function(object_type: TGType; first_property_name: Pgchar; var_args: Tva_list; cancellable: PGCancellable; error: PPGError): PGObject; cdecl; g_initable_newv: function(object_type: TGType; n_parameters: guint; parameters: PGParameter; cancellable: PGCancellable; error: PPGError): PGObject; cdecl; g_input_stream_clear_pending: procedure(stream: PGInputStream); cdecl; g_input_stream_close: function(stream: PGInputStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_input_stream_close_async: procedure(stream: PGInputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_input_stream_close_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_input_stream_get_type: function:TGType; cdecl; g_input_stream_has_pending: function(stream: PGInputStream): gboolean; cdecl; g_input_stream_is_closed: function(stream: PGInputStream): gboolean; cdecl; g_input_stream_read: function(stream: PGInputStream; buffer: Pguint8; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_input_stream_read_all: function(stream: PGInputStream; buffer: Pguint8; count: gsize; bytes_read: Pgsize; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_input_stream_read_async: procedure(stream: PGInputStream; buffer: Pguint8; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_input_stream_read_bytes: function(stream: PGInputStream; count: gsize; cancellable: PGCancellable; error: PPGError): PGBytes; cdecl; g_input_stream_read_bytes_async: procedure(stream: PGInputStream; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_input_stream_read_bytes_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): PGBytes; cdecl; g_input_stream_read_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; g_input_stream_set_pending: function(stream: PGInputStream; error: PPGError): gboolean; cdecl; g_input_stream_skip: function(stream: PGInputStream; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_input_stream_skip_async: procedure(stream: PGInputStream; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_input_stream_skip_finish: function(stream: PGInputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; g_io_error_from_errno: function(err_no: gint): TGIOErrorEnum; cdecl; g_io_error_quark: function: TGQuark; cdecl; g_io_extension_get_name: function(extension: PGIOExtension): Pgchar; cdecl; g_io_extension_get_priority: function(extension: PGIOExtension): gint; cdecl; g_io_extension_get_type: function(extension: PGIOExtension): TGType; cdecl; g_io_extension_point_get_extension_by_name: function(extension_point: PGIOExtensionPoint; name: Pgchar): PGIOExtension; cdecl; g_io_extension_point_get_extensions: function(extension_point: PGIOExtensionPoint): PGList; cdecl; g_io_extension_point_get_required_type: function(extension_point: PGIOExtensionPoint): TGType; cdecl; g_io_extension_point_implement: function(extension_point_name: Pgchar; type_: TGType; extension_name: Pgchar; priority: gint): PGIOExtension; cdecl; g_io_extension_point_lookup: function(name: Pgchar): PGIOExtensionPoint; cdecl; g_io_extension_point_register: function(name: Pgchar): PGIOExtensionPoint; cdecl; g_io_extension_point_set_required_type: procedure(extension_point: PGIOExtensionPoint; type_: TGType); cdecl; g_io_extension_ref_class: function(extension: PGIOExtension): PGTypeClass; cdecl; g_io_module_get_type: function:TGType; cdecl; g_io_module_new: function(filename: Pgchar): PGIOModule; cdecl; g_io_module_scope_block: procedure(scope: PGIOModuleScope; basename: Pgchar); cdecl; g_io_module_scope_free: procedure(scope: PGIOModuleScope); cdecl; g_io_module_scope_new: function(flags: TGIOModuleScopeFlags): PGIOModuleScope; cdecl; g_io_modules_load_all_in_directory: function(dirname: Pgchar): PGList; cdecl; g_io_modules_load_all_in_directory_with_scope: function(dirname: Pgchar; scope: PGIOModuleScope): PGList; cdecl; g_io_modules_scan_all_in_directory: procedure(dirname: Pgchar); cdecl; g_io_modules_scan_all_in_directory_with_scope: procedure(dirname: Pgchar; scope: PGIOModuleScope); cdecl; g_io_scheduler_cancel_all_jobs: procedure; cdecl; g_io_scheduler_push_job: procedure(job_func: TGIOSchedulerJobFunc; user_data: gpointer; notify: TGDestroyNotify; io_priority: gint; cancellable: PGCancellable); cdecl; g_io_stream_clear_pending: procedure(stream: PGIOStream); cdecl; g_io_stream_close: function(stream: PGIOStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_io_stream_close_async: procedure(stream: PGIOStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_io_stream_close_finish: function(stream: PGIOStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_io_stream_get_input_stream: function(stream: PGIOStream): PGInputStream; cdecl; g_io_stream_get_output_stream: function(stream: PGIOStream): PGOutputStream; cdecl; g_io_stream_get_type: function:TGType; cdecl; g_io_stream_has_pending: function(stream: PGIOStream): gboolean; cdecl; g_io_stream_is_closed: function(stream: PGIOStream): gboolean; cdecl; g_io_stream_set_pending: function(stream: PGIOStream; error: PPGError): gboolean; cdecl; g_io_stream_splice_async: procedure(stream1: PGIOStream; stream2: PGIOStream; flags: TGIOStreamSpliceFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_io_stream_splice_finish: function(result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_loadable_icon_get_type: function:TGType; cdecl; g_loadable_icon_load: function(icon: PGLoadableIcon; size: gint; type_: PPgchar; cancellable: PGCancellable; error: PPGError): PGInputStream; cdecl; g_loadable_icon_load_async: procedure(icon: PGLoadableIcon; size: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_loadable_icon_load_finish: function(icon: PGLoadableIcon; res: PGAsyncResult; type_: PPgchar; error: PPGError): PGInputStream; cdecl; g_memory_input_stream_add_bytes: procedure(stream: PGMemoryInputStream; bytes: PGBytes); cdecl; g_memory_input_stream_add_data: procedure(stream: PGMemoryInputStream; data: Pguint8; len: gssize; destroy_: TGDestroyNotify); cdecl; g_memory_input_stream_get_type: function:TGType; cdecl; g_memory_input_stream_new: function: PGMemoryInputStream; cdecl; g_memory_input_stream_new_from_bytes: function(bytes: PGBytes): PGMemoryInputStream; cdecl; g_memory_input_stream_new_from_data: function(data: Pguint8; len: gssize; destroy_: TGDestroyNotify): PGMemoryInputStream; cdecl; g_memory_output_stream_get_data: function(ostream: PGMemoryOutputStream): gpointer; cdecl; g_memory_output_stream_get_data_size: function(ostream: PGMemoryOutputStream): gsize; cdecl; g_memory_output_stream_get_size: function(ostream: PGMemoryOutputStream): gsize; cdecl; g_memory_output_stream_get_type: function:TGType; cdecl; g_memory_output_stream_new: function(data: gpointer; size: gsize; realloc_function: TGReallocFunc; destroy_function: TGDestroyNotify): PGMemoryOutputStream; cdecl; g_memory_output_stream_new_resizable: function: PGMemoryOutputStream; cdecl; g_memory_output_stream_steal_as_bytes: function(ostream: PGMemoryOutputStream): PGBytes; cdecl; g_memory_output_stream_steal_data: function(ostream: PGMemoryOutputStream): gpointer; cdecl; g_menu_append: procedure(menu: PGMenu; label_: Pgchar; detailed_action: Pgchar); cdecl; g_menu_append_item: procedure(menu: PGMenu; item: PGMenuItem); cdecl; g_menu_append_section: procedure(menu: PGMenu; label_: Pgchar; section: PGMenuModel); cdecl; g_menu_append_submenu: procedure(menu: PGMenu; label_: Pgchar; submenu: PGMenuModel); cdecl; g_menu_attribute_iter_get_name: function(iter: PGMenuAttributeIter): Pgchar; cdecl; g_menu_attribute_iter_get_next: function(iter: PGMenuAttributeIter; out_name: PPgchar; value: PPGVariant): gboolean; cdecl; g_menu_attribute_iter_get_type: function:TGType; cdecl; g_menu_attribute_iter_get_value: function(iter: PGMenuAttributeIter): PGVariant; cdecl; g_menu_attribute_iter_next: function(iter: PGMenuAttributeIter): gboolean; cdecl; g_menu_freeze: procedure(menu: PGMenu); cdecl; g_menu_get_type: function:TGType; cdecl; g_menu_insert: procedure(menu: PGMenu; position: gint; label_: Pgchar; detailed_action: Pgchar); cdecl; g_menu_insert_item: procedure(menu: PGMenu; position: gint; item: PGMenuItem); cdecl; g_menu_insert_section: procedure(menu: PGMenu; position: gint; label_: Pgchar; section: PGMenuModel); cdecl; g_menu_insert_submenu: procedure(menu: PGMenu; position: gint; label_: Pgchar; submenu: PGMenuModel); cdecl; g_menu_item_get_attribute: function(menu_item: PGMenuItem; attribute: Pgchar; format_string: Pgchar; args: array of const): gboolean; cdecl; g_menu_item_get_attribute_value: function(menu_item: PGMenuItem; attribute: Pgchar; expected_type: PGVariantType): PGVariant; cdecl; g_menu_item_get_link: function(menu_item: PGMenuItem; link: Pgchar): PGMenuModel; cdecl; g_menu_item_get_type: function:TGType; cdecl; g_menu_item_new: function(label_: Pgchar; detailed_action: Pgchar): PGMenuItem; cdecl; g_menu_item_new_from_model: function(model: PGMenuModel; item_index: gint): PGMenuItem; cdecl; g_menu_item_new_section: function(label_: Pgchar; section: PGMenuModel): PGMenuItem; cdecl; g_menu_item_new_submenu: function(label_: Pgchar; submenu: PGMenuModel): PGMenuItem; cdecl; g_menu_item_set_action_and_target: procedure(menu_item: PGMenuItem; action: Pgchar; format_string: Pgchar; args: array of const); cdecl; g_menu_item_set_action_and_target_value: procedure(menu_item: PGMenuItem; action: Pgchar; target_value: PGVariant); cdecl; g_menu_item_set_attribute: procedure(menu_item: PGMenuItem; attribute: Pgchar; format_string: Pgchar; args: array of const); cdecl; g_menu_item_set_attribute_value: procedure(menu_item: PGMenuItem; attribute: Pgchar; value: PGVariant); cdecl; g_menu_item_set_detailed_action: procedure(menu_item: PGMenuItem; detailed_action: Pgchar); cdecl; g_menu_item_set_label: procedure(menu_item: PGMenuItem; label_: Pgchar); cdecl; g_menu_item_set_link: procedure(menu_item: PGMenuItem; link: Pgchar; model: PGMenuModel); cdecl; g_menu_item_set_section: procedure(menu_item: PGMenuItem; section: PGMenuModel); cdecl; g_menu_item_set_submenu: procedure(menu_item: PGMenuItem; submenu: PGMenuModel); cdecl; g_menu_link_iter_get_name: function(iter: PGMenuLinkIter): Pgchar; cdecl; g_menu_link_iter_get_next: function(iter: PGMenuLinkIter; out_link: PPgchar; value: PPGMenuModel): gboolean; cdecl; g_menu_link_iter_get_type: function:TGType; cdecl; g_menu_link_iter_get_value: function(iter: PGMenuLinkIter): PGMenuModel; cdecl; g_menu_link_iter_next: function(iter: PGMenuLinkIter): gboolean; cdecl; g_menu_model_get_item_attribute: function(model: PGMenuModel; item_index: gint; attribute: Pgchar; format_string: Pgchar; args: array of const): gboolean; cdecl; g_menu_model_get_item_attribute_value: function(model: PGMenuModel; item_index: gint; attribute: Pgchar; expected_type: PGVariantType): PGVariant; cdecl; g_menu_model_get_item_link: function(model: PGMenuModel; item_index: gint; link: Pgchar): PGMenuModel; cdecl; g_menu_model_get_n_items: function(model: PGMenuModel): gint; cdecl; g_menu_model_get_type: function:TGType; cdecl; g_menu_model_is_mutable: function(model: PGMenuModel): gboolean; cdecl; g_menu_model_items_changed: procedure(model: PGMenuModel; position: gint; removed: gint; added: gint); cdecl; g_menu_model_iterate_item_attributes: function(model: PGMenuModel; item_index: gint): PGMenuAttributeIter; cdecl; g_menu_model_iterate_item_links: function(model: PGMenuModel; item_index: gint): PGMenuLinkIter; cdecl; g_menu_new: function: PGMenu; cdecl; g_menu_prepend: procedure(menu: PGMenu; label_: Pgchar; detailed_action: Pgchar); cdecl; g_menu_prepend_item: procedure(menu: PGMenu; item: PGMenuItem); cdecl; g_menu_prepend_section: procedure(menu: PGMenu; label_: Pgchar; section: PGMenuModel); cdecl; g_menu_prepend_submenu: procedure(menu: PGMenu; label_: Pgchar; submenu: PGMenuModel); cdecl; g_menu_remove: procedure(menu: PGMenu; position: gint); cdecl; g_mount_can_eject: function(mount: PGMount): gboolean; cdecl; g_mount_can_unmount: function(mount: PGMount): gboolean; cdecl; g_mount_eject_with_operation: procedure(mount: PGMount; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_mount_eject_with_operation_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_mount_get_default_location: function(mount: PGMount): PGFile; cdecl; g_mount_get_drive: function(mount: PGMount): PGDrive; cdecl; g_mount_get_icon: function(mount: PGMount): PGIcon; cdecl; g_mount_get_name: function(mount: PGMount): Pgchar; cdecl; g_mount_get_root: function(mount: PGMount): PGFile; cdecl; g_mount_get_sort_key: function(mount: PGMount): Pgchar; cdecl; g_mount_get_symbolic_icon: function(mount: PGMount): PGIcon; cdecl; g_mount_get_type: function:TGType; cdecl; g_mount_get_uuid: function(mount: PGMount): Pgchar; cdecl; g_mount_get_volume: function(mount: PGMount): PGVolume; cdecl; g_mount_guess_content_type: procedure(mount: PGMount; force_rescan: gboolean; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_mount_guess_content_type_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): PPgchar; cdecl; g_mount_guess_content_type_sync: function(mount: PGMount; force_rescan: gboolean; cancellable: PGCancellable; error: PPGError): PPgchar; cdecl; g_mount_is_shadowed: function(mount: PGMount): gboolean; cdecl; g_mount_operation_get_anonymous: function(op: PGMountOperation): gboolean; cdecl; g_mount_operation_get_choice: function(op: PGMountOperation): gint; cdecl; g_mount_operation_get_domain: function(op: PGMountOperation): Pgchar; cdecl; g_mount_operation_get_password: function(op: PGMountOperation): Pgchar; cdecl; g_mount_operation_get_password_save: function(op: PGMountOperation): TGPasswordSave; cdecl; g_mount_operation_get_type: function:TGType; cdecl; g_mount_operation_get_username: function(op: PGMountOperation): Pgchar; cdecl; g_mount_operation_new: function: PGMountOperation; cdecl; g_mount_operation_reply: procedure(op: PGMountOperation; result_: TGMountOperationResult); cdecl; g_mount_operation_set_anonymous: procedure(op: PGMountOperation; anonymous: gboolean); cdecl; g_mount_operation_set_choice: procedure(op: PGMountOperation; choice: gint); cdecl; g_mount_operation_set_domain: procedure(op: PGMountOperation; domain: Pgchar); cdecl; g_mount_operation_set_password: procedure(op: PGMountOperation; password: Pgchar); cdecl; g_mount_operation_set_password_save: procedure(op: PGMountOperation; save: TGPasswordSave); cdecl; g_mount_operation_set_username: procedure(op: PGMountOperation; username: Pgchar); cdecl; g_mount_remount: procedure(mount: PGMount; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_mount_remount_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_mount_shadow: procedure(mount: PGMount); cdecl; g_mount_unmount_with_operation: procedure(mount: PGMount; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_mount_unmount_with_operation_finish: function(mount: PGMount; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_mount_unshadow: procedure(mount: PGMount); cdecl; g_native_volume_monitor_get_type: function:TGType; cdecl; g_network_address_get_hostname: function(addr: PGNetworkAddress): Pgchar; cdecl; g_network_address_get_port: function(addr: PGNetworkAddress): guint16; cdecl; g_network_address_get_scheme: function(addr: PGNetworkAddress): Pgchar; cdecl; g_network_address_get_type: function:TGType; cdecl; g_network_address_new: function(hostname: Pgchar; port: guint16): PGNetworkAddress; cdecl; g_network_address_parse: function(host_and_port: Pgchar; default_port: guint16; error: PPGError): PGSocketConnectable; cdecl; g_network_address_parse_uri: function(uri: Pgchar; default_port: guint16; error: PPGError): PGSocketConnectable; cdecl; g_network_monitor_can_reach: function(monitor: PGNetworkMonitor; connectable: PGSocketConnectable; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_network_monitor_can_reach_async: procedure(monitor: PGNetworkMonitor; connectable: PGSocketConnectable; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_network_monitor_can_reach_finish: function(monitor: PGNetworkMonitor; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_network_monitor_get_default: function: PGNetworkMonitor; cdecl; g_network_monitor_get_network_available: function(monitor: PGNetworkMonitor): gboolean; cdecl; g_network_monitor_get_type: function:TGType; cdecl; g_network_service_get_domain: function(srv: PGNetworkService): Pgchar; cdecl; g_network_service_get_protocol: function(srv: PGNetworkService): Pgchar; cdecl; g_network_service_get_scheme: function(srv: PGNetworkService): Pgchar; cdecl; g_network_service_get_service: function(srv: PGNetworkService): Pgchar; cdecl; g_network_service_get_type: function:TGType; cdecl; g_network_service_new: function(service: Pgchar; protocol: Pgchar; domain: Pgchar): PGNetworkService; cdecl; g_network_service_set_scheme: procedure(srv: PGNetworkService; scheme: Pgchar); cdecl; g_networking_init: procedure; cdecl; g_output_stream_clear_pending: procedure(stream: PGOutputStream); cdecl; g_output_stream_close: function(stream: PGOutputStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_output_stream_close_async: procedure(stream: PGOutputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_output_stream_close_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_output_stream_flush: function(stream: PGOutputStream; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_output_stream_flush_async: procedure(stream: PGOutputStream; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_output_stream_flush_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_output_stream_get_type: function:TGType; cdecl; g_output_stream_has_pending: function(stream: PGOutputStream): gboolean; cdecl; g_output_stream_is_closed: function(stream: PGOutputStream): gboolean; cdecl; g_output_stream_is_closing: function(stream: PGOutputStream): gboolean; cdecl; g_output_stream_set_pending: function(stream: PGOutputStream; error: PPGError): gboolean; cdecl; g_output_stream_splice: function(stream: PGOutputStream; source: PGInputStream; flags: TGOutputStreamSpliceFlags; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_output_stream_splice_async: procedure(stream: PGOutputStream; source: PGInputStream; flags: TGOutputStreamSpliceFlags; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_output_stream_splice_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; g_output_stream_write: function(stream: PGOutputStream; buffer: Pguint8; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_output_stream_write_all: function(stream: PGOutputStream; buffer: Pguint8; count: gsize; bytes_written: Pgsize; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_output_stream_write_async: procedure(stream: PGOutputStream; buffer: Pguint8; count: gsize; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_output_stream_write_bytes: function(stream: PGOutputStream; bytes: PGBytes; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_output_stream_write_bytes_async: procedure(stream: PGOutputStream; bytes: PGBytes; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_output_stream_write_bytes_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; g_output_stream_write_finish: function(stream: PGOutputStream; result_: PGAsyncResult; error: PPGError): gssize; cdecl; g_permission_acquire: function(permission: PGPermission; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_permission_acquire_async: procedure(permission: PGPermission; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_permission_acquire_finish: function(permission: PGPermission; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_permission_get_allowed: function(permission: PGPermission): gboolean; cdecl; g_permission_get_can_acquire: function(permission: PGPermission): gboolean; cdecl; g_permission_get_can_release: function(permission: PGPermission): gboolean; cdecl; g_permission_get_type: function:TGType; cdecl; g_permission_impl_update: procedure(permission: PGPermission; allowed: gboolean; can_acquire: gboolean; can_release: gboolean); cdecl; g_permission_release: function(permission: PGPermission; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_permission_release_async: procedure(permission: PGPermission; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_permission_release_finish: function(permission: PGPermission; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_pollable_input_stream_can_poll: function(stream: PGPollableInputStream): gboolean; cdecl; g_pollable_input_stream_create_source: function(stream: PGPollableInputStream; cancellable: PGCancellable): PGSource; cdecl; g_pollable_input_stream_get_type: function:TGType; cdecl; g_pollable_input_stream_is_readable: function(stream: PGPollableInputStream): gboolean; cdecl; g_pollable_input_stream_read_nonblocking: function(stream: PGPollableInputStream; buffer: Pgpointer; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_pollable_output_stream_can_poll: function(stream: PGPollableOutputStream): gboolean; cdecl; g_pollable_output_stream_create_source: function(stream: PGPollableOutputStream; cancellable: PGCancellable): PGSource; cdecl; g_pollable_output_stream_get_type: function:TGType; cdecl; g_pollable_output_stream_is_writable: function(stream: PGPollableOutputStream): gboolean; cdecl; g_pollable_output_stream_write_nonblocking: function(stream: PGPollableOutputStream; buffer: Pguint8; count: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_pollable_source_new: function(pollable_stream: PGObject): PGSource; cdecl; g_pollable_source_new_full: function(pollable_stream: PGObject; child_source: PGSource; cancellable: PGCancellable): PGSource; cdecl; g_pollable_stream_read: function(stream: PGInputStream; buffer: Pgpointer; count: gsize; blocking: gboolean; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_pollable_stream_write: function(stream: PGOutputStream; buffer: Pguint8; count: gsize; blocking: gboolean; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_pollable_stream_write_all: function(stream: PGOutputStream; buffer: Pguint8; count: gsize; blocking: gboolean; bytes_written: Pgsize; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_proxy_address_enumerator_get_type: function:TGType; cdecl; g_proxy_address_get_destination_hostname: function(proxy: PGProxyAddress): Pgchar; cdecl; g_proxy_address_get_destination_port: function(proxy: PGProxyAddress): guint16; cdecl; g_proxy_address_get_destination_protocol: function(proxy: PGProxyAddress): Pgchar; cdecl; g_proxy_address_get_password: function(proxy: PGProxyAddress): Pgchar; cdecl; g_proxy_address_get_protocol: function(proxy: PGProxyAddress): Pgchar; cdecl; g_proxy_address_get_type: function:TGType; cdecl; g_proxy_address_get_uri: function(proxy: PGProxyAddress): Pgchar; cdecl; g_proxy_address_get_username: function(proxy: PGProxyAddress): Pgchar; cdecl; g_proxy_address_new: function(inetaddr: PGInetAddress; port: guint16; protocol: Pgchar; dest_hostname: Pgchar; dest_port: guint16; username: Pgchar; password: Pgchar): PGProxyAddress; cdecl; g_proxy_connect: function(proxy: PGProxy; connection: PGIOStream; proxy_address: PGProxyAddress; cancellable: PGCancellable; error: PPGError): PGIOStream; cdecl; g_proxy_connect_async: procedure(proxy: PGProxy; connection: PGIOStream; proxy_address: PGProxyAddress; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_proxy_connect_finish: function(proxy: PGProxy; result_: PGAsyncResult; error: PPGError): PGIOStream; cdecl; g_proxy_get_default_for_protocol: function(protocol: Pgchar): PGProxy; cdecl; g_proxy_get_type: function:TGType; cdecl; g_proxy_resolver_get_default: function: PGProxyResolver; cdecl; g_proxy_resolver_get_type: function:TGType; cdecl; g_proxy_resolver_is_supported: function(resolver: PGProxyResolver): gboolean; cdecl; g_proxy_resolver_lookup: function(resolver: PGProxyResolver; uri: Pgchar; cancellable: PGCancellable; error: PPGError): PPgchar; cdecl; g_proxy_resolver_lookup_async: procedure(resolver: PGProxyResolver; uri: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_proxy_resolver_lookup_finish: function(resolver: PGProxyResolver; result_: PGAsyncResult; error: PPGError): PPgchar; cdecl; g_proxy_supports_hostname: function(proxy: PGProxy): gboolean; cdecl; g_remote_action_group_activate_action_full: procedure(remote: PGRemoteActionGroup; action_name: Pgchar; parameter: PGVariant; platform_data: PGVariant); cdecl; g_remote_action_group_change_action_state_full: procedure(remote: PGRemoteActionGroup; action_name: Pgchar; value: PGVariant; platform_data: PGVariant); cdecl; g_remote_action_group_get_type: function:TGType; cdecl; g_resolver_error_quark: function: TGQuark; cdecl; g_resolver_free_addresses: procedure(addresses: PGList); cdecl; g_resolver_free_targets: procedure(targets: PGList); cdecl; g_resolver_get_default: function: PGResolver; cdecl; g_resolver_get_type: function:TGType; cdecl; g_resolver_lookup_by_address: function(resolver: PGResolver; address: PGInetAddress; cancellable: PGCancellable; error: PPGError): Pgchar; cdecl; g_resolver_lookup_by_address_async: procedure(resolver: PGResolver; address: PGInetAddress; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_resolver_lookup_by_address_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): Pgchar; cdecl; g_resolver_lookup_by_name: function(resolver: PGResolver; hostname: Pgchar; cancellable: PGCancellable; error: PPGError): PGList; cdecl; g_resolver_lookup_by_name_async: procedure(resolver: PGResolver; hostname: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_resolver_lookup_by_name_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): PGList; cdecl; g_resolver_lookup_records: function(resolver: PGResolver; rrname: Pgchar; record_type: TGResolverRecordType; cancellable: PGCancellable; error: PPGError): PGList; cdecl; g_resolver_lookup_records_async: procedure(resolver: PGResolver; rrname: Pgchar; record_type: TGResolverRecordType; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_resolver_lookup_records_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): PGList; cdecl; g_resolver_lookup_service: function(resolver: PGResolver; service: Pgchar; protocol: Pgchar; domain: Pgchar; cancellable: PGCancellable; error: PPGError): PGList; cdecl; g_resolver_lookup_service_async: procedure(resolver: PGResolver; service: Pgchar; protocol: Pgchar; domain: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_resolver_lookup_service_finish: function(resolver: PGResolver; result_: PGAsyncResult; error: PPGError): PGList; cdecl; g_resolver_set_default: procedure(resolver: PGResolver); cdecl; g_resource_enumerate_children: function(resource: PGResource; path: Pgchar; lookup_flags: TGResourceLookupFlags; error: PPGError): PPgchar; cdecl; g_resource_error_quark: function: TGQuark; cdecl; g_resource_get_info: function(resource: PGResource; path: Pgchar; lookup_flags: TGResourceLookupFlags; size: Pgsize; flags: Pguint32; error: PPGError): gboolean; cdecl; g_resource_get_type: function:TGType; cdecl; g_resource_load: function(filename: Pgchar; error: PPGError): PGResource; cdecl; g_resource_lookup_data: function(resource: PGResource; path: Pgchar; lookup_flags: TGResourceLookupFlags; error: PPGError): PGBytes; cdecl; g_resource_new_from_data: function(data: PGBytes; error: PPGError): PGResource; cdecl; g_resource_open_stream: function(resource: PGResource; path: Pgchar; lookup_flags: TGResourceLookupFlags; error: PPGError): PGInputStream; cdecl; g_resource_ref: function(resource: PGResource): PGResource; cdecl; g_resource_unref: procedure(resource: PGResource); cdecl; g_resources_enumerate_children: function(path: Pgchar; lookup_flags: TGResourceLookupFlags; error: PPGError): PPgchar; cdecl; g_resources_get_info: function(path: Pgchar; lookup_flags: TGResourceLookupFlags; size: Pgsize; flags: Pguint32; error: PPGError): gboolean; cdecl; g_resources_lookup_data: function(path: Pgchar; lookup_flags: TGResourceLookupFlags; error: PPGError): PGBytes; cdecl; g_resources_open_stream: function(path: Pgchar; lookup_flags: TGResourceLookupFlags; error: PPGError): PGInputStream; cdecl; g_resources_register: procedure(resource: PGResource); cdecl; g_resources_unregister: procedure(resource: PGResource); cdecl; g_seekable_can_seek: function(seekable: PGSeekable): gboolean; cdecl; g_seekable_can_truncate: function(seekable: PGSeekable): gboolean; cdecl; g_seekable_get_type: function:TGType; cdecl; g_seekable_seek: function(seekable: PGSeekable; offset: gint64; type_: TGSeekType; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_seekable_tell: function(seekable: PGSeekable): gint64; cdecl; g_seekable_truncate: function(seekable: PGSeekable; offset: gint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_settings_apply: procedure(settings: PGSettings); cdecl; g_settings_bind: procedure(settings: PGSettings; key: Pgchar; object_: PGObject; property_: Pgchar; flags: TGSettingsBindFlags); cdecl; g_settings_bind_with_mapping: procedure(settings: PGSettings; key: Pgchar; object_: PGObject; property_: Pgchar; flags: TGSettingsBindFlags; get_mapping: TGSettingsBindGetMapping; set_mapping: TGSettingsBindSetMapping; user_data: gpointer; destroy_: TGDestroyNotify); cdecl; g_settings_bind_writable: procedure(settings: PGSettings; key: Pgchar; object_: PGObject; property_: Pgchar; inverted: gboolean); cdecl; g_settings_create_action: function(settings: PGSettings; key: Pgchar): PGAction; cdecl; g_settings_delay: procedure(settings: PGSettings); cdecl; g_settings_get: procedure(settings: PGSettings; key: Pgchar; format: Pgchar; args: array of const); cdecl; g_settings_get_boolean: function(settings: PGSettings; key: Pgchar): gboolean; cdecl; g_settings_get_child: function(settings: PGSettings; name: Pgchar): PGSettings; cdecl; g_settings_get_double: function(settings: PGSettings; key: Pgchar): gdouble; cdecl; g_settings_get_enum: function(settings: PGSettings; key: Pgchar): gint; cdecl; g_settings_get_flags: function(settings: PGSettings; key: Pgchar): guint; cdecl; g_settings_get_has_unapplied: function(settings: PGSettings): gboolean; cdecl; g_settings_get_int: function(settings: PGSettings; key: Pgchar): gint; cdecl; g_settings_get_mapped: function(settings: PGSettings; key: Pgchar; mapping: TGSettingsGetMapping; user_data: gpointer): gpointer; cdecl; g_settings_get_range: function(settings: PGSettings; key: Pgchar): PGVariant; cdecl; g_settings_get_string: function(settings: PGSettings; key: Pgchar): Pgchar; cdecl; g_settings_get_strv: function(settings: PGSettings; key: Pgchar): PPgchar; cdecl; g_settings_get_type: function:TGType; cdecl; g_settings_get_uint: function(settings: PGSettings; key: Pgchar): guint; cdecl; g_settings_get_value: function(settings: PGSettings; key: Pgchar): PGVariant; cdecl; g_settings_is_writable: function(settings: PGSettings; name: Pgchar): gboolean; cdecl; g_settings_list_children: function(settings: PGSettings): PPgchar; cdecl; g_settings_list_keys: function(settings: PGSettings): PPgchar; cdecl; g_settings_list_relocatable_schemas: function: PPgchar; cdecl; g_settings_list_schemas: function: PPgchar; cdecl; g_settings_new: function(schema_id: Pgchar): PGSettings; cdecl; g_settings_new_full: function(schema: PGSettingsSchema; backend: PGSettingsBackend; path: Pgchar): PGSettings; cdecl; g_settings_new_with_backend: function(schema_id: Pgchar; backend: PGSettingsBackend): PGSettings; cdecl; g_settings_new_with_backend_and_path: function(schema_id: Pgchar; backend: PGSettingsBackend; path: Pgchar): PGSettings; cdecl; g_settings_new_with_path: function(schema_id: Pgchar; path: Pgchar): PGSettings; cdecl; g_settings_range_check: function(settings: PGSettings; key: Pgchar; value: PGVariant): gboolean; cdecl; g_settings_reset: procedure(settings: PGSettings; key: Pgchar); cdecl; g_settings_revert: procedure(settings: PGSettings); cdecl; g_settings_schema_get_id: function(schema: PGSettingsSchema): Pgchar; cdecl; g_settings_schema_get_path: function(schema: PGSettingsSchema): Pgchar; cdecl; g_settings_schema_get_type: function:TGType; cdecl; g_settings_schema_ref: function(schema: PGSettingsSchema): PGSettingsSchema; cdecl; g_settings_schema_source_get_default: function: PGSettingsSchemaSource; cdecl; g_settings_schema_source_get_type: function:TGType; cdecl; g_settings_schema_source_lookup: function(source: PGSettingsSchemaSource; schema_id: Pgchar; recursive: gboolean): PGSettingsSchema; cdecl; g_settings_schema_source_new_from_directory: function(directory: Pgchar; parent: PGSettingsSchemaSource; trusted: gboolean; error: PPGError): PGSettingsSchemaSource; cdecl; g_settings_schema_source_ref: function(source: PGSettingsSchemaSource): PGSettingsSchemaSource; cdecl; g_settings_schema_source_unref: procedure(source: PGSettingsSchemaSource); cdecl; g_settings_schema_unref: procedure(schema: PGSettingsSchema); cdecl; g_settings_set: function(settings: PGSettings; key: Pgchar; format: Pgchar; args: array of const): gboolean; cdecl; g_settings_set_boolean: function(settings: PGSettings; key: Pgchar; value: gboolean): gboolean; cdecl; g_settings_set_double: function(settings: PGSettings; key: Pgchar; value: gdouble): gboolean; cdecl; g_settings_set_enum: function(settings: PGSettings; key: Pgchar; value: gint): gboolean; cdecl; g_settings_set_flags: function(settings: PGSettings; key: Pgchar; value: guint): gboolean; cdecl; g_settings_set_int: function(settings: PGSettings; key: Pgchar; value: gint): gboolean; cdecl; g_settings_set_string: function(settings: PGSettings; key: Pgchar; value: Pgchar): gboolean; cdecl; g_settings_set_strv: function(settings: PGSettings; key: Pgchar; value: PPgchar): gboolean; cdecl; g_settings_set_uint: function(settings: PGSettings; key: Pgchar; value: guint): gboolean; cdecl; g_settings_set_value: function(settings: PGSettings; key: Pgchar; value: PGVariant): gboolean; cdecl; g_settings_sync: procedure; cdecl; g_settings_unbind: procedure(object_: gpointer; property_: Pgchar); cdecl; g_simple_action_get_type: function:TGType; cdecl; g_simple_action_group_add_entries: procedure(simple: PGSimpleActionGroup; entries: PGActionEntry; n_entries: gint; user_data: gpointer); cdecl; g_simple_action_group_get_type: function:TGType; cdecl; g_simple_action_group_insert: procedure(simple: PGSimpleActionGroup; action: PGAction); cdecl; g_simple_action_group_lookup: function(simple: PGSimpleActionGroup; action_name: Pgchar): PGAction; cdecl; g_simple_action_group_new: function: PGSimpleActionGroup; cdecl; g_simple_action_group_remove: procedure(simple: PGSimpleActionGroup; action_name: Pgchar); cdecl; g_simple_action_new: function(name: Pgchar; parameter_type: PGVariantType): PGSimpleAction; cdecl; g_simple_action_new_stateful: function(name: Pgchar; parameter_type: PGVariantType; state: PGVariant): PGSimpleAction; cdecl; g_simple_action_set_enabled: procedure(simple: PGSimpleAction; enabled: gboolean); cdecl; g_simple_action_set_state: procedure(simple: PGSimpleAction; value: PGVariant); cdecl; g_simple_async_report_error_in_idle: procedure(object_: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; domain: TGQuark; code: gint; format: Pgchar; args: array of const); cdecl; g_simple_async_report_gerror_in_idle: procedure(object_: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; error: PGError); cdecl; g_simple_async_report_take_gerror_in_idle: procedure(object_: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; error: PGError); cdecl; g_simple_async_result_complete: procedure(simple: PGSimpleAsyncResult); cdecl; g_simple_async_result_complete_in_idle: procedure(simple: PGSimpleAsyncResult); cdecl; g_simple_async_result_get_op_res_gboolean: function(simple: PGSimpleAsyncResult): gboolean; cdecl; g_simple_async_result_get_op_res_gpointer: function(simple: PGSimpleAsyncResult): gpointer; cdecl; g_simple_async_result_get_op_res_gssize: function(simple: PGSimpleAsyncResult): gssize; cdecl; g_simple_async_result_get_source_tag: function(simple: PGSimpleAsyncResult): gpointer; cdecl; g_simple_async_result_get_type: function:TGType; cdecl; g_simple_async_result_is_valid: function(result_: PGAsyncResult; source: PGObject; source_tag: gpointer): gboolean; cdecl; g_simple_async_result_new: function(source_object: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; source_tag: gpointer): PGSimpleAsyncResult; cdecl; g_simple_async_result_new_error: function(source_object: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; domain: TGQuark; code: gint; format: Pgchar; args: array of const): PGSimpleAsyncResult; cdecl; g_simple_async_result_new_from_error: function(source_object: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; error: PGError): PGSimpleAsyncResult; cdecl; g_simple_async_result_new_take_error: function(source_object: PGObject; callback: TGAsyncReadyCallback; user_data: gpointer; error: PGError): PGSimpleAsyncResult; cdecl; g_simple_async_result_propagate_error: function(simple: PGSimpleAsyncResult; error: PPGError): gboolean; cdecl; g_simple_async_result_run_in_thread: procedure(simple: PGSimpleAsyncResult; func: TGSimpleAsyncThreadFunc; io_priority: gint; cancellable: PGCancellable); cdecl; g_simple_async_result_set_check_cancellable: procedure(simple: PGSimpleAsyncResult; check_cancellable: PGCancellable); cdecl; g_simple_async_result_set_error: procedure(simple: PGSimpleAsyncResult; domain: TGQuark; code: gint; format: Pgchar; args: array of const); cdecl; g_simple_async_result_set_error_va: procedure(simple: PGSimpleAsyncResult; domain: TGQuark; code: gint; format: Pgchar; args: Tva_list); cdecl; g_simple_async_result_set_from_error: procedure(simple: PGSimpleAsyncResult; error: PGError); cdecl; g_simple_async_result_set_handle_cancellation: procedure(simple: PGSimpleAsyncResult; handle_cancellation: gboolean); cdecl; g_simple_async_result_set_op_res_gboolean: procedure(simple: PGSimpleAsyncResult; op_res: gboolean); cdecl; g_simple_async_result_set_op_res_gpointer: procedure(simple: PGSimpleAsyncResult; op_res: gpointer; destroy_op_res: TGDestroyNotify); cdecl; g_simple_async_result_set_op_res_gssize: procedure(simple: PGSimpleAsyncResult; op_res: gssize); cdecl; g_simple_async_result_take_error: procedure(simple: PGSimpleAsyncResult; error: PGError); cdecl; g_simple_permission_get_type: function:TGType; cdecl; g_simple_permission_new: function(allowed: gboolean): PGSimplePermission; cdecl; g_simple_proxy_resolver_get_type: function:TGType; cdecl; g_simple_proxy_resolver_new: function(default_proxy: Pgchar; ignore_hosts: PPgchar): PGProxyResolver; cdecl; g_simple_proxy_resolver_set_default_proxy: procedure(resolver: PGSimpleProxyResolver; default_proxy: Pgchar); cdecl; g_simple_proxy_resolver_set_ignore_hosts: procedure(resolver: PGSimpleProxyResolver; ignore_hosts: PPgchar); cdecl; g_simple_proxy_resolver_set_uri_proxy: procedure(resolver: PGSimpleProxyResolver; uri_scheme: Pgchar; proxy: Pgchar); cdecl; g_socket_accept: function(socket: PGSocket; cancellable: PGCancellable; error: PPGError): PGSocket; cdecl; g_socket_address_enumerator_get_type: function:TGType; cdecl; g_socket_address_enumerator_next: function(enumerator: PGSocketAddressEnumerator; cancellable: PGCancellable; error: PPGError): PGSocketAddress; cdecl; g_socket_address_enumerator_next_async: procedure(enumerator: PGSocketAddressEnumerator; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_address_enumerator_next_finish: function(enumerator: PGSocketAddressEnumerator; result_: PGAsyncResult; error: PPGError): PGSocketAddress; cdecl; g_socket_address_get_family: function(address: PGSocketAddress): TGSocketFamily; cdecl; g_socket_address_get_native_size: function(address: PGSocketAddress): gssize; cdecl; g_socket_address_get_type: function:TGType; cdecl; g_socket_address_new_from_native: function(native: gpointer; len: gsize): PGSocketAddress; cdecl; g_socket_address_to_native: function(address: PGSocketAddress; dest: gpointer; destlen: gsize; error: PPGError): gboolean; cdecl; g_socket_bind: function(socket: PGSocket; address: PGSocketAddress; allow_reuse: gboolean; error: PPGError): gboolean; cdecl; g_socket_check_connect_result: function(socket: PGSocket; error: PPGError): gboolean; cdecl; g_socket_client_add_application_proxy: procedure(client: PGSocketClient; protocol: Pgchar); cdecl; g_socket_client_connect: function(client: PGSocketClient; connectable: PGSocketConnectable; cancellable: PGCancellable; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_async: procedure(client: PGSocketClient; connectable: PGSocketConnectable; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_client_connect_finish: function(client: PGSocketClient; result_: PGAsyncResult; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_to_host: function(client: PGSocketClient; host_and_port: Pgchar; default_port: guint16; cancellable: PGCancellable; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_to_host_async: procedure(client: PGSocketClient; host_and_port: Pgchar; default_port: guint16; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_client_connect_to_host_finish: function(client: PGSocketClient; result_: PGAsyncResult; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_to_service: function(client: PGSocketClient; domain: Pgchar; service: Pgchar; cancellable: PGCancellable; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_to_service_async: procedure(client: PGSocketClient; domain: Pgchar; service: Pgchar; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_client_connect_to_service_finish: function(client: PGSocketClient; result_: PGAsyncResult; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_to_uri: function(client: PGSocketClient; uri: Pgchar; default_port: guint16; cancellable: PGCancellable; error: PPGError): PGSocketConnection; cdecl; g_socket_client_connect_to_uri_async: procedure(client: PGSocketClient; uri: Pgchar; default_port: guint16; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_client_connect_to_uri_finish: function(client: PGSocketClient; result_: PGAsyncResult; error: PPGError): PGSocketConnection; cdecl; g_socket_client_get_enable_proxy: function(client: PGSocketClient): gboolean; cdecl; g_socket_client_get_family: function(client: PGSocketClient): TGSocketFamily; cdecl; g_socket_client_get_local_address: function(client: PGSocketClient): PGSocketAddress; cdecl; g_socket_client_get_protocol: function(client: PGSocketClient): TGSocketProtocol; cdecl; g_socket_client_get_proxy_resolver: function(client: PGSocketClient): PGProxyResolver; cdecl; g_socket_client_get_socket_type: function(client: PGSocketClient): TGSocketType; cdecl; g_socket_client_get_timeout: function(client: PGSocketClient): guint; cdecl; g_socket_client_get_tls: function(client: PGSocketClient): gboolean; cdecl; g_socket_client_get_tls_validation_flags: function(client: PGSocketClient): TGTlsCertificateFlags; cdecl; g_socket_client_get_type: function:TGType; cdecl; g_socket_client_new: function: PGSocketClient; cdecl; g_socket_client_set_enable_proxy: procedure(client: PGSocketClient; enable: gboolean); cdecl; g_socket_client_set_family: procedure(client: PGSocketClient; family: TGSocketFamily); cdecl; g_socket_client_set_local_address: procedure(client: PGSocketClient; address: PGSocketAddress); cdecl; g_socket_client_set_protocol: procedure(client: PGSocketClient; protocol: TGSocketProtocol); cdecl; g_socket_client_set_proxy_resolver: procedure(client: PGSocketClient; proxy_resolver: PGProxyResolver); cdecl; g_socket_client_set_socket_type: procedure(client: PGSocketClient; type_: TGSocketType); cdecl; g_socket_client_set_timeout: procedure(client: PGSocketClient; timeout: guint); cdecl; g_socket_client_set_tls: procedure(client: PGSocketClient; tls: gboolean); cdecl; g_socket_client_set_tls_validation_flags: procedure(client: PGSocketClient; flags: TGTlsCertificateFlags); cdecl; g_socket_close: function(socket: PGSocket; error: PPGError): gboolean; cdecl; g_socket_condition_check: function(socket: PGSocket; condition: TGIOCondition): TGIOCondition; cdecl; g_socket_condition_timed_wait: function(socket: PGSocket; condition: TGIOCondition; timeout: gint64; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_socket_condition_wait: function(socket: PGSocket; condition: TGIOCondition; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_socket_connect: function(socket: PGSocket; address: PGSocketAddress; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_socket_connectable_enumerate: function(connectable: PGSocketConnectable): PGSocketAddressEnumerator; cdecl; g_socket_connectable_get_type: function:TGType; cdecl; g_socket_connectable_proxy_enumerate: function(connectable: PGSocketConnectable): PGSocketAddressEnumerator; cdecl; g_socket_connection_connect: function(connection: PGSocketConnection; address: PGSocketAddress; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_socket_connection_connect_async: procedure(connection: PGSocketConnection; address: PGSocketAddress; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_connection_connect_finish: function(connection: PGSocketConnection; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_socket_connection_factory_create_connection: function(socket: PGSocket): PGSocketConnection; cdecl; g_socket_connection_factory_lookup_type: function(family: TGSocketFamily; type_: TGSocketType; protocol_id: gint): TGType; cdecl; g_socket_connection_factory_register_type: procedure(g_type: TGType; family: TGSocketFamily; type_: TGSocketType; protocol: gint); cdecl; g_socket_connection_get_local_address: function(connection: PGSocketConnection; error: PPGError): PGSocketAddress; cdecl; g_socket_connection_get_remote_address: function(connection: PGSocketConnection; error: PPGError): PGSocketAddress; cdecl; g_socket_connection_get_socket: function(connection: PGSocketConnection): PGSocket; cdecl; g_socket_connection_get_type: function:TGType; cdecl; g_socket_connection_is_connected: function(connection: PGSocketConnection): gboolean; cdecl; g_socket_control_message_deserialize: function(level: gint; type_: gint; size: gsize; data: guint8): PGSocketControlMessage; cdecl; g_socket_control_message_get_level: function(message: PGSocketControlMessage): gint; cdecl; g_socket_control_message_get_msg_type: function(message: PGSocketControlMessage): gint; cdecl; g_socket_control_message_get_size: function(message: PGSocketControlMessage): gsize; cdecl; g_socket_control_message_get_type: function:TGType; cdecl; g_socket_control_message_serialize: procedure(message: PGSocketControlMessage; data: gpointer); cdecl; g_socket_create_source: function(socket: PGSocket; condition: TGIOCondition; cancellable: PGCancellable): PGSource; cdecl; g_socket_get_available_bytes: function(socket: PGSocket): gssize; cdecl; g_socket_get_blocking: function(socket: PGSocket): gboolean; cdecl; g_socket_get_broadcast: function(socket: PGSocket): gboolean; cdecl; g_socket_get_credentials: function(socket: PGSocket; error: PPGError): PGCredentials; cdecl; g_socket_get_family: function(socket: PGSocket): TGSocketFamily; cdecl; g_socket_get_fd: function(socket: PGSocket): gint; cdecl; g_socket_get_keepalive: function(socket: PGSocket): gboolean; cdecl; g_socket_get_listen_backlog: function(socket: PGSocket): gint; cdecl; g_socket_get_local_address: function(socket: PGSocket; error: PPGError): PGSocketAddress; cdecl; g_socket_get_multicast_loopback: function(socket: PGSocket): gboolean; cdecl; g_socket_get_multicast_ttl: function(socket: PGSocket): guint; cdecl; g_socket_get_option: function(socket: PGSocket; level: gint; optname: gint; value: Pgint; error: PPGError): gboolean; cdecl; g_socket_get_protocol: function(socket: PGSocket): TGSocketProtocol; cdecl; g_socket_get_remote_address: function(socket: PGSocket; error: PPGError): PGSocketAddress; cdecl; g_socket_get_socket_type: function(socket: PGSocket): TGSocketType; cdecl; g_socket_get_timeout: function(socket: PGSocket): guint; cdecl; g_socket_get_ttl: function(socket: PGSocket): guint; cdecl; g_socket_get_type: function:TGType; cdecl; g_socket_is_closed: function(socket: PGSocket): gboolean; cdecl; g_socket_is_connected: function(socket: PGSocket): gboolean; cdecl; g_socket_join_multicast_group: function(socket: PGSocket; group: PGInetAddress; source_specific: gboolean; iface: Pgchar; error: PPGError): gboolean; cdecl; g_socket_leave_multicast_group: function(socket: PGSocket; group: PGInetAddress; source_specific: gboolean; iface: Pgchar; error: PPGError): gboolean; cdecl; g_socket_listen: function(socket: PGSocket; error: PPGError): gboolean; cdecl; g_socket_listener_accept: function(listener: PGSocketListener; source_object: PPGObject; cancellable: PGCancellable; error: PPGError): PGSocketConnection; cdecl; g_socket_listener_accept_async: procedure(listener: PGSocketListener; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_listener_accept_finish: function(listener: PGSocketListener; result_: PGAsyncResult; source_object: PPGObject; error: PPGError): PGSocketConnection; cdecl; g_socket_listener_accept_socket: function(listener: PGSocketListener; source_object: PPGObject; cancellable: PGCancellable; error: PPGError): PGSocket; cdecl; g_socket_listener_accept_socket_async: procedure(listener: PGSocketListener; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_socket_listener_accept_socket_finish: function(listener: PGSocketListener; result_: PGAsyncResult; source_object: PPGObject; error: PPGError): PGSocket; cdecl; g_socket_listener_add_address: function(listener: PGSocketListener; address: PGSocketAddress; type_: TGSocketType; protocol: TGSocketProtocol; source_object: PGObject; effective_address: PPGSocketAddress; error: PPGError): gboolean; cdecl; g_socket_listener_add_any_inet_port: function(listener: PGSocketListener; source_object: PGObject; error: PPGError): guint16; cdecl; g_socket_listener_add_inet_port: function(listener: PGSocketListener; port: guint16; source_object: PGObject; error: PPGError): gboolean; cdecl; g_socket_listener_add_socket: function(listener: PGSocketListener; socket: PGSocket; source_object: PGObject; error: PPGError): gboolean; cdecl; g_socket_listener_close: procedure(listener: PGSocketListener); cdecl; g_socket_listener_get_type: function:TGType; cdecl; g_socket_listener_new: function: PGSocketListener; cdecl; g_socket_listener_set_backlog: procedure(listener: PGSocketListener; listen_backlog: gint); cdecl; g_socket_new: function(family: TGSocketFamily; type_: TGSocketType; protocol: TGSocketProtocol; error: PPGError): PGSocket; cdecl; g_socket_new_from_fd: function(fd: gint; error: PPGError): PGSocket; cdecl; g_socket_receive: function(socket: PGSocket; buffer: Pgchar; size: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_receive_from: function(socket: PGSocket; address: PPGSocketAddress; buffer: Pgchar; size: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_receive_message: function(socket: PGSocket; address: PPGSocketAddress; vectors: PGInputVector; num_vectors: gint; messages: PPPGSocketControlMessage; num_messages: Pgint; flags: Pgint; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_receive_with_blocking: function(socket: PGSocket; buffer: Pgchar; size: gsize; blocking: gboolean; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_send: function(socket: PGSocket; buffer: Pgchar; size: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_send_message: function(socket: PGSocket; address: PGSocketAddress; vectors: PGOutputVector; num_vectors: gint; messages: PPGSocketControlMessage; num_messages: gint; flags: gint; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_send_to: function(socket: PGSocket; address: PGSocketAddress; buffer: Pgchar; size: gsize; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_send_with_blocking: function(socket: PGSocket; buffer: Pgchar; size: gsize; blocking: gboolean; cancellable: PGCancellable; error: PPGError): gssize; cdecl; g_socket_service_get_type: function:TGType; cdecl; g_socket_service_is_active: function(service: PGSocketService): gboolean; cdecl; g_socket_service_new: function: PGSocketService; cdecl; g_socket_service_start: procedure(service: PGSocketService); cdecl; g_socket_service_stop: procedure(service: PGSocketService); cdecl; g_socket_set_blocking: procedure(socket: PGSocket; blocking: gboolean); cdecl; g_socket_set_broadcast: procedure(socket: PGSocket; broadcast: gboolean); cdecl; g_socket_set_keepalive: procedure(socket: PGSocket; keepalive: gboolean); cdecl; g_socket_set_listen_backlog: procedure(socket: PGSocket; backlog: gint); cdecl; g_socket_set_multicast_loopback: procedure(socket: PGSocket; loopback: gboolean); cdecl; g_socket_set_multicast_ttl: procedure(socket: PGSocket; ttl: guint); cdecl; g_socket_set_option: function(socket: PGSocket; level: gint; optname: gint; value: gint; error: PPGError): gboolean; cdecl; g_socket_set_timeout: procedure(socket: PGSocket; timeout: guint); cdecl; g_socket_set_ttl: procedure(socket: PGSocket; ttl: guint); cdecl; g_socket_shutdown: function(socket: PGSocket; shutdown_read: gboolean; shutdown_write: gboolean; error: PPGError): gboolean; cdecl; g_socket_speaks_ipv4: function(socket: PGSocket): gboolean; cdecl; g_srv_target_copy: function(target: PGSrvTarget): PGSrvTarget; cdecl; g_srv_target_free: procedure(target: PGSrvTarget); cdecl; g_srv_target_get_hostname: function(target: PGSrvTarget): Pgchar; cdecl; g_srv_target_get_port: function(target: PGSrvTarget): guint16; cdecl; g_srv_target_get_priority: function(target: PGSrvTarget): guint16; cdecl; g_srv_target_get_type: function:TGType; cdecl; g_srv_target_get_weight: function(target: PGSrvTarget): guint16; cdecl; g_srv_target_list_sort: function(targets: PGList): PGList; cdecl; g_srv_target_new: function(hostname: Pgchar; port: guint16; priority: guint16; weight: guint16): PGSrvTarget; cdecl; g_static_resource_fini: procedure(static_resource: PGStaticResource); cdecl; g_static_resource_get_resource: function(static_resource: PGStaticResource): PGResource; cdecl; g_static_resource_init: procedure(static_resource: PGStaticResource); cdecl; g_task_attach_source: procedure(task: PGTask; source: PGSource; callback: TGSourceFunc); cdecl; g_task_get_cancellable: function(task: PGTask): PGCancellable; cdecl; g_task_get_check_cancellable: function(task: PGTask): gboolean; cdecl; g_task_get_context: function(task: PGTask): PGMainContext; cdecl; g_task_get_priority: function(task: PGTask): gint; cdecl; g_task_get_return_on_cancel: function(task: PGTask): gboolean; cdecl; g_task_get_source_object: function(task: PGTask): PGObject; cdecl; g_task_get_source_tag: function(task: PGTask): gpointer; cdecl; g_task_get_task_data: function(task: PGTask): gpointer; cdecl; g_task_get_type: function:TGType; cdecl; g_task_had_error: function(task: PGTask): gboolean; cdecl; g_task_is_valid: function(result_: PGAsyncResult; source_object: PGObject): gboolean; cdecl; g_task_new: function(source_object: PGObject; cancellable: PGCancellable; callback: TGAsyncReadyCallback; callback_data: gpointer): PGTask; cdecl; g_task_propagate_boolean: function(task: PGTask; error: PPGError): gboolean; cdecl; g_task_propagate_int: function(task: PGTask; error: PPGError): gssize; cdecl; g_task_propagate_pointer: function(task: PGTask; error: PPGError): gpointer; cdecl; g_task_report_error: procedure(source_object: PGObject; callback: TGAsyncReadyCallback; callback_data: gpointer; source_tag: gpointer; error: PGError); cdecl; g_task_report_new_error: procedure(source_object: PGObject; callback: TGAsyncReadyCallback; callback_data: gpointer; source_tag: gpointer; domain: TGQuark; code: gint; format: Pgchar; args: array of const); cdecl; g_task_return_boolean: procedure(task: PGTask; result_: gboolean); cdecl; g_task_return_error: procedure(task: PGTask; error: PGError); cdecl; g_task_return_error_if_cancelled: function(task: PGTask): gboolean; cdecl; g_task_return_int: procedure(task: PGTask; result_: gssize); cdecl; g_task_return_new_error: procedure(task: PGTask; domain: TGQuark; code: gint; format: Pgchar; args: array of const); cdecl; g_task_return_pointer: procedure(task: PGTask; result_: gpointer; result_destroy: TGDestroyNotify); cdecl; g_task_run_in_thread: procedure(task: PGTask; task_func: TGTaskThreadFunc); cdecl; g_task_run_in_thread_sync: procedure(task: PGTask; task_func: TGTaskThreadFunc); cdecl; g_task_set_check_cancellable: procedure(task: PGTask; check_cancellable: gboolean); cdecl; g_task_set_priority: procedure(task: PGTask; priority: gint); cdecl; g_task_set_return_on_cancel: function(task: PGTask; return_on_cancel: gboolean): gboolean; cdecl; g_task_set_source_tag: procedure(task: PGTask; source_tag: gpointer); cdecl; g_task_set_task_data: procedure(task: PGTask; task_data: gpointer; task_data_destroy: TGDestroyNotify); cdecl; g_tcp_connection_get_graceful_disconnect: function(connection: PGTcpConnection): gboolean; cdecl; g_tcp_connection_get_type: function:TGType; cdecl; g_tcp_connection_set_graceful_disconnect: procedure(connection: PGTcpConnection; graceful_disconnect: gboolean); cdecl; g_tcp_wrapper_connection_get_base_io_stream: function(conn: PGTcpWrapperConnection): PGIOStream; cdecl; g_tcp_wrapper_connection_get_type: function:TGType; cdecl; g_tcp_wrapper_connection_new: function(base_io_stream: PGIOStream; socket: PGSocket): PGTcpWrapperConnection; cdecl; g_test_dbus_add_service_dir: procedure(self: PGTestDBus; path: Pgchar); cdecl; g_test_dbus_down: procedure(self: PGTestDBus); cdecl; g_test_dbus_get_bus_address: function(self: PGTestDBus): Pgchar; cdecl; g_test_dbus_get_flags: function(self: PGTestDBus): TGTestDBusFlags; cdecl; g_test_dbus_get_type: function:TGType; cdecl; g_test_dbus_new: function(flags: TGTestDBusFlags): PGTestDBus; cdecl; g_test_dbus_stop: procedure(self: PGTestDBus); cdecl; g_test_dbus_unset: procedure; cdecl; g_test_dbus_up: procedure(self: PGTestDBus); cdecl; g_themed_icon_append_name: procedure(icon: PGThemedIcon; iconname: Pgchar); cdecl; g_themed_icon_get_names: function(icon: PGThemedIcon): PPgchar; cdecl; g_themed_icon_get_type: function:TGType; cdecl; g_themed_icon_new: function(iconname: Pgchar): PGThemedIcon; cdecl; g_themed_icon_new_from_names: function(iconnames: PPgchar; len: gint): PGThemedIcon; cdecl; g_themed_icon_new_with_default_fallbacks: function(iconname: Pgchar): PGThemedIcon; cdecl; g_themed_icon_prepend_name: procedure(icon: PGThemedIcon; iconname: Pgchar); cdecl; g_threaded_socket_service_get_type: function:TGType; cdecl; g_threaded_socket_service_new: function(max_threads: gint): PGThreadedSocketService; cdecl; g_tls_backend_get_certificate_type: function(backend: PGTlsBackend): TGType; cdecl; g_tls_backend_get_client_connection_type: function(backend: PGTlsBackend): TGType; cdecl; g_tls_backend_get_default: function: PGTlsBackend; cdecl; g_tls_backend_get_default_database: function(backend: PGTlsBackend): PGTlsDatabase; cdecl; g_tls_backend_get_file_database_type: function(backend: PGTlsBackend): TGType; cdecl; g_tls_backend_get_server_connection_type: function(backend: PGTlsBackend): TGType; cdecl; g_tls_backend_get_type: function:TGType; cdecl; g_tls_backend_supports_tls: function(backend: PGTlsBackend): gboolean; cdecl; g_tls_certificate_get_issuer: function(cert: PGTlsCertificate): PGTlsCertificate; cdecl; g_tls_certificate_get_type: function:TGType; cdecl; g_tls_certificate_is_same: function(cert_one: PGTlsCertificate; cert_two: PGTlsCertificate): gboolean; cdecl; g_tls_certificate_list_new_from_file: function(file_: Pgchar; error: PPGError): PGList; cdecl; g_tls_certificate_new_from_file: function(file_: Pgchar; error: PPGError): PGTlsCertificate; cdecl; g_tls_certificate_new_from_files: function(cert_file: Pgchar; key_file: Pgchar; error: PPGError): PGTlsCertificate; cdecl; g_tls_certificate_new_from_pem: function(data: Pgchar; length: gssize; error: PPGError): PGTlsCertificate; cdecl; g_tls_certificate_verify: function(cert: PGTlsCertificate; identity: PGSocketConnectable; trusted_ca: PGTlsCertificate): TGTlsCertificateFlags; cdecl; g_tls_client_connection_get_accepted_cas: function(conn: PGTlsClientConnection): PGList; cdecl; g_tls_client_connection_get_server_identity: function(conn: PGTlsClientConnection): PGSocketConnectable; cdecl; g_tls_client_connection_get_type: function:TGType; cdecl; g_tls_client_connection_get_use_ssl3: function(conn: PGTlsClientConnection): gboolean; cdecl; g_tls_client_connection_get_validation_flags: function(conn: PGTlsClientConnection): TGTlsCertificateFlags; cdecl; g_tls_client_connection_new: function(base_io_stream: PGIOStream; server_identity: PGSocketConnectable; error: PPGError): PGTlsClientConnection; cdecl; g_tls_client_connection_set_server_identity: procedure(conn: PGTlsClientConnection; identity: PGSocketConnectable); cdecl; g_tls_client_connection_set_use_ssl3: procedure(conn: PGTlsClientConnection; use_ssl3: gboolean); cdecl; g_tls_client_connection_set_validation_flags: procedure(conn: PGTlsClientConnection; flags: TGTlsCertificateFlags); cdecl; g_tls_connection_emit_accept_certificate: function(conn: PGTlsConnection; peer_cert: PGTlsCertificate; errors: TGTlsCertificateFlags): gboolean; cdecl; g_tls_connection_get_certificate: function(conn: PGTlsConnection): PGTlsCertificate; cdecl; g_tls_connection_get_database: function(conn: PGTlsConnection): PGTlsDatabase; cdecl; g_tls_connection_get_interaction: function(conn: PGTlsConnection): PGTlsInteraction; cdecl; g_tls_connection_get_peer_certificate: function(conn: PGTlsConnection): PGTlsCertificate; cdecl; g_tls_connection_get_peer_certificate_errors: function(conn: PGTlsConnection): TGTlsCertificateFlags; cdecl; g_tls_connection_get_rehandshake_mode: function(conn: PGTlsConnection): TGTlsRehandshakeMode; cdecl; g_tls_connection_get_require_close_notify: function(conn: PGTlsConnection): gboolean; cdecl; g_tls_connection_get_type: function:TGType; cdecl; g_tls_connection_handshake: function(conn: PGTlsConnection; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_tls_connection_handshake_async: procedure(conn: PGTlsConnection; io_priority: gint; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_tls_connection_handshake_finish: function(conn: PGTlsConnection; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_tls_connection_set_certificate: procedure(conn: PGTlsConnection; certificate: PGTlsCertificate); cdecl; g_tls_connection_set_database: procedure(conn: PGTlsConnection; database: PGTlsDatabase); cdecl; g_tls_connection_set_interaction: procedure(conn: PGTlsConnection; interaction: PGTlsInteraction); cdecl; g_tls_connection_set_rehandshake_mode: procedure(conn: PGTlsConnection; mode: TGTlsRehandshakeMode); cdecl; g_tls_connection_set_require_close_notify: procedure(conn: PGTlsConnection; require_close_notify: gboolean); cdecl; g_tls_database_create_certificate_handle: function(self: PGTlsDatabase; certificate: PGTlsCertificate): Pgchar; cdecl; g_tls_database_get_type: function:TGType; cdecl; g_tls_database_lookup_certificate_for_handle: function(self: PGTlsDatabase; handle: Pgchar; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; error: PPGError): PGTlsCertificate; cdecl; g_tls_database_lookup_certificate_for_handle_async: procedure(self: PGTlsDatabase; handle: Pgchar; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_tls_database_lookup_certificate_for_handle_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): PGTlsCertificate; cdecl; g_tls_database_lookup_certificate_issuer: function(self: PGTlsDatabase; certificate: PGTlsCertificate; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; error: PPGError): PGTlsCertificate; cdecl; g_tls_database_lookup_certificate_issuer_async: procedure(self: PGTlsDatabase; certificate: PGTlsCertificate; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_tls_database_lookup_certificate_issuer_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): PGTlsCertificate; cdecl; g_tls_database_lookup_certificates_issued_by: function(self: PGTlsDatabase; issuer_raw_dn: Pguint8; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; error: PPGError): PGList; cdecl; g_tls_database_lookup_certificates_issued_by_async: procedure(self: PGTlsDatabase; issuer_raw_dn: Pguint8; interaction: PGTlsInteraction; flags: TGTlsDatabaseLookupFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_tls_database_lookup_certificates_issued_by_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): PGList; cdecl; g_tls_database_verify_chain: function(self: PGTlsDatabase; chain: PGTlsCertificate; purpose: Pgchar; identity: PGSocketConnectable; interaction: PGTlsInteraction; flags: TGTlsDatabaseVerifyFlags; cancellable: PGCancellable; error: PPGError): TGTlsCertificateFlags; cdecl; g_tls_database_verify_chain_async: procedure(self: PGTlsDatabase; chain: PGTlsCertificate; purpose: Pgchar; identity: PGSocketConnectable; interaction: PGTlsInteraction; flags: TGTlsDatabaseVerifyFlags; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_tls_database_verify_chain_finish: function(self: PGTlsDatabase; result_: PGAsyncResult; error: PPGError): TGTlsCertificateFlags; cdecl; g_tls_error_quark: function: TGQuark; cdecl; g_tls_file_database_get_type: function:TGType; cdecl; g_tls_file_database_new: function(anchors: Pgchar; error: PPGError): PGTlsFileDatabase; cdecl; g_tls_interaction_ask_password: function(interaction: PGTlsInteraction; password: PGTlsPassword; cancellable: PGCancellable; error: PPGError): TGTlsInteractionResult; cdecl; g_tls_interaction_ask_password_async: procedure(interaction: PGTlsInteraction; password: PGTlsPassword; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_tls_interaction_ask_password_finish: function(interaction: PGTlsInteraction; result_: PGAsyncResult; error: PPGError): TGTlsInteractionResult; cdecl; g_tls_interaction_get_type: function:TGType; cdecl; g_tls_interaction_invoke_ask_password: function(interaction: PGTlsInteraction; password: PGTlsPassword; cancellable: PGCancellable; error: PPGError): TGTlsInteractionResult; cdecl; g_tls_password_get_description: function(password: PGTlsPassword): Pgchar; cdecl; g_tls_password_get_flags: function(password: PGTlsPassword): TGTlsPasswordFlags; cdecl; g_tls_password_get_type: function:TGType; cdecl; g_tls_password_get_value: function(password: PGTlsPassword; length: Pgsize): Pguint8; cdecl; g_tls_password_get_warning: function(password: PGTlsPassword): Pgchar; cdecl; g_tls_password_new: function(flags: TGTlsPasswordFlags; description: Pgchar): PGTlsPassword; cdecl; g_tls_password_set_description: procedure(password: PGTlsPassword; description: Pgchar); cdecl; g_tls_password_set_flags: procedure(password: PGTlsPassword; flags: TGTlsPasswordFlags); cdecl; g_tls_password_set_value: procedure(password: PGTlsPassword; value: Pguint8; length: gssize); cdecl; g_tls_password_set_value_full: procedure(password: PGTlsPassword; value: Pguint8; length: gssize; destroy_: TGDestroyNotify); cdecl; g_tls_password_set_warning: procedure(password: PGTlsPassword; warning: Pgchar); cdecl; g_tls_server_connection_get_type: function:TGType; cdecl; g_tls_server_connection_new: function(base_io_stream: PGIOStream; certificate: PGTlsCertificate; error: PPGError): PGTlsServerConnection; cdecl; g_unix_connection_get_type: function:TGType; cdecl; g_unix_connection_receive_credentials: function(connection: PGUnixConnection; cancellable: PGCancellable; error: PPGError): PGCredentials; cdecl; g_unix_connection_receive_credentials_async: procedure(connection: PGUnixConnection; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_unix_connection_receive_credentials_finish: function(connection: PGUnixConnection; result_: PGAsyncResult; error: PPGError): PGCredentials; cdecl; g_unix_connection_receive_fd: function(connection: PGUnixConnection; cancellable: PGCancellable; error: PPGError): gint; cdecl; g_unix_connection_send_credentials: function(connection: PGUnixConnection; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_unix_connection_send_credentials_async: procedure(connection: PGUnixConnection; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_unix_connection_send_credentials_finish: function(connection: PGUnixConnection; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_unix_connection_send_fd: function(connection: PGUnixConnection; fd: gint; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; g_unix_credentials_message_get_credentials: function(message: PGUnixCredentialsMessage): PGCredentials; cdecl; g_unix_credentials_message_get_type: function:TGType; cdecl; g_unix_credentials_message_is_supported: function: gboolean; cdecl; g_unix_credentials_message_new: function: PGUnixCredentialsMessage; cdecl; g_unix_credentials_message_new_with_credentials: function(credentials: PGCredentials): PGUnixCredentialsMessage; cdecl; g_unix_fd_list_append: function(list: PGUnixFDList; fd: gint; error: PPGError): gint; cdecl; g_unix_fd_list_get: function(list: PGUnixFDList; index_: gint; error: PPGError): gint; cdecl; g_unix_fd_list_get_length: function(list: PGUnixFDList): gint; cdecl; g_unix_fd_list_get_type: function:TGType; cdecl; g_unix_fd_list_new: function: PGUnixFDList; cdecl; g_unix_fd_list_new_from_array: function(fds: Pgint; n_fds: gint): PGUnixFDList; cdecl; g_unix_fd_list_peek_fds: function(list: PGUnixFDList; length: Pgint): Pgint; cdecl; g_unix_fd_list_steal_fds: function(list: PGUnixFDList; length: Pgint): Pgint; cdecl; g_unix_fd_message_append_fd: function(message: PGUnixFDMessage; fd: gint; error: PPGError): gboolean; cdecl; g_unix_fd_message_get_fd_list: function(message: PGUnixFDMessage): PGUnixFDList; cdecl; g_unix_fd_message_get_type: function:TGType; cdecl; g_unix_fd_message_new: function: PGUnixFDMessage; cdecl; g_unix_fd_message_new_with_fd_list: function(fd_list: PGUnixFDList): PGUnixFDMessage; cdecl; g_unix_fd_message_steal_fds: function(message: PGUnixFDMessage; length: Pgint): Pgint; cdecl; g_unix_input_stream_get_close_fd: function(stream: PGUnixInputStream): gboolean; cdecl; g_unix_input_stream_get_fd: function(stream: PGUnixInputStream): gint; cdecl; g_unix_input_stream_get_type: function:TGType; cdecl; g_unix_input_stream_new: function(fd: gint; close_fd: gboolean): PGUnixInputStream; cdecl; g_unix_input_stream_set_close_fd: procedure(stream: PGUnixInputStream; close_fd: gboolean); cdecl; g_unix_is_mount_path_system_internal: function(mount_path: Pgchar): gboolean; cdecl; g_unix_mount_at: function(mount_path: Pgchar; time_read: Pguint64): PGUnixMountEntry; cdecl; g_unix_mount_compare: function(mount1: PGUnixMountEntry; mount2: PGUnixMountEntry): gint; cdecl; g_unix_mount_free: procedure(mount_entry: PGUnixMountEntry); cdecl; g_unix_mount_get_device_path: function(mount_entry: PGUnixMountEntry): Pgchar; cdecl; g_unix_mount_get_fs_type: function(mount_entry: PGUnixMountEntry): Pgchar; cdecl; g_unix_mount_get_mount_path: function(mount_entry: PGUnixMountEntry): Pgchar; cdecl; g_unix_mount_guess_can_eject: function(mount_entry: PGUnixMountEntry): gboolean; cdecl; g_unix_mount_guess_icon: function(mount_entry: PGUnixMountEntry): PGIcon; cdecl; g_unix_mount_guess_name: function(mount_entry: PGUnixMountEntry): Pgchar; cdecl; g_unix_mount_guess_should_display: function(mount_entry: PGUnixMountEntry): gboolean; cdecl; g_unix_mount_guess_symbolic_icon: function(mount_entry: PGUnixMountEntry): PGIcon; cdecl; g_unix_mount_is_readonly: function(mount_entry: PGUnixMountEntry): gboolean; cdecl; g_unix_mount_is_system_internal: function(mount_entry: PGUnixMountEntry): gboolean; cdecl; g_unix_mount_monitor_get_type: function:TGType; cdecl; g_unix_mount_monitor_new: function: PGUnixMountMonitor; cdecl; g_unix_mount_monitor_set_rate_limit: procedure(mount_monitor: PGUnixMountMonitor; limit_msec: gint); cdecl; g_unix_mount_point_compare: function(mount1: PGUnixMountPoint; mount2: PGUnixMountPoint): gint; cdecl; g_unix_mount_point_free: procedure(mount_point: PGUnixMountPoint); cdecl; g_unix_mount_point_get_device_path: function(mount_point: PGUnixMountPoint): Pgchar; cdecl; g_unix_mount_point_get_fs_type: function(mount_point: PGUnixMountPoint): Pgchar; cdecl; g_unix_mount_point_get_mount_path: function(mount_point: PGUnixMountPoint): Pgchar; cdecl; g_unix_mount_point_get_options: function(mount_point: PGUnixMountPoint): Pgchar; cdecl; g_unix_mount_point_guess_can_eject: function(mount_point: PGUnixMountPoint): gboolean; cdecl; g_unix_mount_point_guess_icon: function(mount_point: PGUnixMountPoint): PGIcon; cdecl; g_unix_mount_point_guess_name: function(mount_point: PGUnixMountPoint): Pgchar; cdecl; g_unix_mount_point_guess_symbolic_icon: function(mount_point: PGUnixMountPoint): PGIcon; cdecl; g_unix_mount_point_is_loopback: function(mount_point: PGUnixMountPoint): gboolean; cdecl; g_unix_mount_point_is_readonly: function(mount_point: PGUnixMountPoint): gboolean; cdecl; g_unix_mount_point_is_user_mountable: function(mount_point: PGUnixMountPoint): gboolean; cdecl; g_unix_mount_points_changed_since: function(time: guint64): gboolean; cdecl; g_unix_mount_points_get: function(time_read: Pguint64): PGList; cdecl; g_unix_mounts_changed_since: function(time: guint64): gboolean; cdecl; g_unix_mounts_get: function(time_read: Pguint64): PGList; cdecl; g_unix_output_stream_get_close_fd: function(stream: PGUnixOutputStream): gboolean; cdecl; g_unix_output_stream_get_fd: function(stream: PGUnixOutputStream): gint; cdecl; g_unix_output_stream_get_type: function:TGType; cdecl; g_unix_output_stream_new: function(fd: gint; close_fd: gboolean): PGUnixOutputStream; cdecl; g_unix_output_stream_set_close_fd: procedure(stream: PGUnixOutputStream; close_fd: gboolean); cdecl; g_unix_socket_address_abstract_names_supported: function: gboolean; cdecl; g_unix_socket_address_get_address_type: function(address: PGUnixSocketAddress): TGUnixSocketAddressType; cdecl; g_unix_socket_address_get_path: function(address: PGUnixSocketAddress): Pgchar; cdecl; g_unix_socket_address_get_path_len: function(address: PGUnixSocketAddress): gsize; cdecl; g_unix_socket_address_get_type: function:TGType; cdecl; g_unix_socket_address_new: function(path: Pgchar): PGUnixSocketAddress; cdecl; g_unix_socket_address_new_with_type: function(path: Pgchar; path_len: gint; type_: TGUnixSocketAddressType): PGUnixSocketAddress; cdecl; g_vfs_get_default: function: PGVfs; cdecl; g_vfs_get_file_for_path: function(vfs: PGVfs; path: Pgchar): PGFile; cdecl; g_vfs_get_file_for_uri: function(vfs: PGVfs; uri: Pgchar): PGFile; cdecl; g_vfs_get_local: function: PGVfs; cdecl; g_vfs_get_supported_uri_schemes: function(vfs: PGVfs): PPgchar; cdecl; g_vfs_get_type: function:TGType; cdecl; g_vfs_is_active: function(vfs: PGVfs): gboolean; cdecl; g_vfs_parse_name: function(vfs: PGVfs; parse_name: Pgchar): PGFile; cdecl; g_volume_can_eject: function(volume: PGVolume): gboolean; cdecl; g_volume_can_mount: function(volume: PGVolume): gboolean; cdecl; g_volume_eject_with_operation: procedure(volume: PGVolume; flags: TGMountUnmountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_volume_eject_with_operation_finish: function(volume: PGVolume; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_volume_enumerate_identifiers: function(volume: PGVolume): PPgchar; cdecl; g_volume_get_activation_root: function(volume: PGVolume): PGFile; cdecl; g_volume_get_drive: function(volume: PGVolume): PGDrive; cdecl; g_volume_get_icon: function(volume: PGVolume): PGIcon; cdecl; g_volume_get_identifier: function(volume: PGVolume; kind: Pgchar): Pgchar; cdecl; g_volume_get_mount: function(volume: PGVolume): PGMount; cdecl; g_volume_get_name: function(volume: PGVolume): Pgchar; cdecl; g_volume_get_sort_key: function(volume: PGVolume): Pgchar; cdecl; g_volume_get_symbolic_icon: function(volume: PGVolume): PGIcon; cdecl; g_volume_get_type: function:TGType; cdecl; g_volume_get_uuid: function(volume: PGVolume): Pgchar; cdecl; g_volume_monitor_get: function: PGVolumeMonitor; cdecl; g_volume_monitor_get_connected_drives: function(volume_monitor: PGVolumeMonitor): PGList; cdecl; g_volume_monitor_get_mount_for_uuid: function(volume_monitor: PGVolumeMonitor; uuid: Pgchar): PGMount; cdecl; g_volume_monitor_get_mounts: function(volume_monitor: PGVolumeMonitor): PGList; cdecl; g_volume_monitor_get_type: function:TGType; cdecl; g_volume_monitor_get_volume_for_uuid: function(volume_monitor: PGVolumeMonitor; uuid: Pgchar): PGVolume; cdecl; g_volume_monitor_get_volumes: function(volume_monitor: PGVolumeMonitor): PGList; cdecl; g_volume_mount: procedure(volume: PGVolume; flags: TGMountMountFlags; mount_operation: PGMountOperation; cancellable: PGCancellable; callback: TGAsyncReadyCallback; user_data: gpointer); cdecl; g_volume_mount_finish: function(volume: PGVolume; result_: PGAsyncResult; error: PPGError): gboolean; cdecl; g_volume_should_automount: function(volume: PGVolume): gboolean; cdecl; g_zlib_compressor_get_file_info: function(compressor: PGZlibCompressor): PGFileInfo; cdecl; g_zlib_compressor_get_type: function:TGType; cdecl; g_zlib_compressor_new: function(format: TGZlibCompressorFormat; level: gint): PGZlibCompressor; cdecl; g_zlib_compressor_set_file_info: procedure(compressor: PGZlibCompressor; file_info: PGFileInfo); cdecl; g_zlib_decompressor_get_file_info: function(decompressor: PGZlibDecompressor): PGFileInfo; cdecl; g_zlib_decompressor_get_type: function:TGType; cdecl; g_zlib_decompressor_new: function(format: TGZlibCompressorFormat): PGZlibDecompressor; cdecl; implementation uses DynLibs; var libgio_2_0_so_0: TLibHandle; procedure LoadLibraries; begin libgio_2_0_so_0 := SafeLoadLibrary('libgio-2.0.so.0'); end; procedure LoadProcs; procedure LoadProc(var AProc: Pointer; AName: String); var ProcPtr: Pointer; begin ProcPtr := GetProcedureAddress(libgio_2_0_so_0, AName); AProc := ProcPtr; end; begin LoadProc(Pointer(g_action_activate), 'g_action_activate'); LoadProc(Pointer(g_action_change_state), 'g_action_change_state'); LoadProc(Pointer(g_action_get_enabled), 'g_action_get_enabled'); LoadProc(Pointer(g_action_get_name), 'g_action_get_name'); LoadProc(Pointer(g_action_get_parameter_type), 'g_action_get_parameter_type'); LoadProc(Pointer(g_action_get_state), 'g_action_get_state'); LoadProc(Pointer(g_action_get_state_hint), 'g_action_get_state_hint'); LoadProc(Pointer(g_action_get_state_type), 'g_action_get_state_type'); LoadProc(Pointer(g_action_get_type), 'g_action_get_type'); LoadProc(Pointer(g_action_group_action_added), 'g_action_group_action_added'); LoadProc(Pointer(g_action_group_action_enabled_changed), 'g_action_group_action_enabled_changed'); LoadProc(Pointer(g_action_group_action_removed), 'g_action_group_action_removed'); LoadProc(Pointer(g_action_group_action_state_changed), 'g_action_group_action_state_changed'); LoadProc(Pointer(g_action_group_activate_action), 'g_action_group_activate_action'); LoadProc(Pointer(g_action_group_change_action_state), 'g_action_group_change_action_state'); LoadProc(Pointer(g_action_group_get_action_enabled), 'g_action_group_get_action_enabled'); LoadProc(Pointer(g_action_group_get_action_parameter_type), 'g_action_group_get_action_parameter_type'); LoadProc(Pointer(g_action_group_get_action_state), 'g_action_group_get_action_state'); LoadProc(Pointer(g_action_group_get_action_state_hint), 'g_action_group_get_action_state_hint'); LoadProc(Pointer(g_action_group_get_action_state_type), 'g_action_group_get_action_state_type'); LoadProc(Pointer(g_action_group_get_type), 'g_action_group_get_type'); LoadProc(Pointer(g_action_group_has_action), 'g_action_group_has_action'); LoadProc(Pointer(g_action_group_list_actions), 'g_action_group_list_actions'); LoadProc(Pointer(g_action_group_query_action), 'g_action_group_query_action'); LoadProc(Pointer(g_action_map_add_action), 'g_action_map_add_action'); LoadProc(Pointer(g_action_map_add_action_entries), 'g_action_map_add_action_entries'); LoadProc(Pointer(g_action_map_get_type), 'g_action_map_get_type'); LoadProc(Pointer(g_action_map_lookup_action), 'g_action_map_lookup_action'); LoadProc(Pointer(g_action_map_remove_action), 'g_action_map_remove_action'); LoadProc(Pointer(g_app_info_add_supports_type), 'g_app_info_add_supports_type'); LoadProc(Pointer(g_app_info_can_delete), 'g_app_info_can_delete'); LoadProc(Pointer(g_app_info_can_remove_supports_type), 'g_app_info_can_remove_supports_type'); LoadProc(Pointer(g_app_info_create_from_commandline), 'g_app_info_create_from_commandline'); LoadProc(Pointer(g_app_info_delete), 'g_app_info_delete'); LoadProc(Pointer(g_app_info_dup), 'g_app_info_dup'); LoadProc(Pointer(g_app_info_equal), 'g_app_info_equal'); LoadProc(Pointer(g_app_info_get_all), 'g_app_info_get_all'); LoadProc(Pointer(g_app_info_get_all_for_type), 'g_app_info_get_all_for_type'); LoadProc(Pointer(g_app_info_get_commandline), 'g_app_info_get_commandline'); LoadProc(Pointer(g_app_info_get_default_for_type), 'g_app_info_get_default_for_type'); LoadProc(Pointer(g_app_info_get_default_for_uri_scheme), 'g_app_info_get_default_for_uri_scheme'); LoadProc(Pointer(g_app_info_get_description), 'g_app_info_get_description'); LoadProc(Pointer(g_app_info_get_display_name), 'g_app_info_get_display_name'); LoadProc(Pointer(g_app_info_get_executable), 'g_app_info_get_executable'); LoadProc(Pointer(g_app_info_get_fallback_for_type), 'g_app_info_get_fallback_for_type'); LoadProc(Pointer(g_app_info_get_icon), 'g_app_info_get_icon'); LoadProc(Pointer(g_app_info_get_id), 'g_app_info_get_id'); LoadProc(Pointer(g_app_info_get_name), 'g_app_info_get_name'); LoadProc(Pointer(g_app_info_get_recommended_for_type), 'g_app_info_get_recommended_for_type'); LoadProc(Pointer(g_app_info_get_supported_types), 'g_app_info_get_supported_types'); LoadProc(Pointer(g_app_info_get_type), 'g_app_info_get_type'); LoadProc(Pointer(g_app_info_launch), 'g_app_info_launch'); LoadProc(Pointer(g_app_info_launch_default_for_uri), 'g_app_info_launch_default_for_uri'); LoadProc(Pointer(g_app_info_launch_uris), 'g_app_info_launch_uris'); LoadProc(Pointer(g_app_info_remove_supports_type), 'g_app_info_remove_supports_type'); LoadProc(Pointer(g_app_info_reset_type_associations), 'g_app_info_reset_type_associations'); LoadProc(Pointer(g_app_info_set_as_default_for_extension), 'g_app_info_set_as_default_for_extension'); LoadProc(Pointer(g_app_info_set_as_default_for_type), 'g_app_info_set_as_default_for_type'); LoadProc(Pointer(g_app_info_set_as_last_used_for_type), 'g_app_info_set_as_last_used_for_type'); LoadProc(Pointer(g_app_info_should_show), 'g_app_info_should_show'); LoadProc(Pointer(g_app_info_supports_files), 'g_app_info_supports_files'); LoadProc(Pointer(g_app_info_supports_uris), 'g_app_info_supports_uris'); LoadProc(Pointer(g_app_launch_context_get_display), 'g_app_launch_context_get_display'); LoadProc(Pointer(g_app_launch_context_get_environment), 'g_app_launch_context_get_environment'); LoadProc(Pointer(g_app_launch_context_get_startup_notify_id), 'g_app_launch_context_get_startup_notify_id'); LoadProc(Pointer(g_app_launch_context_get_type), 'g_app_launch_context_get_type'); LoadProc(Pointer(g_app_launch_context_launch_failed), 'g_app_launch_context_launch_failed'); LoadProc(Pointer(g_app_launch_context_new), 'g_app_launch_context_new'); LoadProc(Pointer(g_app_launch_context_setenv), 'g_app_launch_context_setenv'); LoadProc(Pointer(g_app_launch_context_unsetenv), 'g_app_launch_context_unsetenv'); LoadProc(Pointer(g_application_activate), 'g_application_activate'); LoadProc(Pointer(g_application_command_line_create_file_for_arg), 'g_application_command_line_create_file_for_arg'); LoadProc(Pointer(g_application_command_line_get_arguments), 'g_application_command_line_get_arguments'); LoadProc(Pointer(g_application_command_line_get_cwd), 'g_application_command_line_get_cwd'); LoadProc(Pointer(g_application_command_line_get_environ), 'g_application_command_line_get_environ'); LoadProc(Pointer(g_application_command_line_get_exit_status), 'g_application_command_line_get_exit_status'); LoadProc(Pointer(g_application_command_line_get_is_remote), 'g_application_command_line_get_is_remote'); LoadProc(Pointer(g_application_command_line_get_platform_data), 'g_application_command_line_get_platform_data'); LoadProc(Pointer(g_application_command_line_get_stdin), 'g_application_command_line_get_stdin'); LoadProc(Pointer(g_application_command_line_get_type), 'g_application_command_line_get_type'); LoadProc(Pointer(g_application_command_line_getenv), 'g_application_command_line_getenv'); LoadProc(Pointer(g_application_command_line_print), 'g_application_command_line_print'); LoadProc(Pointer(g_application_command_line_printerr), 'g_application_command_line_printerr'); LoadProc(Pointer(g_application_command_line_set_exit_status), 'g_application_command_line_set_exit_status'); LoadProc(Pointer(g_application_get_application_id), 'g_application_get_application_id'); LoadProc(Pointer(g_application_get_dbus_connection), 'g_application_get_dbus_connection'); LoadProc(Pointer(g_application_get_dbus_object_path), 'g_application_get_dbus_object_path'); LoadProc(Pointer(g_application_get_default), 'g_application_get_default'); LoadProc(Pointer(g_application_get_flags), 'g_application_get_flags'); LoadProc(Pointer(g_application_get_inactivity_timeout), 'g_application_get_inactivity_timeout'); LoadProc(Pointer(g_application_get_is_registered), 'g_application_get_is_registered'); LoadProc(Pointer(g_application_get_is_remote), 'g_application_get_is_remote'); LoadProc(Pointer(g_application_get_type), 'g_application_get_type'); LoadProc(Pointer(g_application_hold), 'g_application_hold'); LoadProc(Pointer(g_application_id_is_valid), 'g_application_id_is_valid'); LoadProc(Pointer(g_application_new), 'g_application_new'); LoadProc(Pointer(g_application_open), 'g_application_open'); LoadProc(Pointer(g_application_quit), 'g_application_quit'); LoadProc(Pointer(g_application_register), 'g_application_register'); LoadProc(Pointer(g_application_release), 'g_application_release'); LoadProc(Pointer(g_application_run), 'g_application_run'); LoadProc(Pointer(g_application_set_application_id), 'g_application_set_application_id'); LoadProc(Pointer(g_application_set_default), 'g_application_set_default'); LoadProc(Pointer(g_application_set_flags), 'g_application_set_flags'); LoadProc(Pointer(g_application_set_inactivity_timeout), 'g_application_set_inactivity_timeout'); LoadProc(Pointer(g_async_initable_get_type), 'g_async_initable_get_type'); LoadProc(Pointer(g_async_initable_init_async), 'g_async_initable_init_async'); LoadProc(Pointer(g_async_initable_init_finish), 'g_async_initable_init_finish'); LoadProc(Pointer(g_async_initable_new_async), 'g_async_initable_new_async'); LoadProc(Pointer(g_async_initable_new_finish), 'g_async_initable_new_finish'); LoadProc(Pointer(g_async_initable_new_valist_async), 'g_async_initable_new_valist_async'); LoadProc(Pointer(g_async_initable_newv_async), 'g_async_initable_newv_async'); LoadProc(Pointer(g_async_result_get_source_object), 'g_async_result_get_source_object'); LoadProc(Pointer(g_async_result_get_type), 'g_async_result_get_type'); LoadProc(Pointer(g_async_result_get_user_data), 'g_async_result_get_user_data'); LoadProc(Pointer(g_async_result_is_tagged), 'g_async_result_is_tagged'); LoadProc(Pointer(g_async_result_legacy_propagate_error), 'g_async_result_legacy_propagate_error'); LoadProc(Pointer(g_buffered_input_stream_fill), 'g_buffered_input_stream_fill'); LoadProc(Pointer(g_buffered_input_stream_fill_async), 'g_buffered_input_stream_fill_async'); LoadProc(Pointer(g_buffered_input_stream_fill_finish), 'g_buffered_input_stream_fill_finish'); LoadProc(Pointer(g_buffered_input_stream_get_available), 'g_buffered_input_stream_get_available'); LoadProc(Pointer(g_buffered_input_stream_get_buffer_size), 'g_buffered_input_stream_get_buffer_size'); LoadProc(Pointer(g_buffered_input_stream_get_type), 'g_buffered_input_stream_get_type'); LoadProc(Pointer(g_buffered_input_stream_new), 'g_buffered_input_stream_new'); LoadProc(Pointer(g_buffered_input_stream_new_sized), 'g_buffered_input_stream_new_sized'); LoadProc(Pointer(g_buffered_input_stream_peek), 'g_buffered_input_stream_peek'); LoadProc(Pointer(g_buffered_input_stream_peek_buffer), 'g_buffered_input_stream_peek_buffer'); LoadProc(Pointer(g_buffered_input_stream_read_byte), 'g_buffered_input_stream_read_byte'); LoadProc(Pointer(g_buffered_input_stream_set_buffer_size), 'g_buffered_input_stream_set_buffer_size'); LoadProc(Pointer(g_buffered_output_stream_get_auto_grow), 'g_buffered_output_stream_get_auto_grow'); LoadProc(Pointer(g_buffered_output_stream_get_buffer_size), 'g_buffered_output_stream_get_buffer_size'); LoadProc(Pointer(g_buffered_output_stream_get_type), 'g_buffered_output_stream_get_type'); LoadProc(Pointer(g_buffered_output_stream_new), 'g_buffered_output_stream_new'); LoadProc(Pointer(g_buffered_output_stream_new_sized), 'g_buffered_output_stream_new_sized'); LoadProc(Pointer(g_buffered_output_stream_set_auto_grow), 'g_buffered_output_stream_set_auto_grow'); LoadProc(Pointer(g_buffered_output_stream_set_buffer_size), 'g_buffered_output_stream_set_buffer_size'); LoadProc(Pointer(g_bus_get), 'g_bus_get'); LoadProc(Pointer(g_bus_get_finish), 'g_bus_get_finish'); LoadProc(Pointer(g_bus_get_sync), 'g_bus_get_sync'); LoadProc(Pointer(g_bus_own_name), 'g_bus_own_name'); LoadProc(Pointer(g_bus_own_name_on_connection), 'g_bus_own_name_on_connection'); LoadProc(Pointer(g_bus_own_name_on_connection_with_closures), 'g_bus_own_name_on_connection_with_closures'); LoadProc(Pointer(g_bus_own_name_with_closures), 'g_bus_own_name_with_closures'); LoadProc(Pointer(g_bus_unown_name), 'g_bus_unown_name'); LoadProc(Pointer(g_bus_unwatch_name), 'g_bus_unwatch_name'); LoadProc(Pointer(g_bus_watch_name), 'g_bus_watch_name'); LoadProc(Pointer(g_bus_watch_name_on_connection), 'g_bus_watch_name_on_connection'); LoadProc(Pointer(g_bus_watch_name_on_connection_with_closures), 'g_bus_watch_name_on_connection_with_closures'); LoadProc(Pointer(g_bus_watch_name_with_closures), 'g_bus_watch_name_with_closures'); LoadProc(Pointer(g_cancellable_cancel), 'g_cancellable_cancel'); LoadProc(Pointer(g_cancellable_connect), 'g_cancellable_connect'); LoadProc(Pointer(g_cancellable_disconnect), 'g_cancellable_disconnect'); LoadProc(Pointer(g_cancellable_get_current), 'g_cancellable_get_current'); LoadProc(Pointer(g_cancellable_get_fd), 'g_cancellable_get_fd'); LoadProc(Pointer(g_cancellable_get_type), 'g_cancellable_get_type'); LoadProc(Pointer(g_cancellable_is_cancelled), 'g_cancellable_is_cancelled'); LoadProc(Pointer(g_cancellable_make_pollfd), 'g_cancellable_make_pollfd'); LoadProc(Pointer(g_cancellable_new), 'g_cancellable_new'); LoadProc(Pointer(g_cancellable_pop_current), 'g_cancellable_pop_current'); LoadProc(Pointer(g_cancellable_push_current), 'g_cancellable_push_current'); LoadProc(Pointer(g_cancellable_release_fd), 'g_cancellable_release_fd'); LoadProc(Pointer(g_cancellable_reset), 'g_cancellable_reset'); LoadProc(Pointer(g_cancellable_set_error_if_cancelled), 'g_cancellable_set_error_if_cancelled'); LoadProc(Pointer(g_cancellable_source_new), 'g_cancellable_source_new'); LoadProc(Pointer(g_charset_converter_get_num_fallbacks), 'g_charset_converter_get_num_fallbacks'); LoadProc(Pointer(g_charset_converter_get_type), 'g_charset_converter_get_type'); LoadProc(Pointer(g_charset_converter_get_use_fallback), 'g_charset_converter_get_use_fallback'); LoadProc(Pointer(g_charset_converter_new), 'g_charset_converter_new'); LoadProc(Pointer(g_charset_converter_set_use_fallback), 'g_charset_converter_set_use_fallback'); LoadProc(Pointer(g_content_type_can_be_executable), 'g_content_type_can_be_executable'); LoadProc(Pointer(g_content_type_equals), 'g_content_type_equals'); LoadProc(Pointer(g_content_type_from_mime_type), 'g_content_type_from_mime_type'); LoadProc(Pointer(g_content_type_get_description), 'g_content_type_get_description'); LoadProc(Pointer(g_content_type_get_generic_icon_name), 'g_content_type_get_generic_icon_name'); LoadProc(Pointer(g_content_type_get_icon), 'g_content_type_get_icon'); LoadProc(Pointer(g_content_type_get_mime_type), 'g_content_type_get_mime_type'); LoadProc(Pointer(g_content_type_get_symbolic_icon), 'g_content_type_get_symbolic_icon'); LoadProc(Pointer(g_content_type_guess), 'g_content_type_guess'); LoadProc(Pointer(g_content_type_guess_for_tree), 'g_content_type_guess_for_tree'); LoadProc(Pointer(g_content_type_is_a), 'g_content_type_is_a'); LoadProc(Pointer(g_content_type_is_unknown), 'g_content_type_is_unknown'); LoadProc(Pointer(g_content_types_get_registered), 'g_content_types_get_registered'); LoadProc(Pointer(g_converter_convert), 'g_converter_convert'); LoadProc(Pointer(g_converter_get_type), 'g_converter_get_type'); LoadProc(Pointer(g_converter_input_stream_get_converter), 'g_converter_input_stream_get_converter'); LoadProc(Pointer(g_converter_input_stream_get_type), 'g_converter_input_stream_get_type'); LoadProc(Pointer(g_converter_input_stream_new), 'g_converter_input_stream_new'); LoadProc(Pointer(g_converter_output_stream_get_converter), 'g_converter_output_stream_get_converter'); LoadProc(Pointer(g_converter_output_stream_get_type), 'g_converter_output_stream_get_type'); LoadProc(Pointer(g_converter_output_stream_new), 'g_converter_output_stream_new'); LoadProc(Pointer(g_converter_reset), 'g_converter_reset'); LoadProc(Pointer(g_credentials_get_native), 'g_credentials_get_native'); LoadProc(Pointer(g_credentials_get_type), 'g_credentials_get_type'); LoadProc(Pointer(g_credentials_get_unix_pid), 'g_credentials_get_unix_pid'); LoadProc(Pointer(g_credentials_get_unix_user), 'g_credentials_get_unix_user'); LoadProc(Pointer(g_credentials_is_same_user), 'g_credentials_is_same_user'); LoadProc(Pointer(g_credentials_new), 'g_credentials_new'); LoadProc(Pointer(g_credentials_set_native), 'g_credentials_set_native'); LoadProc(Pointer(g_credentials_set_unix_user), 'g_credentials_set_unix_user'); LoadProc(Pointer(g_credentials_to_string), 'g_credentials_to_string'); LoadProc(Pointer(g_data_input_stream_get_byte_order), 'g_data_input_stream_get_byte_order'); LoadProc(Pointer(g_data_input_stream_get_newline_type), 'g_data_input_stream_get_newline_type'); LoadProc(Pointer(g_data_input_stream_get_type), 'g_data_input_stream_get_type'); LoadProc(Pointer(g_data_input_stream_new), 'g_data_input_stream_new'); LoadProc(Pointer(g_data_input_stream_read_byte), 'g_data_input_stream_read_byte'); LoadProc(Pointer(g_data_input_stream_read_int16), 'g_data_input_stream_read_int16'); LoadProc(Pointer(g_data_input_stream_read_int32), 'g_data_input_stream_read_int32'); LoadProc(Pointer(g_data_input_stream_read_int64), 'g_data_input_stream_read_int64'); LoadProc(Pointer(g_data_input_stream_read_line), 'g_data_input_stream_read_line'); LoadProc(Pointer(g_data_input_stream_read_line_async), 'g_data_input_stream_read_line_async'); LoadProc(Pointer(g_data_input_stream_read_line_finish), 'g_data_input_stream_read_line_finish'); LoadProc(Pointer(g_data_input_stream_read_line_finish_utf8), 'g_data_input_stream_read_line_finish_utf8'); LoadProc(Pointer(g_data_input_stream_read_line_utf8), 'g_data_input_stream_read_line_utf8'); LoadProc(Pointer(g_data_input_stream_read_uint16), 'g_data_input_stream_read_uint16'); LoadProc(Pointer(g_data_input_stream_read_uint32), 'g_data_input_stream_read_uint32'); LoadProc(Pointer(g_data_input_stream_read_uint64), 'g_data_input_stream_read_uint64'); LoadProc(Pointer(g_data_input_stream_read_until), 'g_data_input_stream_read_until'); LoadProc(Pointer(g_data_input_stream_read_until_async), 'g_data_input_stream_read_until_async'); LoadProc(Pointer(g_data_input_stream_read_until_finish), 'g_data_input_stream_read_until_finish'); LoadProc(Pointer(g_data_input_stream_read_upto), 'g_data_input_stream_read_upto'); LoadProc(Pointer(g_data_input_stream_read_upto_async), 'g_data_input_stream_read_upto_async'); LoadProc(Pointer(g_data_input_stream_read_upto_finish), 'g_data_input_stream_read_upto_finish'); LoadProc(Pointer(g_data_input_stream_set_byte_order), 'g_data_input_stream_set_byte_order'); LoadProc(Pointer(g_data_input_stream_set_newline_type), 'g_data_input_stream_set_newline_type'); LoadProc(Pointer(g_data_output_stream_get_byte_order), 'g_data_output_stream_get_byte_order'); LoadProc(Pointer(g_data_output_stream_get_type), 'g_data_output_stream_get_type'); LoadProc(Pointer(g_data_output_stream_new), 'g_data_output_stream_new'); LoadProc(Pointer(g_data_output_stream_put_byte), 'g_data_output_stream_put_byte'); LoadProc(Pointer(g_data_output_stream_put_int16), 'g_data_output_stream_put_int16'); LoadProc(Pointer(g_data_output_stream_put_int32), 'g_data_output_stream_put_int32'); LoadProc(Pointer(g_data_output_stream_put_int64), 'g_data_output_stream_put_int64'); LoadProc(Pointer(g_data_output_stream_put_string), 'g_data_output_stream_put_string'); LoadProc(Pointer(g_data_output_stream_put_uint16), 'g_data_output_stream_put_uint16'); LoadProc(Pointer(g_data_output_stream_put_uint32), 'g_data_output_stream_put_uint32'); LoadProc(Pointer(g_data_output_stream_put_uint64), 'g_data_output_stream_put_uint64'); LoadProc(Pointer(g_data_output_stream_set_byte_order), 'g_data_output_stream_set_byte_order'); LoadProc(Pointer(g_dbus_action_group_get), 'g_dbus_action_group_get'); LoadProc(Pointer(g_dbus_action_group_get_type), 'g_dbus_action_group_get_type'); LoadProc(Pointer(g_dbus_address_escape_value), 'g_dbus_address_escape_value'); LoadProc(Pointer(g_dbus_address_get_for_bus_sync), 'g_dbus_address_get_for_bus_sync'); LoadProc(Pointer(g_dbus_address_get_stream), 'g_dbus_address_get_stream'); LoadProc(Pointer(g_dbus_address_get_stream_finish), 'g_dbus_address_get_stream_finish'); LoadProc(Pointer(g_dbus_address_get_stream_sync), 'g_dbus_address_get_stream_sync'); LoadProc(Pointer(g_dbus_annotation_info_get_type), 'g_dbus_annotation_info_get_type'); LoadProc(Pointer(g_dbus_annotation_info_lookup), 'g_dbus_annotation_info_lookup'); LoadProc(Pointer(g_dbus_annotation_info_ref), 'g_dbus_annotation_info_ref'); LoadProc(Pointer(g_dbus_annotation_info_unref), 'g_dbus_annotation_info_unref'); LoadProc(Pointer(g_dbus_arg_info_get_type), 'g_dbus_arg_info_get_type'); LoadProc(Pointer(g_dbus_arg_info_ref), 'g_dbus_arg_info_ref'); LoadProc(Pointer(g_dbus_arg_info_unref), 'g_dbus_arg_info_unref'); LoadProc(Pointer(g_dbus_auth_observer_allow_mechanism), 'g_dbus_auth_observer_allow_mechanism'); LoadProc(Pointer(g_dbus_auth_observer_authorize_authenticated_peer), 'g_dbus_auth_observer_authorize_authenticated_peer'); LoadProc(Pointer(g_dbus_auth_observer_get_type), 'g_dbus_auth_observer_get_type'); LoadProc(Pointer(g_dbus_auth_observer_new), 'g_dbus_auth_observer_new'); LoadProc(Pointer(g_dbus_connection_add_filter), 'g_dbus_connection_add_filter'); LoadProc(Pointer(g_dbus_connection_call), 'g_dbus_connection_call'); LoadProc(Pointer(g_dbus_connection_call_finish), 'g_dbus_connection_call_finish'); LoadProc(Pointer(g_dbus_connection_call_sync), 'g_dbus_connection_call_sync'); LoadProc(Pointer(g_dbus_connection_call_with_unix_fd_list), 'g_dbus_connection_call_with_unix_fd_list'); LoadProc(Pointer(g_dbus_connection_call_with_unix_fd_list_finish), 'g_dbus_connection_call_with_unix_fd_list_finish'); LoadProc(Pointer(g_dbus_connection_call_with_unix_fd_list_sync), 'g_dbus_connection_call_with_unix_fd_list_sync'); LoadProc(Pointer(g_dbus_connection_close), 'g_dbus_connection_close'); LoadProc(Pointer(g_dbus_connection_close_finish), 'g_dbus_connection_close_finish'); LoadProc(Pointer(g_dbus_connection_close_sync), 'g_dbus_connection_close_sync'); LoadProc(Pointer(g_dbus_connection_emit_signal), 'g_dbus_connection_emit_signal'); LoadProc(Pointer(g_dbus_connection_export_action_group), 'g_dbus_connection_export_action_group'); LoadProc(Pointer(g_dbus_connection_export_menu_model), 'g_dbus_connection_export_menu_model'); LoadProc(Pointer(g_dbus_connection_flush), 'g_dbus_connection_flush'); LoadProc(Pointer(g_dbus_connection_flush_finish), 'g_dbus_connection_flush_finish'); LoadProc(Pointer(g_dbus_connection_flush_sync), 'g_dbus_connection_flush_sync'); LoadProc(Pointer(g_dbus_connection_get_capabilities), 'g_dbus_connection_get_capabilities'); LoadProc(Pointer(g_dbus_connection_get_exit_on_close), 'g_dbus_connection_get_exit_on_close'); LoadProc(Pointer(g_dbus_connection_get_guid), 'g_dbus_connection_get_guid'); LoadProc(Pointer(g_dbus_connection_get_last_serial), 'g_dbus_connection_get_last_serial'); LoadProc(Pointer(g_dbus_connection_get_peer_credentials), 'g_dbus_connection_get_peer_credentials'); LoadProc(Pointer(g_dbus_connection_get_stream), 'g_dbus_connection_get_stream'); LoadProc(Pointer(g_dbus_connection_get_type), 'g_dbus_connection_get_type'); LoadProc(Pointer(g_dbus_connection_get_unique_name), 'g_dbus_connection_get_unique_name'); LoadProc(Pointer(g_dbus_connection_is_closed), 'g_dbus_connection_is_closed'); LoadProc(Pointer(g_dbus_connection_new), 'g_dbus_connection_new'); LoadProc(Pointer(g_dbus_connection_new_finish), 'g_dbus_connection_new_finish'); LoadProc(Pointer(g_dbus_connection_new_for_address), 'g_dbus_connection_new_for_address'); LoadProc(Pointer(g_dbus_connection_new_for_address_finish), 'g_dbus_connection_new_for_address_finish'); LoadProc(Pointer(g_dbus_connection_new_for_address_sync), 'g_dbus_connection_new_for_address_sync'); LoadProc(Pointer(g_dbus_connection_new_sync), 'g_dbus_connection_new_sync'); LoadProc(Pointer(g_dbus_connection_register_object), 'g_dbus_connection_register_object'); LoadProc(Pointer(g_dbus_connection_register_subtree), 'g_dbus_connection_register_subtree'); LoadProc(Pointer(g_dbus_connection_remove_filter), 'g_dbus_connection_remove_filter'); LoadProc(Pointer(g_dbus_connection_send_message), 'g_dbus_connection_send_message'); LoadProc(Pointer(g_dbus_connection_send_message_with_reply), 'g_dbus_connection_send_message_with_reply'); LoadProc(Pointer(g_dbus_connection_send_message_with_reply_finish), 'g_dbus_connection_send_message_with_reply_finish'); LoadProc(Pointer(g_dbus_connection_send_message_with_reply_sync), 'g_dbus_connection_send_message_with_reply_sync'); LoadProc(Pointer(g_dbus_connection_set_exit_on_close), 'g_dbus_connection_set_exit_on_close'); LoadProc(Pointer(g_dbus_connection_signal_subscribe), 'g_dbus_connection_signal_subscribe'); LoadProc(Pointer(g_dbus_connection_signal_unsubscribe), 'g_dbus_connection_signal_unsubscribe'); LoadProc(Pointer(g_dbus_connection_start_message_processing), 'g_dbus_connection_start_message_processing'); LoadProc(Pointer(g_dbus_connection_unexport_action_group), 'g_dbus_connection_unexport_action_group'); LoadProc(Pointer(g_dbus_connection_unexport_menu_model), 'g_dbus_connection_unexport_menu_model'); LoadProc(Pointer(g_dbus_connection_unregister_object), 'g_dbus_connection_unregister_object'); LoadProc(Pointer(g_dbus_connection_unregister_subtree), 'g_dbus_connection_unregister_subtree'); LoadProc(Pointer(g_dbus_error_encode_gerror), 'g_dbus_error_encode_gerror'); LoadProc(Pointer(g_dbus_error_get_remote_error), 'g_dbus_error_get_remote_error'); LoadProc(Pointer(g_dbus_error_is_remote_error), 'g_dbus_error_is_remote_error'); LoadProc(Pointer(g_dbus_error_new_for_dbus_error), 'g_dbus_error_new_for_dbus_error'); LoadProc(Pointer(g_dbus_error_quark), 'g_dbus_error_quark'); LoadProc(Pointer(g_dbus_error_register_error), 'g_dbus_error_register_error'); LoadProc(Pointer(g_dbus_error_register_error_domain), 'g_dbus_error_register_error_domain'); LoadProc(Pointer(g_dbus_error_set_dbus_error), 'g_dbus_error_set_dbus_error'); LoadProc(Pointer(g_dbus_error_set_dbus_error_valist), 'g_dbus_error_set_dbus_error_valist'); LoadProc(Pointer(g_dbus_error_strip_remote_error), 'g_dbus_error_strip_remote_error'); LoadProc(Pointer(g_dbus_error_unregister_error), 'g_dbus_error_unregister_error'); LoadProc(Pointer(g_dbus_generate_guid), 'g_dbus_generate_guid'); LoadProc(Pointer(g_dbus_gvalue_to_gvariant), 'g_dbus_gvalue_to_gvariant'); LoadProc(Pointer(g_dbus_gvariant_to_gvalue), 'g_dbus_gvariant_to_gvalue'); LoadProc(Pointer(g_dbus_interface_dup_object), 'g_dbus_interface_dup_object'); LoadProc(Pointer(g_dbus_interface_get_info), 'g_dbus_interface_get_info'); LoadProc(Pointer(g_dbus_interface_get_object), 'g_dbus_interface_get_object'); LoadProc(Pointer(g_dbus_interface_get_type), 'g_dbus_interface_get_type'); LoadProc(Pointer(g_dbus_interface_info_cache_build), 'g_dbus_interface_info_cache_build'); LoadProc(Pointer(g_dbus_interface_info_cache_release), 'g_dbus_interface_info_cache_release'); LoadProc(Pointer(g_dbus_interface_info_generate_xml), 'g_dbus_interface_info_generate_xml'); LoadProc(Pointer(g_dbus_interface_info_get_type), 'g_dbus_interface_info_get_type'); LoadProc(Pointer(g_dbus_interface_info_lookup_method), 'g_dbus_interface_info_lookup_method'); LoadProc(Pointer(g_dbus_interface_info_lookup_property), 'g_dbus_interface_info_lookup_property'); LoadProc(Pointer(g_dbus_interface_info_lookup_signal), 'g_dbus_interface_info_lookup_signal'); LoadProc(Pointer(g_dbus_interface_info_ref), 'g_dbus_interface_info_ref'); LoadProc(Pointer(g_dbus_interface_info_unref), 'g_dbus_interface_info_unref'); LoadProc(Pointer(g_dbus_interface_set_object), 'g_dbus_interface_set_object'); LoadProc(Pointer(g_dbus_interface_skeleton_export), 'g_dbus_interface_skeleton_export'); LoadProc(Pointer(g_dbus_interface_skeleton_flush), 'g_dbus_interface_skeleton_flush'); LoadProc(Pointer(g_dbus_interface_skeleton_get_connection), 'g_dbus_interface_skeleton_get_connection'); LoadProc(Pointer(g_dbus_interface_skeleton_get_connections), 'g_dbus_interface_skeleton_get_connections'); LoadProc(Pointer(g_dbus_interface_skeleton_get_flags), 'g_dbus_interface_skeleton_get_flags'); LoadProc(Pointer(g_dbus_interface_skeleton_get_info), 'g_dbus_interface_skeleton_get_info'); LoadProc(Pointer(g_dbus_interface_skeleton_get_object_path), 'g_dbus_interface_skeleton_get_object_path'); LoadProc(Pointer(g_dbus_interface_skeleton_get_properties), 'g_dbus_interface_skeleton_get_properties'); LoadProc(Pointer(g_dbus_interface_skeleton_get_type), 'g_dbus_interface_skeleton_get_type'); LoadProc(Pointer(g_dbus_interface_skeleton_get_vtable), 'g_dbus_interface_skeleton_get_vtable'); LoadProc(Pointer(g_dbus_interface_skeleton_has_connection), 'g_dbus_interface_skeleton_has_connection'); LoadProc(Pointer(g_dbus_interface_skeleton_set_flags), 'g_dbus_interface_skeleton_set_flags'); LoadProc(Pointer(g_dbus_interface_skeleton_unexport), 'g_dbus_interface_skeleton_unexport'); LoadProc(Pointer(g_dbus_interface_skeleton_unexport_from_connection), 'g_dbus_interface_skeleton_unexport_from_connection'); LoadProc(Pointer(g_dbus_is_address), 'g_dbus_is_address'); LoadProc(Pointer(g_dbus_is_guid), 'g_dbus_is_guid'); LoadProc(Pointer(g_dbus_is_interface_name), 'g_dbus_is_interface_name'); LoadProc(Pointer(g_dbus_is_member_name), 'g_dbus_is_member_name'); LoadProc(Pointer(g_dbus_is_name), 'g_dbus_is_name'); LoadProc(Pointer(g_dbus_is_supported_address), 'g_dbus_is_supported_address'); LoadProc(Pointer(g_dbus_is_unique_name), 'g_dbus_is_unique_name'); LoadProc(Pointer(g_dbus_menu_model_get), 'g_dbus_menu_model_get'); LoadProc(Pointer(g_dbus_menu_model_get_type), 'g_dbus_menu_model_get_type'); LoadProc(Pointer(g_dbus_message_bytes_needed), 'g_dbus_message_bytes_needed'); LoadProc(Pointer(g_dbus_message_copy), 'g_dbus_message_copy'); LoadProc(Pointer(g_dbus_message_get_arg0), 'g_dbus_message_get_arg0'); LoadProc(Pointer(g_dbus_message_get_body), 'g_dbus_message_get_body'); LoadProc(Pointer(g_dbus_message_get_byte_order), 'g_dbus_message_get_byte_order'); LoadProc(Pointer(g_dbus_message_get_destination), 'g_dbus_message_get_destination'); LoadProc(Pointer(g_dbus_message_get_error_name), 'g_dbus_message_get_error_name'); LoadProc(Pointer(g_dbus_message_get_flags), 'g_dbus_message_get_flags'); LoadProc(Pointer(g_dbus_message_get_header), 'g_dbus_message_get_header'); LoadProc(Pointer(g_dbus_message_get_header_fields), 'g_dbus_message_get_header_fields'); LoadProc(Pointer(g_dbus_message_get_interface), 'g_dbus_message_get_interface'); LoadProc(Pointer(g_dbus_message_get_locked), 'g_dbus_message_get_locked'); LoadProc(Pointer(g_dbus_message_get_member), 'g_dbus_message_get_member'); LoadProc(Pointer(g_dbus_message_get_message_type), 'g_dbus_message_get_message_type'); LoadProc(Pointer(g_dbus_message_get_num_unix_fds), 'g_dbus_message_get_num_unix_fds'); LoadProc(Pointer(g_dbus_message_get_path), 'g_dbus_message_get_path'); LoadProc(Pointer(g_dbus_message_get_reply_serial), 'g_dbus_message_get_reply_serial'); LoadProc(Pointer(g_dbus_message_get_sender), 'g_dbus_message_get_sender'); LoadProc(Pointer(g_dbus_message_get_serial), 'g_dbus_message_get_serial'); LoadProc(Pointer(g_dbus_message_get_signature), 'g_dbus_message_get_signature'); LoadProc(Pointer(g_dbus_message_get_type), 'g_dbus_message_get_type'); LoadProc(Pointer(g_dbus_message_get_unix_fd_list), 'g_dbus_message_get_unix_fd_list'); LoadProc(Pointer(g_dbus_message_lock), 'g_dbus_message_lock'); LoadProc(Pointer(g_dbus_message_new), 'g_dbus_message_new'); LoadProc(Pointer(g_dbus_message_new_from_blob), 'g_dbus_message_new_from_blob'); LoadProc(Pointer(g_dbus_message_new_method_call), 'g_dbus_message_new_method_call'); LoadProc(Pointer(g_dbus_message_new_method_error), 'g_dbus_message_new_method_error'); LoadProc(Pointer(g_dbus_message_new_method_error_literal), 'g_dbus_message_new_method_error_literal'); LoadProc(Pointer(g_dbus_message_new_method_error_valist), 'g_dbus_message_new_method_error_valist'); LoadProc(Pointer(g_dbus_message_new_method_reply), 'g_dbus_message_new_method_reply'); LoadProc(Pointer(g_dbus_message_new_signal), 'g_dbus_message_new_signal'); LoadProc(Pointer(g_dbus_message_print), 'g_dbus_message_print'); LoadProc(Pointer(g_dbus_message_set_body), 'g_dbus_message_set_body'); LoadProc(Pointer(g_dbus_message_set_byte_order), 'g_dbus_message_set_byte_order'); LoadProc(Pointer(g_dbus_message_set_destination), 'g_dbus_message_set_destination'); LoadProc(Pointer(g_dbus_message_set_error_name), 'g_dbus_message_set_error_name'); LoadProc(Pointer(g_dbus_message_set_flags), 'g_dbus_message_set_flags'); LoadProc(Pointer(g_dbus_message_set_header), 'g_dbus_message_set_header'); LoadProc(Pointer(g_dbus_message_set_interface), 'g_dbus_message_set_interface'); LoadProc(Pointer(g_dbus_message_set_member), 'g_dbus_message_set_member'); LoadProc(Pointer(g_dbus_message_set_message_type), 'g_dbus_message_set_message_type'); LoadProc(Pointer(g_dbus_message_set_num_unix_fds), 'g_dbus_message_set_num_unix_fds'); LoadProc(Pointer(g_dbus_message_set_path), 'g_dbus_message_set_path'); LoadProc(Pointer(g_dbus_message_set_reply_serial), 'g_dbus_message_set_reply_serial'); LoadProc(Pointer(g_dbus_message_set_sender), 'g_dbus_message_set_sender'); LoadProc(Pointer(g_dbus_message_set_serial), 'g_dbus_message_set_serial'); LoadProc(Pointer(g_dbus_message_set_signature), 'g_dbus_message_set_signature'); LoadProc(Pointer(g_dbus_message_set_unix_fd_list), 'g_dbus_message_set_unix_fd_list'); LoadProc(Pointer(g_dbus_message_to_blob), 'g_dbus_message_to_blob'); LoadProc(Pointer(g_dbus_message_to_gerror), 'g_dbus_message_to_gerror'); LoadProc(Pointer(g_dbus_method_info_get_type), 'g_dbus_method_info_get_type'); LoadProc(Pointer(g_dbus_method_info_ref), 'g_dbus_method_info_ref'); LoadProc(Pointer(g_dbus_method_info_unref), 'g_dbus_method_info_unref'); LoadProc(Pointer(g_dbus_method_invocation_get_connection), 'g_dbus_method_invocation_get_connection'); LoadProc(Pointer(g_dbus_method_invocation_get_interface_name), 'g_dbus_method_invocation_get_interface_name'); LoadProc(Pointer(g_dbus_method_invocation_get_message), 'g_dbus_method_invocation_get_message'); LoadProc(Pointer(g_dbus_method_invocation_get_method_info), 'g_dbus_method_invocation_get_method_info'); LoadProc(Pointer(g_dbus_method_invocation_get_method_name), 'g_dbus_method_invocation_get_method_name'); LoadProc(Pointer(g_dbus_method_invocation_get_object_path), 'g_dbus_method_invocation_get_object_path'); LoadProc(Pointer(g_dbus_method_invocation_get_parameters), 'g_dbus_method_invocation_get_parameters'); LoadProc(Pointer(g_dbus_method_invocation_get_sender), 'g_dbus_method_invocation_get_sender'); LoadProc(Pointer(g_dbus_method_invocation_get_type), 'g_dbus_method_invocation_get_type'); LoadProc(Pointer(g_dbus_method_invocation_get_user_data), 'g_dbus_method_invocation_get_user_data'); LoadProc(Pointer(g_dbus_method_invocation_return_dbus_error), 'g_dbus_method_invocation_return_dbus_error'); LoadProc(Pointer(g_dbus_method_invocation_return_error), 'g_dbus_method_invocation_return_error'); LoadProc(Pointer(g_dbus_method_invocation_return_error_literal), 'g_dbus_method_invocation_return_error_literal'); LoadProc(Pointer(g_dbus_method_invocation_return_error_valist), 'g_dbus_method_invocation_return_error_valist'); LoadProc(Pointer(g_dbus_method_invocation_return_gerror), 'g_dbus_method_invocation_return_gerror'); LoadProc(Pointer(g_dbus_method_invocation_return_value), 'g_dbus_method_invocation_return_value'); LoadProc(Pointer(g_dbus_method_invocation_return_value_with_unix_fd_list), 'g_dbus_method_invocation_return_value_with_unix_fd_list'); LoadProc(Pointer(g_dbus_method_invocation_take_error), 'g_dbus_method_invocation_take_error'); LoadProc(Pointer(g_dbus_node_info_generate_xml), 'g_dbus_node_info_generate_xml'); LoadProc(Pointer(g_dbus_node_info_get_type), 'g_dbus_node_info_get_type'); LoadProc(Pointer(g_dbus_node_info_lookup_interface), 'g_dbus_node_info_lookup_interface'); LoadProc(Pointer(g_dbus_node_info_new_for_xml), 'g_dbus_node_info_new_for_xml'); LoadProc(Pointer(g_dbus_node_info_ref), 'g_dbus_node_info_ref'); LoadProc(Pointer(g_dbus_node_info_unref), 'g_dbus_node_info_unref'); LoadProc(Pointer(g_dbus_object_get_interface), 'g_dbus_object_get_interface'); LoadProc(Pointer(g_dbus_object_get_interfaces), 'g_dbus_object_get_interfaces'); LoadProc(Pointer(g_dbus_object_get_object_path), 'g_dbus_object_get_object_path'); LoadProc(Pointer(g_dbus_object_get_type), 'g_dbus_object_get_type'); LoadProc(Pointer(g_dbus_object_manager_client_get_connection), 'g_dbus_object_manager_client_get_connection'); LoadProc(Pointer(g_dbus_object_manager_client_get_flags), 'g_dbus_object_manager_client_get_flags'); LoadProc(Pointer(g_dbus_object_manager_client_get_name), 'g_dbus_object_manager_client_get_name'); LoadProc(Pointer(g_dbus_object_manager_client_get_name_owner), 'g_dbus_object_manager_client_get_name_owner'); LoadProc(Pointer(g_dbus_object_manager_client_get_type), 'g_dbus_object_manager_client_get_type'); LoadProc(Pointer(g_dbus_object_manager_client_new), 'g_dbus_object_manager_client_new'); LoadProc(Pointer(g_dbus_object_manager_client_new_finish), 'g_dbus_object_manager_client_new_finish'); LoadProc(Pointer(g_dbus_object_manager_client_new_for_bus), 'g_dbus_object_manager_client_new_for_bus'); LoadProc(Pointer(g_dbus_object_manager_client_new_for_bus_finish), 'g_dbus_object_manager_client_new_for_bus_finish'); LoadProc(Pointer(g_dbus_object_manager_client_new_for_bus_sync), 'g_dbus_object_manager_client_new_for_bus_sync'); LoadProc(Pointer(g_dbus_object_manager_client_new_sync), 'g_dbus_object_manager_client_new_sync'); LoadProc(Pointer(g_dbus_object_manager_get_interface), 'g_dbus_object_manager_get_interface'); LoadProc(Pointer(g_dbus_object_manager_get_object), 'g_dbus_object_manager_get_object'); LoadProc(Pointer(g_dbus_object_manager_get_object_path), 'g_dbus_object_manager_get_object_path'); LoadProc(Pointer(g_dbus_object_manager_get_objects), 'g_dbus_object_manager_get_objects'); LoadProc(Pointer(g_dbus_object_manager_get_type), 'g_dbus_object_manager_get_type'); LoadProc(Pointer(g_dbus_object_manager_server_export), 'g_dbus_object_manager_server_export'); LoadProc(Pointer(g_dbus_object_manager_server_export_uniquely), 'g_dbus_object_manager_server_export_uniquely'); LoadProc(Pointer(g_dbus_object_manager_server_get_connection), 'g_dbus_object_manager_server_get_connection'); LoadProc(Pointer(g_dbus_object_manager_server_get_type), 'g_dbus_object_manager_server_get_type'); LoadProc(Pointer(g_dbus_object_manager_server_is_exported), 'g_dbus_object_manager_server_is_exported'); LoadProc(Pointer(g_dbus_object_manager_server_new), 'g_dbus_object_manager_server_new'); LoadProc(Pointer(g_dbus_object_manager_server_set_connection), 'g_dbus_object_manager_server_set_connection'); LoadProc(Pointer(g_dbus_object_manager_server_unexport), 'g_dbus_object_manager_server_unexport'); LoadProc(Pointer(g_dbus_object_proxy_get_connection), 'g_dbus_object_proxy_get_connection'); LoadProc(Pointer(g_dbus_object_proxy_get_type), 'g_dbus_object_proxy_get_type'); LoadProc(Pointer(g_dbus_object_proxy_new), 'g_dbus_object_proxy_new'); LoadProc(Pointer(g_dbus_object_skeleton_add_interface), 'g_dbus_object_skeleton_add_interface'); LoadProc(Pointer(g_dbus_object_skeleton_flush), 'g_dbus_object_skeleton_flush'); LoadProc(Pointer(g_dbus_object_skeleton_get_type), 'g_dbus_object_skeleton_get_type'); LoadProc(Pointer(g_dbus_object_skeleton_new), 'g_dbus_object_skeleton_new'); LoadProc(Pointer(g_dbus_object_skeleton_remove_interface), 'g_dbus_object_skeleton_remove_interface'); LoadProc(Pointer(g_dbus_object_skeleton_remove_interface_by_name), 'g_dbus_object_skeleton_remove_interface_by_name'); LoadProc(Pointer(g_dbus_object_skeleton_set_object_path), 'g_dbus_object_skeleton_set_object_path'); LoadProc(Pointer(g_dbus_property_info_get_type), 'g_dbus_property_info_get_type'); LoadProc(Pointer(g_dbus_property_info_ref), 'g_dbus_property_info_ref'); LoadProc(Pointer(g_dbus_property_info_unref), 'g_dbus_property_info_unref'); LoadProc(Pointer(g_dbus_proxy_call), 'g_dbus_proxy_call'); LoadProc(Pointer(g_dbus_proxy_call_finish), 'g_dbus_proxy_call_finish'); LoadProc(Pointer(g_dbus_proxy_call_sync), 'g_dbus_proxy_call_sync'); LoadProc(Pointer(g_dbus_proxy_call_with_unix_fd_list), 'g_dbus_proxy_call_with_unix_fd_list'); LoadProc(Pointer(g_dbus_proxy_call_with_unix_fd_list_finish), 'g_dbus_proxy_call_with_unix_fd_list_finish'); LoadProc(Pointer(g_dbus_proxy_call_with_unix_fd_list_sync), 'g_dbus_proxy_call_with_unix_fd_list_sync'); LoadProc(Pointer(g_dbus_proxy_get_cached_property), 'g_dbus_proxy_get_cached_property'); LoadProc(Pointer(g_dbus_proxy_get_cached_property_names), 'g_dbus_proxy_get_cached_property_names'); LoadProc(Pointer(g_dbus_proxy_get_connection), 'g_dbus_proxy_get_connection'); LoadProc(Pointer(g_dbus_proxy_get_default_timeout), 'g_dbus_proxy_get_default_timeout'); LoadProc(Pointer(g_dbus_proxy_get_flags), 'g_dbus_proxy_get_flags'); LoadProc(Pointer(g_dbus_proxy_get_interface_info), 'g_dbus_proxy_get_interface_info'); LoadProc(Pointer(g_dbus_proxy_get_interface_name), 'g_dbus_proxy_get_interface_name'); LoadProc(Pointer(g_dbus_proxy_get_name), 'g_dbus_proxy_get_name'); LoadProc(Pointer(g_dbus_proxy_get_name_owner), 'g_dbus_proxy_get_name_owner'); LoadProc(Pointer(g_dbus_proxy_get_object_path), 'g_dbus_proxy_get_object_path'); LoadProc(Pointer(g_dbus_proxy_get_type), 'g_dbus_proxy_get_type'); LoadProc(Pointer(g_dbus_proxy_new), 'g_dbus_proxy_new'); LoadProc(Pointer(g_dbus_proxy_new_finish), 'g_dbus_proxy_new_finish'); LoadProc(Pointer(g_dbus_proxy_new_for_bus), 'g_dbus_proxy_new_for_bus'); LoadProc(Pointer(g_dbus_proxy_new_for_bus_finish), 'g_dbus_proxy_new_for_bus_finish'); LoadProc(Pointer(g_dbus_proxy_new_for_bus_sync), 'g_dbus_proxy_new_for_bus_sync'); LoadProc(Pointer(g_dbus_proxy_new_sync), 'g_dbus_proxy_new_sync'); LoadProc(Pointer(g_dbus_proxy_set_cached_property), 'g_dbus_proxy_set_cached_property'); LoadProc(Pointer(g_dbus_proxy_set_default_timeout), 'g_dbus_proxy_set_default_timeout'); LoadProc(Pointer(g_dbus_proxy_set_interface_info), 'g_dbus_proxy_set_interface_info'); LoadProc(Pointer(g_dbus_server_get_client_address), 'g_dbus_server_get_client_address'); LoadProc(Pointer(g_dbus_server_get_flags), 'g_dbus_server_get_flags'); LoadProc(Pointer(g_dbus_server_get_guid), 'g_dbus_server_get_guid'); LoadProc(Pointer(g_dbus_server_get_type), 'g_dbus_server_get_type'); LoadProc(Pointer(g_dbus_server_is_active), 'g_dbus_server_is_active'); LoadProc(Pointer(g_dbus_server_new_sync), 'g_dbus_server_new_sync'); LoadProc(Pointer(g_dbus_server_start), 'g_dbus_server_start'); LoadProc(Pointer(g_dbus_server_stop), 'g_dbus_server_stop'); LoadProc(Pointer(g_dbus_signal_info_get_type), 'g_dbus_signal_info_get_type'); LoadProc(Pointer(g_dbus_signal_info_ref), 'g_dbus_signal_info_ref'); LoadProc(Pointer(g_dbus_signal_info_unref), 'g_dbus_signal_info_unref'); LoadProc(Pointer(g_desktop_app_info_get_boolean), 'g_desktop_app_info_get_boolean'); LoadProc(Pointer(g_desktop_app_info_get_categories), 'g_desktop_app_info_get_categories'); LoadProc(Pointer(g_desktop_app_info_get_filename), 'g_desktop_app_info_get_filename'); LoadProc(Pointer(g_desktop_app_info_get_generic_name), 'g_desktop_app_info_get_generic_name'); LoadProc(Pointer(g_desktop_app_info_get_is_hidden), 'g_desktop_app_info_get_is_hidden'); LoadProc(Pointer(g_desktop_app_info_get_keywords), 'g_desktop_app_info_get_keywords'); LoadProc(Pointer(g_desktop_app_info_get_nodisplay), 'g_desktop_app_info_get_nodisplay'); LoadProc(Pointer(g_desktop_app_info_get_show_in), 'g_desktop_app_info_get_show_in'); LoadProc(Pointer(g_desktop_app_info_get_startup_wm_class), 'g_desktop_app_info_get_startup_wm_class'); LoadProc(Pointer(g_desktop_app_info_get_string), 'g_desktop_app_info_get_string'); LoadProc(Pointer(g_desktop_app_info_get_type), 'g_desktop_app_info_get_type'); LoadProc(Pointer(g_desktop_app_info_has_key), 'g_desktop_app_info_has_key'); LoadProc(Pointer(g_desktop_app_info_launch_uris_as_manager), 'g_desktop_app_info_launch_uris_as_manager'); LoadProc(Pointer(g_desktop_app_info_lookup_get_type), 'g_desktop_app_info_lookup_get_type'); LoadProc(Pointer(g_desktop_app_info_new), 'g_desktop_app_info_new'); LoadProc(Pointer(g_desktop_app_info_new_from_filename), 'g_desktop_app_info_new_from_filename'); LoadProc(Pointer(g_desktop_app_info_new_from_keyfile), 'g_desktop_app_info_new_from_keyfile'); LoadProc(Pointer(g_desktop_app_info_set_desktop_env), 'g_desktop_app_info_set_desktop_env'); LoadProc(Pointer(g_drive_can_eject), 'g_drive_can_eject'); LoadProc(Pointer(g_drive_can_poll_for_media), 'g_drive_can_poll_for_media'); LoadProc(Pointer(g_drive_can_start), 'g_drive_can_start'); LoadProc(Pointer(g_drive_can_start_degraded), 'g_drive_can_start_degraded'); LoadProc(Pointer(g_drive_can_stop), 'g_drive_can_stop'); LoadProc(Pointer(g_drive_eject_with_operation), 'g_drive_eject_with_operation'); LoadProc(Pointer(g_drive_eject_with_operation_finish), 'g_drive_eject_with_operation_finish'); LoadProc(Pointer(g_drive_enumerate_identifiers), 'g_drive_enumerate_identifiers'); LoadProc(Pointer(g_drive_get_icon), 'g_drive_get_icon'); LoadProc(Pointer(g_drive_get_identifier), 'g_drive_get_identifier'); LoadProc(Pointer(g_drive_get_name), 'g_drive_get_name'); LoadProc(Pointer(g_drive_get_sort_key), 'g_drive_get_sort_key'); LoadProc(Pointer(g_drive_get_start_stop_type), 'g_drive_get_start_stop_type'); LoadProc(Pointer(g_drive_get_symbolic_icon), 'g_drive_get_symbolic_icon'); LoadProc(Pointer(g_drive_get_type), 'g_drive_get_type'); LoadProc(Pointer(g_drive_get_volumes), 'g_drive_get_volumes'); LoadProc(Pointer(g_drive_has_media), 'g_drive_has_media'); LoadProc(Pointer(g_drive_has_volumes), 'g_drive_has_volumes'); LoadProc(Pointer(g_drive_is_media_check_automatic), 'g_drive_is_media_check_automatic'); LoadProc(Pointer(g_drive_is_media_removable), 'g_drive_is_media_removable'); LoadProc(Pointer(g_drive_poll_for_media), 'g_drive_poll_for_media'); LoadProc(Pointer(g_drive_poll_for_media_finish), 'g_drive_poll_for_media_finish'); LoadProc(Pointer(g_drive_start), 'g_drive_start'); LoadProc(Pointer(g_drive_start_finish), 'g_drive_start_finish'); LoadProc(Pointer(g_drive_stop), 'g_drive_stop'); LoadProc(Pointer(g_drive_stop_finish), 'g_drive_stop_finish'); LoadProc(Pointer(g_emblem_get_icon), 'g_emblem_get_icon'); LoadProc(Pointer(g_emblem_get_origin), 'g_emblem_get_origin'); LoadProc(Pointer(g_emblem_get_type), 'g_emblem_get_type'); LoadProc(Pointer(g_emblem_new), 'g_emblem_new'); LoadProc(Pointer(g_emblem_new_with_origin), 'g_emblem_new_with_origin'); LoadProc(Pointer(g_emblemed_icon_add_emblem), 'g_emblemed_icon_add_emblem'); LoadProc(Pointer(g_emblemed_icon_clear_emblems), 'g_emblemed_icon_clear_emblems'); LoadProc(Pointer(g_emblemed_icon_get_emblems), 'g_emblemed_icon_get_emblems'); LoadProc(Pointer(g_emblemed_icon_get_icon), 'g_emblemed_icon_get_icon'); LoadProc(Pointer(g_emblemed_icon_get_type), 'g_emblemed_icon_get_type'); LoadProc(Pointer(g_emblemed_icon_new), 'g_emblemed_icon_new'); LoadProc(Pointer(g_file_append_to), 'g_file_append_to'); LoadProc(Pointer(g_file_append_to_async), 'g_file_append_to_async'); LoadProc(Pointer(g_file_append_to_finish), 'g_file_append_to_finish'); LoadProc(Pointer(g_file_attribute_info_list_add), 'g_file_attribute_info_list_add'); LoadProc(Pointer(g_file_attribute_info_list_dup), 'g_file_attribute_info_list_dup'); LoadProc(Pointer(g_file_attribute_info_list_get_type), 'g_file_attribute_info_list_get_type'); LoadProc(Pointer(g_file_attribute_info_list_lookup), 'g_file_attribute_info_list_lookup'); LoadProc(Pointer(g_file_attribute_info_list_new), 'g_file_attribute_info_list_new'); LoadProc(Pointer(g_file_attribute_info_list_ref), 'g_file_attribute_info_list_ref'); LoadProc(Pointer(g_file_attribute_info_list_unref), 'g_file_attribute_info_list_unref'); LoadProc(Pointer(g_file_attribute_matcher_enumerate_namespace), 'g_file_attribute_matcher_enumerate_namespace'); LoadProc(Pointer(g_file_attribute_matcher_enumerate_next), 'g_file_attribute_matcher_enumerate_next'); LoadProc(Pointer(g_file_attribute_matcher_get_type), 'g_file_attribute_matcher_get_type'); LoadProc(Pointer(g_file_attribute_matcher_matches), 'g_file_attribute_matcher_matches'); LoadProc(Pointer(g_file_attribute_matcher_matches_only), 'g_file_attribute_matcher_matches_only'); LoadProc(Pointer(g_file_attribute_matcher_new), 'g_file_attribute_matcher_new'); LoadProc(Pointer(g_file_attribute_matcher_ref), 'g_file_attribute_matcher_ref'); LoadProc(Pointer(g_file_attribute_matcher_subtract), 'g_file_attribute_matcher_subtract'); LoadProc(Pointer(g_file_attribute_matcher_to_string), 'g_file_attribute_matcher_to_string'); LoadProc(Pointer(g_file_attribute_matcher_unref), 'g_file_attribute_matcher_unref'); LoadProc(Pointer(g_file_copy), 'g_file_copy'); LoadProc(Pointer(g_file_copy_async), 'g_file_copy_async'); LoadProc(Pointer(g_file_copy_attributes), 'g_file_copy_attributes'); LoadProc(Pointer(g_file_copy_finish), 'g_file_copy_finish'); LoadProc(Pointer(g_file_create), 'g_file_create'); LoadProc(Pointer(g_file_create_async), 'g_file_create_async'); LoadProc(Pointer(g_file_create_finish), 'g_file_create_finish'); LoadProc(Pointer(g_file_create_readwrite), 'g_file_create_readwrite'); LoadProc(Pointer(g_file_create_readwrite_async), 'g_file_create_readwrite_async'); LoadProc(Pointer(g_file_create_readwrite_finish), 'g_file_create_readwrite_finish'); LoadProc(Pointer(g_file_delete), 'g_file_delete'); LoadProc(Pointer(g_file_delete_async), 'g_file_delete_async'); LoadProc(Pointer(g_file_delete_finish), 'g_file_delete_finish'); LoadProc(Pointer(g_file_descriptor_based_get_fd), 'g_file_descriptor_based_get_fd'); LoadProc(Pointer(g_file_descriptor_based_get_type), 'g_file_descriptor_based_get_type'); LoadProc(Pointer(g_file_dup), 'g_file_dup'); LoadProc(Pointer(g_file_eject_mountable_with_operation), 'g_file_eject_mountable_with_operation'); LoadProc(Pointer(g_file_eject_mountable_with_operation_finish), 'g_file_eject_mountable_with_operation_finish'); LoadProc(Pointer(g_file_enumerate_children), 'g_file_enumerate_children'); LoadProc(Pointer(g_file_enumerate_children_async), 'g_file_enumerate_children_async'); LoadProc(Pointer(g_file_enumerate_children_finish), 'g_file_enumerate_children_finish'); LoadProc(Pointer(g_file_enumerator_close), 'g_file_enumerator_close'); LoadProc(Pointer(g_file_enumerator_close_async), 'g_file_enumerator_close_async'); LoadProc(Pointer(g_file_enumerator_close_finish), 'g_file_enumerator_close_finish'); LoadProc(Pointer(g_file_enumerator_get_child), 'g_file_enumerator_get_child'); LoadProc(Pointer(g_file_enumerator_get_container), 'g_file_enumerator_get_container'); LoadProc(Pointer(g_file_enumerator_get_type), 'g_file_enumerator_get_type'); LoadProc(Pointer(g_file_enumerator_has_pending), 'g_file_enumerator_has_pending'); LoadProc(Pointer(g_file_enumerator_is_closed), 'g_file_enumerator_is_closed'); LoadProc(Pointer(g_file_enumerator_next_file), 'g_file_enumerator_next_file'); LoadProc(Pointer(g_file_enumerator_next_files_async), 'g_file_enumerator_next_files_async'); LoadProc(Pointer(g_file_enumerator_next_files_finish), 'g_file_enumerator_next_files_finish'); LoadProc(Pointer(g_file_enumerator_set_pending), 'g_file_enumerator_set_pending'); LoadProc(Pointer(g_file_equal), 'g_file_equal'); LoadProc(Pointer(g_file_find_enclosing_mount), 'g_file_find_enclosing_mount'); LoadProc(Pointer(g_file_find_enclosing_mount_async), 'g_file_find_enclosing_mount_async'); LoadProc(Pointer(g_file_find_enclosing_mount_finish), 'g_file_find_enclosing_mount_finish'); LoadProc(Pointer(g_file_get_basename), 'g_file_get_basename'); LoadProc(Pointer(g_file_get_child), 'g_file_get_child'); LoadProc(Pointer(g_file_get_child_for_display_name), 'g_file_get_child_for_display_name'); LoadProc(Pointer(g_file_get_parent), 'g_file_get_parent'); LoadProc(Pointer(g_file_get_parse_name), 'g_file_get_parse_name'); LoadProc(Pointer(g_file_get_path), 'g_file_get_path'); LoadProc(Pointer(g_file_get_relative_path), 'g_file_get_relative_path'); LoadProc(Pointer(g_file_get_type), 'g_file_get_type'); LoadProc(Pointer(g_file_get_uri), 'g_file_get_uri'); LoadProc(Pointer(g_file_get_uri_scheme), 'g_file_get_uri_scheme'); LoadProc(Pointer(g_file_has_parent), 'g_file_has_parent'); LoadProc(Pointer(g_file_has_prefix), 'g_file_has_prefix'); LoadProc(Pointer(g_file_has_uri_scheme), 'g_file_has_uri_scheme'); LoadProc(Pointer(g_file_hash), 'g_file_hash'); LoadProc(Pointer(g_file_icon_get_file), 'g_file_icon_get_file'); LoadProc(Pointer(g_file_icon_get_type), 'g_file_icon_get_type'); LoadProc(Pointer(g_file_icon_new), 'g_file_icon_new'); LoadProc(Pointer(g_file_info_clear_status), 'g_file_info_clear_status'); LoadProc(Pointer(g_file_info_copy_into), 'g_file_info_copy_into'); LoadProc(Pointer(g_file_info_dup), 'g_file_info_dup'); LoadProc(Pointer(g_file_info_get_attribute_as_string), 'g_file_info_get_attribute_as_string'); LoadProc(Pointer(g_file_info_get_attribute_boolean), 'g_file_info_get_attribute_boolean'); LoadProc(Pointer(g_file_info_get_attribute_byte_string), 'g_file_info_get_attribute_byte_string'); LoadProc(Pointer(g_file_info_get_attribute_data), 'g_file_info_get_attribute_data'); LoadProc(Pointer(g_file_info_get_attribute_int32), 'g_file_info_get_attribute_int32'); LoadProc(Pointer(g_file_info_get_attribute_int64), 'g_file_info_get_attribute_int64'); LoadProc(Pointer(g_file_info_get_attribute_object), 'g_file_info_get_attribute_object'); LoadProc(Pointer(g_file_info_get_attribute_status), 'g_file_info_get_attribute_status'); LoadProc(Pointer(g_file_info_get_attribute_string), 'g_file_info_get_attribute_string'); LoadProc(Pointer(g_file_info_get_attribute_stringv), 'g_file_info_get_attribute_stringv'); LoadProc(Pointer(g_file_info_get_attribute_type), 'g_file_info_get_attribute_type'); LoadProc(Pointer(g_file_info_get_attribute_uint32), 'g_file_info_get_attribute_uint32'); LoadProc(Pointer(g_file_info_get_attribute_uint64), 'g_file_info_get_attribute_uint64'); LoadProc(Pointer(g_file_info_get_content_type), 'g_file_info_get_content_type'); LoadProc(Pointer(g_file_info_get_deletion_date), 'g_file_info_get_deletion_date'); LoadProc(Pointer(g_file_info_get_display_name), 'g_file_info_get_display_name'); LoadProc(Pointer(g_file_info_get_edit_name), 'g_file_info_get_edit_name'); LoadProc(Pointer(g_file_info_get_etag), 'g_file_info_get_etag'); LoadProc(Pointer(g_file_info_get_file_type), 'g_file_info_get_file_type'); LoadProc(Pointer(g_file_info_get_icon), 'g_file_info_get_icon'); LoadProc(Pointer(g_file_info_get_is_backup), 'g_file_info_get_is_backup'); LoadProc(Pointer(g_file_info_get_is_hidden), 'g_file_info_get_is_hidden'); LoadProc(Pointer(g_file_info_get_is_symlink), 'g_file_info_get_is_symlink'); LoadProc(Pointer(g_file_info_get_modification_time), 'g_file_info_get_modification_time'); LoadProc(Pointer(g_file_info_get_name), 'g_file_info_get_name'); LoadProc(Pointer(g_file_info_get_size), 'g_file_info_get_size'); LoadProc(Pointer(g_file_info_get_sort_order), 'g_file_info_get_sort_order'); LoadProc(Pointer(g_file_info_get_symbolic_icon), 'g_file_info_get_symbolic_icon'); LoadProc(Pointer(g_file_info_get_symlink_target), 'g_file_info_get_symlink_target'); LoadProc(Pointer(g_file_info_get_type), 'g_file_info_get_type'); LoadProc(Pointer(g_file_info_has_attribute), 'g_file_info_has_attribute'); LoadProc(Pointer(g_file_info_has_namespace), 'g_file_info_has_namespace'); LoadProc(Pointer(g_file_info_list_attributes), 'g_file_info_list_attributes'); LoadProc(Pointer(g_file_info_new), 'g_file_info_new'); LoadProc(Pointer(g_file_info_remove_attribute), 'g_file_info_remove_attribute'); LoadProc(Pointer(g_file_info_set_attribute), 'g_file_info_set_attribute'); LoadProc(Pointer(g_file_info_set_attribute_boolean), 'g_file_info_set_attribute_boolean'); LoadProc(Pointer(g_file_info_set_attribute_byte_string), 'g_file_info_set_attribute_byte_string'); LoadProc(Pointer(g_file_info_set_attribute_int32), 'g_file_info_set_attribute_int32'); LoadProc(Pointer(g_file_info_set_attribute_int64), 'g_file_info_set_attribute_int64'); LoadProc(Pointer(g_file_info_set_attribute_mask), 'g_file_info_set_attribute_mask'); LoadProc(Pointer(g_file_info_set_attribute_object), 'g_file_info_set_attribute_object'); LoadProc(Pointer(g_file_info_set_attribute_status), 'g_file_info_set_attribute_status'); LoadProc(Pointer(g_file_info_set_attribute_string), 'g_file_info_set_attribute_string'); LoadProc(Pointer(g_file_info_set_attribute_stringv), 'g_file_info_set_attribute_stringv'); LoadProc(Pointer(g_file_info_set_attribute_uint32), 'g_file_info_set_attribute_uint32'); LoadProc(Pointer(g_file_info_set_attribute_uint64), 'g_file_info_set_attribute_uint64'); LoadProc(Pointer(g_file_info_set_content_type), 'g_file_info_set_content_type'); LoadProc(Pointer(g_file_info_set_display_name), 'g_file_info_set_display_name'); LoadProc(Pointer(g_file_info_set_edit_name), 'g_file_info_set_edit_name'); LoadProc(Pointer(g_file_info_set_file_type), 'g_file_info_set_file_type'); LoadProc(Pointer(g_file_info_set_icon), 'g_file_info_set_icon'); LoadProc(Pointer(g_file_info_set_is_hidden), 'g_file_info_set_is_hidden'); LoadProc(Pointer(g_file_info_set_is_symlink), 'g_file_info_set_is_symlink'); LoadProc(Pointer(g_file_info_set_modification_time), 'g_file_info_set_modification_time'); LoadProc(Pointer(g_file_info_set_name), 'g_file_info_set_name'); LoadProc(Pointer(g_file_info_set_size), 'g_file_info_set_size'); LoadProc(Pointer(g_file_info_set_sort_order), 'g_file_info_set_sort_order'); LoadProc(Pointer(g_file_info_set_symbolic_icon), 'g_file_info_set_symbolic_icon'); LoadProc(Pointer(g_file_info_set_symlink_target), 'g_file_info_set_symlink_target'); LoadProc(Pointer(g_file_info_unset_attribute_mask), 'g_file_info_unset_attribute_mask'); LoadProc(Pointer(g_file_input_stream_get_type), 'g_file_input_stream_get_type'); LoadProc(Pointer(g_file_input_stream_query_info), 'g_file_input_stream_query_info'); LoadProc(Pointer(g_file_input_stream_query_info_async), 'g_file_input_stream_query_info_async'); LoadProc(Pointer(g_file_input_stream_query_info_finish), 'g_file_input_stream_query_info_finish'); LoadProc(Pointer(g_file_io_stream_get_etag), 'g_file_io_stream_get_etag'); LoadProc(Pointer(g_file_io_stream_get_type), 'g_file_io_stream_get_type'); LoadProc(Pointer(g_file_io_stream_query_info), 'g_file_io_stream_query_info'); LoadProc(Pointer(g_file_io_stream_query_info_async), 'g_file_io_stream_query_info_async'); LoadProc(Pointer(g_file_io_stream_query_info_finish), 'g_file_io_stream_query_info_finish'); LoadProc(Pointer(g_file_is_native), 'g_file_is_native'); LoadProc(Pointer(g_file_load_contents), 'g_file_load_contents'); LoadProc(Pointer(g_file_load_contents_async), 'g_file_load_contents_async'); LoadProc(Pointer(g_file_load_contents_finish), 'g_file_load_contents_finish'); LoadProc(Pointer(g_file_load_partial_contents_async), 'g_file_load_partial_contents_async'); LoadProc(Pointer(g_file_load_partial_contents_finish), 'g_file_load_partial_contents_finish'); LoadProc(Pointer(g_file_make_directory), 'g_file_make_directory'); LoadProc(Pointer(g_file_make_directory_with_parents), 'g_file_make_directory_with_parents'); LoadProc(Pointer(g_file_make_symbolic_link), 'g_file_make_symbolic_link'); LoadProc(Pointer(g_file_monitor), 'g_file_monitor'); LoadProc(Pointer(g_file_monitor_cancel), 'g_file_monitor_cancel'); LoadProc(Pointer(g_file_monitor_directory), 'g_file_monitor_directory'); LoadProc(Pointer(g_file_monitor_emit_event), 'g_file_monitor_emit_event'); LoadProc(Pointer(g_file_monitor_file), 'g_file_monitor_file'); LoadProc(Pointer(g_file_monitor_get_type), 'g_file_monitor_get_type'); LoadProc(Pointer(g_file_monitor_is_cancelled), 'g_file_monitor_is_cancelled'); LoadProc(Pointer(g_file_monitor_set_rate_limit), 'g_file_monitor_set_rate_limit'); LoadProc(Pointer(g_file_mount_enclosing_volume), 'g_file_mount_enclosing_volume'); LoadProc(Pointer(g_file_mount_enclosing_volume_finish), 'g_file_mount_enclosing_volume_finish'); LoadProc(Pointer(g_file_mount_mountable), 'g_file_mount_mountable'); LoadProc(Pointer(g_file_mount_mountable_finish), 'g_file_mount_mountable_finish'); LoadProc(Pointer(g_file_move), 'g_file_move'); LoadProc(Pointer(g_file_new_for_commandline_arg), 'g_file_new_for_commandline_arg'); LoadProc(Pointer(g_file_new_for_commandline_arg_and_cwd), 'g_file_new_for_commandline_arg_and_cwd'); LoadProc(Pointer(g_file_new_for_path), 'g_file_new_for_path'); LoadProc(Pointer(g_file_new_for_uri), 'g_file_new_for_uri'); LoadProc(Pointer(g_file_new_tmp), 'g_file_new_tmp'); LoadProc(Pointer(g_file_open_readwrite), 'g_file_open_readwrite'); LoadProc(Pointer(g_file_open_readwrite_async), 'g_file_open_readwrite_async'); LoadProc(Pointer(g_file_open_readwrite_finish), 'g_file_open_readwrite_finish'); LoadProc(Pointer(g_file_output_stream_get_etag), 'g_file_output_stream_get_etag'); LoadProc(Pointer(g_file_output_stream_get_type), 'g_file_output_stream_get_type'); LoadProc(Pointer(g_file_output_stream_query_info), 'g_file_output_stream_query_info'); LoadProc(Pointer(g_file_output_stream_query_info_async), 'g_file_output_stream_query_info_async'); LoadProc(Pointer(g_file_output_stream_query_info_finish), 'g_file_output_stream_query_info_finish'); LoadProc(Pointer(g_file_parse_name), 'g_file_parse_name'); LoadProc(Pointer(g_file_poll_mountable), 'g_file_poll_mountable'); LoadProc(Pointer(g_file_poll_mountable_finish), 'g_file_poll_mountable_finish'); LoadProc(Pointer(g_file_query_default_handler), 'g_file_query_default_handler'); LoadProc(Pointer(g_file_query_exists), 'g_file_query_exists'); LoadProc(Pointer(g_file_query_file_type), 'g_file_query_file_type'); LoadProc(Pointer(g_file_query_filesystem_info), 'g_file_query_filesystem_info'); LoadProc(Pointer(g_file_query_filesystem_info_async), 'g_file_query_filesystem_info_async'); LoadProc(Pointer(g_file_query_filesystem_info_finish), 'g_file_query_filesystem_info_finish'); LoadProc(Pointer(g_file_query_info), 'g_file_query_info'); LoadProc(Pointer(g_file_query_info_async), 'g_file_query_info_async'); LoadProc(Pointer(g_file_query_info_finish), 'g_file_query_info_finish'); LoadProc(Pointer(g_file_query_settable_attributes), 'g_file_query_settable_attributes'); LoadProc(Pointer(g_file_query_writable_namespaces), 'g_file_query_writable_namespaces'); LoadProc(Pointer(g_file_read), 'g_file_read'); LoadProc(Pointer(g_file_read_async), 'g_file_read_async'); LoadProc(Pointer(g_file_read_finish), 'g_file_read_finish'); LoadProc(Pointer(g_file_replace), 'g_file_replace'); LoadProc(Pointer(g_file_replace_async), 'g_file_replace_async'); LoadProc(Pointer(g_file_replace_contents), 'g_file_replace_contents'); LoadProc(Pointer(g_file_replace_contents_async), 'g_file_replace_contents_async'); LoadProc(Pointer(g_file_replace_contents_finish), 'g_file_replace_contents_finish'); LoadProc(Pointer(g_file_replace_finish), 'g_file_replace_finish'); LoadProc(Pointer(g_file_replace_readwrite), 'g_file_replace_readwrite'); LoadProc(Pointer(g_file_replace_readwrite_async), 'g_file_replace_readwrite_async'); LoadProc(Pointer(g_file_replace_readwrite_finish), 'g_file_replace_readwrite_finish'); LoadProc(Pointer(g_file_resolve_relative_path), 'g_file_resolve_relative_path'); LoadProc(Pointer(g_file_set_attribute), 'g_file_set_attribute'); LoadProc(Pointer(g_file_set_attribute_byte_string), 'g_file_set_attribute_byte_string'); LoadProc(Pointer(g_file_set_attribute_int32), 'g_file_set_attribute_int32'); LoadProc(Pointer(g_file_set_attribute_int64), 'g_file_set_attribute_int64'); LoadProc(Pointer(g_file_set_attribute_string), 'g_file_set_attribute_string'); LoadProc(Pointer(g_file_set_attribute_uint32), 'g_file_set_attribute_uint32'); LoadProc(Pointer(g_file_set_attribute_uint64), 'g_file_set_attribute_uint64'); LoadProc(Pointer(g_file_set_attributes_async), 'g_file_set_attributes_async'); LoadProc(Pointer(g_file_set_attributes_finish), 'g_file_set_attributes_finish'); LoadProc(Pointer(g_file_set_attributes_from_info), 'g_file_set_attributes_from_info'); LoadProc(Pointer(g_file_set_display_name), 'g_file_set_display_name'); LoadProc(Pointer(g_file_set_display_name_async), 'g_file_set_display_name_async'); LoadProc(Pointer(g_file_set_display_name_finish), 'g_file_set_display_name_finish'); LoadProc(Pointer(g_file_start_mountable), 'g_file_start_mountable'); LoadProc(Pointer(g_file_start_mountable_finish), 'g_file_start_mountable_finish'); LoadProc(Pointer(g_file_stop_mountable), 'g_file_stop_mountable'); LoadProc(Pointer(g_file_stop_mountable_finish), 'g_file_stop_mountable_finish'); LoadProc(Pointer(g_file_supports_thread_contexts), 'g_file_supports_thread_contexts'); LoadProc(Pointer(g_file_trash), 'g_file_trash'); LoadProc(Pointer(g_file_unmount_mountable_with_operation), 'g_file_unmount_mountable_with_operation'); LoadProc(Pointer(g_file_unmount_mountable_with_operation_finish), 'g_file_unmount_mountable_with_operation_finish'); LoadProc(Pointer(g_filename_completer_get_completion_suffix), 'g_filename_completer_get_completion_suffix'); LoadProc(Pointer(g_filename_completer_get_completions), 'g_filename_completer_get_completions'); LoadProc(Pointer(g_filename_completer_get_type), 'g_filename_completer_get_type'); LoadProc(Pointer(g_filename_completer_new), 'g_filename_completer_new'); LoadProc(Pointer(g_filename_completer_set_dirs_only), 'g_filename_completer_set_dirs_only'); LoadProc(Pointer(g_filter_input_stream_get_base_stream), 'g_filter_input_stream_get_base_stream'); LoadProc(Pointer(g_filter_input_stream_get_close_base_stream), 'g_filter_input_stream_get_close_base_stream'); LoadProc(Pointer(g_filter_input_stream_get_type), 'g_filter_input_stream_get_type'); LoadProc(Pointer(g_filter_input_stream_set_close_base_stream), 'g_filter_input_stream_set_close_base_stream'); LoadProc(Pointer(g_filter_output_stream_get_base_stream), 'g_filter_output_stream_get_base_stream'); LoadProc(Pointer(g_filter_output_stream_get_close_base_stream), 'g_filter_output_stream_get_close_base_stream'); LoadProc(Pointer(g_filter_output_stream_get_type), 'g_filter_output_stream_get_type'); LoadProc(Pointer(g_filter_output_stream_set_close_base_stream), 'g_filter_output_stream_set_close_base_stream'); LoadProc(Pointer(g_icon_equal), 'g_icon_equal'); LoadProc(Pointer(g_icon_get_type), 'g_icon_get_type'); LoadProc(Pointer(g_icon_hash), 'g_icon_hash'); LoadProc(Pointer(g_icon_new_for_string), 'g_icon_new_for_string'); LoadProc(Pointer(g_icon_to_string), 'g_icon_to_string'); LoadProc(Pointer(g_inet_address_equal), 'g_inet_address_equal'); LoadProc(Pointer(g_inet_address_get_family), 'g_inet_address_get_family'); LoadProc(Pointer(g_inet_address_get_is_any), 'g_inet_address_get_is_any'); LoadProc(Pointer(g_inet_address_get_is_link_local), 'g_inet_address_get_is_link_local'); LoadProc(Pointer(g_inet_address_get_is_loopback), 'g_inet_address_get_is_loopback'); LoadProc(Pointer(g_inet_address_get_is_mc_global), 'g_inet_address_get_is_mc_global'); LoadProc(Pointer(g_inet_address_get_is_mc_link_local), 'g_inet_address_get_is_mc_link_local'); LoadProc(Pointer(g_inet_address_get_is_mc_node_local), 'g_inet_address_get_is_mc_node_local'); LoadProc(Pointer(g_inet_address_get_is_mc_org_local), 'g_inet_address_get_is_mc_org_local'); LoadProc(Pointer(g_inet_address_get_is_mc_site_local), 'g_inet_address_get_is_mc_site_local'); LoadProc(Pointer(g_inet_address_get_is_multicast), 'g_inet_address_get_is_multicast'); LoadProc(Pointer(g_inet_address_get_is_site_local), 'g_inet_address_get_is_site_local'); LoadProc(Pointer(g_inet_address_get_native_size), 'g_inet_address_get_native_size'); LoadProc(Pointer(g_inet_address_get_type), 'g_inet_address_get_type'); LoadProc(Pointer(g_inet_address_mask_equal), 'g_inet_address_mask_equal'); LoadProc(Pointer(g_inet_address_mask_get_address), 'g_inet_address_mask_get_address'); LoadProc(Pointer(g_inet_address_mask_get_family), 'g_inet_address_mask_get_family'); LoadProc(Pointer(g_inet_address_mask_get_length), 'g_inet_address_mask_get_length'); LoadProc(Pointer(g_inet_address_mask_get_type), 'g_inet_address_mask_get_type'); LoadProc(Pointer(g_inet_address_mask_matches), 'g_inet_address_mask_matches'); LoadProc(Pointer(g_inet_address_mask_new), 'g_inet_address_mask_new'); LoadProc(Pointer(g_inet_address_mask_new_from_string), 'g_inet_address_mask_new_from_string'); LoadProc(Pointer(g_inet_address_mask_to_string), 'g_inet_address_mask_to_string'); LoadProc(Pointer(g_inet_address_new_any), 'g_inet_address_new_any'); LoadProc(Pointer(g_inet_address_new_from_bytes), 'g_inet_address_new_from_bytes'); LoadProc(Pointer(g_inet_address_new_from_string), 'g_inet_address_new_from_string'); LoadProc(Pointer(g_inet_address_new_loopback), 'g_inet_address_new_loopback'); LoadProc(Pointer(g_inet_address_to_bytes), 'g_inet_address_to_bytes'); LoadProc(Pointer(g_inet_address_to_string), 'g_inet_address_to_string'); LoadProc(Pointer(g_inet_socket_address_get_address), 'g_inet_socket_address_get_address'); LoadProc(Pointer(g_inet_socket_address_get_flowinfo), 'g_inet_socket_address_get_flowinfo'); LoadProc(Pointer(g_inet_socket_address_get_port), 'g_inet_socket_address_get_port'); LoadProc(Pointer(g_inet_socket_address_get_scope_id), 'g_inet_socket_address_get_scope_id'); LoadProc(Pointer(g_inet_socket_address_get_type), 'g_inet_socket_address_get_type'); LoadProc(Pointer(g_inet_socket_address_new), 'g_inet_socket_address_new'); LoadProc(Pointer(g_initable_get_type), 'g_initable_get_type'); LoadProc(Pointer(g_initable_init), 'g_initable_init'); LoadProc(Pointer(g_initable_new), 'g_initable_new'); LoadProc(Pointer(g_initable_new_valist), 'g_initable_new_valist'); LoadProc(Pointer(g_initable_newv), 'g_initable_newv'); LoadProc(Pointer(g_input_stream_clear_pending), 'g_input_stream_clear_pending'); LoadProc(Pointer(g_input_stream_close), 'g_input_stream_close'); LoadProc(Pointer(g_input_stream_close_async), 'g_input_stream_close_async'); LoadProc(Pointer(g_input_stream_close_finish), 'g_input_stream_close_finish'); LoadProc(Pointer(g_input_stream_get_type), 'g_input_stream_get_type'); LoadProc(Pointer(g_input_stream_has_pending), 'g_input_stream_has_pending'); LoadProc(Pointer(g_input_stream_is_closed), 'g_input_stream_is_closed'); LoadProc(Pointer(g_input_stream_read), 'g_input_stream_read'); LoadProc(Pointer(g_input_stream_read_all), 'g_input_stream_read_all'); LoadProc(Pointer(g_input_stream_read_async), 'g_input_stream_read_async'); LoadProc(Pointer(g_input_stream_read_bytes), 'g_input_stream_read_bytes'); LoadProc(Pointer(g_input_stream_read_bytes_async), 'g_input_stream_read_bytes_async'); LoadProc(Pointer(g_input_stream_read_bytes_finish), 'g_input_stream_read_bytes_finish'); LoadProc(Pointer(g_input_stream_read_finish), 'g_input_stream_read_finish'); LoadProc(Pointer(g_input_stream_set_pending), 'g_input_stream_set_pending'); LoadProc(Pointer(g_input_stream_skip), 'g_input_stream_skip'); LoadProc(Pointer(g_input_stream_skip_async), 'g_input_stream_skip_async'); LoadProc(Pointer(g_input_stream_skip_finish), 'g_input_stream_skip_finish'); LoadProc(Pointer(g_io_error_from_errno), 'g_io_error_from_errno'); LoadProc(Pointer(g_io_error_quark), 'g_io_error_quark'); LoadProc(Pointer(g_io_extension_get_name), 'g_io_extension_get_name'); LoadProc(Pointer(g_io_extension_get_priority), 'g_io_extension_get_priority'); LoadProc(Pointer(g_io_extension_get_type), 'g_io_extension_get_type'); LoadProc(Pointer(g_io_extension_point_get_extension_by_name), 'g_io_extension_point_get_extension_by_name'); LoadProc(Pointer(g_io_extension_point_get_extensions), 'g_io_extension_point_get_extensions'); LoadProc(Pointer(g_io_extension_point_get_required_type), 'g_io_extension_point_get_required_type'); LoadProc(Pointer(g_io_extension_point_implement), 'g_io_extension_point_implement'); LoadProc(Pointer(g_io_extension_point_lookup), 'g_io_extension_point_lookup'); LoadProc(Pointer(g_io_extension_point_register), 'g_io_extension_point_register'); LoadProc(Pointer(g_io_extension_point_set_required_type), 'g_io_extension_point_set_required_type'); LoadProc(Pointer(g_io_extension_ref_class), 'g_io_extension_ref_class'); LoadProc(Pointer(g_io_module_get_type), 'g_io_module_get_type'); LoadProc(Pointer(g_io_module_new), 'g_io_module_new'); LoadProc(Pointer(g_io_module_scope_block), 'g_io_module_scope_block'); LoadProc(Pointer(g_io_module_scope_free), 'g_io_module_scope_free'); LoadProc(Pointer(g_io_module_scope_new), 'g_io_module_scope_new'); LoadProc(Pointer(g_io_modules_load_all_in_directory), 'g_io_modules_load_all_in_directory'); LoadProc(Pointer(g_io_modules_load_all_in_directory_with_scope), 'g_io_modules_load_all_in_directory_with_scope'); LoadProc(Pointer(g_io_modules_scan_all_in_directory), 'g_io_modules_scan_all_in_directory'); LoadProc(Pointer(g_io_modules_scan_all_in_directory_with_scope), 'g_io_modules_scan_all_in_directory_with_scope'); LoadProc(Pointer(g_io_scheduler_cancel_all_jobs), 'g_io_scheduler_cancel_all_jobs'); LoadProc(Pointer(g_io_scheduler_push_job), 'g_io_scheduler_push_job'); LoadProc(Pointer(g_io_stream_clear_pending), 'g_io_stream_clear_pending'); LoadProc(Pointer(g_io_stream_close), 'g_io_stream_close'); LoadProc(Pointer(g_io_stream_close_async), 'g_io_stream_close_async'); LoadProc(Pointer(g_io_stream_close_finish), 'g_io_stream_close_finish'); LoadProc(Pointer(g_io_stream_get_input_stream), 'g_io_stream_get_input_stream'); LoadProc(Pointer(g_io_stream_get_output_stream), 'g_io_stream_get_output_stream'); LoadProc(Pointer(g_io_stream_get_type), 'g_io_stream_get_type'); LoadProc(Pointer(g_io_stream_has_pending), 'g_io_stream_has_pending'); LoadProc(Pointer(g_io_stream_is_closed), 'g_io_stream_is_closed'); LoadProc(Pointer(g_io_stream_set_pending), 'g_io_stream_set_pending'); LoadProc(Pointer(g_io_stream_splice_async), 'g_io_stream_splice_async'); LoadProc(Pointer(g_io_stream_splice_finish), 'g_io_stream_splice_finish'); LoadProc(Pointer(g_loadable_icon_get_type), 'g_loadable_icon_get_type'); LoadProc(Pointer(g_loadable_icon_load), 'g_loadable_icon_load'); LoadProc(Pointer(g_loadable_icon_load_async), 'g_loadable_icon_load_async'); LoadProc(Pointer(g_loadable_icon_load_finish), 'g_loadable_icon_load_finish'); LoadProc(Pointer(g_memory_input_stream_add_bytes), 'g_memory_input_stream_add_bytes'); LoadProc(Pointer(g_memory_input_stream_add_data), 'g_memory_input_stream_add_data'); LoadProc(Pointer(g_memory_input_stream_get_type), 'g_memory_input_stream_get_type'); LoadProc(Pointer(g_memory_input_stream_new), 'g_memory_input_stream_new'); LoadProc(Pointer(g_memory_input_stream_new_from_bytes), 'g_memory_input_stream_new_from_bytes'); LoadProc(Pointer(g_memory_input_stream_new_from_data), 'g_memory_input_stream_new_from_data'); LoadProc(Pointer(g_memory_output_stream_get_data), 'g_memory_output_stream_get_data'); LoadProc(Pointer(g_memory_output_stream_get_data_size), 'g_memory_output_stream_get_data_size'); LoadProc(Pointer(g_memory_output_stream_get_size), 'g_memory_output_stream_get_size'); LoadProc(Pointer(g_memory_output_stream_get_type), 'g_memory_output_stream_get_type'); LoadProc(Pointer(g_memory_output_stream_new), 'g_memory_output_stream_new'); LoadProc(Pointer(g_memory_output_stream_new_resizable), 'g_memory_output_stream_new_resizable'); LoadProc(Pointer(g_memory_output_stream_steal_as_bytes), 'g_memory_output_stream_steal_as_bytes'); LoadProc(Pointer(g_memory_output_stream_steal_data), 'g_memory_output_stream_steal_data'); LoadProc(Pointer(g_menu_append), 'g_menu_append'); LoadProc(Pointer(g_menu_append_item), 'g_menu_append_item'); LoadProc(Pointer(g_menu_append_section), 'g_menu_append_section'); LoadProc(Pointer(g_menu_append_submenu), 'g_menu_append_submenu'); LoadProc(Pointer(g_menu_attribute_iter_get_name), 'g_menu_attribute_iter_get_name'); LoadProc(Pointer(g_menu_attribute_iter_get_next), 'g_menu_attribute_iter_get_next'); LoadProc(Pointer(g_menu_attribute_iter_get_type), 'g_menu_attribute_iter_get_type'); LoadProc(Pointer(g_menu_attribute_iter_get_value), 'g_menu_attribute_iter_get_value'); LoadProc(Pointer(g_menu_attribute_iter_next), 'g_menu_attribute_iter_next'); LoadProc(Pointer(g_menu_freeze), 'g_menu_freeze'); LoadProc(Pointer(g_menu_get_type), 'g_menu_get_type'); LoadProc(Pointer(g_menu_insert), 'g_menu_insert'); LoadProc(Pointer(g_menu_insert_item), 'g_menu_insert_item'); LoadProc(Pointer(g_menu_insert_section), 'g_menu_insert_section'); LoadProc(Pointer(g_menu_insert_submenu), 'g_menu_insert_submenu'); LoadProc(Pointer(g_menu_item_get_attribute), 'g_menu_item_get_attribute'); LoadProc(Pointer(g_menu_item_get_attribute_value), 'g_menu_item_get_attribute_value'); LoadProc(Pointer(g_menu_item_get_link), 'g_menu_item_get_link'); LoadProc(Pointer(g_menu_item_get_type), 'g_menu_item_get_type'); LoadProc(Pointer(g_menu_item_new), 'g_menu_item_new'); LoadProc(Pointer(g_menu_item_new_from_model), 'g_menu_item_new_from_model'); LoadProc(Pointer(g_menu_item_new_section), 'g_menu_item_new_section'); LoadProc(Pointer(g_menu_item_new_submenu), 'g_menu_item_new_submenu'); LoadProc(Pointer(g_menu_item_set_action_and_target), 'g_menu_item_set_action_and_target'); LoadProc(Pointer(g_menu_item_set_action_and_target_value), 'g_menu_item_set_action_and_target_value'); LoadProc(Pointer(g_menu_item_set_attribute), 'g_menu_item_set_attribute'); LoadProc(Pointer(g_menu_item_set_attribute_value), 'g_menu_item_set_attribute_value'); LoadProc(Pointer(g_menu_item_set_detailed_action), 'g_menu_item_set_detailed_action'); LoadProc(Pointer(g_menu_item_set_label), 'g_menu_item_set_label'); LoadProc(Pointer(g_menu_item_set_link), 'g_menu_item_set_link'); LoadProc(Pointer(g_menu_item_set_section), 'g_menu_item_set_section'); LoadProc(Pointer(g_menu_item_set_submenu), 'g_menu_item_set_submenu'); LoadProc(Pointer(g_menu_link_iter_get_name), 'g_menu_link_iter_get_name'); LoadProc(Pointer(g_menu_link_iter_get_next), 'g_menu_link_iter_get_next'); LoadProc(Pointer(g_menu_link_iter_get_type), 'g_menu_link_iter_get_type'); LoadProc(Pointer(g_menu_link_iter_get_value), 'g_menu_link_iter_get_value'); LoadProc(Pointer(g_menu_link_iter_next), 'g_menu_link_iter_next'); LoadProc(Pointer(g_menu_model_get_item_attribute), 'g_menu_model_get_item_attribute'); LoadProc(Pointer(g_menu_model_get_item_attribute_value), 'g_menu_model_get_item_attribute_value'); LoadProc(Pointer(g_menu_model_get_item_link), 'g_menu_model_get_item_link'); LoadProc(Pointer(g_menu_model_get_n_items), 'g_menu_model_get_n_items'); LoadProc(Pointer(g_menu_model_get_type), 'g_menu_model_get_type'); LoadProc(Pointer(g_menu_model_is_mutable), 'g_menu_model_is_mutable'); LoadProc(Pointer(g_menu_model_items_changed), 'g_menu_model_items_changed'); LoadProc(Pointer(g_menu_model_iterate_item_attributes), 'g_menu_model_iterate_item_attributes'); LoadProc(Pointer(g_menu_model_iterate_item_links), 'g_menu_model_iterate_item_links'); LoadProc(Pointer(g_menu_new), 'g_menu_new'); LoadProc(Pointer(g_menu_prepend), 'g_menu_prepend'); LoadProc(Pointer(g_menu_prepend_item), 'g_menu_prepend_item'); LoadProc(Pointer(g_menu_prepend_section), 'g_menu_prepend_section'); LoadProc(Pointer(g_menu_prepend_submenu), 'g_menu_prepend_submenu'); LoadProc(Pointer(g_menu_remove), 'g_menu_remove'); LoadProc(Pointer(g_mount_can_eject), 'g_mount_can_eject'); LoadProc(Pointer(g_mount_can_unmount), 'g_mount_can_unmount'); LoadProc(Pointer(g_mount_eject_with_operation), 'g_mount_eject_with_operation'); LoadProc(Pointer(g_mount_eject_with_operation_finish), 'g_mount_eject_with_operation_finish'); LoadProc(Pointer(g_mount_get_default_location), 'g_mount_get_default_location'); LoadProc(Pointer(g_mount_get_drive), 'g_mount_get_drive'); LoadProc(Pointer(g_mount_get_icon), 'g_mount_get_icon'); LoadProc(Pointer(g_mount_get_name), 'g_mount_get_name'); LoadProc(Pointer(g_mount_get_root), 'g_mount_get_root'); LoadProc(Pointer(g_mount_get_sort_key), 'g_mount_get_sort_key'); LoadProc(Pointer(g_mount_get_symbolic_icon), 'g_mount_get_symbolic_icon'); LoadProc(Pointer(g_mount_get_type), 'g_mount_get_type'); LoadProc(Pointer(g_mount_get_uuid), 'g_mount_get_uuid'); LoadProc(Pointer(g_mount_get_volume), 'g_mount_get_volume'); LoadProc(Pointer(g_mount_guess_content_type), 'g_mount_guess_content_type'); LoadProc(Pointer(g_mount_guess_content_type_finish), 'g_mount_guess_content_type_finish'); LoadProc(Pointer(g_mount_guess_content_type_sync), 'g_mount_guess_content_type_sync'); LoadProc(Pointer(g_mount_is_shadowed), 'g_mount_is_shadowed'); LoadProc(Pointer(g_mount_operation_get_anonymous), 'g_mount_operation_get_anonymous'); LoadProc(Pointer(g_mount_operation_get_choice), 'g_mount_operation_get_choice'); LoadProc(Pointer(g_mount_operation_get_domain), 'g_mount_operation_get_domain'); LoadProc(Pointer(g_mount_operation_get_password), 'g_mount_operation_get_password'); LoadProc(Pointer(g_mount_operation_get_password_save), 'g_mount_operation_get_password_save'); LoadProc(Pointer(g_mount_operation_get_type), 'g_mount_operation_get_type'); LoadProc(Pointer(g_mount_operation_get_username), 'g_mount_operation_get_username'); LoadProc(Pointer(g_mount_operation_new), 'g_mount_operation_new'); LoadProc(Pointer(g_mount_operation_reply), 'g_mount_operation_reply'); LoadProc(Pointer(g_mount_operation_set_anonymous), 'g_mount_operation_set_anonymous'); LoadProc(Pointer(g_mount_operation_set_choice), 'g_mount_operation_set_choice'); LoadProc(Pointer(g_mount_operation_set_domain), 'g_mount_operation_set_domain'); LoadProc(Pointer(g_mount_operation_set_password), 'g_mount_operation_set_password'); LoadProc(Pointer(g_mount_operation_set_password_save), 'g_mount_operation_set_password_save'); LoadProc(Pointer(g_mount_operation_set_username), 'g_mount_operation_set_username'); LoadProc(Pointer(g_mount_remount), 'g_mount_remount'); LoadProc(Pointer(g_mount_remount_finish), 'g_mount_remount_finish'); LoadProc(Pointer(g_mount_shadow), 'g_mount_shadow'); LoadProc(Pointer(g_mount_unmount_with_operation), 'g_mount_unmount_with_operation'); LoadProc(Pointer(g_mount_unmount_with_operation_finish), 'g_mount_unmount_with_operation_finish'); LoadProc(Pointer(g_mount_unshadow), 'g_mount_unshadow'); LoadProc(Pointer(g_native_volume_monitor_get_type), 'g_native_volume_monitor_get_type'); LoadProc(Pointer(g_network_address_get_hostname), 'g_network_address_get_hostname'); LoadProc(Pointer(g_network_address_get_port), 'g_network_address_get_port'); LoadProc(Pointer(g_network_address_get_scheme), 'g_network_address_get_scheme'); LoadProc(Pointer(g_network_address_get_type), 'g_network_address_get_type'); LoadProc(Pointer(g_network_address_new), 'g_network_address_new'); LoadProc(Pointer(g_network_address_parse), 'g_network_address_parse'); LoadProc(Pointer(g_network_address_parse_uri), 'g_network_address_parse_uri'); LoadProc(Pointer(g_network_monitor_can_reach), 'g_network_monitor_can_reach'); LoadProc(Pointer(g_network_monitor_can_reach_async), 'g_network_monitor_can_reach_async'); LoadProc(Pointer(g_network_monitor_can_reach_finish), 'g_network_monitor_can_reach_finish'); LoadProc(Pointer(g_network_monitor_get_default), 'g_network_monitor_get_default'); LoadProc(Pointer(g_network_monitor_get_network_available), 'g_network_monitor_get_network_available'); LoadProc(Pointer(g_network_monitor_get_type), 'g_network_monitor_get_type'); LoadProc(Pointer(g_network_service_get_domain), 'g_network_service_get_domain'); LoadProc(Pointer(g_network_service_get_protocol), 'g_network_service_get_protocol'); LoadProc(Pointer(g_network_service_get_scheme), 'g_network_service_get_scheme'); LoadProc(Pointer(g_network_service_get_service), 'g_network_service_get_service'); LoadProc(Pointer(g_network_service_get_type), 'g_network_service_get_type'); LoadProc(Pointer(g_network_service_new), 'g_network_service_new'); LoadProc(Pointer(g_network_service_set_scheme), 'g_network_service_set_scheme'); LoadProc(Pointer(g_networking_init), 'g_networking_init'); LoadProc(Pointer(g_output_stream_clear_pending), 'g_output_stream_clear_pending'); LoadProc(Pointer(g_output_stream_close), 'g_output_stream_close'); LoadProc(Pointer(g_output_stream_close_async), 'g_output_stream_close_async'); LoadProc(Pointer(g_output_stream_close_finish), 'g_output_stream_close_finish'); LoadProc(Pointer(g_output_stream_flush), 'g_output_stream_flush'); LoadProc(Pointer(g_output_stream_flush_async), 'g_output_stream_flush_async'); LoadProc(Pointer(g_output_stream_flush_finish), 'g_output_stream_flush_finish'); LoadProc(Pointer(g_output_stream_get_type), 'g_output_stream_get_type'); LoadProc(Pointer(g_output_stream_has_pending), 'g_output_stream_has_pending'); LoadProc(Pointer(g_output_stream_is_closed), 'g_output_stream_is_closed'); LoadProc(Pointer(g_output_stream_is_closing), 'g_output_stream_is_closing'); LoadProc(Pointer(g_output_stream_set_pending), 'g_output_stream_set_pending'); LoadProc(Pointer(g_output_stream_splice), 'g_output_stream_splice'); LoadProc(Pointer(g_output_stream_splice_async), 'g_output_stream_splice_async'); LoadProc(Pointer(g_output_stream_splice_finish), 'g_output_stream_splice_finish'); LoadProc(Pointer(g_output_stream_write), 'g_output_stream_write'); LoadProc(Pointer(g_output_stream_write_all), 'g_output_stream_write_all'); LoadProc(Pointer(g_output_stream_write_async), 'g_output_stream_write_async'); LoadProc(Pointer(g_output_stream_write_bytes), 'g_output_stream_write_bytes'); LoadProc(Pointer(g_output_stream_write_bytes_async), 'g_output_stream_write_bytes_async'); LoadProc(Pointer(g_output_stream_write_bytes_finish), 'g_output_stream_write_bytes_finish'); LoadProc(Pointer(g_output_stream_write_finish), 'g_output_stream_write_finish'); LoadProc(Pointer(g_permission_acquire), 'g_permission_acquire'); LoadProc(Pointer(g_permission_acquire_async), 'g_permission_acquire_async'); LoadProc(Pointer(g_permission_acquire_finish), 'g_permission_acquire_finish'); LoadProc(Pointer(g_permission_get_allowed), 'g_permission_get_allowed'); LoadProc(Pointer(g_permission_get_can_acquire), 'g_permission_get_can_acquire'); LoadProc(Pointer(g_permission_get_can_release), 'g_permission_get_can_release'); LoadProc(Pointer(g_permission_get_type), 'g_permission_get_type'); LoadProc(Pointer(g_permission_impl_update), 'g_permission_impl_update'); LoadProc(Pointer(g_permission_release), 'g_permission_release'); LoadProc(Pointer(g_permission_release_async), 'g_permission_release_async'); LoadProc(Pointer(g_permission_release_finish), 'g_permission_release_finish'); LoadProc(Pointer(g_pollable_input_stream_can_poll), 'g_pollable_input_stream_can_poll'); LoadProc(Pointer(g_pollable_input_stream_create_source), 'g_pollable_input_stream_create_source'); LoadProc(Pointer(g_pollable_input_stream_get_type), 'g_pollable_input_stream_get_type'); LoadProc(Pointer(g_pollable_input_stream_is_readable), 'g_pollable_input_stream_is_readable'); LoadProc(Pointer(g_pollable_input_stream_read_nonblocking), 'g_pollable_input_stream_read_nonblocking'); LoadProc(Pointer(g_pollable_output_stream_can_poll), 'g_pollable_output_stream_can_poll'); LoadProc(Pointer(g_pollable_output_stream_create_source), 'g_pollable_output_stream_create_source'); LoadProc(Pointer(g_pollable_output_stream_get_type), 'g_pollable_output_stream_get_type'); LoadProc(Pointer(g_pollable_output_stream_is_writable), 'g_pollable_output_stream_is_writable'); LoadProc(Pointer(g_pollable_output_stream_write_nonblocking), 'g_pollable_output_stream_write_nonblocking'); LoadProc(Pointer(g_pollable_source_new), 'g_pollable_source_new'); LoadProc(Pointer(g_pollable_source_new_full), 'g_pollable_source_new_full'); LoadProc(Pointer(g_pollable_stream_read), 'g_pollable_stream_read'); LoadProc(Pointer(g_pollable_stream_write), 'g_pollable_stream_write'); LoadProc(Pointer(g_pollable_stream_write_all), 'g_pollable_stream_write_all'); LoadProc(Pointer(g_proxy_address_enumerator_get_type), 'g_proxy_address_enumerator_get_type'); LoadProc(Pointer(g_proxy_address_get_destination_hostname), 'g_proxy_address_get_destination_hostname'); LoadProc(Pointer(g_proxy_address_get_destination_port), 'g_proxy_address_get_destination_port'); LoadProc(Pointer(g_proxy_address_get_destination_protocol), 'g_proxy_address_get_destination_protocol'); LoadProc(Pointer(g_proxy_address_get_password), 'g_proxy_address_get_password'); LoadProc(Pointer(g_proxy_address_get_protocol), 'g_proxy_address_get_protocol'); LoadProc(Pointer(g_proxy_address_get_type), 'g_proxy_address_get_type'); LoadProc(Pointer(g_proxy_address_get_uri), 'g_proxy_address_get_uri'); LoadProc(Pointer(g_proxy_address_get_username), 'g_proxy_address_get_username'); LoadProc(Pointer(g_proxy_address_new), 'g_proxy_address_new'); LoadProc(Pointer(g_proxy_connect), 'g_proxy_connect'); LoadProc(Pointer(g_proxy_connect_async), 'g_proxy_connect_async'); LoadProc(Pointer(g_proxy_connect_finish), 'g_proxy_connect_finish'); LoadProc(Pointer(g_proxy_get_default_for_protocol), 'g_proxy_get_default_for_protocol'); LoadProc(Pointer(g_proxy_get_type), 'g_proxy_get_type'); LoadProc(Pointer(g_proxy_resolver_get_default), 'g_proxy_resolver_get_default'); LoadProc(Pointer(g_proxy_resolver_get_type), 'g_proxy_resolver_get_type'); LoadProc(Pointer(g_proxy_resolver_is_supported), 'g_proxy_resolver_is_supported'); LoadProc(Pointer(g_proxy_resolver_lookup), 'g_proxy_resolver_lookup'); LoadProc(Pointer(g_proxy_resolver_lookup_async), 'g_proxy_resolver_lookup_async'); LoadProc(Pointer(g_proxy_resolver_lookup_finish), 'g_proxy_resolver_lookup_finish'); LoadProc(Pointer(g_proxy_supports_hostname), 'g_proxy_supports_hostname'); LoadProc(Pointer(g_remote_action_group_activate_action_full), 'g_remote_action_group_activate_action_full'); LoadProc(Pointer(g_remote_action_group_change_action_state_full), 'g_remote_action_group_change_action_state_full'); LoadProc(Pointer(g_remote_action_group_get_type), 'g_remote_action_group_get_type'); LoadProc(Pointer(g_resolver_error_quark), 'g_resolver_error_quark'); LoadProc(Pointer(g_resolver_free_addresses), 'g_resolver_free_addresses'); LoadProc(Pointer(g_resolver_free_targets), 'g_resolver_free_targets'); LoadProc(Pointer(g_resolver_get_default), 'g_resolver_get_default'); LoadProc(Pointer(g_resolver_get_type), 'g_resolver_get_type'); LoadProc(Pointer(g_resolver_lookup_by_address), 'g_resolver_lookup_by_address'); LoadProc(Pointer(g_resolver_lookup_by_address_async), 'g_resolver_lookup_by_address_async'); LoadProc(Pointer(g_resolver_lookup_by_address_finish), 'g_resolver_lookup_by_address_finish'); LoadProc(Pointer(g_resolver_lookup_by_name), 'g_resolver_lookup_by_name'); LoadProc(Pointer(g_resolver_lookup_by_name_async), 'g_resolver_lookup_by_name_async'); LoadProc(Pointer(g_resolver_lookup_by_name_finish), 'g_resolver_lookup_by_name_finish'); LoadProc(Pointer(g_resolver_lookup_records), 'g_resolver_lookup_records'); LoadProc(Pointer(g_resolver_lookup_records_async), 'g_resolver_lookup_records_async'); LoadProc(Pointer(g_resolver_lookup_records_finish), 'g_resolver_lookup_records_finish'); LoadProc(Pointer(g_resolver_lookup_service), 'g_resolver_lookup_service'); LoadProc(Pointer(g_resolver_lookup_service_async), 'g_resolver_lookup_service_async'); LoadProc(Pointer(g_resolver_lookup_service_finish), 'g_resolver_lookup_service_finish'); LoadProc(Pointer(g_resolver_set_default), 'g_resolver_set_default'); LoadProc(Pointer(g_resource_enumerate_children), 'g_resource_enumerate_children'); LoadProc(Pointer(g_resource_error_quark), 'g_resource_error_quark'); LoadProc(Pointer(g_resource_get_info), 'g_resource_get_info'); LoadProc(Pointer(g_resource_get_type), 'g_resource_get_type'); LoadProc(Pointer(g_resource_load), 'g_resource_load'); LoadProc(Pointer(g_resource_lookup_data), 'g_resource_lookup_data'); LoadProc(Pointer(g_resource_new_from_data), 'g_resource_new_from_data'); LoadProc(Pointer(g_resource_open_stream), 'g_resource_open_stream'); LoadProc(Pointer(g_resource_ref), 'g_resource_ref'); LoadProc(Pointer(g_resource_unref), 'g_resource_unref'); LoadProc(Pointer(g_resources_enumerate_children), 'g_resources_enumerate_children'); LoadProc(Pointer(g_resources_get_info), 'g_resources_get_info'); LoadProc(Pointer(g_resources_lookup_data), 'g_resources_lookup_data'); LoadProc(Pointer(g_resources_open_stream), 'g_resources_open_stream'); LoadProc(Pointer(g_resources_register), 'g_resources_register'); LoadProc(Pointer(g_resources_unregister), 'g_resources_unregister'); LoadProc(Pointer(g_seekable_can_seek), 'g_seekable_can_seek'); LoadProc(Pointer(g_seekable_can_truncate), 'g_seekable_can_truncate'); LoadProc(Pointer(g_seekable_get_type), 'g_seekable_get_type'); LoadProc(Pointer(g_seekable_seek), 'g_seekable_seek'); LoadProc(Pointer(g_seekable_tell), 'g_seekable_tell'); LoadProc(Pointer(g_seekable_truncate), 'g_seekable_truncate'); LoadProc(Pointer(g_settings_apply), 'g_settings_apply'); LoadProc(Pointer(g_settings_bind), 'g_settings_bind'); LoadProc(Pointer(g_settings_bind_with_mapping), 'g_settings_bind_with_mapping'); LoadProc(Pointer(g_settings_bind_writable), 'g_settings_bind_writable'); LoadProc(Pointer(g_settings_create_action), 'g_settings_create_action'); LoadProc(Pointer(g_settings_delay), 'g_settings_delay'); LoadProc(Pointer(g_settings_get), 'g_settings_get'); LoadProc(Pointer(g_settings_get_boolean), 'g_settings_get_boolean'); LoadProc(Pointer(g_settings_get_child), 'g_settings_get_child'); LoadProc(Pointer(g_settings_get_double), 'g_settings_get_double'); LoadProc(Pointer(g_settings_get_enum), 'g_settings_get_enum'); LoadProc(Pointer(g_settings_get_flags), 'g_settings_get_flags'); LoadProc(Pointer(g_settings_get_has_unapplied), 'g_settings_get_has_unapplied'); LoadProc(Pointer(g_settings_get_int), 'g_settings_get_int'); LoadProc(Pointer(g_settings_get_mapped), 'g_settings_get_mapped'); LoadProc(Pointer(g_settings_get_range), 'g_settings_get_range'); LoadProc(Pointer(g_settings_get_string), 'g_settings_get_string'); LoadProc(Pointer(g_settings_get_strv), 'g_settings_get_strv'); LoadProc(Pointer(g_settings_get_type), 'g_settings_get_type'); LoadProc(Pointer(g_settings_get_uint), 'g_settings_get_uint'); LoadProc(Pointer(g_settings_get_value), 'g_settings_get_value'); LoadProc(Pointer(g_settings_is_writable), 'g_settings_is_writable'); LoadProc(Pointer(g_settings_list_children), 'g_settings_list_children'); LoadProc(Pointer(g_settings_list_keys), 'g_settings_list_keys'); LoadProc(Pointer(g_settings_list_relocatable_schemas), 'g_settings_list_relocatable_schemas'); LoadProc(Pointer(g_settings_list_schemas), 'g_settings_list_schemas'); LoadProc(Pointer(g_settings_new), 'g_settings_new'); LoadProc(Pointer(g_settings_new_full), 'g_settings_new_full'); LoadProc(Pointer(g_settings_new_with_backend), 'g_settings_new_with_backend'); LoadProc(Pointer(g_settings_new_with_backend_and_path), 'g_settings_new_with_backend_and_path'); LoadProc(Pointer(g_settings_new_with_path), 'g_settings_new_with_path'); LoadProc(Pointer(g_settings_range_check), 'g_settings_range_check'); LoadProc(Pointer(g_settings_reset), 'g_settings_reset'); LoadProc(Pointer(g_settings_revert), 'g_settings_revert'); LoadProc(Pointer(g_settings_schema_get_id), 'g_settings_schema_get_id'); LoadProc(Pointer(g_settings_schema_get_path), 'g_settings_schema_get_path'); LoadProc(Pointer(g_settings_schema_get_type), 'g_settings_schema_get_type'); LoadProc(Pointer(g_settings_schema_ref), 'g_settings_schema_ref'); LoadProc(Pointer(g_settings_schema_source_get_default), 'g_settings_schema_source_get_default'); LoadProc(Pointer(g_settings_schema_source_get_type), 'g_settings_schema_source_get_type'); LoadProc(Pointer(g_settings_schema_source_lookup), 'g_settings_schema_source_lookup'); LoadProc(Pointer(g_settings_schema_source_new_from_directory), 'g_settings_schema_source_new_from_directory'); LoadProc(Pointer(g_settings_schema_source_ref), 'g_settings_schema_source_ref'); LoadProc(Pointer(g_settings_schema_source_unref), 'g_settings_schema_source_unref'); LoadProc(Pointer(g_settings_schema_unref), 'g_settings_schema_unref'); LoadProc(Pointer(g_settings_set), 'g_settings_set'); LoadProc(Pointer(g_settings_set_boolean), 'g_settings_set_boolean'); LoadProc(Pointer(g_settings_set_double), 'g_settings_set_double'); LoadProc(Pointer(g_settings_set_enum), 'g_settings_set_enum'); LoadProc(Pointer(g_settings_set_flags), 'g_settings_set_flags'); LoadProc(Pointer(g_settings_set_int), 'g_settings_set_int'); LoadProc(Pointer(g_settings_set_string), 'g_settings_set_string'); LoadProc(Pointer(g_settings_set_strv), 'g_settings_set_strv'); LoadProc(Pointer(g_settings_set_uint), 'g_settings_set_uint'); LoadProc(Pointer(g_settings_set_value), 'g_settings_set_value'); LoadProc(Pointer(g_settings_sync), 'g_settings_sync'); LoadProc(Pointer(g_settings_unbind), 'g_settings_unbind'); LoadProc(Pointer(g_simple_action_get_type), 'g_simple_action_get_type'); LoadProc(Pointer(g_simple_action_group_add_entries), 'g_simple_action_group_add_entries'); LoadProc(Pointer(g_simple_action_group_get_type), 'g_simple_action_group_get_type'); LoadProc(Pointer(g_simple_action_group_insert), 'g_simple_action_group_insert'); LoadProc(Pointer(g_simple_action_group_lookup), 'g_simple_action_group_lookup'); LoadProc(Pointer(g_simple_action_group_new), 'g_simple_action_group_new'); LoadProc(Pointer(g_simple_action_group_remove), 'g_simple_action_group_remove'); LoadProc(Pointer(g_simple_action_new), 'g_simple_action_new'); LoadProc(Pointer(g_simple_action_new_stateful), 'g_simple_action_new_stateful'); LoadProc(Pointer(g_simple_action_set_enabled), 'g_simple_action_set_enabled'); LoadProc(Pointer(g_simple_action_set_state), 'g_simple_action_set_state'); LoadProc(Pointer(g_simple_async_report_error_in_idle), 'g_simple_async_report_error_in_idle'); LoadProc(Pointer(g_simple_async_report_gerror_in_idle), 'g_simple_async_report_gerror_in_idle'); LoadProc(Pointer(g_simple_async_report_take_gerror_in_idle), 'g_simple_async_report_take_gerror_in_idle'); LoadProc(Pointer(g_simple_async_result_complete), 'g_simple_async_result_complete'); LoadProc(Pointer(g_simple_async_result_complete_in_idle), 'g_simple_async_result_complete_in_idle'); LoadProc(Pointer(g_simple_async_result_get_op_res_gboolean), 'g_simple_async_result_get_op_res_gboolean'); LoadProc(Pointer(g_simple_async_result_get_op_res_gpointer), 'g_simple_async_result_get_op_res_gpointer'); LoadProc(Pointer(g_simple_async_result_get_op_res_gssize), 'g_simple_async_result_get_op_res_gssize'); LoadProc(Pointer(g_simple_async_result_get_source_tag), 'g_simple_async_result_get_source_tag'); LoadProc(Pointer(g_simple_async_result_get_type), 'g_simple_async_result_get_type'); LoadProc(Pointer(g_simple_async_result_is_valid), 'g_simple_async_result_is_valid'); LoadProc(Pointer(g_simple_async_result_new), 'g_simple_async_result_new'); LoadProc(Pointer(g_simple_async_result_new_error), 'g_simple_async_result_new_error'); LoadProc(Pointer(g_simple_async_result_new_from_error), 'g_simple_async_result_new_from_error'); LoadProc(Pointer(g_simple_async_result_new_take_error), 'g_simple_async_result_new_take_error'); LoadProc(Pointer(g_simple_async_result_propagate_error), 'g_simple_async_result_propagate_error'); LoadProc(Pointer(g_simple_async_result_run_in_thread), 'g_simple_async_result_run_in_thread'); LoadProc(Pointer(g_simple_async_result_set_check_cancellable), 'g_simple_async_result_set_check_cancellable'); LoadProc(Pointer(g_simple_async_result_set_error), 'g_simple_async_result_set_error'); LoadProc(Pointer(g_simple_async_result_set_error_va), 'g_simple_async_result_set_error_va'); LoadProc(Pointer(g_simple_async_result_set_from_error), 'g_simple_async_result_set_from_error'); LoadProc(Pointer(g_simple_async_result_set_handle_cancellation), 'g_simple_async_result_set_handle_cancellation'); LoadProc(Pointer(g_simple_async_result_set_op_res_gboolean), 'g_simple_async_result_set_op_res_gboolean'); LoadProc(Pointer(g_simple_async_result_set_op_res_gpointer), 'g_simple_async_result_set_op_res_gpointer'); LoadProc(Pointer(g_simple_async_result_set_op_res_gssize), 'g_simple_async_result_set_op_res_gssize'); LoadProc(Pointer(g_simple_async_result_take_error), 'g_simple_async_result_take_error'); LoadProc(Pointer(g_simple_permission_get_type), 'g_simple_permission_get_type'); LoadProc(Pointer(g_simple_permission_new), 'g_simple_permission_new'); LoadProc(Pointer(g_simple_proxy_resolver_get_type), 'g_simple_proxy_resolver_get_type'); LoadProc(Pointer(g_simple_proxy_resolver_new), 'g_simple_proxy_resolver_new'); LoadProc(Pointer(g_simple_proxy_resolver_set_default_proxy), 'g_simple_proxy_resolver_set_default_proxy'); LoadProc(Pointer(g_simple_proxy_resolver_set_ignore_hosts), 'g_simple_proxy_resolver_set_ignore_hosts'); LoadProc(Pointer(g_simple_proxy_resolver_set_uri_proxy), 'g_simple_proxy_resolver_set_uri_proxy'); LoadProc(Pointer(g_socket_accept), 'g_socket_accept'); LoadProc(Pointer(g_socket_address_enumerator_get_type), 'g_socket_address_enumerator_get_type'); LoadProc(Pointer(g_socket_address_enumerator_next), 'g_socket_address_enumerator_next'); LoadProc(Pointer(g_socket_address_enumerator_next_async), 'g_socket_address_enumerator_next_async'); LoadProc(Pointer(g_socket_address_enumerator_next_finish), 'g_socket_address_enumerator_next_finish'); LoadProc(Pointer(g_socket_address_get_family), 'g_socket_address_get_family'); LoadProc(Pointer(g_socket_address_get_native_size), 'g_socket_address_get_native_size'); LoadProc(Pointer(g_socket_address_get_type), 'g_socket_address_get_type'); LoadProc(Pointer(g_socket_address_new_from_native), 'g_socket_address_new_from_native'); LoadProc(Pointer(g_socket_address_to_native), 'g_socket_address_to_native'); LoadProc(Pointer(g_socket_bind), 'g_socket_bind'); LoadProc(Pointer(g_socket_check_connect_result), 'g_socket_check_connect_result'); LoadProc(Pointer(g_socket_client_add_application_proxy), 'g_socket_client_add_application_proxy'); LoadProc(Pointer(g_socket_client_connect), 'g_socket_client_connect'); LoadProc(Pointer(g_socket_client_connect_async), 'g_socket_client_connect_async'); LoadProc(Pointer(g_socket_client_connect_finish), 'g_socket_client_connect_finish'); LoadProc(Pointer(g_socket_client_connect_to_host), 'g_socket_client_connect_to_host'); LoadProc(Pointer(g_socket_client_connect_to_host_async), 'g_socket_client_connect_to_host_async'); LoadProc(Pointer(g_socket_client_connect_to_host_finish), 'g_socket_client_connect_to_host_finish'); LoadProc(Pointer(g_socket_client_connect_to_service), 'g_socket_client_connect_to_service'); LoadProc(Pointer(g_socket_client_connect_to_service_async), 'g_socket_client_connect_to_service_async'); LoadProc(Pointer(g_socket_client_connect_to_service_finish), 'g_socket_client_connect_to_service_finish'); LoadProc(Pointer(g_socket_client_connect_to_uri), 'g_socket_client_connect_to_uri'); LoadProc(Pointer(g_socket_client_connect_to_uri_async), 'g_socket_client_connect_to_uri_async'); LoadProc(Pointer(g_socket_client_connect_to_uri_finish), 'g_socket_client_connect_to_uri_finish'); LoadProc(Pointer(g_socket_client_get_enable_proxy), 'g_socket_client_get_enable_proxy'); LoadProc(Pointer(g_socket_client_get_family), 'g_socket_client_get_family'); LoadProc(Pointer(g_socket_client_get_local_address), 'g_socket_client_get_local_address'); LoadProc(Pointer(g_socket_client_get_protocol), 'g_socket_client_get_protocol'); LoadProc(Pointer(g_socket_client_get_proxy_resolver), 'g_socket_client_get_proxy_resolver'); LoadProc(Pointer(g_socket_client_get_socket_type), 'g_socket_client_get_socket_type'); LoadProc(Pointer(g_socket_client_get_timeout), 'g_socket_client_get_timeout'); LoadProc(Pointer(g_socket_client_get_tls), 'g_socket_client_get_tls'); LoadProc(Pointer(g_socket_client_get_tls_validation_flags), 'g_socket_client_get_tls_validation_flags'); LoadProc(Pointer(g_socket_client_get_type), 'g_socket_client_get_type'); LoadProc(Pointer(g_socket_client_new), 'g_socket_client_new'); LoadProc(Pointer(g_socket_client_set_enable_proxy), 'g_socket_client_set_enable_proxy'); LoadProc(Pointer(g_socket_client_set_family), 'g_socket_client_set_family'); LoadProc(Pointer(g_socket_client_set_local_address), 'g_socket_client_set_local_address'); LoadProc(Pointer(g_socket_client_set_protocol), 'g_socket_client_set_protocol'); LoadProc(Pointer(g_socket_client_set_proxy_resolver), 'g_socket_client_set_proxy_resolver'); LoadProc(Pointer(g_socket_client_set_socket_type), 'g_socket_client_set_socket_type'); LoadProc(Pointer(g_socket_client_set_timeout), 'g_socket_client_set_timeout'); LoadProc(Pointer(g_socket_client_set_tls), 'g_socket_client_set_tls'); LoadProc(Pointer(g_socket_client_set_tls_validation_flags), 'g_socket_client_set_tls_validation_flags'); LoadProc(Pointer(g_socket_close), 'g_socket_close'); LoadProc(Pointer(g_socket_condition_check), 'g_socket_condition_check'); LoadProc(Pointer(g_socket_condition_timed_wait), 'g_socket_condition_timed_wait'); LoadProc(Pointer(g_socket_condition_wait), 'g_socket_condition_wait'); LoadProc(Pointer(g_socket_connect), 'g_socket_connect'); LoadProc(Pointer(g_socket_connectable_enumerate), 'g_socket_connectable_enumerate'); LoadProc(Pointer(g_socket_connectable_get_type), 'g_socket_connectable_get_type'); LoadProc(Pointer(g_socket_connectable_proxy_enumerate), 'g_socket_connectable_proxy_enumerate'); LoadProc(Pointer(g_socket_connection_connect), 'g_socket_connection_connect'); LoadProc(Pointer(g_socket_connection_connect_async), 'g_socket_connection_connect_async'); LoadProc(Pointer(g_socket_connection_connect_finish), 'g_socket_connection_connect_finish'); LoadProc(Pointer(g_socket_connection_factory_create_connection), 'g_socket_connection_factory_create_connection'); LoadProc(Pointer(g_socket_connection_factory_lookup_type), 'g_socket_connection_factory_lookup_type'); LoadProc(Pointer(g_socket_connection_factory_register_type), 'g_socket_connection_factory_register_type'); LoadProc(Pointer(g_socket_connection_get_local_address), 'g_socket_connection_get_local_address'); LoadProc(Pointer(g_socket_connection_get_remote_address), 'g_socket_connection_get_remote_address'); LoadProc(Pointer(g_socket_connection_get_socket), 'g_socket_connection_get_socket'); LoadProc(Pointer(g_socket_connection_get_type), 'g_socket_connection_get_type'); LoadProc(Pointer(g_socket_connection_is_connected), 'g_socket_connection_is_connected'); LoadProc(Pointer(g_socket_control_message_deserialize), 'g_socket_control_message_deserialize'); LoadProc(Pointer(g_socket_control_message_get_level), 'g_socket_control_message_get_level'); LoadProc(Pointer(g_socket_control_message_get_msg_type), 'g_socket_control_message_get_msg_type'); LoadProc(Pointer(g_socket_control_message_get_size), 'g_socket_control_message_get_size'); LoadProc(Pointer(g_socket_control_message_get_type), 'g_socket_control_message_get_type'); LoadProc(Pointer(g_socket_control_message_serialize), 'g_socket_control_message_serialize'); LoadProc(Pointer(g_socket_create_source), 'g_socket_create_source'); LoadProc(Pointer(g_socket_get_available_bytes), 'g_socket_get_available_bytes'); LoadProc(Pointer(g_socket_get_blocking), 'g_socket_get_blocking'); LoadProc(Pointer(g_socket_get_broadcast), 'g_socket_get_broadcast'); LoadProc(Pointer(g_socket_get_credentials), 'g_socket_get_credentials'); LoadProc(Pointer(g_socket_get_family), 'g_socket_get_family'); LoadProc(Pointer(g_socket_get_fd), 'g_socket_get_fd'); LoadProc(Pointer(g_socket_get_keepalive), 'g_socket_get_keepalive'); LoadProc(Pointer(g_socket_get_listen_backlog), 'g_socket_get_listen_backlog'); LoadProc(Pointer(g_socket_get_local_address), 'g_socket_get_local_address'); LoadProc(Pointer(g_socket_get_multicast_loopback), 'g_socket_get_multicast_loopback'); LoadProc(Pointer(g_socket_get_multicast_ttl), 'g_socket_get_multicast_ttl'); LoadProc(Pointer(g_socket_get_option), 'g_socket_get_option'); LoadProc(Pointer(g_socket_get_protocol), 'g_socket_get_protocol'); LoadProc(Pointer(g_socket_get_remote_address), 'g_socket_get_remote_address'); LoadProc(Pointer(g_socket_get_socket_type), 'g_socket_get_socket_type'); LoadProc(Pointer(g_socket_get_timeout), 'g_socket_get_timeout'); LoadProc(Pointer(g_socket_get_ttl), 'g_socket_get_ttl'); LoadProc(Pointer(g_socket_get_type), 'g_socket_get_type'); LoadProc(Pointer(g_socket_is_closed), 'g_socket_is_closed'); LoadProc(Pointer(g_socket_is_connected), 'g_socket_is_connected'); LoadProc(Pointer(g_socket_join_multicast_group), 'g_socket_join_multicast_group'); LoadProc(Pointer(g_socket_leave_multicast_group), 'g_socket_leave_multicast_group'); LoadProc(Pointer(g_socket_listen), 'g_socket_listen'); LoadProc(Pointer(g_socket_listener_accept), 'g_socket_listener_accept'); LoadProc(Pointer(g_socket_listener_accept_async), 'g_socket_listener_accept_async'); LoadProc(Pointer(g_socket_listener_accept_finish), 'g_socket_listener_accept_finish'); LoadProc(Pointer(g_socket_listener_accept_socket), 'g_socket_listener_accept_socket'); LoadProc(Pointer(g_socket_listener_accept_socket_async), 'g_socket_listener_accept_socket_async'); LoadProc(Pointer(g_socket_listener_accept_socket_finish), 'g_socket_listener_accept_socket_finish'); LoadProc(Pointer(g_socket_listener_add_address), 'g_socket_listener_add_address'); LoadProc(Pointer(g_socket_listener_add_any_inet_port), 'g_socket_listener_add_any_inet_port'); LoadProc(Pointer(g_socket_listener_add_inet_port), 'g_socket_listener_add_inet_port'); LoadProc(Pointer(g_socket_listener_add_socket), 'g_socket_listener_add_socket'); LoadProc(Pointer(g_socket_listener_close), 'g_socket_listener_close'); LoadProc(Pointer(g_socket_listener_get_type), 'g_socket_listener_get_type'); LoadProc(Pointer(g_socket_listener_new), 'g_socket_listener_new'); LoadProc(Pointer(g_socket_listener_set_backlog), 'g_socket_listener_set_backlog'); LoadProc(Pointer(g_socket_new), 'g_socket_new'); LoadProc(Pointer(g_socket_new_from_fd), 'g_socket_new_from_fd'); LoadProc(Pointer(g_socket_receive), 'g_socket_receive'); LoadProc(Pointer(g_socket_receive_from), 'g_socket_receive_from'); LoadProc(Pointer(g_socket_receive_message), 'g_socket_receive_message'); LoadProc(Pointer(g_socket_receive_with_blocking), 'g_socket_receive_with_blocking'); LoadProc(Pointer(g_socket_send), 'g_socket_send'); LoadProc(Pointer(g_socket_send_message), 'g_socket_send_message'); LoadProc(Pointer(g_socket_send_to), 'g_socket_send_to'); LoadProc(Pointer(g_socket_send_with_blocking), 'g_socket_send_with_blocking'); LoadProc(Pointer(g_socket_service_get_type), 'g_socket_service_get_type'); LoadProc(Pointer(g_socket_service_is_active), 'g_socket_service_is_active'); LoadProc(Pointer(g_socket_service_new), 'g_socket_service_new'); LoadProc(Pointer(g_socket_service_start), 'g_socket_service_start'); LoadProc(Pointer(g_socket_service_stop), 'g_socket_service_stop'); LoadProc(Pointer(g_socket_set_blocking), 'g_socket_set_blocking'); LoadProc(Pointer(g_socket_set_broadcast), 'g_socket_set_broadcast'); LoadProc(Pointer(g_socket_set_keepalive), 'g_socket_set_keepalive'); LoadProc(Pointer(g_socket_set_listen_backlog), 'g_socket_set_listen_backlog'); LoadProc(Pointer(g_socket_set_multicast_loopback), 'g_socket_set_multicast_loopback'); LoadProc(Pointer(g_socket_set_multicast_ttl), 'g_socket_set_multicast_ttl'); LoadProc(Pointer(g_socket_set_option), 'g_socket_set_option'); LoadProc(Pointer(g_socket_set_timeout), 'g_socket_set_timeout'); LoadProc(Pointer(g_socket_set_ttl), 'g_socket_set_ttl'); LoadProc(Pointer(g_socket_shutdown), 'g_socket_shutdown'); LoadProc(Pointer(g_socket_speaks_ipv4), 'g_socket_speaks_ipv4'); LoadProc(Pointer(g_srv_target_copy), 'g_srv_target_copy'); LoadProc(Pointer(g_srv_target_free), 'g_srv_target_free'); LoadProc(Pointer(g_srv_target_get_hostname), 'g_srv_target_get_hostname'); LoadProc(Pointer(g_srv_target_get_port), 'g_srv_target_get_port'); LoadProc(Pointer(g_srv_target_get_priority), 'g_srv_target_get_priority'); LoadProc(Pointer(g_srv_target_get_type), 'g_srv_target_get_type'); LoadProc(Pointer(g_srv_target_get_weight), 'g_srv_target_get_weight'); LoadProc(Pointer(g_srv_target_list_sort), 'g_srv_target_list_sort'); LoadProc(Pointer(g_srv_target_new), 'g_srv_target_new'); LoadProc(Pointer(g_static_resource_fini), 'g_static_resource_fini'); LoadProc(Pointer(g_static_resource_get_resource), 'g_static_resource_get_resource'); LoadProc(Pointer(g_static_resource_init), 'g_static_resource_init'); LoadProc(Pointer(g_task_attach_source), 'g_task_attach_source'); LoadProc(Pointer(g_task_get_cancellable), 'g_task_get_cancellable'); LoadProc(Pointer(g_task_get_check_cancellable), 'g_task_get_check_cancellable'); LoadProc(Pointer(g_task_get_context), 'g_task_get_context'); LoadProc(Pointer(g_task_get_priority), 'g_task_get_priority'); LoadProc(Pointer(g_task_get_return_on_cancel), 'g_task_get_return_on_cancel'); LoadProc(Pointer(g_task_get_source_object), 'g_task_get_source_object'); LoadProc(Pointer(g_task_get_source_tag), 'g_task_get_source_tag'); LoadProc(Pointer(g_task_get_task_data), 'g_task_get_task_data'); LoadProc(Pointer(g_task_get_type), 'g_task_get_type'); LoadProc(Pointer(g_task_had_error), 'g_task_had_error'); LoadProc(Pointer(g_task_is_valid), 'g_task_is_valid'); LoadProc(Pointer(g_task_new), 'g_task_new'); LoadProc(Pointer(g_task_propagate_boolean), 'g_task_propagate_boolean'); LoadProc(Pointer(g_task_propagate_int), 'g_task_propagate_int'); LoadProc(Pointer(g_task_propagate_pointer), 'g_task_propagate_pointer'); LoadProc(Pointer(g_task_report_error), 'g_task_report_error'); LoadProc(Pointer(g_task_report_new_error), 'g_task_report_new_error'); LoadProc(Pointer(g_task_return_boolean), 'g_task_return_boolean'); LoadProc(Pointer(g_task_return_error), 'g_task_return_error'); LoadProc(Pointer(g_task_return_error_if_cancelled), 'g_task_return_error_if_cancelled'); LoadProc(Pointer(g_task_return_int), 'g_task_return_int'); LoadProc(Pointer(g_task_return_new_error), 'g_task_return_new_error'); LoadProc(Pointer(g_task_return_pointer), 'g_task_return_pointer'); LoadProc(Pointer(g_task_run_in_thread), 'g_task_run_in_thread'); LoadProc(Pointer(g_task_run_in_thread_sync), 'g_task_run_in_thread_sync'); LoadProc(Pointer(g_task_set_check_cancellable), 'g_task_set_check_cancellable'); LoadProc(Pointer(g_task_set_priority), 'g_task_set_priority'); LoadProc(Pointer(g_task_set_return_on_cancel), 'g_task_set_return_on_cancel'); LoadProc(Pointer(g_task_set_source_tag), 'g_task_set_source_tag'); LoadProc(Pointer(g_task_set_task_data), 'g_task_set_task_data'); LoadProc(Pointer(g_tcp_connection_get_graceful_disconnect), 'g_tcp_connection_get_graceful_disconnect'); LoadProc(Pointer(g_tcp_connection_get_type), 'g_tcp_connection_get_type'); LoadProc(Pointer(g_tcp_connection_set_graceful_disconnect), 'g_tcp_connection_set_graceful_disconnect'); LoadProc(Pointer(g_tcp_wrapper_connection_get_base_io_stream), 'g_tcp_wrapper_connection_get_base_io_stream'); LoadProc(Pointer(g_tcp_wrapper_connection_get_type), 'g_tcp_wrapper_connection_get_type'); LoadProc(Pointer(g_tcp_wrapper_connection_new), 'g_tcp_wrapper_connection_new'); LoadProc(Pointer(g_test_dbus_add_service_dir), 'g_test_dbus_add_service_dir'); LoadProc(Pointer(g_test_dbus_down), 'g_test_dbus_down'); LoadProc(Pointer(g_test_dbus_get_bus_address), 'g_test_dbus_get_bus_address'); LoadProc(Pointer(g_test_dbus_get_flags), 'g_test_dbus_get_flags'); LoadProc(Pointer(g_test_dbus_get_type), 'g_test_dbus_get_type'); LoadProc(Pointer(g_test_dbus_new), 'g_test_dbus_new'); LoadProc(Pointer(g_test_dbus_stop), 'g_test_dbus_stop'); LoadProc(Pointer(g_test_dbus_unset), 'g_test_dbus_unset'); LoadProc(Pointer(g_test_dbus_up), 'g_test_dbus_up'); LoadProc(Pointer(g_themed_icon_append_name), 'g_themed_icon_append_name'); LoadProc(Pointer(g_themed_icon_get_names), 'g_themed_icon_get_names'); LoadProc(Pointer(g_themed_icon_get_type), 'g_themed_icon_get_type'); LoadProc(Pointer(g_themed_icon_new), 'g_themed_icon_new'); LoadProc(Pointer(g_themed_icon_new_from_names), 'g_themed_icon_new_from_names'); LoadProc(Pointer(g_themed_icon_new_with_default_fallbacks), 'g_themed_icon_new_with_default_fallbacks'); LoadProc(Pointer(g_themed_icon_prepend_name), 'g_themed_icon_prepend_name'); LoadProc(Pointer(g_threaded_socket_service_get_type), 'g_threaded_socket_service_get_type'); LoadProc(Pointer(g_threaded_socket_service_new), 'g_threaded_socket_service_new'); LoadProc(Pointer(g_tls_backend_get_certificate_type), 'g_tls_backend_get_certificate_type'); LoadProc(Pointer(g_tls_backend_get_client_connection_type), 'g_tls_backend_get_client_connection_type'); LoadProc(Pointer(g_tls_backend_get_default), 'g_tls_backend_get_default'); LoadProc(Pointer(g_tls_backend_get_default_database), 'g_tls_backend_get_default_database'); LoadProc(Pointer(g_tls_backend_get_file_database_type), 'g_tls_backend_get_file_database_type'); LoadProc(Pointer(g_tls_backend_get_server_connection_type), 'g_tls_backend_get_server_connection_type'); LoadProc(Pointer(g_tls_backend_get_type), 'g_tls_backend_get_type'); LoadProc(Pointer(g_tls_backend_supports_tls), 'g_tls_backend_supports_tls'); LoadProc(Pointer(g_tls_certificate_get_issuer), 'g_tls_certificate_get_issuer'); LoadProc(Pointer(g_tls_certificate_get_type), 'g_tls_certificate_get_type'); LoadProc(Pointer(g_tls_certificate_is_same), 'g_tls_certificate_is_same'); LoadProc(Pointer(g_tls_certificate_list_new_from_file), 'g_tls_certificate_list_new_from_file'); LoadProc(Pointer(g_tls_certificate_new_from_file), 'g_tls_certificate_new_from_file'); LoadProc(Pointer(g_tls_certificate_new_from_files), 'g_tls_certificate_new_from_files'); LoadProc(Pointer(g_tls_certificate_new_from_pem), 'g_tls_certificate_new_from_pem'); LoadProc(Pointer(g_tls_certificate_verify), 'g_tls_certificate_verify'); LoadProc(Pointer(g_tls_client_connection_get_accepted_cas), 'g_tls_client_connection_get_accepted_cas'); LoadProc(Pointer(g_tls_client_connection_get_server_identity), 'g_tls_client_connection_get_server_identity'); LoadProc(Pointer(g_tls_client_connection_get_type), 'g_tls_client_connection_get_type'); LoadProc(Pointer(g_tls_client_connection_get_use_ssl3), 'g_tls_client_connection_get_use_ssl3'); LoadProc(Pointer(g_tls_client_connection_get_validation_flags), 'g_tls_client_connection_get_validation_flags'); LoadProc(Pointer(g_tls_client_connection_new), 'g_tls_client_connection_new'); LoadProc(Pointer(g_tls_client_connection_set_server_identity), 'g_tls_client_connection_set_server_identity'); LoadProc(Pointer(g_tls_client_connection_set_use_ssl3), 'g_tls_client_connection_set_use_ssl3'); LoadProc(Pointer(g_tls_client_connection_set_validation_flags), 'g_tls_client_connection_set_validation_flags'); LoadProc(Pointer(g_tls_connection_emit_accept_certificate), 'g_tls_connection_emit_accept_certificate'); LoadProc(Pointer(g_tls_connection_get_certificate), 'g_tls_connection_get_certificate'); LoadProc(Pointer(g_tls_connection_get_database), 'g_tls_connection_get_database'); LoadProc(Pointer(g_tls_connection_get_interaction), 'g_tls_connection_get_interaction'); LoadProc(Pointer(g_tls_connection_get_peer_certificate), 'g_tls_connection_get_peer_certificate'); LoadProc(Pointer(g_tls_connection_get_peer_certificate_errors), 'g_tls_connection_get_peer_certificate_errors'); LoadProc(Pointer(g_tls_connection_get_rehandshake_mode), 'g_tls_connection_get_rehandshake_mode'); LoadProc(Pointer(g_tls_connection_get_require_close_notify), 'g_tls_connection_get_require_close_notify'); LoadProc(Pointer(g_tls_connection_get_type), 'g_tls_connection_get_type'); LoadProc(Pointer(g_tls_connection_handshake), 'g_tls_connection_handshake'); LoadProc(Pointer(g_tls_connection_handshake_async), 'g_tls_connection_handshake_async'); LoadProc(Pointer(g_tls_connection_handshake_finish), 'g_tls_connection_handshake_finish'); LoadProc(Pointer(g_tls_connection_set_certificate), 'g_tls_connection_set_certificate'); LoadProc(Pointer(g_tls_connection_set_database), 'g_tls_connection_set_database'); LoadProc(Pointer(g_tls_connection_set_interaction), 'g_tls_connection_set_interaction'); LoadProc(Pointer(g_tls_connection_set_rehandshake_mode), 'g_tls_connection_set_rehandshake_mode'); LoadProc(Pointer(g_tls_connection_set_require_close_notify), 'g_tls_connection_set_require_close_notify'); LoadProc(Pointer(g_tls_database_create_certificate_handle), 'g_tls_database_create_certificate_handle'); LoadProc(Pointer(g_tls_database_get_type), 'g_tls_database_get_type'); LoadProc(Pointer(g_tls_database_lookup_certificate_for_handle), 'g_tls_database_lookup_certificate_for_handle'); LoadProc(Pointer(g_tls_database_lookup_certificate_for_handle_async), 'g_tls_database_lookup_certificate_for_handle_async'); LoadProc(Pointer(g_tls_database_lookup_certificate_for_handle_finish), 'g_tls_database_lookup_certificate_for_handle_finish'); LoadProc(Pointer(g_tls_database_lookup_certificate_issuer), 'g_tls_database_lookup_certificate_issuer'); LoadProc(Pointer(g_tls_database_lookup_certificate_issuer_async), 'g_tls_database_lookup_certificate_issuer_async'); LoadProc(Pointer(g_tls_database_lookup_certificate_issuer_finish), 'g_tls_database_lookup_certificate_issuer_finish'); LoadProc(Pointer(g_tls_database_lookup_certificates_issued_by), 'g_tls_database_lookup_certificates_issued_by'); LoadProc(Pointer(g_tls_database_lookup_certificates_issued_by_async), 'g_tls_database_lookup_certificates_issued_by_async'); LoadProc(Pointer(g_tls_database_lookup_certificates_issued_by_finish), 'g_tls_database_lookup_certificates_issued_by_finish'); LoadProc(Pointer(g_tls_database_verify_chain), 'g_tls_database_verify_chain'); LoadProc(Pointer(g_tls_database_verify_chain_async), 'g_tls_database_verify_chain_async'); LoadProc(Pointer(g_tls_database_verify_chain_finish), 'g_tls_database_verify_chain_finish'); LoadProc(Pointer(g_tls_error_quark), 'g_tls_error_quark'); LoadProc(Pointer(g_tls_file_database_get_type), 'g_tls_file_database_get_type'); LoadProc(Pointer(g_tls_file_database_new), 'g_tls_file_database_new'); LoadProc(Pointer(g_tls_interaction_ask_password), 'g_tls_interaction_ask_password'); LoadProc(Pointer(g_tls_interaction_ask_password_async), 'g_tls_interaction_ask_password_async'); LoadProc(Pointer(g_tls_interaction_ask_password_finish), 'g_tls_interaction_ask_password_finish'); LoadProc(Pointer(g_tls_interaction_get_type), 'g_tls_interaction_get_type'); LoadProc(Pointer(g_tls_interaction_invoke_ask_password), 'g_tls_interaction_invoke_ask_password'); LoadProc(Pointer(g_tls_password_get_description), 'g_tls_password_get_description'); LoadProc(Pointer(g_tls_password_get_flags), 'g_tls_password_get_flags'); LoadProc(Pointer(g_tls_password_get_type), 'g_tls_password_get_type'); LoadProc(Pointer(g_tls_password_get_value), 'g_tls_password_get_value'); LoadProc(Pointer(g_tls_password_get_warning), 'g_tls_password_get_warning'); LoadProc(Pointer(g_tls_password_new), 'g_tls_password_new'); LoadProc(Pointer(g_tls_password_set_description), 'g_tls_password_set_description'); LoadProc(Pointer(g_tls_password_set_flags), 'g_tls_password_set_flags'); LoadProc(Pointer(g_tls_password_set_value), 'g_tls_password_set_value'); LoadProc(Pointer(g_tls_password_set_value_full), 'g_tls_password_set_value_full'); LoadProc(Pointer(g_tls_password_set_warning), 'g_tls_password_set_warning'); LoadProc(Pointer(g_tls_server_connection_get_type), 'g_tls_server_connection_get_type'); LoadProc(Pointer(g_tls_server_connection_new), 'g_tls_server_connection_new'); LoadProc(Pointer(g_unix_connection_get_type), 'g_unix_connection_get_type'); LoadProc(Pointer(g_unix_connection_receive_credentials), 'g_unix_connection_receive_credentials'); LoadProc(Pointer(g_unix_connection_receive_credentials_async), 'g_unix_connection_receive_credentials_async'); LoadProc(Pointer(g_unix_connection_receive_credentials_finish), 'g_unix_connection_receive_credentials_finish'); LoadProc(Pointer(g_unix_connection_receive_fd), 'g_unix_connection_receive_fd'); LoadProc(Pointer(g_unix_connection_send_credentials), 'g_unix_connection_send_credentials'); LoadProc(Pointer(g_unix_connection_send_credentials_async), 'g_unix_connection_send_credentials_async'); LoadProc(Pointer(g_unix_connection_send_credentials_finish), 'g_unix_connection_send_credentials_finish'); LoadProc(Pointer(g_unix_connection_send_fd), 'g_unix_connection_send_fd'); LoadProc(Pointer(g_unix_credentials_message_get_credentials), 'g_unix_credentials_message_get_credentials'); LoadProc(Pointer(g_unix_credentials_message_get_type), 'g_unix_credentials_message_get_type'); LoadProc(Pointer(g_unix_credentials_message_is_supported), 'g_unix_credentials_message_is_supported'); LoadProc(Pointer(g_unix_credentials_message_new), 'g_unix_credentials_message_new'); LoadProc(Pointer(g_unix_credentials_message_new_with_credentials), 'g_unix_credentials_message_new_with_credentials'); LoadProc(Pointer(g_unix_fd_list_append), 'g_unix_fd_list_append'); LoadProc(Pointer(g_unix_fd_list_get), 'g_unix_fd_list_get'); LoadProc(Pointer(g_unix_fd_list_get_length), 'g_unix_fd_list_get_length'); LoadProc(Pointer(g_unix_fd_list_get_type), 'g_unix_fd_list_get_type'); LoadProc(Pointer(g_unix_fd_list_new), 'g_unix_fd_list_new'); LoadProc(Pointer(g_unix_fd_list_new_from_array), 'g_unix_fd_list_new_from_array'); LoadProc(Pointer(g_unix_fd_list_peek_fds), 'g_unix_fd_list_peek_fds'); LoadProc(Pointer(g_unix_fd_list_steal_fds), 'g_unix_fd_list_steal_fds'); LoadProc(Pointer(g_unix_fd_message_append_fd), 'g_unix_fd_message_append_fd'); LoadProc(Pointer(g_unix_fd_message_get_fd_list), 'g_unix_fd_message_get_fd_list'); LoadProc(Pointer(g_unix_fd_message_get_type), 'g_unix_fd_message_get_type'); LoadProc(Pointer(g_unix_fd_message_new), 'g_unix_fd_message_new'); LoadProc(Pointer(g_unix_fd_message_new_with_fd_list), 'g_unix_fd_message_new_with_fd_list'); LoadProc(Pointer(g_unix_fd_message_steal_fds), 'g_unix_fd_message_steal_fds'); LoadProc(Pointer(g_unix_input_stream_get_close_fd), 'g_unix_input_stream_get_close_fd'); LoadProc(Pointer(g_unix_input_stream_get_fd), 'g_unix_input_stream_get_fd'); LoadProc(Pointer(g_unix_input_stream_get_type), 'g_unix_input_stream_get_type'); LoadProc(Pointer(g_unix_input_stream_new), 'g_unix_input_stream_new'); LoadProc(Pointer(g_unix_input_stream_set_close_fd), 'g_unix_input_stream_set_close_fd'); LoadProc(Pointer(g_unix_is_mount_path_system_internal), 'g_unix_is_mount_path_system_internal'); LoadProc(Pointer(g_unix_mount_at), 'g_unix_mount_at'); LoadProc(Pointer(g_unix_mount_compare), 'g_unix_mount_compare'); LoadProc(Pointer(g_unix_mount_free), 'g_unix_mount_free'); LoadProc(Pointer(g_unix_mount_get_device_path), 'g_unix_mount_get_device_path'); LoadProc(Pointer(g_unix_mount_get_fs_type), 'g_unix_mount_get_fs_type'); LoadProc(Pointer(g_unix_mount_get_mount_path), 'g_unix_mount_get_mount_path'); LoadProc(Pointer(g_unix_mount_guess_can_eject), 'g_unix_mount_guess_can_eject'); LoadProc(Pointer(g_unix_mount_guess_icon), 'g_unix_mount_guess_icon'); LoadProc(Pointer(g_unix_mount_guess_name), 'g_unix_mount_guess_name'); LoadProc(Pointer(g_unix_mount_guess_should_display), 'g_unix_mount_guess_should_display'); LoadProc(Pointer(g_unix_mount_guess_symbolic_icon), 'g_unix_mount_guess_symbolic_icon'); LoadProc(Pointer(g_unix_mount_is_readonly), 'g_unix_mount_is_readonly'); LoadProc(Pointer(g_unix_mount_is_system_internal), 'g_unix_mount_is_system_internal'); LoadProc(Pointer(g_unix_mount_monitor_get_type), 'g_unix_mount_monitor_get_type'); LoadProc(Pointer(g_unix_mount_monitor_new), 'g_unix_mount_monitor_new'); LoadProc(Pointer(g_unix_mount_monitor_set_rate_limit), 'g_unix_mount_monitor_set_rate_limit'); LoadProc(Pointer(g_unix_mount_point_compare), 'g_unix_mount_point_compare'); LoadProc(Pointer(g_unix_mount_point_free), 'g_unix_mount_point_free'); LoadProc(Pointer(g_unix_mount_point_get_device_path), 'g_unix_mount_point_get_device_path'); LoadProc(Pointer(g_unix_mount_point_get_fs_type), 'g_unix_mount_point_get_fs_type'); LoadProc(Pointer(g_unix_mount_point_get_mount_path), 'g_unix_mount_point_get_mount_path'); LoadProc(Pointer(g_unix_mount_point_get_options), 'g_unix_mount_point_get_options'); LoadProc(Pointer(g_unix_mount_point_guess_can_eject), 'g_unix_mount_point_guess_can_eject'); LoadProc(Pointer(g_unix_mount_point_guess_icon), 'g_unix_mount_point_guess_icon'); LoadProc(Pointer(g_unix_mount_point_guess_name), 'g_unix_mount_point_guess_name'); LoadProc(Pointer(g_unix_mount_point_guess_symbolic_icon), 'g_unix_mount_point_guess_symbolic_icon'); LoadProc(Pointer(g_unix_mount_point_is_loopback), 'g_unix_mount_point_is_loopback'); LoadProc(Pointer(g_unix_mount_point_is_readonly), 'g_unix_mount_point_is_readonly'); LoadProc(Pointer(g_unix_mount_point_is_user_mountable), 'g_unix_mount_point_is_user_mountable'); LoadProc(Pointer(g_unix_mount_points_changed_since), 'g_unix_mount_points_changed_since'); LoadProc(Pointer(g_unix_mount_points_get), 'g_unix_mount_points_get'); LoadProc(Pointer(g_unix_mounts_changed_since), 'g_unix_mounts_changed_since'); LoadProc(Pointer(g_unix_mounts_get), 'g_unix_mounts_get'); LoadProc(Pointer(g_unix_output_stream_get_close_fd), 'g_unix_output_stream_get_close_fd'); LoadProc(Pointer(g_unix_output_stream_get_fd), 'g_unix_output_stream_get_fd'); LoadProc(Pointer(g_unix_output_stream_get_type), 'g_unix_output_stream_get_type'); LoadProc(Pointer(g_unix_output_stream_new), 'g_unix_output_stream_new'); LoadProc(Pointer(g_unix_output_stream_set_close_fd), 'g_unix_output_stream_set_close_fd'); LoadProc(Pointer(g_unix_socket_address_abstract_names_supported), 'g_unix_socket_address_abstract_names_supported'); LoadProc(Pointer(g_unix_socket_address_get_address_type), 'g_unix_socket_address_get_address_type'); LoadProc(Pointer(g_unix_socket_address_get_path), 'g_unix_socket_address_get_path'); LoadProc(Pointer(g_unix_socket_address_get_path_len), 'g_unix_socket_address_get_path_len'); LoadProc(Pointer(g_unix_socket_address_get_type), 'g_unix_socket_address_get_type'); LoadProc(Pointer(g_unix_socket_address_new), 'g_unix_socket_address_new'); LoadProc(Pointer(g_unix_socket_address_new_with_type), 'g_unix_socket_address_new_with_type'); LoadProc(Pointer(g_vfs_get_default), 'g_vfs_get_default'); LoadProc(Pointer(g_vfs_get_file_for_path), 'g_vfs_get_file_for_path'); LoadProc(Pointer(g_vfs_get_file_for_uri), 'g_vfs_get_file_for_uri'); LoadProc(Pointer(g_vfs_get_local), 'g_vfs_get_local'); LoadProc(Pointer(g_vfs_get_supported_uri_schemes), 'g_vfs_get_supported_uri_schemes'); LoadProc(Pointer(g_vfs_get_type), 'g_vfs_get_type'); LoadProc(Pointer(g_vfs_is_active), 'g_vfs_is_active'); LoadProc(Pointer(g_vfs_parse_name), 'g_vfs_parse_name'); LoadProc(Pointer(g_volume_can_eject), 'g_volume_can_eject'); LoadProc(Pointer(g_volume_can_mount), 'g_volume_can_mount'); LoadProc(Pointer(g_volume_eject_with_operation), 'g_volume_eject_with_operation'); LoadProc(Pointer(g_volume_eject_with_operation_finish), 'g_volume_eject_with_operation_finish'); LoadProc(Pointer(g_volume_enumerate_identifiers), 'g_volume_enumerate_identifiers'); LoadProc(Pointer(g_volume_get_activation_root), 'g_volume_get_activation_root'); LoadProc(Pointer(g_volume_get_drive), 'g_volume_get_drive'); LoadProc(Pointer(g_volume_get_icon), 'g_volume_get_icon'); LoadProc(Pointer(g_volume_get_identifier), 'g_volume_get_identifier'); LoadProc(Pointer(g_volume_get_mount), 'g_volume_get_mount'); LoadProc(Pointer(g_volume_get_name), 'g_volume_get_name'); LoadProc(Pointer(g_volume_get_sort_key), 'g_volume_get_sort_key'); LoadProc(Pointer(g_volume_get_symbolic_icon), 'g_volume_get_symbolic_icon'); LoadProc(Pointer(g_volume_get_type), 'g_volume_get_type'); LoadProc(Pointer(g_volume_get_uuid), 'g_volume_get_uuid'); LoadProc(Pointer(g_volume_monitor_get), 'g_volume_monitor_get'); LoadProc(Pointer(g_volume_monitor_get_connected_drives), 'g_volume_monitor_get_connected_drives'); LoadProc(Pointer(g_volume_monitor_get_mount_for_uuid), 'g_volume_monitor_get_mount_for_uuid'); LoadProc(Pointer(g_volume_monitor_get_mounts), 'g_volume_monitor_get_mounts'); LoadProc(Pointer(g_volume_monitor_get_type), 'g_volume_monitor_get_type'); LoadProc(Pointer(g_volume_monitor_get_volume_for_uuid), 'g_volume_monitor_get_volume_for_uuid'); LoadProc(Pointer(g_volume_monitor_get_volumes), 'g_volume_monitor_get_volumes'); LoadProc(Pointer(g_volume_mount), 'g_volume_mount'); LoadProc(Pointer(g_volume_mount_finish), 'g_volume_mount_finish'); LoadProc(Pointer(g_volume_should_automount), 'g_volume_should_automount'); LoadProc(Pointer(g_zlib_compressor_get_file_info), 'g_zlib_compressor_get_file_info'); LoadProc(Pointer(g_zlib_compressor_get_type), 'g_zlib_compressor_get_type'); LoadProc(Pointer(g_zlib_compressor_new), 'g_zlib_compressor_new'); LoadProc(Pointer(g_zlib_compressor_set_file_info), 'g_zlib_compressor_set_file_info'); LoadProc(Pointer(g_zlib_decompressor_get_file_info), 'g_zlib_decompressor_get_file_info'); LoadProc(Pointer(g_zlib_decompressor_get_type), 'g_zlib_decompressor_get_type'); LoadProc(Pointer(g_zlib_decompressor_new), 'g_zlib_decompressor_new'); end; procedure UnloadLibraries; begin if libgio_2_0_so_0 <> 0 then UnloadLibrary(libgio_2_0_so_0); libgio_2_0_so_0 := 0; g_action_activate := nil; g_action_change_state := nil; g_action_get_enabled := nil; g_action_get_name := nil; g_action_get_parameter_type := nil; g_action_get_state := nil; g_action_get_state_hint := nil; g_action_get_state_type := nil; g_action_get_type := nil; g_action_group_action_added := nil; g_action_group_action_enabled_changed := nil; g_action_group_action_removed := nil; g_action_group_action_state_changed := nil; g_action_group_activate_action := nil; g_action_group_change_action_state := nil; g_action_group_get_action_enabled := nil; g_action_group_get_action_parameter_type := nil; g_action_group_get_action_state := nil; g_action_group_get_action_state_hint := nil; g_action_group_get_action_state_type := nil; g_action_group_get_type := nil; g_action_group_has_action := nil; g_action_group_list_actions := nil; g_action_group_query_action := nil; g_action_map_add_action := nil; g_action_map_add_action_entries := nil; g_action_map_get_type := nil; g_action_map_lookup_action := nil; g_action_map_remove_action := nil; g_app_info_add_supports_type := nil; g_app_info_can_delete := nil; g_app_info_can_remove_supports_type := nil; g_app_info_create_from_commandline := nil; g_app_info_delete := nil; g_app_info_dup := nil; g_app_info_equal := nil; g_app_info_get_all := nil; g_app_info_get_all_for_type := nil; g_app_info_get_commandline := nil; g_app_info_get_default_for_type := nil; g_app_info_get_default_for_uri_scheme := nil; g_app_info_get_description := nil; g_app_info_get_display_name := nil; g_app_info_get_executable := nil; g_app_info_get_fallback_for_type := nil; g_app_info_get_icon := nil; g_app_info_get_id := nil; g_app_info_get_name := nil; g_app_info_get_recommended_for_type := nil; g_app_info_get_supported_types := nil; g_app_info_get_type := nil; g_app_info_launch := nil; g_app_info_launch_default_for_uri := nil; g_app_info_launch_uris := nil; g_app_info_remove_supports_type := nil; g_app_info_reset_type_associations := nil; g_app_info_set_as_default_for_extension := nil; g_app_info_set_as_default_for_type := nil; g_app_info_set_as_last_used_for_type := nil; g_app_info_should_show := nil; g_app_info_supports_files := nil; g_app_info_supports_uris := nil; g_app_launch_context_get_display := nil; g_app_launch_context_get_environment := nil; g_app_launch_context_get_startup_notify_id := nil; g_app_launch_context_get_type := nil; g_app_launch_context_launch_failed := nil; g_app_launch_context_new := nil; g_app_launch_context_setenv := nil; g_app_launch_context_unsetenv := nil; g_application_activate := nil; g_application_command_line_create_file_for_arg := nil; g_application_command_line_get_arguments := nil; g_application_command_line_get_cwd := nil; g_application_command_line_get_environ := nil; g_application_command_line_get_exit_status := nil; g_application_command_line_get_is_remote := nil; g_application_command_line_get_platform_data := nil; g_application_command_line_get_stdin := nil; g_application_command_line_get_type := nil; g_application_command_line_getenv := nil; g_application_command_line_print := nil; g_application_command_line_printerr := nil; g_application_command_line_set_exit_status := nil; g_application_get_application_id := nil; g_application_get_dbus_connection := nil; g_application_get_dbus_object_path := nil; g_application_get_default := nil; g_application_get_flags := nil; g_application_get_inactivity_timeout := nil; g_application_get_is_registered := nil; g_application_get_is_remote := nil; g_application_get_type := nil; g_application_hold := nil; g_application_id_is_valid := nil; g_application_new := nil; g_application_open := nil; g_application_quit := nil; g_application_register := nil; g_application_release := nil; g_application_run := nil; g_application_set_application_id := nil; g_application_set_default := nil; g_application_set_flags := nil; g_application_set_inactivity_timeout := nil; g_async_initable_get_type := nil; g_async_initable_init_async := nil; g_async_initable_init_finish := nil; g_async_initable_new_async := nil; g_async_initable_new_finish := nil; g_async_initable_new_valist_async := nil; g_async_initable_newv_async := nil; g_async_result_get_source_object := nil; g_async_result_get_type := nil; g_async_result_get_user_data := nil; g_async_result_is_tagged := nil; g_async_result_legacy_propagate_error := nil; g_buffered_input_stream_fill := nil; g_buffered_input_stream_fill_async := nil; g_buffered_input_stream_fill_finish := nil; g_buffered_input_stream_get_available := nil; g_buffered_input_stream_get_buffer_size := nil; g_buffered_input_stream_get_type := nil; g_buffered_input_stream_new := nil; g_buffered_input_stream_new_sized := nil; g_buffered_input_stream_peek := nil; g_buffered_input_stream_peek_buffer := nil; g_buffered_input_stream_read_byte := nil; g_buffered_input_stream_set_buffer_size := nil; g_buffered_output_stream_get_auto_grow := nil; g_buffered_output_stream_get_buffer_size := nil; g_buffered_output_stream_get_type := nil; g_buffered_output_stream_new := nil; g_buffered_output_stream_new_sized := nil; g_buffered_output_stream_set_auto_grow := nil; g_buffered_output_stream_set_buffer_size := nil; g_bus_get := nil; g_bus_get_finish := nil; g_bus_get_sync := nil; g_bus_own_name := nil; g_bus_own_name_on_connection := nil; g_bus_own_name_on_connection_with_closures := nil; g_bus_own_name_with_closures := nil; g_bus_unown_name := nil; g_bus_unwatch_name := nil; g_bus_watch_name := nil; g_bus_watch_name_on_connection := nil; g_bus_watch_name_on_connection_with_closures := nil; g_bus_watch_name_with_closures := nil; g_cancellable_cancel := nil; g_cancellable_connect := nil; g_cancellable_disconnect := nil; g_cancellable_get_current := nil; g_cancellable_get_fd := nil; g_cancellable_get_type := nil; g_cancellable_is_cancelled := nil; g_cancellable_make_pollfd := nil; g_cancellable_new := nil; g_cancellable_pop_current := nil; g_cancellable_push_current := nil; g_cancellable_release_fd := nil; g_cancellable_reset := nil; g_cancellable_set_error_if_cancelled := nil; g_cancellable_source_new := nil; g_charset_converter_get_num_fallbacks := nil; g_charset_converter_get_type := nil; g_charset_converter_get_use_fallback := nil; g_charset_converter_new := nil; g_charset_converter_set_use_fallback := nil; g_content_type_can_be_executable := nil; g_content_type_equals := nil; g_content_type_from_mime_type := nil; g_content_type_get_description := nil; g_content_type_get_generic_icon_name := nil; g_content_type_get_icon := nil; g_content_type_get_mime_type := nil; g_content_type_get_symbolic_icon := nil; g_content_type_guess := nil; g_content_type_guess_for_tree := nil; g_content_type_is_a := nil; g_content_type_is_unknown := nil; g_content_types_get_registered := nil; g_converter_convert := nil; g_converter_get_type := nil; g_converter_input_stream_get_converter := nil; g_converter_input_stream_get_type := nil; g_converter_input_stream_new := nil; g_converter_output_stream_get_converter := nil; g_converter_output_stream_get_type := nil; g_converter_output_stream_new := nil; g_converter_reset := nil; g_credentials_get_native := nil; g_credentials_get_type := nil; g_credentials_get_unix_pid := nil; g_credentials_get_unix_user := nil; g_credentials_is_same_user := nil; g_credentials_new := nil; g_credentials_set_native := nil; g_credentials_set_unix_user := nil; g_credentials_to_string := nil; g_data_input_stream_get_byte_order := nil; g_data_input_stream_get_newline_type := nil; g_data_input_stream_get_type := nil; g_data_input_stream_new := nil; g_data_input_stream_read_byte := nil; g_data_input_stream_read_int16 := nil; g_data_input_stream_read_int32 := nil; g_data_input_stream_read_int64 := nil; g_data_input_stream_read_line := nil; g_data_input_stream_read_line_async := nil; g_data_input_stream_read_line_finish := nil; g_data_input_stream_read_line_finish_utf8 := nil; g_data_input_stream_read_line_utf8 := nil; g_data_input_stream_read_uint16 := nil; g_data_input_stream_read_uint32 := nil; g_data_input_stream_read_uint64 := nil; g_data_input_stream_read_until := nil; g_data_input_stream_read_until_async := nil; g_data_input_stream_read_until_finish := nil; g_data_input_stream_read_upto := nil; g_data_input_stream_read_upto_async := nil; g_data_input_stream_read_upto_finish := nil; g_data_input_stream_set_byte_order := nil; g_data_input_stream_set_newline_type := nil; g_data_output_stream_get_byte_order := nil; g_data_output_stream_get_type := nil; g_data_output_stream_new := nil; g_data_output_stream_put_byte := nil; g_data_output_stream_put_int16 := nil; g_data_output_stream_put_int32 := nil; g_data_output_stream_put_int64 := nil; g_data_output_stream_put_string := nil; g_data_output_stream_put_uint16 := nil; g_data_output_stream_put_uint32 := nil; g_data_output_stream_put_uint64 := nil; g_data_output_stream_set_byte_order := nil; g_dbus_action_group_get := nil; g_dbus_action_group_get_type := nil; g_dbus_address_escape_value := nil; g_dbus_address_get_for_bus_sync := nil; g_dbus_address_get_stream := nil; g_dbus_address_get_stream_finish := nil; g_dbus_address_get_stream_sync := nil; g_dbus_annotation_info_get_type := nil; g_dbus_annotation_info_lookup := nil; g_dbus_annotation_info_ref := nil; g_dbus_annotation_info_unref := nil; g_dbus_arg_info_get_type := nil; g_dbus_arg_info_ref := nil; g_dbus_arg_info_unref := nil; g_dbus_auth_observer_allow_mechanism := nil; g_dbus_auth_observer_authorize_authenticated_peer := nil; g_dbus_auth_observer_get_type := nil; g_dbus_auth_observer_new := nil; g_dbus_connection_add_filter := nil; g_dbus_connection_call := nil; g_dbus_connection_call_finish := nil; g_dbus_connection_call_sync := nil; g_dbus_connection_call_with_unix_fd_list := nil; g_dbus_connection_call_with_unix_fd_list_finish := nil; g_dbus_connection_call_with_unix_fd_list_sync := nil; g_dbus_connection_close := nil; g_dbus_connection_close_finish := nil; g_dbus_connection_close_sync := nil; g_dbus_connection_emit_signal := nil; g_dbus_connection_export_action_group := nil; g_dbus_connection_export_menu_model := nil; g_dbus_connection_flush := nil; g_dbus_connection_flush_finish := nil; g_dbus_connection_flush_sync := nil; g_dbus_connection_get_capabilities := nil; g_dbus_connection_get_exit_on_close := nil; g_dbus_connection_get_guid := nil; g_dbus_connection_get_last_serial := nil; g_dbus_connection_get_peer_credentials := nil; g_dbus_connection_get_stream := nil; g_dbus_connection_get_type := nil; g_dbus_connection_get_unique_name := nil; g_dbus_connection_is_closed := nil; g_dbus_connection_new := nil; g_dbus_connection_new_finish := nil; g_dbus_connection_new_for_address := nil; g_dbus_connection_new_for_address_finish := nil; g_dbus_connection_new_for_address_sync := nil; g_dbus_connection_new_sync := nil; g_dbus_connection_register_object := nil; g_dbus_connection_register_subtree := nil; g_dbus_connection_remove_filter := nil; g_dbus_connection_send_message := nil; g_dbus_connection_send_message_with_reply := nil; g_dbus_connection_send_message_with_reply_finish := nil; g_dbus_connection_send_message_with_reply_sync := nil; g_dbus_connection_set_exit_on_close := nil; g_dbus_connection_signal_subscribe := nil; g_dbus_connection_signal_unsubscribe := nil; g_dbus_connection_start_message_processing := nil; g_dbus_connection_unexport_action_group := nil; g_dbus_connection_unexport_menu_model := nil; g_dbus_connection_unregister_object := nil; g_dbus_connection_unregister_subtree := nil; g_dbus_error_encode_gerror := nil; g_dbus_error_get_remote_error := nil; g_dbus_error_is_remote_error := nil; g_dbus_error_new_for_dbus_error := nil; g_dbus_error_quark := nil; g_dbus_error_register_error := nil; g_dbus_error_register_error_domain := nil; g_dbus_error_set_dbus_error := nil; g_dbus_error_set_dbus_error_valist := nil; g_dbus_error_strip_remote_error := nil; g_dbus_error_unregister_error := nil; g_dbus_generate_guid := nil; g_dbus_gvalue_to_gvariant := nil; g_dbus_gvariant_to_gvalue := nil; g_dbus_interface_dup_object := nil; g_dbus_interface_get_info := nil; g_dbus_interface_get_object := nil; g_dbus_interface_get_type := nil; g_dbus_interface_info_cache_build := nil; g_dbus_interface_info_cache_release := nil; g_dbus_interface_info_generate_xml := nil; g_dbus_interface_info_get_type := nil; g_dbus_interface_info_lookup_method := nil; g_dbus_interface_info_lookup_property := nil; g_dbus_interface_info_lookup_signal := nil; g_dbus_interface_info_ref := nil; g_dbus_interface_info_unref := nil; g_dbus_interface_set_object := nil; g_dbus_interface_skeleton_export := nil; g_dbus_interface_skeleton_flush := nil; g_dbus_interface_skeleton_get_connection := nil; g_dbus_interface_skeleton_get_connections := nil; g_dbus_interface_skeleton_get_flags := nil; g_dbus_interface_skeleton_get_info := nil; g_dbus_interface_skeleton_get_object_path := nil; g_dbus_interface_skeleton_get_properties := nil; g_dbus_interface_skeleton_get_type := nil; g_dbus_interface_skeleton_get_vtable := nil; g_dbus_interface_skeleton_has_connection := nil; g_dbus_interface_skeleton_set_flags := nil; g_dbus_interface_skeleton_unexport := nil; g_dbus_interface_skeleton_unexport_from_connection := nil; g_dbus_is_address := nil; g_dbus_is_guid := nil; g_dbus_is_interface_name := nil; g_dbus_is_member_name := nil; g_dbus_is_name := nil; g_dbus_is_supported_address := nil; g_dbus_is_unique_name := nil; g_dbus_menu_model_get := nil; g_dbus_menu_model_get_type := nil; g_dbus_message_bytes_needed := nil; g_dbus_message_copy := nil; g_dbus_message_get_arg0 := nil; g_dbus_message_get_body := nil; g_dbus_message_get_byte_order := nil; g_dbus_message_get_destination := nil; g_dbus_message_get_error_name := nil; g_dbus_message_get_flags := nil; g_dbus_message_get_header := nil; g_dbus_message_get_header_fields := nil; g_dbus_message_get_interface := nil; g_dbus_message_get_locked := nil; g_dbus_message_get_member := nil; g_dbus_message_get_message_type := nil; g_dbus_message_get_num_unix_fds := nil; g_dbus_message_get_path := nil; g_dbus_message_get_reply_serial := nil; g_dbus_message_get_sender := nil; g_dbus_message_get_serial := nil; g_dbus_message_get_signature := nil; g_dbus_message_get_type := nil; g_dbus_message_get_unix_fd_list := nil; g_dbus_message_lock := nil; g_dbus_message_new := nil; g_dbus_message_new_from_blob := nil; g_dbus_message_new_method_call := nil; g_dbus_message_new_method_error := nil; g_dbus_message_new_method_error_literal := nil; g_dbus_message_new_method_error_valist := nil; g_dbus_message_new_method_reply := nil; g_dbus_message_new_signal := nil; g_dbus_message_print := nil; g_dbus_message_set_body := nil; g_dbus_message_set_byte_order := nil; g_dbus_message_set_destination := nil; g_dbus_message_set_error_name := nil; g_dbus_message_set_flags := nil; g_dbus_message_set_header := nil; g_dbus_message_set_interface := nil; g_dbus_message_set_member := nil; g_dbus_message_set_message_type := nil; g_dbus_message_set_num_unix_fds := nil; g_dbus_message_set_path := nil; g_dbus_message_set_reply_serial := nil; g_dbus_message_set_sender := nil; g_dbus_message_set_serial := nil; g_dbus_message_set_signature := nil; g_dbus_message_set_unix_fd_list := nil; g_dbus_message_to_blob := nil; g_dbus_message_to_gerror := nil; g_dbus_method_info_get_type := nil; g_dbus_method_info_ref := nil; g_dbus_method_info_unref := nil; g_dbus_method_invocation_get_connection := nil; g_dbus_method_invocation_get_interface_name := nil; g_dbus_method_invocation_get_message := nil; g_dbus_method_invocation_get_method_info := nil; g_dbus_method_invocation_get_method_name := nil; g_dbus_method_invocation_get_object_path := nil; g_dbus_method_invocation_get_parameters := nil; g_dbus_method_invocation_get_sender := nil; g_dbus_method_invocation_get_type := nil; g_dbus_method_invocation_get_user_data := nil; g_dbus_method_invocation_return_dbus_error := nil; g_dbus_method_invocation_return_error := nil; g_dbus_method_invocation_return_error_literal := nil; g_dbus_method_invocation_return_error_valist := nil; g_dbus_method_invocation_return_gerror := nil; g_dbus_method_invocation_return_value := nil; g_dbus_method_invocation_return_value_with_unix_fd_list := nil; g_dbus_method_invocation_take_error := nil; g_dbus_node_info_generate_xml := nil; g_dbus_node_info_get_type := nil; g_dbus_node_info_lookup_interface := nil; g_dbus_node_info_new_for_xml := nil; g_dbus_node_info_ref := nil; g_dbus_node_info_unref := nil; g_dbus_object_get_interface := nil; g_dbus_object_get_interfaces := nil; g_dbus_object_get_object_path := nil; g_dbus_object_get_type := nil; g_dbus_object_manager_client_get_connection := nil; g_dbus_object_manager_client_get_flags := nil; g_dbus_object_manager_client_get_name := nil; g_dbus_object_manager_client_get_name_owner := nil; g_dbus_object_manager_client_get_type := nil; g_dbus_object_manager_client_new := nil; g_dbus_object_manager_client_new_finish := nil; g_dbus_object_manager_client_new_for_bus := nil; g_dbus_object_manager_client_new_for_bus_finish := nil; g_dbus_object_manager_client_new_for_bus_sync := nil; g_dbus_object_manager_client_new_sync := nil; g_dbus_object_manager_get_interface := nil; g_dbus_object_manager_get_object := nil; g_dbus_object_manager_get_object_path := nil; g_dbus_object_manager_get_objects := nil; g_dbus_object_manager_get_type := nil; g_dbus_object_manager_server_export := nil; g_dbus_object_manager_server_export_uniquely := nil; g_dbus_object_manager_server_get_connection := nil; g_dbus_object_manager_server_get_type := nil; g_dbus_object_manager_server_is_exported := nil; g_dbus_object_manager_server_new := nil; g_dbus_object_manager_server_set_connection := nil; g_dbus_object_manager_server_unexport := nil; g_dbus_object_proxy_get_connection := nil; g_dbus_object_proxy_get_type := nil; g_dbus_object_proxy_new := nil; g_dbus_object_skeleton_add_interface := nil; g_dbus_object_skeleton_flush := nil; g_dbus_object_skeleton_get_type := nil; g_dbus_object_skeleton_new := nil; g_dbus_object_skeleton_remove_interface := nil; g_dbus_object_skeleton_remove_interface_by_name := nil; g_dbus_object_skeleton_set_object_path := nil; g_dbus_property_info_get_type := nil; g_dbus_property_info_ref := nil; g_dbus_property_info_unref := nil; g_dbus_proxy_call := nil; g_dbus_proxy_call_finish := nil; g_dbus_proxy_call_sync := nil; g_dbus_proxy_call_with_unix_fd_list := nil; g_dbus_proxy_call_with_unix_fd_list_finish := nil; g_dbus_proxy_call_with_unix_fd_list_sync := nil; g_dbus_proxy_get_cached_property := nil; g_dbus_proxy_get_cached_property_names := nil; g_dbus_proxy_get_connection := nil; g_dbus_proxy_get_default_timeout := nil; g_dbus_proxy_get_flags := nil; g_dbus_proxy_get_interface_info := nil; g_dbus_proxy_get_interface_name := nil; g_dbus_proxy_get_name := nil; g_dbus_proxy_get_name_owner := nil; g_dbus_proxy_get_object_path := nil; g_dbus_proxy_get_type := nil; g_dbus_proxy_new := nil; g_dbus_proxy_new_finish := nil; g_dbus_proxy_new_for_bus := nil; g_dbus_proxy_new_for_bus_finish := nil; g_dbus_proxy_new_for_bus_sync := nil; g_dbus_proxy_new_sync := nil; g_dbus_proxy_set_cached_property := nil; g_dbus_proxy_set_default_timeout := nil; g_dbus_proxy_set_interface_info := nil; g_dbus_server_get_client_address := nil; g_dbus_server_get_flags := nil; g_dbus_server_get_guid := nil; g_dbus_server_get_type := nil; g_dbus_server_is_active := nil; g_dbus_server_new_sync := nil; g_dbus_server_start := nil; g_dbus_server_stop := nil; g_dbus_signal_info_get_type := nil; g_dbus_signal_info_ref := nil; g_dbus_signal_info_unref := nil; g_desktop_app_info_get_boolean := nil; g_desktop_app_info_get_categories := nil; g_desktop_app_info_get_filename := nil; g_desktop_app_info_get_generic_name := nil; g_desktop_app_info_get_is_hidden := nil; g_desktop_app_info_get_keywords := nil; g_desktop_app_info_get_nodisplay := nil; g_desktop_app_info_get_show_in := nil; g_desktop_app_info_get_startup_wm_class := nil; g_desktop_app_info_get_string := nil; g_desktop_app_info_get_type := nil; g_desktop_app_info_has_key := nil; g_desktop_app_info_launch_uris_as_manager := nil; g_desktop_app_info_lookup_get_type := nil; g_desktop_app_info_new := nil; g_desktop_app_info_new_from_filename := nil; g_desktop_app_info_new_from_keyfile := nil; g_desktop_app_info_set_desktop_env := nil; g_drive_can_eject := nil; g_drive_can_poll_for_media := nil; g_drive_can_start := nil; g_drive_can_start_degraded := nil; g_drive_can_stop := nil; g_drive_eject_with_operation := nil; g_drive_eject_with_operation_finish := nil; g_drive_enumerate_identifiers := nil; g_drive_get_icon := nil; g_drive_get_identifier := nil; g_drive_get_name := nil; g_drive_get_sort_key := nil; g_drive_get_start_stop_type := nil; g_drive_get_symbolic_icon := nil; g_drive_get_type := nil; g_drive_get_volumes := nil; g_drive_has_media := nil; g_drive_has_volumes := nil; g_drive_is_media_check_automatic := nil; g_drive_is_media_removable := nil; g_drive_poll_for_media := nil; g_drive_poll_for_media_finish := nil; g_drive_start := nil; g_drive_start_finish := nil; g_drive_stop := nil; g_drive_stop_finish := nil; g_emblem_get_icon := nil; g_emblem_get_origin := nil; g_emblem_get_type := nil; g_emblem_new := nil; g_emblem_new_with_origin := nil; g_emblemed_icon_add_emblem := nil; g_emblemed_icon_clear_emblems := nil; g_emblemed_icon_get_emblems := nil; g_emblemed_icon_get_icon := nil; g_emblemed_icon_get_type := nil; g_emblemed_icon_new := nil; g_file_append_to := nil; g_file_append_to_async := nil; g_file_append_to_finish := nil; g_file_attribute_info_list_add := nil; g_file_attribute_info_list_dup := nil; g_file_attribute_info_list_get_type := nil; g_file_attribute_info_list_lookup := nil; g_file_attribute_info_list_new := nil; g_file_attribute_info_list_ref := nil; g_file_attribute_info_list_unref := nil; g_file_attribute_matcher_enumerate_namespace := nil; g_file_attribute_matcher_enumerate_next := nil; g_file_attribute_matcher_get_type := nil; g_file_attribute_matcher_matches := nil; g_file_attribute_matcher_matches_only := nil; g_file_attribute_matcher_new := nil; g_file_attribute_matcher_ref := nil; g_file_attribute_matcher_subtract := nil; g_file_attribute_matcher_to_string := nil; g_file_attribute_matcher_unref := nil; g_file_copy := nil; g_file_copy_async := nil; g_file_copy_attributes := nil; g_file_copy_finish := nil; g_file_create := nil; g_file_create_async := nil; g_file_create_finish := nil; g_file_create_readwrite := nil; g_file_create_readwrite_async := nil; g_file_create_readwrite_finish := nil; g_file_delete := nil; g_file_delete_async := nil; g_file_delete_finish := nil; g_file_descriptor_based_get_fd := nil; g_file_descriptor_based_get_type := nil; g_file_dup := nil; g_file_eject_mountable_with_operation := nil; g_file_eject_mountable_with_operation_finish := nil; g_file_enumerate_children := nil; g_file_enumerate_children_async := nil; g_file_enumerate_children_finish := nil; g_file_enumerator_close := nil; g_file_enumerator_close_async := nil; g_file_enumerator_close_finish := nil; g_file_enumerator_get_child := nil; g_file_enumerator_get_container := nil; g_file_enumerator_get_type := nil; g_file_enumerator_has_pending := nil; g_file_enumerator_is_closed := nil; g_file_enumerator_next_file := nil; g_file_enumerator_next_files_async := nil; g_file_enumerator_next_files_finish := nil; g_file_enumerator_set_pending := nil; g_file_equal := nil; g_file_find_enclosing_mount := nil; g_file_find_enclosing_mount_async := nil; g_file_find_enclosing_mount_finish := nil; g_file_get_basename := nil; g_file_get_child := nil; g_file_get_child_for_display_name := nil; g_file_get_parent := nil; g_file_get_parse_name := nil; g_file_get_path := nil; g_file_get_relative_path := nil; g_file_get_type := nil; g_file_get_uri := nil; g_file_get_uri_scheme := nil; g_file_has_parent := nil; g_file_has_prefix := nil; g_file_has_uri_scheme := nil; g_file_hash := nil; g_file_icon_get_file := nil; g_file_icon_get_type := nil; g_file_icon_new := nil; g_file_info_clear_status := nil; g_file_info_copy_into := nil; g_file_info_dup := nil; g_file_info_get_attribute_as_string := nil; g_file_info_get_attribute_boolean := nil; g_file_info_get_attribute_byte_string := nil; g_file_info_get_attribute_data := nil; g_file_info_get_attribute_int32 := nil; g_file_info_get_attribute_int64 := nil; g_file_info_get_attribute_object := nil; g_file_info_get_attribute_status := nil; g_file_info_get_attribute_string := nil; g_file_info_get_attribute_stringv := nil; g_file_info_get_attribute_type := nil; g_file_info_get_attribute_uint32 := nil; g_file_info_get_attribute_uint64 := nil; g_file_info_get_content_type := nil; g_file_info_get_deletion_date := nil; g_file_info_get_display_name := nil; g_file_info_get_edit_name := nil; g_file_info_get_etag := nil; g_file_info_get_file_type := nil; g_file_info_get_icon := nil; g_file_info_get_is_backup := nil; g_file_info_get_is_hidden := nil; g_file_info_get_is_symlink := nil; g_file_info_get_modification_time := nil; g_file_info_get_name := nil; g_file_info_get_size := nil; g_file_info_get_sort_order := nil; g_file_info_get_symbolic_icon := nil; g_file_info_get_symlink_target := nil; g_file_info_get_type := nil; g_file_info_has_attribute := nil; g_file_info_has_namespace := nil; g_file_info_list_attributes := nil; g_file_info_new := nil; g_file_info_remove_attribute := nil; g_file_info_set_attribute := nil; g_file_info_set_attribute_boolean := nil; g_file_info_set_attribute_byte_string := nil; g_file_info_set_attribute_int32 := nil; g_file_info_set_attribute_int64 := nil; g_file_info_set_attribute_mask := nil; g_file_info_set_attribute_object := nil; g_file_info_set_attribute_status := nil; g_file_info_set_attribute_string := nil; g_file_info_set_attribute_stringv := nil; g_file_info_set_attribute_uint32 := nil; g_file_info_set_attribute_uint64 := nil; g_file_info_set_content_type := nil; g_file_info_set_display_name := nil; g_file_info_set_edit_name := nil; g_file_info_set_file_type := nil; g_file_info_set_icon := nil; g_file_info_set_is_hidden := nil; g_file_info_set_is_symlink := nil; g_file_info_set_modification_time := nil; g_file_info_set_name := nil; g_file_info_set_size := nil; g_file_info_set_sort_order := nil; g_file_info_set_symbolic_icon := nil; g_file_info_set_symlink_target := nil; g_file_info_unset_attribute_mask := nil; g_file_input_stream_get_type := nil; g_file_input_stream_query_info := nil; g_file_input_stream_query_info_async := nil; g_file_input_stream_query_info_finish := nil; g_file_io_stream_get_etag := nil; g_file_io_stream_get_type := nil; g_file_io_stream_query_info := nil; g_file_io_stream_query_info_async := nil; g_file_io_stream_query_info_finish := nil; g_file_is_native := nil; g_file_load_contents := nil; g_file_load_contents_async := nil; g_file_load_contents_finish := nil; g_file_load_partial_contents_async := nil; g_file_load_partial_contents_finish := nil; g_file_make_directory := nil; g_file_make_directory_with_parents := nil; g_file_make_symbolic_link := nil; g_file_monitor := nil; g_file_monitor_cancel := nil; g_file_monitor_directory := nil; g_file_monitor_emit_event := nil; g_file_monitor_file := nil; g_file_monitor_get_type := nil; g_file_monitor_is_cancelled := nil; g_file_monitor_set_rate_limit := nil; g_file_mount_enclosing_volume := nil; g_file_mount_enclosing_volume_finish := nil; g_file_mount_mountable := nil; g_file_mount_mountable_finish := nil; g_file_move := nil; g_file_new_for_commandline_arg := nil; g_file_new_for_commandline_arg_and_cwd := nil; g_file_new_for_path := nil; g_file_new_for_uri := nil; g_file_new_tmp := nil; g_file_open_readwrite := nil; g_file_open_readwrite_async := nil; g_file_open_readwrite_finish := nil; g_file_output_stream_get_etag := nil; g_file_output_stream_get_type := nil; g_file_output_stream_query_info := nil; g_file_output_stream_query_info_async := nil; g_file_output_stream_query_info_finish := nil; g_file_parse_name := nil; g_file_poll_mountable := nil; g_file_poll_mountable_finish := nil; g_file_query_default_handler := nil; g_file_query_exists := nil; g_file_query_file_type := nil; g_file_query_filesystem_info := nil; g_file_query_filesystem_info_async := nil; g_file_query_filesystem_info_finish := nil; g_file_query_info := nil; g_file_query_info_async := nil; g_file_query_info_finish := nil; g_file_query_settable_attributes := nil; g_file_query_writable_namespaces := nil; g_file_read := nil; g_file_read_async := nil; g_file_read_finish := nil; g_file_replace := nil; g_file_replace_async := nil; g_file_replace_contents := nil; g_file_replace_contents_async := nil; g_file_replace_contents_finish := nil; g_file_replace_finish := nil; g_file_replace_readwrite := nil; g_file_replace_readwrite_async := nil; g_file_replace_readwrite_finish := nil; g_file_resolve_relative_path := nil; g_file_set_attribute := nil; g_file_set_attribute_byte_string := nil; g_file_set_attribute_int32 := nil; g_file_set_attribute_int64 := nil; g_file_set_attribute_string := nil; g_file_set_attribute_uint32 := nil; g_file_set_attribute_uint64 := nil; g_file_set_attributes_async := nil; g_file_set_attributes_finish := nil; g_file_set_attributes_from_info := nil; g_file_set_display_name := nil; g_file_set_display_name_async := nil; g_file_set_display_name_finish := nil; g_file_start_mountable := nil; g_file_start_mountable_finish := nil; g_file_stop_mountable := nil; g_file_stop_mountable_finish := nil; g_file_supports_thread_contexts := nil; g_file_trash := nil; g_file_unmount_mountable_with_operation := nil; g_file_unmount_mountable_with_operation_finish := nil; g_filename_completer_get_completion_suffix := nil; g_filename_completer_get_completions := nil; g_filename_completer_get_type := nil; g_filename_completer_new := nil; g_filename_completer_set_dirs_only := nil; g_filter_input_stream_get_base_stream := nil; g_filter_input_stream_get_close_base_stream := nil; g_filter_input_stream_get_type := nil; g_filter_input_stream_set_close_base_stream := nil; g_filter_output_stream_get_base_stream := nil; g_filter_output_stream_get_close_base_stream := nil; g_filter_output_stream_get_type := nil; g_filter_output_stream_set_close_base_stream := nil; g_icon_equal := nil; g_icon_get_type := nil; g_icon_hash := nil; g_icon_new_for_string := nil; g_icon_to_string := nil; g_inet_address_equal := nil; g_inet_address_get_family := nil; g_inet_address_get_is_any := nil; g_inet_address_get_is_link_local := nil; g_inet_address_get_is_loopback := nil; g_inet_address_get_is_mc_global := nil; g_inet_address_get_is_mc_link_local := nil; g_inet_address_get_is_mc_node_local := nil; g_inet_address_get_is_mc_org_local := nil; g_inet_address_get_is_mc_site_local := nil; g_inet_address_get_is_multicast := nil; g_inet_address_get_is_site_local := nil; g_inet_address_get_native_size := nil; g_inet_address_get_type := nil; g_inet_address_mask_equal := nil; g_inet_address_mask_get_address := nil; g_inet_address_mask_get_family := nil; g_inet_address_mask_get_length := nil; g_inet_address_mask_get_type := nil; g_inet_address_mask_matches := nil; g_inet_address_mask_new := nil; g_inet_address_mask_new_from_string := nil; g_inet_address_mask_to_string := nil; g_inet_address_new_any := nil; g_inet_address_new_from_bytes := nil; g_inet_address_new_from_string := nil; g_inet_address_new_loopback := nil; g_inet_address_to_bytes := nil; g_inet_address_to_string := nil; g_inet_socket_address_get_address := nil; g_inet_socket_address_get_flowinfo := nil; g_inet_socket_address_get_port := nil; g_inet_socket_address_get_scope_id := nil; g_inet_socket_address_get_type := nil; g_inet_socket_address_new := nil; g_initable_get_type := nil; g_initable_init := nil; g_initable_new := nil; g_initable_new_valist := nil; g_initable_newv := nil; g_input_stream_clear_pending := nil; g_input_stream_close := nil; g_input_stream_close_async := nil; g_input_stream_close_finish := nil; g_input_stream_get_type := nil; g_input_stream_has_pending := nil; g_input_stream_is_closed := nil; g_input_stream_read := nil; g_input_stream_read_all := nil; g_input_stream_read_async := nil; g_input_stream_read_bytes := nil; g_input_stream_read_bytes_async := nil; g_input_stream_read_bytes_finish := nil; g_input_stream_read_finish := nil; g_input_stream_set_pending := nil; g_input_stream_skip := nil; g_input_stream_skip_async := nil; g_input_stream_skip_finish := nil; g_io_error_from_errno := nil; g_io_error_quark := nil; g_io_extension_get_name := nil; g_io_extension_get_priority := nil; g_io_extension_get_type := nil; g_io_extension_point_get_extension_by_name := nil; g_io_extension_point_get_extensions := nil; g_io_extension_point_get_required_type := nil; g_io_extension_point_implement := nil; g_io_extension_point_lookup := nil; g_io_extension_point_register := nil; g_io_extension_point_set_required_type := nil; g_io_extension_ref_class := nil; g_io_module_get_type := nil; g_io_module_new := nil; g_io_module_scope_block := nil; g_io_module_scope_free := nil; g_io_module_scope_new := nil; g_io_modules_load_all_in_directory := nil; g_io_modules_load_all_in_directory_with_scope := nil; g_io_modules_scan_all_in_directory := nil; g_io_modules_scan_all_in_directory_with_scope := nil; g_io_scheduler_cancel_all_jobs := nil; g_io_scheduler_push_job := nil; g_io_stream_clear_pending := nil; g_io_stream_close := nil; g_io_stream_close_async := nil; g_io_stream_close_finish := nil; g_io_stream_get_input_stream := nil; g_io_stream_get_output_stream := nil; g_io_stream_get_type := nil; g_io_stream_has_pending := nil; g_io_stream_is_closed := nil; g_io_stream_set_pending := nil; g_io_stream_splice_async := nil; g_io_stream_splice_finish := nil; g_loadable_icon_get_type := nil; g_loadable_icon_load := nil; g_loadable_icon_load_async := nil; g_loadable_icon_load_finish := nil; g_memory_input_stream_add_bytes := nil; g_memory_input_stream_add_data := nil; g_memory_input_stream_get_type := nil; g_memory_input_stream_new := nil; g_memory_input_stream_new_from_bytes := nil; g_memory_input_stream_new_from_data := nil; g_memory_output_stream_get_data := nil; g_memory_output_stream_get_data_size := nil; g_memory_output_stream_get_size := nil; g_memory_output_stream_get_type := nil; g_memory_output_stream_new := nil; g_memory_output_stream_new_resizable := nil; g_memory_output_stream_steal_as_bytes := nil; g_memory_output_stream_steal_data := nil; g_menu_append := nil; g_menu_append_item := nil; g_menu_append_section := nil; g_menu_append_submenu := nil; g_menu_attribute_iter_get_name := nil; g_menu_attribute_iter_get_next := nil; g_menu_attribute_iter_get_type := nil; g_menu_attribute_iter_get_value := nil; g_menu_attribute_iter_next := nil; g_menu_freeze := nil; g_menu_get_type := nil; g_menu_insert := nil; g_menu_insert_item := nil; g_menu_insert_section := nil; g_menu_insert_submenu := nil; g_menu_item_get_attribute := nil; g_menu_item_get_attribute_value := nil; g_menu_item_get_link := nil; g_menu_item_get_type := nil; g_menu_item_new := nil; g_menu_item_new_from_model := nil; g_menu_item_new_section := nil; g_menu_item_new_submenu := nil; g_menu_item_set_action_and_target := nil; g_menu_item_set_action_and_target_value := nil; g_menu_item_set_attribute := nil; g_menu_item_set_attribute_value := nil; g_menu_item_set_detailed_action := nil; g_menu_item_set_label := nil; g_menu_item_set_link := nil; g_menu_item_set_section := nil; g_menu_item_set_submenu := nil; g_menu_link_iter_get_name := nil; g_menu_link_iter_get_next := nil; g_menu_link_iter_get_type := nil; g_menu_link_iter_get_value := nil; g_menu_link_iter_next := nil; g_menu_model_get_item_attribute := nil; g_menu_model_get_item_attribute_value := nil; g_menu_model_get_item_link := nil; g_menu_model_get_n_items := nil; g_menu_model_get_type := nil; g_menu_model_is_mutable := nil; g_menu_model_items_changed := nil; g_menu_model_iterate_item_attributes := nil; g_menu_model_iterate_item_links := nil; g_menu_new := nil; g_menu_prepend := nil; g_menu_prepend_item := nil; g_menu_prepend_section := nil; g_menu_prepend_submenu := nil; g_menu_remove := nil; g_mount_can_eject := nil; g_mount_can_unmount := nil; g_mount_eject_with_operation := nil; g_mount_eject_with_operation_finish := nil; g_mount_get_default_location := nil; g_mount_get_drive := nil; g_mount_get_icon := nil; g_mount_get_name := nil; g_mount_get_root := nil; g_mount_get_sort_key := nil; g_mount_get_symbolic_icon := nil; g_mount_get_type := nil; g_mount_get_uuid := nil; g_mount_get_volume := nil; g_mount_guess_content_type := nil; g_mount_guess_content_type_finish := nil; g_mount_guess_content_type_sync := nil; g_mount_is_shadowed := nil; g_mount_operation_get_anonymous := nil; g_mount_operation_get_choice := nil; g_mount_operation_get_domain := nil; g_mount_operation_get_password := nil; g_mount_operation_get_password_save := nil; g_mount_operation_get_type := nil; g_mount_operation_get_username := nil; g_mount_operation_new := nil; g_mount_operation_reply := nil; g_mount_operation_set_anonymous := nil; g_mount_operation_set_choice := nil; g_mount_operation_set_domain := nil; g_mount_operation_set_password := nil; g_mount_operation_set_password_save := nil; g_mount_operation_set_username := nil; g_mount_remount := nil; g_mount_remount_finish := nil; g_mount_shadow := nil; g_mount_unmount_with_operation := nil; g_mount_unmount_with_operation_finish := nil; g_mount_unshadow := nil; g_native_volume_monitor_get_type := nil; g_network_address_get_hostname := nil; g_network_address_get_port := nil; g_network_address_get_scheme := nil; g_network_address_get_type := nil; g_network_address_new := nil; g_network_address_parse := nil; g_network_address_parse_uri := nil; g_network_monitor_can_reach := nil; g_network_monitor_can_reach_async := nil; g_network_monitor_can_reach_finish := nil; g_network_monitor_get_default := nil; g_network_monitor_get_network_available := nil; g_network_monitor_get_type := nil; g_network_service_get_domain := nil; g_network_service_get_protocol := nil; g_network_service_get_scheme := nil; g_network_service_get_service := nil; g_network_service_get_type := nil; g_network_service_new := nil; g_network_service_set_scheme := nil; g_networking_init := nil; g_output_stream_clear_pending := nil; g_output_stream_close := nil; g_output_stream_close_async := nil; g_output_stream_close_finish := nil; g_output_stream_flush := nil; g_output_stream_flush_async := nil; g_output_stream_flush_finish := nil; g_output_stream_get_type := nil; g_output_stream_has_pending := nil; g_output_stream_is_closed := nil; g_output_stream_is_closing := nil; g_output_stream_set_pending := nil; g_output_stream_splice := nil; g_output_stream_splice_async := nil; g_output_stream_splice_finish := nil; g_output_stream_write := nil; g_output_stream_write_all := nil; g_output_stream_write_async := nil; g_output_stream_write_bytes := nil; g_output_stream_write_bytes_async := nil; g_output_stream_write_bytes_finish := nil; g_output_stream_write_finish := nil; g_permission_acquire := nil; g_permission_acquire_async := nil; g_permission_acquire_finish := nil; g_permission_get_allowed := nil; g_permission_get_can_acquire := nil; g_permission_get_can_release := nil; g_permission_get_type := nil; g_permission_impl_update := nil; g_permission_release := nil; g_permission_release_async := nil; g_permission_release_finish := nil; g_pollable_input_stream_can_poll := nil; g_pollable_input_stream_create_source := nil; g_pollable_input_stream_get_type := nil; g_pollable_input_stream_is_readable := nil; g_pollable_input_stream_read_nonblocking := nil; g_pollable_output_stream_can_poll := nil; g_pollable_output_stream_create_source := nil; g_pollable_output_stream_get_type := nil; g_pollable_output_stream_is_writable := nil; g_pollable_output_stream_write_nonblocking := nil; g_pollable_source_new := nil; g_pollable_source_new_full := nil; g_pollable_stream_read := nil; g_pollable_stream_write := nil; g_pollable_stream_write_all := nil; g_proxy_address_enumerator_get_type := nil; g_proxy_address_get_destination_hostname := nil; g_proxy_address_get_destination_port := nil; g_proxy_address_get_destination_protocol := nil; g_proxy_address_get_password := nil; g_proxy_address_get_protocol := nil; g_proxy_address_get_type := nil; g_proxy_address_get_uri := nil; g_proxy_address_get_username := nil; g_proxy_address_new := nil; g_proxy_connect := nil; g_proxy_connect_async := nil; g_proxy_connect_finish := nil; g_proxy_get_default_for_protocol := nil; g_proxy_get_type := nil; g_proxy_resolver_get_default := nil; g_proxy_resolver_get_type := nil; g_proxy_resolver_is_supported := nil; g_proxy_resolver_lookup := nil; g_proxy_resolver_lookup_async := nil; g_proxy_resolver_lookup_finish := nil; g_proxy_supports_hostname := nil; g_remote_action_group_activate_action_full := nil; g_remote_action_group_change_action_state_full := nil; g_remote_action_group_get_type := nil; g_resolver_error_quark := nil; g_resolver_free_addresses := nil; g_resolver_free_targets := nil; g_resolver_get_default := nil; g_resolver_get_type := nil; g_resolver_lookup_by_address := nil; g_resolver_lookup_by_address_async := nil; g_resolver_lookup_by_address_finish := nil; g_resolver_lookup_by_name := nil; g_resolver_lookup_by_name_async := nil; g_resolver_lookup_by_name_finish := nil; g_resolver_lookup_records := nil; g_resolver_lookup_records_async := nil; g_resolver_lookup_records_finish := nil; g_resolver_lookup_service := nil; g_resolver_lookup_service_async := nil; g_resolver_lookup_service_finish := nil; g_resolver_set_default := nil; g_resource_enumerate_children := nil; g_resource_error_quark := nil; g_resource_get_info := nil; g_resource_get_type := nil; g_resource_load := nil; g_resource_lookup_data := nil; g_resource_new_from_data := nil; g_resource_open_stream := nil; g_resource_ref := nil; g_resource_unref := nil; g_resources_enumerate_children := nil; g_resources_get_info := nil; g_resources_lookup_data := nil; g_resources_open_stream := nil; g_resources_register := nil; g_resources_unregister := nil; g_seekable_can_seek := nil; g_seekable_can_truncate := nil; g_seekable_get_type := nil; g_seekable_seek := nil; g_seekable_tell := nil; g_seekable_truncate := nil; g_settings_apply := nil; g_settings_bind := nil; g_settings_bind_with_mapping := nil; g_settings_bind_writable := nil; g_settings_create_action := nil; g_settings_delay := nil; g_settings_get := nil; g_settings_get_boolean := nil; g_settings_get_child := nil; g_settings_get_double := nil; g_settings_get_enum := nil; g_settings_get_flags := nil; g_settings_get_has_unapplied := nil; g_settings_get_int := nil; g_settings_get_mapped := nil; g_settings_get_range := nil; g_settings_get_string := nil; g_settings_get_strv := nil; g_settings_get_type := nil; g_settings_get_uint := nil; g_settings_get_value := nil; g_settings_is_writable := nil; g_settings_list_children := nil; g_settings_list_keys := nil; g_settings_list_relocatable_schemas := nil; g_settings_list_schemas := nil; g_settings_new := nil; g_settings_new_full := nil; g_settings_new_with_backend := nil; g_settings_new_with_backend_and_path := nil; g_settings_new_with_path := nil; g_settings_range_check := nil; g_settings_reset := nil; g_settings_revert := nil; g_settings_schema_get_id := nil; g_settings_schema_get_path := nil; g_settings_schema_get_type := nil; g_settings_schema_ref := nil; g_settings_schema_source_get_default := nil; g_settings_schema_source_get_type := nil; g_settings_schema_source_lookup := nil; g_settings_schema_source_new_from_directory := nil; g_settings_schema_source_ref := nil; g_settings_schema_source_unref := nil; g_settings_schema_unref := nil; g_settings_set := nil; g_settings_set_boolean := nil; g_settings_set_double := nil; g_settings_set_enum := nil; g_settings_set_flags := nil; g_settings_set_int := nil; g_settings_set_string := nil; g_settings_set_strv := nil; g_settings_set_uint := nil; g_settings_set_value := nil; g_settings_sync := nil; g_settings_unbind := nil; g_simple_action_get_type := nil; g_simple_action_group_add_entries := nil; g_simple_action_group_get_type := nil; g_simple_action_group_insert := nil; g_simple_action_group_lookup := nil; g_simple_action_group_new := nil; g_simple_action_group_remove := nil; g_simple_action_new := nil; g_simple_action_new_stateful := nil; g_simple_action_set_enabled := nil; g_simple_action_set_state := nil; g_simple_async_report_error_in_idle := nil; g_simple_async_report_gerror_in_idle := nil; g_simple_async_report_take_gerror_in_idle := nil; g_simple_async_result_complete := nil; g_simple_async_result_complete_in_idle := nil; g_simple_async_result_get_op_res_gboolean := nil; g_simple_async_result_get_op_res_gpointer := nil; g_simple_async_result_get_op_res_gssize := nil; g_simple_async_result_get_source_tag := nil; g_simple_async_result_get_type := nil; g_simple_async_result_is_valid := nil; g_simple_async_result_new := nil; g_simple_async_result_new_error := nil; g_simple_async_result_new_from_error := nil; g_simple_async_result_new_take_error := nil; g_simple_async_result_propagate_error := nil; g_simple_async_result_run_in_thread := nil; g_simple_async_result_set_check_cancellable := nil; g_simple_async_result_set_error := nil; g_simple_async_result_set_error_va := nil; g_simple_async_result_set_from_error := nil; g_simple_async_result_set_handle_cancellation := nil; g_simple_async_result_set_op_res_gboolean := nil; g_simple_async_result_set_op_res_gpointer := nil; g_simple_async_result_set_op_res_gssize := nil; g_simple_async_result_take_error := nil; g_simple_permission_get_type := nil; g_simple_permission_new := nil; g_simple_proxy_resolver_get_type := nil; g_simple_proxy_resolver_new := nil; g_simple_proxy_resolver_set_default_proxy := nil; g_simple_proxy_resolver_set_ignore_hosts := nil; g_simple_proxy_resolver_set_uri_proxy := nil; g_socket_accept := nil; g_socket_address_enumerator_get_type := nil; g_socket_address_enumerator_next := nil; g_socket_address_enumerator_next_async := nil; g_socket_address_enumerator_next_finish := nil; g_socket_address_get_family := nil; g_socket_address_get_native_size := nil; g_socket_address_get_type := nil; g_socket_address_new_from_native := nil; g_socket_address_to_native := nil; g_socket_bind := nil; g_socket_check_connect_result := nil; g_socket_client_add_application_proxy := nil; g_socket_client_connect := nil; g_socket_client_connect_async := nil; g_socket_client_connect_finish := nil; g_socket_client_connect_to_host := nil; g_socket_client_connect_to_host_async := nil; g_socket_client_connect_to_host_finish := nil; g_socket_client_connect_to_service := nil; g_socket_client_connect_to_service_async := nil; g_socket_client_connect_to_service_finish := nil; g_socket_client_connect_to_uri := nil; g_socket_client_connect_to_uri_async := nil; g_socket_client_connect_to_uri_finish := nil; g_socket_client_get_enable_proxy := nil; g_socket_client_get_family := nil; g_socket_client_get_local_address := nil; g_socket_client_get_protocol := nil; g_socket_client_get_proxy_resolver := nil; g_socket_client_get_socket_type := nil; g_socket_client_get_timeout := nil; g_socket_client_get_tls := nil; g_socket_client_get_tls_validation_flags := nil; g_socket_client_get_type := nil; g_socket_client_new := nil; g_socket_client_set_enable_proxy := nil; g_socket_client_set_family := nil; g_socket_client_set_local_address := nil; g_socket_client_set_protocol := nil; g_socket_client_set_proxy_resolver := nil; g_socket_client_set_socket_type := nil; g_socket_client_set_timeout := nil; g_socket_client_set_tls := nil; g_socket_client_set_tls_validation_flags := nil; g_socket_close := nil; g_socket_condition_check := nil; g_socket_condition_timed_wait := nil; g_socket_condition_wait := nil; g_socket_connect := nil; g_socket_connectable_enumerate := nil; g_socket_connectable_get_type := nil; g_socket_connectable_proxy_enumerate := nil; g_socket_connection_connect := nil; g_socket_connection_connect_async := nil; g_socket_connection_connect_finish := nil; g_socket_connection_factory_create_connection := nil; g_socket_connection_factory_lookup_type := nil; g_socket_connection_factory_register_type := nil; g_socket_connection_get_local_address := nil; g_socket_connection_get_remote_address := nil; g_socket_connection_get_socket := nil; g_socket_connection_get_type := nil; g_socket_connection_is_connected := nil; g_socket_control_message_deserialize := nil; g_socket_control_message_get_level := nil; g_socket_control_message_get_msg_type := nil; g_socket_control_message_get_size := nil; g_socket_control_message_get_type := nil; g_socket_control_message_serialize := nil; g_socket_create_source := nil; g_socket_get_available_bytes := nil; g_socket_get_blocking := nil; g_socket_get_broadcast := nil; g_socket_get_credentials := nil; g_socket_get_family := nil; g_socket_get_fd := nil; g_socket_get_keepalive := nil; g_socket_get_listen_backlog := nil; g_socket_get_local_address := nil; g_socket_get_multicast_loopback := nil; g_socket_get_multicast_ttl := nil; g_socket_get_option := nil; g_socket_get_protocol := nil; g_socket_get_remote_address := nil; g_socket_get_socket_type := nil; g_socket_get_timeout := nil; g_socket_get_ttl := nil; g_socket_get_type := nil; g_socket_is_closed := nil; g_socket_is_connected := nil; g_socket_join_multicast_group := nil; g_socket_leave_multicast_group := nil; g_socket_listen := nil; g_socket_listener_accept := nil; g_socket_listener_accept_async := nil; g_socket_listener_accept_finish := nil; g_socket_listener_accept_socket := nil; g_socket_listener_accept_socket_async := nil; g_socket_listener_accept_socket_finish := nil; g_socket_listener_add_address := nil; g_socket_listener_add_any_inet_port := nil; g_socket_listener_add_inet_port := nil; g_socket_listener_add_socket := nil; g_socket_listener_close := nil; g_socket_listener_get_type := nil; g_socket_listener_new := nil; g_socket_listener_set_backlog := nil; g_socket_new := nil; g_socket_new_from_fd := nil; g_socket_receive := nil; g_socket_receive_from := nil; g_socket_receive_message := nil; g_socket_receive_with_blocking := nil; g_socket_send := nil; g_socket_send_message := nil; g_socket_send_to := nil; g_socket_send_with_blocking := nil; g_socket_service_get_type := nil; g_socket_service_is_active := nil; g_socket_service_new := nil; g_socket_service_start := nil; g_socket_service_stop := nil; g_socket_set_blocking := nil; g_socket_set_broadcast := nil; g_socket_set_keepalive := nil; g_socket_set_listen_backlog := nil; g_socket_set_multicast_loopback := nil; g_socket_set_multicast_ttl := nil; g_socket_set_option := nil; g_socket_set_timeout := nil; g_socket_set_ttl := nil; g_socket_shutdown := nil; g_socket_speaks_ipv4 := nil; g_srv_target_copy := nil; g_srv_target_free := nil; g_srv_target_get_hostname := nil; g_srv_target_get_port := nil; g_srv_target_get_priority := nil; g_srv_target_get_type := nil; g_srv_target_get_weight := nil; g_srv_target_list_sort := nil; g_srv_target_new := nil; g_static_resource_fini := nil; g_static_resource_get_resource := nil; g_static_resource_init := nil; g_task_attach_source := nil; g_task_get_cancellable := nil; g_task_get_check_cancellable := nil; g_task_get_context := nil; g_task_get_priority := nil; g_task_get_return_on_cancel := nil; g_task_get_source_object := nil; g_task_get_source_tag := nil; g_task_get_task_data := nil; g_task_get_type := nil; g_task_had_error := nil; g_task_is_valid := nil; g_task_new := nil; g_task_propagate_boolean := nil; g_task_propagate_int := nil; g_task_propagate_pointer := nil; g_task_report_error := nil; g_task_report_new_error := nil; g_task_return_boolean := nil; g_task_return_error := nil; g_task_return_error_if_cancelled := nil; g_task_return_int := nil; g_task_return_new_error := nil; g_task_return_pointer := nil; g_task_run_in_thread := nil; g_task_run_in_thread_sync := nil; g_task_set_check_cancellable := nil; g_task_set_priority := nil; g_task_set_return_on_cancel := nil; g_task_set_source_tag := nil; g_task_set_task_data := nil; g_tcp_connection_get_graceful_disconnect := nil; g_tcp_connection_get_type := nil; g_tcp_connection_set_graceful_disconnect := nil; g_tcp_wrapper_connection_get_base_io_stream := nil; g_tcp_wrapper_connection_get_type := nil; g_tcp_wrapper_connection_new := nil; g_test_dbus_add_service_dir := nil; g_test_dbus_down := nil; g_test_dbus_get_bus_address := nil; g_test_dbus_get_flags := nil; g_test_dbus_get_type := nil; g_test_dbus_new := nil; g_test_dbus_stop := nil; g_test_dbus_unset := nil; g_test_dbus_up := nil; g_themed_icon_append_name := nil; g_themed_icon_get_names := nil; g_themed_icon_get_type := nil; g_themed_icon_new := nil; g_themed_icon_new_from_names := nil; g_themed_icon_new_with_default_fallbacks := nil; g_themed_icon_prepend_name := nil; g_threaded_socket_service_get_type := nil; g_threaded_socket_service_new := nil; g_tls_backend_get_certificate_type := nil; g_tls_backend_get_client_connection_type := nil; g_tls_backend_get_default := nil; g_tls_backend_get_default_database := nil; g_tls_backend_get_file_database_type := nil; g_tls_backend_get_server_connection_type := nil; g_tls_backend_get_type := nil; g_tls_backend_supports_tls := nil; g_tls_certificate_get_issuer := nil; g_tls_certificate_get_type := nil; g_tls_certificate_is_same := nil; g_tls_certificate_list_new_from_file := nil; g_tls_certificate_new_from_file := nil; g_tls_certificate_new_from_files := nil; g_tls_certificate_new_from_pem := nil; g_tls_certificate_verify := nil; g_tls_client_connection_get_accepted_cas := nil; g_tls_client_connection_get_server_identity := nil; g_tls_client_connection_get_type := nil; g_tls_client_connection_get_use_ssl3 := nil; g_tls_client_connection_get_validation_flags := nil; g_tls_client_connection_new := nil; g_tls_client_connection_set_server_identity := nil; g_tls_client_connection_set_use_ssl3 := nil; g_tls_client_connection_set_validation_flags := nil; g_tls_connection_emit_accept_certificate := nil; g_tls_connection_get_certificate := nil; g_tls_connection_get_database := nil; g_tls_connection_get_interaction := nil; g_tls_connection_get_peer_certificate := nil; g_tls_connection_get_peer_certificate_errors := nil; g_tls_connection_get_rehandshake_mode := nil; g_tls_connection_get_require_close_notify := nil; g_tls_connection_get_type := nil; g_tls_connection_handshake := nil; g_tls_connection_handshake_async := nil; g_tls_connection_handshake_finish := nil; g_tls_connection_set_certificate := nil; g_tls_connection_set_database := nil; g_tls_connection_set_interaction := nil; g_tls_connection_set_rehandshake_mode := nil; g_tls_connection_set_require_close_notify := nil; g_tls_database_create_certificate_handle := nil; g_tls_database_get_type := nil; g_tls_database_lookup_certificate_for_handle := nil; g_tls_database_lookup_certificate_for_handle_async := nil; g_tls_database_lookup_certificate_for_handle_finish := nil; g_tls_database_lookup_certificate_issuer := nil; g_tls_database_lookup_certificate_issuer_async := nil; g_tls_database_lookup_certificate_issuer_finish := nil; g_tls_database_lookup_certificates_issued_by := nil; g_tls_database_lookup_certificates_issued_by_async := nil; g_tls_database_lookup_certificates_issued_by_finish := nil; g_tls_database_verify_chain := nil; g_tls_database_verify_chain_async := nil; g_tls_database_verify_chain_finish := nil; g_tls_error_quark := nil; g_tls_file_database_get_type := nil; g_tls_file_database_new := nil; g_tls_interaction_ask_password := nil; g_tls_interaction_ask_password_async := nil; g_tls_interaction_ask_password_finish := nil; g_tls_interaction_get_type := nil; g_tls_interaction_invoke_ask_password := nil; g_tls_password_get_description := nil; g_tls_password_get_flags := nil; g_tls_password_get_type := nil; g_tls_password_get_value := nil; g_tls_password_get_warning := nil; g_tls_password_new := nil; g_tls_password_set_description := nil; g_tls_password_set_flags := nil; g_tls_password_set_value := nil; g_tls_password_set_value_full := nil; g_tls_password_set_warning := nil; g_tls_server_connection_get_type := nil; g_tls_server_connection_new := nil; g_unix_connection_get_type := nil; g_unix_connection_receive_credentials := nil; g_unix_connection_receive_credentials_async := nil; g_unix_connection_receive_credentials_finish := nil; g_unix_connection_receive_fd := nil; g_unix_connection_send_credentials := nil; g_unix_connection_send_credentials_async := nil; g_unix_connection_send_credentials_finish := nil; g_unix_connection_send_fd := nil; g_unix_credentials_message_get_credentials := nil; g_unix_credentials_message_get_type := nil; g_unix_credentials_message_is_supported := nil; g_unix_credentials_message_new := nil; g_unix_credentials_message_new_with_credentials := nil; g_unix_fd_list_append := nil; g_unix_fd_list_get := nil; g_unix_fd_list_get_length := nil; g_unix_fd_list_get_type := nil; g_unix_fd_list_new := nil; g_unix_fd_list_new_from_array := nil; g_unix_fd_list_peek_fds := nil; g_unix_fd_list_steal_fds := nil; g_unix_fd_message_append_fd := nil; g_unix_fd_message_get_fd_list := nil; g_unix_fd_message_get_type := nil; g_unix_fd_message_new := nil; g_unix_fd_message_new_with_fd_list := nil; g_unix_fd_message_steal_fds := nil; g_unix_input_stream_get_close_fd := nil; g_unix_input_stream_get_fd := nil; g_unix_input_stream_get_type := nil; g_unix_input_stream_new := nil; g_unix_input_stream_set_close_fd := nil; g_unix_is_mount_path_system_internal := nil; g_unix_mount_at := nil; g_unix_mount_compare := nil; g_unix_mount_free := nil; g_unix_mount_get_device_path := nil; g_unix_mount_get_fs_type := nil; g_unix_mount_get_mount_path := nil; g_unix_mount_guess_can_eject := nil; g_unix_mount_guess_icon := nil; g_unix_mount_guess_name := nil; g_unix_mount_guess_should_display := nil; g_unix_mount_guess_symbolic_icon := nil; g_unix_mount_is_readonly := nil; g_unix_mount_is_system_internal := nil; g_unix_mount_monitor_get_type := nil; g_unix_mount_monitor_new := nil; g_unix_mount_monitor_set_rate_limit := nil; g_unix_mount_point_compare := nil; g_unix_mount_point_free := nil; g_unix_mount_point_get_device_path := nil; g_unix_mount_point_get_fs_type := nil; g_unix_mount_point_get_mount_path := nil; g_unix_mount_point_get_options := nil; g_unix_mount_point_guess_can_eject := nil; g_unix_mount_point_guess_icon := nil; g_unix_mount_point_guess_name := nil; g_unix_mount_point_guess_symbolic_icon := nil; g_unix_mount_point_is_loopback := nil; g_unix_mount_point_is_readonly := nil; g_unix_mount_point_is_user_mountable := nil; g_unix_mount_points_changed_since := nil; g_unix_mount_points_get := nil; g_unix_mounts_changed_since := nil; g_unix_mounts_get := nil; g_unix_output_stream_get_close_fd := nil; g_unix_output_stream_get_fd := nil; g_unix_output_stream_get_type := nil; g_unix_output_stream_new := nil; g_unix_output_stream_set_close_fd := nil; g_unix_socket_address_abstract_names_supported := nil; g_unix_socket_address_get_address_type := nil; g_unix_socket_address_get_path := nil; g_unix_socket_address_get_path_len := nil; g_unix_socket_address_get_type := nil; g_unix_socket_address_new := nil; g_unix_socket_address_new_with_type := nil; g_vfs_get_default := nil; g_vfs_get_file_for_path := nil; g_vfs_get_file_for_uri := nil; g_vfs_get_local := nil; g_vfs_get_supported_uri_schemes := nil; g_vfs_get_type := nil; g_vfs_is_active := nil; g_vfs_parse_name := nil; g_volume_can_eject := nil; g_volume_can_mount := nil; g_volume_eject_with_operation := nil; g_volume_eject_with_operation_finish := nil; g_volume_enumerate_identifiers := nil; g_volume_get_activation_root := nil; g_volume_get_drive := nil; g_volume_get_icon := nil; g_volume_get_identifier := nil; g_volume_get_mount := nil; g_volume_get_name := nil; g_volume_get_sort_key := nil; g_volume_get_symbolic_icon := nil; g_volume_get_type := nil; g_volume_get_uuid := nil; g_volume_monitor_get := nil; g_volume_monitor_get_connected_drives := nil; g_volume_monitor_get_mount_for_uuid := nil; g_volume_monitor_get_mounts := nil; g_volume_monitor_get_type := nil; g_volume_monitor_get_volume_for_uuid := nil; g_volume_monitor_get_volumes := nil; g_volume_mount := nil; g_volume_mount_finish := nil; g_volume_should_automount := nil; g_zlib_compressor_get_file_info := nil; g_zlib_compressor_get_type := nil; g_zlib_compressor_new := nil; g_zlib_compressor_set_file_info := nil; g_zlib_decompressor_get_file_info := nil; g_zlib_decompressor_get_type := nil; g_zlib_decompressor_new := nil; end; initialization LoadLibraries; LoadProcs; finalization UnloadLibraries; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/glib/uglib2.pas��������������������������������������������������0000644�0001750�0000144�00000605615�14743153644�021027� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an autogenerated unit using gobject introspection (gir2pascal). Do not Edit. } unit uGLib2; {$MODE OBJFPC}{$H+} {$PACKRECORDS C} {$MODESWITCH DUPLICATELOCALS+} {$LINKLIB libglib-2.0.so.0} {$LINKLIB libgobject-2.0.so.0} interface uses CTypes; const GLib2_library = 'libglib-2.0.so.0'; ASCII_DTOSTR_BUF_SIZE = 39; BIG_ENDIAN = 4321; CAN_INLINE = 1; CSET_A_2_Z_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; CSET_DIGITS = '0123456789'; CSET_a_2_z_lower = 'abcdefghijklmnopqrstuvwxyz'; DATALIST_FLAGS_MASK = 3; DATE_BAD_DAY = 0; DATE_BAD_JULIAN = 0; DATE_BAD_YEAR = 0; DIR_SEPARATOR = 92; DIR_SEPARATOR_S = '\'; E = 2.718282; GINT16_FORMAT = 'hi'; GINT16_MODIFIER = 'h'; GINT32_FORMAT = 'i'; GINT32_MODIFIER = ''; GINT64_FORMAT = 'li'; GINT64_MODIFIER = 'l'; GINTPTR_FORMAT = 'li'; GINTPTR_MODIFIER = 'l'; GNUC_FUNCTION = ''; GNUC_PRETTY_FUNCTION = ''; GSIZE_FORMAT = 'lu'; GSIZE_MODIFIER = 'l'; GSSIZE_FORMAT = 'li'; GUINT16_FORMAT = 'hu'; GUINT32_FORMAT = 'u'; GUINT64_FORMAT = 'lu'; GUINTPTR_FORMAT = 'lu'; HAVE_GINT64 = 1; HAVE_GNUC_VARARGS = 1; HAVE_GNUC_VISIBILITY = 1; HAVE_GROWING_STACK = 1; HAVE_INLINE = 1; HAVE_ISO_VARARGS = 1; HAVE___INLINE = 1; HAVE___INLINE__ = 1; HOOK_FLAG_USER_SHIFT = 4; IEEE754_DOUBLE_BIAS = 1023; IEEE754_FLOAT_BIAS = 127; KEY_FILE_DESKTOP_GROUP = 'Desktop Entry'; KEY_FILE_DESKTOP_KEY_CATEGORIES = 'Categories'; KEY_FILE_DESKTOP_KEY_COMMENT = 'Comment'; KEY_FILE_DESKTOP_KEY_EXEC = 'Exec'; KEY_FILE_DESKTOP_KEY_FULLNAME = 'X-GNOME-FullName'; KEY_FILE_DESKTOP_KEY_GENERIC_NAME = 'GenericName'; KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN = 'X-GNOME-Gettext-Domain'; KEY_FILE_DESKTOP_KEY_HIDDEN = 'Hidden'; KEY_FILE_DESKTOP_KEY_ICON = 'Icon'; KEY_FILE_DESKTOP_KEY_KEYWORDS = 'Keywords'; KEY_FILE_DESKTOP_KEY_MIME_TYPE = 'MimeType'; KEY_FILE_DESKTOP_KEY_NAME = 'Name'; KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN = 'NotShowIn'; KEY_FILE_DESKTOP_KEY_NO_DISPLAY = 'NoDisplay'; KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN = 'OnlyShowIn'; KEY_FILE_DESKTOP_KEY_PATH = 'Path'; KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY = 'StartupNotify'; KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS = 'StartupWMClass'; KEY_FILE_DESKTOP_KEY_TERMINAL = 'Terminal'; KEY_FILE_DESKTOP_KEY_TRY_EXEC = 'TryExec'; KEY_FILE_DESKTOP_KEY_TYPE = 'Type'; KEY_FILE_DESKTOP_KEY_URL = 'URL'; KEY_FILE_DESKTOP_KEY_VERSION = 'Version'; KEY_FILE_DESKTOP_TYPE_APPLICATION = 'Application'; KEY_FILE_DESKTOP_TYPE_DIRECTORY = 'Directory'; KEY_FILE_DESKTOP_TYPE_LINK = 'Link'; LITTLE_ENDIAN = 1234; LN10 = 2.302585; LN2 = 0.693147; LOG_2_BASE_10 = 0.301030; LOG_DOMAIN = 0; LOG_FATAL_MASK = 0; LOG_LEVEL_USER_SHIFT = 8; MAJOR_VERSION = 2; MAXINT16 = 32767; MAXINT32 = 2147483647; MAXINT64 = 9223372036854775807; MAXINT8 = 127; MAXUINT16 = 65535; MAXUINT32 = 4294967295; MAXUINT64 = 18446744073709551615; MAXUINT8 = 255; MICRO_VERSION = 1; MININT16 = 32768; MININT32 = 2147483648; MININT64 = -9223372036854775808; MININT8 = 128; MINOR_VERSION = 36; MODULE_SUFFIX = 'so'; OPTION_REMAINING = ''; PDP_ENDIAN = 3412; PI = 3.141593; PI_2 = 1.570796; PI_4 = 0.785398; POLLFD_FORMAT = '%#I64x'; PRIORITY_DEFAULT = 0; PRIORITY_DEFAULT_IDLE = 200; PRIORITY_HIGH = -100; PRIORITY_HIGH_IDLE = 100; PRIORITY_LOW = 300; SEARCHPATH_SEPARATOR = 59; SEARCHPATH_SEPARATOR_S = ';'; SIZEOF_LONG = 8; SIZEOF_SIZE_T = 8; SIZEOF_VOID_P = 8; SQRT2 = 1.414214; STR_DELIMITERS = '_-|> <.'; SYSDEF_AF_INET = 2; SYSDEF_AF_INET6 = 10; SYSDEF_AF_UNIX = 1; SYSDEF_MSG_DONTROUTE = 4; SYSDEF_MSG_OOB = 1; SYSDEF_MSG_PEEK = 2; TIME_SPAN_DAY = 86400000000; TIME_SPAN_HOUR = 3600000000; TIME_SPAN_MILLISECOND = 1000; TIME_SPAN_MINUTE = 60000000; TIME_SPAN_SECOND = 1000000; UNICHAR_MAX_DECOMPOSITION_LENGTH = 18; URI_RESERVED_CHARS_GENERIC_DELIMITERS = ':/?#[]@'; URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS = '!$&''()*+,;='; USEC_PER_SEC = 1000000; VA_COPY_AS_ARRAY = 1; VERSION_MIN_REQUIRED = 2; WIN32_MSG_HANDLE = 19981206; type TGAsciiType = Integer; const { GAsciiType } G_ASCII_ALNUM: TGAsciiType = 1; G_ASCII_ALPHA: TGAsciiType = 2; G_ASCII_CNTRL: TGAsciiType = 4; G_ASCII_DIGIT: TGAsciiType = 8; G_ASCII_GRAPH: TGAsciiType = 16; G_ASCII_LOWER: TGAsciiType = 32; G_ASCII_PRINT: TGAsciiType = 64; G_ASCII_PUNCT: TGAsciiType = 128; G_ASCII_SPACE: TGAsciiType = 256; G_ASCII_UPPER: TGAsciiType = 512; G_ASCII_XDIGIT: TGAsciiType = 1024; type TGBookmarkFileError = Integer; const { GBookmarkFileError } G_BOOKMARK_FILE_ERROR_INVALID_URI: TGBookmarkFileError = 0; G_BOOKMARK_FILE_ERROR_INVALID_VALUE: TGBookmarkFileError = 1; G_BOOKMARK_FILE_ERROR_APP_NOT_REGISTERED: TGBookmarkFileError = 2; G_BOOKMARK_FILE_ERROR_URI_NOT_FOUND: TGBookmarkFileError = 3; G_BOOKMARK_FILE_ERROR_READ: TGBookmarkFileError = 4; G_BOOKMARK_FILE_ERROR_UNKNOWN_ENCODING: TGBookmarkFileError = 5; G_BOOKMARK_FILE_ERROR_WRITE: TGBookmarkFileError = 6; G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND: TGBookmarkFileError = 7; type TGChecksumType = Integer; const { GChecksumType } G_CHECKSUM_MD5: TGChecksumType = 0; G_CHECKSUM_SHA1: TGChecksumType = 1; G_CHECKSUM_SHA256: TGChecksumType = 2; G_CHECKSUM_SHA512: TGChecksumType = 3; type TGConvertError = Integer; const { GConvertError } G_CONVERT_ERROR_NO_CONVERSION: TGConvertError = 0; G_CONVERT_ERROR_ILLEGAL_SEQUENCE: TGConvertError = 1; G_CONVERT_ERROR_FAILED: TGConvertError = 2; G_CONVERT_ERROR_PARTIAL_INPUT: TGConvertError = 3; G_CONVERT_ERROR_BAD_URI: TGConvertError = 4; G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: TGConvertError = 5; type TGDateMonth = Integer; const { GDateMonth } G_DATE_BAD_MONTH: TGDateMonth = 0; G_DATE_JANUARY: TGDateMonth = 1; G_DATE_FEBRUARY: TGDateMonth = 2; G_DATE_MARCH: TGDateMonth = 3; G_DATE_APRIL: TGDateMonth = 4; G_DATE_MAY: TGDateMonth = 5; G_DATE_JUNE: TGDateMonth = 6; G_DATE_JULY: TGDateMonth = 7; G_DATE_AUGUST: TGDateMonth = 8; G_DATE_SEPTEMBER: TGDateMonth = 9; G_DATE_OCTOBER: TGDateMonth = 10; G_DATE_NOVEMBER: TGDateMonth = 11; G_DATE_DECEMBER: TGDateMonth = 12; type TGDateWeekday = Integer; const { GDateWeekday } G_DATE_BAD_WEEKDAY: TGDateWeekday = 0; G_DATE_MONDAY: TGDateWeekday = 1; G_DATE_TUESDAY: TGDateWeekday = 2; G_DATE_WEDNESDAY: TGDateWeekday = 3; G_DATE_THURSDAY: TGDateWeekday = 4; G_DATE_FRIDAY: TGDateWeekday = 5; G_DATE_SATURDAY: TGDateWeekday = 6; G_DATE_SUNDAY: TGDateWeekday = 7; type TGDateDMY = Integer; const { GDateDMY } G_DATE_DAY: TGDateDMY = 0; G_DATE_MONTH: TGDateDMY = 1; G_DATE_YEAR: TGDateDMY = 2; type TGTimeType = Integer; const { GTimeType } G_TIME_TYPE_STANDARD: TGTimeType = 0; G_TIME_TYPE_DAYLIGHT: TGTimeType = 1; G_TIME_TYPE_UNIVERSAL: TGTimeType = 2; type TGErrorType = Integer; const { GErrorType } G_ERR_UNKNOWN: TGErrorType = 0; G_ERR_UNEXP_EOF: TGErrorType = 1; G_ERR_UNEXP_EOF_IN_STRING: TGErrorType = 2; G_ERR_UNEXP_EOF_IN_COMMENT: TGErrorType = 3; G_ERR_NON_DIGIT_IN_CONST: TGErrorType = 4; G_ERR_DIGIT_RADIX: TGErrorType = 5; G_ERR_FLOAT_RADIX: TGErrorType = 6; G_ERR_FLOAT_MALFORMED: TGErrorType = 7; type TGFileError = Integer; const { GFileError } G_FILE_ERROR_EXIST: TGFileError = 0; G_FILE_ERROR_ISDIR: TGFileError = 1; G_FILE_ERROR_ACCES: TGFileError = 2; G_FILE_ERROR_NAMETOOLONG: TGFileError = 3; G_FILE_ERROR_NOENT: TGFileError = 4; G_FILE_ERROR_NOTDIR: TGFileError = 5; G_FILE_ERROR_NXIO: TGFileError = 6; G_FILE_ERROR_NODEV: TGFileError = 7; G_FILE_ERROR_ROFS: TGFileError = 8; G_FILE_ERROR_TXTBSY: TGFileError = 9; G_FILE_ERROR_FAULT: TGFileError = 10; G_FILE_ERROR_LOOP: TGFileError = 11; G_FILE_ERROR_NOSPC: TGFileError = 12; G_FILE_ERROR_NOMEM: TGFileError = 13; G_FILE_ERROR_MFILE: TGFileError = 14; G_FILE_ERROR_NFILE: TGFileError = 15; G_FILE_ERROR_BADF: TGFileError = 16; G_FILE_ERROR_INVAL: TGFileError = 17; G_FILE_ERROR_PIPE: TGFileError = 18; G_FILE_ERROR_AGAIN: TGFileError = 19; G_FILE_ERROR_INTR: TGFileError = 20; G_FILE_ERROR_IO: TGFileError = 21; G_FILE_ERROR_PERM: TGFileError = 22; G_FILE_ERROR_NOSYS: TGFileError = 23; G_FILE_ERROR_FAILED: TGFileError = 24; type TGFileTest = Integer; const { GFileTest } G_FILE_TEST_IS_REGULAR: TGFileTest = 1; G_FILE_TEST_IS_SYMLINK: TGFileTest = 2; G_FILE_TEST_IS_DIR: TGFileTest = 4; G_FILE_TEST_IS_EXECUTABLE: TGFileTest = 8; G_FILE_TEST_EXISTS: TGFileTest = 16; type TGFormatSizeFlags = Integer; const { GFormatSizeFlags } G_FORMAT_SIZE_DEFAULT: TGFormatSizeFlags = 0; G_FORMAT_SIZE_LONG_FORMAT: TGFormatSizeFlags = 1; G_FORMAT_SIZE_IEC_UNITS: TGFormatSizeFlags = 2; type TGHookFlagMask = Integer; const { GHookFlagMask } G_HOOK_FLAG_ACTIVE: TGHookFlagMask = 1; G_HOOK_FLAG_IN_CALL: TGHookFlagMask = 2; G_HOOK_FLAG_MASK: TGHookFlagMask = 15; type TGSeekType = Integer; const { GSeekType } G_SEEK_CUR: TGSeekType = 0; G_SEEK_SET: TGSeekType = 1; G_SEEK_END: TGSeekType = 2; type TGIOCondition = Integer; const { GIOCondition } G_IO_IN: TGIOCondition = 1; G_IO_OUT: TGIOCondition = 4; G_IO_PRI: TGIOCondition = 2; G_IO_ERR: TGIOCondition = 8; G_IO_HUP: TGIOCondition = 16; G_IO_NVAL: TGIOCondition = 32; type TGIOFlags = Integer; const { GIOFlags } G_IO_FLAG_APPEND: TGIOFlags = 1; G_IO_FLAG_NONBLOCK: TGIOFlags = 2; G_IO_FLAG_IS_READABLE: TGIOFlags = 4; G_IO_FLAG_IS_WRITABLE: TGIOFlags = 8; G_IO_FLAG_IS_WRITEABLE: TGIOFlags = 8; G_IO_FLAG_IS_SEEKABLE: TGIOFlags = 16; G_IO_FLAG_MASK: TGIOFlags = 31; G_IO_FLAG_GET_MASK: TGIOFlags = 31; G_IO_FLAG_SET_MASK: TGIOFlags = 3; type TGIOStatus = Integer; const { GIOStatus } G_IO_STATUS_ERROR: TGIOStatus = 0; G_IO_STATUS_NORMAL: TGIOStatus = 1; G_IO_STATUS_EOF: TGIOStatus = 2; G_IO_STATUS_AGAIN: TGIOStatus = 3; type TGIOError = Integer; const { GIOError } G_IO_ERROR_NONE: TGIOError = 0; G_IO_ERROR_AGAIN: TGIOError = 1; G_IO_ERROR_INVAL: TGIOError = 2; G_IO_ERROR_UNKNOWN: TGIOError = 3; type TGIOChannelError = Integer; const { GIOChannelError } G_IO_CHANNEL_ERROR_FBIG: TGIOChannelError = 0; G_IO_CHANNEL_ERROR_INVAL: TGIOChannelError = 1; G_IO_CHANNEL_ERROR_IO: TGIOChannelError = 2; G_IO_CHANNEL_ERROR_ISDIR: TGIOChannelError = 3; G_IO_CHANNEL_ERROR_NOSPC: TGIOChannelError = 4; G_IO_CHANNEL_ERROR_NXIO: TGIOChannelError = 5; G_IO_CHANNEL_ERROR_OVERFLOW: TGIOChannelError = 6; G_IO_CHANNEL_ERROR_PIPE: TGIOChannelError = 7; G_IO_CHANNEL_ERROR_FAILED: TGIOChannelError = 8; type TGKeyFileFlags = Integer; const { GKeyFileFlags } G_KEY_FILE_NONE: TGKeyFileFlags = 0; G_KEY_FILE_KEEP_COMMENTS: TGKeyFileFlags = 1; G_KEY_FILE_KEEP_TRANSLATIONS: TGKeyFileFlags = 2; type TGKeyFileError = Integer; const { GKeyFileError } G_KEY_FILE_ERROR_UNKNOWN_ENCODING: TGKeyFileError = 0; G_KEY_FILE_ERROR_PARSE: TGKeyFileError = 1; G_KEY_FILE_ERROR_NOT_FOUND: TGKeyFileError = 2; G_KEY_FILE_ERROR_KEY_NOT_FOUND: TGKeyFileError = 3; G_KEY_FILE_ERROR_GROUP_NOT_FOUND: TGKeyFileError = 4; G_KEY_FILE_ERROR_INVALID_VALUE: TGKeyFileError = 5; type TGLogLevelFlags = Integer; const { GLogLevelFlags } G_LOG_FLAG_RECURSION: TGLogLevelFlags = 1; G_LOG_FLAG_FATAL: TGLogLevelFlags = 2; G_LOG_LEVEL_ERROR: TGLogLevelFlags = 4; G_LOG_LEVEL_CRITICAL: TGLogLevelFlags = 8; G_LOG_LEVEL_WARNING: TGLogLevelFlags = 16; G_LOG_LEVEL_MESSAGE: TGLogLevelFlags = 32; G_LOG_LEVEL_INFO: TGLogLevelFlags = 64; G_LOG_LEVEL_DEBUG: TGLogLevelFlags = 128; G_LOG_LEVEL_MASK: TGLogLevelFlags = -4; type TGMarkupCollectType = Integer; const { GMarkupCollectType } G_MARKUP_COLLECT_INVALID: TGMarkupCollectType = 0; G_MARKUP_COLLECT_STRING: TGMarkupCollectType = 1; G_MARKUP_COLLECT_STRDUP: TGMarkupCollectType = 2; G_MARKUP_COLLECT_BOOLEAN: TGMarkupCollectType = 3; G_MARKUP_COLLECT_TRISTATE: TGMarkupCollectType = 4; G_MARKUP_COLLECT_OPTIONAL: TGMarkupCollectType = 65536; type TGMarkupError = Integer; const { GMarkupError } G_MARKUP_ERROR_BAD_UTF8: TGMarkupError = 0; G_MARKUP_ERROR_EMPTY: TGMarkupError = 1; G_MARKUP_ERROR_PARSE: TGMarkupError = 2; G_MARKUP_ERROR_UNKNOWN_ELEMENT: TGMarkupError = 3; G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE: TGMarkupError = 4; G_MARKUP_ERROR_INVALID_CONTENT: TGMarkupError = 5; G_MARKUP_ERROR_MISSING_ATTRIBUTE: TGMarkupError = 6; type TGMarkupParseFlags = Integer; const { GMarkupParseFlags } G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG: TGMarkupParseFlags = 1; G_MARKUP_TREAT_CDATA_AS_TEXT: TGMarkupParseFlags = 2; G_MARKUP_PREFIX_ERROR_POSITION: TGMarkupParseFlags = 4; type TGRegexCompileFlags = Integer; const { GRegexCompileFlags } G_REGEX_CASELESS: TGRegexCompileFlags = 1; G_REGEX_MULTILINE: TGRegexCompileFlags = 2; G_REGEX_DOTALL: TGRegexCompileFlags = 4; G_REGEX_EXTENDED: TGRegexCompileFlags = 8; G_REGEX_ANCHORED: TGRegexCompileFlags = 16; G_REGEX_DOLLAR_ENDONLY: TGRegexCompileFlags = 32; G_REGEX_UNGREEDY: TGRegexCompileFlags = 512; G_REGEX_RAW: TGRegexCompileFlags = 2048; G_REGEX_NO_AUTO_CAPTURE: TGRegexCompileFlags = 4096; G_REGEX_OPTIMIZE: TGRegexCompileFlags = 8192; G_REGEX_FIRSTLINE: TGRegexCompileFlags = 262144; G_REGEX_DUPNAMES: TGRegexCompileFlags = 524288; G_REGEX_NEWLINE_CR: TGRegexCompileFlags = 1048576; G_REGEX_NEWLINE_LF: TGRegexCompileFlags = 2097152; G_REGEX_NEWLINE_CRLF: TGRegexCompileFlags = 3145728; G_REGEX_NEWLINE_ANYCRLF: TGRegexCompileFlags = 5242880; G_REGEX_BSR_ANYCRLF: TGRegexCompileFlags = 8388608; G_REGEX_JAVASCRIPT_COMPAT: TGRegexCompileFlags = 33554432; type TGRegexMatchFlags = Integer; const { GRegexMatchFlags } G_REGEX_MATCH_ANCHORED: TGRegexMatchFlags = 16; G_REGEX_MATCH_NOTBOL: TGRegexMatchFlags = 128; G_REGEX_MATCH_NOTEOL: TGRegexMatchFlags = 256; G_REGEX_MATCH_NOTEMPTY: TGRegexMatchFlags = 1024; G_REGEX_MATCH_PARTIAL: TGRegexMatchFlags = 32768; G_REGEX_MATCH_NEWLINE_CR: TGRegexMatchFlags = 1048576; G_REGEX_MATCH_NEWLINE_LF: TGRegexMatchFlags = 2097152; G_REGEX_MATCH_NEWLINE_CRLF: TGRegexMatchFlags = 3145728; G_REGEX_MATCH_NEWLINE_ANY: TGRegexMatchFlags = 4194304; G_REGEX_MATCH_NEWLINE_ANYCRLF: TGRegexMatchFlags = 5242880; G_REGEX_MATCH_BSR_ANYCRLF: TGRegexMatchFlags = 8388608; G_REGEX_MATCH_BSR_ANY: TGRegexMatchFlags = 16777216; G_REGEX_MATCH_PARTIAL_SOFT: TGRegexMatchFlags = 32768; G_REGEX_MATCH_PARTIAL_HARD: TGRegexMatchFlags = 134217728; G_REGEX_MATCH_NOTEMPTY_ATSTART: TGRegexMatchFlags = 268435456; type TGTraverseFlags = Integer; const { GTraverseFlags } G_TRAVERSE_LEAVES: TGTraverseFlags = 1; G_TRAVERSE_NON_LEAVES: TGTraverseFlags = 2; G_TRAVERSE_ALL: TGTraverseFlags = 3; G_TRAVERSE_MASK: TGTraverseFlags = 3; G_TRAVERSE_LEAFS: TGTraverseFlags = 1; G_TRAVERSE_NON_LEAFS: TGTraverseFlags = 2; type TGTraverseType = Integer; const { GTraverseType } G_IN_ORDER: TGTraverseType = 0; G_PRE_ORDER: TGTraverseType = 1; G_POST_ORDER: TGTraverseType = 2; G_LEVEL_ORDER: TGTraverseType = 3; type TGNormalizeMode = Integer; const { GNormalizeMode } G_NORMALIZE_DEFAULT: TGNormalizeMode = 0; G_NORMALIZE_NFD: TGNormalizeMode = 0; G_NORMALIZE_DEFAULT_COMPOSE: TGNormalizeMode = 1; G_NORMALIZE_NFC: TGNormalizeMode = 1; G_NORMALIZE_ALL: TGNormalizeMode = 2; G_NORMALIZE_NFKD: TGNormalizeMode = 2; G_NORMALIZE_ALL_COMPOSE: TGNormalizeMode = 3; G_NORMALIZE_NFKC: TGNormalizeMode = 3; type TGOnceStatus = Integer; const { GOnceStatus } G_ONCE_STATUS_NOTCALLED: TGOnceStatus = 0; G_ONCE_STATUS_PROGRESS: TGOnceStatus = 1; G_ONCE_STATUS_READY: TGOnceStatus = 2; type TGOptionArg = Integer; const { GOptionArg } G_OPTION_ARG_NONE: TGOptionArg = 0; G_OPTION_ARG_STRING: TGOptionArg = 1; G_OPTION_ARG_INT: TGOptionArg = 2; G_OPTION_ARG_CALLBACK: TGOptionArg = 3; G_OPTION_ARG_FILENAME: TGOptionArg = 4; G_OPTION_ARG_STRING_ARRAY: TGOptionArg = 5; G_OPTION_ARG_FILENAME_ARRAY: TGOptionArg = 6; G_OPTION_ARG_DOUBLE: TGOptionArg = 7; G_OPTION_ARG_INT64: TGOptionArg = 8; type TGOptionError = Integer; const { GOptionError } G_OPTION_ERROR_UNKNOWN_OPTION: TGOptionError = 0; G_OPTION_ERROR_BAD_VALUE: TGOptionError = 1; G_OPTION_ERROR_FAILED: TGOptionError = 2; type TGOptionFlags = Integer; const { GOptionFlags } G_OPTION_FLAG_HIDDEN: TGOptionFlags = 1; G_OPTION_FLAG_IN_MAIN: TGOptionFlags = 2; G_OPTION_FLAG_REVERSE: TGOptionFlags = 4; G_OPTION_FLAG_NO_ARG: TGOptionFlags = 8; G_OPTION_FLAG_FILENAME: TGOptionFlags = 16; G_OPTION_FLAG_OPTIONAL_ARG: TGOptionFlags = 32; G_OPTION_FLAG_NOALIAS: TGOptionFlags = 64; type TGRegexError = Integer; const { GRegexError } G_REGEX_ERROR_COMPILE: TGRegexError = 0; G_REGEX_ERROR_OPTIMIZE: TGRegexError = 1; G_REGEX_ERROR_REPLACE: TGRegexError = 2; G_REGEX_ERROR_MATCH: TGRegexError = 3; G_REGEX_ERROR_INTERNAL: TGRegexError = 4; G_REGEX_ERROR_STRAY_BACKSLASH: TGRegexError = 101; G_REGEX_ERROR_MISSING_CONTROL_CHAR: TGRegexError = 102; G_REGEX_ERROR_UNRECOGNIZED_ESCAPE: TGRegexError = 103; G_REGEX_ERROR_QUANTIFIERS_OUT_OF_ORDER: TGRegexError = 104; G_REGEX_ERROR_QUANTIFIER_TOO_BIG: TGRegexError = 105; G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS: TGRegexError = 106; G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS: TGRegexError = 107; G_REGEX_ERROR_RANGE_OUT_OF_ORDER: TGRegexError = 108; G_REGEX_ERROR_NOTHING_TO_REPEAT: TGRegexError = 109; G_REGEX_ERROR_UNRECOGNIZED_CHARACTER: TGRegexError = 112; G_REGEX_ERROR_POSIX_NAMED_CLASS_OUTSIDE_CLASS: TGRegexError = 113; G_REGEX_ERROR_UNMATCHED_PARENTHESIS: TGRegexError = 114; G_REGEX_ERROR_INEXISTENT_SUBPATTERN_REFERENCE: TGRegexError = 115; G_REGEX_ERROR_UNTERMINATED_COMMENT: TGRegexError = 118; G_REGEX_ERROR_EXPRESSION_TOO_LARGE: TGRegexError = 120; G_REGEX_ERROR_MEMORY_ERROR: TGRegexError = 121; G_REGEX_ERROR_VARIABLE_LENGTH_LOOKBEHIND: TGRegexError = 125; G_REGEX_ERROR_MALFORMED_CONDITION: TGRegexError = 126; G_REGEX_ERROR_TOO_MANY_CONDITIONAL_BRANCHES: TGRegexError = 127; G_REGEX_ERROR_ASSERTION_EXPECTED: TGRegexError = 128; G_REGEX_ERROR_UNKNOWN_POSIX_CLASS_NAME: TGRegexError = 130; G_REGEX_ERROR_POSIX_COLLATING_ELEMENTS_NOT_SUPPORTED: TGRegexError = 131; G_REGEX_ERROR_HEX_CODE_TOO_LARGE: TGRegexError = 134; G_REGEX_ERROR_INVALID_CONDITION: TGRegexError = 135; G_REGEX_ERROR_SINGLE_BYTE_MATCH_IN_LOOKBEHIND: TGRegexError = 136; G_REGEX_ERROR_INFINITE_LOOP: TGRegexError = 140; G_REGEX_ERROR_MISSING_SUBPATTERN_NAME_TERMINATOR: TGRegexError = 142; G_REGEX_ERROR_DUPLICATE_SUBPATTERN_NAME: TGRegexError = 143; G_REGEX_ERROR_MALFORMED_PROPERTY: TGRegexError = 146; G_REGEX_ERROR_UNKNOWN_PROPERTY: TGRegexError = 147; G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG: TGRegexError = 148; G_REGEX_ERROR_TOO_MANY_SUBPATTERNS: TGRegexError = 149; G_REGEX_ERROR_INVALID_OCTAL_VALUE: TGRegexError = 151; G_REGEX_ERROR_TOO_MANY_BRANCHES_IN_DEFINE: TGRegexError = 154; G_REGEX_ERROR_DEFINE_REPETION: TGRegexError = 155; G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS: TGRegexError = 156; G_REGEX_ERROR_MISSING_BACK_REFERENCE: TGRegexError = 157; G_REGEX_ERROR_INVALID_RELATIVE_REFERENCE: TGRegexError = 158; G_REGEX_ERROR_BACKTRACKING_CONTROL_VERB_ARGUMENT_FORBIDDEN: TGRegexError = 159; G_REGEX_ERROR_UNKNOWN_BACKTRACKING_CONTROL_VERB: TGRegexError = 160; G_REGEX_ERROR_NUMBER_TOO_BIG: TGRegexError = 161; G_REGEX_ERROR_MISSING_SUBPATTERN_NAME: TGRegexError = 162; G_REGEX_ERROR_MISSING_DIGIT: TGRegexError = 163; G_REGEX_ERROR_INVALID_DATA_CHARACTER: TGRegexError = 164; G_REGEX_ERROR_EXTRA_SUBPATTERN_NAME: TGRegexError = 165; G_REGEX_ERROR_BACKTRACKING_CONTROL_VERB_ARGUMENT_REQUIRED: TGRegexError = 166; G_REGEX_ERROR_INVALID_CONTROL_CHAR: TGRegexError = 168; G_REGEX_ERROR_MISSING_NAME: TGRegexError = 169; G_REGEX_ERROR_NOT_SUPPORTED_IN_CLASS: TGRegexError = 171; G_REGEX_ERROR_TOO_MANY_FORWARD_REFERENCES: TGRegexError = 172; G_REGEX_ERROR_NAME_TOO_LONG: TGRegexError = 175; G_REGEX_ERROR_CHARACTER_VALUE_TOO_LARGE: TGRegexError = 176; type TGTokenType = Integer; const { GTokenType } G_TOKEN_EOF: TGTokenType = 0; G_TOKEN_LEFT_PAREN: TGTokenType = 40; G_TOKEN_RIGHT_PAREN: TGTokenType = 41; G_TOKEN_LEFT_CURLY: TGTokenType = 123; G_TOKEN_RIGHT_CURLY: TGTokenType = 125; G_TOKEN_LEFT_BRACE: TGTokenType = 91; G_TOKEN_RIGHT_BRACE: TGTokenType = 93; G_TOKEN_EQUAL_SIGN: TGTokenType = 61; G_TOKEN_COMMA: TGTokenType = 44; G_TOKEN_NONE: TGTokenType = 256; G_TOKEN_ERROR: TGTokenType = 257; G_TOKEN_CHAR: TGTokenType = 258; G_TOKEN_BINARY: TGTokenType = 259; G_TOKEN_OCTAL: TGTokenType = 260; G_TOKEN_INT: TGTokenType = 261; G_TOKEN_HEX: TGTokenType = 262; G_TOKEN_FLOAT: TGTokenType = 263; G_TOKEN_STRING: TGTokenType = 264; G_TOKEN_SYMBOL: TGTokenType = 265; G_TOKEN_IDENTIFIER: TGTokenType = 266; G_TOKEN_IDENTIFIER_NULL: TGTokenType = 267; G_TOKEN_COMMENT_SINGLE: TGTokenType = 268; G_TOKEN_COMMENT_MULTI: TGTokenType = 269; type TGShellError = Integer; const { GShellError } G_SHELL_ERROR_BAD_QUOTING: TGShellError = 0; G_SHELL_ERROR_EMPTY_STRING: TGShellError = 1; G_SHELL_ERROR_FAILED: TGShellError = 2; type TGSliceConfig = Integer; const { GSliceConfig } G_SLICE_CONFIG_ALWAYS_MALLOC: TGSliceConfig = 1; G_SLICE_CONFIG_BYPASS_MAGAZINES: TGSliceConfig = 2; G_SLICE_CONFIG_WORKING_SET_MSECS: TGSliceConfig = 3; G_SLICE_CONFIG_COLOR_INCREMENT: TGSliceConfig = 4; G_SLICE_CONFIG_CHUNK_SIZES: TGSliceConfig = 5; G_SLICE_CONFIG_CONTENTION_COUNTER: TGSliceConfig = 6; type TGSpawnError = Integer; const { GSpawnError } G_SPAWN_ERROR_FORK: TGSpawnError = 0; G_SPAWN_ERROR_READ: TGSpawnError = 1; G_SPAWN_ERROR_CHDIR: TGSpawnError = 2; G_SPAWN_ERROR_ACCES: TGSpawnError = 3; G_SPAWN_ERROR_PERM: TGSpawnError = 4; G_SPAWN_ERROR_TOO_BIG: TGSpawnError = 5; G_SPAWN_ERROR_2BIG: TGSpawnError = 5; G_SPAWN_ERROR_NOEXEC: TGSpawnError = 6; G_SPAWN_ERROR_NAMETOOLONG: TGSpawnError = 7; G_SPAWN_ERROR_NOENT: TGSpawnError = 8; G_SPAWN_ERROR_NOMEM: TGSpawnError = 9; G_SPAWN_ERROR_NOTDIR: TGSpawnError = 10; G_SPAWN_ERROR_LOOP: TGSpawnError = 11; G_SPAWN_ERROR_TXTBUSY: TGSpawnError = 12; G_SPAWN_ERROR_IO: TGSpawnError = 13; G_SPAWN_ERROR_NFILE: TGSpawnError = 14; G_SPAWN_ERROR_MFILE: TGSpawnError = 15; G_SPAWN_ERROR_INVAL: TGSpawnError = 16; G_SPAWN_ERROR_ISDIR: TGSpawnError = 17; G_SPAWN_ERROR_LIBBAD: TGSpawnError = 18; G_SPAWN_ERROR_FAILED: TGSpawnError = 19; type TGSpawnFlags = Integer; const { GSpawnFlags } G_SPAWN_LEAVE_DESCRIPTORS_OPEN: TGSpawnFlags = 1; G_SPAWN_DO_NOT_REAP_CHILD: TGSpawnFlags = 2; G_SPAWN_SEARCH_PATH: TGSpawnFlags = 4; G_SPAWN_STDOUT_TO_DEV_NULL: TGSpawnFlags = 8; G_SPAWN_STDERR_TO_DEV_NULL: TGSpawnFlags = 16; G_SPAWN_CHILD_INHERITS_STDIN: TGSpawnFlags = 32; G_SPAWN_FILE_AND_ARGV_ZERO: TGSpawnFlags = 64; G_SPAWN_SEARCH_PATH_FROM_ENVP: TGSpawnFlags = 128; type TGTestLogType = Integer; const { GTestLogType } G_TEST_LOG_NONE: TGTestLogType = 0; G_TEST_LOG_ERROR: TGTestLogType = 1; G_TEST_LOG_START_BINARY: TGTestLogType = 2; G_TEST_LOG_LIST_CASE: TGTestLogType = 3; G_TEST_LOG_SKIP_CASE: TGTestLogType = 4; G_TEST_LOG_START_CASE: TGTestLogType = 5; G_TEST_LOG_STOP_CASE: TGTestLogType = 6; G_TEST_LOG_MIN_RESULT: TGTestLogType = 7; G_TEST_LOG_MAX_RESULT: TGTestLogType = 8; G_TEST_LOG_MESSAGE: TGTestLogType = 9; type TGTestTrapFlags = Integer; const { GTestTrapFlags } G_TEST_TRAP_SILENCE_STDOUT: TGTestTrapFlags = 128; G_TEST_TRAP_SILENCE_STDERR: TGTestTrapFlags = 256; G_TEST_TRAP_INHERIT_STDIN: TGTestTrapFlags = 512; type TGThreadError = Integer; const { GThreadError } G_THREAD_ERROR_AGAIN: TGThreadError = 0; type TGUnicodeBreakType = Integer; const { GUnicodeBreakType } G_UNICODE_BREAK_MANDATORY: TGUnicodeBreakType = 0; G_UNICODE_BREAK_CARRIAGE_RETURN: TGUnicodeBreakType = 1; G_UNICODE_BREAK_LINE_FEED: TGUnicodeBreakType = 2; G_UNICODE_BREAK_COMBINING_MARK: TGUnicodeBreakType = 3; G_UNICODE_BREAK_SURROGATE: TGUnicodeBreakType = 4; G_UNICODE_BREAK_ZERO_WIDTH_SPACE: TGUnicodeBreakType = 5; G_UNICODE_BREAK_INSEPARABLE: TGUnicodeBreakType = 6; G_UNICODE_BREAK_NON_BREAKING_GLUE: TGUnicodeBreakType = 7; G_UNICODE_BREAK_CONTINGENT: TGUnicodeBreakType = 8; G_UNICODE_BREAK_SPACE: TGUnicodeBreakType = 9; G_UNICODE_BREAK_AFTER: TGUnicodeBreakType = 10; G_UNICODE_BREAK_BEFORE: TGUnicodeBreakType = 11; G_UNICODE_BREAK_BEFORE_AND_AFTER: TGUnicodeBreakType = 12; G_UNICODE_BREAK_HYPHEN: TGUnicodeBreakType = 13; G_UNICODE_BREAK_NON_STARTER: TGUnicodeBreakType = 14; G_UNICODE_BREAK_OPEN_PUNCTUATION: TGUnicodeBreakType = 15; G_UNICODE_BREAK_CLOSE_PUNCTUATION: TGUnicodeBreakType = 16; G_UNICODE_BREAK_QUOTATION: TGUnicodeBreakType = 17; G_UNICODE_BREAK_EXCLAMATION: TGUnicodeBreakType = 18; G_UNICODE_BREAK_IDEOGRAPHIC: TGUnicodeBreakType = 19; G_UNICODE_BREAK_NUMERIC: TGUnicodeBreakType = 20; G_UNICODE_BREAK_INFIX_SEPARATOR: TGUnicodeBreakType = 21; G_UNICODE_BREAK_SYMBOL: TGUnicodeBreakType = 22; G_UNICODE_BREAK_ALPHABETIC: TGUnicodeBreakType = 23; G_UNICODE_BREAK_PREFIX: TGUnicodeBreakType = 24; G_UNICODE_BREAK_POSTFIX: TGUnicodeBreakType = 25; G_UNICODE_BREAK_COMPLEX_CONTEXT: TGUnicodeBreakType = 26; G_UNICODE_BREAK_AMBIGUOUS: TGUnicodeBreakType = 27; G_UNICODE_BREAK_UNKNOWN: TGUnicodeBreakType = 28; G_UNICODE_BREAK_NEXT_LINE: TGUnicodeBreakType = 29; G_UNICODE_BREAK_WORD_JOINER: TGUnicodeBreakType = 30; G_UNICODE_BREAK_HANGUL_L_JAMO: TGUnicodeBreakType = 31; G_UNICODE_BREAK_HANGUL_V_JAMO: TGUnicodeBreakType = 32; G_UNICODE_BREAK_HANGUL_T_JAMO: TGUnicodeBreakType = 33; G_UNICODE_BREAK_HANGUL_LV_SYLLABLE: TGUnicodeBreakType = 34; G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE: TGUnicodeBreakType = 35; G_UNICODE_BREAK_CLOSE_PARANTHESIS: TGUnicodeBreakType = 36; G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER: TGUnicodeBreakType = 37; G_UNICODE_BREAK_HEBREW_LETTER: TGUnicodeBreakType = 38; G_UNICODE_BREAK_REGIONAL_INDICATOR: TGUnicodeBreakType = 39; type TGUnicodeScript = Integer; const { GUnicodeScript } G_UNICODE_SCRIPT_INVALID_CODE: TGUnicodeScript = -1; G_UNICODE_SCRIPT_COMMON: TGUnicodeScript = 0; G_UNICODE_SCRIPT_INHERITED: TGUnicodeScript = 1; G_UNICODE_SCRIPT_ARABIC: TGUnicodeScript = 2; G_UNICODE_SCRIPT_ARMENIAN: TGUnicodeScript = 3; G_UNICODE_SCRIPT_BENGALI: TGUnicodeScript = 4; G_UNICODE_SCRIPT_BOPOMOFO: TGUnicodeScript = 5; G_UNICODE_SCRIPT_CHEROKEE: TGUnicodeScript = 6; G_UNICODE_SCRIPT_COPTIC: TGUnicodeScript = 7; G_UNICODE_SCRIPT_CYRILLIC: TGUnicodeScript = 8; G_UNICODE_SCRIPT_DESERET: TGUnicodeScript = 9; G_UNICODE_SCRIPT_DEVANAGARI: TGUnicodeScript = 10; G_UNICODE_SCRIPT_ETHIOPIC: TGUnicodeScript = 11; G_UNICODE_SCRIPT_GEORGIAN: TGUnicodeScript = 12; G_UNICODE_SCRIPT_GOTHIC: TGUnicodeScript = 13; G_UNICODE_SCRIPT_GREEK: TGUnicodeScript = 14; G_UNICODE_SCRIPT_GUJARATI: TGUnicodeScript = 15; G_UNICODE_SCRIPT_GURMUKHI: TGUnicodeScript = 16; G_UNICODE_SCRIPT_HAN: TGUnicodeScript = 17; G_UNICODE_SCRIPT_HANGUL: TGUnicodeScript = 18; G_UNICODE_SCRIPT_HEBREW: TGUnicodeScript = 19; G_UNICODE_SCRIPT_HIRAGANA: TGUnicodeScript = 20; G_UNICODE_SCRIPT_KANNADA: TGUnicodeScript = 21; G_UNICODE_SCRIPT_KATAKANA: TGUnicodeScript = 22; G_UNICODE_SCRIPT_KHMER: TGUnicodeScript = 23; G_UNICODE_SCRIPT_LAO: TGUnicodeScript = 24; G_UNICODE_SCRIPT_LATIN: TGUnicodeScript = 25; G_UNICODE_SCRIPT_MALAYALAM: TGUnicodeScript = 26; G_UNICODE_SCRIPT_MONGOLIAN: TGUnicodeScript = 27; G_UNICODE_SCRIPT_MYANMAR: TGUnicodeScript = 28; G_UNICODE_SCRIPT_OGHAM: TGUnicodeScript = 29; G_UNICODE_SCRIPT_OLD_ITALIC: TGUnicodeScript = 30; G_UNICODE_SCRIPT_ORIYA: TGUnicodeScript = 31; G_UNICODE_SCRIPT_RUNIC: TGUnicodeScript = 32; G_UNICODE_SCRIPT_SINHALA: TGUnicodeScript = 33; G_UNICODE_SCRIPT_SYRIAC: TGUnicodeScript = 34; G_UNICODE_SCRIPT_TAMIL: TGUnicodeScript = 35; G_UNICODE_SCRIPT_TELUGU: TGUnicodeScript = 36; G_UNICODE_SCRIPT_THAANA: TGUnicodeScript = 37; G_UNICODE_SCRIPT_THAI: TGUnicodeScript = 38; G_UNICODE_SCRIPT_TIBETAN: TGUnicodeScript = 39; G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL: TGUnicodeScript = 40; G_UNICODE_SCRIPT_YI: TGUnicodeScript = 41; G_UNICODE_SCRIPT_TAGALOG: TGUnicodeScript = 42; G_UNICODE_SCRIPT_HANUNOO: TGUnicodeScript = 43; G_UNICODE_SCRIPT_BUHID: TGUnicodeScript = 44; G_UNICODE_SCRIPT_TAGBANWA: TGUnicodeScript = 45; G_UNICODE_SCRIPT_BRAILLE: TGUnicodeScript = 46; G_UNICODE_SCRIPT_CYPRIOT: TGUnicodeScript = 47; G_UNICODE_SCRIPT_LIMBU: TGUnicodeScript = 48; G_UNICODE_SCRIPT_OSMANYA: TGUnicodeScript = 49; G_UNICODE_SCRIPT_SHAVIAN: TGUnicodeScript = 50; G_UNICODE_SCRIPT_LINEAR_B: TGUnicodeScript = 51; G_UNICODE_SCRIPT_TAI_LE: TGUnicodeScript = 52; G_UNICODE_SCRIPT_UGARITIC: TGUnicodeScript = 53; G_UNICODE_SCRIPT_NEW_TAI_LUE: TGUnicodeScript = 54; G_UNICODE_SCRIPT_BUGINESE: TGUnicodeScript = 55; G_UNICODE_SCRIPT_GLAGOLITIC: TGUnicodeScript = 56; G_UNICODE_SCRIPT_TIFINAGH: TGUnicodeScript = 57; G_UNICODE_SCRIPT_SYLOTI_NAGRI: TGUnicodeScript = 58; G_UNICODE_SCRIPT_OLD_PERSIAN: TGUnicodeScript = 59; G_UNICODE_SCRIPT_KHAROSHTHI: TGUnicodeScript = 60; G_UNICODE_SCRIPT_UNKNOWN: TGUnicodeScript = 61; G_UNICODE_SCRIPT_BALINESE: TGUnicodeScript = 62; G_UNICODE_SCRIPT_CUNEIFORM: TGUnicodeScript = 63; G_UNICODE_SCRIPT_PHOENICIAN: TGUnicodeScript = 64; G_UNICODE_SCRIPT_PHAGS_PA: TGUnicodeScript = 65; G_UNICODE_SCRIPT_NKO: TGUnicodeScript = 66; G_UNICODE_SCRIPT_KAYAH_LI: TGUnicodeScript = 67; G_UNICODE_SCRIPT_LEPCHA: TGUnicodeScript = 68; G_UNICODE_SCRIPT_REJANG: TGUnicodeScript = 69; G_UNICODE_SCRIPT_SUNDANESE: TGUnicodeScript = 70; G_UNICODE_SCRIPT_SAURASHTRA: TGUnicodeScript = 71; G_UNICODE_SCRIPT_CHAM: TGUnicodeScript = 72; G_UNICODE_SCRIPT_OL_CHIKI: TGUnicodeScript = 73; G_UNICODE_SCRIPT_VAI: TGUnicodeScript = 74; G_UNICODE_SCRIPT_CARIAN: TGUnicodeScript = 75; G_UNICODE_SCRIPT_LYCIAN: TGUnicodeScript = 76; G_UNICODE_SCRIPT_LYDIAN: TGUnicodeScript = 77; G_UNICODE_SCRIPT_AVESTAN: TGUnicodeScript = 78; G_UNICODE_SCRIPT_BAMUM: TGUnicodeScript = 79; G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS: TGUnicodeScript = 80; G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC: TGUnicodeScript = 81; G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI: TGUnicodeScript = 82; G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN: TGUnicodeScript = 83; G_UNICODE_SCRIPT_JAVANESE: TGUnicodeScript = 84; G_UNICODE_SCRIPT_KAITHI: TGUnicodeScript = 85; G_UNICODE_SCRIPT_LISU: TGUnicodeScript = 86; G_UNICODE_SCRIPT_MEETEI_MAYEK: TGUnicodeScript = 87; G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN: TGUnicodeScript = 88; G_UNICODE_SCRIPT_OLD_TURKIC: TGUnicodeScript = 89; G_UNICODE_SCRIPT_SAMARITAN: TGUnicodeScript = 90; G_UNICODE_SCRIPT_TAI_THAM: TGUnicodeScript = 91; G_UNICODE_SCRIPT_TAI_VIET: TGUnicodeScript = 92; G_UNICODE_SCRIPT_BATAK: TGUnicodeScript = 93; G_UNICODE_SCRIPT_BRAHMI: TGUnicodeScript = 94; G_UNICODE_SCRIPT_MANDAIC: TGUnicodeScript = 95; G_UNICODE_SCRIPT_CHAKMA: TGUnicodeScript = 96; G_UNICODE_SCRIPT_MEROITIC_CURSIVE: TGUnicodeScript = 97; G_UNICODE_SCRIPT_MEROITIC_HIEROGLYPHS: TGUnicodeScript = 98; G_UNICODE_SCRIPT_MIAO: TGUnicodeScript = 99; G_UNICODE_SCRIPT_SHARADA: TGUnicodeScript = 100; G_UNICODE_SCRIPT_SORA_SOMPENG: TGUnicodeScript = 101; G_UNICODE_SCRIPT_TAKRI: TGUnicodeScript = 102; type TGUnicodeType = Integer; const { GUnicodeType } G_UNICODE_CONTROL: TGUnicodeType = 0; G_UNICODE_FORMAT: TGUnicodeType = 1; G_UNICODE_UNASSIGNED: TGUnicodeType = 2; G_UNICODE_PRIVATE_USE: TGUnicodeType = 3; G_UNICODE_SURROGATE: TGUnicodeType = 4; G_UNICODE_LOWERCASE_LETTER: TGUnicodeType = 5; G_UNICODE_MODIFIER_LETTER: TGUnicodeType = 6; G_UNICODE_OTHER_LETTER: TGUnicodeType = 7; G_UNICODE_TITLECASE_LETTER: TGUnicodeType = 8; G_UNICODE_UPPERCASE_LETTER: TGUnicodeType = 9; G_UNICODE_SPACING_MARK: TGUnicodeType = 10; G_UNICODE_ENCLOSING_MARK: TGUnicodeType = 11; G_UNICODE_NON_SPACING_MARK: TGUnicodeType = 12; G_UNICODE_DECIMAL_NUMBER: TGUnicodeType = 13; G_UNICODE_LETTER_NUMBER: TGUnicodeType = 14; G_UNICODE_OTHER_NUMBER: TGUnicodeType = 15; G_UNICODE_CONNECT_PUNCTUATION: TGUnicodeType = 16; G_UNICODE_DASH_PUNCTUATION: TGUnicodeType = 17; G_UNICODE_CLOSE_PUNCTUATION: TGUnicodeType = 18; G_UNICODE_FINAL_PUNCTUATION: TGUnicodeType = 19; G_UNICODE_INITIAL_PUNCTUATION: TGUnicodeType = 20; G_UNICODE_OTHER_PUNCTUATION: TGUnicodeType = 21; G_UNICODE_OPEN_PUNCTUATION: TGUnicodeType = 22; G_UNICODE_CURRENCY_SYMBOL: TGUnicodeType = 23; G_UNICODE_MODIFIER_SYMBOL: TGUnicodeType = 24; G_UNICODE_MATH_SYMBOL: TGUnicodeType = 25; G_UNICODE_OTHER_SYMBOL: TGUnicodeType = 26; G_UNICODE_LINE_SEPARATOR: TGUnicodeType = 27; G_UNICODE_PARAGRAPH_SEPARATOR: TGUnicodeType = 28; G_UNICODE_SPACE_SEPARATOR: TGUnicodeType = 29; type TGUserDirectory = Integer; const { GUserDirectory } G_USER_DIRECTORY_DESKTOP: TGUserDirectory = 0; G_USER_DIRECTORY_DOCUMENTS: TGUserDirectory = 1; G_USER_DIRECTORY_DOWNLOAD: TGUserDirectory = 2; G_USER_DIRECTORY_MUSIC: TGUserDirectory = 3; G_USER_DIRECTORY_PICTURES: TGUserDirectory = 4; G_USER_DIRECTORY_PUBLIC_SHARE: TGUserDirectory = 5; G_USER_DIRECTORY_TEMPLATES: TGUserDirectory = 6; G_USER_DIRECTORY_VIDEOS: TGUserDirectory = 7; G_USER_N_DIRECTORIES: TGUserDirectory = 8; type TGVariantClass = Integer; const { GVariantClass } G_VARIANT_CLASS_BOOLEAN: TGVariantClass = 98; G_VARIANT_CLASS_BYTE: TGVariantClass = 121; G_VARIANT_CLASS_INT16: TGVariantClass = 110; G_VARIANT_CLASS_UINT16: TGVariantClass = 113; G_VARIANT_CLASS_INT32: TGVariantClass = 105; G_VARIANT_CLASS_UINT32: TGVariantClass = 117; G_VARIANT_CLASS_INT64: TGVariantClass = 120; G_VARIANT_CLASS_UINT64: TGVariantClass = 116; G_VARIANT_CLASS_HANDLE: TGVariantClass = 104; G_VARIANT_CLASS_DOUBLE: TGVariantClass = 100; G_VARIANT_CLASS_STRING: TGVariantClass = 115; G_VARIANT_CLASS_OBJECT_PATH: TGVariantClass = 111; G_VARIANT_CLASS_SIGNATURE: TGVariantClass = 103; G_VARIANT_CLASS_VARIANT: TGVariantClass = 118; G_VARIANT_CLASS_MAYBE: TGVariantClass = 109; G_VARIANT_CLASS_ARRAY: TGVariantClass = 97; G_VARIANT_CLASS_TUPLE: TGVariantClass = 40; G_VARIANT_CLASS_DICT_ENTRY: TGVariantClass = 123; type TGVariantParseError = Integer; const { GVariantParseError } G_VARIANT_PARSE_ERROR_FAILED: TGVariantParseError = 0; G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED: TGVariantParseError = 1; G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE: TGVariantParseError = 2; G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED: TGVariantParseError = 3; G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END: TGVariantParseError = 4; G_VARIANT_PARSE_ERROR_INVALID_CHARACTER: TGVariantParseError = 5; G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING: TGVariantParseError = 6; G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH: TGVariantParseError = 7; G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE: TGVariantParseError = 8; G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING: TGVariantParseError = 9; G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE: TGVariantParseError = 10; G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE: TGVariantParseError = 11; G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG: TGVariantParseError = 12; G_VARIANT_PARSE_ERROR_TYPE_ERROR: TGVariantParseError = 13; G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN: TGVariantParseError = 14; G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD: TGVariantParseError = 15; G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT: TGVariantParseError = 16; G_VARIANT_PARSE_ERROR_VALUE_EXPECTED: TGVariantParseError = 17; type guint1 = 0..(1 shl 1-1); guint2 = 0..(1 shl 2-1); guint3 = 0..(1 shl 3-1); guint4 = 0..(1 shl 4-1); guint5 = 0..(1 shl 5-1); guint6 = 0..(1 shl 6-1); guint7 = 0..(1 shl 7-1); guint9 = 0..(1 shl 9-1); guint10 = 0..(1 shl 10-1); guint11 = 0..(1 shl 11-1); guint12 = 0..(1 shl 12-1); guint13 = 0..(1 shl 13-1); guint14 = 0..(1 shl 14-1); guint15 = 0..(1 shl 15-1); guint17 = 0..(1 shl 17-1); guint18 = 0..(1 shl 18-1); guint19 = 0..(1 shl 19-1); guint20 = 0..(1 shl 20-1); guint21 = 0..(1 shl 21-1); guint22 = 0..(1 shl 22-1); guint23 = 0..(1 shl 23-1); guint24 = 0..(1 shl 24-1); guint25 = 0..(1 shl 25-1); guint26 = 0..(1 shl 26-1); guint27 = 0..(1 shl 27-1); guint28 = 0..(1 shl 28-1); guint29 = 0..(1 shl 29-1); guint30 = 0..(1 shl 30-1); guint31 = 0..(1 shl 31-1); gpointer = pointer; int = cint; gint = cint; guint = cuint; guint8 = cuint8; guint16 = cuint16; guint32 = cuint32; guint64 = cuint64; gint8 = cint8; gint16 = cint16; gint32 = cint32; gint64 = cint64; gsize = csize_t; glong = clong; gulong = culong; gushort = cushort; gshort = cshort; gchar = char; guchar = byte; gboolean = Boolean32; gssize = PtrInt; size_t = csize_t; gconstpointer = gpointer; gfloat = cfloat; gdouble = cdouble; double = cdouble; goffset = Int64; long_double = Extended; gunichar = guint32; gunichar2 = guint32; unsigned_long_long = qword; PPGDateDay = ^PGDateDay; PGDateDay = ^TGDateDay; TGDateDay = guint8; PPGDateYear = ^PGDateYear; PGDateYear = ^TGDateYear; TGDateYear = guint16; PPGPid = ^PGPid; PGPid = ^TGPid; TGPid = gint; PPGQuark = ^PGQuark; PGQuark = ^TGQuark; TGQuark = guint32; PPGStrv = ^PGStrv; PGStrv = ^TGStrv; TGStrv = gpointer; PPGTime = ^PGTime; PGTime = ^TGTime; TGTime = gint32; PPGTimeSpan = ^PGTimeSpan; PGTimeSpan = ^TGTimeSpan; TGTimeSpan = gint64; PPPGType = ^PPGType; PPGType = ^PGType; PGType = ^TGType; TGType = gsize; PPPgpointer = ^PPgpointer; PPgpointer = ^Pgpointer; Pgpointer = ^gpointer; TGDestroyNotify = procedure(data: gpointer); cdecl; PPPgint = ^PPgint; PPgint = ^Pgint; Pgint = ^gint; TGCompareFunc = function(a: Pgpointer; b: Pgpointer): gint; cdecl; TGCompareDataFunc = function(a: Pgpointer; b: Pgpointer; user_data: gpointer): gint; cdecl; PPGArray = ^PGArray; PGArray = ^TGArray; PPPguint = ^PPguint; PPguint = ^Pguint; Pguint = ^guint; PPPgchar = ^PPgchar; PPgchar = ^Pgchar; Pgchar = ^gchar; PPPgboolean = ^PPgboolean; PPgboolean = ^Pgboolean; Pgboolean = ^gboolean; PPGDestroyNotify = ^PGDestroyNotify; PGDestroyNotify = ^TGDestroyNotify; PPGCompareFunc = ^PGCompareFunc; PGCompareFunc = ^TGCompareFunc; PPGCompareDataFunc = ^PGCompareDataFunc; PGCompareDataFunc = ^TGCompareDataFunc; TGArray = object data: Pgchar; len: guint; end; PPGAsciiType = ^PGAsciiType; PGAsciiType = ^TGAsciiType; PPGAsyncQueue = ^PGAsyncQueue; PGAsyncQueue = ^TGAsyncQueue; PPPguint64 = ^PPguint64; PPguint64 = ^Pguint64; Pguint64 = ^guint64; TGAsyncQueue = object end; PPGTimeVal = ^PGTimeVal; PGTimeVal = ^TGTimeVal; PPPglong = ^PPglong; PPglong = ^Pglong; Pglong = ^glong; TGTimeVal = object tv_sec: glong; tv_usec: glong; end; PPGBookmarkFile = ^PGBookmarkFile; PGBookmarkFile = ^TGBookmarkFile; PPGError = ^PGError; PGError = ^TGError; PPPgsize = ^PPgsize; PPgsize = ^Pgsize; Pgsize = ^gsize; TGBookmarkFile = object end; Pva_list = ^Tva_list; { va_list } Tva_list = record { opaque type } Unknown: Pointer; end; TGError = object domain: TGQuark; code: gint; message: Pgchar; end; PPGBookmarkFileError = ^PGBookmarkFileError; PGBookmarkFileError = ^TGBookmarkFileError; PPGBytes = ^PGBytes; PGBytes = ^TGBytes; PPPguint8 = ^PPguint8; PPguint8 = ^Pguint8; Pguint8 = ^guint8; TGBytes = object end; PPGByteArray = ^PGByteArray; PGByteArray = ^TGByteArray; TGByteArray = object data: Pguint8; len: guint; end; PPGChecksum = ^PGChecksum; PGChecksum = ^TGChecksum; PPGChecksumType = ^PGChecksumType; PGChecksumType = ^TGChecksumType; PPPgssize = ^PPgssize; PPgssize = ^Pgssize; Pgssize = ^gssize; TGChecksum = object end; TGChildWatchFunc = procedure(pid: TGPid; status: gint; user_data: gpointer); cdecl; PPGCond = ^PGCond; PGCond = ^TGCond; PPGMutex = ^PGMutex; PGMutex = ^TGMutex; PPPgint64 = ^PPgint64; PPgint64 = ^Pgint64; Pgint64 = ^gint64; TGCond = object p: gpointer; i: array [0..1] of guint; end; TGMutex = record case longint of 0 : (p: gpointer); 1 : (i: array [0..1] of guint); // // // // // end; PPGConvertError = ^PGConvertError; PGConvertError = ^TGConvertError; TGCopyFunc = function(src: Pgpointer; data: gpointer): gpointer; cdecl; PPGData = ^PGData; PGData = ^TGData; TGData = record end; TGDataForeachFunc = procedure(key_id: TGQuark; data: gpointer; user_data: gpointer); cdecl; PPGDate = ^PGDate; PGDate = ^TGDate; PPGDateMonth = ^PGDateMonth; PGDateMonth = ^TGDateMonth; PPPguint32 = ^PPguint32; PPguint32 = ^Pguint32; Pguint32 = ^guint32; PPGDateWeekday = ^PGDateWeekday; PGDateWeekday = ^TGDateWeekday; TGDateBitfield0 = bitpacked record julian_days: guint32 { changed from guint to accomodate 32 bitsize requirement }; julian: guint1 { changed from guint to accomodate 1 bitsize requirement }; dmy: guint1 { changed from guint to accomodate 1 bitsize requirement }; day: guint6 { changed from guint to accomodate 6 bitsize requirement }; month: guint4 { changed from guint to accomodate 4 bitsize requirement }; year: guint16 { changed from guint to accomodate 16 bitsize requirement }; end; TGDate = object Bitfield0 : TGDateBitfield0; { auto generated type } end; PPGDateDMY = ^PGDateDMY; PGDateDMY = ^TGDateDMY; PPGDateTime = ^PGDateTime; PGDateTime = ^TGDateTime; PPGTimeZone = ^PGTimeZone; PGTimeZone = ^TGTimeZone; PPPgdouble = ^PPgdouble; PPgdouble = ^Pgdouble; Pgdouble = ^gdouble; TGDateTime = object end; PPGTimeType = ^PGTimeType; PGTimeType = ^TGTimeType; PPPgint32 = ^PPgint32; PPgint32 = ^Pgint32; Pgint32 = ^gint32; TGTimeZone = object end; PPGDebugKey = ^PGDebugKey; PGDebugKey = ^TGDebugKey; TGDebugKey = record key: Pgchar; value: guint; end; PPGDir = ^PGDir; PGDir = ^TGDir; TGDir = object end; TGDoubleIEEE754 = record case longint of 0 : (v_double: gdouble); 1 : ( mpn : record mantissa_low: guint32 { changed from guint to accomodate 32 bitsize requirement }; mantissa_high: guint20 { changed from guint to accomodate 20 bitsize requirement }; biased_exponent: guint11 { changed from guint to accomodate 11 bitsize requirement }; sign: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; ); end; TGDuplicateFunc = function(data: gpointer; user_data: gpointer): gpointer; cdecl; TGEqualFunc = function(a: Pgpointer; b: Pgpointer): gboolean; cdecl; PPGErrorType = ^PGErrorType; PGErrorType = ^TGErrorType; PPGFileError = ^PGFileError; PGFileError = ^TGFileError; PPGFileTest = ^PGFileTest; PGFileTest = ^TGFileTest; PPPgfloat = ^PPgfloat; PPgfloat = ^Pgfloat; Pgfloat = ^gfloat; TGFloatIEEE754 = record case longint of 0 : (v_float: gfloat); 1 : ( mpn : record mantissa: guint23 { changed from guint to accomodate 23 bitsize requirement }; biased_exponent: guint8 { changed from guint to accomodate 8 bitsize requirement }; sign: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; ); end; PPGFormatSizeFlags = ^PGFormatSizeFlags; PGFormatSizeFlags = ^TGFormatSizeFlags; TGFreeFunc = procedure(data: gpointer); cdecl; TGFunc = procedure(data: gpointer; user_data: gpointer); cdecl; TGHFunc = procedure(key: gpointer; value: gpointer; user_data: gpointer); cdecl; TGHRFunc = function(key: gpointer; value: gpointer; user_data: gpointer): gboolean; cdecl; TGHashFunc = function(key: Pgpointer): guint; cdecl; PPGHashTable = ^PGHashTable; PGHashTable = ^TGHashTable; PPGHRFunc = ^PGHRFunc; PGHRFunc = ^TGHRFunc; PPGHFunc = ^PGHFunc; PGHFunc = ^TGHFunc; PPGList = ^PGList; PGList = ^TGList; PPGHashFunc = ^PGHashFunc; PGHashFunc = ^TGHashFunc; PPGEqualFunc = ^PGEqualFunc; PGEqualFunc = ^TGEqualFunc; TGHashTable = object end; PPGCopyFunc = ^PGCopyFunc; PGCopyFunc = ^TGCopyFunc; PPGFunc = ^PGFunc; PGFunc = ^TGFunc; TGList = object data: gpointer; next: PGList; prev: PGList; end; PPGHashTableIter = ^PGHashTableIter; PGHashTableIter = ^TGHashTableIter; TGHashTableIter = object dummy1: gpointer; dummy2: gpointer; dummy3: gpointer; dummy4: gint; dummy5: gboolean; dummy6: gpointer; end; PPGHmac = ^PGHmac; PGHmac = ^TGHmac; TGHmac = object end; PPGHook = ^PGHook; PGHook = ^TGHook; PPGHookList = ^PGHookList; PGHookList = ^TGHookList; PPPgulong = ^PPgulong; PPgulong = ^Pgulong; Pgulong = ^gulong; PPGHookFindFunc = ^PGHookFindFunc; PGHookFindFunc = ^TGHookFindFunc; TGHookFindFunc = function(hook: PGHook; data: gpointer): gboolean; cdecl; PPGHookCompareFunc = ^PGHookCompareFunc; PGHookCompareFunc = ^TGHookCompareFunc; TGHookCompareFunc = function(new_hook: PGHook; sibling: PGHook): gint; cdecl; TGHook = object data: gpointer; next: PGHook; prev: PGHook; ref_count: guint; hook_id: gulong; flags: guint; func: gpointer; destroy_1: TGDestroyNotify; end; PPGHookMarshaller = ^PGHookMarshaller; PGHookMarshaller = ^TGHookMarshaller; TGHookMarshaller = procedure(hook: PGHook; marshal_data: gpointer); cdecl; PPGHookCheckMarshaller = ^PGHookCheckMarshaller; PGHookCheckMarshaller = ^TGHookCheckMarshaller; TGHookCheckMarshaller = function(hook: PGHook; marshal_data: gpointer): gboolean; cdecl; TGHookListBitfield0 = bitpacked record hook_size: guint16 { changed from guint to accomodate 16 bitsize requirement }; is_setup: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; PPGHookFinalizeFunc = ^PGHookFinalizeFunc; PGHookFinalizeFunc = ^TGHookFinalizeFunc; TGHookFinalizeFunc = procedure(hook_list: PGHookList; hook: PGHook); cdecl; TGHookList = object seq_id: gulong; Bitfield0 : TGHookListBitfield0; { auto generated type } hooks: PGHook; dummy3: gpointer; finalize_hook: TGHookFinalizeFunc; dummy: array [0..1] of gpointer; end; TGHookCheckFunc = function(data: gpointer): gboolean; cdecl; PPGHookFlagMask = ^PGHookFlagMask; PGHookFlagMask = ^TGHookFlagMask; TGHookFunc = procedure(data: gpointer); cdecl; PPGIConv = ^PGIConv; PGIConv = ^TGIConv; TGIConv = object end; PPGIOFuncs = ^PGIOFuncs; PGIOFuncs = ^TGIOFuncs; PPGIOStatus = ^PGIOStatus; PGIOStatus = ^TGIOStatus; PPGIOChannel = ^PGIOChannel; PGIOChannel = ^TGIOChannel; PPGSeekType = ^PGSeekType; PGSeekType = ^TGSeekType; PPGSource = ^PGSource; PGSource = ^TGSource; PPGIOCondition = ^PGIOCondition; PGIOCondition = ^TGIOCondition; PPGIOFlags = ^PGIOFlags; PGIOFlags = ^TGIOFlags; TGIOFuncs = record io_read: function(channel: PGIOChannel; buf: Pgchar; count: gsize; bytes_read: Pgsize; error: PPGError): TGIOStatus; cdecl; io_write: function(channel: PGIOChannel; buf: Pgchar; count: gsize; bytes_written: Pgsize; error: PPGError): TGIOStatus; cdecl; io_seek: function(channel: PGIOChannel; offset: gint64; type_: TGSeekType; error: PPGError): TGIOStatus; cdecl; io_close: function(channel: PGIOChannel; error: PPGError): TGIOStatus; cdecl; io_create_watch: function(channel: PGIOChannel; condition: TGIOCondition): PGSource; cdecl; io_free: procedure(channel: PGIOChannel); cdecl; io_set_flags: function(channel: PGIOChannel; flags: TGIOFlags; error: PPGError): TGIOStatus; cdecl; io_get_flags: function(channel: PGIOChannel): TGIOFlags; cdecl; end; PPGString = ^PGString; PGString = ^TGString; PPPgunichar = ^PPgunichar; PPgunichar = ^Pgunichar; Pgunichar = ^gunichar; TGString = object str: Pgchar; len: gsize; allocated_len: gsize; end; PPGIOChannelError = ^PGIOChannelError; PGIOChannelError = ^TGIOChannelError; TGIOChannelBitfield0 = bitpacked record use_buffer: guint1 { changed from guint to accomodate 1 bitsize requirement }; do_encode: guint1 { changed from guint to accomodate 1 bitsize requirement }; close_on_unref: guint1 { changed from guint to accomodate 1 bitsize requirement }; is_readable: guint1 { changed from guint to accomodate 1 bitsize requirement }; is_writeable: guint1 { changed from guint to accomodate 1 bitsize requirement }; is_seekable: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; TGIOChannel = object ref_count: gint; funcs: PGIOFuncs; encoding: Pgchar; read_cd: TGIConv; write_cd: TGIConv; line_term: Pgchar; line_term_len: guint; buf_size: gsize; read_buf: PGString; encoded_read_buf: PGString; write_buf: PGString; partial_write_buf: array [0..5] of gchar; Bitfield0 : TGIOChannelBitfield0; { auto generated type } reserved1: gpointer; reserved2: gpointer; end; PPGIOError = ^PGIOError; PGIOError = ^TGIOError; TGIOFunc = function(source: PGIOChannel; condition: TGIOCondition; data: gpointer): gboolean; cdecl; PPGSourceFuncs = ^PGSourceFuncs; PGSourceFuncs = ^TGSourceFuncs; PPPGPollFD = ^PPGPollFD; PPGPollFD = ^PGPollFD; PGPollFD = ^TGPollFD; PPGMainContext = ^PGMainContext; PGMainContext = ^TGMainContext; PPGSourceFunc = ^PGSourceFunc; PGSourceFunc = ^TGSourceFunc; TGSourceFunc = function(user_data: gpointer): gboolean; cdecl; PPGSourceCallbackFuncs = ^PGSourceCallbackFuncs; PGSourceCallbackFuncs = ^TGSourceCallbackFuncs; PPGSList = ^PGSList; PGSList = ^TGSList; PPGSourcePrivate = ^PGSourcePrivate; PGSourcePrivate = ^TGSourcePrivate; TGSource = object callback_data: gpointer; callback_funcs: PGSourceCallbackFuncs; source_funcs: PGSourceFuncs; ref_count: guint; context: PGMainContext; priority: gint; flags: guint; source_id: guint; poll_fds: PGSList; prev: PGSource; next: PGSource; name: Pgchar; priv: PGSourcePrivate; end; PPGKeyFile = ^PGKeyFile; PGKeyFile = ^TGKeyFile; PPGKeyFileFlags = ^PGKeyFileFlags; PGKeyFileFlags = ^TGKeyFileFlags; TGKeyFile = object end; PPGKeyFileError = ^PGKeyFileError; PGKeyFileError = ^TGKeyFileError; PPGLogLevelFlags = ^PGLogLevelFlags; PGLogLevelFlags = ^TGLogLevelFlags; TGLogFunc = procedure(log_domain: Pgchar; log_level: TGLogLevelFlags; message: Pgchar; user_data: gpointer); cdecl; PPGPollFunc = ^PGPollFunc; PGPollFunc = ^TGPollFunc; TGPollFunc = function(ufds: PGPollFD; nfsd: guint; timeout_: gint): gint; cdecl; TGMainContext = object end; PPPgushort = ^PPgushort; PPgushort = ^Pgushort; Pgushort = ^gushort; TGPollFD = object fd: gint; events: gushort; revents: gushort; end; PPGSourceDummyMarshal = ^PGSourceDummyMarshal; PGSourceDummyMarshal = ^TGSourceDummyMarshal; TGSourceDummyMarshal = procedure; cdecl; TGSourceFuncs = record prepare: function(source: PGSource; timeout_: Pgint): gboolean; cdecl; check: function(source: PGSource): gboolean; cdecl; dispatch: function(source: PGSource; callback: TGSourceFunc; user_data: gpointer): gboolean; cdecl; finalize: procedure(source: PGSource); cdecl; closure_callback: TGSourceFunc; closure_marshal: TGSourceDummyMarshal; end; PPGMainLoop = ^PGMainLoop; PGMainLoop = ^TGMainLoop; TGMainLoop = object end; PPGMappedFile = ^PGMappedFile; PGMappedFile = ^TGMappedFile; TGMappedFile = object end; PPGMarkupCollectType = ^PGMarkupCollectType; PGMarkupCollectType = ^TGMarkupCollectType; PPGMarkupError = ^PGMarkupError; PGMarkupError = ^TGMarkupError; PPGMarkupParseContext = ^PGMarkupParseContext; PGMarkupParseContext = ^TGMarkupParseContext; PPGMarkupParser = ^PGMarkupParser; PGMarkupParser = ^TGMarkupParser; PPGMarkupParseFlags = ^PGMarkupParseFlags; PGMarkupParseFlags = ^TGMarkupParseFlags; TGMarkupParseContext = object end; TGMarkupParser = record start_element: procedure(context: PGMarkupParseContext; element_name: Pgchar; attribute_names: PPgchar; attribute_values: PPgchar; user_data: gpointer; error: PPGError); cdecl; end_element: procedure(context: PGMarkupParseContext; element_name: Pgchar; user_data: gpointer; error: PPGError); cdecl; text: procedure(context: PGMarkupParseContext; text: Pgchar; text_len: gsize; user_data: gpointer; error: PPGError); cdecl; passthrough: procedure(context: PGMarkupParseContext; passthrough_text: Pgchar; text_len: gsize; user_data: gpointer; error: PPGError); cdecl; error: procedure(context: PGMarkupParseContext; error: PGError; user_data: gpointer); cdecl; end; TGSList = object data: gpointer; next: PGSList; end; PPGMatchInfo = ^PGMatchInfo; PGMatchInfo = ^TGMatchInfo; PPGRegex = ^PGRegex; PGRegex = ^TGRegex; TGMatchInfo = object end; PPGRegexCompileFlags = ^PGRegexCompileFlags; PGRegexCompileFlags = ^TGRegexCompileFlags; PPGRegexMatchFlags = ^PGRegexMatchFlags; PGRegexMatchFlags = ^TGRegexMatchFlags; PPGRegexEvalCallback = ^PGRegexEvalCallback; PGRegexEvalCallback = ^TGRegexEvalCallback; TGRegexEvalCallback = function(match_info: PGMatchInfo; result_: PGString; user_data: gpointer): gboolean; cdecl; TGRegex = object end; PPGMemVTable = ^PGMemVTable; PGMemVTable = ^TGMemVTable; TGMemVTable = record malloc: function(n_bytes: gsize): gpointer; cdecl; realloc: function(mem: gpointer; n_bytes: gsize): gpointer; cdecl; free: procedure(mem: gpointer); cdecl; calloc: function(n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; try_malloc: function(n_bytes: gsize): gpointer; cdecl; try_realloc: function(mem: gpointer; n_bytes: gsize): gpointer; cdecl; end; PPGNode = ^PGNode; PGNode = ^TGNode; PPGTraverseFlags = ^PGTraverseFlags; PGTraverseFlags = ^TGTraverseFlags; PPGNodeForeachFunc = ^PGNodeForeachFunc; PGNodeForeachFunc = ^TGNodeForeachFunc; TGNodeForeachFunc = procedure(node: PGNode; data: gpointer); cdecl; PPGTraverseType = ^PGTraverseType; PGTraverseType = ^TGTraverseType; PPGNodeTraverseFunc = ^PGNodeTraverseFunc; PGNodeTraverseFunc = ^TGNodeTraverseFunc; TGNodeTraverseFunc = function(node: PGNode; data: gpointer): gboolean; cdecl; TGNode = object data: gpointer; next: PGNode; prev: PGNode; parent: PGNode; children: PGNode; end; PPGNormalizeMode = ^PGNormalizeMode; PGNormalizeMode = ^TGNormalizeMode; PPGOnceStatus = ^PGOnceStatus; PGOnceStatus = ^TGOnceStatus; PPGOnce = ^PGOnce; PGOnce = ^TGOnce; PPGThreadFunc = ^PGThreadFunc; PGThreadFunc = ^TGThreadFunc; TGThreadFunc = function(data: gpointer): gpointer; cdecl; TGOnce = object status: TGOnceStatus; retval: gpointer; end; PPGOptionArg = ^PGOptionArg; PGOptionArg = ^TGOptionArg; TGOptionArgFunc = function(option_name: Pgchar; value: Pgchar; data: gpointer; error: PPGError): gboolean; cdecl; PPGOptionContext = ^PGOptionContext; PGOptionContext = ^TGOptionContext; PPGOptionGroup = ^PGOptionGroup; PGOptionGroup = ^TGOptionGroup; PPGOptionEntry = ^PGOptionEntry; PGOptionEntry = ^TGOptionEntry; PPGTranslateFunc = ^PGTranslateFunc; PGTranslateFunc = ^TGTranslateFunc; TGTranslateFunc = function(str: Pgchar; data: gpointer): Pgchar; cdecl; TGOptionContext = object end; PPGOptionErrorFunc = ^PGOptionErrorFunc; PGOptionErrorFunc = ^TGOptionErrorFunc; TGOptionErrorFunc = procedure(context: PGOptionContext; group: PGOptionGroup; data: gpointer; error: PPGError); cdecl; PPGOptionParseFunc = ^PGOptionParseFunc; PGOptionParseFunc = ^TGOptionParseFunc; TGOptionParseFunc = function(context: PGOptionContext; group: PGOptionGroup; data: gpointer; error: PPGError): gboolean; cdecl; TGOptionGroup = object end; TGOptionEntry = record long_name: Pgchar; short_name: gchar; flags: gint; arg: TGOptionArg; arg_data: gpointer; description: Pgchar; arg_description: Pgchar; end; PPGOptionError = ^PGOptionError; PGOptionError = ^TGOptionError; PPGOptionFlags = ^PGOptionFlags; PGOptionFlags = ^TGOptionFlags; PPGPatternSpec = ^PGPatternSpec; PGPatternSpec = ^TGPatternSpec; TGPatternSpec = object end; TGPrintFunc = procedure(string_: Pgchar); cdecl; PPGPrivate = ^PGPrivate; PGPrivate = ^TGPrivate; TGPrivate = object p: gpointer; notify: TGDestroyNotify; future: array [0..1] of gpointer; end; PPGPtrArray = ^PGPtrArray; PGPtrArray = ^TGPtrArray; TGPtrArray = object pdata: Pgpointer; len: guint; end; PPGQueue = ^PGQueue; PGQueue = ^TGQueue; TGQueue = object head: PGList; tail: PGList; length: guint; end; PPGRWLock = ^PGRWLock; PGRWLock = ^TGRWLock; TGRWLock = object p: gpointer; i: array [0..1] of guint; end; PPGRand = ^PGRand; PGRand = ^TGRand; TGRand = object end; PPGRecMutex = ^PGRecMutex; PGRecMutex = ^TGRecMutex; TGRecMutex = object p: gpointer; i: array [0..1] of guint; end; PPGRegexError = ^PGRegexError; PGRegexError = ^TGRegexError; PPGScannerConfig = ^PGScannerConfig; PGScannerConfig = ^TGScannerConfig; TGScannerConfigBitfield0 = bitpacked record case_sensitive: guint1 { changed from guint to accomodate 1 bitsize requirement }; skip_comment_multi: guint1 { changed from guint to accomodate 1 bitsize requirement }; skip_comment_single: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_comment_multi: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_identifier: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_identifier_1char: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_identifier_NULL: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_symbols: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_binary: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_octal: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_float: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_hex: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_hex_dollar: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_string_sq: guint1 { changed from guint to accomodate 1 bitsize requirement }; scan_string_dq: guint1 { changed from guint to accomodate 1 bitsize requirement }; numbers_2_int: guint1 { changed from guint to accomodate 1 bitsize requirement }; int_2_float: guint1 { changed from guint to accomodate 1 bitsize requirement }; identifier_2_string: guint1 { changed from guint to accomodate 1 bitsize requirement }; char_2_token: guint1 { changed from guint to accomodate 1 bitsize requirement }; symbol_2_token: guint1 { changed from guint to accomodate 1 bitsize requirement }; scope_0_fallback: guint1 { changed from guint to accomodate 1 bitsize requirement }; store_int64: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; TGScannerConfig = record cset_skip_characters: Pgchar; cset_identifier_first: Pgchar; cset_identifier_nth: Pgchar; cpair_comment_single: Pgchar; Bitfield0 : TGScannerConfigBitfield0; { auto generated type } padding_dummy: guint; end; PPGTokenType = ^PGTokenType; PGTokenType = ^TGTokenType; TGTokenValue = record case longint of 0 : (v_symbol: gpointer); 1 : (v_identifier: Pgchar); 2 : (v_binary: gulong); 3 : (v_octal: gulong); 4 : (v_int: gulong); 5 : (v_int64: guint64); 6 : (v_float: gdouble); 7 : (v_hex: gulong); 8 : (v_string: Pgchar); 9 : (v_comment: Pgchar); 10 : (v_char: guint8); 11 : (v_error: guint); end; PPGScanner = ^PGScanner; PGScanner = ^TGScanner; TGScannerMsgFunc = procedure(scanner: PGScanner; message: Pgchar; error: gboolean); cdecl; PPGTokenValue = ^PGTokenValue; PGTokenValue = ^TGTokenValue; PPGScannerMsgFunc = ^PGScannerMsgFunc; PGScannerMsgFunc = ^TGScannerMsgFunc; TGScanner = object user_data: gpointer; max_parse_errors: guint; parse_errors: guint; input_name: Pgchar; qdata: PGData; config: PGScannerConfig; token: TGTokenType; value: TGTokenValue; line: guint; position: guint; next_token: TGTokenType; next_value: TGTokenValue; next_line: guint; next_position: guint; symbol_table: PGHashTable; input_fd: gint; text: Pgchar; text_end: Pgchar; buffer: Pgchar; scope_id: guint; msg_handler: TGScannerMsgFunc; end; PPGSequenceIter = ^PGSequenceIter; PGSequenceIter = ^TGSequenceIter; PPGSequence = ^PGSequence; PGSequence = ^TGSequence; TGSequenceIter = object end; PPGSequenceIterCompareFunc = ^PGSequenceIterCompareFunc; PGSequenceIterCompareFunc = ^TGSequenceIterCompareFunc; TGSequenceIterCompareFunc = function(a: PGSequenceIter; b: PGSequenceIter; data: gpointer): gint; cdecl; TGSequence = object end; PPGShellError = ^PGShellError; PGShellError = ^TGShellError; PPGSliceConfig = ^PGSliceConfig; PGSliceConfig = ^TGSliceConfig; TGSourceCallbackFuncs = record ref: procedure(cb_data: gpointer); cdecl; unref: procedure(cb_data: gpointer); cdecl; get: procedure(cb_data: gpointer; source: PGSource; func: PGSourceFunc; data: Pgpointer); cdecl; end; TGSourcePrivate = record end; TGSpawnChildSetupFunc = procedure(user_data: gpointer); cdecl; PPGSpawnError = ^PGSpawnError; PGSpawnError = ^TGSpawnError; PPGSpawnFlags = ^PGSpawnFlags; PGSpawnFlags = ^TGSpawnFlags; PPGStatBuf = ^PGStatBuf; PGStatBuf = ^TGStatBuf; TGStatBuf = record end; PPGStringChunk = ^PGStringChunk; PGStringChunk = ^TGStringChunk; TGStringChunk = object end; PPGTestCase = ^PGTestCase; PGTestCase = ^TGTestCase; TGTestCase = record end; PPGTestConfig = ^PGTestConfig; PGTestConfig = ^TGTestConfig; TGTestConfig = record test_initialized: gboolean; test_quick: gboolean; test_perf: gboolean; test_verbose: gboolean; test_quiet: gboolean; test_undefined: gboolean; end; TGTestDataFunc = procedure(user_data: Pgpointer); cdecl; TGTestFixtureFunc = procedure(fixture: gpointer; user_data: Pgpointer); cdecl; TGTestFunc = procedure; cdecl; PPGTestLogBuffer = ^PGTestLogBuffer; PGTestLogBuffer = ^TGTestLogBuffer; PPGTestLogMsg = ^PGTestLogMsg; PGTestLogMsg = ^TGTestLogMsg; TGTestLogBuffer = object data: PGString; msgs: PGSList; end; PPGTestLogType = ^PGTestLogType; PGTestLogType = ^TGTestLogType; TGTestLogMsg = object log_type: TGTestLogType; n_strings: guint; strings: PPgchar; n_nums: guint; nums: Pglong; end; TGTestLogFatalFunc = function(log_domain: Pgchar; log_level: TGLogLevelFlags; message: Pgchar; user_data: gpointer): gboolean; cdecl; PPGTestSuite = ^PGTestSuite; PGTestSuite = ^TGTestSuite; TGTestSuite = object end; PPGTestTrapFlags = ^PGTestTrapFlags; PGTestTrapFlags = ^TGTestTrapFlags; PPGThread = ^PGThread; PGThread = ^TGThread; TGThread = object end; PPGThreadError = ^PGThreadError; PGThreadError = ^TGThreadError; PPGThreadPool = ^PGThreadPool; PGThreadPool = ^TGThreadPool; TGThreadPool = object func: TGFunc; user_data: gpointer; exclusive: gboolean; end; PPGTimer = ^PGTimer; PGTimer = ^TGTimer; TGTimer = object end; PPGTrashStack = ^PGTrashStack; PGTrashStack = ^TGTrashStack; TGTrashStack = object next: PGTrashStack; end; TGTraverseFunc = function(key: gpointer; value: gpointer; data: gpointer): gboolean; cdecl; PPGTree = ^PGTree; PGTree = ^TGTree; PPGTraverseFunc = ^PGTraverseFunc; PGTraverseFunc = ^TGTraverseFunc; TGTree = object end; PPGUnicodeBreakType = ^PGUnicodeBreakType; PGUnicodeBreakType = ^TGUnicodeBreakType; PPGUnicodeScript = ^PGUnicodeScript; PGUnicodeScript = ^TGUnicodeScript; PPGUnicodeType = ^PGUnicodeType; PGUnicodeType = ^TGUnicodeType; TGUnixFDSourceFunc = function(fd: gint; condition: TGIOCondition; user_data: gpointer): gboolean; cdecl; PPGUserDirectory = ^PGUserDirectory; PGUserDirectory = ^TGUserDirectory; PPGVariant = ^PGVariant; PGVariant = ^TGVariant; PPGVariantType = ^PGVariantType; PGVariantType = ^TGVariantType; PPPgint16 = ^PPgint16; PPgint16 = ^Pgint16; Pgint16 = ^gint16; PPPguint16 = ^PPguint16; PPguint16 = ^Pguint16; Pguint16 = ^guint16; PPGVariantClass = ^PGVariantClass; PGVariantClass = ^TGVariantClass; PPGVariantIter = ^PGVariantIter; PGVariantIter = ^TGVariantIter; TGVariant = object end; TGVariantType = object end; TGVariantIter = object x: array [0..15] of gsize; end; PPGVariantBuilder = ^PGVariantBuilder; PGVariantBuilder = ^TGVariantBuilder; TGVariantBuilder = object x: array [0..15] of gsize; end; PPGVariantParseError = ^PGVariantParseError; PGVariantParseError = ^TGVariantParseError; TGVoidFunc = procedure; cdecl; function g_access(filename: Pgchar; mode: gint): gint; cdecl; external; function g_array_append_vals(array_: Pgpointer; data: Pgpointer; len: guint): Pgpointer; cdecl; external; function g_array_free(array_: Pgpointer; free_segment: gboolean): Pgchar; cdecl; external; function g_array_get_element_size(array_: Pgpointer): guint; cdecl; external; function g_array_get_type: TGType; cdecl; external; function g_array_insert_vals(array_: Pgpointer; index_: guint; data: Pgpointer; len: guint): Pgpointer; cdecl; external; function g_array_new(zero_terminated: gboolean; clear_: gboolean; element_size: guint): Pgpointer; cdecl; external; function g_array_prepend_vals(array_: Pgpointer; data: Pgpointer; len: guint): Pgpointer; cdecl; external; function g_array_ref(array_: Pgpointer): Pgpointer; cdecl; external; function g_array_remove_index(array_: Pgpointer; index_: guint): Pgpointer; cdecl; external; function g_array_remove_index_fast(array_: Pgpointer; index_: guint): Pgpointer; cdecl; external; function g_array_remove_range(array_: Pgpointer; index_: guint; length: guint): Pgpointer; cdecl; external; function g_array_set_size(array_: Pgpointer; length: guint): Pgpointer; cdecl; external; function g_array_sized_new(zero_terminated: gboolean; clear_: gboolean; element_size: guint; reserved_size: guint): Pgpointer; cdecl; external; function g_ascii_digit_value(c: gchar): gint; cdecl; external; function g_ascii_dtostr(buffer: Pgchar; buf_len: gint; d: gdouble): Pgchar; cdecl; external; function g_ascii_formatd(buffer: Pgchar; buf_len: gint; format: Pgchar; d: gdouble): Pgchar; cdecl; external; function g_ascii_strcasecmp(s1: Pgchar; s2: Pgchar): gint; cdecl; external; function g_ascii_strdown(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_ascii_strncasecmp(s1: Pgchar; s2: Pgchar; n: gsize): gint; cdecl; external; function g_ascii_strtod(nptr: Pgchar; endptr: PPgchar): gdouble; cdecl; external; function g_ascii_strtoll(nptr: Pgchar; endptr: PPgchar; base: guint): gint64; cdecl; external; function g_ascii_strtoull(nptr: Pgchar; endptr: PPgchar; base: guint): guint64; cdecl; external; function g_ascii_strup(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_ascii_tolower(c: gchar): gchar; cdecl; external; function g_ascii_toupper(c: gchar): gchar; cdecl; external; function g_ascii_xdigit_value(c: gchar): gint; cdecl; external; function g_async_queue_length(queue: PGAsyncQueue): gint; cdecl; external; function g_async_queue_length_unlocked(queue: PGAsyncQueue): gint; cdecl; external; function g_async_queue_new: PGAsyncQueue; cdecl; external; function g_async_queue_new_full(item_free_func: TGDestroyNotify): PGAsyncQueue; cdecl; external; function g_async_queue_pop(queue: PGAsyncQueue): gpointer; cdecl; external; function g_async_queue_pop_unlocked(queue: PGAsyncQueue): gpointer; cdecl; external; function g_async_queue_ref(queue: PGAsyncQueue): PGAsyncQueue; cdecl; external; function g_async_queue_timeout_pop(queue: PGAsyncQueue; timeout: guint64): gpointer; cdecl; external; function g_async_queue_timeout_pop_unlocked(queue: PGAsyncQueue; timeout: guint64): gpointer; cdecl; external; function g_async_queue_try_pop(queue: PGAsyncQueue): gpointer; cdecl; external; function g_async_queue_try_pop_unlocked(queue: PGAsyncQueue): gpointer; cdecl; external; function g_atomic_int_add(atomic: Pgint; val: gint): gint; cdecl; external; function g_atomic_int_and(atomic: Pguint; val: guint): guint; cdecl; external; function g_atomic_int_compare_and_exchange(atomic: Pgint; oldval: gint; newval: gint): gboolean; cdecl; external; function g_atomic_int_dec_and_test(atomic: Pgint): gboolean; cdecl; external; function g_atomic_int_exchange_and_add(atomic: Pgint; val: gint): gint; cdecl; external; function g_atomic_int_get(atomic: Pgint): gint; cdecl; external; function g_atomic_int_or(atomic: Pguint; val: guint): guint; cdecl; external; function g_atomic_int_xor(atomic: Pguint; val: guint): guint; cdecl; external; function g_atomic_pointer_add(atomic: Pgpointer; val: gssize): gssize; cdecl; external; function g_atomic_pointer_and(atomic: Pgpointer; val: gsize): gsize; cdecl; external; function g_atomic_pointer_compare_and_exchange(atomic: Pgpointer; oldval: gpointer; newval: gpointer): gboolean; cdecl; external; function g_atomic_pointer_get(atomic: Pgpointer): gpointer; cdecl; external; function g_atomic_pointer_or(atomic: Pgpointer; val: gsize): gsize; cdecl; external; function g_atomic_pointer_xor(atomic: Pgpointer; val: gsize): gsize; cdecl; external; function g_base64_decode(text: Pgchar; out_len: Pgsize): Pguint8; cdecl; external; function g_base64_decode_inplace(text: Pgchar; out_len: Pgsize): Pguint8; cdecl; external; function g_base64_decode_step(in_: Pgchar; len: gsize; out_: Pguint8; state: Pgint; save: Pguint): gsize; cdecl; external; function g_base64_encode(data: Pguint8; len: gsize): Pgchar; cdecl; external; function g_base64_encode_close(break_lines: gboolean; out_: Pgchar; state: Pgint; save: Pgint): gsize; cdecl; external; function g_base64_encode_step(in_: Pguint8; len: gsize; break_lines: gboolean; out_: Pgchar; state: Pgint; save: Pgint): gsize; cdecl; external; function g_basename(file_name: Pgchar): Pgchar; cdecl; external; function g_bit_nth_lsf(mask: gulong; nth_bit: gint): gint; cdecl; external; function g_bit_nth_msf(mask: gulong; nth_bit: gint): gint; cdecl; external; function g_bit_storage(number: gulong): guint; cdecl; external; function g_bit_trylock(address: Pgint; lock_bit: gint): gboolean; cdecl; external; function g_bookmark_file_error_quark: TGQuark; cdecl; external; function g_bookmark_file_get_added(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): glong; cdecl; external; function g_bookmark_file_get_app_info(bookmark: PGBookmarkFile; uri: Pgchar; name: Pgchar; exec: PPgchar; count: Pguint; stamp: Pglong; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_get_applications(bookmark: PGBookmarkFile; uri: Pgchar; length: Pgsize; error: PPGError): PPgchar; cdecl; external; function g_bookmark_file_get_description(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_bookmark_file_get_groups(bookmark: PGBookmarkFile; uri: Pgchar; length: Pgsize; error: PPGError): PPgchar; cdecl; external; function g_bookmark_file_get_icon(bookmark: PGBookmarkFile; uri: Pgchar; href: PPgchar; mime_type: PPgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_get_is_private(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_get_mime_type(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_bookmark_file_get_modified(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): glong; cdecl; external; function g_bookmark_file_get_size(bookmark: PGBookmarkFile): gint; cdecl; external; function g_bookmark_file_get_title(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_bookmark_file_get_uris(bookmark: PGBookmarkFile; length: Pgsize): PPgchar; cdecl; external; function g_bookmark_file_get_visited(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): glong; cdecl; external; function g_bookmark_file_has_application(bookmark: PGBookmarkFile; uri: Pgchar; name: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_has_group(bookmark: PGBookmarkFile; uri: Pgchar; group: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_has_item(bookmark: PGBookmarkFile; uri: Pgchar): gboolean; cdecl; external; function g_bookmark_file_load_from_data(bookmark: PGBookmarkFile; data: Pgchar; length: gsize; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_load_from_data_dirs(bookmark: PGBookmarkFile; file_: Pgchar; full_path: PPgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_load_from_file(bookmark: PGBookmarkFile; filename: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_move_item(bookmark: PGBookmarkFile; old_uri: Pgchar; new_uri: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_new: PGBookmarkFile; cdecl; external; function g_bookmark_file_remove_application(bookmark: PGBookmarkFile; uri: Pgchar; name: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_remove_group(bookmark: PGBookmarkFile; uri: Pgchar; group: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_remove_item(bookmark: PGBookmarkFile; uri: Pgchar; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_set_app_info(bookmark: PGBookmarkFile; uri: Pgchar; name: Pgchar; exec: Pgchar; count: gint; stamp: glong; error: PPGError): gboolean; cdecl; external; function g_bookmark_file_to_data(bookmark: PGBookmarkFile; length: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_bookmark_file_to_file(bookmark: PGBookmarkFile; filename: Pgchar; error: PPGError): gboolean; cdecl; external; function g_build_filename(first_element: Pgchar; args: array of const): Pgchar; cdecl; external; function g_build_filenamev(args: PPgchar): Pgchar; cdecl; external; function g_build_path(separator: Pgchar; first_element: Pgchar; args: array of const): Pgchar; cdecl; external; function g_build_pathv(separator: Pgchar; args: PPgchar): Pgchar; cdecl; external; function g_byte_array_append(array_: Pguint8; data: Pguint8; len: guint): Pguint8; cdecl; external; function g_byte_array_free(array_: Pguint8; free_segment: gboolean): Pguint8; cdecl; external; function g_byte_array_free_to_bytes(array_: Pguint8): PGBytes; cdecl; external; function g_byte_array_get_type: TGType; cdecl; external; function g_byte_array_new: Pguint8; cdecl; external; function g_byte_array_new_take(data: Pguint8; len: gsize): Pguint8; cdecl; external; function g_byte_array_prepend(array_: Pguint8; data: Pguint8; len: guint): Pguint8; cdecl; external; function g_byte_array_ref(array_: Pguint8): Pguint8; cdecl; external; function g_byte_array_remove_index(array_: Pguint8; index_: guint): Pguint8; cdecl; external; function g_byte_array_remove_index_fast(array_: Pguint8; index_: guint): Pguint8; cdecl; external; function g_byte_array_remove_range(array_: Pguint8; index_: guint; length: guint): Pguint8; cdecl; external; function g_byte_array_set_size(array_: Pguint8; length: guint): Pguint8; cdecl; external; function g_byte_array_sized_new(reserved_size: guint): Pguint8; cdecl; external; function g_bytes_compare(bytes1: PGBytes; bytes2: PGBytes): gint; cdecl; external; function g_bytes_equal(bytes1: PGBytes; bytes2: PGBytes): gboolean; cdecl; external; function g_bytes_get_data(bytes: PGBytes; size: Pgsize): guint8; cdecl; external; function g_bytes_get_size(bytes: PGBytes): gsize; cdecl; external; function g_bytes_get_type: TGType; cdecl; external; function g_bytes_hash(bytes: PGBytes): guint; cdecl; external; function g_bytes_new(data: guint8; size: gsize): PGBytes; cdecl; external; function g_bytes_new_from_bytes(bytes: PGBytes; offset: gsize; length: gsize): PGBytes; cdecl; external; function g_bytes_new_static(data: guint8; size: gsize): PGBytes; cdecl; external; function g_bytes_new_take(data: guint8; size: gsize): PGBytes; cdecl; external; function g_bytes_new_with_free_func(data: gpointer; size: gsize; free_func: TGDestroyNotify; user_data: gpointer): PGBytes; cdecl; external; function g_bytes_ref(bytes: PGBytes): PGBytes; cdecl; external; function g_bytes_unref_to_array(bytes: PGBytes): Pguint8; cdecl; external; function g_bytes_unref_to_data(bytes: PGBytes; size: Pgsize): gpointer; cdecl; external; function g_chdir(path: Pgchar): gint; cdecl; external; function g_checksum_copy(checksum: PGChecksum): PGChecksum; cdecl; external; function g_checksum_get_string(checksum: PGChecksum): Pgchar; cdecl; external; function g_checksum_get_type: TGType; cdecl; external; function g_checksum_new(checksum_type: TGChecksumType): PGChecksum; cdecl; external; function g_checksum_type_get_length(checksum_type: TGChecksumType): gssize; cdecl; external; function g_child_watch_add(pid: TGPid; function_: TGChildWatchFunc; data: gpointer): guint; cdecl; external; function g_child_watch_add_full(priority: gint; pid: TGPid; function_: TGChildWatchFunc; data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_child_watch_source_new(pid: TGPid): PGSource; cdecl; external; function g_close(fd: gint; error: PPGError): gboolean; cdecl; external; function g_compute_checksum_for_bytes(checksum_type: TGChecksumType; data: PGBytes): Pgchar; cdecl; external; function g_compute_checksum_for_data(checksum_type: TGChecksumType; data: Pguint8; length: gsize): Pgchar; cdecl; external; function g_compute_checksum_for_string(checksum_type: TGChecksumType; str: Pgchar; length: gssize): Pgchar; cdecl; external; function g_compute_hmac_for_data(digest_type: TGChecksumType; key: Pguint8; key_len: gsize; data: Pguint8; length: gsize): Pgchar; cdecl; external; function g_compute_hmac_for_string(digest_type: TGChecksumType; key: Pguint8; key_len: gsize; str: Pgchar; length: gssize): Pgchar; cdecl; external; function g_cond_wait_until(cond: PGCond; mutex: PGMutex; end_time: gint64): gboolean; cdecl; external; function g_convert(str: Pgchar; len: gssize; to_codeset: Pgchar; from_codeset: Pgchar; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_convert_error_quark: TGQuark; cdecl; external; function g_convert_with_fallback(str: Pgchar; len: gssize; to_codeset: Pgchar; from_codeset: Pgchar; fallback: Pgchar; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_convert_with_iconv(str: Pgchar; len: gssize; converter: TGIConv; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_datalist_get_data(datalist: PPGData; key: Pgchar): gpointer; cdecl; external; function g_datalist_get_flags(datalist: PPGData): guint; cdecl; external; function g_datalist_id_dup_data(datalist: PPGData; key_id: TGQuark; dup_func: TGDuplicateFunc; user_data: gpointer): gpointer; cdecl; external; function g_datalist_id_get_data(datalist: PPGData; key_id: TGQuark): gpointer; cdecl; external; function g_datalist_id_remove_no_notify(datalist: PPGData; key_id: TGQuark): gpointer; cdecl; external; function g_datalist_id_replace_data(datalist: PPGData; key_id: TGQuark; oldval: gpointer; newval: gpointer; destroy_: TGDestroyNotify; old_destroy: PGDestroyNotify): gboolean; cdecl; external; function g_dataset_id_get_data(dataset_location: Pgpointer; key_id: TGQuark): gpointer; cdecl; external; function g_dataset_id_remove_no_notify(dataset_location: Pgpointer; key_id: TGQuark): gpointer; cdecl; external; function g_date_compare(lhs: PGDate; rhs: PGDate): gint; cdecl; external; function g_date_days_between(date1: PGDate; date2: PGDate): gint; cdecl; external; function g_date_get_day(date: PGDate): TGDateDay; cdecl; external; function g_date_get_day_of_year(date: PGDate): guint; cdecl; external; function g_date_get_days_in_month(month: TGDateMonth; year: TGDateYear): guint8; cdecl; external; function g_date_get_iso8601_week_of_year(date: PGDate): guint; cdecl; external; function g_date_get_julian(date: PGDate): guint32; cdecl; external; function g_date_get_monday_week_of_year(date: PGDate): guint; cdecl; external; function g_date_get_monday_weeks_in_year(year: TGDateYear): guint8; cdecl; external; function g_date_get_month(date: PGDate): TGDateMonth; cdecl; external; function g_date_get_sunday_week_of_year(date: PGDate): guint; cdecl; external; function g_date_get_sunday_weeks_in_year(year: TGDateYear): guint8; cdecl; external; function g_date_get_type: TGType; cdecl; external; function g_date_get_weekday(date: PGDate): TGDateWeekday; cdecl; external; function g_date_get_year(date: PGDate): TGDateYear; cdecl; external; function g_date_is_first_of_month(date: PGDate): gboolean; cdecl; external; function g_date_is_last_of_month(date: PGDate): gboolean; cdecl; external; function g_date_is_leap_year(year: TGDateYear): gboolean; cdecl; external; function g_date_new: PGDate; cdecl; external; function g_date_new_dmy(day: TGDateDay; month: TGDateMonth; year: TGDateYear): PGDate; cdecl; external; function g_date_new_julian(julian_day: guint32): PGDate; cdecl; external; function g_date_strftime(s: Pgchar; slen: gsize; format: Pgchar; date: PGDate): gsize; cdecl; external; function g_date_time_add(datetime: PGDateTime; timespan: TGTimeSpan): PGDateTime; cdecl; external; function g_date_time_add_days(datetime: PGDateTime; days: gint): PGDateTime; cdecl; external; function g_date_time_add_full(datetime: PGDateTime; years: gint; months: gint; days: gint; hours: gint; minutes: gint; seconds: gdouble): PGDateTime; cdecl; external; function g_date_time_add_hours(datetime: PGDateTime; hours: gint): PGDateTime; cdecl; external; function g_date_time_add_minutes(datetime: PGDateTime; minutes: gint): PGDateTime; cdecl; external; function g_date_time_add_months(datetime: PGDateTime; months: gint): PGDateTime; cdecl; external; function g_date_time_add_seconds(datetime: PGDateTime; seconds: gdouble): PGDateTime; cdecl; external; function g_date_time_add_weeks(datetime: PGDateTime; weeks: gint): PGDateTime; cdecl; external; function g_date_time_add_years(datetime: PGDateTime; years: gint): PGDateTime; cdecl; external; function g_date_time_compare(dt1: Pgpointer; dt2: Pgpointer): gint; cdecl; external; function g_date_time_difference(end_: PGDateTime; begin_: PGDateTime): TGTimeSpan; cdecl; external; function g_date_time_equal(dt1: Pgpointer; dt2: Pgpointer): gboolean; cdecl; external; function g_date_time_format(datetime: PGDateTime; format: Pgchar): Pgchar; cdecl; external; function g_date_time_get_day_of_month(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_day_of_week(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_day_of_year(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_hour(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_microsecond(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_minute(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_month(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_second(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_seconds(datetime: PGDateTime): gdouble; cdecl; external; function g_date_time_get_timezone_abbreviation(datetime: PGDateTime): Pgchar; cdecl; external; function g_date_time_get_type: TGType; cdecl; external; function g_date_time_get_utc_offset(datetime: PGDateTime): TGTimeSpan; cdecl; external; function g_date_time_get_week_numbering_year(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_week_of_year(datetime: PGDateTime): gint; cdecl; external; function g_date_time_get_year(datetime: PGDateTime): gint; cdecl; external; function g_date_time_hash(datetime: Pgpointer): guint; cdecl; external; function g_date_time_is_daylight_savings(datetime: PGDateTime): gboolean; cdecl; external; function g_date_time_new(tz: PGTimeZone; year: gint; month: gint; day: gint; hour: gint; minute: gint; seconds: gdouble): PGDateTime; cdecl; external; function g_date_time_new_from_timeval_local(tv: PGTimeVal): PGDateTime; cdecl; external; function g_date_time_new_from_timeval_utc(tv: PGTimeVal): PGDateTime; cdecl; external; function g_date_time_new_from_unix_local(t: gint64): PGDateTime; cdecl; external; function g_date_time_new_from_unix_utc(t: gint64): PGDateTime; cdecl; external; function g_date_time_new_local(year: gint; month: gint; day: gint; hour: gint; minute: gint; seconds: gdouble): PGDateTime; cdecl; external; function g_date_time_new_now(tz: PGTimeZone): PGDateTime; cdecl; external; function g_date_time_new_now_local: PGDateTime; cdecl; external; function g_date_time_new_now_utc: PGDateTime; cdecl; external; function g_date_time_new_utc(year: gint; month: gint; day: gint; hour: gint; minute: gint; seconds: gdouble): PGDateTime; cdecl; external; function g_date_time_ref(datetime: PGDateTime): PGDateTime; cdecl; external; function g_date_time_to_local(datetime: PGDateTime): PGDateTime; cdecl; external; function g_date_time_to_timeval(datetime: PGDateTime; tv: PGTimeVal): gboolean; cdecl; external; function g_date_time_to_timezone(datetime: PGDateTime; tz: PGTimeZone): PGDateTime; cdecl; external; function g_date_time_to_unix(datetime: PGDateTime): gint64; cdecl; external; function g_date_time_to_utc(datetime: PGDateTime): PGDateTime; cdecl; external; function g_date_valid(date: PGDate): gboolean; cdecl; external; function g_date_valid_day(day: TGDateDay): gboolean; cdecl; external; function g_date_valid_dmy(day: TGDateDay; month: TGDateMonth; year: TGDateYear): gboolean; cdecl; external; function g_date_valid_julian(julian_date: guint32): gboolean; cdecl; external; function g_date_valid_month(month: TGDateMonth): gboolean; cdecl; external; function g_date_valid_weekday(weekday: TGDateWeekday): gboolean; cdecl; external; function g_date_valid_year(year: TGDateYear): gboolean; cdecl; external; function g_dcgettext(domain: Pgchar; msgid: Pgchar; category: gint): Pgchar; cdecl; external; function g_dgettext(domain: Pgchar; msgid: Pgchar): Pgchar; cdecl; external; function g_dir_make_tmp(tmpl: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_dir_open(path: Pgchar; flags: guint; error: PPGError): PGDir; cdecl; external; function g_dir_read_name(dir: PGDir): Pgchar; cdecl; external; function g_direct_equal(v1: Pgpointer; v2: Pgpointer): gboolean; cdecl; external; function g_direct_hash(v: Pgpointer): guint; cdecl; external; function g_dngettext(domain: Pgchar; msgid: Pgchar; msgid_plural: Pgchar; n: gulong): Pgchar; cdecl; external; function g_double_equal(v1: Pgpointer; v2: Pgpointer): gboolean; cdecl; external; function g_double_hash(v: Pgpointer): guint; cdecl; external; function g_dpgettext(domain: Pgchar; msgctxtid: Pgchar; msgidoffset: gsize): Pgchar; cdecl; external; function g_dpgettext2(domain: Pgchar; context: Pgchar; msgid: Pgchar): Pgchar; cdecl; external; function g_environ_getenv(envp: PPgchar; variable: Pgchar): Pgchar; cdecl; external; function g_environ_setenv(envp: PPgchar; variable: Pgchar; value: Pgchar; overwrite: gboolean): PPgchar; cdecl; external; function g_environ_unsetenv(envp: PPgchar; variable: Pgchar): PPgchar; cdecl; external; function g_error_copy(error: PGError): PGError; cdecl; external; function g_error_get_type: TGType; cdecl; external; function g_error_matches(error: PGError; domain: TGQuark; code: gint): gboolean; cdecl; external; function g_error_new(domain: TGQuark; code: gint; format: Pgchar; args: array of const): PGError; cdecl; external; function g_error_new_literal(domain: TGQuark; code: gint; message: Pgchar): PGError; cdecl; external; function g_error_new_valist(domain: TGQuark; code: gint; format: Pgchar; args: Tva_list): PGError; cdecl; external; function g_file_error_from_errno(err_no: gint): TGFileError; cdecl; external; function g_file_error_quark: TGQuark; cdecl; external; function g_file_get_contents(filename: Pgchar; contents: PPgchar; length: Pgsize; error: PPGError): gboolean; cdecl; external; function g_file_open_tmp(tmpl: Pgchar; name_used: PPgchar; error: PPGError): gint; cdecl; external; function g_file_read_link(filename: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_file_set_contents(filename: Pgchar; contents: Pgchar; length: gssize; error: PPGError): gboolean; cdecl; external; function g_file_test(filename: Pgchar; test: TGFileTest): gboolean; cdecl; external; function g_filename_display_basename(filename: Pgchar): Pgchar; cdecl; external; function g_filename_display_name(filename: Pgchar): Pgchar; cdecl; external; function g_filename_from_uri(uri: Pgchar; hostname: PPgchar; error: PPGError): Pgchar; cdecl; external; function g_filename_from_utf8(utf8string: Pgchar; len: gssize; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_filename_to_uri(filename: Pgchar; hostname: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_filename_to_utf8(opsysstring: Pgchar; len: gssize; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_find_program_in_path(program_: Pgchar): Pgchar; cdecl; external; function g_format_size(size: guint64): Pgchar; cdecl; external; function g_format_size_for_display(size: gint64): Pgchar; cdecl; external; function g_format_size_full(size: guint64; flags: TGFormatSizeFlags): Pgchar; cdecl; external; function g_fprintf(file_: Pgpointer; format: Pgchar; args: array of const): gint; cdecl; external; function g_get_application_name: Pgchar; cdecl; external; function g_get_charset(charset: PPgchar): gboolean; cdecl; external; function g_get_codeset: Pgchar; cdecl; external; function g_get_current_dir: Pgchar; cdecl; external; function g_get_environ: PPgchar; cdecl; external; function g_get_filename_charsets(charsets: PPPgchar): gboolean; cdecl; external; function g_get_home_dir: Pgchar; cdecl; external; function g_get_host_name: Pgchar; cdecl; external; function g_get_language_names: PPgchar; cdecl; external; function g_get_locale_variants(locale: Pgchar): PPgchar; cdecl; external; function g_get_monotonic_time: gint64; cdecl; external; function g_get_num_processors: guint; cdecl; external; function g_get_prgname: Pgchar; cdecl; external; function g_get_real_name: Pgchar; cdecl; external; function g_get_real_time: gint64; cdecl; external; function g_get_system_config_dirs: PPgchar; cdecl; external; function g_get_system_data_dirs: PPgchar; cdecl; external; function g_get_tmp_dir: Pgchar; cdecl; external; function g_get_user_cache_dir: Pgchar; cdecl; external; function g_get_user_config_dir: Pgchar; cdecl; external; function g_get_user_data_dir: Pgchar; cdecl; external; function g_get_user_name: Pgchar; cdecl; external; function g_get_user_runtime_dir: Pgchar; cdecl; external; function g_get_user_special_dir(directory: TGUserDirectory): Pgchar; cdecl; external; function g_getenv(variable: Pgchar): Pgchar; cdecl; external; function g_gstring_get_type: TGType; cdecl; external; function g_hash_table_contains(hash_table: PGHashTable; key: Pgpointer): gboolean; cdecl; external; function g_hash_table_find(hash_table: PGHashTable; predicate: TGHRFunc; user_data: gpointer): gpointer; cdecl; external; function g_hash_table_foreach_remove(hash_table: PGHashTable; func: TGHRFunc; user_data: gpointer): guint; cdecl; external; function g_hash_table_foreach_steal(hash_table: PGHashTable; func: TGHRFunc; user_data: gpointer): guint; cdecl; external; function g_hash_table_get_keys(hash_table: PGHashTable): PGList; cdecl; external; function g_hash_table_get_type: TGType; cdecl; external; function g_hash_table_get_values(hash_table: PGHashTable): PGList; cdecl; external; function g_hash_table_iter_get_hash_table(iter: PGHashTableIter): PGHashTable; cdecl; external; function g_hash_table_iter_next(iter: PGHashTableIter; key: Pgpointer; value: Pgpointer): gboolean; cdecl; external; function g_hash_table_lookup(hash_table: PGHashTable; key: Pgpointer): gpointer; cdecl; external; function g_hash_table_lookup_extended(hash_table: PGHashTable; lookup_key: Pgpointer; orig_key: Pgpointer; value: Pgpointer): gboolean; cdecl; external; function g_hash_table_new(hash_func: TGHashFunc; key_equal_func: TGEqualFunc): PGHashTable; cdecl; external; function g_hash_table_new_full(hash_func: TGHashFunc; key_equal_func: TGEqualFunc; key_destroy_func: TGDestroyNotify; value_destroy_func: TGDestroyNotify): PGHashTable; cdecl; external; function g_hash_table_ref(hash_table: PGHashTable): PGHashTable; cdecl; external; function g_hash_table_remove(hash_table: PGHashTable; key: Pgpointer): gboolean; cdecl; external; function g_hash_table_size(hash_table: PGHashTable): guint; cdecl; external; function g_hash_table_steal(hash_table: PGHashTable; key: Pgpointer): gboolean; cdecl; external; function g_hmac_copy(hmac: PGHmac): PGHmac; cdecl; external; function g_hmac_get_string(hmac: PGHmac): Pgchar; cdecl; external; function g_hmac_new(digest_type: TGChecksumType; key: Pguint8; key_len: gsize): PGHmac; cdecl; external; function g_hmac_ref(hmac: PGHmac): PGHmac; cdecl; external; function g_hook_alloc(hook_list: PGHookList): PGHook; cdecl; external; function g_hook_compare_ids(new_hook: PGHook; sibling: PGHook): gint; cdecl; external; function g_hook_destroy(hook_list: PGHookList; hook_id: gulong): gboolean; cdecl; external; function g_hook_find(hook_list: PGHookList; need_valids: gboolean; func: TGHookFindFunc; data: gpointer): PGHook; cdecl; external; function g_hook_find_data(hook_list: PGHookList; need_valids: gboolean; data: gpointer): PGHook; cdecl; external; function g_hook_find_func(hook_list: PGHookList; need_valids: gboolean; func: gpointer): PGHook; cdecl; external; function g_hook_find_func_data(hook_list: PGHookList; need_valids: gboolean; func: gpointer; data: gpointer): PGHook; cdecl; external; function g_hook_first_valid(hook_list: PGHookList; may_be_in_call: gboolean): PGHook; cdecl; external; function g_hook_get(hook_list: PGHookList; hook_id: gulong): PGHook; cdecl; external; function g_hook_next_valid(hook_list: PGHookList; hook: PGHook; may_be_in_call: gboolean): PGHook; cdecl; external; function g_hook_ref(hook_list: PGHookList; hook: PGHook): PGHook; cdecl; external; function g_hostname_is_ascii_encoded(hostname: Pgchar): gboolean; cdecl; external; function g_hostname_is_ip_address(hostname: Pgchar): gboolean; cdecl; external; function g_hostname_is_non_ascii(hostname: Pgchar): gboolean; cdecl; external; function g_hostname_to_ascii(hostname: Pgchar): Pgchar; cdecl; external; function g_hostname_to_unicode(hostname: Pgchar): Pgchar; cdecl; external; function g_iconv(converter: TGIConv; inbuf: PPgchar; inbytes_left: Pgsize; outbuf: PPgchar; outbytes_left: Pgsize): gsize; cdecl; external; function g_iconv_close(converter: TGIConv): gint; cdecl; external; function g_iconv_open(to_codeset: Pgchar; from_codeset: Pgchar): TGIConv; cdecl; external; function g_idle_add(function_: TGSourceFunc; data: gpointer): guint; cdecl; external; function g_idle_add_full(priority: gint; function_: TGSourceFunc; data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_idle_remove_by_data(data: gpointer): gboolean; cdecl; external; function g_idle_source_new: PGSource; cdecl; external; function g_int64_equal(v1: Pgpointer; v2: Pgpointer): gboolean; cdecl; external; function g_int64_hash(v: Pgpointer): guint; cdecl; external; function g_int_equal(v1: Pgpointer; v2: Pgpointer): gboolean; cdecl; external; function g_int_hash(v: Pgpointer): guint; cdecl; external; function g_intern_static_string(string_: Pgchar): Pgchar; cdecl; external; function g_intern_string(string_: Pgchar): Pgchar; cdecl; external; function g_io_add_watch(channel: PGIOChannel; condition: TGIOCondition; func: TGIOFunc; user_data: gpointer): guint; cdecl; external; function g_io_add_watch_full(channel: PGIOChannel; priority: gint; condition: TGIOCondition; func: TGIOFunc; user_data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_io_channel_error_from_errno(en: gint): TGIOChannelError; cdecl; external; function g_io_channel_error_quark: TGQuark; cdecl; external; function g_io_channel_flush(channel: PGIOChannel; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_get_buffer_condition(channel: PGIOChannel): TGIOCondition; cdecl; external; function g_io_channel_get_buffer_size(channel: PGIOChannel): gsize; cdecl; external; function g_io_channel_get_buffered(channel: PGIOChannel): gboolean; cdecl; external; function g_io_channel_get_close_on_unref(channel: PGIOChannel): gboolean; cdecl; external; function g_io_channel_get_encoding(channel: PGIOChannel): Pgchar; cdecl; external; function g_io_channel_get_flags(channel: PGIOChannel): TGIOFlags; cdecl; external; function g_io_channel_get_line_term(channel: PGIOChannel; length: Pgint): Pgchar; cdecl; external; function g_io_channel_get_type: TGType; cdecl; external; function g_io_channel_new_file(filename: Pgchar; mode: Pgchar; error: PPGError): PGIOChannel; cdecl; external; function g_io_channel_read_chars(channel: PGIOChannel; buf: Pgchar; count: gsize; bytes_read: Pgsize; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_read_line(channel: PGIOChannel; str_return: PPgchar; length: Pgsize; terminator_pos: Pgsize; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_read_line_string(channel: PGIOChannel; buffer: PGString; terminator_pos: Pgsize; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_read_to_end(channel: PGIOChannel; str_return: PPgchar; length: Pgsize; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_read_unichar(channel: PGIOChannel; thechar: Pgunichar; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_ref(channel: PGIOChannel): PGIOChannel; cdecl; external; function g_io_channel_seek_position(channel: PGIOChannel; offset: gint64; type_: TGSeekType; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_set_encoding(channel: PGIOChannel; encoding: Pgchar; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_set_flags(channel: PGIOChannel; flags: TGIOFlags; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_shutdown(channel: PGIOChannel; flush: gboolean; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_unix_get_fd(channel: PGIOChannel): gint; cdecl; external; function g_io_channel_unix_new(fd: gint): PGIOChannel; cdecl; external; function g_io_channel_write_chars(channel: PGIOChannel; buf: Pgchar; count: gssize; bytes_written: Pgsize; error: PPGError): TGIOStatus; cdecl; external; function g_io_channel_write_unichar(channel: PGIOChannel; thechar: gunichar; error: PPGError): TGIOStatus; cdecl; external; function g_io_create_watch(channel: PGIOChannel; condition: TGIOCondition): PGSource; cdecl; external; function g_key_file_error_quark: TGQuark; cdecl; external; function g_key_file_get_boolean(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gboolean; cdecl; external; function g_key_file_get_boolean_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; length: Pgsize; error: PPGError): Pgboolean; cdecl; external; function g_key_file_get_comment(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_key_file_get_double(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gdouble; cdecl; external; function g_key_file_get_double_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; length: Pgsize; error: PPGError): Pgdouble; cdecl; external; function g_key_file_get_groups(key_file: PGKeyFile; length: Pgsize): PPgchar; cdecl; external; function g_key_file_get_int64(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gint64; cdecl; external; function g_key_file_get_integer(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gint; cdecl; external; function g_key_file_get_integer_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; length: Pgsize; error: PPGError): Pgint; cdecl; external; function g_key_file_get_keys(key_file: PGKeyFile; group_name: Pgchar; length: Pgsize; error: PPGError): PPgchar; cdecl; external; function g_key_file_get_locale_string(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; locale: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_key_file_get_locale_string_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; locale: Pgchar; length: Pgsize; error: PPGError): PPgchar; cdecl; external; function g_key_file_get_start_group(key_file: PGKeyFile): Pgchar; cdecl; external; function g_key_file_get_string(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_key_file_get_string_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; length: Pgsize; error: PPGError): PPgchar; cdecl; external; function g_key_file_get_type: TGType; cdecl; external; function g_key_file_get_uint64(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): guint64; cdecl; external; function g_key_file_get_value(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_key_file_has_group(key_file: PGKeyFile; group_name: Pgchar): gboolean; cdecl; external; function g_key_file_has_key(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gboolean; cdecl; external; function g_key_file_load_from_data(key_file: PGKeyFile; data: Pgchar; length: gsize; flags: TGKeyFileFlags; error: PPGError): gboolean; cdecl; external; function g_key_file_load_from_data_dirs(key_file: PGKeyFile; file_: Pgchar; full_path: PPgchar; flags: TGKeyFileFlags; error: PPGError): gboolean; cdecl; external; function g_key_file_load_from_dirs(key_file: PGKeyFile; file_: Pgchar; search_dirs: PPgchar; full_path: PPgchar; flags: TGKeyFileFlags; error: PPGError): gboolean; cdecl; external; function g_key_file_load_from_file(key_file: PGKeyFile; file_: Pgchar; flags: TGKeyFileFlags; error: PPGError): gboolean; cdecl; external; function g_key_file_new: PGKeyFile; cdecl; external; function g_key_file_ref(key_file: PGKeyFile): PGKeyFile; cdecl; external; function g_key_file_remove_comment(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gboolean; cdecl; external; function g_key_file_remove_group(key_file: PGKeyFile; group_name: Pgchar; error: PPGError): gboolean; cdecl; external; function g_key_file_remove_key(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; error: PPGError): gboolean; cdecl; external; function g_key_file_set_comment(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; comment: Pgchar; error: PPGError): gboolean; cdecl; external; function g_key_file_to_data(key_file: PGKeyFile; length: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_list_alloc: PGList; cdecl; external; function g_list_append(list: PGList; data: gpointer): PGList; cdecl; external; function g_list_concat(list1: PGList; list2: PGList): PGList; cdecl; external; function g_list_copy(list: PGList): PGList; cdecl; external; function g_list_copy_deep(list: PGList; func: TGCopyFunc; user_data: gpointer): PGList; cdecl; external; function g_list_delete_link(list: PGList; link_: PGList): PGList; cdecl; external; function g_list_find(list: PGList; data: Pgpointer): PGList; cdecl; external; function g_list_find_custom(list: PGList; data: Pgpointer; func: TGCompareFunc): PGList; cdecl; external; function g_list_first(list: PGList): PGList; cdecl; external; function g_list_index(list: PGList; data: Pgpointer): gint; cdecl; external; function g_list_insert(list: PGList; data: gpointer; position: gint): PGList; cdecl; external; function g_list_insert_before(list: PGList; sibling: PGList; data: gpointer): PGList; cdecl; external; function g_list_insert_sorted(list: PGList; data: gpointer; func: TGCompareFunc): PGList; cdecl; external; function g_list_insert_sorted_with_data(list: PGList; data: gpointer; func: TGCompareDataFunc; user_data: gpointer): PGList; cdecl; external; function g_list_last(list: PGList): PGList; cdecl; external; function g_list_length(list: PGList): guint; cdecl; external; function g_list_nth(list: PGList; n: guint): PGList; cdecl; external; function g_list_nth_data(list: PGList; n: guint): gpointer; cdecl; external; function g_list_nth_prev(list: PGList; n: guint): PGList; cdecl; external; function g_list_position(list: PGList; llink: PGList): gint; cdecl; external; function g_list_prepend(list: PGList; data: gpointer): PGList; cdecl; external; function g_list_remove(list: PGList; data: Pgpointer): PGList; cdecl; external; function g_list_remove_all(list: PGList; data: Pgpointer): PGList; cdecl; external; function g_list_remove_link(list: PGList; llink: PGList): PGList; cdecl; external; function g_list_reverse(list: PGList): PGList; cdecl; external; function g_list_sort(list: PGList; compare_func: TGCompareFunc): PGList; cdecl; external; function g_list_sort_with_data(list: PGList; compare_func: TGCompareDataFunc; user_data: gpointer): PGList; cdecl; external; function g_listenv: PPgchar; cdecl; external; function g_locale_from_utf8(utf8string: Pgchar; len: gssize; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_locale_to_utf8(opsysstring: Pgchar; len: gssize; bytes_read: Pgsize; bytes_written: Pgsize; error: PPGError): Pgchar; cdecl; external; function g_log_set_always_fatal(fatal_mask: TGLogLevelFlags): TGLogLevelFlags; cdecl; external; function g_log_set_default_handler(log_func: TGLogFunc; user_data: gpointer): TGLogFunc; cdecl; external; function g_log_set_fatal_mask(log_domain: Pgchar; fatal_mask: TGLogLevelFlags): TGLogLevelFlags; cdecl; external; function g_log_set_handler(log_domain: Pgchar; log_levels: TGLogLevelFlags; log_func: TGLogFunc; user_data: gpointer): guint; cdecl; external; function g_main_context_acquire(context: PGMainContext): gboolean; cdecl; external; function g_main_context_check(context: PGMainContext; max_priority: gint; fds: PGPollFD; n_fds: gint): gint; cdecl; external; function g_main_context_default: PGMainContext; cdecl; external; function g_main_context_find_source_by_funcs_user_data(context: PGMainContext; funcs: PGSourceFuncs; user_data: gpointer): PGSource; cdecl; external; function g_main_context_find_source_by_id(context: PGMainContext; source_id: guint): PGSource; cdecl; external; function g_main_context_find_source_by_user_data(context: PGMainContext; user_data: gpointer): PGSource; cdecl; external; function g_main_context_get_poll_func(context: PGMainContext): TGPollFunc; cdecl; external; function g_main_context_get_thread_default: PGMainContext; cdecl; external; function g_main_context_get_type: TGType; cdecl; external; function g_main_context_is_owner(context: PGMainContext): gboolean; cdecl; external; function g_main_context_iteration(context: PGMainContext; may_block: gboolean): gboolean; cdecl; external; function g_main_context_new: PGMainContext; cdecl; external; function g_main_context_pending(context: PGMainContext): gboolean; cdecl; external; function g_main_context_prepare(context: PGMainContext; priority: Pgint): gboolean; cdecl; external; function g_main_context_query(context: PGMainContext; max_priority: gint; timeout_: Pgint; fds: PGPollFD; n_fds: gint): gint; cdecl; external; function g_main_context_ref(context: PGMainContext): PGMainContext; cdecl; external; function g_main_context_ref_thread_default: PGMainContext; cdecl; external; function g_main_context_wait(context: PGMainContext; cond: PGCond; mutex: PGMutex): gboolean; cdecl; external; function g_main_current_source: PGSource; cdecl; external; function g_main_depth: gint; cdecl; external; function g_main_loop_get_context(loop: PGMainLoop): PGMainContext; cdecl; external; function g_main_loop_get_type: TGType; cdecl; external; function g_main_loop_is_running(loop: PGMainLoop): gboolean; cdecl; external; function g_main_loop_new(context: PGMainContext; is_running: gboolean): PGMainLoop; cdecl; external; function g_main_loop_ref(loop: PGMainLoop): PGMainLoop; cdecl; external; function g_malloc(n_bytes: gsize): gpointer; cdecl; external; function g_malloc0(n_bytes: gsize): gpointer; cdecl; external; function g_malloc0_n(n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; external; function g_malloc_n(n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; external; function g_mapped_file_get_bytes(file_: PGMappedFile): PGBytes; cdecl; external; function g_mapped_file_get_contents(file_: PGMappedFile): Pgchar; cdecl; external; function g_mapped_file_get_length(file_: PGMappedFile): gsize; cdecl; external; function g_mapped_file_new(filename: Pgchar; writable: gboolean; error: PPGError): PGMappedFile; cdecl; external; function g_mapped_file_new_from_fd(fd: gint; writable: gboolean; error: PPGError): PGMappedFile; cdecl; external; function g_mapped_file_ref(file_: PGMappedFile): PGMappedFile; cdecl; external; function g_markup_collect_attributes(element_name: Pgchar; attribute_names: PPgchar; attribute_values: PPgchar; error: PPGError; first_type: TGMarkupCollectType; first_attr: Pgchar; args: array of const): gboolean; cdecl; external; function g_markup_error_quark: TGQuark; cdecl; external; function g_markup_escape_text(text: Pgchar; length: gssize): Pgchar; cdecl; external; function g_markup_parse_context_end_parse(context: PGMarkupParseContext; error: PPGError): gboolean; cdecl; external; function g_markup_parse_context_get_element(context: PGMarkupParseContext): Pgchar; cdecl; external; function g_markup_parse_context_get_element_stack(context: PGMarkupParseContext): PGSList; cdecl; external; function g_markup_parse_context_get_type: TGType; cdecl; external; function g_markup_parse_context_get_user_data(context: PGMarkupParseContext): gpointer; cdecl; external; function g_markup_parse_context_new(parser: PGMarkupParser; flags: TGMarkupParseFlags; user_data: gpointer; user_data_dnotify: TGDestroyNotify): PGMarkupParseContext; cdecl; external; function g_markup_parse_context_parse(context: PGMarkupParseContext; text: Pgchar; text_len: gssize; error: PPGError): gboolean; cdecl; external; function g_markup_parse_context_pop(context: PGMarkupParseContext): gpointer; cdecl; external; function g_markup_parse_context_ref(context: PGMarkupParseContext): PGMarkupParseContext; cdecl; external; function g_markup_printf_escaped(format: Pgchar; args: array of const): Pgchar; cdecl; external; function g_markup_vprintf_escaped(format: Pgchar; args: Tva_list): Pgchar; cdecl; external; function g_match_info_expand_references(match_info: PGMatchInfo; string_to_expand: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_match_info_fetch(match_info: PGMatchInfo; match_num: gint): Pgchar; cdecl; external; function g_match_info_fetch_all(match_info: PGMatchInfo): PPgchar; cdecl; external; function g_match_info_fetch_named(match_info: PGMatchInfo; name: Pgchar): Pgchar; cdecl; external; function g_match_info_fetch_named_pos(match_info: PGMatchInfo; name: Pgchar; start_pos: Pgint; end_pos: Pgint): gboolean; cdecl; external; function g_match_info_fetch_pos(match_info: PGMatchInfo; match_num: gint; start_pos: Pgint; end_pos: Pgint): gboolean; cdecl; external; function g_match_info_get_match_count(match_info: PGMatchInfo): gint; cdecl; external; function g_match_info_get_regex(match_info: PGMatchInfo): PGRegex; cdecl; external; function g_match_info_get_string(match_info: PGMatchInfo): Pgchar; cdecl; external; function g_match_info_get_type: TGType; cdecl; external; function g_match_info_is_partial_match(match_info: PGMatchInfo): gboolean; cdecl; external; function g_match_info_matches(match_info: PGMatchInfo): gboolean; cdecl; external; function g_match_info_next(match_info: PGMatchInfo; error: PPGError): gboolean; cdecl; external; function g_match_info_ref(match_info: PGMatchInfo): PGMatchInfo; cdecl; external; function g_mem_is_system_malloc: gboolean; cdecl; external; function g_memdup(mem: Pgpointer; byte_size: guint): gpointer; cdecl; external; function g_mkdir_with_parents(pathname: Pgchar; mode: gint): gint; cdecl; external; function g_mkdtemp(tmpl: Pgchar): Pgchar; cdecl; external; function g_mkdtemp_full(tmpl: Pgchar; mode: gint): Pgchar; cdecl; external; function g_mkstemp(tmpl: Pgchar): gint; cdecl; external; function g_mkstemp_full(tmpl: Pgchar; flags: gint; mode: gint): gint; cdecl; external; function g_mutex_trylock(mutex: PGMutex): gboolean; cdecl; external; function g_node_child_index(node: PGNode; data: gpointer): gint; cdecl; external; function g_node_child_position(node: PGNode; child: PGNode): gint; cdecl; external; function g_node_copy(node: PGNode): PGNode; cdecl; external; function g_node_copy_deep(node: PGNode; copy_func: TGCopyFunc; data: gpointer): PGNode; cdecl; external; function g_node_depth(node: PGNode): guint; cdecl; external; function g_node_find(root: PGNode; order: TGTraverseType; flags: TGTraverseFlags; data: gpointer): PGNode; cdecl; external; function g_node_find_child(node: PGNode; flags: TGTraverseFlags; data: gpointer): PGNode; cdecl; external; function g_node_first_sibling(node: PGNode): PGNode; cdecl; external; function g_node_get_root(node: PGNode): PGNode; cdecl; external; function g_node_insert(parent: PGNode; position: gint; node: PGNode): PGNode; cdecl; external; function g_node_insert_after(parent: PGNode; sibling: PGNode; node: PGNode): PGNode; cdecl; external; function g_node_insert_before(parent: PGNode; sibling: PGNode; node: PGNode): PGNode; cdecl; external; function g_node_is_ancestor(node: PGNode; descendant: PGNode): gboolean; cdecl; external; function g_node_last_child(node: PGNode): PGNode; cdecl; external; function g_node_last_sibling(node: PGNode): PGNode; cdecl; external; function g_node_max_height(root: PGNode): guint; cdecl; external; function g_node_n_children(node: PGNode): guint; cdecl; external; function g_node_n_nodes(root: PGNode; flags: TGTraverseFlags): guint; cdecl; external; function g_node_new(data: gpointer): PGNode; cdecl; external; function g_node_nth_child(node: PGNode; n: guint): PGNode; cdecl; external; function g_node_prepend(parent: PGNode; node: PGNode): PGNode; cdecl; external; function g_once_impl(once: PGOnce; func: TGThreadFunc; arg: gpointer): gpointer; cdecl; external; function g_once_init_enter(location: Pgpointer): gboolean; cdecl; external; function g_option_context_get_description(context: PGOptionContext): Pgchar; cdecl; external; function g_option_context_get_help(context: PGOptionContext; main_help: gboolean; group: PGOptionGroup): Pgchar; cdecl; external; function g_option_context_get_help_enabled(context: PGOptionContext): gboolean; cdecl; external; function g_option_context_get_ignore_unknown_options(context: PGOptionContext): gboolean; cdecl; external; function g_option_context_get_main_group(context: PGOptionContext): PGOptionGroup; cdecl; external; function g_option_context_get_summary(context: PGOptionContext): Pgchar; cdecl; external; function g_option_context_new(parameter_string: Pgchar): PGOptionContext; cdecl; external; function g_option_context_parse(context: PGOptionContext; argc: Pgint; argv: PPPgchar; error: PPGError): gboolean; cdecl; external; function g_option_error_quark: TGQuark; cdecl; external; function g_option_group_new(name: Pgchar; description: Pgchar; help_description: Pgchar; user_data: gpointer; destroy_: TGDestroyNotify): PGOptionGroup; cdecl; external; function g_parse_debug_string(string_: Pgchar; keys: PGDebugKey; nkeys: guint): guint; cdecl; external; function g_path_get_basename(file_name: Pgchar): Pgchar; cdecl; external; function g_path_get_dirname(file_name: Pgchar): Pgchar; cdecl; external; function g_path_is_absolute(file_name: Pgchar): gboolean; cdecl; external; function g_path_skip_root(file_name: Pgchar): Pgchar; cdecl; external; function g_pattern_match(pspec: PGPatternSpec; string_length: guint; string_: Pgchar; string_reversed: Pgchar): gboolean; cdecl; external; function g_pattern_match_simple(pattern: Pgchar; string_: Pgchar): gboolean; cdecl; external; function g_pattern_match_string(pspec: PGPatternSpec; string_: Pgchar): gboolean; cdecl; external; function g_pattern_spec_equal(pspec1: PGPatternSpec; pspec2: PGPatternSpec): gboolean; cdecl; external; function g_pattern_spec_new(pattern: Pgchar): PGPatternSpec; cdecl; external; function g_pointer_bit_trylock(address: Pgpointer; lock_bit: gint): gboolean; cdecl; external; function g_poll(fds: PGPollFD; nfds: guint; timeout: gint): gint; cdecl; external; function g_pollfd_get_type: TGType; cdecl; external; function g_printf(format: Pgchar; args: array of const): gint; cdecl; external; function g_printf_string_upper_bound(format: Pgchar; args: Tva_list): gsize; cdecl; external; function g_private_get(key: PGPrivate): gpointer; cdecl; external; function g_ptr_array_free(array_: Pgpointer; free_seg: gboolean): Pgpointer; cdecl; external; function g_ptr_array_get_type: TGType; cdecl; external; function g_ptr_array_new: Pgpointer; cdecl; external; function g_ptr_array_new_full(reserved_size: guint; element_free_func: TGDestroyNotify): Pgpointer; cdecl; external; function g_ptr_array_new_with_free_func(element_free_func: TGDestroyNotify): Pgpointer; cdecl; external; function g_ptr_array_ref(array_: Pgpointer): Pgpointer; cdecl; external; function g_ptr_array_remove(array_: Pgpointer; data: gpointer): gboolean; cdecl; external; function g_ptr_array_remove_fast(array_: Pgpointer; data: gpointer): gboolean; cdecl; external; function g_ptr_array_remove_index(array_: Pgpointer; index_: guint): gpointer; cdecl; external; function g_ptr_array_remove_index_fast(array_: Pgpointer; index_: guint): gpointer; cdecl; external; function g_ptr_array_sized_new(reserved_size: guint): Pgpointer; cdecl; external; function g_quark_from_static_string(string_: Pgchar): TGQuark; cdecl; external; function g_quark_from_string(string_: Pgchar): TGQuark; cdecl; external; function g_quark_to_string(quark: TGQuark): Pgchar; cdecl; external; function g_quark_try_string(string_: Pgchar): TGQuark; cdecl; external; function g_queue_copy(queue: PGQueue): PGQueue; cdecl; external; function g_queue_find(queue: PGQueue; data: Pgpointer): PGList; cdecl; external; function g_queue_find_custom(queue: PGQueue; data: Pgpointer; func: TGCompareFunc): PGList; cdecl; external; function g_queue_get_length(queue: PGQueue): guint; cdecl; external; function g_queue_index(queue: PGQueue; data: Pgpointer): gint; cdecl; external; function g_queue_is_empty(queue: PGQueue): gboolean; cdecl; external; function g_queue_link_index(queue: PGQueue; link_: PGList): gint; cdecl; external; function g_queue_new: PGQueue; cdecl; external; function g_queue_peek_head(queue: PGQueue): gpointer; cdecl; external; function g_queue_peek_head_link(queue: PGQueue): PGList; cdecl; external; function g_queue_peek_nth(queue: PGQueue; n: guint): gpointer; cdecl; external; function g_queue_peek_nth_link(queue: PGQueue; n: guint): PGList; cdecl; external; function g_queue_peek_tail(queue: PGQueue): gpointer; cdecl; external; function g_queue_peek_tail_link(queue: PGQueue): PGList; cdecl; external; function g_queue_pop_head(queue: PGQueue): gpointer; cdecl; external; function g_queue_pop_head_link(queue: PGQueue): PGList; cdecl; external; function g_queue_pop_nth(queue: PGQueue; n: guint): gpointer; cdecl; external; function g_queue_pop_nth_link(queue: PGQueue; n: guint): PGList; cdecl; external; function g_queue_pop_tail(queue: PGQueue): gpointer; cdecl; external; function g_queue_pop_tail_link(queue: PGQueue): PGList; cdecl; external; function g_queue_remove(queue: PGQueue; data: Pgpointer): gboolean; cdecl; external; function g_queue_remove_all(queue: PGQueue; data: Pgpointer): guint; cdecl; external; function g_rand_copy(rand_: PGRand): PGRand; cdecl; external; function g_rand_double(rand_: PGRand): gdouble; cdecl; external; function g_rand_double_range(rand_: PGRand; begin_: gdouble; end_: gdouble): gdouble; cdecl; external; function g_rand_int(rand_: PGRand): guint32; cdecl; external; function g_rand_int_range(rand_: PGRand; begin_: gint32; end_: gint32): gint32; cdecl; external; function g_rand_new: PGRand; cdecl; external; function g_rand_new_with_seed(seed: guint32): PGRand; cdecl; external; function g_rand_new_with_seed_array(seed: Pguint32; seed_length: guint): PGRand; cdecl; external; function g_random_double: gdouble; cdecl; external; function g_random_double_range(begin_: gdouble; end_: gdouble): gdouble; cdecl; external; function g_random_int: guint32; cdecl; external; function g_random_int_range(begin_: gint32; end_: gint32): gint32; cdecl; external; function g_realloc(mem: gpointer; n_bytes: gsize): gpointer; cdecl; external; function g_realloc_n(mem: gpointer; n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; external; function g_rec_mutex_trylock(rec_mutex: PGRecMutex): gboolean; cdecl; external; function g_regex_check_replacement(replacement: Pgchar; has_references: Pgboolean; error: PPGError): gboolean; cdecl; external; function g_regex_error_quark: TGQuark; cdecl; external; function g_regex_escape_nul(string_: Pgchar; length: gint): Pgchar; cdecl; external; function g_regex_escape_string(string_: Pgchar; length: gint): Pgchar; cdecl; external; function g_regex_get_capture_count(regex: PGRegex): gint; cdecl; external; function g_regex_get_compile_flags(regex: PGRegex): TGRegexCompileFlags; cdecl; external; function g_regex_get_has_cr_or_lf(regex: PGRegex): gboolean; cdecl; external; function g_regex_get_match_flags(regex: PGRegex): TGRegexMatchFlags; cdecl; external; function g_regex_get_max_backref(regex: PGRegex): gint; cdecl; external; function g_regex_get_pattern(regex: PGRegex): Pgchar; cdecl; external; function g_regex_get_string_number(regex: PGRegex; name: Pgchar): gint; cdecl; external; function g_regex_get_type: TGType; cdecl; external; function g_regex_match(regex: PGRegex; string_: Pgchar; match_options: TGRegexMatchFlags; match_info: PPGMatchInfo): gboolean; cdecl; external; function g_regex_match_all(regex: PGRegex; string_: Pgchar; match_options: TGRegexMatchFlags; match_info: PPGMatchInfo): gboolean; cdecl; external; function g_regex_match_all_full(regex: PGRegex; string_: Pgchar; string_len: gssize; start_position: gint; match_options: TGRegexMatchFlags; match_info: PPGMatchInfo; error: PPGError): gboolean; cdecl; external; function g_regex_match_full(regex: PGRegex; string_: Pgchar; string_len: gssize; start_position: gint; match_options: TGRegexMatchFlags; match_info: PPGMatchInfo; error: PPGError): gboolean; cdecl; external; function g_regex_match_simple(pattern: Pgchar; string_: Pgchar; compile_options: TGRegexCompileFlags; match_options: TGRegexMatchFlags): gboolean; cdecl; external; function g_regex_new(pattern: Pgchar; compile_options: TGRegexCompileFlags; match_options: TGRegexMatchFlags; error: PPGError): PGRegex; cdecl; external; function g_regex_ref(regex: PGRegex): PGRegex; cdecl; external; function g_regex_replace(regex: PGRegex; string_: Pgchar; string_len: gssize; start_position: gint; replacement: Pgchar; match_options: TGRegexMatchFlags; error: PPGError): Pgchar; cdecl; external; function g_regex_replace_eval(regex: PGRegex; string_: Pgchar; string_len: gssize; start_position: gint; match_options: TGRegexMatchFlags; eval: TGRegexEvalCallback; user_data: gpointer; error: PPGError): Pgchar; cdecl; external; function g_regex_replace_literal(regex: PGRegex; string_: Pgchar; string_len: gssize; start_position: gint; replacement: Pgchar; match_options: TGRegexMatchFlags; error: PPGError): Pgchar; cdecl; external; function g_regex_split(regex: PGRegex; string_: Pgchar; match_options: TGRegexMatchFlags): PPgchar; cdecl; external; function g_regex_split_full(regex: PGRegex; string_: Pgchar; string_len: gssize; start_position: gint; match_options: TGRegexMatchFlags; max_tokens: gint; error: PPGError): PPgchar; cdecl; external; function g_regex_split_simple(pattern: Pgchar; string_: Pgchar; compile_options: TGRegexCompileFlags; match_options: TGRegexMatchFlags): PPgchar; cdecl; external; function g_rmdir(filename: Pgchar): gint; cdecl; external; function g_rw_lock_reader_trylock(rw_lock: PGRWLock): gboolean; cdecl; external; function g_rw_lock_writer_trylock(rw_lock: PGRWLock): gboolean; cdecl; external; function g_scanner_cur_line(scanner: PGScanner): guint; cdecl; external; function g_scanner_cur_position(scanner: PGScanner): guint; cdecl; external; function g_scanner_cur_token(scanner: PGScanner): TGTokenType; cdecl; external; function g_scanner_cur_value(scanner: PGScanner): TGTokenValue; cdecl; external; function g_scanner_eof(scanner: PGScanner): gboolean; cdecl; external; function g_scanner_get_next_token(scanner: PGScanner): TGTokenType; cdecl; external; function g_scanner_lookup_symbol(scanner: PGScanner; symbol: Pgchar): gpointer; cdecl; external; function g_scanner_new(config_templ: PGScannerConfig): PGScanner; cdecl; external; function g_scanner_peek_next_token(scanner: PGScanner): TGTokenType; cdecl; external; function g_scanner_scope_lookup_symbol(scanner: PGScanner; scope_id: guint; symbol: Pgchar): gpointer; cdecl; external; function g_scanner_set_scope(scanner: PGScanner; scope_id: guint): guint; cdecl; external; function g_sequence_append(seq: PGSequence; data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_get(iter: PGSequenceIter): gpointer; cdecl; external; function g_sequence_get_begin_iter(seq: PGSequence): PGSequenceIter; cdecl; external; function g_sequence_get_end_iter(seq: PGSequence): PGSequenceIter; cdecl; external; function g_sequence_get_iter_at_pos(seq: PGSequence; pos: gint): PGSequenceIter; cdecl; external; function g_sequence_get_length(seq: PGSequence): gint; cdecl; external; function g_sequence_insert_before(iter: PGSequenceIter; data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_insert_sorted(seq: PGSequence; data: gpointer; cmp_func: TGCompareDataFunc; cmp_data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_insert_sorted_iter(seq: PGSequence; data: gpointer; iter_cmp: TGSequenceIterCompareFunc; cmp_data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_iter_compare(a: PGSequenceIter; b: PGSequenceIter): gint; cdecl; external; function g_sequence_iter_get_position(iter: PGSequenceIter): gint; cdecl; external; function g_sequence_iter_get_sequence(iter: PGSequenceIter): PGSequence; cdecl; external; function g_sequence_iter_is_begin(iter: PGSequenceIter): gboolean; cdecl; external; function g_sequence_iter_is_end(iter: PGSequenceIter): gboolean; cdecl; external; function g_sequence_iter_move(iter: PGSequenceIter; delta: gint): PGSequenceIter; cdecl; external; function g_sequence_iter_next(iter: PGSequenceIter): PGSequenceIter; cdecl; external; function g_sequence_iter_prev(iter: PGSequenceIter): PGSequenceIter; cdecl; external; function g_sequence_lookup(seq: PGSequence; data: gpointer; cmp_func: TGCompareDataFunc; cmp_data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_lookup_iter(seq: PGSequence; data: gpointer; iter_cmp: TGSequenceIterCompareFunc; cmp_data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_new(data_destroy: TGDestroyNotify): PGSequence; cdecl; external; function g_sequence_prepend(seq: PGSequence; data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_range_get_midpoint(begin_: PGSequenceIter; end_: PGSequenceIter): PGSequenceIter; cdecl; external; function g_sequence_search(seq: PGSequence; data: gpointer; cmp_func: TGCompareDataFunc; cmp_data: gpointer): PGSequenceIter; cdecl; external; function g_sequence_search_iter(seq: PGSequence; data: gpointer; iter_cmp: TGSequenceIterCompareFunc; cmp_data: gpointer): PGSequenceIter; cdecl; external; function g_set_print_handler(func: TGPrintFunc): TGPrintFunc; cdecl; external; function g_set_printerr_handler(func: TGPrintFunc): TGPrintFunc; cdecl; external; function g_setenv(variable: Pgchar; value: Pgchar; overwrite: gboolean): gboolean; cdecl; external; function g_shell_error_quark: TGQuark; cdecl; external; function g_shell_parse_argv(command_line: Pgchar; argcp: Pgint; argvp: PPPgchar; error: PPGError): gboolean; cdecl; external; function g_shell_quote(unquoted_string: Pgchar): Pgchar; cdecl; external; function g_shell_unquote(quoted_string: Pgchar; error: PPGError): Pgchar; cdecl; external; function g_slice_alloc(block_size: gsize): gpointer; cdecl; external; function g_slice_alloc0(block_size: gsize): gpointer; cdecl; external; function g_slice_copy(block_size: gsize; mem_block: Pgpointer): gpointer; cdecl; external; function g_slice_get_config(ckey: TGSliceConfig): gint64; cdecl; external; function g_slice_get_config_state(ckey: TGSliceConfig; address: gint64; n_values: Pguint): Pgint64; cdecl; external; function g_slist_alloc: PGSList; cdecl; external; function g_slist_append(list: PGSList; data: gpointer): PGSList; cdecl; external; function g_slist_concat(list1: PGSList; list2: PGSList): PGSList; cdecl; external; function g_slist_copy(list: PGSList): PGSList; cdecl; external; function g_slist_copy_deep(list: PGSList; func: TGCopyFunc; user_data: gpointer): PGSList; cdecl; external; function g_slist_delete_link(list: PGSList; link_: PGSList): PGSList; cdecl; external; function g_slist_find(list: PGSList; data: Pgpointer): PGSList; cdecl; external; function g_slist_find_custom(list: PGSList; data: Pgpointer; func: TGCompareFunc): PGSList; cdecl; external; function g_slist_index(list: PGSList; data: Pgpointer): gint; cdecl; external; function g_slist_insert(list: PGSList; data: gpointer; position: gint): PGSList; cdecl; external; function g_slist_insert_before(slist: PGSList; sibling: PGSList; data: gpointer): PGSList; cdecl; external; function g_slist_insert_sorted(list: PGSList; data: gpointer; func: TGCompareFunc): PGSList; cdecl; external; function g_slist_insert_sorted_with_data(list: PGSList; data: gpointer; func: TGCompareDataFunc; user_data: gpointer): PGSList; cdecl; external; function g_slist_last(list: PGSList): PGSList; cdecl; external; function g_slist_length(list: PGSList): guint; cdecl; external; function g_slist_nth(list: PGSList; n: guint): PGSList; cdecl; external; function g_slist_nth_data(list: PGSList; n: guint): gpointer; cdecl; external; function g_slist_position(list: PGSList; llink: PGSList): gint; cdecl; external; function g_slist_prepend(list: PGSList; data: gpointer): PGSList; cdecl; external; function g_slist_remove(list: PGSList; data: Pgpointer): PGSList; cdecl; external; function g_slist_remove_all(list: PGSList; data: Pgpointer): PGSList; cdecl; external; function g_slist_remove_link(list: PGSList; link_: PGSList): PGSList; cdecl; external; function g_slist_reverse(list: PGSList): PGSList; cdecl; external; function g_slist_sort(list: PGSList; compare_func: TGCompareFunc): PGSList; cdecl; external; function g_slist_sort_with_data(list: PGSList; compare_func: TGCompareDataFunc; user_data: gpointer): PGSList; cdecl; external; function g_snprintf(string_: Pgchar; n: gulong; format: Pgchar; args: array of const): gint; cdecl; external; function g_source_add_unix_fd(source: PGSource; fd: gint; events: TGIOCondition): gpointer; cdecl; external; function g_source_attach(source: PGSource; context: PGMainContext): guint; cdecl; external; function g_source_get_can_recurse(source: PGSource): gboolean; cdecl; external; function g_source_get_context(source: PGSource): PGMainContext; cdecl; external; function g_source_get_id(source: PGSource): guint; cdecl; external; function g_source_get_name(source: PGSource): Pgchar; cdecl; external; function g_source_get_priority(source: PGSource): gint; cdecl; external; function g_source_get_ready_time(source: PGSource): gint64; cdecl; external; function g_source_get_time(source: PGSource): gint64; cdecl; external; function g_source_get_type: TGType; cdecl; external; function g_source_is_destroyed(source: PGSource): gboolean; cdecl; external; function g_source_new(source_funcs: PGSourceFuncs; struct_size: guint): PGSource; cdecl; external; function g_source_query_unix_fd(source: PGSource; tag: gpointer): TGIOCondition; cdecl; external; function g_source_ref(source: PGSource): PGSource; cdecl; external; function g_source_remove(tag: guint): gboolean; cdecl; external; function g_source_remove_by_funcs_user_data(funcs: PGSourceFuncs; user_data: gpointer): gboolean; cdecl; external; function g_source_remove_by_user_data(user_data: gpointer): gboolean; cdecl; external; function g_spaced_primes_closest(num: guint): guint; cdecl; external; function g_spawn_async(working_directory: Pgchar; argv: PPgchar; envp: PPgchar; flags: TGSpawnFlags; child_setup: TGSpawnChildSetupFunc; user_data: gpointer; child_pid: PGPid; error: PPGError): gboolean; cdecl; external; function g_spawn_async_with_pipes(working_directory: Pgchar; argv: PPgchar; envp: PPgchar; flags: TGSpawnFlags; child_setup: TGSpawnChildSetupFunc; user_data: gpointer; child_pid: PGPid; standard_input: Pgint; standard_output: Pgint; standard_error: Pgint; error: PPGError): gboolean; cdecl; external; function g_spawn_check_exit_status(exit_status: gint; error: PPGError): gboolean; cdecl; external; function g_spawn_command_line_async(command_line: Pgchar; error: PPGError): gboolean; cdecl; external; function g_spawn_command_line_sync(command_line: Pgchar; standard_output: PPgchar; standard_error: PPgchar; exit_status: Pgint; error: PPGError): gboolean; cdecl; external; function g_spawn_error_quark: TGQuark; cdecl; external; function g_spawn_exit_error_quark: TGQuark; cdecl; external; function g_spawn_sync(working_directory: Pgchar; argv: PPgchar; envp: PPgchar; flags: TGSpawnFlags; child_setup: TGSpawnChildSetupFunc; user_data: gpointer; standard_output: PPgchar; standard_error: PPgchar; exit_status: Pgint; error: PPGError): gboolean; cdecl; external; function g_sprintf(string_: Pgchar; format: Pgchar; args: array of const): gint; cdecl; external; function g_stpcpy(dest: Pgchar; src: Pgchar): Pgchar; cdecl; external; function g_str_equal(v1: Pgpointer; v2: Pgpointer): gboolean; cdecl; external; function g_str_has_prefix(str: Pgchar; prefix: Pgchar): gboolean; cdecl; external; function g_str_has_suffix(str: Pgchar; suffix: Pgchar): gboolean; cdecl; external; function g_str_hash(v: Pgpointer): guint; cdecl; external; function g_strcanon(string_: Pgchar; valid_chars: Pgchar; substitutor: gchar): Pgchar; cdecl; external; function g_strcasecmp(s1: Pgchar; s2: Pgchar): gint; cdecl; external; function g_strchomp(string_: Pgchar): Pgchar; cdecl; external; function g_strchug(string_: Pgchar): Pgchar; cdecl; external; function g_strcmp0(str1: Pgchar; str2: Pgchar): gint; cdecl; external; function g_strcompress(source: Pgchar): Pgchar; cdecl; external; function g_strconcat(string1: Pgchar; args: array of const): Pgchar; cdecl; external; function g_strdelimit(string_: Pgchar; delimiters: Pgchar; new_delimiter: gchar): Pgchar; cdecl; external; function g_strdown(string_: Pgchar): Pgchar; cdecl; external; function g_strdup(str: Pgchar): Pgchar; cdecl; external; function g_strdup_printf(format: Pgchar; args: array of const): Pgchar; cdecl; external; function g_strdup_vprintf(format: Pgchar; args: Tva_list): Pgchar; cdecl; external; function g_strdupv(str_array: PPgchar): PPgchar; cdecl; external; function g_strerror(errnum: gint): Pgchar; cdecl; external; function g_strescape(source: Pgchar; exceptions: Pgchar): Pgchar; cdecl; external; function g_string_append(string_: PGString; val: Pgchar): PGString; cdecl; external; function g_string_append_c(string_: PGString; c: gchar): PGString; cdecl; external; function g_string_append_len(string_: PGString; val: Pgchar; len: gssize): PGString; cdecl; external; function g_string_append_unichar(string_: PGString; wc: gunichar): PGString; cdecl; external; function g_string_append_uri_escaped(string_: PGString; unescaped: Pgchar; reserved_chars_allowed: Pgchar; allow_utf8: gboolean): PGString; cdecl; external; function g_string_ascii_down(string_: PGString): PGString; cdecl; external; function g_string_ascii_up(string_: PGString): PGString; cdecl; external; function g_string_assign(string_: PGString; rval: Pgchar): PGString; cdecl; external; function g_string_chunk_insert(chunk: PGStringChunk; string_: Pgchar): Pgchar; cdecl; external; function g_string_chunk_insert_const(chunk: PGStringChunk; string_: Pgchar): Pgchar; cdecl; external; function g_string_chunk_insert_len(chunk: PGStringChunk; string_: Pgchar; len: gssize): Pgchar; cdecl; external; function g_string_chunk_new(size: gsize): PGStringChunk; cdecl; external; function g_string_equal(v: PGString; v2: PGString): gboolean; cdecl; external; function g_string_erase(string_: PGString; pos: gssize; len: gssize): PGString; cdecl; external; function g_string_free(string_: PGString; free_segment: gboolean): Pgchar; cdecl; external; function g_string_free_to_bytes(string_: PGString): PGBytes; cdecl; external; function g_string_hash(str: PGString): guint; cdecl; external; function g_string_insert(string_: PGString; pos: gssize; val: Pgchar): PGString; cdecl; external; function g_string_insert_c(string_: PGString; pos: gssize; c: gchar): PGString; cdecl; external; function g_string_insert_len(string_: PGString; pos: gssize; val: Pgchar; len: gssize): PGString; cdecl; external; function g_string_insert_unichar(string_: PGString; pos: gssize; wc: gunichar): PGString; cdecl; external; function g_string_new(init: Pgchar): PGString; cdecl; external; function g_string_new_len(init: Pgchar; len: gssize): PGString; cdecl; external; function g_string_overwrite(string_: PGString; pos: gsize; val: Pgchar): PGString; cdecl; external; function g_string_overwrite_len(string_: PGString; pos: gsize; val: Pgchar; len: gssize): PGString; cdecl; external; function g_string_prepend(string_: PGString; val: Pgchar): PGString; cdecl; external; function g_string_prepend_c(string_: PGString; c: gchar): PGString; cdecl; external; function g_string_prepend_len(string_: PGString; val: Pgchar; len: gssize): PGString; cdecl; external; function g_string_prepend_unichar(string_: PGString; wc: gunichar): PGString; cdecl; external; function g_string_set_size(string_: PGString; len: gsize): PGString; cdecl; external; function g_string_sized_new(dfl_size: gsize): PGString; cdecl; external; function g_string_truncate(string_: PGString; len: gsize): PGString; cdecl; external; function g_strip_context(msgid: Pgchar; msgval: Pgchar): Pgchar; cdecl; external; function g_strjoin(separator: Pgchar; args: array of const): Pgchar; cdecl; external; function g_strjoinv(separator: Pgchar; str_array: PPgchar): Pgchar; cdecl; external; function g_strlcat(dest: Pgchar; src: Pgchar; dest_size: gsize): gsize; cdecl; external; function g_strlcpy(dest: Pgchar; src: Pgchar; dest_size: gsize): gsize; cdecl; external; function g_strncasecmp(s1: Pgchar; s2: Pgchar; n: guint): gint; cdecl; external; function g_strndup(str: Pgchar; n: gsize): Pgchar; cdecl; external; function g_strnfill(length: gsize; fill_char: gchar): Pgchar; cdecl; external; function g_strreverse(string_: Pgchar): Pgchar; cdecl; external; function g_strrstr(haystack: Pgchar; needle: Pgchar): Pgchar; cdecl; external; function g_strrstr_len(haystack: Pgchar; haystack_len: gssize; needle: Pgchar): Pgchar; cdecl; external; function g_strsignal(signum: gint): Pgchar; cdecl; external; function g_strsplit(string_: Pgchar; delimiter: Pgchar; max_tokens: gint): PPgchar; cdecl; external; function g_strsplit_set(string_: Pgchar; delimiters: Pgchar; max_tokens: gint): PPgchar; cdecl; external; function g_strstr_len(haystack: Pgchar; haystack_len: gssize; needle: Pgchar): Pgchar; cdecl; external; function g_strtod(nptr: Pgchar; endptr: PPgchar): gdouble; cdecl; external; function g_strup(string_: Pgchar): Pgchar; cdecl; external; function g_strv_get_type: TGType; cdecl; external; function g_strv_length(str_array: PPgchar): guint; cdecl; external; function g_test_create_case(test_name: Pgchar; data_size: gsize; test_data: Pgpointer; data_setup: TGTestFixtureFunc; data_test: TGTestFixtureFunc; data_teardown: TGTestFixtureFunc): PGTestCase; cdecl; external; function g_test_create_suite(suite_name: Pgchar): PGTestSuite; cdecl; external; function g_test_get_root: PGTestSuite; cdecl; external; function g_test_log_buffer_new: PGTestLogBuffer; cdecl; external; function g_test_log_buffer_pop(tbuffer: PGTestLogBuffer): PGTestLogMsg; cdecl; external; function g_test_log_type_name(log_type: TGTestLogType): Pgchar; cdecl; external; function g_test_rand_double: gdouble; cdecl; external; function g_test_rand_double_range(range_start: gdouble; range_end: gdouble): gdouble; cdecl; external; function g_test_rand_int: gint32; cdecl; external; function g_test_rand_int_range(begin_: gint32; end_: gint32): gint32; cdecl; external; function g_test_run: gint; cdecl; external; function g_test_run_suite(suite: PGTestSuite): gint; cdecl; external; function g_test_timer_elapsed: gdouble; cdecl; external; function g_test_timer_last: gdouble; cdecl; external; function g_test_trap_fork(usec_timeout: guint64; test_trap_flags: TGTestTrapFlags): gboolean; cdecl; external; function g_test_trap_has_passed: gboolean; cdecl; external; function g_test_trap_reached_timeout: gboolean; cdecl; external; function g_thread_error_quark: TGQuark; cdecl; external; function g_thread_get_type: TGType; cdecl; external; function g_thread_join(thread: PGThread): gpointer; cdecl; external; function g_thread_new(name: Pgchar; func: TGThreadFunc; data: gpointer): PGThread; cdecl; external; function g_thread_pool_get_max_idle_time: guint; cdecl; external; function g_thread_pool_get_max_threads(pool: PGThreadPool): gint; cdecl; external; function g_thread_pool_get_max_unused_threads: gint; cdecl; external; function g_thread_pool_get_num_threads(pool: PGThreadPool): guint; cdecl; external; function g_thread_pool_get_num_unused_threads: guint; cdecl; external; function g_thread_pool_new(func: TGFunc; user_data: gpointer; max_threads: gint; exclusive: gboolean; error: PPGError): PGThreadPool; cdecl; external; function g_thread_pool_push(pool: PGThreadPool; data: gpointer; error: PPGError): gboolean; cdecl; external; function g_thread_pool_set_max_threads(pool: PGThreadPool; max_threads: gint; error: PPGError): gboolean; cdecl; external; function g_thread_pool_unprocessed(pool: PGThreadPool): guint; cdecl; external; function g_thread_ref(thread: PGThread): PGThread; cdecl; external; function g_thread_self: PGThread; cdecl; external; function g_thread_try_new(name: Pgchar; func: TGThreadFunc; data: gpointer; error: PPGError): PGThread; cdecl; external; function g_time_val_from_iso8601(iso_date: Pgchar; time_: PGTimeVal): gboolean; cdecl; external; function g_time_val_to_iso8601(time_: PGTimeVal): Pgchar; cdecl; external; function g_time_zone_adjust_time(tz: PGTimeZone; type_: TGTimeType; time_: Pgint64): gint; cdecl; external; function g_time_zone_find_interval(tz: PGTimeZone; type_: TGTimeType; time_: gint64): gint; cdecl; external; function g_time_zone_get_abbreviation(tz: PGTimeZone; interval: gint): Pgchar; cdecl; external; function g_time_zone_get_offset(tz: PGTimeZone; interval: gint): gint32; cdecl; external; function g_time_zone_get_type: TGType; cdecl; external; function g_time_zone_is_dst(tz: PGTimeZone; interval: gint): gboolean; cdecl; external; function g_time_zone_new(identifier: Pgchar): PGTimeZone; cdecl; external; function g_time_zone_new_local: PGTimeZone; cdecl; external; function g_time_zone_new_utc: PGTimeZone; cdecl; external; function g_time_zone_ref(tz: PGTimeZone): PGTimeZone; cdecl; external; function g_timeout_add(interval: guint; function_: TGSourceFunc; data: gpointer): guint; cdecl; external; function g_timeout_add_full(priority: gint; interval: guint; function_: TGSourceFunc; data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_timeout_add_seconds(interval: guint; function_: TGSourceFunc; data: gpointer): guint; cdecl; external; function g_timeout_add_seconds_full(priority: gint; interval: guint; function_: TGSourceFunc; data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_timeout_source_new(interval: guint): PGSource; cdecl; external; function g_timeout_source_new_seconds(interval: guint): PGSource; cdecl; external; function g_timer_elapsed(timer: PGTimer; microseconds: Pgulong): gdouble; cdecl; external; function g_timer_new: PGTimer; cdecl; external; function g_trash_stack_height(stack_p: PPGTrashStack): guint; cdecl; external; function g_trash_stack_peek(stack_p: PPGTrashStack): gpointer; cdecl; external; function g_trash_stack_pop(stack_p: PPGTrashStack): gpointer; cdecl; external; function g_tree_height(tree: PGTree): gint; cdecl; external; function g_tree_lookup(tree: PGTree; key: Pgpointer): gpointer; cdecl; external; function g_tree_lookup_extended(tree: PGTree; lookup_key: Pgpointer; orig_key: Pgpointer; value: Pgpointer): gboolean; cdecl; external; function g_tree_new(key_compare_func: TGCompareFunc): PGTree; cdecl; external; function g_tree_new_full(key_compare_func: TGCompareDataFunc; key_compare_data: gpointer; key_destroy_func: TGDestroyNotify; value_destroy_func: TGDestroyNotify): PGTree; cdecl; external; function g_tree_new_with_data(key_compare_func: TGCompareDataFunc; key_compare_data: gpointer): PGTree; cdecl; external; function g_tree_nnodes(tree: PGTree): gint; cdecl; external; function g_tree_ref(tree: PGTree): PGTree; cdecl; external; function g_tree_remove(tree: PGTree; key: Pgpointer): gboolean; cdecl; external; function g_tree_search(tree: PGTree; search_func: TGCompareFunc; user_data: Pgpointer): gpointer; cdecl; external; function g_tree_steal(tree: PGTree; key: Pgpointer): gboolean; cdecl; external; function g_try_malloc(n_bytes: gsize): gpointer; cdecl; external; function g_try_malloc0(n_bytes: gsize): gpointer; cdecl; external; function g_try_malloc0_n(n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; external; function g_try_malloc_n(n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; external; function g_try_realloc(mem: gpointer; n_bytes: gsize): gpointer; cdecl; external; function g_try_realloc_n(mem: gpointer; n_blocks: gsize; n_block_bytes: gsize): gpointer; cdecl; external; function g_ucs4_to_utf16(str: Pgunichar; len: glong; items_read: Pglong; items_written: Pglong; error: PPGError): Pguint16; cdecl; external; function g_ucs4_to_utf8(str: Pgunichar; len: glong; items_read: Pglong; items_written: Pglong; error: PPGError): Pgchar; cdecl; external; function g_unichar_break_type(c: gunichar): TGUnicodeBreakType; cdecl; external; function g_unichar_combining_class(uc: gunichar): gint; cdecl; external; function g_unichar_compose(a: gunichar; b: gunichar; ch: Pgunichar): gboolean; cdecl; external; function g_unichar_decompose(ch: gunichar; a: Pgunichar; b: Pgunichar): gboolean; cdecl; external; function g_unichar_digit_value(c: gunichar): gint; cdecl; external; function g_unichar_fully_decompose(ch: gunichar; compat: gboolean; result_: Pgunichar; result_len: gsize): gsize; cdecl; external; function g_unichar_get_mirror_char(ch: gunichar; mirrored_ch: Pgunichar): gboolean; cdecl; external; function g_unichar_get_script(ch: gunichar): TGUnicodeScript; cdecl; external; function g_unichar_isalnum(c: gunichar): gboolean; cdecl; external; function g_unichar_isalpha(c: gunichar): gboolean; cdecl; external; function g_unichar_iscntrl(c: gunichar): gboolean; cdecl; external; function g_unichar_isdefined(c: gunichar): gboolean; cdecl; external; function g_unichar_isdigit(c: gunichar): gboolean; cdecl; external; function g_unichar_isgraph(c: gunichar): gboolean; cdecl; external; function g_unichar_islower(c: gunichar): gboolean; cdecl; external; function g_unichar_ismark(c: gunichar): gboolean; cdecl; external; function g_unichar_isprint(c: gunichar): gboolean; cdecl; external; function g_unichar_ispunct(c: gunichar): gboolean; cdecl; external; function g_unichar_isspace(c: gunichar): gboolean; cdecl; external; function g_unichar_istitle(c: gunichar): gboolean; cdecl; external; function g_unichar_isupper(c: gunichar): gboolean; cdecl; external; function g_unichar_iswide(c: gunichar): gboolean; cdecl; external; function g_unichar_iswide_cjk(c: gunichar): gboolean; cdecl; external; function g_unichar_isxdigit(c: gunichar): gboolean; cdecl; external; function g_unichar_iszerowidth(c: gunichar): gboolean; cdecl; external; function g_unichar_to_utf8(c: gunichar; outbuf: Pgchar): gint; cdecl; external; function g_unichar_tolower(c: gunichar): gunichar; cdecl; external; function g_unichar_totitle(c: gunichar): gunichar; cdecl; external; function g_unichar_toupper(c: gunichar): gunichar; cdecl; external; function g_unichar_type(c: gunichar): TGUnicodeType; cdecl; external; function g_unichar_validate(ch: gunichar): gboolean; cdecl; external; function g_unichar_xdigit_value(c: gunichar): gint; cdecl; external; function g_unicode_canonical_decomposition(ch: gunichar; result_len: Pgsize): Pgunichar; cdecl; external; function g_unicode_script_from_iso15924(iso15924: guint32): TGUnicodeScript; cdecl; external; function g_unicode_script_to_iso15924(script: TGUnicodeScript): guint32; cdecl; external; function g_unix_error_quark: TGQuark; cdecl; external; function g_unix_fd_add(fd: gint; condition: TGIOCondition; function_: TGUnixFDSourceFunc; user_data: gpointer): guint; cdecl; external; function g_unix_fd_add_full(priority: gint; fd: gint; condition: TGIOCondition; function_: TGUnixFDSourceFunc; user_data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_unix_fd_source_new(fd: gint; condition: TGIOCondition): PGSource; cdecl; external; function g_unix_open_pipe(fds: Pgint; flags: gint; error: PPGError): gboolean; cdecl; external; function g_unix_set_fd_nonblocking(fd: gint; nonblock: gboolean; error: PPGError): gboolean; cdecl; external; function g_unix_signal_add(signum: gint; handler: TGSourceFunc; user_data: gpointer): guint; cdecl; external; function g_unix_signal_add_full(priority: gint; signum: gint; handler: TGSourceFunc; user_data: gpointer; notify: TGDestroyNotify): guint; cdecl; external; function g_unix_signal_source_new(signum: gint): PGSource; cdecl; external; function g_unlink(filename: Pgchar): gint; cdecl; external; function g_uri_escape_string(unescaped: Pgchar; reserved_chars_allowed: Pgchar; allow_utf8: gboolean): Pgchar; cdecl; external; function g_uri_list_extract_uris(uri_list: Pgchar): PPgchar; cdecl; external; function g_uri_parse_scheme(uri: Pgchar): Pgchar; cdecl; external; function g_uri_unescape_segment(escaped_string: Pgchar; escaped_string_end: Pgchar; illegal_characters: Pgchar): Pgchar; cdecl; external; function g_uri_unescape_string(escaped_string: Pgchar; illegal_characters: Pgchar): Pgchar; cdecl; external; function g_utf16_to_ucs4(str: Pguint16; len: glong; items_read: Pglong; items_written: Pglong; error: PPGError): Pgunichar; cdecl; external; function g_utf16_to_utf8(str: Pguint16; len: glong; items_read: Pglong; items_written: Pglong; error: PPGError): Pgchar; cdecl; external; function g_utf8_casefold(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_utf8_collate(str1: Pgchar; str2: Pgchar): gint; cdecl; external; function g_utf8_collate_key(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_utf8_collate_key_for_filename(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_utf8_find_next_char(p: Pgchar; end_: Pgchar): Pgchar; cdecl; external; function g_utf8_find_prev_char(str: Pgchar; p: Pgchar): Pgchar; cdecl; external; function g_utf8_get_char(p: Pgchar): gunichar; cdecl; external; function g_utf8_get_char_validated(p: Pgchar; max_len: gssize): gunichar; cdecl; external; function g_utf8_normalize(str: Pgchar; len: gssize; mode: TGNormalizeMode): Pgchar; cdecl; external; function g_utf8_offset_to_pointer(str: Pgchar; offset: glong): Pgchar; cdecl; external; function g_utf8_pointer_to_offset(str: Pgchar; pos: Pgchar): glong; cdecl; external; function g_utf8_prev_char(p: Pgchar): Pgchar; cdecl; external; function g_utf8_strchr(p: Pgchar; len: gssize; c: gunichar): Pgchar; cdecl; external; function g_utf8_strdown(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_utf8_strlen(p: Pgchar; max: gssize): glong; cdecl; external; function g_utf8_strncpy(dest: Pgchar; src: Pgchar; n: gsize): Pgchar; cdecl; external; function g_utf8_strrchr(p: Pgchar; len: gssize; c: gunichar): Pgchar; cdecl; external; function g_utf8_strreverse(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_utf8_strup(str: Pgchar; len: gssize): Pgchar; cdecl; external; function g_utf8_substring(str: Pgchar; start_pos: glong; end_pos: glong): Pgchar; cdecl; external; function g_utf8_to_ucs4(str: Pgchar; len: glong; items_read: Pglong; items_written: Pglong; error: PPGError): Pgunichar; cdecl; external; function g_utf8_to_ucs4_fast(str: Pgchar; len: glong; items_written: Pglong): Pgunichar; cdecl; external; function g_utf8_to_utf16(str: Pgchar; len: glong; items_read: Pglong; items_written: Pglong; error: PPGError): Pguint16; cdecl; external; function g_utf8_validate(str: Pgchar; max_len: gssize; end_: PPgchar): gboolean; cdecl; external; function g_variant_builder_end(builder: PGVariantBuilder): PGVariant; cdecl; external; function g_variant_builder_get_type: TGType; cdecl; external; function g_variant_builder_new(type_: PGVariantType): PGVariantBuilder; cdecl; external; function g_variant_builder_ref(builder: PGVariantBuilder): PGVariantBuilder; cdecl; external; function g_variant_byteswap(value: PGVariant): PGVariant; cdecl; external; function g_variant_check_format_string(value: PGVariant; format_string: Pgchar; copy_only: gboolean): gboolean; cdecl; external; function g_variant_classify(value: PGVariant): TGVariantClass; cdecl; external; function g_variant_compare(one: PGVariant; two: PGVariant): gint; cdecl; external; function g_variant_dup_bytestring(value: PGVariant; length: Pgsize): Pgchar; cdecl; external; function g_variant_dup_bytestring_array(value: PGVariant; length: Pgsize): PPgchar; cdecl; external; function g_variant_dup_objv(value: PGVariant; length: Pgsize): PPgchar; cdecl; external; function g_variant_dup_string(value: PGVariant; length: Pgsize): Pgchar; cdecl; external; function g_variant_dup_strv(value: PGVariant; length: Pgsize): PPgchar; cdecl; external; function g_variant_equal(one: PGVariant; two: PGVariant): gboolean; cdecl; external; function g_variant_get_boolean(value: PGVariant): gboolean; cdecl; external; function g_variant_get_byte(value: PGVariant): guint8; cdecl; external; function g_variant_get_bytestring(value: PGVariant): Pgchar; cdecl; external; function g_variant_get_bytestring_array(value: PGVariant; length: Pgsize): PPgchar; cdecl; external; function g_variant_get_child_value(value: PGVariant; index_: gsize): PGVariant; cdecl; external; function g_variant_get_data(value: PGVariant): Pgpointer; cdecl; external; function g_variant_get_data_as_bytes(value: PGVariant): PGBytes; cdecl; external; function g_variant_get_double(value: PGVariant): gdouble; cdecl; external; function g_variant_get_fixed_array(value: PGVariant; n_elements: Pgsize; element_size: gsize): gpointer; cdecl; external; function g_variant_get_gtype: TGType; cdecl; external; function g_variant_get_handle(value: PGVariant): gint32; cdecl; external; function g_variant_get_int16(value: PGVariant): gint16; cdecl; external; function g_variant_get_int32(value: PGVariant): gint32; cdecl; external; function g_variant_get_int64(value: PGVariant): gint64; cdecl; external; function g_variant_get_maybe(value: PGVariant): PGVariant; cdecl; external; function g_variant_get_normal_form(value: PGVariant): PGVariant; cdecl; external; function g_variant_get_objv(value: PGVariant; length: Pgsize): PPgchar; cdecl; external; function g_variant_get_size(value: PGVariant): gsize; cdecl; external; function g_variant_get_string(value: PGVariant; length: Pgsize): Pgchar; cdecl; external; function g_variant_get_strv(value: PGVariant; length: Pgsize): PPgchar; cdecl; external; function g_variant_get_type(value: PGVariant): PGVariantType; cdecl; external; function g_variant_get_type_string(value: PGVariant): Pgchar; cdecl; external; function g_variant_get_uint16(value: PGVariant): guint16; cdecl; external; function g_variant_get_uint32(value: PGVariant): guint32; cdecl; external; function g_variant_get_uint64(value: PGVariant): guint64; cdecl; external; function g_variant_get_variant(value: PGVariant): PGVariant; cdecl; external; function g_variant_hash(value: PGVariant): guint; cdecl; external; function g_variant_is_container(value: PGVariant): gboolean; cdecl; external; function g_variant_is_floating(value: PGVariant): gboolean; cdecl; external; function g_variant_is_normal_form(value: PGVariant): gboolean; cdecl; external; function g_variant_is_object_path(string_: Pgchar): gboolean; cdecl; external; function g_variant_is_of_type(value: PGVariant; type_: PGVariantType): gboolean; cdecl; external; function g_variant_is_signature(string_: Pgchar): gboolean; cdecl; external; function g_variant_iter_copy(iter: PGVariantIter): PGVariantIter; cdecl; external; function g_variant_iter_init(iter: PGVariantIter; value: PGVariant): gsize; cdecl; external; function g_variant_iter_loop(iter: PGVariantIter; format_string: Pgchar; args: array of const): gboolean; cdecl; external; function g_variant_iter_n_children(iter: PGVariantIter): gsize; cdecl; external; function g_variant_iter_new(value: PGVariant): PGVariantIter; cdecl; external; function g_variant_iter_next(iter: PGVariantIter; format_string: Pgchar; args: array of const): gboolean; cdecl; external; function g_variant_iter_next_value(iter: PGVariantIter): PGVariant; cdecl; external; function g_variant_lookup(dictionary: PGVariant; key: Pgchar; format_string: Pgchar; args: array of const): gboolean; cdecl; external; function g_variant_lookup_value(dictionary: PGVariant; key: Pgchar; expected_type: PGVariantType): PGVariant; cdecl; external; function g_variant_n_children(value: PGVariant): gsize; cdecl; external; function g_variant_new(format_string: Pgchar; args: array of const): PGVariant; cdecl; external; function g_variant_new_array(child_type: PGVariantType; children: PPGVariant; n_children: gsize): PGVariant; cdecl; external; function g_variant_new_boolean(value: gboolean): PGVariant; cdecl; external; function g_variant_new_byte(value: guint8): PGVariant; cdecl; external; function g_variant_new_bytestring(string_: Pgchar): PGVariant; cdecl; external; function g_variant_new_bytestring_array(strv: PPgchar; length: gssize): PGVariant; cdecl; external; function g_variant_new_dict_entry(key: PGVariant; value: PGVariant): PGVariant; cdecl; external; function g_variant_new_double(value: gdouble): PGVariant; cdecl; external; function g_variant_new_fixed_array(element_type: PGVariantType; elements: Pgpointer; n_elements: gsize; element_size: gsize): PGVariant; cdecl; external; function g_variant_new_from_bytes(type_: PGVariantType; bytes: PGBytes; trusted: gboolean): PGVariant; cdecl; external; function g_variant_new_from_data(type_: PGVariantType; data: guint8; size: gsize; trusted: gboolean; notify: TGDestroyNotify; user_data: gpointer): PGVariant; cdecl; external; function g_variant_new_handle(value: gint32): PGVariant; cdecl; external; function g_variant_new_int16(value: gint16): PGVariant; cdecl; external; function g_variant_new_int32(value: gint32): PGVariant; cdecl; external; function g_variant_new_int64(value: gint64): PGVariant; cdecl; external; function g_variant_new_maybe(child_type: PGVariantType; child: PGVariant): PGVariant; cdecl; external; function g_variant_new_object_path(object_path: Pgchar): PGVariant; cdecl; external; function g_variant_new_objv(strv: PPgchar; length: gssize): PGVariant; cdecl; external; function g_variant_new_parsed(format: Pgchar; args: array of const): PGVariant; cdecl; external; function g_variant_new_parsed_va(format: Pgchar; app: Pva_list): PGVariant; cdecl; external; function g_variant_new_signature(signature: Pgchar): PGVariant; cdecl; external; function g_variant_new_string(string_: Pgchar): PGVariant; cdecl; external; function g_variant_new_strv(strv: PPgchar; length: gssize): PGVariant; cdecl; external; function g_variant_new_tuple(children: PPGVariant; n_children: gsize): PGVariant; cdecl; external; function g_variant_new_uint16(value: guint16): PGVariant; cdecl; external; function g_variant_new_uint32(value: guint32): PGVariant; cdecl; external; function g_variant_new_uint64(value: guint64): PGVariant; cdecl; external; function g_variant_new_va(format_string: Pgchar; endptr: PPgchar; app: Pva_list): PGVariant; cdecl; external; function g_variant_new_variant(value: PGVariant): PGVariant; cdecl; external; function g_variant_parse(type_: PGVariantType; text: Pgchar; limit: Pgchar; endptr: PPgchar; error: PPGError): PGVariant; cdecl; external; function g_variant_parser_get_error_quark: TGQuark; cdecl; external; function g_variant_print(value: PGVariant; type_annotate: gboolean): Pgchar; cdecl; external; function g_variant_print_string(value: PGVariant; string_: PGString; type_annotate: gboolean): PGString; cdecl; external; function g_variant_ref(value: PGVariant): PGVariant; cdecl; external; function g_variant_ref_sink(value: PGVariant): PGVariant; cdecl; external; function g_variant_take_ref(value: PGVariant): PGVariant; cdecl; external; function g_variant_type_checked_(arg0: Pgchar): PGVariantType; cdecl; external; function g_variant_type_copy(type_: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_dup_string(type_: PGVariantType): Pgchar; cdecl; external; function g_variant_type_element(type_: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_equal(type1: PGVariantType; type2: PGVariantType): gboolean; cdecl; external; function g_variant_type_first(type_: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_get_gtype: TGType; cdecl; external; function g_variant_type_get_string_length(type_: PGVariantType): gsize; cdecl; external; function g_variant_type_hash(type_: PGVariantType): guint; cdecl; external; function g_variant_type_is_array(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_basic(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_container(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_definite(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_dict_entry(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_maybe(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_subtype_of(type_: PGVariantType; supertype: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_tuple(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_is_variant(type_: PGVariantType): gboolean; cdecl; external; function g_variant_type_key(type_: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_n_items(type_: PGVariantType): gsize; cdecl; external; function g_variant_type_new(type_string: Pgchar): PGVariantType; cdecl; external; function g_variant_type_new_array(element: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_new_dict_entry(key: PGVariantType; value: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_new_maybe(element: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_new_tuple(items: PPGVariantType; length: gint): PGVariantType; cdecl; external; function g_variant_type_next(type_: PGVariantType): PGVariantType; cdecl; external; function g_variant_type_peek_string(type_: PGVariantType): Pgchar; cdecl; external; function g_variant_type_string_is_valid(type_string: Pgchar): gboolean; cdecl; external; function g_variant_type_string_scan(string_: Pgchar; limit: Pgchar; endptr: PPgchar): gboolean; cdecl; external; function g_variant_type_value(type_: PGVariantType): PGVariantType; cdecl; external; function g_vasprintf(string_: PPgchar; format: Pgchar; args: Tva_list): gint; cdecl; external; function g_vfprintf(file_: Pgpointer; format: Pgchar; args: Tva_list): gint; cdecl; external; function g_vprintf(format: Pgchar; args: Tva_list): gint; cdecl; external; function g_vsnprintf(string_: Pgchar; n: gulong; format: Pgchar; args: Tva_list): gint; cdecl; external; function g_vsprintf(string_: Pgchar; format: Pgchar; args: Tva_list): gint; cdecl; external; function glib_check_version(required_major: guint; required_minor: guint; required_micro: guint): Pgchar; cdecl; external; procedure g_array_set_clear_func(array_: Pgpointer; clear_func: TGDestroyNotify); cdecl; external; procedure g_array_sort(array_: Pgpointer; compare_func: TGCompareFunc); cdecl; external; procedure g_array_sort_with_data(array_: Pgpointer; compare_func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_array_unref(array_: Pgpointer); cdecl; external; procedure g_assert_warning(log_domain: Pgchar; file_: Pgchar; line: gint; pretty_function: Pgchar; expression: Pgchar); cdecl; external; procedure g_assertion_message(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; message: Pgchar); cdecl; external; procedure g_assertion_message_cmpnum(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; expr: Pgchar; arg1: long_double; cmp: Pgchar; arg2: long_double; numtype: gchar); cdecl; external; procedure g_assertion_message_cmpstr(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; expr: Pgchar; arg1: Pgchar; cmp: Pgchar; arg2: Pgchar); cdecl; external; procedure g_assertion_message_error(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; expr: Pgchar; error: PGError; error_domain: TGQuark; error_code: gint); cdecl; external; procedure g_assertion_message_expr(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; expr: Pgchar); cdecl; external; procedure g_async_queue_lock(queue: PGAsyncQueue); cdecl; external; procedure g_async_queue_push(queue: PGAsyncQueue; data: gpointer); cdecl; external; procedure g_async_queue_push_sorted(queue: PGAsyncQueue; data: gpointer; func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_async_queue_push_sorted_unlocked(queue: PGAsyncQueue; data: gpointer; func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_async_queue_push_unlocked(queue: PGAsyncQueue; data: gpointer); cdecl; external; procedure g_async_queue_sort(queue: PGAsyncQueue; func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_async_queue_sort_unlocked(queue: PGAsyncQueue; func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_async_queue_unlock(queue: PGAsyncQueue); cdecl; external; procedure g_async_queue_unref(queue: PGAsyncQueue); cdecl; external; procedure g_atexit(func: TGVoidFunc); cdecl; external; procedure g_atomic_int_inc(atomic: Pgint); cdecl; external; procedure g_atomic_int_set(atomic: Pgint; newval: gint); cdecl; external; procedure g_atomic_pointer_set(atomic: Pgpointer; newval: gpointer); cdecl; external; procedure g_bit_lock(address: Pgint; lock_bit: gint); cdecl; external; procedure g_bit_unlock(address: Pgint; lock_bit: gint); cdecl; external; procedure g_bookmark_file_add_application(bookmark: PGBookmarkFile; uri: Pgchar; name: Pgchar; exec: Pgchar); cdecl; external; procedure g_bookmark_file_add_group(bookmark: PGBookmarkFile; uri: Pgchar; group: Pgchar); cdecl; external; procedure g_bookmark_file_free(bookmark: PGBookmarkFile); cdecl; external; procedure g_bookmark_file_set_added(bookmark: PGBookmarkFile; uri: Pgchar; added: glong); cdecl; external; procedure g_bookmark_file_set_description(bookmark: PGBookmarkFile; uri: Pgchar; description: Pgchar); cdecl; external; procedure g_bookmark_file_set_groups(bookmark: PGBookmarkFile; uri: Pgchar; groups: PPgchar; length: gsize); cdecl; external; procedure g_bookmark_file_set_icon(bookmark: PGBookmarkFile; uri: Pgchar; href: Pgchar; mime_type: Pgchar); cdecl; external; procedure g_bookmark_file_set_is_private(bookmark: PGBookmarkFile; uri: Pgchar; is_private: gboolean); cdecl; external; procedure g_bookmark_file_set_mime_type(bookmark: PGBookmarkFile; uri: Pgchar; mime_type: Pgchar); cdecl; external; procedure g_bookmark_file_set_modified(bookmark: PGBookmarkFile; uri: Pgchar; modified: glong); cdecl; external; procedure g_bookmark_file_set_title(bookmark: PGBookmarkFile; uri: Pgchar; title: Pgchar); cdecl; external; procedure g_bookmark_file_set_visited(bookmark: PGBookmarkFile; uri: Pgchar; visited: glong); cdecl; external; procedure g_byte_array_sort(array_: Pguint8; compare_func: TGCompareFunc); cdecl; external; procedure g_byte_array_sort_with_data(array_: Pguint8; compare_func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_byte_array_unref(array_: Pguint8); cdecl; external; procedure g_bytes_unref(bytes: PGBytes); cdecl; external; procedure g_checksum_free(checksum: PGChecksum); cdecl; external; procedure g_checksum_get_digest(checksum: PGChecksum; buffer: Pguint8; digest_len: Pgsize); cdecl; external; procedure g_checksum_reset(checksum: PGChecksum); cdecl; external; procedure g_checksum_update(checksum: PGChecksum; data: Pguint8; length: gssize); cdecl; external; procedure g_clear_error; cdecl; external; procedure g_clear_pointer(pp: Pgpointer; destroy_: TGDestroyNotify); cdecl; external; procedure g_cond_broadcast(cond: PGCond); cdecl; external; procedure g_cond_clear(cond: PGCond); cdecl; external; procedure g_cond_init(cond: PGCond); cdecl; external; procedure g_cond_signal(cond: PGCond); cdecl; external; procedure g_cond_wait(cond: PGCond; mutex: PGMutex); cdecl; external; procedure g_datalist_clear(datalist: PPGData); cdecl; external; procedure g_datalist_foreach(datalist: PPGData; func: TGDataForeachFunc; user_data: gpointer); cdecl; external; procedure g_datalist_id_set_data_full(datalist: PPGData; key_id: TGQuark; data: gpointer; destroy_func: TGDestroyNotify); cdecl; external; procedure g_datalist_init(datalist: PPGData); cdecl; external; procedure g_datalist_set_flags(datalist: PPGData; flags: guint); cdecl; external; procedure g_datalist_unset_flags(datalist: PPGData; flags: guint); cdecl; external; procedure g_dataset_destroy(dataset_location: Pgpointer); cdecl; external; procedure g_dataset_foreach(dataset_location: Pgpointer; func: TGDataForeachFunc; user_data: gpointer); cdecl; external; procedure g_dataset_id_set_data_full(dataset_location: Pgpointer; key_id: TGQuark; data: gpointer; destroy_func: TGDestroyNotify); cdecl; external; procedure g_date_add_days(date: PGDate; n_days: guint); cdecl; external; procedure g_date_add_months(date: PGDate; n_months: guint); cdecl; external; procedure g_date_add_years(date: PGDate; n_years: guint); cdecl; external; procedure g_date_clamp(date: PGDate; min_date: PGDate; max_date: PGDate); cdecl; external; procedure g_date_clear(date: PGDate; n_dates: guint); cdecl; external; procedure g_date_free(date: PGDate); cdecl; external; procedure g_date_order(date1: PGDate; date2: PGDate); cdecl; external; procedure g_date_set_day(date: PGDate; day: TGDateDay); cdecl; external; procedure g_date_set_dmy(date: PGDate; day: TGDateDay; month: TGDateMonth; y: TGDateYear); cdecl; external; procedure g_date_set_julian(date: PGDate; julian_date: guint32); cdecl; external; procedure g_date_set_month(date: PGDate; month: TGDateMonth); cdecl; external; procedure g_date_set_parse(date: PGDate; str: Pgchar); cdecl; external; procedure g_date_set_time_t(date: PGDate; timet: glong); cdecl; external; procedure g_date_set_time_val(date: PGDate; timeval: PGTimeVal); cdecl; external; procedure g_date_set_year(date: PGDate; year: TGDateYear); cdecl; external; procedure g_date_subtract_days(date: PGDate; n_days: guint); cdecl; external; procedure g_date_subtract_months(date: PGDate; n_months: guint); cdecl; external; procedure g_date_subtract_years(date: PGDate; n_years: guint); cdecl; external; procedure g_date_time_get_ymd(datetime: PGDateTime; year: Pgint; month: Pgint; day: Pgint); cdecl; external; procedure g_date_time_unref(datetime: PGDateTime); cdecl; external; procedure g_date_to_struct_tm(date: PGDate; tm: Pgpointer); cdecl; external; procedure g_dir_close(dir: PGDir); cdecl; external; procedure g_dir_rewind(dir: PGDir); cdecl; external; procedure g_error_free(error: PGError); cdecl; external; procedure g_free(mem: gpointer); cdecl; external; procedure g_get_current_time(result_: PGTimeVal); cdecl; external; procedure g_hash_table_add(hash_table: PGHashTable; key: gpointer); cdecl; external; procedure g_hash_table_destroy(hash_table: PGHashTable); cdecl; external; procedure g_hash_table_foreach(hash_table: PGHashTable; func: TGHFunc; user_data: gpointer); cdecl; external; procedure g_hash_table_insert(hash_table: PGHashTable; key: gpointer; value: gpointer); cdecl; external; procedure g_hash_table_iter_init(iter: PGHashTableIter; hash_table: PGHashTable); cdecl; external; procedure g_hash_table_iter_remove(iter: PGHashTableIter); cdecl; external; procedure g_hash_table_iter_replace(iter: PGHashTableIter; value: gpointer); cdecl; external; procedure g_hash_table_iter_steal(iter: PGHashTableIter); cdecl; external; procedure g_hash_table_remove_all(hash_table: PGHashTable); cdecl; external; procedure g_hash_table_replace(hash_table: PGHashTable; key: gpointer; value: gpointer); cdecl; external; procedure g_hash_table_steal_all(hash_table: PGHashTable); cdecl; external; procedure g_hash_table_unref(hash_table: PGHashTable); cdecl; external; procedure g_hmac_get_digest(hmac: PGHmac; buffer: Pguint8; digest_len: Pgsize); cdecl; external; procedure g_hmac_unref(hmac: PGHmac); cdecl; external; procedure g_hmac_update(hmac: PGHmac; data: Pguint8; length: gssize); cdecl; external; procedure g_hook_destroy_link(hook_list: PGHookList; hook: PGHook); cdecl; external; procedure g_hook_free(hook_list: PGHookList; hook: PGHook); cdecl; external; procedure g_hook_insert_before(hook_list: PGHookList; sibling: PGHook; hook: PGHook); cdecl; external; procedure g_hook_insert_sorted(hook_list: PGHookList; hook: PGHook; func: TGHookCompareFunc); cdecl; external; procedure g_hook_list_clear(hook_list: PGHookList); cdecl; external; procedure g_hook_list_init(hook_list: PGHookList; hook_size: guint); cdecl; external; procedure g_hook_list_invoke(hook_list: PGHookList; may_recurse: gboolean); cdecl; external; procedure g_hook_list_invoke_check(hook_list: PGHookList; may_recurse: gboolean); cdecl; external; procedure g_hook_list_marshal(hook_list: PGHookList; may_recurse: gboolean; marshaller: TGHookMarshaller; marshal_data: gpointer); cdecl; external; procedure g_hook_list_marshal_check(hook_list: PGHookList; may_recurse: gboolean; marshaller: TGHookCheckMarshaller; marshal_data: gpointer); cdecl; external; procedure g_hook_prepend(hook_list: PGHookList; hook: PGHook); cdecl; external; procedure g_hook_unref(hook_list: PGHookList; hook: PGHook); cdecl; external; procedure g_io_channel_init(channel: PGIOChannel); cdecl; external; procedure g_io_channel_set_buffer_size(channel: PGIOChannel; size: gsize); cdecl; external; procedure g_io_channel_set_buffered(channel: PGIOChannel; buffered: gboolean); cdecl; external; procedure g_io_channel_set_close_on_unref(channel: PGIOChannel; do_close: gboolean); cdecl; external; procedure g_io_channel_set_line_term(channel: PGIOChannel; line_term: Pgchar; length: gint); cdecl; external; procedure g_io_channel_unref(channel: PGIOChannel); cdecl; external; procedure g_key_file_free(key_file: PGKeyFile); cdecl; external; procedure g_key_file_set_boolean(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; value: gboolean); cdecl; external; procedure g_key_file_set_boolean_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; list: gboolean; length: gsize); cdecl; external; procedure g_key_file_set_double(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; value: gdouble); cdecl; external; procedure g_key_file_set_double_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; list: gdouble; length: gsize); cdecl; external; procedure g_key_file_set_int64(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; value: gint64); cdecl; external; procedure g_key_file_set_integer(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; value: gint); cdecl; external; procedure g_key_file_set_integer_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; list: gint; length: gsize); cdecl; external; procedure g_key_file_set_list_separator(key_file: PGKeyFile; separator: gchar); cdecl; external; procedure g_key_file_set_locale_string(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; locale: Pgchar; string_: Pgchar); cdecl; external; procedure g_key_file_set_locale_string_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; locale: Pgchar; list: Pgchar; length: gsize); cdecl; external; procedure g_key_file_set_string(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; string_: Pgchar); cdecl; external; procedure g_key_file_set_string_list(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; list: Pgchar; length: gsize); cdecl; external; procedure g_key_file_set_uint64(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; value: guint64); cdecl; external; procedure g_key_file_set_value(key_file: PGKeyFile; group_name: Pgchar; key: Pgchar; value: Pgchar); cdecl; external; procedure g_key_file_unref(key_file: PGKeyFile); cdecl; external; procedure g_list_foreach(list: PGList; func: TGFunc; user_data: gpointer); cdecl; external; procedure g_list_free(list: PGList); cdecl; external; procedure g_list_free_1(list: PGList); cdecl; external; procedure g_list_free_full(list: PGList; free_func: TGDestroyNotify); cdecl; external; procedure g_log(log_domain: Pgchar; log_level: TGLogLevelFlags; format: Pgchar; args: array of const); cdecl; external; procedure g_log_default_handler(log_domain: Pgchar; log_level: TGLogLevelFlags; message: Pgchar; unused_data: gpointer); cdecl; external; procedure g_log_remove_handler(log_domain: Pgchar; handler_id: guint); cdecl; external; procedure g_logv(log_domain: Pgchar; log_level: TGLogLevelFlags; format: Pgchar; args: Tva_list); cdecl; external; procedure g_main_context_add_poll(context: PGMainContext; fd: PGPollFD; priority: gint); cdecl; external; procedure g_main_context_dispatch(context: PGMainContext); cdecl; external; procedure g_main_context_invoke(context: PGMainContext; function_: TGSourceFunc; data: gpointer); cdecl; external; procedure g_main_context_invoke_full(context: PGMainContext; priority: gint; function_: TGSourceFunc; data: gpointer; notify: TGDestroyNotify); cdecl; external; procedure g_main_context_pop_thread_default(context: PGMainContext); cdecl; external; procedure g_main_context_push_thread_default(context: PGMainContext); cdecl; external; procedure g_main_context_release(context: PGMainContext); cdecl; external; procedure g_main_context_remove_poll(context: PGMainContext; fd: PGPollFD); cdecl; external; procedure g_main_context_set_poll_func(context: PGMainContext; func: TGPollFunc); cdecl; external; procedure g_main_context_unref(context: PGMainContext); cdecl; external; procedure g_main_context_wakeup(context: PGMainContext); cdecl; external; procedure g_main_loop_quit(loop: PGMainLoop); cdecl; external; procedure g_main_loop_run(loop: PGMainLoop); cdecl; external; procedure g_main_loop_unref(loop: PGMainLoop); cdecl; external; procedure g_mapped_file_unref(file_: PGMappedFile); cdecl; external; procedure g_markup_parse_context_free(context: PGMarkupParseContext); cdecl; external; procedure g_markup_parse_context_get_position(context: PGMarkupParseContext; line_number: Pgint; char_number: Pgint); cdecl; external; procedure g_markup_parse_context_push(context: PGMarkupParseContext; parser: PGMarkupParser; user_data: gpointer); cdecl; external; procedure g_markup_parse_context_unref(context: PGMarkupParseContext); cdecl; external; procedure g_match_info_free(match_info: PGMatchInfo); cdecl; external; procedure g_match_info_unref(match_info: PGMatchInfo); cdecl; external; procedure g_mem_profile; cdecl; external; procedure g_mem_set_vtable(vtable: PGMemVTable); cdecl; external; procedure g_mutex_clear(mutex: PGMutex); cdecl; external; procedure g_mutex_init(mutex: PGMutex); cdecl; external; procedure g_mutex_lock(mutex: PGMutex); cdecl; external; procedure g_mutex_unlock(mutex: PGMutex); cdecl; external; procedure g_node_children_foreach(node: PGNode; flags: TGTraverseFlags; func: TGNodeForeachFunc; data: gpointer); cdecl; external; procedure g_node_destroy(root: PGNode); cdecl; external; procedure g_node_reverse_children(node: PGNode); cdecl; external; procedure g_node_traverse(root: PGNode; order: TGTraverseType; flags: TGTraverseFlags; max_depth: gint; func: TGNodeTraverseFunc; data: gpointer); cdecl; external; procedure g_node_unlink(node: PGNode); cdecl; external; procedure g_nullify_pointer(nullify_location: Pgpointer); cdecl; external; procedure g_on_error_query(prg_name: Pgchar); cdecl; external; procedure g_on_error_stack_trace(prg_name: Pgchar); cdecl; external; procedure g_once_init_leave(location: Pgpointer; result_: gsize); cdecl; external; procedure g_option_context_add_group(context: PGOptionContext; group: PGOptionGroup); cdecl; external; procedure g_option_context_add_main_entries(context: PGOptionContext; entries: PGOptionEntry; translation_domain: Pgchar); cdecl; external; procedure g_option_context_free(context: PGOptionContext); cdecl; external; procedure g_option_context_set_description(context: PGOptionContext; description: Pgchar); cdecl; external; procedure g_option_context_set_help_enabled(context: PGOptionContext; help_enabled: gboolean); cdecl; external; procedure g_option_context_set_ignore_unknown_options(context: PGOptionContext; ignore_unknown: gboolean); cdecl; external; procedure g_option_context_set_main_group(context: PGOptionContext; group: PGOptionGroup); cdecl; external; procedure g_option_context_set_summary(context: PGOptionContext; summary: Pgchar); cdecl; external; procedure g_option_context_set_translate_func(context: PGOptionContext; func: TGTranslateFunc; data: gpointer; destroy_notify: TGDestroyNotify); cdecl; external; procedure g_option_context_set_translation_domain(context: PGOptionContext; domain: Pgchar); cdecl; external; procedure g_option_group_add_entries(group: PGOptionGroup; entries: PGOptionEntry); cdecl; external; procedure g_option_group_free(group: PGOptionGroup); cdecl; external; procedure g_option_group_set_error_hook(group: PGOptionGroup; error_func: TGOptionErrorFunc); cdecl; external; procedure g_option_group_set_parse_hooks(group: PGOptionGroup; pre_parse_func: TGOptionParseFunc; post_parse_func: TGOptionParseFunc); cdecl; external; procedure g_option_group_set_translate_func(group: PGOptionGroup; func: TGTranslateFunc; data: gpointer; destroy_notify: TGDestroyNotify); cdecl; external; procedure g_option_group_set_translation_domain(group: PGOptionGroup; domain: Pgchar); cdecl; external; procedure g_pattern_spec_free(pspec: PGPatternSpec); cdecl; external; procedure g_pointer_bit_lock(address: Pgpointer; lock_bit: gint); cdecl; external; procedure g_pointer_bit_unlock(address: Pgpointer; lock_bit: gint); cdecl; external; procedure g_prefix_error(err: PPGError; format: Pgchar; args: array of const); cdecl; external; procedure g_print(format: Pgchar; args: array of const); cdecl; external; procedure g_printerr(format: Pgchar; args: array of const); cdecl; external; procedure g_private_replace(key: PGPrivate; value: gpointer); cdecl; external; procedure g_private_set(key: PGPrivate; value: gpointer); cdecl; external; procedure g_propagate_error(dest: PPGError; src: PGError); cdecl; external; procedure g_propagate_prefixed_error(dest: PPGError; src: PGError; format: Pgchar; args: array of const); cdecl; external; procedure g_ptr_array_add(array_: Pgpointer; data: gpointer); cdecl; external; procedure g_ptr_array_foreach(array_: Pgpointer; func: TGFunc; user_data: gpointer); cdecl; external; procedure g_ptr_array_remove_range(array_: Pgpointer; index_: guint; length: guint); cdecl; external; procedure g_ptr_array_set_free_func(array_: Pgpointer; element_free_func: TGDestroyNotify); cdecl; external; procedure g_ptr_array_set_size(array_: Pgpointer; length: gint); cdecl; external; procedure g_ptr_array_sort(array_: Pgpointer; compare_func: TGCompareFunc); cdecl; external; procedure g_ptr_array_sort_with_data(array_: Pgpointer; compare_func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_ptr_array_unref(array_: Pgpointer); cdecl; external; procedure g_qsort_with_data(pbase: Pgpointer; total_elems: gint; size: gsize; compare_func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_queue_clear(queue: PGQueue); cdecl; external; procedure g_queue_delete_link(queue: PGQueue; link_: PGList); cdecl; external; procedure g_queue_foreach(queue: PGQueue; func: TGFunc; user_data: gpointer); cdecl; external; procedure g_queue_free(queue: PGQueue); cdecl; external; procedure g_queue_free_full(queue: PGQueue; free_func: TGDestroyNotify); cdecl; external; procedure g_queue_init(queue: PGQueue); cdecl; external; procedure g_queue_insert_after(queue: PGQueue; sibling: PGList; data: gpointer); cdecl; external; procedure g_queue_insert_before(queue: PGQueue; sibling: PGList; data: gpointer); cdecl; external; procedure g_queue_insert_sorted(queue: PGQueue; data: gpointer; func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_queue_push_head(queue: PGQueue; data: gpointer); cdecl; external; procedure g_queue_push_head_link(queue: PGQueue; link_: PGList); cdecl; external; procedure g_queue_push_nth(queue: PGQueue; data: gpointer; n: gint); cdecl; external; procedure g_queue_push_nth_link(queue: PGQueue; n: gint; link_: PGList); cdecl; external; procedure g_queue_push_tail(queue: PGQueue; data: gpointer); cdecl; external; procedure g_queue_push_tail_link(queue: PGQueue; link_: PGList); cdecl; external; procedure g_queue_reverse(queue: PGQueue); cdecl; external; procedure g_queue_sort(queue: PGQueue; compare_func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_queue_unlink(queue: PGQueue; link_: PGList); cdecl; external; procedure g_rand_free(rand_: PGRand); cdecl; external; procedure g_rand_set_seed(rand_: PGRand; seed: guint32); cdecl; external; procedure g_rand_set_seed_array(rand_: PGRand; seed: Pguint32; seed_length: guint); cdecl; external; procedure g_random_set_seed(seed: guint32); cdecl; external; procedure g_rec_mutex_clear(rec_mutex: PGRecMutex); cdecl; external; procedure g_rec_mutex_init(rec_mutex: PGRecMutex); cdecl; external; procedure g_rec_mutex_lock(rec_mutex: PGRecMutex); cdecl; external; procedure g_rec_mutex_unlock(rec_mutex: PGRecMutex); cdecl; external; procedure g_regex_unref(regex: PGRegex); cdecl; external; procedure g_reload_user_special_dirs_cache; cdecl; external; procedure g_return_if_fail_warning(log_domain: Pgchar; pretty_function: Pgchar; expression: Pgchar); cdecl; external; procedure g_rw_lock_clear(rw_lock: PGRWLock); cdecl; external; procedure g_rw_lock_init(rw_lock: PGRWLock); cdecl; external; procedure g_rw_lock_reader_lock(rw_lock: PGRWLock); cdecl; external; procedure g_rw_lock_reader_unlock(rw_lock: PGRWLock); cdecl; external; procedure g_rw_lock_writer_lock(rw_lock: PGRWLock); cdecl; external; procedure g_rw_lock_writer_unlock(rw_lock: PGRWLock); cdecl; external; procedure g_scanner_destroy(scanner: PGScanner); cdecl; external; procedure g_scanner_error(scanner: PGScanner; format: Pgchar; args: array of const); cdecl; external; procedure g_scanner_input_file(scanner: PGScanner; input_fd: gint); cdecl; external; procedure g_scanner_input_text(scanner: PGScanner; text: Pgchar; text_len: guint); cdecl; external; procedure g_scanner_scope_add_symbol(scanner: PGScanner; scope_id: guint; symbol: Pgchar; value: gpointer); cdecl; external; procedure g_scanner_scope_foreach_symbol(scanner: PGScanner; scope_id: guint; func: TGHFunc; user_data: gpointer); cdecl; external; procedure g_scanner_scope_remove_symbol(scanner: PGScanner; scope_id: guint; symbol: Pgchar); cdecl; external; procedure g_scanner_sync_file_offset(scanner: PGScanner); cdecl; external; procedure g_scanner_unexp_token(scanner: PGScanner; expected_token: TGTokenType; identifier_spec: Pgchar; symbol_spec: Pgchar; symbol_name: Pgchar; message: Pgchar; is_error: gint); cdecl; external; procedure g_scanner_warn(scanner: PGScanner; format: Pgchar; args: array of const); cdecl; external; procedure g_sequence_foreach(seq: PGSequence; func: TGFunc; user_data: gpointer); cdecl; external; procedure g_sequence_foreach_range(begin_: PGSequenceIter; end_: PGSequenceIter; func: TGFunc; user_data: gpointer); cdecl; external; procedure g_sequence_free(seq: PGSequence); cdecl; external; procedure g_sequence_move(src: PGSequenceIter; dest: PGSequenceIter); cdecl; external; procedure g_sequence_move_range(dest: PGSequenceIter; begin_: PGSequenceIter; end_: PGSequenceIter); cdecl; external; procedure g_sequence_remove(iter: PGSequenceIter); cdecl; external; procedure g_sequence_remove_range(begin_: PGSequenceIter; end_: PGSequenceIter); cdecl; external; procedure g_sequence_set(iter: PGSequenceIter; data: gpointer); cdecl; external; procedure g_sequence_sort(seq: PGSequence; cmp_func: TGCompareDataFunc; cmp_data: gpointer); cdecl; external; procedure g_sequence_sort_changed(iter: PGSequenceIter; cmp_func: TGCompareDataFunc; cmp_data: gpointer); cdecl; external; procedure g_sequence_sort_changed_iter(iter: PGSequenceIter; iter_cmp: TGSequenceIterCompareFunc; cmp_data: gpointer); cdecl; external; procedure g_sequence_sort_iter(seq: PGSequence; cmp_func: TGSequenceIterCompareFunc; cmp_data: gpointer); cdecl; external; procedure g_sequence_swap(a: PGSequenceIter; b: PGSequenceIter); cdecl; external; procedure g_set_application_name(application_name: Pgchar); cdecl; external; procedure g_set_error(err: PPGError; domain: TGQuark; code: gint; format: Pgchar; args: array of const); cdecl; external; procedure g_set_error_literal(err: PPGError; domain: TGQuark; code: gint; message: Pgchar); cdecl; external; procedure g_set_prgname(prgname: Pgchar); cdecl; external; procedure g_slice_free1(block_size: gsize; mem_block: gpointer); cdecl; external; procedure g_slice_free_chain_with_offset(block_size: gsize; mem_chain: gpointer; next_offset: gsize); cdecl; external; procedure g_slice_set_config(ckey: TGSliceConfig; value: gint64); cdecl; external; procedure g_slist_foreach(list: PGSList; func: TGFunc; user_data: gpointer); cdecl; external; procedure g_slist_free(list: PGSList); cdecl; external; procedure g_slist_free_1(list: PGSList); cdecl; external; procedure g_slist_free_full(list: PGSList; free_func: TGDestroyNotify); cdecl; external; procedure g_source_add_child_source(source: PGSource; child_source: PGSource); cdecl; external; procedure g_source_add_poll(source: PGSource; fd: PGPollFD); cdecl; external; procedure g_source_destroy(source: PGSource); cdecl; external; procedure g_source_modify_unix_fd(source: PGSource; tag: gpointer; new_events: TGIOCondition); cdecl; external; procedure g_source_remove_child_source(source: PGSource; child_source: PGSource); cdecl; external; procedure g_source_remove_poll(source: PGSource; fd: PGPollFD); cdecl; external; procedure g_source_remove_unix_fd(source: PGSource; tag: gpointer); cdecl; external; procedure g_source_set_callback(source: PGSource; func: TGSourceFunc; data: gpointer; notify: TGDestroyNotify); cdecl; external; procedure g_source_set_callback_indirect(source: PGSource; callback_data: gpointer; callback_funcs: PGSourceCallbackFuncs); cdecl; external; procedure g_source_set_can_recurse(source: PGSource; can_recurse: gboolean); cdecl; external; procedure g_source_set_funcs(source: PGSource; funcs: PGSourceFuncs); cdecl; external; procedure g_source_set_name(source: PGSource; name: Pgchar); cdecl; external; procedure g_source_set_name_by_id(tag: guint; name: Pgchar); cdecl; external; procedure g_source_set_priority(source: PGSource; priority: gint); cdecl; external; procedure g_source_set_ready_time(source: PGSource; ready_time: gint64); cdecl; external; procedure g_source_unref(source: PGSource); cdecl; external; procedure g_spawn_close_pid(pid: TGPid); cdecl; external; procedure g_strfreev(str_array: PPgchar); cdecl; external; procedure g_string_append_printf(string_: PGString; format: Pgchar; args: array of const); cdecl; external; procedure g_string_append_vprintf(string_: PGString; format: Pgchar; args: Tva_list); cdecl; external; procedure g_string_chunk_clear(chunk: PGStringChunk); cdecl; external; procedure g_string_chunk_free(chunk: PGStringChunk); cdecl; external; procedure g_string_printf(string_: PGString; format: Pgchar; args: array of const); cdecl; external; procedure g_string_vprintf(string_: PGString; format: Pgchar; args: Tva_list); cdecl; external; procedure g_test_add_data_func(testpath: Pgchar; test_data: Pgpointer; test_func: TGTestDataFunc); cdecl; external; procedure g_test_add_data_func_full(testpath: Pgchar; test_data: gpointer; test_func: TGTestDataFunc; data_free_func: TGDestroyNotify); cdecl; external; procedure g_test_add_func(testpath: Pgchar; test_func: TGTestFunc); cdecl; external; procedure g_test_add_vtable(testpath: Pgchar; data_size: gsize; test_data: Pgpointer; data_setup: TGTestFixtureFunc; data_test: TGTestFixtureFunc; data_teardown: TGTestFixtureFunc); cdecl; external; procedure g_test_assert_expected_messages_internal(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar); cdecl; external; procedure g_test_bug(bug_uri_snippet: Pgchar); cdecl; external; procedure g_test_bug_base(uri_pattern: Pgchar); cdecl; external; procedure g_test_expect_message(log_domain: Pgchar; log_level: TGLogLevelFlags; pattern: Pgchar); cdecl; external; procedure g_test_fail; cdecl; external; procedure g_test_init(argc: Pgint; argv: PPPgchar; args: array of const); cdecl; external; procedure g_test_log_buffer_free(tbuffer: PGTestLogBuffer); cdecl; external; procedure g_test_log_buffer_push(tbuffer: PGTestLogBuffer; n_bytes: guint; bytes: Pguint8); cdecl; external; procedure g_test_log_msg_free(tmsg: PGTestLogMsg); cdecl; external; procedure g_test_log_set_fatal_handler(log_func: TGTestLogFatalFunc; user_data: gpointer); cdecl; external; procedure g_test_maximized_result(maximized_quantity: gdouble; format: Pgchar; args: array of const); cdecl; external; procedure g_test_message(format: Pgchar; args: array of const); cdecl; external; procedure g_test_minimized_result(minimized_quantity: gdouble; format: Pgchar; args: array of const); cdecl; external; procedure g_test_queue_destroy(destroy_func: TGDestroyNotify; destroy_data: gpointer); cdecl; external; procedure g_test_queue_free(gfree_pointer: gpointer); cdecl; external; procedure g_test_suite_add(suite: PGTestSuite; test_case: PGTestCase); cdecl; external; procedure g_test_suite_add_suite(suite: PGTestSuite; nestedsuite: PGTestSuite); cdecl; external; procedure g_test_timer_start; cdecl; external; procedure g_test_trap_assertions(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; assertion_flags: guint64; pattern: Pgchar); cdecl; external; procedure g_thread_exit(retval: gpointer); cdecl; external; procedure g_thread_pool_free(pool: PGThreadPool; immediate: gboolean; wait_: gboolean); cdecl; external; procedure g_thread_pool_set_max_idle_time(interval: guint); cdecl; external; procedure g_thread_pool_set_max_unused_threads(max_threads: gint); cdecl; external; procedure g_thread_pool_set_sort_function(pool: PGThreadPool; func: TGCompareDataFunc; user_data: gpointer); cdecl; external; procedure g_thread_pool_stop_unused_threads; cdecl; external; procedure g_thread_unref(thread: PGThread); cdecl; external; procedure g_thread_yield; cdecl; external; procedure g_time_val_add(time_: PGTimeVal; microseconds: glong); cdecl; external; procedure g_time_zone_unref(tz: PGTimeZone); cdecl; external; procedure g_timer_continue(timer: PGTimer); cdecl; external; procedure g_timer_destroy(timer: PGTimer); cdecl; external; procedure g_timer_reset(timer: PGTimer); cdecl; external; procedure g_timer_start(timer: PGTimer); cdecl; external; procedure g_timer_stop(timer: PGTimer); cdecl; external; procedure g_trash_stack_push(stack_p: PPGTrashStack; data_p: gpointer); cdecl; external; procedure g_tree_destroy(tree: PGTree); cdecl; external; procedure g_tree_foreach(tree: PGTree; func: TGTraverseFunc; user_data: gpointer); cdecl; external; procedure g_tree_insert(tree: PGTree; key: gpointer; value: gpointer); cdecl; external; procedure g_tree_replace(tree: PGTree; key: gpointer; value: gpointer); cdecl; external; procedure g_tree_unref(tree: PGTree); cdecl; external; procedure g_unicode_canonical_ordering(string_: Pgunichar; len: gsize); cdecl; external; procedure g_unsetenv(variable: Pgchar); cdecl; external; procedure g_usleep(microseconds: gulong); cdecl; external; procedure g_variant_builder_add(builder: PGVariantBuilder; format_string: Pgchar; args: array of const); cdecl; external; procedure g_variant_builder_add_parsed(builder: PGVariantBuilder; format: Pgchar; args: array of const); cdecl; external; procedure g_variant_builder_add_value(builder: PGVariantBuilder; value: PGVariant); cdecl; external; procedure g_variant_builder_clear(builder: PGVariantBuilder); cdecl; external; procedure g_variant_builder_close(builder: PGVariantBuilder); cdecl; external; procedure g_variant_builder_init(builder: PGVariantBuilder; type_: PGVariantType); cdecl; external; procedure g_variant_builder_open(builder: PGVariantBuilder; type_: PGVariantType); cdecl; external; procedure g_variant_builder_unref(builder: PGVariantBuilder); cdecl; external; procedure g_variant_get(value: PGVariant; format_string: Pgchar; args: array of const); cdecl; external; procedure g_variant_get_child(value: PGVariant; index_: gsize; format_string: Pgchar; args: array of const); cdecl; external; procedure g_variant_get_va(value: PGVariant; format_string: Pgchar; endptr: PPgchar; app: Pva_list); cdecl; external; procedure g_variant_iter_free(iter: PGVariantIter); cdecl; external; procedure g_variant_store(value: PGVariant; data: gpointer); cdecl; external; procedure g_variant_type_free(type_: PGVariantType); cdecl; external; procedure g_variant_unref(value: PGVariant); cdecl; external; procedure g_warn_message(domain: Pgchar; file_: Pgchar; line: gint; func: Pgchar; warnexpr: Pgchar); cdecl; external; implementation end.�������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/glib/ugobject2.pas�����������������������������������������������0000644�0001750�0000144�00000205536�14743153644�021525� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an autogenerated unit using gobject introspection (gir2pascal). Do not Edit. } unit uGObject2; {$MODE OBJFPC}{$H+} {$PACKRECORDS C} {$MODESWITCH DUPLICATELOCALS+} {$LINKLIB libgobject-2.0.so.0} interface uses CTypes, uGLib2; const GObject2_library = 'libgobject-2.0.so.0'; PARAM_MASK = 255; PARAM_READWRITE = 0; PARAM_STATIC_STRINGS = 0; PARAM_USER_SHIFT = 8; SIGNAL_FLAGS_MASK = 511; SIGNAL_MATCH_MASK = 63; TYPE_FLAG_RESERVED_ID_BIT = 1; TYPE_FUNDAMENTAL_MAX = 255; TYPE_FUNDAMENTAL_SHIFT = 2; TYPE_RESERVED_BSE_FIRST = 32; TYPE_RESERVED_BSE_LAST = 48; TYPE_RESERVED_GLIB_FIRST = 22; TYPE_RESERVED_GLIB_LAST = 31; TYPE_RESERVED_USER_FIRST = 49; VALUE_COLLECT_FORMAT_MAX_LENGTH = 8; VALUE_NOCOPY_CONTENTS = 134217728; type TGBindingFlags = Integer; const { GBindingFlags } G_BINDING_DEFAULT: TGBindingFlags = 0; G_BINDING_BIDIRECTIONAL: TGBindingFlags = 1; G_BINDING_SYNC_CREATE: TGBindingFlags = 2; G_BINDING_INVERT_BOOLEAN: TGBindingFlags = 4; type TGConnectFlags = Integer; const { GConnectFlags } G_CONNECT_AFTER: TGConnectFlags = 1; G_CONNECT_SWAPPED: TGConnectFlags = 2; type TGParamFlags = Integer; const { GParamFlags } G_PARAM_READABLE: TGParamFlags = 1; G_PARAM_WRITABLE: TGParamFlags = 2; G_PARAM_CONSTRUCT: TGParamFlags = 4; G_PARAM_CONSTRUCT_ONLY: TGParamFlags = 8; G_PARAM_LAX_VALIDATION: TGParamFlags = 16; G_PARAM_STATIC_NAME: TGParamFlags = 32; G_PARAM_PRIVATE: TGParamFlags = 32; G_PARAM_STATIC_NICK: TGParamFlags = 64; G_PARAM_STATIC_BLURB: TGParamFlags = 128; type TGSignalFlags = Integer; const { GSignalFlags } G_SIGNAL_RUN_FIRST: TGSignalFlags = 1; G_SIGNAL_RUN_LAST: TGSignalFlags = 2; G_SIGNAL_RUN_CLEANUP: TGSignalFlags = 4; G_SIGNAL_NO_RECURSE: TGSignalFlags = 8; G_SIGNAL_DETAILED: TGSignalFlags = 16; G_SIGNAL_ACTION: TGSignalFlags = 32; G_SIGNAL_NO_HOOKS: TGSignalFlags = 64; G_SIGNAL_MUST_COLLECT: TGSignalFlags = 128; G_SIGNAL_DEPRECATED: TGSignalFlags = 256; type TGSignalMatchType = Integer; const { GSignalMatchType } G_SIGNAL_MATCH_ID: TGSignalMatchType = 1; G_SIGNAL_MATCH_DETAIL: TGSignalMatchType = 2; G_SIGNAL_MATCH_CLOSURE: TGSignalMatchType = 4; G_SIGNAL_MATCH_FUNC: TGSignalMatchType = 8; G_SIGNAL_MATCH_DATA: TGSignalMatchType = 16; G_SIGNAL_MATCH_UNBLOCKED: TGSignalMatchType = 32; type TGTypeDebugFlags = Integer; const { GTypeDebugFlags } G_TYPE_DEBUG_NONE: TGTypeDebugFlags = 0; G_TYPE_DEBUG_OBJECTS: TGTypeDebugFlags = 1; G_TYPE_DEBUG_SIGNALS: TGTypeDebugFlags = 2; G_TYPE_DEBUG_MASK: TGTypeDebugFlags = 3; type TGTypeFlags = Integer; const { GTypeFlags } G_TYPE_FLAG_ABSTRACT: TGTypeFlags = 16; G_TYPE_FLAG_VALUE_ABSTRACT: TGTypeFlags = 32; type TGTypeFundamentalFlags = Integer; const { GTypeFundamentalFlags } G_TYPE_FLAG_CLASSED: TGTypeFundamentalFlags = 1; G_TYPE_FLAG_INSTANTIATABLE: TGTypeFundamentalFlags = 2; G_TYPE_FLAG_DERIVABLE: TGTypeFundamentalFlags = 4; G_TYPE_FLAG_DEEP_DERIVABLE: TGTypeFundamentalFlags = 8; type PPGClosure = ^PGClosure; PGClosure = ^TGClosure; PPPGValue = ^PPGValue; PPGValue = ^PGValue; PGValue = ^TGValue; TGClosureMarshal = procedure(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; PPGSignalCMarshaller = ^PGSignalCMarshaller; PGSignalCMarshaller = ^TGSignalCMarshaller; TGSignalCMarshaller = TGClosureMarshal; TGVaClosureMarshal = procedure(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; PPGSignalCVaMarshaller = ^PGSignalCVaMarshaller; PGSignalCVaMarshaller = ^TGSignalCVaMarshaller; TGSignalCVaMarshaller = TGVaClosureMarshal; PPGType = ^PGType; PGType = ^TGType; TGType = gsize; TGBaseFinalizeFunc = procedure(g_class: gpointer); cdecl; TGBaseInitFunc = procedure(g_class: gpointer); cdecl; PPGBindingFlags = ^PGBindingFlags; PGBindingFlags = ^TGBindingFlags; PPGBinding = ^PGBinding; PGBinding = ^TGBinding; PPGObject = ^PGObject; PGObject = ^TGObject; PPGParameter = ^PGParameter; PGParameter = ^TGParameter; PPGParamSpec = ^PGParamSpec; PGParamSpec = ^TGParamSpec; PPGToggleNotify = ^PGToggleNotify; PGToggleNotify = ^TGToggleNotify; TGToggleNotify = procedure(data: gpointer; object_: PGObject; is_last_ref: gboolean); cdecl; PPGBindingTransformFunc = ^PGBindingTransformFunc; PGBindingTransformFunc = ^TGBindingTransformFunc; TGBindingTransformFunc = function(binding: PGBinding; source_value: PGValue; target_value: PGValue; user_data: gpointer): gboolean; cdecl; PPGWeakNotify = ^PGWeakNotify; PGWeakNotify = ^TGWeakNotify; TGWeakNotify = procedure(data: gpointer; where_the_object_was: PGObject); cdecl; PPGTypeInstance = ^PGTypeInstance; PGTypeInstance = ^TGTypeInstance; PPGTypeClass = ^PGTypeClass; PGTypeClass = ^TGTypeClass; TGTypeInstance = object g_class: PGTypeClass; end; TGObject = object g_type_instance: TGTypeInstance; ref_count: guint; qdata: PGData; end; TGBinding = object(TGObject) end; PPGValueTransform = ^PGValueTransform; PGValueTransform = ^TGValueTransform; TGValueTransform = procedure(src_value: PGValue; dest_value: PGValue); cdecl; PP_Value__data__union = ^P_Value__data__union; P_Value__data__union = ^T_Value__data__union; T_Value__data__union = record case longint of 0 : (v_int: gint); 1 : (v_uint: guint); 2 : (v_long: glong); 3 : (v_ulong: gulong); 4 : (v_int64: gint64); 5 : (v_uint64: guint64); 6 : (v_float: gfloat); 7 : (v_double: gdouble); 8 : (v_pointer: gpointer); end; TGValue = object g_type: TGType; data: array [0..1] of T_Value__data__union; end; TGBoxedCopyFunc = function(boxed: gpointer): gpointer; cdecl; TGBoxedFreeFunc = procedure(boxed: gpointer); cdecl; PPGClosureNotify = ^PGClosureNotify; PGClosureNotify = ^TGClosureNotify; TGClosureNotify = procedure(data: gpointer; closure: PGClosure); cdecl; PPGClosureMarshal = ^PGClosureMarshal; PGClosureMarshal = ^TGClosureMarshal; TGClosureBitfield0 = bitpacked record ref_count: guint15 { changed from guint to accomodate 15 bitsize requirement }; meta_marshal_nouse: guint1 { changed from guint to accomodate 1 bitsize requirement }; n_guards: guint1 { changed from guint to accomodate 1 bitsize requirement }; n_fnotifiers: guint2 { changed from guint to accomodate 2 bitsize requirement }; n_inotifiers: guint8 { changed from guint to accomodate 8 bitsize requirement }; in_inotify: guint1 { changed from guint to accomodate 1 bitsize requirement }; floating: guint1 { changed from guint to accomodate 1 bitsize requirement }; derivative_flag: guint1 { changed from guint to accomodate 1 bitsize requirement }; in_marshal: guint1 { changed from guint to accomodate 1 bitsize requirement }; is_invalid: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; PPGClosureNotifyData = ^PGClosureNotifyData; PGClosureNotifyData = ^TGClosureNotifyData; TGClosure = object Bitfield0 : TGClosureBitfield0; { auto generated type } marshal: procedure(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; data: gpointer; notifiers: PGClosureNotifyData; end; TGCallback = procedure; cdecl; PPGCClosure = ^PGCClosure; PGCClosure = ^TGCClosure; PPGCallback = ^PGCallback; PGCallback = ^TGCallback; TGCClosure = object closure: TGClosure; callback: gpointer; end; TGClassFinalizeFunc = procedure(g_class: gpointer; class_data: gpointer); cdecl; TGClassInitFunc = procedure(g_class: gpointer; class_data: gpointer); cdecl; TGClosureNotifyData = record data: gpointer; notify: TGClosureNotify; end; PPGConnectFlags = ^PGConnectFlags; PGConnectFlags = ^TGConnectFlags; TGTypeClass = object g_type: TGType; end; PPGEnumValue = ^PGEnumValue; PGEnumValue = ^TGEnumValue; TGEnumValue = record value: gint; value_name: Pgchar; value_nick: Pgchar; end; PPGEnumClass = ^PGEnumClass; PGEnumClass = ^TGEnumClass; TGEnumClass = record g_type_class: TGTypeClass; minimum: gint; maximum: gint; n_values: guint; values: PGEnumValue; end; PPGFlagsValue = ^PGFlagsValue; PGFlagsValue = ^TGFlagsValue; TGFlagsValue = record value: guint; value_name: Pgchar; value_nick: Pgchar; end; PPGFlagsClass = ^PGFlagsClass; PGFlagsClass = ^TGFlagsClass; TGFlagsClass = record g_type_class: TGTypeClass; mask: guint; n_values: guint; values: PGFlagsValue; end; PPGInitiallyUnowned = ^PGInitiallyUnowned; PGInitiallyUnowned = ^TGInitiallyUnowned; TGInitiallyUnowned = object(TGObject) end; PPGObjectConstructParam = ^PGObjectConstructParam; PGObjectConstructParam = ^TGObjectConstructParam; TGObjectConstructParam = record pspec: PGParamSpec; value: PGValue; end; PPGParamFlags = ^PGParamFlags; PGParamFlags = ^TGParamFlags; TGParamSpec = object g_type_instance: TGTypeInstance; name: Pgchar; flags: TGParamFlags; value_type: TGType; owner_type: TGType; _nick: Pgchar; _blurb: Pgchar; qdata: PGData; ref_count: guint; param_id: guint; end; PPGInitiallyUnownedClass = ^PGInitiallyUnownedClass; PGInitiallyUnownedClass = ^TGInitiallyUnownedClass; TGInitiallyUnownedClass = object g_type_class: TGTypeClass; construct_properties: PGSList; constructor_: function(type_: TGType; n_construct_properties: guint; construct_properties: PGObjectConstructParam): PGObject; cdecl; set_property: procedure(object_: PGObject; property_id: guint; value: PGValue; pspec: PGParamSpec); cdecl; get_property: procedure(object_: PGObject; property_id: guint; value: PGValue; pspec: PGParamSpec); cdecl; dispose: procedure(object_: PGObject); cdecl; finalize: procedure(object_: PGObject); cdecl; dispatch_properties_changed: procedure(object_: PGObject; n_pspecs: guint; pspecs: PPGParamSpec); cdecl; notify: procedure(object_: PGObject; pspec: PGParamSpec); cdecl; constructed: procedure(object_: PGObject); cdecl; flags: gsize; pdummy: array [0..5] of gpointer; end; TGInstanceInitFunc = procedure(instance: PGTypeInstance; g_class: gpointer); cdecl; TGInterfaceFinalizeFunc = procedure(g_iface: gpointer; iface_data: gpointer); cdecl; TGInterfaceInitFunc = procedure(g_iface: gpointer; iface_data: gpointer); cdecl; PPGInterfaceInfo = ^PGInterfaceInfo; PGInterfaceInfo = ^TGInterfaceInfo; PPGInterfaceInitFunc = ^PGInterfaceInitFunc; PGInterfaceInitFunc = ^TGInterfaceInitFunc; PPGInterfaceFinalizeFunc = ^PGInterfaceFinalizeFunc; PGInterfaceFinalizeFunc = ^TGInterfaceFinalizeFunc; TGInterfaceInfo = record interface_init: TGInterfaceInitFunc; interface_finalize: TGInterfaceFinalizeFunc; interface_data: gpointer; end; TGParameter = record name: Pgchar; value: TGValue; end; PPGObjectClass = ^PGObjectClass; PGObjectClass = ^TGObjectClass; TGObjectClass = object g_type_class: TGTypeClass; construct_properties: PGSList; constructor_: function(type_: TGType; n_construct_properties: guint; construct_properties: PGObjectConstructParam): PGObject; cdecl; set_property: procedure(object_: PGObject; property_id: guint; value: PGValue; pspec: PGParamSpec); cdecl; get_property: procedure(object_: PGObject; property_id: guint; value: PGValue; pspec: PGParamSpec); cdecl; dispose: procedure(object_: PGObject); cdecl; finalize: procedure(object_: PGObject); cdecl; dispatch_properties_changed: procedure(object_: PGObject; n_pspecs: guint; pspecs: PPGParamSpec); cdecl; notify: procedure(object_: PGObject; pspec: PGParamSpec); cdecl; constructed: procedure(object_: PGObject); cdecl; flags: gsize; pdummy: array [0..5] of gpointer; end; TGObjectFinalizeFunc = procedure(object_: PGObject); cdecl; TGObjectGetPropertyFunc = procedure(object_: PGObject; property_id: guint; value: PGValue; pspec: PGParamSpec); cdecl; TGObjectSetPropertyFunc = procedure(object_: PGObject; property_id: guint; value: PGValue; pspec: PGParamSpec); cdecl; PPGParamSpecBoolean = ^PGParamSpecBoolean; PGParamSpecBoolean = ^TGParamSpecBoolean; TGParamSpecBoolean = object(TGParamSpec) default_value: gboolean; end; PPGParamSpecBoxed = ^PGParamSpecBoxed; PGParamSpecBoxed = ^TGParamSpecBoxed; TGParamSpecBoxed = object(TGParamSpec) end; PPGParamSpecChar = ^PGParamSpecChar; PGParamSpecChar = ^TGParamSpecChar; TGParamSpecChar = object(TGParamSpec) minimum: gint8; maximum: gint8; default_value: gint8; end; PPGParamSpecClass = ^PGParamSpecClass; PGParamSpecClass = ^TGParamSpecClass; TGParamSpecClass = object g_type_class: TGTypeClass; value_type: TGType; finalize: procedure(pspec: PGParamSpec); cdecl; value_set_default: procedure(pspec: PGParamSpec; value: PGValue); cdecl; value_validate: function(pspec: PGParamSpec; value: PGValue): gboolean; cdecl; values_cmp: function(pspec: PGParamSpec; value1: PGValue; value2: PGValue): gint; cdecl; dummy: array [0..3] of gpointer; end; PPGParamSpecDouble = ^PGParamSpecDouble; PGParamSpecDouble = ^TGParamSpecDouble; TGParamSpecDouble = object(TGParamSpec) minimum: gdouble; maximum: gdouble; default_value: gdouble; epsilon: gdouble; end; PPGParamSpecEnum = ^PGParamSpecEnum; PGParamSpecEnum = ^TGParamSpecEnum; TGParamSpecEnum = object(TGParamSpec) enum_class: PGEnumClass; default_value: gint; end; PPGParamSpecFlags = ^PGParamSpecFlags; PGParamSpecFlags = ^TGParamSpecFlags; TGParamSpecFlags = object(TGParamSpec) flags_class: PGFlagsClass; default_value: guint; end; PPGParamSpecFloat = ^PGParamSpecFloat; PGParamSpecFloat = ^TGParamSpecFloat; TGParamSpecFloat = object(TGParamSpec) minimum: gfloat; maximum: gfloat; default_value: gfloat; epsilon: gfloat; end; PPGParamSpecGType = ^PGParamSpecGType; PGParamSpecGType = ^TGParamSpecGType; TGParamSpecGType = object(TGParamSpec) is_a_type: TGType; end; PPGParamSpecInt = ^PGParamSpecInt; PGParamSpecInt = ^TGParamSpecInt; TGParamSpecInt = object(TGParamSpec) minimum: gint; maximum: gint; default_value: gint; end; PPGParamSpecInt64 = ^PGParamSpecInt64; PGParamSpecInt64 = ^TGParamSpecInt64; TGParamSpecInt64 = object(TGParamSpec) minimum: gint64; maximum: gint64; default_value: gint64; end; PPGParamSpecLong = ^PGParamSpecLong; PGParamSpecLong = ^TGParamSpecLong; TGParamSpecLong = object(TGParamSpec) minimum: glong; maximum: glong; default_value: glong; end; PPGParamSpecObject = ^PGParamSpecObject; PGParamSpecObject = ^TGParamSpecObject; TGParamSpecObject = object(TGParamSpec) end; PPGParamSpecOverride = ^PGParamSpecOverride; PGParamSpecOverride = ^TGParamSpecOverride; TGParamSpecOverride = object(TGParamSpec) overridden: PGParamSpec; end; PPGParamSpecParam = ^PGParamSpecParam; PGParamSpecParam = ^TGParamSpecParam; TGParamSpecParam = object(TGParamSpec) end; PPGParamSpecPointer = ^PGParamSpecPointer; PGParamSpecPointer = ^TGParamSpecPointer; TGParamSpecPointer = object(TGParamSpec) end; PPGParamSpecPool = ^PGParamSpecPool; PGParamSpecPool = ^TGParamSpecPool; TGParamSpecPool = object end; PPGParamSpecString = ^PGParamSpecString; PGParamSpecString = ^TGParamSpecString; TGParamSpecStringBitfield0 = bitpacked record null_fold_if_empty: guint1 { changed from guint to accomodate 1 bitsize requirement }; ensure_non_null: guint1 { changed from guint to accomodate 1 bitsize requirement }; end; TGParamSpecString = object(TGParamSpec) default_value: Pgchar; cset_first: Pgchar; cset_nth: Pgchar; substitutor: gchar; Bitfield0 : TGParamSpecStringBitfield0; { auto generated type } end; PPGParamSpecTypeInfo = ^PGParamSpecTypeInfo; PGParamSpecTypeInfo = ^TGParamSpecTypeInfo; TGParamSpecTypeInfo = record instance_size: guint16; n_preallocs: guint16; instance_init: procedure(pspec: PGParamSpec); cdecl; value_type: TGType; finalize: procedure(pspec: PGParamSpec); cdecl; value_set_default: procedure(pspec: PGParamSpec; value: PGValue); cdecl; value_validate: function(pspec: PGParamSpec; value: PGValue): gboolean; cdecl; values_cmp: function(pspec: PGParamSpec; value1: PGValue; value2: PGValue): gint; cdecl; end; PPGParamSpecUChar = ^PGParamSpecUChar; PGParamSpecUChar = ^TGParamSpecUChar; TGParamSpecUChar = object(TGParamSpec) minimum: guint8; maximum: guint8; default_value: guint8; end; PPGParamSpecUInt = ^PGParamSpecUInt; PGParamSpecUInt = ^TGParamSpecUInt; TGParamSpecUInt = object(TGParamSpec) minimum: guint; maximum: guint; default_value: guint; end; PPGParamSpecUInt64 = ^PGParamSpecUInt64; PGParamSpecUInt64 = ^TGParamSpecUInt64; TGParamSpecUInt64 = object(TGParamSpec) minimum: guint64; maximum: guint64; default_value: guint64; end; PPGParamSpecULong = ^PGParamSpecULong; PGParamSpecULong = ^TGParamSpecULong; TGParamSpecULong = object(TGParamSpec) minimum: gulong; maximum: gulong; default_value: gulong; end; PPGParamSpecUnichar = ^PGParamSpecUnichar; PGParamSpecUnichar = ^TGParamSpecUnichar; TGParamSpecUnichar = object(TGParamSpec) default_value: gunichar; end; PPGParamSpecValueArray = ^PGParamSpecValueArray; PGParamSpecValueArray = ^TGParamSpecValueArray; TGParamSpecValueArray = object(TGParamSpec) element_spec: PGParamSpec; fixed_n_elements: guint; end; PPGParamSpecVariant = ^PGParamSpecVariant; PGParamSpecVariant = ^TGParamSpecVariant; TGParamSpecVariant = object(TGParamSpec) type_: PGVariantType; default_value: PGVariant; padding: array [0..3] of gpointer; end; PPGSignalInvocationHint = ^PGSignalInvocationHint; PGSignalInvocationHint = ^TGSignalInvocationHint; PPGSignalFlags = ^PGSignalFlags; PGSignalFlags = ^TGSignalFlags; TGSignalInvocationHint = record signal_id: guint; detail: TGQuark; run_type: TGSignalFlags; end; TGSignalAccumulator = function(ihint: PGSignalInvocationHint; return_accu: PGValue; handler_return: PGValue; data: gpointer): gboolean; cdecl; TGSignalEmissionHook = function(ihint: PGSignalInvocationHint; n_param_values: guint; param_values: PGValue; data: gpointer): gboolean; cdecl; PPGSignalMatchType = ^PGSignalMatchType; PGSignalMatchType = ^TGSignalMatchType; PPGSignalQuery = ^PGSignalQuery; PGSignalQuery = ^TGSignalQuery; TGSignalQuery = record signal_id: guint; signal_name: Pgchar; itype: TGType; signal_flags: TGSignalFlags; return_type: TGType; n_params: guint; param_types: PGType; end; TGTypeCValue = record case longint of 0 : (v_int: gint); 1 : (v_long: glong); 2 : (v_int64: gint64); 3 : (v_double: gdouble); 4 : (v_pointer: gpointer); end; TGTypeClassCacheFunc = function(cache_data: gpointer; g_class: PGTypeClass): gboolean; cdecl; PPGTypeDebugFlags = ^PGTypeDebugFlags; PGTypeDebugFlags = ^TGTypeDebugFlags; PPGTypeFlags = ^PGTypeFlags; PGTypeFlags = ^TGTypeFlags; PPGTypeFundamentalFlags = ^PGTypeFundamentalFlags; PGTypeFundamentalFlags = ^TGTypeFundamentalFlags; PPGTypeFundamentalInfo = ^PGTypeFundamentalInfo; PGTypeFundamentalInfo = ^TGTypeFundamentalInfo; TGTypeFundamentalInfo = record type_flags: TGTypeFundamentalFlags; end; PPGTypeValueTable = ^PGTypeValueTable; PGTypeValueTable = ^TGTypeValueTable; PPGTypeCValue = ^PGTypeCValue; PGTypeCValue = ^TGTypeCValue; TGTypeValueTable = object value_init: procedure(value: PGValue); cdecl; value_free: procedure(value: PGValue); cdecl; value_copy: procedure(src_value: PGValue; dest_value: PGValue); cdecl; value_peek_pointer: function(value: PGValue): gpointer; cdecl; collect_format: Pgchar; collect_value: function(value: PGValue; n_collect_values: guint; collect_values: PGTypeCValue; collect_flags: guint): Pgchar; cdecl; lcopy_format: Pgchar; lcopy_value: function(value: PGValue; n_collect_values: guint; collect_values: PGTypeCValue; collect_flags: guint): Pgchar; cdecl; end; PPGTypeInfo = ^PGTypeInfo; PGTypeInfo = ^TGTypeInfo; PPGBaseInitFunc = ^PGBaseInitFunc; PGBaseInitFunc = ^TGBaseInitFunc; PPGBaseFinalizeFunc = ^PGBaseFinalizeFunc; PGBaseFinalizeFunc = ^TGBaseFinalizeFunc; PPGClassInitFunc = ^PGClassInitFunc; PGClassInitFunc = ^TGClassInitFunc; PPGClassFinalizeFunc = ^PGClassFinalizeFunc; PGClassFinalizeFunc = ^TGClassFinalizeFunc; PPGInstanceInitFunc = ^PGInstanceInitFunc; PGInstanceInitFunc = ^TGInstanceInitFunc; TGTypeInfo = record class_size: guint16; base_init: TGBaseInitFunc; base_finalize: TGBaseFinalizeFunc; class_init: TGClassInitFunc; class_finalize: TGClassFinalizeFunc; class_data: Pgpointer; instance_size: guint16; n_preallocs: guint16; instance_init: TGInstanceInitFunc; value_table: PGTypeValueTable; end; PPGTypeInterface = ^PGTypeInterface; PGTypeInterface = ^TGTypeInterface; PPGTypePlugin = ^PGTypePlugin; PGTypePlugin = ^TGTypePlugin; TGTypeInterface = object g_type: TGType; g_instance_type: TGType; end; TGTypePlugin = object end; TGTypeInterfaceCheckFunc = procedure(check_data: gpointer; g_iface: gpointer); cdecl; PPGTypeModule = ^PGTypeModule; PGTypeModule = ^TGTypeModule; TGTypeModule = object(TGObject) use_count: guint; type_infos: PGSList; interface_infos: PGSList; name: Pgchar; end; PPGTypeModuleClass = ^PGTypeModuleClass; PGTypeModuleClass = ^TGTypeModuleClass; TGTypeModuleClass = object parent_class: TGObjectClass; load: function(module: PGTypeModule): gboolean; cdecl; unload: procedure(module: PGTypeModule); cdecl; reserved1: procedure; cdecl; reserved2: procedure; cdecl; reserved3: procedure; cdecl; reserved4: procedure; cdecl; end; TGTypePluginUse = procedure(plugin: PGTypePlugin); cdecl; TGTypePluginUnuse = procedure(plugin: PGTypePlugin); cdecl; TGTypePluginCompleteTypeInfo = procedure(plugin: PGTypePlugin; g_type: TGType; info: PGTypeInfo; value_table: PGTypeValueTable); cdecl; TGTypePluginCompleteInterfaceInfo = procedure(plugin: PGTypePlugin; instance_type: TGType; interface_type: TGType; info: PGInterfaceInfo); cdecl; PPGTypePluginClass = ^PGTypePluginClass; PGTypePluginClass = ^TGTypePluginClass; PPGTypePluginUse = ^PGTypePluginUse; PGTypePluginUse = ^TGTypePluginUse; PPGTypePluginUnuse = ^PGTypePluginUnuse; PGTypePluginUnuse = ^TGTypePluginUnuse; PPGTypePluginCompleteTypeInfo = ^PGTypePluginCompleteTypeInfo; PGTypePluginCompleteTypeInfo = ^TGTypePluginCompleteTypeInfo; PPGTypePluginCompleteInterfaceInfo = ^PGTypePluginCompleteInterfaceInfo; PGTypePluginCompleteInterfaceInfo = ^TGTypePluginCompleteInterfaceInfo; TGTypePluginClass = record base_iface: TGTypeInterface; use_plugin: TGTypePluginUse; unuse_plugin: TGTypePluginUnuse; complete_type_info: TGTypePluginCompleteTypeInfo; complete_interface_info: TGTypePluginCompleteInterfaceInfo; end; PPGTypeQuery = ^PGTypeQuery; PGTypeQuery = ^TGTypeQuery; TGTypeQuery = record type_: TGType; type_name: Pgchar; class_size: guint; instance_size: guint; end; PPGValueArray = ^PGValueArray; PGValueArray = ^TGValueArray; TGValueArray = object n_values: guint; values: PGValue; n_prealloced: guint; end; PPGWeakRef = ^PGWeakRef; PGWeakRef = ^TGWeakRef; TGWeakRef_union_priv = record case longint of 0 : (p: gpointer); end; TGWeakRef = object priv: TGWeakRef_union_priv; //union extracted from object and named 'TGWeakRef_union_priv' end; function g_binding_get_flags(binding: PGBinding): TGBindingFlags; cdecl; external; function g_binding_get_source(binding: PGBinding): PGObject; cdecl; external; function g_binding_get_source_property(binding: PGBinding): Pgchar; cdecl; external; function g_binding_get_target(binding: PGBinding): PGObject; cdecl; external; function g_binding_get_target_property(binding: PGBinding): Pgchar; cdecl; external; function g_binding_get_type: TGType; cdecl; external; function g_boxed_copy(boxed_type: TGType; src_boxed: Pgpointer): gpointer; cdecl; external; function g_boxed_type_register_static(name: Pgchar; boxed_copy: TGBoxedCopyFunc; boxed_free: TGBoxedFreeFunc): TGType; cdecl; external; function g_cclosure_new(callback_func: TGCallback; user_data: gpointer; destroy_data: TGClosureNotify): PGClosure; cdecl; external; function g_cclosure_new_object(callback_func: TGCallback; object_: PGObject): PGClosure; cdecl; external; function g_cclosure_new_object_swap(callback_func: TGCallback; object_: PGObject): PGClosure; cdecl; external; function g_cclosure_new_swap(callback_func: TGCallback; user_data: gpointer; destroy_data: TGClosureNotify): PGClosure; cdecl; external; function g_closure_get_type: TGType; cdecl; external; function g_closure_new_object(sizeof_closure: guint; object_: PGObject): PGClosure; cdecl; external; function g_closure_new_simple(sizeof_closure: guint; data: gpointer): PGClosure; cdecl; external; function g_closure_ref(closure: PGClosure): PGClosure; cdecl; external; function g_enum_get_value(enum_class: PGEnumClass; value: gint): PGEnumValue; cdecl; external; function g_enum_get_value_by_name(enum_class: PGEnumClass; name: Pgchar): PGEnumValue; cdecl; external; function g_enum_get_value_by_nick(enum_class: PGEnumClass; nick: Pgchar): PGEnumValue; cdecl; external; function g_enum_register_static(name: Pgchar; const_static_values: PGEnumValue): TGType; cdecl; external; function g_flags_get_first_value(flags_class: PGFlagsClass; value: guint): PGFlagsValue; cdecl; external; function g_flags_get_value_by_name(flags_class: PGFlagsClass; name: Pgchar): PGFlagsValue; cdecl; external; function g_flags_get_value_by_nick(flags_class: PGFlagsClass; nick: Pgchar): PGFlagsValue; cdecl; external; function g_flags_register_static(name: Pgchar; const_static_values: PGFlagsValue): TGType; cdecl; external; function g_gtype_get_type: TGType; cdecl; external; function g_initially_unowned_get_type: TGType; cdecl; external; function g_object_bind_property(source: PGObject; source_property: Pgchar; target: PGObject; target_property: Pgchar; flags: TGBindingFlags): PGBinding; cdecl; external; function g_object_bind_property_full(source: PGObject; source_property: Pgchar; target: PGObject; target_property: Pgchar; flags: TGBindingFlags; transform_to: TGBindingTransformFunc; transform_from: TGBindingTransformFunc; user_data: gpointer; notify: TGDestroyNotify): PGBinding; cdecl; external; function g_object_bind_property_with_closures(source: PGObject; source_property: Pgchar; target: PGObject; target_property: Pgchar; flags: TGBindingFlags; transform_to: PGClosure; transform_from: PGClosure): PGBinding; cdecl; external; function g_object_class_find_property(oclass: PGObjectClass; property_name: Pgchar): PGParamSpec; cdecl; external; function g_object_class_list_properties(oclass: PGObjectClass; n_properties: Pguint): PPGParamSpec; cdecl; external; function g_object_compat_control(what: gsize; data: gpointer): gsize; cdecl; external; function g_object_connect(object_: gpointer; signal_spec: Pgchar; args: array of const): gpointer; cdecl; external; function g_object_dup_data(object_: PGObject; key: Pgchar; dup_func: TGDuplicateFunc; user_data: gpointer): gpointer; cdecl; external; function g_object_dup_qdata(object_: PGObject; quark: TGQuark; dup_func: TGDuplicateFunc; user_data: gpointer): gpointer; cdecl; external; function g_object_get_data(object_: PGObject; key: Pgchar): gpointer; cdecl; external; function g_object_get_qdata(object_: PGObject; quark: TGQuark): gpointer; cdecl; external; function g_object_get_type: TGType; cdecl; external; function g_object_interface_find_property(g_iface: gpointer; property_name: Pgchar): PGParamSpec; cdecl; external; function g_object_interface_list_properties(g_iface: gpointer; n_properties_p: Pguint): PPGParamSpec; cdecl; external; function g_object_is_floating(object_: PGObject): gboolean; cdecl; external; function g_object_new(object_type: TGType; first_property_name: Pgchar; args: array of const): gpointer; cdecl; external; function g_object_new_valist(object_type: TGType; first_property_name: Pgchar; var_args: Tva_list): PGObject; cdecl; external; function g_object_newv(object_type: TGType; n_parameters: guint; parameters: PGParameter): PGObject; cdecl; external; function g_object_ref(object_: PGObject): PGObject; cdecl; external; function g_object_ref_sink(object_: PGObject): PGObject; cdecl; external; function g_object_replace_data(object_: PGObject; key: Pgchar; oldval: gpointer; newval: gpointer; destroy_: TGDestroyNotify; old_destroy: PGDestroyNotify): gboolean; cdecl; external; function g_object_replace_qdata(object_: PGObject; quark: TGQuark; oldval: gpointer; newval: gpointer; destroy_: TGDestroyNotify; old_destroy: PGDestroyNotify): gboolean; cdecl; external; function g_object_steal_data(object_: PGObject; key: Pgchar): gpointer; cdecl; external; function g_object_steal_qdata(object_: PGObject; quark: TGQuark): gpointer; cdecl; external; function g_param_spec_boolean(name: Pgchar; nick: Pgchar; blurb: Pgchar; default_value: gboolean; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_boxed(name: Pgchar; nick: Pgchar; blurb: Pgchar; boxed_type: TGType; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_char(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: gint8; maximum: gint8; default_value: gint8; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_double(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: gdouble; maximum: gdouble; default_value: gdouble; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_enum(name: Pgchar; nick: Pgchar; blurb: Pgchar; enum_type: TGType; default_value: gint; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_flags(name: Pgchar; nick: Pgchar; blurb: Pgchar; flags_type: TGType; default_value: guint; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_float(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: gfloat; maximum: gfloat; default_value: gfloat; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_get_blurb(pspec: PGParamSpec): Pgchar; cdecl; external; function g_param_spec_get_name(pspec: PGParamSpec): Pgchar; cdecl; external; function g_param_spec_get_nick(pspec: PGParamSpec): Pgchar; cdecl; external; function g_param_spec_get_qdata(pspec: PGParamSpec; quark: TGQuark): gpointer; cdecl; external; function g_param_spec_get_redirect_target(pspec: PGParamSpec): PGParamSpec; cdecl; external; function g_param_spec_gtype(name: Pgchar; nick: Pgchar; blurb: Pgchar; is_a_type: TGType; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_int(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: gint; maximum: gint; default_value: gint; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_int64(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: gint64; maximum: gint64; default_value: gint64; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_internal(param_type: TGType; name: Pgchar; nick: Pgchar; blurb: Pgchar; flags: TGParamFlags): gpointer; cdecl; external; function g_param_spec_long(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: glong; maximum: glong; default_value: glong; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_object(name: Pgchar; nick: Pgchar; blurb: Pgchar; object_type: TGType; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_override(name: Pgchar; overridden: PGParamSpec): PGParamSpec; cdecl; external; function g_param_spec_param(name: Pgchar; nick: Pgchar; blurb: Pgchar; param_type: TGType; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_pointer(name: Pgchar; nick: Pgchar; blurb: Pgchar; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_pool_list(pool: PGParamSpecPool; owner_type: TGType; n_pspecs_p: Pguint): PPGParamSpec; cdecl; external; function g_param_spec_pool_list_owned(pool: PGParamSpecPool; owner_type: TGType): PGList; cdecl; external; function g_param_spec_pool_lookup(pool: PGParamSpecPool; param_name: Pgchar; owner_type: TGType; walk_ancestors: gboolean): PGParamSpec; cdecl; external; function g_param_spec_pool_new(type_prefixing: gboolean): PGParamSpecPool; cdecl; external; function g_param_spec_ref(pspec: PGParamSpec): PGParamSpec; cdecl; external; function g_param_spec_ref_sink(pspec: PGParamSpec): PGParamSpec; cdecl; external; function g_param_spec_steal_qdata(pspec: PGParamSpec; quark: TGQuark): gpointer; cdecl; external; function g_param_spec_string(name: Pgchar; nick: Pgchar; blurb: Pgchar; default_value: Pgchar; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_uchar(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: guint8; maximum: guint8; default_value: guint8; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_uint(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: guint; maximum: guint; default_value: guint; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_uint64(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: guint64; maximum: guint64; default_value: guint64; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_ulong(name: Pgchar; nick: Pgchar; blurb: Pgchar; minimum: gulong; maximum: gulong; default_value: gulong; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_unichar(name: Pgchar; nick: Pgchar; blurb: Pgchar; default_value: gunichar; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_value_array(name: Pgchar; nick: Pgchar; blurb: Pgchar; element_spec: PGParamSpec; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_spec_variant(name: Pgchar; nick: Pgchar; blurb: Pgchar; type_: PGVariantType; default_value: PGVariant; flags: TGParamFlags): PGParamSpec; cdecl; external; function g_param_type_register_static(name: Pgchar; pspec_info: PGParamSpecTypeInfo): TGType; cdecl; external; function g_param_value_convert(pspec: PGParamSpec; src_value: PGValue; dest_value: PGValue; strict_validation: gboolean): gboolean; cdecl; external; function g_param_value_defaults(pspec: PGParamSpec; value: PGValue): gboolean; cdecl; external; function g_param_value_validate(pspec: PGParamSpec; value: PGValue): gboolean; cdecl; external; function g_param_values_cmp(pspec: PGParamSpec; value1: PGValue; value2: PGValue): gint; cdecl; external; function g_pointer_type_register_static(name: Pgchar): TGType; cdecl; external; function g_signal_accumulator_first_wins(ihint: PGSignalInvocationHint; return_accu: PGValue; handler_return: PGValue; dummy: gpointer): gboolean; cdecl; external; function g_signal_accumulator_true_handled(ihint: PGSignalInvocationHint; return_accu: PGValue; handler_return: PGValue; dummy: gpointer): gboolean; cdecl; external; function g_signal_add_emission_hook(signal_id: guint; detail: TGQuark; hook_func: TGSignalEmissionHook; hook_data: gpointer; data_destroy: TGDestroyNotify): gulong; cdecl; external; function g_signal_connect_closure(instance: gpointer; detailed_signal: Pgchar; closure: PGClosure; after: gboolean): gulong; cdecl; external; function g_signal_connect_closure_by_id(instance: gpointer; signal_id: guint; detail: TGQuark; closure: PGClosure; after: gboolean): gulong; cdecl; external; function g_signal_connect_data(instance: gpointer; detailed_signal: Pgchar; c_handler: TGCallback; data: gpointer; destroy_data: TGClosureNotify; connect_flags: TGConnectFlags): gulong; cdecl; external; function g_signal_connect_object(instance: gpointer; detailed_signal: Pgchar; c_handler: TGCallback; gobject: gpointer; connect_flags: TGConnectFlags): gulong; cdecl; external; function g_signal_get_invocation_hint(instance: gpointer): PGSignalInvocationHint; cdecl; external; function g_signal_handler_find(instance: gpointer; mask: TGSignalMatchType; signal_id: guint; detail: TGQuark; closure: PGClosure; func: gpointer; data: gpointer): gulong; cdecl; external; function g_signal_handler_is_connected(instance: gpointer; handler_id: gulong): gboolean; cdecl; external; function g_signal_handlers_block_matched(instance: gpointer; mask: TGSignalMatchType; signal_id: guint; detail: TGQuark; closure: PGClosure; func: gpointer; data: gpointer): guint; cdecl; external; function g_signal_handlers_disconnect_matched(instance: gpointer; mask: TGSignalMatchType; signal_id: guint; detail: TGQuark; closure: PGClosure; func: gpointer; data: gpointer): guint; cdecl; external; function g_signal_handlers_unblock_matched(instance: gpointer; mask: TGSignalMatchType; signal_id: guint; detail: TGQuark; closure: PGClosure; func: gpointer; data: gpointer): guint; cdecl; external; function g_signal_has_handler_pending(instance: gpointer; signal_id: guint; detail: TGQuark; may_be_blocked: gboolean): gboolean; cdecl; external; function g_signal_list_ids(itype: TGType; n_ids: Pguint): Pguint; cdecl; external; function g_signal_lookup(name: Pgchar; itype: TGType): guint; cdecl; external; function g_signal_name(signal_id: guint): Pgchar; cdecl; external; function g_signal_new(signal_name: Pgchar; itype: TGType; signal_flags: TGSignalFlags; class_offset: guint; accumulator: TGSignalAccumulator; accu_data: gpointer; c_marshaller: TGSignalCMarshaller; return_type: TGType; n_params: guint; args: array of const): guint; cdecl; external; function g_signal_new_class_handler(signal_name: Pgchar; itype: TGType; signal_flags: TGSignalFlags; class_handler: TGCallback; accumulator: TGSignalAccumulator; accu_data: gpointer; c_marshaller: TGSignalCMarshaller; return_type: TGType; n_params: guint; args: array of const): guint; cdecl; external; function g_signal_new_valist(signal_name: Pgchar; itype: TGType; signal_flags: TGSignalFlags; class_closure: PGClosure; accumulator: TGSignalAccumulator; accu_data: gpointer; c_marshaller: TGSignalCMarshaller; return_type: TGType; n_params: guint; args: Tva_list): guint; cdecl; external; function g_signal_newv(signal_name: Pgchar; itype: TGType; signal_flags: TGSignalFlags; class_closure: PGClosure; accumulator: TGSignalAccumulator; accu_data: gpointer; c_marshaller: TGSignalCMarshaller; return_type: TGType; n_params: guint; param_types: PGType): guint; cdecl; external; function g_signal_parse_name(detailed_signal: Pgchar; itype: TGType; signal_id_p: Pguint; detail_p: PGQuark; force_detail_quark: gboolean): gboolean; cdecl; external; function g_signal_type_cclosure_new(itype: TGType; struct_offset: guint): PGClosure; cdecl; external; function g_strdup_value_contents(value: PGValue): Pgchar; cdecl; external; function g_type_check_class_cast(g_class: PGTypeClass; is_a_type: TGType): PGTypeClass; cdecl; external; function g_type_check_class_is_a(g_class: PGTypeClass; is_a_type: TGType): gboolean; cdecl; external; function g_type_check_instance(instance: PGTypeInstance): gboolean; cdecl; external; function g_type_check_instance_cast(instance: PGTypeInstance; iface_type: TGType): PGTypeInstance; cdecl; external; function g_type_check_instance_is_a(instance: PGTypeInstance; iface_type: TGType): gboolean; cdecl; external; function g_type_check_is_value_type(type_: TGType): gboolean; cdecl; external; function g_type_check_value(value: PGValue): gboolean; cdecl; external; function g_type_check_value_holds(value: PGValue; type_: TGType): gboolean; cdecl; external; function g_type_children(type_: TGType; n_children: Pguint): PGType; cdecl; external; function g_type_class_get_private(klass: PGTypeClass; private_type: TGType): gpointer; cdecl; external; function g_type_class_peek(type_: TGType): PGTypeClass; cdecl; external; function g_type_class_peek_parent(g_class: PGTypeClass): PGTypeClass; cdecl; external; function g_type_class_peek_static(type_: TGType): PGTypeClass; cdecl; external; function g_type_class_ref(type_: TGType): PGTypeClass; cdecl; external; function g_type_create_instance(type_: TGType): PGTypeInstance; cdecl; external; function g_type_default_interface_peek(g_type: TGType): PGTypeInterface; cdecl; external; function g_type_default_interface_ref(g_type: TGType): PGTypeInterface; cdecl; external; function g_type_depth(type_: TGType): guint; cdecl; external; function g_type_from_name(name: Pgchar): TGType; cdecl; external; function g_type_fundamental(type_id: TGType): TGType; cdecl; external; function g_type_fundamental_next: TGType; cdecl; external; function g_type_get_plugin(type_: TGType): PGTypePlugin; cdecl; external; function g_type_get_qdata(type_: TGType; quark: TGQuark): gpointer; cdecl; external; function g_type_get_type_registration_serial: guint; cdecl; external; function g_type_instance_get_private(instance: PGTypeInstance; private_type: TGType): gpointer; cdecl; external; function g_type_interface_get_plugin(instance_type: TGType; interface_type: TGType): PGTypePlugin; cdecl; external; function g_type_interface_peek(instance_class: PGTypeClass; iface_type: TGType): PGTypeInterface; cdecl; external; function g_type_interface_peek_parent(g_iface: PGTypeInterface): PGTypeInterface; cdecl; external; function g_type_interface_prerequisites(interface_type: TGType; n_prerequisites: Pguint): PGType; cdecl; external; function g_type_interfaces(type_: TGType; n_interfaces: Pguint): PGType; cdecl; external; function g_type_is_a(type_: TGType; is_a_type: TGType): gboolean; cdecl; external; function g_type_module_get_type: TGType; cdecl; external; function g_type_module_register_enum(module: PGTypeModule; name: Pgchar; const_static_values: PGEnumValue): TGType; cdecl; external; function g_type_module_register_flags(module: PGTypeModule; name: Pgchar; const_static_values: PGFlagsValue): TGType; cdecl; external; function g_type_module_register_type(module: PGTypeModule; parent_type: TGType; type_name: Pgchar; type_info: PGTypeInfo; flags: TGTypeFlags): TGType; cdecl; external; function g_type_module_use(module: PGTypeModule): gboolean; cdecl; external; function g_type_name(type_: TGType): Pgchar; cdecl; external; function g_type_name_from_class(g_class: PGTypeClass): Pgchar; cdecl; external; function g_type_name_from_instance(instance: PGTypeInstance): Pgchar; cdecl; external; function g_type_next_base(leaf_type: TGType; root_type: TGType): TGType; cdecl; external; function g_type_parent(type_: TGType): TGType; cdecl; external; function g_type_plugin_get_type: TGType; cdecl; external; function g_type_qname(type_: TGType): TGQuark; cdecl; external; function g_type_register_dynamic(parent_type: TGType; type_name: Pgchar; plugin: PGTypePlugin; flags: TGTypeFlags): TGType; cdecl; external; function g_type_register_fundamental(type_id: TGType; type_name: Pgchar; info: PGTypeInfo; finfo: PGTypeFundamentalInfo; flags: TGTypeFlags): TGType; cdecl; external; function g_type_register_static(parent_type: TGType; type_name: Pgchar; info: PGTypeInfo; flags: TGTypeFlags): TGType; cdecl; external; function g_type_register_static_simple(parent_type: TGType; type_name: Pgchar; class_size: guint; class_init: TGClassInitFunc; instance_size: guint; instance_init: TGInstanceInitFunc; flags: TGTypeFlags): TGType; cdecl; external; function g_type_test_flags(type_: TGType; flags: guint): gboolean; cdecl; external; function g_type_value_table_peek(type_: TGType): PGTypeValueTable; cdecl; external; function g_value_array_get_type: TGType; cdecl; external; function g_value_dup_boxed(value: PGValue): gpointer; cdecl; external; function g_value_dup_object(value: PGValue): PGObject; cdecl; external; function g_value_dup_param(value: PGValue): PGParamSpec; cdecl; external; function g_value_dup_string(value: PGValue): Pgchar; cdecl; external; function g_value_dup_variant(value: PGValue): PGVariant; cdecl; external; function g_value_fits_pointer(value: PGValue): gboolean; cdecl; external; function g_value_get_boolean(value: PGValue): gboolean; cdecl; external; function g_value_get_boxed(value: PGValue): gpointer; cdecl; external; function g_value_get_double(value: PGValue): gdouble; cdecl; external; function g_value_get_enum(value: PGValue): gint; cdecl; external; function g_value_get_flags(value: PGValue): guint; cdecl; external; function g_value_get_float(value: PGValue): gfloat; cdecl; external; function g_value_get_gtype(value: PGValue): TGType; cdecl; external; function g_value_get_int(value: PGValue): gint; cdecl; external; function g_value_get_int64(value: PGValue): gint64; cdecl; external; function g_value_get_long(value: PGValue): glong; cdecl; external; function g_value_get_object(value: PGValue): PGObject; cdecl; external; function g_value_get_param(value: PGValue): PGParamSpec; cdecl; external; function g_value_get_pointer(value: PGValue): gpointer; cdecl; external; function g_value_get_schar(value: PGValue): gint8; cdecl; external; function g_value_get_string(value: PGValue): Pgchar; cdecl; external; function g_value_get_type: TGType; cdecl; external; function g_value_get_uchar(value: PGValue): guint8; cdecl; external; function g_value_get_uint(value: PGValue): guint; cdecl; external; function g_value_get_uint64(value: PGValue): guint64; cdecl; external; function g_value_get_ulong(value: PGValue): gulong; cdecl; external; function g_value_get_variant(value: PGValue): PGVariant; cdecl; external; function g_value_init(value: PGValue; g_type: TGType): PGValue; cdecl; external; function g_value_peek_pointer(value: PGValue): gpointer; cdecl; external; function g_value_reset(value: PGValue): PGValue; cdecl; external; function g_value_transform(src_value: PGValue; dest_value: PGValue): gboolean; cdecl; external; function g_value_type_compatible(src_type: TGType; dest_type: TGType): gboolean; cdecl; external; function g_value_type_transformable(src_type: TGType; dest_type: TGType): gboolean; cdecl; external; function g_weak_ref_get(weak_ref: PGWeakRef): PGObject; cdecl; external; procedure g_boxed_free(boxed_type: TGType; boxed: gpointer); cdecl; external; procedure g_cclosure_marshal_BOOLEAN__BOXED_BOXED(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_BOOLEAN__BOXED_BOXEDv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_BOOLEAN__FLAGS(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_BOOLEAN__FLAGSv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_generic(closure: PGClosure; return_gvalue: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_generic_va(closure: PGClosure; return_value: PGValue; instance: gpointer; args_list: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_STRING__OBJECT_POINTER(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_STRING__OBJECT_POINTERv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__BOOLEAN(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__BOOLEANv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__BOXED(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__BOXEDv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__CHAR(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__CHARv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__DOUBLE(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__DOUBLEv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__ENUM(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__ENUMv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__FLAGS(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__FLAGSv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__FLOAT(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__FLOATv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__INT(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__INTv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__LONG(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__LONGv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__OBJECT(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__OBJECTv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__PARAM(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__PARAMv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__POINTER(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__POINTERv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__STRING(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__STRINGv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__UCHAR(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__UCHARv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__UINT(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__UINT_POINTER(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__UINT_POINTERv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__UINTv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__ULONG(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__ULONGv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__VARIANT(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__VARIANTv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_cclosure_marshal_VOID__VOID(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer; marshal_data: gpointer); cdecl; external; procedure g_cclosure_marshal_VOID__VOIDv(closure: PGClosure; return_value: PGValue; instance: gpointer; args: Tva_list; marshal_data: gpointer; n_params: gint; param_types: PGType); cdecl; external; procedure g_clear_object(object_ptr: PPGObject); cdecl; external; procedure g_closure_add_finalize_notifier(closure: PGClosure; notify_data: gpointer; notify_func: TGClosureNotify); cdecl; external; procedure g_closure_add_invalidate_notifier(closure: PGClosure; notify_data: gpointer; notify_func: TGClosureNotify); cdecl; external; procedure g_closure_add_marshal_guards(closure: PGClosure; pre_marshal_data: gpointer; pre_marshal_notify: TGClosureNotify; post_marshal_data: gpointer; post_marshal_notify: TGClosureNotify); cdecl; external; procedure g_closure_invalidate(closure: PGClosure); cdecl; external; procedure g_closure_invoke(closure: PGClosure; return_value: PGValue; n_param_values: guint; param_values: PGValue; invocation_hint: gpointer); cdecl; external; procedure g_closure_remove_finalize_notifier(closure: PGClosure; notify_data: gpointer; notify_func: TGClosureNotify); cdecl; external; procedure g_closure_remove_invalidate_notifier(closure: PGClosure; notify_data: gpointer; notify_func: TGClosureNotify); cdecl; external; procedure g_closure_set_marshal(closure: PGClosure; marshal: TGClosureMarshal); cdecl; external; procedure g_closure_set_meta_marshal(closure: PGClosure; marshal_data: gpointer; meta_marshal: TGClosureMarshal); cdecl; external; procedure g_closure_sink(closure: PGClosure); cdecl; external; procedure g_closure_unref(closure: PGClosure); cdecl; external; procedure g_enum_complete_type_info(g_enum_type: TGType; info: PGTypeInfo; const_values: PGEnumValue); cdecl; external; procedure g_flags_complete_type_info(g_flags_type: TGType; info: PGTypeInfo; const_values: PGFlagsValue); cdecl; external; procedure g_object_add_toggle_ref(object_: PGObject; notify: TGToggleNotify; data: gpointer); cdecl; external; procedure g_object_add_weak_pointer(object_: PGObject; weak_pointer_location: Pgpointer); cdecl; external; procedure g_object_class_install_properties(oclass: PGObjectClass; n_pspecs: guint; pspecs: PPGParamSpec); cdecl; external; procedure g_object_class_install_property(oclass: PGObjectClass; property_id: guint; pspec: PGParamSpec); cdecl; external; procedure g_object_class_override_property(oclass: PGObjectClass; property_id: guint; name: Pgchar); cdecl; external; procedure g_object_disconnect(object_: gpointer; signal_spec: Pgchar; args: array of const); cdecl; external; procedure g_object_force_floating(object_: PGObject); cdecl; external; procedure g_object_freeze_notify(object_: PGObject); cdecl; external; procedure g_object_get(object_: gpointer; first_property_name: Pgchar; args: array of const); cdecl; external; procedure g_object_get_property(object_: PGObject; property_name: Pgchar; value: PGValue); cdecl; external; procedure g_object_get_valist(object_: PGObject; first_property_name: Pgchar; var_args: Tva_list); cdecl; external; procedure g_object_interface_install_property(g_iface: gpointer; pspec: PGParamSpec); cdecl; external; procedure g_object_notify(object_: PGObject; property_name: Pgchar); cdecl; external; procedure g_object_notify_by_pspec(object_: PGObject; pspec: PGParamSpec); cdecl; external; procedure g_object_remove_toggle_ref(object_: PGObject; notify: TGToggleNotify; data: gpointer); cdecl; external; procedure g_object_remove_weak_pointer(object_: PGObject; weak_pointer_location: Pgpointer); cdecl; external; procedure g_object_run_dispose(object_: PGObject); cdecl; external; procedure g_object_set(object_: gpointer; first_property_name: Pgchar; args: array of const); cdecl; external; procedure g_object_set_data(object_: PGObject; key: Pgchar; data: gpointer); cdecl; external; procedure g_object_set_data_full(object_: PGObject; key: Pgchar; data: gpointer; destroy_: TGDestroyNotify); cdecl; external; procedure g_object_set_property(object_: PGObject; property_name: Pgchar; value: PGValue); cdecl; external; procedure g_object_set_qdata(object_: PGObject; quark: TGQuark; data: gpointer); cdecl; external; procedure g_object_set_qdata_full(object_: PGObject; quark: TGQuark; data: gpointer; destroy_: TGDestroyNotify); cdecl; external; procedure g_object_set_valist(object_: PGObject; first_property_name: Pgchar; var_args: Tva_list); cdecl; external; procedure g_object_thaw_notify(object_: PGObject); cdecl; external; procedure g_object_unref(object_: PGObject); cdecl; external; procedure g_object_watch_closure(object_: PGObject; closure: PGClosure); cdecl; external; procedure g_object_weak_ref(object_: PGObject; notify: TGWeakNotify; data: gpointer); cdecl; external; procedure g_object_weak_unref(object_: PGObject; notify: TGWeakNotify; data: gpointer); cdecl; external; procedure g_param_spec_pool_insert(pool: PGParamSpecPool; pspec: PGParamSpec; owner_type: TGType); cdecl; external; procedure g_param_spec_pool_remove(pool: PGParamSpecPool; pspec: PGParamSpec); cdecl; external; procedure g_param_spec_set_qdata(pspec: PGParamSpec; quark: TGQuark; data: gpointer); cdecl; external; procedure g_param_spec_set_qdata_full(pspec: PGParamSpec; quark: TGQuark; data: gpointer; destroy_: TGDestroyNotify); cdecl; external; procedure g_param_spec_sink(pspec: PGParamSpec); cdecl; external; procedure g_param_spec_unref(pspec: PGParamSpec); cdecl; external; procedure g_param_value_set_default(pspec: PGParamSpec; value: PGValue); cdecl; external; procedure g_signal_chain_from_overridden(instance_and_params: PGValue; return_value: PGValue); cdecl; external; procedure g_signal_chain_from_overridden_handler(instance: gpointer; args: array of const); cdecl; external; procedure g_signal_emit(instance: gpointer; signal_id: guint; detail: TGQuark; args: array of const); cdecl; external; procedure g_signal_emit_by_name(instance: gpointer; detailed_signal: Pgchar; args: array of const); cdecl; external; procedure g_signal_emit_valist(instance: gpointer; signal_id: guint; detail: TGQuark; var_args: Tva_list); cdecl; external; procedure g_signal_emitv(instance_and_params: PGValue; signal_id: guint; detail: TGQuark; return_value: PGValue); cdecl; external; procedure g_signal_handler_block(instance: gpointer; handler_id: gulong); cdecl; external; procedure g_signal_handler_disconnect(instance: gpointer; handler_id: gulong); cdecl; external; procedure g_signal_handler_unblock(instance: gpointer; handler_id: gulong); cdecl; external; procedure g_signal_handlers_destroy(instance: gpointer); cdecl; external; procedure g_signal_override_class_closure(signal_id: guint; instance_type: TGType; class_closure: PGClosure); cdecl; external; procedure g_signal_override_class_handler(signal_name: Pgchar; instance_type: TGType; class_handler: TGCallback); cdecl; external; procedure g_signal_query(signal_id: guint; query: PGSignalQuery); cdecl; external; procedure g_signal_remove_emission_hook(signal_id: guint; hook_id: gulong); cdecl; external; procedure g_signal_set_va_marshaller(signal_id: guint; instance_type: TGType; va_marshaller: TGSignalCVaMarshaller); cdecl; external; procedure g_signal_stop_emission(instance: gpointer; signal_id: guint; detail: TGQuark); cdecl; external; procedure g_signal_stop_emission_by_name(instance: gpointer; detailed_signal: Pgchar); cdecl; external; procedure g_source_set_closure(source: PGSource; closure: PGClosure); cdecl; external; procedure g_source_set_dummy_callback(source: PGSource); cdecl; external; procedure g_type_add_class_cache_func(cache_data: gpointer; cache_func: TGTypeClassCacheFunc); cdecl; external; procedure g_type_add_class_private(class_type: TGType; private_size: gsize); cdecl; external; procedure g_type_add_interface_check(check_data: gpointer; check_func: TGTypeInterfaceCheckFunc); cdecl; external; procedure g_type_add_interface_dynamic(instance_type: TGType; interface_type: TGType; plugin: PGTypePlugin); cdecl; external; procedure g_type_add_interface_static(instance_type: TGType; interface_type: TGType; info: PGInterfaceInfo); cdecl; external; procedure g_type_class_add_private(g_class: gpointer; private_size: gsize); cdecl; external; procedure g_type_class_unref(g_class: PGTypeClass); cdecl; external; procedure g_type_class_unref_uncached(g_class: PGTypeClass); cdecl; external; procedure g_type_default_interface_unref(g_iface: PGTypeInterface); cdecl; external; procedure g_type_ensure(type_: TGType); cdecl; external; procedure g_type_free_instance(instance: PGTypeInstance); cdecl; external; procedure g_type_init; cdecl; external; procedure g_type_init_with_debug_flags(debug_flags: TGTypeDebugFlags); cdecl; external; procedure g_type_interface_add_prerequisite(interface_type: TGType; prerequisite_type: TGType); cdecl; external; procedure g_type_module_add_interface(module: PGTypeModule; instance_type: TGType; interface_type: TGType; interface_info: PGInterfaceInfo); cdecl; external; procedure g_type_module_set_name(module: PGTypeModule; name: Pgchar); cdecl; external; procedure g_type_module_unuse(module: PGTypeModule); cdecl; external; procedure g_type_plugin_complete_interface_info(plugin: PGTypePlugin; instance_type: TGType; interface_type: TGType; info: PGInterfaceInfo); cdecl; external; procedure g_type_plugin_complete_type_info(plugin: PGTypePlugin; g_type: TGType; info: PGTypeInfo; value_table: PGTypeValueTable); cdecl; external; procedure g_type_plugin_unuse(plugin: PGTypePlugin); cdecl; external; procedure g_type_plugin_use(plugin: PGTypePlugin); cdecl; external; procedure g_type_query(type_: TGType; query: PGTypeQuery); cdecl; external; procedure g_type_remove_class_cache_func(cache_data: gpointer; cache_func: TGTypeClassCacheFunc); cdecl; external; procedure g_type_remove_interface_check(check_data: gpointer; check_func: TGTypeInterfaceCheckFunc); cdecl; external; procedure g_type_set_qdata(type_: TGType; quark: TGQuark; data: gpointer); cdecl; external; procedure g_value_copy(src_value: PGValue; dest_value: PGValue); cdecl; external; procedure g_value_register_transform_func(src_type: TGType; dest_type: TGType; transform_func: TGValueTransform); cdecl; external; procedure g_value_set_boolean(value: PGValue; v_boolean: gboolean); cdecl; external; procedure g_value_set_boxed(value: PGValue; v_boxed: Pgpointer); cdecl; external; procedure g_value_set_double(value: PGValue; v_double: gdouble); cdecl; external; procedure g_value_set_enum(value: PGValue; v_enum: gint); cdecl; external; procedure g_value_set_flags(value: PGValue; v_flags: guint); cdecl; external; procedure g_value_set_float(value: PGValue; v_float: gfloat); cdecl; external; procedure g_value_set_gtype(value: PGValue; v_gtype: TGType); cdecl; external; procedure g_value_set_instance(value: PGValue; instance: gpointer); cdecl; external; procedure g_value_set_int(value: PGValue; v_int: gint); cdecl; external; procedure g_value_set_int64(value: PGValue; v_int64: gint64); cdecl; external; procedure g_value_set_long(value: PGValue; v_long: glong); cdecl; external; procedure g_value_set_object(value: PGValue; v_object: PGObject); cdecl; external; procedure g_value_set_param(value: PGValue; param: PGParamSpec); cdecl; external; procedure g_value_set_pointer(value: PGValue; v_pointer: gpointer); cdecl; external; procedure g_value_set_schar(value: PGValue; v_char: gint8); cdecl; external; procedure g_value_set_static_boxed(value: PGValue; v_boxed: Pgpointer); cdecl; external; procedure g_value_set_static_string(value: PGValue; v_string: Pgchar); cdecl; external; procedure g_value_set_string(value: PGValue; v_string: Pgchar); cdecl; external; procedure g_value_set_uchar(value: PGValue; v_uchar: guint8); cdecl; external; procedure g_value_set_uint(value: PGValue; v_uint: guint); cdecl; external; procedure g_value_set_uint64(value: PGValue; v_uint64: guint64); cdecl; external; procedure g_value_set_ulong(value: PGValue; v_ulong: gulong); cdecl; external; procedure g_value_set_variant(value: PGValue; variant: PGVariant); cdecl; external; procedure g_value_take_boxed(value: PGValue; v_boxed: Pgpointer); cdecl; external; procedure g_value_take_object(value: PGValue; v_object: gpointer); cdecl; external; procedure g_value_take_param(value: PGValue; param: PGParamSpec); cdecl; external; procedure g_value_take_string(value: PGValue; v_string: Pgchar); cdecl; external; procedure g_value_take_variant(value: PGValue; variant: PGVariant); cdecl; external; procedure g_value_unset(value: PGValue); cdecl; external; procedure g_weak_ref_clear(weak_ref: PGWeakRef); cdecl; external; procedure g_weak_ref_init(weak_ref: PGWeakRef; object_: gpointer); cdecl; external; procedure g_weak_ref_set(weak_ref: PGWeakRef; object_: gpointer); cdecl; external; implementation end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/gst.pas����������������������������������������������������������0000644�0001750�0000144�00000007100�14743153644�017504� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit gst; {$mode delphi} {$packenum 4} interface uses SysUtils, CTypes, uGlib2; const GST_CLOCK_TIME_NONE = UInt64(-1); const GST_MESSAGE_EOS = (1 << 0); GST_MESSAGE_ERROR = (1 << 1); type GstState = ( GST_STATE_VOID_PENDING = 0, GST_STATE_NULL = 1, GST_STATE_READY = 2, GST_STATE_PAUSED = 3, GST_STATE_PLAYING = 4 ); GstStateChangeReturn = ( GST_STATE_CHANGE_FAILURE = 0, GST_STATE_CHANGE_SUCCESS = 1, GST_STATE_CHANGE_ASYNC = 2, GST_STATE_CHANGE_NO_PREROLL = 3 ); type GstClockTime = guint64; PGstBus = type Pointer; PGstElement = type Pointer; PGstMessage = type Pointer; PGstMiniObject = type Pointer; GstMessageType = type Integer; var gst_object_unref: procedure(object_: gpointer); cdecl; gst_element_get_bus: function(element: PGstElement): PGstBus; cdecl; gst_mini_object_unref: procedure(mini_object: PGstMiniObject); cdecl; gst_init_check: function(argc: pcint; argv: PPChar; error: PPGError): gboolean; cdecl; gst_element_set_state: function(element: PGstElement; state: GstState): GstStateChangeReturn; cdecl; gst_element_factory_make: function(const factoryname: Pgchar; const name: Pgchar): PGstElement; cdecl; gst_bus_timed_pop_filtered: function(bus: PGstBus; timeout: GstClockTime; types: GstMessageType): PGstMessage; cdecl; function GST_Initialize: Boolean; function GST_Play(const FileName: String): Boolean; implementation uses URIParser, LazLogger, DCOSUtils, uGObject2; function WaitMsg(Parameter: Pointer): PtrInt; var bus: PGstBus; msg: PGstMessage; playbin: PGstElement absolute Parameter; begin Result:= 0; bus:= gst_element_get_bus(playbin); msg:= gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS or GST_MESSAGE_ERROR); if Assigned(msg) then begin gst_mini_object_unref(msg); end; gst_object_unref(bus); gst_element_set_state(playbin, GST_STATE_NULL); gst_object_unref(playbin); end; function GST_Play(const FileName: String): Boolean; var playbin: PGstElement; res: GstStateChangeReturn; begin playbin:= gst_element_factory_make ('playbin', 'playbin'); Result:= Assigned(playbin); if Result then begin g_object_set(playbin, 'uri', [Pgchar(FilenameToURI(FileName)), nil]); BeginThread(@WaitMsg, playbin); res:= gst_element_set_state(playbin, GST_STATE_PLAYING); Result:= (res <> GST_STATE_CHANGE_FAILURE); end; end; const gstlib = 'libgstreamer-1.0.so.0'; var libgst: TLibHandle; function GST_Initialize: Boolean; var AMsg: String; AError: PGError = nil; begin libgst:= SafeLoadLibrary(gstlib); Result:= (libgst <> NilHandle); if Result then try gst_init_check:= SafeGetProcAddress(libgst, 'gst_init_check'); gst_object_unref:= SafeGetProcAddress(libgst, 'gst_object_unref'); gst_element_get_bus:= SafeGetProcAddress(libgst, 'gst_element_get_bus'); gst_mini_object_unref:= SafeGetProcAddress(libgst, 'gst_mini_object_unref'); gst_element_set_state:= SafeGetProcAddress(libgst, 'gst_element_set_state'); gst_element_factory_make:= SafeGetProcAddress(libgst, 'gst_element_factory_make'); gst_bus_timed_pop_filtered:= SafeGetProcAddress(libgst, 'gst_bus_timed_pop_filtered'); Result:= gst_init_check(nil, nil, @AError); if not Result then begin AMsg:= AError^.message; g_error_free(AError); raise Exception.Create(AMsg); end; except on E: Exception do begin Result:= False; DebugLn(E.Message); FreeLibrary(libgst); end; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/gtk2/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017053� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/gtk2/interfaces.pas����������������������������������������������0000644�0001750�0000144�00000012600�14743153644�021702� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Interfaces; {$mode objfpc}{$H+} interface uses InterfaceBase, LCLType, Gtk2Int; type { TGtk2WidgetSetEx } TGtk2WidgetSetEx = class(TGtk2WidgetSet) public function SetCursor(ACursor: HICON): HCURSOR; override; end; implementation uses Forms, Controls, Gtk2Extra, Gtk2Def, Gtk2Proc, Glib2, Gdk2, Gtk2, Gdk2x, X, XLib; procedure XSetWindowCursor(AWindow: PGdkWindow; ACursor: PGdkCursor); var XCursor: TCursor = None; begin gdk_window_set_cursor(AWindow, ACursor); if Assigned(ACursor) then begin XCursor:= gdk_x11_cursor_get_xcursor(ACursor) end; XDefineCursor(gdk_x11_get_default_xdisplay, gdk_x11_drawable_get_xid(AWindow), XCursor); end; {------------------------------------------------------------------------------ procedure: SetWindowCursor Params: AWindow : PGDkWindow, ACursor: PGdkCursor, ASetDefault: Boolean Returns: Nothing Sets the cursor for a window. Tries to avoid messing with the cursors of implicitly created child windows (e.g. headers in TListView) with the following logic: - If Cursor <> nil, saves the old cursor (if not already done or ASetDefault = true) before setting the new one. - If Cursor = nil, restores the old cursor (if not already done). Unfortunately gdk_window_get_cursor is only available from version 2.18, so it needs to be retrieved dynamically. If gdk_window_get_cursor is not available, the cursor is set according to LCL widget data. ------------------------------------------------------------------------------} procedure SetWindowCursor(AWindow: PGdkWindow; Cursor: PGdkCursor; ASetDefault: Boolean); var OldCursor: PGdkCursor; Data: gpointer; Info: PWidgetInfo; begin Info := nil; gdk_window_get_user_data(AWindow, @Data); if (Data <> nil) and GTK_IS_WIDGET(Data) then begin Info := GetWidgetInfo(PGtkWidget(Data)); end; if not Assigned(gdk_window_get_cursor) and (Info = nil) then Exit; if ASetDefault then //and ((Cursor <> nil) or ( <> nil)) then begin // Override any old default cursor g_object_steal_data(PGObject(AWindow), 'havesavedcursor'); // OK? g_object_steal_data(PGObject(AWindow), 'savedcursor'); XSetWindowCursor(AWindow, Cursor); Exit; end; if Cursor <> nil then begin if Assigned(gdk_window_get_cursor) then OldCursor := gdk_window_get_cursor(AWindow) else OldCursor := {%H-}PGdkCursor(Info^.ControlCursor); // As OldCursor can be nil, use a separate key to indicate whether it // is stored. if ASetDefault or (g_object_get_data(PGObject(AWindow), 'havesavedcursor') = nil) then begin g_object_set_data(PGObject(AWindow), 'havesavedcursor', gpointer(1)); g_object_set_data(PGObject(AWindow), 'savedcursor', gpointer(OldCursor)); end; // gdk_pointer_grab(AWindow, False, 0, AWindow, Cursor, 1); try XSetWindowCursor(AWindow, Cursor); finally // gdk_pointer_ungrab(0); end; end else begin if g_object_steal_data(PGObject(AWindow), 'havesavedcursor') <> nil then begin Cursor := g_object_steal_data(PGObject(AWindow), 'savedcursor'); XSetWindowCursor(AWindow, Cursor); end; end; end; {------------------------------------------------------------------------------ procedure: SetWindowCursor Params: AWindow : PGDkWindow, ACursor: HCursor, ARecursive: Boolean Returns: Nothing Sets the cursor for a window (or recursively for window with children) ------------------------------------------------------------------------------} procedure SetWindowCursor(AWindow: PGdkWindow; ACursor: HCursor; ARecursive: Boolean; ASetDefault: Boolean); var Cursor: PGdkCursor; procedure SetCursorRecursive(AWindow: PGdkWindow); var ChildWindows, ListEntry: PGList; begin SetWindowCursor(AWindow, Cursor, ASetDefault); ChildWindows := gdk_window_get_children(AWindow); ListEntry := ChildWindows; while ListEntry <> nil do begin SetCursorRecursive(PGdkWindow(ListEntry^.Data)); ListEntry := ListEntry^.Next; end; g_list_free(ChildWindows); end; begin Cursor := {%H-}PGdkCursor(ACursor); if ARecursive then SetCursorRecursive(AWindow) else SetWindowCursor(AWindow, Cursor, ASetDefault); end; {------------------------------------------------------------------------------ procedure: SetGlobalCursor Params: ACursor: HCursor Returns: Nothing Sets the cursor for all toplevel windows. Also sets the cursor for all child windows recursively provided gdk_get_window_cursor is available. ------------------------------------------------------------------------------} procedure SetGlobalCursor(Cursor: HCURSOR); var TopList, List: PGList; begin TopList := gdk_window_get_toplevels; List := TopList; while List <> nil do begin if (List^.Data <> nil) then SetWindowCursor(PGDKWindow(List^.Data), Cursor, Assigned(gdk_window_get_cursor), False); list := g_list_next(list); end; if TopList <> nil then g_list_free(TopList); end; { TGtk2WidgetSetEx } function TGtk2WidgetSetEx.SetCursor(ACursor: HICON): HCURSOR; begin gdk_window_get_cursor:= nil; // set global gtk cursor Result := FGlobalCursor; if ACursor = FGlobalCursor then Exit; if ACursor = Screen.Cursors[crDefault] then SetGlobalCursor(0) else SetGlobalCursor(ACursor); FGlobalCursor := ACursor; end; initialization CreateWidgetset(TGtk2WidgetSetEx); finalization FreeWidgetSet; end. ��������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/haiku/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017305� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/haiku/ipc.pas����������������������������������������������������0000644�0001750�0000144�00000001726�14743153644�020573� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ipc; {$mode objfpc}{$H+} {$packrecords c} interface uses BaseUnix, CTypes; const IPC_CREAT = &01000; IPC_EXCL = &02000; IPC_NOWAIT = &04000; IPC_RMID = 0; IPC_SET = 1; IPC_STAT = 2; type key_t = cint32; TKey = key_t; function ftok(path: pansichar; id: cint): key_t; cdecl; external clib; const SEM_GETPID = 3; SEM_GETVAL = 4; SEM_SETVAL = 8; SEM_UNDO = 10; type sembuf = record sem_num: cushort; sem_op: cshort; sem_flg: cshort; end; Tsembuf = sembuf; Psembuf = ^sembuf; semun = record case cint of 0 : ( val : cint ); 1 : ( buf : Pointer ); end; Tsemun = semun; Psemun = ^semun; function semctl(semID: cint; semNum: cint; command: cint; var arg: tsemun): cint; cdecl; external clib; function semget(key: key_t; numSems: cint; semFlags: cint): cint; cdecl; external clib; function semop(semID: cint; semOps: Psembuf; numSemOps: csize_t): cint; cdecl; external clib; implementation end. ������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/�����������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017343� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/inotify.pp�������������������������������������������������0000644�0001750�0000144�00000006720�14743153644�021372� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit inotify; {$mode delphi} {$packrecords c} interface uses InitC, CTypes; type {en Structure describing an inotify event. } inotify_event = record wd: cint32; //en< Watch descriptor. mask: cuint32; //en< Watch mask. cookie: cuint32; //en< Cookie to synchronize two events. len: cuint32; //en< Length (including NULs) of name. name: record end; //en< Stub for possible name (doesn't add to event size). end; {en Pointer to structure describing an inotify event. } pinotify_event = ^inotify_event; const { Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH. } IN_ACCESS = $00000001; {en< File was accessed. } IN_MODIFY = $00000002; {en< File was modified. } IN_ATTRIB = $00000004; {en< Metadata changed. } IN_CLOSE_WRITE = $00000008; {en< Writtable file was closed. } IN_CLOSE_NOWRITE = $00000010; {en< Unwrittable file closed. } IN_CLOSE = IN_CLOSE_WRITE or IN_CLOSE_NOWRITE; {en< Close. } IN_OPEN = $00000020; {en< File was opened. } IN_MOVED_FROM = $00000040; {en< File was moved from X. } IN_MOVED_TO = $00000080; {en< File was moved to Y. } IN_MOVE = IN_MOVED_FROM or IN_MOVED_TO; {en< Moves. } IN_CREATE = $00000100; {en< Subfile was created. } IN_DELETE = $00000200; {en< Subfile was deleted. } IN_DELETE_SELF = $00000400; {en< Self was deleted. } IN_MOVE_SELF = $00000800; {en< Self was moved. } { Events sent by the kernel. } IN_UNMOUNT = $00002000; {en< Backing fs was unmounted. } IN_Q_OVERFLOW = $00004000; {en< Event queued overflowed. } IN_IGNORED = $00008000; {en< File was ignored. } { Special flags. } IN_ONLYDIR = $01000000; {en< Only watch the path if it is a directory. } IN_DONT_FOLLOW = $02000000; {en< Do not follow a sym link. } IN_MASK_ADD = $20000000; {en< Add to the mask of an already existing watch. } IN_ISDIR = $40000000; {en< Event occurred against dir. } IN_ONESHOT = $80000000; {en< Only send event once. } {en All events which a program can wait on. } IN_ALL_EVENTS = ((((((((((IN_ACCESS or IN_MODIFY) or IN_ATTRIB) or IN_CLOSE_WRITE) or IN_CLOSE_NOWRITE) or IN_OPEN) or IN_MOVED_FROM) or IN_MOVED_TO) or IN_CREATE) or IN_DELETE) or IN_DELETE_SELF) or IN_MOVE_SELF; {en Create and initialize inotify instance. } function fpinotify_init: cint; {en Add watch of object NAME to inotify instance FD. Notify about events specified by MASK. } function fpinotify_add_watch(fd: cint; pathname: string; mask: cuint32): cint; {en Remove the watch specified by WD from the inotify instance FD. } function fpinotify_rm_watch(fd: cint; wd: cuint32): cint; implementation uses BaseUnix, DCConvertEncoding; function inotify_init: cint; cdecl; external clib; function inotify_rm_watch(__fd: cint; __wd: cuint32): cint; cdecl; external clib; function inotify_add_watch(__fd: cint; __name: pansichar; __mask: cuint32): cint; cdecl; external clib; function fpinotify_init: cint; begin Result:= inotify_init; if Result = -1 then fpseterrno(fpgetCerrno); end; function fpinotify_add_watch(fd: cint; pathname: string; mask: cuint32): cint; begin Result:= inotify_add_watch(fd, PAnsiChar(CeUtf8ToSys(pathname)), mask); if Result = -1 then fpseterrno(fpgetCerrno); end; function fpinotify_rm_watch(fd: cint; wd: cuint32): cint; begin Result:= inotify_rm_watch(fd, wd); if Result = -1 then fpseterrno(fpgetCerrno); end; end. ������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/statx.pp���������������������������������������������������0000644�0001750�0000144�00000005351�14743153644�021053� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit statx; {$mode objfpc}{$H+} {$packrecords c} interface uses SysUtils, CTypes; const STATX_BTIME = $00000800; //* Want/got stx_btime */ type statx_timestamp = record tv_sec: cint64; tv_nsec: cuint32; __reserved: cint32; end; PStatX = ^TStatX; TStatX = record //* 0x00 */ stx_mask: cuint32; //* What results were written [uncond] */ stx_blksize: cuint32; //* Preferred general I/O size [uncond] */ stx_attributes: cuint64; //* Flags conveying information about the file [uncond] */ //* 0x10 */ stx_nlink: cuint32; //* Number of hard links */ stx_uid: cuint32; //* User ID of owner */ stx_gid: cuint32; //* Group ID of owner */ stx_mode: cuint16; //* File mode */ __spare0: cuint16; //* 0x20 */ stx_ino: cuint64; //* Inode number */ stx_size: cuint64; //* File size */ stx_blocks: cuint64; //* Number of 512-byte blocks allocated */ stx_attributes_mask: cuint64; //* Mask to show what's supported in stx_attributes */ //* 0x40 */ stx_atime: statx_timestamp; //* Last access time */ stx_btime: statx_timestamp; //* File creation time */ stx_ctime: statx_timestamp; //* Last attribute change time */ stx_mtime: statx_timestamp; //* Last data modification time */ //* 0x80 */ stx_rdev_major: cuint32; //* Device ID of special file [if bdev/cdev] */ stx_rdev_minor: cuint32; stx_dev_major: cuint32; //* ID of device containing file [uncond] */ stx_dev_minor: cuint32; //* 0x90 */ __spare2: array[0..13] of cuint64; //* Spare space for future expansion */ //* 0x100 */ end; function fpstatx(dfd: cint; const path: string; flags: cuint; mask: cuint; buffer: pstatx): cint; var HasStatX: Boolean = False; implementation uses SysCall, Dos, DCConvertEncoding; const {$IF DEFINED(CPUI386)} syscall_nr_statx = 383; {$ELSEIF DEFINED(CPUX86_64)} syscall_nr_statx = 332; {$ELSEIF DEFINED(CPUARM) or DEFINED(CPUARM64)} syscall_nr_statx = 397; {$ELSE} syscall_nr_statx = 0; {$ENDIF} function fpstatx(dfd: cint; const path: string; flags: cuint; mask: cuint; buffer: pstatx): cint; var pathname: String; filename: PAnsiChar; begin if (Length(path) = 0) then filename:= nil else begin pathname:= CeUtf8ToSys(path); filename:= PAnsiChar(pathname); end; {$PUSH}{$WARNINGS OFF}{$HINTS OFF} Result := do_syscall(syscall_nr_statx, TSysParam(dfd), TSysParam(filename), TSysParam(flags), TSysParam(mask), TSysParam(buffer)); {$POP} end; initialization // Linux kernel >= 4.11 HasStatX:= (syscall_nr_statx > 0) and (SwapEndian(DosVersion) >= $40B); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/uappimage.pas����������������������������������������������0000644�0001750�0000144�00000000376�14743153644�022026� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uAppImage; {$mode objfpc}{$H+} interface implementation uses BaseUnix; function unsetenv(const name: pansichar): cint; cdecl; external 'c'; initialization if (fpGetEnv(PAnsiChar('APPIMAGE')) <> nil) then unsetenv('PYTHONHOME'); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/uflatpak.pas�����������������������������������������������0000644�0001750�0000144�00000010447�14743153644�021665� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFlatpak; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, uMyUnix; function FlatpakOpen(const FileName: String; Ask: Boolean32): Boolean; implementation uses BaseUnix, DCOSUtils, DCUnix, uTrash, uDebug, uGLib2, uGObject2, uGio2; const PORTAL_BUS_NAME = 'org.freedesktop.portal.Desktop'; PORTAL_OBJECT_PATH = '/org/freedesktop/portal/desktop'; PORTAL_INTERFACE_TRASH = 'org.freedesktop.portal.Trash'; PORTAL_INTERFACE_OPENURI = 'org.freedesktop.portal.OpenURI'; var PortalBusName: String; DBusConn: PGDBusConnection = nil; procedure PrintError(AError: PGError); begin DCDebug(AError^.message); g_error_free(AError); end; function FlatpakOpen(const FileName: String; Ask: Boolean32): Boolean; var Res: PGVariant; Handle: THandle; FDList: PGUnixFDList; AError: PGError = nil; Options: TGVariantBuilder; begin if (DBusConn = nil) then Exit(False); Handle:= mbFileOpen(FileName, fmOpenRead or fmShareDenyNone); if Handle < 0 then Exit(False); FDList:= g_unix_fd_list_new_from_array(@Handle, 1); g_variant_builder_init(@Options, PGVariantType(Pgchar('a{sv}'))); g_variant_builder_add(@Options, '{sv}', ['ask', g_variant_new_boolean(Ask)]); Res:= g_dbus_connection_call_with_unix_fd_list_sync(DBusConn, Pgchar(PortalBusName), PORTAL_OBJECT_PATH, PORTAL_INTERFACE_OPENURI, 'OpenFile', g_variant_new('(sha{sv})', ['', 0, @Options]), nil, G_DBUS_CALL_FLAGS_NONE, -1, FDList, nil, nil, @AError); g_object_unref(PGObject(FDList)); if Assigned(AError) then begin PrintError(AError); end; Result:= Assigned(Res); if Result then g_variant_unref(Res); end; function FileTrash(const FileName: String): Boolean; var Answer: guint; Ret: PGVariant; Handle: THandle; FDList: PGUnixFDList; AError: PGError = nil; begin repeat Handle:= fpOpen(FileName, O_PATH or O_CLOEXEC); until (Handle <> -1) or (fpgeterrno <> ESysEINTR); if Handle < 0 then Exit(False); FDList:= g_unix_fd_list_new_from_array(@Handle, 1); Ret:= g_dbus_connection_call_with_unix_fd_list_sync(DBusConn, Pgchar(PortalBusName), PORTAL_OBJECT_PATH, PORTAL_INTERFACE_TRASH, 'TrashFile', g_variant_new('(h)', [0]), nil, G_DBUS_CALL_FLAGS_NONE, -1, FDList, nil, nil, @AError); g_object_unref(PGObject(FDList)); if Assigned(AError) then begin PrintError(AError); end; if (Ret = nil) then Result:= False else begin g_variant_get(Ret, '(u)', [@Answer]); Result:= (Answer = 1); g_variant_unref(Ret); end; end; procedure Initialize; var AError: PGError = nil; begin if (DesktopEnv = DE_FLATPAK) then begin PortalBusName:= GetEnvironmentVariable('LIBPORTAL_PORTAL_BUS_NAME'); if (Length(PortalBusName) = 0) then PortalBusName:= PORTAL_BUS_NAME; DBusConn:= g_bus_get_sync(G_BUS_TYPE_SESSION, nil, @AError); if (DBusConn = nil) then PrintError(AError) else begin FileTrashUtf8:= @FileTrash; end; end; end; procedure Finalize; begin if Assigned(DBusConn) then g_object_unref(PGObject(DBusConn)); end; initialization Initialize; finalization Finalize; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/umountwatcher.pas������������������������������������������0000644�0001750�0000144�00000002227�14743153644�022760� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uMountWatcher; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Unix, BaseUnix, CTypes; type { TMountWatcher } TMountWatcher = class private FOnMountEvent: TNotifyEvent; protected procedure DoMountEvent; procedure Handler(Sender: TObject); procedure ShowMessage(const Message: String); public procedure Start; property OnMountEvent: TNotifyEvent read FOnMountEvent write FOnMountEvent; end; implementation uses RtlConsts, DCOSUtils, uDebug, uPollThread; { TMountWatcher } procedure TMountWatcher.DoMountEvent; begin if Assigned(FOnMountEvent) then FOnMountEvent(Self); end; procedure TMountWatcher.Handler(Sender: TObject); begin Sleep(1000); TThread.Synchronize(nil, @DoMountEvent); ShowMessage('DoMountEvent'); end; procedure TMountWatcher.ShowMessage(const Message: String); begin DCDebug(ClassName + ': ' + Message); end; procedure TMountWatcher.Start; var fd: cint; begin fd:= mbFileOpen('/proc/self/mounts', fmOpenRead); if (fd = feInvalidHandle) then ShowMessage(Format(SFOpenError, ['/proc/self/mounts'])) else begin AddPoll(fd, POLLERR, @Handler, True); end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/umylinux.pas�����������������������������������������������0000644�0001750�0000144�00000004476�14743153644�021755� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains specific LINUX functions. Copyright (C) 2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uMyLinux; {$mode delphi} interface uses SysUtils; function GetFreeMem(out MemFree, MemTotal: Int64): Boolean; implementation uses DCStrUtils; function Convert(const S: String; Index: Integer): Int64; var V: String; K: Integer; begin K:= 1; V:= Trim(Copy(S, Index, MaxInt)); while (V[K] in ['0'..'9']) do Inc(K); Result:= StrToInt64Def(Copy(V, 1, K - 1), 0); V:= Trim(Copy(V, K, MaxInt)); if Length(V) > 0 then begin case LowerCase(V[1]) of 'k': Result:= Result * 1024; 'm': Result:= Result * 1024 * 1024; 'g': Result:= Result * 1024 * 1024 * 1024; end; end; end; function GetFreeMem(out MemFree, MemTotal: Int64): Boolean; var S: String; F: TextFile; Count: Integer = 0; MemAvailable: Int64; begin try AssignFile(F, '/proc/meminfo'); try Reset(F); repeat ReadLn(F, S); if StrBegins(S, 'MemTotal:') then begin Inc(Count); MemTotal:= Convert(S, 10); end else if StrBegins(S, 'MemFree:') then begin Inc(Count); MemFree:= Convert(S, 9); end else if StrBegins(S, 'MemAvailable:') then begin Inc(Count); MemAvailable:= Convert(S, 14); end; until EOF(F) or (Count = 3); if MemAvailable < MemTotal then begin MemFree:= MemAvailable; end; Result:= (Count = 3); finally System.Close(F); end; except Result:= False; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/uudev.pas��������������������������������������������������0000644�0001750�0000144�00000052515�14743153644�021210� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Interface to UDev service via libudev. Copyright (C) 2014-2022 Alexander Koblov (alexx2000@mail.ru) Based on udisks-1.0.4/src/device.c Copyright (C) 2008 David Zeuthen <david@fubar.dk> 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 } unit uUDev; {$mode delphi} {$assertions on} interface uses Classes, SysUtils, CTypes, Unix, BaseUnix, uUDisks; function Initialize: Boolean; procedure Finalize; procedure AddObserver(Func: TUDisksDeviceNotify); procedure RemoveObserver(Func: TUDisksDeviceNotify); function EnumerateDevices(out DevicesInfos: TUDisksDevicesInfos): Boolean; function GetDeviceInfo(const ObjectPath: String; out Info: TUDisksDeviceInfo): Boolean; overload; var HasUdev: Boolean = False; implementation uses DynLibs, DCOSUtils, DCStrUtils, uDebug, uPollThread; type { TMonitorObject } TMonitorObject = class private FAction: String; FDevicePath: String; private procedure ReceiveDevice; procedure Handler(Sender: TObject); public constructor Create; end; type Pudev = ^Tudev; Tudev = record end; Pudev_device = ^Tudev_device; Tudev_device = record end; Pudev_monitor = ^Tudev_monitor; Tudev_monitor = record end; Pudev_enumerate = ^Tudev_enumerate; Tudev_enumerate = record end; Pudev_list_entry = ^Tudev_list_entry; Tudev_list_entry = record end; var // udev — libudev context udev_new: function(): Pudev; cdecl; udev_unref: function(udev: Pudev): Pudev; cdecl; // udev_list — list operation udev_list_entry_get_next: function(list_entry: Pudev_list_entry): Pudev_list_entry; cdecl; udev_list_entry_get_name: function(list_entry: Pudev_list_entry): PAnsiChar; cdecl; // udev_device — kernel sys devices udev_device_unref: procedure(udev_device: Pudev_device); cdecl; udev_device_new_from_syspath: function(udev: Pudev; const syspath: PAnsiChar): Pudev_device; cdecl; udev_device_get_devnode: function(udev_device: Pudev_device): PAnsiChar; cdecl; udev_device_get_devtype: function(udev_device: Pudev_device): PAnsiChar; cdecl; udev_device_get_syspath: function(udev_device: Pudev_device): PAnsiChar; cdecl; udev_device_get_action: function(udev_device: Pudev_device): PAnsiChar; cdecl; udev_device_get_property_value: function(udev_device: Pudev_device; const key: PAnsiChar): PAnsiChar; cdecl; udev_device_get_sysattr_value: function(udev_device: Pudev_device; const sysattr: PAnsiChar): PAnsiChar; cdecl; // udev_monitor — device event source udev_monitor_unref: procedure(udev_monitor: Pudev_monitor); cdecl; udev_monitor_new_from_netlink: function(udev: Pudev; const name: PAnsiChar): Pudev_monitor; cdecl; udev_monitor_filter_add_match_subsystem_devtype: function(udev_monitor: Pudev_monitor; const subsystem: PAnsiChar; const devtype: PAnsiChar): cint; cdecl; udev_monitor_enable_receiving: function(udev_monitor: Pudev_monitor): cint; cdecl; udev_monitor_get_fd: function(udev_monitor: Pudev_monitor): cint; cdecl; udev_monitor_receive_device: function(udev_monitor: Pudev_monitor): Pudev_device; cdecl; // udev_enumerate — lookup and sort sys devices udev_enumerate_new: function(udev: Pudev): Pudev_enumerate; cdecl; udev_enumerate_unref: function(udev_enumerate: Pudev_enumerate): Pudev_enumerate; cdecl; udev_enumerate_add_match_subsystem: function(udev_enumerate: Pudev_enumerate; const subsystem: PAnsiChar): cint; cdecl; udev_enumerate_scan_devices: function(udev_enumerate: Pudev_enumerate): cint; cdecl; udev_enumerate_get_list_entry: function(udev_enumerate: Pudev_enumerate): Pudev_list_entry; cdecl; const LibraryName = 'libudev.so.%d'; var udev: Pudev = nil; libudev: TLibHandle = NilHandle; udev_monitor: Pudev_monitor = nil; udev_monitor_object: TMonitorObject = nil; observers: TUDisksObserverList = nil; const UDEV_DEVICE_TYPE_DISK = 'disk'; UDEV_DEVICE_TYPE_PARTITION = 'partition'; { udev property, media name, force non removable, force removable } drive_media_mapping: array [0..33, 0..3] of String = ( ( 'ID_DRIVE_THUMB', 'thumb', 'TRUE', 'FALSE' ), ( 'ID_DRIVE_FLASH', 'flash', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_CF', 'flash_cf', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_MS', 'flash_ms', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_SM', 'flash_sm', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_SD', 'flash_sd', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_SDHC', 'flash_sdhc', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_SDXC', 'flash_sdxc', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_SDIO', 'flash_sdio', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_SD_COMBO', 'flash_sd_combo', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLASH_MMC', 'flash_mmc', 'TRUE', 'FALSE' ), ( 'ID_DRIVE_FLOPPY', 'floppy', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLOPPY_ZIP', 'floppy_zip', 'FALSE', 'TRUE' ), ( 'ID_DRIVE_FLOPPY_JAZ', 'floppy_jaz', 'FALSE', 'TRUE' ), ( 'ID_CDROM', 'optical_cd', 'FALSE', 'TRUE' ), ( 'ID_CDROM_CD_R', 'optical_cd_r', 'FALSE', 'TRUE' ), ( 'ID_CDROM_CD_RW', 'optical_cd_rw', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD', 'optical_dvd', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_R', 'optical_dvd_r', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_RW', 'optical_dvd_rw', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_RAM', 'optical_dvd_ram', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_PLUS_R', 'optical_dvd_plus_r', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_PLUS_RW', 'optical_dvd_plus_rw', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_PLUS_R_DL', 'optical_dvd_plus_r_dl', 'FALSE', 'TRUE' ), ( 'ID_CDROM_DVD_PLUS_RW_DL', 'optical_dvd_plus_rw_dl', 'FALSE', 'TRUE' ), ( 'ID_CDROM_BD', 'optical_bd', 'FALSE', 'TRUE' ), ( 'ID_CDROM_BD_R', 'optical_bd_r', 'FALSE', 'TRUE' ), ( 'ID_CDROM_BD_RE', 'optical_bd_re', 'FALSE', 'TRUE' ), ( 'ID_CDROM_HDDVD', 'optical_hddvd', 'FALSE', 'TRUE' ), ( 'ID_CDROM_HDDVD_R', 'optical_hddvd_r', 'FALSE', 'TRUE' ), ( 'ID_CDROM_HDDVD_RW', 'optical_hddvd_rw', 'FALSE', 'TRUE' ), ( 'ID_CDROM_MO', 'optical_mo', 'FALSE', 'TRUE' ), ( 'ID_CDROM_MRW', 'optical_mrw', 'FALSE', 'TRUE' ), ( 'ID_CDROM_MRW_W', 'optical_mrw_w', 'FALSE', 'TRUE' ) ); procedure Print(const sMessage: String); begin DCDebug('UDev: ', sMessage); end; procedure Load; var Version: Integer; begin for Version:= 1 downto 0 do begin libudev:= LoadLibrary(Format(LibraryName, [Version])); if libudev <> NilHandle then Break; end; HasUdev:= libudev <> NilHandle; if HasUdev then try // udev — libudev context udev_new:= SafeGetProcAddress(libudev, 'udev_new'); udev_unref:= SafeGetProcAddress(libudev, 'udev_unref'); // udev_list — list operation udev_list_entry_get_next:= SafeGetProcAddress(libudev, 'udev_list_entry_get_next'); udev_list_entry_get_name:= SafeGetProcAddress(libudev, 'udev_list_entry_get_name'); // udev_device — kernel sys devices udev_device_unref:= SafeGetProcAddress(libudev, 'udev_device_unref'); udev_device_new_from_syspath:= SafeGetProcAddress(libudev, 'udev_device_new_from_syspath'); udev_device_get_devnode:= SafeGetProcAddress(libudev, 'udev_device_get_devnode'); udev_device_get_devtype:= SafeGetProcAddress(libudev, 'udev_device_get_devtype'); udev_device_get_syspath:= SafeGetProcAddress(libudev, 'udev_device_get_syspath'); udev_device_get_action:= SafeGetProcAddress(libudev, 'udev_device_get_action'); udev_device_get_property_value:= SafeGetProcAddress(libudev, 'udev_device_get_property_value'); udev_device_get_sysattr_value:= SafeGetProcAddress(libudev, 'udev_device_get_sysattr_value'); // udev_monitor — device event source udev_monitor_unref:= SafeGetProcAddress(libudev, 'udev_monitor_unref'); udev_monitor_new_from_netlink:= SafeGetProcAddress(libudev, 'udev_monitor_new_from_netlink'); udev_monitor_filter_add_match_subsystem_devtype:= SafeGetProcAddress(libudev, 'udev_monitor_filter_add_match_subsystem_devtype'); udev_monitor_enable_receiving:= SafeGetProcAddress(libudev, 'udev_monitor_enable_receiving'); udev_monitor_get_fd:= SafeGetProcAddress(libudev, 'udev_monitor_get_fd'); udev_monitor_receive_device:= SafeGetProcAddress(libudev, 'udev_monitor_receive_device'); // udev_enumerate — lookup and sort sys devices udev_enumerate_new:= SafeGetProcAddress(libudev, 'udev_enumerate_new'); udev_enumerate_unref:= SafeGetProcAddress(libudev, 'udev_enumerate_unref'); udev_enumerate_add_match_subsystem:= SafeGetProcAddress(libudev, 'udev_enumerate_add_match_subsystem'); udev_enumerate_scan_devices:= SafeGetProcAddress(libudev, 'udev_enumerate_scan_devices'); udev_enumerate_get_list_entry:= SafeGetProcAddress(libudev, 'udev_enumerate_get_list_entry'); // Create the udev object udev:= udev_new(); if udev = nil then Raise Exception.Create('Can''t create udev'); except on E: Exception do begin HasUdev:= False; UnloadLibrary(libudev); Print(E.Message); end; end; end; procedure Free; begin if Assigned(udev) then udev_unref(udev); if libudev <> NilHandle then UnloadLibrary(libudev); end; function GetDeviceProperty(const Device: Pudev_device; const PropertyName: String; out Value: Boolean): Boolean; overload; var pacValue: PAnsiChar; begin pacValue:= udev_device_get_property_value(Device, PAnsiCHar(PropertyName)); Result:= Assigned(pacValue); if (Result = False) then Value:= False else Value:= StrToBool(pacValue); end; function GetDeviceProperty(const Device: Pudev_device; const PropertyName: String; out Value: String): Boolean; overload; var pacValue: PAnsiChar; begin pacValue:= udev_device_get_property_value(Device, PAnsiCHar(PropertyName)); Result:= Assigned(pacValue); if (Result = False) then Value:= EmptyStr else Value:= StrPas(pacValue); end; function GetDeviceAttribute(const Device: Pudev_device; const AttributeName: String; out Value: String): Boolean; overload; var pacValue: PAnsiChar; begin pacValue:= udev_device_get_sysattr_value(Device, PAnsiCHar(AttributeName)); Result:= Assigned(pacValue); if (Result = False) then Value:= EmptyStr else Value:= StrPas(pacValue); end; function GetDeviceAttribute(const Device: Pudev_device; const AttributeName: String; out Value: Boolean): Boolean; overload; var S: String; begin Result:= GetDeviceAttribute(Device, AttributeName, S); if Result then Result:= TryStrToBool(S, Value); end; function GetDeviceAttribute(const SystemPath: String; const AttributeName: String; out Value: Boolean): Boolean; overload; var S: AnsiChar; Handle: THandle; FileName: String; begin FileName:= IncludeTrailingBackslash(SystemPath) + AttributeName; Handle:= mbFileOpen(FileName, fmOpenRead or fmShareDenyNone); Result:= Handle <> feInvalidHandle; if Result then begin Result:= FileRead(Handle, S, SizeOf(S)) > 0; if Result then Result:= TryStrToBool(S, Value); FileClose(Handle); end; end; function DecodeString(const EncodedString: String): String; var Finish: Integer; Index: Integer = 1; StartIndex: Integer = 1; begin Result:= EmptyStr; Finish:= Length(EncodedString); while Index <= Finish - 3 do begin if EncodedString[Index] <> '\' then Inc(Index) else begin if EncodedString[Index + 1] <> 'x' then begin Print('**** NOTE: malformed encoded string: ' + EncodedString); Exit(EncodedString); end; Result:= Result + Copy(EncodedString, StartIndex, Index - StartIndex) + Chr(StrToInt('$' + Copy(EncodedString, Index + 2, 2))); Index:= Index + 4; StartIndex:= Index; end; end; Result:= Result + Copy(EncodedString, StartIndex, Finish - StartIndex + 1); end; procedure UpdateDriveConnectionInterface(SystemPath: PAnsiChar; var Info: TUDisksDeviceInfo); var Path, Connection: String; begin Path:= IncludeTrailingPathDelimiter(SystemPath); repeat Connection:= fpReadLink(Path + 'subsystem'); Connection:= ExtractFileName(ExcludeTrailingPathDelimiter(Connection)); if Connection = 'usb' then begin // Both the interface and the device will be 'usb'. // However only the device will have the 'speed' property. if mbFileExists(Path + 'speed') then begin Info.DriveConnectionInterface:= Connection; Break; end; end; Path:= ExtractFilePath(ExcludeTrailingPathDelimiter(Path)); until (Length(Path) = 0) or (CompareStr(Path, '/sys/devices/') = 0); end; procedure GetDeviceInfo(SystemPath: PAnsiChar; Device: Pudev_device; out Info: TUDisksDeviceInfo); overload; var I: Integer; Value: String; DeviceName: String; force_removable: Boolean = False; force_non_removable: Boolean = False; begin with Info do begin DeviceFile:= udev_device_get_devnode(Device); DeviceName:= ExtractFileName(DeviceFile); DeviceObjectPath:= SystemPath; GetDeviceProperty(Device, 'ID_FS_USAGE', IdUsage); GetDeviceProperty(Device, 'ID_FS_TYPE', IdType); GetDeviceProperty(Device, 'ID_FS_VERSION', IdVersion); GetDeviceProperty(Device, 'ID_FS_UUID', IdUuid); GetDeviceProperty(Device, 'ID_FS_LABEL_ENC', IdLabel); if Length(IdLabel) > 0 then IdLabel:= DecodeString(IdLabel) else begin GetDeviceProperty(Device, 'ID_FS_LABEL', IdLabel); end; GetDeviceProperty(Device, 'ID_BUS', DriveConnectionInterface); for I:= Low(drive_media_mapping) to High(drive_media_mapping) do begin if Assigned(udev_device_get_property_value(Device, PAnsiChar(drive_media_mapping[I, 0]))) then begin AddString(DriveMediaCompatibility, drive_media_mapping[I, 1]); if StrToBool(drive_media_mapping[I, 2]) then force_non_removable:= True; if StrToBool(drive_media_mapping[I, 3]) then force_removable:= True; end; end; GetDeviceProperty(Device, 'UDISKS_SYSTEM', DeviceIsSystemInternal); GetDeviceProperty(Device, 'UDISKS_IGNORE', DevicePresentationHide); GetDeviceProperty(Device, 'UDISKS_AUTO', DeviceAutomountHint); GetDeviceProperty(Device, 'UDISKS_NAME', DevicePresentationName); GetDeviceProperty(Device, 'UDISKS_ICON_NAME', DevicePresentationIconName); Value:= udev_device_get_devtype(Device); DeviceIsDrive:= (Value = UDEV_DEVICE_TYPE_DISK); DeviceIsPartition:= (Value = UDEV_DEVICE_TYPE_PARTITION); DeviceIsRemovable := False; if DeviceIsDrive then begin DeviceIsPartitionTable:= (udev_device_get_property_value(Device, 'ID_PART_TABLE_TYPE' ) <> nil); end else if DeviceIsPartition then begin if DeviceObjectPath[Length(DeviceObjectPath)] in ['0'..'9'] then begin PartitionSlave:= ExtractFileDir(DeviceObjectPath); GetDeviceAttribute(PartitionSlave, 'removable', DeviceIsRemovable); end; end; if not DeviceIsRemovable then begin GetDeviceAttribute(Device, 'removable', DeviceIsRemovable); end; DriveIsMediaEjectable:= DeviceIsRemovable; if force_non_removable then DeviceIsRemovable:= False; if force_removable then DeviceIsRemovable:= True; if StrBegins(DeviceName, 'mmcblk') then DriveIsMediaEjectable:= DeviceIsRemovable; if (StrBegins(DeviceName, 'fd')) or (udev_device_get_property_value(Device, 'ID_DRIVE_FLOPPY' ) <> nil) then begin DriveIsMediaEjectable:= False; end; GetDeviceAttribute(Device, 'size', DeviceSize); UpdateDriveConnectionInterface(SystemPath, Info); DeviceIsMediaAvailable:= (Length(IdUsage) > 0) or (Length(IdType) > 0) or (Length(IdUuid) > 0) or (Length(IdLabel) > 0); if not DeviceIsMediaAvailable then begin GetDeviceProperty(Device, 'ID_CDROM_MEDIA', DeviceIsMediaAvailable); end; { WriteLn('Device: ', DeviceFile); WriteLn(' Devtype: ', Value); WriteLn(' IdType: ', IdType); WriteLn(' IdLabel: ', IdLabel ); WriteLn(' IdVersion: ', IdVersion ); WriteLn(' IdUsage: ', IdUsage ); WriteLn(' IdUuid: ', IdUuid ); WriteLn(' DriveIsMediaEjectable: ', DriveIsMediaEjectable ); WriteLn(' DeviceIsSystemInternal: ', DeviceIsSystemInternal ); WriteLn(' DeviceIsPartitionTable: ', DeviceIsPartitionTable ); WriteLn(' DevicePresentationHide: ', DevicePresentationHide ); WriteLn(' DevicePresentationName: ', DevicePresentationName ); WriteLn(' DevicePresentationIconName: ', DevicePresentationIconName ); WriteLn(' DeviceAutomountHint: ', DeviceAutomountHint ); WriteLn(' PartitionSlave: ', PartitionSlave ); WriteLn(' DeviceIsRemovable: ', DeviceIsRemovable ); WriteLn(' DriveConnectionInterface: ', DriveConnectionInterface ); WriteLn(' DriveMediaCompatibility: ', ArrayToString(DriveMediaCompatibility, ',') ); } end; end; function EnumerateDevices(out DevicesInfos: TUDisksDevicesInfos): Boolean; var path: PAnsiChar; device: Pudev_device; devices: Pudev_list_entry; enumerate: Pudev_enumerate; begin SetLength(DevicesInfos, 0); // Create a list of the devices in the 'block' subsystem enumerate:= udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, 'block'); udev_enumerate_scan_devices(enumerate); devices:= udev_enumerate_get_list_entry(enumerate); while devices <> nil do begin // Get the filename of the /sys entry for the device // and create a udev_device object (dev) representing it path:= udev_list_entry_get_name(devices); device:= udev_device_new_from_syspath(udev, path); if Assigned(device) then begin SetLength(DevicesInfos, Length(DevicesInfos) + 1); GetDeviceInfo(path, device, DevicesInfos[High(DevicesInfos)]); udev_device_unref(Device); end; devices:= udev_list_entry_get_next(devices); end; // Free the enumerator object udev_enumerate_unref(enumerate); Result:= Length(DevicesInfos) > 0; end; function GetDeviceInfo(const ObjectPath: String; out Info: TUDisksDeviceInfo): Boolean; var Device: Pudev_device; begin Device:= udev_device_new_from_syspath(udev, PAnsiChar(ObjectPath)); Result:= Assigned(Device); if Result then begin GetDeviceInfo(PAnsiChar(ObjectPath), Device, Info); udev_device_unref(Device); end; end; function Initialize: Boolean; var Return: cint; begin // Set up a monitor to monitor block devices udev_monitor:= udev_monitor_new_from_netlink(udev, 'udev'); Result:= Assigned(udev_monitor); if Result then try Return:= udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, 'block', nil); Assert(Return = 0, 'udev_monitor_filter_add_match_subsystem_devtype'); Return:= udev_monitor_enable_receiving(udev_monitor); Assert(Return = 0, 'udev_monitor_enable_receiving'); observers:= TUDisksObserverList.Create; udev_monitor_object:= TMonitorObject.Create; except Result:= False; udev_monitor_unref(udev_monitor); udev_monitor:= nil; end; end; procedure Finalize; begin FreeAndNil(udev_monitor_object); FreeAndNil(observers); udev_monitor_unref(udev_monitor); end; procedure AddObserver(Func: TUDisksDeviceNotify); begin if Observers.IndexOf(Func) < 0 then Observers.Add(Func); end; procedure RemoveObserver(Func: TUDisksDeviceNotify); begin Observers.Remove(Func); end; { TMonitorThread } procedure TMonitorObject.ReceiveDevice; var I: Integer; Method: TUDisksMethod; begin if FAction = 'add' then Method:= UDisks_DeviceAdded else if FAction = 'remove' then Method:= UDisks_DeviceRemoved else if FAction = 'change' then Method:= UDisks_DeviceChanged else Method:= UDisks_DeviceChanged; Print('Device ' + FAction + ': ' + FDevicePath); for I := 0 to Observers.Count - 1 do Observers[I](Method, FDevicePath); end; procedure TMonitorObject.Handler(Sender: TObject); var device: Pudev_device; begin // Make the call to ReceiveDevice the device // select() ensured that this will not block device:= udev_monitor_receive_device(udev_monitor); if Assigned(device) then begin FAction:= udev_device_get_action(device); FDevicePath:= udev_device_get_syspath(device); TThread.Synchronize(nil, ReceiveDevice); udev_device_unref(device); end; end; constructor TMonitorObject.Create; var fd: cint; begin // Get the file descriptor (fd) for the monitor // This fd will get passed to poll() fd := udev_monitor_get_fd(udev_monitor); AddPoll(fd, POLLIN, Handler, False); Print('Begin monitoring'); end; initialization Load; finalization Free; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/uudisks.pas������������������������������������������������0000644�0001750�0000144�00000004431�14743153644�021541� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- UDisks types unit Copyright (C) 2010-2012 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uUDisks; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fgl; type TUDisksDeviceInfo = record DeviceObjectPath: String; DeviceFile: String; DeviceIsDrive, DeviceIsSystemInternal, DeviceIsPartition, DeviceIsPartitionTable, // Does the device have a partition table DeviceIsMounted, DeviceIsRemovable, // If contains removable media. DeviceIsOpticalDisc, // If is an optical drive and optical disk is inserted. DeviceIsMediaAvailable, DriveIsMediaEjectable: Boolean; DeviceMountPaths: TStringArray; DevicePresentationHide: Boolean; DevicePresentationName: String; DevicePresentationIconName: String; DeviceAutomountHint: String; // Whether automatically mount or not DriveConnectionInterface, DriveMedia: String; // Type of media currently in the drive. DriveMediaCompatibility: TStringArray; // Possible media types. IdUsage, IdType, IdVersion, IdUuid, IdLabel, DeviceSize, PartitionSlave: String; // Owner device if this is a partition end; TUDisksDevicesInfos = array of TUDisksDeviceInfo; TUDisksMethod = (UDisks_DeviceAdded, UDisks_DeviceRemoved, UDisks_DeviceChanged); TUDisksDeviceNotify = procedure(Reason: TUDisksMethod; const ObjectPath: String) of object; TUDisksObserverList = specialize TFPGList<TUDisksDeviceNotify>; implementation end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/linux/uudisks2.pas�����������������������������������������������0000644�0001750�0000144�00000023512�14743153644�021624� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Interface to UDisks2 service via libudisks2. Copyright (C) 2020-2022 Alexander Koblov (alexx2000@mail.ru) Based on udisks-2.8.4/tools/udisksctl.c Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com> 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, see <http://www.gnu.org/licenses/>. } unit uUDisks2; {$mode delphi} interface uses SysUtils; function Mount(const ObjectPath: String; out MountPath: String): Boolean; function Unmount(const ObjectPath: String): Boolean; function Eject(const ObjectPath: String): Boolean; var HasUDisks2: Boolean = False; implementation uses DynLibs, LazLogger, DCOSUtils, uGio2, uGObject2, uGlib2; type PUDisksBlock = Pointer; PUDisksDrive = Pointer; PUDisksObject = Pointer; PUDisksClient = Pointer; PUDisksFilesystem = Pointer; var udisks_block_get_drive: function(object_: PUDisksBlock): Pgchar; cdecl; udisks_block_get_device: function(object_: PUDisksBlock): Pgchar; cdecl; udisks_block_get_symlinks: function(object_: PUDisksBlock): PPgchar; cdecl; udisks_object_peek_drive: function(object_: PUDisksObject): PUDisksDrive; cdecl; udisks_object_peek_block: function(object_: PUDisksObject): PUDisksBlock; cdecl; udisks_filesystem_get_mount_points: function(object_: PUDisksFilesystem): PPgchar; cdecl; udisks_object_peek_filesystem: function(object_: PUDisksObject): PUDisksFilesystem; cdecl; udisks_client_get_object_manager: function(client: PUDisksClient): PGDBusObjectManager; cdecl; udisks_client_new_sync: function(cancellable: PGCancellable; error: PPGError): PUDisksClient; cdecl; udisks_drive_call_eject_sync: function(proxy: PUDisksDrive; arg_options: PGVariant; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; udisks_filesystem_call_unmount_sync: function(proxy: PUDisksFilesystem; arg_options: PGVariant; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; udisks_filesystem_call_mount_sync: function(proxy: PUDisksFilesystem; arg_options: PGVariant; out_mount_path: PPgchar; cancellable: PGCancellable; error: PPGError): gboolean; cdecl; procedure Print(const sMessage: String); begin DebugLn('UDisks2: ', sMessage); end; procedure PrintError(var AError: PGError); begin Print(AError^.message); g_error_free(AError); AError:= nil; end; function DeviceFileToUDisksObject(Client: PUDisksClient; Device: Pgchar): PUDisksObject; var Symlinks: PPgchar; L, Objects: PGList; Block: PUDisksBlock; Object_: PUDisksObject; begin Result:= nil; Objects:= g_dbus_object_manager_get_objects(udisks_client_get_object_manager(Client)); if Assigned(Objects) then try L:= Objects; while (L <> nil) do begin Object_:= PUDisksObject(L^.data); Block:= udisks_object_peek_block(Object_); if Assigned(Block) then begin if (g_strcmp0(udisks_block_get_device(Block), Device) = 0) then begin Result:= PUDisksObject(g_object_ref(PGObject(Object_))); Exit; end; Symlinks:= udisks_block_get_symlinks(Block); while (Symlinks <> nil) and (Symlinks^ <> nil) do begin if (g_strcmp0(Symlinks^, Device) = 0) then begin Result:= PUDisksObject(g_object_ref(PGObject(Object_))); Exit; end; Inc(Symlinks); end; end; L:= L^.next; end; finally g_list_free_full(Objects, TGDestroyNotify(@g_object_unref)); end; end; function MountUnmount(const ObjectPath: String; Mount: Boolean; MountPath: PString): Boolean; var mount_path: Pgchar; options: PGVariant; AError: PGError = nil; object_: PUDisksObject; builder: TGVariantBuilder; client: PUDisksClient = nil; filesystem: PUDisksFilesystem; begin client := udisks_client_new_sync (nil, @AError); if (client = nil) then begin PrintError(AError); Exit(False); end; object_:= DeviceFileToUDisksObject(client, Pgchar(ObjectPath)); Result:= Assigned(object_); if Result then begin filesystem:= udisks_object_peek_filesystem(object_); Result:= Assigned(filesystem); if Result then begin g_variant_builder_init(@builder, PGVariantType(PAnsiChar('a{sv}'))); options:= g_variant_builder_end (@builder); g_variant_ref_sink(options); if not Mount then begin Result:= udisks_filesystem_call_unmount_sync(filesystem, options, nil, @AError); if not Result then PrintError(AError); end else begin Result:= udisks_filesystem_call_mount_sync(filesystem, options, @mount_path, nil, @AError); if not Result then PrintError(AError) else begin MountPath^:= StrPas(mount_path); g_free(mount_path); end; end; g_variant_unref(options); end; g_object_unref(PGObject(object_)); end; g_object_unref(PGObject(client)); end; function Mount(const ObjectPath: String; out MountPath: String): Boolean; begin Result:= MountUnmount(ObjectPath, True, @MountPath); end; function Unmount(const ObjectPath: String): Boolean; begin Result:= MountUnmount(ObjectPath, False, nil); end; function Eject(const ObjectPath: String): Boolean; var DrivePath: Pgchar; Options: PGVariant; Drive: PUDisksDrive; Block: PUDisksBlock; MountPoints: PPgchar; AError: PGError = nil; Builder: TGVariantBuilder; BlockObject: PUDisksObject; DriveObject: PUDisksObject; Client: PUDisksClient = nil; FileSystem: PUDisksFilesystem; begin Client := udisks_client_new_sync (nil, @AError); if (Client = nil) then begin PrintError(AError); Exit(False); end; BlockObject:= DeviceFileToUDisksObject(Client, Pgchar(ObjectPath)); Result:= Assigned(BlockObject); if Result then begin Block:= udisks_object_peek_block(BlockObject); Result:= Assigned(Block); if Result then begin DrivePath:= udisks_block_get_drive(Block); DriveObject:= g_dbus_object_manager_get_object(udisks_client_get_object_manager(Client), DrivePath); Result:= Assigned(DriveObject); if Result then begin Drive:= udisks_object_peek_drive(DriveObject); Result:= Assigned(Drive); if Result then begin g_variant_builder_init(@Builder, PGVariantType(PAnsiChar('a{sv}'))); Options:= g_variant_builder_end(@Builder); g_variant_ref_sink(Options); FileSystem:= udisks_object_peek_filesystem(BlockObject); if Assigned(FileSystem) then begin MountPoints:= udisks_filesystem_get_mount_points(FileSystem); if Assigned(MountPoints) and Assigned(MountPoints^) then begin Result:= udisks_filesystem_call_unmount_sync(FileSystem, options, nil, @AError); if not Result then PrintError(AError); end; end; Result:= udisks_drive_call_eject_sync(Drive, Options, nil, @AError); if not Result then PrintError(AError); g_variant_unref(Options); end; g_object_unref(PGObject(DriveObject)); end; end; g_object_unref(PGObject(BlockObject)); end; g_object_unref(PGObject(Client)); end; function CheckUDisks({%H-}Parameter : Pointer): PtrInt; var AClient: PGObject; AError: PGError = nil; begin Result:= 0; AClient := udisks_client_new_sync (nil, @AError); HasUDisks2:= Assigned(AClient); if HasUDisks2 then g_object_unref(AClient) else begin PrintError(AError); end; EndThread; end; var libudisks2_so_0: TLibHandle; procedure Initialize; begin libudisks2_so_0:= SafeLoadLibrary('libudisks2.so.0'); if (libudisks2_so_0 <> NilHandle) then try @udisks_block_get_drive:= SafeGetProcAddress(libudisks2_so_0, 'udisks_block_get_drive'); @udisks_block_get_device:= SafeGetProcAddress(libudisks2_so_0, 'udisks_block_get_device'); @udisks_block_get_symlinks:= SafeGetProcAddress(libudisks2_so_0, 'udisks_block_get_symlinks'); @udisks_object_peek_drive:= SafeGetProcAddress(libudisks2_so_0, 'udisks_object_peek_drive'); @udisks_object_peek_block:= SafeGetProcAddress(libudisks2_so_0, 'udisks_object_peek_block'); @udisks_object_peek_filesystem:= SafeGetProcAddress(libudisks2_so_0, 'udisks_object_peek_filesystem'); @udisks_client_get_object_manager:= SafeGetProcAddress(libudisks2_so_0, 'udisks_client_get_object_manager'); @udisks_client_new_sync:= SafeGetProcAddress(libudisks2_so_0, 'udisks_client_new_sync'); @udisks_drive_call_eject_sync:= SafeGetProcAddress(libudisks2_so_0, 'udisks_drive_call_eject_sync'); @udisks_filesystem_get_mount_points:= SafeGetProcAddress(libudisks2_so_0, 'udisks_filesystem_get_mount_points'); @udisks_filesystem_call_unmount_sync:= SafeGetProcAddress(libudisks2_so_0, 'udisks_filesystem_call_unmount_sync'); @udisks_filesystem_call_mount_sync:= SafeGetProcAddress(libudisks2_so_0, 'udisks_filesystem_call_mount_sync'); BeginThread(@CheckUDisks); except on E: Exception do begin UnloadLibrary(libudisks2_so_0); libudisks2_so_0:= NilHandle; Print(E.Message); end; end; end; initialization Initialize; finalization if (libudisks2_so_0 <> NilHandle) then UnloadLibrary(libudisks2_so_0); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/mime/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017133� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/mime/umimeactions.pas��������������������������������������������0000644�0001750�0000144�00000045410�14743153644�022341� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Handles actions associated with MIME types in .desktop files. Based on FreeDesktop.org specifications (http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html) (http://www.freedesktop.org/wiki/Specifications/mime-apps-spec) Copyright (C) 2009-2010 Przemyslaw Nagay (cobines@gmail.com) Copyright (C) 2011-2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uMimeActions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes; type PDesktopFileEntry = ^TDesktopFileEntry; TDesktopFileEntry = record DesktopFilePath: String; MimeType: String; DisplayName: String; Comment: String; ExecWithParams: String; // with %F, %U etc. Exec: String; // % params resolved IconName: String; Categories: TDynamicStringArray; Terminal: Boolean; Hidden: Boolean; end; {en Needs absolute file names. Returns a list of PDesktopFileEntry. } function GetDesktopEntries(FileNames: TStringList): TList; {en Needs absolute file names. Returns a default application command line. } function GetDefaultAppCmd(FileNames: TStringList): String; {en Get desktop entry by desktop file name. } function GetDesktopEntry(const FileName: String): PDesktopFileEntry; {en Adds a new action for given mimetype. @param(MimeType File mime type) @param(DesktopEntry Desktop file name or user command) @param(DefaultAction Set as default action for this mime type) @returns(The function returns @true if successful, @false otherwise) } function AddDesktopEntry(const MimeType, DesktopEntry: String; DefaultAction: Boolean): Boolean; function TranslateAppExecToCmdLine(const entry: PDesktopFileEntry; const fileList: TStringList): String; implementation uses Unix, BaseUnix, DCClassesUtf8, DCStrUtils, uDCUtils, uGlib2, uFileProcs, uIconTheme, uClipboard, DCOSUtils, uKeyFile, uGio, uXdg, uMimeType, uDebug, uMyUnix; type TMimeAppsGroup = (magDefault, magAdded, magRemoved); TMimeAppsGroupSet = set of TMimeAppsGroup; const MIME_APPS: array[TMimeAppsGroup] of String = ( 'Default Applications', 'Added Associations', 'Removed Associations' ); type TMimeAppsList = record Defaults, Added, Removed: TDynamicStringArray; end; function TranslateAppExecToCmdLine(const entry: PDesktopFileEntry; const fileList: TStringList): String; var StartPos: Integer = 1; CurPos: Integer = 1; i: Integer; filesAdded: Boolean = False; begin // The .desktop standard does not recommend using % parameters inside quotes // in the Exec entry (the behaviour is undefined), so all those parameters // can be quoted using any method. Result := ''; while CurPos <= Length(entry^.ExecWithParams) do begin if entry^.ExecWithParams[CurPos] = '%' then begin Result := Result + Copy(entry^.ExecWithParams, StartPos, CurPos - StartPos); Inc(CurPos); if CurPos <= Length(entry^.ExecWithParams) then case entry^.ExecWithParams[CurPos] of { 'U': begin for i := 0 to fileList.Count - 1 do begin if i <> 0 then Result := Result + ' '; Result := Result + QuoteStr(fileScheme + '//' + URIEncode(fileList[i])); end; filesAdded := True; end; 'u': if fileList.Count > 0 then begin Result := Result + QuoteStr(fileScheme + '//' + URIEncode(fileList[0])); filesAdded := True; end; } 'F','U': begin for i := 0 to fileList.Count - 1 do begin if i <> 0 then Result := Result + ' '; Result := Result + QuoteStr(fileList[i]); end; filesAdded := True; end; 'f','u': if fileList.Count > 0 then begin Result := Result + QuoteStr(fileList[0]); filesAdded := True; end; 'N': // deprecated begin for i := 0 to fileList.Count - 1 do begin if i <> 0 then Result := Result + ' '; Result := Result + QuoteStr(fileList[i]); end; filesAdded := True; end; 'n': // deprecated if fileList.Count > 0 then begin Result := Result + QuoteStr(fileList[0]); filesAdded := True; end; 'D': // deprecated begin for i := 0 to fileList.Count - 1 do begin if i <> 0 then Result := Result + ' '; Result := Result + QuoteStr(ExtractFilePath(fileList[i])); end; filesAdded := True; end; 'd': // deprecated if fileList.Count > 0 then begin Result := Result + QuoteStr(ExtractFilePath(fileList[0])); filesAdded := True; end; 'i': if entry^.IconName <> '' then Result := Result + '--icon ' + QuoteStr(entry^.IconName); 'c': Result := Result + QuoteStr(entry^.DisplayName); 'k': Result := Result + QuoteStr(entry^.DesktopFilePath); '%': Result := Result + '%'; end; Inc(CurPos); StartPos := CurPos; end else Inc(CurPos); end; if (StartPos <> CurPos) then Result := Result + Copy(entry^.ExecWithParams, StartPos, CurPos - StartPos); if not filesAdded then begin for i := 0 to fileList.Count - 1 do Result := Result + ' ' + QuoteStr(fileList[i]); end; end; procedure ParseActions(Actions: TDynamicStringArray; var ActionList: TDynamicStringArray); var Action: String; begin for Action in Actions do begin if Length(GetDesktopPath(Action)) > 0 then begin if not Contains(ActionList, Action) then AddString(ActionList, Action); end; end; end; procedure SetFindPath(var MimeAppsPath: TDynamicStringArray); const APPLICATIONS = 'applications/'; var I: Integer; Temp: TDynamicStringArray; begin // $XDG_CONFIG_HOME AddString(MimeAppsPath, IncludeTrailingBackslash(GetUserConfigDir)); // $XDG_CONFIG_DIRS Temp:= GetSystemConfigDirs; for I:= Low(Temp) to High(Temp) do begin AddString(MimeAppsPath, IncludeTrailingBackslash(Temp[I])); end; // $XDG_DATA_HOME AddString(MimeAppsPath, IncludeTrailingBackslash(GetUserDataDir) + APPLICATIONS); // $XDG_DATA_DIRS Temp:= GetSystemDataDirs; for I:= Low(Temp) to High(Temp) do begin AddString(MimeAppsPath, IncludeTrailingBackslash(Temp[I]) + APPLICATIONS); end; end; function ReadMimeAppsList(const MimeType, MimeAppsPath: String; Flags: TMimeAppsGroupSet): TMimeAppsList; const MIME_APPS_LIST = 'mimeapps.list'; var J: LongInt; FileName: String; MimeApps: TKeyFile; Actions: TDynamicStringArray; MimeAppsFile: TDynamicStringArray; begin // $XDG_CURRENT_DESKTOP Actions:= GetCurrentDesktop; // Desktop specific configuration for J:= Low(Actions) to High(Actions) do begin AddString(MimeAppsFile, LowerCase(Actions[J]) + '-' + MIME_APPS_LIST); end; // Common configuration AddString(MimeAppsFile, MIME_APPS_LIST); for J:= Low(MimeAppsFile) to High(MimeAppsFile) do begin FileName:= MimeAppsPath + MimeAppsFile[J]; if mbFileExists(FileName) then try MimeApps:= TKeyFile.Create(FileName); try if magDefault in Flags then begin Actions:= MimeApps.ReadStringList(MIME_APPS[magDefault], MimeType); if (Length(Actions) > 0) then ParseActions(Actions, Result.Defaults); end; if magAdded in Flags then begin Actions:= MimeApps.ReadStringList(MIME_APPS[magAdded], MimeType); if (Length(Actions) > 0) then ParseActions(Actions, Result.Added); end; if magRemoved in Flags then begin Actions:= MimeApps.ReadStringList(MIME_APPS[magRemoved], MimeType); if (Length(Actions) > 0) then ParseActions(Actions, Result.Removed); end; finally FreeAndNil(MimeApps); end; except // Continue end; end; end; procedure ReadMimeInfoCache(const MimeType, Path: String; out Actions: TDynamicStringArray); const MIME_INFO_CACHE = 'mimeinfo.cache'; var MimeCache: TKeyFile; FileName: String; AValue: TDynamicStringArray; begin FileName:= IncludeTrailingBackslash(Path) + MIME_INFO_CACHE; if mbFileExists(FileName) then try MimeCache:= TKeyFile.Create(FileName); try AValue:= MimeCache.ReadStringList('MIME Cache', MimeType); if (Length(AValue) > 0) then ParseActions(AValue, Actions); finally FreeAndNil(MimeCache); end; except // Continue end; end; function GetDesktopEntries(FileNames: TStringList): TList; var Apps: TMimeAppsList; Entry: PDesktopFileEntry; Path, Action, MimeType: String; Actions, MimeTypes: TDynamicStringArray; ResultArray, MimeAppsPath: TDynamicStringArray; procedure AddAction(const Action: String); begin Path := GetDesktopPath(Action); if Length(Path) > 0 then begin Entry := GetDesktopEntry(Path); if Assigned(Entry) then begin Entry^.MimeType := MimeType; // Set Exec as last because it uses other fields of Entry. Entry^.Exec := TranslateAppExecToCmdLine(Entry, Filenames); Result.Add(Entry); end; end; end; begin if FileNames.Count = 0 then Exit(nil); // Get file mime type MimeTypes := GetFileMimeTypes(FileNames[0]); if Length(MimeTypes) = 0 then Exit(nil); Result := TList.Create; SetFindPath(MimeAppsPath); SetLength(ResultArray, 0); for MimeType in MimeTypes do begin for Path in MimeAppsPath do begin // Read actions from mimeapps.list Apps:= ReadMimeAppsList(MimeType, Path, [magDefault, magAdded, magRemoved]); // Add actions from default group for Action in Apps.Defaults do begin if (not Contains(ResultArray, Action)) and (not Contains(Apps.Removed, Action)) then AddString(ResultArray, Action); end; // Add actions from added group for Action in Apps.Added do begin if (not Contains(ResultArray, Action)) and (not Contains(Apps.Defaults, Action)) then AddString(ResultArray, Action); end; // Read actions from mimeinfo.cache ReadMimeInfoCache(MimeType, Path, Actions); for Action in Actions do begin if (not Contains(ResultArray, Action)) and (not Contains(Apps.Removed, Action)) then begin AddString(ResultArray, Action); AddString(Apps.Removed, Action); end; end; end; end; if HasGio then begin Actions:= GioMimeTypeGetActions(MimeTypes[0]); for Action in Actions do begin if not Contains(ResultArray, Action) then AddString(ResultArray, Action); end; end; // Fill result list for Action in ResultArray do begin AddAction(Action); end; end; function GetDefaultAppCmd(FileNames: TStringList): String; var I: Integer; Action: String; Apps: TMimeAppsList; MimeType, Path: String; Entry: PDesktopFileEntry; Actions: TDynamicStringArray; MimeTypes: TDynamicStringArray; MimeAppsPath: TDynamicStringArray; function GetAppExec: String; begin if Length(Action) > 0 then begin Path := GetDesktopPath(Action); if Length(Path) > 0 then begin Entry := GetDesktopEntry(Path); if Assigned(Entry) then begin Entry^.MimeType := MimeType; // Set Exec as last because it uses other fields of Entry. Result := TranslateAppExecToCmdLine(Entry, Filenames); Dispose(Entry); end; end; end; end; begin Result:= EmptyStr; if FileNames.Count = 0 then Exit; // Get file mime type MimeTypes := GetFileMimeTypes(FileNames[0]); if Length(MimeTypes) = 0 then Exit; SetFindPath(MimeAppsPath); for MimeType in MimeTypes do begin // Check defaults for Path in MimeAppsPath do begin // Read actions from mimeapps.list Apps:= ReadMimeAppsList(MimeType, Path, [magDefault]); if Length(Apps.Defaults) > 0 then begin // First Action is default Action:= Apps.Defaults[0]; Exit(GetAppExec); end end; // Check added for Path in MimeAppsPath do begin // Read actions from mimeapps.list Apps:= ReadMimeAppsList(MimeType, Path, [magAdded]); if Length(Apps.Added) > 0 then begin // First Action is default Action:= Apps.Added[0]; Exit(GetAppExec); end; end; // Check mime info cache for Path in MimeAppsPath do begin // Read actions from mimeinfo.cache ReadMimeInfoCache(MimeType, Path, Actions); if Length(Actions) > 0 then begin // Read actions from mimeapps.list Apps:= ReadMimeAppsList(MimeType, Path, [magRemoved]); for I:= Low(Actions) to High(Actions) do begin if not Contains(Apps.Removed, Actions[I]) then begin Action:= Actions[I]; Exit(GetAppExec); end; end; end; end; end; //for end; function GetDesktopEntry(const FileName: String): PDesktopFileEntry; var TryExec: String; DesktopEntryFile: TKeyFile; begin try DesktopEntryFile:= TKeyFile.Create(FileName); if not DesktopEntryFile.SectionExists(DESKTOP_GROUP) then begin DesktopEntryFile.Free; Exit(nil); end; try TryExec:= DesktopEntryFile.ReadString(DESKTOP_GROUP, DESKTOP_KEY_TRY_EXEC, EmptyStr); if Length(TryExec) > 0 then begin case GetPathType(TryExec) of ptAbsolute: if fpAccess(TryExec, X_OK) <> 0 then Exit(nil); ptNone: if not ExecutableInSystemPath(TryExec) then Exit(nil); end; end; New(Result); with Result^, DesktopEntryFile do begin DesktopFilePath := FileName; DisplayName := ReadLocaleString(DESKTOP_GROUP, DESKTOP_KEY_NAME, EmptyStr); Comment := ReadLocaleString(DESKTOP_GROUP, DESKTOP_KEY_COMMENT, EmptyStr); ExecWithParams := ReadString(DESKTOP_GROUP, DESKTOP_KEY_EXEC, EmptyStr); IconName := ReadString(DESKTOP_GROUP, DESKTOP_KEY_ICON, EmptyStr); Categories := ReadStringList(DESKTOP_GROUP, DESKTOP_KEY_CATEGORIES); Terminal := ReadBool(DESKTOP_GROUP, DESKTOP_KEY_TERMINAL, False); Hidden := ReadBool(DESKTOP_GROUP, DESKTOP_KEY_NO_DISPLAY, False); { Some icon names in .desktop files are specified with an extension, even though it is not allowed by the standard unless an absolute path to the icon is supplied. We delete this extension here. } if GetPathType(IconName) = ptNone then IconName := TIconTheme.CutTrailingExtension(IconName); end; finally DesktopEntryFile.Free; end; except on E: Exception do begin Result:= nil; DCDebug('GetDesktopEntry: ', E.Message); end; end; end; function AddDesktopEntry(const MimeType, DesktopEntry: String; DefaultAction: Boolean): Boolean; var Value: String; Args: TStringArray; CustomFile: String; UserDataDir: String; DesktopFile: TIniFileEx; MimeApps: String = '/mimeapps.list'; procedure UpdateDesktop(const Group: String); begin // Read current actions of this mime type Value:= DesktopFile.ReadString(Group, MimeType, EmptyStr); if (Length(Value) > 0) and (not StrEnds(Value, ';')) then Value += ';'; if DefaultAction then begin // Remove chosen action if it exists Value:= StringReplace(Value, CustomFile, EmptyStr, [rfReplaceAll]); // Save chosen action as first DesktopFile.WriteString(Group, MimeType, CustomFile + Value); end else if (Pos(CustomFile, Value) = 0) then begin // Save chosen action as last DesktopFile.WriteString(Group, MimeType, Value + CustomFile); end; end; begin CustomFile:= DesktopEntry; UserDataDir:= GetUserDataDir + '/applications'; if (StrEnds(DesktopEntry, '.desktop') = False) then begin mbForceDirectory(UserDataDir); // Create new desktop entry file for user command SplitCmdLine(CustomFile, Value, Args); CustomFile:= 'dc_' + ExtractFileName(Value) + '_'; CustomFile:= UserDataDir + PathDelim + CustomFile; CustomFile:= GetTempName(CustomFile, 'desktop'); try DesktopFile:= TIniFileEx.Create(CustomFile, fmCreate or fmOpenReadWrite); try DesktopFile.WriteBool(DESKTOP_GROUP, DESKTOP_KEY_NO_DISPLAY, True); DesktopFile.WriteString(DESKTOP_GROUP, DESKTOP_KEY_EXEC, DesktopEntry); DesktopFile.WriteString(DESKTOP_GROUP, DESKTOP_KEY_MIME_TYPE, MimeType); DesktopFile.WriteString(DESKTOP_GROUP, DESKTOP_KEY_NAME, ExtractFileName(Value)); DesktopFile.WriteString(DESKTOP_GROUP, DESKTOP_KEY_TYPE, KEY_FILE_DESKTOP_TYPE_APPLICATION); DesktopFile.UpdateFile; finally DesktopFile.Free; end; fpSystem('update-desktop-database ' + UserDataDir); except Exit(False); end; CustomFile:= ExtractFileName(CustomFile); end; // Save association in MimeApps CustomFile:= CustomFile + ';'; UserDataDir:= GetUserConfigDir; MimeApps:= UserDataDir + MimeApps; try mbForceDirectory(UserDataDir); DesktopFile:= TIniFileEx.Create(MimeApps, fmOpenReadWrite); try // Update added associations UpdateDesktop(MIME_APPS[magAdded]); // Set as default action if needed if DefaultAction then begin // Update default applications UpdateDesktop(MIME_APPS[magDefault]); end; DesktopFile.UpdateFile; if DesktopEnv = DE_KDE then fpSystem('kbuildsycoca5'); finally DesktopFile.Free; end; Result:= True; except on E: Exception do begin Result:= False; DCDebug(E.Message); end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/mime/umimecache.pas����������������������������������������������0000644�0001750�0000144�00000034507�14743153644�021751� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Shared MIME-info Database mime.cache file parser (http://standards.freedesktop.org/shared-mime-info-spec) Copyright (C) 2014-2015 Alexander Koblov (alexx2000@mail.ru) Based on PCManFM v0.5.1 (http://pcmanfm.sourceforge.net) Copyright (C) 2007 Houng Jen Yee (PCMan) <pcman.tw@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. } unit uMimeCache; {$mode objfpc}{$H+} interface uses Classes, SysUtils, BaseUnix, Unix, Math, DCBasicTypes, DCOSUtils; type PMimeCache = ^TMimeCache; TMimeCache = record file_path: String; buffer: PAnsiChar; size: LongWord; n_alias: LongWord; s_alias: PAnsiChar; n_parents: LongWord; parents: PAnsiChar; n_literals: LongWord; literals: PAnsiChar; n_globs: LongWord; globs: PAnsiChar; n_suffix_roots: LongWord; suffix_roots: PAnsiChar; n_magics: LongWord; magic_max_extent: LongWord; magics: PAnsiChar; end; function mime_cache_new(const file_path: String): PMimeCache; procedure mime_cache_free(cache: PMimeCache); function mime_cache_load(cache: PMimeCache; const file_path: String): Boolean; function mime_cache_lookup_literal(cache: PMimeCache; const filename: PChar): PAnsiChar; function mime_cache_lookup_magic(cache: PMimeCache; const data: PByte; len: Integer): PAnsiChar; function mime_cache_lookup_parents(cache: PMimeCache; const mime_type: PChar): TDynamicStringArray; function mime_cache_lookup_glob(cache: PMimeCache; const filename: PChar; glob_len: PInteger): PAnsiChar; function mime_cache_lookup_suffix(cache: PMimeCache; const filename: PChar; const suffix_pos: PPChar): PAnsiChar; implementation uses uGlib2, CTypes; function fnmatch(const pattern: PAnsiChar; const str: PAnsiChar; flags: cint): cint; cdecl; external; const LIB_MAJOR_VERSION = 1; (* FIXME: since mime-cache 1.2, weight is splitted into three parts * only lower 8 bit contains weight, and higher bits are flags and case-sensitivity. * anyway, since we don't support weight at all, it'll be fixed later. * We claimed that we support 1.2 to cheat pcmanfm as a temporary quick dirty fix * for the broken file manager, but this should be correctly done in the future. * Weight and case-sensitivity are not handled now. *) LIB_MAX_MINOR_VERSION = 2; LIB_MIN_MINOR_VERSION = 1; const //* cache header */ MAJOR_VERSION = 0; MINOR_VERSION = 2; ALIAS_LIST = 4; PARENT_LIST = 8; LITERAL_LIST = 12; SUFFIX_TREE = 16; GLOB_LIST = 20; MAGIC_LIST = 24; NAMESPACE_LIST = 28; function VAL16(buffer: PAnsiChar; idx: Integer): Word; inline; begin Result := BEtoN(PWord(buffer + idx)^); end; function VAL32(buffer: PAnsiChar; idx: Integer): LongWord; inline; begin Result := BEtoN(PLongWord(buffer + idx)^); end; function mime_cache_new(const file_path: String): PMimeCache; begin New(Result); FillChar(Result^, SizeOf(TMimeCache), 0); if (Length(file_path) > 0) then mime_cache_load(Result, file_path); end; procedure mime_cache_unload(cache: PMimeCache; Clear: Boolean); begin if Assigned(cache^.buffer) then begin {$IF DEFINED(HAVE_MMAP)} fpmunmap(cache^.buffer, cache^.size); {$ELSE} FreeMem(cache^.buffer); {$ENDIF} end; if (Clear) then FillChar(cache^, sizeof(TMimeCache), 0); end; procedure mime_cache_free(cache: PMimeCache); begin mime_cache_unload(cache, False); Dispose(cache); end; function mime_cache_load(cache: PMimeCache; const file_path: String): Boolean; var offset: LongWord; fd: Integer = -1; majv, minv: LongWord; statbuf: BaseUnix.Stat; buffer: PAnsiChar = nil; begin //* Unload old cache first if needed */ mime_cache_unload(cache, True); //* Store the file path */ cache^.file_path := file_path; //* Open the file and map it into memory */ fd := mbFileOpen(file_path, fmOpenRead); if (fd < 0) then Exit(False); if (fpFStat(fd, statbuf) < 0) then begin FileClose(fd); Exit(False); end; {$IF DEFINED(HAVE_MMAP)} buffer := fpmmap(nil, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); {$ELSE} buffer := GetMem(statbuf.st_size); if Assigned(buffer) then fpRead(fd, buffer^, statbuf.st_size) else buffer := Pointer(-1); {$ENDIF} FileClose(fd); if (buffer = Pointer(-1)) then Exit(False); majv := VAL16(buffer, MAJOR_VERSION); minv := VAL16(buffer, MINOR_VERSION); //* Check version */ if (majv > LIB_MAJOR_VERSION) or (minv > LIB_MAX_MINOR_VERSION) or (minv < LIB_MIN_MINOR_VERSION) then begin {$IF DEFINED(HAVE_MMAP)} fpmunmap(buffer, statbuf.st_size); {$ELSE} FreeMem(buffer); {$ENDIF} Exit(False); end; cache^.buffer := buffer; cache^.size := statbuf.st_size; offset := VAL32(buffer, ALIAS_LIST); cache^.s_alias := buffer + offset + 4; cache^.n_alias := VAL32(buffer, offset); offset := VAL32(buffer, PARENT_LIST); cache^.parents := buffer + offset + 4; cache^.n_parents := VAL32(buffer, offset); offset := VAL32(buffer, LITERAL_LIST); cache^.literals := buffer + offset + 4; cache^.n_literals := VAL32(buffer, offset); offset := VAL32(buffer, GLOB_LIST); cache^.globs := buffer + offset + 4; cache^.n_globs := VAL32(buffer, offset); offset := VAL32(buffer, SUFFIX_TREE); cache^.suffix_roots := buffer + VAL32(buffer + offset, 4); cache^.n_suffix_roots := VAL32(buffer, offset); offset := VAL32(buffer, MAGIC_LIST); cache^.n_magics := VAL32(buffer, offset); cache^.magic_max_extent := VAL32(buffer + offset, 4); cache^.magics := buffer + VAL32(buffer + offset, 8); Result := True; end; function magic_rule_match(const buf: PAnsiChar; rule: PAnsiChar; const data: PByte; len: Integer): Boolean; var i: Integer; value, mask: PByte; match: Boolean = False; offset, range: LongWord; val_off, mask_off: LongWord; max_offset, val_len: LongWord; n_children, first_child_off: LongWord; begin offset := VAL32(rule, 0); range := VAL32(rule, 4); max_offset := offset + range; val_len := VAL32(rule, 12); while (offset < max_offset) and ((offset + val_len) <= len) do begin val_off := VAL32(rule, 16); mask_off := VAL32(rule, 20); value := PByte(buf + val_off); //* FIXME: word_size and byte order are not supported! */ if (mask_off > 0) then //* compare with mask applied */ begin mask := PByte(buf + mask_off); for i := 0 to val_len - 1 do begin if ((data[offset + i] and mask[i]) <> value[i]) then break; end; if (i >= val_len) then match := True; end else //* direct comparison */ begin if (CompareMem(value, data + offset, val_len)) then match := True; end; if (match) then begin n_children := VAL32(rule, 24); if (n_children > 0) then begin i := 0; first_child_off := VAL32(rule, 28); rule := buf + first_child_off; while (i < n_children) do begin if (magic_rule_match(buf, rule, data, len)) then Exit(True); Inc(i); rule += 32; end; end else Exit(True); end; Inc(offset); end; Result := False; end; function magic_match(const buf: PAnsiChar; const magic: PAnsiChar; const data: PByte; len: Integer): Boolean; var i: Integer = 0; rule: PAnsiChar; n_rules, rules_off: LongWord; begin n_rules := VAL32(magic, 8); rules_off := VAL32(magic, 12); rule := buf + rules_off; while (i < n_rules) do begin if (magic_rule_match(buf, rule, data, len)) then Exit(True); Inc(i); rule += 32; end; Result := False; end; function mime_cache_lookup_magic(cache: PMimeCache; const data: PByte; len: Integer): PAnsiChar; var i: Integer = 0; magic: PAnsiChar; begin magic := cache^.magics; if (data = nil) or (0 = len) or (magic = nil) then Exit(nil); while (i < cache^.n_magics) do begin if (magic_match(cache^.buffer, magic, data, len)) then begin Exit(cache^.buffer + VAL32(magic, 4)); end; Inc(i); magic += 16; end; Result := nil; end; (* Reverse suffix tree is used since mime.cache 1.1 (shared mime info 0.4) * Returns the address of the found "node", not mime-type. * FIXME: 1. Should be optimized with binary search * 2. Should consider weight of suffix nodes *) function lookup_reverse_suffix_nodes(const buf: PAnsiChar; const nodes: PAnsiChar; n: LongWord; const name: Pgchar; const suffix: Pgchar; const suffix_pos: PPChar): PAnsiChar; var i: Integer; ch: LongWord; uchar: gunichar; node: PAnsiChar; ret: PAnsiChar = nil; cur_suffix_pos: Pgchar; _suffix_pos: Pgchar = nil; leaf_node: PAnsiChar = nil; n_children, first_child_off: LongWord; begin cur_suffix_pos := suffix + 1; if Assigned(suffix) then uchar := g_unichar_tolower(g_utf8_get_char(suffix)) else uchar := 0; //* g_debug("%s: suffix= '%s'", name, suffix); */ for i := 0 to n - 1 do begin node := nodes + i * 12; ch := VAL32(node, 0); _suffix_pos := suffix; if (ch > 0) then begin if (ch = uchar) then begin n_children := VAL32(node, 4); first_child_off := VAL32(node, 8); leaf_node := lookup_reverse_suffix_nodes(buf, buf + first_child_off, n_children, name, g_utf8_find_prev_char(name, suffix), @_suffix_pos); if Assigned(leaf_node) and (_suffix_pos < cur_suffix_pos) then begin ret := leaf_node; cur_suffix_pos := _suffix_pos; end; end; end else //* ch == 0 */ begin //* guint32 weight = VAL32(node, 8); */ //* suffix is found in the tree! */ if (suffix < cur_suffix_pos) then begin ret := node; cur_suffix_pos := suffix; end; end; end; suffix_pos^ := cur_suffix_pos; Result := ret; end; function mime_cache_lookup_suffix(cache: PMimeCache; const filename: PChar; const suffix_pos: PPChar): PAnsiChar; var suffix: Pgchar; root: PAnsiChar; n, fn_len: Integer; ret: PAnsiChar = nil; leaf_node: PAnsiChar; mime_type: PAnsiChar = nil; _suffix_pos: PChar = PAnsiChar(-1); begin root := cache^.suffix_roots; n := cache^.n_suffix_roots; if (filename = nil) or (filename^ = #0) or (0 = n) then Exit(nil); fn_len := strlen(filename); suffix := g_utf8_find_prev_char(filename, filename + fn_len); leaf_node := lookup_reverse_suffix_nodes(cache^.buffer, root, n, filename, suffix, @_suffix_pos); if (leaf_node <> nil) then begin mime_type := cache^.buffer + VAL32(leaf_node, 4); //* g_debug( "found: %s", mime_type ); */ suffix_pos^ := _suffix_pos; ret := mime_type; end; Result := ret; end; function lookup_str_in_entries(cache: PMimeCache; const entries: PAnsiChar; n: Integer; const str: Pgchar): PAnsiChar; var str2: Pgchar; entry: PAnsiChar; lower: Integer = 0; comp, upper, middle: Integer; begin upper := n; middle := upper div 2; if (Assigned(entries) and Assigned(str) and (str^ <> #0)) then begin //* binary search */ while (upper >= lower) do begin entry := entries + middle * 8; str2 := Pgchar(cache^.buffer + VAL32(entry, 0)); comp := strcomp(str, str2); if (comp < 0) then upper := middle - 1 else if (comp > 0) then lower := middle + 1 else //* comp == 0 */ Exit(cache^.buffer + VAL32(entry, 4)); middle := (upper + lower) div 2; end; end; Result := nil; end; function mime_cache_lookup_alias(cache: PMimeCache; const mime_type: PChar): PAnsiChar; begin Result := lookup_str_in_entries(cache, cache^.s_alias, cache^.n_alias, mime_type); end; function mime_cache_lookup_literal(cache: PMimeCache; const filename: PChar): PAnsiChar; var str2: Pgchar; lower: Integer = 0; entries, entry: PAnsiChar; comp, upper, middle: Integer; begin (* FIXME: weight is used in literal lookup after mime.cache v1.1. * However, it's poorly documented. So I've no idea how to implement this. *) entries := cache^.literals; upper := cache^.n_literals; middle := upper div 2; if (Assigned(entries) and Assigned(filename) and (filename^ <> #0)) then begin //* binary search */ while (upper >= lower) do begin //* The entry size is different in v 1.1 */ entry := entries + middle * 12; str2 := Pgchar(cache^.buffer + VAL32(entry, 0)); comp := strcomp(filename, str2); if (comp < 0) then upper := middle - 1 else if (comp > 0) then lower := middle + 1 else //* comp == 0 */ Exit(cache^.buffer + VAL32(entry, 4)); middle := (upper + lower) div 2; end; end; Result := nil; end; function mime_cache_lookup_glob(cache: PMimeCache; const filename: PChar; glob_len: PInteger): PAnsiChar; var glob: PChar; entry: PAnsiChar; i, _glob_len: Integer; max_glob_len: Integer = 0; begin Result := nil; entry := cache^.globs; for i := 0 to cache^.n_globs - 1 do begin glob := PChar(cache^.buffer + VAL32(entry, 0)); _glob_len := strlen(glob); if (fnmatch(glob, filename, 0) = 0) and (_glob_len > max_glob_len) then begin max_glob_len := _glob_len; Result := (cache^.buffer + VAL32(entry, 4)); end; entry += 12; end; glob_len^ := max_glob_len; end; function mime_cache_lookup_parents(cache: PMimeCache; const mime_type: PChar): TDynamicStringArray; var parent: PChar; n, i: LongWord; parents: PAnsiChar; parent_off: LongWord; begin parents := lookup_str_in_entries(cache, cache^.parents, cache^.n_parents, mime_type); if (parents = nil) then Exit(nil); n := VAL32(parents, 0); parents += 4; SetLength(Result, n); for i := 0 to n - 1 do begin parent_off := VAL32(parents, i * 4); parent := PChar(cache^.buffer + parent_off); Result[i] := parent; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/mime/umimetype.pas�����������������������������������������������0000644�0001750�0000144�00000022721�14743153644�021662� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Shared MIME-info Database - mime type guess Copyright (C) 2014-2017 Alexander Koblov (alexx2000@mail.ru) Based on PCManFM v0.5.1 (http://pcmanfm.sourceforge.net) Copyright (C) 2007 Houng Jen Yee (PCMan) <pcman.tw@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. } unit uMimeType; {$mode delphi} interface uses DCBasicTypes; {en Get file mime type. } function GetFileMimeType(const FileName: String): String; {en Get file mime type with parents. } function GetFileMimeTypes(const FileName: String): TDynamicStringArray; implementation uses Classes, SysUtils, Unix, BaseUnix, Math, LazFileUtils, DCStrUtils, DCOSUtils, uMimeCache, uXdg, uGio, uGlib2, uGio2; const xdg_mime_type_plain_text = 'text/plain'; xdg_mime_type_directory = 'inode/directory'; xdg_mime_type_unknown = 'application/octet-stream'; xdg_mime_type_executable = 'application/x-executable'; var caches: TFPList = nil; mime_magic_buf: PByte; mime_cache_max_extent: LongWord = 0; CriticalSection: TRTLCriticalSection; (* load all mime.cache files on the system, * including /usr/share/mime/mime.cache, * /usr/local/share/mime/mime.cache, * and $HOME/.local/share/mime/mime.cache. *) procedure mime_cache_load_all(); const MIME_CACHE = 'mime/mime.cache'; var I: Integer; Cache: PMimeCache; FileName: String; Path: TDynamicStringArray; begin caches := TFPList.Create; Path := GetSystemDataDirs; AddString(Path, GetUserDataDir); for I := Low(Path) to High(Path) do begin FileName := IncludeTrailingBackslash(Path[I]) + MIME_CACHE; if mbFileAccess(FileName, fmOpenRead or fmShareDenyNone) then begin Cache := mime_cache_new(FileName); caches.Add(Cache); if Cache^.magic_max_extent > mime_cache_max_extent then mime_cache_max_extent := Cache^.magic_max_extent; end; end; mime_magic_buf := GetMem(mime_cache_max_extent); end; //* free all mime.cache files on the system */ procedure mime_cache_free_all(); var I: Integer; begin for I := 0 to caches.Count - 1 do begin mime_cache_free(PMimeCache(caches[I])); end; FreeAndNil(caches); FreeMem(mime_magic_buf); end; (* * Get mime-type of the specified file (quick, but less accurate): * Mime-type of the file is determined by cheking the filename only. * If statbuf != NULL, it will be used to determine if the file is a directory. *) function mime_type_get_by_filename(const filename: PAnsiChar): PAnsiChar; var i: cint; cache: PMimeCache; glob_len: cint = 0; max_glob_len: cint = 0; suffix_pos: PByte = nil; mime_type, type_suffix: PAnsiChar; prev_suffix_pos: PByte = PByte(-1); begin //* literal matching */ for i := 0 to caches.Count - 1 do begin cache := PMimeCache(caches[i]); mime_type := mime_cache_lookup_literal(cache, filename); if Assigned(mime_type) then Exit(PAnsiChar(mime_type)); end; //* suffix matching */ for i := 0 to caches.Count - 1 do begin cache := PMimeCache(caches[i]); type_suffix := mime_cache_lookup_suffix(cache, filename, @suffix_pos); if (type_suffix <> nil) and (suffix_pos < prev_suffix_pos) then begin mime_type := type_suffix; prev_suffix_pos := suffix_pos; end; end; if Assigned(mime_type) then Exit(PAnsiChar(mime_type)); //* glob matching */ for i := 0 to caches.Count - 1 do begin cache := PMimeCache(caches[i]); type_suffix := mime_cache_lookup_glob(cache, filename, @glob_len); //* according to the mime.cache 1.0 spec, we should use the longest glob matched. */ if (type_suffix <> nil) and (glob_len > max_glob_len) then begin mime_type := type_suffix; max_glob_len := glob_len; end; end; if Assigned(mime_type) then Exit(PAnsiChar(mime_type)); Result := XDG_MIME_TYPE_UNKNOWN; end; (* * Get mime-type info of the specified file (slow, but more accurate): * To determine the mime-type of the file, mime_type_get_by_filename() is * tried first. If the mime-type couldn't be determined, the content of * the file will be checked, which is much more time-consuming. * If statbuf is not NULL, it will be used to determine if the file is a directory, * or if the file is an executable file; otherwise, the function will call stat() * to gather this info itself. So if you already have stat info of the file, * pass it to the function to prevent checking the file stat again. * If you have basename of the file, pass it to the function can improve the * efifciency, too. Otherwise, the function will try to get the basename of * the specified file again. *) function mime_type_get_by_file(const filepath: String; max_extent: cint): String; var data: PByte; i, len: cint; fd: cint = -1; mime_type: PAnsiChar; FileName: String; begin FileName := ExtractFileName(FilePath); mime_type := mime_type_get_by_filename(PAnsiChar(FileName)); if (strcomp(mime_type, XDG_MIME_TYPE_UNKNOWN) <> 0) then Exit(mime_type); if (max_extent > 0) then begin //* Open the file and map it into memory */ fd := mbFileOpen(filepath, fmOpenRead or fmShareDenyNone); if (fd <> -1) then begin {$IF DEFINED(HAVE_MMAP)} data := fpmmap(nil, mime_cache_max_extent, PROT_READ, MAP_SHARED, fd, 0); {$ELSE} (* * FIXME: Can g_alloca() be used here? It's very fast, but is it safe? * Actually, we can allocate a block of memory with the size of mime_cache_max_extent, * then we don't need to do dynamic allocation/free every time, but multi-threading * will be a nightmare, so... *) //* try to lock the common buffer */ if (TryEnterCriticalSection(CriticalSection) <> 0) then data := mime_magic_buf else //* the buffer is in use, allocate new one */ data := GetMem(max_extent); len := fpRead(fd, data^, max_extent); if (len = -1) then begin if (data = mime_magic_buf) then LeaveCriticalSection(CriticalSection) else FreeMem(data); data := Pointer(-1); end; {$ENDIF} if (data <> Pointer(-1)) then begin for i := 0 to caches.Count - 1 do begin mime_type := mime_cache_lookup_magic(PMimeCache(caches[i]), data, len); if (mime_type <> nil) then Break; end; //* Check for executable file */ if (mime_type = nil) and g_file_test(PAnsiChar(filepath), G_FILE_TEST_IS_EXECUTABLE) then mime_type := XDG_MIME_TYPE_EXECUTABLE; //* fallback: check for plain text */ if (mime_type = nil) then begin if FileIsText(filepath) then mime_type := XDG_MIME_TYPE_PLAIN_TEXT; end; {$IF DEFINED(HAVE_MMAP)} fpmunmap(data, mime_cache_max_extent); {$ELSE} if (data = mime_magic_buf) then LeaveCriticalSection(CriticalSection) //* unlock the common buffer */ else //* we use our own buffer */ FreeMem(data); {$ENDIF} end; FileClose(fd); end; end else begin //* empty file can be viewed as text file */ mime_type := XDG_MIME_TYPE_PLAIN_TEXT; end; if Assigned(mime_type) then Result := StrPas(mime_type) else Result := XDG_MIME_TYPE_UNKNOWN; end; (* * Get all parent type of this mime_type *) procedure mime_type_get_parents(const MimeType: String; var Parents: TDynamicStringArray); var I, J: Integer; Temp: TDynamicStringArray; begin for I := 0 to caches.Count - 1 do begin Temp := mime_cache_lookup_parents(PMimeCache(caches[I]), PAnsiChar(MimeType)); for J := Low(Temp) to High(Temp) do begin AddString(Parents, Temp[J]); end; end; end; function GetFileMimeType(const FileName: String): String; var Stat: TStat; MaxExtent: LongWord; begin if fpStat(FileName, Stat) < 0 then Exit(EmptyStr); if fpS_ISREG(Stat.st_mode) then begin MaxExtent:= Min(mime_cache_max_extent, Stat.st_size); if HasGio then Result:= GioGetMimeType(FileName, MaxExtent) else begin Result := mime_type_get_by_file(FileName, MaxExtent); end; end else if fpS_ISDIR(Stat.st_mode) then Result:= XDG_MIME_TYPE_DIRECTORY else if fpS_ISCHR(Stat.st_mode) then Result:= 'inode/chardevice' else if fpS_ISBLK(Stat.st_mode) then Result:= 'inode/blockdevice' else if fpS_ISFIFO(Stat.st_mode) then Result:= 'inode/fifo' else if fpS_ISLNK(Stat.st_mode) then Result:= 'inode/symlink' else if fpS_ISSOCK(Stat.st_mode) then Result:= 'inode/socket'; end; function GetFileMimeTypes(const FileName: String): TDynamicStringArray; var MimeType: String; begin MimeType:= GetFileMimeType(FileName); AddString(Result, MimeType); mime_type_get_parents(MimeType, Result); end; initialization mime_cache_load_all(); InitCriticalSection(CriticalSection); finalization mime_cache_free_all(); DoneCriticalSection(CriticalSection); end. �����������������������������������������������doublecmd-1.1.22/src/platform/unix/qt5/�������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016715� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/qt5/interfaces.pas�����������������������������������������������0000644�0001750�0000144�00000000764�14743153644�021554� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Interfaces; {$mode objfpc}{$H+} interface uses InterfaceBase, qtint; type { TQtWidgetSetEx } TQtWidgetSetEx = Class(TQtWidgetSet) public procedure AppRun(const ALoop: TApplicationMainLoop); override; end; implementation uses Forms; { TQtWidgetSetEx } procedure TQtWidgetSetEx.AppRun(const ALoop: TApplicationMainLoop); begin // Use LCL loop if Assigned(ALoop) then ALoop; end; initialization CreateWidgetset(TQtWidgetSetEx); finalization FreeWidgetset; end. ������������doublecmd-1.1.22/src/platform/unix/sdl2.pas���������������������������������������������������������0000644�0001750�0000144�00000011437�14743153644�017563� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit sdl2; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils, CTypes; const SDL_INIT_AUDIO = $00000010; SDL_AUDIO_ALLOW_FREQUENCY_CHANGE = $00000001; SDL_AUDIO_ALLOW_FORMAT_CHANGE = $00000002; SDL_AUDIO_ALLOW_CHANNELS_CHANGE = $00000004; SDL_AUDIO_ALLOW_SAMPLES_CHANGE = $00000008; SDL_AUDIO_ALLOW_ANY_CHANGE = (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE or SDL_AUDIO_ALLOW_FORMAT_CHANGE or SDL_AUDIO_ALLOW_CHANNELS_CHANGE or SDL_AUDIO_ALLOW_SAMPLES_CHANGE); type SDL_AudioFormat = type UInt16; SDL_AudioDeviceID = type UInt32; TSDL_RWops = record end; PSDL_RWops = ^TSDL_RWops; SDL_AudioCallback = procedure(userdata: Pointer; stream: PByte; len: cint); cdecl; SDL_AudioSpec = record freq: cint; format: SDL_AudioFormat; channels: UInt8; silence: UInt8; samples: UInt16; padding: UInt16; size: UInt32; callback: SDL_AudioCallback; userdata: Pointer; end; PSDL_AudioSpec = ^SDL_AudioSpec; TAudioData = record wavStart: PByte; wavLength: UInt32; wavSpec: SDL_AudioSpec; end; PAudioData = ^TAudioData; var SDL_InitSubSystem: function(flags: UInt32): cint; cdecl; SDL_Delay: procedure(ms: UInt32); cdecl; SDL_GetError: function(): PAnsiChar; cdecl; SDL_RWFromFile: function(const file_name: PAnsiChar; const mode: PAnsiChar): PSDL_RWops; cdecl; SDL_LoadWAV_RW: function(src: PSDL_RWops; freesrc: cint; spec: PSDL_AudioSpec; audio_buf: PPByte; audio_len: PUInt32): PSDL_AudioSpec; cdecl; SDL_FreeWAV: procedure(audio_buf: PByte); cdecl; SDL_QueueAudio: function(dev: SDL_AudioDeviceID; const data: Pointer; len: UInt32): cint; cdecl; SDL_GetQueuedAudioSize: function(dev: SDL_AudioDeviceID): UInt32; cdecl; SDL_OpenAudioDevice: function(const device: PAnsiChar; iscapture: cint; const desired: PSDL_AudioSpec; obtained: PSDL_AudioSpec; allowed_changes: cint): SDL_AudioDeviceID; cdecl; SDL_PauseAudioDevice: procedure(dev: SDL_AudioDeviceID; pause_on: cint); cdecl; SDL_CloseAudioDevice: procedure(dev: SDL_AudioDeviceID); cdecl; function SDL_Initialize: Boolean; function SDL_Play(const FileName: String): Boolean; implementation uses DCOSUtils, LazLogger; function Play(Parameter: Pointer): PtrInt; var audioDevice: SDL_AudioDeviceID; AudioData: PAudioData absolute parameter; begin Result:= 0; try audioDevice:= SDL_OpenAudioDevice(nil, 0, @AudioData^.wavSpec, nil, SDL_AUDIO_ALLOW_ANY_CHANGE); if audioDevice = 0 then begin DebugLn('SDL_OpenAudioDevice: ', SDL_GetError()); Exit(-1); end; SDL_QueueAudio(audioDevice, AudioData^.wavStart, AudioData^.wavLength); SDL_PauseAudioDevice(audioDevice, 0); while SDL_GetQueuedAudioSize(audioDevice) > 0 do begin SDL_Delay(100); end; SDL_CloseAudioDevice(audioDevice); finally SDL_FreeWAV(AudioData^.wavStart); Dispose(AudioData); end; end; function SDL_Play(const FileName: String): Boolean; var RWops: PSDL_RWops; AudioData: PAudioData; begin RWops:= SDL_RWFromFile(PAnsiChar(FileName), 'rb'); if (RWops = nil) then begin DebugLn('SDL_RWFromFile: ', SDL_GetError()); Exit(False); end; New(AudioData); with AudioData^ do begin if (SDL_LoadWAV_RW(RWops, 1, @wavSpec, @wavStart, @wavLength) = nil) then begin DebugLn('SDL_LoadWAV_RW: ', SDL_GetError()); Dispose(AudioData); Exit(False); end; end; Result:= BeginThread(@Play, AudioData) > 0; end; const sdllib= 'libSDL2-2.0.so.0'; var libsdl: TLibHandle; function SDL_Initialize: Boolean; var AMsg: String; begin libsdl:= SafeLoadLibrary(sdllib); Result:= (libsdl <> NilHandle); if Result then try SDL_InitSubSystem:= SafeGetProcAddress(libsdl, 'SDL_InitSubSystem'); SDL_Delay:= SafeGetProcAddress(libsdl, 'SDL_Delay'); SDL_GetError:= SafeGetProcAddress(libsdl, 'SDL_GetError'); SDL_RWFromFile:= SafeGetProcAddress(libsdl, 'SDL_RWFromFile'); SDL_LoadWAV_RW:= SafeGetProcAddress(libsdl, 'SDL_LoadWAV_RW'); SDL_FreeWAV:= SafeGetProcAddress(libsdl, 'SDL_FreeWAV'); SDL_QueueAudio:= SafeGetProcAddress(libsdl, 'SDL_QueueAudio'); SDL_GetQueuedAudioSize:= SafeGetProcAddress(libsdl, 'SDL_GetQueuedAudioSize'); SDL_OpenAudioDevice:= SafeGetProcAddress(libsdl, 'SDL_OpenAudioDevice'); SDL_PauseAudioDevice:= SafeGetProcAddress(libsdl, 'SDL_PauseAudioDevice'); SDL_CloseAudioDevice:= SafeGetProcAddress(libsdl, 'SDL_CloseAudioDevice'); Result:= SDL_InitSubSystem(SDL_INIT_AUDIO) = 0; if not Result then begin AMsg:= SDL_GetError(); raise Exception.Create(AMsg); end; except on E: Exception do begin Result:= False; DebugLn(E.Message); FreeLibrary(libsdl); end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uaudiothumb.pas��������������������������������������������������0000644�0001750�0000144�00000007325�14743153644�021246� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uAudioThumb; {$mode objfpc}{$H+} interface uses Classes, SysUtils; implementation uses Graphics, Types, DCClassesUtf8, uThumbnails, uMasks, uGraphics; var MaskList: TMaskList = nil; type TFrameHeader = packed record ID: array [1..4] of AnsiChar; Size: Integer; Flags: UInt16; end; TTagHeader = packed record ID: array [1..3] of AnsiChar; Version: Byte; Revision: Byte; Flags: Byte; Size: array [1..4] of Byte; end; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var AInc: Byte; FSize: Int64; AData: UInt16; Index: Integer; AChar: AnsiChar; ALength: Integer; ATag: TTagHeader; AFile: TFileStreamEx; AFrame: TFrameHeader; ABitmap: TRasterImage; AStream: TMemoryStream; AMimeType: array[Byte] of AnsiChar; begin Result:= nil; if MaskList.Matches(aFileName) then begin try AFile:= TFileStreamEx.Create(aFileName, fmOpenRead or fmShareDenyNone); try AFile.ReadBuffer(ATag, SizeOf(TTagHeader)); if (ATag.ID = 'ID3') and (ATag.Version >= 3) then begin FSize := (ATag.Size[1] shl 21) or (ATag.Size[2] shl 14) + (ATag.Size[3] shl 7 ) or (ATag.Size[4]) + 10; if ATag.Flags and $10 = $10 then Inc(FSize, 10); while (AFile.Position < FSize) do begin AFile.ReadBuffer(AFrame, SizeOf(TFrameHeader)); if not (AFrame.ID[1] in ['A'..'Z']) then Break; ALength:= BEtoN(AFrame.Size); if (AFrame.ID = 'APIC') then begin AStream:= TMemoryStream.Create; try AStream.SetSize(ALength); AFile.ReadBuffer(AStream.Memory^, ALength); // Text encoding case AStream.ReadByte of $01, $02: AInc:= 2; else AInc:= 1; end; // MIME type Index:= 0; repeat AChar:= Chr(AStream.ReadByte); AMimeType[Index]:= AChar; Inc(Index); until not ((AChar > #0) and (Index < High(Byte))); // Picture type AStream.ReadByte; // Description AData:= 0; repeat AStream.ReadBuffer(AData, AInc); until (AData = 0); // Picture data if (StrPos(AMimeType, 'image/') = nil) then begin AMimeType := 'image/' + AMimeType; end; if AMimeType = 'image/png' then begin ABitmap:= TPortableNetworkGraphic.Create; end else if AMimeType = 'image/jpeg' then begin ABitmap:= TJPEGImage.Create; end else begin ABitmap:= nil; end; if Assigned(ABitmap) then try ABitmap.LoadFromStream(AStream, ALength - AStream.Position); Result:= TBitmap.Create; BitmapAssign(Result, ABitmap); finally ABitmap.Free; end; finally AStream.Free; end; Break; end; AFile.Seek(ALength, soCurrent); end; end; finally AFile.Free; end; except // Ignore end; end; end; procedure Initialize; begin MaskList:= TMaskList.Create('*.mp3'); // Register thumbnail provider TThumbnailManager.RegisterProvider(@GetThumbnail); end; initialization Initialize; finalization MaskList.Free; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/udcreadwebp.pas��������������������������������������������������0000644�0001750�0000144�00000010572�14743153644�021203� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- WebP reader implementation (via libwebp library) Copyright (C) 2017-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uDCReadWebP; {$mode delphi} interface uses Classes, SysUtils, Graphics, FPImage; type { TDCReaderWebP } TDCReaderWebP = class (TFPCustomImageReader) protected function InternalCheck(Stream: TStream): Boolean; override; procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override; end; { TWeppyImage } TWeppyImage = class(TFPImageBitmap) protected class function GetReaderClass: TFPCustomImageReaderClass; override; class function GetSharedImageClass: TSharedRasterImageClass; override; public class function GetFileExtensions: String; override; end; implementation uses InitC, DynLibs, IntfGraphics, GraphType, CTypes, DCOSUtils; procedure CFree(P: Pointer); cdecl; external clib name 'free'; var WebPFree: procedure(ptr: pointer); cdecl; WebPGetInfo: function(const data: pcuint8; data_size: csize_t; width: pcint; height: pcint): cint; cdecl; WebPDecodeRGBA: function(const data: pcuint8; data_size: csize_t; width: pcint; height: pcint): pcuint8; cdecl; type PRGBA = ^TRGBA; TRGBA = packed record Red, Green, Blue, Alpha: Byte; end; { TDCReaderWebP } function TDCReaderWebP.InternalCheck(Stream: TStream): Boolean; var MemoryStream: TMemoryStream; begin Result:= Stream is TMemoryStream; if Result then begin MemoryStream:= TMemoryStream(Stream); Result:= WebPGetInfo(MemoryStream.Memory, MemoryStream.Size, nil, nil) <> 0; end; end; procedure TDCReaderWebP.InternalRead(Stream: TStream; Img: TFPCustomImage); var Data: Pointer; ImageData: PRGBA; AWidth, AHeight: cint; Desc: TRawImageDescription; MemoryStream: TMemoryStream; begin MemoryStream:= Stream as TMemoryStream; Data:= WebPDecodeRGBA(MemoryStream.Memory, MemoryStream.Size, @AWidth, @AHeight); if Assigned(Data) then begin ImageData:= PRGBA(Data); // Set output image size Img.SetSize(AWidth, AHeight); // Initialize image description Desc.Init_BPP32_R8G8B8A8_BIO_TTB(Img.Width, Img.Height); TLazIntfImage(Img).DataDescription:= Desc; // Copy image data Move(ImageData^, TLazIntfImage(Img).PixelData^, Img.Width * Img.Height * SizeOf(TRGBA)); if Assigned(WebPFree) then WebPFree(Data) else begin CFree(Data); end; end; end; { TWeppyImage } class function TWeppyImage.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TDCReaderWebP; end; class function TWeppyImage.GetSharedImageClass: TSharedRasterImageClass; begin Result:= TSharedBitmap; end; class function TWeppyImage.GetFileExtensions: String; begin Result:= 'webp'; end; const webplib = 'libwebp.so.%d'; var libwebp: TLibHandle; procedure Initialize; var Version: Integer; LibraryName: AnsiString; begin for Version:= 7 downto 5 do begin LibraryName:= Format(webplib, [Version]); libwebp:= LoadLibrary(LibraryName); if (libwebp <> NilHandle) then Break; end; if (libwebp <> NilHandle) then try @WebPFree:= GetProcAddress(libwebp, 'WebPFree'); @WebPGetInfo:= SafeGetProcAddress(libwebp, 'WebPGetInfo'); @WebPDecodeRGBA:= SafeGetProcAddress(libwebp, 'WebPDecodeRGBA'); // Register image handler and format ImageHandlers.RegisterImageReader('Weppy Image', 'WEBP', TDCReaderWebP); TPicture.RegisterFileFormat('webp', 'Weppy Image', TWeppyImage); except // Skip end; end; initialization Initialize; finalization if (libwebp <> NilHandle) then FreeLibrary(libwebp); end. ��������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/udefaultterminal.pas���������������������������������������������0000644�0001750�0000144�00000012555�14743153644�022266� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Auto-detect default terminal emulator Copyright (C) 2021 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } unit uDefaultTerminal; {$mode objfpc}{$H+} interface uses Classes, SysUtils; implementation {$IF DEFINED(DARWIN)} uses uOSUtils, uMyDarwin; procedure Initialize; var Cmd: String; begin Cmd:= getMacOSDefaultTerminal; if Length(Cmd) > 0 then begin RunTermCmd:= Cmd; end; end; {$ELSE} uses DCOSUtils, DCClassesUtf8, uMyUnix, uGio, uOSUtils, uSysFolders; const TERM_KDE = 'konsole'; TERM_LXQT = 'qterminal'; TERM_LXDE = 'lxterminal'; TERM_MATE = 'mate-terminal'; TERM_XFCE = 'xfce4-terminal'; TERM_GNOME = 'gnome-terminal'; TERM_DEBIAN = 'x-terminal-emulator'; function GetPathTerminal(const Exe: String; var Cmd: String): Boolean; begin Result:= ExecutableInSystemPath(Exe); if Result then Cmd:= Exe; end; function GetKdeTerminal(var Cmd, Params: String): Boolean; const kde5Config = '/.kde/share/config/kdeglobals'; kde4Config = '/.kde4/share/config/kdeglobals'; var I: Integer; S: String = ''; iniCfg: TIniFileEx = nil; kdeConfig: array[1..2] of String = (kde4Config, kde5Config); begin for I:= Low(kdeConfig) to High(kdeConfig) do begin if (Length(S) = 0) and mbFileExists(GetHomeDir + kdeConfig[I]) then try iniCfg:= TIniFileEx.Create(GetHomeDir + kdeConfig[I]); try S:= iniCfg.ReadString('General', 'TerminalApplication', EmptyStr); finally iniCfg.Free; end; except // Skip end; end; Params:= EmptyStr; Result:= Length(S) > 0; if not Result then begin Result:= GetPathTerminal(TERM_KDE, S); end; if Result then Cmd:= S; end; function GetXfceTerminal(var Cmd, Params: String): Boolean; const xfceConfig = '/.config/xfce4/helpers.rc'; var S: String = ''; FileName: String; begin FileName:= GetHomeDir + xfceConfig; if mbFileExists(FileName) then begin with TStringListEx.Create do try try LoadFromFile(FileName); S:= Values['TerminalEmulator']; except // Skip end; finally Free; end; end; Result:= (Length(S) > 0); if not Result then begin Result:= GetPathTerminal(TERM_XFCE, S); end; if (S = TERM_XFCE) then begin Params:= '-x'; end; if Result then Cmd:= S; end; function GetLxdeTerminal(var Cmd, Params: String): Boolean; begin Params:= EmptyStr; Result:= GetPathTerminal(TERM_LXDE, Cmd); end; function GetLxqtTerminal(var Cmd, Params: String): Boolean; begin Params:= EmptyStr; Result:= GetPathTerminal(TERM_LXQT, Cmd); end; function GetGioTerminal(const Scheme: String; var Cmd, Params: String): Boolean; begin Cmd:= GioGetSetting(Scheme, 'exec'); Params:= GioGetSetting(Scheme, 'exec-arg'); Result:= Length(Cmd) > 0; end; function GetGnomeTerminal(var Cmd, Params: String): Boolean; begin Result:= GetGioTerminal('org.gnome.desktop.default-applications.terminal', Cmd, Params); if not Result then begin Params:= '-x'; Result:= GetPathTerminal(TERM_GNOME, Cmd); end; end; function GetMateTerminal(var Cmd, Params: String): Boolean; begin Result:= GetGioTerminal('org.mate.applications-terminal', Cmd, Params); if not Result then begin Params:= '-x'; Result:= GetPathTerminal(TERM_MATE, Cmd); end; end; function GetCinnamonTerminal(var Cmd, Params: String): Boolean; begin Result:= GetGioTerminal('org.cinnamon.desktop.default-applications.terminal', Cmd, Params); if not Result then begin Params:= '-x'; Result:= GetPathTerminal(TERM_GNOME, Cmd); end; end; function GetDefaultTerminal(var Cmd, Params: String): Boolean; begin if mbFileExists('/etc/debian_version') then begin Cmd:= TERM_DEBIAN; Exit(True); end; case DesktopEnv of DE_UNKNOWN: Result:= False; DE_KDE: Result:= GetKdeTerminal(Cmd, Params); DE_XFCE: Result:= GetXfceTerminal(Cmd, Params); DE_LXDE: Result:= GetLxdeTerminal(Cmd, Params); DE_LXQT: Result:= GetLxqtTerminal(Cmd, Params); DE_MATE: Result:= GetMateTerminal(Cmd, Params); DE_GNOME: Result:= GetGnomeTerminal(Cmd, Params); DE_CINNAMON: Result:= GetCinnamonTerminal(Cmd, Params); end; end; procedure Initialize; var Cmd: String = ''; Params: String = ''; begin if GetDefaultTerminal(Cmd, Params) then begin RunTermCmd:= Cmd; RunInTermCloseCmd:= Cmd; RunInTermStayOpenCmd:= Cmd; if (Length(Params) > 0) then begin RunInTermCloseParams:= StringReplace(RunInTermCloseParams, '-e', Params, []); RunInTermStayOpenParams:= StringReplace(RunInTermStayOpenParams, '-e', Params, []); end; end; end; {$ENDIF} initialization Initialize; end. ���������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ufilemanager.pas�������������������������������������������������0000644�0001750�0000144�00000007235�14743153644�021357� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileManager; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFile; function ShowItemProperties(const Files: TFiles): Boolean; implementation uses DBus, URIParser, uDebug; const DBUS_TIMEOUT_INFINITE = Integer($7fffffff); const FileManagerAddress = 'org.freedesktop.FileManager1'; FileManagerObjectPath = '/org/freedesktop/FileManager1'; FileManagerInterface = 'org.freedesktop.FileManager1'; var DBusError: DBus.DBusError; DBusConn: DBus.PDBusConnection; FileManagerAvailable: Boolean = True; procedure Print(const sMessage: String); begin DCDebug('FileManager: ', sMessage); end; function CheckError(const sMessage: String; pError: PDBusError): Boolean; begin if (dbus_error_is_set(pError) = 0) then Result:= False else begin Print(sMessage + ': ' + pError^.name + ' ' + pError^.message); dbus_error_free(pError); Result:= True; end; end; function SendMessage(AMessage: PDBusMessage): Boolean; var AReply: PDBusMessage; begin dbus_error_init (@DBusError); AReply := dbus_connection_send_with_reply_and_block(DBusConn, AMessage, DBUS_TIMEOUT_INFINITE, @DBusError); if CheckError('Error sending message', @DBusError) then Result:= False else if Assigned(AReply) then begin Result:= True; dbus_message_unref(AReply); end else begin Result:= False; Print('Reply not received'); end; end; function ShowItemProperties(const Files: TFiles): Boolean; var AFile: String; Index: Integer; StringPtr: PAnsiChar; AMessage: PDBusMessage; argsIter, arrayIter: DBusMessageIter; begin if (DBusConn = nil) then Exit(False); if (not FileManagerAvailable) then Exit(False); { <method name='ShowItemProperties'> <arg type='as' name='URIs' direction='in'/> <arg type='s' name='StartupId' direction='in'/> </method> } AMessage:= dbus_message_new_method_call(FileManagerAddress, FileManagerObjectPath, FileManagerInterface, 'ShowItemProperties'); if not Assigned(AMessage) then begin Print('Cannot create message "FilesystemMount"'); Result:= False; end else begin dbus_message_iter_init_append(AMessage, @argsIter); Result:= (dbus_message_iter_open_container(@argsIter, DBUS_TYPE_ARRAY, PAnsiChar(DBUS_TYPE_STRING_AS_STRING), @arrayIter) <> 0); if Result then begin for Index := 0 to Files.Count - 1 do begin AFile:= FilenameToURI(Files[Index].FullPath); StringPtr:= PAnsiChar(AFile); if dbus_message_iter_append_basic(@arrayIter, DBUS_TYPE_STRING, @StringPtr) = 0 then begin Result:= False; Break; end; end; if dbus_message_iter_close_container(@argsIter, @arrayIter) = 0 then Result:= False; end; if Result then begin StringPtr:= ''; Result:= (dbus_message_iter_append_basic(@argsIter, DBUS_TYPE_STRING, @StringPtr) <> 0); end; if not Result then begin Print('Cannot append arguments'); end else begin Result:= SendMessage(AMessage); end; dbus_message_unref(AMessage); end; FileManagerAvailable:= Result; end; procedure Initialize; begin dbus_error_init(@DBusError); DBusConn:= dbus_bus_get(DBUS_BUS_SESSION, @DBusError); if CheckError('Cannot acquire connection to DBUS session bus', @DBusError) then Exit; if Assigned(DBusConn) then begin dbus_connection_set_exit_on_disconnect(DBusConn, 0); end; end; procedure Finalize; begin if Assigned(DBusConn) then dbus_connection_unref(DBusConn); end; initialization Initialize; finalization Finalize; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ufolderthumb.pas�������������������������������������������������0000644�0001750�0000144�00000012231�14743153644�021410� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple folder thumbnail provider Copyright (C) 2019-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uFolderThumb; {$mode objfpc}{$H+} interface implementation uses Math, Classes, SysUtils, Graphics, IntfGraphics, GraphType, BaseUnix, Unix, Types, FPImage, DCClassesUtf8, DCOSUtils, DCStrUtils, DCConvertEncoding, LCLVersion, uThumbnails, uPixMapManager, uReSample, uGraphics; var ProviderIndex: Integer; function GetPreviewScaleSize(aSize: Types.TSize; aWidth, aHeight: Integer): Types.TSize; begin if aWidth > aHeight then begin Result.cx:= aSize.cx; Result.cy:= Result.cx * aHeight div aWidth; if Result.cy > aSize.cy then begin Result.cy:= aSize.cy; Result.cx:= Result.cy * aWidth div aHeight; end; end else begin Result.cy:= aSize.cy; Result.cx:= Result.cy * aWidth div aHeight; end; end; function GetThumbnail(const aFileName: String; aSize: Types.TSize): Graphics.TBitmap; var AExt: String; DirPtr: pDir; X, Y: Integer; OBitmap: TBitmap; InnerSize: TSize; sFileName: String; PtrDirEnt: pDirent; ABitmap: TBitmap = nil; Picture: TPicture = nil; FileStream: TFileStreamEx; Source, Target: TLazIntfImage; begin Result:= nil; if FPS_ISDIR(mbFileGetAttrNoLinks(aFileName)) then begin // Create half size inner icon InnerSize.cx:= aSize.cx * 50 div 100; InnerSize.cy:= aSize.cy * 50 div 100; DirPtr:= fpOpenDir(PAnsiChar(CeUtf8ToSys(aFileName))); if Assigned(DirPtr) then try Picture:= TPicture.Create; PtrDirEnt:= fpReadDir(DirPtr^); while PtrDirEnt <> nil do begin if (PtrDirEnt^.d_name <> '..') and (PtrDirEnt^.d_name <> '.') then begin sFileName:= IncludeTrailingBackslash(aFileName); sFileName+= CeSysToUtf8(PtrDirEnt^.d_name); // Try to create thumnail using providers ABitmap:= TThumbnailManager.GetPreviewFromProvider(sFileName, InnerSize, ProviderIndex); if Assigned(ABitmap) then Break; // Create thumnail for image files AExt:= ExtractOnlyFileExt(sFileName); if GetGraphicClassForFileExtension(AExt) <> nil then try FileStream:= TFileStreamEx.Create(sFileName, fmOpenRead or fmShareDenyNone or fmOpenNoATime); try Picture.LoadFromStreamWithFileExt(FileStream, AExt); ABitmap:= TBitmap.Create; ABitmap.Assign(Picture.Graphic); Break; finally FreeAndNil(FileStream); end; except // Ignore end; end; PtrDirEnt:= fpReadDir(DirPtr^); end; finally fpCloseDir(DirPtr^); Picture.Free; end; if Assigned(ABitmap) then begin Target:= TLazIntfImage.Create(aSize.cx, aSize.cy, [riqfRGB, riqfAlpha]); try {$if lcl_fullversion < 2020000} Target.CreateData; {$endif} Target.FillPixels(colTransparent); // Draw default folder icon Result:= PixMapManager.GetThemeIcon('folder', Min(aSize.cx, aSize.cy)); Source:= TLazIntfImage.Create(Result.RawImage, False); try X:= (aSize.cx - Result.Width) div 2; Y:= (aSize.cy - Result.Height) div 2; Target.CopyPixels(Source, X, Y); finally Source.Free; end; // Scale folder inner icon if (ABitmap.Width > InnerSize.cx) or (ABitmap.Height > InnerSize.cy) then begin InnerSize:= GetPreviewScaleSize(InnerSize, ABitmap.Width, ABitmap.Height); OBitmap:= TBitmap.Create; try OBitmap.SetSize(InnerSize.cx, InnerSize.cy); Stretch(ABitmap, OBitmap, ResampleFilters[2].Filter, ResampleFilters[2].Width); finally ABitmap.Free; ABitmap:= OBitmap; end; end; // Draw folder inner icon Source:= TLazIntfImage.Create(ABitmap.RawImage, False); try X:= (aSize.cx - ABitmap.Width) div 2; Y:= (aSize.cy - ABitmap.Height) div 2; Target.AlphaBlend(Source, nil, X, Y); finally Source.Free; end; BitmapAssign(Result, Target); finally Target.Free; end; ABitmap.Free; end; end; end; initialization ProviderIndex:= TThumbnailManager.RegisterProvider(@GetThumbnail); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ufontconfig.pas��������������������������������������������������0000644�0001750�0000144�00000003656�14743153644�021244� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFontConfig; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils, CTypes; type TFcBool = cint; PFcChar8 = PAnsiChar; PFcConfig = ^TFcConfig; TFcConfig = record end; PFcPattern = ^TFcPattern; TFcPattern = record end; TFcMatchKind = (FcMatchPattern, FcMatchFont, FcMatchScan); PFcResult = ^TFcResult; TFcResult = (FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId, FcResultOutOfMemory); var FcStrFree: procedure(s: PFcChar8); cdecl; FcPatternDestroy: procedure(p: PFcPattern); cdecl; FcNameParse: function(name: PFcChar8): PFcPattern; cdecl; FcDefaultSubstitute: procedure(pattern: PFcPattern); cdecl; FcPatternFormat: function(pat: PFcPattern; format: PFcChar8): PFcChar8; cdecl; FcFontMatch: function(config: PFcConfig; p: PFcPattern; result: PFcResult): PFcPattern; cdecl; FcConfigSubstitute: function(config: PFcConfig; p: PFcPattern; kind: TFcMatchKind): TFcBool; cdecl; function LoadFontConfigLib(const ALibName: String): Boolean; procedure UnLoadFontConfigLib; implementation uses DCOSUtils, uDebug; var hLib: TLibHandle; function LoadFontConfigLib(const ALibName: String): Boolean; begin hLib:= SafeLoadLibrary(ALibName); Result:= (hLib <> NilHandle); if Result then try FcStrFree:= SafeGetProcAddress(hLib, 'FcStrFree'); FcNameParse:= SafeGetProcAddress(hLib, 'FcNameParse'); FcFontMatch:= SafeGetProcAddress(hLib, 'FcFontMatch'); FcPatternFormat:= SafeGetProcAddress(hLib, 'FcPatternFormat'); FcPatternDestroy:= SafeGetProcAddress(hLib, 'FcPatternDestroy'); FcConfigSubstitute:= SafeGetProcAddress(hLib, 'FcConfigSubstitute'); FcDefaultSubstitute:= SafeGetProcAddress(hLib, 'FcDefaultSubstitute'); except on E: Exception do begin Result:= False; DCDebug(E.Message); UnLoadFontConfigLib; end; end; end; procedure UnLoadFontConfigLib; begin if (hLib <> NilHandle) then FreeLibrary(hLib); end; end. ����������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ugio.pas���������������������������������������������������������0000644�0001750�0000144�00000021375�14743153644�017664� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Interface to GIO - GLib Input, Output and Streaming Library This unit loads all libraries dynamically so it can work without it Copyright (C) 2011-2024 Alexander Koblov (alexx2000@mail.ru) 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 } unit uGio; {$mode delphi} {$assertions on} interface uses Classes, SysUtils, DCBasicTypes, uGio2; function GioOpen(const Uri: String): Boolean; function GioNewFile(const Address: String): PGFile; function GioGetIconTheme(const Scheme: String): String; function GioFileGetIcon(const FileName: String): String; function GioMimeGetIcon(const MimeType: String): String; function GioGetSetting(const Scheme, Key: String): String; function GioFileGetEmblem(const FileName: String): String; function GioMimeTypeGetActions(const MimeType: String): TDynamicStringArray; function GioGetMimeType(const FileName: String; MaxExtent: LongWord): String; var HasGio: Boolean = True; implementation uses StrUtils, LazLogger, DCStrUtils, DCClassesUtf8, uGlib2, uGObject2; function GioOpen(const Uri: String): Boolean; var AFile: PGFile; AFileList: TGList; AppInfo: PGAppInfo; begin Result:= False; AFileList.next:= nil; AFileList.prev:= nil; if not HasGio then Exit; AFile:= GioNewFile(Pgchar(Uri)); try AppInfo:= g_file_query_default_handler(AFile, nil, nil); if (AppInfo = nil) then Exit; if g_file_is_native(AFile) then begin AFileList.data:= AFile; Result:= g_app_info_launch (AppInfo, @AFileList, nil, nil); end else begin AFileList.data:= Pgchar(Uri); Result:= g_app_info_launch_uris (AppInfo, @AFileList, nil, nil); end; g_object_unref(PGObject(AppInfo)); finally g_object_unref(PGObject(AFile)); end; end; function GioNewFile(const Address: String): PGFile; var URI: Pgchar; Index: Integer; begin Index:= Pos('://', Address); if Index = 0 then Result:= g_file_new_for_path(Pgchar(Address)) else begin Index:= PosEx('/', Address, Index + 3); if (Index = 0) or (Index = Length(Address)) then Result:= g_file_new_for_uri(Pgchar(Address)) else begin URI:= g_uri_escape_string(Pgchar(Address) + Index, ':/', True); if (URI = nil) then Result:= g_file_new_for_uri(Pgchar(Address)) else begin Result:= g_file_new_for_uri(Pgchar(Copy(Address, 1, Index) + URI)); g_free(URI); end; end; end; end; function GioGetSetting(const Scheme, Key: String): String; var Theme: Pgchar; Settings: PGSettings; SettingsSchema: PGSettingsSchema; SchemaSource: PGSettingsSchemaSource; begin Result:= EmptyStr; if not HasGio then Exit; SchemaSource:= g_settings_schema_source_get_default(); if Assigned(SchemaSource) then begin SettingsSchema:= g_settings_schema_source_lookup(SchemaSource, Pgchar(Scheme), False); if Assigned(SettingsSchema) then begin Settings:= g_settings_new(Pgchar(Scheme)); if Assigned(Settings) then begin Theme:= g_settings_get_string(Settings, Pgchar(Key)); if Assigned(Theme) then begin Result:= StrPas(Theme); g_free(Theme); end; g_object_unref(Settings); end; g_object_unref(PGObject(SettingsSchema)); end; g_object_unref(PGObject(SchemaSource)); end; end; function GioGetIconTheme(const Scheme: String): String; begin Result:= GioGetSetting(Scheme, 'icon-theme'); end; function GioGetIconName(GIcon: PGIcon): String; var AIconList: PPgchar; begin if g_type_check_instance_is_a(PGTypeInstance(GIcon), g_themed_icon_get_type()) then begin AIconList:= g_themed_icon_get_names(PGThemedIcon(GIcon)); if Assigned(AIconList) then Result:= AIconList[0]; end; end; function GioMimeGetIcon(const MimeType: String): String; var GIcon: PGIcon; ContentType: Pgchar; begin Result:= EmptyStr; ContentType:= g_content_type_from_mime_type(Pgchar(MimeType)); if Assigned(ContentType) then begin GIcon:= g_content_type_get_icon(ContentType); if Assigned(GIcon) then begin Result:= GioGetIconName(GIcon); g_object_unref(PGObject(GIcon)); end; g_free(ContentType); end; end; function GioFileGetIcon(const FileName: String): String; var GFile: PGFile; GIcon: PGIcon; GFileInfo: PGFileInfo; begin Result:= EmptyStr; GFile:= GioNewFile(Pgchar(FileName)); GFileInfo:= g_file_query_info(GFile, FILE_ATTRIBUTE_STANDARD_ICON, 0, nil, nil); if Assigned(GFileInfo) then begin GIcon:= g_file_info_get_icon(GFileInfo); Result:= GioGetIconName(GIcon); g_object_unref(GFileInfo); end; g_object_unref(PGObject(GFile)); end; function GioFileGetEmblem(const FileName: String): String; const FILE_ATTRIBUTE_METADATA_EMBLEMS = 'metadata::emblems'; var GFile: PGFile; AIconList: PPgchar; GFileInfo: PGFileInfo; begin Result:= EmptyStr; GFile:= GioNewFile(Pgchar(FileName)); GFileInfo:= g_file_query_info(GFile, FILE_ATTRIBUTE_METADATA_EMBLEMS, 0, nil, nil); if Assigned(GFileInfo) then begin AIconList:= g_file_info_get_attribute_stringv(GFileInfo, FILE_ATTRIBUTE_METADATA_EMBLEMS); if Assigned(AIconList) then Result:= AIconList[0]; g_object_unref(GFileInfo); end; g_object_unref(PGObject(GFile)); end; function GioMimeTypeGetActions(const MimeType: String): TDynamicStringArray; var AppList, TempList: PGList; DesktopFile: PAnsiChar; begin AppList:= g_app_info_get_all_for_type(PAnsiChar(MimeType)); if Assigned(AppList) then begin TempList:= AppList; repeat DesktopFile:= g_app_info_get_id(TempList^.data); if Assigned(DesktopFile) then AddString(Result, DesktopFile); g_object_unref(TempList^.data); TempList:= TempList^.next; until TempList = nil; g_list_free(AppList); end; end; function GioGetMimeType(const FileName: String; MaxExtent: LongWord): String; var Size: gsize; MimeType: Pgchar; Uncertain: gboolean; Buffer: array of Byte; FileStream: TFileStreamEx; begin // First check by file name (fast) MimeType:= g_content_type_guess(Pgchar(FileName), nil, 0, @Uncertain); if Assigned(MimeType) then begin Result:= StrPas(MimeType); g_free(MimeType); end; // Second check by file content (slow) if Uncertain then begin if MaxExtent = 0 then Result:= 'text/plain' else begin SetLength(Buffer, MaxExtent); try FileStream:= TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try Size:= FileStream.Read(Buffer[0], MaxExtent); finally FileStream.Free; end; MimeType:= g_content_type_guess(nil, @Buffer[0], Size, @Uncertain); if Assigned(MimeType) then begin Result:= StrPas(MimeType); g_free(MimeType); end; except // Skip end; end; end; end; procedure Initialize; begin try Assert(@g_file_is_native <> nil, 'g_file_is_native'); Assert(@g_file_new_for_commandline_arg <> nil, 'g_file_new_for_commandline_arg'); Assert(@g_file_query_default_handler <> nil, 'g_file_query_default_handler'); Assert(@g_file_query_info <> nil, 'g_file_query_info'); Assert(@g_file_info_get_icon <> nil, 'g_file_info_get_icon'); Assert(@g_themed_icon_get_type <> nil, 'g_themed_icon_get_type'); Assert(@g_themed_icon_get_names <> nil, 'g_themed_icon_get_names'); Assert(@g_app_info_launch <> nil, 'g_app_info_launch'); Assert(@g_app_info_launch_uris <> nil, 'g_app_info_launch_uris'); Assert(@g_app_info_get_all_for_type <> nil, 'g_app_info_get_all_for_type'); Assert(@g_app_info_get_id <> nil, 'g_app_info_get_id'); Assert(@g_settings_new <> nil, 'g_settings_new'); Assert(@g_settings_get_string <> nil, 'g_settings_get_string'); Assert(@g_settings_schema_source_get_default <> nil, 'g_settings_schema_source_get_default'); Assert(@g_settings_schema_source_lookup <> nil, 'g_settings_schema_source_lookup'); Assert(@g_content_type_guess <> nil, 'g_content_type_guess'); except on E: Exception do begin HasGio:= False; DebugLn(E.Message); end; end; end; initialization Initialize; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ugtk2fixcursorpos.pas��������������������������������������������0000644�0001750�0000144�00000016635�14743153644�022447� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Workaround: http://doublecmd.sourceforge.net/mantisbt/view.php?id=1473 } unit uGtk2FixCursorPos; {$mode objfpc}{$H+} interface uses LCLVersion; implementation uses Classes, SysUtils, Gtk2WSStdCtrls, Gtk2, Gtk2Def, Gtk2WSSpin, Gtk2Proc, WSLCLClasses, StdCtrls, Glib2, Gtk2Globals, Spin, LMessages, LazUTF8, Gdk2, Controls, ExtCtrls, WSExtCtrls, Gtk2WSExtCtrls, Graphics ; type { TGtk2WSCustomEditEx } TGtk2WSCustomEditEx = class(TGtk2WSCustomEdit) published class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); override; end; { TGtk2WSCustomFloatSpinEditEx } TGtk2WSCustomFloatSpinEditEx = class(TGtk2WSCustomFloatSpinEdit) protected class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); override; end; { TGtk2WSCustomPanelEx } TGtk2WSCustomPanelEx = class(TGtk2WSCustomPanel) published class function GetDefaultColor(const AControl: TControl; const ADefaultColorType: TDefaultColorType): TColor; override; end; procedure gtkcuttoclip_ex(widget: PGtkWidget; {%H-}data: gPointer); cdecl; var Info: PWidgetInfo; begin if (Widget <> nil) and (GTK_IS_ENTRY(Widget)) then begin Info := GetWidgetInfo(Widget); Include(Info^.Flags, wwiInvalidEvent); end; end; procedure gtkchanged_editbox_backspace_ex(widget: PGtkWidget; {%H-}data: gPointer); cdecl; var Info: PWidgetInfo; begin if (Widget <> nil) and (GTK_IS_ENTRY(Widget)) then begin Info := GetWidgetInfo(Widget); Include(Info^.Flags, wwiInvalidEvent); end; end; procedure gtkchanged_editbox_ex(widget: PGtkWidget; {%H-}data: gPointer); cdecl; forward; function GtkEntryDelayCursorPos(AGtkWidget: Pointer): GBoolean; cdecl; var Info: PWidgetInfo; begin Result := AGtkWidget <> nil; if AGtkWidget <> nil then begin g_idle_remove_by_data(AGtkWidget); Info := GetWidgetInfo(AGtkWidget); if Info <> nil then gtkchanged_editbox_ex(PGtkWidget(AGtkWidget), Info^.LCLObject); end; end; procedure gtkchanged_editbox_ex(widget: PGtkWidget; {%H-}data: gPointer); cdecl; var Mess : TLMessage; GStart, GEnd: gint; Info: PWidgetInfo; EntryText: PgChar; NeedCursorCheck: Boolean; begin if LockOnChange(PgtkObject(Widget),0)>0 then exit; {$IFDEF EventTrace} EventTrace('changed_editbox', data); {$ENDIF} NeedCursorCheck := False; if GTK_IS_ENTRY(Widget) and (not (TObject(data) is TCustomFloatSpinEdit)) then begin // lcl-do-not-change-selection comes from gtkKeyPress. // Only floatspinedit sets that data, so default is nil. issue #18679 if g_object_get_data(PGObject(Widget),'lcl-do-not-change-selection') = nil then begin {cheat GtkEditable to update cursor pos in gtkEntry. issue #7243} gtk_editable_get_selection_bounds(PGtkEditable(Widget), @GStart, @GEnd); EntryText := gtk_entry_get_text(PGtkEntry(Widget)); if (GStart = GEnd) and (UTF8Length(EntryText) >= PGtkEntry(Widget)^.text_length) then begin Info := GetWidgetInfo(Widget); {do not update position if backspace or delete pressed} if wwiInvalidEvent in Info^.Flags then begin Exclude(Info^.Flags, wwiInvalidEvent); {take care of pasted data since it does not return proper cursor pos.} // issue #7243 if g_object_get_data(PGObject(Widget),'lcl-delay-cm_textchaged') <> nil then begin g_object_set_data(PGObject(Widget),'lcl-delay-cm_textchaged',nil); g_object_set_data(PGObject(Widget),'lcl-gtkentry-pasted-data',Widget); g_idle_add(@GtkEntryDelayCursorPos, Widget); exit; end; end else begin // if we change selstart in OnChange event new cursor pos need to // be postponed in TGtk2WSCustomEdit.SetSelStart NeedCursorCheck := True; if g_object_get_data(PGObject(Widget),'lcl-gtkentry-pasted-data') <> nil then begin g_object_set_data(PGObject(Widget),'lcl-gtkentry-pasted-data',nil); gtk_editable_set_position(PGtkEditable(Widget), GStart); end else begin //NeedCursorCheck := True; g_object_set_data(PGObject(Widget),'lcl-gtkentry-pasted-data',Widget); g_idle_add(@GtkEntryDelayCursorPos, Widget); exit; end; end; end; end else g_object_set_data(PGObject(Widget),'lcl-do-not-change-selection', nil); end; if NeedCursorCheck then LockOnChange(PgtkObject(Widget), +1); FillByte(Mess{%H-},SizeOf(Mess),0); Mess.Msg := CM_TEXTCHANGED; DeliverMessage(Data, Mess); if NeedCursorCheck then LockOnChange(PgtkObject(Widget), -1); end; function gtkMotionNotifyEx(Widget:PGTKWidget; Event: PGDKEventMotion; Data: gPointer): GBoolean; cdecl; var ACtl: TWinControl; begin // Call inherited function Result:= gtkMotionNotify(Widget, Event, Data); ACtl:= TWinControl(Data); if (ACtl is TCustomEdit) then begin if (Event^.x < 0) or (Event^.y < 0) or (Event^.x > ACtl.Width) or (Event^.y > ACtl.Height) then Result:= CallBackDefaultReturn; end; end; { TGtk2WSCustomPanelEx } class function TGtk2WSCustomPanelEx.GetDefaultColor(const AControl: TControl; const ADefaultColorType: TDefaultColorType): TColor; const DefColors: array[TDefaultColorType] of TColor = ( { dctBrush } clForm, { dctFont } clBtnText ); begin Result := DefColors[ADefaultColorType]; end; { TGtk2WSCustomEditEx } class procedure TGtk2WSCustomEditEx.SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); var gObject: PGTKObject; ALCLObject: TObject; begin inherited SetCallbacks(AGtkWidget, AWidgetInfo); ALCLObject:= AWidgetInfo^.LCLObject; // gObject if AGtkWidget = nil then gObject := ObjectToGTKObject(ALCLObject) else gObject := PGtkObject(AGtkWidget); if gObject = nil then Exit; if GTK_IS_ENTRY(gObject) then begin if ALCLObject is TCustomFloatSpinEdit then ConnectSignal(gObject, 'value-changed', @gtkchanged_editbox_ex, ALCLObject) else begin ConnectSignal(gObject, 'changed', @gtkchanged_editbox_ex, ALCLObject); end; ConnectSignal(gObject, 'cut-clipboard', @gtkcuttoclip_ex, ALCLObject); g_signal_handlers_disconnect_by_func(gObject, @gtkchanged_editbox, ALCLObject); ConnectSignal(gObject, 'backspace', @gtkchanged_editbox_backspace_ex, ALCLObject); ConnectSignal(gObject, 'delete-from-cursor', @gtkchanged_editbox_delete, ALCLObject); g_signal_handlers_disconnect_by_func(gObject, @GTKMotionNotify, ALCLObject); ConnectSignal(gObject, 'motion-notify-event', @GTKMotionNotifyEx, ALCLObject, GDK_POINTER_MOTION_HINT_MASK or GDK_POINTER_MOTION_MASK); end; end; { TGtk2WSCustomFloatSpinEditEx } class procedure TGtk2WSCustomFloatSpinEditEx.SetCallbacks( const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); begin TGtk2WSCustomEditEx.SetCallbacks(AGtkWidget, AWidgetInfo); end; procedure Initialize; begin // Replace TCustomEdit widgetset class with TCustomEdit.Create(nil) do Free; RegisterWSComponent(TCustomEdit, TGtk2WSCustomEditEx); // Replace TCustomFloatSpinEdit widgetset class with TCustomFloatSpinEdit.Create(nil) do Free; RegisterWSComponent(TCustomFloatSpinEdit, TGtk2WSCustomFloatSpinEditEx); // Replace TCustomPanel widgetset class WSExtCtrls.RegisterCustomPanel; RegisterWSComponent(TCustomPanel, TGtk2WSCustomPanelEx); end; initialization Initialize; end. ���������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ugvolume.pas�����������������������������������������������������0000644�0001750�0000144�00000023436�14743153644�020564� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Interface to GVolumeMonitor Copyright (C) 2014-2022 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uGVolume; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uDrive; type TGVolumeSignal = (GVolume_Added, GVolume_Removed, GVolume_Changed); TGVolumeNotify = procedure(Signal: TGVolumeSignal; Drive: PDrive) of object; function Initialize: Boolean; procedure Finalize; procedure AddObserver(Func: TGVolumeNotify); procedure RemoveObserver(Func: TGVolumeNotify); function Eject(const Path: String): Boolean; function Unmount(const Path: String): Boolean; function EnumerateVolumes(DrivesList: TDrivesList): Boolean; implementation uses typinfo, fgl, LazLogger, uGLib2, uGio2, uGObject2, uShowMsg; type TGVolumeObserverList = specialize TFPGList<TGVolumeNotify>; var VolumeMonitor: PGVolumeMonitor = nil; Observers: TGVolumeObserverList = nil; procedure Print(const Message: String); begin DebugLn('GVolumeMonitor: ', Message); end; function ReadString(Volume: PGVolume; const Kind: Pgchar): String; var Value: PAnsiChar; begin Value:= g_volume_get_identifier(Volume, Kind); if Value = nil then Result:= EmptyStr else begin Result:= StrPas(Value); g_free(Value); end; end; function VolumeToDrive(Volume: PGVolume): PDrive; var GFile: PGFile; GMount: PGMount; Name, Path: Pgchar; begin Result:= nil; GMount:= g_volume_get_mount(Volume); if Assigned(GMount) then g_object_unref(PGObject(GMount)) else begin GFile:= g_volume_get_activation_root(Volume); if Assigned(GFile) then begin if not g_file_has_uri_scheme(GFile, 'file') then begin Path:= g_file_get_uri(GFile); if Assigned(Path) then begin New(Result); Result^.IsMounted:= True; Result^.DriveType:= dtSpecial; Result^.IsMediaAvailable:= True; Result^.IsMediaEjectable:= g_volume_can_eject(Volume); Result^.DeviceId:= ReadString(Volume, VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); Result^.DriveLabel:= ReadString(Volume, VOLUME_IDENTIFIER_KIND_LABEL); Name:= g_volume_get_name(Volume); if (Name = nil) then Result^.DisplayName:= ExtractFileName(Result^.DeviceId) else begin Result^.DisplayName := StrPas(Name); g_free(Name); end; Result^.Path:= StrPas(Path); { Name:= g_uri_unescape_string(Path, nil); if (Name = nil) then Result^.Path:= StrPas(Path) else begin Result^.Path:= StrPas(Name); g_free(Name); end; } g_free(Path); end; end; g_object_unref(PGObject(GFile)); end; end; end; function MountToDrive(Mount: PGMount): PDrive; var GFile: PGFile; Name, Path: Pgchar; begin Result:= nil; if not g_mount_is_shadowed(Mount) then begin GFile:= g_mount_get_root(Mount); if Assigned(GFile) then begin if not g_file_has_uri_scheme(GFile, 'file') then begin Path:= g_file_get_uri(GFile); if Assigned(Path) then begin New(Result); Result^.IsMounted:= True; Result^.DriveType:= dtSpecial; Result^.IsMediaAvailable:= True; Result^.IsMediaEjectable:= g_mount_can_eject(Mount); Name:= g_mount_get_name(Mount); if (Name = nil) then Result^.DisplayName:= ExtractFileName(Result^.Path) else begin Result^.DisplayName := StrPas(Name); g_free(Name); end; Result^.Path:= StrPas(Path); { Name:= g_uri_unescape_string(Path, nil); if (Name = nil) then Result^.Path:= StrPas(Path) else begin Result^.Path:= StrPas(Name); g_free(Name); end; } g_free(Path); end; end; g_object_unref(PGObject(GFile)); end; end; end; procedure VolumeEvent(volume_monitor: PGVolumeMonitor; volume: PGVolume; user_data: gpointer); cdecl; var Drive: PDrive; Index: Integer; VolumeEvent: TGVolumeSignal absolute user_data; begin Drive:= VolumeToDrive(volume); if Assigned(Drive) then begin Print(GetEnumName(TypeInfo(TGVolumeSignal), PtrInt(VolumeEvent)) + ': ' + Drive^.Path); for Index:= 0 to Observers.Count - 1 do Observers[Index](VolumeEvent, Drive); end; end; procedure MountEvent(volume_monitor: PGVolumeMonitor; mount: PGMount; user_data: gpointer); cdecl; var Drive: PDrive; Index: Integer; VolumeEvent: TGVolumeSignal absolute user_data; begin Drive:= MountToDrive(mount); if Assigned(Drive) then begin Print(GetEnumName(TypeInfo(TGVolumeSignal), PtrInt(VolumeEvent)) + ': ' + Drive^.Path); for Index:= 0 to Observers.Count - 1 do Observers[Index](VolumeEvent, Drive); end; end; procedure AddObserver(Func: TGVolumeNotify); begin if Observers.IndexOf(Func) < 0 then Observers.Add(Func); end; procedure RemoveObserver(Func: TGVolumeNotify); begin Observers.Remove(Func); end; function Initialize: Boolean; begin VolumeMonitor:= g_volume_monitor_get(); Result:= Assigned(VolumeMonitor); if Result then begin Observers:= TGVolumeObserverList.Create; g_signal_connect_data(VolumeMonitor, 'volume-added', TGCallback(@VolumeEvent), gpointer(PtrInt(GVolume_Added)), nil, G_CONNECT_AFTER); g_signal_connect_data(VolumeMonitor, 'volume-changed', TGCallback(@VolumeEvent), gpointer(PtrInt(GVolume_Changed)), nil, G_CONNECT_AFTER); g_signal_connect_data(VolumeMonitor, 'volume-removed', TGCallback(@VolumeEvent), gpointer(PtrInt(GVolume_Removed)), nil, G_CONNECT_AFTER); g_signal_connect_data(VolumeMonitor, 'mount-added', TGCallback(@MountEvent), gpointer(PtrInt(GVolume_Added)), nil, G_CONNECT_AFTER); g_signal_connect_data(VolumeMonitor, 'mount-changed', TGCallback(@MountEvent), gpointer(PtrInt(GVolume_Changed)), nil, G_CONNECT_AFTER); g_signal_connect_data(VolumeMonitor, 'mount-removed', TGCallback(@MountEvent), gpointer(PtrInt(GVolume_Removed)), nil, G_CONNECT_AFTER); end; end; procedure Finalize; begin if Assigned(VolumeMonitor) then begin FreeAndNil(Observers); g_object_unref(VolumeMonitor); VolumeMonitor:= nil; end; end; procedure FinishEject(source_object: PGObject; res: PGAsyncResult; user_data: gpointer); cdecl; var AError: PGError = nil; begin if not g_mount_eject_with_operation_finish(PGMount(source_object), res, @AError) then begin msgError(nil, AError^.message); g_error_free(AError); end; g_object_unref(source_object); end; function Eject(const Path: String): Boolean; var AFile: PGFile; AMount: PGMount; begin AFile:= g_file_new_for_path(Pgchar(Path)); AMount:= g_file_find_enclosing_mount(AFile, nil, nil); Result:= Assigned(AMount); if Result then begin g_mount_eject_with_operation(AMount, G_MOUNT_UNMOUNT_NONE, nil, nil, @FinishEject, nil); end; g_object_unref(PGObject(AFile)); end; procedure FinishUnmount(source_object: PGObject; res: PGAsyncResult; user_data: gpointer); cdecl; var AError: PGError = nil; begin if not g_mount_unmount_with_operation_finish(PGMount(source_object), res, @AError) then begin msgError(nil, AError^.message); g_error_free(AError); end; g_object_unref(source_object); end; function Unmount(const Path: String): Boolean; var AFile: PGFile; AMount: PGMount; begin AFile:= g_file_new_for_uri(Pgchar(Path)); AMount:= g_file_find_enclosing_mount(AFile, nil, nil); Result:= Assigned(AMount); if Result then begin g_mount_unmount_with_operation(AMount, G_MOUNT_UNMOUNT_NONE, nil, nil, @FinishUnmount, nil); end; g_object_unref(PGObject(AFile)); end; function EnumerateVolumes(DrivesList: TDrivesList): Boolean; var Drive: PDrive; GMount: PGMount; GVolume: PGVolume; VolumeList: PGList; VolumeTemp: PGList; begin Result:= False; VolumeList:= g_volume_monitor_get_volumes(VolumeMonitor); if Assigned(VolumeList) then begin Result:= True; VolumeTemp:= VolumeList; while Assigned(VolumeTemp) do begin GVolume:= VolumeTemp^.data; Drive:= VolumeToDrive(GVolume); if (Assigned(Drive)) then begin DrivesList.Add(Drive); // WriteLn('GVolume: ', Drive^.Path); end; g_object_unref(PGObject(GVolume)); VolumeTemp:= VolumeTemp^.next; end; g_list_free(VolumeList); end; VolumeList:= g_volume_monitor_get_mounts(VolumeMonitor); if Assigned(VolumeList) then begin Result:= True; VolumeTemp:= VolumeList; while Assigned(VolumeTemp) do begin GMount:= VolumeTemp^.data; Drive:= MountToDrive(GMount); if (Assigned(Drive)) then begin DrivesList.Add(Drive); // WriteLn('GMount: ', Drive^.Path); end; g_object_unref(PGObject(GMount)); VolumeTemp:= VolumeTemp^.next; end; g_list_free(VolumeList); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ujpegthumb.pas���������������������������������������������������0000644�0001750�0000144�00000005332�14743153644�021066� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Fast JPEG thumbnail provider Copyright (C) 2013 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uJpegThumb; {$mode objfpc}{$H+} interface implementation uses Classes, SysUtils, Types, Graphics, FPReadJPEG, IntfGraphics, GraphType, DCClassesUtf8, uReSample, uThumbnails; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var Bitmap: TBitmap; RawImage: TRawImage; FileStream: TFileStreamEx; FPReaderJPEG: TFPReaderJPEG; LazIntfImage: TLazIntfImage; begin Result:= nil; if TJPEGImage.IsFileExtensionSupported(ExtractFileExt(aFileName)) then begin Result:= TBitmap.Create; FPReaderJPEG:= TFPReaderJPEG.Create; FPReaderJPEG.MinWidth:= aSize.cx; FPReaderJPEG.MinHeight:= aSize.cy; try FileStream:= TFileStreamEx.Create(aFileName, fmOpenRead or fmShareDenyNone); LazIntfImage:= TLazIntfImage.Create(aSize.cx, aSize.cy, [riqfRGB]); try FPReaderJPEG.ImageRead(FileStream, LazIntfImage); LazIntfImage.GetRawImage(RawImage, True); if not ((LazIntfImage.Width > aSize.cx) or (LazIntfImage.Height > aSize.cy)) then Result.LoadFromRawImage(RawImage, True) else begin Bitmap:= TBitmap.Create; try Bitmap.LoadFromRawImage(RawImage, True); aSize:= TThumbnailManager.GetPreviewScaleSize(Bitmap.Width, Bitmap.Height); Result.SetSize(aSize.cx, aSize.cy); Stretch(Bitmap, Result, ResampleFilters[2].Filter, ResampleFilters[2].Width); finally Bitmap.Free; end; end; finally FPReaderJPEG.Free; LazIntfImage.Free; FileStream.Free; end; except FreeAndNil(Result); end; end; end; initialization TThumbnailManager.RegisterProvider(@GetThumbnail); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ukde.pas���������������������������������������������������������0000644�0001750�0000144�00000003573�14743153644�017651� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- K Desktop Environment integration unit Copyright (C) 2014-2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uKde; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uMyUnix; function KioOpen(const URL: String): Boolean; var HasKdeOpen: Boolean = False; implementation uses LazLogger, uDCUtils, uGlobs, uOSUtils, uTrash; var KdeVersion: String; KdeOpen: String = 'kioclient'; function KioOpen(const URL: String): Boolean; begin Result:= ExecCmdFork(KdeOpen + ' exec ' + QuoteStr(URL)); end; function FileTrash(const FileName: String): Boolean; begin try Result:= ExecuteProcess(KdeOpen, ['--noninteractive', 'move', FileName, 'trash:/']) = 0; except on E: Exception do begin Result:= False; DebugLn('FileTrash: ', E.Message); end; end; end; procedure Initialize; begin if (DesktopEnv = DE_KDE) then begin KdeVersion:= GetEnvironmentVariable('KDE_SESSION_VERSION'); if KdeVersion = '5' then KdeOpen:= 'kioclient5'; HasKdeOpen:= FindExecutableInSystemPath(KdeOpen); // if HasKdeOpen then FileTrashUtf8:= @FileTrash; end; end; initialization RegisterInitialization(@Initialize); end. �������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ukeyfile.pas�����������������������������������������������������0000644�0001750�0000144�00000014721�14743153644�020533� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple key file implementation based on GKeyFile Copyright (C) 2014 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uKeyFile; {$mode objfpc}{$H+} interface uses Classes, SysUtils, IniFiles, DCBasicTypes, uGLib2; const { Constants for handling freedesktop.org Desktop files } DESKTOP_GROUP = 'Desktop Entry'; DESKTOP_KEY_CATEGORIES = 'Categories'; DESKTOP_KEY_COMMENT = 'Comment'; DESKTOP_KEY_EXEC = 'Exec'; DESKTOP_KEY_ICON = 'Icon'; DESKTOP_KEY_NAME = 'Name'; DESKTOP_KEY_TYPE = 'Type'; DESKTOP_KEY_TRY_EXEC = 'TryExec'; DESKTOP_KEY_MIME_TYPE = 'MimeType'; DESKTOP_KEY_NO_DISPLAY = 'NoDisplay'; DESKTOP_KEY_TERMINAL = 'Terminal'; DESKTOP_KEY_KDE_BUG = 'Path[$e]'; type { TKeyFile } TKeyFile = class(TCustomIniFile) private FGKeyFile: PGKeyFile; protected function LoadFromFile(const AFileName: String; out AMessage: String): Boolean; inline; public constructor Create(const AFileName: String; AEscapeLineFeeds : Boolean = False); override; destructor Destroy; override; public function SectionExists(const Section: String): Boolean; override; function ReadBool(const Section, Ident: String; Default: Boolean): Boolean; override; function ReadString(const Section, Ident, Default: String): String; override; function ReadLocaleString(const Section, Ident, Default: String): String; virtual; function ReadStringList(const Section, Ident: String): TDynamicStringArray; virtual; protected procedure WriteString(const Section, Ident, Value: String); override; procedure ReadSection(const Section: string; Strings: TStrings); override; procedure ReadSections(Strings: TStrings); override; procedure ReadSectionValues(const Section: string; Strings: TStrings); override; procedure EraseSection(const Section: string); override; procedure DeleteKey(const Section, Ident: String); override; procedure UpdateFile; override; end; implementation uses RtlConsts, DCStrUtils; { TKeyFile } function TKeyFile.LoadFromFile(const AFileName: String; out AMessage: String): Boolean; var AChar: Pgchar; ALength: gsize; AContents: Pgchar; AError: PGError = nil; function FormatMessage: String; begin if Assigned(AError) then begin Result:= StrPas(AError^.message); g_error_free(AError); AError:= nil; end; end; begin Result:= g_key_file_load_from_file(FGKeyFile, Pgchar(AFileName), G_KEY_FILE_NONE, @AError); if not Result then begin AMessage:= FormatMessage; // KDE menu editor adds invalid "Path[$e]" key. GKeyFile cannot parse // such desktop files. We comment it before parsing to avoid this problem. if Pos(DESKTOP_KEY_KDE_BUG, AMessage) > 0 then begin Result:= g_file_get_contents(Pgchar(AFileName), @AContents, @ALength, @AError); if not Result then AMessage:= FormatMessage else try AChar:= g_strstr_len(AContents, ALength, DESKTOP_KEY_KDE_BUG); if Assigned(AChar) then AChar^:= '#'; Result:= g_key_file_load_from_data(FGKeyFile, AContents, ALength, G_KEY_FILE_NONE, @AError); if not Result then AMessage:= FormatMessage; finally g_free(AContents); end; end; end; end; constructor TKeyFile.Create(const AFileName: String; AEscapeLineFeeds: Boolean); var AMessage: String; begin FGKeyFile:= g_key_file_new(); if not LoadFromFile(AFileName, AMessage) then raise EFOpenError.CreateFmt(SFOpenErrorEx, [AFileName, AMessage]); inherited Create(AFileName, AEscapeLineFeeds); CaseSensitive:= True; end; destructor TKeyFile.Destroy; begin inherited Destroy; g_key_file_free(FGKeyFile); end; function TKeyFile.SectionExists(const Section: String): Boolean; begin Result:= g_key_file_has_group(FGKeyFile, Pgchar(Section)); end; function TKeyFile.ReadBool(const Section, Ident: String; Default: Boolean): Boolean; {$OPTIMIZATION OFF} var AError: PGError = nil; begin Result:= g_key_file_get_boolean(FGKeyFile, Pgchar(Section), Pgchar(Ident), @AError); if (AError <> nil) then begin Result:= Default; g_error_free(AError); end; end; {$OPTIMIZATION DEFAULT} function TKeyFile.ReadString(const Section, Ident, Default: String): String; var AValue: Pgchar; begin AValue:= g_key_file_get_string(FGKeyFile, Pgchar(Section), Pgchar(Ident), nil); if (AValue = nil) then Result:= Default else begin Result:= StrPas(AValue); g_free(AValue); end; end; function TKeyFile.ReadLocaleString(const Section, Ident, Default: String): String; var AValue: Pgchar; begin AValue:= g_key_file_get_locale_string(FGKeyFile, Pgchar(Section), Pgchar(Ident), nil, nil); if (AValue = nil) then Result:= Default else begin Result:= StrPas(AValue); g_free(AValue); end; end; function TKeyFile.ReadStringList(const Section, Ident: String): TDynamicStringArray; var ALength: gsize; AIndex: Integer; AValue: PPgchar; begin AValue:= g_key_file_get_string_list(FGKeyFile, Pgchar(Section), Pgchar(Ident), @ALength, nil); if Assigned(AValue) then begin SetLength(Result, ALength); for AIndex:= 0 to Pred(Integer(ALength)) do begin Result[AIndex]:= StrPas(AValue[AIndex]); end; g_strfreev(AValue); end; end; procedure TKeyFile.WriteString(const Section, Ident, Value: String); begin end; procedure TKeyFile.ReadSection(const Section: string; Strings: TStrings); begin end; procedure TKeyFile.ReadSections(Strings: TStrings); begin end; procedure TKeyFile.ReadSectionValues(const Section: string; Strings: TStrings); begin end; procedure TKeyFile.EraseSection(const Section: string); begin end; procedure TKeyFile.DeleteKey(const Section, Ident: String); begin end; procedure TKeyFile.UpdateFile; begin end; end. �����������������������������������������������doublecmd-1.1.22/src/platform/unix/umagickwand.pas��������������������������������������������������0000644�0001750�0000144�00000017450�14743153644�021212� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- ImageMagick thumbnail provider Copyright (C) 2013-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uMagickWand; {$mode delphi} interface implementation uses LCLIntf, Classes, SysUtils, DynLibs, FileUtil, Types, Graphics, CTypes, DCOSUtils, DCConvertEncoding, uThumbnails, uDebug, uClassesEx, uGraphics, uMasks; const MagickFalse = 0; MagickTrue = 1; const libMagickWand: array[0..7] of String = ( 'libMagickWand-7.Q16.so.10', 'libMagickWand-7.Q16HDRI.so.10', 'libMagickWand-6.Q16.so.7', 'libMagickWand-6.Q16HDRI.so.7', 'libMagickWand-6.Q16.so.6', 'libMagickWand-6.Q16HDRI.so.6', 'libMagickWand-6.Q16.so.3', 'libMagickWand-6.Q16HDRI.so.3' ); type PMagickWand = Pointer; MagickBooleanType = culong; ExceptionType = Word; PExceptionType = ^ExceptionType; {$PACKENUM 4} type FilterTypes = ( UndefinedFilter, PointFilter, BoxFilter, TriangleFilter, HermiteFilter, HannFilter, HammingFilter, BlackmanFilter, GaussianFilter, QuadraticFilter, CubicFilter, CatromFilter, MitchellFilter, JincFilter, SincFilter, SincFastFilter, KaiserFilter, WelchFilter, ParzenFilter, BohmanFilter, BartlettFilter, LagrangeFilter, LanczosFilter ); var MagickWand: TLibHandle; MaskList: TMaskList = nil; var MagickWandGenesis: procedure(); cdecl; MagickWandTerminus: procedure(); cdecl; NewMagickWand: function(): PMagickWand; cdecl; DestroyMagickWand: function(wand: PMagickWand): PMagickWand; cdecl; MagickGetException: function(wand: PMagickWand; severity: PExceptionType): PAnsiChar; cdecl; MagickRelinquishMemory: function(resource: Pointer): Pointer; cdecl; MagickReadImage: function(wand: PMagickWand; const filename: PAnsiChar): MagickBooleanType; cdecl; MagickGetImageWidth: function(wand: PMagickWand): csize_t; cdecl; MagickGetImageHeight: function(wand: PMagickWand): csize_t; cdecl; MagickResizeImageOld: function(wand: PMagickWand; const columns, rows: csize_t; const filter: FilterTypes; const blur: double): MagickBooleanType; cdecl; MagickResizeImageNew: function(wand: PMagickWand; const columns, rows: csize_t; const filter: FilterTypes): MagickBooleanType; cdecl; MagickSetImageFormat: function(wand: PMagickWand; const format: PAnsiChar): MagickBooleanType; cdecl; MagickGetImageBlob: function(wand: PMagickWand; length: Pcsize_t): PByte; cdecl; procedure RaiseWandException(Wand: PMagickWand); var Description: PAnsiChar; Severity: ExceptionType; ExceptionMessage: AnsiString; begin Description:= MagickGetException(Wand, @Severity); ExceptionMessage:= AnsiString(Description); Description:= MagickRelinquishMemory(Description); Raise Exception.Create(ExceptionMessage); end; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var Memory: PByte; Wand: PMagickWand; MemorySize: csize_t; Width, Height: csize_t; BlobStream: TBlobStream; Status: MagickBooleanType; Bitmap: TPortableNetworkGraphic; begin Result:= nil; if MaskList.Matches(aFileName) then begin // DCDebug('GetThumbnail start: ' + IntToStr(GetTickCount)); Wand:= NewMagickWand; try Status:= MagickReadImage(Wand, PAnsiChar(CeUtf8ToSys(aFileName))); try if (Status = MagickFalse) then RaiseWandException(Wand); // Get image width and height Width:= MagickGetImageWidth(Wand); Height:= MagickGetImageHeight(Wand); if (Width > aSize.cx) or (Height > aSize.cy) then begin // Calculate aspect width and height of thumb aSize:= TThumbnailManager.GetPreviewScaleSize(Width, Height); // Create image thumbnail if Assigned(MagickResizeImageNew) then Status:= MagickResizeImageNew(Wand, aSize.cx, aSize.cy, LanczosFilter) else begin Status:= MagickResizeImageOld(Wand, aSize.cx, aSize.cy, LanczosFilter, 1.0); end; if (Status = MagickFalse) then RaiseWandException(Wand); end; Status:= MagickSetImageFormat(Wand, 'PNG32'); if (Status = MagickFalse) then RaiseWandException(Wand); Memory:= MagickGetImageBlob(Wand, @MemorySize); if Assigned(Memory) then try BlobStream:= TBlobStream.Create(Memory, MemorySize); Bitmap:= TPortableNetworkGraphic.Create; try Bitmap.LoadFromStream(BlobStream); Result:= Graphics.TBitmap.Create; BitmapAssign(Result, Bitmap); except FreeAndNil(Result); end; Bitmap.Free; BlobStream.Free; finally MagickRelinquishMemory(Memory); end; except on E: Exception do DCDebug('ImageMagick: ' + E.Message); end; finally Wand:= DestroyMagickWand(Wand); // DCDebug('GetThumbnail finish: ' + IntToStr(GetTickCount)); end; end; end; procedure Initialize; var Version: Integer; LibraryName: AnsiString; begin for Version:= 0 to High(libMagickWand) do begin LibraryName:= libMagickWand[Version]; MagickWand:= LoadLibrary(LibraryName); if (MagickWand <> NilHandle) then Break; end; if (MagickWand <> NilHandle) then try @MagickWandGenesis:= SafeGetProcAddress(MagickWand, 'MagickWandGenesis'); @MagickWandTerminus:= SafeGetProcAddress(MagickWand, 'MagickWandTerminus'); @NewMagickWand:= SafeGetProcAddress(MagickWand, 'NewMagickWand'); @DestroyMagickWand:= SafeGetProcAddress(MagickWand, 'DestroyMagickWand'); @MagickGetException:= SafeGetProcAddress(MagickWand, 'MagickGetException'); @MagickRelinquishMemory:= SafeGetProcAddress(MagickWand, 'MagickRelinquishMemory'); @MagickReadImage:= SafeGetProcAddress(MagickWand, 'MagickReadImage'); @MagickGetImageWidth:= SafeGetProcAddress(MagickWand, 'MagickGetImageWidth'); @MagickGetImageHeight:= SafeGetProcAddress(MagickWand, 'MagickGetImageHeight'); if (LibraryName[15] = '6') then @MagickResizeImageOld:= SafeGetProcAddress(MagickWand, 'MagickResizeImage') else begin @MagickResizeImageNew:= SafeGetProcAddress(MagickWand, 'MagickResizeImage'); end; @MagickSetImageFormat:= SafeGetProcAddress(MagickWand, 'MagickSetImageFormat'); @MagickGetImageBlob:= SafeGetProcAddress(MagickWand, 'MagickGetImageBlob'); MagickWandGenesis; // Register thumbnail provider TThumbnailManager.RegisterProvider(@GetThumbnail); MaskList:= TMaskList.Create('*.xcf'); DCDebug('ImageMagick: ' + LibraryName); except FreeLibrary(MagickWand); MagickWand:= NilHandle; end; end; procedure Finalize; begin if (MagickWand <> NilHandle) then begin MaskList.Free; MagickWandTerminus; FreeLibrary(MagickWand); end; end; initialization Initialize; finalization Finalize; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/umyunix.pas������������������������������������������������������0000644�0001750�0000144�00000044022�14743153644�020431� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains specific UNIX functions. Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uMyUnix; {$mode objfpc}{$H+} {$packrecords c} {$IF NOT DEFINED(LINUX)} {$DEFINE FPC_USE_LIBC} {$ENDIF} interface uses Classes, SysUtils, BaseUnix, CTypes, DCBasicTypes, uDrive; const libc = 'c'; _PATH_FSTAB = '/etc/fstab'; _PATH_MOUNTED = '/etc/mtab'; type TDesktopEnvironment = ( DE_UNKNOWN = 0, DE_KDE = 1, DE_GNOME = 2, DE_XFCE = 3, DE_LXDE = 4, DE_MATE = 5, DE_CINNAMON = 6, DE_LXQT = 7, DE_FLY = 8, DE_FLATPAK = 9 ); const DesktopName: array[TDesktopEnvironment] of String = ( 'Unknown', 'KDE', 'GNOME', 'Xfce', 'LXDE', 'MATE', 'Cinnamon', 'LXQt', 'Fly', 'Flatpak' ); {$IF DEFINED(LINUX)} type PIOFILE = Pointer; PFILE = PIOFILE; //en Mount entry record mntent = record mnt_fsname: PChar; //en< name of mounted file system mnt_dir: PChar; //en< file system path prefix mnt_type: PChar; //en< mount type mnt_opts: PChar; //en< mount options mnt_freq: LongInt; //en< dump frequency in days mnt_passno: LongInt; //en< pass number on parallel fsck end; TMountEntry = mntent; PMountEntry = ^TMountEntry; {en Opens the file system description file @param(filename File system description file) @param(mode Type of access) @returns(The function returns a file pointer to file system description file) } function setmntent(const filename: PChar; const mode: PChar): PFILE; cdecl; external libc name 'setmntent'; {en Reads the next line from the file system description file @param(stream File pointer to file system description file) @returns(The function returns a pointer to a structure containing the broken out fields from a line in the file) } function getmntent(stream: PFILE): PMountEntry; cdecl; external libc name 'getmntent'; {en Closes the file system description file @param(stream File pointer to file system description file) @returns(The function always returns 1) } function endmntent(stream: PFILE): LongInt; cdecl; external libc name 'endmntent'; {$ENDIF} function fpSystemStatus(Command: string): cint; function GetDesktopEnvironment: TDesktopEnvironment; function FileIsLinkToFolder(const FileName: String; out LinkTarget: String): Boolean; {en Checks if file is executable or script @param(FileName File name) @returns(The function returns @true if successful, @false otherwise) } function FileIsUnixExecutable(const Filename: String): Boolean; function FindExecutableInSystemPath(var FileName: String): Boolean; function ExecutableInSystemPath(const FileName: String): Boolean; function GetDefaultAppCmd(const FileName: String): String; function GetFileMimeType(const FileName: String): String; {en Fix separators in case they are broken UTF-8 characters (FPC takes only first byte as it doesn't support Unicode). } procedure FixDateTimeSeparators; function MountDrive(Drive: PDrive): Boolean; function UnmountDrive(Drive: PDrive): Boolean; function EjectDrive(Drive: PDrive): Boolean; function ExecuteCommand(Command: String; Args: TDynamicStringArray; StartPath: String): Boolean; {$IF DEFINED(BSD)} const MNT_WAIT = 1; // synchronously wait for I/O to complete MNT_NOWAIT = 2; // start all I/O, but do not wait for it MNT_LAZY = 3; // push data not written by filesystem syncer MNT_SUSPEND = 4; // suspend file system after sync type TFSTab = record fs_spec: PChar; // block special device name fs_file: PChar; // file system path prefix fs_vfstype: PChar; // file system type, ufs, nfs fs_mntops: PChar; // mount options ala -o fs_type: PChar; // FSTAB_* from fs_mntops fs_freq: longint; // dump frequency, in days fs_passno: longint; // pass number on parallel fsc end; PFSTab = ^TFSTab; PStatFS = ^TStatFS; {$IF DEFINED(DARWIN)} function getfsstat(buf: pstatfs; bufsize: cint; flags: cint): cint; cdecl; external libc name 'getfsstat'; {$ELSE} function getfsstat(struct_statfs: PStatFS; const buffsize: int64; const int_flags: integer): integer; {$ENDIF} function getfsent(): PFSTab; cdecl; external libc name 'getfsent'; procedure endfsent(); cdecl; external libc name 'endfsent'; {$ENDIF} var DesktopEnv: TDesktopEnvironment = DE_UNKNOWN; implementation uses URIParser, Unix, Process, LazUTF8, DCOSUtils, DCClassesUtf8, DCStrUtils, LazLogger, DCUnix, uDCUtils, uOSUtils {$IF (NOT DEFINED(FPC_USE_LIBC)) or (DEFINED(BSD) AND NOT DEFINED(DARWIN))} , SysCall {$ENDIF} {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} , uFontConfig, uMimeActions, uMimeType, uGVolume {$ENDIF} {$IFDEF DARWIN} , uMyDarwin {$ENDIF} {$IFDEF LINUX} , uUDisks2 {$ENDIF} ; {$IF DEFINED(BSD) AND NOT DEFINED(DARWIN)} function getfsstat(struct_statfs: PStatFS; const buffsize: int64; const int_flags: integer): integer; {$IF DEFINED(FREEBSD) AND ((fpc_version<2) OR ((fpc_version=2) AND (fpc_release<5)))} const syscall_nr_getfsstat = 18; // was not defined before fpc 2.5.1 {$ENDIF} begin Result := do_syscall(syscall_nr_getfsstat, TSysParam(struct_statfs), TSysParam(buffsize), TSysParam(int_flags)); end; {$ENDIF} function fpSystemStatus(Command: string): cint; begin Result := fpSystem(UTF8ToSys(Command)); if wifexited(Result) then Result := wexitStatus(Result); end; {$IFDEF LINUX} var HavePMount: Boolean = False; procedure CheckPMount; begin // Check pumount first because Puppy Linux has another tool named pmount HavePMount := (fpSystemStatus('pumount --version > /dev/null 2>&1') = 0) and (fpSystemStatus('pmount --version > /dev/null 2>&1') = 0); end; {$ENDIF LINUX} function GetDesktopEnvironment: TDesktopEnvironment; var I: Integer; DesktopSession: String; const EnvVariable: array[0..2] of String = ('XDG_CURRENT_DESKTOP', 'XDG_SESSION_DESKTOP', 'DESKTOP_SESSION'); begin if fpGetEnv(PAnsiChar('FLATPAK_ID')) <> nil then begin Exit(DE_FLATPAK); end; Result:= DE_UNKNOWN; for I:= Low(EnvVariable) to High(EnvVariable) do begin DesktopSession:= GetEnvironmentVariable(EnvVariable[I]); if Length(DesktopSession) = 0 then Continue; DesktopSession:= LowerCase(DesktopSession); if Pos('kde', DesktopSession) <> 0 then Exit(DE_KDE); if Pos('plasma', DesktopSession) <> 0 then Exit(DE_KDE); if Pos('gnome', DesktopSession) <> 0 then Exit(DE_GNOME); if Pos('xfce', DesktopSession) <> 0 then Exit(DE_XFCE); if Pos('lxde', DesktopSession) <> 0 then Exit(DE_LXDE); if Pos('lxqt', DesktopSession) <> 0 then Exit(DE_LXQT); if Pos('mate', DesktopSession) <> 0 then Exit(DE_MATE); if Pos('cinnamon', DesktopSession) <> 0 then Exit(DE_CINNAMON); if Pos('fly', DesktopSession) <> 0 then Exit(DE_FLY); end; if GetEnvironmentVariable('KDE_FULL_SESSION') <> '' then Exit(DE_KDE); if GetEnvironmentVariable('GNOME_DESKTOP_SESSION_ID') <> '' then Exit(DE_GNOME); if GetEnvironmentVariable('_LXSESSION_PID') <> '' then Exit(DE_LXDE); end; function FileIsLinkToFolder(const FileName: String; out LinkTarget: String): Boolean; var StatInfo: BaseUnix.Stat; iniDesktop: TIniFileEx = nil; begin Result:= False; try iniDesktop:= TIniFileEx.Create(FileName, fmOpenRead); try if iniDesktop.ReadString('Desktop Entry', 'Type', EmptyStr) = 'Link' then begin LinkTarget:= iniDesktop.ReadString('Desktop Entry', 'URL', EmptyStr); if not URIToFilename(LinkTarget, LinkTarget) then Exit; if fpLStat(UTF8ToSys(LinkTarget), StatInfo) <> 0 then Exit; Result:= FPS_ISDIR(StatInfo.st_mode); end; finally FreeAndNil(iniDesktop); end; except // Ignore end; end; function FileIsUnixExecutable(const FileName: String): Boolean; var Info : Stat; dwSign : LongWord; fsExeScr : TFileStreamEx = nil; begin // First check FileName is not a directory and then check if executable Result:= (fpStat(UTF8ToSys(FileName), Info) <> -1) and (FPS_ISREG(Info.st_mode)) and (Info.st_size >= SizeOf(dwSign)) and (BaseUnix.fpAccess(UTF8ToSys(FileName), BaseUnix.X_OK) = 0); if Result then try fsExeScr := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try dwSign := fsExeScr.ReadDWord; // ELF or #! Result := ((dwSign = NtoBE($7F454C46)) or (Lo(dwSign) = NtoBE($2321))); finally fsExeScr.Free; end; except Result:= False; end; end; function FindExecutableInSystemPath(var FileName: String): Boolean; var I: Integer; Path, FullName: String; Value: TDynamicStringArray; begin Path:= GetEnvironmentVariable('PATH'); Value:= SplitString(Path, PathSeparator); for I:= Low(Value) to High(Value) do begin FullName:= IncludeTrailingPathDelimiter(Value[I]) + FileName; if fpAccess(FullName, X_OK) = 0 then begin FileName:= FullName; Exit(True); end; end; Result:= False; end; function ExecutableInSystemPath(const FileName: String): Boolean; var FullName: String; begin FullName:= FileName; Result:= FindExecutableInSystemPath(FullName); end; function GetDefaultAppCmd(const FileName: String): String; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} var Filenames: TStringList; begin Filenames:= TStringList.Create; Filenames.Add(FileName); Result:= uMimeActions.GetDefaultAppCmd(Filenames); if Length(Result) = 0 then Result:= 'xdg-open ' + QuoteStr(FileName); FreeAndNil(Filenames); end; {$ELSEIF DEFINED(HAIKU)} begin Result:= '/bin/open ' + QuoteStr(FileName); end; {$ELSE} begin Result:= 'xdg-open ' + QuoteStr(FileName); end; {$ENDIF} function GetFileMimeType(const FileName: String): String; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} begin Result:= uMimeType.GetFileMimeType(FileName); end; {$ELSE} begin Result:= EmptyStr; end; {$ENDIF} procedure FixDateTimeSeparators; var TimeEnv: String; begin TimeEnv := GetEnvironmentVariable('LC_TIME'); if TimeEnv = EmptyStr then TimeEnv := GetEnvironmentVariable('LC_ALL'); if TimeEnv = EmptyStr then TimeEnv := GetEnvironmentVariable('LANG'); if TimeEnv <> EmptyStr then begin TimeEnv := upcase(TimeEnv); if StrEnds(TimeEnv, 'UTF-8') or StrEnds(TimeEnv, 'UTF8') then with FormatSettings do begin if Ord(DateSeparator) > $7F then DateSeparator := '/'; if Ord(TimeSeparator) > $7F then TimeSeparator := ':'; end; end; end; function Mount(const Path: String; Timeout: Integer): Boolean; var Message: String; Handler: TMethod; Process: TProcess; Index: Integer = 0; procedure ProcessForkEvent{$IF (FPC_FULLVERSION >= 30000)}(Self, Sender : TObject){$ENDIF}; begin if (setpgid(0, 0) < 0) then fpExit(127); end; begin Process:= TProcess.Create(nil); try Handler.Data:= Process; Process.Executable:= 'mount'; Process.Parameters.Add(Path); Handler.Code:= @ProcessForkEvent; {$IF (FPC_FULLVERSION >= 30000)} Process.OnForkEvent:= TProcessForkEvent(Handler); {$ELSE} Process.OnForkEvent:= TProcessForkEvent(@ProcessForkEvent); {$ENDIF} Process.Options:= Process.Options + [poUsePipes, poStderrToOutPut]; try Process.Execute; while Process.Running do begin Inc(Index); Sleep(100); if (Index > Timeout) then begin Process.Terminate(-1); fpKill(-Process.Handle, SIGTERM); Exit(False); end; Process.Input.Write(#13#10, 2); if (Process.Output.NumBytesAvailable > 0) then begin SetLength(Message, Process.Output.NumBytesAvailable); Process.Output.Read(Message[1], Length(Message)); Write(Message); end; end; {$IF (FPC_FULLVERSION >= 30000)} Result:= (Process.ExitCode = 0); {$ELSE} Result:= (Process.ExitStatus = 0); {$ENDIF} except Result:= False; end; finally Process.Free; end; end; function MountDrive(Drive: PDrive): Boolean; {$IFDEF LINUX} var MountPath: String = ''; {$ENDIF} begin if not Drive^.IsMounted then begin {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)} Result := False; // If Path is not empty "mount" can mount it because it has a destination path from fstab. if Drive^.Path <> EmptyStr then {$ENDIF} Result := Mount(Drive^.Path, 300); {$IF DEFINED(LINUX)} if not Result and HasUDisks2 then begin Result:= uUDisks2.Mount(Drive^.DeviceId, MountPath); if Result then begin Drive^.Path:= MountPath; DebugLn(Drive^.DeviceId, ' -> ', MountPath); end end; if not Result and HavePMount and Drive^.IsMediaRemovable then Result := fpSystemStatus('pmount ' + Drive^.DeviceId) = 0; {$ELSEIF DEFINED(DARWIN)} if not Result then Result := fpSystemStatus('diskutil mount ' + Drive^.DeviceId) = 0; {$ENDIF} end else Result := True; end; function UnmountDrive(Drive: PDrive): Boolean; begin if Drive^.IsMounted then begin {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} if Drive^.DriveType = dtSpecial then begin Exit(uGVolume.Unmount(Drive^.Path)); end; {$ENDIF} {$IF DEFINED(LINUX)} Result := False; if HasUDisks2 then Result := uUDisks2.Unmount(Drive^.DeviceId); if not Result and HavePMount and Drive^.IsMediaRemovable then Result := fpSystemStatus('pumount ' + Drive^.DeviceId) = 0; if not Result then {$ELSEIF DEFINED(DARWIN)} Result := unmountAndEject( Drive^.Path ); if not Result then {$ENDIF} Result := fpSystemStatus('umount ' + Drive^.Path) = 0; end else Result := True; end; function EjectDrive(Drive: PDrive): Boolean; begin {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} Result:= uGVolume.Eject(Drive^.Path); if not Result then {$ENDIF} {$IF DEFINED(LINUX)} Result := False; if HasUDisks2 then Result := uUDisks2.Eject(Drive^.DeviceId); if not Result then {$ELSEIF DEFINED(DARWIN)} Result := unmountAndEject( Drive^.Path ); if not Result then {$ENDIF} Result := fpSystemStatus('eject ' + Drive^.DeviceId) = 0; end; {en Waits for a child process to finish and collects its exit status, causing it to be released by the system (prevents defunct processes). Instead of the wait-thread we could just ignore or handle SIGCHLD signal for the process, but this way we don't interfere with the signal handling. The downside is that there's a thread for every child process running. Another method is to periodically do a cleanup, for example from OnIdle or OnTimer event. Remember PIDs of spawned child processes and when cleaning call FpWaitpid(PID, nil, WNOHANG) on each PID. Downside is they are not released immediately after the child process finish (may be relevant if we want to display exit status to the user). } function WaitForPidThread(Parameter : Pointer): PtrInt; var Status : cInt = 0; PID: PtrInt absolute Parameter; begin while (FpWaitPid(PID, @Status, 0) = -1) and (fpgeterrno() = ESysEINTR) do; WriteLn('Process ', PID, ' finished, exit status ', Status); Result:= Status; EndThread(Result); end; function ExecuteCommand(Command: String; Args: TDynamicStringArray; StartPath: String): Boolean; var pid : TPid; begin {$IFDEF DARWIN} // If we run application bundle (*.app) then // execute it by 'open -a' command (see 'man open' for details) if StrEnds(Command, '.app') then begin SetLength(Args, Length(Args) + 2); for pid := High(Args) downto Low(Args) + 2 do Args[pid]:= Args[pid - 2]; Args[0] := '-a'; Args[1] := Command; Command := 'open'; end; {$ENDIF} pid := fpFork; if pid = 0 then begin { Set the close-on-exec flag to all } FileCloseOnExecAll; { Set child current directory } if Length(StartPath) > 0 then fpChdir(StartPath); { The child does the actual exec, and then exits } if FpExecLP(Command, Args) = -1 then DebugLn('Execute error %d: %s', [fpgeterrno, SysErrorMessage(fpgeterrno)]); { If the FpExecLP fails, we return an exitvalue of 127, to let it be known } fpExit(127); end else if pid = -1 then { Fork failed } begin DebugLn('Fork failed: ' + Command, LineEnding, SysErrorMessage(fpgeterrno)); end else if pid > 0 then { Parent } begin {$PUSH}{$WARNINGS OFF}{$HINTS OFF} BeginThread(@WaitForPidThread, Pointer(PtrInt(pid))); {$POP} end; Result := (pid > 0); end; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} function GetFontName(const AName: String): String; var Res: TFcResult; AFont: PFcPattern; AFontName: PFcChar8; APattern: PFcPattern; begin Result:= AName; APattern:= FcNameParse(PFcChar8(AName)); if Assigned(APattern) then begin FcConfigSubstitute(nil, APattern, FcMatchPattern); FcDefaultSubstitute(APattern); AFont:= FcFontMatch(nil, APattern, @Res); if Assigned(AFont) then begin AFontName:= FcPatternFormat(AFont, '%{fullname}'); if Assigned(AFontName) then begin Result:= StrPas(AFontName); FcStrFree(AFontName); end; FcPatternDestroy(AFont); end; FcPatternDestroy(APattern); end; end; initialization DesktopEnv := GetDesktopEnvironment; {$IFDEF LINUX} CheckPMount; {$ENDIF} if LoadFontConfigLib('libfontconfig.so.1') then begin MonoSpaceFont:= GetFontName(MonoSpaceFont); UnLoadFontConfigLib; end; {$ENDIF} end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uoverlayscrollbarfix.pas�����������������������������������������0000644�0001750�0000144�00000000737�14743153644�023201� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uOverlayScrollBarFix; {$mode objfpc}{$H+} interface implementation uses BaseUnix, XLib; function setenv(const name, value: pchar; overwrite: longint): longint; cdecl; external 'c' name 'setenv'; initialization setenv('LIBOVERLAY_SCROLLBAR', '0', 1); if (fpGetEnv(PAnsiChar('GTK_IM_MODULE')) = 'xim') then begin setenv('GTK_IM_MODULE', '', 1); WriteLn('Warning: Unsupported input method (xim)'); end; WriteLn('XInitThreads: ', XInitThreads); end. ���������������������������������doublecmd-1.1.22/src/platform/unix/upipeserver.pas��������������������������������������������������0000644�0001750�0000144�00000007346�14743153644�021274� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Unix implementation of one-way IPC between 2 processes Copyright (C) 2015-2021 Alexander Koblov (alexx2000@mail.ru) Based on simpleipc.inc from Free Component Library. Copyright (c) 2005 by Michael Van Canneyt, member of the Free Pascal development team See the file COPYING.FPC.txt, included in this distribution, for details about the copyright. 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. } unit uPipeServer; {$mode objfpc}{$H+} interface uses Classes, SysUtils; function GetPipeFileName(const FileName: String; Global : Boolean): String; implementation uses SimpleIPC, BaseUnix, uPollThread {$IF DEFINED(DARWIN)} , uMyDarwin {$ELSE} , uXdg {$ENDIF} ; ResourceString SErrFailedToCreatePipe = 'Failed to create named pipe: %s'; SErrFailedToRemovePipe = 'Failed to remove named pipe: %s'; Type { TPipeServerComm } TPipeServerComm = Class(TIPCServerComm) Private FFileName: String; FStream: TFileStream; private procedure OwnerReadMessage; procedure Handler(Sender: TObject); Public Constructor Create(AOWner : TSimpleIPCServer); override; Procedure StartServer; override; Procedure StopServer; override; Function PeekMessage(TimeOut : Integer) : Boolean; override; Procedure ReadMessage ; override; Function GetInstanceID : String;override; Property FileName : String Read FFileName; Property Stream : TFileStream Read FStream; end; function GetPipeFileName(const FileName: String; Global : Boolean): String; begin {$IF DEFINED(DARWIN)} Result:= NSGetTempPath + FileName; {$ELSEIF DEFINED(HAIKU)} Result:= IncludeTrailingBackslash(GetTempDir) + FileName; {$ELSE} Result:= IncludeTrailingBackslash(GetUserRuntimeDir) + FileName; {$ENDIF} Result:= Result + '.pipe' end; { TPipeServerComm } procedure TPipeServerComm.OwnerReadMessage; begin {$IF FPC_FULLVERSION >= 30200} ReadMessage; {$ENDIF} Owner.ReadMessage; end; procedure TPipeServerComm.Handler(Sender: TObject); begin TThread.Synchronize(nil, @OwnerReadMessage); end; constructor TPipeServerComm.Create(AOWner: TSimpleIPCServer); begin inherited Create(AOWner); FFileName:= Owner.ServerID; if not Owner.Global then FFileName:= FFileName + '-' + IntToStr(fpGetPID); if FFileName[1] <> '/' then FFileName:= GetPipeFileName(FFileName, Owner.Global); end; procedure TPipeServerComm.StartServer; const PrivateRights = S_IRUSR or S_IWUSR; GlobalRights = PrivateRights or S_IRGRP or S_IWGRP or S_IROTH or S_IWOTH; Rights : Array [Boolean] of Integer = (PrivateRights,GlobalRights); begin If not FileExists(FFileName) then If (fpmkFifo(FFileName, &600)<>0) then DoError(SErrFailedToCreatePipe,[FFileName]); FStream:=TFileStream.Create(FFileName,fmOpenReadWrite+fmShareDenyNone,Rights[Owner.Global]); AddPoll(FStream.Handle, POLLIN, @Handler, False); end; procedure TPipeServerComm.StopServer; begin RemovePoll(FStream.Handle); FreeAndNil(FStream); if Not DeleteFile(FFileName) then DoError(SErrFailedtoRemovePipe,[FFileName]); end; function TPipeServerComm.PeekMessage(TimeOut: Integer): Boolean; Var FDS : TFDSet; begin fpfd_zero(FDS); fpfd_set(FStream.Handle,FDS); Result:=fpSelect(FStream.Handle+1,@FDS,Nil,Nil,TimeOut)>0; end; procedure TPipeServerComm.ReadMessage; var Hdr : TMsgHeader; begin FStream.ReadBuffer(Hdr,SizeOf(Hdr)); PushMessage(Hdr,FStream); end; function TPipeServerComm.GetInstanceID: String; begin Result:=IntToStr(fpGetPID); end; initialization DefaultIPCServerClass:= TPipeServerComm; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/upollthread.pas��������������������������������������������������0000644�0001750�0000144�00000010051�14743153644�021231� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uPollThread; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Unix, BaseUnix; procedure AddPoll(fd: cint; events: cshort; handler: TNotifyEvent; CloseOnDestroy: Boolean = True); procedure RemovePoll(fd: cint); implementation uses DCUnix, uDebug; type { TPollRecord } TPollRecord = record handler: TNotifyEvent; CloseOnDestroy: Boolean; end; { TPollThread } TPollThread = class(TThread) private FCount: Cardinal; FEventPipe: TFilDes; FDesc: array of tpollfd; FHandler: array of TPollRecord; protected procedure Refresh; procedure Execute; override; procedure Clear(Sender: TObject); public procedure AddPoll(fd: cint; events: cshort; handler: TNotifyEvent; CloseOnDestroy: Boolean = True); constructor Create; reintroduce; destructor Destroy; override; end; var Mutex: TRTLCriticalSection; PollThread: TPollThread = nil; procedure Print(const sMessage: String); begin DCDebug('PollThread: ', sMessage); end; procedure AddPoll(fd: cint; events: cshort; handler: TNotifyEvent; CloseOnDestroy: Boolean); begin EnterCriticalSection(Mutex); try if not Assigned(PollThread) then begin PollThread:= TPollThread.Create; end; PollThread.AddPoll(fd, events, handler, CloseOnDestroy); Print('AddPoll ' + IntToStr(fd)); finally LeaveCriticalSection(Mutex); end; end; procedure RemovePoll(fd: cint); var Index: Integer; begin EnterCriticalSection(Mutex); try for Index:= 0 to PollThread.FCount - 1 do begin if PollThread.FDesc[Index].fd = fd then begin PollThread.FDesc[Index].events:= 0; Break; end; end; Print('RemovePoll ' + IntToStr(fd)); finally LeaveCriticalSection(Mutex); end; end; { TPollThread } procedure TPollThread.Clear(Sender: TObject); var Symbol: Byte = 0; begin // Clear pipe while FileRead(FEventPipe[0], Symbol, 1) <> -1 do; end; procedure TPollThread.Refresh; var Symbol: Byte = 0; begin FileWrite(FEventPipe[1], Symbol, 1); end; procedure TPollThread.Execute; var i: cint; ret: cint; begin while not Terminated do begin repeat ret:= fpPoll(@FDesc[0], FCount, -1); until (ret <> -1) or (fpGetErrNo <> ESysEINTR); if (ret = -1) then begin Print(SysErrorMessage(fpGetErrNo)); Exit; end; for i := 0 to FCount - 1 do begin if (FDesc[i].events and FDesc[i].revents <> 0) then begin FHandler[i].handler(Self); end; end; end; end; procedure TPollThread.AddPoll(fd: cint; events: cshort; handler: TNotifyEvent; CloseOnDestroy: Boolean); var NewLength: Integer; begin NewLength:= FCount + 1; SetLength(FDesc, NewLength); SetLength(FHandler, NewLength); FDesc[FCount].fd:= fd; FDesc[FCount].events:= events; FHandler[FCount].handler:= handler; FHandler[FCount].CloseOnDestroy:= CloseOnDestroy; InterLockedIncrement(FCount); if FCount = 2 then begin Start; Print('Start polling'); end; Refresh; end; constructor TPollThread.Create; begin inherited Create(True); // Create pipe for user triggered fake event FEventPipe[0] := -1; FEventPipe[1] := -1; if fpPipe(FEventPipe) < 0 then Print(SysErrorMessage(fpGetErrNo)) else begin // Set both ends of pipe non blocking FileCloseOnExec(FEventPipe[0]); FileCloseOnExec(FEventPipe[1]); FpFcntl(FEventPipe[0], F_SetFl, FpFcntl(FEventPipe[0], F_GetFl) or O_NONBLOCK); FpFcntl(FEventPipe[1], F_SetFl, FpFcntl(FEventPipe[1], F_GetFl) or O_NONBLOCK); end; Self.AddPoll(FEventPipe[0], POLLIN, @Clear, True); end; destructor TPollThread.Destroy; var Index: Integer; begin Terminate; Refresh; inherited Destroy; // Close both ends of pipe if FEventPipe[1] <> -1 then begin FileClose(FEventPipe[1]); FEventPipe[1] := -1; end; for Index:= 0 to FCount - 1 do begin if FHandler[Index].CloseOnDestroy then FileClose(FDesc[Index].fd); end; Print('Finish polling'); end; initialization InitCriticalSection(Mutex); finalization PollThread.Free; DoneCriticalSection(Mutex); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/upython.pas������������������������������������������������������0000644�0001750�0000144�00000021114�14743153644�020416� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple interface to the Python language Copyright (C) 2014-2020 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uPython; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils, CTypes, DCOSUtils; type PPyObject = ^TPyObject; PPyTypeObject = ^TPyTypeObject; TPyTypeObject = record ob_refcnt: csize_t; ob_type: PPyTypeObject; ob_size: csize_t; tp_name: PAnsiChar; tp_basicsize, tp_itemsize: csize_t; //* Methods to implement standard operations */ tp_dealloc: procedure(obj: PPyObject); cdecl; end; TPyObject = record ob_refcnt: csize_t; ob_type: PPyTypeObject; end; var // pythonrun.h Py_Initialize: procedure; cdecl; Py_Finalize: procedure; cdecl; PyErr_Print: procedure; cdecl; PyRun_SimpleString: function(s: PAnsiChar): cint; cdecl; // import.h PyImport_Import: function(name: PPyObject): PPyObject; cdecl; // object.h PyCallable_Check: function(ob: PPyObject): cint; cdecl; PyObject_GetAttrString: function (ob: PPyObject; c: PAnsiChar): PPyObject; cdecl; // abstract.h PyObject_CallObject: function(callable_object, args: PPyObject): PPyObject; cdecl; PyObject_CallFunctionObjArgs: function(callable: PPyObject): PPyObject; cdecl; varargs; PyObject_CallMethodObjArgs: function(o, name: PPyObject): PPyObject; cdecl; varargs; // stringobject.h PyString_AsString: function(ob: PPyObject): PAnsiChar; cdecl; PyString_FromString: function(s: PAnsiChar): PPyObject; cdecl; // sysmodule.h PySys_SetArgvEx: procedure(argc: cint; argv: PPointer; updatepath: cint); cdecl; // listobject.h PyList_New: function(size: csize_t): PPyObject; cdecl; PyList_Size: function (ob: PPyObject): csize_t; cdecl; PyList_GetItem: function(ob: PPyObject; index: csize_t): PPyObject; cdecl; PyList_SetItem: function(ob: PPyObject; index: csize_t; item: PPyObject): cint; cdecl; // tupleobject.h PyTuple_New: function(size: csize_t): PPyObject; cdecl; PyTuple_SetItem: function(ob: PPyObject; index: csize_t; item: PPyObject): cint; cdecl; procedure Py_DECREF(op: PPyObject); procedure Py_XDECREF(op: PPyObject); function PyStringToString(S: PPyObject): String; function PythonInitialize(const Version: String): Boolean; procedure PythonFinalize; procedure PythonAddModulePath(const Path: String); function PythonLoadModule(const ModuleName: String): PPyObject; function PythonRunFunction(Module: PPyObject; const FunctionName: String): PPyObject; overload; function PythonRunFunction(Module: PPyObject; const FunctionName, FunctionArg: String): PPyObject; overload; function PythonRunFunction(Module: PPyObject; const FunctionName: String; FileList: TStrings): PPyObject; overload; var HasPython: Boolean = False; implementation uses dynlibs, dl, uMyUnix; procedure Py_DECREF(op: PPyObject); begin with op^ do begin Dec(ob_refcnt); if ob_refcnt = 0 then begin ob_type^.tp_dealloc(op); end; end; end; procedure Py_XDECREF(op: PPyObject); inline; begin if Assigned(op) then Py_DECREF(op); end; function PyStringToString(S: PPyObject): String; begin if not Assigned(S) then Result:= EmptyStr else begin Result:= StrPas(PyString_AsString(S)); Py_DECREF(S); end; end; function StringsToPyList(Strings: TStrings): PPyObject; var I: LongInt; begin Result:= PyList_New(Strings.Count); if not Assigned(Result) then Exit; for I:= 0 to Strings.Count - 1 do begin PyList_SetItem(Result, I, PyString_FromString(PAnsiChar(Strings[I]))); end; end; function PyObjectsToPyTuple(Values: array of PPyObject): PPyObject; var Index: csize_t; begin Result:= PyTuple_New(Length(Values)); if not Assigned(Result) then Exit; for Index:= Low(Values) to High(Values) do begin PyTuple_SetItem(Result, Index, Values[Index]); end; end; procedure PythonAddModulePath(const Path: String); begin PyRun_SimpleString('import sys'); PyRun_SimpleString(PAnsiChar('sys.path.append("' + Path + '")')); end; function PythonLoadModule(const ModuleName: String): PPyObject; var pyName: PPyObject; begin pyName:= PyString_FromString(PAnsiChar(ModuleName)); Result:= PyImport_Import(pyName); Py_DECREF(pyName); end; function PythonCallFunction(Module: PPyObject; const FunctionName: String; FunctionArg: PPyObject): PPyObject; overload; var pyFunc, pyArgs: PPyObject; begin if Assigned(Module) then begin pyFunc:= PyObject_GetAttrString(Module, PAnsiChar(FunctionName)); if (Assigned(pyFunc) and (PyCallable_Check(pyFunc) <> 0)) then begin if (FunctionArg = nil) then pyArgs:= nil else begin pyArgs:= PyObjectsToPyTuple([FunctionArg]); end; Result:= PyObject_CallObject(pyFunc, pyArgs); Py_XDECREF(pyArgs); if (Result = nil) then begin PyErr_Print() end; Py_DECREF(pyFunc); end; end; end; function PythonRunFunction(Module: PPyObject; const FunctionName: String): PPyObject; begin Result:= PythonCallFunction(Module, FunctionName, nil); end; function PythonRunFunction(Module: PPyObject; const FunctionName, FunctionArg: String): PPyObject; var pyArgs: PPyObject; begin pyArgs:= PyString_FromString(PAnsiChar(FunctionArg)); Result:= PythonCallFunction(Module, FunctionName, pyArgs); end; function PythonRunFunction(Module: PPyObject; const FunctionName: String; FileList: TStrings): PPyObject; var pyArgs: PPyObject; begin pyArgs:= StringsToPyList(FileList); Result:= PythonCallFunction(Module, FunctionName, pyArgs); end; var libpython: TLibHandle; function LoadPython(const Name: String): TLibHandle; var Handle: Pointer absolute Result; begin Handle:= dlopen(PAnsiChar(Name), RTLD_NOW or RTLD_GLOBAL); end; function PythonInitialize(const Version: String): Boolean; var PythonLibrary: String ='libpython%s.so.1.0'; begin libpython:= LoadPython(Format(PythonLibrary, [Version])); HasPython:= libpython <> NilHandle; if HasPython then try @Py_Initialize:= SafeGetProcAddress(libpython, 'Py_Initialize'); @Py_Finalize:= SafeGetProcAddress(libpython, 'Py_Finalize'); @PyErr_Print:= SafeGetProcAddress(libpython, 'PyErr_Print'); @PyRun_SimpleString:= SafeGetProcAddress(libpython, 'PyRun_SimpleString'); @PyImport_Import:= SafeGetProcAddress(libpython, 'PyImport_Import'); @PyCallable_Check:= SafeGetProcAddress(libpython, 'PyCallable_Check'); @PyObject_GetAttrString:= SafeGetProcAddress(libpython, 'PyObject_GetAttrString'); @PyObject_CallObject:= SafeGetProcAddress(libpython, 'PyObject_CallObject'); @PyObject_CallMethodObjArgs:= SafeGetProcAddress(libpython, 'PyObject_CallMethodObjArgs'); @PyObject_CallFunctionObjArgs:= SafeGetProcAddress(libpython, 'PyObject_CallFunctionObjArgs'); if (Version[1] < '3') then begin @PyString_AsString:= SafeGetProcAddress(libpython, 'PyString_AsString'); @PyString_FromString:= SafeGetProcAddress(libpython, 'PyString_FromString'); end else begin @PyString_AsString:= SafeGetProcAddress(libpython, 'PyUnicode_AsUTF8'); @PyString_FromString:= SafeGetProcAddress(libpython, 'PyUnicode_FromString'); end; @PySys_SetArgvEx:= SafeGetProcAddress(libpython, 'PySys_SetArgvEx'); @PyList_New:= SafeGetProcAddress(libpython, 'PyList_New'); @PyList_Size:= SafeGetProcAddress(libpython, 'PyList_Size'); @PyList_GetItem:= SafeGetProcAddress(libpython, 'PyList_GetItem'); @PyList_SetItem:= SafeGetProcAddress(libpython, 'PyList_SetItem'); @PyTuple_New:= SafeGetProcAddress(libpython, 'PyTuple_New'); @PyTuple_SetItem:= SafeGetProcAddress(libpython, 'PyTuple_SetItem'); // Initialize the Python interpreter Py_Initialize(); PySys_SetArgvEx(0, nil, 0); except HasPython:= False; FreeLibrary(libpython); end; Result:= HasPython; end; procedure PythonFinalize; begin if HasPython then begin Py_Finalize(); HasPython:= False; FreeLibrary(libpython); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uqt5workaround.pas�����������������������������������������������0000644�0001750�0000144�00000001255�14743153644�021726� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uQt5Workaround; {$mode objfpc}{$H+} interface implementation uses InitC, BaseUnix, LCLVersion; procedure _exit(status: cint); cdecl; external clib; function setenv(const name, value: pchar; overwrite: cint): cint; cdecl; external clib; {$IF LCL_FULLVERSION < 2020000} initialization if (LowerCase(fpGetEnv(PAnsiChar('XDG_SESSION_TYPE'))) = 'wayland') then setenv('QT_QPA_PLATFORM', 'xcb', 1); {$ENDIF} finalization // Workaround: https://doublecmd.sourceforge.io/mantisbt/view.php?id=2079 if (UpCase(fpGetEnv(PAnsiChar('XDG_CURRENT_DESKTOP'))) = 'KDE') then begin WriteLn('Warning: Skip libKF5IconThemes exit handler'); _exit(ExitCode); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/urabbitvcs.pas���������������������������������������������������0000644�0001750�0000144�00000035250�14743153644�021062� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uRabbitVCS; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Menus, Graphics, uPixMapManager; const RabbitVCSAddress = 'org.google.code.rabbitvcs.RabbitVCS.Checker'; RabbitVCSObject = '/org/google/code/rabbitvcs/StatusChecker'; RabbitVCSInterface = 'org.google.code.rabbitvcs.StatusChecker'; {$IF DEFINED(RabbitVCS)} type TVcsStatus = (vscNormal, vscModified, vscAdded, vscDeleted, vscIgnored, vscReadOnly, vscLocked, vscUnknown, vscMissing, vscReplaced, vscComplicated, vscCalculating, vscError, vscUnversioned); const VcsStatusText: array[TVcsStatus] of String = ( 'normal', 'modified', 'added', 'deleted', 'ignored', 'locked', 'locked', 'unknown', 'missing', 'replaced', 'complicated', 'calculating', 'error', 'unversioned' ); VcsStatusEmblems: array[TVcsStatus] of String = ( 'emblem-rabbitvcs-normal', 'emblem-rabbitvcs-modified', 'emblem-rabbitvcs-added', 'emblem-rabbitvcs-deleted', 'emblem-rabbitvcs-ignored', 'emblem-rabbitvcs-locked', 'emblem-rabbitvcs-locked', 'emblem-rabbitvcs-unknown', 'emblem-rabbitvcs-complicated', 'emblem-rabbitvcs-modified', 'emblem-rabbitvcs-complicated', 'emblem-rabbitvcs-calculating', 'emblem-rabbitvcs-error', 'emblem-rabbitvcs-unversioned' ); {en Requests a status check from the underlying status checker. } function CheckStatus(Path: String; Recurse: Boolean32 = False; Invalidate: Boolean32 = True; Summary: Boolean32 = False): string; {$ENDIF} procedure FillRabbitMenu(Menu: TPopupMenu; Paths: TStringList); var RabbitVCS: Boolean = False; implementation uses BaseUnix, Unix, DBus, LazLogger, DCUnix, DCClassesUtf8, uGlobs, uGlobsPaths, uMyUnix, uPython {$IF DEFINED(RabbitVCS)} , fpjson, jsonparser, jsonscanner {$ENDIF} {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} , uGObject2 {$ENDIF} ; const MODULE_NAME = 'rabbit-vcs'; var error: DBusError; RabbitGtk3: Boolean; conn: PDBusConnection = nil; PythonModule: PPyObject = nil; ShellContextMenu: PPyObject = nil; PythonVersion: array[Byte] of AnsiChar; procedure Initialize(Self: TObject); forward; procedure Print(const sMessage: String); begin DebugLn('RabbitVCS: ', sMessage); end; function CheckError(const sMessage: String; pError: PDBusError): Boolean; begin if (dbus_error_is_set(pError) <> 0) then begin Print(sMessage + ': ' + pError^.name + ' ' + pError^.message); dbus_error_free(pError); Result := True; end else Result := False; end; function CheckRabbit: Boolean; var service_exists: dbus_bool_t; begin dbus_error_init(@error); // Check if RabbitVCS service is running service_exists := dbus_bus_name_has_owner(conn, RabbitVCSAddress, @error); if CheckError('Cannot query RabbitVCS on DBUS', @error) then Result:= False else Result:= (service_exists <> 0); end; function CheckService: Boolean; var pyValue: PPyObject; begin Result:= CheckRabbit; if Result then Print('Service found running') else begin // Try to start RabbitVCS service pyValue:= PythonRunFunction(PythonModule, 'StartService'); Py_XDECREF(pyValue); Result:= CheckRabbit; if Result then Print('Service successfully started'); end; end; {$IF DEFINED(RabbitVCS)} function CheckStatus(Path: String; Recurse: Boolean32; Invalidate: Boolean32; Summary: Boolean32): string; var Return: Boolean; StringPtr: PAnsiChar; JAnswer : TJSONObject; VcsStatus: TVcsStatus; message: PDBusMessage; argsIter: DBusMessageIter; pending: PDBusPendingCall; arrayIter: DBusMessageIter; begin if not RabbitVCS then Exit; // Create a new method call and check for errors message := dbus_message_new_method_call(RabbitVCSAddress, // target for the method call RabbitVCSObject, // object to call on RabbitVCSInterface, // interface to call on 'CheckStatus'); // method name if (message = nil) then begin Print('Cannot create message "CheckStatus"'); Exit; end; try // Append arguments StringPtr:= PAnsiChar(Path); dbus_message_iter_init_append(message, @argsIter); if not RabbitGtk3 then Return:= (dbus_message_iter_append_basic(@argsIter, DBUS_TYPE_STRING, @StringPtr) <> 0) else begin Return:= (dbus_message_iter_open_container(@argsIter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, @arrayIter) <> 0); Return:= Return and (dbus_message_iter_append_fixed_array(@arrayIter, DBUS_TYPE_BYTE, @StringPtr, Length(Path)) <> 0); Return:= Return and (dbus_message_iter_close_container(@argsIter, @arrayIter) <> 0); end; Return:= Return and (dbus_message_iter_append_basic(@argsIter, DBUS_TYPE_BOOLEAN, @Recurse) <> 0); Return:= Return and (dbus_message_iter_append_basic(@argsIter, DBUS_TYPE_BOOLEAN, @Invalidate) <> 0); Return:= Return and (dbus_message_iter_append_basic(@argsIter, DBUS_TYPE_BOOLEAN, @Summary) <> 0); if not Return then begin Print('Cannot append arguments'); Exit; end; // Send message and get a handle for a reply if (dbus_connection_send_with_reply(conn, message, @pending, -1) = 0) then begin Print('Error sending message'); Exit; end; if (pending = nil) then begin Print('Pending call is null'); Exit; end; dbus_connection_flush(conn); finally dbus_message_unref(message); end; // Block until we recieve a reply dbus_pending_call_block(pending); // Get the reply message message := dbus_pending_call_steal_reply(pending); // Free the pending message handle dbus_pending_call_unref(pending); if (message = nil) then begin Print('Reply is null'); Exit; end; try // Read the parameters if (dbus_message_iter_init(message, @argsIter) <> 0) then begin if (dbus_message_iter_get_arg_type(@argsIter) = DBUS_TYPE_STRING) then begin dbus_message_iter_get_basic(@argsIter, @StringPtr); with TJSONParser.Create(StrPas(StringPtr), [joUTF8]) do try try JAnswer:= Parse as TJSONObject; try Result:= JAnswer.Strings['content']; if Result = 'unknown' then Exit(EmptyStr); finally JAnswer.Free; end; except Exit(EmptyStr); end; finally Free; end; for VcsStatus:= Low(TVcsStatus) to High(VcsStatus) do begin if (VcsStatusText[VcsStatus] = Result) then begin Result:= VcsStatusEmblems[VcsStatus]; Break; end; end; end; end; finally dbus_message_unref(message); end; end; {$ENDIF} procedure MenuClickHandler(Self, Sender: TObject); var pyMethod, pyArgs: PPyObject; MenuItem: TMenuItem absolute Sender; begin if Assigned(ShellContextMenu) then begin pyMethod:= PyString_FromString('Execute'); pyArgs:= PyString_FromString(PAnsiChar(MenuItem.Hint)); PyObject_CallMethodObjArgs(ShellContextMenu, pyMethod, pyArgs, nil); Py_XDECREF(pyArgs); Py_XDECREF(pyMethod); end; end; procedure FillRabbitMenu(Menu: TPopupMenu; Paths: TStringList); var Handler: TMethod; pyMethod, pyValue: PPyObject; procedure SetBitmap(Item: TMenuItem; const IconName: String); var bmpTemp: TBitmap; begin bmpTemp:= PixMapManager.LoadBitmapEnhanced(IconName, 16, True, clMenu); if Assigned(bmpTemp) then begin Item.Bitmap.Assign(bmpTemp); FreeAndNil(bmpTemp); end; end; procedure BuildMenu(pyMenu: PPyObject; BaseItem: TMenuItem); var Index: Integer; IconName: String; MenuItem: TMenuItem; pyItem, pyObject: PPyObject; begin for Index:= 0 to PyList_Size(pyMenu) - 1 do begin pyItem:= PyList_GetItem(pyMenu, Index); MenuItem:= TMenuItem.Create(BaseItem); pyObject:= PyObject_GetAttrString(pyItem, 'label'); MenuItem.Caption:= PyStringToString(pyObject); if MenuItem.Caption <> '-' then begin pyObject:= PyObject_GetAttrString(pyItem, 'identifier'); MenuItem.Hint:= PyStringToString(pyObject); if Length(MenuItem.Hint) > 0 then begin MenuItem.OnClick:= TNotifyEvent(Handler); end; pyObject:= PyObject_GetAttrString(pyItem, 'icon'); IconName:= PyStringToString(pyObject); if Length(IconName) > 0 then SetBitmap(MenuItem, IconName); end; pyObject:= PyObject_GetAttrString(pyItem, 'menu'); if Assigned(pyObject) and (PyList_Size(pyObject) > 0) then begin BuildMenu(pyObject, MenuItem); Py_DECREF(pyObject); end; BaseItem.Add(MenuItem); end; end; begin if not RabbitVCS then Exit; Py_XDECREF(ShellContextMenu); ShellContextMenu:= PythonRunFunction(PythonModule, 'GetContextMenu', Paths); if Assigned(ShellContextMenu) then begin Handler.Data:= Menu; Handler.Code:= @MenuClickHandler; pyMethod:= PyString_FromString('GetMenu'); pyValue:= PyObject_CallMethodObjArgs(ShellContextMenu, pyMethod, nil); if Assigned(pyValue) then begin BuildMenu(pyValue, Menu.Items); Py_DECREF(pyValue); end; Py_XDECREF(pyMethod); end; end; function FindPython(const Path: String): String; const Debian = '/usr/share/python3/debian_defaults'; begin Result:= ExtractFileName(Path); Result:= StringReplace(Result, 'python', '', []); if Length(Result) > 0 then begin if Result[1] = '2' then Exit; if fpAccess(Debian, F_OK) = 0 then try with TIniFileEx.Create(Debian, fmOpenRead) do try Result:= ReadString('DEFAULT', 'default-version', Result); Result:= StringReplace(Trim(Result), 'python', '', []); finally Free; end; except // Ignore end; end; end; function CheckPackage({%H-}Parameter : Pointer): PtrInt; const Path = '/usr/lib'; var DirPtr: pDir; Handler: TMethod; Directory: String; DirEntPtr: pDirent; PackageFormat: String; begin if fpAccess('/etc/debian_version', F_OK) = 0 then PackageFormat:= 'dist-packages/rabbitvcs' else begin PackageFormat:= 'site-packages/rabbitvcs'; end; DirPtr:= fpOpenDir(Path); if Assigned(DirPtr) then try DirEntPtr:= fpReadDir(DirPtr^); while DirEntPtr <> nil do begin if (DirEntPtr^.d_name <> '..') and (DirEntPtr^.d_name <> '.') then begin if FNMatch('python*', DirEntPtr^.d_name, 0) = 0 then begin Directory:= Path + PathDelim + DirEntPtr^.d_name; if (fpAccess(Directory + PathDelim + PackageFormat, F_OK) = 0) then begin PythonVersion:= FindPython(Directory); if Length(PythonVersion) > 0 then begin Handler.Data:= nil; Handler.Code:= @Initialize; while (gConfig = nil) do Sleep(10); TThread.Synchronize(nil, TThreadMethod(Handler)); end; Exit(0); end; end; end; DirEntPtr:= fpReadDir(DirPtr^); end; finally fpCloseDir(DirPtr^); end; Result:= 1; end; function CheckVersion: Boolean; var ATemp: AnsiString; pyModule: PPyObject; pyVersion: PPyObject; AVersion: TStringArray; Major, Minor, Micro: Integer; {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} GtkWidget: TGType; GtkClass, Gtk3: Pointer; {$ENDIF} begin Result:= False; pyModule:= PythonLoadModule('rabbitvcs'); if Assigned(pyModule) then begin pyVersion:= PythonRunFunction(pyModule, 'package_version'); if Assigned(pyVersion) then begin ATemp:= PyStringToString(pyVersion); AVersion:= ATemp.Split(['.']); Print('Version ' + ATemp); if (Length(AVersion) > 1) then begin Major:= StrToIntDef(AVersion[0], 0); Minor:= StrToIntDef(AVersion[1], 0); if (Length(AVersion) > 2) then Micro:= StrToIntDef(AVersion[2], 0) else begin Micro:= 0; end; // RabbitVCS migrated to GTK3 from version 0.17.1 RabbitGtk3:= (Major > 0) or (Minor > 17) or ((Minor = 17) and (Micro > 0)); {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} // Check GTK platform theme plugin GtkWidget:= g_type_from_name('GtkWidget'); Result:= (GtkWidget = 0); if not Result then begin GtkClass:= g_type_class_ref(GtkWidget); // Property 'expand' since GTK 3.0 Gtk3:= g_object_class_find_property(GtkClass, 'expand'); // RabbitVCS GTK version should be same as Qt platform theme plugin GTK version Result:= (RabbitGtk3 = Assigned(Gtk3)); end; {$ELSEIF DEFINED(LCLGTK2)} Result:= not RabbitGTK3; {$ELSEIF DEFINED(LCLGTK3)} Result:= RabbitGTK3; {$ELSE} Result:= True {$ENDIF} end; end; end; end; procedure Initialize(Self: TObject); begin dbus_error_init(@error); conn := dbus_bus_get(DBUS_BUS_SESSION, @error); if CheckError('Cannot acquire connection to DBUS session bus', @error) then Exit; if PythonInitialize(PythonVersion) then begin if not CheckVersion then Exit; Print('Python version ' + PythonVersion); PythonAddModulePath(gpExePath + 'scripts'); PythonModule:= PythonLoadModule(MODULE_NAME); RabbitVCS:= Assigned(PythonModule) and CheckService; end; end; procedure Finalize; begin PythonFinalize; if Assigned(conn) then dbus_connection_unref(conn); end; initialization BeginThread(@CheckPackage); finalization Finalize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/ushellcontextmenu.pas��������������������������������������������0000644�0001750�0000144�00000100703�14743153644�022500� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Shell context menu implementation. Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uShellContextMenu; {$mode delphi}{$H+} {$IF DEFINED(DARWIN)} {$modeswitch objectivec2} {$ENDIF} interface uses Classes, SysUtils, Controls, Menus, uGlobs, uFile, uDrive; type { EContextMenuException } EContextMenuException = class(Exception); { TShellContextMenu } TShellContextMenu = class(TPopupMenu) private FFiles: TFiles; FDrive: TDrive; FUserWishForContextMenu: TUserWishForContextMenu; FMenuImageList: TImageList; procedure PackHereSelect(Sender: TObject); procedure ExtractHereSelect(Sender: TObject); procedure ContextMenuSelect(Sender: TObject); procedure StandardContextMenuSelect(Sender: TObject); procedure TemplateContextMenuSelect(Sender: TObject); procedure DriveMountSelect(Sender: TObject); procedure DriveUnmountSelect(Sender: TObject); procedure DriveEjectSelect(Sender: TObject); procedure OpenWithOtherSelect(Sender: TObject); procedure OpenWithMenuItemSelect(Sender: TObject); private procedure LeaveDrive; function FillOpenWithSubMenu: Boolean; {$IF DEFINED(DARWIN)} procedure FillServicesSubMenu; procedure SharingMenuItemSelect(Sender: TObject); {$ENDIF} procedure CreateActionSubMenu(MenuWhereToAdd:TComponent; aFile:TFile; bIncludeViewEdit:boolean); public constructor Create(Owner: TWinControl; ADrive: PDrive); reintroduce; overload; constructor Create(Owner: TWinControl; var Files : TFiles; Background: Boolean; UserWishForContextMenu: TUserWishForContextMenu = uwcmComplete); reintroduce; overload; destructor Destroy; override; end; implementation uses LCLProc, Dialogs, Graphics, uFindEx, uDCUtils, uShowMsg, uFileSystemFileSource, uOSUtils, uFileProcs, uShellExecute, uLng, uPixMapManager, uMyUnix, uOSForms, fMain, fFileProperties, DCOSUtils, DCStrUtils, uExts, uArchiveFileSourceUtil, uSysFolders {$IF DEFINED(DARWIN)} , MacOSAll, CocoaAll, uMyDarwin {$ELSEIF NOT DEFINED(HAIKU)} , uKeyFile, uMimeActions {$IF DEFINED(LINUX)} , uRabbitVCS, uFlatpak {$ENDIF} {$ENDIF} ; const sCmdVerbProperties = 'properties'; var // The "ContextMenuActionList" will hold the possible actions to do from the // context menu. Each "TMenuItem" associated with these actions will have the // the "tag" set to the matching "TExtActionCommand" in this "TextActionList" // list. ContextMenuActionList: TExtActionList = nil; procedure addDelimiterMenuItem( menu:TMenuItem ); overload; var item: TMenuItem; begin item:= TMenuItem.Create( menu ); item.Caption:= '-'; menu.Add( item ); end; procedure addDelimiterMenuItem( menu:TMenu ); overload; var item: TMenuItem; begin item:= TMenuItem.Create( menu ); item.Caption:= '-'; menu.Items.Add( item ); end; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} function GetGnomeTemplateMenu(out Items: TStringList): Boolean; var searchRec: TSearchRecEx; templateDir: String; bmpBitmap: TBitmap = nil; userDirs: TStringList = nil; begin Result:= False; templateDir:= GetHomeDir + '/.config/user-dirs.dirs'; if not mbFileExists(templateDir) then Exit; try Items:= nil; userDirs:= TStringList.Create; try userDirs.LoadFromFile(templateDir); templateDir:= userDirs.Values['XDG_TEMPLATES_DIR']; except Exit; end; if Length(templateDir) = 0 then Exit; templateDir:= TrimQuotes(templateDir); // Skip misconfigured template path if (ExcludeTrailingBackslash(templateDir) = '$HOME') then Exit; templateDir:= IncludeTrailingPathDelimiter(mbExpandFileName(templateDir)); if mbDirectoryExists(templateDir) then begin if FindFirstEx(templateDir, 0, searchRec) = 0 then begin Items:= TStringList.Create; repeat // Skip directories if FPS_ISDIR(searchRec.Attr) then Continue; bmpBitmap:= PixMapManager.LoadBitmapEnhanced(templateDir + searchRec.Name, 16, True, clMenu); Items.AddObject(ExtractOnlyFileName(searchRec.Name) + '=' + templateDir + searchRec.Name, bmpBitmap); until FindNextEx(searchRec) <> 0; Result:= Items.Count > 0; end; FindCloseEx(searchRec); end; finally if Assigned(Items) and (Items.Count = 0) then FreeAndNil(Items); FreeAndNil(userDirs); end; end; function GetKdeTemplateMenu(out Items: TStringList): Boolean; var I: Integer; bmpBitmap: TBitmap = nil; desktopFile: TKeyFile = nil; templateDir: array [0..1] of String; searchRec: TSearchRecEx; templateName, templateIcon, templatePath: String; begin Result:= False; try Items:= nil; templateDir[0]:= '/usr/share/templates'; templateDir[1]:= GetHomeDir + '/.kde/share/templates'; for I:= Low(templateDir) to High(templateDir) do if mbDirectoryExists(templateDir[I]) then begin if FindFirstEx(templateDir[I] + PathDelim + '*.desktop', 0, searchRec) = 0 then begin if not Assigned(Items) then Items:= TStringList.Create; repeat // Skip directories if FPS_ISDIR(searchRec.Attr) then Continue; try desktopFile:= TKeyFile.Create(templateDir[I] + PathDelim + searchRec.Name); try templateName:= desktopFile.ReadLocaleString('Desktop Entry', 'Name', EmptyStr); templateIcon:= desktopFile.ReadString('Desktop Entry', 'Icon', EmptyStr); templatePath:= desktopFile.ReadString('Desktop Entry', 'URL', EmptyStr); templatePath:= GetAbsoluteFileName(templateDir[I] + PathDelim, templatePath); if not mbFileExists(templatePath) then Continue; // Skip the non-existent templates bmpBitmap:= PixMapManager.LoadBitmapEnhanced(templateIcon, 16, True, clMenu); Items.AddObject(templateName + '=' + templatePath, bmpBitmap); finally FreeAndNil(desktopFile); end; except // Skip end; until FindNextEx(searchRec) <> 0; Result:= Items.Count > 0; end; FindCloseEx(searchRec); end; finally if Assigned(Items) and (Items.Count = 0) then FreeAndNil(Items); end; end; {$ENDIF} function GetTemplateMenu(out Items: TStringList): Boolean; begin {$IF DEFINED(DARWIN) OR DEFINED(HAIKU)} Result:= False; {$ELSE} case GetDesktopEnvironment of DE_KDE: Result:= GetKdeTemplateMenu(Items); else Result:= GetGnomeTemplateMenu(Items); end; if Result then Items.Sort; {$ENDIF} end; procedure TShellContextMenu.LeaveDrive; begin if frmMain.ActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin if IsInPath(FDrive.Path, frmMain.ActiveFrame.CurrentPath, True, True) then begin frmMain.ActiveFrame.CurrentPath:= GetHomeDir; end; end; if frmMain.NotActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin if IsInPath(FDrive.Path, frmMain.NotActiveFrame.CurrentPath, True, True) then begin frmMain.NotActiveFrame.CurrentPath:= GetHomeDir; end; end end; procedure TShellContextMenu.PackHereSelect(Sender: TObject); begin frmMain.Commands.cm_PackFiles(['PackHere']); end; procedure TShellContextMenu.ExtractHereSelect(Sender: TObject); begin frmMain.Commands.cm_ExtractFiles(['ExtractHere']); end; (* handling user commands from context menu *) procedure TShellContextMenu.ContextMenuSelect(Sender: TObject); var UserSelectedCommand: TExtActionCommand = nil; begin with Sender as TComponent do UserSelectedCommand := ContextMenuActionList.ExtActionCommand[tag].CloneExtAction; try try //For the %-Variable replacement that follows it might sounds incorrect to do it with "nil" instead of "aFile", //but original code was like that. It is useful, at least, when more than one file is selected so because of that, //it's pertinent and should be kept! ProcessExtCommandFork(UserSelectedCommand.CommandName, UserSelectedCommand.Params, UserSelectedCommand.StartPath, nil); except on e: EInvalidCommandLine do MessageDlg(rsMsgErrorInContextMenuCommand, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0); end; finally FreeAndNil(UserSelectedCommand); end; end; procedure TShellContextMenu.StandardContextMenuSelect(Sender: TObject); var MenuItem: TMenuItem absolute Sender; begin with frmMain.ActiveFrame do begin if SameText(MenuItem.Hint, sCmdVerbProperties) then ShowFilePropertiesDialog(FileSource, FFiles); end; end; (* handling user commands from template context menu *) procedure TShellContextMenu.TemplateContextMenuSelect(Sender: TObject); var FileName: String; SelectedItem: TMenuItem; AbsoluteTargetFileName: String; begin // ShowMessage((Sender as TMenuItem).Hint); SelectedItem:= (Sender as TMenuItem); FileName:= SelectedItem.Caption; if InputQuery(rsMsgNewFile, rsMsgEnterName, FileName) then begin FileName:= FileName + ExtractFileExt(SelectedItem.Hint); AbsoluteTargetFileName:= frmMain.ActiveFrame.CurrentPath + FileName; if (not mbFileExists(AbsoluteTargetFileName)) or (msgYesNo(Format(rsMsgFileExistsRwrt, [FileName]))) then begin if CopyFile(SelectedItem.Hint, AbsoluteTargetFileName) then begin frmMain.ActiveFrame.Reload; frmMain.ActiveFrame.SetActiveFile(FileName); end; end; end; end; procedure TShellContextMenu.DriveMountSelect(Sender: TObject); begin MountDrive(@FDrive); end; procedure TShellContextMenu.DriveUnmountSelect(Sender: TObject); begin LeaveDrive; UnmountDrive(@FDrive); end; procedure TShellContextMenu.DriveEjectSelect(Sender: TObject); begin LeaveDrive; EjectDrive(@FDrive); end; procedure TShellContextMenu.OpenWithOtherSelect(Sender: TObject); {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} var I: LongInt; FileNames: TStringList; {$ENDIF} begin {$IF DEFINED(LINUX)} if DesktopEnv = DE_FLATPAK then FlatpakOpen(FFiles[0].FullPath, True) else {$ENDIF} {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} begin FileNames := TStringList.Create; for I := 0 to FFiles.Count - 1 do FileNames.Add(FFiles[I].FullPath); ShowOpenWithDialog(frmMain, FileNames); end; {$ENDIF} end; {$IF DEFINED(DARWIN)} function OpenWithComparator(param1:id; param2:id; nouse: pointer): NSInteger; cdecl; var fileManager: NSFileManager; string1: NSString; string2: NSString; begin fileManager:= NSFileManager.defaultManager; string1:= fileManager.displayNameAtPath( param1.path ); string2:= fileManager.displayNameAtPath( param2.path ); Result:= string1.localizedStandardCompare( string2 ); end; function filesToNSUrlArray( const files:TFiles ): NSArray; var theArray: NSMutableArray; theFile: TFile; path: String; url: NSUrl; begin theArray:= NSMutableArray.arrayWithCapacity( files.Count ); for theFile in files.List do begin path:= theFile.FullPath; url:= NSUrl.fileURLWithPath( StringToNSString(path) ); theArray.addObject( url ); end; Result:= theArray; end; function getAppArrayFromFiles( const files:TFiles ): NSArray; const ROLE_MASK = kLSRolesViewer or kLSRolesEditor or kLSRolesShell; var theFile: TFile; path: String; url: NSUrl; appSet: NSMutableSet = nil; newSet: NSSet; appArray: NSMutableArray; newArray: NSArray; defaultAppUrl: NSUrl = nil; begin Result:= nil; try for theFile in files.List do begin path:= theFile.FullPath; url:= NSUrl.fileURLWithPath( StringToNSString(path) ); newArray:= NSArray( LSCopyApplicationURLsForURL(CFURLRef(url), ROLE_MASK) ); newSet:= NSSet.setWithArray( newArray ); if Assigned(appSet) then begin appSet.intersectSet( newSet ); end else begin appSet:= NSMutableSet.alloc.initWithSet( newSet ); if newArray.count > 0 then defaultAppUrl:= newArray.objectAtIndex(0); end; newArray.release; end; newArray:= NSArray.arrayWithArray( appSet.allObjects ); newArray:= newArray.sortedArrayUsingFunction_context( @OpenWithComparator, nil ); appArray:= NSMutableArray.arrayWithArray( newArray ); if appArray.containsObject(defaultAppUrl) then begin appArray.removeObject( defaultAppUrl ); appArray.insertObject_atIndex( defaultAppUrl, 0 ); end; Result:= appArray; finally appSet.release; end; end; // Context Menu / Open with / Other... function getOtherAppFromDialog(): String; var appDialog: TOpenDialog; begin Result:= ''; appDialog:= TOpenDialog.Create(nil); appDialog.DefaultExt:= 'app'; appDialog.InitialDir:= '/Applications'; appDialog.Filter:= rsOpenWithMacOSFilter; if appDialog.Execute and (NOT appDialog.FileName.IsEmpty) then begin Result:= appDialog.FileName; end; FreeAndNil( appDialog ); end; procedure TShellContextMenu.OpenWithMenuItemSelect(Sender: TObject); var appPath: String; launchParam: LSLaunchURLSpec; begin appPath := (Sender as TMenuItem).Hint; if appPath.IsEmpty then begin appPath:= getOtherAppFromDialog; if appPath.IsEmpty then Exit; end; launchParam.appURL:= CFURLRef( NSUrl.fileURLWithPath(StringToNSString(appPath)) ); launchParam.itemURLs:= CFArrayRef( filesToNSUrlArray(FFiles) ); launchParam.launchFlags:= 0; launchParam.asyncRefCon:= nil; launchParam.passThruParams:= nil; LSOpenFromURLSpec( launchParam, nil ); end; {$ELSE} procedure TShellContextMenu.OpenWithMenuItemSelect(Sender: TObject); var ExecCmd: String; begin ExecCmd := (Sender as TMenuItem).Hint; if ExecCmd.IsEmpty then Exit; try ExecCmdFork(ExecCmd); except on e: EInvalidCommandLine do MessageDlg(rsMsgErrorInContextMenuCommand, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0); end; end; {$ENDIF} function TShellContextMenu.FillOpenWithSubMenu: Boolean; {$IF DEFINED(DARWIN)} var I: Integer; ImageIndex: PtrInt; bmpTemp: TBitmap = nil; mi, miOpenWith: TMenuItem; appArray: NSArray; appUrl: NSURL; begin Result:= False; if FFiles.Count=0 then Exit; appArray:= getAppArrayFromFiles( FFiles ); miOpenWith:= TMenuItem.Create(Self); miOpenWith.Caption:= rsMnuOpenWith; if Assigned(appArray) and (appArray.count>0) then begin FMenuImageList := TImageList.Create(nil); miOpenWith.SubMenuImages := FMenuImageList; for I:= 0 to appArray.count-1 do begin appUrl:= NSURL( appArray.objectAtIndex(I) ); mi:= TMenuItem.Create( miOpenWith ); mi.Caption:= NSFileManager.defaultManager.displayNameAtPath(appUrl.path).UTF8String; mi.Hint := appUrl.path.UTF8String; ImageIndex:= PixMapManager.GetApplicationBundleIcon(appUrl.path.UTF8String, -1); if ImageIndex >= 0 then begin bmpTemp:= PixMapManager.GetBitmap(ImageIndex); if Assigned(bmpTemp) then begin mi.ImageIndex:=FMenuImageList.Count; FMenuImageList.Add( bmpTemp , nil ); FreeAndNil(bmpTemp); end; end; mi.OnClick := Self.OpenWithMenuItemSelect; miOpenWith.Add(mi); if (i=0) and (appArray.count>=2) then addDelimiterMenuItem( miOpenWith ); end; end; // Other... addDelimiterMenuItem( miOpenWith ); mi:= TMenuItem.Create(miOpenWith); mi.Caption:= rsMnuOpenWithOther; mi.OnClick := Self.OpenWithMenuItemSelect; miOpenWith.Add(mi); Self.Items.Add(miOpenWith); Result:= True; end; {$ELSEIF DEFINED(HAIKU)} begin Result:= False; end; {$ELSE} var I: LongInt; bmpTemp: TBitmap; FileNames: TStringList; Entry: PDesktopFileEntry; mi, miOpenWith: TMenuItem; DesktopEntries: TList = nil; begin Result := True; FileNames := TStringList.Create; try miOpenWith := TMenuItem.Create(Self); miOpenWith.Caption := rsMnuOpenWith; Self.Items.Add(miOpenWith); for I := 0 to FFiles.Count - 1 do FileNames.Add(FFiles[I].FullPath); DesktopEntries := GetDesktopEntries(FileNames); if Assigned(DesktopEntries) and (DesktopEntries.Count > 0) then begin for I := 0 to DesktopEntries.Count - 1 do begin Entry := PDesktopFileEntry(DesktopEntries[I]); mi := TMenuItem.Create(miOpenWith); mi.Caption := Entry^.DisplayName; mi.Hint := Entry^.Exec; bmpTemp:= PixMapManager.LoadBitmapEnhanced(Entry^.IconName, 16, True, clMenu); if Assigned(bmpTemp) then begin mi.Bitmap.Assign(bmpTemp); FreeAndNil(bmpTemp); end; mi.OnClick := Self.OpenWithMenuItemSelect; miOpenWith.Add(mi); end; miOpenWith.AddSeparator; end; mi := TMenuItem.Create(miOpenWith); mi.Caption := rsMnuOpenWithOther; mi.OnClick := Self.OpenWithOtherSelect; miOpenWith.Add(mi); {$IF DEFINED(LINUX)} FillRabbitMenu(Self, FileNames); {$ENDIF} finally FreeAndNil(FileNames); if Assigned(DesktopEntries) then begin for I := 0 to DesktopEntries.Count - 1 do Dispose(PDesktopFileEntry(DesktopEntries[I])); FreeAndNil(DesktopEntries); end; end; end; {$ENDIF} {$IF DEFINED(DARWIN)} procedure TShellContextMenu.FillServicesSubMenu; var mi: TMenuItem; begin addDelimiterMenuItem( self ); // attach Services Menu in TMacosServiceMenuHelper mi:=TMenuItem.Create(Self); mi.Caption:=uLng.rsMenuMacOsServices; Self.Items.Add(mi); addDelimiterMenuItem( self ); // add Sharing Menu // similar to MacOS 13, the Share MenuItem does not expand the submenu, // and the SharingServicePicker pops up after clicking Share MenuItem. mi:=TMenuItem.Create(Self); mi.Caption:= uLng.rsMenuMacOsShare; mi.OnClick:= self.SharingMenuItemSelect; Self.Items.Add(mi); end; procedure TShellContextMenu.SharingMenuItemSelect(Sender: TObject); begin showMacOSSharingServiceMenu; end; {$ENDIF} constructor TShellContextMenu.Create(Owner: TWinControl; ADrive: PDrive); var mi: TMenuItem; begin inherited Create(Owner); FDrive := ADrive^; mi := TMenuItem.Create(Self); if not ADrive^.IsMounted then begin if ADrive^.IsMediaAvailable then begin mi.Caption := rsMnuMount; mi.OnClick := Self.DriveMountSelect; end else begin mi.Caption := rsMnuNoMedia; mi.Enabled := False; end; end else begin {$IF not DEFINED(DARWIN)} mi.Caption := rsMnuUmount; mi.OnClick := Self.DriveUnmountSelect; {$ELSE} mi.Caption := rsMnuUmount + ' / ' + rsMnuEject; mi.OnClick := Self.DriveEjectSelect; {$ENDIF} end; Self.Items.Add(mi); {$IF not DEFINED(DARWIN)} if ADrive^.IsMediaEjectable then begin mi :=TMenuItem.Create(Self); mi.Caption := rsMnuEject; mi.OnClick := Self.DriveEjectSelect; Self.Items.Add(mi); end; {$ENDIF} end; { TShellContextMenu.CreateActionSubMenu } // Create the "Actions" menu/submenu. procedure TShellContextMenu.CreateActionSubMenu(MenuWhereToAdd:TComponent; aFile:TFile; bIncludeViewEdit:boolean); var mi: TMenuItem; I, iDummy:integer; sAct: String; iMenuPositionInsertion: integer =0; procedure AddMenuItemRightPlace; begin if MenuWhereToAdd is TMenuItem then TMenuItem(MenuWhereToAdd).Add(mi) else Self.Items.Add(mi); inc(iMenuPositionInsertion); end; procedure LocalInsertMenuSeparator; begin mi:=TMenuItem.Create(MenuWhereToAdd); mi.Caption:='-'; AddMenuItemRightPlace; end; procedure LocalInsertMenuItem(CaptionMenu:string; MenuDispatcher:integer); begin mi := TMenuItem.Create(MenuWhereToAdd); mi.Caption := CaptionMenu; mi.Tag := MenuDispatcher; mi.OnClick:= Self.ContextMenuSelect; AddMenuItemRightPlace; end; begin // Read actions from "extassoc.xml" if not gExtendedContextMenu then gExts.GetExtActions(aFile, ContextMenuActionList, @iDummy, False) else gExts.GetExtActions(aFile, ContextMenuActionList, @iDummy, True); if not gExtendedContextMenu then begin // In non expanded context menu (legacy), the order of items is: // 1o) Custom action different then Open, View or Edit // 2o) Add a separator in any action added above // 3o) View (always) // 4o) Edit (always) // note: In Windows flavor, this is not the same order but to respect initial DC legacy order, that was it. if ContextMenuActionList.Count > 0 then begin for I := 0 to pred(ContextMenuActionList.Count) do begin sAct := ContextMenuActionList.ExtActionCommand[I].ActionName; if (SysUtils.CompareText('OPEN', sAct) <> 0) and (SysUtils.CompareText('VIEW', sAct) <> 0) and (SysUtils.CompareText('EDIT', sAct) <> 0) then LocalInsertMenuItem(sAct, I); end; end; if iMenuPositionInsertion>0 then //It cannot be just (ContextMenuActionList.Count>0) 'case if the list has just OPEN, VIEW or READ, we will have nothing and we don't want the separator. LocalInsertMenuSeparator; I := ContextMenuActionList.Add(TExtActionCommand.Create(rsMnuView, '{!VIEWER}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName, I); I := ContextMenuActionList.Add(TExtActionCommand.Create(rsMnuEdit, '{!EDITOR}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName, I); end else begin // In expanded context menu (legacy), the order of items is the following. // 1o) Custom actions, no matter is open, view or edit (if any, add also a separator just before). // These will be shown in the same order as what they are configured in File Association. // The routine "GetExtActions" has already placed them in the wanted order. // Also, the routine "GetExtActions" has already included the menu separator ('-') between different "TExtAction". // 2o) Add a separator in any action added above // 3o) View (always, and if "external" is used, shows also the "internal" if user wants it. // 4o) Edit (always, and if "external" is used, shows also the "internal" if user wants it. // 5o) We add the Execute via shell if user requested it. // 6o) We add the Execute via terminal if user requested it (close and then stay open). // 7o) Still if user requested it, the shortcut run file association configuration, if user wanted it. // A separator also prior that last action. // note: In Windows flavor, this is not the same order but to respect initial DC legacy order, that was it. for I:= 0 to pred(ContextMenuActionList.Count) do begin if ContextMenuActionList.ExtActionCommand[I].ActionName<>'-' then begin sAct:= ContextMenuActionList.ExtActionCommand[I].ActionName; if (SysUtils.CompareText('OPEN', sAct) = 0) or (SysUtils.CompareText('VIEW', sAct) = 0) or (SysUtils.CompareText('EDIT', sAct) = 0) then sAct:=sAct+' ('+ExtractFilename(ContextMenuActionList.ExtActionCommand[I].CommandName)+')'; LocalInsertMenuItem(sAct,I); end else begin LocalInsertMenuSeparator; end; end; // If the default context actions not hidden if gDefaultContextActions then begin if ContextMenuActionList.Count>0 then LocalInsertMenuSeparator; // If the external generic viewer is configured, offer it. if gExternalTools[etViewer].Enabled then begin I := ContextMenuActionList.Add(TExtActionCommand.Create(rsMnuView+' ('+rsViewWithExternalViewer+')','{!VIEWER}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; // Make sure we always shows our internal viewer I := ContextMenuActionList.Add(TExtActionCommand.Create(rsMnuView+' ('+rsViewWithInternalViewer+')','{!DC-VIEWER}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); // If the external generic editor is configured, offer it. if gExternalTools[etEditor].Enabled then begin I := ContextMenuActionList.Add(TExtActionCommand.Create(rsMnuEdit+' ('+rsEditWithExternalEditor+')','{!EDITOR}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; // Make sure we always shows our internal editor I := ContextMenuActionList.Add(TExtActionCommand.Create(rsMnuEdit+' ('+rsEditWithInternalEditor+')','{!DC-EDITOR}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; if (gOpenExecuteViaShell or gExecuteViaTerminalClose or gExecuteViaTerminalStayOpen) and (ContextMenuActionList.Count>0) then LocalInsertMenuSeparator; // Execute via shell if gOpenExecuteViaShell then begin I := ContextMenuActionList.Add(TExtActionCommand.Create(rsExecuteViaShell,'{!SHELL}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; // Execute via terminal and close if gExecuteViaTerminalClose then begin I := ContextMenuActionList.Add(TExtActionCommand.Create(rsExecuteViaTerminalClose,'{!TERMANDCLOSE}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; // Execute via terminal and stay open if gExecuteViaTerminalStayOpen then begin I := ContextMenuActionList.Add(TExtActionCommand.Create(rsExecuteViaTerminalStayOpen,'{!TERMSTAYOPEN}',QuoteStr(aFile.FullPath),'')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; // Add shortcut to launch file association cnfiguration screen if gIncludeFileAssociation then begin if ContextMenuActionList.Count>0 then LocalInsertMenuSeparator; I := ContextMenuActionList.Add(TExtActionCommand.Create(rsConfigurationFileAssociation,'cm_FileAssoc','','')); LocalInsertMenuItem(ContextMenuActionList.ExtActionCommand[I].ActionName,I); end; end; end; constructor TShellContextMenu.Create(Owner: TWinControl; var Files: TFiles; Background: Boolean; UserWishForContextMenu: TUserWishForContextMenu); var I: Integer; aFile: TFile = nil; sl: TStringList = nil; mi, miActions, miSortBy: TMenuItem; AddActionsMenu: Boolean = False; AddOpenWithMenu: Boolean = False; begin inherited Create(Owner); FFiles:= Files; FUserWishForContextMenu:= UserWishForContextMenu; try if ContextMenuActionList=nil then ContextMenuActionList:=TExtActionList.Create; ContextMenuActionList.Clear; if not Background then begin aFile := Files[0]; // Add the "Open" if FUserWishForContextMenu = uwcmComplete then begin mi:=TMenuItem.Create(Self); mi.Action := frmMain.actShellExecute; Self.Items.Add(mi); end; // Add the "Actions" menu if FUserWishForContextMenu = uwcmComplete then begin miActions:=TMenuItem.Create(Self); miActions.Caption:= rsMnuActions; CreateActionSubMenu(miActions, aFile, ((FFiles.Count = 1) and not (aFile.IsDirectory or aFile.IsLinkToDirectory))); if miActions.Count>0 then Self.Items.Add(miActions) else miActions.Free; end else begin CreateActionSubMenu(Self, aFile, ((FFiles.Count = 1) and not (aFile.IsDirectory or aFile.IsLinkToDirectory))) end; if FUserWishForContextMenu = uwcmComplete then begin addDelimiterMenuItem( self ); // Add "Open with" submenu if needed AddOpenWithMenu := FillOpenWithSubMenu; // Add "Services" menu if MacOS {$IF DEFINED(DARWIN)} FillServicesSubMenu; {$ENDIF} // Add delimiter menu addDelimiterMenuItem( self ); // Add "Pack here..." mi:=TMenuItem.Create(Self); mi.Caption:= rsMnuPackHere; mi.OnClick:= Self.PackHereSelect; Self.Items.Add(mi); // Add "Extract here..." if FileIsArchive(aFile.FullPath) then begin mi:=TMenuItem.Create(Self); mi.Caption:= rsMnuExtractHere; mi.OnClick:= Self.ExtractHereSelect; Self.Items.Add(mi); end; // Add delimiter menu addDelimiterMenuItem( self ); // Add "Move" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actRename; Self.Items.Add(mi); // Add "Copy" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actCopy; Self.Items.Add(mi); // Add "Delete" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actDelete; Self.Items.Add(mi); // Add "Rename" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actRenameOnly; Self.Items.Add(mi); addDelimiterMenuItem( self ); // Add "Cut" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actCutToClipboard; Self.Items.Add(mi); // Add "Copy" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actCopyToClipboard; Self.Items.Add(mi); // Add "PAste" mi:=TMenuItem.Create(Self); mi.Action := frmMain.actPasteFromClipboard; Self.Items.Add(mi); addDelimiterMenuItem( self ); // Add "Show file properties" mi:= TMenuItem.Create(Self); mi.Hint:= sCmdVerbProperties; mi.Caption:= frmMain.actFileProperties.Caption; mi.ShortCut:= frmMain.actFileProperties.ShortCut; mi.OnClick:= Self.StandardContextMenuSelect; Self.Items.Add(mi); end; end else begin mi:=TMenuItem.Create(Self); mi.Action := frmMain.actRefresh; Self.Items.Add(mi); // Add "Sort by" submenu miSortBy := TMenuItem.Create(Self); miSortBy.Caption := rsMnuSortBy; Self.Items.Add(miSortBy); mi:=TMenuItem.Create(miSortBy); mi.Action := frmMain.actSortByName; miSortBy.Add(mi); mi:=TMenuItem.Create(miSortBy); mi.Action := frmMain.actSortByExt; miSortBy.Add(mi); mi:=TMenuItem.Create(miSortBy); mi.Action := frmMain.actSortBySize; miSortBy.Add(mi); mi:=TMenuItem.Create(miSortBy); mi.Action := frmMain.actSortByDate; miSortBy.Add(mi); mi:=TMenuItem.Create(miSortBy); mi.Action := frmMain.actSortByAttr; miSortBy.Add(mi); addDelimiterMenuItem( miSortBy ); mi:=TMenuItem.Create(miSortBy); mi.Action := frmMain.actReverseOrder; miSortBy.Add(mi); addDelimiterMenuItem( self ); mi:=TMenuItem.Create(Self); mi.Action := frmMain.actPasteFromClipboard; Self.Items.Add(mi); addDelimiterMenuItem( self ); // Add "New" submenu miSortBy := TMenuItem.Create(Self); miSortBy.Caption := rsMnuNew; Self.Items.Add(miSortBy); // Add "Create directory" mi:= TMenuItem.Create(miSortBy); mi.Action := frmMain.actMakeDir; mi.Caption:= rsPropsFolder; miSortBy.Add(mi); // Add "Create file" mi:= TMenuItem.Create(miSortBy); mi.Action := frmMain.actEditNew; mi.Caption:= rsPropsFile; miSortBy.Add(mi); if GetTemplateMenu(sl) then begin addDelimiterMenuItem( miSortBy ); for I:= 0 to sl.Count - 1 do begin mi:=TMenuItem.Create(miSortBy); mi.Caption:= sl.Names[I]; mi.Hint:= sl.ValueFromIndex[I]; mi.OnClick:= Self.TemplateContextMenuSelect; if Assigned(sl.Objects[I]) then begin mi.Bitmap.Assign(TBitmap(sl.Objects[I])); sl.Objects[I].Free; sl.Objects[I]:= nil; end; miSortBy.Add(mi); end; FreeAndNil(sl); end; addDelimiterMenuItem( self ); mi:= TMenuItem.Create(Self); mi.Hint:= sCmdVerbProperties; mi.Caption:= frmMain.actFileProperties.Caption; mi.ShortCut:= frmMain.actFileProperties.ShortCut; mi.OnClick:= Self.StandardContextMenuSelect; Self.Items.Add(mi); end; finally Files:= nil; end; end; destructor TShellContextMenu.Destroy; begin FreeAndNil(FFiles); FreeAndNil(FMenuImageList); inherited Destroy; end; end. �������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uunixicontheme.pas�����������������������������������������������0000644�0001750�0000144�00000015523�14743153644�021763� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Some useful functions for Unix icon theme implementation Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uUnixIconTheme; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes, uIconTheme; const DEFAULT_THEME_NAME = 'hicolor'; function GetCurrentIconTheme: String; function GetUnixDefaultTheme: String; function GetUnixIconThemeBaseDirList: TDynamicStringArray; implementation uses Laz2_DOM, Laz2_XMLRead, DCClassesUtf8, uMyUnix, DCOSUtils, uOSUtils, uGio, uSysFolders, uXdg {$IF DEFINED(LCLQT5)} , Qt5 {$ELSEIF DEFINED(LCLQT6)} , Qt6 {$ENDIF} ; {$IF DEFINED(LCLQT5) OR DEFINED(LCLQT6)} function GetQtIconTheme: String; var AValue: WideString; begin QIcon_themeName(@AValue); Result:= UTF8Encode(AValue); end; {$ENDIF} function GetKdeIconTheme: String; var I: Integer; FileName: String; iniCfg: TIniFileEx; kdeConfig: array[1..3] of String = ( 'kdeglobals', '/.kde/share/config/kdeglobals', '/.kde4/share/config/kdeglobals' ); begin Result:= EmptyStr; for I:= Low(kdeConfig) to High(kdeConfig) do begin if (I > 1) then FileName:= GetHomeDir + kdeConfig[I] else begin FileName:= IncludeTrailingBackslash(GetUserConfigDir) + kdeConfig[I]; end; if mbFileExists(FileName) then try iniCfg:= TIniFileEx.Create(FileName, fmOpenRead); try Result:= iniCfg.ReadString('Icons', 'Theme', EmptyStr); if (Length(Result) > 0) then Break; finally iniCfg.Free; end; except // Skip end; end; if Length(Result) = 0 then Result:= 'breeze'; end; function GetGnomeIconTheme: String; begin Result:= GioGetIconTheme('org.gnome.desktop.interface'); if Length(Result) = 0 then Result:= 'Adwaita'; end; function GetXfceIconTheme: String; const xfceConfig = '/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml'; var J, I: Integer; ChildNode1, ChildNode2: TDOMNode; xmlCfg: TXMLDocument = nil; begin Result:= EmptyStr; if mbFileExists(GetHomeDir + xfceConfig) then try ReadXMLFile(xmlCfg, GetHomeDir + xfceConfig); try for J := 0 to xmlCfg.DocumentElement.ChildNodes.Count -1 do begin ChildNode1:= xmlCfg.DocumentElement.ChildNodes.Item[J]; if (ChildNode1.NodeName = 'property') then if (ChildNode1.Attributes.Length > 0) and (ChildNode1.Attributes[0].NodeValue = 'Net') then for I:= 0 to ChildNode1.ChildNodes.Count - 1 do begin ChildNode2 := ChildNode1.ChildNodes.Item[I]; if (ChildNode2.NodeName = 'property') then if (ChildNode2.Attributes.Length > 2) and (ChildNode2.Attributes[0].NodeValue = 'IconThemeName') then begin Result:= ChildNode2.Attributes[2].NodeValue; Exit; end; end; end; finally xmlCfg.Free; end; except // Skip end; end; function GetLxdeIconTheme: String; const lxdeConfig1 = '/.config/lxsession/%s/desktop.conf'; lxdeConfig2 = '/etc/xdg/lxsession/%s/desktop.conf'; var I: Integer; DesktopSession: String; iniCfg: TIniFileEx = nil; lxdeConfig: array[1..2] of String = (lxdeConfig1, lxdeConfig2); begin Result:= EmptyStr; DesktopSession:= mbGetEnvironmentVariable('DESKTOP_SESSION'); if Length(DesktopSession) <> 0 then begin lxdeConfig[1]:= GetHomeDir + Format(lxdeConfig[1], [DesktopSession]); lxdeConfig[2]:= Format(lxdeConfig[2], [DesktopSession]); for I:= Low(lxdeConfig) to High(lxdeConfig) do begin if (Length(Result) = 0) and mbFileExists(lxdeConfig[I]) then try iniCfg:= TIniFileEx.Create(lxdeConfig[I]); try Result:= iniCfg.ReadString('GTK', 'sNet/IconThemeName', EmptyStr); finally iniCfg.Free; end; except // Skip end; end; end; end; function GetLxqtIconTheme: String; const lxqtConfig = '/.config/lxqt/lxqt.conf'; var iniCfg: TIniFileEx; begin Result:= EmptyStr; if mbFileExists(GetHomeDir + lxqtConfig) then try iniCfg:= TIniFileEx.Create(GetHomeDir + lxqtConfig); try Result:= iniCfg.ReadString('General', 'icon_theme', EmptyStr); finally iniCfg.Free; end; except // Skip end; end; function GetMateIconTheme: String; inline; begin Result:= GioGetIconTheme('org.mate.interface'); end; function GetCinnamonIconTheme: String; inline; begin Result:= GioGetIconTheme('org.cinnamon.desktop.interface'); end; function GetCurrentIconTheme: String; begin Result:= EmptyStr; case DesktopEnv of DE_KDE: Result:= GetKdeIconTheme; DE_GNOME: Result:= GetGnomeIconTheme; DE_XFCE: Result:= GetXfceIconTheme; DE_LXDE: Result:= GetLxdeIconTheme; DE_LXQT: Result:= GetLxqtIconTheme; DE_MATE: Result:= GetMateIconTheme; DE_CINNAMON: Result:= GetCinnamonIconTheme; end; if Result = EmptyStr then begin {$IF DEFINED(LCLQT5) OR DEFINED(LCLQT6)} Result:= GetQtIconTheme; if Result = EmptyStr then {$ENDIF} Result:= DEFAULT_THEME_NAME; end; end; var UnixDefaultTheme: String = DEFAULT_THEME_NAME; UnixIconThemesBaseDirList: TDynamicStringArray; function GetUnixDefaultTheme: String; begin Result:= UnixDefaultTheme; end; function GetUnixIconThemeBaseDirList: TDynamicStringArray; begin Result:= UnixIconThemesBaseDirList; end; procedure InitIconThemesBaseDirList; var Home: String; I: Integer = 1; begin Home := GetHomeDir; SetLength(UnixIconThemesBaseDirList, 6); UnixIconThemesBaseDirList[0] := Home + '/.icons'; UnixIconThemesBaseDirList[1] := Home + '/.local/share/icons'; if DesktopEnv = DE_KDE then begin I:= 2; SetLength(UnixIconThemesBaseDirList, 7); UnixIconThemesBaseDirList[2] := Home + '/.kde/share/icons'; end; UnixIconThemesBaseDirList[I + 1] := '/usr/local/share/icons'; UnixIconThemesBaseDirList[I + 2] := '/usr/local/share/pixmaps'; UnixIconThemesBaseDirList[I + 3] := '/usr/share/icons'; UnixIconThemesBaseDirList[I + 4] := '/usr/share/pixmaps'; end; initialization InitIconThemesBaseDirList; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uusersgroups.pas�������������������������������������������������0000644�0001750�0000144�00000006545�14743153644�021511� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ File name: uUsersGroups.pas Date: 2003/07/03 Author: Martin Matusu <xmat@volny.cz> Copyright (C) 2003 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 in a file called COPYING along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } {mate} unit uUsersGroups; {$mode objfpc}{$H+} interface uses Classes; const groupInfo = '/etc/group'; userInfo = '/etc/passwd'; function uidToStr(uid: Cardinal): String; function gidToStr(gid: Cardinal): String; function strToUID(uname: AnsiString): Cardinal; function strToGID(gname: AnsiString): Cardinal; procedure getUsrGroups(uid: Cardinal; List: TStrings); procedure getUsers(List: TStrings); procedure getGroups(List: TStrings); implementation uses SysUtils, DCUnix; function uidToStr(uid: Cardinal): String; var uinfo: PPasswordRecord; begin uinfo:= getpwuid(uid); if (uinfo = nil) then Result:= UIntToStr(uid) else Result:= String(uinfo^.pw_name); end; function gidToStr(gid: Cardinal): String; var ginfo: PGroupRecord; begin ginfo:= getgrgid(gid); if (ginfo = nil) then Result:= UIntToStr(gid) else Result:= String(ginfo^.gr_name); end; procedure getUsrGroups(uid: Cardinal; List: TStrings); var groups: TStrings; iC,iD: integer; sT: string; begin // parse groups records groups:= TStringlist.Create; try List.Clear; groups.LoadFromFile(groupInfo); for ic:= 0 to (groups.Count - 1) do begin st:= groups.Strings[ic]; //get one record to parse id:= Pos(UIDtoStr(uid), st); //get position of uname if ((id<>0) or (uid=0)) then begin st:= Copy(st, 1, Pos(':',st) - 1); List.Append(st); end; // if end; // for finally FreeAndNil(groups); end; end; procedure getGroups(List: TStrings); begin getUsrGroups(0, List); end; procedure GetUsers(List: TStrings); var Users: TStrings; iC: integer; sT: string; begin users:= TStringList.Create; try users.LoadFromFile(userInfo); List.Clear; for ic:= 0 to (users.Count - 1) do begin st:= users.Strings[ic]; //get one record (line) st:= copy(st, 1, Pos(':',st) - 1); //extract username List.Append(st); //append to the list end; finally FreeAndNil(users); end; end; function strToUID(uname: AnsiString): Cardinal; //Converts username to UID ('root' results to 0) var uinfo: PPasswordRecord; begin uinfo:= getpwnam(PChar(uname)); if (uinfo = nil) then Result:= StrToUIntDef(uname, High(Cardinal)) else Result:= uinfo^.pw_uid; end; function strToGID(gname: AnsiString): Cardinal; var ginfo: PGroupRecord; begin ginfo:= getgrnam(PChar(gname)); if (ginfo = nil) then Result:= StrToUIntDef(gname, High(Cardinal)) else Result:= ginfo^.gr_gid; end; {/mate} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uvideothumb.pas��������������������������������������������������0000644�0001750�0000144�00000013052�14743153644�021245� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- FFmpeg thumbnail provider Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) FFmpegthumbnailer - lightweight video thumbnailer Copyright (C) 2010 Dirk Vanden Boer <dirk.vdb@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uVideoThumb; {$mode delphi} {$packrecords c} interface uses Classes, SysUtils; implementation uses CTypes, DynLibs, Graphics, Types, LazUTF8, DCOSUtils, DCConvertEncoding, uThumbnails, uClassesEx, uMasks, uGraphics; type ThumbnailerImageType = ( Png, Jpeg, Unknown ); Pvideo_thumbnailer = ^Tvideo_thumbnailer; Tvideo_thumbnailer = record thumbnail_size: cint; //* default = 128 */ seek_percentage: cint; //* default = 10 */ seek_time: pchar; //* default = NULL (format hh:mm:ss, overrides seek_percentage if set) */ overlay_film_strip: cint; //* default = 0 */ workaround_bugs: cint; //* default = 0 */ thumbnail_image_quality: cint; //* default = 8 (0 is bad, 10 is best)*/ thumbnail_image_type: ThumbnailerImageType; //* default = Png */ av_format_context: pointer; //* default = NULL */ maintain_aspect_ratio: cint; //* default = 1 */ thumbnailer: pointer; //* for internal use only */ filter: pointer; //* for internal use only */ end; Pimage_data = ^Timage_data; Timage_data = record image_data_ptr: pcuint8; //* points to the image data after call to generate_thumbnail_to_buffer */ image_data_size: cint; //* contains the size of the image data after call to generate_thumbnail_to_buffer */ internal_data: pointer; //* for internal use only */ end; var { create video_thumbnailer structure } video_thumbnailer_create: function(): Pvideo_thumbnailer; cdecl; { destroy video_thumbnailer structure } video_thumbnailer_destroy: procedure(thumbnailer: Pvideo_thumbnailer); cdecl; { create image_data structure } video_thumbnailer_create_image_data: function(): Pimage_data; cdecl; { destroy image_data structure } video_thumbnailer_destroy_image_data: procedure(data: Pimage_data); cdecl; { generate thumbnail from video file (movie_filename), image data is stored in generated_image_data struct } video_thumbnailer_generate_thumbnail_to_buffer: function(thumbnailer: Pvideo_thumbnailer; movie_filename: Pchar; generated_image_data: Pimage_data): cint; cdecl; var MaskList: TMaskList = nil; libffmpeg: TLibHandle = NilHandle; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var Data: Pimage_data; BlobStream: TBlobStream; Thumb: Pvideo_thumbnailer; Bitmap: TPortableNetworkGraphic; begin Result:= nil; if MaskList.Matches(aFileName) then begin Thumb:= video_thumbnailer_create(); if Assigned(Thumb) then try Thumb.thumbnail_size:= aSize.cx; Data:= video_thumbnailer_create_image_data(); if Assigned(Data) then try if video_thumbnailer_generate_thumbnail_to_buffer(Thumb, PAnsiChar(CeUtf8ToSys(aFileName)), Data) = 0 then begin Bitmap:= TPortableNetworkGraphic.Create; BlobStream:= TBlobStream.Create(Data^.image_data_ptr, Data^.image_data_size); try Bitmap.LoadFromStream(BlobStream); Result:= Graphics.TBitmap.Create; BitmapAssign(Result, Bitmap); except FreeAndNil(Result); end; Bitmap.Free; BlobStream.Free; end; finally video_thumbnailer_destroy_image_data(Data); end; finally video_thumbnailer_destroy(Thumb); end; end; end; procedure Initialize; begin libffmpeg:= LoadLibrary('libffmpegthumbnailer.so.4'); if (libffmpeg <> NilHandle) then try @video_thumbnailer_create:= SafeGetProcAddress(libffmpeg, 'video_thumbnailer_create'); @video_thumbnailer_destroy:= SafeGetProcAddress(libffmpeg, 'video_thumbnailer_destroy'); @video_thumbnailer_create_image_data:= SafeGetProcAddress(libffmpeg, 'video_thumbnailer_create_image_data'); @video_thumbnailer_destroy_image_data:= SafeGetProcAddress(libffmpeg, 'video_thumbnailer_destroy_image_data'); @video_thumbnailer_generate_thumbnail_to_buffer:= SafeGetProcAddress(libffmpeg, 'video_thumbnailer_generate_thumbnail_to_buffer'); // Register thumbnail provider TThumbnailManager.RegisterProvider(@GetThumbnail); MaskList:= TMaskList.Create('*.avi;*.flv;*.mkv;*.mp4;*.mpg;*.mov;*.wmv;*.vob;*.mpeg;*.webm'); except // Skip end; end; procedure Finalize; begin MaskList.Free; if (libffmpeg <> NilHandle) then FreeLibrary(libffmpeg); end; initialization Initialize; finalization Finalize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/unix/uxdg.pas���������������������������������������������������������0000644�0001750�0000144�00000012141�14743153644�017657� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Miscellaneous freedesktop.org compatible utility functions Copyright (C) 2014-2021 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uXdg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes; {en Returns a base directory in which to store non-essential, cached data specific to particular user. } function GetUserCacheDir: String; {en Returns a base directory relative to which user-specific data files should be written. } function GetUserDataDir: String; {en Returns an ordered list of base directories in which to access system-wide application data. } function GetSystemDataDirs: TDynamicStringArray; {en Returns a base directory in which to store user-specific application configuration information such as user preferences and settings. } function GetUserConfigDir: String; {en Returns a directory that is unique to the current user on the local system. } function GetUserRuntimeDir: String; {en Returns an ordered list of base directories in which to access system-wide configuration information. } function GetSystemConfigDirs: TDynamicStringArray; {en Get current desktop names } function GetCurrentDesktop: TDynamicStringArray; {en Get desktop file path by desktop base file name. } function GetDesktopPath(const DesktopName: String): String; implementation uses BaseUnix, LazLogger, DCStrUtils, DCOSUtils, uSysFolders; function GetUserCacheDir: String; begin Result:= mbGetEnvironmentVariable('XDG_CACHE_HOME'); if Length(Result) = 0 then begin Result:= GetHomeDir + '/.cache'; end; end; function GetUserDataDir: String; begin Result:= mbGetEnvironmentVariable('XDG_DATA_HOME'); if Length(Result) = 0 then begin Result:= GetHomeDir + '/.local/share'; end; end; function GetSystemDataDirs: TDynamicStringArray; var Value: String; begin Value:= mbGetEnvironmentVariable('XDG_DATA_DIRS'); if Length(Value) = 0 then begin Value:= '/usr/local/share/:/usr/share/'; end; Result:= SplitString(Value, PathSeparator); end; function GetUserConfigDir: String; begin Result:= mbGetEnvironmentVariable('XDG_CONFIG_HOME'); if Length(Result) = 0 then begin Result:= GetHomeDir + '/.config'; end; end; function GetUserRuntimeDir: String; begin Result:= mbGetEnvironmentVariable('XDG_RUNTIME_DIR'); if Length(Result) = 0 then begin if fpGetUID = 0 then Result:= '/run' else begin Result:= '/run/user/' + IntToStr(fpGetUID); if not mbDirectoryExists(Result) then begin Result:= '/var' + Result; if not mbDirectoryExists(Result) then begin Result:= GetUserCacheDir; DebugLn('WARNING: XDG_RUNTIME_DIR not set, defaulting to ', Result); end; end; end; end; end; function GetSystemConfigDirs: TDynamicStringArray; var Value: String; begin Value:= mbGetEnvironmentVariable('XDG_CONFIG_DIRS'); if Length(Value) = 0 then begin Value:= '/etc/xdg'; end; Result:= SplitString(Value, PathSeparator); end; function GetCurrentDesktop: TDynamicStringArray; var Value: String; begin Value:= mbGetEnvironmentVariable('XDG_CURRENT_DESKTOP'); if Length(Value) > 0 then begin Result:= SplitString(Value, PathSeparator); end; end; function GetDesktopPath(const DesktopName: String): String; const PrefixDelim = '-'; var Index: Integer; HasPrefix: Boolean; FileName: String; Path: TDynamicStringArray; function DesktopExists(var DesktopPath: String): Boolean; var Prefix: PAnsiChar; begin if mbFileExists(DesktopPath) then Exit(True); if HasPrefix then begin Prefix := PAnsiChar(DesktopPath); Prefix := strrscan(Prefix, PathDelim); Prefix := strscan(Prefix, PrefixDelim); while (Prefix <> nil) do begin Prefix^:= PathDelim; if mbFileExists(DesktopPath) then Exit(True); Prefix := strscan(Prefix, PrefixDelim); end; end; Result:= False; end; begin HasPrefix:= (Pos(PrefixDelim, DesktopName) > 0); FileName:= 'applications' + PathDelim + DesktopName; // Find in user data directory Result:= IncludeTrailingBackslash(GetUserDataDir) + FileName; if DesktopExists(Result) then Exit; // Find in system data directories Path:= GetSystemDataDirs; for Index:= Low(Path) to High(Path) do begin Result:= IncludeTrailingBackslash(Path[Index]) + FileName; if DesktopExists(Result) then Exit; end; Result:= EmptyStr; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uosforms.pas����������������������������������������������������������0000644�0001750�0000144�00000073535�14743153644�017620� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains platform depended functions. Copyright (C) 2006-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uOSForms; {$mode delphi}{$H+} interface uses LCLType, LMessages, Forms, Classes, SysUtils, Controls, uGlobs, uShellContextMenu, uDrive, uFile, uFileSource; type { TAloneForm } TAloneForm = class(TForm) {$IF DEFINED(DARWIN) AND DEFINED(LCLQT)} protected procedure DoClose(var CloseAction: TCloseAction); override; {$ENDIF} public constructor CreateNew(AOwner: TComponent; Num: Integer = 0); override; end; { TModalDialog } TModalDialog = class(TAloneForm) protected FParentWindow: HWND; procedure CloseModal; protected procedure CreateParams(var Params: TCreateParams); override; public procedure ExecuteModal; virtual; function ShowModal: Integer; override; end; { TModalForm } {$IF DEFINED(LCLWIN32)} TModalForm = class(TModalDialog); {$ELSE} TModalForm = class(TForm); {$ENDIF} {en Must be called on main form create @param(MainForm Main form) } procedure MainFormCreate(MainForm : TCustomForm); {en Show file/folder properties dialog @param(Files List of files to show properties for) } procedure ShowFilePropertiesDialog(aFileSource: IFileSource; const Files: TFiles); {en Show file/folder context menu @param(Parent Parent window) @param(Files List of files to show context menu for. It is freed by this function.) @param(X Screen X coordinate) @param(Y Screen Y coordinate) @param(CloseEvent Method called when popup menu is closed (optional)) } procedure ShowContextMenu(Parent: TWinControl; var Files : TFiles; X, Y : Integer; Background: Boolean; CloseEvent: TNotifyEvent; UserWishForContextMenu:TUserWishForContextMenu = uwcmComplete); {en Show drive context menu @param(Parent Parent window) @param(sPath Path to drive) @param(X Screen X coordinate) @param(Y Screen Y coordinate) @param(CloseEvent Method called when popup menu is closed (optional)) } procedure ShowDriveContextMenu(Parent: TWinControl; ADrive: PDrive; X, Y : Integer; CloseEvent: TNotifyEvent); {en Show trash context menu @param(Parent Parent window) @param(X Screen X coordinate) @param(Y Screen Y coordinate) @param(CloseEvent Method called when popup menu is closed (optional)) } procedure ShowTrashContextMenu(Parent: TWinControl; X, Y : Integer; CloseEvent: TNotifyEvent); {en Show open icon dialog @param(Owner Owner) @param(sFileName Icon file name) @returns(The function returns @true if successful, @false otherwise) } function ShowOpenIconDialog(Owner: TCustomControl; var sFileName : String) : Boolean; {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} {en Show open with dialog @param(FileList List of files to open with) } procedure ShowOpenWithDialog(TheOwner: TComponent; const FileList: TStringList); {$ENDIF} function GetControlHandle(AWindow: TWinControl): HWND; function GetWindowHandle(AWindow: TWinControl): HWND; overload; function GetWindowHandle(AHandle: HWND): HWND; overload; procedure CopyNetNamesToClip; function DarkStyle: Boolean; implementation uses ExtDlgs, LCLProc, Menus, Graphics, InterfaceBase, WSForms, LCLIntf, fMain, uConnectionManager, uShowMsg, uLng, uDCUtils, uDebug {$IF DEFINED(MSWINDOWS)} , LCLStrConsts, ComObj, ActiveX, DCOSUtils, uOSUtils, uFileSystemFileSource , uTotalCommander, FileUtil, Windows, ShlObj, uShlObjAdditional , uWinNetFileSource, uVfsModule, uMyWindows, DCStrUtils, uOleDragDrop , uDCReadRSVG, uFileSourceUtil, uGdiPlusJPEG, uListGetPreviewBitmap , Dialogs, Clipbrd, JwaDbt, uThumbnailProvider, uShellFolder , uRecycleBinFileSource, uWslFileSource, uDCReadHEIF, uDCReadWIC , uShellFileSource, uPixMapManager {$IF DEFINED(DARKWIN)} , uDarkStyle {$ELSEIF DEFINED(LCLQT5)} , qt5, qtwidgets, uDarkStyle {$ENDIF} {$ENDIF} {$IF DEFINED(DARWIN)} , BaseUnix, Errors, fFileProperties , uQuickLook, uOpenDocThumb, uMyDarwin, uDefaultTerminal {$ELSEIF DEFINED(UNIX)} , BaseUnix, Errors, fFileProperties, uJpegThumb, uOpenDocThumb {$IF NOT DEFINED(HAIKU)} , uDCReadRSVG, uMagickWand, uGio, uGioFileSource, uVfsModule, uVideoThumb , uDCReadWebP, uFolderThumb, uAudioThumb, uDefaultTerminal, uDCReadHEIF , uTrashFileSource, uFileManager, uFileSystemFileSource, fOpenWith , uNetworkFileSource {$ENDIF} {$IF DEFINED(LINUX)} , uFlatpak {$ENDIF} {$IF DEFINED(LCLQT)} , qt4, qtwidgets {$ENDIF} {$IF DEFINED(LCLQT5)} , qt5, qtwidgets {$ENDIF} {$IF DEFINED(LCLQT6)} , qt6, qtwidgets {$ENDIF} {$IF DEFINED(LCLGTK2)} , Gtk2, Glib2, Themes {$ENDIF} {$ENDIF} {$IF FPC_FULLVERSION < 30300} , uDCReadPNM {$ENDIF} , uDCReadSVG, uTurboJPEG; { TAloneForm } {$IF DEFINED(DARWIN) AND DEFINED(LCLQT)} var FMain, FBefore, FCurrent: TCustomForm; procedure TAloneForm.DoClose(var CloseAction: TCloseAction); procedure TrySetFocus(Form: TCustomForm); inline; begin if Form.CanFocus then Form.SetFocus; end; var psnFront, psnCurrent: ProcessSerialNumber; begin inherited DoClose(CloseAction); if (GetCurrentProcess(psnCurrent) = noErr) and (GetFrontProcess(psnFront) = noErr) then begin // Check that our process is active if (psnCurrent.lowLongOfPSN = psnFront.lowLongOfPSN) and (psnCurrent.highLongOfPSN = psnFront.highLongOfPSN) then begin // Restore active form if (Screen.CustomFormIndex(FBefore) < 0) then TrySetFocus(FMain) else if (FBefore <> Self) then TrySetFocus(FBefore) else FBefore:= FMain; end; end; end; procedure ActiveFormChangedHandler(Self, Sender: TObject; Form: TCustomForm); begin if (Form is TAloneForm) or (FMain = Form) then begin if FCurrent <> Form then begin FBefore:= FCurrent; FCurrent:= Form; end; end; end; {$ENDIF} constructor TAloneForm.CreateNew(AOwner: TComponent; Num: Integer); begin inherited CreateNew(AOwner, Num); // https://github.com/doublecmd/doublecmd/issues/769 // https://github.com/doublecmd/doublecmd/issues/1358 Constraints.MaxWidth:= High(Int16); Constraints.MaxHeight:= High(Int16); end; { TModalDialog } procedure TModalDialog.CloseModal; var CloseAction: TCloseAction; begin try CloseAction := caNone; if CloseQuery then begin CloseAction := caHide; DoClose(CloseAction); end; case CloseAction of caNone: ModalResult := 0; caFree: Release; end; { do not call widgetset CloseModal here, but in ShowModal to guarantee execution of it } except ModalResult := 0; Application.HandleException(Self); end; end; procedure TModalDialog.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); if FParentWindow <> 0 then begin // It doesn't affect anything under GTK2 and raise // a range check error (LCLGTK2 bug in the function CreateWidgetInfo) {$IFNDEF LCLGTK2} Params.Style := Params.Style or WS_POPUP; {$ENDIF} Params.WndParent := FParentWindow; end; end; procedure TModalDialog.ExecuteModal; begin repeat { Delphi calls Application.HandleMessage But HandleMessage processes all pending events and then calls idle, which will wait for new messages. Under Win32 there is always a next message, so it works there. The LCL is OS independent, and so it uses a better way: } try WidgetSet.AppProcessMessages; // process all events except if Application.CaptureExceptions then Application.HandleException(Self) else raise; end; if Application.Terminated then ModalResult := mrCancel; if ModalResult <> 0 then begin CloseModal; if ModalResult <> 0 then Break; end; Application.Idle(true); until False; end; function TModalDialog.ShowModal: Integer; procedure RaiseShowModalImpossible; var s: String; begin DebugLn('TModalForm.ShowModal Visible=',dbgs(Visible),' Enabled=',dbgs(Enabled), ' fsModal=',dbgs(fsModal in FFormState),' MDIChild=',dbgs(FormStyle = fsMDIChild)); s:='TCustomForm.ShowModal for '+DbgSName(Self)+' impossible, because'; if Visible then s:=s+' already visible (hint for designer forms: set Visible property to false)'; if not Enabled then s:=s+' not enabled'; if fsModal in FFormState then s:=s+' already modal'; if FormStyle = fsMDIChild then s:=s+' FormStyle=fsMDIChild'; raise EInvalidOperation.Create(s); end; var {$IF DEFINED(LCLCOCOA)} DisabledList: TList; {$ENDIF} SavedFocusState: TFocusState; ActiveWindow: HWnd; begin if Self = nil then raise EInvalidOperation.Create('TModalForm.ShowModal Self = nil'); if Application.Terminated then ModalResult := 0; // Cancel drags DragManager.DragStop(false); // Close popupmenus if ActivePopupMenu <> nil then ActivePopupMenu.Close; if Visible or (not Enabled) or (FormStyle = fsMDIChild) then RaiseShowModalImpossible; // Kill capture when opening another dialog if GetCapture <> 0 then SendMessage(GetCapture, LM_CANCELMODE, 0, 0); ReleaseCapture; if Owner is TCustomForm then ActiveWindow := TCustomForm(Owner).Handle else begin ActiveWindow := GetActiveWindow; end; // If parent window is normal window then call inherited method // if GetWindowLong(ActiveWindow, GWL_HWNDPARENT) <> 0 then // Result:= inherited ShowModal // else begin Include(FFormState, fsModal); FParentWindow := ActiveWindow; SavedFocusState := SaveFocusState; Screen.MoveFormToFocusFront(Self); ModalResult := 0; try {$IF NOT DEFINED(LCLCOCOA)} EnableWindow(FParentWindow, False); {$ENDIF} // If window already created then recreate it to force // call CreateParams with appropriate parent window if HandleAllocated then begin {$IF NOT DEFINED(LCLWIN32)} RecreateWnd(Self); {$ELSE} SetWindowLongPtr(Handle, GWL_STYLE, GetWindowLongPtr(Handle, GWL_STYLE) or LONG_PTR(WS_POPUP)); SetWindowLongPtr(Handle, GWL_HWNDPARENT, FParentWindow); {$ENDIF} end; {$IF DEFINED(LCLCOCOA)} if WidgetSet.GetLCLCapability(lcModalWindow) = LCL_CAPABILITY_NO then DisabledList := Screen.DisableForms(Self) else DisabledList := nil; {$ENDIF} Show; try EnableWindow(Handle, True); // Activate must happen after show Perform(CM_ACTIVATE, 0, 0); TWSCustomFormClass(WidgetSetClass).ShowModal(Self); ExecuteModal; Result := ModalResult; if HandleAllocated and (GetActiveWindow <> Handle) then ActiveWindow := 0; finally { Guarantee execution of widgetset CloseModal } TWSCustomFormClass(WidgetSetClass).CloseModal(Self); // Set our modalresult to mrCancel before hiding. if ModalResult = 0 then ModalResult := mrCancel; {$IF DEFINED(LCLCOCOA)} Screen.EnableForms(DisabledList); {$ELSE} EnableWindow(FParentWindow, True); {$ENDIF} // Needs to be called only in ShowModal Perform(CM_DEACTIVATE, 0, 0); Exclude(FFormState, fsModal); end; finally RestoreFocusState(SavedFocusState); if LCLIntf.IsWindow(ActiveWindow) then SetActiveWindow(ActiveWindow); // Hide window when focus already changed back // to parent window to avoid blinking LCLIntf.ShowWindow(Handle, SW_HIDE); Visible := False; end; end; end; var ShellContextMenu : TShellContextMenu = nil; {$IFDEF MSWINDOWS} const WM_USER_ASSOCCHANGED = WM_USER + 201; var OldWProc: WNDPROC; function MyWndProc(hWnd: HWND; uiMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin if (uiMsg = WM_SETTINGCHANGE) and (lParam <> 0) and (StrComp('Environment', {%H-}PAnsiChar(lParam)) = 0) then begin UpdateEnvironment; DCDebug('WM_SETTINGCHANGE:Environment'); end; if (uiMsg = WM_DEVICECHANGE) and (wParam = DBT_DEVNODES_CHANGED) and (lParam = 0) then begin Screen.UpdateMonitors; // Refresh monitor list DCDebug('WM_DEVICECHANGE:DBT_DEVNODES_CHANGED'); end; if (uiMsg = WM_USER_ASSOCCHANGED) then begin PixMapManager.ClearSystemCache; DCDebug('WM_USER_ASSOCCHANGED'); end; Result := CallWindowProc(OldWProc, hWnd, uiMsg, wParam, lParam); end; {$IF DEFINED(LCLWIN32)} procedure ActivateHandler(Self, Sender: TObject); var I: Integer = 0; begin with Screen do begin while (I < CustomFormCount) and (((CustomFormsZOrdered[I] is TModalForm) and ((CustomFormsZOrdered[I] as TModalForm).FParentWindow <> 0)) or not (fsModal in CustomFormsZOrdered[I].FormState)) do Inc(I); // If modal form exists then activate it if (I >= 0) and (I < CustomFormCount) then CustomFormsZOrdered[I].BringToFront; end; end; {$ELSEIF DEFINED(LCLQT5)} procedure ScreenFormEvent(Self, Sender: TObject; Form: TCustomForm); var Handle: HWND; AWindow: QWidgetH; begin if g_darkModeSupported then begin Handle:= GetWindowHandle(Form); AllowDarkModeForWindow(Handle, True); RefreshTitleBarThemeColor(Handle); end; if (Form is THintWindow) then begin AWindow:= QWidget_window(TQtWidget(Form.Handle).GetContainerWidget); QWidget_setWindowFlags(AWindow, QtTool or QtFramelessWindowHint); QWidget_setAttribute(AWindow, QtWA_ShowWithoutActivating); end; end; {$ENDIF} procedure MenuHandler(Self, Sender: TObject); var Ret: DWORD; Res: TNetResourceA; CDS: TConnectDlgStruct; begin if (Sender as TMenuItem).Tag = 0 then begin ZeroMemory(@Res, SizeOf(TNetResourceA)); Res.dwType := RESOURCETYPE_DISK; CDS.cbStructure := SizeOf(TConnectDlgStruct); CDS.hwndOwner := frmMain.Handle; CDS.lpConnRes := @Res; CDS.dwFlags := 0; Ret:= WNetConnectionDialog1(CDS); if Ret = NO_ERROR then begin SetFileSystemPath(frmMain.ActiveFrame, AnsiChar(Int64(CDS.dwDevNum) + Ord('a') - 1) + ':\'); end else if Ret <> DWORD(-1) then begin MessageDlg(mbSysErrorMessage(Ret), mtError, [mbOK], 0); end; end else begin Ret:= WNetDisconnectDialog(fmain.frmMain.Handle, RESOURCETYPE_DISK); case Ret of NO_ERROR, DWORD(-1): ; else MessageDlg(mbSysErrorMessage(Ret), mtError, [mbOK], 0); end; end; end; procedure CreateShortcut(Self, Sender: TObject); var ShortcutName: String; SelectedFiles: TFiles; begin if (not frmMain.ActiveFrame.FileSource.IsClass(TFileSystemFileSource)) or (not frmMain.NotActiveFrame.FileSource.IsClass(TFileSystemFileSource))then begin msgWarning(rsMsgErrNotSupported); Exit; end; SelectedFiles := frmMain.ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count > 0 then begin ShortcutName:= frmMain.NotActiveFrame.CurrentPath + SelectedFiles[0].NameNoExt + '.lnk'; if ShowInputQuery(rsMnuCreateShortcut, EmptyStr, ShortcutName) then begin if mbFileExists(ShortcutName) then begin if not msgYesNo(Format(rsMsgFileExistsRwrt, [WrapTextSimple(ShortcutName, 100)])) then Exit; end; try uMyWindows.CreateShortcut(SelectedFiles[0].FullPath, ShortcutName); except on E: Exception do msgError(E.Message); end; end; end; finally FreeAndNil(SelectedFiles); end; end; {$ENDIF} {$IF DEFINED(LCLGTK2) or ((DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)) and not (DEFINED(DARWIN) or DEFINED(MSWINDOWS)))} procedure ScreenFormEvent(Self, Sender: TObject; Form: TCustomForm); {$IF DEFINED(LCLGTK2)} var ClassName: String; begin ClassName:= Form.ClassName; gtk_window_set_role(PGtkWindow(Form.Handle), PAnsiChar(ClassName)); end; {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} var ClassName: WideString; begin if not (Form is THintWindow) then begin ClassName:= Form.ClassName; QWidget_setWindowRole(QWidget_window(TQtWidget(Form.Handle).GetContainerWidget), @ClassName); end; end; {$ENDIF} {$ENDIF} {$IF DEFINED(DARWIN)} procedure MenuHandler(Self, Sender: TObject); var Address: String = ''; begin if ShowInputQuery(Application.Title, rsMsgURL, False, Address) then MountNetworkDrive(Address); end; {$ELSEIF DEFINED(LCLGTK2)} procedure OnThemeChange; cdecl; begin ThemeServices.IntfDoOnThemeChange; end; {$ENDIF} procedure MainFormCreate(MainForm : TCustomForm); {$IFDEF MSWINDOWS} const SHCNRF_ShellLevel = $0002; var Handle: HWND; Handler: TMethod; MenuItem: TMenuItem; AEntries: TSHChangeNotifyEntry; begin {$IF DEFINED(LCLWIN32)} Handler.Code:= @ActivateHandler; Handler.Data:= MainForm; // Setup application OnActivate handler Application.AddOnActivateHandler(TNotifyEvent(Handler), True); // Disable application button on taskbar with Widgetset do SetWindowLong(AppHandle, GWL_EXSTYLE, GetWindowLong(AppHandle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW); {$ELSEIF DEFINED(LCLQT5)} if g_darkModeEnabled then begin Handler.Data:= MainForm; Handler.Code:= @ScreenFormEvent; Screen.AddHandlerFormVisibleChanged(TScreenFormEvent(Handler), True); end; {$ENDIF} // Register shell folder file source if (Win32MajorVersion > 5) then begin RegisterVirtualFileSource(TShellFileSource.RootName, TShellFileSource); end; // Register recycle bin file source if CheckWin32Version(5, 1) then begin RegisterVirtualFileSource(rsVfsRecycleBin, TRecycleBinFileSource); end; // Register Windows Subsystem for Linux (WSL) file source if CheckWin32Version(10) then begin RegisterVirtualFileSource('Linux', TWslFileSource, TWslFileSource.Available); end; // Register network file source RegisterVirtualFileSource(rsVfsNetwork, TWinNetFileSource); // If run under administrator if (IsUserAdmin = dupAccept) then begin with TfrmMain(MainForm) do StaticTitle:= StaticTitle + ' - Administrator'; end; Handle:= GetWindowHandle(Application.MainForm); // Add main window message handler {$PUSH}{$HINTS OFF} OldWProc := WNDPROC(SetWindowLongPtr(Handle, GWL_WNDPROC, LONG_PTR(@MyWndProc))); {$POP} if Succeeded(SHGetFolderLocation(Handle, CSIDL_DRIVES, 0, 0, AEntries.pidl)) then begin AEntries.fRecursive:= False; SHChangeNotifyRegister(Handle, SHCNRF_ShellLevel, SHCNE_ASSOCCHANGED, WM_USER_ASSOCCHANGED, 1, @AEntries); end; with frmMain do begin Handler.Code:= @MenuHandler; Handler.Data:= MainForm; MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= '-'; mnuNetwork.Add(MenuItem); MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= rsMnuMapNetworkDrive; MenuItem.Tag:= 0; MenuItem.OnClick:= TNotifyEvent(Handler); mnuNetwork.Add(MenuItem); MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= rsMnuDisconnectNetworkDrive; MenuItem.Tag:= 1; MenuItem.OnClick:= TNotifyEvent(Handler); mnuNetwork.Add(MenuItem); MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= '-'; mnuNetwork.Add(MenuItem); MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Action:= frmMain.actCopyNetNamesToClip; mnuNetwork.Add(MenuItem); MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= rsMnuCreateShortcut; Handler.Code:= @CreateShortcut; MenuItem.OnClick:= TNotifyEvent(Handler); mnuFiles.Insert(mnuFiles.IndexOf(miMakeDir) + 1, MenuItem); end; end; {$ELSE} {$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6) or DEFINED(LCLGTK2) or DEFINED(DARWIN)} var Handler: TMethod; {$ENDIF} {$IF DEFINED(DARWIN)} MenuItem: TMenuItem; {$ENDIF} begin if fpGetUID = 0 then // if run under root begin with TfrmMain(MainForm) do StaticTitle:= StaticTitle + ' - ROOT PRIVILEGES'; end; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} if HasGio then begin if TGioFileSource.IsSupportedPath('trash://') then RegisterVirtualFileSource(rsVfsRecycleBin, TTrashFileSource, True); if TGioFileSource.IsSupportedPath('network://') then RegisterVirtualFileSource(rsVfsNetwork, TNetworkFileSource, True); RegisterVirtualFileSource('GVfs', TGioFileSource, False); end; {$ENDIF} {$IF DEFINED(DARWIN) AND DEFINED(LCLQT)} FMain:= MainForm; Handler.Data:= MainForm; Handler.Code:= @ActiveFormChangedHandler; Screen.AddHandlerActiveFormChanged(TScreenFormEvent(Handler), True); {$ELSEIF DEFINED(LCLGTK2) or DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} Handler.Data:= MainForm; Handler.Code:= @ScreenFormEvent; ScreenFormEvent(MainForm, MainForm, MainForm); Screen.AddHandlerFormAdded(TScreenFormEvent(Handler), True); {$ENDIF} {$IF DEFINED(LCLGTK2)} Handler.Data:= gtk_settings_get_default(); if Assigned(Handler.Data) then begin g_signal_connect_data(Handler.Data, 'notify::gtk-theme-name', @OnThemeChange, nil, nil, 0); end; {$ENDIF} {$IF DEFINED(DARWIN)} if HasMountURL then begin with frmMain do begin Handler.Code:= @MenuHandler; Handler.Data:= MainForm; MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= '-'; mnuNetwork.Add(MenuItem); MenuItem:= TMenuItem.Create(mnuMain); MenuItem.Caption:= rsMnuMapNetworkDrive; MenuItem.OnClick:= TNotifyEvent(Handler); mnuNetwork.Add(MenuItem); end; end; {$ENDIF} end; {$ENDIF} procedure ShowContextMenu(Parent: TWinControl; var Files : TFiles; X, Y : Integer; Background: Boolean; CloseEvent: TNotifyEvent; UserWishForContextMenu:TUserWishForContextMenu = uwcmComplete); {$IFDEF MSWINDOWS} begin if Assigned(Files) and (Files.Count = 0) then begin FreeAndNil(Files); Exit; end; try // Create new context menu ShellContextMenu:= TShellContextMenu.Create(Parent, Files, Background, UserWishForContextMenu); ShellContextMenu.OnClose := CloseEvent; // Show context menu ShellContextMenu.PopUp(X, Y); finally // Free created menu FreeAndNil(ShellContextMenu); end; end; {$ELSE} begin if Files.Count = 0 then begin FreeAndNil(Files); Exit; end; // Free previous created menu FreeAndNil(ShellContextMenu); // Create new context menu ShellContextMenu:= TShellContextMenu.Create(nil, Files, Background, UserWishForContextMenu); ShellContextMenu.OnClose := CloseEvent; // Show context menu {$IF DEFINED(DARWIN)} MacosServiceMenuHelper.PopUp( ShellContextMenu, uLng.rsMenuMacOsServices ); {$ELSE} ShellContextMenu.PopUp(X, Y); {$ENDIF} end; {$ENDIF} procedure ShowDriveContextMenu(Parent: TWinControl; ADrive: PDrive; X, Y : Integer; CloseEvent: TNotifyEvent); {$IFDEF MSWINDOWS} var aFile: TFile; Files: TFiles; begin if ADrive.DriveType = dtVirtual then ShowVirtualDriveMenu(ADrive, X, Y, CloseEvent) else begin aFile := TFileSystemFileSource.CreateFile(EmptyStr); if ADrive^.DriveType = dtSpecial then begin aFile.LinkProperty.LinkTo := ADrive^.DeviceId; aFile.Attributes := FILE_ATTRIBUTE_DEVICE; end else begin aFile.FullPath := ADrive^.Path; aFile.Attributes := faFolder or FILE_ATTRIBUTE_DEVICE; end; Files:= TFiles.Create(EmptyStr); // free in ShowContextMenu Files.Add(aFile); ShowContextMenu(Parent, Files, X, Y, False, CloseEvent); end; end; {$ELSE} begin if ADrive.DriveType = dtVirtual then ShowVirtualDriveMenu(ADrive, X, Y, CloseEvent) else begin // Free previous created menu FreeAndNil(ShellContextMenu); // Create new context menu ShellContextMenu:= TShellContextMenu.Create(nil, ADrive); ShellContextMenu.OnClose := CloseEvent; // show context menu ShellContextMenu.PopUp(X, Y); end; end; {$ENDIF} procedure ShowTrashContextMenu(Parent: TWinControl; X, Y: Integer; CloseEvent: TNotifyEvent); {$IFDEF MSWINDOWS} var Files: TFiles = nil; begin ShowContextMenu(Parent, Files, X, Y, False, CloseEvent); end; {$ELSE} begin end; {$ENDIF} (* Show file properties dialog *) procedure ShowFilePropertiesDialog(aFileSource: IFileSource; const Files: TFiles); {$IFDEF UNIX} begin {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} if gSystemItemProperties and aFileSource.IsClass(TFileSystemFileSource) then begin if ShowItemProperties(Files) then Exit; end; {$ENDIF} ShowFileProperties(aFileSource, Files); end; {$ELSE} var Index: Integer; contMenu: IContextMenu; cmici: TCMInvokeCommandInfo; DataObject: THDropDataObject; begin if Files.Count = 0 then Exit; try if CheckWin32Version(5, 1) then begin DataObject:= THDropDataObject.Create(DROPEFFECT_NONE); for Index:= 0 to Files.Count - 1 do begin DataObject.Add(Files[Index].FullPath); end; OleCheckUTF8(MultiFileProperties(DataObject, 0)); end else begin contMenu := GetShellContextMenu(frmMain.Handle, Files, False); if Assigned(contMenu) then begin cmici:= Default(TCMInvokeCommandInfo); with cmici do begin cbSize := SizeOf(TCMInvokeCommandInfo); hwnd := frmMain.Handle; lpVerb := sCmdVerbProperties; nShow := SW_SHOWNORMAL; end; OleCheckUTF8(contMenu.InvokeCommand(cmici)); end; end; except on E: EOleError do raise EContextMenuException.Create(E.Message); end; end; {$ENDIF} function ShowOpenIconDialog(Owner: TCustomControl; var sFileName : String) : Boolean; var opdDialog : TOpenPictureDialog; {$IFDEF MSWINDOWS} sFilter : String; iPos, iIconIndex: Integer; bAlreadyOpen : Boolean; bFlagKeepGoing : Boolean = True; {$ENDIF} begin opdDialog := nil; {$IFDEF MSWINDOWS} sFilter := GraphicFilter(TGraphic) + '|' + rsFilterProgramsLibraries + ' (*.exe;*.dll)|*.exe;*.dll' + '|' + Format(rsAllFiles, [GetAllFilesMask, GetAllFilesMask, '']); bAlreadyOpen := False; iPos :=Pos(',', sFileName); if iPos <> 0 then begin iIconIndex := StrToIntDef(Copy(sFileName, iPos + 1, Length(sFileName) - iPos), 0); sFileName := Copy(sFileName, 1, iPos - 1); end else begin opdDialog := TOpenPictureDialog.Create(Owner); opdDialog.Filter := sFilter; opdDialog.InitialDir := ExtractFileDir(sFileName); opdDialog.FileName := sFileName; Result := opdDialog.Execute; if Result then sFileName := opdDialog.FileName else bFlagKeepGoing := False; bAlreadyOpen := True; end; if FileIsExeLib(sFileName) then begin if bFlagKeepGoing then begin Result := SHChangeIconDialog(GetWindowHandle(Owner), sFileName, iIconIndex); if Result then sFileName := sFileName + ',' + IntToStr(iIconIndex); end; end else if not bAlreadyOpen then {$ENDIF} begin opdDialog := TOpenPictureDialog.Create(Owner); opdDialog.InitialDir:=ExtractFileDir(sFileName); {$IFDEF MSWINDOWS} opdDialog.Filter:= sFilter; {$ENDIF} opdDialog.FileName := sFileName; Result:= opdDialog.Execute; sFileName := opdDialog.FileName; end; if Assigned(opdDialog) then FreeAndNil(opdDialog); end; function GetControlHandle(AWindow: TWinControl): HWND; {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} begin Result:= HWND(QWidget_winId(TQtWidget(AWindow.Handle).GetContainerWidget)); end; {$ELSE} begin Result:= AWindow.Handle; end; {$ENDIF} function GetWindowHandle(AWindow: TWinControl): HWND; {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} begin Result:= Windows.GetAncestor(HWND(QWidget_winId(TQtWidget(AWindow.Handle).GetContainerWidget)), GA_ROOT); end; {$ELSE} begin Result:= AWindow.Handle; end; {$ENDIF} function GetWindowHandle(AHandle: HWND): HWND; {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} begin Result:= Windows.GetAncestor(HWND(QWidget_winId(TQtWidget(AHandle).GetContainerWidget)), GA_ROOT); end; {$ELSE} begin Result:= AHandle; end; {$ENDIF} procedure CopyNetNamesToClip; {$IF DEFINED(MSWINDOWS)} var I: Integer; sl: TStringList = nil; SelectedFiles: TFiles = nil; begin SelectedFiles := frmMain.ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count > 0 then begin sl := TStringList.Create; for I := 0 to SelectedFiles.Count - 1 do begin sl.Add(mbGetRemoteFileName(SelectedFiles[I].FullPath)); end; Clipboard.Clear; // Prevent multiple formats in Clipboard (specially synedit) Clipboard.AsText := TrimRightLineEnding(sl.Text, sl.TextLineBreakStyle); end; finally FreeAndNil(sl); FreeAndNil(SelectedFiles); end; end; {$ELSE} begin msgWarning(rsMsgErrNotSupported); end; {$ENDIF} function DarkStyle: Boolean; {$IF DEFINED(DARKWIN)} begin Result:= g_darkModeEnabled; end; {$ELSE} begin Result:= not ColorIsLight(ColorToRGB(clWindow)); end; {$ENDIF} {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} procedure ShowOpenWithDialog(TheOwner: TComponent; const FileList: TStringList); begin fOpenWith.ShowOpenWithDlg(TheOwner, FileList); end; {$ENDIF} {$IF DEFINED(UNIX)} procedure handle_sigterm(signal: longint); cdecl; begin DCDebug('SIGTERM'); frmMain.Close; end; procedure RegisterHandler; var sa: sigactionrec; begin FillChar(sa, SizeOf(sa), #0); sa.sa_handler := @handle_sigterm; if (fpSigAction(SIGTERM, @sa, nil) = -1) then begin Errors.PError('fpSigAction', GetLastOSError); end; end; initialization RegisterHandler; {$ENDIF} finalization FreeAndNil(ShellContextMenu); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/upixmapgtk.pas��������������������������������������������������������0000644�0001750�0000144�00000006652�14743153644�020130� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uPixMapGtk; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, IntfGraphics, gtk2def, gdk2pixbuf, gdk2, glib2; function ImageToPixBuf(Image: TLazIntfImage): PGdkPixbuf; procedure DrawPixbufAtCanvas(Canvas: TCanvas; Pixbuf : PGdkPixbuf; SrcX, SrcY, DstX, DstY, Width, Height: Integer); function PixBufToBitmap(Pixbuf: PGdkPixbuf): TBitmap; implementation uses GraphType, uGraphics; procedure DrawPixbufAtCanvas(Canvas: TCanvas; Pixbuf : PGdkPixbuf; SrcX, SrcY, DstX, DstY, Width, Height: Integer); var gdkDrawable : PGdkDrawable; gdkGC : PGdkGC; gtkDC : TGtkDeviceContext; iPixbufWidth, iPixbufHeight: Integer; StretchedPixbuf: PGdkPixbuf; begin gtkDC := TGtkDeviceContext(Canvas.Handle); gdkDrawable := gtkDC.Drawable; gdkGC := gdk_gc_new(gdkDrawable); iPixbufWidth := gdk_pixbuf_get_width(Pixbuf); iPixbufHeight := gdk_pixbuf_get_height(Pixbuf); if (Width <> iPixbufWidth) or (Height <> iPixbufHeight) then begin StretchedPixbuf := gdk_pixbuf_scale_simple(Pixbuf, Width, Height, GDK_INTERP_BILINEAR); gdk_draw_pixbuf(gdkDrawable, gdkGC, StretchedPixbuf, SrcX, SrcY, DstX, DstY, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); gdk_pixbuf_unref(StretchedPixbuf); end else gdk_draw_pixbuf(gdkDrawable, gdkGC, Pixbuf, SrcX, SrcY, DstX, DstY, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); g_object_unref(gdkGC); end; function PixBufToBitmap(Pixbuf: PGdkPixbuf): TBitmap; var width, height, rowstride, n_channels, i, j: Integer; pixels: Pguchar; pSrc: PByte; pDst: PLongWord; BmpData: TLazIntfImage; hasAlphaChannel: Boolean; QueryFlags: TRawImageQueryFlags = [riqfRGB]; Description: TRawImageDescription; begin Result := nil; n_channels:= gdk_pixbuf_get_n_channels(Pixbuf); if ((n_channels <> 3) and (n_channels <> 4)) or // RGB or RGBA (gdk_pixbuf_get_colorspace(pixbuf) <> GDK_COLORSPACE_RGB) or (gdk_pixbuf_get_bits_per_sample(pixbuf) <> 8) then Exit; width:= gdk_pixbuf_get_width(Pixbuf); height:= gdk_pixbuf_get_height(Pixbuf); rowstride:= gdk_pixbuf_get_rowstride(Pixbuf); pixels:= gdk_pixbuf_get_pixels(Pixbuf); hasAlphaChannel:= gdk_pixbuf_get_has_alpha(Pixbuf); if hasAlphaChannel then Include(QueryFlags, riqfAlpha); BmpData := TLazIntfImage.Create(width, height, QueryFlags); try BmpData.CreateData; Description := BmpData.DataDescription; pDst := PLongWord(BmpData.PixelData); for j:= 0 to Height - 1 do begin pSrc := PByte(pixels) + j * rowstride; for i:= 0 to Width - 1 do begin pDst^ := pSrc[0] shl Description.RedShift + pSrc[1] shl Description.GreenShift + pSrc[2] shl Description.BlueShift; if hasAlphaChannel then pDst^ := pDst^ + pSrc[3] shl Description.AlphaShift; Inc(pSrc, n_channels); Inc(pDst); end; end; Result := TBitmap.Create; BitmapAssign(Result, BmpData); if not hasAlphaChannel then Result.Transparent := True; finally BmpData.Free; end; end; procedure GdkPixbufDestroy(pixels: Pguchar; data: gpointer); cdecl; begin PRawImage(data)^.FreeData; Dispose(PRawImage(data)); end; function ImageToPixBuf(Image: TLazIntfImage): PGdkPixbuf; var ARawImage: PRawImage; begin New(ARawImage); Image.GetRawImage(ARawImage^, True); Result:= gdk_pixbuf_new_from_data(Image.PixelData, GDK_COLORSPACE_RGB, True, 8, Image.Width, Image.Height, Image.Width * 4, @GdkPixbufDestroy, ARawImage); end; end. ��������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/upixmapmanager.pas����������������������������������������������������0000644�0001750�0000144�00000246254�14743153644�020761� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Fast pixmap memory manager and loader Copyright (C) 2004 Radek Cervinka (radek.cervinka@centrum.cz) Copyright (C) 2006-2025 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uPixMapManager; {$mode objfpc}{$H+} {$IFDEF DARWIN} {$modeswitch objectivec1} {$ENDIF} interface { GTK2 is used directly in PixmapManager, because FPC/Lazarus draws bitmaps without alpha channel under GTK2, so bitmaps looks ugly. If this problem will be fixed then GTK2 specific code could be dropped. } {$IF DEFINED(LCLGTK2) AND DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} {$DEFINE GTK2_FIX} {$ENDIF} // Use freedesktop.org specifications {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} {$DEFINE XDG} {$ENDIF} uses Classes, SysUtils, Graphics, syncobjs, uFileSorting, DCStringHashListUtf8, uFile, uIconTheme, uDrive, uDisplayFile, uGlobs, uDCReadPSD, uOSUtils, FPImage, LCLVersion, uVectorImage {$IF DEFINED(MSWINDOWS)} , ShlObj {$ELSEIF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} , fgl {$ELSEIF DEFINED(UNIX)} , DCFileAttributes {$IF DEFINED(DARWIN)} , CocoaUtils, uMyDarwin {$ELSEIF NOT DEFINED(HAIKU)} , Math, Contnrs, uGio, uXdg {$IFDEF GTK2_FIX} , gtk2 {$ELSE} , uUnixIconTheme {$ENDIF} {$ENDIF} {$ENDIF}; const DC_THEME_NAME = 'dctheme'; type TDriveIconList = record Size: Integer; Bitmap: array[TDriveType] of TBitmap; end; { TfromWhatBitmapWasLoaded } //Used to indicate from where the icon was loaded from. //Useful when exporting to TC for example which cannot used "as is" the same icon file in some circumstances. TfromWhatBitmapWasLoaded = (fwbwlNotLoaded, fwbwlIconThemeBitmap, fwbwlResourceFileExtracted, fwbwlGraphicFile, fwbwlGraphicFileNotSupportedByTC, fwbwlFileIconByExtension, fwbwlFiDefaultIconID); PTfromWhatBitmapWasLoaded = ^TfromWhatBitmapWasLoaded; { TPixMapManager } TPixMapManager = class private {en Maps file extension to index of bitmap (in FPixmapList) for this file extension. } FExtList : TStringHashListUtf8; {en Maps icon filename to index of bitmap (in FPixmapList) for this icon. Uses absolute file names. } FPixmapsFileNames : TStringHashListUtf8; {en A list of loaded bitmaps. Stores TBitmap objects (on GTK2 it stores PGdkPixbuf pointers). } FPixmapList : TFPList; {en Lock used to synchronize access to PixmapManager storage. } FPixmapsLock: TCriticalSection; FDriveIconList : array[0..2] of TDriveIconList; FiDirIconID : PtrInt; FiDirLinkBrokenIconID : PtrInt; FiLinkBrokenIconID : PtrInt; FiEmblemLinkID: PtrInt; FiEmblemUnreadableID: PtrInt; FiUpDirIconID : PtrInt; FiDefaultIconID : PtrInt; FiExeIconID : PtrInt; FiArcIconID : PtrInt; FiSortAscID : PtrInt; FiSortDescID : PtrInt; FiHashIconID : PtrInt; {$IF DEFINED(MSWINDOWS)} FSysImgList : THandle; FiSysDirIconID : PtrInt; FiEmblemPinned: PtrInt; FiEmblemOnline: PtrInt; FiEmblemOffline: PtrInt; FiShortcutIconID: PtrInt; FOneDrivePath: String; {$ELSEIF DEFINED(DARWIN)} FUseSystemTheme: Boolean; {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(HAIKU)} {en Maps file extension to MIME icon name(s). } FExtToMimeIconName: TFPDataHashTable; {$IFDEF GTK2_FIX} FIconTheme: PGtkIconTheme; {$ELSE} FIconTheme: TIconTheme; {$ENDIF} FHomeFolder: String; {$ENDIF} {en Maps theme icon name to index of bitmap (in FPixmapList) for this icon. } FThemePixmapsFileNames: TStringHashListUtf8; FDCIconTheme: TIconTheme; {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} type TPtrIntMap = specialize TFPGMap<PtrInt, PtrInt>; var FSystemIndexList: TPtrIntMap; {$ENDIF} procedure CreateIconTheme; procedure DestroyIconTheme; function AddSpecial(ALow, AHigh: PtrInt): PtrInt; {en Same as LoadBitmap but displays a warning if pixmap file doesn't exist. } function CheckLoadPixmapFromFile(const AIconName: String) : TBitmap; {en If path is absolute tries to load bitmap and add to storage. If path is relative it tries to load theme icon and add to storage. } function CheckAddPixmap(AIconName: String; AIconSize : Integer = 0): PtrInt; {en Loads a theme icon and adds it to storage. This function should only be called under FPixmapLock. } function CheckAddThemePixmapLocked(AIconName: String; AIconSize: Integer): PtrInt; {en Loads a theme icon and adds it to storage. Safe to call without a lock. } function CheckAddThemePixmap(const AIconName: String; AIconSize: Integer = 0) : PtrInt; {en Loads an icon from default theme (DCTheme) and adds it to storage. } function AddDefaultThemePixmap(const AIconName: String; AIconSize: Integer = 0) : PtrInt; {en Loads an icon from the theme } function LoadThemeIcon(AIconTheme: TIconTheme; const AIconName: String; AIconSize: Integer): TBitmap; {en Loads a theme icon. Returns TBitmap (on GTK2 convert GdkPixbuf to TBitmap). This function should only be called under FPixmapLock. } function LoadIconThemeBitmapLocked(AIconName: String; AIconSize: Integer): TBitmap; {en Loads a plugin icon. } function GetPluginIcon(const AIconName: String; ADefaultIcon: PtrInt): PtrInt; {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} function CheckAddSystemIcon(ASystemIndex: PtrInt): PtrInt; {$ENDIF} {$IF DEFINED(WINDOWS)} function GetShellFolderIcon(AFile: TFile): PtrInt; {en Checks if the AIconName points to an icon resource in a library, executable, etc. @param(AIconName Full path to the file with the icon with appended "," and icon index.) @param(IconFile Returns the full path to the file containing the icon resource.) @param(IconIndex Returns the index of the icon in the file.) @returns(@true if AIconName points to an icon resource, @false otherwise.) } function GetIconResourceIndex(const IconPath: String; out IconFile: String; out IconIndex: PtrInt): Boolean; function GetSystemFileIcon(const FileName: String; dwFileAttributes: DWORD = 0): PtrInt; function GetSystemFolderIcon: PtrInt; function GetSystemArchiveIcon: PtrInt; function GetSystemShortcutIcon: PtrInt; inline; function GetSystemExecutableIcon: PtrInt; inline; {$ENDIF} {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} function GetSystemFolderIcon: PtrInt; function GetSystemArchiveIcon: PtrInt; {en Loads MIME icons names and creates a mapping: file extension -> MIME icon name. Doesn't need to be synchronized as long as it's only called from Load(). } procedure LoadMimeIconNames; {en Retrieves index of a theme icon based on file extension using Extension->MIME map. Loads the icon and adds it into PixmapManager, if not yet added. This function should only be called under FPixmapLock. } function GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt; {en It is synchronized in GetIconByName->CheckAddPixmap. } function GetIconByDesktopFile(sFileName: String; iDefaultIcon: PtrInt): PtrInt; {$ENDIF} {$IF DEFINED(DARWIN)} function GetSystemFolderIcon: PtrInt; function GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt; function LoadImageFileBitmap( const filename:String; const size:Integer ): TBitmap; {$ENDIF} function GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} procedure LoadApplicationThemeIcon; {$ENDIF} public constructor Create; destructor Destroy; override; procedure Load(const sFileName : String); {en Loads a graphical file (if supported) to a bitmap. @param(AIconFileName must be a full path to the graphical file.) @param(ABitmap receives a new bitmap object.) @returns(@true if bitmap has been loaded, @false otherwise.) } function LoadBitmapFromFile(AIconFileName: String; out ABitmap: TBitmap): Boolean; {en Loads a graphical file as a bitmap if filename is full path. Environment variables in the filename are supported. If filename is not graphic file it tries to load some bitmap associated with the file (by extension, attributes, etc.). Loads an icon from a file's resources if filename ends with ",Nr" (on Windows). Loads a theme icon if filename is not a full path. Performs resize of the bitmap to <iIconSize>x<iIconSize> if Stretch = @true. If Stretch = @false then clBackColor is ignored. } function LoadBitmapEnhanced(sFileName : String; iIconSize : Integer; Stretch: Boolean; clBackColor : TColor; fromWhatItWasLoaded:PTfromWhatBitmapWasLoaded = nil) : Graphics.TBitmap; {en Loads a theme icon as bitmap. @param(AIconName is a MIME type name.) } function LoadIconThemeBitmap(AIconName: String; AIconSize: Integer): TBitmap; {en Retrieves a bitmap stored in PixmapManager by index (always returns a new copy). On Windows if iIndex points to system icon list it creates a new bitmap by loading system icon and drawing onto the bitmap. } function GetBitmap(iIndex : PtrInt) : TBitmap; function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean; function DrawBitmapAlpha(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean; {en Draws bitmap stretching it if needed to Width x Height. If Width is 0 then full bitmap width is used. If Height is 0 then full bitmap height is used. @param(iIndex Index of pixmap manager's bitmap.) } function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y, Width, Height: Integer) : Boolean; {en Draws overlay bitmap for a file. @param(AFile File for which is needed to draw the overlay icon.) @param(DirectAccess Whether the file is on a directly accessible file source.) } function DrawBitmapOverlay(AFile: TDisplayFile; DirectAccess: Boolean; Canvas : TCanvas; X, Y: Integer) : Boolean; function GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt; {en Retrieves icon index in FPixmapList table for a file. @param(AFile File for which to retrieve the icon.) @param(DirectAccess Whether the file is on a directly accessible file source.) @param(LoadIcon Only used when an icon for a file does not yet exist in FPixmapsList. If @true then it loads the icon into FPixmapsList table and returns the index of the loaded icon. If @false then it returns -1 to notify that an icon for the file does not exist in FPixmapsList. If the icon already exists for the file the function returns its index regardless of LoadIcon parameter.) @param(IconsMode Whether to retrieve only standard icon, also from file resources, etc.) @param(GetIconWithLink If the file is a link and GetLinkIcon is @true it retrieves icon with embedded link bitmap. If @false it only retrieves the file icon itself.) } function GetIconByFile(AFile: TFile; DirectAccess: Boolean; LoadIcon: Boolean; IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt; {$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)} {en Retrieves overlay icon index for a file. @param(AFile File for which to retrieve the overlay icon.) @param(DirectAccess Whether the file is on a directly accessible file source.) } function GetIconOverlayByFile(AFile: TFile; DirectAccess: Boolean): PtrInt; {$ELSEIF DEFINED(DARWIN)} function GetApplicationBundleIcon(sFileName: String; iDefaultIcon: PtrInt): PtrInt; {$ENDIF} function GetIconByName(const AIconName: String): PtrInt; function GetThemeIcon(const AIconName: String; AIconSize: Integer) : Graphics.TBitmap; function GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor; LoadIcon: Boolean = True) : Graphics.TBitmap; function GetDefaultDriveIcon(IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap; function GetArchiveIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap; function GetFolderIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap; {en Returns default icon for a file. For example default folder icon for folder, default executable icon for *.exe, etc. } function GetDefaultIcon(AFile: TFile): PtrInt; {$IF DEFINED(MSWINDOWS)} procedure ClearSystemCache; {$ENDIF} end; var PixMapManager: TPixMapManager = nil; var ICON_SIZES: array [0..3] of Integer = (16, 24, 32, 48); procedure LoadPixMapManager; function AdjustIconSize(ASize: Integer; APixelsPerInch: Integer): Integer; function StretchBitmap(var bmBitmap : Graphics.TBitmap; iIconSize : Integer; clBackColor : TColor; bFreeAtEnd : Boolean = False) : Graphics.TBitmap; implementation uses GraphType, LCLIntf, LCLType, LCLProc, Forms, uGlobsPaths, WcxPlugin, DCStrUtils, uDCUtils, uFileSystemFileSource, uReSample, uDebug, IntfGraphics, DCOSUtils, DCClassesUtf8, LazUTF8, uGraphics, uHash, uSysFolders {$IFDEF GTK2_FIX} , uPixMapGtk, gdk2pixbuf, gdk2, glib2 {$ENDIF} {$IFDEF MSWINDOWS} , ActiveX, CommCtrl, ShellAPI, Windows, DCFileAttributes, uBitmap, uGdiPlus, DCConvertEncoding, uShlObjAdditional, uShellFolder, uShellFileSourceUtil {$ELSE} , StrUtils, Types, DCBasicTypes {$ENDIF} {$IFDEF DARWIN} , CocoaAll, MacOSAll, uClassesEx {$ENDIF} {$IFDEF RabbitVCS} , uRabbitVCS {$ENDIF} ; {$IF DEFINED(MSWINDOWS)} type TBitmap = Graphics.TBitmap; {$ENDIF} {$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)} const SystemIconIndexStart: PtrInt = High(PtrInt) div 2; {$ENDIF} function AdjustIconSize(ASize: Integer; APixelsPerInch: Integer): Integer; begin {$IF DEFINED(MSWINDOWS)} if (APixelsPerInch = Screen.PixelsPerInch) then Result:= ASize else begin Result:= MulDiv(ASize, Screen.PixelsPerInch, APixelsPerInch); end; {$ELSE} Result:= ASize; {$ENDIF} end; function StretchBitmap(var bmBitmap : Graphics.TBitmap; iIconSize : Integer; clBackColor : TColor; bFreeAtEnd : Boolean = False) : Graphics.TBitmap; begin if (bmBitmap.Height > 0) and (bmBitmap.Width > 0) and ((iIconSize <> bmBitmap.Height) or (iIconSize <> bmBitmap.Width)) then begin Result := Graphics.TBitMap.Create; try Result.SetSize(iIconSize, iIconSize); Stretch(bmBitmap, Result, ResampleFilters[2].Filter, ResampleFilters[2].Width); if bFreeAtEnd then FreeAndNil(bmBitmap); except FreeAndNil(Result); raise; end; end // Don't need to stretch. else if bFreeAtEnd then begin Result := bmBitmap; bmBitmap := nil; end else begin Result := Graphics.TBitMap.Create; try Result.Assign(bmBitmap); except FreeAndNil(Result); raise; end; end; end; { TPixMapManager } { TPixMapManager.LoadBitmapFromFile } function TPixMapManager.LoadBitmapFromFile(AIconFileName: String; out ABitmap: Graphics.TBitmap): Boolean; var {$IFDEF GTK2_FIX} pbPicture : PGdkPixbuf; {$ELSE} Picture: TPicture; {$ENDIF} begin Result:= False; {$IFDEF GTK2_FIX} pbPicture := gdk_pixbuf_new_from_file(PChar(AIconFileName), nil); if pbPicture <> nil then begin ABitmap := PixBufToBitmap(pbPicture); gdk_pixmap_unref(pbPicture); // if unsupported BitsPerPixel then exit if (ABitmap = nil) or (ABitmap.RawImage.Description.BitsPerPixel > 32) then raise EInvalidGraphic.Create('Unsupported bits per pixel'); Result:= True; end; {$ELSE} Picture := TPicture.Create; try ABitmap := Graphics.TBitmap.Create; try Picture.LoadFromFile(AIconFileName); //Picture.Graphic.Transparent := True; ABitmap.Assign(Picture.Graphic); // if unsupported BitsPerPixel then exit if ABitmap.RawImage.Description.BitsPerPixel > 32 then raise EInvalidGraphic.Create('Unsupported bits per pixel'); Result:= True; except on E: Exception do begin FreeAndNil(ABitmap); DCDebug(Format('Error: Cannot load pixmap [%s] : %s',[AIconFileName, e.Message])); end; end; finally FreeAndNil(Picture); end; {$ENDIF} end; function TPixMapManager.LoadBitmapEnhanced(sFileName : String; iIconSize : Integer; Stretch: Boolean; clBackColor : TColor; fromWhatItWasLoaded:PTfromWhatBitmapWasLoaded) : Graphics.TBitmap; var {$IFDEF MSWINDOWS} iIconIndex: PtrInt; iIconSmall: Integer; phIcon: HICON = INVALID_HANDLE_VALUE; phIconLarge : HICON = 0; phIconSmall : HICON = 0; IconFileName: String; {$ENDIF} AFile: TFile; AIcon: TIcon; iIndex : PtrInt; GraphicClass: TGraphicClass; bmStandartBitmap : Graphics.TBitMap = nil; begin Result := nil; if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlNotLoaded; sFileName:= ReplaceEnvVars(sFileName); sFileName:= ExpandAbsolutePath(sFileName); // If the name is not full path then treat it as MIME type. if GetPathType(sFileName) = ptNone then begin bmStandartBitmap := LoadIconThemeBitmap(sFileName, iIconSize); if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlIconThemeBitmap; end else {$IFDEF MSWINDOWS} if GetIconResourceIndex(sFileName, IconFileName, iIconIndex) then begin if ExtractIconExW(PWChar(CeUtf8ToUtf16(IconFileName)), iIconIndex, phIconLarge, phIconSmall, 1) = 2 then // if extracted both icons begin // Get system metrics iIconSmall:= GetSystemMetrics(SM_CXSMICON); if iIconSize <= iIconSmall then phIcon:= phIconSmall // Use small icon else begin phIcon:= phIconLarge // Use large icon end; if phIcon <> INVALID_HANDLE_VALUE then begin bmStandartBitmap := BitmapCreateFromHICON(phIcon); if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlResourceFileExtracted; end; DestroyIcon(phIconLarge); DestroyIcon(phIconSmall); end; end // GetIconResourceIndex else {$ENDIF} begin // if file is graphic GraphicClass:= GetGraphicClassForFileExtension(ExtractOnlyFileExt(sFileName)); if (GraphicClass <> nil) and mbFileExists(sFileName) then begin if (GraphicClass = TIcon) then begin AIcon:= TIcon.Create; try AIcon.LoadFromFile(sFileName); AIcon.Current:= AIcon.GetBestIndexForSize(TSize.Create(iIconSize, iIconSize)); bmStandartBitmap:= Graphics.TBitmap.Create; try if AIcon.RawImage.Description.AlphaPrec <> 0 then BitmapAssign(bmStandartBitmap, AIcon) else BitmapConvert(AIcon, bmStandartBitmap); except FreeAndNil(bmStandartBitmap); end; except on E: Exception do DCDebug(Format('Error: Cannot load icon [%s] : %s',[sFileName, E.Message])); end; AIcon.Free; end else begin LoadBitmapFromFile(sFileName, bmStandartBitmap); end; if fromWhatItWasLoaded <> nil then fromWhatItWasLoaded^ := fwbwlGraphicFile; end; end; if not Assigned(bmStandartBitmap) then // get file icon by ext begin if mbFileSystemEntryExists(sFileName) then begin AFile := TFileSystemFileSource.CreateFileFromFile(sFileName); try iIndex := GetIconByFile(AFile, True, True, sim_all_and_exe, False); bmStandartBitmap := GetBitmap(iIndex); if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlFileIconByExtension; finally FreeAndNil(AFile); end; end else // file not found begin bmStandartBitmap := GetBitmap(FiDefaultIconID); if fromWhatItWasLoaded<> nil then fromWhatItWasLoaded^ := fwbwlFiDefaultIconID; end; end; if Stretch and Assigned(bmStandartBitmap) then Result := StretchBitmap(bmStandartBitmap, iIconSize, clBackColor, True) else Result := bmStandartBitmap; end; function TPixMapManager.LoadIconThemeBitmap(AIconName: String; AIconSize: Integer): Graphics.TBitmap; begin FPixmapsLock.Acquire; try Result := LoadIconThemeBitmapLocked(AIconName, AIconSize); finally FPixmapsLock.Release; end; end; function TPixMapManager.CheckLoadPixmapFromFile(const AIconName: String): Graphics.TBitmap; begin if not mbFileExists(AIconName) then begin DCDebug(Format('Warning: pixmap [%s] not exists!',[AIconName])); Exit(nil); end; LoadBitmapFromFile(AIconName, Result); end; function TPixMapManager.CheckAddThemePixmap(const AIconName: String; AIconSize : Integer) : PtrInt; begin if AIconSize = 0 then AIconSize := gIconsSize; FPixmapsLock.Acquire; try Result := CheckAddThemePixmapLocked(AIconName, AIconSize); finally FPixmapsLock.Release; end; end; function TPixMapManager.CheckAddPixmap(AIconName: String; AIconSize : Integer): PtrInt; var fileIndex: PtrInt; {$IFDEF GTK2_FIX} pbPicture : PGdkPixbuf; {$ELSE} bmpBitmap: Graphics.TBitmap; {$ENDIF} begin Result:= -1; if AIconName = EmptyStr then Exit; if AIconSize = 0 then AIconSize := gIconsSize; AIconName := ReplaceEnvVars(AIconName); if GetPathType(AIconName) = ptAbsolute then begin FPixmapsLock.Acquire; try // Determine if this file is already loaded. fileIndex := FPixmapsFileNames.Find(AIconName); if fileIndex < 0 then begin {$IFDEF GTK2_FIX} if not mbFileExists(AIconName) then begin DCDebug(Format('Warning: pixmap [%s] not exists!', [AIconName])); Exit; end; pbPicture := gdk_pixbuf_new_from_file_at_size(PChar(AIconName), AIconSize, AIconSize, nil); if Assigned(pbPicture) then begin Result := FPixmapList.Add(pbPicture); FPixmapsFileNames.Add(AIconName, Pointer(Result)); end else DCDebug(Format('Error: pixmap [%s] not loaded!', [AIconName])); {$ELSE} {$IFDEF DARWIN} bmpBitmap := LoadImageFileBitmap(AIconName, AIconSize); {$ELSE} bmpBitmap := LoadBitmapEnhanced(AIconName, AIconSize, False, clNone, nil); {$ENDIF} if Assigned(bmpBitmap) then begin // MacOS' high resolution screen parameters are different from other operating systems {$IF NOT DEFINED(DARWIN)} // Shrink big bitmaps before putting them into PixmapManager, // to speed up later drawing. if (bmpBitmap.Width > 48) or (bmpBitmap.Height > 48) then begin bmpBitmap := StretchBitmap(bmpBitmap, AIconSize, clBlack, True); end; {$ENDIF} Result := FPixmapList.Add(bmpBitmap); FPixmapsFileNames.Add(AIconName, Pointer(Result)); end; {$ENDIF} end else begin Result:= PtrInt(FPixmapsFileNames.List[fileIndex]^.Data); end; finally FPixmapsLock.Release; end; end else begin Result := CheckAddThemePixmap(AIconName, AIconSize); end; end; procedure TPixMapManager.CreateIconTheme; var DirList: array of string; begin {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} {$IFDEF GTK2_FIX} // get current gtk theme FIconTheme:= gtk_icon_theme_get_for_screen(gdk_screen_get_default); { // load custom theme FIconTheme:= gtk_icon_theme_new; gtk_icon_theme_set_custom_theme(FIconTheme, 'oxygen'); } {$ELSE} FIconTheme:= TIconTheme.Create(GetCurrentIconTheme, GetUnixIconThemeBaseDirList, GetUnixDefaultTheme); {$ENDIF} {$ENDIF} // Create DC theme. if not gUseConfigInProgramDir then begin AddString(DirList, IncludeTrailingBackslash(GetAppDataDir) + 'pixmaps'); end; AddString(DirList, ExcludeTrailingPathDelimiter(gpPixmapPath)); FDCIconTheme := TIconTheme.Create(gIconTheme, DirList, DC_THEME_NAME); end; procedure TPixMapManager.DestroyIconTheme; begin {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} {$IFDEF GTK2_FIX} FIconTheme:= nil; {$ELSE} if Assigned(FIconTheme) then FreeAndNil(FIconTheme); {$ENDIF} {$ENDIF} FreeAndNil(FDCIconTheme); end; function TPixMapManager.AddSpecial(ALow, AHigh: PtrInt): PtrInt; var X, Y: Integer; AIcon: TBitmap; ABitmap: TBitmap; Source, Target: TLazIntfImage; begin AIcon:= GetBitmap(ALow); Target:= TLazIntfImage.Create(AIcon.Width, AIcon.Height, [riqfRGB, riqfAlpha]); try {$if lcl_fullversion < 2020000} Target.CreateData; {$endif} Target.FillPixels(colTransparent); Source:= TLazIntfImage.Create(AIcon.RawImage, False); try Target.CopyPixels(Source); finally Source.Free; end; ABitmap:= GetBitmap(AHigh); try Source:= TLazIntfImage.Create(ABitmap.RawImage, False); try X:= (AIcon.Width - ABitmap.Width); Y:= (AIcon.Height - ABitmap.Height); BitmapMerge(Target, Source, X, Y); finally Source.Free; end; finally ABitmap.Free; end; {$IF DEFINED(GTK2_FIX)} Result := FPixmapList.Add(ImageToPixBuf(Target)); AIcon.Free; {$ELSE} BitmapAssign(AIcon, Target); Result := FPixmapList.Add(AIcon); {$ENDIF} finally Target.Free; end; end; {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} procedure TPixMapManager.LoadMimeIconNames; const mime_globs = 'globs'; mime_icons = 'icons'; mime_generic_icons = 'generic-icons'; pixmaps_cache = 'pixmaps.cache'; cache_signature: DWord = $44435043; // 'DCPC' cache_version: DWord = 1; var I, J, K: Integer; mTime: TFileTime; LocalMime: String; iconsList: TStringList; nodeList: TFPObjectList; node: THTDataNode = nil; cache: TFileStreamEx = nil; EntriesCount, IconsCount: Cardinal; GlobalMime: String = '/usr/share/mime/'; sMimeType, sMimeIconName, sExtension: String; procedure LoadGlobs(const APath: String); var I: Integer; globs: TStringListEx = nil; icons: TStringListEx = nil; generic_icons: TStringListEx = nil; begin if mbFileAccess(APath + mime_globs, fmOpenRead) then try // Load mapping: MIME type -> file extension. globs:= TStringListEx.Create; globs.NameValueSeparator:= ':'; globs.LoadFromFile(APath + mime_globs); // Try to load mapping: MIME type -> MIME icon name. if mbFileExists(APath + mime_icons) then begin icons:= TStringListEx.Create; icons.NameValueSeparator:= ':'; icons.LoadFromFile(APath + mime_icons); if (icons.Count = 0) then FreeAndNil(icons); end; // Try to load mapping: MIME type -> generic MIME icon name. if mbFileExists(APath + mime_generic_icons) then begin generic_icons:= TStringListEx.Create; generic_icons.NameValueSeparator:= ':'; generic_icons.LoadFromFile(APath + mime_generic_icons); if (generic_icons.Count = 0) then FreeAndNil(generic_icons); end; // Create mapping: file extension -> list of MIME icon names. for I:= 0 to globs.Count - 1 do if (globs.Strings[I] <> '') and // bypass empty lines (globs.Strings[I][1] <> '#') then // and comments begin sMimeType := globs.Names[I]; sExtension:= ExtractFileExt(globs.ValueFromIndex[I]); // Support only extensions, not full file name masks. if (sExtension <> '') and (sExtension <> '.*') then begin Delete(sExtension, 1, 1); node := THTDataNode(FExtToMimeIconName.Find(sExtension)); if Assigned(node) then iconsList := TStringList(node.Data) else begin iconsList := TStringList.Create; FExtToMimeIconName.Add(sExtension, iconsList); Inc(EntriesCount); end; if Assigned(icons) then begin J := icons.IndexOfName(sMimeType); if J <> -1 then begin sMimeIconName := icons.ValueFromIndex[J]; // found icon if iconsList.IndexOf(sMimeIconName) < 0 then iconsList.Add(sMimeIconName); end; end; sMimeIconName:= StringReplace(sMimeType, '/', '-', []); if iconsList.IndexOf(sMimeIconName) < 0 then iconsList.Add(sMimeIconName); // Shared-mime-info spec says: // "If [generic-icon] is not specified then the mimetype is used to generate the // generic icon by using the top-level media type (e.g. "video" in "video/ogg") // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)." if Assigned(generic_icons) then begin J := generic_icons.IndexOfName(sMimeType); if J <> -1 then sMimeIconName := generic_icons.ValueFromIndex[J] // found generic icon else sMimeIconName := Copy2Symb(sMimeIconName, '-') + '-x-generic'; end else sMimeIconName := Copy2Symb(sMimeIconName, '-') + '-x-generic'; if iconsList.IndexOf(sMimeIconName) < 0 then iconsList.Add(sMimeIconName); end; end; finally globs.Free; icons.Free; generic_icons.Free; end; end; begin LocalMime:= IncludeTrailingBackslash(GetUserDataDir) + 'mime/'; mTime:= Max(mbFileAge(LocalMime + mime_globs), mbFileAge(GlobalMime + mime_globs)); // Try to load from cache. if (mbFileAge(gpCfgDir + pixmaps_cache) = mTime) and (mbFileAccess(gpCfgDir + pixmaps_cache, fmOpenRead)) and (mbFileSize(gpCfgDir + pixmaps_cache) > SizeOf(DWord) * 2) then try cache := TFileStreamEx.Create(gpCfgDir + pixmaps_cache, fmOpenRead or fmShareDenyWrite); try if (cache.ReadDWord = NtoBE(cache_signature)) and (cache.ReadDWord = cache_version) then begin EntriesCount := cache.ReadDWord; FExtToMimeIconName.HashTableSize := EntriesCount; // Each entry is a file extension with a list of icon names. for I := 0 to EntriesCount - 1 do begin sExtension := cache.ReadAnsiString; IconsCount := cache.ReadDWord; iconsList := TStringList.Create; FExtToMimeIconName.Add(sExtension, iconsList); iconsList.Capacity := IconsCount; for J := 0 to IconsCount - 1 do begin iconsList.Add(cache.ReadAnsiString); end; end; Exit; end; finally FreeAndNil(cache); end; except on E: Exception do DCDebug(Format('Error: Cannot load from pixmaps cache [%s] : %s',[gpCfgDir + pixmaps_cache, E.Message])); end; EntriesCount := 0; LoadGlobs(LocalMime); LoadGlobs(GlobalMime); // save to cache if EntriesCount > 0 then try cache := TFileStreamEx.Create(gpCfgDir + pixmaps_cache, fmCreate or fmShareDenyWrite); try cache.WriteDWord(NtoBE(cache_signature)); cache.WriteDWord(cache_version); cache.WriteDWord(EntriesCount); for I := 0 to FExtToMimeIconName.HashTable.Count - 1 do begin nodeList := TFPObjectList(FExtToMimeIconName.HashTable.Items[I]); if Assigned(nodeList) then for J := 0 to nodeList.Count - 1 do begin node := THtDataNode(nodeList.Items[J]); iconsList := TStringList(node.Data); cache.WriteAnsiString(node.Key); cache.WriteDWord(iconsList.Count); for K := 0 to iconsList.Count - 1 do cache.WriteAnsiString(iconsList.Strings[K]); end; end; finally FreeAndNil(cache); // Close file end; mbFileSetTime(gpCfgDir + pixmaps_cache, mTime, 0, 0); except on E: Exception do DCDebug(Format('Error: Cannot save pixmaps cache [%s] : %s',[gpCfgDir + pixmaps_cache, E.Message])); end; end; function TPixMapManager.GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt; var I: Integer; node: THTDataNode; iconList: TStringList; begin // This function must be called under FPixmapsLock. Result := -1; // Search for an icon for this file extension. node := THTDataNode(FExtToMimeIconName.Find(AFileExt)); if Assigned(node) then begin iconList := TStringList(node.Data); // Try to load one of the icons in the list. for I := 0 to iconList.Count - 1 do begin Result := CheckAddThemePixmapLocked(iconList.Strings[I], AIconSize); if Result <> -1 then break; end; end; end; function TPixMapManager.GetSystemFolderIcon: PtrInt; var AIconName: String; begin AIconName:= GioMimeGetIcon('inode/directory'); if Length(AIconName) = 0 then Result:= -1 else begin Result:= CheckAddThemePixmap(AIconName); end; if (Result < 0) and (AIconName <> 'folder') then begin Result:= CheckAddThemePixmap('folder'); end; end; function TPixMapManager.GetSystemArchiveIcon: PtrInt; begin Result:= CheckAddThemePixmap('package-x-generic'); end; function TPixMapManager.GetIconByDesktopFile(sFileName: String; iDefaultIcon: PtrInt): PtrInt; var I: PtrInt; iniDesktop: TIniFileEx = nil; sIconName: String; begin try iniDesktop:= TIniFileEx.Create(sFileName, fmOpenRead); try sIconName:= iniDesktop.ReadString('Desktop Entry', 'Icon', EmptyStr); finally FreeAndNil(iniDesktop); end; except Exit(iDefaultIcon); end; { Some icon names in .desktop files are specified with an extension, even though it is not allowed by the standard unless an absolute path to the icon is supplied. We delete this extension here. } if GetPathType(sIconName) = ptNone then sIconName := TIconTheme.CutTrailingExtension(sIconName); I:= GetIconByName(sIconName); if I < 0 then Result:= iDefaultIcon else Result:= I; end; {$ELSEIF DEFINED(DARWIN)} function getAppIconFilename( appName: String ) : String; var appBundle : NSBundle; infoDict : NSDictionary; iconTag : NSString; begin Result := ''; appBundle := NSBundle.bundleWithPath( StringToNSString(appName) ); if appBundle=nil then exit; infoDict := appBundle.infoDictionary; if infoDict=nil then exit; iconTag := NSString( infoDict.valueForKey( StringToNSString('CFBundleIconFile')) ); Result := NSStringToString( appBundle.pathForImageResource( iconTag ) ); end; function getBestNSImageWithSize( const srcImage:NSImage; const size:Integer ): NSImage; var bestRect: NSRect; bestImageRep: NSImageRep; bestImage: NSImage; begin Result := nil; if srcImage=nil then exit; bestRect.origin.x := 0; bestRect.origin.y := 0; bestRect.size.width := size; bestRect.size.height := size; bestImageRep:= srcImage.bestRepresentationForRect_context_hints( bestRect, nil, nil ); bestImage:= NSImage.Alloc.InitWithSize( bestImageRep.size ); bestImage.AddRepresentation( bestImageRep ); Result := bestImage; end; function getImageFileBestNSImage( const filename:NSString; const size:Integer ): NSImage; var srcImage: NSImage; begin Result:= nil; try srcImage:= NSImage.Alloc.initByReferencingFile( filename ); Result:= getBestNSImageWithSize( srcImage, size ); finally if Assigned(srcImage) then srcImage.release; end; end; function NSImageToTBitmap( const image:NSImage ): TBitmap; var tempData: NSData; tempStream: TBlobStream; tempBitmap: TTiffImage; bitmap: TBitmap; begin Result:= nil; if image=nil then exit; tempStream:= nil; tempBitmap:= nil; try tempData:= image.TIFFRepresentation; tempStream:= TBlobStream.Create( tempData.Bytes, tempData.Length ); tempBitmap:= TTiffImage.Create; tempBitmap.LoadFromStream( tempStream ); bitmap:= TBitmap.Create; bitmap.Assign( tempBitmap ); Result:= bitmap; finally FreeAndNil(tempBitmap); FreeAndNil(tempStream); end; end; function TPixMapManager.LoadImageFileBitmap( const filename:String; const size:Integer ): TBitmap; var image: NSImage; begin Result:= nil; image:= nil; try image:= getImageFileBestNSImage( StringToNSString(filename), size ); if Assigned(image) then Result:= NSImageToTBitmap( image ); finally if Assigned(image) then image.release; end; end; function TPixMapManager.GetApplicationBundleIcon(sFileName: String; iDefaultIcon: PtrInt): PtrInt; var I: PtrInt; sIconName: String; begin Result:= iDefaultIcon; sIconName:= getAppIconFilename(sFileName); I:= GetIconByName(sIconName); if I >= 0 then Result:= I; end; {$ENDIF} // Unix function TPixMapManager.CheckAddThemePixmapLocked(AIconName: String; AIconSize: Integer): PtrInt; var fileIndex: PtrInt; {$IFDEF GTK2_FIX} pbPicture: PGdkPixbuf = nil; sIconFileName: String; {$ELSE} bmpBitmap: Graphics.TBitmap; {$ENDIF} begin // This function must be called under FPixmapsLock. fileIndex := FThemePixmapsFileNames.Find(AIconName); if fileIndex < 0 then begin {$IF DEFINED(GTK2_FIX) AND DEFINED(UNIX) AND NOT DEFINED(DARWIN)} if gShowIcons > sim_standart then begin pbPicture:= gtk_icon_theme_load_icon(FIconTheme, Pgchar(AIconName), AIconSize, GTK_ICON_LOOKUP_USE_BUILTIN, nil); end; // If not found in system theme or using of system theme is disabled look in DC theme. if not Assigned(pbPicture) then begin sIconFileName := FDCIconTheme.FindIcon(AIconName, AIconSize); if sIconFileName <> EmptyStr then pbPicture := gdk_pixbuf_new_from_file_at_size( PChar(sIconFileName), AIconSize, AIconSize, nil); end; if Assigned(pbPicture) then begin Result := FPixmapList.Add(pbPicture); FThemePixmapsFileNames.Add(AIconName, Pointer(Result)); end else Result := -1; {$ELSE} bmpBitmap := LoadIconThemeBitmapLocked(AIconName, AIconSize); if Assigned(bmpBitmap) then begin Result := FPixmapList.Add(bmpBitmap); // add to list FThemePixmapsFileNames.Add(AIconName, Pointer(Result)); end else Result := -1; {$ENDIF} end else Result := PtrInt(FThemePixmapsFileNames.List[fileIndex]^.Data); end; function TPixMapManager.AddDefaultThemePixmap(const AIconName: String; AIconSize: Integer): PtrInt; var bmpBitmap: Pointer; {$IF DEFINED(GTK2_FIX)} sIconFileName: String; {$ENDIF} begin if AIconSize = 0 then AIconSize := gIconsSize; {$IF DEFINED(GTK2_FIX)} sIconFileName := FDCIconTheme.FindIcon(AIconName, AIconSize); if Length(sIconFileName) = 0 then Exit(-1); bmpBitmap := gdk_pixbuf_new_from_file_at_size(PChar(sIconFileName), AIconSize, AIconSize, nil); {$ELSE} bmpBitmap := LoadThemeIcon(FDCIconTheme, AIconName, AIconSize); {$ENDIF} if (bmpBitmap = nil) then Result := -1 else begin Result := FPixmapList.Add(bmpBitmap); // add to list FThemePixmapsFileNames.Add(AIconName, Pointer(Result)); end; end; function TPixMapManager.LoadThemeIcon(AIconTheme: TIconTheme; const AIconName: String; AIconSize: Integer): Graphics.TBitmap; var FileName: String; begin FileName:= AIconTheme.FindIcon(AIconName, AIconSize); if FileName = EmptyStr then Exit(nil); if TScalableVectorGraphics.IsFileExtensionSupported(ExtractFileExt(FileName)) then Result := TScalableVectorGraphics.CreateBitmap(FileName, AIconSize, AIconSize) else begin Result := CheckLoadPixmapFromFile(FileName); if Assigned(Result) then begin Result:= StretchBitmap(Result, AIconSize, clNone, True); end; end; end; function TPixMapManager.LoadIconThemeBitmapLocked(AIconName: String; AIconSize: Integer): Graphics.TBitmap; {$IFDEF GTK2_FIX} var pbPicture: PGdkPixbuf = nil; {$ENDIF} begin // This function must be called under FPixmapsLock. {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} Result := nil; // Try to load icon from system theme if gShowIcons > sim_standart then begin {$IFDEF GTK2_FIX} pbPicture:= gtk_icon_theme_load_icon(FIconTheme, Pgchar(PChar(AIconName)), AIconSize, GTK_ICON_LOOKUP_USE_BUILTIN, nil); if pbPicture <> nil then Result := PixBufToBitmap(pbPicture); {$ELSE} Result:= LoadThemeIcon(FIconTheme, AIconName, AIconSize); {$ENDIF} end; if not Assigned(Result) then {$ENDIF} Result:= LoadThemeIcon(FDCIconTheme, AIconName, AIconSize); end; function TPixMapManager.GetPluginIcon(const AIconName: String; ADefaultIcon: PtrInt): PtrInt; {$IF DEFINED(MSWINDOWS)} var phIcon: HICON; fileIndex: PtrInt; AIconSize: Integer; phIconLarge : HICON = 0; phIconSmall : HICON = 0; begin FPixmapsLock.Acquire; try // Determine if this file is already loaded. fileIndex := FPixmapsFileNames.Find(AIconName); if fileIndex >= 0 then Result:= PtrInt(FPixmapsFileNames.List[fileIndex]^.Data) else begin if ExtractIconExW(PWChar(CeUtf8ToUtf16(AIconName)), 0, phIconLarge, phIconSmall, 1) = 0 then Result:= ADefaultIcon else begin if not ImageList_GetIconSize(FSysImgList, @AIconSize, @AIconSize) then AIconSize:= gIconsSize; // Get system metrics if AIconSize <= GetSystemMetrics(SM_CXSMICON) then phIcon:= phIconSmall // Use small icon else begin phIcon:= phIconLarge // Use large icon end; if phIcon = 0 then Result:= ADefaultIcon else begin Result:= ImageList_AddIcon(FSysImgList, phIcon) + SystemIconIndexStart; {$IF DEFINED(LCLQT5)} Result:= CheckAddSystemIcon(Result); {$ENDIF} end; if (phIconLarge <> 0) then DestroyIcon(phIconLarge); if (phIconSmall <> 0) then DestroyIcon(phIconSmall); end; FPixmapsFileNames.Add(AIconName, Pointer(Result)); end; finally FPixmapsLock.Release; end; end; {$ELSE} var AIcon: TIcon; ABitmap: TBitmap; AFileName: String; AResult: Pointer absolute Result; begin AFileName:= ChangeFileExt(AIconName, '.ico'); if not mbFileExists(AFileName) then Exit(ADefaultIcon); FPixmapsLock.Acquire; try Result:= FPixmapsFileNames.Find(AFileName); if Result >= 0 then AResult:= FPixmapsFileNames.List[Result]^.Data else begin {$IF DEFINED(GTK2_FIX)} AResult := gdk_pixbuf_new_from_file_at_size(PChar(AFileName), gIconsSize, gIconsSize, nil); if (AResult = nil) then Exit(ADefaultIcon); Result := FPixmapList.Add(AResult); FPixmapsFileNames.Add(AFileName, AResult); {$ELSE} AIcon:= TIcon.Create; try AIcon.LoadFromFile(AFileName); AIcon.Current:= AIcon.GetBestIndexForSize(TSize.Create(gIconsSize, gIconsSize)); ABitmap:= TBitmap.Create; try BitmapAssign(ABitmap, AIcon); Result := FPixmapList.Add(ABitmap); FPixmapsFileNames.Add(AFileName, AResult); except FreeAndNil(ABitmap); end; except Result:= ADefaultIcon; end; AIcon.Free; {$ENDIF} end; finally FPixmapsLock.Release; end; end; {$ENDIF} {$IFDEF DARWIN} function TPixMapManager.GetSystemFolderIcon: PtrInt; var FileType: String; begin FileType:= NSFileTypeForHFSTypeCode(kGenericFolderIcon).UTF8String; Result:= GetMimeIcon(FileType, gIconsSize); end; function TPixMapManager.GetMimeIcon(AFileExt: String; AIconSize: Integer): PtrInt; var I: Integer; nData: NSData; nImage: NSImage; bestRect: NSRect; nRepresentations: NSArray; nImageRep: NSImageRep; WorkStream: TBlobStream; tfBitmap: TTiffImage; bmBitmap: TBitmap; begin Result:= -1; if not FUseSystemTheme then Exit; if AIconSize = 24 then AIconSize:= 32; nImage:= NSWorkspace.sharedWorkspace.iconForFileType(NSSTR(PChar(AFileExt))); // Try to find best representation for requested icon size bestRect.origin.x:= 0; bestRect.origin.y:= 0; bestRect.size.width:= AIconSize; bestRect.size.height:= AIconSize; nImageRep:= nImage.bestRepresentationForRect_context_hints(bestRect, nil, nil); if Assigned(nImageRep) then begin nImage:= NSImage.Alloc.InitWithSize(nImageRep.Size); nImage.AddRepresentation(nImageRep); end // Try old method else begin nRepresentations:= nImage.Representations; for I:= nRepresentations.Count - 1 downto 0 do begin nImageRep:= NSImageRep(nRepresentations.objectAtIndex(I)); if (AIconSize <> nImageRep.Size.Width) then nImage.removeRepresentation(nImageRep); end; if nImage.Representations.Count = 0 then Exit; end; nData:= nImage.TIFFRepresentation; tfBitmap:= TTiffImage.Create; WorkStream:= TBlobStream.Create(nData.Bytes, nData.Length); try tfBitmap.LoadFromStream(WorkStream); bmBitmap:= TBitmap.Create; try bmBitmap.Assign(tfBitmap); Result:= FPixmapList.Add(bmBitmap); except bmBitmap.Free; end; finally tfBitmap.Free; nImage.Release; WorkStream.Free; end; end; {$ENDIF} {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} function TPixMapManager.CheckAddSystemIcon(ASystemIndex: PtrInt): PtrInt; var AIcon: HICON; ABitmap: Graphics.TBitmap; begin if not FSystemIndexList.TryGetData(ASystemIndex, Result) then begin Result:= -1; AIcon:= ImageList_GetIcon(FSysImgList, ASystemIndex - SystemIconIndexStart, ILD_NORMAL); if AIcon <> 0 then try ABitmap := BitmapCreateFromHICON(AIcon); if (ABitmap.Width <> gIconsSize) or (ABitmap.Height <> gIconsSize) then ABitmap:= StretchBitmap(ABitmap, gIconsSize, clWhite, True); Result := FPixmapList.Add(ABitmap); FSystemIndexList.Add(ASystemIndex, Result); finally DestroyIcon(AIcon); end end; end; {$ENDIF} {$IFDEF WINDOWS} function TPixMapManager.GetShellFolderIcon(AFile: TFile): PtrInt; const uFlags: UINT = SHGFI_SYSICONINDEX or SHGFI_PIDL; var FileInfo: TSHFileInfoW; begin if (SHGetFileInfoW(PWideChar(TFileShellProperty(AFile.LinkProperty).Item), 0, {%H-}FileInfo, SizeOf(FileInfo), uFlags) <> 0) then begin Result := FileInfo.iIcon + SystemIconIndexStart; {$IF DEFINED(LCLQT5)} FPixmapsLock.Acquire; try Result := CheckAddSystemIcon(Result); finally FPixmapsLock.Release; end; {$ENDIF} Exit; end; // Could not retrieve the icon if AFile.IsDirectory then Result := FiDirIconID else begin Result := FiDefaultIconID; end; end; function TPixMapManager.GetIconResourceIndex(const IconPath: String; out IconFile: String; out IconIndex: PtrInt): Boolean; var iPos, iIndex: Integer; begin iPos := Pos(',', IconPath); if iPos <> 0 then begin if TryStrToInt(Copy(IconPath, iPos + 1, Length(IconPath) - iPos), iIndex) and (iIndex >= 0) then begin IconIndex := iIndex; IconFile := Copy(IconPath, 1, iPos - 1); Result := FileIsExeLib(IconFile); end else Result := False; end else begin IconIndex := 0; IconFile := IconPath; Result := FileIsExeLib(IconFile); end; end; function TPixMapManager.GetSystemFileIcon(const FileName: String; dwFileAttributes: DWORD): PtrInt; var FileInfo: TSHFileInfo; begin if (SHGetFileInfo(PAnsiChar(FileName), // Ansi version is enough. FILE_ATTRIBUTE_NORMAL or dwFileAttributes, FileInfo, SizeOf(FileInfo), SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES) = 0) then Result := -1 else begin Result := FileInfo.iIcon + SystemIconIndexStart; {$IF DEFINED(LCLQT5)} Result := CheckAddSystemIcon(Result); {$ENDIF} end; end; function TPixMapManager.GetSystemFolderIcon: PtrInt; var FileInfo: TSHFileInfo; begin if (SHGetFileInfo('nil', FILE_ATTRIBUTE_DIRECTORY, FileInfo, SizeOf(FileInfo), SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES) = 0) then Result := -1 else begin Result := FileInfo.iIcon + SystemIconIndexStart; {$IF DEFINED(LCLQT5)} Result := CheckAddSystemIcon(Result); {$ENDIF} end; end; function TPixMapManager.GetSystemArchiveIcon: PtrInt; var psii: TSHStockIconInfo; begin if not SHGetStockIconInfo(SIID_ZIPFILE, SHGFI_SYSICONINDEX, psii) then Result:= -1 else begin Result:= psii.iSysImageIndex + SystemIconIndexStart; {$IF DEFINED(LCLQT5)} Result := CheckAddSystemIcon(Result); {$ENDIF} end; end; function TPixMapManager.GetSystemShortcutIcon: PtrInt; begin Result:= GetSystemFileIcon('a.url'); end; function TPixMapManager.GetSystemExecutableIcon: PtrInt; begin Result:= GetSystemFileIcon('a.exe'); end; {$ENDIF} constructor TPixMapManager.Create; {$IF DEFINED(DARWIN)} var systemVersion: SInt32; {$ELSEIF DEFINED(MSWINDOWS)} var iIconSize : Integer; {$ENDIF} begin FExtList := TStringHashListUtf8.Create(True); FPixmapsFileNames := TStringHashListUtf8.Create(True); FPixmapList := TFPList.Create; {$IF DEFINED(DARWIN)} FUseSystemTheme:= NSAppKitVersionNumber >= 1038; {$ELSEIF DEFINED(UNIX) AND NOT DEFINED(HAIKU)} FExtToMimeIconName := TFPDataHashTable.Create; FHomeFolder := IncludeTrailingBackslash(GetHomeDir); {$ENDIF} FThemePixmapsFileNames := TStringHashListUtf8.Create(True); CreateIconTheme; {$IFDEF MSWINDOWS} for iIconSize:= Low(ICON_SIZES) to High(ICON_SIZES) do ICON_SIZES[iIconSize]:= AdjustIconSize(ICON_SIZES[iIconSize], 96); if gIconsSize <= ICON_SIZES[0] then iIconSize := SHIL_SMALL else if gIconsSize <= ICON_SIZES[2] then iIconSize := SHIL_LARGE else begin iIconSize := SHIL_EXTRALARGE; end; FSysImgList := SHGetSystemImageList(iIconSize); {$ENDIF} {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} FSystemIndexList:= TPtrIntMap.Create; FSystemIndexList.Sorted:= True; {$ENDIF} FPixmapsLock := syncobjs.TCriticalSection.Create; end; destructor TPixMapManager.Destroy; var I : Integer; K: TDriveType; {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} J : Integer; nodeList: TFPObjectList; {$ENDIF} begin if Assigned(FPixmapList) then begin for I := 0 to FPixmapList.Count - 1 do if Assigned(FPixmapList.Items[I]) then {$IFDEF GTK2_FIX} g_object_unref(PGdkPixbuf(FPixmapList.Items[I])); {$ELSE} Graphics.TBitmap(FPixmapList.Items[I]).Free; {$ENDIF} FreeAndNil(FPixmapList); end; if Assigned(FExtList) then FreeAndNil(FExtList); if Assigned(FPixmapsFileNames) then FreeAndNil(FPixmapsFileNames); for I := Low(FDriveIconList) to High(FDriveIconList) do begin with FDriveIconList[I] do begin for K:= Low(Bitmap) to High(Bitmap) do FreeAndNil(Bitmap[K]); end; end; {$IF DEFINED(MSWINDOWS)} ImageList_Destroy(FSysImgList); {$ELSEIF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} for I := 0 to FExtToMimeIconName.HashTable.Count - 1 do begin nodeList := TFPObjectList(FExtToMimeIconName.HashTable.Items[I]); if Assigned(nodeList) then for J := 0 to nodeList.Count - 1 do TStringList(THtDataNode(nodeList.Items[J]).Data).Free; end; FreeAndNil(FExtToMimeIconName); {$ENDIF} {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} FSystemIndexList.Free; {$ENDIF} DestroyIconTheme; FreeAndNil(FThemePixmapsFileNames); FreeAndNil(FPixmapsLock); inherited Destroy; end; procedure TPixMapManager.Load(const sFileName: String); var slPixmapList: TStringListEx; s:String; sExt, sPixMap:String; iekv:integer; iPixMap:PtrInt; I : Integer; iPixmapSize: Integer; begin // This function doesn't need to be synchronized // as long as it is called before creating the main form // (via LoadPixMapManager in doublecmd.lpr). // Load icon themes. {$IF DEFINED(XDG)} if gShowIcons > sim_standart then begin LoadMimeIconNames; // For use with GetMimeIcon {$IFNDEF GTK2_FIX} FIconTheme.Load; // Load system icon theme. {$ENDIF} end; {$ENDIF} FDCIconTheme.Load; // Load DC theme. // load all drive icons FDriveIconList[0].Size := 16; FDriveIconList[1].Size := 24; FDriveIconList[2].Size := 32; for I:= Low(FDriveIconList) to High(FDriveIconList) do with FDriveIconList[I] do begin iPixmapSize := FDriveIconList[I].Size; Bitmap[dtFloppy] := LoadIconThemeBitmapLocked('media-floppy', iPixmapSize); Bitmap[dtHardDisk] := LoadIconThemeBitmapLocked('drive-harddisk', iPixmapSize); Bitmap[dtFlash] := LoadIconThemeBitmapLocked('media-flash', iPixmapSize); Bitmap[dtOptical] := LoadIconThemeBitmapLocked('media-optical', iPixmapSize); Bitmap[dtNetwork] := LoadIconThemeBitmapLocked('network-wired', iPixmapSize); Bitmap[dtVirtual] := LoadIconThemeBitmapLocked('drive-virtual', iPixmapSize); Bitmap[dtRemovable] := LoadIconThemeBitmapLocked('drive-removable-media', iPixmapSize); Bitmap[dtRemovableUsb] := LoadIconThemeBitmapLocked('drive-removable-media-usb', iPixmapSize); end; // load emblems if gIconsSize = 24 then I:= 16 else I:= gIconsSize div 2; FiEmblemLinkID:= CheckAddThemePixmap('emblem-symbolic-link', I); FiEmblemUnreadableID:= CheckAddThemePixmap('emblem-unreadable', I); // add some standard icons FiDefaultIconID:=CheckAddThemePixmap('unknown'); {$IF DEFINED(MSWINDOWS)} FiSysDirIconID := GetSystemFolderIcon; if (Win32MajorVersion >= 10) then begin FiEmblemPinned:= CheckAddThemePixmap('emblem-cloud-pinned', I); FiEmblemOnline:= CheckAddThemePixmap('emblem-cloud-online', I); FiEmblemOffline:= CheckAddThemePixmap('emblem-cloud-offline', I); GetKnownFolderPath(FOLDERID_SkyDrive, FOneDrivePath); end; FiShortcutIconID := -1; if gShowIcons > sim_standart then FiShortcutIconID := GetSystemShortcutIcon; if FiShortcutIconID = -1 then FiShortcutIconID := CheckAddThemePixmap('text-html'); {$ENDIF} {$IF NOT DEFINED(HAIKU)} FiDirIconID := -1; if (gShowIcons > sim_standart) and (not (cimFolder in gCustomIcons)) then FiDirIconID := GetSystemFolderIcon; if FiDirIconID = -1 then {$ENDIF} FiDirIconID:= AddDefaultThemePixmap('folder'); FiDirLinkBrokenIconID:= AddSpecial(FiDirIconID, FiEmblemUnreadableID); FiLinkBrokenIconID:= AddSpecial(FiDefaultIconID, FiEmblemUnreadableID); FiUpDirIconID:= CheckAddThemePixmap('go-up'); {$IF DEFINED(MSWINDOWS) OR DEFINED(XDG)} FiArcIconID := -1; if (gShowIcons > sim_standart) and (not (cimArchive in gCustomIcons)) then FiArcIconID := GetSystemArchiveIcon; if FiArcIconID = -1 then {$ENDIF} FiArcIconID := AddDefaultThemePixmap('package-x-generic'); {$IFDEF MSWINDOWS} FiExeIconID := -1; if gShowIcons > sim_standart then FiExeIconID := GetSystemExecutableIcon; if FiExeIconID = -1 then {$ENDIF} FiExeIconID:= CheckAddThemePixmap('application-x-executable'); FiSortAscID := CheckAddThemePixmap('view-sort-ascending'); FiSortDescID := CheckAddThemePixmap('view-sort-descending'); FiHashIconID := CheckAddThemePixmap('text-x-hash'); { Load icons from "extassoc.xml" } for I := 0 to gExts.Count - 1 do begin iPixMap := CheckAddPixmap(gExts.Items[I].Icon, gIconsSize); if iPixMap >= 0 then begin // set pixmap index for all extensions for iekv := 0 to gExts.Items[I].Extensions.Count - 1 do begin sExt := LowerCase(gExts.Items[I].Extensions[iekv]); if FExtList.Find(sExt) < 0 then FExtList.Add(sExt, TObject(iPixMap)); end; end else iPixMap:= FiDefaultIconID; gExts.Items[I].IconIndex:= iPixMap; end; {/ Load icons from "extassoc.xml" } // Load icons from pixmaps.txt only if "Only standart icons" enabled if (gShowIcons = sim_standart) and mbFileExists(sFileName) then try slPixmapList:= TStringListEx.Create; try slPixmapList.LoadFromFile(sFileName); for I:= 0 to slPixmapList.Count - 1 do begin s:= Trim(slPixmapList.Strings[I]); iekv := Pos('=',s); if iekv = 0 then Continue; sPixMap := Copy(s, iekv+1, length(s)-iekv); // Since DC 0.4.6 filename without path is treated as a MIME type // and it shouldn't have an extension. Cut any extension here. // Only '.png' were used in previous versions of pixmaps.txt. if (GetPathType(sPixMap) = ptNone) and StrEnds(sPixMap, '.png') then Delete(sPixMap, Length(sPixMap) - 3, 4); iPixMap := CheckAddPixmap(sPixMap); if iPixMap >= 0 then begin sExt := Copy(s, 1, iekv-1); if FExtList.Find(sExt) < 0 then FExtList.Add(sExt, TObject(iPixMap)); end; end; except on E: Exception do with Application do MessageBox(PAnsiChar(E.Message), PAnsiChar(Title), MB_OK or MB_ICONERROR); end; finally slPixmapList.Free; end; for sExt in HashFileExt do begin FExtList.Add(sExt, TObject(FiHashIconID)); end; (* Set archive icons *) for I:=0 to gWCXPlugins.Count - 1 do begin if gWCXPlugins.Enabled[I] and ((gWCXPlugins.Flags[I] and PK_CAPS_HIDE) <> PK_CAPS_HIDE) then begin sExt := gWCXPlugins.Ext[I]; if (Length(sExt) > 0) and (FExtList.Find(sExt) < 0) then FExtList.Add(sExt, TObject(FiArcIconID)); end; end; //for for I:= 0 to gMultiArcList.Count - 1 do begin if gMultiArcList.Items[I].FEnabled then begin sExt := gMultiArcList.Items[I].FExtension; if (Length(sExt) > 0) and (FExtList.Find(sExt) < 0) then FExtList.Add(sExt, TObject(FiArcIconID)); end; end; (* /Set archive icons *) {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} LoadApplicationThemeIcon; {$ENDIF} end; function TPixMapManager.GetBitmap(iIndex: PtrInt): Graphics.TBitmap; var PPixmap: Pointer; PixmapFromList: Boolean = False; {$IFDEF LCLWIN32} AIcon: HICON; {$ENDIF} begin FPixmapsLock.Acquire; try if (iIndex >= 0) and (iIndex < FPixmapList.Count) then begin PPixmap := FPixmapList[iIndex]; PixmapFromList := True; end; finally FPixmapsLock.Release; end; if PixmapFromList then begin {$IFDEF GTK2_FIX} Result:= PixBufToBitmap(PGdkPixbuf(PPixmap)); {$ELSE} // Make a new copy. Result := Graphics.TBitmap.Create; Result.Assign(Graphics.TBitmap(PPixmap)); {$ENDIF} end else {$IFDEF LCLWIN32} if iIndex >= SystemIconIndexStart then begin Result:= nil; AIcon:= ImageList_GetIcon(FSysImgList, iIndex - SystemIconIndexStart, ILD_NORMAL); if AIcon <> 0 then try Result := BitmapCreateFromHICON(AIcon); finally DestroyIcon(AIcon); end end else {$ENDIF} Result:= nil; end; function TPixMapManager.DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean; begin Result := DrawBitmap(iIndex, Canvas, X, Y, gIconsSize, gIconsSize); // No bitmap stretching. end; function TPixMapManager.DrawBitmapAlpha(iIndex: PtrInt; Canvas: TCanvas; X, Y: Integer): Boolean; var ARect: TRect; ABitmap: Graphics.TBitmap; begin ABitmap:= GetBitmap(iIndex); Result := Assigned(ABitmap); if Result then begin BitmapAlpha(ABitmap, 0.5); ARect := Classes.Bounds(X, Y, gIconsSize, gIconsSize); Canvas.StretchDraw(aRect, ABitmap); ABitmap.Free; end; end; function TPixMapManager.DrawBitmap(iIndex: PtrInt; Canvas: TCanvas; X, Y, Width, Height: Integer): Boolean; procedure TrySetSize(aWidth, aHeight: Integer); begin if Width = 0 then Width := aWidth; if Height = 0 then Height := aHeight; end; var PPixmap: Pointer; PixmapFromList: Boolean = False; {$IFDEF MSWINDOWS} hicn: HICON; cx, cy: Integer; {$ENDIF} {$IFDEF GTK2_FIX} pbPicture : PGdkPixbuf; iPixbufWidth : Integer; iPixbufHeight : Integer; {$ELSE} Bitmap: Graphics.TBitmap; aRect: TRect; {$ENDIF} begin Result := True; FPixmapsLock.Acquire; try if (iIndex >= 0) and (iIndex < FPixmapList.Count) then begin PPixmap := FPixmapList[iIndex]; PixmapFromList := True; end; finally FPixmapsLock.Release; end; if PixmapFromList then begin {$IFDEF GTK2_FIX} pbPicture := PGdkPixbuf(PPixmap); iPixbufWidth := gdk_pixbuf_get_width(pbPicture); iPixbufHeight := gdk_pixbuf_get_height(pbPicture); TrySetSize(iPixbufWidth, iPixbufHeight); DrawPixbufAtCanvas(Canvas, pbPicture, 0, 0, X, Y, Width, Height); {$ELSE} Bitmap := Graphics.TBitmap(PPixmap); TrySetSize(Bitmap.Width, Bitmap.Height); aRect := Classes.Bounds(X, Y, Width, Height); Canvas.StretchDraw(aRect, Bitmap); {$ENDIF} end else {$IFDEF MSWINDOWS} if iIndex >= SystemIconIndexStart then try if ImageList_GetIconSize(FSysImgList, @cx, @cy) then TrySetSize(cx, cy) else TrySetSize(gIconsSize, gIconsSize); {$IF DEFINED(LCLWIN32)} if (cx = Width) and (cy = Height) then ImageList_Draw(FSysImgList, iIndex - SystemIconIndexStart, Canvas.Handle, X, Y, ILD_TRANSPARENT) else begin hicn:= ImageList_GetIcon(FSysImgList, iIndex - SystemIconIndexStart, ILD_NORMAL); try if IsGdiPlusLoaded then Result:= GdiPlusStretchDraw(hicn, Canvas.Handle, X, Y, Width, Height) else Result:= DrawIconEx(Canvas.Handle, X, Y, hicn, Width, Height, 0, 0, DI_NORMAL); finally DestroyIcon(hicn); end; end; {$ELSEIF DEFINED(LCLQT5)} hicn:= ImageList_GetIcon(FSysImgList, iIndex - SystemIconIndexStart, ILD_NORMAL); try Bitmap:= BitmapCreateFromHICON(hicn); aRect := Classes.Bounds(X, Y, Width, Height); Canvas.StretchDraw(aRect, Bitmap); finally FreeAndNil(Bitmap); DestroyIcon(hicn); end {$ENDIF} except Result:= False; end; {$ELSE} Result:= False; {$ENDIF} end; function TPixMapManager.DrawBitmapOverlay(AFile: TDisplayFile; DirectAccess: Boolean; Canvas: TCanvas; X, Y: Integer): Boolean; var I: Integer; begin if AFile.FSFile.IsLink then begin I:= gIconsSize div 2; Result:= DrawBitmap(FiEmblemLinkID, Canvas, X, Y + I, I, I); if Assigned(AFile.FSFile.LinkProperty) then begin if not AFile.FSFile.LinkProperty.IsValid then Result:= DrawBitmap(FiEmblemUnreadableID, Canvas, X + I, Y + I, I, I); end; end {$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)} else if DirectAccess then begin if AFile.IconOverlayID >= SystemIconIndexStart then Result:= DrawBitmap(AFile.IconOverlayID {$IFDEF RabbitVCS} - SystemIconIndexStart {$ENDIF}, Canvas, X, Y) {$IF DEFINED(MSWINDOWS)} // Special case for OneDrive else if AFile.IconOverlayID > 0 then begin I:= gIconsSize div 2; Result:= DrawBitmap(AFile.IconOverlayID, Canvas, X, Y + I, I, I); end; {$ENDIF} end; {$ENDIF} ; end; function TPixMapManager.GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt; begin case SortingDirection of sdDescending: begin Result := FiSortDescID; end; sdAscending: begin Result := FiSortAscID; end; else Result := -1; end; end; function TPixMapManager.GetIconByFile(AFile: TFile; DirectAccess: Boolean; LoadIcon: Boolean; IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt; var Ext: String; {$IFDEF MSWINDOWS} sFileName: String; FileInfo: TSHFileInfoW; dwFileAttributes: DWORD; uFlags: UINT; const FILE_ATTRIBUTE_SHELL = FILE_ATTRIBUTE_DEVICE or FILE_ATTRIBUTE_VIRTUAL; {$ENDIF} begin Result := -1; if not Assigned(AFile) then Exit; with AFile do begin if Name = '..' then begin Result := FiUpDirIconID; Exit; end; if IsLinkToDirectory and GetIconWithLink then begin if Assigned(LinkProperty) and not LinkProperty.IsValid then Exit(FiDirLinkBrokenIconID); end; if (DirectAccess = False) then begin if (AFile.Attributes = (FILE_ATTRIBUTE_NORMAL or FILE_ATTRIBUTE_VIRTUAL)) and Assigned(AFile.LinkProperty) then begin if not LoadIcon then Result := -1 else begin Result := GetPluginIcon(AFile.LinkProperty.LinkTo, FiDirIconID); end; Exit; end else if (AFile.Attributes = (FILE_ATTRIBUTE_OFFLINE or FILE_ATTRIBUTE_VIRTUAL)) and Assigned(AFile.LinkProperty) then begin if not LoadIcon then Result := -1 else begin Result := CheckAddPixmap(AFile.LinkProperty.LinkTo); if Result < 0 then Result := FiDirIconID; end; Exit; end {$IF DEFINED(MSWINDOWS)} else if (AFile.Attributes and FILE_ATTRIBUTE_SHELL = FILE_ATTRIBUTE_SHELL) and Assigned(AFile.LinkProperty) then begin if not LoadIcon then Result := -1 else begin Result:= GetShellFolderIcon(AFile); end; Exit; end; {$ENDIF} end; if IsDirectory or IsLinkToDirectory then begin {$IF DEFINED(MSWINDOWS)} if (IconsMode = sim_standart) or // Directory has special icon only if it has "read only" or "system" attributes // and contains desktop.ini file (not (DirectAccess and (IsSysFile or FileIsReadOnly(Attributes)) and mbFileExists(FullPath + '\desktop.ini'))) or (ScreenInfo.ColorDepth < 16) then {$ELSEIF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} if (IconsMode = sim_all_and_exe) and (DirectAccess) then begin if not LoadIcon then Exit(-1); if mbFileAccess(Path + Name + '/.directory', fmOpenRead) then begin Result := GetIconByDesktopFile(Path + Name + '/.directory', FiDirIconID); Exit; end else if (FHomeFolder = Path) then begin Result := CheckAddThemePixmap(GioFileGetIcon(FullPath)); Exit; end else Exit(FiDirIconID); end else {$ELSEIF DEFINED(DARWIN)} if (IconsMode = sim_all_and_exe) and (DirectAccess and (ExtractFileExt(FullPath) = '.app')) then begin if LoadIcon then Result := GetApplicationBundleIcon(FullPath, FiDirIconID) else Result := -1; Exit; end else {$ENDIF} begin Exit(FiDirIconID); end; end else // not directory begin if IsLink and GetIconWithLink then begin if Assigned(LinkProperty) and not LinkProperty.IsValid then Exit(FiLinkBrokenIconID); end; if (Extension = '') then begin {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} if IconsMode = sim_all_and_exe then begin if DirectAccess and (Attributes and S_IXUGO <> 0) then begin if not LoadIcon then Result := -1 else begin Ext := GioFileGetIcon(FullPath); if Ext = 'application-x-sharedlib' then Result := FiExeIconID else Result := CheckAddThemePixmap(Ext); end; Exit; end; end; {$ENDIF} Exit(FiDefaultIconID); end; Ext := UTF8LowerCase(Extension); {$IF DEFINED(MSWINDOWS)} if (IconsMode > sim_standart) and (Win32MajorVersion >= 10) then begin if (AFile.Attributes and FILE_ATTRIBUTE_ENCRYPTED <> 0) then begin if (IconsMode = sim_all) or ((Ext <> 'exe') and (Ext <> 'ico') and (Ext <> 'ani') and (Ext <> 'cur')) then begin if (IconsMode = sim_all) and ((Ext = 'ico') or (Ext = 'ani') or (Ext = 'cur')) then Result:= GetSystemFileIcon('aaa', AFile.Attributes) else begin Result:= GetSystemFileIcon(AFile.Name, AFile.Attributes); end; if Result > -1 then Exit; end; end; end; if IconsMode <> sim_all_and_exe then begin if Ext = 'exe' then Exit(FiExeIconID) else if Ext = 'lnk' then Exit(FiDefaultIconID) else if Ext = 'url' then Exit(FiShortcutIconID) end; {$ELSEIF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} if IconsMode = sim_all_and_exe then begin if DirectAccess and ((Ext = 'desktop') or (Ext = 'directory')) then begin if LoadIcon then Result := GetIconByDesktopFile(Path + Name, FiDefaultIconID) else Result := -1; Exit; end; end; {$ENDIF} FPixmapsLock.Acquire; try Result := FExtList.Find(Ext); if Result >= 0 then Exit(PtrInt(PtrUInt(FExtList.List[Result]^.Data))); {$IF DEFINED(MSWINDOWS)} if IconsMode = sim_all then begin if (Ext = 'ico') or (Ext = 'ani') or (Ext = 'cur') then Exit(FiDefaultIconID) end else {$ENDIF} if IconsMode <= sim_standart then Exit(FiDefaultIconID); {$IF DEFINED(UNIX) AND NOT DEFINED(HAIKU)} if LoadIcon = False then Exit(-1); Result := GetMimeIcon(Ext, gIconsSize); if Result < 0 then Result := FiDefaultIconID; // Default icon should also be associated with the extension // because it will be faster to find next time. FExtList.Add(Ext, Pointer(Result)); {$ENDIF} finally FPixmapsLock.Release; end; end; {$IF DEFINED(MSWINDOWS)} if DirectAccess then begin if LoadIcon = False then Exit(-1); dwFileAttributes := 0; uFlags := SHGFI_SYSICONINDEX; sFileName := FullPath; end else begin // This is fast, so do it even if LoadIcon is false. dwFileAttributes := FILE_ATTRIBUTE_NORMAL; uFlags := SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES; sFileName := Name; end; if (SHGetFileInfoW(PWideChar(CeUtf8ToUtf16(sFileName)), dwFileAttributes, FileInfo, SizeOf(FileInfo), uFlags) = 0) then begin // Could not retrieve icon. if IsDirectory then Result := FiDirIconID else Result := FiDefaultIconID; end else begin Result := FileInfo.iIcon + SystemIconIndexStart; {$IF DEFINED(LCLQT5)} FPixmapsLock.Acquire; try Result := CheckAddSystemIcon(Result); finally FPixmapsLock.Release; end; {$ENDIF} if IsDirectory then begin // In the fact the folder does not have a special icon if (cimFolder in gCustomIcons) and (Result = FiSysDirIconID) then Result := FiDirIconID; end else if (Ext <> 'exe') and (Ext <> 'ico') and (Ext <> 'ani') and (Ext <> 'cur') and (Ext <> 'lnk') and (Ext <> 'url') then begin FPixmapsLock.Acquire; try FExtList.Add(Ext, Pointer(Result)); finally FPixmapsLock.Release; end; end; end; {$ENDIF} end; end; {$IF DEFINED(MSWINDOWS)} procedure TPixMapManager.ClearSystemCache; var I: Integer; IData: IntPtr; AData: Pointer absolute IData; begin FPixmapsLock.Acquire; try for I:= FExtList.Count - 1 downto 0 do begin AData:= FExtList.List[I]^.Data; if (IData >= SystemIconIndexStart) and (IData <> FiArcIconID) then begin FExtList.Remove(I); end; end; finally FPixmapsLock.Release; end; end; function TPixMapManager.GetIconOverlayByFile(AFile: TFile; DirectAccess: Boolean): PtrInt; begin if not DirectAccess then Exit(-1); Result:= SHGetOverlayIconIndex(AFile.Path, AFile.Name); if Result >= 0 then begin Result += SystemIconIndexStart; end // Special case for OneDrive else if (Win32MajorVersion >= 10) and IsInPath(FOneDrivePath, AFile.Path, True, True) then begin if AFile.Attributes and FILE_ATTRIBUTE_PINNED <> 0 then Result:= FiEmblemPinned else if AFile.Attributes and FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS <> 0 then Result:= FiEmblemOnline else begin Result:= SHGetStorePropertyValue(AFile.FullPath, PKEY_StorageProviderState); case Result of 1: Result:= FiEmblemOnline; 2: Result:= FiEmblemOffline; 3: Result:= FiEmblemPinned; else Result:= 0; end; end; end else Result:= 0; end; {$ELSEIF DEFINED(RabbitVCS)} function TPixMapManager.GetIconOverlayByFile(AFile: TFile; DirectAccess: Boolean): PtrInt; var Emblem: String; begin if RabbitVCS and DirectAccess then begin Emblem:= CheckStatus(AFile.FullPath); if Length(Emblem) = 0 then Exit(0); Result:= CheckAddThemePixmap(Emblem); Result:= IfThen(Result < 0, 0, Result + SystemIconIndexStart); end else Result:= 0; end; {$ENDIF} function TPixMapManager.GetIconByName(const AIconName: String): PtrInt; begin Result := CheckAddPixmap(AIconName, gIconsSize); end; function TPixMapManager.GetThemeIcon(const AIconName: String; AIconSize: Integer): Graphics.TBitmap; var ABitmap: Graphics.TBitmap; begin Result:= LoadIconThemeBitmap(AIconName, AIconSize); if Assigned(Result) then begin if (Result.Width > AIconSize) or (Result.Height > AIconSize) then begin ABitmap:= Graphics.TBitmap.Create; ABitmap.SetSize(AIconSize, AIconSize); Stretch(Result, ABitmap, ResampleFilters[2].Filter, ResampleFilters[2].Width); Result.Free; Result:= ABitmap; end; end; end; function TPixMapManager.GetDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor; LoadIcon: Boolean) : Graphics.TBitmap; {$IFDEF MSWINDOWS} var PIDL: PItemIDList; SFI: TSHFileInfoW; uFlags: UINT; iIconSmall, iIconLarge: Integer; psii: TSHStockIconInfo; {$ENDIF} begin if Drive^.DriveType = dtVirtual then begin Result := GetBuiltInDriveIcon(Drive, IconSize, clBackColor); Exit; end; Result := nil; {$IFDEF MSWINDOWS} if ScreenInfo.ColorDepth < 15 then Exit; if (not (cimDrive in gCustomIcons)) and (ScreenInfo.ColorDepth > 16) then begin if (Win32MajorVersion < 6) and (not LoadIcon) and (Drive^.DriveType = dtNetwork) then begin Result := GetBuiltInDriveIcon(Drive, IconSize, clBackColor); Exit; end; SFI.hIcon := 0; iIconLarge:= GetSystemMetrics(SM_CXICON); iIconSmall:= GetSystemMetrics(SM_CXSMICON); if (IconSize <= iIconSmall) then uFlags := SHGFI_SMALLICON // Use small icon else begin uFlags := SHGFI_LARGEICON; // Use large icon end; uFlags := uFlags or SHGFI_ICON; if (Drive^.DriveType = dtSpecial) then begin if Succeeded(SHParseDisplayName(PWideChar(CeUtf8ToUtf16(Drive^.DeviceId)), nil, PIDL, 0, nil)) then begin SHGetFileInfoW(PWideChar(PIDL), 0, SFI, SizeOf(SFI), uFlags or SHGFI_PIDL); CoTaskMemFree(PIDL); end; end else if (not LoadIcon) and (Drive^.DriveType = dtNetwork) and SHGetStockIconInfo(SIID_DRIVENET, uFlags, psii) then SFI.hIcon:= psii.hIcon else if (SHGetFileInfoW(PWideChar(CeUtf8ToUtf16(Drive^.Path)), 0, SFI, SizeOf(SFI), uFlags) = 0) then begin SFI.hIcon := 0; end; if (SFI.hIcon <> 0) then try Result:= BitmapCreateFromHICON(SFI.hIcon); if (IconSize <> iIconSmall) and (IconSize <> iIconLarge) then // non standart icon size Result := StretchBitmap(Result, IconSize, clBackColor, True); finally DestroyIcon(SFI.hIcon); end; end // not gCustomDriveIcons else {$ENDIF} begin Result := GetBuiltInDriveIcon(Drive, IconSize, clBackColor); end; if Assigned(Result) and (gDiskIconsAlpha in [1..99]) and (not Drive^.IsMounted) then begin BitmapAlpha(Result, gDiskIconsAlpha / 100); end; end; function TPixMapManager.GetBuiltInDriveIcon(Drive : PDrive; IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap; var DriveIconListIndex: Integer; ABitmap: Graphics.TBitmap; begin {$IFDEF MSWINDOWS} if ScreenInfo.ColorDepth < 15 then Exit(nil); {$ENDIF} case IconSize of 16: // Standart 16x16 icon size DriveIconListIndex := 0; 24: // Standart 24x24 icon size DriveIconListIndex := 1; 32: // Standart 32x32 icon size DriveIconListIndex := 2; else // for non standart icon size use more large icon for stretch DriveIconListIndex := 2; end; with FDriveIconList[DriveIconListIndex] do begin if Assigned(Bitmap[Drive^.DriveType]) then ABitmap:= Bitmap[Drive^.DriveType] else begin ABitmap:= Bitmap[dtHardDisk]; end; end; // if need stretch icon if (IconSize <> 16) and (IconSize <> 24) and (IconSize <> 32) then begin Result := StretchBitmap(ABitmap, IconSize, clBackColor, False); end else begin Result := Graphics.TBitmap.Create; Result.Assign(ABitmap); end; // 'Bitmap' should not be freed, because it only points to DriveIconList. end; {$IF NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} procedure TPixMapManager.LoadApplicationThemeIcon; var AIcon: TIcon; LargeIcon: Graphics.TBitmap; SmallSize, LargeSize: Integer; SmallIcon: Graphics.TBitmap = nil; begin LargeSize:= GetSystemMetrics(SM_CXICON); SmallSize:= GetSystemMetrics(SM_CXSMICON); LargeIcon:= LoadIconThemeBitmapLocked('doublecmd', LargeSize); if (LargeSize <> SmallSize) then begin SmallIcon:= LoadIconThemeBitmapLocked('doublecmd', SmallSize); end; if Assigned(LargeIcon) or Assigned(SmallIcon) then try AIcon:= TIcon.Create; try if Assigned(SmallIcon) then begin AIcon.Add(pf32bit, SmallIcon.Height, SmallIcon.Width); AIcon.AssignImage(SmallIcon); SmallIcon.Free; end; if Assigned(LargeIcon) then begin AIcon.Add(pf32bit, LargeIcon.Height, LargeIcon.Width); if AIcon.Count > 1 then AIcon.Current:= AIcon.Current + 1; AIcon.AssignImage(LargeIcon); LargeIcon.Free; end; Application.Icon.Assign(AIcon); finally AIcon.Free; end; except // Skip end; end; {$ENDIF} function TPixMapManager.GetDefaultDriveIcon(IconSize : Integer; clBackColor : TColor) : Graphics.TBitmap; var Drive: TDrive = (DisplayName: ''; Path: ''; DriveLabel: ''; DeviceId: ''; DriveType: dtHardDisk; DriveSize: 0; FileSystem: ''; IsMediaAvailable: True; IsMediaEjectable: False; IsMediaRemovable: False; IsMounted: True; AutoMount: True); begin Result := GetBuiltInDriveIcon(@Drive, IconSize, clBackColor); end; function TPixMapManager.GetArchiveIcon(IconSize: Integer; clBackColor : TColor) : Graphics.TBitmap; begin Result := GetBitmap(FiArcIconID); if Assigned(Result) then begin // if need stretch icon if (IconSize <> gIconsSize) then begin Result := StretchBitmap(Result, IconSize, clBackColor, True); end; end; end; function TPixMapManager.GetFolderIcon(IconSize: Integer; clBackColor: TColor): Graphics.TBitmap; begin Result := GetBitmap(FiDirIconID); if Assigned(Result) then begin // if need stretch icon if (IconSize <> gIconsSize) then begin Result := StretchBitmap(Result, IconSize, clBackColor, True); end; end; end; function TPixMapManager.GetDefaultIcon(AFile: TFile): PtrInt; begin if AFile.IsDirectory then Result := FiDirIconID else if UTF8LowerCase(AFile.Extension) = 'exe' then Result := FiExeIconID else Result := FiDefaultIconID; end; procedure LoadPixMapManager; begin DCDebug('Creating PixmapManager'); PixMapManager:=TPixMapManager.Create; PixMapManager.Load(gpCfgDir + 'pixmaps.txt'); end; initialization finalization if Assigned(PixMapManager) then begin DCDebug('Shutting down PixmapManager'); FreeAndNil(PixMapManager); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uplaysound.pas��������������������������������������������������������0000644�0001750�0000144�00000003741�14743153644�020136� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uPlaySound; {$mode objfpc}{$H+} {$IF DEFINED(DARWIN)} {$modeswitch objectivec1} {$ENDIF} interface uses Classes, SysUtils {$IF DEFINED(MSWINDOWS)} , MMSystem, LazUTF8 {$ELSEIF DEFINED(DARWIN)} , CocoaAll, uMyDarwin {$ELSE} , LazLogger, sdl2 {$IFNDEF HAIKU} , gst {$ENDIF} {$ENDIF} ; function PlaySound(const FileName: String): Boolean; implementation {$IF DEFINED(DARWIN)} type { NSSoundFinishedDelegate } SoundFinishedDelegate = objcclass(NSObject, NSSoundDelegateProtocol) public procedure sound_didFinishPlaying(Sound: NSSound; FinishedPlaying: Boolean); message 'sound:didFinishPlaying:'; end; var SoundDelegate: SoundFinishedDelegate; { NSSoundFinishedDelegate } procedure SoundFinishedDelegate.sound_didFinishPlaying(Sound: NSSound; FinishedPlaying: Boolean); begin if (FinishedPlaying) then begin Sound.Release; Sound:= nil; Sound.dealloc; end; end; {$ENDIF} function PlaySound(const FileName: String): Boolean; {$IF DEFINED(MSWINDOWS)} begin Result:= sndPlaySoundW(PWideChar(UTF8ToUTF16(FileName)), SND_ASYNC or SND_NODEFAULT); end; {$ELSEIF DEFINED(DARWIN)} var Sound: NSSound; audioFilePath: NSString; begin audioFilePath:= StringToNSString(FileName); Sound:= NSSound.alloc.initWithContentsOfFile_byReference(audioFilePath, True); Sound.setDelegate(SoundDelegate); Result:= Sound.Play; if not Result then begin Sound.Release; Sound:= nil; Sound.dealloc; end; end; {$ELSE} const First: Boolean = True; Play: function(const FileName: String): Boolean = nil; begin if First then begin {$IF NOT DEFINED(HAIKU)} if GST_Initialize then begin Play:= @GST_Play; end else {$ENDIF} if SDL_Initialize then begin Play:= @SDL_Play; end; First:= False; end; if (Play = nil) then Result:= False else begin Result:= Play(FileName); end; end; {$ENDIF} {$IF DEFINED(DARWIN)} initialization SoundDelegate:= SoundFinishedDelegate.alloc.init; {$ENDIF} end. �������������������������������doublecmd-1.1.22/src/platform/urandom.pas�����������������������������������������������������������0000644�0001750�0000144�00000006373�14743153644�017404� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Cryptographically secure pseudo-random number generator Copyright (C) 2017 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uRandom; {$mode delphi} interface procedure Random(ABlock: PByte; ACount: Integer); implementation uses ISAAC {$IF DEFINED(MSWINDOWS)} , Windows {$ELSEIF DEFINED(UNIX)} , DCOSUtils {$IF DEFINED(LINUX)} , dl, BaseUnix, InitC {$ENDIF} {$ENDIF} , SysUtils {$IF (FPC_FULLVERSION < 30000)} , LazUTF8SysUtils {$ENDIF} ; threadvar Context: isaac_ctx; {$IF DEFINED(MSWINDOWS)} var RtlGenRandom: function(RandomBuffer: PByte; RandomBufferLength: ULONG): LongBool; stdcall; {$ELSEIF DEFINED(UNIX)} const random_dev = '/dev/urandom'; var HasRandom: Boolean = False; {$IF DEFINED(LINUX)} getrandom: function(buf: PByte; buflen: csize_t; flags: cuint): cint; cdecl; {$ENDIF} {$ENDIF} procedure Random(ABlock: PByte; ACount: Integer); var {$IF DEFINED(UNIX)} Handle: THandle; {$ENDIF} Result: Boolean = False; begin {$IF DEFINED(MSWINDOWS)} Result:= Assigned(RtlGenRandom); if Result then Result:= RtlGenRandom(ABlock, ACount); {$ELSEIF DEFINED(UNIX)} {$IF DEFINED(LINUX)} if Assigned(getrandom) then begin repeat Result:= (getrandom(ABlock, ACount, 0) = ACount); until (Result = True) or (fpgetCerrno <> ESysEINTR); end; if not Result then {$ENDIF} if HasRandom then begin Handle:= mbFileOpen(random_dev, fmOpenRead or fmShareDenyNone); Result:= (Handle <> feInvalidHandle); if Result then begin Result:= (FileRead(Handle, ABlock^, ACount) = ACount); FileClose(Handle); end; end; {$ENDIF} if not Result then begin if (Context.randidx = 0) then begin isaac_inita({%H-}Context, [Int32(GetTickCount64), Integer(GetThreadID), Integer(GetProcessID), GetHeapStatus.TotalFree, Int32(Trunc(Now * MSecsPerDay))], 5); end; isaac_read(Context, ABlock, ACount); end; end; initialization {$IF DEFINED(MSWINDOWS)} @RtlGenRandom:= GetProcAddress(GetModuleHandle('advapi32.dll'), 'SystemFunction036'); {$ELSEIF DEFINED(UNIX)} HasRandom:= mbFileAccess(random_dev, fmOpenRead); {$IF DEFINED(LINUX)} @getrandom:= dlsym(dlopen('libc.so.6', RTLD_NOW), 'getrandom'); {$ENDIF} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/usysfolders.pas�������������������������������������������������������0000644�0001750�0000144�00000012461�14743153644�020314� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Get system folders. Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uSysFolders; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils; {en Get the user home directory @returns(The user home directory) } function GetHomeDir : String; {en Get the appropriate directory for the application's configuration files @returns(The directory for the application's configuration files) } function GetAppConfigDir: String; {en Get the appropriate directory for the application's cache files @returns(The directory for the application's cache files) } function GetAppCacheDir: String; {en Get the appropriate directory for the application's data files @returns(The directory for the application's data files) } function GetAppDataDir: String; implementation uses DCOSUtils, DCStrUtils, DCConvertEncoding, LazUTF8 {$IF DEFINED(MSWINDOWS)} , Windows, ShlObj, DCWindows {$ENDIF} {$IF DEFINED(UNIX)} , BaseUnix, Unix, DCUnix {$IF DEFINED(DARWIN)} , CocoaAll, uMyDarwin {$ELSEIF DEFINED(HAIKU)} , DCHaiku {$ELSE} , uXdg {$ENDIF} {$ENDIF} ; function GetHomeDir : String; {$IFDEF MSWINDOWS} begin Result:= ExcludeBackPathDelimiter(mbGetEnvironmentVariable('USERPROFILE')); end; {$ELSE} begin {$IF DEFINED(HAIKU)} if mbFindDirectory(B_USER_DIRECTORY, -1, True, Result) then Result:= ExcludeBackPathDelimiter(Result) else {$ENDIF} Result:= ExcludeBackPathDelimiter(SysToUTF8(GetEnvironmentVariable('HOME'))); end; {$ENDIF} function GetAppConfigDir: String; {$IF DEFINED(MSWINDOWS)} const SHGFP_TYPE_CURRENT = 0; var wPath: array[0..MAX_PATH-1] of WideChar; wUser: UnicodeString; dwLength: DWORD; begin if SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA or CSIDL_FLAG_CREATE, 0, SHGFP_TYPE_CURRENT, @wPath[0])) or SUCCEEDED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA or CSIDL_FLAG_CREATE, 0, SHGFP_TYPE_CURRENT, @wPath[0])) then begin Result := UTF16ToUTF8(UnicodeString(wPath)); end else begin dwLength := UNLEN + 1; SetLength(wUser, dwLength); if GetUserNameW(PWideChar(wUser), @dwLength) then begin SetLength(wUser, dwLength - 1); Result := GetTempDir + UTF16ToUTF8(wUser); end else Result := EmptyStr; end; if Result <> '' then Result := Result + DirectorySeparator + ApplicationName; end; {$ELSEIF DEFINED(DARWIN)} begin Result:= GetHomeDir + '/Library/Preferences/' + ApplicationName; end; {$ELSEIF DEFINED(HAIKU)} begin if mbFindDirectory(B_USER_SETTINGS_DIRECTORY, -1, True, Result) then Result:= IncludeTrailingBackslash(Result) + ApplicationName else begin Result:= GetHomeDir + '/config/settings/' + ApplicationName; end; end; {$ELSE} var uinfo: PPasswordRecord; begin uinfo:= getpwuid(fpGetUID); if (uinfo <> nil) and (uinfo^.pw_dir <> '') then Result:= CeSysToUtf8(uinfo^.pw_dir) + '/.config/' + ApplicationName else Result:= ExcludeTrailingPathDelimiter(SysToUTF8(SysUtils.GetAppConfigDir(False))); end; {$ENDIF} function GetAppCacheDir: String; {$IF DEFINED(MSWINDOWS)} var APath: array[0..MAX_PATH] of WideChar; begin if SHGetSpecialFolderPathW(0, APath, CSIDL_LOCAL_APPDATA, True) then Result:= UTF16ToUTF8(UnicodeString(APath)) + DirectorySeparator + ApplicationName else Result:= GetAppConfigDir; end; {$ELSEIF DEFINED(DARWIN)} begin Result:= NSGetFolderPath(NSCachesDirectory); end; {$ELSEIF DEFINED(HAIKU)} begin if mbFindDirectory(B_USER_CACHE_DIRECTORY, -1, True, Result) then Result:= IncludeTrailingBackslash(Result) + ApplicationName else begin Result:= GetHomeDir + '/config/cache/' + ApplicationName; end; end; {$ELSE} var uinfo: PPasswordRecord; begin uinfo:= getpwuid(fpGetUID); if (uinfo <> nil) and (uinfo^.pw_dir <> '') then Result:= CeSysToUtf8(uinfo^.pw_dir) + '/.cache/' + ApplicationName else Result:= GetHomeDir + '/.cache/' + ApplicationName; end; {$ENDIF} function GetAppDataDir: String; {$IF DEFINED(MSWINDOWS)} begin Result:= GetAppCacheDir; end; {$ELSEIF DEFINED(DARWIN)} begin Result:= NSGetFolderPath(NSApplicationSupportDirectory); end; {$ELSEIF DEFINED(HAIKU)} begin if mbFindDirectory(B_USER_DATA_DIRECTORY, -1, True, Result) then Result:= IncludeTrailingBackslash(Result) + ApplicationName else begin Result:= GetHomeDir + '/config/data/' + ApplicationName; end; end; {$ELSE} begin Result:= IncludeTrailingPathDelimiter(GetUserDataDir) + ApplicationName; end; {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/usystem.pas�����������������������������������������������������������0000644�0001750�0000144�00000000732�14743153644�017441� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uSystem; {$mode objfpc}{$H+} interface uses Math {$IF DEFINED(MSWINDOWS)} , Windows {$ENDIF} ; procedure Initialize; implementation procedure Initialize; begin // Disable invalid floating point operation exception SetExceptionMask(GetExceptionMask + [exInvalidOp, exZeroDivide]); {$IF DEFINED(MSWINDOWS)} SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX); {$ENDIF} end; initialization Initialize; end. ��������������������������������������doublecmd-1.1.22/src/platform/utarwriter.pas��������������������������������������������������������0000644�0001750�0000144�00000055611�14743153644�020146� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple TAR archive writer Copyright (C) 2011-2019 Alexander Koblov (alexx2000@mail.ru) This unit is based on libtar.pp from the Free Component Library (FCL) 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, see <http://www.gnu.org/licenses/>. } unit uTarWriter; {$mode objfpc}{$H+} interface uses Classes, SysUtils,LazUtf8, uGlobs, uWcxModule, WcxPlugin, DCClassesUtf8, uFile, uFileSource, uFileSourceOperationUI, uFileSourceOperation, uFileSourceCopyOperation; const RECORDSIZE = 512; NAMSIZ = 100; TUNMLEN = 32; TGNMLEN = 32; CHKBLANKS = #32#32#32#32#32#32#32#32; USTAR = 'ustar'#32#32; LONGLINK = '././@LongLink'; LONGLEN = RECORDSIZE * 64; LONGMAX = RECORDSIZE * 128; type TDataWriteProcedure = procedure(Buffer: Pointer; BytesToWrite: Int64) of object; TUpdateStatisticsFunction = procedure(var NewStatistics: TFileSourceCopyOperationStatistics) of object; { TTarHeader } TTarHeader = packed record Name: array [0..NAMSIZ - 1] of AnsiChar; Mode: array [0..7] of AnsiChar; UID: array [0..7] of AnsiChar; GID: array [0..7] of AnsiChar; Size: array [0..11] of AnsiChar; MTime: array [0..11] of AnsiChar; ChkSum: array [0..7] of AnsiChar; TypeFlag: AnsiChar; LinkName: array [0..NAMSIZ - 1] of AnsiChar; Magic: array [0..7] of AnsiChar; UName: array [0..TUNMLEN - 1] of AnsiChar; GName: array [0..TGNMLEN - 1] of AnsiChar; DevMajor: array [0..7] of AnsiChar; DevMinor: array [0..7] of AnsiChar; Prefix: array [0..154] of AnsiChar; end; { TTarHeaderEx } TTarHeaderEx = packed record case Boolean of True: (HR: TTarHeader); False: (HA: array [0..RECORDSIZE - 1] of AnsiChar); end; { TTarWriter } TTarWriter = class private FSourceStream, FTargetStream: TFileStreamEx; FWcxModule: TWcxModule; FTarHeader: TTarHeaderEx; FBasePath, FTargetPath, FArchiveFileName: String; FBufferIn, FBufferOut: Pointer; FBufferSize: LongWord; FMemPack: TArcHandle; FLongName: array[0..Pred(LONGMAX)] of AnsiChar; procedure WriteFakeHeader(const ItemName: String; IsFileName: Boolean; Offset: LongInt); function MakeLongName(const FileName, LinkName: String; NameLen, LinkLen: LongInt): LongInt; function ReadData(BytesToRead: Int64): Int64; procedure WriteData(Buffer: Pointer; BytesToWrite: Int64); procedure CompressData(BufferIn: Pointer; BytesToCompress: Int64); protected AskQuestion: TAskQuestionFunction; AbortOperation: TAbortOperationFunction; CheckOperationState: TCheckOperationStateFunction; UpdateStatistics: TUpdateStatisticsFunction; DataWrite: TDataWriteProcedure; procedure ShowError(sMessage: String); procedure AddFile(const FileName: String); function WriteFile(const FileName: String; var Statistics: TFileSourceCopyOperationStatistics): Boolean; public constructor Create(ArchiveFileName: String; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction ); constructor Create(ArchiveFileName: String; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; WcxModule: TWcxModule ); destructor Destroy; override; function ProcessTree(var Files: TFiles; var Statistics: TFileSourceCopyOperationStatistics): Boolean; end; implementation uses {$IF DEFINED(MSWINDOWS)} Windows, DCFileAttributes, DCWindows, uMyWindows, {$ELSEIF DEFINED(UNIX)} BaseUnix, FileUtil, uUsersGroups, {$ENDIF} uLng, DCStrUtils, DCOSUtils, uOSUtils; {$IF DEFINED(MSWINDOWS)} const FILE_UNIX_MODE = S_IRUSR or S_IWUSR or S_IRGRP or S_IROTH; FOLDER_UNIX_MODE = S_IRUSR or S_IWUSR or S_IXUSR or S_IRGRP or S_IXGRP or S_IROTH or S_IXOTH; {$ENDIF} // Makes a string of octal digits // The string will always be "Len" characters long procedure Octal64(N : Int64; P : PAnsiChar; Len : Integer); var I : Integer; begin for I := Len - 1 downto 0 do begin (P + I)^ := AnsiChar (ORD ('0') + ORD (N and $07)); N := N shr 3; end; for I := 0 to Len - 1 do begin if (P + I)^ in ['0'..'7'] then Break; (P + I)^ := '0'; end; end; procedure OctalN(N : Int64; P : PAnsiChar; Len : Integer); begin Octal64(N, P, Len-1); (P + Len - 1)^ := #0; end; procedure CheckSum(var TarHeader: TTarHeaderEx); var I: Integer; ChkSum : Cardinal = 0; begin with TarHeader do begin StrMove(HR.ChkSum, CHKBLANKS, 8); for I := 0 to SizeOf(TTarHeader) - 1 do Inc(ChkSum, Ord(HA[I])); Octal64(ChkSum, HR.ChkSum, 6); HR.ChkSum[6] := #0; HR.ChkSum[7] := #32; end; end; {$IF DEFINED(MSWINDOWS)} function GetFileInfo(const FileName: String; out FileInfo: TWin32FindDataW): Boolean; var Handle: System.THandle; begin Handle := FindFirstFileW(PWideChar(UTF16LongName(FileName)), FileInfo); Result := Handle <> INVALID_HANDLE_VALUE; if Result then begin FileInfo.dwFileAttributes:= ExtractFileAttributes(FileInfo); Windows.FindClose(Handle); end; end; {$ELSEIF DEFINED(UNIX)} function GetFileInfo(const FileName: String; out FileInfo: BaseUnix.Stat): Boolean; begin Result:= fpLStat(UTF8ToSys(FileName), FileInfo) >= 0; end; {$ENDIF} { TTarWriter } procedure TTarWriter.ShowError(sMessage: String); begin AskQuestion(sMessage, '', [fsourAbort], fsourAbort, fsourAbort); AbortOperation; end; constructor TTarWriter.Create(ArchiveFileName: String; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction); begin AskQuestion := AskQuestionFunction; AbortOperation := AbortOperationFunction; CheckOperationState := CheckOperationStateFunction; UpdateStatistics := UpdateStatisticsFunction; DataWrite:= @WriteData; FArchiveFileName:= ArchiveFileName; FTargetPath:= ExtractFilePath(ArchiveFileName); // Allocate buffers FBufferSize := gCopyBlockSize; GetMem(FBufferIn, FBufferSize); FBufferOut:= nil; FWcxModule:= nil; FMemPack:= 0; end; constructor TTarWriter.Create(ArchiveFileName: String; AskQuestionFunction: TAskQuestionFunction; AbortOperationFunction: TAbortOperationFunction; CheckOperationStateFunction: TCheckOperationStateFunction; UpdateStatisticsFunction: TUpdateStatisticsFunction; WcxModule: TWcxModule); begin AskQuestion := AskQuestionFunction; AbortOperation := AbortOperationFunction; CheckOperationState := CheckOperationStateFunction; UpdateStatistics := UpdateStatisticsFunction; DataWrite:= @CompressData; FArchiveFileName:= ArchiveFileName; FTargetPath:= ExtractFilePath(ArchiveFileName); // Allocate buffers FBufferSize := gCopyBlockSize; GetMem(FBufferIn, FBufferSize); GetMem(FBufferOut, FBufferSize); FWcxModule:= WcxModule; // Starts packing into memory FMemPack:= FWcxModule.WcxStartMemPack(MEM_OPTIONS_WANTHEADERS, ExtractFileName(ArchiveFileName)); end; destructor TTarWriter.Destroy; begin inherited Destroy; if Assigned(FWcxModule) then begin // Ends packing into memory if (FMemPack <> 0) then FWcxModule.DoneMemPack(FMemPack); end; if Assigned(FBufferIn) then begin FreeMem(FBufferIn); FBufferIn := nil; end; if Assigned(FBufferOut) then begin FreeMem(FBufferOut); FBufferOut := nil; end; end; procedure TTarWriter.AddFile(const FileName: String); {$IF DEFINED(MSWINDOWS)} var FileInfo: TWin32FindDataW; LinkName, FileNameIn: String; FileMode: Cardinal; FileTime, FileSize: Int64; NameLen, LinkLen: LongInt; begin if GetFileInfo(FileName, FileInfo) then with FTarHeader do begin FillByte(HR, SizeOf(FTarHeader), 0); // File name FileNameIn:= ExtractDirLevel(FBasePath, FileName); FileNameIn:= StringReplace (FileNameIn, '\', '/', [rfReplaceAll]); if FPS_ISDIR(FileInfo.dwFileAttributes) then FileNameIn:= FileNameIn + '/'; StrLCopy (HR.Name, PAnsiChar(FileNameIn), NAMSIZ); // File mode if FPS_ISDIR(FileInfo.dwFileAttributes) then FileMode:= FOLDER_UNIX_MODE else FileMode:= FILE_UNIX_MODE; OctalN(FileMode, HR.Mode, 8); // File size FileSize:= (FileInfo.nFileSizeHigh shl 32) or FileInfo.nFileSizeLow; if FPS_ISLNK(FileInfo.dwFileAttributes) then OctalN(0, HR.Size, 12) else OctalN(FileSize, HR.Size, 12); // Modification time FileTime:= Round((Int64(FileInfo.ftLastWriteTime) - 116444736000000000) / 10000000); OctalN(FileTime, HR.MTime, 12); // File type if FPS_ISLNK(FileInfo.dwFileAttributes) then HR.TypeFlag := '2' else if FPS_ISDIR(FileInfo.dwFileAttributes) then HR.TypeFlag := '5' else HR.TypeFlag := '0'; // Link name if FPS_ISLNK(FileInfo.dwFileAttributes) then begin LinkName:= ReadSymLink(FileName); StrLCopy(HR.LinkName, PAnsiChar(LinkName), NAMSIZ); end; // Magic StrLCopy (HR.Magic, PAnsiChar(USTAR), 8); // Header checksum CheckSum(FTarHeader); // Get file name and link name length NameLen:= Length(FileNameIn); LinkLen:= Length(LinkName); // Write data if not ((NameLen > NAMSIZ) or (LinkLen > NAMSIZ)) then DataWrite(@HA, RECORDSIZE) else begin NameLen:= MakeLongName(FileNameIn, LinkName, NameLen, LinkLen); DataWrite(@FLongName, NameLen); end; end; end; {$ELSEIF DEFINED(UNIX)} var FileInfo: BaseUnix.Stat; LinkName, FileNameIn: String; NameLen, LinkLen: LongInt; begin if GetFileInfo(FileName, FileInfo) then with FTarHeader do begin FillByte(HR, SizeOf(FTarHeader), 0); // File name FileNameIn:= ExtractDirLevel(FBasePath, FileName); if fpS_ISDIR(FileInfo.st_mode) then FileNameIn:= FileNameIn + PathDelim; StrLCopy (HR.Name, PAnsiChar(FileNameIn), NAMSIZ); // File mode OctalN(FileInfo.st_mode and $FFF, HR.Mode, 8); // UID OctalN(FileInfo.st_uid, HR.UID, 8); // GID OctalN(FileInfo.st_gid, HR.GID, 8); // File size if fpS_ISLNK(FileInfo.st_mode) or fpS_ISDIR(FileInfo.st_mode) then OctalN(0, HR.Size, 12) else OctalN(FileInfo.st_size, HR.Size, 12); // Modification time OctalN(FileInfo.st_mtime, HR.MTime, 12); // File type if fpS_ISLNK(FileInfo.st_mode) then HR.TypeFlag:= '2' else if fpS_ISCHR(FileInfo.st_mode) then HR.TypeFlag:= '3' else if fpS_ISBLK(FileInfo.st_mode) then HR.TypeFlag:= '4' else if fpS_ISDIR(FileInfo.st_mode) then HR.TypeFlag:= '5' else if fpS_ISFIFO(FileInfo.st_mode) then HR.TypeFlag:= '6' else HR.TypeFlag:= '0'; // Link name if fpS_ISLNK(FileInfo.st_mode) then begin LinkName:= ReadSymLink(FileName); StrLCopy(HR.LinkName, PAnsiChar(LinkName), NAMSIZ); end; // Magic StrLCopy (HR.Magic, PAnsiChar(USTAR), 8); // User StrPLCopy(HR.UName, UIDToStr(FileInfo.st_uid), TUNMLEN); // Group StrPLCopy(HR.GName, GIDToStr(FileInfo.st_gid), TGNMLEN); // Header checksum CheckSum(FTarHeader); // Get file name and link name length NameLen:= Length(FileNameIn); LinkLen:= Length(LinkName); // Write data if not ((NameLen > NAMSIZ) or (LinkLen > NAMSIZ)) then DataWrite(@HA, RECORDSIZE) else begin NameLen:= MakeLongName(FileNameIn, LinkName, NameLen, LinkLen); DataWrite(@FLongName, NameLen); end; end; end; {$ENDIF} procedure TTarWriter.WriteFakeHeader(const ItemName: String; IsFileName: Boolean; Offset: LongInt); var TarHeader: TTarHeaderEx; begin with TarHeader do begin FillByte(TarHeader, SizeOf(TTarHeaderEx), 0); StrPLCopy (HR.Name, LONGLINK, NAMSIZ); if IsFileName then HR.TypeFlag:= 'L' else HR.TypeFlag:= 'K'; // File mode OctalN(0, HR.Mode, 8); // UID OctalN(0, HR.UID, 8); // GID OctalN(0, HR.GID, 8); // Name size OctalN(Length(ItemName) + 1, HR.Size, 12); // Modification time OctalN(0, HR.MTime, 12); // Magic StrLCopy (HR.Magic, PAnsiChar(USTAR), 8); // User StrPLCopy(HR.UName, 'root', TUNMLEN); // Group StrPLCopy(HR.GName, 'root', TGNMLEN); // Header checksum CheckSum(TarHeader); // Copy file record Move(HA, PByte(PAnsiChar(@FLongName) + Offset)^, RECORDSIZE); // Copy file name StrMove(PAnsiChar(@FLongName) + Offset + RECORDSIZE, PAnsiChar(ItemName), Length(ItemName)); end; end; function TTarWriter.MakeLongName(const FileName, LinkName: String; NameLen, LinkLen: LongInt): LongInt; begin with FTarHeader do begin Result:= 0; // Strip string length to maximum length if (NameLen + RECORDSIZE) > LONGLEN then NameLen:= LONGLEN - RECORDSIZE * 2; if (LinkLen + RECORDSIZE) > LONGLEN then LinkLen:= LONGLEN - RECORDSIZE * 2; // Clear output buffer FillChar(FLongName, NameLen + LinkLen + RECORDSIZE * 4, #0); // Write Header for long link name if LinkLen > NAMSIZ then begin WriteFakeHeader(LinkName, False, Result); // Align link name by RECORDSIZE (512) if (LinkLen mod RECORDSIZE) = 0 then Result:= Result + RECORDSIZE + Linklen else Result:= Result + RECORDSIZE * 2 + (LinkLen div RECORDSIZE) * RECORDSIZE; end; // Write Header for long file name if NameLen > NAMSIZ then begin WriteFakeHeader(FileName, True, Result); // Align file name by RECORDSIZE (512) if (NameLen mod RECORDSIZE) = 0 then Result:= Result + RECORDSIZE + NameLen else Result:= Result + RECORDSIZE * 2 + (NameLen div RECORDSIZE) * RECORDSIZE; end; // Copy file record Move(HA, PByte(PAnsiChar(@FLongName) + Result)^, RECORDSIZE); Result:= Result + RECORDSIZE; end; end; function TTarWriter.ReadData(BytesToRead: Int64): Int64; var bRetryRead: Boolean; BytesRead: Int64; begin repeat try bRetryRead := False; FillByte(FBufferIn^, FBufferSize, 0); BytesRead:= FSourceStream.Read(FBufferIn^, BytesToRead); if (BytesRead = 0) then Raise EReadError.Create(mbSysErrorMessage(GetLastOSError)); except on E: EReadError do begin case AskQuestion(rsMsgErrERead + ' ' + FSourceStream.FileName + ':', E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryRead := True; fsourAbort: AbortOperation; fsourSkip: Exit; end; // case end; end; until not bRetryRead; Result:= BytesRead; end; procedure TTarWriter.WriteData(Buffer: Pointer; BytesToWrite: Int64); var iTotalDiskSize, iFreeDiskSize: Int64; bRetryWrite: Boolean; BytesWrittenTry, BytesWritten: Int64; begin BytesWritten := 0; repeat try bRetryWrite := False; BytesWrittenTry := FTargetStream.Write((Buffer + BytesWritten)^, BytesToWrite - BytesWritten); BytesWritten := BytesWritten + BytesWrittenTry; if BytesWrittenTry = 0 then begin Raise EWriteError.Create(mbSysErrorMessage(GetLastOSError)); end else if BytesWritten < BytesToWrite then begin bRetryWrite := True; // repeat and try to write the rest end; except on E: EWriteError do begin { Check disk free space } GetDiskFreeSpace(FTargetPath, iFreeDiskSize, iTotalDiskSize); if BytesToWrite > iFreeDiskSize then begin case AskQuestion(rsMsgNoFreeSpaceRetry, '', [fsourYes, fsourNo], fsourYes, fsourNo) of fsourYes: bRetryWrite := True; fsourNo: AbortOperation; end; // case end else begin case AskQuestion(rsMsgErrEWrite + ' ' + FArchiveFileName + ':', E.Message, [fsourRetry, fsourSkip, fsourAbort], fsourRetry, fsourSkip) of fsourRetry: bRetryWrite := True; fsourAbort: AbortOperation; fsourSkip: Exit; end; // case end; end; // on do end; // except until not bRetryWrite; end; procedure TTarWriter.CompressData(BufferIn: Pointer; BytesToCompress: Int64); var InLen: LongInt; Written: LongInt = 0; Taken: LongInt = 0; SeekBy: LongInt = 0; OffSet: LongInt = 0; Result: LongInt; begin InLen:= BytesToCompress; // Do while not all data accepted repeat // Recalculate offset if (Taken <> 0) then begin OffSet:= OffSet + Taken; InLen:= InLen - Taken; end; // Compress input buffer {$PUSH}{$WARNINGS OFF} Result:= FWcxModule.PackToMem(FMemPack, PByte(PtrUInt(BufferIn) + OffSet), InLen, @Taken, FBufferOut, FBufferSize, @Written, @SeekBy); {$POP} if not (Result in [MEMPACK_OK, MEMPACK_DONE]) then begin ShowError(Format(rsMsgLogError + rsMsgLogPack, [FArchiveFileName + ' - ' + GetErrorMsg(Result)])); end; // Seek if needed if (SeekBy <> 0) then FTargetStream.Seek(SeekBy, soCurrent); // Write compressed data if Written > 0 then WriteData(FBufferOut, Written); until ((Taken = InLen) and (BytesToCompress <> 0)) or (Result = MEMPACK_DONE); end; function TTarWriter.WriteFile(const FileName: String; var Statistics: TFileSourceCopyOperationStatistics): Boolean; var BytesRead, BytesToRead, BytesToWrite: Int64; TotalBytesToRead: Int64 = 0; begin Result := False; BytesToRead := FBufferSize; try FSourceStream:= nil; try FSourceStream := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite); TotalBytesToRead := FSourceStream.Size; while TotalBytesToRead > 0 do begin // Without the following line the reading is very slow // if it tries to read past end of file. if TotalBytesToRead < BytesToRead then BytesToRead := TotalBytesToRead; BytesRead:= ReadData(BytesToRead); TotalBytesToRead := TotalBytesToRead - BytesRead; BytesToWrite:= BytesRead; if (BytesRead mod RECORDSIZE) <> 0 then begin // Align by TAR RECORDSIZE BytesToWrite:= (BytesRead div RECORDSIZE) * RECORDSIZE + RECORDSIZE; end; // Write data DataWrite(FBufferIn, BytesToWrite); with Statistics do begin CurrentFileDoneBytes := CurrentFileDoneBytes + BytesRead; DoneBytes := DoneBytes + BytesRead; UpdateStatistics(Statistics); end; CheckOperationState; // check pause and stop end; // while finally FreeAndNil(FSourceStream); end; Result:= True; except on EFOpenError do begin ShowError(rsMsgLogError + rsMsgErrEOpen + ': ' + FileName); end; on EWriteError do begin ShowError(rsMsgLogError + rsMsgErrEWrite + ': ' + FArchiveFileName); end; end; end; function TTarWriter.ProcessTree(var Files: TFiles; var Statistics: TFileSourceCopyOperationStatistics): Boolean; var aFile: TFile; Divider: Int64 = 1; CurrentFileIndex: Integer; iTotalDiskSize, iFreeDiskSize: Int64; begin try Result:= False; // Set base path FBasePath:= Files.Path; if FMemPack = 0 then begin Divider:= 2; end; // Update progress with Statistics do begin TotalBytes:= TotalBytes * Divider; UpdateStatistics(Statistics); end; // Check disk free space //if FCheckFreeSpace = True then begin GetDiskFreeSpace(FTargetPath, iFreeDiskSize, iTotalDiskSize); if Statistics.TotalBytes > iFreeDiskSize then begin AskQuestion('', rsMsgNoFreeSpaceCont, [fsourAbort], fsourAbort, fsourAbort); AbortOperation; end; end; // Create destination file FTargetStream := TFileStreamEx.Create(FArchiveFileName, fmCreate); try for CurrentFileIndex := 0 to Files.Count - 1 do begin aFile := Files[CurrentFileIndex]; if aFile.IsDirectory or aFile.IsLink then begin // Add file record only AddFile(aFile.FullPath); end else begin // Update progress with Statistics do begin CurrentFileFrom := aFile.FullPath; CurrentFileTotalBytes := aFile.Size; CurrentFileDoneBytes := 0; end; UpdateStatistics(Statistics); // Add file record AddFile(aFile.FullPath); // TAR current file if not WriteFile(aFile.FullPath, Statistics) then Break; end; CheckOperationState; end; // Finish TAR archive with two null records FillByte(FBufferIn^, RECORDSIZE * 2, 0); DataWrite(FBufferIn, RECORDSIZE * 2); // Finish compression if needed if (FMemPack <> 0) then CompressData(FBufferIn, 0); finally if Assigned(FTargetStream) then begin FreeAndNil(FTargetStream); if (Statistics.DoneBytes <> Statistics.TotalBytes div Divider) then // There was some error, because not all files has been archived. // Delete the not completed target file. mbDeleteFile(FArchiveFileName) else Result:= True; end; end; except on EFCreateError do begin ShowError(rsMsgLogError + rsMsgErrECreate + ': ' + FArchiveFileName); end; end; end; end. �����������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/utrash.pas������������������������������������������������������������0000644�0001750�0000144�00000027614�14743153644�017246� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Some functions for working with trash Copyright (C) 2009-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uTrash; {$mode objfpc}{$H+} {$IF DEFINED(DARWIN)} {$modeswitch objectivec1} {$ENDIF} interface uses LazUtf8, Classes, SysUtils; // this function move files and folders to trash can. function mbDeleteToTrash(const FileName: String): Boolean; // this funсtion checks trash availability. function mbCheckTrash(sPath: String): Boolean; var FileTrashUtf8: function(const FileName: String): Boolean; implementation uses DCOSUtils, DCStrUtils, {$IF DEFINED(MSWINDOWS)} Windows, ShellApi, DCConvertEncoding, uMyWindows {$ELSEIF DEFINED(UNIX)} BaseUnix, DCUnix, uMyUnix, uOSUtils, FileUtil, uSysFolders {$IF DEFINED(DARWIN)} , MacOSAll, DynLibs, CocoaAll, uMyDarwin {$ELSEIF DEFINED(HAIKU)} , DCHaiku, DCConvertEncoding {$ELSE} , uFileProcs, uClipboard, uXdg {$ENDIF} {$ENDIF} ; {$IF DEFINED(DARWIN)} type NSFileManager = objcclass external (NSObject) public class function defaultManager: NSFileManager; message 'defaultManager'; function trashItemAtURL_resultingItemURL_error(url: NSURL; outResultingURL: NSURLPtr; error: NSErrorPtr): Boolean; message 'trashItemAtURL:resultingItemURL:error:'; end; var CoreLib: TLibHandle; FSMoveObjectToTrash: function( const (*var*) source: FSRef; var target: FSRef; options: OptionBits ): OSStatus; stdcall; {$ENDIF} function mbDeleteToTrash(const FileName: String): Boolean; {$IF DEFINED(MSWINDOWS)} var wsFileName: WideString; FileOp: TSHFileOpStructW; dwFileAttributes: LongWord; begin // Windows cannot move file with space at the end into // recycle bin correctly, so we return False in this case if StrEnds(FileName, ' ') then Exit(False); wsFileName:= CeUtf8ToUtf16(FileName); // Windows before Vista cannot move symlink into // recycle bin correctly, so we return False in this case if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 6) then begin dwFileAttributes:= GetFileAttributesW(PWideChar(wsFileName)); if FPS_ISLNK(dwFileAttributes) and FPS_ISDIR(dwFileAttributes) then Exit(False); end; wsFileName:= wsFileName + #0; FillChar(FileOp, SizeOf(FileOp), 0); FileOp.wFunc := FO_DELETE; FileOp.pFrom := PWideChar(wsFileName); // Move without question FileOp.fFlags := FOF_ALLOWUNDO or FOF_NOERRORUI or FOF_SILENT or FOF_NOCONFIRMATION; Result := (SHFileOperationW(@FileOp) = 0) and (not FileOp.fAnyOperationsAborted); end; {$ELSEIF DEFINED(DARWIN)} var theSourceFSRef, theTargetFSRef: FSRef; newFileName: String; trashDir: String; begin // Mac OS X >= 10.8 if (NSAppKitVersionNumber >= 1187) then begin Result:= NSFileManager.defaultManager.trashItemAtURL_resultingItemURL_error(NSURL(NSURL.fileURLWithPath(StringToNSString(FileName))), nil, nil); Exit; end; // Mac OS X >= 10.5 if Assigned(FSMoveObjectToTrash) then begin if (FSPathMakeRefWithOptions(PAnsiChar(FileName), kFSPathMakeRefDoNotFollowLeafSymlink, theSourceFSRef, nil) = noErr) then begin Result:= (FSMoveObjectToTrash(theSourceFSRef, theTargetFSRef, kFSFileOperationDefaultOptions) = noErr); Exit; end; end; { if } { MacOSX 10.4 and below compatibility mode: - If file is in base drive, it gets moved to $HOME/.Trash/ - If file is in some other local drive, it gets moved to /Volumes/$(Volume)/.Trashes/$UID/ - If file is in network, it can't be moved to trash Trash folders are automatically created by OS at login and deleted if empty at logout. If a file with same name exists in trash folder, time is appended to filename } trashDir := FindMountPointPath(FileName); if (trashDir = PathDelim) then trashDir := GetHomeDir + '/.Trash' else begin // file is not located at base drive trashDir += '.Trashes/' + IntToStr(fpGetUID); end; { if } // check if trash folder exists (e.g. network drives don't have one) if not mbDirectoryExists(trashDir) then begin Result := false; Exit; end; { if } newFileName := trashDir + PathDelim + ExtractFileName(FileName); if mbFileSystemEntryExists(newFileName) then newFileName := Format('%s %s', [newFileName, FormatDateTime('hh-nn-ss', Time)]); Result := mbRenameFile(FileName, newFileName); end; {$ELSEIF DEFINED(HAIKU)} const kAttrOriginalPath = '_trk/original_path'; var dev: dev_t; ATrash: String; AHandle: THandle; AFileName, ATrashFile: String; begin AFileName:= CeUtf8ToSys(FileName); dev:= dev_for_path(PAnsiChar(AFileName)); if not mbFindDirectory(B_TRASH_DIRECTORY, dev, True, ATrash) then Exit(False); if IsInPath(ATrash, FileName, True, True) then Exit(False); ATrash:= IncludeTrailingBackslash(ATrash); ATrashFile:= ATrash + ExtractOnlyFileName(FileName); ATrashFile:= GetTempName(ATrashFile, ExtractOnlyFileExt(FileName)); if fpRename(FileName, ATrashFile) < 0 then Exit(False); Result:= mbFileWriteXattr(ATrashFile, kAttrOriginalPath, AFileName); if not Result then begin fpRename(ATrashFile, FileName); end; end; {$ELSEIF DEFINED(UNIX)} // This implementation is based on FreeDesktop.org "Trash Specification" // (http://www.freedesktop.org/wiki/Specifications/trash-spec) const trashFolder = '.Trash'; trashFiles = 'files'; trashInfo = 'info'; trashExt = '.trashinfo'; var sUserID: AnsiString; sTopDir, sFileName, sTemp, sNow, sHomeDir, sTrashInfoFile, sTrashDataFile: String; dtNow: TDateTime; st1, st2: Stat; function CreateTrashInfoFile: Boolean; var hFile: THandle; begin Result:= False; hFile:= mbFileCreate(sTrashInfoFile); if hFile <> feInvalidHandle then begin sTemp:= '[Trash Info]' + LineEnding; FileWrite(hFile, PChar(sTemp)[0], Length(sTemp)); sTemp:= 'Path=' + URIEncode(FileName) + LineEnding; FileWrite(hFile, PChar(sTemp)[0], Length(sTemp)); sTemp:= 'DeletionDate=' + FormatDateTime('YYYY-MM-DD', dtNow); sTemp:= sTemp + 'T' + FormatDateTime('hh:nn:ss', dtNow) + LineEnding; FileWrite(hFile, PChar(sTemp)[0], Length(sTemp)); FileClose(hFile); Result:= True; end; end; function TrashFile: Boolean; begin Result:= False; if CreateTrashInfoFile then begin Result:= (fpRename(UTF8ToSys(FileName), sTrashDataFile) >= 0); if not Result then mbDeleteFile(sTrashInfoFile); end; end; begin Result:= False; dtNow:= Now; sNow:= IntToStr(Trunc(dtNow * 86400000)); // The time in milliseconds sFileName:= ExtractOnlyFileName(FileName) + '_' + sNow + ExtractFileExt(FileName); // Get user home directory sHomeDir:= GetHomeDir; // Check if file in home directory // If it's a file, stat the parent directory instead for correct behavior on OverlayFS, // it shouldn't make any difference in other cases if (fpStat(UTF8ToSys(sHomeDir), st1) >= 0) and (fpLStat(UTF8ToSys(FileName), st2) >= 0) and (fpS_ISDIR(st2.st_mode) or (fpStat(UTF8ToSys(ExtractFileDir(FileName)), st2) >= 0)) and (st1.st_dev = st2.st_dev) then begin // Get trash directory in $XDG_DATA_HOME sTemp:= IncludeTrailingPathDelimiter(GetUserDataDir) + 'Trash'; // Create destination directories if needed if (mbForceDirectory(sTemp + PathDelim + trashFiles) and mbForceDirectory(sTemp + PathDelim + trashInfo)) then begin sTrashInfoFile:= sTemp + PathDelim + trashInfo + PathDelim + sFileName + trashExt; sTrashDataFile:= sTemp + PathDelim + trashFiles + PathDelim + sFileName; Result:= TrashFile; Exit; end; end; sUserID:= IntToStr(fpGetUID); // Get “top directory” for file sTopDir:= FindMountPointPath(FileName); // Try to use "$topdir/.Trash/$uid" directory sTemp:= sTopDir + trashFolder; if (fpLStat(UTF8ToSys(sTemp), st1) >= 0) and fpS_ISDIR(st1.st_mode) and not fpS_ISLNK(st1.st_mode) then begin sTemp:= sTemp + PathDelim + sUserID; // Create destination directories if needed if mbForceDirectory(sTemp + PathDelim + trashFiles) and mbForceDirectory(sTemp + PathDelim + trashInfo) then begin sTrashInfoFile:= sTemp + PathDelim + trashInfo + PathDelim + sFileName + trashExt; sTrashDataFile:= sTemp + PathDelim + trashFiles + PathDelim + sFileName; Result:= TrashFile; Exit; end; end; // Try to use "$topdir/.Trash-$uid" directory sTemp:= sTopDir + trashFolder + '-' + sUserID; if ((fpLStat(UTF8ToSys(sTemp), st1) >= 0) and fpS_ISDIR(st1.st_mode) and not fpS_ISLNK(st1.st_mode)) or mbCreateDir(sTemp) then begin // Create destination directories if needed if mbForceDirectory(sTemp + PathDelim + trashFiles) and mbForceDirectory(sTemp + PathDelim + trashInfo) then begin sTrashInfoFile:= sTemp + PathDelim + trashInfo + PathDelim + sFileName + trashExt; sTrashDataFile:= sTemp + PathDelim + trashFiles + PathDelim + sFileName; Result:= TrashFile; Exit; end; end; end; {$ELSE} begin Result:= False; end; {$ENDIF} function mbCheckTrash(sPath: String): Boolean; {$IF DEFINED(MSWINDOWS)} const wsRoot: WideString = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\'; var Key: HKEY; Value: DWORD; ValueSize: LongInt; VolumeName: WideString; begin Result:= False; if not mbDirectoryExists(sPath) then Exit; ValueSize:= SizeOf(DWORD); // Windows Vista/Seven if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 6) then begin VolumeName:= GetMountPointVolumeName(CeUtf8ToUtf16(ExtractFileDrive(sPath))); VolumeName:= 'Volume' + PathDelim + ExtractVolumeGUID(VolumeName); if RegOpenKeyExW(HKEY_CURRENT_USER, PWideChar(wsRoot + VolumeName), 0, KEY_READ, Key) = ERROR_SUCCESS then begin if RegQueryValueExW(Key, 'NukeOnDelete', nil, nil, @Value, @ValueSize) <> ERROR_SUCCESS then Value:= 0; // delete to trash by default Result:= (Value = 0); RegCloseKey(Key); end; end // Windows 2000/XP else if RegOpenKeyExW(HKEY_LOCAL_MACHINE, PWideChar(wsRoot), 0, KEY_READ, Key) = ERROR_SUCCESS then begin if RegQueryValueExW(Key, 'UseGlobalSettings', nil, nil, @Value, @ValueSize) <> ERROR_SUCCESS then Value:= 1; // use global settings by default if (Value = 1) then begin if RegQueryValueExW(Key, 'NukeOnDelete', nil, nil, @Value, @ValueSize) <> ERROR_SUCCESS then Value:= 0; // delete to trash by default Result:= (Value = 0); RegCloseKey(Key); end else begin RegCloseKey(Key); if RegOpenKeyExW(HKEY_LOCAL_MACHINE, PWideChar(wsRoot + sPath[1]), 0, KEY_READ, Key) = ERROR_SUCCESS then begin if RegQueryValueExW(Key, 'NukeOnDelete', nil, nil, @Value, @ValueSize) <> ERROR_SUCCESS then Value:= 0; // delete to trash by default Result:= (Value = 0); RegCloseKey(Key); end; end; end; end; {$ELSE} begin Result := True; end; {$ENDIF} initialization FileTrashUtf8:= @mbDeleteToTrash; {$IF DEFINED(DARWIN)} CoreLib := LoadLibrary('CoreServices.framework/CoreServices'); if CoreLib <> NilHandle then begin Pointer(FSMoveObjectToTrash) := GetProcedureAddress(CoreLib, 'FSMoveObjectToTrashSync'); end; {$ENDIF} end. ��������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uturbojpeg.pas��������������������������������������������������������0000755�0001750�0000144�00000012426�14743153644�020124� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uTurboJPEG; {$mode delphi} interface uses Classes, SysUtils, FPImage, Graphics, IntfGraphics; type { TDCReaderJPEGTurbo } TDCReaderJPEGTurbo = class(TFPCustomImageReader) private FGrayscale: Boolean; protected procedure InternalRead(Str: TStream; Img: TFPCustomImage); override; function InternalCheck(Str: TStream): boolean; override; end; { TJPEGTurboImage } TJPEGTurboImage = class(TJPEGImage) protected procedure InitializeReader({%H-}AImage: TLazIntfImage; {%H-}AReader: TFPCustomImageReader); override; procedure FinalizeReader({%H-}AReader: TFPCustomImageReader); override; class function GetReaderClass: TFPCustomImageReaderClass; override; end; implementation uses DynLibs, CTypes, GraphType, LCLStrConsts, DCOSUtils; const TJCS_GRAY = 2; TJSAMP_GRAY = 3; TJFLAG_ACCURATEDCT = 4096; type tjhandle = type Pointer; TJPF = ( TJPF_RGB = 0, TJPF_BGR, TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_GRAY, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB, TJPF_CMYK ); var tjInitDecompress: function(): tjhandle; cdecl; tjDestroy: function(handle: tjhandle): cint; cdecl; tjGetErrorStr2: function(handle: tjhandle): PAnsiChar; cdecl; tjDecompressHeader3: function(handle: tjhandle; jpegBuf: pcuchar; jpegSize: culong; width: pcint; height: pcint; jpegSubsamp: pcint; jpegColorspace: pcint): cint; cdecl; tjDecompress2: function(handle: tjhandle; jpegBuf: pcuchar; jpegSize: culong; dstBuf: pcuchar; width: cint; pitch: cint; height: cint; pixelFormat: cint; flags: cint): cint; cdecl; { TJPEGTurboImage } procedure TJPEGTurboImage.InitializeReader(AImage: TLazIntfImage; AReader: TFPCustomImageReader); begin end; procedure TJPEGTurboImage.FinalizeReader(AReader: TFPCustomImageReader); begin PBoolean(@GrayScale)^ := TDCReaderJPEGTurbo(AReader).FGrayScale; end; class function TJPEGTurboImage.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TDCReaderJPEGTurbo; end; { TDCReaderJPEGTurbo } procedure TDCReaderJPEGTurbo.InternalRead(Str: TStream; Img: TFPCustomImage); var AFormat: TJPF; ASize: Integer; jpegSubsamp: cint; jpegColorspace: cint; AWidth, AHeight: cint; AStream: TMemoryStream; jpegDecompressor: tjhandle; DataDescription: TRawImageDescription; begin ASize:= Str.Size; AStream:= Str as TMemoryStream; jpegDecompressor:= tjInitDecompress(); if (jpegDecompressor = nil) then raise Exception.Create(EmptyStr); try if tjDecompressHeader3(jpegDecompressor, AStream.Memory, ASize, @AWidth, @AHeight, @jpegSubsamp, @jpegColorspace) < 0 then raise Exception.Create(tjGetErrorStr2(jpegDecompressor)); FGrayscale:= (jpegColorspace = TJCS_GRAY) or (jpegSubsamp = TJSAMP_GRAY); // Get native RGBA pixel format DataDescription:= QueryDescription([riqfRGB, riqfAlpha], AWidth, AHeight); with DataDescription do begin // Library does not support reversed bits if BitOrder = riboReversedBits then begin Init_BPP32_R8G8B8A8_BIO_TTB(AWidth, AHeight); end; if ByteOrder = riboLSBFirst then begin case RedShift of 0: AFormat:= TJPF_RGBA; 8: AFormat:= TJPF_ARGB; 16: AFormat:= TJPF_BGRA; 24: AFormat:= TJPF_ABGR; end; end else begin case RedShift of 0: AFormat:= TJPF_ABGR; 8: AFormat:= TJPF_BGRA; 16: AFormat:= TJPF_ARGB; 24: AFormat:= TJPF_RGBA; end; end; end; TLazIntfImage(Img).DataDescription:= DataDescription; if tjDecompress2(jpegDecompressor, AStream.Memory, ASize, TLazIntfImage(Img).PixelData, AWidth, 0, AHeight, cint(AFormat), TJFLAG_ACCURATEDCT) < 0 then raise Exception.Create(tjGetErrorStr2(jpegDecompressor)); finally tjDestroy(jpegDecompressor); end; end; function TDCReaderJPEGTurbo.InternalCheck(Str: TStream): boolean; begin Result:= TJpegImage.IsStreamFormatSupported(Str); end; const {$IF DEFINED(MSWINDOWS)} turbolib = 'libturbojpeg.dll'; {$ELSEIF DEFINED(DARWIN)} turbolib = 'libturbojpeg.dylib'; {$ELSEIF DEFINED(UNIX)} turbolib = 'libturbojpeg.so.0'; {$ENDIF} var libturbo: TLibHandle; procedure Initialize; begin libturbo:= SafeLoadLibrary(turbolib); if (libturbo <> NilHandle) then try @tjInitDecompress:= GetProcAddress(libturbo, 'tjInitDecompress'); @tjDestroy:= SafeGetProcAddress(libturbo, 'tjDestroy'); @tjGetErrorStr2:= SafeGetProcAddress(libturbo, 'tjGetErrorStr2'); @tjDecompressHeader3:= SafeGetProcAddress(libturbo, 'tjDecompressHeader3'); @tjDecompress2:= SafeGetProcAddress(libturbo, 'tjDecompress2'); // Replace image handler GraphicFilter(TJPEGImage); TPicture.UnregisterGraphicClass(TJPEGImage); TPicture.RegisterFileFormat(TJpegImage.GetFileExtensions, rsJpeg, TJPEGTurboImage); except // Skip end; end; initialization Initialize; finalization if (libturbo <> NilHandle) then FreeLibrary(libturbo); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/uuniqueinstance.pas���������������������������������������������������0000644�0001750�0000144�00000027025�14743153644�021154� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uUniqueInstance; {$mode objfpc}{$H+} interface uses Classes, SysUtils, SimpleIPC, uCmdLineParams; type TOnUniqueInstanceMessage = procedure (Sender: TObject; Params: TCommandLineParams) of object; { TUniqueInstance } TUniqueInstance = class private FHandle: THandle; FInstanceName: String; FServerIPC: TSimpleIPCServer; FClientIPC: TSimpleIPCClient; FOnMessage: TOnUniqueInstanceMessage; FServernameByUser: String; {$IF DEFINED(UNIX)} FMyProgramCreateSemaphore:Boolean; {$ENDIF} procedure OnNative(Sender: TObject); procedure OnMessageQueued(Sender: TObject); procedure CreateServer; procedure CreateClient; function IsRunning: Boolean; procedure DisposeMutex; public constructor Create(aInstanceName: String; aServernameByUser: String); destructor Destroy; override; function IsRunInstance: Boolean; procedure SendParams; procedure RunListen; procedure StopListen; function isAnotherDCRunningWhileIamRunning:boolean; property OnMessage: TOnUniqueInstanceMessage read FOnMessage write FOnMessage; property ServernameByUser: String read FServernameByUser; end; procedure InitInstance; procedure InitInstanceWithName(aInstanceName: String; aServernameByUser: String); function IsUniqueInstance: Boolean; function WantsToBeClient: Boolean; {en Returns @true if current application instance is allowed to run. Returns @false if current instance should not be run. } function IsInstanceAllowed: Boolean; var UniqueInstance: TUniqueInstance = nil; FIsUniqueInstance: Boolean = False; implementation uses {$IF DEFINED(MSWINDOWS)} Windows, {$ELSEIF DEFINED(UNIX)} ipc, baseunix, uPipeServer, {$ENDIF} Forms, StrUtils, FileUtil, uRegExprA, uGlobs, uDebug; {$IF DEFINED(DARWIN)} const SEM_GETVAL = 5; // Return the value of semval (READ) SEM_SETVAL = 8; // Set the value of semval to arg.val (ALTER) {$ENDIF} { TUniqueInstance } procedure TUniqueInstance.OnNative(Sender: TObject); var Params: TCommandLineParams; begin if Assigned(FOnMessage) then begin FServerIPC.MsgData.Seek(0, soFromBeginning); FServerIPC.MsgData.ReadBuffer(Params, FServerIPC.MsgType); FOnMessage(Self, Params); end; end; procedure TUniqueInstance.OnMessageQueued(Sender: TObject); begin {$IF (FPC_FULLVERSION >= 030001)} FServerIPC.ReadMessage; {$ENDIF} end; procedure TUniqueInstance.CreateServer; begin if FServerIPC = nil then begin FServerIPC:= TSimpleIPCServer.Create(nil); FServerIPC.OnMessage:= @OnNative; {$IF DEFINED(MSWINDOWS) and (FPC_FULLVERSION >= 030001)} FServerIPC.OnMessageQueued:= @OnMessageQueued; {$ENDIF} end; if FClientIPC <> nil then FreeAndNil(FClientIPC); end; procedure TUniqueInstance.CreateClient; begin if FClientIPC = nil then FClientIPC:= TSimpleIPCClient.Create(nil); end; function TUniqueInstance.IsRunning: Boolean; {$IF DEFINED(MSWINDOWS)} var MutexName: AnsiString; begin Result:= False; MutexName:= ExtractFileName(ParamStr(0)); FHandle:= OpenMutex(MUTEX_MODIFY_STATE, False, PAnsiChar(MutexName)); if FHandle = 0 then FHandle:= CreateMutex(nil, True, PAnsiChar(MutexName)) else begin if WaitForSingleObject(FHandle, 0) <> WAIT_ABANDONED then Result:= True; end; end; {$ELSEIF DEFINED(UNIX)} const SEM_PERM = 6 shl 6 { 0600 }; var semkey: TKey; status: longint = 0; arg: tsemun; function id: byte; var UserID: LongRec; begin Result := 0; UserID := LongRec(fpGetUID); Result := Result xor UserID.Bytes[0]; Result := Result xor UserID.Bytes[1]; Result := Result xor UserID.Bytes[2]; Result := Result xor UserID.Bytes[3]; end; function semlock(semid: longint): boolean; // increase special Value in semaphore structure (value decreases automatically // when program completed incorrectly) var p_buf: tsembuf; begin p_buf.sem_num := 0; p_buf.sem_op := 1; p_buf.sem_flg := SEM_UNDO; Result:= semop(semid, @p_buf, 1) = 0; end; begin Result := False; semkey := ftok(PAnsiChar(ParamStr(0)), id); // try create semapore for semkey // If semflg specifies both IPC_CREAT and IPC_EXCL and a semaphore set already // exists for semkey, then semget() return -1 and errno set to EEXIST FHandle := semget(semkey, 1, SEM_PERM or IPC_CREAT or IPC_EXCL); // if semaphore exists if FHandle = -1 then begin // get semaphore id FHandle := semget(semkey, 1, 0); // get special Value from semaphore structure status := semctl(FHandle, 0, SEM_GETVAL, arg); if status = 1 then // There is other running copy of the program begin Result := True; // Not to release semaphore when exiting from the program FMyProgramCreateSemaphore := false; end else begin // Other copy of the program has created a semaphore but has been completed incorrectly // increase special Value in semaphore structure (value decreases automatically // when program completed incorrectly) semlock(FHandle); // its one copy of program running, release semaphore when exiting from the program FMyProgramCreateSemaphore := true; end; end else begin // its one copy of program running, release semaphore when exiting from the program FMyProgramCreateSemaphore := true; // set special Value in semaphore structure to 0 arg.val := 0; status := semctl(FHandle, 0, SEM_SETVAL, arg); // increase special Value in semaphore structure (value decreases automatically // when program completed incorrectly) semlock(FHandle); end; end; {$ENDIF} procedure TUniqueInstance.DisposeMutex; {$IF DEFINED(MSWINDOWS)} begin ReleaseMutex(FHandle); end; {$ELSEIF DEFINED(UNIX)} var arg: tsemun; begin // If my copy of the program created a semaphore then released it if FMyProgramCreateSemaphore then semctl(FHandle, 0, IPC_RMID, arg); end; {$ENDIF} function TUniqueInstance.IsRunInstance: Boolean; begin CreateClient; FClientIPC.ServerID:= FInstanceName; Result:= IsRunning and FClientIPC.ServerRunning; end; procedure TUniqueInstance.SendParams; var Stream: TMemoryStream = nil; begin CreateClient; FClientIPC.ServerID:= FInstanceName; if not FClientIPC.ServerRunning then Exit; Stream:= TMemoryStream.Create; Stream.WriteBuffer(CommandLineParams, SizeOf(TCommandLineParams)); try FClientIPC.Connect; Stream.Seek(0, soFromBeginning); FClientIPC.SendMessage(SizeOf(TCommandLineParams), Stream); finally Stream.Free; FClientIPC.Disconnect; end; end; procedure TUniqueInstance.RunListen; begin CreateServer; FServerIPC.ServerID:= FInstanceName; FServerIPC.Global:= True; FServerIPC.StartServer; end; procedure TUniqueInstance.StopListen; begin DisposeMutex; if FServerIPC = nil then Exit; FServerIPC.StopServer; end; function TUniqueInstance.isAnotherDCRunningWhileIamRunning:boolean; var LocalClientIPC: TSimpleIPCClient; IndexInstance:integer; function GetServerIdNameToCheck:string; begin Result:= ApplicationName; if IndexInstance > 1 then Result+= '-' + IntToStr(IndexInstance); {$IF DEFINED(UNIX)} Result:= GetPipeFileName(Result, True); {$ENDIF} end; begin Result:=True; if IsRunning then begin FServerIPC.Active:=False; try LocalClientIPC:=TSimpleIPCClient.Create(nil); try IndexInstance:=1; Result:=FALSE; repeat LocalClientIPC.ServerID:=GetServerIdNameToCheck; Result:=LocalClientIPC.ServerRunning; inc(IndexInstance); until Result OR (IndexInstance>=10); finally FreeAndNil(LocalClientIPC); end; finally FServerIPC.Active:=True; end; end; end; constructor TUniqueInstance.Create(aInstanceName: String; aServernameByUser: String); begin FInstanceName:= aInstanceName; FServernameByUser:= aServernameByUser; if Length(FServernameByUser) > 0 then FInstanceName+= '-' + FServernameByUser; {$IF DEFINED(UNIX)} FInstanceName:= GetPipeFileName(FInstanceName, True); {$ENDIF} end; destructor TUniqueInstance.Destroy; begin if Assigned(FClientIPC) then FreeAndNil(FClientIPC); if Assigned(FServerIPC) then FreeAndNil(FServerIPC); inherited Destroy; end; {en Initializes instance with given name (currently this is ApplicationName), and user-provided servername (typically, an empty string). If there is no already existing instance, then create it. If there is already existing instance, and the current one is a client, then send params to the server (i.e. to the existing instance) If there is already existing instance, and the current one is not a client, (i.e. gOnlyOneAppInstance is false and no --client/-c options were given), then user-provided servername is altered: firstly, just add a trailing number '2'. If there is already some trailing number, then increase it by 1, until we found a servername that isn't busy yet, and then create instance with this servername. } procedure InitInstanceWithName(aInstanceName: String; aServernameByUser: String); {en If a given servername doesn't contain a trailing number, then add a trailing number '2'; otherwise increase existing number and return resulting string. } function GetNextServername(CurServername: String): String; var SNameRegExp: TRegExpr; CurNumber: Integer; begin SNameRegExp := TRegExpr.Create(); try SNameRegExp.Expression := '(\d+)$'; if SNameRegExp.Exec(CurServername) then begin //-- there is existing trailing number, so, increase it by 1 CurNumber := StrToInt(SNameRegExp.Match[1]) + 1; Result := ReplaceRegExpr(SNameRegExp.Expression, CurServername, IntToStr(CurNumber), False); end else //-- there is no trailing number, so, add a trailing number '2' Result := CurServername + '2'; finally SNameRegExp.Free; end; end; begin FIsUniqueInstance := True; //-- determine if the instance with the same name already exists UniqueInstance := TUniqueInstance.Create(aInstanceName, aServernameByUser); if UniqueInstance.IsRunInstance then //-- it does exist, so, set flag that instance is not unique FIsUniqueInstance := False; //-- if instance is allowed (i.e. is not a client), then find unique // servername if IsInstanceAllowed then begin while UniqueInstance.IsRunInstance do begin UniqueInstance.Free; aServernameByUser := GetNextServername(aServernameByUser); UniqueInstance := TUniqueInstance.Create(aInstanceName, aServernameByUser); end; //-- unique servername is found, so, run it as a server and set // FIsUniqueInstance flag UniqueInstance.RunListen; FIsUniqueInstance := True end else //-- if this instance is not allowed (i.e. it's a client), then send params to the server. UniqueInstance.SendParams; end; {en Initialize instance with an application name and user-provided servername (see detailed comment for InitInstanceWithName) } procedure InitInstance; begin InitInstanceWithName(ApplicationName, CommandLineParams.Servername); end; function IsUniqueInstance: Boolean; begin Result := FIsUniqueInstance; end; function WantsToBeClient: Boolean; begin Result := (gOnlyOneAppInstance or CommandLineParams.Client); end; function IsInstanceAllowed: Boolean; begin Result := (not WantsToBeClient) or IsUniqueInstance; end; finalization if Assigned(UniqueInstance) then begin UniqueInstance.StopListen; FreeAndNil(UniqueInstance); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�016016� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/uTotalCommander.pas�����������������������������������������������0000644�0001750�0000144�00000317213�14743153644�021630� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Total Commander integration functions Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } { Equivalence of some abbreviation here: TC = Total Commander DC = Double Commander } unit uTotalCommander; {$MODE DELPHI} interface uses //Lazarus, Free-Pascal, etc. Windows, Classes, //DC DCXmlConfig, uFormCommands, KASToolItems, KASToolBar; const TCCONFIG_MAINBAR_NOTPRESENT = ':-<#/?*+*?\#>-:'; TCCONFIG_BUTTONBAR_SECTION = 'Buttonbar'; TCCONFIG_BUTTONBAR_COUNT = 'Buttoncount'; TCCONFIG_DEFAULTBAR_FILENAME = 'DEFAULT.bar'; TCCONFIG_BUTTONHEIGHT = 'Buttonheight'; TCCONFIG_BUTTON_PREFIX = 'button'; TCCONFIG_ICONIC_PREFIX = 'iconic'; TCCONFIG_CMD_PREFIX = 'cmd'; TCCONFIG_STARTINGPATH_PREFIX = 'path'; TCCONFIG_HINT_PREFIX = 'menu'; TCCONFIG_PARAM_PREFIX = 'param'; var sTotalCommanderMainbarFilename: string = TCCONFIG_MAINBAR_NOTPRESENT; function ConvertTCStringToString(TCString: ansistring): string; function ConvertStringToTCString(sString: string): ansistring; function ReplaceDCEnvVars(const sText: string): string; function ReplaceTCEnvVars(const sText: string): string; function areWeInSituationToPlayWithTCFiles: boolean; function GetActualTCIni(NormalizedTCIniFilename, SectionName: String): String; function GetTCEquivalentCommandToDCCommand(DCCommand: string; var TCIndexOfCommand: integer): string; function GetTCIconFromDCIconAndCreateIfNecessary(const DCIcon: string): string; function GetTCEquivalentCommandIconToDCCommandIcon(DCIcon: string; TCIndexOfCommand: integer): string; procedure ExportDCToolbarsToTC(Toolbar: TKASToolbar; Barfilename: string; FlushExistingContent, FlagNeedToUpdateConfigIni: boolean); procedure ConvertTCToolbarToDCXmlConfig(sTCBarFilename: string; ADCXmlConfig:TXmlConfig); implementation uses //Lazarus, Free-Pascal, etc. Graphics, LCLVersion, Forms, SysUtils, LCLProc, LazUTF8, //DC fOptionsMisc, uKASToolItemsExtended, DCClassesUtf8, DCOSUtils, DCStrUtils, uPixMapManager, uShowMsg, uDCUtils, uLng, uGlobs, uGlobsPaths, DCConvertEncoding, uMyWindows; type { TTCommandEquivalence } TTCommandEquivalence = record TCCommand: string; TCIcon: longint; DCCommand: string; DCParameters: string; end; const NUMBEROFCOMMANDS = 465; //jcf:format=off COMMANDS_LIST_TC: array[1..NUMBEROFCOMMANDS] of TTCommandEquivalence = ( (TCCommand: 'cm_SrcComments'; TCIcon: 21; DCCommand: ''; DCParameters: '' ), //Source: Show comments (TCCommand: 'cm_SrcShort'; TCIcon: 3; DCCommand: 'cm_BriefView'; DCParameters: '' ), //Source: Only file names (TCCommand: 'cm_SrcLong'; TCIcon: 4; DCCommand: 'cm_ColumnsView'; DCParameters: '' ), //Source: All file details (TCCommand: 'cm_SrcTree'; TCIcon: 2; DCCommand: ''; DCParameters: '' ), //Source: Directory tree (TCCommand: 'cm_SrcQuickview'; TCIcon: 22; DCCommand: 'cm_QuickView'; DCParameters: '' ), //Source: Quick view panel (TCCommand: 'cm_VerticalPanels'; TCIcon: 23; DCCommand: 'cm_HorizontalFilePanels'; DCParameters: '' ), //File windows above each other (TCCommand: 'cm_SrcQuickInternalOnly'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Source: Quick view, no plugins (TCCommand: 'cm_SrcHideQuickview'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Source: Quick view panel off (TCCommand: 'cm_SrcExecs'; TCIcon: 12; DCCommand: ''; DCParameters: '' ), //Source: Only programs (TCCommand: 'cm_SrcAllFiles'; TCIcon: 13; DCCommand: ''; DCParameters: '' ), //Source: All files (TCCommand: 'cm_SrcUserSpec'; TCIcon: 24; DCCommand: ''; DCParameters: '' ), //Source: Last selected (TCCommand: 'cm_SrcUserDef'; TCIcon: 25; DCCommand: ''; DCParameters: '' ), //Source: Select user type (TCCommand: 'cm_SrcByName'; TCIcon: 5; DCCommand: 'cm_SortByName'; DCParameters: '' ), //Source: Sort by name (TCCommand: 'cm_SrcByExt'; TCIcon: 6; DCCommand: 'cm_SortByExt'; DCParameters: '' ), //Source: Sort by extension (TCCommand: 'cm_SrcBySize'; TCIcon: 8; DCCommand: 'cm_SortBySize'; DCParameters: '' ), //Source: Sort by size (TCCommand: 'cm_SrcByDateTime'; TCIcon: 7; DCCommand: 'cm_SortByDate'; DCParameters: '' ), //Source: Sort by date (TCCommand: 'cm_SrcUnsorted'; TCIcon: 9; DCCommand: ''; DCParameters: '' ), //Source: Unsorted (TCCommand: 'cm_SrcNegOrder'; TCIcon: 10; DCCommand: 'cm_ReverseOrder'; DCParameters: '' ), //Source: Reversed order (TCCommand: 'cm_SrcOpenDrives'; TCIcon: -1; DCCommand: 'cm_SrcOpenDrives'; DCParameters: '' ), //Source: Open drive list (TCCommand: 'cm_SrcThumbs'; TCIcon: 26; DCCommand: 'cm_ThumbnailsView'; DCParameters: '' ), //Source: Thumbnail view (TCCommand: 'cm_SrcCustomViewMenu'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), //Source: Custom view menu (TCCommand: 'cm_SrcPathFocus'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Source: Put focus on path (TCCommand: 'cm_LeftComments'; TCIcon: 21; DCCommand: ''; DCParameters: '' ), //Left: Show comments (TCCommand: 'cm_LeftShort'; TCIcon: 3; DCCommand: 'cm_LeftBriefView'; DCParameters: '' ), //Left: Only file names (TCCommand: 'cm_LeftLong'; TCIcon: 4; DCCommand: 'cm_LeftColumnsView'; DCParameters: '' ), //Left: All file details (TCCommand: 'cm_LeftTree'; TCIcon: 2; DCCommand: ''; DCParameters: '' ), //Left: Directory tree (TCCommand: 'cm_LeftQuickview'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Left: Quick view panel (TCCommand: 'cm_LeftQuickInternalOnly'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Left: Quick view, no plugins (TCCommand: 'cm_LeftHideQuickview'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Left: Quick view panel off (TCCommand: 'cm_LeftExecs'; TCIcon: 12; DCCommand: ''; DCParameters: '' ), //Left: Only programs (TCCommand: 'cm_LeftAllFiles'; TCIcon: 13; DCCommand: ''; DCParameters: '' ), //Left: All files (TCCommand: 'cm_LeftUserSpec'; TCIcon: 24; DCCommand: ''; DCParameters: '' ), //Left: Last selected (TCCommand: 'cm_LeftUserDef'; TCIcon: 25; DCCommand: ''; DCParameters: '' ), //Left: Select user type (TCCommand: 'cm_LeftByName'; TCIcon: 5; DCCommand: 'cm_LeftSortByName'; DCParameters: '' ), //Left: Sort by name (TCCommand: 'cm_LeftByExt'; TCIcon: 6; DCCommand: 'cm_LeftSortByExt'; DCParameters: '' ), //Left: Sort by extension (TCCommand: 'cm_LeftBySize'; TCIcon: 8; DCCommand: 'cm_LeftSortBySize'; DCParameters: '' ), //Left: Sort by size (TCCommand: 'cm_LeftByDateTime'; TCIcon: 7; DCCommand: 'cm_LeftSortByDate'; DCParameters: '' ), //Left: Sort by date (TCCommand: 'cm_LeftUnsorted'; TCIcon: 9; DCCommand: ''; DCParameters: '' ), //Left: Unsorted (TCCommand: 'cm_LeftNegOrder'; TCIcon: 10; DCCommand: 'cm_LeftReverseOrder'; DCParameters: '' ), //Left: Reversed order (TCCommand: 'cm_LeftOpenDrives'; TCIcon: -1; DCCommand: 'cm_LeftOpenDrives'; DCParameters: '' ), //Left: Open drive list (TCCommand: 'cm_LeftPathFocus'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Left: Put focus on path (TCCommand: 'cm_LeftDirBranch'; TCIcon: 50; DCCommand: 'cm_LeftFlatView'; DCParameters: '' ), //Left: Branch view (TCCommand: 'cm_LeftDirBranchSel'; TCIcon: 50; DCCommand: ''; DCParameters: '' ), //Left: branch view, only selected (TCCommand: 'cm_LeftThumbs'; TCIcon: 26; DCCommand: 'cm_LeftThumbView'; DCParameters: '' ), //Left: Thumbnail view (TCCommand: 'cm_LeftCustomViewMenu'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), //Left: Custom view menu (TCCommand: 'cm_RightComments'; TCIcon: 21; DCCommand: ''; DCParameters: '' ), //Right: Show comments (TCCommand: 'cm_RightShort'; TCIcon: 3; DCCommand: 'cm_RightBriefView'; DCParameters: '' ), //Right: Only file names (TCCommand: 'cm_RightLong'; TCIcon: 4; DCCommand: 'cm_RightColumnsView'; DCParameters: '' ), //Right: All file details (TCCommand: 'cm_RightTree'; TCIcon: 2; DCCommand: ''; DCParameters: '' ), //Right: Directory tree (TCCommand: 'cm_RightQuickview'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Right: Quick view panel (TCCommand: 'cm_RightQuickInternalOnly'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Right: Quick view, no plugins (TCCommand: 'cm_RightHideQuickview'; TCIcon: 22; DCCommand: ''; DCParameters: '' ), //Right: Quick view panel off (TCCommand: 'cm_RightExecs'; TCIcon: 12; DCCommand: ''; DCParameters: '' ), //Right: Only programs (TCCommand: 'cm_RightAllFiles'; TCIcon: 13; DCCommand: ''; DCParameters: '' ), //Right: All files (TCCommand: 'cm_RightUserSpec'; TCIcon: 24; DCCommand: ''; DCParameters: '' ), //Right: Last selected (TCCommand: 'cm_RightUserDef'; TCIcon: 25; DCCommand: ''; DCParameters: '' ), //Right: Select user type (TCCommand: 'cm_RightByName'; TCIcon: 5; DCCommand: ''; DCParameters: '' ), //Right: Sort by name (TCCommand: 'cm_RightByExt'; TCIcon: 6; DCCommand: 'cm_RightSortByName'; DCParameters: '' ), //Right: Sort by extension (TCCommand: 'cm_RightBySize'; TCIcon: 8; DCCommand: 'cm_RightSortByExt'; DCParameters: '' ), //Right: Sort by size (TCCommand: 'cm_RightByDateTime'; TCIcon: 7; DCCommand: 'cm_RightSortBySize'; DCParameters: '' ), //Right: Sort by date (TCCommand: 'cm_RightUnsorted'; TCIcon: 9; DCCommand: 'cm_RightSortByDate'; DCParameters: '' ), //Right: Unsorted (TCCommand: 'cm_RightNegOrder'; TCIcon: 10; DCCommand: 'cm_RightReverseOrder'; DCParameters: '' ), //Right: Reversed order (TCCommand: 'cm_RightOpenDrives'; TCIcon: -1; DCCommand: 'cm_RightOpenDrives'; DCParameters: '' ), //Right: Open drive list (TCCommand: 'cm_RightPathFocus'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Right: Put focus on path (TCCommand: 'cm_RightDirBranch'; TCIcon: 50; DCCommand: 'cm_RightFlatView'; DCParameters: '' ), //Right: branch view (TCCommand: 'cm_RightDirBranchSel'; TCIcon: 50; DCCommand: ''; DCParameters: '' ), //Right: branch view, only selected (TCCommand: 'cm_RightThumbs'; TCIcon: 26; DCCommand: 'cm_RightThumbView'; DCParameters: '' ), //Right: Thumbnail view (TCCommand: 'cm_RightCustomViewMenu'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), //Right: Custom view menu (TCCommand: 'cm_List'; TCIcon: 27; DCCommand: 'cm_View'; DCParameters: '' ), //View with Lister (TCCommand: 'cm_ListInternalOnly'; TCIcon: 27; DCCommand: 'cm_view'; DCParameters: '' ), //Lister without plugins/multimedia (TCCommand: 'cm_Edit'; TCIcon: 28; DCCommand: 'cm_Edit'; DCParameters: '' ), //Edit (Notepad) (TCCommand: 'cm_Copy'; TCIcon: 62; DCCommand: 'cm_Copy'; DCParameters: '' ), //Copy files (TCCommand: 'cm_CopySamepanel'; TCIcon: 62; DCCommand: 'cm_CopySamePanel'; DCParameters: '' ), //Copy within panel (TCCommand: 'cm_CopyOtherpanel'; TCIcon: 62; DCCommand: ''; DCParameters: '' ), //Copy to other (TCCommand: 'cm_RenMov'; TCIcon: 63; DCCommand: 'cm_Rename'; DCParameters: '' ), //Rename/Move files (TCCommand: 'cm_MkDir'; TCIcon: 29; DCCommand: 'cm_MakeDir'; DCParameters: '' ), //Make directory (TCCommand: 'cm_Delete'; TCIcon: 64; DCCommand: 'cm_Delete'; DCParameters: '' ), //Delete files (TCCommand: 'cm_TestArchive'; TCIcon: 60; DCCommand: 'cm_TestArchive'; DCParameters: '' ), //Test selected archives (TCCommand: 'cm_PackFiles'; TCIcon: 30; DCCommand: 'cm_PackFiles'; DCParameters: '' ), //Pack files (TCCommand: 'cm_UnpackFiles'; TCIcon: 31; DCCommand: 'cm_ExtractFiles'; DCParameters: '' ), //Unpack all (TCCommand: 'cm_RenameOnly'; TCIcon: 32; DCCommand: 'cm_RenameOnly'; DCParameters: '' ), //Rename (Shift+F6) (TCCommand: 'cm_RenameSingleFile'; TCIcon: 32; DCCommand: 'cm_RenameOnly'; DCParameters: '' ), //Rename file under cursor (TCCommand: 'cm_MoveOnly'; TCIcon: 63; DCCommand: ''; DCParameters: '' ), //Move (F6) (TCCommand: 'cm_Properties'; TCIcon: -1; DCCommand: 'cm_FileProperties'; DCParameters: '' ), //Properties dialog (TCCommand: 'cm_CreateShortcut'; TCIcon: 65; DCCommand: ''; DCParameters: '' ), //Create a shortcut (TCCommand: 'cm_Return'; TCIcon: -1; DCCommand: 'cm_Open'; DCParameters: '' ), //Simulate: Return pressed (TCCommand: 'cm_OpenAsUser'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Open program under cursor as different user (TCCommand: 'cm_Split'; TCIcon: 68; DCCommand: 'cm_FileSpliter'; DCParameters: '' ), //Split file into pieces (TCCommand: 'cm_Combine'; TCIcon: 69; DCCommand: 'cm_FileLinker'; DCParameters: '' ), //Combine partial files (TCCommand: 'cm_Encode'; TCIcon: 66; DCCommand: ''; DCParameters: '' ), //Encode MIME/UUE/XXE (TCCommand: 'cm_Decode'; TCIcon: 67; DCCommand: ''; DCParameters: '' ), //Decode MIME/UUE/XXE/BinHex (TCCommand: 'cm_CRCcreate'; TCIcon: -1; DCCommand: 'cm_CheckSumCalc'; DCParameters: '' ), //Create CRC checksums (TCCommand: 'cm_CRCcheck'; TCIcon: 61; DCCommand: 'cm_CheckSumVerify'; DCParameters: '' ), //Verify CRC checksums (TCCommand: 'cm_SetAttrib'; TCIcon: 33; DCCommand: 'cm_SetFileProperties'; DCParameters: '' ), //Change attributes (TCCommand: 'cm_Config'; TCIcon: 34; DCCommand: 'cm_Options'; DCParameters: '' ), //Conf: Layout (first page) (TCCommand: 'cm_DisplayConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Display (TCCommand: 'cm_IconConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Icons (TCCommand: 'cm_FontConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Font (TCCommand: 'cm_ColorConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Colors (TCCommand: 'cm_ConfTabChange'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Tabstops (TCCommand: 'cm_DirTabsConfig'; TCIcon: 34; DCCommand: 'cm_ConfigFolderTabs'; DCParameters: '' ), //Conf: Directory tabs (TCCommand: 'cm_CustomColumnConfig'; TCIcon: 56; DCCommand: ''; DCParameters: '' ), //Conf: Custom colums (TCCommand: 'cm_CustomColumnDlg'; TCIcon: 56; DCCommand: ''; DCParameters: '' ), //Change current custom columns (TCCommand: 'cm_LanguageConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Language (TCCommand: 'cm_Config2'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Operation (TCCommand: 'cm_EditConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Viewer/Editor (TCCommand: 'cm_CopyConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Copy/Delete (TCCommand: 'cm_RefreshConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Refresh file lists (TCCommand: 'cm_QuickSearchConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Quick Search (TCCommand: 'cm_FtpConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //FTP options (TCCommand: 'cm_PluginsConfig'; TCIcon: 34; DCCommand: 'cm_ConfigPlugins'; DCParameters: '' ), //Conf: Plugins (TCCommand: 'cm_ThumbnailsConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Thumbnails (TCCommand: 'cm_LogConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Log file (TCCommand: 'cm_IgnoreConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Ignore list (TCCommand: 'cm_PackerConfig'; TCIcon: 34; DCCommand: 'cm_ConfigArchivers'; DCParameters: '' ), //Conf: Packer (TCCommand: 'cm_ZipPackerConfig'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: ZIP packer (TCCommand: 'cm_Confirmation'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Conf: Misc, Confirmation (TCCommand: 'cm_ConfigSavePos'; TCIcon: -1; DCCommand: 'cm_ConfigSavePos'; DCParameters: '' ), //Conf: Save position (TCCommand: 'cm_ButtonConfig'; TCIcon: 14; DCCommand: 'cm_ConfigToolbars'; DCParameters: '' ), //Conf: Button bar (TCCommand: 'cm_ConfigSaveSettings'; TCIcon: -1; DCCommand: 'cm_ConfigSaveSettings'; DCParameters: '' ), //Save current paths etc. (TCCommand: 'cm_ConfigChangeIniFiles'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Open ini files in notepad (TCCommand: 'cm_ConfigSaveDirHistory'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Save directory history (TCCommand: 'cm_ChangeStartMenu'; TCIcon: 34; DCCommand: ''; DCParameters: '' ), //Change Start menu (TCCommand: 'cm_NetConnect'; TCIcon: 53; DCCommand: 'cm_NetworkConnect'; DCParameters: '' ), //Network connections (TCCommand: 'cm_NetDisconnect'; TCIcon: 54; DCCommand: 'cm_NetworkDisconnect'; DCParameters: '' ), //Disconnect network drives (TCCommand: 'cm_NetShareDir'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Share directory (TCCommand: 'cm_NetUnshareDir'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Unshare directory (TCCommand: 'cm_AdministerServer'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Connect to admin share to open \\server\c$ etc. (TCCommand: 'cm_ShowFileUser'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Which remote user has opened a local file (TCCommand: 'cm_GetFileSpace'; TCIcon: -1; DCCommand: 'cm_CalculateSpace'; DCParameters: '' ), //Calculate space (TCCommand: 'cm_VolumeId'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Volume label (TCCommand: 'cm_VersionInfo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Version information (TCCommand: 'cm_ExecuteDOS'; TCIcon: -1; DCCommand: 'cm_RunTerm'; DCParameters: '' ), //Open command prompt window (TCCommand: 'cm_CompareDirs'; TCIcon: 35; DCCommand: 'cm_CompareDirectories'; DCParameters: '' ), //Compare dirs (TCCommand: 'cm_CompareDirsWithSubdirs'; TCIcon: 35; DCCommand: 'cm_CompareDirectories'; DCParameters: 'directories=on'), //Also mark subdirs not present in other dir (TCCommand: 'cm_ContextMenu'; TCIcon: -1; DCCommand: 'cm_ContextMenu'; DCParameters: '' ), //Show context menu (TCCommand: 'cm_ContextMenuInternal'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show context menu for internal associations (TCCommand: 'cm_ContextMenuInternalCursor'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Internal context menu for file under cursor (TCCommand: 'cm_ShowRemoteMenu'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Context menu for Media Center remote control Play/Pause (TCCommand: 'cm_SyncChangeDir'; TCIcon: 75; DCCommand: 'cm_SyncChangeDir'; DCParameters: '' ), //Synchronous directory changing in both windows (TCCommand: 'cm_EditComment'; TCIcon: -1; DCCommand: 'cm_EditComment'; DCParameters: '' ), //Edit file comment (TCCommand: 'cm_FocusLeft'; TCIcon: -1; DCCommand: 'cm_FocusSwap'; DCParameters: 'side=left' ), //Focus on left file list (TCCommand: 'cm_FocusRight'; TCIcon: -1; DCCommand: 'cm_FocusSwap'; DCParameters: 'side=right'), //Focus on right file list (TCCommand: 'cm_FocusCmdLine'; TCIcon: -1; DCCommand: 'cm_FocusCmdLine'; DCParameters: '' ), //Focus on command line (TCCommand: 'cm_FocusButtonBar'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Focus on button bar (TCCommand: 'cm_CountDirContent'; TCIcon: 36; DCCommand: 'cm_CountDirContent'; DCParameters: '' ), //Calculate space occupied by subdirs in current dir (TCCommand: 'cm_UnloadPlugins'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Unload all plugins (TCCommand: 'cm_DirMatch'; TCIcon: 35; DCCommand: ''; DCParameters: '' ), //Mark newer (TCCommand: 'cm_Exchange'; TCIcon: 37; DCCommand: 'cm_Exchange'; DCParameters: '' ), //Swap panels (TCCommand: 'cm_MatchSrc'; TCIcon: 86; DCCommand: 'cm_TargetEqualSource'; DCParameters: '' ), //target=Source (TCCommand: 'cm_ReloadSelThumbs'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Re-load selected thumbnails (TCCommand: 'cm_DirectCableConnect'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Connect to other PC by cable (TCCommand: 'cm_NTinstallDriver'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Install parallel port driver on NT (TCCommand: 'cm_NTremoveDriver'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Remove parallel port driver on NT (TCCommand: 'cm_PrintDir'; TCIcon: 38; DCCommand: ''; DCParameters: '' ), //Print current directory (with preview) (TCCommand: 'cm_PrintDirSub'; TCIcon: 38; DCCommand: ''; DCParameters: '' ), //Print dir with subdirs (TCCommand: 'cm_PrintFile'; TCIcon: 38; DCCommand: ''; DCParameters: '' ), //Print file (TCCommand: 'cm_SpreadSelection'; TCIcon: 39; DCCommand: 'cm_MarkPlus'; DCParameters: '' ), //Select group (TCCommand: 'cm_SelectBoth'; TCIcon: 72; DCCommand: 'cm_MarkPlus'; DCParameters: 'attr=' ), //Select group: files+folders (TCCommand: 'cm_SelectFiles'; TCIcon: 70; DCCommand: 'cm_MarkPlus'; DCParameters: 'attr=d-' ), //Select group: just files (TCCommand: 'cm_SelectFolders'; TCIcon: 71; DCCommand: 'cm_MarkPlus'; DCParameters: 'attr=d+' ), //Select group: just folders (TCCommand: 'cm_ShrinkSelection'; TCIcon: 40; DCCommand: 'cm_MarkMinus'; DCParameters: 'attr=' ), //Unselect group (TCCommand: 'cm_ClearFiles'; TCIcon: 40; DCCommand: 'cm_MarkMinus'; DCParameters: 'attr=d+' ), //Unselect group: just files (TCCommand: 'cm_ClearFolders'; TCIcon: 40; DCCommand: 'cm_MarkMinus'; DCParameters: 'attr=d-' ), //Unselect group: just folders (TCCommand: 'cm_ClearSelCfg'; TCIcon: 40; DCCommand: 'cm_MarkMinus'; DCParameters: '' ), //Unselect group (files or both, as configured) (TCCommand: 'cm_SelectAll'; TCIcon: 44; DCCommand: 'cm_MarkMarkAll'; DCParameters: '' ), //Select all (files or both, as configured) (TCCommand: 'cm_SelectAllBoth'; TCIcon: 44; DCCommand: 'cm_MarkMarkAll'; DCParameters: 'attr=' ), //Select both files+folders (TCCommand: 'cm_SelectAllFiles'; TCIcon: 44; DCCommand: 'cm_MarkMarkAll'; DCParameters: 'attr=d-' ), //Select all files (TCCommand: 'cm_SelectAllFolders'; TCIcon: 44; DCCommand: 'cm_MarkMarkAll'; DCParameters: 'attr=d+' ), //Select all folders (TCCommand: 'cm_ClearAll'; TCIcon: -1; DCCommand: 'cm_MarkUnmarkAll'; DCParameters: 'attr=' ), //Unselect all (files+folders) (TCCommand: 'cm_ClearAllFiles'; TCIcon: -1; DCCommand: 'cm_MarkUnmarkAll'; DCParameters: 'attr=d-' ), //Unselect all files (TCCommand: 'cm_ClearAllFolders'; TCIcon: -1; DCCommand: 'cm_MarkUnmarkAll'; DCParameters: 'attr=d+' ), //Unselect all folders (TCCommand: 'cm_ClearAllCfg'; TCIcon: -1; DCCommand: 'cm_MarkUnmarkAll'; DCParameters: '' ), //Unselect all (files or both, as configured) (TCCommand: 'cm_ExchangeSelection'; TCIcon: 11; DCCommand: 'cm_MarkInvert'; DCParameters: '' ), //Invert selection (TCCommand: 'cm_ExchangeSelBoth'; TCIcon: 11; DCCommand: 'cm_MarkInvert'; DCParameters: 'attr=' ), //Invert selection (files+folders) (TCCommand: 'cm_ExchangeSelFiles'; TCIcon: 11; DCCommand: 'cm_MarkInvert'; DCParameters: 'attr=d-' ), //Invert selection (files) (TCCommand: 'cm_ExchangeSelFolders'; TCIcon: 11; DCCommand: 'cm_MarkInvert'; DCParameters: 'attr=d+' ), //Invert selection (folders) (TCCommand: 'cm_SelectCurrentExtension'; TCIcon: 41; DCCommand: 'cm_MarkCurrentExtension'; DCParameters: '' ), //Select all files with same ext. (TCCommand: 'cm_UnselectCurrentExtension'; TCIcon: -1; DCCommand: 'cm_UnmarkCurrentExtension'; DCParameters: '' ), //Unselect all files with same ext. (TCCommand: 'cm_SelectCurrentName'; TCIcon: -1; DCCommand: 'cm_MarkCurrentName'; DCParameters: '' ), //Select all files with same name (TCCommand: 'cm_UnselectCurrentName'; TCIcon: -1; DCCommand: 'cm_UnmarkCurrentName'; DCParameters: '' ), //Unselect all files with same name (TCCommand: 'cm_SelectCurrentNameExt'; TCIcon: -1; DCCommand: 'cm_MarkCurrentNameExt'; DCParameters: '' ), //Select all files with same name+ext. (TCCommand: 'cm_UnselectCurrentNameExt'; TCIcon: -1; DCCommand: 'cm_UnmarkCurrentNameExt'; DCParameters: '' ), //Unselect all files with same name+ext. (TCCommand: 'cm_SelectCurrentPath'; TCIcon: 72; DCCommand: 'cm_MarkCurrentPath'; DCParameters: '' ), //Select all in same path (for branch view+search) (TCCommand: 'cm_UnselectCurrentPath'; TCIcon: -1; DCCommand: 'cm_UnmarkCurrentPath'; DCParameters: '' ), //Unselect all in same path (TCCommand: 'cm_RestoreSelection'; TCIcon: 42; DCCommand: 'cm_RestoreSelection'; DCParameters: '' ), //Selection before last operation (TCCommand: 'cm_SaveSelection'; TCIcon: 43; DCCommand: 'cm_SaveSelection'; DCParameters: '' ), //Temporarily save selection (TCCommand: 'cm_SaveSelectionToFile'; TCIcon: -1; DCCommand: 'cm_SaveSelectionToFile'; DCParameters: '' ), //Save file selection to file (TCCommand: 'cm_SaveSelectionToFileA'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Save file selection to file (ANSI) (TCCommand: 'cm_SaveSelectionToFileW'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Save file selection to file (Unicode) (TCCommand: 'cm_SaveDetailsToFile'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Save all shown columns to file (TCCommand: 'cm_SaveDetailsToFileA'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Save all shown columns to file (ANSI) (TCCommand: 'cm_SaveDetailsToFileW'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Save all shown columns to file (Unicode) (TCCommand: 'cm_LoadSelectionFromFile'; TCIcon: -1; DCCommand: 'cm_LoadSelectionFromFile'; DCParameters: '' ), //Read file selection from file (TCCommand: 'cm_LoadSelectionFromClip'; TCIcon: -1; DCCommand: 'cm_LoadSelectionFromClip'; DCParameters: '' ), //Read file selection from clipboard (TCCommand: 'cm_EditPermissionInfo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Permissions dialog (NTFS) (TCCommand: 'cm_EditPersmissionInfo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Typo... (TCCommand: 'cm_EditAuditInfo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //File auditing (NTFS) (TCCommand: 'cm_EditOwnerInfo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Take ownership (NTFS) (TCCommand: 'cm_CutToClipboard'; TCIcon: -1; DCCommand: 'cm_CutToClipboard'; DCParameters: '' ), //Cut selected files to clipboard (TCCommand: 'cm_CopyToClipboard'; TCIcon: -1; DCCommand: 'cm_CopyToClipboard'; DCParameters: '' ), //Copy selected files to clipboard (TCCommand: 'cm_PasteFromClipboard'; TCIcon: -1; DCCommand: 'cm_PasteFromClipboard'; DCParameters: '' ), //Paste from clipboard to current dir (TCCommand: 'cm_CopyNamesToClip'; TCIcon: 45; DCCommand: 'cm_CopyNamesToClip'; DCParameters: '' ), //Copy filenames to clipboard (TCCommand: 'cm_CopyFullNamesToClip'; TCIcon: 45; DCCommand: 'cm_CopyFullNamesToClip'; DCParameters: '' ), //Copy names with full path (TCCommand: 'cm_CopyNetNamesToClip'; TCIcon: 45; DCCommand: 'cm_CopyNetNamesToClip'; DCParameters: '' ), //Copy names with UNC path (TCCommand: 'cm_CopySrcPathToClip'; TCIcon: 45; DCCommand: ''; DCParameters: '' ), //Copy source path to clipboard (TCCommand: 'cm_CopyTrgPathToClip'; TCIcon: 45; DCCommand: ''; DCParameters: '' ), //Copy target path to clipboard (TCCommand: 'cm_CopyFileDetailsToClip'; TCIcon: 59; DCCommand: 'cm_CopyFileDetailsToClip'; DCParameters: '' ), //Copy all shown columns (TCCommand: 'cm_CopyFpFileDetailsToClip'; TCIcon: 59; DCCommand: ''; DCParameters: '' ), //Copy all columns, with full path (TCCommand: 'cm_CopyNetFileDetailsToClip'; TCIcon: 59; DCCommand: ''; DCParameters: '' ), //Copy all columns, with UNC path (TCCommand: 'cm_FtpConnect'; TCIcon: 16; DCCommand: ''; DCParameters: '' ), //Connect to FTP (TCCommand: 'cm_FtpNew'; TCIcon: 17; DCCommand: ''; DCParameters: '' ), //New FTP connection (TCCommand: 'cm_FtpDisconnect'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Disconnect from FTP (TCCommand: 'cm_FtpHiddenFiles'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show hidden FTP files (TCCommand: 'cm_FtpAbort'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Abort current FTP command (TCCommand: 'cm_FtpResumeDownload'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Resume aborted download (TCCommand: 'cm_FtpSelectTransferMode'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Select Binary, ASCII or Auto mode (TCCommand: 'cm_FtpAddToList'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Add selected files to download list (TCCommand: 'cm_FtpDownloadList'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Download files in download list (TCCommand: 'cm_GotoPreviousDir'; TCIcon: 18; DCCommand: ''; DCParameters: '' ), //Go back (TCCommand: 'cm_GotoNextDir'; TCIcon: 19; DCCommand: ''; DCParameters: '' ), //Go forward (TCCommand: 'cm_DirectoryHistory'; TCIcon: -1; DCCommand: 'cm_DirHistory'; DCParameters: '' ), //History list (TCCommand: 'cm_GotoPreviousLocalDir'; TCIcon: 18; DCCommand: ''; DCParameters: '' ), //Go back, no ftp (TCCommand: 'cm_GotoNextLocalDir'; TCIcon: 19; DCCommand: ''; DCParameters: '' ), //Go forward, no ftp (TCCommand: 'cm_DirectoryHotlist'; TCIcon: -1; DCCommand: 'cm_DirHotList'; DCParameters: '' ), //Directory popup menu (TCCommand: 'cm_GoToRoot'; TCIcon: -1; DCCommand: 'cm_ChangeDirToRoot'; DCParameters: '' ), //Go to root directory (TCCommand: 'cm_GoToParent'; TCIcon: 15; DCCommand: 'cm_ChangeDirToParent'; DCParameters: '' ), //Go to parent directory (TCCommand: 'cm_GoToDir'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Open dir or zip under cursor (TCCommand: 'cm_OpenDesktop'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Desktop folder (TCCommand: 'cm_OpenDrives'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //My computer (TCCommand: 'cm_OpenControls'; TCIcon: 20; DCCommand: ''; DCParameters: '' ), //Control panel (TCCommand: 'cm_OpenFonts'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Fonts folder (TCCommand: 'cm_OpenNetwork'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Network neighborhood (TCCommand: 'cm_OpenPrinters'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Printers folder (TCCommand: 'cm_OpenRecycled'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Recycle bin (TCCommand: 'cm_CDtree'; TCIcon: 1; DCCommand: ''; DCParameters: '' ), //Popup directory tree (TCCommand: 'cm_TransferLeft'; TCIcon: -1; DCCommand: 'cm_TransferLeft'; DCParameters: '' ), //Transfer dir under cursor to left window (TCCommand: 'cm_TransferRight'; TCIcon: -1; DCCommand: 'cm_TransferRight'; DCParameters: '' ), //Transfer dir under cursor to right window (TCCommand: 'cm_EditPath'; TCIcon: -1; DCCommand: 'cm_EditPath'; DCParameters: '' ), //Edit path field above file list (TCCommand: 'cm_GoToFirstEntry'; TCIcon: -1; DCCommand: 'cm_GoToFirstEntry'; DCParameters: '' ), //Place cursor on first folder or file (TCCommand: 'cm_GoToFirstFile'; TCIcon: -1; DCCommand: 'cm_GoToFirstFile'; DCParameters: '' ), //Place cursor on first file in list (TCCommand: 'cm_GotoNextDrive'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Go one drive up (C->D) (TCCommand: 'cm_GotoPreviousDrive'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Go one drive down (TCCommand: 'cm_GotoNextSelected'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Go to next selected file (TCCommand: 'cm_GotoPrevSelected'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Go to previous selected file (TCCommand: 'cm_GotoDriveA'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Switch to drive A (TCCommand: 'cm_GotoDriveC'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Switch to drive C (TCCommand: 'cm_GotoDriveD'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Switch to drive D (TCCommand: 'cm_GotoDriveE'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Switch to drive E (TCCommand: 'cm_GotoDriveF'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //(etc, define your own if) (TCCommand: 'cm_GotoDriveZ'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //(you need more drives) (TCCommand: 'cm_HelpIndex'; TCIcon: 55; DCCommand: 'cm_HelpIndex'; DCParameters: '' ), //Help index (TCCommand: 'cm_Keyboard'; TCIcon: -1; DCCommand: 'cm_Keyboard'; DCParameters: '' ), //Keyboard help (TCCommand: 'cm_Register'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Registration info (TCCommand: 'cm_VisitHomepage'; TCIcon: -1; DCCommand: 'cm_VisitHomePage'; DCParameters: '' ), //Visit http://www.ghisler.com/ (TCCommand: 'cm_About'; TCIcon: -1; DCCommand: 'cm_About'; DCParameters: '' ), //Help/About Total Commander (TCCommand: 'cm_Exit'; TCIcon: -1; DCCommand: 'cm_Exit'; DCParameters: '' ), //Exit Total Commander (TCCommand: 'cm_Minimize'; TCIcon: -1; DCCommand: 'cm_Minimize'; DCParameters: '' ), //Minimize Total Commander (TCCommand: 'cm_Maximize'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Maximize Total Commander (TCCommand: 'cm_Restore'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Restore normal size (TCCommand: 'cm_ClearCmdLine'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Clear command line (TCCommand: 'cm_NextCommand'; TCIcon: -1; DCCommand: 'cm_CmdLineNext'; DCParameters: '' ), //Next command line (TCCommand: 'cm_PrevCommand'; TCIcon: -1; DCCommand: 'cm_CmdLinePrev'; DCParameters: '' ), //Previous command line (TCCommand: 'cm_AddPathToCmdline'; TCIcon: -1; DCCommand: 'cm_AddPathToCmdLine'; DCParameters: '' ), //Copy path to command line (TCCommand: 'cm_MultiRenameFiles'; TCIcon: 46; DCCommand: 'cm_MultiRename'; DCParameters: '' ), //Rename multiple files (TCCommand: 'cm_SysInfo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //System information (TCCommand: 'cm_OpenTransferManager'; TCIcon: 74; DCCommand: ''; DCParameters: '' ), //Background transfer manager (TCCommand: 'cm_SearchFor'; TCIcon: 47; DCCommand: 'cm_Search'; DCParameters: '' ), //Search for (TCCommand: 'cm_SearchStandalone'; TCIcon: 47; DCCommand: ''; DCParameters: '' ), //Search in separate process (TCCommand: 'cm_FileSync'; TCIcon: 48; DCCommand: 'cm_SyncDirs'; DCParameters: '' ), //Synchronize directories (TCCommand: 'cm_Associate'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Associate (TCCommand: 'cm_InternalAssociate'; TCIcon: -1; DCCommand: 'cm_FileAssoc'; DCParameters: '' ), //Define internal associations (TCCommand: 'cm_CompareFilesByContent'; TCIcon: 49; DCCommand: 'cm_CompareContents'; DCParameters: '' ), //File comparison (TCCommand: 'cm_IntCompareFilesByContent'; TCIcon: 49; DCCommand: 'cm_CompareContents'; DCParameters: '' ), //Use internal compare tool (TCCommand: 'cm_CommandBrowser'; TCIcon: 82; DCCommand: ''; DCParameters: '' ), //Browse internal commands (TCCommand: 'cm_VisButtonbar'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide button bar (TCCommand: 'cm_VisDriveButtons'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide drive button bars (TCCommand: 'cm_VisTwoDriveButtons'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide two drive bars (TCCommand: 'cm_VisFlatDriveButtons'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Buttons: Flat/normal mode (TCCommand: 'cm_VisFlatInterface'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Interface: Flat/normal mode (TCCommand: 'cm_VisDriveCombo'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide drive combobox (TCCommand: 'cm_VisCurDir'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide current directory (TCCommand: 'cm_VisBreadCrumbs'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide Breadcrumb bar (TCCommand: 'cm_VisTabHeader'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide tab header (sorting) (TCCommand: 'cm_VisStatusbar'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide status bar (TCCommand: 'cm_VisCmdLine'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide Command line (TCCommand: 'cm_VisKeyButtons'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide function key buttons (TCCommand: 'cm_ShowHint'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show file tip window (TCCommand: 'cm_ShowQuickSearch'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show name search window (TCCommand: 'cm_SwitchLongNames'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Turn long names on and off (TCCommand: 'cm_RereadSource'; TCIcon: 0; DCCommand: 'cm_Refresh'; DCParameters: '' ), //Reread source (TCCommand: 'cm_ShowOnlySelected'; TCIcon: 73; DCCommand: ''; DCParameters: '' ), //Hide files which aren't selected (TCCommand: 'cm_SwitchHidSys'; TCIcon: 79; DCCommand: ''; DCParameters: '' ), //Turn hidden/system files on and off (TCCommand: 'cm_SwitchHid'; TCIcon: 79; DCCommand: ''; DCParameters: '' ), //Turn hidden files on and off (TCCommand: 'cm_SwitchSys'; TCIcon: 79; DCCommand: 'cm_ShowSysFiles'; DCParameters: '' ), //Turn system files on and off (TCCommand: 'cm_Switch83Names'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Turn 8.3 names lowercase on/off (TCCommand: 'cm_SwitchDirSort'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Turn directory sorting by name on/off (TCCommand: 'cm_DirBranch'; TCIcon: 50; DCCommand: 'cm_FlatView'; DCParameters: '' ), //Show all files in current dir and all subdirs (TCCommand: 'cm_DirBranchSel'; TCIcon: 50; DCCommand: 'cm_FlatViewSel'; DCParameters: '' ), //Show selected files, and all in selected subdirs (TCCommand: 'cm_50Percent'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Window separator at 50% (TCCommand: 'cm_100Percent'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Window separator at 100% (TCCommand: 'cm_VisDirTabs'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide folder tabs (TCCommand: 'cm_VisXPThemeBackground'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide XP theme background (TCCommand: 'cm_SwitchOverlayIcons'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Switch icon overlays on/off (TCCommand: 'cm_VisHistHotButtons'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show/hide dir history+hotlist (TCCommand: 'cm_SwitchWatchDirs'; TCIcon: 80; DCCommand: ''; DCParameters: '' ), //Enable/disable WatchDirs auto-refresh temporarily (TCCommand: 'cm_SwitchIgnoreList'; TCIcon: 81; DCCommand: 'cm_SwitchIgnoreList'; DCParameters: '' ), //Enable/disable ignore list file to not show file names (TCCommand: 'cm_SwitchX64Redirection'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //64-bit Windows: Redirect 32-bit system32 dir off/on (TCCommand: 'cm_SeparateTreeOff'; TCIcon: 76; DCCommand: ''; DCParameters: '' ), //Disable separate tree panel (TCCommand: 'cm_SeparateTree1'; TCIcon: 77; DCCommand: ''; DCParameters: '' ), //One separate tree panel (TCCommand: 'cm_SeparateTree2'; TCIcon: 78; DCCommand: ''; DCParameters: '' ), //Two separate tree panels (TCCommand: 'cm_SwitchSeparateTree'; TCIcon: 51; DCCommand: ''; DCParameters: '' ), //Switch through tree panel options (TCCommand: 'cm_ToggleSeparateTree1'; TCIcon: 77; DCCommand: ''; DCParameters: '' ), //One separate tree panel on/off (TCCommand: 'cm_ToggleSeparateTree2'; TCIcon: 78; DCCommand: ''; DCParameters: '' ), //Two separate tree panels on/off (TCCommand: 'cm_UserMenu1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Start first menu item in Start menu (TCCommand: 'cm_UserMenu2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Second item (TCCommand: 'cm_UserMenu3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Third item (TCCommand: 'cm_UserMenu4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //etc. (TCCommand: 'cm_UserMenu5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_UserMenu6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_UserMenu7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_UserMenu8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //You can add more (TCCommand: 'cm_UserMenu9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //custom user menu ids (TCCommand: 'cm_UserMenu10'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //in totalcmd.inc! (TCCommand: 'cm_OpenNewTab'; TCIcon: 83; DCCommand: 'cm_NewTab'; DCParameters: '' ), //Open new tab (TCCommand: 'cm_OpenNewTabBg'; TCIcon: 83; DCCommand: ''; DCParameters: '' ), //Open new tab in background (TCCommand: 'cm_OpenDirInNewTab'; TCIcon: -1; DCCommand: 'cm_OpenDirInNewTab'; DCParameters: '' ), //Open dir under cursor in tab (TCCommand: 'cm_OpenDirInNewTabOther'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Open dir under cursor (other window) (TCCommand: 'cm_SwitchToNextTab'; TCIcon: -1; DCCommand: 'cm_NextTab'; DCParameters: '' ), //Switch to next Tab (as Ctrl+Tab) (TCCommand: 'cm_SwitchToPreviousTab'; TCIcon: -1; DCCommand: 'cm_PrevTab'; DCParameters: '' ), //Switch to previous Tab (Ctrl+Shift+Tab) (TCCommand: 'cm_MoveTabLeft'; TCIcon: -1; DCCommand: 'cm_MoveTabLeft'; DCParameters: '' ), //Move current tab to the left (TCCommand: 'cm_MoveTabRight'; TCIcon: -1; DCCommand: 'cm_MoveTabRight'; DCParameters: '' ), //Move current tab to the right (TCCommand: 'cm_CloseCurrentTab'; TCIcon: 84; DCCommand: 'cm_CloseTab'; DCParameters: '' ), //Close tab (TCCommand: 'cm_CloseAllTabs'; TCIcon: 85; DCCommand: 'cm_CloseAllTabs'; DCParameters: '' ), //Close all (TCCommand: 'cm_DirTabsShowMenu'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Show tab menu (TCCommand: 'cm_ToggleLockCurrentTab'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Turn on/off tab locking (TCCommand: 'cm_ToggleLockDcaCurrentTab'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Same but with dir changes allowed (TCCommand: 'cm_ExchangeWithTabs'; TCIcon: 37; DCCommand: ''; DCParameters: '' ), //Swap all Tabs (TCCommand: 'cm_GoToLockedDir'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Go to the base dir of locked tab (TCCommand: 'cm_SrcTabsList'; TCIcon: -1; DCCommand: 'cm_ShowTabsList'; DCParameters: '' ), //Source: Show list of all open tabs (TCCommand: 'cm_TrgTabsList'; TCIcon: -1; DCCommand: 'cm_ShowTabsList'; DCParameters: 'side=inactive'), //Target: Show list of all open tabs (TCCommand: 'cm_LeftTabsList'; TCIcon: -1; DCCommand: 'cm_ShowTabsList'; DCParameters: 'side=left' ), //Left: Show list of all open tabs (TCCommand: 'cm_RightTabsList'; TCIcon: -1; DCCommand: 'cm_ShowTabsList'; DCParameters: 'side=right' ), //Right: Show list of all open tabs (TCCommand: 'cm_SrcActivateTab1'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=1' ), //Activate first tab (TCCommand: 'cm_SrcActivateTab2'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=2' ), //Activate second tab (TCCommand: 'cm_SrcActivateTab3'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=3' ), //(Source window) (TCCommand: 'cm_SrcActivateTab4'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=4' ), //etc. (TCCommand: 'cm_SrcActivateTab5'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=5' ), (TCCommand: 'cm_SrcActivateTab6'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=6' ), (TCCommand: 'cm_SrcActivateTab7'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=7' ), (TCCommand: 'cm_SrcActivateTab8'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=8' ), (TCCommand: 'cm_SrcActivateTab9'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=9' ), (TCCommand: 'cm_SrcActivateTab10'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'index=10' ), //(up to 99 items) (TCCommand: 'cm_TrgActivateTab1'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=1' ), //Activate first tab (TCCommand: 'cm_TrgActivateTab2'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=2' ), //Activate second tab (TCCommand: 'cm_TrgActivateTab3'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=3' ), //(Target window) (TCCommand: 'cm_TrgActivateTab4'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=4' ), //etc. (TCCommand: 'cm_TrgActivateTab5'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=5' ), (TCCommand: 'cm_TrgActivateTab6'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=6' ), (TCCommand: 'cm_TrgActivateTab7'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=7' ), (TCCommand: 'cm_TrgActivateTab8'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=8' ), (TCCommand: 'cm_TrgActivateTab9'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=9' ), (TCCommand: 'cm_TrgActivateTab10'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=inactive;index=10' ), (TCCommand: 'cm_LeftActivateTab1'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=1' ), //Activate first tab (TCCommand: 'cm_LeftActivateTab2'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=2' ), //Activate second tab (TCCommand: 'cm_LeftActivateTab3'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=3' ), //(Left window) (TCCommand: 'cm_LeftActivateTab4'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=4' ), //etc. (TCCommand: 'cm_LeftActivateTab5'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=5' ), (TCCommand: 'cm_LeftActivateTab6'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=6' ), (TCCommand: 'cm_LeftActivateTab7'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=7' ), (TCCommand: 'cm_LeftActivateTab8'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=8' ), (TCCommand: 'cm_LeftActivateTab9'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=9' ), (TCCommand: 'cm_LeftActivateTab10'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=left;index=10' ), (TCCommand: 'cm_RightActivateTab1'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=1' ), //Activate first tab (TCCommand: 'cm_RightActivateTab2'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=2' ), //Activate second tab (TCCommand: 'cm_RightActivateTab3'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=3' ), //(Right window) (TCCommand: 'cm_RightActivateTab4'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=4' ), //etc. (TCCommand: 'cm_RightActivateTab5'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=5' ), (TCCommand: 'cm_RightActivateTab6'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=6' ), (TCCommand: 'cm_RightActivateTab7'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=7' ), (TCCommand: 'cm_RightActivateTab8'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=8' ), (TCCommand: 'cm_RightActivateTab9'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=9' ), (TCCommand: 'cm_RightActivateTab10'; TCIcon: -1; DCCommand: 'cm_ActivateTabByIndex'; DCParameters: 'side=right;index=10' ), (TCCommand: 'cm_SrcSortByCol1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by first column (TCCommand: 'cm_SrcSortByCol2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by second column (TCCommand: 'cm_SrcSortByCol3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (source window) (TCCommand: 'cm_SrcSortByCol4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_SrcSortByCol5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcSortByCol6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcSortByCol7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcSortByCol8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcSortByCol9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcSortByCol10'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcSortByCol99'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by first column (TCCommand: 'cm_TrgSortByCol2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by second column (TCCommand: 'cm_TrgSortByCol3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (target window) (TCCommand: 'cm_TrgSortByCol4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_TrgSortByCol5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol10'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_TrgSortByCol99'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by first column (TCCommand: 'cm_LeftSortByCol2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by second column (TCCommand: 'cm_LeftSortByCol3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (left window) (TCCommand: 'cm_LeftSortByCol4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_LeftSortByCol5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol10'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftSortByCol99'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by first column (TCCommand: 'cm_RightSortByCol2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Sort by second column (TCCommand: 'cm_RightSortByCol3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (right window) (TCCommand: 'cm_RightSortByCol4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_RightSortByCol5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol10'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightSortByCol99'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcCustomView1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Source: Custom columns 1 (TCCommand: 'cm_SrcCustomView2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (user defined columns) (TCCommand: 'cm_SrcCustomView3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_SrcCustomView4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcCustomView5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcCustomView6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcCustomView7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcCustomView8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcCustomView9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. until 299 (TCCommand: 'cm_LeftCustomView1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Left: Custom columns 1 (TCCommand: 'cm_LeftCustomView2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (user defined columns) (TCCommand: 'cm_LeftCustomView3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_LeftCustomView4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftCustomView5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftCustomView6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftCustomView7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftCustomView8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_LeftCustomView9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightCustomView1'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // Right: Custom columns 1 (TCCommand: 'cm_RightCustomView2'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // (user defined columns) (TCCommand: 'cm_RightCustomView3'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), // etc. (TCCommand: 'cm_RightCustomView4'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightCustomView5'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightCustomView6'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightCustomView7'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightCustomView8'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_RightCustomView9'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), (TCCommand: 'cm_SrcNextCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), // Source: Next custom view (TCCommand: 'cm_SrcPrevCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), // Source: Previous custom view (TCCommand: 'cm_TrgNextCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), // Target: Next custom view (TCCommand: 'cm_TrgPrevCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), // Target: Previous custom view (TCCommand: 'cm_LeftNextCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), // Left: Next custom view (TCCommand: 'cm_LeftPrevCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), // Left: Previous custom view (TCCommand: 'cm_RightNextCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), //Right: Next custom view (TCCommand: 'cm_RightPrevCustomView'; TCIcon: 52; DCCommand: ''; DCParameters: '' ), //Right: Previous custom view (TCCommand: 'cm_LoadAllOnDemandFields'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Load on demand fields for all files (TCCommand: 'cm_LoadSelOnDemandFields'; TCIcon: -1; DCCommand: ''; DCParameters: '' ), //Load on demand fields for selected files (TCCommand: 'cm_ContentStopLoadFields'; TCIcon: -1; DCCommand: ''; DCParameters: '' ) //Stop loading on demand fields ); //jcf:format=on //DC commands unmatched for the moment //------------------------------------ //cm_AddFilenameToCmdLine - Looks like TC can do it with a CTRL+ENTER but no cm_ command for this. //cm_AddPathAndFilenameToCmdLine - Looks like TC can do it with a CTRL+SHIFT+ENTER but no cm_ command for this. //cm_ChangeDir - Looks like TC can do it with "CD ..." bit no cm_ command for this. //cm_ChangeDirToHome - Looks like there is no TC equivalent //cm_ClearLogFile - //cm_ClearLogWindow //cm_ConfigDirHotList //cm_CopyNoAsk //cm_DebugShowCommandParameters //cm_EditNew //cm_GoToLastFile //cm_HardLink //cm_LeftEqualRight //cm_LoadTabs //cm_OpenArchive //cm_OpenBar //cm_OpenVirtualFileSystemList //cm_OperationsViewer //cm_PanelsSplitterPerPos //cm_QuickFilter //cm_QuickSearch //cm_RenameNoAsk //cm_RenameTab //cm_RightEqualLeft //cm_SaveTabs //cm_SetTabOptionNormal //cm_SetTabOptionPathLocked //cm_SetTabOptionPathResets //cm_SetTabOptionDirsInNewTab //cm_ShellExecute //cm_ShowButtonMenu //cm_ShowCmdLineHistory //cm_ShowMainMenu //cm_SortByAttr //cm_SymLink //cm_UniversalSingleDirectSort //cm_ViewHistory //cm_ViewHistoryNext //cm_ViewHistoryPrev //cm_ViewLogFile //cm_Wipe //cm_WorkWithDirectoryHotlist var TCIconSize: integer = 32; TCNumberOfInstance: integer; TCListOfCreatedTCIconFilename: TStringList; // Test have been made with string from site http://stackoverflow.com/questions/478201/how-to-test-an-application-for-correct-encoding-e-g-utf-8 // Note: If you ever "think" to change or modify this routine, make sure to test the following: // 1o) Make a directory with utf-8 special characters, a path like this: "Card-♠♣♥♦" // 2o) Then, go with TC and add it as a favorite. // 3o) Then, exit it to make sure it is saved in its wndcmd.ini file // 4o) Then, go in the hotlist of DC and do an import from TC file // 5o) Make sure the path you've created has really been imported and it's NOT written "cd Card-♠♣♥♦\" or things like that. // 6o) Make sure you can also GO TO this folder from the popup menu of hotlist. // 7o) After that, repeat the step one through six with a path called "français", or "Esta frase está en español" and really take the time to do it. // 8o) Really take the time to do step 7 with the suggested two folder mentionned here. // In its "wincmd", TC is using AnsiString for character that don't need UTF-8 string. // He add the identifier "AnsiChar($EF) + AnsiChar($BB) + AnsiChar($BF)" at the beginning of each value that requires that the following needs to be interpret as UTF8 string. // So we cannot systematically convert the string. Some are using code between 128 and 255 that needs to be interpert as what it was in ANSI. // ALSO, lettings the $EF $BB $BF in the "string" make the string to be displayble "normally" in Lazarus, yes... // ...but when it's time to do things like "pos(...", "copy(...", the $EF $BB $BF are there, taken into acocunt, even when doing a print of the string we don't see see them! // Anyway. If you ever modify the following thinking it shouldn't be like this or there is a better way or whatever, please, take the time to do the test written after your modifications function ConvertTCStringToString(TCString: ansistring): string; begin Result := TCString; if length(Result) >= 3 then begin if ((TCString[1] = AnsiChar($EF)) and (TCString[2] = AnsiChar($BB)) and (TCString[3] = AnsiChar($BF))) then begin Result := copy(Result, 4, (length(Result) - 3)); end else begin Result := CeAnsiToUtf8(Result); end; end; end; // TC is adding the "$EF $BB $BF" identifier if the string stored in its config file require to be interpret in uniccode. // Adding it systematically, like we already tried before, doesn't work in 100% of the situation. // For example, for raison that can't explain without its source code, if a toolbar filename is express with the "$EF $BB $BF" in the name, // it will "basically work", but if it is defined to be shown as a drop menu, the little down triangle won't be shown in TC!!! // So let's add the "$EF $BB $BF" only when it required. function ConvertStringToTCString(sString: string): ansistring; begin if CeUtf8ToAnsi(sString) = sString then Result := sString else Result := AnsiChar($EF) + AnsiChar($BB) + AnsiChar($BF) + sString; end; { ReplaceDCEnvVars } // Routine to replace %VARIABLE% of DC path by the actual absolute path // This is useful when we "export" to TC related path to place them in absolute format this way TC refer them correctly after export. function ReplaceDCEnvVars(const sText: string): string; begin Result := StringReplace(sText, '%DC_CONFIG_PATH%', ExcludeTrailingPathDelimiter(gpCfgDir), [rfIgnoreCase]); Result := StringReplace(Result, '%COMMANDER_PATH%', ExcludeTrailingPathDelimiter(ExtractFilePath(gpExePath)), [rfIgnoreCase]); end; { ReplaceTCEnvVars } // Routine to replace %VARIABLE% of TC path by the actual absolute path // This is useful when we "import" TC related path to place them in absolute format this way DC refer them correctly after import. function ReplaceTCEnvVars(const sText: string): string; var sAbsoluteTotalCommanderExecutableFilename, sAbsoluteTotalCommanderConfigFilename: string; begin sAbsoluteTotalCommanderExecutableFilename := mbExpandFileName(gTotalCommanderExecutableFilename); sAbsoluteTotalCommanderConfigFilename := mbExpandFileName(gTotalCommanderConfigFilename); Result := StringReplace(sText, '%COMMANDER_INI%\..', ExcludeTrailingPathDelimiter(ExtractFilePath(sAbsoluteTotalCommanderConfigFilename)),[rfIgnoreCase]); Result := StringReplace(Result, '%COMMANDER_INI%', sAbsoluteTotalCommanderConfigFilename, [rfIgnoreCase]); Result := StringReplace(Result, '%COMMANDER_PATH%', ExcludeTrailingPathDelimiter(ExtractFilePath(sAbsoluteTotalCommanderExecutableFilename)), [rfIgnoreCase]); Result := StringReplace(Result, '%COMMANDER_EXE%', ExcludeTrailingPathDelimiter(ExtractFilePath(sAbsoluteTotalCommanderExecutableFilename)), [rfIgnoreCase]); Result := StringReplace(Result, '%COMMANDER_DRIVE%', ExcludeTrailingPathDelimiter(ExtractFileDrive(sAbsoluteTotalCommanderExecutableFilename)), [rfIgnoreCase]); if utf8pos(UTF8UpperCase('wcmicons.dll'), UTF8UpperCase(Result)) = 1 then Result := StringReplace(Result, 'wcmicons.dll', ExtractFilePath(sAbsoluteTotalCommanderExecutableFilename) + 'wcmicons.dll', [rfIgnoreCase]); end; { GetTotalCommandeMainBarFilename } // We'll return the TC main bar filename. // At the same time, since we're in the config file, we'll determine the icon size for the button bar. // TC attempts to save the "default.bar" file in the same location as the executable. // When it can, it will be located there. // If not, it will store it in the same location as the ini file. // Obviously, if it's configured somewhere else by the user, its location will be stored into the ini file in the section "Buttonbar" under the variable "Buttonbar". // So the flow to find it would be something like that: // 1.Let's attempt to read it from "Buttonbar/Buttonbar" from the ini file. If it's there, we may quit searching and exit with that. // 2.If it was not found, let's attempt to see if we have one in the same directory as the ini config file. If it's there, we may quit searching and exit with that. // 3.If we still don't have one, let's check if it is in the same folder as the executable itself... And it will have to be there! function GetTotalCommandeMainBarFilename: string; var TCMainConfigFile: TIniFileEx; begin Result := ''; //1.Let's attempt to read it from configuration file. if mbFileExists(mbExpandFileName(gTotalCommanderConfigFilename)) then begin TCMainConfigFile := TIniFileEx.Create(mbExpandFileName(gTotalCommanderConfigFilename)); try Result := mbExpandFileName(ReplaceTCEnvVars(ConvertTCStringToString(TCMainConfigFile.ReadString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTONBAR_SECTION, Result)))); //While we're there, we'll get the button height. TCIconSize := TCMainConfigFile.ReadInteger(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTONHEIGHT, 32 + 5); TCIconSize := TCIconSize - 5; //Yeah... A magic -5... finally TCMainConfigFile.Free; end; //2.If we have no result, let's let see if we have from one from the same location as the configuration file. if Result = '' then if FileExists(ExtractFilePath(mbExpandFileName(gTotalCommanderConfigFilename)) + TCCONFIG_DEFAULTBAR_FILENAME) then result := ExtractFilePath(mbExpandFileName(gTotalCommanderConfigFilename)) + TCCONFIG_DEFAULTBAR_FILENAME; end; //3.If we still did not find it, let's finally attempt to take it from the same location as the executable. if Result = '' then if FileExists(ExtractFilePath(mbExpandFileName(gTotalCommanderExecutableFilename)) + TCCONFIG_DEFAULTBAR_FILENAME) then result := ExtractFilePath(mbExpandFileName(gTotalCommanderExecutableFilename)) + TCCONFIG_DEFAULTBAR_FILENAME; end; { EnumTaskWindowsProc } // Routine used for the following "IsTotalCommanderSeemsRunning" routine. function EnumTaskWindowsProc(Wnd: THandle; List{%H-}: TStrings): boolean; stdcall; var ClassName: PChar; begin ClassName := Stralloc(100); if GetClassName(Wnd, ClassName, 99) > 0 then begin if ClassName = 'TTOTAL_CMD' then begin // Skip Double Commander main window class if GetPropW(Wnd, 'WinControlDC') = 0 then Inc(TCNumberOfInstance); end; end; Result := True; strDispose(ClassName); end; { IsTotalCommanderSeemsRunning } // Routine that we'll return TRUE if TC is currently running and false otherwise function IsTotalCommanderSeemsRunning: boolean; begin TCNumberOfInstance := 0; try EnumWindows(@EnumTaskWindowsProc, 0); finally end; Result := (TCNumberOfInstance > 0); end; { areTCRelatedPathsAndFilesDetected } //To consider to be cumfortable to work with TC related stuff we need to make sure: //1o) We know where is the TC executable //2o) We know where is the TC config file //3o) We know where where is the file for the TC main toolbar //4o) We know where the toolbar and associted icon COULD be stored (util when exporting the DC toolbar) function areTCRelatedPathsAndFilesDetected: boolean; begin Result := False; if mbFileExists(mbExpandFileName(gTotalCommanderExecutableFilename)) then begin if mbFileExists(mbExpandFileName(gTotalCommanderConfigFilename)) then begin sTotalCommanderMainbarFilename := GetTotalCommandeMainBarFilename; if mbFileExists(sTotalCommanderMainbarFilename) then begin if mbDirectoryExists(ExcludeTrailingPathDelimiter(mbExpandFileName(gTotalCommanderToolbarPath))) then begin Result := True; end else begin MsgError(Format(rsMsgTCToolbarNotFound, [gTotalCommanderToolbarPath])); end; end else begin MsgError(Format(rsImportToolbarProblem, [sTotalCommanderMainbarFilename])); end; end else begin MsgError(Format(rsMsgTCConfigNotFound, [gTotalCommanderConfigFilename])); end; end else begin MsgError(Format(rsMsgTCExecutableNotFound, [gTotalCommanderExecutableFilename])); end; if not Result then BringUsToTCConfigurationPage; end; { areWeInSituationToPlayWithTCFiles } function areWeInSituationToPlayWithTCFiles: boolean; var FlagCancelWaitingTCClose: TMyMsgResult; FlagTCIsRunning: boolean; begin Result := False; if areTCRelatedPathsAndFilesDetected then begin repeat FlagTCIsRunning := IsTotalCommanderSeemsRunning; if FlagTCIsRunning then FlagCancelWaitingTCClose := MsgBox(rsMsgTCisRunning, [msmbOk, msmbCancel], msmbOk, msmbCancel); until (FlagTCIsRunning = False) or (FlagCancelWaitingTCClose = mmrCancel); Result := not FlagTCIsRunning; end; end; { GetTCEquivalentCommandToDCCommand } // From the given DC command, we'll return the equivalent TC command. // If not found, we'll return the same DC command, at least. function GetTCEquivalentCommandToDCCommand(DCCommand: string; var TCIndexOfCommand: integer): string; var SearchingIndex: integer = 1; begin Result := ''; TCIndexOfCommand := -1; if DCCommand <> '' then begin DCCommand := UTF8LowerCase(DCCommand); //Let's see if we have an equivalent TC for our DC command. while (SearchingIndex <= NUMBEROFCOMMANDS) and (TCIndexOfCommand = -1) do begin if DCCommand = UTF8LowerCase(COMMANDS_LIST_TC[SearchingIndex].DCCommand) then begin Result := COMMANDS_LIST_TC[SearchingIndex].TCCommand; TCIndexOfCommand := SearchingIndex; end else begin Inc(SearchingIndex); end; end; if TCIndexOfCommand = -1 then Result := DCCommand; end; end; { GetTCIconFromDCIconAndCreateIfNecessary } // Will return the string to use for the icon for the tool bar button when doing an export to TC bar file. // Will also create a .ICO file if we know the fiel can't be load by TC. // Basically routine generate the same bitmap as what DC would generate to show. // Then, we look from where it's coming from with "fromWhatItWasLoaded)". // Depending of this, will simply return the same filename OR will create and icon for TC. // This has been test with: // fwbwlNotLoaded: NOT TESTED // fwbwlIconThemeBitmap: Tested with 'cm_configdirhotlist', 'cm_dirhotlist', 'utilities-terminal', 'cm_markunmarkall', 'go-previous', 'go-next' // fwbwlResourceFileExtracted: Tested with 'wcmicons.dll,3', 'MyOwnIcons.icl,12', 'doublecmd.exe', 'TOTALCMD64.EXE', 'HWorks32.exe' // fwbwlGraphicFile: Test with 'UploadDispatcher.ico', 'Carlos.bmp' // fwbwlGraphicFile switched to fwbwlGraphicFileNotSupportedByTC: Tested with 'Nop.png', 'cm_extractfiles.png', 'cm_about.png', a corrutped .png file // fwbwlFileIconByExtension: Tested with 'ElementaryOS-32bits.vbox', 'backupsource.bat', 'Microsoft Word 2010.lnk', a corrupted .bmp file since DC at least attenmpt to by the extension which is nice! // fwbwlFiDefaultIconID: Tested with "a missing unknown extension file", An empty icon string, function GetTCIconFromDCIconAndCreateIfNecessary(const DCIcon: string): string; var LocalBitmap: Graphics.TBitmap = nil; fromWhatItWasLoaded: TfromWhatBitmapWasLoaded; LocalIcon: Graphics.TIcon = nil; Suffix: string; needToBeConvertToIco: boolean = False; begin Result := DCIcon; //In any case, by default at least, return the same thing as what we got in DC and good luck TC! //Get the bitmap of the icon and make sure to get "fromWhatItWasLoaded" to see from where it came from LocalBitmap := PixmapManager.LoadBitmapEnhanced(DCICon, TCIconSize, True, clBtnFace, @fromWhatItWasLoaded); try if ExtractFileExt(UTF8Lowercase(DCIcon)) = '.png' then fromWhatItWasLoaded := fwbwlGraphicFileNotSupportedByTC; case fromWhatItWasLoaded of fwbwlNotLoaded: needToBeConvertToIco := False; fwbwlIconThemeBitmap: needToBeConvertToIco := True; fwbwlResourceFileExtracted: needToBeConvertToIco := False; fwbwlGraphicFile: needToBeConvertToIco := False; fwbwlGraphicFileNotSupportedByTC: needToBeConvertToIco := True; fwbwlFileIconByExtension: needToBeConvertToIco := True; fwbwlFiDefaultIconID: needToBeConvertToIco := True; end; // If TC can't load the file, let's generate a .ICO file for it. // We use a .ICO so we can passed at least something with transparency. if needToBeConvertToIco then begin Result := RemoveFileExt(ExtractFilename(DCIcon)); if Result = '' then Result := 'empty'; Result := IncludeTrailingPathDelimiter(mbExpandFileName(gTotalCommanderToolbarPath)) + Result; //Make sure to use a filename not already generated. Suffix := ''; while TCListOfCreatedTCIconFilename.IndexOf(Result + Suffix + '.ico') <> -1 do Suffix := IntToStr(StrToIntDef(Suffix, 0) + 1); Result := Result + Suffix + '.ico'; //.ICO conversion. LocalIcon := Graphics.TIcon.Create; try LocalIcon.Assign(LocalBitmap); LocalIcon.SaveToFile(Result); TCListOfCreatedTCIconFilename.Add(Result); finally LocalIcon.Free; end; end; finally LocalBitmap.Free; end; end; { GetTCEquivalentCommandIconToDCCommandIcon } // Different from the previous "GetTCIconFromDCIconAndCreateIfNecessary" routine because it concerns "commands". // If TC has an icon in its "wcmicons.dll" file for the command, we'll use it. // If not, we'll save a .ICO for it, no matter where it is comming from. function GetTCEquivalentCommandIconToDCCommandIcon(DCIcon: string; TCIndexOfCommand: integer): string; begin Result := ''; if TCIndexOfCommand <> -1 then begin if COMMANDS_LIST_TC[TCIndexOfCommand].TCIcon <> -1 then Result := 'wcmicons.dll,' + IntToStr(COMMANDS_LIST_TC[TCIndexOfCommand].TCIcon); end; if Result = '' then Result := GetTCIconFromDCIconAndCreateIfNecessary(DCIcon); end; { GetDCEquivalentCommandToTCCommand } // From the given TC command, we'll return the equivalent DC command. function GetDCEquivalentCommandToTCCommand(TCCommand: string; var TCIndexOfCommand: integer; ListOfParameters: TStringList): string; begin Result := 'nil'; TCIndexOfCommand := 1; ListOfParameters.Clear; if TCCommand <> '' then begin TCCommand := UTF8LowerCase(TCCommand); //Let's see if we have an equivalent DC for the TC command. while (TCIndexOfCommand <= NUMBEROFCOMMANDS) and (Result = 'nil') do begin if TCCommand = UTF8LowerCase(COMMANDS_LIST_TC[TCIndexOfCommand].TCCommand) then begin Result := COMMANDS_LIST_TC[TCIndexOfCommand].DCCommand; ParseLineToList(COMMANDS_LIST_TC[TCIndexOfCommand].DCParameters, ListOfParameters); end else Inc(TCIndexOfCommand); end; end; if (Result = '') or (Result = 'nil') then begin TCIndexOfCommand := -1; Result := TCCommand; end; end; { ExportDCToolbarsToTC } procedure ExportDCToolbarsToTC(Toolbar: TKASToolbar; Barfilename: string; FlushExistingContent, FlagNeedToUpdateConfigIni: boolean); var TargetBarFilenamePrefix: string; TCToolBarIndex: integer; ExportationDateTime: TDateTime; procedure PossiblyRecursiveAddThisToolItemToConfigFile(ToolItem: TKASToolItem; TCBarConfigFile: TIniFileEx; TCIndexButton: integer); var sTCIndexButton: string; TCIndexOfCommand: integer = -1; IndexItem: integer; TCCommand, TCIcon: string; InnerTCBarConfigFilename: string; InnerTCBarConfigFile: TIniFileEx; begin sTCIndexButton := IntToStr(TCIndexButton); if ToolItem is TKASSeparatorItem then begin TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTON_PREFIX + sTCIndexButton, ''); TCBarConfigFile.WriteInteger(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_ICONIC_PREFIX + sTCIndexButton, 0); end; if ToolItem is TKASCommandItem then begin TCCommand := GetTCEquivalentCommandToDCCommand(TKASCommandItem(ToolItem).Command, TCIndexOfCommand); TCIcon := GetTCEquivalentCommandIconToDCCommandIcon(TKASCommandItem(ToolItem).Icon, TCIndexOfCommand); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_CMD_PREFIX + sTCIndexButton, ConvertStringToTCString(TCCommand)); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTON_PREFIX + sTCIndexButton, ConvertStringToTCString(TCIcon)); if (TKASCommandItem(ToolItem).Hint <> '') and (TCIndexOfCommand = -1) then //We'll write the hint *only* if command is not a recognized Total Commander command. TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_HINT_PREFIX + sTCIndexButton, ConvertStringToTCString(TKASCommandItem(ToolItem).Hint)); end; if ToolItem is TKASProgramItem then begin TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTON_PREFIX + sTCIndexButton, ConvertStringToTCString(GetTCIconFromDCIconAndCreateIfNecessary(TKASProgramItem(ToolItem).Icon))); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_CMD_PREFIX + sTCIndexButton, ConvertStringToTCString(mbExpandFileName(TKASProgramItem(ToolItem).Command))); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_STARTINGPATH_PREFIX + sTCIndexButton, ConvertStringToTCString(mbExpandFileName(TKASProgramItem(ToolItem).StartPath))); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_HINT_PREFIX + sTCIndexButton, ConvertStringToTCString(TKASProgramItem(ToolItem).Hint)); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_PARAM_PREFIX + sTCIndexButton, ConvertStringToTCString(TKASProgramItem(ToolItem).Params)); end; if ToolItem is TKASMenuItem then begin InnerTCBarConfigFilename := TargetBarFilenamePrefix + '_SubBar' + Format('%2.2d', [TCToolBarIndex]) + '_' + GetDateTimeInStrEZSortable(ExportationDateTime) + '.BAR'; Inc(TCToolBarIndex); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_CMD_PREFIX + sTCIndexButton, ConvertStringToTCString(InnerTCBarConfigFilename)); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTON_PREFIX + sTCIndexButton, ConvertStringToTCString(mbExpandFileName(TKASMenuItem(ToolItem).Icon))); TCBarConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_HINT_PREFIX + sTCIndexButton, ConvertStringToTCString(TKASMenuItem(ToolItem).Hint)); TCBarConfigFile.WriteInteger(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_ICONIC_PREFIX + sTCIndexButton, 1); //Now we have to create the TC toolbar file to store the coming subbar. InnerTCBarConfigFile := TIniFileEx.Create(InnerTCBarConfigFilename, fmOpenWrite); try for IndexItem := 0 to pred(TKASMenuItem(ToolItem).SubItems.Count) do PossiblyRecursiveAddThisToolItemToConfigFile(TKASMenuItem(ToolItem).SubItems[IndexItem], InnerTCBarConfigFile, (IndexItem + 1)); //*AFTER* all the buttons have been added, let's update for TC the number of buttons now present. InnerTCBarConfigFile.WriteInteger(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTONBAR_COUNT, TKASMenuItem(ToolItem).SubItems.Count); InnerTCBarConfigFile.UpdateFile; finally InnerTCBarConfigFile.Free; end; end; end; var //Placed intentionnally *AFTER* above routine to make sure these variable names are not used in above possibly recursive routines. TCMainConfigFile, MainTCBarConfigFile: TIniFileEx; IndexButton, TCMainIndexButton: integer; begin ExportationDateTime := now; TargetBarFilenamePrefix := IncludeTrailingPathDelimiter(mbExpandFilename(gTotalCommanderToolbarPath)) + rsFilenameExportedTCBarPrefix; TCToolBarIndex := 1; TCListOfCreatedTCIconFilename := TStringList.Create; TCListOfCreatedTCIconFilename.Sorted := True; TCListOfCreatedTCIconFilename.Clear; try //Let's create/append the .BAR file(s)! MainTCBarConfigFile := TIniFileEx.Create(Barfilename, fmOpenReadWrite); try if FlushExistingContent then begin MainTCBarConfigFile.EraseSection(TCCONFIG_BUTTONBAR_SECTION); TCMainIndexButton := 0; end else begin TCMainIndexButton := MainTCBarConfigFile.ReadInteger(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTONBAR_COUNT, 0); end; //Let's add the DC toolbar to the TC .BAR file. for IndexButton := 0 to pred(Toolbar.ButtonCount) do begin Inc(TCMainIndexButton); PossiblyRecursiveAddThisToolItemToConfigFile(Toolbar.Buttons[IndexButton].ToolItem, MainTCBarConfigFile, TCMainIndexButton); end; //*AFTER* all the buttons have been added, let's update for TC the number of buttons now present. MainTCBarConfigFile.WriteInteger(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTONBAR_COUNT, TCMainIndexButton); MainTCBarConfigFile.UpdateFile; finally MainTCBarConfigFile.Free; end; finally TCListOfCreatedTCIconFilename.Free; end; //If we've been asked to play in the Wincmd.ini file, let's make sure to save the main bar filename. if FlagNeedToUpdateConfigIni then begin TCMainConfigFile := TIniFileEx.Create(mbExpandFileName(gTotalCommanderConfigFilename), fmOpenReadWrite); try //2014-11-27:It looks like, will with TC 8.50B12, the main bar file cannot have unicode in the name??? //It "basically" works but have some annoying problem from here to thre. //So intentionnally, we don't use "ConvertStringToTCString(SaveDialog.Filename)" TCMainConfigFile.WriteString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTONBAR_SECTION, ansistring(Barfilename)); TCMainConfigFile.UpdateFile; finally TCMainConfigFile.Free; end; end; end; { ConvertTCToolbarToDCXmlConfig } // Will import the TC toolbar file named "sBarFilename" into either our "AToolbarConfig" XML structure. // If the TC toolbar have buttons pointing other TC toolbar file, the routine will import them as well // and organize something similar in the tree structure of subtoolbar DC is using. // Obviously to avoid keeps cycling in round if "Toolbar A points toolbar B and toolbar B points toolbar A", // this import routine will not re-importe a toolbar already imported. procedure ConvertTCToolbarToDCXmlConfig(sTCBarFilename: string; ADCXmlConfig:TXmlConfig); var TCToolbarFilenameList: TStringList; //To hold the TC toolbarfile already imported so we don't re-import more than once a toolbar file already imported. TCIndexOfCommand: integer; DCListOfParameters: TStringList; ToolBarNode, RowNode: TXmlNode; // WARNING: "RecursiveIncorporateTCBarfile" is recursive and may call itself! procedure RecursiveIncorporateTCBarfile(Barfilename: string; InsertionNode:TXmlNode); var TCBarConfigFile: TIniFileEx; IndexButton: integer; sButtonName, sCmdName, sHintName, sParamValue, sStartingPath: string; SubMenuNode, CommandNode, MenuItemsNode: TXmlNode; begin if mbFileExists(Barfilename) then begin TCBarConfigFile := TIniFileEx.Create(Barfilename); try IndexButton := 1; repeat sButtonName := ConvertTCStringToString(TCBarConfigFile.ReadString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_BUTTON_PREFIX + IntToStr(IndexButton), TCCONFIG_MAINBAR_NOTPRESENT)); if sButtonName <> TCCONFIG_MAINBAR_NOTPRESENT then begin if sButtonName = '' then begin //We have a separator bar! CommandNode := ADCXmlConfig.AddNode(InsertionNode, 'Separator'); end else begin sButtonName := ReplaceTCEnvVars(sButtonName); sCmdName := TrimQuotes(ReplaceTCEnvVars(ConvertTCStringToString(TCBarConfigFile.ReadString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_CMD_PREFIX + IntToStr(IndexButton), 'cmd_notimplement')))); sParamValue := ReplaceTCEnvVars(ConvertTCStringToString(TCBarConfigFile.ReadString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_PARAM_PREFIX + IntToStr(IndexButton), ''))); sStartingPath := TrimQuotes(ReplaceTCEnvVars(ConvertTCStringToString(TCBarConfigFile.ReadString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_STARTINGPATH_PREFIX + IntToStr(IndexButton), '')))); sHintName := ConvertTCStringToString(TCBarConfigFile.ReadString(TCCONFIG_BUTTONBAR_SECTION, TCCONFIG_HINT_PREFIX + IntToStr(IndexButton), '')); if pos('cm_', UTF8LowerCase(sCmdName)) = 1 then begin // We have an internal command! sCmdName := GetDCEquivalentCommandToTCCommand(sCmdName, TCIndexOfCommand, DCListOfParameters); if TCIndexOfCommand <> -1 then begin // If we have an equivalent, we add it as the equivalent internal command. CommandNode := ADCXmlConfig.AddNode(InsertionNode, 'Command'); ADCXmlConfig.AddValue(CommandNode, 'ID', GuidToString(DCGetNewGUID)); ADCXmlConfig.AddValue(CommandNode, 'Icon', UTF8LowerCase(sCmdName)); ADCXmlConfig.AddValue(CommandNode, 'Command', sCmdName); ADCXmlConfig.AddValue(CommandNode, 'Hint', sHintName); end else begin // If we don't have an equivalent, we add is as an external command and we will write info to mean it. CommandNode := ADCXmlConfig.AddNode(InsertionNode, 'Program'); ADCXmlConfig.AddValue(CommandNode, 'ID', GuidToString(DCGetNewGUID)); ADCXmlConfig.AddValue(CommandNode, 'Icon', '???: '+sButtonName); // ???: will result into the question mark icon so it's easy for user to see that one did not work. ADCXmlConfig.AddValue(CommandNode, 'Command', rsNoEquivalentInternalCommand + ' - ' + sCmdName); ADCXmlConfig.AddValue(CommandNode, 'Params', ''); ADCXmlConfig.AddValue(CommandNode, 'StartPath', ''); ADCXmlConfig.AddValue(CommandNode, 'Hint', rsNoEquivalentInternalCommand); end; end else begin if UTF8UpperCase(ExtractFileExt(sCmdName)) = '.BAR' then begin //Since with TC we could have toolbars recursively pointing themselves, we need to make sure we'll not get lost cycling throught the same ones over and over. if TCToolbarFilenameList.IndexOf(UTF8UpperCase(sCmdName)) = -1 then begin //We have a subtoolbar! TCToolbarFilenameList.Add(UTF8UpperCase(sCmdName)); SubMenuNode := ADCXmlConfig.AddNode(InsertionNode, 'Menu'); ADCXmlConfig.AddValue(SubMenuNode, 'ID', GuidToString(DCGetNewGUID)); if sHintName <> '' then ADCXmlConfig.AddValue(SubMenuNode, 'Hint', sHintName) else ADCXmlConfig.AddValue(SubMenuNode, 'Hint', 'Sub menu'); ADCXmlConfig.AddValue(SubMenuNode, 'Icon', sButtonName); MenuItemsNode := ADCXmlConfig.AddNode(SubMenuNode, 'MenuItems'); RecursiveIncorporateTCBarfile(sCmdName, MenuItemsNode); end; end else begin //We have a "Program Item" CommandNode := ADCXmlConfig.AddNode(InsertionNode, 'Program'); ADCXmlConfig.AddValue(CommandNode, 'ID', GuidToString(DCGetNewGUID)); ADCXmlConfig.AddValue(CommandNode, 'Icon', sButtonName); ADCXmlConfig.AddValue(CommandNode, 'Command', sCmdName); ADCXmlConfig.AddValue(CommandNode, 'Params', sParamValue); ADCXmlConfig.AddValue(CommandNode, 'StartPath', sStartingPath); if sHintName <> '' then ADCXmlConfig.AddValue(CommandNode, 'Hint', sHintName) else ADCXmlConfig.AddValue(CommandNode, 'Hint', 'Program'); end; end; end; end; Inc(IndexButton); until sButtonName = TCCONFIG_MAINBAR_NOTPRESENT; finally TCBarConfigFile.Free; end; end; end; begin TCToolbarFilenameList := TStringList.Create; try ToolBarNode := ADCXmlConfig.FindNode(ADCXmlConfig.RootNode, 'Toolbars/MainToolbar', True); ADCXmlConfig.ClearNode(ToolBarNode); RowNode := ADCXmlConfig.AddNode(ToolBarNode, 'Row'); DCListOfParameters := TStringList.Create; try RecursiveIncorporateTCBarfile(sTCBarFilename, RowNode); finally DCListOfParameters.Free; end; finally TCToolbarFilenameList.Free; end; end; { GetActualTCIni } // Returns actual ini filename when using 'RedirectSection' key function GetActualTCIni(NormalizedTCIniFilename, SectionName: String): String; var ConfigFile: TIniFileEx; begin ConfigFile := TIniFileEx.Create(NormalizedTCIniFilename); Result := ConvertTCStringToString(ConfigFile.ReadString(SectionName, 'RedirectSection', '')); ConfigFile.Free; if Result <> '' then Result := GetActualTCIni(ReplaceTCEnvVars(ReplaceEnvVars(Result)), SectionName) else Result := NormalizedTCIniFilename; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/ubitmap.pas�������������������������������������������������������0000644�0001750�0000144�00000027626�14743153644�020201� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Windows specific bitmap functions Copyright (C) 2020 Alexander Koblov (alexx2000@mail.ru) Based on Win32Proc.pas from the Lazarus Component Library (LCL) See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the copyright. 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. } unit uBitmap; {$mode objfpc}{$H+} interface uses LCLIntf, Classes, Graphics, Windows, LCLVersion; function BitmapCreateFromHICON(Handle: HICON): Graphics.TBitmap; function BitmapCreateFromHBITMAP(Handle: HBITMAP): Graphics.TBitmap; implementation uses FPImage, GraphType, Forms, IntfGraphics {$IF DEFINED(LCLQT5) OR (LCL_FULLVERSION >= 3000000)} , SysUtils, LCLProc {$ENDIF} ; {$IF DEFINED(LCLQT5) OR (LCL_FULLVERSION >= 3000000)} procedure FillRawImageDescriptionColors(var ADesc: TRawImageDescription); begin case ADesc.BitsPerPixel of 1,4,8: begin // palette mode, no offsets ADesc.Format := ricfGray; ADesc.RedPrec := ADesc.BitsPerPixel; ADesc.GreenPrec := 0; ADesc.BluePrec := 0; ADesc.RedShift := 0; ADesc.GreenShift := 0; ADesc.BlueShift := 0; end; 16: begin // 5-5-5 mode ADesc.RedPrec := 5; ADesc.GreenPrec := 5; ADesc.BluePrec := 5; ADesc.RedShift := 10; ADesc.GreenShift := 5; ADesc.BlueShift := 0; ADesc.Depth := 15; end; 24: begin // 8-8-8 mode ADesc.RedPrec := 8; ADesc.GreenPrec := 8; ADesc.BluePrec := 8; ADesc.RedShift := 16; ADesc.GreenShift := 8; ADesc.BlueShift := 0; end; else // 32: // 8-8-8-8 mode, high byte can be native alpha or custom 1bit maskalpha ADesc.AlphaPrec := 8; ADesc.RedPrec := 8; ADesc.GreenPrec := 8; ADesc.BluePrec := 8; ADesc.AlphaShift := 24; ADesc.RedShift := 16; ADesc.GreenShift := 8; ADesc.BlueShift := 0; ADesc.Depth := 32; end; end; procedure FillRawImageDescription(const ABitmapInfo: Windows.TBitmap; out ADesc: TRawImageDescription); begin ADesc.Init; ADesc.Format := ricfRGBA; ADesc.Depth := ABitmapInfo.bmBitsPixel; // used bits per pixel ADesc.Width := ABitmapInfo.bmWidth; ADesc.Height := ABitmapInfo.bmHeight; ADesc.BitOrder := riboReversedBits; ADesc.ByteOrder := riboLSBFirst; ADesc.LineOrder := riloTopToBottom; ADesc.BitsPerPixel := ABitmapInfo.bmBitsPixel; // bits per pixel. can be greater than Depth. ADesc.LineEnd := rileDWordBoundary; if ABitmapInfo.bmBitsPixel <= 8 then begin // each pixel is an index in the palette // TODO, ColorCount ADesc.PaletteColorCount := 0; end else ADesc.PaletteColorCount := 0; FillRawImageDescriptionColors(ADesc); ADesc.MaskBitsPerPixel := 1; ADesc.MaskShift := 0; ADesc.MaskLineEnd := rileWordBoundary; // CreateBitmap requires word boundary ADesc.MaskBitOrder := riboReversedBits; end; function GetBitmapOrder(AWinBmp: Windows.TBitmap; ABitmap: HBITMAP): TRawImageLineOrder; procedure DbgLog(const AFunc: String); begin DebugLn('GetBitmapOrder - GetDIBits ', AFunc, ' failed: ', SysErrorMessage(Windows.GetLastError)); end; var SrcPixel: PCardinal absolute AWinBmp.bmBits; OrgPixel, TstPixel: Cardinal; Scanline: Pointer; DC: HDC; Info: record Header: Windows.TBitmapInfoHeader; Colors: array[Byte] of Cardinal; // reserve extra color for colormasks end; FullScanLine: Boolean; // win9x requires a full scanline to be retrieved // others won't fail when one pixel is requested begin if AWinBmp.bmBits = nil then begin // no DIBsection so always bottom-up Exit(riloBottomToTop); end; // try to figure out the orientation of the given bitmap. // Unfortunately MS doesn't provide a direct function for this. // So modify the first pixel to see if it changes. This pixel is always part // of the first scanline of the given bitmap. // When we request the data through GetDIBits as bottom-up, windows adjusts // the data when it is a top-down. So if the pixel doesn't change the bitmap // was internally a top-down image. FullScanLine := Win32Platform = VER_PLATFORM_WIN32_WINDOWS; if FullScanLine then ScanLine := GetMem(AWinBmp.bmWidthBytes) else ScanLine := nil; FillChar(Info.Header, sizeof(Windows.TBitmapInfoHeader), 0); Info.Header.biSize := sizeof(Windows.TBitmapInfoHeader); DC := Windows.GetDC(0); if Windows.GetDIBits(DC, ABitmap, 0, 1, nil, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS) = 0 then begin DbgLog('Getinfo'); // failed ??? Windows.ReleaseDC(0, DC); Exit(riloBottomToTop); end; // Get only 1 pixel (or full scanline for win9x) OrgPixel := 0; if FullScanLine then begin if Windows.GetDIBits(DC, ABitmap, 0, 1, ScanLine, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS) = 0 then DbgLog('OrgPixel') else OrgPixel := PCardinal(ScanLine)^; end else begin Info.Header.biWidth := 1; if Windows.GetDIBits(DC, ABitmap, 0, 1, @OrgPixel, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS) = 0 then DbgLog('OrgPixel'); end; // modify pixel SrcPixel^ := not SrcPixel^; // get test TstPixel := 0; if FullScanLine then begin if Windows.GetDIBits(DC, ABitmap, 0, 1, ScanLine, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS) = 0 then DbgLog('TstPixel') else TstPixel := PCardinal(ScanLine)^; end else begin if Windows.GetDIBits(DC, ABitmap, 0, 1, @TstPixel, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS) = 0 then DbgLog('TstPixel'); end; if OrgPixel = TstPixel then Result := riloTopToBottom else Result := riloBottomToTop; // restore pixel & cleanup SrcPixel^ := not SrcPixel^; Windows.ReleaseDC(0, DC); if FullScanLine then FreeMem(Scanline); end; function GetBitmapBytes(AWinBmp: Windows.TBitmap; ABitmap: HBITMAP; const ARect: TRect; ALineEnd: TRawImageLineEnd; ALineOrder: TRawImageLineOrder; out AData: Pointer; out ADataSize: PtrUInt): Boolean; var DC: HDC; Info: record Header: Windows.TBitmapInfoHeader; Colors: array[Byte] of TRGBQuad; // reserve extra colors for palette (256 max) end; H: Cardinal; R: TRect; SrcData: PByte; SrcSize: PtrUInt; SrcLineBytes: Cardinal; SrcLineOrder: TRawImageLineOrder; StartScan: Integer; begin SrcLineOrder := GetBitmapOrder(AWinBmp, ABitmap); SrcLineBytes := (AWinBmp.bmWidthBytes + 3) and not 3; if AWinBmp.bmBits <> nil then begin // this is bitmapsection data :) we can just copy the bits // We cannot trust windows with bmWidthBytes. Use SrcLineBytes which takes // DWORD alignment into consideration with AWinBmp do Result := CopyImageData(bmWidth, bmHeight, SrcLineBytes, bmBitsPixel, bmBits, ARect, SrcLineOrder, ALineOrder, ALineEnd, AData, ADataSize); Exit; end; // retrieve the data though GetDIBits // initialize bitmapinfo structure Info.Header.biSize := sizeof(Info.Header); Info.Header.biPlanes := 1; Info.Header.biBitCount := AWinBmp.bmBitsPixel; Info.Header.biCompression := BI_RGB; Info.Header.biSizeImage := 0; Info.Header.biWidth := AWinBmp.bmWidth; H := ARect.Bottom - ARect.Top; // request a top-down DIB if AWinBmp.bmHeight > 0 then begin Info.Header.biHeight := -AWinBmp.bmHeight; StartScan := AWinBmp.bmHeight - ARect.Bottom; end else begin Info.Header.biHeight := AWinBmp.bmHeight; StartScan := ARect.Top; end; // adjust height if StartScan < 0 then begin Inc(H, StartScan); StartScan := 0; end; // alloc buffer SrcSize := SrcLineBytes * H; GetMem(SrcData, SrcSize); DC := Windows.GetDC(0); Result := Windows.GetDIBits(DC, ABitmap, StartScan, H, SrcData, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS) <> 0; Windows.ReleaseDC(0, DC); // since we only got the needed scanlines, adjust top and bottom R.Left := ARect.Left; R.Top := 0; R.Right := ARect.Right; R.Bottom := H; with Info.Header do Result := Result and CopyImageData(biWidth, H, SrcLineBytes, biBitCount, SrcData, R, riloTopToBottom, ALineOrder, ALineEnd, AData, ADataSize); FreeMem(SrcData); end; function RawImage_FromBitmap(out ARawImage: TRawImage; ABitmap, AMask: HBITMAP; ARect: PRect = nil): Boolean; var WinDIB: Windows.TDIBSection; WinBmp: Windows.TBitmap absolute WinDIB.dsBm; ASize: Integer; R: TRect; begin ARawImage.Init; FillChar(WinDIB, SizeOf(WinDIB), 0); ASize := Windows.GetObject(ABitmap, SizeOf(WinDIB), @WinDIB); if ASize = 0 then Exit(False); //DbgDumpBitmap(ABitmap, 'FromBitmap - Image'); //DbgDumpBitmap(AMask, 'FromMask - Mask'); FillRawImageDescription(WinBmp, ARawImage.Description); // if it is not DIB then alpha in bitmaps is not supported => use 0 alpha prec if ASize < SizeOf(WinDIB) then ARawImage.Description.AlphaPrec := 0; if ARect = nil then begin R := Classes.Rect(0, 0, WinBmp.bmWidth, WinBmp.bmHeight); end else begin R := ARect^; if R.Top > WinBmp.bmHeight then R.Top := WinBmp.bmHeight; if R.Bottom > WinBmp.bmHeight then R.Bottom := WinBmp.bmHeight; if R.Left > WinBmp.bmWidth then R.Left := WinBmp.bmWidth; if R.Right > WinBmp.bmWidth then R.Right := WinBmp.bmWidth; end; ARawImage.Description.Width := R.Right - R.Left; ARawImage.Description.Height := R.Bottom - R.Top; // copy bitmap Result := GetBitmapBytes(WinBmp, ABitmap, R, ARawImage.Description.LineEnd, ARawImage.Description.LineOrder, ARawImage.Data, ARawImage.DataSize); // check mask if AMask <> 0 then begin if Windows.GetObject(AMask, SizeOf(WinBmp), @WinBmp) = 0 then Exit(False); Result := GetBitmapBytes(WinBmp, AMask, R, ARawImage.Description.MaskLineEnd, ARawImage.Description.LineOrder, ARawImage.Mask, ARawImage.MaskSize); end else begin ARawImage.Description.MaskBitsPerPixel := 0; end; end; {$ENDIF} function BitmapCreateFromHICON(Handle: HICON): Graphics.TBitmap; var Index: Integer; IconInfo: TIconInfo; ARawImage: TRawImage; AImage: TLazIntfImage; begin Result:= Graphics.TBitmap.Create; if Windows.GetIconInfo(Handle, IconInfo) = False then Exit; if RawImage_FromBitmap(ARawImage, IconInfo.hbmColor, IconInfo.hbmMask) then begin // Check if the bitmap has alpha channel if (ARawImage.Description.BitsPerPixel = 32) and (ScreenInfo.ColorDepth = 32) then begin for Index:= 0 to (ARawImage.DataSize div 4) - 1 do begin if (PLongWord(ARawImage.Data)[Index] shr ARawImage.Description.AlphaShift) and $FF <> 0 then begin ARawImage.Description.AlphaPrec:= 8; Break; end; end; // Invalid alpha channel, use mask instead if ARawImage.Description.AlphaPrec = 0 then begin ARawImage.Description.AlphaPrec:= 8; AImage:= TLazIntfImage.Create(ARawImage, False); AImage.AlphaFromMask(False); AImage.Free; end; end; Result.LoadFromRawImage(ARawImage, True); end; Windows.DeleteObject(IconInfo.hbmMask); Windows.DeleteObject(IconInfo.hbmColor); end; function BitmapCreateFromHBITMAP(Handle: HBITMAP): Graphics.TBitmap; {$IF DEFINED(LCLWIN32)} begin Result:= Graphics.TBitmap.Create; Result.Handle:= Handle; end; {$ELSE} var ARawImage: TRawImage; begin Result:= Graphics.TBitmap.Create; if RawImage_FromBitmap(ARawImage, Handle, 0) then begin Result.LoadFromRawImage(ARawImage, True); end; end; {$ENDIF} end. ����������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/udarkstyle.pas����������������������������������������������������0000644�0001750�0000144�00000022022�14743153644�020710� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Dark mode support unit (Windows 10 + Qt5). Copyright (C) 2019-2021 Richard Yu Copyright (C) 2019-2022 Alexander Koblov (alexx2000@mail.ru) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } unit uDarkStyle; {$mode delphi} interface uses Classes, SysUtils, Windows; var g_buildNumber: DWORD = 0; g_darkModeEnabled: bool = false; g_darkModeSupported: bool = false; {$IF DEFINED(LCLQT5)} procedure ApplyDarkStyle; {$ENDIF} procedure RefreshTitleBarThemeColor(hWnd: HWND); function AllowDarkModeForWindow(hWnd: HWND; allow: bool): bool; implementation uses UxTheme, JwaWinUser, FileInfo, uEarlyConfig {$IF DEFINED(LCLQT5)} , Qt5 {$ENDIF} ; type // Insider 18334 TPreferredAppMode = ( pamDefault, pamAllowDark, pamForceDark, pamForceLight ); var AppMode: TPreferredAppMode; var RtlGetNtVersionNumbers: procedure(major, minor, build: LPDWORD); stdcall; DwmSetWindowAttribute: function(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HRESULT; stdcall; // 1809 17763 _ShouldAppsUseDarkMode: function(): bool; stdcall; // ordinal 132 _AllowDarkModeForWindow: function(hWnd: HWND; allow: bool): bool; stdcall; // ordinal 133 _AllowDarkModeForApp: function(allow: bool): bool; stdcall; // ordinal 135, removed since 18334 _RefreshImmersiveColorPolicyState: procedure(); stdcall; // ordinal 104 _IsDarkModeAllowedForWindow: function(hWnd: HWND): bool; stdcall; // ordinal 137 // Insider 18334 _SetPreferredAppMode: function(appMode: TPreferredAppMode): TPreferredAppMode; stdcall; // ordinal 135, since 18334 function AllowDarkModeForWindow(hWnd: HWND; allow: bool): bool; begin if (g_darkModeSupported) then Result:= _AllowDarkModeForWindow(hWnd, allow) else Result:= false; end; function IsHighContrast(): bool; var highContrast: HIGHCONTRASTW; begin highContrast.cbSize:= SizeOf(HIGHCONTRASTW); if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, SizeOf(highContrast), @highContrast, 0)) then Result:= (highContrast.dwFlags and HCF_HIGHCONTRASTON <> 0) else Result:= false; end; function ShouldAppsUseDarkMode: Boolean; begin Result:= (_ShouldAppsUseDarkMode() or (AppMode = pamForceDark)) and not IsHighContrast(); end; procedure RefreshTitleBarThemeColor(hWnd: HWND); const DWMWA_USE_IMMERSIVE_DARK_MODE_OLD = 19; DWMWA_USE_IMMERSIVE_DARK_MODE_NEW = 20; var dark: BOOL; dwAttribute: DWORD; begin dark:= (_IsDarkModeAllowedForWindow(hWnd) and ShouldAppsUseDarkMode); if (Win32BuildNumber < 19041) then dwAttribute:= DWMWA_USE_IMMERSIVE_DARK_MODE_OLD else begin dwAttribute:= DWMWA_USE_IMMERSIVE_DARK_MODE_NEW; end; DwmSetWindowAttribute(hwnd, dwAttribute, @dark, SizeOf(dark)); end; procedure AllowDarkModeForApp(allow: bool); begin if Assigned(_AllowDarkModeForApp) then _AllowDarkModeForApp(allow) else if Assigned(_SetPreferredAppMode) then begin if (allow) then _SetPreferredAppMode(AppMode) else _SetPreferredAppMode(pamDefault); end; end; {$IF DEFINED(LCLQT5)} procedure ApplyDarkStyle; const StyleName: WideString = 'Fusion'; var AColor: TQColor; APalette: QPaletteH; function QColor(R: Integer; G: Integer; B: Integer; A: Integer = 255): PQColor; begin Result:= @AColor; QColor_fromRgb(Result, R, G, B, A); end; begin g_darkModeEnabled:= True; QApplication_setStyle(QStyleFactory_create(@StyleName)); APalette:= QPalette_Create(); // Modify palette to dark QPalette_setColor(APalette, QPaletteWindow, QColor(53, 53, 53)); QPalette_setColor(APalette, QPaletteWindowText, QColor(255, 255, 255)); QPalette_setColor(APalette, QPaletteDisabled, QPaletteWindowText, QColor(127, 127, 127)); QPalette_setColor(APalette, QPaletteBase, QColor(42, 42, 42)); QPalette_setColor(APalette, QPaletteAlternateBase, QColor(66, 66, 66)); QPalette_setColor(APalette, QPaletteToolTipBase, QColor(255, 255, 255)); QPalette_setColor(APalette, QPaletteToolTipText, QColor(53, 53, 53)); QPalette_setColor(APalette, QPaletteText, QColor(255, 255, 255)); QPalette_setColor(APalette, QPaletteDisabled, QPaletteText, QColor(127, 127, 127)); QPalette_setColor(APalette, QPaletteDark, QColor(35, 35, 35)); QPalette_setColor(APalette, QPaletteLight, QColor(66, 66, 66)); QPalette_setColor(APalette, QPaletteShadow, QColor(20, 20, 20)); QPalette_setColor(APalette, QPaletteButton, QColor(53, 53, 53)); QPalette_setColor(APalette, QPaletteButtonText, QColor(255, 255, 255)); QPalette_setColor(APalette, QPaletteDisabled, QPaletteButtonText, QColor(127, 127, 127)); QPalette_setColor(APalette, QPaletteBrightText, QColor(255, 0, 0)); QPalette_setColor(APalette, QPaletteLink, QColor(42, 130, 218)); QPalette_setColor(APalette, QPaletteHighlight, QColor(42, 130, 218)); QPalette_setColor(APalette, QPaletteDisabled, QPaletteHighlight, QColor(80, 80, 80)); QPalette_setColor(APalette, QPaletteHighlightedText, QColor(255, 255, 255)); QPalette_setColor(APalette, QPaletteDisabled, QPaletteHighlightedText, QColor(127, 127, 127)); QApplication_setPalette(APalette); end; {$ENDIF} const LOAD_LIBRARY_SEARCH_SYSTEM32 = $800; function CheckBuildNumber(buildNumber: DWORD): Boolean; inline; begin Result := (buildNumber = 17763) or // Win 10: 1809 (buildNumber = 18362) or // Win 10: 1903 & 1909 (buildNumber = 19041) or // Win 10: 2004 & 20H2 & 21H1 & 21H2 (buildNumber = 22000) or // Win 11: 21H2 (buildNumber > 22000); // Win 11: Insider Preview end; function GetBuildNumber(Instance: THandle): DWORD; begin try with TVersionInfo.Create do try Load(Instance); Result:= FixedInfo.FileVersion[2]; finally Free; end; except Exit(0); end; end; procedure InitDarkMode(); var hUxtheme: HMODULE; major, minor, build: DWORD; begin @RtlGetNtVersionNumbers := GetProcAddress(GetModuleHandleW('ntdll.dll'), 'RtlGetNtVersionNumbers'); if Assigned(RtlGetNtVersionNumbers) then begin RtlGetNtVersionNumbers(@major, @minor, @build); if (major = 10) and (minor = 0) then begin hUxtheme := LoadLibraryExW('uxtheme.dll', 0, LOAD_LIBRARY_SEARCH_SYSTEM32); if (hUxtheme <> 0) then begin g_buildNumber:= GetBuildNumber(hUxtheme); if CheckBuildNumber(g_buildNumber) then begin @_RefreshImmersiveColorPolicyState := GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104)); @_ShouldAppsUseDarkMode := GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132)); @_AllowDarkModeForWindow := GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133)); if (g_buildNumber < 18362) then @_AllowDarkModeForApp := GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135)) else @_SetPreferredAppMode := GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135)); @_IsDarkModeAllowedForWindow := GetProcAddress(hUxtheme, MAKEINTRESOURCEA(137)); @DwmSetWindowAttribute := GetProcAddress(LoadLibrary('dwmapi.dll'), 'DwmSetWindowAttribute'); if Assigned(_RefreshImmersiveColorPolicyState) and Assigned(_ShouldAppsUseDarkMode) and Assigned(_AllowDarkModeForWindow) and (Assigned(_AllowDarkModeForApp) or Assigned(_SetPreferredAppMode)) and Assigned(_IsDarkModeAllowedForWindow) then begin g_darkModeSupported := true; AppMode := TPreferredAppMode(gAppMode); if AppMode <> pamForceLight then begin AllowDarkModeForApp(true); _RefreshImmersiveColorPolicyState(); g_darkModeEnabled := ShouldAppsUseDarkMode; if g_darkModeEnabled then AppMode := pamForceDark; end; end; end; end; end; end; end; initialization InitDarkMode; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/udclass.pas�������������������������������������������������������0000644�0001750�0000144�00000011460�14743153644�020163� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Setup unique window class name for main form Copyright (C) 2016-2022 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uDClass; {$mode objfpc}{$H+} interface implementation uses Classes, SysUtils, Win32Int, WSLCLClasses, Forms, Windows, Win32Proc, Controls, LCLType, fMain, Win32WSControls, uImport {$IF DEFINED(DARKWIN)} , uDarkStyle {$ENDIF} ; const ClassNameW: PWideChar = 'TTOTAL_CMD'; // for compatibility with plugins function WinRegister: Boolean; var WindowClassW: WndClassW; begin ZeroMemory(@WindowClassW, SizeOf(WndClassW)); with WindowClassW do begin Style := CS_DBLCLKS; LPFnWndProc := @WindowProc; hInstance := System.HInstance; hIcon := Windows.LoadIcon(MainInstance, 'MAINICON'); if hIcon = 0 then hIcon := Windows.LoadIcon(0, IDI_APPLICATION); hCursor := Windows.LoadCursor(0, IDC_ARROW); LPSzClassName := ClassNameW; end; Result := Windows.RegisterClassW(@WindowClassW) <> 0; end; var __GetProp: function(hWnd: HWND; lpString: LPCSTR): HANDLE; stdcall; __SetProp: function(hWnd: HWND; lpString: LPCSTR; hData: HANDLE): WINBOOL; stdcall; __CreateWindowExW: function(dwExStyle: DWORD; lpClassName: LPCWSTR; lpWindowName: LPCWSTR; dwStyle: DWORD; X: longint; Y: longint; nWidth: longint; nHeight: longint; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: LPVOID): HWND; stdcall; function _GetProp(hWnd: HWND; lpString: LPCSTR): HANDLE; stdcall; var Atom: UIntPtr absolute lpString; begin if (Atom > MAXWORD) and (lpString = 'WinControl') then Result:= __GetProp(hWnd, 'WinControlDC') else Result:= __GetProp(hWnd, lpString); end; function _SetProp(hWnd: HWND; lpString: LPCSTR; hData: HANDLE): WINBOOL; stdcall; var Atom: UIntPtr absolute lpString; begin if (Atom > MAXWORD) and (lpString = 'WinControl') then Result:= __SetProp(hWnd, 'WinControlDC', hData) else Result:= __SetProp(hWnd, lpString, hData); end; function _CreateWindowExW(dwExStyle: DWORD; lpClassName: LPCWSTR; lpWindowName: LPCWSTR; dwStyle: DWORD; X: longint; Y: longint; nWidth: longint; nHeight: longint; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: LPVOID): HWND; stdcall; var AParams: PNCCreateParams absolute lpParam; begin if (hWndParent = 0) and Assigned(AParams) and (AParams^.WinControl is TfrmMain) then lpClassName:= ClassNameW; Result:= __CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); end; procedure Initialize; var hModule: THandle; pLibrary, pFunction: PPointer; begin pLibrary:= FindImportLibrary(MainInstance, user32); if Assigned(pLibrary) then begin hModule:= GetModuleHandle(user32); {$IF DEFINED(DARKWIN)} if not g_darkModeEnabled then {$ENDIF} begin pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'CreateWindowExW')); if Assigned(pFunction) then begin WinRegister; Pointer(__CreateWindowExW):= ReplaceImportFunction(pFunction, @_CreateWindowExW); end; end; // Prevent plugins written in Lazarus from crashing by changing the name for // GetProp/SetProp to store control data from 'WinControl' to 'WinControlDC' pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'GetPropA')); if Assigned(pFunction) then begin Pointer(__GetProp):= ReplaceImportFunction(pFunction, @_GetProp); end; pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'SetPropA')); if Assigned(pFunction) then begin Pointer(__SetProp):= ReplaceImportFunction(pFunction, @_SetProp); end; end; Windows.GlobalDeleteAtom(WindowInfoAtom); WindowInfoAtom := Windows.GlobalAddAtom('WindowInfoDC'); end; initialization Initialize; finalization {$IF DEFINED(DARKWIN)} if not g_darkModeEnabled then {$ENDIF} Windows.UnregisterClassW(PWideChar(ClassNameW), System.HInstance); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/udcreadwic.pas����������������������������������������������������0000644�0001750�0000144�00000056412�14743153644�020645� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uDCReadWIC; {$mode delphi} interface uses Windows, Classes, SysUtils, FPImage, Graphics, IntfGraphics, ComObj, ActiveX; const WICDecoder = $01; WICBitmapCacheOnLoad = $2; WICDecodeMetadataCacheOnDemand = 0; CLSID_WICImagingFactory: TGUID = '{CACAF262-9370-4615-A13B-9F5539DA4C0A}'; GUID_WICPixelFormat32bppBGRA: TGUID = '{6FDDC324-4E03-4BFE-B185-3D77768DC90F}'; type PWICColor = ^TWicColor; TWICColor = Cardinal; PWICRect = ^TWICRect; TWICRect = record X: Integer; Y: Integer; Width: Integer; Height: Integer; end; PIWICColorContext = ^IWICColorContext; PWICBitmapPattern = ^TWICBitmapPattern; TWICBitmapPattern = record Position: ULARGE_INTEGER; Length: ULONG; Pattern: PByte; Mask: PByte; EndOfStream: BOOL; end; PPropBag2 = ^TPropBag2; TPropBag2 = record dwType: DWORD; vt: TVarType; cfType: TClipFormat; dwHint: DWORD; pstrName: POleStr; clsid: TCLSID; end; TWICInProcPointer = PByte; TWICPixelFormatGUID = TGUID; TREFWICPixelFormatGUID = PGUID; TWICComponentType = type Integer; TWICDecodeOptions = type Integer; TWICColorContextType = type Integer; TWICBitmapDitherType = type Integer; TWICBitmapPaletteType = type Integer; TWICBitmapInterpolationMode = type Integer; TWICBitmapEncoderCacheOption = type Integer; TWICBitmapTransformOptions = type Integer; TWICBitmapCreateCacheOption = type Integer; TWICBitmapAlphaChannelOption = type Integer; IWICPalette = interface; IWICBitmapLock = interface; IWICBitmapEncoderInfo = interface; IWICBitmapDecoderInfo = interface; IWICBitmapFrameEncode = interface; IWICBitmapFrameDecode = interface; IWICMetadataQueryReader = interface; IWICMetadataQueryWriter = interface; IPropertyBag2 = interface(IUnknown) ['{22F55882-280B-11d0-A8A9-00A0C90C2004}'] function Read(pPropBag: PPropBag2; pErrLog: IErrorLog; pvarValue: PVariant; phrError: PHResult): HRESULT; stdcall; function Write(cProperties: ULONG; pPropBag: PPropBag2; pvarValue: PVariant): HRESULT; stdcall; function CountProperties(var pcProperties: ULONG): HRESULT; stdcall; function GetPropertyInfo(iProperty, cProperties: ULONG; pPropBag: PPropBag2; var pcProperties: ULONG): HRESULT; stdcall; function LoadObject(pstrName:POleStr; dwHint: DWORD; pUnkObject: IUnknown; pErrLog: IErrorLog): HRESULT; stdcall; end; IWICComponentInfo = interface(IUnknown) ['{23BC3F0A-698B-4357-886B-F24D50671334}'] function GetComponentType(var pType: TWICComponentType): HRESULT; stdcall; function GetCLSID(var pclsid: TGUID): HRESULT; stdcall; function GetSigningStatus(var pStatus: DWORD): HRESULT; stdcall; function GetAuthor(cchAuthor: UINT; wzAuthor: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetVendorGUID(var pguidVendor: TGUID): HRESULT; stdcall; function GetVersion(cchVersion: UINT; wzVersion: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetSpecVersion(cchSpecVersion: UINT; wzSpecVersion: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetFriendlyName(cchFriendlyName: UINT; wzFriendlyName: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; end; IWICBitmapSource = interface(IUnknown) ['{00000120-a8f2-4877-ba0a-fd2b6645fb94}'] function GetSize(var puiWidth: UINT; var puiHeight: UINT): HRESULT; stdcall; function GetPixelFormat(var pPixelFormat: TWICPixelFormatGUID): HRESULT; stdcall; function GetResolution(var pDpiX: Double; var pDpiY: Double): HRESULT; stdcall; function CopyPalette(pIPalette: IWICPalette): HRESULT; stdcall; function CopyPixels(prc: PWICRect; cbStride: UINT; cbBufferSize: UINT; pbBuffer: PByte): HRESULT; stdcall; end; IWICBitmap = interface(IWICBitmapSource) ['{00000121-a8f2-4877-ba0a-fd2b6645fb94}'] function Lock(const prcLock: TWICRect; flags: DWORD; out ppILock: IWICBitmapLock): HRESULT; stdcall; function SetPalette(pIPalette: IWICPalette): HRESULT; stdcall; function SetResolution(dpiX: Double; dpiY: Double): HRESULT; stdcall; end; IWICBitmapLock = interface(IUnknown) ['{00000123-a8f2-4877-ba0a-fd2b6645fb94}'] function GetSize(var puiWidth: UINT; var puiHeight: UINT): HRESULT; stdcall; function GetStride(var pcbStride: UINT): HRESULT; stdcall; function GetDataPointer(var pcbBufferSize: UINT; var ppbData: TWICInProcPointer): HRESULT; stdcall; function GetPixelFormat(var pPixelFormat: TWICPixelFormatGUID): HRESULT; stdcall; end; IWICBitmapCodecInfo = interface(IWICComponentInfo) ['{E87A44C4-B76E-4c47-8B09-298EB12A2714}'] function GetContainerFormat(var pguidContainerFormat: TGUID): HRESULT; stdcall; function GetPixelFormats(cFormats: UINT; var guidPixelFormats: PGUID; var pcActual: UINT): HRESULT; stdcall; function GetColorManagementVersion(cchColorManagementVersion: UINT; wzColorManagementVersion: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetDeviceManufacturer(cchDeviceManufacturer: UINT; wzDeviceManufacturer: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetDeviceModels(cchDeviceModels: UINT; wzDeviceModels: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetMimeTypes(cchMimeTypes: UINT; wzMimeTypes: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function GetFileExtensions(cchFileExtensions: UINT; wzFileExtensions: PWCHAR; var pcchActual: UINT): HRESULT; stdcall; function DoesSupportAnimation(var pfSupportAnimation: BOOL): HRESULT; stdcall; function DoesSupportChromakey(var pfSupportChromakey: BOOL): HRESULT; stdcall; function DoesSupportLossless(var pfSupportLossless: BOOL): HRESULT; stdcall; function DoesSupportMultiframe(var pfSupportMultiframe: BOOL): HRESULT; stdcall; function MatchesMimeType(wzMimeType: LPCWSTR; var pfMatches: BOOL): HRESULT; stdcall; end; IWICBitmapEncoder = interface(IUnknown) ['{00000103-a8f2-4877-ba0a-fd2b6645fb94}'] function Initialize(pIStream: IStream; cacheOption: TWICBitmapEncoderCacheOption): HRESULT; stdcall; function GetContainerFormat(var pguidContainerFormat: TGUID): HRESULT; stdcall; function GetEncoderInfo(out ppIEncoderInfo: IWICBitmapEncoderInfo): HRESULT; stdcall; function SetColorContexts(cCount: UINT; ppIColorContext: PIWICColorContext): HRESULT; stdcall; function SetPalette(pIPalette: IWICPalette): HRESULT; stdcall; function SetThumbnail(pIThumbnail: IWICBitmapSource): HRESULT; stdcall; function SetPreview(pIPreview: IWICBitmapSource): HRESULT; stdcall; function CreateNewFrame(out ppIFrameEncode: IWICBitmapFrameEncode; var ppIEncoderOptions: IPropertyBag2): HRESULT; stdcall; function Commit: HRESULT; stdcall; function GetMetadataQueryWriter(out ppIMetadataQueryWriter: IWICMetadataQueryWriter): HRESULT; stdcall; end; IWICBitmapDecoder = interface(IUnknown) ['{9EDDE9E7-8DEE-47ea-99DF-E6FAF2ED44BF}'] function QueryCapability(pIStream: IStream; var pdwCapability: DWORD): HRESULT; stdcall; function Initialize(pIStream: IStream; cacheOptions: TWICDecodeOptions): HRESULT; stdcall; function GetContainerFormat(var pguidContainerFormat: TGUID): HRESULT; stdcall; function GetDecoderInfo(out ppIDecoderInfo: IWICBitmapDecoderInfo): HRESULT; stdcall; function CopyPalette(pIPalette: IWICPalette): HRESULT; stdcall; function GetMetadataQueryReader(out ppIMetadataQueryReader: IWICMetadataQueryReader): HRESULT; stdcall; function GetPreview(out ppIBitmapSource: IWICBitmapSource): HRESULT; stdcall; function GetColorContexts(cCount: UINT; ppIColorContexts: PIWICColorContext; var pcActualCount : UINT): HRESULT; stdcall; function GetThumbnail(out ppIThumbnail: IWICBitmapSource): HRESULT; stdcall; function GetFrameCount(var pCount: UINT): HRESULT; stdcall; function GetFrame(index: UINT; out ppIBitmapFrame: IWICBitmapFrameDecode): HRESULT; stdcall; end; IWICBitmapEncoderInfo = interface(IWICBitmapCodecInfo) ['{94C9B4EE-A09F-4f92-8A1E-4A9BCE7E76FB}'] function CreateInstance(out ppIBitmapEncoder: IWICBitmapEncoder): HRESULT; stdcall; end; IWICBitmapDecoderInfo = interface(IWICBitmapCodecInfo) ['{D8CD007F-D08F-4191-9BFC-236EA7F0E4B5}'] function GetPatterns(cbSizePatterns: UINT; pPatterns: PWICBitmapPattern; var pcPatterns: UINT; var pcbPatternsActual: UINT): HRESULT; stdcall; function MatchesPattern(pIStream: IStream; var pfMatches: BOOL): HRESULT; stdcall; function CreateInstance(out ppIBitmapDecoder: IWICBitmapDecoder): HRESULT; stdcall; end; IWICBitmapFrameEncode = interface(IUnknown) ['{00000105-a8f2-4877-ba0a-fd2b6645fb94}'] function Initialize(pIEncoderOptions: IPropertyBag2): HRESULT; stdcall; function SetSize(uiWidth: UINT; uiHeight: UINT): HRESULT; stdcall; function SetResolution(dpiX: Double; dpiY: Double): HRESULT; stdcall; function SetPixelFormat(var pPixelFormat: TWICPixelFormatGUID): HRESULT; stdcall; function SetColorContexts(cCount: UINT; ppIColorContext: PIWICColorContext): HRESULT; stdcall; function SetPalette(pIPalette: IWICPalette): HRESULT; stdcall; function SetThumbnail(pIThumbnail: IWICBitmapSource): HRESULT; stdcall; function WritePixels(lineCount: UINT; cbStride: UINT; cbBufferSize: UINT; pbPixels: PByte): HRESULT; stdcall; function WriteSource(pIBitmapSource: IWICBitmapSource; prc: PWICRect): HRESULT; stdcall; function Commit: HRESULT; stdcall; function GetMetadataQueryWriter(out ppIMetadataQueryWriter: IWICMetadataQueryWriter): HRESULT; stdcall; end; IWICBitmapFrameDecode = interface(IWICBitmapSource) ['{3B16811B-6A43-4ec9-A813-3D930C13B940}'] function GetMetadataQueryReader(out ppIMetadataQueryReader: IWICMetadataQueryReader): HRESULT; stdcall; function GetColorContexts(cCount: UINT; ppIColorContexts: PIWICColorContext; var pcActualCount : UINT): HRESULT; stdcall; function GetThumbnail(out ppIThumbnail: IWICBitmapSource): HRESULT; stdcall; end; IWICBitmapScaler = interface(IWICBitmapSource) ['{00000302-a8f2-4877-ba0a-fd2b6645fb94}'] function Initialize(pISource: IWICBitmapSource; uiWidth: UINT; uiHeight: UINT; mode: TWICBitmapInterpolationMode): HRESULT; stdcall; end; IWICBitmapClipper = interface(IWICBitmapSource) ['{E4FBCF03-223D-4e81-9333-D635556DD1B5}'] function Initialize(pISource: IWICBitmapSource; var prc: TWICRect): HRESULT; stdcall; end; IWICBitmapFlipRotator = interface(IWICBitmapSource) ['{5009834F-2D6A-41ce-9E1B-17C5AFF7A782}'] function Initialize(pISource: IWICBitmapSource; options: TWICBitmapTransformOptions): HRESULT; stdcall; end; IWICPalette = interface(IUnknown) ['{00000040-a8f2-4877-ba0a-fd2b6645fb94}'] function InitializePredefined(ePaletteType: TWICBitmapPaletteType; fAddTransparentColor: BOOL): HRESULT; stdcall; function InitializeCustom(pColors: PWICColor; cCount: UINT): HRESULT; stdcall; function InitializeFromBitmap(pISurface: IWICBitmapSource; cCount: UINT; fAddTransparentColor: BOOL): HRESULT; stdcall; function InitializeFromPalette(pIPalette: IWICPalette): HRESULT; stdcall; function GetType(var pePaletteType: TWICBitmapPaletteType): HRESULT; stdcall; function GetColorCount(var pcCount: UINT): HRESULT; stdcall; function GetColors(cCount: UINT; pColors: PWICColor; var pcActualColors: UINT): HRESULT; stdcall; function IsBlackWhite(var pfIsBlackWhite: BOOL): HRESULT; stdcall; function IsGrayscale(var pfIsGrayscale: BOOL): HRESULT; stdcall; function HasAlpha(var pfHasAlpha: BOOL): HRESULT; stdcall; end; IWICColorContext = interface(IUnknown) ['{3C613A02-34B2-44ea-9A7C-45AEA9C6FD6D}'] function InitializeFromFilename(wzFilename: LPCWSTR): HRESULT; stdcall; function InitializeFromMemory(const pbBuffer: PByte; cbBufferSize: UINT): HRESULT; stdcall; function InitializeFromExifColorSpace(value: UINT): HRESULT; stdcall; function GetType(var pType: TWICColorContextType): HRESULT; stdcall; function GetProfileBytes(cbBuffer: UINT; pbBuffer: PByte; var pcbActual: UINT): HRESULT; stdcall; function GetExifColorSpace(var pValue: UINT): HRESULT; stdcall; end; IWICColorTransform = interface(IWICBitmapSource) ['{B66F034F-D0E2-40ab-B436-6DE39E321A94}'] function Initialize(pIBitmapSource: IWICBitmapSource; pIContextSource: IWICColorContext; pIContextDest: IWICColorContext; pixelFmtDest: TREFWICPixelFormatGUID): HRESULT; stdcall; end; IWICMetadataQueryReader = interface(IUnknown) ['{30989668-E1C9-4597-B395-458EEDB808DF}'] function GetContainerFormat(var pguidContainerFormat: TGUID): HRESULT; stdcall; function GetLocation(cchMaxLength: UINT; wzNamespace: PWCHAR; var pcchActualLength: UINT): HRESULT; stdcall; function GetMetadataByName(wzName: LPCWSTR; var pvarValue: PROPVARIANT): HRESULT; stdcall; function GetEnumerator(out ppIEnumString: IEnumString): HRESULT; stdcall; end; IWICMetadataQueryWriter = interface(IWICMetadataQueryReader) ['{A721791A-0DEF-4d06-BD91-2118BF1DB10B}'] function SetMetadataByName(wzName: LPCWSTR; const pvarValue: TPropVariant): HRESULT; stdcall; function RemoveMetadataByName(wzName: LPCWSTR): HRESULT; stdcall; end; IWICFastMetadataEncoder = interface(IUnknown) ['{B84E2C09-78C9-4AC4-8BD3-524AE1663A2F}'] function Commit: HRESULT; stdcall; function GetMetadataQueryWriter(out ppIMetadataQueryWriter: IWICMetadataQueryWriter): HRESULT; stdcall; end; IWICStream = interface(IStream) ['{135FF860-22B7-4ddf-B0F6-218F4F299A43}'] function InitializeFromIStream(pIStream: IStream): HRESULT; stdcall; function InitializeFromFilename(wzFileName: LPCWSTR; dwDesiredAccess: DWORD): HRESULT; stdcall; function InitializeFromMemory(pbBuffer: TWICInProcPointer; cbBufferSize: DWORD): HRESULT; stdcall; function InitializeFromIStreamRegion(pIStream: IStream; ulOffset: ULARGE_INTEGER; ulMaxSize: ULARGE_INTEGER): HRESULT; stdcall; end; IWICFormatConverter = interface(IWICBitmapSource) ['{00000301-a8f2-4877-ba0a-fd2b6645fb94}'] function Initialize(pISource: IWICBitmapSource; const dstFormat: TWICPixelFormatGUID; dither: TWICBitmapDitherType; const pIPalette: IWICPalette; alphaThresholdPercent: Double; paletteTranslate: TWICBitmapPaletteType): HRESULT; stdcall; function CanConvert(srcPixelFormat: TREFWICPixelFormatGUID; dstPixelFormat: TREFWICPixelFormatGUID; var pfCanConvert: BOOL): HRESULT; stdcall; end; IWICImagingFactory = interface(IUnknown) ['{ec5ec8a9-c395-4314-9c77-54d7a935ff70}'] function CreateDecoderFromFilename(wzFilename: LPCWSTR; const pguidVendor: TGUID; dwDesiredAccess: DWORD; metadataOptions: TWICDecodeOptions; out ppIDecoder: IWICBitmapDecoder): HRESULT; stdcall; function CreateDecoderFromStream(pIStream: IStream; const pguidVendor: TGUID; metadataOptions: TWICDecodeOptions; out ppIDecoder: IWICBitmapDecoder): HRESULT; stdcall; function CreateDecoderFromFileHandle(hFile: ULONG_PTR; const pguidVendor: TGUID; metadataOptions: TWICDecodeOptions; out ppIDecoder: IWICBitmapDecoder): HRESULT; stdcall; function CreateComponentInfo(const clsidComponent: TGUID; out ppIInfo: IWICComponentInfo): HRESULT; stdcall; function CreateDecoder(const guidContainerFormat: TGUID; const pguidVendor: TGUID; out ppIDecoder: IWICBitmapDecoder): HRESULT; stdcall; function CreateEncoder(const guidContainerFormat: TGUID; const pguidVendor: TGUID; out ppIEncoder: IWICBitmapEncoder): HRESULT; stdcall; function CreatePalette(out ppIPalette: IWICPalette): HRESULT; stdcall; function CreateFormatConverter(out ppIFormatConverter: IWICFormatConverter): HRESULT; stdcall; function CreateBitmapScaler(out ppIBitmapScaler: IWICBitmapScaler): HRESULT; stdcall; function CreateBitmapClipper(out ppIBitmapClipper: IWICBitmapClipper): HRESULT; stdcall; function CreateBitmapFlipRotator(out ppIBitmapFlipRotator: IWICBitmapFlipRotator): HRESULT; stdcall; function CreateStream(out ppIWICStream: IWICStream): HRESULT; stdcall; function CreateColorContext(out ppIWICColorContext: IWICColorContext): HRESULT; stdcall; function CreateColorTransformer(out ppIWICColorTransform: IWICColorTransform): HRESULT; stdcall; function CreateBitmap(uiWidth: UINT; uiHeight: UINT; pixelFormat: TREFWICPixelFormatGUID; option: TWICBitmapCreateCacheOption; out ppIBitmap: IWICBitmap): HRESULT; stdcall; function CreateBitmapFromSource(pIBitmapSource: IWICBitmapSource; option: TWICBitmapCreateCacheOption; out ppIBitmap: IWICBitmap): HRESULT; stdcall; function CreateBitmapFromSourceRect(pIBitmapSource: IWICBitmapSource; x: UINT; y: UINT; width: UINT; height: UINT; out ppIBitmap: IWICBitmap): HRESULT; stdcall; function CreateBitmapFromMemory(uiWidth: UINT; uiHeight: UINT; const pixelFormat: TWICPixelFormatGUID; cbStride: UINT; cbBufferSize: UINT; pbBuffer: PByte; out ppIBitmap: IWICBitmap): HRESULT; stdcall; function CreateBitmapFromHBITMAP(hBitmap: HBITMAP; hPalette: HPALETTE; options: TWICBitmapAlphaChannelOption; out ppIBitmap: IWICBitmap): HRESULT; stdcall; function CreateBitmapFromHICON(hIcon: HICON; out ppIBitmap: IWICBitmap): HRESULT; stdcall; function CreateComponentEnumerator(componentTypes: DWORD; options: DWORD; out ppIEnumUnknown: IEnumUnknown): HRESULT; stdcall; function CreateFastMetadataEncoderFromDecoder(pIDecoder: IWICBitmapDecoder; out ppIFastEncoder: IWICFastMetadataEncoder): HRESULT; stdcall; function CreateFastMetadataEncoderFromFrameDecode(pIFrameDecoder: IWICBitmapFrameDecode; out ppIFastEncoder: IWICFastMetadataEncoder): HRESULT; stdcall; function CreateQueryWriter(const guidMetadataFormat: TGUID; const pguidVendor: TGUID; out ppIQueryWriter: IWICMetadataQueryWriter): HRESULT; stdcall; function CreateQueryWriterFromReader(pIQueryReader: IWICMetadataQueryReader; const pguidVendor: TGUID; out ppIQueryWriter: IWICMetadataQueryWriter): HRESULT; stdcall; end; type { TImageReaderWIC } TImageReaderWIC = class(TFPCustomImageReader) private FBitmapDecoder: IWICBitmapDecoder; protected procedure InternalRead({%H-}Str: TStream; Img: TFPCustomImage); override; function InternalCheck(Str: TStream): Boolean; override; end; { TImageWIC } TImageWIC = class(TFPImageBitmap) protected class function GetReaderClass: TFPCustomImageReaderClass; override; public class var Extensions: String; class function GetFileExtensions: String; override; end; implementation uses GraphType, DCOSUtils; var ImagingFactory: IWICImagingFactory; WICConvertBitmapSource: function(const dstFormat: TWICPixelFormatGUID; pISrc: IWICBitmapSource; out ppIDst: IWICBitmapSource): HRESULT; stdcall; const CLSID_WICPngDecoder: TGUID = '{389ea17b-5078-4cde-b6ef-25c15175c751}'; CLSID_WICPngDecoder1: TGUID = '{389ea17b-5078-4cde-b6ef-25c15175c751}'; CLSID_WICPngDecoder2: TGUID = '{e018945b-aa86-4008-9bd4-6777a1e40c11}'; CLSID_WICBmpDecoder: TGUID = '{6b462062-7cbf-400d-9fdb-813dd10f2778}'; CLSID_WICIcoDecoder: TGUID = '{c61bfcdf-2e0f-4aad-a8d7-e06bafebcdfe}'; CLSID_WICJpegDecoder: TGUID = '{9456a480-e88b-43ea-9e73-0b2d9b71b1ca}'; CLSID_WICGifDecoder: TGUID = '{381dda3c-9ce9-4834-a23e-1f98f8fc52be}'; CLSID_WICTiffDecoder: TGUID = '{b54e85d9-fe23-499f-8b88-6acea713752b}'; CLSID_WICCurDecoder: TGUID = '{22696B76-881B-48D7-88F0-DC6111FF9F0B}'; CLSID_WICHeicDecoder: TGUID = '{E9A4A80A-44FE-4DE4-8971-7150B10A5199}'; CLSID_WICIgnoreDecoders: array[0..9] of PGUID = ( @CLSID_WICPngDecoder, @CLSID_WICPngDecoder1, @CLSID_WICPngDecoder2, @CLSID_WICBmpDecoder, @CLSID_WICIcoDecoder, @CLSID_WICJpegDecoder, @CLSID_WICGifDecoder, @CLSID_WICTiffDecoder, @CLSID_WICCurDecoder, @CLSID_WICHeicDecoder ); { TImageWIC } class function TImageWIC.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TImageReaderWIC; end; class function TImageWIC.GetFileExtensions: String; begin Result:= Extensions; end; { TImageReaderWIC } procedure TImageReaderWIC.InternalRead(Str: TStream; Img: TFPCustomImage); var AWidth: Cardinal = 0; AHeight: Cardinal = 0; BitmapObject: IWICBitmap; BitmapSource: IWICBitmapSource; Description: TRawImageDescription; BitmapFrame: IWICBitmapFrameDecode; begin OleCheck(FBitmapDecoder.GetFrame(0, BitmapFrame)); OleCheck(ImagingFactory.CreateBitmapFromSource(BitmapFrame, WICBitmapCacheOnLoad, BitmapObject)); OleCheck(BitmapObject.GetSize(AWidth, AHeight)); OleCheck(WICConvertBitmapSource(GUID_WICPixelFormat32bppBGRA, BitmapObject, BitmapSource)); Description.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight); TLazIntfImage(Img).DataDescription:= Description; OleCheck(BitmapSource.CopyPixels(nil, AWidth * 4, AWidth * AHeight * 4, TLazIntfImage(Img).PixelData)); end; function TImageReaderWIC.InternalCheck(Str: TStream): Boolean; var AStream: IStream; begin AStream:= TStreamAdapter.Create(Str); try Result:= (ImagingFactory.CreateDecoderFromStream(AStream, GUID_NULL, WICDecodeMetadataCacheOnDemand, FBitmapDecoder) = S_OK); finally AStream:= nil; end; end; function IsStandardDecoder(const pclsid: TGUID): Boolean; var Index: Integer; begin for Index:= 0 to High(CLSID_WICIgnoreDecoders) do begin if IsEqualGUID(pclsid, CLSID_WICIgnoreDecoders[Index]^) then Exit(True); end; Result:= False; end; procedure Initialize; var AClass: TGUID; ATemp: String; hModule: TLibHandle; cbActual: ULONG = 0; cchActual: UINT = 0; dwOptions: DWORD = 0; ACodec: IUnknown = nil; AInfo: IWICBitmapCodecInfo; wzFileExtensions: UnicodeString; ppIEnumUnknown: IEnumUnknown = nil; begin if (Win32MajorVersion > 5) then try OleInitialize(nil); OleCheck(CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, ImagingFactory)); OleCheck(ImagingFactory.CreateComponentEnumerator(WICDecoder, dwOptions, ppIEnumUnknown)); SetLength(wzFileExtensions, MaxSmallint + 1); while(ppIEnumUnknown.Next(1, ACodec, @cbActual) = S_OK) do begin if (ACodec.QueryInterface(IWICBitmapCodecInfo, AInfo) = S_OK) then begin // Skip standard decoders if (AInfo.GetCLSID(AClass) = S_OK) then begin if IsStandardDecoder(AClass) then Continue; end; if (AInfo.GetFileExtensions(MaxSmallint, PWideChar(wzFileExtensions), cchActual) = S_OK) then begin ATemp:= UTF8Encode(Copy(wzFileExtensions, 1, cchActual - 1)); TImageWIC.Extensions+= StringReplace(StringReplace(ATemp, ',', ';', [rfReplaceAll]), '.', '', [rfReplaceAll]) + ';'; end; end; end; if (Length(TImageWIC.Extensions) > 0) then begin hModule:= LoadLibraryExW('WindowsCodecs.dll', 0, LOAD_LIBRARY_SEARCH_SYSTEM32); if (hModule <> NilHandle) then begin @WICConvertBitmapSource:= SafeGetProcAddress(hModule, 'WICConvertBitmapSource'); ImageHandlers.RegisterImageReader('Windows Imaging Component', TImageWIC.Extensions, TImageReaderWIC); TPicture.RegisterFileFormat(TImageWIC.Extensions, 'Windows Imaging Component', TImageWIC); end; end; except // Skip end; end; initialization Initialize; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/ufileunlock.pas���������������������������������������������������0000644�0001750�0000144�00000041762�14743153644�021055� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileUnlock; {$mode delphi}{$R-} interface uses Classes, SysUtils; type TProcessInfo = record ProcessId: DWORD; FileHandle: THandle; ApplicationName: String; ExecutablePath: String; end; TProcessInfoArray = array of TProcessInfo; function TerminateProcess(ProcessId: DWORD): Boolean; function FileUnlock(ProcessId: DWORD; hFile: THandle): Boolean; function GetFileInUseProcessFast(const FileName: String; out ProcessInfo: TProcessInfoArray): Boolean; function GetFileInUseProcessSlow(const FileName: String; LastError: Integer; var ProcessInfo: TProcessInfoArray): Boolean; implementation uses JwaWinType, JwaNative, JwaNtStatus, JwaPsApi, Windows, DCConvertEncoding, DCWindows; const RstrtMgr = 'RstrtMgr.dll'; const PROCESS_QUERY_LIMITED_INFORMATION = $1000; CCH_RM_MAX_SVC_NAME = 63; CCH_RM_MAX_APP_NAME = 255; RM_SESSION_KEY_LEN = SizeOf(TGUID); CCH_RM_SESSION_KEY = RM_SESSION_KEY_LEN * 2; type TRMAppType = ( RmUnknownApp = 0, RmMainWindow = 1, RmOtherWindow = 2, RmService = 3, RmExplorer = 4, RmConsole = 5, RmCritical = 1000 ); PRMUniqueProcess = ^TRMUniqueProcess; TRMUniqueProcess = record dwProcessId: DWORD; ProcessStartTime: TFileTime; end; PRMProcessInfo = ^TRMProcessInfo; TRMProcessInfo = record Process: TRMUniqueProcess; strAppName: array[0..CCH_RM_MAX_APP_NAME] of WideChar; strServiceShortName: array[0..CCH_RM_MAX_SVC_NAME] of WideChar; ApplicationType: TRMAppType; AppStatus: ULONG; TSSessionId: DWORD; bRestartable: BOOL; end; PSystemHandleInformationFx = ^TSystemHandleInformationFx; TSystemHandleInformationFx = record Count: ULONG; Handle: array[0..0] of TSystemHandleInformation; end; TSystemHandleTableEntryInfoEx = record Object_: PVOID; ProcessId: ULONG_PTR; Handle: ULONG_PTR; GrantedAccess: ULONG; CreatorBackTraceIndex: USHORT; ObjectTypeNumber: USHORT; HandleAttributes: ULONG; Reserved: ULONG; end; PSystemHandleInformationEx = ^TSystemHandleInformationEx; TSystemHandleInformationEx = record Count: ULONG_PTR; Reserved: ULONG_PTR; Handle: array[0..0] of TSystemHandleTableEntryInfoEx; end; var RmStartSession: function (pSessionHandle: LPDWORD; dwSessionFlags: DWORD; strSessionKey: LPWSTR): DWORD; stdcall; RmEndSession: function (dwSessionHandle: DWORD): DWORD; stdcall; RmRegisterResources: function(dwSessionHandle: DWORD; nFiles: UINT; rgsFileNames: LPPWSTR; nApplications: UINT; rgApplications: PRMUniqueProcess; nServices: UINT; rgsServiceNames: LPPWSTR): DWORD; stdcall; RmGetList: function(dwSessionHandle: DWORD; pnProcInfoNeeded: PUINT; pnProcInfo: PUINT; rgAffectedApps: PRMProcessInfo; lpdwRebootReasons: LPDWORD): DWORD; stdcall; QueryFullProcessImageNameW: function(hProcess: HANDLE; dwFlags: DWORD; lpExeName: LPWSTR; lpdwSize: PDWORD): BOOL; stdcall; GetFinalPathNameByHandleW: function(hFile: HANDLE; lpszFilePath: LPWSTR; cchFilePath: DWORD; dwFlags: DWORD): DWORD; stdcall; NtQueryObject: function(ObjectHandle : HANDLE; ObjectInformationClass : OBJECT_INFORMATION_CLASS; ObjectInformation : PVOID; ObjectInformationLength : ULONG; ReturnLength : PULONG): NTSTATUS; stdcall; var RstrtMgrLib: HMODULE = 0; GetFileName: function(hFile: HANDLE): UnicodeString; function _wcsnicmp(const s1, s2: pwidechar; count: ptruint): integer; cdecl; external 'msvcrt.dll'; function GetFileHandleList(out SystemInformation : PSystemHandleInformationEx): Boolean; const MEM_SIZE = SizeOf(TSystemHandleInformationEx); var Index: Integer; Status: NTSTATUS; SystemInformationLength : ULONG = MEM_SIZE; SystemInformationOld : PSystemHandleInformationFx; begin if CheckWin32Version(5, 1) then begin SystemInformation:= GetMem(MEM_SIZE); repeat Status:= NtQuerySystemInformation(TSystemInformationClass(64), SystemInformation, SystemInformationLength, @SystemInformationLength); if Status = STATUS_INFO_LENGTH_MISMATCH then begin SystemInformationLength+= SizeOf(TSystemHandleTableEntryInfoEx) * 100; ReAllocMem(SystemInformation, SystemInformationLength); end; until Status <> STATUS_INFO_LENGTH_MISMATCH; Result:= (Status = STATUS_SUCCESS); if not Result then FreeMem(SystemInformation); end else begin SystemInformationOld:= GetMem(MEM_SIZE); repeat Status:= NtQuerySystemInformation(SystemHandleInformation, SystemInformationOld, SystemInformationLength, @SystemInformationLength); if Status = STATUS_INFO_LENGTH_MISMATCH then begin SystemInformationLength+= SizeOf(TSystemHandleInformation) * 100; ReAllocMem(SystemInformationOld, SystemInformationLength); end; until Status <> STATUS_INFO_LENGTH_MISMATCH; Result:= (Status = STATUS_SUCCESS); if Result then begin SystemInformation:= GetMem(SystemInformationOld.Count * SizeOf(TSystemHandleTableEntryInfoEx) + SizeOf(TSystemHandleInformationEx)); for Index := 0 to SystemInformationOld.Count - 1 do begin with SystemInformation.Handle[Index] do begin Handle:= SystemInformationOld.Handle[Index].Handle; Object_:= SystemInformationOld.Handle[Index].Object_; ProcessId:= SystemInformationOld.Handle[Index].ProcessId; GrantedAccess:= SystemInformationOld.Handle[Index].GrantedAccess; ObjectTypeNumber:= SystemInformationOld.Handle[Index].ObjectTypeNumber; end; end; SystemInformation.Count:= SystemInformationOld.Count; end; FreeMem(SystemInformationOld); end; end; function GetFileNameOld(hFile: HANDLE): UnicodeString; const MAX_SIZE = SizeOf(TObjectNameInformation) + MAXWORD; var ReturnLength : ULONG; ObjectInformation : PObjectNameInformation; begin ObjectInformation:= GetMem(MAX_SIZE); if (NtQueryObject(hFile, ObjectNameInformation, ObjectInformation, MAXWORD, @ReturnLength) <> STATUS_SUCCESS) then Result:= EmptyWideStr else begin SetLength(Result, ObjectInformation^.Name.Length div SizeOf(WideChar)); Move(ObjectInformation^.Name.Buffer^, Result[1], ObjectInformation^.Name.Length); end; FreeMem(ObjectInformation); end; function GetFileNameNew(hFile: HANDLE): UnicodeString; begin SetLength(Result, maxSmallint + 1); SetLength(Result, GetFinalPathNameByHandleW(hFile, PWideChar(Result), maxSmallint, 0)); end; var FileHandleType: ULONG; function GetFileHandleType: ULONG; var Index: DWORD; Handle: THandle; ProcessId: DWORD; SystemInformation : PSystemHandleInformationEx; begin Handle:= FileOpen('NUL', fmOpenRead or fmShareDenyNone); if Handle <> feInvalidHandle then begin if GetFileHandleList(SystemInformation) then begin ProcessId:= GetCurrentProcessId; for Index:= 0 to SystemInformation^.Count - 1 do begin if (SystemInformation^.Handle[Index].Handle = Handle) and (SystemInformation^.Handle[Index].ProcessId = ProcessId) then begin Result:= SystemInformation^.Handle[Index].ObjectTypeNumber; Break; end; end; FreeMem(SystemInformation); end; FileClose(Handle); end; end; function GetProcessFileName(hProcess: HANDLE): UnicodeString; var dwSize: DWORD; begin if (Win32MajorVersion < 6) then begin SetLength(Result, maxSmallint + 1); SetLength(Result, GetModuleFileNameExW(hProcess, 0, PWideChar(Result), maxSmallint)); end else begin dwSize:= maxSmallint; SetLength(Result, dwSize + 1); if QueryFullProcessImageNameW(hProcess, 0, PWideChar(Result), @dwSize) then begin SetLength(Result, dwSize); end else begin SetLength(Result, 0); end; end; end; function GetModuleFileName(hProcess, hModule: HANDLE): UnicodeString; begin SetLength(Result, maxSmallint + 1); SetLength(Result, GetModuleFileNameExW(hProcess, hModule, PWideChar(Result), maxSmallint)); end; function GetNativeName(const FileName: String; out NativeName: UnicodeString): Boolean; var hFile: HANDLE; begin hFile := CreateFileW(PWideChar(UTF16LongName(FileName)), FILE_READ_ATTRIBUTES, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING, 0, 0); Result:= (hFile <> INVALID_HANDLE_VALUE); if Result then begin NativeName:= GetFileName(hFile); CloseHandle(hFile); end; end; function CheckHandleType(hFile: HANDLE): Boolean; var hFileMap: HANDLE; begin hFileMap:= CreateFileMappingW(hFile, nil, PAGE_READONLY, 0, 1, nil); Result:= (hFileMap <> 0); if Result then CloseHandle(hFileMap) else begin Result:= (GetLastError <> ERROR_BAD_EXE_FORMAT); end; end; procedure AddLock(var ProcessInfo: TProcessInfoArray; ProcessId: DWORD; Process, FileHandle: HANDLE); var Index: Integer; begin for Index:= 0 to High(ProcessInfo) do begin if (ProcessInfo[Index].ProcessId = ProcessId) then begin if (ProcessInfo[Index].FileHandle = 0) and (FileHandle <> 0) then begin ProcessInfo[Index].FileHandle:= FileHandle; Exit; end; end; end; Index:= Length(ProcessInfo); SetLength(ProcessInfo, Index + 1); ProcessInfo[Index].ProcessId:= ProcessId; ProcessInfo[Index].FileHandle:= FileHandle; ProcessInfo[Index].ExecutablePath:= CeUtf16ToUtf8(GetProcessFileName(Process)); end; procedure GetModuleInUseProcess(const FileName: String; var ProcessInfo: TProcessInfoArray); var I, J: Integer; hProcess: HANDLE; cbNeeded: DWORD = 0; AFileName, AOpenName: UnicodeString; dwProcessList: array[0..4095] of DWORD; hModuleList: array [0..4095] of HMODULE; begin if EnumProcesses(@dwProcessList[0], SizeOf(dwProcessList), cbNeeded) then begin AFileName:= CeUtf8ToUtf16(FileName); for I:= 0 to (cbNeeded div SizeOf(DWORD)) do begin hProcess:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, dwProcessList[I]); if (hProcess <> 0) then begin if EnumProcessModules(hProcess, @hModuleList[0], SizeOf(hModuleList), cbNeeded) then begin for J:= 0 to (cbNeeded div SizeOf(HMODULE)) do begin AOpenName:= GetModuleFileName(hProcess, hModuleList[J]); if (Length(AOpenName) = Length(AFileName)) then begin if (_wcsnicmp(PWideChar(AOpenName), PWideChar(AFileName), Length(AFileName)) = 0) then begin AddLock(ProcessInfo, dwProcessList[I], hProcess, 0); Break; end; end; end; end; CloseHandle(hProcess); end; end; end; end; procedure GetFileInUseProcess(const FileName: String; var ProcessInfo: TProcessInfoArray); var hFile: HANDLE; Index: Integer; ALength: Integer; hProcess: HANDLE; hCurrentProcess: HANDLE; AFileName, AOpenName: UnicodeString; SystemInformation : PSystemHandleInformationEx; begin if GetNativeName(FileName, AFileName) and GetFileHandleList(SystemInformation) then begin ALength:= Length(AFileName); hCurrentProcess:= GetCurrentProcess; for Index:= 0 to SystemInformation^.Count - 1 do begin if (SystemInformation^.Handle[Index].ObjectTypeNumber = FileHandleType) then begin hProcess:= OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, SystemInformation^.Handle[Index].ProcessId); if (hProcess <> 0) then begin if DuplicateHandle(hProcess, SystemInformation^.Handle[Index].Handle, hCurrentProcess, @hFile, 0, False, DUPLICATE_SAME_ACCESS) then begin if CheckHandleType(hFile) then begin AOpenName:= GetFileName(hFile); if Length(AOpenName) >= ALength then begin if (_wcsnicmp(PWideChar(AOpenName), PWideChar(AFileName), ALength) = 0) then begin if (Length(AOpenName) = ALength) or (AOpenName[ALength + 1] = PathDelim) then AddLock(ProcessInfo, SystemInformation^.Handle[Index].ProcessId, hProcess, SystemInformation^.Handle[Index].Handle); end; end; end; CloseHandle(hFile); end; CloseHandle(hProcess); end; end; end; FreeMem(SystemInformation); end; end; function GetFileInUseProcessFast(const FileName: String; out ProcessInfo: TProcessInfoArray): Boolean; const MAX_CNT = 64; var I: Integer; dwReason: DWORD; dwSession: DWORD; hProcess: HANDLE; nProcInfoNeeded: UINT; rgsFileNames: PWideChar; nProcInfo: UINT = MAX_CNT; ftCreation, ftDummy: TFileTime; szSessionKey: array[0..CCH_RM_SESSION_KEY] of WideChar; rgAffectedApps: array[0..MAX_CNT - 1] of TRMProcessInfo; begin if (RstrtMgrLib = 0) then Exit(False); ZeroMemory(@szSessionKey[0], SizeOf(szSessionKey)); Result:= (RmStartSession(@dwSession, 0, szSessionKey) = ERROR_SUCCESS); if Result then try rgsFileNames:= PWideChar(CeUtf8ToUtf16(FileName)); Result:= (RmRegisterResources(dwSession, 1, @rgsFileNames, 0, nil, 0, nil) = ERROR_SUCCESS) and (RmGetList(dwSession, @nProcInfoNeeded, @nProcInfo, rgAffectedApps, @dwReason) = ERROR_SUCCESS); if Result then begin Result:= (nProcInfo > 0); SetLength(ProcessInfo, nProcInfo); for I:= 0 to nProcInfo - 1 do begin ProcessInfo[I].ProcessId:= rgAffectedApps[I].Process.dwProcessId; ProcessInfo[I].ApplicationName:= CeUtf16ToUtf8(UnicodeString(rgAffectedApps[I].strAppName)); hProcess:= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, rgAffectedApps[I].Process.dwProcessId); if hProcess <> 0 then try if GetProcessTimes(hProcess, ftCreation, ftDummy, ftDummy, ftDummy) and (CompareFileTime(@rgAffectedApps[I].Process.ProcessStartTime, @ftCreation) = 0) then begin ProcessInfo[I].ExecutablePath:= CeUtf16ToUtf8(GetProcessFileName(hProcess)); end; finally CloseHandle(hProcess); end; end; end; finally RmEndSession(dwSession); end; end; function GetFileInUseProcessSlow(const FileName: String; LastError: Integer; var ProcessInfo: TProcessInfoArray): Boolean; begin if (Win32MajorVersion < 6) and (LastError = ERROR_ACCESS_DENIED) then begin GetModuleInUseProcess(FileName, ProcessInfo) end; if (LastError = ERROR_SHARING_VIOLATION) then begin GetFileInUseProcess(FileName, ProcessInfo); end; Result:= (Length(ProcessInfo) > 0); end; function TerminateProcess(ProcessId: DWORD): Boolean; var hProcess: HANDLE; begin hProcess:= OpenProcess(SYNCHRONIZE or PROCESS_TERMINATE, False, ProcessId); Result:= (hProcess <> 0); if Result then begin Result:= Windows.TerminateProcess(hProcess, 1); CloseHandle(hProcess); end; end; function FileUnlock(ProcessId: DWORD; hFile: THandle): Boolean; var hProcess: HANDLE; hDuplicate: HANDLE; begin Result:= False; hProcess:= OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessId); if (hProcess <> 0) then begin if (DuplicateHandle(hProcess, hFile, GetCurrentProcess, @hDuplicate, 0, False, DUPLICATE_SAME_ACCESS or DUPLICATE_CLOSE_SOURCE)) then begin Result:= CloseHandle(hDuplicate); end; CloseHandle(hProcess); end; end; procedure GetFileHandleTypeThread({%H-}Parameter : Pointer); begin FileHandleType:= GetFileHandleType; end; procedure Initialize; var SystemDirectory: UnicodeString; begin if Win32MajorVersion < 6 then begin GetFileName:= @GetFileNameOld; @NtQueryObject:= GetProcAddress(GetModuleHandleW(ntdll), 'NtQueryObject'); end else begin SetLength(SystemDirectory, maxSmallint + 1); SetLength(SystemDirectory, GetSystemDirectoryW(Pointer(SystemDirectory), maxSmallint)); RstrtMgrLib:= LoadLibraryW(PWideChar(SystemDirectory + PathDelim + RstrtMgr)); if RstrtMgrLib <> 0 then begin @RmStartSession := GetProcAddress(RstrtMgrLib, 'RmStartSession'); @RmEndSession := GetProcAddress(RstrtMgrLib, 'RmEndSession'); @RmRegisterResources := GetProcAddress(RstrtMgrLib, 'RmRegisterResources'); @RmGetList := GetProcAddress(RstrtMgrLib, 'RmGetList'); end; GetFileName:= @GetFileNameNew; @QueryFullProcessImageNameW:= GetProcAddress(GetModuleHandleW(Kernel32), 'QueryFullProcessImageNameW'); @GetFinalPathNameByHandleW:= GetProcAddress(GetModuleHandleW(Kernel32), 'GetFinalPathNameByHandleW'); end; TThread.ExecuteInThread(@GetFileHandleTypeThread, nil); end; initialization Initialize; end. ��������������doublecmd-1.1.22/src/platform/win/ugdiplus.pas������������������������������������������������������0000644�0001750�0000144�00000037764�14743153644�020400� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains some GDI+ API functions Copyright (C) 2008-2020 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uGdiPlus; {$mode delphi} {$pointermath on} interface uses Windows, ActiveX, FPImage, Classes; type GPSTATUS = ( Ok, GenericError, InvalidParameter, OutOfMemory, ObjectBusy, InsufficientBuffer, NotImplemented, Win32Error, WrongState, Aborted, FileNotFound, ValueOverflow, AccessDenied, UnknownImageFormat, FontFamilyNotFound, FontStyleNotFound, NotTrueTypeFont, UnsupportedGdiplusVersion, GdiplusNotInitialized, PropertyNotFound, PropertyNotSupported ); GpColorAdjustType = ( ColorAdjustTypeDefault = 0, ColorAdjustTypeBitmap = 1, ColorAdjustTypeBrush = 2, ColorAdjustTypePen = 3, ColorAdjustTypeText = 4, ColorAdjustTypeCount = 5, ColorAdjustTypeAny = 6 ); GpUnit = ( UnitWorld = 0, UnitDisplay = 1, UnitPixel = 2, UnitPoint = 3, UnitInch = 4, UnitDocument = 5, UnitMillimeter = 6 ); const GdipPixelFormatIndexed = $00010000; // Indexes into a palette GdipPixelFormatGDI = $00020000; // Is a GDI-supported format GdipPixelFormatAlpha = $00040000; // Has an alpha component GdipPixelFormatPAlpha = $00080000; // Pre-multiplied alpha GdipPixelFormatExtended = $00100000; // Extended color 16 bits/channel GdipPixelFormatCanonical = $00200000; type GPPIXELFORMAT = ( // ... PixelFormat16bppGrayScale = ( 4 or (16 shl 8) or GdipPixelFormatExtended), PixelFormat24bppRGB = ( 8 or (24 shl 8) or GdipPixelFormatGDI), PixelFormat32bppRGB = ( 9 or (32 shl 8) or GdipPixelFormatGDI), PixelFormat32bppARGB = (10 or (32 shl 8) or GdipPixelFormatAlpha or GdipPixelFormatGDI or GdipPixelFormatCanonical), PixelFormat32bppPARGB = (11 or (32 shl 8) or GdipPixelFormatAlpha or GdipPixelFormatPAlpha or GdipPixelFormatGDI) // ... ); GpGraphics = Pointer; GpImage = Pointer; GpBitmap = Pointer; GpImageAttributes = Pointer; type TDebugEventLevel = (DebugEventLevelFatal, DebugEventLevelWarning); // Callback function that GDI+ can call, on debug builds, for assertions // and warnings. TDebugEventProc = procedure(level: TDebugEventLevel; message: PChar); stdcall; // Notification functions which the user must call appropriately if // "SuppressBackgroundThread" (below) is set. TNotificationHookProc = function(out token: ULONG): GPSTATUS; stdcall; TNotificationUnhookProc = procedure(token: ULONG); stdcall; // Input structure for GdiplusStartup GdiplusStartupInput = packed record GdiplusVersion : Cardinal; // Must be 1 DebugEventCallback : TDebugEventProc; // Ignored on free builds SuppressBackgroundThread: BOOL; // FALSE unless you're prepared to call // the hook/unhook functions properly SuppressExternalCodecs : BOOL; // FALSE unless you want GDI+ only to use end; // its internal image codecs. TGdiplusStartupInput = GdiplusStartupInput; PGdiplusStartupInput = ^TGdiplusStartupInput; // Output structure for GdiplusStartup() GdiplusStartupOutput = packed record NotificationHook : TNotificationHookProc; NotificationUnhook: TNotificationUnhookProc; end; TGdiplusStartupOutput = GdiplusStartupOutput; PGdiplusStartupOutput = ^TGdiplusStartupOutput; PGdiPlusBitmapData = ^GdiPlusBitmapData; GdiPlusBitmapData = packed record Width: UINT; Height: UINT; Stride: UINT; PixelFormat: GPPIXELFORMAT; Scan0: LPBYTE; Reserved: UINT_PTR; end; PARGBQUAD = ^ARGBQUAD; ARGBQUAD = record rgbBlue : BYTE; rgbGreen : BYTE; rgbRed : BYTE; rgbAlpha : BYTE; end; const GdipImageLockModeRead = 1; GdipImageLockModeWrite = 2; GdipImageLockModeUserInputBuf = 4; var IsGdiPlusLoaded: Boolean = False; GdiplusStartup: function (out token: ULONG; input: PGdiplusStartupInput; output: PGdiplusStartupOutput): GPSTATUS; stdcall; GdiplusShutdown: procedure (token: ULONG); stdcall; GdipCreateBitmapFromHICON: function (hicon: HICON; out bitmap: GPBITMAP): GPSTATUS; stdcall; GdipCreateBitmapFromHBITMAP: function (hbitmap: HBITMAP; hpalette: HPALETTE; out bitmap: GPBITMAP): GPSTATUS; stdcall; GdipCreateBitmapFromScan0: function (Width, Height: Integer; Stride: Integer; PixelFormat: GPPIXELFORMAT; Scan0: LPBYTE; out bitmap: GPBITMAP): GPSTATUS; stdcall; GdipCreateBitmapFromGraphics: function (Width, Height: Integer; graphics: GPGRAPHICS; out bitmap: GPBITMAP): GPSTATUS; stdcall; GdipCreateFromHDC: function (hdc: HDC; out graphics: GPGRAPHICS): GPSTATUS; stdcall; GdipDrawImageRectI: function (graphics: GPGRAPHICS; image: GPIMAGE; x: Integer; y: Integer; width: Integer; height: Integer): GPSTATUS; stdcall; GdipDrawImageRectRectI: function (graphics: GPGRAPHICS; image: GPIMAGE; dstx, dsty, dstwidth, dstheight: Integer; srcx, srcy, srcwidth, srcheight: Integer; srcUnit: GpUnit; imageattr: GPIMAGEATTRIBUTES; abortCallback: Pointer = nil; callbackData: Pointer = nil): GPSTATUS; stdcall; GdipLoadImageFromStream: function (stream: IStream; out image: GPIMAGE): GPSTATUS; stdcall; GdipDisposeImage: function (image: GPIMAGE): GPSTATUS; stdcall; GdipDeleteGraphics: function (graphics: GPGRAPHICS): GPSTATUS; stdcall; GdipGraphicsClear: function (graphics: GPGRAPHICS; color: Integer): GPSTATUS; stdcall; GdipSetInterpolationMode: function (graphics: GPGRAPHICS; interpolation: Integer): GPSTATUS; stdcall; GdipCreateImageAttributes: function (out imageattr: GPIMAGEATTRIBUTES): GPSTATUS; stdcall; GdipDisposeImageAttributes: function (imageattr: GPIMAGEATTRIBUTES): GPSTATUS; stdcall; GdipSetImageAttributesColorKeys: function (imageattr: GPIMAGEATTRIBUTES; ColorAdjustType: GpColorAdjustType; Enable: BOOL; ColorLow: LONG; ColorHigh: LONG): GPSTATUS; stdcall; GdipBitmapLockBits: function (bitmap: GPBITMAP; rect: LPRECT; flags: UINT; PixelFormat: GPPIXELFORMAT; lockedData: PGdiPlusBitmapData): GPSTATUS; stdcall; GdipBitmapUnlockBits: function (bitmap: GPBITMAP; lockedData: PGdiPlusBitmapData): GPSTATUS; stdcall; GdipGetImagePixelFormat: function (image: GPIMAGE; out pixelFormat: GPPIXELFORMAT): GPSTATUS; stdcall; GdipGetImageWidth: function (image: GPIMAGE; out width: cardinal): GPSTATUS; stdcall; GdipGetImageHeight: function (image: GPIMAGE; out height: cardinal): GPSTATUS; stdcall; function GdiPlusLoadFromStream(Str: TStream; Img: TFPCustomImage; out PixelFormat: GPPIXELFORMAT): GPSTATUS; function GdiPlusStretchDraw(hicn: hIcon; hCanvas: HDC; X, Y, cxWidth, cyHeight: Integer): Boolean; overload; function GdiPlusStretchDraw(himl: hImageList; ImageIndex: Integer; hCanvas: HDC; X, Y, cxWidth, cyHeight: Integer): Boolean; overload; implementation uses CommCtrl, IntfGraphics, GraphType; var StartupInput: TGDIPlusStartupInput; gdiplusToken: ULONG; function GetBitmapPixels(hDC: HDC; BitmapInfo: LPBITMAPINFO; hBitmap: HBITMAP): PBYTE; begin; // Buffer must be aligned to DWORD (it should automatically be on a 32-bit machine). Result := GetMem(BitmapInfo^.bmiHeader.biWidth * BitmapInfo^.bmiHeader.biHeight * BitmapInfo^.bmiHeader.biBitCount shr 3); if GetDIBits(hDC, hBitmap, 0, BitmapInfo^.bmiHeader.biHeight, Result, BitmapInfo, DIB_RGB_COLORS) = 0 then begin Freemem(Result); Result := nil; end; end; function GetBitmapFromARGBPixels(graphics: GPGRAPHICS; pixels: LPBYTE; Width, Height: Integer): GPBITMAP; var x, y: Integer; pSrc, pDst: LPDWORD; bmBounds: TRECT; bmData: GdiPlusBitmapData; begin if GdipCreateBitmapFromGraphics(Width, Height, graphics, Result) <> ok then Exit(nil); Windows.SetRect(@bmBounds, 0, 0, Width, Height); if GdipBitmapLockBits(Result, @bmBounds, GdipImageLockModeWrite, PixelFormat32bppARGB, @bmData) <> ok then begin GdipDisposeImage(Result); Exit(nil); end; pSrc := LPDWORD(pixels); pDst := LPDWORD(bmData.Scan0); // Pixels retrieved by GetDIBits are bottom-up, left-right. for x := 0 to Width - 1 do for y := 0 to Height - 1 do pDst[(Height - 1 - y) * Width + x] := pSrc[y * Width + x]; GdipBitmapUnlockBits(Result, @bmData); end; function HasAlphaChannel(pixels: LPBYTE; Width, Height: Integer): Boolean; var i: Integer; begin for i := 0 to Width * Height - 1 do begin if PARGBQUAD(pixels)[i].rgbAlpha <> 0 then Exit(True); end; Result := False; end; function GdiPlusLoadFromStream(Str: TStream; Img: TFPCustomImage; out PixelFormat: GPPIXELFORMAT): GPSTATUS; var AImage: GpImage; bmBounds: TRect; AStream: IStream; bmData: GdiPlusBitmapData; AWidth, AHeight: Cardinal; Description: TRawImageDescription; begin AStream:= TStreamAdapter.Create(Str); try Result:= GdipLoadImageFromStream(AStream, AImage); if (Result = Ok) then begin Result:= GdipGetImageWidth(AImage, AWidth); if Result = Ok then begin Result:= GdipGetImageHeight(AImage, AHeight); if Result = Ok then begin Result:= GdipGetImagePixelFormat(AImage, PixelFormat); if Result = Ok then begin Description.Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight); TLazIntfImage(Img).DataDescription:= Description; Windows.SetRect(@bmBounds, 0, 0, AWidth, AHeight); Result:= GdipBitmapLockBits(AImage, @bmBounds, GdipImageLockModeRead, PixelFormat24bppRGB, @bmData); if Result = Ok then begin Move(bmData.Scan0^, TLazIntfImage(Img).PixelData^, bmData.Stride * bmData.Height); GdipBitmapUnlockBits(AImage, @bmData); end; end; end; end; GdipDisposeImage(AImage); end; finally AStream:= nil; end; end; function GdiPlusStretchDraw(hicn: hIcon; hCanvas: HDC; X, Y, cxWidth, cyHeight: Integer): Boolean; overload; var pIcon: GPIMAGE; pCanvas: GPGRAPHICS; IconInfo: TICONINFO; BitmapInfo: TBITMAPINFO; pixels: LPBYTE = nil; begin Result:= False; if GetIconInfo(hicn, IconInfo) = False then Exit; try GdipCreateFromHDC(hCanvas, pCanvas); // Prepare bitmap info structure. FillMemory(@BitmapInfo, sizeof(BitmapInfo), 0); BitmapInfo.bmiHeader.biSize := Sizeof(BitmapInfo.bmiHeader); GetDIBits(hCanvas, IconInfo.hbmColor, 0, 0, nil, @BitmapInfo, 0); if (BitmapInfo.bmiHeader.biBitCount = 32) then { only 32bpp } begin // Get pixels data. pixels := GetBitmapPixels(hCanvas, @BitmapInfo, IconInfo.hbmColor); // Check if the bitmap has alpha channel (have to be 32bpp to have ARGB format). if HasAlphaChannel(pixels, BitmapInfo.bmiHeader.biWidth, BitmapInfo.bmiHeader.biHeight) then begin // GdipCreateBitmapFromHICON and GdipCreateBitmapFromHBITMAP functions // destroy alpha channel (they write alpha=255 for each pixel). // Copy the ARGB values manually. pIcon := GetBitmapFromARGBPixels(pCanvas, pixels, BitmapInfo.bmiHeader.biWidth, BitmapInfo.bmiHeader.biHeight); end else // This is OK for bitmaps without alpha channel or < 32bpp. GdipCreateBitmapFromHICON(hicn, pIcon); end else // This is OK for bitmaps without alpha channel or < 32bpp. GdipCreateBitmapFromHICON(hicn, pIcon); Result:= GdipDrawImageRectI(pCanvas, pIcon, X, Y, cxWidth, cyHeight) = Ok; finally GdipDisposeImage(pIcon); GdipDeleteGraphics(pCanvas); DeleteObject(IconInfo.hbmColor); DeleteObject(IconInfo.hbmMask); if Assigned(pixels) then Freemem(pixels); end; end; function GdiPlusStretchDraw(himl: hImageList; ImageIndex: Integer; hCanvas: HDC; X, Y, cxWidth, cyHeight: Integer): Boolean; overload; var hicn: HICON; begin Result:= False; try hicn:= ImageList_ExtractIcon(0, himl, ImageIndex); Result:= GdiPlusStretchDraw(hicn, hCanvas, X, Y, cxWidth, cyHeight); finally DestroyIcon(hicn); end; end; var hLib: HMODULE; procedure Initialize; begin hLib:= LoadLibrary('gdiplus.dll'); if (hLib <> 0) then begin @GdiplusStartup:= GetProcAddress(hLib, 'GdiplusStartup'); @GdiplusShutdown:= GetProcAddress(hLib, 'GdiplusShutdown'); @GdipCreateBitmapFromHICON:= GetProcAddress(hLib, 'GdipCreateBitmapFromHICON'); @GdipCreateBitmapFromHBITMAP:= GetProcAddress(hLib, 'GdipCreateBitmapFromHBITMAP'); @GdipCreateBitmapFromScan0:= GetProcAddress(hLib, 'GdipCreateBitmapFromScan0'); @GdipCreateBitmapFromGraphics:= GetProcAddress(hLib, 'GdipCreateBitmapFromGraphics'); @GdipCreateFromHDC:= GetProcAddress(hLib, 'GdipCreateFromHDC'); @GdipDrawImageRectI:= GetProcAddress(hLib, 'GdipDrawImageRectI'); @GdipDrawImageRectRectI:= GetProcAddress(hLib, 'GdipDrawImageRectRectI'); @GdipLoadImageFromStream:= GetProcAddress(hLib, 'GdipLoadImageFromStream'); @GdipDisposeImage:= GetProcAddress(hLib, 'GdipDisposeImage'); @GdipDeleteGraphics:= GetProcAddress(hLib, 'GdipDeleteGraphics'); @GdipGraphicsClear:= GetProcAddress(hLib, 'GdipGraphicsClear'); @GdipSetInterpolationMode:= GetProcAddress(hLib, 'GdipSetInterpolationMode'); @GdipCreateImageAttributes:= GetProcAddress(hLib, 'GdipCreateImageAttributes'); @GdipDisposeImageAttributes:= GetProcAddress(hLib, 'GdipDisposeImageAttributes'); @GdipSetImageAttributesColorKeys:= GetProcAddress(hLib, 'GdipSetImageAttributesColorKeys'); @GdipBitmapLockBits:= GetProcAddress(hLib, 'GdipBitmapLockBits'); @GdipBitmapUnlockBits:= GetProcAddress(hLib, 'GdipBitmapUnlockBits'); @GdipGetImagePixelFormat:= GetProcAddress(hLib, 'GdipGetImagePixelFormat'); @GdipGetImageWidth:= GetProcAddress(hLib, 'GdipGetImageWidth'); @GdipGetImageHeight:= GetProcAddress(hLib, 'GdipGetImageHeight'); // Initialize GDI+ StartupInput structure StartupInput.DebugEventCallback:= nil; StartupInput.SuppressBackgroundThread:= False; StartupInput.SuppressExternalCodecs:= False; StartupInput.GdiplusVersion:= 1; // Initialize GDI+ IsGdiPlusLoaded:= (GdiplusStartup(gdiplusToken, @StartupInput, nil) = Ok); end; end; procedure Finalize; begin if (hLib <> 0) then begin // Close GDI+ if IsGdiPlusLoaded then GdiplusShutdown(gdiplusToken); FreeLibrary(hLib); end; end; initialization Initialize; finalization Finalize; end. ������������doublecmd-1.1.22/src/platform/win/ugdiplusjpeg.pas��������������������������������������������������0000644�0001750�0000144�00000004116�14743153644�021227� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGdiPlusJPEG; {$mode delphi} interface uses Classes, SysUtils, FPImage, Graphics, IntfGraphics; type { TGdiPlusReaderJPEG } TGdiPlusReaderJPEG = class(TFPCustomImageReader) private FGrayscale: Boolean; protected procedure InternalRead(Str: TStream; Img: TFPCustomImage); override; function InternalCheck(Str: TStream): boolean; override; end; { TGdiPlusJPEGImage } TGdiPlusJPEGImage = class(TJPEGImage) protected procedure InitializeReader({%H-}AImage: TLazIntfImage; {%H-}AReader: TFPCustomImageReader); override; procedure FinalizeReader({%H-}AReader: TFPCustomImageReader); override; class function GetReaderClass: TFPCustomImageReaderClass; override; end; implementation uses GraphType, LCLStrConsts, SysConst, DCOSUtils, uGdiPlus; { TGdiPlusJPEGImage } procedure TGdiPlusJPEGImage.InitializeReader(AImage: TLazIntfImage; AReader: TFPCustomImageReader); begin end; procedure TGdiPlusJPEGImage.FinalizeReader(AReader: TFPCustomImageReader); begin PBoolean(@GrayScale)^ := TGdiPlusReaderJPEG(AReader).FGrayScale; end; class function TGdiPlusJPEGImage.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TGdiPlusReaderJPEG; end; { TGdiPlusReaderJPEG } procedure TGdiPlusReaderJPEG.InternalRead(Str: TStream; Img: TFPCustomImage); var Result: GPSTATUS; PixelFormat: GPPIXELFORMAT; begin Result:= GdiPlusLoadFromStream(Str, Img, PixelFormat); if (Result <> Ok) then raise Exception.CreateFmt(SUnknownErrorCode, [Result]); FGrayScale:= (PixelFormat = PixelFormat16bppGrayScale); end; function TGdiPlusReaderJPEG.InternalCheck(Str: TStream): boolean; begin Result:= TJpegImage.IsStreamFormatSupported(Str); end; procedure Initialize; begin if IsGdiPlusLoaded then try // Replace image handler GraphicFilter(TJPEGImage); TPicture.UnregisterGraphicClass(TJPEGImage); TPicture.RegisterFileFormat(TJpegImage.GetFileExtensions, rsJpeg, TGdiPlusJPEGImage); except // Skip end; end; initialization Initialize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/uimport.pas�������������������������������������������������������0000644�0001750�0000144�00000010647�14743153644�020232� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uImport; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Windows; function FindImportLibrary(hModule: THandle; pLibName: PAnsiChar): PPointer; function FindImportFunction(pLibrary: PPointer; pFunction: Pointer): PPointer; function ReplaceImportFunction(pOldFunction: PPointer; pNewFunction: Pointer): Pointer; function FindDelayImportLibrary(hModule: THandle; pLibName: PAnsiChar): Pointer; function FindDelayImportFunction(hModule: THandle; pImpDesc: PIMAGE_DELAYLOAD_DESCRIPTOR; pFuncName: PAnsiChar): PPointer; procedure ReplaceDelayImportFunction(hModule: THandle; pImpDesc: PIMAGE_DELAYLOAD_DESCRIPTOR; pFuncName: PAnsiChar; pNewFunction: Pointer); implementation type {$IFDEF WIN64} PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS64; {$ELSE} PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS32; {$ENDIF} function FindImageDirectory(hModule: THandle; Index: Integer; out DataDir: PIMAGE_DATA_DIRECTORY): Pointer; var pNTHeaders: PIMAGE_NT_HEADERS; pModule: PByte absolute hModule; pDosHeader: PIMAGE_DOS_HEADER absolute hModule; begin if pDosHeader^.e_magic = IMAGE_DOS_SIGNATURE then begin pNTHeaders := @pModule[pDosHeader^.e_lfanew]; if pNTHeaders^.Signature = IMAGE_NT_SIGNATURE then begin DataDir := @pNTHeaders^.OptionalHeader.DataDirectory[Index]; Result := @pModule[DataDir^.VirtualAddress]; Exit; end; end; Result := nil; end; function FindImportLibrary(hModule: THandle; pLibName: PAnsiChar): PPointer; var pEnd: PByte; pImpDir: PIMAGE_DATA_DIRECTORY; pImpDesc: PIMAGE_IMPORT_DESCRIPTOR; pModule: PAnsiChar absolute hModule; begin pImpDesc := FindImageDirectory(hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, pImpDir); if pImpDesc = nil then Exit(nil); pEnd := PByte(pImpDesc) + pImpDir^.Size; while (PByte(pImpDesc) < pEnd) and (pImpDesc^.FirstThunk <> 0) do begin if StrIComp(@pModule[pImpDesc^.Name], pLibName) = 0 then begin Result := @pModule[pImpDesc^.FirstThunk]; Exit; end; Inc(pImpDesc); end; Result := nil; end; function FindImportFunction(pLibrary: PPointer; pFunction: Pointer): PPointer; begin while Assigned(pLibrary^) do begin if pLibrary^ = pFunction then Exit(pLibrary); Inc(pLibrary); end; Result := nil; end; function ReplaceImportFunction(pOldFunction: PPointer; pNewFunction: Pointer): Pointer; var dwOldProtect: DWORD = 0; begin if VirtualProtect(pOldFunction, SizeOf(Pointer), PAGE_READWRITE, dwOldProtect) then begin Result := pOldFunction^; pOldFunction^ := pNewFunction; VirtualProtect(pOldFunction, SizeOf(Pointer), dwOldProtect, dwOldProtect); end; end; function FindDelayImportLibrary(hModule: THandle; pLibName: PAnsiChar): Pointer; var pEnd: PByte; pImpDir: PIMAGE_DATA_DIRECTORY; pImpDesc: PIMAGE_DELAYLOAD_DESCRIPTOR; pModule: PAnsiChar absolute hModule; begin pImpDesc := FindImageDirectory(hModule, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, pImpDir); if pImpDesc = nil then Exit(nil); pEnd := PByte(pImpDesc) + pImpDir^.Size; while (PByte(pImpDesc) < pEnd) and (pImpDesc^.DllNameRVA > 0) do begin if StrIComp(@pModule[pImpDesc^.DllNameRVA], pLibName) = 0 then Exit(pImpDesc); Inc(pImpDesc); end; Result := nil; end; function FindDelayImportFunction(hModule: THandle; pImpDesc: PIMAGE_DELAYLOAD_DESCRIPTOR; pFuncName: PAnsiChar): PPointer; var pImpName: PIMAGE_IMPORT_BY_NAME; pImgThunkName: PIMAGE_THUNK_DATA; pImgThunkAddr: PIMAGE_THUNK_DATA; pModule: PAnsiChar absolute hModule; begin pImgThunkName:= @pModule[pImpDesc^.ImportNameTableRVA]; pImgThunkAddr:= @pModule[pImpDesc^.ImportAddressTableRVA]; while (pImgThunkName^.u1.Ordinal <> 0) do begin if not (IMAGE_SNAP_BY_ORDINAL(pImgThunkName^.u1.Ordinal)) then begin pImpName:= @pModule[pImgThunkName^.u1.AddressOfData]; if (StrIComp(pImpName^.Name, pFuncName) = 0) then Exit(PPointer(@pImgThunkAddr^.u1._Function)); end; Inc(pImgThunkName); Inc(pImgThunkAddr); end; Result:= nil; end; procedure ReplaceDelayImportFunction(hModule: THandle; pImpDesc: PIMAGE_DELAYLOAD_DESCRIPTOR; pFuncName: PAnsiChar; pNewFunction: Pointer); var pOldFunction: PPointer; begin pOldFunction:= FindDelayImportFunction(hModule, pImpDesc, pFuncName); if Assigned(pOldFunction) then ReplaceImportFunction(pOldFunction, pNewFunction); end; end. �����������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/ulistgetpreviewbitmap.pas�����������������������������������������0000644�0001750�0000144�00000004370�14743153644�023166� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Lister plugins thumbnail provider Copyright (C) 2018 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uListGetPreviewBitmap; {$mode objfpc}{$H+} interface uses Classes, SysUtils, WlxPlugin; implementation uses Types, Graphics, DCOSUtils, uThumbnails, uWlxModule, uBitmap, uGlobs; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; const MAX_LEN = 8192; var Data: String; Index: Integer; Bitmap: HBITMAP; Handle: THandle; Module: TWlxModule; begin if gWLXPlugins.Count = 0 then Exit(nil); SetLength(Data, MAX_LEN); Handle:= mbFileOpen(aFileName, fmOpenRead or fmShareDenyNone); if (Handle = feInvalidHandle) then Exit(nil); Index:= FileRead(Handle, Data[1], MAX_LEN); if Index >= 0 then SetLength(Data, Index); FileClose(Handle); for Index:= 0 to gWLXPlugins.Count - 1 do begin Module:= gWLXPlugins.GetWlxModule(Index); if Module.FileParamVSDetectStr(aFileName, True) then begin if (Module.IsLoaded or Module.LoadModule) and Module.CanPreview then begin Bitmap:= Module.CallListGetPreviewBitmap(aFileName, aSize.cx, aSize.cy, Data); if Bitmap <> 0 then begin Result:= BitmapCreateFromHBITMAP(Bitmap); Exit; end; end; end; end; Result:= nil; end; initialization TThumbnailManager.RegisterProvider(@GetThumbnail); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/umywindows.pas����������������������������������������������������0000644�0001750�0000144�00000122706�14743153644�020760� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains specific WINDOWS functions. Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uMyWindows; {$mode objfpc}{$H+} interface uses Graphics, Classes, SysUtils, JwaWinType, JwaWinBase, JwaNative, Windows; const // STORAGE_BUS_TYPE BusTypeUnknown = $00; BusTypeUsb = $07; BusTypeSd = $0C; BusTypeMmc = $0D; function IsWow64: BOOL; procedure ShowWindowEx(hWnd: HWND); function FindMainWindow(ProcessId: DWORD): HWND; function GetMenuItemText(hMenu: HMENU; uItem: UINT; fByPosition: LongBool): UnicodeString; function GetMenuItemType(hMenu: HMENU; uItem: UINT; fByPosition: LongBool): UINT; function InsertMenuItemEx(hMenu, SubMenu: HMENU; Caption: PWideChar; Position, ItemID, ItemType : UINT; Bitmap:Graphics.TBitmap = nil): boolean; function RegReadKey(ARoot: HKEY; const APath, AName: UnicodeString; out AValue: UnicodeString): Boolean; {en Extracts volume GUID from a volume GUID path } function ExtractVolumeGUID(const VolumeName: UnicodeString): UnicodeString; {en Retrieves a volume GUID path for the volume that is associated with the specified volume mount point (drive letter, volume GUID path, or mounted folder) @param(Path The string that contains the path of a mounted folder or a drive letter) @returns(Volume GUID path) } function GetMountPointVolumeName(const Path: UnicodeString): UnicodeString; {en Checks readiness of a drive @param(sDrv String specifying the root directory of a file system volume) @returns(The function returns @true if drive is ready, @false otherwise) } function mbDriveReady(const sDrv: String): Boolean; {en Get the label of a file system volume @param(sDrv String specifying the root directory of a file system volume) @param(bVolReal @true if it a real file system volume) @returns(The function returns volume label) } function mbGetVolumeLabel(const sDrv: String; const bVolReal: Boolean): String; {en Set the label of a file system volume @param(sRootPathName String specifying the root directory of a file system volume) @param(sVolumeName String specifying a new name for the volume) @returns(The function returns @true if successful, @false otherwise) } function mbSetVolumeLabel(sRootPathName, sVolumeName: String): Boolean; {en Wait for change disk label @param(sDrv String specifying the root directory of a file system volume) @param(sCurLabel Current volume label) } procedure mbWaitLabelChange(const sDrv: String; const sCurLabel: String); {en Close CD/DVD drive @param(sDrv String specifying the root directory of a drive) } procedure mbCloseCD(const sDrv: String); function mbGetDriveType(Drive: AnsiChar): UInt32; function mbDriveBusType(Drive: AnsiChar): UInt32; {en Get physical drive serial number } function mbGetDriveSerialNumber(Drive: AnsiChar): String; procedure mbDriveUnlock(const sDrv: String); {en Get remote file name by local file name @param(sLocalName String specifying the local file name) @returns(The function returns remote file name) } function mbGetRemoteFileName(const sLocalName: String): String; {en Retrieves the short path form of the specified path @param(sLongPath The path string) @param(sShortPath A string to receive the short form of the path that sLongPath specifies) @returns(The function returns @true if successful, @false otherwise) } function mbGetShortPathName(const sLongPath: String; var sShortPath: AnsiString): Boolean; {en Retrieves Network Error } function mbWinNetErrorMessage(dwError: DWORD): String; {en Retrieves the current status of the specified service } function GetServiceStatus(const AName: String): DWORD; {en The QueryDirectoryFile routine returns various kinds of information about files in the directory specified by a given file handle. } function QueryDirectoryFile(Handle: THandle; FileInfo: PVOID; FileInfoLength: ULONG; FileInfoClass: TFileInformationClass; ReturnSingleEntry: Boolean; const FileName: UnicodeString; RestartScan: Boolean): Boolean; {en Retrieves owner of the file (user and group). Both user and group contain computer name. @param(sPath Absolute path to the file. May be UNC path.) @param(sUser Returns user name of the file.) @param(sGroup Returns primary group of the file.) } function GetFileOwner(const sPath: String; out sUser, sGroup: String): Boolean; {en Retrieves a description of file's type. @param(sPath Absolute path to the file.) } function GetFileDescription(const sPath: String): String; {en Retrieves file system name of the volume that sRootPath points to. @param(sRootPath Root directory of the volume, for example C:\) } function mbGetFileSystem(const sRootPath: String): String; {en Retrieves the actual number of bytes of disk storage used to store a specified file. @param(FileName The name of the file.) } function mbGetCompressedFileSize(const FileName: String): Int64; {en Retrieves the time the file was changed. } function mbGetFileChangeTime(const FileName: String; out ChangeTime: TFileTime): Boolean; {en Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyStateEx. } function GetAsyncKeyStateEx(vKey: Integer): Boolean; {en This routine returns @true if the caller's process is a member of the Administrators local group. @returns(The function returns @true if caller has Administrators local group, @false otherwise) } function IsUserAdmin: TDuplicates; {en This routine returns @true if the caller's process is running in the remote desktop session } function RemoteSession: Boolean; {en Creates windows shortcut file (.lnk) } procedure CreateShortcut(const Target, Shortcut: String); {en Extract file attributes from find data record. Removes reparse point attribute if a reparse point tag is not a name surrogate. @param(FindData Find data record from FindFirstFile/FindNextFile function.) } function ExtractFileAttributes(const FindData: TWin32FindDataW): DWORD; function CheckPhotosVersion: Boolean; procedure UpdateEnvironment; procedure FixCommandLineToUTF8; implementation uses JwaNtStatus, ShellAPI, MMSystem, JwaWinNetWk, JwaWinUser, JwaVista, LazUTF8, SysConst, ActiveX, ShlObj, ComObj, DCWindows, DCConvertEncoding, uShlObjAdditional; var Wow64DisableWow64FsRedirection: function(OldValue: PPointer): BOOL; stdcall; Wow64RevertWow64FsRedirection: function(OldValue: Pointer): BOOL; stdcall; type PHandleData = ^THandleData; THandleData = record ProcessId: DWORD; WindowHandle: HWND; end; function IsMainWindow(Handle: HWND): Boolean; begin Result:= (GetWindow(Handle, GW_OWNER) = 0) and IsWindowVisible(Handle); end; function EnumWindowsCallback(Handle: HWND; lParam: LPARAM): BOOL; stdcall; var ProcessId: DWORD = 0; Data: PHandleData absolute lParam; begin GetWindowThreadProcessId(Handle, @ProcessId); Result:= (Data^.ProcessId <> ProcessId) or (not IsMainWindow(Handle)); if not Result then Data^.WindowHandle:= Handle; end; procedure ShowWindowEx(hWnd: HWND); var Placement: TWindowPlacement; begin ZeroMemory(@Placement, SizeOf(TWindowPlacement)); Placement.length:= SizeOf(TWindowPlacement); GetWindowPlacement(hWnd, Placement); case (Placement.showCmd) of SW_SHOWMAXIMIZED: ShowWindow(hWnd, SW_SHOWMAXIMIZED); SW_SHOWMINIMIZED: ShowWindow(hWnd, SW_RESTORE); else ShowWindow(hWnd, SW_NORMAL); end; SetForegroundWindow(hWnd); end; function FindMainWindow(ProcessId: DWORD): HWND; var Data: THandleData; begin Data.WindowHandle:= 0; Data.ProcessId:= ProcessId; EnumWindows(@EnumWindowsCallback, {%H-}LPARAM(@Data)); Result:= Data.WindowHandle; end; function GetMenuItemText(hMenu: HMENU; uItem: UINT; fByPosition: LongBool): UnicodeString; var miiw: TMenuItemInfoW; wca: array[0..Pred(MAX_PATH)] of WideChar; begin Result:= EmptyWideStr; FillChar(miiw, SizeOf(TMenuItemInfoW), 0); with miiw do begin cbSize:= SizeOf(TMenuItemInfoW); fMask:= MIIM_FTYPE or MIIM_STRING; dwTypeData:= @wca[0]; cch:= MAX_PATH; end; if GetMenuItemInfoW(hMenu, uItem, fByPosition, miiw) then begin Result:= miiw.dwTypeData; end; end; function GetMenuItemType(hMenu: HMENU; uItem: UINT; fByPosition: LongBool): UINT; var miiw: TMenuItemInfoW; begin Result:= 0; FillChar(miiw, SizeOf(TMenuItemInfoW), 0); with miiw do begin cbSize:= SizeOf(TMenuItemInfoW); fMask:= MIIM_FTYPE; end; if GetMenuItemInfoW(hMenu, uItem, fByPosition, miiw) then begin Result:= miiw.fType; end; end; function InsertMenuItemEx(hMenu, SubMenu: HMENU; Caption: PWideChar; Position, ItemID, ItemType : UINT; Bitmap:Graphics.TBitmap): boolean; var mi: TMenuItemInfoW; begin FillChar(mi, SizeOf(mi), 0); with mi do begin cbSize := SizeOf(mi); case ItemType of MFT_SEPARATOR: begin fMask := MIIM_STATE or MIIM_TYPE or MIIM_ID; end; MFT_STRING: begin fMask := MIIM_BITMAP or MIIM_STRING or MIIM_SUBMENU or MIIM_ID; if BitMap<>nil then hbmpItem:=Bitmap.Handle; end; end; fType := ItemType; fState := MFS_ENABLED; wID := ItemID; hSubMenu := SubMenu; dwItemData := 0; dwTypeData := Caption; cch := SizeOf(Caption); end; Result := InsertMenuItemW(hMenu, Position, True, mi); end; function RegReadKey(ARoot: HKEY; const APath, AName: UnicodeString; out AValue: UnicodeString): Boolean; var AKey: HKEY = 0; dwSize: DWORD = MaxSmallint; begin Result:= RegOpenKeyExW(ARoot, PWideChar(APath), 0, KEY_READ, AKey) = ERROR_SUCCESS; if Result then begin SetLength(AValue, MaxSmallint); Result:= RegQueryValueExW(AKey, PWideChar(AName), nil, nil, PByte(AValue), @dwSize) = ERROR_SUCCESS; if Result then begin dwSize:= dwSize div SizeOf(WideChar); if (dwSize > 0) and (AValue[dwSize] = #0) then Dec(dwSize); SetLength(AValue, dwSize); end; RegCloseKey(AKey); end; end; function DisplayName(const wsDrv: UnicodeString): UnicodeString; var Index: Integer; SFI: TSHFileInfoW; begin FillChar(SFI, SizeOf(SFI), 0); if SHGetFileInfoW(PWideChar(wsDrv), 0, SFI, SizeOf(SFI), SHGFI_DISPLAYNAME) = 0 then Result:= EmptyWideStr else begin Result:= SFI.szDisplayName; Index:= Pos('(', Result); if Index > 1 then SetLength(Result, Index - 2); end; end; function ExtractVolumeGUID(const VolumeName: UnicodeString): UnicodeString; var I, J: LongInt; begin I:= Pos('{', VolumeName); J:= Pos('}', VolumeName); if (I = 0) or (J = 0) then Exit(EmptyWideStr); Result:= Copy(VolumeName, I, J - I + 1); end; function GetMountPointVolumeName(const Path: UnicodeString): UnicodeString; const MAX_VOLUME_NAME = 50; var wsPath: UnicodeString; wsVolumeName: array[0..Pred(MAX_VOLUME_NAME)] of WideChar; begin FillByte(wsVolumeName, MAX_VOLUME_NAME, 0); wsPath:= IncludeTrailingPathDelimiter(Path); if not GetVolumeNameForVolumeMountPointW(PWideChar(wsPath), wsVolumeName, MAX_VOLUME_NAME) then Result:= EmptyWideStr else Result:= UnicodeString(wsVolumeName); end; function mbDriveReady(const sDrv: String): Boolean; var NotUsed: DWORD = 0; wsDrv: UnicodeString; begin wsDrv:= CeUtf8ToUtf16(sDrv); Result:= GetVolumeInformationW(PWideChar(wsDrv), nil, 0, nil, NotUsed, NotUsed, nil, 0); end; function mbGetVolumeLabel(const sDrv: String; const bVolReal: Boolean): String; var dwDummy: DWORD = 0; wsDrv, wsResult: UnicodeString; wcName: array [0..MAX_PATH] of WideChar; begin wsDrv:= CeUtf8ToUtf16(sDrv); if not bVolReal then wsResult:= DisplayName(wsDrv) else begin wcName[0]:= #0; if GetVolumeInformationW(PWideChar(wsDrv), wcName, MAX_PATH, nil, dwDummy, dwDummy, nil, 0) then begin wsResult:= wcName; end else begin wsResult:= Default(UnicodeString); end; end; Result:= CeUtf16ToUtf8(wsResult); end; function mbSetVolumeLabel(sRootPathName, sVolumeName: String): Boolean; var wsRootPathName, wsVolumeName: UnicodeString; begin wsRootPathName:= CeUtf8ToUtf16(sRootPathName); wsVolumeName:= CeUtf8ToUtf16(sVolumeName); Result:= SetVolumeLabelW(PWChar(wsRootPathName), PWChar(wsVolumeName)); end; procedure mbWaitLabelChange(const sDrv: String; const sCurLabel: String); var st1, st2: String; begin if mbGetVolumeLabel(sDrv, True) = '' then Exit; st1:= TrimLeft(sCurLabel); st2:= st1; while st1 = st2 do st2:= mbGetVolumeLabel(sDrv, FALSE); end; procedure mbCloseCD(const sDrv: String); var OpenParms: MCI_OPEN_PARMSA; begin FillChar(OpenParms, SizeOf(OpenParms), 0); OpenParms.lpstrDeviceType:= 'CDAudio'; OpenParms.lpstrElementName:= PAnsiChar(ExtractFileDrive(sDrv)); mciSendCommandA(0, MCI_OPEN, MCI_OPEN_TYPE or MCI_OPEN_ELEMENT, DWORD_PTR(@OpenParms)); mciSendCommandA(OpenParms.wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0); mciSendCommandA(OpenParms.wDeviceID, MCI_CLOSE, MCI_OPEN_TYPE or MCI_OPEN_ELEMENT, DWORD_PTR(@OpenParms)); end; const IOCTL_STORAGE_QUERY_PROPERTY = $2D1400; type FILE_FS_DEVICE_INFORMATION = record DeviceType: ULONG; Characteristics: ULONG; end; STORAGE_PROPERTY_QUERY = record PropertyId: DWORD; QueryType: DWORD; AdditionalParameters: array[0..0] of Byte; end; STORAGE_DEVICE_DESCRIPTOR = record Version: DWORD; Size: DWORD; DeviceType: Byte; DeviceTypeModifier: Byte; RemovableMedia: Boolean; CommandQueueing: Boolean; VendorIdOffset: DWORD; ProductIdOffset: DWORD; ProductRevisionOffset: DWORD; SerialNumberOffset: DWORD; BusType: DWORD; RawPropertiesLength: DWORD; RawDeviceProperties: array[0..0] of Byte; end; function mbGetDriveType(Drive: AnsiChar): UInt32; var Handle: THandle; IoStatusBlock: IO_STATUS_BLOCK; VolumePath: UnicodeString = '\\.\X:'; FileFsDeviceInfo: FILE_FS_DEVICE_INFORMATION; begin Result:= 0; VolumePath[5] := WideChar(Drive); Handle:= CreateFileW(PWideChar(VolumePath), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if Handle <> INVALID_HANDLE_VALUE then begin if (NtQueryVolumeInformationFile(Handle, @IoStatusBlock, @FileFsDeviceInfo, SizeOf(FileFsDeviceInfo), FileFsDeviceInformation) = STATUS_SUCCESS) then begin Result:= FileFsDeviceInfo.Characteristics; end; CloseHandle(Handle); end; end; function mbDriveBusType(Drive: AnsiChar): UInt32; var Dummy: DWORD; Handle: THandle; Query: STORAGE_PROPERTY_QUERY; Descr: STORAGE_DEVICE_DESCRIPTOR; VolumePath: UnicodeString = '\\.\X:'; begin Result := BusTypeUnknown; VolumePath[5] := WideChar(Drive); Handle := CreateFileW(PWideChar(VolumePath), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if (Handle <> INVALID_HANDLE_VALUE) then begin ZeroMemory(@Query, SizeOf(STORAGE_PROPERTY_QUERY)); if (DeviceIoControl(Handle, IOCTL_STORAGE_QUERY_PROPERTY, @Query, SizeOf(STORAGE_PROPERTY_QUERY), @Descr, SizeOf(STORAGE_DEVICE_DESCRIPTOR), @Dummy, nil)) then begin Result := Descr.BusType; end; CloseHandle(Handle); end; end; function mbGetDriveSerialNumber(Drive: AnsiChar): String; var Handle: THandle; dwBytesReturned: DWORD; Query: STORAGE_PROPERTY_QUERY; ABuffer: array[0..4095] of Byte; VolumePath: UnicodeString = '\\.\X:'; Descr: STORAGE_DEVICE_DESCRIPTOR absolute ABuffer; begin Result:= EmptyStr; VolumePath[5] := WideChar(Drive); Handle:= CreateFileW(PWideChar(VolumePath), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if Handle <> INVALID_HANDLE_VALUE then begin ZeroMemory(@ABuffer[0], SizeOf(ABuffer)); ZeroMemory(@Query, SizeOf(STORAGE_PROPERTY_QUERY)); if DeviceIoControl(Handle, IOCTL_STORAGE_QUERY_PROPERTY, @Query, SizeOf(STORAGE_PROPERTY_QUERY), @ABuffer[0], SizeOf(ABuffer), @dwBytesReturned, nil) then begin if (Descr.SerialNumberOffset > 0) then Result := StrPas(PAnsiChar(@ABuffer[0] + Descr.SerialNumberOffset)); end; CloseHandle(Handle); end; end; function IsWow64: BOOL; const Wow64Process: TDuplicates = dupIgnore; var usMachine: USHORT; hModule: TLibHandle; IsWow64Process: function(hProcess: HANDLE; Wow64Process: PBOOL): BOOL; stdcall; IsWow64Process2: function(hProcess: HANDLE; pProcessMachine, pNativeMachine: PUSHORT): BOOL; stdcall; begin if (Wow64Process = dupIgnore) then begin Wow64Process:= dupError; hModule:= GetModuleHandle(Kernel32); Pointer(IsWow64Process2):= GetProcAddress(hModule, 'IsWow64Process2'); if Assigned(IsWow64Process2) then begin usMachine:= 0; if IsWow64Process2(GetCurrentProcess, @usMachine, nil) and (usMachine <> 0) then Wow64Process:= dupAccept; end else begin Pointer(IsWow64Process):= GetProcAddress(hModule, 'IsWow64Process'); if Assigned(IsWow64Process) then begin Result:= False; if IsWow64Process(GetCurrentProcess, @Result) and Result then Wow64Process:= dupAccept; end; end end; Result:= (Wow64Process = dupAccept); end; function Wow64DisableRedirection(OldValue: PPointer): BOOL; begin if (IsWow64 = False) then Result:= True else begin Result:= Wow64DisableWow64FsRedirection(OldValue); end; end; function Wow64RevertRedirection(OldValue: Pointer): BOOL; begin if (IsWow64 = False) then Result:= True else begin Result:= Wow64RevertWow64FsRedirection(OldValue); end; end; procedure ShellExecuteThread(Parameter : Pointer); var Result: DWORD = 0; OldValue: Pointer = nil; Status : BOOL absolute Result; lpExecInfo: LPShellExecuteInfoW absolute Parameter; begin if Wow64DisableRedirection(@OldValue) then begin CoInitializeEx(nil, COINIT_APARTMENTTHREADED); Status:= ShellExecuteExW(lpExecInfo); CoUninitialize(); Wow64RevertRedirection(OldValue); end; EndThread(Result); end; procedure mbDriveUnlock(const sDrv: String); const FVE_E_LOCKED_VOLUME = HRESULT($80310000); FVE_E_VOLUME_NOT_BOUND = HRESULT($80310017); var Msg: TMSG; LastError: HRESULT; ShellThread: TThread; wsDrive: UnicodeString; lpExecInfo: TShellExecuteInfoW; begin wsDrive:= CeUtf8ToUtf16(sDrv); if not GetDiskFreeSpaceExW(PWideChar(wsDrive), nil, nil, nil) then begin LastError:= GetLastError; if (LastError = FVE_E_LOCKED_VOLUME) or (LastError = FVE_E_VOLUME_NOT_BOUND) then begin ZeroMemory(@lpExecInfo, SizeOf(lpExecInfo)); lpExecInfo.cbSize:= SizeOf(lpExecInfo); lpExecInfo.fMask:= SEE_MASK_NOCLOSEPROCESS; lpExecInfo.lpFile:= PWideChar(wsDrive); lpExecInfo.lpVerb:= 'unlock-bde'; ShellThread:= TThread.ExecuteInThread(@ShellExecuteThread, @lpExecInfo); if (ShellThread.WaitFor <> 0) and (lpExecInfo.hProcess <> 0) then begin while (WaitForSingleObject(lpExecInfo.hProcess, 100) = WAIT_TIMEOUT) do begin if (GetAsyncKeyStateEx(VK_ESCAPE)) then begin TerminateProcess(lpExecInfo.hProcess, 1); Break; end; PeekMessageW({%H-}Msg, 0, 0, 0, PM_REMOVE); end; { if GetExitCodeProcess(lpExecInfo.hProcess, @LastError) then Result:= (LastError = 0); } CloseHandle(lpExecInfo.hProcess); end; end; end; end; function mbGetRemoteFileName(const sLocalName: String): String; var dwResult, lpBufferSize: DWORD; wsLocalName: UnicodeString; lpBuffer: PUniversalNameInfoW; begin Result:= sLocalName; wsLocalName:= CeUtf8ToUtf16(sLocalName); lpBufferSize:= SizeOf(TUniversalNameInfoW); GetMem(lpBuffer, lpBufferSize); try dwResult:= WNetGetUniversalNameW(PWideChar(wsLocalName), UNIVERSAL_NAME_INFO_LEVEL, lpBuffer, lpBufferSize); if dwResult = ERROR_MORE_DATA then begin lpBuffer:= ReallocMem(lpBuffer, lpBufferSize); dwResult:= WNetGetUniversalNameW(PWideChar(wsLocalName), UNIVERSAL_NAME_INFO_LEVEL, lpBuffer, lpBufferSize); end; if dwResult = NO_ERROR then Result:= UTF16ToUTF8(UnicodeString(lpBuffer^.lpUniversalName)); finally FreeMem(lpBuffer); end; end; function mbGetShortPathName(const sLongPath: String; var sShortPath: AnsiString): Boolean; var wsLongPath, wsShortPath: UnicodeString; cchBuffer: DWORD; begin Result:= False; wsLongPath:= UTF16LongName(sLongPath); cchBuffer:= GetShortPathNameW(PWideChar(wsLongPath), nil, 0); if cchBuffer = 0 then Exit; SetLength(wsShortPath, cchBuffer); cchBuffer:= GetShortPathNameW(PWideChar(wsLongPath), PWideChar(wsShortPath), cchBuffer); if cchBuffer <> 0 then begin sShortPath:= AnsiString(wsShortPath); Result:= True; end; end; function mbWinNetErrorMessage(dwError: DWORD): String; var dwWNetResult: DWORD; lpNameBuf: array [0..MAX_PATH] of WideChar; lpErrorBuf: array[0..maxSmallint] of WideChar; begin if dwError <> ERROR_EXTENDED_ERROR then Result:= SysErrorMessage(dwError) else begin dwWNetResult:= WNetGetLastErrorW(dwError, lpErrorBuf, maxSmallint, lpNameBuf, MAX_PATH); if (dwWNetResult <> NO_ERROR) then Result:= SysErrorMessage(dwWNetResult) else begin Result:= UTF16ToUTF8(UnicodeString(lpErrorBuf)); end; end; if (Length(Result) = 0) then Result:= Format(SUnknownErrorCode, [dwError]); end; function GetServiceStatus(const AName: String): DWORD; var hSCManager, hService: SC_HANDLE; lpServiceStatus: TServiceStatus; begin hSCManager:= OpenSCManagerW(nil, nil, SC_MANAGER_ENUMERATE_SERVICE); if (hSCManager = 0) then Exit(0); try hService:= OpenServiceW(hSCManager, PWideChar(CeUtf8ToUtf16(AName)), SERVICE_QUERY_STATUS); if (hService = 0) then Exit(0); if not QueryServiceStatus(hService, {%H-}lpServiceStatus) then Result:= 0 else begin Result:= lpServiceStatus.dwCurrentState; end; CloseServiceHandle(hService); finally CloseServiceHandle(hSCManager); end; end; function NtQueryDirectoryFile(FileHandle: HANDLE; Event: HANDLE; ApcRoutine: PIO_APC_ROUTINE; ApcContext: PVOID; IoStatusBlock: PIO_STATUS_BLOCK; FileInformation: PVOID; FileInformationLength: ULONG; FileInformationClass: ULONG; ReturnSingleEntry: BOOLEAN; FileName: PUNICODE_STRING; RestartScan: BOOLEAN): NTSTATUS; stdcall; external ntdll; function QueryDirectoryFile(Handle: THandle; FileInfo: PVOID; FileInfoLength: ULONG; FileInfoClass: TFileInformationClass; ReturnSingleEntry: Boolean; const FileName: UnicodeString; RestartScan: Boolean): Boolean; var Status: NTSTATUS; PFileName: PUnicodeString; AFileName: TUnicodeString; IoStatusBlock: TIoStatusBlock; begin if Length(FileName) = 0 then PFileName:= nil else begin PFileName:= @AFileName; AFileName.Buffer:= PWideChar(FileName); AFileName.Length:= Length(FileName) * SizeOf(WideChar); AFileName.MaximumLength:= AFileName.Length; end; Status:= NtQueryDirectoryFile(Handle, 0, nil, nil, @IoStatusBlock, FileInfo, FileInfoLength, ULONG(FileInfoClass), ReturnSingleEntry, PFileName, RestartScan); if (Status <> STATUS_SUCCESS) then SetLastError(RtlNtStatusToDosError(Status)); Result:= (Status = STATUS_SUCCESS) and (IoStatusBlock.Information > 0); end; function GetFileOwner(const sPath: String; out sUser, sGroup: String): Boolean; var wsMachineName: UnicodeString; function SidToDisplayString(sid: PSID; sidType: SID_NAME_USE): String; var pName: PWideChar = nil; pDomain: PWideChar = nil; NameLen: DWORD = 0; DomainLen: DWORD = 0; begin // We're expecting insufficient buffer error here. if (LookupAccountSidW(PWideChar(wsMachineName), sid, nil, @NameLen, nil, @DomainLen, @SidType) = False) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin pName := Getmem(NameLen * SizeOf(WideChar)); pDomain := Getmem(DomainLen * SizeOf(WideChar)); if Assigned(pName) and Assigned(pDomain) and LookupAccountSidW(PWideChar(wsMachineName), sid, pName, @NameLen, pDomain, @DomainLen, @SidType) then begin if pDomain[0] <> #0 then Result := UTF16ToUTF8(UnicodeString(pDomain) + PathDelim + UnicodeString(pName)) else Result := UTF16ToUTF8(UnicodeString(pName)); end else Result := EmptyStr; Freemem(pName); Freemem(pDomain); end else Result := EmptyStr; end; // From UNC name extracts computer name. function GetMachineName(wPathName: LPCWSTR): UnicodeString; var lpMachineName, lpMachineNameNext: PWideChar; begin lpMachineName := PathFindNextComponentW(wPathName); if Assigned(lpMachineName) then begin lpMachineNameNext := PathFindNextComponentW(lpMachineName); if Assigned(lpMachineNameNext) then SetString(Result, lpMachineName, lpMachineNameNext - lpMachineName - 1) else Result := lpMachineName; end else Result := EmptyWideStr; end; var wszUNCPathName: array[0..32767] of WideChar; wsPathName: UnicodeString; pSecurityDescriptor: PSECURITY_DESCRIPTOR = nil; pOwnerSid: PSID = nil; pUNI: PUniversalNameInfoW; bDefault: Boolean; dwBufferSize: DWORD = 0; dwSizeNeeded: DWORD = 0; begin Result := False; if Length(sPath) = 0 then Exit; try wsPathName := CeUtf8ToUtf16(sPath); // Check if the path is to remote share and get remote machine name. if PathIsUNCW(PWideChar(wsPathName)) then begin // Path is in full UNC format. wsMachineName := GetMachineName(PWideChar(wsPathName)); end else begin // Check if local path is mapped to network share. dwBufferSize := SizeOf(wszUNCPathName); pUNI := PUniversalNameInfoW(@wszUNCPathName[0]); if WNetGetUniversalNameW(PWideChar(wsPathName), UNIVERSAL_NAME_INFO_LEVEL, pUNI, dwBufferSize) = NO_ERROR then begin wsMachineName := GetMachineName(pUNI^.lpUniversalName); end; // else not a network share, no network connection, etc. end; { Get security descriptor. } // We're expecting insufficient buffer error here. if (GetFileSecurityW(PWideChar(wsPathName), OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION, nil, 0, @dwSizeNeeded) <> False) or (GetLastError <> ERROR_INSUFFICIENT_BUFFER) or (dwSizeNeeded = 0) then begin Exit; end; pSecurityDescriptor := GetMem(dwSizeNeeded); if not Assigned(pSecurityDescriptor) then Exit; if not GetFileSecurityW(PWideChar(wsPathName), OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION, pSecurityDescriptor, dwSizeNeeded, @dwSizeNeeded) then begin Exit; end; { Get Owner and Group. } if GetSecurityDescriptorOwner(pSecurityDescriptor, pOwnerSid, @bDefault) then sUser := SidToDisplayString(pOwnerSid, SidTypeUser) else sUser := EmptyStr; if GetSecurityDescriptorGroup(pSecurityDescriptor, pOwnerSid, @bDefault) then sGroup := SidToDisplayString(pOwnerSid, SidTypeGroup) else sGroup := EmptyStr; Result := True; finally if Assigned(pSecurityDescriptor) then Freemem(pSecurityDescriptor); end; end; function GetFileDescription(const sPath: String): String; var SFI: TSHFileInfoW; begin FillChar(SFI, SizeOf(SFI), 0); if SHGetFileInfoW(PWideChar(CeUtf8ToUtf16(sPath)), 0, SFI, SizeOf(SFI), SHGFI_TYPENAME) <> 0 then Result := UTF16ToUTF8(UnicodeString(SFI.szTypeName)) else Result := EmptyStr; end; function mbGetFileSystem(const sRootPath: String): String; var Buf: array [0..MAX_PATH] of WideChar; NotUsed: DWORD = 0; begin // Available since Windows XP. if ((Win32MajorVersion > 5) or ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) and GetVolumeInformationW(PWideChar(CeUtf8ToUtf16(sRootPath)), nil, 0, nil, NotUsed, NotUsed, Buf, SizeOf(Buf)) then begin Result:= UTF16ToUTF8(UnicodeString(Buf)); end else Result := EmptyStr; end; function mbGetCompressedFileSize(const FileName: String): Int64; begin Int64Rec(Result).Lo:= GetCompressedFileSizeW(PWideChar(UTF16LongName(FileName)), @Int64Rec(Result).Hi); end; function mbGetFileChangeTime(const FileName: String; out ChangeTime: TFileTime): Boolean; var Handle: System.THandle; IoStatusBlock : TIoStatusBlock; FileInformation: TFileBasicInformation; begin Handle:= CreateFileW(PWideChar(UTF16LongName(FileName)), FILE_READ_ATTRIBUTES, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if Handle = INVALID_HANDLE_VALUE then Exit(False); Result:= NtQueryInformationFile(Handle, @IoStatusBlock, @FileInformation, SizeOf(FileInformation), FileBasicInformation) = 0; CloseHandle(Handle); ChangeTime:= TFileTime(FileInformation.ChangeTime); end; function GetAsyncKeyStateEx(vKey: Integer): Boolean; var Handle: HWND; dwProcessId: DWORD = 0; begin if (GetAsyncKeyState(vKey) < 0) then begin Handle:= GetForegroundWindow; if (Handle <> 0) then begin GetWindowThreadProcessId(Handle, @dwProcessId); Exit(GetCurrentProcessId = dwProcessId); end; end; Result:= False; end; function SHGetValueW(hkey: HKEY; pszSubKey, pszValue: LPCWSTR; pdwType: PDWORD; pvData: LPVOID; pcbData: PDWORD): DWORD; stdcall; external 'shlwapi.dll'; function IsUserAdmin: TDuplicates; const SYSTEM = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'; var Success: Boolean; dwValue: DWORD = 0; ReturnLength: DWORD = 0; dwType: DWORD = REG_DWORD; dwValueSize: DWORD = SizeOf(DWORD); TokenHandle: HANDLE = INVALID_HANDLE_VALUE; TokenInformation: array [0..1023] of Byte; ElevationType: JwaVista.TTokenElevationType absolute TokenInformation; begin if (Win32MajorVersion < 6) then Exit(dupIgnore); Success:= OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, TokenHandle); if not Success then begin if GetLastError = ERROR_NO_TOKEN then Success:= OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle); end; if Success then begin Success:= GetTokenInformation(TokenHandle, Windows.TTokenInformationClass(TokenElevationType), @TokenInformation, SizeOf(TokenInformation), ReturnLength); CloseHandle(TokenHandle); if Success then begin case ElevationType of // The token is an elevated token. (Administrator) TokenElevationTypeFull: Result:= dupAccept; // The token is a limited token. (User) TokenElevationTypeLimited: Result:= dupError; // The token does not have a linked token. (UAC disabled or standard user) TokenElevationTypeDefault: begin if (SHGetValueW( HKEY_LOCAL_MACHINE, SYSTEM, 'EnableLUA', @dwType, @dwValue, @dwValueSize) <> ERROR_SUCCESS) then begin Exit(dupError); end; if (dwValue > 0) then begin if (SHGetValueW( HKEY_LOCAL_MACHINE, SYSTEM, 'ConsentPromptBehaviorUser', @dwType, @dwValue, @dwValueSize) <> ERROR_SUCCESS) then begin Exit(dupError); end; end; if (dwValue > 0) then Result:= dupError else begin Result:= dupIgnore; end; end; end; end; end; if not Success then Result:= dupError; end; function RemoteSession: Boolean; const GLASS_SESSION_ID = 'GlassSessionId'; TERMINAL_SERVER_KEY = 'SYSTEM\CurrentControlSet\Control\Terminal Server\'; var dwType: DWORD; lResult: LONG; AKey: HKEY = 0; dwGlassSessionId, cbGlassSessionId, dwCurrentSessionId: DWORD; ProcessIdToSessionId: function(dwProcessId: DWORD; pSessionId: PDWORD): BOOL; stdcall; begin Result:= False; if (GetSystemMetrics(SM_REMOTESESSION) <> 0) then begin Result:= True; end else if (Win32MajorVersion > 5) then begin Pointer(ProcessIdToSessionId):= GetProcAddress(GetModuleHandle(Kernel32), 'ProcessIdToSessionId'); if Assigned(ProcessIdToSessionId) then begin lResult:= RegOpenKeyEx(HKEY_LOCAL_MACHINE, TERMINAL_SERVER_KEY, 0, KEY_READ, AKey); if (lResult = ERROR_SUCCESS) then begin cbGlassSessionId:= SizeOf(dwGlassSessionId); lResult:= RegQueryValueEx(AKey, GLASS_SESSION_ID, nil, @dwType, @dwGlassSessionId, @cbGlassSessionId); if (lResult = ERROR_SUCCESS) then begin if (ProcessIdToSessionId(GetCurrentProcessId(), @dwCurrentSessionId)) then begin Result:= (dwCurrentSessionId <> dwGlassSessionId); end; end; RegCloseKey(AKey); end; end; end; end; procedure CreateShortcut(const Target, Shortcut: String); var IObject: IUnknown; ISLink: IShellLinkW; IPFile: IPersistFile; LinkName: WideString; TargetArguments: WideString; begin TargetArguments:= EmptyWideStr; { Creates an instance of IShellLink } IObject := CreateComObject(CLSID_ShellLink); IPFile := IObject as IPersistFile; ISLink := IObject as IShellLinkW; OleCheckUTF8(ISLink.SetPath(PWideChar(CeUtf8ToUtf16(Target)))); OleCheckUTF8(ISLink.SetArguments(PWideChar(TargetArguments))); OleCheckUTF8(ISLink.SetWorkingDirectory(PWideChar(CeUtf8ToUtf16(ExtractFilePath(Target))))); { Get the desktop location } LinkName := CeUtf8ToUtf16(Shortcut); if LowerCase(ExtractFileExt(LinkName)) <> '.lnk' then LinkName := LinkName + '.lnk'; { Create the link } OleCheckUTF8(IPFile.Save(PWideChar(LinkName), False)); end; function ExtractFileAttributes(const FindData: TWin32FindDataW): DWORD; inline; begin // If a reparse point tag is not a name surrogate then remove reparse point attribute // Fixes bug: http://doublecmd.sourceforge.net/mantisbt/view.php?id=531 if (FindData.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT <> 0) and (FindData.dwReserved0 and $20000000 = 0) then Result:= FindData.dwFileAttributes - FILE_ATTRIBUTE_REPARSE_POINT else Result:= FindData.dwFileAttributes; end; procedure UpdateEnvironment; var dwSize: DWORD; ASysPath: UnicodeString; AUserPath: UnicodeString; APath: UnicodeString = ''; begin // System environment if RegReadKey(HKEY_LOCAL_MACHINE, 'System\CurrentControlSet\Control\Session Manager\Environment', 'Path', ASysPath) then begin APath := ASysPath; if (Length(APath) > 0) and (APath[Length(APath)] <> PathSeparator) then APath += PathSeparator; end; // User environment if RegReadKey(HKEY_CURRENT_USER, 'Environment', 'Path', AUserPath) then begin APath := APath + AUserPath; if (Length(APath) > 0) and (APath[Length(APath)] <> PathSeparator) then APath += PathSeparator; end; // Update path environment variable if Length(APath) > 0 then begin SetLength(ASysPath, MaxSmallInt + 1); dwSize:= ExpandEnvironmentStringsW(PWideChar(APath), PWideChar(ASysPath), MaxSmallInt); if (dwSize = 0) or (dwSize > MaxSmallInt) then ASysPath:= APath else begin SetLength(ASysPath, dwSize - 1); end; SetEnvironmentVariableW('Path', PWideChar(ASysPath)); end; end; procedure FixCommandLineToUTF8; var I, nArgs: Integer; sTemp: String; szArgList: PPWideChar; pwcCommandLine: PWideChar; lpFileName: array[0..Pred(MaxSmallInt)] of WideChar; begin {$IF DEFINED(FPC_HAS_CPSTRING)} if DefaultSystemCodePage = CP_UTF8 then Exit; {$ENDIF} pwcCommandLine:= GetCommandLineW(); for I:= 0 to lstrlenW(pwcCommandLine) - 1 do begin if (pwcCommandLine[I] = PathDelim) and (pwcCommandLine[I + 1] = '"') then begin pwcCommandLine[I]:= '"'; pwcCommandLine[I + 1]:= #32; end; end; szArgList:= CommandLineToArgvW(pwcCommandLine, @nArgs); if Assigned(szArgList) then begin if (nArgs > argc) then begin SysReAllocMem(argv, nArgs * SizeOf(Pointer)); FillChar(argv[argc], (nArgs - argc) * Sizeof(Pointer), #0); argc:= nArgs; end; // Special case for ParamStr(0) I:= GetModuleFileNameW(0, lpFileName, MaxSmallInt); lpFileName[I]:= #0; // to be safe sTemp:= UTF16ToUTF8(UnicodeString(lpFileName)); SysReAllocMem(argv[0], Length(sTemp) + 1); StrPCopy(argv[0], sTemp); // Process all other parameters for I:= 1 to nArgs - 1 do begin sTemp:= UTF16ToUTF8(UnicodeString(szArgList[I])); SysReAllocMem(argv[I], Length(sTemp) + 1); StrPCopy(argv[I], sTemp); end; LocalFree(HLOCAL(szArgList)); end; end; type PACKAGE_INFO_REFERENCE = record reserved: PVOID; end; PPACKAGE_INFO_REFERENCE = ^PACKAGE_INFO_REFERENCE; PACKAGE_VERSION = record case Boolean of False: ( Version: UINT64; ); True: ( Revision: USHORT; Build: USHORT; Minor: USHORT; Major: USHORT; ); end; PACKAGE_ID = record reserved: UINT32; processorArchitecture: UINT32; version: PACKAGE_VERSION; name: PWSTR; publisher: PWSTR; resourceId: PWSTR; publisherId: PWSTR; end; PACKAGE_INFO = record reserved: UINT32; flags: UINT32; path: PWSTR; packageFullName: PWSTR; packageFamilyName: PWSTR; packageId: PACKAGE_ID; end; PPACKAGE_INFO = ^PACKAGE_INFO; var OpenPackageInfoByFullName: function(packageFullName: PCWSTR; const reserved: UINT32; packageInfoReference: PPACKAGE_INFO_REFERENCE): LONG; stdcall; GetPackagesByPackageFamily: function(packageFamilyName: PCWSTR; count: PUINT32; packageFullNames: PPWideChar; bufferLength: PUINT32; buffer: PWCHAR): LONG; stdcall; GetPackageInfo: function(packageInfoReference: PACKAGE_INFO_REFERENCE; const flags: UINT32; bufferLength: PUINT32; buffer: PBYTE; count: PUINT32): LONG; stdcall; ClosePackageInfo: function(packageInfoReference: PACKAGE_INFO_REFERENCE): LONG; stdcall; function CheckPackageVersion(const Package: UnicodeString; Build, Revision: UInt16): Boolean; var Ret: ULONG; Count: UINT32 = 0; PackageBuffer: TBytes; BufferLength: UINT32 = 0; Buffer: array of WideChar; P: PACKAGE_INFO_REFERENCE; PackageFullNames: array of PWideChar; begin Result:= False; Ret:= GetPackagesByPackageFamily(PWideChar(Package), @Count, nil, @BufferLength, nil); if Ret = ERROR_INSUFFICIENT_BUFFER then begin SetLength(PackageFullNames, Count); SetLength(Buffer, BufferLength + 1); Ret:= GetPackagesByPackageFamily(PWideChar(Package), @Count, @PackageFullNames[0], @BufferLength, @Buffer[0]); if Ret = ERROR_SUCCESS then begin if OpenPackageInfoByFullName(PackageFullNames[0], 0, @P) = ERROR_SUCCESS then begin Count:= 0; BufferLength:= 0; Ret:= GetPackageInfo(P, 0, @BufferLength, nil, @Count); if Ret = ERROR_INSUFFICIENT_BUFFER then begin SetLength(PackageBuffer, BufferLength); if GetPackageInfo(P, 0, @BufferLength, @PackageBuffer[0], @Count) = ERROR_SUCCESS then begin with PPACKAGE_INFO(@PackageBuffer[0])^.packageId do begin Result:= (version.Build > Build) or ((version.Build = Build) and (version.Revision >= Revision)); end; end; end; ClosePackageInfo(P); end; end; end; end; function CheckPhotosVersion: Boolean; const PhotosNew: TDuplicates = dupIgnore; begin if (PhotosNew = dupIgnore) then begin // https://blogs.windows.com/windowsdeveloper/2024/06/03/microsoft-photos-migrating-from-uwp-to-windows-app-sdk/ if CheckPackageVersion('Microsoft.Windows.Photos_8wekyb3d8bbwe', 2024, 11050) then PhotosNew:= dupAccept else begin PhotosNew:= dupError; end; end; Result:= (PhotosNew = dupAccept); end; var hModule: TLibHandle; initialization if (IsWow64) then begin hModule:= GetModuleHandle(Kernel32); Pointer(Wow64DisableWow64FsRedirection):= GetProcAddress(hModule, 'Wow64DisableWow64FsRedirection'); Pointer(Wow64RevertWow64FsRedirection):= GetProcAddress(hModule, 'Wow64RevertWow64FsRedirection'); end; if CheckWin32Version(10) then begin hModule:= GetModuleHandle(Kernel32); Pointer(GetPackageInfo):= GetProcAddress(hModule, 'GetPackageInfo'); Pointer(ClosePackageInfo):= GetProcAddress(hModule, 'ClosePackageInfo'); Pointer(OpenPackageInfoByFullName):= GetProcAddress(hModule, 'OpenPackageInfoByFullName'); Pointer(GetPackagesByPackageFamily):= GetProcAddress(hModule, 'GetPackagesByPackageFamily'); end; end. ����������������������������������������������������������doublecmd-1.1.22/src/platform/win/unetworkthread.pas������������������������������������������������0000644�0001750�0000144�00000014746�14743153644�021605� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uNetworkThread; {$mode objfpc}{$H+} interface uses Classes, SysUtils, SyncObjs, JwaWinNetWk, Windows, Forms, Graphics, Dialogs, StdCtrls, ComCtrls, Buttons, uDrive, uOSForms; type { TDriveIcon } TDriveIcon = class public Drive: TDrive; Bitmap: TBitmap; destructor Destroy; override; end; { TNetworkForm } TNetworkForm = class(TModalDialog) lblPrompt: TLabel; btnAbort: TBitBtn; pbConnect: TProgressBar; private FThread: TThread; public constructor Create(TheOwner: TComponent; AThread: TThread; APath: PWideChar); reintroduce; procedure ExecuteModal; override; end; { TNetworkThread } TNetworkThread = class(TThread) private FWaitFinish: TSimpleEvent; FWaitConnect: TSimpleEvent; NetResource: TNetResourceW; protected procedure Execute; override; public constructor Create(lpLocalName, lpRemoteName: LPWSTR; dwType: DWORD); reintroduce; destructor Destroy; override; public class function Connect(lpLocalName, lpRemoteName: LPWSTR; dwType: DWORD): Integer; overload; class function Connect(lpLocalName, lpRemoteName: LPWSTR; dwType: DWORD; CheckOperationState: TThreadMethod): Integer; overload; end; { TNetworkDriveLoader } TNetworkDriveLoader = class(TThread) private FDrive: TDrive; FIconSize: Integer; FBackColor: TColor; FCallback: TDataEvent; protected procedure Execute; override; public constructor Create(ADrive: PDrive; AIconSize: Integer; ABackColor: TColor; ACallback: TDataEvent); reintroduce; end; implementation uses Math, InterfaceBase, Controls, fMain, uMyWindows, uPixMapManager, uLng; { TDriveIcon } destructor TDriveIcon.Destroy; begin Bitmap.Free; inherited Destroy; end; { TNetworkDriveLoader } procedure TNetworkDriveLoader.Execute; var AIcon: TDriveIcon; AData: PtrInt absolute AIcon; begin AIcon:= TDriveIcon.Create; AIcon.Drive:= FDrive; AIcon.Bitmap:= PixMapManager.GetDriveIcon(@FDrive, FIconSize, FBackColor); Application.QueueAsyncCall(FCallback, AData); end; constructor TNetworkDriveLoader.Create(ADrive: PDrive; AIconSize: Integer; ABackColor: TColor; ACallback: TDataEvent); begin FDrive:= ADrive^; FIconSize:= AIconSize; FBackColor:= ABackColor; FCallback:= ACallback; inherited Create(True); FreeOnTerminate:= True; end; { TNetworkForm } constructor TNetworkForm.Create(TheOwner: TComponent; AThread: TThread; APath: PWideChar); begin FThread:= AThread; inherited CreateNew(TheOwner); AutoSize:= True; BorderStyle:= bsDialog; Caption:= Application.Title; Position:= poOwnerFormCenter; ChildSizing.TopBottomSpacing:= 6; ChildSizing.LeftRightSpacing:= 6; lblPrompt := TLabel.Create(Self); with lblPrompt do begin Parent:= Self; AutoSize:= True; Caption:= rsOperWaitingForConnection + ' ' + UTF8Encode(UnicodeString(APath)); end; pbConnect:= TProgressBar.Create(Self); with pbConnect do begin Parent:= Self; Style:= pbstMarquee; AnchorToNeighbour(akTop, 6, lblPrompt); Constraints.MinWidth:= Math.Max(280, Screen.Width div 4); end; btnAbort:= TBitBtn.Create(Self); with btnAbort do begin Parent:= Self; Kind:= bkAbort; Default:= True; Cancel:= True; AutoSize:= True; AnchorHorizontalCenterTo(Self); AnchorToNeighbour(akTop, 12, pbConnect); end; end; procedure TNetworkForm.ExecuteModal; begin repeat WidgetSet.AppProcessMessages; if Application.Terminated then begin ModalResult:= mrCancel; end; if ModalResult <> 0 then begin CloseModal; if ModalResult <> 0 then Break; end; with TNetworkThread(FThread) do begin if (FWaitConnect.WaitFor(1) <> wrTimeout) then begin ModalResult:= mrOK; Break; end; end; Application.Idle(True); until False; end; { TNetworkThread } procedure TNetworkThread.Execute; begin // Function WNetAddConnection2W works very slow // when the final character is a backslash ('\') ReturnValue:= WNetAddConnection2W(@NetResource, nil, nil, CONNECT_INTERACTIVE); FWaitConnect.SetEvent; FWaitFinish.WaitFor(INFINITE); end; constructor TNetworkThread.Create(lpLocalName, lpRemoteName: LPWSTR; dwType: DWORD); begin inherited Create(True); FreeOnTerminate:= True; FWaitFinish:= TSimpleEvent.Create; FWaitConnect:= TSimpleEvent.Create; ZeroMemory(@NetResource, SizeOf(TNetResourceW)); if Assigned(lpLocalName) then begin NetResource.lpLocalName:= StrNew(lpLocalName); end; if Assigned(lpRemoteName) then begin NetResource.lpRemoteName:= StrNew(lpRemoteName); end; NetResource.dwType:= dwType; end; destructor TNetworkThread.Destroy; begin FWaitFinish.Free; FWaitConnect.Free; StrDispose(NetResource.lpLocalName); StrDispose(NetResource.lpRemoteName); inherited Destroy; end; class function TNetworkThread.Connect(lpLocalName, lpRemoteName: LPWSTR; dwType: DWORD): Integer; var AStartTime: QWord; AThread: TNetworkThread; begin AThread:= TNetworkThread.Create(lpLocalName, lpRemoteName, dwType); with AThread do begin Start; AStartTime:= GetTickCount64; try while True do begin if (GetTickCount64 - AStartTime > 3000) then begin with TNetworkForm.Create(frmMain, AThread, lpRemoteName) do try if (ShowModal = mrOK) then Exit(ReturnValue) else begin Exit(ERROR_CANCELLED); end; finally Free; end; end; if (GetAsyncKeyStateEx(VK_ESCAPE)) then Exit(ERROR_CANCELLED); if (FWaitConnect.WaitFor(1) <> wrTimeout) then Exit(ReturnValue); end; finally FWaitFinish.SetEvent; end; end; end; class function TNetworkThread.Connect(lpLocalName, lpRemoteName: LPWSTR; dwType: DWORD; CheckOperationState: TThreadMethod): Integer; begin with TNetworkThread.Create(lpLocalName, lpRemoteName, dwType) do begin Start; try while True do begin if Assigned(CheckOperationState) then CheckOperationState else if (GetAsyncKeyStateEx(VK_ESCAPE)) then Exit(ERROR_CANCELLED); if (FWaitConnect.WaitFor(1) <> wrTimeout) then Exit(ReturnValue); end; finally FWaitFinish.SetEvent; end; end; end; end. ��������������������������doublecmd-1.1.22/src/platform/win/ushellcontextmenu.pas���������������������������������������������0000644�0001750�0000144�00000103373�14743153644�022320� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Shell context menu implementation. Copyright (C) 2006-2021 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uShellContextMenu; {$mode delphi}{$H+} {$IF (FPC_VERSION > 2) or ((FPC_VERSION = 2) and (FPC_RELEASE >= 5))} {$POINTERMATH ON} {$ENDIF} interface uses Classes, SysUtils, Controls, uFile, Windows, ComObj, ShlObj, ActiveX, JwaShlGuid, uGlobs, uShlObjAdditional; const sCmdVerbOpen = 'open'; sCmdVerbRename = 'rename'; sCmdVerbDelete = 'delete'; sCmdVerbCut = 'cut'; sCmdVerbCopy = 'copy'; sCmdVerbPaste = 'paste'; sCmdVerbLink = 'link'; sCmdVerbProperties = 'properties'; sCmdVerbNewFolder = 'NewFolder'; sCmdVerbCopyPath = 'copyaspath'; type { EContextMenuException } EContextMenuException = class(Exception); { TShellContextMenu } TShellContextMenu = class private FOnClose: TNotifyEvent; FParent: HWND; FFiles: TFiles; FBackground: boolean; FShellMenu1: IContextMenu; FShellMenu: HMENU; FUserWishForContextMenu: TUserWishForContextMenu; protected procedure Execute(Data: PtrInt); public constructor Create(Parent: TWinControl; var Files: TFiles; Background: boolean; UserWishForContextMenu: TUserWishForContextMenu = uwcmComplete); reintroduce; destructor Destroy; override; procedure PopUp(X, Y: integer); property OnClose: TNotifyEvent read FOnClose write FOnClose; end; procedure PasteFromClipboard(Parent: HWND; const Path: String); function GetShellContextMenu(Handle: HWND; Files: TFiles; Background: boolean): IContextMenu; implementation uses graphtype, intfgraphics, Graphics, uPixMapManager, Dialogs, uLng, uMyWindows, uShellExecute, fMain, uDCUtils, uFormCommands, DCOSUtils, uOSUtils, uShowMsg, uExts, uFileSystemFileSource, DCConvertEncoding, LazUTF8, uOSForms, uGraphics, Forms, DCWindows, DCStrUtils, Clipbrd, uFileSystemWatcher, uShellFolder, uOleDragDrop, uGdiPlus; const USER_CMD_ID = $1000; var OldWProc: WNDPROC = nil; ShellMenu2: IContextMenu2 = nil; ShellMenu3: IContextMenu3 = nil; ContextMenuDCIcon: Graphics.TBitmap = nil; ContextMenucm_FileAssoc: Graphics.TBitmap = nil; ContextMenucm_RunTerm: Graphics.TBitmap = nil; function MyWndProc(hWnd: HWND; uiMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin case uiMsg of WM_MENUSELECT: Result := DefWindowProcW(hWnd, uiMsg, wParam, lParam); (* For working with submenu of context menu *) WM_INITMENUPOPUP, WM_DRAWITEM, WM_MENUCHAR, WM_MEASUREITEM: if Assigned(ShellMenu3) then ShellMenu3.HandleMenuMsg2(uiMsg, wParam, lParam, @Result) else if Assigned(ShellMenu2) then begin ShellMenu2.HandleMenuMsg(uiMsg, wParam, lParam); Result := 0; end else Result := CallWindowProc(OldWProc, hWnd, uiMsg, wParam, lParam); else Result := CallWindowProc(OldWProc, hWnd, uiMsg, wParam, lParam); end; // case end; function GetDriveContextMenu(Handle: HWND; Files: TFiles): IContextMenu; var Path: String; pchEaten: ULONG; S: UnicodeString; dwAttributes: ULONG = 0; PathPIDL: PItemIDList = nil; Folder, DesktopFolder: IShellFolder; begin OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(Handle, CSIDL_DRIVES, 0, 0, PathPIDL)); try if Files[0].Attributes <> FILE_ATTRIBUTE_DEVICE then Path:= Files[0].FullPath else begin Path:= GetDisplayName(DesktopFolder, PathPIDL, SHGDN_FORPARSING); Path:= Copy(Files[0].LinkProperty.LinkTo, Length(Path) + 2, MaxInt); end; OleCheckUTF8(DeskTopFolder.BindToObject(PathPIDL, nil, IID_IShellFolder, Folder)); finally CoTaskMemFree(PathPIDL); end; S := CeUtf8ToUtf16(Path); OleCheckUTF8(Folder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, PathPIDL, dwAttributes)); try OleCheckUTF8(Folder.GetUIObjectOf(Handle, 1, PathPIDL, IID_IContextMenu, nil, Result)); finally CoTaskMemFree(PathPIDL); end; end; function GetRecycleBinContextMenu(Handle: HWND): IContextMenu; var PathPIDL: PItemIDList = nil; DesktopFolder: IShellFolder; begin OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); OleCheckUTF8(SHGetFolderLocation(Handle, CSIDL_BITBUCKET, 0, 0, PathPIDL)); try OleCheckUTF8(DesktopFolder.GetUIObjectOf(Handle, 1, PathPIDL, IID_IContextMenu, nil, Result)); finally CoTaskMemFree(PathPIDL); end; end; function GetForegroundContextMenu(Handle: HWND; Files: TFiles): IContextMenu; var I: Integer; pchEaten: ULONG; S: UnicodeString; APath: UnicodeString; AFolder: TShellFolder; AMenu: TDefContextMenu; dwAttributes: ULONG = 0; List: PPItemIDList = nil; ASamePath: Boolean = True; tmpPIDL: PItemIDList = nil; PathPIDL: PItemIDList = nil; ADataObject: THDropDataObject; Folder, DesktopFolder: IShellFolder; begin Result := nil; OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); try List := CoTaskMemAlloc(SizeOf(PItemIDList) * Files.Count); ZeroMemory(List, SizeOf(PItemIDList) * Files.Count); APath:= CeUtf8ToUtf16(Files[0].Path); for I := 0 to Files.Count - 1 do begin if Files[I].Name = EmptyStr then S := EmptyWideStr else S := CeUtf8ToUtf16(Files[I].Path); if ASamePath then begin ASamePath:= UnicodeSameText(S, APath); end; OleCheckUTF8(DeskTopFolder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, PathPIDL, dwAttributes)); try OleCheckUTF8(DeskTopFolder.BindToObject(PathPIDL, nil, IID_IShellFolder, Folder)); finally CoTaskMemFree(PathPIDL); end; if Files[I].Name = EmptyStr then S := CeUtf8ToUtf16(Files[I].Path) else S := CeUtf8ToUtf16(Files[I].Name); OleCheckUTF8(Folder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, tmpPIDL, dwAttributes)); (List + i)^ := tmpPIDL; end; if (Win32MajorVersion < 6) or (ASamePath) or (Files.Count = 1) then Folder.GetUIObjectOf(Handle, Files.Count, PItemIDList(List^), IID_IContextMenu, nil, Result) else begin AMenu:= Default(TDefContextMenu); AMenu.hwnd:= Handle; ADataObject:= THDropDataObject.Create(DROPEFFECT_NONE); AFolder:= TShellFolder.Create(DeskTopFolder, ADataObject); for I := 0 to Files.Count - 1 do begin ADataObject.Add(Files[I].FullPath); end; AMenu.psf:= AFolder; AMenu.cidl:= Files.Count; AMenu.apidl:= PPItemIDList(List); OleCheckUTF8(CreateDefaultContextMenu(AMenu, IID_IContextMenu, Result)); end; finally if Assigned(List) then begin for I := 0 to Files.Count - 1 do if Assigned((List + i)^) then CoTaskMemFree((List + i)^); CoTaskMemFree(List); end; Folder := nil; DesktopFolder := nil; end; end; function GetBackgroundContextMenu(Handle: HWND; Files: TFiles): IContextMenu; var DesktopFolder, Folder: IShellFolder; wsFileName: WideString; PathPIDL: PItemIDList = nil; pchEaten: ULONG; dwAttributes: ULONG = 0; begin Result := nil; if Files.Count > 0 then begin wsFileName := CeUtf8ToUtf16(Files[0].FullPath); OleCheckUTF8(SHGetDesktopFolder(DesktopFolder)); try OleCheckUTF8(DesktopFolder.ParseDisplayName(Handle, nil, PWideChar(wsFileName), pchEaten, PathPIDL, dwAttributes)); try OleCheckUTF8(DesktopFolder.BindToObject(PathPIDL, nil, IID_IShellFolder, Folder)); finally CoTaskMemFree(PathPIDL); end; OleCheckUTF8(Folder.CreateViewObject(Handle, IID_IContextMenu, Result)); finally Folder := nil; DesktopFolder := nil; end; end; end; function GetShellContextMenu(Handle: HWND; Files: TFiles; Background: boolean): IContextMenu; inline; begin if Files = nil then Result := GetRecycleBinContextMenu(Handle) else if (Files.Count = 1) and (Files[0].Attributes and FILE_ATTRIBUTE_DEVICE <> 0) then Result := GetDriveContextMenu(Handle, Files) else if Background then Result := GetBackgroundContextMenu(Handle, Files) else Result := GetForegroundContextMenu(Handle, Files); end; type { TShellThread } TShellThread = class(TThread) private FParent: HWND; FVerb: ansistring; FShellMenu: IContextMenu; protected procedure Execute; override; public constructor Create(Parent: HWND; ShellMenu: IContextMenu; Verb: ansistring); reintroduce; destructor Destroy; override; end; { TShellThread } procedure TShellThread.Execute; var Result: HRESULT; cmici: TCMINVOKECOMMANDINFO; begin CoInitializeEx(nil, COINIT_APARTMENTTHREADED); try FillByte(cmici, SizeOf(cmici), 0); with cmici do begin cbSize := SizeOf(cmici); hwnd := FParent; lpVerb := PAnsiChar(FVerb); nShow := SW_NORMAL; end; Result := FShellMenu.InvokeCommand(cmici); if not (Succeeded(Result) or (Result = COPYENGINE_E_USER_CANCELLED) or (Result = HRESULT_ERROR_CANCELLED)) then msgError(Self, mbSysErrorMessage(Result)); finally CoUninitialize; end; end; constructor TShellThread.Create(Parent: HWND; ShellMenu: IContextMenu; Verb: ansistring); begin inherited Create(True); FVerb := Verb; FParent := Parent; FShellMenu := ShellMenu; FreeOnTerminate := True; end; destructor TShellThread.Destroy; begin FShellMenu := nil; inherited Destroy; end; procedure CreateActionSubMenu(MenuWhereToAdd: HMenu; paramExtActionList: TExtActionList; aFile: TFile; bIncludeViewEdit: boolean); const Always_Legacy_Action_Count = 2; var I, iDummy: integer; sAct: String; iMenuPositionInsertion: integer = 0; Always_Expanded_Action_Count: integer = 0; bSeparatorAlreadyInserted: boolean; function CreateBitmap: TBitmap; begin Result := Graphics.TBitmap.Create; Result.SetSize(gIconsSize, gIconsSize); Result.Transparent := True; Result.Canvas.Brush.Color := clMenu; Result.Canvas.Brush.Style := bsSolid; Result.Canvas.FillRect(0, 0, gIconsSize, gIconsSize); end; function GetMyIcon: TBitmap; var AIcon: TIcon; begin Result:= CreateBitmap; AIcon:= TIcon.Create; try AIcon.LoadFromResourceName(MainInstance, 'MAINICON'); AIcon.Current:= AIcon.GetBestIndexForSize(TSize.Create(gIconsSize, gIconsSize)); if (AIcon.Width = gIconsSize) and (AIcon.Height = gIconsSize) then DrawIcon(Result.Canvas.Handle, 0, 0, AIcon.Handle) else if IsGdiPlusLoaded then GdiPlusStretchDraw(AIcon.Handle, Result.Canvas.Handle, 0, 0, gIconsSize, gIconsSize) else begin DrawIconEx(Result.Canvas.Handle, 0, 0, AIcon.Handle, gIconsSize, gIconsSize, 0, 0, DI_NORMAL); end; finally AIcon.Free; end; if Result.PixelFormat <> pf32bit then BitmapConvert(Result); end; function GetMeTheBitmapForThis(ImageRequiredIndex: PtrInt): TBitmap; begin Result:= CreateBitmap; PixMapManager.DrawBitmap(ImageRequiredIndex, Result.Canvas, 0, 0); if Result.PixelFormat <> pf32bit then BitmapConvert(Result); end; procedure LocalInsertMenuSeparator; begin InsertMenuItemEx(MenuWhereToAdd, 0, nil, iMenuPositionInsertion, 0, MFT_SEPARATOR); Inc(iMenuPositionInsertion); end; procedure LocalInsertMenuItemExternal(MenuDispatcher: integer; BitmapProvided: TBitmap = nil); begin if BitmapProvided = nil then InsertMenuItemEx(MenuWhereToAdd, 0, PWChar(CeUtf8ToUtf16(paramExtActionList.ExtActionCommand[MenuDispatcher].ActionName)), iMenuPositionInsertion, MenuDispatcher + USER_CMD_ID, MFT_STRING, paramExtActionList.ExtActionCommand[MenuDispatcher].IconBitmap) else InsertMenuItemEx(MenuWhereToAdd, 0, PWChar(CeUtf8ToUtf16(paramExtActionList.ExtActionCommand[MenuDispatcher].ActionName)), iMenuPositionInsertion, MenuDispatcher + USER_CMD_ID, MFT_STRING, BitmapProvided); Inc(iMenuPositionInsertion); end; begin // Read actions from "extassoc.xml" if not gExtendedContextMenu then gExts.GetExtActions(aFile, paramExtActionList, @iDummy, False) else gExts.GetExtActions(aFile, paramExtActionList, @iDummy, True); if not gExtendedContextMenu then begin // In non expanded context menu (legacy), the order of items is: // 1o) View (always) // 2o) Edit (always) // 3o) Custom action different then Open, View or Edit (if any, add also a separator just before) I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuView, '{!VIEWER}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I); I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuEdit, '{!EDITOR}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I); if paramExtActionList.Count > Always_Legacy_Action_Count then begin bSeparatorAlreadyInserted := false; for I := 0 to (pred(paramExtActionList.Count) - Always_Legacy_Action_Count) do begin sAct := paramExtActionList.ExtActionCommand[I].ActionName; if (CompareText('OPEN', sAct) <> 0) and (CompareText('VIEW', sAct) <> 0) and (CompareText('EDIT', sAct) <> 0) then begin if not bSeparatorAlreadyInserted then begin LocalInsertMenuSeparator; bSeparatorAlreadyInserted := true; end; LocalInsertMenuItemExternal(I); end; end; end; end else begin // In expanded context menu, the order of items is: // 1o) View (always, and if "external" is used, shows also the "internal" if user wants it. // 2o) Edit (always, and if "external" is used, shows also the "internal" if user wants it. // 3o) Custom actions, no matter is open, view or edit (if any, add also a separator just before). // These will be shown in the same order as what they are configured in File Association. // The routine "GetExtActions" has already placed them in the wanted order. // Also, the routine "GetExtActions" has already included the menu separator ('-') between different "TExtAction". // 4o) We add the Execute via shell if user requested it. // 5o) We add the Execute via terminal if user requested it (close and then stay open). // 6o) Still if user requested it, the shortcut run file association configuration, if user wanted it. // A separator also prior that last action. // Let's prepare our icon for extended menu if not already prepaed during the session. if ContextMenuDCIcon = nil then ContextMenuDCIcon := GetMyIcon; if ContextMenucm_FileAssoc = nil then ContextMenucm_FileAssoc := GetMeTheBitmapForThis(PixMapManager.GetIconByName('cm_fileassoc')); if ContextMenucm_RunTerm = nil then ContextMenucm_RunTerm := GetMeTheBitmapForThis(PixMapManager.GetIconByName('cm_runterm')); // If the default context actions not hidden if gDefaultContextActions then begin // If the external generic viewer is configured, offer it. if gExternalTools[etViewer].Enabled then begin I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuView + ' (' + rsViewWithExternalViewer + ')', '{!VIEWER}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I); Inc(Always_Expanded_Action_Count); end; // Make sure we always shows our internal viewer I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuView + ' (' + rsViewWithInternalViewer + ')', '{!DC-VIEWER}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I, ContextMenuDCIcon); Inc(Always_Expanded_Action_Count); // If the external generic editor is configured, offer it. if gExternalTools[etEditor].Enabled then begin I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuEdit + ' (' + rsEditWithExternalEditor + ')', '{!EDITOR}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I); Inc(Always_Expanded_Action_Count); end; // Make sure we always shows our internal editor I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuEdit + ' (' + rsEditWithInternalEditor + ')', '{!DC-EDITOR}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I, ContextMenuDCIcon); Inc(Always_Expanded_Action_Count); end; // Now let's add the action button if paramExtActionList.Count > Always_Expanded_Action_Count then begin if iMenuPositionInsertion > 0 then LocalInsertMenuSeparator; for I := 0 to (pred(paramExtActionList.Count) - Always_Expanded_Action_Count) do begin if paramExtActionList.ExtActionCommand[I].ActionName <> '-' then begin sAct := paramExtActionList.ExtActionCommand[I].ActionName; if (CompareText('OPEN', sAct) = 0) or (CompareText('VIEW', sAct) = 0) or (CompareText('EDIT', sAct) = 0) then sAct := sAct + ' (' + ExtractFilename(paramExtActionList.ExtActionCommand[I].CommandName) + ')'; if paramExtActionList.ExtActionCommand[I].IconIndex <> -1 then begin paramExtActionList.ExtActionCommand[I].IconBitmap := Graphics.TBitmap.Create; paramExtActionList.ExtActionCommand[I].IconBitmap.SetSize(gIconsSize, gIconsSize); paramExtActionList.ExtActionCommand[I].IconBitmap.Transparent := True; paramExtActionList.ExtActionCommand[I].IconBitmap.Canvas.Brush.Color := clMenu; paramExtActionList.ExtActionCommand[I].IconBitmap.Canvas.Brush.Style := bsSolid; paramExtActionList.ExtActionCommand[I].IconBitmap.Canvas.FillRect(0, 0, gIconsSize, gIconsSize); PixMapManager.DrawBitmap(paramExtActionList.ExtActionCommand[I].IconIndex, paramExtActionList.ExtActionCommand[I].IconBitmap.Canvas, 0, 0); if paramExtActionList.ExtActionCommand[I].IconBitmap.PixelFormat <> pf32bit then begin BitmapConvert(paramExtActionList.ExtActionCommand[I].IconBitmap); end; end; LocalInsertMenuItemExternal(I); end else begin LocalInsertMenuSeparator; end; end; end; if (gOpenExecuteViaShell or gExecuteViaTerminalClose or gExecuteViaTerminalStayOpen) and (iMenuPositionInsertion > 0) then LocalInsertMenuSeparator; // now add various SHELL item if gOpenExecuteViaShell then begin I := paramExtActionList.Add(TExtActionCommand.Create(rsMnuOpen + ' (' + rsExecuteViaShell + ')', '{!SHELL}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I); end; if gExecuteViaTerminalClose then begin I := paramExtActionList.Add(TExtActionCommand.Create(rsExecuteViaTerminalClose, '{!TERMANDCLOSE}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I, ContextMenucm_RunTerm); end; if gExecuteViaTerminalStayOpen then begin I := paramExtActionList.Add(TExtActionCommand.Create(rsExecuteViaTerminalStayOpen, '{!TERMSTAYOPEN}', QuoteStr(aFile.FullPath), '')); LocalInsertMenuItemExternal(I, ContextMenucm_RunTerm); end; // Add shortcut to launch file association configuration screen if gIncludeFileAssociation then begin if iMenuPositionInsertion > 0 then LocalInsertMenuSeparator; I := paramExtActionList.Add(TExtActionCommand.Create(rsConfigurationFileAssociation, 'cm_FileAssoc', '', '')); LocalInsertMenuItemExternal(I, ContextMenucm_FileAssoc); end; end; end; { TShellContextMenu } procedure TShellContextMenu.Execute(Data: PtrInt); var UserSelectedCommand: TExtActionCommand absolute Data; begin try with frmMain.ActiveFrame do begin try //For the %-Variable replacement that follows it might sounds incorrect to do it with "nil" instead of "aFile", //but original code was like that. It is useful, at least, when more than one file is selected so because of that, //it's pertinent and should be kept! ProcessExtCommandFork(UserSelectedCommand.CommandName, UserSelectedCommand.Params, UserSelectedCommand.StartPath, nil); except on e: EInvalidCommandLine do MessageDlg(rsMsgErrorInContextMenuCommand, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0); end; end; finally FreeAndNil(UserSelectedCommand); end; end; { TShellContextMenu.Create } constructor TShellContextMenu.Create(Parent: TWinControl; var Files: TFiles; Background: boolean; UserWishForContextMenu: TUserWishForContextMenu); var UFlags: UINT = CMF_EXPLORE; begin FParent:= GetControlHandle(Parent); // Replace window procedure {$PUSH}{$HINTS OFF} OldWProc := WNDPROC(SetWindowLongPtrW(FParent, GWL_WNDPROC, LONG_PTR(@MyWndProc))); {$POP} FFiles := Files; FBackground := Background; FShellMenu := 0; FUserWishForContextMenu := UserWishForContextMenu; if Assigned(Files) and (Files.Count > 0) and (Files[0].Attributes <> FILE_ATTRIBUTE_DEVICE) then begin UFlags := UFlags or CMF_CANRENAME; end; // Add extended verbs if shift key is down if (ssShift in GetKeyShiftState) then begin UFlags := UFlags or CMF_EXTENDEDVERBS; end; try try FShellMenu1 := GetShellContextMenu(FParent, Files, Background); if Assigned(FShellMenu1) then begin FShellMenu := CreatePopupMenu; if FUserWishForContextMenu = uwcmComplete then OleCheckUTF8(FShellMenu1.QueryContextMenu(FShellMenu, 0, 1, USER_CMD_ID - 1, UFlags)); FShellMenu1.QueryInterface(IID_IContextMenu2, ShellMenu2); // to handle submenus. FShellMenu1.QueryInterface(IID_IContextMenu3, ShellMenu3); // to handle submenus. end; except on e: EOleError do raise EContextMenuException.Create(e.Message); end; finally Files := nil; end; end; destructor TShellContextMenu.Destroy; begin // Restore window procedure {$PUSH}{$HINTS OFF} SetWindowLongPtrW(FParent, GWL_WNDPROC, LONG_PTR(@OldWProc)); {$POP} // Free global variables ShellMenu2 := nil; ShellMenu3 := nil; // Free internal objects FShellMenu1 := nil; FreeAndNil(FFiles); if FShellMenu <> 0 then DestroyMenu(FShellMenu); inherited Destroy; end; procedure TShellContextMenu.PopUp(X, Y: integer); var aFile: TFile = nil; i: integer; hActionsSubMenu: HMENU = 0; iActionsItemsCount: integer; cmd: UINT = 0; iCmd: integer; cmici: TCMInvokeCommandInfoEx; lpici: TCMINVOKECOMMANDINFO absolute cmici; bHandled: boolean = False; ZVerb: array[0..255] of AnsiChar; sVerb: string; Result: HRESULT; FormCommands: IFormCommands; InnerExtActionList: TExtActionList = nil; UserSelectedCommand: TExtActionCommand = nil; sVolumeLabel: string; begin try try if Assigned(FShellMenu1) then try FormCommands := frmMain as IFormCommands; if Assigned(FFiles) then begin aFile := FFiles[0]; if FBackground then // Add "Background" context menu specific items begin SetMenuDefaultItem(FShellMenu, UINT(-1), 0); InnerExtActionList := TExtActionList.Create; // Add commands to root of context menu I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_Refresh'), 'cm_Refresh', '', '')); InsertMenuItemEx(FShellMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); // Add "Sort by" submenu hActionsSubMenu := CreatePopupMenu; I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_ReverseOrder'), 'cm_ReverseOrder', '', '')); InsertMenuItemEx(hActionsSubMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); // Add separator InsertMenuItemEx(hActionsSubMenu, 0, nil, 0, 0, MFT_SEPARATOR); // Add "Sort by" items I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_SortByAttr'), 'cm_SortByAttr', '', '')); InsertMenuItemEx(hActionsSubMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_SortByDate'), 'cm_SortByDate', '', '')); InsertMenuItemEx(hActionsSubMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_SortBySize'), 'cm_SortBySize', '', '')); InsertMenuItemEx(hActionsSubMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_SortByExt'), 'cm_SortByExt', '', '')); InsertMenuItemEx(hActionsSubMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_SortByName'), 'cm_SortByName', '', '')); InsertMenuItemEx(hActionsSubMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 0, I + USER_CMD_ID, MFT_STRING); // Add submenu to context menu InsertMenuItemEx(FShellMenu, hActionsSubMenu, PWideChar(CeUtf8ToUtf16(rsMnuSortBy)), 1, 333, MFT_STRING); // Add menu separator InsertMenuItemEx(FShellMenu, 0, nil, 2, 0, MFT_SEPARATOR); // Add commands to root of context menu I := InnerExtActionList.Add(TExtActionCommand.Create(FormCommands.GetCommandCaption('cm_PasteFromClipboard'), 'cm_PasteFromClipboard', '', '')); InsertMenuItemEx(FShellMenu, 0, PWideChar(CeUtf8ToUtf16(InnerExtActionList.ExtActionCommand[I].ActionName)), 3, I + USER_CMD_ID, MFT_STRING); // Add menu separator InsertMenuItemEx(FShellMenu, 0, nil, 4, 0, MFT_SEPARATOR); end else // Add "Actions" submenu begin InnerExtActionList := TExtActionList.Create; if FUserWishForContextMenu = uwcmComplete then begin hActionsSubMenu := CreatePopupMenu; CreateActionSubMenu(hActionsSubMenu, InnerExtActionList, aFile, ((FFiles.Count = 1) and not (aFile.IsDirectory or aFile.IsLinkToDirectory))); end else begin CreateActionSubMenu(FShellMenu, InnerExtActionList, aFile, ((FFiles.Count = 1) and not (aFile.IsDirectory or aFile.IsLinkToDirectory))); end; // Add Actions submenu (Will never be empty, we always have View and Edit...) iCmd := GetMenuItemCount(FShellMenu) - 1; for I := 0 to iCmd do begin if GetMenuItemType(FShellMenu, I, True) = MFT_SEPARATOR then Break; end; iActionsItemsCount := GetMenuItemCount(hActionsSubMenu); if (FUserWishForContextMenu = uwcmComplete) and (iActionsItemsCount > 0) then InsertMenuItemEx(FShellMenu, hActionsSubMenu, PWideChar(CeUtf8ToUtf16(rsMnuActions)), I, 333, MFT_STRING); end; { /Actions submenu } end; //------------------------------------------------------------------------------ cmd := UINT(TrackPopupMenu(FShellMenu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, X, Y, 0, FParent, nil)); finally if hActionsSubMenu <> 0 then DestroyMenu(hActionsSubMenu); end; if (cmd > 0) and (cmd < USER_CMD_ID) then begin iCmd := longint(Cmd) - 1; if Succeeded(FShellMenu1.GetCommandString(iCmd, GCS_VERBA, nil, ZVerb, SizeOf(ZVerb))) then begin sVerb := StrPas(ZVerb); if SameText(sVerb, sCmdVerbRename) then begin if (FFiles.Count = 1) then begin // Change drive label if (FFiles[0].Attributes and FILE_ATTRIBUTE_DEVICE <> 0) then begin aFile := FFiles[0]; sVolumeLabel := mbGetVolumeLabel(aFile.FullPath, True); if InputQuery(rsMsgSetVolumeLabel, rsMsgVolumeLabel, sVolumeLabel) then mbSetVolumeLabel(aFile.FullPath, sVolumeLabel); end else begin frmMain.actRenameOnly.Execute; end; end else begin frmMain.actRename.Execute; end; bHandled := True; end else if SameText(sVerb, sCmdVerbCut) then begin frmMain.actCutToClipboard.Execute; bHandled := True; end else if SameText(sVerb, sCmdVerbCopy) then begin frmMain.actCopyToClipboard.Execute; bHandled := True; end else if SameText(sVerb, sCmdVerbNewFolder) then begin frmMain.actMakeDir.Execute; bHandled := True; end else if SameText(sVerb, sCmdVerbPaste) or SameText(sVerb, sCmdVerbDelete) then begin TShellThread.Create(FParent, FShellMenu1, sVerb).Start; bHandled := True; end else if SameText(sVerb, sCmdVerbCopyPath) then begin with TStringList.Create do begin for i:= 0 to FFiles.Count - 1 do begin sVolumeLabel:= FFiles[i].FullPath; if UTF8Length(sVolumeLabel) >= MAX_PATH then Add(QuoteStr(UTF16ToUTF8(UTF16LongName(sVolumeLabel)))) else begin Add(QuoteStr(sVolumeLabel)); end; end; Clipboard.AsText:= TrimRightLineEnding(Text, TextLineBreakStyle); Free; end; bHandled := True; end; end; if not bHandled then begin if Assigned(FFiles) then begin if FBackground then sVolumeLabel := FFiles[0].FullPath else begin sVolumeLabel := ExcludeTrailingBackslash(FFiles[0].Path); end; end; ZeroMemory(@cmici, SizeOf(cmici)); with cmici do begin cbSize := SizeOf(cmici); hwnd := FParent; fMask := CMIC_MASK_UNICODE; {$PUSH}{$HINTS OFF} lpVerb := PAnsiChar(PtrUInt(cmd - 1)); {$POP} nShow := SW_NORMAL; if Assigned(FFiles) and (FFiles[0].Path <> FFiles[0].FullPath) then begin lpDirectory := PAnsiChar(CeUtf8ToSys(sVolumeLabel)); lpDirectoryW := PWideChar(UTF8ToUTF16(sVolumeLabel)); end; end; Result := FShellMenu1.InvokeCommand(lpici); if not Succeeded(Result) then begin case Result of COPYENGINE_E_USER_CANCELLED, E_FAIL: ; // Ignore else OleErrorUTF8(Result); end; end; // Reload after possible changes on the filesystem. if SameText(sVerb, sCmdVerbLink) or SameText(sVerb, sCmdVerbDelete) then frmMain.ActiveFrame.FileSource.Reload(frmMain.ActiveFrame.CurrentPath); // "New" submenu if FBackground and (StrBegins(sVerb, ExtensionSeparator)) then begin sVolumeLabel:= frmMain.ActiveFrame.CurrentPath; if not (TFileSystemWatcher.CanWatch([sVolumeLabel]) and frmMain.ActiveFrame.WatcherActive) then frmMain.ActiveFrame.FileSource.Reload(sVolumeLabel); end; end; end // if cmd > 0 else if (cmd >= USER_CMD_ID) then // actions sub menu begin if (cmd - USER_CMD_ID) < InnerExtActionList.Count then UserSelectedCommand := InnerExtActionList.ExtActionCommand[cmd - USER_CMD_ID].CloneExtAction; if FBackground then begin if SameText(UserSelectedCommand.CommandName, 'cm_PasteFromClipboard') then TShellThread.Create(FParent, FShellMenu1, sCmdVerbPaste).Start else FormCommands.ExecuteCommand(UserSelectedCommand.CommandName, []); bHandled := True; end else begin Application.QueueAsyncCall(Execute, PtrInt(UserSelectedCommand)); UserSelectedCommand := nil; bHandled := True; end; end; finally FreeAndNil(InnerExtActionList); FreeAndNil(UserSelectedCommand); FreeAndNil(ContextMenuDCIcon); end; except on e: EOleError do raise EContextMenuException.Create(e.Message); end; if Assigned(FOnClose) then FOnClose(Self); end; procedure PasteFromClipboard(Parent: HWND; const Path: String); var AFile: TFile; Files: TFiles; ShellMenu: IContextMenu; begin Files:= TFiles.Create(EmptyStr); try AFile := TFileSystemFileSource.CreateFile(EmptyStr); AFile.FullPath := Path; AFile.Attributes := faFolder; Files.Add(AFile); ShellMenu:= GetShellContextMenu(Parent, Files, True); if Assigned(ShellMenu) then begin TShellThread.Create(Parent, ShellMenu, sCmdVerbPaste).Start; end; except on E: Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; FreeAndNil(Files); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/ushellfileoperation.pas�������������������������������������������0000644�0001750�0000144�00000007122�14743153644�022602� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellFileOperation; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Windows, ActiveX, ShlObj, ComObj, ShlWAPI, ShellAPI, uShellFolder; const CLSID_FileOperation: TGUID = '{3ad05575-8857-4850-9277-11b85bdb8e09}'; type IOperationsProgressDialog = IUnknown; { IObjectWithPropertyKey } IObjectWithPropertyKey = interface(IUnknown) ['{fc0ca0a7-c316-4fd2-9031-3e628e6d4f23}'] function SetPropertyKey(key: REFPROPERTYKEY): HRESULT; stdcall; function GetPropertyKey(var pkey: PROPERTYKEY): HRESULT; stdcall; end; { IPropertyChange } IPropertyChange = interface(IObjectWithPropertyKey) ['{f917bc8a-1bba-4478-a245-1bde03eb9431}'] function ApplyToPropVariant(propvarIn: REFPROPVARIANT; ppropvarOut: PPROPVARIANT): HRESULT; stdcall; end; { IPropertyChangeArray } IPropertyChangeArray = interface(IUnknown) ['{380f5cad-1b5e-42f2-805d-637fd392d31e}'] function GetCount(pcOperations: PUINT): HRESULT; stdcall; function GetAt(iIndex: UINT; const riid: REFIID; out ppv): HRESULT; stdcall; function InsertAt(iIndex: UINT; ppropChange: IPropertyChange): HRESULT; stdcall; function Append(ppropChange: IPropertyChange): HRESULT; stdcall; function AppendOrReplace(ppropChange: IPropertyChange): HRESULT; stdcall; function RemoveAt(iIndex: UINT): HRESULT; stdcall; function IsKeyInArray(key: REFPROPERTYKEY): HRESULT; stdcall; end; { IFileOperation } IFileOperation = interface(IUnknown) ['{947aab5f-0a5c-4c13-b4d6-4bf7836fc9f8}'] function Advise(pfops: IFileOperationProgressSink; pdwCookie: PDWORD): HRESULT; stdcall; function Unadvise(dwCookie: DWORD): HRESULT; stdcall; function SetOperationFlags(dwOperationFlags: DWORD): HRESULT; stdcall; function SetProgressMessage(pszMessage: LPCWSTR): HRESULT; stdcall; function SetProgressDialog(popd: IOperationsProgressDialog): HRESULT; stdcall; function SetProperties(pproparray: IPropertyChangeArray): HRESULT; stdcall; function SetOwnerWindow(hwndOwner: HWND): HRESULT; stdcall; function ApplyPropertiesToItem(psiItem: IShellItem): HRESULT; stdcall; function ApplyPropertiesToItems(punkItems: IUnknown): HRESULT; stdcall; function RenameItem(psiItem: IShellItem; pszNewName: LPCWSTR; pfopsItem: IFileOperationProgressSink): HRESULT; stdcall; function RenameItems(pUnkItems: IUnknown; pszNewName: LPCWSTR): HRESULT; stdcall; function MoveItem(psiItem: IShellItem; psiDestinationFolder: IShellItem; pszNewName: LPCWSTR; pfopsItem: IFileOperationProgressSink): HRESULT; stdcall; function MoveItems(punkItems: IUnknown; psiDestinationFolder: IShellItem): HRESULT; stdcall; function CopyItem(psiItem: IShellItem; psiDestinationFolder: IShellItem; pszCopyName: LPCWSTR; pfopsItem: IFileOperationProgressSink): HRESULT; stdcall; function CopyItems(punkItems: IUnknown; psiDestinationFolder: IShellItem): HRESULT; stdcall; function DeleteItem(psiItem: IShellItem; pfopsItem: IFileOperationProgressSink): HRESULT; stdcall; function DeleteItems(punkItems: IUnknown): HRESULT; stdcall; function NewItem(psiDestinationFolder: IShellItem; dwFileAttributes: DWORD; pszName: LPCWSTR; pszTemplateName: LPCWSTR; pfopsItem: IFileOperationProgressSink): HRESULT; stdcall; function PerformOperations(): HRESULT; stdcall; function GetAnyOperationsAborted(pfAnyOperationsAborted: PBOOL): HRESULT; stdcall; end; implementation end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/ushellfolder.pas��������������������������������������������������0000644�0001750�0000144�00000035677�14743153644�021235� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uShellFolder; {$mode delphi} interface uses Classes, SysUtils, Windows, ShlObj, ActiveX, ComObj, ShlWapi, uShlObjAdditional; const SID_SYSTEM = '{B725F130-47EF-101A-A5F1-02608C9EEBAC}'; SCID_FileSize: TSHColumnID = ( fmtid: SID_SYSTEM; pid: 12 ); SCID_DateModified: TSHColumnID = ( fmtid: SID_SYSTEM; pid: 14 ); SCID_DateCreated: TSHColumnID = ( fmtid: SID_SYSTEM; pid: 15 ); SID_NAME = '{41CF5AE0-F75A-4806-BD87-59C7D9248EB9}'; SCID_FileName: TSHColumnID = ( fmtid: SID_NAME; pid: 100 ); SID_COMPUTER = '{9B174B35-40FF-11D2-A27E-00C04FC30871}'; SCID_Capacity: TSHColumnID = ( fmtid: SID_COMPUTER; pid: 3 ); const FOLDERID_AccountPictures: TGUID = '{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}'; FOLDERID_ApplicationShortcuts: TGUID = '{A3918781-E5F2-4890-B3D9-A7E54332328C}'; FOLDERID_CameraRoll: TGUID = '{AB5FB87B-7CE2-4F83-915D-550846C9537B}'; FOLDERID_Contacts: TGUID = '{56784854-C6CB-462b-8169-88E350ACB882}'; FOLDERID_DeviceMetadataStore: TGUID = '{5CE4A5E9-E4EB-479D-B89F-130C02886155}'; FOLDERID_Downloads: TGUID = '{374DE290-123F-4565-9164-39C4925E467B}'; FOLDERID_GameTasks: TGUID = '{054FAE61-4DD8-4787-80B6-090220C4B700}'; FOLDERID_ImplicitAppShortcuts: TGUID = '{BCB5256F-79F6-4CEE-B725-DC34E402FD46}'; FOLDERID_Libraries: TGUID = '{1B3EA5DC-B587-4786-B4EF-BD1DC332AEAE}'; FOLDERID_Links: TGUID = '{bfb9d5e0-c6a9-404c-b2b2-ae6db6af4968}'; FOLDERID_LocalAppDataLow: TGUID = '{A520A1A4-1780-4FF6-BD18-167343C5AF16}'; FOLDERID_OriginalImages: TGUID = '{2C36C0AA-5812-4b87-BFD0-4CD0DFB19B39}'; FOLDERID_PhotoAlbums: TGUID = '{69D2CF90-FC33-4FB7-9A0C-EBB0F0FCB43C}'; FOLDERID_Playlists: TGUID = '{DE92C1C7-837F-4F69-A3BB-86E631204A23}'; FOLDERID_ProgramFilesX64: TGUID = '{6D809377-6AF0-444b-8957-A3773F02200E}'; FOLDERID_ProgramFilesCommonX64: TGUID = '{6365D5A7-0F0D-45E5-87F6-0DA56B6A4F7D}'; FOLDERID_Public: TGUID = '{DFDF76A2-C82A-4D63-906A-5644AC457385}'; FOLDERID_PublicDownloads: TGUID = '{3D644C9B-1FB8-4f30-9B45-F670235F79C0}'; FOLDERID_PublicGameTasks: TGUID = '{DEBF2536-E1A8-4c59-B6A2-414586476AEA}'; FOLDERID_PublicLibraries: TGUID = '{48DAF80B-E6CF-4F4E-B800-0E69D84EE384}'; FOLDERID_PublicRingtones: TGUID = '{E555AB60-153B-4D17-9F04-A5FE99FC15EC}'; FOLDERID_PublicUserTiles: TGUID = '{0482af6c-08f1-4c34-8c90-e17ec98b1e17}'; FOLDERID_QuickLaunch: TGUID = '{52a4f021-7b75-48a9-9f6b-4b87a210bc8f}'; FOLDERID_Ringtones: TGUID = '{C870044B-F49E-4126-A9C3-B52A1FF411E8}'; FOLDERID_RoamedTileImages: TGUID = '{AAA8D5A5-F1D6-4259-BAA8-78E7EF60835E}'; FOLDERID_RoamingTiles: TGUID = '{00BCFC5A-ED94-4e48-96A1-3F6217F21990}'; FOLDERID_SampleMusic: TGUID = '{B250C668-F57D-4EE1-A63C-290EE7D1AA1F}'; FOLDERID_SamplePictures: TGUID = '{C4900540-2379-4C75-844B-64E6FAF8716B}'; FOLDERID_SamplePlaylists: TGUID = '{15CA69B3-30EE-49C1-ACE1-6B5EC372AFB5}'; FOLDERID_SampleVideos: TGUID = '{859EAD94-2E85-48AD-A71A-0969CB56A6CD}'; FOLDERID_SavedGames: TGUID = '{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}'; FOLDERID_SavedPictures: TGUID = '{3B193882-D3AD-4eab-965A-69829D1FB59F}'; FOLDERID_SavedSearches: TGUID = '{7d1d3a04-debb-4115-95cf-2f29da2920da}'; FOLDERID_Screenshots: TGUID = '{b7bede81-df94-4682-a7d8-57a52620b86f}'; FOLDERID_SearchHistory: TGUID = '{0D4C3DB6-03A3-462F-A0E6-08924C41B5D4}'; FOLDERID_SearchTemplates: TGUID = '{7E636BFE-DFA9-4D5E-B456-D7B39851D8A9}'; FOLDERID_SidebarDefaultParts: TGUID = '{7B396E54-9EC5-4300-BE0A-2482EBAE1A26}'; FOLDERID_SidebarParts: TGUID = '{A75D362E-50FC-4fb7-AC2C-A8BEAA314493}'; FOLDERID_SkyDrive: TGUID = '{A52BBA46-E9E1-435f-B3D9-28DAA648C0F6}'; FOLDERID_SkyDriveCameraRoll: TGUID = '{767E6811-49CB-4273-87C2-20F355E1085B}'; FOLDERID_SkyDriveDocuments: TGUID = '{24D89E24-2F19-4534-9DDE-6A6671FBB8FE}'; FOLDERID_SkyDrivePictures: TGUID = '{339719B5-8C47-4894-94C2-D8F77ADD44A6}'; FOLDERID_UserPinned: TGUID = '{9E3995AB-1F9C-4F13-B827-48B24B6C7174}'; FOLDERID_UserProfiles: TGUID = '{0762D272-C50A-4BB0-A382-697DCD729B80}'; FOLDERID_UserProgramFiles: TGUID = '{5CD7AEE2-2219-4A67-B85D-6C9CE15660CB}'; FOLDERID_UserProgramFilesCommon: TGUID = '{BCBD3057-CA5C-4622-B42D-BC56DB0AE516}'; type PPItemIDList = ^PItemIDList; TDefContextMenu = record hwnd : HWND; pcmcb : IUnknown; pidlFolder : PCIDLIST_ABSOLUTE; psf : IShellFolder; cidl : UINT; apidl : PPItemIDList; punkAssociationInfo : IUnknown; cKeys : UINT; aKeys : PHKEY; end; { TShellFolder } TShellFolder = class(TInterfacedObject, IShellFolder) private FFolder: IShellFolder; FDataObject: IDataObject; protected function QueryInterface(constref iid : tguid; out obj) : longint; stdcall; public constructor Create(AFolder: IShellFolder; DataObject: IDataObject); public function ParseDisplayName(hwndOwner: HWND; pbcReserved: Pointer; lpszDisplayName: POLESTR; out pchEaten: ULONG; out ppidl: PItemIDList; var dwAttributes: ULONG): HRESULT; stdcall; function EnumObjects(hwndOwner: HWND; grfFlags: DWORD; out EnumIDList: IEnumIDList): HRESULT; stdcall; function BindToObject(pidl: PItemIDList; pbcReserved: Pointer; const riid: TIID; out ppvOut): HRESULT; stdcall; function BindToStorage(pidl: PItemIDList; pbcReserved: Pointer; const riid: TIID; out ppvObj): HRESULT; stdcall; function CompareIDs(lParam: LPARAM; pidl1, pidl2: PItemIDList): HRESULT; stdcall; function CreateViewObject(hwndOwner: HWND; const riid: TIID; out ppvOut): HRESULT; stdcall; function GetAttributesOf(cidl: UINT; var apidl: PItemIDList; var rgfInOut: UINT): HRESULT; stdcall; function GetUIObjectOf(hwndOwner: HWND; cidl: UINT; var apidl: PItemIDList; const riid: TIID; prgfInOut: Pointer; out ppvOut): HRESULT; stdcall; function GetDisplayNameOf(pidl: PItemIDList; uFlags: DWORD; var lpName: TStrRet): HRESULT; stdcall; function SetNameOf(hwndOwner: HWND; pidl: PItemIDList; lpszName: POLEStr; uFlags: DWORD; var ppidlOut: PItemIDList): HRESULT; stdcall; end; function GetKnownFolderPath(const rfid: TGUID; out APath: String): Boolean; function MultiFileProperties(pdtobj: IDataObject; dwFlags: DWORD): HRESULT; function GetIsFolder(AParent: IShellFolder; PIDL: PItemIDList): Boolean; function GetDisplayName(AFolder: IShellFolder; PIDL: PItemIDList; Flags: DWORD): String; function GetDisplayNameEx(AFolder: IShellFolder2; PIDL: PItemIDList; Flags: DWORD): String; function GetDetails(AFolder: IShellFolder2; PIDL: PItemIDList; const pscid: SHCOLUMNID): OleVariant; function ParseDisplayName(Desktop: IShellFolder; const AName: String; out PIDL: PItemIDList): HRESULT; function CreateDefaultContextMenu(constref pdcm: TDefContextMenu; const riid: REFIID; out ppv): HRESULT; implementation uses Variants, ShellApi, LazUTF8, DCConvertEncoding, DCStrUtils; const KF_FLAG_DEFAULT = $00000000; var SHMultiFileProperties: function(pdtobj: IDataObject; dwFlags: DWORD): HRESULT; stdcall; SHCreateDefaultContextMenu: function(constref pdcm: TDefContextMenu; const riid: REFIID; out ppv): HRESULT; stdcall; SHGetKnownFolderPath: function(const rfid: TGUID; dwFlags: DWORD; hToken: HANDLE; out ppszPath: LPCWSTR): HRESULT; stdcall; function StrRetToString(PIDL: PItemIDList; StrRet: TStrRet): String; var S: array[0..MAX_PATH] of WideChar; begin if StrRetToBufW(@StrRet, PIDL, S, MAX_PATH) <> S_OK then Result:= EmptyStr else Result:= CeUtf16ToUtf8(UnicodeString(S)); end; function MultiFileProperties(pdtobj: IDataObject; dwFlags: DWORD): HRESULT; begin Result:= SHMultiFileProperties(pdtobj, dwFlags); end; function GetIsFolder(AParent: IShellFolder; PIDL: PItemIDList): Boolean; var Flags: LongWord; begin Flags:= SFGAO_FOLDER; AParent.GetAttributesOf(1, PIDL, Flags); Result:= (SFGAO_FOLDER and Flags) <> 0; end; function GetDisplayName(AFolder: IShellFolder; PIDL: PItemIDList; Flags: DWORD): String; var StrRet: TStrRet; begin Result:= EmptyStr; StrRet:= Default(TStrRet); if Succeeded(AFolder.GetDisplayNameOf(PIDL, Flags, StrRet)) then Result := StrRetToString(PIDL, StrRet); if (Length(Result) = 0) and (Flags <> SHGDN_NORMAL) then Result := GetDisplayName(AFolder, PIDL, SHGDN_NORMAL); end; function GetDisplayNameEx(AFolder: IShellFolder2; PIDL: PItemIDList; Flags: DWORD): String; var AValue: OleVariant; begin AValue:= GetDetails(AFolder, PIDL, SCID_FileName); if VarIsStr(AValue) then Result:= AValue else begin Result:= GetDisplayName(AFolder, PIDL, Flags); end; end; function GetDetails(AFolder: IShellFolder2; PIDL: PItemIDList; const pscid: SHCOLUMNID): OleVariant; var AValue: OleVariant; begin if Succeeded(AFolder.GetDetailsEx(pidl, @pscid, @AValue)) then Result:= AValue else Result:= Unassigned; end; function SplitParsingPath(const S: String): TStringArray; var P: PAnsiChar; AItem: String; I, Len: Integer; Start: Integer = 0; begin I:= 0; Len:= Length(S); P:= PAnsiChar(S); Result:= Default(TStringArray); while I < Len do begin if P[I] = '\' then begin SetString(AItem, @P[Start], I - Start); AddString(Result, AItem); Start:= I + 1; // Special case for "\\?\" and "\\.\" if (P[I + 1] = '\') and (P[I + 2] = '\') and (P[I + 3] in ['?', '.']) and (P[I + 4] = '\') then Inc(I, 4); end; Inc(I); end; if Start < Len then begin SetString(AItem, @P[Start], Len - Start); AddString(Result, AItem); end; end; function ParseDisplayName(Desktop: IShellFolder; const AName: String; out PIDL: PItemIDList): HRESULT; var AItem: String; Index: Integer; pchEaten: ULONG; APath: TStringArray; NumIDs: LongWord = 0; dwAttributes: ULONG = 0; EnumIDList: IEnumIDList; ParentFolder, AFolder: IShellFolder; ParentPIDL, RelativePIDL: PItemIDList; begin APath:= SplitParsingPath(AName); ParentFolder:= Desktop; SHGetFolderLocation(0, CSIDL_DESKTOP, 0, 0, {%H-}ParentPIDL); for Index:= 0 to High(APath) do begin dwAttributes:= 0; AItem:= APath[Index]; Result:= ParentFolder.ParseDisplayName(0, nil, PWideChar(CeUtf8ToUtf16(AItem)), pchEaten, RelativePIDL, dwAttributes); if Failed(Result) then begin Result:= ParentFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList); if Succeeded(Result) then begin Result:= STG_E_PATHNOTFOUND; while EnumIDList.Next(1, RelativePIDL, NumIDs) = S_OK do begin if AItem = GetDisplayName(ParentFolder, RelativePIDL, SHGDN_INFOLDER or SHGDN_FORPARSING) then begin Result:= S_OK; Break; end; CoTaskMemFree(RelativePIDL); end; end; end; if Succeeded(Result) then begin PIDL:= ILCombine(ParentPIDL, RelativePIDL); end; CoTaskMemFree(ParentPIDL); if Failed(Result) then Break; if Index < High(APath) then begin Result:= ParentFolder.BindToObject(RelativePIDL, nil, IID_IShellFolder, Pointer(AFolder)); if Succeeded(Result) then begin ParentPIDL:= PIDL; ParentFolder:= AFolder; end; end; CoTaskMemFree(RelativePIDL); if Failed(Result) then begin CoTaskMemFree(PIDL); Break; end; end; end; function CreateDefaultContextMenu(constref pdcm: TDefContextMenu; const riid: REFIID; out ppv): HRESULT; begin Result:= SHCreateDefaultContextMenu(pdcm, riid, ppv); end; function GetKnownFolderPath(const rfid: TGUID; out APath: String): Boolean; var ppszPath: LPCWSTR; begin Result:= Succeeded(SHGetKnownFolderPath(rfid, KF_FLAG_DEFAULT, 0, ppszPath)); if Result then APath:= UTF16ToUTF8(ppszPath); CoTaskMemFree(ppszPath); end; { TShellFolder } function TShellFolder.QueryInterface(constref iid: tguid; out obj): longint; stdcall; begin Result:= FFolder.QueryInterface(iid, obj); end; constructor TShellFolder.Create(AFolder: IShellFolder; DataObject: IDataObject); begin FFolder:= AFolder; FDataObject:= DataObject; end; function TShellFolder.ParseDisplayName(hwndOwner: HWND; pbcReserved: Pointer; lpszDisplayName: POLESTR; out pchEaten: ULONG; out ppidl: PItemIDList; var dwAttributes: ULONG): HRESULT; stdcall; begin Result:= FFolder.ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten, ppidl, dwAttributes); end; function TShellFolder.EnumObjects(hwndOwner: HWND; grfFlags: DWORD; out EnumIDList: IEnumIDList): HRESULT; stdcall; begin Result:= FFolder.EnumObjects(hwndOwner, grfFlags, EnumIDList); end; function TShellFolder.BindToObject(pidl: PItemIDList; pbcReserved: Pointer; const riid: TIID; out ppvOut): HRESULT; stdcall; begin Result:= FFolder.BindToObject(pidl, pbcReserved, riid, ppvOut); end; function TShellFolder.BindToStorage(pidl: PItemIDList; pbcReserved: Pointer; const riid: TIID; out ppvObj): HRESULT; stdcall; begin Result:= FFolder.BindToStorage(pidl, pbcReserved, riid, ppvObj); end; function TShellFolder.CompareIDs(lParam: LPARAM; pidl1, pidl2: PItemIDList): HRESULT; stdcall; begin Result:= FFolder.CompareIDs(lParam, pidl1, pidl2); end; function TShellFolder.CreateViewObject(hwndOwner: HWND; const riid: TIID; out ppvOut): HRESULT; stdcall; begin Result:= FFolder.CreateViewObject(hwndOwner, riid, ppvOut); end; function TShellFolder.GetAttributesOf(cidl: UINT; var apidl: PItemIDList; var rgfInOut: UINT): HRESULT; stdcall; begin Result:= FFolder.GetAttributesOf(cidl, apidl, rgfInOut); end; function TShellFolder.GetUIObjectOf(hwndOwner: HWND; cidl: UINT; var apidl: PItemIDList; const riid: TIID; prgfInOut: Pointer; out ppvOut ): HRESULT; stdcall; begin if (IsEqualGUID(riid, IID_IDataObject)) then Result:= FDataObject.QueryInterface(riid, ppvOut) else begin Result:= FFolder.GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut); end; end; function TShellFolder.GetDisplayNameOf(pidl: PItemIDList; uFlags: DWORD; var lpName: TStrRet): HRESULT; stdcall; begin Result:= FFolder.GetDisplayNameOf(pidl, uFlags, lpName); end; function TShellFolder.SetNameOf(hwndOwner: HWND; pidl: PItemIDList; lpszName: POLEStr; uFlags: DWORD; var ppidlOut: PItemIDList): HRESULT; stdcall; begin Result:= FFolder.SetNameOf(hwndOwner, pidl, lpszName, uFlags, ppidlOut); end; var AModule: HMODULE; initialization if CheckWin32Version(5, 1) then begin AModule:= GetModuleHandleW(shell32); @SHMultiFileProperties:= GetProcAddress(AModule, 'SHMultiFileProperties'); if Win32MajorVersion > 5 then begin @SHGetKnownFolderPath:= GetProcAddress(AModule, 'SHGetKnownFolderPath'); @SHCreateDefaultContextMenu:= GetProcAddress(AModule, 'SHCreateDefaultContextMenu'); end; end; end. �����������������������������������������������������������������doublecmd-1.1.22/src/platform/win/ushlobjadditional.pas���������������������������������������������0000644�0001750�0000144�00000027256�14743153644�022236� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(* Daniel U. Thibault <D.U.Thibault@Bigfoot.com> 19 August 1999 Updated 15 September 1999 Constants, types that have appeared since ShlObj.pas. The values marked //MISSING VALUES remain unidentified (two sets). Koblov Alexander (Alexx2000@mail.ru) 15 July 2007 Add some functions, constants and types for Lazarus compability *) unit uShlObjAdditional; {$mode delphi} interface uses Windows, ShlObj, ShellApi, ActiveX; const { The operation was canceled by the user } HRESULT_ERROR_CANCELLED = HRESULT($800704C7); { User canceled the current action } COPYENGINE_E_USER_CANCELLED = HRESULT($80270000); const IID_IImageList: TGUID = '{46EB5926-582E-4017-9FDF-E8998DAA0950}'; { IShellIconOverlay Interface } { Used to return the icon overlay index or its icon index for an IShellFolder object, this is always implemented with IShellFolder [Member functions] IShellIconOverlay::GetOverlayIndex Parameters: pidl object to identify icon overlay for. pdwIndex the Overlay Index in the system image list IShellIconOverlay::GetOverlayIconIndex This method is only used for those who are interested in seeing the real bits of the Overlay Icon Returns: S_OK, if the index of an Overlay is found S_FALSE, if no Overlay exists for this file E_FAIL, if pidl is bad Parameters: pdwIconIndex the Overlay Icon index in the system image list } const IID_IShellIconOverlay : TGUID = ( D1:$7D688A70; D2:$C613; D3:$11D0; D4:($99,$9B,$00,$C0,$4F,$D6,$55,$E1)); SID_IShellIconOverlay = '{7D688A70-C613-11D0-999B-00C04FD655E1}'; type IShellIconOverlay = interface(IUnknown) [SID_IShellIconOverlay] function GetOverlayIndex(pidl : PItemIDList; var Index : Integer) : HResult; stdcall; function GetOverlayIconIndex(pidl : PItemIDList; var IconIndex : Integer) : HResult; stdcall; end; { IShellIconOverlay } {$IF FPC_FULLVERSION < 30200} PSHColumnID = ^TSHColumnID; IShellFolder2 = interface(IShellFolder) ['{93F2F68C-1D1B-11d3-A30E-00C04F79ABD1}'] function GetDefaultSearchGUID(out guid:TGUID):HResult;StdCall; function EnumSearches(out ppenum:IEnumExtraSearch):HResult;StdCall; function GetDefaultColumn(dwres:DWORD;psort :pulong; pdisplay:pulong):HResult;StdCall; function GetDefaultColumnState(icolumn:UINT;pscflag:PSHCOLSTATEF):HResult;StdCall; function GetDetailsEx(pidl:LPCITEMIDLIST;pscid:PSHCOLUMNID; pv : pOLEvariant):HResult;StdCall; function GetDetailsOf(pidl:LPCITEMIDLIST;iColumn:UINT;psd:PSHELLDETAILS):HResult;StdCall; function MapColumnToSCID(iColumn:UINT;pscid:PSHCOLUMNID):HResult;StdCall; end; {$ENDIF} const SIID_DRIVENET = 9; SIID_ZIPFILE = 105; PKEY_StorageProviderState: PROPERTYKEY = (fmtid: '{E77E90DF-6271-4F5B-834F-2DD1F245DDA4}'; pid: 3); type TSHStockIconInfo = record cbSize: DWORD; hIcon: HICON; iSysImageIndex: Int32; iIcon: Int32; szPath: array[0..MAX_PATH-1] of WCHAR; end; function SHGetSystemImageList(iImageList: Integer): HIMAGELIST; function SHGetStockIconInfo(siid: Int32; uFlags: UINT; out psii: TSHStockIconInfo): Boolean; function SHChangeIconDialog(hOwner: HWND; var FileName: String; var IconIndex: Integer): Boolean; function SHGetStorePropertyValue(const FileName: String; const Key: PROPERTYKEY): Integer; function SHGetOverlayIconIndex(const sFilePath, sFileName: String): Integer; function SHGetInfoTip(const sFilePath, sFileName: String): String; function SHFileIsLinkToFolder(const FileName: String; out LinkTarget: String): Boolean; function SHGetFolderLocation(hwnd: HWND; csidl: Longint; hToken: HANDLE; dwFlags: DWORD; var ppidl: LPITEMIDLIST): HRESULT; stdcall; external shell32 name 'SHGetFolderLocation'; function PathIsUNCW(pwszPath: LPCWSTR): WINBOOL; stdcall; external 'shlwapi' name 'PathIsUNCW'; function PathFindNextComponentW(pwszPath: LPCWSTR): LPWSTR; stdcall; external 'shlwapi' name 'PathFindNextComponentW'; function StrRetToBufW(pstr: PSTRRET; pidl: PItemIDList; pszBuf: LPWSTR; cchBuf: UINT): HRESULT; stdcall; external 'shlwapi.dll'; procedure OleErrorUTF8(ErrorCode: HResult); procedure OleCheckUTF8(Result: HResult); implementation uses SysUtils, JwaShlGuid, ComObj, LazUTF8, DCOSUtils, DCConvertEncoding; var SHGetPropertyStoreFromParsingName: function(pszPath: PCWSTR; const pbc: IBindCtx; flags: GETPROPERTYSTOREFLAGS; const riid: TIID; out ppv): HRESULT; stdcall; function SHGetImageListFallback(iImageList: Integer; const riid: TGUID; var ImageList: HIMAGELIST): HRESULT; stdcall; var FileInfo: TSHFileInfoW; Flags: UINT = SHGFI_SYSICONINDEX; begin if not IsEqualGUID(riid, IID_IImageList) then Exit(E_NOINTERFACE); case iImageList of SHIL_LARGE, SHIL_EXTRALARGE: Flags:= Flags or SHGFI_LARGEICON; SHIL_SMALL: Flags:= Flags or SHGFI_SMALLICON; end; ZeroMemory(@FileInfo, SizeOf(TSHFileInfoW)); ImageList:= SHGetFileInfoW('', 0, FileInfo, SizeOf(FileInfo), Flags); if ImageList <> 0 then Exit(S_OK) else Exit(E_FAIL); end; function SHGetSystemImageList(iImageList: Integer): HIMAGELIST; var ShellHandle: THandle; SHGetImageList: function(iImageList: Integer; const riid: TGUID; var ImageList: HIMAGELIST): HRESULT; stdcall; begin Result:= 0; ShellHandle:= GetModuleHandle(Shell32); if (ShellHandle <> 0) then begin @SHGetImageList:= GetProcAddress(ShellHandle, 'SHGetImageList'); if @SHGetImageList = nil then begin @SHGetImageList:= GetProcAddress(ShellHandle, PAnsiChar(727)); if @SHGetImageList = nil then SHGetImageList:= @SHGetImageListFallback; end; SHGetImageList(iImageList, IID_IImageList, Result); end; end; function SHGetStockIconInfo(siid: Int32; uFlags: UINT; out psii: TSHStockIconInfo): Boolean; var SHGetStockIconInfo: function(siid: Int32; uFlags: UINT; var psii: TSHStockIconInfo): HRESULT; stdcall; begin Result:= False; if (Win32MajorVersion > 5) then begin @SHGetStockIconInfo:= GetProcAddress(GetModuleHandle(Shell32), 'SHGetStockIconInfo'); if Assigned(SHGetStockIconInfo) then begin psii.cbSize:= SizeOf(TSHStockIconInfo); Result:= SHGetStockIconInfo(siid, uFlags, psii) = S_OK; end; end; end; function SHChangeIconDialog(hOwner: HWND; var FileName: String; var IconIndex: Integer): Boolean; type TSHChangeIconProcW = function(Wnd: HWND; szFileName: PWideChar; Reserved: Integer; var lpIconIndex: Integer): BOOL; stdcall; var ShellHandle: THandle; SHChangeIconW: TSHChangeIconProcW; FileNameW: array[0..MAX_PATH] of WideChar; begin Result := True; IconIndex := 0; ShellHandle := GetModuleHandle(Shell32); if ShellHandle <> 0 then begin @SHChangeIconW := Windows.GetProcAddress(ShellHandle, PAnsiChar(62)); if Assigned(SHChangeIconW) then begin FileNameW := CeUtf8ToUtf16(FileName); Result := SHChangeIconW(hOwner, FileNameW, SizeOf(FileNameW), IconIndex); if Result then FileName := UTF16ToUTF8(UnicodeString(FileNameW)); end end; end; function SHGetStorePropertyValue(const FileName: String; const Key: PROPERTYKEY): Integer; var AValue: Variant; AStorage: IPropertyStore; begin if Succeeded(SHGetPropertyStoreFromParsingName(PWideChar(CeUtf8ToUtf16(FileName)), nil, GPS_DEFAULT, IPropertyStore, AStorage)) then begin if Succeeded(AStorage.GetValue(@Key, TPROPVARIANT(AValue))) then Exit(AValue); end; Result:= -1; end; function SHGetOverlayIconIndex(const sFilePath, sFileName: String): Integer; var Folder, DesktopFolder: IShellFolder; Pidl, ParentPidl: PItemIDList; IconOverlay: IShellIconOverlay; pchEaten: ULONG; dwAttributes: ULONG = 0; wsTemp: WideString; begin Result:= -1; if SHGetDesktopFolder(DesktopFolder) = S_OK then begin wsTemp:= CeUtf8ToUtf16(sFilePath); if DesktopFolder.ParseDisplayName(0, nil, PWideChar(wsTemp), pchEaten, ParentPidl, dwAttributes) = S_OK then begin if DesktopFolder.BindToObject(ParentPidl, nil, IID_IShellFolder, Folder) = S_OK then begin // Get an IShellIconOverlay interface for the folder. // If this fails then this version of // the shell does not have this // interface. if Folder.QueryInterface(IID_IShellIconOverlay, IconOverlay) = S_OK then begin // Get a pidl for the file. wsTemp:= CeUtf8ToUtf16(sFileName); if Folder.ParseDisplayName(0, nil, PWideChar(wsTemp), pchEaten, Pidl, dwAttributes) = S_OK then begin // Get the overlay icon index. if IconOverlay.GetOverlayIconIndex(Pidl, Result) <> S_OK then Result:= -1 // Microsoft OneDrive returns invalid zero index, ignore else if (Result = 0) and (Win32MajorVersion >= 10) then Result:= -1; CoTaskMemFree(Pidl); end; end; end; CoTaskMemFree(ParentPidl); end; DesktopFolder:= nil; end; // SHGetDesktopFolder end; function SHGetInfoTip(const sFilePath, sFileName: String): String; var DesktopFolder, Folder: IShellFolder; pidlFolder: PItemIDList = nil; pidlFile: PItemIDList = nil; queryInfo: IQueryInfo; ppwszTip: PWideChar = nil; pchEaten: ULONG; dwAttributes: ULONG = 0; wsTemp: WideString; begin Result:= EmptyStr; if Succeeded(SHGetDesktopFolder(DesktopFolder)) then try wsTemp:= CeUtf8ToUtf16(sFilePath); if Succeeded(DesktopFolder.ParseDisplayName(0, nil, PWideChar(wsTemp), pchEaten, pidlFolder, dwAttributes)) then if Succeeded(DesktopFolder.BindToObject(pidlFolder, nil, IID_IShellFolder, Folder)) then try wsTemp:= CeUtf8ToUtf16(sFileName); if Succeeded(Folder.ParseDisplayName(0, nil, PWideChar(wsTemp), pchEaten, pidlFile, dwAttributes)) then if Succeeded(Folder.GetUIObjectOf(0, 1, pidlFile, IID_IQueryInfo, nil, queryInfo)) then if Succeeded(queryInfo.GetInfoTip(QITIPF_USESLOWTIP, ppwszTip)) then Result:= UTF16ToUTF8(WideString(ppwszTip)); finally Folder:= nil; queryInfo:= nil; if Assigned(ppwszTip) then CoTaskMemFree(ppwszTip); if Assigned(pidlFile) then CoTaskMemFree(pidlFile); end; finally DesktopFolder:= nil; if Assigned(pidlFolder) then CoTaskMemFree(pidlFolder); end; end; function SHFileIsLinkToFolder(const FileName: String; out LinkTarget: String): Boolean; var Unknown: IUnknown; ShellLink: IShellLinkW; PersistFile: IPersistFile; FindData: TWin32FindDataW; pszFile:LPWSTR; begin Result := False; try Unknown := CreateComObject(CLSID_ShellLink); ShellLink := Unknown as IShellLinkW; PersistFile := Unknown as IPersistFile; if Failed(PersistFile.Load(PWideChar(CeUtf8ToUtf16(FileName)), OF_READ)) then Exit; pszFile:= GetMem(MAX_PATH * 2); try if Failed(ShellLink.GetPath(pszFile, MAX_PATH, @FindData, 0)) then Exit; if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then begin LinkTarget := UTF16ToUTF8(WideString(pszFile)); Result := (LinkTarget <> EmptyStr); end; finally FreeMem(pszFile); end; except LinkTarget := EmptyStr; end; end; procedure OleErrorUTF8(ErrorCode: HResult); begin raise EOleError.Create(mbSysErrorMessage(ErrorCode)); end; procedure OleCheckUTF8(Result: HResult); begin if not Succeeded(Result) then OleErrorUTF8(Result); end; initialization SHGetPropertyStoreFromParsingName:= GetProcAddress(GetModuleHandle('shell32.dll'), 'SHGetPropertyStoreFromParsingName'); end. { ShlObjAdditional } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/uthumbnailprovider.pas��������������������������������������������0000644�0001750�0000144�00000011716�14743153644�022454� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Windows thumbnail provider Copyright (C) 2012-2013 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uThumbnailProvider; {$mode delphi} interface uses uThumbnails; implementation uses SysUtils, Forms, Graphics, Windows, ActiveX, ShlObj, DCConvertEncoding, uBitmap; const SIIGBF_RESIZETOFIT = $00000000; SIIGBF_BIGGERSIZEOK = $00000001; SIIGBF_MEMORYONLY = $00000002; SIIGBF_ICONONLY = $00000004; SIIGBF_THUMBNAILONLY = $00000008; SIIGBF_INCACHEONLY = $00000010; const IID_IExtractImage: TGUID = '{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}'; type SIIGBF = Integer; IShellItemImageFactory = interface(IUnknown) ['{BCC18B79-BA16-442F-80C4-8A59C30C463B}'] function GetImage(size: TSize; flags: SIIGBF; out phbm: HBITMAP): HRESULT; stdcall; end; IExtractImage = interface(IUnknown) ['{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}'] function GetLocation(pszPathBuffer: LPWSTR; cchMax: DWORD; out pdwPriority: DWORD; const prgSize: LPSIZE; dwRecClrDepth: DWORD; var pdwFlags: DWORD): HRESULT; stdcall; function Extract(out phBmpImage: HBITMAP): HRESULT; stdcall; end; var SHCreateItemFromParsingName: function(pszPath: LPCWSTR; const pbc: IBindCtx; const riid: TIID; out ppv): HRESULT; stdcall; function GetThumbnailOld(const aFileName: String; aSize: TSize; out Bitmap: HBITMAP): HRESULT; var Folder, DesktopFolder: IShellFolder; Pidl, ParentPidl: PItemIDList; Image: IExtractImage; pchEaten: ULONG; wsTemp: WideString; dwPriority: DWORD; Status: HRESULT; dwRecClrDepth: DWORD; dwAttributes: ULONG = 0; dwFlags: DWORD = IEIFLAG_SCREEN or IEIFLAG_QUALITY or IEIFLAG_ORIGSIZE; begin Result:= E_FAIL; if SHGetDesktopFolder(DesktopFolder) = S_OK then begin wsTemp:= CeUtf8ToUtf16(ExtractFilePath(aFileName)); if DesktopFolder.ParseDisplayName(0, nil, PWideChar(wsTemp), pchEaten, ParentPidl, dwAttributes) = S_OK then begin if DesktopFolder.BindToObject(ParentPidl, nil, IID_IShellFolder, Folder) = S_OK then begin wsTemp:= CeUtf8ToUtf16(ExtractFileName(aFileName)); if Folder.ParseDisplayName(0, nil, PWideChar(wsTemp), pchEaten, Pidl, dwAttributes) = S_OK then begin if Succeeded(Folder.GetUIObjectOf(0, 1, Pidl, IID_IExtractImage, nil, Image)) then begin SetLength(wsTemp, MAX_PATH * SizeOf(WideChar)); dwRecClrDepth:= GetDeviceCaps(Application.MainForm.Canvas.Handle, BITSPIXEL); Status:= Image.GetLocation(PWideChar(wsTemp), Length(wsTemp), dwPriority, @aSize, dwRecClrDepth, dwFlags); if (Status = NOERROR) or (Status = E_PENDING) then begin Result:= Image.Extract(Bitmap); end; end; CoTaskMemFree(Pidl); end; Folder:= nil; end; CoTaskMemFree(ParentPidl); end; DesktopFolder:= nil; end; // SHGetDesktopFolder end; function GetThumbnailNew(const aFileName: String; aSize: TSize; out Bitmap: HBITMAP): HRESULT; var ShellItemImage: IShellItemImageFactory; begin Result:= SHCreateItemFromParsingName(PWideChar(CeUtf8ToUtf16(aFileName)), nil, IShellItemImageFactory, ShellItemImage); if Succeeded(Result) then begin Result:= ShellItemImage.GetImage(aSize, SIIGBF_THUMBNAILONLY, Bitmap); end; end; function GetThumbnail(const aFileName: String; aSize: TSize): Graphics.TBitmap; var Bitmap: HBITMAP; Status: HRESULT = E_FAIL; begin Result:= nil; if (Win32MajorVersion > 5) then begin Status:= GetThumbnailNew(aFileName, aSize, Bitmap); end; if Failed(Status) then begin Status:= GetThumbnailOld(aFileName, aSize, Bitmap); end; if Succeeded(Status) then begin Result:= BitmapCreateFromHBITMAP(Bitmap); end; end; initialization SHCreateItemFromParsingName:= GetProcAddress(GetModuleHandle('shell32.dll'), 'SHCreateItemFromParsingName'); TThumbnailManager.RegisterProvider(@GetThumbnail); end. ��������������������������������������������������doublecmd-1.1.22/src/platform/win/uwin32widgetsetdark.pas�������������������������������������������0000644�0001750�0000144�00000160102�14743153644�022434� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Windows dark style widgetset implementation Copyright (C) 2021-2024 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. } unit uWin32WidgetSetDark; {$mode objfpc}{$H+} {$modeswitch advancedrecords} interface uses LCLVersion; procedure ApplyDarkStyle; implementation uses Classes, SysUtils, Win32Int, WSLCLClasses, Forms, Windows, Win32Proc, Menus, Controls, LCLType, Win32WSComCtrls, ComCtrls, LMessages, Win32WSStdCtrls, WSStdCtrls, Win32WSControls, StdCtrls, WSControls, Graphics, Themes, LazUTF8, UxTheme, Win32Themes, ExtCtrls, WSMenus, JwaWinGDI, FPImage, Math, uDarkStyle, WSComCtrls, CommCtrl, uImport, WSForms, Win32WSButtons, Buttons, Win32Extra, Win32WSForms, Win32WSSpin, Spin, Win32WSMenus, Dialogs, GraphUtil, Generics.Collections, TmSchema, InterfaceBase; type TWinControlDark = class(TWinControl); TCustomGroupBoxDark = class(TCustomGroupBox); type { TWin32WSWinControlDark } TWin32WSWinControlDark = class(TWin32WSWinControl) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSStatusBarDark } TWin32WSStatusBarDark = class(TWin32WSStatusBar) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSCustomComboBoxDark } TWin32WSCustomComboBoxDark = class(TWin32WSCustomComboBox) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; class function GetDefaultColor(const AControl: TControl; const ADefaultColorType: TDefaultColorType): TColor; override; end; { TWin32WSCustomMemoDark } TWin32WSCustomMemoDark = class(TWin32WSCustomMemo) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSCustomListBoxDark } TWin32WSCustomListBoxDark = class(TWin32WSCustomListBox) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSScrollBoxDark } TWin32WSScrollBoxDark = class(TWin32WSScrollBox) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSCustomFormDark } TWin32WSCustomFormDark = class(TWin32WSCustomForm) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSTrackBarDark } TWin32WSTrackBarDark = class(TWin32WSTrackBar) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; class procedure DefaultWndHandler(const AWinControl: TWinControl; var AMessage); override; end; { TWin32WSPopupMenuDark } TWin32WSPopupMenuDark = class(TWin32WSPopupMenu) published class procedure Popup(const APopupMenu: TPopupMenu; const X, Y: integer); override; end; const ID_SUB_SCROLLBOX = 1; ID_SUB_LISTBOX = 2; ID_SUB_COMBOBOX = 3; ID_SUB_STATUSBAR = 4; ID_SUB_TRACKBAR = 5; const themelib = 'uxtheme.dll'; const VSCLASS_DARK_EDIT = 'DarkMode_CFD::Edit'; VSCLASS_DARK_TAB = 'BrowserTab::Tab'; VSCLASS_DARK_BUTTON = 'DarkMode_Explorer::Button'; VSCLASS_DARK_COMBOBOX = 'DarkMode_CFD::Combobox'; VSCLASS_DARK_SCROLLBAR = 'DarkMode_Explorer::ScrollBar'; VSCLASS_PROGRESS_INDER = 'Indeterminate::Progress'; const MDL_MENU_SUBMENU = #$EE#$A5#$B0; // $E970 MDL_RADIO_FILLED = #$EE#$A8#$BB; // $EA3B MDL_RADIO_CHECKED = #$EE#$A4#$95; // $E915 MDL_RADIO_OUTLINE = #$EE#$A8#$BA; // $EA3A MDL_CHECKBOX_FILLED = #$EE#$9C#$BB; // $E73B MDL_CHECKBOX_CHECKED = #$EE#$9C#$BE; // $E73E MDL_CHECKBOX_GRAYED = #$EE#$9C#$BC; // $E73C MDL_CHECKBOX_OUTLINE = #$EE#$9C#$B9; // $E739 type TThemeClassMap = specialize TDictionary<HTHEME, String>; var ThemeClass: TThemeClassMap; Win32Theme: TWin32ThemeServices; OldUpDownWndProc: Windows.WNDPROC; CustomFormWndProc: Windows.WNDPROC; SysColor: array[0..COLOR_ENDCOLORS] of TColor; SysColorBrush: array[0..COLOR_ENDCOLORS] of HBRUSH; DefSubclassProc: function(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; SetWindowSubclass: function(hWnd: HWND; pfnSubclass: SUBCLASSPROC; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): BOOL; stdcall; procedure EnableDarkStyle(Window: HWND); begin AllowDarkModeForWindow(Window, True); SetWindowTheme(Window, 'DarkMode_Explorer', nil); SendMessageW(Window, WM_THEMECHANGED, 0, 0); end; procedure AllowDarkStyle(var Window: HWND); begin if (Window <> 0) then begin AllowDarkModeForWindow(Window, True); Window:= 0; end; end; function HSVToColor(H, S, V: Double): TColor; var R, G, B: Integer; begin HSVtoRGB(H, S, V, R, G, B); R := Min(MAXBYTE, R); G := Min(MAXBYTE, G); B := Min(MAXBYTE, B); Result:= RGBToColor(R, G, B); end; function Darker(Color: TColor; Factor: Integer): TColor; forward; function Lighter(Color: TColor; Factor: Integer): TColor; var H, S, V: Double; begin // Invalid factor if (Factor <= 0) then Exit(Color); // Makes color darker if (Factor < 100) then begin Exit(darker(Color, 10000 div Factor)); end; ColorToHSV(Color, H, S, V); V:= (Factor * V) / 100; if (V > High(Word)) then begin // Overflow, adjust saturation S -= V - High(Word); if (S < 0) then S := 0; V:= High(Word); end; Result:= HSVToColor(H, S, V); end; function Darker(Color: TColor; Factor: Integer): TColor; var H, S, V: Double; begin // Invalid factor if (Factor <= 0) then Exit(Color); // Makes color lighter if (Factor < 100) then Exit(lighter(Color, 10000 div Factor)); ColorToHSV(Color, H, S, V); V := (V * 100) / Factor; Result:= HSVToColor(H, S, V); end; { Fill rectangle gradient } function FillGradient(hDC: HDC; Start, Finish: TColor; ARect: TRect; dwMode: ULONG): Boolean; var cc: TFPColor; gRect: GRADIENT_RECT; vert: array[0..1] of TRIVERTEX; begin cc:= TColorToFPColor(Start); vert[0].x := ARect.Left; vert[0].y := ARect.Top; vert[0].Red := cc.red; vert[0].Green := cc.green; vert[0].Blue := cc.blue; vert[0].Alpha := cc.alpha; cc:= TColorToFPColor(ColorToRGB(Finish)); vert[1].x := ARect.Right; vert[1].y := ARect.Bottom; vert[1].Red := cc.red; vert[1].Green := cc.green; vert[1].Blue := cc.blue; vert[1].Alpha := cc.alpha; gRect.UpperLeft := 0; gRect.LowerRight := 1; Result:= JwaWinGDI.GradientFill(hDC, vert, 2, @gRect, 1, dwMode); end; function GetNonClientMenuBorderRect(Window: HWND): TRect; var R, W: TRect; begin GetClientRect(Window, @R); // Map to screen coordinate space MapWindowPoints(Window, 0, @R, 2); GetWindowRect(Window, @W); OffsetRect(R, -W.Left, -W.Top); Result:= Classes.Rect(R.Left, R.Top - 1, R.Right, R.Top); end; { Set menu background color } procedure SetMenuBackground(Menu: HMENU); var MenuInfo: TMenuInfo; begin MenuInfo:= Default(TMenuInfo); MenuInfo.cbSize:= SizeOf(MenuInfo); MenuInfo.fMask:= MIM_BACKGROUND or MIM_APPLYTOSUBMENUS; MenuInfo.hbrBack:= CreateSolidBrush(RGBToColor(45, 45, 45)); SetMenuInfo(Menu, @MenuInfo); end; { Set control colors } procedure SetControlColors(Control: TControl; Canvas: HDC); var Color: TColor; begin // Set background color Color:= Control.Color; if Color = clDefault then begin Color:= Control.GetDefaultColor(dctBrush); end; SetBkColor(Canvas, ColorToRGB(Color)); // Set text color Color:= Control.Font.Color; if Color = clDefault then begin Color:= Control.GetDefaultColor(dctFont); end; SetTextColor(Canvas, ColorToRGB(Color)); end; { TWin32WSUpDownControlDark } procedure DrawUpDownArrow(Window: HWND; Canvas: TCanvas; ARect: TRect; AType: TUDAlignButton); var j: integer; ax, ay, ah, aw: integer; procedure Calculate(var a, b: Integer); var tmp: Double; begin tmp:= Double(a + 1) / 2; if (tmp > b) then begin a:= 2 * b - 1; b:= (a + 1) div 2; end else begin b:= Round(tmp); a:= 2 * b - 1; end; b:= Max(b, 3); a:= Max(a, 5); end; begin aw:= ARect.Width div 2; ah:= ARect.Height div 2; if IsWindowEnabled(Window) then Canvas.Pen.Color:= clBtnText else begin Canvas.Pen.Color:= clGrayText; end; if (AType in [udLeft, udRight]) then Calculate(ah, aw) else begin Calculate(aw, ah); end; ax:= ARect.Left + (ARect.Width - aw) div 2; ay:= ARect.Top + (ARect.Height - ah) div 2; case AType of udLeft: begin for j:= 0 to ah div 2 do begin Canvas.MoveTo(ax + aw - j - 2, ay + j); Canvas.LineTo(ax + aw - j - 2, ay + ah - j - 1); end; end; udRight: begin for j:= 0 to ah div 2 do begin Canvas.MoveTo(ax + j, ay + j); Canvas.LineTo(ax + j, ay + ah - j - 1); end; end; udTop: begin for j:= 0 to aw div 2 do begin Canvas.MoveTo(ax + j, ay + ah - j - 1); Canvas.LineTo(ax + aw - j, ay + ah - j - 1); end; end; udBottom: begin for j:= 0 to aw div 2 do begin Canvas.MoveTo(ax + j, ay + j); Canvas.LineTo(ax + aw - j, ay + j); end; end; end; end; function UpDownWndProc(Window: HWND; Msg: UINT; wParam: Windows.WPARAM; lParam: Windows.LPARAM): LRESULT; stdcall; var DC: HDC; L, R: TRect; rcDst: TRect; ARect: TRect; PS: PAINTSTRUCT; LCanvas : TCanvas; LButton, RButton: TUDAlignButton; begin case Msg of WM_PAINT: begin DC := BeginPaint(Window, @ps); LCanvas := TCanvas.Create; try LCanvas.Handle:= DC; GetClientRect(Window, @ARect); LCanvas.Brush.Color:= SysColor[COLOR_BTNFACE]; LCanvas.FillRect(ps.rcPaint); L:= ARect; R:= ARect; if (GetWindowLongPtr(Window, GWL_STYLE) and UDS_HORZ <> 0) then begin LButton:= udLeft; RButton:= udRight; R.Left:= R.Width div 2; L.Right:= L.Right - L.Width div 2; end else begin LButton:= udTop; RButton:= udBottom; R.Top:= R.Height div 2; L.Bottom:= L.Bottom - L.Height div 2; end; if (IntersectRect(rcDst, L, PS.rcPaint)) then begin LCanvas.Pen.Color:= RGBToColor(38, 38, 38); LCanvas.RoundRect(L, 4, 4); InflateRect(L, -1, -1); LCanvas.Pen.Color:= RGBToColor(92, 92, 92); LCanvas.RoundRect(L, 4, 4); DrawUpDownArrow(Window, LCanvas, L, LButton); end; if (IntersectRect(rcDst, R, PS.rcPaint)) then begin LCanvas.Pen.Color:= RGBToColor(38, 38, 38); LCanvas.RoundRect(R, 4, 4); InflateRect(R, -1, -1); LCanvas.Pen.Color:= RGBToColor(92, 92, 92); LCanvas.RoundRect(R, 4, 4); DrawUpDownArrow(Window, LCanvas, R, RButton); end; finally LCanvas.Handle:= 0; LCanvas.Free; end; EndPaint(Window, @ps); Result:= 0; end; WM_ERASEBKGND: begin Exit(1); end; else begin Result:= CallWindowProc(OldUpDownWndProc, Window, Msg, WParam, LParam); end; end; end; { TWin32WSTrackBarDark } function TrackBarWindowProc(Window: HWND; Msg: UINT; wParam: Windows.WPARAM; lParam: Windows.LPARAM; uISubClass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; begin if Msg = WM_ERASEBKGND then Result := 1 else Result := DefSubclassProc(Window, Msg, WParam, LParam); end; class function TWin32WSTrackBarDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; begin AWinControl.Color:= SysColor[COLOR_BTNFACE]; Result:= inherited CreateHandle(AWinControl, AParams); SetWindowSubclass(Result, @TrackBarWindowProc, ID_SUB_TRACKBAR, 0); end; class procedure TWin32WSTrackBarDark.DefaultWndHandler( const AWinControl: TWinControl; var AMessage); var NMHdr: PNMHDR; NMCustomDraw: PNMCustomDraw; begin with TLMessage(AMessage) do case Msg of CN_NOTIFY: begin NMHdr := PNMHDR(LParam); if NMHdr^.code = NM_CUSTOMDRAW then begin NMCustomDraw:= PNMCustomDraw(LParam); case NMCustomDraw^.dwDrawStage of CDDS_PREPAINT: begin Result := CDRF_NOTIFYITEMDRAW; end; CDDS_ITEMPREPAINT: begin case NMCustomDraw^.dwItemSpec of TBCD_CHANNEL: begin Result:= CDRF_SKIPDEFAULT; SelectObject(NMCustomDraw^.hdc, GetStockObject(DC_PEN)); SetDCPenColor(NMCustomDraw^.hdc, SysColor[COLOR_BTNSHADOW]); SelectObject(NMCustomDraw^.hdc, GetStockObject(DC_BRUSH)); SetDCBrushColor(NMCustomDraw^.hdc, SysColor[COLOR_BTNFACE]); with NMCustomDraw^.rc do RoundRect(NMCustomDraw^.hdc, Left, Top, Right, Bottom, 6, 6); end; else begin Result:= CDRF_DODEFAULT; end; end; end; end; end; end else inherited DefaultWndHandler(AWinControl, AMessage); end; end; { TWin32WSScrollBoxDark } function ScrollBoxWindowProc(Window: HWND; Msg: UINT; wParam: Windows.WPARAM; lParam: Windows.LPARAM; uISubClass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; var DC: HDC; R, W: TRect; Delta: Integer; begin Result:= DefSubclassProc(Window, Msg, WParam, LParam); if Msg = WM_NCPAINT then begin GetClientRect(Window, @R); MapWindowPoints(Window, 0, @R, 2); GetWindowRect(Window, @W); Delta:= Abs(W.Top - R.Top); DC:= GetWindowDC(Window); ExcludeClipRect(DC, Delta, Delta, W.Width - Delta, W.Height - Delta); SelectObject(DC, GetStockObject(DC_PEN)); SelectObject(DC, GetStockObject(DC_BRUSH)); SetDCPenColor(DC, SysColor[COLOR_BTNSHADOW]); SetDCBrushColor(DC, SysColor[COLOR_BTNHIGHLIGHT]); Rectangle(DC, 0, 0, W.Width, W.Height); ReleaseDC(Window, DC); end; end; class function TWin32WSScrollBoxDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; begin Result:= inherited CreateHandle(AWinControl, AParams); if TScrollBox(AWinControl).BorderStyle = bsSingle then begin SetWindowSubclass(Result, @ScrollBoxWindowProc, ID_SUB_SCROLLBOX, 0); end; EnableDarkStyle(Result); end; { TWin32WSPopupMenuDark } class procedure TWin32WSPopupMenuDark.Popup(const APopupMenu: TPopupMenu; const X, Y: integer); begin SetMenuBackground(APopupMenu.Handle); inherited Popup(APopupMenu, X, Y); end; { TWin32WSWinControlDark } class function TWin32WSWinControlDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var P: TCreateParams; begin P:= AParams; if (AWinControl is TCustomTreeView) then begin AWinControl.Color:= SysColor[COLOR_WINDOW]; with TCustomTreeView(AWinControl) do begin ExpandSignType:= tvestPlusMinus; TreeLineColor:= SysColor[COLOR_GRAYTEXT]; ExpandSignColor:= SysColor[COLOR_GRAYTEXT]; end; end; P.ExStyle:= p.ExStyle and not WS_EX_CLIENTEDGE; TWinControlDark(AWinControl).BorderStyle:= bsNone; Result:= inherited CreateHandle(AWinControl, P); EnableDarkStyle(Result); end; { TWin32WSCustomFormDark } function FormWndProc2(Window: HWnd; Msg: UInt; WParam: Windows.WParam; LParam: Windows.LParam): LResult; stdcall; var DC: HDC; R: TRect; begin case Msg of WM_NCACTIVATE, WM_NCPAINT: begin Result:= CallWindowProc(CustomFormWndProc, Window, Msg, wParam, lParam); DC:= GetWindowDC(Window); R:= GetNonclientMenuBorderRect(Window); FillRect(DC, R, GetSysColorBrush(COLOR_WINDOW)); ReleaseDC(Window, DC); end; WM_SHOWWINDOW: begin AllowDarkModeForWindow(Window, True); RefreshTitleBarThemeColor(Window); end else begin Result:= CallWindowProc(CustomFormWndProc, Window, Msg, wParam, lParam); end; end; end; class function TWin32WSCustomFormDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var Info: PWin32WindowInfo; begin AWinControl.DoubleBuffered:= True; AWinControl.Color:= SysColor[COLOR_BTNFACE]; AWinControl.Brush.Color:= SysColor[COLOR_BTNFACE]; Result:= inherited CreateHandle(AWinControl, AParams); Info:= GetWin32WindowInfo(Result); Info^.DefWndProc:= @WindowProc; CustomFormWndProc:= Windows.WNDPROC(SetWindowLongPtrW(Result, GWL_WNDPROC, LONG_PTR(@FormWndProc2))); AWinControl.Color:= SysColor[COLOR_BTNFACE]; AWinControl.Font.Color:= SysColor[COLOR_BTNTEXT]; end; { TWin32WSCustomListBoxDark } function ListBoxWindowProc2(Window: HWND; Msg: UINT; wParam: Windows.WPARAM; lParam: Windows.LPARAM; uISubClass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; var PS: TPaintStruct; begin if Msg = WM_PAINT then begin if SendMessage(Window, LB_GETCOUNT, 0, 0) = 0 then begin BeginPaint(Window, @ps); // ListBox:= TCustomListBox(GetWin32WindowInfo(Window)^.WinControl); // Windows.FillRect(DC, ps.rcPaint, ListBox.Brush.Reference.Handle); EndPaint(Window, @ps); end; end; Result:= DefSubclassProc(Window, Msg, WParam, LParam); end; class function TWin32WSCustomListBoxDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var P: TCreateParams; begin P:= AParams; P.ExStyle:= P.ExStyle and not WS_EX_CLIENTEDGE; TCustomListBox(AWinControl).BorderStyle:= bsNone; Result:= inherited CreateHandle(AWinControl, P); EnableDarkStyle(Result); SetWindowSubclass(Result, @ListBoxWindowProc2, ID_SUB_LISTBOX, 0); TCustomListBox(AWinControl).Color:= SysColor[COLOR_WINDOW]; AWinControl.Font.Color:= SysColor[COLOR_WINDOWTEXT]; end; { TWin32WSCustomMemoDark } class function TWin32WSCustomMemoDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var P: TCreateParams; begin P:= AParams; TCustomEdit(AWinControl).BorderStyle:= bsNone; P.ExStyle:= P.ExStyle and not WS_EX_CLIENTEDGE; AWinControl.Color:= SysColor[COLOR_WINDOW]; AWinControl.Font.Color:= SysColor[COLOR_WINDOWTEXT]; Result:= inherited CreateHandle(AWinControl, P); EnableDarkStyle(Result); end; { TWin32WSCustomComboBoxDark } function ComboBoxWindowProc(Window:HWND; Msg:UINT; wParam:Windows.WPARAM;lparam:Windows.LPARAM;uISubClass : UINT_PTR;dwRefData:DWORD_PTR):LRESULT; stdcall; var DC: HDC; ComboBox: TCustomComboBox; begin case Msg of WM_CTLCOLORLISTBOX: begin ComboBox:= TCustomComboBox(GetWin32WindowInfo(Window)^.WinControl); DC:= HDC(wParam); SetControlColors(ComboBox, DC); Exit(LResult(ComboBox.Brush.Reference.Handle)); end; end; Result:= DefSubclassProc(Window, Msg, wParam, lParam); end; class function TWin32WSCustomComboBoxDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var Info: TComboboxInfo; begin AWinControl.Color:= SysColor[COLOR_BTNFACE]; AWinControl.Font.Color:= SysColor[COLOR_BTNTEXT]; Result:= inherited CreateHandle(AWinControl, AParams); Info.cbSize:= SizeOf(Info); Win32Extra.GetComboBoxInfo(Result, @Info); EnableDarkStyle(Info.hwndList); AllowDarkModeForWindow(Result, True); SetWindowSubclass(Result, @ComboBoxWindowProc, ID_SUB_COMBOBOX, 0); end; class function TWin32WSCustomComboBoxDark.GetDefaultColor( const AControl: TControl; const ADefaultColorType: TDefaultColorType): TColor; const DefColors: array[TDefaultColorType] of TColor = ( { dctBrush } clBtnFace, { dctFont } clBtnText ); begin Result:= DefColors[ADefaultColorType]; end; { TWin32WSStatusBarDark } function StatusBarWndProc(Window: HWND; Msg: UINT; wParam: Windows.WPARAM; lParam: Windows.LPARAM; uISubClass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; var DC: HDC; X: Integer; Index: Integer; PS: TPaintStruct; LCanvas: TCanvas; APanel: TStatusPanel; StatusBar: TStatusBar; Info: PWin32WindowInfo; begin Info:= GetWin32WindowInfo(Window); if (Info = nil) or (Info^.WinControl = nil) then begin Result:= CallDefaultWindowProc(Window, Msg, WParam, LParam); Exit; end; if Msg = WM_PAINT then begin StatusBar:= TStatusBar(Info^.WinControl); TWin32WSStatusBar.DoUpdate(StatusBar); DC:= BeginPaint(Window, @ps); LCanvas:= TCanvas.Create; try LCanvas.Handle:= DC; LCanvas.Brush.Color:= SysColor[COLOR_BTNFACE]; LCanvas.FillRect(ps.rcPaint); X:= 1; LCanvas.Font.Color:= clWhite; for Index:= 0 to StatusBar.Panels.Count - 1 do begin APanel:= StatusBar.Panels[Index]; LCanvas.TextOut(X, 1, APanel.Text); X+= APanel.Width; { LCanvas.Pen.Color:= Darker(RGBToColor(53, 53, 53), 120); LCanvas.Line(x-1, ps.rcPaint.Top, x-1, ps.rcPaint.Bottom); LCanvas.Pen.Color:= Lighter(RGBToColor(53, 53, 53), 154); LCanvas.Line(x-2, ps.rcPaint.Top, x-2, ps.rcPaint.Bottom); } end; finally LCanvas.Handle:= 0; LCanvas.Free; end; EndPaint(Window, @ps); Result:= 0; end else Result:= DefSubclassProc(Window, Msg, WParam, LParam); end; class function TWin32WSStatusBarDark.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; begin Result:= inherited CreateHandle(AWinControl, AParams); SetWindowSubclass(Result, @StatusBarWndProc, ID_SUB_STATUSBAR, 0); end; { Forward declared functions } function InterceptOpenThemeData(hwnd: hwnd; pszClassList: LPCWSTR): hTheme; stdcall; forward; procedure DrawButton(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); forward; { Draws text using the color and font defined by the visual style } function DrawThemeTextDark(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; pszText: LPCWSTR; iCharCount: Integer; dwTextFlags, dwTextFlags2: DWORD; const pRect: TRect): HRESULT; stdcall; var OldColor: COLORREF; begin if (hTheme = Win32Theme.Theme[teToolTip]) then OldColor:= SysColor[COLOR_INFOTEXT] else begin OldColor:= SysColor[COLOR_BTNTEXT]; end; OldColor:= SetTextColor(hdc, OldColor); SetBkMode(hdc, TRANSPARENT); DrawTextExW(hdc, pszText, iCharCount, @pRect, dwTextFlags, nil); SetTextColor(hdc, OldColor); Result:= S_OK; end; { Draws the border and fill defined by the visual style for the specified control part } function DrawThemeBackgroundDark(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT): HRESULT; stdcall; var LRect: TRect; AColor: TColor; LCanvas: TCanvas; AStyle: TTextStyle; begin if (hTheme = Win32Theme.Theme[teHeader]) then begin if iPartId in [HP_HEADERITEM, HP_HEADERITEMRIGHT] then begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= hdc; AColor:= SysColor[COLOR_BTNFACE]; if iStateId in [HIS_HOT, HIS_SORTEDHOT, HIS_ICONHOT, HIS_ICONSORTEDHOT] then FillGradient(hdc, Lighter(AColor, 174), Lighter(AColor, 166), pRect, GRADIENT_FILL_RECT_V) else FillGradient(hdc, Lighter(AColor, 124), Lighter(AColor, 116), pRect, GRADIENT_FILL_RECT_V); if (iPartId <> HP_HEADERITEMRIGHT) then begin LCanvas.Pen.Color:= Lighter(AColor, 158); LCanvas.Line(pRect.Right - 1, pRect.Top, pRect.Right - 1, pRect.Bottom); end; // Top line LCanvas.Pen.Color:= Lighter(AColor, 164); LCanvas.Line(pRect.Left, pRect.Top, pRect.Right, pRect.Top); // Bottom line LCanvas.Pen.Color:= Darker(AColor, 140); LCanvas.Line(pRect.Left, pRect.Bottom - 1, pRect.Right, pRect.Bottom - 1); finally LCanvas.Handle:= 0; LCanvas.Free; end; end; end else if (hTheme = Win32Theme.Theme[teMenu]) then begin if iPartId in [MENU_BARBACKGROUND, MENU_POPUPITEM, MENU_POPUPGUTTER, MENU_POPUPSUBMENU, MENU_POPUPSEPARATOR, MENU_POPUPCHECK, MENU_POPUPCHECKBACKGROUND] then begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= hdc; if not (iPartId in [MENU_POPUPSUBMENU, MENU_POPUPCHECK, MENU_POPUPCHECKBACKGROUND]) then begin if iStateId = MDS_HOT then LCanvas.Brush.Color:= SysColor[COLOR_MENUHILIGHT] else begin LCanvas.Brush.Color:= RGBToColor(45, 45, 45); end; LCanvas.FillRect(pRect); end; if iPartId = MENU_POPUPCHECK then begin AStyle:= LCanvas.TextStyle; AStyle.Layout:= tlCenter; AStyle.Alignment:= taCenter; LCanvas.Brush.Style:= bsClear; LCanvas.Font.Name:= 'Segoe MDL2 Assets'; LCanvas.Font.Color:= RGBToColor(212, 212, 212); LCanvas.TextRect(pRect, 0, 0, MDL_CHECKBOX_CHECKED, AStyle); end; if iPartId = MENU_POPUPSEPARATOR then begin LRect:= pRect; LCanvas.Pen.Color:= RGBToColor(112, 112, 112); LRect.Top:= LRect.Top + (LRect.Height div 2); LRect.Bottom:= LRect.Top; LCanvas.Line(LRect); end; if (iPartId = MENU_POPUPCHECKBACKGROUND) then begin LRect:= pRect; InflateRect(LRect, -1, -1); LCanvas.Pen.Color:= RGBToColor(45, 45, 45); LCanvas.Brush.Color:= RGBToColor(81, 81, 81); LCanvas.RoundRect(LRect, 6, 6); end; if iPartId = MENU_POPUPSUBMENU then begin LCanvas.Brush.Style:= bsClear; LCanvas.Font.Name:= 'Segoe MDL2 Assets'; LCanvas.Font.Color:= RGBToColor(111, 111, 111); LCanvas.TextOut(pRect.Left, pRect.Top, MDL_MENU_SUBMENU); end; finally LCanvas.Handle:= 0; LCanvas.Free; end; end; end else if (hTheme = Win32Theme.Theme[teToolBar]) then begin if iPartId in [TP_BUTTON] then begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= hdc; AColor:= SysColor[COLOR_BTNFACE]; if iStateId = TS_HOT then LCanvas.Brush.Color:= Lighter(AColor, 116) else if iStateId = TS_PRESSED then LCanvas.Brush.Color:= Darker(AColor, 116) else begin LCanvas.Brush.Color:= AColor; end; LCanvas.FillRect(pRect); if iStateId <> TS_NORMAL then begin if iStateId = TS_CHECKED then begin LRect:= pRect; InflateRect(LRect, -2, -2); LCanvas.Brush.Color:= Lighter(AColor, 146); LCanvas.FillRect(LRect); end; LCanvas.Pen.Color:= Darker(AColor, 140); LCanvas.RoundRect(pRect, 6, 6); LRect:= pRect; LCanvas.Pen.Color:= Lighter(AColor, 140); InflateRect(LRect, -1, -1); LCanvas.RoundRect(LRect, 6, 6); end; finally LCanvas.Handle:= 0; LCanvas.Free; end; end; end else if (hTheme = Win32Theme.Theme[teButton]) then begin DrawButton(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end; Result:= S_OK; end; var __CreateWindowExW: function(dwExStyle: DWORD; lpClassName: LPCWSTR; lpWindowName: LPCWSTR; dwStyle: DWORD; X: longint; Y: longint; nWidth: longint; nHeight: longint; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: LPVOID): HWND; stdcall; function _DrawEdge(hdc: HDC; var qrc: TRect; edge: UINT; grfFlags: UINT): BOOL; stdcall; var Original: HGDIOBJ; ClientRect: TRect; ColorDark, ColorLight: TColorRef; procedure DrawLine(X1, Y1, X2, Y2: Integer); begin MoveToEx(hdc, X1, Y1, nil); LineTo(hdc, X2, Y2); end; procedure InternalDrawEdge(Outer: Boolean; const R: TRect); var X1, Y1, X2, Y2: Integer; ColorLeftTop, ColorRightBottom: TColor; begin X1:= R.Left; Y1:= R.Top; X2:= R.Right; Y2:= R.Bottom; ColorLeftTop:= clNone; ColorRightBottom:= clNone; if Outer then begin if Edge and BDR_RAISEDOUTER <> 0 then begin ColorLeftTop:= ColorLight; ColorRightBottom:= ColorDark; end else if Edge and BDR_SUNKENOUTER <> 0 then begin ColorLeftTop:= ColorDark; ColorRightBottom:= ColorLight; end; end else begin if Edge and BDR_RAISEDINNER <> 0 then begin ColorLeftTop:= ColorLight; ColorRightBottom:= ColorDark; end else if Edge and BDR_SUNKENINNER <> 0 then begin ColorLeftTop:= ColorDark; ColorRightBottom:= ColorLight; end; end; SetDCPenColor(hdc, ColorLeftTop); if grfFlags and BF_LEFT <> 0 then DrawLine(X1, Y1, X1, Y2); if grfFlags and BF_TOP <> 0 then DrawLine(X1, Y1, X2, Y1); SetDCPenColor(hdc, ColorRightBottom); if grfFlags and BF_RIGHT <> 0 then DrawLine(X2, Y1, X2, Y2); if grfFlags and BF_BOTTOM <> 0 then DrawLine(X1, Y2, X2, Y2); end; begin Result:= False; if IsRectEmpty(qrc) then Exit; ClientRect:= qrc; Dec(ClientRect.Right, 1); Dec(ClientRect.Bottom, 1); Original:= SelectObject(hdc, GetStockObject(DC_PEN)); try ColorDark:= SysColor[COLOR_BTNSHADOW]; ColorLight:= SysColor[COLOR_BTNHIGHLIGHT]; if Edge and (BDR_SUNKENOUTER or BDR_RAISEDOUTER) <> 0 then begin InternalDrawEdge(True, ClientRect); end; InflateRect(ClientRect, -1, -1); if Edge and (BDR_SUNKENINNER or BDR_RAISEDINNER) <> 0 then begin InternalDrawEdge(False, ClientRect); InflateRect(ClientRect, -1, -1); end; Inc(ClientRect.Right); Inc(ClientRect.Bottom); if grfFlags and BF_ADJUST <> 0 then begin qrc:= ClientRect; end; Result:= True; finally SelectObject(hdc, Original); end; end; { Retrieves the current color of the specified display element } function GetSysColorDark(nIndex: longint): DWORD; stdcall; begin if (nIndex >= 0) and (nIndex <= COLOR_ENDCOLORS) then Result:= SysColor[nIndex] else begin Result:= 0; end; end; { Retrieves a handle identifying a logical brush that corresponds to the specified color index } function GetSysColorBrushDark(nIndex: longint): HBRUSH; stdcall; begin if (nIndex >= 0) and (nIndex <= COLOR_ENDCOLORS) then begin if (SysColorBrush[nIndex] = 0) then begin SysColorBrush[nIndex]:= CreateSolidBrush(SysColor[nIndex]); end; Result:= SysColorBrush[nIndex]; end else begin Result:= CreateSolidBrush(GetSysColorDark(nIndex)); end; end; const ClassNameW: PWideChar = 'TCustomForm'; ClassNameTC: PWideChar = 'TTOTAL_CMD'; // for compatibility with plugins function _CreateWindowExW(dwExStyle: DWORD; lpClassName: LPCWSTR; lpWindowName: LPCWSTR; dwStyle: DWORD; X: longint; Y: longint; nWidth: longint; nHeight: longint; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: LPVOID): HWND; stdcall; var AParams: PNCCreateParams absolute lpParam; begin if Assigned(AParams) and (AParams^.WinControl is TCustomForm) then begin if (hWndParent = 0) and AParams^.WinControl.ClassNameIs('TfrmMain') then lpClassName:= ClassNameTC else begin lpClassName:= ClassNameW; end; end else begin dwExStyle:= dwExStyle or WS_EX_CONTEXTHELP; end; Result:= __CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); end; function TaskDialogIndirectDark(const pTaskConfig: PTASKDIALOGCONFIG; pnButton: PInteger; pnRadioButton: PInteger; pfVerificationFlagChecked: PBOOL): HRESULT; stdcall; const BTN_USER = $1000; var Idx: Integer; Index: Integer; Button: TDialogButton; Buttons: TDialogButtons; DlgType: Integer = idDialogInfo; begin with pTaskConfig^ do begin if (pszMainIcon = TD_INFORMATION_ICON) then DlgType:= idDialogInfo else if (pszMainIcon = TD_WARNING_ICON) then DlgType:= idDialogWarning else if (pszMainIcon = TD_ERROR_ICON) then DlgType:= idDialogError else if (pszMainIcon = TD_SHIELD_ICON) then DlgType:= idDialogShield else if (dwFlags and TDF_USE_HICON_MAIN <> 0) then begin if (hMainIcon = Windows.LoadIcon(0, IDI_QUESTION)) then DlgType:= idDialogConfirm; end; Buttons:= TDialogButtons.Create(TDialogButton); try for Index:= 0 to cButtons - 1 do begin Button:= Buttons.Add; Idx:= pButtons[Index].nButtonID; Button.ModalResult:= (Idx + BTN_USER); Button.Default:= (Idx = nDefaultButton); Button.Caption:= UTF8Encode(UnicodeString(pButtons[Index].pszButtonText)); end; Result:= DefaultQuestionDialog(UTF8Encode(UnicodeString(pszWindowTitle)), UTF8Encode(UnicodeString(pszContent)), DlgType, Buttons, 0); if Assigned(pnButton) then begin if (Result < BTN_USER) then pnButton^:= Result else begin pnButton^:= Result - BTN_USER; end; end; finally Buttons.Free; end; end; Result:= S_OK; end; procedure SubClassUpDown; var Window: HWND; begin Window:= CreateWindowW(UPDOWN_CLASSW, nil, 0, 0, 0, 200, 20, 0, 0, HINSTANCE, nil); OldUpDownWndProc:= Windows.WNDPROC(GetClassLongPtr(Window, GCLP_WNDPROC)); SetClassLongPtr(Window, GCLP_WNDPROC, LONG_PTR(@UpDownWndProc)); DestroyWindow(Window); end; procedure ScreenFormEvent(Self, Sender: TObject; Form: TCustomForm); begin if Assigned(Form.Menu) then begin Form.Menu.OwnerDraw:= True; SetMenuBackground(GetMenu(Form.Handle)); Form.Menu.OwnerDraw:= False; end; end; { Override several widgetset controls } procedure ApplyDarkStyle; var Handler: TMethod; Index: TThemedElement; begin if not g_darkModeEnabled then Exit; SubClassUpDown; OpenThemeData:= @InterceptOpenThemeData; DefBtnColors[dctFont]:= SysColor[COLOR_BTNTEXT]; DefBtnColors[dctBrush]:= SysColor[COLOR_BTNFACE]; Handler.Code:= @ScreenFormEvent; Screen.AddHandlerFormVisibleChanged(TScreenFormEvent(Handler), True); with TWinControl.Create(nil) do Free; RegisterWSComponent(TWinControl, TWin32WSWinControlDark); WSComCtrls.RegisterStatusBar; RegisterWSComponent(TStatusBar, TWin32WSStatusBarDark); WSStdCtrls.RegisterCustomComboBox; RegisterWSComponent(TCustomComboBox, TWin32WSCustomComboBoxDark); WSStdCtrls.RegisterCustomEdit; WSStdCtrls.RegisterCustomMemo; RegisterWSComponent(TCustomMemo, TWin32WSCustomMemoDark); WSStdCtrls.RegisterCustomListBox; RegisterWSComponent(TCustomListBox, TWin32WSCustomListBoxDark); WSForms.RegisterScrollingWinControl; WSForms.RegisterCustomForm; RegisterWSComponent(TCustomForm, TWin32WSCustomFormDark); WSMenus.RegisterMenu; WSMenus.RegisterPopupMenu; RegisterWSComponent(TPopupMenu, TWin32WSPopupMenuDark); WSForms.RegisterScrollBox; RegisterWSComponent(TScrollBox, TWin32WSScrollBoxDark); RegisterCustomTrackBar; RegisterWSComponent(TCustomTrackBar, TWin32WSTrackBarDark); DrawThemeText:= @DrawThemeTextDark; DrawThemeBackground:= @DrawThemeBackgroundDark; DefaultWindowInfo.DefWndProc:= @WindowProc; TaskDialogIndirect:= @TaskDialogIndirectDark; Win32Theme:= TWin32ThemeServices(ThemeServices); end; function FormWndProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam; LParam: Windows.LParam): LResult; stdcall; var Info: PWin32WindowInfo; begin if Msg = WM_CREATE then begin AllowDarkModeForWindow(Window, True); RefreshTitleBarThemeColor(Window); end else if (Msg = WM_SETFONT) then begin Info := GetWin32WindowInfo(Window); if Assigned(Info) then begin Info^.DefWndProc:= @WindowProc; end; Result:= CallWindowProc(@WindowProc, Window, Msg, WParam, LParam); Exit; end; Result:= DefWindowProcW(Window, Msg, WParam, LParam); end; var TrampolineOpenThemeData: function(hwnd: HWND; pszClassList: LPCWSTR): HTHEME; stdcall = nil; TrampolineDrawThemeText: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; pszText: LPCWSTR; iCharCount: Integer; dwTextFlags, dwTextFlags2: DWORD; const pRect: TRect): HRESULT; stdcall = nil; TrampolineDrawThemeBackground: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: Pointer): HRESULT; stdcall = nil; procedure DrawCheckBox(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); var LCanvas: TCanvas; AStyle: TTextStyle; begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= HDC; LCanvas.Brush.Color:= clBtnFace; LCanvas.FillRect(pRect); AStyle:= LCanvas.TextStyle; AStyle.Layout:= tlCenter; AStyle.ShowPrefix:= True; // Fill checkbox rect LCanvas.Font.Name:= 'Segoe MDL2 Assets'; LCanvas.Font.Color:= SysColor[COLOR_WINDOW]; LCanvas.TextRect(pRect, 0, 0, MDL_CHECKBOX_FILLED, AStyle); // Draw checkbox border if iStateId in [CBS_UNCHECKEDHOT, CBS_MIXEDHOT, CBS_CHECKEDHOT] then LCanvas.Font.Color:= SysColor[COLOR_HIGHLIGHT] else begin LCanvas.Font.Color:= RGBToColor(192, 192, 192); end; LCanvas.TextRect(pRect, 0, 0, MDL_CHECKBOX_OUTLINE, AStyle); // Draw checkbox state if iStateId in [CBS_MIXEDNORMAL, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDDISABLED] then begin LCanvas.Font.Color:= RGBToColor(120, 120, 120); LCanvas.TextRect(pRect, 0, 0, MDL_CHECKBOX_GRAYED, AStyle); end else if iStateId in [CBS_CHECKEDNORMAL, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDDISABLED] then begin LCanvas.Font.Color:= RGBToColor(192, 192, 192); LCanvas.TextRect(pRect, 0, 0, MDL_CHECKBOX_CHECKED, AStyle); end; finally LCanvas.Handle:= 0; LCanvas.Free; end; end; procedure DrawRadionButton(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); var LCanvas: TCanvas; AStyle: TTextStyle; begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= hdc; LCanvas.Brush.Color:= SysColor[COLOR_BTNFACE]; LCanvas.FillRect(pRect); AStyle:= LCanvas.TextStyle; AStyle.Layout:= tlCenter; AStyle.ShowPrefix:= True; // Draw radio circle LCanvas.Font.Name:= 'Segoe MDL2 Assets'; LCanvas.Font.Color:= SysColor[COLOR_WINDOW]; LCanvas.TextRect(pRect, 0, 0, MDL_RADIO_FILLED, AStyle); // Draw radio button state if iStateId in [RBS_CHECKEDNORMAL, RBS_CHECKEDHOT, RBS_CHECKEDPRESSED, RBS_CHECKEDDISABLED] then begin LCanvas.Font.Color:= RGBToColor(192, 192, 192); LCanvas.TextRect(pRect, 0, 0, MDL_RADIO_CHECKED, AStyle ); end; // Set outline circle color if iStateId in [RBS_UNCHECKEDPRESSED, RBS_CHECKEDPRESSED] then LCanvas.Font.Color:= RGBToColor(83, 160, 237) else if iStateId in [RBS_UNCHECKEDHOT, RBS_CHECKEDHOT] then LCanvas.Font.Color:= SysColor[COLOR_HIGHLIGHT] else begin LCanvas.Font.Color:= RGBToColor(192, 192, 192); end; // Draw outline circle LCanvas.TextRect(pRect, 0, 0, MDL_RADIO_OUTLINE, AStyle); finally LCanvas.Handle:= 0; LCanvas.Free; end; end; procedure DrawGroupBox(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); var LCanvas: TCanvas; begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= HDC; // Draw border LCanvas.Brush.Style:= bsClear; LCanvas.Pen.Color:= SysColor[COLOR_BTNHIGHLIGHT]; LCanvas.RoundRect(pRect, 10, 10); finally LCanvas.Handle:= 0; LCanvas.Free; end; end; procedure DrawButton(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); begin case iPartId of BP_PUSHBUTTON: TrampolineDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); BP_RADIOBUTTON: DrawRadionButton(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); BP_CHECKBOX: DrawCheckBox(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); BP_GROUPBOX: DrawGroupBox(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end; end; procedure DrawTabControl(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); var ARect: TRect; AColor: TColor; ALight: TColor; LCanvas: TCanvas; begin LCanvas:= TCanvas.Create; try LCanvas.Handle:= hdc; AColor:= SysColor[COLOR_BTNFACE]; ALight:= Lighter(AColor, 160); if (iPartId < TABP_PANE) then begin ARect:= pRect; // Fill tab inside if (iStateId <> TIS_SELECTED) then begin if iStateId <> TIS_HOT then LCanvas.Brush.Color:= Lighter(AColor, 117) else begin LCanvas.Brush.Color:= Lighter(AColor, 200); end; end else begin Dec(ARect.Bottom); InflateRect(ARect, -1, -1); LCanvas.Brush.Color:= Lighter(AColor, 176); end; LCanvas.FillRect(ARect); LCanvas.Pen.Color:= ALight; if iPartId in [TABP_TABITEMLEFTEDGE, TABP_TABITEMBOTHEDGE, TABP_TOPTABITEMLEFTEDGE, TABP_TOPTABITEMBOTHEDGE] then begin // Draw left border LCanvas.Line(pRect.Left, pRect.Top, pRect.Left, pRect.Bottom); end; if (iStateId <> TIS_SELECTED) then begin // Draw right border LCanvas.Line(pRect.Right - 1, pRect.Top, pRect.Right - 1, pRect.Bottom) end else begin // Draw left border if (iPartId in [TABP_TABITEM, TABP_TOPTABITEM]) then begin LCanvas.Line(pRect.Left, pRect.Top, pRect.Left, pRect.Bottom - 1); end; // Draw right border LCanvas.Line(pRect.Right - 1, pRect.Top, pRect.Right - 1, pRect.Bottom - 1); end; // Draw top border LCanvas.Line(pRect.Left, pRect.Top, pRect.Right, pRect.Top); end else if (iPartId = TABP_PANE) then begin // Draw tab pane border LCanvas.Brush.Color:= AColor; LCanvas.Pen.Color:= ALight; LCanvas.Rectangle(pRect); end; finally LCanvas.Handle:= 0; LCanvas.Free; end; end; procedure DrawProgressBar(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: PRECT); begin if not (iPartId in [PP_TRANSPARENTBAR, PP_TRANSPARENTBARVERT]) then TrampolineDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect) else begin SelectObject(hdc, GetStockObject(DC_PEN)); SetDCPenColor(hdc, SysColor[COLOR_BTNSHADOW]); SelectObject(hdc, GetStockObject(DC_BRUSH)); SetDCBrushColor(hdc, SysColor[COLOR_BTNFACE]); with pRect do Rectangle(hdc, Left, Top, Right, Bottom); end; end; function InterceptOpenThemeData(hwnd: hwnd; pszClassList: LPCWSTR): hTheme; stdcall; var P: LONG_PTR; begin if (hwnd <> 0) then begin P:= GetWindowLongPtr(hwnd, GWL_EXSTYLE); if (P and WS_EX_CONTEXTHELP = 0) or (lstrcmpiW(pszClassList, VSCLASS_MONTHCAL) = 0) then begin Result:= TrampolineOpenThemeData(hwnd, pszClassList); Exit; end; end; if lstrcmpiW(pszClassList, VSCLASS_TAB) = 0 then begin AllowDarkStyle(hwnd); pszClassList:= PWideChar(VSCLASS_DARK_TAB); end else if lstrcmpiW(pszClassList, VSCLASS_BUTTON) = 0 then begin AllowDarkStyle(hwnd); pszClassList:= PWideChar(VSCLASS_DARK_BUTTON); end else if lstrcmpiW(pszClassList, VSCLASS_EDIT) = 0 then begin AllowDarkStyle(hwnd); pszClassList:= PWideChar(VSCLASS_DARK_EDIT); end else if lstrcmpiW(pszClassList, VSCLASS_COMBOBOX) = 0 then begin AllowDarkStyle(hwnd); pszClassList:= PWideChar(VSCLASS_DARK_COMBOBOX); end else if lstrcmpiW(pszClassList, VSCLASS_SCROLLBAR) = 0 then begin AllowDarkStyle(hwnd); pszClassList:= PWideChar(VSCLASS_DARK_SCROLLBAR); end; Result:= TrampolineOpenThemeData(hwnd, pszClassList); ThemeClass.AddOrSetValue(Result, pszClassList); end; function InterceptDrawThemeText(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; pszText: LPCWSTR; iCharCount: Integer; dwTextFlags, dwTextFlags2: DWORD; const pRect: TRect): HRESULT; stdcall; var OldColor: COLORREF; ClassName: String; begin if ThemeClass.TryGetValue(hTheme, ClassName) then begin if SameText(ClassName, VSCLASS_DARK_COMBOBOX) or SameText(ClassName, VSCLASS_DARK_EDIT) then begin Result:= TrampolineDrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect); Exit; end; if SameText(ClassName, VSCLASS_TOOLTIP) then OldColor:= SysColor[COLOR_INFOTEXT] else begin OldColor:= SysColor[COLOR_BTNTEXT]; end; if SameText(ClassName, VSCLASS_DARK_BUTTON) then begin if (iPartId = BP_CHECKBOX) and (iStateId in [CBS_UNCHECKEDDISABLED, CBS_CHECKEDDISABLED, CBS_MIXEDDISABLED]) then OldColor:= SysColor[COLOR_GRAYTEXT] else if (iPartId = BP_RADIOBUTTON) and (iStateId in [RBS_UNCHECKEDDISABLED, RBS_CHECKEDDISABLED]) then OldColor:= SysColor[COLOR_GRAYTEXT] else if (iPartId = BP_GROUPBOX) and (iStateId = GBS_DISABLED) then OldColor:= SysColor[COLOR_GRAYTEXT] else if (iPartId = BP_PUSHBUTTON) then begin Result:= TrampolineDrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect); Exit; end; end; OldColor:= SetTextColor(hdc, OldColor); SetBkMode(hdc, TRANSPARENT); DrawTextExW(hdc, pszText, iCharCount, @pRect, dwTextFlags, nil); SetTextColor(hdc, OldColor); Exit(S_OK); end; Result:= TrampolineDrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect); end; function InterceptDrawThemeBackground(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: Pointer): HRESULT; stdcall; var Index: Integer; ClassName: String; begin if ThemeClass.TryGetValue(hTheme, ClassName) then begin Index:= SaveDC(hdc); try if SameText(ClassName, VSCLASS_DARK_BUTTON) then begin DrawButton(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end else if SameText(ClassName, VSCLASS_DARK_TAB) then begin DrawTabControl(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end else if SameText(ClassName, VSCLASS_PROGRESS) or SameText(ClassName, VSCLASS_PROGRESS_INDER) then begin DrawProgressBar(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end else begin Result:= TrampolineDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end; finally RestoreDC(hdc, Index); end; Exit(S_OK); end; Result:= TrampolineDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); end; function DrawThemeEdgeDark(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pDestRect: TRect; uEdge, uFlags: UINT; pContentRect: PRECT): HRESULT; stdcall; var ARect: TRect; begin ARect:= pDestRect; _DrawEdge(hdc, ARect, uEdge, uFlags); if (uFlags and DFCS_ADJUSTRECT <> 0) and (pContentRect <> nil) then pContentRect^ := ARect; Result:= S_OK; end; function GetThemeSysColorDark(hTheme: HTHEME; iColorId: Integer): COLORREF; stdcall; begin Result:= GetSysColor(iColorId); end; function GetThemeSysColorBrushDark(hTheme: HTHEME; iColorId: Integer): HBRUSH; stdcall; begin Result:= GetSysColorBrush(iColorId); end; var DeleteObjectOld: function(ho: HGDIOBJ): WINBOOL; stdcall; function __DeleteObject(ho: HGDIOBJ): WINBOOL; stdcall; var Index: Integer; begin for Index:= 0 to High(SysColorBrush) do begin if SysColorBrush[Index] = ho then Exit(True); end; Result:= DeleteObjectOld(ho); end; procedure InitializeColors; begin SysColor[COLOR_SCROLLBAR] := RGBToColor(53, 53, 53); SysColor[COLOR_BACKGROUND] := RGBToColor(53, 53, 53); SysColor[COLOR_ACTIVECAPTION] := RGBToColor(42, 130, 218); SysColor[COLOR_INACTIVECAPTION] := RGBToColor(53, 53, 53); SysColor[COLOR_MENU] := RGBToColor(42, 42, 42); SysColor[COLOR_WINDOW] := RGBToColor(42, 42, 42); SysColor[COLOR_WINDOWFRAME] := RGBToColor(20, 20, 20); SysColor[COLOR_MENUTEXT] := RGBToColor(255, 255, 255); SysColor[COLOR_WINDOWTEXT] := RGBToColor(255, 255, 255); SysColor[COLOR_CAPTIONTEXT] := RGBToColor(255, 255, 255); SysColor[COLOR_ACTIVEBORDER] := RGBToColor(53, 53, 53); SysColor[COLOR_INACTIVEBORDER] := RGBToColor(53, 53, 53); SysColor[COLOR_APPWORKSPACE] := RGBToColor(53, 53, 53); SysColor[COLOR_HIGHLIGHT] := RGBToColor(42, 130, 218); SysColor[COLOR_HIGHLIGHTTEXT] := RGBToColor(255, 255, 255); SysColor[COLOR_BTNFACE] := RGBToColor(53, 53, 53); SysColor[COLOR_BTNSHADOW] := RGBToColor(35, 35, 35); SysColor[COLOR_GRAYTEXT] := RGBToColor(160, 160, 160); SysColor[COLOR_BTNTEXT] := RGBToColor(255, 255, 255); SysColor[COLOR_INACTIVECAPTIONTEXT] := RGBToColor(255, 255, 255); SysColor[COLOR_BTNHIGHLIGHT] := RGBToColor(66, 66, 66); SysColor[COLOR_3DDKSHADOW] := RGBToColor(20, 20, 20); SysColor[COLOR_3DLIGHT] := RGBToColor(40, 40, 40); SysColor[COLOR_INFOTEXT] := RGBToColor(53, 53, 53); SysColor[COLOR_INFOBK] := RGBToColor(255, 255, 255); SysColor[COLOR_HOTLIGHT] := RGBToColor(66, 66, 66); SysColor[COLOR_GRADIENTACTIVECAPTION] := GetSysColor(COLOR_GRADIENTACTIVECAPTION); SysColor[COLOR_GRADIENTINACTIVECAPTION] := GetSysColor(COLOR_GRADIENTINACTIVECAPTION); SysColor[COLOR_MENUHILIGHT] := RGBToColor(42, 130, 218); SysColor[COLOR_MENUBAR] := RGBToColor(42, 42, 42); SysColor[COLOR_FORM] := RGBToColor(53, 53, 53); end; function WinRegister(ClassName: PWideChar): Boolean; var WindowClassW: WndClassW; begin ZeroMemory(@WindowClassW, SizeOf(WndClassW)); with WindowClassW do begin Style := CS_DBLCLKS; LPFnWndProc := @FormWndProc; hInstance := System.HInstance; hIcon := Windows.LoadIcon(MainInstance, 'MAINICON'); if hIcon = 0 then hIcon := Windows.LoadIcon(0, IDI_APPLICATION); hCursor := Windows.LoadCursor(0, IDC_ARROW); LPSzClassName := ClassName; end; Result := Windows.RegisterClassW(@WindowClassW) <> 0; end; procedure Initialize; var hModule, hUxTheme: THandle; pLibrary, pFunction: PPointer; pImpDesc: PIMAGE_DELAYLOAD_DESCRIPTOR; begin if not g_darkModeEnabled then Exit; InitializeColors; WinRegister(ClassNameW); WinRegister(ClassNameTC); ThemeClass:= TThemeClassMap.Create; hModule:= GetModuleHandle(gdi32); Pointer(DeleteObjectOld):= GetProcAddress(hModule, 'DeleteObject'); hModule:= GetModuleHandle(comctl32); Pointer(DefSubclassProc):= GetProcAddress(hModule, 'DefSubclassProc'); Pointer(SetWindowSubclass):= GetProcAddress(hModule, 'SetWindowSubclass'); // Override several system functions pLibrary:= FindImportLibrary(MainInstance, user32); if Assigned(pLibrary) then begin hModule:= GetModuleHandle(user32); pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'CreateWindowExW')); if Assigned(pFunction) then begin Pointer(__CreateWindowExW):= ReplaceImportFunction(pFunction, @_CreateWindowExW); end; pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'DrawEdge')); if Assigned(pFunction) then begin ReplaceImportFunction(pFunction, @_DrawEdge); end; pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'GetSysColor')); if Assigned(pFunction) then begin ReplaceImportFunction(pFunction, @GetSysColorDark); end; pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'GetSysColorBrush')); if Assigned(pFunction) then begin ReplaceImportFunction(pFunction, @GetSysColorBrushDark); end; end; pLibrary:= FindImportLibrary(MainInstance, gdi32); if Assigned(pLibrary) then begin hModule:= GetModuleHandle(gdi32); pFunction:= FindImportFunction(pLibrary, Pointer(DeleteObjectOld)); if Assigned(pFunction) then begin ReplaceImportFunction(pFunction, @__DeleteObject); end; end; hModule:= GetModuleHandle(comctl32); pImpDesc:= FindDelayImportLibrary(hModule, themelib); if Assigned(pImpDesc) then begin hUxTheme:= GetModuleHandle(themelib); Pointer(TrampolineOpenThemeData):= GetProcAddress(hUxTheme, 'OpenThemeData'); Pointer(TrampolineDrawThemeText):= GetProcAddress(hUxTheme, 'DrawThemeText'); Pointer(TrampolineDrawThemeBackground):= GetProcAddress(hUxTheme, 'DrawThemeBackground'); ReplaceDelayImportFunction(hModule, pImpDesc, 'OpenThemeData', @InterceptOpenThemeData); ReplaceDelayImportFunction(hModule, pImpDesc, 'DrawThemeText', @InterceptDrawThemeText); ReplaceDelayImportFunction(hModule, pImpDesc, 'DrawThemeBackground', @InterceptDrawThemeBackground); ReplaceDelayImportFunction(hModule, pImpDesc, 'DrawThemeEdge', @DrawThemeEdgeDark); end; pLibrary:= FindImportLibrary(hModule, gdi32); if Assigned(pLibrary) then begin pFunction:= FindImportFunction(pLibrary, Pointer(DeleteObjectOld)); if Assigned(pFunction) then begin ReplaceImportFunction(pFunction, @__DeleteObject); end; end; hModule:= GetModuleHandle(comctl32); pLibrary:= FindImportLibrary(hModule, user32); if Assigned(pLibrary) then begin hModule:= GetModuleHandle(user32); pFunction:= FindImportFunction(pLibrary, GetProcAddress(hModule, 'DrawEdge')); if Assigned(pFunction) then begin ReplaceImportFunction(pFunction, @_DrawEdge); end; end; end; initialization Initialize; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/uwin32widgetsetfix.pas��������������������������������������������0000644�0001750�0000144�00000006770�14743153644�022313� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWin32WidgetSetFix; {$mode objfpc}{$H+} interface uses LCLVersion; implementation uses Classes, SysUtils, Win32Int, WSLCLClasses, Forms, Windows, Win32Proc, Controls, LCLType, Win32WSComCtrls, ComCtrls, LMessages, LCLMessageGlue; type { TWin32WSCustomTabControlEx } TWin32WSCustomTabControlEx = class(TWin32WSCustomTabControl) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; end; { TWin32WSCustomTabControlEx } function ChangeTabPage(TabControlHandle: HWND): Integer; var TabControl: TCustomTabControl; PageIndex: Integer; PageHandle: HWND; begin TabControl := GetWin32WindowInfo(TabControlHandle)^.WinControl as TCustomTabControl; if (TabControl.PageIndex <> -1) then Windows.ShowWindow(TabControl.CustomPage(TabControl.PageIndex).Handle, SW_HIDE); PageIndex := Windows.SendMessage(TabControlHandle, TCM_GETCURSEL, 0, 0); PageIndex := TabControl.TabToPageIndex(PageIndex); if (TabControl is TTabControl) then Exit(PageIndex); if PageIndex = -1 then Exit(PageIndex); PageHandle := TabControl.CustomPage(PageIndex).Handle; Windows.SetWindowPos(PageHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW); Windows.RedrawWindow(PageHandle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN or RDW_ERASE); Result := PageIndex; end; function TabControlParentMsgHandler(const AWinControl: TWinControl; Window: HWnd; Msg: UInt; WParam: Windows.WParam; LParam: Windows.LParam; var MsgResult: Windows.LResult; var WinProcess: Boolean): Boolean; var NMHdr: PNMHDR; LMNotify: TLMNotify; begin Result := False; if Msg = WM_NOTIFY then begin NMHdr := PNMHDR(LParam); with NMHdr^ do case code of TCN_SELCHANGE: begin Result := True; idFrom := ChangeTabPage(HWndFrom); with LMNotify Do begin Msg := LM_NOTIFY; IDCtrl := WParam; NMHdr := PNMHDR(LParam); Result := CallDefaultWindowProc(Window, Msg, WParam, LParam); end; DeliverMessage(AWinControl, LMNotify); TabControlFocusNewControl(AWinControl as TCustomTabControl, idFrom); MsgResult := LMNotify.Result; end; TCN_SELCHANGING: begin Result := True; with LMNotify Do begin Msg := LM_NOTIFY; IDCtrl := WParam; NMHdr := PNMHDR(LParam); Result := CallDefaultWindowProc(Window, Msg, WParam, LParam); end; DeliverMessage(AWinControl, LMNotify); MsgResult := LMNotify.Result; end; end; end; end; class function TWin32WSCustomTabControlEx.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var WindowInfo: PWin32WindowInfo; begin Result:= inherited CreateHandle(AWinControl, AParams); WindowInfo:= GetWin32WindowInfo(Result); WindowInfo^.ParentMsgHandler := @TabControlParentMsgHandler; end; procedure Initialize; begin // Replace TCustomTabControl widgetset class // Fix blinking: https://bugs.freepascal.org/view.php?id=22080 RegisterCustomTabControl; RegisterWSComponent(TCustomTabControl, TWin32WSCustomTabControlEx); end; initialization {$if lcl_fullversion < 2010000} Initialize; {$endif} end. ��������doublecmd-1.1.22/src/platform/win/winrt/������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�017161� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/winrt/WinRT.Classes.pas�������������������������������������������0000644�0001750�0000144�00000052117�14743153644�022273� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit WinRT.Classes; {$mode delphi} interface uses Classes, SysUtils, Types, WinRT.Core; const Windows_System_Launcher = UnicodeString('Windows.System.Launcher'); Windows_Storage_StorageFile = UnicodeString('Windows.Storage.StorageFile'); Windows_Storage_StorageFolder = UnicodeString('Windows.Storage.StorageFolder'); Windows_System_LauncherOptions = UnicodeString('Windows.System.LauncherOptions'); type // Windows.Foundation.AsyncStatus AsyncStatus = ( Started = 0, Completed = 1, Canceled = 2, Error = 3 ); // Windows.Storage.Search.FolderDepth FolderDepth = ( Shallow = 0, Deep = 1 ); // Windows.Storage.Search.IndexerOption IndexerOption = ( UseIndexerWhenAvailable = 0, OnlyUseIndexer = 1, DoNotUseIndexer = 2, OnlyUseIndexerAndOptimizeForIndexedProperties = 3 ); // Windows.Storage.Search.DateStackOption DateStackOption = ( None = 0, Year = 1, Month = 2 ); // Windows.Storage.Search.CommonFileQuery CommonFileQuery = ( DefaultQuery = 0, OrderByName = 1, OrderByTitle = 2, OrderByMusicProperties = 3, OrderBySearchRank = 4, OrderByDate = 5 ); // Windows.Storage.FileAccessMode FileAccessMode = ( Read = 0, ReadWrite = 1 ); // Windows.Storage.NameCollisionOption NameCollisionOption = ( GenerateUniqueName = 0, ReplaceExisting = 1, FailIfExists = 2 ); // Windows.Storage.CreationCollisionOption CreationCollisionOption = ( GenerateUniqueNamez = 0, ReplaceExistingz = 1, FailIfExistsz = 2, OpenIfExists = 3 ); // Forward declarations IStorageFolder = interface; IAsyncOperation_1_Boolean = interface; IAsyncOperation_1_IStorageFile = interface; IAsyncOperation_1_IStorageFolder = interface; // Windows.Foundation.AsyncOperationCompletedHandler`1<Windows.Storage.StorageFolder> IAsyncOperationCompletedHandler_1_IStorageFolder = interface(IUnknown) ['{C211026E-9E63-5452-BA54-3A07D6A96874}'] procedure Invoke(asyncInfo: IAsyncOperation_1_IStorageFolder; asyncStatus: AsyncStatus); safecall; end; // Windows.Foundation.IAsyncOperation`1<Windows.Storage.IStorageFolder> IAsyncOperation_1_IStorageFolder = interface(IInspectable) ['{6BE9E7D7-E83A-5CBC-802C-1768960B52C3}'] procedure Set_Completed(handler: IAsyncOperationCompletedHandler_1_IStorageFolder); safecall; function Get_Completed: IAsyncOperationCompletedHandler_1_IStorageFolder; safecall; function GetResults: IStorageFolder; safecall; property Completed: IAsyncOperationCompletedHandler_1_IStorageFolder read Get_Completed write Set_Completed; end; IStorageFolder = interface(IInspectable) ['{72D1CB78-B3EF-4F75-A80B-6FD9DAE2944B}'] function CreateFileAsync(desiredName: HSTRING): IAsyncOperation_1_IStorageFile; safecall; overload; function CreateFileAsync(desiredName: HSTRING; options: CreationCollisionOption): IAsyncOperation_1_IStorageFile; safecall; overload; function CreateFolderAsync(desiredName: HSTRING): IAsyncOperation_1_IStorageFolder; safecall; overload; function CreateFolderAsync(desiredName: HSTRING; options: CreationCollisionOption): IAsyncOperation_1_IStorageFolder; safecall; overload; function GetFileAsync(name: HSTRING): IAsyncOperation_1_IStorageFile; safecall; function GetFolderAsync(name: HSTRING): IAsyncOperation_1_IStorageFolder; safecall; function GetItemAsync(name: HSTRING): IInspectable; safecall; function GetFilesAsync: IInspectable; safecall; function GetFoldersAsync: IInspectable; safecall; function GetItemsAsync: IInspectable; safecall; end; IStorageFile = interface(IInspectable) ['{FA3F6186-4214-428C-A64C-14C9AC7315EA}'] function Get_FileType: HSTRING; safecall; function Get_ContentType: HSTRING; safecall; function OpenAsync(accessMode: FileAccessMode): IInspectable; safecall; function OpenTransactedWriteAsync: IInspectable; safecall; function CopyAsync(destinationFolder: IStorageFolder): IAsyncOperation_1_IStorageFile; safecall; overload; function CopyAsync(destinationFolder: IStorageFolder; desiredNewName: HSTRING): IAsyncOperation_1_IStorageFile; safecall; overload; function CopyAsync(destinationFolder: IStorageFolder; desiredNewName: HSTRING; option: NameCollisionOption): IAsyncOperation_1_IStorageFile; safecall; overload; function CopyAndReplaceAsync(fileToReplace: IStorageFile): IInspectable; safecall; function MoveAsync(destinationFolder: IStorageFolder): IInspectable; safecall; overload; function MoveAsync(destinationFolder: IStorageFolder; desiredNewName: HSTRING): IInspectable; safecall; overload; function MoveAsync(destinationFolder: IStorageFolder; desiredNewName: HSTRING; option: NameCollisionOption): IInspectable; safecall; overload; function MoveAndReplaceAsync(fileToReplace: IStorageFile): IInspectable; safecall; property ContentType: HSTRING read Get_ContentType; property FileType: HSTRING read Get_FileType; end; // Windows.Foundation.AsyncOperationCompletedHandler`1<Windows.Storage.IStorageFile> IAsyncOperationCompletedHandler_1_IStorageFile = interface(IUnknown) ['{E521C894-2C26-5946-9E61-2B5E188D01ED}'] procedure Invoke(asyncInfo: IAsyncOperation_1_IStorageFile; asyncStatus: AsyncStatus); safecall; end; // Windows.Foundation.IAsyncOperation`1<Windows.Storage.IStorageFile> IAsyncOperation_1_IStorageFile = interface(IInspectable) ['{5E52F8CE-ACED-5A42-95B4-F674DD84885E}'] procedure Set_Completed(handler: IAsyncOperationCompletedHandler_1_IStorageFile); safecall; function Get_Completed: IAsyncOperationCompletedHandler_1_IStorageFile; safecall; function GetResults: IStorageFile; safecall; property Completed: IAsyncOperationCompletedHandler_1_IStorageFile read Get_Completed write Set_Completed; end; // Windows.Storage.StorageFile IStorageFileStatics = interface(IInspectable) ['{5984C710-DAF2-43C8-8BB4-A4D3EACFD03F}'] function GetFileFromPathAsync(path: HSTRING): IAsyncOperation_1_IStorageFile; safecall; function GetFileFromApplicationUriAsync(uri: IInspectable): IAsyncOperation_1_IStorageFile; safecall; function CreateStreamedFileAsync(displayNameWithExtension: HSTRING; dataRequested: IUnknown; thumbnail: IInspectable): IAsyncOperation_1_IStorageFile; safecall; function ReplaceWithStreamedFileAsync(fileToReplace: IStorageFile; dataRequested: IUnknown; thumbnail: IInspectable): IAsyncOperation_1_IStorageFile; safecall; function CreateStreamedFileFromUriAsync(displayNameWithExtension: HSTRING; uri: IInspectable; thumbnail: IInspectable): IAsyncOperation_1_IStorageFile; safecall; function ReplaceWithStreamedFileFromUriAsync(fileToReplace: IStorageFile; uri: IInspectable; thumbnail: IInspectable): IAsyncOperation_1_IStorageFile; safecall; end; // Windows.Storage.Search.StorageFileQueryResult IStorageFileQueryResult = interface(IInspectable) ['{52FDA447-2BAA-412C-B29F-D4B1778EFA1E}'] function GetFilesAsync(startIndex: UINT32; maxNumberOfItems: UINT32; out operation: IInspectable): HRESULT; stdcall; function GetFilesAsyncDefaultStartAndCount(out operation: IInspectable): HRESULT; stdcall; end; // Windows.Storage.Search.QueryOptions IQueryOptions = interface(IInspectable) ['{1E5E46EE-0F45-4838-A8E9-D0479D446C30}'] function Get_FileTypeFilter(out value: IUnknown): HRESULT; stdcall; function Get_FolderDepth(out value: FolderDepth): HRESULT; stdcall; function Put_FolderDepth(value: FolderDepth): HRESULT; stdcall; function Get_ApplicationSearchFilter(out value: HSTRING): HRESULT; stdcall; function Put_ApplicationSearchFilter(value: HSTRING): HRESULT; stdcall; function Get_UserSearchFilter(out value: HSTRING): HRESULT; stdcall; function Put_UserSearchFilter(value: HSTRING): HRESULT; stdcall; function Get_Language(out value: HSTRING): HRESULT; stdcall; function Put_Language(value: HSTRING): HRESULT; stdcall; function Get_IndexerOption(out value: IndexerOption): HRESULT; stdcall; function Put_IndexerOption(value: IndexerOption): HRESULT; stdcall; function Get_SortOrder(out value: IUnknown): HRESULT; stdcall; function Get_GroupPropertyName(out value: HSTRING): HRESULT; stdcall; function Get_DateStackOption(out value: DateStackOption): HRESULT; stdcall; function SaveToString(out value: HSTRING): HRESULT; stdcall; function LoadFromString(value: HSTRING): HRESULT; stdcall; function SetThumbnailPrefetch(mode: DWORD; requestedSize: UINT32; options: DWORD): HRESULT; stdcall; function SetPropertyPrefetch(options: DWORD; propertiesToRetrieve: IUnknown): HRESULT; stdcall; end; // Windows.Storage.Search.QueryOptions IQueryOptionsFactory = interface(IInspectable) ['{032E1F8C-A9C1-4E71-8011-0DEE9D4811A3}'] function CreateCommonFileQuery(query: CommonFileQuery; fileTypeFilter: IInspectable; out queryOptions: IQueryOptions): HRESULT; stdcall; function CreateCommonFolderQuery(query: DWORD; out queryOptions: IQueryOptions): HRESULT; stdcall; end; IStorageFolderQueryOperations = interface(IInspectable) ['{CB43CCC9-446B-4A4F-BE97-757771BE5203}'] function GetIndexedStateAsync(out operation: IUnknown): HRESULT; stdcall; function CreateFileQueryOverloadDefault(out value: IStorageFileQueryResult): HRESULT; stdcall; function CreateFileQuery(query: CommonFileQuery; out value: IStorageFileQueryResult): HRESULT; stdcall; function CreateFileQueryWithOptions(queryOptions: IQueryOptions; out value: IStorageFileQueryResult): HRESULT; stdcall; function CreateFolderQueryOverloadDefault(out value: IInspectable): HRESULT; stdcall; function CreateFolderQuery(query: DWORD; out value: IInspectable): HRESULT; stdcall; function CreateFolderQueryWithOptions(queryOptions: IQueryOptions; out value: IInspectable): HRESULT; stdcall; function CreateItemQuery(out value: IInspectable): HRESULT; stdcall; function CreateItemQueryWithOptions(queryOptions: IQueryOptions; out value: IInspectable): HRESULT; stdcall; function GetFilesAsync(query: CommonFileQuery; startIndex: UINT32; maxItemsToRetrieve: UINT32; out operation: IUnknown): HRESULT; stdcall; function GetFilesAsyncOverloadDefaultStartAndCount(query: CommonFileQuery; out operation: IInspectable): HRESULT; stdcall; function GetFoldersAsync(query: DWORD; startIndex: UINT32; maxItemsToRetrieve: UINT32; out operation: IInspectable): HRESULT; stdcall; function GetFoldersAsyncOverloadDefaultStartAndCount(query: DWORD; out operation: IInspectable): HRESULT; stdcall; function GetItemsAsync(startIndex: UINT32; maxItemsToRetrieve: UINT32; out operation: IInspectable): HRESULT; stdcall; function AreQueryOptionsSupported(queryOptions: IQueryOptions; out value: LongBool): HRESULT; stdcall; function IsCommonFolderQuerySupported(query: DWORD; out value: LongBool): HRESULT; stdcall; function IsCommonFileQuerySupported(query: CommonFileQuery; out value: LongBool): HRESULT; stdcall; end; // Windows.Storage.StorageFolder IStorageFolderStatics = interface(IInspectable) ['{08F327FF-85D5-48B9-AEE9-28511E339F9F}'] function GetFolderFromPathAsync(path: HSTRING): IAsyncOperation_1_IStorageFolder; safecall; end; // Windows.System.LauncherOptions ILauncherOptions = interface(IInspectable) ['{BAFA21D8-B071-4CD8-853E-341203E557D3}'] function Get_TreatAsUntrusted(value: PLongBool): HRESULT; stdcall; function Set_TreatAsUntrusted(value: LongBool): HRESULT; stdcall; function Get_DisplayApplicationPicker(value: PLongBool): HRESULT; stdcall; function Set_DisplayApplicationPicker(value: LongBool): HRESULT; stdcall; function UI(out value: IInspectable): HRESULT; stdcall; function Get_PreferredApplicationPackageFamilyName(out value: HSTRING): HRESULT; stdcall; function Set_PreferredApplicationPackageFamilyName(value: HSTRING): HRESULT; stdcall; function Get_PreferredApplicationDisplayName(out value: HSTRING): HRESULT; stdcall; function Set_PreferredApplicationDisplayName(value: HSTRING): HRESULT; stdcall; function Get_FallbackUri(out value: IUnknown): HRESULT; stdcall; function Set_FallbackUri(value: IUnknown): HRESULT; stdcall; function Get_ContentType(out value: HSTRING): HRESULT; stdcall; function Set_ContentType(value: HSTRING): HRESULT; stdcall; end; // Windows.System.LauncherOptions ILauncherOptions2 = interface(IInspectable) ['{3BA08EB4-6E40-4DCE-A1A3-2F53950AFB49}'] function Get_TargetApplicationPackageFamilyName: HSTRING; safecall; procedure Set_TargetApplicationPackageFamilyName(value: HSTRING); safecall; function Get_NeighboringFilesQuery: IStorageFileQueryResult; safecall; procedure Set_NeighboringFilesQuery(value: IStorageFileQueryResult); safecall; property NeighboringFilesQuery: IStorageFileQueryResult read Get_NeighboringFilesQuery write Set_NeighboringFilesQuery; property TargetApplicationPackageFamilyName: HSTRING read Get_TargetApplicationPackageFamilyName write Set_TargetApplicationPackageFamilyName; end; // Windows.Foundation.AsyncOperationCompletedHandler`1<Boolean> IAsyncOperationCompletedHandler_1_Boolean = interface(IUnknown) ['{C1D3D1A2-AE17-5A5F-B5A2-BDCC8844889A}'] procedure Invoke(asyncInfo: IAsyncOperation_1_Boolean; asyncStatus: AsyncStatus); safecall; end; // Windows.Foundation.IAsyncOperation`1<Boolean> IAsyncOperation_1_Boolean = interface(IInspectable) ['{CDB5EFB3-5788-509D-9BE1-71CCB8A3362A}'] procedure Set_Completed(handler: IAsyncOperationCompletedHandler_1_Boolean); safecall; function Get_Completed: IAsyncOperationCompletedHandler_1_Boolean; safecall; function GetResults: Boolean; safecall; property Completed: IAsyncOperationCompletedHandler_1_Boolean read Get_Completed write Set_Completed; end; // Windows.System.Launcher ILauncherStatics = interface(IInspectable) ['{277151C3-9E3E-42F6-91A4-5DFDEB232451}'] function LaunchFileAsync(AFile: IStorageFile): IAsyncOperation_1_Boolean; safecall; function LaunchFileWithOptionsAsync(AFile: IStorageFile; options: ILauncherOptions): IAsyncOperation_1_Boolean; safecall; function LaunchUriAsync(uri: IUnknown): IAsyncOperation_1_Boolean; safecall; function LaunchUriWithOptionsAsync(uri: IUnknown; options: ILauncherOptions): IAsyncOperation_1_Boolean; safecall; end; { TStorageFile } TStorageFile = class private FInstance: IStorageFileStatics; static; class function Instance: IStorageFileStatics; public class function GetFileFromPathAsync(const APath: String): IAsyncOperation_1_IStorageFile; end; { TStorageFolder } TStorageFolder = class private FInstance: IStorageFolderStatics; static; class function Instance: IStorageFolderStatics; public class function GetFolderFromPathAsync(const APath: String): IAsyncOperation_1_IStorageFolder; end; { TLauncher } TLauncher = class private FInstance: ILauncherStatics; static; class function Instance: ILauncherStatics; public class function LaunchFileAsync(AFile: IStorageFile): IAsyncOperation_1_Boolean; class function LaunchFileWithOptionsAsync(AFile: IStorageFile; options: ILauncherOptions): IAsyncOperation_1_Boolean; end; { TLauncherThread } TLauncherThread = class(TThread) private FEvent: THandle; FFileName: String; FStorageFile: IStorageFile; FStorageFolder: IStorageFolder; protected procedure Execute; override; public constructor Create(const FileName: String); destructor Destroy; override; class procedure LaunchFileAsync(const FileName: String); end; { TAsyncOperationCompletedHandler_1_IStorageFile } TAsyncOperationCompletedHandler_1_IStorageFile = class(TInterfacedObject, IAsyncOperationCompletedHandler_1_IStorageFile) private FLauncher: TLauncherThread; protected procedure Invoke(asyncInfo: IAsyncOperation_1_IStorageFile; asyncStatus: AsyncStatus); safecall; public constructor Create(ALauncher: TLauncherThread); end; { TAsyncOperationCompletedHandler_1_IStorageFolder } TAsyncOperationCompletedHandler_1_IStorageFolder = class(TInterfacedObject, IAsyncOperationCompletedHandler_1_IStorageFolder) private FLauncher: TLauncherThread; protected procedure Invoke(asyncInfo: IAsyncOperation_1_IStorageFolder; asyncStatus: AsyncStatus); safecall; public constructor Create(ALauncher: TLauncherThread); end; implementation uses ComObj, Windows; { TStorageFile } class function TStorageFile.Instance: IStorageFileStatics; begin if (FInstance = nil) then begin OleCheck(RoCreateInstance(Windows_Storage_StorageFile, IStorageFileStatics, FInstance)); end; Result:= FInstance; end; class function TStorageFile.GetFileFromPathAsync(const APath: String): IAsyncOperation_1_IStorageFile; begin with TWindowsString.Create(APath) do try Result:= Instance.GetFileFromPathAsync(Handle); finally Free; end; end; { TStorageFolder } class function TStorageFolder.Instance: IStorageFolderStatics; begin if (FInstance = nil) then begin OleCheck(RoCreateInstance(Windows_Storage_StorageFolder, IStorageFolderStatics, FInstance)); end; Result:= FInstance; end; class function TStorageFolder.GetFolderFromPathAsync(const APath: String): IAsyncOperation_1_IStorageFolder; begin with TWindowsString.Create(APath) do try Result:= Instance.GetFolderFromPathAsync(Handle); finally Free; end; end; { TLauncher } class function TLauncher.Instance: ILauncherStatics; begin if (FInstance = nil) then begin OleCheck(RoCreateInstance(Windows_System_Launcher, ILauncherStatics, FInstance)); end; Result:= FInstance; end; class function TLauncher.LaunchFileAsync(AFile: IStorageFile): IAsyncOperation_1_Boolean; begin Result:= Instance.LaunchFileAsync(AFile); end; class function TLauncher.LaunchFileWithOptionsAsync(AFile: IStorageFile; options: ILauncherOptions): IAsyncOperation_1_Boolean; begin Result:= Instance.LaunchFileWithOptionsAsync(AFile, options); end; { TLauncherThread } procedure TLauncherThread.Execute; var AOptions: ILauncherOptions; AOptions2: ILauncherOptions2; AQuery: IStorageFileQueryResult; AFolderQuery: IStorageFolderQueryOperations; FileOperation: IAsyncOperation_1_IStorageFile; FolderOperation: IAsyncOperation_1_IStorageFolder; FileHandler: TAsyncOperationCompletedHandler_1_IStorageFile; FolderHandler: TAsyncOperationCompletedHandler_1_IStorageFolder; begin try FileHandler:= TAsyncOperationCompletedHandler_1_IStorageFile.Create(Self); FileOperation:= TStorageFile.GetFileFromPathAsync(FFileName); FileOperation.Completed:= FileHandler; WaitForSingleObject(FEvent, INFINITE); ResetEvent(FEvent); FolderHandler:= TAsyncOperationCompletedHandler_1_IStorageFolder.Create(Self); FolderOperation:= TStorageFolder.GetFolderFromPathAsync(ExtractFileDir(FFileName)); FolderOperation.Completed:= FolderHandler; WaitForSingleObject(FEvent, INFINITE); OleCheck(RtActivateInstance(Windows_System_LauncherOptions, AOptions)); OleCheck(AOptions.QueryInterface(ILauncherOptions2, AOptions2)); OleCheck(FStorageFolder.QueryInterface(IStorageFolderQueryOperations, AFolderQuery)); OleCheck(AFolderQuery.CreateFileQuery(DefaultQuery, AQuery)); AOptions2.NeighboringFilesQuery:= AQuery; TLauncher.LaunchFileWithOptionsAsync(FStorageFile, AOptions); except on E: Exception do begin MessageBoxW(0, PWideChar(UTF8Decode(E.Message)), nil, MB_OK or MB_ICONERROR); end; end; end; constructor TLauncherThread.Create(const FileName: String); begin FFileName:= FileName; inherited Create(True); FreeOnTerminate:= True; FEvent:= CreateEventW(nil, True, False, nil); end; destructor TLauncherThread.Destroy; begin CloseHandle(FEvent); inherited Destroy; end; class procedure TLauncherThread.LaunchFileAsync(const FileName: String); begin with TLauncherThread.Create(FileName) do Start; end; { TAsyncOperationCompletedHandler_1_IStorageFolder } procedure TAsyncOperationCompletedHandler_1_IStorageFolder.Invoke( asyncInfo: IAsyncOperation_1_IStorageFolder; asyncStatus: AsyncStatus); safecall; begin FLauncher.FStorageFolder:= asyncInfo.GetResults; SetEvent(FLauncher.FEvent); end; constructor TAsyncOperationCompletedHandler_1_IStorageFolder.Create( ALauncher: TLauncherThread); begin FLauncher:= ALauncher; end; { TAsyncOperationCompletedHandler_1_IStorageFile } procedure TAsyncOperationCompletedHandler_1_IStorageFile.Invoke( asyncInfo: IAsyncOperation_1_IStorageFile; asyncStatus: AsyncStatus); safecall; begin FLauncher.FStorageFile:= asyncInfo.GetResults; SetEvent(FLauncher.FEvent); end; constructor TAsyncOperationCompletedHandler_1_IStorageFile.Create( ALauncher: TLauncherThread); begin FLauncher:= ALauncher; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/platform/win/winrt/WinRT.Core.pas����������������������������������������������0000644�0001750�0000144�00000011713�14743153644�021563� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit WinRT.Core; {$mode delphi} interface uses Classes, SysUtils, Windows; type HSTRING = HANDLE; PCNZWCH = PWideChar; TrustLevel = ( BaseTrust = 0, PartialTrust = (BaseTrust + 1), FullTrust = (PartialTrust + 1) ); IInspectable = interface(IUnknown) ['{AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90}'] function GetIids(out iidCount: ULONG; out iids: PIID): HRESULT; stdcall; function GetRuntimeClassName(out className: HSTRING): HRESULT; stdcall; function GetTrustLevel(out trustLevel: TrustLevel): HRESULT; stdcall; end; { TWindowsString } TWindowsString = class private FHandle: HSTRING; public constructor Create(AHandle: HSTRING); overload; constructor Create(const AString: String); overload; constructor Create(const AString: UnicodeString); overload; destructor Destroy; override; function ToString: AnsiString; override; property Handle: HSTRING read FHandle; end; function RtActivateInstance(const AClassName: UnicodeString; out AInstance): HRESULT; function RoCreateInstance(const AClassName: UnicodeString; constref AClassID: TIID; out AInstance): HRESULT; implementation uses ComObj; type RO_INIT_TYPE = ( RO_INIT_SINGLETHREADED = 0, RO_INIT_MULTITHREADED = 1 ); var RoInitialize: function(initType: RO_INIT_TYPE): HRESULT; stdcall; RoUninitialize: procedure(); stdcall; RoActivateInstance: function(activatableClassId: HSTRING; out instance): HRESULT; stdcall; RoGetActivationFactory: function(activatableClassId: HSTRING; constref iid: TIID; out factory: IInspectable): HRESULT; stdcall; var WindowsCreateString: function(sourceString: PCNZWCH; length: UINT32; out str: HSTRING): HRESULT; stdcall; WindowsDeleteString: function(str: HSTRING): HRESULT; stdcall; WindowsGetStringRawBuffer: function(str: HSTRING; length: PUINT32): PCWSTR; stdcall; const libwinrt = 'api-ms-win-core-winrt-l1-1-0.dll'; libwinrt_string = 'api-ms-win-core-winrt-string-l1-1-0.dll'; var hWinRT: TLibHandle; hWinRTString: TLibHandle; procedure Initialize; begin if CheckWin32Version(10) then begin hWinRT:= LoadLibrary(libwinrt); if (hWinRT <> NilHandle) then try @RoInitialize:= GetProcAddress(hWinRT, 'RoInitialize'); @RoUninitialize:= GetProcAddress(hWinRT, 'RoUninitialize'); @RoActivateInstance:= GetProcAddress(hWinRT, 'RoActivateInstance'); @RoGetActivationFactory:= GetProcAddress(hWinRT, 'RoGetActivationFactory'); RoInitialize(RO_INIT_MULTITHREADED); except FreeLibrary(hWinRT); hWinRT:= NilHandle; end; hWinRTString:= LoadLibrary(libwinrt_string); if (hWinRTString <> NilHandle) then try @WindowsCreateString:= GetProcAddress(hWinRTString, 'WindowsCreateString'); @WindowsDeleteString:= GetProcAddress(hWinRTString, 'WindowsDeleteString'); @WindowsGetStringRawBuffer:= GetProcAddress(hWinRTString, 'WindowsGetStringRawBuffer'); except FreeLibrary(hWinRTString); hWinRTString:= NilHandle; end; end; end; procedure Finalize; begin if (hWinRT <> NilHandle) then begin RoUninitialize; FreeLibrary(hWinRT); end; if (hWinRTString <> NilHandle) then begin FreeLibrary(hWinRTString); end; end; function RtActivateInstance(const AClassName: UnicodeString; out AInstance): HRESULT; var AName: TWindowsString; begin AName:= TWindowsString.Create(AClassName); try Result:= RoActivateInstance(AName.FHandle, AInstance); finally AName.Free; end; end; function RoCreateInstance(const AClassName: UnicodeString; constref AClassID: TIID; out AInstance): HRESULT; var AName: TWindowsString; AFactory: IInspectable; begin AName:= TWindowsString.Create(AClassName); try Result:= RoGetActivationFactory(AName.FHandle, AClassID, AFactory); if Succeeded(Result) then begin Result:= AFactory.QueryInterface(AClassID, AInstance); end; finally AName.Free; end; end; { TWindowsString } constructor TWindowsString.Create(const AString: String); begin Create(UTF8Decode(AString)); end; constructor TWindowsString.Create(AHandle: HSTRING); begin FHandle:= AHandle; end; constructor TWindowsString.Create(const AString: UnicodeString); begin OleCheck(WindowsCreateString(PWideChar(AString), Length(AString), FHandle)); end; destructor TWindowsString.Destroy; begin inherited Destroy; if (FHandle <> 0) then WindowsDeleteString(FHandle); end; function TWindowsString.ToString: AnsiString; var P: PWideChar; L: UINT32 = 0; usString: UnicodeString; begin P:= WindowsGetStringRawBuffer(FHandle, @L); SetString(usString, P, L); Result:= UTF8Encode(usString); end; initialization Initialize; finalization Finalize; end. �����������������������������������������������������doublecmd-1.1.22/src/rpc/���������������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�014161� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/�����������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�014777� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/felevation.lfm���������������������������������������������������������0000644�0001750�0000144�00000045553�14743153644�017647� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object frmElevation: TfrmElevation Left = 430 Height = 145 Top = 282 Width = 400 AutoSize = True BorderStyle = bsDialog ChildSizing.LeftRightSpacing = 12 ChildSizing.TopBottomSpacing = 12 ClientHeight = 145 ClientWidth = 400 DesignTimePPI = 120 Position = poScreenCenter LCLVersion = '2.0.12.0' object lblText: TLabel AnchorSideLeft.Control = imgShield AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Owner Left = 114 Height = 20 Top = 12 Width = 64 BorderSpacing.Left = 12 Constraints.MinHeight = 20 Constraints.MinWidth = 64 ParentColor = False end object chkElevateAll: TCheckBox AnchorSideLeft.Control = lblText AnchorSideTop.Control = lblText AnchorSideTop.Side = asrBottom Left = 114 Height = 24 Top = 44 Width = 216 BorderSpacing.Top = 12 Caption = 'Do this for &all current objects' Checked = True State = cbChecked TabOrder = 1 end object imgShield: TImage AnchorSideLeft.Control = Owner AnchorSideTop.Control = Owner Left = 12 Height = 90 Top = 12 Width = 90 AutoSize = True Picture.Data = { 1754506F727461626C654E6574776F726B477261706869631C1E000089504E47 0D0A1A0A0000000D494844520000005A0000005A080600000038A8410200001D E349444154789CED9C79941DD57DE7BF77A9AAB7F55377ABD52DB5568800095B 586C09AB8C1DE3046C8775C6394EEC99C127F1829339B1C743EC73662699D8CE 39F1F1C46B26719878663CB68163B0216C3604B42124D40884760949AD6E2DBD F75BEBD576EF9D3F6E6DAFD5C0EB564B62E6E807A57A5BD7ABFABC5F7D7FCBBD 55C005BB6017EC825DB00B3647367A641F3D7570CFF9DE8D191B39DF3BD0AA6D FEF6172141AF50C0B74088ED79FE97E717DB0E5EF599BF3ADFBBD692FD3F017A F3771F58A280BFCCE6729F2ACE9BC71933603B0DC7B61B3F745DF7EBEBEEFFDA C8F9DEC777B27735E8CDDFFBF35E10F2E54C26FBC7C579F3726626034A392863 A08C412AC0B6ED8ADD687CD76934BE73DD7D5F193BDFFBFC56F6AE03BDFDFBFF 11AE222B40D89F65B2D9FB8AF3E615AC4C16947350C641A9864C2903A1148432 482951ABD74B8D86FDF74EA3F1BDAECECE93CB7EE793E7FB509AEC5D037ACBB7 BF0441D90D84F23FC9E5F377B715E7991160C6122FA68C83509A024D41080508 819012F57ADD6ED8F6438ED3F81E91F2F5F7DCFD99F37D6800DE05A09FF9C617 BA72D9CCBDDC34FF285F68BBAA502CC23433609C8372039431FD987110CA4059 08995080525042014A404000420102482161371AD2B6EB5B5DD7FDC7C0711EBB FC8EFB2AE7F338CF0BE8E7BFF1D9A2A2ECC3DC303F9ECDE56FCFB71573B97C01 DC34C1B801C6391837B454A4BD798A1713AA3D9910A2D72050A943924AC1F33C D876BDE2349C273CD77D9848F1C2A5B7FFA17DAE8FF99C807EF62B1FA71E3556 51C63FC84DEBB66C2EBF2EDFD656C817DA60581970C304338C10B29140E62C0E 7E4D72114A450C59FB3314490E47A5FE510A9052C0F53C34EC46C9759DF541E0 3FE3BBCEFAAEF6E29BDD37DE29CF368339057DDF3D1FA197E5DC621B572BB206 5F6518C61A3393B92A9BCD5D932F14BA72853664F30598A6056E5A60869978B1 9178F3544F269481528AC19109FCEC571BF1FE9B6FC69AA5F391B78CF010F461 A8D4BFE987D1EB4A01500A4A29F8BE0FD7F3E079EE90EF077D42043B8490BB84 94FB05E103ACB3B776F935D7CFD90FD012E8BFF9E0E22E42D9554A4980B0A252 324729EDA48CCF679C775133D36B9AE642D3CA2CCB6432ED563697C9E4F2C8E6 F3B0B2399856063C846B846B6E9860A6A9D75C7B34653C014D1908D380C7AB75 FCFCB997F0FAFED770F5CA0A1EDB64E0DEBBEFC66FAEBE0897F4B4C3E22C3E9A B42787FFA7D8ABA6E34A5E561052420401822040200247083121A51C90529E54 420E4925C7A0D42421644C88C03138AFF89E03A5B0F592DFF9C43BEA3F6F05B4 64E60739910F67AD3C38E720948071038661C2B0343CC3B4C02D0BDCB0605899 F079267C3F031E7E8E1B16B869261ECD0D50C3D099C594146EA25AC7E3EBB761 EBCE1DB866958BCFDD938395B9087FF1FDA771F8CD37B16EDD3A7CF8D60FE1BD CB17E2A2F905188C4ED9F3D08B4F479B32ED6B8C5230CB82655900410620BD84 A057FF58FA2C98BA5042F13F1EF9C5FD00FE6E4E4073C3C83019C0300D988619 062BAE4185A73F37226FCD68D09606AE9FA73C39F2E6F06F6924176186412943 FFD0289EDAFC2ADED8BF0BD7AC0AF0F97BB3E8EA5A81627B274033300C0300B0 75EB56ECDAB50B37DC70036EBAF146AC5AB200BD450B394E63802089674F7BFA 9250DFA3C75AEC41888252240C054407DFF0B348ADED86B3A82586AD7C888441 8780E8D399E9AC8087DAFA5690A7056D5860662217915438BEC02B6F1CC40BAF EC44B53E886B5713FCE9EFE7D0D1D98562B113D97C1B4C2B0B37002CCB82691A 31F0BEBE3EECDDBB17575C7105AEB9E61A5CB6BC170BB20C450ED050C2898AC0 4F393610FD7ED33A01AC103D0E7F3442E25F8D002094B5E6ACAD7C0800258480 500A16E6B5CC309A3D3A252111642D1999666F36CD58321ABEC0AE8347F0CA9E 3771E0D8115CBCC8C5FBD71A58B1A4136DF33A5128B4239B2BC0302D30C60142 41A468021D2D94521C387000478E1EC592C58BB166CD1A5CBEEA3274172C14A8 40067E1236238F0C9D287CB1D963A7599A5E070151AD339C8147D3F0140F2173 33CE1A628896D6656E864BCABB4139C66A0E4E8C8FE0E8D0180E0C0C61B23A8C 8B1649AC5EC1F1BB37E4502C76235F68472E5F8065E5B4B430A601479848E2D1 9CF326D88661803386B1F1716CDAB409DBB66DC3B265CBB072E54A5C7CD10A74 CF2BC054010CE981090F5406A783450A289D0A9B6AEFA6899428359DEECF1234 08918CEA5298B130D7358CD09B2DD45801BE07380D0F810AE0CA1A1CA150F704 CA0D0F93751B8E57475BD6C7820E8525DD0C1FB9D140F7FC22F2853664F36DC8 660BB03239188605C68CA418417CDEEA5D413368CE39B861C0881E730E462928 63504AE1F8F1E33879F224366DDA8462B188DEDE5E2C5CB810DDDDDD58D0D585 622E038B02440A10198028012225A02402DF43E079285A611E4FA4061C6A38A1 044A8AB9034D2905E32C06CCB8114B4660157184B5C3AFEC85E3344089878C09 E4F3C0FC0504C50245471B432167C1CAB4C1CAE4F462E5605A39ADE35CE7D094 6AEF8D05B0A9D28B3C9AC0CA5830C34C8573A6E1B264CD18038D8B196D4A2994 CB6594CB65ECDBB70F524A28A5303A3A8A818101747575A1A7A7079D9D9D9837 6F1E2CCB42AD56C3F2E5CB71E7D52B91350D484241A80455DAA3A9A210816829 D76ED1A3A98C7539821C660ECA30D19EA9E1A29E61CC5FB008D95C4F7CB08C1B 604C07CD285FE6DC006326283340290F3D574B838A3CB86941F3EB8420635989 F746DF15E6DCD19AA440A74F6F952A5876ECD8817DFBF6BDEDA17FF18B5F84B7 66390C4A40290195148A52101A6F279833D0C2776B2C9F0B2127A0B961403003 9C07E8E8EAC6A2252B90CB174149D28BA0715F226C04110A205C0889D70ADA93 559354A4ABBEB0D426D095256F069C5EC834DE1CADA55298181FC7E6CD9B512A 95DEF9D88580EFFB108C4046DB0FD78A52946BF5C69C81A64A3A2CD4C238CB08 73E7C030408980656691C9E491CDE6913EF511830BBDB609B0864B22C8D1EB88 1A4440940DA8785B80699A21640D752AE0A99055B49612FBF7EFC78E1D3B2044 6BDAAA94D2D5A2AFB3AEA87BA842D0954AD59B3BD086E5C5FA1CA575316C0320 6E538327EEA4C50D1FFD58A9C4A3B514E8C75A1A68D367A3C749E21BA5641486 6168C894C65A1CC19D0E329482E338D8B2650B8E1F3FDECA21C7460881F07DF8 54C72A2A292895B167D7EDBAD3CA765ACB01392BC5DACC23D9D0397360984010 556289F7AAC8A3098552894424702948B8D6DE9C928E698260BA3B67183CF6E0 90C669555F5A2E864746B079D326D8F6CCBBA3945204818F802ADD1A4881A68C E2C4D068AD25862D7D99997128E73A90994920E4A6098319CDA0D31E0D9D0A29 1020F26692E8B30243FAC7D15557F359004C29E608D18301B4B9AF11796EBC0E 973D7BF660E7CE9D9072768D38CE39A41FC0270A940A30C14099068D8060B25C 993BD019D3AC30CE25334CCAE31CDA00332C706640391C883435F4D4047C4A2E 52DE4BE280987C56856953E4CD710F227C16F97A94BE01893C9029905DD79D95 544C35D33421020F0174D0958C81CAF0B19472786272EE409BA659A28C4B6E98 34C938B43E2B6E4081874028A048A2B9213402A6353A055DA53C3BFE415292A1 90C84173ED45C2AC2695B64DE9AA4D4C4C60C3860DA8D55A62F0B666591602DF D370190315128C0910C660371C59AA355A1A226B09B4651A36E586C30DA3D014 100D13841B903034600568602C9541A4E582861E9BCA40E2C018C18D52BCE6FC 577BB702A0A6680992AC42291C397204DBB66D4310B494DEBEA365331684E7C1 677ABC92310E2919A81028572A8194B2A55F736A03775ABBF707BF9294F1128B 8B0E33CE404CD380821107BCC86B091862B92011E4F0355080B0584AA2A0190D 51C5312EB5205E9F5E7C282921A5445F5F1F5E7AE9A539834C2945C63411782E 7CCF85EF794DCB64A91298A6F9CEC9385AEFDE811B7C841BC6920830E7496309 440F292995C8804A4B44F4186F2117641A17055299876A5E52CD7829251CC7C1 E6CD9B71F2E4C9560FA7B563E61C9669C0773C48C6B4373309168E614E94CB9E 1062EEA4030028E323710F9A1B71C3DE300C50624229164B07494905422F4EA7 77914420EAF7028882A9CE0AD3AAAC100EF6C58F959231E472B98C175F7C1195 CADCCF26B02C0B1667F05D179273482EC12483941AF464B9628390B90B860040 281BD2450B4FA60384232D06E3908A27E533D13ADD546EA7321112434FCA10E0 746968029C022EA40494C2D0D010366CD800D7755B3D8C19592E97035312BEEF 4186F224E3A90F14956A6D02C0DC55860040283BAE47A6136FA68C833006CBE0 089409A574805369AF9E462E9261A594170388C7AB55F48E022063C02AF26629 71F8F0616CDDBA75D6F9712B562C1641840FDFF3A0B8FE5EC919A8D0B0ABB5FA C9C0F75BDA56CBA041D92061BAF9CFC2E900D13A677204D28252805261208CCB ED482292EC222ED5713A6428157739D290A1A47E5D49BCBE732776BDF146CBBB 3E5BEBECEC84F21C049E174296609283529DDE556AF59693F41978341D00A1C9 C496D4ECA1AC65C01326942461A04A171EC940A92248D2B7D8C2D65118E0880E 73204A7BAA0A012B84CDF8C6E173021900DADBDB21DD06A4EFC5198E9461F92D 184E8D4D1C6B755BAD7B3421FD20249912C0384838E1B0609928DB169454495F A3498B9B5B9F692DD650A3E7A9800705A21408240009A204947B18F0CFDDCCDC EEEE6E88460DC2F7C3DD92A09247DD44797C7462A0D56DB50CDAE0ECA402B129 63399A0A08845214B216462A265474A68750556AB033110995ACD5D4E7892693 509F1524880A00E71088A862CA448DB36A3D3D3DF06B25C810B454124C4A8050 D88E178C94AB2D836EA96001807C365B03C88806AC677692702E5C5BD644C337 7425A71B1E7156A148589623A9EC54F88BC4CF43594834590210501080F4A01A FBA1826A58299EF56972B12D5AB4086EB5ACFBD1810FE107087C1F81EF61B454 F69442CB897BCBA0AFFDDC37240839184D348CBC99108AB6AC05C7B7A0A4806C F23892C882D252A0BD35D263A99718B2064C2074F0932ED0D80F22EAA18444F2 72F68D1082DE9E6E78B52A84EF43F8BE6E97FA7A19992C97B2A631D4EAF65A06 0D000A646F3C2C4593F2DA343894322115A0840CCFEEB416AB26502A04ACD314 192F040280D01E2F1DC0DE07481B88FE5645DB38FBD6D1D1010B0102CF8DE7E4 698FD6CB78B97AFC5FFFD6EA96ABA4D683210005EC5288E63BD078DE034090CF 5868B81CF36474FA4752916A08298090483E00A264F889C4A30914201DA8C601 40B9F1679366D2B901BD62C50A3893E3904240501A37B9A2C1E4D17265EFCF5E DAD9F2F666045A48F9BA542A1E788D279110A0B39045D9A6E8090228A90006A4 BB1571800BA191B8EA4BA44337881CC039A0658384124310B742A1CE8D46AF5C B912F6D810841420429FF88A0110020AC0B1D172EB943143D08C92FD428A1A08 29C413D2428FEE6ACB61FB810087074F82672641583895764A1328DDAB88AA3C A524A492A8D7EA387A687BE8C968FAFBD808F057FFE13753D9876A5A357F38FD DE34AF03CD598C52F03D1FA55205EF5BF73E945FDB19760645F8B63E476B8EEB 0D95EB7B67C26E46A0DBF2795B4AEC26845C0790A60AAFAB98C77089A0BF7FB4 E96FE2443F6C6746497F7A1142A06EDB58FFE28BA856AB6FBB0FF92C476DF7BF D3674D9883ABF8CC49465900C46750DCC74E0127917C21CA7E0025254AA52A8E 1E3D017BD12ABCF0F493204A828804B4541227272B154AC98C40CF28185E7CC7 67A194DA1A6570716E4C080A59139DC5821E4B8B762A0553A5A0A6974008D8B6 8D0DEBD7BF23E4D8A2EC654A572F0AAE240EB2513A98143F24AA3AD3EF857F2F 8480E7BA70451E76D987EF34F47E0BA9B55A0490426268B2DADF9135677411E9 8C4003809062834EE152DDF9D016751691C964B4F74E013D157004D96934B071 E3C699B53953909A80C6F093BE887E4DC63F848A3397E6CF4049083F40C376A1 B29761FCE8A1F0ABF4DFC8F08A0021029C2C55B7F68F576634BA3063D0BEE76E 148108226923516F19048B3B8BC8E572B1F7CA10F65B41765DB7E51943CD96C0 51A9B542F43CD47F34BF97787E2A46C46B09DFF761DB0DF0F62B317C485FD81F C99E062D6037DCE0D0586DC34CB9CD18F4EA3B3F3321A5EC4B291F001D137BE7 17D15628249E1C8195522F29C8BEE761EBCB2F637C7C7CA6BB90920915E7E324 920C24DE4BD2DE1B672C538B27BD9642C2715CD46D1F34B70A63470E845F150E 95090121058E97AA25A554DF4C7779C6A0014048F954240F911110644D034BBB 3BF5107D3AE04DF1E4C0F7D1D7D787E1E1E1D97C7DA8C3290F4DC9482C1DE9F6 6A93B49C0E1B5010818F86DD80CC5C8A91A3C72045A80CE1718A30CE0C4E54F7 7F607967FF4C777976A083E04925955469D861A677514F07DADADA4E832B8220 5EEFDCB9F38CE65BA8E83F75BA54A82932D2B420FD3894166880AEEBA15AB561 2C588781D7B7E929C40843AD529042C0F37DD93F597FEAC9832D57DEB1CD0A34 27EA0D21C59BF104420051BAB7A2BB035DF33B9BB53905F9C08103387AF4E86C BE36361295EC2A29EDE36C02899C248305512A98144969AD16810E82355B81B7 ADC5F0A1BDA0AC397B124260B86AD7466DEFF9D9ECF3AC40F77EE0E3524AF948 A45F5105480841C6E0B8647137F2F9BCF6E6208881F7F7F7BFE37CE4562CF662 4C0978B177271A1E77FCA280987A2F82EDFB3EAAD53A68E74D18DCBD4B1F0B0D 47E843D04A291C19ABEEEFCA1AB31A7598156800F03DEF275269F940AC1E7A6A EBAAC50BD0DDDD1D430E84C0D0A95378634E4646D2A57B737A968C33264B73F3 2AFD39ED204208D8B68372B98EC2B23B70B46F33188FE672EB6F1452C2F57D79 78D27EF478D96E693076AACD1A349162BF927273934E83801282EE79795CBA7C 3132D92C022130393181575F7DB529789E8991A6CC624A609B12FC549859440B 52520225E1B93E2AE53A647E2D26876D3895C9B08FA32947C17C70B236567283 2766BBCFB306BD68DDDD9042FC830E16E1294C105FBDF4BEE53D58B674296AD5 2AB66FDFDEF2C4EF964C4D8596A47151604C5782694D4E17392210B0EB0D4C4E D631EFD27F83432FFD8BEEB30371E08CAADA0363D58DDD597E70B6BB3C6BD000 1078CECF9594C7E32C090088BED6A3B7B388F7AE5C81F1F1F1B99F7791F2DE38 C8A5F2E2B87F719A1E270131CA344AA51AD07E034AA3012AC32752458C82925A 5AC6EA8DDAE192FBA3817263D6ADC33302DD7DFDC73C25E577E2CE5C2A285242 70F5C58B70DB6DB781C59DBCB9B269BC744A494EA6786FFA7DA52482C047A552 C744D947E7EA3FC6BEF5CF404A0129F41275ED9452D8335CDE5D34D9ACB28DC8 CE083400388EFDA0526A04E9A0185E65DBD596C3BAB5AB71CB2DB79CE9D73459 93D7BD5DAE7CDAA2254E08817ADDC1D878058595F7A17FE71E54C786F470951F 84CD2381201098AC379C0313CE0F46EBCEAC826064670CBAE7B76E2F89407C53 37E9138B60AF5DDE837B7EEFA358BC78F1997E55B2ED54F91D697094473775E9 20F5859748321229259C8687F1F12A5CBE0ABCFD66ECDDF02C7CD785EFBA087C 0F221010818094026F0C955FCFB7B5FDF24CF7F98C4103C0F0D8C4DF29A5FA23 A12661F1420981C9196E5AB5149FFAD42791C964E6E2EB101528D395D2F192EA D821F27229E13A1E2627AA98A8702CBAF63F61F34F1F845BAFC3731AF03D570F C486A3DEA355BB76A81AFCEDF0D8F819CF689F13D097FDF65DB6E77A0F2417EF 84ABD0AB17B4E570EB5597E3139FF844DCAF3E238B6420D45E95D2ECF4548674 01A3A44EE54AA53A86466DF4DEF0D7D8FAF813181B3C0AB761C3731C0D3AF0F5 2204FA4E95D77775F79CB1370373041A000E1E3BFE8810E2D9E8F9D4BB015CBA B0031FBBE57ADC75D75D67FE654A36E5C549233FE9C611158DA284903D1F93A5 1A4E0D95D073ED5F60FFF6C3D8FFD2BFC06BD8F09C060237F16621040E8E9486 4E38F8FA912347CE489B239B33D0D7DDF94954AAD5FB01549AEE1690BA4BC095 4BE6E35FDDFE217CF4A31F3DC36F4BA5774AA59EA725240A9802AEEB6162B28A 93A72A98BFF6AB18381C60F3C33F82EF38F05D3D893108BD3808042AB6E36D1F A93F78F3CD376F3D6330A1CD196800587CFD6D47AAB5DA97485A3AE2DB2FE82B 5CAF593A1F7F70C7EDB8E79E7B9A2EBE9C99453D8E94344C936D4829D0687818 1FAFE1E4A92A7AAEFD4B9C3866E0D97FF896BE7381EF21F07D4811C43DE72008 B065707C2B32856F3DFDF4D373C666AE135C2C5DBCE8F54B572CBBCC348DF742 211ED68AB55349F4E44D74F52C42AEA30B7BF7EE9DD11C67D3A0F8EAA757A63A 7188E7A79268DE87520884845D77313E5EC5F07880E5B77C177BFB4EE2570F7E 7B4AA044529C48819D27C606F654C41F9526270FCF25973907FDECFA97D4F557 BEE7B9C50BBB3F6670DE7D5A1E2BF5E305398E9EEE05E859B112070E1C44A3D1 D2B5EB300D8AAF7CFA6220D4E078620BC2B2592A78BE40ADDAC0C8680565B70B BF71EB0FB1E1E7CF62CBA33FC65B9D43524A1C1B2B95369EA87DF58EBBEE7E72 6E1A6089CDF6DC7D47FBF5FFFEFEA5575EBE7A9369F06EDD8BF6C3E9547AEE9A EF7B083C1FA72A36B60F8CE3270F3D8CDDBB77BFE376F35986DA965BA1643261 3D9A05258480E3F8A8546C8C8C56612EFC307AAEF8F778EC5B7F8D63BB774CBB BD68F464A454B1FFF9D0E8F7B31D5D5F191C1898F3593A670D3400FCFA7F7EEF A6B5EF59F58CC1792108029D9FC6A0F5AC4CDFF3506DB8D83BE1E2B9CD5BF1F8 E38FBF6D6F4483FE6D2889F86A5929257C2F40BDEE62A25447A94AB1E4FAFF8C 4AAD1B8FFFED7F45BD34010071F750E92700740B74B252739E3870EA21DEBEE0 FE8163C7CECAED34E75C3AD2F6E35F3E3370C3556B5E5DD8BDE01ECE9811E9B4 4CCB89546044A1CB5458DADB8BCBD65E83D1B1318C8E8E4EBB4D93537CF5D317 034A424A95009EAC6368A80C74BE1F17DDF21D6C7BE6253CFF4FDF45E0BA2034 4A359B6F1FA49442A956F7FEF9C0A95FD0E2FC3F191C18687162C9CCEDAC8206 80879F7AEEF095AB56EE58B2A8E74E837173BA0C210A4C052AD09DE5B87CEDD5 58B8740506070751AFD79BB667728207FEED72F85E00DB763159AA6378A48C9A ECC5B2757F03575D815FFEB76F6060CF6B1A2C254DB79A48DF1561A25A779ED8 7FF2D13A31BF303C3C3C7936399C75D000F0D8AFD7BFB972D9E297972CECF93D CB32B3902A649B1E6ED2BC3914E6C1C3E2F9EDB8EAC675287674E2F8F1E3701C 7D5B0C83137CFEAE6E94CA3686472B283BEDE8B9FA01B4FFC67DD8F8F0A378E5 8987E03B8D54FE4EE325BA861C004E4D566ABFD833F853DAD6F1A7232323339D 5832633B27A001E0A9F55BFA8BB9CCD3CB7A17FD6E219FEB88DAAA4DE37B4832 081302EDD2C68AC58B70FD073E848EF95D181B1B43C3AEE1CEEB0DD8588AEE2B BF84AED55FC0AEF5DBB1E967FF84CAD8A9783A31A551BF25BA05502417C0C153 A3134FEC3BF1DF3B7B973E70F4E8D1FA3BECFA9CD8590D86D3D93DB7AE5BF8B9 3FB8F7E15517AF581707C8D44CFAC0D7D7F5459989EFB9F05C1F559A41CD2A62 70640C1FB96515BA17AE41FFF64DE87FFD95B8E81042843DE5D49CBF30A59452 0FC2BE7CF0D8C0C6FEB1AF77742D78F0587FFF39BB4EE39C797464FB8E1CAB6D 78E5B587962D5C505CB2B0FB5A4AB59BE94C00B16747160D2498C243CE29A327 67A0766A0CC7B66F4465E494FE4CAAFA8C27C84737990A5FAFD98DE0891D07FA 5E3951BABF56B71F2D974A733380D9A29D73D00050AED6826CC67AF6CDA3C7DE E8EDEEBAA5AD502844D37015A22B04C27532615507B1C083F2DD705A7672D541 136C4A637D06804327864B3F7979CF238393F6676DC7393717294EB1F3021A00 761F3A822DAFEFDE7FF0C8B187E7CF6B5BD9DBB3E01212DFEE33AD6949EB55A7 65490F256A5E455E4B23C8E1EB75C7099E7975EFC1C7771CFA2F59C3F8DA44CD 3EEB41EFADECBC818E6C7068B47264F0D4234323A3871774765CD739AFD82665 D8C320D1346C322DE8A66B69E2FBEB114829B1FBE8E0C4FF7AB1EFD17D27C73F 6FBBDEF355C73D77D7CD4D63E71D34008C4C4CAABE3D07DFD8FCEACEFF93358D 7C7767C79A6CC6E24AA9A4A78D481E10171F69D8342C464E8E8ED93F7D61EBAB 4F6CDFF7E7BD9DC56F1E1F2F4D5FF99C637B57808EAC5CB3EB41103CFDECE6AD 4F654C6359F7FC8E8B4C8353A5544A2E9A0147AF8F4D96BCC7366E3BF0A3E75E FEE644ADF1E5AADD786DB85C3BAF5E9CB67715680018181AC189D18921DB711F 7A616BDF6646E9D2059DED4B4DC3A0518E4DC30A0F04189B98F41E7D61CBE11F 3EF9E20F0E0F8D7DE96B9FBAE3D78F6EDED1D24DFFCEA59DF33C7AA676ED7B2E A3AEEBACFBD8FBAFFBB3AB565FF2A1455DF37322087064F044EDA94DDBFA9FEF DBF5E340C8872A75BBE5EBB22FD8DBD8CD57AD414F67FB7B7FFFD69BBEB96EED E5BFB04CF30F7B3ADB3BCFF77EFD7F6DEB37CCF812920B76C12ED805BB6017EC 2DEDFF02651502B1A25FA0770000000049454E44AE426082 } end object ButtonPanel: TButtonPanel AnchorSideTop.Control = chkElevateAll AnchorSideTop.Side = asrBottom Left = 12 Height = 33 Top = 100 Width = 376 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 24 BorderSpacing.Around = 8 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True HelpButton.Name = 'HelpButton' HelpButton.DefaultCaption = True CloseButton.Name = 'CloseButton' CloseButton.DefaultCaption = True CancelButton.Name = 'CancelButton' CancelButton.DefaultCaption = True TabOrder = 0 ShowButtons = [pbOK, pbCancel] ShowBevel = False end end �����������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/felevation.lrj���������������������������������������������������������0000644�0001750�0000144�00000000417�14743153644�017646� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"version":1,"strings":[ {"hash":234500131,"name":"tfrmelevation.chkelevateall.caption","sourcebytes":[68,111,32,116,104,105,115,32,102,111,114,32,38,97,108,108,32,99,117,114,114,101,110,116,32,111,98,106,101,99,116,115],"value":"Do this for &all current objects"} ]} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/felevation.pas���������������������������������������������������������0000644�0001750�0000144�00000004146�14743153644�017645� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fElevation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel, ExtCtrls, uShowMsg; type { TfrmElevation } TfrmElevation = class(TForm) ButtonPanel: TButtonPanel; chkElevateAll: TCheckBox; imgShield: TImage; lblText: TLabel; public function ShowModal: Integer; override; end; function ShowElevation(const ATitle, AText: String): TMyMsgResult; implementation {$R *.lfm} {$IF DEFINED(MSWINDOWS)} uses Windows, uBitmap; {$ENDIF} type TElevationData = class FResult: TMyMsgResult; FTitle, FText: String; procedure ShowElevation; public constructor Create(const ATitle, AText: String); end; function ShowElevation(const ATitle, AText: String): TMyMsgResult; begin with TElevationData.Create(ATitle, AText) do try TThread.Synchronize(nil, @ShowElevation); Result:= FResult; finally Free end; end; { TElevationData } procedure TElevationData.ShowElevation; begin with TfrmElevation.Create(Application) do try Caption:= FTitle; lblText.Caption:= FText; ShowModal; if (ModalResult <> mrOK) then begin if chkElevateAll.Checked then FResult:= mmrSkipAll else FResult:= mmrSkip end else begin if chkElevateAll.Checked then FResult:= mmrAll else FResult:= mmrOK; end; finally Free; end; end; constructor TElevationData.Create(const ATitle, AText: String); begin FText:= AText; FTitle:= ATitle; end; { TfrmElevation } function TfrmElevation.ShowModal: Integer; {$IF DEFINED(MSWINDOWS)} const IDI_SHIELD = PAnsiChar(32518); var hIcon: THandle; AIcon: Graphics.TBitmap; {$ENDIF} begin {$IF DEFINED(MSWINDOWS)} hIcon:= LoadImage(0, IDI_SHIELD, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE or LR_SHARED); if (hIcon <> 0) then begin AIcon:= BitmapCreateFromHICON(hIcon); imgShield.Picture.Assign(AIcon); AIcon.Free; end; {$ENDIF} Result:= inherited ShowModal; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/unix/������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015762� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/unix/uclientserver.pas�������������������������������������������������0000644�0001750�0000144�00000012020�14743153644�021354� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Remote procedure call implementation (Unix) Copyright (C) 2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uClientServer; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Ssockets, uService; type { TUnixServer } TUnixServer = class(Ssockets.TUnixServer) protected procedure Bind; override; end; { TPipeTransport } TPipeTransport = class(TBaseTransport) private FAddress : String; FConnection : TSocketStream; private procedure Connect; public procedure Disconnect; override; procedure WriteHandle(AHandle: THandle); override; function ReadHandle(var AHandle: THandle) : Int64; override; procedure WriteBuffer(const AData; const ALength : Int64); override; function ReadBuffer(var AData; const ALength : Int64) : Int64; override; public constructor Create(const Address : String); constructor Create(ASocket : TSocketStream); destructor Destroy; override; end; { TClientHandlerThread } TClientHandlerThread = class(TClientThread) public constructor Create(ASocket : TSocketStream; AOwner : TBaseService); end; { TServerListnerThread } TServerListnerThread = class(TServerThread) private FSocketObject : TUnixServer; procedure DoConnect(Sender: TObject; Data: TSocketStream); public destructor Destroy; override; procedure Execute; override; end; implementation uses BaseUnix, Unix, uLocalSockets, uDebug; { TUnixServer } procedure TUnixServer.Bind; begin inherited Bind; fpChmod(FileName, &0666); end; { TPipeTransport } procedure TPipeTransport.Connect; begin if FConnection = nil then begin FConnection:= TUnixSocket.Create(SocketDirectory + FAddress); SetSocketClientProcessId(FConnection.Handle); end; end; procedure TPipeTransport.Disconnect; begin FreeAndNil(FConnection); end; procedure TPipeTransport.WriteHandle(AHandle: THandle); begin SendHandle(FConnection.Handle, AHandle); end; function TPipeTransport.ReadHandle(var AHandle: THandle): Int64; begin AHandle:= RecvHandle(FConnection.Handle); end; procedure TPipeTransport.WriteBuffer(const AData; const ALength : Int64); var P : PByte; C, Len : Integer; begin Connect; P := PByte(@AData); Len := ALength; repeat C := FConnection.Write(P^,len); if (C < 0) then raise EInOutError.Create(SysErrorMessage(FConnection.LastError)); if (C > 0) then begin Inc(P, C); Dec(Len, C); end; until (Len = 0); end; function TPipeTransport.ReadBuffer(var AData; const ALength : Int64) : Int64; Var P : PByte; C : Integer; Len : Int64; begin Len := ALength; P:= PByte(@AData); repeat C:= FConnection.Read(P^, Len); if (C <= 0) then raise EInOutError.Create(SysErrorMessage(FConnection.LastError)); if (C > 0) then begin Inc(P, C); Dec(Len, C); end until (Len = 0); Result := ALength; end; constructor TPipeTransport.Create(const Address: String); begin FAddress:= Address; end; constructor TPipeTransport.Create(ASocket: TSocketStream); begin FConnection:= ASocket; end; destructor TPipeTransport.Destroy; begin FreeAndNil(FConnection); inherited Destroy; end; { TClientHandlerThread } constructor TClientHandlerThread.Create(ASocket : TSocketStream; AOwner : TBaseService); begin FOwner := AOwner; FreeOnTerminate := True; FTransport:= TPipeTransport.Create(ASocket); inherited Create(False); end; { TServerListnerThread } procedure TServerListnerThread.DoConnect(Sender: TObject; Data: TSocketStream); begin if (FOwner.VerifyChild and not VerifyChild(Data.Handle)) or (FOwner.VerifyParent and not VerifyParent(Data.Handle)) then begin Data.Free; Exit; end; if not Terminated then TClientHandlerThread.Create(Data, FOwner) else Data.Free; end; destructor TServerListnerThread.Destroy; begin DCDebug('TServerListnerThread.Destroy'); FSocketObject.StopAccepting(True); inherited Destroy; end; procedure TServerListnerThread.Execute; begin try FSocketObject:= TUnixServer.Create(SocketDirectory + FOwner.Name); try FSocketObject.Bind; FReadyEvent.SetEvent; FSocketObject.OnConnect:= @DoConnect; FSocketObject.StartAccepting; finally FreeAndNil(FSocketObject); end; except on e : Exception do begin Terminate; end; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/unix/ulocalsockets.pas�������������������������������������������������0000644�0001750�0000144�00000022120�14743153644�021337� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uLocalSockets; {$mode objfpc}{$H+} {$packrecords c} interface uses Classes, SysUtils, BaseUnix, Sockets; function VerifyChild(Handle: THandle): Boolean; function VerifyParent(Handle: THandle): Boolean; procedure SetSocketClientProcessId({%H-}fd: cint); function GetSocketClientProcessId(fd: cint): pid_t; function SendHandle(sock: cint; fd: cint): Boolean; function RecvHandle(sock: cint): cint; function SocketDirectory: String; implementation uses InitC, uProcessInfo, uDebug; const SCM_RIGHTS = $01; //* Transfer file descriptors. */ type msglen_t = {$IF DEFINED(BSD) OR DEFINED(HAIKU)}cint{$ELSE}size_t{$ENDIF}; Pmsghdr = ^msghdr; msghdr = record msg_name : pointer; msg_namelen : socklen_t; msg_iov : piovec; msg_iovlen : msglen_t; msg_control : pointer; msg_controllen : msglen_t; msg_flags : cInt; end; Pcmsghdr = ^cmsghdr; cmsghdr = record cmsg_len : msglen_t; cmsg_level : cInt; cmsg_type : cInt; end; function sendmsg(__fd: cInt; __message: pmsghdr; __flags: cInt): ssize_t; cdecl; external clib name 'sendmsg'; function recvmsg(__fd: cInt; __message: pmsghdr; __flags: cInt): ssize_t; cdecl; external clib name 'recvmsg'; {$IF DEFINED(LINUX)} type ucred = record pid : pid_t; uid : uid_t; gid : gid_t; end; {$ELSEIF DEFINED(HAIKU)} const MSG_NOSIGNAL = $0800; SO_PEERCRED = $4000000; type ucred = record pid : pid_t; uid : uid_t; gid : gid_t; end; {$ELSEIF DEFINED(DARWIN)} const MSG_NOSIGNAL = $20000; LOCAL_PEERPID = $002; //* retrieve peer pid */ SOL_LOCAL = 0; //* Level number of get/setsockopt for local domain sockets */ {$ELSEIF DEFINED(BSD)} const SCM_CREDS = $03; //* process creds (struct cmsgcred) */ type Pcmsgcred = ^cmsgcred; cmsgcred = record cmcred_pid: pid_t; //* PID of sending process */ cmcred_uid: uid_t; //* real UID of sending process */ cmcred_euid: uid_t; //* effective UID of sending process */ cmcred_gid: gid_t; //* real GID of sending process */ cmcred_ngroups: cshort; //* number or groups */ cmcred_groups: array[0..15] of gid_t; //* groups */ end; {$ENDIF} const {$IF DEFINED(DARWIN)} ALIGN_BYTES = csize_t(SizeOf(cuint32) - 1); {$ELSE} ALIGN_BYTES = csize_t(SizeOf(csize_t) - 1); {$ENDIF} function CMSG_ALIGN(len: csize_t): csize_t; inline; begin Result:= (((len) + ALIGN_BYTES) and (not (ALIGN_BYTES))); end; function CMSG_SPACE(len: csize_t): csize_t; inline; begin Result:= (CMSG_ALIGN(len) + CMSG_ALIGN(SizeOf(cmsghdr))); end; function CMSG_LEN(len: csize_t): csize_t; inline; begin Result:= (CMSG_ALIGN(SizeOf(cmsghdr)) + (len)); end; function CMSG_DATA(cmsg: Pcmsghdr): PByte; inline; {$IF DEFINED(BSD)} begin Result:= PByte(cmsg) + CMSG_ALIGN(SizeOf(cmsghdr)); end; {$ELSE} begin Result:= PByte(cmsg + 1) end; {$ENDIF} function SendMessage(__fd: cInt; __message: pmsghdr; __flags: cInt): ssize_t; begin repeat Result:= sendmsg(__fd, __message, __flags); until (Result <> -1) or (fpgetCerrno <> ESysEINTR); end; function RecvMessage(__fd: cInt; __message: pmsghdr; __flags: cInt): ssize_t; begin repeat Result:= recvmsg(__fd, __message, __flags); until (Result <> -1) or (fpgetCerrno <> ESysEINTR); end; procedure SetSocketClientProcessId(fd: cint); {$IF DEFINED(LINUX) OR DEFINED(DARWIN) OR DEFINED(HAIKU)} begin end; {$ELSE} var buf: Byte; iov: iovec; msg: msghdr; cmsga: Pcmsghdr; nbytes: ssize_t; data: array[Byte] of Byte; begin cmsga := Pcmsghdr(@data[0]); {* * The backend doesn't care what we send here, but it wants * exactly one character to force recvmsg() to block and wait * for us. *} buf := 0; iov.iov_base := @buf; iov.iov_len := 1; cmsga^.cmsg_len := CMSG_LEN(SizeOf(cmsgcred)); cmsga^.cmsg_level := SOL_SOCKET; cmsga^.cmsg_type := SCM_CREDS; {* * cmsg.cred will get filled in with the correct information * by the kernel when this message is sent. *} msg.msg_name := nil; msg.msg_namelen := 0; msg.msg_iov := @iov; msg.msg_iovlen := 1; msg.msg_control := cmsga; msg.msg_controllen := CMSG_SPACE(SizeOf(cmsgcred)); msg.msg_flags := MSG_NOSIGNAL; nbytes := SendMessage(fd, @msg, MSG_NOSIGNAL); if (nbytes = -1) then DCDebug('SendMessage: ', SysErrorMessage(fpgetCerrno)); end; {$ENDIF} function GetSocketClientProcessId(fd: cint): pid_t; {$IF DEFINED(LINUX) OR DEFINED(HAIKU)} var cred: ucred; ALength: TSockLen; begin ALength:= SizeOf(ucred); if (fpgetsockopt(fd, SOL_SOCKET, SO_PEERCRED, @cred, @ALength) = -1) then Exit(-1); Result:= cred.pid; end; {$ELSEIF DEFINED(DARWIN)} var ALength: TSockLen; begin ALength:= SizeOf(Result); if (fpgetsockopt(fd, SOL_LOCAL, LOCAL_PEERPID, @Result, @ALength) = -1) then Exit(-1); end; {$ELSE} var buf: Byte; iov: iovec; msg: msghdr; cmsga: Pcmsghdr; nbytes: ssize_t; data: array[Byte] of Byte; begin cmsga := Pcmsghdr(@data[0]); msg.msg_name := nil; msg.msg_namelen := 0; msg.msg_iov := @iov; msg.msg_iovlen := 1; msg.msg_control := cmsga; msg.msg_controllen := CMSG_SPACE(SizeOf(cmsgcred)); msg.msg_flags := MSG_NOSIGNAL; {* * The one character which is received here is not meaningful; * its purposes is only to make sure that recvmsg() blocks * long enough for the other side to send its credentials. *} iov.iov_base := @buf; iov.iov_len := 1; nbytes := RecvMessage(fd, @msg, MSG_NOSIGNAL); if (nbytes = -1) then DCDebug('RecvMessage: ', SysErrorMessage(fpgetCerrno)); Result:= Pcmsgcred(CMSG_DATA(cmsga))^.cmcred_pid; end; {$ENDIF} function SendHandle(sock: cint; fd: cint): Boolean; var buf: Byte; iov: iovec; msg: msghdr; cmsga: Pcmsghdr; nbytes: ssize_t; data: array[Byte] of Byte; begin cmsga := Pcmsghdr(@data[0]); {* * The backend doesn't care what we send here, but it wants * exactly one character to force recvmsg() to block and wait * for us. *} buf := 0; iov.iov_base := @buf; iov.iov_len := 1; cmsga^.cmsg_len := CMSG_LEN(SizeOf(fd)); cmsga^.cmsg_level := SOL_SOCKET; cmsga^.cmsg_type := SCM_RIGHTS; {* * cmsg.cred will get filled in with the correct information * by the kernel when this message is sent. *} msg.msg_name := nil; msg.msg_namelen := 0; msg.msg_iov := @iov; msg.msg_iovlen := 1; msg.msg_control := cmsga; msg.msg_controllen := CMSG_SPACE(SizeOf(fd)); msg.msg_flags := MSG_NOSIGNAL; Move(fd, CMSG_DATA(cmsga)^, SizeOf(fd)); nbytes := SendMessage(sock, @msg, MSG_NOSIGNAL); if (nbytes = -1) then DCDebug('SendHandle: ', SysErrorMessage(fpgetCerrno)); FileClose(fd); Result:= (nbytes > 0) end; function RecvHandle(sock: cint): cint; var buf: Byte; iov: iovec; msg: msghdr; cmsga: Pcmsghdr; nbytes: ssize_t; data: array[Byte] of Byte; begin cmsga := Pcmsghdr(@data[0]); msg.msg_name := nil; msg.msg_namelen := 0; msg.msg_iov := @iov; msg.msg_iovlen := 1; msg.msg_control := cmsga; msg.msg_controllen := CMSG_SPACE(SizeOf(Result)); msg.msg_flags := MSG_NOSIGNAL; {* * The one character which is received here is not meaningful; * its purposes is only to make sure that recvmsg() blocks * long enough for the other side to send its credentials. *} iov.iov_base := @buf; iov.iov_len := 1; nbytes := RecvMessage(sock, @msg, MSG_NOSIGNAL); if (nbytes = -1) then DCDebug('RecvHandle: ', SysErrorMessage(fpgetCerrno)); Move(CMSG_DATA(cmsga)^, Result, SizeOf(Result)); end; function CheckParent(ProcessId, ParentId: pid_t): Boolean; begin DCDebug(['ProcessId: ', ProcessId]); while (ProcessId <> ParentId) and (ProcessId > 1) do begin ProcessId:= GetParentProcessId(ProcessId); DCDebug(['ProcessId: ', ProcessId]); end; Result:= (ProcessId = ParentId); end; function VerifyChild(Handle: THandle): Boolean; var ProcessId: pid_t; begin DCDebug('VerifyChild'); ProcessId:= GetSocketClientProcessId(Handle); DCDebug(['Credentials from socket: pid=', ProcessId]); Result:= CheckParent(ProcessId, GetProcessId);{ and (GetProcessFileName(ProcessId) = GetProcessFileName(GetProcessId));} DCDebug(['VerifyChild: ', Result]); end; function VerifyParent(Handle: THandle): Boolean; var ProcessId: pid_t; begin DCDebug('VerifyParent'); ProcessId:= GetSocketClientProcessId(Handle); DCDebug(['Credentials from socket: pid=', ProcessId]); Result:= CheckParent(FpGetppid, ProcessId) and (GetProcessFileName(ProcessId) = GetProcessFileName(GetProcessId)); DCDebug(['VerifyParent: ', Result]); end; function SocketDirectory: String; var Stat: TStat; UserID: TUid; begin UserID:= fpGetUID; if UserID = 0 then begin UserID:= GetProcessUserId(StrToInt(ParamStr(2))); end; Result:= '/tmp/doublecmd' + '-' + IntToStr(UserID); // Verify directory owner if not DirectoryExists(Result) then begin if fpMkDir(Result, &700) <> 0 then RaiseLastOSError; end else begin if fpStat(Result, Stat) <> 0 then RaiseLastOSError; if (Stat.st_uid <> UserID) and (fpChown(Result, UserID, Stat.st_gid) < 0) then RaiseLastOSError; if ((Stat.st_mode and $0FFF) <> &700) and (fpChmod(Result, &700) < 0) then RaiseLastOSError; end; Result += PathDelim; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/unix/uprocessinfo.pas��������������������������������������������������0000644�0001750�0000144�00000011400�14743153644�021202� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uProcessInfo; {$mode objfpc}{$H+} {$packrecords c} interface uses Classes, SysUtils, BaseUnix; function GetProcessUserId(ProcessId: pid_t): uid_t; function GetParentProcessId(ProcessId: pid_t): pid_t; function GetProcessFileName(ProcessId: pid_t): String; implementation uses InitC {$IF DEFINED(FREEBSD)} , FreeBSD, SysCtl {$ENDIF} ; {$IF DEFINED(LINUX)} function GetProcessUserId(ProcessId: pid_t): uid_t; var Info: TStat; begin if fpStat(Format('/proc/%d', [ProcessId]), Info) < 0 then Result:= 0 else Result:= Info.st_uid; end; function GetParentProcessId(ProcessId: pid_t): pid_t; var pid: pid_t; hFile: THandle; ABuffer: String; comm, state: String; begin hFile:= FileOpen(Format('/proc/%d/stat', [ProcessId]), fmOpenRead or fmShareDenyNone); if hFile = feInvalidHandle then (Exit(-1)); SetLength(ABuffer, MAX_PATH); Result:= FileRead(hFile, ABuffer[1], MAX_PATH); if (Result >= 0) then begin SetLength(ABuffer, Result); SScanf(ABuffer, '%d %s %s %d', [@pid, @comm, @state, @Result]); end; FileClose(hFile); end; function GetProcessFileName(ProcessId: pid_t): String; begin Result:= fpReadLink(Format('/proc/%d/exe', [ProcessId])); end; {$ELSEIF DEFINED(DARWIN)} const MAXCOMLEN = 16; PROC_PIDPATHINFO = 11; PROC_PIDT_SHORTBSDINFO = 13; type Tproc_bsdshortinfo = record pbsi_pid: UInt32; // Process identifier pbsi_ppid: UInt32; // Parent process identifier pbsi_pgid: UInt32; pbsi_status: UInt32; pbsi_comm: array[0..MAXCOMLEN-1] of AnsiChar; // Process name pbsi_flags: UInt32; pbsi_uid: uid_t; pbsi_gid: gid_t; pbsi_ruid: uid_t; pbsi_rgid: gid_t; pbsi_svuid: uid_t; pbsi_svgid: gid_t; pbsi_rfu: UInt32; end; function proc_pidinfo(pid: cint; flavor: cint; arg: cuint64; buffer: pointer; buffersize: cint): cint; cdecl; external 'proc'; function GetProcessUserId(ProcessId: pid_t): uid_t; var ret: cint; info: Tproc_bsdshortinfo; begin ret:= proc_pidinfo(ProcessId, PROC_PIDT_SHORTBSDINFO, 0, @info, SizeOf(Tproc_bsdshortinfo)); if (ret = SizeOf(Tproc_bsdshortinfo)) then Result:= info.pbsi_ruid else Result:= 0; end; function GetParentProcessId(ProcessId: pid_t): pid_t; var ret: cint; info: Tproc_bsdshortinfo; begin ret:= proc_pidinfo(ProcessId, PROC_PIDT_SHORTBSDINFO, 0, @info, SizeOf(Tproc_bsdshortinfo)); if (ret = SizeOf(Tproc_bsdshortinfo)) then Result:= info.pbsi_ppid else Result:= -1; end; function GetProcessFileName(ProcessId: pid_t): String; begin SetLength(Result, MAX_PATH + 1); if proc_pidinfo(ProcessId, PROC_PIDPATHINFO, 0, Pointer(Result), MAX_PATH) < 0 then SetLength(Result, 0); end; {$ELSEIF DEFINED(FREEBSD)} type Tkinfo_proc = record ki_structsize: cint; ki_layout: cint; ki_args: pointer; ki_paddr: pointer; ki_addr: pointer; ki_tracep: pointer; ki_textvp: pointer; ki_fd: pointer; ki_vmspace: pointer; ki_wchan: pointer; ki_pid: pid_t; // Process identifier ki_ppid: pid_t; // Parent process identifier ki_pgid: pid_t; ki_tpgid: pid_t; ki_sid: pid_t; ki_tsid: pid_t; ki_jobc: cshort; ki_spare_short1: cshort; ki_tdev_freebsd11: cuint32; ki_siglist: sigset_t; ki_sigmask: sigset_t; ki_sigignore: sigset_t; ki_sigcatch: sigset_t; ki_uid: uid_t; // Effective user id ki_ruid: uid_t; // Real user id ki_reserved: array[0..4095] of byte; end; function GetProcessUserId(ProcessId: pid_t): uid_t; var length: csize_t; info: Tkinfo_proc; mib: array[0..3] of cint = (CTL_KERN, KERN_PROC, KERN_PROC_PID, 0); begin mib[3] := ProcessId; length := SizeOf(Tkinfo_proc); if (FPsysctl(@mib, 4, @info, @length, nil, 0) < 0) then Exit(0); if (length = 0) then Exit(0); Result:= info.ki_ruid; end; function GetParentProcessId(ProcessId: pid_t): pid_t; var length: csize_t; info: Tkinfo_proc; mib: array[0..3] of cint = (CTL_KERN, KERN_PROC, KERN_PROC_PID, 0); begin mib[3] := ProcessId; length := SizeOf(Tkinfo_proc); if (FPsysctl(@mib, 4, @info, @length, nil, 0) < 0) then Exit(-1); if (length = 0) then Exit(-1); Result:= info.ki_ppid; end; function GetProcessFileName(ProcessId: pid_t): String; begin kernproc_getpath(ProcessId, Result); end; {$ELSE} function GetProcessUserId(ProcessId: pid_t): uid_t; begin Result:= 0; end; function GetParentProcessId(ProcessId: pid_t): pid_t; begin Result:= -1; end; function GetProcessFileName(ProcessId: pid_t): String; begin Result:= EmptyStr; end; {$ENDIF} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/usuperuser.pas���������������������������������������������������������0000644�0001750�0000144�00000017656�14743153644�017745� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uSuperUser; {$mode objfpc}{$H+} interface procedure WaitProcess(Process: UIntPtr); function AdministratorPrivileges: Boolean; inline; function TerminateProcess(Process: UIntPtr): Boolean; function ElevationRequired(LastError: Integer = 0): Boolean; function ExecCmdAdmin(const Exe: String; Args: array of String; sStartPath: String = ''): UIntPtr; implementation uses SysUtils {$IF DEFINED(MSWINDOWS)} , Types, Windows, DCOSUtils, ShellApi, DCConvertEncoding, uMyWindows {$ELSEIF DEFINED(UNIX)} , Classes, Unix, BaseUnix, DCUnix, Dialogs, SyncObjs, Process, un_process {$IF DEFINED(DARWIN)} , DCStrUtils {$ENDIF} {$ENDIF} ; var FAdministratorPrivileges: Boolean; procedure WaitProcess(Process: UIntPtr); {$IF DEFINED(MSWINDOWS)} begin WaitForSingleObject(Process, INFINITE); CloseHandle(Process); end; {$ELSE} var Status : cInt = 0; begin while (FpWaitPid(Process, @Status, 0) = -1) and (fpgeterrno() = ESysEINTR) do; end; {$ENDIF} function ElevationRequired(LastError: Integer = 0): Boolean; {$IF DEFINED(MSWINDOWS)} begin if FAdministratorPrivileges then Exit(False); if LastError = 0 then LastError:= GetLastError; Result:= (LastError = ERROR_ACCESS_DENIED) or (LastError = ERROR_PRIVILEGE_NOT_HELD) or (LastError = ERROR_INVALID_OWNER) or (LastError = ERROR_NOT_ALL_ASSIGNED); end; {$ELSE} begin if FAdministratorPrivileges then Exit(False); if LastError = 0 then LastError:= GetLastOSError; Result:= (LastError = ESysEPERM) or (LastError = ESysEACCES); end; {$ENDIF} function AdministratorPrivileges: Boolean; begin Result:= FAdministratorPrivileges; end; function TerminateProcess(Process: UIntPtr): Boolean; {$IF DEFINED(MSWINDOWS)} begin Result:= Windows.TerminateProcess(Process, 1); end; {$ELSE} begin Result:= fpKill(Process, SIGTERM) = 0; end; {$ENDIF} {$IF DEFINED(UNIX)} const SYS_PATH: array[0..1] of String = ('/usr/bin/', '/usr/local/bin/'); resourcestring rsMsgPasswordEnter = 'Please enter the password:'; type TSuperProgram = (spNone, spSudo, spPkexec); { TSuperUser } TSuperUser = class(TThread) private FPrompt: String; FCtl: TExProcess; FMessage: String; FArgs: TStringArray; FEvent: TSimpleEvent; private procedure Ready; procedure RequestPassword; procedure OnReadLn(Str: String); procedure OnQueryString(Str: String); protected procedure Execute; override; public constructor Create(Args: TStringArray; const StartPath: String); destructor Destroy; override; end; var SuperExe: String; SuperProgram: TSuperProgram; function ExecuteCommand(Command: String; Args: TStringArray; StartPath: String): UIntPtr; var ProcessId : TPid; begin ProcessId := fpFork; if ProcessId = 0 then begin { Set the close-on-exec flag to all } FileCloseOnExecAll; { Set child current directory } if Length(StartPath) > 0 then fpChdir(StartPath); { The child does the actual exec, and then exits } if FpExecLP(Command, Args) = -1 then Writeln(Format('Execute error %d: %s', [fpgeterrno, SysErrorMessage(fpgeterrno)])); { If the FpExecLP fails, we return an exitvalue of 127, to let it be known } fpExit(127); end else if ProcessId = -1 then { Fork failed } begin WriteLn('Fork failed: ' + Command, LineEnding, SysErrorMessage(fpgeterrno)); end; if ProcessId < 0 then Result := 0 else Result := ProcessId; end; function FindExecutable(const FileName: String; out FullName: String): Boolean; var Index: Integer; begin for Index:= Low(SYS_PATH) to High(SYS_PATH) do begin FullName:= SYS_PATH[Index] + FileName; if fpAccess(FullName, X_OK) = 0 then Exit(True); end; Result:= False; end; function ExecuteSudo(Args: TStringArray; const StartPath: String): UIntPtr; begin with TSuperUser.Create(Args, StartPath) do begin Start; FEvent.WaitFor(INFINITE); Result:= FCtl.Process.ProcessHandle; end; end; { TSuperUser } procedure TSuperUser.Ready; begin FEvent.SetEvent; Yield; FreeOnTerminate:= True; FCtl.OnOperationProgress:= nil; end; procedure TSuperUser.RequestPassword; var S: String = ''; begin if Length(FMessage) = 0 then begin FMessage:= rsMsgPasswordEnter end; if not InputQuery('Double Commander', FMessage, True, S) then FCtl.Stop else begin S:= S + LineEnding; FCtl.Process.Input.Write(S[1], Length(S)); end; FMessage:= EmptyStr; end; procedure TSuperUser.OnReadLn(Str: String); begin FMessage:= Str; end; procedure TSuperUser.OnQueryString(Str: String); begin Synchronize(@RequestPassword) end; procedure TSuperUser.Execute; var GUID : TGUID; Index: Integer; begin CreateGUID(GUID); FPrompt:= GUIDToString(GUID); FCtl.Process.Options:= FCtl.Process.Options + [poStderrToOutPut]; FCtl.Process.Executable:= SuperExe; FCtl.Process.Parameters.Add('-S'); FCtl.Process.Parameters.Add('-k'); FCtl.Process.Parameters.Add('-p'); FCtl.Process.Parameters.Add(FPrompt); for Index:= 0 to High(FArgs) do begin FCtl.Process.Parameters.Add(FArgs[Index]); end; FCtl.QueryString:= FPrompt; FCtl.OnQueryString:= @OnQueryString; FCtl.OnOperationProgress:= @Ready; fCtl.OnProcessExit:= @Ready; FCtl.OnReadLn:= @OnReadLn; FCtl.Execute; end; constructor TSuperUser.Create(Args: TStringArray; const StartPath: String); begin inherited Create(True); FCtl:= TExProcess.Create(EmptyStr); FCtl.Process.CurrentDirectory:= StartPath; FEvent:= TSimpleEvent.Create; FArgs:= Args; end; destructor TSuperUser.Destroy; begin inherited Destroy; FEvent.Free; FCtl.Free; end; {$ELSEIF DEFINED(MSWINDOWS)} function MaybeQuoteIfNotQuoted(const S: String): String; begin if (Pos(' ', S) <> 0) and (pos('"', S) = 0) then Result := '"' + S + '"' else Result := S; end; {$ENDIF} function ExecCmdAdmin(const Exe: String; Args: array of String; sStartPath: String): UIntPtr; {$IF DEFINED(MSWINDOWS)} var Index: Integer; AParams: String; lpExecInfo: TShellExecuteInfoW; begin AParams := EmptyStr; for Index := Low(Args) to High(Args) do AParams += MaybeQuoteIfNotQuoted(Args[Index]) + ' '; if sStartPath = EmptyStr then sStartPath:= mbGetCurrentDir; ZeroMemory(@lpExecInfo, SizeOf(lpExecInfo)); lpExecInfo.cbSize:= SizeOf(lpExecInfo); lpExecInfo.fMask:= SEE_MASK_NOCLOSEPROCESS; lpExecInfo.lpFile:= PWideChar(CeUtf8ToUtf16(Exe)); lpExecInfo.lpDirectory:= PWideChar(CeUtf8ToUtf16(sStartPath)); lpExecInfo.lpParameters:= PWideChar(CeUtf8ToUtf16(AParams)); lpExecInfo.lpVerb:= 'runas'; if ShellExecuteExW(@lpExecInfo) then Result:= lpExecInfo.hProcess else Result:= 0; end; {$ELSEIF DEFINED(DARWIN)} var Index: Integer; ACommand: String; AParams: TStringArray; begin ACommand:= EscapeNoQuotes(Exe); for Index := Low(Args) to High(Args) do ACommand += ' ' + EscapeNoQuotes(Args[Index]); SetLength(AParams, 7); AParams[0]:= '-e'; AParams[1]:= 'on run argv'; AParams[2]:= '-e'; AParams[3]:= 'do shell script (item 1 of argv) with administrator privileges'; AParams[4]:= '-e'; AParams[5]:='end run'; AParams[6]:= ACommand; Result:= ExecuteCommand('/usr/bin/osascript', AParams, sStartPath); end; {$ELSE} var Index: Integer; AParams: TStringArray; begin SetLength(AParams, Length(Args) + 1); for Index := Low(Args) to High(Args) do AParams[Index + 1]:= Args[Index]; AParams[0] := Exe; case SuperProgram of spSudo: Result:= ExecuteSudo(AParams, sStartPath); spPkexec: Result:= ExecuteCommand(SuperExe, AParams, sStartPath); end; end; {$ENDIF} initialization {$IF DEFINED(DARWIN) OR DEFINED(HAIKU)} FAdministratorPrivileges:= True; {$ELSEIF DEFINED(UNIX)} {$IFDEF LINUX} if FindExecutable('pkexec', SuperExe) then SuperProgram:= spPkexec else {$ENDIF} if FindExecutable('sudo', SuperExe) then SuperProgram:= spSudo else begin SuperProgram:= spNone; end; FAdministratorPrivileges:= (fpGetUID = 0) or (SuperProgram = spNone); {$ELSE} FAdministratorPrivileges:= (IsUserAdmin <> dupError); {$ENDIF} end. ����������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/win/�������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�015574� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/win/uclientserver.pas��������������������������������������������������0000644�0001750�0000144�00000027761�14743153644�021210� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Remote procedure call implementation (Windows) Copyright (C) 2019-2021 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uClientServer; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uService; type { TPipeTransport } TPipeTransport = class(TBaseTransport) private FPipe: THandle; FProcessID: UInt32; FAddress: UnicodeString; private procedure Connect; public procedure Disconnect; override; procedure WriteHandle(AHandle: THandle); override; function ReadHandle(var AHandle: THandle) : Int64; override; procedure WriteBuffer(const AData; const ALength : Int64); override; function ReadBuffer(var AData; const ALength : Int64) : Int64; override; public constructor Create(APipe: THandle; ProcessID: UInt32); constructor Create(Address: String); destructor Destroy; override; end; { TClientHandlerThread } TClientHandlerThread = class(TClientThread) public constructor Create(APipe : THandle; AOwner : TBaseService); end; { TServerListnerThread } TServerListnerThread = class(TServerThread) private FEvent: THandle; public constructor Create(AOwner : TBaseService); override; destructor Destroy; override; procedure Execute; override; end; implementation uses JwaWinNT, JwaAclApi, JwaAccCtrl, JwaWinBase, Windows, DCOSUtils, DCConvertEncoding, uNamedPipes, uDebug, uProcessInfo; { TPipeTransport } procedure TPipeTransport.Connect; begin if (FPipe = 0) then begin DCDebug('Connect to ', String(FAddress)); FPipe:= CreateFileW(PWideChar('\\.\pipe\' + FAddress), GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if FPipe = INVALID_HANDLE_VALUE then RaiseLastOSError; end; end; procedure TPipeTransport.Disconnect; begin CloseHandle(FPipe); FPipe:= 0; end; procedure TPipeTransport.WriteHandle(AHandle: THandle); var hProcess: THandle; hDuplicate: THandle; begin hProcess:= OpenProcess(PROCESS_DUP_HANDLE, False, FProcessID); if (hProcess <> 0) then begin if DuplicateHandle(GetCurrentProcess(), AHandle, hProcess, @hDuplicate, 0, False, DUPLICATE_SAME_ACCESS or DUPLICATE_CLOSE_SOURCE) then WriteBuffer(hDuplicate, SizeOf(hDuplicate)); CloseHandle(hProcess); end; end; function TPipeTransport.ReadHandle(var AHandle: THandle): Int64; begin Result:= ReadBuffer(AHandle, SizeOf(AHandle)); end; procedure TPipeTransport.WriteBuffer(const AData; const ALength : Int64); var P: PByte; Len: Int64; LastError: DWORD; Overlapped: TOverlapped; dwNumberOfBytesTransferred: DWORD; begin Connect; Len := ALength; P := PByte(@AData); Repeat LastError := 0; dwNumberOfBytesTransferred:= 0; ZeroMemory(@Overlapped, SizeOf(TOverlapped)); if not WriteFile(FPipe, P^, Len, dwNumberOfBytesTransferred, @Overlapped) then LastError := GetLastError; if (LastError <> 0) and (LastError <> ERROR_IO_PENDING) then raise EInOutError.Create(SysErrorMessage(LastError)); LastError := WaitForSingleObject(FPipe, INFINITE); if LastError = WAIT_TIMEOUT then begin raise EInOutError.Create(SysErrorMessage(LastError)); end; if not GetOverlappedResult(FPipe, Overlapped, dwNumberOfBytesTransferred, False) then raise EInOutError.Create(SysErrorMessage(GetLastError)); if (dwNumberOfBytesTransferred > 0) then begin Inc(P, dwNumberOfBytesTransferred); Dec(Len, dwNumberOfBytesTransferred); end; until (Len = 0); end; function TPipeTransport.ReadBuffer(var AData; const ALength : Int64) : Int64; Var P : PByte; Len : Int64; LastError: DWORD; Overlapped: TOverlapped; dwNumberOfBytesTransferred: DWORD; begin Len := ALength; P := PByte(@AData); repeat LastError := 0; dwNumberOfBytesTransferred:= 0; ZeroMemory(@Overlapped, SizeOf(TOverlapped)); if not ReadFile(FPipe, P^, Len, dwNumberOfBytesTransferred, @Overlapped) then LastError := GetLastError; if (LastError <> 0) and (LastError <> ERROR_IO_PENDING) then raise EInOutError.Create(SysErrorMessage(LastError)); LastError := WaitForSingleObject(FPipe, INFINITE); if LastError = WAIT_TIMEOUT then raise EInOutError.Create(SysErrorMessage(LastError)); if not GetOverlappedResult(FPipe, Overlapped, dwNumberOfBytesTransferred, False) then raise EInOutError.Create(SysErrorMessage(GetLastError)); if (dwNumberOfBytesTransferred = 0) then raise EInOutError.Create(EmptyStr); if (dwNumberOfBytesTransferred > 0) then begin Inc(P, dwNumberOfBytesTransferred); Dec(Len, dwNumberOfBytesTransferred); end until (Len = 0); Result := ALength; end; constructor TPipeTransport.Create(APipe: THandle; ProcessID: UInt32); begin FPipe:= APipe; FProcessID:= ProcessID; end; constructor TPipeTransport.Create(Address: String); begin FAddress:= CeUtf8ToUtf16(Address); end; destructor TPipeTransport.Destroy; begin CloseHandle(FPipe); inherited Destroy; end; { TClientHandlerThread } constructor TClientHandlerThread.Create(APipe: THandle; AOwner: TBaseService); begin FOwner := AOwner; FreeOnTerminate := True; DCDebug('Connected success'); FTransport:= TPipeTransport.Create(APipe, FOwner.ProcessID); inherited Create(False); end; { TServerListnerThread } constructor TServerListnerThread.Create(AOwner: TBaseService); begin FEvent:= CreateEvent(nil, False, False, nil); inherited Create(AOwner); end; destructor TServerListnerThread.Destroy; begin Terminate; SetEvent(FEvent); inherited Destroy; CloseHandle(FEvent); end; procedure TServerListnerThread.Execute; var SID: TBytes; dwWait: DWORD; ACL: PACL = nil; hProcess: HANDLE; bPending: Boolean; cCount: ULONG = 1; SecondSID: TBytes; AName: UnicodeString; ReturnLength: DWORD = 0; Overlapped: TOverlapped; SA: TSecurityAttributes; SD: TSecurityDescriptor; TokenHandle: HANDLE = 0; Events: array[0..1] of THandle; hPipe: THandle = INVALID_HANDLE_VALUE; TokenInformation: array [0..1023] of Byte; ExplicitAccess: array [0..1] of TExplicitAccess; ElevationType: TTokenElevationType absolute TokenInformation; begin AName:= CeUtf8ToUtf16(FOwner.Name); if (FOwner.ProcessId > 0) then dwWait:= FOwner.ProcessId else begin dwWait:= System.GetProcessId; end; try hProcess:= OpenProcess(PROCESS_QUERY_INFORMATION, False, dwWait); if hProcess = 0 then RaiseLastOSError; ZeroMemory(@Overlapped, SizeOf(TOverlapped)); try if not OpenProcessToken(hProcess, TOKEN_QUERY, TokenHandle) then RaiseLastOSError; if not GetTokenUserSID(TokenHandle, SID) then RaiseLastOSError; ZeroMemory(@ExplicitAccess, SizeOf(ExplicitAccess)); with ExplicitAccess[0] do begin grfAccessPermissions:= GENERIC_ALL; grfAccessMode:= DWORD(SET_ACCESS); grfInheritance:= NO_INHERITANCE; Trustee.TrusteeForm:= DWORD(TRUSTEE_IS_SID); Trustee.TrusteeType:= DWORD(TRUSTEE_IS_USER); Trustee.ptstrName:= PAnsiChar(@SID[0]); end; if not GetTokenInformation(TokenHandle, TokenElevationType, @TokenInformation, SizeOf(TokenInformation), ReturnLength) then begin RaiseLastOSError; end; if ElevationType = TokenElevationTypeDefault then begin with ExplicitAccess[1] do begin grfAccessPermissions:= GENERIC_ALL; grfAccessMode:= DWORD(SET_ACCESS); grfInheritance:= NO_INHERITANCE; Trustee.TrusteeForm:= DWORD(TRUSTEE_IS_SID); end; if (FOwner.ProcessId = 0) then begin if not GetAdministratorsSID(SecondSID) then RaiseLastOSError; ExplicitAccess[1].Trustee.TrusteeType:= DWORD(TRUSTEE_IS_GROUP); end else begin if not GetProcessUserSID(GetCurrentProcess, SecondSID) then RaiseLastOSError; ExplicitAccess[1].Trustee.TrusteeType:= DWORD(TRUSTEE_IS_USER); end; ExplicitAccess[1].Trustee.ptstrName:= PAnsiChar(@SecondSID[0]); cCount:= 2; end; if SetEntriesInAcl(cCount, @ExplicitAccess[0], nil, JwaWinNT.PACL(ACL)) <> ERROR_SUCCESS then RaiseLastOSError; if not InitializeSecurityDescriptor (@SD, SECURITY_DESCRIPTOR_REVISION) then RaiseLastOSError; if not SetSecurityDescriptorDacl(@SD, True, ACL, False) then RaiseLastOSError; Overlapped.hEvent:= CreateEvent(nil, True, True, nil); Events[0]:= Overlapped.hEvent; Events[1]:= FEvent; while not Terminated do begin SA.nLength := SizeOf(SA); SA.lpSecurityDescriptor := @SD; SA.bInheritHandle := True; // Create pipe server hPipe := CreateNamedPipeW(PWideChar('\\.\pipe\' + AName), PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED, PIPE_WAIT or PIPE_READMODE_BYTE or PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, maxSmallint, maxSmallint, 0, @SA); if hPipe = INVALID_HANDLE_VALUE then RaiseLastOSError; DCDebug('Start server ', FOwner.Name); FReadyEvent.SetEvent; while not Terminated do begin bPending:= False; if not ConnectNamedPipe(hPipe, @Overlapped) then begin case (GetLastError()) of ERROR_IO_PENDING: bPending:= True; ERROR_PIPE_CONNECTED: SetEvent(Overlapped.hEvent); else begin DisconnectNamedPipe(hPipe); Continue; end; end; end; // Wait client connection dwWait := WaitForMultipleObjectsEx(Length(Events), Events, False, INFINITE, True); if (dwWait = 1) or ((dwWait = 0) and bPending and (not GetOverlappedResult(hPipe, Overlapped, dwWait, False))) then begin DisconnectNamedPipe(hPipe); Continue; end; if (FOwner.VerifyChild and not VerifyChild(hPipe)) or (FOwner.VerifyParent and not VerifyParent(hPipe)) then begin DisconnectNamedPipe(hPipe); Continue; end; Break; end; // while if not Terminated then TClientHandlerThread.Create(hPipe, FOwner) else begin DisconnectNamedPipe(hPipe); end; end; // while finally CloseHandle(hProcess); if Assigned(ACL) then LocalFree(HLOCAL(ACL)); if (TokenHandle > 0) then CloseHandle(TokenHandle); if (hPipe <> INVALID_HANDLE_VALUE) then CloseHandle(hPipe); if (Overlapped.hEvent > 0) then CloseHandle(Overlapped.hEvent); end; except on E: Exception do begin DCDebug(E.Message); if FOwner.ProcessId > 0 then Halt else Exit; end; end; end; end. ���������������doublecmd-1.1.22/src/rpc/sys/win/unamedpipes.pas����������������������������������������������������0000644�0001750�0000144�00000005571�14743153644�020623� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uNamedPipes; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type PTrustee = ^TTrustee; TTrustee = record pMultipleTrustee: PTrustee; MultipleTrusteeOperation: DWORD; TrusteeForm: DWORD; TrusteeType: DWORD; ptstrName: PAnsiChar; end; TExplicitAccess = record grfAccessPermissions: DWORD; grfAccessMode: DWORD; grfInheritance: DWORD; Trustee: TTrustee; end; function VerifyChild(hPipe: THandle): Boolean; function VerifyParent(hPipe: THandle): Boolean; function GetAdministratorsSID(out SID: TBytes): Boolean; implementation uses Windows, uProcessInfo, uDebug; var GetNamedPipeClientProcessId: function(Pipe: HANDLE; ClientProcessId: PULONG): BOOL; stdcall; function VerifyChild(hPipe: HANDLE): Boolean; var ClientProcessId: ULONG; begin if GetNamedPipeClientProcessId(hPipe, @ClientProcessId) then begin // Allow to connect from child process and same executable only if GetCurrentProcessId = GetParentProcessId(ClientProcessId) then begin DCDebug('My: ', GetProcessFileName(GetCurrentProcess)); DCDebug('Client: ', GetProcessFileNameEx(ClientProcessId)); if UnicodeSameText(GetProcessFileName(GetCurrentProcess), GetProcessFileNameEx(ClientProcessId)) then Exit(True); end; end; Result:= False; end; function VerifyParent(hPipe: HANDLE): Boolean; var ClientProcessId: ULONG; begin if GetNamedPipeClientProcessId(hPipe, @ClientProcessId) then begin // Allow to connect from parent process and same executable only if ClientProcessId = GetParentProcessId(GetCurrentProcessId) then begin DCDebug('My: ', GetProcessFileName(GetCurrentProcess)); DCDebug('Client: ', GetProcessFileNameEx(ClientProcessId)); if UnicodeSameText(GetProcessFileName(GetCurrentProcess), GetProcessFileNameEx(ClientProcessId)) then Exit(True); end; end; Result:= False; end; function GetAdministratorsSID(out SID: TBytes): Boolean; const SECURITY_NT_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5)); var AdministratorsGroup: PSID = nil; begin Result:= AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, AdministratorsGroup); if Result then begin SetLength(SID, GetLengthSid(AdministratorsGroup)); CopySid(Length(SID), PSID(@SID[0]), AdministratorsGroup); FreeSid(AdministratorsGroup); end; end; initialization Pointer(GetNamedPipeClientProcessId):= GetProcAddress(GetModuleHandleW(kernel32), 'GetNamedPipeClientProcessId'); end. ���������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/sys/win/uprocessinfo.pas���������������������������������������������������0000644�0001750�0000144�00000005342�14743153644�021024� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uProcessInfo; {$mode objfpc}{$H+} interface uses Classes, SysUtils, JwaWinNT, Windows; function GetParentProcessId(ProcessId: DWORD): DWORD; function GetProcessFileName(hProcess: HANDLE): UnicodeString; function GetProcessFileNameEx(ProcessId: DWORD): UnicodeString; function GetTokenUserSID(hToken: HANDLE; out SID: TBytes): Boolean; function GetProcessUserSID(hProcess: HANDLE; out SID: TBytes): Boolean; implementation uses JwaTlHelp32; var GetProcessImageFileNameW: function(hProcess: HANDLE; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall; function GetParentProcessId(ProcessId: DWORD): DWORD; var hSnapshot : THandle; ProcessEntry : TProcessEntry32; begin Result := 0; hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if hSnapshot <> INVALID_HANDLE_VALUE then begin ProcessEntry.dwSize := SizeOf(TProcessEntry32); if Process32First(hSnapshot, ProcessEntry) then begin repeat if ProcessEntry.th32ProcessID = ProcessId then begin Result:= ProcessEntry.th32ParentProcessID; Break; end; until not Process32Next(hSnapshot, ProcessEntry); end; CloseHandle(hSnapshot); end; end; function GetProcessFileName(hProcess: HANDLE): UnicodeString; begin SetLength(Result, maxSmallint + 1); SetLength(Result, GetProcessImageFileNameW(hProcess, PWideChar(Result), maxSmallint)); end; function GetProcessFileNameEx(ProcessId: DWORD): UnicodeString; const PROCESS_QUERY_LIMITED_INFORMATION = $1000; var hProcess: HANDLE; begin Result:= EmptyWideStr; hProcess:= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, ProcessId); if hProcess <> 0 then try Result:= GetProcessFileName(hProcess); finally CloseHandle(hProcess); end; end; function GetTokenUserSID(hToken: HANDLE; out SID: TBytes): Boolean; var ReturnLength: DWORD = 0; TokenInformation: array [0..SECURITY_MAX_SID_SIZE] of Byte; UserToken: TTokenUser absolute TokenInformation; begin Result:= GetTokenInformation(hToken, TokenUser, @TokenInformation, SizeOf(TokenInformation), ReturnLength); if Result then begin SetLength(SID, GetLengthSid(UserToken.User.Sid)); CopySid(Length(SID), PSID(@SID[0]), UserToken.User.Sid); end; end; function GetProcessUserSID(hProcess: HANDLE; out SID: TBytes): Boolean; var hToken: HANDLE = 0; begin Result:= OpenProcessToken(hProcess, TOKEN_QUERY, hToken); if Result then begin Result:= GetTokenUserSID(hToken, SID); CloseHandle(hToken); end; end; initialization Pointer(GetProcessImageFileNameW):= GetProcAddress(GetModuleHandle('psapi.dll'), 'GetProcessImageFileNameW'); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/uadministrator.pas���������������������������������������������������������0000644�0001750�0000144�00000035470�14743153644�017744� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uAdministrator; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes, DCClassesUtf8, DCOSUtils, uFindEx, uFileCopyEx; procedure PushPop(var Elevate: TDuplicates); function FileExistsUAC(const FileName: String): Boolean; function FileGetAttrUAC(const FileName: String; FollowLink: Boolean = False): TFileAttrs; function FileGetAttrUAC(const FileName: String; out Attr: TFileAttributeData): Boolean; function FileSetAttrUAC(const FileName: String; Attr: TFileAttrs): Boolean; function FileSetTimeUAC(const FileName: String; ModificationTime: TFileTimeEx; CreationTime: TFileTimeEx; LastAccessTime: TFileTimeEx): LongBool; function FileSetReadOnlyUAC(const FileName: String; ReadOnly: Boolean): Boolean; function FileCopyAttrUAC(const sSrc, sDst: String; Options: TCopyAttributesOptions): TCopyAttributesOptions; function FileOpenUAC(const FileName: String; Mode: LongWord): System.THandle; function FileCreateUAC(const FileName: String; Mode: LongWord): System.THandle; function FileCopyUAC(const Source, Target: String; Options: UInt32; UpdateProgress: TFileCopyProgress; UserData: Pointer): Boolean; function DeleteFileUAC(const FileName: String): LongBool; function RenameFileUAC(const OldName, NewName: String): LongBool; function FindFirstUAC(const Path: String; Flags: UInt32; out SearchRec: TSearchRecEx): Integer; function FindNextUAC(var SearchRec: TSearchRecEx): Integer; procedure FindCloseUAC(var SearchRec: TSearchRecEx); function ForceDirectoriesUAC(const Path: String): Boolean; function CreateDirectoryUAC(const Directory: String): Boolean; function RemoveDirectoryUAC(const Directory: String): Boolean; function DirectoryExistsUAC(const Directory : String): Boolean; function CreateSymbolicLinkUAC(const Path, LinkName: String) : Boolean; function CreateHardLinkUAC(const Path, LinkName: String) : Boolean; type { TFileStreamUAC class } TFileStreamUAC = class(TFileStreamEx) public constructor Create(const AFileName: String; Mode: LongWord); override; end; { TStringListUAC } TStringListUAC = class(TStringListEx) public procedure LoadFromFile(const FileName: String); override; procedure SaveToFile(const FileName: String); override; end; threadvar ElevateAction: TDuplicates; implementation uses RtlConsts, DCStrUtils, LCLType, uShowMsg, uElevation, uSuperUser, fElevation; resourcestring rsElevationRequired = 'You need to provide administrator permission'; rsElevationRequiredDelete = 'to delete this object:'; rsElevationRequiredOpen = 'to open this object:'; rsElevationRequiredCopy = 'to copy this object:'; rsElevationRequiredCreate = 'to create this object:'; rsElevationRequiredRename = 'to rename this object:'; rsElevationRequiredHardLink = 'to create this hard link:'; rsElevationRequiredSymLink = 'to create this symbolic link:'; rsElevationRequiredGetAttributes = 'to get attributes of this object:'; rsElevationRequiredSetAttributes = 'to set attributes of this object:'; procedure PushPop(var Elevate: TDuplicates); var AValue: TDuplicates; begin AValue:= ElevateAction; ElevateAction:= Elevate; Elevate:= AValue; end; function RequestElevation(const Message, FileName: String): Boolean; var Text: String; begin case ElevateAction of dupAccept: Exit(True); dupError: Exit(False); end; Text:= rsElevationRequired + LineEnding; Text += Message + LineEnding + FileName; case ShowElevation(mbSysErrorMessage, Text) of mmrOK: Result:= True; mmrSkip: Result:= False; mmrSkipAll: begin Result:= False; ElevateAction:= dupError; end; mmrAll: begin Result:= True; ElevateAction:= dupAccept; end; end; end; function FileExistsUAC(const FileName: String): Boolean; var LastError: Integer; begin Result:= mbFileExists(FileName); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredGetAttributes, FileName) then Result:= TWorkerProxy.Instance.FileExists(FileName) else SetLastOSError(LastError); end; end; function FileGetAttrUAC(const FileName: String; FollowLink: Boolean): TFileAttrs; var LastError: Integer; begin if not FollowLink then Result:= mbFileGetAttr(FileName) else begin Result:= mbFileGetAttrNoLinks(FileName); end; if (Result = faInvalidAttributes) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredGetAttributes, FileName) then Result:= TWorkerProxy.Instance.FileGetAttr(FileName, FollowLink) else SetLastOSError(LastError); end; end; function FileGetAttrUAC(const FileName: String; out Attr: TFileAttributeData): Boolean; var LastError: Integer; begin Result:= mbFileGetAttr(FileName, Attr); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredGetAttributes, FileName) then Result:= TWorkerProxy.Instance.FileGetAttr(FileName, Attr) else SetLastOSError(LastError); end; end; function FileSetAttrUAC(const FileName: String; Attr: TFileAttrs): Boolean; var LastError: Integer; begin Result:= mbFileSetAttr(FileName, Attr); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredSetAttributes, FileName) then Result:= TWorkerProxy.Instance.FileSetAttr(FileName, Attr) else SetLastOSError(LastError); end; end; function FileSetTimeUAC(const FileName: String; ModificationTime: DCBasicTypes.TFileTimeEx; CreationTime : DCBasicTypes.TFileTimeEx; LastAccessTime : DCBasicTypes.TFileTimeEx): LongBool; var LastError: Integer; begin Result:= mbFileSetTimeEx(FileName, ModificationTime, CreationTime, LastAccessTime); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredSetAttributes, FileName) then Result:= TWorkerProxy.Instance.FileSetTime(FileName, ModificationTime, CreationTime, LastAccessTime) else SetLastOSError(LastError); end; end; function FileSetReadOnlyUAC(const FileName: String; ReadOnly: Boolean): Boolean; var LastError: Integer; begin Result:= mbFileSetReadOnly(FileName, ReadOnly); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredSetAttributes, FileName) then Result:= TWorkerProxy.Instance.FileSetReadOnly(FileName, ReadOnly) else SetLastOSError(LastError); end; end; function FileCopyAttrUAC(const sSrc, sDst: String; Options: TCopyAttributesOptions): TCopyAttributesOptions; var Option: TCopyAttributesOption; Errors: TCopyAttributesResult; begin Result:= mbFileCopyAttr(sSrc, sDst, Options, @Errors); if (Result <> []) then begin for Option in Result do begin if ElevationRequired(Errors[Option]) then begin if RequestElevation(rsElevationRequiredSetAttributes, sDst) then Result:= TWorkerProxy.Instance.FileCopyAttr(sSrc, sDst, Result) else SetLastOSError(Errors[Option]); Break; end; end; end; end; function FileOpenUAC(const FileName: String; Mode: LongWord): System.THandle; var LastError: Integer; begin Result:= mbFileOpen(FileName, Mode); if (Result = feInvalidHandle) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredOpen, FileName) then Result:= TWorkerProxy.Instance.FileOpen(FileName, Mode) else SetLastOSError(LastError); end; end; function FileCreateUAC(const FileName: String; Mode: LongWord): System.THandle; var LastError: Integer; begin Result:= mbFileCreate(FileName, Mode); if (Result = feInvalidHandle) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredCreate, FileName) then Result:= TWorkerProxy.Instance.FileCreate(FileName, Mode) else SetLastOSError(LastError); end; end; function FileCopyUAC(const Source, Target: String; Options: UInt32; UpdateProgress: TFileCopyProgress; UserData: Pointer): Boolean; var LastError: Integer; begin Result:= FileCopyEx(Source, Target, Options, UpdateProgress, UserData); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredCopy, Source) then Result:= TWorkerProxy.Instance.FileCopy(Source, Target, Options, UpdateProgress, UserData) else SetLastOSError(LastError); end; end; function DeleteFileUAC(const FileName: String): LongBool; var LastError: Integer; begin Result:= mbDeleteFile(FileName); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredDelete, FileName) then Result:= TWorkerProxy.Instance.DeleteFile(FileName) else SetLastOSError(LastError); end; end; function RenameFileUAC(const OldName, NewName: String): LongBool; var LastError: Integer; begin Result:= mbRenameFile(OldName, NewName); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredRename, OldName) then Result:= TWorkerProxy.Instance.RenameFile(OldName, NewName) else SetLastOSError(LastError); end; end; function CreateDirectoryUAC(const Directory: String): Boolean; var LastError: Integer; begin Result:= mbCreateDir(Directory); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredCreate, Directory) then Result:= TWorkerProxy.Instance.CreateDirectory(Directory) else SetLastOSError(LastError); end; end; function RemoveDirectoryUAC(const Directory: String): Boolean; var LastError: Integer; begin Result:= mbRemoveDir(Directory); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredDelete, Directory) then Result:= TWorkerProxy.Instance.RemoveDirectory(Directory) else SetLastOSError(LastError); end; end; function DirectoryExistsUAC(const Directory: String): Boolean; var LastError: Integer; begin Result:= mbDirectoryExists(Directory); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredGetAttributes, Directory) then Result:= TWorkerProxy.Instance.DirectoryExists(Directory) else SetLastOSError(LastError); end; end; function CreateHardLinkUAC(const Path, LinkName: String): Boolean; var LastError: Integer; begin Result:= CreateHardLink(Path, LinkName); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredHardLink, LinkName) then Result:= TWorkerProxy.Instance.CreateHardLink(Path, LinkName) else SetLastOSError(LastError); end; end; function CreateSymbolicLinkUAC(const Path, LinkName: String): Boolean; var LastError: Integer; begin Result:= CreateSymLink(Path, LinkName); if (not Result) and ElevationRequired then begin LastError:= GetLastOSError; if RequestElevation(rsElevationRequiredSymLink, LinkName) then Result:= TWorkerProxy.Instance.CreateSymbolicLink(Path, LinkName) else SetLastOSError(LastError); end; end; function FindFirstUAC(const Path: String; Flags: UInt32; out SearchRec: TSearchRecEx): Integer; begin Result:= FindFirstEx(Path, Flags, SearchRec); if (Result <> 0) and ElevationRequired(Result) then begin if RequestElevation(rsElevationRequiredOpen, Path) then begin SearchRec.Flags:= SearchRec.Flags or fffElevated; Result:= TWorkerProxy.Instance.FindFirst(Path, Flags, SearchRec) end; end; end; function FindNextUAC(var SearchRec: TSearchRecEx): Integer; begin if (SearchRec.Flags and fffElevated <> 0) then Result:= TWorkerProxy.Instance.FindNext(SearchRec) else Result:= FindNextEx(SearchRec); end; procedure FindCloseUAC(var SearchRec: TSearchRecEx); begin if (SearchRec.Flags and fffElevated <> 0) then TWorkerProxy.Instance.FindClose(SearchRec) else FindCloseEx(SearchRec); end; function ForceDirectoriesUAC(const Path: String): Boolean; var Index: Integer; ADirectory: String; ADirectoryPath: String; begin if Path = '' then Exit; ADirectoryPath := IncludeTrailingPathDelimiter(Path); Index:= 1; if Pos('\\', ADirectoryPath) = 1 then // if network path begin Index := CharPos(PathDelim, ADirectoryPath, 3); // index of the end of computer name Index := CharPos(PathDelim, ADirectoryPath, Index + 1); // index of the end of first remote directory end; // Move past path delimiter at the beginning. if (Index = 1) and (ADirectoryPath[Index] = PathDelim) then Index := Index + 1; while Index <= Length(ADirectoryPath) do begin if ADirectoryPath[Index] = PathDelim then begin ADirectory:= Copy(ADirectoryPath, 1, Index - 1); if not DirectoryExistsUAC(ADirectory) then begin Result:= CreateDirectoryUAC(ADirectory); if not Result then Exit; end; end; Inc(Index); end; Result := True; end; { TFileStreamUAC } constructor TFileStreamUAC.Create(const AFileName: String; Mode: LongWord); var AHandle: System.THandle; begin if (Mode and fmCreate) <> 0 then begin AHandle:= FileCreateUAC(AFileName, Mode); if AHandle = feInvalidHandle then raise EFCreateError.CreateFmt(SFCreateError, [AFileName]) else inherited Create(AHandle); end else begin AHandle:= FileOpenUAC(AFileName, Mode); if AHandle = feInvalidHandle then raise EFOpenError.CreateFmt(SFOpenError, [AFilename]) else inherited Create(AHandle); end; FFileName:= AFileName; end; { TStringListUAC } procedure TStringListUAC.LoadFromFile(const FileName: String); var fsFileStream: TFileStreamUAC; begin fsFileStream:= TFileStreamUAC.Create(FileName, fmOpenRead or fmShareDenyNone); try LoadFromStream(fsFileStream); finally fsFileStream.Free; end; end; procedure TStringListUAC.SaveToFile(const FileName: String); var fsFileStream: TFileStreamUAC; begin fsFileStream:= TFileStreamUAC.Create(FileName, fmCreate); try SaveToStream(fsFileStream); finally fsFileStream.Free; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/uelevation.pas�������������������������������������������������������������0000644�0001750�0000144�00000053252�14743153644�017050� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uElevation; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes, DCOSUtils, uClientServer, uService, uWorker, uFindEx, uFileCopyEx; type { TMasterProxy } TMasterProxy = class private FClient: TBaseTransport; public function Execute: LongBool; public constructor Create(const AName: String); destructor Destroy; override; class function Instance: TMasterProxy; end; { TWorkerProxy } TWorkerProxy = class private FClient: TBaseTransport; procedure ReadSearchRec(Data: TMemoryStream; var SearchRec: TSearchRecEx); function ProcessObject(ACommand: UInt32; const ObjectName: String): LongBool; function ProcessObject(ACommand: UInt32; const OldName, NewName: String): LongBool; function ProcessObject(ACommand: UInt32; const ObjectName: String; Attr: UInt32): LongBool; function ProcessObject(ACommand: UInt32; const ObjectName: String; Mode: Integer): THandle; public function Terminate: Boolean; function FileExists(const FileName: String): LongBool; inline; function FileGetAttr(const FileName: String; FollowLink: LongBool): TFileAttrs; inline; function FileGetAttr(const FileName: String; out Attr: TFileAttributeData): LongBool; function FileSetAttr(const FileName: String; Attr: TFileAttrs): LongBool; inline; function FileSetTime(const FileName: String; ModificationTime: TFileTimeEx; CreationTime: TFileTimeEx; LastAccessTime: TFileTimeEx): LongBool; function FileSetReadOnly(const FileName: String; ReadOnly: Boolean): LongBool; inline; function FileCopyAttr(const sSrc, sDst: String; Options: TCopyAttributesOptions): TCopyAttributesOptions; function FileOpen(const FileName: String; Mode: Integer): THandle; inline; function FileCreate(const FileName: String; Mode: Integer): THandle; inline; function FileCopy(const Source, Target: String; Options: UInt32; UpdateProgress: TFileCopyProgress; UserData: Pointer): LongBool; function DeleteFile(const FileName: String): LongBool; inline; function RenameFile(const OldName, NewName: String): LongBool; inline; function FindFirst(const Path: String; Flags: UInt32; out SearchRec: TSearchRecEx): Integer; function FindNext(var SearchRec: TSearchRecEx): Integer; procedure FindClose(var SearchRec: TSearchRecEx); function CreateHardLink(const Path, LinkName: String): LongBool; inline; function CreateSymbolicLink(const Path, LinkName: String): LongBool; inline; function CreateDirectory(const Directory: String): LongBool; inline; function RemoveDirectory(const Directory: String): LongBool; inline; function DirectoryExists(const Directory: String): LongBool; inline; public constructor Create; destructor Destroy; override; class function Instance: TWorkerProxy; end; procedure StartMasterServer; procedure StartWorkerServer(const AName: String); procedure CreateWorkerProxy(); procedure CreateMasterProxy(const AName: String); var MasterService: TMasterService = nil; WorkerService: TWorkerService = nil; implementation uses SyncObjs, LazUtf8, uSuperUser, uDebug; const MasterAddress = 'doublecmd-master-'; WorkerAddress = 'doublecmd-worker-'; var MasterProxy: TMasterProxy = nil; WorkerProxy: TWorkerProxy = nil; procedure StartMasterServer; var Address: String; begin Address:= MasterAddress + IntToStr(GetProcessID); MasterService := TMasterService.Create(Address); MasterService.Start; end; procedure StartWorkerServer(const AName: String); var Address: String; begin Address:= WorkerAddress + AName; WorkerService := TWorkerService.Create(Address); WorkerService.ProcessID:= StrToDWord(AName); WorkerService.Start; end; procedure CreateMasterProxy(const AName: String); begin MasterProxy:= TMasterProxy.Create(AName); if not MasterProxy.Execute then WorkerService.Event.SetEvent; end; procedure CreateWorkerProxy; begin WorkerProxy:= TWorkerProxy.Create; end; var Mutex: TRTLCriticalSection; WorkerProcess: UIntPtr = 0; function WaitProcessThread({%H-}Parameter: Pointer): PtrInt; begin Result:= 0; WaitProcess(WorkerProcess); WorkerProcess:= 0; MasterService.Event.SetEvent; EndThread(Result); end; function ElevateSelf: Boolean; begin WorkerProcess:= ExecCmdAdmin(ParamStrUtf8(0), ['--service', IntToStr(GetProcessID)]); Result := (WorkerProcess > 0); if Result then BeginThread(@WaitProcessThread); end; { TMasterProxy } function TMasterProxy.Execute: LongBool; var Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(UInt32(RPC_Execute)); Stream.WriteDWord(SizeOf(SizeUInt)); // Write process identifier Stream.WriteBuffer(GetProcessID, SizeOf(SizeUInt)); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; constructor TMasterProxy.Create(const AName: String); begin FClient:= TPipeTransport.Create(MasterAddress + AName); end; destructor TMasterProxy.Destroy; begin inherited Destroy; FClient.Free; end; class function TMasterProxy.Instance: TMasterProxy; begin Result:= MasterProxy; end; { TWorkerProxy } procedure TWorkerProxy.ReadSearchRec(Data: TMemoryStream; var SearchRec: TSearchRecEx); begin Data.ReadBuffer((@SearchRec.PlatformTime)^, SizeOf(SearchRec.PlatformTime)); Data.ReadBuffer((@SearchRec.LastAccessTime)^, SizeOf(SearchRec.LastAccessTime)); Data.ReadBuffer(SearchRec.Time, SizeOf(TFileTime)); Data.ReadBuffer(SearchRec.Size, SizeOf(Int64)); Data.ReadBuffer(SearchRec.Attr, SizeOf(TFileAttrs)); SearchRec.Name:= Data.ReadAnsiString; end; function TWorkerProxy.ProcessObject(ACommand: UInt32; const ObjectName: String): LongBool; var LastError: Integer; Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(ACommand); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(ObjectName); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.ProcessObject(ACommand: UInt32; const OldName, NewName: String): LongBool; var LastError: Integer; Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(ACommand); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(OldName); Stream.WriteAnsiString(NewName); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.ProcessObject(ACommand: UInt32; const ObjectName: String; Attr: UInt32): LongBool; var LastError: Integer; Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(ACommand); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(ObjectName); Stream.WriteDWord(Attr); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.ProcessObject(ACommand: UInt32; const ObjectName: String; Mode: Integer): THandle; var LastError: Integer; Stream: TMemoryStream; begin Result:= feInvalidHandle; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(ACommand); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(ObjectName); Stream.WriteDWord(Mode); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(LastError, SizeOf(LastError)); if (LastError = 0) then FClient.ReadHandle(Result) else begin SetLastOSError(LastError); end; finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.Terminate: Boolean; var Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_Terminate); Stream.WriteDWord(SizeOf(SizeUInt)); // Write process identifier Stream.WriteBuffer(GetProcessID, SizeOf(SizeUInt)); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.FileExists(const FileName: String): LongBool; begin Result:= ProcessObject(RPC_FileExists, FileName); end; function TWorkerProxy.FileGetAttr(const FileName: String; FollowLink: LongBool): TFileAttrs; begin Result:= TFileAttrs(ProcessObject(RPC_FileGetAttr, FileName, UInt32(FollowLink))); end; function TWorkerProxy.FileGetAttr(const FileName: String; out Attr: TFileAttributeData): LongBool; var LastError: Integer; Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FileGetAttr); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(FileName); Stream.WriteDWord(maxSmallint); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); FClient.ReadBuffer(Attr, SizeOf(TFileAttributeData)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.FileSetAttr(const FileName: String; Attr: TFileAttrs): LongBool; begin Result:= ProcessObject(RPC_FileSetAttr, FileName, Attr); end; function TWorkerProxy.FileSetTime(const FileName: String; ModificationTime: TFileTimeEx; CreationTime: TFileTimeEx; LastAccessTime: TFileTimeEx): LongBool; var LastError: Integer; Stream: TMemoryStream; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FileSetTime); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(FileName); Stream.WriteBuffer(ModificationTime, SizeOf(TFileTimeEx)); Stream.WriteBuffer(CreationTime, SizeOf(TFileTimeEx)); Stream.WriteBuffer(LastAccessTime, SizeOf(TFileTimeEx)); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.FileSetReadOnly(const FileName: String; ReadOnly: Boolean): LongBool; begin Result:= ProcessObject(RPC_FileSetReadOnly, FileName, UInt32(ReadOnly)); end; function TWorkerProxy.FileCopyAttr(const sSrc, sDst: String; Options: TCopyAttributesOptions): TCopyAttributesOptions; var LastError: Integer; Stream: TMemoryStream; begin Result:= Options; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FileCopyAttr); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(sSrc); Stream.WriteAnsiString(sDst); Stream.WriteDWord(UInt32(Options)); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.FileOpen(const FileName: String; Mode: Integer): THandle; begin Result:= ProcessObject(RPC_FileOpen, FileName, Mode); end; function TWorkerProxy.FileCreate(const FileName: String; Mode: Integer): THandle; begin Result:= ProcessObject(RPC_FileCreate, FileName, Mode); end; function TWorkerProxy.FileCopy(const Source, Target: String; Options: UInt32; UpdateProgress: TFileCopyProgress; UserData: Pointer): LongBool; var LastError: Integer; Stream: TMemoryStream; TotalBytes, DoneBytes: Int64; begin Result:= False; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FileCopy); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(Source); Stream.WriteAnsiString(Target); Stream.WriteBuffer(Options, SizeOf(Options)); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); repeat FClient.ReadBuffer(LastError, SizeOf(LastError)); // Receive progress info if (LastError = 1) then begin FClient.ReadBuffer(TotalBytes, SizeOf(TotalBytes)); FClient.ReadBuffer(DoneBytes, SizeOf(DoneBytes)); Result:= UpdateProgress(TotalBytes, DoneBytes, UserData); FClient.WriteBuffer(Result, SizeOf(Result)); end; until (LastError <> 1); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(LastError, SizeOf(LastError)); SetLastOSError(LastError); finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.DeleteFile(const FileName: String): LongBool; begin Result:= ProcessObject(RPC_DeleteFile, FileName); end; function TWorkerProxy.RenameFile(const OldName, NewName: String): LongBool; begin Result:= ProcessObject(RPC_RenameFile, OldName, NewName); end; function TWorkerProxy.FindFirst(const Path: String; Flags: UInt32; out SearchRec: TSearchRecEx): Integer; var ASize: UInt32 = 0; Stream: TMemoryStream; Data: TMemoryStream absolute SearchRec.FindHandle; begin Result:= -1; try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FindFirst); Stream.Seek(SizeOf(UInt32), soFromCurrent); // Write arguments Stream.WriteAnsiString(Path); Stream.WriteDWord(Flags); // Write data size Stream.Seek(SizeOf(UInt32), soFromBeginning); Stream.WriteDWord(Stream.Size - SizeOf(UInt32) * 2); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(ASize, SizeOf(ASize)); if ASize > 0 then begin Data:= TMemoryStream.Create; Data.Size:= ASize; FClient.ReadBuffer(Data.Memory^, ASize); Data.Seek(SizeOf(Pointer), soBeginning); ReadSearchRec(Data, SearchRec); end; finally Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.FindNext(var SearchRec: TSearchRecEx): Integer; var ASize: UInt32 = 0; Stream: TMemoryStream; Data: TMemoryStream absolute SearchRec.FindHandle; begin Result:= -1; try if Data.Position < Data.Size then begin Result:= 0; ReadSearchRec(Data, SearchRec); end else begin Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FindNext); Stream.WriteDWord(SizeOf(Pointer)); // Write arguments Stream.WriteBuffer(Data.Memory^, SizeOf(Pointer)); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); // Receive command result FClient.ReadBuffer(Result, SizeOf(Result)); FClient.ReadBuffer(ASize, SizeOf(ASize)); if ASize > 0 then begin Data.Size:= ASize; FClient.ReadBuffer(Data.Memory^, ASize); Data.Seek(SizeOf(Pointer), soBeginning); ReadSearchRec(Data, SearchRec); end; finally Stream.Free; end; end; except on E: Exception do DCDebug(E.Message); end; end; procedure TWorkerProxy.FindClose(var SearchRec: TSearchRecEx); var Stream: TMemoryStream; Data: TMemoryStream absolute SearchRec.FindHandle; begin try Stream:= TMemoryStream.Create; try // Write header Stream.WriteDWord(RPC_FindClose); Stream.WriteDWord(SizeOf(Pointer)); // Write arguments Stream.WriteBuffer(Data.Memory^, SizeOf(Pointer)); // Send command FClient.WriteBuffer(Stream.Memory^, Stream.Size); finally Data.Free; Stream.Free; end; except on E: Exception do DCDebug(E.Message); end; end; function TWorkerProxy.CreateHardLink(const Path, LinkName: String): LongBool; begin Result:= ProcessObject(RPC_CreateHardLink, Path, LinkName); end; function TWorkerProxy.CreateSymbolicLink(const Path, LinkName: String): LongBool; begin Result:= ProcessObject(RPC_CreateSymbolicLink, Path, LinkName); end; function TWorkerProxy.CreateDirectory(const Directory: String): LongBool; begin Result:= ProcessObject(RPC_CreateDirectory, Directory); end; function TWorkerProxy.RemoveDirectory(const Directory: String): LongBool; begin Result:= ProcessObject(RPC_RemoveDirectory, Directory); end; function TWorkerProxy.DirectoryExists(const Directory: String): LongBool; begin Result:= ProcessObject(RPC_DirectoryExists, Directory); end; constructor TWorkerProxy.Create; begin FClient:= TPipeTransport.Create(WorkerAddress + IntToStr(GetProcessID)); end; destructor TWorkerProxy.Destroy; begin DCDebug('TWorkerProxy.Destroy'); inherited Destroy; FClient.Free; end; class function TWorkerProxy.Instance: TWorkerProxy; var AProxy: PPointer; AThread: TThread; begin if GetCurrentThreadId = MainThreadID then Result:= WorkerProxy else begin AThread:= TThread.CurrentThread; AProxy:= @AThread.FatalException; if (AProxy^ = nil) then begin AProxy^:= TWorkerProxy.Create; end; Result:= TWorkerProxy(AProxy^); end; EnterCriticalSection(Mutex); try if MasterService.ClientCount = 0 then begin MasterService.Event.ResetEvent; if ElevateSelf then begin MasterService.Event.WaitFor(60000); end; Result.FClient.Disconnect; end; finally LeaveCriticalSection(Mutex); end; end; procedure Initialize; begin if ParamCount > 0 then begin if ParamStr(1) = '--service' then begin DCDebug('Start worker server'); StartWorkerServer(ParamStr(2)); CreateMasterProxy(ParamStr(2)); WorkerService.Event.WaitFor(INFINITE); WorkerService.Free; Halt; end; end; if not AdministratorPrivileges then begin InitCriticalSection(Mutex); StartMasterServer; CreateWorkerProxy; end; end; procedure Finalize; begin if WorkerProcess > 0 then begin WorkerProxy.Terminate; end; if Assigned(MasterService) then begin DoneCriticalSection(Mutex); MasterService.Free; end; end; initialization Initialize; finalization Finalize; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/uservice.pas���������������������������������������������������������������0000644�0001750�0000144�00000010227�14743153644�016515� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uService; {$mode objfpc}{$H+} interface uses Classes, SysUtils, SyncObjs; type { TBaseTransport } TBaseTransport = class public procedure Disconnect; virtual; abstract; procedure WriteHandle(AHandle: THandle); virtual; abstract; function ReadHandle(var AHandle: THandle) : Int64; virtual; abstract; procedure WriteBuffer(const AData; const ALength : Int64); virtual; abstract; function ReadBuffer(var AData; const ALength : Int64) : Int64; virtual; abstract; end; { TBaseService } TBaseService = class protected FName: String; FEvent: TEvent; FProcessId: UInt32; FVerifyChild: Boolean; FVerifyParent: Boolean; FServerThread: TThread; protected procedure ProcessRequest(ATransport: TBaseTransport; ACommand: Int32; ARequest: TStream); virtual; abstract; public constructor Create(const AName: String); virtual; destructor Destroy; override; procedure Start; public ClientCount: Integer; property Name: String read FName; property Event: TEvent read FEvent; property ProcessId: UInt32 read FProcessId write FProcessId; property VerifyChild: Boolean read FVerifyChild write FVerifyChild; property VerifyParent: Boolean read FVerifyParent write FVerifyParent; end; { TClientThread } TClientThread = class(TThread) protected FOwner : TBaseService; FTransport: TBaseTransport; protected function ReadRequest(ARequest : TMemoryStream; var ACommand : LongInt): Integer; procedure SendResponse(AResponse : TMemoryStream); public procedure Execute; override; destructor Destroy; override; end; { TServerThread } TServerThread = class(TThread) protected FReadyEvent: TEvent; FOwner : TBaseService; public constructor Create(AOwner : TBaseService); virtual; destructor Destroy; override; end; implementation uses uClientServer, uDebug; { TServerThread } constructor TServerThread.Create(AOwner: TBaseService); begin FOwner := AOwner; FReadyEvent:= TSimpleEvent.Create; inherited Create(False); end; destructor TServerThread.Destroy; begin inherited Destroy; FReadyEvent.Free; end; { TBaseService } constructor TBaseService.Create(const AName: String); begin FName:= AName; FEvent:= TEvent.Create(nil, False, False, ''); end; destructor TBaseService.Destroy; begin if (FServerThread <> nil) then begin FServerThread.Terminate; FServerThread.Free; end; FEvent.Free; inherited Destroy; end; procedure TBaseService.Start; begin FServerThread:= TServerListnerThread.Create(Self); TServerThread(FServerThread).FReadyEvent.WaitFor(30000); end; { TClientThread } function TClientThread.ReadRequest(ARequest: TMemoryStream; var ACommand: LongInt): Integer; var R: Int64; ALength : Int32 = 0; begin // Read command R:= FTransport.ReadBuffer(ACommand, SizeOf(ACommand)); if (R = 0) then Exit(0); // Read arguments size R:= FTransport.ReadBuffer(ALength, SizeOf(ALength)); if (R = 0) then Exit(0); // Read arguments if (ALength > 0) then begin ARequest.Size:= ALength; Result:= FTransport.ReadBuffer(ARequest.Memory^, ALength); end; end; procedure TClientThread.SendResponse(AResponse: TMemoryStream); begin FTransport.WriteBuffer(AResponse.Memory^, AResponse.Size); end; procedure TClientThread.Execute; var ACommand : Int32 = 0; ARequest : TMemoryStream; begin InterLockedIncrement(FOwner.ClientCount); while not Terminated do begin try ARequest:= TMemoryStream.Create; try if ReadRequest(ARequest, ACommand) >= SizeOf(Int32) then begin FOwner.ProcessRequest(FTransport, ACommand, ARequest); end; finally ARequest.Free; end; except on E: Exception do begin Terminate; DCDebug(E.Message); end; end; end; InterLockedDecrement(FOwner.ClientCount); end; destructor TClientThread.Destroy; begin FTransport.Free; inherited Destroy; DCDebug('TClientThread.Destroy'); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/rpc/uworker.pas����������������������������������������������������������������0000644�0001750�0000144�00000026430�14743153644�016371� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uWorker; {$mode objfpc}{$H+} interface uses Classes, SysUtils, SyncObjs, uService; const RPC_Execute = 1; type { TMasterService } TMasterService = class(TBaseService) public constructor Create(const AName: String); override; procedure ProcessRequest(ATransport: TBaseTransport; ACommand: Int32; ARequest: TStream); override; end; const RPC_Terminate = 0; RPC_FileOpen = 1; RPC_FileCreate = 2; RPC_DeleteFile = 3; RPC_RenameFile = 4; RPC_FileExists = 9; RPC_FileGetAttr = 10; RPC_FileSetAttr = 11; RPC_FileSetTime = 12; RPC_FileSetReadOnly = 14; RPC_FileCopyAttr = 15; RPC_FileCopy = 19; RPC_FindFirst = 16; RPC_FindNext = 17; RPC_FindClose = 18; RPC_CreateHardLink = 8; RPC_CreateSymbolicLink = 7; RPC_CreateDirectory = 5; RPC_RemoveDirectory = 6; RPC_DirectoryExists = 13; type { TWorkerService } TWorkerService = class(TBaseService) public constructor Create(const AName: String); override; procedure ProcessRequest(ATransport: TBaseTransport; ACommand: Int32; ARequest: TStream); override; end; var WorkerProcessId: SizeUInt = 0; implementation uses DCBasicTypes, DCOSUtils, uFindEx, uDebug, uFileCopyEx; function FileCopyProgress(TotalBytes, DoneBytes: Int64; UserData: Pointer): LongBool; var Code: UInt32 = 1; ATransport: TBaseTransport absolute UserData; begin ATransport.WriteBuffer(Code, SizeOf(UInt32)); ATransport.WriteBuffer(TotalBytes, SizeOf(TotalBytes)); ATransport.WriteBuffer(DoneBytes, SizeOf(DoneBytes)); ATransport.ReadBuffer(Result, SizeOf(Result)); end; { TMasterService } constructor TMasterService.Create(const AName: String); begin inherited Create(AName); Self.FVerifyChild:= True; end; procedure TMasterService.ProcessRequest(ATransport: TBaseTransport; ACommand: Int32; ARequest: TStream); var Result: LongBool = True; begin case ACommand of RPC_Execute: begin ARequest.ReadBuffer(WorkerProcessId, SizeOf(SizeUInt)); ATransport.WriteBuffer(Result, SizeOf(Result)); FEvent.SetEvent; end; end; end; { TWorkerService } constructor TWorkerService.Create(const AName: String); begin inherited Create(AName); Self.FVerifyParent:= True; end; procedure TWorkerService.ProcessRequest(ATransport: TBaseTransport; ACommand: Int32; ARequest: TStream); const FIND_MAX = 512; var Mode: Integer; Index: Integer; Handle: THandle; Options: UInt32; NewName: String; FileName: String; Result: LongBool; Attr: TFileAttrs; LastError: Integer; Data: TMemoryStream; SearchRec: PSearchRecEx; CreationTime: TFileTimeEx; LastAccessTime: TFileTimeEx; ModificationTime: TFileTimeEx; FileAttr: TFileAttributeData; procedure WriteSearchRec(Data: TMemoryStream; SearchRec: PSearchRecEx); begin Data.WriteBuffer(SearchRec^.PlatformTime, SizeOf(SearchRec^.PlatformTime)); Data.WriteBuffer(SearchRec^.LastAccessTime, SizeOf(SearchRec^.LastAccessTime)); Data.WriteBuffer(SearchRec^.Time, SizeOf(TFileTime)); Data.WriteBuffer(SearchRec^.Size, SizeOf(Int64)); Data.WriteBuffer(SearchRec^.Attr, SizeOf(TFileAttrs)); Data.WriteAnsiString(SearchRec^.Name); end; begin case ACommand of RPC_DeleteFile: begin FileName:= ARequest.ReadAnsiString; DCDebug('DeleteFile ', FileName); Result:= mbDeleteFile(FileName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileExists: begin FileName:= ARequest.ReadAnsiString; DCDebug('FileExists ', FileName); Result:= mbFileExists(FileName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileGetAttr: begin FileName:= ARequest.ReadAnsiString; Mode:= ARequest.ReadDWord; DCDebug('FileGetAttr ', FileName); case Mode of Ord(LongBool(False)): Result:= LongBool(mbFileGetAttr(FileName)); Ord(LongBool(True)): Result:= LongBool(mbFileGetAttrNoLinks(FileName)); maxSmallint: Result:= LongBool(mbFileGetAttr(FileName, FileAttr)); end; LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); if (Mode = maxSmallint) then ATransport.WriteBuffer(FileAttr, SizeOf(FileAttr)); end; RPC_FileSetAttr: begin FileName:= ARequest.ReadAnsiString; Attr:= ARequest.ReadDWord; DCDebug('FileSetAttr ', FileName); Result:= mbFileSetAttr(FileName, Attr); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileSetTime: begin FileName:= ARequest.ReadAnsiString; ARequest.ReadBuffer(ModificationTime, SizeOf(TFileTimeEx)); ARequest.ReadBuffer(CreationTime, SizeOf(TFileTimeEx)); ARequest.ReadBuffer(LastAccessTime, SizeOf(TFileTimeEx)); DCDebug('FileSetTime ', FileName); Result:= mbFileSetTimeEx(FileName, ModificationTime, CreationTime, LastAccessTime); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileSetReadOnly: begin FileName:= ARequest.ReadAnsiString; Attr:= ARequest.ReadDWord; DCDebug('FileSetReadOnly ', FileName); Result:= mbFileSetReadOnly(FileName, Boolean(Attr)); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileCopyAttr: begin FileName:= ARequest.ReadAnsiString; NewName:= ARequest.ReadAnsiString; Attr:= ARequest.ReadDWord; DCDebug('FileCopyAttr ', NewName); Result:= LongBool(mbFileCopyAttr(FileName, NewName, TCopyAttributesOptions(Attr))); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileOpen: begin FileName:= ARequest.ReadAnsiString; Mode:= ARequest.ReadDWord; DCDebug('FileOpen ', FileName); Handle:= mbFileOpen(FileName, Mode); if (Handle <> feInvalidHandle) then LastError:= 0 else begin LastError:= GetLastOSError; end; ATransport.WriteBuffer(LastError, SizeOf(LastError)); if (LastError = 0) then ATransport.WriteHandle(Handle); end; RPC_FileCreate: begin FileName:= ARequest.ReadAnsiString; Mode:= ARequest.ReadDWord; DCDebug('FileCreate ', FileName); Handle:= mbFileCreate(FileName, Mode); if (Handle <> feInvalidHandle) then LastError:= 0 else begin LastError:= GetLastOSError; end; ATransport.WriteBuffer(LastError, SizeOf(LastError)); if (LastError = 0) then ATransport.WriteHandle(Handle); end; RPC_RenameFile: begin FileName:= ARequest.ReadAnsiString; NewName:= ARequest.ReadAnsiString; DCDebug('RenameFile ', FileName); Result:= mbRenameFile(FileName, NewName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FindFirst: begin Index:= 0; FileName:= ARequest.ReadAnsiString; Mode:= ARequest.ReadDWord; New(SearchRec); LastError:= FindFirstEx(FileName, Mode, SearchRec^); if LastError = 0 then begin Data:= TMemoryStream.Create; Data.WriteBuffer(SearchRec, SizeOf(SearchRec)); repeat Inc(Index); WriteSearchRec(Data, SearchRec); until not ((Index < FIND_MAX) and (FindNextEx(SearchRec^) = 0)); Index:= Data.Size; end; ATransport.WriteBuffer(LastError, SizeOf(LastError)); ATransport.WriteBuffer(Index, SizeOf(Index)); if Index > 0 then begin ATransport.WriteBuffer(Data.Memory^, Index); Data.Free; end; end; RPC_FindNext: begin Index:= 0; ARequest.ReadBuffer(SearchRec, SizeOf(SearchRec)); LastError:= FindNextEx(SearchRec^); if LastError = 0 then begin Data:= TMemoryStream.Create; Data.WriteBuffer(SearchRec, SizeOf(SearchRec)); repeat Inc(Index); WriteSearchRec(Data, SearchRec); until not ((Index < FIND_MAX) and (FindNextEx(SearchRec^) = 0)); Index:= Data.Size; end; ATransport.WriteBuffer(LastError, SizeOf(LastError)); ATransport.WriteBuffer(Index, SizeOf(Index)); if Index > 0 then begin ATransport.WriteBuffer(Data.Memory^, Index); Data.Free; end; end; RPC_FindClose: begin ARequest.ReadBuffer(SearchRec, SizeOf(SearchRec)); FindCloseEx(SearchRec^); Dispose(SearchRec); end; RPC_CreateHardLink: begin FileName:= ARequest.ReadAnsiString; NewName:= ARequest.ReadAnsiString; DCDebug('CreateHardLink ', NewName); Result:= CreateHardLink(FileName, NewName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_CreateSymbolicLink: begin FileName:= ARequest.ReadAnsiString; NewName:= ARequest.ReadAnsiString; DCDebug('CreateSymbolicLink ', NewName); Result:= CreateSymLink(FileName, NewName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_CreateDirectory: begin FileName:= ARequest.ReadAnsiString; DCDebug('CreateDirectory ', FileName); Result:= mbCreateDir(FileName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_RemoveDirectory: begin FileName:= ARequest.ReadAnsiString; DCDebug('RemoveDirectory ', FileName); Result:= mbRemoveDir(FileName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_DirectoryExists: begin FileName:= ARequest.ReadAnsiString; DCDebug('DirectoryExists ', FileName); Result:= mbDirectoryExists(FileName); LastError:= GetLastOSError; ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_FileCopy: begin FileName:= ARequest.ReadAnsiString; NewName:= ARequest.ReadAnsiString; Options:= ARequest.ReadDWord; DCDebug('FileCopy ', FileName); Result:= FileCopyEx(FileName, NewName, Options, @FileCopyProgress, ATransport); LastError:= GetLastOSError; Index:= 0; ATransport.WriteBuffer(Index, SizeOf(Index)); ATransport.WriteBuffer(Result, SizeOf(Result)); ATransport.WriteBuffer(LastError, SizeOf(LastError)); end; RPC_Terminate: FEvent.SetEvent; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/synhighlighterlua.pas����������������������������������������������������������0000644�0001750�0000144�00000123130�14743153644�017634� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{------------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: SynHighlighterLua.pas, the Initial Author of this file is Zhou Kan. All Rights Reserved. Contributors to the SynEdit and mwEdit projects are listed in the Contributors.txt file. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 or later (the "GPL"), in which case the provisions of the GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. $Id: SynHighlighterLua.pas,v 1.00 2005/01/24 17:58:27 Kan Exp $ You may retrieve the latest version of this file at the SynEdit home page, located at http://SynEdit.SourceForge.net Known Issues: -------------------------------------------------------------------------------} { @abstract(Provides a Lua Script highlighter for SynEdit) @author(Zhou Kan [textrush@tom.com]) @created(June 2004) @lastmod(2005-01-24) The SynHighlighterLua unit provides SynEdit with a Lua Script (*.lua) highlighter. The highlighter formats Lua Script source code highlighting keywords, strings, numbers and characters. } unit SynHighlighterLua; {$mode objfpc}{$H+} interface uses SysUtils, Classes, Graphics, SynEditHighlighter, SynEditTypes, SynEditStrConst; type TtkTokenKind = ( tkComment, tkFunction, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, tkString, tkSymbol, tkUnknown); TRangeState = (rsUnKnown, rsComment, rsString, rsQuoteString, rsMultilineString); TProcTableProc = procedure of object; PIdentFuncTableFunc = ^TIdentFuncTableFunc; TIdentFuncTableFunc = function: TtkTokenKind of object; const MaxKey = 185; type { TSynLuaSyn } TSynLuaSyn = class(TSynCustomHighlighter) private fLineRef: string; fLine: PChar; fLineNumber: Integer; fProcTable: array[#0..#255] of TProcTableProc; fRange: TRangeState; Run: LongInt; fCommentEnd: String; fStringLen: Integer; fToIdent: PChar; fTokenPos: Integer; fTokenID: TtkTokenKind; fIdentFuncTable: array[0 .. MaxKey] of TIdentFuncTableFunc; fCommentAttri: TSynHighlighterAttributes; fFunctionAttri: TSynHighlighterAttributes; fIdentifierAttri: TSynHighlighterAttributes; fKeyAttri: TSynHighlighterAttributes; fNumberAttri: TSynHighlighterAttributes; fSpaceAttri: TSynHighlighterAttributes; fStringAttri: TSynHighlighterAttributes; fSymbolAttri: TSynHighlighterAttributes; function KeyHash(ToHash: PChar): Integer; function KeyComp(const aKey: string): Boolean; function Func17: TtkTokenKind; function Func19: TtkTokenKind; function Func21: TtkTokenKind; function Func22: TtkTokenKind; function Func25: TtkTokenKind; function Func26: TtkTokenKind; function Func31: TtkTokenKind; function Func32: TtkTokenKind; function Func33: TtkTokenKind; function Func34: TtkTokenKind; function Func35: TtkTokenKind; function Func37: TtkTokenKind; function Func38: TtkTokenKind; function Func39: TtkTokenKind; function Func40: TtkTokenKind; function Func41: TtkTokenKind; function Func42: TtkTokenKind; function Func44: TtkTokenKind; function Func45: TtkTokenKind; function Func46: TtkTokenKind; function Func47: TtkTokenKind; function Func48: TtkTokenKind; function Func49: TtkTokenKind; function Func50: TtkTokenKind; function Func51: TtkTokenKind; function Func52: TtkTokenKind; function Func53: TtkTokenKind; function Func56: TtkTokenKind; function Func57: TtkTokenKind; function Func60: TtkTokenKind; function Func62: TtkTokenKind; function Func63: TtkTokenKind; function Func66: TtkTokenKind; function Func67: TtkTokenKind; function Func70: TtkTokenKind; function Func71: TtkTokenKind; function Func73: TtkTokenKind; function Func74: TtkTokenKind; function Func75: TtkTokenKind; function Func76: TtkTokenKind; function Func78: TtkTokenKind; function Func79: TtkTokenKind; function Func80: TtkTokenKind; function Func81: TtkTokenKind; function Func82: TtkTokenKind; function Func83: TtkTokenKind; function Func84: TtkTokenKind; function Func88: TtkTokenKind; function Func89: TtkTokenKind; function Func90: TtkTokenKind; function Func92: TtkTokenKind; function Func94: TtkTokenKind; function Func95: TtkTokenKind; function Func97: TtkTokenKind; function Func99: TtkTokenKind; function Func101: TtkTokenKind; function Func102: TtkTokenKind; function Func105: TtkTokenKind; function Func107: TtkTokenKind; function Func108: TtkTokenKind; function Func110: TtkTokenKind; function Func111: TtkTokenKind; function Func112: TtkTokenKind; function Func113: TtkTokenKind; function Func114: TtkTokenKind; function Func116: TtkTokenKind; function Func117: TtkTokenKind; function Func125: TtkTokenKind; function Func130: TtkTokenKind; function Func132: TtkTokenKind; function Func135: TtkTokenKind; function Func137: TtkTokenKind; function Func138: TtkTokenKind; function Func141: TtkTokenKind; function Func143: TtkTokenKind; function Func144: TtkTokenKind; function Func147: TtkTokenKind; function Func149: TtkTokenKind; function Func185: TtkTokenKind; function AltFunc: TtkTokenKind; procedure InitIdent; function IdentKind(MayBe: PChar): TtkTokenKind; procedure MakeMethodTables; procedure NullProc; procedure SpaceProc; procedure CRProc; procedure LFProc; procedure IdentProc; procedure NumberProc; procedure UnknownProc; procedure MinusProc; procedure CommentProc; procedure StringProc; procedure QuoteStringProc; procedure StringEndProc; procedure BraceCloseProc; procedure BraceOpenProc; procedure GreaterProc; procedure LowerProc; procedure RoundCloseProc; procedure RoundOpenProc; procedure SquareCloseProc; procedure SquareOpenProc; procedure ColonProc; procedure CommaProc; procedure SemiColonProc; procedure PointProc; procedure DirectiveProc; procedure EqualProc; procedure PlusProc; procedure StarProc; procedure SlashProc; procedure ModSymbolProc; procedure AndSymbolProc; procedure NotSymbolProc; procedure OrSymbolProc; procedure TildeProc; procedure ArrowProc; procedure QuestionProc; protected function GetIdentChars: TSynIdentChars; override; function IsFilterStored: Boolean; override; function GetSampleSource: String; override; public constructor Create(AOwner: TComponent); override; function GetRange: Pointer; override; procedure ResetRange; override; procedure SetRange(Value: Pointer); override; function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes; override; function GetEol: Boolean; override; function GetTokenID: TtkTokenKind; procedure SetLine(const NewValue: String; LineNumber: Integer); override; function GetToken: String; override; procedure GetTokenEx(out TokenStart :PChar; out TokenLength :integer); override; function GetTokenAttribute: TSynHighlighterAttributes; override; function GetTokenKind: integer; override; function GetTokenPos: Integer; override; procedure Next; override; class function GetLanguageName :string; override; published property CommentAttri: TSynHighlighterAttributes read fCommentAttri write fCommentAttri; property FunctionAttri: TSynHighlighterAttributes read fFunctionAttri write fFunctionAttri; property IdentifierAttri: TSynHighlighterAttributes read fIdentifierAttri write fIdentifierAttri; property KeyAttri: TSynHighlighterAttributes read fKeyAttri write fKeyAttri; property NumberAttri: TSynHighlighterAttributes read fNumberAttri write fNumberAttri; property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri write fSpaceAttri; property StringAttri: TSynHighlighterAttributes read fStringAttri write fStringAttri; property SymbolAttri: TSynHighlighterAttributes read fSymbolAttri write fSymbolAttri; end; implementation resourcestring SYNS_LangLua = 'Lua Script'; SYNS_FilterLua = 'Lua Script File (*.lua)|*.lua'; var Identifiers: array[#0..#255] of ByteBool; mHashTable : array[#0..#255] of Integer; procedure MakeIdentTable; var I: Char; begin for I := #0 to #255 do begin case I of '_', 'a'..'z', 'A'..'Z', '0'..'9': Identifiers[I] := True; else Identifiers[I] := False; end; case I in ['_', 'A'..'Z', 'a'..'z'] of True: begin if (I > #64) and (I < #91) then mHashTable[I] := Ord(I) - 64 else if (I > #96) then mHashTable[I] := Ord(I) - 95; end; else mHashTable[I] := 0; end; end; end; procedure TSynLuaSyn.InitIdent; var I: Integer; pF: PIdentFuncTableFunc; begin pF := PIdentFuncTableFunc(@fIdentFuncTable); for I := Low(fIdentFuncTable) to High(fIdentFuncTable) do begin pF^ := @AltFunc; Inc(pF); end; fIdentFuncTable[17] := @Func17; fIdentFuncTable[19] := @Func19; fIdentFuncTable[21] := @Func21; fIdentFuncTable[22] := @Func22; fIdentFuncTable[25] := @Func25; fIdentFuncTable[26] := @Func26; fIdentFuncTable[31] := @Func31; fIdentFuncTable[32] := @Func32; fIdentFuncTable[33] := @Func33; fIdentFuncTable[34] := @Func34; fIdentFuncTable[35] := @Func35; fIdentFuncTable[37] := @Func37; fIdentFuncTable[38] := @Func38; fIdentFuncTable[39] := @Func39; fIdentFuncTable[40] := @Func40; fIdentFuncTable[41] := @Func41; fIdentFuncTable[42] := @Func42; fIdentFuncTable[44] := @Func44; fIdentFuncTable[45] := @Func45; fIdentFuncTable[46] := @Func46; fIdentFuncTable[47] := @Func47; fIdentFuncTable[48] := @Func48; fIdentFuncTable[49] := @Func49; fIdentFuncTable[50] := @Func50; fIdentFuncTable[51] := @Func51; fIdentFuncTable[52] := @Func52; fIdentFuncTable[53] := @Func53; fIdentFuncTable[56] := @Func56; fIdentFuncTable[57] := @Func57; fIdentFuncTable[60] := @Func60; fIdentFuncTable[62] := @Func62; fIdentFuncTable[63] := @Func63; fIdentFuncTable[66] := @Func66; fIdentFuncTable[67] := @Func67; fIdentFuncTable[70] := @Func70; fIdentFuncTable[71] := @Func71; fIdentFuncTable[73] := @Func73; fIdentFuncTable[74] := @Func74; fIdentFuncTable[75] := @Func75; fIdentFuncTable[76] := @Func76; fIdentFuncTable[78] := @Func78; fIdentFuncTable[79] := @Func79; fIdentFuncTable[80] := @Func80; fIdentFuncTable[81] := @Func81; fIdentFuncTable[82] := @Func82; fIdentFuncTable[83] := @Func83; fIdentFuncTable[84] := @Func84; fIdentFuncTable[88] := @Func88; fIdentFuncTable[89] := @Func89; fIdentFuncTable[90] := @Func90; fIdentFuncTable[92] := @Func92; fIdentFuncTable[94] := @Func94; fIdentFuncTable[95] := @Func95; fIdentFuncTable[97] := @Func97; fIdentFuncTable[99] := @Func99; fIdentFuncTable[101] := @Func101; fIdentFuncTable[102] := @Func102; fIdentFuncTable[105] := @Func105; fIdentFuncTable[107] := @Func107; fIdentFuncTable[108] := @Func108; fIdentFuncTable[110] := @Func110; fIdentFuncTable[111] := @Func111; fIdentFuncTable[112] := @Func112; fIdentFuncTable[113] := @Func113; fIdentFuncTable[114] := @Func114; fIdentFuncTable[116] := @Func116; fIdentFuncTable[117] := @Func117; fIdentFuncTable[125] := @Func125; fIdentFuncTable[130] := @Func130; fIdentFuncTable[132] := @Func132; fIdentFuncTable[135] := @Func135; fIdentFuncTable[137] := @Func137; fIdentFuncTable[138] := @Func138; fIdentFuncTable[141] := @Func141; fIdentFuncTable[143] := @Func143; fIdentFuncTable[144] := @Func144; fIdentFuncTable[147] := @Func147; fIdentFuncTable[149] := @Func149; fIdentFuncTable[185] := @Func185; end; function TSynLuaSyn.KeyHash(ToHash: PChar): Integer; begin Result := 0; while ToHash^ in ['_', 'a'..'z', 'A'..'Z', '0'..'9'] do begin inc(Result, mHashTable[ToHash^]); inc(ToHash); end; fStringLen := ToHash - fToIdent; end; function TSynLuaSyn.KeyComp(const aKey :string) :Boolean; var I: Integer; Temp: PChar; begin Temp := fToIdent; if Length(aKey) = fStringLen then begin Result := True; for i := 1 to fStringLen do begin if Temp^ <> aKey[i] then begin Result := False; break; end; inc(Temp); end; end else Result := False; end; function TSynLuaSyn.Func17: TtkTokenKind; begin if KeyComp('if') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func19: TtkTokenKind; begin if KeyComp('deg') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func21: TtkTokenKind; begin if KeyComp('do') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func22: TtkTokenKind; begin if KeyComp('and') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func25: TtkTokenKind; begin if KeyComp('PI') then Result := tkFunction else if KeyComp('abs') then Result := tkFunction else if KeyComp('in') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func26: TtkTokenKind; begin if KeyComp('end') then Result := tkKey else if KeyComp('rad') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func31: TtkTokenKind; begin if KeyComp('tag') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func32: TtkTokenKind; begin if KeyComp('read') then Result := tkFunction else if KeyComp('call') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func33: TtkTokenKind; begin if KeyComp('ceil') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func34: TtkTokenKind; begin if KeyComp('date') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func35: TtkTokenKind; begin if KeyComp('mod') then Result := tkFunction else if KeyComp('or') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func37: TtkTokenKind; begin if KeyComp('log') then Result := tkFunction else if KeyComp('log10') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func38: TtkTokenKind; begin if KeyComp('nil') then Result := tkKey else if KeyComp('tan') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func39: TtkTokenKind; begin if KeyComp('min') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func40: TtkTokenKind; begin if KeyComp('atan') then Result := tkFunction else if KeyComp('cos') then Result := tkFunction else if KeyComp('atan2') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func41: TtkTokenKind; begin if KeyComp('max') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func42: TtkTokenKind; begin if KeyComp('break') then Result := tkKey else if KeyComp('for') then Result := tkKey else if KeyComp('acos') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func44: TtkTokenKind; begin if KeyComp('debug') then Result := tkFunction else if KeyComp('seek') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func45: TtkTokenKind; begin if KeyComp('else') then Result := tkKey else if KeyComp('sin') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func46: TtkTokenKind; begin if KeyComp('ascii') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func47: TtkTokenKind; begin if KeyComp('asin') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func48: TtkTokenKind; begin if KeyComp('local') then Result := tkKey else if KeyComp('exp') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func49: TtkTokenKind; begin if KeyComp('clock') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func50: TtkTokenKind; begin if KeyComp('getn') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func51: TtkTokenKind; begin if KeyComp('then') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func52: TtkTokenKind; begin if KeyComp('not') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func53: TtkTokenKind; begin if KeyComp('gsub') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func56: TtkTokenKind; begin if KeyComp('_ALERT') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func57: TtkTokenKind; begin if KeyComp('dofile') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func60: TtkTokenKind; begin if KeyComp('gcinfo') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func62: TtkTokenKind; begin if KeyComp('elseif') then Result := tkKey else if KeyComp('exit') then Result := tkFunction else if KeyComp('while') then Result := tkKey else if KeyComp('rename') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func63: TtkTokenKind; begin if KeyComp('foreach') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func66: TtkTokenKind; begin if KeyComp('_STDIN') then Result := tkFunction else if KeyComp('ldexp') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func67: TtkTokenKind; begin if KeyComp('next') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func70: TtkTokenKind; begin if KeyComp('type') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func71: TtkTokenKind; begin if KeyComp('random') then Result := tkFunction else if KeyComp('repeat') then Result := tkKey else if KeyComp('floor') then Result := tkFunction else if KeyComp('flush') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func73: TtkTokenKind; begin if KeyComp('foreachi') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func74: TtkTokenKind; begin if KeyComp('frexp') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func75: TtkTokenKind; begin if KeyComp('globals') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func76: TtkTokenKind; begin if KeyComp('newtag') then Result := tkFunction else if KeyComp('sort') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func78: TtkTokenKind; begin if KeyComp('sqrt') then Result := tkFunction else if KeyComp('settag') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func79: TtkTokenKind; begin if KeyComp('format') then Result := tkFunction else if KeyComp('getenv') then Result := tkFunction else if KeyComp('error') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func80: TtkTokenKind; begin if KeyComp('_INPUT') then Result := tkFunction else if KeyComp('write') then Result := tkFunction else if KeyComp('rawget') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func81: TtkTokenKind; begin if KeyComp('until') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func82: TtkTokenKind; begin if KeyComp('print') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func83: TtkTokenKind; begin if KeyComp('getinfo') then Result := tkFunction else if KeyComp('getlocal') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func84: TtkTokenKind; begin if KeyComp('_STDERR') then Result := tkFunction else if KeyComp('getargs') then Result := tkFunction else if KeyComp('remove') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func88: TtkTokenKind; begin if KeyComp('assert') then Result := tkFunction else if KeyComp('readfrom') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func89: TtkTokenKind; begin if KeyComp('tmpname') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func90: TtkTokenKind; begin if KeyComp('execute') then Result := tkFunction else if KeyComp('openfile') then Result := tkFunction else if KeyComp('getglobal') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func92: TtkTokenKind; begin if KeyComp('rawset') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func94: TtkTokenKind; begin if KeyComp('strchar') then Result := tkFunction else if KeyComp('strlen') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func95: TtkTokenKind; begin if KeyComp('setlocal') then Result := tkFunction else if KeyComp('closefile') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func97: TtkTokenKind; begin if KeyComp('strfind') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func99: TtkTokenKind; begin if KeyComp('_STDOUT') then Result := tkFunction else if KeyComp('appendto') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func101: TtkTokenKind; begin if KeyComp('setlocale') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func102: TtkTokenKind; begin if KeyComp('setglobal') then Result := tkFunction else if KeyComp('return') then Result := tkKey else if KeyComp('strrep') then Result := tkFunction else if KeyComp('_VERSION') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func105: TtkTokenKind; begin if KeyComp('strsub') then Result := tkFunction else if KeyComp('tremove') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func107: TtkTokenKind; begin if KeyComp('foreachvar') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func108: TtkTokenKind; begin if KeyComp('randomseed') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func110: TtkTokenKind; begin if KeyComp('function') then Result := tkKey else Result := tkIdentifier; end; function TSynLuaSyn.Func111: TtkTokenKind; begin if KeyComp('nextvar') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func112: TtkTokenKind; begin if KeyComp('tinsert') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func113: TtkTokenKind; begin if KeyComp('_OUTPUT') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func114: TtkTokenKind; begin if KeyComp('dostring') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func116: TtkTokenKind; begin if KeyComp('tonumber') then Result := tkFunction else if KeyComp('strbyte') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func117: TtkTokenKind; begin if KeyComp('writeto') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func125: TtkTokenKind; begin if KeyComp('rawgettable') then Result := tkFunction else if KeyComp('collectgarbage') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func130: TtkTokenKind; begin if KeyComp('tostring') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func132: TtkTokenKind; begin if KeyComp('setcallhook') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func135: TtkTokenKind; begin if KeyComp('rawgetglobal') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func137: TtkTokenKind; begin if KeyComp('gettagmethod') then Result := tkFunction else if KeyComp('rawsettable') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func138: TtkTokenKind; begin if KeyComp('strlower') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func141: TtkTokenKind; begin if KeyComp('strupper') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func143: TtkTokenKind; begin if KeyComp('_ERRORMESSAGE') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func144: TtkTokenKind; begin if KeyComp('setlinehook') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func147: TtkTokenKind; begin if KeyComp('rawsetglobal') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func149: TtkTokenKind; begin if KeyComp('settagmethod') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.Func185: TtkTokenKind; begin if KeyComp('copytagmethods') then Result := tkFunction else Result := tkIdentifier; end; function TSynLuaSyn.AltFunc: TtkTokenKind; begin Result := tkIdentifier; end; function TSynLuaSyn.IdentKind(MayBe: PChar): TtkTokenKind; var HashKey: Integer; begin fToIdent := MayBe; HashKey := KeyHash(MayBe); if HashKey <= MaxKey then Result := fIdentFuncTable[HashKey]() else Result := tkIdentifier; end; procedure TSynLuaSyn.MakeMethodTables; var I: Char; begin for I := #0 to #255 do case I of #0: fProcTable[I] := @NullProc; #10: fProcTable[I] := @LFProc; #13: fProcTable[I] := @CRProc; #1..#9, #11, #12, #14..#32 : fProcTable[I] := @SpaceProc; 'A'..'Z', 'a'..'z', '_': fProcTable[I] := @IdentProc; '0'..'9': fProcTable[I] := @NumberProc; '''': fProcTable[I] := @StringProc; '"': fProcTable[I] := @QuoteStringProc; '-': fProcTable[I] := @MinusProc; '}': fProcTable[I] := @BraceCloseProc; '{': fProcTable[I] := @BraceOpenProc; '>': fProcTable[I] := @GreaterProc; '<': fProcTable[I] := @LowerProc; ')': fProcTable[I] := @RoundCloseProc; '(': fProcTable[I] := @RoundOpenProc; ']': fProcTable[I] := @SquareCloseProc; '[': fProcTable[I] := @SquareOpenProc; ':': fProcTable[I] := @ColonProc; ',': fProcTable[I] := @CommaProc; ';': fProcTable[I] := @SemiColonProc; '.': fProcTable[I] := @PointProc; '#': fProcTable[I] := @DirectiveProc; '=': fProcTable[I] := @EqualProc; '+': fProcTable[I] := @PlusProc; '*': fProcTable[I] := @StarProc; '/': fProcTable[I] := @SlashProc; '%': fProcTable[I] := @ModSymbolProc; '&': fProcTable[I] := @AndSymbolProc; '!': fProcTable[I] := @NotSymbolProc; '|': fProcTable[I] := @OrSymbolProc; '~': fProcTable[I] := @TildeProc; '^': fProcTable[I] := @ArrowProc; '?': fProcTable[I] := @QuestionProc; else fProcTable[I] := @UnknownProc; end; end; constructor TSynLuaSyn.Create(AOwner: TComponent); begin inherited Create(AOwner); fCommentAttri := TSynHighLighterAttributes.Create(@SYNS_AttrComment, SYNS_XML_AttrComment); fCommentAttri.Foreground := clGreen; AddAttribute(fCommentAttri); fFunctionAttri := TSynHighLighterAttributes.Create(@SYNS_AttrFunction, SYNS_XML_AttrFunction); fFunctionAttri.Foreground := $00C05000; AddAttribute(fFunctionAttri); fIdentifierAttri := TSynHighLighterAttributes.Create(@SYNS_AttrIdentifier, SYNS_XML_AttrIdentifier); fIdentifierAttri.Foreground := clWindowText; AddAttribute(fIdentifierAttri); fKeyAttri := TSynHighLighterAttributes.Create(@SYNS_AttrReservedWord, SYNS_XML_AttrReservedWord); fKeyAttri.Foreground := clBlue; AddAttribute(fKeyAttri); fNumberAttri := TSynHighLighterAttributes.Create(@SYNS_AttrNumber, SYNS_XML_AttrNumber); fNumberAttri.Foreground := clPurple; AddAttribute(fNumberAttri); fSpaceAttri := TSynHighLighterAttributes.Create(@SYNS_AttrSpace, SYNS_XML_AttrSpace); AddAttribute(fSpaceAttri); fStringAttri := TSynHighLighterAttributes.Create(@SYNS_AttrString, SYNS_XML_AttrString); fStringAttri.Foreground := clMaroon; AddAttribute(fStringAttri); fSymbolAttri := TSynHighLighterAttributes.Create(@SYNS_AttrSymbol, SYNS_XML_AttrSymbol); fSymbolAttri.Foreground := clNavy; AddAttribute(fSymbolAttri); SetAttributesOnChange(@DefHighlightChange); InitIdent; MakeMethodTables; fRange := rsUnknown; fDefaultFilter := SYNS_FilterLua; end; procedure TSynLuaSyn.SpaceProc; begin fTokenID := tkSpace; repeat Inc(Run); until not (fLine[Run] in [#1..#32]); end; procedure TSynLuaSyn.NullProc; begin fTokenID := tkNull; end; procedure TSynLuaSyn.CRProc; begin fTokenID := tkSpace; Inc(Run); if fLine[Run] = #10 then Inc(Run); end; procedure TSynLuaSyn.LFProc; begin fTokenID := tkSpace; Inc(Run); end; procedure TSynLuaSyn.MinusProc; var Idx: Integer; begin case fLine[Run + 1] of '-': begin fTokenID := tkComment; if (fLine[Run + 2] = '[') and (fLine[Run + 3] in ['[', '=']) then begin Idx := Run + 2; repeat Inc(Idx); until fLine[Idx] in [#0, #10, #13, '[']; if (fLine[Idx] = '[') then begin if (fLine[Run + 3] = '[') then fCommentEnd := ']]' else begin SetString(fCommentEnd, fLine + Run + 3, Idx - (Run + 3)); fCommentEnd := ']' + fCommentEnd + ']'; end; fRange := rsComment; Run := Idx; Exit; end; end; repeat Inc(Run); until fLine[Run] in [#0, #10, #13]; end; '=', '>': begin Inc(Run, 2); fTokenID := tkSymbol; end else begin fTokenID := tkSymbol; Inc(Run); {subtract} end; end; end; procedure TSynLuaSyn.CommentProc; var ALength: Integer; ACommentEnd: PAnsiChar; begin case FLine[Run] of #0: NullProc; #10: LFProc; #13: CRProc; else begin fTokenID := tkComment; ALength := Length(fCommentEnd); ACommentEnd := PAnsiChar(fCommentEnd); repeat if (StrLComp(fLine + Run, ACommentEnd, ALength) = 0) then begin Inc(Run, ALength); fRange := rsUnKnown; Break; end; Inc(Run); until fLine[Run] in [#0, #10, #13]; end; end; end; procedure TSynLuaSyn.StringProc; begin fTokenID := tkString; repeat if fLine[Run] = '\' then begin if fLine[Run + 1] in [#39, '\'] then Inc(Run); end; Inc(Run); until fLine[Run] in [#0, #10, #13, #39]; if fLine[Run] = #39 then Inc(Run); end; procedure TSynLuaSyn.QuoteStringProc; begin fTokenID := tkString; repeat if fLine[Run] = '\' then begin case fLine[Run + 1] of #34, '\': Inc(Run); #00: begin Inc(Run); fRange := rsMultilineString; Exit; end; end; end; Inc(Run); until fLine[Run] in [#0, #10, #13, #34]; if FLine[Run] = #34 then Inc(Run); end; procedure TSynLuaSyn.StringEndProc; begin fTokenID := tkString; case FLine[Run] of #0: begin NullProc; Exit; end; #10: begin LFProc; Exit; end; #13: begin CRProc; Exit; end; end; fRange := rsUnknown; repeat case FLine[Run] of #0, #10, #13: Break; '\': begin case fLine[Run + 1] of #34, '\': Inc(Run); #00: begin Inc(Run); fRange := rsMultilineString; Exit; end; end; end; #34: Break; end; Inc(Run); until fLine[Run] in [#0, #10, #13, #34]; if FLine[Run] = #34 then Inc(Run); end; procedure TSynLuaSyn.BraceCloseProc; begin Inc(Run); fTokenId := tkSymbol; end; procedure TSynLuaSyn.BraceOpenProc; begin Inc(Run); fTokenId := tkSymbol; end; procedure TSynLuaSyn.GreaterProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {greater than or equal to} '>': begin if FLine[Run + 2] = '=' then {shift right assign} Inc(Run, 3) else {shift right} Inc(Run, 2); end; else {greater than} Inc(run); end; end; procedure TSynLuaSyn.LowerProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {less than or equal to} '<': begin if FLine[Run + 2] = '=' then {shift left assign} Inc(Run, 3) else {shift left} Inc(Run, 2); end; else Inc(Run); {less than} end; end; procedure TSynLuaSyn.RoundCloseProc; begin Inc(Run); fTokenID := tkSymbol; end; procedure TSynLuaSyn.RoundOpenProc; begin Inc(Run); FTokenID := tkSymbol; end; procedure TSynLuaSyn.SquareCloseProc; begin Inc(Run); fTokenID := tkSymbol; end; procedure TSynLuaSyn.SquareOpenProc; begin Inc(Run); fTokenID := tkSymbol; end; procedure TSynLuaSyn.ColonProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of ':': Inc(Run, 2); {scope resolution operator} else {colon} Inc(Run); end; end; procedure TSynLuaSyn.CommaProc; begin Inc(Run); fTokenID := tkSymbol; end; procedure TSynLuaSyn.SemiColonProc; begin Inc(Run); fTokenID := tkSymbol; end; procedure TSynLuaSyn.PointProc; begin fTokenID := tkSymbol; if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then {ellipse} Inc(Run, 3) else if FLine[Run + 1] in ['0'..'9'] then // float begin Dec(Run); // numberproc must see the point NumberProc; end else {point} Inc(Run); end; procedure TSynLuaSyn.DirectiveProc; begin Inc(Run); fTokenID := tkSymbol; end; procedure TSynLuaSyn.EqualProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {logical equal} else {assign} Inc(Run); end; end; procedure TSynLuaSyn.IdentProc; begin fTokenID := IdentKind((fLine + Run)); Inc(Run, fStringLen); while Identifiers[fLine[Run]] do Inc(Run); end; procedure TSynLuaSyn.PlusProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {add assign} '+': Inc(Run, 2); {increment} else {add} Inc(Run); end; end; procedure TSynLuaSyn.StarProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {multiply assign} else Inc(Run); {star} end; end; procedure TSynLuaSyn.SlashProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {multiply assign} else Inc(Run); {star} end; end; procedure TSynLuaSyn.ModSymbolProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {mod assign} else Inc(Run); {mod} end; end; procedure TSynLuaSyn.AndSymbolProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); // and assign '&': Inc(Run, 2); // logical and else Inc(Run); // and end; end; procedure TSynLuaSyn.NotSymbolProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {not equal} else Inc(Run); {not} end; end; procedure TSynLuaSyn.OrSymbolProc; begin fTokenID := tkSymbol; case FLine[Run + 1] of '=': Inc(Run, 2); {or assign} '|': Inc(Run, 2); {logical or} else Inc(Run); {or} end; end; procedure TSynLuaSyn.TildeProc; begin Inc(Run); {bitwise complement} fTokenId := tkSymbol; end; procedure TSynLuaSyn.ArrowProc; begin Inc(Run); {bitwise complement} fTokenId := tkSymbol; end; procedure TSynLuaSyn.QuestionProc; begin fTokenID := tkSymbol; {conditional} Inc(Run); end; procedure TSynLuaSyn.NumberProc; begin Inc(Run); fTokenID := tkNumber; while FLine[Run] in ['0'..'9', '.', 'u', 'U', 'l', 'L', 'x', 'X', 'e', 'E', 'f', 'F'] do //Kan //['0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X'] do //Commented by Kan begin case FLine[Run] of '.': if FLine[Run + 1] = '.' then break; end; Inc(Run); end; end; procedure TSynLuaSyn.UnknownProc; begin Inc(Run); while (fLine[Run] in [#128..#191]) or // continued utf8 subcode ((fLine[Run] <> #0) and (fProcTable[fLine[Run]] = @UnknownProc)) do Inc(Run); fTokenID := tkUnknown; end; procedure TSynLuaSyn.SetLine(const NewValue :String; LineNumber :Integer); begin fLineRef := NewValue; fLine := PChar(fLineRef); Run := 0; fLineNumber := LineNumber; Next; end; procedure TSynLuaSyn.Next; begin fTokenPos := Run; case fRange of rsComment: CommentProc(); rsMultilineString: StringEndProc; else begin fRange := rsUnknown; fProcTable[fLine[Run]]; end; end; end; class function TSynLuaSyn.GetLanguageName :string; begin Result := SYNS_LangLua; end; function TSynLuaSyn.GetDefaultAttribute(Index :integer) :TSynHighlighterAttributes; begin case Index of SYN_ATTR_COMMENT : Result := fCommentAttri; SYN_ATTR_IDENTIFIER : Result := fIdentifierAttri; SYN_ATTR_KEYWORD : Result := fKeyAttri; SYN_ATTR_STRING : Result := fStringAttri; SYN_ATTR_WHITESPACE : Result := fSpaceAttri; SYN_ATTR_SYMBOL : Result := fSymbolAttri; else Result := nil; end; end; function TSynLuaSyn.GetEol: Boolean; begin Result := fTokenID = tkNull; end; function TSynLuaSyn.GetToken: String; var Len: LongInt; begin Len := Run - fTokenPos; SetString(Result, (FLine + fTokenPos), Len); end; procedure TSynLuaSyn.GetTokenEx(out TokenStart :PChar; out TokenLength :integer); begin TokenLength := Run - fTokenPos; TokenStart := FLine + fTokenPos; end; function TSynLuaSyn.GetTokenID: TtkTokenKind; begin Result := fTokenId; end; function TSynLuaSyn.GetTokenAttribute :TSynHighlighterAttributes; begin case GetTokenID of tkComment: Result := fCommentAttri; tkFunction: Result := fFunctionAttri; tkIdentifier: Result := fIdentifierAttri; tkKey: Result := fKeyAttri; tkNumber: Result := fNumberAttri; tkSpace: Result := fSpaceAttri; tkString: Result := fStringAttri; tkSymbol: Result := fSymbolAttri; tkUnknown: Result := fIdentifierAttri; else Result := nil; end; end; function TSynLuaSyn.GetTokenKind: integer; begin Result := Ord(fTokenId); end; function TSynLuaSyn.GetTokenPos: Integer; begin Result := fTokenPos; end; function TSynLuaSyn.GetIdentChars: TSynIdentChars; begin Result := ['_', 'a'..'z', 'A'..'Z', '0'..'9']; end; function TSynLuaSyn.IsFilterStored :Boolean; begin Result := (fDefaultFilter <> SYNS_FilterLua); end; function TSynLuaSyn.GetSampleSource: String; begin Result:= '-- Sample comment'#13 + 'local str = "String"'#13 + 'a = {}'#13 + 'local x = 20'#13 + 'for i = 1,10 do'#13 + ' local y = 0'#13 + ' a[i] = function () y = y + 1; return x + y end'#13 + 'end'#13 + 'print(str)'; end; procedure TSynLuaSyn.ResetRange; begin fRange := rsUnknown; end; procedure TSynLuaSyn.SetRange(Value: Pointer); begin {$PUSH}{$HINTS OFF}{$WARNINGS OFF} fRange := TRangeState(PtrInt(Value)); {$POP} end; function TSynLuaSyn.GetRange: Pointer; begin {$PUSH}{$HINTS OFF} Result := Pointer(PtrInt(fRange)); {$POP} end; initialization MakeIdentTable; RegisterPlaceableHighlighter(TSynLuaSyn); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uColorExt.pas������������������������������������������������������������������0000644�0001750�0000144�00000021516�14743153644�016033� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Load colors of files in file panels Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz) Copyright (C) 2006-2022 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) 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 } unit uColorExt; {$mode objfpc}{$H+} interface uses Classes, Graphics, uFile, uMasks, uSearchTemplate, DCXmlConfig, DCJsonConfig, fpJson; type { TMaskItem } TMaskItem = class private FExt: String; FModeStr: String; FMaskList: TMaskList; FAttrList: TMaskList; FTemplate: TSearchTemplate; FColor: array[0..1] of TColor; private function GetColor: TColor; procedure SetColor(AValue: TColor); procedure SetExt(const AValue: String); procedure SetModeStr(const AValue: String); public sName: String; destructor Destroy; override; procedure Assign(ASource: TMaskItem); property sExt: String read FExt write SetExt; property cColor: TColor read GetColor write SetColor; property sModeStr: String read FModeStr write SetModeStr; end; { TColorExt } TColorExt = class private FStyle: Integer; FMaskItems: TList; function GetCount: Integer; function GetItems(const Index: Integer): TMaskItem; public constructor Create; destructor Destroy; override; procedure Clear; procedure Add(AItem: TMaskItem); function GetColorBy(const AFile: TFile): TColor; procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Load(AConfig: TJSONObject); overload; procedure Save(AConfig: TJSONObject); overload; procedure UpdateStyle; property Count: Integer read GetCount; property Items[const Index: Integer]: TMaskItem read GetItems; default; end; implementation uses SysUtils, uDebug, uGlobs, uFileProperty, uColors; { TMaskItem } procedure TMaskItem.SetExt(const AValue: String); var ATemplate: TSearchTemplate; begin FExt:= AValue; FreeAndNil(FMaskList); // Plain mask if not IsMaskSearchTemplate(FExt) then begin FreeAndNil(FTemplate); if (Length(FExt) > 0) then FMaskList:= TMaskList.Create(FExt); end // Search template else begin ATemplate:= gSearchTemplateList.TemplateByName[PAnsiChar(FExt) + 1]; if (ATemplate = nil) then FreeAndNil(FTemplate) else begin if (FTemplate = nil) then begin FTemplate:= TSearchTemplate.Create; end; FTemplate.SearchRecord:= ATemplate.SearchRecord; end; end; end; function TMaskItem.GetColor: TColor; begin Result:= FColor[TColorThemes.StyleIndex]; end; procedure TMaskItem.SetColor(AValue: TColor); begin FColor[TColorThemes.StyleIndex]:= AValue; end; procedure TMaskItem.SetModeStr(const AValue: String); begin if FModeStr <> AValue then begin FModeStr:= AValue; FreeAndNil(FAttrList); if (Length(FModeStr) > 0) then FAttrList:= TMaskList.Create(FModeStr); end; end; destructor TMaskItem.Destroy; begin FAttrList.Free; FTemplate.Free; FMaskList.Free; inherited Destroy; end; procedure TMaskItem.Assign(ASource: TMaskItem); begin Assert(Assigned(ASource)); sExt := ASource.sExt; sModeStr := ASource.sModeStr; FColor[0] := ASource.FColor[0]; FColor[1] := ASource.FColor[1]; sName := ASource.sName; end; function TColorExt.GetCount: Integer; begin Result := FMaskItems.Count; end; function TColorExt.GetItems(const Index: Integer): TMaskItem; begin Result := TMaskItem(FMaskItems[Index]); end; constructor TColorExt.Create; begin FMaskItems:= TList.Create; FStyle:= TColorThemes.StyleIndex; end; destructor TColorExt.Destroy; begin Clear; FreeAndNil(FMaskItems); inherited Destroy; end; procedure TColorExt.Clear; begin while FMaskItems.Count > 0 do begin TMaskItem(FMaskItems[0]).Free; FMaskItems.Delete(0); end; end; procedure TColorExt.Add(AItem: TMaskItem); begin FMaskItems.Add(AItem); end; function TColorExt.GetColorBy(const AFile: TFile): TColor; var Attr: String; Index: Integer; MaskItem: TMaskItem; begin Result:= clDefault; if not (fpAttributes in AFile.SupportedProperties) then Attr:= EmptyStr else begin Attr:= AFile.Properties[fpAttributes].AsString; end; for Index:= 0 to FMaskItems.Count - 1 do begin MaskItem:= TMaskItem(FMaskItems[Index]); // Get color by search template if IsMaskSearchTemplate(MaskItem.FExt) then begin if Assigned(MaskItem.FTemplate) and MaskItem.FTemplate.CheckFile(AFile) then begin Result:= MaskItem.FColor[FStyle]; Exit; end; Continue; end; // Get color by extension and attribute. // If attributes field is empty then don't match directories. if ((MaskItem.FMaskList = nil) or (((MaskItem.FAttrList <> nil) or not (AFile.IsDirectory or AFile.IsLinkToDirectory)) and MaskItem.FMaskList.Matches(AFile.Name))) and ((MaskItem.FAttrList = nil) or (Length(Attr) = 0) or MaskItem.FAttrList.Matches(Attr)) then begin Result:= MaskItem.FColor[FStyle]; Exit; end; end; end; procedure TColorExt.Load(AConfig: TXmlConfig; ANode: TXmlNode); var iColor: Integer; MaskItem: TMaskItem; sAttr, sName, sExtMask: String; begin Clear; ANode := ANode.FindNode('FileFilters'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('Filter') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', sName) and AConfig.TryGetValue(ANode, 'FileMasks', sExtMask) and AConfig.TryGetValue(ANode, 'Color', iColor) and AConfig.TryGetValue(ANode, 'Attributes', sAttr) then begin MaskItem := TMaskItem.Create; MaskItem.sName := sName; MaskItem.FColor[FStyle] := iColor; MaskItem.FColor[Abs(FStyle - 1)] := iColor; MaskItem.sExt := sExtMask; MaskItem.sModeStr := sAttr; FMaskItems.Add(MaskItem); end else begin DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; end; ANode := ANode.NextSibling; end; end; end; procedure TColorExt.Save(AConfig: TXmlConfig; ANode: TXmlNode); begin ANode:= AConfig.FindNode(ANode, 'FileFilters', False); if Assigned(ANode) then AConfig.DeleteNode(ANode); end; procedure TColorExt.Load(AConfig: TJSONObject); var I: Integer; AList: TJSONArray; AItem: TJSONObject; MaskItem: TMaskItem; AColors: TJSONArray; sAttr, sName, sExtMask: TJSONString; begin if not AConfig.Find('FileColors', AList) then Exit; for I:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[I]; if AItem.Find('Name', sName) and AItem.Find('Masks', sExtMask) and AItem.Find('Colors', AColors) and AItem.Find('Attributes', sAttr) then begin MaskItem := TMaskItem.Create; MaskItem.sName := sName.AsString; MaskItem.FColor[0] := AColors.Integers[0]; MaskItem.FColor[1] := AColors.Integers[1]; MaskItem.sExt := sExtMask.AsString; MaskItem.sModeStr := sAttr.AsString; FMaskItems.Add(MaskItem); end; end; end; procedure TColorExt.Save(AConfig: TJSONObject); var I: Integer; AList: TJSONArray; AItem: TJSONObject; AColors: TJSONArray; MaskItem: TMaskItem; begin if not Assigned(FMaskItems) then Exit; if AConfig.Find('FileColors', AList) then AList.Clear else begin AList:= TJSONArray.Create; AConfig.Add('FileColors', AList); end; for I:= 0 to FMaskItems.Count - 1 do begin MaskItem := TMaskItem(FMaskItems[I]); AItem:= TJSONObject.Create; AItem.Add('Name', MaskItem.sName); AItem.Add('Masks', MaskItem.sExt); AColors:= TJSONArray.Create; AColors.Add(MaskItem.FColor[0]); AColors.Add(MaskItem.FColor[1]); AItem.Add('Colors', AColors); AItem.Add('Attributes', MaskItem.sModeStr); AList.Add(AItem); end; end; procedure TColorExt.UpdateStyle; begin FStyle:= TColorThemes.StyleIndex; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uGlobsPaths.pas����������������������������������������������������������������0000644�0001750�0000144�00000005660�14743153644�016344� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uGlobsPaths; interface var gpExePath : String = ''; // executable directory gpCfgDir : String = ''; // directory from which configuration files are used gpGlobalCfgDir : String = ''; // config dir global for all user gpCmdLineCfgDir : String = ''; // config dir passed on the command line gpLngDir : String = ''; // path to language *.po files gpPixmapPath : String = ''; // path to pixmaps gpHighPath : String = ''; // editor highlighter directory gpCacheDir : String = ''; // cache directory gpThumbCacheDir : String = ''; // thumbnails cache directory //Global Configuration Filename const gcfExtensionAssociation : string = 'extassoc.xml'; procedure LoadPaths; procedure UpdateEnvironmentVariable; implementation uses SysUtils, LazFileUtils, uDebug, DCOSUtils, DCStrUtils, uSysFolders; var gpExeFile: String; function GetAppName : String; begin Result := 'doublecmd'; end; procedure UpdateEnvironmentVariable; begin mbSetEnvironmentVariable('COMMANDER_INI', gpCfgDir + 'doublecmd.xml'); mbSetEnvironmentVariable('DC_CONFIG_PATH', ExcludeTrailingPathDelimiter(gpCfgDir)); mbSetEnvironmentVariable('COMMANDER_INI_PATH', ExcludeTrailingPathDelimiter(gpCfgDir)); end; procedure LoadPaths; begin OnGetApplicationName := @GetAppName; if gpCmdLineCfgDir <> EmptyStr then begin if GetPathType(gpCmdLineCfgDir) <> ptAbsolute then gpCmdLineCfgDir := IncludeTrailingPathDelimiter(mbGetCurrentDir) + gpCmdLineCfgDir; gpCmdLineCfgDir := ExpandAbsolutePath(gpCmdLineCfgDir); gpCfgDir := gpCmdLineCfgDir; end else if mbFileExists(gpGlobalCfgDir + 'doublecmd.inf') then gpCfgDir := gpGlobalCfgDir else begin gpCfgDir := GetAppConfigDir; if gpCfgDir = EmptyStr then begin DCDebug('Warning: Cannot get user config directory.'); gpCfgDir := gpGlobalCfgDir; end; end; if gpCfgDir <> gpGlobalCfgDir then gpCacheDir := GetAppCacheDir else begin gpCacheDir := gpExePath + 'cache'; end; DCDebug('Executable directory: ', gpExePath); DCDebug('Configuration directory: ', gpCfgDir); DCDebug('Global configuration directory: ', gpGlobalCfgDir); gpCfgDir := IncludeTrailingPathDelimiter(gpCfgDir); gpLngDir := gpExePath + 'language' + DirectorySeparator; gpPixmapPath := gpExePath + 'pixmaps' + DirectorySeparator; gpHighPath:= gpExePath + 'highlighters' + DirectorySeparator; gpThumbCacheDir := gpCacheDir + PathDelim + 'thumbnails'; // set up environment variables UpdateEnvironmentVariable; mbSetEnvironmentVariable('COMMANDER_EXE', gpExeFile); mbSetEnvironmentVariable('COMMANDER_DRIVE', ExtractRootDir(gpExePath)); mbSetEnvironmentVariable('COMMANDER_PATH', ExcludeTrailingBackslash(gpExePath)); end; procedure Initialize; begin gpExeFile := ParamStr(0); gpExeFile := TryReadAllLinks(gpExeFile); gpExePath := ExtractFilePath(gpExeFile); gpGlobalCfgDir := gpExePath + 'settings' + DirectorySeparator; end; initialization Initialize; end. ��������������������������������������������������������������������������������doublecmd-1.1.22/src/uPinyin.pas��������������������������������������������������������������������0000644�0001750�0000144�00000002343�14743153644�015537� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uPinyin; interface type TPinyinArray = array[0..20901] of Word; function PinyinMatch(a,b:UnicodeChar):boolean; implementation Uses sysutils; var PINYINTABLE: TPinyinArray; PINYINTABLELOADED: boolean = False; procedure loadPinyinTable; var f: THandle; tblpath: String; begin tblpath := ExtractFilePath(Paramstr(0)) + 'pinyin.tbl'; if FileExists(tblpath) then begin f:= FileOpen(tblpath, fmOpenRead or fmShareDenyNone); if (f <> feInvalidHandle) then begin if FileRead(f, PINYINTABLE, SizeOf(TPinyinArray)) = SizeOf(TPinyinArray) then PINYINTABLELOADED := True; FileClose(f); end; end; end; function PinyinMatch(a,b:UnicodeChar):boolean; var i,code:word; j:byte; begin PinyinMatch := True; if a = b then exit; if PINYINTABLELOADED then begin if (Ord(a) >= 19968) and (Ord(a) <= 40869) then begin i := Ord(a) - 19968; code := PINYINTABLE[i]; j := code and 31; if(j > 0) and (j+96 = Ord(b)) then exit; j := code >> 5 and 31; if(j > 0) and (j+96 = Ord(b)) then exit; j := code >> 10 and 31; if(j > 0) and (j+96 = Ord(b)) then exit; end; end; PinyinMatch := False; end; initialization loadPinyinTable; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uShowMsg.pas�������������������������������������������������������������������0000644�0001750�0000144�00000071140�14743153644�015661� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ { Double commander ------------------------------------------------------------------------- Implementing of Showing messages with localization Copyright (C) 2007-2020 Alexander Koblov (alexx2000@mail.ru) This library 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 library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library. If not, see <http://www.gnu.org/licenses/>. } { Seksi Commander ---------------------------- Implementing of Showing messages with localization Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz contributors: Koblov Alexander (Alexx2000@mail.ru) } unit uShowMsg; {$mode delphi}{$H+} interface uses Forms, Classes, DCBasicTypes; type TMyMsgResult=(mmrOK, mmrNo, mmrYes, mmrCancel, mmrNone, mmrAppend, mmrResume, mmrCopyInto, mmrCopyIntoAll, mmrOverwrite, mmrOverwriteAll, mmrOverwriteOlder, mmrOverwriteSmaller, mmrOverwriteLarger, mmrAutoRenameSource, mmrAutoRenameTarget, mmrRenameSource, mmrSkip, mmrSkipAll, mmrIgnore, mmrIgnoreAll, mmrAll, mmrRetry, mmrAbort, mmrRetryAdmin, mmrUnlock); TMyMsgButton=(msmbOK, msmbNo, msmbYes, msmbCancel, msmbNone, msmbAppend, msmbResume, msmbCopyInto, msmbCopyIntoAll, msmbOverwrite, msmbOverwriteAll, msmbOverwriteOlder, msmbOverwriteSmaller, msmbOverwriteLarger, msmbAutoRenameSource, msmbAutoRenameTarget, msmbRenameSource, msmbSkip, msmbSkipAll, msmbIgnore, msmbIgnoreAll, msmbAll, msmbRetry, msmbAbort, msmbRetryAdmin, msmbUnlock, // Actions, they do not close the form and therefore have no corresponding result value: msmbCompare); TMyMsgActionButton = msmbCompare..High(TMyMsgButton); TMyMsgActionHandler = procedure(Button: TMyMsgActionButton) of object; { TDialogMainThread } TDialogMainThread = class private procedure SyncMsgBox; procedure SyncMessageBox; procedure SyncInputQuery; procedure SyncMessageChoiceBox; protected FThread: TThread; FCaption, FMessage, FValue: String; FMaskInput: Boolean; FFlags: Longint; FBtnDef, FBtnEsc: Integer; FButtons: array of TMyMsgButton; FButDefault, FButEscape: TMyMsgButton; FInputQueryResult: Boolean; FMsgBoxResult: TMyMsgResult; FMessageBoxResult: LongInt; FChoices: TDynamicStringArray; public constructor Create(AThread: TThread); destructor Destroy;override; function ShowMsgBox(const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape:TMyMsgButton) : TMyMsgResult; function ShowMessageBox(const AText, ACaption: String; Flags: LongInt): LongInt; function ShowMessageChoiceBox(const Message, ACaption: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; function ShowInputQuery(const ACaption, APrompt: String; MaskInput: Boolean; var Value: String) : Boolean; end; function msgYesNo(const sMsg: String; ButDefault: TMyMsgButton = msmbYes): Boolean; overload; function msgYesNo(Thread: TThread; const sMsg: String): Boolean; overload; function msgYesNoCancel(const sMsg: String; ButDefault: TMyMsgButton = msmbYes):TMyMsgResult; overload; function msgYesNoCancel(Thread: TThread; const sMsg: String): TMyMsgResult; overload; procedure msgOK(const sMsg: String); overload; procedure msgOK(Thread: TThread; const sMsg: String); overload; procedure msgWarning(const sMsg: String); overload; procedure msgWarning(Thread: TThread; const sMsg: String); overload; procedure msgError(const sMsg: String); overload; procedure msgError(Thread: TThread; const sMsg: String); overload; function MsgBox(const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape: TMyMsgButton; ActionHandler: TMyMsgActionHandler = nil): TMyMsgResult; overload; function MsgBox(Thread: TThread; const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape: TMyMsgButton): TMyMsgResult; overload; function MsgTest:TMyMsgResult; function MsgChoiceBox(const Message: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; overload; function MsgChoiceBox(const Message, ACaption: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; overload; function MsgChoiceBox(Thread: TThread; const Message: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; overload; function MsgChoiceBox(Thread: TThread; const Message, ACaption: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; overload; function ShowMessageBox(const AText, ACaption: String; Flags: LongInt): LongInt; overload; function ShowMessageBox(Thread: TThread; const AText, ACaption: String; Flags: LongInt): LongInt; overload; function ShowInputQuery(const ACaption, APrompt: String; MaskInput: Boolean; var Value: String): Boolean; overload; function ShowInputQuery(Thread: TThread; const ACaption, APrompt: String; MaskInput: Boolean; var Value: String): Boolean; overload; function ShowInputQuery(const ACaption, APrompt: String; var Value: String): Boolean; overload; function ShowInputQuery(Thread: TThread; const ACaption, APrompt: String; var Value: String): Boolean; overload; function ShowInputComboBox(const sCaption, sPrompt : String; slValueList : TStringList; var sValue : String) : Boolean; function ShowInputListBox(const sCaption, sPrompt : String; slValueList : TStringList; var sValue : String; var SelectedChoice:integer) : Boolean; function ShowInputMultiSelectListBox(const sCaption, sPrompt : String; slValueList, slOutputIndexSelected : TStringList) : Boolean; procedure msgLoadLng; implementation uses LCLIntf, SysUtils, StdCtrls, Graphics, Math, typinfo, Menus, fMsg, uLng, Buttons, Controls, uLog, uGlobs, uDebug; const cMsgName = 'Double Commander'; var cLngButton: array[TMyMsgButton] of String; { TDialogMainThread } procedure TDialogMainThread.SyncMsgBox; begin FMsgBoxResult:= MsgBox(FMessage, FButtons, FButDefault, FButEscape); end; procedure TDialogMainThread.SyncMessageBox; begin FMessageBoxResult:= MessageBoxFunction(PAnsiChar(FMessage), PAnsiChar(FCaption), FFlags); end; procedure TDialogMainThread.SyncInputQuery; begin FInputQueryResult := LCLIntf.RequestInput(FCaption, FMessage, FMaskInput, FValue); end; procedure TDialogMainThread.SyncMessageChoiceBox; begin FMessageBoxResult:= MsgChoiceBox(FMessage, FCaption, FChoices, FBtnDef, FBtnEsc); end; constructor TDialogMainThread.Create(AThread : TThread); begin FThread:= AThread; end; destructor TDialogMainThread.Destroy; begin FButtons:= nil; inherited Destroy; end; function TDialogMainThread.ShowMsgBox(const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape: TMyMsgButton) : TMyMsgResult; var I : Integer; begin FMessage := sMsg; SetLength(FButtons, Length(Buttons)); for I := Low(Buttons) to High(Buttons) do FButtons[I] := Buttons[I]; FButDefault := ButDefault; FButEscape := ButEscape; TThread.Synchronize(FThread, SyncMsgBox); Result := FMsgBoxResult; end; function TDialogMainThread.ShowMessageBox(const AText, ACaption: String; Flags: LongInt): LongInt; begin FCaption:= ACaption; FMessage:= AText; FFlags:= Flags; TThread.Synchronize(FThread, SyncMessageBox); Result:= FMessageBoxResult; end; function TDialogMainThread.ShowMessageChoiceBox(const Message, ACaption: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; begin FBtnDef:= BtnDef; FBtnEsc:= BtnEsc; FMessage:= Message; FChoices:= Buttons; FCaption:= ACaption; TThread.Synchronize(FThread, SyncMessageChoiceBox); Result:= FMessageBoxResult; end; function TDialogMainThread.ShowInputQuery(const ACaption, APrompt: String; MaskInput: Boolean; var Value: String): Boolean; begin FCaption:= ACaption; FMessage:= APrompt; FMaskInput:= MaskInput; FValue:= Value; TThread.Synchronize(FThread, SyncInputQuery); Value:= FValue; Result:= FInputQueryResult; end; procedure SetMsgBoxParams(var frmMsg: TfrmMsg; const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape: TMyMsgButton); procedure FormShowEvent(Self, Sender: TCustomForm); begin if (Self.Tag <> 0) and (TObject(Self.Tag) is TButton) then SendMessage(TButton(Self.Tag).Handle, $160C, 0, 1); end; const cButtonCount = 8; cButtonSpace = 8; var iIndex: Integer; iCount: Integer; Handler: TMethod; MenuItem: TMenuItem; CaptionWidth: Integer; More: Boolean = False; MinButtonWidth: Integer; iIndexDefault : Integer = -1; begin Assert(Assigned(frmMsg)); frmMsg.Position:= poScreenCenter; frmMsg.BorderStyle:= bsSingle; frmMsg.BorderIcons:= [biSystemMenu]; frmMsg.Caption:= cMsgName; frmMsg.lblMsg.Caption:= sMsg; // Get default button width with TButton.Create(nil) do begin MinButtonWidth:= GetDefaultWidth; Free; end; // Determine number of buttons iCount:= High(Buttons); if iCount > cButtonCount then begin More:= True; iCount:= cButtonCount - 1; CaptionWidth:= frmMsg.Canvas.TextWidth(rsDlgButtonOther); if CaptionWidth >= (MinButtonWidth - cButtonSpace) then MinButtonWidth:= CaptionWidth + cButtonSpace; end; // Calculate minimum button width for iIndex:= Low(Buttons) to iCount do begin CaptionWidth:= frmMsg.Canvas.TextWidth(cLngButton[Buttons[iIndex]]); if CaptionWidth >= (MinButtonWidth - cButtonSpace) then MinButtonWidth:= CaptionWidth + cButtonSpace; end; // Add first 9 items as buttons for iIndex:= Low(Buttons) to iCount do begin with TButton.Create(frmMsg) do begin {$IF DEFINED(LCLCOCOA)} Constraints.MinHeight:= 34; {$ENDIF} AutoSize:= True; Caption:= cLngButton[Buttons[iIndex]]; Parent:= frmMsg.pnlButtons; Constraints.MinWidth:= MinButtonWidth; if Buttons[iIndex] >= Low(TMyMsgActionButton) then Tag:= -2-iIndex else Tag:= iIndex; if Buttons[iIndex] = msmbRetryAdmin then begin Handler.Data:= frmMsg; frmMsg.Tag:= GetHashCode; Handler.Code:= @FormShowEvent; frmMsg.OnShow:= TNotifyEvent(Handler); Constraints.MinWidth:= MinButtonWidth + GetSystemMetrics(49); end; OnClick:= frmMsg.ButtonClick; OnMouseUp:= frmMsg.MouseUpEvent; if Buttons[iIndex] = ButDefault then begin Default:= True; iIndexDefault:=iIndex; end; if Buttons[iIndex] = ButEscape then frmMsg.Escape:= iIndex; end; end; //Once the buttons has been added, let's set the correct "TabOrder" in such way: //1o) The one with the default is "TabOrder=0" //2o) If we press "TAB" key, it keeps moving to the right //Let's determine what should be the "TabOrder" initial value so //1. The default button will have tab order 0 //2. When moving with "tab" key, it will move from left to right //"TabOrder" need to be set *after* all the buttons are there if iIndexDefault<>-1 then begin for iIndex:= 0 to pred(frmMsg.ComponentCount) do begin if frmMsg.Components[iIndex] is TButton then with frmMsg.Components[iIndex] as TButton do begin if Tag >= 0 then TabOrder:= (Tag+(iCount+1)-iIndexDefault) mod (iCount+1) //Tricky but it does it, no "if", no negative after to check, etc. else TabOrder:= (-2-Tag+(iCount+1)-iIndexDefault) mod (iCount+1); end; end; end; // More add as popup menu if More then begin // Add button with popup menu with TButton.Create(frmMsg) do begin AutoSize:= True; Caption:= rsDlgButtonOther; Parent:= frmMsg.pnlButtons; Constraints.MinWidth:= MinButtonWidth; OnClick:= frmMsg.ButtonOtherClick; end; // Fill popup menu for iIndex:= cButtonCount to High(Buttons) do begin MenuItem:= TMenuItem.Create(frmMsg.mnuOther); with MenuItem do begin if Buttons[iIndex] >= Low(TMyMsgActionButton) then Tag:= -2-iIndex else Tag:= iIndex; Caption:= cLngButton[Buttons[iIndex]]; OnClick:= frmMsg.ButtonClick; frmMsg.mnuOther.Items.Add(MenuItem); end; end; end; end; type TMsgBoxHelper = class Buttons: array of TMyMsgButton; ActionHandler: TMyMsgActionHandler; procedure MsgBoxActionHandler(Tag: PtrInt); end; procedure TMsgBoxHelper.MsgBoxActionHandler(Tag: PtrInt); begin ActionHandler(Buttons[-Tag-2]); end; function MsgBox(const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape: TMyMsgButton; ActionHandler: TMyMsgActionHandler = nil): TMyMsgResult; var frmMsg:TfrmMsg; MsgBoxHelper: TMsgBoxHelper = nil; I: Integer; begin frmMsg:=TfrmMsg.Create(Application); try MsgBoxHelper := TMsgBoxHelper.Create(); SetLength(MsgBoxHelper.Buttons, Length(Buttons)); for I := Low(Buttons) to High(Buttons) do MsgBoxHelper.Buttons[I] := Buttons[I]; MsgBoxHelper.ActionHandler := ActionHandler; frmMsg.ActionHandler := MsgBoxHelper.MsgBoxActionHandler; SetMsgBoxParams(frmMsg, sMsg, Buttons, ButDefault, ButEscape); frmMsg.ShowModal; if (frmMsg.iSelected)=-1 then Result:=mmrNone else { TODO : not safe code because of direct typecast from one enumeration to another, better to use array lookup } Result:=TMyMsgResult(Buttons[frmMsg.iSelected]); finally frmMsg.Free; MsgBoxHelper.Free; end; end; function MsgBox(Thread: TThread; const sMsg: String; const Buttons: array of TMyMsgButton; ButDefault, ButEscape: TMyMsgButton): TMyMsgResult; var DialogMainThread : TDialogMainThread; begin Result := mmrNone; DialogMainThread := TDialogMainThread.Create(Thread); try Result := DialogMainThread.ShowMsgBox(sMsg, Buttons, ButDefault, ButEscape); finally DialogMainThread.Free; end; end; Function MsgTest:TMyMsgResult; begin Result:= MsgBox('test language of msg subsystem'#10'Second line',[msmbOK, msmbNO, msmbYes, msmbCancel, msmbNone, msmbAppend, msmbOverwrite, msmbOverwriteAll],msmbOK, msmbNO); end; function msgYesNo(const sMsg: String; ButDefault: TMyMsgButton = msmbYes):Boolean; begin Result:= MsgBox(nil, sMsg,[msmbYes, msmbNo], ButDefault, msmbNo )= mmrYes; end; function msgYesNo(Thread: TThread; const sMsg: String): Boolean; begin Result:= MsgBox(Thread, sMsg,[msmbYes, msmbNo], msmbYes, msmbNo )= mmrYes; end; function msgYesNoCancel(const sMsg: String; ButDefault: TMyMsgButton = msmbYes):TMyMsgResult; begin Result:= MsgBox(sMsg,[msmbYes, msmbNo, msmbCancel], ButDefault, msmbCancel); end; function msgYesNoCancel(Thread: TThread; const sMsg: String): TMyMsgResult; begin Result:= MsgBox(Thread, sMsg,[msmbYes, msmbNo, msmbCancel], msmbYes, msmbCancel); end; procedure msgOK(const sMsg: String); begin MsgBox(sMsg,[msmbOK],msmbOK, msmbOK); end; procedure msgOK(Thread: TThread; const sMsg: String); begin MsgBox(Thread, sMsg,[msmbOK],msmbOK, msmbOK); end; procedure msgError(const sMsg: String); begin MsgBox(sMsg,[msmbOK],msmbOK, msmbOK); end; procedure msgError(Thread: TThread; const sMsg: String); begin MsgBox(Thread, sMsg,[msmbOK],msmbOK, msmbOK) end; procedure msgWarning(const sMsg: String); begin if gShowWarningMessages then MsgBox(sMsg,[msmbOK],msmbOK, msmbOK) else begin if gLogWindow then // if log window enabled then write error to it logWrite(sMsg, lmtError) else Beep; end; end; procedure msgWarning(Thread: TThread; const sMsg: String); begin if gShowWarningMessages then MsgBox(Thread, sMsg,[msmbOK],msmbOK, msmbOK) else begin if gLogWindow then // if log window enabled then write error to it logWrite(Thread, sMsg, lmtError) else Beep; end; end; function ShowMessageBox(const AText, ACaption: String; Flags: LongInt): LongInt; begin Result:= ShowMessageBox(nil, AText, ACaption, Flags); end; function ShowMessageBox(Thread: TThread; const AText, ACaption: String; Flags: LongInt): LongInt; var DialogMainThread : TDialogMainThread; begin Result:= 0; DialogMainThread:= TDialogMainThread.Create(Thread); try Result:= DialogMainThread.ShowMessageBox(AText, ACaption, Flags); finally DialogMainThread.Free; end; end; function ShowInputQuery(const ACaption, APrompt: String; MaskInput: Boolean; var Value: String): Boolean; overload; begin Result:= ShowInputQuery(nil, ACaption, APrompt, MaskInput, Value); end; function ShowInputQuery(Thread: TThread; const ACaption, APrompt: String; MaskInput: Boolean; var Value: String): Boolean; var DialogMainThread : TDialogMainThread; begin Result := False; DialogMainThread:= TDialogMainThread.Create(Thread); try Result:= DialogMainThread.ShowInputQuery(ACaption, APrompt, MaskInput, Value); finally DialogMainThread.Free; end; end; function ShowInputQuery(const ACaption, APrompt: String; var Value: String): Boolean; overload; begin Result:= ShowInputQuery(nil, ACaption, APrompt, False, Value); end; function ShowInputQuery(Thread: TThread; const ACaption, APrompt: String; var Value: String): Boolean; begin Result:= ShowInputQuery(Thread, ACaption, APrompt, False, Value); end; function ShowInputComboBox(const sCaption, sPrompt : String; slValueList : TStringList; var sValue : String) : Boolean; var Index: Integer; frmDialog : TForm; lblPrompt : TLabel; cbValue : TComboBox; bbtnOK, bbtnCancel : TBitBtn; begin frmDialog := TForm.CreateNew(nil, 0); with frmDialog do try BorderStyle := bsDialog; Position := poScreenCenter; AutoSize := True; Height := 120; ChildSizing.TopBottomSpacing := 8; ChildSizing.LeftRightSpacing := 8; Caption := sCaption; lblPrompt := TLabel.Create(frmDialog); with lblPrompt do begin Parent := frmDialog; Caption := sPrompt; Top := 6; Left := 6; end; cbValue := TComboBox.Create(frmDialog); with cbValue do begin Parent := frmDialog; Items.Assign(slValueList); Text := sValue; Left := 6; AnchorToNeighbour(akTop, 6, lblPrompt); Constraints.MinWidth := max(280, Screen.Width div 4); end; bbtnCancel := TBitBtn.Create(frmDialog); with bbtnCancel do begin Parent := frmDialog; Kind := bkCancel; Cancel := True; Left := 6; Width:= 90; Anchors := [akTop, akRight]; AnchorToNeighbour(akTop, 18, cbValue); AnchorSide[akRight].Control := cbValue; AnchorSide[akRight].Side := asrRight; end; bbtnOK := TBitBtn.Create(frmDialog); with bbtnOK do begin Parent := frmDialog; Kind := bkOk; Default := True; Width:= 90; Anchors := [akTop, akRight]; AnchorToNeighbour(akTop, 18, cbValue); AnchorToNeighbour(akRight, 6, bbtnCancel); end; Result := (ShowModal = mrOK); if Result then begin Index:= slValueList.IndexOf(cbValue.Text); if Index < 0 then slValueList.Add(cbValue.Text) else begin slValueList.Move(Index, 0); end; sValue := cbValue.Text; end; finally FreeAndNil(frmDialog); end; // with frmDialog end; type TProcedureHolder=class(TObject) public procedure ListBoxDblClick(Sender: TObject); end; procedure TProcedureHolder.ListBoxDblClick(Sender: TObject); begin TForm(TComponent(Sender).Owner).ModalResult:=mrOk; end; function InnerShowInputListBox(const sCaption, sPrompt: String; bMultiSelect:boolean; slValueList,slOutputIndexSelected:TStringList; var sValue: String; var SelectedChoice:integer) : Boolean; var frmDialog : TForm; lblPrompt : TLabel; lbValue : TListBox; bbtnOK, bbtnCancel, bbtnSelectAll : TBitBtn; iIndex, iModalResult: integer; ProcedureHolder:TProcedureHolder; begin SelectedChoice:=-1; ProcedureHolder:=TProcedureHolder.Create; try frmDialog := TForm.CreateNew(nil, 0); with frmDialog do try BorderStyle := bsDialog; Position := poScreenCenter; AutoSize := True; Height := 120; ChildSizing.TopBottomSpacing := 8; ChildSizing.LeftRightSpacing := 8; Caption := sCaption; lblPrompt := TLabel.Create(frmDialog); with lblPrompt do begin Parent := frmDialog; Caption := sPrompt; Top := 6; Left := 6; end; lbValue := TListBox.Create(frmDialog); with lbValue do begin Parent := frmDialog; Height := (slValueList.Count*15)+50; if height=0 then Height:=150 else if height > (screen.Height div 2) then height := (Screen.Height div 2); Items.Assign(slValueList); ItemIndex:=Items.IndexOf(sValue); lbValue.MultiSelect:=bMultiSelect; if (ItemIndex=-1) AND (Items.count>0) then ItemIndex:=0; Left := 6; AnchorToNeighbour(akTop, 6, lblPrompt); Constraints.MinWidth := max(280, Screen.Width div 4); OnDblClick:= ProcedureHolder.ListBoxDblClick; end; if bMultiSelect then begin bbtnSelectAll := TBitBtn.Create(frmDialog); with bbtnSelectAll do begin Parent := frmDialog; Kind := bkAll; Cancel := True; Left := 6; Width:= 90; Anchors := [akTop, akLeft]; AnchorToNeighbour(akTop, 18, lbValue); AnchorSide[akLeft].Control := lbValue; AnchorSide[akLeft].Side := asrLeft; end; end; bbtnCancel := TBitBtn.Create(frmDialog); with bbtnCancel do begin Parent := frmDialog; Kind := bkCancel; Cancel := True; Left := 6; Width:= 90; Anchors := [akTop, akRight]; AnchorToNeighbour(akTop, 18, lbValue); AnchorSide[akRight].Control := lbValue; AnchorSide[akRight].Side := asrRight; end; bbtnOK := TBitBtn.Create(frmDialog); with bbtnOK do begin Parent := frmDialog; Kind := bkOk; Default := True; Width:= 90; Anchors := [akTop, akRight]; AnchorToNeighbour(akTop, 18, lbValue); AnchorToNeighbour(akRight, 6, bbtnCancel); end; iModalResult:=ShowModal; Result := (iModalResult = mrOK) AND (lbValue.ItemIndex<>-1); if (not Result) AND (bMultiSelect) AND (iModalResult = mrAll) then begin lbValue.SelectAll; Result:=True; end; if Result then begin sValue:=lbValue.Items.Strings[lbValue.ItemIndex]; SelectedChoice:=lbValue.ItemIndex; if bMultiSelect then for iIndex:=0 to pred(lbValue.Items.count) do if lbValue.Selected[iIndex] then slOutputIndexSelected.Add(IntToStr(iIndex)); end; finally FreeAndNil(frmDialog); end; // with frmDialog finally ProcedureHolder.Free; end; end; function ShowInputListBox(const sCaption, sPrompt : String; slValueList : TStringList; var sValue : String; var SelectedChoice:integer) : Boolean; begin result := InnerShowInputListBox(sCaption, sPrompt, False, slValueList, nil, sValue, SelectedChoice); end; function ShowInputMultiSelectListBox(const sCaption, sPrompt : String; slValueList, slOutputIndexSelected : TStringList) : Boolean; var sDummyValue:string; iDummySelectedChoice:integer; begin if slValueList.Count>0 then sDummyValue := slValueList.Strings[0]; result := InnerShowInputListBox(sCaption, sPrompt, True, slValueList, slOutputIndexSelected, sDummyValue, iDummySelectedChoice); end; function MsgChoiceBox(const Message: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; begin Result:= MsgChoiceBox(Message, EmptyStr, Buttons, BtnDef, BtnEsc); end; function MsgChoiceBox(const Message, ACaption: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; const cButtonSpace = 8; var Index: Integer; frmMsg: TfrmMsg; CaptionWidth: Integer; MinButtonWidth, iCount: Integer; begin frmMsg:= TfrmMsg.Create(Application); try frmMsg.BorderStyle:= bsSingle; frmMsg.Position:= poScreenCenter; frmMsg.BorderIcons:= [biSystemMenu]; if Length(ACaption) > 0 then frmMsg.Caption:= ACaption else begin frmMsg.Caption:= Application.Title; end; frmMsg.lblMsg.WordWrap:= True; frmMsg.lblMsg.Caption:= Message; frmMsg.Constraints.MaxWidth:= 600; // Get default button width with TButton.Create(nil) do begin MinButtonWidth:= GetDefaultWidth; Free; end; // Calculate minimum button width for Index:= Low(Buttons) to High(Buttons) do begin CaptionWidth:= frmMsg.Canvas.TextWidth(Buttons[Index]); if CaptionWidth >= (MinButtonWidth - cButtonSpace) then MinButtonWidth:= CaptionWidth + cButtonSpace; end; iCount:= Length(Buttons); // Add all buttons for Index:= Low(Buttons) to High(Buttons) do begin with TButton.Create(frmMsg) do begin Tag:= Index; AutoSize:= True; Caption:= Buttons[Index]; Parent:= frmMsg.pnlButtons; OnClick:= frmMsg.ButtonClick; Constraints.MinWidth:= MinButtonWidth; if Index = BtnDef then Default:= True else if (Index = BtnEsc) then begin Cancel:= True; frmMsg.Escape:= BtnEsc; end; if BtnDef > -1 then begin TabOrder:= (Tag + iCount - BtnDef) mod iCount; end; end; end; frmMsg.ShowModal; Result:= frmMsg.iSelected; finally frmMsg.Free; end; end; function MsgChoiceBox(Thread: TThread; const Message: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; begin Result:= MsgChoiceBox(Thread, Message, EmptyStr, Buttons, BtnDef, BtnEsc); end; function MsgChoiceBox(Thread: TThread; const Message, ACaption: String; Buttons: TDynamicStringArray; BtnDef, BtnEsc: Integer): Integer; var DialogMainThread : TDialogMainThread; begin Result := -1; DialogMainThread:= TDialogMainThread.Create(Thread); try Result:= DialogMainThread.ShowMessageChoiceBox(Message, ACaption, Buttons, BtnDef, BtnEsc); finally DialogMainThread.Free; end; end; procedure msgLoadLng; var I: TMyMsgButton; begin cLngButton[msmbOK] := rsDlgButtonOK; cLngButton[msmbNo] := rsDlgButtonNo; cLngButton[msmbYes] := rsDlgButtonYes; cLngButton[msmbCancel] := rsDlgButtonCancel; cLngButton[msmbNone] := rsDlgButtonNone; cLngButton[msmbAppend] := rsDlgButtonAppend; cLngButton[msmbResume] := rsDlgButtonResume; cLngButton[msmbCopyInto] := rsDlgButtonCopyInto; cLngButton[msmbCopyIntoAll] := rsDlgButtonCopyIntoAll; cLngButton[msmbOverwrite] := rsDlgButtonOverwrite; cLngButton[msmbOverwriteAll] := rsDlgButtonOverwriteAll; cLngButton[msmbOverwriteOlder] := rsDlgButtonOverwriteOlder; cLngButton[msmbOverwriteSmaller] := rsDlgButtonOverwriteSmaller; cLngButton[msmbOverwriteLarger] := rsDlgButtonOverwriteLarger; cLngButton[msmbAutoRenameSource] := rsDlgButtonAutoRenameSource; cLngButton[msmbAutoRenameTarget] := rsDlgButtonAutoRenameTarget; cLngButton[msmbRenameSource] := rsDlgButtonRename; cLngButton[msmbSkip] := rsDlgButtonSkip; cLngButton[msmbSkipAll] := rsDlgButtonSkipAll; cLngButton[msmbIgnore] := rsDlgButtonIgnore; cLngButton[msmbIgnoreAll] := rsDlgButtonIgnoreAll; cLngButton[msmbAll] := rsDlgButtonAll; cLngButton[msmbRetry] := rsDlgButtonRetry; cLngButton[msmbAbort] := rsDlgButtonAbort; cLngButton[msmbRetryAdmin] := rsDlgButtonRetryAdmin; cLngButton[msmbUnlock] := rsDlgButtonUnlock; cLngButton[msmbCompare] := rsDlgButtonCompare; for I:= Low(TMyMsgButton) to High(TMyMsgButton) do begin // A reminder in case someone forgots to assign text. if cLngButton[I] = EmptyStr then DCDebug('Warning: MsgBox button ' + GetEnumName(TypeInfo(TMyMsgButton), Integer(I)) + ' caption not set.'); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uaccentsutils.pas��������������������������������������������������������������0000644�0001750�0000144�00000016451�14743153644�016777� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Routine related with characters with accents/ligatures and their equivalents without Copyright (C) 2016 Alexander Koblov (alexx2000@mail.ru) 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 } unit uAccentsUtils; {$mode objfpc}{$H+} interface uses Classes, SysUtils; procedure LoadInMemoryOurAccentLookupTableList; procedure FreeMemoryFromOurAccentLookupTableList; function NormalizeAccentedChar(sInput: string): string; function PosOfSubstrWithVersatileOptions(sSubString, sWholeString: string; bCaseSensitive, bIgnoreAccent: boolean; var ActualCharFittedInInput: integer): integer; var gslAccents, gslAccentsStripped: TStringList; resourcestring rsStrAccents = 'á;â;à;å;ã;ä;ç;é;ê;è;ë;í;î;ì;ï;ñ;ó;ô;ò;ø;õ;ö;ú;û;ù;ü;ÿ;Á;Â;À;Å;Ã;Ä;Ç;É;Ê;È;Ë;Í;Í;Ì;Ï;Ñ;Ó;Ô;Ø;Õ;Ö;ß;Ú;Û;Ù;Ü;Ÿ;¿;¡;œ;æ;Æ;Œ'; rsStrAccentsStripped = 'a;a;a;a;a;a;c;e;e;e;e;i;i;i;i;n;o;o;o;o;o;o;u;u;u;u;y;A;A;A;A;A;A;C;E;E;E;E;I;I;I;I;N;O;O;O;O;O;B;U;U;U;U;Y;?;!;oe;ae;AE;OE'; implementation uses //Lazarus, Free-Pascal, etc. LazUTF8, //DC DCStrUtils; { LoadInMemoryOurAccentLookupTableList } procedure LoadInMemoryOurAccentLookupTableList; var slTempoAccents, slTempoAccentsStripped: TStringList; iChar, iPos: integer; begin slTempoAccents := TStringList.Create; slTempoAccentsStripped := TStringList.Create; try ParseLineToList(rsStrAccents, slTempoAccents); ParseLineToList(rsStrAccentsStripped, slTempoAccentsStripped); if slTempoAccents.Count <> slTempoAccentsStripped.Count then raise Exception.Create('Unexpected situation in LoadInMemoryOurAccentLookupTableList!' + #$0A + 'Most probably problem in language file regarding conversion string with accents...'); gslAccents := TStringList.Create; gslAccents.Assign(slTempoAccents); gslAccents.Sort; gslAccentsStripped := TStringList.Create; for iChar := 0 to pred(gslAccents.Count) do begin iPos := slTempoAccents.IndexOf(gslAccents.Strings[iChar]); if iPos <> -1 then gslAccentsStripped.add(slTempoAccentsStripped.Strings[iPos]) else raise Exception.Create('Unexpected situation in LoadInMemoryOurAccentLookupTableList! (Error in Rejavik)'); end; if gslAccents.Count <> gslAccentsStripped.Count then raise Exception.Create('Unexpected situation in LoadInMemoryOurAccentLookupTableList! (Error in Mexico)'); finally FreeAndNil(slTempoAccents); FreeAndNil(slTempoAccentsStripped); end; end; { FreeMemoryFromOurAccentLookupTableList } procedure FreeMemoryFromOurAccentLookupTableList; begin if gslAccents <> nil then FreeAndNil(gslAccents); if gslAccentsStripped <> nil then FreeAndNil(gslAccentsStripped); end; { NormalizeAccentedChar } function NormalizeAccentedChar(sInput: string): string; var iIndexChar, iPosChar: integer; cWorkingChar: string; begin Result := ''; for iIndexChar := 1 to UTF8length(sInput) do begin cWorkingChar := UTF8Copy(sInput, iIndexChar, 1); iPosChar := gslAccents.IndexOf(cWorkingChar); if iPosChar = -1 then Result := Result + cWorkingChar else Result := Result + gslAccentsStripped.Strings[iPosChar]; end; end; { PosOfSubstrWithVersatileOptions } // NOTE: Function will search "sSubString" inside the "sWholeString" and return the position where it found it. // WARNING! Function is assuming the "sSubString" is already preformated adequately and won't do it. // For example, if we do a search case insensitive, it is assumed you arrived here with "sSubString" already in UTF8UpperCase. So with "ABC" and not "abc". // For example, if you search ignoring accent, it is assumed you arrived here with "sSubString" already without accents. So with "aei" and not "àéî". // For example, if you search ignoring ligature, it is assumed you arrived here with "sSubString" already without ligature. So with "oe" and not with "œ". // No need to preformat, obviously, the "sWholeString". // ALL this is to speed up a little things since often we'll search the SAME string over and over in a whole string. // We'll gain something preparing our "sWholeString" once for all AND THEN keep re-searhcing in many strings using the following routine. // ALSO, because of the ligature possibility, the parameter "ActualCharFittedInInput" will be set according to the number of chars from the "sWholeString" that was used for finding the "sSubString". // For example, if we search "oeu" inside "soeur", the return value will be 2 and the "ActualCharFittedInInput" will be set to 3... // But if we search "oeu" inside "sœur", the return value will still be 2 BUT the "ActualCharFittedInInput" will be set to 2 since only two chars were required! // The author of this doesn't know for other language, but for French, this is a nice routine! :-) function PosOfSubstrWithVersatileOptions(sSubString, sWholeString: string; bCaseSensitive, bIgnoreAccent: boolean; var ActualCharFittedInInput: integer): integer; var sLocal: string; iActualPos: integer; iInnerResult: integer = 0; begin ActualCharFittedInInput := 0; if bIgnoreAccent then sLocal := NormalizeAccentedChar(sWholeString) else sLocal := sWholeString; if not bCaseSensitive then sLocal := UTF8UpperCase(sLocal); iInnerResult := UTF8Pos(sSubString, sLocal); if iInnerResult > 0 then begin iActualPos := 0; sLocal := ''; while (UTF8Length(sLocal) < iInnerResult) and (iActualPos < length(sWholeString)) do begin Inc(iActualPos); if bIgnoreAccent then sLocal := sLocal + NormalizeAccentedChar(UTF8copy(sWholeString, iActualPos, 1)) else sLocal := sLocal + UTF8copy(sWholeString, iActualPos, 1); end; Result := iActualPos; //Once here, "iActualPos" holds the actual position of our substring in the string. //Then, we now add the char one by one until it match what were where searching AND IT SHOULD MATCH because "iInnerResult" has a value. sLocal := ''; while (UTF8Pos(sSubString, sLocal) = 0) and ((Result + ActualCharFittedInInput) <= UTF8Length(sWholeString)) do begin Inc(ActualCharFittedInInput); sLocal := UTF8copy(sWholeString, Result, ActualCharFittedInInput); if bIgnoreAccent then sLocal := NormalizeAccentedChar(sLocal) else sLocal := sLocal; if not bCaseSensitive then sLocal := UTF8UpperCase(sLocal); end; end else begin Result := 0; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ubinarydiffviewer.pas����������������������������������������������������������0000644�0001750�0000144�00000015436�14743153644�017637� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Binary difference viewer and comparator Copyright (C) 2014-2024 Alexander Koblov (alexx2000@mail.ru) 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 } unit uBinaryDiffViewer; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, ViewerControl; type { TBinaryDiffViewer } TBinaryDiffViewer = class(TViewerControl) private FModified: TColor; FScrollLock: Integer; FKeepScrolling: Boolean; FSecondViewer: TBinaryDiffViewer; protected procedure WriteCustom; override; procedure SetPosition(Value: PtrInt); override; public constructor Create(AOwner: TComponent); override; property KeepScrolling: Boolean read FKeepScrolling write FKeepScrolling; property SecondViewer: TBinaryDiffViewer read FSecondViewer write FSecondViewer; property Modified: TColor read FModified write FModified; property LastError: String read FLastError; end; { TBinaryCompare } TBinaryCompare = class(TThread) private FFirst, FSecond: PByte; FFinish: PtrInt; FEqual: Boolean; FResult: TFPList; FOnFinish: TThreadMethod; protected procedure Execute; override; public constructor Create(First, Second: PByte; FirstSize, SecondSize: PtrInt; Result: TFPList); property OnFinish: TThreadMethod read FOnFinish write FOnFinish; end; implementation uses Math, LazUTF8; const cHexWidth = 16; cHexOffsetWidth = 8; cHexStartHex = cHexOffsetWidth + 2; // ': ' cHexStartAscii = cHexStartHex + (cHexWidth * 3) + 2; // ' ' { TBinaryDiffViewer } procedure TBinaryDiffViewer.WriteCustom; const cWordSize = 3; var I: Integer; X, Y: Integer; yIndex: Integer; CharLen: Integer; P1, P2: PAnsiChar; CurrentPos, SecondPos: PtrInt; Mine, Foreign, WordHex: String; WordWidth, SymbolWidth: Integer; MineLength, ForeignLength: Integer; SymbolColor: array[0..15] of TColor; begin CurrentPos := Position; SymbolWidth := Canvas.TextWidth('W'); WordWidth := SymbolWidth * cWordSize; // Draw visible lines for yIndex := 0 to GetClientHeightInLines - 1 do begin if CurrentPos >= FHighLimit then Break; // Draw if second viewer exists if Assigned(SecondViewer) then begin X := 0; SecondPos := CurrentPos; Y := yIndex * FTextHeight; AddLineOffset(CurrentPos); // Mine text Mine := TransformHex(CurrentPos, FHighLimit); MineLength:= Min(cHexWidth, (Length(Mine) - cHexStartHex) div cWordSize); // Foreign text if SecondPos >= SecondViewer.FHighLimit then begin Foreign := Mine; ForeignLength := -1; end else begin Foreign := SecondViewer.TransformHex(SecondPos, SecondViewer.FHighLimit); ForeignLength:= (Length(Foreign) - cHexStartHex) div cWordSize; end; // Pointers to text P1 := PAnsiChar(Mine) + cHexStartHex; P2 := PAnsiChar(Foreign) + cHexStartHex; // Write line number Canvas.TextOut(X, Y, Copy(Mine, 1, cHexStartHex)); X := X + SymbolWidth * cHexStartHex; // Write hex part for I := 0 to MineLength - 1 do begin if (I > ForeignLength) or (PWord(P1)^ <> PWord(P2)^) then Canvas.Font.Color := FModified else Canvas.Font.Color := clWindowText; SymbolColor[I]:= Canvas.Font.Color; WordHex:= Copy(P1, 1, cWordSize); Canvas.TextOut(X, Y, WordHex); Inc(X, WordWidth); Inc(P1, cWordSize); Inc(P2, cWordSize) end; Inc(X, SymbolWidth); // Write ASCII part WordHex:= Copy(Mine, cHexStartAscii + 1, MaxInt); I:= 0; P1:= PAnsiChar(WordHex); P2:= P1 + Length(WordHex); while (P1 < P2) do begin CharLen := UTF8CodepointSize(P1); if (CharLen = 0) then Break; Canvas.Font.Color := SymbolColor[I]; Canvas.TextOut(X, Y, Copy(P1, 1, CharLen)); Inc(X, SymbolWidth); Inc(P1, CharLen); Inc(I); end; Canvas.Font.Color := clWindowText; end; end; end; procedure TBinaryDiffViewer.SetPosition(Value: PtrInt); begin if not (csDestroying in ComponentState) then begin if FScrollLock = 0 then begin Inc(FScrollLock); try inherited SetPosition(Value); if FKeepScrolling and Assigned(SecondViewer) then SecondViewer.SetPosition(Value); finally Dec(FScrollLock); end; end; end; end; constructor TBinaryDiffViewer.Create(AOwner: TComponent); begin inherited Create(AOwner); FModified:= clRed; Mode:= vcmHex; end; { TBinaryCompare } procedure TBinaryCompare.Execute; var Finish: PtrInt; Remain: PtrInt; Position: PtrInt = 0; Equal: Boolean = True; begin FResult.Clear; Remain:= (FFinish mod cHexWidth); Finish:= (FFinish - Remain); // Compare integer block size while (Terminated = False) and (Position < Finish) do begin if CompareMem(FFirst + Position, FSecond + Position, cHexWidth) then Equal:= True else if Equal then begin Equal:= False; FResult.Add(Pointer(Position)); end; Position:= Position + cHexWidth; end; // Compare remain bytes if (Remain > 0) then begin if not CompareMem(FFirst + Position, FSecond + Position, Remain) then begin if Equal then begin Equal:= False; FResult.Add(Pointer(Position)); end; end; end; // Different file size if (FEqual = False) and (Equal = True) then begin FResult.Add(Pointer(Position + Remain)) end; if Assigned(FOnFinish) then Synchronize(FOnFinish); end; constructor TBinaryCompare.Create(First, Second: PByte; FirstSize, SecondSize: PtrInt; Result: TFPList); begin FFirst:= First; FSecond:= Second; FResult:= Result; inherited Create(True); FreeOnTerminate:= True; FEqual:= (FirstSize = SecondSize); FFinish:= Min(FirstSize, SecondSize); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uclassesex.pas�����������������������������������������������������������������0000644�0001750�0000144�00000013751�14743153644�016270� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- This module contains additional or extended classes. Copyright (C) 2008-2017 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uClassesEx; {$mode objfpc}{$H+} interface uses Classes, SysUtils, IniPropStorage, Contnrs, SynEdit; type { TObjectEx } TObjectEx = class(TObject) public function Clone: TObjectEx; virtual; abstract; end; { TBlobStream } TBlobStream = class(TCustomMemoryStream) public constructor Create(Ptr: Pointer; ASize: PtrInt); end; { TIniPropStorageEx } TIniPropStorageEx = class(TCustomIniPropStorage) private FPixelsPerInch: Integer; function ChangeIdent(const Ident: String): String; protected procedure SaveProperties; override; function IniFileClass: TIniFileClass; override; public procedure Restore; override; function DoReadString(const Section, Ident, Default: string): string; override; procedure DoWriteString(const Section, Ident, Value: string); override; end; { TThreadObjectList } TThreadObjectList = class private FList: TObjectList; FLock: TRTLCriticalSection; public constructor Create; destructor Destroy; override; public procedure Clear; function Clone: TObjectList; function Add(AObject: TObjectEx): Integer; function LockList: TObjectList; procedure UnlockList; end; { TSynEditHelper } TSynEditHelper = class helper for TSynEdit public procedure FixDefaultKeystrokes; end; implementation uses LCLType, Forms, Controls, LCLVersion, SynEditKeyCmds, DCStrUtils, DCClassesUtf8; { TThreadObjectList } constructor TThreadObjectList.Create; begin inherited Create; InitCriticalSection(FLock); FList:= TObjectList.Create(True); end; destructor TThreadObjectList.Destroy; begin LockList; try FList.Free; inherited Destroy; finally UnlockList; DoneCriticalSection(FLock); end; end; procedure TThreadObjectList.Clear; begin Locklist; try FList.Clear; finally UnLockList; end; end; function TThreadObjectList.Clone: TObjectList; var Index: Integer; begin LockList; try Result:= TObjectList.Create(True); for Index:= 0 to FList.Count - 1 do begin Result.Add(TObjectEx(FList[Index]).Clone); end; finally UnlockList; end; end; function TThreadObjectList.Add(AObject: TObjectEx): Integer; begin Result:= FList.Add(AObject); end; function TThreadObjectList.LockList: TObjectList; begin Result:= FList; System.EnterCriticalSection(FLock); end; procedure TThreadObjectList.UnlockList; begin System.LeaveCriticalSection(FLock); end; { TBlobStream } constructor TBlobStream.Create(Ptr: Pointer; ASize: PtrInt); begin inherited Create; SetPointer(Ptr, ASize); end; { TIniPropStorageEx } procedure TIniPropStorageEx.SaveProperties; begin inherited SaveProperties; IniFile.WriteInteger(IniSection, 'Screen_PixelsPerInch', Screen.PixelsPerInch); end; function TIniPropStorageEx.IniFileClass: TIniFileClass; begin Result:= TIniFileEx; end; procedure TIniPropStorageEx.Restore; var AMonitor: TMonitor; begin StorageNeeded(True); try FPixelsPerInch := IniFile.ReadInteger(IniSection, 'Screen_PixelsPerInch', Screen.PixelsPerInch); inherited Restore; finally FreeStorage; end; if Self.Owner is TCustomForm then begin with TCustomForm(Self.Owner) do begin // Refresh monitor list Screen.UpdateMonitors; AMonitor:= Screen.MonitorFromPoint(Classes.Point(Left, Top)); if Assigned(AMonitor) then MakeFullyVisible(AMonitor, True); // Workaround for bug: http://bugs.freepascal.org/view.php?id=18514 if WindowState = wsMinimized then WindowState:= wsNormal; end; end; end; function TIniPropStorageEx.DoReadString(const Section, Ident, Default: string): string; var Value: Integer; Form: TCustomForm; begin Result := inherited DoReadString(Section, ChangeIdent(Ident), Default); {$if lcl_fullversion >= 1070000} // Workaround for bug: http://bugs.freepascal.org/view.php?id=31526 if (Self.Owner is TCustomForm) and (TCustomForm(Self.Owner).Scaled) then begin Form := TCustomForm(Self.Owner); if (Form.DesignTimePPI <> FPixelsPerInch) then begin if StrEnds(Ident, '_Width') or StrEnds(Ident, '_Height') then begin if TryStrToInt(Result, Value) then begin Result := IntToStr(MulDiv(Value, Form.DesignTimePPI, FPixelsPerInch)); end; end; end; end; {$endif} end; procedure TIniPropStorageEx.DoWriteString(const Section, Ident, Value: string); begin inherited DoWriteString(Section, ChangeIdent(Ident), Value); end; function TIniPropStorageEx.ChangeIdent(const Ident: String): String; begin // Change component name to class name. if StrBegins(Ident, Owner.Name) then Result := Owner.ClassName + Copy(Ident, 1 + Length(Owner.Name), MaxInt) else Result := Ident; end; { TSynEditHelper } procedure TSynEditHelper.FixDefaultKeystrokes; procedure AddKey(const ACmd: TSynEditorCommand; const AKey: Word; const AShift: TShiftState; const AShiftMask: TShiftState = []); begin with Keystrokes.Add do begin Key := AKey; Shift := AShift; ShiftMask := AShiftMask; Command := ACmd; end; end; begin AddKey(ecCopy, VK_C, [ssModifier]); AddKey(ecSelectAll, VK_A, [ssModifier]); end; end. �����������������������doublecmd-1.1.22/src/ucmdlineparams.pas�������������������������������������������������������������0000644�0001750�0000144�00000007416�14743153644�017116� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uCmdLineParams; {$mode objfpc}{$H+} interface type TCommandLineParams = packed record NewTab: Boolean; NoSplash: Boolean; ActivePanelSpecified: Boolean; ActiveRight: Boolean; LeftPath: array[0..1023] of AnsiChar; RightPath: array[0..1023] of AnsiChar; ActivePanelPath: array[0..1023] of AnsiChar; Client: Boolean; Servername: array[0..1023] of AnsiChar; end; procedure ProcessCommandLineParams; var CommandLineParams: TCommandLineParams; implementation uses Forms, Dialogs, SysUtils, uOSUtils, uDCUtils, uGlobsPaths, getopts, uDebug, uLng, uClipboard, DCStrUtils; function DecodePath(const Path: String): String; begin Result := TrimQuotes(Path); if Pos(fileScheme, Result) = 1 then begin Result:= URIDecode(Copy(Result, 8, MaxInt)); end; Result:= GetAbsoluteFileName(IncludeTrailingBackslash(GetCurrentDir), Result); end; procedure ProcessCommandLineParams; var Option: AnsiChar = #0; OptionIndex: LongInt = 0; Options: array[1..5] of TOption; OptionUnknown: String; begin FillChar(Options, SizeOf(Options), #0); with Options[1] do begin Name:= 'debug-log'; Has_arg:= 1; end; with Options[2] do begin Name:= 'config-dir'; Has_arg:= 1; end; with Options[3] do begin Name:= 'client'; end; with Options[4] do begin Name:= 'servername'; Has_arg:= 1; end; with Options[5] do begin Name:= 'no-splash'; end; FillChar(CommandLineParams, SizeOf(TCommandLineParams), #0); repeat try Option:= GetLongOpts('L:l:R:r:P:p:TtCc', @Options[1], OptionIndex); except MessageDlg(Application.Title, rsMsgInvalidCommandLine, mtError, [mbOK], 0, mbOK); Exit; end; case Option of #0: begin case OptionIndex of 1: begin // Used by LazLogger end; 2: begin gpCmdLineCfgDir:= ParamStrU(TrimQuotes(OptArg)); end; 3: begin CommandLineParams.Client:= True; CommandLineParams.NoSplash:= True; end; 4: begin CommandLineParams.Servername:= ParamStrU(TrimQuotes(OptArg)); end; 5: begin CommandLineParams.NoSplash:= True; end; end; end; 'L', 'l': CommandLineParams.LeftPath:= DecodePath(ParamStrU(OptArg)); 'R', 'r': CommandLineParams.RightPath:= DecodePath(ParamStrU(OptArg)); 'P', 'p': begin CommandLineParams.ActivePanelSpecified:= True; CommandLineParams.ActiveRight:= (UpperCase(OptArg) = 'R'); end; 'T', 't': CommandLineParams.NewTab:= True; 'C', 'c': begin CommandLineParams.Client:= True; CommandLineParams.NoSplash:= True; end; '?', ':': DCDebug ('Error with opt : ', OptOpt); end; { case } until Option = EndOfOptions; if OptInd <= ParamCount then begin // If also found one parameter then use it as path of active panel if ParamCount - OptInd = 0 then begin CommandLineParams.ActivePanelPath:= DecodePath(ParamStrU(OptInd)); Inc(OptInd, 1); end // If also found two parameters then use it as paths in panels else if ParamCount - OptInd = 1 then begin CommandLineParams.LeftPath:= DecodePath(ParamStrU(OptInd)); CommandLineParams.RightPath:= DecodePath(ParamStrU(OptInd + 1)); Inc(OptInd, 2); end; // Unknown options, print to console if OptInd <= ParamCount then begin while OptInd <= ParamCount do begin OptionUnknown:= ParamStrU(OptInd) + ' '; Inc(OptInd) end; DCDebug ('Non options : ', OptionUnknown); end; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ucolors.pas��������������������������������������������������������������������0000644�0001750�0000144�00000052126�14743153644�015576� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Color themes unit Copyright (C) 2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uColors; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, fpjson, DCXmlConfig; const THEME_COUNT = 2; DARK_THEME = 'Dark'; LIGHT_THEME = 'Light'; THEME_NAME: array[0..Pred(THEME_COUNT)] of String = (LIGHT_THEME, DARK_THEME); type TFilePanelColors = record CursorBorderColor: TColor; ForeColor, BackColor, BackColor2, MarkColor, CursorColor, CursorText, GridLine, InactiveCursorColor, InactiveMarkColor: TColor; end; PFilePanelColors = ^TFilePanelColors; TFreeSpaceIndColors = record ForeColor, BackColor, ThresholdForeColor: TColor; end; PFreeSpaceIndColors = ^TFreeSpaceIndColors; TPathColors = record ActiveColor, ActiveFontColor, InactiveColor, InactiveFontColor: TColor; end; PPathColors = ^TPathColors; TLogColors = record InfoColor, ErrorColor, SuccessColor: TColor; end; PLogColors = ^TLogColors; TSyncDirsColors = record LeftColor, RightColor, UnknownColor: TColor; end; PSyncDirsColors = ^TSyncDirsColors; TViewerColors = record ImageBackColor1, ImageBackColor2: TColor; BookBackgroundColor, BookFontColor: TColor; end; PViewerColors = ^TViewerColors; TDifferColors = record AddedColor: TColor; DeletedColor: TColor; ModifiedColor: TColor; ModifiedBinaryColor: TColor; end; PDifferColors = ^TDifferColors; TTreeViewMenuColors = record BackgroundColor: TColor; ShortcutColor: TColor; NormalTextColor: TColor; SecondaryTextColor: TColor; FoundTextColor: TColor; UnselectableTextColor: TColor; CursorColor: TColor; ShortcutUnderCursor: TColor; NormalTextUnderCursor: TColor; SecondaryTextUnderCursor: TColor; FoundTextUnderCursor: TColor; UnselectableUnderCursor: TColor; end; PTreeViewMenuColors = ^TTreeViewMenuColors; { TColorTheme } TColorTheme = class public Log: TLogColors; Path: TPathColors; Viewer: TViewerColors; Differ: TDifferColors; SyncDirs: TSyncDirsColors; FilePanel: TFilePanelColors; FreeSpaceInd: TFreeSpaceIndColors; TreeViewMenu: TTreeViewMenuColors; public procedure Assign(ATheme: TColorTheme); end; { TColorThemes } TColorThemes = class private FColors: array[0..Pred(THEME_COUNT)] of TColorTheme; private procedure CreateDefault; public function Log: PLogColors; function Path: PPathColors; function Differ: PDifferColors; function Viewer: PViewerColors; function SyncDirs: PSyncDirsColors; function FilePanel: PFilePanelColors; function FreeSpaceInd: PFreeSpaceIndColors; function TreeViewMenu: PTreeViewMenuColors; public constructor Create; destructor Destroy; override; function Current: TColorTheme; class function StyleIndex: Integer; procedure LoadFromXml(AConfig: TXmlConfig); procedure Save(AConfig: TJSONObject); procedure Load(AConfig: TJSONObject); function GetTheme(const AName: String): TColorTheme; end; implementation uses DCClassesUtf8, uSynDiffControls, uOSForms, uGlobs; { TColorTheme } procedure TColorTheme.Assign(ATheme: TColorTheme); begin Log:= ATheme.Log; Path:= ATheme.Path; Differ:= ATheme.Differ; Viewer:= ATheme.Viewer; SyncDirs:= ATheme.SyncDirs; FilePanel:= ATheme.FilePanel; FreeSpaceInd:= ATheme.FreeSpaceInd; TreeViewMenu:= ATheme.TreeViewMenu; end; { TColorThemes } function TColorThemes.Log: PLogColors; begin Result:= @Current.Log; end; function TColorThemes.Path: PPathColors; begin Result:= @Current.Path; end; function TColorThemes.Differ: PDifferColors; begin Result:= @Current.Differ; end; function TColorThemes.Viewer: PViewerColors; begin Result:= @Current.Viewer; end; function TColorThemes.SyncDirs: PSyncDirsColors; begin Result:= @Current.SyncDirs; end; function TColorThemes.FilePanel: PFilePanelColors; begin Result:= @Current.FilePanel; end; function TColorThemes.FreeSpaceInd: PFreeSpaceIndColors; begin Result:= @Current.FreeSpaceInd; end; function TColorThemes.TreeViewMenu: PTreeViewMenuColors; begin Result:= @Current.TreeViewMenu; end; constructor TColorThemes.Create; begin CreateDefault; end; destructor TColorThemes.Destroy; begin FColors[0].Free; FColors[1].Free; inherited Destroy; end; class function TColorThemes.StyleIndex: Integer; begin if DarkStyle then Result:= 1 else begin Result:= 0; end; end; procedure TColorThemes.CreateDefault; begin // Light theme FColors[0]:= TColorTheme.Create; with FColors[0].FilePanel do begin CursorBorderColor := clHighlight; ForeColor := clWindowText; BackColor := clWindow; BackColor2 := clWindow; MarkColor := clRed; CursorColor := clHighlight; CursorText := clHighlightText; GridLine := clSilver; InactiveCursorColor := clInactiveCaption; InactiveMarkColor := clMaroon; end; with FColors[0].Path do begin ActiveColor := clHighlight; ActiveFontColor := clHighlightText; InactiveColor := clBtnFace; InactiveFontColor := clBtnText; end; with FColors[0].FreeSpaceInd do begin ForeColor := clBlack; BackColor := clWhite; ThresholdForeColor := clRed; end; with FColors[0].Log do begin InfoColor:= clNavy; ErrorColor:= clRed; SuccessColor:= clGreen; end; with FColors[0].SyncDirs do begin LeftColor:= clGreen; RightColor:= clBlue; UnknownColor:= clRed; end; with FColors[0].Viewer do begin ImageBackColor1 := clWindow; ImageBackColor2 := clDefault; BookBackgroundColor := clBlack; BookFontColor := clWhite; end; with FColors[0].Differ do begin AddedColor := clPaleGreen; DeletedColor := clPaleRed; ModifiedColor := clPaleBlue; ModifiedBinaryColor := clRed; end; with FColors[0].TreeViewMenu do begin BackgroundColor := clForm; ShortcutColor := clRed; NormalTextColor := clWindowText; SecondaryTextColor := clWindowFrame; FoundTextColor := clHighLight; UnselectableTextColor := clGrayText; CursorColor := clHighlight; ShortcutUnderCursor := clHighlightText; NormalTextUnderCursor := clHighlightText; SecondaryTextUnderCursor := clBtnHighlight; FoundTextUnderCursor := clYellow; UnselectableUnderCursor := clGrayText; end; // Dark theme FColors[1]:= TColorTheme.Create; FColors[1].Assign(FColors[0]); with FColors[1].FilePanel do begin GridLine:= $484848; end; with FColors[1].Log do begin InfoColor:= $C09B61; ErrorColor:= $6166C0; SuccessColor:= $8AD277; end; with FColors[1].Differ do begin AddedColor:= $8AD277; DeletedColor:= $6166C0; ModifiedColor:= $C09B61; ModifiedBinaryColor:= $6166C0; end; with FColors[1].SyncDirs do begin LeftColor:= $8AD277; RightColor:= $C09B61; UnknownColor:= $6166C0; end; end; procedure TColorThemes.LoadFromXml(AConfig: TXmlConfig); var Root, Node: TXmlNode; ColorTheme: TColorTheme; LoadedConfigVersion: Integer; begin with AConfig do begin Root := RootNode; LoadedConfigVersion := GetAttr(Root, 'ConfigVersion', ConfigVersion); if (LoadedConfigVersion >= 14) then Exit; ColorTheme:= Current; { Colors } Node := Root.FindNode('Colors'); if Assigned(Node) then begin with ColorTheme.FilePanel do begin CursorBorderColor:= GetValue(Node, 'CursorBorderColor', CursorBorderColor); ForeColor:= GetValue(Node, 'Foreground', ForeColor); BackColor:= GetValue(Node, 'Background', BackColor); BackColor2:= GetValue(Node, 'Background2', BackColor2); MarkColor:= GetValue(Node, 'Mark', MarkColor); CursorColor:= GetValue(Node, 'Cursor', CursorColor); CursorText:= GetValue(Node, 'CursorText', CursorText); InactiveCursorColor:= GetValue(Node, 'InactiveCursor', InactiveCursorColor); InactiveMarkColor:= GetValue(Node, 'InactiveMark', InactiveMarkColor); end; with ColorTheme.Path do begin ActiveColor := GetValue(Node, 'PathLabel/ActiveColor', ActiveColor); ActiveFontColor := GetValue(Node, 'PathLabel/ActiveFontColor', ActiveFontColor); InactiveColor := GetValue(Node, 'PathLabel/InactiveColor', InactiveColor); InactiveFontColor := GetValue(Node, 'PathLabel/InactiveFontColor', InactiveFontColor); end; with ColorTheme.FreeSpaceInd do begin ForeColor := GetValue(Node, 'FreeSpaceIndicator/ForeColor', ForeColor); BackColor := GetValue(Node, 'FreeSpaceIndicator/BackColor', BackColor); ThresholdForeColor := GetValue(Node, 'FreeSpaceIndicator/ThresholdForeColor', ThresholdForeColor); end; with ColorTheme.Log do begin InfoColor:= GetValue(Node, 'LogWindow/Info', InfoColor); ErrorColor:= GetValue(Node, 'LogWindow/Error', ErrorColor); SuccessColor:= GetValue(Node, 'LogWindow/Success', SuccessColor); end; end; { Differ } Node:= Root.FindNode('Differ/Colors'); if Assigned(Node) then begin with ColorTheme.Differ do begin AddedColor := GetValue(Node, 'Added', AddedColor); DeletedColor := GetValue(Node, 'Deleted', DeletedColor); ModifiedColor := GetValue(Node, 'Modified', ModifiedColor); Node := FindNode(Node, 'Colors/Binary'); if Assigned(Node) then begin ModifiedBinaryColor := GetValue(Node, 'Modified', ModifiedBinaryColor); end; end; end; { Viewer } Node := Root.FindNode('Viewer'); if Assigned(Node) then begin with ColorTheme.Viewer do begin ImageBackColor1:= GetValue(Node, 'ImageBackColor1', ImageBackColor1); ImageBackColor2:= GetValue(Node, 'ImageBackColor2', ImageBackColor2); BookBackgroundColor := GetValue(Node, 'BackgroundColor', BookBackgroundColor); BookFontColor := GetValue(Node, 'FontColor', BookFontColor); end; end; { Tree View Menu } Node := Root.FindNode('TreeViewMenu'); if Assigned(Node) then begin with ColorTheme.TreeViewMenu do begin BackgroundColor := GetValue(Node, 'BackgroundColor', BackgroundColor); ShortcutColor := GetValue(Node, 'ShortcutColor', ShortcutColor); NormalTextColor := GetValue(Node, 'NormalTextColor', NormalTextColor); SecondaryTextColor := GetValue(Node, 'SecondaryTextColor', SecondaryTextColor); FoundTextColor := GetValue(Node, 'FoundTextColor', FoundTextColor); UnselectableTextColor := GetValue(Node, 'UnselectableTextColor', UnselectableTextColor); CursorColor := GetValue(Node, 'CursorColor', CursorColor); ShortcutUnderCursor := GetValue(Node, 'ShortcutUnderCursor', ShortcutUnderCursor); NormalTextUnderCursor := GetValue(Node, 'NormalTextUnderCursor', NormalTextUnderCursor); SecondaryTextUnderCursor := GetValue(Node, 'SecondaryTextUnderCursor', SecondaryTextUnderCursor); FoundTextUnderCursor := GetValue(Node, 'FoundTextUnderCursor', FoundTextUnderCursor); UnselectableUnderCursor := GetValue(Node, 'UnselectableUnderCursor', UnselectableUnderCursor); end; end; end; end; procedure TColorThemes.Save(AConfig: TJSONObject); var Index: Integer; Theme: TJSONObject; Themes: TJSONArray; Group: TJSONObject; ColorTheme: TColorTheme; begin if AConfig.Find('Styles', Themes) then Themes.Clear else begin Themes:= TJSONArray.Create; AConfig.Add('Styles', Themes); end; for Index:= 0 to High(FColors) do begin ColorTheme:= FColors[Index]; Theme:= TJSONObject.Create; Themes.Add(Theme); Theme.Add('Name', THEME_NAME[Index]); Group:= TJSONObject.Create; Theme.Add('FilePanel', Group); Group.Add('CursorBorderColor', ColorTheme.FilePanel.CursorBorderColor); Group.Add('ForeColor', ColorTheme.FilePanel.ForeColor); Group.Add('BackColor', ColorTheme.FilePanel.BackColor); Group.Add('BackColor2', ColorTheme.FilePanel.BackColor2); Group.Add('MarkColor', ColorTheme.FilePanel.MarkColor); Group.Add('CursorColor', ColorTheme.FilePanel.CursorColor); Group.Add('CursorText', ColorTheme.FilePanel.CursorText); Group.Add('GridLine', ColorTheme.FilePanel.GridLine); Group.Add('InactiveCursorColor', ColorTheme.FilePanel.InactiveCursorColor); Group.Add('InactiveMarkColor', ColorTheme.FilePanel.InactiveMarkColor); Group:= TJSONObject.Create; Theme.Add('FreeSpaceIndicator', Group); Group.Add('ForeColor', ColorTheme.FreeSpaceInd.ForeColor); Group.Add('BackColor', ColorTheme.FreeSpaceInd.BackColor); Group.Add('ThresholdForeColor', ColorTheme.FreeSpaceInd.ThresholdForeColor); Group:= TJSONObject.Create; Theme.Add('Path', Group); Group.Add('ActiveColor', ColorTheme.Path.ActiveColor); Group.Add('ActiveFontColor', ColorTheme.Path.ActiveFontColor); Group.Add('InactiveColor', ColorTheme.Path.InactiveColor); Group.Add('InactiveFontColor', ColorTheme.Path.InactiveFontColor); Group:= TJSONObject.Create; Theme.Add('Log', Group); Group.Add('InfoColor', ColorTheme.Log.InfoColor); Group.Add('ErrorColor', ColorTheme.Log.ErrorColor); Group.Add('SuccessColor', ColorTheme.Log.SuccessColor); Group:= TJSONObject.Create; Theme.Add('SyncDirs', Group); Group.Add('LeftColor', ColorTheme.SyncDirs.LeftColor); Group.Add('RightColor', ColorTheme.SyncDirs.RightColor); Group.Add('UnknownColor', ColorTheme.SyncDirs.UnknownColor); Group:= TJSONObject.Create; Theme.Add('Viewer', Group); Group.Add('ImageBackColor1', ColorTheme.Viewer.ImageBackColor1); Group.Add('ImageBackColor2', ColorTheme.Viewer.ImageBackColor2); Group.Add('BookBackgroundColor', ColorTheme.Viewer.BookBackgroundColor); Group.Add('BookFontColor', ColorTheme.Viewer.BookFontColor); Group:= TJSONObject.Create; Theme.Add('Differ', Group); Group.Add('AddedColor', ColorTheme.Differ.AddedColor); Group.Add('DeletedColor', ColorTheme.Differ.DeletedColor); Group.Add('ModifiedColor', ColorTheme.Differ.ModifiedColor); Group.Add('ModifiedBinaryColor', ColorTheme.Differ.ModifiedBinaryColor); Group:= TJSONObject.Create; Theme.Add('TreeViewMenu', Group); Group.Add('BackgroundColor', ColorTheme.TreeViewMenu.BackgroundColor); Group.Add('ShortcutColor', ColorTheme.TreeViewMenu.ShortcutColor); Group.Add('NormalTextColor', ColorTheme.TreeViewMenu.NormalTextColor); Group.Add('SecondaryTextColor', ColorTheme.TreeViewMenu.SecondaryTextColor); Group.Add('FoundTextColor', ColorTheme.TreeViewMenu.FoundTextColor); Group.Add('UnselectableTextColor', ColorTheme.TreeViewMenu.UnselectableTextColor); Group.Add('CursorColor', ColorTheme.TreeViewMenu.CursorColor); Group.Add('ShortcutUnderCursor', ColorTheme.TreeViewMenu.ShortcutUnderCursor); Group.Add('NormalTextUnderCursor', ColorTheme.TreeViewMenu.NormalTextUnderCursor); Group.Add('SecondaryTextUnderCursor', ColorTheme.TreeViewMenu.SecondaryTextUnderCursor); Group.Add('FoundTextUnderCursor', ColorTheme.TreeViewMenu.FoundTextUnderCursor); Group.Add('UnselectableUnderCursor', ColorTheme.TreeViewMenu.UnselectableUnderCursor); end; end; procedure TColorThemes.Load(AConfig: TJSONObject); var AName: String; Index: Integer; Theme: TJSONObject; Themes: TJSONArray; Group: TJSONObject; Empty: TJSONObject; ColorTheme: TColorTheme; begin Themes:= AConfig.Get('Styles', TJSONArray(nil)); if Assigned(Themes) then try Empty:= TJSONObject.Create; for Index:= 0 to Themes.Count - 1 do begin Theme:= Themes.Objects[Index]; AName:= Theme.Get('Name', EmptyStr); ColorTheme:= GetTheme(AName); if (ColorTheme = nil) then Continue; Group:= Theme.Get('FilePanel', Empty); with ColorTheme.FilePanel do begin CursorBorderColor:= Group.Get('CursorBorderColor', CursorBorderColor); ForeColor:= Group.Get('ForeColor', ForeColor); BackColor:= Group.Get('BackColor', BackColor); BackColor2:= Group.Get('BackColor2', BackColor2); MarkColor:= Group.Get('MarkColor', MarkColor); CursorColor:= Group.Get('CursorColor', CursorColor); CursorText:= Group.Get('CursorText', CursorText); GridLine:= Group.Get('GridLine', GridLine); InactiveCursorColor:= Group.Get('InactiveCursorColor', InactiveCursorColor); InactiveMarkColor:= Group.Get('InactiveMarkColor', InactiveMarkColor); end; Group:= Theme.Get('FreeSpaceIndicator', Empty); with ColorTheme.FreeSpaceInd do begin ForeColor:= Group.Get('ForeColor', ForeColor); BackColor:= Group.Get('BackColor', BackColor); ThresholdForeColor:= Group.Get('ThresholdForeColor', ThresholdForeColor); end; Group:= Theme.Get('Path', Empty); with ColorTheme.Path do begin ActiveColor:= Group.Get('ActiveColor', ActiveColor); ActiveFontColor:= Group.Get('ActiveFontColor', ActiveFontColor); InactiveColor:= Group.Get('InactiveColor', InactiveColor); InactiveFontColor:= Group.Get('InactiveFontColor', InactiveFontColor); end; Group:= Theme.Get('Log', Empty); with ColorTheme.Log do begin InfoColor:= Group.Get('InfoColor', InfoColor); ErrorColor:= Group.Get('ErrorColor', ErrorColor); SuccessColor:= Group.Get('SuccessColor', SuccessColor); end; Group:= Theme.Get('SyncDirs', Empty); with ColorTheme.SyncDirs do begin LeftColor:= Group.Get('LeftColor', LeftColor); RightColor:= Group.Get('RightColor', RightColor); UnknownColor:= Group.Get('UnknownColor', UnknownColor); end; Group:= Theme.Get('Viewer', Empty); with ColorTheme.Viewer do begin ImageBackColor1:= Group.Get('ImageBackColor1', ImageBackColor1); ImageBackColor2:= Group.Get('ImageBackColor2', ImageBackColor2); BookBackgroundColor:= Group.Get('BookBackgroundColor', BookBackgroundColor); BookFontColor:= Group.Get('BookFontColor', BookFontColor); end; Group:= Theme.Get('Differ', Empty); with ColorTheme.Differ do begin AddedColor:= Group.Get('AddedColor', AddedColor); DeletedColor:= Group.Get('DeletedColor', DeletedColor); ModifiedColor:= Group.Get('ModifiedColor', ModifiedColor); ModifiedBinaryColor:= Group.Get('ModifiedBinaryColor', ModifiedBinaryColor); end; Group:= Theme.Get('TreeViewMenu', Empty); with ColorTheme.TreeViewMenu do begin BackgroundColor:= Group.Get('BackgroundColor', BackgroundColor); ShortcutColor:= Group.Get('ShortcutColor', ShortcutColor); NormalTextColor:= Group.Get('NormalTextColor', NormalTextColor); SecondaryTextColor:= Group.Get('SecondaryTextColor', SecondaryTextColor); FoundTextColor:= Group.Get('FoundTextColor', FoundTextColor); UnselectableTextColor:= Group.Get('UnselectableTextColor', UnselectableTextColor); CursorColor:= Group.Get('CursorColor', CursorColor); ShortcutUnderCursor:= Group.Get('ShortcutUnderCursor', ShortcutUnderCursor); NormalTextUnderCursor:= Group.Get('NormalTextUnderCursor', NormalTextUnderCursor); SecondaryTextUnderCursor:= Group.Get('SecondaryTextUnderCursor', SecondaryTextUnderCursor); FoundTextUnderCursor:= Group.Get('FoundTextUnderCursor', FoundTextUnderCursor); UnselectableUnderCursor:= Group.Get('UnselectableUnderCursor', UnselectableUnderCursor); end; end; finally Empty.Free; end; end; function TColorThemes.GetTheme(const AName: String): TColorTheme; begin if (AName = LIGHT_THEME) then Result:= FColors[0] else if (AName = DARK_THEME) then Result:= FColors[1] else begin Result:= nil; end; end; function TColorThemes.Current: TColorTheme; begin if DarkStyle then Result:= FColors[1] else begin Result:= FColors[0]; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ucolumns.pas�������������������������������������������������������������������0000644�0001750�0000144�00000141603�14743153644�015754� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Filepanel columns implementation unit Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2015-2023 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uColumns; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, uFile, uFileSource, DCXmlConfig, FpJson, DCBasicTypes, uFileFunctions, uColors; const FS_GENERAL = '<General>'; type { TColPrm } TColPrm = class FontName: String; FontSize: Integer; FontStyle: TFontStyles; TextColor, Background, Background2, MarkColor, CursorColor, CursorText, InactiveCursorColor, InactiveMarkColor: TColor; UseInvertedSelection: Boolean; UseInactiveSelColor: Boolean; Overcolor: Boolean; public constructor Create; end; { TPanelColumnsType } TPanelColumn = class private FUnique: String; FFuncString: String; procedure SetUnique(const AValue: String); procedure SetFuncString(NewValue: String); function GetColumnResultString(AFile: TFile; const AFileSource: IFileSource): String; public //--------------------- Title: String; {String is function or simpletext; TObject(integer)=indicator of function: 0 is simpletext; 1 is function;} FuncList: TStringList; Width: Integer; Align: TAlignment; //--------------------- FontName: String; FontSize: Integer; FontStyle: TFontStyles; TextColor, Background, Background2, MarkColor, CursorColor, CursorText, InactiveCursorColor, InactiveMarkColor: TColor; BorderFrameWidth :integer; UseInvertedSelection: Boolean; UseInactiveSelColor: Boolean; Overcolor: Boolean; //--------------------- constructor Create; constructor CreateNew; destructor Destroy; override; //------------------------------------------------------ property Unique: String read FUnique write SetUnique; property FuncString: String read FFuncString write SetFuncString; end; { TPanelColumnsClass } TPanelColumnsClass = class //------------------------------------------------------ private FList: TList; FUnique: String; fSetName: String; // Global settings for columns view. FFileSystem: String; FCustomView: Boolean; FCursorBorder: Boolean; FCursorBorderColor: TColor; FUseFrameCursor: Boolean; //------------------------------------------------------ function GetCursorBorder: boolean; function GetCursorBorderColor: TColor; function GetUseFrameCursor: Boolean; procedure SetUnique(const AValue: String); protected procedure AddColumn(AList: TJSONArray; AColumn: TPanelColumn); public constructor Create; destructor Destroy; override; procedure Assign(const OtherColumnsClass: TPanelColumnsClass); //--------------------- function GetColumnTitle(const Index: Integer): String; function GetColumnFuncString(const Index: Integer): String; function GetColumnWidth(const Index: Integer): Integer; function GetColumnAlign(const Index: Integer): TAlignment; function GetColumnAlignString(const Index: Integer): String; //--------------------- function GetColumnFontName(const Index: Integer): String; function GetColumnFontSize(const Index: Integer): Integer; function GetColumnFontStyle(const Index: Integer): TFontStyles; function GetColumnFontQuality(const Index: Integer): TFontQuality; function GetColumnTextColor(const Index: Integer): TColor; function GetColumnBackground(const Index: Integer): TColor; function GetColumnBackground2(const Index: Integer): TColor; function GetColumnMarkColor(const Index: Integer): TColor; function GetColumnCursorColor(const Index: Integer): TColor; function GetColumnCursorText(const Index: Integer): TColor; function GetColumnInactiveCursorColor(const Index: Integer): TColor; function GetColumnInactiveMarkColor(const Index: Integer): TColor; function GetColumnUseInvertedSelection(const Index: Integer): Boolean; function GetColumnUseInactiveSelColor(const Index: Integer): Boolean; function GetColumnOvercolor(const Index: Integer): Boolean; function GetColumnBorderFrameWidth(const Index: Integer):integer; //--------------------- function GetColumnPrm(const Index: Integer): TColPrm; //-------------------------------------------------------------------------- function GetColumnsVariants: TDynamicStringArray; {en Converts string functions in the column into their integer values, so that they don't have to be compared by string during sorting. Call this before sorting then pass result to Compare in the sorting loop. } function GetColumnFunctions(const Index: Integer): TFileFunctions; function GetColumnItemResultString(const Index: Integer; const AFile: TFile; const AFileSource: IFileSource): String; //-------------------------------------------------------------------------- function GetColumnItem(const Index: Integer): TPanelColumn; function GetCount: Integer; function Add(Item: TPanelColumn): Integer; function Add(const Title, FuncString: String; const Width: Integer; const Align: TAlignment = taLeftJustify): Integer; overload; //--------------------- procedure SetColumnTitle(const Index: Integer; Title: String); procedure SetColumnFuncString(const Index: Integer; FuncString: String); procedure SetColumnWidth(Index, Width: Integer); procedure SetColumnAlign(const Index: Integer; Align: TAlignment); //--------------------- procedure SetColumnFontName(const Index: Integer; Value: String); procedure SetColumnFontSize(const Index: Integer; Value: Integer); procedure SetColumnFontStyle(const Index: Integer; Value: TFontStyles); procedure SetColumnTextColor(const Index: Integer; Value: TColor); procedure SetColumnBackground(const Index: Integer; Value: TColor); procedure SetColumnBackground2(const Index: Integer; Value: TColor); procedure SetColumnMarkColor(const Index: Integer; Value: TColor); procedure SetColumnCursorColor(const Index: Integer; Value: TColor); procedure SetColumnCursorText(const Index: Integer; Value: TColor); procedure SetColumnInactiveCursorColor(const Index: Integer; Value: TColor); procedure SetColumnInactiveMarkColor(const Index: Integer; Value: TColor); procedure SetColumnUseInvertedSelection(const Index: Integer; Value: Boolean); procedure SetColumnUseInactiveSelColor(const Index: Integer; Value: Boolean); procedure SetColumnOvercolor(const Index: Integer; Value: Boolean); //--------------------- procedure SetColumnPrm(const Index: Integer; Value: TColPrm); //--------------------- procedure Delete(const Index: Integer); procedure Exchange(Index1, Index2: Integer); procedure Clear; procedure AddDefaultColumns; procedure AddDefaultEverything; //--------------------- procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); //--------------------- procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); //--------------------- procedure LoadColors(ANode: TJSONObject); procedure SaveColors(ANode: TJSONObject); procedure Synchronize(ANode: TJSONObject); //--------------------- function GetSignature(Seed:dword=$000000):dword; property ColumnsCount: Integer read GetCount; property Count: Integer read GetCount; property CustomView: Boolean read FCustomView write FCustomView; property Name: String read fSetName write fSetName; property Unique: String read FUnique write SetUnique; property FileSystem: String read FFileSystem write FFileSystem; property UseCursorBorder: boolean read GetCursorBorder write FCursorBorder; property CursorBorderColor: TColor read GetCursorBorderColor write FCursorBorderColor; property UseFrameCursor: boolean read GetUseFrameCursor write FUseFrameCursor; //------------------------------------------------------ end; { TPanelColumnsList } TPanelColumnsList = class private FStyle: Integer; fSet: TStringList; FStyles: array[0..Pred(THEME_COUNT)] of TJSONArray; private function GetCount: Integer; procedure Synchronize(Item: TPanelColumnsClass); public constructor Create; destructor Destroy; override; //--------------------- procedure Clear; procedure UpdateStyle; procedure LoadColors; overload; procedure SaveColors; overload; procedure LoadColors(AConfig: TJSONObject); overload; procedure SaveColors(AConfig: TJSONObject); overload; procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload; function Add(Item: TPanelColumnsClass): Integer; procedure Insert(AIndex: Integer; Item: TPanelColumnsClass); procedure DeleteColumnSet(SetName: String); procedure DeleteColumnSet(SetIndex: Integer); overload; procedure CopyColumnSet(SetName, NewSetName: String); function GetColumnSet(const Index: Integer): TPanelColumnsClass; function GetColumnSet(Setname: String): TPanelColumnsClass; function GetColumnSet(const AName, FileSystem: String): TPanelColumnsClass; //--------------------- property Items: TStringList read fSet; property Count: Integer read GetCount; end; function StrToAlign(str: String): TAlignment; implementation uses StrUtils, LCLType, Forms, crc, DCStrUtils, uDebug, uLng, uGlobs, uDCUtils; const JsonConfigVersion = 15; var LoadedConfigVersion: Integer; DefaultTitleHash: LongWord = 0; procedure UpdateDefaultTitleHash; var Title: String = ''; begin DefaultTitleHash:= CRC32(0, nil, 0); Title:= rsColName + rsColExt + rsColSize + rsColDate + rsColAttr; DefaultTitleHash:= CRC32(DefaultTitleHash, Pointer(Title), Length(Title)); end; function StrToAlign(str: String): TAlignment; begin if str = '<-' then Result := taLeftJustify else if str = '->' then Result := taRightJustify else if str = '=' then Result := taCenter; end; function GetUnique: String; begin Result:= TrimSet(GuidToString(DCGetNewGUID), ['{', '}']); end; { TPanelColumnsType } function TPanelColumnsClass.GetColumnTitle(const Index: Integer): String; begin if Index >= Flist.Count then Exit(EmptyStr); Result := TPanelColumn(Flist[Index]).Title; end; function TPanelColumnsClass.GetColumnFuncString(const Index: Integer): String; begin if Index >= Flist.Count then Exit(EmptyStr); Result := TPanelColumn(Flist[Index]).FuncString; end; function TPanelColumnsClass.GetColumnWidth(const Index: Integer): Integer; begin if Index >= Flist.Count then Exit(0); Result := TPanelColumn(Flist[Index]).Width; end; function TPanelColumnsClass.GetColumnAlign(const Index: Integer): TAlignment; begin if Index >= Flist.Count then Exit(taLeftJustify); Result := TPanelColumn(Flist[Index]).Align; end; function TPanelColumnsClass.GetColumnAlignString(const Index: Integer): String; begin if Index >= Flist.Count then Exit(EmptyStr); case TPanelColumn(Flist[Index]).Align of taLeftJustify: Result := '<-'; taRightJustify: Result := '->'; taCenter: Result := '='; end; end; function TPanelColumnsClass.GetColumnFontName(const Index: Integer): String; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).FontName else Result := gFonts[dcfMain].Name; end; function TPanelColumnsClass.GetColumnFontSize(const Index: Integer): Integer; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).FontSize else Result := gFonts[dcfMain].Size; end; function TPanelColumnsClass.GetColumnFontStyle(const Index: Integer): TFontStyles; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).FontStyle else Result := gFonts[dcfMain].Style; end; function TPanelColumnsClass.GetColumnFontQuality(const Index: Integer): TFontQuality; begin Result := gFonts[dcfMain].Quality; end; function TPanelColumnsClass.GetColumnTextColor(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).TextColor else Result := gColors.FilePanel^.ForeColor; end; function TPanelColumnsClass.GetColumnBackground(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).Background else Result := gColors.FilePanel^.BackColor; end; function TPanelColumnsClass.GetColumnBackground2(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).Background2 else Result := gColors.FilePanel^.BackColor2; end; function TPanelColumnsClass.GetColumnMarkColor(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).MarkColor else Result := gColors.FilePanel^.MarkColor; end; function TPanelColumnsClass.GetColumnCursorColor(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).CursorColor else Result := gColors.FilePanel^.CursorColor; end; function TPanelColumnsClass.GetColumnCursorText(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).CursorText else Result := gColors.FilePanel^.CursorText; end; function TPanelColumnsClass.GetColumnInactiveCursorColor(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).InactiveCursorColor else Result := gColors.FilePanel^.InactiveCursorColor; end; function TPanelColumnsClass.GetColumnInactiveMarkColor(const Index: Integer): TColor; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).InactiveMarkColor else Result := gColors.FilePanel^.InactiveMarkColor; end; function TPanelColumnsClass.GetColumnUseInvertedSelection(const Index: Integer): Boolean; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).UseInvertedSelection else Result := gUseInvertedSelection; end; function TPanelColumnsClass.GetColumnUseInactiveSelColor(const Index: Integer): Boolean; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).UseInactiveSelColor else Result := gUseInactiveSelColor; end; function TPanelColumnsClass.GetColumnOvercolor(const Index: Integer): Boolean; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).Overcolor else Result := gAllowOverColor; end; function TPanelColumnsClass.GetColumnBorderFrameWidth(const Index: Integer): integer; begin if FCustomView and (Index < Flist.Count) then Result := TPanelColumn(Flist[Index]).BorderFrameWidth else Result := gBorderFrameWidth; end; function TPanelColumnsClass.GetColumnPrm(const Index: Integer): TColPrm; begin if Index >= Flist.Count then Exit(nil); Result := TColPrm.Create; Result.FontName := GetColumnFontName(Index); Result.FontSize := GetColumnFontSize(Index); Result.FontStyle := GetColumnFontStyle(Index); Result.TextColor := GetColumnTextColor(Index); Result.Background := GetColumnBackground(Index); Result.Background2 := GetColumnBackground2(Index); Result.MarkColor := GetColumnMarkColor(Index); Result.CursorColor := GetColumnCursorColor(Index); Result.CursorText := GetColumnCursorText(Index); Result.InactiveCursorColor := GetColumnInactiveCursorColor(Index); Result.InactiveMarkColor := GetColumnInactiveMarkColor(Index); Result.UseInvertedSelection:= GetColumnUseInvertedSelection(Index); Result.UseInactiveSelColor:= GetColumnUseInactiveSelColor(Index); Result.Overcolor := GetColumnOvercolor(Index); end; function TPanelColumnsClass.GetColumnsVariants: TDynamicStringArray; var I, J: Integer; begin for J:= 0 to Flist.Count - 1 do begin with TPanelColumn(Flist[J]) do begin if Assigned(FuncList) and (FuncList.Count > 0) then begin for I := 0 to FuncList.Count - 1 do begin // Don't need to compare simple text, only functions. if PtrInt(FuncList.Objects[I]) = 1 then begin if GetFileFunctionByName(FuncList.Strings[I]) = fsfVariant then AddString(Result, FuncList.Strings[I]); end; end; end; end; end; end; function TPanelColumnsClass.GetColumnItem(const Index: Integer): TPanelColumn; begin if Index >= Flist.Count then Exit(nil); Result := TPanelColumn(Flist[Index]); end; function TPanelColumnsClass.GetColumnFunctions(const Index: Integer): TFileFunctions; var FuncCount: Integer = 0; i, J: Integer; Value: TFileFunction; VariantIndex: Integer = 0; begin for J:= 0 to Index do with TPanelColumn(Flist[J]) do begin if Assigned(FuncList) and (FuncList.Count > 0) then begin SetLength(Result, FuncList.Count); // Start with all strings. for i := 0 to FuncList.Count - 1 do begin // Don't need to compare simple text, only functions. if PtrInt(FuncList.Objects[i]) = 1 then begin Value := GetFileFunctionByName(FuncList.Strings[i]); if Value = fsfVariant then begin Value := TFileFunction(Ord(fsfVariant) + VariantIndex); Inc(VariantIndex); end; if (J = Index) then begin Result[FuncCount] := Value; // If the function was found, save it's number. if Result[FuncCount] <> fsfInvalid then FuncCount := FuncCount + 1; end; end; end; SetLength(Result, FuncCount); // Set the actual functions count. end else SetLength(Result, 0); end; end; function TPanelColumnsClass.GetColumnItemResultString(const Index: Integer; const AFile: TFile; const AFileSource: IFileSource): String; begin if Index >= Flist.Count then Exit(EmptyStr); Result := TPanelColumn(Flist[Index]).GetColumnResultString(AFile, AFileSource); end; function TPanelColumnsClass.GetUseFrameCursor: Boolean; begin if FCustomView then Result := FUseFrameCursor else Result := gUseFrameCursor; end; procedure TPanelColumnsClass.SetUnique(const AValue: String); begin if Length(AValue) > 0 then FUnique:= AValue else begin FUnique:= GetUnique; end; end; function TPanelColumnsClass.GetCursorBorder: boolean; begin if FCustomView then Result := FCursorBorder else Result := gUseCursorBorder; end; function TPanelColumnsClass.GetCursorBorderColor: TColor; begin if FCustomView then Result := FCursorBorderColor else Result := gColors.FilePanel^.CursorBorderColor; end; constructor TPanelColumnsClass.Create; begin FList := TList.Create; end; procedure TPanelColumnsClass.Clear; begin while Flist.Count > 0 do begin TPanelColumn(Flist[0]).Free; FList.Delete(0); end; end; destructor TPanelColumnsClass.Destroy; begin Self.Clear; FreeAndNil(FList); inherited Destroy; end; procedure TPanelColumnsClass.Assign(const OtherColumnsClass: TPanelColumnsClass); var OldColumn, NewColumn: TPanelColumn; i: Integer; begin Clear; if not Assigned(OtherColumnsClass) then Exit; Name := OtherColumnsClass.Name; FUnique := OtherColumnsClass.Unique; FFileSystem := OtherColumnsClass.FFileSystem; FCustomView := OtherColumnsClass.FCustomView; FCursorBorder := OtherColumnsClass.FCursorBorder; FCursorBorderColor := OtherColumnsClass.FCursorBorderColor; FUseFrameCursor := OtherColumnsClass.FUseFrameCursor; for i := 0 to OtherColumnsClass.ColumnsCount - 1 do begin OldColumn := OtherColumnsClass.GetColumnItem(i); NewColumn := TPanelColumn.Create; Add(NewColumn); NewColumn.FUnique := OldColumn.FUnique; NewColumn.Title := OldColumn.Title; NewColumn.FuncString := OldColumn.FuncString; NewColumn.Width := OldColumn.Width; NewColumn.Align := OldColumn.Align; NewColumn.FontName := OldColumn.FontName; NewColumn.FontSize := OldColumn.FontSize; NewColumn.FontStyle := OldColumn.FontStyle; NewColumn.TextColor := OldColumn.TextColor; NewColumn.Background := OldColumn.Background; NewColumn.Background2 := OldColumn.Background2; NewColumn.MarkColor := OldColumn.MarkColor; NewColumn.CursorColor := OldColumn.CursorColor; NewColumn.CursorText := OldColumn.CursorText; NewColumn.InactiveCursorColor := OldColumn.InactiveCursorColor; NewColumn.InactiveMarkColor := OldColumn.InactiveMarkColor; NewColumn.UseInvertedSelection := OldColumn.UseInvertedSelection; NewColumn.UseInactiveSelColor := OldColumn.UseInactiveSelColor; NewColumn.Overcolor := OldColumn.Overcolor; end; end; function TPanelColumnsClass.GetCount: Integer; begin Result := FList.Count; end; function TPanelColumnsClass.Add(Item: TPanelColumn): Integer; begin Result := FList.Add(Item); end; function TPanelColumnsClass.Add(const Title, FuncString: String; const Width: Integer; const Align: TAlignment): Integer; var AColumn: TPanelColumn; begin AColumn := TPanelColumn.CreateNew; Result := FList.Add(AColumn); AColumn.Title := Title; AColumn.FuncString := FuncString; AColumn.Width := Width; AColumn.Align := Align; AColumn.FontName := gFonts[dcfMain].Name; AColumn.FontSize := gFonts[dcfMain].Size; AColumn.FontStyle := gFonts[dcfMain].Style; with gColors.FilePanel^ do begin AColumn.TextColor := ForeColor; AColumn.Background := BackColor; AColumn.Background2 := BackColor2; AColumn.MarkColor := MarkColor; AColumn.CursorColor := CursorColor; AColumn.CursorText := CursorText; AColumn.InactiveCursorColor := InactiveCursorColor; AColumn.InactiveMarkColor := InactiveMarkColor; end; AColumn.UseInvertedSelection := gUseInvertedSelection; AColumn.UseInactiveSelColor := gUseInactiveSelColor; AColumn.Overcolor := gAllowOverColor; end; procedure TPanelColumnsClass.SetColumnTitle(const Index: Integer; Title: String); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Title := Title; end; procedure TPanelColumnsClass.SetColumnFuncString(const Index: Integer; FuncString: String); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).FuncString := FuncString; end; procedure TPanelColumnsClass.SetColumnWidth(Index, Width: Integer); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Width := Width; end; procedure TPanelColumnsClass.SetColumnAlign(const Index: Integer; Align: TAlignment); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Align := Align; end; procedure TPanelColumnsClass.SetColumnFontName(const Index: Integer; Value: String); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).FontName := Value; end; procedure TPanelColumnsClass.SetColumnFontSize(const Index: Integer; Value: Integer); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).FontSize := Value; end; procedure TPanelColumnsClass.SetColumnFontStyle(const Index: Integer; Value: TFontStyles); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).FontStyle := Value; end; procedure TPanelColumnsClass.SetColumnTextColor(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).TextColor := Value; end; procedure TPanelColumnsClass.SetColumnBackground(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Background := Value; end; procedure TPanelColumnsClass.SetColumnBackground2(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Background2 := Value; end; procedure TPanelColumnsClass.SetColumnMarkColor(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).MarkColor := Value; end; procedure TPanelColumnsClass.SetColumnCursorColor(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).CursorColor := Value; end; procedure TPanelColumnsClass.SetColumnCursorText(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).CursorText := Value; end; procedure TPanelColumnsClass.SetColumnInactiveCursorColor(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).InactiveCursorColor := Value; end; procedure TPanelColumnsClass.SetColumnInactiveMarkColor(const Index: Integer; Value: TColor); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).InactiveMarkColor := Value; end; procedure TPanelColumnsClass.SetColumnUseInvertedSelection(const Index: Integer; Value: Boolean); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).UseInvertedSelection := Value; end; procedure TPanelColumnsClass.SetColumnUseInactiveSelColor(const Index: Integer; Value: Boolean); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).UseInactiveSelColor := Value; end; procedure TPanelColumnsClass.SetColumnOvercolor(const Index: Integer; Value: Boolean); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Overcolor := Value; end; procedure TPanelColumnsClass.SetColumnPrm(const Index: Integer; Value: TColPrm); begin if Index >= Flist.Count then Exit; SetColumnFontName(Index, Value.FontName); SetColumnFontSize(Index, Value.FontSize); SetColumnFontStyle(Index, Value.FontStyle); SetColumnTextColor(Index, Value.TextColor); SetColumnBackground(Index, Value.Background); SetColumnBackground2(Index, Value.Background2); SetColumnMarkColor(Index, Value.MarkColor); SetColumnCursorColor(Index, Value.CursorColor); SetColumnCursorText(Index, Value.CursorText); SetColumnInactiveCursorColor(Index, Value.InactiveCursorColor); SetColumnInactiveMarkColor(Index, Value.InactiveMarkColor); SetColumnUseInvertedSelection(Index, Value.UseInvertedSelection); SetColumnUseInactiveSelColor(Index, Value.UseInactiveSelColor); SetColumnOvercolor(Index, Value.Overcolor); end; procedure TPanelColumnsClass.AddDefaultColumns; var DCFunc: String; begin fSetName := 'Default'; FFileSystem := FS_GENERAL; DCFunc := '[' + sFuncTypeDC + '().%s{}]'; // file name Add(rsColName, Format(DCFunc, [TFileFunctionStrings[fsfNameNoExtension]]), 250, taLeftJustify); // file ext Add(rsColExt, Format(DCFunc, [TFileFunctionStrings[fsfExtension]]), 50, taLeftJustify); // file size Add(rsColSize, Format(DCFunc, [TFileFunctionStrings[fsfSize]]), 70, taRightJustify); // file date/time Add(rsColDate, Format(DCFunc, [TFileFunctionStrings[fsfModificationTime]]), 140, taRightJustify); // file attributes Add(rsColAttr, Format(DCFunc, [TFileFunctionStrings[fsfAttr]]), 100, taLeftJustify); // Default title hash UpdateDefaultTitleHash; end; procedure TPanelColumnsClass.AddDefaultEverything; begin AddDefaultColumns; Unique := EmptyStr; FCustomView := False; FCursorBorder := gUseCursorBorder; FCursorBorderColor := gColors.FilePanel^.CursorBorderColor; FUseFrameCursor := gUseFrameCursor; end; procedure TPanelColumnsClass.Load(AConfig: TXmlConfig; ANode: TXmlNode); var Title: String; Hash: LongWord; SubNode: TXmlNode; Quality: Integer = 0; AColumn: TPanelColumn; APixelsPerInch: Integer; begin Unique := AConfig.GetValue(ANode, 'Unique', EmptyStr); FCustomView := AConfig.GetValue(ANode, 'CustomView', False); FFileSystem := AConfig.GetValue(ANode, 'FileSystem', FS_GENERAL); APixelsPerInch:= AConfig.GetValue(ANode, 'PixelsPerInch', Screen.PixelsPerInch); FCursorBorder := AConfig.GetAttr(ANode, 'CursorBorder/Enabled', gUseCursorBorder); FUseFrameCursor := AConfig.GetAttr(ANode, 'UseFrameCursor', gUseFrameCursor); if (LoadedConfigVersion < JsonConfigVersion) then begin FCursorBorderColor := TColor(AConfig.GetValue(ANode, 'CursorBorder/Color', gColors.FilePanel^.CursorBorderColor)); end; Clear; SubNode := ANode.FindNode('Columns'); if Assigned(SubNode) then begin SubNode := SubNode.FirstChild; while Assigned(SubNode) do begin if SubNode.CompareName('Column') = 0 then begin AColumn := TPanelColumn.Create; FList.Add(AColumn); AColumn.Title := AConfig.GetValue(SubNode, 'Title', ''); AColumn.Unique := AConfig.GetValue(SubNode, 'Unique', ''); AColumn.FuncString := AConfig.GetValue(SubNode, 'FuncString', ''); AColumn.Width := AConfig.GetValue(SubNode, 'Width', 50); AColumn.Width := MulDiv(AColumn.Width, Screen.PixelsPerInch, APixelsPerInch); AColumn.Align := TAlignment(AConfig.GetValue(SubNode, 'Align', Integer(0))); AConfig.GetFont(SubNode, 'Font', AColumn.FontName, AColumn.FontSize, Integer(AColumn.FontStyle), Quality, gFonts[dcfMain].Name, gFonts[dcfMain].Size, Integer(gFonts[dcfMain].Style), Quality); if (LoadedConfigVersion < JsonConfigVersion) then begin with gColors.FilePanel^ do begin AColumn.TextColor := TColor(AConfig.GetValue(SubNode, 'TextColor', ForeColor)); AColumn.Background := TColor(AConfig.GetValue(SubNode, 'Background', BackColor)); AColumn.Background2 := TColor(AConfig.GetValue(SubNode, 'Background2', BackColor2)); AColumn.MarkColor := TColor(AConfig.GetValue(SubNode, 'MarkColor', MarkColor)); AColumn.CursorColor := TColor(AConfig.GetValue(SubNode, 'CursorColor', CursorColor)); AColumn.CursorText := TColor(AConfig.GetValue(SubNode, 'CursorText', CursorText)); AColumn.InactiveCursorColor := TColor(AConfig.GetValue(SubNode, 'InactiveCursorColor', InactiveCursorColor)); AColumn.InactiveMarkColor := TColor(AConfig.GetValue(SubNode, 'InactiveMarkColor', InactiveMarkColor)); end; end; AColumn.UseInvertedSelection := AConfig.GetValue(SubNode, 'UseInvertedSelection', gUseInvertedSelection); AColumn.UseInactiveSelColor := AConfig.GetValue(SubNode, 'UseInactiveSelColor', gUseInactiveSelColor); AColumn.Overcolor := AConfig.GetValue(SubNode, 'Overcolor', True); end; SubNode := SubNode.NextSibling; end; end; if Count = 0 then AddDefaultColumns else begin Title:= EmptyStr; for Quality:= 0 to Count - 1 do begin Title += TPanelColumn(Flist[Quality]).Title; end; Hash:= CRC32(0, nil, 0); Hash:= CRC32(Hash, Pointer(Title), Length(Title)); if Hash = DefaultTitleHash then begin SetColumnTitle(0, rsColName); SetColumnTitle(1, rsColExt); SetColumnTitle(2, rsColSize); SetColumnTitle(3, rsColDate); SetColumnTitle(4, rsColAttr); // Default title hash UpdateDefaultTitleHash; end; end; end; procedure TPanelColumnsClass.Save(AConfig: TXmlConfig; ANode: TXmlNode); var I: Integer; SubNode: TXmlNode; AColumn: TPanelColumn; begin AConfig.SetValue(ANode, 'Unique', Unique); AConfig.SetValue(ANode, 'CustomView', FCustomView); AConfig.SetValue(ANode, 'FileSystem', FFileSystem); AConfig.SetValue(ANode, 'PixelsPerInch', Screen.PixelsPerInch); AConfig.SetAttr(ANode, 'CursorBorder/Enabled', FCursorBorder); AConfig.SetAttr(ANode, 'UseFrameCursor', FUseFrameCursor); ANode := AConfig.FindNode(ANode, 'Columns', True); AConfig.ClearNode(ANode); for I := 0 to FList.Count - 1 do begin AColumn := TPanelColumn(FList[I]); SubNode := AConfig.AddNode(ANode, 'Column'); AConfig.AddValue(SubNode, 'Title', AColumn.Title); AConfig.AddValue(SubNode, 'Unique', AColumn.Unique); AConfig.AddValue(SubNode, 'FuncString', AColumn.FuncString); AConfig.AddValue(SubNode, 'Width', AColumn.Width); AConfig.AddValue(SubNode, 'Align', Integer(AColumn.Align)); AConfig.SetFont(SubNode, 'Font', AColumn.FontName, AColumn.FontSize, Integer(AColumn.FontStyle), 0); AConfig.AddValue(SubNode, 'UseInvertedSelection', AColumn.UseInvertedSelection); AConfig.AddValue(SubNode, 'UseInactiveSelColor', AColumn.UseInactiveSelColor); AConfig.AddValue(SubNode, 'Overcolor', AColumn.Overcolor); end; end; procedure TPanelColumnsClass.LoadColors(ANode: TJSONObject); var I, J: Integer; AName: String; AList: TJSONArray; AItem: TJSONObject; AColumn: TPanelColumn; begin FCursorBorderColor:= ANode.Get('CursorBorderColor', gColors.FilePanel^.CursorBorderColor); if ANode.Find('Columns', AList) then begin for I:= 0 to Count - 1 do begin AColumn:= GetColumnItem(I); for J:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[J]; AName:= AItem.Get('Unique', EmptyStr); if AColumn.FUnique = AName then begin with gColors.FilePanel^ do begin AColumn.TextColor := AItem.Get('TextColor', ForeColor); AColumn.Background := AItem.Get('Background', BackColor); AColumn.Background2 := AItem.Get('Background2', BackColor2); AColumn.MarkColor := AItem.Get('MarkColor', MarkColor); AColumn.CursorColor := AItem.Get('CursorColor', CursorColor); AColumn.CursorText := AItem.Get('CursorText', CursorText); AColumn.InactiveCursorColor := AItem.Get('InactiveCursorColor', InactiveCursorColor); AColumn.InactiveMarkColor := AItem.Get('InactiveMarkColor', InactiveMarkColor); end; Break; end; end; end; end; end; procedure TPanelColumnsClass.AddColumn(AList: TJSONArray; AColumn: TPanelColumn); var AItem: TJSONObject; begin AItem:= TJSONObject.Create; AItem.Add('Unique', AColumn.Unique); AItem.Add('Title', AColumn.Title); AItem.Add('TextColor', AColumn.TextColor); AItem.Add('Background', AColumn.Background); AItem.Add('Background2', AColumn.Background2); AItem.Add('MarkColor', AColumn.MarkColor); AItem.Add('CursorColor', AColumn.CursorColor); AItem.Add('CursorText', AColumn.CursorText); AItem.Add('InactiveCursorColor', AColumn.InactiveCursorColor); AItem.Add('InactiveMarkColor', AColumn.InactiveMarkColor); AList.Add(AItem); end; procedure TPanelColumnsClass.SaveColors(ANode: TJSONObject); var I: Integer; AList: TJSONArray; begin ANode.Add('Unique', Unique); ANode.Add('Name', Name); ANode.Add('CursorBorderColor', FCursorBorderColor); if ANode.Find('Columns', AList) then AList.Clear else begin AList:= TJSONArray.Create; ANode.Add('Columns', AList); end; for I := 0 to FList.Count - 1 do begin AddColumn(AList, TPanelColumn(FList[I])); end; end; procedure TPanelColumnsClass.Synchronize(ANode: TJSONObject); var I, J: Integer; AName: String; Found: Boolean; AList: TJSONArray; AItem: TJSONObject; AColumn: TPanelColumn; begin ANode.Strings['Name']:= Name; if ANode.Find('Columns', AList) then begin // Insert for I:= 0 to Count - 1 do begin Found:= False; AColumn:= GetColumnItem(I); for J:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[J]; AName:= AItem.Get('Unique', EmptyStr); if AColumn.FUnique = AName then begin Found:= True; Break; end; end; if not Found then begin AddColumn(AList, AColumn); end; end; // Delete for I:= AList.Count - 1 downto 0 do begin Found:= False; AItem:= AList.Objects[I]; AName:= AItem.Get('Unique', EmptyStr); for J:= 0 to Count - 1 do begin AColumn:= GetColumnItem(J); if AColumn.FUnique = AName then begin Found:= True; Break; end; end; if not Found then begin AList.Delete(I); end; end; end; end; procedure TPanelColumnsClass.Delete(const Index: Integer); begin if Index > Flist.Count then Exit; TPanelColumn(Flist[Index]).Free; FList.Delete(Index); end; procedure TPanelColumnsClass.Exchange(Index1, Index2: Integer); begin FList.Exchange(Index1, Index2); end; function TPanelColumnsClass.GetSignature(Seed:dword=$000000):dword; procedure ProgressSignatureWithThisString(sSomething:string); begin if length(sSomething) > 0 then Result := crc32(Result, @sSomething[1], length(sSomething)); end; var iPanelColumnIndex: integer; iFunction: integer; begin result:=Seed; for iPanelColumnIndex := 0 to pred(Count) do begin with TPanelColumn(Flist[iPanelColumnIndex]) do begin ProgressSignatureWithThisString(Title); for iFunction:=0 to pred(FuncList.Count) do ProgressSignatureWithThisString(FuncList.Strings[iFunction]); Result := crc32(Result, @Width, sizeof(Width)); Result := crc32(Result, @Align, sizeof(Align)); if FCustomView then begin ProgressSignatureWithThisString(FontName); Result := crc32(Result, @FontSize, sizeof(FontSize)); Result := crc32(Result, @FontStyle, sizeof(FontStyle)); Result := crc32(Result, @TextColor, sizeof(TextColor)); Result := crc32(Result, @Background, sizeof(Background)); Result := crc32(Result, @Background2, sizeof(Background2)); Result := crc32(Result, @MarkColor, sizeof(MarkColor)); Result := crc32(Result, @CursorColor, sizeof(CursorColor)); Result := crc32(Result, @CursorText, sizeof(CursorText)); Result := crc32(Result, @InactiveCursorColor, sizeof(InactiveCursorColor)); Result := crc32(Result, @InactiveMarkColor, sizeof(InactiveMarkColor)); Result := crc32(Result, @UseInvertedSelection, sizeof(UseInvertedSelection)); Result := crc32(Result, @UseInactiveSelColor, sizeof(UseInactiveSelColor)); Result := crc32(Result, @Overcolor, sizeof(Overcolor)); end; end; end; ProgressSignatureWithThisString(fSetName); Result := crc32(Result, @FCustomView, sizeof(FCustomView)); Result := crc32(Result, @FCursorBorder, sizeof(FCursorBorder)); Result := crc32(Result, @FCursorBorderColor, sizeof(FCursorBorderColor)); Result := crc32(Result, @FUseFrameCursor, sizeof(FUseFrameCursor)); end; { TPanelColumn } constructor TPanelColumn.Create; begin FuncList := TStringList.Create; end; constructor TPanelColumn.CreateNew; begin Create; FUnique:= GetUnique; end; destructor TPanelColumn.Destroy; begin FreeAndNil(FuncList); inherited Destroy; end; function TPanelColumn.GetColumnResultString(AFile: TFile; const AFileSource: IFileSource): String; var i: Integer; s: String; begin s := ''; Result := ''; if (not Assigned(FuncList)) or (FuncList.Count = 0) then Exit; for i := 0 to FuncList.Count - 1 do begin //Item is simpletext if PtrInt(FuncList.Objects[i]) = 0 then s := s + FuncList[I] else //Item is function begin s := s + FormatFileFunction(FuncList[I], AFile, AFileSource); end; end; Result := s; end; procedure TPanelColumn.SetUnique(const AValue: String); begin if Length(AValue) > 0 then FUnique:= AValue else begin FUnique:= GetUnique; end; end; procedure TPanelColumn.SetFuncString(NewValue: String); procedure FillListFromString(List: TStrings; FuncS: String); var p: Integer; begin while True do begin p := pos('[', FuncS); if p = 0 then Break else if p > 1 then List.AddObject(Copy(FuncS, 1, p - 1), TObject(0)); Delete(FuncS, 1, p); p := pos(']', FuncS); if p = 0 then Break else if p > 1 then List.AddObject(Copy(FuncS, 1, p - 1), TObject(1)); Delete(FuncS, 1, p); end; if FuncS <> '' then List.AddObject(FuncS, TObject(0)); end; begin FuncList.Clear; FFuncString := NewValue; FillListFromString(FuncList, NewValue); end; { TPanelColumnsList } function TPanelColumnsList.GetCount: Integer; begin Result := fSet.Count; end; procedure TPanelColumnsList.Synchronize(Item: TPanelColumnsClass); var AName: String; Index: Integer; Found: Boolean; AList: TJSONArray; AItem: TJSONObject; procedure AddItem; begin AItem:= TJSONObject.Create; Item.SaveColors(AItem); AList.Add(AItem); end; begin // Current style Found:= False; AName:= Item.Unique; AList:= FStyles[FStyle]; for Index:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[Index]; if AName = AItem.Get('Unique', EmptyStr) then begin AItem.Clear; Found:= True; Item.SaveColors(AItem); Break; end; end; if not Found then AddItem; // Second style AList:= FStyles[Abs(FStyle - 1)]; for Index:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[Index]; if AName = AItem.Get('Unique', EmptyStr) then begin Item.Synchronize(AItem); Exit; end; end; AddItem; end; constructor TPanelColumnsList.Create; var Index: Integer; begin FSet:= TStringList.Create; FStyle:= TColorThemes.StyleIndex; for Index:= 0 to High(FStyles) do begin FStyles[Index]:= TJSONArray.Create; end; end; destructor TPanelColumnsList.Destroy; var Index: Integer; begin if Assigned(FSet) then begin for Index := 0 to Fset.Count - 1 do begin FSet.Objects[Index].Free; end; FreeAndNil(FSet); end; for Index:= 0 to High(FStyles) do begin FStyles[Index].Free; end; inherited Destroy; end; procedure TPanelColumnsList.Clear; var Index: Integer; begin for Index := 0 to Fset.Count - 1 do begin FSet.Objects[Index].Free; end; FSet.Clear; end; procedure TPanelColumnsList.UpdateStyle; var ANewStyle: Integer; begin ANewStyle:= TColorThemes.StyleIndex; if FStyle <> ANewStyle then begin SaveColors; FStyle:= ANewStyle; LoadColors; end; end; procedure TPanelColumnsList.Load(AConfig: TXmlConfig; ANode: TXmlNode); var AName: String; AnObject: TPanelColumnsClass; begin Clear; LoadedConfigVersion := AConfig.GetAttr(AConfig.RootNode, 'ConfigVersion', ConfigVersion); ANode := ANode.FindNode('ColumnsSets'); if Assigned(ANode) then begin DefaultTitleHash := AConfig.GetAttr(ANode, 'DefaultTitleHash', Int64(0)); ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('ColumnsSet') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', AName) then begin AnObject := TPanelColumnsClass.Create; fSet.AddObject(AName, AnObject); AnObject.Name := AName; AnObject.Load(AConfig, ANode); end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; end; if (LoadedConfigVersion < JsonConfigVersion) then begin SaveColors; FStyles[Abs(FStyle - 1)].Free; FStyles[Abs(FStyle - 1)]:= FStyles[FStyle].Clone as TJSONArray; end; end; procedure TPanelColumnsList.Save(AConfig: TXmlConfig; ANode: TXmlNode); var I: Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'ColumnsSets', True); AConfig.ClearNode(ANode); AConfig.SetAttr(ANode, 'DefaultTitleHash', Int64(DefaultTitleHash)); for I := 0 to FSet.Count - 1 do begin SubNode := AConfig.AddNode(ANode, 'ColumnsSet'); AConfig.AddValue(SubNode, 'Name', FSet[I]); TPanelColumnsClass(Fset.Objects[I]).Save(AConfig, SubNode); end; end; procedure TPanelColumnsList.LoadColors; var I, J: Integer; AList: TJSONArray; AItem: TJSONObject; AColSet: TPanelColumnsClass; begin AList:= FStyles[FStyle]; for I := 0 to FSet.Count - 1 do begin AColSet:= GetColumnSet(I); for J:= 0 to AList.Count - 1 do begin AItem:= AList.Objects[J]; if AColSet.FUnique = AItem.Get('Unique', EmptyStr) then begin AColSet.LoadColors(AItem); Break; end; end; end; end; procedure TPanelColumnsList.SaveColors; var Index: Integer; AList: TJSONArray; AItem: TJSONObject; AColSet: TPanelColumnsClass; begin AList:= FStyles[FStyle]; AList.Clear; for Index := 0 to FSet.Count - 1 do begin AColSet:= GetColumnSet(Index); AItem:= TJSONObject.Create; AColSet.SaveColors(AItem); AList.Add(AItem); end; end; procedure TPanelColumnsList.LoadColors(AConfig: TJSONObject); var AName: String; I, J: Integer; Style: TJSONArray; Theme: TJSONObject; Themes: TJSONArray; begin if AConfig.Find('Styles', Themes) then begin for I:= 0 to Themes.Count - 1 do begin Theme:= Themes.Objects[I]; AName:= Theme.Get('Name', EmptyStr); for J:= 0 to High(THEME_NAME) do begin if (AName = THEME_NAME[J]) then begin if Theme.Find('ColumnSets', Style) then begin FStyles[J].Free; FStyles[J]:= Style.Clone as TJSONArray; end; Break; end; end; end; LoadColors; end; end; procedure TPanelColumnsList.SaveColors(AConfig: TJSONObject); var AName: String; I, J: Integer; Theme: TJSONObject; Themes: TJSONArray; begin SaveColors; if AConfig.Find('Styles', Themes) then begin for I:= 0 to Themes.Count - 1 do begin Theme:= Themes.Objects[I]; AName:= Theme.Get('Name', EmptyStr); for J:= 0 to High(THEME_NAME) do begin if (AName = THEME_NAME[J]) then begin Theme.Arrays['ColumnSets']:= FStyles[J].Clone as TJSONArray; Break; end; end; end; end; end; function TPanelColumnsList.Add(Item: TPanelColumnsClass): Integer; begin Result := Fset.AddObject(Item.Name, Item); Synchronize(Item); end; procedure TPanelColumnsList.Insert(AIndex: Integer; Item: TPanelColumnsClass); begin Fset.InsertObject(AIndex, Item.Name, Item); Synchronize(Item); end; procedure TPanelColumnsList.DeleteColumnSet(SetName: String); begin DeleteColumnSet(fSet.IndexOf(SetName)); end; procedure TPanelColumnsList.DeleteColumnSet(SetIndex: Integer); begin if (SetIndex >= Fset.Count) or (SetIndex < 0) then Exit; TPanelColumnsClass(fSet.Objects[SetIndex]).Free; fSet.Delete(SetIndex); end; procedure TPanelColumnsList.CopyColumnSet(SetName, NewSetName: String); var OldSetIndex, NewSetIndex: Integer; OldSet, NewSet: TPanelColumnsClass; begin OldSetIndex := fSet.IndexOf(SetName); if OldSetIndex <> -1 then begin OldSet := TPanelColumnsClass(fSet.Objects[OldSetIndex]); NewSetIndex := fSet.IndexOf(NewSetName); if NewSetIndex <> -1 then NewSet := TPanelColumnsClass(fSet.Objects[NewSetIndex]) else begin NewSet := TPanelColumnsClass.Create; fSet.AddObject(NewSetName, NewSet); end; NewSet.Assign(OldSet); // Set new name. NewSet.Name := NewSetName; end; end; function TPanelColumnsList.GetColumnSet(const Index: Integer): TPanelColumnsClass; begin //DCDebug('FsetCount='+inttostr(fset.Count)); if (Index > -1) and (Index < Fset.Count) then Result := TPanelColumnsClass(Fset.Objects[Index]) else begin if fset.Count = 0 then begin Result:= TPanelColumnsClass.Create; Result.AddDefaultEverything; Add(Result); end; Result := TPanelColumnsClass(Fset.Objects[0]); end; end; function TPanelColumnsList.GetColumnSet(Setname: String): TPanelColumnsClass; begin Result:= GetColumnSet(FSet.IndexOf(Setname)); end; function TPanelColumnsList.GetColumnSet(const AName, FileSystem: String): TPanelColumnsClass; var Index: Integer; begin if (FileSystem = EmptyStr) or SameText(FileSystem, FS_GENERAL) then Result:= GetColumnSet(AName) else begin for Index:= 0 to Fset.Count - 1 do begin if SameText(AName, fset[Index]) and SameText(FileSystem, TPanelColumnsClass(Fset.Objects[Index]).FileSystem) then begin Exit(TPanelColumnsClass(Fset.Objects[Index])); end; end; Result:= nil; end; end; { TColPrm } constructor TColPrm.Create; begin Self.FontName := gFonts[dcfMain].Name; Self.FontSize := gFonts[dcfMain].Size; Self.FontStyle := gFonts[dcfMain].Style; with gColors.FilePanel^ do begin Self.TextColor := ForeColor; Self.Background := BackColor; Self.Background2 := BackColor2; Self.MarkColor := MarkColor; Self.CursorColor := CursorColor; Self.CursorText := CursorText; Self.InactiveCursorColor := InactiveCursorColor; Self.InactiveMarkColor := InactiveMarkColor; end; Self.UseInvertedSelection:= gUseInvertedSelection; Self.UseInactiveSelColor:= gUseInactiveSelColor; Self.Overcolor := gAllowOverColor; end; end. �����������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uconnectionmanager.pas���������������������������������������������������������0000644�0001750�0000144�00000015731�14743153644�017770� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uConnectionManager; {$mode delphi} interface uses Classes, SysUtils, uFileSource, uDrive, uDrivesList; type TFileSourceRecord = record Count: Integer; Name, Path: String; FileSource: IFileSource; end; PFileSourceRecord = ^TFileSourceRecord; function GetNetworkPath(ADrive: PDrive): String; procedure UpdateDriveList(ADriveList: TDrivesList); procedure ShowVirtualDriveMenu(ADrive: PDrive; X, Y : Integer; CloseEvent: TNotifyEvent); procedure AddNetworkConnection(const Name, Path: String; FileSource: IFileSource); procedure RemoveNetworkConnection(const Name, Path: String); procedure CloseNetworkConnection(); var WfxConnectionList: TStringList = nil; implementation uses Forms, Menus, StrUtils, DCStrUtils, fMain, uWfxPluginFileSource, uLog, uGlobs, uFileSourceUtil, uFileView; var ContextMenu: TPopupMenu = nil; function GetConnectionName(const Name, Path: String): String; inline; begin Result:= Name + ': ' + Path; end; function NewFileSourceRecord(FileSource: IFileSource; const Name, Path: String): PFileSourceRecord; begin New(Result); Result^.Count:= 1; Result^.Name:= Name; Result^.Path:= Path; Result^.FileSource:= FileSource; end; procedure DisposeFileSourceRecord(FileSourceRecord: PFileSourceRecord); begin FileSourceRecord^.FileSource:= nil; Dispose(FileSourceRecord); end; procedure CloseConnection(Index: Integer); var Connection: TFileSourceRecord; FileSource: IWfxPluginFileSource; begin PFileSourceRecord(WfxConnectionList.Objects[Index]).Count:= 1; Connection:= PFileSourceRecord(WfxConnectionList.Objects[Index])^; FileSource:= Connection.FileSource as IWfxPluginFileSource; if FileSource.WfxModule.WfxDisconnect(Connection.Path) then begin RemoveNetworkConnection(Connection.Name, Connection.Path); end; with frmMain do begin if ActiveFrame.FileSource.Equals(FileSource) and IsInPath(Connection.Path, ActiveFrame.CurrentPath, True, True) then begin ActiveFrame.RemoveCurrentFileSource; end else if NotActiveFrame.FileSource.Equals(FileSource) and IsInPath(Connection.Path, NotActiveFrame.CurrentPath, True, True) then begin NotActiveFrame.RemoveCurrentFileSource end; end; end; procedure OnNetworkDisconnect(Self, Sender: TObject); var Index: Integer; MenuItem: TMenuItem absolute Sender; begin Index:= WfxConnectionList.IndexOf(MenuItem.Hint); if Index >= 0 then CloseConnection(Index); end; function GetNetworkPath(ADrive: PDrive): String; begin Result:= ADrive^.DeviceId + StringReplace(ADrive^.Path, '\', '/', [rfReplaceAll]); end; procedure UpdateDriveList(ADriveList: TDrivesList); var Drive: PDrive; Index: Integer; FileSourceRecord: PFileSourceRecord; begin for Index:= 0 to WfxConnectionList.Count - 1 do begin FileSourceRecord:= PFileSourceRecord(WfxConnectionList.Objects[Index]); New(Drive); Drive^.DriveSize:= 0; Drive^.IsMounted:= True; Drive^.DriveType:= dtVirtual; Drive^.Path:= FileSourceRecord.Path; Drive^.DisplayName:= IntToStr(Index); Drive^.DeviceId:= 'wfx://' + FileSourceRecord.Name; Drive^.DriveLabel:= GetConnectionName(FileSourceRecord.Name, FileSourceRecord.Path); ADriveList.Add(Drive); end; end; procedure ShowVirtualDriveMenu(ADrive: PDrive; X, Y: Integer; CloseEvent: TNotifyEvent); var Handler: TMethod; MenuItem: TMenuItem; begin if not StrBegins(ADrive^.DeviceId, 'wfx://') then Exit; // Free previous created menu FreeAndNil(ContextMenu); // Create new context menu ContextMenu:= TPopupMenu.Create(nil); ContextMenu.OnClose := CloseEvent; MenuItem:= TMenuItem.Create(ContextMenu); MenuItem.Caption:= ADrive.DriveLabel; MenuItem.Enabled:= False; ContextMenu.Items.Add(MenuItem); MenuItem:= TMenuItem.Create(ContextMenu); MenuItem.Caption:= '-'; ContextMenu.Items.Add(MenuItem); MenuItem:= TMenuItem.Create(ContextMenu); MenuItem.Caption:= frmMain.actNetworkDisconnect.Caption; MenuItem.Hint:= ADrive.DriveLabel; Handler.Data:= MenuItem; Handler.Code:= @OnNetworkDisconnect; MenuItem.OnClick:= TNotifyEvent(Handler); ContextMenu.Items.Add(MenuItem); // Show context menu ContextMenu.PopUp(X, Y); end; procedure AddNetworkConnection(const Name, Path: String; FileSource: IFileSource); var Index: Integer; ConnectionName: String; FileSourceRecord: PFileSourceRecord; begin ConnectionName:= GetConnectionName(Name, Path); Index:= WfxConnectionList.IndexOf(ConnectionName); if Index >= 0 then begin FileSourceRecord:= PFileSourceRecord(WfxConnectionList.Objects[Index]); FileSourceRecord.Count:= FileSourceRecord.Count + 1; end else begin FileSourceRecord:= NewFileSourceRecord(FileSource, Name, Path); WfxConnectionList.AddObject(ConnectionName, TObject(FileSourceRecord)); with frmMain do begin miNetworkDisconnect.Enabled:= WfxConnectionList.Count > 0; UpdateDiskCount; end; end; end; procedure RemoveNetworkConnection(const Name, Path: String); var Index: Integer; ConnectionName: String; FileSourceRecord: PFileSourceRecord; begin ConnectionName:= GetConnectionName(Name, Path); Index:= WfxConnectionList.IndexOf(ConnectionName); if Index >= 0 then with frmMain do begin FileSourceRecord:= PFileSourceRecord(WfxConnectionList.Objects[Index]); FileSourceRecord^.Count:= FileSourceRecord^.Count - 1; if FileSourceRecord^.Count > 0 then Exit; DisposeFileSourceRecord(PFileSourceRecord(WfxConnectionList.Objects[Index])); WfxConnectionList.Delete(Index); miNetworkDisconnect.Enabled:= WfxConnectionList.Count > 0; if WfxConnectionList.Count = 0 then begin if gLogWindow = False then begin ShowLogWindow(PtrInt(False)); end; end; UpdateDiskCount; end; end; procedure CloseNetworkConnection; var Index: Integer; ConnectionName: String; FileView: TFileView = nil; begin if WfxConnectionList.Count > 0 then with frmMain do begin if ActiveFrame.FileSource.IsInterface(IWfxPluginFileSource) and (ActiveFrame.CurrentPath <> PathDelim) then FileView:= ActiveFrame else if NotActiveFrame.FileSource.IsInterface(IWfxPluginFileSource) and (NotActiveFrame.CurrentPath <> PathDelim) then begin FileView:= NotActiveFrame end; if Assigned(FileView) then begin ConnectionName:= ExtractWord(2, FileView.CurrentAddress, ['/']); ConnectionName:= GetConnectionName(ConnectionName, PathDelim + ExtractWord(1, FileView.CurrentPath, [PathDelim])); Index:= WfxConnectionList.IndexOf(ConnectionName); if Index >= 0 then CloseConnection(Index); end // Close last connection else begin CloseConnection(WfxConnectionList.Count - 1); end; end; end; initialization WfxConnectionList:= TStringList.Create; finalization FreeAndNil(WfxConnectionList); end. ���������������������������������������doublecmd-1.1.22/src/uconvencoding.pas��������������������������������������������������������������0000644�0001750�0000144�00000041454�14743153644�016753� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Encoding conversion and related stuff Copyright (C) 2011-2022 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uConvEncoding; {$mode delphi} interface uses Classes; const EncodingOem = 'oem'; EncodingNone = 'none'; EncodingDefault = 'default'; EncodingUTF16LE = 'utf16le'; EncodingUTF16BE = 'utf16be'; type TMacroEncoding = (meOEM, meANSI, meUTF8, meUTF8BOM, meUTF16LE, meUTF16BE); function HexToBin(HexString: String): String; function TextIsASCII(const S: String): Boolean; procedure GetSupportedEncodings(List: TStrings); function DetectEncoding(const S: String): String; overload; function SingleByteEncoding(TextEncoding: String): Boolean; function DetectEncoding(const S: String; ADefault: TMacroEncoding; AStrict: Boolean): TMacroEncoding; overload; function ConvertEncoding(const S, FromEncoding, ToEncoding: String{$ifdef FPC_HAS_CPSTRING}; SetTargetCodePage: Boolean = False{$endif}): String; implementation uses SysUtils, LazUTF8, LConvEncoding, GetText, DCConvertEncoding, DCUnicodeUtils, nsCore, nsUniversalDetector, uLng, uGlobs; var SupportedEncodings: TStringList = nil; type TMyCodePages = (cp1251, cpKOI8R, cp866); const scCodePage : array[TMyCodePages] of AnsiString = ( // CP1251 (WINDOWS) #$C0#$E0 + // Аа #$C1#$E1 + // Бб #$C2#$E2 + // Вв #$C3#$E3 + // Гг #$C4#$E4 + // Дд #$C5#$E5 + // Ее #$A8#$B8 + // Ёё #$C6#$E6 + // Жж #$C7#$E7 + // Зз #$C8#$E8 + // Ии #$C9#$E9 + // Йй #$CA#$EA + // Кк #$CB#$EB + // Лл #$CC#$EC + // Мм #$CD#$ED + // Нн #$CE#$EE + // Оо #$CF#$EF + // Пп #$D0#$F0 + // Рр #$D1#$F1 + // Сс #$D2#$F2 + // Тт #$D3#$F3 + // Уу #$D4#$F4 + // Фф #$D5#$F5 + // Хх #$D6#$F6 + // Цц #$D7#$F7 + // Чч #$D8#$F8 + // Шш #$D9#$F9 + // Щщ #$DA#$FA + // Ъъ #$DB#$FB + // Ыы #$DC#$FC + // Ьь #$DD#$FD + // Ээ #$DE#$FE + // Юю #$DF#$FF , // Яя // KOI8-R (UNIX) #$E1#$C1 + // Аа #$E2#$C2 + // Бб #$F7#$D7 + // Вв #$E7#$C7 + // Гг #$E4#$C4 + // Дд #$E5#$C5 + // Ее #$B3#$A3 + // Ёё #$F6#$D6 + // Жж #$FA#$DA + // Зз #$E9#$C9 + // Ии #$EA#$CA + // Йй #$EB#$CB + // Кк #$EC#$CC + // Лл #$ED#$CD + // Мм #$EE#$CE + // Нн #$EF#$CF + // Оо #$F0#$D0 + // Пп #$F2#$D2 + // Рр #$F3#$D3 + // Сс #$F4#$D4 + // Тт #$F5#$D5 + // Уу #$E6#$C6 + // Фф #$E8#$C8 + // Хх #$E3#$C3 + // Цц #$FE#$DE + // Чч #$FB#$DB + // Шш #$FD#$DD + // Щщ #$FF#$DF + // Ъъ #$F9#$D9 + // Ыы #$F8#$D8 + // Ьь #$FC#$DC + // Ээ #$E0#$C0 + // Юю #$F1#$D1 , // Яя // CP866 (DOS) #$80#$A0 + // Аа #$81#$A1 + // Бб #$82#$A2 + // Вв #$83#$A3 + // Гг #$84#$A4 + // Дд #$85#$A5 + // Ее #$F0#$F1 + // Ёё #$86#$A6 + // Жж #$87#$A7 + // Зз #$88#$A8 + // Ии #$89#$A9 + // Йй #$8A#$AA + // Кк #$8B#$AB + // Лл #$8C#$AC + // Мм #$8D#$AD + // Нн #$8E#$AE + // Оо #$8F#$AF + // Пп #$90#$E0 + // Рр #$91#$E1 + // Сс #$92#$E2 + // Тт #$93#$E3 + // Уу #$94#$E4 + // Фф #$95#$E5 + // Хх #$96#$E6 + // Цц #$97#$E7 + // Чч #$98#$E8 + // Шш #$99#$E9 + // Щщ #$9A#$EA + // Ъъ #$9B#$EB + // Ыы #$9C#$EC + // Ьь #$9D#$ED + // Ээ #$9E#$EE + // Юю #$9F#$EF // Яя ); var svStatistic : array[AnsiChar] of Single; procedure InitStatistic; begin FillChar(svStatistic, SizeOf(svStatistic), 0); // CP1251 (WINDOWS) svStatistic[#$C0] := 0.001; // 'А' svStatistic[#$C1] := 0; // 'Б' svStatistic[#$C2] := 0.002; // 'В' svStatistic[#$C3] := 0; // 'Г' svStatistic[#$C4] := 0.001; // 'Д' svStatistic[#$C5] := 0.001; // 'Е' svStatistic[#$C6] := 0; // 'Ж' svStatistic[#$C7] := 0; // 'З' svStatistic[#$C8] := 0.001; // 'И' svStatistic[#$C9] := 0; // 'Й' svStatistic[#$CA] := 0.001; // 'К' svStatistic[#$CB] := 0; // 'Л' svStatistic[#$CC] := 0.001; // 'М' svStatistic[#$CD] := 0.001; // 'Н' svStatistic[#$CE] := 0.001; // 'О' svStatistic[#$CF] := 0.002; // 'П' svStatistic[#$D0] := 0.002; // 'Р' svStatistic[#$D1] := 0.001; // 'С' svStatistic[#$D2] := 0.001; // 'Т' svStatistic[#$D3] := 0; // 'У' svStatistic[#$D4] := 0; // 'Ф' svStatistic[#$D5] := 0; // 'Х' svStatistic[#$D6] := 0; // 'Ц' svStatistic[#$D7] := 0.001; // 'Ч' svStatistic[#$D8] := 0.001; // 'Ш' svStatistic[#$D9] := 0; // 'Щ' svStatistic[#$DA] := 0; // 'Ъ' svStatistic[#$DB] := 0; // 'Ы' svStatistic[#$DC] := 0; // 'Ь' svStatistic[#$DD] := 0.001; // 'Э' svStatistic[#$DE] := 0; // 'Ю' svStatistic[#$DF] := 0; // 'Я' svStatistic[#$E0] := 0.057; // 'а' svStatistic[#$E1] := 0.01; // 'б' svStatistic[#$E2] := 0.031; // 'в' svStatistic[#$E3] := 0.011; // 'г' svStatistic[#$E4] := 0.021; // 'д' svStatistic[#$E5] := 0.067; // 'е' svStatistic[#$E6] := 0.007; // 'ж' svStatistic[#$E7] := 0.013; // 'з' svStatistic[#$E8] := 0.052; // 'и' svStatistic[#$E9] := 0.011; // 'й' svStatistic[#$EA] := 0.023; // 'к' svStatistic[#$EB] := 0.03; // 'л' svStatistic[#$EC] := 0.024; // 'м' svStatistic[#$ED] := 0.043; // 'н' svStatistic[#$EE] := 0.075; // 'о' svStatistic[#$EF] := 0.026; // 'п' svStatistic[#$F0] := 0.038; // 'р' svStatistic[#$F1] := 0.034; // 'с' svStatistic[#$F2] := 0.046; // 'т' svStatistic[#$F3] := 0.016; // 'у' svStatistic[#$F4] := 0.001; // 'ф' svStatistic[#$F5] := 0.006; // 'х' svStatistic[#$F6] := 0.002; // 'ц' svStatistic[#$F7] := 0.011; // 'ч' svStatistic[#$F8] := 0.004; // 'ш' svStatistic[#$F9] := 0.004; // 'щ' svStatistic[#$FA] := 0; // 'ъ' svStatistic[#$FB] := 0.012; // 'ы' svStatistic[#$FC] := 0.012; // 'ь' svStatistic[#$FD] := 0.003; // 'э' svStatistic[#$FE] := 0.005; // 'ю' svStatistic[#$FF] := 0.015; // 'я' end; function MyConvertString(const S: AnsiString; const FromCP, ToCP: TMyCodePages): AnsiString; var I: Integer; C: AnsiChar; Chars: array [AnsiChar] of AnsiChar; begin Result:= S; if FromCP = ToCP then Exit; for C := #0 to #255 do Chars[C] := C; for I := 1 to Length(scCodePage[cp1251]) do Chars[scCodePage[FromCP][I]] := scCodePage[ToCP][I]; for I := 1 to Length(s) do Result[I] := Chars[Result[I]]; end; function DetectCharsetCyrillic(const S: AnsiString): AnsiString; var I: Integer; J: LongWord; C: AnsiChar; D, M: Single; T: AnsiString; CodePage: TMyCodePages; CharCount: array [AnsiChar] of Integer; begin J := 0; M := 0; T := S; FillChar(CharCount, SizeOf(CharCount), 0); for I := 1 to Length(S) do Inc(CharCount[S[I]]); // Check for CP866 encoding for C := #$80 {'А'} to #$AF {'п'} do Inc(J, CharCount[C]); if J > (Length(S) div 3) then begin Result := 'CP866'; Exit; end; for C := #$C0 {'А'} to #$FF {'я'} do M := M + sqr(CharCount[C] / Length(S) - svStatistic[C]); for CodePage := Low(TMyCodePages) to High(TMyCodePages) do begin // Convert to cp1251, because statistic in this encoding T:= MyConvertString(S, CodePage, cp1251); FillChar(CharCount, SizeOf(CharCount), 0); for I := 1 to Length(T) do Inc(CharCount[T[I]]); D := 0; for C := #$C0 {'А'} to #$FF {'я'} do D := D + sqr(CharCount[C] / Length(S) - svStatistic[C]); if D <= M then begin M := D; case CodePage of cp1251 : Result:= 'CP1251'; cpKOI8R: Result:= 'KOI8-R'; cp866 : Result:= 'CP866'; end; end; end; end; function MyDetectCodePageType(const S: AnsiString): AnsiString; var Detector: TnsUniversalDetector = nil; CharsetInfo: rCharsetInfo; begin Detector:= TnsUniversalDetector.Create; try Detector.Reset; Detector.HandleData(PChar(S), Length(S)); if not Detector.Done then Detector.DataEnd; CharsetInfo:= Detector.GetDetectedCharsetInfo; case CharsetInfo.CodePage of 866: Result:= 'CP866'; 932: Result:= 'CP932'; 950: Result:= 'CP950'; 1251: Result:= 'CP1251'; 1252: Result:= 'CP1252'; 1253: Result:= 'CP1253'; 1255: Result:= 'CP1255'; 20866: Result:= 'KOI8-R'; 52936, // GB2312 54936: Result:= 'CP936'; // GB18030 51932: Result:= 'CP932'; // EUC-JP 51949: Result:= 'CP949'; // EUC-KR else begin Result:= CharsetInfo.Name; // When unknown encoding then use system encoding if SupportedEncodings.IndexOf(Result) < 0 then begin if (SystemLanguage = 'be') or (SystemLanguage = 'bg') or (SystemLanguage = 'ky') or (SystemLanguage = 'mk') or (SystemLanguage = 'mn') or (SystemLanguage = 'ru') or (SystemLanguage = 'tt') then Result:= DetectCharsetCyrillic(S) else begin Result:= GetDefaultTextEncoding; if NormalizeEncoding(Result) = EncodingUTF8 then begin // the system encoding is UTF-8, but it is not UTF-8 // use ISO-8859-1 instead. This encoding has a full 1:1 mapping to unicode, // so no character is lost during conversions. Result:= 'ISO-8859-1'; end; end; end; end; end; finally FreeAndNil(Detector); end; end; procedure GetSupportedEncodings(List: TStrings); var Index: Integer; begin if SupportedEncodings.Count > 0 then List.Assign(SupportedEncodings) else begin TStringList(List).CaseSensitive:= False; LConvEncoding.GetSupportedEncodings(List); Index:= List.IndexOf(EncodingAnsi); List[Index] := UpperCase(EncodingAnsi); List.Insert(Index + 1, UpperCase(EncodingOem)); Index:= List.IndexOf('UCS-2LE'); List[Index] := 'UTF-16LE'; Index:= List.IndexOf('UCS-2BE'); List[Index] := 'UTF-16BE'; end; end; function DetectEncoding(const S: String): String; function CompareI(p1, p2: PChar; Count: integer): boolean; var i: Integer; Chr1: Byte; Chr2: Byte; begin for i:=1 to Count do begin Chr1 := byte(p1^); Chr2 := byte(p2^); if Chr1<>Chr2 then begin if Chr1 in [97..122] then dec(Chr1,32); if Chr2 in [97..122] then dec(Chr2,32); if Chr1<>Chr2 then exit(false); end; inc(p1); inc(p2); end; Result:=true; end; var L, P: Integer; EndPos: Integer; UserEncoding: Boolean; begin UserEncoding:= (gDefaultTextEncoding <> EncodingNone); L:= Length(S); if L = 0 then begin if UserEncoding then Result:= gDefaultTextEncoding else begin Result:= GetDefaultTextEncoding; end; Exit; end; // Try detect Unicode case DetectEncoding(S, meOEM, UserEncoding) of meUTF8: Exit(EncodingUTF8); meUTF8BOM: Exit(EncodingUTF8BOM); meUTF16LE: Exit(EncodingUTF16LE); meUTF16BE: Exit(EncodingUTF16BE); end; // Try {%encoding eee} if (L >= 11) and CompareI(@S[1], '{%encoding ', 11) then begin P:= 12; while (P <= L) and (S[P] in [' ', #9]) do Inc(P); EndPos:= P; while (EndPos <= L) and (not (S[EndPos] in ['}', ' ', #9])) do Inc(EndPos); Result:= NormalizeEncoding(Copy(S, P, EndPos - P)); Exit; end; if UserEncoding then Result:= gDefaultTextEncoding else begin // Try to detect encoding Result:= MyDetectCodePageType(S); end; end; function SingleByteEncoding(TextEncoding: String): Boolean; begin TextEncoding := NormalizeEncoding(TextEncoding); if TextEncoding = EncodingDefault then TextEncoding := GetDefaultTextEncoding; Result := (TextEncoding <> EncodingUTF8) and (TextEncoding <> EncodingUTF8BOM) and (TextEncoding <> EncodingUTF16LE) and (TextEncoding <> EncodingUTF16BE); end; function DetectEncoding(const S: String; ADefault: TMacroEncoding; AStrict: Boolean): TMacroEncoding; var L, P, I: Integer; begin L:= Length(S); if L = 0 then Exit(ADefault); // Try UTF-8 BOM (Byte Order Mark) if (L >= 3) and (S[1] = #$EF) and (S[2] = #$BB ) and (S[3] = #$BF) then begin Result:= meUTF8BOM; Exit; end; // Try ucs-2le BOM FF FE if (L >= 2) and (S[1] = #$FF) and (S[2] = #$FE) then begin Result:= meUTF16LE; Exit; end; // Try ucs-2be BOM FE FF if (L >= 2) and (S[1] = #$FE) and (S[2] = #$FF) then begin Result:= meUTF16BE; Exit; end; // Try UTF-8 (this includes ASCII) P:= 1; I:= Ord(not AStrict); while (P <= L) do begin if Ord(S[P]) < 128 then begin // ASCII Inc(P); end else begin I:= UTF8CodepointStrictSize(@S[P]); if (I = 0) then begin // Ignore last char if (L - P > 2) then Result:= ADefault else begin Result:= meUTF8; end; Exit; end; Inc(P, I); end; end; if I <> 0 then Result:= meUTF8 else begin Result:= ADefault; end; end; function ConvertEncoding(const S, FromEncoding, ToEncoding: String{$ifdef FPC_HAS_CPSTRING}; SetTargetCodePage: Boolean{$endif}): String; var Encoded : Boolean; AFrom, ATo : String; begin AFrom:= NormalizeEncoding(FromEncoding); ATo:= NormalizeEncoding(ToEncoding); if AFrom = ATo then Exit(S); if S = EmptyStr then begin if ATo = EncodingUTF8BOM then Result:= UTF8BOM else begin Result := S; end; Exit; end; Encoded:= True; if AFrom = EncodingUTF8 then begin if ATo = EncodingAnsi then Result:= CeUtf8ToAnsi(S) else if ATo = EncodingOem then Result:= CeUtf8ToOem(S) else if ATo = EncodingDefault then Result:= CeUtf8ToSys(S) else if ATo = EncodingUTF16LE then Result:= Utf8ToUtf16LE(S) else if ATo = EncodingUTF16BE then Result:= Utf8ToUtf16BE(S) else Result:= ConvertEncodingFromUTF8(S, ATo, Encoded{$ifdef FPC_HAS_CPSTRING}, SetTargetCodePage{$endif}); if Encoded then Exit; end else if ATo = EncodingUTF8 then begin if AFrom = EncodingAnsi then Result:= CeAnsiToUtf8(S) else if AFrom = EncodingOem then Result:= CeOemToUtf8(S) else if AFrom = EncodingDefault then Result:= CeSysToUtf8(S) else if AFrom = EncodingUTF16LE then Result:= Utf16LEToUtf8(S) else if AFrom = EncodingUTF16BE then Result:= Utf16BEToUtf8(S) else Result:= ConvertEncodingToUTF8(S, AFrom, Encoded); if Encoded then Exit; end else begin Result:= ConvertEncodingToUTF8(S, AFrom, Encoded); if Encoded then Result:= ConvertEncodingFromUTF8(Result, ATo, Encoded{$ifdef FPC_HAS_CPSTRING}, SetTargetCodePage{$endif}); if Encoded then Exit; end; // Cannot encode: return original string Result:= S; end; function TextIsASCII(const S: String): Boolean; inline; var I: Integer; begin for I:= 1 to Length(S) do begin if Ord(S[I]) > 127 then Exit(False); end; Result:= True; end; function HexToBin(HexString: String): String; var Byte: LongRec; L, J, C: Integer; HexValue: PAnsiChar; BinValue: PAnsiChar; begin C:= 0; L:= Length(HexString); SetLength(Result, L); BinValue:= PAnsiChar(Result); HexValue:= PAnsiChar(HexString); while (L > 0) do begin // Skip space if HexValue^ = #32 then begin Dec(L); Inc(HexValue); Continue; end; // Read high and low 4 bits for J:= 1 downto 0 do begin if HexValue^ in ['A'..'F', 'a'..'f'] then Byte.Bytes[J]:= ((Ord(HexValue^) + 9) and 15) else if HexValue^ in ['0'..'9'] then Byte.Bytes[J]:= ((Ord(HexValue^)) and 15) else raise EConvertError.CreateFmt(rsMsgInvalidHexNumber, [HexValue^]); Dec(L); Inc(HexValue); end; // Result 8 bit BinValue^:= Chr(Byte.Bytes[0] + (Byte.Bytes[1] shl 4)); Inc(BinValue); Inc(C); end; SetLength(Result, C); end; initialization InitStatistic; SupportedEncodings:= TStringList.Create; GetSupportedEncodings(SupportedEncodings); finalization FreeAndNil(SupportedEncodings); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ucryptproc.pas�����������������������������������������������������������������0000644�0001750�0000144�00000033560�14743153644�016323� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains Encrypt/Decrypt classes and functions. Copyright (C) 2009-2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uCryptProc; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCClassesUtf8; type { TCryptStoreResult } TCryptStoreResult = ( csrSuccess, // Success csrFailed, // Encrypt/Decrypt failed csrWriteError, // Could not write password to password store csrNotFound, // Password not found in password store csrNoMasterKey // No master password entered yet ); { TPasswordStore } TPasswordStore = class(TIniFileEx) private FMode: Byte; FMasterStrong: Boolean; FMasterKey: AnsiString; FMasterKeyHash: AnsiString; private procedure ConvertStore; procedure UpdateMasterKey(var MasterKey: AnsiString; var MasterKeyHash: AnsiString); public constructor Create(const AFileName: String); reintroduce; public function MasterKeySet: Boolean; function HasMasterKey: Boolean; function CheckMasterKey: Boolean; function WritePassword(Prefix, Name, Connection: String; const Password: AnsiString): TCryptStoreResult; function ReadPassword(Prefix, Name, Connection: String; out Password: AnsiString): TCryptStoreResult; function DeletePassword(Prefix, Name, Connection: String): Boolean; end; procedure InitPasswordStore; var PasswordStore: TPasswordStore = nil; implementation uses LCLType, LCLStrConsts, Base64, BlowFish, MD5, HMAC, SCRYPT, SHA3_512, Hash, DCPrijndael, Argon2, uShowMsg, uGlobsPaths, uLng, uDebug, uRandom; const SCRYPT_N = (1 shl 14); SCRYPT_R = 8; SCRYPT_P = 1; const ARGON2_M = (1 shl 16); ARGON2_T = 2; ARGON2_P = 4; const AES_OFFS = 12; // (56 - 32) / 2 KEY_SIZE = SizeOf(TBlowFishKey); MAC_SIZE = SizeOf(TSHA3_256Digest); BUF_SIZE = KEY_SIZE + MAC_SIZE; type TBlowFishKeyRec = record dwSize: LongWord; case Boolean of True: (bBlowFishKey: TBlowFishKey); False: (cBlowFishKey: array [0..KEY_SIZE - 1] of AnsiChar); end; function Encode(MasterKey, Data: AnsiString): AnsiString; var BlowFishKeyRec: TBlowFishKeyRec; StringStream: TStringStream = nil; Base64EncodingStream: TBase64EncodingStream = nil; BlowFishEncryptStream: TBlowFishEncryptStream = nil; begin Result:= EmptyStr; BlowFishKeyRec.cBlowFishKey:= MasterKey; BlowFishKeyRec.dwSize:= Length(MasterKey); try StringStream:= TStringStream.Create(EmptyStr); Base64EncodingStream:= TBase64EncodingStream.Create(StringStream); BlowFishEncryptStream:= TBlowFishEncryptStream.Create(BlowFishKeyRec.bBlowFishKey, BlowFishKeyRec.dwSize, Base64EncodingStream); BlowFishEncryptStream.Write(PAnsiChar(Data)^, Length(Data)); BlowFishEncryptStream.Flush; Base64EncodingStream.Flush; Result:= StringStream.DataString; finally FreeAndNil(BlowFishEncryptStream); FreeAndNil(Base64EncodingStream); FreeAndNil(StringStream); end; end; function Decode(MasterKey, Data: AnsiString): AnsiString; var BlowFishKeyRec: TBlowFishKeyRec; StringStream: TStringStream = nil; Base64DecodingStream: TBase64DecodingStream = nil; BlowFishDeCryptStream: TBlowFishDeCryptStream = nil; begin Result:= EmptyStr; BlowFishKeyRec.cBlowFishKey:= MasterKey; BlowFishKeyRec.dwSize:= Length(MasterKey); try StringStream:= TStringStream.Create(Data); Base64DecodingStream:= TBase64DecodingStream.Create(StringStream); SetLength(Result, Base64DecodingStream.Size); BlowFishDeCryptStream:= TBlowFishDeCryptStream.Create(BlowFishKeyRec.bBlowFishKey, BlowFishKeyRec.dwSize, Base64DecodingStream); BlowFishDeCryptStream.Read(PAnsiChar(Result)^, Base64DecodingStream.Size); finally FreeAndNil(BlowFishDeCryptStream); FreeAndNil(Base64DecodingStream); FreeAndNil(StringStream); end; end; function hmac_sha3_512(AKey: PByte; AKeyLength: Integer; AMessage: AnsiString): AnsiString; var HashDesc: PHashDesc; Buffer: THashDigest; Context: THMAC_Context; begin HashDesc:= FindHash_by_ID(_SHA3_512); hmac_init({%H-}Context, HashDesc, AKey, AKeyLength); hmac_update(Context, Pointer(AMessage), Length(AMessage)); hmac_final(Context, {%H-}Buffer); SetLength(Result, HashDesc^.HDigestlen); Move(Buffer[0], Result[1], HashDesc^.HDigestlen); end; procedure DeriveBytes(Mode: Byte; MasterKey, Salt: AnsiString; var Key; KeyLen: Int32); begin if (Mode > 1) then begin argon2id_kdf(ARGON2_T, ARGON2_M, ARGON2_P, Pointer(MasterKey), Length(MasterKey), Pointer(Salt), Length(Salt), @Key, KeyLen); end else begin scrypt_kdf(Pointer(MasterKey), Length(MasterKey), Pointer(Salt), Length(Salt), SCRYPT_N, SCRYPT_R, SCRYPT_P, Key, KeyLen); end; end; function EncodeStrong(Mode: Byte; MasterKey, Data: AnsiString): AnsiString; var Salt, Hash: AnsiString; StringStream: TStringStream = nil; Buffer: array[0..BUF_SIZE - 1] of Byte; BlowFishKey: TBlowFishKey absolute Buffer; BlowFishEncryptStream: TBlowFishEncryptStream = nil; begin // Generate random salt SetLength(Salt, SizeOf(TSHA3_256Digest)); Random(PByte(Salt), SizeOf(TSHA3_256Digest)); // Generate encryption key DeriveBytes(Mode, MasterKey, Salt, {%H-}Buffer[0], SizeOf(Buffer)); // Encrypt password using encryption key StringStream:= TStringStream.Create(EmptyStr); try BlowFishEncryptStream:= TBlowFishEncryptStream.Create(BlowFishKey, SizeOf(TBlowFishKey), StringStream); try BlowFishEncryptStream.Write(PAnsiChar(Data)^, Length(Data)); finally BlowFishEncryptStream.Free; end; Result:= StringStream.DataString; finally StringStream.Free; end; if (Mode > 0) then begin with TDCP_rijndael.Create(nil) do begin Data:= Copy(Result, 1, Length(Result)); Init(Buffer[AES_OFFS], GetMaxKeySize, nil); Encrypt(PAnsiChar(Data)^, Pointer(Result)^, Length(Data)); Free; end; end; // Calculate password hash message authentication code Hash := hmac_sha3_512(@Buffer[KEY_SIZE], MAC_SIZE, Result); // Calcuate result base64 encoded string Result := EncodeStringBase64(Salt + Result + Copy(Hash, 1, 8)); end; function DecodeStrong(Mode: Byte; MasterKey, Data: AnsiString): AnsiString; var Salt, Hash: AnsiString; StringStream: TStringStream = nil; Buffer: array[0..BUF_SIZE - 1] of Byte; BlowFishKey: TBlowFishKey absolute Buffer; BlowFishDeCryptStream: TBlowFishDeCryptStream = nil; begin Data:= DecodeStringBase64(Data); Hash:= Copy(Data, Length(Data) - 7, 8); Data:= Copy(Data, 1, Length(Data) - 8); Salt:= Copy(Data, 1, SizeOf(TSHA3_256Digest)); Data:= Copy(Data, SizeOf(TSHA3_256Digest) + 1, MaxInt); // Generate encryption key DeriveBytes(Mode, MasterKey, Salt, {%H-}Buffer[0], SizeOf(Buffer)); // Verify password using hash message authentication code Salt:= hmac_sha3_512(@Buffer[KEY_SIZE], MAC_SIZE, Data); if StrLComp(Pointer(Hash), Pointer(Salt), 8) <> 0 then Exit(EmptyStr); // Decrypt password using encryption key SetLength(Result, Length(Data)); if (Mode > 0) then begin with TDCP_rijndael.Create(nil) do begin Init(Buffer[AES_OFFS], GetMaxKeySize, nil); Decrypt(PAnsiChar(Data)^, Pointer(Result)^, Length(Data)); Data:= Copy(Result, 1, Length(Result)); Free; end; end; StringStream:= TStringStream.Create(Data); try BlowFishDeCryptStream:= TBlowFishDeCryptStream.Create(BlowFishKey, SizeOf(TBlowFishKey), StringStream); try BlowFishDeCryptStream.Read(PAnsiChar(Result)^, Length(Result)); finally BlowFishDeCryptStream.Free; end; finally StringStream.Free; end; end; { TPasswordStore } procedure TPasswordStore.ConvertStore; var I, J: Integer; Password: String; Sections, Strings: TStringList; begin if ReadOnly then Exit; Strings:= TStringList.Create; Sections:= TStringList.Create; try CacheUpdates:= True; ReadSections(Sections); for I:= 0 to Sections.Count - 1 do begin if not SameText(Sections[I], 'General') then begin ReadSectionValues(Sections[I], Strings); for J:= 0 to Strings.Count - 1 do begin Password:= Decode(FMasterKey, Strings.ValueFromIndex[J]); Password:= EncodeStrong(FMode, FMasterKey, Password); WriteString(Sections[I], Strings.Names[J], Password); end; end; end; FMasterStrong:= True; FMasterKeyHash:= EmptyStr; UpdateMasterKey(FMasterKey, FMasterKeyHash); WriteString('General', 'MasterKey', FMasterKeyHash); try CacheUpdates:= False; except on E: Exception do msgError(E.Message); end; finally Strings.Free; Sections.Free; end; end; procedure TPasswordStore.UpdateMasterKey(var MasterKey: AnsiString; var MasterKeyHash: AnsiString); const RAND_SIZE = 16; var Randata: AnsiString; begin if not FMasterStrong then begin MasterKeyHash:= MD5Print(MD5String(MasterKey)); MasterKeyHash:= Encode(MasterKey, MasterKeyHash); end else begin if Length(FMasterKeyHash) = 0 then begin SetLength(Randata, RAND_SIZE); Random(PByte(Randata), RAND_SIZE); MasterKeyHash:= '!' + IntToStr(FMode) + EncodeStrong(FMode, MasterKey, Randata); end else begin FMode:= StrToIntDef(Copy(FMasterKeyHash, 2, 1), FMode); Randata:= DecodeStrong(FMode, MasterKey, Copy(FMasterKeyHash, 3, MaxInt)); if Length(Randata) < RAND_SIZE then MasterKeyHash:= EmptyStr else begin MasterKeyHash:= FMasterKeyHash; end; end; end; end; constructor TPasswordStore.Create(const AFileName: String); begin inherited Create(AFileName); FMode:= 1; CacheUpdates:= False; if ReadOnly then DCDebug('Read only password store!'); FMasterKeyHash:= ReadString('General', 'MasterKey', EmptyStr); FMasterStrong:= (Length(FMasterKeyHash) = 0) or (FMasterKeyHash[1] = '!'); end; function TPasswordStore.MasterKeySet: Boolean; begin Result:= (Length(FMasterKeyHash) <> 0); end; function TPasswordStore.HasMasterKey: Boolean; begin Result:= (Length(FMasterKey) <> 0); end; function TPasswordStore.CheckMasterKey: Boolean; var MasterKey, MasterKeyHash: AnsiString; begin Result:= False; if Length(FMasterKey) <> 0 then Exit(True); while (Result = False) do begin if not ShowInputQuery(rsMsgMasterPassword, rsMsgMasterPasswordEnter, True, MasterKey) then Exit; if Length(MasterKey) = 0 then Exit; if Length(FMasterKeyHash) = 0 then repeat if not ShowInputQuery(rsMsgMasterPassword, rsMsgPasswordVerify, True, MasterKeyHash) then Exit; until (MasterKey = MasterKeyHash); UpdateMasterKey(MasterKey, MasterKeyHash); if FMasterKeyHash = EmptyStr then begin FMasterKey:= MasterKey; FMasterKeyHash:= MasterKeyHash; WriteString('General', 'MasterKey', FMasterKeyHash); Result:= True; end else if SameText(FMasterKeyHash, MasterKeyHash) then begin FMasterKey:= MasterKey; if not FMasterStrong then ConvertStore; Result:= True; end else begin ShowMessageBox(rsMsgWrongPasswordTryAgain, rsMtError, MB_OK or MB_ICONERROR); end; end; end; function TPasswordStore.WritePassword(Prefix, Name, Connection: String; const Password: AnsiString): TCryptStoreResult; var Data: AnsiString; begin if ReadOnly then Exit(csrWriteError); if CheckMasterKey = False then Exit(csrFailed); if not FMasterStrong then Data:= Encode(FMasterKey, Password) else begin Data:= EncodeStrong(FMode, FMasterKey, Password) end; if Length(Data) = 0 then Exit(csrFailed); try WriteString(Prefix + '_' + Name, Connection, Data); except Exit(csrWriteError); end; Result:= csrSuccess; end; function TPasswordStore.ReadPassword(Prefix, Name, Connection: String; out Password: AnsiString): TCryptStoreResult; var Data: AnsiString = ''; begin if CheckMasterKey = False then Exit(csrFailed); Data:= ReadString(Prefix + '_' + Name, Connection, Data); if Length(Data) = 0 then Exit(csrNotFound); if not FMasterStrong then Password:= Decode(FMasterKey, Data) else begin Password:= DecodeStrong(FMode, FMasterKey, Data) end; if Length(Password) = 0 then Result:= csrFailed else begin Result:= csrSuccess; end; end; function TPasswordStore.DeletePassword(Prefix, Name, Connection: String): Boolean; begin Result:= not ReadOnly; if Result then try DeleteKey(Prefix + '_' + Name, Connection); except Result:= False; end; end; procedure InitPasswordStore; var AFileName: String; begin AFileName := gpCfgDir + 'pwd.ini'; try PasswordStore:= TPasswordStore.Create(AFileName); except DCDebug('Can not create secure password store!'); end; end; finalization FreeAndNil(PasswordStore); end. ������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udcreadpnm.pas�����������������������������������������������������������������0000644�0001750�0000144�00000024445�14743153644�016235� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{*****************************************************************************} { This file is part of the Free Pascal's "Free Components Library". Copyright (c) 2003 by Mazen NEIFER of the Free Pascal development team PNM writer implementation. See the file COPYING.FPC, included in this distribution, for details about the copyright. 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. } {*****************************************************************************} { The PNM (Portable aNyMaps) is a generic name for : PBM : Portable BitMaps, PGM : Portable GrayMaps, PPM : Portable PixMaps. There is normally no file format associated with PNM itself.} {$mode objfpc}{$h+} unit uDCReadPNM; interface uses FPImage, Classes, SysUtils, Graphics; Const BufSize = 1024; type { TDCReaderPNM } TDCReaderPNM=class (TFPCustomImageReader) private FBitMapType : Integer; FWidth : Integer; FHeight : Integer; FBufPos : Integer; FBufLen : Integer; FBuffer : Array of AnsiChar; function DropWhiteSpaces(Stream: TStream): AnsiChar; function ReadChar(Stream: TStream): AnsiChar; function ReadInteger(Stream: TStream): Integer; procedure ReadScanlineBuffer(Stream: TStream;p:Pbyte;Len:Integer); protected FMaxVal : Cardinal; FBitPP : Byte; FScanLineSize : Integer; FScanLine : PByte; procedure ReadHeader(Stream : TStream); virtual; function InternalCheck (Stream:TStream):boolean;override; procedure InternalRead(Stream:TStream;Img:TFPCustomImage);override; procedure ReadScanLine(Row : Integer; Stream:TStream); procedure WriteScanLine(Row : Integer; Img : TFPCustomImage); end; { TPortableAnyMapGraphic } TPortableAnyMapGraphic = class(Graphics.TPortableAnyMapGraphic) protected class function GetReaderClass: TFPCustomImageReaderClass; override; end; implementation uses LCLStrConsts; const WhiteSpaces=[#9,#10,#13,#32]; {Whitespace (TABs, CRs, LFs, blanks) are separators in the PNM Headers} { The magic number at the beginning of a pnm file is 'P1', 'P2', ..., 'P7' followed by a WhiteSpace character } function TDCReaderPNM.InternalCheck(Stream:TStream):boolean; var hdr: array[0..2] of AnsiChar; oldPos: Int64; i,n: Integer; begin Result:=False; if Stream = nil then exit; oldPos := Stream.Position; try n := SizeOf(hdr); Result:=(Stream.Size-OldPos>=N); if not Result then exit; For I:=0 to N-1 do hdr[i]:=ReadChar(Stream); Result:=(hdr[0] = 'P') and (hdr[1] in ['1'..'7']) and (hdr[2] in WhiteSpaces); finally Stream.Position := oldPos; FBufLen:=0; end; end; function TDCReaderPNM.DropWhiteSpaces(Stream : TStream) :AnsiChar; begin with Stream do begin repeat Result:=ReadChar(Stream); {If we encounter comment then eate line} if DropWhiteSpaces='#' then repeat Result:=ReadChar(Stream); until Result=#10; until not (Result in WhiteSpaces); end; end; function TDCReaderPNM.ReadInteger(Stream : TStream) :Integer; var s:String[7]; begin s:=''; s[1]:=DropWhiteSpaces(Stream); repeat Inc(s[0]); s[Length(s)+1]:=ReadChar(Stream); until (s[0]=#7) or (s[Length(s)+1] in WhiteSpaces); Result:=StrToInt(s); end; procedure TDCReaderPNM.ReadScanlineBuffer(Stream: TStream;p:Pbyte;Len:Integer); // after the header read, there are still bytes in the buffer. // drain the buffer before going for direct stream reads. var BytesLeft : integer; begin BytesLeft:=FBufLen-FBufPos; if BytesLeft>0 then begin if BytesLeft>Len then BytesLeft:=Len; Move (FBuffer[FBufPos],p^,BytesLeft); Dec(Len,BytesLeft); Inc(FBufPos,BytesLeft); Inc(p,BytesLeft); if Len>0 then Stream.ReadBuffer(p^,len); end else Stream.ReadBuffer(p^,len); end; Function TDCReaderPNM.ReadChar(Stream : TStream) : AnsiChar; begin If (FBufPos>=FBufLen) then begin if Length(FBuffer)=0 then SetLength(FBuffer,BufSize); FBufLen:=Stream.Read(FBuffer[0],Length(FBuffer)); if FBuflen=0 then Raise EReadError.Create('Failed to read from stream'); FBufPos:=0; end; Result:=FBuffer[FBufPos]; Inc(FBufPos); end; procedure TDCReaderPNM.ReadHeader(Stream : TStream); Var C : AnsiChar; begin C:=ReadChar(Stream); If (C<>'P') then Raise Exception.Create('Not a valid PNM image.'); C:=ReadChar(Stream); FBitmapType:=Ord(C)-Ord('0'); If Not (FBitmapType in [1..6]) then Raise Exception.CreateFmt('Unknown PNM subtype : %s',[C]); FWidth:=ReadInteger(Stream); FHeight:=ReadInteger(Stream); if FBitMapType in [1,4] then FMaxVal:=1 else FMaxVal:=ReadInteger(Stream); If (FWidth<=0) or (FHeight<=0) or (FMaxVal<=0) then Raise Exception.Create('Invalid PNM header data'); case FBitMapType of 1: FBitPP := 1; // 1bit PP (text) 2: FBitPP := 8 * SizeOf(Word); // Grayscale (text) 3: FBitPP := 8 * SizeOf(Word)*3; // RGB (text) 4: FBitPP := 1; // 1bit PP (raw) 5: If (FMaxval>255) then // Grayscale (raw); FBitPP:= 8 * 2 else FBitPP:= 8; 6: if (FMaxVal>255) then // RGB (raw) FBitPP:= 8 * 6 else FBitPP:= 8 * 3 end; // Writeln(FWidth,'x',Fheight,' Maxval: ',FMaxVal,' BitPP: ',FBitPP); end; procedure TDCReaderPNM.InternalRead(Stream:TStream;Img:TFPCustomImage); var Row:Integer; begin ReadHeader(Stream); Img.SetSize(FWidth,FHeight); Case FBitmapType of 5,6 : FScanLineSize:=(FBitPP div 8) * FWidth; else FScanLineSize:=FBitPP*((FWidth+7) shr 3); end; GetMem(FScanLine,FScanLineSize); try for Row:=0 to img.Height-1 do begin ReadScanLine(Row,Stream); WriteScanLine(Row,Img); // Writeln(Stream.Position,' ',Stream.Size); end; finally FreeMem(FScanLine); end; end; procedure TDCReaderPNM.ReadScanLine(Row : Integer; Stream:TStream); Var P : PWord; I,j,bitsLeft : Integer; PB: PByte; begin Case FBitmapType of 1 : begin PB:=FScanLine; For I:=0 to ((FWidth+7)shr 3)-1 do begin PB^:=0; bitsLeft := FWidth-(I shl 3)-1; if bitsLeft > 7 then bitsLeft := 7; for j:=0 to bitsLeft do PB^:=PB^ or (ReadInteger(Stream) shl (7-j)); Inc(PB); end; end; 2 : begin P:=PWord(FScanLine); For I:=0 to FWidth-1 do begin P^:=ReadInteger(Stream); Inc(P); end; end; 3 : begin P:=PWord(FScanLine); For I:=0 to FWidth-1 do begin P^:=ReadInteger(Stream); // Red Inc(P); P^:=ReadInteger(Stream); // Green Inc(P); P^:=ReadInteger(Stream); // Blue; Inc(P) end; end; 4,5,6 : if FBufPos>=FBufLen then // still bytes in buffer? Stream.ReadBuffer(FScanLine^,FScanLineSize) else ReadScanLineBuffer(Stream,FScanLine,FScanLineSize); end; end; procedure TDCReaderPNM.WriteScanLine(Row : Integer; Img : TFPCustomImage); Var C : TFPColor; L : Cardinal; Scale: Int64; function ScaleByte(B: Byte):Word; begin if FMaxVal = 255 then Result := (B shl 8) or B { As used for reading .BMP files } else { Mimic the above with multiplications } Result := (B*(FMaxVal+1) + B) * 65535 div Scale; end; function ScaleWord(W: Word):Word; begin if FMaxVal = 65535 then Result := BEtoN(W) else { Mimic the above with multiplications } Result := Int64(W*(FMaxVal+1) + W) * 65535 div Scale; end; Procedure ByteBnWScanLine; Var P : PByte; I,j,x,bitsLeft : Integer; begin P:=PByte(FScanLine); For I:=0 to ((FWidth+7)shr 3)-1 do begin L:=P^; x := I shl 3; bitsLeft := FWidth-x-1; if bitsLeft > 7 then bitsLeft := 7; for j:=0 to bitsLeft do begin if L and $80 <> 0 then Img.Colors[x,Row]:=colBlack else Img.Colors[x,Row]:=colWhite; L:=L shl 1; inc(x); end; Inc(P); end; end; Procedure WordGrayScanLine; Var P : PWord; I : Integer; begin P:=PWord(FScanLine); For I:=0 to FWidth-1 do begin L:=ScaleWord(P^); C.Red:=L; C.Green:=L; C.Blue:=L; Img.Colors[I,Row]:=C; Inc(P); end; end; Procedure WordRGBScanLine; Var P : PWord; I : Integer; begin P:=PWord(FScanLine); For I:=0 to FWidth-1 do begin C.Red:=ScaleWord(P^); Inc(P); C.Green:=ScaleWord(P^); Inc(P); C.Blue:=ScaleWord(P^); Img.Colors[I,Row]:=C; Inc(P); end; end; Procedure ByteGrayScanLine; Var P : PByte; I : Integer; begin P:=PByte(FScanLine); For I:=0 to FWidth-1 do begin L:=ScaleByte(P^); C.Red:=L; C.Green:=L; C.Blue:=L; Img.Colors[I,Row]:=C; Inc(P); end; end; Procedure ByteRGBScanLine; Var P : PByte; I : Integer; begin P:=PByte(FScanLine); For I:=0 to FWidth-1 do begin C.Red:=ScaleByte(P^); Inc(P); C.Green:=ScaleByte(P^); Inc(P); C.Blue:=ScaleByte(P^); Img.Colors[I,Row]:=C; Inc(P); end; end; begin C.Alpha:=AlphaOpaque; Scale := FMaxVal*(FMaxVal+1) + FMaxVal; Case FBitmapType of 1 : ByteBnWScanLine; 2 : WordGrayScanline; 3 : WordRGBScanline; 4 : ByteBnWScanLine; 5 : If FBitPP=8 then ByteGrayScanLine else WordGrayScanLine; 6 : If FBitPP=24 then ByteRGBScanLine else WordRGBScanLine; end; end; { TPortableAnyMapGraphic } class function TPortableAnyMapGraphic.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TDCReaderPNM; end; procedure Initialize; begin // Replace image handler GraphicFilter(Graphics.TPortableAnyMapGraphic); TPicture.UnregisterGraphicClass(Graphics.TPortableAnyMapGraphic); TPicture.RegisterFileFormat(TPortableAnyMapGraphic.GetFileExtensions, rsPortablePixmap, TPortableAnyMapGraphic); end; initialization Initialize; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udcreadpsd.pas�����������������������������������������������������������������0000644�0001750�0000144�00000003642�14743153644�016225� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Photoshop Document image class Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } unit uDCReadPSD; {$mode objfpc}{$H+} interface uses Graphics, FPImage; type { TPhotoshopDocument } TPhotoshopDocument = class(TFPImageBitmap) protected class function GetReaderClass: TFPCustomImageReaderClass; override; class function GetSharedImageClass: TSharedRasterImageClass; override; public class function GetFileExtensions: String; override; end; implementation uses FPReadPSD; { TPhotoshopDocument } class function TPhotoshopDocument.GetReaderClass: TFPCustomImageReaderClass; begin Result:= TFPReaderPSD; end; class function TPhotoshopDocument.GetSharedImageClass: TSharedRasterImageClass; begin Result:= TSharedBitmap; end; class function TPhotoshopDocument.GetFileExtensions: String; begin Result:= 'psd'; end; procedure Initialize; begin // Register image format TPicture.RegisterFileFormat('psd', 'Photoshop Document', TPhotoshopDocument); end; initialization Initialize; end. ����������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udcutils.pas�������������������������������������������������������������������0000755�0001750�0000144�00000121357�14743153644�015752� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Several useful functions Copyright (C) 2006-2024 Alexander Koblov (alexx2000@mail.ru) contributors: Radek Cervinka <radek.cervinka@centrum.cz> (cnvFormatFileSize and DivFileName functions) Tomas Bzatek <tbzatek@users.sourceforge.net> (QuoteStr, RemoveQuotation and SplitArgs functions) 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, see <http://www.gnu.org/licenses/>. } unit uDCUtils; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, Controls, StdCtrls, ColorBox, {$IF DEFINED(UNIX)} DCBasicTypes, uSysFolders, {$ENDIF} uFile, uTypes; const TextLineBreakValue: array[TTextLineBreakStyle] of String = (#10, #13#10, #13); {$IFDEF MSWINDOWS} VARDELIMITER='%'; VARDELIMITER_END='%'; {$ENDIF} {$IFDEF UNIX } VARDELIMITER='$'; VARDELIMITER_END=''; {$ENDIF} EnvVarCommanderPath = '%COMMANDER_PATH%'; // Using '%' for backward compatibility EnvVarConfigPath = '%DC_CONFIG_PATH%'; // Using '%' for backward compatibility EnvVarTodaysDate = VARDELIMITER + 'DC_TODAYSDATE' + VARDELIMITER_END; type TUsageOfSizeConversion = (uoscFile, uoscHeader, uoscFooter, uoscOperation); function GetCmdDirFromEnvVar(const sPath : String) : String; function SetCmdDirAsEnvVar(const sPath : String) : String; {en Replaces environment variables of form %<NAME>% with their values. Also replaces the internal "%COMMANDER_PATH%". } function ReplaceEnvVars(const sText: String): String; {en Replaces home directory at the beginning of the string with tilde ~. } function ReplaceHome(const Path: String): String; {en Replaces tilde ~ at the beginning of the string with home directory. } function ReplaceTilde(const Path: String): String; {en Expands the file name with environment variables by replacing them by absolute path. @param(sFileName File name to expand.) @returns(Absolute file name.) } function mbExpandFileName(const sFileName: String): String; {en Convert Int64 to string with Thousand separators. We can't use FloatToStrF with ffNumber because of integer rounding to thousands @param(AValue Integer value) @returns(String represenation) } function IntToStrTS(const APositiveValue: Int64): String; {en Convert file size to string representation in floating format (Kb, Mb, Gb) @param(iSize File size) @param(ShortFormat If @true than short format is used, otherwise long format (bytes) is used.) @param(Number Number of digits after decimal) @returns(File size in string representation) } function cnvFormatFileSize(const iSize: Int64; FSF: TFileSizeFormat; const Number: Integer): String; function cnvFormatFileSize(const iSize: Int64; const UsageOfSizeConversion: TUsageOfSizeConversion): String; function cnvFormatFileSize(const iSize: Int64): String; inline; {en Minimize file path replacing the folder name before the last PathDelim with '..' (if path ending with PathDelim it replaces the last folder name!!!) @param(PathToMince File path) @param(Canvas Output canvas) @param(MaxWidth Max width of the path in pixels) @returns(Minimized file path) } function MinimizeFilePath(const PathToMince: String; Canvas: TCanvas; MaxWidth: Integer): String; {en Checks if a filename matches any filename in the filelist or if it could be in any directory of the file list or any of their subdirectories. @param(Files List of files to which the filename must be matched.) @param(FileName Path to a file that will be matched. This may be absolute, relative or contain no path at all (only filename).) } function MatchesFileList(const Files: TFiles; FileName: String): Boolean; {en Checks if a file matches any mask in the masklist. @param(aFile File that will be matched.) @param(MaskList List of masks to which the file must be matched.) } function MatchesMaskListEx(const aFile: TFile; MaskList: TStringList): Boolean; {en Checks if a file or directory belongs in the specified path list. Only strings are compared, no file-system checks are done. @param(sBasePathList List of absolute paths where the path to check should be in.) @param(sPathToCheck Absolute path to file or directory to check.) @return(@true if sPathToCheck points to a directory or file in sBasePathList. @false otherwise.) } function IsInPathList(sBasePathList : String; sPathToCheck : String; ASeparator: AnsiChar = ';') : Boolean; {en Changes all the files' paths making them relative to 'sNewRootPath'. It is done by removing 'sNewRootPath' prefix from the paths and setting the general path (Files.Path) to sNewRootPath. @param(sNewRootPath Path that specifies new 'root' directory for all filenames.) @param(Files Contains list of files to change.) } procedure ChangeFileListRoot(sNewRootPath: String; Files: TFiles); {en Replace executable extension by system specific executable extension @param(sFileName File name) @returns(Executable name with system specific executable extension) } function FixExeExt(const sFileName: String): String; {en Delete quotes from string @param(Str String) } function TrimQuotes(const Str: String): String; function QuoteStr(const Str: String): String; function QuoteFilenameIfNecessary(const Str: String): String; function ConcatenateStrWithSpace(const Str: String; const Addition: String):string; {$IFDEF UNIX} function QuoteSingle(const Str: String): String; {$ENDIF} function QuoteDouble(const Str: String): String; {$IFDEF UNIX} {en Split command line parameters into argument array } procedure SplitCommandArgs(const Params: String; out Args: TDynamicStringArray); {$ENDIF} {en Delete quotation characters from string @param(Str String) @returns(String without quotation characters) } function RemoveQuotation(const Str: String): String; {$IF DEFINED(UNIX)} {en Split command line to command and a list of arguments. Each argument is unquoted. @param(sCmdLine Command line) @param(sCommand Command) @param(Args List of arguments) } procedure SplitCmdLine(sCmdLine: String; out sCommand: String; out Args: TDynamicStringArray); {$ELSEIF DEFINED(MSWINDOWS)} {en Split command line to command and parameters @param(sCmdLine Command line) @param(sCmd Command) @param(sParams Parameters) } procedure SplitCmdLine(sCmdLine : String; var sCmd, sParams : String); {$ENDIF} function CompareStrings(const s1, s2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt; procedure InsertFirstItem(sLine: String; comboBox: TCustomComboBox; AValue: UIntPtr = 0); {en Compares two strings taking into account the numbers or special chararcters } function StrChunkCmp(const str1, str2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt; function EstimateRemainingTime(StartValue, CurrentValue, EndValue: Int64; StartTime: TDateTime; CurrentTime: TDateTime; out SpeedPerSecond: Int64): TDateTime; {en Check color lightness @returns(@true when color is light, @false otherwise) } function ColorIsLight(AColor: TColor): Boolean; {en Modify color levels } function ModColor(AColor: TColor; APercent: Byte) : TColor; {en Makes a color some darker @param(AColor Source color) @param(APercent The percentage of brightness decrease) @returns(New some darker color) } function DarkColor(AColor: TColor; APercent: Byte): TColor; {en Makes a color some lighter @param(AColor Source color) @param(APercent The percentage of brightness increase) @returns(New some lighter color) } function LightColor(AColor: TColor; APercent: Byte): TColor; function ContrastColor(Color: TColor; APercent: Byte): TColor; procedure SetColorInColorBox(const lcbColorBox: TColorBox; const lColor: TColor); procedure UpdateColor(Control: TControl; Checked: Boolean); procedure EnableControl(Control: TControl; Enabled: Boolean); procedure SetComboWidthToLargestElement(AComboBox: TCustomComboBox; iExtraWidthToAdd: integer = 0); procedure SplitCmdLineToCmdParams(sCmdLine : String; var sCmd, sParams : String); function GuessLineBreakStyle(const S: String): TTextLineBreakStyle; function GetTextRange(Strings: TStrings; Start, Finish: Integer): String; function DCGetNewGUID: TGUID; procedure DCPlaceCursorNearControlIfNecessary(AControl: TControl); implementation uses uLng, LCLProc, LCLType, uMasks, FileUtil, StrUtils, uOSUtils, uGlobs, uGlobsPaths, DCStrUtils, DCOSUtils, DCConvertEncoding, LazUTF8 {$IF DEFINED(MSWINDOWS)} , Windows {$ENDIF} ; var dtLastDateSubstitutionCheck:TDateTime=0; function GetCmdDirFromEnvVar(const sPath: String): String; begin Result := NormalizePathDelimiters(sPath); Result := StringReplace(Result, EnvVarCommanderPath, ExcludeTrailingPathDelimiter(gpExePath), [rfIgnoreCase]); Result := StringReplace(Result, EnvVarConfigPath, ExcludeTrailingPathDelimiter(gpCfgDir), [rfIgnoreCase]); end; function SetCmdDirAsEnvVar(const sPath: String): String; begin Result := NormalizePathDelimiters(sPath); Result := StringReplace(Result, ExcludeTrailingPathDelimiter(gpExePath), EnvVarCommanderPath, []); Result := StringReplace(Result, ExcludeTrailingPathDelimiter(gpCfgDir), EnvVarConfigPath, []); end; function ReplaceEnvVars(const sText: String): String; var I: Integer; MyYear, MyMonth, MyDay:word; begin Result:= sText; //1st, if we have an empty string, get out of here, quick if sText = EmptyStr then Exit; //2th, let's check the "easy" substitution, there one related with Double Commander if pos('%', sText) > 0 then begin Result := StringReplace(Result, EnvVarCommanderPath, ExcludeTrailingPathDelimiter(gpExePath), [rfReplaceAll, rfIgnoreCase]); Result := StringReplace(Result, EnvVarConfigPath, ExcludeTrailingPathDelimiter(gpCfgDir), [rfReplaceAll, rfIgnoreCase]); end; //3nd, if we don't have the variable indication (% in windows for example), get out of here here, quick if pos(VARDELIMITER, sText) = 0 then Exit; //4rd, let's check if date changed since last time we updated our dc_todaysdate variable if dtLastDateSubstitutionCheck<>Trunc(now) then begin //Date changed! Let's find where variable is and update it. //Don't worry for time consumed: this is done only once per day! I:=0; while (I<gSpecialDirList.Count) do begin if gSpecialDirList.SpecialDir[I].VariableName=ENVVARTODAYSDATE then begin //Variable name found! Let's assign the new date to path value DecodeDate(now,MyYear,MyMonth,MyDay); gSpecialDirList.SpecialDir[I].PathValue:=Format('%d-%2.2d-%2.2d',[MyYear,MyMonth,MyDay]); I:=gSpecialDirList.Count; //To make sure we will end the search loop end; inc(I); end; dtLastDateSubstitutionCheck:=Trunc(now); //So we won't re-check this while we're under the same day end; //5th, let's roll through the possible variable. We did that with a "while" instead of a constant "for-loop" to get out quickly as soon as we solved the variables I:=0; while (I<gSpecialDirList.Count) AND (pos(VARDELIMITER,sText)<>0) do begin if pos(gSpecialDirList.SpecialDir[I].VariableName,Result)<>0 then Result := StringReplace(Result, gSpecialDirList.SpecialDir[I].VariableName, ExcludeTrailingPathDelimiter(gSpecialDirList.SpecialDir[I].PathValue), [rfReplaceAll, rfIgnoreCase]); inc(I); end; //6th, if we don't have variable indication anymore, (% in windows for example), get out of here here, quick if pos(VARDELIMITER, sText) = 0 then Exit; //7th, if still we have variable there, let's scan through the environment variable. // We got them in the "gSpecialDirList" but just in case some others were added on-the-fly // between the moment the application started and the moment we might needed them Result:= mbExpandEnvironmentStrings(Result); end; function ReplaceHome(const Path: String): String; {$IFDEF UNIX} var Len: Integer; AHome: String; {$ENDIF} begin {$IFDEF UNIX} AHome:= GetHomeDir; Len:= Length(AHome); if StrBegins(Path, AHome) and ((Length(Path) = Len) or (Path[Len + 1] = PathDelim)) then Result := '~' + Copy(Path, Len + 1, MaxInt) else {$ENDIF} Result := Path; end; function ReplaceTilde(const Path: String): String; begin {$IFDEF UNIX} if StrBegins(Path, '~') and ((Length(Path) = 1) or (Path[2] = PathDelim)) then Result := GetHomeDir + Copy(Path, 2, MaxInt) else {$ENDIF} Result := Path; end; function mbExpandFileName(const sFileName: String): String; const PATH_DELIM_POS = {$IFDEF MSWINDOWS}1{$ELSE}0{$ENDIF}; begin if (Pos('://', sFileName) > 2) then Result:= sFileName else begin Result:= NormalizePathDelimiters(sFileName); Result:= ReplaceEnvVars(Result); if Pos(PathDelim, Result) > PATH_DELIM_POS then begin {$IF DEFINED(MSWINDOWS)} if (Length(Result) > 1) and (Result[1] in ['A'..'Z', 'a'..'z']) and (Result[2] = DriveSeparator) and (GetDriveType(PAnsiChar(ExtractFileDrive(Result) + PathDelim)) = DRIVE_REMOTE) then begin Result:= ExpandAbsolutePath(Result) end else {$ENDIF} Result:= ExpandFileName(Result); end; {$IF DEFINED(MSWINDOWS)} // Remove double backslash '\\' after calling 'ExpandFileName' if (Pos(':\\', Result) = 2) and (Result[1] in ['A'..'Z', 'a'..'z']) then Result:= Result.Remove(2, 1); {$ENDIF} end; end; function IntToStrTS(const APositiveValue: Int64): String; var i, vSrcLen, vSrcI, vSrcNumberNo, vResLen: byte; begin if APositiveValue < 0 then Exit(IntToStr(APositiveValue)); Str(APositiveValue, Result); vSrcLen := Result.Length; vResLen := vSrcLen + ((vSrcLen - 1) div 3); if vSrcLen = vResLen then Exit; SetLength(Result, vResLen); vSrcI := vResLen; vSrcNumberNo := 1; for i:= vSrcLen downto 1 do begin Result[vSrcI] := Result[i]; Dec(vSrcI); if(vSrcNumberNo <> vSrcLen) and (vSrcNumberNo mod 3 = 0) then begin Result[vSrcI] := FormatSettings.ThousandSeparator; Dec(vSrcI); end; Inc(vSrcNumberNo); end; end; function cnvFormatFileSize(const iSize: int64; FSF: TFileSizeFormat; const Number: integer): string; const DIVISORS: array[LOW(TFileSizeFormat) .. HIGH(TFileSizeFormat)] of uint64 = (1, 1, 1024, (1024*1024), (1024*1024*1024), (1024*1024*1024*1024), 1, 1, 1024, (1024*1024), (1024*1024*1024), (1024*1024*1024*1024)); var FloatSize: extended; begin FloatSize := iSize; if FSF = fsfPersonalizedFloat then begin if iSize div (1024 * 1024 * 1024 * 1024) > 0 then FSF := fsfPersonalizedTera else if iSize div (1024 * 1024 * 1024) > 0 then FSF := fsfPersonalizedGiga else if iSize div (1024 * 1024) > 0 then FSF := fsfPersonalizedMega else if iSize div 1024 > 0 then FSF := fsfPersonalizedKilo else FSF := fsfPersonalizedByte; end else if FSF = fsfFloat then begin if iSize div (1024 * 1024 * 1024 * 1024) > 0 then FSF := fsfTera else if iSize div (1024 * 1024 * 1024) > 0 then FSF := fsfGiga else if iSize div (1024 * 1024) > 0 then FSF := fsfMega else if iSize div 1024 > 0 then FSF := fsfKilo else FSF := fsfByte; end; case FSF of fsfByte, fsfPersonalizedByte: Result := Format('%.0n%s', [FloatSize, gSizeDisplayUnits[FSF]]); else Result := FloatToStrF(FloatSize / DIVISORS[FSF], ffNumber, 15, Number) + gSizeDisplayUnits[FSF]; end; end; function cnvFormatFileSize(const iSize: Int64; const UsageOfSizeConversion: TUsageOfSizeConversion): String; begin case UsageOfSizeConversion of uoscOperation: //By legacy, it was simply adding a "B" to single size letter so we will do the samefor legacy mode. begin Result := cnvFormatFileSize(iSize, gOperationSizeFormat, gOperationSizeDigits); case gOperationSizeFormat of fsfFloat: if iSize div 1024 > 0 then Result := Result + rsLegacyOperationByteSuffixLetter else Result := Result + ' ' + rsLegacyOperationByteSuffixLetter; fsfByte: Result := Result + ' ' + rsLegacyOperationByteSuffixLetter; fsfKilo, fsfMega, fsfGiga, fsfTera: Result := Result + rsLegacyOperationByteSuffixLetter; end; end; uoscFile: Result := cnvFormatFileSize(iSize, gFileSizeFormat, gFileSizeDigits); uoscHeader: Result := cnvFormatFileSize(iSize, gHeaderSizeFormat, gHeaderDigits); uoscFooter: Result := cnvFormatFileSize(iSize, gFooterSizeFormat, gFooterDigits); end; end; function cnvFormatFileSize(const iSize: Int64): String; begin Result := cnvFormatFileSize(iSize, gFileSizeFormat, gFileSizeDigits); end; { This function based on code from http://www.delphirus.com.ru } {=========================================================} function MinimizeFilePath(const PathToMince: String; Canvas: TCanvas; MaxWidth: Integer): String; {=========================================================} // "C:\Program Files\Delphi\DDropTargetDemo\main.pas" // "C:\Program Files\..\main.pas" Var sl: TStringList; sHelp, sFile, sFirst: String; iPos: Integer; Len: Integer; Begin if MaxWidth <= 0 then Exit; sHelp := PathToMince; iPos := Pos(PathDelim, sHelp); If iPos = 0 Then Begin Result := PathToMince; End Else Begin sl := TStringList.Create; // Decode string While iPos <> 0 Do Begin sl.Add(Copy(sHelp, 1, (iPos - 1))); sHelp := Copy(sHelp, (iPos + 1), Length(sHelp)); iPos := Pos(PathDelim, sHelp); End; If sHelp <> '' Then Begin sl.Add(sHelp); End; // Encode string sFirst := sl[0]; sFile := sl[sl.Count - 1]; sl.Delete(sl.Count - 1); Result := ''; MaxWidth := MaxWidth - Canvas.TextWidth('XXX'); if (sl.Count <> 0) and (Canvas.TextWidth(Result + sl[0] + PathDelim + sFile) < MaxWidth) then begin While (sl.Count <> 0) and (Canvas.TextWidth(Result + sl[0] + PathDelim + sFile) < MaxWidth) Do Begin Result := Result + sl[0] + PathDelim; sl.Delete(0); End; If sl.Count = 0 Then Begin Result := Result + sFile; End Else Begin Result := Result + '..' + PathDelim + sFile; End; end else If sl.Count = 0 Then Begin Result := sFirst + PathDelim; End Else Begin Result := sFirst + PathDelim + '..' + PathDelim + sFile; End; sl.Free; End; if Canvas.TextWidth(Result) > MaxWidth + Canvas.TextWidth('XXX') then begin Len:= UTF8Length(Result); while (Len >= 3) and (Canvas.TextWidth(Result) > MaxWidth) do begin UTF8Delete(Result, Len, 1); Dec(Len); end; Result := UTF8Copy(Result, 1, Len - 3) + '...'; end; End; function MatchesFileList(const Files: TFiles; FileName: String): Boolean; var i: Integer; aFile: TFile; begin for i := 0 to Files.Count - 1 do begin aFile := Files[i]; if aFile.IsDirectory then begin // Check if 'FileName' is in this directory or any of its subdirectories. if IsInPath(aFile.FullPath, FileName, True, True) then Exit(True); end else begin // Item in the list is a file, only compare names. if aFile.FullPath = FileName then Exit(True); end; end; Result := False; end; function MatchesMaskListEx(const aFile: TFile; MaskList: TStringList): Boolean; var I: Integer; sMask, sFileName: String; begin Result:= False; for I:= 0 to MaskList.Count - 1 do begin sMask:= MaskList[I]; case GetPathType(sMask) of ptAbsolute: sFileName:= aFile.FullPath; else sFileName:= aFile.Name; end; // When a mask is ended with a PathDelim, it will match only directories if (Length(sMask) > 1) and (sMask[Length(sMask)] = PathDelim) then begin if aFile.IsDirectory then sMask:= ExcludeTrailingPathDelimiter(sMask) else Continue; end; if MatchesMaskList(sFileName, sMask) then Exit(True); end; end; function IsInPathList(sBasePathList: String; sPathToCheck: String; ASeparator: AnsiChar = ';'): Boolean; var sBasePath: String; begin sBasePathList := UTF8UpperCase(sBasePathList); sPathToCheck := UTF8UpperCase(sPathToCheck); repeat sBasePath := Copy2SymbDel(sBasePathList, ASeparator); if IsInPath(sBasePath, sPathToCheck, True, True) then Exit(True); until Length(sBasePathList) = 0; Result := False end; procedure ChangeFileListRoot(sNewRootPath: String; Files: TFiles); var i: Integer; aFile: TFile; begin if IsInPath(sNewRootPath, Files.Path, True, True) then begin // Current path is a subpath of new root path. for i := 0 to Files.Count - 1 do begin aFile := Files[i]; aFile.Path := ExtractDirLevel(sNewRootPath, aFile.Path); end; Files.Path := ExtractDirLevel(sNewRootPath, Files.Path); end else begin // Current path has a different base than new root path. if sNewRootPath <> EmptyStr then sNewRootPath := IncludeTrailingPathDelimiter(sNewRootPath); for i := 0 to Files.Count - 1 do begin aFile := Files[i]; aFile.Path := sNewRootPath + ExtractDirLevel(Files.Path, aFile.Path); end; Files.Path := sNewRootPath; end; end; function FixExeExt(const sFileName: String): String; var ExeExt: String; begin Result:= sFileName; ExeExt:= GetExeExt; if not SameText(ExeExt, ExtractFileExt(sFileName)) then Result:= ChangeFileExt(sFileName, ExeExt); end; function TrimQuotes(const Str: String): String; begin Result:= Str; if (Length(Str) > 0) then begin if (Str[1] in ['"', '''']) then begin if (Length(Str) = 1) then Result:= EmptyStr else if (Str[1] = Str[Length(Str)]) then Result:= Copy(Str, 2, Length(Str) - 2); end; end; end; function QuoteStr(const Str: String): String; {$IF DEFINED(UNIX)} begin // Default method is to escape every special char with backslash. Result := EscapeNoQuotes(Str); end; {$ELSE} begin // On Windows only double quotes can be used for quoting. // The double quotes on Windows can be nested, e.g., // "cmd /C "type "Some long file name""" or // "cmd /C ""some long file.exe" "long param1" "long param2"" Result := QuoteDouble(Str); end; {$ENDIF} function QuoteFilenameIfNecessary(const Str: String): String; {$IF DEFINED(UNIX)} begin // Default method is to escape every special char with backslash. Result := EscapeNoQuotes(Str); end; {$ELSE} begin if Pos(#32, Str) <> 0 then Result := QuoteDouble(Str) else Result := Str; end; {$ENDIF} function ConcatenateStrWithSpace(const Str: String; const Addition: String):string; begin result:=Str; if Addition <> EmptyStr then if result = EmptyStr then result := Addition else result := result + #32 + Addition; end; {$IF DEFINED(UNIX)} function QuoteSingle(const Str: String): String; begin Result := '''' + EscapeSingleQuotes(Str) + ''''; end; {$ENDIF} function QuoteDouble(const Str: String): String; begin {$IF DEFINED(UNIX)} Result := '"' + EscapeDoubleQuotes(Str) + '"'; {$ELSEIF DEFINED(MSWINDOWS)} // Nothing needs to be escaped on Windows, because only double quote (") itself // would need to be escaped but there's no standard mechanism for escaping it. // It seems every application handles it on their own and CMD doesn't support it at all. // Also double quote is a forbidden character on FAT, NTFS. Result := '"' + Str + '"'; {$ENDIF} end; {$IF DEFINED(UNIX)} // Helper for RemoveQuotation and SplitCmdLine. procedure RemoveQuotationOrSplitCmdLine(sCmdLine: String; out sCommand: String; out Args: TDynamicStringArray; bSplitArgs: Boolean; bNoCmd: Boolean = False); var I : Integer; QuoteChar : Char; CurrentArg: String = ''; DoubleQuotesEscape: Boolean = False; procedure AddArgument; begin if bSplitArgs then begin if (bNoCmd = False) and (sCommand = '') then sCommand := CurrentArg else begin SetLength(Args, Length(Args) + 1); Args[Length(Args) - 1] := CurrentArg; end; CurrentArg := ''; end; end; begin sCommand := ''; SetLength(Args, 0); QuoteChar := #0; for I := 1 to Length(sCmdLine) do case QuoteChar of '\': begin if sCmdLine[I] <> #10 then begin if not (sCmdLine[I] in NoQuotesSpecialChars) then CurrentArg := CurrentArg + '\'; CurrentArg := CurrentArg + sCmdLine[I]; end; QuoteChar := #0; end; '''': begin if sCmdLine[I] = '''' then QuoteChar := #0 else CurrentArg := CurrentArg + sCmdLine[I]; end; '"': begin if DoubleQuotesEscape then begin if not (sCmdLine[I] in DoubleQuotesSpecialChars) then CurrentArg := CurrentArg + '\'; CurrentArg := CurrentArg + sCmdLine[I]; DoubleQuotesEscape := False; end else begin case sCmdLine[I] of '\': DoubleQuotesEscape := True; '"': QuoteChar := #0; else CurrentArg := CurrentArg + sCmdLine[I]; end; end; end; else begin case sCmdLine[I] of '\', '''', '"': QuoteChar := sCmdLine[I]; ' ', #9: if CurrentArg <> '' then AddArgument; #10: AddArgument; else CurrentArg := CurrentArg + sCmdLine[I]; end; end; end; if QuoteChar <> #0 then raise EInvalidQuoting.Create; if CurrentArg <> '' then AddArgument; if (not bSplitArgs) then sCommand := CurrentArg; end; procedure SplitCommandArgs(const Params: String; out Args: TDynamicStringArray); var Unused: String; begin RemoveQuotationOrSplitCmdLine(Params, Unused, Args, True, True); end; {$ENDIF} function RemoveQuotation(const Str: String): String; {$IF DEFINED(MSWINDOWS)} var TrimmedStr: String; begin if Length(Str) = 0 then Result := EmptyStr else begin TrimmedStr := Trim(Str); if (TrimmedStr[1] = '"') and (TrimmedStr[Length(TrimmedStr)] = '"') then Result := Copy(TrimmedStr, 2, Length(TrimmedStr) - 2) else Result := Str; end; end; {$ELSEIF DEFINED(UNIX)} var Args: TDynamicStringArray; begin RemoveQuotationOrSplitCmdLine(Str, Result, Args, False); end; {$ENDIF} procedure SplitCmdLineToCmdParams(sCmdLine : String; var sCmd, sParams : String); var iPos : Integer; begin if Pos('"', sCmdLine) = 1 then begin iPos := CharPos('"', sCmdLine, 2); if iPos = 0 then raise EInvalidQuoting.Create; sCmd := Copy(sCmdLine, 2, iPos - 2); sParams := Copy(sCmdLine, iPos + 2, Length(sCmdLine) - iPos + 1) end else begin iPos := Pos(#32, sCmdLine); if iPos <> 0 then begin sCmd := Copy(sCmdLine, 1, iPos - 1); sParams := Copy(sCmdLine, iPos + 1, Length(sCmdLine) - iPos + 1) end else begin sCmd := sCmdLine; sParams := ''; end; end; end; {$IF DEFINED(UNIX)} procedure SplitCmdLine(sCmdLine: String; out sCommand: String; out Args: TDynamicStringArray); begin RemoveQuotationOrSplitCmdLine(sCmdLine, sCommand, Args, True); end; {$ELSEIF DEFINED(MSWINDOWS)} procedure SplitCmdLine(sCmdLine : String; var sCmd, sParams : String); begin SplitCmdLineToCmdParams(sCmdLine,sCmd,sParams); end; {$ENDIF} function CompareStrings(const s1, s2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt; inline; {$IF DEFINED(MSWINDOWS)} var dwCmpFlags: DWORD; U1, U2: UnicodeString; {$ENDIF} begin if Natural or Special then begin {$IF DEFINED(MSWINDOWS)} if (CaseSensitivity <> cstCharValue) and ((Win32MajorVersion > 6) or ((Win32MajorVersion = 6) and (Win32MinorVersion >= 1))) then begin dwCmpFlags := 0; U1 := CeUtf8ToUtf16(s1); U2 := CeUtf8ToUtf16(s2); if CaseSensitivity = cstNotSensitive then begin dwCmpFlags := dwCmpFlags or NORM_IGNORECASE; end; if Natural then begin dwCmpFlags := dwCmpFlags or SORT_DIGITSASNUMBERS; end; if Special then begin dwCmpFlags := dwCmpFlags or SORT_STRINGSORT; end; Result := CompareStringW(LOCALE_USER_DEFAULT, dwCmpFlags, PWideChar(U1), Length(U1), PWideChar(U2), Length(U2)); if Result <> 0 then Result := Result - 2 else begin Result := StrChunkCmp(s1, s2, Natural, Special, CaseSensitivity); end; end else {$ENDIF} Result := StrChunkCmp(s1, s2, Natural, Special, CaseSensitivity) end else begin case CaseSensitivity of cstNotSensitive: Result := UnicodeCompareText(CeUtf8ToUtf16(s1), CeUtf8ToUtf16(s2)); cstLocale: Result := UnicodeCompareStr(CeUtf8ToUtf16(s1), CeUtf8ToUtf16(s2)); cstCharValue: Result := SysUtils.CompareStr(S1, S2); else raise Exception.Create('Invalid CaseSensitivity parameter'); end; end; end; procedure InsertFirstItem(sLine: String; comboBox: TCustomComboBox; AValue: UIntPtr); var I: Integer = 0; begin if sLine = EmptyStr then Exit; with comboBox.Items do begin // Use case sensitive search while (I < Count) and (CompareStr(Strings[I], sLine) <> 0) do Inc(I); if (I < 0) or (I >= Count) then begin comboBox.Items.Insert(0, sLine); comboBox.ItemIndex := 0; end else if (I > 0) then begin comboBox.Items.Move(I, 0); // Reset selected item (and combobox text), because Move has destroyed it. comboBox.ItemIndex := 0; end; Objects[0]:= TObject(AValue); end; end; function UnicodeStrComp(const Str1, Str2 : UnicodeString): PtrInt; var counter: SizeInt = 0; pstr1, pstr2: PWideChar; Begin pstr1 := PWideChar(Str1); pstr2 := PWideChar(Str2); While pstr1[counter] = pstr2[counter] do Begin if (pstr2[counter] = #0) or (pstr1[counter] = #0) then break; Inc(counter); end; Result := ord(pstr1[counter]) - ord(pstr2[counter]); end; function StrChunkCmp(const str1, str2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt; type TCategory = (cNone, cNumber, cSpecial, cString); TChunk = record FullStr: String; Str: String; Category: TCategory; PosStart: Integer; PosEnd: Integer; end; var Chunk1, Chunk2: TChunk; function Categorize(c: Char): TCategory; inline; begin if Natural and (c in ['0'..'9']) then Result := cNumber else if Special and (c in [' '..'/', ':'..'@', '['..'`', '{'..'~']) then Result := cSpecial else Result := cString; end; procedure NextChunkInit(var Chunk: TChunk); inline; begin Chunk.PosStart := Chunk.PosEnd; if Chunk.PosStart > Length(Chunk.FullStr) then Chunk.Category := cNone else Chunk.Category := Categorize(Chunk.FullStr[Chunk.PosStart]); end; procedure FindChunk(var Chunk: TChunk); inline; begin Chunk.PosEnd := Chunk.PosStart; repeat inc(Chunk.PosEnd); until (Chunk.PosEnd > Length(Chunk.FullStr)) or (Categorize(Chunk.FullStr[Chunk.PosEnd]) <> Chunk.Category); end; procedure FindSameCategoryChunks; inline; begin Chunk1.PosEnd := Chunk1.PosStart; Chunk2.PosEnd := Chunk2.PosStart; repeat inc(Chunk1.PosEnd); inc(Chunk2.PosEnd); until (Chunk1.PosEnd > Length(Chunk1.FullStr)) or (Chunk2.PosEnd > Length(Chunk2.FullStr)) or (Categorize(Chunk1.FullStr[Chunk1.PosEnd]) <> Chunk1.Category) or (Categorize(Chunk2.FullStr[Chunk2.PosEnd]) <> Chunk2.Category); end; procedure PrepareChunk(var Chunk: TChunk); inline; begin Chunk.Str := Copy(Chunk.FullStr, Chunk.PosStart, Chunk.PosEnd - Chunk.PosStart); end; procedure PrepareNumberChunk(var Chunk: TChunk); inline; begin while (Chunk.PosStart <= Length(Chunk.FullStr)) and (Chunk.FullStr[Chunk.PosStart] = '0') do inc(Chunk.PosStart); PrepareChunk(Chunk); end; begin Chunk1.FullStr := str1; Chunk2.FullStr := str2; Chunk1.PosEnd := 1; Chunk2.PosEnd := 1; NextChunkInit(Chunk1); NextChunkInit(Chunk2); if (Chunk1.Category = cSpecial) and (Chunk2.Category <> cSpecial) then Exit(-1); if (Chunk2.Category = cSpecial) and (Chunk1.Category <> cSpecial) then Exit(1); if Chunk1.Category = cSpecial then FindSameCategoryChunks else begin FindChunk(Chunk1); FindChunk(Chunk2); end; if (Chunk1.Category = cNumber) xor (Chunk2.Category = cNumber) then // one of them is number Chunk1.Category := cString; // compare as strings to put numbers in a natural position while True do begin case Chunk1.Category of cString: begin PrepareChunk(Chunk1); PrepareChunk(Chunk2); case CaseSensitivity of cstNotSensitive: Result := UnicodeCompareText(CeUtf8ToUtf16(Chunk1.Str), CeUtf8ToUtf16(Chunk2.Str)); cstLocale: Result := UnicodeCompareStr(CeUtf8ToUtf16(Chunk1.Str), CeUtf8ToUtf16(Chunk2.Str)); cstCharValue: Result := UnicodeStrComp(CeUtf8ToUtf16(Chunk1.Str), CeUtf8ToUtf16(Chunk2.Str)); else raise Exception.Create('Invalid CaseSensitivity parameter'); end; if Result <> 0 then Exit; end; cNumber: begin PrepareNumberChunk(Chunk1); PrepareNumberChunk(Chunk2); Result := Length(Chunk1.Str) - Length(Chunk2.Str); if Result <> 0 then Exit; Result := CompareStr(Chunk1.Str, Chunk2.Str); if Result <> 0 then Exit; end; cSpecial: begin PrepareChunk(Chunk1); PrepareChunk(Chunk2); Result := CompareStr(Chunk1.Str, Chunk2.Str); if Result <> 0 then Exit; end; cNone: Exit(UnicodeStrComp(CeUtf8ToUtf16(str1), CeUtf8ToUtf16(str2))); end; NextChunkInit(Chunk1); NextChunkInit(Chunk2); if (Chunk1.Category = cNone) and (Chunk2.Category = cNone) then Exit; if Chunk1.Category <> Chunk2.Category then if Chunk1.Category < Chunk2.Category then Exit(-1) else Exit(1); if Chunk1.Category = cSpecial then FindSameCategoryChunks else begin FindChunk(Chunk1); FindChunk(Chunk2); end; end; end; function EstimateRemainingTime(StartValue, CurrentValue, EndValue: Int64; StartTime: TDateTime; CurrentTime: TDateTime; out SpeedPerSecond: Int64): TDateTime; var Speed: Double; begin SpeedPerSecond := 0; Result := 0; if (CurrentValue > StartValue) and (CurrentTime > StartTime) then begin Speed := Double(CurrentValue - StartValue) / (CurrentTime - StartTime); Result := Double(EndValue - CurrentValue) / Speed; SpeedPerSecond := Trunc(Speed) div SecsPerDay; end; end; function ColorIsLight(AColor: TColor): Boolean; var R, G, B: Byte; begin RedGreenBlue(ColorToRGB(AColor), R, G, B); Result:= ((0.299 * R + 0.587 * G + 0.114 * B) / 255) > 0.5; end; function ModColor(AColor: TColor; APercent: Byte) : TColor; var R, G, B : Byte; begin RedGreenBlue(ColorToRGB(AColor), R, G, B); R := R * APercent div 100; G := G * APercent div 100; B := B * APercent div 100; Result := RGBToColor(R, G, B); end; function DarkColor(AColor: TColor; APercent: Byte): TColor; var R, G, B: Byte; begin RedGreenBlue(ColorToRGB(AColor), R, G, B); R:= R - MulDiv(R, APercent, 100); G:= G - MulDiv(G, APercent, 100); B:= B - MulDiv(B, APercent, 100); Result:= RGBToColor(R, G, B); end; function LightColor(AColor: TColor; APercent: Byte): TColor; var R, G, B: Byte; begin RedGreenBlue(ColorToRGB(AColor), R, G, B); R:= R + MulDiv(255 - R, APercent, 100); G:= G + MulDiv(255 - G, APercent, 100); B:= B + MulDiv(255 - B, APercent, 100); Result:= RGBToColor(R, G, B); end; function ContrastColor(Color: TColor; APercent: Byte): TColor; begin if ColorIsLight(Color) then Result:= DarkColor(Color, APercent) else begin Result:= LightColor(Color, APercent); end; end; procedure SetColorInColorBox(const lcbColorBox: TColorBox; const lColor: TColor); //< select in lcbColorBox lColor if lColor in lcbColorBox else // add to lcbColorBox lColor and select him var I: LongInt; begin if (lcbColorBox = nil) then Exit; // if lcbColorBox not exist with lcbColorBox do begin // search lColor in colorbox colorlist for I:= 0 to Items.Count - 1 do if Colors[I] = lColor then // find color begin // select color Selected:= lColor; Exit; end;// if for //add items to colorbox list Items.Objects[Items.Add('$'+HexStr(lColor, 8))]:= TObject(PtrInt(lColor)); Selected:= lColor; end; // with end; procedure UpdateColor(Control: TControl; Checked: Boolean); begin if Checked then Control.Color:= clDefault else Control.Color:= $FFFFFFFF8000000F; end; procedure EnableControl(Control: TControl; Enabled: Boolean); begin Control.Enabled:= Enabled; {$IF DEFINED(LCLWIN32)} if Enabled then begin Control.Color:= clDefault; Control.Font.Color:= clDefault; end else begin Control.Color:= clBtnFace; Control.Font.Color:= clGrayText; end; {$ENDIF} end; { SetComboWidthToLargestElement } // Set the width of a TComboBox to fit to the largest element in it. procedure SetComboWidthToLargestElement(AComboBox: TCustomComboBox; iExtraWidthToAdd: integer = 0); var iElementIndex, iCurrentElementWidth, iLargestWidth: integer; begin iLargestWidth := 0; iElementIndex := 0; while (iElementIndex < AComboBox.Items.Count) do begin iCurrentElementWidth := AComboBox.Canvas.TextWidth(AComboBox.Items.Strings[iElementIndex]); if iCurrentElementWidth > iLargestWidth then iLargestWidth := iCurrentElementWidth; inc(iElementIndex); end; if iLargestWidth > 0 then AComboBox.Width := (iLargestWidth + iExtraWidthToAdd); end; function GuessLineBreakStyle(const S: String): TTextLineBreakStyle; var Start, Finish, Current: PAnsiChar; begin Start:= PAnsiChar(S); Finish:= Start + Length(S); Current:= Start; while Current < Finish do begin case Current[0] of #10, #13: begin if (Current[0] = #13) then begin if (Current[1] = #10) then Result:= tlbsCRLF else Result:= tlbsCR; end else begin Result:= tlbsLF; end; Exit; end; end; Inc(Current); end; Result:= DefaultTextLineBreakStyle; end; function GetTextRange(Strings: TStrings; Start, Finish: Integer): String; var P: PAnsiChar; S, NL: String; I, L, NLS: LongInt; begin with Strings do begin L:= 0; NL:= TextLineBreakValue[TextLineBreakStyle]; NLS:= Length(NL); for I:= Start to Finish do L:= L + Length(Strings[I]) + NLS; SetLength(Result, L); P:= Pointer(Result); for I:= Start to Finish do begin S:= Strings[I]; L:= Length(S); if L <> 0 then System.Move(Pointer(S)^, P^, L); P:= P + L; for L:= 1 to NLS do begin P^:= NL[L]; Inc(P); end; end; end; end; { DCGetNewGUID } function DCGetNewGUID: TGUID; var iIndex: integer; begin if CreateGuid(Result) <> 0 then begin Result.Data1 := random($233528DE); Result.Data2 := random($FFFF); Result.Data3 := random($FFFF); for iIndex := 0 to 7 do Result.Data4[iIndex] := random($FF); end; end; { DCPlaceCursorNearControlIfNecessary } //Note: Programmatically move cursor position near a control if it's not around it. // This is for those who would use the keyboard accelerator key for making popup at a logical place. procedure DCPlaceCursorNearControlIfNecessary(AControl: TControl); var ptControlCenter: TPoint; begin ptControlCenter := AControl.ClientToScreen(Classes.Point(AControl.Width div 2, AControl.Height div 2)); if (abs(Mouse.CursorPos.x - ptControlCenter.x) > (AControl.Width div 2)) or (abs(Mouse.CursorPos.y - ptControlCenter.y) > (AControl.Height div 2)) then Mouse.CursorPos := Classes.Point((ptControlCenter.x + (AControl.width div 2)) - 10, ptControlCenter.y); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udebug.pas���������������������������������������������������������������������0000644�0001750�0000144�00000007254�14743153644�015365� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains functions used for debugging. Copyright (C) 2011 Przemysław Nagay (cobines@gmail.com) Copyright (C) 2019 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uDebug; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLVersion; // DebugLn and DbgOut are thread-safe due to TDCLogger but since TLazLogger // itself is designed for single-thread then DebugLnEnter, DebugLnExit cannot // be used from multiple threads. procedure DCDebug(Args: array of const); procedure DCDebug(const S: String; Args: array of const);// similar to Format(s,Args) procedure DCDebug(const s: String); procedure DCDebug(const s1,s2: String); procedure DCDebug(const s1,s2,s3: String); procedure DCDebug(const s1,s2,s3,s4: String); procedure DCDebug(const s1,s2,s3,s4,s5: String); implementation uses LCLProc, SyncObjs, LazLogger, LazLoggerBase, LazClasses; type {en Logger with thread-safe DebugLn and DbgOut. } TDCLogger = class(TLazLoggerFile) private DebugLnLock: TCriticalSection; protected procedure DoDbgOut(s: string{$if lcl_fullversion >= 2030000}; AGroup: PLazLoggerLogGroup = nil{$endif}); override; procedure DoDebugLn(s: string{$if lcl_fullversion >= 2030000}; AGroup: PLazLoggerLogGroup = nil{$endif}); override; public constructor Create; destructor Destroy; override; end; function CreateDCLogger: TRefCountedObject; begin Result := TDCLogger.Create; TDCLogger(Result).Assign(GetExistingDebugLogger); {$if lcl_fullversion >= 2020000} TDCLogger(Result).ParamForLogFileName:= '--debug-log'; {$endif} end; { TDCLogger } procedure TDCLogger.DoDbgOut(s: string{$if lcl_fullversion >= 2030000}; AGroup: PLazLoggerLogGroup = nil{$endif}); begin DebugLnLock.Acquire; try inherited DoDbgOut(s); finally DebugLnLock.Release; end; end; procedure TDCLogger.DoDebugLn(s: string{$if lcl_fullversion >= 2030000}; AGroup: PLazLoggerLogGroup = nil{$endif}); begin DebugLnLock.Acquire; try inherited DoDebugLn(s); finally DebugLnLock.Release; end; end; constructor TDCLogger.Create; begin DebugLnLock := TCriticalSection.Create; inherited Create; end; destructor TDCLogger.Destroy; begin inherited Destroy; DebugLnLock.Free; end; procedure DCDebug(Args: array of const); begin DebugLn(Args); end; procedure DCDebug(const S: String; Args: array of const);// similar to Format(s,Args) begin DebugLn(S, Args); end; procedure DCDebug(const s: String); begin DebugLn(s); end; procedure DCDebug(const s1,s2: String); begin DebugLn(s1, s2); end; procedure DCDebug(const s1,s2,s3: String); begin DebugLn(s1, s2, s3); end; procedure DCDebug(const s1,s2,s3,s4: String); begin DebugLn(s1, s2, s3, s4); end; procedure DCDebug(const s1,s2,s3,s4,s5: String); begin DebugLn(s1, s2, s3, s4, s5); end; procedure DCDebug(const s1,s2,s3,s4,s5,s6: String); begin DebugLn(s1, s2, s3, s4, s5, s6); end; initialization LazDebugLoggerCreator := @CreateDCLogger; RecreateDebugLogger; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udefaultfilepropertyformatter.pas����������������������������������������������0000644�0001750�0000144�00000010632�14743153644�022306� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uDefaultFilePropertyFormatter; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileProperty; type TDefaultFilePropertyFormatter = class(TInterfacedObject, IFilePropertyFormatter) public function FormatFileName(FileProperty: TFileNameProperty): String; function FormatFileSize(FileProperty: TFileSizeProperty): String; function FormatDateTime(FileProperty: TFileDateTimeProperty): String; function FormatModificationDateTime(FileProperty: TFileModificationDateTimeProperty): String; function FormatNtfsAttributes(FileProperty: TNtfsFileAttributesProperty): String; function FormatUnixAttributes(FileProperty: TUnixFileAttributesProperty): String; end; TMaxDetailsFilePropertyFormatter = class(TInterfacedObject, IFilePropertyFormatter) public function FormatFileName(FileProperty: TFileNameProperty): String; function FormatFileSize(FileProperty: TFileSizeProperty): String; function FormatDateTime(FileProperty: TFileDateTimeProperty): String; function FormatModificationDateTime(FileProperty: TFileModificationDateTimeProperty): String; function FormatNtfsAttributes(FileProperty: TNtfsFileAttributesProperty): String; function FormatUnixAttributes(FileProperty: TUnixFileAttributesProperty): String; end; var DefaultFilePropertyFormatter: IFilePropertyFormatter = nil; MaxDetailsFilePropertyFormatter: IFilePropertyFormatter = nil; implementation uses uGlobs, uDCUtils, DCBasicTypes, DCFileAttributes, DCDateTimeUtils; function TDefaultFilePropertyFormatter.FormatFileName( FileProperty: TFileNameProperty): String; begin Result := FileProperty.Value; end; function TDefaultFilePropertyFormatter.FormatFileSize( FileProperty: TFileSizeProperty): String; begin Result := cnvFormatFileSize(FileProperty.Value); end; function TDefaultFilePropertyFormatter.FormatDateTime( FileProperty: TFileDateTimeProperty): String; begin Result := SysUtils.FormatDateTime(gDateTimeFormat, FileProperty.Value); end; function TDefaultFilePropertyFormatter.FormatModificationDateTime( FileProperty: TFileModificationDateTimeProperty): String; begin Result := FormatDateTime(FileProperty); end; function TDefaultFilePropertyFormatter.FormatNtfsAttributes(FileProperty: TNtfsFileAttributesProperty): String; { Format as decimal: begin Result := IntToStr(FileProperty.Value); end; } begin Result:= DCFileAttributes.FormatNtfsAttributes(FileProperty.Value); end; function TDefaultFilePropertyFormatter.FormatUnixAttributes(FileProperty: TUnixFileAttributesProperty): String; begin Result:= DCFileAttributes.FormatUnixAttributes(FileProperty.Value); end; // ---------------------------------------------------------------------------- function TMaxDetailsFilePropertyFormatter.FormatFileName( FileProperty: TFileNameProperty): String; begin Result := FileProperty.Value; end; function TMaxDetailsFilePropertyFormatter.FormatFileSize( FileProperty: TFileSizeProperty): String; var d: Double; begin d := FileProperty.Value; Result := Format('%.0n', [d]); end; function TMaxDetailsFilePropertyFormatter.FormatDateTime( FileProperty: TFileDateTimeProperty): String; var Bias: LongInt = 0; Sign: String; begin Bias := -GetTimeZoneBias; if Bias >= 0 then Sign := '+' else Sign := '-'; Result := SysUtils.FormatDateTime('ddd, dd mmmm yyyy hh:nn:ss', FileProperty.Value) + ' UT' + Sign + Format('%.2D%.2D', [Bias div 60, Bias mod 60]); end; function TMaxDetailsFilePropertyFormatter.FormatModificationDateTime( FileProperty: TFileModificationDateTimeProperty): String; begin Result := FormatDateTime(FileProperty); end; function TMaxDetailsFilePropertyFormatter.FormatNtfsAttributes(FileProperty: TNtfsFileAttributesProperty): String; begin Result := DefaultFilePropertyFormatter.FormatNtfsAttributes(FileProperty); end; function TMaxDetailsFilePropertyFormatter.FormatUnixAttributes(FileProperty: TUnixFileAttributesProperty): String; begin Result := DefaultFilePropertyFormatter.FormatUnixAttributes(FileProperty); end; initialization DefaultFilePropertyFormatter := TDefaultFilePropertyFormatter.Create as IFilePropertyFormatter; MaxDetailsFilePropertyFormatter := TMaxDetailsFilePropertyFormatter.Create as IFilePropertyFormatter; finalization DefaultFilePropertyFormatter := nil; // frees the interface MaxDetailsFilePropertyFormatter := nil; end. ������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udescr.pas���������������������������������������������������������������������0000644�0001750�0000144�00000033106�14743153644�015372� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- This unit contains class for working with file comments. Copyright (C) 2008-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uDescr; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCClassesUtf8, uConvEncoding; const DESCRIPT_ION = 'descript.ion'; type { TDescription } TDescription = class(TStringListEx) private FModified: Boolean; FLastDescrFile: String; FDestDescr: TDescription; FEncoding: TMacroEncoding; FNewEncoding: TMacroEncoding; procedure PrepareDescrFile(FileName: String); function GetDescription(Index: Integer): String; function GetDescription(const FileName: String): String; procedure SetDescription(Index: Integer; const AValue: String); procedure SetDescription(const FileName: String; const AValue: String); procedure SetEncoding(const AValue: TMacroEncoding); public {en Create TDescription class @param(UseSubDescr @true if need Copy/Move functions) } constructor Create(UseSubDescr: Boolean); {en Destroy TDescription class } destructor Destroy; override; {en Load data from description file } procedure LoadFromFile(const FileName: String); override; {en Save data to description file } procedure SaveToFile(const FileName: String); override; {en Add description for file @param(FileName File name) @param(Descr Description) @returns(Index of added item) } function AddDescription(FileName, Descr: String): Integer; {en Read description by file name @param(FileName File name) @returns(Description of file) } function ReadDescription(FileName: String): String; {en Write description for file @param(FileName File name) @param(Descr Description) } procedure WriteDescription(FileName: String; const Descr: String); {en Delete description by file name @param(FileName File name) @returns(The function returns @true if successful, @false otherwise) } function DeleteDescription(const FileName: String): Boolean; {en Copy description for file @param(FileNameFrom Source file name) @param(FileNameTo Destination file name) @returns(The function returns @true if successful, @false otherwise) } function CopyDescription(const FileNameFrom, FileNameTo: String): Boolean; {en Move description for file @param(FileNameFrom Source file name) @param(FileNameTo Destination file name) @returns(The function returns @true if successful, @false otherwise) } function MoveDescription(const FileNameFrom, FileNameTo: String): Boolean; {en Rename file in description @param(FileNameOld Old file name) @param(FileNameNew New file name) @returns(The function returns @true if successful, @false otherwise) } function Rename(const FileNameOld, FileNameNew: String): Boolean; {en Save all changes to description file } procedure SaveDescription; {en Reset last description file name } procedure Reset; function Find(const S: string; out Index: Integer): Boolean; override; {en File description encoding } property Encoding: TMacroEncoding read FEncoding write SetEncoding; {en Get description by file name } property DescrByFileName[const FileName: String]: String read GetDescription write SetDescription; {en Get description by file name index } property DescrByIndex[Index: Integer]: String read GetDescription write SetDescription; end; implementation uses LazUTF8, LConvEncoding, uDebug, DCOSUtils, DCConvertEncoding, DCUnicodeUtils, uGlobs; { TDescription } procedure TDescription.PrepareDescrFile(FileName: String); var sDescrFile: String; begin sDescrFile:= ExtractFilePath(FileName) + DESCRIPT_ION; if sDescrFile <> FLastDescrFile then try // save previous decription file if need if FModified and (FLastDescrFile <> EmptyStr) and (Count > 0) then SaveToFile(FLastDescrFile); // load description file if exists FLastDescrFile:= sDescrFile; if not mbFileExists(FLastDescrFile) then begin Clear; FModified:= False; // use new encoding if new file FEncoding:= FNewEncoding; end else begin FEncoding:= gDescReadEncoding; LoadFromFile(FLastDescrFile); // set target encoding if Assigned(FDestDescr) then begin FDestDescr.FNewEncoding:= FEncoding; end; end; except on E: Exception do DCDebug('TDescription.PrepareDescrFile - ' + E.Message); end; end; function TDescription.Find(const S: string; out Index: Integer): Boolean; var iIndex, iPosOfDivider, iLength, iFirstStringPos: Integer; sFileName, sIndexString: String; cSearchChar : Char; begin Result:= False; sFileName:= ExtractFileName(S); //DCDebug('#########################'); //DCDebug('sFileName: '+ sFileName); for iIndex:= Count - 1 downto 0 do begin sIndexString := Self[iIndex]; //DCDebug('Self[I]: '+ sIndexString); //DCDebug('iIndex: '+ IntToStr(iIndex)); //DCDebug('Count: '+ IntToStr(Count)); //DCDebug('Pos(sFileName, Self[I]): '+ IntToStr(Pos(sFileName, sIndexString))); // File comment length iLength := Length(sIndexString); if iLength = 0 then Continue; //at the first, look if first char a " if(sIndexString[1]='"')then begin // YES cSearchChar := '"'; iFirstStringPos := 2; end else begin //NO cSearchChar := ' '; iFirstStringPos := 1; end; // find position of next cSearchChar in sIndexString iPosOfDivider:= 2; while (iPosOfDivider < iLength) do // don't look above the strings length begin // is at this position the cSearchChar? if (sIndexString[iPosOfDivider] = cSearchChar) then begin // YES // found the sFileName in the sIndexString (no more, no less) if mbCompareFileNames(sFileName, Copy(sIndexString, iFirstStringPos, iPosOfDivider-iFirstStringPos)) then begin // YES Index := iIndex; Exit(True); end else begin // NO Break; end; end; Inc(iPosOfDivider); end; end; end; function TDescription.GetDescription(Index: Integer): String; var sLine: String; iDescrStart: Integer; begin sLine:= Self[Index]; if Pos(#34, sLine) <> 1 then begin iDescrStart:= Pos(#32, sLine); Result:= Copy(sLine, iDescrStart+1, Length(sLine) - iDescrStart); end else begin iDescrStart:= Pos(#34#32, sLine); Result:= Copy(sLine, iDescrStart+2, Length(sLine) - iDescrStart); end; end; function TDescription.GetDescription(const FileName: String): String; var I: Integer; begin if Find(FileName, I) then Result:= GetDescription(I) else begin Result:= EmptyStr; end; end; procedure TDescription.SetDescription(Index: Integer; const AValue: String); var sLine, sFileName: String; iDescrStart: Integer; begin FModified:= True; sLine:= Self[Index]; if Pos('"', sLine) <> 1 then begin iDescrStart:= Pos(#32, sLine); sFileName:= Copy(sLine, 1, iDescrStart); Self[Index]:= sFileName + AValue; end else begin iDescrStart:= Pos(#34#32, sLine); sFileName:= Copy(sLine, 1, iDescrStart+1); Self[Index]:= sFileName + AValue; end; end; procedure TDescription.SetDescription(const FileName: String; const AValue: String); var I: Integer; begin if Find(FileName, I) then SetDescription(I, AValue) else AddDescription(FileName, AValue); end; procedure TDescription.SetEncoding(const AValue: TMacroEncoding); begin if FEncoding <> AValue then begin FEncoding:= AValue; if mbFileExists(FLastDescrFile) then LoadFromFile(FLastDescrFile); end; end; constructor TDescription.Create(UseSubDescr: Boolean); begin FModified:= False; FEncoding:= gDescReadEncoding; if gDescCreateUnicode then FNewEncoding:= gDescWriteEncoding else begin FNewEncoding:= gDescReadEncoding; end; if UseSubDescr then begin FDestDescr:= TDescription.Create(False) end; inherited Create; end; destructor TDescription.Destroy; begin FreeAndNil(FDestDescr); inherited Destroy; end; procedure TDescription.LoadFromFile(const FileName: String); var S: String; fsFileStream: TFileStreamEx; begin FModified:= False; fsFileStream:= TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try SetLength(S, fsFileStream.Size); fsFileStream.Read(S[1], Length(S)); finally fsFileStream.Free; end; // Try to guess encoding FEncoding:= DetectEncoding(S, FEncoding, True); // If need convert encoding case FEncoding of meUTF8: Text:= S; meOEM: Text:= CeOemToUtf8(S); meANSI: Text:= CeAnsiToUtf8(S); meUTF8BOM: Text:= Copy(S, 4, MaxInt); meUTF16LE: Text:= Utf16LEToUtf8(Copy(S, 3, MaxInt)); meUTF16BE: Text:= Utf16BEToUtf8(Copy(S, 3, MaxInt)); end; end; procedure TDescription.SaveToFile(const FileName: String); const faSpecial = faHidden or faSysFile; var S: String; Attr: Integer; fsFileStream: TFileStreamEx; begin FModified:= False; case FEncoding of meUTF8: S:= Text; meANSI: S:= CeUtf8ToAnsi(Text); meOem: S:= CeUtf8ToOem(Text); meUTF8BOM: S:= UTF8BOM + Text; meUTF16LE: S:= UTF16LEBOM + Utf8ToUtf16LE(Text); meUTF16BE: S:= UTF16BEBOM + Utf8ToUtf16BE(Text); end; Attr:= FileGetAttr(UTF8ToSys(FileName)); // Remove hidden & system attributes if (Attr <> -1) and ((Attr and faSpecial) <> 0) then begin FileSetAttr(UTF8ToSys(FileName), faArchive); end; fsFileStream:= TFileStreamEx.Create(FileName, fmCreate or fmShareDenyWrite); try fsFileStream.Write(S[1], Length(S)); finally fsFileStream.Free; end; // Restore original attributes if (Attr <> -1) and ((Attr and faSpecial) <> 0) then begin FileSetAttr(UTF8ToSys(FileName), Attr); end; end; function TDescription.AddDescription(FileName, Descr: String): Integer; begin FModified:= True; FileName:= ExtractFileName(FileName); if Pos(#32, FileName) <> 0 then Result := Add(#34+FileName+#34#32+Descr) else Result := Add(FileName+#32+Descr); end; function TDescription.ReadDescription(FileName: String): String; begin PrepareDescrFile(FileName); Result:= GetDescription(FileName); end; procedure TDescription.WriteDescription(FileName: String; const Descr: String); begin PrepareDescrFile(FileName); SetDescription(FileName, Descr); end; function TDescription.DeleteDescription(const FileName: String): Boolean; var I: Integer; begin Result:= False; PrepareDescrFile(FileName); if Find(FileName, I) then begin Delete(I); FModified:= True; Result:= True; end; end; function TDescription.CopyDescription(const FileNameFrom, FileNameTo: String): Boolean; var I: Integer; begin Result:= False; PrepareDescrFile(FileNameFrom); if Find(FileNameFrom, I) then begin DCDebug(FileNameFrom, '=', DescrByIndex[I]); FDestDescr.WriteDescription(FileNameTo, DescrByIndex[I]); Result:= True; end; end; function TDescription.MoveDescription(const FileNameFrom, FileNameTo: String): Boolean; var I: Integer; begin Result:= False; PrepareDescrFile(FileNameFrom); if Find(FileNameFrom, I) then begin DCDebug(FileNameFrom, '=', DescrByIndex[I]); FDestDescr.WriteDescription(FileNameTo, DescrByIndex[I]); Delete(I); FModified:= True; Result:= True; end; end; function TDescription.Rename(const FileNameOld, FileNameNew: String): Boolean; var I: Integer; AValue: String; begin Result:= False; PrepareDescrFile(FileNameOld); if Find(FileNameOld, I) then begin AValue:= GetDescription(I); Delete(I); AddDescription(FileNameNew, AValue); FModified:= True; Result:= True; end; end; procedure TDescription.SaveDescription; begin try if FModified then begin if Count > 0 then SaveToFile(FLastDescrFile) else mbDeleteFile(FLastDescrFile); end; if Assigned(FDestDescr) then FDestDescr.SaveDescription; except on E: Exception do DCDebug('TDescription.SaveDescription - ' + E.Message); end; end; procedure TDescription.Reset; begin FLastDescrFile:= EmptyStr; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udetectstr.pas�����������������������������������������������������������������0000644�0001750�0000144�00000030237�14743153644�016275� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Detect string parser. Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2009-2022 Alexander Koblov (alexx2000@mail.ru) Based on TMathControl by Vimil Saju 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, see <http://www.gnu.org/licenses/>. } unit uDetectStr; {$mode objfpc}{$H+} interface uses SysUtils, Classes, uMasks, uFile; type TMathType = (mtnil, mtoperator, mtlbracket, mtrbracket, mtoperand); type TMathOperatorType = (monone, // NULL moequ, // = moneq, // != replaced with # moles, // < momor, // > moand, // & moor, // | monot // NOT ); type PMathChar = ^TMathChar; TMathChar = record case mathtype: TMathType of mtoperand: (data: shortstring); mtoperator: (op: TMathOperatorType); end; type { TParserControl } TParserControl = class private FData: TBytes; FForce: Boolean; FDataSize: Integer; FFileRead: Boolean; FDetectStr: String; FMathString: String; FInput, FOutput, FStack: array of TMathChar; private function FileRead(const FileName: String): Boolean; function Calculate(aFile: TFile; operand1, operand2, Aoperator: TMathChar): String; function GetOperator(C: AnsiChar): TMathOperatorType; function GetOperand(Mid: Integer; var Len: Integer): String; procedure ProcessString; procedure ConvertInfixToPostfix; function IsOperand(C: AnsiChar): Boolean; function IsOperator(C: AnsiChar): Boolean; function GetPrecedence(mop: TMathOperatorType): Integer; procedure SetDetectStr(const AValue: String); function BooleanToStr(X: Boolean): String; function StrToBoolean(S: String):Boolean; public function TestFileResult(const aFile: TFile): Boolean; overload; function TestFileResult(const aFileName: String): Boolean; overload; published property DetectStr: String read FDetectStr write SetDetectStr; property IsForce: Boolean read FForce write FForce; end; implementation uses DCStrUtils, DCClassesUtf8, uDebug, uFileProperty, uFileSystemFileSource, uFindMmap; function TParserControl.FileRead(const FileName: String): Boolean; begin FFileRead:= True; SetLength(FData, 8192); try with TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone) do try FDataSize:= Read(FData[0], Length(FData)); finally Free; end; Result:= True; except FDataSize:= 0; Result:= False; end; end; function TParserControl.Calculate(aFile: TFile; operand1, operand2, Aoperator: TMathChar): String; var ASize: Int64; AValue: Boolean; AChar, Index: Integer; tmp, data1, data2: String; begin Result:= 'false'; data1:= UpperCase(operand1.data); // NOT if (operand1.data = 'NOT') and ((operand2.data = 'true') or (operand2.data = 'false')) then begin Result:= BooleanToStr(not StrToBoolean(operand2.data)); end; // & | if ((operand1.data = 'true') or (operand1.data = 'false')) and ((operand2.data = 'true') or (operand2.data = 'false')) then begin case Aoperator.op of moand: Result:= BooleanToStr((StrToBoolean(operand1.data)) and (StrToBoolean(operand2.data))); moor: Result:= BooleanToStr((StrToBoolean(operand1.data)) or (StrToBoolean(operand2.data))); end; end; // [X]= [X]!= if StrBegins(data1, '[') and StrEnds(data1, ']') then begin if FFileRead then begin if (FDataSize = 0) then Exit; end else begin if not FileRead(aFile.FullPath) then Exit; end; data2:= operand2.data; ASize:= Length(data1); Index:= StrToIntDef(Copy(data1, 2, ASize - 2), -1); if (Index >= 0) and (Index < FDataSize) then begin ASize:= Length(data2); if (ASize > 2) and (data2[1] = '"') and (data2[ASize] = '"') then AChar:= Ord(data2[2]) else begin if not TryStrToInt(data2, AChar) then Exit; end; Result:= BooleanToStr(FData[Index] = AChar); end; end; // FIND FINDI if (data1 = 'FIND') or (data1 = 'FINDI') then begin if FFileRead then begin if (FDataSize = 0) then Exit; end else begin if not FileRead(aFile.FullPath) then Exit; end; data2:= operand2.data; ASize:= Length(data2); AValue:= (data1 = 'FIND'); if (ASize > 2) and (data2[1] = '"') and (data2[ASize] = '"') then begin data2:= Copy(data2, 2, ASize - 2); Result:= BooleanToStr(PosMem(@FData[0], FDataSize, 0, data2, AValue, False) <> Pointer(-1)); end; end; // EXT= EXT!= if (data1 = 'EXT') then begin tmp:= aFile.Extension; tmp:= UpperCase(tmp); tmp:= '"' + tmp + '"'; case Aoperator.op of moequ: Result:= BooleanToStr(MatchesMask(tmp, operand2.data)); moneq: Result:= BooleanToStr(not MatchesMask(tmp, operand2.data)); end; end; // SIZE > < = != if (data1 = 'SIZE') and (fpSize in aFile.SupportedProperties) then begin if TryStrToInt64(operand2.data, ASize) then begin case Aoperator.op of moequ: Result:= BooleanToStr(aFile.Size = ASize); moneq: Result:= BooleanToStr(aFile.Size <> ASize); moles: Result:= BooleanToStr(aFile.Size < ASize); momor: Result:= BooleanToStr(aFile.Size > ASize); end; end; end; end; function TParserControl.TestFileResult(const aFile: TFile): Boolean; var I: Integer; tmp1, tmp2, tmp3: TMathChar; begin if FMathString = '' then begin Result:= True; Exit; end; FFileRead:= False; SetLength(FStack, 0); for I:= 0 to Length(FOutput) - 1 do begin if FOutput[I].mathtype = mtoperand then begin SetLength(FStack, Length(FStack) + 1); FStack[Length(FStack) - 1]:= FOutput[I]; end else if FOutput[I].mathtype = mtoperator then begin if Length(FStack) > 1 then begin tmp1:= FStack[Length(FStack) - 1]; tmp2:= FStack[Length(FStack) - 2]; SetLength(FStack, Length(FStack) - 2); tmp3.mathtype:= mtoperand; tmp3.data:= Calculate(aFile, tmp2, tmp1, FOutput[I]); SetLength(FStack, Length(FStack) + 1); FStack[Length(FStack) - 1]:= tmp3; end; end; end; Result:= (Length(FStack) > 0) and StrToBoolean(FStack[0].data); SetLength(FStack, 0); end; function TParserControl.TestFileResult(const aFileName: String): Boolean; var aFile: TFile; begin try aFile:= TFileSystemFileSource.CreateFileFromFile(aFileName); try Result:= TestFileResult(aFile); finally aFile.Free; end; except Result:= False; end; end; function TParserControl.GetOperator(C: AnsiChar): TMathOperatorType; begin case C of '<': Result:= moles; '>': Result:= momor; '&': Result:= moand; '=': Result:= moequ; '#': Result:= moneq; '!': Result:= monot; '|': Result:= moor; else Result:= monone; end; end; function TParserControl.GetOperand(Mid: Integer; var Len: Integer): String; var I: Integer; begin Len:= High(FMathString); if (FMathString[Mid] = '"') then begin Result:= FMathString[Mid]; for I:= Mid + 1 to Len do begin Result:= Result + FMathString[I]; if FMathString[I] = '"' then Break; end; end else begin Result:= EmptyStr; for I:= Mid to Len do begin if IsOperand(FMathString[I]) then Result:= Result + FMathString[I] else Break; end; end; Len:= Length(Result); end; procedure TParserControl.ProcessString; const Flags: TReplaceFlags = [rfReplaceAll, rfIgnoreCase]; var I: Integer; NumLen: Integer; begin FMathString:= StringReplace(FMathString, 'FIND(', 'FIND=(', Flags); FMathString:= StringReplace(FMathString, '!=', '#', [rfReplaceAll]); FMathString:= StringReplace(FMathString, 'FINDI(', 'FINDI=(', Flags); FMathString:= StringReplace(FMathString, 'MULTIMEDIA', 'true', Flags); FMathString:= StringReplace(FMathString, 'FORCE', BooleanToStr(FForce), Flags); NumLen:= 1; while NumLen < Length(FMathString) do begin if (FMathString[NumLen] = '!') and (FMathString[NumLen + 1] <> '=') then begin I:= NumLen; Delete(FMathString, I, 1); Insert('NOT!', FMathString, I); Inc(NumLen, 4); end else Inc(NumLen); end; I:= 0; NumLen:= 0; SetLength(FInput, 0); SetLength(FStack, 0); SetLength(FOutput, 0); FMathString:= '(' + FMathString + ')'; SetLength(FInput, Length(FMathString)); while I <= Length(FMathString) - 1 do begin if FMathString[I + 1] = '(' then begin FInput[I].mathtype:= mtlbracket; Inc(I); end else if FMathString[I + 1] = ')' then begin FInput[I].mathtype:= mtrbracket; Inc(I); end else if IsOperator(FMathString[I + 1]) then begin FInput[I].mathtype:= mtoperator; FInput[I].op:= GetOperator(FMathString[I + 1]); Inc(I); end else if IsOperand(FMathString[I+1]) then begin FInput[I].mathtype:= mtoperand; FInput[I].data:= GetOperand(I + 1, NumLen); Inc(I, NumLen); end else {if FMathString[I + 1] = ' ' then} Inc(I); end; end; function TParserControl.IsOperator(C: AnsiChar): Boolean; begin Result:= (C in ['=', '#', '!', '&', '<', '>', '|']); end; function TParserControl.IsOperand(C: AnsiChar): Boolean; begin Result:= not (C in ['=', '#', '!', '&', '<', '>', '|', '(', ')', ' ']); end; function TParserControl.GetPrecedence(mop: TMathOperatorType): Integer; begin case mop of moor: Result:= 0; moand: Result:= 1; moequ: Result:= 2; moneq: Result:= 2; moles: Result:= 2; momor: Result:= 2; monot: Result:= 2; else Result:= -1; end; end; function TParserControl.BooleanToStr(X: Boolean): String; begin if X then Result:= 'true' else Result:= 'false'; end; procedure TParserControl.SetDetectStr(const AValue: String); begin if FDetectStr <> AValue then begin FDetectStr:= AValue; FMathString:= AValue; ConvertInfixToPostfix; end; end; function TParserControl.StrToBoolean(S: String): Boolean; begin if S = 'true' then Result:= True else Result:= False; end; procedure TParserControl.ConvertInfixToPostfix; var i, j, prec: Integer; begin ProcessString; for i:= 0 to Length(FInput) - 1 do begin if FInput[i].mathtype = mtoperand then begin SetLength(FOutput, Length(FOutput) + 1); FOutput[Length(FOutput) - 1]:= FInput[i]; end else if FInput[i].mathtype = mtlbracket then begin SetLength(FStack, Length(FStack) + 1); FStack[Length(FStack) - 1]:= FInput[i]; end else if FInput[i].mathtype = mtoperator then begin prec:= GetPrecedence(FInput[i].op); j:= Length(FStack) - 1; if j >= 0 then begin while (j >= 0) and (GetPrecedence(FStack[j].op) >= prec) do begin SetLength(FOutput, Length(FOutput) + 1); FOutput[Length(FOutput) - 1]:= FStack[j]; Setlength(FStack, Length(FStack) - 1); j:= j - 1; end; SetLength(FStack, Length(FStack) + 1); FStack[Length(FStack) - 1]:= FInput[i]; end; end else if FInput[i].mathtype = mtrbracket then begin j:= Length(FStack) - 1; if j >= 0 then begin while (j >= 0) and (FStack[j].mathtype <> mtlbracket) do begin SetLength(FOutput, Length(FOutput) + 1); FOutput[Length(FOutput) - 1]:= FStack[j]; SetLength(FStack, Length(FStack) - 1); j:= j - 1; end; if j >= 0 then begin SetLength(FStack, Length(FStack) - 1); end; end; end; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udiffond.pas�������������������������������������������������������������������0000644�0001750�0000144�00000060743�14743153644�015712� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uDiffOND; (******************************************************************************* * Component TDiff * * Version: 3.1 * * Date: 7 November 2009 * * Compilers: Delphi 7 - Delphi2009 * * Author: Angus Johnson - angusj-AT-myrealbox-DOT-com * * Copyright: 2001-200( Angus Johnson * * * * Licence to use, terms and conditions: * * The code in the TDiff component is released as freeware * * provided you agree to the following terms & conditions: * * 1. the copyright notice, terms and conditions are * * left unchanged * * 2. modifications to the code by other authors must be * * clearly documented and accompanied by the modifier's name. * * 3. the TDiff component may be freely compiled into binary * * format and no acknowledgement is required. However, a * * discrete acknowledgement would be appreciated (eg. in a * * program's 'About Box'). * * * * Description: Component to list differences between two integer arrays * * using a "longest common subsequence" algorithm. * * Typically, this component is used to diff 2 text files * * once their individuals lines have been hashed. * * * * Acknowledgements: The key algorithm in this component is based on: * * "An O(ND) Difference Algorithm and its Variations" * * By E Myers - Algorithmica Vol. 1 No. 2, 1986, pp. 251-266 * * http://www.cs.arizona.edu/people/gene/ * * http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps * * * *******************************************************************************) (******************************************************************************* * History: * * 13 December 2001 - Original Release * * 22 April 2008 - Complete rewrite to greatly improve the code and * * provide a much simpler view of differences through a new * * 'Compares' property. * * 7 November 2009 - Updated so now compiles in newer versions of Delphi. * *******************************************************************************) {$mode delphi}{$H+} interface uses SysUtils, Classes, Math, Forms; const //Maximum realistic deviation from centre diagonal vector ... MAX_DIAGONAL = $FFFFFF; //~16 million type {$IFDEF UNICODE} P8Bits = PByte; {$ELSE} P8Bits = PAnsiChar; {$ENDIF} PDiags = ^TDiags; TDiags = array [-MAX_DIAGONAL .. MAX_DIAGONAL] of integer; PIntArray = ^TIntArray; TIntArray = array[0 .. MAXINT div sizeof(integer) -1] of Integer; PChrArray = ^TChrArray; TChrArray = array[0 .. MAXINT div sizeof(char) -1] of Char; TChangeKind = (ckNone, ckAdd, ckDelete, ckModify); PCompareRec = ^TCompareRec; TCompareRec = record Kind : TChangeKind; oldIndex1, oldIndex2 : integer; case boolean of false : (chr1, chr2 : Char); true : (int1, int2 : integer); end; TDiffStats = record matches : integer; adds : integer; deletes : integer; modifies : integer; end; TDiff = class(TComponent) private fCompareList: TList; fCancelled: boolean; fExecuting: boolean; fDiagBuffer, bDiagBuffer: pointer; Chrs1, Chrs2: PChrArray; Ints1, Ints2: PIntArray; LastCompareRec: TCompareRec; fDiag, bDiag: PDiags; fDiffStats: TDiffStats; procedure InitDiagArrays(MaxOscill, len1, len2: integer); //nb: To optimize speed, separate functions are called for either //integer or character compares ... procedure RecursiveDiffChr(offset1, offset2, len1, len2: integer); procedure AddChangeChrs(offset1, range: integer; ChangeKind: TChangeKind); procedure RecursiveDiffInt(offset1, offset2, len1, len2: integer); procedure AddChangeInts(offset1, range: integer; ChangeKind: TChangeKind); function GetCompareCount: integer; function GetCompare(index: integer): TCompareRec; public constructor Create(aOwner: TComponent); override; destructor Destroy; override; //compare either and array of characters or an array of integers ... function Execute(pints1, pints2: PInteger; len1, len2: integer): boolean; overload; function Execute(pchrs1, pchrs2: PChar; len1, len2: integer): boolean; overload; //Cancel allows interrupting excessively prolonged comparisons procedure Cancel; procedure Clear; property Cancelled: boolean read fCancelled; property Count: integer read GetCompareCount; property Compares[index: integer]: TCompareRec read GetCompare; default; property DiffStats: TDiffStats read fDiffStats; end; procedure Register; implementation procedure Register; begin RegisterComponents('Samples', [TDiff]); end; constructor TDiff.Create(aOwner: TComponent); begin inherited; fCompareList := TList.create; end; //------------------------------------------------------------------------------ destructor TDiff.Destroy; begin Clear; fCompareList.free; inherited; end; //------------------------------------------------------------------------------ function TDiff.Execute(pchrs1, pchrs2: PChar; len1, len2: integer): boolean; var maxOscill, x1,x2, savedLen: integer; compareRec: PCompareRec; begin result := not fExecuting; if not result then exit; fExecuting := true; fCancelled := false; try Clear; //save first string length for later (ie for any trailing matches) ... savedLen := len1-1; //setup the character arrays ... Chrs1 := pointer(pchrs1); Chrs2 := pointer(pchrs2); //ignore top matches ... x1:= 0; x2 := 0; while (len1 > 0) and (len2 > 0) and (Chrs1[len1-1] = Chrs2[len2-1]) do begin dec(len1); dec(len2); end; //if something doesn't match ... if (len1 <> 0) or (len2 <> 0) then begin //ignore bottom of matches too ... while (len1 > 0) and (len2 > 0) and (Chrs1[x1] = Chrs2[x2]) do begin dec(len1); dec(len2); inc(x1); inc(x2); end; maxOscill := min(max(len1,len2), MAX_DIAGONAL); fCompareList.Capacity := len1 + len2; //nb: the Diag arrays are extended by 1 at each end to avoid testing //for array limits. Hence '+3' because will also includes Diag[0] ... GetMem(fDiagBuffer, sizeof(integer)*(maxOscill*2+3)); GetMem(bDiagBuffer, sizeof(integer)*(maxOscill*2+3)); try RecursiveDiffChr(x1, x2, len1, len2); finally freeMem(fDiagBuffer); freeMem(bDiagBuffer); end; end; if fCancelled then begin result := false; Clear; exit; end; //finally, append any trailing matches onto compareList ... while (LastCompareRec.oldIndex1 < savedLen) do begin with LastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); chr1 := Chrs1[oldIndex1]; chr2 := Chrs2[oldIndex2]; end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; finally fExecuting := false; end; end; //------------------------------------------------------------------------------ function TDiff.Execute(pints1, pints2: PInteger; len1, len2: integer): boolean; var maxOscill, x1,x2, savedLen: integer; compareRec: PCompareRec; begin result := not fExecuting; if not result then exit; fExecuting := true; fCancelled := false; try Clear; //setup the character arrays ... Ints1 := pointer(pints1); Ints2 := pointer(pints2); //save first string length for later (ie for any trailing matches) ... savedLen := len1-1; //ignore top matches ... x1:= 0; x2 := 0; while (len1 > 0) and (len2 > 0) and (Ints1[len1-1] = Ints2[len2-1]) do begin dec(len1); dec(len2); end; //if something doesn't match ... if (len1 <> 0) or (len2 <> 0) then begin //ignore bottom of matches too ... while (len1 > 0) and (len2 > 0) and (Ints1[x1] = Ints2[x2]) do begin dec(len1); dec(len2); inc(x1); inc(x2); end; maxOscill := min(max(len1,len2), MAX_DIAGONAL); fCompareList.Capacity := len1 + len2; //nb: the Diag arrays are extended by 1 at each end to avoid testing //for array limits. Hence '+3' because will also includes Diag[0] ... GetMem(fDiagBuffer, sizeof(integer)*(maxOscill*2+3)); GetMem(bDiagBuffer, sizeof(integer)*(maxOscill*2+3)); try RecursiveDiffInt(x1, x2, len1, len2); finally freeMem(fDiagBuffer); freeMem(bDiagBuffer); end; end; if fCancelled then begin result := false; Clear; exit; end; //finally, append any trailing matches onto compareList ... while (LastCompareRec.oldIndex1 < savedLen) do begin with LastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); int1 := Ints1[oldIndex1]; int2 := Ints2[oldIndex2]; end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; finally fExecuting := false; end; end; //------------------------------------------------------------------------------ procedure TDiff.InitDiagArrays(MaxOscill, len1, len2: integer); var diag: integer; begin inc(maxOscill); //for the extra diag at each end of the arrays ... P8Bits(fDiag) := P8Bits(fDiagBuffer) - sizeof(integer)*(MAX_DIAGONAL-maxOscill); P8Bits(bDiag) := P8Bits(bDiagBuffer) - sizeof(integer)*(MAX_DIAGONAL-maxOscill); //initialize Diag arrays (assumes 0 based arrays) ... for diag := - maxOscill to maxOscill do fDiag[diag] := -MAXINT; fDiag[0] := -1; for diag := - maxOscill to maxOscill do bDiag[diag] := MAXINT; bDiag[len1 - len2] := len1-1; end; //------------------------------------------------------------------------------ procedure TDiff.RecursiveDiffChr(offset1, offset2, len1, len2: integer); var diag, lenDelta, Oscill, maxOscill, x1, x2: integer; begin //nb: the possible depth of recursion here is most unlikely to cause // problems with stack overflows. application.processmessages; if fCancelled then exit; if (len1 = 0) then begin AddChangeChrs(offset1, len2, ckAdd); exit; end else if (len2 = 0) then begin AddChangeChrs(offset1, len1, ckDelete); exit; end else if (len1 = 1) and (len2 = 1) then begin AddChangeChrs(offset1, 1, ckDelete); AddChangeChrs(offset1, 1, ckAdd); exit; end; maxOscill := min(max(len1,len2), MAX_DIAGONAL); InitDiagArrays(MaxOscill, len1, len2); lenDelta := len1 -len2; Oscill := 1; //ie assumes prior filter of top and bottom matches while Oscill <= maxOscill do begin if (Oscill mod 200) = 0 then begin application.processmessages; if fCancelled then exit; end; //do forward oscillation (keeping diag within assigned grid)... diag := Oscill; while diag > len1 do dec(diag,2); while diag >= max(- Oscill, -len2) do begin if fDiag[diag-1] < fDiag[diag+1] then x1 := fDiag[diag+1] else x1 := fDiag[diag-1]+1; x2 := x1 - diag; while (x1 < len1-1) and (x2 < len2-1) and (Chrs1[offset1+x1+1] = Chrs2[offset2+x2+1]) do begin inc(x1); inc(x2); end; fDiag[diag] := x1; //nb: (fDiag[diag] is always < bDiag[diag]) here when NOT odd(lenDelta) ... if odd(lenDelta) and (fDiag[diag] >= bDiag[diag]) then begin inc(x1);inc(x2); //save x1 & x2 for second recursive_diff() call by reusing no longer //needed variables (ie minimize variable allocation in recursive fn) ... diag := x1; Oscill := x2; while (x1 > 0) and (x2 > 0) and (Chrs1[offset1+x1-1] = Chrs2[offset2+x2-1]) do begin dec(x1); dec(x2); end; RecursiveDiffChr(offset1, offset2, x1, x2); x1 := diag; x2 := Oscill; RecursiveDiffChr(offset1+x1, offset2+x2, len1-x1, len2-x2); exit; //ALL DONE end; dec(diag,2); end; //do backward oscillation (keeping diag within assigned grid)... diag := lenDelta + Oscill; while diag > len1 do dec(diag,2); while diag >= max(lenDelta - Oscill, -len2) do begin if bDiag[diag-1] < bDiag[diag+1] then x1 := bDiag[diag-1] else x1 := bDiag[diag+1]-1; x2 := x1 - diag; while (x1 > -1) and (x2 > -1) and (Chrs1[offset1+x1] = Chrs2[offset2+x2]) do begin dec(x1); dec(x2); end; bDiag[diag] := x1; if bDiag[diag] <= fDiag[diag] then begin //flag return value then ... inc(x1);inc(x2); RecursiveDiffChr(offset1, offset2, x1, x2); while (x1 < len1) and (x2 < len2) and (Chrs1[offset1+x1] = Chrs2[offset2+x2]) do begin inc(x1); inc(x2); end; RecursiveDiffChr(offset1+x1, offset2+x2, len1-x1, len2-x2); exit; //ALL DONE end; dec(diag,2); end; inc(Oscill); end; //while Oscill <= maxOscill raise Exception.create('oops - error in RecursiveDiffChr()'); end; //------------------------------------------------------------------------------ procedure TDiff.RecursiveDiffInt(offset1, offset2, len1, len2: integer); var diag, lenDelta, Oscill, maxOscill, x1, x2: integer; begin //nb: the possible depth of recursion here is most unlikely to cause // problems with stack overflows. application.processmessages; if fCancelled then exit; if (len1 = 0) then begin assert(len2 > 0,'oops!'); AddChangeInts(offset1, len2, ckAdd); exit; end else if (len2 = 0) then begin AddChangeInts(offset1, len1, ckDelete); exit; end else if (len1 = 1) and (len2 = 1) then begin assert(Ints1[offset1] <> Ints2[offset2],'oops!'); AddChangeInts(offset1, 1, ckDelete); AddChangeInts(offset1, 1, ckAdd); exit; end; maxOscill := min(max(len1,len2), MAX_DIAGONAL); InitDiagArrays(MaxOscill, len1, len2); lenDelta := len1 -len2; Oscill := 1; //ie assumes prior filter of top and bottom matches while Oscill <= maxOscill do begin if (Oscill mod 200) = 0 then begin application.processmessages; if fCancelled then exit; end; //do forward oscillation (keeping diag within assigned grid)... diag := Oscill; while diag > len1 do dec(diag,2); while diag >= max(- Oscill, -len2) do begin if fDiag[diag-1] < fDiag[diag+1] then x1 := fDiag[diag+1] else x1 := fDiag[diag-1]+1; x2 := x1 - diag; while (x1 < len1-1) and (x2 < len2-1) and (Ints1[offset1+x1+1] = Ints2[offset2+x2+1]) do begin inc(x1); inc(x2); end; fDiag[diag] := x1; //nb: (fDiag[diag] is always < bDiag[diag]) here when NOT odd(lenDelta) ... if odd(lenDelta) and (fDiag[diag] >= bDiag[diag]) then begin inc(x1);inc(x2); //save x1 & x2 for second recursive_diff() call by reusing no longer //needed variables (ie minimize variable allocation in recursive fn) ... diag := x1; Oscill := x2; while (x1 > 0) and (x2 > 0) and (Ints1[offset1+x1-1] = Ints2[offset2+x2-1]) do begin dec(x1); dec(x2); end; RecursiveDiffInt(offset1, offset2, x1, x2); x1 := diag; x2 := Oscill; RecursiveDiffInt(offset1+x1, offset2+x2, len1-x1, len2-x2); exit; //ALL DONE end; dec(diag,2); end; //do backward oscillation (keeping diag within assigned grid)... diag := lenDelta + Oscill; while diag > len1 do dec(diag,2); while diag >= max(lenDelta - Oscill, -len2) do begin if bDiag[diag-1] < bDiag[diag+1] then x1 := bDiag[diag-1] else x1 := bDiag[diag+1]-1; x2 := x1 - diag; while (x1 > -1) and (x2 > -1) and (Ints1[offset1+x1] = Ints2[offset2+x2]) do begin dec(x1); dec(x2); end; bDiag[diag] := x1; if bDiag[diag] <= fDiag[diag] then begin //flag return value then ... inc(x1);inc(x2); RecursiveDiffInt(offset1, offset2, x1, x2); while (x1 < len1) and (x2 < len2) and (Ints1[offset1+x1] = Ints2[offset2+x2]) do begin inc(x1); inc(x2); end; RecursiveDiffInt(offset1+x1, offset2+x2, len1-x1, len2-x2); exit; //ALL DONE end; dec(diag,2); end; inc(Oscill); end; //while Oscill <= maxOscill raise Exception.create('oops - error in RecursiveDiffInt()'); end; //------------------------------------------------------------------------------ procedure TDiff.Clear; var i: integer; begin for i := 0 to fCompareList.Count-1 do dispose(PCompareRec(fCompareList[i])); fCompareList.clear; LastCompareRec.Kind := ckNone; LastCompareRec.oldIndex1 := -1; LastCompareRec.oldIndex2 := -1; fDiffStats.matches := 0; fDiffStats.adds := 0; fDiffStats.deletes :=0; fDiffStats.modifies :=0; Chrs1 := nil; Chrs2 := nil; Ints1 := nil; Ints2 := nil; end; //------------------------------------------------------------------------------ function TDiff.GetCompareCount: integer; begin result := fCompareList.count; end; //------------------------------------------------------------------------------ function TDiff.GetCompare(index: integer): TCompareRec; begin result := PCompareRec(fCompareList[index])^; end; //------------------------------------------------------------------------------ procedure TDiff.AddChangeChrs(offset1, range: integer; ChangeKind: TChangeKind); var i,j: integer; compareRec: PCompareRec; begin //first, add any unchanged items into this list ... while (LastCompareRec.oldIndex1 < offset1 -1) do begin with LastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); chr1 := Chrs1[oldIndex1]; chr2 := Chrs2[oldIndex2]; end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; case ChangeKind of ckAdd : begin for i := 1 to range do begin with LastCompareRec do begin //check if a range of adds are following a range of deletes //and convert them to modifies ... if Kind = ckDelete then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckDelete) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.deletes); inc(fDiffStats.modifies); inc(LastCompareRec.oldIndex2); PCompareRec(fCompareList[j]).oldIndex2 := LastCompareRec.oldIndex2; PCompareRec(fCompareList[j]).chr2 := Chrs2[oldIndex2]; if j = fCompareList.Count-1 then LastCompareRec.Kind := ckModify; continue; end; Kind := ckAdd; chr1 := #0; inc(oldIndex2); chr2 := Chrs2[oldIndex2]; //ie what we added end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.adds); end; end; ckDelete : begin for i := 1 to range do begin with LastCompareRec do begin //check if a range of deletes are following a range of adds //and convert them to modifies ... if Kind = ckAdd then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckAdd) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.adds); inc(fDiffStats.modifies); inc(LastCompareRec.oldIndex1); PCompareRec(fCompareList[j]).oldIndex1 := LastCompareRec.oldIndex1; PCompareRec(fCompareList[j]).chr1 := Chrs1[oldIndex1]; if j = fCompareList.Count-1 then LastCompareRec.Kind := ckModify; continue; end; Kind := ckDelete; chr2 := #0; inc(oldIndex1); chr1 := Chrs1[oldIndex1]; //ie what we deleted end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.deletes); end; end; end; end; //------------------------------------------------------------------------------ procedure TDiff.AddChangeInts(offset1, range: integer; ChangeKind: TChangeKind); var i,j: integer; compareRec: PCompareRec; begin //first, add any unchanged items into this list ... while (LastCompareRec.oldIndex1 < offset1 -1) do begin with LastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); int1 := Ints1[oldIndex1]; int2 := Ints2[oldIndex2]; end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; case ChangeKind of ckAdd : begin for i := 1 to range do begin with LastCompareRec do begin //check if a range of adds are following a range of deletes //and convert them to modifies ... if Kind = ckDelete then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckDelete) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.deletes); inc(fDiffStats.modifies); inc(LastCompareRec.oldIndex2); PCompareRec(fCompareList[j]).oldIndex2 := LastCompareRec.oldIndex2; PCompareRec(fCompareList[j]).int2 := Ints2[oldIndex2]; if j = fCompareList.Count-1 then LastCompareRec.Kind := ckModify; continue; end; Kind := ckAdd; int1 := $0; inc(oldIndex2); int2 := Ints2[oldIndex2]; //ie what we added end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.adds); end; end; ckDelete : begin for i := 1 to range do begin with LastCompareRec do begin //check if a range of deletes are following a range of adds //and convert them to modifies ... if Kind = ckAdd then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckAdd) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.adds); inc(fDiffStats.modifies); inc(LastCompareRec.oldIndex1); PCompareRec(fCompareList[j]).oldIndex1 := LastCompareRec.oldIndex1; PCompareRec(fCompareList[j]).int1 := Ints1[oldIndex1]; if j = fCompareList.Count-1 then LastCompareRec.Kind := ckModify; continue; end; Kind := ckDelete; int2 := $0; inc(oldIndex1); int1 := Ints1[oldIndex1]; //ie what we deleted end; New(compareRec); compareRec^ := LastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.deletes); end; end; end; end; //------------------------------------------------------------------------------ procedure TDiff.Cancel; begin fCancelled := true; end; //------------------------------------------------------------------------------ end. �����������������������������doublecmd-1.1.22/src/udiffonp.pas�������������������������������������������������������������������0000644�0001750�0000144�00000067101�14743153644�015721� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uDiffONP; (******************************************************************************* * Component TDiff * * Version: 4.1 * * Date: 7 November 2009 * * Compilers: Delphi 7 - Delphi 2009 * * Author: Angus Johnson - angusj-AT-myrealbox-DOT-com * * Copyright: 2001-2009 Angus Johnson * * * * Licence to use, terms and conditions: * * The code in the TDiff component is released as freeware * * provided you agree to the following terms & conditions: * * 1. the copyright notice, terms and conditions are * * left unchanged * * 2. modifications to the code by other authors must be * * clearly documented and accompanied by the modifier's name. * * 3. the TDiff component may be freely compiled into binary * * format and no acknowledgement is required. However, a * * discrete acknowledgement would be appreciated (eg. in a * * program's 'About Box'). * * * * Description: Component to list differences between two integer arrays * * using a "longest common subsequence" algorithm. * * Typically, this component is used to diff 2 text files * * once their individuals lines have been hashed. * * * * Acknowledgements: The key algorithm in this component is based on: * * "An O(NP) Sequence Comparison Algorithm" * * by Sun Wu, Udi Manber & Gene Myers * * and uses a "divide-and-conquer" technique to avoid * * using exponential amounts of memory as described in * * "An O(ND) Difference Algorithm and its Variations" * * By E Myers - Algorithmica Vol. 1 No. 2, 1986, pp. 251-266 * *******************************************************************************) (******************************************************************************* * History: * * 13 December 2001 - Original release (used Myer's O(ND) Difference Algorithm) * * 22 April 2008 - Complete rewrite to greatly improve the code and * * provide a much simpler view of differences through a new * * 'Compares' property. * * 21 May 2008 - Another complete code rewrite to use Sun Wu et al.'s * * O(NP) Sequence Comparison Algorithm which more than * * halves times of typical comparisons. * * 24 May 2008 - Reimplemented "divide-and-conquer" technique (which was * * omitted in 21 May release) so memory use is again minimal.* * 25 May 2008 - Removed recursion to avoid the possibility of running out * * of stack memory during massive comparisons. * * 2 June 2008 - Bugfix: incorrect number of appended AddChangeInt() calls * * in Execute() for integer arrays. (It was OK with Chars) * * Added check to prevent repeat calls to Execute() while * * already executing. * * Added extra parse of differences to find occasional * * missed matches. (See readme.txt for further discussion) * * 7 November 2009 - Updated so now compiles in newer versions of Delphi. * *******************************************************************************) {$mode delphi} interface uses SysUtils, Classes, Math, Forms, Dialogs; const MAX_DIAGONAL = $FFFFFF; //~16 million type {$IFDEF UNICODE} P8Bits = PByte; {$ELSE} P8Bits = PAnsiChar; {$ENDIF} PDiags = ^TDiags; TDiags = array [-MAX_DIAGONAL .. MAX_DIAGONAL] of integer; PIntArray = ^TIntArray; TIntArray = array[0 .. MAXINT div sizeof(integer) -1] of Integer; PChrArray = ^TChrArray; TChrArray = array[0 .. MAXINT div sizeof(char) -1] of Char; TChangeKind = (ckNone, ckAdd, ckDelete, ckModify); PCompareRec = ^TCompareRec; TCompareRec = record Kind : TChangeKind; oldIndex1, oldIndex2 : integer; case boolean of false : (chr1, chr2 : Char); true : (int1, int2 : integer); end; PDiffVars = ^TDiffVars; TDiffVars = record offset1 : integer; offset2 : integer; len1 : integer; len2 : integer; end; TDiffStats = record matches : integer; adds : integer; deletes : integer; modifies : integer; end; TDiff = class(TComponent) private fCompareList: TList; fDiffList: TList; //this TList circumvents the need for recursion fCancelled: boolean; fExecuting: boolean; fCompareInts: boolean; //ie are we comparing integer arrays or char arrays DiagBufferF: pointer; DiagBufferB: pointer; DiagF, DiagB: PDiags; Ints1, Ints2: PIntArray; Chrs1, Chrs2: PChrArray; fDiffStats: TDiffStats; fLastCompareRec: TCompareRec; procedure PushDiff(offset1, offset2, len1, len2: integer); function PopDiff: boolean; procedure InitDiagArrays(len1, len2: integer); procedure DiffInt(offset1, offset2, len1, len2: integer); procedure DiffChr(offset1, offset2, len1, len2: integer); function SnakeChrF(k,offset1,offset2,len1,len2: integer): boolean; function SnakeChrB(k,offset1,offset2,len1,len2: integer): boolean; function SnakeIntF(k,offset1,offset2,len1,len2: integer): boolean; function SnakeIntB(k,offset1,offset2,len1,len2: integer): boolean; procedure AddChangeChr(offset1, range: integer; ChangeKind: TChangeKind); procedure AddChangeInt(offset1, range: integer; ChangeKind: TChangeKind); function GetCompareCount: integer; function GetCompare(index: integer): TCompareRec; public constructor Create(aOwner: TComponent); override; destructor Destroy; override; //compare either and array of characters or an array of integers ... function Execute(pints1, pints2: PInteger; len1, len2: integer): boolean; overload; function Execute(pchrs1, pchrs2: PChar; len1, len2: integer): boolean; overload; //Cancel allows interrupting excessively prolonged comparisons procedure Cancel; procedure Clear; property Cancelled: boolean read fCancelled; property Count: integer read GetCompareCount; property Compares[index: integer]: TCompareRec read GetCompare; default; property DiffStats: TDiffStats read fDiffStats; end; implementation procedure Register; begin RegisterComponents('Samples', [TDiff]); end; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ constructor TDiff.Create(aOwner: TComponent); begin inherited; fCompareList := TList.create; fDiffList := TList.Create; end; //------------------------------------------------------------------------------ destructor TDiff.Destroy; begin Clear; fCompareList.free; fDiffList.Free; inherited; end; //------------------------------------------------------------------------------ function TDiff.Execute(pints1, pints2: PInteger; len1, len2: integer): boolean; var i, Len1Minus1: integer; begin result := not fExecuting; if not result then exit; fCancelled := false; fExecuting := true; try Clear; Len1Minus1 := len1 -1; fCompareList.Capacity := len1 + len2; fCompareInts := true; GetMem(DiagBufferF, sizeof(integer)*(len1+len2+3)); GetMem(DiagBufferB, sizeof(integer)*(len1+len2+3)); Ints1 := pointer(pints1); Ints2 := pointer(pints2); try PushDiff(0, 0, len1, len2); while PopDiff do; finally freeMem(DiagBufferF); freeMem(DiagBufferB); end; if fCancelled then begin result := false; Clear; exit; end; //correct the occasional missed match ... for i := 1 to count -1 do with PCompareRec(fCompareList[i])^ do if (Kind = ckModify) and (int1 = int2) then begin Kind := ckNone; Dec(fDiffStats.modifies); Inc(fDiffStats.matches); end; //finally, append any trailing matches onto compareList ... with fLastCompareRec do AddChangeInt(oldIndex1,len1Minus1-oldIndex1, ckNone); finally fExecuting := false; end; end; //------------------------------------------------------------------------------ function TDiff.Execute(pchrs1, pchrs2: PChar; len1, len2: integer): boolean; var i, Len1Minus1: integer; begin result := not fExecuting; if not result then exit; fCancelled := false; fExecuting := true; try Clear; Len1Minus1 := len1 -1; fCompareList.Capacity := len1 + len2; fDiffList.Capacity := 1024; fCompareInts := false; GetMem(DiagBufferF, sizeof(integer)*(len1+len2+3)); GetMem(DiagBufferB, sizeof(integer)*(len1+len2+3)); Chrs1 := pointer(pchrs1); Chrs2 := pointer(pchrs2); try PushDiff(0, 0, len1, len2); while PopDiff do; finally freeMem(DiagBufferF); freeMem(DiagBufferB); end; if fCancelled then begin result := false; Clear; exit; end; //correct the occasional missed match ... for i := 1 to count -1 do with PCompareRec(fCompareList[i])^ do if (Kind = ckModify) and (chr1 = chr2) then begin Kind := ckNone; Dec(fDiffStats.modifies); Inc(fDiffStats.matches); end; //finally, append any trailing matches onto compareList ... with fLastCompareRec do AddChangeChr(oldIndex1,len1Minus1-oldIndex1, ckNone); finally fExecuting := false; end; end; //------------------------------------------------------------------------------ procedure TDiff.PushDiff(offset1, offset2, len1, len2: integer); var DiffVars: PDiffVars; begin new(DiffVars); DiffVars.offset1 := offset1; DiffVars.offset2 := offset2; DiffVars.len1 := len1; DiffVars.len2 := len2; fDiffList.Add(DiffVars); end; //------------------------------------------------------------------------------ function TDiff.PopDiff: boolean; var DiffVars: PDiffVars; idx: integer; begin idx := fDiffList.Count -1; result := idx >= 0; if not result then exit; DiffVars := PDiffVars(fDiffList[idx]); with DiffVars^ do if fCompareInts then DiffInt(offset1, offset2, len1, len2) else DiffChr(offset1, offset2, len1, len2); Dispose(DiffVars); fDiffList.Delete(idx); end; //------------------------------------------------------------------------------ procedure TDiff.InitDiagArrays(len1, len2: integer); var i: integer; begin //assumes that top and bottom matches have been excluded P8Bits(DiagF) := P8Bits(DiagBufferF) - sizeof(integer)*(MAX_DIAGONAL-(len1+1)); for i := - (len1+1) to (len2+1) do DiagF[i] := -MAXINT; DiagF[1] := -1; P8Bits(DiagB) := P8Bits(DiagBufferB) - sizeof(integer)*(MAX_DIAGONAL-(len1+1)); for i := - (len1+1) to (len2+1) do DiagB[i] := MAXINT; DiagB[len2-len1+1] := len2; end; //------------------------------------------------------------------------------ procedure TDiff.DiffInt(offset1, offset2, len1, len2: integer); var p, k, delta: integer; begin //trim matching bottoms ... while (len1 > 0) and (len2 > 0) and (Ints1[offset1] = Ints2[offset2]) do begin inc(offset1); inc(offset2); dec(len1); dec(len2); end; //trim matching tops ... while (len1 > 0) and (len2 > 0) and (Ints1[offset1+len1-1] = Ints2[offset2+len2-1]) do begin dec(len1); dec(len2); end; //stop diff'ing if minimal conditions reached ... if (len1 = 0) then begin AddChangeInt(offset1 ,len2, ckAdd); exit; end else if (len2 = 0) then begin AddChangeInt(offset1 ,len1, ckDelete); exit; end else if (len1 = 1) and (len2 = 1) then begin AddChangeInt(offset1, 1, ckDelete); AddChangeInt(offset1, 1, ckAdd); exit; end; p := -1; delta := len2 - len1; InitDiagArrays(len1, len2); if delta < 0 then begin repeat inc(p); if (p mod 1024) = 1023 then begin Application.ProcessMessages; if fCancelled then exit; end; //nb: the Snake order is important here for k := p downto delta +1 do if SnakeIntF(k,offset1,offset2,len1,len2) then exit; for k := -p + delta to delta-1 do if SnakeIntF(k,offset1,offset2,len1,len2) then exit; for k := delta -p to -1 do if SnakeIntB(k,offset1,offset2,len1,len2) then exit; for k := p downto 1 do if SnakeIntB(k,offset1,offset2,len1,len2) then exit; if SnakeIntF(delta,offset1,offset2,len1,len2) then exit; if SnakeIntB(0,offset1,offset2,len1,len2) then exit; until(false); end else begin repeat inc(p); if (p mod 1024) = 1023 then begin Application.ProcessMessages; if fCancelled then exit; end; //nb: the Snake order is important here for k := -p to delta -1 do if SnakeIntF(k,offset1,offset2,len1,len2) then exit; for k := p + delta downto delta +1 do if SnakeIntF(k,offset1,offset2,len1,len2) then exit; for k := delta + p downto 1 do if SnakeIntB(k,offset1,offset2,len1,len2) then exit; for k := -p to -1 do if SnakeIntB(k,offset1,offset2,len1,len2) then exit; if SnakeIntF(delta,offset1,offset2,len1,len2) then exit; if SnakeIntB(0,offset1,offset2,len1,len2) then exit; until(false); end; end; //------------------------------------------------------------------------------ procedure TDiff.DiffChr(offset1, offset2, len1, len2: integer); var p, k, delta: integer; begin //trim matching bottoms ... while (len1 > 0) and (len2 > 0) and (Chrs1[offset1] = Chrs2[offset2]) do begin inc(offset1); inc(offset2); dec(len1); dec(len2); end; //trim matching tops ... while (len1 > 0) and (len2 > 0) and (Chrs1[offset1+len1-1] = Chrs2[offset2+len2-1]) do begin dec(len1); dec(len2); end; //stop diff'ing if minimal conditions reached ... if (len1 = 0) then begin AddChangeChr(offset1 ,len2, ckAdd); exit; end else if (len2 = 0) then begin AddChangeChr(offset1, len1, ckDelete); exit; end else if (len1 = 1) and (len2 = 1) then begin AddChangeChr(offset1, 1, ckDelete); AddChangeChr(offset1, 1, ckAdd); exit; end; p := -1; delta := len2 - len1; InitDiagArrays(len1, len2); if delta < 0 then begin repeat inc(p); if (p mod 1024 = 1023) then begin Application.ProcessMessages; if fCancelled then exit; end; //nb: the Snake order is important here for k := p downto delta +1 do if SnakeChrF(k,offset1,offset2,len1,len2) then exit; for k := -p + delta to delta-1 do if SnakeChrF(k,offset1,offset2,len1,len2) then exit; for k := delta -p to -1 do if SnakeChrB(k,offset1,offset2,len1,len2) then exit; for k := p downto 1 do if SnakeChrB(k,offset1,offset2,len1,len2) then exit; if SnakeChrF(delta,offset1,offset2,len1,len2) then exit; if SnakeChrB(0,offset1,offset2,len1,len2) then exit; until(false); end else begin repeat inc(p); if (p mod 1024 = 1023) then begin Application.ProcessMessages; if fCancelled then exit; end; //nb: the Snake order is important here for k := -p to delta -1 do if SnakeChrF(k,offset1,offset2,len1,len2) then exit; for k := p + delta downto delta +1 do if SnakeChrF(k,offset1,offset2,len1,len2) then exit; for k := delta + p downto 1 do if SnakeChrB(k,offset1,offset2,len1,len2) then exit; for k := -p to -1 do if SnakeChrB(k,offset1,offset2,len1,len2) then exit; if SnakeChrF(delta,offset1,offset2,len1,len2) then exit; if SnakeChrB(0,offset1,offset2,len1,len2) then exit; until(false); end; end; //------------------------------------------------------------------------------ function TDiff.SnakeChrF(k,offset1,offset2,len1,len2: integer): boolean; var x,y: integer; begin if DiagF[k+1] > DiagF[k-1] then y := DiagF[k+1] else y := DiagF[k-1]+1; x := y - k; while (x < len1-1) and (y < len2-1) and (Chrs1[offset1+x+1] = Chrs2[offset2+y+1]) do begin inc(x); inc(y); end; DiagF[k] := y; result := (DiagF[k] >= DiagB[k]); if not result then exit; inc(x); inc(y); PushDiff(offset1+x, offset2+y, len1-x, len2-y); PushDiff(offset1, offset2, x, y); end; //------------------------------------------------------------------------------ function TDiff.SnakeChrB(k,offset1,offset2,len1,len2: integer): boolean; var x,y: integer; begin if DiagB[k-1] < DiagB[k+1] then y := DiagB[k-1] else y := DiagB[k+1]-1; x := y - k; while (x >= 0) and (y >= 0) and (Chrs1[offset1+x] = Chrs2[offset2+y]) do begin dec(x); dec(y); end; DiagB[k] := y; result := DiagB[k] <= DiagF[k]; if not result then exit; inc(x); inc(y); PushDiff(offset1+x, offset2+y, len1-x, len2-y); PushDiff(offset1, offset2, x, y); end; //------------------------------------------------------------------------------ function TDiff.SnakeIntF(k,offset1,offset2,len1,len2: integer): boolean; var x,y: integer; begin if DiagF[k+1] > DiagF[k-1] then y := DiagF[k+1] else y := DiagF[k-1]+1; x := y - k; while (x < len1-1) and (y < len2-1) and (Ints1[offset1+x+1] = Ints2[offset2+y+1]) do begin inc(x); inc(y); end; DiagF[k] := y; result := (DiagF[k] >= DiagB[k]); if not result then exit; inc(x); inc(y); PushDiff(offset1+x, offset2+y, len1-x, len2-y); PushDiff(offset1, offset2, x, y); end; //------------------------------------------------------------------------------ function TDiff.SnakeIntB(k,offset1,offset2,len1,len2: integer): boolean; var x,y: integer; begin if DiagB[k-1] < DiagB[k+1] then y := DiagB[k-1] else y := DiagB[k+1]-1; x := y - k; while (x >= 0) and (y >= 0) and (Ints1[offset1+x] = Ints2[offset2+y]) do begin dec(x); dec(y); end; DiagB[k] := y; result := DiagB[k] <= DiagF[k]; if not result then exit; inc(x); inc(y); PushDiff(offset1+x, offset2+y, len1-x, len2-y); PushDiff(offset1, offset2, x, y); end; //------------------------------------------------------------------------------ procedure TDiff.AddChangeChr(offset1, range: integer; ChangeKind: TChangeKind); var i,j: integer; compareRec: PCompareRec; begin //first, add any unchanged items into this list ... while (fLastCompareRec.oldIndex1 < offset1 -1) do begin with fLastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); chr1 := Chrs1[oldIndex1]; chr2 := Chrs2[oldIndex2]; end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; case ChangeKind of ckNone: for i := 1 to range do begin with fLastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); chr1 := Chrs1[oldIndex1]; chr2 := Chrs2[oldIndex2]; end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; ckAdd : begin for i := 1 to range do begin with fLastCompareRec do begin //check if a range of adds are following a range of deletes //and convert them to modifies ... if Kind = ckDelete then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckDelete) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.deletes); inc(fDiffStats.modifies); inc(fLastCompareRec.oldIndex2); PCompareRec(fCompareList[j]).oldIndex2 := fLastCompareRec.oldIndex2; PCompareRec(fCompareList[j]).chr2 := Chrs2[oldIndex2]; if j = fCompareList.Count-1 then fLastCompareRec.Kind := ckModify; continue; end; Kind := ckAdd; chr1 := #0; inc(oldIndex2); chr2 := Chrs2[oldIndex2]; //ie what we added end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.adds); end; end; ckDelete : begin for i := 1 to range do begin with fLastCompareRec do begin //check if a range of deletes are following a range of adds //and convert them to modifies ... if Kind = ckAdd then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckAdd) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.adds); inc(fDiffStats.modifies); inc(fLastCompareRec.oldIndex1); PCompareRec(fCompareList[j]).oldIndex1 := fLastCompareRec.oldIndex1; PCompareRec(fCompareList[j]).chr1 := Chrs1[oldIndex1]; if j = fCompareList.Count-1 then fLastCompareRec.Kind := ckModify; continue; end; Kind := ckDelete; chr2 := #0; inc(oldIndex1); chr1 := Chrs1[oldIndex1]; //ie what we deleted end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.deletes); end; end; end; end; //------------------------------------------------------------------------------ procedure TDiff.AddChangeInt(offset1, range: integer; ChangeKind: TChangeKind); var i,j: integer; compareRec: PCompareRec; begin //first, add any unchanged items into this list ... while (fLastCompareRec.oldIndex1 < offset1 -1) do begin with fLastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); int1 := Ints1[oldIndex1]; int2 := Ints2[oldIndex2]; end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; case ChangeKind of ckNone: for i := 1 to range do begin with fLastCompareRec do begin Kind := ckNone; inc(oldIndex1); inc(oldIndex2); int1 := Ints1[oldIndex1]; int2 := Ints2[oldIndex2]; end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.matches); end; ckAdd : begin for i := 1 to range do begin with fLastCompareRec do begin //check if a range of adds are following a range of deletes //and convert them to modifies ... if Kind = ckDelete then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckDelete) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.deletes); inc(fDiffStats.modifies); inc(fLastCompareRec.oldIndex2); PCompareRec(fCompareList[j]).oldIndex2 := fLastCompareRec.oldIndex2; PCompareRec(fCompareList[j]).int2 := Ints2[oldIndex2]; if j = fCompareList.Count-1 then fLastCompareRec.Kind := ckModify; continue; end; Kind := ckAdd; int1 := $0; inc(oldIndex2); int2 := Ints2[oldIndex2]; //ie what we added end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.adds); end; end; ckDelete : begin for i := 1 to range do begin with fLastCompareRec do begin //check if a range of deletes are following a range of adds //and convert them to modifies ... if Kind = ckAdd then begin j := fCompareList.Count -1; while (j > 0) and (PCompareRec(fCompareList[j-1]).Kind = ckAdd) do dec(j); PCompareRec(fCompareList[j]).Kind := ckModify; dec(fDiffStats.adds); inc(fDiffStats.modifies); inc(fLastCompareRec.oldIndex1); PCompareRec(fCompareList[j]).oldIndex1 := fLastCompareRec.oldIndex1; PCompareRec(fCompareList[j]).int1 := Ints1[oldIndex1]; if j = fCompareList.Count-1 then fLastCompareRec.Kind := ckModify; continue; end; Kind := ckDelete; int2 := $0; inc(oldIndex1); int1 := Ints1[oldIndex1]; //ie what we deleted end; New(compareRec); compareRec^ := fLastCompareRec; fCompareList.Add(compareRec); inc(fDiffStats.deletes); end; end; end; end; //------------------------------------------------------------------------------ procedure TDiff.Clear; var i: integer; begin for i := 0 to fCompareList.Count-1 do dispose(PCompareRec(fCompareList[i])); fCompareList.clear; fLastCompareRec.Kind := ckNone; fLastCompareRec.oldIndex1 := -1; fLastCompareRec.oldIndex2 := -1; fDiffStats.matches := 0; fDiffStats.adds := 0; fDiffStats.deletes :=0; fDiffStats.modifies :=0; Ints1 := nil; Ints2 := nil; Chrs1 := nil; Chrs2 := nil; end; //------------------------------------------------------------------------------ function TDiff.GetCompareCount: integer; begin result := fCompareList.count; end; //------------------------------------------------------------------------------ function TDiff.GetCompare(index: integer): TCompareRec; begin result := PCompareRec(fCompareList[index])^; end; //------------------------------------------------------------------------------ procedure TDiff.Cancel; begin fCancelled := true; end; //------------------------------------------------------------------------------ end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udisplayfile.pas���������������������������������������������������������������0000644�0001750�0000144�00000015470�14743153644�016603� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uDisplayFile; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, uFile; type TDisplayItemPtr = Pointer; TBusyState = (bsProp, bsTag); TDisplayFileBusy = set of TBusyState; {en Describes the file displayed in the file view. } { TDisplayFile } TDisplayFile = class private FFSFile: TFile; //<en reference to file source's file FDisplayItem: TDisplayItemPtr; //<en Item that displays this file (for example Node in a tree). // Other properties. FTag: PtrInt; //<en File view related info FSelected: Boolean; //<en If is selected FBusy: TDisplayFileBusy; //<en File properties is busy FIconID: PtrInt; //<en Icon ID for PixmapManager FIconOverlayID: PtrInt; //<en Overlay icon ID for PixmapManager FTextColor: TColor; //<en Text color in file list {en Used to indicate that the file has been recently updated. Value goes from 100 to 0. 0 - not recently updated, 100 - just updated. } FRecentlyUpdatedPct: Integer; // Cache of displayed strings. FDisplayStrings: TStringList; public {en @param(ReferenceFile Reference file source file that will be associated with this display file. The TDisplayFile takes ownership and will destroy the FS file.) } constructor Create(ReferenceFile: TFile); virtual reintroduce; destructor Destroy; override; {en Creates an identical copy of the object (as far as object data is concerned). @param(NewReferenceFile FS file to assign as the reference file (possibly a clone too).) } function Clone(NewReferenceFile: TFile): TDisplayFile; {en Creates an identical copy of the object (as far as object data is concerned). @param(CloneFSFile If @false then the reference FS file must be later manually assigned. Also, if @false DisplayStrings are not cloned.) } function Clone(CloneFSFile: Boolean): TDisplayFile; virtual; procedure CloneTo(AFile: TDisplayFile); virtual; property FSFile: TFile read FFSFile write FFSFile; property DisplayItem: TDisplayItemPtr read FDisplayItem write FDisplayItem; property Selected: Boolean read FSelected write FSelected; property IconID: PtrInt read FIconID write FIconID; property IconOverlayID: PtrInt read FIconOverlayID write FIconOverlayID; property TextColor: TColor read FTextColor write FTextColor; property DisplayStrings: TStringList read FDisplayStrings; property RecentlyUpdatedPct: Integer read FRecentlyUpdatedPct write FRecentlyUpdatedPct; property Busy: TDisplayFileBusy read FBusy write FBusy; property Tag: PtrInt read FTag write FTag; end; { TDisplayFiles } TDisplayFiles = class private FList: TFPList; FOwnsObjects: Boolean; protected function GetCount: Integer; procedure SetCount(Count: Integer); function Get(Index: Integer): TDisplayFile; procedure Put(Index: Integer; AFile: TDisplayFile); public constructor Create(AOwnsObjects: Boolean = True); virtual; destructor Destroy; override; {en Create a list with cloned files. @param(CloneFSFiles If @true automatically clones all FS reference files too. If @false does not clone reference files and some properties that are affected by reference FS files.) } function Clone(CloneFSFiles: Boolean): TDisplayFiles; virtual; procedure CloneTo(Files: TDisplayFiles; CloneFSFiles: Boolean); virtual; function Add(AFile: TDisplayFile): Integer; procedure Clear; procedure Delete(Index: Integer); function Find(AFile: TDisplayFile): Integer; procedure Remove(AFile: TDisplayFile); property Count: Integer read GetCount write SetCount; property Items[Index: Integer]: TDisplayFile read Get write Put; default; property List: TFPList read FList; property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects; end; implementation constructor TDisplayFile.Create(ReferenceFile: TFile); begin FTag := -1; FIconID := -1; FIconOverlayID := -1; FTextColor := clNone; FFSFile := ReferenceFile; FDisplayStrings := TStringList.Create; end; destructor TDisplayFile.Destroy; begin inherited Destroy; FDisplayStrings.Free; FSFile.Free; end; function TDisplayFile.Clone(NewReferenceFile: TFile): TDisplayFile; begin Result := TDisplayFile.Create(NewReferenceFile); CloneTo(Result); end; function TDisplayFile.Clone(CloneFSFile: Boolean): TDisplayFile; var AFile: TFile; begin if CloneFSFile then AFile := FSFile.Clone else AFile := nil; Result := TDisplayFile.Create(AFile); CloneTo(Result); end; procedure TDisplayFile.CloneTo(AFile: TDisplayFile); begin if Assigned(AFile) then begin AFile.FSelected := FSelected; AFile.FIconID := FIconID; AFile.FIconOverlayID := FIconOverlayID; AFile.FTextColor := FTextColor; if Assigned(AFile.FFSFile) then begin AFile.FDisplayStrings.AddStrings(FDisplayStrings); end; end; end; // ---------------------------------------------------------------------------- constructor TDisplayFiles.Create(AOwnsObjects: Boolean = True); begin inherited Create; FOwnsObjects := AOwnsObjects; FList := TFPList.Create; end; destructor TDisplayFiles.Destroy; begin Clear; FreeAndNil(FList); inherited Destroy; end; function TDisplayFiles.Clone(CloneFSFiles: Boolean): TDisplayFiles; begin Result := TDisplayFiles.Create(FOwnsObjects); CloneTo(Result, CloneFSFiles); end; procedure TDisplayFiles.CloneTo(Files: TDisplayFiles; CloneFSFiles: Boolean); var i: Integer; begin for i := 0 to FList.Count - 1 do begin Files.Add(Get(i).Clone(CloneFSFiles)); end; end; function TDisplayFiles.GetCount: Integer; begin Result := FList.Count; end; procedure TDisplayFiles.SetCount(Count: Integer); begin FList.Count := Count; end; function TDisplayFiles.Add(AFile: TDisplayFile): Integer; begin Result := FList.Add(AFile); end; procedure TDisplayFiles.Clear; var i: Integer; p: Pointer; begin if FOwnsObjects then begin for i := 0 to FList.Count - 1 do begin p := FList.Items[i]; TDisplayFile(p).Free; end; end; FList.Clear; end; procedure TDisplayFiles.Delete(Index: Integer); begin if FOwnsObjects then TDisplayFile(FList.Items[Index]).Free; FList.Delete(Index); end; function TDisplayFiles.Find(AFile: TDisplayFile): Integer; begin Result := FList.IndexOf(AFile); end; procedure TDisplayFiles.Remove(AFile: TDisplayFile); var i: Integer; begin i := Find(AFile); if i >= 0 then Delete(i); end; function TDisplayFiles.Get(Index: Integer): TDisplayFile; begin Result := TDisplayFile(FList.Items[Index]); end; procedure TDisplayFiles.Put(Index: Integer; AFile: TDisplayFile); begin FList.Items[Index] := AFile; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udrive.pas���������������������������������������������������������������������0000644�0001750�0000144�00000010503�14743153644�015377� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Structures describing drives. Copyright (C) 2006-2010 Koblov Alexander (Alexx2000@mail.ru) Copyright (C) 2010 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uDrive; {$mode objfpc}{$H+} interface uses Classes; type TDriveType = (dtUnknown, dtFlash, // Flash drive dtFloppy, // 3.5'', ZIP drive, etc. dtHardDisk, // Hard disk drive dtNetwork, // Network share dtOptical, // CD, DVD, Blu-Ray, etc. dtRamDisk, // Ram-disk dtRemovable, // Drive with removable media dtRemovableUsb, // Drive connected via USB dtVirtual, // Virtual drive dtSpecial); // Special drive { TDrive } // On Linux we also put here mount points other than drives. TDrive = record DisplayName, //<en Name displayed to the user. Path, //<en Where this drive is or should be mounted (by /etc/fstab). DriveLabel, //<en Drive label if filesystem on the drive supports it. DeviceId: String; //<en Device ID that can be used for mounting, ejecting, etc. DriveType : TDriveType; DriveSize : Int64; //<en Drive size FileSystem: String; //<en Filesystem on the drive IsMediaAvailable: Boolean; //<en Is media available in a drive with removable media. IsMediaEjectable: Boolean; //<en Can eject media by a command. IsMediaRemovable: Boolean; //<en If the drive has removable media. IsMounted: Boolean; //<en Is the drive mounted. AutoMount: Boolean; //<en Should the drive be automounted end; PDrive = ^TDrive; { TDrivesList } TDrivesList = class private FList: TFPList; protected function Get(Index: Integer): PDrive; function GetCount: Integer; public constructor Create; destructor Destroy; override; function Add(ADrive: PDrive): Integer; procedure Remove(Index: Integer); procedure RemoveAll; procedure Sort(Compare: TListSortCompare); property Items[Index: Integer]: PDrive read Get; default; property Count: Integer read GetCount; end; {en Returns drive label or status description. } function GetDriveLabelOrStatus(Drive: PDrive): String; implementation uses SysUtils, uLng; function GetDriveLabelOrStatus(Drive: PDrive): String; begin if Drive^.DriveLabel <> EmptyStr then Result := Drive^.DriveLabel else if not Drive^.IsMediaAvailable then Result := rsDriveNoMedia else Result := rsDriveNoLabel; end; { TDrivesList } constructor TDrivesList.Create; begin FList := TFPList.Create; end; destructor TDrivesList.Destroy; begin inherited Destroy; RemoveAll; FList.Free; end; function TDrivesList.Add(ADrive: PDrive): Integer; begin Result := FList.Add(ADrive); end; procedure TDrivesList.Remove(Index: Integer); begin if (Index >= 0) and (Index < FList.Count) then begin Dispose(PDrive(FList[Index])); FList.Delete(Index); end else raise ERangeError.Create('Invalid index'); end; procedure TDrivesList.RemoveAll; begin while FList.Count > 0 do Remove(0); end; procedure TDrivesList.Sort(Compare: TListSortCompare); begin FList.Sort(Compare); end; function TDrivesList.Get(Index: Integer): PDrive; begin if (Index >= 0) and (Index < FList.Count) then begin Result := PDrive(FList.Items[Index]); end else raise ERangeError.Create('Invalid index'); end; function TDrivesList.GetCount: Integer; begin Result := FList.Count; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udriveslist.pas����������������������������������������������������������������0000644�0001750�0000144�00000040374�14743153644�016467� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Control that shows drives list and allows selecting a drive. Copyright (C) 2009-2018 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2009-2011 Przemyslaw Nagay (cobines@gmail.com) 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, see <http://www.gnu.org/licenses/>. } unit uDrivesList; {$mode objfpc}{$H+} {$IFDEF MSWINDOWS} {$DEFINE ForceVirtualKeysShortcuts} {$DEFINE FileCaseInsensitive} {$ENDIF} {$IFDEF DARWIN} {$DEFINE FileCaseInsensitive} {$ENDIF} interface uses Classes, SysUtils, Grids, Controls, LCLType, uFilePanelSelect, uDrive; type TDriveSelected = procedure (Sender: TObject; ADriveIndex: Integer; APanel: TFilePanelSelect) of object; { TDrivesListPopup } TDrivesListPopup = class(TStringGrid) private FDriveIconSize: Integer; FDrivesList: TDrivesList; FPanel: TFilePanelSelect; FShortCuts: array of TUTF8Char; FAllowSelectDummyRow: Boolean; FOnDriveSelected: TDriveSelected; FOnClose: TNotifyEvent; {en @param(ARow Row nr in the grid (LowestRow..HighestRow).) } function GetDriveIndexByRow(ARow: Integer): Integer; function GetDrivesCount: Integer; function GetLowestRow: Integer; function GetHighestRow: Integer; procedure PrepareCanvasEvent(Sender: TObject; aCol, {%H-}aRow: Integer; {%H-}aState: TGridDrawState); procedure SelectCellEvent(Sender: TObject; {%H-}aCol, aRow: Integer; var CanSelect: Boolean); procedure EnterEvent(Sender: TObject); procedure ExitEvent(Sender: TObject); procedure KeyDownEvent(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState); procedure KeyPressEvent(Sender: TObject; var Key: Char); {$IFNDEF ForceVirtualKeysShortcuts} procedure UTF8KeyPressEvent(Sender: TObject; var UTF8Key: TUTF8Char); {$ENDIF} procedure SelectDrive(ADriveIndex: Integer); procedure DoDriveSelected(ADriveIndex: Integer); procedure ShowContextMenu(ADriveIndex: Integer; X, Y: Integer); procedure ContextMenuClosed(Sender: TObject); {en Checks if the given shortcut is assigned to a drive. If it is then that drive is selected. @returns(@true if shortcut found, @false otherwise.) } function CheckShortcut(AShortcut: TUTF8Char): Boolean; procedure Close; procedure UpdateCells; procedure UpdateSize; property LowestRow: Integer read GetLowestRow; property HighestRow: Integer read GetHighestRow; protected procedure DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); override; procedure MouseDown(Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer); override; procedure MouseMove({%H-}Shift: TShiftState; X, Y: Integer); override; procedure MouseUp({%H-}Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer); override; procedure Paint; override; public constructor Create(AOwner: TComponent; AParent: TWinControl); reintroduce; procedure UpdateDrivesList(ADrivesList: TDrivesList); procedure UpdateView; {en Shows the drive list. @param(AtPoint Position where to show the list.) @param(APanel For which panel the list is to be shown.) @param(ASelectedDriveIndex Which drive to pre-select (0..DrivesCount-1).) } procedure Show(AtPoint: TPoint; APanel: TFilePanelSelect; ASelectedDriveIndex: Integer = -1); procedure SetFocus; override; property Panel: TFilePanelSelect read FPanel; property DrivesCount: Integer read GetDrivesCount; property OnDriveSelected: TDriveSelected read FOnDriveSelected write FOnDriveSelected; property OnClose: TNotifyEvent read FOnClose write FOnClose; end; implementation uses StdCtrls, Graphics, LCLProc, LazUTF8, uPixMapManager, uOSUtils, uDCUtils, uOSForms, uGlobs; const DriveIconSize = 16; // One dummy row is added, which is not displayed and cannot be selected. // It is used to simulate having no selection in the grid, because the // TCustomGrid forces at least one row/cell to be selected or focused. DummyRows = 1; constructor TDrivesListPopup.Create(AOwner: TComponent; AParent: TWinControl); begin inherited Create(AOwner); ControlStyle := ControlStyle + [csNoFocus]; Parent := AParent; FDrivesList := nil; FShortCuts := nil; FAllowSelectDummyRow := False; FOnDriveSelected := nil; FOnClose := nil; AllowOutboundEvents := False; AutoFillColumns := False; BorderStyle := bsNone; BorderWidth := 0; ExtendedSelect := False; Flat := False; FocusRectVisible := False; MouseWheelOption := mwGrid; Options := [goRowSelect, goThumbTracking]; ScrollBars := ssNone; Visible := False; while Columns.Count < 5 do Columns.Add; RowCount := 0 + DummyRows; FixedCols := 0; FixedRows := 0; if DummyRows > 0 then RowHeights[FixedRows] := 1; // Every row must have Height > 0 Color := clBtnFace; Font.Color := clWindowText; FDriveIconSize := AdjustIconSize(DriveIconSize, 96); OnPrepareCanvas := @PrepareCanvasEvent; OnSelectCell := @SelectCellEvent; OnEnter := @EnterEvent; OnExit := @ExitEvent; OnKeyDown := @KeyDownEvent; OnKeyPress := @KeyPressEvent; {$IFNDEF ForceVirtualKeysShortcuts} OnUTF8KeyPress := @UTF8KeyPressEvent; {$ENDIF} end; procedure TDrivesListPopup.UpdateDrivesList(ADrivesList: TDrivesList); begin FDrivesList := ADrivesList; RowCount := LowestRow + ADrivesList.Count; Clean; SetLength(FShortCuts, ADrivesList.Count); // If currently visible update the grid. if IsVisible then begin UpdateCells; UpdateSize; end; end; procedure TDrivesListPopup.UpdateView; begin Columns.Items[2].Visible := dlbShowLabel in gDrivesListButtonOptions; Columns.Items[3].Visible := dlbShowFileSystem in gDrivesListButtonOptions; Columns.Items[4].Visible := dlbShowFreeSpace in gDrivesListButtonOptions; end; procedure TDrivesListPopup.Show(AtPoint: TPoint; APanel: TFilePanelSelect; ASelectedDriveIndex: Integer = -1); begin UpdateCells; UpdateSize; FPanel := APanel; Left := AtPoint.X; Top := AtPoint.Y; Visible := True; ASelectedDriveIndex := LowestRow + ASelectedDriveIndex; if (ASelectedDriveIndex >= LowestRow) and (ASelectedDriveIndex <= HighestRow) then Row := ASelectedDriveIndex else begin FAllowSelectDummyRow := True; Row := FixedRows; // Select dummy row to clear selection FAllowSelectDummyRow := False; end; // Set focus using parent procedure. inherited SetFocus; end; procedure TDrivesListPopup.SetFocus; begin // Empty - don't allow setting focus. end; procedure TDrivesListPopup.PrepareCanvasEvent(Sender: TObject; aCol, aRow: Integer; aState: TGridDrawState); var ts: TTextStyle; begin if aCol = 4 then begin // Right-align free space text in third column. ts := Canvas.TextStyle; ts.Alignment := taRightJustify; Canvas.TextStyle := ts; end else if aCol > 0 then begin // Left-align other columns (except column 0 which shows the icon). ts := Canvas.TextStyle; ts.Alignment := taLeftJustify; Canvas.TextStyle := ts; end; end; function TDrivesListPopup.GetDriveIndexByRow(ARow: Integer): Integer; begin if (ARow >= LowestRow) and (ARow <= HighestRow) then Result := ARow - LowestRow else Result := -1; end; function TDrivesListPopup.GetDrivesCount: Integer; begin Result := HighestRow - LowestRow + 1; end; function TDrivesListPopup.GetLowestRow: Integer; begin Result := FixedRows + DummyRows; end; function TDrivesListPopup.GetHighestRow: Integer; begin Result := RowCount - 1; end; procedure TDrivesListPopup.DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); var Drive: PDrive; BitmapTmp: TBitmap; begin if (aRow = FixedRows) and (DummyRows > 0) then // Don't draw the dummy row. Exit else if (aCol = 0) and (aRow >= LowestRow) then begin inherited; // Draw drive icon in the first column. Drive := FDrivesList.Items[GetDriveIndexByRow(aRow)]; // get disk icon BitmapTmp := PixMapManager.GetDriveIcon(Drive, FDriveIconSize, Self.Color); if Assigned(BitmapTmp) then begin // Center icon in the cell. aRect.Left := aRect.Left + (ColWidths[aCol] - FDriveIconSize) div 2; aRect.Top := aRect.Top + (RowHeights[aRow] - FDriveIconSize) div 2; Canvas.Draw(aRect.Left, aRect.Top, BitmapTmp); FreeAndNil(BitmapTmp); end; end else begin inherited; // Draw vertical lines separating cells, but only in columns other than first. with Canvas, aRect do begin MoveTo(Right - 1, Top); LineTo(Right - 1, Bottom); end; end; end; procedure TDrivesListPopup.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ACol, ARow: Integer; begin // Totally override MouseDown (don't call inherited). if (X < 0) or (Y < 0) or (X >= Width) or (Y >= Height) then Close else begin MouseToCell(X, Y, ACol, ARow); if (ACol < 0) or (ARow < 0) then Close else begin case Button of mbLeft: SelectDrive(GetDriveIndexByRow(ARow)); mbRight: ShowContextMenu(GetDriveIndexByRow(ARow), X, Y); end; end; end; end; procedure TDrivesListPopup.MouseMove(Shift: TShiftState; X, Y: Integer); var ACol, ARow: Integer; begin // Totally override MouseMove (don't call inherited). if (X < 0) or (Y < 0) or (X >= Width) or (Y >= Height) then Exit; MouseToCell(X, Y, ACol, ARow); if (ACol >= 0) and (ARow >= 0) then Row := ARow; end; procedure TDrivesListPopup.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ACol, ARow: Integer; begin // Totally override MouseUp (don't call inherited). MouseToCell(X, Y, ACol, ARow); if (X < 0) or (Y < 0) or (X >= Width) or (Y >= Height) or (ACol < 0) or (ARow < 0) then Close; end; procedure TDrivesListPopup.Paint; var ARect: TRect; begin {$IFDEF LCLQT} // In QT Frame3d draws filled rectangle, so it must be drawn before // or it would overwrite all the painting done below. ARect := Classes.Rect(0, 0, Width, Height); Canvas.Frame3d(ARect, 1, bvRaised); {$ENDIF} inherited Paint; {$IFNDEF LCLQT} // This draws empty frame rectangle. ARect := Classes.Rect(0, 0, Width, Height); Canvas.Frame3d(ARect, 1, bvRaised); {$ENDIF} end; procedure TDrivesListPopup.SelectCellEvent(Sender: TObject; aCol, aRow: Integer; var CanSelect: Boolean); begin // Don't allow selecting dummy row. if (not FAllowSelectDummyRow) and (DummyRows > 0) then CanSelect := aRow > FixedRows else CanSelect := True; end; procedure TDrivesListPopup.EnterEvent(Sender: TObject); begin // Mouse capture is needed for detecting when mouse is clicked outside the control. // This also recaptures mouse if user switched to another application and back. MouseCapture := True; end; procedure TDrivesListPopup.ExitEvent(Sender: TObject); begin Close; end; procedure TDrivesListPopup.KeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState); var Rect: TRect; begin case Key of VK_HOME, VK_PRIOR: begin Row := LowestRow; Key := 0; end; VK_END, VK_NEXT: begin Row := HighestRow; Key := 0; end; VK_UP, VK_LEFT: begin if Row > LowestRow then Row := Row - 1 // If dummy row selected then select the last row. else if Row = FixedRows then Row := HighestRow; Key := 0; end; VK_DOWN, VK_RIGHT: begin if Row < HighestRow then Row := Row + 1; Key := 0; end; VK_RETURN, VK_SELECT, VK_SPACE: begin SelectDrive(GetDriveIndexByRow(Row)); Key := 0; end; VK_ESCAPE: begin Close; Key := 0; end; VK_APPS: begin Rect := CellRect(2, Row); ShowContextMenu(GetDriveIndexByRow(Row), Rect.Left, Rect.Top); Key := 0; end; {$IFDEF ForceVirtualKeysShortcuts} VK_0..VK_9, VK_A..VK_Z: begin if (CheckShortcut(TUTF8Char(Char(Key)))) then Key := 0; end; {$ENDIF} end; end; procedure TDrivesListPopup.KeyPressEvent(Sender: TObject; var Key: Char); begin if CheckShortcut(TUTF8Char(Key)) then Key := #0; end; {$IFNDEF ForceVirtualKeysShortcuts} procedure TDrivesListPopup.UTF8KeyPressEvent(Sender: TObject; var UTF8Key: TUTF8Char); begin if CheckShortcut(UTF8Key) then UTF8Key := ''; end; {$ENDIF} procedure TDrivesListPopup.SelectDrive(ADriveIndex: Integer); begin if (ADriveIndex >= 0) and (ADriveIndex < DrivesCount) then begin MouseCapture := False; DoDriveSelected(ADriveIndex); Close; end; end; procedure TDrivesListPopup.DoDriveSelected(ADriveIndex: Integer); begin if Assigned(FOnDriveSelected) then FOnDriveSelected(Self, ADriveIndex, FPanel); end; procedure TDrivesListPopup.ShowContextMenu(ADriveIndex: Integer; X, Y: Integer); var pt: TPoint; begin if (ADriveIndex >= 0) and (ADriveIndex < FDrivesList.Count) then begin pt.X := X; pt.Y := Y; pt := ClientToScreen(pt); // Context menu usually captures mouse so we have to disable ours. MouseCapture := False; ShowDriveContextMenu(Self, FDrivesList[ADriveIndex], pt.X, pt.Y, @ContextMenuClosed); end; end; procedure TDrivesListPopup.ContextMenuClosed(Sender: TObject); begin MouseCapture := True; end; function TDrivesListPopup.CheckShortcut(AShortcut: TUTF8Char): Boolean; var i: Integer; begin {$IFDEF FileCaseInsensitive} AShortCut := UpperCase(AShortcut); {$ENDIF} for i := 0 to Length(FShortCuts) - 1 do begin if FShortCuts[i] = AShortcut then begin SelectDrive(i); Exit(True); end; end; Result := False; end; procedure TDrivesListPopup.Close; begin MouseCapture := False; Visible := False; if Assigned(FOnClose) then FOnClose(Self); end; procedure TDrivesListPopup.UpdateCells; var I, RowNr : Integer; FreeSize, TotalSize: Int64; Drive: PDrive; begin for I := 0 to FDrivesList.Count - 1 do begin Drive := FDrivesList[I]; RowNr := LowestRow + I; if Length(Drive^.DisplayName) > 0 then begin Cells[1, RowNr] := Drive^.DisplayName; {$IFDEF FileCaseInsensitive} FShortCuts[I] := UTF8Copy(UpperCase(Drive^.DisplayName), 1, 1); {$ELSE} FShortCuts[I] := UTF8Copy(Drive^.DisplayName, 1, 1); {$ENDIF} end else begin Cells[1, RowNr] := Drive^.Path; FShortCuts[I] := ''; end; Cells[2, RowNr] := GetDriveLabelOrStatus(Drive); Cells[3, RowNr] := Drive^.FileSystem; // Display free space only for some drives // (removable, network, etc. may be slow). if (Drive^.DriveType in [dtHardDisk, dtOptical, dtRamDisk, dtRemovableUsb]) and IsAvailable(Drive, False) and GetDiskFreeSpace(Drive^.Path, FreeSize, TotalSize) then begin Cells[4, RowNr] := Format('%s/%s', [cnvFormatFileSize(FreeSize, uoscHeader), cnvFormatFileSize(TotalSize, uoscHeader)]) end else if (Drive^.DriveSize > 0) then begin Cells[4, RowNr] := cnvFormatFileSize(Drive^.DriveSize, uoscHeader); end end; // for end; procedure TDrivesListPopup.UpdateSize; var I : Integer; w, h: Integer; begin // Needed for autosizing to work before the control is visible. HandleNeeded; AutoSizeColumns; // Add some space to the icon column. ColWidths[0] := FDriveIconSize + 8; // Add some space to other columns. for I := 1 to ColCount - 1 do ColWidths[I] := ColWidths[I] + 4; w := GridWidth; h := GridHeight; if DummyRows > 0 then Inc(h, RowHeights[FixedRows] + GridLineWidth); Width := w; Height := h; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/udsxmodule.pas�����������������������������������������������������������������0000644�0001750�0000144�00000024403�14743153644�016276� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- (DSX) Search plugin API implementation. DSX - Double commander Search eXtentions. Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2008-2018 Alexander Koblov (alexx2000@mail.ru) 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 } unit uDsxModule; {$mode objfpc}{$H+} interface uses Classes, SysUtils, dynlibs, LCLProc, DsxPlugin, DCClassesUtf8, uDCUtils, DCXmlConfig; type { TDsxModule } TDsxModule = class protected SStartSearch: TSStartSearch; SStopSearch: TSStopSearch; SAddFileProc: TSAddFileProc; SUpdateStatusProc: TSUpdateStatusProc; SInit: TSInit; SFinalize: TSFinalize; private FPluginNr: integer; FModuleHandle: TLibHandle; // Handle to .DLL or .so function GIsLoaded: boolean; public Name: string; FileName: string; Descr: string; //--------------------- constructor Create; destructor Destroy; override; //--------------------- function LoadModule: boolean; procedure UnloadModule; //--------------------- function CallInit(pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): integer; procedure CallStartSearch(SearchRec: TDsxSearchRecord); procedure CallStopSearch; procedure CallFinalize; //--------------------- property IsLoaded: boolean read GIsLoaded; property ModuleHandle: TLibHandle read FModuleHandle write FModuleHandle; end; { TDSXModuleList } TDSXModuleList = class private Flist: TStringList; function GetCount: integer; public //--------------------- constructor Create; destructor Destroy; override; //--------------------- procedure Clear; procedure Exchange(Index1, Index2: Integer); procedure Move(CurIndex, NewIndex: Integer); procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload; function ComputeSignature(seed: dword): dword; procedure DeleteItem(Index: integer); //--------------------- function Add(Item: TDSXModule): integer; overload; function Add(FileName: string): integer; overload; function Add(AName, FileName, Descr: string): integer; overload; //--------------------- procedure Assign(OtherList: TDSXModuleList); //--------------------- function IsLoaded(AName: string): boolean; overload; function IsLoaded(Index: integer): boolean; overload; function LoadModule(AName: string): boolean; overload; function LoadModule(Index: integer): boolean; overload; //--------------------- function GetDSXModule(Index: integer): TDSXModule; overload; function GetDSXModule(AName: string): TDSXModule; overload; //--------------------- property Count: integer read GetCount; end; implementation uses //Lazarus, Free-Pascal, etc. //DC DCOSUtils, uDebug, uGlobs, uGlobsPaths, uComponentsSignature; const DsxIniFileName = 'dsx.ini'; { TDsxModule } function TDsxModule.GIsLoaded: boolean; begin Result := FModuleHandle <> 0; end; constructor TDsxModule.Create; begin FModuleHandle := 0; inherited Create; end; destructor TDsxModule.Destroy; begin if GIsLoaded then UnloadModule; inherited Destroy; end; function TDsxModule.LoadModule: boolean; begin FModuleHandle := mbLoadLibrary(mbExpandFileName(Self.FileName)); Result := (FModuleHandle <> 0); if FModuleHandle = 0 then exit; SStopSearch := TSStopSearch(GetProcAddress(FModuleHandle, 'StopSearch')); SStartSearch := TSStartSearch(GetProcAddress(FModuleHandle, 'StartSearch')); SInit := TSInit(GetProcAddress(FModuleHandle, 'Init')); SFinalize := TSFinalize(GetProcAddress(FModuleHandle, 'Finalize')); end; procedure TDsxModule.UnloadModule; begin if Assigned(SFinalize) then SFinalize(FPluginNr); {$IF (not DEFINED(LINUX)) or ((FPC_VERSION > 2) or ((FPC_VERSION=2) and (FPC_RELEASE >= 5)))} if FModuleHandle <> 0 then FreeLibrary(FModuleHandle); {$ENDIF} FModuleHandle := 0; SStartSearch := nil; SStopSearch := nil; SInit := nil; SFinalize := nil; end; function TDsxModule.CallInit(pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): integer; var dps: TDsxDefaultParamStruct; begin if Assigned(SInit) then begin dps.DefaultIniName := gpCfgDir + DsxIniFileName; dps.PluginInterfaceVersionHi := 0; dps.PluginInterfaceVersionLow := 10; dps.size := SizeOf(TDsxDefaultParamStruct); FPluginNr := Sinit(@dps, pAddFileProc, pUpdateStatus); Result := FPluginNr; end; end; procedure TDsxModule.CallStartSearch(SearchRec: TDsxSearchRecord); begin if Assigned(SStartSearch) then SStartSearch(FPluginNr, @SearchRec); end; procedure TDsxModule.CallStopSearch; begin if Assigned(SStopSearch) then SStopSearch(FPluginNr); end; procedure TDsxModule.CallFinalize; begin if Assigned(SFinalize) then SFinalize(FPluginNr); end; { TDSXModuleList } function TDSXModuleList.GetCount: integer; begin if Assigned(Flist) then Result := Flist.Count else Result := 0; end; constructor TDSXModuleList.Create; begin Flist := TStringList.Create; end; destructor TDSXModuleList.Destroy; begin Clear; FreeAndNil(Flist); inherited Destroy; end; procedure TDSXModuleList.Clear; begin while Flist.Count > 0 do begin TDSXModule(Flist.Objects[0]).Free; Flist.Delete(0); end; end; procedure TDSXModuleList.Exchange(Index1, Index2: Integer); begin FList.Exchange(Index1, Index2); end; procedure TDSXModuleList.Move(CurIndex, NewIndex: Integer); begin FList.Move(CurIndex, NewIndex); end; procedure TDSXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode); var AName, APath: String; ADsxModule: TDSXModule; begin Clear; ANode := ANode.FindNode('DsxPlugins'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('DsxPlugin') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', AName) and AConfig.TryGetValue(ANode, 'Path', APath) then begin ADsxModule := TDsxModule.Create; Flist.AddObject(UpCase(AName), ADsxModule); ADsxModule.Name := AName; ADsxModule.FileName := APath; ADsxModule.Descr := AConfig.GetValue(ANode, 'Description', ''); end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; end; end; procedure TDSXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode); var i: Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'DsxPlugins', True); AConfig.ClearNode(ANode); for i := 0 to Flist.Count - 1 do begin SubNode := AConfig.AddNode(ANode, 'DsxPlugin'); AConfig.AddValue(SubNode, 'Name', TDSXModule(Flist.Objects[I]).Name); AConfig.AddValue(SubNode, 'Path', TDSXModule(Flist.Objects[I]).FileName); AConfig.AddValue(SubNode, 'Description', TDSXModule(Flist.Objects[I]).Descr); end; end; { TDSXModuleList.ComputeSignature } function TDSXModuleList.ComputeSignature(seed: dword): dword; var iIndex: integer; begin result := seed; for iIndex := 0 to pred(Count) do begin result := ComputeSignatureString(result, TDSXModule(Flist.Objects[iIndex]).Name); result := ComputeSignatureString(result, TDSXModule(Flist.Objects[iIndex]).FileName); result := ComputeSignatureString(result, TDSXModule(Flist.Objects[iIndex]).Descr); end; end; procedure TDSXModuleList.DeleteItem(Index: integer); begin if (Index > -1) and (Index < Flist.Count) then begin TDSXModule(Flist.Objects[Index]).Free; Flist.Delete(Index); end; end; function TDSXModuleList.Add(Item: TDSXModule): integer; begin Result := Flist.AddObject(UpCase(item.Name), Item); end; function TDSXModuleList.Add(FileName: string): integer; var s: string; begin s := ExtractFileName(FileName); if pos('.', s) > 0 then Delete(s, pos('.', s), length(s)); Result := Flist.AddObject(UpCase(s), TDSXModule.Create); TDSXModule(Flist.Objects[Result]).Name := s; TDSXModule(Flist.Objects[Result]).FileName := FileName; end; function TDSXModuleList.Add(AName, FileName, Descr: string): integer; begin Result := Flist.AddObject(UpCase(AName), TDSXModule.Create); TDSXModule(Flist.Objects[Result]).Name := AName; TDSXModule(Flist.Objects[Result]).Descr := Descr; TDSXModule(Flist.Objects[Result]).FileName := FileName; end; procedure TDSXModuleList.Assign(OtherList: TDSXModuleList); var i: Integer; begin Clear; for i := 0 to OtherList.Flist.Count - 1 do begin with TDSXModule(OtherList.Flist.Objects[I]) do Add(Name, FileName, Descr); end; end; function TDSXModuleList.IsLoaded(AName: string): boolean; var x: integer; begin x := Flist.IndexOf(AName); if x = -1 then Result := False else begin Result := GetDSXModule(x).IsLoaded; end; end; function TDSXModuleList.IsLoaded(Index: integer): boolean; begin Result := GetDSXModule(Index).IsLoaded; end; function TDSXModuleList.LoadModule(AName: string): boolean; var x: integer; begin x := Flist.IndexOf(UpCase(AName)); if x = -1 then Result := False else begin Result := GetDSXModule(x).LoadModule; end; end; function TDSXModuleList.LoadModule(Index: integer): boolean; begin Result := GetDSXModule(Index).LoadModule; end; function TDSXModuleList.GetDSXModule(Index: integer): TDSXModule; begin Result := TDSXModule(Flist.Objects[Index]); end; function TDSXModuleList.GetDSXModule(AName: string): TDSXModule; var tmp: integer; begin tmp := Flist.IndexOf(upcase(AName)); if tmp > -1 then Result := TDSXModule(Flist.Objects[tmp]); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uexceptions.pas����������������������������������������������������������������0000644�0001750�0000144�00000014127�14743153644�016455� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uExceptions; {$mode objfpc}{$H+} interface uses Classes, SysUtils; function ExceptionToString: String; procedure WriteExceptionToFile(const aFileName: String; const ExceptionText: String = ''); procedure WriteExceptionToErrorFile(const ExceptionText: String = ''); inline; procedure ShowExceptionDialog(const ExceptionText: String = ''); procedure ShowException(e: Exception); {en Log exception to file, show on console and show message dialog. Can be called from other threads. } procedure HandleException(e: Exception; AThread: TThread = nil); implementation uses Forms, Controls, Dialogs, LCLProc, LCLStrConsts, syncobjs, uDebug, uLng, uGlobs, uDCVersion, DCOSUtils, LazUTF8, DCConvertEncoding; type THandleException = class private FHandleExceptionLock: TCriticalSection; FHandleExceptionMessage: String; FHandleExceptionBackTrace: String; procedure ShowException; public constructor Create; reintroduce; destructor Destroy; override; procedure HandleException(e: Exception; AThread: TThread = nil); end; var HandleExceptionObj: THandleException; function ExceptionToString: String; var FrameCount: Integer; FrameNumber: Integer; Frames: PPointer; begin Result := 'Unhandled exception:'; if Assigned(ExceptObject) and (ExceptObject is Exception) then begin Result := Result + ' ' + Exception(ExceptObject).ClassName + ': ' + Exception(ExceptObject).Message; end; Result := Result + LineEnding + ' Stack trace:' + LineEnding + BackTraceStrFunc(ExceptAddr) + LineEnding; FrameCount := ExceptFrameCount; Frames := ExceptFrames; for FrameNumber := 0 to FrameCount - 1 do Result := Result + BackTraceStrFunc(Frames[FrameNumber]) + LineEnding; end; procedure WriteExceptionToFile(const aFileName: String; const ExceptionText: String); var f: System.Text; begin if (aFileName <> EmptyStr) and not mbDirectoryExists(aFileName) then begin AssignFile(f, UTF8ToSys(aFileName)); {$PUSH}{$I-} if not mbFileExists(aFileName) then Rewrite(f) else if mbFileAccess(aFileName, fmOpenWrite or fmShareDenyNone) then Append(f); {$POP} if (TextRec(f).mode <> fmClosed) and (IOResult = 0) then begin WriteLn(f, '--------------- ', FormatDateTime('dd-mm-yyyy, hh:nn:ss', SysUtils.Now), ' ---------------'); WriteLn(f, '| DC v', dcVersion, ' Rev. ', dcRevision, ' -- ', TargetCPU + '-' + TargetOS + '-' + TargetWS); if WSVersion <> EmptyStr then Write(f, '| ', OSVersion, ' -- ', WSVersion) else Write(f, '| ', OSVersion); WriteLn(f, ' | PID ', GetProcessID); if ExceptionText = EmptyStr then begin if Assigned(ExceptObject) and (ExceptObject is Exception) then WriteLn(f, 'Unhandled exception: ', Exception(ExceptObject).ClassName, ': ', Exception(ExceptObject).Message) else WriteLn(f, 'Unhandled exception'); WriteLn(f, ' Stack trace:'); System.DumpExceptionBackTrace(f); end else WriteLn(f, ExceptionText); // Make one empty line. WriteLn(f); CloseFile(f); end; end; end; procedure WriteExceptionToErrorFile(const ExceptionText: String = ''); begin WriteExceptionToFile(gErrorFile, ExceptionText); end; procedure ShowExceptionDialog(const ExceptionText: String = ''); // Based on TApplication.ShowException. var Msg: string; MsgResult: Integer; begin if AppNoExceptionMessages in Application.Flags then exit; if ExceptionText = EmptyStr then begin if Assigned(ExceptObject) and (ExceptObject is Exception) then Msg := Exception(ExceptObject).Message else Msg := ''; end else Msg := ExceptionText; if FindInvalidUTF8Codepoint(PChar(Msg), Length(Msg), False) > 0 then Msg := CeSysToUtf8(Msg); if (Msg <> '') and (Msg[length(Msg)] = LineEnding) then Delete(Msg, Length(Msg), 1); with Application do if (not Terminated) and (Application <> nil) and (AppInitialized in Flags) then begin DisableIdleHandler; try MsgResult := MessageDlg( Application.Title + ' - ' + rsMtError, rsMtError + ':' + LineEnding + Msg + LineEnding + LineEnding + Format(rsUnhandledExceptionMessage, [LineEnding + gErrorFile + LineEnding + LineEnding, StringReplace(rsMbIgnore, '&', '', [rfReplaceAll]), StringReplace(rsMbAbort, '&', '', [rfReplaceAll])]), mtError, [mbIgnore, mbAbort], 0, mbIgnore); finally EnableIdleHandler; end; if MsgResult = mrAbort then begin Flags := Flags + [AppNoExceptionMessages]; Halt; end; end; end; procedure ShowException(e: Exception); begin MessageDlg(Application.Title, rsMsgLogError + LineEnding + e.Message, mtError, [mbOK], 0); end; procedure HandleException(e: Exception; AThread: TThread); begin HandleExceptionObj.HandleException(e, AThread); end; constructor THandleException.Create; begin FHandleExceptionLock := TCriticalSection.Create; end; destructor THandleException.Destroy; begin inherited; FreeAndNil(FHandleExceptionLock); end; procedure THandleException.HandleException(e: Exception; AThread: TThread); var BackTrace: String; begin if MainThreadID = GetCurrentThreadId then begin BackTrace := ExceptionToString; DCDebug(BackTrace); WriteExceptionToErrorFile(BackTrace); ShowExceptionDialog(e.Message); end else begin FHandleExceptionLock.Acquire; try FHandleExceptionMessage := e.Message; FHandleExceptionBackTrace := ExceptionToString; if FHandleExceptionBackTrace <> EmptyStr then DCDebug(FHandleExceptionBackTrace); TThread.Synchronize(AThread, @ShowException); finally FHandleExceptionLock.Release; end; end; end; procedure THandleException.ShowException; begin WriteExceptionToErrorFile(FHandleExceptionBackTrace); ShowExceptionDialog(FHandleExceptionMessage); end; initialization HandleExceptionObj := THandleException.Create; finalization FreeAndNil(HandleExceptionObj); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uexifreader.pas����������������������������������������������������������������0000644�0001750�0000144�00000020417�14743153644�016411� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple exchangeable image file format reader Copyright (C) 2016-2024 Alexander Koblov (alexx2000@mail.ru) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } unit uExifReader; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StreamEx; type { TTag } TTag = packed record ID : UInt16; // Tag number Typ : UInt16; // Tag type Count : UInt32; // Tag length Offset : UInt32; // Offset / Value end; { TExifReader } TExifReader = class(TMemoryStream) private FOffset: Int64; FSwap: Boolean; protected FMake: String; FModel: String; FImageWidth: UInt16; FImageHeight: UInt16; FOrientation: UInt16; FDateTimeOriginal: TDateTime; private procedure Reset; function ReadString(Offset, Count: Int32): String; function ReadDateTime(Offset, Count: Int32): TDateTime; procedure ReadTag(var ATag: TTag); function DoImageFileDirectory: Boolean; public function LoadFromFile(const FileName: String): Boolean; property Make: String read FMake; property Model: String read FModel; property ImageWidth: UInt16 read FImageWidth; property ImageHeight: UInt16 read FImageHeight; property Orientation: UInt16 read FOrientation; property DateTimeOriginal: TDateTime read FDateTimeOriginal; end; const cMake = 'Manufacturer'; cModel = 'Camera model'; cImageWidth = 'Width'; cImageHeight = 'Height'; cOrientation = 'Orientation'; cDateTimeOriginal = 'Date taken'; resourcestring rsMake = cMake; rsModel = cModel; rsImageWidth = cImageWidth; rsImageHeight = cImageHeight; rsOrientation = cOrientation; rsDateTimeOriginal = cDateTimeOriginal; implementation uses Math, DCClassesUtf8; { TExifReader } procedure TExifReader.Reset; begin Clear; FImageWidth:= 0; FImageHeight:= 0; FOrientation:= 0; FMake:= EmptyStr; FModel:= EmptyStr; FDateTimeOriginal:= 0; end; function TExifReader.ReadString(Offset, Count: Int32): String; var AOffset: Int64; begin if Count <= 4 then Result:= PAnsiChar(@Offset) else begin AOffset:= Self.Seek(0, soCurrent); Self.Seek(Offset + FOffset, soBeginning); SetLength(Result, Count); Self.ReadBuffer(Result[1], Count); Result:= PAnsiChar(Result); Self.Seek(AOffset, soBeginning); end; end; function TExifReader.ReadDateTime(Offset, Count: Int32): TDateTime; var S: String; SystemTime: TSystemTime; begin S:= ReadString(Offset, Count); try SystemTime.Millisecond:= 0; // Data format is "YYYY:MM:DD HH:MM:SS" SystemTime.Year:= StrToDWord(Copy(S, 1, 4)); SystemTime.Month:= StrToDWord(Copy(S, 6, 2)); SystemTime.Day:= StrToDWord(Copy(S, 9, 2)); SystemTime.Hour:= StrToDWord(Copy(S, 12, 2)); SystemTime.Minute:= StrToDWord(Copy(S, 15, 2)); SystemTime.Second:= StrToDWord(Copy(S, 18, 2)); Result:= SystemTimeToDateTime(SystemTime); except Result:= 0; end; end; procedure TExifReader.ReadTag(var ATag: TTag); begin Self.ReadBuffer(ATag, SizeOf(TTag)); if FSwap = False then begin case ATag.Typ of 1, 6: ATag.Offset:= UInt8(ATag.Offset); 3, 8: ATag.Offset:= UInt16(ATag.Offset); end; end else begin ATag.ID:= SwapEndian(ATag.ID); ATag.Typ:= SwapEndian(ATag.Typ); ATag.Count:= SwapEndian(ATag.Count); case ATag.Typ of 1, 6: ATag.Offset:= UInt8(ATag.Offset); 3, 8: ATag.Offset:= SwapEndian(UInt16(ATag.Offset)); else if (ATag.Typ <> 2) or (ATag.Count > 4) then ATag.Offset:= SwapEndian(ATag.Offset); end; end; end; function TExifReader.DoImageFileDirectory: Boolean; var I: Int32; ATag: TTag; ACount: UInt16; AOffset: Int32 = 0; begin ACount:= Self.ReadWord; if FSwap then ACount:= SwapEndian(ACount); for I:= 1 to ACount do begin ReadTag(ATag); case ATag.ID of $100: // Image width begin FImageWidth := ATag.Offset; end; $101: // Image height begin FImageHeight := ATag.Offset; end; $010f: // Shows manufacturer of digicam begin FMake:= ReadString(ATag.Offset, ATag.Count); end; $0110: // Shows model number of digicam begin FModel:= ReadString(ATag.Offset, ATag.Count); end; $0112: // The orientation of the camera relative to the scene begin FOrientation:= ATag.Offset; end; $8769: // Exif IFD Pointer begin AOffset:= ATag.Offset; end; end; end; Result:= ACount > 0; if AOffset > 0 then begin Self.Seek(FOffset + AOffset, soBeginning); ACount:= Self.ReadWord; if FSwap then ACount:= SwapEndian(ACount); for I:= 1 to ACount do begin ReadTag(ATag); case ATag.ID of $9003: // Date/Time of original image taken begin FDateTimeOriginal:= ReadDateTime(ATag.Offset, ATag.Count); end; // Image pixel width $A002: if FImageWidth = 0 then FImageWidth := ATag.Offset; // Image pixel height $A003: if FImageHeight = 0 then FImageHeight := ATag.Offset; end; end; end; end; function TExifReader.LoadFromFile(const FileName: String): Boolean; const BUFFER_SIZE = 196608; var P: UInt16; ASize: UInt16; Offset: UInt32; AFile: TFileStreamEx; Magic: array [0..5] of AnsiChar; begin Reset; try AFile:= TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try Self.SetSize(Min(AFile.Size, BUFFER_SIZE)); AFile.ReadBuffer(Self.Memory^, Self.Size); finally AFile.Free; end; except Exit(False); end; try if (Self.ReadByte <> $FF) then Exit(False); if (Self.ReadByte <> $D8) then Exit(False); repeat if Self.ReadByte = $FF then begin case Self.ReadByte of $E1: // Exif Marker begin Break; end; $D9: // End Of Image (EOI) begin Exit(False); end; else begin // Unknown section, skip P:= Self.ReadWordBE; Self.Seek(Int64(P) - 2, soCurrent); end; end; end; until False; // Exif data size ASize:= Self.ReadWordBE; // Exif magic string Self.Read(Magic, SizeOf(Magic)); if (CompareByte(Magic, 'Exif'#0#0, SizeOf(Magic)) <> 0) then Exit(False); FOffset:= Self.Seek(0, soCurrent); // Byte order case Self.ReadWord of $4949: FSwap:= {$IF DEFINED(ENDIAN_BIG)} True {$ELSE} False {$ENDIF}; // little-endian $4D4D: FSwap:= {$IF DEFINED(ENDIAN_LITTLE)} True {$ELSE} False {$ENDIF}; // big-endian else Exit(False); end; // Magic word P:= Self.ReadWord; if (P <> $002A) and (P <> $2A00) then Exit(False); // Offset to first IFD Offset:= Self.ReadDWord; if FSwap then Offset:= SwapEndian(Offset); // Go to Image file directory Self.Seek(Offset - 8, soCurrent); Result:= DoImageFileDirectory; except Reset; Result:= False; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uexifwdx.pas�������������������������������������������������������������������0000644�0001750�0000144�00000011525�14743153644�015751� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Simple exif-wdx plugin. Copyright (C) 2016-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uExifWdx; {$mode delphi} interface uses Classes, SysUtils, WdxPlugin, uWDXModule, uExifReader; type { TExifWdx } TExifWdx = class(TEmbeddedWDX) private FFileName: String; FExif: TExifReader; procedure GetData(const FileName: String); protected function GetAName: String; override; public //--------------------- constructor Create; override; destructor Destroy; override; //------------------------------------------------------ procedure CallContentGetSupportedField; override; procedure CallContentSetDefaultParams; override; procedure CallContentStopGetValue(FileName: String); override; //--------------------- function CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; override; function CallContentGetDetectString: String; override; function CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; overload; override; function CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; overload; override; function CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; override; //------------------------------------------------------ end; implementation { TExifWdx } procedure TExifWdx.GetData(const FileName: String); begin if (FFileName <> FileName) then begin FFileName:= FileName; FExif.LoadFromFile(FileName); end; end; function TExifWdx.GetAName: String; begin Result:= '<Exif>'; end; constructor TExifWdx.Create; begin inherited Create; FExif:= TExifReader.Create; DetectStr:= CallContentGetDetectString; end; destructor TExifWdx.Destroy; begin FExif.Free; inherited Destroy; end; procedure TExifWdx.CallContentGetSupportedField; begin AddField(cMake, rsMake, ft_string); AddField(cModel, rsModel, ft_string); AddField(cImageWidth, rsImageWidth, ft_numeric_32); AddField(cImageHeight, rsImageHeight, ft_numeric_32); AddField(cOrientation, rsOrientation, ft_numeric_32); AddField(cDateTimeOriginal, rsDateTimeOriginal, ft_datetime); end; procedure TExifWdx.CallContentSetDefaultParams; begin end; procedure TExifWdx.CallContentStopGetValue(FileName: String); begin end; function TExifWdx.CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; begin Result:= False; end; function TExifWdx.CallContentGetDetectString: String; begin Result:= '(EXT="JPG") | (EXT="JPEG")'; end; function TExifWdx.CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; begin Result:= Unassigned; EnterCriticalSection(FMutex); try GetData(FileName); case FieldIndex of 0: if Length(FExif.Make) > 0 then Result:= FExif.Make; 1: if Length(FExif.Model) > 0 then Result:= FExif.Model; 2: if FExif.ImageWidth > 0 then Result:= FExif.ImageWidth; 3: if FExif.ImageHeight > 0 then Result:= FExif.ImageHeight; 4: if FExif.Orientation > 0 then Result:= FExif.Orientation; 5: if FExif.DateTimeOriginal > 0 then Result:= FExif.DateTimeOriginal; end; finally LeaveCriticalSection(FMutex); end; end; function TExifWdx.CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; begin Result:= EmptyStr; EnterCriticalSection(FMutex); try GetData(FileName); case FieldIndex of 0: Result:= FExif.Make; 1: Result:= FExif.Model; 2: if FExif.ImageWidth > 0 then Result:= IntToStr(FExif.ImageWidth); 3: if FExif.ImageHeight > 0 then Result:= IntToStr(FExif.ImageHeight); 4: if FExif.Orientation > 0 then Result:= IntToStr(FExif.Orientation); 5: if FExif.DateTimeOriginal > 0 then Result:= DateTimeToStr(FExif.DateTimeOriginal); end; finally LeaveCriticalSection(FMutex); end; end; function TExifWdx.CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; begin Result:= 0; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uextension.pas�����������������������������������������������������������������0000644�0001750�0000144�00000006025�14743153644�016306� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Extension API implementation Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uExtension; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, Extension, Translations; type { TDcxModule } TDcxModule = class protected FPOFile: TPOFile; FModulePath: String; FModuleHandle: TLibHandle; public destructor Destroy; override; procedure InitializeExtension(StartupInfo: PExtensionStartupInfo); end; implementation uses Math, LazFileUtils, DCOSUtils, fDialogBox, uGlobs, uGlobsPaths; function Translate(Translation: Pointer; Identifier, Original: PAnsiChar; Output: PAnsiChar; OutLen: Integer): Integer; dcpcall; var AText: String; POFile: TPOFile absolute Translation; begin if (POFile = nil) then begin Result:= 0; Output^:= #0; end else begin AText:= POFile.Translate(Identifier, Original); StrPLCopy(Output, AText, OutLen - 1); Result:= Min(Length(AText), OutLen - 1); end; end; { TDcxModule } destructor TDcxModule.Destroy; begin inherited Destroy; FPOFile.Free; end; procedure TDcxModule.InitializeExtension(StartupInfo: PExtensionStartupInfo); const VERSION_API = 4; var Language: String; AFileName, APath: String; begin FillByte(StartupInfo^, SizeOf(TExtensionStartupInfo), 0); AFileName:= FModulePath; APath:= ExtractFilePath(AFileName) + 'language' + PathDelim; Language:= ExtractFileExt(ExtractFileNameOnly(gPOFileName)); AFileName:= APath + ExtractFileNameOnly(AFileName) + Language + '.po'; if mbFileExists(AFileName) then FPOFile:= TPOFile.Create(AFileName); with StartupInfo^ do begin StructSize:= SizeOf(TExtensionStartupInfo); PluginDir:= ExtractFilePath(FModulePath); PluginConfDir:= gpCfgDir; InputBox:= @fDialogBox.InputBox; MessageBox:= @fDialogBox.MessageBox; DialogBoxLFM:= @fDialogBox.DialogBoxLFM; DialogBoxLRS:= @fDialogBox.DialogBoxLRS; DialogBoxLFMFile:= @fDialogBox.DialogBoxLFMFile; SendDlgMsg:= @fDialogBox.SendDlgMsg; Translation:= FPOFile; TranslateString:= @Translate; VersionAPI:= VERSION_API; MsgChoiceBox:= @fDialogBox.MsgChoiceBox; DialogBoxParam:= @fDialogBox.DialogBoxParam; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uexts.pas����������������������������������������������������������������������0000644�0001750�0000144�00000054044�14743153644�015261� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double commander ------------------------------------------------------------------------- Manager for commands associated to file extension. Copyright (C) 2008-2018 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Original comment: ---------------------------- Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz storing commands (by file extensions) } unit uExts; {$mode objfpc}{$H+} interface uses Graphics, Classes, Contnrs, uFile; type { What constitutes our basic info for the external actual action } TExtActionCommand = class FActionName: string; FCommandName: string; FParams: string; FStartPath: string; FIconIndex: integer; FIconBitmap: Graphics.TBitmap; public constructor Create(ParamActionName, ParamCommandName, ParamParams, ParamStartPath: string); destructor Destroy; override; function CloneExtAction: TExtActionCommand; property ActionName: string read FActionName write FActionName; property CommandName: string read FCommandName write FCommandName; property Params: string read FParams write FParams; property StartPath: string read FStartPath write FStartPath; property IconIndex: integer read FIconIndex write FIconIndex; property IconBitmap: Graphics.TBitmap read FIconBitmap write FIconBitmap; end; { Each file type may have more than one possible associated action ("TExtActionCommand"). This class is to hold a collection of this } TExtActionList = class(TList) private function GetExtActionCommand(Index: integer): TExtActionCommand; public constructor Create; procedure Clear; override; function Add(ExtActionCommand: TExtActionCommand): integer; procedure Insert(Index: integer; ExtActionCommand: TExtActionCommand); procedure DeleteExtActionCommand(Index: integer); property ExtActionCommand[Index: integer]: TExtActionCommand read GetExtActionCommand; end; { Class for storage actions by file extensions } TExtAction = class Name: string; //en< File type name, for example "Hyper text documents" Icon: string; //en< Path to icon IconIndex: integer; Extensions: TStringList; //en< List of extensions ActionList: TExtActionList; public constructor Create; destructor Destroy; override; function GetIconListForStorage: string; procedure SetIconListFromStorage(sStorage: string); end; { Main class for storage actions list by file extensions } TExts = class private function GetCount: integer; function GetItems(Index: integer): TExtAction; procedure LegacyLoadFromFile(const sName: string); protected FExtList: TObjectList; public constructor Create; destructor Destroy; override; procedure Clear; function AddItem(AExtAction: TExtAction): integer; procedure DeleteItem(Index: integer); procedure MoveItem(SrcIndex, DestIndex: integer); function Load: boolean; function LoadXMLFile: boolean; procedure SaveXMLFile; function GetExtActionCmd(aFile: TFile; const sActionName: string; var sCmd: string; var sParams: string; var sStartPath: string): boolean; function GetExtActions(aFile: TFile; paramActionList: TExtActionList; pIndexOfFirstPossibleFileType: PInteger = nil; bWantedAllActions: boolean = False): boolean; function ComputeSignature(Seed:dword=$00000000): dword; property Count: integer read GetCount; property Items[Index: integer]: TExtAction read GetItems; property FileType[Index: integer]: TExtAction read GetItems; end; const cMaskDefault = 'default'; cMaskFolder = 'folder'; cMaskFile = 'file'; implementation uses DCXmlConfig, uDCVersion, uGlobsPaths, uDCUtils, crc, uLng, SysUtils, uLog, DCClassesUtf8, DCOSUtils, strUtils; { TExtActionCommand.Create } constructor TExtActionCommand.Create(ParamActionName, ParamCommandName, ParamParams, ParamStartPath: string); begin inherited Create; FActionName := ParamActionName; FCommandName := ParamCommandName; FParams := ParamParams; FStartPath := ParamStartPath; FIconIndex := -1; // <--IconIndex is used only in "uShellContextMenu" to show an icon next to the command AND is filled correctly when doing "TExts.GetExtActions" FIconBitmap := nil; // <--IconBitmap is used only in "uShellContextMenu" to show an icon next to the command AND is filled correctly when doing "CreateActionSubMenu" from "uShellContextMenu" end; { TExtActionCommand.Destroy } destructor TExtActionCommand.Destroy; begin if Assigned(FIconBitmap) then FreeAndNil(FIconBitmap); inherited; end; { TExtActionCommand.CloneExtAction } function TExtActionCommand.CloneExtAction: TExtActionCommand; begin Result := TExtActionCommand.Create(self.FActionName, self.FCommandName, self.FParams, self.FStartPath); end; { TExtActionList.Create } constructor TExtActionList.Create; begin inherited Create; end; { TExtActionList.Clear } procedure TExtActionList.Clear; var i: integer; begin for i := 0 to Count - 1 do ExtActionCommand[i].Free; inherited Clear; end; { TExtActionList.Add } function TExtActionList.Add(ExtActionCommand: TExtActionCommand): integer; begin Result := inherited Add(ExtActionCommand); end; { TExtActionList.Insert } procedure TExtActionList.Insert(Index: integer; ExtActionCommand: TExtActionCommand); begin inherited Insert(Index, ExtActionCommand); end; { TExtActionList.DeleteExtActionCommand } procedure TExtActionList.DeleteExtActionCommand(Index: integer); begin ExtActionCommand[Index].Free; Delete(Index); end; { TExtActionList.GetExtActionCommand } function TExtActionList.GetExtActionCommand(Index: integer): TExtActionCommand; begin Result := TExtActionCommand(Items[Index]); end; constructor TExtAction.Create; begin inherited Create; Extensions := TStringList.Create; Extensions.CaseSensitive := False; ActionList := TExtActionList.Create; end; destructor TExtAction.Destroy; begin if Assigned(Extensions) then FreeAndNil(Extensions); if Assigned(ActionList) then FreeAndNil(ActionList); inherited; end; { TExtAction.GetIconListForStorage } function TExtAction.GetIconListForStorage: string; var iExtension: integer; begin Result := ''; if Extensions.Count = 0 then Result := rsMsgUserDidNotSetExtension else for iExtension := 0 to pred(Extensions.Count) do if Result = '' then Result := Extensions[iExtension] else Result := Result + '|' + Extensions[iExtension]; end; { TExtAction.SetIconListFromStorage } procedure TExtAction.SetIconListFromStorage(sStorage: string); var PosPipe, LastPosPipe: integer; begin LastPosPipe := 0; repeat PosPipe := posEx('|', sStorage, LastPosPipe + 1); if PosPipe <> 0 then begin Extensions.add(copy(sStorage, LastPosPipe + 1, ((PosPipe - LastPosPipe) - 1))); LastPosPipe := PosPipe; end; until PosPipe = 0; if length(sStorage) > LastPosPipe then Extensions.add(copy(sStorage, LastPosPipe + 1, (length(sStorage) - LastPosPipe))); if Extensions.Count = 0 then Extensions.Add(rsMsgUserDidNotSetExtension); end; { TExts.LegacyLoadFromFile } //We need to keep this routine to be able to load "old legacy format" of the //file associated action based on file extension that was using DC originally. procedure TExts.LegacyLoadFromFile(const sName: string); var extFile: TStringListEx; sLine, s, sExt: string; extCurrentFileType: TExtAction; I, iIndex: integer; sCommandName, sEndingPart, sCommandCmd, sParams: string; begin extFile := TStringListEx.Create; try extFile.LoadFromFile(sName); extCurrentFileType := nil; for I := 0 to extFile.Count - 1 do begin sLine := extFile.Strings[I]; sLine := Trim(sLine); if (sLine = '') or (sLine[1] = '#') then Continue; if sLine[1] = '[' then begin extCurrentFileType := TExtAction.Create; FExtList.Add(extCurrentFileType); iIndex := pos(']', sLine); if iIndex > 0 then sLine := Copy(sLine, 1, iIndex) else logWrite(Format(rsExtsClosedBracketNoFound, [sLine])); extCurrentFileType.Name:=sLine; // Just in case we don't have a name later on, let's named the file type based on the extension defined. // fill extensions list s := sLine; Delete(s, 1, 1); // Delete '[' Delete(s, Length(s), 1); // Delete ']' s := s + '|'; while Pos('|', s) <> 0 do begin iIndex := Pos('|', s); sExt := Copy(s, 1, iIndex - 1); Delete(s, 1, iIndex); extCurrentFileType.Extensions.Add(sExt); end; end // end if.. '[' else begin // this must be a command if not assigned(extCurrentFileType) then begin logWrite(Format(rsExtsCommandWithNoExt, [sLine])); Continue; end; // now set command to lowercase s := sLine; for iIndex := 1 to Length(s) do begin if s[iIndex] = '=' then Break; s[iIndex] := LowerCase(s[iIndex]); end; if Pos('name', s) = 1 then // File type name extCurrentFileType.Name := Copy(sLine, iIndex + 1, Length(sLine)) else if Pos('icon', s) = 1 then // File type icon extCurrentFileType.Icon := Copy(sLine, iIndex + 1, Length(sLine)) else // action begin sCommandName := Copy(sLine, 1, iIndex - 1); sEndingPart := Copy(sLine, iIndex + 1, Length(sLine)); try SplitCmdLineToCmdParams(sEndingPart, sCommandCmd, sParams); except sCommandCmd := '<ERROR IN CONVERSION> '+sEndingPart; //Just in case the user has something wrong in his settings, LIKE a missing ending quote... sParams := ''; end; sCommandCmd := Trim(sCommandCmd); sParams := Trim(sParams); extCurrentFileType.ActionList.Add(TExtActionCommand.Create(sCommandName, sCommandCmd, sParams, '')); end; end; end; finally extFile.Free; end; end; function TExts.GetExtActions(aFile: TFile; paramActionList: TExtActionList; pIndexOfFirstPossibleFileType: PInteger = nil; bWantedAllActions: boolean = False): boolean; var I, iActionNo: integer; sMask: string; ExtActionCommand: TExtActionCommand; begin if pIndexOfFirstPossibleFileType <> nil then pIndexOfFirstPossibleFileType^ := -1; Result := False; if aFile.IsDirectory or aFile.IsLinkToDirectory then sMask := cMaskFolder else sMask := LowerCase(aFile.Extension); if Length(sMask) <> 0 then for I := 0 to FExtList.Count - 1 do with GetItems(i) do begin if Extensions.IndexOf(sMask) >= 0 then begin if paramActionList.Count > 0 then paramActionList.Add(TExtActionCommand.Create('-', '', '', '')); for iActionNo := 0 to pred(ActionList.Count) do begin ExtActionCommand := ActionList.ExtActionCommand[iActionNo].CloneExtAction; ExtActionCommand.IconIndex := IconIndex; paramActionList.Add(ExtActionCommand); end; if pIndexOfFirstPossibleFileType <> nil then if pIndexOfFirstPossibleFileType^ = -1 then pIndexOfFirstPossibleFileType^ := I; Result := True; if not bWantedAllActions then Break; end; end; if sMask = cMaskFolder then Exit; for I := 0 to FExtList.Count - 1 do with GetItems(i) do begin if Extensions.IndexOf(cMaskFile) >= 0 then begin if paramActionList.Count > 0 then paramActionList.Add(TExtActionCommand.Create('-', '', '', '')); for iActionNo := 0 to pred(ActionList.Count) do begin ExtActionCommand := ActionList.ExtActionCommand[iActionNo].CloneExtAction; ExtActionCommand.IconIndex := IconIndex; paramActionList.Add(ExtActionCommand); end; if pIndexOfFirstPossibleFileType <> nil then if pIndexOfFirstPossibleFileType^ = -1 then pIndexOfFirstPossibleFileType^ := I; Result := True; if not bWantedAllActions then Break; end; end; end; function TExts.GetCount: integer; begin Result := FExtList.Count; end; function TExts.GetItems(Index: integer): TExtAction; begin Result := TExtAction(FExtList.Items[Index]); end; constructor TExts.Create; begin inherited Create; FExtList := TObjectList.Create; end; destructor TExts.Destroy; begin if assigned(FExtList) then FreeAndNil(FExtList); inherited; end; procedure TExts.Clear; begin FExtList.Clear; end; function TExts.AddItem(AExtAction: TExtAction): integer; begin Result := FExtList.Add(AExtAction); end; procedure TExts.DeleteItem(Index: integer); begin FExtList.Delete(Index); end; procedure TExts.MoveItem(SrcIndex, DestIndex: integer); begin FExtList.Move(SrcIndex, DestIndex); end; function TExts.GetExtActionCmd(aFile: TFile; const sActionName: string; var sCmd: string; var sParams: string; var sStartPath: string): boolean; var I: integer; sMask: string; iAction: integer; begin Result := False; sCmd := ''; sParams := ''; sStartPath := ''; if aFile.IsDirectory or aFile.IsLinkToDirectory then sMask := cMaskFolder else sMask := LowerCase(aFile.Extension); if Length(sMask) <> 0 then begin for I := 0 to FExtList.Count - 1 do with GetItems(I) do begin if Extensions.IndexOf(sMask) >= 0 then begin iAction := 0; while (iAction < ActionList.Count) and (not Result) do begin if UpperCase(ActionList.ExtActionCommand[iAction].ActionName) = UpperCase(sActionName) then begin sCmd := ActionList.ExtActionCommand[iAction].CommandName; sParams := ActionList.ExtActionCommand[iAction].Params; sStartPath := ActionList.ExtActionCommand[iAction].StartPath; Result := True; Exit; end else begin Inc(iAction); end; end; end; end; end; // if command not found then try to find default command for I := 0 to FExtList.Count - 1 do with GetItems(I) do begin if Extensions.IndexOf(cMaskDefault) >= 0 then begin iAction := 0; while (iAction < ActionList.Count) and (not Result) do begin if UpperCase(ActionList.ExtActionCommand[iAction].ActionName) = UpperCase(sActionName) then begin sCmd := ActionList.ExtActionCommand[iAction].CommandName; sParams := ActionList.ExtActionCommand[iAction].Params; sStartPath := ActionList.ExtActionCommand[iAction].StartPath; Result := True; Exit; end else begin Inc(iAction); end; end; end; end; end; { TExts.ComputeSignature } function TExts.ComputeSignature(Seed:dword): dword; var iExtType, iExtension, iAction: integer; begin Result := Seed; for iExtType := 0 to pred(Count) do begin Result := crc32(Result, @Items[iExtType].Name[1], length(Items[iExtType].Name)); if length(Items[iExtType].Icon) > 0 then Result := crc32(Result, @Items[iExtType].Icon[1], length(Items[iExtType].Icon)); for iExtension := 0 to pred(Items[iExtType].Extensions.Count) do if length(Items[iExtType].Extensions.Strings[iExtension]) > 0 then Result := crc32(Result, @Items[iExtType].Extensions.Strings[iExtension][1], length(Items[iExtType].Extensions.Strings[iExtension])); for iAction := 0 to pred(Items[iExtType].ActionList.Count) do begin if length(Items[iExtType].ActionList.ExtActionCommand[iAction].FActionName) > 0 then Result := crc32(Result, @Items[iExtType].ActionList.ExtActionCommand[iAction].FActionName[1], length(Items[iExtType].ActionList.ExtActionCommand[iAction].FActionName)); if length(Items[iExtType].ActionList.ExtActionCommand[iAction].FCommandName) > 0 then Result := crc32(Result, @Items[iExtType].ActionList.ExtActionCommand[iAction].FCommandName[1], length(Items[iExtType].ActionList.ExtActionCommand[iAction].FCommandName)); if length(Items[iExtType].ActionList.ExtActionCommand[iAction].FParams) > 0 then Result := crc32(Result, @Items[iExtType].ActionList.ExtActionCommand[iAction].FParams[1], length(Items[iExtType].ActionList.ExtActionCommand[iAction].FParams)); if length(Items[iExtType].ActionList.ExtActionCommand[iAction].FStartPath) > 0 then Result := crc32(Result, @Items[iExtType].ActionList.ExtActionCommand[iAction].FStartPath[1], length(Items[iExtType].ActionList.ExtActionCommand[iAction].FStartPath)); end; end; end; { TExts.SaveXMLFile } procedure TExts.SaveXMLFile; var ActionList: TExtActionList; iFileType, iAction: Integer; ExtXMLSettings: TXmlConfig = nil; Root, Node, SubNode, SubSubNode: TXmlNode; begin ExtXMLSettings := TXmlConfig.Create(gpCfgDir + gcfExtensionAssociation); try with ExtXMLSettings do begin Root := ExtXMLSettings.RootNode; SetAttr(Root, 'DCVersion', dcVersion); Node := FindNode(Root, 'ExtensionAssociation', True); ClearNode(Node); { Each file type has its own extensions } for iFileType := 0 to Pred(Count) do begin SubNode := AddNode(Node, 'FileType'); SetValue(SubNode, 'Name', FileType[iFileType].Name); SetValue(SubNode, 'IconFile', FileType[iFileType].Icon); SetValue(SubNode, 'ExtensionList', FileType[iFileType].GetIconListForStorage); SubNode := AddNode(SubNode, 'Actions'); ActionList := FileType[iFileType].ActionList; for iAction := 0 to Pred(ActionList.Count) do begin SubSubNode := AddNode(SubNode, 'Action'); SetValue(SubSubNode, 'Name', ActionList.ExtActionCommand[iAction].ActionName); if ActionList.ExtActionCommand[iAction].CommandName <> '' then SetValue(SubSubNode, 'Command', ActionList.ExtActionCommand[iAction].CommandName); if ActionList.ExtActionCommand[iAction].Params <> '' then SetValue(SubSubNode, 'Params', ActionList.ExtActionCommand[iAction].Params); if ActionList.ExtActionCommand[iAction].StartPath <> '' then SetValue(SubSubNode, 'StartPath', ActionList.ExtActionCommand[iAction].StartPath); end; end; end; ExtXMLSettings.Save; finally ExtXMLSettings.Free; end; end; { TExts.Load} function TExts.Load: boolean; begin Result := False; try if (mbFileExists(gpCfgDir + 'doublecmd.ext')) AND (not mbFileExists(gpCfgDir + gcfExtensionAssociation)) then begin LegacyLoadFromFile(gpCfgDir + 'doublecmd.ext'); SaveXmlFile; mbRenameFile(gpCfgDir + 'doublecmd.ext', gpCfgDir + 'doublecmd.ext.obsolete'); Result := True; end else begin Result := LoadXMLFile; end; except Result := False; end; end; { TExts.LoadXMLFile } function TExts.LoadXMLFile: boolean; var extCurrentFileType: TExtAction; ExtXMLSettings: TXmlConfig = nil; Node, SubNode, SubSubNode: TXmlNode; sName, sIconFilename, sExtensionList, sActionName, sCommandName, sParams, sStartPath: string; begin Result := False; try ExtXMLSettings := TXmlConfig.Create(gpCfgDir + gcfExtensionAssociation); try ExtXMLSettings.Load; with ExtXMLSettings do begin Node := FindNode(ExtXMLSettings.RootNode, 'ExtensionAssociation'); if Assigned(Node) then begin SubNode := Node.FirstChild; while Assigned(SubNode) do begin if SubNode.CompareName('FileType') = 0 then begin sName := ExtXMLSettings.GetValue(SubNode, 'Name', rsMsgUserDidNotSetName); if sName <> rsMsgUserDidNotSetName then begin sIconFilename := ExtXMLSettings.GetValue(SubNode, 'IconFile', ''); sExtensionList := ExtXMLSettings.GetValue(SubNode, 'ExtensionList', rsMsgUserDidNotSetExtension); extCurrentFileType := TExtAction.Create; extCurrentFileType.Name := sName; extCurrentFileType.Icon := sIconFilename; extCurrentFileType.SetIconListFromStorage(sExtensionList); SubSubNode := FindNode(SubNode, 'Actions'); if Assigned(SubSubNode) then begin SubSubNode := SubSubNode.FirstChild; while Assigned(SubSubNode) do begin if SubSubNode.CompareName('Action') = 0 then begin sActionName := ExtXMLSettings.GetValue(SubSubNode, 'Name', rsMsgUserDidNotSetName); sCommandName := ExtXMLSettings.GetValue(SubSubNode, 'Command', ''); sParams := ExtXMLSettings.GetValue(SubSubNode, 'Params', ''); sStartPath := ExtXMLSettings.GetValue(SubSubNode, 'StartPath', ''); extCurrentFileType.ActionList.Add(TExtActionCommand.Create(sActionName, sCommandName, sParams, sStartPath)); end; SubSubNode := SubSubNode.NextSibling; end; end; AddItem(extCurrentFileType); end; end; SubNode := SubNode.NextSibling; end; end; end; finally ExtXMLSettings.Free; end; Result := True; except Result := False; end; end; end. //Cleaner les >Action@//Utiliser ExtFileType comme nom au lieu de Action car pas tout de suite une action//Remplacer le Savefile by SaveXMLFile ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufavoritetabs.pas��������������������������������������������������������������0000644�0001750�0000144�00000155334�14743153644�016773� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Structure/Load/Save/Working With FavoriteTab and List of them Copyright (C) 2016-2017 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit ufavoritetabs; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, Menus, ExtCtrls, Controls, ComCtrls, //DC DCXmlConfig; const FAVORITETABS_SEPARATORSTRING: string = '···························'; // In "uMainCommands", the procedure "DoOnClickMenuJobFavoriteTabs" is called when a menu item of "FavoriteTabs" popup menu item is clicked. // Associted to the "tag" properties of the menuitem, these offset are added to "tag" to help for dispatching of action. TAGOFFSET_FAVTABS_FORSAVEOVEREXISTING = $10000; TAGOFFSET_FAVTABS_SOMETHINGELSE = $20000; // These must match with the order of "TTabConfigLocation" afew lines below. gsConfigLocationName: array[0..5] of string = ('left', 'right', 'active', 'inactive', 'both', 'none'); type { TTabsConfigLocation } // These must match with the order of "gsConfigLocationName" // Note: NEVER CHANGE THE ORDER OF THESE CONSTANTS SINCE SETTINGS SAVED ASSUMED THIS ORDER FOREVER. TTabsConfigLocation = (tclLeft, tclRight, tclActive, tclInactive, tclBoth, tclNone); TTabsFlagsAlreadyDestroyed = set of (tfadLeft, tfadRight); { TKindOfFavoriteTabsEntry } TKindOfFavoriteTabsEntry = (fte_NULL, fte_ACTUALFAVTABS, fte_SEPARATOR, fte_STARTMENU, fte_ENDMENU); { TKindFavoriteTabsMenuPopulation } TKindFavoriteTabsMenuPopulation = (ftmp_JUSTFAVTABS, ftmp_FAVTABSWITHCONFIG); { TPositionWhereToAddFavoriteTabs } TPositionWhereToAddFavoriteTabs = (afte_First, afte_Last, afte_Alphabetical); { TProcedureWhenClickMenuItem} TProcedureWhenClickOnMenuItem = procedure(Sender: TObject) of object; { TFavoriteTabs } TFavoriteTabs = class private FDispatcher: TKindOfFavoriteTabsEntry; FFavoriteTabsName: string; // Friendly name, what the user decides, see, use, breath! FDestinationForSavedLeftTabs: TTabsConfigLocation; // Configured restoration destination side for what was saved from left panel. FDestinationForSavedRightTabs: TTabsConfigLocation; // Configured restoration destination side for what was saved from right panel. FExistingTabsToKeep: TTabsConfigLocation; // Useful when we restore tabs, to determine if we keep or not the existing ones. FSaveDirHistory: boolean; // Indicate if we save the dir history or not for that setup. FUniqueID: TGUID; // Key info! This is the unique number identifying the FactoriteTabs. FGroupNumber: integer; // We won't save in the XML. Just useful run-time with the tree. public constructor Create; procedure CopyToFavoriteTabs(DestinationFavoriteTabs: TFavoriteTabs; bExactCopyWanted: boolean = True); function GuidToXMLString: string; procedure SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode); property Dispatcher: TKindOfFavoriteTabsEntry read FDispatcher write FDispatcher; property FavoriteTabsName: string read FFavoriteTabsName write FFavoriteTabsName; property DestinationForSavedLeftTabs: TTabsConfigLocation read FDestinationForSavedLeftTabs write FDestinationForSavedLeftTabs; property DestinationForSavedRightTabs: TTabsConfigLocation read FDestinationForSavedRightTabs write FDestinationForSavedRightTabs; property ExistingTabsToKeep: TTabsConfigLocation read FExistingTabsToKeep write FExistingTabsToKeep; property SaveDirHistory: boolean read FSaveDirHistory write FSaveDirHistory; property UniqueID: TGUID read FUniqueID write FUniqueID; property GroupNumber: integer read FGroupNumber write FGroupNumber; end; { TFavoriteTabsList } TFavoriteTabsList = class(TList) private FLastFavoriteTabsLoadedUniqueId: TGUID; FLastImportationStringUniqueId: TStringList; FAssociatedMainMenuItem: TMenuItem; function GetFavoriteTabs(Index: integer): TFavoriteTabs; function GetBestIndexForAlphabeticalNewFavoriteTabs(sFavoriteTabsNameToFindAPlaceFor: string): integer; procedure AddToListAndToXmlFileHeader(paramFavoriteTabs: TFavoriteTabs; AConfig: TXmlConfig; SpecifiedIndex: integer = -1); function ActualDumpFavoriteTabsListInXml(AConfig: TXmlConfig): boolean; public constructor Create; destructor Destroy; override; procedure Clear; override; function Add(FavoriteTabs: TFavoriteTabs): integer; procedure DeleteFavoriteTabs(Index: integer); procedure CopyFavoriteTabsListToFavoriteTabsList(var DestinationFavoriteTabsList: TFavoriteTabsList); function GetIndexLastFavoriteTabsLoaded: integer; function GetIndexPreviousLastFavoriteTabsLoaded: integer; function GetIndexNextLastFavoriteTabsLoaded: integer; function GetIndexForSuchUniqueID(SearchedGUID: TGUID): integer; function GetSuggestedParamsForFavoriteTabs(sAttemptedName: string; var SuggestedFavoriteTabsName: string): boolean; function ComputeSignature(Seed:dword=$00000000): dword; procedure LoadAllListFromXml; function LoadTabsFromXmlEntry(paramIndexToLoad: integer): boolean; function SaveNewEntryFavoriteTabs(paramFavoriteTabsEntryName: string): boolean; function ReSaveTabsToXMLEntry(paramIndexToSave: integer): boolean; function SaveCurrentFavoriteTabsIfAnyPriorToChange: boolean; function RefreshXmlFavoriteTabsListSection: boolean; procedure PopulateMenuWithFavoriteTabs(mncmpMenuComponentToPopulate: TComponent; ProcedureWhenFavoriteTabItemClicked: TProcedureWhenClickOnMenuItem; KindFavoriteTabMenuPopulation: TKindFavoriteTabsMenuPopulation); procedure RefreshAssociatedMainMenu; procedure LoadTTreeView(ParamTreeView: TTreeView); procedure RefreshFromTTreeView(ParamTreeView: TTreeView); function ImportFromLegacyTabsFile(paramFilename: string; SpecifiedIndex: integer = -1): boolean; function ExportToLegacyTabsFile(index: integer; OutputDirectory: string): boolean; function GetIndexForSuchFavoriteTabsName(sSearchedFavoriteTabsName: string): integer; property FavoriteTabs[Index: integer]: TFavoriteTabs read GetFavoriteTabs; property LastFavoriteTabsLoadedUniqueId: TGUID read FLastFavoriteTabsLoadedUniqueId write FLastFavoriteTabsLoadedUniqueId; property AssociatedMainMenuItem: TMenuItem read FAssociatedMainMenuItem write FAssociatedMainMenuItem; property LastImportationStringUniqueId: TStringList read FLastImportationStringUniqueId write FLastImportationStringUniqueId; end; implementation uses //Lazarus, Free-Pascal, etc. LCLProc, crc, Graphics, Forms, lazutf8, Dialogs, //DC fMain, DCFileAttributes, uDebug, uDCUtils, uLng, DCOSUtils, uGlobs, uShowMsg, uFilePanelSelect, DCStrUtils; { GetSingleXmlFavoriteTabsFilename } function GetSingleXmlFavoriteTabsFilename: string; begin Result := mbExpandFileName(IncludeTrailingPathDelimiter(EnvVarConfigPath) + 'favoritetabs.xml'); end; { XmlStringToGuid } function XmlStringToGuid(sXmlString: string): TGUID; begin sXmlString := '{' + copy(sXmlString, 5, (length(sXmlString) - 4)) + '}'; Result := StringToGuid(sXmlString); end; { TFavoriteTabs } { TFavoriteTabs.Create } constructor TFavoriteTabs.Create; begin inherited Create; FDispatcher := fte_NULL; FFavoriteTabsName := ''; FDestinationForSavedLeftTabs := tclLeft; FDestinationForSavedRightTabs := tclRight; FExistingTabsToKeep := tclNone; FSaveDirHistory := False; FUniqueID := DCGetNewGUID; FGroupNumber := 0; end; { TFavoriteTabs.CopyToFavoriteTabs } procedure TFavoriteTabs.CopyToFavoriteTabs(DestinationFavoriteTabs: TFavoriteTabs; bExactCopyWanted: boolean = True); begin DestinationFavoriteTabs.Dispatcher := FDispatcher; DestinationFavoriteTabs.FavoriteTabsName := FFavoriteTabsName; DestinationFavoriteTabs.DestinationForSavedLeftTabs := FDestinationForSavedLeftTabs; DestinationFavoriteTabs.DestinationForSavedRightTabs := FDestinationForSavedRightTabs; DestinationFavoriteTabs.ExistingTabsToKeep := FExistingTabsToKeep; DestinationFavoriteTabs.SaveDirHistory := FSaveDirHistory; if bExactCopyWanted then DestinationFavoriteTabs.UniqueID := FUniqueId else DestinationFavoriteTabs.UniqueID := DCGetNewGUID; DestinationFavoriteTabs.GroupNumber := FGroupNumber; end; {TFavoriteTabs.GuidToXMLString } function TFavoriteTabs.GuidToXMLString: string; begin Result := GuidToString(FUniqueID); Result := 'GUID' + copy(Result, 2, (length(Result) - 2)); end; { TFavoriteTabs.SaveToXml } procedure TFavoriteTabs.SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode); begin AConfig.SetAttr(ANode, 'UniqueID', GuidToString(FUniqueID)); case Dispatcher of fte_NULL: begin AConfig.SetAttr(ANode, 'Name', ''); end; fte_ACTUALFAVTABS: begin AConfig.SetAttr(ANode, 'Name', FFavoriteTabsName); AConfig.SetAttr(ANode, 'DestLeft', integer(FDestinationForSavedLeftTabs)); AConfig.SetAttr(ANode, 'DestRight', integer(FDestinationForSavedRightTabs)); AConfig.SetAttr(ANode, 'ExistingKeep', integer(FExistingTabsToKeep)); AConfig.SetAttr(ANode, 'SaveDirHistory', FSaveDirHistory); end; fte_SEPARATOR: begin AConfig.SetAttr(ANode, 'Name', '-'); end; fte_STARTMENU: begin AConfig.SetAttr(ANode, 'Name', '-' + FFavoriteTabsName); end; fte_ENDMENU: begin AConfig.SetAttr(ANode, 'Name', '--'); end; end; end; { TFavoriteTabsList } { TFavoriteTabsList.Create } constructor TFavoriteTabsList.Create; begin inherited Create; FLastFavoriteTabsLoadedUniqueId := DCGetNewGUID; FLastImportationStringUniqueId := TStringList.Create; FAssociatedMainMenuItem := nil; end; { TFavoriteTabsList.Destroy } destructor TFavoriteTabsList.Destroy; begin if Assigned(FLastImportationStringUniqueId) then FreeAndNil(FLastImportationStringUniqueId); inherited; end; { TFavoriteTabsList.Clear } procedure TFavoriteTabsList.Clear; var i: integer; begin for i := 0 to Count - 1 do FavoriteTabs[i].Free; inherited Clear; end; { TFavoriteTabsList.Add } function TFavoriteTabsList.Add(FavoriteTabs: TFavoriteTabs): integer; begin Result := inherited Add(FavoriteTabs); end; { TFavoriteTabsList.DeleteFavoriteTab } procedure TFavoriteTabsList.DeleteFavoriteTabs(Index: integer); begin FavoriteTabs[Index].Free; Delete(Index); end; { TFavoriteTabsList.GetFavoriteTabs } function TFavoriteTabsList.GetFavoriteTabs(Index: integer): TFavoriteTabs; begin Result := TFavoriteTabs(Items[Index]); end; { GenericCopierProcessNode } // Will copy a given Xml structure from a certain node to another one. // Maybe this function should be located elsewhere but for now it's here. // WARNING: "GenericCopierProcessNode" is recursive and may call itself! procedure GenericCopierProcessNode(paramInputNode: TXmlNode; paramOutputConfig: TXmlConfig; paramOutputNode: TXmlNode); var InnerInputNode, InnerOutputNode: TXmlNode; iAttribute: integer; begin if paramInputNode = nil then Exit; // Stoppe si on a atteint une feuille if paramInputNode.NodeName <> '#text' then begin if paramOutputNode <> nil then InnerOutputNode := paramOutputConfig.AddNode(paramOutputNode, paramInputNode.NodeName) else InnerOutputNode := paramOutputConfig.FindNode(paramOutputConfig.RootNode, paramInputNode.NodeName, True); end else begin paramOutputConfig.SetValue(paramOutputNode, '', UTF16ToUTF8(paramInputNode.NodeValue)); end; // Ajoute un nœud à l'arbre s'il existe if paramInputNode.HasAttributes and (paramInputNode.Attributes.Length > 0) then for iAttribute := 0 to pred(paramInputNode.Attributes.Length) do paramOutputConfig.SetAttr(InnerOutputNode, paramInputNode.Attributes[iAttribute].NodeName, UTF16ToUTF8(paramInputNode.Attributes[iAttribute].NodeValue)); // Va au nœud enfant InnerInputNode := paramInputNode.ChildNodes.Item[0]; // Traite tous les nœuds enfants while InnerInputNode <> nil do begin GenericCopierProcessNode(InnerInputNode, paramOutputConfig, InnerOutputNode); InnerInputNode := InnerInputNode.NextSibling; end; end; { TFavoriteTabsList.CopyFavoriteTabsListToFavoriteTabsList } procedure TFavoriteTabsList.CopyFavoriteTabsListToFavoriteTabsList(var DestinationFavoriteTabsList: TFavoriteTabsList); var LocalFavoriteTabs: TFavoriteTabs; Index: longint; begin // Let's delete possible previous list content for Index := pred(DestinationFavoriteTabsList.Count) downto 0 do DestinationFavoriteTabsList.DeleteFavoriteTabs(Index); DestinationFavoriteTabsList.Clear; // Now let's create entries and add them one by one to the destination list. for Index := 0 to pred(Count) do begin LocalFavoriteTabs := TFavoriteTabs.Create; FavoriteTabs[Index].CopyToFavoriteTabs(LocalFavoriteTabs); DestinationFavoriteTabsList.Add(LocalFavoriteTabs); end; // So when we go in the editor, we know which one was the latest one. DestinationFavoriteTabsList.LastFavoriteTabsLoadedUniqueId := FLastFavoriteTabsLoadedUniqueId; end; { TFavoriteTabsList.GetIndexLastFavoriteTabsLoaded } function TFavoriteTabsList.GetIndexLastFavoriteTabsLoaded: integer; var Index: integer; begin Result := -1; Index := 0; while (Index < Count) and (Result = -1) do if IsEqualGUID(FavoriteTabs[Index].UniqueID, FLastFavoriteTabsLoadedUniqueId) then Result := Index else Inc(Index); end; { TFavoriteTabsList.GetIndexPreviousLastFavoriteTabsLoaded } function TFavoriteTabsList.GetIndexPreviousLastFavoriteTabsLoaded: integer; var SearchingIndex: integer; begin Result := -1; SearchingIndex := GetIndexLastFavoriteTabsLoaded; if SearchingIndex > 0 then begin while (Result = -1) and (SearchingIndex > 0) do begin Dec(SearchingIndex); if FavoriteTabs[SearchingIndex].Dispatcher = fte_ACTUALFAVTABS then Result := SearchingIndex; end; end; end; { TFavoriteTabsList.GetIndexNextLastFavoriteTabsLoaded } function TFavoriteTabsList.GetIndexNextLastFavoriteTabsLoaded: integer; var SearchingIndex: integer; begin Result := -1; SearchingIndex := GetIndexLastFavoriteTabsLoaded; if SearchingIndex < pred(Count) then begin while (Result = -1) and (SearchingIndex < pred(Count)) do begin Inc(SearchingIndex); if FavoriteTabs[SearchingIndex].Dispatcher = fte_ACTUALFAVTABS then Result := SearchingIndex; end; end; end; { TFavoriteTabsList.GetIndexForSuchUniqueID } function TFavoriteTabsList.GetIndexForSuchUniqueID(SearchedGUID: TGUID): integer; var iSearchedIndex: integer; begin Result := -1; iSearchedIndex := 0; while (Result = -1) and (iSearchedIndex < Count) do begin if IsEqualGUID(SearchedGUID, FavoriteTabs[iSearchedIndex].UniqueID) then Result := iSearchedIndex else Inc(iSearchedIndex); end; end; { TFavoriteTabsList.GetIndexForSuchFavoriteTabsName } function TFavoriteTabsList.GetIndexForSuchFavoriteTabsName(sSearchedFavoriteTabsName: string): integer; var iSearchedIndex: integer; begin Result := -1; iSearchedIndex := 0; while (Result = -1) and (iSearchedIndex < Count) do begin if FavoriteTabs[iSearchedIndex].FavoriteTabsName = sSearchedFavoriteTabsName then Result := iSearchedIndex else Inc(iSearchedIndex); end; end; { TFavoriteTabsList.GetSuggestedParamsForFavoriteTabs } // It won't hurt anything here if user want to use more than once the SAME name... // By adding the (1), (2), etc. between parenthesis, it's a kind of friendly indication the same name already exists. // But we do not blocked this. If he ever decides to specifically rename with the same name. This was a kind of friendly reminder. function TFavoriteTabsList.GetSuggestedParamsForFavoriteTabs(sAttemptedName: string; var SuggestedFavoriteTabsName: string): boolean; var iIndexInCaseFound: integer; begin Result := False; if length(sAttemptedName) > 0 then sAttemptedName := UTF8UpperCase(LeftStr(sAttemptedName, 1)) + RightStr(sAttemptedName, length(sAttemptedName) - 1); SuggestedFavoriteTabsName := sAttemptedName; iIndexInCaseFound := 1; while GetIndexForSuchFavoriteTabsName(SuggestedFavoriteTabsName) <> -1 do begin SuggestedFavoriteTabsName := Format('%s(%d)', [sAttemptedName, iIndexInCaseFound]); Inc(iIndexInCaseFound); end; if InputQuery(rsMsgFavoriteTabsEnterNameTitle, rsMsgFavoriteTabsEnterName, SuggestedFavoriteTabsName) then Result := (length(SuggestedFavoriteTabsName) > 0); end; { TFavoriteTabsList.ComputeSignature } // Routine tries to pickup all char chain from element of favorite tabs list to compute a unique CRC32. // This CRC32 will be a kind of signature of the favorite tabs list. function TFavoriteTabsList.ComputeSignature(Seed:dword): dword; var Index: integer; begin Result := Seed; for Index := 0 to pred(Count) do begin Result := crc32(Result, @FavoriteTabs[Index].Dispatcher, 1); if length(FavoriteTabs[Index].FavoriteTabsName) > 0 then Result := crc32(Result, @FavoriteTabs[Index].FavoriteTabsName[1], length(FavoriteTabs[Index].FavoriteTabsName)); Result := crc32(Result, @FavoriteTabs[Index].DestinationForSavedLeftTabs, sizeof(TTabsConfigLocation)); Result := crc32(Result, @FavoriteTabs[Index].DestinationForSavedRightTabs, sizeof(TTabsConfigLocation)); Result := crc32(Result, @FavoriteTabs[Index].ExistingTabsToKeep, sizeof(TTabsConfigLocation)); end; end; { TFavoriteTabsList.LoadAllListFromXml} procedure TFavoriteTabsList.LoadAllListFromXml; var ANode: TXmlNode; AConfig: TXmlConfig; LocalFavoriteTabs: TFavoriteTabs; sName: string; CurrentMenuLevel: integer; FlagAvortInsertion: boolean; begin Clear; CurrentMenuLevel := 0; // We don't add it to the list UNTIL a new entry has been added to the XML file. AConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); try ANode := AConfig.FindNode(AConfig.RootNode, 'FavoriteTabsList'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('FavoriteTabs') = 0 then begin if AConfig.TryGetAttr(ANode, 'Name', sName) then begin FlagAvortInsertion := False; LocalFavoriteTabs := TFavoriteTabs.Create; if sName = '-' then begin LocalFavoriteTabs.Dispatcher := fte_SEPARATOR; end else begin if sName = '--' then begin LocalFavoriteTabs.Dispatcher := fte_ENDMENU; if CurrentMenuLevel > 0 then Dec(CurrentMenuLevel) else FlagAvortInsertion := True; // Sanity correction in case we got corrupted from any ways end else begin if (UTF8Length(sName) > 1) then begin if (sName[1] = '-') and (sName[2] <> '-') then begin Inc(CurrentMenuLevel); LocalFavoriteTabs.Dispatcher := fte_STARTMENU; LocalFavoriteTabs.FavoriteTabsName := UTF8RightStr(sName, UTF8Length(sName) - 1); end; end; if LocalFavoriteTabs.Dispatcher = fte_NULL then begin LocalFavoriteTabs.FavoriteTabsName := sName; LocalFavoriteTabs.Dispatcher := fte_ACTUALFAVTABS; LocalFavoriteTabs.DestinationForSavedLeftTabs := TTabsConfigLocation(AConfig.GetAttr(Anode, 'DestLeft', integer(tclLeft))); LocalFavoriteTabs.DestinationForSavedRightTabs := TTabsConfigLocation(AConfig.GetAttr(Anode, 'DestRight', integer(tclRight))); LocalFavoriteTabs.ExistingTabsToKeep := TTabsConfigLocation(AConfig.GetAttr(Anode, 'ExistingKeep', integer(tclNone))); LocalFavoriteTabs.SaveDirHistory := AConfig.GetAttr(Anode, 'SaveDirHistory', False); LocalFavoriteTabs.UniqueID := StringToGuid(AConfig.GetAttr(Anode, 'UniqueID', GuidToString(DCGetNewGUID))); end; end; end; if not FlagAvortInsertion then begin Add(LocalFavoriteTabs); end else begin LocalFavoriteTabs.Free; end; end; end; ANode := ANode.NextSibling; end; while CurrentMenuLevel > 0 do begin Dec(CurrentMenuLevel); LocalFavoriteTabs := TFavoriteTabs.Create; LocalFavoriteTabs.Dispatcher := fte_ENDMENU; Add(LocalFavoriteTabs); end; end; finally FreeAndNil(AConfig); end; RefreshAssociatedMainMenu; end; { TFavoriteTabsList.LoadTabsFromXmlEntry } function TFavoriteTabsList.LoadTabsFromXmlEntry(paramIndexToLoad: integer): boolean; var AConfig: TXmlConfig; sActualTabSection: string; TestNode: TXmlNode; // Use just to validate there will be something to load from file. originalFilePanel: TFilePanelSelect; // Following variables are "pre-initialized" to default values AND are values used when not using the possibility to configure redirection of tabs in our setups. TargetDestinationForLeft: TTabsConfigLocation = tclLeft; TargetDestinationForRight: TTabsConfigLocation = tclRight; DestinationToKeep: TTabsConfigLocation = tclNone; TabsAlreadyDestroyedFlags: TTabsFlagsAlreadyDestroyed = []; begin Result := False; if (paramIndexToLoad >= 0) and (paramIndexToLoad < Count) then begin if FavoriteTabs[paramIndexToLoad].Dispatcher = fte_ACTUALFAVTABS then begin // 1. We remember to restore later the current selected panel. originalFilePanel := frmMain.SelectedPanel; // 2. We set the section-path to our wanted setup. (Don't forget the trailing slash at the end because "LoadTheseTabsWithThisConfig" requires it for the "ABranch" parameter. sActualTabSection := 'ActualTabs/' + FavoriteTabs[paramIndexToLoad].GuidToXMLString + '/'; // 3. We set the location where to restore tabs according to our setup IF we're configure for it. if gFavoriteTabsUseRestoreExtraOptions then begin TargetDestinationForLeft := FavoriteTabs[paramIndexToLoad].DestinationForSavedLeftTabs; TargetDestinationForRight := FavoriteTabs[paramIndexToLoad].DestinationForSavedRightTabs; DestinationToKeep := FavoriteTabs[paramIndexToLoad].ExistingTabsToKeep; end; // 4. We're ready to open the config files and actually load the stored tabs to the correct target side. AConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); if Assigned(AConfig) then begin try // 5.1. We load the left tabs (We check before to make sure there is a "Left" section to don't possibly destroy existing tabs and later realize there is no section to load (But it should not happen...)). TestNode := AConfig.FindNode(AConfig.RootNode, sActualTabSection + 'Left/Tab'); if Assigned(TestNode) then frmMain.LoadTheseTabsWithThisConfig(AConfig, sActualTabSection, tclLeft, TargetDestinationForLeft, DestinationToKeep, TabsAlreadyDestroyedFlags); // 5.2. We load the right tabs (We check before to make sure there is a "Right" section to don't possibly destroy existing tabs and later realize there is no section to load (But it should not happen...)). TestNode := AConfig.FindNode(AConfig.RootNode, sActualTabSection + 'Right/Tab'); if Assigned(TestNode) then frmMain.LoadTheseTabsWithThisConfig(AConfig, sActualTabSection, tclRight, TargetDestinationForRight, DestinationToKeep, TabsAlreadyDestroyedFlags); // 6. We've loaded a setup, let's remember it. FLastFavoriteTabsLoadedUniqueId := FavoriteTabs[paramIndexToLoad].FUniqueID; // 7. We need to refresh main menu so the check will be on the right setup. The "Reload" and "Resave" will be enabled also. RefreshAssociatedMainMenu; // 8. If we reach that point, we deserve to return True! Result := True; finally FreeAndNil(AConfig); end; end; // 9. We restore focuse to what was our active panel, ready to play in it. frmMain.SelectedPanel := originalFilePanel; frmMain.ActiveFrame.SetFocus; end; end; end; { TFavoriteTabsList.GetBestIndexForAlphabeticalNewFavoriteTabs } // We take the whole list of "FavoriteTabsName" seen as one single alphabetical sorted list. // We find the exact place where our string to add could fit. // We insert it right in front of the one its is closed to go. // If we have the last one, we placed it last! function TFavoriteTabsList.GetBestIndexForAlphabeticalNewFavoriteTabs(sFavoriteTabsNameToFindAPlaceFor: string): integer; var I, iPosInserted: integer; localFavoriteTabsNameToFindAPlaceFor: string; MagickSortedList: TStringList; begin Result := -1; localFavoriteTabsNameToFindAPlaceFor := UTF8LowerCase(sFavoriteTabsNameToFindAPlaceFor); MagickSortedList := TStringList.Create; try MagickSortedList.Sorted := True; MagickSortedList.Duplicates := dupAccept; // 1. We add in the list only the actual FavoriteTabsName. for I := 0 to pred(Count) do if FavoriteTabs[I].Dispatcher = fte_ACTUALFAVTABS then MagickSortedList.Add(UTF8LowerCase(FavoriteTabs[I].FavoriteTabsName) + DirectorySeparator + IntToStr(I)); // 2. Add to list our string. iPosInserted := MagickSortedList.Add(localFavoriteTabsNameToFindAPlaceFor); // 3. We now know the best place to insert our entry (unless it's last one). if MagickSortedList.Count > 1 then begin if iPosInserted < pred(MagickSortedList.Count) then begin Result := StrToInt(GetLastDir(MagickSortedList.Strings[iPosInserted + 1])); end else begin Result := (StrToInt(GetLastDir(MagickSortedList.Strings[iPosInserted - 1]))) + 1; if Result >= Count then Result := -1; end; end; finally MagickSortedList.Free; end; end; { TFavoriteTabsList.AddToListAndToXmlFileHeader } procedure TFavoriteTabsList.AddToListAndToXmlFileHeader(paramFavoriteTabs: TFavoriteTabs; AConfig: TXmlConfig; SpecifiedIndex: integer = -1); var SubNode, RootNode: TXmlNode; iIndexToInsert: integer; begin if SpecifiedIndex = -1 then begin case gWhereToAddNewFavoriteTabs of afte_Last: begin // The simplest case: We add the node, we add it at the end of the list, that's it! RootNode := AConfig.FindNode(AConfig.RootNode, 'FavoriteTabsList', True); SubNode := AConfig.AddNode(RootNode, 'FavoriteTabs'); paramFavoriteTabs.SaveToXml(AConfig, SubNode); Add(paramFavoriteTabs); end; afte_First: begin // A bit more complicated: we will "insert" at position 0 our Favorites Tabs in our list and then we'll recreate the index at the beginning of our Xml file. Insert(0, paramFavoriteTabs); ActualDumpFavoriteTabsListInXml(AConfig); end; afte_Alphabetical: begin //A medium bit more complicated: we will iIndexToInsert := GetBestIndexForAlphabeticalNewFavoriteTabs(paramFavoriteTabs.FavoriteTabsName); if (iIndexToInsert >= 0) and (Count > 0) then Insert(iIndexToInsert, paramFavoriteTabs) else Add(paramFavoriteTabs); ActualDumpFavoriteTabsListInXml(AConfig); end; end; end else begin if SpecifiedIndex < pred(Count) then Insert(SpecifiedIndex, paramFavoriteTabs) else Add(paramFavoriteTabs); ActualDumpFavoriteTabsListInXml(AConfig); end; end; { TFavoriteTabsList.SaveNewEntryFavoriteTabs } function TFavoriteTabsList.SaveNewEntryFavoriteTabs(paramFavoriteTabsEntryName: string): boolean; var AConfig: TXmlConfig; sActualTabSection: string; LocalFavoriteTabs: TFavoriteTabs; bFlagToSaveHistoryOrNot: boolean; begin try LocalFavoriteTabs := TFavoriteTabs.Create; LocalFavoriteTabs.Dispatcher := fte_ACTUALFAVTABS; LocalFavoriteTabs.FavoriteTabsName := paramFavoriteTabsEntryName; LocalFavoriteTabs.DestinationForSavedLeftTabs := gDefaultTargetPanelLeftSaved; LocalFavoriteTabs.DestinationForSavedRightTabs := gDefaultTargetPanelRightSaved; LocalFavoriteTabs.ExistingTabsToKeep := gDefaultExistingTabsToKeep; LocalFavoriteTabs.SaveDirHistory := gFavoriteTabsSaveDirHistory; //The UniqueID is not assigned here because it has already been set when "LocalFavoriteTabs" has been created. if gFavoriteTabsUseRestoreExtraOptions then bFlagToSaveHistoryOrNot := LocalFavoriteTabs.SaveDirHistory else bFlagToSaveHistoryOrNot := gFavoriteTabsSaveDirHistory; AConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); try AddToListAndToXmlFileHeader(LocalFavoriteTabs, AConfig); sActualTabSection := 'ActualTabs/' + LocalFavoriteTabs.GuidToXMLString; frmMain.SaveTabsXml(AConfig, sActualTabSection, frmMain.LeftTabs, bFlagToSaveHistoryOrNot); frmMain.SaveTabsXml(AConfig, sActualTabSection, frmMain.RightTabs, bFlagToSaveHistoryOrNot); AConfig.Save; FLastFavoriteTabsLoadedUniqueId := LocalFavoriteTabs.UniqueID; RefreshAssociatedMainMenu; // To possibly enable the action for the "ReLoad" and "ReSave". finally FreeAndNil(AConfig); end; Result := True; // If we get here, we'll assumed Favorite Tabs has been saved! except Result := False; end; end; { TFavoriteTabsList.ReSaveTabsToXMLEntry } // When "ReSaving", we must first find in the Xml the previous entry to write over it. function TFavoriteTabsList.ReSaveTabsToXMLEntry(paramIndexToSave: integer): boolean; var ANode: TXmlNode; AConfig: TXmlConfig; sActualTabSection, sGUIDTemp: string; bFlagSaved: boolean = False; bFlagToSaveHistoryOrNot: boolean; begin Result := False; if (paramIndexToSave >= 0) and (paramIndexToSave < Count) then begin if FavoriteTabs[paramIndexToSave].Dispatcher = fte_ACTUALFAVTABS then begin AConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); try ANode := AConfig.FindNode(AConfig.RootNode, 'FavoriteTabsList'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) and (not bFlagSaved) do begin if ANode.CompareName('FavoriteTabs') = 0 then begin if AConfig.TryGetAttr(ANode, 'UniqueID', sGUIDTemp) then begin if IsEqualGUID(FavoriteTabs[paramIndexToSave].UniqueID, StringToGuid(sGUIDTemp)) then begin FavoriteTabs[paramIndexToSave].SaveToXml(AConfig, ANode); bFlagSaved := True; FLastFavoriteTabsLoadedUniqueId := FavoriteTabs[paramIndexToSave].UniqueID; end; end; end; ANode := ANode.NextSibling; end; end; if bFlagSaved then begin if gFavoriteTabsUseRestoreExtraOptions then bFlagToSaveHistoryOrNot := FavoriteTabs[paramIndexToSave].SaveDirHistory else bFlagToSaveHistoryOrNot := gFavoriteTabsSaveDirHistory; sActualTabSection := 'ActualTabs/' + FavoriteTabs[paramIndexToSave].GuidToXMLString; frmMain.SaveTabsXml(AConfig, sActualTabSection, frmMain.LeftTabs, bFlagToSaveHistoryOrNot); frmMain.SaveTabsXml(AConfig, sActualTabSection, frmMain.RightTabs, bFlagToSaveHistoryOrNot); AConfig.Save; Result := True; end; finally FreeAndNil(AConfig); end; end; end; end; { TFavoriteTabsList.SaveCurrentFavoriteTabsIfAnyPriorToChange } function TFavoriteTabsList.SaveCurrentFavoriteTabsIfAnyPriorToChange: boolean; var iIndex: integer; bFlagToSaveHistoryOrNot: boolean; begin Result := True; iIndex := GetIndexLastFavoriteTabsLoaded; if iIndex <> -1 then begin if gFavoriteTabsUseRestoreExtraOptions then bFlagToSaveHistoryOrNot := FavoriteTabs[iIndex].SaveDirHistory else bFlagToSaveHistoryOrNot := gFavoriteTabsSaveDirHistory; if bFlagToSaveHistoryOrNot then Result := ReSaveTabsToXMLEntry(iIndex); end; end; { TFavoriteTabsList.ActualDumpFavoriteTabsListInXml } // Since we save everything, we will will flush the current "FavoriteTabsList" header section to restore it. // We need to do in case we would delete entries. // Also, certainly we could have done something like "AConfig.DeleteNode(ListNode)" and then rewrite completely our table after. // BUT, doing that would place our list at the end. That's fine and functional. But it's nice for human to see it on top when debugging. // So that's why we delete item one by one without deleting the initial node. // Also, we need to do a kind of purge of the subsequent node regarding actual tab setup. // To do that, we check each node to see if we have a correspondant entry in the header. // If not, we flush that node! function TFavoriteTabsList.ActualDumpFavoriteTabsListInXml(AConfig: TXmlConfig): boolean; var SubNode, ListNode, ANode, BNode: TXmlNode; iIndex: integer; begin ListNode := AConfig.FindNode(AConfig.RootNode, 'FavoriteTabsList', True); if Assigned(ListNode) then begin ANode := ListNode.FirstChild; while Assigned(ANode) do begin BNode := ANode.NextSibling; AConfig.DeleteNode(ANode); ANode := BNode; end; end; // 1. Write the kind of "Table" of Favorite Tabs iIndex := 0; while iIndex < Count do begin case FavoriteTabs[iIndex].Dispatcher of fte_ACTUALFAVTABS, fte_SEPARATOR, fte_STARTMENU, fte_ENDMENU: begin SubNode := AConfig.AddNode(ListNode, 'FavoriteTabs'); FavoriteTabs[iIndex].SaveToXml(AConfig, SubNode); end; end; Inc(iIndex); end; // 2. Validate if bare data for actual tabs have a matching entry in our table. // If not, flush it. ListNode := AConfig.FindNode(AConfig.RootNode, 'ActualTabs'); if Assigned(ListNode) then begin ANode := ListNode.FirstChild; while Assigned(ANode) do begin BNode := ANode.NextSibling; if GetIndexForSuchUniqueID(XmlStringToGuid(ANode.NodeName)) = -1 then AConfig.DeleteNode(ANode); ANode := BNode; end; end; end; { TFavoriteTabsList.RefreshXmlFavoriteTabsListSection } function TFavoriteTabsList.RefreshXmlFavoriteTabsListSection: boolean; var AConfig: TXmlConfig; begin Result := False; try AConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); try ActualDumpFavoriteTabsListInXml(AConfig); AConfig.Save; finally FreeAndNil(AConfig); end; Result := True; except on E: Exception do msgError(E.Message); end; end; { TFavoriteTabsList.PopulateMenuWithFavoriteTabs } procedure TFavoriteTabsList.PopulateMenuWithFavoriteTabs(mncmpMenuComponentToPopulate: TComponent; ProcedureWhenFavoriteTabItemClicked: TProcedureWhenClickOnMenuItem; KindFavoriteTabMenuPopulation: TKindFavoriteTabsMenuPopulation); var I: longint; //Same variable for main and local routine // WARNING: "CompleteMenu" is recursive and may call itself! function CompleteMenu(ParamMenuItem: TComponent; TagOffset: integer = 0): longint; // WARNING: "DoCheckedBackToTop" is recursive and may call itself! procedure DoCheckedBackToTop(paramTMenuItem: TComponent); begin if (mncmpMenuComponentToPopulate = paramTMenuItem) then Exit; if (paramTMenuItem.ClassType = TMenuItem) and (TMenuItem(paramTMenuItem).Caption <> rsMsgFavortieTabsSaveOverExisting) then if TMenuItem(paramTMenuItem).Parent <> nil then if (TMenuItem(paramTMenuItem).Parent.ClassType <> TMainMenu) then begin TMenuItem(paramTMenuItem).Checked := True; DoCheckedBackToTop(TMenuItem(paramTMenuItem).Parent); end; end; var localmi: TMenuItem; LocalLastAdditionIsASeparator: boolean; begin Result := 0; LocalLastAdditionIsASeparator := False; while I < Count do begin Inc(I); case FavoriteTabs[I - 1].Dispatcher of fte_ACTUALFAVTABS: begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption := FavoriteTabs[I - 1].FFavoriteTabsName.Replace('&', '&&', [rfReplaceAll]); localmi.tag := (I - 1) + TagOffset; localmi.OnClick := ProcedureWhenFavoriteTabItemClicked; localmi.Checked := IsEqualGUID(FavoriteTabs[I - 1].UniqueID, FLastFavoriteTabsLoadedUniqueId); if ParamMenuItem.ClassType = TPopupMenu then TPopupMenu(ParamMenuItem).Items.Add(localmi) else if ParamMenuItem.ClassType = TMenuItem then begin TMenuItem(ParamMenuItem).Add(localmi); if localmi.Checked then DoCheckedBackToTop(localmi); end; LocalLastAdditionIsASeparator := False; Inc(Result); end; fte_SEPARATOR: begin if (not LocalLastAdditionIsASeparator) then begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption := '-'; if ParamMenuItem.ClassType = TPopupMenu then TPopupMenu(ParamMenuItem).Items.Add(localmi) else if ParamMenuItem.ClassType = TMenuItem then TMenuItem(ParamMenuItem).Add(localmi); LocalLastAdditionIsASeparator := True; Inc(Result); end; end; fte_STARTMENU: begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption := FavoriteTabs[I - 1].FavoriteTabsName.Replace('&', '&&', [rfReplaceAll]); //if gIconsInMenus then // localmi.ImageIndex := frmMain.miLoadFavoriteTabs.ImageIndex; if ParamMenuItem.ClassType = TPopupMenu then TPopupMenu(ParamMenuItem).Items.Add(localmi) else if ParamMenuItem.ClassType = TMenuItem then TMenuItem(ParamMenuItem).Add(localmi); CompleteMenu(localmi, TagOffset); if localmi.Count <> 0 then begin LocalLastAdditionIsASeparator := False; Inc(Result); end else begin localmi.Free; end; end; fte_ENDMENU: begin if LocalLastAdditionIsASeparator then begin if ParamMenuItem.ClassType = TPopupMenu then TPopupMenu(ParamMenuItem).Items[pred(TPopupMenu(ParamMenuItem).Items.Count)].Free else if ParamMenuItem.ClassType = TMenuItem then TMenuItem(ParamMenuItem).Items[pred(TMenuItem(ParamMenuItem).Count)].Free; Dec(Result); end; exit; end; end; //case FavoriteTabs[I-1].Dispatcher of end; //while I<Count do end; var miMainTree: TMenuItem; begin // 1. Let's clear possible previous items in the menu to create a fresh new one. if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Clear; // 2. Add the Favorite Tabs shortcuts if we have any. if Count > 0 then begin I := 0; CompleteMenu(mncmpMenuComponentToPopulate, 0); end; // 3. Customize minimally our menu. If we wants some configuration and saving, let's add them. case KindFavoriteTabMenuPopulation of ftmp_FAVTABSWITHCONFIG: begin // 3.1. Add the reload/resave items. if (Count > 0) and (GetIndexLastFavoriteTabsLoaded <> -1) then begin miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := ('-'); if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Action := frmMain.actReloadFavoriteTabs; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Action := frmMain.actResaveFavoriteTabs; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; // 3.2. Add a delimiter, a simple line to separate. if Count > 0 then begin miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := '-'; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; // 3.3 Now add "Add current tabs to Favorite Tabs". miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Action := frmMain.actSaveFavoriteTabs; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); // 3.4. If we have at least one entry, let's create the "Save Over Existing.." items. if Count > 0 then begin // 3.4.1. Add the "Save current tabs over existing Favorite Tabs entry" in a submenu. // It's placed in a sub menu since when it's time to saved since it's less frequent then keeping accessing... // ...and to avoid to click on it by accident and overwring existing stuff. miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := rsMsgFavortieTabsSaveOverExisting; miMainTree.ImageIndex := frmMain.actResaveFavoriteTabs.ImageIndex; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); // 3.4.1. And then add our favorite tabs again BUT with the "TAGOFFSET_FAVTABS_FORSAVEOVEREXISTING" offset in the tag. I := 0; CompleteMenu(miMainTree, TAGOFFSET_FAVTABS_FORSAVEOVEREXISTING); // 3.4.2. Then another separator. // Intentionnally there is no separator when user has no favorite tabs and there is one when there is at least one... // It seems stupid to have a single separator when there is only two items... // ... and when we have many items, it looks good to have the "Save's" enclose between separators. miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := '-'; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; // 3.5 Now add "Configure Folder tab". miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Action := frmMain.actConfigFolderTabs; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); // 3.6 Now add "Configure Favorite Tabs". miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Action := frmMain.actConfigFavoriteTabs; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; end; //case KindFavoriteTabMenuPopulation of if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then if TPopupMenu(mncmpMenuComponentToPopulate).Images = nil then TPopupMenu(mncmpMenuComponentToPopulate).Images := frmMain.imgLstActions; if mncmpMenuComponentToPopulate.ClassType = TMenuItem then if TMenuItem(mncmpMenuComponentToPopulate).GetParentMenu.Images = nil then TMenuItem(mncmpMenuComponentToPopulate).GetParentMenu.Images := frmMain.imgLstActions; end; { TFavoriteTabsList.RefreshAssociatedMainMenu } procedure TFavoriteTabsList.RefreshAssociatedMainMenu; var iIndex: integer; miMainTree: TMenuItem; begin if FAssociatedMainMenuItem <> nil then begin if FAssociatedMainMenuItem <> nil then begin if FAssociatedMainMenuItem.Count > 4 then begin iIndex := pred(FAssociatedMainMenuItem.Count); while iIndex > 3 do begin FAssociatedMainMenuItem.Delete(iIndex); Dec(iIndex); end; end; if Count > 0 then begin miMainTree := TMenuItem.Create(FAssociatedMainMenuItem); miMainTree.Caption := '-'; FAssociatedMainMenuItem.Add(miMainTree); end; if GetIndexLastFavoriteTabsLoaded = -1 then begin frmMain.actReloadFavoriteTabs.Enabled := False; frmMain.actResaveFavoriteTabs.Enabled := False; end else begin frmMain.actReloadFavoriteTabs.Enabled := True; frmMain.actResaveFavoriteTabs.Enabled := True; end; end; PopulateMenuWithFavoriteTabs(FAssociatedMainMenuItem, @frmMain.Commands.DoOnClickMenuJobFavoriteTabs, ftmp_JUSTFAVTABS); end; end; { TFavoriteTabsList.LoadTTreeView } // We'll try to restore what was selected prior the reload for the situation where it's pertinent. procedure TFavoriteTabsList.LoadTTreeView(ParamTreeView: TTreeView); var Index: longint; procedure RecursivAddElements(WorkingNode: TTreeNode); var FlagGetOut: boolean = False; LocalNode: TTreeNode; begin while (FlagGetOut = False) and (Index < Count) do begin case FavoriteTabs[Index].Dispatcher of fte_STARTMENU: begin LocalNode := ParamTreeView.Items.AddChildObject(WorkingNode, FavoriteTabs[Index].FavoriteTabsName, FavoriteTabs[Index]); LocalNode.Data := FavoriteTabs[Index]; Inc(Index); RecursivAddElements(LocalNode); end; fte_ENDMENU: begin FlagGetOut := True; Inc(Index); end; fte_SEPARATOR: begin LocalNode := ParamTreeView.Items.AddChildObject(WorkingNode, FAVORITETABS_SEPARATORSTRING, FavoriteTabs[Index]); LocalNode.Data := FavoriteTabs[Index]; Inc(Index); end else // ...but should not happened. begin LocalNode := ParamTreeView.Items.AddChildObject(WorkingNode, FavoriteTabs[Index].FavoriteTabsName, FavoriteTabs[Index]); Inc(Index); end; end; end; end; begin ParamTreeView.Items.Clear; Index := 0; RecursivAddElements(nil); end; { TFavoriteTabsList.RefreshFromTTreeView } // The routine will recreate the complete TFavoriteTabsList from a TTreeView. // It cannot erase or replace immediately the current list because the TTreeView refer to it! // So it create it into the "TransitFavoriteTabsList" and then, it will copy it to self one. // It will remember what was selected before based on the unique ID and then restore what is possible to restored after. procedure TFavoriteTabsList.RefreshFromTTreeView(ParamTreeView: TTreeView); var TransitFavoriteTabsList: TFavoriteTabsList; iIndex: integer; slRememberCurrentSelections: TStringList; procedure RecursiveEncapsulateSubMenu(WorkingTreeNode: TTreeNode); var MaybeChildNode: TTreeNode; WorkingFavoriteTabEntry: TFavoriteTabs; begin while WorkingTreeNode <> nil do begin MaybeChildNode := WorkingTreeNode.GetFirstChild; if MaybeChildNode <> nil then begin WorkingFavoriteTabEntry := TFavoriteTabs.Create; TFavoriteTabs(WorkingTreeNode.Data).CopyToFavoriteTabs(WorkingFavoriteTabEntry); WorkingFavoriteTabEntry.Dispatcher := fte_STARTMENU; //Probably not necessary, but let's make sure it will start a menu TransitFavoriteTabsList.Add(WorkingFavoriteTabEntry); RecursiveEncapsulateSubMenu(MaybeChildNode); WorkingFavoriteTabEntry := TFavoriteTabs.Create; WorkingFavoriteTabEntry.Dispatcher := fte_ENDMENU; TransitFavoriteTabsList.Add(WorkingFavoriteTabEntry); end else begin //We won't copy EMPTY submenu so that's why we check for "fte_STARTMENU". And the check for "fte_ENDMENU" is simply probably unecessary protection if (TFavoriteTabs(WorkingTreeNode.Data).Dispatcher <> fte_STARTMENU) and (TFavoriteTabs(WorkingTreeNode.Data).Dispatcher <> fte_ENDMENU) then begin WorkingFavoriteTabEntry := TFavoriteTabs.Create; TFavoriteTabs(WorkingTreeNode.Data).CopyToFavoriteTabs(WorkingFavoriteTabEntry); TransitFavoriteTabsList.Add(WorkingFavoriteTabEntry); end; end; WorkingTreeNode := WorkingTreeNode.GetNextSibling; end; end; begin if ParamTreeView.Items.Count > 0 then begin slRememberCurrentSelections := TStringList.Create; TransitFavoriteTabsList := TFavoriteTabsList.Create; try //Saving a trace of what is selected right now. for iIndex := 0 to pred(ParamTreeView.Items.Count) do if ParamTreeView.Items[iIndex].Selected then if TFavoriteTabs(ParamTreeView.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then slRememberCurrentSelections.Add(GUIDtoString(TFavoriteTabs(ParamTreeView.Items[iIndex].Data).UniqueID)); TransitFavoriteTabsList.LastFavoriteTabsLoadedUniqueId := FLastFavoriteTabsLoadedUniqueId; RecursiveEncapsulateSubMenu(ParamTreeView.Items.Item[0]); TransitFavoriteTabsList.CopyFavoriteTabsListToFavoriteTabsList(self); LoadTTreeView(ParamTreeView); // Restoring what was selected. ParamTreeView.ClearSelection(False); for iIndex := 0 to pred(ParamTreeView.Items.Count) do if TFavoriteTabs(ParamTreeView.Items[iIndex].Data).Dispatcher = fte_ACTUALFAVTABS then ParamTreeView.Items[iIndex].Selected := (slRememberCurrentSelections.IndexOf(GUIDtoString(TFavoriteTabs(ParamTreeView.Items[iIndex].Data).UniqueID)) <> -1); finally TransitFavoriteTabsList.Clear; TransitFavoriteTabsList.Free; FreeAndNil(slRememberCurrentSelections); end; end else begin Self.Clear; mbDeleteFile(GetSingleXmlFavoriteTabsFilename); end; end; { TFavoriteTabsList.ImportFromLegacyTabsFile } function TFavoriteTabsList.ImportFromLegacyTabsFile(paramFilename: string; SpecifiedIndex: integer = -1): boolean; var iNode, oNode: TXmlNode; InputXmlConfig: TXmlConfig; OutputXmlConfig: TXmlConfig; LocalFavoriteTabs: TFavoriteTabs; begin Result := False; try LocalFavoriteTabs := TFavoriteTabs.Create; LocalFavoriteTabs.Dispatcher := fte_ACTUALFAVTABS; LocalFavoriteTabs.FavoriteTabsName := ExtractOnlyFileName(paramFilename); LocalFavoriteTabs.DestinationForSavedLeftTabs := tclLeft; LocalFavoriteTabs.DestinationForSavedRightTabs := tclRight; LocalFavoriteTabs.ExistingTabsToKeep := tclNone; //The UniqueID is not assigned here because it has already been set when "LocalFavoriteTabs" has been created. InputXmlConfig := TXmlConfig.Create(paramFilename, True); OutputXmlConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); try AddToListAndToXmlFileHeader(LocalFavoriteTabs, OutputXmlConfig, SpecifiedIndex); iNode := InputXmlConfig.FindNode(InputXmlConfig.RootNode, 'Tabs/OpenedTabs/Left'); oNode := OutputXmlConfig.FindNode(OutputXmlConfig.RootNode, 'ActualTabs/' + LocalFavoriteTabs.GuidToXMLString, True); while iNode <> nil do begin GenericCopierProcessNode(iNode, OutputXmlConfig, oNode); // Procédure récursive iNode := iNode.NextSibling; end; OutputXmlConfig.Save; gFavoriteTabsList.LastImportationStringUniqueId.Add(GUIDToString(LocalFavoriteTabs.UniqueID)); Result := True; finally FreeAndNil(OutputXmlConfig); FreeAndNil(InputXmlConfig); end; except on E: Exception do msgError(E.Message); end; end; { TFavoriteTabsList.ExportToLegacyTabsFile } function TFavoriteTabsList.ExportToLegacyTabsFile(index: integer; OutputDirectory: string): boolean; var iNode, oNode: TXmlNode; InputXmlConfig: TXmlConfig; OutputXmlConfig: TXmlConfig; sBasicOutputFilename, sConfigFilename: string; iAttempt: integer; begin Result := False; try // 1. Let's try to give an exported filename based of the Favorite Tabs friendly name. // If a filename like that already exists, add "(x)" to the name and increase "x" until the file does not already exists! sBasicOutputFilename := RemoveInvalidCharsFromFileName(FavoriteTabs[index].FavoriteTabsName); if sBasicOutputFilename = '' then sBasicOutputFilename := 'TabsExported'; sBasicOutputFilename := IncludeTrailingPathDelimiter(OutputDirectory) + sBasicOutputFilename; sConfigFilename := sBasicOutputFilename + '.tab'; iAttempt := 1; while FileExists(sConfigFilename) do begin sConfigFilename := sBasicOutputFilename + '(' + IntToStr(iAttempt) + ').tab'; Inc(iAttempt); end; // 2. Ok. Let's start our exportatation. Basically we start from the section of the source setup and write it to a new single isolated one. InputXmlConfig := TXmlConfig.Create(GetSingleXmlFavoriteTabsFilename, True); OutputXmlConfig := TXmlConfig.Create(sConfigFilename); try iNode := InputXmlConfig.FindNode(InputXmlConfig.RootNode, 'ActualTabs/' + FavoriteTabs[index].GuidToXMLString + '/Left'); if iNode <> nil then begin oNode := OutputXmlConfig.FindNode(OutputXmlConfig.RootNode, 'Tabs/OpenedTabs', True); while iNode <> nil do begin GenericCopierProcessNode(iNode, OutputXmlConfig, oNode); // Procédure récursive iNode := iNode.NextSibling; end; OutputXmlConfig.Save; gFavoriteTabsList.LastImportationStringUniqueId.Add(sConfigFilename); Result := True; end; finally FreeAndNil(OutputXmlConfig); FreeAndNil(InputXmlConfig); end; except on E: Exception do msgError(E.Message); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufile.pas����������������������������������������������������������������������0000644�0001750�0000144�00000074342�14743153644�015220� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFile; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileProperty, DCBasicTypes; type { TFile } TFile = class private // Cached values for extension and name. // Automatically set when name changes. FExtension: String; //<en Extension. FNameNoExt: String; //<en Name without extension. FPath: String; //<en Path to the file. Always includes trailing path delimiter. FProperties: TFileProperties; FVariantProperties: TFileVariantProperties; FSupportedProperties: TFilePropertiesTypes; procedure SplitIntoNameAndExtension(const FileName: string; var aFileNameOnly: string; var aExtension: string); procedure UpdateNameAndExtension(const FileName: string); protected function GetProperty(PropType: TFilePropertyType): TFileProperty; procedure SetProperty(PropType: TFilePropertyType; NewValue: TFileProperty); function GetFullPath: String; procedure SetFullPath(const NewFullPath: String); procedure SetPath(const NewPath: String); function GetName: String; procedure SetName(NewName: String); function GetExtension: String; {en Retrieves name without extension. } function GetNameNoExt: String; // Values. function GetAttributes: TFileAttrs; procedure SetAttributes(NewAttributes: TFileAttrs); function GetSize: Int64; procedure SetSize(NewSize: Int64); function GetCompressedSize: Int64; procedure SetCompressedSize(NewCompressedSize: Int64); function GetModificationTime: TDateTime; procedure SetModificationTime(NewTime: TDateTime); function GetCreationTime: TDateTime; procedure SetCreationTime(NewTime: TDateTime); function GetLastAccessTime: TDateTime; procedure SetLastAccessTime(NewTime: TDateTime); function GetChangeTime: TDateTime; procedure SetChangeTime(AValue: TDateTime); function GetIsLinkToDirectory: Boolean; procedure SetIsLinkToDirectory(NewValue: Boolean); function GetType: String; procedure SetType(NewValue: String); // Properties. function GetNameProperty: TFileNameProperty; procedure SetNameProperty(NewValue: TFileNameProperty); function GetSizeProperty: TFileSizeProperty; procedure SetSizeProperty(NewValue: TFileSizeProperty); function GetCompressedSizeProperty: TFileCompressedSizeProperty; procedure SetCompressedSizeProperty(NewValue: TFileCompressedSizeProperty); function GetAttributesProperty: TFileAttributesProperty; procedure SetAttributesProperty(NewValue: TFileAttributesProperty); function GetModificationTimeProperty: TFileModificationDateTimeProperty; procedure SetModificationTimeProperty(NewValue: TFileModificationDateTimeProperty); function GetCreationTimeProperty: TFileCreationDateTimeProperty; procedure SetCreationTimeProperty(NewValue: TFileCreationDateTimeProperty); function GetLastAccessTimeProperty: TFileLastAccessDateTimeProperty; procedure SetLastAccessTimeProperty(NewValue: TFileLastAccessDateTimeProperty); function GetChangeTimeProperty: TFileChangeDateTimeProperty; procedure SetChangeTimeProperty(AValue: TFileChangeDateTimeProperty); function GetLinkProperty: TFileLinkProperty; procedure SetLinkProperty(NewValue: TFileLinkProperty); function GetOwnerProperty: TFileOwnerProperty; procedure SetOwnerProperty(NewValue: TFileOwnerProperty); function GetTypeProperty: TFileTypeProperty; procedure SetTypeProperty(NewValue: TFileTypeProperty); function GetCommentProperty: TFileCommentProperty; procedure SetCommentProperty(NewValue: TFileCommentProperty); public constructor Create(const APath: String); constructor CreateForCloning; destructor Destroy; override; {en Creates an identical copy of the object (as far as object data is concerned). } function Clone: TFile; procedure CloneTo(AFile: TFile); function Compare(AFile: TFile): TFilePropertiesTypes; {en Frees all properties except for Name (which is always required). } procedure ClearProperties; procedure ClearVariantProperties; function ReleaseProperty(PropType: TFilePropertyType): TFileProperty; {en Returns True if name is not '..'. May be extended to include other conditions. } function IsNameValid: Boolean; {en This list only contains pointers to TFileProperty objects. Never free element from this list! Choices for implementing retrieval of file properties: 1. array [TFilePropertyType] of TFileProperty (current implementation) Upside: it should be the fastest method. Downside: uses more memory as the array size includes properties not supported by the given file type 2. hash table indexed by TFilePropertyType key. It _may_ be a bit slower than the table. It _may_ use less memory though. 3. a simple list Slowest, but the least memory usage. } //property Properties[Index: Integer]; //property Properties[Name: String]; //property Properties[Type: TFilePropertiesType] property VariantProperties: TFileVariantProperties read FVariantProperties; property Properties[PropType: TFilePropertyType]: TFileProperty read GetProperty write SetProperty; {en All supported properties should have an assigned Properties[propertyType]. } property SupportedProperties: TFilePropertiesTypes read FSupportedProperties; property AssignedProperties: TFilePropertiesTypes read FSupportedProperties; { Accessors to each property. } property NameProperty: TFileNameProperty read GetNameProperty write SetNameProperty; property SizeProperty: TFileSizeProperty read GetSizeProperty write SetSizeProperty; property CompressedSizeProperty: TFileCompressedSizeProperty read GetCompressedSizeProperty write SetCompressedSizeProperty; property AttributesProperty: TFileAttributesProperty read GetAttributesProperty write SetAttributesProperty; property ModificationTimeProperty: TFileModificationDateTimeProperty read GetModificationTimeProperty write SetModificationTimeProperty; property CreationTimeProperty: TFileCreationDateTimeProperty read GetCreationTimeProperty write SetCreationTimeProperty; property LastAccessTimeProperty: TFileLastAccessDateTimeProperty read GetLastAccessTimeProperty write SetLastAccessTimeProperty; property ChangeTimeProperty: TFileChangeDateTimeProperty read GetChangeTimeProperty write SetChangeTimeProperty; property LinkProperty: TFileLinkProperty read GetLinkProperty write SetLinkProperty; property OwnerProperty: TFileOwnerProperty read GetOwnerProperty write SetOwnerProperty; property TypeProperty: TFileTypeProperty read GetTypeProperty write SetTypeProperty; property CommentProperty: TFileCommentProperty read GetCommentProperty write SetCommentProperty; { Accessors to each property's value. } {en Sets/gets absolute path to file. On get returns Path + Name. On set sets Path and Name accordingly. } property FullPath: String read GetFullPath write SetFullPath; property Path: String read FPath write SetPath; property Name: String read GetName write SetName; property NameNoExt: String read GetNameNoExt; property Extension: String read GetExtension; property Size: Int64 read GetSize write SetSize; property CompressedSize: Int64 read GetCompressedSize write SetCompressedSize; property Attributes: TFileAttrs read GetAttributes write SetAttributes; property ModificationTime: TDateTime read GetModificationTime write SetModificationTime; property CreationTime: TDateTime read GetCreationTime write SetCreationTime; property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; property ChangeTime: TDateTime read GetChangeTime write SetChangeTime; property FileType: String read GetType write SetType; // Convenience functions. // We assume here that when the file has no attributes // the result is false for all these functions. // These functions should probably be moved from here and should not be methods. function IsDirectory: Boolean; function IsSpecial: Boolean; function IsSysFile: Boolean; function IsHidden: Boolean; function IsLink: Boolean; property IsLinkToDirectory: Boolean read GetIsLinkToDirectory write SetIsLinkToDirectory; function IsExecutable: Boolean; // for ShellExecute end; // -------------------------------------------------------------------------- { TFiles } TFiles = class { A list of TFile } private FList: TFPList; FFlat: Boolean; FOwnsObjects: Boolean; FPath: String; //<en path of all files protected function GetCount: Integer; procedure SetCount(Count: Integer); function Get(Index: Integer): TFile; procedure Put(Index: Integer; AFile: TFile); procedure SetPath(const NewPath: String); public constructor Create(const APath: String); destructor Destroy; override; {en Create a list with cloned files. } function Clone: TFiles; procedure CloneTo(Files: TFiles); function Add(AFile: TFile): Integer; procedure Insert(AFile: TFile; AtIndex: Integer); procedure Delete(AtIndex: Integer); procedure Clear; property Count: Integer read GetCount write SetCount; property Items[Index: Integer]: TFile read Get write Put; default; property List: TFPList read FList; property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects; property Path: String read FPath write SetPath; property Flat: Boolean read FFlat write FFlat; end; {en Tree structure representing directories/files hierarchy. } TFileTreeNode = class private {en File object associated with this node. } FFile: TFile; {en Subnodes - usually files within a directory. This is a list of TFileTreeNode. } FSubNodes: TFPList; {en Additional data stored in the node. If assigned, it is automatically freed when node is destroyed. } FData: TObject; protected function Get(Index: Integer): TFileTreeNode; function GetCount: Integer; procedure SetCount(Count: Integer); procedure SetData(NewData: TObject); public constructor Create; overload; constructor Create(aFile: TFile); overload; constructor Create(aFile: TFile; DataClass: TClass); overload; destructor Destroy; override; function AddSubNode(aFile: TFile): Integer; procedure RemoveSubNode(Index: Integer); property SubNodesCount: Integer read GetCount write SetCount; property SubNodes[Index: Integer]: TFileTreeNode read Get; property TheFile: TFile read FFile; property Data: TObject read FData write SetData; end; TFileTree = TFileTreeNode; // alias implementation {$IFDEF UNIX} uses DCFileAttributes; {$ENDIF} constructor TFile.Create(const APath: String); begin inherited Create; // Name property always present. NameProperty := TFileNameProperty.Create; Path := APath; end; constructor TFile.CreateForCloning; begin // Create empty object. inherited Create; end; destructor TFile.Destroy; var AIndex: Integer; PropertyType: TFilePropertyType; begin inherited Destroy; for PropertyType := Low(FProperties) to High(FProperties) do FProperties[PropertyType].Free; for AIndex:= Low(FVariantProperties) to High(FVariantProperties) do FVariantProperties[AIndex].Free; end; function TFile.Clone: TFile; begin Result := TFile.CreateForCloning; CloneTo(Result); end; procedure TFile.CloneTo(AFile: TFile); var AIndex: Integer; PropertyType: TFilePropertyType; begin if Assigned(AFile) then begin AFile.FExtension := FExtension; AFile.FNameNoExt := FNameNoExt; AFile.FPath := FPath; AFile.FSupportedProperties := FSupportedProperties; for PropertyType := Low(FProperties) to High(FProperties) do begin if Assigned(Self.FProperties[PropertyType]) then begin AFile.FProperties[PropertyType] := Self.FProperties[PropertyType].Clone; end; end; SetLength(AFile.FVariantProperties, Length(FVariantProperties)); for AIndex:= Low(FVariantProperties) to High(FVariantProperties) do begin if Assigned(Self.FVariantProperties[AIndex]) then begin AFile.FVariantProperties[AIndex] := Self.FVariantProperties[AIndex].Clone; end; end; end; end; function TFile.Compare(AFile: TFile): TFilePropertiesTypes; var AIndex: Integer; PropertyType: TFilePropertyType; begin Result := []; if self.FPath <> AFile.FPath then begin Include(Result, TFilePropertyType.fpName); exit; end; for PropertyType := Low(FProperties) to High(FProperties) do begin if Assigned(self.FProperties[PropertyType]) then begin if not self.FProperties[PropertyType].equals(AFile.FProperties[PropertyType]) then Include(Result, PropertyType); end else begin if Assigned(AFile.FProperties[PropertyType]) then Include(Result, PropertyType); end; end; if Length(self.FVariantProperties) <> Length(AFile.FVariantProperties) then begin Include(Result, TFilePropertyType.fpVariant); exit; end; for AIndex := Low(FVariantProperties) to High(FVariantProperties) do begin if Assigned(Self.FVariantProperties[AIndex]) then begin if not self.FVariantProperties[AIndex].equals(AFile.FVariantProperties[AIndex]) then begin Include(Result, TFilePropertyType.fpVariant); exit; end; end else begin if Assigned(AFile.FVariantProperties[AIndex]) then begin Include(Result, TFilePropertyType.fpVariant); exit; end; end; end; end; procedure TFile.ClearProperties; var PropertyType: TFilePropertyType; begin ClearVariantProperties; for PropertyType := TFilePropertyType(Ord(fpName) + 1) to High(FProperties) do FreeAndNil(FProperties[PropertyType]); FSupportedProperties := [fpName]; end; procedure TFile.ClearVariantProperties; var AIndex: Integer; begin for AIndex:= Low(FVariantProperties) to High(FVariantProperties) do FreeAndNil(FVariantProperties[AIndex]); FSupportedProperties := FSupportedProperties * fpAll; end; function TFile.ReleaseProperty(PropType: TFilePropertyType): TFileProperty; var AIndex: Integer; begin if PropType in fpVariantAll then begin AIndex := Ord(PropType) - Ord(fpVariant); if (AIndex >= 0) and (AIndex <= High(FVariantProperties)) then begin Result := FVariantProperties[AIndex]; FVariantProperties[AIndex] := nil; end; end else begin Result := FProperties[PropType]; FProperties[PropType] := nil; end; Exclude(FSupportedProperties, PropType); end; function TFile.GetExtension: String; begin Result := FExtension; end; function TFile.GetNameNoExt: String; begin Result := FNameNoExt; end; function TFile.GetName: String; begin Result := TFileNameProperty(FProperties[fpName]).Value; end; procedure TFile.SetName(NewName: String); begin TFileNameProperty(FProperties[fpName]).Value := NewName; UpdateNameAndExtension(NewName); end; function TFile.GetProperty(PropType: TFilePropertyType): TFileProperty; var AIndex: Integer; begin if PropType < fpInvalid then Result := FProperties[PropType] else begin AIndex := Ord(PropType) - Ord(fpVariant); if (AIndex >= 0) and (AIndex <= High(FVariantProperties)) then Result := FVariantProperties[AIndex] else begin Result := nil; end; end; end; procedure TFile.SetProperty(PropType: TFilePropertyType; NewValue: TFileProperty); var AIndex: Integer; begin if PropType < fpInvalid then FProperties[PropType] := NewValue else begin AIndex := Ord(PropType) - Ord(fpVariant); if AIndex > High(FVariantProperties) then SetLength(FVariantProperties, AIndex + 4); FVariantProperties[AIndex]:= NewValue; end; if Assigned(NewValue) then Include(FSupportedProperties, PropType) else Exclude(FSupportedProperties, PropType); end; function TFile.GetFullPath: String; begin Result := Path + TFileNameProperty(FProperties[fpName]).Value; end; procedure TFile.SetFullPath(const NewFullPath: String); var aExtractedName: String; begin if NewFullPath <> '' then begin if NewFullPath[Length(NewFullPath)] = PathDelim then begin // Only path passed. SetPath(NewFullPath); SetName(''); end else begin aExtractedName := ExtractFileName(NewFullPath); SetPath(Copy(NewFullPath, 1, Length(NewFullPath) - Length(aExtractedName))); SetName(aExtractedName); end; end; end; procedure TFile.SetPath(const NewPath: String); begin if NewPath = '' then FPath := '' else FPath := IncludeTrailingPathDelimiter(NewPath); end; function TFile.GetAttributes: TFileAttrs; begin Result := TFileAttributesProperty(FProperties[fpAttributes]).Value; end; procedure TFile.SetAttributes(NewAttributes: TFileAttrs); begin TFileAttributesProperty(FProperties[fpAttributes]).Value := NewAttributes; UpdateNameAndExtension(Name); end; function TFile.GetSize: Int64; begin Result := TFileSizeProperty(FProperties[fpSize]).Value; end; procedure TFile.SetSize(NewSize: Int64); begin TFileSizeProperty(FProperties[fpSize]).Value := NewSize; end; function TFile.GetCompressedSize: Int64; begin Result := TFileCompressedSizeProperty(FProperties[fpCompressedSize]).Value; end; procedure TFile.SetCompressedSize(NewCompressedSize: Int64); begin TFileCompressedSizeProperty(FProperties[fpCompressedSize]).Value := NewCompressedSize; end; function TFile.GetModificationTime: TDateTime; begin Result := TFileModificationDateTimeProperty(FProperties[fpModificationTime]).Value; end; procedure TFile.SetModificationTime(NewTime: TDateTime); begin TFileModificationDateTimeProperty(FProperties[fpModificationTime]).Value := NewTime; end; function TFile.GetCreationTime: TDateTime; begin Result := TFileCreationDateTimeProperty(FProperties[fpCreationTime]).Value; end; procedure TFile.SetCreationTime(NewTime: TDateTime); begin TFileCreationDateTimeProperty(FProperties[fpCreationTime]).Value := NewTime; end; function TFile.GetLastAccessTime: TDateTime; begin Result := TFileLastAccessDateTimeProperty(FProperties[fpLastAccessTime]).Value; end; procedure TFile.SetLastAccessTime(NewTime: TDateTime); begin TFileLastAccessDateTimeProperty(FProperties[fpLastAccessTime]).Value := NewTime; end; function TFile.GetIsLinkToDirectory: Boolean; begin if fpLink in SupportedProperties then Result := TFileLinkProperty(FProperties[fpLink]).IsLinkToDirectory else Result := False; end; procedure TFile.SetIsLinkToDirectory(NewValue: Boolean); begin TFileLinkProperty(FProperties[fpLink]).IsLinkToDirectory := NewValue; end; function TFile.GetType: String; begin Result := TFileTypeProperty(FProperties[fpType]).Value; end; procedure TFile.SetType(NewValue: String); begin TFileTypeProperty(FProperties[fpType]).Value := NewValue; end; function TFile.GetNameProperty: TFileNameProperty; begin Result := TFileNameProperty(FProperties[fpName]); end; procedure TFile.SetNameProperty(NewValue: TFileNameProperty); begin FProperties[fpName] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpName) else Exclude(FSupportedProperties, fpName); end; function TFile.GetAttributesProperty: TFileAttributesProperty; begin Result := TFileAttributesProperty(FProperties[fpAttributes]); end; procedure TFile.SetAttributesProperty(NewValue: TFileAttributesProperty); begin FProperties[fpAttributes] := NewValue; if Assigned(NewValue) then begin Include(FSupportedProperties, fpAttributes); UpdateNameAndExtension(Name); end else Exclude(FSupportedProperties, fpAttributes); end; function TFile.GetSizeProperty: TFileSizeProperty; begin Result := TFileSizeProperty(FProperties[fpSize]); end; procedure TFile.SetSizeProperty(NewValue: TFileSizeProperty); begin FProperties[fpSize] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpSize) else Exclude(FSupportedProperties, fpSize); end; function TFile.GetCompressedSizeProperty: TFileCompressedSizeProperty; begin Result := TFileCompressedSizeProperty(FProperties[fpCompressedSize]); end; procedure TFile.SetCompressedSizeProperty(NewValue: TFileCompressedSizeProperty); begin FProperties[fpCompressedSize] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpCompressedSize) else Exclude(FSupportedProperties, fpCompressedSize); end; function TFile.GetModificationTimeProperty: TFileModificationDateTimeProperty; begin Result := TFileModificationDateTimeProperty(FProperties[fpModificationTime]); end; procedure TFile.SetModificationTimeProperty(NewValue: TFileModificationDateTimeProperty); begin FProperties[fpModificationTime] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpModificationTime) else Exclude(FSupportedProperties, fpModificationTime); end; function TFile.GetCreationTimeProperty: TFileCreationDateTimeProperty; begin Result := TFileCreationDateTimeProperty(FProperties[fpCreationTime]); end; procedure TFile.SetCreationTimeProperty(NewValue: TFileCreationDateTimeProperty); begin FProperties[fpCreationTime] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpCreationTime) else Exclude(FSupportedProperties, fpCreationTime); end; function TFile.GetLastAccessTimeProperty: TFileLastAccessDateTimeProperty; begin Result := TFileLastAccessDateTimeProperty(FProperties[fpLastAccessTime]); end; procedure TFile.SetLastAccessTimeProperty(NewValue: TFileLastAccessDateTimeProperty); begin FProperties[fpLastAccessTime] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpLastAccessTime) else Exclude(FSupportedProperties, fpLastAccessTime); end; function TFile.GetChangeTime: TDateTime; begin Result := TFileChangeDateTimeProperty(FProperties[fpChangeTime]).Value; end; procedure TFile.SetChangeTime(AValue: TDateTime); begin TFileChangeDateTimeProperty(FProperties[fpChangeTime]).Value := AValue; end; function TFile.GetChangeTimeProperty: TFileChangeDateTimeProperty; begin Result := TFileChangeDateTimeProperty(FProperties[fpChangeTime]); end; procedure TFile.SetChangeTimeProperty(AValue: TFileChangeDateTimeProperty); begin FProperties[fpChangeTime] := AValue; if Assigned(AValue) then Include(FSupportedProperties, fpChangeTime) else Exclude(FSupportedProperties, fpChangeTime); end; function TFile.GetLinkProperty: TFileLinkProperty; begin Result := TFileLinkProperty(FProperties[fpLink]); end; procedure TFile.SetLinkProperty(NewValue: TFileLinkProperty); begin FProperties[fpLink] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpLink) else Exclude(FSupportedProperties, fpLink); end; function TFile.GetOwnerProperty: TFileOwnerProperty; begin Result := TFileOwnerProperty(FProperties[fpOwner]); end; procedure TFile.SetOwnerProperty(NewValue: TFileOwnerProperty); begin FProperties[fpOwner] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpOwner) else Exclude(FSupportedProperties, fpOwner); end; function TFile.GetTypeProperty: TFileTypeProperty; begin Result := TFileTypeProperty(FProperties[fpType]); end; procedure TFile.SetTypeProperty(NewValue: TFileTypeProperty); begin FProperties[fpType] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpType) else Exclude(FSupportedProperties, fpType); end; function TFile.GetCommentProperty: TFileCommentProperty; begin Result := TFileCommentProperty(FProperties[fpComment]); end; procedure TFile.SetCommentProperty(NewValue: TFileCommentProperty); begin FProperties[fpComment] := NewValue; if Assigned(NewValue) then Include(FSupportedProperties, fpComment) else Exclude(FSupportedProperties, fpComment); end; function TFile.IsNameValid: Boolean; begin if Name <> '..' then Result := True else Result := False; end; function TFile.IsDirectory: Boolean; begin if fpAttributes in SupportedProperties then Result := TFileAttributesProperty(FProperties[fpAttributes]).IsDirectory else Result := False; end; function TFile.IsSpecial: Boolean; begin if fpAttributes in SupportedProperties then Result := TFileAttributesProperty(FProperties[fpAttributes]).IsSpecial else Result := False; end; function TFile.IsLink: Boolean; begin if fpAttributes in SupportedProperties then Result := TFileAttributesProperty(FProperties[fpAttributes]).IsLink else Result := False; end; function TFile.IsExecutable: Boolean; var FileAttributes: TFileAttributesProperty; begin if fpAttributes in SupportedProperties then begin FileAttributes := TFileAttributesProperty(FProperties[fpAttributes]); {$IF DEFINED(MSWINDOWS)} Result := not FileAttributes.IsDirectory; {$ELSEIF DEFINED(UNIX)} Result := (not FileAttributes.IsDirectory) and (FileAttributes.Value AND (S_IXUSR OR S_IXGRP OR S_IXOTH)>0); {$ELSE} Result := False; {$ENDIF} end else Result := False; end; function TFile.IsSysFile: Boolean; begin {$IF DEFINED(MSWINDOWS)} if fpAttributes in SupportedProperties then Result := TFileAttributesProperty(Properties[fpAttributes]).IsSysFile else Result := False; {$ELSEIF DEFINED(DARWIN)} if (Length(Name) > 1) and (Name[1] = '.') and (Name <> '..') then exit(true); if Name='Icon'#$0D then exit(true); exit(false); {$ELSE} // Files beginning with '.' are treated as system/hidden files on Unix. Result := (Length(Name) > 1) and (Name[1] = '.') and (Name <> '..'); {$ENDIF} end; function TFile.IsHidden: Boolean; begin if not (fpAttributes in SupportedProperties) then Result := False else begin if Properties[fpAttributes] is TNtfsFileAttributesProperty then Result := TNtfsFileAttributesProperty(Properties[fpAttributes]).IsHidden else begin // Files beginning with '.' are treated as system/hidden files on Unix. Result := (Length(Name) > 1) and (Name[1] = '.') and (Name <> '..'); end; end; end; procedure TFile.SplitIntoNameAndExtension(const FileName: string; var aFileNameOnly: string; var aExtension: string); var i : longint; begin I := Length(FileName); while (I > 0) and (FileName[I] <> ExtensionSeparator) do Dec(I); if I > 1 then begin aFileNameOnly := Copy(FileName, 1, I - 1); aExtension := Copy(FileName, I + 1, MaxInt); end else begin // For files that does not have '.' or that have only // one '.' and beginning with '.' there is no extension. aFileNameOnly := FileName; aExtension := ''; end; end; procedure TFile.UpdateNameAndExtension(const FileName: string); begin // Cache Extension and NameNoExt. if (FileName = '') or IsDirectory or IsLinkToDirectory or IsSpecial then begin // For directories there is no extension. FExtension := ''; FNameNoExt := FileName; end else begin SplitIntoNameAndExtension(FileName, FNameNoExt, FExtension); end; end; // ---------------------------------------------------------------------------- constructor TFiles.Create(const APath: String); begin inherited Create; FList := TFPList.Create; FOwnsObjects := True; Path := APath; end; destructor TFiles.Destroy; begin Clear; FreeAndNil(FList); inherited; end; function TFiles.Clone: TFiles; begin Result := TFiles.Create(Path); CloneTo(Result); end; procedure TFiles.CloneTo(Files: TFiles); var i: Integer; begin for i := 0 to FList.Count - 1 do begin Files.Add(Get(i).Clone); end; end; function TFiles.GetCount: Integer; begin Result := FList.Count; end; procedure TFiles.SetCount(Count: Integer); begin FList.Count := Count; end; function TFiles.Add(AFile: TFile): Integer; begin Result := FList.Add(AFile); end; procedure TFiles.Insert(AFile: TFile; AtIndex: Integer); begin FList.Insert(AtIndex, AFile); end; procedure TFiles.Delete(AtIndex: Integer); var p: Pointer; begin p := FList.Items[AtIndex]; TFile(p).Free; FList.Delete(AtIndex); end; procedure TFiles.Clear; var i: Integer; p: Pointer; begin if OwnsObjects then begin for i := 0 to FList.Count - 1 do begin p := FList.Items[i]; TFile(p).Free; end; end; FList.Clear; end; function TFiles.Get(Index: Integer): TFile; begin Result := TFile(FList.Items[Index]); end; procedure TFiles.Put(Index: Integer; AFile: TFile); begin FList.Items[Index] := AFile; end; procedure TFiles.SetPath(const NewPath: String); begin if NewPath = '' then FPath := '' else FPath := IncludeTrailingPathDelimiter(NewPath); end; // ---------------------------------------------------------------------------- constructor TFileTreeNode.Create; begin Create(nil); end; constructor TFileTreeNode.Create(aFile: TFile); begin FSubNodes := nil; FFile := aFile; FData := nil; inherited Create; end; constructor TFileTreeNode.Create(aFile: TFile; DataClass: TClass); begin Create(aFile); FData := DataClass.Create; end; destructor TFileTreeNode.Destroy; var i: Integer; begin inherited Destroy; FreeAndNil(FFile); if Assigned(FSubNodes) then begin for i := 0 to FSubNodes.Count - 1 do TFileTreeNode(FSubNodes.Items[i]).Free; FreeAndNil(FSubNodes); end; FreeAndNil(FData); end; function TFileTreeNode.AddSubNode(aFile: TFile): Integer; var aNode: TFileTreeNode; begin if not Assigned(FSubNodes) then FSubNodes := TFPList.Create; aNode := TFileTreeNode.Create(aFile); Result := FSubNodes.Add(aNode); end; procedure TFileTreeNode.RemoveSubNode(Index: Integer); begin if (Index >= 0) and (Index < FSubNodes.Count) then begin TFileTreeNode(FSubNodes.Items[Index]).Free; FSubNodes.Delete(Index); end; end; function TFileTreeNode.Get(Index: Integer): TFileTreeNode; begin Result := TFileTreeNode(FSubNodes.Items[Index]); end; function TFileTreeNode.GetCount: Integer; begin if Assigned(FSubNodes) then Result := FSubNodes.Count else Result := 0; end; procedure TFileTreeNode.SetCount(Count: Integer); begin if not Assigned(FSubNodes) then FSubNodes := TFPList.Create; FSubNodes.Count := Count; end; procedure TFileTreeNode.SetData(NewData: TObject); var TmpData: TObject; begin if Assigned(FData) then begin TmpData := FData; FData := NewData; TmpData.Free; end else FData := NewData; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufilefunctions.pas�������������������������������������������������������������0000644�0001750�0000144�00000050603�14743153644�017143� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Filepanel columns implementation unit Copyright (C) 2008-2020 Alexander Koblov (alexx2000@mail.ru) Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) 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, see <http://www.gnu.org/licenses/>. } unit uFileFunctions; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Menus, uFile, uFileProperty, uFileSource; type TFileFunction = (fsfName = 0, fsfExtension = 1, fsfSize = 2, fsfAttr = 3, fsfPath = 4, fsfGroup = 5, fsfOwner = 6, fsfModificationTime = 7, fsfCreationTime = 8, fsfLastAccessTime = 9, fsfChangeTime = 10, fsfLinkTo = 11, fsfNameNoExtension = 12, fsfType = 13, fsfComment = 14, fsfCompressedSize = 15, fsfInvalid = 16, fsfVariant = Ord(fpVariant), fsfMaximum = Ord(fpMaximum)); TFileFunctions = array of TFileFunction; const fsfVariantAll = [fsfVariant..fsfMaximum]; const TFileFunctionStrings: array [Low(TFileFunction)..fsfInvalid] of string = ('GETFILENAME', 'GETFILEEXT', 'GETFILESIZE', 'GETFILEATTR', 'GETFILEPATH', 'GETFILEGROUP', 'GETFILEOWNER', 'GETFILETIME', 'GETFILECREATIONTIME', 'GETFILELASTACCESSTIME', 'GETFILECHANGETIME', 'GETFILELINKTO', 'GETFILENAMENOEXT', 'GETFILETYPE', 'GETFILECOMMENT', 'GETFILECOMPRESSEDSIZE', '' // fsfInvalid ); function FormatFileFunction(FuncS: string; AFile: TFile; const AFileSource: IFileSource; RetrieveProperties: Boolean = False): string; function FormatFileFunctions(FuncS: String; AFile: TFile; const AFileSource: IFileSource): String; function GetVariantFileProperty(const FuncS: String; AFile: TFile; const AFileSource: IFileSource): Variant; function GetFileFunctionByName(FuncS: string): TFileFunction; function GetFilePropertyType(FileFunction: TFileFunction): TFilePropertiesTypes; inline; procedure FillContentFieldMenu(MenuOrMenuItem: TObject; OnMenuItemClick: TNotifyEvent; const FileSystem: String = ''); procedure FillFileFuncList; const sFuncTypeDC = 'DC'; sFuncTypePlugin = 'PLUGIN'; var FileFunctionsStr: TStringList; implementation uses StrUtils, WdxPlugin, uWdxModule, uGlobs, uLng, uDefaultFilePropertyFormatter, uFileSourceProperty, uWfxPluginFileSource, uWfxModule, uColumns, DCFileAttributes, DCStrUtils, DCBasicTypes, Variants, uDCUtils, uTypes; const ATTR_OCTAL = 'OCTAL'; //***Note: Number of elements in "FILE_SIZE" should normally fit with the number of element in "TFileSizeFormat" we have in "uTypes" unit.: FILE_SIZE: array[0..11] of String = ('FLOAT', 'BYTE', 'KILO', 'MEGA', 'GIGA', 'TERA', 'PERSFLOAT', 'PERSBYTE', 'PERSKILO', 'PERSMEGA', 'PERSGIGA', 'PERSTERA'); // Which file properties must be supported for each file function to work. const TFileFunctionToProperty: array [Low(TFileFunction)..fsfInvalid] of TFilePropertiesTypes = ([fpName], [fpName], [fpSize], [fpAttributes], [] { path }, [fpOwner], [fpOwner], [fpModificationTime], [fpCreationTime], [fpLastAccessTime], [fpChangeTime], [fpLink], [fpName], [fpType], [fpComment], [fpCompressedSize], [] { invalid }); //Return type (Script or DC or Plugin etc) function GetModType(str: String): String; begin if pos('(', Str) > 0 then Result := Copy(Str, 1, pos('(', Str) - 1) else Result := EmptyStr; end; //Return name in (). (SriptName or PluginName etc) function GetModName(str: String): String; var s: String; begin s := str; if pos('(', S) > 0 then Delete(s, 1, pos('(', S)) else Exit(EmptyStr); if pos(')', s) > 0 then Result := Copy(s, 1, pos(')', s) - 1); end; //Return function name (DCFunction,PluginFunction etc) function GetModFunctionName(str: String): String; var s: String; begin s := str; if pos('.', S) > 0 then Delete(s, 1, pos('.', S)) else Exit(EmptyStr); if pos('{', S) > 0 then Result := Copy(s, 1, pos('{', S) - 1); end; // Return function parameters function GetModFunctionParams(str: String): String; var I: Integer; S: String; begin S := str; I := pos('{', S); if I < 0 then Exit(EmptyStr); Delete(S, 1, I); I := pos('}', S); if I < 0 then Exit(EmptyStr); Result := Copy(S, 1, I - 1); end; function FormatFileFunction(FuncS: string; AFile: TFile; const AFileSource: IFileSource; RetrieveProperties: Boolean): string; var AIndex: Integer; AValue: Variant; FileFunction: TFileFunction; AType, AFunc, AParam: String; AFileProperty: TFileVariantProperty; FilePropertiesNeeded: TFilePropertiesTypes; begin Result := EmptyStr; //--------------------- AType := upcase(GetModType(FuncS)); AFunc := upcase(GetModFunctionName(FuncS)); AParam := upcase(GetModFunctionParams(FuncS)); //--------------------- //Internal doublecmd function //------------------------------------------------------ if AType = sFuncTypeDC then begin AIndex:= FileFunctionsStr.IndexOfName(AFunc); if AIndex < 0 then Exit; FileFunction:= TFileFunction(AIndex); // Retrieve additional properties if needed if RetrieveProperties then begin FilePropertiesNeeded:= TFileFunctionToProperty[FileFunction]; if aFileSource.CanRetrieveProperties(AFile, FilePropertiesNeeded) then aFileSource.RetrieveProperties(AFile, FilePropertiesNeeded, []); end; case FileFunction of fsfName: begin // Show square brackets around directories if gDirBrackets and (AFile.IsDirectory or AFile.IsLinkToDirectory) then Result := gFolderPrefix + AFile.Name + gFolderPostfix else Result := AFile.Name; end; fsfExtension: begin Result := AFile.Extension; end; fsfSize: begin if (AFile.IsDirectory or AFile.IsLinkToDirectory) and ((not (fpSize in AFile.SupportedProperties)) or (AFile.Size = 0)) then begin if AFile.IsLinkToDirectory then Result := rsAbbrevDisplayLink else Result := rsAbbrevDisplayDir; end else if fpSize in AFile.SupportedProperties then begin if AFile.IsDirectory and (AFile.Size < 0) then begin case AFile.Size of FOLDER_SIZE_ZERO: Result := '0'; FOLDER_SIZE_WAIT: Result := '??'; FOLDER_SIZE_CALC: Result := '--'; FOLDER_SIZE_ERRO: Result := '0?'; end; end else if AFile.SizeProperty.IsValid then begin if Length(AParam) = 0 then Result := AFile.Properties[fpSize].Format(DefaultFilePropertyFormatter) else begin for AIndex:= 0 to High(FILE_SIZE) do begin if AParam = FILE_SIZE[AIndex] then begin Result := cnvFormatFileSize(AFile.Size, TFileSizeFormat(AIndex), gFileSizeDigits); Break; end; end; end; end; end; end; fsfAttr: if fpAttributes in AFile.SupportedProperties then begin if (AFile.Properties[fpAttributes] is TUnixFileAttributesProperty) and (AParam = ATTR_OCTAL) then Result := FormatUnixModeOctal(AFile.Attributes) else Result := AFile.Properties[fpAttributes].Format(DefaultFilePropertyFormatter); end; fsfPath: Result := AFile.Path; fsfGroup: if fpOwner in AFile.SupportedProperties then Result := AFile.OwnerProperty.GroupStr; fsfOwner: if fpOwner in AFile.SupportedProperties then Result := AFile.OwnerProperty.OwnerStr; fsfModificationTime: if fpModificationTime in AFile.SupportedProperties then begin if AFile.ModificationTimeProperty.IsValid then begin if Length(AParam) > 0 then Result := SysUtils.FormatDateTime(AParam, AFile.ModificationTime) else Result := AFile.Properties[fpModificationTime].Format(DefaultFilePropertyFormatter); end; end; fsfCreationTime: if fpCreationTime in AFile.SupportedProperties then begin if Length(AParam) > 0 then Result := SysUtils.FormatDateTime(AParam, AFile.CreationTime) else Result := AFile.Properties[fpCreationTime].Format(DefaultFilePropertyFormatter); end; fsfLastAccessTime: if fpLastAccessTime in AFile.SupportedProperties then begin if Length(AParam) > 0 then Result := SysUtils.FormatDateTime(AParam, AFile.LastAccessTime) else Result := AFile.Properties[fpLastAccessTime].Format(DefaultFilePropertyFormatter); end; fsfChangeTime: if fpChangeTime in AFile.SupportedProperties then begin if Length(AParam) > 0 then Result := SysUtils.FormatDateTime(AParam, AFile.ChangeTime) else Result := AFile.Properties[fpChangeTime].Format(DefaultFilePropertyFormatter); end; fsfLinkTo: if fpLink in AFile.SupportedProperties then Result := AFile.LinkProperty.LinkTo; fsfNameNoExtension: begin // Show square brackets around directories if gDirBrackets and (AFile.IsDirectory or AFile.IsLinkToDirectory) then Result := gFolderPrefix + AFile.NameNoExt + gFolderPostfix else Result := AFile.NameNoExt; end; fsfType: if fpType in AFile.SupportedProperties then Result := AFile.TypeProperty.Format(DefaultFilePropertyFormatter); fsfComment: if fpComment in AFile.SupportedProperties then Result := AFile.CommentProperty.Format(DefaultFilePropertyFormatter); fsfCompressedSize: begin if (AFile.IsDirectory or AFile.IsLinkToDirectory) and ((not (fpCompressedSize in AFile.SupportedProperties)) or (AFile.CompressedSize = 0)) then begin if AFile.IsLinkToDirectory then Result := rsAbbrevDisplayLink else Result := rsAbbrevDisplayDir; end else if fpCompressedSize in AFile.SupportedProperties then Result := AFile.Properties[fpCompressedSize].Format(DefaultFilePropertyFormatter); end; end; end //------------------------------------------------------ //Plugin function //------------------------------------------------------ else if AType = sFuncTypePlugin then begin // Retrieve additional properties if needed if RetrieveProperties then begin AValue:= GetVariantFileProperty(FuncS, AFile, AFileSource); if not VarIsBool(AValue) then Result := AValue else if AValue then Result := rsSimpleWordTrue else Result := rsSimpleWordFalse; end else begin for AIndex:= 0 to High(AFile.VariantProperties) do begin AFileProperty:= TFileVariantProperty(AFile.VariantProperties[AIndex]); if Assigned(AFileProperty) and SameText(FuncS, AFileProperty.Name) then begin Result:= AFileProperty.Format(DefaultFilePropertyFormatter); Break; end; end; end; end; //------------------------------------------------------ end; function FormatFileFunctions(FuncS: String; AFile: TFile; const AFileSource: IFileSource): String; var P: Integer; begin Result:= EmptyStr; while True do begin P := Pos('[', FuncS); if P = 0 then Break else if P > 1 then Result:= Result + Copy(FuncS, 1, P - 1); Delete(FuncS, 1, P); P := Pos(']', FuncS); if P = 0 then Break else if P > 1 then Result:= Result + FormatFileFunction(Copy(FuncS, 1, P - 1), AFile, AFileSource, True); Delete(FuncS, 1, P); end; if Length(FuncS) <> 0 then Result:= Result + FuncS; end; function GetFileFunctionByName(FuncS: String): TFileFunction; var AIndex: Integer; AType, AFunc: String; begin AType := UpCase(GetModType(FuncS)); AFunc := UpCase(GetModFunctionName(FuncS)); // Only internal DC functions. if AType = sFuncTypeDC then begin AIndex := FileFunctionsStr.IndexOfName(AFunc); if AIndex >= 0 then Exit(TFileFunction(AIndex)); end else if AType = sFuncTypePlugin then Exit(fsfVariant); Result := fsfInvalid; end; function GetVariantFileProperty(const FuncS: String; AFile: TFile; const AFileSource: IFileSource): Variant; var AType, AName, AFunc, AParam: String; begin Result := Unassigned; //--------------------- AType := upcase(GetModType(FuncS)); AName := upcase(GetModName(FuncS)); AFunc := upcase(GetModFunctionName(FuncS)); AParam := upcase(GetModFunctionParams(FuncS)); //------------------------------------------------------ //Plugin function //------------------------------------------------------ if AType = sFuncTypePlugin then begin if AFileSource.IsClass(TWfxPluginFileSource) then begin with AFileSource as IWfxPluginFileSource do begin if WfxModule.ContentPlugin and WfxModule.FileParamVSDetectStr(AFile) then begin Result := WfxModule.CallContentGetValueV(AFile.FullPath, AFunc, AParam, 0); end; end; end else if fspDirectAccess in AFileSource.Properties then begin if not gWdxPlugins.IsLoaded(AName) then if not gWdxPlugins.LoadModule(AName) then Exit; if gWdxPlugins.GetWdxModule(AName).FileParamVSDetectStr(AFile) then begin Result := gWdxPlugins.GetWdxModule(AName).CallContentGetValueV( AFile.FullPath, AFunc, AParam, 0); end; end; end; //------------------------------------------------------ end; function GetFilePropertyType(FileFunction: TFileFunction): TFilePropertiesTypes; begin if FileFunction >= fsfVariant then Result:= [TFilePropertyType(FileFunction)] else begin Result:= TFileFunctionToProperty[FileFunction]; end; end; procedure AddModule(MenuItem: TMenuItem; OnMenuItemClick: TNotifyEvent; Module: TWDXModule); var J, K: Integer; MI, MI2: TMenuItem; WdxField: TWdxField; begin MI:= TMenuItem.Create(MenuItem); MI.Caption:= Module.Name; MenuItem.Add(MI); // Load fields list for J:= 0 to Module.FieldList.Count - 1 do begin WdxField:= TWdxField(Module.FieldList.Objects[J]); if not (WdxField.FType in [ft_fulltext, ft_fulltextw]) then begin MI:= TMenuItem.Create(MenuItem); MI.Tag:= 1; MI.Caption:= WdxField.LName; MI.Hint:= Module.FieldList[J]; MenuItem.Items[MenuItem.Count - 1].Add(MI); if WdxField.FType <> ft_multiplechoice then begin for K:= 0 to High(WdxField.FUnits) do begin MI2:=TMenuItem.Create(MenuItem); MI2.Tag:= 2; MI2.Caption:= WdxField.LUnits[K]; MI2.Hint:= WdxField.FUnits[K]; MI2.OnClick:= OnMenuItemClick; MI.Add(MI2); end; end; if MI.Count = 0 then MI.OnClick:= OnMenuItemClick; end; end; end; procedure FillContentFieldMenu(MenuOrMenuItem: TObject; OnMenuItemClick: TNotifyEvent; const FileSystem: String); var I, J: Integer; MI, MI2, localMenuItem: TMenuItem; Module: TWDXModule; FileSize: TDynamicStringArray; begin if MenuOrMenuItem.ClassType = TPopupMenu then localMenuItem := TPopupMenu(MenuOrMenuItem).Items else localMenuItem := TMenuItem(MenuOrMenuItem); localMenuItem.Clear; // DC commands MI:= TMenuItem.Create(localMenuItem); MI.Caption:= 'DC'; localMenuItem.Add(MI); for I:= 0 to FileFunctionsStr.Count - 1 do begin MI:= TMenuItem.Create(localMenuItem); MI.Tag:= 0; MI.Hint:= FileFunctionsStr.Names[I]; MI.Caption:= FileFunctionsStr.ValueFromIndex[I] + ' (' + MI.Hint + ')'; localMenuItem.Items[0].Add(MI); // Special case for attributes if TFileFunctionStrings[fsfAttr] = FileFunctionsStr.Names[I] then begin // String attributes MI2:= TMenuItem.Create(localMenuItem); MI2.Tag:= 3; MI2.Hint:= ''; MI2.Caption:= rsMnuContentDefault; MI2.OnClick:= OnMenuItemClick; MI.Add(MI2); // Octal attributes MI2:= TMenuItem.Create(localMenuItem); MI2.Tag:= 3; MI2.Hint:= ATTR_OCTAL; MI2.Caption:= rsMnuContentOctal; MI2.OnClick:= OnMenuItemClick; MI.Add(MI2); end; // Special case for size if TFileFunctionStrings[fsfSize] = FileFunctionsStr.Names[I] then begin // Default format MI2:= TMenuItem.Create(localMenuItem); MI2.Tag:= 3; MI2.Hint:= ''; MI2.Caption:= rsMnuContentDefault; MI2.OnClick:= OnMenuItemClick; MI.Add(MI2); FileSize:= SplitString(rsOptFileSizeFloat + ';' + rsLegacyOperationByteSuffixLetter + ';' + rsLegacyDisplaySizeSingleLetterKilo + ';' + rsLegacyDisplaySizeSingleLetterMega + ';' + rsLegacyDisplaySizeSingleLetterGiga + ';' + rsLegacyDisplaySizeSingleLetterTera + ';' + rsOptPersonalizedFileSizeFormat, ';'); for J:= 0 to High(FILE_SIZE) do begin MI2:= TMenuItem.Create(localMenuItem); MI2.Tag:= 3; MI2.Hint:= FILE_SIZE[J]; MI2.Caption:= FileSize[J]; MI2.OnClick:= OnMenuItemClick; MI.Add(MI2); end; end; if MI.Count = 0 then MI.OnClick:= OnMenuItemClick; end; // Plugins if (FileSystem = EmptyStr) or SameText(FileSystem, FS_GENERAL) then begin MI:= TMenuItem.Create(localMenuItem); MI.Caption:= rsOptionsEditorPlugins; localMenuItem.Add(MI); for I:= 0 to gWdxPlugins.Count - 1 do begin Module:= gWdxPlugins.GetWdxModule(I); if not (Module.IsLoaded or Module.LoadModule) then Continue; AddModule(MI, OnMenuItemClick, Module); end; end else begin I:= gWFXPlugins.IndexOfName(FileSystem); if (I >= 0) then begin Module:= gWFXPlugins.LoadModule(gWFXPlugins.FileName[I]); if Assigned(Module) and TWfxModule(Module).ContentPlugin then AddModule(localMenuItem, OnMenuItemClick, Module); end; end; end; procedure FillFileFuncList; begin with FileFunctionsStr do begin Add(TFileFunctionStrings[fsfName] + '=' + rsFuncName); Add(TFileFunctionStrings[fsfExtension] + '=' + rsFuncExt); Add(TFileFunctionStrings[fsfSize] + '=' + rsFuncSize); Add(TFileFunctionStrings[fsfAttr] + '=' + rsFuncAttr); Add(TFileFunctionStrings[fsfPath] + '=' + rsFuncPath); Add(TFileFunctionStrings[fsfGroup] + '=' + rsFuncGroup); Add(TFileFunctionStrings[fsfOwner] + '=' + rsFuncOwner); Add(TFileFunctionStrings[fsfModificationTime] + '=' + rsFuncMTime); Add(TFileFunctionStrings[fsfCreationTime] + '=' + rsFuncCTime); Add(TFileFunctionStrings[fsfLastAccessTime] + '=' + rsFuncATime); Add(TFileFunctionStrings[fsfChangeTime] + '=' + rsFuncHTime); Add(TFileFunctionStrings[fsfLinkTo] + '=' + rsFuncLinkTo); Add(TFileFunctionStrings[fsfNameNoExtension] + '=' + rsFuncNameNoExt); Add(TFileFunctionStrings[fsfType] + '=' + rsFuncType); Add(TFileFunctionStrings[fsfComment] + '=' + rsFuncComment); Add(TFileFunctionStrings[fsfCompressedSize] + '=' + rsFuncCompressedSize); end; end; initialization FileFunctionsStr := TStringList.Create; finalization FreeAndNil(FileFunctionsStr); end. �����������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufilepanelselect.pas�����������������������������������������������������������0000644�0001750�0000144�00000000231�14743153644�017422� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFilePanelSelect; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type TFilePanelSelect = (fpLeft, fpRight); implementation end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufileprocs.pas�����������������������������������������������������������������0000644�0001750�0000144�00000020466�14743153644�016265� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz some file routines contributors: Mattias Gaertner (from Lazarus code) Copyright (C) 2007-2010 Koblov Alexander (Alexx2000@mail.ru) } unit uFileProcs; {$mode objfpc}{$H+} interface uses Classes; {en Create a chain of directories @param(DirectoryName The full path to directory) @returns(@true if DirectoryName already existed or was created succesfully. If it failed to create any of the parts, @false is returned.) } function mbForceDirectory(DirectoryName: string): boolean; {en Copies a file. @param(sSrc String expression that specifies the name of the file to be copied) @param(sDst String expression that specifies the target file name) @returns(The function returns @true if successful, @false otherwise) } function CopyFile(const sSrc, sDst: String; bAppend: Boolean = False): Boolean; {en Remove the contents of directory recursively @param(sFolderName String expression that specifies the name of the folder to be removed) } procedure DelTree(const sFolderName: String); {en Write string to a text file and append newline @param(hFile Handle of file) @param(S String for writing) } procedure FileWriteLn(hFile: THandle; S: String); function GetNextCopyName(FileName: String; IsDirectory: Boolean): String; function mbFileIsText(const FileName: String): Boolean; function mbReadFileToString(const FileName: String): String; implementation uses LCLProc, Dialogs, SysUtils, uLng, uGlobs, DCClassesUtf8, DCStrUtils, DCOSUtils, uFileSystemFileSource, uFile, uFileSystemDeleteOperation, uFileSourceOperationOptions, uAdministrator; const cBlockSize=16384; // size of block if copyfile // if pb is assigned > use, else work without pb :-) function CopyFile(const sSrc, sDst: String; bAppend: Boolean): Boolean; var src: TFileStreamEx = nil; dst: TFileStreamEx = nil; iDstBeg:Integer; // in the append mode we store original size Buffer: PChar = nil; CopyPropertiesOptions: TCopyAttributesOptions; begin Result:=False; if not mbFileExists(sSrc) then Exit; GetMem(Buffer,cBlockSize+1); try try src:=TFileStreamEx.Create(sSrc,fmOpenRead or fmShareDenyNone); if not Assigned(src) then Exit; if bAppend then begin dst:=TFileStreamEx.Create(sDst,fmOpenReadWrite); dst.Seek(0,soFromEnd); // seek to end end else dst:=TFileStreamEx.Create(sDst,fmCreate); if not Assigned(dst) then Exit; iDstBeg:=dst.Size; // we dont't use CopyFrom, because it's alocate and free buffer every time is called while (dst.Size+cBlockSize)<= (src.Size+iDstBeg) do begin Src.ReadBuffer(Buffer^, cBlockSize); dst.WriteBuffer(Buffer^, cBlockSize); end; if (iDstBeg+src.Size)>dst.Size then begin // dst.CopyFrom(src,src.Size-dst.size); src.ReadBuffer(Buffer^, src.Size+iDstBeg-dst.size); dst.WriteBuffer(Buffer^, src.Size+iDstBeg-dst.size); end; CopyPropertiesOptions := CopyAttributesOptionCopyAll; if gDropReadOnlyFlag then Include(CopyPropertiesOptions, caoRemoveReadOnlyAttr); Result := mbFileCopyAttr(sSrc, sDst, CopyPropertiesOptions) = []; // chmod, chgrp except on EStreamError do MessageDlg('Error', Format(rsMsgErrCannotCopyFile, [sSrc, sDst]), mtError, [mbOK], 0); end; finally if assigned(src) then FreeAndNil(src); if assigned(dst) then FreeAndNil(dst); if assigned(Buffer) then FreeMem(Buffer); end; end; procedure DelTree(const sFolderName: String); var DeleteOperation: TFileSystemDeleteOperation = nil; aFiles: TFiles = nil; begin aFiles := TFiles.Create(sFolderName); try aFiles.Add(TFileSystemFileSource.CreateFileFromFile(sFolderName)); DeleteOperation := TFileSystemDeleteOperation.Create( TFileSystemFileSource.GetFileSource, aFiles); DeleteOperation.DeleteReadOnly := fsoogYes; DeleteOperation.SymLinkOption := fsooslDontFollow; DeleteOperation.SkipErrors := True; DeleteOperation.Execute; finally FreeAndNil(aFiles); FreeAndNil(DeleteOperation); end; end; procedure FileWriteLn(hFile: THandle; S: String); begin S:= S + LineEnding; FileWrite(hFile, PAnsiChar(S)^, Length(S)); end; function mbForceDirectory(DirectoryName: string): boolean; var i: integer; sDir: string; begin if DirectoryName = '' then Exit; DirectoryName := IncludeTrailingPathDelimiter(DirectoryName); i:= 1; if Pos('\\', DirectoryName) = 1 then // if network path begin i := CharPos(PathDelim, DirectoryName, 3); // index of the end of computer name i := CharPos(PathDelim, DirectoryName, i + 1); // index of the end of first remote directory end; // Move past path delimiter at the beginning. if (i = 1) and (DirectoryName[i] = PathDelim) then i := i + 1; while i<=length(DirectoryName) do begin if DirectoryName[i]=PathDelim then begin sDir:=copy(DirectoryName,1,i-1); if not mbDirectoryExists(sDir) then begin Result:=mbCreateDir(sDir); if not Result then exit; end; end; Inc(i); end; Result := True; end; function GetNextCopyName(FileName: String; IsDirectory: Boolean): String; var CopyNumber: Int64 = 1; sFilePath, sFileName, SuffixStr: String; begin SuffixStr:= ''; sFilePath:= ExtractFilePath(FileName); sFileName:= ExtractFileName(FileName); repeat case gTypeOfDuplicatedRename of drLegacyWithCopy: begin {$IFDEF UNIX} if (Length(sFileName) > 0) and (sFileName[1] = ExtensionSeparator) then Result := sFilePath + ExtensionSeparator + Format(rsCopyNameTemplate, [CopyNumber, Copy(sFileName, 2, MaxInt)]) else {$ENDIF} Result := sFilePath + Format(rsCopyNameTemplate, [CopyNumber, sFileName]); end; drLikeWindows7, drLikeTC: begin if IsDirectory then Result := FileName + SuffixStr else Result := sFilePath + RemoveFileExt(sFileName) + SuffixStr + ExtractFileExt(sFileName); end; end; Inc(CopyNumber); case gTypeOfDuplicatedRename of drLikeWindows7: SuffixStr:= ' (' + IntToStr(CopyNumber) + ')'; drLikeTC: SuffixStr:= '(' + IntToStr(CopyNumber) + ')'; end; until not mbFileSystemEntryExists(Result); end; function mbFileIsText(const FileName: String): Boolean; const BUF_LEN = 4096; var Len: Integer; H, L: Integer; Wide: Boolean; Buffer: String; Handle: THandle; P, F: PAnsiChar; begin Handle:= FileOpenUAC(FileName, fmOpenRead or fmShareDenyNone); if (Handle = feInvalidHandle) then Exit(False); try Wide:= False; SetLength(Buffer{%H-}, BUF_LEN); Len:= FileRead(Handle, Buffer[1], BUF_LEN); if Len > 0 then begin P:= PAnsiChar(Buffer); F:= P + Len; // UTF-8 BOM if (P[0] = #$EF) and (P[1] = #$BB) and (P[2] = #$BF) then begin Inc(P, 3); end // UTF-16LE BOM else if (P[0] = #$FF) and (P[1] = #$FE) then begin H:= 1; L:= 0; Inc(P, 2); Wide:= True; end // UTF-16BE BOM else if (P[0] = #$FE) and (P[1] = #$FF) then begin H:= 0; L:= 1; Inc(P, 2); Wide:= True; end; if not Wide then begin while P < F do begin case P^ of #0..#8, #11, #14..#25, #27..#31: Exit(False); end; Inc(P); end; end else begin while P < F do begin if P[H] = #0 then begin case P[L] of #0..#8, #11, #14..#25, #27..#31: Exit(False); end; end; Inc(P, 2); end; end; end; finally FileClose(Handle); end; Result:= True; end; function mbReadFileToString(const FileName: String): String; var ASize: Int64; Handle: THandle; begin Result:= EmptyStr; Handle:= mbFileOpen(FileName, fmOpenRead or fmShareDenyNone); if Handle <> feInvalidHandle then begin ASize:= FileGetSize(Handle); SetLength(Result, ASize); if Length(Result) > 0 then begin if FileRead(Handle, Result[1], ASize) <> ASize then begin SetLength(Result, 0); end; end; FileClose(Handle); end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufileproperty.pas��������������������������������������������������������������0000644�0001750�0000144�00000074415�14743153644�017026� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileProperty; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes; const FOLDER_SIZE_UNKN = 0; FOLDER_SIZE_ZERO = -1; FOLDER_SIZE_WAIT = -2; FOLDER_SIZE_CALC = -3; FOLDER_SIZE_ERRO = -4; type TFilePropertyType = ( fpName = 0, fpSize = 1, // = fpUncompressedSize fpCompressedSize = 2, fpOwner = 3, fpAttributes = 4, fpModificationTime = 5, fpCreationTime = 6, fpLastAccessTime = 7, fpChangeTime = 8, fpLink = 9, fpType = 10, fpComment = 11, fpInvalid = 12, fpVariant = 128, fpMaximum = 255 ); const fpAll = [Low(TFilePropertyType) .. fpInvalid]; fpVariantAll = [fpVariant .. High(TFilePropertyType)]; type TFilePropertiesTypes = set of TFilePropertyType; TFilePropertiesDescriptions = array of String;//TFileProperty; EInvalidFileProperty = class(Exception); // Forward declarations. IFilePropertyFormatter = interface; { TFileProperty } TFileProperty = class private public constructor Create; virtual; function Clone: TFileProperty; virtual; procedure CloneTo({%H-}FileProperty: TFileProperty); virtual; // Text description of the property. // Don't know if it will be really needed. class function GetDescription: String; virtual abstract; class function GetID: TFilePropertyType; virtual abstract; function AsString: String; virtual; // Formats the property value as a string using some formatter object. function Format(Formatter: IFilePropertyFormatter): String; virtual abstract; end; TFileVariantProperties = array of TFileProperty; TFileProperties = array [Low(TFilePropertyType)..fpInvalid] of TFileProperty//class(TList) { A list of TFileProperty. It would allow to query properties by index and name and by TFilePropertyType. Implement Clone if made into a class. } //end ; // -- Concrete properties --------------------------------------------------- TFileNameProperty = class(TFileProperty) private FName: String; // only name, no path procedure SetName(NewName: String); public constructor Create; override; constructor Create(Name: String); virtual; overload; function Clone: TFileNameProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; function Format(Formatter: IFilePropertyFormatter): String; override; property Value: String read FName write SetName; end; TFileSizeProperty = class(TFileProperty) private FSize: Int64; FIsValid: Boolean; public constructor Create; override; constructor Create(Size: Int64); virtual; overload; function Clone: TFileSizeProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; // Retrieve possible values for the property. function GetMinimumValue: Int64; function GetMaximumValue: Int64; function Format(Formatter: IFilePropertyFormatter): String; override; property IsValid: Boolean read FIsValid write FIsValid; property Value: Int64 read FSize write FSize; end; { TFileCompressedSizeProperty } TFileCompressedSizeProperty = class(TFileSizeProperty) public function Clone: TFileCompressedSizeProperty; override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; end; { TFileDateTimeProperty } TFileDateTimeProperty = class(TFileProperty) private FIsValid: Boolean; FDateTime: TDateTime; public constructor Create; override; constructor Create(FileTime: TFileTime); virtual; overload; constructor Create(DateTime: TDateTime); virtual; overload; procedure CloneTo(FileProperty: TFileProperty); override; function Equals(p: TObject): Boolean; override; // Retrieve possible values for the property. function GetMinimumValue: TDateTime; function GetMaximumValue: TDateTime; property IsValid: Boolean read FIsValid write FIsValid; property Value: TDateTime read FDateTime write FDateTime; end; TFileModificationDateTimeProperty = class(TFileDateTimeProperty) public function Clone: TFileModificationDateTimeProperty; override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Format(Formatter: IFilePropertyFormatter): String; override; end; TFileCreationDateTimeProperty = class(TFileDateTimeProperty) public function Clone: TFileCreationDateTimeProperty; override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Format(Formatter: IFilePropertyFormatter): String; override; end; TFileLastAccessDateTimeProperty = class(TFileDateTimeProperty) public function Clone: TFileLastAccessDateTimeProperty; override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Format(Formatter: IFilePropertyFormatter): String; override; end; { TFileChangeDateTimeProperty } TFileChangeDateTimeProperty = class(TFileDateTimeProperty) public function Clone: TFileChangeDateTimeProperty; override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Format(Formatter: IFilePropertyFormatter): String; override; end; {en File system attributes. } TFileAttributesProperty = class(TFileProperty) private FAttributes: TFileAttrs; public constructor Create; override; constructor Create(Attr: TFileAttrs); virtual; overload; class function CreateOSAttributes: TFileAttributesProperty; overload; class function CreateOSAttributes(Attr: TFileAttrs): TFileAttributesProperty; overload; function Clone: TFileAttributesProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; function Equals(p: TObject): Boolean; override; class function GetID: TFilePropertyType; override; function IsNativeAttributes: Boolean; // Is the file a directory. function IsDirectory: Boolean; virtual; function IsSpecial: Boolean; virtual; // Is this a system file. function IsSysFile: boolean; virtual abstract; // Is it a symbolic link. function IsLink: Boolean; virtual; // Retrieves raw attributes. function GetAttributes: TFileAttrs; virtual; // Sets raw attributes. procedure SetAttributes(Attributes: TFileAttrs); virtual; property Value: TFileAttrs read GetAttributes write SetAttributes; end; { TNtfsFileAttributesProperty } TNtfsFileAttributesProperty = class(TFileAttributesProperty) public function Clone: TNtfsFileAttributesProperty; override; // Is the file a directory. function IsDirectory: Boolean; override; function IsSpecial: Boolean; override; // Is this a system file. function IsSysFile: boolean; override; // Is it a symbolic link. function IsLink: Boolean; override; function IsReadOnly: Boolean; function IsHidden: Boolean; class function GetDescription: String; override; function Format(Formatter: IFilePropertyFormatter): String; override; end; { TUnixFileAttributesProperty } TUnixFileAttributesProperty = class(TFileAttributesProperty) public function Clone: TUnixFileAttributesProperty; override; // Is the file a directory. function IsDirectory: Boolean; override; // Is this a system file. function IsSysFile: boolean; override; // Is it a symbolic link. function IsLink: Boolean; override; function IsOwnerRead: Boolean; function IsOwnerWrite: Boolean; function IsOwnerExecute: Boolean; // ... class function GetDescription: String; override; function Format(Formatter: IFilePropertyFormatter): String; override; end; { TFileLinkProperty } TFileLinkProperty = class(TFileProperty) private FIsLinkToDirectory: Boolean; FIsValid: Boolean; FLinkTo: String; public constructor Create; override; function Clone: TFileLinkProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; function Format({%H-}Formatter: IFilePropertyFormatter): String; override; property IsLinkToDirectory: Boolean read FIsLinkToDirectory write FIsLinkToDirectory; property IsValid: Boolean read FIsValid write FIsValid; property LinkTo: String read FLinkTo write FLinkTo; end; { TFileOwnerProperty } {en Owner of the file. } TFileOwnerProperty = class(TFileProperty) private FOwner: Cardinal; FGroup: Cardinal; FOwnerStr: String; FGroupStr: String; public constructor Create; override; function Clone: TFileOwnerProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; function Format({%H-}Formatter: IFilePropertyFormatter): String; override; property Owner: Cardinal read FOwner write FOwner; property Group: Cardinal read FGroup write FGroup; property OwnerStr: String read FOwnerStr write FOwnerStr; property GroupStr: String read FGroupStr write FGroupStr; end; { TFileTypeProperty } {en File type description. } TFileTypeProperty = class(TFileProperty) private FType: String; public constructor Create; override; function Clone: TFileTypeProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; function Format({%H-}Formatter: IFilePropertyFormatter): String; override; property Value: String read FType write FType; end; { TFileCommentProperty } TFileCommentProperty = class(TFileProperty) private FComment: String; public constructor Create; override; function Clone: TFileCommentProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; function Format({%H-}Formatter: IFilePropertyFormatter): String; override; property Value: String read FComment write FComment; end; { TFileVariantProperty } TFileVariantProperty = class(TFileProperty) private FName: String; FValue: Variant; public constructor Create; override; constructor Create(const AName: String); virtual; overload; function Clone: TFileVariantProperty; override; procedure CloneTo(FileProperty: TFileProperty); override; class function GetDescription: String; override; class function GetID: TFilePropertyType; override; function Equals(p: TObject): Boolean; override; function Format({%H-}Formatter: IFilePropertyFormatter): String; override; property Value: Variant read FValue write FValue; property Name: String read FName; end; // -- Property formatter interface ------------------------------------------ IFilePropertyFormatter = interface(IInterface) ['{18EF8E34-1010-45CD-8DC9-678C7C2DC89F}'] function FormatFileName(FileProperty: TFileNameProperty): String; function FormatFileSize(FileProperty: TFileSizeProperty): String; function FormatDateTime(FileProperty: TFileDateTimeProperty): String; function FormatModificationDateTime(FileProperty: TFileModificationDateTimeProperty): String; function FormatNtfsAttributes(FileProperty: TNtfsFileAttributesProperty): String; function FormatUnixAttributes(FileProperty: TUnixFileAttributesProperty): String; end; implementation uses Variants, uLng, DCOSUtils, DCFileAttributes, DCDateTimeUtils, uDefaultFilePropertyFormatter, uDebug; resourcestring rsSizeDescription = 'Size'; rsCompressedSizeDescription = 'Compressed size'; rsDateTimeDescription = 'DateTime'; rsModificationDateTimeDescription = 'Modification date/time'; // ---------------------------------------------------------------------------- constructor TFileProperty.Create; begin inherited; end; function TFileProperty.Clone: TFileProperty; begin Result:= nil; raise Exception.Create('Cannot create abstract class'); end; procedure TFileProperty.CloneTo(FileProperty: TFileProperty); begin end; function TFileProperty.AsString: String; begin Result := Format(DefaultFilePropertyFormatter); end; // ---------------------------------------------------------------------------- constructor TFileNameProperty.Create; begin Self.Create(''); end; constructor TFileNameProperty.Create(Name: String); begin inherited Create; Value := Name; end; function TFileNameProperty.Clone: TFileNameProperty; begin Result := TFileNameProperty.Create; CloneTo(Result); end; procedure TFileNameProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileNameProperty do begin FName := Self.FName; end; end; end; class function TFileNameProperty.GetDescription: String; begin Result := 'name'; end; class function TFileNameProperty.GetID: TFilePropertyType; begin Result := fpName; end; function TFileNameProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileNameProperty) then exit; if self.FName <> TFileNameProperty(p).FName then exit; Result:= true; end; function TFileNameProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := Formatter.FormatFileName(Self); end; procedure TFileNameProperty.SetName(NewName: String); var i: Integer; begin for i := 1 to Length(NewName) do if NewName[i] in AllowDirectorySeparators then begin DCDebug('Name cannot have directory separators: "%s"', [NewName]); Break; end; FName := NewName; end; // ---------------------------------------------------------------------------- constructor TFileSizeProperty.Create; begin Self.Create(0); end; constructor TFileSizeProperty.Create(Size: Int64); begin inherited Create; Value := Size; FIsValid := True; end; function TFileSizeProperty.Clone: TFileSizeProperty; begin Result := TFileSizeProperty.Create; CloneTo(Result); end; procedure TFileSizeProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileSizeProperty do begin FSize := Self.FSize; FIsValid := Self.FIsValid; end; end; end; class function TFileSizeProperty.GetDescription: String; begin Result := rsSizeDescription; end; class function TFileSizeProperty.GetID: TFilePropertyType; begin Result := fpSize; end; function TFileSizeProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileSizeProperty) then exit; if self.FIsValid <> TFileSizeProperty(p).FIsValid then exit; if self.FIsValid and (self.FSize <> TFileSizeProperty(p).FSize) then exit; Result:= true; end; function TFileSizeProperty.GetMinimumValue: Int64; begin Result := 0; end; function TFileSizeProperty.GetMaximumValue: Int64; begin Result := 0; // maximum file size end; function TFileSizeProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := Formatter.FormatFileSize(Self); end; // ---------------------------------------------------------------------------- function TFileCompressedSizeProperty.Clone: TFileCompressedSizeProperty; begin Result := TFileCompressedSizeProperty.Create; CloneTo(Result); end; class function TFileCompressedSizeProperty.GetDescription: String; begin Result:= rsCompressedSizeDescription; end; class function TFileCompressedSizeProperty.GetID: TFilePropertyType; begin Result := fpCompressedSize; end; // ---------------------------------------------------------------------------- constructor TFileDateTimeProperty.Create; begin Self.Create(SysUtils.Now); end; constructor TFileDateTimeProperty.Create(FileTime: TFileTime); begin Self.Create(FileTimeToDateTime(FileTime)); end; constructor TFileDateTimeProperty.Create(DateTime: TDateTime); begin inherited Create; Value := DateTime; FIsValid := True; end; procedure TFileDateTimeProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileDateTimeProperty do begin FIsValid := Self.FIsValid; FDateTime := Self.FDateTime; end; end; end; function TFileDateTimeProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileDateTimeProperty) then exit; if self.FIsValid <> TFileDateTimeProperty(p).FIsValid then exit; if self.FIsValid and (self.FDateTime <> TFileDateTimeProperty(p).FDateTime) then exit; Result:= true; end; function TFileDateTimeProperty.GetMinimumValue: TDateTime; begin Result := MinDateTime; end; function TFileDateTimeProperty.GetMaximumValue: TDateTime; begin Result := MaxDateTime; end; // ---------------------------------------------------------------------------- function TFileModificationDateTimeProperty.Clone: TFileModificationDateTimeProperty; begin Result := TFileModificationDateTimeProperty.Create; CloneTo(Result); end; class function TFileModificationDateTimeProperty.GetDescription: String; begin Result := rsModificationDateTimeDescription; end; class function TFileModificationDateTimeProperty.GetID: TFilePropertyType; begin Result := fpModificationTime; end; function TFileModificationDateTimeProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := Formatter.FormatModificationDateTime(Self); end; // ---------------------------------------------------------------------------- function TFileCreationDateTimeProperty.Clone: TFileCreationDateTimeProperty; begin Result := TFileCreationDateTimeProperty.Create; CloneTo(Result); end; class function TFileCreationDateTimeProperty.GetDescription: String; begin Result := rsDateTimeDescription; end; class function TFileCreationDateTimeProperty.GetID: TFilePropertyType; begin Result := fpCreationTime; end; function TFileCreationDateTimeProperty.Format(Formatter: IFilePropertyFormatter): String; begin if not FIsValid then Result := EmptyStr else Result := Formatter.FormatDateTime(Self); end; // ---------------------------------------------------------------------------- function TFileLastAccessDateTimeProperty.Clone: TFileLastAccessDateTimeProperty; begin Result := TFileLastAccessDateTimeProperty.Create; CloneTo(Result); end; class function TFileLastAccessDateTimeProperty.GetDescription: String; begin Result := rsDateTimeDescription; end; class function TFileLastAccessDateTimeProperty.GetID: TFilePropertyType; begin Result := fpLastAccessTime; end; function TFileLastAccessDateTimeProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := Formatter.FormatDateTime(Self); end; // ---------------------------------------------------------------------------- function TFileChangeDateTimeProperty.Clone: TFileChangeDateTimeProperty; begin Result := TFileChangeDateTimeProperty.Create; CloneTo(Result); end; class function TFileChangeDateTimeProperty.GetDescription: String; begin Result := rsDateTimeDescription; end; class function TFileChangeDateTimeProperty.GetID: TFilePropertyType; begin Result := fpChangeTime; end; function TFileChangeDateTimeProperty.Format(Formatter: IFilePropertyFormatter): String; begin if not FIsValid then Result := EmptyStr else Result := Formatter.FormatDateTime(Self); end; // ---------------------------------------------------------------------------- constructor TFileAttributesProperty.Create; begin Create(0); end; constructor TFileAttributesProperty.Create(Attr: TFileAttrs); begin inherited Create; FAttributes := Attr; end; function TFileAttributesProperty.IsNativeAttributes: Boolean; begin {$IF DEFINED(WINDOWS)} Result := Self is TNtfsFileAttributesProperty; {$ELSEIF DEFINED(UNIX)} Result := Self is TUnixFileAttributesProperty; {$ELSE} Result := False; {$ENDIF} end; class function TFileAttributesProperty.CreateOSAttributes: TFileAttributesProperty; begin Result := CreateOSAttributes(0); end; class function TFileAttributesProperty.CreateOSAttributes(Attr: TFileAttrs): TFileAttributesProperty; begin {$IF DEFINED(WINDOWS)} Result := TNtfsFileAttributesProperty.Create(Attr); {$ELSEIF DEFINED(UNIX)} Result := TUnixFileAttributesProperty.Create(Attr); {$ELSE} Result := nil; {$ENDIF} end; function TFileAttributesProperty.Clone: TFileAttributesProperty; begin Result:= nil; raise Exception.Create('Cannot create abstract class'); end; procedure TFileAttributesProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileAttributesProperty do begin FAttributes := Self.FAttributes; end; end; end; class function TFileAttributesProperty.GetID: TFilePropertyType; begin Result := fpAttributes; end; function TFileAttributesProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileAttributesProperty) then exit; if self.FAttributes <> TFileAttributesProperty(p).FAttributes then exit; Result:= true; end; function TFileAttributesProperty.GetAttributes: TFileAttrs; begin Result := FAttributes; end; procedure TFileAttributesProperty.SetAttributes(Attributes: TFileAttrs); begin FAttributes := Attributes; end; function TFileAttributesProperty.IsDirectory: Boolean; begin Result := fpS_ISDIR(FAttributes); end; function TFileAttributesProperty.IsSpecial: Boolean; begin Result := False; end; function TFileAttributesProperty.IsLink: Boolean; begin Result := fpS_ISLNK(FAttributes); end; // ---------------------------------------------------------------------------- function TNtfsFileAttributesProperty.Clone: TNtfsFileAttributesProperty; begin Result := TNtfsFileAttributesProperty.Create; CloneTo(Result); end; function TNtfsFileAttributesProperty.IsDirectory: Boolean; begin Result:= ((FAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0); end; function TNtfsFileAttributesProperty.IsSpecial: Boolean; begin Result:= ((FAttributes and FILE_ATTRIBUTE_DEVICE) <> 0) or ((FAttributes and FILE_ATTRIBUTE_VOLUME) <> 0); end; function TNtfsFileAttributesProperty.IsSysFile: boolean; begin Result := ((FAttributes and FILE_ATTRIBUTE_HIDDEN) <> 0) or (((FAttributes and FILE_ATTRIBUTE_SYSTEM) <> 0) and ((FAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0)); end; function TNtfsFileAttributesProperty.IsLink: Boolean; begin Result:= ((FAttributes and FILE_ATTRIBUTE_REPARSE_POINT) <> 0); end; function TNtfsFileAttributesProperty.IsReadOnly: Boolean; begin Result := (FAttributes and FILE_ATTRIBUTE_READONLY) <> 0; end; function TNtfsFileAttributesProperty.IsHidden: Boolean; begin Result := (FAttributes and FILE_ATTRIBUTE_HIDDEN) <> 0; end; class function TNtfsFileAttributesProperty.GetDescription: String; begin Result:= EmptyStr; end; function TNtfsFileAttributesProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := Formatter.FormatNtfsAttributes(Self) end; // ---------------------------------------------------------------------------- function TUnixFileAttributesProperty.Clone: TUnixFileAttributesProperty; begin Result := TUnixFileAttributesProperty.Create; CloneTo(Result); end; function TUnixFileAttributesProperty.IsDirectory: Boolean; begin Result:= ((FAttributes and S_IFMT) = S_IFDIR); end; function TUnixFileAttributesProperty.IsSysFile: Boolean; begin Result := False; end; function TUnixFileAttributesProperty.IsLink: Boolean; begin Result:= ((FAttributes and S_IFMT) = S_IFLNK); end; function TUnixFileAttributesProperty.IsOwnerRead: Boolean; begin Result:= False; end; function TUnixFileAttributesProperty.IsOwnerWrite: Boolean; begin Result:= False; end; function TUnixFileAttributesProperty.IsOwnerExecute: Boolean; begin Result:= False; end; class function TUnixFileAttributesProperty.GetDescription: String; begin Result:= EmptyStr; end; function TUnixFileAttributesProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := Formatter.FormatUnixAttributes(Self); end; // ---------------------------------------------------------------------------- constructor TFileLinkProperty.Create; begin inherited Create; FIsLinkToDirectory := False; FIsValid := True; end; function TFileLinkProperty.Clone: TFileLinkProperty; begin Result := TFileLinkProperty.Create; CloneTo(Result); end; procedure TFileLinkProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileLinkProperty do begin FIsLinkToDirectory := Self.FIsLinkToDirectory; FIsValid := Self.FIsValid; FLinkTo := Self.FLinkTo; end; end; end; class function TFileLinkProperty.GetDescription: String; begin Result := ''; end; class function TFileLinkProperty.GetID: TFilePropertyType; begin Result := fpLink; end; function TFileLinkProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileLinkProperty) then exit; if self.FIsValid <> TFileLinkProperty(p).FIsValid then exit; if self.FIsValid then begin if self.FIsLinkToDirectory <> TFileLinkProperty(p).FIsLinkToDirectory then exit; if self.FLinkTo <> TFileLinkProperty(p).FLinkTo then exit; end; Result:= true; end; function TFileLinkProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := ''; end; // ---------------------------------------------------------------------------- constructor TFileOwnerProperty.Create; begin inherited Create; end; function TFileOwnerProperty.Clone: TFileOwnerProperty; begin Result := TFileOwnerProperty.Create; CloneTo(Result); end; procedure TFileOwnerProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileOwnerProperty do begin FOwner := Self.FOwner; FGroup := Self.FGroup; FOwnerStr := Self.FOwnerStr; FGroupStr := Self.FGroupStr; end; end; end; class function TFileOwnerProperty.GetDescription: String; begin Result := ''; end; class function TFileOwnerProperty.GetID: TFilePropertyType; begin Result := fpOwner; end; function TFileOwnerProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileOwnerProperty) then exit; if self.FOwner <> TFileOwnerProperty(p).FOwner then exit; if self.FGroup <> TFileOwnerProperty(p).FGroup then exit; Result:= true; end; function TFileOwnerProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := ''; end; { TFileTypeProperty } constructor TFileTypeProperty.Create; begin inherited Create; end; function TFileTypeProperty.Clone: TFileTypeProperty; begin Result := TFileTypeProperty.Create; CloneTo(Result); end; procedure TFileTypeProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileTypeProperty do begin FType := Self.FType; end; end; end; class function TFileTypeProperty.GetDescription: String; begin Result := ''; end; class function TFileTypeProperty.GetID: TFilePropertyType; begin Result := fpType; end; function TFileTypeProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileTypeProperty) then exit; if self.FType <> TFileTypeProperty(p).FType then exit; Result:= true; end; function TFileTypeProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result := FType; end; { TFileCommentProperty } constructor TFileCommentProperty.Create; begin inherited Create; end; function TFileCommentProperty.Clone: TFileCommentProperty; begin Result := TFileCommentProperty.Create; CloneTo(Result); end; procedure TFileCommentProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileCommentProperty do begin FComment := Self.FComment; end; end; end; class function TFileCommentProperty.GetDescription: String; begin Result:= ''; end; class function TFileCommentProperty.GetID: TFilePropertyType; begin Result := fpComment; end; function TFileCommentProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileCommentProperty) then exit; if self.FComment <> TFileCommentProperty(p).FComment then exit; Result:= true; end; function TFileCommentProperty.Format(Formatter: IFilePropertyFormatter): String; begin Result:= FComment; end; { TFileVariantProperty } constructor TFileVariantProperty.Create; begin inherited Create; FValue:= Unassigned; end; constructor TFileVariantProperty.Create(const AName: String); begin Create; FName:= AName; end; function TFileVariantProperty.Clone: TFileVariantProperty; begin Result := TFileVariantProperty.Create; CloneTo(Result); end; procedure TFileVariantProperty.CloneTo(FileProperty: TFileProperty); begin if Assigned(FileProperty) then begin inherited CloneTo(FileProperty); with FileProperty as TFileVariantProperty do begin FName := Self.FName; FValue := Self.FValue; end; end; end; class function TFileVariantProperty.GetDescription: String; begin Result:= EmptyStr; end; class function TFileVariantProperty.GetID: TFilePropertyType; begin Result:= fpVariant; end; function TFileVariantProperty.Equals(p: TObject): Boolean; begin Result:= false; if not (p is TFileVariantProperty) then exit; if self.FName <> TFileVariantProperty(p).FName then exit; if self.FValue <> TFileVariantProperty(p).FValue then exit; Result:= true; end; function TFileVariantProperty.Format(Formatter: IFilePropertyFormatter): String; begin if not VarIsBool(FValue) then Result := FValue else if FValue then result := rsSimpleWordTrue else result := rsSimpleWordFalse; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufilesorting.pas���������������������������������������������������������������0000644�0001750�0000144�00000106415�14743153644�016623� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uFileSorting; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileFunctions, uFile, uFileProperty, uDisplayFile; type TSortDirection = (sdNone, sdAscending, sdDescending); TFileSorting = record SortFunctions: TFileFunctions; SortDirection: TSortDirection; end; TFileSortings = array of TFileSorting; { TBaseSorter } TBaseSorter = class private FSortings: TFileSortings; {en Checks the files list for supported properties and removes not supported sortings. Currently treats files as if they all had the same properties. } procedure CheckSupportedProperties(SupportedFileProperties: TFilePropertiesTypes); {en Compares two file records using file functions. @param(ptr1 First file) @param(ptr2 Second file) @returns(-1 lesser @br 0 equal @br 1 greater) } class function Compare(const FileSorting: TFileSorting; File1, File2: TFile): Integer; public constructor Create(const Sortings: TFileSortings); reintroduce; end; { TFileSorter } TFileSorter = class(TBaseSorter) private FSortList: TFiles; function MultiCompare(item1, item2: Pointer):Integer; procedure QuickSort(FList: PPointerList; L, R : Longint); public {en Creates the sorter. @param(Files List of files to be sorted.) @param(FileSorting Sorting which will be used to sort file records.) } constructor Create(Files: TFiles; Sortings: TFileSortings); procedure Sort; {en Sorts files in FilesToSort using ASorting. } class procedure Sort(FilesToSort: TFiles; const ASortings: TFileSortings); end; { TDisplayFileSorter } TDisplayFileSorter = class(TBaseSorter) private FDisplaySortList: TDisplayFiles; FFileToInsert: TDisplayFile; FFilesToInsert: TDisplayFiles; FFileIndexToResort: Integer; FResortSingle: Boolean; FSequentialSearch: Boolean; // Use sequential search instead of binary protected procedure BinaryInsertSingle(FileToInsert: TDisplayFile; List: TFPList; L, R: Longint); procedure BinaryResortSingle(UnsortedIndex: Integer; PList: PPointerList; L, R : Longint); function BinarySearch(DisplayFile: Pointer; PList: PPointerList; L, R: Longint; out FoundIndex: Longint): Integer; procedure InsertSort(FilesToInsert, AlreadySortedFiles: TDisplayFiles); procedure InsertSort(FileToInsert: TDisplayFile; AlreadySortedFiles: TDisplayFiles); function MultiCompare(item1, item2: Pointer):Integer; procedure QuickSort(FList: PPointerList; L, R : Longint); {en The single file at index IndexToResort should be repositioned in the SortedFiles list. All other elements, except for the element at IndexToResort, must be already sorted. } procedure ResortSingle(IndexToResort: Integer; SortedFiles: TDisplayFiles); procedure SequentialInsertSingle(FileToInsert: TDisplayFile; List: TFPList); public constructor Create(Files: TDisplayFiles; Sortings: TFileSortings); constructor Create(FilesToInsert, AlreadySortedFiles: TDisplayFiles; const Sortings: TFileSortings); constructor Create(FileToInsert: TDisplayFile; AlreadySortedFiles: TDisplayFiles; const Sortings: TFileSortings; ASequentialSearch: Boolean = False); constructor Create(IndexToResort: Integer; SortedFiles: TDisplayFiles; const Sortings: TFileSortings); procedure Sort; class procedure InsertSort(FilesToInsert, AlreadySortedFiles: TDisplayFiles; const ASortings: TFileSortings); class procedure InsertSort(FileToInsert: TDisplayFile; AlreadySortedFiles: TDisplayFiles; const ASortings: TFileSortings; ASequentialSearch: Boolean = False); class procedure ResortSingle(IndexToResort: Integer; SortedFiles: TDisplayFiles; const ASortings: TFileSortings); class procedure Sort(FilesToSort: TDisplayFiles; const ASortings: TFileSortings); end; {en Returns true if the file functions will sort by the given sort function. } function HasSortFunction(FileFunctions: TFileFunctions; SortFunction: TFileFunction): Boolean; function HasSortFunction(FileSortings: TFileSortings; SortFunction: TFileFunction): Boolean; function GetSortDirection(FileSortings: TFileSortings; SortFunction: TFileFunction): TSortDirection; function GetSortDirection(FileSortings: TFileSortings; SortFunctions: TFileFunctions): TSortDirection; {en Adds a function to the given list of functions. } procedure AddSortFunction(var FileFunctions: TFileFunctions; SortFunction: TFileFunction); {en Deletes a function from the given list of functions. } procedure DeleteSortFunction(var FileFunctions: TFileFunctions; SortFunction: TFileFunction); {en Adds sorting by functions with a given sorting direction to existing sorting. } procedure AddSorting(var Sortings: TFileSortings; SortFunctions: TFileFunctions; SortDirection: TSortDirection); procedure AddOrUpdateSorting(var Sortings: TFileSortings; SortFunctions: TFileFunctions; SortDirection: TSortDirection); {en Checks if there is a sorting by Name, NameNoExtension or Extension and adds such sortings if there isn't. } procedure AddSortingByNameIfNeeded(var FileSortings: TFileSortings); {en Creates a deep copy of sortings. } function CloneSortings(const Sortings: TFileSortings): TFileSortings; function ICompareByDirectory(item1, item2: TFile; bSortNegative: Boolean):Integer; function ICompareByName(item1, item2: TFile; bSortNegative: Boolean):Integer; function ICompareByNameNoExt(item1, item2: TFile; bSortNegative: Boolean):Integer; function ICompareByExt (item1, item2: TFile; bSortNegative: Boolean):Integer; function ICompareBySize(item1, item2: TFile; bSortNegative: Boolean):Integer; function ICompareByDate(date1, date2: TDateTime; bSortNegative: Boolean):Integer; function ICompareByAttr(item1, item2: TFile; bSortNegative: Boolean):Integer; function CloneAndAddSortByNameIfNeeded(const Sortings: TFileSortings): TFileSortings; function ReverseSortDirection(SortDirection: TSortDirection): TSortDirection; function ReverseSortDirection(Sortings: TFileSortings): TFileSortings; implementation uses Variants, DCBasicTypes, uGlobs, DCStrUtils, uDCUtils {$IFDEF fileSortingTime} , uDebug {$ENDIF} ; {$IFDEF fileSortingTime} var fileSortingTimer: TDateTime; {$ENDIF} procedure TFPListFastMove(CurIndex, NewIndex: Integer; PList: PPointerList); var Temp: Pointer; begin Temp := PList^[CurIndex]; if NewIndex > CurIndex then System.Move(PList^[CurIndex+1], PList^[CurIndex], (NewIndex - CurIndex) * SizeOf(Pointer)) else System.Move(PList^[NewIndex], PList^[NewIndex+1], (CurIndex - NewIndex) * SizeOf(Pointer)); PList^[NewIndex] := Temp; end; function HasSortFunction(FileFunctions: TFileFunctions; SortFunction: TFileFunction): Boolean; var i: Integer; begin for i := 0 to Length(FileFunctions) - 1 do begin if SortFunction = FileFunctions[i] then Exit(True); end; Result := False; end; function HasSortFunction(FileSortings: TFileSortings; SortFunction: TFileFunction): Boolean; var i: Integer; begin for i := 0 to Length(FileSortings) - 1 do begin if HasSortFunction(FileSortings[i].SortFunctions, SortFunction) then Exit(True); end; Result := False; end; function GetSortDirection(FileSortings: TFileSortings; SortFunction: TFileFunction): TSortDirection; var i: Integer; begin for i := 0 to Length(FileSortings) - 1 do begin if HasSortFunction(FileSortings[i].SortFunctions, SortFunction) then Exit(FileSortings[i].SortDirection); end; Result := sdNone; end; function GetSortDirection(FileSortings: TFileSortings; SortFunctions: TFileFunctions): TSortDirection; var i, j: Integer; Found: Boolean; begin for i := 0 to Length(FileSortings) - 1 do begin if Length(FileSortings[i].SortFunctions) = Length(SortFunctions) then begin Found := True; for j := 0 to Length(SortFunctions) - 1 do if FileSortings[i].SortFunctions[j] <> SortFunctions[j] then begin Found := False; Break; end; if Found then Exit(FileSortings[i].SortDirection); end; end; Result := sdNone; end; procedure AddSortFunction(var FileFunctions: TFileFunctions; SortFunction: TFileFunction); begin SetLength(FileFunctions, Length(FileFunctions) + 1); FileFunctions[Length(FileFunctions) - 1] := SortFunction; end; procedure DeleteSorting(var FileSortings: TFileSortings; Index: Integer); var Len: Integer; i: Integer; begin Len := Length(FileSortings); for i := Index + 1 to Len - 1 do FileSortings[i - 1] := FileSortings[i]; SetLength(FileSortings, Len - 1); end; procedure DeleteSortFunction(var FileFunctions: TFileFunctions; SortFunction: TFileFunction); var Len: Integer; i, j: Integer; begin for i := Low(FileFunctions) to High(FileFunctions) do if FileFunctions[i] = SortFunction then begin Len := Length(FileFunctions); for j := i + 1 to Len - 1 do FileFunctions[j - 1] := FileFunctions[j]; SetLength(FileFunctions, Len - 1); Break; end; end; procedure AddSorting(var Sortings: TFileSortings; SortFunctions: TFileFunctions; SortDirection: TSortDirection); var SortingIndex: Integer; begin if Length(SortFunctions) > 0 then begin SortingIndex := Length(Sortings); SetLength(Sortings, SortingIndex + 1); Sortings[SortingIndex].SortFunctions := SortFunctions; Sortings[SortingIndex].SortDirection := SortDirection; end; end; procedure AddSorting(var FileSortings: TFileSortings; SortFunction: TFileFunction; SortDirection: TSortDirection); var SortFunctions: TFileFunctions = nil; begin AddSortFunction(SortFunctions, SortFunction); AddSorting(FileSortings, SortFunctions, SortDirection); end; procedure AddOrUpdateSorting(var Sortings: TFileSortings; SortFunctions: TFileFunctions; SortDirection: TSortDirection); var i, j: Integer; RemainingFunctions: TFileFunctions; begin if Length(SortFunctions) = 0 then Exit; RemainingFunctions := SortFunctions; // Check if there is already sorting by the functions. // If it is then reverse direction of sorting. for i := Low(Sortings) to High(Sortings) do begin RemainingFunctions := SortFunctions; for j := Low(SortFunctions) to High(SortFunctions) do begin if HasSortFunction(Sortings[i].SortFunctions, SortFunctions[j]) then DeleteSortFunction(RemainingFunctions, SortFunctions[j]); end; if Length(RemainingFunctions) = 0 then begin // Sorting contains all functions - reverse direction. Sortings[i].SortDirection := ReverseSortDirection(Sortings[i].SortDirection); SortFunctions := nil; Break; end else if Length(RemainingFunctions) < Length(SortFunctions) then begin // Sorting contains some but not all functions - delete this one and later add sorting with all functions. Sortings[i].SortDirection := sdNone; end; end; for i := High(Sortings) downto Low(Sortings) do if Sortings[i].SortDirection = sdNone then DeleteSorting(Sortings, i); AddSorting(Sortings, SortFunctions, SortDirection); end; procedure AddSortingByNameIfNeeded(var FileSortings: TFileSortings); var bSortedByName: Boolean = False; bSortedByExtension: Boolean = False; i: Integer; begin for i := 0 to Length(FileSortings) - 1 do begin if HasSortFunction(FileSortings[i].SortFunctions, fsfName) then begin bSortedByName := True; bSortedByExtension := True; Exit; end else if HasSortFunction(FileSortings[i].SortFunctions, fsfNameNoExtension) then begin bSortedByName := True; end else if HasSortFunction(FileSortings[i].SortFunctions, fsfExtension) then begin bSortedByExtension := True; end; end; if not bSortedByName then begin if not bSortedByExtension then AddSorting(FileSortings, fsfName, sdAscending) else AddSorting(FileSortings, fsfNameNoExtension, sdAscending); end else if not bSortedByExtension then AddSorting(FileSortings, fsfExtension, sdAscending); // else // There is already a sorting by filename and extension. end; function CloneSortings(const Sortings: TFileSortings): TFileSortings; var i, j: Integer; begin SetLength(Result, Length(Sortings)); for i := 0 to Length(Sortings) - 1 do begin SetLength(Result[i].SortFunctions, Length(Sortings[i].SortFunctions)); for j := 0 to Length(Sortings[i].SortFunctions) - 1 do Result[i].SortFunctions[j] := Sortings[i].SortFunctions[j]; Result[i].SortDirection := Sortings[i].SortDirection; end; end; function CloneAndAddSortByNameIfNeeded(const Sortings: TFileSortings): TFileSortings; begin Result := CloneSortings(Sortings); // Add automatic sorting by name and/or extension if there wasn't any. AddSortingByNameIfNeeded(Result); end; function ICompareByDirectory(item1, item2: TFile; bSortNegative: Boolean):Integer; var IsDir1, IsDir2: Boolean; begin IsDir1 := item1.IsDirectory or item1.IsLinkToDirectory; IsDir2 := item2.IsDirectory or item2.IsLinkToDirectory; if (not IsDir1) and (not IsDir2) then Result := 0 else if (not IsDir1) and IsDir2 then Result := 1 else if IsDir1 and (not IsDir2) then Result := -1 // Put '..' first. else if item1.Name = '..' then Result := -1 else if item2.Name = '..' then Result := 1 else if (gSortFolderMode <> sfmSortNameShowFirst) then Result := 0 else Result := CompareStrings(item1.Name, item2.Name, gSortNatural, gSortSpecial, gSortCaseSensitivity); end; function ICompareByName(item1, item2: TFile; bSortNegative: Boolean):Integer; begin Result := CompareStrings(item1.Name, item2.Name, gSortNatural, gSortSpecial, gSortCaseSensitivity); if bSortNegative then Result := -Result; end; function ICompareByNameNoExt(item1, item2: TFile; bSortNegative: Boolean):Integer; begin // Don't sort directories only by name. if item1.IsDirectory or item1.IsLinkToDirectory or item2.IsDirectory or item2.IsLinkToDirectory then begin // Sort by full name. Result := ICompareByName(item1, item2, bSortNegative); end else begin Result := CompareStrings(item1.NameNoExt, item2.NameNoExt, gSortNatural, gSortSpecial, gSortCaseSensitivity); if bSortNegative then Result := -Result; end; end; function ICompareByExt(item1, item2: TFile; bSortNegative: Boolean):Integer; begin Result := CompareStrings(item1.Extension, item2.Extension, gSortNatural, gSortSpecial, gSortCaseSensitivity); if bSortNegative then Result := -Result; end; function ICompareByDate(date1, date2: TDateTime; bSortNegative: Boolean):Integer; begin if date1 = date2 then Result := 0 else begin if date1 < date2 then Result := -1 else Result := +1; if bSortNegative then Result := -Result; end; end; function ICompareByAttr(item1, item2: TFile; bSortNegative: Boolean):Integer; var Attr1, Attr2: TFileAttrs; begin Attr1 := item1.Attributes; Attr2 := item2.Attributes; if Attr1 = Attr2 then Result := 0 else begin if Attr1 > Attr2 then Result := -1 else Result := +1; if bSortNegative then Result := -Result; end; end; function ICompareBySize(item1, item2: TFile; bSortNegative: Boolean):Integer; var iSize1 : Int64; iSize2 : Int64; begin iSize1 := item1.Size; iSize2 := item2.Size; if iSize1 = iSize2 then Result := 0 else begin if iSize1 < iSize2 then Result := -1 else Result := +1; if bSortNegative then Result := -Result; end; end; function ICompareByVariant(Value1, Value2: Variant; bSortNegative: Boolean):Integer; begin if VarIsType(Value1, varString) then Result := CompareStrings(Value1, Value2, gSortNatural, gSortSpecial, gSortCaseSensitivity) else if Value1 = Value2 then Exit(0) else begin if Value1 < Value2 then Result := -1 else Result := +1; end; if bSortNegative then Result := -Result; end; function ReverseSortDirection(SortDirection: TSortDirection): TSortDirection; begin case SortDirection of sdAscending: Result := sdDescending; sdDescending: Result := sdAscending; end; end; function ReverseSortDirection(Sortings: TFileSortings): TFileSortings; var i: Integer; begin Result := CloneSortings(Sortings); for i := 0 to Length(Result) - 1 do Result[i].SortDirection := ReverseSortDirection(Result[i].SortDirection); end; { TBaseSorter } constructor TBaseSorter.Create(const Sortings: TFileSortings); begin FSortings := Sortings; inherited Create; end; procedure TBaseSorter.CheckSupportedProperties(SupportedFileProperties: TFilePropertiesTypes); var SortingIndex: Integer; FunctionIndex: Integer; i: Integer; begin // Check if each sort function is supported. SortingIndex := 0; while SortingIndex < Length(FSortings) do begin FunctionIndex := 0; while FunctionIndex < Length(FSortings[SortingIndex].SortFunctions) do begin if not (GetFilePropertyType(FSortings[SortingIndex].SortFunctions[FunctionIndex]) <= SupportedFileProperties) then begin for i := FunctionIndex to Length(FSortings[SortingIndex].SortFunctions) - 2 do FSortings[SortingIndex].SortFunctions[i] := FSortings[SortingIndex].SortFunctions[i+1]; SetLength(FSortings[SortingIndex].SortFunctions, Length(FSortings[SortingIndex].SortFunctions) - 1); end else Inc(FunctionIndex); end; if Length(FSortings[SortingIndex].SortFunctions) = 0 then begin for i := SortingIndex to Length(FSortings) - 2 do FSortings[i] := FSortings[i+1]; SetLength(FSortings, Length(FSortings) - 1); end else Inc(SortingIndex); end; end; class function TBaseSorter.Compare(const FileSorting: TFileSorting; File1, File2: TFile): Integer; var i: Integer; bNegative: Boolean; AFileProp: TFilePropertyType; begin Result := 0; case FileSorting.SortDirection of sdAscending: bNegative := False; sdDescending: bNegative := True; else Exit; end; for i := 0 to Length(FileSorting.SortFunctions) - 1 do begin //------------------------------------------------------ case FileSorting.SortFunctions[i] of fsfName: Result := ICompareByName(File1, File2, bNegative); fsfExtension: Result := ICompareByExt(File1, File2, bNegative); fsfSize: Result := ICompareBySize(File1, File2, bNegative); fsfAttr: Result := ICompareByAttr(File1, File2, bNegative); fsfPath: begin Result := mbCompareText(File1.Path, File2.Path); if bNegative then Result := -Result; end; fsfGroup: begin Result := mbCompareText(File1.OwnerProperty.GroupStr, File2.OwnerProperty.GroupStr); if bNegative then Result := -Result; end; fsfOwner: begin Result := mbCompareText(File1.OwnerProperty.OwnerStr, File2.OwnerProperty.OwnerStr); if bNegative then Result := -Result; end; fsfModificationTime: Result := ICompareByDate(File1.ModificationTime, File2.ModificationTime, bNegative); fsfCreationTime: Result := ICompareByDate(File1.CreationTime, File2.CreationTime, bNegative); fsfLastAccessTime: Result := ICompareByDate(File1.LastAccessTime, File2.LastAccessTime, bNegative); fsfChangeTime: Result := ICompareByDate(File1.ChangeTime, File2.ChangeTime, bNegative); fsfLinkTo: begin Result := mbCompareText(File1.LinkProperty.LinkTo, File2.LinkProperty.LinkTo); if bNegative then Result := -Result; end; fsfNameNoExtension: Result := ICompareByNameNoExt(File1, File2, bNegative); fsfType: begin Result := mbCompareText(File1.TypeProperty.Value, File2.TypeProperty.Value); if bNegative then Result := -Result; end; fsfComment: begin Result := mbCompareText(File1.CommentProperty.Value, File2.CommentProperty.Value); if bNegative then Result := -Result; end; // Variant properties from plugins else if FileSorting.SortFunctions[i] in fsfVariantAll then begin AFileProp:= TFilePropertyType(FileSorting.SortFunctions[i]); Result:= ICompareByVariant(TFileVariantProperty(File1.Properties[AFileProp]).Value, TFileVariantProperty(File2.Properties[AFileProp]).Value, bNegative) end; end; if Result <> 0 then Exit; end; end; { TDisplayFileSorter } constructor TDisplayFileSorter.Create(Files: TDisplayFiles; Sortings: TFileSortings); begin inherited Create(Sortings); FDisplaySortList := Files; if Assigned(FDisplaySortList) and (FDisplaySortList.Count > 0) then CheckSupportedProperties(FDisplaySortList[0].FSFile.SupportedProperties); end; constructor TDisplayFileSorter.Create(FilesToInsert, AlreadySortedFiles: TDisplayFiles; const Sortings: TFileSortings); begin inherited Create(Sortings); FFilesToInsert := FilesToInsert; FDisplaySortList := AlreadySortedFiles; if Assigned(FDisplaySortList) and (FDisplaySortList.Count > 0) and Assigned(FFilesToInsert) and (FFilesToInsert.Count > 0) then begin CheckSupportedProperties(FDisplaySortList[0].FSFile.SupportedProperties); CheckSupportedProperties(FFilesToInsert[0].FSFile.SupportedProperties); end; end; constructor TDisplayFileSorter.Create(FileToInsert: TDisplayFile; AlreadySortedFiles: TDisplayFiles; const Sortings: TFileSortings; ASequentialSearch: Boolean); begin inherited Create(Sortings); FFileToInsert := FileToInsert; FDisplaySortList := AlreadySortedFiles; FSequentialSearch := ASequentialSearch; if Assigned(FDisplaySortList) and (FDisplaySortList.Count > 0) and Assigned(FFileToInsert) then begin CheckSupportedProperties(FDisplaySortList[0].FSFile.SupportedProperties); CheckSupportedProperties(FFileToInsert.FSFile.SupportedProperties); end; end; constructor TDisplayFileSorter.Create(IndexToResort: Integer; SortedFiles: TDisplayFiles; const Sortings: TFileSortings); begin inherited Create(Sortings); FFileIndexToResort := IndexToResort; FResortSingle := True; FDisplaySortList := SortedFiles; if Assigned(FDisplaySortList) and (FDisplaySortList.Count > 0) then CheckSupportedProperties(FDisplaySortList[0].FSFile.SupportedProperties); end; procedure TDisplayFileSorter.Sort; begin {$IFDEF fileSortingTime} fileSortingTimer := Now; {$ENDIF} // Restore this check when independent SortFunctions are implemented and sorting // by directory condition (gSortFolderMode <> sfmSortLikeFile) is removed from // the sorter and moved into Sortings. //if Length(FSortings) > 0 then begin if FResortSingle and Assigned(FDisplaySortList) then begin ResortSingle(FFileIndexToResort, FDisplaySortList); {$IFDEF fileSortingTime} DCDebug('FileSorter: Resort time: ', IntToStr(DateTimeToTimeStamp(Now - fileSortingTimer).Time)); {$ENDIF} end else if Assigned(FFileToInsert) and Assigned(FDisplaySortList) then begin InsertSort(FFileToInsert, FDisplaySortList); {$IFDEF fileSortingTime} DCDebug('FileSorter: Insert sort time: ', IntToStr(DateTimeToTimeStamp(Now - fileSortingTimer).Time)); {$ENDIF} end else if Assigned(FFilesToInsert) and Assigned(FDisplaySortList) then begin InsertSort(FFilesToInsert, FDisplaySortList); {$IFDEF fileSortingTime} DCDebug('FileSorter: Insert sort time: ', IntToStr(DateTimeToTimeStamp(Now - fileSortingTimer).Time)); {$ENDIF} end else if Assigned(FDisplaySortList) and (FDisplaySortList.Count > 1) then begin QuickSort(FDisplaySortList.List.List, 0, FDisplaySortList.List.Count-1); {$IFDEF fileSortingTime} DCDebug('FileSorter: Sorting DisplayFiles time: ', IntToStr(DateTimeToTimeStamp(Now - fileSortingTimer).Time)); {$ENDIF} end; end; end; class procedure TDisplayFileSorter.InsertSort(FilesToInsert, AlreadySortedFiles: TDisplayFiles; const ASortings: TFileSortings); var FileListSorter: TDisplayFileSorter; begin FileListSorter := TDisplayFileSorter.Create(FilesToInsert, AlreadySortedFiles, ASortings); try FileListSorter.Sort; finally FreeAndNil(FileListSorter); end; end; class procedure TDisplayFileSorter.InsertSort(FileToInsert: TDisplayFile; AlreadySortedFiles: TDisplayFiles; const ASortings: TFileSortings; ASequentialSearch: Boolean); var FileListSorter: TDisplayFileSorter; begin FileListSorter := TDisplayFileSorter.Create(FileToInsert, AlreadySortedFiles, ASortings, ASequentialSearch); try FileListSorter.Sort; finally FreeAndNil(FileListSorter); end; end; class procedure TDisplayFileSorter.ResortSingle(IndexToResort: Integer; SortedFiles: TDisplayFiles; const ASortings: TFileSortings); var FileListSorter: TDisplayFileSorter; begin FileListSorter := TDisplayFileSorter.Create(IndexToResort, SortedFiles, ASortings); try FileListSorter.Sort; finally FreeAndNil(FileListSorter); end; end; class procedure TDisplayFileSorter.Sort(FilesToSort: TDisplayFiles; const ASortings: TFileSortings); var FileListSorter: TDisplayFileSorter; begin FileListSorter := TDisplayFileSorter.Create(FilesToSort, ASortings); try FileListSorter.Sort; finally FreeAndNil(FileListSorter); end; end; procedure TDisplayFileSorter.BinaryInsertSingle(FileToInsert: TDisplayFile; List: TFPList; L, R: Longint); var CompareRes: Integer; FoundIndex: Longint; begin if List.Count = 0 then FoundIndex := 0 else begin CompareRes := BinarySearch(FileToInsert, List.List, L, R, FoundIndex); if CompareRes > 0 then Inc(FoundIndex); // Insert after because it's greater than FoundIndex item. end; List.Insert(FoundIndex, FileToInsert); end; procedure TDisplayFileSorter.BinaryResortSingle(UnsortedIndex: Integer; PList: PPointerList; L, R: Longint); var CompareRes: Integer; FoundIndex: Longint; begin CompareRes := BinarySearch(PList^[UnsortedIndex], PList, L, R, FoundIndex); if CompareRes = 0 then TFPListFastMove(UnsortedIndex, FoundIndex, PList) else begin if UnsortedIndex < FoundIndex then begin if CompareRes < 0 then Dec(FoundIndex); end else begin if CompareRes > 0 then Inc(FoundIndex); end; TFPListFastMove(UnsortedIndex, FoundIndex, PList); end; end; function TDisplayFileSorter.BinarySearch( DisplayFile: Pointer; PList: PPointerList; L, R: Longint; out FoundIndex: Longint): Integer; var I, J, K : Longint; begin I := L; J := R; repeat K := (I + J) div 2; Result := MultiCompare(DisplayFile, PList^[K]); if Result < 0 then J := K - 1 else if Result > 0 then I := K + 1 else Break; until I > J; FoundIndex := K; end; procedure TDisplayFileSorter.InsertSort(FilesToInsert, AlreadySortedFiles: TDisplayFiles); var i, j: PtrInt; L, R, FoundIndex: Longint; Psrc: PPointerList; Pcur: Pointer; SearchResult: Integer; DestList: TFPList; begin if FFilesToInsert.Count > 0 then begin if FFilesToInsert.Count = 1 then begin InsertSort(FFilesToInsert[0], AlreadySortedFiles); Exit; end else begin // First sort the files to insert of which there should be only a small number. QuickSort(FilesToInsert.List.List, 0, FilesToInsert.List.Count-1); end; Psrc := FilesToInsert.List.List; DestList := AlreadySortedFiles.List; L := 0; R := DestList.Count - 1; if R < 0 then begin // Add remaining files at the end. for j := 0 to FilesToInsert.Count - 1 do DestList.Add(Psrc^[j]); end else begin FoundIndex := 0; for i := 0 to FilesToInsert.Count - 1 do begin Pcur := Psrc^[i]; SearchResult := BinarySearch(Pcur, DestList.List, L, R, FoundIndex); // Insert Pcur after FoundIndex if it was greater. if SearchResult > 0 then Inc(FoundIndex); if FoundIndex > R then begin // Add remaining files at the end. for j := i to FilesToInsert.Count - 1 do DestList.Add(Psrc^[j]); Break; end; DestList.Insert(FoundIndex, Pcur); L := FoundIndex + 1; // Next time start searching from the next element after the one just inserted. Inc(R); // Number of elements has increased so also increase right boundary. end; end; end; end; procedure TDisplayFileSorter.InsertSort(FileToInsert: TDisplayFile; AlreadySortedFiles: TDisplayFiles); begin if FSequentialSearch then SequentialInsertSingle(FileToInsert, AlreadySortedFiles.List) else BinaryInsertSingle(FileToInsert, AlreadySortedFiles.List, 0, AlreadySortedFiles.Count - 1); end; function TDisplayFileSorter.MultiCompare(item1, item2: Pointer): Integer; var i : Integer; begin Result := 0; if item1 = item2 then Exit; // Put directories first. if (gSortFolderMode <> sfmSortLikeFile) then begin Result := ICompareByDirectory(TDisplayFile(item1).FSFile, TDisplayFile(item2).FSFile, False); // Ascending if Result <> 0 then Exit; end else begin // Put '..' first. if TDisplayFile(item1).FSFile.Name = '..' then Exit(-1); if TDisplayFile(item2).FSFile.Name = '..' then Exit(+1); end; for i := 0 to Length(FSortings) - 1 do begin Result := Compare(FSortings[i], TDisplayFile(item1).FSFile, TDisplayFile(item2).FSFile); if Result <> 0 then Exit; end; end; procedure TDisplayFileSorter.QuickSort(FList: PPointerList; L, R: Longint); var I, J : Longint; P, Q : Pointer; begin repeat I := L; J := R; P := FList^[ (L + R) div 2 ]; repeat while MultiCompare(P, FList^[i]) > 0 do I := I + 1; while MultiCompare(P, FList^[J]) < 0 do J := J - 1; If I <= J then begin Q := FList^[I]; Flist^[I] := FList^[J]; FList^[J] := Q; I := I + 1; J := J - 1; end; until I > J; if L < J then QuickSort(FList, L, J); L := I; until I >= R; end; procedure TDisplayFileSorter.ResortSingle(IndexToResort: Integer; SortedFiles: TDisplayFiles); var PUnsorted: Pointer; PSorted: PPointerList; begin PSorted := SortedFiles.List.List; PUnsorted := PSorted^[IndexToResort]; // The element at IndexToResort must either be moved left or right, // or should stay where it is. if (IndexToResort > 0) and (MultiCompare(PUnsorted, PSorted^[IndexToResort - 1]) < 0) then begin if IndexToResort = 1 then SortedFiles.List.Exchange(IndexToResort, IndexToResort - 1) else BinaryResortSingle(IndexToResort, PSorted, 0, IndexToResort - 1); end else if (IndexToResort < SortedFiles.List.Count - 1) and (MultiCompare(PUnsorted, PSorted^[IndexToResort + 1]) > 0) then begin if IndexToResort = SortedFiles.List.Count - 2 then SortedFiles.List.Exchange(IndexToResort, IndexToResort + 1) else BinaryResortSingle(IndexToResort, PSorted, IndexToResort + 1, SortedFiles.List.Count - 1); end; end; procedure TDisplayFileSorter.SequentialInsertSingle(FileToInsert: TDisplayFile; List: TFPList); var SortedIndex: PtrInt; Pdst: PPointerList; begin SortedIndex := 0; Pdst := List.List; while (SortedIndex < List.Count) and (MultiCompare(FileToInsert, Pdst^[SortedIndex]) > 0) do Inc(SortedIndex); List.Insert(SortedIndex, FileToInsert); end; { TFileSorter } constructor TFileSorter.Create(Files: TFiles; Sortings: TFileSortings); begin inherited Create(Sortings); FSortList := Files; if Assigned(FSortList) and (FSortList.Count > 0) then CheckSupportedProperties(FSortList.Items[0].SupportedProperties); end; procedure TFileSorter.Sort; begin {$IFDEF fileSortingTime} fileSortingTimer := Now; {$ENDIF} // Restore this check when independent SortFunctions are implemented and sorting // by directory condition (gSortFolderMode <> sfmSortLikeFile) is removed from // the sorter and moved into Sortings. //if Length(FSortings) > 0 then begin if Assigned(FSortList) and (FSortList.Count > 1) then begin QuickSort(FSortList.List.List, 0, FSortList.List.Count-1); {$IFDEF fileSortingTime} DCDebug('FileSorter: Sorting FSFiles time: ', IntToStr(DateTimeToTimeStamp(Now - fileSortingTimer).Time)); {$ENDIF} end; end; end; class procedure TFileSorter.Sort(FilesToSort: TFiles; const ASortings: TFileSortings); var FileListSorter: TFileSorter; begin FileListSorter := TFileSorter.Create(FilesToSort, ASortings); try FileListSorter.Sort; finally FreeAndNil(FileListSorter); end; end; { Return Values for ICompareByxxxx function > 0 (positive) Item1 is greater than Item2 0 Item1 is equal to Item2 < 0 (negative) Item1 is less than Item2 } { This function is simples support of sorting directory (handle uglobs.gDirSortFirst) Result is 0 if both parametres is directory and equal or not a directory (both). Else return +/- as ICompare**** } function TFileSorter.MultiCompare(item1, item2: Pointer):Integer; var i : Integer; begin Result := 0; if item1 = item2 then Exit; // Put directories first. if (gSortFolderMode <> sfmSortLikeFile) then begin Result := ICompareByDirectory(TFile(item1), TFile(item2), False); // Ascending if Result <> 0 then Exit; end else begin // Put '..' first. if TFile(item1).Name = '..' then Exit(-1); if TFile(item2).Name = '..' then Exit(+1); end; for i := 0 to Length(FSortings) - 1 do begin Result := Compare(FSortings[i], TFile(item1), TFile(item2)); if Result <> 0 then Exit; end; end; // From FPC: lists.inc. procedure TFileSorter.QuickSort(FList: PPointerList; L, R : Longint); var I, J : Longint; P, Q : Pointer; begin repeat I := L; J := R; P := FList^[ (L + R) div 2 ]; repeat while MultiCompare(P, FList^[i]) > 0 do I := I + 1; while MultiCompare(P, FList^[J]) < 0 do J := J - 1; If I <= J then begin Q := FList^[I]; Flist^[I] := FList^[J]; FList^[J] := Q; I := I + 1; J := J - 1; end; until I > J; if L < J then QuickSort(FList, L, J); L := I; until I >= R; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufileviewnotebook.pas����������������������������������������������������������0000644�0001750�0000144�00000057515�14743153644�017657� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- This unit contains TFileViewPage and TFileViewNotebook objects. Copyright (C) 2016-2024 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Notes: 1. TFileViewNotebook.DestroyAllPages is the workaround for the bug of Lazarus. TFileViewNotebook.DestroyAllPages and the related codes can be removed, after Double Commander built with Lazarus 2.4 on Linux. see also: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40019 https://github.com/doublecmd/doublecmd/pull/703 } unit uFileViewNotebook; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, ComCtrls, LMessages, LCLType, Forms, uFileView, uFilePanelSelect, DCXmlConfig; type TTabLockState = ( tlsNormal, //<en Default state. tlsPathLocked, //<en Path changes are not allowed. tlsPathResets, //<en Path is reset when activating the tab. tlsDirsInNewTab); //<en Path change opens a new tab. TFileViewNotebook = class; { TFileViewPage } TFileViewPage = class(TTabSheet) private FLockState: TTabLockState; FLockPath: String; //<en Path on which tab is locked FOnActivate: TNotifyEvent; FCurrentTitle: String; FPermanentTitle: String; FBackupViewMode: String; FBackupColumnSet: String; FOnChangeFileView: TNotifyEvent; FBackupViewClass: TFileViewClass; procedure AssignPage(OtherPage: TFileViewPage); procedure AssignProperties(OtherPage: TFileViewPage); {en Retrieves the file view on this page. } function GetFileView: TFileView; {en Retrieves notebook on which this page is. } function GetNotebook: TFileViewNotebook; {en Frees current file view and assigns a new one. } procedure SetFileView(aFileView: TFileView); procedure SetLockState(NewLockState: TTabLockState); procedure SetPermanentTitle(AValue: String); procedure DoActivate; protected procedure PaintWindow(DC: HDC); override; {$IF DEFINED(LCLWIN32)} procedure RealSetText(const AValue: TCaption); override; {$ENDIF} procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message LM_ERASEBKGND; public constructor Create(TheOwner: TComponent); override; function IsActive: Boolean; procedure MakeActive; procedure UpdateTitle; procedure LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); procedure SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); property LockState: TTabLockState read FLockState write SetLockState; property LockPath: String read FLockPath write FLockPath; property FileView: TFileView read GetFileView write SetFileView; property Notebook: TFileViewNotebook read GetNotebook; property PermanentTitle: String read FPermanentTitle write SetPermanentTitle; property CurrentTitle: String read FCurrentTitle; property OnActivate: TNotifyEvent read FOnActivate write FOnActivate; property BackupViewMode: String read FBackupViewMode write FBackupViewMode; property BackupColumnSet: String read FBackupColumnSet write FBackupColumnSet; property BackupViewClass: TFileViewClass read FBackupViewClass write FBackupViewClass; property OnChangeFileView: TNotifyEvent read FOnChangeFileView write FOnChangeFileView; end; { TFileViewNotebook } TFileViewNotebook = class(TPageControl) private FNotebookSide: TFilePanelSelect; FStartDrag: Boolean; FDraggedPageIndex: Integer; FTabDblClicked: Boolean; FHintPageIndex: Integer; FHintPos: TPoint; FLastMouseDownTime: TDateTime; FLastMouseDownPageIndex: Integer; function GetActivePage: TFileViewPage; function GetActiveView: TFileView; function GetFileViewOnPage(Index: Integer): TFileView; function GetPage(Index: Integer): TFileViewPage; reintroduce; procedure TabShowHint(Sender: TObject; HintInfo: PHintInfo); protected procedure DoChange; override; function GetPageClass: TCustomPageClass; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message LM_ERASEBKGND; {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6))} procedure CNNotify(var Message: TLMNotify); message CN_NOTIFY; {$ENDIF} {$IF DEFINED(LCLWIN32)} procedure PaintWindow(DC: HDC); override; {$ENDIF} public constructor Create(ParentControl: TWinControl; NotebookSide: TFilePanelSelect); reintroduce; {$IFDEF LCLWIN32} {en Removes the rectangle of the pages contents from erasing background to reduce flickering. This is not needed on non-Windows because EraseBackground is not used there. } procedure EraseBackground(DC: HDC); override; procedure WndProc(var Message: TLMessage); override; {$ENDIF} function AddPage: TFileViewPage; function InsertPage(Index: Integer): TFileViewPage; reintroduce; function NewEmptyPage: TFileViewPage; function NewPage(CloneFromPage: TFileViewPage): TFileViewPage; function NewPage(CloneFromView: TFileView): TFileViewPage; procedure RemovePage(Index: Integer); reintroduce; procedure RemovePage(var aPage: TFileViewPage); procedure DestroyAllPages; procedure ActivatePrevTab; procedure ActivateNextTab; procedure ActivateTabByIndex(Index: Integer); function IndexOfPageAt(P: TPoint): Integer; override; procedure DragDrop(Source: TObject; X,Y: Integer); override; procedure DragOver(Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean); override; property ActivePage: TFileViewPage read GetActivePage; property ActiveView: TFileView read GetActiveView; property DoubleClickPageIndex: Integer read FLastMouseDownPageIndex; property Page[Index: Integer]: TFileViewPage read GetPage; property View[Index: Integer]: TFileView read GetFileViewOnPage; default; property Side: TFilePanelSelect read FNotebookSide; published property OnDblClick; property OnChange; property OnMouseDown; property OnMouseUp; end; implementation uses LCLIntf, LazUTF8, DCStrUtils, uGlobs, uColumnsFileView, uArchiveFileSource {$IF DEFINED(LCLGTK2)} , Glib2, Gtk2 {$ELSEIF DEFINED(LCLWIN32)} , Win32Proc, Win32Themes, UxTheme, Graphics , Themes {$IF DEFINED(DARKWIN)}, uDarkStyle {$ENDIF} {$ENDIF} {$IF DEFINED(MSWINDOWS)} , Windows, Messages {$ENDIF} ; // -- TFileViewPage ----------------------------------------------------------- procedure TFileViewPage.AssignPage(OtherPage: TFileViewPage); begin AssignProperties(OtherPage); SetFileView(nil); // Remove previous view. OtherPage.FileView.Clone(Self); end; procedure TFileViewPage.AssignProperties(OtherPage: TFileViewPage); begin FLockState := OtherPage.FLockState; FLockPath := OtherPage.FLockPath; FCurrentTitle := OtherPage.FCurrentTitle; FPermanentTitle := OtherPage.FPermanentTitle; end; constructor TFileViewPage.Create(TheOwner: TComponent); begin FLockState := tlsNormal; FBackupViewClass := TColumnsFileView; inherited Create(TheOwner); end; {$IF DEFINED(LCLWIN32)} procedure TFileViewPage.RealSetText(const AValue: TCaption); begin inherited RealSetText(AValue); if HandleAllocated then LCLControlSizeNeedsUpdate(Parent, True); end; {$ENDIF} function TFileViewPage.IsActive: Boolean; begin Result := Assigned(Notebook) and (Notebook.PageIndex = PageIndex); end; procedure TFileViewPage.LoadConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); begin FLockState := TTabLockState(AConfig.GetValue(ANode, 'Options', Integer(tlsNormal))); FLockPath := AConfig.GetValue(ANode, 'LockPath', ''); FPermanentTitle := AConfig.GetValue(ANode, 'Title', ''); end; procedure TFileViewPage.SaveConfiguration(AConfig: TXmlConfig; ANode: TXmlNode); begin AConfig.AddValueDef(ANode, 'Options', Integer(FLockState), Integer(tlsNormal)); AConfig.AddValueDef(ANode, 'LockPath', FLockPath, ''); AConfig.AddValueDef(ANode, 'Title', FPermanentTitle, ''); end; procedure TFileViewPage.MakeActive; var aFileView: TFileView; begin if Assigned(Notebook) then begin Notebook.PageIndex := PageIndex; aFileView := FileView; if Assigned(aFileView) then aFileView.SetFocus; end; end; procedure TFileViewPage.PaintWindow(DC: HDC); begin // Don't paint anything. end; procedure TFileViewPage.UpdateTitle; {$IFDEF MSWINDOWS} function LocalGetDriveName(A:string):string; begin result:=LowerCase(ExtractFileDrive(A)); if length(result)>2 then // Server path name are shown simply like \: in TC so let's do the same for those who get used to that. result:='\:' else if Lowercase(A) = (result+DirectorySeparator) then result:=''; //To avoid to get "c:C:" :-) end; {$ENDIF} var NewCaption: String; begin if Assigned(FileView) then begin if FPermanentTitle <> '' then begin NewCaption := FPermanentTitle; FCurrentTitle := FPermanentTitle; end else begin if (FileView.FileSource is TArchiveFileSource) and (FileView.FileSource.IsPathAtRoot(FileView.CurrentPath)) then begin with (FileView.FileSource as TArchiveFileSource) do NewCaption := ExtractFileName(ArchiveFileName); end else begin NewCaption := FileView.CurrentPath; if NewCaption <> '' then NewCaption := GetLastDir(NewCaption); end; FCurrentTitle := NewCaption; end; {$IFDEF MSWINDOWS} if tb_show_drive_letter in gDirTabOptions then begin if (FileView.FileSource is TArchiveFileSource) then with (FileView.FileSource as TArchiveFileSource) do NewCaption := LocalGetDriveName(ArchiveFileName) + NewCaption else NewCaption := LocalGetDriveName(FileView.CurrentPath) + NewCaption; end; {$ENDIF} if (FLockState in [tlsPathLocked, tlsPathResets, tlsDirsInNewTab]) and (tb_show_asterisk_for_locked in gDirTabOptions) then NewCaption := '*' + NewCaption; if (tb_text_length_limit in gDirTabOptions) and (UTF8Length(NewCaption) > gDirTabLimit) then NewCaption := UTF8Copy(NewCaption, 1, gDirTabLimit) + '..'; {$IF DEFINED(LCLGTK2)} Caption := NewCaption; {$ELSE} Caption := StringReplace(NewCaption, '&', '&&', [rfReplaceAll]); {$ENDIF} end; end; procedure TFileViewPage.WMEraseBkgnd(var Message: TLMEraseBkgnd); begin Message.Result := 1; end; function TFileViewPage.GetFileView: TFileView; begin if ComponentCount > 0 then Result := TFileView(Components[0]) else Result := nil; end; procedure TFileViewPage.SetFileView(aFileView: TFileView); var aComponent: TComponent; begin if ComponentCount > 0 then begin aComponent := Components[0]; aComponent.Free; end; if Assigned(aFileView) then begin aFileView.Parent := Self; BackupViewMode := EmptyStr; if Assigned(FOnChangeFileView) then FOnChangeFileView(aFileView); end; end; function TFileViewPage.GetNotebook: TFileViewNotebook; begin Result := Parent as TFileViewNotebook; end; procedure TFileViewPage.SetLockState(NewLockState: TTabLockState); begin if FLockState = NewLockState then Exit; if NewLockState in [tlsPathLocked, tlsPathResets, tlsDirsInNewTab] then begin LockPath := FileView.CurrentPath; if (FLockState <> tlsNormal) or (Length(FPermanentTitle) = 0) then FPermanentTitle := GetLastDir(LockPath); end else begin LockPath := ''; if not (tb_keep_renamed_when_back_normal in gDirTabOptions) then FPermanentTitle := ''; end; FLockState := NewLockState; UpdateTitle; end; procedure TFileViewPage.SetPermanentTitle(AValue: String); begin if FPermanentTitle = AValue then Exit; FPermanentTitle := AValue; UpdateTitle; end; procedure TFileViewPage.DoActivate; begin if Assigned(FOnActivate) then FOnActivate(Self); end; // -- TFileViewNotebook ------------------------------------------------------- constructor TFileViewNotebook.Create(ParentControl: TWinControl; NotebookSide: TFilePanelSelect); begin inherited Create(ParentControl); ControlStyle := ControlStyle + [csNoFocus]; Parent := ParentControl; TabStop := False; ShowHint := True; FHintPageIndex := -1; FNotebookSide := NotebookSide; FStartDrag := False; OnShowHint := @TabShowHint; {$IFDEF MSWINDOWS} // The pages contents are removed from drawing background in EraseBackground. // But double buffering could be enabled to eliminate flickering of drawing // the tabs buttons themselves. But currently there's a bug where the buffer // bitmap is temporarily drawn in different position, probably at (0,0) and // not where pages contents start (after applying TCM_ADJUSTRECT). //DoubleBuffered := True; {$ENDIF} end; function TFileViewNotebook.GetActivePage: TFileViewPage; begin if PageIndex <> -1 then Result := GetPage(PageIndex) else Result := nil; end; function TFileViewNotebook.GetActiveView: TFileView; var APage: TFileViewPage; begin APage := GetActivePage; if Assigned(APage) then Result := APage.FileView else Result := nil; end; function TFileViewNotebook.GetFileViewOnPage(Index: Integer): TFileView; var APage: TFileViewPage; begin APage := GetPage(Index); Result := APage.FileView; end; function TFileViewNotebook.GetPage(Index: Integer): TFileViewPage; begin Result := TFileViewPage(CustomPage(Index)); end; function TFileViewNotebook.AddPage: TFileViewPage; begin Result := InsertPage(PageCount); end; function TFileViewNotebook.InsertPage(Index: Integer): TFileViewPage; begin Tabs.Insert(Index, ''); Result := GetPage(Index); ShowTabs:= ((PageCount > 1) or (tb_always_visible in gDirTabOptions)) and gDirectoryTabs; end; function TFileViewNotebook.NewEmptyPage: TFileViewPage; begin if tb_open_new_near_current in gDirTabOptions then Result := InsertPage(PageIndex + 1) else Result := InsertPage(PageCount); end; function TFileViewNotebook.NewPage(CloneFromPage: TFileViewPage): TFileViewPage; begin if Assigned(CloneFromPage) then begin Result := NewEmptyPage; Result.AssignPage(CloneFromPage); end else Result := nil; end; function TFileViewNotebook.NewPage(CloneFromView: TFileView): TFileViewPage; begin if Assigned(CloneFromView) then begin Result := NewEmptyPage; CloneFromView.Clone(Result); end else Result := nil; end; procedure TFileViewNotebook.RemovePage(Index: Integer); begin {$IFDEF LCLGTK2} // If removing currently active page, switch to another page first. // Otherwise there can be no page selected. if (PageIndex = Index) and (PageCount > 1) then begin if Index = PageCount - 1 then Page[Index - 1].MakeActive else Page[Index + 1].MakeActive; end; {$ENDIF} Page[Index].Free; ShowTabs:= ((PageCount > 1) or (tb_always_visible in gDirTabOptions)) and gDirectoryTabs; {$IFNDEF LCLGTK2} // Force-activate current page. if PageIndex <> -1 then Page[PageIndex].MakeActive; {$ENDIF} end; procedure TFileViewNotebook.RemovePage(var aPage: TFileViewPage); begin RemovePage(aPage.PageIndex); aPage := nil; end; procedure TFileViewNotebook.WMEraseBkgnd(var Message: TLMEraseBkgnd); begin inherited WMEraseBkgnd(Message); // Always set as handled otherwise if not handled Windows will draw background // with hbrBackground brush of the window class. This might cause flickering // because later background will be again be erased but with TControl.Brush. // This is not actually needed on non-Windows because WMEraseBkgnd is not used there. Message.Result := 1; end; {$IF (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6))} procedure TFileViewNotebook.CNNotify(var Message: TLMNotify); begin // Workaround: https://github.com/doublecmd/doublecmd/issues/1570 if Message.NMHdr^.code = TCN_SELCHANGE then begin if PtrInt(Message.NMHDR^.idfrom) >= PageCount then Message.NMHDR^.idfrom:= PtrUInt(PageCount - 1); end; inherited CNNotify(Message); end; {$ENDIF} {$IF DEFINED(LCLWIN32)} procedure TFileViewNotebook.PaintWindow(DC: HDC); var ARect: TRect; begin inherited PaintWindow(DC); {$IF DEFINED(DARKWIN)} if g_darkModeEnabled then Exit; {$ENDIF} if (Win32MajorVersion >= 10) and (PageIndex > -1) then begin ARect:= TabRect(PageIndex); IntersectClipRect(DC, ARect.Left, ARect.Top, ARect.Right, ARect.Top + ScaleY(3, 96)); InflateRect(ARect, ScaleX(8, 96), 0); DrawThemeBackground(TWin32ThemeServices(ThemeServices).Theme[teToolBar], DC, TP_BUTTON, TS_CHECKED, ARect, nil); end; end; {$ENDIF} procedure TFileViewNotebook.DestroyAllPages; var i: Integer; begin for i:=PageCount-1 downto 0 do if i<>ActivePageIndex then Tabs.Delete( i ); Tabs.Delete( 0 ); end; procedure TFileViewNotebook.ActivatePrevTab; begin if PageIndex = 0 then Page[PageCount - 1].MakeActive else Page[PageIndex - 1].MakeActive; end; procedure TFileViewNotebook.ActivateNextTab; begin if PageIndex = PageCount - 1 then Page[0].MakeActive else Page[PageIndex + 1].MakeActive; end; procedure TFileViewNotebook.ActivateTabByIndex(Index: Integer); begin if Index < -1 then Exit; if Index = -1 then Page[PageCount - 1].MakeActive else if PageCount >= Index + 1 then Page[Index].MakeActive; end; function TFileViewNotebook.IndexOfPageAt(P: TPoint): Integer; begin Result:= inherited IndexOfPageAt(P); if (Result >= PageCount) then Result:= -1; end; // compared to handling hints in MouseMove(), DoShowHint() is compatible // with all WidgetSets. // on Windows, when Mouse Move in the blank of the TabControl, // MouseMove() will not be called, then the wrong hint is shown. procedure TFileViewNotebook.TabShowHint(Sender: TObject; HintInfo: PHintInfo); var ATabIndex: Integer; begin ATabIndex := IndexOfPageAt( ScreenToClient(Mouse.CursorPos) ); if ATabIndex >= 0 then begin if (ATabIndex <> PageIndex) and (Length(Page[ATabIndex].LockPath) <> 0) then HintInfo^.HintStr := '* ' + Page[ATabIndex].LockPath else HintInfo^.HintStr := View[ATabIndex].CurrentPath; end else begin HintInfo^.HintStr := ''; FHintPos := TPoint.Zero; end; if ATabIndex <> FHintPageIndex then begin FHintPageIndex := ATabIndex; FHintPos := HintInfo^.HintPos; end else begin if not FHintPos.IsZero then HintInfo^.HintPos := FHintPos; end; HintInfo^.ReshowTimeout := 500; end; procedure TFileViewNotebook.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); {$IF DEFINED(LCLGTK2)} var ArrowWidth: Integer; arrow_spacing: gint = 0; scroll_arrow_hlength: gint = 16; {$ENDIF} begin inherited; if Button = mbLeft then begin FDraggedPageIndex := IndexOfPageAt(Classes.Point(X, Y)); FStartDrag := (FDraggedPageIndex <> -1); end; // Emulate double click if (Button = mbLeft) and Assigned(OnDblClick) then begin if ((Now - FLastMouseDownTime) > ((1/86400)*(GetDoubleClickTime/1000))) then begin FLastMouseDownTime:= Now; FLastMouseDownPageIndex:= FDraggedPageIndex; end else if (FDraggedPageIndex = FLastMouseDownPageIndex) then begin {$IF DEFINED(LCLGTK2)} gtk_widget_style_get(PGtkWidget(Self.Handle), 'arrow-spacing', @arrow_spacing, 'scroll-arrow-hlength', @scroll_arrow_hlength, nil); ArrowWidth:= arrow_spacing + scroll_arrow_hlength; if (X > ArrowWidth) and (X < ClientWidth - ArrowWidth) then {$ENDIF} {$IFNDEF LCLCOCOA} OnDblClick(Self); FStartDrag:= False; FLastMouseDownTime:= 0; FLastMouseDownPageIndex:= -1; {$ELSE} FStartDrag:= False; FLastMouseDownTime:= 0; FTabDblClicked := true; {$ENDIF} end; end; end; procedure TFileViewNotebook.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited; if FStartDrag then begin FStartDrag := False; BeginDrag(False); end; end; procedure TFileViewNotebook.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin {$IFDEF LCLCOCOA} if FTabDblClicked then begin OnDblClick(Self); FLastMouseDownPageIndex:= -1; FTabDblClicked := false; end; {$ENDIF} inherited; FStartDrag := False; end; procedure TFileViewNotebook.DragOver(Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean); var ATabIndex: Integer; begin if (Source is TFileViewNotebook) then begin ATabIndex := IndexOfPageAt(Classes.Point(X, Y)); Accept := (Source <> Self) or ((ATabIndex <> -1) and (ATabIndex <> FDraggedPageIndex)); end else begin inherited DragOver(Source, X, Y, State, Accept); end; end; {$IFDEF LCLWIN32} procedure TFileViewNotebook.EraseBackground(DC: HDC); var ARect: TRect; SaveIndex: Integer; Clip: Integer; begin if HandleAllocated and (DC <> 0) then begin ARect := Classes.Rect(0, 0, Width, Height); Windows.TabCtrl_AdjustRect(Handle, False, ARect); SaveIndex := SaveDC(DC); Clip := ExcludeClipRect(DC, ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); if Clip <> NullRegion then begin ARect := Classes.Rect(0, 0, Width, Height); FillRect(DC, ARect, HBRUSH(Brush.Reference.Handle)); end; RestoreDC(DC, SaveIndex); end; end; procedure TFileViewNotebook.WndProc(var Message: TLMessage); begin inherited WndProc(Message); if Message.Msg = TCM_ADJUSTRECT then begin if Message.WParam = 0 then PRect(Message.LParam)^.Left := PRect(Message.LParam)^.Left - 2 else begin PRect(Message.LParam)^.Left := PRect(Message.LParam)^.Left + 2; end; end; end; {$ENDIF} procedure TFileViewNotebook.DragDrop(Source: TObject; X,Y: Integer); var ATabIndex: Integer; SourceNotebook: TFileViewNotebook; ANewPage, DraggedPage: TFileViewPage; begin if (Source is TFileViewNotebook) then begin SourceNotebook := TFileViewNotebook(Source); ATabIndex := IndexOfPageAt(Classes.Point(X, Y)); if Source = Self then begin // Move within the same panel. if ATabIndex <> -1 then Tabs.Move(FDraggedPageIndex, ATabIndex); end else if (SourceNotebook.FDraggedPageIndex < SourceNotebook.PageCount) then begin // Move page between panels. DraggedPage := SourceNotebook.Page[SourceNotebook.FDraggedPageIndex]; if ATabIndex = -1 then ATabIndex := PageCount; // Create a clone of the page in the panel. ANewPage := InsertPage(ATabIndex); ANewPage.AssignPage(DraggedPage); ANewPage.MakeActive; if (ssShift in GetKeyShiftState) and (SourceNotebook.PageCount > 1) then begin // Remove page from source panel. SourceNotebook.RemovePage(DraggedPage); end; end; end else begin inherited DragDrop(Source, X, Y); end; end; procedure TFileViewNotebook.DoChange; begin inherited DoChange; ActivePage.DoActivate; {$IF DEFINED(LCLWIN32)} if (Win32MajorVersion >= 10) {$IF DEFINED(DARKWIN)} and (not g_darkModeEnabled){$ENDIF} then Invalidate; {$ENDIF} end; function TFileViewNotebook.GetPageClass: TCustomPageClass; begin Result:= TFileViewPage; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufindbyrmr.pas�����������������������������������������������������������������0000644�0001750�0000144�00000010537�14743153644�016271� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ implementing memory searching with case (any single-byte encoding) and mmap file to memory based on ufindmmap.pas by radek.cervinka@centrum.cz } unit uFindByrMr; {$mode objfpc}{$H+} interface type TAbortFunction = function: Boolean of object; TRecodeTable = array[0..255] of byte; function PosMemBoyerMur(pAdr: PChar; iLength: PtrInt; const sFindData: String; RecodeTable: TRecodeTable): PtrInt; {en Searches a file for a string using memory mapping. @param(sFileName File to search in.) @param(sFindData String to search for.) @param(RecodeTable table for case-insensitive compare) @param(Abort This function is called repeatedly during searching. If it returns @true the search is aborted.) @returns(-1 in case of error @br 0 if the string wasn't found @br 1 if the string was found) } function FindMmapBM(const sFileName: String; const sFindData: String; RecodeTable: TRecodeTable; Abort: TAbortFunction): PtrInt; {en Initializes table for recode from different encodings. @param(Encoding Name of encoding.) @param(bCaseSensitive If @true the search is case sensitive.) @returns(TRecodeTable array to use in FindMmap) } function InitRecodeTable(Encoding: String; bCaseSensitive: Boolean): TRecodeTable; implementation uses DCOSUtils, LConvEncoding, LazUTF8, uConvEncoding; type TIntArray = array of Integer; function InitRecodeTable(Encoding:string; bCaseSensitive: Boolean): TRecodeTable; var i:byte; c:string; begin for i:=0 to 255 do begin if bCaseSensitive then Result[i]:=i else begin c:=ConvertEncoding(chr(i), Encoding, EncodingUTF8); c:=UTF8UpperCase(c); c:=ConvertEncoding(c, EncodingUTF8, Encoding); if length(c)>0 then Result[i]:=ord(c[1]); end; end; end; function PosMemBoyerMur(pAdr: PChar; iLength: PtrInt; const sFindData: String; RecodeTable: TRecodeTable): PtrInt; function prefixFunc(s:string):TIntArray; var k,i:Integer; begin SetLength(Result, Length(s)+1); Result[0] := 0; Result[1] := 0; k := 0; for i := 2 to Length(s) do begin while (k > 0) and (s[k+1] <> s[i]) do k := Result[k]; if s[k+1] = s[i] then Inc(k); Result[i] := k; end; end; var StopTable:array[0..255] of byte; prefTable,pf1,pf2:TIntArray; i,j,len:Integer; curPos,curCharPos:PtrInt; encStr,rvrsStr:string; curChar:byte; begin Result:=-1; len:=Length(sFindData); encStr:=''; for i:=1 to len do encStr:=encStr+chr(RecodeTable[ord(sFindData[i])]); rvrsStr:=''; for i:=len downto 1 do rvrsStr:=rvrsStr+encStr[i]; for i:=0 to 255 do StopTable[i]:=0; for i:=len-1 downto 1 do if StopTable[ord(encStr[i])]=0 then StopTable[ord(encStr[i])]:=i; //Calc prefix table pf1:=prefixFunc(encStr); pf2:=prefixFunc(rvrsStr); setLength(prefTable,len+1); for j:=0 to len do prefTable[j]:= len - pf1[len]; for i:=1 to len do begin j:= len - pf2[i]; if i - pf2[i] < prefTable[j] then prefTable[j]:= i - pf2[i]; end; curPos:=0; while curPos<=iLength-len do begin curCharPos:=len; curChar:=RecodeTable[ord((pAdr+curPos+curCharPos-1)^)]; while (curCharPos>0) do begin if (curChar<>byte(encStr[curCharPos])) then break; dec(curCharPos); if curCharPos>0 then curChar:=RecodeTable[ord((pAdr+curPos+curCharPos-1)^)]; end; if curCharPos=0 then begin//found Result:=curPos; exit; end else begin//shift if curCharPos=len then curPos:=curPos+len-StopTable[curChar] else curPos:=curPos+prefTable[curCharPos]; end end; end; function FindMmapBM(const sFileName, sFindData: String; RecodeTable: TRecodeTable; Abort: TAbortFunction): PtrInt; var fmr : TFileMapRec; begin Result := -1; if MapFile(sFileName, fmr) then begin try begin if PosMemBoyerMur(fmr.MappedFile, fmr.FileSize, sFindData, RecodeTable) <> -1 then Result := 1 else Result := 0; end; finally UnMapFile(fmr); end; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufindfiles.pas�����������������������������������������������������������������0000644�0001750�0000144�00000045604�14743153644�016243� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Structures and functions for searching files. Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz) Copyright (C) 2010 Przemysaw Nagay (cobines@gmail.com) Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uFindFiles; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes, uFile, uFindEx; type TTextSearchOption = (tsoMatchCase, tsoRegExpr, tsoHex); TTextSearchOptions = set of TTextSearchOption; TTextSearch = (tsAnsi, tsUtf8, tsUtf16le, tsUtf16be, tsOther); TTimeUnit = (tuSecond, tuMinute, tuHour, tuDay, tuWeek, tuMonth, tuYear); TFileSizeUnit = (suBytes, suKilo, suMega, suGiga, suTera); TPluginOperator = (poEqualCaseSensitive, poNotEqualCaseSensitive, poMore, poLess, poMoreEqual, poLessEqual, poEqualCaseInsensitive, poNotEqualCaseInsensitive, poContainsCaseSensitive, poNotContainsCaseSensitive, poContainsCaseInsensitive, poNotContainsCaseInsensitive, poRegExpr, poNotRegExpr); TPluginSearchRec = record Plugin: String; Field: String; UnitName: String; FieldType: Integer; Compare: TPluginOperator; Value: Variant; end; TSearchTemplateRec = record StartPath: String; ExcludeDirectories: String; FilesMasks: String; ExcludeFiles: String; SearchDepth: Integer; // -1 = unlimited RegExp: Boolean; IsPartialNameSearch: Boolean; FollowSymLinks: Boolean; AttributesPattern: String; FindInArchives: Boolean; { Date/time } IsDateFrom, IsDateTo, IsTimeFrom, IsTimeTo : Boolean; DateTimeFrom, DateTimeTo : TDateTime; IsNotOlderThan: Boolean; NotOlderThan: Integer; NotOlderThanUnit: TTimeUnit; { File size } IsFileSizeFrom, IsFileSizeTo : Boolean; FileSizeFrom, FileSizeTo : Int64; FileSizeUnit: TFileSizeUnit; { Find/replace text } IsFindText: Boolean; FindText: String; IsReplaceText : Boolean; ReplaceText: String; HexValue, CaseSensitive, NotContainingText: Boolean; TextRegExp: Boolean; TextEncoding: String; OfficeXML: Boolean; { Duplicates } Duplicates: Boolean; DuplicateName: Boolean; DuplicateSize: Boolean; DuplicateHash: Boolean; DuplicateContent: Boolean; { Plugins } SearchPlugin: String; ContentPlugin: Boolean; ContentPluginCombine: Boolean; ContentPlugins: array of TPluginSearchRec; end; TFindFileAttrsCheck = record HaveAttrs: TFileAttrs; //en> what attributes files must have DontHaveAttrs: TFileAttrs; //en> what attributes files must not have Negated: Boolean; end; TFindFileChecks = record FilesMasks: String; ExcludeFiles: String; ExcludeDirectories: String; RegExp: Boolean; DateTimeFrom, DateTimeTo : TDateTime; FileSizeFrom, FileSizeTo : Int64; Attributes: array of TFindFileAttrsCheck; //en> Each entry is OR'ed. end; TPFindFileChecks = ^TFindFileChecks; procedure SearchTemplateToFindFileChecks(const SearchTemplate: TSearchTemplateRec; out FileChecks: TFindFileChecks); procedure DateTimeOptionsToChecks(const SearchTemplate: TSearchTemplateRec; var FileChecks: TFindFileChecks); function CheckPlugin(const SearchTemplate: TSearchTemplateRec; const AFile: TFile) : Boolean; function CheckPlugin(const SearchTemplate: TSearchTemplateRec; const SearchRec: TSearchRecEx; const Folder: String) : Boolean; function CheckDirectoryName(const FileChecks: TFindFileChecks; const DirectoryName: String) : Boolean; function CheckDirectoryNameEx(const FileChecks: TFindFileChecks; const FullPath, BasePath: String) : Boolean; function CheckFileName(const FileChecks: TFindFileChecks; const FileName: String) : Boolean; function CheckFileTime(const FileChecks: TFindFileChecks; FT : TFileTime) : Boolean; inline; function CheckFileDateTime(const FileChecks: TFindFileChecks; DT : TDateTime) : Boolean; function CheckFileSize(const FileChecks: TFindFileChecks; FileSize : Int64) : Boolean; function CheckFileAttributes(const FileChecks: TFindFileChecks; Attrs : TFileAttrs) : Boolean; function CheckFile(const SearchTemplate: TSearchTemplateRec; const FileChecks: TFindFileChecks; const AFile: TFile) : Boolean; procedure AttrsPatternOptionsToChecks(const SearchTemplate: TSearchTemplateRec; var FileChecks: TFindFileChecks); implementation uses StrUtils, DateUtils, DCDateTimeUtils, DCFileAttributes, RegExpr, uMasks, DCStrUtils, DCUnicodeUtils, uFileProperty, uGlobs, uWDXModule, LazUTF8, WdxPlugin, Variants, uRegExprW, uFileSystemFileSource; const cKilo = 1024; cMega = 1024 * cKilo; cGiga = 1024 * cMega; cTera = 1024 * cGiga; procedure FileMaskOptionsToChecks(const SearchTemplate: TSearchTemplateRec; var FileChecks: TFindFileChecks); var sMask, sTemp: String; begin FileChecks.FilesMasks := SearchTemplate.FilesMasks; if SearchTemplate.IsPartialNameSearch then begin sTemp:= EmptyStr; while (Length(FileChecks.FilesMasks) > 0) do begin sMask:= Copy2SymbDel(FileChecks.FilesMasks, ';'); if not ContainsOneOf(sMask, '*?') then begin if Length(sMask) = 0 then sMask:= AllFilesMask else begin sMask:= '*' + sMask + '*'; end; end; sTemp:= sTemp + sMask + ';'; end; if (Length(sTemp) = 0) then FileChecks.FilesMasks := AllFilesMask else FileChecks.FilesMasks := Copy(sTemp, 1, Length(sTemp) - 1); end; end; procedure DateTimeOptionsToChecks(const SearchTemplate: TSearchTemplateRec; var FileChecks: TFindFileChecks); begin with FileChecks do begin if SearchTemplate.IsNotOlderThan then begin DateTimeFrom := SysUtils.Now; DateTimeTo := MaxDateTime; case SearchTemplate.NotOlderThanUnit of tuSecond: DateTimeFrom := IncSecond(DateTimeFrom, -SearchTemplate.NotOlderThan); tuMinute: DateTimeFrom := IncMinute(DateTimeFrom, -SearchTemplate.NotOlderThan); tuHour: DateTimeFrom := IncHour(DateTimeFrom, -SearchTemplate.NotOlderThan); tuDay: DateTimeFrom := IncDay(DateTimeFrom, -SearchTemplate.NotOlderThan); tuWeek: DateTimeFrom := IncWeek(DateTimeFrom, -SearchTemplate.NotOlderThan); tuMonth: DateTimeFrom := IncMonth(DateTimeFrom, -SearchTemplate.NotOlderThan); tuYear: DateTimeFrom := IncYear(DateTimeFrom, -SearchTemplate.NotOlderThan); end; end else begin if SearchTemplate.IsDateFrom then begin if SearchTemplate.IsTimeFrom then DateTimeFrom := SearchTemplate.DateTimeFrom else DateTimeFrom := Trunc(SearchTemplate.DateTimeFrom); end else if SearchTemplate.IsTimeFrom then DateTimeFrom := Frac(SearchTemplate.DateTimeFrom) else DateTimeFrom := MinDateTime; if SearchTemplate.IsDateTo then begin if SearchTemplate.IsTimeTo then DateTimeTo := SearchTemplate.DateTimeTo else DateTimeTo := Trunc(SearchTemplate.DateTimeTo) + Frac(MaxDateTime); end else if SearchTemplate.IsTimeTo then DateTimeTo := Frac(SearchTemplate.DateTimeTo) else DateTimeTo := MaxDateTime; end; end; end; procedure FileSizeOptionsToChecks(const SearchTemplate: TSearchTemplateRec; var FileChecks: TFindFileChecks); function GetFileSizeWithUnit(Size: Int64): Int64; begin case SearchTemplate.FileSizeUnit of suBytes: Result := Size; suKilo: Result := Size * cKilo; suMega: Result := Size * cMega; suGiga: Result := Size * cGiga; suTera: Result := Size * cTera; end; end; begin if SearchTemplate.IsFileSizeFrom then FileChecks.FileSizeFrom := GetFileSizeWithUnit(SearchTemplate.FileSizeFrom) else FileChecks.FileSizeFrom := 0; if SearchTemplate.IsFileSizeTo then FileChecks.FileSizeTo := GetFileSizeWithUnit(SearchTemplate.FileSizeTo) else FileChecks.FileSizeTo := High(FileChecks.FileSizeTo); end; function AttrPatternToCheck(const AttrPattern: String): TFindFileAttrsCheck; var StartIndex, CurIndex: Integer; begin Result.HaveAttrs := 0; Result.DontHaveAttrs := 0; Result.Negated := False; StartIndex := 1; CurIndex := StartIndex; while CurIndex <= Length(AttrPattern) do begin case AttrPattern[CurIndex] of '+': begin Result.HaveAttrs := Result.HaveAttrs or SingleStrToFileAttr(Copy(AttrPattern, StartIndex, CurIndex - StartIndex)); StartIndex := CurIndex + 1; end; '-': begin Result.DontHaveAttrs := Result.DontHaveAttrs or SingleStrToFileAttr(Copy(AttrPattern, StartIndex, CurIndex - StartIndex)); StartIndex := CurIndex + 1; end; '!': begin if CurIndex = 1 then Result.Negated := True; StartIndex := CurIndex + 1; end; ' ': // omit spaces begin StartIndex := CurIndex + 1; end; end; Inc(CurIndex); end; end; procedure AttrsPatternOptionsToChecks(const SearchTemplate: TSearchTemplateRec; var FileChecks: TFindFileChecks); var AttrsPattern, CurPattern: String; begin FileChecks.Attributes := nil; AttrsPattern := SearchTemplate.AttributesPattern; while AttrsPattern <> '' do begin // For each pattern separated by '|' create a new TFindFileAttrsCheck. CurPattern := Copy2SymbDel(AttrsPattern, '|'); if CurPattern <> '' then with FileChecks do begin SetLength(Attributes, Length(Attributes) + 1); Attributes[Length(Attributes) - 1] := AttrPatternToCheck(CurPattern); end; end; end; procedure SearchTemplateToFindFileChecks(const SearchTemplate: TSearchTemplateRec; out FileChecks: TFindFileChecks); begin FileChecks.ExcludeFiles := SearchTemplate.ExcludeFiles; FileChecks.ExcludeDirectories := SearchTemplate.ExcludeDirectories; FileChecks.RegExp := SearchTemplate.RegExp; FileMaskOptionsToChecks(SearchTemplate, FileChecks); DateTimeOptionsToChecks(SearchTemplate, FileChecks); FileSizeOptionsToChecks(SearchTemplate, FileChecks); AttrsPatternOptionsToChecks(SearchTemplate, FileChecks); end; function CheckPluginFullText(Module: TWdxModule; constref ContentPlugin: TPluginSearchRec; const FileName: String): Boolean; var Value: String; Old: String = ''; FindText: String; FieldIndex: Integer; UnitIndex: Integer = 0; begin // Prepare find text case ContentPlugin.Compare of poContainsCaseInsensitive, poNotContainsCaseInsensitive: FindText := UTF8LowerCase(ContentPlugin.Value); else FindText:= ContentPlugin.Value; end; // Find field index FieldIndex:= Module.GetFieldIndex(ContentPlugin.Field); Value:= Module.CallContentGetValue(FileName, FieldIndex, UnitIndex); while Length(Value) > 0 do begin Old+= Value; DCUnicodeUtils.Utf8FixBroken(Old); case ContentPlugin.Compare of poContainsCaseSensitive: Result := Pos(FindText, Old) > 0; poNotContainsCaseSensitive: Result := Pos(FindText, Old) = 0; poContainsCaseInsensitive: Result := Pos(FindText, UTF8LowerCase(Old)) > 0; poNotContainsCaseInsensitive: Result := Pos(FindText, UTF8LowerCase(Old)) = 0; end; if Result then begin Module.CallContentGetValue(FileName, FieldIndex, -1, 0); Exit; end; Old:= RightStr(Value, Length(FindText)); Value:= Module.CallContentGetValue(FileName, FieldIndex, UnitIndex); end; Result:= False; end; function CheckPlugin(const SearchTemplate: TSearchTemplateRec; const AFile: TFile): Boolean; var I: Integer; Work: Boolean; Value: Variant; FileName: String; Module: TWdxModule; begin FileName := AFile.FullPath; Result := SearchTemplate.ContentPluginCombine; for I:= Low(SearchTemplate.ContentPlugins) to High(SearchTemplate.ContentPlugins) do with SearchTemplate do begin Module := gWDXPlugins.GetWdxModule(ContentPlugins[I].Plugin); if (Module = nil) or (not Module.IsLoaded) then Work:= False else if not Module.FileParamVSDetectStr(AFile) then Work:= False else if ContentPlugins[I].FieldType in [ft_fulltext, ft_fulltextw] then Work:= CheckPluginFullText(Module, ContentPlugins[I], FileName) else begin Value:= Module.CallContentGetValueV(FileName, ContentPlugins[I].Field, ContentPlugins[I].UnitName, 0); if VarIsEmpty(Value) then begin Work:= False; end else case ContentPlugins[I].Compare of poEqualCaseSensitive: Work:= (ContentPlugins[I].Value = Value); poNotEqualCaseSensitive: Work:= (ContentPlugins[I].Value <> Value); poMore: Work := (Value > ContentPlugins[I].Value); poLess: Work := (Value < ContentPlugins[I].Value); poMoreEqual: Work := (Value >= ContentPlugins[I].Value); poLessEqual: Work := (Value <= ContentPlugins[I].Value); poEqualCaseInsensitive: Work:= UTF8CompareText(Value, ContentPlugins[I].Value) = 0; poNotEqualCaseInsensitive: Work:= UTF8CompareText(Value, ContentPlugins[I].Value) <> 0; poContainsCaseSensitive: Work := UTF8Pos(ContentPlugins[I].Value, Value) > 0; poNotContainsCaseSensitive: Work := UTF8Pos(ContentPlugins[I].Value, Value) = 0; poContainsCaseInsensitive: Work := UTF8Pos(UTF8LowerCase(ContentPlugins[I].Value), UTF8LowerCase(Value)) > 0; poNotContainsCaseInsensitive: Work := UTF8Pos(UTF8LowerCase(ContentPlugins[I].Value), UTF8LowerCase(Value)) = 0; poRegExpr: Work := ExecRegExpr(UTF8ToUTF16(ContentPlugins[I].Value), UTF8ToUTF16(Value)); poNotRegExpr: Work := not ExecRegExpr(UTF8ToUTF16(ContentPlugins[I].Value), UTF8ToUTF16(Value)); end; end; if ContentPluginCombine then begin Result := Result and Work; if not Result then Break; end else begin Result := Result or Work; if Result then Break; end; end; end; function CheckPlugin(const SearchTemplate: TSearchTemplateRec; const SearchRec: TSearchRecEx; const Folder: String): Boolean; var AFile: TFile; begin try AFile:= TFileSystemFileSource.CreateFile(Folder, @SearchRec); try Result:= CheckPlugin(SearchTemplate, AFile); finally AFile.Free; end; except Exit(False); end; end; function CheckDirectoryName(const FileChecks: TFindFileChecks; const DirectoryName: String): Boolean; begin with FileChecks do begin Result := not MatchesMaskList(DirectoryName, ExcludeDirectories); end; end; function CheckDirectoryNameEx(const FileChecks: TFindFileChecks; const FullPath, BasePath: String): Boolean; var APath: String; begin Result := True; with FileChecks do begin for APath in ExcludeDirectories.Split([';'], TStringSplitOptions.ExcludeEmpty) do begin case GetPathType(APath) of ptRelative: begin // Check if FullPath is a path relative to BasePath. if MatchesMask(ExtractDirLevel(BasePath, FullPath), APath) then Exit(False); end; ptAbsolute: begin if MatchesMask(FullPath, APath) then Exit(False); end; end; end; end; end; function CheckFileName(const FileChecks: TFindFileChecks; const FileName: String): Boolean; begin with FileChecks do begin if RegExp then begin Result := ((FilesMasks = '') or ExecRegExpr(FilesMasks, FileName)) and ((ExcludeFiles = '') or not ExecRegExpr(ExcludeFiles, FileName)); end else begin Result := MatchesMaskList(FileName, FilesMasks) and not MatchesMaskList(FileName, ExcludeFiles); end; end; end; function CheckFileTime(const FileChecks: TFindFileChecks; FT : TFileTime) : Boolean; begin Result := CheckFileDateTime(FileChecks, FileTimeToDateTime(FT)); end; function CheckFileDateTime(const FileChecks: TFindFileChecks; DT : TDateTime) : Boolean; begin with FileChecks do Result := (DateTimeFrom <= DT) and (DT <= DateTimeTo); end; function CheckFileSize(const FileChecks: TFindFileChecks; FileSize: Int64): Boolean; begin with FileChecks do Result := (FileSizeFrom <= FileSize) and (FileSize <= FileSizeTo); end; function CheckFileAttributes(const FileChecks: TFindFileChecks; Attrs : TFileAttrs) : Boolean; var i: Integer; begin if Length(FileChecks.Attributes) = 0 then Result := True else begin for i := Low(FileChecks.Attributes) to High(FileChecks.Attributes) do begin with FileChecks.Attributes[i] do begin Result := ((Attrs and HaveAttrs) = HaveAttrs) and ((Attrs and DontHaveAttrs) = 0); if Negated then Result := not Result; if Result then Exit; end; end; Result := False; end; end; function CheckFile(const SearchTemplate: TSearchTemplateRec; const FileChecks: TFindFileChecks; const AFile: TFile): Boolean; var IsDir: Boolean; DirectoryName: String; begin Result := True; with SearchTemplate do begin IsDir := AFile.IsDirectory or AFile.IsLinkToDirectory; if (fpName in AFile.SupportedProperties) then begin DirectoryName:= ExtractFileName(ExcludeTrailingBackslash(AFile.Path)); Result := CheckDirectoryName(FileChecks, DirectoryName); if Result then Result := CheckFileName(FileChecks, AFile.Name); end; if Result and (fpModificationTime in AFile.SupportedProperties) then if (IsDateFrom or IsDateTo or IsTimeFrom or IsTimeTo or IsNotOlderThan) then Result:= CheckFileDateTime(FileChecks, AFile.ModificationTime); if Result and not IsDir and (fpSize in AFile.SupportedProperties) then if (IsFileSizeFrom or IsFileSizeTo) then Result:= CheckFileSize(FileChecks, AFile.Size); if Result and (fpAttributes in AFile.SupportedProperties) then begin if AFile.AttributesProperty.IsNativeAttributes then Result:= CheckFileAttributes(FileChecks, AFile.Attributes) else if (Length(FileChecks.Attributes) > 0) then Result:= False; end; if Result and ContentPlugin then begin Result:= CheckPlugin(SearchTemplate, AFile); end; end; end; end. ����������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufindmmap.pas������������������������������������������������������������������0000644�0001750�0000144�00000031655�14743153644�016074� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz implementind memory searching with case and mmap file to memory contributors: Copyright (C) 2006-2007 Koblov Alexander (Alexx2000@mail.ru) } unit uFindMmap; {$mode objfpc}{$H+} interface uses uFindByrMr; type TAbortFunction = function: Boolean of object; {en Searches data in memory for a string. @param(pDataAddr Pointer to the beginning of the data buffer.) @param(iDataLength Length of the data buffer in bytes.) @param(iStartPos Position in the buffer from which to begin search.) @param(sSearchText Text that is searched for in the data buffer.) @param(bCaseSensitive If @true the search is case sensitive.) @param(bSearchBackwards If @true the search is done in iStartPos..0. If @false the search is done in iStartPos..(iLength-1).) @returns(If the string was not found it returns -1. If the string was found it returns pointer to the data buffer where the searched text begins.) } function PosMem(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bCaseSensitive: Boolean; bSearchBackwards: Boolean): Pointer; function PosMemU(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bSearchBackwards: Boolean): Pointer; function PosMemW(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bSearchBackwards, bLittleEndian: Boolean): Pointer; function PosMemA(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bCaseSensitive, bSearchBackwards: Boolean; RecodeTable: TRecodeTable): Pointer; {en Searches a file for a string using memory mapping. @param(sFileName File to search in.) @param(sFindData String to search for.) @param(bCase If @true the search is case-sensitive.) @param(Abort This function is called repeatedly during searching. If it returns @true the search is aborted.) @returns(-1 in case of error @br 0 if the string wasn't found @br 1 if the string was found) } function FindMmap(const sFileName:String; const sFindData:String; bCase:Boolean; Abort: TAbortFunction):Integer; function FindMmapU(const sFileName: String; const sFindData: String): Integer; function FindMmapW(const sFileName: String; const sFindData: String; bLittleEndian: Boolean): Integer; implementation uses SysUtils, DCOSUtils, DCUnicodeUtils, LazUTF8, StrUtils, DCStrUtils; function PosMem(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bCaseSensitive: Boolean; bSearchBackwards: Boolean): Pointer; var SearchTextLength: Integer; function sPos2(pAdr: PChar):Boolean; inline; var i: Integer; begin Result := False; for i := 1 to SearchTextLength do begin case bCaseSensitive of False: if UpCase(pAdr^) <> UpCase(sSearchText[i]) then Exit; // Only for Ansi True : if pAdr^ <> sSearchText[i] then Exit; end; Inc(pAdr); end; Result:=True; end; var pCurrentAddr, pEndAddr: PAnsiChar; begin Result := Pointer(-1); SearchTextLength := Length(sSearchText); if (SearchTextLength <= 0) or (iDataLength <= 0) then Exit; pCurrentAddr := pDataAddr + iStartPos; pEndAddr := pDataAddr + iDataLength - SearchTextLength; if bSearchBackwards and (pCurrentAddr > pEndAddr) then // Move to the first possible position for searching backwards. pCurrentAddr := pEndAddr; if (pEndAddr < pDataAddr) or (pCurrentAddr < pDataAddr) or (pCurrentAddr > pEndAddr) then Exit; while True do begin if (pCurrentAddr > pEndAddr) or (pCurrentAddr < pDataAddr) then Exit; if sPos2(pCurrentAddr) then begin Result := pCurrentAddr; Exit; end; case bSearchBackwards of False: Inc(pCurrentAddr); True : Dec(pCurrentAddr); end; end; end; function PosMemU(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bSearchBackwards: Boolean): Pointer; const BUFFER_SIZE = 4096; var iSize: PtrInt; iLength: Integer; iTextPos: Integer; sTextBuffer: String; sLowerCase: String; begin Result := Pointer(-1); iLength:= Length(sSearchText); if bSearchBackwards then begin iSize:= iStartPos; if iLength > iSize then Exit; sLowerCase:= UTF8LowerCase(sSearchText); // While text size > buffer size while iStartPos > BUFFER_SIZE do begin iStartPos:= iStartPos - BUFFER_SIZE; SetString(sTextBuffer, pDataAddr + iStartPos, BUFFER_SIZE); DCUnicodeUtils.Utf8FixBroken(sTextBuffer); sTextBuffer:= UTF8LowerCase(sTextBuffer); iTextPos:= RPos(sLowerCase, sTextBuffer); if iTextPos > 0 then Exit(pDataAddr + iStartPos + iTextPos - 1) else begin // Shift text buffer iStartPos:= iStartPos + iLength; end; end; // Process remaining buffer if iLength > iStartPos then Exit; SetString(sTextBuffer, pDataAddr, iStartPos); DCUnicodeUtils.Utf8FixBroken(sTextBuffer); sTextBuffer:= UTF8LowerCase(sTextBuffer); iTextPos:= RPos(sLowerCase, sTextBuffer); if iTextPos > 0 then Result:= pDataAddr + iTextPos - 1; end else begin iSize:= iDataLength - iStartPos; if iLength > iSize then Exit; sLowerCase:= UTF8LowerCase(sSearchText); // While text size > buffer size while iSize > BUFFER_SIZE do begin SetString(sTextBuffer, pDataAddr + iStartPos, BUFFER_SIZE); DCUnicodeUtils.Utf8FixBroken(sTextBuffer); sTextBuffer:= UTF8LowerCase(sTextBuffer); iTextPos:= Pos(sLowerCase, sTextBuffer); if iTextPos > 0 then Exit(pDataAddr + iStartPos + iTextPos - 1) else begin // Shift text buffer iStartPos:= iStartPos + (BUFFER_SIZE - iLength); end; iSize:= iDataLength - iStartPos; end; // Process remaining buffer if iLength > iSize then Exit; SetString(sTextBuffer, pDataAddr + iStartPos, iSize); DCUnicodeUtils.Utf8FixBroken(sTextBuffer); sTextBuffer:= UTF8LowerCase(sTextBuffer); iTextPos:= Pos(sLowerCase, sTextBuffer); if iTextPos > 0 then Result:= pDataAddr + iStartPos + iTextPos - 1; end; end; function PosMemW(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bSearchBackwards, bLittleEndian: Boolean): Pointer; const BUFFER_SIZE = 4096; var iSize: PtrInt; iLength: Integer; iTextPos: Integer; bSwapEndian: Boolean; sTextBuffer: UnicodeString; sLowerCase: UnicodeString; begin Result := Pointer(-1); iLength:= Length(sSearchText); bSwapEndian:= {$IFDEF ENDIAN_BIG}bLittleEndian{$ELSE}not bLittleEndian{$ENDIF}; if bSearchBackwards then begin iSize:= iStartPos; if iLength > iSize then Exit; sLowerCase:= PUnicodeChar(Pointer(sSearchText + #0)); if bSwapEndian then Utf16SwapEndian(sLowerCase); sLowerCase:= UnicodeLowerCase(sLowerCase); // While text size > buffer size while iStartPos > BUFFER_SIZE do begin iStartPos:= iStartPos - BUFFER_SIZE; SetString(sTextBuffer, PUnicodeChar(pDataAddr + iStartPos), BUFFER_SIZE div 2); if bSwapEndian then Utf16SwapEndian(sTextBuffer); sTextBuffer:= UnicodeLowerCase(sTextBuffer); iTextPos:= RPos(sLowerCase, sTextBuffer); if iTextPos > 0 then Exit(pDataAddr + iStartPos + iTextPos * 2 - 2) else begin // Shift text buffer iStartPos:= iStartPos + iLength; end; end; // Process remaining buffer if iLength > iStartPos then Exit; SetString(sTextBuffer, PUnicodeChar(pDataAddr), iStartPos div 2); if bSwapEndian then Utf16SwapEndian(sTextBuffer); sTextBuffer:= UnicodeLowerCase(sTextBuffer); iTextPos:= RPos(sLowerCase, sTextBuffer); if iTextPos > 0 then Result:= pDataAddr + iTextPos * 2 - 2 end else begin iSize:= iDataLength - iStartPos; if iLength > iSize then Exit; sLowerCase:= PUnicodeChar(Pointer(sSearchText + #0)); if bSwapEndian then Utf16SwapEndian(sLowerCase); sLowerCase:= UnicodeLowerCase(sLowerCase); // While text size > buffer size while iSize > BUFFER_SIZE do begin SetString(sTextBuffer, PUnicodeChar(pDataAddr + iStartPos), BUFFER_SIZE div 2); if bSwapEndian then Utf16SwapEndian(sTextBuffer); sTextBuffer:= UnicodeLowerCase(sTextBuffer); iTextPos:= Pos(sLowerCase, sTextBuffer); if iTextPos > 0 then Exit(pDataAddr + iStartPos + iTextPos * 2 - 2) else begin // Shift text buffer iStartPos:= iStartPos + (BUFFER_SIZE - iLength); end; iSize:= iDataLength - iStartPos; end; // Process remaining buffer if iLength > iSize then Exit; SetString(sTextBuffer, PUnicodeChar(pDataAddr + iStartPos), iSize div 2); if bSwapEndian then Utf16SwapEndian(sTextBuffer); sTextBuffer:= UnicodeLowerCase(sTextBuffer); iTextPos:= Pos(sLowerCase, sTextBuffer); if iTextPos > 0 then Result:= pDataAddr + iStartPos + iTextPos * 2 - 2; end; end; function PosMemA(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String; bCaseSensitive, bSearchBackwards: Boolean; RecodeTable: TRecodeTable): Pointer; var SearchTextLength: Integer; function sPos2(pAdr: PChar):Boolean; inline; var i: Integer; begin Result := False; for i := 1 to SearchTextLength do begin case bCaseSensitive of False: if Chr(RecodeTable[Ord(pAdr^)]) <> Chr(RecodeTable[Ord(sSearchText[i])]) then Exit; True : if pAdr^ <> sSearchText[i] then Exit; end; Inc(pAdr); end; Result:=True; end; var pCurrentAddr, pEndAddr: PAnsiChar; begin Result := Pointer(-1); SearchTextLength := Length(sSearchText); if (SearchTextLength <= 0) or (iDataLength <= 0) then Exit; pCurrentAddr := pDataAddr + iStartPos; pEndAddr := pDataAddr + iDataLength - SearchTextLength; if bSearchBackwards and (pCurrentAddr > pEndAddr) then // Move to the first possible position for searching backwards. pCurrentAddr := pEndAddr; if (pEndAddr < pDataAddr) or (pCurrentAddr < pDataAddr) or (pCurrentAddr > pEndAddr) then Exit; while True do begin if (pCurrentAddr > pEndAddr) or (pCurrentAddr < pDataAddr) then Exit; if sPos2(pCurrentAddr) then begin Result := pCurrentAddr; Exit; end; case bSearchBackwards of False: Inc(pCurrentAddr); True : Dec(pCurrentAddr); end; end; end; function FindMmap(const sFileName: String; const sFindData: String; bCase: Boolean; Abort: TAbortFunction): Integer; function PosMem(pAdr:PChar; iLength:Integer):Pointer; var xIndex:Integer; DataLength: Integer; function sPos(pAdr:PChar):Boolean; inline; var i:Integer; begin Result:=False; for i:=1 to DataLength do begin case bCase of False:if UpCase(pAdr^)<>UpCase(sFindData[i]) then Exit; True: if pAdr^<>sFindData[i] then Exit; end; inc(pAdr); end; Result:=True; end; begin Result:=pointer(-1); DataLength := Length(sFindData); for xIndex:=0 to iLength - DataLength do begin if sPos(pAdr) then begin Result:=pAdr; Exit; end; inc(pAdr); if Abort() then Exit; end; end; var fmr : TFileMapRec; begin Result := -1; if MapFile(sFileName, fmr) then begin try begin if PosMem(fmr.MappedFile, fmr.FileSize) <> Pointer(-1) then Result := 1 else Result := 0; end; finally UnMapFile(fmr); end; end; end; function FindMmapU(const sFileName: String; const sFindData: String): Integer; var fmr : TFileMapRec; begin Result := -1; if MapFile(sFileName, fmr) then begin try begin if PosMemU(fmr.MappedFile, fmr.FileSize, 0, sFindData, False) <> Pointer(-1) then Result := 1 else Result := 0; end; finally UnMapFile(fmr); end; end; end; function FindMmapW(const sFileName: String; const sFindData: String; bLittleEndian: Boolean): Integer; var fmr : TFileMapRec; begin Result := -1; if MapFile(sFileName, fmr) then begin try begin if PosMemW(fmr.MappedFile, fmr.FileSize, 0, sFindData, False, bLittleEndian) <> Pointer(-1) then Result := 1 else Result := 0; end; finally UnMapFile(fmr); end; end; end; end. �����������������������������������������������������������������������������������doublecmd-1.1.22/src/ufindthread.pas����������������������������������������������������������������0000644�0001750�0000144�00000071562�14743153644�016412� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Thread for search files (called from frmSearchDlg) Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz) Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. } unit uFindThread; {$mode objfpc}{$H+} {$include calling.inc} interface uses Classes, SysUtils, Contnrs, DCStringHashListUtf8, uFindFiles, uFindEx, uFindByrMr, uMasks, uRegExpr, uRegExprW, uWcxModule; type { TDuplicate } TDuplicate = class Name: String; Hash: String; Size: Int64; Index: IntPtr; Count: Integer; function Clone: TDuplicate; end; { TEncoding } TEncoding = class FindText: String; ReplaceText: String; FRegExpr: TRegExprEx; RecodeTable: TRecodeTable; FTextSearchType: TTextSearch; public destructor Destroy; override; end; { TFindThread } TFindThread = class(TThread) private FItems: TStrings; FCurrentDir:String; FFilesScanned:Integer; FFilesFound:Integer; FFoundFile:String; FCurrentDepth: Integer; FSearchText: String; FSearchTemplate: TSearchTemplateRec; FSelectedFiles: TStringList; FFileChecks: TFindFileChecks; FLinkTargets: TStringList; // A list of encountered directories (for detecting cycles) FFilesMasks: TMaskList; FExcludeFiles: TMaskList; FEncodings: TObjectList; FExcludeDirectories: TMaskList; FFilesMasksRegExp: TRegExprW; FExcludeFilesRegExp: TRegExprW; FArchive: TWcxModule; FHeader: TWcxHeader; FTimeSearchStart:TTime; FTimeSearchEnd:TTime; FTimeOfScan:TTime; FBuffer: TBytes; FFoundIndex: IntPtr; FDuplicateIndex: Integer; FDuplicates: TStringHashListUtf8; function GetTimeOfScan:TTime; procedure FindInArchive(const FileName: String); function CheckFileName(const FileName: String) : Boolean; function CheckDirectoryName(const DirectoryName: String) : Boolean; function CheckFile(const Folder : String; const sr : TSearchRecEx) : Boolean; function CheckDirectory(const CurrentDir, FolderName : String) : Boolean; function CheckDuplicate(const Folder : String; const sr : TSearchRecEx): Boolean; function FindInFile(const sFileName: String; bCase, bRegExp: Boolean): Boolean; procedure FileReplaceString(const FileName: String; bCase, bRegExp: Boolean); protected procedure Execute; override; public constructor Create(const AFindOptions: TSearchTemplateRec; SelectedFiles: TStringList); destructor Destroy; override; procedure AddFile; procedure AddArchiveFile; procedure AddDuplicateFile; procedure DoFile(const sNewDir: String; const sr : TSearchRecEx); procedure WalkAdr(const sNewDir: String); function IsAborting: Boolean; property FilesScanned: Integer read FFilesScanned; property FilesFound: Integer read FFilesFound; property CurrentDir: String read FCurrentDir; property TimeOfScan:TTime read GetTimeOfScan; property Archive: TWcxModule write FArchive; property Items:TStrings write FItems; end; implementation uses LCLProc, LazUtf8, StrUtils, LConvEncoding, DCStrUtils, DCConvertEncoding, uLng, DCClassesUtf8, uFindMmap, uGlobs, uShowMsg, DCOSUtils, uOSUtils, uHash, uLog, WcxPlugin, Math, uDCUtils, uConvEncoding, DCDateTimeUtils, uOfficeXML; function ProcessDataProcAG(FileName: PAnsiChar; Size: LongInt): LongInt; dcpcall; begin if TThread.CheckTerminated then Result:= 0 else Result:= 1; end; function ProcessDataProcWG(FileName: PWideChar; Size: LongInt): LongInt; dcpcall; begin if TThread.CheckTerminated then Result:= 0 else Result:= 1; end; { TDuplicate } function TDuplicate.Clone: TDuplicate; begin Result:= TDuplicate.Create; Result.Index:= Self.Index; end; { TEncoding } destructor TEncoding.Destroy; begin FRegExpr.Free; inherited Destroy; end; { TFindThread } constructor TFindThread.Create(const AFindOptions: TSearchTemplateRec; SelectedFiles: TStringList); var S: String; Index: Integer; AEncoding: TEncoding; ATextEncoding: String; AEncodings: TStringArray; begin inherited Create(True); FEncodings:= TObjectList.Create(True); FLinkTargets := TStringList.Create; FSearchTemplate := AFindOptions; FSelectedFiles := SelectedFiles; FDuplicates:= TStringHashListUtf8.Create(True); with FSearchTemplate do begin if SearchDepth < 0 then SearchDepth := MaxInt; if IsFindText then begin FSearchText := FindText; AEncodings:= SplitString(TextEncoding, '|'); for Index:= 0 to High(AEncodings) do begin AEncoding:= TEncoding.Create; ATextEncoding:= AEncodings[Index]; if HexValue then begin ATextEncoding := EncodingAnsi; AEncoding.FindText := HexToBin(FindText); end else begin ATextEncoding := NormalizeEncoding(ATextEncoding); AEncoding.FindText := ConvertEncoding(FindText, EncodingUTF8, ATextEncoding); AEncoding.ReplaceText := ConvertEncoding(ReplaceText, EncodingUTF8, ATextEncoding); if TextRegExp then begin AEncoding.FRegExpr := TRegExprEx.Create(ATextEncoding, True); AEncoding.FRegExpr.Expression := FSearchText; end; end; // Determine search type if SingleByteEncoding(ATextEncoding) then begin AEncoding.FTextSearchType := tsAnsi; AEncoding.RecodeTable := InitRecodeTable(ATextEncoding, CaseSensitive); end else if (CaseSensitive = False) then begin if ATextEncoding = EncodingDefault then begin ATextEncoding := GetDefaultTextEncoding; end; if ((ATextEncoding = EncodingUTF8) or (ATextEncoding = EncodingUTF8BOM)) then AEncoding.FTextSearchType:= tsUtf8 else if (ATextEncoding = EncodingUTF16LE) then AEncoding.FTextSearchType:= tsUtf16le else if (ATextEncoding = EncodingUTF16BE) then AEncoding.FTextSearchType:= tsUtf16be else AEncoding.FTextSearchType:= tsOther; end else begin AEncoding.FTextSearchType:= tsOther; end; FEncodings.Add(AEncoding); if HexValue then Break; end; end end; SearchTemplateToFindFileChecks(FSearchTemplate, FFileChecks); with FFileChecks do begin if RegExp then begin FFilesMasksRegExp := TRegExprW.Create(CeUtf8ToUtf16(FilesMasks)); FExcludeFilesRegExp := TRegExprW.Create(CeUtf8ToUtf16(ExcludeFiles)); end else begin FFilesMasks := TMaskList.Create(FilesMasks); FExcludeFiles := TMaskList.Create(ExcludeFiles); end; FExcludeDirectories := TMaskList.Create(ExcludeDirectories); end; if FSearchTemplate.Duplicates and FSearchTemplate.DuplicateHash then SetLength(FBuffer, gHashBlockSize); FTimeSearchStart:=0; FTimeSearchEnd:=0; FTimeOfScan:=0; end; destructor TFindThread.Destroy; var Index: Integer; begin // FItems.Add('End'); FreeAndNil(FEncodings); FreeAndNil(FFilesMasks); FreeAndNil(FExcludeFiles); FreeAndNil(FLinkTargets); FreeAndNil(FFilesMasksRegExp); FreeAndNil(FExcludeFilesRegExp); FreeAndNil(FExcludeDirectories); for Index:= 0 to FDuplicates.Count - 1 do TObject(FDuplicates.List[Index]^.Data).Free; FreeAndNil(FDuplicates); inherited Destroy; end; procedure TFindThread.Execute; var I: Integer; sPath: String; sr: TSearchRecEx; begin FTimeSearchStart:=Now; FreeOnTerminate := True; try Assert(Assigned(FItems), 'Assert: FItems is empty'); FCurrentDepth:= -1; if Assigned(FArchive) then begin FindInArchive(FSearchTemplate.StartPath); end else if not Assigned(FSelectedFiles) or (FSelectedFiles.Count = 0) then begin // Normal search (all directories). for sPath in SplitPath(FSearchTemplate.StartPath) do begin WalkAdr(ExcludeBackPathDelimiter(sPath)); end; end else begin // Search only selected directories. for I := 0 to FSelectedFiles.Count - 1 do begin sPath:= FSelectedFiles[I]; sPath:= ExcludeBackPathDelimiter(sPath); if FindFirstEx(sPath, 0, sr) = 0 then begin if FPS_ISDIR(sr.Attr) then WalkAdr(sPath) else DoFile(ExtractFileDir(sPath), sr); end; FindCloseEx(sr); end; end; FCurrentDir:= rsOperFinished; except on E:Exception do msgError(Self, E.Message); end; FTimeSearchEnd:=Now; FTimeOfScan:=FTimeSearchEnd-FTimeSearchStart; end; procedure TFindThread.AddFile; begin FItems.Add(FFoundFile); end; procedure TFindThread.AddArchiveFile; begin FItems.AddObject(FFoundFile, FHeader.Clone); end; procedure TFindThread.AddDuplicateFile; var AData: TDuplicate; begin AData:= TDuplicate(FDuplicates.List[FFoundIndex]^.Data); if AData.Count = 1 then begin Inc(FFilesFound); FItems.AddObject(AData.Name, AData.Clone); end; Inc(FFilesFound); FItems.AddObject(FFoundFile, AData.Clone); end; function TFindThread.CheckDirectory(const CurrentDir, FolderName : String): Boolean; begin with FSearchTemplate do begin Result := CheckDirectoryName(FolderName) and CheckDirectoryNameEx(FFileChecks, CurrentDir + PathDelim + FolderName, FSearchTemplate.StartPath); end; end; function TFindThread.FindInFile(const sFileName: String; bCase, bRegExp: Boolean): Boolean; var fs: TFileStreamEx; function FillBuffer(Buffer: PAnsiChar; BytesToRead: Longint): Longint; var DataRead: Longint; begin Result := 0; repeat DataRead := fs.Read(Buffer[Result], BytesToRead - Result); if DataRead = 0 then Break; Result := Result + DataRead; until Result >= BytesToRead; end; var S: String; Index: Integer; MaxLen: Integer; lastPos: Pointer; DataRead: Integer; fmr : TFileMapRec; BufferSize: Integer; sDataLength: Integer; AEncoding: TEncoding; Buffer: PAnsiChar = nil; begin Result := False; if FSearchText = '' then Exit; if FSearchTemplate.OfficeXML and OfficeMask.Matches(sFileName) then begin if LoadFromOffice(sFileName, S) then begin if bRegExp then Result:= uRegExprW.ExecRegExpr(UTF8ToUTF16(FSearchText), UTF8ToUTF16(S)) else if FSearchTemplate.CaseSensitive then Result:= PosMem(Pointer(S), Length(S), 0, FSearchText, False, False) <> Pointer(-1) else begin Result:= PosMemU(Pointer(S), Length(S), 0, FSearchText, False) <> Pointer(-1); end; end; Exit; end; // Simple regular expression search (don't work for very big files) if bRegExp then begin fs := TFileStreamEx.Create(sFileName, fmOpenRead or fmShareDenyNone or fmOpenNoATime); try if fs.Size = 0 then Exit; {$PUSH}{$R-} SetLength(S, fs.Size); {$POP} if Length(S) = 0 then raise EFOpenError.Create(EmptyStr); fs.ReadBuffer(S[1], fs.Size); finally fs.Free; end; for Index:= 0 to FEncodings.Count - 1 do begin AEncoding:= TEncoding(FEncodings[Index]); AEncoding.FRegExpr.SetInputString(Pointer(S), Length(S)); if AEncoding.FRegExpr.Exec() then Exit(True); end; Exit; end; if gUseMmapInSearch then begin // Memory mapping should be slightly faster and use less memory if MapFile(sFileName, fmr) then try for Index:= 0 to FEncodings.Count - 1 do begin AEncoding:= TEncoding(FEncodings[Index]); with AEncoding do begin case FTextSearchType of tsAnsi: lastPos:= Pointer(PosMemBoyerMur(fmr.MappedFile, fmr.FileSize, FindText, RecodeTable)); tsUtf8: lastPos:= PosMemU(fmr.MappedFile, fmr.FileSize, 0, FindText, False); tsUtf16le: lastPos:= PosMemW(fmr.MappedFile, fmr.FileSize, 0, FindText, False, True); tsUtf16be: lastPos:= PosMemW(fmr.MappedFile, fmr.FileSize, 0, FindText, False, False); else lastPos:= PosMem(fmr.MappedFile, fmr.FileSize, 0, FindText, bCase, False); end; end; if (lastPos <> Pointer(-1)) then Exit(True); end; Exit; finally UnMapFile(fmr); end; // else fall back to searching via stream reading end; fs := TFileStreamEx.Create(sFileName, fmOpenRead or fmShareDenyNone or fmOpenNoATime); try MaxLen:= 0; BufferSize := gCopyBlockSize; for Index:= 0 to FEncodings.Count - 1 do begin AEncoding:= TEncoding(FEncodings[Index]); sDataLength := Length(AEncoding.FindText); if sDataLength > MaxLen then MaxLen:= sDataLength; end; // Buffer is extended by sDataLength-1 and BufferSize + sDataLength - 1 // bytes are read. Then strings of length sDataLength are compared with // sData starting from offset 0 to BufferSize-1. The remaining part of the // buffer [BufferSize, BufferSize+sDataLength-1] is moved to the beginning, // buffer is filled up with BufferSize bytes and the search continues. GetMem(Buffer, BufferSize + MaxLen - 1); if Assigned(Buffer) then try for Index:= 0 to FEncodings.Count - 1 do begin fs.Seek(0, soFromBeginning); AEncoding:= TEncoding(FEncodings[Index]); sDataLength := Length(AEncoding.FindText); if sDataLength > BufferSize then raise Exception.Create(rsMsgErrSmallBuf); if sDataLength > fs.Size then // string longer than file, cannot search Continue; try if FillBuffer(Buffer, sDataLength-1) = sDataLength-1 then begin while not Terminated do begin DataRead := FillBuffer(@Buffer[sDataLength - 1], BufferSize); if DataRead = 0 then Break; case AEncoding.FTextSearchType of tsAnsi: begin if PosMemBoyerMur(@Buffer[0], DataRead + sDataLength - 1, AEncoding.FindText, AEncoding.RecodeTable) <> -1 then Exit(True); end; tsUtf8: begin if PosMemU(@Buffer[0], DataRead + sDataLength - 1, 0, AEncoding.FindText, False) <> Pointer(-1) then Exit(True); end; tsUtf16le, tsUtf16be: begin if PosMemW(@Buffer[0], DataRead + sDataLength - 1, 0, AEncoding.FindText, False, AEncoding.FTextSearchType = tsUtf16le) <> Pointer(-1) then Exit(True); end; else begin if PosMem(@Buffer[0], DataRead + sDataLength - 1, 0, AEncoding.FindText, bCase, False) <> Pointer(-1) then Exit(True); end; end; // Copy last 'sDataLength-1' bytes to the beginning of the buffer // (to search 'on the boundary' - where previous buffer ends, // and the next buffer starts). Move(Buffer[DataRead], Buffer^, sDataLength-1); end; end; except end; end; finally FreeMem(Buffer); Buffer := nil; end; finally FreeAndNil(fs); end; end; procedure TFindThread.FileReplaceString(const FileName: String; bCase, bRegExp: Boolean); var S: String; fs: TFileStreamEx; AEncoding: TEncoding; Flags : TReplaceFlags = []; begin fs := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try if fs.Size = 0 then Exit; {$PUSH}{$R-} SetLength(S, fs.Size); {$POP} if Length(S) = 0 then raise EFOpenError.Create(EmptyStr); fs.ReadBuffer(S[1], fs.Size); finally fs.Free; end; AEncoding:= TEncoding(FEncodings[0]); if bRegExp then S := AEncoding.FRegExpr.ReplaceAll(AEncoding.FindText, S, AEncoding.ReplaceText) else begin Include(Flags, rfReplaceAll); if not bCase then Include(Flags, rfIgnoreCase); S := StringReplace(S, AEncoding.FindText, AEncoding.ReplaceText, Flags); end; fs := TFileStreamEx.Create(FileName, fmCreate); try fs.WriteBuffer(S[1], Length(S)); finally fs.Free; end; end; function TFindThread.GetTimeOfScan: TTime; begin FTimeOfScan:=Now-FTimeSearchStart; Result:=FTimeOfScan; end; procedure TFindThread.FindInArchive(const FileName: String); var Index: Integer; function CheckHeader: Boolean; var NameLength: Integer; DirectoryName: String; begin with FSearchTemplate do begin Result:= True; if IsFindText then begin // Skip directories if (FHeader.FileAttr and faFolder) <> 0 then Exit(False); // Some plugins end directories with path delimiter. // And not set directory attribute. Process this case. NameLength := Length(FHeader.FileName); if (NameLength > 0) and (FHeader.FileName[NameLength] = PathDelim) then Exit(False); end; DirectoryName:= ExtractFileName(ExtractFileDir(FHeader.FileName)); if not CheckDirectoryName(DirectoryName) then Exit(False); if not CheckFileName(ExtractFileName(FHeader.FileName)) then Exit(False); if (IsDateFrom or IsDateTo or IsTimeFrom or IsTimeTo or IsNotOlderThan) then Result := CheckFileDateTime(FFileChecks, FHeader.DateTime); if (IsFileSizeFrom or IsFileSizeTo) and Result then Result := CheckFileSize(FFileChecks, FHeader.UnpSize); if Result then Result := CheckFileAttributes(FFileChecks, FHeader.FileAttr); end; end; var Flags: Integer; Result: Boolean; Operation: Integer; TargetPath: String; ArcHandle: TArcHandle; TargetFileName: String; WcxModule: TWcxModule = nil; begin if Assigned(FArchive) then WcxModule:= FArchive else begin TargetPath:= ExtractOnlyFileExt(FileName); for Index := 0 to gWCXPlugins.Count - 1 do begin if SameText(TargetPath, gWCXPlugins.Ext[Index]) and (gWCXPlugins.Enabled[Index]) then begin if FSearchTemplate.IsFindText and (gWCXPlugins.Flags[Index] and PK_CAPS_SEARCHTEXT = 0) then Continue; WcxModule:= gWCXPlugins.LoadModule(GetCmdDirFromEnvVar(gWCXPlugins.FileName[Index])); Break; end; end; end; if Assigned(WcxModule) then begin if FSearchTemplate.IsFindText then begin Flags:= PK_OM_EXTRACT; Operation:= PK_EXTRACT; end else begin Flags:= PK_OM_LIST; Operation:= PK_SKIP; end; ArcHandle := WcxModule.OpenArchiveHandle(FileName, Flags, Index); if ArcHandle <> 0 then try if Operation = PK_EXTRACT then begin TargetPath:= GetTempName(GetTempFolder); if not mbCreateDir(TargetPath) then Exit; end; WcxModule.WcxSetChangeVolProc(ArcHandle); WcxModule.WcxSetProcessDataProc(ArcHandle, @ProcessDataProcAG, @ProcessDataProcWG); while (WcxModule.ReadWCXHeader(ArcHandle, FHeader) = E_SUCCESS) do begin Result:= CheckHeader; if Terminated then Break; Flags:= IfThen(Result, Operation, PK_SKIP); if Flags = PK_EXTRACT then TargetFileName:= TargetPath + PathDelim + ExtractFileName(FHeader.FileName); if WcxModule.WcxProcessFile(ArcHandle, Flags, EmptyStr, TargetFileName) = E_SUCCESS then begin with FSearchTemplate do begin if Result and IsFindText then begin Result:= FindInFile(TargetFileName, CaseSensitive, TextRegExp); if NotContainingText then Result:= not Result; mbDeleteFile(TargetFileName); end; end; end; if Result then begin FFoundFile := FileName + ReversePathDelim + FHeader.FileName; Synchronize(@AddArchiveFile); Inc(FFilesFound); end; FreeAndNil(FHeader); end; if Operation = PK_EXTRACT then mbRemoveDir(TargetPath); finally WcxModule.CloseArchive(ArcHandle); end; end; end; function TFindThread.CheckFileName(const FileName: String): Boolean; var AFileName: UnicodeString; begin with FFileChecks do begin if RegExp then begin AFileName := CeUtf8ToUtf16(FileName); Result := ((FilesMasks = '') or FFilesMasksRegExp.Exec(AFileName)) and ((ExcludeFiles = '') or not FExcludeFilesRegExp.Exec(AFileName)); end else begin Result := FFilesMasks.Matches(FileName) and not FExcludeFiles.Matches(FileName); end; end; end; function TFindThread.CheckDuplicate(const Folder: String; const sr: TSearchRecEx): Boolean; var AKey: String; AHash: String; Index: IntPtr; AData: TDuplicate; AFileName: String; AValue: String = ''; AStart, AFinish: Integer; function FileHash(const AName: String; Size: Int64; out Hash: String): Boolean; var Handle: THandle; BytesRead: Integer; BytesToRead: Integer; Context: THashContext; begin Handle:= mbFileOpen(AName, fmOpenRead or fmShareDenyWrite); Result:= (Handle <> feInvalidHandle); if Result then begin HashInit(Context, HASH_BEST); BytesToRead:= Length(FBuffer); while (Size > 0) and (not Terminated) do begin if (Size < BytesToRead) then BytesToRead:= Size; BytesRead := FileRead(Handle, FBuffer[0], BytesToRead); if (BytesRead < 0) then Break; HashUpdate(Context, FBuffer[0], BytesRead); Dec(Size, BytesRead); end; FileClose(Handle); Result:= (Size = 0); HashFinal(Context, Hash); end; end; function CompareFiles(fn1, fn2: String; len: Int64): Boolean; const BUFLEN = 1024 * 32; var i, j: Int64; fs1, fs2: TFileStreamEx; buf1, buf2: array [1..BUFLEN] of Byte; begin try fs1 := TFileStreamEx.Create(fn1, fmOpenRead or fmShareDenyWrite); try fs2 := TFileStreamEx.Create(fn2, fmOpenRead or fmShareDenyWrite); try i := 0; repeat if len - i <= BUFLEN then j := len - i else begin j := BUFLEN; end; fs1.ReadBuffer(buf1, j); fs2.ReadBuffer(buf2, j); i := i + j; Result := CompareMem(@buf1, @buf2, j); until Terminated or not Result or (i >= len); finally fs2.Free; end; finally fs1.Free; end; except Result:= False; end; end; begin AFileName:= IncludeTrailingBackslash(Folder) + sr.Name; if (FPS_ISDIR(sr.Attr) or FileIsLinkToDirectory(AFileName, sr.Attr)) then Exit(False); if FSearchTemplate.DuplicateName then begin if FileNameCaseSensitive then AValue:= sr.Name else AValue:= UTF8LowerCase(sr.Name); end; if FSearchTemplate.DuplicateSize then AValue+= IntToStr(sr.Size); if FSearchTemplate.DuplicateHash then AHash:= EmptyStr; Index:= FDuplicates.Find(AValue); Result:= (Index >= 0); if Result then begin FDuplicates.FindBoundaries(Index, AStart, AFinish); for Index:= AStart to AFinish do begin AKey:= FDuplicates.List[Index]^.Key; if (Length(AKey) = Length(AValue)) and (CompareByte(AKey[1], AValue[1], Length(AKey)) = 0) then begin AData:= TDuplicate(FDuplicates.List[Index]^.Data); if FSearchTemplate.DuplicateHash then begin // Group file hash if Length(AData.Hash) = 0 then begin if not FileHash(AData.Name, AData.Size, AData.Hash) then begin AData.Name:= AFileName; AData.Size:= sr.Size; if (Index < AFinish) then begin Result:= False; Continue; end; Exit(False); end; end; // Current file hash if (Length(AHash) = 0) then begin if not FileHash(AFileName, sr.Size, AHash) then Exit; end; Result:= SameStr(AHash, AData.Hash); end else if FSearchTemplate.DuplicateContent then Result:= CompareFiles(AData.Name, AFileName, sr.Size) else begin Result:= True; end; if Result then begin Inc(AData.Count); FFoundIndex:= Index; // First match if (AData.Count = 1) then begin Inc(FDuplicateIndex); AData.Index:= FDuplicateIndex; end; Exit; end; end; end; end; if not Result then begin AData:= TDuplicate.Create; AData.Name:= AFileName; AData.Hash:= AHash; AData.Size:= sr.Size; FDuplicates.Add(AValue, AData); end; end; function TFindThread.CheckDirectoryName(const DirectoryName: String): Boolean; begin with FFileChecks do begin Result := not FExcludeDirectories.Matches(DirectoryName); end; end; function TFindThread.CheckFile(const Folder : String; const sr : TSearchRecEx) : Boolean; begin Result := True; with FSearchTemplate do begin if not CheckFileName(sr.Name) then Exit(False); if (IsDateFrom or IsDateTo or IsTimeFrom or IsTimeTo or IsNotOlderThan) then Result := CheckFileTime(FFileChecks, sr.Time); if (IsFileSizeFrom or IsFileSizeTo) and Result then Result := CheckFileSize(FFileChecks, sr.Size); if Result then Result := CheckFileAttributes(FFileChecks, sr.Attr); if (Result and IsFindText) then begin if FPS_ISDIR(sr.Attr) or (sr.Size = 0) then Exit(False); try Result := FindInFile(IncludeTrailingBackslash(Folder) + sr.Name, CaseSensitive, TextRegExp); if (Result and IsReplaceText) then FileReplaceString(IncludeTrailingBackslash(Folder) + sr.Name, CaseSensitive, TextRegExp); if NotContainingText then Result := not Result; except on E : Exception do begin Result := False; if (log_errors in gLogOptions) then begin logWrite(Self, rsMsgLogError + E.Message + ' (' + IncludeTrailingBackslash(Folder) + sr.Name + ')', lmtError); end; end; end; end; if Result and ContentPlugin then begin Result:= CheckPlugin(FSearchTemplate, sr, Folder); end; end; end; procedure TFindThread.DoFile(const sNewDir: String; const sr : TSearchRecEx); begin if FSearchTemplate.FindInArchives then FindInArchive(IncludeTrailingBackslash(sNewDir) + sr.Name); if CheckFile(sNewDir, sr) then begin if FSearchTemplate.Duplicates then begin if CheckDuplicate(sNewDir, sr) then begin FFoundFile := IncludeTrailingBackslash(sNewDir) + sr.Name; Synchronize(@AddDuplicateFile); end; end else begin FFoundFile := IncludeTrailingBackslash(sNewDir) + sr.Name; Synchronize(@AddFile); Inc(FFilesFound); end; end; Inc(FFilesScanned); end; procedure TFindThread.WalkAdr(const sNewDir:String); var sr: TSearchRecEx; Path, SubPath: String; IsLink: Boolean; begin if Terminated then Exit; Inc(FCurrentDepth); FCurrentDir := sNewDir; // Search all files to display statistics Path := IncludeTrailingBackslash(sNewDir) + '*'; if FindFirstEx(Path, 0, sr) = 0 then repeat if not (FPS_ISDIR(sr.Attr) or FileIsLinkToDirectory(sNewDir + PathDelim + sr.Name, sr.Attr)) then DoFile(sNewDir, sr) else if (sr.Name <> '.') and (sr.Name <> '..') then begin DoFile(sNewDir, sr); // Search in sub folders if (FCurrentDepth < FSearchTemplate.SearchDepth) and CheckDirectory(sNewDir, sr.Name) then begin SubPath := IncludeTrailingBackslash(sNewDir) + sr.Name; IsLink := FPS_ISLNK(sr.Attr); if FSearchTemplate.FollowSymLinks then begin if IsLink then SubPath := mbReadAllLinks(SubPath); if FLinkTargets.IndexOf(SubPath) >= 0 then Continue; // Link already encountered - links form a cycle. // Add directory to already-searched list. FLinkTargets.Add(SubPath); end else if IsLink then Continue; WalkAdr(SubPath); FCurrentDir := sNewDir; end; end; until (FindNextEx(sr) <> 0) or Terminated; FindCloseEx(sr); Dec(FCurrentDepth); end; function TFindThread.IsAborting: Boolean; begin Result := Terminated; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uformcommands.pas��������������������������������������������������������������0000644�0001750�0000144�00000057065�14743153644�016771� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Implements custom commands for a component Copyright (C) 2011-2012 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uFormCommands; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StringHashList, ActnList, Menus; type TCommandFuncResult = (cfrSuccess, cfrDisabled, cfrNotFound); TCommandFunc = procedure(const Params: array of string) of object; TCommandCaptionType = (cctShort, cctLong); TCommandCategorySortOrder = (ccsLegacy, ccsAlphabetical); TCommandSortOrder = (csLegacy, csAlphabetical); (* The commands are 'user' functions which can be assigned to toolbar button, hotkey, menu item, executed by scripts, etc. Only published functions and procedures can by found by MethodAddress. How to set up a form to handle hotkeys: 1. Specify that the form class implements IFormCommands (class (TForm, IFormCommands)). 2. Add private FCommands: TFormCommands that will implement the interface. 3. Add property that will specify that FCommands implements the interface in place of the form. property Commands: TFormCommands read FCommands{$IF FPC_FULLVERSION >= 020501} implements IFormCommands{$ENDIF}; For FPC < 2.5.1 "implements" does not work correctly so the form must implement the interface itself. For example see fViewer. {$IF FPC_FULLVERSION < 020501} // "implements" does not work in FPC < 2.5.1 function ExecuteCommand(Command: string; Param: String=''): TCommandFuncResult; function GetCommandCaption(Command: String; CaptionType: TCommandCaptionType): String; procedure GetCommandsList(List: TStrings); {$ENDIF} 4. Make sure a default constructor Create(TheOwner: TComponent) is present which will create the FCommands on demand when it is needed to read the hotkeys when the form is not currently created. 5. Register the form and action list in HotkeyManager somewhere in constructor: const HotkeysCategory = <unique_name>; HMForm := HotMan.Register(Self, HotkeysCategory); HMForm.RegisterActionList(actionList); And unregister in destructor: HotMan.UnRegister(Self); 6. Register form as commands form so that it is displayed in Options: initialization TFormCommands.RegisterCommandsForm(Tfrm..., HotkeysCategory, @rsHotkeyCategory...); *) { IFormCommands } {$interfaces corba} // If a form/object implements this interface then it can execute custom // commands with parameters. IFormCommands = interface ['{0464B1C0-BA98-4258-A286-F0F726FF66C4}'] function ExecuteCommand(Command: String; const Params: array of string): TCommandFuncResult; function GetCommandCaption(Command: String; CaptionType: TCommandCaptionType = cctShort): String; procedure GetCommandsList(List: TStrings); function GetCommandAction(const Command: String): TAction; procedure GetCommandCategoriesList(List: TStringList; CommandCategorySortOrder:TCommandCategorySortOrder); procedure GetCommandsListForACommandCategory(List: TStringList; sCategoryName:String; CommandSortOrder: TCommandSortOrder); procedure ExtractCommandFields(ItemInList: string; var sCategory:string; var sCommand: string; var sHint: string; var sHotKey: string; var FlagCategoryTitle: boolean); end; {$interfaces default} // Used to filter out commands. If this function returns True the command // is not included in the commands list. TCommandFilterFunc = function (Command: String): Boolean of object; TCommandRec = record Address: Pointer; //<en Address of the command function in the class. Action: TAction; //<en If a TAction is assigned to a named action it is cached here. end; PCommandRec = ^TCommandRec; {en Stores association between method name and its address. StringHashList is used for this purpose, which may be faster than linear scanning by using MethodAddress on the given object. } { TFormCommands } TFormCommands = class(TComponent, IFormCommands) private FFilterFunc: TCommandFilterFunc; FInstanceObject: TObject; FMethods: TStringHashList; FTranslatableCommandCategory: TStringList; class procedure GetMethodsList(Instance: TObject; MethodsList: TStringHashList; ActionList: TActionList); public {en Creates methods list. @param(TheOwner Object of which we want the list of methods. It will also be the owner component.) @param(ActionList Optional. If contains actions corresponding to commands names (but prefixed with "act" instead of "cm_") then actions hints or captions will be used as descriptions for the commands.) } constructor Create(TheOwner: TComponent; ActionList: TActionList = nil); reintroduce; destructor Destroy; override; function ExecuteCommand(Command: string; const Params: array of string): TCommandFuncResult; {en Enables/disables command. @param(CommandName Name of the command. Include prefix if exists, like 'cm_'.) @param(Enable Whether to enable or disable the command.) } procedure EnableCommand(Command: String; Enable: Boolean); function GetCommandCaption(Command: String; CaptionType: TCommandCaptionType): String; function GetCommandName(Index: Integer): String; function GetCommandRec(Command: String): PCommandRec; procedure GetCommandsList(List: TStrings); function GetCommandAction(const Command: String): TAction; procedure GetCommandCategoriesList(List: TStringList; CommandCategorySortOrder:TCommandCategorySortOrder); procedure GetCommandsListForACommandCategory(List: TStringList; sCategoryName:String; CommandSortOrder: TCommandSortOrder); procedure ExtractCommandFields(ItemInList: string; var sCategory: string; var sCommand: string; var sHint: string; var sHotKey: string; var FlagCategoryTitle: boolean); class procedure GetCategoriesList(List: TStrings; Translated: TStrings); class function GetCommandsForm(CategoryName: String): TComponentClass; class procedure RegisterCommandsForm(AClass: TClass; CategoryName: String; TranslatedName: PResStringRec); property FilterFunc: TCommandFilterFunc read FFilterFunc write FFilterFunc; end; function GetDefaultParam(const Params: array of String): String; {en Searches for parameters starting with "Key=" and sets Value to the the rest of the parameter string (Key=Value). If the key is not found it sets Value to empty string and returns @false. @returns(@true if the key was found, @false if it was not found) } function GetParamValue(const Params: array of String; Key: String; out Value: String): Boolean; function GetParamValue(const Param: String; Key: String; out Value: String): Boolean; function GetParamBoolValue(const Param: String; Key: String; out BoolValue: Boolean): Boolean; {en If StrValue matches any value that can be translated into boolean then it returns @true and sets Value appropriately. Otherwise returns @false. } function GetBoolValue(StrValue: string; out BoolValue: Boolean): Boolean; function CloneMainAction(AMainAction:TAction; ATargetActionList:TActionList; AMenuToInsert:TMenuItem=nil; APositionToInsert:integer=-1):TAction; implementation uses uGlobs, uHotkeyManager, DCStrUtils, uLng; type TCommandsFormRec = record AClass: TComponentClass; Name: String; TranslatedName: PResStringRec; // Until FPC 2.7.1 resource strings translation // is not applied after assining so pointer is used here. // It is OK because the address doesn't change after translation. end; var CommandsForms: array of TCommandsFormRec; constructor TFormCommands.Create(TheOwner: TComponent; ActionList: TActionList); begin inherited Create(TheOwner); FInstanceObject := TheOwner; FMethods := TStringHashList.Create(False); // False = not case-sensitive GetMethodsList(FInstanceObject, FMethods, ActionList); FTranslatableCommandCategory:=TStringList.Create; ParseLineToList(rsCmdCategoryListInOrder, FTranslatableCommandCategory); end; destructor TFormCommands.Destroy; var Index: Integer; begin for Index := 0 to FMethods.Count - 1 do Dispose(PCommandRec(FMethods.List[Index]^.Data)); FreeAndNil(FMethods); FTranslatableCommandCategory.Free; inherited; end; function TFormCommands.ExecuteCommand(Command: String; const Params: array of string): TCommandFuncResult; var Method: TMethod; CommandRec: PCommandRec; begin CommandRec := GetCommandRec(Command); if Assigned(CommandRec) then begin if Assigned(CommandRec^.Action) and not CommandRec^.Action.Enabled then Result := cfrDisabled else begin Method.Code := CommandRec^.Address; // address of method Method.Data := FInstanceObject; // pointer to instance TCommandFunc(Method)(Params); Result := cfrSuccess; end; end else Result := cfrNotFound; end; procedure TFormCommands.EnableCommand(Command: String; Enable: Boolean); var CommandRec: PCommandRec; begin CommandRec := GetCommandRec(Command); if Assigned(CommandRec) then begin if Assigned(CommandRec^.Action) then CommandRec^.Action.Enabled := Enable; end else raise Exception.Create('Invalid command name: ' + Command); end; function TFormCommands.GetCommandCaption(Command: String; CaptionType: TCommandCaptionType): String; var CommandRec: PCommandRec; begin CommandRec := GetCommandRec(Command); if Assigned(CommandRec) and Assigned(CommandRec^.Action) then begin if (CaptionType = cctLong) and (CommandRec^.Action.Hint <> EmptyStr) then Result := CommandRec^.Action.Hint else Result := StringReplace(CommandRec^.Action.Caption, '&', '', [rfReplaceAll]); end else Result:= ''; end; function TFormCommands.GetCommandName(Index: Integer): String; begin if (Index >= 0) and (Index < FMethods.Count) then Result := FMethods.List[Index]^.Key else raise ERangeError.Create('Invalid command index'); end; function TFormCommands.GetCommandRec(Command: String): PCommandRec; var Index: Integer; begin Index := FMethods.Find(Command); if Index = -1 then Result := nil else Result := PCommandRec(FMethods.List[Index]^.Data); end; procedure TFormCommands.GetCommandsList(List: TStrings); var Index: Integer; Command: String; begin List.Clear; List.BeginUpdate; try for Index := 0 to FMethods.Count - 1 do begin Command := FMethods.List[Index]^.Key; if not (Assigned(FilterFunc) and FilterFunc(Command)) then List.Add(Command); end; finally List.EndUpdate; end; end; function TFormCommands.GetCommandAction(const Command: String): TAction; var CommandRec: PCommandRec; begin CommandRec := GetCommandRec(Command); if Assigned(CommandRec) then Result:= CommandRec^.Action else begin Result:= nil; end; end; procedure TFormCommands.GetCommandCategoriesList(List: TStringList; CommandCategorySortOrder:TCommandCategorySortOrder); var Index: Integer; Command, Category: String; begin List.Clear; List.BeginUpdate; try for Index := 0 to FMethods.Count - 1 do begin Command := FMethods.List[Index]^.Key; if not (Assigned(FilterFunc) and FilterFunc(Command)) then begin if TCommandRec(FMethods.List[Index]^.Data^).Action.Tag <> 0 then begin case CommandCategorySortOrder of ccsLegacy: Category:=Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag])+FTranslatableCommandCategory.Strings[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag]; else Category:=FTranslatableCommandCategory.Strings[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag]; end; if List.IndexOf(Category)=-1 then List.Add(Category); end; end; end; List.Sort; if CommandCategorySortOrder=ccsLegacy then for Index:=0 to pred(List.count) do List.Strings[Index]:=RightStr(List.Strings[Index],length(List.Strings[Index])-2); List.Insert(0,'('+rsSimpleWordAll+')'); finally List.EndUpdate; end; end; { TFormCommands.GetCommandsListForACommandCategory } { Routine is in fact going through all the commands present in the main form. They will store them into a list passed in parameter "List". Each item of the list will be a string with information separate between pipe "|" symbol. These info will be command name|shortcut|hint|category number. For example: cm_ChangeDirToHome|Ctrl+Alt+H|Change directory to home|14 While building the list, if the wanted sort method is "csLegacy", each item will preceeded with category index on two digt and by command index on three digits. This is to help to sort the element. We'll simply sort calling "TStringList.Sort" since the beginning of the string have the legacy reference order. For example: 14106cm_ChangeDirToHome|Ctrl+Alt+H|Change directory to home|14 At the end, when exiting, these 5 digits which help to sort will simply be removed. ALSO, the routine has the parameter "sCategoryName" to determine the command from which category should be in the list OR if all the commands from ALL the catagory must be returned. When the commands from ALL the category are requested, category header will be inserted in the returned list. These command will have the prefix for the command index set to '000' to make sure it appear at the beginning of the category command name. For these category identifier, the other fields are empty so that's why pipe are following with nothing between. Example: 14000Navigation|||| No special "class" has been created for all this. It seem simple like that. } procedure TFormCommands.GetCommandsListForACommandCategory(List: TStringList; sCategoryName:String; CommandSortOrder: TCommandSortOrder); var Index, iHotKey, iControl: Integer; Command, Category, sHotKey, LocalHint, HeaderSortedHelper, HeaderCategorySortedHelper: String; HMForm: THMForm; HMControl: THMControl; hotkey: THotkey; begin List.Clear; List.BeginUpdate; try HeaderSortedHelper:=''; HMForm := HotMan.Forms.Find('main'); for Index := 0 to FMethods.Count - 1 do begin Command := FMethods.List[Index]^.Key; if not (Assigned(FilterFunc) and FilterFunc(Command)) then begin Category:=FTranslatableCommandCategory.Strings[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag]; if (Category = sCategoryName) OR (sCategoryName=('('+rsSimpleWordAll+')')) then begin sHotKey := ''; iHotKey := 0; while (iHotKey < HMForm.Hotkeys.Count) and (sHotKey = '') do begin hotkey := HMForm.Hotkeys[iHotKey]; if hotkey.Command = Command then sHotKey := ShortcutsToText(hotkey.Shortcuts); Inc(iHotKey); end; if sHotKey='' then begin iControl:=0; while (iControl<HMForm.Controls.Count) and (sHotKey='') do begin HMControl := HMForm.Controls[iControl]; iHotKey:=0; while (iHotKey < HMControl.Hotkeys.Count) and (sHotKey = '') do begin hotkey := HMControl.Hotkeys[iHotKey]; if hotkey.Command = Command then sHotKey := ShortcutsToText(hotkey.Shortcuts); Inc(iHotKey); end; inc(iControl); end; end; if CommandSortOrder=csLegacy then begin HeaderSortedHelper:=Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag])+ Format('%3.3d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Index+1]); if sCategoryName=('('+rsSimpleWordAll+')') then begin HeaderCategorySortedHelper:=Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag])+'000'; if List.IndexOf(HeaderCategorySortedHelper+Category+'||||')=-1 then List.Add(HeaderCategorySortedHelper+Category+'||||'); end; end; if TCommandRec(FMethods.List[Index]^.Data^).Action.Hint <> EmptyStr then LocalHint := TCommandRec(FMethods.List[Index]^.Data^).Action.Hint else LocalHint := StringReplace(TCommandRec(FMethods.List[Index]^.Data^).Action.Caption, '&', '', [rfReplaceAll]); if LocalHint<>EmptyStr then Command:=Command+'|'+sHotKey+'|'+LocalHint+'|'+Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag]); List.Add(HeaderSortedHelper+Command); end; end; end; List.Sort; if CommandSortOrder=csLegacy then for Index:=0 to pred(List.count) do List.Strings[Index]:=RightStr(List.Strings[Index],length(List.Strings[Index])-(2+3)); finally List.EndUpdate; end; end; procedure TFormCommands.ExtractCommandFields(ItemInList: string; var sCategory: string; var sCommand: string; var sHint: string; var sHotKey: string; var FlagCategoryTitle: boolean); var PosPipe: longint; sWorkingString: String; begin FlagCategoryTitle := False; sCommand := ''; sHint := ''; sHotKey := ''; sCategory := ''; PosPipe := Pos('|', ItemInList); if PosPipe <> 0 then begin if pos('||||', ItemInList) = 0 then begin sCommand := Copy(ItemInList, 1, pred(PosPipe)); sWorkingString := RightStr(ItemInList, length(ItemInList) - PosPipe); PosPipe := pos('|', sWorkingString); if PosPipe <> 0 then begin sHotKey := copy(sWorkingString, 1, pred(PosPipe)); sWorkingString := rightStr(sWorkingString, length(sWorkingString) - PosPipe); PosPipe := pos('|', sWorkingString); if PosPipe <> 0 then begin sHint := copy(sWorkingString, 1, pred(PosPipe)); sCategory := rightStr(sWorkingString, length(sWorkingString) - PosPipe); sCategory := FTranslatableCommandCategory.Strings[StrToIntDef(sCategory,0)]; end; end; end else begin sCommand := Copy(ItemInList, 1, pred(PosPipe)); FlagCategoryTitle := True; end; end; end; class procedure TFormCommands.GetMethodsList(Instance: TObject; MethodsList: TStringHashList; ActionList: TActionList); type pmethodnamerec = ^tmethodnamerec; tmethodnamerec = packed record name : pshortstring; addr : pointer; end; tmethodnametable = packed record count : dword; entries : tmethodnamerec; // first entry // subsequent tmethodnamerec records follow end; pmethodnametable = ^tmethodnametable; var methodtable : pmethodnametable; i : dword; vmt : PVmt; pentry: pmethodnamerec; CommandRec: PCommandRec; Command: String; Action: TContainedAction; begin vmt := PVmt(Instance.ClassType); while assigned(vmt) do begin methodtable := pmethodnametable(vmt^.vMethodTable); if assigned(methodtable) then begin pentry := @methodtable^.entries; for i := 0 to methodtable^.count - 1 do begin Command := pentry[i].name^; if StrBegins(Command, 'cm_') then // TODO: Match functions parameter too. begin New(CommandRec); MethodsList.Add(Command, CommandRec); CommandRec^.Address := pentry[i].addr; CommandRec^.Action := nil; if Assigned(ActionList) then begin Action := ActionList.ActionByName('act' + Copy(Command, 4, Length(Command) - 3)); if Action is TAction then CommandRec^.Action := TAction(Action); end; end; end; end; vmt := vmt^.vParent; end; end; class procedure TFormCommands.GetCategoriesList(List: TStrings; Translated: TStrings); var i: Integer; begin List.Clear; Translated.Clear; for i := Low(CommandsForms) to High(CommandsForms) do begin List.Add(CommandsForms[i].Name); Translated.Add(CommandsForms[i].TranslatedName^); end; end; class function TFormCommands.GetCommandsForm(CategoryName: String): TComponentClass; var i: Integer; begin for i := Low(CommandsForms) to High(CommandsForms) do if CommandsForms[i].Name = CategoryName then begin Exit(CommandsForms[i].AClass); end; Result := nil; end; class procedure TFormCommands.RegisterCommandsForm(AClass: TClass; CategoryName: String; TranslatedName: PResStringRec); begin SetLength(CommandsForms, Length(CommandsForms) + 1); CommandsForms[High(CommandsForms)].AClass := TComponentClass(AClass); CommandsForms[High(CommandsForms)].Name := CategoryName; CommandsForms[High(CommandsForms)].TranslatedName := TranslatedName; end; function GetDefaultParam(const Params: array of String): String; begin if Length(Params) > 0 then Result := Params[0] else Result := ''; end; function GetParamValue(const Params: array of String; Key: String; out Value: String): Boolean; var Param: String; begin Key := Key + '='; for Param in Params do if StrBegins(Param, Key) then begin Value := Copy(Param, Length(Key) + 1, MaxInt); Exit(True); end; Value := ''; Result := False; end; function GetParamValue(const Param: String; Key: String; out Value: String): Boolean; begin Key := Key + '='; if StrBegins(Param, Key) then begin Value := Copy(Param, Length(Key) + 1, MaxInt); Exit(True); end; Value := ''; Result := False; end; function GetParamBoolValue(const Param: String; Key: String; out BoolValue: Boolean): Boolean; var sValue: String; begin Result := GetParamValue(Param, Key, sValue) and GetBoolValue(sValue, BoolValue); end; function GetBoolValue(StrValue: string; out BoolValue: Boolean): Boolean; begin StrValue := upcase(StrValue); if (StrValue = 'TRUE') or (StrValue = 'YES') or (StrValue = 'ON') or (StrValue = '1') then begin BoolValue := True; Result := True; end else if (StrValue = 'FALSE') or (StrValue = 'NO') or (StrValue = 'OFF') or (StrValue = '0') then begin BoolValue := False; Result := True; end else Result := False; end; { CloneMainAction } // Useful to implement an action in sub window form that will invoke a main action function CloneMainAction(AMainAction:TAction; ATargetActionList:TActionList; AMenuToInsert:TMenuItem=nil; APositionToInsert:integer=-1):TAction; var AMenuItem:TMenuItem; begin result:= TAction.Create(ATargetActionList); result.Name := AMainAction.Name; result.Caption := AMainAction.Caption; result.Hint := AMainAction.Hint; result.Category := AMainAction.Category; result.GroupIndex := AMainAction.GroupIndex; result.ShortCut:= AMainAction.ShortCut; result.Enabled := AMainAction.Enabled; result.ActionList := ATargetActionList; result.OnExecute := AMainAction.OnExecute; if AMenuToInsert<>nil then begin AMenuItem:=TMenuItem.Create(AMenuToInsert); AMenuItem.Action:=result; if APositionToInsert=-1 then AMenuToInsert.Add(AMenuItem) else AMenuToInsert.Insert(APositionToInsert,AMenuItem); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ufunctionthread.pas������������������������������������������������������������0000644�0001750�0000144�00000010360�14743153644�017304� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Executing functions in a thread. Copyright (C) 2009-2011 Przemysław Nagay (cobines@gmail.com) 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 } unit uFunctionThread; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs; type TFunctionThreadMethod = procedure(Params: Pointer) of object; PFunctionThreadItem = ^TFunctionThreadItem; TFunctionThreadItem = record Method: TFunctionThreadMethod; Params: Pointer; end; TFunctionThread = class(TThread) private FFunctionsToCall: TFPList; FWaitEvent: PRTLEvent; FLock: TCriticalSection; FFinished: Boolean; protected procedure Execute; override; public constructor Create(CreateSuspended: Boolean); reintroduce; destructor Destroy; override; procedure QueueFunction(AFunctionToCall: TFunctionThreadMethod; AParams: Pointer = nil); procedure Finish; class procedure Finalize(var AThread: TFunctionThread); property Finished: Boolean read FFinished; end; implementation uses LCLProc, uDebug, uExceptions {$IFDEF MSWINDOWS} , ActiveX {$ENDIF} ; constructor TFunctionThread.Create(CreateSuspended: Boolean); begin FWaitEvent := RTLEventCreate; FFunctionsToCall := TFPList.Create; FLock := TCriticalSection.Create; FFinished := False; FreeOnTerminate := False; inherited Create(CreateSuspended, DefaultStackSize); end; destructor TFunctionThread.Destroy; var i: Integer; begin RTLeventdestroy(FWaitEvent); FLock.Acquire; for i := 0 to FFunctionsToCall.Count - 1 do Dispose(PFunctionThreadItem(FFunctionsToCall[i])); FLock.Release; FreeAndNil(FFunctionsToCall); FreeAndNil(FLock); inherited Destroy; end; procedure TFunctionThread.QueueFunction(AFunctionToCall: TFunctionThreadMethod; AParams: Pointer); var pItem: PFunctionThreadItem; begin if (not Terminated) and Assigned(AFunctionToCall) then begin New(pItem); pItem^.Method := AFunctionToCall; pItem^.Params := AParams; FLock.Acquire; try FFunctionsToCall.Add(pItem); finally FLock.Release; end; RTLeventSetEvent(FWaitEvent); end; end; procedure TFunctionThread.Finish; begin Terminate; RTLeventSetEvent(FWaitEvent); end; procedure TFunctionThread.Execute; var pItem: PFunctionThreadItem; begin {$IFDEF MSWINDOWS} CoInitializeEx(nil, COINIT_APARTMENTTHREADED); {$ENDIF} try while (not Terminated) or (FFunctionsToCall.Count > 0) do begin RTLeventResetEvent(FWaitEvent); pItem := nil; FLock.Acquire; try if FFunctionsToCall.Count > 0 then begin pItem := PFunctionThreadItem(FFunctionsToCall[0]); FFunctionsToCall.Delete(0); end; finally FLock.Release; end; if Assigned(pItem) then begin try pItem^.Method(pItem^.Params); Dispose(pItem); except on e: Exception do begin Dispose(pItem); HandleException(e, Self); end; end; end else begin RTLeventWaitFor(FWaitEvent); end; end; finally {$IFDEF MSWINDOWS} CoUninitialize; {$ENDIF} FFinished := True; end; end; class procedure TFunctionThread.Finalize(var AThread: TFunctionThread); begin AThread.Finish; {$IF (fpc_version<2) or ((fpc_version=2) and (fpc_release<5))} If (MainThreadID=GetCurrentThreadID) then while not AThread.Finished do CheckSynchronize(100); {$ENDIF} AThread.WaitFor; AThread.Free; AThread := nil; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uglobs.pas���������������������������������������������������������������������0000755�0001750�0000144�00000510632�14743153644�015407� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Globals variables and some consts Copyright (C) 2008-2020 Alexander Koblov (alexx2000@mail.ru) 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, see <http://www.gnu.org/licenses/>. Original comment: ------------------------------------------------------------ Seksi Commander ---------------------------- Licence : GNU GPL v 2.0 Author : radek.cervinka@centrum.cz Globals variables and some consts contributors: Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2008 Vitaly Zotov (vitalyzotov@mail.ru) Copyright (C) 2006-2019 Alexander Koblov (alexx2000@mail.ru) } unit uGlobs; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, Forms, Grids, Types, uExts, uColorExt, Graphics, LCLVersion, DCClassesUtf8, uMultiArc, uColumns, uHotkeyManager, uSearchTemplate, uFileSourceOperationOptions, uWFXModule, uWCXModule, uWDXModule, uwlxmodule, udsxmodule, DCXmlConfig, uInfoToolTip, fQuickSearch, uTypes, uClassesEx, uColors, uHotDir, uSpecialDir, SynEdit, SynEditTypes, uFavoriteTabs, fTreeViewMenu, uConvEncoding, DCJsonConfig, uFileSourceOperationTypes; type { Configuration options } TSortConfigurationOptions = (scoClassicLegacy, scoAlphabeticalButLanguage); TConfigurationTreeState = (ctsFullExpand, ctsFullCollapse); { Log options } TLogOptions = set of (log_cp_mv_ln, log_delete, log_dir_op, log_arc_op, log_vfs_op, log_success, log_errors, log_info, log_start_shutdown, log_commandlineexecution); { Watch dirs options } TWatchOptions = set of (watch_file_name_change, watch_attributes_change, watch_only_foreground, watch_exclude_dirs); { Tabs options } TTabsOptions = set of (tb_always_visible, tb_multiple_lines, tb_same_width, tb_text_length_limit, tb_confirm_close_all, tb_close_on_dbl_click, tb_open_new_in_foreground, tb_open_new_near_current, tb_show_asterisk_for_locked, tb_activate_panel_on_click, tb_show_close_button, tb_close_duplicate_when_closing, tb_close_on_doubleclick, tb_show_drive_letter, tb_reusing_tab_when_possible, tb_confirm_close_locked_tab, tb_keep_renamed_when_back_normal); TTabsOptionsDoubleClick = (tadc_Nothing, tadc_CloseTab, tadc_FavoriteTabs, tadc_TabsPopup); TTabsPosition = (tbpos_top, tbpos_bottom); { Show icons mode } TShowIconsMode = (sim_none, sim_standart, sim_all, sim_all_and_exe); { Custom icons mode } TCustomIconsMode = set of (cimDrive, cimFolder, cimArchive); TScrollMode = (smLineByLineCursor, smLineByLine, smPageByPage); { Sorting directories mode } TSortFolderMode = (sfmSortNameShowFirst, sfmSortLikeFileShowFirst, sfmSortLikeFile); { Where to insert new files in the filelist } TNewFilesPosition = (nfpTop, nfpTopAfterDirectories, nfpSortedPosition, nfpBottom); { Where to move updated files in the filelist } TUpdatedFilesPosition = (ufpSameAsNewFiles, ufpSortedPosition, ufpNoChange); { How initially progress is shown for file operations } TFileOperationsProgressKind = (fopkSeparateWindow, fopkSeparateWindowMinimized, fopkOperationsPanel); { Operations with confirmation } TFileOperationsConfirmation = (focCopy, focMove, focDelete, focDeleteToTrash, focVerifyChecksum, focTestArchive); TFileOperationsConfirmations = set of TFileOperationsConfirmation; { Multi-Rename } TMulRenLaunchBehavior = (mrlbLastMaskUnderLastOne, mrlbLastPreset, mrlbFreshNew); TMulRenExitModifiedPreset = (mrempIgnoreSaveLast, mrempPromptUser, mrempSaveAutomatically); TMulRenSaveRenamingLog = (mrsrlPerPreset, mrsrlAppendSameLog); { Internal Associations} //What the use wish for the context menu // uwcmComplete : DEFAULT, or user specifically wish the "Windows' one + the actions". // uwcmJustDCAction : User specifically wish only the actions, even if default set is not it. TUserWishForContextMenu = (uwcmComplete, uwcmJustDCAction); TExternalTool = (etViewer, etEditor, etDiffer); TExternalToolOptions = record Enabled: Boolean; Path: String; Parameters: String; RunInTerminal: Boolean; KeepTerminalOpen: Boolean; end; TExternalToolsOptions = array[TExternalTool] of TExternalToolOptions; TResultingFramePositionAfterCompare = (rfpacActiveOnLeft, rfpacLeftOnLeft); //Related with the Viewer TViewerPaintTool = (vptPen, vptRectangle, vptEllipse); TPluginType = (ptDSX, ptWCX, ptWDX, ptWFX, ptWLX); //*Important: Keep that order to to fit with procedures LoadXmlConfig/SaveXmlConfig when we save/restore widths of "TfrmTweakPlugin". TWcxCfgViewMode = (wcvmByPlugin, wcvmByExtension); TDCFont = (dcfMain, dcfEditor, dcfViewer, dcfViewerBook, dcfLog, dcfConsole, dcfPathEdit, dcfSearchResults, dcfFunctionButtons, dcfTreeViewMenu, dcfStatusBar); TDCFontOptions = record Usage: string; Name: string; Size: Integer; Style: TFontStyles; Quality: TFontQuality; MinValue: integer; MaxValue: integer; end; TDCFontsOptions = array[TDCFont] of TDCFontOptions; // fswmPreventDelete - prevents deleting watched directories // fswmAllowDelete - does not prevent deleting watched directories // fswmWholeDrive - watch whole drives instead of single directories to omit problems with deleting watched directories TWatcherMode = (fswmPreventDelete, fswmAllowDelete, fswmWholeDrive); TDrivesListButtonOption = (dlbShowLabel, dlbShowFileSystem, dlbShowFreeSpace); TDrivesListButtonOptions = set of TDrivesListButtonOption; TKeyTypingModifier = (ktmNone, ktmAlt, ktmCtrlAlt); TKeyTypingAction = (ktaNone, ktaCommandLine, ktaQuickSearch, ktaQuickFilter); tDesiredDropTextFormat=record Name:string; DesireLevel:longint; end; tDuplicatedRename = (drLegacyWithCopy, drLikeWindows7, drLikeTC); TBriefViewMode = (bvmFixedWidth, bvmFixedCount, bvmAutoSize); TFiltersOnNewSearch = (fonsKeep, fonsClear, fonsPrompt); THotKeySortOrder = (hksoByCommand, hksoByHotKeyGrouped, hksoByHotKeyOnePerRow); TToolTipMode = (tttmCombineDcSystem, tttmDcSystemCombine, tttmDcIfPossThenSystem, tttmDcOnly, tttmSystemOnly); TToolTipHideTimeOut = (ttthtSystem, tttht1Sec, tttht2Sec, tttht3Sec, tttht5Sec, tttht10Sec, tttht30Sec, tttht1Min, ttthtNeverHide); TConfigFilenameStyle = (pfsAbsolutePath, pfsRelativeToDC, pfsRelativeToFollowingPath); tToolbarPathModifierElement = (tpmeIcon, tpmeCommand, tpmeStartingPath); tToolbarPathModifierElements = set of tToolbarPathModifierElement; tFileAssocPathModifierElement = (fameIcon, fameCommand, fameStartingPath); tFileAssocPathModifierElements = set of tFileAssocPathModifierElement; tHotDirPathModifierElement = (hdpmSource, hdpmTarget); tHotDirPathModifierElements = set of tHotDirPathModifierElement; const { Default hotkey list version number } hkVersion = 63; // 54 - In "Viewer" context, added the "W" for "cm_WrapText", "4" for "cm_ShowAsDec", "8" for "cm_ShowOffice". // 53 - In "Main" context, change shortcut "Alt+`" to "Alt+0" for the "cm_ActivateTabByIndex". // 52 - In "Main" context, add shortcut "Ctrl+Shift+B" for "cm_FlatViewSel". // 51 - In "Multi-Rename" context, added the "Shift+F4" shortcut for the "cm_EditNewNames". // 50 - To load shortcut keys for the "Multi-Rename" which is now driven with "cm_Actions". // 49 - In "Viewer" context, added the "F6" for "cm_ShowCaret". // 48 - In "Viewer" context, added the "CTRL+P" for the "cm_Print". // 47 - In "Copy/Move Dialog" context, add the shortcuts "F5" and "F6" for "cm_ToggleSelectionInName". // 46 - In "Main" context, add shortcut "Shift+Tab" for "cm_FocusTreeView". // 45 - Automatically add default shortcuts to internal editor (shortcuts had not converted correctly without hkVersion update) // 44 - Attempt to repair shortcut keys for "cm_ShowCmdLineHistory" in "Main" context. // 43 - To load shortcut keys for the "Synchronize Directories" which is driven with "cm_Actions". // 42 - In "Find Files" context, added the "CTRL+TAB" and "CTRL+SHIFT+TAB" shortcut keys for the "cm_PageNext" and "cm_PagePrev" commands. // 41 - Keyboard shortcuts to change encoding in Viewer (A, S, Z and X). // 40 - In "Main" context, added the "Ctrl+Shift+F7" for "cm_AddNewSearch". // In "Find Files" context, changed "cm_Start" that was "Enter" for "F9". // In "Find Files" context, added "Alt+F7" as a valid alternative for "cm_PageStandard". // Previously existing names if reused must check for ConfigVersion >= X. // History: // 2 - removed Layout/SmallIcons // renamed Layout/SmallIconSize to Layout/IconSize // 3 - Layout/DriveMenuButton -> Layout/DrivesListButton and added subnodes: // ShowLabel, ShowFileSystem, ShowFreeSpace // 4 - changed QuickSearch/Enabled, QuickSearch/Mode and same for QuickFilter // to Keyboard/Typing. // 5 - changed Behaviours/SortCaseSensitive to FilesViews/Sorting/CaseSensitivity // changed Behaviours/SortNatural to FilesViews/Sorting/NaturalSorting // 6 - changed Behaviours/ShortFileSizeFormat to Behaviours/FileSizeFormat // 7 - changed Viewer/SaveThumbnails to Thumbnails/Save // 8 - changed Behaviours/BriefViewFileExtAligned to FilesViews/BriefView/FileExtAligned // 9 - few new options regarding tabs // 10 - changed Icons/CustomDriveIcons to Icons/CustomIcons // 11 - During the last 2-3 years the default font for search result was set in file, not loaded and different visually than was was stored. // 12 - Split Behaviours/HeaderFooterSizeFormat to Behaviours/HeaderSizeFormat and Behaviours/FooterSizeFormat // Loading a config prior of version 11 should ignore that setting and keep default. // 13 - Replace Configuration/UseConfigInProgramDir by doublecmd.inf // 14 - Move some colors to colors.json // 15 - Move custom columns colors to colors.json ConfigVersion = 15; COLORS_JSON = 'colors.json'; // Configuration related filenames sMULTIARC_FILENAME = 'multiarc.ini'; TKeyTypingModifierToShift: array[TKeyTypingModifier] of TShiftState = ([], [ssAlt], [ssCtrl, ssAlt]); { Related with the drop of text over panels} NbOfDropTextFormat = 4; DropTextRichText_Index=0; DropTextHtml_Index=1; DropTextUnicode_Index=2; DropTextSimpleText_Index=3; var { For localization } gPOFileName, gHelpLang: String; { DSX plugins } gDSXPlugins: TDSXModuleList; { WCX plugins } gWCXPlugins: TWCXModuleList; { WDX plugins } gWDXPlugins:TWDXModuleList; { WFX plugins } gWFXPlugins: TWFXModuleList; { WLX plugins } gWLXPlugins: TWLXModuleList; gTweakPluginWidth: array[ord(ptDSX)..ord(ptWLX)] of integer; gTweakPluginHeight: array[ord(ptDSX)..ord(ptWLX)] of integer; gPluginInAutoTweak: boolean; gWCXConfigViewMode: TWcxCfgViewMode; gPluginFilenameStyle: TConfigFilenameStyle = pfsAbsolutePath; gPluginPathToBeRelativeTo: string = '%COMMANDER_PATH%'; { Colors } gColors: TColorThemes; { MultiArc addons } gMultiArcList: TMultiArcList; { Columns Set } ColSet:TPanelColumnsList; { Layout page } gMainMenu, gButtonBar, gToolBarFlat, gMiddleToolBar, gDriveBar1, gDriveBar2, gDriveBarFlat, gDrivesListButton, gDirectoryTabs, gCurDir, gTabHeader, gStatusBar, gCmdLine, gLogWindow, gTermWindow, gKeyButtons, gInterfaceFlat, gDriveInd, gDriveFreeSpace, gProgInMenuBar, gPanelOfOp, gHorizontalFilePanels, gUpperCaseDriveLetter, gShowColonAfterDrive, gShortFormatDriveInfo: Boolean; gDrivesListButtonOptions: TDrivesListButtonOptions; gSeparateTree: Boolean; { Toolbar } gMiddleToolBarFlat, gMiddleToolBarShowCaptions, gMiddleToolbarReportErrorWithCommands: Boolean; gMiddleToolBarButtonSize, gMiddleToolBarIconSize, gToolBarButtonSize, gToolBarIconSize: Integer; gToolBarShowCaptions: Boolean; gToolbarReportErrorWithCommands: boolean; gToolbarFilenameStyle: TConfigFilenameStyle; gToolbarPathToBeRelativeTo: string; gToolbarPathModifierElements: tToolbarPathModifierElements; gRepeatPassword:Boolean; // repeat password when packing files gDirHistoryCount:Integer; // how many history we remember gShowSystemFiles:Boolean; gRunInTermStayOpenCmd: String; gRunInTermStayOpenParams: String; gRunInTermCloseCmd: String; gRunInTermCloseParams: String; gRunTermCmd: String; gRunTermParams: String; gSortCaseSensitivity: TCaseSensitivity; gSortNatural: Boolean; gSortSpecial: Boolean; gSortFolderMode: TSortFolderMode; gNewFilesPosition: TNewFilesPosition; gUpdatedFilesPosition: TUpdatedFilesPosition; gLynxLike:Boolean; gFirstTextSearch: Boolean; { File views page } gExtraLineSpan: Integer; gFolderPrefix, gFolderPostfix: String; gRenameConfirmMouse: Boolean; { Mouse } gMouseSelectionEnabled: Boolean; gMouseSelectionButton: Integer; gMouseSingleClickStart: Integer; gMouseSelectionIconClick: Integer; gAutoFillColumns: Boolean; gAutoSizeColumn: Integer; gColumnsLongInStatus : Boolean; gColumnsAutoSaveWidth: Boolean; gColumnsTitleStyle: TTitleStyle; gCustomColumnsChangeAllColumns: Boolean; gSpecialDirList:TSpecialDirList=nil; gDirectoryHotlist:TDirectoryHotlist; gHotDirAddTargetOrNot: Boolean; gHotDirFullExpandOrNot: Boolean; gShowPathInPopup: boolean; gShowOnlyValidEnv: boolean = TRUE; gWhereToAddNewHotDir: TPositionWhereToAddHotDir; gHotDirFilenameStyle: TConfigFilenameStyle; gHotDirPathToBeRelativeTo: string; gHotDirPathModifierElements: tHotDirPathModifierElements; glsDirHistory:TStringListEx; glsCmdLineHistory: TStringListEx; glsMaskHistory : TStringListEx; glsSearchHistory : TStringListEx; glsSearchPathHistory : TStringListEx; glsReplaceHistory : TStringListEx; glsReplacePathHistory : TStringListEx; glsCreateDirectoriesHistory : TStringListEx; glsRenameNameMaskHistory : TStringListEx; glsRenameExtMaskHistory : TStringListEx; glsSearchDirectories: TStringList; glsSearchExcludeFiles: TStringList; glsSearchExcludeDirectories: TStringList; glsVolumeSizeHistory : TStringListEx; glsIgnoreList : TStringListEx; gOnlyOneAppInstance, gColumnsTitleLikeValues: Boolean; gCutTextToColWidth : Boolean; gExtendCellWidth : Boolean; gSpaceMovesDown: Boolean; gScrollMode: TScrollMode; gWheelScrollLines: Integer; gAlwaysShowTrayIcon: Boolean; gMinimizeToTray: Boolean; gConfirmQuit: Boolean; gFileSizeFormat: TFileSizeFormat; gHeaderSizeFormat: TFileSizeFormat; gFooterSizeFormat: TFileSizeFormat; gOperationSizeFormat: TFileSizeFormat; gFileSizeDigits: Integer; gHeaderDigits: Integer; gFooterDigits: Integer; gOperationSizeDigits: Integer; gSizeDisplayUnits: array[LOW(TFileSizeFormat) .. HIGH(TFileSizeFormat)] of string; gDateTimeFormat : String; gDriveBlackList: String; gDriveBlackListUnmounted: Boolean; // Automatically black list unmounted devices gListFilesInThread: Boolean; gLoadIconsSeparately: Boolean; gDelayLoadingTabs: Boolean; gHighlightUpdatedFiles: Boolean; gLastUsedPacker: String; gLastDoAnyCommand: String; gbMarkMaskCaseSensitive: boolean; gbMarkMaskIgnoreAccents: boolean; gMarkMaskFilterWindows: boolean; gMarkShowWantedAttribute: boolean; gMarkDefaultWantedAttribute: string; gMarkLastWantedAttribute: string; { Favorite Tabs } gFavoriteTabsUseRestoreExtraOptions: boolean; gFavoriteTabsList: TFavoriteTabsList; gWhereToAddNewFavoriteTabs: TPositionWhereToAddFavoriteTabs; gFavoriteTabsFullExpandOrNot: boolean; gFavoriteTabsGoToConfigAfterSave: boolean; gFavoriteTabsGoToConfigAfterReSave: boolean; gDefaultTargetPanelLeftSaved: TTabsConfigLocation; gDefaultTargetPanelRightSaved: TTabsConfigLocation; gDefaultExistingTabsToKeep: TTabsConfigLocation; gFavoriteTabsSaveDirHistory: boolean; { Brief view page } gBriefViewFixedWidth: Integer; gBriefViewFixedCount: Integer; gBriefViewMode: TBriefViewMode; gBriefViewFileExtAligned: Boolean; { Tools page } gExternalTools: TExternalToolsOptions; gResultingFramePositionAfterCompare:TResultingFramePositionAfterCompare; gLuaLib:String; gExts:TExts; gColorExt:TColorExt; gFileInfoToolTip: TFileInfoToolTip; gFileInfoToolTipValue: array[0..ord(ttthtNeverHide)] of integer = (-1, 1000, 2000, 3000, 5000, 10000, 30000, 60000, integer.MaxValue); { Fonts page } gFonts: TDCFontsOptions; { File panels color page } gUseCursorBorder: Boolean; gUseFrameCursor: Boolean; gUseInvertedSelection: Boolean; gUseInactiveSelColor: Boolean; gAllowOverColor: Boolean; gBorderFrameWidth :integer; gInactivePanelBrightness: Integer; // 0 .. 100 (black .. full color) gIndUseGradient : Boolean; // use gradient on drive label gShowIcons: TShowIconsMode; gShowIconsNew: TShowIconsMode; gIconOverlays : Boolean; gIconsSize, gIconsSizeNew : Integer; gDiskIconsSize : Integer; gDiskIconsAlpha : Integer; gToolIconsSize: Integer; gIconsExclude: Boolean; gIconsExcludeDirs: String; gPixelsPerInch: Integer; gCustomIcons : TCustomIconsMode; // for use custom icons under windows gIconsInMenus: Boolean; gIconsInMenusSize, gIconsInMenusSizeNew: Integer; gShowHiddenDimmed: Boolean; gIconTheme: String; { Keys page } gKeyTyping: array[TKeyTypingModifier] of TKeyTypingAction; { File operations page } gLongNameAlert: Boolean; gCopyBlockSize : Integer; gHashBlockSize : Integer; gUseMmapInSearch : Boolean; gPartialNameSearch: Boolean; gInitiallyClearFileMask : Boolean; gNewSearchClearFiltersAction : TFiltersOnNewSearch; gShowMenuBarInFindFiles : Boolean; gSkipFileOpError: Boolean; gTypeOfDuplicatedRename: tDuplicatedRename; gDropReadOnlyFlag : Boolean; gWipePassNumber: Integer; gProcessComments: Boolean; gShowCopyTabSelectPanel:boolean; gUseTrash : Boolean; // if using delete to trash by default gRenameSelOnlyName:boolean; gDefaultDropEffect: Boolean; gShowDialogOnDragDrop: Boolean; gDragAndDropDesiredTextFormat:array[0..pred(NbOfDropTextFormat)] of tDesiredDropTextFormat; gDragAndDropAskFormatEachTime: Boolean; gDragAndDropTextAutoFilename: Boolean; gDragAndDropSaveUnicodeTextInUFT8: Boolean; gNtfsHourTimeDelay: Boolean; gAutoExtractOpenMask: String; gFileOperationsProgressKind: TFileOperationsProgressKind; gFileOperationsConfirmations: TFileOperationsConfirmations; gFileOperationsSounds: array[TFileSourceOperationType] of String; gFileOperationDuration: Integer; { Multi-Rename} gMulRenShowMenuBarOnTop : boolean; gMulRenInvalidCharReplacement : string; gMulRenLaunchBehavior : TMulRenLaunchBehavior; gMulRenExitModifiedPreset : TMulRenExitModifiedPreset; gMulRenSaveRenamingLog : TMulRenSaveRenamingLog; gMulRenLogFilename : string; gMultRenDailyIndividualDirLog: boolean; gMulRenFilenameWithFullPathInLog:boolean; gMulRenPathRangeSeparator: string; { Folder tabs page } gDirTabOptions : TTabsOptions; gDirTabActionOnDoubleClick : TTabsOptionsDoubleClick; gDirTabLimit : Integer; gDirTabPosition : TTabsPosition; { Log page } gLogFile : Boolean; gLogFileWithDateInName : Boolean; gLogFileCount: Integer; gLogFileName : String; gLogOptions : TLogOptions; { Configuration page } gUseConfigInProgramDir, gUseConfigInProgramDirNew, gSaveConfiguration, gSaveWindowState, gSaveFolderTabs, gSaveSearchReplaceHistory, gSaveDirHistory, gSaveCmdLineHistory, gSaveFileMaskHistory, gSaveVolumeSizeHistory, gSaveCreateDirectoriesHistory: Boolean; gSortOrderOfConfigurationOptionsTree: TSortConfigurationOptions; gCollapseConfigurationOptionsTree: TConfigurationTreeState; { Quick Search page } gQuickSearchOptions: TQuickSearchOptions; gQuickFilterAutoHide: Boolean; gQuickFilterSaveSessionModifications: Boolean; { Misc page } gGridVertLine, gGridHorzLine, gShowWarningMessages, gDirBrackets, gInplaceRename, gInplaceRenameButton, gDblClickToParent, gDblClickEditPath, gGoToRoot: Boolean; gShowCurDirTitleBar: Boolean; gActiveRight: Boolean; gShowToolTip: Boolean; gShowToolTipMode: TToolTipMode; gToolTipHideTimeOut: TToolTipHideTimeOut; gThumbSize: TSize; gThumbSave: Boolean; gSearchDefaultTemplate: String; gSearchTemplateList: TSearchTemplateList; gDescCreateUnicode: Boolean; gDescReadEncoding: TMacroEncoding; gDescWriteEncoding: TMacroEncoding; gDefaultTextEncoding: String; { Auto refresh page } gWatchDirs: TWatchOptions; gWatchDirsExclude: String; gWatcherMode: TWatcherMode; { Ignore list page } gIgnoreListFileEnabled: Boolean; gIgnoreListFile: String; {HotKey Manager} HotMan:THotKeyManager; gNameSCFile: string; gHotKeySortOrder: THotKeySortOrder; gUseEnterToCloseHotKeyEditor: boolean; {Copy/Move operation options} gOperationOptionSymLinks: TFileSourceOperationOptionSymLink; gOperationOptionCorrectLinks: Boolean; gOperationOptionCopyOnWrite: TFileSourceOperationOptionGeneral; gOperationOptionFileExists: TFileSourceOperationOptionFileExists; gOperationOptionDirectoryExists: TFileSourceOperationOptionDirectoryExists; gOperationOptionSetPropertyError: TFileSourceOperationOptionSetPropertyError; gOperationOptionReserveSpace: Boolean; gOperationOptionCheckFreeSpace: Boolean; gOperationOptionCopyAttributes: Boolean; gOperationOptionCopyXattributes: Boolean; gOperationOptionCopyTime: Boolean; gOperationOptionVerify: Boolean; gOperationOptionCopyOwnership: Boolean; gOperationOptionCopyPermissions: Boolean; gOperationOptionExcludeEmptyDirectories: Boolean; {Extract dialog options} gExtractOverwrite: Boolean; {Error file} gErrorFile: String; {Viewer} gPreviewVisible, gImageStretch: Boolean; gImageExifRotate: Boolean; gImageStretchOnlyLarge: Boolean; gImageShowTransparency: Boolean; gImageCenter: Boolean; gCopyMovePath1, gCopyMovePath2, gCopyMovePath3, gCopyMovePath4, gCopyMovePath5: String; gImagePaintMode: TViewerPaintTool; gImagePaintWidth, gColCount, gViewerMode, gMaxCodeSize, gMaxTextWidth, gTabSpaces : Integer; gImagePaintColor, gTextPosition:PtrInt; gPrintMargins: TRect; gShowCaret: Boolean; gViewerWrapText: Boolean; gViewerLeftMargin: Integer; gViewerLineSpacing: Integer; gViewerAutoCopy: Boolean; gViewerSynEditMask: String; gViewerJpegQuality: Integer; { Editor } gEditWaitTime: Integer; gEditorSynEditOptions: TSynEditorOptions; gEditorSynEditTabWidth, gEditorSynEditRightEdge, gEditorSynEditBlockIndent: Integer; gEditorFindWordAtCursor: Boolean; { Differ } gDifferIgnoreCase, gDifferAutoCompare, gDifferKeepScrolling, gDifferLineDifferences, gDifferPaintBackground, gDifferIgnoreWhiteSpace: Boolean; {SyncDirs} gSyncDirsSubdirs, gSyncDirsByContent, gSyncDirsAsymmetric, gSyncDirsIgnoreDate, gSyncDirsAsymmetricSave, gSyncDirsShowFilterCopyRight, gSyncDirsShowFilterEqual, gSyncDirsShowFilterNotEqual, gSyncDirsShowFilterUnknown, gSyncDirsShowFilterCopyLeft, gSyncDirsShowFilterDuplicates, gSyncDirsShowFilterSingles: Boolean; gSyncDirsFileMask: string; gSyncDirsFileMaskSave: Boolean; gDateTimeFormatSync : String; { Internal Associations} gFileAssociationLastCustomAction: string; gOfferToAddToFileAssociations: boolean; gExtendedContextMenu: boolean; gDefaultContextActions: boolean; gOpenExecuteViaShell: boolean; gExecuteViaTerminalClose: boolean; gExecuteViaTerminalStayOpen: boolean; gIncludeFileAssociation: boolean; gFileAssocFilenameStyle: TConfigFilenameStyle; gFileAssocPathToBeRelativeTo: string; gFileAssocPathModifierElements: tFileAssocPathModifierElements; { TreeViewMenu } gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand: boolean; gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick: boolean; gUseTreeViewMenuWithFavoriteTabsFromMenuCommand: boolean; gUseTreeViewMenuWithFavoriteTabsFromDoubleClick: boolean; gUseTreeViewMenuWithDirHistory: boolean; gUseTreeViewMenuWithViewHistory: boolean; gUseTreeViewMenuWithCommandLineHistory: boolean; gTreeViewMenuUseKeyboardShortcut: boolean; gTreeViewMenuOptions: array [0..(ord(tvmcLASTONE)-2)] of TTreeViewMenuOptions; gTreeViewMenuShortcutExit: boolean; gTreeViewMenuSingleClickExit: boolean; gTreeViewMenuDoubleClickExit: boolean; crArrowCopy: Integer = 1; crArrowMove: Integer = 2; crArrowLink: Integer = 3; {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} gSystemItemProperties: Boolean = False; {$ENDIF} { TotalCommander Import/Export } {$IFDEF MSWINDOWS} gTotalCommanderExecutableFilename:string; gTotalCommanderConfigFilename:string; gTotalCommanderToolbarPath:string; {$ENDIF} function LoadConfig: Boolean; function InitGlobs: Boolean; function LoadGlobs: Boolean; procedure SaveGlobs; procedure LoadXmlConfig; procedure SaveXmlConfig; procedure LoadDefaultHotkeyBindings; function InitPropStorage(Owner: TComponent): TIniPropStorageEx; procedure FontToFontOptions(Font: TFont; var Options: TDCFontOptions); procedure FontOptionsToFont(Options: TDCFontOptions; Font: TFont); function GetKeyTypingAction(ShiftStateEx: TShiftState): TKeyTypingAction; function IsFileSystemWatcher: Boolean; function GetValidDateTimeFormat(const aFormat, ADefaultFormat: string): string; procedure RegisterInitialization(InitProc: TProcedure); const cMaxStringItems=50; var gConfig: TXmlConfig = nil; gStyles: TJsonConfig = nil; DefaultDateTimeFormat: String; DefaultDateTimeFormatSync: String; implementation uses LCLProc, LCLType, Dialogs, Laz2_XMLRead, LazUTF8, LConvEncoding, uExifWdx, uGlobsPaths, uLng, uShowMsg, uFileProcs, uOSUtils, uFindFiles, uEarlyConfig, dmHigh, uDCUtils, fMultiRename, uDCVersion, uDebug, uFileFunctions, uDefaultPlugins, Lua, uKeyboard, DCOSUtils, DCStrUtils, uPixMapManager, FileUtil, uSynDiffControls {$IF DEFINED(MSWINDOWS)} , ShlObj {$ENDIF} {$if lcl_fullversion >= 2010000} , SynEditMiscClasses {$endif} ; const TKeyTypingModifierToNodeName: array[TKeyTypingModifier] of String = ('NoModifier', 'Alt', 'CtrlAlt'); type TLoadConfigProc = function(var ErrorMessage: String): Boolean; var // Double Commander version // loaded from configuration file gPreviousVersion: String = ''; FInitList: array of TProcedure; CustomDecimalSeparator: String = #$EF#$BF#$BD; function LoadConfigCheckErrors(LoadConfigProc: TLoadConfigProc; ConfigFileName: String; var ErrorMessage: String): Boolean; procedure AddMsg(Msg, eMsg: String); begin AddStrWithSep(ErrorMessage, Msg + ':', LineEnding + LineEnding); AddStrWithSep(ErrorMessage, ConfigFileName, LineEnding); if eMsg <> EmptyStr then AddStrWithSep(ErrorMessage, eMsg, LineEnding); end; begin Result := False; try Result := LoadConfigProc(ErrorMessage); except // If the file does not exist or is empty, // simply default configuration is applied. on EXmlConfigNotFound do Result := True; on EXmlConfigEmpty do Result := True; on e: EFOpenError do AddMsg(rsMsgErrEOpen, e.Message); on e: EStreamError do AddMsg(rsMsgErrERead, e.Message); on e: EXMLReadError do AddMsg(rsMsgInvalidFormatOfConfigurationFile, e.Message); end; end; type TSaveCfgProc = procedure; procedure SaveWithCheck(SaveProc: TSaveCfgProc; CfgDescription: String; var ErrMsg: String); begin try SaveProc; except on E: EStreamError do ErrMsg := ErrMsg + 'Cannot save ' + CfgDescription + ': ' + e.Message; end; end; procedure SaveCfgIgnoreList; var FileName: String; begin if gIgnoreListFileEnabled then begin FileName:= ReplaceEnvVars(gIgnoreListFile); mbForceDirectory(ExtractFileDir(FileName)); glsIgnoreList.SaveToFile(FileName); end; end; procedure SaveCfgMainConfig; begin SaveXmlConfig; // Force saving config to file. gConfig.Save; end; procedure SaveColorsConfig; begin gColors.Save(gStyles.Root); gColorExt.Save(gStyles.Root); ColSet.SaveColors(gStyles.Root); gHighlighters.SaveColors(gStyles.Root); gStyles.SaveToFile(gpCfgDir + COLORS_JSON); end; procedure SaveHighlightersConfig; begin gHighlighters.Save(gpCfgDir + HighlighterConfig); end; function AskUserOnError(var ErrorMessage: String): Boolean; begin // Show error messages. if ErrorMessage <> EmptyStr then begin Result := QuestionDlg(Application.Title + ' - ' + rsMsgErrorLoadingConfiguration, ErrorMessage, mtWarning, [1, rsDlgButtonContinue, 'isdefault', 2, rsDlgButtonExitProgram], 0) = 1; // Reset error message. ErrorMessage := ''; end else Result := True; end; function LoadGlobalConfig(var {%H-}ErrorMessage: String): Boolean; begin Result := gConfig.Load; end; function LoadExtsConfig(var {%H-}ErrorMessage: String): Boolean; begin gExts.Load; Result := True; end; function LoadHotManConfig(var {%H-}ErrorMessage: String): Boolean; begin HotMan.Load(gpCfgDir + gNameSCFile); Result := True; end; function LoadColorsConfig(var {%H-}ErrorMessage: String): Boolean; begin gStyles.LoadFromFile(gpCfgDir + COLORS_JSON); gColors.Load(gStyles.Root); gColorExt.Load(gStyles.Root); ColSet.LoadColors(gStyles.Root); gHighlighters.LoadColors(gStyles.Root); Result := True; end; function LoadHighlightersConfig(var {%H-}ErrorMessage: String): Boolean; begin gHighlighters.Load(gpCfgDir + HighlighterConfig); Result := True; end; function LoadMultiArcConfig(var {%H-}ErrorMessage: String): Boolean; begin gMultiArcList.LoadFromFile(gpCfgDir + sMULTIARC_FILENAME); Result := True; end; function LoadHistoryConfig(var {%H-}ErrorMessage: String): Boolean; var Root: TXmlNode; History: TXmlConfig; procedure LoadHistory(const NodeName: String; HistoryList: TStrings; LoadObj: Boolean = False); var Idx: Integer; Node: TXmlNode; begin Node := History.FindNode(Root, NodeName); if Assigned(Node) then begin HistoryList.Clear; Node := Node.FirstChild; while Assigned(Node) do begin if Node.CompareName('Item') = 0 then begin Idx:= HistoryList.Add(History.GetContent(Node)); if LoadObj then begin HistoryList.Objects[Idx]:= TObject(UIntPtr(History.GetAttr(Node, 'Tag', 0))); end; if HistoryList.Count >= cMaxStringItems then Break; end; Node := Node.NextSibling; end; end; end; begin Result:= False; History:= TXmlConfig.Create(gpCfgDir + 'history.xml', True); try Root:= History.FindNode(History.RootNode, 'History'); if Assigned(Root) then begin LoadHistory('Navigation', glsDirHistory); LoadHistory('CommandLine', glsCmdLineHistory); LoadHistory('VolumeSize', glsVolumeSizeHistory); LoadHistory('FileMask', glsMaskHistory); LoadHistory('SearchText', glsSearchHistory, True); LoadHistory('SearchTextPath', glsSearchPathHistory); LoadHistory('ReplaceText', glsReplaceHistory); LoadHistory('ReplaceTextPath', glsReplacePathHistory); LoadHistory('CreateDirectories', glsCreateDirectoriesHistory, True); LoadHistory('RenameNameMask', glsRenameNameMaskHistory); LoadHistory('RenameExtMask', glsRenameExtMaskHistory); LoadHistory('SearchDirectories', glsSearchDirectories); LoadHistory('SearchExcludeFiles', glsSearchExcludeFiles); LoadHistory('SearchExcludeDirectories', glsSearchExcludeDirectories); end; Result:= True; finally History.Free; end; end; procedure SaveHistoryConfig; var Root: TXmlNode; History: TXmlConfig; procedure SaveHistory(const NodeName: String; HistoryList: TStrings; SaveObj: Boolean = False); var I: Integer; Node, SubNode: TXmlNode; begin Node := History.FindNode(Root, NodeName, True); History.ClearNode(Node); for I:= 0 to HistoryList.Count - 1 do begin SubNode := History.AddNode(Node, 'Item'); History.SetContent(SubNode, HistoryList[I]); if SaveObj then begin History.SetAttr(SubNode, 'Tag', UInt32(UIntPtr(HistoryList.Objects[I]))); end; if I >= cMaxStringItems then Break; end; end; begin History:= TXmlConfig.Create(gpCfgDir + 'history.xml'); try Root:= History.FindNode(History.RootNode, 'History', True); if gSaveDirHistory then SaveHistory('Navigation', glsDirHistory); if gSaveCmdLineHistory then SaveHistory('CommandLine', glsCmdLineHistory); if gSaveFileMaskHistory then SaveHistory('FileMask', glsMaskHistory); if gSaveVolumeSizeHistory then SaveHistory('VolumeSize', glsVolumeSizeHistory); if gSaveCreateDirectoriesHistory then begin SaveHistory('CreateDirectories', glsCreateDirectoriesHistory, True); end; if gSaveSearchReplaceHistory then begin SaveHistory('SearchText', glsSearchHistory, True); SaveHistory('SearchTextPath', glsSearchPathHistory); SaveHistory('ReplaceText', glsReplaceHistory); SaveHistory('ReplaceTextPath', glsReplacePathHistory); SaveHistory('RenameNameMask', glsRenameNameMaskHistory); SaveHistory('RenameExtMask', glsRenameExtMaskHistory); SaveHistory('SearchDirectories', glsSearchDirectories); SaveHistory('SearchExcludeFiles', glsSearchExcludeFiles); SaveHistory('SearchExcludeDirectories', glsSearchExcludeDirectories); end; History.Save; finally History.Free; end; end; function GetValidDateTimeFormat(const aFormat, ADefaultFormat: string): string; begin try SysUtils.FormatDateTime(aFormat, Now); Result := aFormat; except on EConvertError do Result := ADefaultFormat; end; end; procedure RegisterInitialization(InitProc: TProcedure); begin SetLength(FInitList, Length(FInitList) + 1); FInitList[High(FInitList)]:= InitProc; end; procedure LoadDefaultHotkeyBindings; var HMForm: THMForm; HMHotKey: THotkey; HMControl: THMControl; begin // Note: Increase hkVersion if you change default hotkeys list // Shortcuts that can conflict with default OS shortcuts for some controls // should be put only to Files Panel. // For a list of such possible shortcuts see THotKeyManager.IsShortcutConflictingWithOS. // If adding multiple shortcuts for the same command use: // AddIfNotExists([Shortcut1, Param1, Shortcut2, Param2, ...], Command); // // Shortcuts Ctrl+Alt+<letter> should not be added as the combinations may be // used to enter international characters on Windows (where Ctrl+Alt = AltGr). HMForm := HotMan.Forms.FindOrCreate('Main'); with HMForm.Hotkeys do begin if HotMan.Version < 58 then begin HMHotKey:= FindByCommand('cm_About'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['F1']) then begin Remove(HMHotKey); end; end; if HotMan.Version < 63 then begin HMHotKey:= FindByCommand('cm_View'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['F3']) then begin Remove(HMHotKey); end; end; AddIfNotExists(['F1'],[],'cm_HelpIndex'); AddIfNotExists(['F2','','', 'Shift+F6','',''],'cm_RenameOnly'); AddIfNotExists(['F3','','', 'Shift+F3','','cursor=1',''], 'cm_View'); AddIfNotExists(['F4'],[],'cm_Edit'); AddIfNotExists(['F5'],[],'cm_Copy'); AddIfNotExists(['F6'],[],'cm_Rename'); AddIfNotExists(['F7'],[],'cm_MakeDir'); AddIfNotExists(['F8','','', 'Shift+F8','','trashcan=reversesetting',''], 'cm_Delete'); AddIfNotExists(['F9'],[],'cm_RunTerm'); if HotMan.Version < 44 then begin HMHotKey:= FindByCommand('cm_ShowCmdLineHistory'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['Ctrl+7']) then begin Remove(HMHotKey); AddIfNotExists(['Alt+F8'],'cm_ShowCmdLineHistory',['Ctrl+Down'],[]); end; end; if HotMan.Version < 53 then begin HMHotKey:= Find(['Alt+`']); if Assigned(HMHotKey) and (HMHotKey.Command = 'cm_ActivateTabByIndex') then begin if HMHotKey.SameParams(['index=-1']) then HMHotKey.Shortcuts[0]:= 'Alt+0'; end; end; AddIfNotExists(['Alt+F8','','', 'Ctrl+Down','',''], 'cm_ShowCmdLineHistory'); AddIfNotExists(['Ctrl+B'],[],'cm_FlatView'); AddIfNotExists(['Ctrl+D'],[],'cm_DirHotList'); AddIfNotExists(['Ctrl+F'],[],'cm_QuickFilter'); AddIfNotExists(['Ctrl+H'],[],'cm_DirHistory'); AddIfNotExists(['Alt+Down'],'cm_DirHistory',['Ctrl+H'],[]); //Historic backward support reason... AddIfNotExists(['Ctrl+L'],[],'cm_CalculateSpace'); AddIfNotExists(['Ctrl+M'],[],'cm_MultiRename'); AddIfNotExists(['Ctrl+O'],[],'cm_ToggleFullscreenConsole'); AddIfNotExists(['Ctrl+P'],[],'cm_AddPathToCmdLine'); AddIfNotExists(['Ctrl+Q'],[],'cm_QuickView'); AddIfNotExists(['Ctrl+S'],[],'cm_QuickSearch'); AddIfNotExists(['Ctrl+R'],[],'cm_Refresh'); AddIfNotExists(['Ctrl+T'],[],'cm_NewTab'); AddIfNotExists(['Ctrl+U'],[],'cm_Exchange'); AddIfNotExists(['Ctrl+W'],[],'cm_CloseTab'); AddIfNotExists(['Ctrl+F1'],[],'cm_BriefView'); AddIfNotExists(['Ctrl+F2'],[],'cm_ColumnsView'); AddIfNotExists(['Ctrl+F3'],[],'cm_SortByName'); AddIfNotExists(['Ctrl+F4'],[],'cm_SortByExt'); AddIfNotExists(['Ctrl+F5'],[],'cm_SortByDate'); AddIfNotExists(['Ctrl+F6'],[],'cm_SortBySize'); AddIfNotExists(['Ctrl+Enter'],[],'cm_AddFilenameToCmdLine'); AddIfNotExists(['Ctrl+PgDn'],[],'cm_OpenArchive'); AddIfNotExists(['Ctrl+PgUp'],[],'cm_ChangeDirToParent'); AddIfNotExists(['Ctrl+Alt+Enter'],[],'cm_ShellExecute'); AddIfNotExists(['Ctrl+Shift+A'],[],'cm_ShowTabsList'); AddIfNotExists(['Ctrl+Shift+B'],[],'cm_FlatViewSel'); AddIfNotExists(['Ctrl+Shift+C'],[],'cm_CopyFullNamesToClip'); AddIfNotExists(['Ctrl+Shift+D'],[],'cm_ConfigDirHotList'); AddIfNotExists(['Ctrl+Shift+H'],[],'cm_HorizontalFilePanels'); AddIfNotExists(['Ctrl+Shift+X'],[],'cm_CopyNamesToClip'); AddIfNotExists(['Ctrl+Shift+F1'],[],'cm_ThumbnailsView'); AddIfNotExists(['Ctrl+Shift+Enter'],[],'cm_AddPathAndFilenameToCmdLine'); AddIfNotExists(['Ctrl+Shift+Tab'],[],'cm_PrevTab'); AddIfNotExists(['Ctrl+Shift+F7'],[],'cm_AddNewSearch'); AddIfNotExists(['Ctrl+Shift+F8'],[],'cm_TreeView'); AddIfNotExists(['Ctrl+Tab'],[],'cm_NextTab'); AddIfNotExists(['Ctrl+Up'],[],'cm_OpenDirInNewTab'); AddIfNotExists(['Ctrl+\'],[],'cm_ChangeDirToRoot'); AddIfNotExists(['Ctrl+.'],[],'cm_ShowSysFiles'); AddIfNotExists(['Shift+F2'],[],'cm_FocusCmdLine'); AddIfNotExists(['Shift+F4'],[],'cm_EditNew'); AddIfNotExists(['Shift+F5'],[],'cm_CopySamePanel'); AddIfNotExists(['Shift+F10'],[],'cm_ContextMenu'); AddIfNotExists(['Shift+F12'],[],'cm_DoAnyCmCommand'); AddIfNotExists(['Shift+Tab'],[],'cm_FocusTreeView'); AddIfNotExists(['Alt+V'],[],'cm_OperationsViewer'); AddIfNotExists(['Alt+X'],[],'cm_Exit'); AddIfNotExists(['Alt+Z'],[],'cm_TargetEqualSource'); AddIfNotExists(['Alt+F1'],[],'cm_LeftOpenDrives'); AddIfNotExists(['Alt+F2'],[],'cm_RightOpenDrives'); AddIfNotExists(['Alt+F5'],[],'cm_PackFiles'); AddIfNotExists(['Alt+F7'],[],'cm_Search'); AddIfNotExists(['Alt+F9'],[],'cm_ExtractFiles'); AddIfNotExists(['Alt+Del'],[],'cm_Wipe'); AddIfNotExists(['Alt+Enter'],[],'cm_FileProperties'); AddIfNotExists(['Alt+Left'],[],'cm_ViewHistoryPrev'); AddIfNotExists(['Alt+Right'],[],'cm_ViewHistoryNext'); AddIfNotExists(['Alt+Shift+Enter'],[],'cm_CountDirContent'); AddIfNotExists(['Alt+Shift+F9'],[],'cm_TestArchive'); AddIfNotExists([ 'Alt+1','','index=1','', 'Alt+2','','index=2','', 'Alt+3','','index=3','', 'Alt+4','','index=4','', 'Alt+5','','index=5','', 'Alt+6','','index=6','', 'Alt+7','','index=7','', 'Alt+8','','index=8','', 'Alt+9','','index=9','', 'Alt+0','','index=-1',''], 'cm_ActivateTabByIndex'); AddIfNotExists([ 'Ctrl+1','','index=1','', 'Ctrl+2','','index=2','', 'Ctrl+3','','index=3','', 'Ctrl+4','','index=4','', 'Ctrl+5','','index=5','', 'Ctrl+6','','index=6','', 'Ctrl+7','','index=7','', 'Ctrl+8','','index=8','', 'Ctrl+9','','index=9',''], 'cm_OpenDriveByIndex'); if HotMan.Version < 38 then begin HMHotKey:= FindByCommand('cm_EditComment'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['Ctrl+Z']) then Remove(HMHotKey); end; end; HMControl := HMForm.Controls.FindOrCreate('Files Panel'); with HMControl.Hotkeys do begin AddIfNotExists(['Del' ,'','', 'Shift+Del','','trashcan=reversesetting',''], 'cm_Delete'); AddIfNotExists(['Ctrl+A' ,'','', 'Ctrl+Num+','',''],'cm_MarkMarkAll', ['Ctrl+A'], []); AddIfNotExists(['Num+'],[],'cm_MarkPlus'); AddIfNotExists(['Shift+Num+'],[],'cm_MarkCurrentExtension'); AddIfNotExists(['Ctrl+Num-'],[],'cm_MarkUnmarkAll'); AddIfNotExists(['Num-'],[],'cm_MarkMinus'); AddIfNotExists(['Shift+Num-'],[],'cm_UnmarkCurrentExtension'); AddIfNotExists(['Num*'],[],'cm_MarkInvert'); AddIfNotExists(['Ctrl+Z'],[],'cm_EditComment'); AddIfNotExists(['Ctrl+Shift+Home'],[],'cm_ChangeDirToHome'); AddIfNotExists(['Ctrl+Left'],[],'cm_TransferLeft'); AddIfNotExists(['Ctrl+Right'],[],'cm_TransferRight'); if HotMan.Version < 46 then begin HMHotKey:= FindByCommand('cm_NextGroup'); if Assigned(HMHotKey) then Remove(HMHotKey); end; AddIfNotExists(VK_C, [ssModifier], 'cm_CopyToClipboard'); AddIfNotExists(VK_V, [ssModifier], 'cm_PasteFromClipboard'); AddIfNotExists(VK_X, [ssModifier], 'cm_CutToClipboard'); end; HMForm := HotMan.Forms.FindOrCreate('Viewer'); with HMForm.Hotkeys do begin AddIfNotExists(['F1'],[],'cm_About'); AddIfNotExists(['F2'],[],'cm_Reload'); if HotMan.Version < 60 then begin HMHotKey:= Find(['Right']); if Assigned(HMHotKey) and (HMHotKey.Command = 'cm_LoadNextFile') then begin HMHotKey.Shortcuts[0]:= 'Alt+Right'; end; HMHotKey:= Find(['Left']); if Assigned(HMHotKey) and (HMHotKey.Command = 'cm_LoadPrevFile') then begin HMHotKey.Shortcuts[0]:= 'Alt+Left'; end; end; AddIfNotExists(['N' ,'','', 'Alt+Right','',''],'cm_LoadNextFile'); AddIfNotExists(['P' ,'','', 'Alt+Left','',''],'cm_LoadPrevFile'); if HotMan.Version < 54 then begin HMHotKey:= FindByCommand('cm_ShowAsWrapText'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['4']) then Remove(HMHotKey); end; if HotMan.Version < 56 then begin HMHotKey:= FindByCommand('cm_Find'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['F']) then Remove(HMHotKey); end; AddIfNotExists(['1'],[],'cm_ShowAsText'); AddIfNotExists(['2'],[],'cm_ShowAsBin'); AddIfNotExists(['3'],[],'cm_ShowAsHex'); AddIfNotExists(['4'],[],'cm_ShowAsDec'); AddIfNotExists(['5'],[],'cm_ShowAsBook'); AddIfNotExists(['6'],[],'cm_ShowGraphics'); AddIfNotExists(['7'],[],'cm_ShowPlugins'); AddIfNotExists(['8'],[],'cm_ShowOffice'); AddIfNotExists(['9'],[],'cm_ShowCode'); AddIfNotExists(['C'],[],'cm_ImageCenter'); AddIfNotExists(['F'],[],'cm_StretchImage'); AddIfNotExists(['L'],[],'cm_StretchOnlyLarge'); AddIfNotExists(['W'],[],'cm_WrapText'); AddIfNotExists(['F6'],[],'cm_ShowCaret'); AddIfNotExists(['Q' ,'','', 'Esc','',''],'cm_ExitViewer'); AddIfNotExists([SmkcSuper + 'F' ,'','', 'F7' ,'',''],'cm_Find'); AddIfNotExists(['F3'],[],'cm_FindNext'); AddIfNotExists(['Shift+F3'],[],'cm_FindPrev'); AddIfNotExists(['`'],[],'cm_Preview'); // til'da on preview mode AddIfNotExists(['Num+'],[],'cm_ZoomIn'); AddIfNotExists(['Num-'],[],'cm_ZoomOut'); AddIfNotExists(['Alt+Enter'],[],'cm_Fullscreen'); //AddIfNotExists(['Up'],[],'cm_Rotate270'); // how at once add this keys only to Image control? //AddIfNotExists(['Down'],[],'cm_Rotate90'); AddIfNotExists(VK_P, [ssModifier], 'cm_Print'); AddIfNotExists(VK_G, [ssModifier], 'cm_GotoLine'); AddIfNotExists(VK_A, [ssModifier], 'cm_SelectAll'); AddIfNotExists(VK_C, [ssModifier], 'cm_CopyToClipboard'); AddIfNotExists(VK_Z, [ssModifier], 'cm_Undo'); AddIfNotExists(['A','','ANSI','', 'S','','OEM','', 'Z','','UTF-8','', 'X','','UTF-16LE',''],'cm_ChangeEncoding'); end; HMForm := HotMan.Forms.FindOrCreate('Differ'); with HMForm.Hotkeys do begin AddIfNotExists(['Ctrl+R'],[],'cm_Reload'); AddIfNotExists([SmkcSuper + 'F' ,'','', 'F7' ,'',''],'cm_Find'); AddIfNotExists(['F3'],[],'cm_FindNext'); AddIfNotExists(['Shift+F3'],[],'cm_FindPrev'); AddIfNotExists(VK_G, [ssModifier], 'cm_GotoLine'); AddIfNotExists(['Alt+Down'],[],'cm_NextDifference'); AddIfNotExists(['Alt+Up'],[],'cm_PrevDifference'); AddIfNotExists(['Alt+Home'],[],'cm_FirstDifference'); AddIfNotExists(['Alt+End'],[],'cm_LastDifference'); AddIfNotExists(['Alt+X'],[],'cm_Exit'); AddIfNotExists(['Alt+Left'],[],'cm_CopyRightToLeft'); AddIfNotExists(['Alt+Right'],[],'cm_CopyLeftToRight'); end; HMForm := HotMan.Forms.FindOrCreate('Confirmation'); with HMForm.Hotkeys do begin AddIfNotExists(['F2'], [],'cm_AddToQueue'); end; HMForm := HotMan.Forms.FindOrCreate('Copy/Move Dialog'); with HMForm.Hotkeys do begin AddIfNotExists(['F2'], [],'cm_AddToQueue'); AddIfNotExists(['F5', '', '', 'F6', '', ''], 'cm_ToggleSelectionInName'); end; HMForm := HotMan.Forms.FindOrCreate('Edit Comment Dialog'); with HMForm.Hotkeys do begin AddIfNotExists(['F2'],[],'cm_SaveDescription'); end; HMForm := HotMan.Forms.FindOrCreate('Synchronize Directories'); with HMForm.Hotkeys do begin AddIfNotExists(VK_M, [ssModifier], 'cm_SelectClear'); AddIfNotExists(VK_D, [ssModifier], 'cm_SelectCopyDefault'); AddIfNotExists(VK_W, [ssModifier], 'cm_SelectCopyReverse'); AddIfNotExists(VK_L, [ssModifier], 'cm_SelectCopyLeftToRight'); AddIfNotExists(VK_R, [ssModifier], 'cm_SelectCopyRightToLeft'); end; HMForm := HotMan.Forms.FindOrCreate('Editor'); with HMForm.Hotkeys do begin if HotMan.Version < 45 then begin HMHotKey:= FindByCommand('cm_EditFind'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['F7']) then Remove(HMHotKey); HMHotKey:= FindByCommand('cm_FileSave'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['F2']) then Remove(HMHotKey); HMHotKey:= FindByCommand('cm_FileExit'); if Assigned(HMHotKey) and HMHotKey.SameShortcuts(['Esc']) then Remove(HMHotKey); end; AddIfNotExists([SmkcSuper + 'F' ,'','', 'F7' ,'',''],'cm_EditFind'); AddIfNotExists(['F2' ,'','', SmkcSuper + 'S' ,'',''],'cm_FileSave'); AddIfNotExists(['F3'],[],'cm_EditFindNext'); AddIfNotExists(['Shift+F3'],[],'cm_EditFindPrevious'); AddIfNotExists(['Alt+X', '', '', //Let is be first since by legacy what we get used to see in main menu as shortcut was "Alt+X". 'Esc', '', ''], 'cm_FileExit'); AddIfNotExists(VK_X, [ssModifier], 'cm_EditCut'); AddIfNotExists(VK_N, [ssModifier], 'cm_FileNew'); AddIfNotExists(VK_O, [ssModifier], 'cm_FileOpen'); AddIfNotExists(VK_R, [ssModifier], 'cm_EditRplc'); AddIfNotExists(VK_C, [ssModifier], 'cm_EditCopy'); AddIfNotExists(VK_Z, [ssModifier], 'cm_EditUndo'); AddIfNotExists(VK_V, [ssModifier], 'cm_EditPaste'); AddIfNotExists(VK_A, [ssModifier], 'cm_EditSelectAll'); AddIfNotExists(VK_Z, [ssModifier, ssShift], 'cm_EditRedo'); AddIfNotExists(VK_G, [ssModifier], 'cm_EditGotoLine'); end; HMForm := HotMan.Forms.FindOrCreate('Find Files'); with HMForm.Hotkeys do begin AddIfNotExists(['F3'],[],'cm_View'); AddIfNotExists(['F4'],[],'cm_Edit'); AddIfNotExists(['F7'],[],'cm_IntelliFocus'); AddIfNotExists(['F9'],[],'cm_Start'); AddIfNotExists(['Esc'],[],'cm_CancelClose'); AddIfNotExists(['Ctrl+N'],[],'cm_NewSearch'); AddIfNotExists(['Ctrl+Shift+N'],[],'cm_NewSearchClearFilters'); AddIfNotExists(['Ctrl+L'],[],'cm_LastSearch'); AddIfNotExists(['Alt+1','','', 'Alt+F7','',''],'cm_PageStandard'); AddIfNotExists(['Alt+2'],[],'cm_PageAdvanced'); AddIfNotExists(['Alt+3'],[],'cm_PagePlugins'); AddIfNotExists(['Alt+4'],[],'cm_PageLoadSave'); AddIfNotExists(['Alt+5'],[],'cm_PageResults'); AddIfNotExists(['Alt+F4','',''],'cm_FreeFromMem'); AddIfNotExists(VK_TAB, [ssModifier], 'cm_PageNext'); AddIfNotExists(VK_TAB, [ssModifier, ssShift], 'cm_PagePrev'); end; HMForm := HotMan.Forms.FindOrCreate(HotkeysCategoryMultiRename); with HMForm.Hotkeys do begin AddIfNotExists(['Ctrl+R'],[],'cm_ResetAll'); AddIfNotExists(['Ctrl+I'],[],'cm_InvokeEditor'); AddIfNotExists(['F3'],[],'cm_LoadNamesFromFile'); AddIfNotExists(['F4'],[],'cm_EditNames'); AddIfNotExists(['Shift+F4'],[],'cm_EditNewNames'); AddIfNotExists(['F10'],[],'cm_Config'); AddIfNotExists(['F9'],[],'cm_Rename'); AddIfNotExists(['Esc'],[],'cm_Close'); AddIfNotExists(['Shift+F2'],[],'cm_ShowPresetsMenu'); AddIfNotExists(['F2'],[],'cm_DropDownPresetList'); AddIfNotExists(['Alt+0'],[],'cm_LoadLastPreset'); AddIfNotExists(['Alt+1'],[],'cm_LoadPreset1'); AddIfNotExists(['Alt+2'],[],'cm_LoadPreset2'); AddIfNotExists(['Alt+3'],[],'cm_LoadPreset3'); AddIfNotExists(['Alt+4'],[],'cm_LoadPreset4'); AddIfNotExists(['Alt+5'],[],'cm_LoadPreset5'); AddIfNotExists(['Alt+6'],[],'cm_LoadPreset6'); AddIfNotExists(['Alt+7'],[],'cm_LoadPreset7'); AddIfNotExists(['Alt+8'],[],'cm_LoadPreset8'); AddIfNotExists(['Alt+9'],[],'cm_LoadPreset9'); AddIfNotExists(['Ctrl+S'],[],'cm_SavePreset'); AddIfNotExists(['F12'],[],'cm_SavePresetAs'); AddIfNotExists(['Shift+F6'],[],'cm_RenamePreset'); AddIfNotExists(['Ctrl+D'],[],'cm_DeletePreset'); AddIfNotExists(['Ctrl+Shift+S'],[],'cm_SortPresets'); AddIfNotExists(['Ctrl+F2'],[],'cm_AnyNameMask'); AddIfNotExists(['Ctrl+F3'],[],'cm_NameNameMask'); AddIfNotExists(['Ctrl+F4'],[],'cm_ExtNameMask'); AddIfNotExists(['Ctrl+F7'],[],'cm_CtrNameMask'); AddIfNotExists(['Ctrl+F5'],[],'cm_DateNameMask'); AddIfNotExists(['Ctrl+F6'],[],'cm_TimeNameMask'); AddIfNotExists(['Ctrl+F1'],[],'cm_PlgnNameMask'); AddIfNotExists(['Ctrl+Shift+F2'],[],'cm_AnyExtMask'); AddIfNotExists(['Ctrl+Shift+F3'],[],'cm_NameExtMask'); AddIfNotExists(['Ctrl+Shift+F4'],[],'cm_ExtExtMask'); AddIfNotExists(['Ctrl+Shift+F7'],[],'cm_CtrExtMask'); AddIfNotExists(['Ctrl+Shift+F5'],[],'cm_DateExtMask'); AddIfNotExists(['Ctrl+Shift+F6'],[],'cm_TimeExtMask'); AddIfNotExists(['Ctrl+Shift+F1'],[],'cm_PlgnExtMask'); end; if not mbFileExists(gpCfgDir + gNameSCFile) then gNameSCFile := 'shortcuts.scf'; HotMan.Save(gpCfgDir + gNameSCFile); end; function InitPropStorage(Owner: TComponent): TIniPropStorageEx; var sWidth, sHeight: String; begin Result:= TIniPropStorageEx.Create(Owner); Result.IniFileName:= gpCfgDir + 'session.ini'; if Owner is TCustomForm then with Owner as TCustomForm do begin if (Monitor = nil) then Result.IniSection:= ClassName else begin sWidth:= IntToStr(Monitor.Width); sHeight:= IntToStr(Monitor.Height); Result.IniSection:= ClassName + '(' + sWidth + 'x' + sHeight + ')'; end; end; end; procedure FontToFontOptions(Font: TFont; var Options: TDCFontOptions); begin with Options do begin Name := Font.Name; Size := Font.Size; Style := Font.Style; Quality := Font.Quality; end; end; procedure FontOptionsToFont(Options: TDCFontOptions; Font: TFont); begin with Options do begin Font.Name := Name; Font.Size := Size; Font.Style := Style; Font.Quality := Quality; end; end; procedure OldKeysToNew(ActionEnabled: Boolean; ShiftState: TShiftState; Action: TKeyTypingAction); var Modifier: TKeyTypingModifier; begin if ActionEnabled then begin for Modifier in TKeyTypingModifier do begin if TKeyTypingModifierToShift[Modifier] = ShiftState then gKeyTyping[Modifier] := Action else if gKeyTyping[Modifier] = Action then gKeyTyping[Modifier] := ktaNone; end; end else begin for Modifier in TKeyTypingModifier do begin if gKeyTyping[Modifier] = Action then begin gKeyTyping[Modifier] := ktaNone; Break; end; end; end; end; function LoadStringsFromFile(var list: TStringListEx; const sFileName:String; MaxStrings: Integer = 0): Boolean; var i:Integer; begin Assert(list <> nil,'LoadStringsFromFile: list=nil'); list.Clear; Result:=False; if mbFileExists(sFileName) then begin list.LoadFromFile(sFileName); if MaxStrings > 0 then begin for i:=list.Count-1 downto 0 do if i>MaxStrings then list.Delete(i) else Break; end; Result:=True; end; end; procedure CopySettingsFiles; begin { Copy default configuration files if needed } // pixmaps file if not mbFileExists(gpCfgDir + 'pixmaps.txt') then begin CopyFile(gpExePath + 'default' + PathDelim + 'pixmaps.txt', gpCfgDir + 'pixmaps.txt'); end; // multiarc configuration file if (mbFileSize(gpCfgDir + sMULTIARC_FILENAME) = 0) then begin CopyFile(gpExePath + 'default' + PathDelim + sMULTIARC_FILENAME, gpCfgDir + sMULTIARC_FILENAME); end; end; procedure CreateGlobs; begin gExts := TExts.Create; gColorExt := TColorExt.Create; gFileInfoToolTip := TFileInfoToolTip.Create; gDirectoryHotlist := TDirectoryHotlist.Create; gFavoriteTabsList := TFavoriteTabsList.Create; glsDirHistory := TStringListEx.Create; glsCmdLineHistory := TStringListEx.Create; glsVolumeSizeHistory := TStringListEx.Create; glsMaskHistory := TStringListEx.Create; glsSearchHistory := TStringListEx.Create; glsSearchPathHistory := TStringListEx.Create; glsReplaceHistory := TStringListEx.Create; glsReplacePathHistory := TStringListEx.Create; glsCreateDirectoriesHistory := TStringListEx.Create; glsRenameNameMaskHistory := TStringListEx.Create; glsRenameExtMaskHistory := TStringListEx.Create; glsIgnoreList := TStringListEx.Create; glsSearchDirectories := TStringList.Create; glsSearchExcludeFiles:= TStringList.Create; glsSearchExcludeDirectories:= TStringList.Create; gSearchTemplateList := TSearchTemplateList.Create; gDSXPlugins := TDSXModuleList.Create; gWCXPlugins := TWCXModuleList.Create; gWDXPlugins := TWDXModuleList.Create; gWFXPlugins := TWFXModuleList.Create; gWLXPlugins := TWLXModuleList.Create; gMultiArcList := TMultiArcList.Create; gColors := TColorThemes.Create; gStyles := TJsonConfig.Create; ColSet := TPanelColumnsList.Create; HotMan := THotKeyManager.Create; end; procedure DestroyGlobs; begin FreeAndNil(gColorExt); FreeAndNil(gFileInfoToolTip); FreeAndNil(glsDirHistory); FreeAndNil(glsCmdLineHistory); FreeAndNil(glsVolumeSizeHistory); FreeAndNil(gSpecialDirList); FreeAndNil(gDirectoryHotlist); FreeAndNil(gFavoriteTabsList); FreeAndNil(glsMaskHistory); FreeAndNil(glsSearchHistory); FreeAndNil(glsSearchPathHistory); FreeAndNil(glsReplaceHistory); FreeAndNil(glsReplacePathHistory); FreeAndNil(glsCreateDirectoriesHistory); FreeAndNil(glsRenameNameMaskHistory); FreeAndNil(glsRenameExtMaskHistory); FreeAndNil(glsIgnoreList); FreeAndNil(glsSearchDirectories); FreeAndNil(glsSearchExcludeFiles); FreeAndNil(glsSearchExcludeDirectories); FreeAndNil(gExts); FreeAndNil(gConfig); FreeAndNil(gSearchTemplateList); FreeAndNil(gDSXPlugins); FreeAndNil(gWCXPlugins); FreeAndNil(gWDXPlugins); FreeAndNil(gWFXPlugins); FreeAndNil(gWLXPlugins); FreeAndNil(gMultiArcList); FreeAndNil(gColors); FreeAndNil(gStyles); FreeAndNil(ColSet); FreeAndNil(HotMan); FreeAndNil(gHighlighters); end; {$IFDEF MSWINDOWS} function GetPathNameIfItMatch(SpecialConstant:integer; FilenameSearched:string):string; var MaybePath:string; FilePath: array [0..Pred(MAX_PATH)] of WideChar = ''; begin result:=''; FillChar(FilePath, MAX_PATH, 0); SHGetSpecialFolderPathW(0, @FilePath[0], SpecialConstant, FALSE); if FilePath<>'' then begin MaybePath:=IncludeTrailingPathDelimiter(UTF16ToUTF8(WideString(FilePath))); if mbFileExists(MaybePath+FilenameSearched) then result:=MaybePath+FilenameSearched; end; end; {$ENDIF} procedure SetDefaultConfigGlobs; procedure SetDefaultExternalTool(var ExternalToolOptions: TExternalToolOptions); begin with ExternalToolOptions do begin Enabled := False; Path := ''; Parameters := ''; RunInTerminal := False; KeepTerminalOpen := False; end; end; var iIndexContextMode:integer; begin { Language page } gPOFileName := ''; { Behaviours page } gRunInTermStayOpenCmd := RunInTermStayOpenCmd; gRunInTermStayOpenParams := RunInTermStayOpenParams; gRunInTermCloseCmd := RunInTermCloseCmd; gRunInTermCloseParams := RunInTermCloseParams; gRunTermCmd := RunTermCmd; gRunTermParams := RunTermParams; gOnlyOneAppInstance := False; gLynxLike := True; gSortCaseSensitivity := cstNotSensitive; gSortNatural := False; gSortSpecial := False; gSortFolderMode := sfmSortLikeFileShowFirst; gNewFilesPosition := nfpSortedPosition; gUpdatedFilesPosition := ufpNoChange; gFileSizeFormat := fsfFloat; gHeaderSizeFormat := fsfFloat; gFooterSizeFormat := fsfFloat; gOperationSizeFormat := fsfFloat; gFileSizeDigits := 1; gHeaderDigits := 1; gFooterDigits := 1; gOperationSizeDigits := 1; //NOTES: We're intentionnaly not setting our default memory immediately because language file has not been loaded yet. // We'll set them *after* after language has been loaded since we'll know the correct default to use. gConfirmQuit := False; gMinimizeToTray := False; gAlwaysShowTrayIcon := False; gMouseSelectionEnabled := True; gMouseSelectionButton := 0; // Left gMouseSingleClickStart := 0; gMouseSelectionIconClick := 0; gScrollMode := smLineByLine; gWheelScrollLines:= Mouse.WheelScrollLines; gAutoFillColumns := False; gAutoSizeColumn := 1; gColumnsLongInStatus := False; gColumnsAutoSaveWidth := True; gColumnsTitleStyle := tsNative; gCustomColumnsChangeAllColumns := False; gDateTimeFormat := DefaultDateTimeFormat; gColumnsTitleLikeValues := False; gCutTextToColWidth := True; gExtendCellWidth := False; gShowSystemFiles := False; // Under Mac OS X loading file list in separate thread are very very slow // so disable and hide this option under Mac OS X Carbon gListFilesInThread := {$IFDEF LCLCARBON}False{$ELSE}True{$ENDIF}; gLoadIconsSeparately := True; gDelayLoadingTabs := True; gHighlightUpdatedFiles := True; gDriveBlackList := ''; gDriveBlackListUnmounted := False; { File views page } gExtraLineSpan := 2; gFolderPrefix := '['; gFolderPostfix := ']'; gRenameConfirmMouse := False; { Brief view page } gBriefViewFixedCount := 2; gBriefViewFixedWidth := 100; gBriefViewMode := bvmAutoSize; gBriefViewFileExtAligned := False; { Tools page } SetDefaultExternalTool(gExternalTools[etViewer]); SetDefaultExternalTool(gExternalTools[etEditor]); SetDefaultExternalTool(gExternalTools[etDiffer]); { Differ related} gResultingFramePositionAfterCompare := rfpacActiveOnLeft; { Fonts page } gFonts[dcfMain].Name := 'default'; gFonts[dcfMain].Size := 10; gFonts[dcfMain].Style := [fsBold]; gFonts[dcfMain].Quality := fqDefault; gFonts[dcfMain].MinValue := 6; gFonts[dcfMain].MaxValue := 200; gFonts[dcfEditor].Name := MonoSpaceFont; gFonts[dcfEditor].Size := 14; gFonts[dcfEditor].Style := []; gFonts[dcfEditor].Quality := fqDefault; gFonts[dcfEditor].MinValue := 6; gFonts[dcfEditor].MaxValue := 200; gFonts[dcfViewer].Name := MonoSpaceFont; gFonts[dcfViewer].Size := 14; gFonts[dcfViewer].Style := []; gFonts[dcfViewer].Quality := fqDefault; gFonts[dcfViewer].MinValue := 6; gFonts[dcfViewer].MaxValue := 200; gFonts[dcfViewerBook].Name := 'default'; gFonts[dcfViewerBook].Size := 16; gFonts[dcfViewerBook].Style := [fsBold]; gFonts[dcfViewerBook].Quality := fqDefault; gFonts[dcfViewerBook].MinValue := 6; gFonts[dcfViewerBook].MaxValue := 200; gFonts[dcfLog].Name := MonoSpaceFont; gFonts[dcfLog].Size := 12; gFonts[dcfLog].Style := []; gFonts[dcfLog].Quality := fqDefault; gFonts[dcfLog].MinValue := 6; gFonts[dcfLog].MaxValue := 200; gFonts[dcfConsole].Name := MonoSpaceFont; gFonts[dcfConsole].Size := 12; gFonts[dcfConsole].Style := []; gFonts[dcfConsole].Quality := fqDefault; gFonts[dcfConsole].MinValue := 6; gFonts[dcfConsole].MaxValue := 200; gFonts[dcfPathEdit].Name := 'default'; gFonts[dcfPathEdit].Size := 10; gFonts[dcfPathEdit].Style := []; gFonts[dcfPathEdit].Quality := fqDefault; gFonts[dcfPathEdit].MinValue := 6; gFonts[dcfPathEdit].MaxValue := 200; gFonts[dcfFunctionButtons].Name := 'default'; gFonts[dcfFunctionButtons].Size := 10; gFonts[dcfFunctionButtons].Style := []; gFonts[dcfFunctionButtons].Quality := fqDefault; gFonts[dcfFunctionButtons].MinValue := 6; gFonts[dcfFunctionButtons].MaxValue := 200; gFonts[dcfSearchResults].Name := 'default'; gFonts[dcfSearchResults].Size := 10; gFonts[dcfSearchResults].Style := []; gFonts[dcfSearchResults].Quality := fqDefault; gFonts[dcfSearchResults].MinValue := 6; gFonts[dcfSearchResults].MaxValue := 200; gFonts[dcfTreeViewMenu].Name := 'default'; gFonts[dcfTreeViewMenu].Size := 10; gFonts[dcfTreeViewMenu].Style := []; gFonts[dcfTreeViewMenu].Quality := fqDefault; gFonts[dcfTreeViewMenu].MinValue := 6; gFonts[dcfTreeViewMenu].MaxValue := 200; gFonts[dcfStatusBar].Name := 'default'; gFonts[dcfStatusBar].Size := 0; gFonts[dcfStatusBar].Style := []; gFonts[dcfStatusBar].Quality := fqDefault; gFonts[dcfStatusBar].MinValue := 6; gFonts[dcfStatusBar].MaxValue := 200; { Colors page } gUseCursorBorder := False; gUseFrameCursor := False; gUseInvertedSelection := False; gUseInactiveSelColor := False; gAllowOverColor := True; gBorderFrameWidth:=1; gInactivePanelBrightness := 100; // Full brightness gIndUseGradient := True; { Layout page } gMainMenu := True; gButtonBar := True; gToolBarFlat := True; gMiddleToolBar := False; gToolBarButtonSize := 24; gToolBarIconSize := 16; gToolBarShowCaptions := False; gToolbarReportErrorWithCommands := FALSE; gMiddleToolBarFlat := True; gMiddleToolBarButtonSize := 24; gMiddleToolBarIconSize := 16; gMiddleToolBarShowCaptions := False; gMiddleToolbarReportErrorWithCommands := FALSE; gToolbarFilenameStyle := pfsAbsolutePath; gToolbarPathToBeRelativeTo := EnvVarCommanderPath; gToolbarPathModifierElements := []; gDriveBar1 := True; gDriveBar2 := True; gDriveBarFlat := True; gDrivesListButton := True; gDirectoryTabs := True; gCurDir := True; gTabHeader := True; gStatusBar := True; gCmdLine := True; gLogWindow := False; gTermWindow := False; gKeyButtons := True; gInterfaceFlat := True; gDriveInd := False; gDriveFreeSpace := True; gProgInMenuBar := False; gPanelOfOp := True; gShortFormatDriveInfo := True; gHorizontalFilePanels := False; gUpperCaseDriveLetter := False; gShowColonAfterDrive := False; gDrivesListButtonOptions := [dlbShowLabel, dlbShowFileSystem, dlbShowFreeSpace]; gSeparateTree := False; { Keys page } gKeyTyping[ktmNone] := ktaQuickSearch; gKeyTyping[ktmAlt] := ktaNone; gKeyTyping[ktmCtrlAlt] := ktaQuickFilter; { File operations page } gLongNameAlert := True; gCopyBlockSize := 524288; gHashBlockSize := 8388608; gUseMmapInSearch := False; gPartialNameSearch := True; gInitiallyClearFileMask := True; gNewSearchClearFiltersAction := fonsKeep; gShowMenuBarInFindFiles := True; gWipePassNumber := 1; gDropReadOnlyFlag := False; gProcessComments := False; gRenameSelOnlyName := False; gShowCopyTabSelectPanel := False; gUseTrash := True; gSkipFileOpError := False; gTypeOfDuplicatedRename := drLegacyWithCopy; gDefaultDropEffect:= True; gShowDialogOnDragDrop := True; gDragAndDropDesiredTextFormat[DropTextRichText_Index].Name:='Richtext format'; gDragAndDropDesiredTextFormat[DropTextRichText_Index].DesireLevel:=0; gDragAndDropDesiredTextFormat[DropTextHtml_Index].Name:='HTML format'; gDragAndDropDesiredTextFormat[DropTextHtml_Index].DesireLevel:=1; gDragAndDropDesiredTextFormat[DropTextUnicode_Index].Name:='Unicode format'; gDragAndDropDesiredTextFormat[DropTextUnicode_Index].DesireLevel:=2; gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].Name:='Simple text format'; gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].DesireLevel:=3; gDragAndDropAskFormatEachTime := False; gDragAndDropTextAutoFilename := False; gDragAndDropSaveUnicodeTextInUFT8 := True; gNtfsHourTimeDelay := False; gAutoExtractOpenMask := EmptyStr; gFileOperationsProgressKind := fopkSeparateWindow; gFileOperationsConfirmations := [focCopy, focMove, focDelete, focDeleteToTrash]; gFileOperationDuration := -1; { Multi-Rename } gMulRenShowMenuBarOnTop := True; gMulRenInvalidCharReplacement := '.'; gMulRenLaunchBehavior := mrlbLastMaskUnderLastOne; gMulRenExitModifiedPreset := mrempIgnoreSaveLast; gMulRenSaveRenamingLog := mrsrlPerPreset; gMulRenLogFilename := EnvVarConfigPath + PathDelim + 'multirename.log'; gMultRenDailyIndividualDirLog := True; gMulRenFilenameWithFullPathInLog:= False; gMulRenPathRangeSeparator := ' - '; // Operations options gOperationOptionSymLinks := fsooslNone; gOperationOptionCorrectLinks := False; gOperationOptionCopyOnWrite := fsoogNo; gOperationOptionFileExists := fsoofeNone; gOperationOptionDirectoryExists := fsoodeNone; gOperationOptionSetPropertyError := fsoospeNone; gOperationOptionReserveSpace := True; gOperationOptionCheckFreeSpace := True; gOperationOptionCopyAttributes := True; gOperationOptionCopyXattributes := True; gOperationOptionCopyTime := True; gOperationOptionVerify := False; gOperationOptionCopyOwnership := False; gOperationOptionCopyPermissions := False; gOperationOptionExcludeEmptyDirectories := True; // Extract gExtractOverwrite := False; { Tabs page } gDirTabOptions := [tb_always_visible, tb_confirm_close_all, tb_show_asterisk_for_locked, tb_activate_panel_on_click, tb_close_on_doubleclick, tb_reusing_tab_when_possible, tb_confirm_close_locked_tab]; gDirTabActionOnDoubleClick := tadc_FavoriteTabs; gDirTabLimit := 32; gDirTabPosition := tbpos_top; { Favorite Tabs} gFavoriteTabsUseRestoreExtraOptions := False; gWhereToAddNewFavoriteTabs := afte_Last; gFavoriteTabsFullExpandOrNot := True; gFavoriteTabsGoToConfigAfterSave := False; gFavoriteTabsGoToConfigAfterReSave := False; gDefaultTargetPanelLeftSaved := tclLeft; gDefaultTargetPanelRightSaved := tclRight; gDefaultExistingTabsToKeep := tclNone; gFavoriteTabsSaveDirHistory := False; { Log page } gLogFile := False; gLogFileCount:= 0; gLogFileWithDateInName := FALSE; gLogFileName := EnvVarConfigPath + PathDelim + 'doublecmd.log'; gLogOptions := [log_cp_mv_ln, log_delete, log_dir_op, log_arc_op, log_vfs_op, log_success, log_errors, log_info, log_start_shutdown, log_commandlineexecution]; { Configuration page } gSaveConfiguration := True; gSaveWindowState := True; gSaveFolderTabs := True; gSaveSearchReplaceHistory := True; gSaveDirHistory := True; gDirHistoryCount := 30; gSaveCmdLineHistory := True; gSaveFileMaskHistory := True; gSaveVolumeSizeHistory := True; gSaveCreateDirectoriesHistory := True; gPluginInAutoTweak := False; gWCXConfigViewMode := wcvmByPlugin; { Quick Search/Filter page } gQuickSearchOptions.Match := [qsmBeginning, qsmEnding]; gQuickSearchOptions.Items := qsiFilesAndDirectories; gQuickSearchOptions.SearchCase := qscInsensitive; gQuickFilterAutoHide := True; gQuickFilterSaveSessionModifications := False; //Legacy... { Miscellaneous page } gGridVertLine := False; gGridHorzLine := False; gShowCurDirTitleBar := False; gShowWarningMessages := True; gSpaceMovesDown := False; gDirBrackets := True; gInplaceRename := False; gInplaceRenameButton := True; gDblClickToParent := False; gDblClickEditPath := False; gHotDirAddTargetOrNot := False; gHotDirFullExpandOrNot:=False; gShowPathInPopup:=FALSE; gShowOnlyValidEnv:=TRUE; gWhereToAddNewHotDir := ahdSmart; gHotDirFilenameStyle := pfsAbsolutePath; gHotDirPathToBeRelativeTo := EnvVarCommanderPath; gHotDirPathModifierElements := []; gShowToolTip := True; gShowToolTipMode := tttmCombineDcSystem; gToolTipHideTimeOut := ttthtSystem; gThumbSave := True; gThumbSize.cx := 128; gThumbSize.cy := 128; gSearchDefaultTemplate := EmptyStr; gDescReadEncoding:= meUTF8; gDescWriteEncoding:= meUTF8BOM; gDescCreateUnicode:= True; gDefaultTextEncoding:= EncodingNone; { Auto refresh page } gWatchDirs := [watch_file_name_change, watch_attributes_change]; gWatchDirsExclude := ''; gWatcherMode := fswmAllowDelete; { Icons page } gShowIcons := sim_all_and_exe; gShowIconsNew := gShowIcons; gIconOverlays := {$IFDEF UNIX}True{$ELSE}False{$ENDIF}; gIconsSize := 32; gIconsSizeNew := gIconsSize; gDiskIconsSize := 16; gDiskIconsAlpha := 50; gToolIconsSize := 24; gIconsExclude := False; gIconsExcludeDirs := EmptyStr; gPixelsPerInch := 96; gCustomIcons := []; gIconsInMenus := False; gIconsInMenusSize := 16; gIconsInMenusSizeNew := gIconsInMenusSize; gShowHiddenDimmed := False; gIconTheme := DC_THEME_NAME; { Ignore list page } gIgnoreListFileEnabled := False; gIgnoreListFile := EnvVarConfigPath + PathDelim + 'ignorelist.txt'; {Viewer} gImageStretch := False; gImageExifRotate := True; gImageStretchOnlyLarge := True; gImageShowTransparency := False; gImageCenter := True; gPreviewVisible := False; gCopyMovePath1 := ''; gCopyMovePath2 := ''; gCopyMovePath3 := ''; gCopyMovePath4 := ''; gCopyMovePath5 := ''; gImagePaintMode := vptPen; gImagePaintWidth := 5; gColCount := 1; gTabSpaces := 8; gMaxCodeSize := 128; gMaxTextWidth := 1024; gImagePaintColor := clRed; gTextPosition:= 0; gViewerMode:= 0; gShowCaret := False; gViewerWrapText := False; gViewerLeftMargin := 4; gViewerLineSpacing := 0; gPrintMargins:= Classes.Rect(200, 200, 200, 200); gViewerAutoCopy := True; gViewerSynEditMask := AllFilesMask; gViewerJpegQuality := 80; { Editor } gEditWaitTime := 2000; gEditorSynEditOptions := SYNEDIT_DEFAULT_OPTIONS; gEditorSynEditTabWidth := 8; gEditorSynEditRightEdge := 80; gEditorSynEditBlockIndent := 2; gEditorFindWordAtCursor := True; { Differ } gDifferIgnoreCase := False; gDifferAutoCompare := True; gDifferKeepScrolling := True; gDifferPaintBackground := True; gDifferLineDifferences := False; gDifferIgnoreWhiteSpace := False; {SyncDirs} gSyncDirsSubdirs := False; gSyncDirsByContent := False; gSyncDirsAsymmetric := False; gSyncDirsIgnoreDate := False; gSyncDirsAsymmetricSave := False; gSyncDirsShowFilterCopyRight := True; gSyncDirsShowFilterEqual := True; gSyncDirsShowFilterNotEqual := True; gSyncDirsShowFilterUnknown := True; gSyncDirsShowFilterCopyLeft := True; gSyncDirsShowFilterDuplicates := True; gSyncDirsShowFilterSingles := True; gSyncDirsFileMask := '*'; gSyncDirsFileMaskSave := True; gDateTimeFormatSync := DefaultDateTimeFormatSync; { Internal Associations} gFileAssociationLastCustomAction := rsMsgDefaultCustomActionName; gOfferToAddToFileAssociations := False; gExtendedContextMenu := False; gOpenExecuteViaShell := False; gDefaultContextActions := True; gExecuteViaTerminalClose := False; gExecuteViaTerminalStayOpen := False; gIncludeFileAssociation := False; gFileAssocFilenameStyle := pfsAbsolutePath; gFileAssocPathToBeRelativeTo := EnvVarCommanderPath; gFileAssocPathModifierElements := []; { Tree View Menu } gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand := False; gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick := False; gUseTreeViewMenuWithFavoriteTabsFromMenuCommand := False; gUseTreeViewMenuWithFavoriteTabsFromDoubleClick := False; gUseTreeViewMenuWithDirHistory := False; gUseTreeViewMenuWithViewHistory := False; gUseTreeViewMenuWithCommandLineHistory := False; gTreeViewMenuShortcutExit := True; gTreeViewMenuSingleClickExit := True; gTreeViewMenuDoubleClickExit := True; for iIndexContextMode:=0 to (ord(tvmcLASTONE)-2) do begin gTreeViewMenuOptions[iIndexContextMode].CaseSensitive := False; gTreeViewMenuOptions[iIndexContextMode].IgnoreAccents := True; gTreeViewMenuOptions[iIndexContextMode].ShowWholeBranchIfMatch := False; end; gTreeViewMenuUseKeyboardShortcut := True; { - Other - } gGoToRoot := False; gLuaLib := LuaDLL; gActiveRight := False; gNameSCFile := 'shortcuts.scf'; gHotKeySortOrder := hksoByCommand; gUseEnterToCloseHotKeyEditor := True; gLastUsedPacker := 'zip'; gLastDoAnyCommand := 'cm_Refresh'; gbMarkMaskCaseSensitive := False; gbMarkMaskIgnoreAccents := False; gMarkMaskFilterWindows := False; gMarkShowWantedAttribute := False; gMarkDefaultWantedAttribute := ''; gMarkLastWantedAttribute := ''; { TotalCommander Import/Export } //Will search minimally where TC could be installed so the default value would have some chances to be correct. {$IFDEF MSWINDOWS} gTotalCommanderExecutableFilename:=''; gTotalCommanderConfigFilename:=''; gTotalCommanderToolbarPath:=''; if mbFileExists('c:\totalcmd\TOTALCMD.EXE') then gTotalCommanderExecutableFilename:='c:\totalcmd\TOTALCMD.EXE'; if (gTotalCommanderExecutableFilename='') AND (mbFileExists('c:\totalcmd\TOTALCMD64.EXE')) then gTotalCommanderExecutableFilename:='c:\totalcmd\TOTALCMD64.EXE'; if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_COMMON_PROGRAMS,'totalcmd\TOTALCMD.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_PROGRAMS,'totalcmd\TOTALCMD.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_PROGRAM_FILESX86,'totalcmd\TOTALCMD.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_PROGRAM_FILES_COMMON,'totalcmd\TOTALCMD.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_PROGRAM_FILES_COMMONX86,'totalcmd\TOTALCMD.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_COMMON_PROGRAMS,'totalcmd\TOTALCMD64.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_PROGRAMS,'totalcmd\TOTALCMD64.EXE'); if gTotalCommanderExecutableFilename='' then gTotalCommanderExecutableFilename:=GetPathNameIfItMatch(CSIDL_PROGRAM_FILES_COMMON,'totalcmd\TOTALCMD64.EXE'); if mbFileExists('c:\totalcmd\wincmd.ini') then gTotalCommanderConfigFilename:='c:\totalcmd\wincmd.ini'; if gTotalCommanderConfigFilename='' then gTotalCommanderConfigFilename:=GetPathNameIfItMatch(CSIDL_APPDATA,'GHISLER\wincmd.ini'); if gTotalCommanderConfigFilename='' then gTotalCommanderConfigFilename:=GetPathNameIfItMatch(CSIDL_PROFILE,'wincmd.ini'); if gTotalCommanderConfigFilename='' then gTotalCommanderConfigFilename:=GetPathNameIfItMatch(CSIDL_WINDOWS,'wincmd.ini'); //Don't laugh. The .INI file were originally saved in windows folder for many programs! if gTotalCommanderConfigFilename<>'' then gTotalCommanderToolbarPath:=ExtractFilePath(gTotalCommanderConfigFilename); {$ENDIF} gExts.Clear; gColorExt.Clear; gFileInfoToolTip.Clear; gDirectoryHotlist.Clear; gFavoriteTabsList.Clear; glsDirHistory.Clear; glsMaskHistory.Clear; glsSearchHistory.Clear; glsSearchPathHistory.Clear; glsReplaceHistory.Clear; glsReplacePathHistory.Clear; glsCreateDirectoriesHistory.Clear; glsIgnoreList.Clear; gSearchTemplateList.Clear; gDSXPlugins.Clear; gWCXPlugins.Clear; gWDXPlugins.Clear; gWFXPlugins.Clear; gWLXPlugins.Clear; gMultiArcList.Clear; ColSet.Clear; end; procedure SetDefaultNonConfigGlobs; begin { - Not in config - } gHelpLang := ''; gRepeatPassword := True; gFirstTextSearch := True; gErrorFile := gpCfgDir + ExtractOnlyFileName(Application.ExeName) + '.err'; DefaultDateTimeFormat := FormatSettings.ShortDateFormat + ' hh:nn:ss'; DefaultDateTimeFormatSync := 'yyyy.mm.dd hh:nn:ss'; end; function OpenConfig(var ErrorMessage: String): Boolean; begin if Assigned(gConfig) then Exit(True); // Check global directory for XML config. if (gpCmdLineCfgDir = EmptyStr) then begin gUseConfigInProgramDir:= mbFileExists(gpGlobalCfgDir + 'doublecmd.inf'); if gUseConfigInProgramDir or mbFileExists(gpGlobalCfgDir + 'doublecmd.xml') then begin gConfig := TXmlConfig.Create(gpGlobalCfgDir + 'doublecmd.xml'); if mbFileExists(gpGlobalCfgDir + 'doublecmd.xml') then begin if mbFileAccess(gpGlobalCfgDir + 'doublecmd.xml', fmOpenRead or fmShareDenyWrite) then begin LoadConfigCheckErrors(@LoadGlobalConfig, gpGlobalCfgDir + 'doublecmd.xml', ErrorMessage); if gConfig.TryGetValue(gConfig.RootNode, 'Configuration/UseConfigInProgramDir', gUseConfigInProgramDir) then begin gConfig.DeleteNode(gConfig.RootNode, 'Configuration/UseConfigInProgramDir'); if not gUseConfigInProgramDir then begin gConfig.Save; mbDeleteFile(gpGlobalCfgDir + 'doublecmd.inf'); end; end; if not gUseConfigInProgramDir then begin if mbFileExists(gpCfgDir + 'doublecmd.xml') then // Close global config so that the local config is opened below. FreeAndNil(gConfig) else // Local config is used but it doesn't exist. Use global config that has just // been read but set file name accordingly and later save to local config. gConfig.FileName := gpCfgDir + 'doublecmd.xml'; end; end else begin // Configuration file is not readable. AddStrWithSep(ErrorMessage, 'Config file "' + gpGlobalCfgDir + 'doublecmd.xml' + '" exists but is not readable.', LineEnding); Exit(False); end; end; end; end; // Check user directory for XML config. if not Assigned(gConfig) and mbFileExists(gpCfgDir + 'doublecmd.xml') then begin gConfig := TXmlConfig.Create(gpCfgDir + 'doublecmd.xml'); gUseConfigInProgramDir := False; if mbFileAccess(gpCfgDir + 'doublecmd.xml', fmOpenRead or fmShareDenyWrite) then begin LoadConfigCheckErrors(@LoadGlobalConfig, gpCfgDir + 'doublecmd.xml', ErrorMessage); end else begin // Configuration file is not readable. AddStrWithSep(ErrorMessage, 'Config file "' + gpCfgDir + 'doublecmd.xml' + '" exists but is not readable.', LineEnding); Exit(False); end; end; // By default use config in user directory. if not Assigned(gConfig) then begin gConfig := TXmlConfig.Create(gpCfgDir + 'doublecmd.xml'); gUseConfigInProgramDir := False; end; gUseConfigInProgramDirNew := gUseConfigInProgramDir; // If global config is used then set config directory as global config directory. if gUseConfigInProgramDir then begin gpCfgDir := gpGlobalCfgDir; UpdateEnvironmentVariable; end; if mbFileExists(gpCfgDir + 'doublecmd.xml') and (not mbFileAccess(gpCfgDir + 'doublecmd.xml', fmOpenWrite or fmShareDenyWrite)) then begin DCDebug('Warning: Config file "' + gpCfgDir + 'doublecmd.xml' + '" is not accessible for writing. Configuration will not be saved.'); end; if not mbDirectoryExists(gpCfgDir) then mbForceDirectory(gpCfgDir); Result := True; end; function LoadGlobs: Boolean; var ErrorMessage: String = ''; begin Result := False; if not OpenConfig(ErrorMessage) then Exit; DCDebug('Loading configuration from ', gpCfgDir); SetDefaultConfigGlobs; if Assigned(gConfig) then LoadXmlConfig else begin DCDebug('Error: No config created.'); Exit(False); end; { Favorite Tabs } gFavoriteTabsList.LoadAllListFromXml; // Update plugins if DC version is changed if (gPreviousVersion <> dcVersion) then UpdatePlugins; // Adjust icons size gIconsSize:= AdjustIconSize(gIconsSize, gPixelsPerInch); gDiskIconsSize:= AdjustIconSize(gDiskIconsSize, gPixelsPerInch); gToolBarIconSize:= AdjustIconSize(gToolBarIconSize, gPixelsPerInch); gToolBarButtonSize:= AdjustIconSize(gToolBarButtonSize, gPixelsPerInch); // Set secondary variables for options that need restart. gShowIconsNew := gShowIcons; gIconsSizeNew := gIconsSize; gIconsInMenusSizeNew := gIconsInMenusSize; CopySettingsFiles; { Internal associations } // "LoadExtsConfig" checks itself if file is present or not LoadConfigCheckErrors(@LoadExtsConfig, gpCfgDir + gcfExtensionAssociation, ErrorMessage); LoadStringsFromFile(glsIgnoreList, ReplaceEnvVars(gIgnoreListFile)); { Localization } msgLoadLng; if (gHighlighters = nil) then begin // Must be after msgLoadLng and before LoadColorsConfig gHighlighters := THighlighters.Create; end; { Highlighters } if mbFileExists(gpCfgDir + HighlighterConfig) then LoadConfigCheckErrors(@LoadHighlightersConfig, gpCfgDir + HighlighterConfig, ErrorMessage); { Hotkeys } if not mbFileExists(gpCfgDir + gNameSCFile) then gNameSCFile := 'shortcuts.scf'; LoadConfigCheckErrors(@LoadHotManConfig, gpCfgDir + gNameSCFile, ErrorMessage); { Colors } gColors.LoadFromXml(gConfig); if mbFileExists(gpCfgDir + COLORS_JSON) then LoadConfigCheckErrors(@LoadColorsConfig, gpCfgDir + COLORS_JSON, ErrorMessage); { MultiArc addons } if mbFileExists(gpCfgDir + sMULTIARC_FILENAME) then LoadConfigCheckErrors(@LoadMultiArcConfig, gpCfgDir + sMULTIARC_FILENAME, ErrorMessage); { Various history } if mbFileExists(gpCfgDir + 'history.xml') then LoadConfigCheckErrors(@LoadHistoryConfig, gpCfgDir + 'history.xml', ErrorMessage); FillFileFuncList; { Specialdir } if gShowOnlyValidEnv=FALSE then gSpecialDirList.PopulateSpecialDir; //We must reload it if user has included the unsignificant environment variable. But anyway, this will not happen often. Result := AskUserOnError(ErrorMessage); end; procedure SaveGlobs; var OldDir: String; ErrMsg: String = ''; begin if (gUseConfigInProgramDirNew <> gUseConfigInProgramDir) and (gpCmdLineCfgDir = EmptyStr) then begin OldDir := gpCfgDir; if gUseConfigInProgramDirNew then begin mbForceDirectory(gpGlobalCfgDir); FileClose(mbFileCreate(gpGlobalCfgDir + 'doublecmd.inf')); end else begin if mbFileExists(gpGlobalCfgDir + 'doublecmd.inf') then mbDeleteFile(gpGlobalCfgDir + 'doublecmd.inf') end; LoadPaths; gConfig.FileName := gpCfgDir + 'doublecmd.xml'; // Copy the configuration to a new location CopyDirTree(OldDir, gpCfgDir, [cffOverwriteFile]); gUseConfigInProgramDir := gUseConfigInProgramDirNew; end; if mbFileAccess(gpCfgDir, fmOpenWrite or fmShareDenyNone) then begin SaveWithCheck(@SaveEarlyConfig, 'early config', ErrMsg); SaveWithCheck(@SaveCfgIgnoreList, 'ignore list', ErrMsg); SaveWithCheck(@SaveCfgMainConfig, 'main configuration', ErrMsg); SaveWithCheck(@SaveHighlightersConfig, 'highlighters config', ErrMsg); SaveWithCheck(@SaveHistoryConfig, 'various history', ErrMsg); SaveWithCheck(@SaveColorsConfig, 'color themes', ErrMsg); if ErrMsg <> EmptyStr then DebugLn(ErrMsg); end else DebugLn('Not saving configuration - no write access to ', gpCfgDir); end; procedure LoadContentPlugins; var I: Integer; Module: TWdxModule; Template: TSearchTemplate; Content: TPluginSearchRec; begin for I:= 0 to gSearchTemplateList.Count - 1 do begin Template:= gSearchTemplateList.Templates[I]; if Template.SearchRecord.ContentPlugin then begin for Content in Template.SearchRecord.ContentPlugins do begin Module:= gWDXPlugins.GetWdxModule(Content.Plugin); if Assigned(Module) and (Module.IsLoaded = False) then begin Module.LoadModule; end; end; end; end; end; procedure LoadXmlConfig; procedure GetExtTool(Node: TXmlNode; var ExternalToolOptions: TExternalToolOptions); begin if Assigned(Node) then with ExternalToolOptions do begin Enabled := gConfig.GetAttr(Node, 'Enabled', Enabled); Path := gConfig.GetValue(Node, 'Path', Path); Parameters := gConfig.GetValue(Node, 'Parameters', Parameters); RunInTerminal := gConfig.GetValue(Node, 'RunInTerminal', RunInTerminal); KeepTerminalOpen := gConfig.GetValue(Node, 'KeepTerminalOpen', KeepTerminalOpen); end; end; procedure GetDCFont(Node: TXmlNode; var FontOptions: TDCFontOptions); var FontQuality: Integer; begin if Assigned(Node) then begin FontQuality:= Integer(FontOptions.Quality); gConfig.GetFont(Node, '', FontOptions.Name, FontOptions.Size, Integer(FontOptions.Style), FontQuality, FontOptions.Name, FontOptions.Size, Integer(FontOptions.Style), FontQuality); FontOptions.Quality:= TFontQuality(FontQuality); end; end; procedure LoadOption(Node: TXmlNode; var Options: TDrivesListButtonOptions; Option: TDrivesListButtonOption; AName: String); var Value: Boolean; begin if gConfig.TryGetValue(Node, AName, Value) then begin if Value then Include(Options, Option) else Exclude(Options, Option); end; end; var DecimalSeparator: String; Root, Node, SubNode: TXmlNode; LoadedConfigVersion, iIndexContextMode: Integer; oldQuickSearch: Boolean = True; oldQuickFilter: Boolean = False; oldQuickSearchMode: TShiftState = [ssCtrl, ssAlt]; oldQuickFilterMode: TShiftState = []; KeyTypingModifier: TKeyTypingModifier; begin with gConfig do begin Root := gConfig.RootNode; { Double Commander Version } gPreviousVersion:= GetAttr(Root, 'DCVersion', EmptyStr); LoadedConfigVersion := GetAttr(Root, 'ConfigVersion', ConfigVersion); { Create config backup } if (LoadedConfigVersion < ConfigVersion) then try WriteToFile(gpCfgDir + 'doublecmd-' + IntToStr(LoadedConfigVersion) + '.xml.bak'); except // Ignore end; if (LoadedConfigVersion < 13) then begin DeleteNode(Root, 'Configuration/UseConfigInProgramDir'); end; { Language page } gPOFileName := GetValue(Root, 'Language/POFileName', gPOFileName); DoLoadLng; { Since language file has been loaded, we'll not set our default memory size string. They will be in the correct language } gSizeDisplayUnits[fsfFloat] := ''; //Not used, but at least it will be defined. gSizeDisplayUnits[fsfByte] := ''; //Not user changeable by legacy and empty by legacy. gSizeDisplayUnits[fsfKilo] := ' ' + Trim(rsLegacyDisplaySizeSingleLetterKilo); //Not user changeable by legacy, taken from language file since 2018-11. gSizeDisplayUnits[fsfMega] := ' ' + Trim(rsLegacyDisplaySizeSingleLetterMega); //Not user changeable by legacy, taken from language file since 2018-11. gSizeDisplayUnits[fsfGiga] := ' ' + Trim(rsLegacyDisplaySizeSingleLetterGiga); //Not user changeable by legacy, taken from language file since 2018-11. gSizeDisplayUnits[fsfTera] := ' ' + Trim(rsLegacyDisplaySizeSingleLetterTera); //Not user changeable by legacy, taken from language file since 2018-11. gSizeDisplayUnits[fsfPersonalizedFloat] := ''; //Not used, but at least it will be defined. gSizeDisplayUnits[fsfPersonalizedByte] := rsDefaultPersonalizedAbbrevByte; gSizeDisplayUnits[fsfPersonalizedKilo] := rsDefaultPersonalizedAbbrevKilo; gSizeDisplayUnits[fsfPersonalizedMega] := rsDefaultPersonalizedAbbrevMega; gSizeDisplayUnits[fsfPersonalizedGiga] := rsDefaultPersonalizedAbbrevGiga; gSizeDisplayUnits[fsfPersonalizedTera] := rsDefaultPersonalizedAbbrevTera; { Since language has been loaded, we may now load our font usage name} gFonts[dcfMain].Usage := rsFontUsageMain; gFonts[dcfEditor].Usage := rsFontUsageEditor; gFonts[dcfViewer].Usage := rsFontUsageViewer; gFonts[dcfViewerBook].Usage := rsFontUsageViewerBook; gFonts[dcfLog].Usage := rsFontUsageLog; gFonts[dcfConsole].Usage := rsFontUsageConsole; gFonts[dcfPathEdit].Usage := rsFontUsagePathEdit; gFonts[dcfFunctionButtons].Usage := rsFontUsageFunctionButtons; gFonts[dcfSearchResults].Usage := rsFontUsageSearchResults; gFonts[dcfTreeViewMenu].Usage := rsFontUsageTreeViewMenu; gFonts[dcfStatusBar].Usage := rsFontUsageStatusBar; { Behaviours page } Node := Root.FindNode('Behaviours'); if Assigned(Node) then begin gGoToRoot := GetValue(Node, 'GoToRoot', gGoToRoot); gShowCurDirTitleBar := GetValue(Node, 'ShowCurDirTitleBar', gShowCurDirTitleBar); gActiveRight := GetValue(Node, 'ActiveRight', gActiveRight); gRunTermCmd := GetValue(Node, 'JustRunTerminal', RunTermCmd); gRunTermParams := GetValue(Node, 'JustRunTermParams', RunTermParams); gRunInTermCloseCmd := GetValue(Node, 'RunInTerminalCloseCmd', RunInTermCloseCmd); gRunInTermCloseParams := GetValue(Node, 'RunInTerminalCloseParams', RunInTermCloseParams); gRunInTermStayOpenCmd := GetValue(Node, 'RunInTerminalStayOpenCmd', RunInTermStayOpenCmd); gRunInTermStayOpenParams := GetValue(Node, 'RunInTerminalStayOpenParams', RunInTermStayOpenParams); gOnlyOneAppInstance := GetValue(Node, 'OnlyOneAppInstance', gOnlyOneAppInstance); gLynxLike := GetValue(Node, 'LynxLike', gLynxLike); if LoadedConfigVersion < 5 then begin if GetValue(Node, 'SortCaseSensitive', False) = False then gSortCaseSensitivity := cstNotSensitive else gSortCaseSensitivity := cstLocale; gSortNatural := GetValue(Node, 'SortNatural', gSortNatural); end; if LoadedConfigVersion < 6 then begin if GetValue(Node, 'ShortFileSizeFormat', True) then gFileSizeFormat := fsfFloat else gFileSizeFormat := fsfByte; end else begin gFileSizeFormat := TFileSizeFormat(GetValue(Node, 'FileSizeFormat', Ord(gFileSizeFormat))); end; if LoadedConfigVersion < 12 then begin gHeaderDigits := GetValue(Node, 'HeaderFooterDigits', gHeaderDigits); gFooterDigits := GetValue(Node, 'HeaderFooterDigits', gFooterDigits); gHeaderSizeFormat := TFileSizeFormat(GetValue(Node,'HeaderFooterSizeFormat', ord(gHeaderSizeFormat))); gFooterSizeFormat := TFileSizeFormat(GetValue(Node,'HeaderFooterSizeFormat', ord(gFooterSizeFormat))); end else begin gHeaderDigits := GetValue(Node, 'HeaderDigits', gHeaderDigits); gFooterDigits := GetValue(Node, 'FooterDigits', gFooterDigits); gHeaderSizeFormat := TFileSizeFormat(GetValue(Node,'HeaderSizeFormat', ord(gHeaderSizeFormat))); gFooterSizeFormat := TFileSizeFormat(GetValue(Node,'FooterSizeFormat', ord(gFooterSizeFormat))); end; gOperationSizeFormat := TFileSizeFormat(GetValue(Node, 'OperationSizeFormat', Ord(gOperationSizeFormat))); gFileSizeDigits := GetValue(Node, 'FileSizeDigits', gFileSizeDigits); gOperationSizeDigits := GetValue(Node, 'OperationSizeDigits', gOperationSizeDigits); gSizeDisplayUnits[fsfPersonalizedByte] := Trim(GetValue(Node, 'PersonalizedByte', gSizeDisplayUnits[fsfPersonalizedByte])); if gSizeDisplayUnits[fsfPersonalizedByte]<>'' then gSizeDisplayUnits[fsfPersonalizedByte] := ' ' + gSizeDisplayUnits[fsfPersonalizedByte]; gSizeDisplayUnits[fsfPersonalizedKilo] := ' ' + Trim(GetValue(Node, 'PersonalizedKilo', gSizeDisplayUnits[fsfPersonalizedKilo])); gSizeDisplayUnits[fsfPersonalizedMega] := ' ' + Trim(GetValue(Node, 'PersonalizedMega', gSizeDisplayUnits[fsfPersonalizedMega])); gSizeDisplayUnits[fsfPersonalizedGiga] := ' ' + Trim(GetValue(Node, 'PersonalizedGiga', gSizeDisplayUnits[fsfPersonalizedGiga])); gSizeDisplayUnits[fsfPersonalizedTera] := ' ' + Trim(GetValue(Node, 'PersonalizedTera', gSizeDisplayUnits[fsfPersonalizedTera])); gConfirmQuit := GetValue(Node, 'ConfirmQuit', gConfirmQuit); gMinimizeToTray := GetValue(Node, 'MinimizeToTray', gMinimizeToTray); gAlwaysShowTrayIcon := GetValue(Node, 'AlwaysShowTrayIcon', gAlwaysShowTrayIcon); gMouseSelectionEnabled := GetAttr(Node, 'Mouse/Selection/Enabled', gMouseSelectionEnabled); gMouseSelectionButton := GetValue(Node, 'Mouse/Selection/Button', gMouseSelectionButton); gMouseSingleClickStart := GetValue(Node, 'Mouse/SingleClickStart', gMouseSingleClickStart); gMouseSelectionIconClick := GetValue(Node, 'Mouse/Selection/IconClick', gMouseSelectionIconClick); gScrollMode := TScrollMode(GetValue(Node, 'Mouse/ScrollMode', Integer(gScrollMode))); gWheelScrollLines:= GetValue(Node, 'Mouse/WheelScrollLines', gWheelScrollLines); gAutoFillColumns := GetValue(Node, 'AutoFillColumns', gAutoFillColumns); gAutoSizeColumn := GetValue(Node, 'AutoSizeColumn', gAutoSizeColumn); gDateTimeFormat := GetValidDateTimeFormat(GetValue(Node, 'DateTimeFormat', gDateTimeFormat), DefaultDateTimeFormat); gColumnsTitleLikeValues := GetValue(Node, 'ColumnsTitleLikeValues', gColumnsTitleLikeValues); gCutTextToColWidth := GetValue(Node, 'CutTextToColumnWidth', gCutTextToColWidth); gExtendCellWidth := GetValue(Node, 'ExtendCellWidth', gExtendCellWidth); gShowSystemFiles := GetValue(Node, 'ShowSystemFiles', gShowSystemFiles); {$IFNDEF LCLCARBON} // Under Mac OS X loading file list in separate thread are very very slow // so disable and hide this option under Mac OS X Carbon gListFilesInThread := GetValue(Node, 'ListFilesInThread', gListFilesInThread); {$ENDIF} gLoadIconsSeparately := GetValue(Node, 'LoadIconsSeparately', gLoadIconsSeparately); gDelayLoadingTabs := GetValue(Node, 'DelayLoadingTabs', gDelayLoadingTabs); gHighlightUpdatedFiles := GetValue(Node, 'HighlightUpdatedFiles', gHighlightUpdatedFiles); gDriveBlackList := GetValue(Node, 'DriveBlackList', gDriveBlackList); gDriveBlackListUnmounted := GetValue(Node, 'DriveBlackListUnmounted', gDriveBlackListUnmounted); if LoadedConfigVersion < 8 then begin gBriefViewFileExtAligned := GetValue(Node, 'BriefViewFileExtAligned', gBriefViewFileExtAligned); end; end; { Tools page } GetExtTool(gConfig.FindNode(Root, 'Tools/Viewer'), gExternalTools[etViewer]); GetExtTool(gConfig.FindNode(Root, 'Tools/Editor'), gExternalTools[etEditor]); GetExtTool(gConfig.FindNode(Root, 'Tools/Differ'), gExternalTools[etDiffer]); { Differ related} Node := Root.FindNode('Tools'); SubNode := FindNode(Node, 'Differ', TRUE); gResultingFramePositionAfterCompare := TResultingFramePositionAfterCompare(GetValue(SubNode, 'FramePosAfterComp', Integer(gResultingFramePositionAfterCompare))); { Fonts page } GetDCFont(gConfig.FindNode(Root, 'Fonts/Main'), gFonts[dcfMain]); GetDCFont(gConfig.FindNode(Root, 'Fonts/Editor'), gFonts[dcfEditor]); GetDCFont(gConfig.FindNode(Root, 'Fonts/Viewer'), gFonts[dcfViewer]); GetDCFont(gConfig.FindNode(Root, 'Fonts/ViewerBook'), gFonts[dcfViewerBook]); GetDCFont(gConfig.FindNode(Root, 'Fonts/Log'), gFonts[dcfLog]); GetDCFont(gConfig.FindNode(Root, 'Fonts/Console'), gFonts[dcfConsole]); GetDCFont(gConfig.FindNode(Root, 'Fonts/PathEdit'), gFonts[dcfPathEdit]); GetDCFont(gConfig.FindNode(Root, 'Fonts/FunctionButtons'), gFonts[dcfFunctionButtons]); if LoadedConfigVersion >= 11 then GetDCFont(gConfig.FindNode(Root, 'Fonts/SearchResults'), gFonts[dcfSearchResults]); //Let's ignore possible previous setting for this and keep our default. GetDCFont(gConfig.FindNode(Root, 'Fonts/TreeViewMenu'), gFonts[dcfTreeViewMenu]); GetDCFont(gConfig.FindNode(Root, 'Fonts/StatusBar'), gFonts[dcfStatusBar]); { Colors page } Node := Root.FindNode('Colors'); if Assigned(Node) then begin gUseCursorBorder := GetValue(Node, 'UseCursorBorder', gUseCursorBorder); gUseFrameCursor := GetValue(Node, 'UseFrameCursor', gUseFrameCursor); gUseInvertedSelection := GetValue(Node, 'UseInvertedSelection', gUseInvertedSelection); gUseInactiveSelColor := GetValue(Node, 'UseInactiveSelColor', gUseInactiveSelColor); gAllowOverColor := GetValue(Node, 'AllowOverColor', gAllowOverColor); gBorderFrameWidth := GetValue(Node, 'gBorderFrameWidth', gBorderFrameWidth); gInactivePanelBrightness := GetValue(Node, 'InactivePanelBrightness', gInactivePanelBrightness); gIndUseGradient := GetValue(Node, 'FreeSpaceIndicator/UseGradient', gIndUseGradient); end; { ToolTips page } Node := Root.FindNode('ToolTips'); if Assigned(Node) then begin gShowToolTip := GetValue(Node, 'ShowToolTipMode', gShowToolTip); gShowToolTipMode := TToolTipMode(GetValue(Node, 'ActualToolTipMode', Integer(gShowToolTipMode))); gToolTipHideTimeOut := TToolTipHideTimeOut(GetValue(Node, 'ToolTipHideTimeOut', Integer(gToolTipHideTimeOut))); gFileInfoToolTip.Load(gConfig, Node); end; { Layout page } Node := Root.FindNode('Layout'); if Assigned(Node) then begin gMainMenu := GetValue(Node, 'MainMenu', gMainMenu); SubNode := Node.FindNode('ButtonBar'); if Assigned(SubNode) then begin gButtonBar := GetAttr(SubNode, 'Enabled', gButtonBar); gToolBarFlat := GetValue(SubNode, 'FlatIcons', gToolBarFlat); gToolBarButtonSize := GetValue(SubNode, 'ButtonHeight', gToolBarButtonSize); if LoadedConfigVersion <= 1 then gToolBarIconSize := GetValue(SubNode, 'SmallIconSize', gToolBarIconSize) else gToolBarIconSize := GetValue(SubNode, 'IconSize', gToolBarIconSize); gToolBarShowCaptions := GetValue(SubNode, 'ShowCaptions', gToolBarShowCaptions); gToolbarReportErrorWithCommands := GetValue(SubNode,'ReportErrorWithCommands',gToolbarReportErrorWithCommands); gToolbarFilenameStyle := TConfigFilenameStyle(GetValue(SubNode, 'FilenameStyle', ord(gToolbarFilenameStyle))); gToolbarPathToBeRelativeTo := gConfig.GetValue(SubNode, 'PathToBeRelativeTo', gToolbarPathToBeRelativeTo); gToolbarPathModifierElements := tToolbarPathModifierElements(GetValue(SubNode, 'PathModifierElements', Integer(gToolbarPathModifierElements))); end; SubNode := Node.FindNode('MiddleBar'); if Assigned(SubNode) then begin gMiddleToolBar := GetAttr(SubNode, 'Enabled', gMiddleToolBar); gMiddleToolBarFlat := GetValue(SubNode, 'FlatIcons', gMiddleToolBarFlat); gMiddleToolBarButtonSize := GetValue(SubNode, 'ButtonHeight', gMiddleToolBarButtonSize); gMiddleToolBarIconSize := GetValue(SubNode, 'IconSize', gMiddleToolBarIconSize); gMiddleToolBarShowCaptions := GetValue(SubNode, 'ShowCaptions', gMiddleToolBarShowCaptions); gMiddleToolbarReportErrorWithCommands := GetValue(SubNode,'ReportErrorWithCommands', gMiddleToolbarReportErrorWithCommands); end; gDriveBar1 := GetValue(Node, 'DriveBar1', gDriveBar1); gDriveBar2 := GetValue(Node, 'DriveBar2', gDriveBar2); gDriveBarFlat := GetValue(Node, 'DriveBarFlat', gDriveBarFlat); if LoadedConfigVersion < 3 then gDrivesListButton := GetValue(Node, 'DriveMenuButton', gDrivesListButton) else begin SubNode := Node.FindNode('DrivesListButton'); if Assigned(SubNode) then begin gDrivesListButton := GetAttr(SubNode, 'Enabled', gDrivesListButton); LoadOption(SubNode, gDrivesListButtonOptions, dlbShowLabel, 'ShowLabel'); LoadOption(SubNode, gDrivesListButtonOptions, dlbShowFileSystem, 'ShowFileSystem'); LoadOption(SubNode, gDrivesListButtonOptions, dlbShowFreeSpace, 'ShowFreeSpace'); end; end; gSeparateTree := GetValue(Node, 'SeparateTree', gSeparateTree); gDirectoryTabs := GetValue(Node, 'DirectoryTabs', gDirectoryTabs); gCurDir := GetValue(Node, 'CurrentDirectory', gCurDir); gTabHeader := GetValue(Node, 'TabHeader', gTabHeader); gStatusBar := GetValue(Node, 'StatusBar', gStatusBar); gCmdLine := GetValue(Node, 'CmdLine', gCmdLine); gLogWindow := GetValue(Node, 'LogWindow', gLogWindow); gTermWindow := GetValue(Node, 'TermWindow', gTermWindow); gKeyButtons := GetValue(Node, 'KeyButtons', gKeyButtons); gInterfaceFlat := GetValue(Node, 'InterfaceFlat', gInterfaceFlat); gDriveFreeSpace := GetValue(Node, 'DriveFreeSpace', gDriveFreeSpace); gDriveInd := GetValue(Node, 'DriveIndicator', gDriveInd); gProgInMenuBar := GetValue(Node, 'ProgressInMenuBar', gProgInMenuBar); gPanelOfOp := GetValue(Node, 'PanelOfOperationsInBackground', gPanelOfOp); gHorizontalFilePanels := GetValue(Node, 'HorizontalFilePanels', gHorizontalFilePanels); gShortFormatDriveInfo := GetValue(Node, 'ShortFormatDriveInfo', gShortFormatDriveInfo); gUpperCaseDriveLetter := GetValue(Node, 'UppercaseDriveLetter', gUpperCaseDriveLetter); gShowColonAfterDrive := GetValue(Node, 'ShowColonAfterDrive', gShowColonAfterDrive); end; { Files views } Node := Root.FindNode('FilesViews'); if Assigned(Node) then begin SubNode := Node.FindNode('Sorting'); if Assigned(SubNode) then begin gSortCaseSensitivity := TCaseSensitivity(GetValue(SubNode, 'CaseSensitivity', Integer(gSortCaseSensitivity))); gSortNatural := GetValue(SubNode, 'NaturalSorting', gSortNatural); gSortSpecial := GetValue(SubNode, 'SpecialSorting', gSortSpecial); gSortFolderMode:= TSortFolderMode(GetValue(SubNode, 'SortFolderMode', Integer(gSortFolderMode))); gNewFilesPosition := TNewFilesPosition(GetValue(SubNode, 'NewFilesPosition', Integer(gNewFilesPosition))); gUpdatedFilesPosition := TUpdatedFilesPosition(GetValue(SubNode, 'UpdatedFilesPosition', Integer(gUpdatedFilesPosition))); end; SubNode := FindNode(Node, 'ColumnsView'); if Assigned(SubNode) then begin gColumnsLongInStatus := GetValue(SubNode, 'LongInStatus', gColumnsLongInStatus); gColumnsAutoSaveWidth := GetValue(SubNode, 'AutoSaveWidth', gColumnsAutoSaveWidth); gColumnsTitleStyle := TTitleStyle(GetValue(SubNode, 'TitleStyle', Integer(gColumnsTitleStyle))); end; SubNode := Node.FindNode('BriefView'); if Assigned(SubNode) then begin gBriefViewFileExtAligned := GetValue(SubNode, 'FileExtAligned', gBriefViewFileExtAligned); SubNode := SubNode.FindNode('Columns'); if Assigned(SubNode) then begin gBriefViewFixedWidth := GetValue(SubNode, 'FixedWidth', gBriefViewFixedWidth); gBriefViewFixedCount := GetValue(SubNode, 'FixedCount', gBriefViewFixedCount); gBriefViewMode := TBriefViewMode(GetValue(SubNode, 'AutoSize', Integer(gBriefViewMode))); end; end; gExtraLineSpan := GetValue(Node, 'ExtraLineSpan', gExtraLineSpan); gFolderPrefix := GetValue(Node, 'FolderPrefix', gFolderPrefix); gFolderPostfix := GetValue(Node, 'FolderPostfix', gFolderPostfix); gRenameConfirmMouse := GetValue(Node, 'RenameConfirmMouse', gRenameConfirmMouse); end; { Keys page } Node := Root.FindNode('Keyboard'); if Assigned(Node) then begin SubNode := FindNode(Node, 'Typing/Actions'); if Assigned(SubNode) then begin for KeyTypingModifier in TKeyTypingModifier do gKeyTyping[KeyTypingModifier] := TKeyTypingAction(GetValue(SubNode, TKeyTypingModifierToNodeName[KeyTypingModifier], Integer(gKeyTyping[KeyTypingModifier]))); end; end; { File operations page } Node := Root.FindNode('FileOperations'); if Assigned(Node) then begin gCopyBlockSize := GetValue(Node, 'BufferSize', gCopyBlockSize); gLongNameAlert := GetValue(Node, 'LongNameAlert', gLongNameAlert); gHashBlockSize := GetValue(Node, 'HashBufferSize', gHashBlockSize); gUseMmapInSearch := GetValue(Node, 'UseMmapInSearch', gUseMmapInSearch); gPartialNameSearch := GetValue(Node, 'PartialNameSearch', gPartialNameSearch); gInitiallyClearFileMask := GetValue(Node, 'InitiallyClearFileMask', gInitiallyClearFileMask); gNewSearchClearFiltersAction := TFiltersOnNewSearch(GetValue(Node, 'NewSearchClearFiltersAction', integer(gNewSearchClearFiltersAction))); gShowMenuBarInFindFiles := GetValue(Node, 'ShowMenuBarInFindFiles', gShowMenuBarInFindFiles); gWipePassNumber := GetValue(Node, 'WipePassNumber', gWipePassNumber); gDropReadOnlyFlag := GetValue(Node, 'DropReadOnlyFlag', gDropReadOnlyFlag); gProcessComments := GetValue(Node, 'ProcessComments', gProcessComments); gRenameSelOnlyName := GetValue(Node, 'RenameSelOnlyName', gRenameSelOnlyName); gShowCopyTabSelectPanel := GetValue(Node, 'ShowCopyTabSelectPanel', gShowCopyTabSelectPanel); gUseTrash := GetValue(Node, 'UseTrash', gUseTrash); gSkipFileOpError := GetValue(Node, 'SkipFileOpError', gSkipFileOpError); gTypeOfDuplicatedRename := tDuplicatedRename(GetValue(Node, 'TypeOfDuplicatedRename', Integer(gTypeOfDuplicatedRename))); gDefaultDropEffect := GetValue(Node, 'DefaultDropEffect', gDefaultDropEffect); gShowDialogOnDragDrop := GetValue(Node, 'ShowDialogOnDragDrop', gShowDialogOnDragDrop); gDragAndDropDesiredTextFormat[DropTextRichText_Index].DesireLevel := GetValue(Node, 'DragAndDropTextRichtextDesireLevel', gDragAndDropDesiredTextFormat[DropTextRichText_Index].DesireLevel); gDragAndDropDesiredTextFormat[DropTextHtml_Index].DesireLevel := GetValue(Node, 'DragAndDropTextHtmlDesireLevel',gDragAndDropDesiredTextFormat[DropTextHtml_Index].DesireLevel); gDragAndDropDesiredTextFormat[DropTextUnicode_Index].DesireLevel := GetValue(Node, 'DragAndDropTextUnicodeDesireLevel',gDragAndDropDesiredTextFormat[DropTextUnicode_Index].DesireLevel); gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].DesireLevel := GetValue(Node, 'DragAndDropTextSimpletextDesireLevel',gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].DesireLevel); gDragAndDropAskFormatEachTime := GetValue(Node,'DragAndDropAskFormatEachTime', gDragAndDropAskFormatEachTime); gDragAndDropTextAutoFilename := GetValue(Node, 'DragAndDropTextAutoFilename', gDragAndDropTextAutoFilename); gDragAndDropSaveUnicodeTextInUFT8 := GetValue(Node, 'DragAndDropSaveUnicodeTextInUFT8', gDragAndDropSaveUnicodeTextInUFT8); gNtfsHourTimeDelay := GetValue(Node, 'NtfsHourTimeDelay', gNtfsHourTimeDelay); gAutoExtractOpenMask := GetValue(Node, 'AutoExtractOpenMask', gAutoExtractOpenMask); gSearchDefaultTemplate := GetValue(Node, 'SearchDefaultTemplate', gSearchDefaultTemplate); gFileOperationsProgressKind := TFileOperationsProgressKind(GetValue(Node, 'ProgressKind', Integer(gFileOperationsProgressKind))); gFileOperationsConfirmations := TFileOperationsConfirmations(GetValue(Node, 'Confirmations', Integer(gFileOperationsConfirmations))); // Operations sounds SubNode := Node.FindNode('Sounds'); if Assigned(SubNode) then begin gFileOperationDuration:= GetAttr(SubNode, 'Duration', gFileOperationDuration); gFileOperationsSounds[fsoCopy]:= ReplaceEnvVars(GetValue(SubNode, 'Copy', EmptyStr)); gFileOperationsSounds[fsoMove]:= ReplaceEnvVars(GetValue(SubNode, 'Move', EmptyStr)); gFileOperationsSounds[fsoWipe]:= ReplaceEnvVars(GetValue(SubNode, 'Wipe', EmptyStr)); gFileOperationsSounds[fsoDelete]:= ReplaceEnvVars(GetValue(SubNode, 'Delete', EmptyStr)); gFileOperationsSounds[fsoSplit]:= ReplaceEnvVars(GetValue(SubNode, 'Split', EmptyStr)); gFileOperationsSounds[fsoCombine]:= ReplaceEnvVars(GetValue(SubNode, 'Combine', EmptyStr)); end; // Operations options SubNode := Node.FindNode('Options'); if Assigned(SubNode) then begin gOperationOptionSymLinks := TFileSourceOperationOptionSymLink(GetValue(SubNode, 'Symlink', Integer(gOperationOptionSymLinks))); gOperationOptionCorrectLinks := GetValue(SubNode, 'CorrectLinks', gOperationOptionCorrectLinks); gOperationOptionCopyOnWrite := TFileSourceOperationOptionGeneral(GetValue(SubNode, 'CopyOnWrite', Integer(gOperationOptionCopyOnWrite))); gOperationOptionFileExists := TFileSourceOperationOptionFileExists(GetValue(SubNode, 'FileExists', Integer(gOperationOptionFileExists))); gOperationOptionDirectoryExists := TFileSourceOperationOptionDirectoryExists(GetValue(SubNode, 'DirectoryExists', Integer(gOperationOptionDirectoryExists))); gOperationOptionSetPropertyError := TFileSourceOperationOptionSetPropertyError(GetValue(SubNode, 'SetPropertyError', Integer(gOperationOptionSetPropertyError))); gOperationOptionReserveSpace := GetValue(SubNode, 'ReserveSpace', gOperationOptionReserveSpace); gOperationOptionCheckFreeSpace := GetValue(SubNode, 'CheckFreeSpace', gOperationOptionCheckFreeSpace); gOperationOptionCopyAttributes := GetValue(SubNode, 'CopyAttributes', gOperationOptionCopyAttributes); gOperationOptionCopyXattributes := GetValue(SubNode, 'CopyXattributes', gOperationOptionCopyXattributes); gOperationOptionVerify := GetValue(SubNode, 'Verify', gOperationOptionVerify); gOperationOptionCopyTime := GetValue(SubNode, 'CopyTime', gOperationOptionCopyTime); gOperationOptionCopyOwnership := GetValue(SubNode, 'CopyOwnership', gOperationOptionCopyOwnership); gOperationOptionCopyPermissions := GetValue(SubNode, 'CopyPermissions', gOperationOptionCopyPermissions); gOperationOptionExcludeEmptyDirectories := GetValue(SubNode, 'ExcludeEmptyTemplateDirectories', gOperationOptionExcludeEmptyDirectories); end; // Extract SubNode := Node.FindNode('Extract'); if Assigned(SubNode) then begin gExtractOverwrite := GetValue(SubNode, 'Overwrite', gExtractOverwrite); end; // Multi-Rename SubNode := Node.FindNode('MultiRename'); if Assigned(SubNode) then begin gMulRenShowMenuBarOnTop := GetValue(SubNode, 'MulRenShowMenuBarOnTop', gMulRenShowMenuBarOnTop); gMulRenInvalidCharReplacement := GetValue(SubNode, 'MulRenInvalidCharReplacement', gMulRenInvalidCharReplacement); gMulRenLaunchBehavior := TMulRenLaunchBehavior(GetValue(SubNode, 'MulRenLaunchBehavor', Integer(gMulRenLaunchBehavior))); gMulRenExitModifiedPreset := TMulRenExitModifiedPreset(GetValue(SubNode, 'MulRenExitModifiedPreset', Integer(gMulRenExitModifiedPreset))); gMulRenSaveRenamingLog := TMulRenSaveRenamingLog(GetValue(SubNode, 'MulRenSaveRenamingLog', Integer(gMulRenSaveRenamingLog))); gMulRenLogFilename := GetValue(SubNode, 'MulRenLogFilename', gMulRenLogFilename); gMultRenDailyIndividualDirLog := GetValue(SubNode, 'MultRenDailyIndividualDirLog', gMultRenDailyIndividualDirLog); gMulRenFilenameWithFullPathInLog := GetValue(SubNode, 'MulRenFilenameWithFullPathInLog', gMulRenFilenameWithFullPathInLog); gMulRenPathRangeSeparator := GetValue(SubNode, 'MulRenPathRangeSeparator', gMulRenPathRangeSeparator); end; end; { Tabs page } Node := Root.FindNode('Tabs'); if Assigned(Node) then begin // Loading tabs relating option respecting legacy order of options setting and wanted default values. // The default action on double click is to close tab simply to respect legacy of what it was doing hardcoded before. gDirTabOptions := TTabsOptions(GetValue(Node, 'Options', Integer(gDirTabOptions))); if LoadedConfigVersion<9 then begin gDirTabOptions := gDirTabOptions + [tb_close_on_doubleclick , tb_reusing_tab_when_possible, tb_confirm_close_locked_tab]; //The "tb_close_on_doubleclick" is useless but anyway... :-) gDirTabActionOnDoubleClick:=tadc_CloseTab; end; gDirTabLimit := GetValue(Node, 'CharacterLimit', gDirTabLimit); gDirTabPosition := TTabsPosition(GetValue(Node, 'Position', Integer(gDirTabPosition))); gDirTabActionOnDoubleClick := TTabsOptionsDoubleClick(GetValue(Node, 'ActionOnDoubleClick', Integer(tadc_CloseTab))); end; { Log page } Node := Root.FindNode('Log'); if Assigned(Node) then begin gLogFile := GetAttr(Node, 'Enabled', gLogFile); gLogFileCount := GetAttr(Node, 'Count', gLogFileCount); gLogFileWithDateInName := GetAttr(Node, 'LogFileWithDateInName', gLogFileWithDateInName); gLogFileName := GetValue(Node, 'FileName', gLogFileName); gLogOptions := TLogOptions(GetValue(Node, 'Options', Integer(gLogOptions))); end; { Configuration page } gSaveConfiguration := GetAttr(Root, 'Configuration/Save', gSaveConfiguration); gSaveWindowState := GetAttr(Root, 'MainWindow/Position/Save', gSaveWindowState); gSaveFolderTabs := GetAttr(Root, 'Configuration/FolderTabs/Save', gSaveFolderTabs); gSaveSearchReplaceHistory:= GetAttr(Root, 'History/SearchReplaceHistory/Save', gSaveSearchReplaceHistory); gSaveDirHistory := GetAttr(Root, 'History/DirHistory/Save', gSaveDirHistory); gDirHistoryCount := GetAttr(Root, 'History/DirHistory/Count', gDirHistoryCount); gSaveCmdLineHistory := GetAttr(Root, 'History/CmdLineHistory/Save', gSaveCmdLineHistory); gSaveFileMaskHistory := GetAttr(Root, 'History/FileMaskHistory/Save', gSaveFileMaskHistory); gSaveVolumeSizeHistory := GetAttr(Root, 'History/VolumeSizeHistory/Save', gSaveVolumeSizeHistory); gSaveCreateDirectoriesHistory := GetAttr(Root, 'History/CreateDirectoriesHistory/Save', gSaveCreateDirectoriesHistory); gSortOrderOfConfigurationOptionsTree := TSortConfigurationOptions(GetAttr(Root, 'Configuration/SortOrder', Integer(scoAlphabeticalButLanguage))); gCollapseConfigurationOptionsTree := TConfigurationTreeState(GetAttr(Root, 'Configuration/TreeType', Integer(ctsFullExpand))); { Quick Search/Filter page } Node := Root.FindNode('QuickSearch'); if Assigned(Node) then begin if LoadedConfigVersion < 4 then begin oldQuickSearch := GetAttr(Node, 'Enabled', oldQuickSearch); oldQuickSearchMode := TShiftState(GetValue(Node, 'Mode', Integer(oldQuickSearchMode))); OldKeysToNew(oldQuickSearch, oldQuickSearchMode, ktaQuickSearch); end; if GetValue(Node, 'MatchBeginning', qsmBeginning in gQuickSearchOptions.Match) then Include(gQuickSearchOptions.Match, qsmBeginning) else Exclude(gQuickSearchOptions.Match, qsmBeginning); if GetValue(Node, 'MatchEnding', qsmEnding in gQuickSearchOptions.Match) then Include(gQuickSearchOptions.Match, qsmEnding) else Exclude(gQuickSearchOptions.Match, qsmEnding); gQuickSearchOptions.SearchCase := TQuickSearchCase(GetValue(Node, 'Case', Integer(gQuickSearchOptions.SearchCase))); gQuickSearchOptions.Items := TQuickSearchItems(GetValue(Node, 'Items', Integer(gQuickSearchOptions.Items))); end; Node := Root.FindNode('QuickFilter'); if Assigned(Node) then begin if LoadedConfigVersion < 4 then begin oldQuickFilter := GetAttr(Node, 'Enabled', oldQuickFilter); oldQuickFilterMode := TShiftState(GetValue(Node, 'Mode', Integer(oldQuickFilterMode))); OldKeysToNew(oldQuickFilter, oldQuickFilterMode, ktaQuickFilter); end; gQuickFilterAutoHide := GetValue(Node, 'AutoHide', gQuickFilterAutoHide); gQuickFilterSaveSessionModifications := GetValue(Node, 'SaveSessionModifications', gQuickFilterSaveSessionModifications); end; { Miscellaneous page } Node := Root.FindNode('Miscellaneous'); if Assigned(Node) then begin gGridVertLine := GetValue(Node, 'GridVertLine', gGridVertLine); gGridHorzLine := GetValue(Node, 'GridHorzLine', gGridHorzLine); gShowWarningMessages := GetValue(Node, 'ShowWarningMessages', gShowWarningMessages); gSpaceMovesDown := GetValue(Node, 'SpaceMovesDown', gSpaceMovesDown); gDirBrackets := GetValue(Node, 'DirBrackets', gDirBrackets); gInplaceRename := GetValue(Node, 'InplaceRename', gInplaceRename); gInplaceRenameButton := GetValue(Node, 'InplaceRenameButton', gInplaceRenameButton); gDblClickToParent := GetValue(Node, 'DblClickToParent', gDblClickToParent); gDblClickEditPath := GetValue(Node, 'DoubleClickEditPath', gDblClickEditPath); gHotDirAddTargetOrNot:=GetValue(Node, 'HotDirAddTargetOrNot', gHotDirAddTargetOrNot); gHotDirFullExpandOrNot:=GetValue(Node, 'HotDirFullExpandOrNot', gHotDirFullExpandOrNot); gShowPathInPopup:=GetValue(Node, 'ShowPathInPopup', gShowPathInPopup); gShowOnlyValidEnv:=GetValue(Node, 'ShowOnlyValidEnv', gShowOnlyValidEnv); gWhereToAddNewHotDir:=TPositionWhereToAddHotDir(GetValue(Node, 'WhereToAddNewHotDir', Integer(gWhereToAddNewHotDir))); gHotDirFilenameStyle := TConfigFilenameStyle(GetValue(Node, 'FilenameStyle', ord(gHotDirFilenameStyle))); gHotDirPathToBeRelativeTo := gConfig.GetValue(Node, 'PathToBeRelativeTo', gHotDirPathToBeRelativeTo); gHotDirPathModifierElements := tHotDirPathModifierElements(GetValue(Node, 'PathModifierElements', Integer(gHotDirPathModifierElements))); gDefaultTextEncoding := NormalizeEncoding(GetValue(Node, 'DefaultTextEncoding', gDefaultTextEncoding)); {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} gSystemItemProperties := GetValue(Node, 'SystemItemProperties', gSystemItemProperties); {$ENDIF} DecimalSeparator:= GetValue(Node, 'DecimalSeparator', FormatSettings.DecimalSeparator); if (Length(DecimalSeparator) > 0) and (Ord(DecimalSeparator[1]) < $80) and (DecimalSeparator[1] <> FormatSettings.DecimalSeparator) then begin CustomDecimalSeparator:= DecimalSeparator; FormatSettings.DecimalSeparator:= CustomDecimalSeparator[1]; end; end; { Thumbnails } Node := Root.FindNode('Thumbnails'); if Assigned(Node) then begin gThumbSave := GetAttr(Node, 'Save', gThumbSave); gThumbSize.cx := GetValue(Node, 'Width', gThumbSize.cx); gThumbSize.cy := GetValue(Node, 'Height', gThumbSize.cy); end; { Description } Node := Root.FindNode('Description'); if Assigned(Node) then begin gDescCreateUnicode := GetValue(Node, 'CreateNewUnicode', gDescCreateUnicode); gDescReadEncoding := TMacroEncoding(GetValue(Node, 'DefaultEncoding', Integer(gDescReadEncoding))); gDescWriteEncoding := TMacroEncoding(GetValue(Node, 'CreateNewEncoding', Integer(gDescWriteEncoding))); end; { Auto refresh page } Node := Root.FindNode('AutoRefresh'); if Assigned(Node) then begin gWatchDirs := TWatchOptions(GetValue(Node, 'Options', Integer(gWatchDirs))); gWatchDirsExclude := GetValue(Node, 'ExcludeDirs', gWatchDirsExclude); gWatcherMode := TWatcherMode(GetValue(Node, 'Mode', Integer(gWatcherMode))); end; { Icons page } Node := Root.FindNode('Icons'); if Assigned(Node) then begin gIconTheme := GetValue(Node, 'Theme', gIconTheme); gShowHiddenDimmed := GetValue(Node, 'ShowHiddenDimmed', gShowHiddenDimmed); gShowIcons := TShowIconsMode(GetValue(Node, 'ShowMode', Integer(gShowIcons))); gIconOverlays := GetValue(Node, 'ShowOverlays', gIconOverlays); gIconsSize := GetValue(Node, 'Size', gIconsSize); gDiskIconsSize := GetValue(Node, 'DiskSize', gDiskIconsSize); gDiskIconsAlpha := GetValue(Node, 'DiskAlpha', gDiskIconsAlpha); gToolIconsSize := GetValue(Node, 'ToolSize', gToolIconsSize); gIconsExclude := GetValue(Node, 'Exclude', gIconsExclude); gIconsExcludeDirs := GetValue(Node, 'ExcludeDirs', gIconsExcludeDirs); gPixelsPerInch := GetValue(Node, 'PixelsPerInch', gPixelsPerInch); if LoadedConfigVersion < 10 then begin if GetValue(Node, 'CustomDriveIcons', False) then gCustomIcons += [cimDrive]; DeleteNode(Node, 'CustomDriveIcons'); end; gCustomIcons := TCustomIconsMode(GetValue(Node, 'CustomIcons', Integer(gCustomIcons))); gIconsInMenus := GetAttr(Node, 'ShowInMenus/Enabled', gIconsInMenus); gIconsInMenusSize := GetValue(Node, 'ShowInMenus/Size', gIconsInMenusSize); Application.ShowButtonGlyphs := TApplicationShowGlyphs(GetValue(Node, 'ShowButtonGlyphs', Integer(Application.ShowButtonGlyphs))); end; { Ignore list page } Node := Root.FindNode('IgnoreList'); if Assigned(Node) then begin gIgnoreListFileEnabled:= GetAttr(Node, 'Enabled', gIgnoreListFileEnabled); gIgnoreListFile:= GetValue(Node, 'IgnoreListFile', gIgnoreListFile); end; { Directories HotList } gDirectoryHotlist.LoadFromXML(gConfig, Root); { Viewer } Node := Root.FindNode('Viewer'); if Assigned(Node) then begin gImageStretch := GetValue(Node, 'ImageStretch', gImageStretch); gImageExifRotate := GetValue(Node, 'ImageExifRotate', gImageExifRotate); gImageStretchOnlyLarge := GetValue(Node, 'ImageStretchLargeOnly', gImageStretchOnlyLarge); gImageShowTransparency := GetValue(Node, 'ImageShowTransparency', gImageShowTransparency); gImageCenter := GetValue(Node, 'ImageCenter', gImageCenter); gPreviewVisible := GetValue(Node, 'PreviewVisible', gPreviewVisible); gCopyMovePath1 := GetValue(Node, 'CopyMovePath1', gCopyMovePath1); gCopyMovePath2 := GetValue(Node, 'CopyMovePath2', gCopyMovePath2); gCopyMovePath3 := GetValue(Node, 'CopyMovePath3', gCopyMovePath3); gCopyMovePath4 := GetValue(Node, 'CopyMovePath4', gCopyMovePath4); gCopyMovePath5 := GetValue(Node, 'CopyMovePath5', gCopyMovePath5); gImagePaintMode := TViewerPaintTool(GetValue(Node, 'PaintMode', Integer(gImagePaintMode))); gImagePaintWidth := GetValue(Node, 'PaintWidth', gImagePaintWidth); gColCount := GetValue(Node, 'NumberOfColumns', gColCount); gTabSpaces := GetValue(Node, 'TabSpaces', gTabSpaces); gMaxTextWidth := GetValue(Node, 'MaxTextWidth', gMaxTextWidth); gMaxCodeSize := GetValue(Node, 'MaxCodeSize', gMaxCodeSize); gViewerMode := GetValue(Node, 'ViewerMode' , gViewerMode); gPrintMargins := GetValue(Node, 'PrintMargins' , gPrintMargins); gShowCaret := GetValue(Node, 'ShowCaret' , gShowCaret); gViewerWrapText := GetValue(Node, 'WrapText', gViewerWrapText); gViewerLeftMargin := GetValue(Node, 'LeftMargin' , gViewerLeftMargin); gViewerLineSpacing := GetValue(Node, 'ExtraLineSpan' , gViewerLineSpacing); gImagePaintColor := GetValue(Node, 'PaintColor', gImagePaintColor); gTextPosition := GetValue(Node, 'TextPosition', gTextPosition); gViewerAutoCopy := GetValue(Node, 'AutoCopy', gViewerAutoCopy); gViewerSynEditMask := GetValue(Node, 'SynEditMask', gViewerSynEditMask); gViewerJpegQuality := GetValue(Node, 'JpegQuality', gViewerJpegQuality); if LoadedConfigVersion < 7 then begin gThumbSave := GetValue(Node, 'SaveThumbnails', gThumbSave); end; end; { Editor } Node := Root.FindNode('Editor'); if Assigned(Node) then begin gEditWaitTime := GetValue(Node, 'EditWaitTime', gEditWaitTime); gEditorSynEditOptions := TSynEditorOptions(GetValue(Node, 'SynEditOptions', Integer(gEditorSynEditOptions))); gEditorSynEditTabWidth := GetValue(Node, 'SynEditTabWidth', gEditorSynEditTabWidth); gEditorSynEditRightEdge := GetValue(Node, 'SynEditRightEdge', gEditorSynEditRightEdge); gEditorSynEditBlockIndent := GetValue(Node, 'SynEditBlockIndent', gEditorSynEditBlockIndent); gEditorFindWordAtCursor := GetValue(Node, 'FindWordAtCursor', gEditorFindWordAtCursor); end; { Differ } Node := Root.FindNode('Differ'); if Assigned(Node) then begin gDifferIgnoreCase := GetValue(Node, 'IgnoreCase', gDifferIgnoreCase); gDifferAutoCompare := GetValue(Node, 'AutoCompare', gDifferAutoCompare); gDifferKeepScrolling := GetValue(Node, 'KeepScrolling', gDifferKeepScrolling); gDifferPaintBackground := GetValue(Node, 'PaintBackground', gDifferPaintBackground); gDifferLineDifferences := GetValue(Node, 'LineDifferences', gDifferLineDifferences); gDifferIgnoreWhiteSpace := GetValue(Node, 'IgnoreWhiteSpace', gDifferIgnoreWhiteSpace); end; { SyncDirs } Node := Root.FindNode('SyncDirs'); if Assigned(Node) then begin gSyncDirsSubdirs := GetValue(Node, 'Subdirs', gSyncDirsSubdirs); gSyncDirsByContent := GetValue(Node, 'ByContent', gSyncDirsByContent); gSyncDirsAsymmetric := GetValue(Node, 'Asymmetric', gSyncDirsAsymmetric); gSyncDirsAsymmetricSave := GetAttr(Node, 'Asymmetric/Save', gSyncDirsAsymmetricSave); gSyncDirsIgnoreDate := GetValue(Node, 'IgnoreDate', gSyncDirsIgnoreDate); gSyncDirsShowFilterCopyRight := GetValue(Node, 'FilterCopyRight', gSyncDirsShowFilterCopyRight); gSyncDirsShowFilterEqual := GetValue(Node, 'FilterEqual', gSyncDirsShowFilterEqual); gSyncDirsShowFilterNotEqual := GetValue(Node, 'FilterNotEqual', gSyncDirsShowFilterNotEqual); gSyncDirsShowFilterUnknown := GetValue(Node, 'FilterUnknown', gSyncDirsShowFilterUnknown); gSyncDirsShowFilterCopyLeft := GetValue(Node, 'FilterCopyLeft', gSyncDirsShowFilterCopyLeft); gSyncDirsShowFilterDuplicates := GetValue(Node, 'FilterDuplicates', gSyncDirsShowFilterDuplicates); gSyncDirsShowFilterSingles := GetValue(Node, 'FilterSingles', gSyncDirsShowFilterSingles); gSyncDirsFileMask := GetValue(Node, 'FileMask', gSyncDirsFileMask); gSyncDirsFileMaskSave := GetAttr(Node, 'FileMask/Save', gSyncDirsFileMaskSave); gDateTimeFormatSync := GetValidDateTimeFormat(GetValue(Node, 'DateTimeFormat', gDateTimeFormatSync), DefaultDateTimeFormatSync); end; { Internal Associations} Node := Root.FindNode('InternalAssociations'); if Assigned(Node) then begin gOfferToAddToFileAssociations := GetValue(Node, 'OfferToAddNewFileType', gOfferToAddToFileAssociations); gFileAssociationLastCustomAction := GetValue(Node, 'LastCustomAction', gFileAssociationLastCustomAction); gExtendedContextMenu := GetValue(Node, 'ExpandedContextMenu', gExtendedContextMenu); gDefaultContextActions := GetValue(Node,'DefaultContextActions', gDefaultContextActions); gOpenExecuteViaShell := GetValue(Node,'ExecuteViaShell', gOpenExecuteViaShell); gExecuteViaTerminalClose := GetValue(Node,'OpenSystemWithTerminalClose', gExecuteViaTerminalClose); gExecuteViaTerminalStayOpen := GetValue(Node,'OpenSystemWithTerminalStayOpen', gExecuteViaTerminalStayOpen); gIncludeFileAssociation := GetValue(Node,'IncludeFileAssociation',gIncludeFileAssociation); gFileAssocFilenameStyle := TConfigFilenameStyle(GetValue(Node, 'FilenameStyle', ord(gFileAssocFilenameStyle))); gFileAssocPathToBeRelativeTo := GetValue(Node, 'PathToBeRelativeTo', gFileAssocPathToBeRelativeTo); gFileAssocPathModifierElements := tFileAssocPathModifierElements(GetValue(Node, 'PathModifierElements', Integer(gFileAssocPathModifierElements))); end; { Tree View Menu } Node := Root.FindNode('TreeViewMenu'); if Assigned(Node) then begin gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand := GetValue(Node, 'UseTVMDirectoryHotlistFMC', gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand); gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick := GetValue(Node, 'UseTVMDirectoryHotlistFDC', gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick); gUseTreeViewMenuWithFavoriteTabsFromMenuCommand := GetValue(Node, 'UseTVMFavoriteTabsFMC', gUseTreeViewMenuWithFavoriteTabsFromMenuCommand); gUseTreeViewMenuWithFavoriteTabsFromDoubleClick := GetValue(Node, 'UseTVMFavoriteTabsFDC', gUseTreeViewMenuWithFavoriteTabsFromDoubleClick); gUseTreeViewMenuWithDirHistory := GetValue(Node, 'UseTVMDirHistory', gUseTreeViewMenuWithDirHistory); gUseTreeViewMenuWithViewHistory := GetValue(Node, 'UseTVMViewHistory', gUseTreeViewMenuWithViewHistory); gUseTreeViewMenuWithCommandLineHistory := GetValue(Node, 'UseTVMCommandLineHistory', gUseTreeViewMenuWithCommandLineHistory); gTreeViewMenuShortcutExit := GetValue(Node, 'TreeViewMenuShortcutExit', gTreeViewMenuShortcutExit); gTreeViewMenuSingleClickExit := GetValue(Node, 'TreeViewMenuSingleClickExit', gTreeViewMenuSingleClickExit); gTreeViewMenuDoubleClickExit := GetValue(Node, 'TreeViewMenuDoubleClickExit', gTreeViewMenuDoubleClickExit); for iIndexContextMode:=0 to (ord(tvmcLASTONE)-2) do begin SubNode := Node.FindNode(Format('Context%.2d',[iIndexContextMode])); gTreeViewMenuOptions[iIndexContextMode].CaseSensitive := GetValue(SubNode, 'CaseSensitive', gTreeViewMenuOptions[iIndexContextMode].CaseSensitive); gTreeViewMenuOptions[iIndexContextMode].IgnoreAccents := GetValue(SubNode, 'IgnoreAccents', gTreeViewMenuOptions[iIndexContextMode].IgnoreAccents); gTreeViewMenuOptions[iIndexContextMode].ShowWholeBranchIfMatch := GetValue(SubNode, 'ShowWholeBranchIfMatch', gTreeViewMenuOptions[iIndexContextMode].ShowWholeBranchIfMatch); end; gTreeViewMenuUseKeyboardShortcut := GetValue(Node, 'TreeViewMenuUseKeyboardShortcut', gTreeViewMenuUseKeyboardShortcut); end; { Favorite Tabs } Node := Root.FindNode('FavoriteTabsOptions'); if Assigned(Node) then begin gFavoriteTabsUseRestoreExtraOptions := GetValue(Node, 'FavoriteTabsUseRestoreExtraOptions', gFavoriteTabsUseRestoreExtraOptions); gWhereToAddNewFavoriteTabs := TPositionWhereToAddFavoriteTabs(GetValue(Node, 'WhereToAdd', Integer(gWhereToAddNewFavoriteTabs))); gFavoriteTabsFullExpandOrNot := GetValue(Node, 'Expand', gFavoriteTabsFullExpandOrNot); gFavoriteTabsGoToConfigAfterSave := GetValue(Node, 'GotoConfigAftSav', gFavoriteTabsGoToConfigAfterSave); gFavoriteTabsGoToConfigAfterReSave := GetValue(Node, 'GotoConfigAftReSav', gFavoriteTabsGoToConfigAfterReSave); gDefaultTargetPanelLeftSaved := TTabsConfigLocation(GetValue(Node, 'DfltLeftGoTo', Integer(gDefaultTargetPanelLeftSaved))); gDefaultTargetPanelRightSaved := TTabsConfigLocation(GetValue(Node, 'DfltRightGoTo', Integer(gDefaultTargetPanelRightSaved))); gDefaultExistingTabsToKeep := TTabsConfigLocation(GetValue(Node, 'DfltKeep', Integer(gDefaultExistingTabsToKeep))); gFavoriteTabsSaveDirHistory := GetValue(Node, 'DfltSaveDirHistory', gFavoriteTabsSaveDirHistory); gFavoriteTabsList.LastFavoriteTabsLoadedUniqueId := StringToGUID(GetValue(Node,'FavTabsLastUniqueID',GUIDtoString(DCGetNewGUID))); end; { - Other - } gLuaLib := GetValue(Root, 'Lua/PathToLibrary', gLuaLib); gNameSCFile:= GetValue(Root, 'NameShortcutFile', gNameSCFile); gHotKeySortOrder := THotKeySortOrder(GetValue(Root, 'HotKeySortOrder', Integer(hksoByCommand))); gUseEnterToCloseHotKeyEditor := GetValue(Root,'UseEnterToCloseHotKeyEditor',gUseEnterToCloseHotKeyEditor); gLastUsedPacker:= GetValue(Root, 'LastUsedPacker', gLastUsedPacker); gLastDoAnyCommand:=GetValue(Root, 'LastDoAnyCommand', gLastDoAnyCommand); gbMarkMaskCaseSensitive := GetValue(Root, 'MarkMaskCaseSensitive', gbMarkMaskCaseSensitive); gbMarkMaskIgnoreAccents := GetValue(Root, 'MarkMaskIgnoreAccents', gbMarkMaskIgnoreAccents); gMarkMaskFilterWindows := GetValue(Root, 'MarkMaskFilterWindows', gMarkMaskFilterWindows); gMarkShowWantedAttribute := GetValue(Root, 'MarkShowWantedAttribute', gMarkShowWantedAttribute); gMarkDefaultWantedAttribute := GetValue(Root, 'MarkDefaultWantedAttribute', gMarkDefaultWantedAttribute); gMarkLastWantedAttribute := GetValue(Root, 'MarkLastWantedAttribute', gMarkLastWantedAttribute); { TotalCommander Import/Export } {$IFDEF MSWINDOWS} Node := Root.FindNode('TCSection'); if Assigned(Node) then begin gTotalCommanderExecutableFilename := GetValue(Node, 'TCExecutableFilename', gTotalCommanderExecutableFilename); gTotalCommanderConfigFilename := GetValue(Node, 'TCConfigFilename', gTotalCommanderConfigFilename); gTotalCommanderToolbarPath:=GetValue(Node,'TCToolbarPath',gTotalCommanderToolbarPath); end; {$ENDIF} end; { Search template list } gSearchTemplateList.LoadFromXml(gConfig, Root); { File type colors, load after search templates } Node := Root.FindNode('Colors'); if Assigned(Node) then begin gColorExt.Load(gConfig, Node); end; { Columns sets } ColSet.Load(gConfig, Root); { Plugins } Node := gConfig.FindNode(Root, 'Plugins'); if Assigned(Node) then begin gDSXPlugins.Load(gConfig, Node); gWCXPlugins.Load(gConfig, Node); gWDXPlugins.Load(gConfig, Node); gWFXPlugins.Load(gConfig, Node); gWLXPlugins.Load(gConfig, Node); for iIndexContextMode:=ord(ptDSX) to ord(ptWLX) do begin gTweakPluginWidth[iIndexContextMode]:=gConfig.GetValue(Node, Format('TweakPluginWidth%d',[iIndexContextMode]), 0); gTweakPluginHeight[iIndexContextMode]:=gConfig.GetValue(Node, Format('TweakPluginHeight%d',[iIndexContextMode]), 0); end; gPluginFilenameStyle := TConfigFilenameStyle(gConfig.GetValue(Node, 'PluginFilenameStyle', ord(gPluginFilenameStyle))); gPluginPathToBeRelativeTo := gConfig.GetValue(Node, 'PluginPathToBeRelativeTo', gPluginPathToBeRelativeTo); gPluginInAutoTweak := gConfig.GetValue(Node, 'AutoTweak', gPluginInAutoTweak); gWCXConfigViewMode := TWcxCfgViewMode(gConfig.GetValue(Node, 'WCXConfigViewMode', Integer(gWCXConfigViewMode))); end; gWDXPlugins.Add(TExifWdx.Create); { Load content plugins used in search templates } LoadContentPlugins; end; procedure SaveXmlConfig; procedure SetExtTool(Node: TXmlNode; const ExternalToolOptions: TExternalToolOptions); begin if Assigned(Node) then with ExternalToolOptions do begin gConfig.SetAttr(Node, 'Enabled', Enabled); gConfig.SetValue(Node, 'Path', Path); gConfig.SetValue(Node, 'Parameters', Parameters); gConfig.SetValue(Node, 'RunInTerminal', RunInTerminal); gConfig.SetValue(Node, 'KeepTerminalOpen', KeepTerminalOpen); end; end; procedure SetDCFont(Node: TXmlNode; const FontOptions: TDCFontOptions); begin if Assigned(Node) then gConfig.SetFont(Node, '', FontOptions.Name, FontOptions.Size, Integer(FontOptions.Style), Integer(FontOptions.Quality)); end; var Root, Node, SubNode: TXmlNode; KeyTypingModifier: TKeyTypingModifier; iIndexContextMode: integer; begin with gConfig do begin Root := gConfig.RootNode; SetAttr(Root, 'DCVersion', dcVersion); SetAttr(Root, 'ConfigVersion', ConfigVersion); { Language page } SetValue(Root, 'Language/POFileName', gPOFileName); { Behaviours page } Node := FindNode(Root, 'Behaviours', True); ClearNode(Node); SetValue(Node, 'GoToRoot', gGoToRoot); SetValue(Node, 'ShowCurDirTitleBar', gShowCurDirTitleBar); SetValue(Node, 'ActiveRight', gActiveRight); SetValue(Node, 'RunInTerminalStayOpenCmd', gRunInTermStayOpenCmd); SetValue(Node, 'RunInTerminalStayOpenParams', gRunInTermStayOpenParams); SetValue(Node, 'RunInTerminalCloseCmd', gRunInTermCloseCmd); SetValue(Node, 'RunInTerminalCloseParams', gRunInTermCloseParams); SetValue(Node, 'JustRunTerminal', gRunTermCmd); SetValue(Node, 'JustRunTermParams', gRunTermParams); SetValue(Node, 'OnlyOneAppInstance', gOnlyOneAppInstance); SetValue(Node, 'LynxLike', gLynxLike); SetValue(Node, 'FileSizeFormat', Ord(gFileSizeFormat)); SetValue(Node, 'OperationSizeFormat', Ord(gOperationSizeFormat)); SetValue(Node, 'HeaderSizeFormat', Ord(gHeaderSizeFormat)); SetValue(Node, 'FooterSizeFormat', Ord(gFooterSizeFormat)); SetValue(Node, 'FileSizeDigits', gFileSizeDigits); SetValue(Node, 'HeaderDigits', gHeaderDigits); SetValue(Node, 'FooterDigits', gFooterDigits); SetValue(Node, 'OperationSizeDigits', gOperationSizeDigits); SetValue(Node, 'PersonalizedByte', Trim(gSizeDisplayUnits[fsfPersonalizedByte])); SetValue(Node, 'PersonalizedKilo', Trim(gSizeDisplayUnits[fsfPersonalizedKilo])); SetValue(Node, 'PersonalizedMega', Trim(gSizeDisplayUnits[fsfPersonalizedMega])); SetValue(Node, 'PersonalizedGiga', Trim(gSizeDisplayUnits[fsfPersonalizedGiga])); SetValue(Node, 'PersonalizedTera', Trim(gSizeDisplayUnits[fsfPersonalizedTera])); SetValue(Node, 'ConfirmQuit', gConfirmQuit); SetValue(Node, 'MinimizeToTray', gMinimizeToTray); SetValue(Node, 'AlwaysShowTrayIcon', gAlwaysShowTrayIcon); SubNode := FindNode(Node, 'Mouse', True); SetAttr(SubNode, 'Selection/Enabled', gMouseSelectionEnabled); SetValue(SubNode, 'Selection/Button', gMouseSelectionButton); SetValue(SubNode, 'SingleClickStart', gMouseSingleClickStart); SetValue(SubNode, 'Selection/IconClick', gMouseSelectionIconClick); SetValue(SubNode, 'ScrollMode', Integer(gScrollMode)); SetValue(SubNode, 'WheelScrollLines', gWheelScrollLines); SetValue(Node, 'AutoFillColumns', gAutoFillColumns); SetValue(Node, 'AutoSizeColumn', gAutoSizeColumn); SetValue(Node, 'CustomColumnsChangeAllColumns', gCustomColumnsChangeAllColumns); SetValue(Node, 'BriefViewFileExtAligned', gBriefViewFileExtAligned); SetValue(Node, 'DateTimeFormat', gDateTimeFormat); SetValue(Node, 'ColumnsTitleLikeValues', gColumnsTitleLikeValues); SetValue(Node, 'CutTextToColumnWidth', gCutTextToColWidth); SetValue(Node, 'ExtendCellWidth', gExtendCellWidth); SetValue(Node, 'ShowSystemFiles', gShowSystemFiles); {$IFNDEF LCLCARBON} // Under Mac OS X loading file list in separate thread are very very slow // so disable and hide this option under Mac OS X Carbon SetValue(Node, 'ListFilesInThread', gListFilesInThread); {$ENDIF} SetValue(Node, 'LoadIconsSeparately', gLoadIconsSeparately); SetValue(Node, 'DelayLoadingTabs', gDelayLoadingTabs); SetValue(Node, 'HighlightUpdatedFiles', gHighlightUpdatedFiles); SetValue(Node, 'DriveBlackList', gDriveBlackList); SetValue(Node, 'DriveBlackListUnmounted', gDriveBlackListUnmounted); { Tools page } SetExtTool(gConfig.FindNode(Root, 'Tools/Viewer', True), gExternalTools[etViewer]); SetExtTool(gConfig.FindNode(Root, 'Tools/Editor', True), gExternalTools[etEditor]); SetExtTool(gConfig.FindNode(Root, 'Tools/Differ', True), gExternalTools[etDiffer]); { Differ related} Node := Root.FindNode('Tools'); SubNode := FindNode(Node, 'Differ', TRUE); SetValue(SubNode, 'FramePosAfterComp', Integer(gResultingFramePositionAfterCompare)); { Fonts page } SetDCFont(gConfig.FindNode(Root, 'Fonts/Main', True), gFonts[dcfMain]); SetDCFont(gConfig.FindNode(Root, 'Fonts/Editor', True), gFonts[dcfEditor]); SetDCFont(gConfig.FindNode(Root, 'Fonts/Viewer', True), gFonts[dcfViewer]); SetDCFont(gConfig.FindNode(Root, 'Fonts/ViewerBook', True), gFonts[dcfViewerBook]); SetDCFont(gConfig.FindNode(Root, 'Fonts/Log', True), gFonts[dcfLog]); SetDCFont(gConfig.FindNode(Root, 'Fonts/Console', True), gFonts[dcfConsole]); SetDCFont(gConfig.FindNode(Root, 'Fonts/PathEdit',True), gFonts[dcfPathEdit]); SetDCFont(gConfig.FindNode(Root, 'Fonts/FunctionButtons',True), gFonts[dcfFunctionButtons]); SetDCFont(gConfig.FindNode(Root, 'Fonts/SearchResults',True), gFonts[dcfSearchResults]); SetDCFont(gConfig.FindNode(Root, 'Fonts/TreeViewMenu', True), gFonts[dcfTreeViewMenu]); SetDCFont(gConfig.FindNode(Root, 'Fonts/StatusBar', True), gFonts[dcfStatusBar]); { Colors page } Node := FindNode(Root, 'Colors', True); SetValue(Node, 'UseCursorBorder', gUseCursorBorder); SetValue(Node, 'UseFrameCursor', gUseFrameCursor); SetValue(Node, 'UseInvertedSelection', gUseInvertedSelection); SetValue(Node, 'UseInactiveSelColor', gUseInactiveSelColor); SetValue(Node, 'AllowOverColor', gAllowOverColor); SetValue(Node, 'gBorderFrameWidth', gBorderFrameWidth); SetValue(Node, 'InactivePanelBrightness', gInactivePanelBrightness); SetValue(Node, 'FreeSpaceIndicator/UseGradient', gIndUseGradient); gColorExt.Save(gConfig, Node); { ToolTips page } Node := FindNode(Root, 'ToolTips', True); SetValue(Node, 'ShowToolTipMode', gShowToolTip); SetValue(Node, 'ActualToolTipMode', Integer(gShowToolTipMode)); SetValue(Node, 'ToolTipHideTimeOut', Integer(gToolTipHideTimeOut)); gFileInfoToolTip.Save(gConfig, Node); { Layout page } Node := FindNode(Root, 'Layout', True); ClearNode(Node); SetValue(Node, 'MainMenu', gMainMenu); SubNode := FindNode(Node, 'ButtonBar', True); SetAttr(SubNode, 'Enabled', gButtonBar); SetValue(SubNode, 'FlatIcons', gToolBarFlat); SetValue(SubNode, 'ButtonHeight', gToolBarButtonSize); SetValue(SubNode, 'IconSize', gToolBarIconSize); SetValue(SubNode, 'ShowCaptions', gToolBarShowCaptions); SetValue(SubNode, 'ReportErrorWithCommands', gToolbarReportErrorWithCommands); SetValue(SubNode, 'FilenameStyle', ord(gToolbarFilenameStyle)); SetValue(SubNode, 'PathToBeRelativeTo', gToolbarPathToBeRelativeTo); SetValue(SubNode, 'PathModifierElements', Integer(gToolbarPathModifierElements)); SubNode := FindNode(Node, 'MiddleBar', True); SetAttr(SubNode, 'Enabled', gMiddleToolBar); SetValue(SubNode, 'FlatIcons', gMiddleToolBarFlat); SetValue(SubNode, 'ButtonHeight', gMiddleToolBarButtonSize); SetValue(SubNode, 'IconSize', gMiddleToolBarIconSize); SetValue(SubNode, 'ShowCaptions', gMiddleToolBarShowCaptions); SetValue(SubNode,'ReportErrorWithCommands', gMiddleToolbarReportErrorWithCommands); SetValue(Node, 'DriveBar1', gDriveBar1); SetValue(Node, 'DriveBar2', gDriveBar2); SetValue(Node, 'DriveBarFlat', gDriveBarFlat); SubNode := FindNode(Node, 'DrivesListButton', True); SetAttr(SubNode, 'Enabled', gDrivesListButton); SetValue(SubNode, 'ShowLabel', dlbShowLabel in gDrivesListButtonOptions); SetValue(SubNode, 'ShowFileSystem', dlbShowFileSystem in gDrivesListButtonOptions); SetValue(SubNode, 'ShowFreeSpace', dlbShowFreeSpace in gDrivesListButtonOptions); SetValue(Node, 'SeparateTree', gSeparateTree); SetValue(Node, 'DirectoryTabs', gDirectoryTabs); SetValue(Node, 'CurrentDirectory', gCurDir); SetValue(Node, 'TabHeader', gTabHeader); SetValue(Node, 'StatusBar', gStatusBar); SetValue(Node, 'CmdLine', gCmdLine); SetValue(Node, 'LogWindow', gLogWindow); SetValue(Node, 'TermWindow', gTermWindow); SetValue(Node, 'KeyButtons', gKeyButtons); SetValue(Node, 'InterfaceFlat', gInterfaceFlat); SetValue(Node, 'DriveFreeSpace', gDriveFreeSpace); SetValue(Node, 'DriveIndicator', gDriveInd); SetValue(Node, 'ProgressInMenuBar', gProgInMenuBar); SetValue(Node, 'PanelOfOperationsInBackground', gPanelOfOp); SetValue(Node, 'HorizontalFilePanels', gHorizontalFilePanels); SetValue(Node, 'ShortFormatDriveInfo', gShortFormatDriveInfo); SetValue(Node, 'UppercaseDriveLetter', gUpperCaseDriveLetter); SetValue(Node, 'ShowColonAfterDrive', gShowColonAfterDrive); { Files views } Node := FindNode(Root, 'FilesViews', True); SubNode := FindNode(Node, 'Sorting', True); SetValue(SubNode, 'CaseSensitivity', Integer(gSortCaseSensitivity)); SetValue(SubNode, 'NaturalSorting', gSortNatural); SetValue(SubNode, 'SpecialSorting', gSortSpecial); SetValue(SubNode, 'SortFolderMode', Integer(gSortFolderMode)); SetValue(SubNode, 'NewFilesPosition', Integer(gNewFilesPosition)); SetValue(SubNode, 'UpdatedFilesPosition', Integer(gUpdatedFilesPosition)); SubNode := FindNode(Node, 'ColumnsView', True); SetValue(SubNode, 'LongInStatus', gColumnsLongInStatus); SetValue(SubNode, 'AutoSaveWidth', gColumnsAutoSaveWidth); SetValue(SubNode, 'TitleStyle', Integer(gColumnsTitleStyle)); SubNode := FindNode(Node, 'BriefView', True); SetValue(SubNode, 'FileExtAligned', gBriefViewFileExtAligned); SubNode := FindNode(SubNode, 'Columns', True); SetValue(SubNode, 'FixedWidth', gBriefViewFixedWidth); SetValue(SubNode, 'FixedCount', gBriefViewFixedCount); SetValue(SubNode, 'AutoSize', Integer(gBriefViewMode)); SetValue(Node, 'ExtraLineSpan', gExtraLineSpan); SetValue(Node, 'FolderPrefix', gFolderPrefix); SetValue(Node, 'FolderPostfix', gFolderPostfix); SetValue(Node, 'RenameConfirmMouse', gRenameConfirmMouse); { Keys page } Node := FindNode(Root, 'Keyboard', True); SubNode := FindNode(Node, 'Typing/Actions', True); for KeyTypingModifier in TKeyTypingModifier do SetValue(SubNode, TKeyTypingModifierToNodeName[KeyTypingModifier], Integer(gKeyTyping[KeyTypingModifier])); { File operations page } Node := FindNode(Root, 'FileOperations', True); SetValue(Node, 'BufferSize', gCopyBlockSize); SetValue(Node, 'LongNameAlert', gLongNameAlert); SetValue(Node, 'HashBufferSize', gHashBlockSize); SetValue(Node, 'UseMmapInSearch', gUseMmapInSearch); SetValue(Node, 'PartialNameSearch', gPartialNameSearch); SetValue(Node, 'InitiallyClearFileMask', gInitiallyClearFileMask); SetValue(Node, 'NewSearchClearFiltersAction', integer(gNewSearchClearFiltersAction)); SetValue(Node, 'ShowMenuBarInFindFiles', gShowMenuBarInFindFiles); SetValue(Node, 'WipePassNumber', gWipePassNumber); SetValue(Node, 'DropReadOnlyFlag', gDropReadOnlyFlag); SetValue(Node, 'ProcessComments', gProcessComments); SetValue(Node, 'RenameSelOnlyName', gRenameSelOnlyName); SetValue(Node, 'ShowCopyTabSelectPanel', gShowCopyTabSelectPanel); SetValue(Node, 'UseTrash', gUseTrash); SetValue(Node, 'SkipFileOpError', gSkipFileOpError); SetValue(Node, 'TypeOfDuplicatedRename', Integer(gTypeOfDuplicatedRename)); SetValue(Node, 'DefaultDropEffect', gDefaultDropEffect); SetValue(Node, 'ShowDialogOnDragDrop', gShowDialogOnDragDrop); SetValue(Node, 'DragAndDropTextRichtextDesireLevel', gDragAndDropDesiredTextFormat[DropTextRichText_Index].DesireLevel); SetValue(Node, 'DragAndDropTextHtmlDesireLevel',gDragAndDropDesiredTextFormat[DropTextHtml_Index].DesireLevel); SetValue(Node, 'DragAndDropTextUnicodeDesireLevel',gDragAndDropDesiredTextFormat[DropTextUnicode_Index].DesireLevel); SetValue(Node, 'DragAndDropTextSimpletextDesireLevel',gDragAndDropDesiredTextFormat[DropTextSimpleText_Index].DesireLevel); SetValue(Node, 'DragAndDropAskFormatEachTime', gDragAndDropAskFormatEachTime); SetValue(Node, 'DragAndDropTextAutoFilename', gDragAndDropTextAutoFilename); SetValue(Node, 'DragAndDropSaveUnicodeTextInUFT8', gDragAndDropSaveUnicodeTextInUFT8); SetValue(Node, 'NtfsHourTimeDelay', gNtfsHourTimeDelay); SetValue(Node, 'AutoExtractOpenMask', gAutoExtractOpenMask); SetValue(Node, 'SearchDefaultTemplate', gSearchDefaultTemplate); SetValue(Node, 'ProgressKind', Integer(gFileOperationsProgressKind)); SetValue(Node, 'Confirmations', Integer(gFileOperationsConfirmations)); // Operations options SubNode := FindNode(Node, 'Options', True); SetValue(SubNode, 'Symlink', Integer(gOperationOptionSymLinks)); SetValue(SubNode, 'CorrectLinks', gOperationOptionCorrectLinks); SetValue(SubNode, 'CopyOnWrite', Integer(gOperationOptionCopyOnWrite)); SetValue(SubNode, 'FileExists', Integer(gOperationOptionFileExists)); SetValue(SubNode, 'DirectoryExists', Integer(gOperationOptionDirectoryExists)); SetValue(SubNode, 'SetPropertyError', Integer(gOperationOptionSetPropertyError)); SetValue(SubNode, 'ReserveSpace', gOperationOptionReserveSpace); SetValue(SubNode, 'CheckFreeSpace', gOperationOptionCheckFreeSpace); SetValue(SubNode, 'CopyAttributes', gOperationOptionCopyAttributes); SetValue(SubNode, 'CopyXattributes', gOperationOptionCopyXattributes); SetValue(SubNode, 'Verify', gOperationOptionVerify); SetValue(SubNode, 'CopyTime', gOperationOptionCopyTime); SetValue(SubNode, 'CopyOwnership', gOperationOptionCopyOwnership); SetValue(SubNode, 'CopyPermissions', gOperationOptionCopyPermissions); SetValue(SubNode, 'ExcludeEmptyTemplateDirectories', gOperationOptionExcludeEmptyDirectories); // Extract SubNode := FindNode(Node, 'Extract', True); if Assigned(SubNode) then begin SetValue(SubNode, 'Overwrite', gExtractOverwrite); end; // Multi-Rename SubNode := FindNode(Node, 'MultiRename', True); SetValue(SubNode, 'MulRenShowMenuBarOnTop', gMulRenShowMenuBarOnTop); SetValue(SubNode, 'MulRenInvalidCharReplacement', gMulRenInvalidCharReplacement); SetValue(SubNode, 'MulRenLaunchBehavor', Integer(gMulRenLaunchBehavior)); SetValue(SubNode, 'MulRenExitModifiedPreset', Integer(gMulRenExitModifiedPreset)); SetValue(SubNode, 'MulRenSaveRenamingLog', Integer(gMulRenSaveRenamingLog)); SetValue(SubNode, 'MulRenLogFilename', gMulRenLogFilename); SetValue(SubNode, 'MultRenDailyIndividualDirLog', gMultRenDailyIndividualDirLog); SetValue(SubNode, 'MulRenFilenameWithFullPathInLog', gMulRenFilenameWithFullPathInLog); SetValue(SubNode, 'MulRenPathRangeSeparator', gMulRenPathRangeSeparator); { Tabs page } Node := FindNode(Root, 'Tabs', True); SetValue(Node, 'Options', Integer(gDirTabOptions)); SetValue(Node, 'CharacterLimit', gDirTabLimit); SetValue(Node, 'Position', Integer(gDirTabPosition)); SetValue(Node, 'ActionOnDoubleClick',Integer(gDirTabActionOnDoubleClick)); { Log page } Node := FindNode(Root, 'Log', True); SetAttr(Node, 'Enabled', gLogFile); SetAttr(Node, 'Count', gLogFileCount); SetAttr(Node, 'LogFileWithDateInName', gLogFileWithDateInName); SetValue(Node, 'FileName', gLogFileName); SetValue(Node, 'Options', Integer(gLogOptions)); { Configuration page } SetAttr(Root, 'Configuration/Save', gSaveConfiguration); SetAttr(Root, 'MainWindow/Position/Save', gSaveWindowState); SetAttr(Root, 'Configuration/FolderTabs/Save', gSaveFolderTabs); SetAttr(Root, 'History/SearchReplaceHistory/Save', gSaveSearchReplaceHistory); SetAttr(Root, 'History/DirHistory/Save', gSaveDirHistory); SetAttr(Root, 'History/DirHistory/Count', gDirHistoryCount); SetAttr(Root, 'History/CmdLineHistory/Save', gSaveCmdLineHistory); SetAttr(Root, 'History/FileMaskHistory/Save', gSaveFileMaskHistory); SetAttr(Root, 'History/VolumeSizeHistory/Save', gSaveVolumeSizeHistory); SetAttr(Root, 'History/CreateDirectoriesHistory/Save', gSaveCreateDirectoriesHistory); SetAttr(Root, 'Configuration/SortOrder', Integer(gSortOrderOfConfigurationOptionsTree)); SetAttr(Root, 'Configuration/TreeType', Integer(gCollapseConfigurationOptionsTree)); { Quick Search/Filter page } Node := FindNode(Root, 'QuickSearch', True); SetValue(Node, 'MatchBeginning', qsmBeginning in gQuickSearchOptions.Match); SetValue(Node, 'MatchEnding', qsmEnding in gQuickSearchOptions.Match); SetValue(Node, 'Case', Integer(gQuickSearchOptions.SearchCase)); SetValue(Node, 'Items', Integer(gQuickSearchOptions.Items)); Node := FindNode(Root, 'QuickFilter', True); SetValue(Node, 'AutoHide', gQuickFilterAutoHide); SetValue(Node, 'SaveSessionModifications', gQuickFilterSaveSessionModifications); { Misc page } Node := FindNode(Root, 'Miscellaneous', True); SetValue(Node, 'GridVertLine', gGridVertLine); SetValue(Node, 'GridHorzLine', gGridHorzLine); SetValue(Node, 'ShowWarningMessages', gShowWarningMessages); SetValue(Node, 'SpaceMovesDown', gSpaceMovesDown); SetValue(Node, 'DirBrackets', gDirBrackets); SetValue(Node, 'InplaceRename', gInplaceRename); SetValue(Node, 'InplaceRenameButton', gInplaceRenameButton); SetValue(Node, 'DblClickToParent', gDblClickToParent); SetValue(Node, 'DoubleClickEditPath', gDblClickEditPath); SetValue(Node, 'HotDirAddTargetOrNot',gHotDirAddTargetOrNot); SetValue(Node, 'HotDirFullExpandOrNot', gHotDirFullExpandOrNot); SetValue(Node, 'ShowPathInPopup', gShowPathInPopup); SetValue(Node, 'ShowOnlyValidEnv', gShowOnlyValidEnv); SetValue(Node, 'WhereToAddNewHotDir', Integer(gWhereToAddNewHotDir)); SetValue(Node, 'FilenameStyle', ord(gHotDirFilenameStyle)); SetValue(Node, 'PathToBeRelativeTo', gHotDirPathToBeRelativeTo); SetValue(Node, 'PathModifierElements', Integer(gHotDirPathModifierElements)); SetValue(Node, 'DefaultTextEncoding', gDefaultTextEncoding); {$IF DEFINED(UNIX) AND NOT (DEFINED(DARWIN) OR DEFINED(HAIKU))} SetValue(Node, 'SystemItemProperties', gSystemItemProperties); {$ENDIF} SetValue(Node, 'DecimalSeparator', CustomDecimalSeparator); { Thumbnails } Node := FindNode(Root, 'Thumbnails', True); SetAttr(Node, 'Save', gThumbSave); SetValue(Node, 'Width', gThumbSize.cx); SetValue(Node, 'Height', gThumbSize.cy); { Description } Node := FindNode(Root, 'Description', True); SetValue(Node, 'CreateNewUnicode', gDescCreateUnicode); SetValue(Node, 'DefaultEncoding', Integer(gDescReadEncoding)); SetValue(Node, 'CreateNewEncoding', Integer(gDescWriteEncoding)); { Auto refresh page } Node := FindNode(Root, 'AutoRefresh', True); SetValue(Node, 'Options', Integer(gWatchDirs)); SetValue(Node, 'ExcludeDirs', gWatchDirsExclude); SetValue(Node, 'Mode', Integer(gWatcherMode)); { Icons page } Node := FindNode(Root, 'Icons', True); SetValue(Node, 'Theme', gIconTheme); SetValue(Node, 'ShowHiddenDimmed', gShowHiddenDimmed); SetValue(Node, 'ShowMode', Integer(gShowIconsNew)); SetValue(Node, 'ShowOverlays', gIconOverlays); SetValue(Node, 'Size', gIconsSizeNew); SetValue(Node, 'DiskSize', gDiskIconsSize); SetValue(Node, 'DiskAlpha', gDiskIconsAlpha); SetValue(Node, 'ToolSize', gToolIconsSize); SetValue(Node, 'Exclude', gIconsExclude); SetValue(Node, 'ExcludeDirs', gIconsExcludeDirs); SetValue(Node, 'CustomIcons', Integer(gCustomIcons)); SetValue(Node, 'PixelsPerInch', Screen.PixelsPerInch); SetAttr(Node, 'ShowInMenus/Enabled', gIconsInMenus); SetValue(Node, 'ShowInMenus/Size', gIconsInMenusSizeNew); SetValue(Node, 'ShowButtonGlyphs', Integer(Application.ShowButtonGlyphs)); { Ignore list page } Node := FindNode(Root, 'IgnoreList', True); SetAttr(Node, 'Enabled', gIgnoreListFileEnabled); SetValue(Node, 'IgnoreListFile', gIgnoreListFile); { Directories HotList } gDirectoryHotlist.SaveToXml(gConfig, Root, TRUE); { Viewer } Node := FindNode(Root, 'Viewer',True); SetValue(Node, 'PreviewVisible',gPreviewVisible); SetValue(Node, 'ImageStretch',gImageStretch); SetValue(Node, 'ImageExifRotate', gImageExifRotate); SetValue(Node, 'ImageStretchLargeOnly', gImageStretchOnlyLarge); SetValue(Node, 'ImageShowTransparency', gImageShowTransparency); SetValue(Node, 'ImageCenter', gImageCenter); SetValue(Node, 'CopyMovePath1', gCopyMovePath1); SetValue(Node, 'CopyMovePath2', gCopyMovePath2); SetValue(Node, 'CopyMovePath3', gCopyMovePath3); SetValue(Node, 'CopyMovePath4', gCopyMovePath4); SetValue(Node, 'CopyMovePath5', gCopyMovePath5); SetValue(Node, 'PaintMode', Integer(gImagePaintMode)); SetValue(Node, 'PaintWidth', gImagePaintWidth); SetValue(Node, 'NumberOfColumns', gColCount); SetValue(Node, 'TabSpaces', gTabSpaces); SetValue(Node, 'MaxCodeSize', gMaxCodeSize); SetValue(Node, 'MaxTextWidth', gMaxTextWidth); SetValue(Node, 'ViewerMode' , gViewerMode); SetValue(Node, 'PrintMargins', gPrintMargins); SetValue(Node, 'ShowCaret' , gShowCaret); SetValue(Node, 'WrapText' , gViewerWrapText); SetValue(Node, 'LeftMargin' , gViewerLeftMargin); SetValue(Node, 'ExtraLineSpan' , gViewerLineSpacing); SetValue(Node, 'PaintColor', gImagePaintColor); SetValue(Node, 'TextPosition', gTextPosition); SetValue(Node, 'AutoCopy', gViewerAutoCopy); SetValue(Node, 'SynEditMask', gViewerSynEditMask); SetValue(Node, 'JpegQuality', gViewerJpegQuality); { Editor } Node := FindNode(Root, 'Editor',True); SetValue(Node, 'EditWaitTime', gEditWaitTime); SetValue(Node, 'SynEditOptions', Integer(gEditorSynEditOptions)); SetValue(Node, 'SynEditTabWidth', gEditorSynEditTabWidth); SetValue(Node, 'SynEditRightEdge', gEditorSynEditRightEdge); SetValue(Node, 'SynEditBlockIndent', gEditorSynEditBlockIndent); SetValue(Node, 'FindWordAtCursor', gEditorFindWordAtCursor); { Differ } Node := FindNode(Root, 'Differ',True); SetValue(Node, 'IgnoreCase', gDifferIgnoreCase); SetValue(Node, 'AutoCompare', gDifferAutoCompare); SetValue(Node, 'KeepScrolling', gDifferKeepScrolling); SetValue(Node, 'PaintBackground', gDifferPaintBackground); SetValue(Node, 'LineDifferences', gDifferLineDifferences); SetValue(Node, 'IgnoreWhiteSpace', gDifferIgnoreWhiteSpace); { SyncDirs } Node := FindNode(Root, 'SyncDirs', True); SetValue(Node, 'Subdirs', gSyncDirsSubdirs); SetValue(Node, 'ByContent', gSyncDirsByContent); SetValue(Node, 'Asymmetric', gSyncDirsAsymmetric and gSyncDirsAsymmetricSave); SetAttr(Node, 'Asymmetric/Save', gSyncDirsAsymmetricSave); SetValue(Node, 'IgnoreDate', gSyncDirsIgnoreDate); SetValue(Node, 'FilterCopyRight', gSyncDirsShowFilterCopyRight); SetValue(Node, 'FilterEqual', gSyncDirsShowFilterEqual); SetValue(Node, 'FilterNotEqual', gSyncDirsShowFilterNotEqual); SetValue(Node, 'FilterUnknown', gSyncDirsShowFilterUnknown); SetValue(Node, 'FilterCopyLeft', gSyncDirsShowFilterCopyLeft); SetValue(Node, 'FilterDuplicates', gSyncDirsShowFilterDuplicates); SetValue(Node, 'FilterSingles', gSyncDirsShowFilterSingles); SetValue(Node, 'FileMask', gSyncDirsFileMask); SetAttr(Node, 'FileMask/Save', gSyncDirsFileMaskSave); SetValue(Node, 'DateTimeFormat', gDateTimeFormatSync); { Internal Associations} Node := FindNode(Root, 'InternalAssociations', True); SetValue(Node, 'OfferToAddNewFileType', gOfferToAddToFileAssociations); SetValue(Node, 'LastCustomAction', gFileAssociationLastCustomAction); SetValue(Node, 'ExpandedContextMenu', gExtendedContextMenu); SetValue(Node, 'DefaultContextActions', gDefaultContextActions); SetValue(Node, 'ExecuteViaShell', gOpenExecuteViaShell); SetValue(Node, 'OpenSystemWithTerminalClose', gExecuteViaTerminalClose); SetValue(Node, 'OpenSystemWithTerminalStayOpen', gExecuteViaTerminalStayOpen); SetValue(Node, 'IncludeFileAssociation', gIncludeFileAssociation); SetValue(Node, 'FilenameStyle', ord(gFileAssocFilenameStyle)); SetValue(Node, 'PathToBeRelativeTo', gFileAssocPathToBeRelativeTo); SetValue(Node, 'PathModifierElements', Integer(gFileAssocPathModifierElements)); { Tree View Menu } Node := FindNode(Root, 'TreeViewMenu', True); SetValue(Node, 'UseTVMDirectoryHotlistFMC', gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand); SetValue(Node, 'UseTVMDirectoryHotlistFDC', gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick); SetValue(Node, 'UseTVMFavoriteTabsFMC', gUseTreeViewMenuWithFavoriteTabsFromMenuCommand); SetValue(Node, 'UseTVMFavoriteTabsFDC', gUseTreeViewMenuWithFavoriteTabsFromDoubleClick); SetValue(Node, 'UseTVMDirHistory', gUseTreeViewMenuWithDirHistory); SetValue(Node, 'UseTVMViewHistory', gUseTreeViewMenuWithViewHistory); SetValue(Node, 'UseTVMCommandLineHistory', gUseTreeViewMenuWithCommandLineHistory); SetValue(Node, 'TreeViewMenuShortcutExit', gTreeViewMenuShortcutExit); SetValue(Node, 'TreeViewMenuSingleClickExit', gTreeViewMenuSingleClickExit); SetValue(Node, 'TreeViewMenuDoubleClickExit', gTreeViewMenuDoubleClickExit); for iIndexContextMode:=0 to (ord(tvmcLASTONE)-2) do begin SubNode := FindNode(Node, Format('Context%.2d',[iIndexContextMode]), True); SetValue(SubNode, 'CaseSensitive', gTreeViewMenuOptions[iIndexContextMode].CaseSensitive); SetValue(SubNode, 'IgnoreAccents', gTreeViewMenuOptions[iIndexContextMode].IgnoreAccents); SetValue(SubNode, 'ShowWholeBranchIfMatch', gTreeViewMenuOptions[iIndexContextMode].ShowWholeBranchIfMatch); end; SetValue(Node, 'TreeViewMenuUseKeyboardShortcut', gTreeViewMenuUseKeyboardShortcut); { Favorite Tabs } Node := FindNode(Root, 'FavoriteTabsOptions', True); SetValue(Node, 'FavoriteTabsUseRestoreExtraOptions', gFavoriteTabsUseRestoreExtraOptions); SetValue(Node, 'WhereToAdd', Integer(gWhereToAddNewFavoriteTabs)); SetValue(Node, 'Expand', gFavoriteTabsFullExpandOrNot); SetValue(Node, 'GotoConfigAftSav', gFavoriteTabsGoToConfigAfterSave); SetValue(Node, 'GotoConfigAftReSav', gFavoriteTabsGoToConfigAfterReSave); SetValue(Node, 'DfltLeftGoTo', Integer(gDefaultTargetPanelLeftSaved)); SetValue(Node, 'DfltRightGoTo', Integer(gDefaultTargetPanelRightSaved)); SetValue(Node, 'DfltKeep', Integer(gDefaultExistingTabsToKeep)); SetValue(Node, 'DfltSaveDirHistory', gFavoriteTabsSaveDirHistory); SetValue(Node, 'FavTabsLastUniqueID',GUIDtoString(gFavoriteTabsList.LastFavoriteTabsLoadedUniqueId)); { - Other - } SetValue(Root, 'Lua/PathToLibrary', gLuaLib); SetValue(Root, 'NameShortcutFile', gNameSCFile); SetValue(Root, 'HotKeySortOrder', Integer(gHotKeySortOrder)); SetValue(Root, 'UseEnterToCloseHotKeyEditor', gUseEnterToCloseHotKeyEditor); SetValue(Root, 'LastUsedPacker', gLastUsedPacker); SetValue(Root, 'LastDoAnyCommand', gLastDoAnyCommand); SetValue(Root, 'MarkMaskCaseSensitive', gbMarkMaskCaseSensitive); SetValue(Root, 'MarkMaskIgnoreAccents', gbMarkMaskIgnoreAccents); SetValue(Root, 'MarkMaskFilterWindows', gMarkMaskFilterWindows); SetValue(Root, 'MarkShowWantedAttribute', gMarkShowWantedAttribute); SetValue(Root, 'MarkDefaultWantedAttribute', gMarkDefaultWantedAttribute); SetValue(Root, 'MarkLastWantedAttribute', gMarkLastWantedAttribute); {$IFDEF MSWINDOWS} { TotalCommander Import/Export } //We'll save the last TC executable filename AND TC configuration filename ONLY if both has been set if (gTotalCommanderExecutableFilename<>'') AND (gTotalCommanderConfigFilename<>'') then begin Node := FindNode(Root, 'TCSection', True); if Assigned(Node) then begin SetValue(Node, 'TCExecutableFilename', gTotalCommanderExecutableFilename); SetValue(Node, 'TCConfigFilename', gTotalCommanderConfigFilename); SetValue(Node,'TCToolbarPath',gTotalCommanderToolbarPath); end; end; {$ENDIF} end; { Search template list } gSearchTemplateList.SaveToXml(gConfig, Root); { Columns sets } ColSet.Save(gConfig, Root); { Plugins } Node := gConfig.FindNode(Root, 'Plugins', True); gDSXPlugins.Save(gConfig, Node); gWCXPlugins.Save(gConfig, Node); gWDXPlugins.Save(gConfig, Node); gWFXPlugins.Save(gConfig, Node); gWLXPlugins.Save(gConfig, Node); for iIndexContextMode:=ord(ptDSX) to ord(ptWLX) do begin gConfig.SetValue(Node, Format('TweakPluginWidth%d',[iIndexContextMode]), gTweakPluginWidth[iIndexContextMode]); gConfig.SetValue(Node, Format('TweakPluginHeight%d',[iIndexContextMode]), gTweakPluginHeight[iIndexContextMode]); end; gConfig.SetValue(Node, 'AutoTweak', gPluginInAutoTweak); gConfig.SetValue(Node, 'WCXConfigViewMode', Integer(gWCXConfigViewMode)); gConfig.SetValue(Node, 'PluginFilenameStyle', ord(gPluginFilenameStyle)); gConfig.SetValue(Node,'PluginPathToBeRelativeTo', gPluginPathToBeRelativeTo); end; function LoadConfig: Boolean; var ErrorMessage: String = ''; begin Result := LoadConfigCheckErrors(@LoadGlobalConfig, gConfig.FileName, ErrorMessage); if not Result then Result := AskUserOnError(ErrorMessage); end; function InitGlobs: Boolean; var InitProc: TProcedure; ErrorMessage: String = ''; begin CreateGlobs; if not OpenConfig(ErrorMessage) then begin if not AskUserOnError(ErrorMessage) then Exit(False); end; SetDefaultNonConfigGlobs; if not LoadGlobs then begin if not AskUserOnError(ErrorMessage) then Exit(False); end; for InitProc in FInitList do InitProc(); Result := AskUserOnError(ErrorMessage); end; function GetKeyTypingAction(ShiftStateEx: TShiftState): TKeyTypingAction; var Modifier: TKeyTypingModifier; begin for Modifier in TKeyTypingModifier do if ShiftStateEx * KeyModifiersShortcutNoText = TKeyTypingModifierToShift[Modifier] then Exit(gKeyTyping[Modifier]); Result := ktaNone; end; function IsFileSystemWatcher: Boolean; begin Result := ([watch_file_name_change, watch_attributes_change] * gWatchDirs <> []); end; initialization finalization DestroyGlobs; end. ������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/ugraphics.pas������������������������������������������������������������������0000644�0001750�0000144�00000014421�14743153644�016071� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Graphic functions Copyright (C) 2013-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } unit uGraphics; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, IntfGraphics, LCLVersion; procedure BitmapConvert(Bitmap: TRasterImage); procedure BitmapAssign(Bitmap, Image: TRasterImage); procedure BitmapConvert(ASource, ATarget: TRasterImage); procedure BitmapAlpha(var ABitmap: TBitmap; APercent: Single); procedure BitmapAssign(Bitmap: TRasterImage; Image: TLazIntfImage); procedure BitmapCenter(var Bitmap: TBitmap; Width, Height: Integer); procedure BitmapMerge(ALow, AHigh: TLazIntfImage; const ADestX, ADestY: Integer); implementation uses Math, GraphType, FPimage; type TRawAccess = class(TRasterImage) end; procedure BitmapConvert(Bitmap: TRasterImage); begin BitmapConvert(Bitmap, Bitmap); end; procedure BitmapConvert(ASource, ATarget: TRasterImage); var Source, Target: TLazIntfImage; begin Source:= TLazIntfImage.Create(ASource.RawImage, False); try Target:= TLazIntfImage.Create(ASource.Width, ASource.Height, [riqfRGB, riqfAlpha]); try {$if lcl_fullversion < 2020000} Target.CreateData; {$endif} Target.CopyPixels(Source); BitmapAssign(ATarget, Target); finally Target.Free; end; finally Source.Free; end; end; procedure BitmapAssign(Bitmap, Image: TRasterImage); var RawImage: PRawImage; begin RawImage:= TRawAccess(Image).GetRawImagePtr; // Simply change raw image owner without data copy Bitmap.LoadFromRawImage(RawImage^, True); // Set image data pointer to nil, so it will not free double RawImage^.ReleaseData; end; procedure BitmapAssign(Bitmap: TRasterImage; Image: TLazIntfImage); var ARawImage: TRawImage; begin Image.GetRawImage(ARawImage, True); // Simply change raw image owner without data copy Bitmap.LoadFromRawImage(ARawImage, True); end; procedure BitmapAlpha(var ABitmap: TBitmap; APercent: Single); var X, Y: Integer; Color: TFPColor; Masked: Boolean; AImage: TLazIntfImage; SrcIntfImage: TLazIntfImage; begin if ABitmap.RawImage.Description.AlphaPrec <> 0 then begin ABitmap.BeginUpdate; try AImage:= TLazIntfImage.Create(ABitmap.RawImage, False); for X:= 0 to AImage.Width - 1 do begin for Y:= 0 to AImage.Height - 1 do begin Color:= AImage.Colors[X, Y]; Color.Alpha:= Round(Color.Alpha * APercent); AImage.Colors[X, Y]:= Color; end; end; AImage.Free; finally ABitmap.EndUpdate; end; end else begin Masked:= ABitmap.RawImage.Description.MaskBitsPerPixel > 0; SrcIntfImage:= TLazIntfImage.Create(ABitmap.RawImage, False); AImage:= TLazIntfImage.Create(ABitmap.Width, ABitmap.Height, [riqfRGB, riqfAlpha]); {$if lcl_fullversion < 2020000} AImage.CreateData; {$endif} for X:= 0 to AImage.Width - 1 do begin for Y:= 0 to AImage.Height - 1 do begin Color := SrcIntfImage.Colors[X, Y]; if Masked and SrcIntfImage.Masked[X, Y] then Color.Alpha:= Low(Color.Alpha) else begin Color.Alpha:= Round(High(Color.Alpha) * APercent); end; AImage.Colors[X, Y]:= Color; end end; SrcIntfImage.Free; BitmapAssign(ABitmap, AImage); AImage.Free; end; end; procedure BitmapCenter(var Bitmap: TBitmap; Width, Height: Integer); var X, Y: Integer; Source, Target: TLazIntfImage; begin if (Bitmap.Width <> Width) or (Bitmap.Height <> Height) then begin Source:= TLazIntfImage.Create(Bitmap.RawImage, False); try Target:= TLazIntfImage.Create(Width, Height, [riqfRGB, riqfAlpha]); try {$if lcl_fullversion < 2020000} Target.CreateData; {$endif} Target.FillPixels(colTransparent); X:= (Width - Bitmap.Width) div 2; Y:= (Height - Bitmap.Height) div 2; Target.CopyPixels(Source, X, Y); BitmapAssign(Bitmap, Target); finally Target.Free; end; finally Source.Free; end; end; end; procedure BitmapMerge(ALow, AHigh: TLazIntfImage; const ADestX, ADestY: Integer); var CurColor: TFPColor; X, Y, CurX, CurY: Integer; MaskValue, InvMaskValue: Word; lDrawWidth, lDrawHeight: Integer; begin lDrawWidth := Min(ALow.Width - ADestX, AHigh.Width); lDrawHeight := Min(ALow.Height - ADestY, AHigh.Height); for Y := 0 to lDrawHeight - 1 do begin for X := 0 to lDrawWidth - 1 do begin CurX := ADestX + X; CurY := ADestY + Y; if (CurX < 0) or (CurY < 0) then Continue; MaskValue := AHigh.Colors[X, Y].Alpha; InvMaskValue := $FFFF - MaskValue; if MaskValue = $FFFF then begin ALow.Colors[CurX, CurY] := AHigh.Colors[X, Y]; end else if MaskValue > $00 then begin CurColor := ALow.Colors[CurX, CurY]; if CurColor.Alpha = 0 then begin CurColor:= AHigh.Colors[X, Y]; end else begin if MaskValue > CurColor.Alpha then CurColor.Alpha:= MaskValue; CurColor.Red := Round( CurColor.Red * InvMaskValue / $FFFF + AHigh.Colors[X, Y].Red * MaskValue / $FFFF); CurColor.Green := Round( CurColor.Green * InvMaskValue / $FFFF + AHigh.Colors[X, Y].Green * MaskValue / $FFFF); CurColor.Blue := Round( CurColor.Blue * InvMaskValue / $FFFF + AHigh.Colors[X, Y].Blue * MaskValue / $FFFF); end; ALow.Colors[CurX, CurY] := CurColor; end; end; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uguimessagequeue.pas�����������������������������������������������������������0000644�0001750�0000144�00000014334�14743153644�017472� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- Thread-safe asynchronous call queue. It allows queueing methods that should be called by GUI thread. Copyright (C) 2009-2011 Przemysław Nagay (cobines@gmail.com) 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 } unit uGuiMessageQueue; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs; type TGuiMessageProc = procedure (Data: Pointer) of object; PMessageQueueItem = ^TMessageQueueItem; TMessageQueueItem = record Method: TGuiMessageProc; Data : Pointer; Next : PMessageQueueItem; end; TGuiMessageQueueThread = class(TThread) private FWakeThreadEvent: PRTLEvent; FMessageQueue: PMessageQueueItem; FMessageQueueLastItem: PMessageQueueItem; FMessageQueueLock: TCriticalSection; FFinished: Boolean; {en This method executes some queued functions. It is called from main thread through Synchronize. } procedure CallMethods; public constructor Create(CreateSuspended: Boolean = False); reintroduce; destructor Destroy; override; procedure Terminate; procedure Execute; override; {en @param(AllowDuplicates If @false then if the queue already has AMethod with AData parameter then it is not queued for a second time. If @true then the same methods with the same parameters are allowed to exists multiple times in the queue.) } procedure QueueMethod(AMethod: TGuiMessageProc; AData: Pointer; AllowDuplicates: Boolean = True); end; procedure InitializeGuiMessageQueue; procedure FinalizeGuiMessageQueue; var GuiMessageQueue: TGuiMessageQueueThread; implementation uses uDebug, uExceptions; const // How many functions maximum to call per one Synchronize. MaxMessages = 10; constructor TGuiMessageQueueThread.Create(CreateSuspended: Boolean = False); begin FWakeThreadEvent := RTLEventCreate; FMessageQueue := nil; FMessageQueueLastItem := nil; FMessageQueueLock := TCriticalSection.Create; FFinished := False; FreeOnTerminate := False; inherited Create(CreateSuspended, DefaultStackSize); end; destructor TGuiMessageQueueThread.Destroy; var item: PMessageQueueItem; begin // Make sure the thread is not running anymore. Terminate; FMessageQueueLock.Acquire; while Assigned(FMessageQueue) do begin item := FMessageQueue^.Next; Dispose(FMessageQueue); FMessageQueue := item; end; FMessageQueueLock.Release; RTLeventdestroy(FWakeThreadEvent); FreeAndNil(FMessageQueueLock); inherited Destroy; end; procedure TGuiMessageQueueThread.Terminate; begin inherited Terminate; // Wake after setting Terminate to True. RTLeventSetEvent(FWakeThreadEvent); end; procedure TGuiMessageQueueThread.Execute; begin try while not Terminated do begin if Assigned(FMessageQueue) then // Call some methods. Synchronize(@CallMethods) else // Wait for messages. RTLeventWaitFor(FWakeThreadEvent); end; finally FFinished := True; end; end; procedure TGuiMessageQueueThread.QueueMethod(AMethod: TGuiMessageProc; AData: Pointer; AllowDuplicates: Boolean = True); var item: PMessageQueueItem; begin FMessageQueueLock.Acquire; try if AllowDuplicates = False then begin // Search the queue for this method and parameter. item := FMessageQueue; while Assigned(item) do begin if (item^.Method = AMethod) and (item^.Data = AData) then Exit; item := item^.Next; end; end; New(item); item^.Method := AMethod; item^.Data := AData; item^.Next := nil; if not Assigned(FMessageQueue) then FMessageQueue := item else FMessageQueueLastItem^.Next := item; FMessageQueueLastItem := item; RTLeventSetEvent(FWakeThreadEvent); finally FMessageQueueLock.Release; end; end; procedure TGuiMessageQueueThread.CallMethods; var MessagesCount: Integer = MaxMessages; item: PMessageQueueItem; begin while Assigned(FMessageQueue) and (MessagesCount > 0) do begin try // Call method with parameter. FMessageQueue^.Method(FMessageQueue^.Data); except on e: Exception do begin HandleException(e, Self); end; end; FMessageQueueLock.Acquire; try item := FMessageQueue^.Next; Dispose(FMessageQueue); FMessageQueue := item; // If queue is empty then reset wait event (must be done under lock). if not Assigned(FMessageQueue) then RTLeventResetEvent(FWakeThreadEvent); finally FMessageQueueLock.Release; end; Dec(MessagesCount, 1); end; end; // ---------------------------------------------------------------------------- procedure InitializeGuiMessageQueue; begin DCDebug('Starting GuiMessageQueue'); {$IF (fpc_version<2) or ((fpc_version=2) and (fpc_release<5))} GuiMessageQueue := TGuiMessageQueueThread.Create(True); GuiMessageQueue.Resume; {$ELSE} GuiMessageQueue := TGuiMessageQueueThread.Create(False); {$ENDIF} end; procedure FinalizeGuiMessageQueue; begin GuiMessageQueue.Terminate; DCDebug('Finishing GuiMessageQueue'); {$IF (fpc_version<2) or ((fpc_version=2) and (fpc_release<5))} If (MainThreadID=GetCurrentThreadID) then while not GuiMessageQueue.FFinished do CheckSynchronize(100); {$ENDIF} GuiMessageQueue.WaitFor; FreeAndNil(GuiMessageQueue); end; initialization InitializeGuiMessageQueue; finalization FinalizeGuiMessageQueue; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uhash.pas����������������������������������������������������������������������0000644�0001750�0000144�00000014564�14743153644�015224� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Double Commander ------------------------------------------------------------------------- General Hash Unit: This unit defines the common types, functions, and procedures Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) 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 } unit uHash; {$mode delphi} interface uses Classes, SysUtils, DCPcrypt2, crc; type THashContext = TDCP_hash; THashAlgorithm = (HASH_BLAKE2S, HASH_BLAKE2SP, HASH_BLAKE2B, HASH_BLAKE2BP, HASH_BLAKE3, HASH_CHECKSUM32, HASH_CRC32, HASH_HAVAL, HASH_MD4, HASH_MD5, HASH_RIPEMD128, HASH_RIPEMD160, HASH_SFV, HASH_SHA1, HASH_SHA224, HASH_SHA256, HASH_SHA384, HASH_SHA512, HASH_SHA3_224, HASH_SHA3_256, HASH_SHA3_384, HASH_SHA3_512, HASH_TIGER, HASH_BEST ); var HashFileExt: array[Low(THashAlgorithm)..Pred(High(THashAlgorithm))] of String = ( 'blake2s', 'blake2sp', 'blake2b', 'blake2bp', 'blake3', 'checksum32', 'crc32', 'haval', 'md4', 'md5', 'ripemd128', 'ripemd160', 'sfv', 'sha', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3', 'sha3', 'sha3', 'sha3', 'tiger' ); var HashName: array[Low(THashAlgorithm)..Pred(High(THashAlgorithm))] of String = ( 'blake2s', 'blake2sp', 'blake2b', 'blake2bp', 'blake3', 'checksum32', 'crc32', 'haval', 'md4', 'md5', 'ripemd128', 'ripemd160', 'sfv', 'sha1_160', 'sha2_224', 'sha2_256', 'sha2_384', 'sha2_512', 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', 'tiger' ); procedure HashInit(out Context: THashContext; Algorithm: THashAlgorithm); procedure HashUpdate(var Context: THashContext; const Buffer; BufLen: LongWord); procedure HashFinal(var Context: THashContext; out Hash: String); function HashString(const Line: String; IgnoreCase, IgnoreWhiteSpace: Boolean): LongWord; { Helper functions } function TrimHash(const AHash: String): String; function FileExtIsHash(const FileExt: String): Boolean; function FileExtToHashAlg(const FileExt: String): THashAlgorithm; implementation uses LazUTF8, DCPhaval, DCPmd4, DCPmd5, DCPripemd128, DCPripemd160, DCPChecksum32, DCPcrc32, DCPsha1, DCPsha256, DCPsha512, DCPtiger, DCPblake2, DCPblake3, DCPsha3; procedure HashInit(out Context: THashContext; Algorithm: THashAlgorithm); begin {$PUSH}{$WARNINGS OFF} if (Algorithm = HASH_BEST) then begin if SizeOf(UIntPtr) = Sizeof(UInt64) then Algorithm:= HASH_BLAKE2B else Algorithm:= HASH_BLAKE2S; end; {$POP} case Algorithm of HASH_BLAKE2S: Context:= TDCP_blake2s.Create(nil); HASH_BLAKE2SP: Context:= TDCP_blake2sp.Create(nil); HASH_BLAKE2B: Context:= TDCP_blake2b.Create(nil); HASH_BLAKE2BP: Context:= TDCP_blake2bp.Create(nil); HASH_BLAKE3: Context:= TDCP_blake3.Create(nil); HASH_CHECKSUM32: Context:= TDCP_checksum32.Create(nil); HASH_CRC32: Context:= TDCP_crc32.Create(nil); HASH_HAVAL: Context:= TDCP_haval.Create(nil); HASH_MD4: Context:= TDCP_md4.Create(nil); HASH_MD5: Context:= TDCP_md5.Create(nil); HASH_RIPEMD128: Context:= TDCP_ripemd128.Create(nil); HASH_RIPEMD160: Context:= TDCP_ripemd160.Create(nil); HASH_SFV: Context:= TDCP_crc32.Create(nil); HASH_SHA1: Context:= TDCP_sha1.Create(nil); HASH_SHA224: Context:= TDCP_sha224.Create(nil); HASH_SHA256: Context:= TDCP_sha256.Create(nil); HASH_SHA384: Context:= TDCP_sha384.Create(nil); HASH_SHA512: Context:= TDCP_sha512.Create(nil); HASH_SHA3_224: Context:= TDCP_sha3_224.Create(nil); HASH_SHA3_256: Context:= TDCP_sha3_256.Create(nil); HASH_SHA3_384: Context:= TDCP_sha3_384.Create(nil); HASH_SHA3_512: Context:= TDCP_sha3_512.Create(nil); HASH_TIGER: Context:= TDCP_tiger.Create(nil); end; Context.Init; end; procedure HashUpdate(var Context: THashContext; const Buffer; BufLen: LongWord); begin Context.Update(Buffer, BufLen); end; procedure HashFinal(var Context: THashContext; out Hash: String); var I, HashSize: LongWord; Digest: array of Byte; begin Hash:= EmptyStr; HashSize:= Context.HashSize div 8; SetLength(Digest, HashSize); Context.Final(Pointer(Digest)^); for I := 0 to HashSize - 1 do Hash := Hash + HexStr(Digest[I], 2); Hash := LowerCase(Hash); FreeAndNil(Context); end; function HashString(const Line: String; IgnoreCase, IgnoreWhiteSpace: Boolean): LongWord; var S: String; I, J, L: Integer; begin S := Line; if IgnoreWhiteSpace then begin J := 1; L := Length(Line); for I:= 1 to L do begin // Skip white spaces if not (Line[I] in [#9, #32]) then begin S[J] := Line[I]; Inc(J); end; end; SetLength(S, J - 1); end; if IgnoreCase then S := UTF8LowerCase(S); Result := crc32(0, nil, 0); Result := crc32(Result, PByte(S), Length(S)); end; function TrimHash(const AHash: String): String; var I, J: Integer; begin J:= 0; Result:= EmptyStr; SetLength(Result, Length(AHash)); for I:= 1 to Length(AHash) do begin if (AHash[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then begin Inc(J); Result[J]:= AHash[I]; end; end; SetLength(Result, J); end; function FileExtIsHash(const FileExt: String): Boolean; var I: THashAlgorithm; begin Result:= False; for I:= Low(HashFileExt) to High(HashFileExt) do begin if SameText(FileExt, HashFileExt[I]) then Exit(True); end; end; function FileExtToHashAlg(const FileExt: String): THashAlgorithm; var I: THashAlgorithm; begin for I:= Low(HashFileExt) to High(HashFileExt) do begin if SameText(FileExt, HashFileExt[I]) then Exit(I); end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/src/uhighlighterprocs.pas����������������������������������������������������������0000644�0001750�0000144�00000006657�14743153644�017652� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{------------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: uHighlighterProcs.pas, released 2000-06-23. The Initial Author of the Original Code is Michael Hieke. All Rights Reserved. Contributors to the SynEdit project are listed in the Contributors.txt file. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 or later (the "GPL"), in which case the provisions of the GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. $Id: uHighlighterProcs.pas,v 1.3 2002/06/15 06:57:24 etrusco Exp $ You may retrieve the latest version of this file at the SynEdit home page, located at http://SynEdit.SourceForge.net Known Issues: -------------------------------------------------------------------------------} unit uHighlighterProcs; interface uses Classes, SynEditHighlighter; function GetHighlightersFilter(AHighlighters: TStringList): string; function GetHighlighterFromFileExt(AHighlighters: TStringList; Extension: string): TSynCustomHighlighter; implementation uses SysUtils; function GetHighlightersFilter(AHighlighters: TStringList): string; var i: integer; Highlighter: TSynCustomHighlighter; begin Result := ''; if Assigned(AHighlighters) then for i := 0 to AHighlighters.Count - 1 do begin if not (AHighlighters.Objects[i] is TSynCustomHighlighter) then continue; Highlighter := TSynCustomHighlighter(AHighlighters.Objects[i]); if Highlighter.DefaultFilter = '' then continue; Result := Result + Highlighter.DefaultFilter; if Result[Length(Result)] <> '|' then Result := Result + '|'; end; end; function GetHighlighterFromFileExt(AHighlighters: TStringList; Extension: string): TSynCustomHighlighter; var ExtLen: integer; i, j: integer; Highlighter: TSynCustomHighlighter; Filter: string; begin Extension := LowerCase(Extension); ExtLen := Length(Extension); if Assigned(AHighlighters) and (ExtLen > 0) then begin for i := 0 to AHighlighters.Count - 1 do begin if not (AHighlighters.Objects[i] is TSynCustomHighlighter) then continue; Highlighter := TSynCustomHighlighter(AHighlighters.Objects[i]); Filter := LowerCase(Highlighter.DefaultFilter); j := Pos('|', Filter); if j > 0 then begin Delete(Filter, 1, j); j := Pos(Extension, Filter); if (j > 0) and ((j + ExtLen > Length(Filter)) or (Filter[j + ExtLen] = ';')) then begin Result := Highlighter; exit; end; end; end; end; Result := nil; end; end. ���������������������������������������������������������������������������������doublecmd-1.1.22/src/uhighlighters.pas��������������������������������������������������������������0000644�0001750�0000144�00000022014�14743153644�016747� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit uHighlighters; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, SynEditHighlighter, SynHighlighterPas, SynHighlighterCPP, SynHighlighterHTML, SynHighlighterUNIXShellScript, SynHighlighterPerl, SynHighlighterDiff, SynHighlighterPo, SynHighlighterIni, SynHighlighterBat, SynHighlighterTeX, LCLVersion; const SYNS_XML_DefaultText = 'Default text'; type { TSynBatSynEx } TSynBatSynEx = class(TSynBatSyn) public constructor Create(AOwner: TComponent); override; end; { TSynCppSynEx } TSynCppSynEx = class(TSynCppSyn) protected function GetSampleSource: string; override; end; { TSynDiffSynEx } TSynDiffSynEx = class(TSynDiffSyn) protected function GetSampleSource: string; override; function GetDefaultFilter: string; override; end; { TSynHTMLSynEx } TSynHTMLSynEx = class(TSynHTMLSyn) protected function GetSampleSource: string; override; end; { TSynIniSynEx } TSynIniSynEx = class(TSynIniSyn) public constructor Create(AOwner: TComponent); override; end; { TSynPasSynEx } TSynPasSynEx = class(TSynPasSyn) protected function GetSampleSource: string; override; function GetDefaultFilter: string; override; end; { TSynPerlSynEx } TSynPerlSynEx = class(TSynPerlSyn) protected function GetSampleSource: string; override; end; { TSynPoSynEx } TSynPoSynEx = class(TSynPoSyn) protected function GetDefaultFilter: string; override; public constructor Create(AOwner: TComponent); override; end; { TSynTeXSynEx } TSynTeXSynEx = class(TSynTeXSyn) public constructor Create(AOwner: TComponent); override; end; { TSynUNIXShellScriptSynEx } TSynUNIXShellScriptSynEx = class(TSynUNIXShellScriptSyn) protected function GetSampleSource: string; override; end; { TSynPlainTextHighlighter } TSynPlainTextHighlighter = class(TSynCustomHighlighter) protected function GetSampleSource: string; override; public class function GetLanguageName: string; override; end; { TSynCustomHighlighterHelper } TSynCustomHighlighterHelper = class helper for TSynCustomHighlighter public function LanguageName: String; function Other: Boolean; end; TSynHighlighterAttrFeature = ( hafBackColor, hafForeColor, hafFrameColor, hafStyle, hafStyleMask, hafFrameStyle, hafFrameEdges ); TSynHighlighterAttrFeatures = set of TSynHighlighterAttrFeature; { TSynHighlighterAttributesHelper } TSynHighlighterAttributesHelper = class helper for TSynHighlighterAttributes private function GetFeatures: TSynHighlighterAttrFeatures; public property Features: TSynHighlighterAttrFeatures read GetFeatures; end; implementation uses SynEditStrConst, SynUniHighlighter, SynUniClasses, uLng; { TSynBatSynEx } constructor TSynBatSynEx.Create(AOwner: TComponent); begin inherited Create(AOwner); CommentAttri.StoredName := SYNS_XML_AttrComment; IdentifierAttri.StoredName := SYNS_XML_AttrIdentifier; KeyAttri.StoredName := SYNS_XML_AttrKey; NumberAttri.StoredName := SYNS_XML_AttrNumber; SpaceAttri.StoredName := SYNS_XML_AttrSpace; VariableAttri.StoredName := SYNS_XML_AttrVariable; end; { TSynCppSynEx } function TSynCppSynEx.GetSampleSource: string; begin Result := '/* Comment */'#13 + '#include <stdio.h>'#13 + '#include <stdlib.h>'#13 + #13 + 'static char line_buf[LINE_BUF];'#13 + #13 + 'int main(int argc,char **argv){'#13 + ' FILE *file;'#13 + ' line_buf[0]=0;'#13 + ' printf("\n");'#13 + ' return 0;'#13 + '}'#13 + ''#13 + #13; end; { TSynDiffSynEx } function TSynDiffSynEx.GetSampleSource: string; begin Result := '*** /a/file'#13#10 + '--- /b/file'#13#10 + '***************'#13#10 + '*** 2,5 ****'#13#10 + '--- 2,5 ----'#13#10 + ' context'#13#10 + '- removed'#13#10 + '! Changed'#13#10 + '+ added'#13#10 + ' context'#13#10; end; function TSynDiffSynEx.GetDefaultFilter: string; begin Result:= 'Difference Files (*.diff,*.patch)|*.diff;*.patch'; end; { TSynHTMLSynEx } function TSynHTMLSynEx.GetSampleSource: string; begin Result := '<html>'#13 + '<title>Lazarus Sample source for html'#13 + ''#13 + ''#13 + ''#13 + '

'#13 + ' Some Text'#13 + ' Ampersands:  F P C'#13 + '

'#13 + ''#13 + ''#13 + ''#13 + ''#13 + #13; end; { TSynIniSynEx } constructor TSynIniSynEx.Create(AOwner: TComponent); begin inherited Create(AOwner); {$IF (LCL_FULLVERSION >= 3990000)} CommentTypes := [ictSemicolon, ictHash]; {$ENDIF} CommentAttri.StoredName := SYNS_XML_AttrComment; TextAttri.StoredName := SYNS_XML_AttrText; SectionAttri.StoredName := SYNS_XML_AttrSection; KeyAttri.StoredName := SYNS_XML_AttrKey; NumberAttri.StoredName := SYNS_XML_AttrNumber; SpaceAttri.StoredName := SYNS_XML_AttrSpace; StringAttri.StoredName := SYNS_XML_AttrString; SymbolAttri.StoredName := SYNS_XML_AttrSymbol; end; { TSynPasSynEx } function TSynPasSynEx.GetSampleSource: string; begin Result := '{ Comment }'#13 + '{$R- compiler directive}'#13 + 'procedure TForm1.Button1Click(Sender: TObject);'#13 + 'var // Delphi Comment'#13 + ' Number, I, X: Integer;'#13 + 'begin'#13 + ' Number := 12345 * (2 + 9) // << Matching Brackets ;'#13 + ' Caption := ''The number is '' + IntToStr(Number);'#13 + ' asm'#13 + ' MOV AX,1234h'#13 + ' MOV Number,AX'#13 + ' end;'#13 + ' case ModalResult of'#13+ ' mrOK: inc(X);'#13+ ' mrCancel, mrIgnore: dec(X);'#13+ ' end;'#13+ ' ListBox1.Items.Add(IntToStr(X));'#13 + 'end;'#13 + #13; end; function TSynPasSynEx.GetDefaultFilter: string; begin Result:= 'Pascal Files (*.pas,*.dpr,*.dpk,*.inc,*.pp,*.lpr)|*.pas;*.dpr;*.dpk;*.inc;*.pp;*.lpr'; end; { TSynPerlSynEx } function TSynPerlSynEx.GetSampleSource: string; begin Result := '#!/usr/bin/perl'#13 + '# Perl sample code'#13 + ''#13 + '$i = "10";'#13 + 'print "$ENV{PATH}\n";'#13 + '($i =~ /\d+/) || die "Error\n";'#13 + ''#13 + '# Text Block'#13 + ''#13 + #13; end; { TSynPoSynEx } function TSynPoSynEx.GetDefaultFilter: string; begin Result:= 'Po Files (*.po,*.pot)|*.po;*.pot'; end; constructor TSynPoSynEx.Create(AOwner: TComponent); begin inherited Create(AOwner); CommentAttri.StoredName := SYNS_XML_AttrComment; TextAttri.StoredName := SYNS_XML_AttrText; KeyAttri.StoredName := SYNS_XML_AttrKey; end; { TSynTeXSynEx } constructor TSynTeXSynEx.Create(AOwner: TComponent); begin inherited Create(AOwner); CommentAttri.StoredName := SYNS_XML_AttrComment; TextAttri.StoredName := SYNS_XML_AttrText; MathmodeAttri.StoredName := SYNS_XML_AttrMathmode; SpaceAttri.StoredName := SYNS_XML_AttrSpace; ControlSequenceAttri.StoredName := SYNS_XML_AttrTexCommand; BracketAttri.StoredName := SYNS_XML_AttrSquareBracket; BraceAttri.StoredName := SYNS_XML_AttrRoundBracket; end; { TSynUNIXShellScriptSynEx } function TSynUNIXShellScriptSynEx.GetSampleSource: string; begin Result := '#!/bin/bash'#13#13 + '# Bash syntax highlighting'#13#10 + 'set -x'#13#10 + 'set -e'#13#10 + 'Usage="Usage: $0 devel|stable"'#13#10 + 'FPCVersion=$1'#13#10 + 'for ver in devel stable; do'#13#10 + ' if [ "x$FPCVersion" = "x$ver" ]; then'#13#10 + ' fi'#13#10 + 'done'#13#10 + '# Text Block'#13#10 + #13#10; end; { TSynPlainTextHighlighter } function TSynPlainTextHighlighter.GetSampleSource: string; begin Result := 'Double Commander is a cross platform open source file manager'#13 + 'with two panels side by side. It is inspired by Total Commander'#13 + 'and features some new ideas.'#13; end; class function TSynPlainTextHighlighter.GetLanguageName: string; begin Result:= rsSynLangPlainText; end; { TSynCustomHighlighterHelper } function TSynCustomHighlighterHelper.LanguageName: String; begin if Self is TSynUniSyn then Result:= TSynUniSyn(Self).Info.General.Name else Result:= Self.GetLanguageName; end; function TSynCustomHighlighterHelper.Other: Boolean; begin if Self is TSynUniSyn then Result:= TSynUniSyn(Self).Info.General.Other else Result:= False; end; { TSynHighlighterAttributesHelper } function TSynHighlighterAttributesHelper.GetFeatures: TSynHighlighterAttrFeatures; begin if SameText(StoredName, SYNS_XML_DefaultText) then Result:= [hafBackColor, hafForeColor] else begin if Self is TSynAttributes then Result:= [hafBackColor, hafForeColor, hafStyle] else Result:= [hafBackColor, hafForeColor, hafFrameColor, hafStyle, hafFrameStyle, hafFrameEdges]; end; end; end. doublecmd-1.1.22/src/uhotdir.pas0000644000175000001440000014144214743153644015566 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Load/Save/WorkingWith HotDir Copyright (C) 2014-2019 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uHotDir; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, Menus, ExtCtrls, Controls, ComCtrls, //DC DCClassesUtf8, DCXmlConfig; const cSectionOfHotDir = 'DirectoryHotList'; ACTION_INVALID = 0; ACTION_ADDTOHOTLIST = 1; ACTION_ADDJUSTSOURCETOHOTLIST = 2; ACTION_ADDBOTHTOHOTLIST = 3; ACTION_CONFIGTOHOTLIST = 4; ACTION_JUSTSHOWCONFIGHOTLIST = 5; ACTION_ADDSELECTEDDIR = 6; ACTION_DIRECTLYCONFIGENTRY = 7; HOTLISTMAGICWORDS:array[1..7] of string =('add','addsrconly','addboth','config','show','addsel','directconfig'); TAGOFFSET_FORCHANGETOSPECIALDIR = $10000; ICONINDEX_SUBMENU = 0; ICONINDEX_DIRECTORYNOTPRESENTHERE = 1; ICONINDEX_SUBMENUWITHMISSING = 2; ICONINDEX_NEWADDEDDIRECTORY = 3; ICONINDEXNAME:array[0..3] of string = ('submenu','dirmissing','submenuwithmissing','newaddition'); HOTLIST_SEPARATORSTRING:string='···························'; TERMINATORNOTPRESENT = ':-<#/?*+*?\#>-:'; STR_ACTIVEFRAME: string = 'panel=active'; STR_NOTACTIVEFRAME: string = 'panel=inactive'; STR_LEFTFRAME: string = 'panel=left'; STR_RIGHTFRAME: string = 'panel=right'; STR_NAME: string = 'column=name'; STR_EXTENSION: string = 'column=ext'; STR_SIZE: string = 'column=size'; STR_MODIFICATIONDATETIME: string = 'column=datetime'; STR_ASCENDING : string = 'order=ascending'; STR_DESCENDING : string = 'order=descending'; type { TKindOfHotDirEntry } TKindOfHotDirEntry = (hd_NULL, hd_CHANGEPATH, hd_SEPARATOR, hd_STARTMENU, hd_ENDMENU, hd_COMMAND); { TKindHotDirMenuPopulation } TKindHotDirMenuPopulation = (mpJUSTHOTDIRS, mpHOTDIRSWITHCONFIG, mpPATHHELPER); { TPositionWhereToAddHotDir } TPositionWhereToAddHotDir = (ahdFirst, ahdLast, ahdSmart); { TExistingState } TExistingState = (DirExistUnknown, DirExist, DirNotExist); { TProcedureWhenClickMenuItem} TProcedureWhenClickOnMenuItem = procedure(Sender: TObject) of object; { THotDir } THotDir = class private FDispatcher: TKindOfHotDirEntry; FHotDirName: string; FHotDirPath: string; FHotDirPathSort: longint; FHotDirTarget: string; FHotDirTargetSort: longint; FHotDirExistingState: TExistingState; FGroupNumber : integer; public constructor Create; procedure CopyToHotDir(var DestinationHotDir: THotDir); property Dispatcher: TKindOfHotDirEntry read FDispatcher write FDispatcher; property HotDirName: string read FHotDirName write FHotDirName; property HotDirPath: string read FHotDirPath write FHotDirPath; property HotDirPathSort: longint read FHotDirPathSort write FHotDirPathSort; property HotDirTarget: string read FHotDirTarget write FHotDirTarget; property HotDirTargetSort: longint read FHotDirTargetSort write FHotDirTargetSort; property HotDirExisting: TExistingState read FHotDirExistingState write FHotDirExistingState; property GroupNumber: integer read FGroupNumber write FGroupNumber; end; { TDirectoryHotlist } TDirectoryHotlist = class(TList) private function GetHotDir(Index: integer): THotDir; public constructor Create; procedure Clear; override; function Add(HotDir: THotDir): integer; procedure DeleteHotDir(Index: integer); procedure CopyDirectoryHotlistToDirectoryHotlist(var DestinationDirectoryHotlist: TDirectoryHotlist); procedure LoadFromXml(AConfig: TXmlConfig; ANode: TXmlNode); procedure SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode; FlagEraseOriginalOnes: boolean); procedure ImportDoubleCommander(DoubleCommanderFilename: String); function ExportDoubleCommander(DoubleCommanderFilename: String; FlagEraseOriginalOnes: boolean): boolean; procedure PopulateMenuWithHotDir(mncmpMenuComponentToPopulate: TComponent; ProcedureWhenHotDirItemClicked, ProcedureWhenHotDirAddOrConfigClicked: TProcedureWhenClickOnMenuItem; KindHotDirMenuPopulation: TKindHotDirMenuPopulation; TagOffset: longint); function LoadTTreeView(ParamTreeView:TTreeView; DirectoryHotlistIndexToSelectIfAny:longint):TTreeNode; procedure RefreshFromTTreeView(ParamTreeView:TTreeView); function AddFromAnotherTTreeViewTheSelected(ParamWorkingTreeView, ParamTreeViewToImport:TTreeView; FlagAddThemAll: boolean): longint; function ComputeSignature(Seed:dword=$00000000):dword; property HotDir[Index: integer]: THotDir read GetHotDir; {$IFDEF MSWINDOWS} function ImportTotalCommander(TotalCommanderConfigFilename: String): integer; function ExportTotalCommander(TotalCommanderConfigFilename: String; FlagEraseOriginalOnes: boolean): boolean; {$ENDIF} end; { TCheckDrivePresenceThread } TCheckDrivePresenceThread = class(TThread) private FDriveToSearchFor: string; FListOfNonExistingDrive: TStringList; FThreadCountPoint: ^longint; procedure ReportNotPresentInTheThread; procedure ReportPresentInTheThread; protected procedure Execute; override; public constructor Create(sDrive: string; ParamListOfNonExistingDrive: TStringList; var ThreadCount: longint); destructor Destroy; override; end; implementation uses //Lazarus, Free-Pascal, etc. crc, Graphics, Forms, lazutf8, //DC DCFileAttributes, uDebug, uDCUtils, fMain, uFile, uLng, DCOSUtils, DCStrUtils, uGlobs, uSpecialDir {$IFDEF MSWINDOWS} ,uTotalCommander {$ENDIF} ; function GetCaption(const ACaption: TCaption): TCaption; begin {$IF not (DEFINED(LCLWIN32) or DEFINED(LCLCOCOA))} if (Pos('&', StringReplace(ACaption, '&&', '', [rfReplaceAll])) = 0) then Result:= '&' + ACaption else {$ENDIF} Result:= ACaption; end; { THotDir.Create } constructor THotDir.Create; begin inherited Create; FDispatcher := hd_NULL; FHotDirName := ''; FHotDirPath := ''; FHotDirPathSort := 0; FHotDirTarget := ''; FHotDirTargetSort := 0; FHotDirExistingState := DirExistUnknown; FGroupNumber := 0; end; { THotDir.CopyToHotDir } procedure THotDir.CopyToHotDir(var DestinationHotDir: THotDir); begin DestinationHotDir.Dispatcher := FDispatcher; DestinationHotDir.HotDirName := FHotDirName; DestinationHotDir.HotDirPath := FHotDirPath; DestinationHotDir.HotDirPathSort := FHotDirPathSort; DestinationHotDir.HotDirTarget := FHotDirTarget; DestinationHotDir.HotDirTargetSort := FHotDirTargetSort; DestinationHotDir.HotDirExisting := FHotDirExistingState; DestinationHotDir.GroupNumber := FGroupNumber; end; { TDirectoryHotlist.Create } constructor TDirectoryHotlist.Create; begin inherited Create; end; { TDirectoryHotlist.Clear } procedure TDirectoryHotlist.Clear; var i: integer; begin for i := 0 to Count - 1 do HotDir[i].Free; inherited Clear; end; { TDirectoryHotlist.Add } function TDirectoryHotlist.Add(HotDir: THotDir): integer; begin Result := inherited Add(HotDir); end; { TDirectoryHotlist.DeleteHotDir } procedure TDirectoryHotlist.DeleteHotDir(Index: integer); begin HotDir[Index].Free; Delete(Index); end; { TDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist } procedure TDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist(var DestinationDirectoryHotlist: TDirectoryHotlist); var LocalHotDir: THotDir; Index: longint; begin //Let's delete possible previous list content for Index := pred(DestinationDirectoryHotlist.Count) downto 0 do DestinationDirectoryHotlist.DeleteHotDir(Index); DestinationDirectoryHotlist.Clear; //Now let's create entries and add them one by one to the destination list for Index := 0 to pred(Count) do begin LocalHotDir := THotDir.Create; LocalHotDir.Dispatcher := HotDir[Index].Dispatcher; LocalHotDir.HotDirName := HotDir[Index].HotDirName; LocalHotDir.HotDirPath := HotDir[Index].HotDirPath; LocalHotDir.HotDirPathSort := HotDir[Index].HotDirPathSort; LocalHotDir.HotDirTarget := HotDir[Index].HotDirTarget; LocalHotDir.HotDirTargetSort := HotDir[Index].HotDirTargetSort; LocalHotDir.FHotDirExistingState := HotDir[Index].HotDirExisting; LocalHotDir.FGroupNumber := HotDir[Index].GroupNumber; DestinationDirectoryHotlist.Add(LocalHotDir); end; end; { TDirectoryHotlist.LoadTTreeView } //For each node, the "ImageIndex" field is recuperated to be an index of which //item in the directory list it represent. Because of the fact that the //"hd_ENDMENU's" don't have their direct element in the tree, the field //"absoluteindex" cannot be used for that since as soon as there is a subment, //we lost the linearity of the matching of absoluteindex vs index of hotdir in //the list. function TDirectoryHotlist.LoadTTreeView(ParamTreeView:TTreeView; DirectoryHotlistIndexToSelectIfAny:longint):TTreeNode; var Index: longint; procedure RecursivAddElements(WorkingNode: TTreeNode); var FlagGetOut: boolean = False; LocalNode: TTreeNode; begin while (FlagGetOut = False) and (Index < Count) do begin case HotDir[Index].Dispatcher of hd_STARTMENU: begin LocalNode := ParamTreeView.Items.AddChildObject(WorkingNode, HotDir[Index].HotDirName,HotDir[Index]); if HotDir[Index].FHotDirExistingState=DirNotExist then begin LocalNode.ImageIndex:=ICONINDEX_SUBMENUWITHMISSING; LocalNode.SelectedIndex:=ICONINDEX_SUBMENUWITHMISSING; LocalNode.StateIndex:=ICONINDEX_SUBMENUWITHMISSING; end else begin LocalNode.ImageIndex:=ICONINDEX_SUBMENU; LocalNode.SelectedIndex:=ICONINDEX_SUBMENU; LocalNode.StateIndex:=ICONINDEX_SUBMENU; end; LocalNode.Data:=HotDir[Index]; if DirectoryHotlistIndexToSelectIfAny=Index then result:=LocalNode; Inc(Index); RecursivAddElements(LocalNode); end; hd_ENDMENU: begin FlagGetOut := True; Inc(Index); end; hd_SEPARATOR: begin LocalNode:=ParamTreeView.Items.AddChildObject(WorkingNode, HOTLIST_SEPARATORSTRING ,HotDir[Index]); LocalNode.Data:=HotDir[Index]; if DirectoryHotlistIndexToSelectIfAny=Index then result:=LocalNode; Inc(Index); end else begin LocalNode:=ParamTreeView.Items.AddChildObject(WorkingNode, HotDir[Index].HotDirName,HotDir[Index]); if HotDir[Index].FHotDirExistingState=DirNotExist then begin LocalNode.ImageIndex:=ICONINDEX_DIRECTORYNOTPRESENTHERE; LocalNode.SelectedIndex:=ICONINDEX_DIRECTORYNOTPRESENTHERE; LocalNode.StateIndex:=ICONINDEX_DIRECTORYNOTPRESENTHERE; end; LocalNode.Data:=HotDir[Index]; if DirectoryHotlistIndexToSelectIfAny=Index then result:=LocalNode; Inc(Index); end; end; end; end; begin result:=nil; ParamTreeView.Items.Clear; Index := 0; RecursivAddElements(nil); end; { TDirectoryHotlist.PopulateMenuWithHotDir } procedure TDirectoryHotlist.PopulateMenuWithHotDir(mncmpMenuComponentToPopulate: TComponent; ProcedureWhenHotDirItemClicked, ProcedureWhenHotDirAddOrConfigClicked: TProcedureWhenClickOnMenuItem; KindHotDirMenuPopulation: TKindHotDirMenuPopulation; TagOffset: longint); var I: longint; //Same variable for main and local routine FlagCurrentPathAlreadyInMenu, FlagSelectedPathAlreadyInMenu: boolean; CurrentPathToSearch, SelectedPathToSearch: string; MaybeActiveOrSelectedDirectories: TFiles; //Warning: "CompleteMenu" is recursive and call itself. function CompleteMenu(ParamMenuItem: TMenuItem): longint; var localmi: TMenuItem; LocalLastAdditionIsASeparator: boolean; begin Result := 0; LocalLastAdditionIsASeparator := False; while I < Count do begin Inc(I); case HotDir[I - 1].Dispatcher of hd_CHANGEPATH: begin case HotDir[I - 1].HotDirExisting of DirExistUnknown, DirExist: begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption:= GetCaption(GetMenuCaptionAccordingToOptions(HotDir[I - 1].HotDirName,HotDir[I - 1].HotDirPath)); localmi.tag := (I - 1) + TagOffset; localmi.OnClick := ProcedureWhenHotDirItemClicked; ParamMenuItem.Add(localmi); if CurrentPathToSearch = UpperCase(mbExpandFileName(HotDir[I - 1].FHotDirPath)) then FlagCurrentPathAlreadyInMenu := True; if SelectedPathToSearch = UpperCase(mbExpandFileName(HotDir[I - 1].FHotDirPath)) then FlagSelectedPathAlreadyInMenu := True; LocalLastAdditionIsASeparator := False; Inc(Result); end; end; end; hd_NULL, hd_COMMAND: begin if KindHotDirMenuPopulation <> mpPATHHELPER then begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption := GetCaption(HotDir[I - 1].HotDirName); localmi.tag := (I - 1) + TagOffset; localmi.OnClick := ProcedureWhenHotDirItemClicked; ParamMenuItem.Add(localmi); LocalLastAdditionIsASeparator := False; Inc(Result); end; end; hd_SEPARATOR: begin if (ParamMenuItem.Count > 0) and (not LocalLastAdditionIsASeparator) then begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption := '-'; ParamMenuItem.Add(localmi); LocalLastAdditionIsASeparator := True; Inc(Result); end; end; hd_STARTMENU: begin localmi := TMenuItem.Create(ParamMenuItem); localmi.Caption := GetCaption(HotDir[I - 1].HotDirName); if gIconsInMenus then localmi.ImageIndex:=ICONINDEX_SUBMENU; ParamMenuItem.Add(localmi); CompleteMenu(localmi); if localmi.Count <> 0 then begin LocalLastAdditionIsASeparator := False; Inc(Result); end else begin localmi.Free; end; end; hd_ENDMENU: begin if LocalLastAdditionIsASeparator then begin ParamMenuItem.Items[pred(ParamMenuItem.Count)].Free; Dec(Result); end; exit; end; end; //case HotDir[I-1].Dispatcher of end; //while I 0) and (not LastAdditionIsASeparator) then begin miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := '-'; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); LastAdditionIsASeparator := True; end; end; hd_STARTMENU: begin miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := GetCaption(HotDir[I - 1].HotDirName); if gIconsInMenus then miMainTree.ImageIndex := ICONINDEX_SUBMENU; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); CompleteMenu(miMainTree); if miMainTree.Count <> 0 then begin LastAdditionIsASeparator := False; end else begin miMainTree.Free; end; end; hd_ENDMENU: begin if LastAdditionIsASeparator then begin if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items[pred(TPopupMenu(mncmpMenuComponentToPopulate).Items.Count)].Free else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Items[pred(TMenuItem(mncmpMenuComponentToPopulate).Count)].Free; end; end; end; end; //2014-08-25:If last item added is a separator, we need to remove it so it will not look bad with another separator added at the end if LastAdditionIsASeparator then begin if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items[pred(TPopupMenu(mncmpMenuComponentToPopulate).Items.Count)].Free else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Items[pred(TMenuItem(mncmpMenuComponentToPopulate).Count)].Free; end; case KindHotDirMenuPopulation of mpHOTDIRSWITHCONFIG: begin if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then begin if mncmpMenuComponentToPopulate.ComponentCount>InitialNumberOfItems then begin miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := '-'; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; end; // Let's add the "Special path" in a context of change directory gSpecialDirList.PopulateMenuWithSpecialDir(mncmpMenuComponentToPopulate, mp_CHANGEDIR, ProcedureWhenHotDirItemClicked); // now add delimiter miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := '-'; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); //now add the "selected path", if any, if it's the case if MaybeActiveOrSelectedDirectories.Count>0 then begin miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); case MaybeActiveOrSelectedDirectories.Count of 1: with Application.MainForm as TForm do if not FlagSelectedPathAlreadyInMenu then miMainTree.Caption := rsMsgHotDirAddSelectedDirectory + MinimizeFilePath(MaybeActiveOrSelectedDirectories.Items[0].FullPath, Canvas, 250).Replace('&','&&') else miMainTree.Caption := rsMsgHotDirReAddSelectedDirectory + MinimizeFilePath(MaybeActiveOrSelectedDirectories.Items[0].FullPath, Canvas, 250).Replace('&','&&'); else miMainTree.Caption := Format(rsMsgHotDirAddSelectedDirectories,[MaybeActiveOrSelectedDirectories.Count]); end; miMainTree.Tag := ACTION_ADDSELECTEDDIR; miMainTree.OnClick := ProcedureWhenHotDirAddOrConfigClicked; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; // now allow to add or re-add the "current path" miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); with Application.MainForm as TForm do if not FlagCurrentPathAlreadyInMenu then miMainTree.Caption := rsMsgHotDirAddThisDirectory + MinimizeFilePath(frmMain.ActiveFrame.CurrentPath, Canvas, 250).Replace('&','&&') else miMainTree.Caption := rsMsgHotDirReAddThisDirectory + MinimizeFilePath(frmMain.ActiveFrame.CurrentPath, Canvas, 250).Replace('&','&&'); miMainTree.Tag := ACTION_ADDTOHOTLIST; miMainTree.OnClick := ProcedureWhenHotDirAddOrConfigClicked; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); // now add configure item miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption := rsMsgHotDirConfigHotlist; miMainTree.Tag := ACTION_CONFIGTOHOTLIST; miMainTree.ShortCut := frmMain.mnuCmdConfigDirHotlist.ShortCut; miMainTree.OnClick := ProcedureWhenHotDirAddOrConfigClicked; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; end; //case KindHotDirMenuPopulation of finally FreeAndNil(MaybeActiveOrSelectedDirectories); end; if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then if TPopupMenu(mncmpMenuComponentToPopulate).Images=nil then TPopupMenu(mncmpMenuComponentToPopulate).Images:= frmMain.imgLstDirectoryHotlist; if mncmpMenuComponentToPopulate.ClassType = TMenuItem then if TMenuItem(mncmpMenuComponentToPopulate).GetParentMenu.Images=nil then TMenuItem(mncmpMenuComponentToPopulate).GetParentMenu.Images:= frmMain.imgLstDirectoryHotlist; end; { TDirectoryHotlist.LoadFromXml } { Information are stored like originally DC was storing them WITH addition of menu related info in a simular way TC. } procedure TDirectoryHotlist.LoadFromXml(AConfig: TXmlConfig; ANode: TXmlNode); var sName, sPath: string; LocalHotDir: THotDir; CurrentMenuLevel: integer; FlagAvortInsertion: boolean; begin Clear; CurrentMenuLevel := 0; ANode := ANode.FindNode(cSectionOfHotDir); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('HotDir') = 0 then begin if AConfig.TryGetAttr(ANode, 'Name', sName) and AConfig.TryGetAttr(ANode, 'Path', sPath) then begin FlagAvortInsertion := False; LocalHotDir := THotDir.Create; if sName = '-' then begin LocalHotDir.Dispatcher := hd_SEPARATOR; end else begin if sName = '--' then begin LocalHotDir.Dispatcher := hd_ENDMENU; if CurrentMenuLevel > 0 then Dec(CurrentMenuLevel) else FlagAvortInsertion := True; //Sanity correction in case we got corrupted from any ways end else begin if (UTF8Length(sName) > 1) then begin if (sName[1] = '-') and (sName[2] <> '-') then begin Inc(CurrentMenuLevel); LocalHotDir.Dispatcher := hd_STARTMENU; LocalHotDir.HotDirName := UTF8RightStr(sName, UTF8Length(sName) - 1); end; end; if LocalHotDir.Dispatcher = hd_NULL then begin LocalHotDir.HotDirName := sName; LocalHotDir.HotDirPath := sPath; if UTF8Pos('cm_', UTF8LowerCase(sPath)) <> 1 then begin LocalHotDir.HotDirPathSort := AConfig.GetAttr(Anode, 'PathSort', 0); LocalHotDir.HotDirTarget := AConfig.GetAttr(ANode, 'Target', ''); LocalHotDir.HotDirTargetSort := AConfig.GetAttr(Anode, 'TargetSort', 0); if Pos('://', LocalHotDir.HotDirPath) = 0 then LocalHotDir.HotDirPath:=ExcludeBackPathDelimiter(LocalHotDir.HotDirPath); if Pos('://', LocalHotDir.HotDirTarget) = 0 then LocalHotDir.HotDirTarget:=ExcludeBackPathDelimiter(LocalHotDir.HotDirTarget); LocalHotDir.Dispatcher := hd_CHANGEPATH; end else begin LocalHotDir.Dispatcher := hd_COMMAND; end; end; end; end; if not FlagAvortInsertion then begin Add(LocalHotDir); end else begin LocalHotDir.Free; end; end; end; ANode := ANode.NextSibling; end; //Try to fix possible problem if the LAST MENU is not ending correctly... while CurrentMenuLevel > 0 do begin Dec(CurrentMenuLevel); LocalHotDir := THotDir.Create; LocalHotDir.Dispatcher := hd_ENDMENU; Add(LocalHotDir); end; end; end; { TDirectoryHotlist.SaveToXml } // Information are stored like originally DC was storing them WITH addition of menu related info in a simular way TC. // When the parameter has the same value as it would have when loaded with no value (so with the default value), the parameter is not saved... // ...this way, it makes the overall filelenth smaller. When running on a portable mode from a usb key, everything thing counts! :-) // ..."Name" and "Path" always must be present for backward compatibility reason in case someone would go backward. // ...Not saving the value that are correctly initialized anyway as default on startup, with a setup of 386 entries for example saved 6642 bytes (5.3% of original 126005 bytes file) // procedure TDirectoryHotlist.SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode; FlagEraseOriginalOnes: boolean); var Index: integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, cSectionOfHotDir, True); if FlagEraseOriginalOnes then AConfig.ClearNode(ANode); for Index := 0 to pred(Count) do begin SubNode := AConfig.AddNode(ANode, 'HotDir'); case THotDir(HotDir[Index]).Dispatcher of hd_NULL: begin AConfig.SetAttr(SubNode, 'Name', ''); AConfig.SetAttr(SubNode, 'Path', ''); end; hd_CHANGEPATH: begin AConfig.SetAttr(SubNode, 'Name', HotDir[Index].HotDirName); AConfig.SetAttr(SubNode, 'Path', HotDir[Index].HotDirPath); if HotDir[Index].HotDirTarget <> '' then AConfig.SetAttr(SubNode, 'Target', HotDir[Index].HotDirTarget); if HotDir[Index].HotDirPathSort <> 0 then AConfig.SetAttr(SubNode, 'PathSort', HotDir[Index].HotDirPathSort); if HotDir[Index].HotDirTargetSort <> 0 then AConfig.SetAttr(SubNode, 'TargetSort', HotDir[Index].HotDirTargetSort); end; hd_SEPARATOR: begin AConfig.SetAttr(SubNode, 'Name', '-'); AConfig.SetAttr(SubNode, 'Path', ''); end; hd_STARTMENU: begin AConfig.SetAttr(SubNode, 'Name', '-' + THotDir(HotDir[Index]).HotDirName); AConfig.SetAttr(SubNode, 'Path', ''); end; hd_ENDMENU: begin AConfig.SetAttr(SubNode, 'Name', '--'); AConfig.SetAttr(SubNode, 'Path', ''); end; hd_COMMAND: begin AConfig.SetAttr(SubNode, 'Name', HotDir[Index].HotDirName); AConfig.SetAttr(SubNode, 'Path', HotDir[Index].HotDirPath); if HotDir[Index].HotDirTarget <> '' then AConfig.SetAttr(SubNode, 'Target', HotDir[Index].HotDirTarget); end; end; end; end; { TDirectoryHotlist.ImportDoubleCommander } procedure TDirectoryHotlist.ImportDoubleCommander(DoubleCommanderFilename: String); var DoubleCommanderXMLToImport: TXmlConfig; Root: TXmlNode; begin DoubleCommanderXMLToImport := TXmlConfig.Create(DoubleCommanderFilename); try if DoubleCommanderXMLToImport.Load then begin Root := DoubleCommanderXMLToImport.RootNode; LoadFromXML(DoubleCommanderXMLToImport, Root); end; finally FreeAndNil(DoubleCommanderXMLToImport); end; end; { TDirectoryHotlist.ExportDoubleCommander } function TDirectoryHotlist.ExportDoubleCommander(DoubleCommanderFilename: String; FlagEraseOriginalOnes: boolean): boolean; var DoubleCommanderXMLToImport: TXmlConfig; Root: TXmlNode; FlagKeepGoing: boolean; begin Result := False; //Unless we reach correctly the end, the result is negative FlagKeepGoing := True; DoubleCommanderXMLToImport := TXmlConfig.Create(DoubleCommanderFilename); try //Just in case we're requested to add or update content of a .XML file will already other data in it, first we load the structure if FileExists(DoubleCommanderFilename) then FlagKeepGoing := DoubleCommanderXMLToImport.Load; if FlagKeepGoing then begin Root := DoubleCommanderXMLToImport.RootNode; SaveToXml(DoubleCommanderXMLToImport, Root, FlagEraseOriginalOnes); Result := DoubleCommanderXMLToImport.Save; end; finally FreeAndNil(DoubleCommanderXMLToImport); end; end; { TDirectoryHotlist.AddFromAnotherTTreeViewTheSelected } //It looks the ".selected" field only gives us the kind of "itemindex" of current selection in the TTREE. //So, the apparent way to detect the current selected node is to check the ".Selection" fields. //So, we'll set the "GroupNumber" of pointed HotDir to 1 to indicate the one to import. // function TDirectoryHotlist.AddFromAnotherTTreeViewTheSelected(ParamWorkingTreeView, ParamTreeViewToImport:TTreeView; FlagAddThemAll: boolean): longint; procedure RecursiveAddTheOnesWithGroupNumberOne(WorkingTreeNode:TTreeNode; InsertionNodePlace:TTreeNode); var MaybeChildNode:TTreeNode; WorkingHotDirEntry:THotDir; NewTreeNode:TTreeNode; begin while WorkingTreeNode<>nil do begin MaybeChildNode:=WorkingTreeNode.GetFirstChild; if MaybeChildNode<>nil then begin if (THotDir(WorkingTreeNode.Data).GroupNumber = 1) OR (FlagAddThemAll) then begin WorkingHotDirEntry:=THotDir.Create; THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry); WorkingHotDirEntry.Dispatcher:=hd_STARTMENU; //Probably not necessary, but let's make sure it will start a menu Add(WorkingHotDirEntry); if ParamWorkingTreeView<>nil then begin NewTreeNode := ParamWorkingTreeView.Items.AddChildObject(InsertionNodePlace, WorkingHotDirEntry.HotDirName,HotDir[count-1]); NewTreeNode.ImageIndex:=ICONINDEX_SUBMENU; NewTreeNode.SelectedIndex:=ICONINDEX_SUBMENU; NewTreeNode.StateIndex:=ICONINDEX_SUBMENU; end; inc(result); end; RecursiveAddTheOnesWithGroupNumberOne(MaybeChildNode,NewTreeNode); if (THotDir(WorkingTreeNode.Data).GroupNumber=1) OR (FlagAddThemAll) then begin WorkingHotDirEntry:=THotDir.Create; WorkingHotDirEntry.Dispatcher:=hd_ENDMENU; Add(WorkingHotDirEntry); end; end else begin if (THotDir(WorkingTreeNode.Data).GroupNumber=1) OR (FlagAddThemAll) then begin WorkingHotDirEntry:=THotDir.Create; THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry); Add(WorkingHotDirEntry); if ParamWorkingTreeView<>nil then begin case WorkingHotDirEntry.Dispatcher of hd_Separator: NewTreeNode := ParamWorkingTreeView.Items.AddChildObject(InsertionNodePlace, HOTLIST_SEPARATORSTRING, HotDir[count-1]); else NewTreeNode := ParamWorkingTreeView.Items.AddChildObject(InsertionNodePlace, WorkingHotDirEntry.HotDirName, HotDir[count-1]); end; end; inc(result); end; end; WorkingTreeNode:=WorkingTreeNode.GetNextSibling; end; end; procedure RecursiveSetGroupNumberToOne(WorkingTreeNode:TTreeNode; FlagTakeAlsoSibling:boolean); begin repeat if WorkingTreeNode.GetFirstChild=nil then begin if (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_STARTMENU) AND (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_ENDMENU) then begin THotDir(WorkingTreeNode.Data).GroupNumber:=1; end; end else begin THotDir(WorkingTreeNode.Data).GroupNumber:=1; RecursiveSetGroupNumberToOne(WorkingTreeNode.GetFirstChild,TRUE); end; if FlagTakeAlsoSibling then WorkingTreeNode:=WorkingTreeNode.GetNextSibling; until (FlagTakeAlsoSibling=FALSE) OR (WorkingTreeNode=nil); end; var OutsideIndex:integer; begin result:=0; //First, make sure no one is marked for OutsideIndex:=0 to pred(ParamTreeViewToImport.Items.Count) do THotDir(ParamTreeViewToImport.Items.Item[OutsideIndex].Data).GroupNumber:=0; //Then, set the "GroupNumber" to 1 to the ones to import if ParamTreeViewToImport.SelectionCount>0 then for OutsideIndex:=0 to pred(ParamTreeViewToImport.SelectionCount) do RecursiveSetGroupNumberToOne(ParamTreeViewToImport.Selections[OutsideIndex],FALSE); //Finally now collect the one with the "GroupNumber" set to 1. RecursiveAddTheOnesWithGroupNumberOne(ParamTreeViewToImport.Items.Item[0],nil); end; { TDirectoryHotlist.ComputeSignature } // Routine tries to pickup all char chain from element of directory hotlist and compute a unique CRC32. // This CRC32 will bea kind of signature of the directory hotlist. function TDirectoryHotlist.ComputeSignature(Seed:dword):dword; var Index:integer; begin result:=Seed; for Index := 0 to pred(Count) do begin Result := crc32(Result,@HotDir[Index].Dispatcher,1); if length(HotDir[Index].HotDirName)>0 then Result := crc32(Result,@HotDir[Index].HotDirName[1],length(HotDir[Index].HotDirName)); if length(HotDir[Index].HotDirPath)>0 then Result := crc32(Result,@HotDir[Index].HotDirPath[1],length(HotDir[Index].HotDirPath)); Result := crc32(Result,@HotDir[Index].HotDirPathSort,4); if length(HotDir[Index].HotDirTarget)>0 then Result := crc32(Result,@HotDir[Index].HotDirTarget[1],length(HotDir[Index].HotDirTarget)); Result := crc32(Result,@HotDir[Index].HotDirTargetSort,4); Result := crc32(Result,@HotDir[Index].HotDirExisting,1); Result := crc32(Result,@HotDir[Index].GroupNumber,4); end; end; { TDirectoryHotlist.GetHotDir } function TDirectoryHotlist.GetHotDir(Index: integer): THotDir; begin Result := THotDir(Items[Index]); end; { TDirectoryHotlist.RefreshFromTTreeView } //The routine will recreate the complete TDirectoryHotlist from a TTreeView. //It cannot erase or replace immediately the current list because the TTreeView refer to it! //So it create it into the "TransitDirectoryHotlist" and then, it will copy it to self one. // procedure TDirectoryHotlist.RefreshFromTTreeView(ParamTreeView:TTreeView); var TransitDirectoryHotlist:TDirectoryHotlist; IndexToTryToRestore:longint=-1; MaybeTTreeNodeToSelect:TTreeNode; procedure RecursiveEncapsulateSubMenu(WorkingTreeNode:TTreeNode); var MaybeChildNode:TTreeNode; WorkingHotDirEntry:THotDir; begin while WorkingTreeNode<>nil do begin if WorkingTreeNode=ParamTreeView.Selected then IndexToTryToRestore:=TransitDirectoryHotlist.Count; MaybeChildNode:=WorkingTreeNode.GetFirstChild; if MaybeChildNode<>nil then begin WorkingHotDirEntry:=THotDir.Create; THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry); WorkingHotDirEntry.Dispatcher:=hd_STARTMENU; //Probably not necessary, but let's make sure it will start a menu TransitDirectoryHotlist.Add(WorkingHotDirEntry); RecursiveEncapsulateSubMenu(MaybeChildNode); WorkingHotDirEntry:=THotDir.Create; WorkingHotDirEntry.Dispatcher:=hd_ENDMENU; TransitDirectoryHotlist.Add(WorkingHotDirEntry); end else begin //We won't copy EMPTY submenu so that's why we check for "hd_STARTMENU". And the check for "hd_ENDMENU" is simply probably unecessary protection if (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_STARTMENU) AND (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_ENDMENU) then begin WorkingHotDirEntry:=THotDir.Create; THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry); TransitDirectoryHotlist.Add(WorkingHotDirEntry); end; end; WorkingTreeNode:=WorkingTreeNode.GetNextSibling; end; end; begin if ParamTreeView.Items.count>0 then begin TransitDirectoryHotlist:=TDirectoryHotlist.Create; try RecursiveEncapsulateSubMenu(ParamTreeView.Items.Item[0]); TransitDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist(self); MaybeTTreeNodeToSelect:=LoadTTreeView(ParamTreeView,IndexToTryToRestore); if MaybeTTreeNodeToSelect<>nil then MaybeTTreeNodeToSelect.Selected:=TRUE else if ParamTreeView.Items.count>0 then ParamTreeView.Items.Item[0].Selected:=TRUE; finally TransitDirectoryHotlist.Clear; TransitDirectoryHotlist.Free; end; end else begin Self.Clear; end; end; { TCheckDrivePresenceThread.Create } constructor TCheckDrivePresenceThread.Create(sDrive: string; ParamListOfNonExistingDrive: TStringList; var ThreadCount: longint); begin FListOfNonExistingDrive := ParamListOfNonExistingDrive; FDriveToSearchFor := sDrive; FThreadCountPoint := addr(ThreadCount); FreeOnTerminate := True; inherited Create(False); end; { TCheckDrivePresenceThread.Destroy } destructor TCheckDrivePresenceThread.Destroy; begin inherited Destroy; end; {TCheckDrivePresenceThread.Execute} procedure TCheckDrivePresenceThread.Execute; begin if FDriveToSearchFor = '' then begin Synchronize(@Self.ReportPresentInTheThread); end else begin if mbDirectoryExists(FDriveToSearchFor) then begin Synchronize(@Self.ReportPresentInTheThread); end else begin Synchronize(@Self.ReportNotPresentInTheThread); end; end; Terminate; end; { TCheckDrivePresenceThread.ReportPresentInTheThread } procedure TCheckDrivePresenceThread.ReportPresentInTheThread; begin Dec(FThreadCountPoint^); end; { TCheckDrivePresenceThread.ReportNotPresentInTheThread } procedure TCheckDrivePresenceThread.ReportNotPresentInTheThread; begin FListOfNonExistingDrive.Add(FDriveToSearchFor); Dec(FThreadCountPoint^); end; {$IFDEF MSWINDOWS} { TDirectoryHotlist.ImportTotalCommander } function TDirectoryHotlist.ImportTotalCommander(TotalCommanderConfigFilename: String): integer; const CONFIGFILE_SECTIONNAME = 'DirMenu'; CONFIGFILE_NAMEPREFIX = 'menu'; CONFIGFILE_PATHPREFIX = 'cmd'; CONFIGFILE_TARGETPREFIX = 'path'; var LocalHotDir: THotDir; ConfigFile: TIniFileEx; sName, sPath, sTarget: string; Index, CurrentMenuLevel, InitialNumberOfElement: longint; FlagAvortInsertion: boolean; begin InitialNumberOfElement := Count; Index := 1; CurrentMenuLevel := 0; ConfigFile := TIniFileEx.Create(GetActualTCIni(mbExpandFilename(TotalCommanderConfigFilename), CONFIGFILE_SECTIONNAME)); try repeat sName := ConvertTCStringToString(ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(Index), TERMINATORNOTPRESENT)); if sName <> TERMINATORNOTPRESENT then begin FlagAvortInsertion := False; LocalHotDir := THotDir.Create; if sName = '-' then //Was it a separator? begin LocalHotDir.Dispatcher := hd_SEPARATOR; end else begin if sName = '--' then //Was is a end of menu? begin LocalHotDir.Dispatcher := hd_ENDMENU; if CurrentMenuLevel > 0 then Dec(CurrentMenuLevel) else FlagAvortInsertion := True; //Sanity correction since Total Commande may contains extra end of menu... end else begin if (UTF8Length(sName) > 1) then //Was it a menu start? begin if (sName[1] = '-') and (sName[2] <> '-') then begin Inc(CurrentMenuLevel); LocalHotDir.Dispatcher := hd_STARTMENU; LocalHotDir.HotDirName := UTF8RightStr(sName, UTF8Length(sName) - 1); end; end; if LocalHotDir.Dispatcher = hd_NULL then begin LocalHotDir.HotDirName := sName; sPath := ReplaceTCEnvVars(ConvertTCStringToString(ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_PATHPREFIX + IntToStr(Index), ''))); if UTF8Length(sPath) > 3 then if UTF8Pos('cd ', UTF8LowerCase(sPath)) = 1 then sPath := UTF8Copy(sPath, 4, UTF8Length(sPath) - 3); if UTF8Pos('cm_', UTF8LowerCase(sPath)) = 0 then //Make sure it's not a command begin if sPath <> '' then sPath := ExcludeBackPathDelimiter(sPath); //Not an obligation but DC convention seems to like a backslash at the end sTarget := ReplaceTCEnvVars(ConvertTCStringToString(ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_TARGETPREFIX + IntToStr(Index), ''))); if UTF8Length(sTarget) > 3 then if UTF8Pos('cd ', UTF8LowerCase(sTarget)) = 1 then sTarget := UTF8Copy(sTarget, 4, UTF8Length(sTarget) - 3); if sTarget <> '' then sTarget := ExcludeBackPathDelimiter(sTarget); //Not an obligation but DC convention seems to like a backslash at the end LocalHotDir.Dispatcher := hd_CHANGEPATH; LocalHotDir.HotDirPath := sPath; LocalHotDir.HotDirTarget := sTarget; end else begin //If it's command, store it as a command LocalHotDir.Dispatcher := hd_COMMAND; LocalHotDir.HotDirPath := sPath; end; end; end; end; if not FlagAvortInsertion then Add(LocalHotDir) else LocalHotDir.Free; Inc(Index); end; until sName = TERMINATORNOTPRESENT; //Try to fix possible problem if the LAST MENU is not ending correctly... while CurrentMenuLevel > 0 do begin Dec(CurrentMenuLevel); LocalHotDir := THotDir.Create; LocalHotDir.Dispatcher := hd_ENDMENU; Add(LocalHotDir); end; finally ConfigFile.Free; end; Result := Count - InitialNumberOfElement; end; { TDirectoryHotlist.ExportTotalCommander } function TDirectoryHotlist.ExportTotalCommander(TotalCommanderConfigFilename: String; FlagEraseOriginalOnes: boolean): boolean; const CONFIGFILE_SECTIONNAME = 'DirMenu'; CONFIGFILE_NAMEPREFIX = 'menu'; CONFIGFILE_PATHPREFIX = 'cmd'; CONFIGFILE_TARGETPREFIX = 'path'; TERMINATORNOTPRESENT = ':-<#/?*+*?\#>-:'; var ConfigFile: TIniFileEx; Index, OffsetForOnesAlreadyThere: integer; sName: string; begin Result := True; OffsetForOnesAlreadyThere := 0; try Screen.BeginWaitCursor; try ConfigFile := TIniFileEx.Create(mbExpandFileName(TotalCommanderConfigFilename)); try with ConfigFile do begin if FlagEraseOriginalOnes then begin EraseSection(CONFIGFILE_SECTIONNAME); end else begin Index := 1; repeat sName := ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(Index), TERMINATORNOTPRESENT); if sName <> TERMINATORNOTPRESENT then Inc(OffsetForOnesAlreadyThere); Inc(Index); until sName = TERMINATORNOTPRESENT; end; for Index := 0 to pred(Count) do begin case THotDir(HotDir[Index]).Dispatcher of hd_NULL: begin end; hd_CHANGEPATH: begin WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirName)); if THotDir(HotDir[Index]).HotDirPath <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_PATHPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString('cd ' + ReplaceDCEnvVars(THotDir(HotDir[Index]).HotDirPath))); if THotDir(HotDir[Index]).HotDirTarget <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_TARGETPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(ReplaceDCEnvVars(THotDir(HotDir[Index]).HotDirTarget))); end; hd_SEPARATOR: begin WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), '-'); end; hd_STARTMENU: begin //See the position of the '-'. It *must* be inside the parameter for calling "ConvertStringToTCString" because the expected utf8 signature of TC must be before the '-'. WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString('-' + THotDir(HotDir[Index]).HotDirName)); end; hd_ENDMENU: begin WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), '--'); end; hd_COMMAND: begin WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirName)); if THotDir(HotDir[Index]).HotDirPath <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_PATHPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirPath)); if THotDir(HotDir[Index]).HotDirTarget <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_TARGETPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirTarget)); end; end; end; end; ConfigFile.UpdateFile; finally ConfigFile.Free; end; except Result := False; end; finally Screen.EndWaitCursor; end; end; {$ENDIF} end. doublecmd-1.1.22/src/uhotkeymanager.pas0000644000175000001440000011030114743153644017121 0ustar alexxusers { Double Commander ------------------------------------------------------------------------- HotKey Manager. Allow to set it's own bindings to each TWinControl on form. Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2011-2012 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uHotkeyManager; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, LCLProc, LCLType, LCLIntf, Forms, ActnList, DCClassesUtf8, fgl, contnrs, DCXmlConfig, DCBasicTypes; type generic THMObjectInstance = class Instance: InstanceClass; KeyDownProc: TKeyEvent; end; THMFormInstance = specialize THMObjectInstance; THMControlInstance = specialize THMObjectInstance; { THotkey } THotkey = class Shortcuts: array of String; Command: String; Params: array of String; procedure Assign(Hotkey: THotkey); function Clone: THotkey; function HasParam(const aParam: String): Boolean; overload; function HasParam(const aParams: array of String): Boolean; overload; function SameAs(Hotkey: THotkey): Boolean; function SameParams(const aParams: array of String): Boolean; function SameShortcuts(const aShortcuts: array of String): Boolean; end; TBaseHotkeysList = specialize TFPGObjectList; { TFreeNotifier } TFreeNotifier = class(TComponent) private FFreeEvent: TNotifyEvent; protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; public property OnFree: TNotifyEvent read FFreeEvent write FFreeEvent; end; THotkeyOperation = (hopAdd, hopRemove, hopClear, hopUpdate); THotkeyEvent = procedure (hotkey: THotkey; operation: THotkeyOperation) of object; { THotkeys } THotkeys = class(TBaseHotkeysList) private FOnChange: THotkeyEvent; procedure DoOnChange(hotkey: THotkey; operation: THotkeyOperation); public constructor Create(AFreeObjects: Boolean = True); reintroduce; function Add(const Shortcuts, Params: array of String; Command: String): THotkey; overload; function AddIfNotExists(const Shortcuts, Params: array of String; Command: String): THotkey; overload; {en Adds multiple shortcuts to the same command. @param(ShortcutsWithParams Array of shortcuts followed by any number of parameters. Each shortcuts array must end with an empty string, and similarly each parameters must end with an empty string. [Shortcut1A, Shortcut1B, '', S1ParamA, '', Shortcut2, '', S2ParamA, S2ParamB, '', ...]) @param(Command Command to which the shortcuts should be added.) @param(OldShortcuts, OldParams Adds new shortcuts even if old shortcut exists. If a different shortcuts exists however then doesn't add new one.) } procedure AddIfNotExists(const ShortcutsWithParams: array of String; Command: String; const OldShortcuts, OldParams: array of String); overload; procedure AddIfNotExists(const ShortcutsWithParams: array of String; Command: String); overload; procedure AddIfNotExists(Key: Word; Shift: TShiftState; const Command: String; const Param: String = ''); overload; procedure Clear; reintroduce; procedure Remove(var hotkey: THotkey); reintroduce; function Find(const Shortcuts: array of String): THotkey; {en Find hotkey which shortcuts begin with Shortcuts parameter. If BothWays=@true then also looks for shortcuts which are the beginning of Shortcuts parameter. } function FindByBeginning(const Shortcuts: TDynamicStringArray; BothWays: Boolean): THotkey; function FindByCommand(Command: String): THotkey; function FindByContents(Hotkey: THotkey): THotkey; {en Should be called whenever a hotkey has shortcut updated to update the shortcuts in ActionLists. } procedure UpdateHotkey(Hotkey: THotkey); property OnChange: THotkeyEvent read FOnChange write FOnChange; end; { THMBaseObject } generic THMBaseObject = class private FObjects: TFPObjectList; FHotkeys: THotkeys; FName: String; public constructor Create(AName: String); virtual; destructor Destroy; override; function Add(AInstanceInfo: InstanceInfoClass): Integer; procedure Delete(AInstance: InstanceClass); function Find(AInstance: InstanceClass): InstanceInfoClass; property Hotkeys: THotkeys read FHotkeys; property Name: String read FName; end; THMControl = specialize THMBaseObject; THMBaseControls = specialize TFPGObjectList; { THMControls } THMControls = class(THMBaseControls) procedure Delete(AName: String); overload; function Find(AName: String): THMControl; function Find(AControl: TWinControl): THMControl; function FindOrCreate(AName: String): THMControl; end; THMBaseForm = specialize THMBaseObject; TActionLists = specialize TFPGObjectList; { THMForm } THMForm = class(THMBaseForm) private {en Used for notifying when an ActionList is destroyed. } FFreeNotifier: TFreeNotifier; FActionLists: TActionLists; function GetActionByCommand(ActionList: TActionList; Command: String): TAction; procedure OnActionListFree(Sender: TObject); procedure OnHotkeyEvent(hotkey: THotkey; operation: THotkeyOperation); procedure RemoveActionShortcut(hotkey: THotkey; AssignNextShortcut: Boolean); procedure SetActionShortcut(hotkey: THotkey; OverridePrevious: Boolean); public Controls: THMControls; constructor Create(AName: String); override; destructor Destroy; override; procedure RegisterActionList(ActionList: TActionList); procedure UnregisterActionList(ActionList: TActionList); end; TBaseForms = specialize TFPGObjectList; { THMForms } THMForms = class(TBaseForms) procedure Delete(AName: String); overload; function Find(AName: String): THMForm; function Find(AForm: TCustomForm): THMForm; function FindOrCreate(AName: String): THMForm; end; { THotKeyManager } THotKeyManager = class private FForms: THMForms; FLastShortcutTime: Double; // When last shortcut was received (used for sequences of shortcuts) FSequenceStep: Integer; // Which hotkey we are waiting for (from 0) FShortcutsSequence: TDynamicStringArray; // Sequence of shortcuts that has been processed since last key event FVersion: Integer; //--------------------- procedure ClearAllHotkeys; //Hotkey Handler procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState); //--------------------- //This function is called from KeyDownHandler to find registered hotkey and execute assigned action function HotKeyEvent(Form: TCustomForm; Hotkeys: THotkeys): Boolean; //--------------------- function RegisterForm(AFormName: String): THMForm; function RegisterControl(AFormName: String; AControlName: String): THMControl; //--------------------- procedure Save(Config: TXmlConfig; Root: TXmlNode); procedure Load(Config: TXmlConfig; Root: TXmlNode); procedure LoadIni(FileName: String); public constructor Create; destructor Destroy; override; //--------------------- procedure Save(FileName: String); procedure Load(FileName: String); //--------------------- function Register(AForm: TCustomForm; AFormName: String): THMForm; function Register(AControl: TWinControl; AControlName: String): THMControl; procedure UnRegister(AForm: TCustomForm); procedure UnRegister(AControl: TWinControl); //--------------------- property Forms: THMForms read FForms; property Version: Integer read FVersion; end; implementation uses Laz2_XMLRead, uKeyboard, uGlobs, uDebug, uDCVersion, uFormCommands, DCOSUtils, DCStrUtils; const MaxShortcutSequenceInterval = 1000; // in ms { THotkey } procedure THotkey.Assign(Hotkey: THotkey); begin Shortcuts := Copy(Hotkey.Shortcuts); Params := Copy(Hotkey.Params); Command := Hotkey.Command; end; function THotkey.Clone: THotkey; begin Result := THotkey.Create; Result.Assign(Self); end; function THotkey.HasParam(const aParams: array of String): Boolean; begin Result := ContainsOneOf(Params, aParams); end; function THotkey.HasParam(const aParam: String): Boolean; begin Result := Contains(Params, aParam); end; function THotkey.SameAs(Hotkey: THotkey): Boolean; begin Result := (Command = Hotkey.Command) and (SameShortcuts(Hotkey.Shortcuts)) and (SameParams(Hotkey.Params)); end; function THotkey.SameParams(const aParams: array of String): Boolean; begin Result := Compare(Params, aParams); end; function THotkey.SameShortcuts(const aShortcuts: array of String): Boolean; begin Result := Compare(Shortcuts, aShortcuts); end; { TFreeNotifier } procedure TFreeNotifier.Notification(AComponent: TComponent; Operation: TOperation); begin if (Operation = opRemove) and Assigned(FFreeEvent) then FFreeEvent(AComponent); inherited Notification(AComponent, Operation); end; { THotkeys } constructor THotkeys.Create(AFreeObjects: Boolean); begin FOnChange := nil; inherited Create(AFreeObjects); end; function THotkeys.Add(const Shortcuts, Params: array of String; Command: String): THotkey; begin if (Command <> EmptyStr) and (Length(Shortcuts) > 0) then begin Result := THotkey.Create; Result.Shortcuts := CopyArray(Shortcuts); Result.Params := CopyArray(Params); Result.Command := Command; Add(Result); DoOnChange(Result, hopAdd); end else Result := nil; end; function THotkeys.AddIfNotExists(const Shortcuts, Params: array of String; Command: String): THotkey; var i: Integer; begin // Check if the shortcuts aren't already assigned to a different command // or if a different shortcut isn't already assigned to the command. // Also check if the shortucts aren't a partial match to another shortcuts. for i := 0 to Count - 1 do begin if ArrBegins(Items[i].Shortcuts, Shortcuts, True) or (Items[i].Command = Command) then Exit(nil); end; Result := Add(Shortcuts, Params, Command); end; procedure THotkeys.AddIfNotExists(const ShortcutsWithParams: array of String; Command: String); begin AddIfNotExists(ShortcutsWithParams, Command, [], []); end; procedure THotkeys.AddIfNotExists(Key: Word; Shift: TShiftState; const Command: String; const Param: String); var AParams: TDynamicStringArray; begin if (Length(Param) > 0) then AddString(AParams, Param); AddIfNotExists([VirtualKeyToText(Key, Shift)], AParams, Command); end; procedure THotkeys.AddIfNotExists(const ShortcutsWithParams: array of String; Command: String; const OldShortcuts, OldParams: array of String); var s: String; StartIndex: Integer; function GetArray: TDynamicStringArray; var Index: Integer; begin Result := nil; Index := StartIndex; while Index <= High(ShortcutsWithParams) do begin s := ShortcutsWithParams[Index]; if s <> '' then AddString(Result, s) else Break; Inc(Index); end; StartIndex := Index + 1; end; function CheckIfOldOrEmpty: Boolean; var i: Integer; begin for i := 0 to Count - 1 do if Items[i].Command = Command then begin if not (Items[i].SameShortcuts(OldShortcuts) and Items[i].SameParams(OldParams)) then Exit(False); end; Result := True; end; var Shortcuts, Params: array of String; begin // Check if a different shortcut isn't already assigned to the command. // If there is only the old shortcut then allow adding new one. if not CheckIfOldOrEmpty then Exit; StartIndex := Low(ShortcutsWithParams); while True do begin Shortcuts := GetArray; Params := GetArray; if Length(Shortcuts) > 0 then begin // Check if the shortcuts aren't already assigned to a different command. if not Assigned(FindByBeginning(Shortcuts, True)) then Add(Shortcuts, Params, Command); end else Break; end; end; procedure THotkeys.Clear; var i: Integer; begin for i := 0 to Count - 1 do begin DoOnChange(Items[0], hopClear); inherited Delete(0); end; end; procedure THotkeys.Remove(var hotkey: THotkey); begin if Assigned(hotkey) then begin DoOnChange(hotkey, hopRemove); inherited Remove(hotkey); if FreeObjects then hotkey := nil; end; end; procedure THotkeys.UpdateHotkey(Hotkey: THotkey); begin DoOnChange(Hotkey, hopUpdate); end; function THotkeys.Find(const Shortcuts: array of String): THotkey; var i: Integer; begin for i := 0 to Count - 1 do if Items[i].SameShortcuts(Shortcuts) then Exit(Items[i]); Result := nil; end; function THotkeys.FindByBeginning(const Shortcuts: TDynamicStringArray; BothWays: Boolean): THotkey; var i: Integer; begin for i := 0 to Count - 1 do if ArrBegins(Items[i].Shortcuts, Shortcuts, BothWays) then Exit(Items[i]); Result := nil; end; function THotkeys.FindByCommand(Command: String): THotkey; var i: Integer; begin for i := 0 to Count - 1 do if Items[i].Command = Command then Exit(Items[i]); Result := nil; end; function THotkeys.FindByContents(Hotkey: THotkey): THotkey; var i: Integer; begin for i := 0 to Count - 1 do begin Result := Items[i]; if Result.SameAs(Hotkey) then Exit; end; Result := nil; end; procedure THotkeys.DoOnChange(hotkey: THotkey; operation: THotkeyOperation); begin if Assigned(FOnChange) then FOnChange(hotkey, operation); end; { THMForm } constructor THMForm.Create(AName: String); begin FFreeNotifier := nil; inherited; Controls := THMControls.Create(True); FActionLists := TActionLists.Create(False); end; destructor THMForm.Destroy; begin inherited; Controls.Free; FActionLists.Free; FFreeNotifier.Free; end; procedure THMForm.RegisterActionList(ActionList: TActionList); var i: Integer; begin if FActionLists.IndexOf(ActionList) < 0 then begin FActionLists.Add(ActionList); Hotkeys.OnChange := @OnHotkeyEvent; if not Assigned(FFreeNotifier) then begin FFreeNotifier := TFreeNotifier.Create(nil); FFreeNotifier.OnFree := @OnActionListFree; end; ActionList.FreeNotification(FFreeNotifier); // Initialize actionlist with shortcuts. for i := 0 to hotkeys.Count - 1 do SetActionShortcut(hotkeys[i], False); end; end; procedure THMForm.UnregisterActionList(ActionList: TActionList); begin if FActionLists.Remove(ActionList) >= 0 then ActionList.RemoveFreeNotification(FFreeNotifier); end; function THMForm.GetActionByCommand(ActionList: TActionList; Command: String): TAction; var action: TContainedAction; begin action := ActionList.ActionByName('act' + Copy(Command, 4, Length(Command) - 3)); if action is TAction then Result := action as TAction else Result := nil; end; procedure THMForm.OnActionListFree(Sender: TObject); begin if Sender is TActionList then UnregisterActionList(Sender as TActionList); end; procedure THMForm.OnHotkeyEvent(hotkey: THotkey; operation: THotkeyOperation); begin case operation of hopAdd: SetActionShortcut(hotkey, False); hopRemove: RemoveActionShortcut(hotkey, True); hopClear: RemoveActionShortcut(hotkey, False); hopUpdate: SetActionShortcut(hotkey, True); end; end; procedure THMForm.RemoveActionShortcut(hotkey: THotkey; AssignNextShortcut: Boolean); var action: TAction; i, j: Integer; shortcut, newShortcut: TShortCut; begin shortcut := TextToShortCutEx(hotkey.Shortcuts[0]); for i := 0 to FActionLists.Count - 1 do begin action := GetActionByCommand(FActionLists[i], hotkey.Command); if Assigned(action) then begin if action.Shortcut = shortcut then begin newShortcut := VK_UNKNOWN; if AssignNextShortcut then begin // Search for another possible hotkey assigned for the same command. for j := 0 to hotkeys.Count - 1 do if (hotkeys[j].Command = hotkey.Command) and (hotkeys[j] <> hotkey) then begin newShortcut := TextToShortCutEx(hotkeys[j].Shortcuts[0]); Break; end; end; action.ShortCut := newShortcut; end; end; end; end; procedure THMForm.SetActionShortcut(hotkey: THotkey; OverridePrevious: Boolean); var action: TAction; i: Integer; shortcut: TShortCut; begin if Length(hotkey.Params) > 0 then Exit; shortcut := TextToShortCutEx(hotkey.Shortcuts[0]); for i := 0 to FActionLists.Count - 1 do begin action := GetActionByCommand(FActionLists[i], hotkey.Command); if Assigned(action) then begin if OverridePrevious or (action.Shortcut = VK_UNKNOWN) then action.ShortCut := shortcut; end; end; end; { THMBaseObject } constructor THMBaseObject.Create(AName: String); begin FName := AName; FHotkeys := THotkeys.Create(True); FObjects := TFPObjectList.Create(True); end; destructor THMBaseObject.Destroy; begin inherited Destroy; FHotkeys.Free; FObjects.Free; end; function THMBaseObject.Add(AInstanceInfo: InstanceInfoClass): Integer; begin Result := FObjects.Add(AInstanceInfo); end; procedure THMBaseObject.Delete(AInstance: InstanceClass); var i: Integer; begin for i := 0 to FObjects.Count - 1 do if InstanceInfoClass(FObjects[i]).Instance = AInstance then begin FObjects.Delete(i); Exit; end; end; function THMBaseObject.Find(AInstance: InstanceClass): InstanceInfoClass; var i: Integer; begin for i := 0 to FObjects.Count - 1 do begin if InstanceInfoClass(FObjects[i]).Instance = AInstance then Exit(InstanceInfoClass(FObjects[i])); end; Result := nil; end; { THMControls } procedure THMControls.Delete(AName: String); var i: Integer; begin for i := 0 to Count - 1 do if SameText(Items[i].Name, AName) then begin Delete(i); Exit; end; end; function THMControls.Find(AName: String): THMControl; var i: Integer; begin for i := 0 to Count - 1 do if SameText(Items[i].Name, AName) then Exit(Items[i]); Result := nil; end; function THMControls.Find(AControl: TWinControl): THMControl; var i: Integer; begin for i := 0 to Count - 1 do begin if Assigned(Items[i].Find(AControl)) then Exit(Items[i]); end; Result := nil; end; function THMControls.FindOrCreate(AName: String): THMControl; begin Result := Find(AName); if not Assigned(Result) then begin Result := THMControl.Create(AName); Add(Result); end; end; { THMForms } procedure THMForms.Delete(AName: String); var i: Integer; begin for i := 0 to Count - 1 do if SameText(Items[i].Name, AName) then begin Delete(i); Exit; end; end; function THMForms.Find(AName: String): THMForm; var i: Integer; begin for i := 0 to Count - 1 do begin if SameText(Items[i].Name, AName) then Exit(Items[i]); end; Result := nil; end; function THMForms.Find(AForm: TCustomForm): THMForm; var i: Integer; begin for i := 0 to Count - 1 do begin if Assigned(Items[i].Find(AForm)) then Exit(Items[i]); end; Result := nil; end; function THMForms.FindOrCreate(AName: String): THMForm; begin Result := Find(AName); if not Assigned(Result) then begin Result := THMForm.Create(AName); Add(Result); end; end; { THotKeyManager } constructor THotKeyManager.Create; begin FForms := THMForms.Create(True); FSequenceStep := 0; end; destructor THotKeyManager.Destroy; begin inherited Destroy; FForms.Free; end; procedure THotKeyManager.Save(FileName: String); var Config: TXmlConfig = nil; begin try Config := TXmlConfig.Create(FileName, True); Config.SetAttr(Config.RootNode, 'DCVersion', dcVersion); Save(Config, Config.RootNode); Config.Save; finally Config.Free; end; end; procedure THotKeyManager.Load(FileName: String); var Config: TXmlConfig = nil; NotAnXML: Boolean = False; begin try Config := TXmlConfig.Create(FileName); try if Config.Load then Load(Config, Config.RootNode); finally Config.Free; end; except on EXMLReadError do NotAnXML := True; end; if NotAnXML then begin LoadIni(FileName); // Immediately save as xml so that configuration isn't lost. if mbRenameFile(FileName, FileName + '.ini.obsolete') then Save(FileName); end; end; procedure THotKeyManager.Save(Config: TXmlConfig; Root: TXmlNode); var SavedHotkeys: THotkeys; procedure SaveHotkeys(Form: THMForm; Hotkeys: THotkeys; ControlIndex: Integer; Node: TXmlNode); var i, j: Integer; HotkeyNode, ControlNode: TXmlNode; Control: THMControl; procedure AddControl(AName: String); begin ControlNode := Config.AddNode(HotkeyNode, 'Control'); Config.SetContent(ControlNode, AName); end; begin for i := 0 to Hotkeys.Count - 1 do begin // Save Form's hotkeys and hotkeys which have not been saved yet. if (ControlIndex < 0) or (not Assigned(SavedHotkeys.FindByContents(Hotkeys[i]))) then begin HotkeyNode := Config.AddNode(Node, 'Hotkey'); for j := Low(Hotkeys[i].Shortcuts) to High(Hotkeys[i].Shortcuts) do Config.AddValue(HotkeyNode, 'Shortcut', Hotkeys[i].Shortcuts[j]); Config.AddValue(HotkeyNode, 'Command', Hotkeys[i].Command); for j := Low(Hotkeys[i].Params) to High(Hotkeys[i].Params) do Config.AddValue(HotkeyNode, 'Param', Hotkeys[i].Params[j]); if ControlIndex >= 0 then AddControl(Form.Controls[ControlIndex].Name); // Search all successive controls for the same hotkey. for j := Succ(ControlIndex) to Form.Controls.Count - 1 do begin Control := Form.Controls[j]; if Assigned(Control.Hotkeys.FindByContents(Hotkeys[i])) then AddControl(Control.Name); end; SavedHotkeys.Add(Hotkeys[i]); end; end; end; var i, j: Integer; FormNode: TXmlNode; Form: THMForm; begin Root := Config.FindNode(Root, 'Hotkeys', True); Config.ClearNode(Root); Config.SetAttr(Root, 'Version', hkVersion); SavedHotkeys := THotkeys.Create(False); try for i := 0 to FForms.Count - 1 do begin Form := FForms[i]; FormNode := Config.AddNode(Root, 'Form'); Config.SetAttr(FormNode, 'Name', Form.Name); SaveHotkeys(Form, Form.Hotkeys, -1, FormNode); for j := 0 to Form.Controls.Count - 1 do SaveHotkeys(Form, Form.Controls[j].Hotkeys, j, FormNode); end; finally SavedHotkeys.Free; end; end; procedure THotKeyManager.Load(Config: TXmlConfig; Root: TXmlNode); var Form: THMForm; procedure AddIfNotEmpty(var Arr: TDynamicStringArray; const Value: String); begin if Value <> '' then AddString(Arr, Value); end; procedure LoadHotkey(FormName: String; Hotkeys: THotkeys; Node: TXmlNode); const RenamedCommandsMain: array [0..1] of record OldName, NewName: String; SinceVersion: Integer end = ( (OldName: 'cm_RemoveTab'; NewName: 'cm_CloseTab'; SinceVersion: 14), (OldName: 'cm_RemoveAllTabs'; NewName: 'cm_CloseAllTabs'; SinceVersion: 14) ); var Shortcut, Command, Param: String; Shortcuts: array of String = nil; Params: array of String = nil; Controls: array of String = nil; HMControl: THMControl; i: Integer; begin // These checks for version may be removed after 0.5.5 release because // the XML format for hotkeys has only been added in development version 0.5.5. // Only Command needs to be retrieved here. if FVersion <= 1 then Command := Config.GetAttr(Node, 'Command', '') else Command := Config.GetValue(Node, 'Command', ''); // Leave only this or move this to the loop "while Assigned(Node) do" below if FVersion <= 1 then Param := Config.GetAttr(Node, 'Params', '') else if FVersion < 9 then Param := Config.GetValue(Node, 'Params', ''); if FVersion < 10 then begin Shortcut := Config.GetAttr(Node, 'Key', ''); if Shortcut <> '' then begin Shortcut := NormalizeModifiers(Shortcut); AddIfNotEmpty(Shortcuts, Shortcut); end; end; if (FVersion < 9) then AddIfNotEmpty(Params, Param); // Up to here may be deleted after 0.5.5 release. Node := Node.FirstChild; while Assigned(Node) do begin if Node.CompareName('Shortcut') = 0 then AddIfNotEmpty(Shortcuts, NormalizeModifiers(Config.GetContent(Node))) else if Node.CompareName('Control') = 0 then AddIfNotEmpty(Controls, Config.GetContent(Node)) else if Node.CompareName('Param') = 0 then AddIfNotEmpty(Params, Config.GetContent(Node)); Node := Node.NextSibling; end; if Command <> EmptyStr then begin // Rename commands that have changed names. if FormName = 'Main' then begin for i := Low(RenamedCommandsMain) to High(RenamedCommandsMain) do begin if (FVersion <= RenamedCommandsMain[i].SinceVersion) and (Command = RenamedCommandsMain[i].OldName) then Command := RenamedCommandsMain[i].NewName; end; end; if Length(Shortcuts) > 0 then begin if Length(Controls) = 0 then begin // This "if" block may also be deleted after 0.5.5 release. if (FVersion <= 3) and IsShortcutConflictingWithOS(Shortcuts[0]) then begin HMControl := Form.Controls.FindOrCreate('Files Panel'); HMControl.Hotkeys.AddIfNotExists(Shortcuts, Params, Command); end else Hotkeys.Add(Shortcuts, Params, Command); // Leave only this end else begin for i := Low(Controls) to High(Controls) do begin HMControl := Form.Controls.FindOrCreate(Controls[i]); HMControl.Hotkeys.Add(Shortcuts, Params, Command); end; end; end; end; end; var FormNode, HotkeyNode: TXmlNode; AName: String; begin ClearAllHotkeys; Root := Config.FindNode(Root, 'Hotkeys'); if Assigned(Root) then begin FVersion := Config.GetAttr(Root, 'Version', hkVersion); FormNode := Root.FirstChild; while Assigned(FormNode) do begin if (FormNode.CompareName('Form') = 0) and (Config.TryGetAttr(FormNode, 'Name', AName)) and (AName <> EmptyStr) then begin Form := FForms.FindOrCreate(AName); HotkeyNode := FormNode.FirstChild; while Assigned(HotkeyNode) do begin if HotkeyNode.CompareName('Hotkey') = 0 then LoadHotkey(Form.Name, Form.Hotkeys, HotkeyNode); HotkeyNode := HotkeyNode.NextSibling; end; end; FormNode := FormNode.NextSibling; end; end; end; procedure THotKeyManager.LoadIni(FileName: String); var st: TStringList; ini: TIniFileEx; i, j: Integer; section: String; shortCut: String; hotkeys: THotkeys; form: THMForm; control: THMControl; Command, Param, FormName, ControlName: String; Params: array of String = nil; procedure RemoveFrmPrexif(var s: String); begin if SameText(Copy(s, 1, 3), 'Frm') then Delete(s, 1, 3); end; begin ClearAllHotkeys; st := TStringList.Create; ini := TIniFileEx.Create(FileName); ini.ReadSections(st); for i := 0 to st.Count - 1 do begin section := st[i]; shortCut := NormalizeModifiers(section); if shortCut <> '' then begin j := 0; while ini.ValueExists(section, 'Command' + IntToStr(j)) do begin Command := ini.ReadString(section, 'Command' + IntToStr(j), ''); Param := ini.ReadString(section, 'Param' + IntToStr(j), ''); ControlName := ini.ReadString(section, 'Object' + IntToStr(j), ''); FormName := ini.ReadString(section, 'Form' + IntToStr(j), ''); RemoveFrmPrexif(FormName); RemoveFrmPrexif(ControlName); form := FForms.FindOrCreate(FormName); if IsShortcutConflictingWithOS(shortCut) then ControlName := 'Files Panel'; // Old config had FormName=ControlName for main form. if SameText(FormName, ControlName) then begin hotkeys := form.Hotkeys; end else begin control := form.Controls.FindOrCreate(ControlName); hotkeys := control.Hotkeys; end; if Param <> '' then begin SetLength(Params, 1); Params[0] := Param; end else Params := nil; hotkeys.Add([shortcut], Params, Command); j := j + 1; end; end; end; FreeAndNil(st); FreeAndNil(ini); end; function THotKeyManager.Register(AForm: TCustomForm; AFormName: String): THMForm; var formInstance: THMFormInstance; begin Result := RegisterForm(AFormName); formInstance := Result.Find(AForm); if not Assigned(formInstance) then begin formInstance := THMFormInstance.Create; formInstance.Instance := AForm; formInstance.KeyDownProc := AForm.OnKeyDown; Result.Add(formInstance); AForm.OnKeyDown := @KeyDownHandler; AForm.KeyPreview := True; end; end; function THotKeyManager.Register(AControl: TWinControl; AControlName: String): THMControl; var ParentForm: TCustomForm; form: THMForm; controlInstance: THMControlInstance; begin ParentForm := GetParentForm(AControl); if Assigned(ParentForm) then begin form := FForms.Find(ParentForm); if not Assigned(form) then begin DCDebug('HotMan: Failed registering ' + AControlName + ': Form ' + ParentForm.ClassName + ':' + ParentForm.Name + ' not registered.'); Exit(nil); end; Result := form.Controls.Find(AControlName); if not Assigned(Result) then begin Result := THMControl.Create(AControlName); form.Controls.Add(Result); end; controlInstance := Result.Find(AControl); if not Assigned(controlInstance) then begin controlInstance := THMControlInstance.Create; controlInstance.Instance := AControl; controlInstance.KeyDownProc := AControl.OnKeyDown; Result.Add(controlInstance); //AControl.OnKeyDown := @KeyDownHandler; end; end; end; function THotKeyManager.RegisterForm(AFormName: String): THMForm; begin Result := FForms.Find(AFormName); if not Assigned(Result) then begin Result := THMForm.Create(AFormName); FForms.Add(Result); end; end; function THotKeyManager.RegisterControl(AFormName: String; AControlName: String): THMControl; var form: THMForm; begin form := RegisterForm(AFormName); Result := form.Controls.Find(AControlName); if not Assigned(Result) then begin Result := THMControl.Create(AControlName); form.Controls.Add(Result); end; end; procedure THotKeyManager.UnRegister(AForm: TCustomForm); var form: THMForm; formInstance: THMFormInstance; begin form := FForms.Find(AForm); if Assigned(form) then begin formInstance := form.Find(AForm); AForm.OnKeyDown := formInstance.KeyDownProc; form.Delete(AForm); end; end; procedure THotKeyManager.UnRegister(AControl: TWinControl); var ParentForm: TCustomForm; form: THMForm; control: THMControl; i: Integer; begin ParentForm := GetParentForm(AControl); if Assigned(ParentForm) then begin form := FForms.Find(ParentForm); if Assigned(form) then begin control := form.Controls.Find(AControl); if Assigned(control) then control.Delete(AControl); end; end else begin // control lost its parent, find through all forms for i := 0 to FForms.Count - 1 do begin form := FForms[i]; control := form.Controls.Find(AControl); if Assigned(control) then control.Delete(AControl); end; end; end; function THotKeyManager.HotKeyEvent(Form: TCustomForm; Hotkeys: THotkeys): Boolean; var hotkey: THotkey; FormCommands: IFormCommands; begin hotkey := Hotkeys.FindByBeginning(FShortcutsSequence, False); if Assigned(hotkey) then begin if High(hotkey.Shortcuts) > FSequenceStep then begin // There are more shortcuts to match. FLastShortcutTime := SysUtils.Now; Inc(FSequenceStep); Result := True; end else begin FSequenceStep := 0; FormCommands := Form as IFormCommands; Result := Assigned(FormCommands) and (FormCommands.ExecuteCommand(hotkey.Command, hotkey.Params) = cfrSuccess); end; end else Result := False; end; procedure THotKeyManager.ClearAllHotkeys; var i, j: Integer; Form: THMForm; begin for i := 0 to FForms.Count - 1 do begin Form := FForms[i]; Form.Hotkeys.Clear; for j := 0 to Form.Controls.Count - 1 do Form.Controls[j].Hotkeys.Clear; end; end; procedure THotKeyManager.KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState); //------------------------------------------------------ var i: Integer; Shortcut: TShortCut; TextShortcut: String; Form: TCustomForm; Control: TWinControl; HMForm: THMForm; HMControl: THMControl; HMFormInstance: THMFormInstance; HMControlInstance: THMControlInstance; ShiftEx: TShiftState; function OrigKeyDown(AKeyDownProc: TKeyEvent): Boolean; begin if Assigned(AKeyDownProc) then begin AKeyDownProc(Sender, Key, ShiftEx); Result := True; end else Result := False; end; begin Form := GetParentForm(Sender as TWinControl); HMForm := FForms.Find(Form); if not Assigned(HMForm) then Exit; ShiftEx := GetKeyShiftStateEx; Shortcut := KeyToShortCutEx(Key, ShiftEx); TextShortcut := ShortCutToTextEx(Shortcut); Control := Form.ActiveControl; // Don't execute hotkeys that coincide with key typing actions. if (TextShortcut <> '') and ((FSequenceStep > 0) or (not ((((GetKeyTypingAction(ShiftEx) <> ktaNone) and (HMForm.Name = 'Main')) {$IFDEF MSWINDOWS} // Don't execute hotkeys with Ctrl+Alt = AltGr on Windows. or (HasKeyboardAltGrKey and (ShiftEx * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]) and (gKeyTyping[ktmNone] <> ktaNone)) // Don't execute hotkeys with AltGr on Windows. or (ShiftEx = [ssAltGr]) {$ENDIF} ) and (Key in [VK_0..VK_9, VK_A..VK_Z])))) then begin // If too much time has passed reset sequence. if (FSequenceStep > 0) and (DateTimeToTimeStamp(SysUtils.Now - FLastShortcutTime).Time > MaxShortcutSequenceInterval) then FSequenceStep := 0; // Add shortcut to sequence. if Length(FShortcutsSequence) <> FSequenceStep + 1 then SetLength(FShortcutsSequence, FSequenceStep + 1); FShortcutsSequence[FSequenceStep] := TextShortcut; if Assigned(Control) then begin for i := 0 to HMForm.Controls.Count - 1 do begin HMControl := HMForm.Controls[i]; HMControlInstance := HMControl.Find(Control); if Assigned(HMControlInstance) then begin if HotKeyEvent(Form, HMControl.Hotkeys) then begin Key := VK_UNKNOWN; Exit; end else Break; end; end; end; // Hotkey for the whole form if (Key <> VK_UNKNOWN) and HotKeyEvent(Form, HMForm.Hotkeys) then begin Key := VK_UNKNOWN; Exit; end; FSequenceStep := 0; // Hotkey was not matched - reset sequence. end; if Key <> VK_UNKNOWN then begin HMFormInstance := HMForm.Find(Form); OrigKeyDown(HMFormInstance.KeyDownProc); end; end; end. doublecmd-1.1.22/src/ukastoolitemsextended.pas0000644000175000001440000002474414743153644020541 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Extended tool items types for KASToolBar Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) 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 } unit uKASToolItemsExtended; {$mode objfpc}{$H+} interface uses Classes, SysUtils, KASToolItems, KASToolBar, IniFiles, DCXmlConfig, uDrive, DCBasicTypes, uFormCommands; type { TKASCommandItem } TKASCommandItem = class(TKASNormalItem) strict private FCommand: String; FCommands: IFormCommands; procedure SetCommand(const AValue: String); strict protected procedure SaveHint(Config: TXmlConfig; Node: TXmlNode); override; public Params: TDynamicStringArray; constructor Create(AFormCommands: IFormCommands); reintroduce; procedure Assign(OtherItem: TKASToolItem); override; function Clone: TKASToolItem; override; function ActionHint: Boolean; override; function ConfigNodeName: String; override; procedure Load(Config: TXmlConfig; Node: TXmlNode; Loader: TKASToolBarLoader); override; procedure SaveContents(Config: TXmlConfig; Node: TXmlNode); override; property Command: String read FCommand write SetCommand; end; { TKASProgramItem } TKASProgramItem = class(TKASNormalItem) Command: String; Params: String; StartPath: String; procedure Assign(OtherItem: TKASToolItem); override; function Clone: TKASToolItem; override; function ConfigNodeName: String; override; procedure Load(Config: TXmlConfig; Node: TXmlNode; Loader: TKASToolBarLoader); override; procedure SaveContents(Config: TXmlConfig; Node: TXmlNode); override; end; { TKASDriveItem } TKASDriveItem = class(TKASNormalItem) Drive: PDrive; procedure Assign(OtherItem: TKASToolItem); override; function Clone: TKASToolItem; override; function ConfigNodeName: String; override; end; TKASToolBarIniLoader = class; TOnLoadIniItem = procedure (Loader: TKASToolBarIniLoader; var Item: TKASToolItem; const Shortcut: String) of object; TOnOpenIniFile = function (FileName: String): TIniFile of object; { TKASToolBarIniLoader } TKASToolBarIniLoader = class strict private FCommands: IFormCommands; FDepthLevel: Integer; // In case .bar files reference each other public constructor Create(AFormCommands: IFormCommands); reintroduce; procedure Load(IniFileName: String; ToolBar: TKASToolBar; ToolItemMenu: TKASMenuItem; OnLoadIniItem: TOnLoadIniItem); end; { TKASToolBarExtendedLoader } TKASToolBarExtendedLoader = class(TKASToolBarLoader) strict private FCommands: IFormCommands; protected function CreateItem(Node: TXmlNode): TKASToolItem; override; public constructor Create(AFormCommands: IFormCommands); reintroduce; end; implementation uses DCClassesUtf8, DCStrUtils; const CommandItemConfigNode = 'Command'; ProgramItemConfigNode = 'Program'; DriveItemConfigNode = 'Drive'; { TKASDriveItem } procedure TKASDriveItem.Assign(OtherItem: TKASToolItem); var DriveItem: TKASDriveItem; begin inherited Assign(OtherItem); if OtherItem is TKASDriveItem then begin DriveItem := TKASDriveItem(OtherItem); Drive := DriveItem.Drive; end; end; function TKASDriveItem.Clone: TKASToolItem; begin Result := TKASDriveItem.Create; Result.Assign(Self); end; function TKASDriveItem.ConfigNodeName: String; begin Result := DriveItemConfigNode; end; { TKASCommandItem } procedure TKASCommandItem.Assign(OtherItem: TKASToolItem); var CommandItem: TKASCommandItem; begin inherited Assign(OtherItem); if OtherItem is TKASCommandItem then begin CommandItem := TKASCommandItem(OtherItem); Command := CommandItem.Command; Params := Copy(CommandItem.Params); end; end; function TKASCommandItem.Clone: TKASToolItem; begin Result := TKASCommandItem.Create(FCommands); Result.Assign(Self); end; function TKASCommandItem.ActionHint: Boolean; begin Result:= (inherited ActionHint) and (Length(Params) = 0); end; function TKASCommandItem.ConfigNodeName: String; begin Result := CommandItemConfigNode; end; constructor TKASCommandItem.Create(AFormCommands: IFormCommands); begin FCommands := AFormCommands; end; procedure TKASCommandItem.Load(Config: TXmlConfig; Node: TXmlNode; Loader: TKASToolBarLoader); begin inherited Load(Config, Node, Loader); Params := nil; Node := Node.FirstChild; while Assigned(Node) do begin if Node.CompareName('Command') = 0 then Command := Config.GetContent(Node) else if Node.CompareName('Param') = 0 then AddString(Params, Config.GetContent(Node)); Node := Node.NextSibling; end; if Hint = EmptyStr then begin Hint := FCommands.GetCommandCaption(Command, cctLong); end; end; procedure TKASCommandItem.SaveContents(Config: TXmlConfig; Node: TXmlNode); var AParam: String; begin inherited SaveContents(Config, Node); Config.AddValue(Node, 'Command', Command); for AParam in Params do Config.AddValueDef(Node, 'Param', AParam, ''); end; procedure TKASCommandItem.SetCommand(const AValue: String); begin if FCommand <> AValue then begin FCommand:= AValue; FAction:= FCommands.GetCommandAction(FCommand); end; end; procedure TKASCommandItem.SaveHint(Config: TXmlConfig; Node: TXmlNode); begin if Hint <> FCommands.GetCommandCaption(Command, cctLong) then begin Config.AddValueDef(Node, 'Hint', Hint, ''); end; // else don't save default text for the hint so that a different text // can be loaded if the language changes. end; { TKASProgramItem } procedure TKASProgramItem.Assign(OtherItem: TKASToolItem); var ProgramItem: TKASProgramItem; begin inherited Assign(OtherItem); if OtherItem is TKASProgramItem then begin ProgramItem := TKASProgramItem(OtherItem); Command := ProgramItem.Command; Params := ProgramItem.Params; StartPath := ProgramItem.StartPath; end; end; function TKASProgramItem.Clone: TKASToolItem; begin Result := TKASProgramItem.Create; Result.Assign(Self); end; function TKASProgramItem.ConfigNodeName: String; begin Result := ProgramItemConfigNode; end; procedure TKASProgramItem.Load(Config: TXmlConfig; Node: TXmlNode; Loader: TKASToolBarLoader); begin inherited Load(Config, Node, Loader); Node := Node.FirstChild; while Assigned(Node) do begin if Node.CompareName('Command') = 0 then Command := Config.GetContent(Node) else if Node.CompareName('Params') = 0 then Params := Config.GetContent(Node) else if Node.CompareName('StartPath') = 0 then StartPath := Config.GetContent(Node); Node := Node.NextSibling; end; end; procedure TKASProgramItem.SaveContents(Config: TXmlConfig; Node: TXmlNode); begin inherited SaveContents(Config, Node); Config.AddValueDef(Node, 'Command', Command, ''); Config.AddValueDef(Node, 'Params', Params, ''); Config.AddValueDef(Node, 'StartPath', StartPath, ''); end; { TKASToolBarExtendedLoader } constructor TKASToolBarExtendedLoader.Create(AFormCommands: IFormCommands); begin FCommands := AFormCommands; end; function TKASToolBarExtendedLoader.CreateItem(Node: TXmlNode): TKASToolItem; begin Result := inherited CreateItem(Node); if not Assigned(Result) then begin if Node.CompareName(CommandItemConfigNode) = 0 then Result := TKASCommandItem.Create(FCommands) else if Node.CompareName(ProgramItemConfigNode) = 0 then Result := TKASProgramItem.Create else if Node.CompareName(DriveItemConfigNode) = 0 then Result := TKASDriveItem.Create; end; end; { TKASToolBarIniLoader } constructor TKASToolBarIniLoader.Create(AFormCommands: IFormCommands); begin FCommands := AFormCommands; end; procedure TKASToolBarIniLoader.Load(IniFileName: String; ToolBar: TKASToolBar; ToolItemMenu: TKASMenuItem; OnLoadIniItem: TOnLoadIniItem); var BtnCount, I: Integer; CommandItem: TKASCommandItem; ProgramItem: TKASProgramItem; Command, Menu, Button, Param, Path, Misk: String; Item: TKASToolItem; IniFile: TIniFileEx = nil; begin if (FDepthLevel < 10) then begin IniFile := TIniFileEx.Create(IniFileName, fmOpenRead or fmShareDenyNone); if Assigned(IniFile) then try Inc(FDepthLevel); BtnCount := IniFile.ReadInteger('Buttonbar', 'Buttoncount', 0); for I := 1 to BtnCount do begin Command := IniFile.ReadString('Buttonbar', 'cmd' + IntToStr(I), ''); Menu := IniFile.ReadString('Buttonbar', 'menu' + IntToStr(I), ''); Button := IniFile.ReadString('Buttonbar', 'button' + IntToStr(I), ''); Param := IniFile.ReadString('Buttonbar', 'param' + IntToStr(I), ''); Path := IniFile.ReadString('Buttonbar', 'path' + IntToStr(I), ''); Misk := IniFile.ReadString('Buttonbar', 'misk' + IntToStr(I), ''); Item := nil; if Menu = '-' then begin Item := TKASSeparatorItem.Create; end else if (Length(Command) > 3) and (Copy(Command, 1, 3) = 'cm_') then begin CommandItem := TKASCommandItem.Create(FCommands); CommandItem.Command := Command; CommandItem.Hint := Menu; CommandItem.Icon := Button; if Param <> EmptyStr then AddString(CommandItem.Params, Param); Item := CommandItem; end else begin ProgramItem := TKASProgramItem.Create; ProgramItem.Command := Command; ProgramItem.Hint := Menu; ProgramItem.Icon := Button; ProgramItem.Params := Param; ProgramItem.StartPath := Path; Item := ProgramItem; end; if Assigned(OnLoadIniItem) then OnLoadIniItem(Self, Item, Misk); if Assigned(ToolBar) then ToolBar.AddButton(Item); if Assigned(ToolItemMenu) then ToolItemMenu.SubItems.Add(Item); end; finally IniFile.Free; Dec(FDepthLevel); end; end; end; end. doublecmd-1.1.22/src/ulng.pas0000644000175000001440000016515714743153644015066 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Localization core unit Copyright (C) 2007-2022 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uLng; {$mode objfpc}{$H+} interface uses LResources; resourcestring // File operations. rsMsgNotDelete = 'Can not delete file %s'; rsMsgCannotDeleteDirectory = 'Cannot delete directory %s'; rsMsgCannotOverwriteDirectory = 'Cannot overwrite directory "%s" with non-directory "%s"'; rsMsgCannotCopySpecialFile = 'Cannot copy special file %s'; rsMsgErrCannotMoveDirectory = 'Cannot move directory %s'; rsMsgErrDirExists = 'Directory %s exists!'; rsMsgErrRename = 'Cannot rename file %s to %s'; rsMsgErrCannotMoveFile = 'Cannot move file %s'; rsMsgErrCannotCopyFile = 'Cannot copy file %s to %s'; rsMsgFileExistsOverwrite = 'Overwrite:'; rsMsgFileExistsWithFile = 'With file:'; rsMsgFileExistsFileInfo = '%s bytes, %s'; rsMsgFileExistsRwrt = 'File %s exists, overwrite?'; rsMsgFileChangedSave = 'File %s changed, save?'; rsMsgReplaceThisText = 'Do you want to replace this text?'; rsMsgCancelOperation = 'Are you sure that you want to cancel this operation?'; rsMsgFileReloadWarning = 'Are you sure you want to reload the current file and lose the changes?'; rsMsgFolderExistsRwrt = 'Folder %s exists, merge?'; rsMsgFileReadOnly = 'File %s is marked as read-only/hidden/system. Delete it?'; rsMsgNewFile = 'New file'; rsMsgDelFlDr = 'Delete %d selected files/directories?'; rsMsgDelSel = 'Delete selected "%s"?'; rsMsgTestArchive = 'Do you want to test selected archives?'; rsMsgVerifyChecksum = 'Do you want to verify selected checksums?'; rsMsgObjectNotExists = 'Object does not exist!'; // 12.05.2009 - another message, when deleting to trash rsMsgDelFlDrT = 'Delete %d selected files/directories into trash can?'; rsMsgDelSelT = 'Delete selected "%s" into trash can?'; rsMsgDelToTrashForce = 'Can not delete "%s" to trash! Delete directly?'; rsMsgFileNotFound = 'File "%s" not found.'; // --- rsMsgVerify = 'VERIFICATION:'; rsMsgVerifyWrong = 'The target file is corrupted, checksum mismatch!'; // --- rsMsgWipeFlDr = 'Wipe %d selected files/directories?'; rsMsgWipeSel = 'Wipe selected "%s"?'; rsMsgCpFlDr = 'Copy %d selected files/directories?'; rsMsgCpSel = 'Copy selected "%s"?'; rsMsgRenFlDr = 'Rename/move %d selected files/directories?'; rsMsgRenSel = 'Rename/move selected "%s"?'; rsMsgErrForceDir = 'Can not create directory %s!'; rsMsgSelectedInfo = 'Selected: %s of %s, files: %d of %d, folders: %d of %d'; rsMsgCloseLockedTab = 'This tab (%s) is locked! Close anyway?'; rsMsgTabForOpeningInNewTab = 'This tab (%s) is locked! Open directory in another tab?'; rsSpaceMsg = 'Files: %d, Dirs: %d, Size: %s (%s bytes)'; rsSelectDir = 'Select a directory'; rsMarkPlus = 'Select mask'; rsMarkMinus = 'Unselect mask'; rsMaskInput = 'Input mask:'; rsMsgPopUpHotDelete = '&Delete %s'; rsMsgDiskNotAvail = 'Disk is not available'; rsMsgChDirFailed = 'Change current directory to "%s" failed!'; rsMsgNoFreeSpaceCont = 'No enough free space on target drive, Continue?'; rsMsgNoFreeSpaceRetry = 'No enough free space on target drive, Retry?'; rsMsgSetVolumeLabel = 'Set volume label'; rsMsgVolumeLabel = 'Volume label:'; rsMsgRestartForApplyChanges = 'Please, restart Double Commander in order to apply changes'; rsMsgEnterName = 'Enter name:'; rsMsgEnterFileExt = 'Enter file extension:'; rsMsgDefaultCustomActionName = 'Custom action'; rsMsgSelectExecutableFile = 'Select executable file for'; rsMsgWithActionWith = 'with'; rsMsgFollowSymlink = 'Follow symlink "%s"?'; rsMsgFileSizeTooBig = 'The file size of "%s" is too big for destination file system!'; rsMsgCloseAllInActiveTabs = 'Remove all inactive tabs?'; rsMsgErrRegExpSyntax = 'Syntax error in regular expression!'; rsMsgNoFilesSelected = 'No files selected.'; rsMsgTooManyFilesSelected = 'Too many files selected.'; rsMsgInvalidSelection = 'Invalid selection.'; rsMsgNotImplemented = 'Not implemented.'; rsMsgInvalidFilename = 'Invalid filename'; rsMsgInvalidPath = 'Invalid path'; rsMsgInvalidPathLong = 'Path %s contains forbidden characters.'; rsMsgSelectOnlyCheckSumFiles = 'Please select only checksum files!'; rsMsgPresetAlreadyExists = 'Preset "%s" already exists. Overwrite?'; rsMsgPresetConfigDelete = 'Are you sure you want to delete preset "%s"?'; rsMsgVolumeSizeEnter = 'Please enter the volume size:'; rsFilterAnyFiles = 'Any files'; rsFilterDCToolTipFiles = 'DC Tooltip files'; rsFilterToolbarFiles = 'DC Toolbar files'; rsFilterXmlConfigFiles = '.xml Config files'; rsFilterTCToolbarFiles = 'TC Toolbar files'; rsFilterExecutableFiles = 'Executables files'; rsFilterIniConfigFiles = '.ini Config files'; rsFilterLegacyTabFiles = 'Legacy DC .tab files'; rsFilterDirectoryHotListFiles = 'Directory Hotlist files'; rsFilterArchiverConfigFiles = 'Archiver config files'; rsFilterPluginFiles = 'Plugin files'; rsFilterLibraries = 'Library files'; rsFilterProgramsLibraries = 'Programs and Libraries'; // Archiver section. rsMsgArchiverCustomParams = 'Additional parameters for archiver command-line:'; rsOptArchiverArchiver = 'Select archiver executable'; rsOptArchiverConfirmDelete = 'Are you sure you want to delete: "%s"?'; rsOptArchiverImportFile = 'Select the file to import archiver configuration(s)'; rsOptArchiverWhereToSave = 'Enter location and filename where to save archiver configuration'; rsOptArchiverDefaultExportFilename = 'Exported Archiver Configuration'; rsOptArchiverImportCaption = 'Import archiver configuration'; rsOptArchiverImportPrompt = 'Select the one(s) you want to import'; rsOptArchiverImportDone = 'Importation of %d elements from file "%s" completed.'; rsOptArchiverExportCaption = 'Export archiver configuration'; rsOptArchiverExportPrompt = 'Select the one(s) you want to export'; rsOptArchiverExportDone = 'Exportation of %d elements to file "%s" completed.'; rsOptArchiverProgramL = 'Archive Program (long name)'; rsOptArchiverProgramS = 'Archive Program (short name)'; rsOptArchiverArchiveL = 'Archive File (long name)'; rsOptArchiverArchiveS = 'Archive file (short name)'; rsOptArchiverFileListL = 'Filelist (long names)'; rsOptArchiverFileListS = 'Filelist (short names)'; rsOptArchiverSingleFProcess = 'Single filename to process'; rsOptArchiverErrorLevel = 'errorlevel'; rsOptArchiverChangeEncoding = 'Change Archiver Listing Encoding'; rsOptArchiverTargetSubDir = 'Target subdirecory'; rsOptArchiverAdditonalCmd = 'Mode dependent, additional command'; rsOptArchiverAddOnlyNotEmpty = 'Add if it is non-empty'; rsOptArchiverQuoteWithSpace = 'Quote names with spaces'; rsOptArchiverQuoteAll = 'Quote all names'; rsOptArchiverJustName = 'Use name only, without path'; rsOptArchiverJustPath = 'Use path only, without name'; rsOptArchiverUseAnsi = 'Use ANSI encoding'; rsOptArchiverUseUTF8 = 'Use UTF8 encoding'; rsOptArchiveConfigureSaveToChange = 'To change current editing archive configuration, either APPLY or DELETE current editing one'; // Font rsFontUsageMain = 'Main &Font'; rsFontUsageEditor = '&Editor Font'; rsFontUsageViewer = '&Viewer Font'; rsFontUsageViewerBook = 'Viewer&Book Font'; rsFontUsageLog = '&Log Font'; rsFontUsageConsole = '&Console Font'; rsFontUsagePathEdit = 'Path Font'; rsFontUsageFunctionButtons = 'Function Buttons Font'; rsFontUsageSearchResults = 'Search Results Font'; rsFontUsageTreeViewMenu = 'Tree View Menu Font'; rsFontUsageStatusBar = 'Status Bar Font'; // Tooltip section rsOptTooltipConfigureSaveToChange = 'To change file type tooltip configuration, either APPLY or DELETE current editing one'; rsOptToolTipsFileTypeName = 'Tooltip file type name'; rsToolTipModeList = 'Combine DC and system tooltip, DC first (legacy);Combine DC and system tooltip, system first;Show DC tooltip when possible and system when not;Show DC tooltip only;Show system tooltip only'; rsToolTipHideTimeOutList = 'System default;1 sec;2 sec;3 sec;5 sec;10 sec;30 sec;1 min;Never hide'; rsOptAddingToolTipFileType = 'Adding new tooltip file type'; rsOptRenamingToolTipFileType = 'Renaming tooltip file type'; rsOptToolTipFileType = 'Tooltip file type name:'; rsOptToolTipFileTypeDefaultExportFilename = 'Exported tooltip file type configuration'; rsOptToolTipFileTypeWhereToSave = 'Enter location and filename where to save tooltip file type configuration'; rsOptToolTipFileTypeAlreadyExists = '"%s" already exists!'; rsOptToolTipFileTypeConfirmDelete = 'Are you sure you want to delete: "%s"?'; rsOptToolTipFileTypeImportCaption = 'Import tooltip file type configuration'; rsOptToolTipFileTypeImportPrompt = 'Select the one(s) you want to import'; rsOptToolTipFileTypeImportFile = 'Select the file to import tooltip file type configuration(s)'; rsOptToolTipFileTypeImportDone = 'Importation of %d elements from file "%s" completed.'; rsOptToolTipFileTypeExportPrompt = 'Select the one(s) you want to export'; rsOptToolTipFileTypeExportCaption = 'Export tooltip file type configuration'; rsOptToolTipFileTypeExportDone = 'Exportation of %d elements to file "%s" completed.'; rsMsgMasterPassword = 'Master Password'; rsMsgMasterPasswordEnter = 'Please enter the master password:'; rsMsgWrongPasswordTryAgain = 'Wrong password!'#13'Please try again!'; rsMsgPasswordEnter = 'Please enter the password:'; rsMsgPasswordVerify = 'Please re-enter the password for verification:'; rsMsgPasswordDiff = 'Passwords are different!'; rsMsgUserName = 'User name:'; rsMsgPassword = 'Password:'; rsMsgAccount = 'Account:'; rsMsgUserNameFirewall = 'User name (Firewall):'; rsMsgPasswordFirewall = 'Password (Firewall):'; rsMsgTargetDir = 'Target path:'; rsMsgURL = 'URL:'; rsMsgLoadingFileList = 'Loading file list...'; rsMsgNoFiles = 'No files'; rsMsgErrSetAttribute = 'Can not set attributes for "%s"'; rsMsgErrSetDateTime = 'Can not set date/time for "%s"'; rsMsgErrSetOwnership = 'Can not set owner/group for "%s"'; rsMsgErrSetPermissions = 'Can not set permissions for "%s"'; rsMsgErrSetXattribute = 'Can not set extended attributes for "%s"'; rsMsgErrDateNotSupported = 'Date %s is not supported'; rsMsgErrSaveFile = 'Cannot save file'; rsMsgErrCanNotConnect = 'Can not connect to server: "%s"'; rsMsgErrSaveAssociation = 'Can not save association!'; rsMsgFileOperationsActive = 'File operations active'; rsMsgFileOperationsActiveLong = 'Some file operations have not yet finished. Closing Double Commander may result in data loss.'; rsMsgConfirmQuit = 'Are you sure you want to quit?'; rsMsgCanNotCopyMoveItSelf = 'You can not copy/move a file "%s" to itself!'; rsMsgTabRenameCaption = 'Rename tab'; rsMsgTabRenamePrompt = 'New tab name:'; rsMsgInvalidPlugin = 'This is not a valid plugin!'; rsMsgInvalidPluginArchitecture = 'This plugin is built for Double Commander for %s.%sIt can not work with Double Commander for %s!'; rsMsgErrCreateFileDirectoryExists = 'There already exists a directory named "%s".'; rsMsgDeletePartiallyCopied = 'Delete the partially copied file ?'; rsMsgInvalidCommandLine = 'Error in command line'; rsMsgCofirmUserParam = 'Confirmation of parameter'; rsMsgAskQuoteOrNot = 'Do you want to enclose between quotes?'; rsMsgInvalidQuoting = 'Invalid quoting'; rsMsgErrorInContextMenuCommand = 'Error in context menu command'; rsMsgErrorLoadingConfiguration = 'Error when loading configuration'; rsMsgInvalidFormatOfConfigurationFile = 'Invalid format of configuration file'; rsDefaultSuffixDroppedText = '_DroppedText'; rsDefaultSuffixDroppedTextRichtextFilename = '_DroppedRichtext'; rsDefaultSuffixDroppedTextHTMLFilename = '_DroppedHTMLtext'; rsDefaultSuffixDroppedTextUnicodeUTF16Filename = '_DroppedUnicodeUTF16text'; rsDefaultSuffixDroppedTextUnicodeUTF8Filename = '_DroppedUnicodeUTF8text'; rsDefaultSuffixDroppedTextSimpleFilename = '_DroppedSimpleText'; rsDragAndDropTextFormat = 'Rich Text Format;HTML Format;Unicode Format;Simple Text Format'; rsCaptionForAskingFilename = 'Enter filename, with extension, for dropped text'; rsMsgPromptAskingFilename = 'Filename for dropped text:'; rsCaptionForTextFormatToImport = 'Text format to import'; rsMsgForTextFormatToImport = 'Select the text format to import'; rsMsgUserDidNotSetExtension = ''; rsMsgUserDidNotSetName = ''; rsMsgCommandNotFound = 'Command not found! (%s)'; rsMsgProblemExecutingCommand = 'Problem executing command (%s)'; rsMsgCopyBackward = 'The file %s has changed. Do you want to copy it backward?'; rsMsgCouldNotCopyBackward = 'Could not copy backward - do you want to keep the changed file?'; rsMsgFilePathOverMaxPath = 'The target name length (%d) is more than %d characters!' + #13 + '%s' + #13 + 'Most programs will not be able to access a file/directory with such a long name!'; rsExtsClosedBracketNoFound = '"]" not found in line %s'; rsExtsCommandWithNoExt = 'No extension defined before command "%s". It will be ignored.'; rsMsgTerminalDisabled = 'Built-in terminal window disabled. Do you want to enable it?'; //Hot Dir related rsMsgHotDirWhatToDelete = 'Do you want to delete all elements inside the sub-menu [%s]?'+#$0A+'Answering NO will delete only menu delimiters but will keep element inside sub-menu.'; rsMsgHotDirAddThisDirectory = 'Add current dir: '; rsMsgHotDirAddSelectedDirectory = 'Add selected dir: '; rsMsgHotDirReAddSelectedDirectory = 'Re-Add selected dir: '; rsMsgHotDirReAddThisDirectory = 'Re-Add current dir: '; rsMsgHotDirAddSelectedDirectories = 'Add %d selected dirs'; rsMsgHotDirConfigHotlist = 'Configuration of Directory Hotlist'; rsMsgHotDirDeleteAllEntries = 'Are you sure you want to remove all entries of your Directory Hotlist? (There is no "undo" to this action!)'; rsMsgHotDirName = 'Hotdir name'; rsMsgHotDirPath = 'Hotdir path'; rsMsgHotDirJustPath = '&Path:'; rsMsgHotDirTarget = 'Hotdir target'; rsMsgHotDirSubMenuName = 'Submenu name'; rsMsgHotDirSimpleName = '&Name:'; rsMsgHotDirSimpleSeparator = '(separator)'; rsMsgHotDirSimpleMenu = 'Menu &name:'; rsMsgHotDirSimpleEndOfMenu = '(end of sub menu)'; rsMsgHotDirSimpleCommand = 'Command:'; rsMsgHotDirCommandName = 'Do command'; rsMsgHotDirCommandSample = 'cm_somthing'; rsMsgHotDirDemoName = 'This is hot dir named '; rsMsgHotDirDemoPath = 'This will change active frame to the following path:'; rsMsgHotDirDemoCommand = 'This will execute the following command:'; rsMsgHotDirDemoTarget = 'And inactive frame would change to the following path:'; rsMsgHotDirLocateHotlistFile = 'Locate ".hotlist" file to import'; rsMsgHotDirWhereToSave = 'Enter location and filename where to save a Directory Hotlist file'; rsMsgHotDirRestoreWhat = 'Enter location and filename of Directory Hotlist to restore'; rsMsgHotDirImportall = 'Import all!'; rsMsgHotDirImportSel = 'Import selected'; rsMsgHotDirImportHotlist = 'Import Directory Hotlist - Select the entries you want to import'; rsMsgHotDirExportall = 'Export all!'; rsMsgHotDirExportSel = 'Export selected'; rsMsgHotDirExportHotlist = 'Export Directory Hotlist - Select the entries you want to export'; rsMsgHotDirNbNewEntries = 'Number of new entries: %d'; rsMsgHotDirTotalExported = 'Total entries exported: '; rsMsgHotDirErrorExporting = 'Error exporting entries...'; rsMsgHotDirNothingToExport = 'Nothing selected to export!'; rsMsgHotDirTipSpecialDirBut = 'Some functions to select appropriate path relative, absolute, windows special folders, etc.'; rsMsgHotDirTipOrderPath = 'Determine if you want the active frame to be sorted in a specified order after changing directory'; rsMsgHotDirTipOrderTarget = 'Determine if you want the not active frame to be sorted in a specified order after changing directory'; rsMsgHotDirTotalBackuped = 'Total entries saved: %d'+#$0A+#$0A+'Backup filename: %s'; rsMsgHotDirErrorBackuping = 'Error backuping entries...'; rsHotDirWarningAbortRestoreBackup = 'Warning! When restoring a .hotlist backup file, this will erase existing list to replace by the imported one.'+#$0A+#$0A+ 'Are you sure you want to proceed?'; rsHotDirForceSortingOrderChoices = 'none;Name, a-z;Name, z-a;Ext, a-z;Ext, z-a;Size 9-0;Size 0-9;Date 9-0;Date 0-9'; //Special dir related rsMsgSpecialDirUseDC = 'Use Double Commander special path...'; rsMsgSpecialDirUseTC = 'Use Windows special folder (TC)...'; rsMsgSpecialDirUseOther = 'Use other Windows special folder...'; rsMsgSpecialDirEnvVar = 'Use environment variable...'; rsMsgSpecialDirMkDCRel = 'Make relative to Double Commander special path...'; rsMsgSpecialDirMkTCTel = 'Make relative to Windows special folder (TC)...'; rsMsgSpecialDirMkWnRel = 'Make relative to other Windows special folder...'; rsMsgSpecialDirMkEnvRel = 'Make relative to environment variable...'; rsMsgSpecialDirMkAbso = 'Make path absolute'; rsMsgSpecialDirAddActi = 'Add path from active frame'; rsMsgSpecialDirAddNonActi = 'Add path from inactive frame'; rsMsgSpecialDirBrowsSel = 'Browse and use selected path'; rsMsgSpecialDir = 'Special Dirs'; rsMsgSpecialDirGotoDC = 'Go to Double Commander special path...'; rsMsgSpecialDirGotoTC = 'Go to Windows special folder (TC)...'; rsMsgSpecialDirGotoOther = 'Go to other Windows special folder...'; rsMsgSpecialDirGotoEnvVar = 'Go to environment variable...'; rsMsgSpecialDirUseHotDir = 'Use hotdir path'; rsMsgSpecialDirMakeRelToHotDir = 'Make relative to hotdir path'; //Favorite Tabs related rsMsgFavoriteTabsEnterName = 'Enter a name for this new Favorite Tabs entry:'; rsMsgFavoriteTabsEnterNameTitle = 'Saving a new Favorite Tabs entry'; rsMsgFavoriteTabsSubMenuName = 'Submenu name'; rsMsgFavoriteTabsImportSubMenuName = 'Legacy tabs imported'; rsMsgFavoriteTabsDragHereEntry = 'Drag here other entries'; rsMsgFavortieTabsSaveOverExisting = 'Save current tabs over existing Favorite Tabs entry'; rsOptFavoriteTabsWhereToAddInList = 'Add at beginning;Add at the end;Alphabetical sort'; rsMsgFavoriteTabsThisWillLoadFavTabs = 'This will load the Favorite Tabs: "%s"'; rsMsgFavoriteTabsDeleteAllEntries = 'Are you sure you want to remove all entries of your Favorite Tabs? (There is no "undo" to this action!)'; rsTitleRenameFavTabs = 'Rename Favorite Tabs'; rsMsgRenameFavTabs = 'Enter new friendly name for this Favorite Tabs'; rsTitleRenameFavTabsMenu = 'Rename Favorite Tabs sub-menu'; rsMsgRenameFavTabsMenu = 'Enter new name for this menu'; rsMsgFavoriteTabsImportedSuccessfully = 'Number of file(s) imported successfully: %d on %d'; rsMsgFavoriteTabsExportedSuccessfully = 'Number of Favorite Tabs exported successfully: %d on %d'; rsMsgFavoriteTabsModifiedNoImport = 'Last Favorite Tabs modification have been saved yet. Do you want to save them prior to continue?'; rsMsgFavoriteTabsSimpleMode = 'Keep saving dir history with Favorite Tabs:'; rsMsgFavoriteTabsExtraMode = 'Default extra setting for save dir history for new Favorite Tabs:'; rsTabsActionOnDoubleClickChoices = 'Do nothing;Close tab;Access Favorite Tabs;Tabs popup menu'; rsFavTabsPanelSideSelection = 'Left;Right;Active;Inactive;Both;None'; rsFavTabsSaveDirHistory = 'No;Yes'; rsMsgFavoriteTabsImportTitle = 'Select .tab file(s) to import (could be more than one at the time!)'; //Total Commander related message rsMsgLocateTCExecutable = 'Locate TC executable file (totalcmd.exe or totalcmd64.exe)'; rsMsgLocateTCConfiguation = 'Locate TC configuration file (wincmd.ini)'; rsDefaultImportedTCToolbarHint = 'Imported TC toolbar'; rsDefaultImportedDCToolbarHint = 'Imported DC toolbar'; rsFilenameExportedTCBarPrefix = 'Exported_from_DC'; rsNoEquivalentInternalCommand = 'No internal equivalent command'; // Locked by another process rsMsgProcessId = 'PID: %d'; rsMsgApplicationName = 'Description: %s'; rsMsgExecutablePath = 'Executable: %s'; rsMsgOpenInAnotherProgram = 'The action cannot be completed because the file is open in another program:'; rsMsgTerminateProcess = 'WARNING: Terminating a process can cause undesired results including loss of data and system instability.' + #32 + 'The process will not be given the chance to save its state or data before it is terminated. Are you sure you want to terminate the process?'; // for context menu rsMnuActions = 'Actions'; rsMnuOpen = 'Open'; rsMnuView = 'View'; rsMnuEdit = 'Edit'; rsMnuOpenWith = 'Open with'; rsMnuOpenWithOther = 'Other...'; rsMenuMacOsServices = 'Services'; rsMenuMacOsShare = 'Share...'; rsMnuMount = 'Mount'; rsMnuUmount = 'Unmount'; rsMnuNoMedia = 'No media available'; rsMnuEject = 'Eject'; rsMnuSortBy = 'Sort by'; rsMnuNew = 'New'; rsMnuRestore = 'Restore'; rsMnuPackHere = 'Pack here...'; rsMnuExtractHere = 'Extract here...'; rsOpenWithMacOSFilter = 'Applications (*.app)|*.app|All files (*)|*'; // for main menu rsMnuCreateShortcut = 'Create Shortcut...'; rsMnuMapNetworkDrive = 'Map Network Drive...'; rsMnuDisconnectNetworkDrive = 'Disconnect Network Drive...'; // for content plugins menu rsMnuContentDefault = ''; rsMnuContentOctal = 'Octal'; // wcx module messages rsMsgSelLocNextVol = 'Please select location of next volume'; rsMsgNextVolUnpack = 'Next volume will be unpacked'; // wcx module errors messages rsMsgErrEndArchive = 'No more files in archive'; rsMsgErrNoMemory = 'Not enough memory'; rsMsgErrBadData = 'Data is bad'; rsMsgErrBadArchive = 'CRC error in archive data'; rsMsgErrUnknownFormat = 'Archive format unknown'; rsMsgErrEOpen = 'Cannot open existing file'; rsMsgErrECreate = 'Cannot create file'; rsMsgErrEClose = 'Error closing file'; rsMsgErrERead = 'Error reading from file'; rsMsgErrEWrite = 'Error writing to file'; rsMsgErrSmallBuf = 'Buffer too small'; rsMsgErrEAborted = 'Function aborted by user'; rsMsgErrNoFiles = 'No files found'; rsMsgErrTooManyFiles = 'Too many files to pack'; rsMsgErrNotSupported = 'Function not supported!'; rsMsgErrInvalidLink = 'Invalid link'; // Vfs rsVfsNetwork = 'Network'; rsVfsRecycleBin = 'Recycle Bin'; // Buttons. rsDlgButtonOK = '&OK'; rsDlgButtonNo = '&No'; rsDlgButtonYes = '&Yes'; rsDlgButtonCancel = '&Cancel'; rsDlgButtonNone = 'Non&e'; rsDlgButtonAppend = 'A&ppend'; rsDlgButtonResume = '&Resume'; rsDlgButtonRename = 'R&ename'; rsDlgButtonCopyInto = '&Merge'; rsDlgButtonCopyIntoAll = 'Mer&ge All'; rsDlgButtonOverwrite = '&Overwrite'; rsDlgButtonOverwriteAll = 'Overwrite &All'; rsDlgButtonOverwriteOlder = 'Overwrite All Ol&der'; rsDlgButtonOverwriteSmaller = 'Overwrite All S&maller'; rsDlgButtonOverwriteLarger = 'Overwrite All &Larger'; rsDlgButtonAutoRenameSource = 'A&uto-rename source files'; rsDlgButtonAutoRenameTarget = 'Auto-rename tar&get files'; rsDlgButtonSkip = '&Skip'; rsDlgButtonSkipAll = 'S&kip All'; rsDlgButtonIgnore = 'Ig&nore'; rsDlgButtonIgnoreAll = 'I&gnore All'; rsDlgButtonAll = 'A&ll'; rsDlgButtonRetry = 'Re&try'; rsDlgButtonAbort = 'Ab&ort'; rsDlgButtonOther = 'Ot&her'; rsDlgButtonRetryAdmin = 'As Ad&ministrator'; rsDlgButtonUnlock = '&Unlock'; rsDlgButtonCompare = 'Compare &by content'; rsDlgButtonContinue = '&Continue'; rsDlgButtonExitProgram = 'E&xit program'; // Log file rsMsgLogSuccess = 'Done: '; rsMsgLogError = 'Error: '; rsMsgLogInfo = 'Info: '; rsMsgLogCopy = 'Copy file %s'; rsMsgLogMove = 'Move file %s'; rsMsgLogDelete = 'Delete file %s'; rsMsgLogWipe = 'Wipe file %s'; rsMsgLogLink = 'Create link %s'; rsMsgLogSymLink = 'Create symlink %s'; rsMsgLogMkDir = 'Create directory %s'; rsMsgLogRmDir = 'Remove directory %s'; rsMsgLogWipeDir = 'Wipe directory %s'; rsMsgLogPack = 'Pack to file %s'; rsMsgLogExtract = 'Extract file %s'; rsMsgLogTest = 'Test file integrity %s'; rsMsgLogExtCmdLaunch = 'Launch external'; rsMsgLogExtCmdResult = 'Result external'; rsMsgLogProgramStart = 'Program start'; rsMsgLogProgramShutdown = 'Program shutdown'; rsMsgExitStatusCode = 'Exit status:'; rsSearchResult = 'Search result'; rsShowHelpFor = '&Show help for %s'; rsClipboardContainsInvalidToolbarData = 'Clipboard doesn''t contain any valid toolbar data.'; //Panel Color Configuration rsMsgPanelPreview = 'Below is a preview. You may move cursor and select files to get immediately an actual look and feel of the various settings.'; // File operations dialog rsDlgCp = 'Copy file(s)'; rsDlgMv = 'Move file(s)'; rsDlgOpPause = 'Pau&se'; rsDlgOpStart = '&Start'; rsDlgQueue = 'Queue'; rsDlgSpeed = 'Speed %s/s'; rsDlgSpeedTime = 'Speed %s/s, time remaining %s'; // File operations rsFileOpDirectoryExistsOptions = 'Ask;Merge;Skip'; rsFileOpFileExistsOptions = 'Ask;Overwrite;Overwrite Older;Skip'; rsFileOpCopyMoveFileExistsOptions = 'Ask;Overwrite;Skip'; rsFileOpSetPropertyErrorOptions = 'Ask;Don''t set anymore;Ignore errors'; // Viewer rsViewAboutText = 'Internal Viewer of Double Commander.'; rsViewNotFound = '%s not found!'; rsViewEncoding = 'Encoding'; rsViewNewSize = 'New Size'; rsViewImageType = 'Image Type'; rsViewBadQuality = 'Bad Quality'; rsViewPaintToolsList = 'Pen;Rect;Ellipse'; // Editor rsEditGotoLineTitle = 'Goto Line'; rsEditGotoLineQuery = 'Goto line:'; rsEditAboutText = 'Internal Editor of Double Commander.'; // Editor Highlighters rsSynLangPlainText = 'Plain text'; rsSynDefaultText = 'Default text'; // Columns in file panel rsColName = 'Name'; rsColExt = 'Ext'; rsColSize = 'Size'; rsColDate = 'Date'; rsColAttr = 'Attr'; // Filter status in file panel rsFilterStatus = 'FILTER'; rsSearchStatus = 'SEARCH'; // Cancel operations in file panel rsCancelFilter = 'Cancel Quick Filter'; rsCancelOperation = 'Cancel Current Operation'; // File function names rsFuncName = 'Name'; rsFuncExt = 'Extension'; rsFuncSize = 'Size'; rsFuncAttr = 'Attributes'; rsFuncPath = 'Path'; rsFuncGroup = 'Group'; rsFuncOwner = 'Owner'; rsFuncMTime = 'Modification date/time'; rsFuncCTime = 'Creation date/time'; rsFuncATime = 'Access date/time'; rsFuncHTime = 'Change date/time'; rsFuncLinkTo = 'Link to'; rsFuncNameNoExt = 'Name without extension'; rsFuncType = 'Type'; rsFuncComment = 'Comment'; rsFuncCompressedSize = 'Compressed size'; rsFuncTrashOrigPath = 'Original path'; // Tools rsToolViewer = 'Viewer'; rsToolEditor = 'Editor'; rsToolDiffer = 'Differ'; rsToolTerminal = 'Terminal'; rsToolErrorOpeningViewer = 'Error opening viewer'; rsToolErrorOpeningEditor = 'Error opening editor'; rsToolErrorOpeningDiffer = 'Error opening differ'; rsToolErrorOpeningTerminal = 'Error opening terminal'; // Configure custom columns dialog rsConfColDelete = 'Delete'; rsConfColCaption = 'Caption'; rsConfColWidth = 'Width'; rsConfColAlign = 'Align'; rsConfColFieldCont = 'Field contents'; rsConfColMove='Move'; rsConfCustHeader='Customize column'; // Open with dialog rsOpenWithMultimedia = 'Multimedia'; rsOpenWithDevelopment = 'Development'; rsOpenWithEducation = 'Education'; rsOpenWithGames = 'Games'; rsOpenWithGraphics = 'Graphics'; rsOpenWithNetwork = 'Network'; rsOpenWithOffice = 'Office'; rsOpenWithScience = 'Science'; rsOpenWithSettings = 'Settings'; rsOpenWithSystem = 'System'; rsOpenWithUtility = 'Accessories'; rsOpenWithOther = 'Other'; // File properties dialog rsPropsFolder = 'Directory'; rsPropsFile = 'File'; rsPropsSpChrDev = 'Special character device'; rsPropsSpBlkDev = 'Special block device'; rsPropsNmdPipe = 'Named pipe'; rsPropsSymLink = 'Symbolic link'; rsPropsSocket = 'Socket'; rsPropsUnknownType = 'Unknown type'; rsPropsMultipleTypes = 'Multiple types'; rsPropsContains = 'Files: %d, folders: %d'; rsPropsErrChMod = 'Can not change access rights for "%s"'; rsPropsErrChOwn = 'Can not change owner for "%s"'; // Compare by content Dialog rsDiffMatches = ' Matches: '; rsDiffModifies = ' Modifies: '; rsDiffAdds = ' Adds: '; rsDiffDeletes = ' Deletes: '; rsDiffComparing = 'Comparing...'; rsDiffFilesIdentical = 'The two files are identical!'; rsDiffTextIdentical = 'The text is identical, but the following options are used:'; rsDiffTextIdenticalNotMatch = 'The text is identical, but the files do not match!'+#$0A+'The following differences were found:'; rsDiffTextDifferenceEncoding = 'Encoding'; rsDiffTextDifferenceLineEnding = 'Line-endings'; // Find files dialog rsFindSearchFiles = 'Find files'; rsFindDefineTemplate = 'Define template'; rsFindScanning = 'Scanning'; rsFindScanned = 'Scanned: %d'; rsFindFound = 'Found: %d'; rsFindTimeOfScan = 'Time of scan: '; rsFindWhereBeg = 'Begin at'; rsFindDirNoEx = 'Directory %s does not exist!'; rsFindDepthAll = 'all (unlimited depth)'; rsFindDepthCurDir = 'current dir only'; rsFindDepth = '%s level(s)'; rsFindSaveTemplateCaption = 'Save search template'; rsFindSaveTemplateTitle = 'Template name:'; rsSearchTemplateUnnamed = ''; rsListOfFindfilesWindows = 'List of "Find files" windows'; rsSelectYouFindFilesWindow = 'Select your window'; rsNoFindFilesWindowYet = 'Sorry, no "Find files" window yet...'; rsNoOtherFindFilesWindowToClose = 'Sorry, no other "Find files" window to close and free from memory...'; rsNewSearchClearFilterOptions = 'Keep;Clear;Prompt'; rsClearFiltersOrNot = 'Do you want to clear filters for this new search?'; rsSearchWithDSXPluginInProgress = 'A file search using DSX plugin is already in progress.'+#$0A+'We need that one to be completed before to launch a new one.'; rsSearchWithWDXPluginInProgress = 'A file search using WDX plugin is already in progress.'+#$0A+'We need that one to be completed before to launch a new one.'; rsPluginSearchFieldNotFound = 'Field "%s" not found!'; rsPluginSearchPluginNotFound = 'Plugin "%s" not found!'; rsPluginSearchUnitNotFoundForField = 'Unit "%s" not found for field "%s" !'; rsPluginSearchContainsNotCase = 'contains'; rsPluginSearchNotContainsNotCase = '!contains'; rsPluginSearchContainsCaseSenstive = 'contains(case)'; rsPluginSearchNotContainsCaseSenstive = '!contains(case)'; rsPluginSearchEqualNotCase = '='; rsPluginSearchNotEqualNotCase = '!='; rsPluginSearchEqualCaseSensitive = '=(case)'; rsPluginSearchNotEquaCaseSensitive = '!=(case)'; rsPluginSearchRegExpr = 'regexp'; rsPluginSearchNotRegExpr = '!regexp'; rsTimeUnitSecond = 'Second(s)'; rsTimeUnitMinute = 'Minute(s)'; rsTimeUnitHour = 'Hour(s)'; rsTimeUnitDay = 'Day(s)'; rsTimeUnitWeek = 'Week(s)'; rsTimeUnitMonth = 'Month(s)'; rsTimeUnitYear = 'Year(s)'; rsSizeUnitBytes = 'Bytes'; rsSizeUnitKBytes = 'Kilobytes'; rsSizeUnitMBytes = 'Megabytes'; rsSizeUnitGBytes = 'Gigabytes'; rsSizeUnitTBytes = 'Terabytes'; rsLegacyOperationByteSuffixLetter = 'B'; //Must be 1 character. Respecting legacy, letter added to following single letters for size when not empty. rsLegacyDisplaySizeSingleLetterKilo = 'K'; //Must be 1 character. By legacy before 2018-11 it was a 'K'. If for a language a different letter was better, it's now changeable in language file. rsLegacyDisplaySizeSingleLetterMega = 'M'; //Must be 1 character. By legacy before 2018-11 it was a 'M'. If for a language a different letter was better, it's now changeable in language file. rsLegacyDisplaySizeSingleLetterGiga = 'G'; //Must be 1 character. By legacy before 2018-11 it was a 'G'. If for a language a different letter was better, it's now changeable in language file. rsLegacyDisplaySizeSingleLetterTera = 'T'; //Must be 1 character. By legacy it was not present before 2018-11. It's also now changeable in language file. rsDefaultPersonalizedAbbrevByte = 'B'; rsDefaultPersonalizedAbbrevKilo = 'KB'; rsDefaultPersonalizedAbbrevMega = 'MB'; rsDefaultPersonalizedAbbrevGiga = 'GB'; rsDefaultPersonalizedAbbrevTera = 'TB'; rsAbbrevDisplayDir = ''; rsAbbrevDisplayLink = ''; rsOptPersonalizedFileSizeFormat = 'Personalized float;Personalized byte;Personalized kilobyte;Personalized megabyte;Personalized gigabyte;Personalized terabyte'; rsOptFileSizeFloat = 'float'; rsFreeMsg = '%s of %s free'; rsFreeMsgShort = '%s free'; // Other rsCopyNameTemplate = 'Copy (%d) %s'; // Symlink dialog rsSymErrCreate = 'Error creating symlink.'; // Hardlink dialog rsHardErrCreate = 'Error creating hardlink.'; // Splitter dialog rsSplitSelDir = 'Select directory:'; rsSplitErrFileSize = 'Incorrect file size format!'; rsSplitErrDirectory = 'Unable to create target directory!'; rsSplitErrSplitFile = 'Unable to split the file!'; rsSplitMsgManyParts = 'The number of parts is more than 100! Continue?'; rsSplitPreDefinedSizes = 'Automatic;1457664B - 3.5" High Density 1.44M;1213952B - 5.25" High Density 1.2M;730112B - 3.5" Double Density 720K;362496B - 5.25" Double Density 360K;98078KB - ZIP 100MB;650MB - CD 650MB;700MB - CD 700MB;4482MB - DVD+R'; // Select duplicate files dialog rsSelectDuplicateMethod = 'Newest;Oldest;Largest;Smallest;First in group;Last in group'; // Multi-Rename Tool dialog rsMulRenLastPreset = '[The last used]'; rsMulRenWarningDuplicate = 'Warning, duplicate names!'; rsMulRenAutoRename = 'Do auto-rename to "name (1).ext", "name (2).ext" etc.?'; rsMulRenWrongLinesNumber = 'File contains wrong number of lines: %d, should be %d!'; rsMulRenFileNameStyleList = 'No change;UPPERCASE;lowercase;First char uppercase;' + 'First Char Of Every Word Uppercase;'; rsMulRenLaunchBehaviorOptions = 'Last masks under [Last One] preset;Last preset;New fresh masks'; rsMulRenSaveModifiedPreset = '"%s" preset has been modified.'+#$0A+'Do you want to save it now?'; rsMulRenSortingPresets = 'Sorting presets'; rsMulRenDefineVariableName = 'Define variable name'; rsMulRenDefineVariableValue = 'Define variable value'; rsMulRenEnterNameForVar = 'Enter variable name'; rsMulRenEnterValueForVar = 'Enter value for variable "%s"'; rsMulRenExitModifiedPresetOptions = 'Ignore, just save as the [Last One];Prompt user to confirm if we save it;Save automatically'; rsMulRenDefaultPresetName = 'Preset name'; rsMulRenPromptForSavedPresetName = 'Save preset as'; rsMulRenPromptNewPresetName = 'Enter new preset name'; rsMulRenPromptNewNameExists = 'Preset name already exists. Overwrite?'; rsMulRenLogStart = 'Multi-Rename Tool'; rsMulRenMaskName = 'Name'; rsMulRenMaskCharAtPosX = 'Character at position x'; rsMulRenMaskCharAtPosXtoY = 'Characters from position x to y'; rsMulRenMaskFullName = 'Complete filename with path and extension'; rsMulRenMaskFullNameCharAtPosXtoY = 'Complete filename, char from pos x to y'; rsMulRenMaskParent = 'Parent folder(s)'; rsMulRenMaskExtension = 'Extension'; rsMulRenMaskCounter = 'Counter'; rsMulRenMaskGUID = 'GUID'; rsMulRenMaskVarOnTheFly = 'Variable on the fly'; rsMulRenMaskYear2Digits = 'Year (2 digits)'; rsMulRenMaskYear4Digits = 'Year (4 digits)'; rsMulRenMaskMonth = 'Month'; rsMulRenMaskMonth2Digits = 'Month (2 digits)'; rsMulRenMaskMonthAbrev = 'Month name (short, e.g., "jan")'; rsMulRenMaskMonthComplete = 'Month name (long, e.g., "january")'; rsMulRenMaskDay = 'Day'; rsMulRenMaskDay2Digits = 'Day (2 digits)'; rsMulRenMaskDOWAbrev = 'Day of the week (short, e.g., "mon")'; rsMulRenMaskDOWComplete = 'Day of the week (long, e.g., "monday")'; rsMulRenMaskCompleteDate = 'Complete date'; rsMulRenMaskHour = 'Hour'; rsMulRenMaskHour2Digits = 'Hour (2 digits)'; rsMulRenMaskMin = 'Minute'; rsMulRenMaskMin2Digits = 'Minute (2 digits)'; rsMulRenMaskSec = 'Second'; rsMulRenMaskSec2Digits = 'Second (2 digits)'; rsMulRenMaskCompleteTime = 'Complete time'; rsMulRenFilename = 'Name'; rsMulRenExtension = 'Extension'; rsMulRenCounter = 'Counter'; rsMulRenDate = 'Date'; rsMulRenTime = 'Time'; rsMulRenPlugins = 'Plugins'; // CheckSumCalcVerify dialog rsCheckSumVerifyTitle = 'Verify checksum'; rsCheckSumVerifyText = 'Enter checksum and select algorithm:'; // CheckSumVerify dialog rsCheckSumVerifyGeneral = 'General:'; rsCheckSumVerifyTotal = 'Total:'; rsCheckSumVerifySuccess = 'Success:'; rsCheckSumVerifyMissing = 'Missing:'; rsCheckSumVerifyBroken = 'Broken:'; rsCheckSumVerifyReadError = 'Read error:'; // Drive status rsDriveNoMedia = ''; rsDriveNoLabel = ''; // Edit rsEditNewFile = 'new.txt'; rsEditNewOpen = 'Open file'; rsEditNewFileName = 'Filename:'; // Edit search rsEditSearchCaption = 'Search'; rsEditSearchReplace ='Replace'; rsEditSearchFrw = '&Forward'; rsEditSearchBack = '&Backward'; rsZeroReplacement = 'No replacement took place.'; rsXReplacements = 'Number of replacement: %d'; // Options editors rsOptionsEditorArchivers = 'Archivers'; rsOptionsEditorAutoRefresh = 'Auto refresh'; rsOptionsEditorBehavior = 'Behaviors'; rsOptionsEditorColors = 'Colors'; rsOptionsEditorBriefView = 'Brief'; rsOptionsEditorColumnsView = 'Columns'; rsOptionsEditorCustomColumns = 'Custom columns'; rsOptionsEditorConfiguration = 'Configuration'; rsOptionsEditorDragAndDrop = 'Drag & drop'; rsOptionsEditorDrivesListButton = 'Drives list button'; rsOptionsEditorFileOperations = 'File operations'; rsOptionsEditorFilePanels = 'File panels'; rsOptionsEditorFileTypes = 'File types'; rsOptionsEditorFileNewFileTypes = 'New'; rsOptionsEditorFilesViews = 'Files views'; rsOptionsEditorFilesViewsComplement = 'Files views extra'; rsOptionsEditorFolderTabs = 'Folder tabs'; rsOptionsEditorFolderTabsExtra = 'Folder tabs extra'; rsOptionsEditorFonts = 'Fonts'; rsOptionsEditorHighlighters = 'Highlighters'; rsOptionsEditorHotKeys = 'Hot keys'; rsOptionsEditorIcons = 'Icons'; rsOptionsEditorIgnoreList = 'Ignore list'; rsOptionsEditorKeyboard = 'Keys'; rsOptionsEditorLanguage = 'Language'; rsOptionsEditorLayout = 'Layout'; rsOptionsEditorLog = 'Log'; rsOptionsEditorMiscellaneous = 'Miscellaneous'; rsOptionsEditorMouse = 'Mouse'; rsOptionsEditorPlugins = 'Plugins'; rsOptionsEditorQuickSearch = 'Quick search/filter'; rsOptionsEditorTerminal = 'Terminal'; rsOptionsEditorToolbar = 'Toolbar'; rsOptionsEditorToolbarExtra = 'Toolbar Extra'; rsOptionsEditorToolbarMiddle = 'Toolbar Middle'; rsOptionsEditorTools = 'Tools'; rsOptionsEditorTooltips = 'Tooltips'; rsOptionsEditorFileAssoc = 'File associations'; rsOptionsEditorFileAssicExtra = 'File associations extra'; rsOptionsEditorDirectoryHotlist = 'Directory Hotlist'; rsOptionsEditorDirectoryHotlistExtra = 'Directory Hotlist Extra'; rsOptionsEditorFavoriteTabs = 'Favorite Tabs'; rsOptionsEditorOptionsChanged = 'Options have changed in "%s"'+#$0A+#$0A+'Do you want to save modifications?'; rsOptionsEditorFileSearch = 'File search'; rsOptionsEditorMultiRename = 'Multi-Rename Tool'; //------------------------------- rsOptConfigSortOrder = 'Classic, legacy order;Alphabetic order (but language still first)'; rsOptConfigTreeState = 'Full expand;Full collapse'; rsOptDifferFramePosition = 'Active frame panel on left, inactive on right (legacy);Left frame panel on left, right on right'; //------------------------------- rsDarkMode = 'Dark mode'; rsDarkModeOptions = 'Auto;Enabled;Disabled'; //------------------------------- rsDriveFreeSpaceIndicator = 'Drive Free Space Indicator'; //------------------------------- rsOptEnterExt = 'Enter extension'; rsOptAssocPluginWith = 'Associate plugin "%s" with:'; rsOptMouseSelectionButton = 'Left button;Right button;'; rsOptAutoSizeColumn = 'First;Last;'; rsOptTabsPosition = 'Top;Bottom;'; rsOptArchiveTypeName = 'Archive type name:'; //------------------------------- // Hotkeys rsOptHotkeysAddDeleteShortcutLong = 'Shortcut %s for cm_Delete will be registered, so it can be used to reverse this setting.'; rsOptHotkeysAddShortcutButton = 'Add shortcut'; rsOptHotkeysCannotSetShortcut = 'Cannot set shortcut'; rsOptHotkeysChangeShortcut = 'Change shortcut'; rsOptHotkeysDeleteTrashCanOverrides = 'Shortcut %s for cm_Delete has a parameter that overrides this setting. Do you want to change this parameter to use the global setting?'; rsOptHotkeysDeleteTrashCanParameterExists = 'Shortcut %s for cm_Delete needs to have a parameter changed to match shortcut %s. Do you want to change it?'; rsOptHotkeysSetDeleteShortcut = 'Set shortcut to delete file'; rsOptHotkeysShortcutForDeleteAlreadyAssigned = 'For this setting to work with shortcut %s, shortcut %s must be assigned to cm_Delete but it is already assigned to %s. Do you want to change it?'; rsOptHotkeysShortcutForDeleteIsSequence = 'Shortcut %s for cm_Delete is a sequence shortcut for which a hotkey with reversed Shift cannot be assigned. This setting might not work.'; rsOptHotkeysCommand = 'Command'; rsOptHotkeysDescription = 'Description'; rsOptHotkeysFixParameter = 'Fix parameter'; rsOptHotkeysHotkeys = 'Hotkeys'; rsOptHotkeysHotkey = 'Hotkey'; rsOptHotkeysNoHotkey = ''; rsOptHotkeysParameters = 'Parameters'; rsOptHotkeysShortCutUsed = 'Shortcut in use'; rsOptHotkeysShortCutUsedText1 = 'Shortcut %s is already used.'; rsOptHotkeysShortCutUsedText2 = 'Change it to %s?'; rsOptHotkeysUsedBy = 'used for %s in %s'; rsOptHotkeysUsedWithDifferentParams = 'used for this command but with different parameters'; rsOptHotkeysAddHotkey = 'Add hotkey for %s'; rsOptHotkeysEditHotkey = 'Edit hotkey for %s'; rsHotkeyCategoryMain = 'Main'; rsHotkeyCategoryViewer = 'Viewer'; rsHotkeyCategoryEditor = 'Editor'; rsHotkeyCategoryFindFiles = 'Find files'; rsHotkeyCategoryDiffer = 'Differ'; rsHotkeyCategoryCopyMoveDialog = 'Copy/Move Dialog'; rsHotkeyCategorySyncDirs = 'Synchronize Directories'; rsHotkeyCategoryEditCommentDialog = 'Edit Comment Dialog'; rsHotkeyCategoryMultiRename = 'Multi-Rename Tool'; rsHotkeySortOrder = 'By command name;By shortcut key (grouped);By shortcut key (one per row)'; rsHotKeyNoSCEnter='No shortcut with "ENTER"'; rsHotKeyFileSaveModified = '"%s" setup has been modified.'+#$0A+'Do you want to save it now?'; rsHotKeyFileNewName = 'New name'; rsHotKeyFileInputNewName = 'Input your new name'; rsHotKeyFileAlreadyExists = 'A setup with that name already exists.'+#$0A+'Do you want to overwrite it?'; rsHotKeyFileCopyOf = 'Copy of %s'; rsHotKeyFileConfirmErasure = 'Are you sure you want to erase setup "%s"?'; rsHotKeyFileMustKeepOne = 'You must keep at least one shortcut file.'; rsHotKeyFileConfirmDefault = 'Are you sure you want to restore default?'; rsCmdCategoryListInOrder='All;Active Panel;Left Panel;Right Panel;File Operations;Configuration;Network;Miscellaneous;Parallel Port;Print;Mark;Security;Clipboard;FTP;Navigation;Help;Window;Command Line;Tools;View;User;Tabs;Sorting;Log'; rsCmdKindOfSort='Legacy sorted;A-Z sorted'; rsMsgThisIsNowInClipboard = '"%s" is now in the clipboard'; rsSimpleWordAll = 'All'; rsSimpleWordCommand = 'Command'; rsSimpleWordCategory = 'Category'; rsSimpleWordFilename = 'Filename'; rsSimpleWordParameter = 'Param'; rsSimpleWordWorkDir = 'WorkDir'; rsSimpleWordResult = 'Result'; rsSimpleWordColumnSingular = 'Column'; rsSimpleWordLetter = 'Letter'; rsSimpleWordTrue = 'True'; rsSimpleWordFalse = 'False'; rsSimpleWordError = 'Error'; rsSimpleWordSuccessExcla = 'Success!'; rsSimpleWordFailedExcla = 'Failed!'; rsSimpleWordVariable = 'Variable'; // Plugins rsOptPluginsActive = 'Active'; rsOptPluginsName = 'Name'; rsOptPluginsRegisteredFor = 'Registered for'; rsOptPluginsFileName = 'File name'; rsOptPluginsDescription = 'Description'; rsOptPluginAlreadyAssigned = 'Plugin %s is already assigned for the following extensions:'; rsOptPluginEnable = 'E&nable'; rsOptPluginDisable = 'D&isable'; rsOptPluginShowByPlugin = 'By Plugin'; rsOptPluginShowByExtension = 'By extension'; rsOptPluginsSelectLuaLibrary = 'Select Lua library file'; rsOptPluginSortOnlyWhenByExtension = 'Sorting WCX plugins is only possible when showing plugins by extension!'; rsPluginFilenameStyleList = 'With complete absolute path;Path relative to %COMMANDER_PATH%;Relative to the following'; //------------------------------- rsOptSortMethod = 'Alphabetical, considering accents;Alphabetical with special characters sort;Natural sorting: alphabetical and numbers;Natural with special characters sort'; rsOptSortCaseSens = 'not case sensitive;according to locale settings (aAbBcC);first upper then lower case (ABCabc)'; rsOptSortFolderMode = 'sort by name and show first;sort like files and show first;sort like files'; rsOptNewFilesPosition = 'at the top of the file list;after directories (if directories are sorted before files);at sorted position;at the bottom of the file list'; rsOptUpdatedFilesPosition = 'don''t change position;use the same setting as for new files;to sorted position'; rsOptFileOperationsProgressKind = 'separate window;minimized separate window;operations panel'; rsOptTypeOfDuplicatedRename = 'DC legacy - Copy (x) filename.ext;Windows - filename (x).ext;Other - filename(x).ext'; // Keyboard rsOptLetters = 'None;Command Line;Quick Search;Quick Filter'; // Directory hotlist rsOptAddFromMainPanel = 'Add at &beginning;Add at the end;Smart add'; //File Associations rsMsgTitleExtNotInFileType = 'Extension of selected file is not in any recognized file types'; rsMsgSekectFileType = 'Select to which file type to add extension "%s"'; rsMsgCreateANewFileType = '< Create a new file type "%s files" >'; rsMsgEnterNewFileTypeName = 'Enter name of new file type to create for extension "%s"'; rsMsgEnterCustomAction = 'Enter custom action name:'; rsSimpleWordFiles = 'files'; rsViewWithInternalViewer = 'with internal viewer'; rsEditWithInternalEditor = 'with internal editor'; rsViewWithExternalViewer = 'with external viewer'; rsEditWithExternalEditor = 'with external editor'; rsExecuteViaShell = 'Execute via shell'; rsExecuteViaTerminalClose = 'Execute via terminal and close'; rsExecuteViaTerminalStayOpen = 'Execute via terminal and stay open'; rsConfigurationFileAssociation = 'Configure file association'; //Variables rsConfirmExecution = 'Confirming command line and parameters'; rsVarHelpWith = 'Help with "%" variables'; rsVarOtherExamples = 'Other example of what''s possible'; rsVarOnlyFilename = 'Only filename'; rsVarPath = 'Path, without ending delimiter'; rsVarLastDirOfPath = 'Last directory of file''s path'; rsVarFullPath = 'Complete filename (path+filename)'; rsVarFilenameNoExt = 'Just filename, no extension'; rsVarOnlyExtension = 'Only file extension'; rsVarRelativePathAndFilename = 'Filename with relative path'; rsVarCurrentPath = 'Path of panel'; rsVarLastDirCurrentPath = 'Last directory of panel''s path'; rsVarListFilename = 'Temporary filename of list of filenames'; rsVarListFullFilename = 'Temporary filename of list of complete filenames (path+filename)'; rsVarListRelativeFilename = 'Temporary filename of list of filenames with relative path'; rsVarListInUTF8 = 'Filenames in list in UTF-8'; rsVarListInUTF16 = 'Filenames in list in UTF-16 with BOM'; rsVarListInUTF8Quoted = 'Filenames in list in UTF-8, inside double quotes'; rsVarListInUTF16Quoted = 'Filenames in list in UTF-16 with BOM, inside double quotes'; rsVarSourcePanel = 'Active panel (source)'; rsVarTargetPanel = 'Inactive panel (target)'; rsVarLeftPanel = 'Left panel'; rsVarRightPanel = 'Right panel'; rsVarBothPanelLeftToRight = 'Both panels, from left to right'; rsVarBothPanelActiveToInactive = 'Both panels, from active to inactive'; rsVarShowCommandPrior = 'Show command prior execute'; rsVarPercentSign = 'Return the percent sign'; rsVarPercentChangeToPound = 'From here to the end of the line, the percent-variable indicator is the "#" sign'; rsVarPoundChangeToPercent = 'From here to the end of the line, the percent-variable indicator is back the "%" sign'; rsVarWillNotBeQuoted = 'Filenames will not be quoted from here'; rsVarWillBeQuoted = 'Filenames will be quoted from here (default)'; rsVarWillNotHaveEndingDelimiter = 'Paths will not have ending delimiter (default)'; rsVarWillHaveEndingDelimiter = 'Paths will have ending delimiter'; rsVarWillNotDoInTerminal = 'Command will be done in terminal, closed at the end'; rsVarWillDoInTerminal = 'Command will be done in terminal, remaining opened at the end'; rsVarSimpleMessage = '%[Simple message]'; rsVarSimpleShowMessage = 'Will show a simple message'; rsVarPromptUserForParam = '%[Prompt user for param;Default value proposed]'; rsVarInputParam = 'Will request request user to enter a parameter with a default suggested value'; rsVarPrependElement = 'Prepend each name with "-a " or what you want'; rsVarEncloseElement = 'Enclose each name in brackets or what you want'; rsVarSecondElementRightPanel = 'Full path of second selected file in right panel'; // Quick Search/Filter rsOptSearchItems = '&Files;Di&rectories;Files a&nd Directories'; rsOptSearchCase = '&Sensitive;&Insensitive'; rsOptSearchOpt = '&Hide filter panel when not focused;Keep saving setting modifications for next session'; // Toolbar rsOptToolbarButtonType = 'S&eparator;Inte&rnal command;E&xternal command;Men&u'; rsImportToolbarProblem = 'Cannot find reference to default bar file'; rsMsgToolbarSaved = 'Saved!'+#$0A+'Toolbar filename: %s'; rsMsgTCToolbarWhereToSave = 'Enter location and filename where to save a TC Toolbar file'; rsMsgDCToolbarWhereToSave = 'Enter location and filename where to save a DC Toolbar file'; rsMsgToolbarRestoreWhat = 'Enter location and filename of Toolbar to restore'; rsMsgToolbarLocateTCToolbarFile = 'Locate ".BAR" file to import'; rsMsgToolbarLocateDCToolbarFile = 'Locate ".toolbar" file to import'; rsMsgTCToolbarNotFound = 'Error! Cannot find the desired wanted TC toolbar output folder:'+#$0A+'%s'; rsMsgTCConfigNotFound = 'Error! Cannot find the TC configuration file:'+#$0A+'%s'; rsMsgTCExecutableNotFound = 'Error! Cannot find the TC configuration executable:'+#$0A+'%s'; rsMsgTCisRunning = 'Error! TC is still running but it should be closed for this operation.'+#$0A+'Close it and press OK or press CANCEL to abort.'; rsMsgAllDCIntCmds = 'All Double Commander internal commands'; //Columns Menu rsMenuConfigureCustomColumns= 'Configure custom columns'; rsMenuConfigureEnterCustomColumnName = 'Enter new custom columns name'; rsMenuConfigureColumnsSaveToChange = 'To change current editing colmuns view, either SAVE, COPY or DELETE current editing one'; rsMenuConfigureColumnsAlreadyExists = 'A columns view with that name already exists.'; // Operation states. rsOperNotStarted = 'Not started'; rsOperStarting = 'Starting'; rsOperRunning = 'Running'; rsOperPausing = 'Pausing'; rsOperPaused = 'Paused'; rsOperWaitingForFeedback = 'Waiting for user response'; rsOperWaitingForConnection = 'Waiting for access to file source'; rsOperStopping = 'Stopping'; rsOperStopped = 'Stopped'; rsOperFinished = 'Finished'; rsOperAborted = 'Aborted'; // Operations descriptions. rsOperCalculatingCheckSum = 'Calculating checksum'; rsOperCalculatingCheckSumIn = 'Calculating checksum in "%s"'; rsOperCalculatingCheckSumOf = 'Calculating checksum of "%s"'; rsOperCalculatingStatictics = 'Calculating'; rsOperCalculatingStatisticsIn = 'Calculating "%s"'; rsOperCombining = 'Joining'; rsOperCombiningFromTo = 'Joining files in "%s" to "%s"'; rsOperCopying = 'Copying'; rsOperCopyingFromTo = 'Copying from "%s" to "%s"'; rsOperCopyingSomethingTo = 'Copying "%s" to "%s"'; rsOperCreatingDirectory = 'Creating directory'; rsOperCreatingSomeDirectory = 'Creating directory "%s"'; rsOperDeleting = 'Deleting'; rsOperDeletingIn = 'Deleting in "%s"'; rsOperDeletingSomething = 'Deleting "%s"'; rsOperExecuting = 'Executing'; rsOperExecutingSomething = 'Executing "%s"'; rsOperExtracting = 'Extracting'; rsOperExtractingFromTo = 'Extracting from "%s" to "%s"'; rsOperListing = 'Listing'; rsOperListingIn = 'Listing "%s"'; rsOperMoving = 'Moving'; rsOperMovingFromTo = 'Moving from "%s" to "%s"'; rsOperMovingSomethingTo = 'Moving "%s" to "%s"'; rsOperPacking = 'Packing'; rsOperPackingFromTo = 'Packing from "%s" to "%s"'; rsOperPackingSomethingTo = 'Packing "%s" to "%s"'; rsOperSettingProperty = 'Setting property'; rsOperSettingPropertyIn = 'Setting property in "%s"'; rsOperSettingPropertyOf = 'Setting property of "%s"'; rsOperSplitting = 'Splitting'; rsOperSplittingFromTo = 'Splitting "%s" to "%s"'; rsOperTesting = 'Testing'; rsOperTestingSomething = 'Testing "%s"'; rsOperTestingIn = 'Testing in "%s"'; rsOperVerifyingCheckSum = 'Verifying checksum'; rsOperVerifyingCheckSumIn = 'Verifying checksum in "%s"'; rsOperVerifyingCheckSumOf = 'Verifying checksum of "%s"'; rsOperWiping = 'Wiping'; rsOperWipingIn = 'Wiping in "%s"'; rsOperWipingSomething = 'Wiping "%s"'; rsOperWorking = 'Working'; // Generic description for unknown operation //TreeViewMenu rsOptionsEditorTreeViewMenu = 'Tree View Menu'; rsOptionsEditorTreeViewMenuColors = 'Tree View Menu Colors'; rsStrPreviewSearchingLetters = 'OU'; rsStrPreviewJustPreview = 'Just preview'; rsStrPreviewWordWithSearched1 = 'Fabulous'; rsStrPreviewWordWithSearched2 = 'Marvelous'; rsStrPreviewWordWithSearched3 = 'Tremendous'; rsStrPreviewSideNote = 'Side note'; rsStrPreviewOthers = 'Others'; rsStrPreviewWordWithoutSearched1 = 'Flat'; rsStrPreviewWordWithoutSearched2 = 'Limited'; rsStrPreviewWordWithoutSearched3 = 'Simple'; rsMsgUnexpectedUsageTreeViewMenu = 'ERROR: Unexpected Tree View Menu usage!'; rsStrTVMChooseHotDirectory = 'Choose your directory from Hot Directory:'; rsStrTVMChooseFavoriteTabs = 'Choose you Favorite Tabs:'; rsStrTVMChooseDirHistory = 'Choose your directory from Dir History'; rsStrTVMChooseViewHistory = 'Choose your directory from File View History'; rsStrTVMChooseFromToolbar = 'Choose your action from Maintool bar'; rsStrTVMChooseFromMainMenu = 'Choose your action from Main Menu'; rsStrTVMChooseFromCmdLineHistory = 'Choose your command from Command Line History'; rsStrTVMChooseYourFileOrDir = 'Choose your file or your directory'; //Split/Combine operation special message rsMsgBadCRC32 = 'Bad CRC32 for resulting file:'+#$0A+'"%s"'+#$0A+#$0A+'Do you want to keep the resulting corrupted file anyway?'; rsMsgProvideThisFile = 'Please, make this file available. Retry?'; rsMsgIncorrectFilelength = 'Incorrect resulting filelength for file : "%s"'; rsMSgUndeterminedNumberOfFile = 'Undetermined'; rsMsgInsertNextDisk = 'Please insert next disk or something similar.'+#$0A+#$0A+'It is to allow writing this file:'+#$0A+'"%s"'+#$0A+''+#$0A+'Number of bytes still to write: %d'; msgTryToLocateCRCFile = 'This file cannot be found and could help to validate final combination of files:'+#$0A+'%s'+#$0A+#$0A+'Could you make it available and press "OK" when ready,'+#$0A+'or press "CANCEL" to continue without it?'; rsMsgInvalidHexNumber = 'Invalid hexadecimal number: "%s"'; //LUA and script related messages rsMsgScriptCantFindLibrary = 'ERROR: Problem loading Lua library file "%s"'; rsMsgWantToConfigureLibraryLocation = 'Do you want to configure Lua library location?'; // Unhandled error. rsUnhandledExceptionMessage = 'Please report this error to the bug tracker with a description ' + 'of what you were doing and the following file:%s' + 'Press %s to continue or %s to abort the program.'; function GetLanguageName(const poFileName : String) : String; procedure lngLoadLng(const sFileName:String); procedure DoLoadLng; implementation uses Forms, Classes, SysUtils, StrUtils, GetText, Translations, uGlobs, uGlobsPaths, uTranslator, uDebug, DCClassesUtf8, DCOSUtils, DCStrUtils, StreamEx; function GetLanguageName(const poFileName: String): String; var sLine: String; S, F, Index : Integer; Stream: TFileStreamEx; Reader: TStreamReader; begin try Stream:= TFileStreamEx.Create(poFileName, fmOpenRead or fmShareDenyNone); try Index:= 0; Reader:= TStreamReader.Create(Stream, BUFFER_SIZE, True); repeat sLine:= Reader.ReadLine; S:= Pos('X-Native-Language', sLine); if S > 0 then begin S:= Pos(':', sLine, S + 17) + 2; F:= Pos('\n', sLine, S) - 1; Result:= Copy(sLine, S, (F - S) + 1); Exit; end; Inc(Index); until (Reader.Eof or (Index > 256)); finally Reader.Free; end; except // Ignore end; Result:= 'Unknown'; end; procedure TranslateLCL(poFileName: String); const BidiModeMap: array[Boolean] of TBiDiMode = (bdLeftToRight, {$IF DEFINED(LCLWIN32)} bdRightToLeftNoAlign // see http://bugs.freepascal.org/view.php?id=28483 {$ELSE} bdRightToLeft {$ENDIF} ); var Lang: String = ''; FallbackLang: string = ''; UserLang, LCLLngDir: String; begin LCLLngDir:= gpLngDir + 'lcl' + PathDelim; if NumCountChars('.', poFileName) >= 2 then begin UserLang:= ExtractDelimited(2, poFileName, ['.']); Application.BidiMode:= BidiModeMap[Application.IsRTLLang(UserLang)]; poFileName:= LCLLngDir + Format('lclstrconsts.%s.po', [UserLang]); if not mbFileExists(poFileName) then begin GetLanguageIDs(Lang, FallbackLang); poFileName:= LCLLngDir + Format('lclstrconsts.%s.po', [Lang]); if not mbFileExists(poFileName) then poFileName:= LCLLngDir + Format('lclstrconsts.%s.po', [FallbackLang]); end; if mbFileExists(poFileName) then Translations.TranslateUnitResourceStrings('LCLStrConsts', poFileName); end; end; procedure lngLoadLng(const sFileName: String); const DEFAULT_PO = 'doublecmd.pot'; var Lang: String = ''; FallbackLang: String = ''; begin // Default english interface if StrBegins(sFileName, 'doublecmd.po') then begin gPOFileName := DEFAULT_PO; Exit; end; gPOFileName := sFileName; if not mbFileExists(gpLngDir + gPOFileName) then begin gPOFileName := 'doublecmd.%s.po'; GetLanguageIDs(Lang, FallbackLang); gPOFileName := Format(gPOFileName,[FallbackLang]); end; if not mbFileExists(gpLngDir + gPOFileName) then begin gPOFileName := Format(gPOFileName,[Lang]); end; if not mbFileExists(gpLngDir + gPOFileName) then gPOFileName := DEFAULT_PO else begin DCDebug('Loading lng file: ' + gpLngDir + gPOFileName); LRSTranslator := TTranslator.Create(gpLngDir + gPOFileName); Translations.TranslateResourceStrings(TTranslator(LRSTranslator).POFile); TranslateLCL(gPOFileName); end; end; procedure DoLoadLng; begin lngLoadLng(gPOFileName); end; finalization FreeAndNil(LRSTranslator); end. doublecmd-1.1.22/src/ulog.pas0000644000175000001440000001306314743153644015053 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- This unit contains log write functions Copyright (C) 2008-2019 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uLog; {$mode objfpc}{$H+} interface uses Classes; type TLogMsgType = (lmtInfo, lmtSuccess, lmtError); function GetActualLogFileName: String; procedure ShowLogWindow(bShow: Boolean); procedure LogWrite(const sText: String; LogMsgType: TLogMsgType = lmtInfo; bForce: Boolean = False; bLogFile: Boolean = True); overload; procedure LogWrite({%H-}Thread: TThread; const sText: String; LogMsgType: TLogMsgType = lmtInfo; bForce: Boolean = False; bLogFile: Boolean = True); overload; implementation uses SysUtils, Forms, FileUtil, fMain, uDebug, uGlobs, uFileProcs, DCOSUtils, uDCUtils; type PLogMessage = ^TLogMessage; TLogMessage = record Message: String; case Boolean of True: (ObjectType: TObject); False: (MessageType: TLogMsgType); end; type { TLogWriter } TLogWriter = class private FMutex: TRTLCriticalSection; private procedure ShowLogWindow; procedure WriteInMainThread(Data: PtrInt); public constructor Create; destructor Destroy; override; procedure Write(const sText: String; LogMsgType: TLogMsgType; bForce, bLogFile: Boolean); end; var LogWriter: TLogWriter; function GetActualLogFileName: String; begin Result:= ReplaceEnvVars(gLogFileName); if gLogFileWithDateInName then begin Result:= Copy(Result, 1, Length(Result) - Length(ExtractFileExt(Result))) + '_' + ReplaceEnvVars(EnvVarTodaysDate) + ExtractFileExt(Result); end; end; procedure ShowLogWindow(bShow: Boolean); begin if Assigned(frmMain) then frmMain.ShowLogWindow(PtrInt(bShow)); end; procedure LogWrite(const sText: String; LogMsgType: TLogMsgType; bForce, bLogFile: Boolean); inline; begin LogWriter.Write(sText, LogMsgType, bForce, bLogFile); end; procedure LogWrite(Thread: TThread; const sText: String; LogMsgType: TLogMsgType; bForce: Boolean; bLogFile: Boolean); inline; begin LogWriter.Write(sText, LogMsgType, bForce, bLogFile); end; function StringListSortCompare(List: TStringList; Index1, Index2: Integer): Integer; begin Result:= CompareText(List[Index2], List[Index1]); end; { TLogWriter } procedure TLogWriter.ShowLogWindow; begin frmMain.ShowLogWindow(PtrInt(True)); end; procedure TLogWriter.WriteInMainThread(Data: PtrInt); var Msg: PLogMessage absolute Data; begin if not Application.Terminated then begin with fMain.frmMain do try seLogWindow.CaretY:= seLogWindow.Lines.AddObject(Msg^.Message, Msg^.ObjectType) + 1; finally Dispose(Msg); end; end; end; constructor TLogWriter.Create; begin InitCriticalSection(FMutex); end; destructor TLogWriter.Destroy; begin inherited Destroy; DoneCriticalsection(FMutex); end; procedure TLogWriter.Write(const sText: String; LogMsgType: TLogMsgType; bForce, bLogFile: Boolean); var Index: Integer; Message: String; hLogFile: THandle; LogMessage: PLogMessage; ActualLogFileName: String; ALogFileList: TStringList; begin if Assigned(fMain.frmMain) and (bForce or gLogWindow) then begin if bForce and (not frmMain.seLogWindow.Visible) then begin if GetCurrentThreadId = MainThreadID then Self.ShowLogWindow else TThread.Synchronize(nil, @Self.ShowLogWindow); end; New(LogMessage); LogMessage^.Message:= sText; LogMessage^.MessageType:= LogMsgType; Application.QueueAsyncCall(@WriteInMainThread, {%H-}PtrInt(LogMessage)); end; if gLogFile and bLogFile then begin EnterCriticalsection(FMutex); try ActualLogFileName:= GetActualLogFileName; Message:= Format('%s %s', [DateTimeToStr(Now), sText]); if mbFileExists(ActualLogFileName) then hLogFile:= mbFileOpen(ActualLogFileName, fmOpenWrite) else begin hLogFile:= mbFileCreate(ActualLogFileName); if gLogFileCount > 0 then begin ALogFileList:= FindAllFiles(ExtractFileDir(ActualLogFileName), '*_????-??-??' + ExtractFileExt(ActualLogFileName), False); ALogFileList.CustomSort(@StringListSortCompare); for Index:= gLogFileCount to ALogFileList.Count - 1 do begin mbDeleteFile(ALogFileList[Index]); end; ALogFileList.Free; end; end; if (hLogFile = feInvalidHandle) then DCDebug('LogWrite: ' + mbSysErrorMessage) else begin FileSeek(hLogFile, 0, soFromEnd); FileWriteLn(hLogFile, Message); FileClose(hLogFile); end; DCDebug(Message); finally LeaveCriticalsection(FMutex); end; end; end; initialization LogWriter:= TLogWriter.Create; finalization LogWriter.Free; end. doublecmd-1.1.22/src/uluapas.pas0000644000175000001440000004642514743153644015567 0ustar alexxusers{ Double commander ------------------------------------------------------------------------- Push some useful functions to Lua Copyright (C) 2016-2023 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . } unit uLuaPas; {$mode objfpc}{$H+} interface uses uDCUtils, Classes, SysUtils, Lua; procedure RegisterPackages(L : Plua_State); procedure SetPackagePath(L: Plua_State; const Path: String); function LuaPCall(L : Plua_State; nargs, nresults : Integer): Boolean; function ExecuteScript(const FileName: String; Args: array of String; var sErrorToReportIfAny:string): Boolean; implementation uses Forms, Dialogs, Clipbrd, LazUTF8, LCLVersion, uLng, DCOSUtils, DCConvertEncoding, fMain, uFormCommands, uOSUtils, uGlobs, uLog, uClipboard, uShowMsg, uLuaStd, uFindEx, uConvEncoding, uFileProcs, uFilePanelSelect, uMasks, LazFileUtils, Character, UnicodeData; procedure luaPushSearchRec(L : Plua_State; Rec: PSearchRecEx); begin lua_pushlightuserdata(L, Rec); lua_newtable(L); lua_pushinteger(L, Rec^.Time); lua_setfield(L, -2, 'Time'); lua_pushinteger(L, Rec^.Size); lua_setfield(L, -2, 'Size'); lua_pushinteger(L, Rec^.Attr); lua_setfield(L, -2, 'Attr'); lua_pushstring(L, Rec^.Name); lua_setfield(L, -2, 'Name'); end; function luaFindFirst(L : Plua_State) : Integer; cdecl; var Path: String; Rec: PSearchRecEx; begin New(Rec); Path:= lua_tostring(L, 1); if FindFirstEx(Path, fffPortable, Rec^) = 0 then begin Result:= 2; luaPushSearchRec(L, Rec); end else begin FindCloseEx(Rec^); lua_pushnil(L); Dispose(Rec); Result:= 1; end; end; function luaFindNext(L : Plua_State) : Integer; cdecl; var Rec: PSearchRecEx; begin Rec:= lua_touserdata(L, 1); if (Rec <> nil) and (FindNextEx(Rec^) = 0) then begin Result:= 2; luaPushSearchRec(L, Rec); end else begin lua_pushnil(L); Result:= 1; end; end; function luaFindClose(L : Plua_State) : Integer; cdecl; var Rec: PSearchRecEx; begin Rec:= lua_touserdata(L, 1); if Assigned(Rec) then begin FindCloseEx(Rec^); Dispose(Rec); end; Result:= 0; end; function luaSleep(L : Plua_State) : Integer; cdecl; begin Result:= 0; Sleep(lua_tointeger(L, 1)); end; function luaGetTickCount(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushinteger(L, GetTickCount64); end; function luaFileGetAttr(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushinteger(L, FileGetAttr(mbFileNameToNative(lua_tostring(L, 1)))); end; function luaFileExists(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushboolean(L, mbFileExists(lua_tostring(L, 1))); end; function luaDirectoryExists(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushboolean(L, mbDirectoryExists(lua_tostring(L, 1))); end; function luaCreateDirectory(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushboolean(L, mbForceDirectory(lua_tostring(L, 1))); end; function luaCreateHardLink(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushboolean(L, CreateHardLink(lua_tostring(L, 1), lua_tostring(L, 2))); end; function luaCreateSymbolicLink(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushboolean(L, CreateSymLink(lua_tostring(L, 1), lua_tostring(L, 2))); end; function luaReadSymbolicLink(L : Plua_State) : Integer; cdecl; var Path: String; Recursive: Boolean = False; begin Result:= 1; Path:= lua_tostring(L, 1); if lua_isboolean(L, 2) then begin Recursive:= lua_toboolean(L, 2) end; if Recursive then Path:= mbReadAllLinks(Path) else begin Path:= ReadSymLink(Path); end; lua_pushstring(L, Path); end; function luaExtractFilePath(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, ExtractFilePath(lua_tostring(L, 1))); end; function luaExtractFileDrive(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, ExtractFileDrive(lua_tostring(L, 1))); end; function luaExtractFileName(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, ExtractFileName(lua_tostring(L, 1))); end; function luaExtractFileExt(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, ExtractFileExt(lua_tostring(L, 1))); end; function luaMatchesMask(L : Plua_State) : Integer; cdecl; var FileName: String; FileMask: String; AOptions: TMaskOptions; begin Result:= 1; FileName:= lua_tostring(L, 1); FileMask:= lua_tostring(L, 2); if lua_isnumber(L, 3) then AOptions:= TMaskOptions(Integer(lua_tointeger(L, 3))) else begin AOptions:= []; end; lua_pushboolean(L, MatchesMask(FileName, FileMask, AOptions)); end; function luaMatchesMaskList(L : Plua_State) : Integer; cdecl; var FileName: String; FileMask: String; AOptions: TMaskOptions; ASeparatorCharset: String; begin Result:= 1; FileName:= lua_tostring(L, 1); FileMask:= lua_tostring(L, 2); if lua_isstring(L, 3) then ASeparatorCharset:= lua_tostring(L, 3) else begin ASeparatorCharset:= ';'; end; if lua_isnumber(L, 4) then AOptions:= TMaskOptions(Integer(lua_tointeger(L, 4))) else begin AOptions:= []; end; lua_pushboolean(L, MatchesMaskList(FileName, FileMask, ASeparatorCharset, AOptions)); end; function luaExtractFileDir(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, ExtractFileDir(lua_tostring(L, 1))); end; function luaGetAbsolutePath(L : Plua_State) : Integer; cdecl; var FileName, BaseDir: String; begin Result:= 1; FileName:= lua_tostring(L, 1); BaseDir:= lua_tostring(L, 2); lua_pushstring(L, CreateAbsolutePath(FileName, BaseDir)); end; function luaGetRelativePath(L : Plua_State) : Integer; cdecl; var FileName, BaseDir: String; begin Result:= 1; FileName:= lua_tostring(L, 1); BaseDir:= lua_tostring(L, 2); lua_pushstring(L, CreateRelativePath(FileName, BaseDir)); end; function luaGetTempName(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, GetTempName(GetTempFolderDeletableAtTheEnd)); end; function utf8_next(L: Plua_State): Integer; cdecl; var S: String; C: Integer; Len: size_t; P: PAnsiChar; Index: Integer; begin P:= lua_tolstring(L, lua_upvalueindex(1), @Len); Index:= lua_tointeger(L, lua_upvalueindex(2)); if (Index >= Integer(Len)) then Exit(0); P:= P + Index; C:= UTF8CodepointSize(P); // Partial UTF-8 character if (Index + C) > Len then Exit(0); SetString(S, P, C); lua_pushinteger(L, Index + C); lua_replace(L, lua_upvalueindex(2)); lua_pushinteger(L, Index + 1); lua_pushstring(L, S); Result:= 2; end; function luaNext(L : Plua_State) : Integer; cdecl; begin lua_pushvalue(L, 1); lua_pushnumber(L, 0); lua_pushcclosure(L, @utf8_next, 2); Result:= 1; end; function luaPos(L : Plua_State) : Integer; cdecl; var Offset: SizeInt = 1; Search, Source: String; begin Result:= 1; Search:= lua_tostring(L, 1); Source:= lua_tostring(L, 2); if lua_isnumber(L, 3) then begin Offset:= lua_tointeger(L, 3) end; lua_pushinteger(L, UTF8Pos(Search, Source, Offset)); end; function luaCopy(L : Plua_State) : Integer; cdecl; var S: String; Start, Count: PtrInt; begin Result:= 1; S:= lua_tostring(L, 1); Start:= lua_tointeger(L, 2); Count:= lua_tointeger(L, 3); S:= UTF8Copy(S, Start, Count); lua_pushstring(L, S); end; function luaLength(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushinteger(L, UTF8Length(lua_tostring(L, 1))); end; function luaUpperCase(L : Plua_State) : Integer; cdecl; var S: String; begin Result:= 1; S:= lua_tostring(L, 1); S:= UTF8UpperCase(S); lua_pushstring(L, S); end; function luaLowerCase(L : Plua_State) : Integer; cdecl; var S: String; begin Result:= 1; S:= lua_tostring(L, 1); S:= UTF8LowerCase(S); lua_pushstring(L, S); end; function luaConvertEncoding(L : Plua_State) : Integer; cdecl; var S, FromEnc, ToEnc: String; begin Result:= 1; S:= lua_tostring(L, 1); FromEnc:= lua_tostring(L, 2); ToEnc:= lua_tostring(L, 3); lua_pushstring(L, ConvertEncoding(S, FromEnc, ToEnc)); end; function luaDetectEncoding(L : Plua_State) : Integer; cdecl; var S: String; begin Result:= 1; S:= lua_tostring(L, 1); lua_pushstring(L, DetectEncoding(S)); end; function char_prepare(L : Plua_State; out Index: Integer): UnicodeString; var Len: size_t; P: PAnsiChar; begin P:= lua_tolstring(L, 1, @Len); Result:= UTF8ToUTF16(P, Len); if lua_isnumber(L, 2) then Index:= Integer(lua_tointeger(L, 2)) else begin Index:= 1; end; end; function luaIsLower(L : Plua_State) : Integer; cdecl; var Index: Integer; S: UnicodeString; begin S:= char_prepare(L, Index); try lua_pushboolean(L, TCharacter.IsLower(S, Index)); Result:= 1; except Result:= 0; end; end; function luaIsUpper(L : Plua_State) : Integer; cdecl; var Index: Integer; S: UnicodeString; begin S:= char_prepare(L, Index); try lua_pushboolean(L, TCharacter.IsUpper(S, Index)); Result:= 1; except Result:= 0; end; end; function luaIsDigit(L : Plua_State) : Integer; cdecl; var Index: Integer; S: UnicodeString; begin S:= char_prepare(L, Index); try lua_pushboolean(L, TCharacter.IsDigit(S, Index)); Result:= 1; except Result:= 0; end; end; function luaIsLetter(L : Plua_State) : Integer; cdecl; var Index: Integer; S: UnicodeString; begin S:= char_prepare(L, Index); try lua_pushboolean(L, TCharacter.IsLetter(S, Index)); Result:= 1; except Result:= 0; end; end; function luaIsLetterOrDigit(L : Plua_State) : Integer; cdecl; var Index: Integer; S: UnicodeString; begin S:= char_prepare(L, Index); try lua_pushboolean(L, TCharacter.IsLetterOrDigit(S, Index)); Result:= 1; except Result:= 0; end; end; function luaGetUnicodeCategory(L : Plua_State) : Integer; cdecl; var Index: Integer; S: UnicodeString; begin S:= char_prepare(L, Index); try lua_pushinteger(L, lua_Integer(TCharacter.GetUnicodeCategory(S, Index))); Result:= 1; except Result:= 0; end; end; function luaClipbrdClear(L : Plua_State) : Integer; cdecl; begin Result:= 0; Clipboard.Clear; end; function luaClipbrdGetText(L : Plua_State) : Integer; cdecl; begin Result:= 1; lua_pushstring(L, Clipboard.AsText); end; function luaClipbrdSetText(L : Plua_State) : Integer; cdecl; begin Result:= 0; ClipboardSetText(luaL_checkstring(L, 1)); end; function luaClipbrdSetHtml(L : Plua_State) : Integer; cdecl; begin Result:= 0; Clipboard.SetAsHtml(luaL_checkstring(L, 1)); end; function luaMessageBox(L : Plua_State) : Integer; cdecl; var flags: Integer; text, caption: PAnsiChar; begin Result:= 1; text:= luaL_checkstring(L, 1); caption:= luaL_checkstring(L, 2); flags:= Integer(lua_tointeger(L, 3)); flags:= ShowMessageBox(text, caption, flags); lua_pushinteger(L, flags); end; function luaInputQuery(L : Plua_State) : Integer; cdecl; var AValue: String; AMaskInput: Boolean; APrompt, ACaption: PAnsiChar; begin Result:= 1; ACaption:= luaL_checkstring(L, 1); APrompt:= luaL_checkstring(L, 2); AMaskInput:= lua_toboolean(L, 3); AValue:= luaL_checkstring(L, 4); AMaskInput:= ShowInputQuery(ACaption, APrompt, AMaskInput, AValue); lua_pushboolean(L, AMaskInput); if AMaskInput then begin Result:= 2; lua_pushstring(L, AValue); end; end; function luaInputListBox(L : Plua_State) : Integer; cdecl; var AValue: String = ''; AIndex, ACount: Integer; AStringList: TStringList; APrompt, ACaption: PAnsiChar; begin Result:= 1; if (lua_gettop(L) < 3) or (not lua_istable(L, 3)) then begin lua_pushnil(L); Exit; end; ACaption:= lua_tocstring(L, 1); APrompt:= lua_tocstring(L, 2); ACount:= lua_objlen(L, 3); AStringList:= TStringList.Create; for AIndex := 1 to ACount do begin lua_rawgeti(L, 3, AIndex); AStringList.Add(luaL_checkstring(L, -1)); lua_pop(L, 1); end; if lua_isstring(L, 4) then begin AValue:= lua_tostring(L, 4); end; if ShowInputListBox(ACaption, APrompt, AStringList, AValue, AIndex) then begin Result:= 2; lua_pushstring(L, AValue); lua_pushinteger(L, AIndex + 1); end else begin lua_pushnil(L); end; AStringList.Free; end; function luaLogWrite(L : Plua_State) : Integer; cdecl; var sText: String; bForce: Boolean = True; bLogFile: Boolean = False; LogMsgType: TLogMsgType = lmtInfo; begin Result:= 0; sText:= lua_tostring(L, 1); if lua_isnumber(L, 2) then LogMsgType:= TLogMsgType(lua_tointeger(L, 2)); if lua_isboolean(L, 3) then bForce:= lua_toboolean(L, 3); if lua_isboolean(L, 4) then bLogFile:= lua_toboolean(L, 4); logWrite(sText, LogMsgType, bForce, bLogFile); end; function luaExecuteCommand(L : Plua_State) : Integer; cdecl; var Index, Count: Integer; Command: String; Args: array of String; Res: TCommandFuncResult; begin Result:= 1; Res:= cfrNotFound; Count:= lua_gettop(L); if Count > 0 then begin // Get command Command:= lua_tostring(L, 1); // Get parameters SetLength(Args, Count - 1); for Index:= 2 to Count do Args[Index - 2]:= lua_tostring(L, Index); // Execute internal command Res:= frmMain.Commands.Commands.ExecuteCommand(Command, Args); Application.ProcessMessages; end; lua_pushboolean(L, Res = cfrSuccess); end; function luaCurrentPanel(L : Plua_State) : Integer; cdecl; var Count: Integer; begin Result:= 1; Count:= lua_gettop(L); lua_pushinteger(L, Integer(frmMain.SelectedPanel)); if (Count > 0) then frmMain.SetActiveFrame(TFilePanelSelect(lua_tointeger(L, 1))); end; procedure luaP_register(L : Plua_State; n : PChar; f : lua_CFunction); begin lua_pushcfunction(L, f); lua_setfield(L, -2, n); end; procedure luaC_register(L : Plua_State; n : PChar; c : PChar); begin lua_pushstring(L, c); lua_setfield(L, -2, n); end; procedure RegisterPackages(L: Plua_State); begin lua_newtable(L); luaP_register(L, 'Sleep', @luaSleep); luaP_register(L, 'FindNext', @luaFindNext); luaP_register(L, 'FindFirst', @luaFindFirst); luaP_register(L, 'FindClose', @luaFindClose); luaP_register(L, 'FileExists', @luaFileExists); luaP_register(L, 'FileGetAttr', @luaFileGetAttr); luaP_register(L, 'GetTickCount', @luaGetTickCount); luaP_register(L, 'DirectoryExists', @luaDirectoryExists); luaP_register(L, 'CreateDirectory', @luaCreateDirectory); luaP_register(L, 'CreateHardLink', @luaCreateHardLink); luaP_register(L, 'CreateSymbolicLink', @luaCreateSymbolicLink); luaP_register(L, 'ReadSymbolicLink', @luaReadSymbolicLink); luaP_register(L, 'ExtractFileExt', @luaExtractFileExt); luaP_register(L, 'ExtractFileDir', @luaExtractFileDir); luaP_register(L, 'ExtractFilePath', @luaExtractFilePath); luaP_register(L, 'ExtractFileName', @luaExtractFileName); luaP_register(L, 'ExtractFileDrive', @luaExtractFileDrive); luaP_register(L, 'GetAbsolutePath', @luaGetAbsolutePath); luaP_register(L, 'GetRelativePath', @luaGetRelativePath); luaP_register(L, 'MatchesMask', @luaMatchesMask); luaP_register(L, 'MatchesMaskList', @luaMatchesMaskList); luaP_register(L, 'GetTempName', @luaGetTempName); luaC_register(L, 'PathDelim', PathDelim); lua_setglobal(L, 'SysUtils'); lua_newtable(L); luaP_register(L, 'Pos', @luaPos); luaP_register(L, 'Next', @luaNext); luaP_register(L, 'Copy', @luaCopy); luaP_register(L, 'Length', @luaLength); luaP_register(L, 'UpperCase', @luaUpperCase); luaP_register(L, 'LowerCase', @luaLowerCase); luaP_register(L, 'ConvertEncoding', @luaConvertEncoding); luaP_register(L, 'DetectEncoding', @luaDetectEncoding); lua_setglobal(L, 'LazUtf8'); lua_newtable(L); luaP_register(L, 'IsLower', @luaIsLower); luaP_register(L, 'IsUpper', @luaIsUpper); luaP_register(L, 'IsDigit', @luaIsDigit); luaP_register(L, 'IsLetter', @luaIsLetter); luaP_register(L, 'IsLetterOrDigit', @luaIsLetterOrDigit); luaP_register(L, 'GetUnicodeCategory', @luaGetUnicodeCategory); lua_setglobal(L, 'Char'); lua_newtable(L); luaP_register(L, 'Clear', @luaClipbrdClear); luaP_register(L, 'GetAsText', @luaClipbrdGetText); luaP_register(L, 'SetAsText', @luaClipbrdSetText); luaP_register(L, 'SetAsHtml', @luaClipbrdSetHtml); lua_setglobal(L, 'Clipbrd'); lua_newtable(L); luaP_register(L, 'MessageBox', @luaMessageBox); luaP_register(L, 'InputQuery', @luaInputQuery); luaP_register(L, 'InputListBox', @luaInputListBox); lua_setglobal(L, 'Dialogs'); lua_newtable(L); luaP_register(L, 'LogWrite', @luaLogWrite); luaP_register(L, 'CurrentPanel', @luaCurrentPanel); luaP_register(L, 'ExecuteCommand', @luaExecuteCommand); lua_setglobal(L, 'DC'); ReplaceLibrary(L); end; procedure SetPackagePath(L: Plua_State; const Path: String); var APath: String; begin lua_getglobal(L, 'package'); // Set package.path lua_getfield(L, -1, 'path'); APath := lua_tostring(L, -1); APath := StringReplace(APath, '.' + PathDelim, Path, []); lua_pop(L, 1); lua_pushstring(L, APath); lua_setfield(L, -2, 'path'); // Set package.cpath lua_getfield(L, -1, 'cpath'); APath := lua_tostring(L, -1); APath := StringReplace(APath, '.' + PathDelim, Path, []); lua_pop(L, 1); lua_pushstring(L, APath); lua_setfield(L, -2, 'cpath'); lua_pop(L, 1); end; function LuaPCall(L: Plua_State; nargs, nresults: Integer): Boolean; var Status: Integer; begin Status:= lua_pcall(L, nargs, nresults, 0); // Check execution result if Status <> 0 then begin logWrite(lua_tostring(L, -1), lmtError, True, False); end; Result:= (Status = 0); end; function ExecuteScript(const FileName: String; Args: array of String; var sErrorToReportIfAny:string): Boolean; var L: Plua_State; Index: Integer; Count: Integer; Script: String; Status: Integer; begin Result:= False; sErrorToReportIfAny := ''; // Load Lua library if not IsLuaLibLoaded then begin if not LoadLuaLib(mbExpandFileName(gLuaLib)) then begin sErrorToReportIfAny := Format(rsMsgScriptCantFindLibrary, [gLuaLib]); Exit; end; end; // Get script file name Script:= mbFileNameToSysEnc(FileName); L := lua_open; if Assigned(L) then begin luaL_openlibs(L); RegisterPackages(L); SetPackagePath(L, ExtractFilePath(Script)); // Load script from file Status := luaL_loadfile(L, PAnsiChar(Script)); if (Status = 0) then begin // Push arguments Count:= Length(Args); if (Count > 0) then begin for Index := 0 to Count - 1 do begin lua_pushstring(L, Args[Index]); end; end; // Execute script Status := lua_pcall(L, Count, 0, 0) end; // Check execution result if Status <> 0 then begin Script:= lua_tostring(L, -1); MessageDlg(CeRawToUtf8(Script), mtError, [mbOK], 0); end; lua_close(L); Result:= (Status = 0); end; end; end. doublecmd-1.1.22/src/uluastd.pas0000644000175000001440000005707614743153644015602 0ustar alexxusers{ Double commander ------------------------------------------------------------------------- Standard Lua libraries with UTF-8 support Copyright (C) 2016-2018 Alexander Koblov (alexx2000@mail.ru) Based on Lua 5.1 - 5.3 source code Copyright (C) 1994-2018 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } unit uLuaStd; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Lua; procedure ReplaceLibrary(L : Plua_State); implementation uses CTypes, DCBasicTypes, DCOSUtils, uMicroLibC, uOSUtils; var CStdIn, CStdOut, CStdErr: Pointer; const EOF = -1; IO_PREFIX = '_IO_'; IO_INPUT_ = IO_PREFIX + 'input'; IO_OUTPUT_ = IO_PREFIX + 'output'; type PLStream = ^luaL_Stream; luaL_Stream = record f: Pointer; //* stream (NULL for incompletely created streams) */ closef: lua_CFunction; //* to close stream (NULL for closed streams) */ end; function os_pushresult(L: Plua_State; i: Boolean; const filename: PAnsiChar): cint; var en: cint; begin en := GetLastOSError; //* calls to Lua API may change this value */ if (i) then begin lua_pushboolean(L, true); Result:= 1; end else begin lua_pushnil(L); lua_pushfstring(L, '%s: %s', filename, PAnsiChar(mbSysErrorMessage(en))); lua_pushinteger(L, en); Result:= 3; end; end; function luaGetEnvironmentVariable(L : Plua_State) : Integer; cdecl; var AValue: String; begin Result:= 1; AValue:= mbGetEnvironmentVariable(luaL_checkstring(L, 1)); if (Length(AValue) = 0) then lua_pushnil(L) else begin lua_pushstring(L, PAnsiChar(AValue)); end; end; function luaSetEnvironmentVariable(L : Plua_State) : Integer; cdecl; begin Result:= 1; if (mbSetEnvironmentVariable(luaL_checkstring(L, 1),luaL_checkstring(L, 2))) then begin lua_pushinteger(L, 0); end else begin lua_pushinteger(L, -1); end; end; function luaUnsetEnvironmentVariable(L : Plua_State) : Integer; cdecl; begin Result:= 1; if (mbUnsetEnvironmentVariable(luaL_checkstring(L, 1))) then begin lua_pushinteger(L, 0); end else begin lua_pushinteger(L, -1); end; end; function luaExecute(L: Plua_State): Integer; cdecl; begin Result:= 1; lua_pushinteger(L, csystem(luaL_optstring(L, 1, nil))); end; function luaRemove(L: Plua_State): Integer; cdecl; var ok: Boolean; attr: TFileAttrs; filename: PAnsiChar; begin filename := luaL_checkstring(L, 1); attr:= mbFileGetAttr(filename); if (attr = faInvalidAttributes) then ok:= True else if FPS_ISDIR(attr) then ok:= mbRemoveDir(filename) else begin ok:= mbDeleteFile(filename); end; Result:= os_pushresult(L, ok, filename); end; function luaRenameFile(L: Plua_State): Integer; cdecl; var oldname, newname: PAnsiChar; begin oldname := luaL_checkstring(L, 1); newname := luaL_checkstring(L, 2); Result:= os_pushresult(L, mbRenameFile(oldname, newname), oldname); end; function luaTempName(L: Plua_State): Integer; cdecl; begin Result:= 1; lua_pushstring(L, PAnsiChar(GetTempName(EmptyStr))); end; function luaL_testudata (L: Plua_State; ud: cint; tname: PAnsiChar): Pointer; begin Result := lua_touserdata(L, ud); if (Result <> nil) then begin //* value is a userdata? */ if (lua_getmetatable(L, ud)) then begin //* does it have a metatable? */ luaL_getmetatable(L, tname); //* get correct metatable */ if (not lua_rawequal(L, -1, -2)) then //* not the same? */ Result := nil; //* value is a userdata with wrong metatable */ lua_pop(L, 2); //* remove both metatables */ end; end; end; function luaL_fileresult(L: Plua_State; i: Boolean; const filename: PAnsiChar): cint; var en: cint; begin en := cerrno; //* calls to Lua API may change this value */ if (i) then begin lua_pushboolean(L, true); Result:= 1; end else begin lua_pushnil(L); if Assigned(filename) then lua_pushfstring(L, '%s: %s', filename, cstrerror(en)) else lua_pushfstring(L, '%s', cstrerror(en)); lua_pushinteger(L, en); Result:= 3; end; end; function tolstream(L: Pointer): PLStream; inline; begin Result := PLStream(luaL_checkudata(L, 1, LUA_FILEHANDLE)); end; function isclosed(p: PLStream): Boolean; inline; begin Result := (p^.closef = nil); end; function io_type (L: Plua_State): cint; cdecl; var p: PLStream; begin luaL_checkany(L, 1); p := PLStream(luaL_testudata(L, 1, LUA_FILEHANDLE)); if (p = nil) then lua_pushnil(L) //* not a file */ else if (isclosed(p)) then lua_pushliteral(L, 'closed file') else lua_pushliteral(L, 'file'); Result := 1; end; function f_tostring (L: Plua_State): cint; cdecl; var p: PLStream; begin p := tolstream(L); if (isclosed(p)) then lua_pushliteral(L, 'file (closed)') else lua_pushfstring(L, 'file (%p)', p^.f); Result := 1; end; function tofile (L: Plua_State): Pointer; var p: PLStream; begin p := tolstream(L); if (isclosed(p)) then luaL_error(L, 'attempt to use a closed file'); lua_assert(p^.f <> nil); Result := p^.f; end; (* ** When creating file handles, always creates a 'closed' file handle ** before opening the actual file; so, if there is a memory error, the ** handle is in a consistent state. *) function newprefile (L: Plua_State): PLStream; begin Result := PLStream(lua_newuserdata(L, sizeof(luaL_Stream))); // WriteLn('newprefile: ', HexStr(Result)); Result^.closef := nil; //* mark file handle as 'closed' */ luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); end; (* ** Calls the 'close' function from a file handle. *) function aux_close (L: Plua_State): cint; cdecl; var p: PLStream; cf: lua_CFunction; begin p := tolstream(L); cf := p^.closef; p^.closef := nil; //* mark stream as closed */ Result := cf(L); //* close it */ end; function f_close (L: Plua_State): cint; cdecl; begin tofile(L); //* make sure argument is an open stream */ Result := aux_close(L); end; function io_close (L: Plua_State): cint; cdecl; begin if (lua_isnone(L, 1)) then //* no argument? */ lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT_); //* use standard output */ Result := f_close(L); end; function f_gc (L: Plua_State): cint; cdecl; var p: PLStream; begin p := tolstream(L); // WriteLn('f_gc: ', hexStr(p)); if (p^.f <> CStdIn) and (p^.f <> CStdOut) and (p^.f <> CStdErr) then begin //* ignore closed and incompletely open files */ if (not isclosed(p)) and (p^.f <> nil) then aux_close(L); end; Result := 0; end; (* ** function to close regular files *) function io_fclose (L: Plua_State): cint; cdecl; var p: PLStream; begin p := tolstream(L); Result := cfclose(p^.f); // p^.closef := nil; Result := luaL_fileresult(L, (Result = 0), nil); end; function newfile (L: Plua_State): PLStream; begin Result := newprefile(L); Result^.f := nil; Result^.closef := @io_fclose; end; procedure opencheck (L: Plua_State; const fname, mode: pansichar); var p: PLStream; begin p := newfile(L); p^.f := cfopen(fname, mode); if (p^.f = nil) then luaL_error(L, 'cannot open file "%s" (%s)', fname, cstrerror(cerrno)); end; function io_open (L: Plua_State): cint; cdecl; var p: PLStream; filename, mode: pansichar; begin filename := luaL_checkstring(L, 1); mode := luaL_optstring(L, 2, 'r'); p := newfile(L); p^.f := cfopen(filename, mode); if (p^.f <> nil) then Result := 1 else begin Result := luaL_fileresult(L, false, filename); end; end; (* ** function to close 'popen' files *) function io_pclose (L: Plua_State): cint; cdecl; var p: PLStream; begin p := tolstream(L); if Assigned(luaL_execresult) then Result := luaL_execresult(L, cpclose(p^.f)) else begin Result := cpclose(p^.f); Result := luaL_fileresult(L, (Result = 0), nil); end; end; function io_popen (L: Plua_State): cint; cdecl; var p: PLStream; filename, mode: pansichar; begin filename := luaL_checkstring(L, 1); mode := luaL_optstring(L, 2, 'r'); p := newprefile(L); p^.f := cpopen(filename, mode); p^.closef := @io_pclose; if (p^.f <> nil) then Result := 1 else begin Result := luaL_fileresult(L, false, filename); end; end; function io_tmpfile (L: Plua_State): cint; cdecl; var p: PLStream; begin p := newfile(L); p^.f := ctmpfile(); if (p^.f <> nil) then Result := 1 else begin Result := luaL_fileresult(L, false, nil); end; end; function getiofile (L: Plua_State; findex: PAnsiChar): Pointer; var p: PLStream; begin lua_getfield(L, LUA_REGISTRYINDEX, findex); p := PLStream(lua_touserdata(L, -1)); if (isclosed(p)) then luaL_error(L, 'standard %s file is closed', findex + Length(IO_PREFIX)); Result := p^.f; end; function g_iofile (L: Plua_State; f, mode: pansichar): cint; cdecl; var filename: PAnsiChar; begin if (not lua_isnoneornil(L, 1)) then begin filename := lua_tocstring(L, 1); if Assigned(filename) then opencheck(L, filename, mode) else begin tofile(L); //* check that it's a valid file handle */ lua_pushvalue(L, 1); end; lua_setfield(L, LUA_REGISTRYINDEX, f); end; //* return current value */ lua_getfield(L, LUA_REGISTRYINDEX, f); Result := 1; end; function io_input (L: Plua_State): cint; cdecl; begin Result := g_iofile(L, IO_INPUT_, 'r'); end; function io_output (L: Plua_State): cint; cdecl; begin Result := g_iofile(L, IO_OUTPUT_, 'w'); end; function io_readline (L: Plua_State): cint; cdecl; forward; procedure aux_lines (L: Plua_State; toclose: boolean); cdecl; var i, n: cint; begin n := lua_gettop(L) - 1; //* number of arguments to read */ //* ensure that arguments will fit here and into 'io_readline' stack */ luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, 'too many options'); lua_pushvalue(L, 1); //* file handle */ lua_pushinteger(L, n); //* number of arguments to read */ lua_pushboolean(L, toclose); //* close/not close file when finished */ for i := 1 to n do lua_pushvalue(L, i + 1); //* copy arguments */ lua_pushcclosure(L, @io_readline, 3 + n); end; function f_lines (L: Plua_State): cint; cdecl; begin tofile(L); //* check that it's a valid file handle */ aux_lines(L, false); Result := 1; end; function io_lines (L: Plua_State): cint; cdecl; var toclose: boolean; filename: PAnsiChar; begin if (lua_isnone(L, 1)) then lua_pushnil(L); //* at least one argument */ if (lua_isnil(L, 1)) then begin //* no file name? */ lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT_); //* get default input */ lua_replace(L, 1); //* put it at index 1 */ tofile(L); //* check that it's a valid file handle */ toclose := false; //* do not close it after iteration */ end else begin //* open a new file */ filename := luaL_checkstring(L, 1); opencheck(L, filename, 'r'); lua_replace(L, 1); //* put file at index 1 */ toclose := true; //* close it after iteration */ end; aux_lines(L, toclose); Result := 1; end; (* ** {====================================================== ** READ ** ======================================================= *) function read_number (L: Plua_State; f: Pointer): cint; cdecl; var d: lua_Number; begin if (cfscanf(f, LUA_NUMBER_SCAN, @d) = 1) then begin lua_pushnumber(L, d); Result := 1; end else begin lua_pushnil(L); //* "result" to be removed */ Result := 0; //* read fails */ end; end; function test_eof (L: Plua_State; f: Pointer): cint; cdecl; var c: cint; begin c := cgetc(f); cungetc(c, f); //* no-op when c == EOF */ lua_pushliteral(L, ''); Result := cint(LongBool(c <> EOF)); end; function read_line (L: Plua_State; f: Pointer; chop: cint): cint; cdecl; var k: csize_t; p: PAnsiChar; b: luaL_Buffer; begin luaL_buffinit(L, @b); while (True) do begin p := luaL_prepbuffer(@b); if (cfgets(p, LUAL_BUFFERSIZE, f) = nil) then //* eof? */ begin luaL_pushresult(@b); //* close buffer */ Exit(cint(lua_objlen(L, -1) > 0)); //* check whether read something */ end; k := strlen(p); if (k = 0) or (p[k - 1] <> #10) then luaL_addsize(@b, k) else begin luaL_addsize(@b, k - chop); //* chop 'eol' if needed */ luaL_pushresult(@b); //* close buffer */ Exit(1); //* read at least an `eol' */ end; end; end; procedure read_all (L: Plua_State; f: Pointer); cdecl; var nr: csize_t; p: PAnsiChar; b: luaL_Buffer; begin luaL_buffinit(L, @b); repeat //* read file in chunks of LUAL_BUFFERSIZE bytes */ p := luaL_prepbuffer(@b); nr := cfread(p, sizeof(AnsiChar), LUAL_BUFFERSIZE, f); luaL_addsize(@b, nr); until (nr <> LUAL_BUFFERSIZE); luaL_pushresult(@b); //* close buffer */ end; function read_chars (L: Plua_State; f: Pointer; n: csize_t): cint; cdecl; var rlen: csize_t; //* how much to read */ nr: csize_t; //* number of chars actually read */ p: PAnsiChar; b: luaL_Buffer; begin luaL_buffinit(L, @b); rlen := LUAL_BUFFERSIZE; //* try to read that much each time */ repeat p := luaL_prepbuffer(@b); if (rlen > n) then rlen := n; //* cannot read more than asked */ nr := cfread(p, sizeof(AnsiChar), rlen, f); luaL_addsize(@b, nr); n -= nr; //* still have to read 'n' chars */ until not ((n > 0) and (nr = rlen)); //* until end of count or eof */ luaL_pushresult(@b); //* close buffer */ Result := cint((n = 0) or (lua_objlen(L, -1) > 0)); end; function g_read (L: Plua_State; f: Pointer; first: cint): cint; cdecl; var k: csize_t; p: PAnsiChar; n, nargs, success: cint; begin nargs := lua_gettop(L) - 1; cclearerr(f); if (nargs = 0) then begin //* no arguments? */ success := read_line(L, f, 1); n := first + 1; //* to return 1 result */ end else begin //* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs + LUA_MINSTACK, 'too many arguments'); success := 1; n := first; while (nargs <> 0) and (success <> 0) do begin if (lua_type(L, n) = LUA_TNUMBER) then begin k := csize_t(luaL_checkinteger(L, n)); if (k = 0) then success := test_eof(L, f) else success := read_chars(L, f, k); end else begin p := luaL_checkstring(L, n); if (p^ = '*') then Inc(p); //* skip optional '*' (for compatibility) */ case (p^) of 'n': //* number */ success := read_number(L, f); 'l': //* line */ success := read_line(L, f, 1); 'L': //* line with end-of-line */ success := read_line(L, f, 0); 'a': //* file */ begin read_all(L, f); //* read entire file */ success := 1; //* always success */ end; else Exit(luaL_argerror(L, n, 'invalid format')); end; end; Inc(n); Dec(nargs); end; end; if (cferror(f) <> 0) then Exit(luaL_fileresult(L, false, nil)); if (success = 0) then begin lua_pop(L, 1); //* remove last result */ lua_pushnil(L); //* push nil instead */ end; Result := n - first; end; function io_read (L: Plua_State): cint; cdecl; begin Result := g_read(L, getiofile(L, IO_INPUT_), 1); end; function f_read (L: Plua_State): cint; cdecl; begin Result := g_read(L, tofile(L), 2); end; function io_readline (L: Plua_State): cint; cdecl; var i, n: cint; p: PLStream; begin p := PLStream(lua_touserdata(L, lua_upvalueindex(1))); n := cint(lua_tointeger(L, lua_upvalueindex(2))); if (isclosed(p)) then //* file is already closed? */ Exit(luaL_error(L, 'file is already closed')); lua_settop(L , 1); luaL_checkstack(L, n, 'too many arguments'); for i := 1 to n do //* push arguments to 'g_read' */ lua_pushvalue(L, lua_upvalueindex(3 + i)); n := g_read(L, p^.f, 2); //* 'n' is number of results */ lua_assert(n > 0); //* should return at least a nil */ if (lua_toboolean(L, -n)) then //* read at least one value? */ Exit(n); //* return them */ //* first result is nil: EOF or error */ if (n > 1) then begin //* is there error information? */ //* 2nd result is error message */ Exit(luaL_error(L, '%s', lua_tocstring(L, -n + 1))); end; if (lua_toboolean(L, lua_upvalueindex(3))) then begin //* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); //* close it */ end; Result := 0; end; //* }====================================================== */ function g_write (L: Plua_State; f: Pointer; arg: cint): cint; cdecl; var k: csize_t; s: PAnsiChar; len, nargs: cint; status: Boolean = True; begin nargs := lua_gettop(L) - arg; while (nargs > 0) do begin if (lua_type(L, arg) = LUA_TNUMBER) then begin //* optimization: could be done exactly as for strings */ if Assigned(lua_isinteger) and lua_isinteger(L, arg) then len := cfprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) else len := cfprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)); status := status and (len > 0); end else begin s := luaL_checklstring(L, arg, @k); status := status and (cfwrite(s, sizeof(AnsiChar), k, f) = k); end; Inc(arg); Dec(nargs); end; if (status) then Result := 1 //* file handle already on stack top */ else Result := luaL_fileresult(L, status, nil); end; function io_write (L: Plua_State): cint; cdecl; begin Result := g_write(L, getiofile(L, IO_OUTPUT_), 1); end; function f_write (L: Plua_State): cint; cdecl; var f: Pointer; begin f := tofile(L); lua_pushvalue(L, 1); //* push file at the stack top (to be returned) */ Result := g_write(L, f, 2); end; function f_seek (L: Plua_State): cint; cdecl; const mode: array[0..2] of cint = (0, 1, 2); modenames: array[0..3] of PAnsiChar = ('set', 'cur', 'end', nil); var op: cint; f: Pointer; offset: clong; begin f := tofile(L); op := luaL_checkoption(L, 2, 'cur', modenames); offset := luaL_optlong(L, 3, 0); op := cfseek(f, offset, mode[op]); if (op <> 0) then Result := luaL_fileresult(L, false, nil) //* error */ else begin lua_pushinteger(L, lua_Integer(cftell(f))); Result := 1; end; end; function f_setvbuf (L: Plua_State): cint; cdecl; const mode: array[0..2] of cint = (_IONBF, _IOFBF, _IOLBF); modenames: array[0..3] of PAnsiChar = ('no', 'full', 'line', nil); var op: cint; f: Pointer; sz: lua_Integer; begin f := tofile(L); op := luaL_checkoption(L, 2, nil, modenames); sz := luaL_optinteger(L, 3, LUAL_BUFFERSIZE); Result := csetvbuf(f, nil, mode[op], csize_t(sz)); Result := luaL_fileresult(L, Result = 0, nil); end; function io_flush (L: Plua_State): cint; cdecl; begin Result := luaL_fileresult(L, cfflush(getiofile(L, IO_OUTPUT_)) = 0, nil); end; function f_flush (L: Plua_State): cint; cdecl; begin Result := luaL_fileresult(L, cfflush(tofile(L)) = 0, nil); end; var io_noclose_: lua_CFunction; (* ** function to (not) close the standard files stdin, stdout, and stderr *) function io_noclose (L: Plua_State): cint; cdecl; var p: PLStream; begin p := tolstream(L); p^.closef := io_noclose_; //* keep file opened */ lua_pushnil(L); lua_pushliteral(L, 'cannot close standard file'); Result := 2; end; procedure createstdfile (L: Plua_State; f: Pointer; k, fname: PAnsiChar); var p: PLStream; begin p := newprefile(L); p^.f := f; p^.closef := @io_noclose; if (k <> nil) then begin lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, k); //* add file to registry */ end; lua_setfield(L, -2, fname); //* add file to module */ end; procedure luaP_register(L : Plua_State; n : PChar; f : lua_CFunction); begin lua_pushcfunction(L, f); lua_setfield(L, -2, n); end; procedure ReplaceLibrary(L : Plua_State); begin //* Replace functions for 'os' library */ lua_getglobal(L, LUA_OSLIBNAME); luaP_register(L, 'remove', @luaRemove); luaP_register(L, 'execute', @luaExecute); luaP_register(L, 'tmpname', @luaTempName); luaP_register(L, 'rename', @luaRenameFile); luaP_register(L, 'getenv', @luaGetEnvironmentVariable); luaP_register(L, 'setenv', @luaSetEnvironmentVariable); luaP_register(L, 'unsetenv', @luaUnsetEnvironmentVariable); lua_pop(L, 1); io_noclose_:= @io_noclose; //* Replace functions for 'io' library */ lua_getglobal(L, LUA_IOLIBNAME); luaP_register(L, 'close', @io_close); luaP_register(L, 'flush', @io_flush); luaP_register(L, 'input', @io_input); luaP_register(L, 'lines', @io_lines); luaP_register(L, 'open', @io_open); luaP_register(L, 'output', @io_output); luaP_register(L, 'popen', @io_popen); luaP_register(L, 'read', @io_read); luaP_register(L, 'tmpfile', @io_tmpfile); luaP_register(L, 'type', @io_type); luaP_register(L, 'write', @io_write); lua_pop(L, 1); //* Create metatable for file handles */ luaL_newmetatable(L, LUA_FILEHANDLE); lua_pushvalue(L, -1); //* push metatable */ lua_setfield(L, -2, '__index'); //* metatable.__index = metatable */ //* add file methods to new metatable */ luaP_register(L, 'close', @f_close); luaP_register(L, 'flush', @f_flush); luaP_register(L, 'lines', @f_lines); luaP_register(L, 'read', @f_read); luaP_register(L, 'seek', @f_seek); luaP_register(L, 'setvbuf', @f_setvbuf); luaP_register(L, 'write', @f_write); luaP_register(L, '__gc', @f_gc); luaP_register(L, '__tostring', @f_tostring); lua_pop(L, 1); //* pop new metatable */ //* get and set default files */ lua_getglobal(L, LUA_IOLIBNAME); lua_getfield(L, -1, 'stdin'); CStdIn := PPointer(lua_touserdata(L, -1))^; lua_pop(L, 1); lua_getfield(L, -1, 'stdout'); CStdOut := PPointer(lua_touserdata(L, -1))^; lua_pop(L, 1); lua_getfield(L, -1, 'stderr'); CStdErr := PPointer(lua_touserdata(L, -1))^; lua_pop(L, 1); createstdfile(L, CStdIn, IO_INPUT_, 'stdin'); createstdfile(L, CStdOut, IO_OUTPUT_, 'stdout'); createstdfile(L, CStdErr, nil, 'stderr'); lua_pop(L, 1); end; end. doublecmd-1.1.22/src/umaincommands.pas0000644000175000001440000056663014743153644016755 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- This unit contains DC actions of the main form Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2008-2023 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uMainCommands; {$mode objfpc}{$H+} interface uses Classes, SysUtils, ActnList, uFileView, uFileViewNotebook, uFileSourceOperation, uGlobs, uFileFunctions, uFormCommands, uFileSorting, uShellContextMenu, Menus, ufavoritetabs,ufile; type TCopyFileNamesToClipboard = (cfntcPathAndFileNames, cfntcJustFileNames, cfntcJustPathWithSeparator, cfntcPathWithoutSeparator); { TProcedureDoingActionOnMultipleTabs } TProcedureDoingActionOnMultipleTabs = procedure(ANotebook: TFileViewNotebook; var bAbort: boolean; bDoLocked: boolean; var iAskForLocked: integer) of object; { TMainCommands } TMainCommands = class(TComponent{$IF FPC_FULLVERSION >= 020501}, IFormCommands{$ENDIF}) private FCommands: TFormCommands; FOriginalNumberOfTabs: integer; FTabsMenu: TPopupMenu; // Helper routines procedure TryGetParentDir(FileView: TFileView; var SelectedFiles: TFiles); // Filters out commands. function CommandsFilter(Command: String): Boolean; procedure OnCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); procedure OnEditCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); procedure OnCalcStatisticsStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); procedure OnCalcChecksumStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); public constructor Create(TheOwner: TComponent; ActionList: TActionList = nil); reintroduce; property Commands: TFormCommands read FCommands{$IF FPC_FULLVERSION >= 020501} implements IFormCommands{$ENDIF}; //--------------------- // The Do... functions are cm_... functions' counterparts which are to be // executed directly from the code with specific - especially non-string // - arguments (instead of calling cm_... functions, in which case // parameters would have to be converted to and from strings). // procedure DoOpenVirtualFileSystemList(Panel: TFileView); procedure DoPanelsSplitterPerPos(SplitPos: Integer); procedure DoUpdateFileView(AFileView: TFileView; {%H-}UserData: Pointer); procedure DoCloseTab(Notebook: TFileViewNotebook; PageIndex: Integer); procedure DoCopySelectedFileNamesToClipboard(FileView: TFileView; TypeOfCopy: TCopyFileNamesToClipboard; const Params: array of string); procedure DoNewTab(Notebook: TFileViewNotebook); procedure DoRenameTab(Page: TFileViewPage); procedure DoTabMenuClick(Sender: TObject); procedure DoContextMenu(Panel: TFileView; X, Y: Integer; Background: Boolean; UserWishForContextMenu:TUserWishForContextMenu = uwcmComplete); procedure DoTransferPath(SourceFrame: TFileView; TargetNotebook: TFileViewNotebook); overload; procedure DoTransferPath(SourcePage: TFileViewPage; TargetPage: TFileViewPage; FromActivePanel: Boolean); procedure DoSortByFunctions(View: TFileView; FileFunctions: TFileFunctions); procedure DoShowMainMenu(bShow: Boolean); procedure DoShowCmdLineHistory(bNextCmdLine: Boolean); procedure DoChangeDirToRoot(FileView: TFileView); procedure GetAndSetMultitabsActionFromParams(const Params: array of string; var APanelSide:TTabsConfigLocation; var ActionOnLocked:boolean; var AskForLocked:integer); procedure DoActionOnMultipleTabs(const Params: array of string; ProcedureDoingActionOnMultipleTabs: TProcedureDoingActionOnMultipleTabs); procedure DoCloseAllTabs(ANotebook: TFileViewNotebook; var bAbort: boolean; bDoLocked: boolean; var iAskForLocked: integer); procedure DoCloseDuplicateTabs(ANotebook: TFileViewNotebook; var bAbort: boolean; bDoLocked: boolean; var iAskForLocked: integer); procedure DoSetAllTabsOptionNormal(ANotebook: TFileViewNotebook; var {%H-}bAbort: boolean; {%H-}bDoLocked: boolean; var {%H-}iAskForLocked: integer); procedure DoSetAllTabsOptionPathLocked(ANotebook: TFileViewNotebook; var {%H-}bAbort: boolean; {%H-}bDoLocked: boolean; var {%H-}iAskForLocked: integer); procedure DoAllTabsOptionPathResets(ANotebook: TFileViewNotebook; var {%H-}bAbort: boolean; {%H-}bDoLocked: boolean; var {%H-}iAskForLocked: integer); procedure DoSetAllTabsOptionDirsInNewTab(ANotebook: TFileViewNotebook; var {%H-}bAbort: boolean; {%H-}bDoLocked: boolean; var {%H-}iAskForLocked: integer); procedure DoOnClickMenuJobFavoriteTabs(Sender: TObject); procedure DoCopyAllTabsToOppositeSide(ANotebook: TFileViewNotebook; var {%H-}bAbort: boolean; {%H-}bDoLocked: boolean; var {%H-}iAskForLocked: integer); procedure DoShowFavoriteTabsOptions; procedure DoParseParametersForPossibleTreeViewMenu(const Params: array of string; gDefaultConfigWithCommand, gDefaultConfigWithDoubleClick:boolean; var bUseTreeViewMenu:boolean; var bUsePanel:boolean; var p: TPoint); procedure DoComputeSizeAndPosForWindowInMiddle(var iPosX:integer; var iPosY:integer; var iWidth:integer; var iHeight:integer); procedure DoActualMarkApplyOnAll(const maoaDispatcher: TMarkApplyOnAllDispatcher; const Params: array of string); procedure DoActualMarkUnMark(const Params: array of string; bSelect: boolean); procedure DoActualAddToCommandLine(const Params: array of string; sAddedString:string; bAddSpaceAtTheEnd:boolean); //--------------------- published //-------------------------------------------------------------------------- // All commands can be split into three groups: // 1. Commands intended for the application (cm_VisitHomePage, // cm_About, cm_Exit, ...). // // 2. Commands intended for file views (cm_QuickSearch, cm_EditPath, etc.). // Those commands are simply redirected to the currently active file view by calling: // frmMain.ActiveFrame.ExecuteCommand(CommandName, Param); // If they are supported by the given file view they are executed there. // // If in future there will be a need to pass specific parameters to the // commands, i.e. not string, they should be implemented by creating // an interface for each command, and each file view implementing those // interfaces which commands it supports. // // 3. Commands intended for file sources (cm_Copy, cm_Rename, cm_MakeDir). // The file operations will mostly work only for non-virtual file sources. // //-------------------------------------------------------------------------- // RECIPE TO ADD A "cm_" COMMAND: //-------------------------------------------------------------------------- // In this recipe, we use as an exemple the command "cm_SrcOpenDrives" // 1. In "fMain" we add the action in the "actionLst". // 2. Make sure we add it in the appropriate category. // 3. The action name must start with "act" and have the exact same name as the "cm_" we want to add. // 4. So if we want "cm_SrcOpenDrives", we name the action "actSrcOpenDrives". // 5. By the way, "KEEP THE SAME SPELLING EVERYWHERE!". // 6. The order in which the "cm_SrcOpenDrives" will appear, is the same as its position in the "actionLst". // 7. So command is "cm_SrcOpenDrives", so keep writing "cm_SrcOpenDrives" and not "cm_srcopendrives" for example. // 8. The only single place to have lowercases is for the icon name which will be "cm_srcopendrives" but it's the only one case. // 9. Give an appropriate "caption" name for the command, so for our example "Open drive list" // 10. Set the "Tag" to the same number as the other command of the same category. // 11. In the "uMainCommands", for the type "TMainCommands", add the code for the command. // 12. The command name must start with "cm_" and ends with the same name as what we added for the "act". // 13. So with our example we add "cm_SrcOpenDrives". // 14. Create an icon for the command. // 15. Make a 24-bits with alpha .PNG file. // 16. Name the file with he same name of the "cm_" command. // 17. But write the name all in lower case so here "cm_srcopendrives". // 18. Store the file here: to path "pixmaps\dctheme\32x32\actions\". // 19. If command is a compatible on with TC, add it in unit "uTotalCommander". // 20. So with this example we add: "(TCCommand: 'cm_SrcOpenDrives'; TCIcon: -1; DCCommand: 'cm_SrcOpenDrives')". // 21. If command needs to have a shortcut, go in unit "uGlobs", go to routine "LoadDefaultHotkeyBindings"(more detailed - read instructions in head of "LoadDefaultHotkeyBindings") and add the appropriate "AddIfNotExists". // 22. Don't abuse on adding keyboard shortcut! We must let some user's keys for user! // 23. For this example, we won't add a keyboard shortcut. TC does'nt have neither. // 24. Edit the file "doc\en\cmds.html" to add help for the command. // 25. For the languages we know, translate the caption of the action added. // 26. For example in our example, it will be "tfrmmain.actsrcopendrives.caption" that will need to be change. // 27. It's important to * T E S T * the "cm_" command you add. // 28. Add a single button in the toolbar to test it works. // 29. Make sure we see the expected icon and the expected tooltip. // 30. Make sure the actual button you added do the expected task. // 31. If command is using parameters, make sure you test the most cases of parameters. // 32. If you added keyboard shortcut, make sure keyboard shortcut works. // 33. With the "cm_DoAnyCmCommand", go find in the "Internal Command Selector" the command you added. // 34. Make sure it's present there, under the appropriate category, sorted at the classic logical place. // 35. Make sure we see the shortcut if any and that the description is correct. // 36. Test the help for the command from there to make sure it links to the correct place in the help file. procedure cm_AddPathToCmdLine(const {%H-}Params: array of string); procedure cm_AddFilenameToCmdLine(const {%H-}Params: array of string); procedure cm_AddPathAndFilenameToCmdLine(const {%H-}Params: array of string); procedure cm_CmdLineNext(const {%H-}Params: array of string); procedure cm_CmdLinePrev(const {%H-}Params: array of string); procedure cm_ContextMenu(const Params: array of string); procedure cm_CopyFullNamesToClip(const {%H-}Params: array of string); procedure cm_CopyFileDetailsToClip(const {%H-}Params: array of string); procedure cm_SaveFileDetailsToFile(const {%H-}Params: array of string); procedure cm_Exchange(const {%H-}Params: array of string); procedure cm_FlatView(const {%H-}Params: array of string); procedure cm_FlatViewSel(const {%H-}Params: array of string); procedure cm_LeftFlatView(const {%H-}Params: array of string); procedure cm_RightFlatView(const {%H-}Params: array of string); procedure cm_OpenArchive(const {%H-}Params: array of string); procedure cm_TestArchive(const {%H-}Params: array of string); procedure cm_OpenDirInNewTab(const {%H-}Params: array of string); procedure cm_Open(const {%H-}Params: array of string); procedure cm_ShellExecute(const Params: array of string); procedure cm_OpenVirtualFileSystemList(const {%H-}Params: array of string); procedure cm_TargetEqualSource(const {%H-}Params: array of string); procedure cm_LeftEqualRight(const {%H-}Params: array of string); procedure cm_RightEqualLeft(const {%H-}Params: array of string); procedure cm_PackFiles(const Params: array of string); procedure cm_ExtractFiles(const Params: array of string); procedure cm_QuickSearch(const Params: array of string); procedure cm_QuickFilter(const Params: array of string); procedure cm_SrcOpenDrives(const {%H-}Params: array of string); procedure cm_LeftOpenDrives(const {%H-}Params: array of string); procedure cm_RightOpenDrives(const {%H-}Params: array of string); procedure cm_OpenBar(const {%H-}Params: array of string); procedure cm_ShowButtonMenu(const Params: array of string); procedure cm_TransferLeft(const {%H-}Params: array of string); procedure cm_TransferRight(const {%H-}Params: array of string); procedure cm_GoToFirstEntry(const {%H-}Params: array of string); procedure cm_GoToLastEntry(const {%H-}Params: array of string); procedure cm_GoToFirstFile(const {%H-}Params: array of string); procedure cm_GoToNextEntry(const {%H-}Params: array of string); procedure cm_GoToPrevEntry(const {%H-}Params: array of string); procedure cm_GoToLastFile(const {%H-}Params: array of string); procedure cm_Minimize(const {%H-}Params: array of string); procedure cm_Wipe(const {%H-}Params: array of string); procedure cm_Exit(const {%H-}Params: array of string); procedure cm_NewTab(const {%H-}Params: array of string); procedure cm_RenameTab(const {%H-}Params: array of string); procedure cm_CloseTab(const {%H-}Params: array of string); procedure cm_CloseAllTabs(const Params: array of string); procedure cm_CloseDuplicateTabs(const Params: array of string); procedure cm_NextTab(const Params: array of string); procedure cm_PrevTab(const Params: array of string); procedure cm_MoveTabLeft(const Params: array of string); procedure cm_MoveTabRight(const Params: array of string); procedure cm_ShowTabsList(const Params: array of string); procedure cm_ActivateTabByIndex(const Params: array of string); procedure cm_SaveTabs(const Params: array of string); procedure cm_LoadTabs(const Params: array of string); procedure cm_SetTabOptionNormal(const Params: array of string); procedure cm_SetTabOptionPathLocked(const Params: array of string); procedure cm_SetTabOptionPathResets(const Params: array of string); procedure cm_SetTabOptionDirsInNewTab(const Params: array of string); procedure cm_Copy(const Params: array of string); procedure cm_CopyNoAsk(const Params: array of string); procedure cm_Delete(const Params: array of string); procedure cm_CheckSumCalc(const Params: array of string); procedure cm_CheckSumVerify(const Params: array of string); procedure cm_Edit(const Params: array of string); procedure cm_EditPath(const Params: array of string); procedure cm_MakeDir(const Params: array of string); procedure cm_Rename(const Params: array of string); procedure cm_RenameNoAsk(const Params: array of string); procedure cm_View(const Params: array of string); procedure cm_QuickView(const Params: array of string); procedure cm_BriefView(const Params: array of string); procedure cm_LeftBriefView(const Params: array of string); procedure cm_RightBriefView(const Params: array of string); procedure cm_ColumnsView(const Params: array of string); procedure cm_LeftColumnsView(const Params: array of string); procedure cm_RightColumnsView(const Params: array of string); procedure cm_ThumbnailsView(const Params: array of string); procedure cm_LeftThumbView(const Params: array of string); procedure cm_RightThumbView(const Params: array of string); procedure cm_TreeView(const Params: array of string); procedure cm_CopyNamesToClip(const {%H-}Params: array of string); procedure cm_FocusTreeView(const {%H-}Params: array of string); procedure cm_FocusCmdLine(const {%H-}Params: array of string); procedure cm_FileAssoc(const {%H-}Params: array of string); procedure cm_HelpIndex(const {%H-}Params: array of string); procedure cm_Keyboard(const {%H-}Params: array of string); procedure cm_VisitHomePage(const {%H-}Params: array of string); procedure cm_About(const {%H-}Params: array of string); procedure cm_ShowSysFiles(const {%H-}Params: array of string); procedure cm_SwitchIgnoreList(const Params: array of string); procedure cm_Options(const Params: array of string); procedure cm_CompareContents(const Params: array of string); procedure cm_Refresh(const {%H-}Params: array of string); procedure cm_ShowMainMenu(const Params: array of string); procedure cm_DirHotList(const Params: array of string); procedure cm_ConfigDirHotList(const {%H-}Params: array of string); procedure cm_WorkWithDirectoryHotlist(const Params: array of string); procedure cm_MarkInvert(const Params: array of string); procedure cm_MarkMarkAll(const Params: array of string); procedure cm_MarkUnmarkAll(const Params: array of string); procedure cm_MarkPlus(const Params: array of string); procedure cm_MarkMinus(const Params: array of string); procedure cm_MarkCurrentName(const Params: array of string); procedure cm_UnmarkCurrentName(const Params: array of string); procedure cm_MarkCurrentNameExt(const Params: array of string); procedure cm_UnmarkCurrentNameExt(const Params: array of string); procedure cm_MarkCurrentExtension(const Params: array of string); procedure cm_UnmarkCurrentExtension(const Params: array of string); procedure cm_MarkCurrentPath(const Params: array of string); procedure cm_UnmarkCurrentPath(const Params: array of string); procedure cm_SaveSelection(const Params: array of string); procedure cm_RestoreSelection(const Params: array of string); procedure cm_SaveSelectionToFile(const Params: array of string); procedure cm_LoadSelectionFromFile(const Params: array of string); procedure cm_LoadSelectionFromClip(const Params: array of string); procedure cm_SyncDirs(const Params: array of string); procedure cm_Search(const Params: array of string); procedure cm_HardLink(const Params: array of string); procedure cm_MultiRename(const Params: array of string); procedure cm_ReverseOrder(const Params: array of string); procedure cm_LeftReverseOrder(const Params: array of string); procedure cm_RightReverseOrder(const Params: array of string); procedure cm_UniversalSingleDirectSort(const Params: array of string); procedure cm_SortByName(const Params: array of string); procedure cm_SortByExt(const Params: array of string); procedure cm_SortByDate(const Params: array of string); procedure cm_SortBySize(const Params: array of string); procedure cm_SortByAttr(const Params: array of string); procedure cm_LeftSortByName(const Params: array of string); procedure cm_LeftSortByExt(const Params: array of string); procedure cm_LeftSortByDate(const Params: array of string); procedure cm_LeftSortBySize(const Params: array of string); procedure cm_LeftSortByAttr(const Params: array of string); procedure cm_RightSortByName(const Params: array of string); procedure cm_RightSortByExt(const Params: array of string); procedure cm_RightSortByDate(const Params: array of string); procedure cm_RightSortBySize(const Params: array of string); procedure cm_RightSortByAttr(const Params: array of string); procedure cm_SymLink(const Params: array of string); procedure cm_CopySamePanel(const Params: array of string); procedure cm_DirHistory(const Params: array of string); procedure cm_ViewHistory(const Params: array of string); procedure cm_ViewHistoryPrev(const {%H-}Params: array of string); procedure cm_ViewHistoryNext(const {%H-}Params: array of string); procedure cm_EditNew(const Params: array of string); procedure cm_RenameOnly(const Params: array of string); procedure cm_RunTerm(const Params: array of string); procedure cm_ShowCmdLineHistory(const Params: array of string); procedure cm_ToggleFullscreenConsole(const Params: array of string); procedure cm_CalculateSpace(const Params: array of string); procedure cm_CountDirContent(const Params: array of string); procedure cm_SetFileProperties(const Params: array of string); procedure cm_FileProperties(const Params: array of string); procedure cm_FileLinker(const Params: array of string); procedure cm_FileSpliter(const Params: array of string); procedure cm_PanelsSplitterPerPos(const Params: array of string); procedure cm_EditComment(const Params: array of string); procedure cm_CopyToClipboard(const Params: array of string); procedure cm_CutToClipboard(const Params: array of string); procedure cm_PasteFromClipboard(const Params: array of string); procedure cm_SyncChangeDir(const Params: array of string); procedure cm_ChangeDirToRoot(const Params: array of string); procedure cm_ChangeDirToHome(const Params: array of string); procedure cm_ChangeDirToParent(const Params: array of string); procedure cm_ChangeDir(const Params: array of string); procedure cm_ClearLogWindow(const Params: array of string); procedure cm_ClearLogFile(const Params: array of string); procedure cm_NetworkConnect(const Params: array of string); procedure cm_NetworkDisconnect(const Params: array of string); procedure cm_CopyNetNamesToClip(const Params: array of string); procedure cm_HorizontalFilePanels(const Params: array of string); procedure cm_OperationsViewer(const Params: array of string); procedure cm_CompareDirectories(const Params: array of string); procedure cm_ViewLogFile(const Params: array of string); procedure cm_ConfigToolbars(const Params: array of string); procedure cm_DebugShowCommandParameters(const Params: array of string); procedure cm_CopyPathOfFilesToClip(const Params: array of string); procedure cm_CopyPathNoSepOfFilesToClip(const Params: array of string); procedure cm_DoAnyCmCommand(const Params: array of string); procedure cm_SetAllTabsOptionNormal(const Params: array of string); procedure cm_SetAllTabsOptionPathLocked(const Params: array of string); procedure cm_SetAllTabsOptionPathResets(const Params: array of string); procedure cm_SetAllTabsOptionDirsInNewTab(const Params: array of string); procedure cm_ConfigFolderTabs(const {%H-}Params: array of string); procedure cm_ConfigFavoriteTabs(const {%H-}Params: array of string); procedure cm_LoadFavoriteTabs(const {%H-}Params: array of string); procedure cm_SaveFavoriteTabs(const {%H-}Params: array of string); procedure cm_ReloadFavoriteTabs(const {%H-}Params: array of string); procedure cm_PreviousFavoriteTabs(const {%H-}Params: array of string); procedure cm_NextFavoriteTabs(const {%H-}Params: array of string); procedure cm_ResaveFavoriteTabs(const {%H-}Params: array of string); procedure cm_CopyAllTabsToOpposite(const {%H-}Params: array of string); procedure cm_ConfigTreeViewMenus(const {%H-}Params: array of string); procedure cm_ConfigTreeViewMenusColors(const {%H-}Params: array of string); procedure cm_ConfigSavePos(const {%H-}Params: array of string); procedure cm_ConfigSaveSettings(const {%H-}Params: array of string); procedure cm_AddNewSearch(const Params: array of string); procedure cm_ViewSearches(const {%H-}Params: array of string); procedure cm_DeleteSearches(const {%H-}Params: array of string); procedure cm_ConfigSearches(const {%H-}Params: array of string); procedure cm_ConfigHotKeys(const {%H-}Params: array of string); procedure cm_ExecuteScript(const {%H-}Params: array of string); procedure cm_FocusSwap(const {%H-}Params: array of string); procedure cm_Benchmark(const {%H-}Params: array of string); procedure cm_ConfigArchivers(const {%H-}Params: array of string); procedure cm_ConfigTooltips(const {%H-}Params: array of string); procedure cm_ConfigPlugins(const {%H-}Params: array of string); procedure cm_OpenDriveByIndex(const Params: array of string); procedure cm_AddPlugin(const Params: array of string); procedure cm_LoadList(const Params: array of string); // Internal commands procedure cm_ExecuteToolbarItem(const Params: array of string); end; implementation uses fOptionsPluginsBase, fOptionsPluginsDSX, fOptionsPluginsWCX, fOptionsPluginsWDX, fOptionsPluginsWFX, fOptionsPluginsWLX, uFlatViewFileSource, uFindFiles, Forms, Controls, Dialogs, Clipbrd, strutils, LCLProc, HelpIntfs, DCStringHashListUtf8, dmHelpManager, typinfo, fMain, fPackDlg, fMkDir, DCDateTimeUtils, KASToolBar, KASToolItems, fExtractDlg, fAbout, fOptions, fDiffer, fFindDlg, fSymLink, fHardLink, fMultiRename, fLinker, fSplitter, fDescrEdit, fCheckSumVerify, fCheckSumCalc, fSetFileProperties, uLng, uLog, uShowMsg, uOSForms, uOSUtils, uDCUtils, uBriefFileView, fSelectDuplicates, uShowForm, uShellExecute, uClipboard, uHash, uDisplayFile, uLuaPas, uSysFolders, uFilePanelSelect, uFileSystemFileSource, uQuickViewPanel, Math, fViewer, uOperationsManager, uFileSourceOperationTypes, uWfxPluginFileSource, uFileSystemDeleteOperation, uFileSourceExecuteOperation, uSearchResultFileSource, uFileSourceOperationMessageBoxesUI, uFileSourceCalcChecksumOperation, uFileSourceCalcStatisticsOperation, uFileSource, uFileSourceProperty, uVfsFileSource, uFileSourceUtil, uArchiveFileSourceUtil, uThumbFileView, uTempFileSystemFileSource, uFileProperty, uFileSourceSetFilePropertyOperation, uTrash, uFileSystemCopyOperation, fOptionsFileAssoc, fDeleteDlg, fViewOperations, uVfsModule, uMultiListFileSource, uExceptions, uFileProcs, DCOSUtils, DCStrUtils, DCBasicTypes, uFileSourceCopyOperation, fSyncDirsDlg, uHotDir, DCXmlConfig, dmCommonData, fOptionsFrame, foptionsDirectoryHotlist, fMainCommandsDlg, uConnectionManager, fOptionsFavoriteTabs, fTreeViewMenu, uArchiveFileSource, fOptionsHotKeys, fBenchmark, uAdministrator, uWcxArchiveFileSource, uColumnsFileView ; resourcestring rsFavoriteTabs_SetupNotExist = 'No setup named "%s"'; procedure ReadCopyRenameParams( const Params: array of string; var Confirmation: Boolean; out HasQueueId: Boolean; out QueueIdentifier: TOperationsManagerQueueIdentifier); var Param, sQueueId: String; BoolValue: Boolean; iQueueId: Integer; begin HasQueueId := False; for Param in Params do begin if GetParamBoolValue(Param, 'confirmation', BoolValue) then Confirmation := BoolValue else if GetParamValue(Param, 'queueid', sQueueId) then begin HasQueueId := TryStrToInt(sQueueId, iQueueId); if HasQueueId then QueueIdentifier := iQueueId; end; end; end; { TMainCommands } constructor TMainCommands.Create(TheOwner: TComponent; ActionList: TActionList = nil); begin inherited Create(TheOwner); FCommands := TFormCommands.Create(Self, ActionList); FCommands.FilterFunc := @CommandsFilter; end; function TMainCommands.CommandsFilter(Command: String): Boolean; begin Result := Command = 'cm_ExecuteToolbarItem'; end; //------------------------------------------------------ procedure TMainCommands.TryGetParentDir(FileView: TFileView; var SelectedFiles: TFiles); var activeFile : TFile; tempPath : String; begin activeFile := FileView.CloneActiveFile; if assigned(activeFile) then begin if activeFile.Name = '..' then begin tempPath := activeFile.FullPath; activeFile.Name := ExtractFileName(ExcludeTrailingPathDelimiter(activeFile.Path)); activeFile.Path := ExpandFileName(tempPath); SelectedFiles.Add(activeFile); end else FreeAndNil(activeFile); end; end; procedure TMainCommands.OnCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); var I: Integer; aFile: TFile; aFileList: TStringList; aFileSource: ITempFileSystemFileSource; aCopyOutOperation: TFileSourceCopyOperation; sCmd: string = ''; sParams: string = ''; sStartPath: string = ''; begin if (State = fsosStopped) and (Operation.Result = fsorFinished) then begin aFileList := TStringList.Create; try aCopyOutOperation := Operation as TFileSourceCopyOperation; aFileSource := aCopyOutOperation.TargetFileSource as ITempFileSystemFileSource; ChangeFileListRoot(aFileSource.FileSystemRoot, aCopyOutOperation.SourceFiles); try for I := 0 to aCopyOutOperation.SourceFiles.Count - 1 do begin aFile := aCopyOutOperation.SourceFiles[I]; if not (aFile.IsDirectory or aFile.IsLinkToDirectory) then begin // Try to find 'view' command in internal associations if not gExts.GetExtActionCmd(aFile, 'view', sCmd, sParams, sStartPath) then aFileList.Add(aFile.FullPath) else begin if sStartPath='' then sStartPath:=aCopyOutOperation.SourceFiles.Path; ProcessExtCommandFork(sCmd, sParams, aCopyOutOperation.SourceFiles.Path, aFile); // TODO: // If TempFileSource is used, create a wait thread that will // keep the TempFileSource alive until the command is finished. aCopyOutOperation.SourceFileSource.AddChild(aFileSource); end; end; // if selected end; // for // if aFileList has files then view it if aFileList.Count > 0 then ShowViewerByGlobList(aFileList, aFileSource); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningViewer, rsMsgInvalidCommandLine + ' (' + rsToolViewer + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; finally FreeAndNil(aFileList); end; end; end; procedure TMainCommands.OnEditCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); var WaitData: TEditorWaitData; begin if (State = fsosStopped) and (Operation.Result = fsorFinished) then begin try WaitData := TEditorWaitData.Create(Operation as TFileSourceCopyOperation); try ShowEditorByGlob(WaitData); except WaitData.Free; end; except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningEditor, rsMsgInvalidCommandLine + ' (' + rsToolEditor + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; end; end; procedure TMainCommands.OnCalcStatisticsStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); var CalcStatisticsOperation: TFileSourceCalcStatisticsOperation; CalcStatisticsOperationStatistics: TFileSourceCalcStatisticsOperationStatistics; begin if (State = fsosStopped) and (Operation.Result = fsorFinished) then begin CalcStatisticsOperation := Operation as TFileSourceCalcStatisticsOperation; CalcStatisticsOperationStatistics := CalcStatisticsOperation.RetrieveStatistics; with CalcStatisticsOperationStatistics do begin if Size < 0 then msgOK(Format(rsSpaceMsg, [Files, Directories, '???', '???'])) else begin msgOK(Format(rsSpaceMsg, [Files, Directories, cnvFormatFileSize(Size), IntToStrTS(Size)])); end; end; end; end; procedure TMainCommands.OnCalcChecksumStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); var CalcChecksumOperation: TFileSourceCalcChecksumOperation; begin if (State = fsosStopped) and (Operation.Result = fsorFinished) then begin CalcChecksumOperation := Operation as TFileSourceCalcChecksumOperation; if CalcChecksumOperation.Mode = checksum_verify then ShowVerifyCheckSum(CalcChecksumOperation.Result); end; end; //------------------------------------------------------ procedure TMainCommands.DoCloseTab(Notebook: TFileViewNotebook; PageIndex: Integer); begin with frmMain do begin RemovePage(Notebook, PageIndex); ActiveFrame.SetFocus; end; end; procedure TMainCommands.DoShowCmdLineHistory(bNextCmdLine: Boolean); begin with frmMain do begin if edtCommand.Visible then begin ShowCommandLine(True); if bNextCmdLine then begin if edtCommand.ItemIndex > 0 then edtCommand.ItemIndex := edtCommand.ItemIndex - 1; end else begin if edtCommand.ItemIndex < edtCommand.Items.Count - 1 then edtCommand.ItemIndex := edtCommand.ItemIndex + 1; end; end; end; end; procedure TMainCommands.DoChangeDirToRoot(FileView: TFileView); var Page: TFileViewPage; begin with FileView do begin Page := TFileViewPage(NotebookPage); if Assigned(Page) then begin if Page.LockState = tlsPathResets then ChooseFileSource(FileView, Page.LockPath) else begin CurrentPath := FileSource.GetRootDir(CurrentPath); end; end; end; end; procedure TMainCommands.DoCopySelectedFileNamesToClipboard(FileView: TFileView; TypeOfCopy: TCopyFileNamesToClipboard; const Params : Array of string); var I: Integer; sl: TStringList = nil; SelectedFiles: TFiles = nil; PathToAdd, FileNameToAdd: String; separator : String; begin SelectedFiles := FileView.CloneSelectedOrActiveFiles; if (SelectedFiles.Count = 0) then TryGetParentDir(FileView, SelectedFiles); try if SelectedFiles.Count > 0 then begin sl := TStringList.Create; for I := 0 to SelectedFiles.Count - 1 do begin PathToAdd:=''; FileNameToAdd:=''; //Let's set the "PathToAdd" according to type of copy. case TypeOfCopy of cfntcPathAndFileNames, cfntcJustPathWithSeparator, cfntcPathWithoutSeparator: begin PathToAdd:= SelectedFiles[I].Path; // Workaround for not fully implemented TMultiListFileSource. if (Pos(FileView.CurrentAddress, PathToAdd) <> 1) and (not FileView.FileSource.IsClass(TMultiListFileSource)) then begin PathToAdd := FileView.CurrentAddress + PathToAdd; end; if TypeOfCopy=cfntcPathWithoutSeparator then PathToAdd:=ExcludeTrailingPathDelimiter(PathToAdd); end; end; //Let's set the "FilenameToAdd" according to type of copy. case TypeOfCopy of cfntcPathAndFileNames, cfntcJustFileNames: FileNameToAdd:=SelectedFiles[I].Name; end; if ((GetParamValue(Params, 'separator', separator)) and (separator.length > 0)) then sl.Add(ReplaceDirectorySeparator(PathToAdd + FileNameToAdd, separator[1])) else sl.Add(PathToAdd + FileNameToAdd); end; Clipboard.Clear; // prevent multiple formats in Clipboard (specially synedit) ClipboardSetText(TrimRightLineEnding(sl.Text, sl.TextLineBreakStyle)); end; finally if Assigned(sl) then FreeAndNil(sl); if Assigned(SelectedFiles) then FreeAndNil(SelectedFiles); end; end; procedure TMainCommands.DoNewTab(Notebook: TFileViewNotebook); var NewPage: TFileViewPage; begin NewPage := Notebook.NewPage(Notebook.ActiveView); NewPage.MakeActive; end; procedure TMainCommands.DoRenameTab(Page: TFileViewPage); var sCaption: String; begin sCaption := Page.CurrentTitle; if InputQuery(rsMsgTabRenameCaption, rsMsgTabRenamePrompt, sCaption) then Page.PermanentTitle := sCaption; end; procedure TMainCommands.DoTabMenuClick(Sender: TObject); var MenuItem: TMenuItem absolute Sender; begin TFileViewNotebook(FTabsMenu.PopupComponent).ActivateTabByIndex(MenuItem.Tag); end; procedure TMainCommands.DoOpenVirtualFileSystemList(Panel: TFileView); var FileSource: IFileSource; begin FileSource:= TVfsFileSource.Create(gWFXPlugins); if Assigned(FileSource) then begin Panel.AddFileSource(FileSource, FileSource.GetRootDir); frmMain.ActiveFrame.SetFocus; end; end; procedure TMainCommands.DoPanelsSplitterPerPos(SplitPos: Integer); begin with frmMain do begin if (SplitPos >= 0) and (SplitPos <= 100) then begin // Update splitter position MainSplitterPos:= SplitPos; pnlNotebooksResize(pnlNotebooks); end; end; end; procedure TMainCommands.DoUpdateFileView(AFileView: TFileView; UserData: Pointer); begin AFileView.UpdateView; end; procedure TMainCommands.DoContextMenu(Panel: TFileView; X, Y: Integer; Background: Boolean; UserWishForContextMenu:TUserWishForContextMenu); var Index: Integer; AMenu: TPopupMenu; aFile: TFile = nil; aFiles: TFiles = nil; sPath, sName: String; OperationsTypes: TFileSourceOperationTypes; begin with frmMain do begin if not (fspDirectAccess in Panel.FileSource.Properties) then begin if not Background then begin AMenu:= pmContextMenu; if (fspContextMenu in Panel.FileSource.Properties) then begin aFiles:= Panel.CloneSelectedOrActiveFiles; try Panel.FileSource.QueryContextMenu(aFiles, AMenu); finally FreeAndNil(aFiles); end; end; OperationsTypes:= Panel.FileSource.GetOperationsTypes; mnuContextDelete.Visible:= fsoDelete in OperationsTypes; mnuContextRenameOnly.Visible:= fsoSetFileProperty in OperationsTypes; AMenu.PopUp(X, Y); end; Exit; end; if not Panel.HasSelectedFiles then begin aFile:= Panel.CloneActiveFile; if not Assigned(aFile) then Background:= True else begin sName:= aFile.Name; FreeAndNil(aFile); end; end; if (Background = True) or (sName = '..') then begin sName:= ExcludeTrailingPathDelimiter(Panel.CurrentPath); sPath:= ExtractFilePath(sName); aFiles:= TFiles.Create(sPath); aFile:= Panel.FileSource.CreateFileObject(sPath); aFile.Attributes:= faFolder; aFile.Name:= ExtractFileName(sName); aFiles.Add(aFile); end else begin aFiles:= Panel.CloneSelectedOrActiveFiles; end; if Assigned(aFiles) then try if aFiles.Count > 0 then try if fspLinksToLocalFiles in Panel.FileSource.Properties then begin for Index:= 0 to aFiles.Count - 1 do begin aFile:= aFiles[Index]; Panel.FileSource.GetLocalName(aFile); end; end; ShowContextMenu(frmMain, aFiles, X, Y, Background, nil, UserWishForContextMenu); except on e: EContextMenuException do ShowException(e); end; finally if Assigned(aFiles) then FreeAndNil(aFiles); end; end; end; procedure TMainCommands.DoTransferPath(SourceFrame: TFileView; TargetNotebook: TFileViewNotebook); begin if TargetNotebook.ActivePage.LockState = tlsPathLocked then Exit; if TargetNotebook.ActivePage.LockState = tlsDirsInNewTab then begin TargetNotebook.NewPage(SourceFrame).MakeActive; TargetNotebook.ActivePage.LockState := tlsNormal; end else begin TargetNotebook.ActivePage.FileView := nil; SourceFrame.Clone(TargetNotebook.ActivePage); end; end; procedure TMainCommands.DoTransferPath(SourcePage: TFileViewPage; TargetPage: TFileViewPage; FromActivePanel: Boolean); var aFile: TFile; NewPath: String; begin if FromActivePanel then begin aFile := SourcePage.FileView.CloneActiveFile; if Assigned(aFile) then try if (fspLinksToLocalFiles in SourcePage.FileView.FileSource.GetProperties) and (SourcePage.FileView.FileSource.GetLocalName(aFile)) then begin if aFile.IsDirectory then ChooseFileSource(TargetPage.FileView, aFile.FullPath) else if not ChooseFileSource(TargetPage.FileView, TargetPage.FileView.FileSource, aFile) then begin ChooseFileSource(TargetPage.FileView, aFile.Path); TargetPage.FileView.SetActiveFile(aFile.Name); end; end else if aFile.IsDirectory then begin if aFile.Name = '..' then begin NewPath := GetParentDir(SourcePage.FileView.CurrentPath); end else begin // Change to a subdirectory. NewPath := aFile.FullPath; end; if NewPath <> EmptyStr then TargetPage.FileView.AddFileSource(SourcePage.FileView.FileSource, NewPath); end else begin // Change file source, if the file under cursor can be opened as another file source. try if not ChooseFileSource(TargetPage.FileView, SourcePage.FileView.FileSource, aFile) then begin if SourcePage.FileView.FileSource.IsClass(TArchiveFileSource) then begin NewPath:= ExtractFilePath(SourcePage.FileView.FileSource.CurrentAddress); if not mbCompareFileNames(TargetPage.FileView.CurrentPath, NewPath) then begin TargetPage.FileView.AddHistory(TFileSystemFileSource.GetFileSource, NewPath); end; end; TargetPage.FileView.AddFileSource(SourcePage.FileView.FileSource, aFile.Path); end; TargetPage.FileView.SetActiveFile(aFile.Name); except on e: EFileSourceException do MessageDlg('Error', e.Message, mtError, [mbOK], 0); end; end; finally FreeAndNil(aFile); end; end else begin TargetPage.FileView.AddFileSource(SourcePage.FileView.FileSource, SourcePage.FileView.CurrentPath); end; end; procedure TMainCommands.DoSortByFunctions(View: TFileView; FileFunctions: TFileFunctions); var NewSorting: TFileSortings = nil; CurrentSorting: TFileSortings; SortDirection: TSortDirection = sdNone; i: Integer; begin if Length(FileFunctions) = 0 then Exit; CurrentSorting := View.Sorting; // Check if there is already sorting by one of the functions. // If it is then reverse direction of sorting. for i := 0 to Length(FileFunctions) - 1 do begin SortDirection := GetSortDirection(CurrentSorting, FileFunctions[i]); if SortDirection <> sdNone then begin SortDirection := ReverseSortDirection(SortDirection); Break; end; end; //If there is no direction currently, sort "sdDescending" for size and date if SortDirection = sdNone then begin case FileFunctions[0] of fsfSize, fsfModificationTime, fsfCreationTime, fsfLastAccessTime: SortDirection:=sdDescending; else SortDirection:=sdAscending; end; end; SetLength(NewSorting, 1); SetLength(NewSorting[0].SortFunctions, 1); NewSorting[0].SortFunctions[0] := FileFunctions[0]; // Sort by single function. NewSorting[0].SortDirection := SortDirection; View.Sorting := NewSorting; end; procedure TMainCommands.DoShowMainMenu(bShow: Boolean); begin gMainMenu := bShow; with frmMain do begin if bShow then begin Menu := mnuMain; end else if Assigned(Menu) then begin Menu := nil; {$IFDEF MSWINDOWS} // Workaround: on Windows need to recreate window to properly recalculate children sizes. RecreateWnd(frmMain); {$ENDIF} end; end; end; //------------------------------------------------------ //Published methods //------------------------------------------------------ { TMainCommands.DoActualAddToCommandLine } procedure TMainCommands.DoActualAddToCommandLine(const Params: array of string; sAddedString:string; bAddSpaceAtTheEnd:boolean); type tQuoteMode = (tqmSmartQuote,tqmForceQuote,tqmNeverQuote); var OldPosition: Integer; sParamValue: String; QuoteMode: tQuoteMode = tqmSmartQuote; DefaultButton: TMyMsgButton; Answer: TMyMsgResult; begin if Length(Params)>0 then begin if GetParamValue(Params[0], 'mode', sParamValue) then begin if sParamValue='smartquote' then QuoteMode:=tqmSmartQuote else if sParamValue='forcequote' then QuoteMode:=tqmForceQuote else if sParamValue='neverquote' then QuoteMode:=tqmNeverQuote else if sParamValue='prompt' then begin if sAddedString = QuoteFilenameIfNecessary(sAddedString) then DefaultButton:=msmbNo else DefaultButton:=msmbYes; Answer:=MsgBox(rsMsgAskQuoteOrNot,[msmbYes, msmbNo], DefaultButton, DefaultButton); case Answer of mmrYes:QuoteMode:=tqmForceQuote; mmrNo:QuoteMode:=tqmNeverQuote; end; end; end; end; case QuoteMode of tqmSmartQuote : sAddedString := QuoteFilenameIfNecessary(sAddedString); tqmForceQuote : sAddedString := QuoteStr(sAddedString); tqmNeverQuote : sAddedString := sAddedString; else sAddedString := QuoteFilenameIfNecessary(sAddedString); end; if bAddSpaceAtTheEnd then sAddedString:=sAddedString+' '; OldPosition := frmMain.edtCommand.SelStart; frmMain.edtCommand.Text := frmMain.edtCommand.Text + sAddedString; frmMain.edtCommand.SelStart := OldPosition + Length(sAddedString); frmMain.ShowCommandLine(False); end; { TMainCommands.cm_AddPathToCmdLine } procedure TMainCommands.cm_AddPathToCmdLine(const Params: array of string); begin DoActualAddToCommandLine(Params, frmMain.ActiveFrame.CurrentPath, False); end; { TMainCommands.cm_AddFilenameToCmdLine } procedure TMainCommands.cm_AddFilenameToCmdLine(const Params: array of string); var aFile: TFile; begin aFile := frmMain.ActiveFrame.CloneActiveFile; if Assigned(aFile) then try DoActualAddToCommandLine(Params, aFile.Name, True); finally FreeAndNil(aFile); end; end; { TMainCommands.cm_AddPathAndFilenameToCmdLine } procedure TMainCommands.cm_AddPathAndFilenameToCmdLine(const Params: array of string); var aFile: TFile; begin aFile := frmMain.ActiveFrame.CloneActiveFile; if Assigned(aFile) then try if aFile.Name = '..' then DoActualAddToCommandLine(Params, frmMain.ActiveFrame.CurrentPath, True) else DoActualAddToCommandLine(Params, aFile.FullPath, True); finally FreeAndNil(aFile); end; end; procedure TMainCommands.cm_ContextMenu(const Params: array of string); begin // Let file view handle displaying context menu at appropriate position. frmMain.ActiveFrame.ExecuteCommand('cm_ContextMenu', Params); end; procedure TMainCommands.cm_SaveFileDetailsToFile(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_SaveFileDetailsToFile', []); end; procedure TMainCommands.cm_CopyFullNamesToClip(const Params: array of string); begin DoCopySelectedFileNamesToClipboard(frmMain.ActiveFrame, cfntcPathAndFileNames, Params); end; procedure TMainCommands.cm_CopyFileDetailsToClip(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_CopyFileDetailsToClip', []); end; procedure TMainCommands.cm_CopyNamesToClip(const Params: array of string); begin DoCopySelectedFileNamesToClipboard(frmMain.ActiveFrame, cfntcJustFileNames, Params); end; procedure TMainCommands.cm_FocusTreeView(const Params: array of string); begin with frmMain do begin if gSeparateTree then begin if ActiveFrame.Focused then ShellTreeView.SetFocus else ActiveFrame.SetFocus; end; end; end; //------------------------------------------------------ procedure TMainCommands.cm_Exchange(const Params: array of string); var AFileView: TFileView; NFileView: TFileView; AFree, NFree: Boolean; begin with frmMain do begin if (ActiveNotebook.ActivePage.LockState = tlsPathLocked) or (NotActiveNotebook.ActivePage.LockState = tlsPathLocked) then Exit; AFileView:= ActiveFrame; NFileView:= NotActiveFrame; if Assigned(QuickViewPanel) then QuickViewClose; AFree:= ActiveNotebook.ActivePage.LockState <> tlsDirsInNewTab; if AFree then ActiveNotebook.ActivePage.RemoveComponent(AFileView); DoTransferPath(NFileView, ActiveNotebook); NFree:= NotActiveNotebook.ActivePage.LockState <> tlsDirsInNewTab; if NFree then NotActiveNotebook.ActivePage.RemoveComponent(NFileView); DoTransferPath(AFileView, NotActiveNotebook); if AFree then AFileView.Free; if NFree then NFileView.Free; ActiveFrame.SetFocus; UpdateSelectedDrive(NotActiveNotebook); end; end; procedure TMainCommands.cm_ExecuteToolbarItem(const Params: array of string); var ToolItemID, ToolBarID: String; begin if GetParamValue(Params, 'ToolItemID', ToolItemID) then begin if not GetParamValue(Params, 'ToolBarID', ToolBarID) then frmMain.MainToolBar.ClickItem(ToolItemID) else begin if (ToolBarID = 'TfrmOptionsToolbar') then frmMain.MainToolBar.ClickItem(ToolItemID) else if (ToolBarID = 'TfrmOptionsToolbarMiddle') then frmMain.MiddleToolBar.ClickItem(ToolItemID); end; end; end; procedure TMainCommands.cm_FlatView(const Params: array of string); var AFile: TFile; AFileView: TFileView; AValue, Param: String; begin with frmMain do begin AFileView:= ActiveFrame; for Param in Params do begin if GetParamValue(Param, 'side', AValue) then begin if AValue = 'left' then AFileView:= FrameLeft else if AValue = 'right' then AFileView:= FrameRight else if AValue = 'inactive' then AFileView:= NotActiveFrame; end end; if not (fspListFlatView in AFileView.FileSource.GetProperties) then begin msgWarning(rsMsgErrNotSupported); end else begin AFileView.FlatView:= not AFileView.FlatView; if not AFileView.FlatView then begin AFile:= AFileView.CloneActiveFile; if Assigned(AFile) and AFile.IsNameValid then begin if not mbCompareFileNames(AFileView.CurrentPath, AFile.Path) then begin AFileView.CurrentPath:= AFile.Path; AFileView.SetActiveFile(AFile.Name); end; end; AFile.Free; end; AFileView.Reload; end; end; end; procedure TMainCommands.cm_FlatViewSel(const Params: array of string); var AFileList: TFileTree; AFileSource: IFileSource; procedure ScanDir(const Dir: String); var I: Integer; AFile: TFile; AFiles: TFiles; begin AFiles := AFileSource.GetFiles(Dir); try for I := 0 to AFiles.Count - 1 do begin AFile := AFiles[I]; if not AFile.IsDirectory then AFileList.AddSubNode(AFile.Clone) else if AFile.IsNameValid then ScanDir(AFile.FullPath); end; finally AFiles.Free; end; end; var J: Integer; AFile: TFile; AFiles: TFiles; AFileView: TFileView; AFlatView: ISearchResultFileSource; begin AFileView:= frmMain.ActiveFrame; AFileSource:= AFileView.FileSource; if AFileView.FlatView then begin AFileView.FlatView := False; if AFileSource.IsInterface(ISearchResultFileSource) then AFileView.ChangePathToParent(True) else AFileView.Reload; Exit; end; AFileList := TFileTree.Create; AFiles := AFileView.CloneSelectedFiles; for J := 0 to AFiles.Count - 1 do begin AFile := AFiles[J]; if not AFile.IsDirectory then AFileList.AddSubNode(AFile.Clone) else if AFile.IsNameValid then ScanDir(AFile.FullPath); end; AFiles.Free; // Create search result file source. AFlatView := TFlatViewFileSource.Create; AFlatView.AddList(AFileList, AFileSource); AFileView.AddFileSource(AFlatView, AFileView.CurrentPath); AFileView.FlatView := True; end; procedure TMainCommands.cm_LeftFlatView(const Params: array of string); begin cm_FlatView(['side=left']); end; procedure TMainCommands.cm_RightFlatView(const Params: array of string); begin cm_FlatView(['side=right']); end; procedure TMainCommands.cm_OpenDirInNewTab(const Params: array of string); function OpenTab(const aFullPath: string): TFileViewPage; begin Result := FrmMain.ActiveNotebook.NewPage(FrmMain.ActiveFrame); // Workaround for Search Result File Source if Result.FileView.FileSource is TSearchResultFileSource then SetFileSystemPath(Result.FileView, aFullPath) else Result.FileView.CurrentPath := aFullPath; end; function OpenArchive(const aFile: TFile): TFileViewPage; begin Result := FrmMain.ActiveNotebook.NewPage(FrmMain.ActiveFrame); ChooseArchive(Result.FileView, Result.FileView.FileSource, aFile); end; function OpenParent: TFileViewPage; begin Result := FrmMain.ActiveNotebook.NewPage(FrmMain.ActiveFrame); Result.FileView.ChangePathToParent(True); end; var aFile: TFile; NewPage: TFileViewPage; begin aFile := FrmMain.ActiveFrame.CloneActiveFile; if not Assigned(aFile) then NewPage := OpenTab(FrmMain.ActiveFrame.CurrentPath) else try if not aFile.IsNameValid then NewPage := OpenParent else if (aFile.IsDirectory or aFile.IsLinkToDirectory) then NewPage := OpenTab(aFile.FullPath) else if FileIsArchive(aFile.FullPath) then NewPage := OpenArchive(aFile) else begin NewPage := OpenTab(aFile.Path); NewPage.FileView.SetActiveFile(aFile.Name); end; finally FreeAndNil(aFile); end; if tb_open_new_in_foreground in gDirTabOptions then NewPage.MakeActive; end; procedure TMainCommands.cm_TargetEqualSource(const Params: array of string); begin with frmMain do begin DoTransferPath(ActiveFrame, NotActiveNotebook); end; end; procedure TMainCommands.cm_LeftEqualRight(const Params: array of string); begin with frmMain do begin DoTransferPath(FrameRight, LeftTabs); // Destroying active view may have caused losing focus. Restore it if needed. if SelectedPanel = fpLeft then FrameLeft.SetFocus; end; end; procedure TMainCommands.cm_RightEqualLeft(const Params: array of string); begin with frmMain do begin DoTransferPath(FrameLeft, RightTabs); // Destroying active view may have caused losing focus. Restore it if needed. if SelectedPanel = fpRight then FrameRight.SetFocus; end; end; procedure TMainCommands.cm_OpenArchive(const Params: array of string); var aFile: TFile; begin with frmMain.ActiveFrame do begin aFile := CloneActiveFile; if Assigned(aFile) then try if aFile.IsNameValid then begin if aFile.IsDirectory or aFile.IsLinkToDirectory then ChangePathToChild(aFile) else ChooseArchive(frmMain.ActiveFrame, FileSource, aFile, True); end; finally FreeAndNil(aFile); end; end; end; procedure TMainCommands.cm_TestArchive(const Params: array of string); var Param: String; BoolValue: Boolean; SelectedFiles: TFiles; bConfirmation, HasConfirmationParam: Boolean; QueueId: TOperationsManagerQueueIdentifier = FreeOperationsQueueId; begin with frmMain do begin HasConfirmationParam := False; for Param in Params do begin if GetParamBoolValue(Param, 'confirmation', BoolValue) then begin HasConfirmationParam := True; bConfirmation := BoolValue; end; end; if not HasConfirmationParam then begin bConfirmation := focTestArchive in gFileOperationsConfirmations; end; if (bConfirmation = False) or (ShowDeleteDialog(rsMsgTestArchive, ActiveFrame.FileSource, QueueId)) then begin SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try TestArchive(ActiveFrame, SelectedFiles, QueueId); finally FreeAndNil(SelectedFiles); end; end; end; end; procedure TMainCommands.cm_Open(const Params: array of string); begin frmMain.ActiveFrame.OpenActiveFile; end; procedure TMainCommands.cm_ShellExecute(const Params: array of string); var aFile: TFile; begin if Length(Params) > 0 then with frmMain do ShellExecute(PrepareParameter(Params[0])) else with frmMain.ActiveFrame do begin aFile := CloneActiveFile; if Assigned(aFile) then try if aFile.IsNameValid then ShellExecute(aFile.FullPath) else if aFile.Name = '..' then ShellExecute(aFile.Path); finally FreeAndNil(aFile); end; end; end; procedure TMainCommands.cm_OpenVirtualFileSystemList(const Params: array of string); begin DoOpenVirtualFileSystemList(frmMain.ActiveFrame); end; //------------------------------------------------------ (* Pack files in archive by creating a new archive *) procedure TMainCommands.cm_PackFiles(const Params: array of string); var Param: String; TargetPath: String; SelectedFiles: TFiles; TargetFileSource: IFileSource; begin with frmMain do begin Param := GetDefaultParam(Params); if Param = 'PackHere' then begin TargetPath:= ActiveFrame.CurrentPath; TargetFileSource:= ActiveFrame.FileSource; end else begin TargetPath:= NotActiveFrame.CurrentPath; TargetFileSource:= NotActiveFrame.FileSource; end; if not (fspDirectAccess in TargetFileSource.Properties) then msgError(rsMsgErrNotSupported) else begin SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count = 0 then msgWarning(rsMsgNoFilesSelected) else begin ShowPackDlg(frmMain, ActiveFrame.FileSource, nil, // No specific target (create new) SelectedFiles, TargetPath, PathDelim { Copy to root of archive } {NotActiveFrame.FileSource.GetRootString} ); end; finally FreeAndNil(SelectedFiles); end; end; end; end; // This command is needed for extracting whole archive by Alt+F9 (without opening it). procedure TMainCommands.cm_ExtractFiles(const Params: array of string); var Param: String; TargetPath: String; SelectedFiles: TFiles; TargetFileSource: IFileSource; begin with frmMain do begin SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; if Assigned(SelectedFiles) then try if SelectedFiles.Count = 0 then msgWarning(rsMsgNoFilesSelected) else begin Param := GetDefaultParam(Params); if Param = 'ExtractHere' then begin TargetPath:= ActiveFrame.CurrentPath; TargetFileSource:= ActiveFrame.FileSource; end else begin TargetPath:= NotActiveFrame.CurrentPath; TargetFileSource:= NotActiveFrame.FileSource; end; ShowExtractDlg(frmMain, ActiveFrame.FileSource, SelectedFiles, TargetFileSource, TargetPath); end; finally FreeAndNil(SelectedFiles); end; end; end; procedure TMainCommands.cm_QuickSearch(const Params: array of string); begin FrmMain.ActiveFrame.ExecuteCommand('cm_QuickSearch', Params); end; procedure TMainCommands.cm_QuickFilter(const Params: array of string); begin FrmMain.ActiveFrame.ExecuteCommand('cm_QuickFilter', Params); end; procedure TMainCommands.cm_SrcOpenDrives(const Params: array of string); begin frmMain.ShowDrivesList(frmMain.SelectedPanel); end; procedure TMainCommands.cm_LeftOpenDrives(const Params: array of string); begin frmMain.ShowDrivesList(fpLeft); end; procedure TMainCommands.cm_RightOpenDrives(const Params: array of string); begin frmMain.ShowDrivesList(fpRight); end; procedure TMainCommands.cm_OpenBar(const Params: array of string); begin // Deprecated. end; { TMainCommands.DoComputeSizeAndPosForWindowInMiddle } procedure TMainCommands.DoComputeSizeAndPosForWindowInMiddle(var iPosX:integer; var iPosY:integer; var iWidth:integer; var iHeight:integer); var pl,pr: TPoint; begin pl := frmMain.FrameLeft.ClientToScreen(Classes.Point(0,0)); pr := frmMain.FrameRight.ClientToScreen(Classes.Point(0,0)); iWidth := (((pr.x+frmMain.FrameRight.Width)- pl.x) * 68) div 100; iHeight := frmMain.FrameLeft.Height; iPosX := pl.x + (((frmMain.FrameLeft.Width+frmMain.FrameRight.Width) - iWidth) div 2); iPosY := pl.y; end; { TMainCommands.cm_ShowButtonMenu } procedure TMainCommands.cm_ShowButtonMenu(const Params: array of string); var WantedButtonMenu, BoolValue: boolean; bWantedTreeViewButtonMenu : boolean = False; Param : string; iWantedPosX: integer = 0; iWantedPosY: integer = 0; iWantedWidth: integer = 800; iWantedHeight: integer = 600; APointer: Pointer; iTypeDispatcher: integer = 0; maybeKASToolButton: TKASToolButton; maybeKASToolItem: TKASToolItem; begin WantedButtonMenu := gButtonBar; if Length(Params) > 0 then begin for Param in Params do if GetParamBoolValue(Param, 'toolbar', BoolValue) then WantedButtonMenu := BoolValue else if GetParamBoolValue(Param, 'treeview', BoolValue) then bWantedTreeViewButtonMenu := BoolValue else WantedButtonMenu := not WantedButtonMenu; end else begin WantedButtonMenu := not WantedButtonMenu; end; if not bWantedTreeViewButtonMenu then begin if WantedButtonMenu <> gButtonBar then begin gButtonBar := WantedButtonMenu; frmMain.UpdateWindowView; end; end else begin DoComputeSizeAndPosForWindowInMiddle(iWantedPosX, iWantedPosY, iWantedWidth, iWantedHeight); APointer := GetUserChoiceFromKASToolBar(frmMain.MainToolBar, tvmcKASToolBar, iWantedPosX, iWantedPosY, iWantedWidth, iWantedHeight, iTypeDispatcher); if APointer<>nil then begin case iTypeDispatcher of 1: begin maybeKASToolButton := TKASToolButton(APointer); maybeKASToolButton.OnClick(maybeKASToolButton); end; 2: begin maybeKASToolItem := TKASToolItem(APointer); frmMain.MainToolBar.PublicExecuteToolItem(maybeKASToolItem); end; end; end; end; end; procedure TMainCommands.cm_TransferLeft(const Params: array of string); begin DoTransferPath(frmMain.RightTabs.ActivePage, frmMain.LeftTabs.ActivePage, frmMain.SelectedPanel = fpRight); end; procedure TMainCommands.cm_TransferRight(const Params: array of string); begin DoTransferPath(frmMain.LeftTabs.ActivePage, frmMain.RightTabs.ActivePage, frmMain.SelectedPanel = fpLeft); end; procedure TMainCommands.cm_GoToFirstEntry(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_GoToFirstEntry', []); end; procedure TMainCommands.cm_GoToLastEntry(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_GoToLastEntry', []); end; procedure TMainCommands.cm_GoToFirstFile(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_GoToFirstFile', []); end; procedure TMainCommands.cm_GoToNextEntry(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_GoToNextEntry', []); end; procedure TMainCommands.cm_GoToPrevEntry(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_GoToPrevEntry', []); end; procedure TMainCommands.cm_GoToLastFile(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_GoToLastFile', []); end; procedure TMainCommands.cm_Minimize(const Params: array of string); begin FrmMain.MinimizeWindow; end; procedure TMainCommands.cm_Wipe(const Params: array of string); var Message: String; theFilesToWipe: TFiles; Operation: TFileSourceOperation; QueueId: TOperationsManagerQueueIdentifier; begin with frmMain.ActiveFrame do begin if not (fsoWipe in FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; // ------------------------------------------------------ theFilesToWipe := CloneSelectedOrActiveFiles; // free at Thread end by thread if Assigned(theFilesToWipe) then try if theFilesToWipe.Count = 0 then Exit; Message:= frmMain.GetFileDlgStr(rsMsgWipeSel, rsMsgWipeFlDr, theFilesToWipe); if not ShowDeleteDialog(Message, FileSource, QueueId) then Exit; Operation := FileSource.CreateWipeOperation(theFilesToWipe); if Assigned(Operation) then begin // Start operation. OperationsManager.AddOperation(Operation, QueueId, False); end else begin msgWarning(rsMsgNotImplemented); end; finally if Assigned(theFilesToWipe) then FreeAndNil(theFilesToWipe); end; end; end; procedure TMainCommands.cm_Exit(const Params: array of string); begin frmMain.Close; // application.Terminate not save settings. end; procedure TMainCommands.cm_NewTab(const Params: array of string); begin DoNewTab(frmMain.ActiveNotebook); end; procedure TMainCommands.cm_RenameTab(const Params: array of string); begin DoRenameTab(frmMain.ActiveNotebook.ActivePage); end; procedure TMainCommands.cm_CloseTab(const Params: array of string); begin with frmMain do DoCloseTab(ActiveNotebook, ActiveNotebook.PageIndex); end; { TMainCommands.cm_CloseAllTabs } procedure TMainCommands.cm_CloseAllTabs(const Params: array of string); begin with frmMain do begin if (tb_confirm_close_all in gDirTabOptions) then if not msgYesNo(rsMsgCloseAllInActiveTabs) then Exit; DoActionOnMultipleTabs(Params,@DoCloseAllTabs); end; end; { TMainCommands.cm_CloseDuplicateTabs } procedure TMainCommands.cm_CloseDuplicateTabs(const Params: array of string); begin DoActionOnMultipleTabs(Params,@DoCloseDuplicateTabs); end; procedure TMainCommands.cm_NextTab(const Params: array of string); begin frmMain.ActiveNotebook.ActivateNextTab; end; procedure TMainCommands.cm_PrevTab(const Params: array of string); begin frmMain.ActiveNotebook.ActivatePrevTab; end; procedure TMainCommands.cm_MoveTabLeft(const Params: array of string); begin with frmMain.ActiveNotebook.ActivePage do if PageIndex > 0 then PageIndex:= PageIndex - 1; end; procedure TMainCommands.cm_MoveTabRight(const Params: array of string); begin with frmMain.ActiveNotebook.ActivePage do PageIndex:= PageIndex + 1; end; procedure TMainCommands.cm_ShowTabsList(const Params: array of string); var ARect: TRect; Param: String; Index: Integer; AValue: String; APoint: TPoint; MenuItem: TMenuItem; ANotebook: TFileViewNotebook; begin ANotebook:= frmMain.ActiveNotebook; for Param in Params do begin if GetParamValue(Param, 'side', AValue) then begin if AValue = 'left' then ANotebook:= frmMain.LeftTabs else if AValue = 'right' then ANotebook:= frmMain.RightTabs else if AValue = 'inactive' then ANotebook:= frmMain.NotActiveNotebook; end end; if (FTabsMenu = nil) then begin FTabsMenu:= TPopupMenu.Create(Self); end; FTabsMenu.Items.Clear; FTabsMenu.PopupComponent:= ANotebook; for Index:= 0 to ANotebook.PageCount - 1 do begin MenuItem:= TMenuItem.Create(FTabsMenu); MenuItem.Tag:= Index; MenuItem.Caption:= ANotebook.Page[Index].Caption; if (ANotebook.Page[Index].LockState in [tlsPathLocked, tlsPathResets, tlsDirsInNewTab]) and (tb_show_asterisk_for_locked in gDirTabOptions) then begin MenuItem.Caption:= Copy(MenuItem.Caption, 2, MaxInt); end; MenuItem.OnClick:= @DoTabMenuClick; FTabsMenu.Items.Add(MenuItem); end; ARect:= ANotebook.TabRect(ANotebook.PageIndex); APoint:= Classes.Point(ARect.Left, ARect.Bottom); APoint:= ANotebook.ClientToScreen(APoint); FTabsMenu.PopUp(APoint.X, APoint.Y); end; procedure TMainCommands.cm_ActivateTabByIndex(const Params: array of string); var Param: String; Index: Integer; AValue: String; ANotebook: TFileViewNotebook; begin if Length(Params) <> 0 then begin ANotebook:= frmMain.ActiveNotebook; for Param in Params do begin if GetParamValue(Param, 'index', AValue) then begin Index:= StrToIntDef(AValue, 1); end else if GetParamValue(Param, 'side', AValue) then begin if AValue = 'left' then ANotebook:= frmMain.LeftTabs else if AValue = 'right' then ANotebook:= frmMain.RightTabs else if AValue = 'inactive' then ANotebook:= frmMain.NotActiveNotebook; end end; if Index = -1 then ANotebook.ActivateTabByIndex(Index) else ANotebook.ActivateTabByIndex(Index - 1); end; end; { TMainCommands.cm_SaveTabs } // To respect legacy, we can invoke "cm_SaveTabs" with a single parameter and it will be a "DefaultParam", which means without any equal sign, directly the filename. // With the following code, we may have more descriptive parameters like the following: // filename= : The giving parameter will be the output filename to save the tabs. If no "filename=" is specified, we will prompt user. // savedirhistory= : We indicate if we want to save dir history or not. procedure TMainCommands.cm_SaveTabs(const Params: array of string); var Config: TXmlConfig; Param, sValue: string; boolValue: boolean; bSaveDirHistory: boolean; sOutputTabsFilename: string = ''; begin // 1. We setup our default options. bSaveDirHistory := gSaveDirHistory; // 2. Let's parse the parameter to get the wanted ones. The default wanted parameter have been set in the "VAR" section // We need to respect legacy of this command where *before* it was possible to simply and directly have the wanted output filename. // Let's assume that if we have an "=" sign, it's can be a legacy usage but one with actual parameters. if (length(Params)>0) then begin sOutputTabsFilename := GetDefaultParam(Params); if pos('=',sOutputTabsFilename)<>0 then begin sOutputTabsFilename := ''; for Param in Params do begin if GetParamValue(Param, 'filename', sValue) then sOutputTabsFilename := sValue else if GetParamBoolValue(Param, 'savedirhistory', boolValue) then bSaveDirHistory := boolValue; end; end; end; // 3. If no output filename has been specified so far, let's request an output filename. if sOutputTabsFilename='' then begin dmComData.SaveDialog.DefaultExt := 'tab'; dmComData.SaveDialog.Filter := '*.tab|*.tab'; if dmComData.SaveDialog.Execute then sOutputTabsFilename := dmComData.SaveDialog.FileName; end; // 4. If we get here with "sOutputTabsFilename<>''", we know what to save and where to save it. if sOutputTabsFilename<>'' then begin try Config := TXmlConfig.Create(sOutputTabsFilename); try frmMain.SaveTabsXml(Config, 'Tabs/OpenedTabs/', frmMain.LeftTabs, bSaveDirHistory); frmMain.SaveTabsXml(Config, 'Tabs/OpenedTabs/', frmMain.RightTabs, bSaveDirHistory); Config.Save; finally Config.Free; end; except on E: Exception do msgError(E.Message); end; end; end; { TMainCommands.cm_LoadTabs } // To respect legacy, invoking "cm_LoadTabs" with no parameter will attempt to load tabs for both panels and prompt the user for a filename. // Still to respect lefacy, we can invoke "cm_LoadTabs" with a single parameter and it will be a "DefaultParam", which means without any equal sign, directly the filename. // With the following code, we may have more descriptive parameters like the following: // filename = The giving parameter will be the input filename to load the tabs from. If no "filename=" is specified, we will prompt user. // loadleftto = Indicate where to load what was saved for left panel. It could be left to be like before but also now right, active, inactive, both and none. // loadrightto= Indicate where to load what was saved for right panel. It could be right to be like before but also now left, active, inactive, both and none. // keep = This indicates if in the target notebook where tabs will be loaded if we remove first the target present or not. When keep is "false", which is the default, we flush them first. If "keep" is "true", we add the loaded tab to the existing ones. procedure TMainCommands.cm_LoadTabs(const Params: array of string); var originalFilePanel:TFilePanelSelect; sInputTabsFilename: string = ''; param, sValue: string; Config: TXmlConfig; TargetDestinationForLeft : TTabsConfigLocation = tclLeft; TargetDestinationForRight : TTabsConfigLocation = tclRight; DestinationToKeep : TTabsConfigLocation = tclNone; TabsAlreadyDestroyedFlags: TTabsFlagsAlreadyDestroyed = []; function EvaluateSideResult(sParamValue:string; DefaultValue:TTabsConfigLocation):TTabsConfigLocation; begin result:=DefaultValue; if sParamValue='left' then result := tclLeft else if sParamValue='right' then result := tclRight else if sParamValue='active' then result := tclActive else if sParamValue='inactive' then result := tclInactive else if sParamValue='both' then result := tclBoth else if sParamValue='none' then result := tclNone; end; begin // 1. Note that most variable have been set with their default value in declaration. originalFilePanel := frmMain.SelectedPanel; // 2. Let's parse the parameter to get the wanted ones // We need to respect legacy of this command where *before* it was possible to simply and directly have the wanted input filename. // Let's assume that if we have an "=" sign, it's can't be a legacy usage but one with actual parameters. if (length(Params)>0) then begin sInputTabsFilename:=GetDefaultParam(Params); if pos('=',sInputTabsFilename)<>0 then begin sInputTabsFilename:=''; for Param in Params do begin if GetParamValue(Param, 'filename', sValue) then sInputTabsFilename := sValue else if GetParamValue(Param, 'loadleftto', sValue) then TargetDestinationForLeft:=EvaluateSideResult(sValue,TargetDestinationForLeft) else if GetParamValue(Param, 'loadrightto', sValue) then TargetDestinationForRight:=EvaluateSideResult(sValue,TargetDestinationForRight) else if GetParamValue(Param, 'keep', sValue) then DestinationToKeep:=EvaluateSideResult(sValue,DestinationToKeep); end; end; end; // 3. If variable "sInputTabsFilename", we''ll request the user to provide an input filename. if sInputTabsFilename='' then begin dmComData.OpenDialog.Filter:= '*.tab|*.tab'; dmComData.OpenDialog.FileName:= GetDefaultParam(Params); if dmComData.OpenDialog.Execute then sInputTabsFilename:=dmComData.OpenDialog.FileName; end; // 4. If we get here with "sInputTabsFilename<>''", we know what to load and from what to load it! if sInputTabsFilename<>'' then begin gFavoriteTabsList.SaveCurrentFavoriteTabsIfAnyPriorToChange; try Config := TXmlConfig.Create(sInputTabsFilename, True); try frmMain.LoadTheseTabsWithThisConfig(Config, 'Tabs/OpenedTabs/', tclLeft, TargetDestinationForLeft, DestinationToKeep, TabsAlreadyDestroyedFlags); frmMain.LoadTheseTabsWithThisConfig(Config, 'Tabs/OpenedTabs/', tclRight, TargetDestinationForRight, DestinationToKeep, TabsAlreadyDestroyedFlags); finally Config.Free; end; except on E: Exception do msgError(E.Message); end; end; frmMain.SelectedPanel := originalFilePanel; frmMain.ActiveFrame.SetFocus; end; procedure TMainCommands.cm_SetTabOptionNormal(const Params: array of string); begin with frmMain.ActiveNotebook.ActivePage do LockState := tlsNormal; end; procedure TMainCommands.cm_SetTabOptionPathLocked(const Params: array of string); begin with frmMain.ActiveNotebook.ActivePage do LockState := tlsPathLocked; end; procedure TMainCommands.cm_SetTabOptionPathResets(const Params: array of string); begin with frmMain.ActiveNotebook.ActivePage do LockState := tlsPathResets; end; procedure TMainCommands.cm_SetTabOptionDirsInNewTab(const Params: array of string); begin with frmMain.ActiveNotebook.ActivePage do LockState := tlsDirsInNewTab; end; //------------------------------------------------------ procedure TMainCommands.cm_View(const Params: array of string); var aFile: TFile; i, n: Integer; IsFile: Boolean; sCmd: String = ''; AMode: Integer = 0; sParams: String = ''; Param, AValue: String; sl: TStringList = nil; AllFiles: TFiles = nil; sStartPath: String = ''; ActiveFile: TFile = nil; aFileSource: IFileSource; ACursor: Boolean = False; SelectedFiles: TFiles = nil; LinksResolveNeeded: Boolean; begin with frmMain do try ActiveFile := ActiveFrame.CloneActiveFile; if (Length(Params) > 0) then begin if GetParamValue(Params, 'cursor', AValue) then GetBoolValue(AValue, ACursor); end; if not ACursor then SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles else begin SelectedFiles:= TFiles.Create(ActiveFrame.CurrentPath); if ActiveFile.IsNameValid then SelectedFiles.Add(ActiveFile.Clone); end; if SelectedFiles.Count = 0 then begin msgWarning(rsMsgNoFilesSelected); Exit; end; aFile:= SelectedFiles[0]; IsFile:= not (aFile.IsDirectory or aFile.IsLinkToDirectory); if (SelectedFiles.Count = 1) and (IsFile) and (Length(Params) > 0) then begin for Param in Params do begin if GetParamValue(Param, 'mode', AValue) then begin case LowerCase(AValue) of 'text': AMode:= 1; 'bin': AMode:= 2; 'hex': AMode:= 3; 'dec': AMode:= 6; end; Break; end; end; if (AMode > 0) then begin with TViewerModeData.Create(AMode) do begin if PrepareData(ActiveFrame.FileSource, SelectedFiles, @OnCopyOutStateChanged) = pdrInCallback then begin Exit; end; Free; end; sl := TStringList.Create; sl.Add(aFile.FullPath); ShowViewer(sl, AMode); Exit; end; end; // Default to using the file source directly. aFileSource := ActiveFrame.FileSource; if not (fspDirectAccess in aFileSource.Properties) and not (fspLinksToLocalFiles in aFileSource.Properties) then begin for I := SelectedFiles.Count - 1 downto 0 do begin with SelectedFiles[I] do begin if IsDirectory or IsLinkToDirectory then SelectedFiles.Delete(I); end; end; if (SelectedFiles.Count = 0) then begin msgWarning(rsMsgNoFilesSelected); Exit; end; end; if PrepareData(aFileSource, SelectedFiles, @OnCopyOutStateChanged) <> pdrSynchronous then Exit; try // Try to find 'view' command in internal associations if gExts.GetExtActionCmd(aFile, 'view', sCmd, sParams, sStartPath) then begin ProcessExtCommandFork(sCmd, sParams, ActiveFrame.CurrentPath); Exit; end; sl := TStringList.Create; for I := 0 to SelectedFiles.Count - 1 do begin sl.Add(SelectedFiles[I].FullPath); end; // for // If only one file was selected then add all files in panel to the list. // Works only for directly accessible files and only when using internal viewer. if (sl.Count = 1) and (IsFile) and (not ACursor) and (not gExternalTools[etViewer].Enabled) and ([fspDirectAccess, fspLinksToLocalFiles] * ActiveFrame.FileSource.Properties <> []) then begin AllFiles := ActiveFrame.CloneFiles; LinksResolveNeeded := fspLinksToLocalFiles in ActiveFrame.FileSource.Properties; n := -1; for i := 0 to AllFiles.Count - 1 do begin aFile := AllFiles[i]; if not (aFile.IsDirectory or aFile.IsLinkToDirectory) then begin if aFile.Name = ActiveFile.Name then n := i; if LinksResolveNeeded then ActiveFrame.FileSource.GetLocalName(aFile); if (n <> -1) and (i <> n) then sl.Add(aFile.FullPath); end; end; for i:=0 to n-1 do begin aFile := AllFiles[i]; if not (aFile.IsDirectory or aFile.IsLinkToDirectory) then sl.Add(aFile.FullPath); end; end; // if sl has files then view it if sl.Count > 0 then ShowViewerByGlobList(sl, aFileSource); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningViewer, rsMsgInvalidCommandLine + ' (' + rsToolViewer + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; finally FreeAndNil(sl); FreeAndNil(AllFiles); FreeAndNil(SelectedFiles); FreeAndNil(ActiveFile); end; end; procedure TMainCommands.cm_QuickView(const Params: array of string); var Param: String; begin with frmMain do begin Param := GetDefaultParam(Params); if Assigned(QuickViewPanel) then begin QuickViewClose; end else if (param <> 'Close') then begin QuickViewShow(NotActiveNotebook.ActivePage, ActiveFrame); end; end; end; procedure TMainCommands.cm_BriefView(const Params: array of string); var aFileView: TFileView; begin with frmMain do begin aFileView:= TBriefFileView.Create(ActiveNotebook.ActivePage, ActiveFrame); ActiveNotebook.ActivePage.FileView:= aFileView; ActiveFrame.SetFocus; end; end; procedure TMainCommands.cm_LeftBriefView(const Params: array of string); var aFileView: TFileView; begin with frmMain do begin aFileView:= TBriefFileView.Create(LeftTabs.ActivePage, FrameLeft); LeftTabs.ActivePage.FileView:= aFileView; end; end; procedure TMainCommands.cm_RightBriefView(const Params: array of string); var aFileView: TFileView; begin with frmMain do begin aFileView:= TBriefFileView.Create(RightTabs.ActivePage, FrameRight); RightTabs.ActivePage.FileView:= aFileView; end; end; procedure TMainCommands.cm_ColumnsView(const Params: array of string); var AParam: String; aFileView: TFileView; begin with frmMain do begin GetParamValue(Params, 'columnset', AParam); if (ActiveFrame is TColumnsFileView) then TColumnsFileView(ActiveFrame).SetColumnSet(AParam) else begin aFileView:= TColumnsFileView.Create(ActiveNotebook.ActivePage, ActiveFrame, AParam); ActiveNotebook.ActivePage.FileView:= aFileView; ActiveFrame.SetFocus; end; end; end; procedure TMainCommands.cm_LeftColumnsView(const Params: array of string); var AParam: String; aFileView: TFileView; begin with frmMain do begin GetParamValue(Params, 'columnset', AParam); if (FrameLeft is TColumnsFileView) then TColumnsFileView(FrameLeft).SetColumnSet(AParam) else begin aFileView:= TColumnsFileView.Create(LeftTabs.ActivePage, FrameLeft, AParam); LeftTabs.ActivePage.FileView:= aFileView; end; end; end; procedure TMainCommands.cm_RightColumnsView(const Params: array of string); var AParam: String; aFileView: TFileView; begin with frmMain do begin GetParamValue(Params, 'columnset', AParam); if (FrameRight is TColumnsFileView) then TColumnsFileView(FrameRight).SetColumnSet(AParam) else begin aFileView:= TColumnsFileView.Create(RightTabs.ActivePage, FrameRight, AParam); RightTabs.ActivePage.FileView:= aFileView; end; end; end; procedure ToggleOrNotToOrFromThumbnailsView(WorkingFileView: TFileView; WorkingNotebook: TFileViewNotebook); var aFileView: TFileView; begin if WorkingFileView.ClassType <> TThumbFileView then begin // Save current file view type WorkingNotebook.ActivePage.BackupViewClass := TFileViewClass(WorkingFileView.ClassType); // Save current columns set name if (WorkingFileView is TColumnsFileView) then begin WorkingNotebook.ActivePage.BackupColumnSet:= TColumnsFileView(WorkingFileView).ActiveColm; end; // Create thumbnails view aFileView:= TThumbFileView.Create(WorkingNotebook.ActivePage, WorkingFileView); end else begin // Restore previous file view type if WorkingNotebook.ActivePage.BackupViewClass <> TColumnsFileView then aFileView:= WorkingNotebook.ActivePage.BackupViewClass.Create(WorkingNotebook.ActivePage, WorkingFileView) else aFileView:= TColumnsFileView.Create(WorkingNotebook.ActivePage, WorkingFileView, WorkingNotebook.ActivePage.BackupColumnSet); end; WorkingNotebook.ActivePage.FileView:= aFileView; end; procedure TMainCommands.cm_ThumbnailsView(const Params: array of string); begin case frmMain.SelectedPanel of fpLeft: ToggleOrNotToOrFromThumbnailsView(frmMain.FrameLeft, frmMain.LeftTabs); fpRight: ToggleOrNotToOrFromThumbnailsView(frmMain.FrameRight, frmMain.RightTabs); end; frmMain.ActiveFrame.SetFocus; end; procedure TMainCommands.cm_LeftThumbView(const Params: array of string); begin ToggleOrNotToOrFromThumbnailsView(frmMain.FrameLeft, frmMain.LeftTabs); frmMain.ActiveFrame.SetFocus; end; procedure TMainCommands.cm_RightThumbView(const Params: array of string); begin ToggleOrNotToOrFromThumbnailsView(frmMain.FrameRight, frmMain.RightTabs); frmMain.ActiveFrame.SetFocus; end; procedure TMainCommands.cm_TreeView(const Params: array of string); begin gSeparateTree := not gSeparateTree; with frmMain do begin DisableAutoSizing; try UpdateShellTreeView; UpdateTreeViewPath; MainSplitterPos:= MainSplitterPos; finally EnableAutoSizing; end; end; end; procedure TMainCommands.cm_Edit(const Params: array of string); var I: Integer; aFile: TFile; sCmd: String = ''; sParams: String = ''; Param, AValue: String; sStartPath: String = ''; ACursor: Boolean = False; SelectedFiles: TFiles = nil; begin with frmMain do try if (Length(Params) > 0) then begin if GetParamValue(Params, 'cursor', AValue) then GetBoolValue(AValue, ACursor); end; if not ACursor then SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles else begin SelectedFiles:= TFiles.Create(ActiveFrame.CurrentPath); aFile:= ActiveFrame.CloneActiveFile; if aFile.IsNameValid then SelectedFiles.Add(aFile) else begin aFile.Free; end; end; for I := SelectedFiles.Count - 1 downto 0 do begin aFile := SelectedFiles[I]; if aFile.IsDirectory or aFile.IsLinkToDirectory then SelectedFiles.Delete(I); end; if SelectedFiles.Count = 0 then begin msgWarning(rsMsgNoFilesSelected); Exit; end; if PrepareData(ActiveFrame.FileSource, SelectedFiles, @OnEditCopyOutStateChanged) <> pdrSynchronous then Exit; try // For now we only process one file. aFile := SelectedFiles[0]; //now test if exists "EDIT" command in "extassoc.xml" :) if gExts.GetExtActionCmd(aFile, 'edit', sCmd, sParams, sStartPath) then ProcessExtCommandFork(sCmd, sParams, aFile.Path) else ShowEditorByGlob(aFile.FullPath); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningEditor, rsMsgInvalidCommandLine + ' (' + rsToolEditor + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; finally FreeAndNil(SelectedFiles); end; end; procedure TMainCommands.cm_EditPath(const Params: array of string); begin if gCurDir then frmMain.ActiveFrame.ExecuteCommand('cm_EditPath', Params); end; // Parameters: // confirmation= // 1/true - show confirmation // 0/false - don't show confirmation // queueid= - by default put to this queue // procedure TMainCommands.cm_Copy(const Params: array of string); var bConfirmation, HasQueueId: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier; begin bConfirmation := focCopy in gFileOperationsConfirmations; ReadCopyRenameParams(Params, bConfirmation, HasQueueId, QueueIdentifier); if HasQueueId then frmMain.CopyFiles(frmMain.NotActiveFrame.CurrentPath, bConfirmation, QueueIdentifier) else frmMain.CopyFiles(frmMain.NotActiveFrame.CurrentPath, bConfirmation); end; procedure TMainCommands.cm_CopyNoAsk(const Params: array of string); begin frmMain.CopyFiles(frmMain.NotActiveFrame.CurrentPath, False); end; // Parameters: // confirmation= // 1/true - show confirmation // 0/false - don't show confirmation // queueid= - by default put to this queue // procedure TMainCommands.cm_Rename(const Params: array of string); var bConfirmation, HasQueueId: Boolean; QueueIdentifier: TOperationsManagerQueueIdentifier; begin bConfirmation := focMove in gFileOperationsConfirmations; ReadCopyRenameParams(Params, bConfirmation, HasQueueId, QueueIdentifier); if HasQueueId then frmMain.MoveFiles(frmMain.NotActiveFrame.CurrentPath, bConfirmation, QueueIdentifier) else frmMain.MoveFiles(frmMain.NotActiveFrame.CurrentPath, bConfirmation); end; procedure TMainCommands.cm_RenameNoAsk(const Params: array of string); begin frmMain.MoveFiles(frmMain.NotActiveFrame.CurrentPath, False); end; procedure TMainCommands.cm_MakeDir(const Params: array of string); var sPath: String; Files: TFiles; Directory: String; ActiveFile: TFile = nil; bMakeViaCopy: Boolean = False; Operation: TFileSourceOperation = nil; UI: TFileSourceOperationMessageBoxesUI = nil; begin with frmMain do try if not (fsoCreateDirectory in ActiveFrame.FileSource.GetOperationsTypes) then begin if (fsoCopyIn in ActiveFrame.FileSource.GetOperationsTypes) then bMakeViaCopy := True else begin msgWarning(rsMsgErrNotSupported); Exit; end; end; ActiveFile := ActiveFrame.CloneActiveFile; if Assigned(ActiveFile) and ActiveFile.IsNameValid then begin if ActiveFile.IsDirectory or ActiveFile.IsLinkToDirectory then sPath := ActiveFile.Name else begin sPath := ActiveFile.NameNoExt; end; end else sPath := EmptyStr; if not ShowMkDir(frmMain, sPath) then Exit; // show makedir dialog if (sPath = EmptyStr) then Exit; if bMakeViaCopy then begin Directory := GetTempName(GetTempFolderDeletableAtTheEnd, EmptyStr); if not mbForceDirectory(IncludeTrailingBackslash(Directory) + sPath) then begin MessageDlg(mbSysErrorMessage(GetLastOSError), mtError, [mbOK], 0); Exit; end; Files := TFiles.Create(Directory); sPath := IncludeTrailingBackslash(Directory) + ExtractWord(1, sPath, [PathDelim]); Files.Add(TFileSystemFileSource.CreateFileFromFile(sPath)); Operation := ActiveFrame.FileSource.CreateCopyInOperation(TFileSystemFileSource.GetFileSource, Files, ActiveFrame.CurrentPath); if Assigned(Operation) then begin OperationsManager.AddOperation(Operation); Operation := nil; end; Exit; end; Operation := ActiveFrame.FileSource.CreateCreateDirectoryOperation(ActiveFrame.CurrentPath, sPath); if Assigned(Operation) then begin // Call directly - not through operations manager. UI := TFileSourceOperationMessageBoxesUI.Create; Operation.AddUserInterface(UI); Operation.Execute; sPath := ExtractFileName(ExcludeTrailingPathDelimiter(sPath)); ActiveFrame.SetActiveFile(sPath); end; finally FreeAndNil(Operation); FreeAndNil(UI); FreeAndNil(ActiveFile); end; end; // Parameters: // trashcan= // 1/true - delete to trash can // 0/false - delete directly // setting - if gUseTrash then delete to trash, otherwise delete directly // reversesetting - if gUseTrash then delete directly, otherwise delete to trash // confirmation= // 1/true - show confirmation // 0/false - don't show confirmation // // Deprecated: // "recycle" - delete to trash can // "norecycle" - delete directly // "recyclesetting" - if gUseTrash then delete to trash, otherwise delete directly // "recyclesettingrev" - if gUseTrash then delete directly, otherwise delete to trash procedure TMainCommands.cm_Delete(const Params: array of string); var I: Integer; Message: String; theFilesToDelete: TFiles; // 12.05.2009 - if delete to trash, then show another messages MsgDelSel, MsgDelFlDr : string; Operation: TFileSourceOperation; bRecycle: Boolean; bConfirmation, HasConfirmationParam: Boolean; Param, ParamTrashCan: String; BoolValue: Boolean; QueueId: TOperationsManagerQueueIdentifier = FreeOperationsQueueId; begin with frmMain.ActiveFrame do begin if not (fsoDelete in FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; bRecycle := gUseTrash; HasConfirmationParam := False; for Param in Params do begin if Param = 'recycle' then bRecycle := True else if Param = 'norecycle' then bRecycle := False else if Param = 'recyclesetting' then bRecycle := gUseTrash else if Param = 'recyclesettingrev' then bRecycle := not gUseTrash else if GetParamValue(Param, 'trashcan', ParamTrashCan) then begin if ParamTrashCan = 'setting' then bRecycle := gUseTrash else if ParamTrashCan = 'reversesetting' then bRecycle := not gUseTrash else if GetBoolValue(ParamTrashCan, BoolValue) then bRecycle := BoolValue; end else if GetParamBoolValue(Param, 'confirmation', BoolValue) then begin HasConfirmationParam := True; bConfirmation := BoolValue; end; end; // Save parameter for later use BoolValue := bRecycle; if bRecycle then bRecycle := FileSource.IsClass(TFileSystemFileSource) and mbCheckTrash(CurrentPath); if not HasConfirmationParam then begin if not bRecycle then bConfirmation := focDelete in gFileOperationsConfirmations else bConfirmation := focDeleteToTrash in gFileOperationsConfirmations; end; // Showing delete dialog: to trash or to /dev/null :) If bRecycle then begin MsgDelSel := rsMsgDelSelT; MsgDelFlDr := rsMsgDelFlDrT; end else begin MsgDelSel := rsMsgDelSel; MsgDelFlDr := rsMsgDelFlDr; end; // Special case for fspLinksToLocalFiles if (fspLinksToLocalFiles in FileSource.Properties) then bRecycle := BoolValue; // ------------------------------------------------------ theFilesToDelete := CloneSelectedOrActiveFiles; // free at Thread end by thread if Assigned(theFilesToDelete) then try if (theFilesToDelete.Count = 0) then Exit; if (theFilesToDelete.Count = 1) then Message:= Format(MsgDelSel, [theFilesToDelete[0].Name]) else begin Message:= Format(MsgDelFlDr, [theFilesToDelete.Count]) + LineEnding; for I:= 0 to Min(4, theFilesToDelete.Count - 1) do begin Message+= LineEnding + theFilesToDelete[I].Name; end; if theFilesToDelete.Count > 5 then Message+= LineEnding + '...'; end; if (bConfirmation = False) or (ShowDeleteDialog(Message, FileSource, QueueId)) then begin if FileSource.IsClass(TFileSystemFileSource) then begin if frmMain.NotActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin for I:= 0 to theFilesToDelete.Count - 1 do begin if (theFilesToDelete[I].IsDirectory or theFilesToDelete[I].IsLinkToDirectory) and IsInPath(theFilesToDelete[I].FullPath, frmMain.NotActiveFrame.CurrentPath, True, True) then begin frmMain.NotActiveFrame.CurrentPath:= theFilesToDelete.Path; Break; end; end; end else if frmMain.NotActiveFrame.FileSource.IsClass(TArchiveFileSource) then begin Message:= (frmMain.NotActiveFrame.FileSource as TArchiveFileSource).ArchiveFileName; for I:= 0 to theFilesToDelete.Count - 1 do begin if IsInPath(theFilesToDelete[I].FullPath, Message, True, True) then begin SetFileSystemPath(frmMain.NotActiveFrame, theFilesToDelete.Path); Break; end; end; end; end; Operation := FileSource.CreateDeleteOperation(theFilesToDelete); if Assigned(Operation) then begin // Special case for filesystem - 'recycle' parameter. if Operation is TFileSystemDeleteOperation then with Operation as TFileSystemDeleteOperation do begin // 30.04.2009 - передаем параметр корзины в поток. Recycle := bRecycle; end; // Start operation. OperationsManager.AddOperation(Operation, QueueId, False); end else begin msgWarning(rsMsgNotImplemented); end; end; finally FreeAndNil(theFilesToDelete); end; end; end; procedure TMainCommands.cm_CheckSumCalc(const Params: array of string); var I: Integer; sFileName: String; SelectedFiles: TFiles; HashAlgorithm: THashAlgorithm; TextLineBreakStyle: TTextLineBreakStyle; QueueId: TOperationsManagerQueueIdentifier; Operation: TFileSourceCalcChecksumOperation; bSeparateFile, bOpenFileAfterJobCompleted: Boolean; begin // This will work only for filesystem. // For other file sources use temp file system when it's done. with frmMain do begin if not (fsoCalcChecksum in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgNotImplemented); Exit; // Create temp file source. // CopyOut ActiveFrame.FileSource to TempFileSource. // Do command on TempFileSource and later delete it (or leave cached on disk?) end; SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count = 0 then begin msgWarning(rsMsgNoFilesSelected); Exit; end; bSeparateFile:= False; bOpenFileAfterJobCompleted:= False; for I := 0 to SelectedFiles.Count - 1 do // find files in selection if not SelectedFiles[I].IsDirectory then begin bSeparateFile:= True; Break; end; if SelectedFiles.Count > 1 then sFileName:= ActiveFrame.CurrentPath + MakeFileName(ActiveFrame.CurrentPath, 'checksum') else sFileName:= ActiveFrame.CurrentPath + SelectedFiles[0].Name; if ShowCalcCheckSum(sFileName, bSeparateFile, HashAlgorithm, bOpenFileAfterJobCompleted, TextLineBreakStyle, QueueId) then begin Operation := ActiveFrame.FileSource.CreateCalcChecksumOperation( SelectedFiles, ActiveFrame.CurrentPath, sFileName) as TFileSourceCalcChecksumOperation; if Assigned(Operation) then begin Operation.Mode := checksum_calc; Operation.OneFile := not bSeparateFile; Operation.TextLineBreakStyle:= TextLineBreakStyle; Operation.OpenFileAfterOperationCompleted := bOpenFileAfterJobCompleted; Operation.Algorithm := HashAlgorithm; // Start operation. OperationsManager.AddOperation(Operation, QueueId, False); end else begin msgWarning(rsMsgNotImplemented); end; end; finally if Assigned(SelectedFiles) then FreeAndNil(SelectedFiles); end; end; end; procedure TMainCommands.cm_CheckSumVerify(const Params: array of string); var I: Integer; Hash: String; Param: String; BoolValue: Boolean; SelectedFiles: TFiles; Algorithm: THashAlgorithm; Operation: TFileSourceCalcChecksumOperation; bConfirmation, HasConfirmationParam: Boolean; QueueId: TOperationsManagerQueueIdentifier = FreeOperationsQueueId; begin // This will work only for filesystem. // For other file sources use temp file system when it's done. with frmMain do begin if not (fsoCalcChecksum in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgNotImplemented); Exit; // Create temp file source. // CopyOut ActiveFrame.FileSource to TempFileSource. // Do command on TempFileSource and later delete it (or leave cached on disk?) end; HasConfirmationParam := False; for Param in Params do begin if GetParamBoolValue(Param, 'confirmation', BoolValue) then begin HasConfirmationParam := True; bConfirmation := BoolValue; end; end; if not HasConfirmationParam then begin bConfirmation := focVerifyChecksum in gFileOperationsConfirmations; end; SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count = 0 then begin msgWarning(rsMsgNoFilesSelected); Exit; end; for I := 0 to SelectedFiles.Count - 1 do // find files in selection if not FileExtIsHash(SelectedFiles[I].Extension) then begin if (SelectedFiles.Count > 1) or (SelectedFiles[I].IsDirectory) or (SelectedFiles[I].IsLinkToDirectory) then begin msgError(rsMsgSelectOnlyCheckSumFiles); Exit; end else begin if not ShowCalcVerifyCheckSum(Hash, Algorithm, QueueId) then Exit; bConfirmation:= False; end; end; if (bConfirmation = False) or (ShowDeleteDialog(rsMsgVerifyChecksum, ActiveFrame.FileSource, QueueId)) then begin Operation := ActiveFrame.FileSource.CreateCalcChecksumOperation( SelectedFiles, Hash, '') as TFileSourceCalcChecksumOperation; if Assigned(Operation) then begin Operation.Algorithm := Algorithm; Operation.AddStateChangedListener([fsosStopped], @OnCalcChecksumStateChanged); Operation.Mode := checksum_verify; // Start operation. OperationsManager.AddOperation(Operation, QueueId, False); end else begin msgWarning(rsMsgNotImplemented); end; end; finally if Assigned(SelectedFiles) then FreeAndNil(SelectedFiles); end; end; end; procedure TMainCommands.cm_FocusCmdLine(const Params: array of string); begin frmMain.ShowCommandLine(True); end; { TMainCommands.cm_FileAssoc } procedure TMainCommands.cm_FileAssoc(const Params: array of string); var Editor: TOptionsEditor; Options: IOptionsDialog; begin Options := ShowOptions(TfrmOptionsFileAssoc); Application.ProcessMessages; Editor := Options.GetEditor(TfrmOptionsFileAssoc); if Editor.CanFocus then Editor.SetFocus; TfrmOptionsFileAssoc(Editor).MakeUsInPositionToWorkWithActiveFile; end; procedure TMainCommands.cm_HelpIndex(const Params: array of string); begin ShowHelpOrErrorForKeyword('', '/index.html'); end; procedure TMainCommands.cm_Keyboard(const Params: array of string); begin ShowHelpOrErrorForKeyword('', '/shortcuts.html'); end; procedure TMainCommands.cm_VisitHomePage(const Params: array of string); var ErrMsg: String = ''; begin dmHelpMgr.HTMLHelpDatabase.ShowURL('https://doublecmd.sourceforge.io','Double Commander Web Site', ErrMsg); end; procedure TMainCommands.cm_About(const Params: array of string); begin ShowAboutBox(frmMain); end; procedure TMainCommands.cm_ShowSysFiles(const Params: array of string); begin with frmMain do begin uGlobs.gShowSystemFiles:= not uGlobs.gShowSystemFiles; actShowSysFiles.Checked:= uGlobs.gShowSystemFiles; UpdateTreeView; // Update all tabs ForEachView(@DoUpdateFileView, nil); end; end; procedure TMainCommands.cm_SwitchIgnoreList(const Params: array of string); {$OPTIMIZATION OFF} var WantedIgnoreList, BoolValue:boolean; begin WantedIgnoreList:=gIgnoreListFileEnabled; with frmMain do begin if Length(Params)>0 then begin if GetParamBoolValue(Params[0], 'ignorelist', BoolValue) then WantedIgnoreList:=BoolValue else WantedIgnoreList := not WantedIgnoreList; end else begin WantedIgnoreList := not WantedIgnoreList; end; if WantedIgnoreList<>gIgnoreListFileEnabled then begin gIgnoreListFileEnabled:=WantedIgnoreList; actSwitchIgnoreList.Checked:= gIgnoreListFileEnabled; //repaint both panels FrameLeft.Reload; FrameRight.Reload; end; end; end; {$OPTIMIZATION DEFAULT} // Parameter is name of TOptionsEditorClass. procedure TMainCommands.cm_Options(const Params: array of string); begin ShowOptions(GetDefaultParam(Params)); end; procedure TMainCommands.cm_CompareContents(const Params: array of string); var FilesNumber: Integer = 0; DirsNumber: Integer = 0; procedure CountFiles(const Files: TFiles); var I: Integer; begin if Assigned(Files) then for I := 0 to Files.Count - 1 do if Files[I].IsDirectory then Inc(DirsNumber) else Inc(FilesNumber); end; var I : Integer; Param: String; ActiveSelectedFiles: TFiles = nil; NotActiveSelectedFiles: TFiles = nil; FirstFileSource: IFileSource = nil; FirstFileSourceFiles: TFiles = nil; SecondFileSource: IFileSource = nil; SecondFileSourceFiles: TFiles = nil; begin with frmMain do begin Param := GetDefaultParam(Params); if Param = 'dir' then begin if gExternalTools[etDiffer].Enabled then ShowDifferByGlob(FrameLeft.CurrentPath, FrameRight.CurrentPath) else MsgWarning(rsMsgNotImplemented); Exit; end; try ActiveSelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; if ActiveSelectedFiles.Count = 1 then begin // If no files selected in the opposite panel and panels have // different path then try to get file with the same name. if (not NotActiveFrame.HasSelectedFiles) and (not mbCompareFileNames(NotActiveFrame.CurrentPath, ActiveFrame.CurrentPath)) then begin for I := 0 to NotActiveFrame.DisplayFiles.Count - 1 do if mbCompareFileNames(NotActiveFrame.DisplayFiles[I].FSFile.Name, ActiveSelectedFiles[0].Name) then begin NotActiveSelectedFiles := TFiles.Create(NotActiveFrame.CurrentPath); NotActiveSelectedFiles.Add(NotActiveFrame.DisplayFiles[I].FSFile.Clone); Break; end; end; if not Assigned(NotActiveSelectedFiles) then NotActiveSelectedFiles := NotActiveFrame.CloneSelectedOrActiveFiles; if NotActiveSelectedFiles.Count <> 1 then begin // Only one file selected in active panel. MsgWarning(rsMsgInvalidSelection); Exit; end; { compare single selected files in both panels } case gResultingFramePositionAfterCompare of rfpacActiveOnLeft: begin FirstFileSource := ActiveFrame.FileSource; FirstFileSourceFiles := ActiveSelectedFiles; SecondFileSource := NotActiveFrame.FileSource; SecondFileSourceFiles := NotActiveSelectedFiles; end; rfpacLeftOnLeft: begin if ActiveFrame = FrameLeft then begin FirstFileSource := ActiveFrame.FileSource; FirstFileSourceFiles := ActiveSelectedFiles; SecondFileSource := NotActiveFrame.FileSource; SecondFileSourceFiles := NotActiveSelectedFiles; end else begin FirstFileSource := NotActiveFrame.FileSource; FirstFileSourceFiles := NotActiveSelectedFiles; SecondFileSource := ActiveFrame.FileSource; SecondFileSourceFiles := ActiveSelectedFiles; end; end; end; end else if ActiveSelectedFiles.Count > 1 then begin { compare all selected files in active frame } FirstFileSource := ActiveFrame.FileSource; FirstFileSourceFiles := ActiveSelectedFiles; end; CountFiles(FirstFileSourceFiles); CountFiles(SecondFileSourceFiles); if ((FilesNumber > 0) and (DirsNumber > 0)) or ((FilesNumber = 1) or (DirsNumber = 1)) then // Either files or directories must be selected and more than one. MsgWarning(rsMsgInvalidSelection) else if (FilesNumber = 0) and (DirsNumber = 0) then MsgWarning(rsMsgNoFilesSelected) else if (FilesNumber > 2) and not gExternalTools[etDiffer].Enabled then MsgWarning(rsMsgTooManyFilesSelected) else if (DirsNumber > 0) and not gExternalTools[etDiffer].Enabled then MsgWarning(rsMsgNotImplemented) else begin if not Assigned(SecondFileSource) then PrepareToolData(FirstFileSource, FirstFileSourceFiles, @ShowDifferByGlobList) else PrepareToolData(FirstFileSource, FirstFileSourceFiles, SecondFileSource, SecondFileSourceFiles, @ShowDifferByGlobList); end; finally ActiveSelectedFiles.Free; NotActiveSelectedFiles.Free; end; end; end; { TMainCommands.cm_ShowMainMenu } procedure TMainCommands.cm_ShowMainMenu(const Params: array of string); {$OPTIMIZATION OFF} var WantedMainMenu, BoolValue: boolean; bWantedTreeViewMenu: boolean = False; Param: string; sMaybeMenuItem: TMenuItem; iWantedPosX: integer = 0; iWantedPosY: integer = 0; iWantedWidth: integer = 800; iWantedHeight: integer = 600; begin WantedMainMenu:=gMainMenu; if Length(Params)>0 then begin for Param in Params do if GetParamBoolValue(Param, 'menu', BoolValue) then WantedMainMenu := BoolValue else if GetParamBoolValue(Param, 'treeview', BoolValue) then bWantedTreeViewMenu := BoolValue else WantedMainMenu := not WantedMainMenu; end else begin WantedMainMenu := not WantedMainMenu; end; if not bWantedTreeViewMenu then begin if WantedMainMenu<>gMainMenu then begin gMainMenu:=WantedMainMenu; DoShowMainMenu(gMainMenu); end; end else begin DoComputeSizeAndPosForWindowInMiddle(iWantedPosX, iWantedPosY, iWantedWidth, iWantedHeight); sMaybeMenuItem := GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(frmMain.mnuMain, tvmcMainMenu, iWantedPosX, iWantedPosY, iWantedWidth, iWantedHeight); if sMaybeMenuItem <> nil then begin if sMaybeMenuItem.Action <> nil then begin if sMaybeMenuItem.Action.OnExecute<>nil then sMaybeMenuItem.Action.OnExecute(sMaybeMenuItem.Action) end else if sMaybeMenuItem.OnClick<>nil then sMaybeMenuItem.OnClick(sMaybeMenuItem); end; end; end; {$OPTIMIZATION DEFAULT} procedure TMainCommands.cm_Refresh(const Params: array of string); begin with frmMain do begin ActiveFrame.FileSource.Reload(ActiveFrame.CurrentPath); ActiveFrame.Reload(True); if ActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin UpdateDiskCount; UpdateSelectedDrives; end; end; end; //------------------------------------------------------ { TMainCommands.DoActualMarkUnMark } procedure TMainCommands.DoActualMarkUnMark(const Params: array of string; bSelect: boolean); var iParameter: integer; sWantedMask, sParamValue: string; sAttribute: string = ''; bWantedCaseSensitive, bWantedIgnoreAccents, bWantedWindowsInterpretation: boolean; pbWantedCaseSensitive, pbWantedIgnoreAccents, pbWantedWindowsInterpretation: PBoolean; psAttribute: pString = nil; MarkSearchTemplateRec: TSearchTemplateRec; MarkFileChecks: TFindFileChecks; begin if frmMain.ActiveFrame is TColumnsFileView then begin if TColumnsFileView(frmMain.ActiveFrame).isSlave then begin ShowSelectDuplicates(frmMain, frmMain.ActiveFrame); Exit; end; end; sWantedMask := ''; pbWantedCaseSensitive := nil; pbWantedIgnoreAccents := nil; pbWantedWindowsInterpretation := nil; for iParameter:=0 to pred(Length(Params)) do begin if GetParamValue(Params[iParameter], 'mask', sParamValue) then sWantedMask := sParamValue else if GetParamBoolValue(Params[iParameter], 'casesensitive', bWantedCaseSensitive) then pbWantedCaseSensitive := @bWantedCaseSensitive else if GetParamBoolValue(Params[iParameter], 'ignoreaccents', bWantedIgnoreAccents) then pbWantedIgnoreAccents := @bWantedIgnoreAccents else if GetParamBoolValue(Params[iParameter], 'windowsinterpretation', bWantedWindowsInterpretation) then pbWantedWindowsInterpretation := @bWantedWindowsInterpretation else if GetParamValue(Params[iParameter], 'attr', sAttribute) then psAttribute := @sAttribute; end; // When mask is specified, we don't prompt the user if sWantedMask<>'' then begin if psAttribute <> nil then MarkSearchTemplateRec.AttributesPattern := psAttribute^ else MarkSearchTemplateRec.AttributesPattern := gMarkDefaultWantedAttribute; AttrsPatternOptionsToChecks(MarkSearchTemplateRec, MarkFileChecks); frmMain.ActiveFrame.MarkGroup(sWantedMask, bSelect, pbWantedCaseSensitive, pbWantedIgnoreAccents, pbWantedWindowsInterpretation, @MarkFileChecks) end else begin frmMain.ActiveFrame.MarkGroup(bSelect, pbWantedCaseSensitive, pbWantedIgnoreAccents, pbWantedWindowsInterpretation, psAttribute) end; end; { TMainCommands.DoActualMarkApplyOnAll } procedure TMainCommands.DoActualMarkApplyOnAll(const maoaDispatcher: TMarkApplyOnAllDispatcher; const Params: array of string); var iParameter: integer; sAttribute, sParam: string; MarkSearchTemplateRec: TSearchTemplateRec; MarkFileChecks: TFindFileChecks; begin sAttribute := gMarkDefaultWantedAttribute; for iParameter:=0 to pred(Length(Params)) do if GetParamValue(Params[iParameter], 'attr', sParam) then sAttribute := sParam; MarkSearchTemplateRec.AttributesPattern := sAttribute; AttrsPatternOptionsToChecks(MarkSearchTemplateRec, MarkFileChecks); frmMain.ActiveFrame.MarkApplyOnAllFiles(maoaDispatcher, MarkFileChecks); end; { TMainCommands.cm_MarkMarkAll } procedure TMainCommands.cm_MarkMarkAll(const Params: array of string); begin DoActualMarkApplyOnAll(tmaoa_Mark, Params); end; { TMainCommands.cm_MarkUnmarkAll } procedure TMainCommands.cm_MarkUnmarkAll(const Params: array of string); begin DoActualMarkApplyOnAll(tmaoa_UnMark, Params); end; { TMainCommands.cm_MarkInvert } procedure TMainCommands.cm_MarkInvert(const Params: array of string); begin DoActualMarkApplyOnAll(tmaoa_InvertMark, Params); end; { TMainCommands.cm_MarkPlus } procedure TMainCommands.cm_MarkPlus(const Params: array of string); begin DoActualMarkUnMark(Params, True); end; { TMainCommands.cm_MarkMinus } procedure TMainCommands.cm_MarkMinus(const Params: array of string); begin DoActualMarkUnMark(Params, False); end; procedure TMainCommands.cm_MarkCurrentName(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentName(True); end; procedure TMainCommands.cm_UnmarkCurrentName(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentName(False); end; procedure TMainCommands.cm_MarkCurrentNameExt(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentNameExt(True); end; procedure TMainCommands.cm_UnmarkCurrentNameExt(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentNameExt(False); end; procedure TMainCommands.cm_MarkCurrentExtension(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentExtension(True); end; procedure TMainCommands.cm_UnmarkCurrentExtension(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentExtension(False); end; procedure TMainCommands.cm_MarkCurrentPath(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentPath(True); end; procedure TMainCommands.cm_UnmarkCurrentPath(const Params: array of string); begin frmMain.ActiveFrame.MarkCurrentPath(False); end; procedure TMainCommands.cm_SaveSelection(const Params: array of string); begin frmMain.ActiveFrame.SaveSelection; end; procedure TMainCommands.cm_RestoreSelection(const Params: array of string); begin frmMain.ActiveFrame.RestoreSelection; end; procedure TMainCommands.cm_SaveSelectionToFile(const Params: array of string); begin frmMain.ActiveFrame.SaveSelectionToFile(GetDefaultParam(Params)); end; procedure TMainCommands.cm_LoadSelectionFromFile(const Params: array of string); begin frmMain.ActiveFrame.LoadSelectionFromFile(GetDefaultParam(Params)); end; procedure TMainCommands.cm_LoadSelectionFromClip(const Params: array of string); begin frmMain.ActiveFrame.LoadSelectionFromClipboard; end; { TMainCommands.DoParseParametersForPossibleTreeViewMenu } procedure TMainCommands.DoParseParametersForPossibleTreeViewMenu(const Params: array of string; gDefaultConfigWithCommand, gDefaultConfigWithDoubleClick:boolean; var bUseTreeViewMenu:boolean; var bUsePanel:boolean; var p: TPoint); var Param, sValue: string; bSpecifiedPopup: boolean = false; bSpecifiedTreeView: boolean = false; bSpecifiedPanel: boolean = false; bSpecifiedMouse: boolean = false; begin for Param in Params do begin if GetParamValue(Param, 'menutype', sValue) then begin if (sValue = 'popup') OR (sValue = 'combobox') then bSpecifiedPopup := True else if sValue = 'treeview' then bSpecifiedTreeView := True; end else if GetParamValue(Param, 'position', sValue) then begin if sValue = 'panel' then bSpecifiedPanel:=true else if sValue = 'cursor' then bSpecifiedMouse:=true; end; end; if (not bSpecifiedPopup) AND (bSpecifiedTreeView OR (not bSpecifiedMouse AND gDefaultConfigWithCommand) OR (bSpecifiedMouse AND gDefaultConfigWithDoubleClick)) then bUseTreeViewMenu:=True; if bSpecifiedPanel OR (not bSpecifiedMouse AND bUsePanel) then begin p := frmMain.ActiveFrame.ClientToScreen(Classes.Point(0, 0)); bUsePanel := True; end else begin p := Mouse.CursorPos; bUsePanel := False; end; end; { TMainCommands.cm_DirHotList } // Command to SHOW the Directory Hotlist popup menu // The directory popup hotlist is run-time continously regenerated each time command is invoken. // If any param is provided, it is assume the popup menu as to be shown where the mouse cursor is which is friendly with user since it minimize mouse travel. // procedure TMainCommands.cm_DirHotList(const Params: array of string); var bUseTreeViewMenu: boolean = false; bUsePanel: boolean = true; p: TPoint = (x:0; y:0); iWantedWidth: integer = 0; iWantedHeight: integer = 0; sMaybeMenuItem: TMenuItem = nil; begin // 1. Let's parse our parameters. DoParseParametersForPossibleTreeViewMenu(Params, gUseTreeViewMenuWithDirectoryHotlistFromMenuCommand, gUseTreeViewMenuWithDirectoryHotlistFromDoubleClick, bUseTreeViewMenu, bUsePanel, p); // 2. No matter what, we need to fill in the popup menu structure. gDirectoryHotlist.PopulateMenuWithHotDir(frmMain.pmHotList,@frmMain.HotDirSelected,@frmMain.miHotAddOrConfigClick,mpHOTDIRSWITHCONFIG,0); // TODO: i thing in future this must call on create or change Application.ProcessMessages; //TODO: Same thing as with "cm_DirHotList", in Windows, Not sure why, but on all system I tried, this eliminate a "beep" when the popup is shown. // 3. Show the appropriate menu. if bUseTreeViewMenu then begin if not bUsePanel then iWantedHeight := 0 else begin iWantedWidth := frmMain.ActiveFrame.Width; iWantedHeight := frmMain.ActiveFrame.Height; end; sMaybeMenuItem := GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(frmMain.pmHotList, tvmcHotDirectory, p.X, p.Y, iWantedWidth, iWantedHeight); if sMaybeMenuItem <> nil then sMaybeMenuItem.OnClick(sMaybeMenuItem); end else begin frmMain.pmHotList.Popup(p.X,p.Y); end; end; { TMainCommands.cm_ConfigDirHotList } // Mainly present for backward compatibility since "cm_ConfigDirHotList" existed before. // procedure TMainCommands.cm_ConfigDirHotList(const Params: array of string); begin cm_WorkWithDirectoryHotlist(['action=config', 'source='+QuoteStr(frmMain.ActiveFrame.CurrentLocation), 'target='+QuoteStr(frmMain.NotActiveFrame.CurrentLocation), 'index=0']); end; { TMainCommands.cm_WorkWithDirectoryHotlist } // The parameter 0, in text, indicate the job to do to generic "SubmitToAddOrConfigToHotDirDlg" routine. // This way, "SubmitToAddOrConfigToHotDirDlg" is to entry point to attempt to do anything in the Directory Hotlist conifguration screen. // procedure TMainCommands.cm_WorkWithDirectoryHotlist(const Params: array of string); var Editor: TOptionsEditor; Options: IOptionsDialog; SearchingIndex, WantedAction, WantedIndexToEdit: integer; WantedSourcePath, WantedTargetPath : string; Param, sValue: String; begin //1o) Let's set our default values WantedAction := ACTION_INVALID; WantedSourcePath := frmMain.ActiveFrame.CurrentPath; WantedTargetPath := frmMain.NotActiveFrame.CurrentPath; WantedIndexToEdit := 0; //2o) Let's parse the parameter to get the wanted ones for Param in Params do begin if GetParamValue(Param, 'action', sValue) then begin SearchingIndex:=1; while ( (SearchingIndex<=length(HOTLISTMAGICWORDS)) AND (WantedAction = ACTION_INVALID) ) do if sValue=HOTLISTMAGICWORDS[SearchingIndex] then WantedAction:=SearchingIndex else inc(SearchingIndex); end else if GetParamValue(Param, 'source', sValue) then begin sValue:=RemoveQuotation(PrepareParameter(sValue)); if (sValue<>'') and (not HasPathInvalidCharacters(sValue)) then WantedSourcePath:=sValue; end else if GetParamValue(Param, 'target', sValue) then begin sValue:=RemoveQuotation(PrepareParameter(sValue)); if (sValue<>'') and (not HasPathInvalidCharacters(sValue)) then WantedTargetPath:=sValue; end else if GetParamValue(Param, 'index', sValue) then begin WantedIndexToEdit:=(strtointdef(sValue,0)); end; end; if WantedAction=ACTION_INVALID then WantedAction:=ACTION_JUSTSHOWCONFIGHOTLIST; //3o) Let's do the sorting job now! Options := ShowOptions(TfrmOptionsDirectoryHotlist); Editor := Options.GetEditor(TfrmOptionsDirectoryHotlist); Application.ProcessMessages; if Editor.CanFocus then Editor.SetFocus; TfrmOptionsDirectoryHotlist(Editor).SubmitToAddOrConfigToHotDirDlg(WantedAction, WantedSourcePath, WantedTargetPath, WantedIndexToEdit); end; procedure TMainCommands.cm_Search(const Params: array of string); var TemplateName: String; begin if not (frmMain.ActiveFrame.FileSource.IsClass(TFileSystemFileSource) or frmMain.ActiveFrame.FileSource.IsClass(TWcxArchiveFileSource)) then begin msgError(rsMsgErrNotSupported) end else begin if Length(Params) > 0 then TemplateName:= Params[0] else begin TemplateName:= gSearchDefaultTemplate; end; ShowFindDlg(frmMain.ActiveFrame, TemplateName); end; end; procedure TMainCommands.cm_SyncDirs(const Params: array of string); var OperationType: TFileSourceOperationType; begin with frmMain do begin if GetCopyOperationType(FrameLeft.FileSource, FrameRight.FileSource, OperationType) or GetCopyOperationType(FrameRight.FileSource, FrameLeft.FileSource, OperationType) then begin ShowSyncDirsDlg(FrameLeft, FrameRight); end else begin msgWarning(rsMsgErrNotSupported); end; end; end; //------------------------------------------------------ procedure TMainCommands.cm_SymLink(const Params: array of string); var sExistingFile, sLinkToCreate: String; SelectedFiles: TFiles; begin with frmMain do begin // Symlinks work only for file system. if not (ActiveFrame.FileSource.IsClass(TFileSystemFileSource)) then begin msgWarning(rsMsgErrNotSupported); Exit; // Or create a symlink in temp filesystem and CopyIn to target file source. end; SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count > 1 then msgWarning(rsMsgTooManyFilesSelected) else if SelectedFiles.Count = 0 then msgWarning(rsMsgNoFilesSelected) else begin sExistingFile := SelectedFiles[0].Path + SelectedFiles[0].Name; if Length(Params) > 0 then sLinkToCreate := Params[0] else begin if NotActiveFrame.FileSource.IsClass(TFileSystemFileSource) then sLinkToCreate := NotActiveFrame.CurrentPath else sLinkToCreate := ActiveFrame.CurrentPath; end; sLinkToCreate := sLinkToCreate + SelectedFiles[0].Name; if ShowSymLinkForm(frmMain, sExistingFile, sLinkToCreate, ActiveFrame.CurrentPath) then begin ActiveFrame.Reload; if NotActiveFrame.FileSource.IsClass(TFileSystemFileSource) then NotActiveFrame.Reload; end; end; finally FreeAndNil(SelectedFiles); end; end; end; procedure TMainCommands.cm_HardLink(const Params: array of string); var sExistingFile, sLinkToCreate: String; SelectedFiles: TFiles; begin with frmMain do begin // Hard links work only for file system. if not (ActiveFrame.FileSource.IsClass(TFileSystemFileSource)) then begin msgWarning(rsMsgErrNotSupported); Exit; end; SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try if SelectedFiles.Count > 1 then msgWarning(rsMsgTooManyFilesSelected) else if SelectedFiles.Count = 0 then msgWarning(rsMsgNoFilesSelected) else begin sExistingFile := SelectedFiles[0].Path + SelectedFiles[0].Name; if Length(Params) > 0 then sLinkToCreate := Params[0] else begin if NotActiveFrame.FileSource.IsClass(TFileSystemFileSource) then sLinkToCreate := NotActiveFrame.CurrentPath else sLinkToCreate := ActiveFrame.CurrentPath; end; sLinkToCreate := sLinkToCreate + SelectedFiles[0].Name; if ShowHardLinkForm(frmMain, sExistingFile, sLinkToCreate, ActiveFrame.CurrentPath) then begin ActiveFrame.Reload; if NotActiveFrame.FileSource.IsClass(TFileSystemFileSource) then NotActiveFrame.Reload; end; end; finally FreeAndNil(SelectedFiles); end; end; end; // Uses to change sort direction when columns header is disabled procedure TMainCommands.cm_ReverseOrder(const Params: array of string); begin with frmMain.ActiveFrame do Sorting := ReverseSortDirection(Sorting); end; procedure TMainCommands.cm_LeftReverseOrder(const Params: array of string); begin with frmMain.FrameLeft do Sorting := ReverseSortDirection(Sorting); end; procedure TMainCommands.cm_RightReverseOrder(const Params: array of string); begin with frmMain.FrameRight do Sorting := ReverseSortDirection(Sorting); end; procedure TMainCommands.cm_SortByName(const Params: array of string); begin DoSortByFunctions(frmMain.ActiveFrame, [fsfNameNoExtension]); end; procedure TMainCommands.cm_SortByExt(const Params: array of string); begin DoSortByFunctions(frmMain.ActiveFrame, [fsfExtension]); end; procedure TMainCommands.cm_SortBySize(const Params: array of string); begin DoSortByFunctions(frmMain.ActiveFrame, [fsfSize]); end; procedure TMainCommands.cm_SortByDate(const Params: array of string); begin DoSortByFunctions(frmMain.ActiveFrame, [fsfModificationTime]); end; procedure TMainCommands.cm_SortByAttr(const Params: array of string); begin DoSortByFunctions(frmMain.ActiveFrame, [fsfAttr]); end; procedure TMainCommands.cm_LeftSortByName(const Params: array of string); begin DoSortByFunctions(frmMain.FrameLeft, [fsfNameNoExtension]); end; procedure TMainCommands.cm_LeftSortByExt(const Params: array of string); begin DoSortByFunctions(frmMain.FrameLeft, [fsfExtension]); end; procedure TMainCommands.cm_LeftSortBySize(const Params: array of string); begin DoSortByFunctions(frmMain.FrameLeft, [fsfSize]); end; procedure TMainCommands.cm_LeftSortByDate(const Params: array of string); begin DoSortByFunctions(frmMain.FrameLeft, [fsfModificationTime]); end; procedure TMainCommands.cm_LeftSortByAttr(const Params: array of string); begin DoSortByFunctions(frmMain.FrameLeft, [fsfAttr]); end; procedure TMainCommands.cm_RightSortByName(const Params: array of string); begin DoSortByFunctions(frmMain.FrameRight, [fsfNameNoExtension]); end; procedure TMainCommands.cm_RightSortByExt(const Params: array of string); begin DoSortByFunctions(frmMain.FrameRight, [fsfExtension]); end; procedure TMainCommands.cm_RightSortBySize(const Params: array of string); begin DoSortByFunctions(frmMain.FrameRight, [fsfSize]); end; procedure TMainCommands.cm_RightSortByDate(const Params: array of string); begin DoSortByFunctions(frmMain.FrameRight, [fsfModificationTime]); end; procedure TMainCommands.cm_RightSortByAttr(const Params: array of string); begin DoSortByFunctions(frmMain.FrameRight, [fsfAttr]); end; { Command to request to sort a frame with a column with a defined order. This command may be user by the user via the toolbar, but it is definitively a nice-to-have for the "uHotDir" unit who may specify the order to be in when switching to a hotdir.} procedure TMainCommands.cm_UniversalSingleDirectSort(const Params: array of string); var Param: String; sValue: String; WantedFileView: TFileView; WantedSortFunction: TFileFunction; WantedSortDirection: TSortDirection; FileFunctions: TFileFunctions = nil; NewSorting: TFileSortings = nil; begin //1o) Let's set our default values WantedFileView:=frmMain.ActiveFrame; WantedSortFunction:=fsfName; WantedSortDirection:=sdAscending; //2o) Let's parse the parameter to get the wanted ones for Param in Params do begin if GetParamValue(Param, 'panel', sValue) then begin if sValue='inactive' then WantedFileView:=frmMain.NotActiveFrame else if sValue='left' then WantedFileView:=frmMain.FrameLeft else if sValue='right' then WantedFileView:=frmMain.FrameRight; end else if GetParamValue(Param, 'column', sValue) then begin if sValue='ext' then WantedSortFunction:=fsfExtension else if sValue='size' then WantedSortFunction:=fsfSize else if sValue='datetime' then WantedSortFunction:=fsfModificationTime; end else if GetParamValue(Param, 'order', sValue) then begin if sValue='descending' then WantedSortDirection:=sdDescending; end; end; //3o) Let's do the sorting job now! AddSortFunction(FileFunctions, WantedSortFunction); SetLength(NewSorting, 1); SetLength(NewSorting[0].SortFunctions, 1); NewSorting[0].SortFunctions[0] := FileFunctions[0]; NewSorting[0].SortDirection := WantedSortDirection; WantedFileView.Sorting := NewSorting; end; procedure TMainCommands.cm_MultiRename(const Params: array of string); var aFiles: TFiles; sValue, Param: string; sPresetToLoad: string = ''; begin with frmMain do begin if not (fsoSetFileProperty in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; aFiles:= ActiveFrame.CloneSelectedOrActiveFiles; if Assigned(aFiles) then try if aFiles.Count > 0 then begin for Param in Params do if GetParamValue(Param, 'preset', sValue) then sPresetToLoad := sValue; ShowMultiRenameForm(ActiveFrame.FileSource, aFiles, sPresetToLoad) end else msgWarning(rsMsgNoFilesSelected); finally FreeAndNil(aFiles); end; end; end; //------------------------------------------------------ procedure TMainCommands.cm_CopySamePanel(const Params: array of string); begin frmMain.CopyFiles('', True); end; procedure TMainCommands.cm_RenameOnly(const Params: array of string); begin frmMain.ActiveFrame.ExecuteCommand('cm_RenameOnly', Params); end; procedure TMainCommands.cm_EditNew(const Params: array of string); var sNewFile: String; hFile: System.THandle = 0; aFile: TFile; Attrs: TFileAttrs; sCmd: string = ''; sParams: string = ''; sStartPath: string = ''; AElevate: TDuplicates = dupIgnore; begin frmMain.ActiveFrame.ExecuteCommand('cm_EditNew', Params); // For now only works for FileSystem. with frmMain do if ActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin aFile := ActiveFrame.CloneActiveFile; if Assigned(aFile) then try if aFile.IsNameValid then sNewFile:= aFile.Name else sNewFile:= rsEditNewFile; finally FreeAndNil(aFile); end; if not InputQuery(rsEditNewOpen, rsEditNewFileName, sNewFile) then Exit; // If user entered only a filename prepend it with current directory. if ExtractFilePath(sNewFile) = '' then sNewFile:= ActiveFrame.CurrentPath + sNewFile; PushPop(AElevate); try sNewFile := TrimPath(sNewFile); Attrs := FileGetAttrUAC(sNewFile); if Attrs = faInvalidAttributes then begin hFile := FileCreateUAC(sNewFile, fmShareDenyWrite); if hFile = feInvalidHandle then begin MessageDlg(rsMsgErrECreate, mbSysErrorMessage(GetLastOSError), mtWarning, [mbOK], 0); Exit; end; FileClose(hFile); ActiveFrame.FileSource.Reload(ExtractFilePath(sNewFile)); ActiveFrame.SetActiveFile(sNewFile); end else if FPS_ISDIR(Attrs) then begin MessageDlg(rsMsgErrECreate, Format(rsMsgErrCreateFileDirectoryExists, [ExtractFileName(sNewFile)]), mtWarning, [mbOK], 0); Exit; end; finally PushPop(AElevate); end; aFile := TFileSystemFileSource.CreateFileFromFile(sNewFile); try // Try to find Edit command in "extassoc.xml" if not gExts.GetExtActionCmd(aFile, 'edit', sCmd, sParams, sStartPath) then ShowEditorByGlob(aFile.FullPath) // If command not found then use default editor else begin ProcessExtCommandFork(sCmd, sParams, aFile.Path, aFile); end; finally FreeAndNil(aFile); end; end else msgWarning(rsMsgNotImplemented); end; { TMainCommands.cm_DirHistory } // Shows recently visited directories (global). procedure TMainCommands.cm_DirHistory(const Params: array of string); var bUseTreeViewMenu: boolean = false; bUsePanel: boolean = true; p: TPoint = (x:0; y:0); iWantedWidth: integer = 0; iWantedHeight: integer = 0; sMaybeMenuItem: TMenuItem = nil; begin // 1. Let's parse our parameters. DoParseParametersForPossibleTreeViewMenu(Params, gUseTreeViewMenuWithDirHistory, gUseTreeViewMenuWithDirHistory, bUseTreeViewMenu, bUsePanel, p); frmMain.CreatePopUpDirHistory(bUseTreeViewMenu, 0); Application.ProcessMessages; //TODO: In Windows, Not sure why, but on all systems tried, this eliminate a "beep" when the popup is shown. if bUseTreeViewMenu then begin if not bUsePanel then iWantedHeight := 0 else begin iWantedWidth := frmMain.ActiveFrame.Width; iWantedHeight := frmMain.ActiveFrame.Height; end; sMaybeMenuItem := GetUserChoiceFromTreeViewMenuLoadedFromPopupMenu(frmMain.pmDirHistory, tvmcDirHistory, p.X, p.Y, iWantedWidth, iWantedHeight); if sMaybeMenuItem <> nil then sMaybeMenuItem.OnClick(sMaybeMenuItem); end else begin frmMain.pmDirHistory.Popup(p.X,p.Y); end; end; // Shows browser-like history for active file view. procedure TMainCommands.cm_ViewHistory(const Params: array of string); begin frmMain.ShowFileViewHistory(Params); end; procedure TMainCommands.cm_ViewHistoryPrev(const Params: array of string); begin with frmMain do begin ActiveFrame.GoToPrevHistory; end; end; procedure TMainCommands.cm_ViewHistoryNext(const Params: array of string); begin with frmMain do begin ActiveFrame.GoToNextHistory; end; end; { TMainCommands.cm_ShowCmdLineHistory } procedure TMainCommands.cm_ShowCmdLineHistory(const Params: array of string); var p: TPoint = (x:0; y:0); sUserChoice:string; bUseTreeViewMenu: boolean = false; bUsePanel: boolean = true; iWantedWidth: integer = 0; iWantedHeight: integer = 0; begin with frmMain do begin if IsCommandLineVisible then begin // 1. Let's parse our parameters. DoParseParametersForPossibleTreeViewMenu(Params, gUseTreeViewMenuWithCommandLineHistory, gUseTreeViewMenuWithCommandLineHistory, bUseTreeViewMenu, bUsePanel, p); // 2. No matter what, we need to fill in the popup menu structure. gFavoriteTabsList.PopulateMenuWithFavoriteTabs(frmMain.pmFavoriteTabs, @DoOnClickMenuJobFavoriteTabs, ftmp_FAVTABSWITHCONFIG); Application.ProcessMessages; // 3. Show the appropriate menu. if bUseTreeViewMenu then begin iWantedWidth := frmMain.edtCommand.Width; iWantedHeight := frmMain.ActiveFrame.Height; p := frmMain.edtCommand.ClientToScreen(Classes.Point(0, 0)); p.y := p.y - iWantedHeight; sUserChoice := GetUserChoiceFromTStrings(edtCommand.Items, tvmcCommandLineHistory, p.x, p.y, iWantedWidth, iWantedHeight); if sUserChoice<>'' then begin edtCommand.ItemIndex:=edtCommand.Items.IndexOf(sUserChoice); edtCommand.SetFocus; end; end else begin edtCommand.SetFocus; if edtCommand.Items.Count>0 then edtCommand.DroppedDown:=True; end; end; end; end; procedure TMainCommands.cm_ToggleFullscreenConsole(const Params: array of string); begin frmMain.ToggleFullscreenConsole; end; procedure TMainCommands.cm_RunTerm(const Params: array of string); begin with frmMain do if not edtCommand.Focused then try ProcessExtCommandFork(gRunTermCmd, gRunTermParams, ActiveFrame.CurrentPath); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningTerminal, rsMsgInvalidCommandLine + ' (' + rsToolTerminal + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; end; procedure TMainCommands.cm_CalculateSpace(const Params: array of string); var SelectedFiles: TFiles; Operation: TFileSourceOperation; begin with frmMain do begin if not (fsoCalcStatistics in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; try Operation := ActiveFrame.FileSource.CreateCalcStatisticsOperation(SelectedFiles); if not Assigned(Operation) then msgWarning(rsMsgErrNotSupported) else begin Operation.AddStateChangedListener([fsosStopped], @OnCalcStatisticsStateChanged); OperationsManager.AddOperation(Operation); end; finally if Assigned(SelectedFiles) then FreeAndNil(SelectedFiles); end; end; end; procedure TMainCommands.cm_CountDirContent(const Params: array of string); begin frmMain.ActiveFrame.CalculateSpaceOfAllDirectories; end; procedure TMainCommands.cm_SetFileProperties(const Params: array of string); var ActiveFile: TFile = nil; SelectedFiles: TFiles = nil; aFileProperties: TFileProperties; CreationTime: DCBasicTypes.TFileTimeEx; LastAccessTime : DCBasicTypes.TFileTimeEx; ModificationTime: DCBasicTypes.TFileTimeEx; Operation: TFileSourceSetFilePropertyOperation = nil; begin with frmMain do try if not (fsoSetFileProperty in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; ActiveFile := ActiveFrame.CloneActiveFile; if Assigned(ActiveFile) and (SelectedFiles.Count > 0) then begin if fspDirectAccess in ActiveFrame.FileSource.Properties then begin if mbFileGetTime(ActiveFile.FullPath, ModificationTime, CreationTime, LastAccessTime) then begin if fpModificationTime in ActiveFile.SupportedProperties then ActiveFile.ModificationTime:= FileTimeToDateTimeEx(ModificationTime); if fpCreationTime in ActiveFile.SupportedProperties then ActiveFile.CreationTime:= FileTimeToDateTimeEx(CreationTime); if fpLastAccessTime in ActiveFile.SupportedProperties then ActiveFile.LastAccessTime:= FileTimeToDateTimeEx(LastAccessTime); end; end; FillByte(aFileProperties, SizeOf(aFileProperties), 0); if fpAttributes in ActiveFile.SupportedProperties then aFileProperties[fpAttributes]:= ActiveFile.Properties[fpAttributes].Clone; if fpModificationTime in ActiveFile.SupportedProperties then aFileProperties[fpModificationTime]:= ActiveFile.Properties[fpModificationTime].Clone; if fpCreationTime in ActiveFile.SupportedProperties then aFileProperties[fpCreationTime]:= ActiveFile.Properties[fpCreationTime].Clone; if fpLastAccessTime in ActiveFile.SupportedProperties then aFileProperties[fpLastAccessTime]:= ActiveFile.Properties[fpLastAccessTime].Clone; Operation:= ActiveFrame.FileSource.CreateSetFilePropertyOperation( SelectedFiles, aFileProperties) as TFileSourceSetFilePropertyOperation; if Assigned(Operation) then begin if (Operation.SupportedProperties * [fpModificationTime, fpCreationTime, fpLastAccessTime, fpAttributes] = []) then begin msgWarning(rsMsgErrNotSupported); Exit; end; if ShowChangeFilePropertiesDialog(Operation) then begin OperationsManager.AddOperation(Operation); Operation := nil; // So it doesn't get destroyed below. end; end; end; finally FreeAndNil(SelectedFiles); FreeAndNil(ActiveFile); FreeAndNil(Operation); end; end; procedure TMainCommands.cm_FileProperties(const Params: array of string); var SelectedFiles: TFiles; Operation: TFileSourceExecuteOperation; aFile: TFile; begin with frmMain do begin if ActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles; if Assigned(SelectedFiles) then try if SelectedFiles.Count > 0 then try ShowFilePropertiesDialog(ActiveFrame.FileSource, SelectedFiles); except on e: EContextMenuException do ShowException(e); end; finally FreeAndNil(SelectedFiles); end; end else if (fsoExecute in ActiveFrame.FileSource.GetOperationsTypes) then begin aFile:= ActiveFrame.CloneActiveFile; if Assigned(aFile) then try Operation:= ActiveFrame.FileSource.CreateExecuteOperation( aFile, ActiveFrame.CurrentPath, 'properties') as TFileSourceExecuteOperation; if Assigned(Operation) then Operation.Execute; finally FreeAndNil(Operation); FreeAndNil(aFile); end; end; end; end; procedure TMainCommands.cm_FileLinker(const Params: array of string); var I: Integer; aSelectedFiles: TFiles = nil; aFile: TFile; aFirstFilenameOfSeries: String; begin with frmMain, frmMain.ActiveFrame do begin if not (fsoCombine in FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; try aSelectedFiles := CloneSelectedOrActiveFiles; for I := 0 to aSelectedFiles.Count - 1 do begin aFile := aSelectedFiles[I]; if (aFile.IsDirectory or aFile.IsLinkToDirectory) then begin msgWarning(rsMsgInvalidSelection); Exit; end; end; if aSelectedFiles.Count > 1 then begin ShowLinkerFilesForm(frmMain, FileSource, aSelectedFiles, NotActiveFrame.CurrentPath); end else begin if aSelectedFiles.Count = 1 then begin try if StrToInt(aSelectedFiles[0].Extension)>0 then begin aFirstFilenameOfSeries:='1'; while length(aFirstFilenameOfSeries) 0 then begin case ClipboardOp of uClipboard.ClipboardCut: begin SourceFileSource := TFileSystemFileSource.GetFileSource; if ActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin if not (fsoMove in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; Operation := SourceFileSource.CreateMoveOperation( Files, ActiveFrame.CurrentPath); end else begin if (not (fsoCopyIn in ActiveFrame.FileSource.GetOperationsTypes)) or (not (fsoDelete in SourceFileSource.GetOperationsTypes)) then begin msgWarning(rsMsgErrNotSupported); Exit; end; { // Meta-operation: CopyIn + Delete Operation := ActiveFrame.FileSource.CreateCopyInOperation( SourceFileSource, Files, ActiveFrame.CurrentPath); } end; end; uClipboard.ClipboardCopy: begin if not (fsoCopyIn in ActiveFrame.FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit; end; SourceFileSource := TFileSystemFileSource.GetFileSource; if ActiveFrame.FileSource.IsClass(TFileSystemFileSource) then begin Operation := SourceFileSource.CreateCopyOutOperation( ActiveFrame.FileSource, Files, ActiveFrame.CurrentPath); end else begin Operation := ActiveFrame.FileSource.CreateCopyInOperation( SourceFileSource, Files, ActiveFrame.CurrentPath); end; end; else // Invalid clipboard operation. Exit; end; if Assigned(Operation) then begin if Operation is TFileSystemCopyOperation then (Operation as TFileSystemCopyOperation).AutoRenameItSelf:= True; OperationsManager.AddOperation(Operation); // Files have been moved so clear the clipboard because // the files location in the clipboard is invalid now. if ClipboardOp = uClipboard.ClipboardCut then uClipboard.ClearClipboard; end else msgWarning(rsMsgNotImplemented); end; finally FreeAndNil(fileNamesList); if Assigned(Files) then FreeAndNil(Files); end; end; end; procedure TMainCommands.cm_SyncChangeDir(const Params: array of string); begin with frmMain do begin actSyncChangeDir.Checked:= not actSyncChangeDir.Checked; if actSyncChangeDir.Checked then SyncChangeDir:= ExcludeTrailingBackslash(ActiveFrame.CurrentPath); end; end; procedure TMainCommands.cm_ChangeDirToRoot(const Params: array of string); begin DoChangeDirToRoot(frmMain.ActiveFrame); end; procedure TMainCommands.cm_ChangeDirToHome(const Params: array of string); begin SetFileSystemPath(frmMain.ActiveFrame, GetHomeDir); end; procedure TMainCommands.cm_ChangeDirToParent(const Params: array of string); begin frmMain.ActiveFrame.ChangePathToParent(True); end; // Parameters: // Full path to a directory. procedure TMainCommands.cm_ChangeDir(const Params: array of string); var Param, WantedPath: string; begin //1o) Let's set our default values WantedPath := frmMain.ActiveFrame.CurrentPath; //2o) Let's parse the parameter to get the wanted ones for Param in Params do begin if GetParamValue(Param, 'activepath', WantedPath) then begin WantedPath:= PrepareParameter(WantedPath); ChooseFileSource(frmMain.ActiveFrame, RemoveQuotation(WantedPath)); end else if GetParamValue(Param, 'inactivepath', WantedPath) then begin WantedPath:= PrepareParameter(WantedPath); ChooseFileSource(frmMain.NotActiveFrame, RemoveQuotation(WantedPath)); end else if GetParamValue(Param, 'leftpath', WantedPath) then begin WantedPath:= PrepareParameter(WantedPath); ChooseFileSource(frmMain.FrameLeft, RemoveQuotation(WantedPath)); end else if GetParamValue(Param, 'rightpath', WantedPath) then begin WantedPath:=PrepareParameter(WantedPath); ChooseFileSource(frmMain.FrameRight, RemoveQuotation(WantedPath)); end; end; //3o) Let's support the DC legacy way of working of the command if Length(Params)=1 then begin if (not GetParamValue(Params[0], 'activepath', WantedPath)) AND (not GetParamValue(Params[0], 'inactivepath', WantedPath)) AND (not GetParamValue(Params[0], 'leftpath', WantedPath)) AND (not GetParamValue(Params[0], 'rightpath', WantedPath)) then ChooseFileSource(frmMain.ActiveFrame, RemoveQuotation(ReplaceEnvVars(Params[0]))); end; end; procedure TMainCommands.cm_ClearLogWindow(const Params: array of string); begin frmMain.seLogWindow.Lines.Clear; end; procedure TMainCommands.cm_CmdLineNext(const Params: array of string); begin DoShowCmdLineHistory(True); end; procedure TMainCommands.cm_CmdLinePrev(const Params: array of string); begin DoShowCmdLineHistory(False); end; procedure TMainCommands.cm_ViewLogFile(const Params: array of string); begin ShowViewerByGlob(GetActualLogFilename); end; procedure TMainCommands.cm_ClearLogFile(const Params: array of string); begin if MsgBox(Format(rsMsgPopUpHotDelete,['log file ('+GetActualLogFilename+')']),[msmbYes, msmbNo], msmbNo, msmbNo ) = mmrYes then begin mbDeleteFile(GetActualLogFilename); end; end; procedure TMainCommands.cm_NetworkConnect(const Params: array of string); begin DoOpenVirtualFileSystemList(frmMain.ActiveFrame); end; procedure TMainCommands.cm_NetworkDisconnect(const Params: array of string); begin CloseNetworkConnection(); end; procedure TMainCommands.cm_CopyNetNamesToClip(const Params: array of string); begin CopyNetNamesToClip; end; procedure TMainCommands.cm_HorizontalFilePanels(const Params: array of string); var sParamValue:string; WantedHorizontalFilePanels:boolean; begin WantedHorizontalFilePanels:=gHorizontalFilePanels; if Length(Params)>0 then begin if GetParamValue(Params[0], 'mode', sParamValue) then begin if sParamValue='legacy' then WantedHorizontalFilePanels := not WantedHorizontalFilePanels else if sParamValue='vertical' then WantedHorizontalFilePanels:=FALSE else if sParamValue='horizontal' then WantedHorizontalFilePanels:=TRUE; end; end else begin WantedHorizontalFilePanels := not WantedHorizontalFilePanels; end; if WantedHorizontalFilePanels<>gHorizontalFilePanels then begin gHorizontalFilePanels:=WantedHorizontalFilePanels; frmMain.actHorizontalFilePanels.Checked := gHorizontalFilePanels; frmMain.UpdateWindowView; end; end; procedure TMainCommands.cm_OperationsViewer(const Params: array of string); begin ShowOperationsViewer; end; procedure TMainCommands.cm_CompareDirectories(const Params: array of string); var I: LongWord; Param: String; BoolValue: Boolean; NtfsShift: Boolean; SourceFile: TDisplayFile; TargetFile: TDisplayFile; AFiles, AFolders: Boolean; SourceList: TStringHashListUtf8; SourceFiles: TDisplayFiles = nil; TargetFiles: TDisplayFiles = nil; begin AFiles := True; AFolders := False; for Param in Params do begin if GetParamBoolValue(Param, 'files', BoolValue) then AFiles := BoolValue else if GetParamBoolValue(Param, 'directories', BoolValue) then begin AFolders := BoolValue end; end; if (AFiles = False) and (AFolders = False) then AFiles := True; SourceList:= TStringHashListUtf8.Create(FileNameCaseSensitive); with frmMain do try NtfsShift:= gNtfsHourTimeDelay and NtfsHourTimeDelay(ActiveFrame.CurrentPath, NotActiveFrame.CurrentPath); SourceFiles:= ActiveFrame.DisplayFiles; TargetFiles:= NotActiveFrame.DisplayFiles; for I:= 0 to SourceFiles.Count - 1 do begin SourceFile:= SourceFiles[I]; if SourceFile.FSFile.IsDirectory or SourceFile.FSFile.IsLinkToDirectory then begin if not AFolders then Continue; end else begin if not AFiles then Continue; end; ActiveFrame.MarkFile(SourceFile, True); SourceList.Add(SourceFile.FSFile.Name, SourceFile); end; for I:= 0 to TargetFiles.Count - 1 do begin TargetFile:= TargetFiles[I]; if TargetFile.FSFile.IsDirectory or TargetFile.FSFile.IsLinkToDirectory then begin if not AFolders then Continue; end else begin if not AFiles then Continue; end; SourceFile:= TDisplayFile(SourceList.Data[TargetFile.FSFile.Name]); if (SourceFile = nil) then NotActiveFrame.MarkFile(TargetFile, True) else case FileTimeCompare(SourceFile.FSFile.ModificationTime, TargetFile.FSFile.ModificationTime, NtfsShift) of 0: ActiveFrame.MarkFile(SourceFile, False); +1: NotActiveFrame.MarkFile(TargetFile, False); -1: begin ActiveFrame.MarkFile(SourceFile, False); NotActiveFrame.MarkFile(TargetFile, True); end; end; end; finally SourceList.Free; ActiveFrame.Repaint; NotActiveFrame.Repaint; end; end; { TMainCommands.cm_ConfigToolbars } procedure TMainCommands.cm_ConfigToolbars(const Params: array of string); begin cm_Options(['TfrmOptionsToolbar']); end; { TMainCommands.cm_DebugShowCommandParameters } procedure TMainCommands.cm_DebugShowCommandParameters(const Params: array of string); var sMessageToshow:string; indexParameter:integer; begin sMessageToshow:='Number of parameters: '+IntToStr(Length(Params)); if Length(Params)>0 then begin sMessageToshow:=sMessageToshow+#$0A; for indexParameter:=0 to pred(Length(Params)) do begin sMessageToshow:=sMessageToshow+#$0A+'Parameter #'+IntToStr(indexParameter)+': '+Params[indexParameter]+' ==> '+PrepareParameter(Params[indexParameter]); end; end; msgOK(sMessageToshow); end; { TMainCommands.cm_CopyPathOfFilesToClip } procedure TMainCommands.cm_CopyPathOfFilesToClip(const Params: array of string); begin DoCopySelectedFileNamesToClipboard(frmMain.ActiveFrame, cfntcJustPathWithSeparator, Params); end; { TMainCommands.cm_CopyPathNoSepOfFilesToClip } procedure TMainCommands.cm_CopyPathNoSepOfFilesToClip(const Params: array of string); begin DoCopySelectedFileNamesToClipboard(frmMain.ActiveFrame, cfntcPathWithoutSeparator, Params); end; { TMainCommands.cm_DoAnyCmCommand } procedure TMainCommands.cm_DoAnyCmCommand(const Params: array of string); var CommandReturnedToExecute:string=''; begin if ShowMainCommandDlgForm(gLastDoAnyCommand,CommandReturnedToExecute) then begin gLastDoAnyCommand := CommandReturnedToExecute; frmMain.Commands.Commands.ExecuteCommand(CommandReturnedToExecute, []); end; end; { TMainCommands.DoCloseAllTabs } procedure TMainCommands.DoCloseAllTabs(ANotebook: TFileViewNotebook; var bAbort: boolean; bDoLocked: boolean; var iAskForLocked: integer); var iPage: integer; begin for iPage := ANotebook.PageCount - 1 downto 0 do if (not bAbort) AND (iPage <> ANotebook.PageIndex) then case frmMain.RemovePage(ANotebook, iPage, bDoLocked, iAskForLocked, True) of 1: Continue; // skip tab 2: bAbort := True; // cancel operation 3: iAskForLocked := 2; // user answered to delete them all, we won't ask anymore during the rest of this command end; end; { TMainCommands.DoCloseDuplicateTabs } // Close tabs pointing to same dirs so at the end of action, only one tab for each dir is kept. // Tabs that are kept follow these rules of priority: // -All the locked tabs are kept without asking question *except* if "bDoLocked" is set, which means we want also to elimit double lock tab. // -The one that has been user renamed by the user are eliminate IF a equivalent locked tab exist. // -If a user rename tab point the same directoy as another tab but not renamed, no matter the order, we keep the renamed tab and eliminate the other. // -A locked renamed tabs is stronger than a non-renamed tab locked so we eliminate the second one, the one not renamed. // -If two equals importance identical exist, we keep the one on left and elimitate the one on right. // At the end of the process, we stay in a tab that has the same path as where we were initally. procedure TMainCommands.DoCloseDuplicateTabs(ANotebook: TFileViewNotebook; var bAbort: boolean; bDoLocked: boolean; var iAskForLocked: integer); var sOriginalPath: String; iTabIndex, jTabIndex, jScore, tScore: Integer; bFlagDeleted: boolean; begin // 1. We save to restore later the original directory of the active tab. sOriginalPath := ANoteBook.Page[ANotebook.PageIndex].FileView.CurrentPath; // 2. We do the actual job. jTabIndex := pred(ANotebook.PageCount); while (not bAbort) AND (jTabIndex>0) do begin jScore:=$0; if (ANoteBook.Page[jTabIndex].PermanentTitle <> '') then jScore := (jScore OR $01); if (ANoteBook.Page[jTabIndex].LockState <> tlsNormal) then jScore := (jScore OR $02); iTabIndex := (jTabIndex-1); bFlagDeleted := FALSE; while (not bAbort) AND (iTabIndex>=0) AND (bFlagDeleted=FALSE) do begin if mbCompareFileNames(ANoteBook.Page[iTabIndex].FileView.CurrentPath, ANoteBook.Page[jTabIndex].FileView.CurrentPath) then begin tScore:=jScore; if (ANoteBook.Page[iTabIndex].PermanentTitle <> '') then tScore := (tScore OR $04); if (ANoteBook.Page[iTabIndex].LockState <> tlsNormal) then tScore := (tScore OR $08); case tScore of $00, $04, $05, $08, $09, $0C, $0D: // We eliminate the one on right. begin frmMain.RemovePage(ANotebook, jTabIndex, False); bFlagDeleted:=TRUE; end; $01, $02, $03, $06, $07: // We eliminate the one on left. begin frmMain.RemovePage(ANotebook, iTabIndex, False); dec(jTabIndex); // If we eliminate one on left, the right tab now moved one position lower, we must take this in account. end; $0A, $0E, $0F: // We eliminate the one on right, EVEN if it is locked if specified. begin if bDoLocked then begin case frmMain.RemovePage(ANotebook, jTabIndex, bDoLocked, iAskForLocked, True) of 0: bFlagDeleted:=True; // Standard Removed. 1: begin end; // Skip tab, we keep going. 2: bAbort := True; // Cancel operation! 3: begin iAskForLocked := 2; // user answered to delete them all, we won't ask anymore during the rest of this command bFlagDeleted:=True; end; end; end; end; $0B: // We eliminate the one on left, EVEN if it is locked, if specified. begin if bDoLocked then begin case frmMain.RemovePage(ANotebook, iTabIndex, bDoLocked, iAskForLocked, True) of 0: dec(jTabIndex); // If we eliminate one on left, the right tab now moved one position lower, we must take this in account. 1: begin end; // Skip tab, we keep going. 2: bAbort := True; // Cancel operation! 3: begin iAskForLocked := 2; // user answered to delete them all, we won't ask anymore during the rest of this command dec(jTabIndex); end; end; end; end; end; // case tScore end; dec(iTabIndex); end; dec(jTabIndex); end; // 3. We attempt to select a tab with the actual original path from where we were. if not mbCompareFileNames(ANoteBook.Page[ANotebook.PageIndex].FileView.CurrentPath , sOriginalPath) then begin iTabIndex:=0; while (iTabIndex nil then sMaybeMenuItem.Click; end else begin frmMain.pmFavoriteTabs.Popup(p.X, p.Y); end; end else begin // If we've seen the 'setup' parameter, let's see if user provided a name or not. if sSearchedFavoriteTabsName<>'' then begin // If we got a name, let's attempt to load a setup with that name. iMaybeIndex := gFavoriteTabsList.GetIndexForSuchFavoriteTabsName(sSearchedFavoriteTabsName); if iMaybeIndex <> -1 then gFavoriteTabsList.LoadTabsFromXmlEntry(iMaybeIndex) else if gToolbarReportErrorWithCommands then msgError(Format(rsFavoriteTabs_SetupNotExist,[sSearchedFavoriteTabsName])); end else begin // If no name provided, it means user want to unselect current setup. gFavoriteTabsList.LastFavoriteTabsLoadedUniqueId := DCGetNewGUID; end; end; end; { TMainCommands.DoCopyAllTabsToOppositeSide } procedure TMainCommands.DoCopyAllTabsToOppositeSide(ANotebook: TFileViewNotebook; var bAbort: boolean; bDoLocked: boolean; var iAskForLocked: integer); var iPage: integer; localFileViewPage: TFileViewPage; localPath: string; TargetNotebook: TFileViewNotebook; iPageCountLimit: integer; begin if FOriginalNumberOfTabs <> -1 then iPageCountLimit := FOriginalNumberOfTabs else iPageCountLimit := ANotebook.PageCount; if ANotebook = FrmMain.LeftTabs then TargetNotebook := FrmMain.RightTabs else TargetNotebook := FrmMain.LeftTabs; for iPage := 0 to pred(iPageCountLimit) do begin localPath := ANotebook.Page[iPage].FileView.CurrentPath; localFileViewPage := TargetNotebook.NewPage(ANotebook.Page[iPage].FileView); // Workaround for Search Result File Source if localFileViewPage.FileView.FileSource is TSearchResultFileSource then SetFileSystemPath(localFileViewPage.FileView, localPath) else localFileViewPage.FileView.CurrentPath := localPath; end; end; { TMainCommands.cm_CopyAllTabsToOpposite } procedure TMainCommands.cm_CopyAllTabsToOpposite(const Params: array of string); begin DoActionOnMultipleTabs(Params, @DoCopyAllTabsToOppositeSide); end; { TMainCommands.cm_ConfigTreeViewMenus } procedure TMainCommands.cm_ConfigTreeViewMenus(const {%H-}Params: array of string); begin cm_Options(['TfrmOptionsTreeViewMenu']); end; { TMainCommands.cm_ConfigTreeViewMenusColors } procedure TMainCommands.cm_ConfigTreeViewMenusColors(const {%H-}Params: array of string); begin cm_Options(['TfrmOptionsTreeViewMenuColor']); end; procedure TMainCommands.cm_ConfigSavePos(const Params: array of string); begin frmMain.SaveWindowState; try gConfig.Save; except on E: Exception do msgError(E.Message); end; end; { TMainCommands.cm_ConfigSaveSettings } procedure TMainCommands.cm_ConfigSaveSettings(const Params: array of string); begin frmMain.ConfigSaveSettings(True); end; { TMainCommands.cm_ExecuteScript } procedure TMainCommands.cm_ExecuteScript(const Params: array of string); var FileName, sErrorMessage: String; Index, Count: Integer; Args: array of String; begin if Length(Params) > 0 then begin // Get script file name FileName:= PrepareParameter(Params[0]); if not mbFileExists(FileName) then begin msgError(Format(rsMsgFileNotFound, [Filename])); Exit; end; // Get script arguments Count:= Length(Params) - 1; if (Count > 0) then begin SetLength(Args, Count); for Index := 1 to Count do begin Args[Index - 1]:= PrepareParameter(Params[Index]); end; end; // Execute script if not ExecuteScript(FileName, Args, sErrorMessage) then if sErrorMessage <> '' then if msgYesNo(sErrorMessage + #$0A + rsMsgWantToConfigureLibraryLocation) then cm_Options(['TfrmOptionsPluginsGroup']); end; end; procedure TMainCommands.cm_FocusSwap(const Params: array of string); var AParam, AValue: String; begin with frmMain do begin // Select opposite panel if Length(Params) = 0 then begin case SelectedPanel of fpLeft: SetActiveFrame(fpRight); fpRight: SetActiveFrame(fpLeft); end; end else begin AParam:= GetDefaultParam(Params); if GetParamValue(AParam, 'side', AValue) then begin if AValue = 'left' then SetActiveFrame(fpLeft) else if AValue = 'right' then SetActiveFrame(fpRight); end; end; end; end; procedure TMainCommands.cm_Benchmark(const Params: array of string); begin OperationsManager.AddOperation(TBenchmarkOperation.Create(frmMain)); end; { TMainCommands.cm_ConfigArchivers } procedure TMainCommands.cm_ConfigArchivers(const {%H-}Params: array of string); begin cm_Options(['TfrmOptionsArchivers']); end; { TMainCommands.cm_ConfigTooltip } procedure TMainCommands.cm_ConfigTooltips(const {%H-}Params: array of string); begin cm_Options(['TfrmOptionsToolTips']); end; procedure TMainCommands.cm_OpenDriveByIndex(const Params: array of string); var Param: String; Index: Integer; AValue: String; SelectedPanel: TFilePanelSelect; begin if Length(Params) > 0 then begin SelectedPanel:= frmMain.SelectedPanel; for Param in Params do begin if GetParamValue(Param, 'index', AValue) then begin Index:= StrToIntDef(AValue, 1) - 1; end else if GetParamValue(Param, 'side', AValue) then begin if AValue = 'left' then SelectedPanel:= fpLeft else if AValue = 'right' then SelectedPanel:= fpRight else if AValue = 'inactive' then begin if frmMain.SelectedPanel = fpLeft then SelectedPanel:= fpRight else if frmMain.SelectedPanel = fpRight then SelectedPanel:= fpLeft; end; end end; if (Index >= 0) and (Index < frmMain.Drives.Count) then begin frmMain.SetPanelDrive(SelectedPanel, frmMain.Drives.Items[Index], True); end; end; end; { TMainCommands.cm_ConfigPlugins } procedure TMainCommands.cm_ConfigPlugins(const {%H-}Params: array of string); begin cm_Options(['TfrmOptionsPluginsGroup']); end; { TMainCommands.cm_AddNewSearch } procedure TMainCommands.cm_AddNewSearch(const Params: array of string); var TemplateName: String; begin if Length(Params) > 0 then TemplateName:= Params[0] else begin TemplateName:= gSearchDefaultTemplate; end; ShowFindDlg(frmMain.ActiveFrame, TemplateName, True); end; { TMainCommands.cm_ViewSearches } procedure TMainCommands.cm_ViewSearches(const {%H-}Params: array of string); var iIndex,iCurrentPage:integer; iSelectedWindow: integer = -1; slWindowTitleToOffer:TStringList; sTitleSelected:string=''; begin if ListOffrmFindDlgInstance.Count>0 then begin slWindowTitleToOffer:=TStringList.Create; try for iIndex:=0 to pred(ListOffrmFindDlgInstance.count) do slWindowTitleToOffer.Add(ListOffrmFindDlgInstance.frmFindDlgInstance[iIndex].Caption); if ShowInputListBox(rsListOfFindFilesWindows, rsSelectYouFindFilesWindow, slWindowTitleToOffer,sTitleSelected,iSelectedWindow) then begin if (iSelectedWindow>-1) AND (iSelectedWindow0 then begin for iIndex := pred(ListOffrmFindDlgInstance.count) downto 0 do ListOffrmFindDlgInstance.frmFindDlgInstance[iIndex].CancelCloseAndFreeMem; end else begin msgOK(rsNoFindFilesWindowYet); end; end; { TMainCommands.cm_ConfigSearches } procedure TMainCommands.cm_ConfigSearches(const Params: array of string); begin cm_Options(['TfrmOptionsFileSearch']); end; { TMainCommands.cm_ConfigHotKeys } procedure TMainCommands.cm_ConfigHotKeys(const Params: array of string); var Editor: TOptionsEditor; Options: IOptionsDialog; Param, sCategoryName:string; begin sCategoryName:=''; Options := ShowOptions(TfrmOptionsHotkeys); Editor := Options.GetEditor(TfrmOptionsHotkeys); Application.ProcessMessages; for Param in Params do GetParamValue(Param, 'category', sCategoryName); TfrmOptionsHotkeys(Editor).TryToSelectThatCategory(sCategoryName); if Editor.CanFocus then Editor.SetFocus; end; { TMainCommands.cm_AddPlugin } procedure TMainCommands.cm_AddPlugin(const Params: array of string); const sPLUGIN_FAMILY = 'DSX|WCX|WDX|WFX|WLX|'; sPLUGIN64_FAMILY = 'DSX64|WCX64|WDX64|WFX64|WLX64|'; var Param, sValue, sMaybeFilename, sPluginFilename: string; PluginType: TPluginType; Editor: TOptionsEditor; Options: IOptionsDialog; sPluginSuffix: string; iPluginDispatcher: integer = -1; procedure SetPluginTypeBasedOnThisString(sSubString:string); begin sSubString := UpperCase(StringReplace(sSubString, '.', '', [rfReplaceAll])); if pos((sSubString+'|'), sPLUGIN_FAMILY) <> 0 then begin sPluginSuffix := sSubString; iPluginDispatcher := ((pos(sPluginSuffix, sPLUGIN_FAMILY) - 1) div 4); end else begin if pos((sSubString+'|'), sPLUGIN64_FAMILY) <> 0 then begin sPluginSuffix := LeftStr(sSubString, 3); iPluginDispatcher := ((pos(sPluginSuffix, sPLUGIN64_FAMILY) - 1) div 6); end; end; end; begin //1. We initialize our seeking variables. sPluginSuffix := ''; sPluginFilename := ''; //2. Let's parse the parameter to get the wanted ones. for Param in Params do begin if GetParamValue(Param, 'type', sValue) then SetPluginTypeBasedOnThisString(sValue) else if GetParamValue(Param, 'file', sValue) then sPluginFilename := RemoveQuotation(PrepareParameter(sValue)); end; //3. If user provided no parameter, let's launch the file requester to have user point a file. if Length(Params) = 0 then begin dmComData.OpenDialog.Filter:= ParseLineToFileFilter([rsFilterPluginFiles, '*.dsx;*.wcx;*.wdx;*.wfx;*.wlx;*.dsx64;*.wcx64;*.wdx64;*.wfx64;*.wlx64', rsFilterAnyFiles, AllFilesMask]); dmComData.OpenDialog.InitialDir := frmMain.ActiveNotebook.ActivePage.FileView.CurrentPath; if dmComData.OpenDialog.Execute then sPluginFilename := dmComData.OpenDialog.FileName; end; //3. If user provided just the filename, let's guess the plugin type based on file's extension. if (sPluginSuffix = '') AND (sPluginFilename <> '') then SetPluginTypeBasedOnThisString(ExtractFileExt(sPluginFilename)); //4. If user provided something but did not specify clear parematers, let's assume it's simply directly a filename. if (sPluginSuffix = '') AND (sPluginFilename = '') and (Length(Params) > 0) then begin sMaybeFilename := RemoveQuotation(PrepareParameter(Params[0])); if FileExists(sMaybeFilename) then begin sPluginFilename := sMaybeFilename; SetPluginTypeBasedOnThisString(ExtractFileExt(sPluginFilename)); end; end; //5. At this point, if we have a filename and have determine plugin type, let's attempt to add the plugin. if (sPluginSuffix <> '') AND (sPluginFilename <> '') then begin if FileExists(sPluginFilename) then begin Options := ShowOptions('TfrmOptionsPlugins' + sPluginSuffix); Application.ProcessMessages; case iPluginDispatcher of 0: Editor := Options.GetEditor(TfrmOptionsPluginsDSX); 1: Editor := Options.GetEditor(TfrmOptionsPluginsWCX); 2: Editor := Options.GetEditor(TfrmOptionsPluginsWDX); 3: Editor := Options.GetEditor(TfrmOptionsPluginsWFX); 4: Editor := Options.GetEditor(TfrmOptionsPluginsWLX); else exit; end; if Editor.CanFocus then Editor.SetFocus; TfrmOptionsPluginsBase(Editor).ActualAddPlugin(sPluginFilename); end; end else if (Length(sMaybeFilename) > 0) then begin InstallPlugin(sMaybeFilename); end; end; procedure TMainCommands.cm_LoadList(const Params: array of string); var aFile: TFile; sValue: String; AParam: String; Index: Integer; AFileName: String; FileList: TFileTree; NewPage: TFileViewPage; StringList: TStringListUAC; Notebook: TFileViewNotebook; SearchResultFS: ISearchResultFileSource; begin with frmMain do begin AFileName:= EmptyStr; Notebook := ActiveNotebook; for AParam in Params do begin if GetParamValue(AParam, 'filename', sValue) then AFileName := sValue else if GetParamValue(AParam, 'side', sValue) then begin if sValue = 'left' then Notebook := LeftTabs else if sValue = 'right' then Notebook := RightTabs else if sValue = 'active' then Notebook := ActiveNotebook else if sValue = 'inactive' then Notebook := NotActiveNotebook; end; end; if (Length(AFileName) = 0) then begin msgError(rsMsgInvalidFilename); Exit; end; StringList:= TStringListUAC.Create; try StringList.LoadFromFile(AFileName); FileList := TFileTree.Create; for Index := 0 to StringList.Count - 1 do begin try aFile := TFileSystemFileSource.CreateFileFromFile(StringList[Index]); FileList.AddSubNode(aFile); except on EFileNotFound do ; end; end; SearchResultFS := TSearchResultFileSource.Create; SearchResultFS.AddList(FileList, TFileSystemFileSource.GetFileSource); NewPage := Notebook.ActivePage; NewPage.FileView.AddFileSource(SearchResultFS, SearchResultFS.GetRootDir); NewPage.FileView.FlatView := True; NewPage.MakeActive; except on E: Exception do msgError(E.Message); end; StringList.Free; end; end; end. doublecmd-1.1.22/src/umasks.pas0000644000175000001440000002630514743153644015413 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Modified version of standard Masks unit Copyright (C) 2010-2021 Alexander Koblov (alexx2000@mail.ru) This file is based on masks.pas from the Lazarus Component Library (LCL) See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the copyright. 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. } unit uMasks; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Contnrs; type TMaskCharType = (mcChar, mcAnyChar, mcAnyText); TMaskOption = (moCaseSensitive, moIgnoreAccents, moWindowsMask, moPinyin); TMaskOptions = set of TMaskOption; TMaskChar = record case CharType: TMaskCharType of mcChar: (CharValue: WideChar); mcAnyChar, mcAnyText: (); end; TMaskString = record MinLength: Integer; MaxLength: Integer; Chars: Array of TMaskChar; end; { TMask } TMask = class private FTemplate:string; FMask: TMaskString; FUsePinyin: Boolean; FCaseSensitive: Boolean; fIgnoreAccents: Boolean; fWindowsInterpretation: boolean; procedure SetCaseSence(ACaseSence:boolean); procedure SetTemplate(AValue: String); procedure Update; public constructor Create(const AValue: string; const AOptions: TMaskOptions = []); function Matches(const AFileName: string): boolean; function LegacyMatches(const AFileName: string): boolean; function WindowsMatches(const AFileName: string): boolean; property CaseSensitive:boolean read FCaseSensitive write SetCaseSence; property Template:string read FTemplate write SetTemplate; end; { TParseStringList } TParseStringList = class(TStringList) public constructor Create(const AText, ASeparators: String); end; { TMaskList } TMaskList = class private FMasks: TObjectList; function GetCount: Integer; function GetItem(Index: Integer): TMask; public constructor Create(const AValue: string; ASeparatorCharset: string = ';'; const AOptions: TMaskOptions = []); destructor Destroy; override; function Matches(const AFileName: String): Boolean; property Count: Integer read GetCount; property Items[Index: Integer]: TMask read GetItem; end; function MatchesMask(const FileName, Mask: String; const AOptions: TMaskOptions = []): Boolean; function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string = ';'; const AOptions: TMaskOptions = []): boolean; implementation uses //Lazarus, Free-Pascal, etc. LazUTF8, //DC DCConvertEncoding, uPinyin, uAccentsUtils; { MatchesMask } function MatchesMask(const FileName, Mask: String; const AOptions: TMaskOptions): Boolean; var AMask: TMask; begin if Mask <> '' then begin AMask := TMask.Create(Mask, AOptions); try Result := AMask.Matches(FileName); finally AMask.Free; end; end else Result := False; end; { MatchesMaskList } function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string; const AOptions: TMaskOptions): boolean; var AMaskList: TMaskList; begin if Mask <> '' then begin AMaskList := TMaskList.Create(Mask, ASeparatorCharset, AOptions); try Result := AMaskList.Matches(FileName); finally AMaskList.Free; end; end else Result := False; end; { TMask } { TMask.Create } constructor TMask.Create(const AValue: string; const AOptions: TMaskOptions); begin FTemplate:= AValue; FUsePinyin:= moPinyin in AOptions; FCaseSensitive := moCaseSensitive in AOptions; fIgnoreAccents := moIgnoreAccents in AOptions; fWindowsInterpretation := moWindowsMask in AOptions; if FIgnoreAccents then FTemplate := NormalizeAccentedChar(FTemplate); //Let's set the mask early in straight letters if match attempt has to be with accent and ligature removed. if not FCaseSensitive then FTemplate := UTF8LowerCase(FTemplate); //Let's set the mask early in lowercase if match attempt has to be case insensitive. Update; end; { TMask.SetCaseSence } procedure TMask.SetCaseSence(ACaseSence:boolean); begin FCaseSensitive:=ACaseSence; Update; end; { TMask.SetTemplate } procedure TMask.SetTemplate(AValue: String); begin FTemplate:=AValue; Update; end; { TMask.Update } procedure TMask.Update; var I: Integer; S: UnicodeString; SkipAnyText: Boolean; AValue:string; procedure AddAnyText; begin if SkipAnyText then begin Inc(I); Exit; end; SetLength(FMask.Chars, Length(FMask.Chars) + 1); FMask.Chars[High(FMask.Chars)].CharType := mcAnyText; FMask.MaxLength := MaxInt; SkipAnyText := True; Inc(I); end; procedure AddAnyChar; begin SkipAnyText := False; SetLength(FMask.Chars, Length(FMask.Chars) + 1); FMask.Chars[High(FMask.Chars)].CharType := mcAnyChar; Inc(FMask.MinLength); if FMask.MaxLength < MaxInt then Inc(FMask.MaxLength); Inc(I); end; procedure AddChar; begin SkipAnyText := False; SetLength(FMask.Chars, Length(FMask.Chars) + 1); with FMask.Chars[High(FMask.Chars)] do begin CharType := mcChar; CharValue := S[I]; end; Inc(FMask.MinLength); if FMask.MaxLength < MaxInt then Inc(FMask.MaxLength); Inc(I); end; begin AValue:=FTemplate; SetLength(FMask.Chars, 0); FMask.MinLength := 0; FMask.MaxLength := 0; SkipAnyText := False; S := CeUtf8ToUtf16(AValue); I := 1; while I <= Length(S) do begin case S[I] of '*': AddAnyText; '?': AddAnyChar; else AddChar; end; end; end; { TMask.Matches } function TMask.Matches(const AFileName: string): boolean; var sFilename: string; begin //Let's set the AFileName in straight letters if match attempt has to be with accent and ligature removed. if FIgnoreAccents then sFilename := NormalizeAccentedChar(AFileName) else sFilename := AFileName; //Let's set our AFileName is lowercase early if not case-sensitive if not FCaseSensitive then sFilename := UTF8LowerCase(sFilename); if not fWindowsInterpretation then Result := LegacyMatches(sFileName) else Result := WindowsMatches(sFileName); end; { TMask.LegacyMatches } function TMask.LegacyMatches(const AFileName: string): boolean; var L: Integer; S: UnicodeString; function MatchToEnd(MaskIndex, CharIndex: Integer): Boolean; var I, J: Integer; begin Result := False; for I := MaskIndex to High(FMask.Chars) do begin case FMask.Chars[I].CharType of mcChar: begin if CharIndex > L then Exit; //DCDebug('Match ' + S[CharIndex] + '' + FMask.Chars[I].CharValue); if FUsePinyin then begin if not PinyinMatch(S[CharIndex], FMask.Chars[I].CharValue) then exit; end else begin if S[CharIndex] <> FMask.Chars[I].CharValue then Exit; end; Inc(CharIndex); end; mcAnyChar: begin if CharIndex > L then Exit; Inc(CharIndex); end; mcAnyText: begin if I = High(FMask.Chars) then begin Result := True; Exit; end; for J := CharIndex to L do if MatchToEnd(I + 1, J) then begin Result := True; Exit; end; end; end; end; Result := CharIndex > L; end; begin Result := False; S := CeUtf8ToUtf16(AFileName); L := Length(S); if L = 0 then begin if FMask.MinLength = 0 then Result := True; Exit; end; if (L < FMask.MinLength) or (L > FMask.MaxLength) then Exit; Result := MatchToEnd(0, 1); end; { TMask.WindowsMatches } // treat initial mask differently for special cases: // foo*.* -> foo* // foo*. -> match foo*, but muts not have an extension // *. -> any file without extension ( .foo is a filename without extension according to Windows) // foo. matches only foo but not foo.txt // foo.* -> match either foo or foo.* function TMask.WindowsMatches(const AFileName: string): boolean; var Ext, sInitialTemplate: string; sInitialMask: UnicodeString; begin sInitialMask := CeUtf8ToUtf16(FTemplate); if (Length(sInitialMask) > 2) and (RightStr(sInitialMask, 3) = '*.*') then // foo*.* begin sInitialTemplate := FTemplate; //Preserve initial state of FTemplate FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 2); Update; Result := LegacyMatches(AFileName); FTemplate := sInitialTemplate; //Restore initial state of FTemplate Update; end else if (Length(sInitialMask) > 1) and (RightStr(sInitialMask, 1) = '.') then //foo*. or *. or foo. begin //if AFileName has an extension then Result is False, otherwise see if it LegacyMatches foo*/foo //a filename like .foo under Windows is considered to be a file without an extension Ext := ExtractFileExt(AFileName); if (Ext = '') or (Ext = AFileName) then begin sInitialTemplate := FTemplate; //Preserve initial state of FTemplate FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 1); Update; Result := LegacyMatches(AFileName); FTemplate := sInitialTemplate; //Restore initial state of FTemplate Update; end else begin Result := False; end; end else if (Length(sInitialMask) > 2) and (RightStr(sInitialMask, 2) = '.*') then //foo.* (but not '.*') begin //First see if we have 'foo' Result := (AFileName = Copy(sInitialMask, 1, Length(sInitialMask) - 2)); if not Result then Result := LegacyMatches(AFileName); end else begin Result := LegacyMatches(AFileName); //all other cases just call LegacyMatches() end; end; { TParseStringList } { TParseStringList.Create } constructor TParseStringList.Create(const AText, ASeparators: String); var I, S: Integer; begin inherited Create; S := 1; for I := 1 to Length(AText) do begin if Pos(AText[I], ASeparators) > 0 then begin if I > S then Add(Copy(AText, S, I - S)); S := I + 1; end; end; if Length(AText) >= S then Add(Copy(AText, S, Length(AText) - S + 1)); end; { TMaskList } function TMaskList.GetItem(Index: Integer): TMask; begin Result := TMask(FMasks.Items[Index]); end; { TMaskList.GetCount } function TMaskList.GetCount: Integer; begin Result := FMasks.Count; end; { TMaskList.Create } constructor TMaskList.Create(const AValue: string; ASeparatorCharset: string; const AOptions: TMaskOptions); var I: Integer; S: TParseStringList; begin FMasks := TObjectList.Create(True); if AValue = '' then exit; S := TParseStringList.Create(AValue, ASeparatorCharset); try for I := 0 to S.Count - 1 do FMasks.Add(TMask.Create(S[I], AOptions)); finally S.Free; end; end; { TMaskList.Destroy } destructor TMaskList.Destroy; begin FMasks.Free; inherited Destroy; end; { TMaskList.Matches } function TMaskList.Matches(const AFileName: String): Boolean; var I: integer; begin Result := False; for I := 0 to FMasks.Count - 1 do begin if TMask(FMasks.Items[I]).Matches(AFileName) then begin Result := True; Exit; end; end; end; end. doublecmd-1.1.22/src/umoveconfig.pas0000644000175000001440000000204414743153644016423 0ustar alexxusersunit uMoveConfig; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, FileUtil, DCOSUtils, uGlobsPaths; implementation procedure Initialize; var Index: Integer; AFileName: String; AList: TStringList; begin // Double Commander Portable // Move settings from executable directory to 'settings' subdirectory if mbFileExists(gpExePath + 'doublecmd.inf') then begin AFileName:= ExcludeTrailingBackslash(gpGlobalCfgDir); if mbDirectoryExists(AFileName) or mbCreateDir(AFileName) then begin AList:= FindAllFiles(gpExePath, '*.cache;*.cfg;*.err;*.json;*.inf;*.ini;*.scf;*.txt;*.xml'); for Index:= 0 to AList.Count - 1 do begin AFileName:= ExtractFileName(AList[Index]); if (AFileName <> 'dcupdater.ini') and (AFileName <> 'doublecmd.visualelementsmanifest.xml') then begin mbRenameFile(gpExePath + AFileName, gpGlobalCfgDir + AFileName); end; end; AList.Free; end; end; end; initialization Initialize; end. doublecmd-1.1.22/src/umultiarc.pas0000644000175000001440000005126514743153644016120 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Implementation of multi archiver support Copyright (C) 2010-2020 Koblov Alexander (Alexx2000@mail.ru) 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 } unit uMultiArc; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCBasicTypes, uMasks, uClassesEx; const MaxSignSize = 1024; SignSeekRange = 1024 * 1024; const MAF_UNIX_PATH = 1; // Use Unix path delimiter (/) MAF_WIN_PATH = 2; // Use Windows path delimiter (\) MAF_UNIX_ATTR = 4; // Use Unix file attributes MAF_WIN_ATTR = 8; // Use Windows file attributes type TMultiArcFlag = (mafFileNameList); TMultiArcFlags = set of TMultiArcFlag; type TSignature = record Value: array[0..Pred(MaxSignSize)] of Byte; Size: LongInt; end; PSignature = ^TSignature; { TSignatureList } TSignatureList = class(TFPList) private function GetSignature(Index: Integer): PSignature; public destructor Destroy; override; procedure Clean; property Items[Index: Integer]: PSignature read GetSignature; default; end; TSignaturePosition = record Value: LongInt; Sign: Boolean; end; PSignaturePosition = ^TSignaturePosition; { TSignaturePositionList } TSignaturePositionList = class(TFPList) private function GetSignaturePosition(Index: Integer): PSignaturePosition; public destructor Destroy; override; procedure Clean; property Items[Index: Integer]: PSignaturePosition read GetSignaturePosition; default; end; { TArchiveItem } TArchiveItem = class(TObjectEx) FileName, FileExt, FileLink: String; PackSize, UnpSize: Int64; Year, Month, Day, Hour, Minute, Second: Word; Attributes: TFileAttrs; function Clone: TArchiveItem; override; end; { TMultiArcItem } TMultiArcItem = class private FExt: String; FMaskList: TMaskList; FSeekAfterSignPos: Boolean; FSignature, FSignaturePosition: AnsiString; FSignatureSeekRange: LongInt; FSignatureList: TSignatureList; FSignaturePositionList: TSignaturePositionList; function GetSignatureSeekRange: AnsiString; procedure SetExtension(const AValue: String); procedure SetSignature(const AValue: AnsiString); procedure SetSignaturePosition(const AValue: AnsiString); procedure SetSignatureSeekRange(const AValue: AnsiString); public FPacker, FArchiver, FDescription, FStart, FEnd: String; FFormat: TStringList; FList, FExtract, FExtractWithoutPath, FTest, FDelete, FAdd, FAddSelfExtract, FPasswordQuery: String; FFormMode: Integer; FFlags: TMultiArcFlags; public FEnabled: Boolean; FOutput: Boolean; FDebug: Boolean; constructor Create; destructor Destroy; override; function Matches(const AFileName: String): Boolean; function CanYouHandleThisFile(const FileName: String): Boolean; function Clone: TMultiArcItem; property FExtension: String read FExt write SetExtension; property FID: AnsiString read FSignature write SetSignature; property FIDPos: AnsiString read FSignaturePosition write SetSignaturePosition; property FIDSeekRange: AnsiString read GetSignatureSeekRange write SetSignatureSeekRange; end; { TMultiArcList } TMultiArcList = class FList: TStringList; private function GetCount: LongInt; function GetItem(Index: Integer): TMultiArcItem; function GetName(Index: Integer): String; procedure SetName(Index: Integer; const AValue: String); public constructor Create; virtual; destructor Destroy; override; procedure AutoConfigure; procedure Clear; procedure LoadFromFile(const FileName: String); procedure SaveToFile(const FileName: String); function Add(const S: String; aMultiArcItem: TMultiArcItem): Integer; function Insert(Index: integer; const S: string; aMultiArcItem: TMultiArcItem): integer; function Clone: TMultiArcList; function ComputeSignature(Seed: dword = $00000000): dword; procedure Delete(Index: Integer); property Names[Index: Integer]: String read GetName write SetName; property Items[Index: Integer]: TMultiArcItem read GetItem; default; property Count: LongInt read GetCount; end; implementation uses crc, LCLProc, StrUtils, Math, FileUtil, DCClassesUtf8, uDCUtils, DCOSUtils, DCStrUtils; { TArchiveItem } function TArchiveItem.Clone: TArchiveItem; begin Result:= TArchiveItem.Create; Result.FileName:= FileName; Result.FileExt:= FileExt; Result.FileLink:= FileLink; Result.PackSize:= PackSize; Result.UnpSize:= UnpSize; Result.Year:= Year; Result.Month:= Month; Result.Day:= Day; Result.Hour:= Hour; Result.Minute:= Minute; Result.Second:= Second; Result.Attributes:= Attributes; end; { TMultiArcList } function TMultiArcList.GetCount: LongInt; begin Result:= FList.Count; end; function TMultiArcList.GetItem(Index: Integer): TMultiArcItem; begin Result:= TMultiArcItem(FList.Objects[Index]); end; function TMultiArcList.GetName(Index: Integer): String; begin Result:= FList.Strings[Index]; end; procedure TMultiArcList.SetName(Index: Integer; const AValue: String); begin FList.Strings[Index]:= AValue; end; constructor TMultiArcList.Create; begin FList:= TStringList.Create; end; destructor TMultiArcList.Destroy; begin Clear; FreeAndNil(FList); inherited Destroy; end; procedure TMultiArcList.AutoConfigure; var I: Integer; ExePath: String; begin for I:= 0 to Count - 1 do begin ExePath:= Items[I].FArchiver; if not mbFileExists(ReplaceEnvVars(ExePath)) then ExePath:= FindDefaultExecutablePath(ExePath); if ExePath = EmptyStr then Items[I].FEnabled:= False else begin Items[I].FArchiver:= ExePath; Items[I].FEnabled:= True; end; end; end; procedure TMultiArcList.Clear; var I: Integer; begin for I:= FList.Count - 1 downto 0 do if Assigned(FList.Objects[I]) then begin FList.Objects[I].Free; FList.Objects[I]:= nil; FList.Delete(I); end; end; procedure TMultiArcList.LoadFromFile(const FileName: String); var I, J: Integer; IniFile: TIniFileEx = nil; Sections: TStringList = nil; Section, Format: String; FirstTime: Boolean = True; MultiArcItem: TMultiArcItem; begin Self.Clear; IniFile:= TIniFileEx.Create(FileName, fmOpenRead); try Sections:= TStringList.Create; IniFile.ReadSections(Sections); for I:= 0 to Sections.Count - 1 do begin Section:= Sections[I]; if SameText(Section, 'MultiArc') then begin FirstTime:= IniFile.ReadBool(Section, 'FirstTime', True); Continue; end; MultiArcItem:= TMultiArcItem.Create; with MultiArcItem do begin FPacker:= Section; FArchiver:= FixExeExt(TrimQuotes(IniFile.ReadString(Section, 'Archiver', EmptyStr))); FDescription:= TrimQuotes(IniFile.ReadString(Section, 'Description', EmptyStr)); FID:= TrimQuotes(IniFile.ReadString(Section, 'ID', EmptyStr)); FIDPos:= TrimQuotes(IniFile.ReadString(Section, 'IDPos', EmptyStr)); FIDSeekRange:= IniFile.ReadString(Section, 'IDSeekRange', EmptyStr); FExtension:= TrimQuotes(IniFile.ReadString(Section, 'Extension', EmptyStr)); FStart:= TrimQuotes(IniFile.ReadString(Section, 'Start', EmptyStr)); FEnd:= TrimQuotes(IniFile.ReadString(Section, 'End', EmptyStr)); for J:= 0 to 50 do begin Format:= TrimQuotes(IniFile.ReadString(Section, 'Format' + IntToStr(J), EmptyStr)); if Format <> EmptyStr then FFormat.Add(Format) else Break; end; FList:= TrimQuotes(IniFile.ReadString(Section, 'List', EmptyStr)); FExtract:= TrimQuotes(IniFile.ReadString(Section, 'Extract', EmptyStr)); FExtractWithoutPath:= TrimQuotes(IniFile.ReadString(Section, 'ExtractWithoutPath', EmptyStr)); FTest:= TrimQuotes(IniFile.ReadString(Section, 'Test', EmptyStr)); FDelete:= TrimQuotes(IniFile.ReadString(Section, 'Delete', EmptyStr)); FAdd:= TrimQuotes(IniFile.ReadString(Section, 'Add', EmptyStr)); FAddSelfExtract:= TrimQuotes(IniFile.ReadString(Section, 'AddSelfExtract', EmptyStr)); FPasswordQuery:= IniFile.ReadString(Section, 'PasswordQuery', EmptyStr); // optional FFlags:= TMultiArcFlags(IniFile.ReadInteger(Section, 'Flags', 0)); FFormMode:= IniFile.ReadInteger(Section, 'FormMode', 0); FEnabled:= IniFile.ReadBool(Section, 'Enabled', True); FOutput:= IniFile.ReadBool(Section, 'Output', False); FDebug:= IniFile.ReadBool(Section, 'Debug', False); end; FList.AddObject(Section, MultiArcItem); end; if FirstTime then try AutoConfigure; SaveToFile(FileName); except // Ignore end; finally FreeAndNil(IniFile); FreeAndNil(Sections); end; end; procedure TMultiArcList.SaveToFile(const FileName: String); var I, J: Integer; IniFile: TIniFileEx; Section: String; MultiArcItem: TMultiArcItem; begin IniFile:= TIniFileEx.Create(FileName, fmOpenWrite); try for I:= 0 to FList.Count - 1 do begin Section:= FList.Strings[I]; MultiArcItem:= TMultiArcItem(FList.Objects[I]); with MultiArcItem do begin IniFile.WriteString(Section, 'Archiver', FArchiver); IniFile.WriteString(Section, 'Description', FDescription); IniFile.WriteString(Section, 'ID', FID); IniFile.WriteString(Section, 'IDPos', FIDPos); IniFile.WriteString(Section, 'IDSeekRange', FIDSeekRange); IniFile.WriteString(Section, 'Extension', FExtension); IniFile.WriteString(Section, 'Start', FStart); IniFile.WriteString(Section, 'End', FEnd); for J:= 0 to FFormat.Count - 1 do begin IniFile.WriteString(Section, 'Format' + IntToStr(J), FFormat[J]); end; IniFile.WriteString(Section, 'List', FList); IniFile.WriteString(Section, 'Extract', FExtract); IniFile.WriteString(Section, 'ExtractWithoutPath', FExtractWithoutPath); IniFile.WriteString(Section, 'Test', FTest); IniFile.WriteString(Section, 'Delete', FDelete); IniFile.WriteString(Section, 'Add', FAdd); IniFile.WriteString(Section, 'AddSelfExtract', FAddSelfExtract); IniFile.WriteString(Section, 'PasswordQuery', FPasswordQuery); // optional IniFile.WriteInteger(Section, 'Flags', Integer(FFlags)); IniFile.WriteInteger(Section, 'FormMode', FFormMode); IniFile.WriteBool(Section, 'Enabled', FEnabled); IniFile.WriteBool(Section, 'Output', FOutput); IniFile.WriteBool(Section, 'Debug', FDebug); end; end; IniFile.WriteBool('MultiArc', 'FirstTime', False); IniFile.UpdateFile; finally IniFile.Free; end; end; function TMultiArcList.Add(const S: String; aMultiArcItem: TMultiArcItem): Integer; begin Result := FList.AddObject(S, aMultiArcItem); end; function TMultiArcList.Insert(Index: integer; const S: string; aMultiArcItem: TMultiArcItem): integer; begin try FList.InsertObject(Index, S, aMultiArcItem); Result := Index; except Result := -1; end; end; procedure TMultiArcList.Delete(Index: Integer); begin Items[Index].Free; FList.Delete(Index); end; function TMultiArcList.Clone: TMultiArcList; var Index: integer; begin Result := TMultiArcList.Create; for Index := 0 to pred(Self.Count) do Result.Add(Self.FList.Strings[Index], Self.Items[Index].Clone); end; { TMultiArcList.ComputeSignature } // Routine tries to pickup all char chain from element of all entries and compute a unique CRC32. // This CRC32 will be a kind of signature of the MultiArc settings. function TMultiArcList.ComputeSignature(Seed: dword): dword; procedure UpdateSignature(sInfo: string); begin if length(sInfo) > 0 then Result := crc32(Result, @sInfo[1], length(sInfo)); end; var Index, iInnerIndex: integer; begin Result := Seed; for Index := 0 to pred(Count) do begin UpdateSignature(Self.FList.Strings[Index]); UpdateSignature(Self.Items[Index].FDescription); UpdateSignature(Self.Items[Index].FArchiver); UpdateSignature(Self.Items[Index].FExtension); UpdateSignature(Self.Items[Index].FList); UpdateSignature(Self.Items[Index].FStart); UpdateSignature(Self.Items[Index].FEnd); for iInnerIndex := 0 to pred(Self.Items[Index].FFormat.Count) do UpdateSignature(Self.Items[Index].FFormat.Strings[iInnerIndex]); UpdateSignature(Self.Items[Index].FExtract); UpdateSignature(Self.Items[Index].FAdd); UpdateSignature(Self.Items[Index].FDelete); UpdateSignature(Self.Items[Index].FTest); UpdateSignature(Self.Items[Index].FExtractWithoutPath); UpdateSignature(Self.Items[Index].FAddSelfExtract); UpdateSignature(Self.Items[Index].FPasswordQuery); UpdateSignature(Self.Items[Index].FID); UpdateSignature(Self.Items[Index].FIDPos); UpdateSignature(Self.Items[Index].FIDSeekRange); Result := crc32(Result, @Self.Items[Index].FFlags, sizeof(Self.Items[Index].FFlags)); Result := crc32(Result, @Self.Items[Index].FFormMode, sizeof(Self.Items[Index].FFormMode)); Result := crc32(Result, @Self.Items[Index].FEnabled, sizeof(Self.Items[Index].FEnabled)); Result := crc32(Result, @Self.Items[Index].FOutput, sizeof(Self.Items[Index].FOutput)); Result := crc32(Result, @Self.Items[Index].FDebug, sizeof(Self.Items[Index].FDebug)); end; end; { TMultiArcItem } function TMultiArcItem.GetSignatureSeekRange: AnsiString; begin if FSignatureSeekRange = SignSeekRange then Result:= EmptyStr else Result:= IntToStr(FSignatureSeekRange); end; procedure TMultiArcItem.SetExtension(const AValue: String); var AMask: String; Index: Integer; AMaskList: TStringArray; begin if FExt <> AValue then begin FExt:= AValue; AMask:= EmptyStr; FreeAndNil(FMaskList); AMaskList:= SplitString(AValue, ','); for Index:= Low(AMaskList) to High(AMaskList) do begin AddStrWithSep(AMask, AllFilesMask + ExtensionSeparator + AMaskList[Index], ','); end; FMaskList:= TMaskList.Create(AMask, ','); end; end; procedure TMultiArcItem.SetSignature(const AValue: AnsiString); var I: Integer; Sign: AnsiString; Value: AnsiString; Signature: PSignature; begin FSignature:= AValue; FSignatureList.Clean; if AValue = EmptyStr then Exit; Value:= AValue; repeat I:= 0; New(Signature); Sign:= Trim(Copy2SymbDel(Value, ',')); try while (Sign <> EmptyStr) and (I < MaxSignSize) do begin Signature^.Value[I]:= StrToInt('$' + Copy2SymbDel(Sign, #32)); Inc(I); end; Signature^.Size:= I; FSignatureList.Add(Signature); except Dispose(Signature); end; until Value = EmptyStr; end; procedure TMultiArcItem.SetSignaturePosition(const AValue: AnsiString); var SignPos, Value: AnsiString; SignaturePosition: PSignaturePosition; begin FSignaturePosition:= AValue; FSignaturePositionList.Clean; if AValue = EmptyStr then Exit; Value:= StringReplace(AValue, '0x', '$', [rfReplaceAll]); repeat SignPos:= Trim(Copy2SymbDel(Value, ',')); if SignPos = '' then FSeekAfterSignPos:= True else try New(SignaturePosition); SignaturePosition^.Value:= StrToInt(SignPos); SignaturePosition^.Sign:= not (SignaturePosition^.Value < 0); SignaturePosition^.Value:= abs(SignaturePosition^.Value); FSignaturePositionList.Add(SignaturePosition); except Dispose(SignaturePosition); end; until Value = EmptyStr; end; procedure TMultiArcItem.SetSignatureSeekRange(const AValue: AnsiString); begin if not TryStrToInt(AValue, FSignatureSeekRange) then FSignatureSeekRange:= SignSeekRange; end; constructor TMultiArcItem.Create; begin FSignatureList:= TSignatureList.Create; FSignaturePositionList:= TSignaturePositionList.Create; FFormat:= TStringList.Create; end; destructor TMultiArcItem.Destroy; begin FreeAndNil(FMaskList); FreeAndNil(FSignatureList); FreeAndNil(FSignaturePositionList); FreeAndNil(FFormat); inherited Destroy; end; function TMultiArcItem.Matches(const AFileName: String): Boolean; begin if (FMaskList = nil) then Result:= False else Result:= FMaskList.Matches(AFileName); end; function TMultiArcItem.CanYouHandleThisFile(const FileName: String): Boolean; var FileMapRec : TFileMapRec; hFile: THandle; I, J: LongInt; lpBuffer: PByte = nil; Origin: LongInt; dwMaxSignSize: LongWord = 0; dwReaded: LongWord; dwOffset: LongWord = 0; begin Result:= False; hFile:= mbFileOpen(FileName, fmOpenRead or fmShareDenyNone); if hFile <> feInvalidHandle then begin // Determine maximum signature size for J:= 0 to FSignatureList.Count - 1 do dwMaxSignSize := Max(FSignatureList[J]^.Size, dwMaxSignSize); { if (FSkipSfxPart) then dwOffset := FSfxOffset } lpBuffer:= GetMem(dwMaxSignSize); if Assigned(lpBuffer) then try // Try to determine by IDPOS for I:= 0 to FSignaturePositionList.Count - 1 do begin case FSignaturePositionList[I]^.Sign of True: Origin:= fsFromBeginning; False: Origin:= fsFromEnd; end; if (FileSeek(hFile, dwOffset + FSignaturePositionList[I]^.Value, Origin) <> -1) then begin dwReaded:= FileRead(hFile, lpBuffer^, dwMaxSignSize); if (dwReaded = dwMaxSignSize) then begin for J := 0 to FSignatureList.Count - 1 do begin if(CompareByte(lpBuffer^, FSignatureList[J]^.Value, FSignatureList[J]^.Size) = 0) then Exit(True); end; end; end; end; finally FreeMem(lpBuffer); FileClose(hFile); end; // if Assigned(lpBuffer) end; // Try raw seek id if (Result = False) and FSeekAfterSignPos then begin FillByte(FileMapRec, SizeOf(FileMapRec), 0); if MapFile(FileName, FileMapRec) then try dwOffset:= Min(FSignatureSeekRange, FileMapRec.FileSize); for I:= 0 to dwOffset do begin for J:= 0 to FSignatureList.Count - 1 do begin if(CompareByte((FileMapRec.MappedFile + I)^, FSignatureList[J]^.Value, FSignatureList[J]^.Size) = 0) then Exit(True); end; end; finally UnMapFile(FileMapRec); end; end; end; function TMultiArcItem.Clone: TMultiArcItem; begin Result := TMultiArcItem.Create; //Keep elements in some ordre a when loading them from the .ini, it will be simpler to validate if we are missing one. Result.FPacker := Self.FPacker; Result.FArchiver := Self.FArchiver; Result.FDescription := Self.FDescription; Result.FID := Self.FID; Result.FIDPos := Self.FIDPos; Result.FIDSeekRange := Self.FIDSeekRange; Result.FExtension := Self.FExtension; Result.FStart := Self.FStart; Result.FEnd := Self.FEnd; Result.FFormat.Assign(Self.FFormat); Result.FList := Self.FList; Result.FExtract := Self.FExtract; Result.FExtractWithoutPath := Self.FExtractWithoutPath; Result.FTest := Self.FTest; Result.FDelete := Self.FDelete; Result.FAdd := Self.FAdd; Result.FAddSelfExtract := Self.FAddSelfExtract; Result.FPasswordQuery := Self.FPasswordQuery; Result.FFlags := Self.FFlags; Result.FFormMode := Self.FFormMode; Result.FEnabled := Self.FEnabled; Result.FOutput := Self.FOutput; Result.FDebug := Self.FDebug; end; { TSignatureList } function TSignatureList.GetSignature(Index: Integer): PSignature; begin Result:= PSignature(Get(Index)); end; destructor TSignatureList.Destroy; begin Clean; inherited Destroy; end; procedure TSignatureList.Clean; var I: Integer; begin for I:= Count - 1 downto 0 do begin Dispose(Items[I]); Delete(I); end; end; { TSignaturePositionList } function TSignaturePositionList.GetSignaturePosition(Index: Integer): PSignaturePosition; begin Result:= PSignaturePosition(Get(Index)); end; destructor TSignaturePositionList.Destroy; begin Clean; inherited Destroy; end; procedure TSignaturePositionList.Clean; var I: Integer; begin for I:= Count - 1 downto 0 do begin Dispose(Items[I]); Delete(I); end; end; end. doublecmd-1.1.22/src/un_lineinfo.pp0000644000175000001440000007066714743153644016263 0ustar alexxusers{ This file is part of the chelinfo library. Copyright (c) 2008 by Anton Rzheshevski Parts (c) 2006 Thomas Schatzl, member of the FreePascal Development team Parts (c) 2000 Peter Vreman (adapted from original stabs line reader) Dwarf LineInfo Extractor See the file COPYING.FPC, included in this distribution, for details about the copyright. 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. **********************************************************************} { 2008, Anton Rzheshevski aka Cheb: Like dr. Frankenshtein I sewn this library together from the dead meat of the the FPC RTL modules lineinfo.pp and lnfodwrf.pp. These (as of Jan. 2008 / FPC 2.2.0) both didn't work and had several limitations (e.g. inability to be used from a DLL) SUPPORTED TARGETS: Linux-32, Linux-64, Win32, Win64. Based on lnfodwrf.pp from FreePascal RTL. Oct 2009, by cobines - Removed the structures holding debugging info. Now the state machine is run for each address requiring line info, like in lnfodwrf.pp. It uses less memory but is slower. But since it is usually called only on unhandled exceptions the speed doesn't matter much. - Updated the code to lnfodwrf.pp from FPC 2.5.1 (rev. 14154). } {--------------------------------------------------------------------------- Generic Dwarf lineinfo reader The line info reader is based on the information contained in DWARF Debugging Information Format Version 3 Chapter 6.2 "Line Number Information" from the DWARF Debugging Information Format Workgroup. For more information on this document see also http://dwarf.freestandards.org/ ---------------------------------------------------------------------------} {$mode delphi} {$longstrings on} {$codepage utf-8} {$coperators on} {$pointermath on} {.$DEFINE DEBUG_DWARF_PARSER} unit un_lineinfo; interface uses SysUtils, Classes; function GetLineInfo(addr: pointer; var moduleFile, sourceFile: ansistring; var line, column: integer): Boolean; { The format of returned information: "moduleFile" *always* receives the full name of the executable file (the main exe or one of dlls it uses) the addr belongs to. In Linux, it returns the real file name, with all symlinks resolved. "line" can be negative, which means no line info has been found for this address. See LineInfoError (below) for details. "sourceFile" returns the source file name. It either doesn't or does contain a full path. If the source was in the same directory as the program itself, there will be no path. If the source was in the different directory, there will be a full path (for the moment when the program was compiled, NOT for the current location of that source). "column" is positive ONLY when there is more than one address stored for the same source line. FreePascal generates this on VERY rare occasions, mostly for the arithmetic formulas spanning several lines. So most of the time column will receive -1. } procedure InitLineInfo; { Installs the custom BackTraceStr handler. } procedure AddLineInfoPath(const Path: String); { Adds a path that will be searched for .zdli files. Paths can be absolute or relative to the directory with the executable module. } procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string); { This function allows you to know which executable (i.e. the main exe or one of the dlls loaded by it) owns this part of the virtual addres space. baseaddr receives the exe/dll base address (always NIL for the main exe in Linux). The mechnaism is made with possibility of a DLL relocation in mind, but that particular feature is untested. This function is used by GetLineInfo() to determine which executable to load line the info from. } var LineInfoError: WideString = ''; implementation uses {$ifdef unix} dl {$else} windows {$endif} , un_xtrctdwrflnfo, zstream; {$MACRO ON} {$ifdef DEBUG_DWARF_PARSER} {$define DEBUG_WRITELN := WriteLn} {$define DEBUG_COMMENT := } {$else} {$define DEBUG_WRITELN := //} {$define DEBUG_COMMENT := //} {$endif} var {You can store the .zdli files in a different folder than the Exe itself. Just fill in this array. Paths can be absolute or relative to BaseModulePath. For example: AddLineInfoPath('debug') - will search in /debug/ } LineInfoPaths: array of string = nil; {Path where the executable module is.} BaseModulePath: String; function ChelinfoBackTraceStr(addr : Pointer) : ShortString; var exe, src: ansistring; line, column: integer; Store : TBackTraceStrFunc; begin { reset to prevent infinite recursion if problems inside the code } Store := BackTraceStrFunc; BackTraceStrFunc := @SysBackTraceStr; GetLineInfo(addr, exe, src, line, column); { create string } Result := ' $' + HexStr(addr); if line >= 0 then begin Result += ' line ' + IntToStr(line); if column >= 0 then Result += ', column ' + IntToStr(column); Result += ' of ' + src; end; Result += ' in ' + exe; BackTraceStrFunc := Store; end; {$packrecords default} type Bool8 = ByteBool; { DWARF 2 default opcodes} const { Extended opcodes } DW_LNE_END_SEQUENCE = 1; DW_LNE_SET_ADDRESS = 2; DW_LNE_DEFINE_FILE = 3; { Standard opcodes } DW_LNS_COPY = 1; DW_LNS_ADVANCE_PC = 2; DW_LNS_ADVANCE_LINE = 3; DW_LNS_SET_FILE = 4; DW_LNS_SET_COLUMN = 5; DW_LNS_NEGATE_STMT = 6; DW_LNS_SET_BASIC_BLOCK = 7; DW_LNS_CONST_ADD_PC = 8; DW_LNS_FIXED_ADVANCE_PC = 9; DW_LNS_SET_PROLOGUE_END = 10; DW_LNS_SET_EPILOGUE_BEGIN = 11; DW_LNS_SET_ISA = 12; type { state record for the line info state machine } TMachineState = record address : QWord; // can hold 32-bit or 64-bit addresses (depending on DWARF type) file_id : DWord; line : QWord; column : DWord; is_stmt : Boolean; basic_block : Boolean; end_sequence : Boolean; prolouge_end : Boolean; epilouge_begin : Boolean; isa : QWord; append_row : Boolean; first_row : Boolean; end; { DWARF line number program header preceding the line number program, 64 bit version } TLineNumberProgramHeader64 = packed record magic : DWord; unit_length : QWord; version : Word; length : QWord; minimum_instruction_length : Byte; default_is_stmt : Bool8; line_base : ShortInt; line_range : Byte; opcode_base : Byte; end; { DWARF line number program header preceding the line number program, 32 bit version } TLineNumberProgramHeader32 = packed record unit_length : DWord; version : Word; length : DWord; minimum_instruction_length : Byte; default_is_stmt : Bool8; line_base : ShortInt; line_range : Byte; opcode_base : Byte; end; procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string); {$ifdef unix} var dlinfo: dl_info; begin FillChar(dlinfo, sizeof(dlinfo), 0); dladdr(addr, @dlinfo); baseaddr:= dlinfo.dli_fbase; filename:= String(dlinfo.dli_fname); {$if not defined(darwin)} if ExtractFileName(filename) = ExtractFileName(ParamStr(0)) then baseaddr:= nil; {$endif} end; {$else} var Tmm: TMemoryBasicInformation; TST: array[0..Max_Path] of Char; begin if VirtualQuery(addr, @Tmm, SizeOf(Tmm)) <> sizeof(Tmm) then raise Exception.Create('The VirualQuery() call failed.'); baseaddr:=Tmm.AllocationBase; TST[0]:= #0; GetModuleFileName(THandle(Tmm.AllocationBase), TST, SizeOf(TST)); filename:= String(PChar(@TST)); end; {$endif} procedure InitLineInfo; begin BackTraceStrFunc := @ChelinfoBacktraceStr; BaseModulePath := ExtractFilePath(ParamStr(0)); end; procedure AddLineInfoPath(const Path: String); begin SetLength(LineInfoPaths, Length(LineInfoPaths) + 1); LineInfoPaths[Length(LineInfoPaths) - 1] := ExcludeTrailingPathDelimiter(Path); end; function GetLineInfo(addr: Pointer; var moduleFile, sourceFile: ansistring; var line, column: integer): Boolean; var dli: TStream = nil; // Stream holding uncompressed debug line info. unit_base, next_base : QWord; unit_length: QWord; { Returns the next Byte from the input stream, or -1 if there has been an error } function ReadNext() : Longint; overload; var bytesread : Longint; b : Byte; begin ReadNext := -1; if (dli.Position < next_base) then begin bytesread := dli.Read(b, sizeof(b)); ReadNext := b; if (bytesread <> 1) then ReadNext := -1; end; end; { Reads the next size bytes into dest. Returns true if successful, false otherwise. Note that dest may be partially overwritten after returning false. } function ReadNext(var dest; size : SizeInt) : Boolean; overload; var bytesread : SizeInt; begin bytesread := 0; if ((dli.Position + size) < next_base) then begin bytesread := dli.Read(dest, size); end; ReadNext := (bytesread = size); end; { Reads an unsigned LEB encoded number from the input stream } function ReadULEB128() : QWord; var shift : Byte; data : PtrInt; val : QWord; begin shift := 0; result := 0; data := ReadNext(); while (data <> -1) do begin val := data and $7f; result := result or (val shl shift); inc(shift, 7); if ((data and $80) = 0) then break; data := ReadNext(); end; end; { Reads a signed LEB encoded number from the input stream } function ReadLEB128() : Int64; var shift : Byte; data : PtrInt; val : Int64; begin shift := 0; result := 0; data := ReadNext(); while (data <> -1) do begin val := data and $7f; result := result or (val shl shift); inc(shift, 7); if ((data and $80) = 0) then break; data := ReadNext(); end; { extend sign. Note that we can not use shl/shr since the latter does not translate to arithmetic shifting for signed types } result := (not ((result and (1 shl (shift-1)))-1)) or result; end; procedure SkipULEB128(); var temp : QWord; begin temp := ReadULEB128(); DEBUG_WRITELN('Skipping ULEB128 : ', temp); end; procedure SkipLEB128(); var temp : Int64; begin temp := ReadLEB128(); DEBUG_WRITELN('Skipping LEB128 : ', temp); end; function ReadString(): ansistring; var a: ansichar; begin Result:= ''; while (true) do begin dli.Read(a, sizeof(a)); if a = #0 then Exit; Result+= a; end; end; function CalculateAddressIncrement(_opcode : Integer; const header : TLineNumberProgramHeader64) : Int64; begin Result := _opcode - header.opcode_base; // adjusted_opcode Result := (Result div header.line_range) * header.minimum_instruction_length; end; { initializes the line info state to the default values } procedure InitStateRegisters(var state : TMachineState; const header : TLineNumberProgramHeader64); begin with state do begin address := 0; file_id := 1; line := 1; column := 0; is_stmt := header.default_is_stmt; basic_block := false; end_sequence := false; prolouge_end := false; epilouge_begin := false; isa := 0; append_row := false; first_row := true; end; end; { Skips all line info directory entries } procedure SkipDirectories(); var s : ShortString; begin while (true) do begin s := ReadString(); if (s = '') then break; DEBUG_WRITELN('Skipping directory : ', s); end; end; { Skips the filename section from the current file stream } procedure SkipFilenames(); var s : ShortString; begin while (true) do begin s := ReadString(); if (s = '') then break; DEBUG_WRITELN('Skipping filename : ', s); SkipULEB128(); { skip the directory index for the file } SkipULEB128(); { skip last modification time for file } SkipULEB128(); { skip length of file } end; end; function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString; var i : DWord; filename, directory : ShortString; dirindex : QWord; {$IFDEF DEBUG_DWARF_PARSER} oldPos: Int64; {$ENDIF} begin filename := ''; directory := ''; i := 1; {$IFDEF DEBUG_DWARF_PARSER} oldPos := dli.Position; {$ENDIF} dli.Seek(filenameStart, soBeginning); while (i <= file_id) do begin filename := ReadString(); DEBUG_WRITELN('Found "', filename, '"'); if (filename = '') then break; dirindex := ReadULEB128(); { read the directory index for the file } SkipULEB128(); { skip last modification time for file } SkipULEB128(); { skip length of file } inc(i); end; { if we could not find the file index, exit } if (filename = '') then begin GetFullFilename := ''; end else begin dli.Seek(directoryStart, soBeginning); i := 1; while (i <= dirindex) do begin directory := ReadString(); if (directory = '') then break; inc(i); end; if (directory<>'') and (directory[length(directory)]<>'/') then directory:=directory+'/'; GetFullFilename := directory + filename; end; {$IFDEF DEBUG_DWARF_PARSER} dli.Position := oldPos; {$ENDIF} end; function ParseCompilationUnit(const addr : PtrUInt) : Boolean; var state : TMachineState; { we need both headers on the stack, although we only use the 64 bit one internally } header64 : TLineNumberProgramHeader64; header32 : TLineNumberProgramHeader32; header_length: QWord; {$ifdef DEBUG_DWARF_PARSER}s : ShortString;{$endif} adjusted_opcode : Int64; opcode, extended_opcode : Integer; extended_opcode_length : PtrInt; addrIncrement, lineIncrement: PtrInt; numoptable : array[1..255] of Byte; { the offset into the file where the include directories are stored for this compilation unit } include_directories : Int64; { the offset into the file where the file names are stored for this compilation unit } file_names : Int64; i: integer; prev_line : QWord; prev_column : DWord; prev_file : DWord; { Reads an address from the current input stream } function ReadAddress() : PtrUInt; begin ReadNext(Result, sizeof(PtrUInt)); end; { Reads an unsigned Half from the current input stream } function ReadUHalf() : Word; begin dli.Read(Result, SizeOf(Result)); end; begin Result := False; // Not found yet. // First DWORD is either unit length of 32-bit or magic value of 64-bit DWARF. dli.Seek(unit_base, soBeginning); dli.Read(header64.magic, sizeof(header64.magic)); dli.Seek(-sizeof(header64.magic), soCurrent); if (header64.magic <> $ffffffff) then begin DEBUG_WRITELN('32 bit DWARF detected'); dli.Read(header32, sizeof(header32)); header64.magic := $ffffffff; header64.unit_length := header32.unit_length; header64.version := header32.version; header64.length := header32.length; header64.minimum_instruction_length := header32.minimum_instruction_length; header64.default_is_stmt := header32.default_is_stmt; header64.line_base := header32.line_base; header64.line_range := header32.line_range; header64.opcode_base := header32.opcode_base; header_length := QWord(header32.length) + sizeof(header32.length) + sizeof(header32.version) + sizeof(header32.unit_length); unit_length := QWord(header32.unit_length) + sizeof(header32.unit_length); end else begin DEBUG_WRITELN('64 bit DWARF detected'); dli.Read(header64, sizeof(header64)); header_length := header64.length + sizeof(header64.magic) + sizeof(header64.length) + sizeof(header64.version) + sizeof(header64.unit_length); unit_length := header64.unit_length + sizeof(header64.magic) + sizeof(header64.unit_length); end; next_base:= unit_base + unit_length; // Read opcodes lengths table. fillchar(numoptable, sizeof(numoptable), #0); if not ReadNext(numoptable, header64.opcode_base - 1) then Exit; DEBUG_WRITELN('Opcode parameter count table'); for i := 1 to header64.opcode_base - 1 do begin DEBUG_WRITELN('Opcode[', i, '] - ', numoptable[i], ' parameters'); end; DEBUG_WRITELN('Reading directories...'); include_directories := dli.Position; SkipDirectories(); DEBUG_WRITELN('Reading filenames...'); file_names := dli.Position; SkipFilenames(); // Position stream after header to read state machine code. dli.Seek(unit_base + header_length, soBeginning); InitStateRegisters(state, header64); opcode := ReadNext(); while (opcode <> -1) do begin case (opcode) of { extended opcode } 0 : begin extended_opcode_length := ReadULEB128(); extended_opcode := ReadNext(); if extended_opcode = -1 then break; case (extended_opcode) of DW_LNE_END_SEQUENCE : begin state.end_sequence := true; state.append_row := true; DEBUG_WRITELN('DW_LNE_END_SEQUENCE'); end; DW_LNE_SET_ADDRESS : begin // Size of address should be extended_opcode_length - 1. state.address := ReadAddress(); DEBUG_WRITELN('DW_LNE_SET_ADDRESS (', hexstr(pointer(state.address)), ')'); end; DW_LNE_DEFINE_FILE : begin {$ifdef DEBUG_DWARF_PARSER}s := {$endif}ReadString(); SkipULEB128(); SkipULEB128(); SkipULEB128(); DEBUG_WRITELN('DW_LNE_DEFINE_FILE (', s, ')'); end; else begin DEBUG_WRITELN('Unknown extended opcode ', extended_opcode, ' (length ', extended_opcode_length, ')'); dli.Position:= dli.Position + extended_opcode_length - 1; end; end; end; DW_LNS_COPY : begin state.basic_block := false; state.prolouge_end := false; state.epilouge_begin := false; state.append_row := true; DEBUG_WRITELN('DW_LNS_COPY'); end; DW_LNS_ADVANCE_PC : begin state.address := state.address + ReadULEB128() * header64.minimum_instruction_length; DEBUG_WRITELN('DW_LNS_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')'); end; DW_LNS_ADVANCE_LINE : begin state.line := state.line + ReadLEB128(); DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')'); end; DW_LNS_SET_FILE : begin state.file_id := ReadULEB128(); DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')'); end; DW_LNS_SET_COLUMN : begin state.column := ReadULEB128(); DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')'); end; DW_LNS_NEGATE_STMT : begin state.is_stmt := not state.is_stmt; DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')'); end; DW_LNS_SET_BASIC_BLOCK : begin state.basic_block := true; DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK'); end; DW_LNS_CONST_ADD_PC : begin state.address := state.address + CalculateAddressIncrement(255, header64); DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')'); end; DW_LNS_FIXED_ADVANCE_PC : begin state.address := state.address + ReadUHalf(); DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')'); end; DW_LNS_SET_PROLOGUE_END : begin state.prolouge_end := true; DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END'); end; DW_LNS_SET_EPILOGUE_BEGIN : begin state.epilouge_begin := true; DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN'); end; DW_LNS_SET_ISA : begin state.isa := ReadULEB128(); DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')'); end; else begin { special opcode } if (opcode < header64.opcode_base) then begin DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping'); for i := 1 to numoptable[opcode] do SkipLEB128(); end else begin adjusted_opcode := opcode - header64.opcode_base; addrIncrement := CalculateAddressIncrement(opcode, header64); state.address := state.address + addrIncrement; lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range); state.line := state.line + lineIncrement; DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement); state.basic_block := false; state.prolouge_end := false; state.epilouge_begin := false; state.append_row := true; end; end; end; //case if (state.append_row) then begin {$IFDEF DEBUG_DWARF_PARSER} Writeln('Address = ', hexstr(pointer(state.address)), ', file_id = ', state.file_id, ', file = ' , GetFullFilename(file_names, include_directories, state.file_id), ', line = ', state.line, ' column = ', state.column); {$ENDIF} if (state.first_row) then begin if (state.address > addr) then break; state.first_row := false; end; { when we have found the address we need to return the previous line because that contains the call instruction } if (state.address >= addr) then begin line := prev_line; column := prev_column; sourceFile := GetFullFilename(file_names, include_directories, prev_file); Exit(True); end else begin { save line information } prev_file := state.file_id; prev_line := state.line; prev_column := state.column; end; state.append_row := false; if (state.end_sequence) then begin // Reset state machine when sequence ends. InitStateRegisters(state, header64); end; end; opcode := ReadNext(); end; //while end; type TPathType = ( ptNone, ptRelative, ptAbsolute ); function GetPathType(sPath : String): TPathType; begin Result := ptNone; {$IFDEF MSWINDOWS} {check for drive/unc info} if ( Pos( '\\', sPath ) > 0 ) or ( Pos( DriveDelim, sPath ) > 0 ) then {$ENDIF MSWINDOWS} {$IFDEF UNIX} { UNIX absolute paths start with a slash } if (sPath[1] = PathDelim) then {$ENDIF UNIX} Result := ptAbsolute else if ( Pos( PathDelim, sPath ) > 0 ) then Result := ptRelative; end; function ExpandAbsolutePath(Path: String): String; var I, J: Integer; begin {First remove all references to '\.\'} I := Pos (DirectorySeparator + '.' + DirectorySeparator, Path); while I <> 0 do begin Delete (Path, I, 2); I := Pos (DirectorySeparator + '.' + DirectorySeparator, Path); end; {Then remove all references to '\..\'} I := Pos (DirectorySeparator + '..', Path); while (I <> 0) do begin J := Pred (I); while (J > 0) and (Path [J] <> DirectorySeparator) do Dec (J); if (J = 0) then Delete (Path, I, 3) else Delete (Path, J, I - J + 3); I := Pos (DirectorySeparator + '..', Path); end; Result := Path; end; function GetAbsoluteFileName(const sPath, sRelativeFileName : String) : String; begin case GetPathType(sRelativeFileName) of ptNone, ptRelative: Result := ExpandAbsolutePath(sPath + sRelativeFileName); else Result := sRelativeFileName; end; end; var i: Integer; dc, ts: TStream; DwarfLineInfo: Pointer; externalFile: AnsiString; DwarfSize: Qword; base_addr: Pointer; ExeImageBase: QWord; begin Result := False; moduleFile := ''; sourceFile := ''; line := -1; column := -1; LineInfoError:= ''; GetModuleByAddr(addr, base_addr, moduleFile); if moduleFile = '' then Exit(False); // No module found at this address. // Never read modules or .zdli files from current directory. // If module path is relative make it relative to BaseModulePath. // (for example ./doublecmd must be expanded). moduleFile := GetAbsoluteFileName(BaseModulePath, moduleFile); DEBUG_WRITELN('Module ', moduleFile, ' at $', hexStr(base_addr)); try try { First, try the external file with line information. Failing that, try to parse the executable itself } externalFile := DlnNameByExename(moduleFile); i:= -1; repeat DEBUG_WRITELN('Checking external file: ', externalFile); if FileExists(externalFile) then break else externalFile := ''; inc(i); if i > high(LineInfoPaths) then break; // Check additional paths. externalFile := GetAbsoluteFileName(BaseModulePath, LineInfoPaths[i]); externalFile := IncludeTrailingPathDelimiter(externalFile) + DlnNameByExename(ExtractFileName(moduleFile)); until False; if externalFile <> '' //and (FileAge(moduleFile) <= FileAge(externalFile)) then begin DEBUG_WRITELN('Reading debug info from external file ', externalFile); //the compression streams are unable to seek, //so we decompress to a memory stream first. ts := TFileStream.Create(externalFile, fmOpenRead or fmShareDenyNone); dc := TDecompressionStream.Create(ts); dli := TMemoryStream.Create; dc.Read(DwarfSize, SizeOf(DwarfSize)); // 8 bytes (QWORD) dc.Read(ExeImageBase, SizeOf(ExeImageBase)); // 8 bytes (QWORD) dli.CopyFrom(dc, DwarfSize); FreeAndNil(dc); FreeAndNil(ts); end else begin DEBUG_WRITELN('Reading debug info from ', moduleFile); if not ExtractDwarfLineInfo(moduleFile, DwarfLineInfo, DwarfSize, ExeImageBase) then begin DEBUG_WRITELN('Debug info not found.'); LineInfoError:= ExtractDwarfLineInfoError; Exit(false); end; dli:= TMemoryStream.Create; dli.Write(DwarfLineInfo^, DwarfSize); FreeMem(DwarfLineInfo); end; DEBUG_WRITELN('dwarf line info: ', dli.size, ' bytes.'); // Account for the possible relocation (in 99% cases ExeImagebase = base_addr) {$PUSH} {$overflowchecks off} {$rangechecks off} {$warnings off} addr := addr - base_addr + Pointer(ExeImageBase); {$POP} next_base := 0; while next_base < dli.Size do begin unit_base := next_base; if ParseCompilationUnit(PtrUInt(addr)) then break; // Found line info end; Result := True; except LineInfoError := 'Crashed parsing the dwarf line info: ' + (ExceptObject as Exception).Message; Result := False; end; finally if Assigned(dli) then FreeAndNil(dli); end; if not Result then DEBUG_WRITELN('Cannot read DWARF debug line info: ', LineInfoError); end; initialization InitLineInfo; end. doublecmd-1.1.22/src/un_process.pas0000644000175000001440000001005414743153644016262 0ustar alexxusersunit un_process; {$mode delphi}{$H+} interface uses Process, SysUtils, DCProcessUtf8; type TOnReadLn = procedure (str: String) of object; TOnOperationProgress = procedure of object; { TExProcess } TExProcess = class protected FProcess: TProcess; FOutputLine: String; FStop: Boolean; FQueryString: String; FOnReadLn, FOnQueryString: TOnReadLn; FOnProcessExit: TOnOperationProgress; FOnOperationProgress: TOnOperationProgress; function _GetExitStatus(): Integer; public constructor Create(CommandLine: String = ''); procedure Execute; procedure Stop; procedure SetCmdLine(CommandLine: String); destructor Destroy; override; property Process: TProcess read FProcess; property ExitStatus: Integer read _GetExitStatus; property QueryString: String read FQueryString write FQueryString; property OnReadLn: TOnReadLn read FOnReadLn write FOnReadLn; property OnQueryString: TOnReadLn read FOnQueryString write FOnQueryString; property OnProcessExit: TOnOperationProgress read FOnProcessExit write FOnProcessExit; property OnOperationProgress: TOnOperationProgress read FOnOperationProgress write FOnOperationProgress; end; implementation uses DCStrUtils; const BufferSize = 3000; { TExProcess } function TExProcess._GetExitStatus(): Integer; begin Result:= FProcess.ExitStatus; end; constructor TExProcess.Create(CommandLine: String = ''); begin FOutputLine:= EmptyStr; FProcess:= TProcessUtf8.Create(nil); FProcess.CommandLine:= CommandLine; FProcess.Options:= [poUsePipes, poNoConsole, poNewProcessGroup]; end; procedure TExProcess.Execute; var P: Integer; S, OutputBuffer: String; begin S:= EmptyStr; FProcess.Execute; try repeat if Assigned(FOnOperationProgress) then FOnOperationProgress(); if FStop then Exit; // If no output yet if FProcess.Output.NumBytesAvailable = 0 then begin if not FProcess.Running then Break else begin Sleep(1); if Assigned(FOnQueryString) and Assigned(FProcess.Stderr) and (FProcess.Stderr.NumBytesAvailable > 0) then begin SetLength(OutputBuffer, BufferSize); // Waits for the process output SetLength(OutputBuffer, FProcess.Stderr.Read(OutputBuffer[1], Length(OutputBuffer))); if (Pos(FQueryString, OutputBuffer) > 0) then FOnQueryString(OutputBuffer); OutputBuffer:= EmptyStr; end; Continue; end end; SetLength(OutputBuffer, BufferSize); // Waits for the process output SetLength(OutputBuffer, FProcess.Output.Read(OutputBuffer[1], Length(OutputBuffer))); // Cut the incoming stream to lines: FOutputLine:= FOutputLine + OutputBuffer; // Add to the accumulator P:= 1; while GetNextLine(FOutputLine, S, P) do begin if FStop then Exit; // Return the line without the CR/LF characters if Assigned(FOnReadLn) then FOnReadLn(S); // Update progress if Assigned(FOnOperationProgress) then FOnOperationProgress(); end; // Remove the processed lines from accumulator Delete(FOutputLine, 1, P - 1); // Check query string if Length(FOutputLine) > 0 then begin if Assigned(FOnQueryString) and (Pos(FQueryString, FOutputLine) <> 0) then begin FOnQueryString(FOutputLine); FOutputLine:= EmptyStr; end; end; // No more data, break if Length(OutputBuffer) = 0 then Break; until False; if FStop then Exit; if (Length(FOutputLine) <> 0) and Assigned(FOnReadLn) then FOnReadLn(FOutputLine); OutputBuffer:= EmptyStr; finally if Assigned(FOnProcessExit) then FOnProcessExit(); end; end; procedure TExProcess.Stop; begin FStop:= True; FProcess.Terminate(-1); end; procedure TExProcess.SetCmdLine(CommandLine: String); begin FProcess.CommandLine:= CommandLine; end; destructor TExProcess.Destroy; begin FreeAndNil(FProcess); end; end. doublecmd-1.1.22/src/un_xtrctdwrflnfo.pp0000644000175000001440000010461514743153644017355 0ustar alexxusers{ This file is part of the chelinfo library. Copyright (c) 2008 by Anton Rzheshevski Parts (c) 2006 Thomas Schatzl, member of the FreePascal Development team Parts (c) 2000 Peter Vreman (adapted from original stabs line reader) Dwarf LineInfo Extractor See the file COPYING.FPC, included in this distribution, for details about the copyright. 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. **********************************************************************} { 2008, Anton Rzheshevski aka Cheb: Like dr. Frankenshtein I sewn this library together from the dead meat of the the FPC RTL modules lineinfo.pp and lnfodwrf.pp. These as of Jan. 2008 / FPC 2.2.0 both didn't work and had several limitations (e.g. inability to be used from a DLL) Oct 2009, by cobines Now can extract from ELF32, ELF64, PE regardless of base platform (Linux and Win). Fixed reading .debug_line section from PE files (now long section name is used). Nov 2012, by alexx2000 Now can extract from Mach-O binary (Mac OS X, Intel 32 and 64 bit). } {$mode delphi} {$longstrings on} {$ifndef endian_little} {$fatal powerpc architecture not supported} {$endif} unit un_xtrctdwrflnfo; interface uses SysUtils, Classes; function ExtractDwarfLineInfo( ExeFileName: ansistring; out _dlnfo: pointer; out _dlnfoSize: QWord; out Imagebase: QWord): longbool; { Reads the dwarf line info from an executable. In case of error, see ExtractDwarfLineInfoError for details. ImageBase is nil for unix DLLs in all other cases the value it receives must be substracted from the addresses in the dwarf line info (and then the real base address added, to account for the possible relocation) NOTE: currently in unix it is also NIL for the main executable, corresponding the GetModuleByAddr() in un_lineinfo also returning NIL as the base address for the main executable. } function DlnNameByExename(exename: string): string; {generates file names with .zdli extension. Use in cases when both your windows and linux binaries are placed in the same folder } var ExtractDwarfLineInfoError: WideString = ''; implementation uses zstream; const // Cannot use reference counted strings because they are emptied // when a function from this module is called two or more times // while an exception is being processed (don't know why). DwarfDebugLine: shortstring = '.debug_line'; DwarfZDebugLine: shortstring = '.zdebug_line'; DwarfDarwinDebugLine: shortstring = '__debug_line'; DwarfDarwinSegmentName: shortstring = '__DWARF'; TextDarwinSegmentName: shortstring = '__TEXT'; type TCheckResult = (header_not_found, header_invalid, no_debug_info, found_debug_info); {$MACRO ON} {$ifdef DEBUG_DWARF_PARSER} {$define DEBUG_WRITELN := WriteLn} {$define DEBUG_COMMENT := } {$else} {$define DEBUG_WRITELN := //} {$define DEBUG_COMMENT := //} {$endif} { ELF Header structures types} type Elf32_Half = Word; Elf64_Half = Word; { Types for signed and unsigned 32-bit quantities. } Elf32_Word = DWord; Elf32_Sword = Longint; Elf64_Word = DWord; Elf64_Sword = Longint; { Types for signed and unsigned 64-bit quantities. } Elf32_Xword = QWord; Elf32_Sxword = Int64; Elf64_Xword = QWord; Elf64_Sxword = Int64; { Type of addresses. } Elf32_Addr = DWord; Elf64_Addr = QWord; { Type of file offsets. } Elf32_Off = DWord; Elf64_Off = QWord; { Type for section indices, which are 16-bit quantities. } Elf32_Section = Word; Elf64_Section = Word; { Type for version symbol information. } Elf32_Versym = Elf32_Half; Elf64_Versym = Elf64_Half; { some constants from the corresponding header files } const El_NIDENT = 16; { some important indices into the e_ident signature of an ELF file } EI_MAG0 = 0; EI_MAG1 = 1; EI_MAG2 = 2; EI_MAG3 = 3; EI_CLASS = 4; { the first byte of the e_ident array must be of this value } ELFMAG0 = $7f; { the second byte of the e_ident array must be of this value } ELFMAG1 = Byte('E'); { the third byte of the e_ident array must be of this value } ELFMAG2 = Byte('L'); { the fourth byte of the e_ident array must be of this value } ELFMAG3 = Byte('F'); { the fifth byte specifies the bitness of the header; all other values are invalid } ELFCLASS32 = 1; ELFCLASS64 = 2; {$packrecords c} type { The ELF file header. This appears at the start of every ELF file, 32 bit version } TElf32_Ehdr = record e_ident : array[0..El_NIDENT-1] of Byte; { file identification } e_type : Elf32_Half; { file type } e_machine : Elf32_Half; { machine architecture } e_version : Elf32_Word; { ELF format version } e_entry : Elf32_Addr; { entry point } e_phoff : Elf32_Off; { program header file offset } e_shoff : Elf32_Off; { section header file offset } e_flags : Elf32_Word; { architecture specific flags } e_ehsize : Elf32_Half; { size of ELF header in bytes } e_phentsize : Elf32_Half; { size of program header entry } e_phnum : Elf32_Half; { number of program header entries } e_shentsize : Elf32_Half; { size of section header entry } e_shnum : Elf32_Half; { number of section header entry } e_shstrndx : Elf32_Half; { section name strings section index } end; { ELF32 Section header } TElf32_Shdr = record sh_name : Elf32_Word; { section name } sh_type : Elf32_Word; { section type } sh_flags : Elf32_Word; { section flags } sh_addr : Elf32_Addr; { virtual address } sh_offset : Elf32_Off; { file offset } sh_size : Elf32_Word; { section size } sh_link : Elf32_Word; { misc info } sh_info : Elf32_Word; { misc info } sh_addralign : Elf32_Word; { memory alignment } sh_entsize : Elf32_Word; { entry size if table } end; { The ELF file header. This appears at the start of every ELF file, 64 bit version } TElf64_Ehdr = record e_ident : array[0..El_NIDENT-1] of Byte; e_type : Elf64_Half; e_machine : Elf64_Half; e_version : Elf64_Word; e_entry : Elf64_Addr; e_phoff : Elf64_Off; e_shoff : Elf64_Off; e_flags : Elf64_Word; e_ehsize : Elf64_Half; e_phentsize : Elf64_Half; e_phnum : Elf64_Half; e_shentsize : Elf64_Half; e_shnum : Elf64_Half; e_shstrndx : Elf64_Half; end; { ELF64 Section header } TElf64_Shdr = record sh_name : Elf64_Word; sh_type : Elf64_Word; sh_flags : Elf64_Xword; sh_addr : Elf64_Addr; sh_offset : Elf64_Off; sh_size : Elf64_Xword; sh_link : Elf64_Word; sh_info : Elf64_Word; sh_addralign : Elf64_Xword; sh_entsize : Elf64_Xword; end; {$packrecords default} const (* Constant for the magic field of the TMacho32Header (32-bit architectures) *) MH_MAGIC = $feedface; (* the mach magic number *) MH_CIGAM = $cefaedfe; (* NXSwapInt(MH_MAGIC) *) (* Constant for the magic field of the TMacho64Header (64-bit architectures) *) MH_MAGIC_64 = $feedfacf; (* the 64-bit mach magic number *) MH_CIGAM_64 = $cffaedfe; (* NXSwapInt(MH_MAGIC_64) *) (* Constants for the cmd field of all load commands, the type *) LC_SEGMENT = $00000001; (* segment of this file to be mapped *) LC_SEGMENT_64 = $00000019; (* 64-bit segment of this file to be mapped *) type { The 32-bit mach header appears at the very beginning of the object file for 32-bit architectures. } TMacho32Header = packed record magic: longword; (* mach magic number identifier *) cputype: longint; (* cpu specifier *) cpusubtype: longint; (* machine specifier *) filetype: longword; (* type of file *) ncmds: longword; (* number of load commands *) sizeofcmds: longword; (* the size of all the load commands *) flags: longword; (* flags *) end; { The 64-bit mach header appears at the very beginning of object files for 64-bit architectures. } TMacho64Header = packed record magic: longword; (* mach magic number identifier *) cputype: longint; (* cpu specifier *) cpusubtype: longint; (* machine specifier *) filetype: longword; (* type of file *) ncmds: longword; (* number of load commands *) sizeofcmds: longword; (* the size of all the load commands *) flags: longword; (* flags *) reserved: longword; (* reserved *) end; { The load commands directly follow the mach_header. } TMachoLoadCommand = packed record cmd: longword; (* type of load command *) cmdsize: longword; (* total size of command in bytes *) end; { The segment load command indicates that a part of this file is to be mapped into the task's address space. } TMacho32SegmentCommand = packed record (* for 32-bit architectures *) cmd: longword; (* LC_SEGMENT *) cmdsize: longword; (* includes sizeof section structs *) segname: array[0..15] of ansichar; (* segment name *) vmaddr: longword; (* memory address of this segment *) vmsize: longword; (* memory size of this segment *) fileoff: longword; (* file offset of this segment *) filesize: longword; (* amount to map from the file *) maxprot: longint; (* maximum VM protection *) initprot: longint; (* initial VM protection *) nsects: longword; (* number of sections in segment *) flags: longword; (* flags *) end; { The 64-bit segment load command indicates that a part of this file is to be mapped into a 64-bit task's address space. } TMacho64SegmentCommand = packed record (* for 64-bit architectures *) cmd: longword; (* LC_SEGMENT_64 *) cmdsize: longword; (* includes sizeof section_64 structs *) segname: array[0..15] of ansichar; (* segment name *) vmaddr: qword; (* memory address of this segment *) vmsize: qword; (* memory size of this segment *) fileoff: qword; (* file offset of this segment *) filesize: qword; (* amount to map from the file *) maxprot: longint; (* maximum VM protection *) initprot: longint; (* initial VM protection *) nsects: longword; (* number of sections in segment *) flags: longword; (* flags *) end; { The 32-bit segment section header. } TMacho32SegmentSection = packed record (* for 32-bit architectures *) sectname: array[0..15] of ansichar; (* name of this section *) segname: array[0..15] of ansichar; (* segment this section goes in *) addr: longword; (* memory address of this section *) size: longword; (* size in bytes of this section *) offset: longword; (* file offset of this section *) align: longword; (* section alignment (power of 2) *) reloff: longword; (* file offset of relocation entries *) nreloc: longword; (* number of relocation entries *) flags: longword; (* flags (section type and attributes)*) reserved1: longword; (* reserved (for offset or index) *) reserved2: longword; (* reserved (for count or sizeof) *) end; { The 64-bit segment section header. } TMacho64SegmentSection = packed record (* for 64-bit architectures *) sectname: array[0..15] of ansichar; (* name of this section *) segname: array[0..15] of ansichar; (* segment this section goes in *) addr: qword; (* memory address of this section *) size: qword; (* size in bytes of this section *) offset: longword; (* file offset of this section *) align: longword; (* section alignment (power of 2) *) reloff: longword; (* file offset of relocation entries *) nreloc: longword; (* number of relocation entries *) flags: longword; (* flags (section type and attributes)*) reserved1: longword; (* reserved (for offset or index) *) reserved2: longword; (* reserved (for count or sizeof) *) reserved3: longword; (* reserved *) end; type tdosheader = packed record e_magic : word; e_cblp : word; e_cp : word; e_crlc : word; e_cparhdr : word; e_minalloc : word; e_maxalloc : word; e_ss : word; e_sp : word; e_csum : word; e_ip : word; e_cs : word; e_lfarlc : word; e_ovno : word; e_res : array[0..3] of word; e_oemid : word; e_oeminfo : word; e_res2 : array[0..9] of word; e_lfanew : longint; end; tpeheader = packed record PEMagic : longint; Machine : word; NumberOfSections : word; TimeDateStamp : longint; PointerToSymbolTable : longint; NumberOfSymbols : longint; SizeOfOptionalHeader : word; Characteristics : word; end; tpeoptionalheader32 = packed record Magic : word; MajorLinkerVersion : byte; MinorLinkerVersion : byte; SizeOfCode : longint; SizeOfInitializedData : longint; SizeOfUninitializedData : longint; AddressOfEntryPoint : longint; BaseOfCode : longint; BaseOfData : longint; ImageBase : longint; SectionAlignment : longint; FileAlignment : longint; MajorOperatingSystemVersion : word; MinorOperatingSystemVersion : word; MajorImageVersion : word; MinorImageVersion : word; MajorSubsystemVersion : word; MinorSubsystemVersion : word; Win32VersionValue : longint; SizeOfImage : longint; SizeOfHeaders : longint; CheckSum : longint; Subsystem : word; DllCharacteristics : word; SizeOfStackReserve : longint; SizeOfStackCommit : longint; SizeOfHeapReserve : longint; SizeOfHeapCommit : longint; LoaderFlags : longint; NumberOfRvaAndSizes : longint; DataDirectory : array[1..$80] of byte; end; tpeoptionalheader64 = packed record Magic : word; MajorLinkerVersion : byte; MinorLinkerVersion : byte; SizeOfCode : longint; SizeOfInitializedData : longint; SizeOfUninitializedData : longint; AddressOfEntryPoint : longint; BaseOfCode : longint; ImageBase : qword; SectionAlignment : longint; FileAlignment : longint; MajorOperatingSystemVersion : word; MinorOperatingSystemVersion : word; MajorImageVersion : word; MinorImageVersion : word; MajorSubsystemVersion : word; MinorSubsystemVersion : word; Win32VersionValue : longint; SizeOfImage : longint; SizeOfHeaders : longint; CheckSum : longint; Subsystem : word; DllCharacteristics : word; SizeOfStackReserve : qword; SizeOfStackCommit : qword; SizeOfHeapReserve : qword; SizeOfHeapCommit : qword; LoaderFlags : longint; NumberOfRvaAndSizes : longint; DataDirectory : array[1..$80] of byte; end; tcoffsechdr=packed record name : array[0..7] of char; vsize : longint; rvaofs : longint; datalen : longint; datapos : longint; relocpos : longint; lineno1 : longint; nrelocs : word; lineno2 : word; flags : longint; end; coffsymbol=packed record name : array[0..3] of char; { real is [0..7], which overlaps the strofs ! } strofs : longint; value : longint; section : smallint; empty : word; typ : byte; aux : byte; end; function DlnNameByExename(exename: string): string; begin Result := ChangeFileExt(exename, '.zdli'); end; function cntostr(cn: pchar): string; var i: integer = 0; begin Result:=''; repeat if cn^ = #0 then break; Result+= cn^; inc(i); inc(cn); until i = 8; end; function ExtractElf32( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): boolean; var header : TElf32_Ehdr; strtab_header : TElf32_Shdr; cursec_header : TElf32_Shdr; i: Integer; buf : array[0..20] of char; sectionName: string; begin DwarfLineInfoOffset := 0; DwarfLineInfoSize := 0; Imagebase:= 0; IsCompressed := False; Result := False; if (f.read(header, sizeof(header)) <> sizeof(header)) then begin ExtractDwarfLineInfoError:='Could not read the ELF header!'; Exit(false); end; { seek to the start of section headers } { first get string section header } f.Position:= header.e_shoff + (header.e_shstrndx * header.e_shentsize); if (f.read(strtab_header, sizeof(strtab_header)) <> sizeof(strtab_header)) then begin ExtractDwarfLineInfoError:='Could not read string section header'; Exit(false); end; for i := 0 to (header.e_shnum-1) do begin // Section nr 0 is reserved. if i = 0 then Continue; f.Position:= header.e_shoff + (i * header.e_shentsize); if (f.Read(cursec_header, sizeof(cursec_header)) <> sizeof(cursec_header)) then begin ExtractDwarfLineInfoError:='Could not read next section header'; Exit(false); end; { paranoia TODO: check cursec_header.e_shentsize } f.Position:= strtab_header.sh_offset + cursec_header.sh_name; if (f.Read(buf, sizeof(buf)) <> sizeof(buf)) then begin ExtractDwarfLineInfoError:='Could not read section name'; Exit(false); end; buf[sizeof(buf)-1] := #0; sectionName := StrPas(pchar(@buf[0])); DEBUG_WRITELN('Section ', i, ': ', sectionName, ', offset ', IntToStr(cursec_header.sh_offset), ', size ', IntToStr(cursec_header.sh_size)); if sectionName = DwarfDebugLine then begin DEBUG_WRITELN(sectionName + ' section found'); DwarfLineInfoOffset := cursec_header.sh_offset; DwarfLineInfoSize := cursec_header.sh_size; { more checks } DEBUG_WRITELN(' offset ', DwarfLineInfoOffset, ', size ', DwarfLineInfoSize); Result := (DwarfLineInfoOffset >= 0) and (DwarfLineInfoSize > 0); break; end else if sectionName = DwarfZDebugLine then begin DEBUG_WRITELN(sectionName + ' section found'); DwarfLineInfoOffset := cursec_header.sh_offset; DEBUG_WRITELN(' offset ', DwarfLineInfoOffset); IsCompressed:= true; Result := (DwarfLineInfoOffset >= 0); break; end; end; end; function ExtractElf64( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): boolean; var header : TElf64_Ehdr; strtab_header : TElf64_Shdr; cursec_header : TElf64_Shdr; i: Integer; buf : array[0..20] of char; sectionName: string; begin DwarfLineInfoOffset := 0; DwarfLineInfoSize := 0; Imagebase:= 0; IsCompressed := False; Result := False; if (f.read(header, sizeof(header)) <> sizeof(header)) then begin ExtractDwarfLineInfoError:='Could not read the ELF header!'; Exit(false); end; { seek to the start of section headers } { first get string section header } f.Position:= header.e_shoff + (header.e_shstrndx * header.e_shentsize); if (f.read(strtab_header, sizeof(strtab_header)) <> sizeof(strtab_header)) then begin ExtractDwarfLineInfoError:='Could not read string section header'; Exit(false); end; for i := 0 to (header.e_shnum-1) do begin f.Position:= header.e_shoff + (i * header.e_shentsize); if (f.Read(cursec_header, sizeof(cursec_header)) <> sizeof(cursec_header)) then begin ExtractDwarfLineInfoError:='Could not read next section header'; Exit(false); end; { paranoia TODO: check cursec_header.e_shentsize } f.Position:= strtab_header.sh_offset + cursec_header.sh_name; if (f.Read(buf, sizeof(buf)) <> sizeof(buf)) then begin ExtractDwarfLineInfoError:='Could not read section name'; Exit(false); end; buf[sizeof(buf)-1] := #0; DEBUG_WRITELN('This section is ', pchar(@buf[0]), ', offset ', IntToStr(cursec_header.sh_offset), ', size ', IntToStr(cursec_header.sh_size)); sectionName := StrPas(pchar(@buf[0])); if sectionName = DwarfDebugLine then begin DEBUG_WRITELN(sectionName + ' section found'); DwarfLineInfoOffset := cursec_header.sh_offset; DwarfLineInfoSize := cursec_header.sh_size; { more checks } DEBUG_WRITELN(' offset ', DwarfLineInfoOffset, ', size ', DwarfLineInfoSize); Result := (DwarfLineInfoOffset >= 0) and (DwarfLineInfoSize > 0); break; end; if sectionName = DwarfZDebugLine then begin DEBUG_WRITELN(sectionName + ' section found'); DwarfLineInfoOffset := cursec_header.sh_offset; DEBUG_WRITELN(' offset ', DwarfLineInfoOffset); IsCompressed:= true; Result := (DwarfLineInfoOffset >= 0); break; end; end; end; function ExtractMacho32( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): boolean; var I, J : Integer; header : TMacho32Header; load_command : TMachoLoadCommand; segment_header : TMacho32SegmentCommand; section_header : TMacho32SegmentSection; begin DwarfLineInfoOffset := 0; DwarfLineInfoSize := 0; Imagebase:= 0; IsCompressed := False; Result := False; if (f.read(header, sizeof(header)) <> sizeof(header)) then begin ExtractDwarfLineInfoError:='Could not read the Mach-O header!'; Exit(false); end; for I:= 1 to header.ncmds do begin if (f.Read(load_command, sizeof(load_command)) <> sizeof(load_command)) then begin ExtractDwarfLineInfoError:='Could not read next segment header'; Exit(false); end; if (load_command.cmd <> LC_SEGMENT) then f.Seek(load_command.cmdsize - sizeof(load_command), soFromCurrent) else begin f.Seek(-sizeof(load_command), soFromCurrent); if (f.Read(segment_header, sizeof(segment_header)) <> sizeof(segment_header)) then begin ExtractDwarfLineInfoError:='Could not read segment name'; Exit(false); end; if segment_header.segname <> DwarfDarwinSegmentName then begin f.Seek(load_command.cmdsize - sizeof(segment_header), soFromCurrent); if segment_header.segname = TextDarwinSegmentName then Imagebase:= segment_header.vmaddr; end else begin for J:= 0 to segment_header.nsects - 1 do begin if (f.Read(section_header, sizeof(section_header)) <> sizeof(section_header)) then begin ExtractDwarfLineInfoError:='Could not read next section header'; Exit(false); end; DEBUG_WRITELN('Section ', I, ': ', section_header.sectname, ', offset ', IntToStr(section_header.offset), ', size ', IntToStr(section_header.size)); if section_header.sectname = DwarfDarwinDebugLine then begin DEBUG_WRITELN(section_header.sectname + ' section found'); DwarfLineInfoOffset := section_header.offset; DwarfLineInfoSize := section_header.size; { more checks } DEBUG_WRITELN(' offset ', DwarfLineInfoOffset, ', size ', DwarfLineInfoSize); Result := (DwarfLineInfoOffset >= 0) and (DwarfLineInfoSize > 0); Break; end else if section_header.sectname = DwarfZDebugLine then begin DEBUG_WRITELN(section_header.sectname + ' section found'); DwarfLineInfoOffset := section_header.offset; DEBUG_WRITELN(' offset ', DwarfLineInfoOffset); IsCompressed:= true; Result := (DwarfLineInfoOffset >= 0); Break; end; end; Break; end; end; end; end; function ExtractMacho64( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): boolean; var I, J : Integer; header : TMacho64Header; load_command : TMachoLoadCommand; segment_header : TMacho64SegmentCommand; section_header : TMacho64SegmentSection; begin DwarfLineInfoOffset := 0; DwarfLineInfoSize := 0; Imagebase:= 0; IsCompressed := False; Result := False; if (f.read(header, sizeof(header)) <> sizeof(header)) then begin ExtractDwarfLineInfoError:='Could not read the Mach-O header!'; Exit(false); end; for I:= 1 to header.ncmds do begin if (f.Read(load_command, sizeof(load_command)) <> sizeof(load_command)) then begin ExtractDwarfLineInfoError:='Could not read next segment header'; Exit(false); end; if (load_command.cmd <> LC_SEGMENT_64) then f.Seek(load_command.cmdsize - sizeof(load_command), soFromCurrent) else begin f.Seek(-sizeof(load_command), soFromCurrent); if (f.Read(segment_header, sizeof(segment_header)) <> sizeof(segment_header)) then begin ExtractDwarfLineInfoError:='Could not read segment name'; Exit(false); end; if segment_header.segname <> DwarfDarwinSegmentName then begin f.Seek(load_command.cmdsize - sizeof(segment_header), soFromCurrent); if segment_header.segname = TextDarwinSegmentName then Imagebase:= segment_header.vmaddr; end else begin for J:= 0 to segment_header.nsects - 1 do begin if (f.Read(section_header, sizeof(section_header)) <> sizeof(section_header)) then begin ExtractDwarfLineInfoError:='Could not read next section header'; Exit(false); end; DEBUG_WRITELN('Section ', I, ': ', section_header.sectname, ', offset ', IntToStr(section_header.offset), ', size ', IntToStr(section_header.size)); if section_header.sectname = DwarfDarwinDebugLine then begin DEBUG_WRITELN(section_header.sectname + ' section found'); DwarfLineInfoOffset := section_header.offset; DwarfLineInfoSize := section_header.size; { more checks } DEBUG_WRITELN(' offset ', DwarfLineInfoOffset, ', size ', DwarfLineInfoSize); Result := (DwarfLineInfoOffset >= 0) and (DwarfLineInfoSize > 0); Break; end else if section_header.sectname = DwarfZDebugLine then begin DEBUG_WRITELN(section_header.sectname + ' section found'); DwarfLineInfoOffset := section_header.offset; DEBUG_WRITELN(' offset ', DwarfLineInfoOffset); IsCompressed:= true; Result := (DwarfLineInfoOffset >= 0); Break; end; end; Break; end; end; end; end; function CheckWindowsExe( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): TCheckResult; var dosheader : tdosheader; peheader : tpeheader; peoptheader32 : tpeoptionalheader32; peoptheader64 : tpeoptionalheader64; coffsec : tcoffsechdr; stringsSectionOffset: PtrUInt; sectionName : String; i: Integer; function GetLongSectionName(numberedSectionName: String): String; var sectionNameBuf : array[0..255] of char; stringOffset : Cardinal; oldOffset: Int64; code: Integer; begin Val(Copy(numberedSectionName, 2, 8), stringOffset, code); if code=0 then begin fillchar(sectionNameBuf, sizeof(sectionNameBuf), 0); oldOffset := f.Position; f.Seek(stringsSectionOffset + stringOffset, soBeginning); f.Read(sectionNameBuf, sizeof(sectionNameBuf)); f.Seek(oldOffset, soBeginning); Result := StrPas(sectionNameBuf); end else Result := ''; end; begin DwarfLineInfoOffset := 0; DwarfLineInfoSize := 0; Imagebase:= 0; IsCompressed := False; Result := header_not_found; { read and check header } if f.Size >= sizeof(tdosheader) then begin f.Read(dosheader, sizeof(tdosheader)); if dosheader.e_magic = $5A4D then // 'MZ' begin f.Position:= dosheader.e_lfanew; if (f.Size - f.Position) >= sizeof(tpeheader) then begin f.Read(peheader, sizeof(tpeheader)); if peheader.pemagic = $4550 then // 'PE' begin peoptheader32.magic := f.ReadWord; if (peoptheader32.magic = $10B) and (peheader.SizeOfOptionalHeader = sizeof(tpeoptionalheader32)) then begin DEBUG_WRITELN('Found Windows Portable Executable header (32-bit).'); f.Read(peoptheader32.MajorLinkerVersion, sizeof(tpeoptionalheader32) - sizeof(tpeoptionalheader32.Magic)); ImageBase:= peoptheader32.Imagebase; end else if (peoptheader32.magic = $20B) and (peheader.SizeOfOptionalHeader = sizeof(tpeoptionalheader64)) then begin DEBUG_WRITELN('Found Windows Portable Executable header (64-bit).'); peoptheader64.magic := peoptheader32.magic; f.Read(peoptheader64.MajorLinkerVersion, sizeof(tpeoptionalheader64) - sizeof(tpeoptionalheader64.Magic)); ImageBase:= peoptheader64.Imagebase; end else begin DEBUG_WRITELN('Unsupported Windows Portable Executable.'); Exit; end; stringsSectionOffset := peheader.PointerToSymbolTable + peheader.NumberOfSymbols * sizeof(coffsymbol); { read section info } for i:=1 to peheader.NumberOfSections do begin f.Read(coffsec, sizeof(tcoffsechdr)); sectionName := cntostr(@coffsec.name); if Length(sectionName) <= 0 then continue; if sectionName[1]='/' then // Section name longer than 8 characters. sectionName := GetLongSectionName(sectionName); DEBUG_WRITELN(sectionName); if sectionName = DwarfDebugLine then begin DwarfLineInfoOffset:= coffsec.datapos; DwarfLineInfoSize:= coffsec.datalen; break; end; if sectionName = DwarfZDebugLine then begin DwarfLineInfoOffset:= coffsec.datapos; IsCompressed:= true; break; end; end; if DwarfLineInfoOffset > 0 then Result := found_debug_info else Result := no_debug_info; end; end; end; end; end; function CheckUnixElf( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): TCheckResult; var fileIdentBuf : array[0..El_NIDENT-1] of byte; begin if f.Size >= El_NIDENT then begin if (f.read(fileIdentBuf, El_NIDENT) <> El_NIDENT) then begin Exit(header_not_found); end; { more paranoia checks } if (fileIdentBuf[EI_MAG0] <> ELFMAG0) or (fileIdentBuf[EI_MAG1] <> ELFMAG1) or (fileIdentBuf[EI_MAG2] <> ELFMAG2) or (fileIdentBuf[EI_MAG3] <> ELFMAG3) then begin ExtractDwarfLineInfoError:='Invalid ELF magic header.'; Exit(header_not_found); end; // Found header. f.Seek(0, soBeginning); case fileIdentBuf[EI_CLASS] of ELFCLASS32: begin DEBUG_WRITELN('Found Unix ELF 32-bit header.'); if ExtractElf32(f, DwarfLineInfoSize, DwarfLineInfoOffset, Imagebase, IsCompressed) then Result := found_debug_info else Result := no_debug_info; end; ELFCLASS64: begin DEBUG_WRITELN('Found Unix ELF 64-bit header.'); if ExtractElf64(f, DwarfLineInfoSize, DwarfLineInfoOffset, Imagebase, IsCompressed) then Result := found_debug_info else Result := no_debug_info; end; else begin Exit(header_invalid); end; end; Imagebase:= 0; end; end; function CheckDarwinMacho( f: TFileStream; out DwarfLineInfoSize: QWord; out DwarfLineInfoOffset: Int64; out Imagebase: QWord; out IsCompressed: Boolean): TCheckResult; var fileIdentBuf : LongWord; begin if f.Size >= SizeOf(LongWord) then begin if (f.read(fileIdentBuf, SizeOf(LongWord)) <> SizeOf(LongWord)) then begin Exit(header_not_found); end; f.Seek(0, soBeginning); case fileIdentBuf of MH_MAGIC, MH_CIGAM: begin DEBUG_WRITELN('Found Darwin Mach-O 32-bit header.'); if ExtractMacho32(f, DwarfLineInfoSize, DwarfLineInfoOffset, Imagebase, IsCompressed) then Result := found_debug_info else Result := no_debug_info; end; MH_MAGIC_64, MH_CIGAM_64: begin DEBUG_WRITELN('Found Darwin Mach-O 64-bit header.'); if ExtractMacho64(f, DwarfLineInfoSize, DwarfLineInfoOffset, Imagebase, IsCompressed) then Result := found_debug_info else Result := no_debug_info; end; else begin Exit(header_not_found); end; end; end; end; function ExtractDwarfLineInfo( ExeFileName: ansistring; out _dlnfo: pointer; out _dlnfoSize: QWord; out Imagebase: QWord): longbool; var DwarfOffset : int64; DwarfSize : QWord; IsCompressed: boolean = False; f : TFileStream; DC: TDecompressionStream; CheckResult: TCheckResult; begin DEBUG_WRITELN('Reading dwarf line info from ', ExeFileName); Result := False; f:= TFileStream.Create(ExeFileName, fmOpenRead or fmShareDenyNone); try { Check for Windows PE. } CheckResult := CheckWindowsExe(f, DwarfSize, DwarfOffset, Imagebase, IsCompressed); { Check for Unix ELF. } if CheckResult = header_not_found then begin f.Seek(0, soBeginning); CheckResult := CheckUnixElf(f, DwarfSize, DwarfOffset, Imagebase, IsCompressed); end; { Check for Darwin Mach-O. } if CheckResult = header_not_found then begin f.Seek(0, soBeginning); CheckResult := CheckDarwinMacho(f, DwarfSize, DwarfOffset, Imagebase, IsCompressed); end; if CheckResult = found_debug_info then begin Result := True; if IsCompressed then begin f.Position:= DwarfOffset; DC:= TDecompressionStream.Create(f); DC.Read(DwarfSize, sizeof(DwarfSize)); // 8 bytes (QWORD) DC.Read(ImageBase, sizeof(ImageBase)); // 8 bytes (QWORD) _dlnfoSize:= DwarfSize; GetMem(_dlnfo, DwarfSize); DC.Read(_dlnfo^, DwarfSize); DC.Free; end else begin GetMem(_dlnfo, DwarfSize); _dlnfoSize:= DwarfSize; f.Position:= DwarfOffset; f.Read(_dlnfo^, DwarfSize); end; end else case CheckResult of header_not_found: ExtractDwarfLineInfoError := 'File not supported.'; header_invalid: ExtractDwarfLineInfoError := 'Invalid header.'; no_debug_info: ExtractDwarfLineInfoError := 'The debug line info section not found.'; end; finally f.Free; end; end; end. doublecmd-1.1.22/src/uofficexml.pas0000644000175000001440000004022014743153644016241 0ustar alexxusers{ Double commander ------------------------------------------------------------------------- Load text from office xml (*.docx, *.odt) Copyright (C) 2021 Alexander Koblov (alexx2000@mail.ru) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . } unit uOfficeXML; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uMasks; var OfficeMask: TMaskList; const OFFICE_FILTER = '(*.docx, *.xlsx, *.odt, *.ods)'; function LoadFromOffice(const FileName: String; out AText: String): Boolean; implementation uses Math, Unzip, ZipUtils, Laz2_DOM, laz2_XMLRead, fpsNumFormat, fpsCommon, fgl; type TIntegerMap = class(specialize TFPGMap); function ExtractFile(ZipFile: unzFile; MemoryStream: TMemoryStream): Boolean; var ASize: LongInt; FileInfo: unz_file_info; begin Result:= unzGetCurrentFileInfo(ZipFile, @FileInfo, nil, 0, nil, 0, nil, 0) = UNZ_OK; if Result then begin MemoryStream.SetSize(FileInfo.uncompressed_size); if unzOpenCurrentFile(ZipFile) = UNZ_OK then begin ASize:= unzReadCurrentFile(ZipFile, MemoryStream.Memory, FileInfo.uncompressed_size); Result:= (ASize = FileInfo.uncompressed_size); unzCloseCurrentFile(ZipFile); end; end; end; { Office Open XML } procedure ProcessOfficeOpenNodes(var S: String; ANode: TDOMNode); var I: Integer; ASubNode: TDOMNode; ANodeName: DOMString; begin for I:= 0 to ANode.ChildNodes.Count - 1 do begin ASubNode := ANode.ChildNodes.Item[I]; ANodeName := ASubNode.NodeName; if (ANodeName = 'w:t') then begin if Assigned(ASubNode.FirstChild) then S += ASubNode.FirstChild.NodeValue; end else if (ANodeName = 'w:p') then S += LineEnding + LineEnding else if (ANodeName = 'w:br') or (ANodeName = 'w:cr') then S += LineEnding else if (ANodeName = 'w:tab') then S += #9; if ASubNode.ChildNodes.Count > 0 then ProcessOfficeOpenNodes(S, ASubNode); end; end; procedure ProcessFile(ZipFile: unzFile; const FileName: String; var AText: String); var ADoc: TXMLDocument; AStream: TMemoryStream; begin if unzLocateFile(ZipFile, PAnsiChar(FileName), 0) = UNZ_OK then begin AStream:= TMemoryStream.Create; try if ExtractFile(ZipFile, AStream) then begin ReadXMLFile(ADoc, AStream, [xrfPreserveWhiteSpace]); if Assigned (ADoc) then begin ProcessOfficeOpenNodes(AText, ADoc.DocumentElement); ADoc.Free; end; end; finally AStream.Free; end; end; end; function LoadFromOfficeOpen(const FileName: String; out AText: String): Boolean; const HEADER_XML = 'word/header%d.xml'; FOOTER_XML = 'word/footer%d.xml'; var Index: Integer; ZipFile: unzFile; begin AText:= EmptyStr; ZipFile:= unzOpen(PAnsiChar(FileName)); Result:= Assigned(ZipFile); if Result then try // Read headers for Index:= 0 to 9 do begin ProcessFile(ZipFile, Format(HEADER_XML, [Index]), AText); end; // Read body ProcessFile(ZipFile, 'word/document.xml', AText); // Read footers for Index:= 0 to 9 do begin ProcessFile(ZipFile, Format(FOOTER_XML, [Index]), AText); end; Result:= Length(AText) > 0; finally unzClose(ZipFile); end; end; { Open Document Format } procedure ProcessOpenOfficeNodes(var S: String; ANode: TDOMNode); var I: Integer; ASubNode: TDOMNode; ANodeName: DOMString; procedure ParseSubNode(ANode: TDOMNode); var J: Integer; ASubNode: TDOMNode; begin for J:= 0 to ANode.ChildNodes.Count - 1 do begin ASubNode := ANode.ChildNodes.Item[J]; ANodeName := ASubNode.NodeName; if ANodeName = 'text:s' then S += ' ' else if ANodeName = 'text:tab' then S += #9 else if ANodeName = 'text:line-break' then S += LineEnding else if (ASubNode.NodeType = TEXT_NODE) then S += ASubNode.NodeValue else begin ParseSubNode(ASubNode); end; end; end; begin for I:= 0 to ANode.ChildNodes.Count - 1 do begin ASubNode := ANode.ChildNodes.Item[I]; ANodeName := ASubNode.NodeName; if (ANodeName = 'text:p') or (ANodeName = 'text:h')then begin if ASubNode.ChildNodes.Count > 0 then begin ParseSubNode(ASubNode); S += LineEnding; end; end else if ASubNode.ChildNodes.Count > 0 then ProcessOpenOfficeNodes(S, ASubNode); end; end; function LoadFromOpenOffice(const FileName: String; out AText: String): Boolean; const CONTENT_XML = 'content.xml'; var ZipFile: unzFile; ADoc: TXMLDocument; AStream: TMemoryStream; begin Result:= False; AText:= EmptyStr; ZipFile:= unzOpen(PAnsiChar(FileName)); if Assigned(ZipFile) then try if unzLocateFile(ZipFile, CONTENT_XML, 0) = UNZ_OK then begin AStream:= TMemoryStream.Create; try if ExtractFile(ZipFile, AStream) then begin ReadXMLFile(ADoc, AStream, [xrfPreserveWhiteSpace]); if Assigned (ADoc) then begin ProcessOpenOfficeNodes(AText, ADoc.DocumentElement); ADoc.Free; end; end; finally AStream.Free; end; end; Result:= Length(AText) > 0; finally unzClose(ZipFile); end; end; { Office Open XML Excel } function FindNode(ANode: TDOMNode; const ANodeName: String): TDOMNode; begin Result:= ANode.FindNode(ANodeName); if Result = nil then Result:= ANode.FindNode('x:' + ANodeName); end; function ParseSubNode(ANode: TDOMNode): String; var ASubNode: TDOMNode; begin Result:= EmptyStr; ASubNode:= ANode.FirstChild; while Assigned(ASubNode) do begin if (ASubNode.NodeType = TEXT_NODE) then Result+= ASubNode.NodeValue else begin Result+= ParseSubNode(ASubNode); end; ASubNode:= ASubNode.NextSibling; end; end; function GetAttrValue(ANode: TDOMNode; AName: String): String; begin Result:= EmptyStr; if (ANode = nil) or (ANode.Attributes = nil) then Exit; ANode:= ANode.Attributes.GetNamedItem(AName); if Assigned(ANode) then Result:= ANode.NodeValue; end; procedure ParseStyles(ZipFile: unzFile; Styles: TIntegerMap; Storage: TsNumFormatList); const STYLES_XML = 'xl/styles.xml'; var AName: String; Index: Integer; Style: Integer; ADoc: TXMLDocument; Formats: TStringList; AStream: TMemoryStream; ANode, ASubNode, AFormat: TDOMNode; begin Formats:= TStringList.Create; try if unzLocateFile(ZipFile, STYLES_XML, 0) = UNZ_OK then begin AStream:= TMemoryStream.Create; try if ExtractFile(ZipFile, AStream) then begin ReadXMLFile(ADoc, AStream, [xrfPreserveWhiteSpace]); if Assigned (ADoc) then begin AddBuiltInBiffFormats(Formats, FormatSettings, 163); ANode:= ADoc.DocumentElement; if Assigned(ANode) then begin ASubNode:= FindNode(ANode, 'numFmts'); if Assigned(ASubNode) then begin AFormat:= ASubNode.FirstChild; while Assigned(AFormat) do begin AName:= AFormat.NodeName; if (AName = 'numFmt') or (AName = 'x:numFmt') then begin AName:= GetAttrValue(AFormat, 'numFmtId'); if TryStrToInt(AName, Index) then begin while Formats.Count <= Index do Formats.Add(EmptyStr); Formats[Index]:= GetAttrValue(AFormat, 'formatCode'); end; end; AFormat:= AFormat.NextSibling; end; end; ASubNode:= FindNode(ANode, 'cellXfs'); if Assigned(ASubNode) then begin Style:= 0; AFormat:= ASubNode.FirstChild; while Assigned(AFormat) do begin AName:= AFormat.NodeName; if (AName = 'xf') or (AName = 'x:xf') then begin AName:= GetAttrValue(AFormat, 'numFmtId'); if TryStrToInt(AName, Index) then begin AName:= GetAttrValue(AFormat, 'applyNumberFormat'); if StrToBoolDef(AName, True) then begin if InRange(Index, 0, Formats.Count - 1) then begin AName:= Formats[Index]; if not SameText(AName, 'General') then begin Index:= Storage.AddFormat(AName); Styles.Add(Style, Storage.Items[Index]); end; end; end; end; Inc(Style); end; AFormat:= AFormat.NextSibling; end; end; end; ADoc.Free; end; end; finally AStream.Free; end; end; finally Formats.Free; end; end; function ParseWorkbook(ZipFile: unzFile; Sheets: TStringList): Boolean; const CONTENT_XML = 'xl/workbook.xml'; var AName: String; ADoc: TXMLDocument; AStream: TMemoryStream; ANode, ASubNode: TDOMNode; begin if unzLocateFile(ZipFile, CONTENT_XML, 0) = UNZ_OK then begin AStream:= TMemoryStream.Create; try if ExtractFile(ZipFile, AStream) then begin ReadXMLFile(ADoc, AStream, [xrfPreserveWhiteSpace]); if Assigned(ADoc) then begin ANode:= FindNode(ADoc.DocumentElement, 'sheets'); if Assigned(ANode) then begin ASubNode:= ANode.FirstChild; while Assigned(ASubNode) do begin AName:= ASubNode.NodeName; if (AName = 'sheet') or (AName = 'x:sheet') then begin AName:= GetAttrValue(ASubNode, 'name'); Sheets.Add(AName); end; ASubNode:= ASubNode.NextSibling; end; end; ADoc.Free; end; end; finally AStream.Free; end; end; Result:= (Sheets.Count > 0); end; procedure ParseSharedStrings(ZipFile: unzFile; Strings: TStringList); const STRINGS_XML = 'xl/sharedStrings.xml'; var AName: String; ADoc: TXMLDocument; AStream: TMemoryStream; ANode, ASubNode: TDOMNode; begin if unzLocateFile(ZipFile, STRINGS_XML, 0) = UNZ_OK then begin AStream:= TMemoryStream.Create; try if ExtractFile(ZipFile, AStream) then begin ReadXMLFile(ADoc, AStream, [xrfPreserveWhiteSpace]); if Assigned (ADoc) then begin ANode:= ADoc.DocumentElement; if Assigned(ANode) then begin ASubNode:= ANode.FirstChild; while Assigned(ASubNode) do begin AName:= ASubNode.NodeName; if (AName = 'si') or (AName = 'x:si') then begin Strings.Add(ParseSubNode(ASubNode)); end; ASubNode:= ASubNode.NextSibling; end; end; ADoc.Free; end; end; finally AStream.Free; end; end; end; procedure ParseCell(ACell: TDOMNode; Strings: TStringList; Styles: TIntegerMap; var Text: String); var D: Double; K: Integer; ATemp: String; AType: String; Index: Integer; AStyle: String; AValue: TDOMNode; F: TsNumFormatParams; Format: TFormatSettings; begin AType:= GetAttrValue(ACell, 't'); if (AType = 'inlineStr') then AValue:= FindNode(ACell, 'is') else begin AValue:= FindNode(ACell, 'v'); end; if Assigned(AValue) then begin ATemp:= ParseSubNode(AValue); // Shared string if AType = 's' then begin K:= StrToIntDef(ATemp, -1); if InRange(K, 0, Strings.Count - 1) then Text+= Strings[K]; end // Inline string or formula else if (AType = 'inlineStr') or (AType = 'str') then begin Text+= ATemp; end // Number or general else if (AType = 'n') or (AType = '') then begin AStyle:= GetAttrValue(ACell, 's'); if not TryStrToInt(AStyle, K) then Text+= ATemp else begin Index:= Styles.IndexOf(K); if (Index < 0) then Text+= ATemp else begin F:= Styles.Data[Index]; Format:= FormatSettings; Format.DecimalSeparator:= '.'; if not TryStrToFloat(ATemp, D, Format) then Text+= ATemp else Text+= ConvertFloatToStr(D, F, FormatSettings); end; end; end; end; end; procedure ParseSheet(ZipFile: unzFile; Sheet: Integer; Strings: TStringList; Styles: TIntegerMap; var Text: String); const SHEET_XML = 'xl/worksheets/sheet%d.xml'; var AName: String; ADoc: TXMLDocument; AStream: TMemoryStream; ANode, ARow, ACell: TDOMNode; begin AName:= Format(SHEET_XML, [Sheet]); if unzLocateFile(ZipFile, PAnsiChar(AName), 0) = UNZ_OK then begin AStream:= TMemoryStream.Create; try if ExtractFile(ZipFile, AStream) then begin ReadXMLFile(ADoc, AStream, [xrfPreserveWhiteSpace]); if Assigned(ADoc) then begin ANode:= FindNode(ADoc.DocumentElement, 'sheetData'); if Assigned(ANode) then begin ARow:= ANode.FirstChild; while Assigned(ARow) do begin AName:= ARow.NodeName; if (AName = 'row') or (AName = 'x:row') then begin ACell:= ARow.FirstChild; while Assigned(ACell) do begin AName:= ACell.NodeName; if (AName = 'c') or (AName = 'x:c') then begin Text+= #26; ParseCell(ACell, Strings, Styles, Text); end; ACell:= ACell.NextSibling; end; Text+= LineEnding; end; ARow:= ARow.NextSibling; end; end; ADoc.Free; end; end; finally AStream.Free; end; end; end; function LoadFromExcel(const FileName: String; out AText: String): Boolean; var Index: Integer; ZipFile: unzFile; Styles: TIntegerMap; Storage: TsNumFormatList; Sheets, Strings: TStringList; begin Result:= False; Sheets:= TStringList.Create; Styles:= TIntegerMap.Create; Strings:= TStringList.Create; Storage:= TsNumFormatList.Create(FormatSettings, True); try ZipFile:= unzOpen(PAnsiChar(FileName)); if Assigned(ZipFile) then try if ParseWorkbook(ZipFile, Sheets) then begin AText:= EmptyStr; ParseSharedStrings(ZipFile, Strings); ParseStyles(ZipFile, Styles, Storage); for Index:= 0 to Sheets.Count - 1 do begin AText+= Sheets[Index] + LineEnding; ParseSheet(ZipFile, Index + 1, Strings, Styles, AText); end; Result:= Length(AText) > 0; end; finally unzClose(ZipFile); end; finally Sheets.Free; Styles.Free; Strings.Free; Storage.Free; end; end; function LoadFromOffice(const FileName: String; out AText: String): Boolean; begin if SameText(ExtractFileExt(FileName), '.docx') then Result:= LoadFromOfficeOpen(FileName, AText) else if SameText(ExtractFileExt(FileName), '.xlsx') then Result:= LoadFromExcel(FileName, AText) else Result:= LoadFromOpenOffice(FileName, AText); end; initialization OfficeMask:= TMaskList.Create('*.docx;*.xlsx;*.odt;*.ods'); finalization OfficeMask.Free; end. doublecmd-1.1.22/src/uopendocthumb.pas0000644000175000001440000000542714743153644016766 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Open Document Format thumbnail provider Copyright (C) 2017 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uOpenDocThumb; {$mode objfpc}{$H+} interface uses Classes, SysUtils; implementation uses Unzip, ZipUtils, Graphics, Types, uThumbnails, uMasks, uGraphics; function ExtractThumbnail(FileName: PAnsiChar; MemoryStream: TMemoryStream): Boolean; var ASize: LongInt; ZipFile: unzFile; FileInfo: unz_file_info; begin Result:= False; ZipFile:= unzOpen(FileName); if Assigned(ZipFile) then try if unzLocateFile(ZipFile, 'Thumbnails/thumbnail.png', 0) = UNZ_OK then begin if unzGetCurrentFileInfo(ZipFile, @FileInfo, nil, 0, nil, 0, nil, 0) = UNZ_OK then begin MemoryStream.SetSize(FileInfo.uncompressed_size); if unzOpenCurrentFile(ZipFile) = UNZ_OK then begin ASize:= unzReadCurrentFile(ZipFile, MemoryStream.Memory, FileInfo.uncompressed_size); Result:= (ASize = FileInfo.uncompressed_size); unzCloseCurrentFile(ZipFile); end; end; end; finally unzClose(ZipFile); end; end; var MaskList: TMaskList = nil; function GetThumbnail(const aFileName: String; {%H-}aSize: TSize): Graphics.TBitmap; var MemoryStream: TMemoryStream; ABitmap: TPortableNetworkGraphic = nil; begin Result:= nil; if MaskList.Matches(aFileName) then begin MemoryStream:= TMemoryStream.Create; try if ExtractThumbnail(PAnsiChar(aFileName), MemoryStream) then begin ABitmap:= TPortableNetworkGraphic.Create; try ABitmap.LoadFromStream(MemoryStream); Result:= TBitmap.Create; BitmapAssign(Result, ABitmap); finally ABitmap.Free; end; end; except // Skip end; MemoryStream.Free; end; end; initialization TThumbnailManager.RegisterProvider(@GetThumbnail); MaskList:= TMaskList.Create('*.odt;*.ods;*.odp;*.odg'); finalization MaskList.Free; end. doublecmd-1.1.22/src/uoperationsmanager.pas0000644000175000001440000007050014743153644020007 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Manager that maintains a list of running file source operations and manages queues of operations. Copyright (C) 2010-2012 Przemysaw Nagay (cobines@gmail.com) 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, see . } unit uOperationsManager; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uOperationThread, uFileSourceOperation; type {en Handle to OperationsManager's operation.} TOperationHandle = type Longint; {en Identifier of OperationsManager's queue.} TOperationsManagerQueueIdentifier = type Longint; const InvalidOperationHandle = TOperationHandle(0); FreeOperationsQueueId = 0; ModalQueueId = Pred(FreeOperationsQueueId); SingleQueueId = Succ(FreeOperationsQueueId); type TOperationsManagerQueue = class; { TOperationsManagerItem } TOperationsManagerItem = class strict private FHandle : TOperationHandle; FOperation : TFileSourceOperation; FQueue : TOperationsManagerQueue; FThread : TOperationThread; private function RemoveFromQueue: Boolean; {en Inserts the item into new queue at specific position. @param(NewQueue To which queue to insert the item. If it is the same queue in which the item is currently nothing is performed.) @param(TargetOperation Handle to another operation in NewQueue near which the item should be placed.) @param(PlaceBefore If @true then places item before TargetOperation. If @false then places item after TargetOperation.) } procedure SetQueue(NewQueue: TOperationsManagerQueue; TargetOperation: TOperationHandle; PlaceBefore: Boolean); public constructor Create(AHandle: TOperationHandle; AOperation: TFileSourceOperation; AThread: TOperationThread); destructor Destroy; override; procedure Start; {en Moves the item and places it before or after another operation. @param(TargetOperation Handle to another operation where item should be moved. If handle belongs to operation from a different queue then the item is moved to that queue and placed before or after the operation.) @param(PlaceBefore If @true then places item before TargetOperation. If @false then places item after TargetOperation.) } procedure Move(TargetOperation: TOperationHandle; PlaceBefore: Boolean); procedure MoveToBottom; function MoveToNewQueue: TOperationsManagerQueueIdentifier; procedure MoveToTop; procedure SetQueue(NewQueue: TOperationsManagerQueue; InsertAtFront: Boolean = False); property Handle: TOperationHandle read FHandle; property Operation: TFileSourceOperation read FOperation; property Queue: TOperationsManagerQueue read FQueue; property Thread: TOperationThread read FThread; end; { TOperationsManagerQueue } TOperationsManagerQueue = class strict private FIdentifier: TOperationsManagerQueueIdentifier; FList: TFPList; FPaused: Boolean; function GetIndexByHandle(Handle: TOperationHandle): Integer; function GetItem(Index: Integer): TOperationsManagerItem; function GetItemByHandle(Handle: TOperationHandle): TOperationsManagerItem; function GetOperationsCount: Integer; private {en Inserts new item into the queue. @param(InsertAt If -1 (default) it adds to the back of the queue. If 0 inserts at the front. If 0 < InsertAt < Count it inserts at specific position.) } function Insert(Item: TOperationsManagerItem; InsertAt: Integer = -1): Integer; {en Inserts new item into the queue. @param(InsertAtFront If @true then inserts at the front, if @false then inserts at the back.) } function Insert(Item: TOperationsManagerItem; TargetOperation: TOperationHandle; PlaceBefore: Boolean): Integer; {en Moves item within the queue. @param(SourceItem Which item should be moved.) @param(TargetItem SourceItem is moved placed either before or after TargetItem. If TargetItem is @nil then SourceItem is moved to the front if PlaceBefore is @true and to the back if PlaceBefore is @false.) @param(PlaceBefore If @true then SourceItem is placed before TargetItem. If @false then SourceItem is placed after TargetItem.) } procedure Move(SourceItem, TargetItem: TOperationsManagerItem; PlaceBefore: Boolean); function Remove(Item: TOperationsManagerItem): Boolean; public constructor Create(AIdentifier: TOperationsManagerQueueIdentifier); destructor Destroy; override; function GetDescription(IncludeCount: Boolean): String; {en Returns @true if this queue is a free operations queue. } function IsFree: Boolean; inline; procedure Pause; procedure Stop; procedure TogglePause; procedure UnPause; property Count: Integer read GetOperationsCount; property Identifier: TOperationsManagerQueueIdentifier read FIdentifier; property Items[Index: Integer]: TOperationsManagerItem read GetItem; property ItemByHandle[Handle: TOperationHandle]: TOperationsManagerItem read GetItemByHandle; property Paused: Boolean read FPaused; end; TOperationManagerEvent = (omevOperationAdded, omevOperationRemoved, omevOperationMoved); TOperationManagerEvents = set of TOperationManagerEvent; TOperationManagerEventNotify = procedure(Item: TOperationsManagerItem; Event: TOperationManagerEvent) of object; {en Manages file source operations. Executes them, stores threads, allows querying active operations (meaning operations being executed). } { TOperationsManager } TOperationsManager = class private FLastUsedHandle: TOperationHandle; FEventsListeners: array[TOperationManagerEvent] of TFPList; FQueues: TFPList; procedure ThreadTerminatedEvent(Sender: TObject); function GetItemByOperation(Operation: TFileSourceOperation): TOperationsManagerItem; function GetItemByIndex(Index: Integer): TOperationsManagerItem; function GetOperationsCount: Integer; function GetNextUnusedHandle: TOperationHandle; function GetQueueByIndex(Index: Integer): TOperationsManagerQueue; function GetQueueByIdentifier(Identifier: TOperationsManagerQueueIdentifier): TOperationsManagerQueue; function GetQueuesCount: Integer; function MoveToNewQueue(Item: TOperationsManagerItem): TOperationsManagerQueueIdentifier; procedure MoveToQueue(Item: TOperationsManagerItem; QueueIdentifier: TOperationsManagerQueueIdentifier); {en Notifies all listeners that an event has occurred (or multiple events). } procedure NotifyEvents(Item: TOperationsManagerItem; Events: TOperationManagerEvents); public constructor Create; destructor Destroy; override; {en Adds an operation to the manager. @param(ShowProgress If @true automatically shows progress window.) } function AddOperation(Operation: TFileSourceOperation; ShowProgress: Boolean = True): TOperationHandle; {en Adds an operation to the manager. @param(QueueIdentifier Specifies to which queue to put the operation.) @param(InsertAtFrontOfQueue If @true inserts the operation at the front of the queue, if @false inserts at the back of the queue.) @param(ShowProgress If @true automatically shows progress window.) } function AddOperation(Operation: TFileSourceOperation; QueueIdentifier: TOperationsManagerQueueIdentifier; InsertAtFrontOfQueue: Boolean; ShowProgress: Boolean = True): TOperationHandle; {en Adds an operation to the manager. Execute operation in the main thread and show progress in modal window. } function AddOperationModal(Operation: TFileSourceOperation): TOperationHandle; {en Operations retrieved this way can be safely used from the main GUI thread. But they should not be stored for longer use, because they may be destroyed by the Operations Manager when they finish. Operation handle can always be used to query OperationsManager if the operation item is still alive. } function GetItemByHandle(Handle: TOperationHandle): TOperationsManagerItem; function GetOrCreateQueue(Identifier: TOperationsManagerQueueIdentifier): TOperationsManagerQueue; function GetNewQueueIdentifier: TOperationsManagerQueueIdentifier; procedure PauseAll; procedure StopAll; procedure UnPauseAll; function AllProgressPoint: Double; {en Adds a function to call on specific events. } procedure AddEventsListener(Events: TOperationManagerEvents; FunctionToCall: TOperationManagerEventNotify); {en Removes a registered function callback for events. } procedure RemoveEventsListener(Events: TOperationManagerEvents; FunctionToCall: TOperationManagerEventNotify); property OperationsCount: Integer read GetOperationsCount; property QueuesCount: Integer read GetQueuesCount; property QueueByIndex[Index: Integer]: TOperationsManagerQueue read GetQueueByIndex; property QueueByIdentifier[Identifier: TOperationsManagerQueueIdentifier]: TOperationsManagerQueue read GetQueueByIdentifier; end; var OperationsManager: TOperationsManager = nil; implementation uses uDebug, uLng, uFileSourceOperationMisc, uFileSourceProperty, uFileSource; type PEventsListItem = ^TEventsListItem; TEventsListItem = record EventFunction: TOperationManagerEventNotify; end; { TOperationsManagerItem } constructor TOperationsManagerItem.Create(AHandle: TOperationHandle; AOperation: TFileSourceOperation; AThread: TOperationThread); begin FHandle := AHandle; FOperation := AOperation; FThread := AThread; end; destructor TOperationsManagerItem.Destroy; begin inherited Destroy; FOperation.Free; end; procedure TOperationsManagerItem.Start; begin if (FThread = nil) then begin FThread := TOperationThread.Create(True, Operation); if Assigned(FThread.FatalException) then raise FThread.FatalException; // Set OnTerminate event so that we can cleanup when thread finishes. // Or instead of this create a timer for each thread and do: // Thread.WaitFor (or WaitForThreadTerminate(Thread.ThreadID)) FThread.OnTerminate := @OperationsManager.ThreadTerminatedEvent; FThread.Start; end; Operation.Start; end; procedure TOperationsManagerItem.Move(TargetOperation: TOperationHandle; PlaceBefore: Boolean); var TargetItem: TOperationsManagerItem; begin TargetItem := OperationsManager.GetItemByHandle(TargetOperation); if Assigned(TargetItem) then begin if Queue = TargetItem.Queue then Queue.Move(Self, TargetItem, PlaceBefore) else SetQueue(TargetItem.Queue, TargetOperation, PlaceBefore); end; end; procedure TOperationsManagerItem.MoveToBottom; begin Queue.Move(Self, nil, False); end; function TOperationsManagerItem.MoveToNewQueue: TOperationsManagerQueueIdentifier; begin Result := OperationsManager.MoveToNewQueue(Self); end; procedure TOperationsManagerItem.MoveToTop; begin Queue.Move(Self, nil, True); end; function TOperationsManagerItem.RemoveFromQueue: Boolean; begin Result := Queue.Remove(Self); if Queue.Count = 0 then begin OperationsManager.FQueues.Remove(Queue); Queue.Free; end; FQueue := nil; end; procedure TOperationsManagerItem.SetQueue(NewQueue: TOperationsManagerQueue; InsertAtFront: Boolean); begin if (Queue <> NewQueue) and Assigned(NewQueue) then begin if not Assigned(Queue) or RemoveFromQueue then begin FQueue := NewQueue; if InsertAtFront then NewQueue.Insert(Self, 0) // Insert at the front of the queue. else NewQueue.Insert(Self); // Add at the back of the queue. OperationsManager.NotifyEvents(Self, [omevOperationMoved]); end; end; end; procedure TOperationsManagerItem.SetQueue(NewQueue: TOperationsManagerQueue; TargetOperation: TOperationHandle; PlaceBefore: Boolean); begin if (Queue <> NewQueue) and Assigned(NewQueue) then begin if not Assigned(Queue) or RemoveFromQueue then begin FQueue := NewQueue; NewQueue.Insert(Self, TargetOperation, PlaceBefore); OperationsManager.NotifyEvents(Self, [omevOperationMoved]); end; end; end; { TOperationsManagerQueue } function TOperationsManagerQueue.GetIndexByHandle(Handle: TOperationHandle): Integer; begin for Result := 0 to Count - 1 do begin if TOperationsManagerItem(Items[Result]).Handle = Handle then Exit; end; Result := -1; end; function TOperationsManagerQueue.GetItem(Index: Integer): TOperationsManagerItem; begin Result := TOperationsManagerItem(FList.Items[Index]); end; function TOperationsManagerQueue.GetItemByHandle(Handle: TOperationHandle): TOperationsManagerItem; var Index: Integer; begin for Index := 0 to Count - 1 do begin Result := Items[Index]; if Result.Handle = Handle then Exit; end; Result := nil; end; function TOperationsManagerQueue.GetOperationsCount: Integer; begin Result := FList.Count; end; constructor TOperationsManagerQueue.Create(AIdentifier: TOperationsManagerQueueIdentifier); begin FList := TFPList.Create; FIdentifier := AIdentifier; end; destructor TOperationsManagerQueue.Destroy; var i: Integer; begin inherited Destroy; for i := 0 to FList.Count - 1 do Items[i].Free; FList.Free; end; function TOperationsManagerQueue.GetDescription(IncludeCount: Boolean): String; begin Result := rsDlgQueue + ' #' + IntToStr(Identifier); if IncludeCount then Result := Result + ' [' + IntToStr(Count) + ']'; end; procedure TOperationsManagerQueue.Move(SourceItem, TargetItem: TOperationsManagerItem; PlaceBefore: Boolean); var FromIndex, ToIndex: Integer; ShouldMove: Boolean = False; begin FromIndex := GetIndexByHandle(SourceItem.Handle); if FromIndex >= 0 then begin if not Assigned(TargetItem) then begin if PlaceBefore then ToIndex := 0 else ToIndex := FList.Count - 1; ShouldMove := True; end else begin ToIndex := GetIndexByHandle(TargetItem.Handle); if ToIndex >= 0 then begin if PlaceBefore then begin if FromIndex < ToIndex then Dec(ToIndex); end else begin if FromIndex > ToIndex then Inc(ToIndex); end; ShouldMove := True; end; end; end; if ShouldMove and (FromIndex <> ToIndex) then begin if (not Paused) and ((FromIndex = 0) or (ToIndex = 0)) and not IsFree then Items[0].Operation.Pause; FList.Move(FromIndex, ToIndex); if (not Paused) and ((FromIndex = 0) or (ToIndex = 0)) and not IsFree then Items[0].Start; OperationsManager.NotifyEvents(SourceItem, [omevOperationMoved]); end; end; function TOperationsManagerQueue.Insert(Item: TOperationsManagerItem; InsertAt: Integer): Integer; begin if InsertAt = -1 then InsertAt := FList.Count else begin if (not Paused) and (InsertAt = 0) and not IsFree then Items[0].Operation.Pause; end; FList.Insert(InsertAt, Item); Result := InsertAt; if (not Paused) and (IsFree or (InsertAt = 0)) then begin Item.Start; end else Item.Operation.Pause; end; function TOperationsManagerQueue.Insert(Item: TOperationsManagerItem; TargetOperation: TOperationHandle; PlaceBefore: Boolean): Integer; begin Result := GetIndexByHandle(TargetOperation); if Result >= 0 then begin if not PlaceBefore then Inc(Result); Insert(Item, Result); end; end; function TOperationsManagerQueue.IsFree: Boolean; begin Result := (FIdentifier = FreeOperationsQueueId) or (FIdentifier = ModalQueueId); end; procedure TOperationsManagerQueue.Pause; var Index: Integer; begin if IsFree then begin for Index := 0 to Count - 1 do Items[Index].Operation.Pause; end else begin FPaused := True; if Count > 0 then Items[0].Operation.Pause; end; end; function TOperationsManagerQueue.Remove(Item: TOperationsManagerItem): Boolean; var Index: Integer; begin Index := FList.Remove(Item); Result := Index <> -1; if Result and (not Paused) and (not IsFree) and (Index = 0) and (Count > 0) then begin Items[0].Start; end; end; procedure TOperationsManagerQueue.Stop; var i: Integer; begin for i := 0 to Count - 1 do Items[i].Operation.Stop; end; procedure TOperationsManagerQueue.TogglePause; begin if Paused then UnPause else Pause; end; procedure TOperationsManagerQueue.UnPause; var Index: Integer; begin if IsFree then begin for Index := 0 to Count - 1 do Items[Index].Start; end else begin if Count > 0 then Items[0].Start; FPaused := False; end; end; { TOperationsManager } constructor TOperationsManager.Create; var Event: TOperationManagerEvent; begin FQueues := TFPList.Create; FLastUsedHandle := InvalidOperationHandle; for Event := Low(FEventsListeners) to High(FEventsListeners) do FEventsListeners[Event] := TFPList.Create; inherited Create; end; destructor TOperationsManager.Destroy; var i: Integer; Event: TOperationManagerEvent; begin inherited Destroy; for Event := Low(FEventsListeners) to High(FEventsListeners) do begin for i := 0 to FEventsListeners[Event].Count - 1 do Dispose(PEventsListItem(FEventsListeners[Event].Items[i])); FreeAndNil(FEventsListeners[Event]); end; if QueuesCount > 0 then DCDebug('Warning: Destroying Operations Manager with active operations!'); FreeAndNil(FQueues); end; function TOperationsManager.AddOperation(Operation: TFileSourceOperation; ShowProgress: Boolean): TOperationHandle; begin if fspListOnMainThread in (Operation.FileSource as IFileSource).Properties then Result := AddOperationModal(Operation) else begin Result := AddOperation(Operation, FreeOperationsQueueId, False, ShowProgress); end; end; function TOperationsManager.AddOperation( Operation: TFileSourceOperation; QueueIdentifier: TOperationsManagerQueueIdentifier; InsertAtFrontOfQueue: Boolean; ShowProgress: Boolean = True): TOperationHandle; var Item: TOperationsManagerItem; begin if QueueIdentifier = ModalQueueId then begin Result:= AddOperationModal(Operation); Exit; end; Result := InvalidOperationHandle; if Assigned(Operation) then begin Item := TOperationsManagerItem.Create(GetNextUnusedHandle, Operation, nil); if Assigned(Item) then try Operation.PreventStart; Result := Item.Handle; Item.SetQueue(GetOrCreateQueue(QueueIdentifier), InsertAtFrontOfQueue); NotifyEvents(Item, [omevOperationAdded]); if ShowProgress then ShowOperation(Item); except Item.Free; end; end; end; function TOperationsManager.AddOperationModal(Operation: TFileSourceOperation): TOperationHandle; var Thread: TOperationThread; Item: TOperationsManagerItem; begin Result := InvalidOperationHandle; if Assigned(Operation) then begin Thread := TOperationThread.Create(True, Operation); if Assigned(Thread) then begin if Assigned(Thread.FatalException) then raise Thread.FatalException; Item := TOperationsManagerItem.Create(GetNextUnusedHandle, Operation, Thread); if Assigned(Item) then try Operation.PreventStart; Result := Item.Handle; Item.SetQueue(GetOrCreateQueue(ModalQueueId), False); NotifyEvents(Item, [omevOperationAdded]); ShowOperationModal(Item); ThreadTerminatedEvent(Thread); except Item.Free; end; end; end; end; function TOperationsManager.GetOperationsCount: Integer; var QueueIndex: Integer; Queue: TOperationsManagerQueue; begin Result := 0; for QueueIndex := 0 to QueuesCount - 1 do begin Queue := QueueByIndex[QueueIndex]; Inc(Result, Queue.Count); end; end; function TOperationsManager.GetQueuesCount: Integer; begin Result := FQueues.Count; end; function TOperationsManager.MoveToNewQueue(Item: TOperationsManagerItem): TOperationsManagerQueueIdentifier; var NewQueueId: TOperationsManagerQueueIdentifier; NewQueue: TOperationsManagerQueue; begin for NewQueueId := Succ(FreeOperationsQueueId) to MaxInt do begin if not Assigned(QueueByIdentifier[NewQueueId]) then begin NewQueue := GetOrCreateQueue(NewQueueId); Item.SetQueue(NewQueue); Exit(NewQueueId); end; end; end; function TOperationsManager.GetItemByHandle(Handle: TOperationHandle): TOperationsManagerItem; var QueueIndex: Integer; Queue: TOperationsManagerQueue; begin if Handle <> InvalidOperationHandle then begin for QueueIndex := 0 to QueuesCount - 1 do begin Queue := QueueByIndex[QueueIndex]; Result := Queue.ItemByHandle[Handle]; if Assigned(Result) then Exit; end; end; Result := nil; end; function TOperationsManager.GetItemByOperation(Operation: TFileSourceOperation): TOperationsManagerItem; var OperIndex, QueueIndex: Integer; Item: TOperationsManagerItem; Queue: TOperationsManagerQueue; begin for QueueIndex := 0 to QueuesCount - 1 do begin Queue := QueueByIndex[QueueIndex]; for OperIndex := 0 to Queue.Count - 1 do begin Item := Queue.Items[OperIndex]; if Item.Operation = Operation then Exit(Item); end; end; Result := nil; end; function TOperationsManager.GetItemByIndex(Index: Integer): TOperationsManagerItem; var OperIndex, QueueIndex: Integer; Queue: TOperationsManagerQueue; Counter: Integer; begin Counter := 0; for QueueIndex := 0 to QueuesCount - 1 do begin Queue := QueueByIndex[QueueIndex]; for OperIndex := 0 to Queue.Count - 1 do begin if Counter = Index then Exit(Queue.Items[OperIndex]); Inc(Counter); end; end; Result := nil; end; function TOperationsManager.GetOrCreateQueue(Identifier: TOperationsManagerQueueIdentifier): TOperationsManagerQueue; begin Result := QueueByIdentifier[Identifier]; if not Assigned(Result) then begin Result := TOperationsManagerQueue.Create(Identifier); FQueues.Add(Result); end; end; function TOperationsManager.GetNewQueueIdentifier: TOperationsManagerQueueIdentifier; var NewQueueId: TOperationsManagerQueueIdentifier; begin for NewQueueId := Succ(FreeOperationsQueueId) to MaxInt do begin if not Assigned(QueueByIdentifier[NewQueueId]) then begin Exit(NewQueueId); end; end; end; procedure TOperationsManager.MoveToQueue(Item: TOperationsManagerItem; QueueIdentifier: TOperationsManagerQueueIdentifier); var Queue: TOperationsManagerQueue; begin Queue := GetOrCreateQueue(QueueIdentifier); Item.SetQueue(Queue); end; function TOperationsManager.GetNextUnusedHandle: TOperationHandle; begin // Handles are consecutively incremented. // Even if they overflow there is little probability that // there will be that many operations. Result := InterLockedIncrement(FLastUsedHandle); if Result = InvalidOperationHandle then Result := InterLockedIncrement(FLastUsedHandle); end; function TOperationsManager.GetQueueByIndex(Index: Integer): TOperationsManagerQueue; begin if (Index >= 0) and (Index < FQueues.Count) then Result := TOperationsManagerQueue(FQueues.Items[Index]) else Result := nil; end; function TOperationsManager.GetQueueByIdentifier(Identifier: TOperationsManagerQueueIdentifier): TOperationsManagerQueue; var i: Integer; Queue: TOperationsManagerQueue; begin for i := 0 to FQueues.Count - 1 do begin Queue := QueueByIndex[i]; if Queue.Identifier = Identifier then Exit(Queue); end; Result := nil; end; procedure TOperationsManager.ThreadTerminatedEvent(Sender: TObject); var Thread: TOperationThread; Item: TOperationsManagerItem; OperIndex, QueueIndex: Integer; Queue: TOperationsManagerQueue; begin // This function is executed from the GUI thread (through Synchronize). Thread := Sender as TOperationThread; // Search the terminated thread in the operations list. for QueueIndex := 0 to QueuesCount - 1 do begin Queue := QueueByIndex[QueueIndex]; for OperIndex := 0 to Queue.Count - 1 do begin Item := TOperationsManagerItem(Queue.Items[OperIndex]); if Item.Thread = Thread then begin Item.RemoveFromQueue; NotifyEvents(Item, [omevOperationRemoved]); // Here the operation should not be used anymore // (by the thread and by any operations viewer). Item.Free; Exit; end; end; end; end; procedure TOperationsManager.PauseAll; var i: Integer; begin for i := 0 to QueuesCount - 1 do OperationsManager.QueueByIndex[i].Pause; end; procedure TOperationsManager.StopAll; var i: Integer; begin for i := 0 to QueuesCount - 1 do OperationsManager.QueueByIndex[i].Stop; end; procedure TOperationsManager.UnPauseAll; var i: Integer; begin for i := 0 to QueuesCount - 1 do OperationsManager.QueueByIndex[i].UnPause; end; function TOperationsManager.AllProgressPoint: Double; var Item: TOperationsManagerItem; i: Integer; begin Result := 0; if OperationsManager.OperationsCount <> 0 then begin for i := 0 to OperationsCount - 1 do begin Item := OperationsManager.GetItemByIndex(i); if Assigned(Item) then Result := Result + Item.Operation.Progress; // calculate allProgressBar end; Result := Result / OperationsManager.OperationsCount; // end; end; procedure TOperationsManager.AddEventsListener(Events: TOperationManagerEvents; FunctionToCall: TOperationManagerEventNotify); var Item: PEventsListItem; Event: TOperationManagerEvent; begin for Event := Low(TOperationManagerEvent) to High(TOperationManagerEvent) do begin if Event in Events then begin Item := New(PEventsListItem); Item^.EventFunction := FunctionToCall; FEventsListeners[Event].Add(Item); end; end; end; procedure TOperationsManager.RemoveEventsListener(Events: TOperationManagerEvents; FunctionToCall: TOperationManagerEventNotify); var Item: PEventsListItem; Event: TOperationManagerEvent; i: Integer; begin for Event := Low(TOperationManagerEvent) to High(TOperationManagerEvent) do begin if Event in Events then begin for i := 0 to FEventsListeners[Event].Count - 1 do begin Item := PEventsListItem(FEventsListeners[Event].Items[i]); if Item^.EventFunction = FunctionToCall then begin FEventsListeners[Event].Delete(i); Dispose(Item); break; // break from one for only end; end; end; end; end; procedure TOperationsManager.NotifyEvents(Item: TOperationsManagerItem; Events: TOperationManagerEvents); var EventItem: PEventsListItem; Event: TOperationManagerEvent; i: Integer; begin for Event := Low(TOperationManagerEvent) to High(TOperationManagerEvent) do begin if Event in Events then begin // Call each listener function. for i := 0 to FEventsListeners[Event].Count - 1 do begin EventItem := PEventsListItem(FEventsListeners[Event].Items[i]); EventItem^.EventFunction(Item, Event); end; end; end; end; initialization OperationsManager := TOperationsManager.Create; finalization FreeAndNil(OperationsManager); end. doublecmd-1.1.22/src/uoperationspanel.pas0000644000175000001440000003476414743153644017510 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Panel displaying file operations. Copyright (C) 2012 Przemysław Nagay (cobines@gmail.com) 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 } unit uOperationsPanel; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, Forms, Graphics, LCLVersion, fFileOpDlg, uFileSourceOperation, uOperationsManager, uFileSourceOperationUI; type { TOperationsPanel } TOperationsPanel = class(TScrollBox) private FMaximumItemWidth: Integer; FUserInterface: TFileSourceOperationUI; FOperations, FQueues: TFPList; FParentWidth: Integer; procedure ClearItems; procedure DeleteItem(List: TFPList; Index: Integer); procedure GetStateColor(State: TFileSourceOperationState; out ColorFrom, ColorTo: TColor); procedure OperationsManagerEvent(Item: TOperationsManagerItem; Event: TOperationManagerEvent); procedure ProgressWindowEvent(OperationHandle: TOperationHandle; Event: TOperationProgressWindowEvent); procedure UpdateItems; procedure UpdateVisibility; {$if lcl_fullversion >= 1070000} protected procedure SetParent(NewParent: TWinControl); override; {$endif} public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure Paint; override; procedure ParentResized(Sender: TObject); procedure UpdateView; end; implementation uses LCLIntf, LCLType, Math, fViewOperations, uDCUtils, uFileSourceOperationMisc, uFileSourceOperationMessageBoxesUI; const MinimumHeight = 25; MaximumItemWidth = 150; LeftRightTextMargin = 4; TopBottomTextMargin = 2; HorizontalSpaceBetween = 1; PanelBorderWidth = 1; type TOperationPanelItem = record Width: Integer; OperationHandle: TOperationHandle; QueueId: TOperationsManagerQueueIdentifier; end; POperationPanelItem = ^TOperationPanelItem; { TOperationsPanel } procedure TOperationsPanel.ParentResized(Sender: TObject); begin FParentWidth := (Sender as TControl).Width; UpdateItems; end; procedure TOperationsPanel.ClearItems; var p: Pointer; begin for p in FOperations do Dispose(POperationPanelItem(p)); for p in FQueues do Dispose(POperationPanelItem(p)); FOperations.Clear; FQueues.Clear; end; procedure TOperationsPanel.DeleteItem(List: TFPList; Index: Integer); begin Dispose(POperationPanelItem(List[Index])); List.Delete(Index); end; procedure TOperationsPanel.GetStateColor(State: TFileSourceOperationState; out ColorFrom, ColorTo: TColor); begin case State of // Green if running fsosRunning: begin ColorFrom:= RGB(203, 233, 171); ColorTo:= RGB(146, 208, 80); end; // Orange if in waiting fsosWaitingForFeedback, fsosWaitingForConnection: begin ColorFrom:= RGB(255, 202, 100); ColorTo:= RGB(255, 153, 4); end; // Red if paused, stopped fsosPaused, fsosStopped: begin ColorFrom:= RGB(255, 153, 149); ColorTo:= RGB(255, 110, 103); end; else begin ColorFrom:= RGB(0, 0, 0); ColorTo:= RGB(255, 255, 255); end; end; end; procedure TOperationsPanel.OperationsManagerEvent(Item: TOperationsManagerItem; Event: TOperationManagerEvent); begin UpdateItems; UpdateView; if Event = omevOperationAdded then Item.Operation.AddUserInterface(FUserInterface) else if Event = omevOperationRemoved then begin Item.Operation.RemoveUserInterface(FUserInterface); end; end; procedure TOperationsPanel.ProgressWindowEvent(OperationHandle: TOperationHandle; Event: TOperationProgressWindowEvent); begin UpdateVisibility; end; procedure TOperationsPanel.UpdateItems; var OpManItem: TOperationsManagerItem; QueueIndex, OperIndex: Integer; OutString: String; ItemRect: TRect; Queue: TOperationsManagerQueue; OperationItem: POperationPanelItem; OverallHeight: Integer = MinimumHeight; OverallWidth: Integer = 0; Visibility: Boolean = False; procedure SetSize; begin ItemRect := Rect(0, 0, 0, 0); DrawText(Canvas.Handle, PChar(OutString), Length(OutString), ItemRect, DT_NOPREFIX or DT_CALCRECT); OperationItem^.Width := Min(ItemRect.Right + (LeftRightTextMargin + PanelBorderWidth) * 2, FMaximumItemWidth); OverallHeight := Max(ItemRect.Bottom + (TopBottomTextMargin + PanelBorderWidth) * 2, OverallHeight); OverallWidth := OverallWidth + OperationItem^.Width + HorizontalSpaceBetween; end; begin ClearItems; for QueueIndex := 0 to OperationsManager.QueuesCount - 1 do begin Queue := OperationsManager.QueueByIndex[QueueIndex]; if Queue.Count > 0 then begin if Queue.Identifier = FreeOperationsQueueId then begin for OperIndex := 0 to Queue.Count - 1 do begin OpManItem := Queue.Items[OperIndex]; if Assigned(OpManItem) then begin New(OperationItem); FOperations.Add(OperationItem); OperationItem^.QueueId := Queue.Identifier; OperationItem^.OperationHandle := OpManItem.Handle; OutString := IntToStr(OpManItem.Handle) + ': ' + OpManItem.Operation.GetDescription(fsoddJob) + ' - ' + GetProgressString(100); SetSize; if not TfrmFileOp.IsOpenedFor(OpManItem.Handle) and not (OpManItem.Operation.State in [fsosStopping, fsosStopped]) then Visibility := True; end; end; end else begin New(OperationItem); FQueues.Add(OperationItem); OperationItem^.QueueId := Queue.Identifier; OperationItem^.OperationHandle := InvalidOperationHandle; OutString := Queue.GetDescription(True) + LineEnding + Queue.Items[0].Operation.GetDescription(fsoddJob) + ' - ' + GetProgressString(100); SetSize; if not TfrmFileOp.IsOpenedFor(Queue.Identifier) then Visibility := True; end; end; end; ClientHeight := OverallHeight + 2; ClientWidth := Max(OverallWidth - HorizontalSpaceBetween, FParentWidth); Visible := Visibility; end; procedure TOperationsPanel.UpdateVisibility; var OpManItem: TOperationsManagerItem; QueueIndex, OperIndex: Integer; Queue: TOperationsManagerQueue; Visibility: Boolean = False; begin for QueueIndex := 0 to OperationsManager.QueuesCount - 1 do begin Queue := OperationsManager.QueueByIndex[QueueIndex]; if Queue.Count > 0 then begin if Queue.Identifier = FreeOperationsQueueId then begin for OperIndex := 0 to Queue.Count - 1 do begin OpManItem := Queue.Items[OperIndex]; if Assigned(OpManItem) then begin if not TfrmFileOp.IsOpenedFor(OpManItem.Handle) and not (OpManItem.Operation.State in [fsosStopping, fsosStopped]) then Visibility := True; end; end; end else begin if not TfrmFileOp.IsOpenedFor(Queue.Identifier) then Visibility := True; end; end; end; Visible := Visibility; end; {$if lcl_fullversion >= 1070000} procedure TOperationsPanel.SetParent(NewParent: TWinControl); var AForm: TCustomForm; begin inherited SetParent(NewParent); AForm := GetParentForm(NewParent); if Assigned(AForm) then begin FMaximumItemWidth := ScaleX(MaximumItemWidth, AForm.DesignTimePPI); end; end; {$endif} constructor TOperationsPanel.Create(AOwner: TComponent); begin inherited Create(AOwner); FOperations := TFPList.Create; FQueues := TFPList.Create; FMaximumItemWidth := MaximumItemWidth; FUserInterface := TFileSourceOperationMessageBoxesUI.Create; OperationsManager.AddEventsListener( [omevOperationAdded, omevOperationRemoved, omevOperationMoved], @OperationsManagerEvent); TfrmFileOp.AddEventsListener([opwevOpened, opwevClosed], @ProgressWindowEvent); end; destructor TOperationsPanel.Destroy; begin OperationsManager.RemoveEventsListener( [omevOperationAdded, omevOperationRemoved, omevOperationMoved], @OperationsManagerEvent); TfrmFileOp.RemoveEventsListener([opwevOpened, opwevClosed], @ProgressWindowEvent); inherited Destroy; FUserInterface.Free; FOperations.Free; FQueues.Free; end; procedure TOperationsPanel.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ClickPos: TPoint; OpManItem: TOperationsManagerItem; procedure HandleItem(Item: POperationPanelItem); var Queue: TOperationsManagerQueue; begin Queue := OperationsManager.QueueByIdentifier[Item^.QueueId]; if Assigned(Queue) and (Queue.Count > 0) then begin if Item^.OperationHandle = InvalidOperationHandle then begin case Button of mbLeft: TfrmFileOp.ShowFor(Item^.QueueId, [opwoIfExistsBringToFront]); mbMiddle: Queue.TogglePause; mbRight: ShowOperationsViewer(Item^.QueueId); end; end else begin OpManItem := Queue.ItemByHandle[Item^.OperationHandle]; if Assigned(OpManItem) then begin case Button of mbLeft: TfrmFileOp.ShowFor(OpManItem.Handle, [opwoIfExistsBringToFront]); mbMiddle: OpManItem.Operation.TogglePause; mbRight: ShowOperationsViewer(OpManItem.Handle); end; end; end; end; end; var ItemRect: TRect; Item: POperationPanelItem; begin inherited MouseDown(Button, Shift, X, Y); ClickPos := Point(X, Y); ItemRect := ClientRect; InflateRect(ItemRect, -PanelBorderWidth, -PanelBorderWidth); ItemRect.Right := ItemRect.Left - HorizontalSpaceBetween; for Item in FQueues do begin ItemRect.Left := ItemRect.Right + HorizontalSpaceBetween; ItemRect.Right := ItemRect.Left + Item^.Width; if PtInRect(ItemRect, ClickPos) then begin HandleItem(Item); Exit; end; end; for Item in FOperations do begin ItemRect.Left := ItemRect.Right + HorizontalSpaceBetween; ItemRect.Right := ItemRect.Left + Item^.Width; if PtInRect(ItemRect, ClickPos) then begin HandleItem(Item); Exit; end; end; end; procedure TOperationsPanel.Paint; var OpManItem: TOperationsManagerItem; ARect, ItemRect: TRect; ColorFrom, ColorTo: TColor; Queue: TOperationsManagerQueue; Item: POperationPanelItem; i: Integer; AProgress: Double; procedure DrawString(s: String); begin // Draw output string Canvas.Brush.Style := bsClear; ARect := ItemRect; InflateRect(ARect, -4, -2); DrawText(Canvas.Handle, PChar(s), Length(s), ARect, DT_LEFT or DT_VCENTER or DT_NOPREFIX); end; procedure DrawProgress(State: TFileSourceOperationState; Progress: Double); begin // Draw progress bar GetStateColor(State, ColorFrom, ColorTo); ARect := ItemRect; InflateRect(ARect, -1, -1); ARect.Right := ARect.Left + Round((ARect.Right - ARect.Left) * Progress); Canvas.GradientFill(ARect, ColorFrom, ColorTo, gdVertical); // Special indication if operation is paused/stopped if State in [fsosPaused, fsosStopped, fsosWaitingForFeedback] then begin Canvas.Brush.Color:= ColorFrom; Canvas.Brush.Style:= bsDiagCross; ARect.Left:= ARect.Right + 1; ARect.Right:= ItemRect.Right - 1; Canvas.FillRect(ARect); end; end; begin inherited Paint; ItemRect := ClientRect; Canvas.Pen.Color:= cl3DDkShadow; Canvas.Rectangle(ItemRect); InflateRect(ItemRect, -PanelBorderWidth, -PanelBorderWidth); Canvas.GradientFill(ItemRect, LightColor(clBtnHiLight, 20), clBtnFace, gdVertical); ItemRect.Right := ItemRect.Left - HorizontalSpaceBetween; i := 0; while i < FQueues.Count do begin Item := FQueues[i]; Queue := OperationsManager.QueueByIdentifier[Item^.QueueId]; if Assigned(Queue) and (Queue.Count > 0) then begin OpManItem := Queue.Items[0]; if Assigned(OpManItem) then begin ItemRect.Left := ItemRect.Right + HorizontalSpaceBetween; ItemRect.Right := ItemRect.Left + Item^.Width; // Draw border Canvas.Pen.Color := LightColor(cl3DDkShadow, 25); Canvas.Pen.Style := psSolid; Canvas.Rectangle(ItemRect); AProgress := OpManItem.Operation.Progress; DrawProgress(OpManItem.Operation.State, AProgress); DrawString(Queue.GetDescription(True) + LineEnding + OpManItem.Operation.GetDescription(fsoddJob) + ' - ' + GetProgressString(AProgress)); Inc(i); end else DeleteItem(FQueues, i); end else DeleteItem(FQueues, i); end; i := 0; while i < FOperations.Count do begin Item := FOperations[i]; Queue := OperationsManager.QueueByIdentifier[Item^.QueueId]; if Assigned(Queue) and (Queue.Count > 0) then begin OpManItem := Queue.ItemByHandle[Item^.OperationHandle]; if Assigned(OpManItem) then begin ItemRect.Left := ItemRect.Right + HorizontalSpaceBetween; ItemRect.Right := ItemRect.Left + Item^.Width; if TfrmFileOp.IsOpenedFor(OpManItem.Handle) then Canvas.Pen.Color := clMenuHighlight else Canvas.Pen.Color := LightColor(cl3DDkShadow, 40); // Draw border Canvas.Pen.Style := psSolid; Canvas.Rectangle(ItemRect); AProgress := OpManItem.Operation.Progress; DrawProgress(OpManItem.Operation.State, AProgress); DrawString(IntToStr(OpManItem.Handle) + ': ' + OpManItem.Operation.GetDescription(fsoddJob) + ' - ' + GetProgressString(AProgress)); Inc(i); end else DeleteItem(FOperations, i); end else DeleteItem(FOperations, i); end; end; procedure TOperationsPanel.UpdateView; begin Invalidate; end; end. doublecmd-1.1.22/src/uparitercontrols.pas0000644000175000001440000002465514743153644017535 0ustar alexxusers{ Copyright (C) 2004 Flavio Etrusco Copyright (C) 2011-2015 Alexander Koblov (alexx2000@mail.ru) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } unit uPariterControls; {$mode objfpc}{$H+} interface uses Controls, SysUtils, Classes, SynEditHighlighter, uSynDiffControls, uDiffONP; const SynSpaceGlyph = Chr($B7); //'·' SynTabGlyph = Chr($BB); //'»' type { TSynDiffHighlighter } TSynDiffHighlighter = class(TSynCustomHighlighter) private fWhitespaceAttribute: TSynHighlighterAttributes; fAddedAttribute: TSynHighlighterAttributes; fRemovedAttribute: TSynHighlighterAttributes; fModifiedAttribute: TSynHighlighterAttributes; fUnmodifiedAttribute: TSynHighlighterAttributes; fDiff: TDiff; fTokens: TStringList; {} fRun: Integer; fTokenPos: Integer; fTokenLen: Integer; fTokenKind: TChangeKind; {} fAddedAttriPointer: TSynHighlighterAttributes; fDefaultAttriPointer: TSynHighlighterAttributes; function GetEditor: TSynDiffEdit; procedure ComputeTokens(const aOldLine, aNewLine: String); protected function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; public constructor Create(aOwner: TSynDiffEdit); reintroduce; overload; constructor Create(aOwner: TComponent); overload; override; destructor Destroy; override; procedure ResetRange; override; procedure SetLine(const aNewValue: String; aLineNumber: Integer); override; procedure UpdateColors; function GetEol: Boolean; override; function GetToken: String; override; procedure GetTokenEx(out TokenStart: PChar; out TokenLength: Integer); override; function GetTokenAttribute: TSynHighlighterAttributes; override; function GetTokenKind: Integer; override; function GetTokenPos: Integer; override; // 0-based procedure Next; override; property Editor: TSynDiffEdit read GetEditor; end; implementation uses LazUTF8, Graphics, DCUnicodeUtils; { TSynDiffHighlighter } procedure TSynDiffHighlighter.ComputeTokens(const aOldLine, aNewLine: String); var I: Integer; LastToken: String; LastKind: TChangeKind; aOld, aNew: UCS4String; FirstToken: Boolean = True; procedure AddTokenIfNeed(Symbol: UCS4Char; Kind: TChangeKind); begin if (Kind = LastKind) then // Same Kind, no need to change colors LastToken := LastToken + UnicodeToUTF8(Symbol) else begin fTokens.AddObject(LastToken, TObject(PtrInt(LastKind))); LastToken := UnicodeToUTF8(Symbol); LastKind := Kind; end; end; begin // Convert to UCS-4 aOld:= UTF8ToUCS4(aOldLine); aNew:= UTF8ToUCS4(aNewLine); // Compare lines if not Assigned(Editor.OriginalFile) then // Original file fDiff.Execute(PInteger(aNew), PInteger(aOld), Length(aNew), Length(aOld)) else if not Assigned(Editor.ModifiedFile) then // Modified file fDiff.Execute(PInteger(aOld), PInteger(aNew), Length(aOld), Length(aNew)); // Prepare diffs to display LastToken:= EmptyStr; for I := 0 to fDiff.Count - 1 do with fDiff.Compares[I] do begin if not Assigned(Editor.OriginalFile) then // Original file begin // Show changes for original file if Kind <> ckAdd then begin if FirstToken then begin LastKind:= Kind; FirstToken:= False; end; AddTokenIfNeed(int1, Kind); end; end else if not Assigned(Editor.ModifiedFile) then // Modified file begin // Show changes for modified file if Kind <> ckDelete then begin if FirstToken then begin LastKind:= Kind; FirstToken:= False; end; AddTokenIfNeed(int2, Kind); end; end; end; // Add last token fTokens.AddObject(LastToken, TObject(PtrInt(LastKind))); end; constructor TSynDiffHighlighter.Create(aOwner: TComponent); begin Create(aOwner as TSynDiffEdit); end; constructor TSynDiffHighlighter.Create(aOwner: TSynDiffEdit); begin inherited Create(aOwner); fDiff := TDiff.Create(Self); {} fWhitespaceAttribute := TSynHighlighterAttributes.Create('Whitespace'); AddAttribute(fWhitespaceAttribute); {} fAddedAttribute := TSynHighlighterAttributes.Create('Added'); fAddedAttribute.Style := [fsBold]; AddAttribute(fAddedAttribute); {} fRemovedAttribute := TSynHighlighterAttributes.Create('Removed'); fRemovedAttribute.Style := [fsBold]; AddAttribute(fRemovedAttribute); {} fModifiedAttribute := TSynHighlighterAttributes.Create('Modified'); fModifiedAttribute.Style := [fsBold]; AddAttribute(fModifiedAttribute); {} fUnmodifiedAttribute := TSynHighlighterAttributes.Create('Unmodified'); AddAttribute(fUnmodifiedAttribute); {} UpdateColors; SetAttributesOnChange(@DefHighlightChange); fTokens := TStringList.Create; end; destructor TSynDiffHighlighter.Destroy; begin inherited Destroy; fTokens.Free; end; function TSynDiffHighlighter.GetEditor: TSynDiffEdit; begin Result := TSynDiffEdit(inherited Owner); end; function TSynDiffHighlighter.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; begin if Index = SYN_ATTR_WHITESPACE then Result := fDefaultAttriPointer else Result := nil; end; function TSynDiffHighlighter.GetEol: Boolean; begin Result := (fTokenLen = 0); end; function TSynDiffHighlighter.GetToken: String; var cChar: Integer; begin Result := fTokens[fRun]; if (Editor.PaintStyle = psForeground) and (fTokenKind <> ckNone) then for cChar := 1 to Length(Result) do if Result[cChar] = #32 then Result[cChar] := SynSpaceGlyph else if Result[cChar] = #9 then Result[cChar] := SynTabGlyph; end; function TSynDiffHighlighter.GetTokenAttribute: TSynHighlighterAttributes; begin case fTokenKind of ckAdd: Result := fAddedAttriPointer; ckModify: Result := fModifiedAttribute; ckDelete: Result := fAddedAttriPointer; else Result := fDefaultAttriPointer; end; end; function TSynDiffHighlighter.GetTokenKind: integer; begin Result := Ord(fTokenKind); end; procedure TSynDiffHighlighter.GetTokenEx(out TokenStart: PChar; out TokenLength: integer); begin TokenLength:= fTokenLen; if TokenLength > 0 then TokenStart:= PChar(fTokens[fRun]) else TokenStart:= nil; end; function TSynDiffHighlighter.GetTokenPos: Integer; begin Result := fTokenPos; end; procedure TSynDiffHighlighter.Next; begin Inc(fRun); if fRun = fTokens.Count then begin fTokenLen := 0; Exit; end; Inc(fTokenPos, fTokenLen); fTokenLen := Length(fTokens[fRun]); fTokenKind := TChangeKind(PtrInt(fTokens.Objects[fRun])); end; procedure TSynDiffHighlighter.ResetRange; begin fDefaultAttriPointer := fWhitespaceAttribute; end; procedure TSynDiffHighlighter.SetLine(const aNewValue: String; aLineNumber: Integer); var vOtherEdit: TSynDiffEdit; vOldLine: String; vNewLine: String; begin fDiff.Clear; fTokens.Clear; fRun := -1; fTokenPos := 0; fTokenLen := 0; if Editor.OriginalFile <> nil then begin fAddedAttriPointer := fAddedAttribute; vOtherEdit := Editor.OriginalFile; end else begin fAddedAttriPointer := fRemovedAttribute; vOtherEdit := Editor.ModifiedFile; end; if TChangeKind(Editor.Lines.Kind[aLineNumber]) = ckModify then fDefaultAttriPointer := fUnmodifiedAttribute else fDefaultAttriPointer := fWhitespaceAttribute; if (vOtherEdit <> nil) and (aLineNumber < vOtherEdit.Lines.Count) then vOldLine := vOtherEdit.Lines[aLineNumber]; vNewLine := aNewValue; if Length(vNewLine) <> 0 then begin if (Length(vOldLine) <> 0) and (TChangeKind(Editor.Lines.Kind[aLineNumber]) = ckModify) then ComputeTokens(vOldLine, vNewLine) else fTokens.Add(vNewLine); end; Next; end; procedure TSynDiffHighlighter.UpdateColors; begin BeginUpdate; try if Editor.PaintStyle = psForeground then begin fAddedAttribute.Foreground := Editor.Colors.Added; fAddedAttribute.Background := clBtnFace; fRemovedAttribute.Foreground := Editor.Colors.Deleted; fRemovedAttribute.Background := clBtnFace; fModifiedAttribute.Foreground := Editor.Colors.Modified; fModifiedAttribute.Background := clBtnFace; fUnmodifiedAttribute.Foreground := clNone; fUnmodifiedAttribute.Background := clNone; end else begin fAddedAttribute.Foreground := clNone; fAddedAttribute.Background := Editor.Colors.Added; fRemovedAttribute.Foreground := clNone; fRemovedAttribute.Background := Editor.Colors.Deleted; fModifiedAttribute.Foreground := clNone; fModifiedAttribute.Background := Editor.Colors.Modified; fUnmodifiedAttribute.Foreground := clNone; fUnmodifiedAttribute.Background := Editor.Colors.Modified; end; finally EndUpdate; end; end; end. doublecmd-1.1.22/src/upathlabel.pas0000644000175000001440000001550614743153644016232 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Label displaying a path, highlighting directories with mouse. Copyright (C) 2010-2011 Przemysław Nagay (cobines@gmail.com) Copyright (C) 2014-2020 Alexander Koblov (alexx2000@mail.ru) 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 } unit uPathLabel; {$mode objfpc}{$H+} interface uses Classes, SysUtils, StdCtrls, Graphics; type { TPathLabel } TPathLabel = class(TLabel) private FActive: Boolean; FAllowHighlight: Boolean; FHighlightStartPos: Integer; FHighlightText: String; FMousePos: Integer; FColors: array[0..3] of TColor; {en How much space to leave between the text and left border. } FLeftSpacing: Integer; {en If a user clicks on a parent directory of the path, this stores the full path of that parent directory. } FSelectedDir: String; {en If a mouse if over some parent directory of the currently displayed path, it is highlighted, so that user can click on it. } procedure Highlight; function GetColor(const AIndex: Integer): TColor; procedure SetColor(const AIndex: Integer; const AValue: TColor); overload; protected procedure TextChanged; override; procedure MouseEnter; override; procedure MouseMove(Shift: TShiftState; X,Y: Integer); override; procedure MouseLeave; override; public constructor Create(AOwner: TComponent; bAllowHighlight: Boolean = False); reintroduce; procedure Paint; override; {en Changes drawing colors depending active/inactive state. } procedure SetActive(Active: Boolean); property AllowHighlight: Boolean read FAllowHighlight write FAllowHighlight; property LeftSpacing: Integer read FLeftSpacing write FLeftSpacing; property SelectedDir: String read FSelectedDir; property ActiveColor: TColor index 0 read GetColor write SetColor; property ActiveFontColor: TColor index 1 read GetColor write SetColor; property InactiveColor: TColor index 2 read GetColor write SetColor; property InactiveFontColor: TColor index 3 read GetColor write SetColor; end; implementation uses Controls, Math; { TPathLabel } constructor TPathLabel.Create(AOwner: TComponent; bAllowHighlight: Boolean); begin FLeftSpacing := 3; // set before painting FColors[0] := clHighlight; FColors[1] := clHighlightText; FColors[2] := clBtnFace; FColors[3] := clBtnText; inherited Create(AOwner); FAllowHighlight := bAllowHighlight; FSelectedDir := ''; FHighlightStartPos := -1; FHighlightText := ''; SetActive(False); end; procedure TPathLabel.Paint; var TextTop: Integer; begin Canvas.Brush.Color := Color; Canvas.Font.Color := Font.Color; // Center vertically. TextTop := (Height - Canvas.TextHeight(Text)) div 2; Canvas.FillRect(0, 0, Width, Height); // background Canvas.TextOut(LeftSpacing, TextTop, Text); // path // Highlight part of the path if mouse is over it. if FHighlightStartPos <> -1 then begin Canvas.Brush.Color := Font.Color; // reverse colors Canvas.Font.Color := Color; Canvas.TextOut(FHighlightStartPos, TextTop, FHighlightText); end; end; procedure TPathLabel.SetActive(Active: Boolean); begin case Active of False: begin Color := InactiveColor; Font.Color := InactiveFontColor; end; True: begin Color := ActiveColor; Font.Color := ActiveFontColor; end; end; FActive := Active; end; procedure TPathLabel.Highlight; var LeftText: String; PartText: String; StartPos, CurPos: Integer; PartWidth: Integer; CurrentHighlightPos, NewHighlightPos: Integer; TextLen: Integer; begin NewHighlightPos := -1; Canvas.Font := Self.Font; TextLen := Length(Text); // Start from the first character, but omit any path delimiters at the beginning. StartPos := 1; while (StartPos <= TextLen) and (Text[StartPos] = PathDelim) do Inc(StartPos); for CurPos := StartPos + 1 to TextLen - 1 do begin if Text[CurPos] = PathDelim then begin PartText := Copy(Text, StartPos, CurPos - StartPos); PartWidth := Canvas.TextWidth(PartText); LeftText := Copy(Text, 0, CurPos-1 ); CurrentHighlightPos:= LeftSpacing + Canvas.TextWidth( LeftText ) - PartWidth; // If mouse is over this part of the path - highlight it. if InRange(FMousePos, CurrentHighlightPos, CurrentHighlightPos + PartWidth) then begin NewHighlightPos := CurrentHighlightPos; Break; end; StartPos := CurPos + 1; end; end; // Repaint if highlighted part has changed. if NewHighlightPos <> FHighlightStartPos then begin // Omit minimized part of the displayed path. if PartText = '..' then FHighlightStartPos := -1 else FHighlightStartPos := NewHighlightPos; if FHighlightStartPos <> -1 then begin Cursor := crHandPoint; FHighlightText := PartText; // If clicked, this will be the new directory. FSelectedDir := Copy(Text, 1, CurPos - 1); end else begin Cursor := crDefault; FSelectedDir := ''; FHighlightText := ''; end; Self.Invalidate; end; end; function TPathLabel.GetColor(const AIndex: Integer): TColor; begin Result:= FColors[AIndex]; end; procedure TPathLabel.SetColor(const AIndex: Integer; const AValue: TColor); begin FColors[AIndex] := AValue; SetActive(FActive); end; procedure TPathLabel.TextChanged; begin inherited TextChanged; if FAllowHighlight and MouseInClient then Highlight; end; procedure TPathLabel.MouseEnter; begin inherited MouseEnter; if FAllowHighlight then begin Cursor := crDefault; FMousePos := ScreenToClient(Mouse.CursorPos).X; Highlight; Invalidate; end; end; procedure TPathLabel.MouseMove(Shift: TShiftState; X,Y: Integer); begin inherited MouseMove(Shift, X, Y); FMousePos := X; if FAllowHighlight then Highlight; end; procedure TPathLabel.MouseLeave; begin inherited MouseLeave; if FAllowHighlight then begin FSelectedDir := ''; FHighlightStartPos := -1; FHighlightText := ''; Cursor := crDefault; Invalidate; end; end; end. doublecmd-1.1.22/src/uquickviewpanel.pas0000644000175000001440000002414114743153644017320 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Quick view panel Copyright (C) 2009-2024 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uQuickViewPanel; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, ExtCtrls, fViewer, uFileViewNotebook, uFile, uFileSource, uFileView; type { TQuickViewPanel } TQuickViewPanel = class(TPanel) private FFirstFile: Boolean; FFileViewPage: TFileViewPage; FFileView: TFileView; FFileSource: IFileSource; FViewer: TfrmViewer; FFileName: String; FTempFileSource: IFileSource; FLastFocusedControl: TWinControl; private procedure LoadFile(const aFileName: String); procedure OnChangeFileView(Sender: TObject); procedure CreateViewer(aFileView: TFileView); procedure FileViewChangeActiveFile(Sender: TFileView; const aFile : TFile); function handleLinksToLocal( const Sender:TFileView; const aFile:TFile; var fullPath:String; var showMsg:String ): Boolean; function handleNotDirect( const Sender:TFileView; const aFile:TFile; var fullPath:String; var showMsg:String ): TDuplicates; function handleDirect( const Sender:TFileView; const aFile:TFile; var fullPath:String; var showMsg:String ): Boolean; procedure PrepareView(const aFile: TFile; var FileName: String); protected procedure DoOnShowHint(HintInfo: PHintInfo) override; public constructor Create(TheOwner: TComponent; aParent: TFileViewPage); reintroduce; destructor Destroy; override; end; procedure QuickViewShow(aFileViewPage: TFileViewPage; aFileView: TFileView); procedure QuickViewClose; var QuickViewPanel: TQuickViewPanel; implementation uses LCLProc, Forms, DCOSUtils, DCStrUtils, fMain, uTempFileSystemFileSource, uLng, uFileSourceProperty, uFileSourceOperation, uFileSourceOperationTypes, uGlobs, uShellExecute; procedure QuickViewShow(aFileViewPage: TFileViewPage; aFileView: TFileView); var aFile: TFile; begin frmMain.actQuickView.Enabled:= False; try QuickViewPanel:= TQuickViewPanel.Create(Application, aFileViewPage); QuickViewPanel.CreateViewer(aFileView); aFile := aFileView.CloneActiveFile; try QuickViewPanel.FileViewChangeActiveFile(aFileView, aFile); finally FreeAndNil(aFile); end; finally frmMain.actQuickView.Enabled:= True; frmMain.actQuickView.Checked:= True; end; end; procedure QuickViewClose; begin if Assigned(QuickViewPanel) then begin FreeAndNil(QuickViewPanel); frmMain.actQuickView.Checked:= False; end; end; { TQuickViewPanel } procedure TQuickViewPanel.DoOnShowHint(HintInfo: PHintInfo); begin HintInfo^.HintStr:= ''; end; constructor TQuickViewPanel.Create(TheOwner: TComponent; aParent: TFileViewPage); begin inherited Create(TheOwner); Parent:= aParent; Align:= alClient; FFileViewPage:= aParent; FFileSource:= nil; FViewer:= nil; end; destructor TQuickViewPanel.Destroy; begin FFileView.OnChangeActiveFile:= nil; TFileViewPage(FFileView.NotebookPage).OnChangeFileView:= nil; FViewer.ExitQuickView; FFileViewPage.FileView.Visible:= True; FreeAndNil(FViewer); FFileSource:= nil; FFileView.SetFocus; inherited Destroy; end; procedure TQuickViewPanel.CreateViewer(aFileView: TFileView); begin FViewer:= TfrmViewer.Create(Self, nil, True); FViewer.Parent:= Self; FViewer.ShowHint:= false; FViewer.BorderStyle:= bsNone; FViewer.Align:= alClient; FFirstFile:= True; FFileView:= aFileView; FFileSource:= aFileView.FileSource; FFileViewPage.FileView.Visible:= False; FFileView.OnChangeActiveFile:= @FileViewChangeActiveFile; with ClientRect do FViewer.SetBounds(Left, Top, Width, Height); TFileViewPage(FFileView.NotebookPage).OnChangeFileView:= @OnChangeFileView; end; procedure TQuickViewPanel.LoadFile(const aFileName: String); begin if (not FFirstFile) then begin FViewer.LoadNextFile(aFileName); end else begin FFirstFile:= False; Caption:= EmptyStr; FViewer.LoadFile(aFileName); FViewer.Show; end; // Viewer can steal focus, so restore it if Assigned(FLastFocusedControl) then FLastFocusedControl.SetFocus else if not FFileView.Focused then FFileView.SetFocus; end; procedure TQuickViewPanel.OnChangeFileView(Sender: TObject); begin FFileView:= TFileView(Sender); FFileView.OnChangeActiveFile:= @FileViewChangeActiveFile; end; procedure TQuickViewPanel.FileViewChangeActiveFile(Sender: TFileView; const aFile: TFile); var fullPath: String; showMsg: String; begin fullPath:= EmptyStr; showMsg:= EmptyStr; FLastFocusedControl:= TCustomForm(Self.GetTopParent).ActiveControl; try if not Assigned(aFile) then raise EAbort.Create(rsMsgErrNotSupported); if not handleLinksToLocal(Sender, aFile, fullPath, showMsg) then begin case handleNotDirect(Sender, aFile, fullPath, showMsg) of dupError: handleDirect(Sender, aFile, fullPath, showMsg); dupIgnore: Exit; end; end; if fullPath.IsEmpty() and ShowMsg.IsEmpty() then showMsg:= rsMsgErrNotSupported; except on E: EAbort do begin showMsg:= E.Message; end; end; if not fullPath.IsEmpty() then begin PrepareView(aFile, fullPath); LoadFile( fullPath ); end else begin FViewer.Hide; FFirstFile:= True; Caption:= showMsg; FViewer.LoadFile(EmptyStr); end; end; // return true if it should handle it, otherwise return false // If files are links to local files // for example: results from searching function TQuickViewPanel.handleLinksToLocal( const Sender:TFileView; const aFile:TFile; var fullPath:String; var showMsg:String ): Boolean; var ActiveFile: TFile = nil; begin if not (fspLinksToLocalFiles in Sender.FileSource.Properties) then exit(false); Result:= true; if not aFile.IsNameValid then exit; FFileSource := Sender.FileSource; ActiveFile:= aFile.Clone; try if not FFileSource.GetLocalName(ActiveFile) then exit; fullPath:= ActiveFile.FullPath; finally FreeAndNil(ActiveFile); end; end; // return true if it should handle it, otherwise return false // If files not directly accessible copy them to temp file source. // for examples: ftp function TQuickViewPanel.handleNotDirect(const Sender: TFileView; const aFile: TFile; var fullPath: String; var showMsg: String): TDuplicates; var ActiveFile: TFile = nil; TempFiles: TFiles = nil; Operation: TFileSourceOperation = nil; TempFileSource: ITempFileSystemFileSource = nil; begin if (fspDirectAccess in Sender.FileSource.Properties) then Exit(dupError); if mbCompareFileNames(FFileName, aFile.FullPath) then Exit(dupIgnore); Result:= dupAccept; FFileName:= aFile.FullPath; if aFile.IsDirectory or aFile.IsLinkToDirectory then exit; if not (fsoCopyOut in Sender.FileSource.GetOperationsTypes) then exit; ActiveFile:= aFile.Clone; TempFiles:= TFiles.Create(ActiveFile.Path); TempFiles.Add(aFile.Clone); try if FFileSource.IsClass(TTempFileSystemFileSource) then TempFileSource := (FFileSource as ITempFileSystemFileSource) else TempFileSource := TTempFileSystemFileSource.GetFileSource; Operation := Sender.FileSource.CreateCopyOutOperation( TempFileSource, TempFiles, TempFileSource.FileSystemRoot); if not Assigned(Operation) then exit; Sender.Enabled:= False; try Operation.Execute; finally FreeAndNil(Operation); Sender.Enabled:= True; end; FFileSource := TempFileSource; ActiveFile.Path:= TempFileSource.FileSystemRoot; fullPath:= ActiveFile.FullPath; finally FreeAndNil(TempFiles); FreeAndNil(ActiveFile); end; end; // return true if it should handle it, otherwise return false // for examples: file system function TQuickViewPanel.handleDirect( const Sender:TFileView; const aFile:TFile; var fullPath:String; var showMsg:String ): Boolean; var parentDir: String; begin Result:= true; FFileSource:= Sender.FileSource; if aFile.IsNameValid then begin fullPath:= aFile.FullPath; end else begin parentDir:= FFileSource.GetParentDir( aFile.Path ); if FFileSource.IsPathAtRoot(parentDir) then showMsg:= rsPropsFolder + ': ' + parentDir else fullPath:= ExcludeTrailingBackslash(parentDir); end; end; procedure TQuickViewPanel.PrepareView(const aFile: TFile; var FileName: String); var ATemp: TFile; sCmd: string = ''; sParams: string = ''; sStartPath: string = ''; bAbortOperationFlag: Boolean = False; bShowCommandLinePriorToExecute: Boolean = False; begin // Try to find 'view' command in the internal associations if gExts.GetExtActionCmd(aFile, 'view', sCmd, sParams, sStartPath) then begin // Internal viewer command if sCmd = '{!DC-VIEWER}' then begin ATemp:= AFile.Clone; try ATemp.FullPath:= FileName; sParams:= PrepareParameter(sParams, ATemp, [], @bShowCommandLinePriorToExecute, nil, nil, @bAbortOperationFlag); finally ATemp.Free; end; if not bAbortOperationFlag then begin if StrBegins(sParams, '')) then begin if (FTempFileSource = nil) then begin if FFileSource is TTempFileSystemFileSource then FTempFileSource:= FFileSource else FTempFileSource:= TTempFileSystemFileSource.GetFileSource; end; PrepareOutput(sParams, sStartPath, FTempFileSource.GetRootDir); if mbFileExists(sParams) then FileName:= sParams; end; end; end; end; end; end. doublecmd-1.1.22/src/uregexpr.pas0000644000175000001440000001067314743153644015752 0ustar alexxusersunit uRegExpr; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LConvEncoding, uConvEncoding, uRegExprA, uRegExprW, uRegExprU; type TRegExprType = (retAnsi, retUtf16le, retUtf8); type { TRegExprEx } TRegExprEx = class private FEncoding: String; FRegExpA: TRegExpr; FRegExpW: TRegExprW; FRegExpU: TRegExprU; FType: TRegExprType; function GetModifierI: Boolean; procedure SetModifierI(AValue: Boolean); procedure SetExpression(const AValue: String); function GetMatchLen(Idx : Integer): PtrInt; function GetMatchPos(Idx : Integer): PtrInt; public constructor Create(const AEncoding: String = EncodingDefault; ASetEncoding: Boolean = False); destructor Destroy; override; function Exec(AOffset: UIntPtr = 1): Boolean; function ReplaceAll(const AExpression, AStr, AReplacement: String): String; procedure ChangeEncoding(const AEncoding: String); procedure SetInputString(AInputString : Pointer; ALength : UIntPtr); public property Expression : String write SetExpression; property MatchPos [Idx : Integer] : PtrInt read GetMatchPos; property MatchLen [Idx : Integer] : PtrInt read GetMatchLen; property ModifierI: Boolean read GetModifierI write SetModifierI; end; implementation uses LazUTF8; { TRegExprEx } function TRegExprEx.GetModifierI: Boolean; begin case FType of retAnsi: Result:= FRegExpA.ModifierI; retUtf8: Result:= FRegExpU.ModifierI; retUtf16le: Result:= FRegExpW.ModifierI; end; end; procedure TRegExprEx.SetModifierI(AValue: Boolean); begin case FType of retAnsi: FRegExpA.ModifierI:= AValue; retUtf8: FRegExpU.ModifierI:= AValue; retUtf16le: FRegExpW.ModifierI:= AValue; end; end; procedure TRegExprEx.SetExpression(const AValue: String); begin case FType of retUtf8: FRegExpU.Expression:= AValue; retUtf16le: FRegExpW.Expression:= UTF8ToUTF16(AValue); retAnsi: FRegExpA.Expression:= ConvertEncoding(AValue, EncodingUTF8, FEncoding); end; end; function TRegExprEx.GetMatchLen(Idx: Integer): PtrInt; begin case FType of retAnsi: Result:= FRegExpA.MatchLen[Idx]; retUtf8: Result:= FRegExpU.MatchLen[Idx]; retUtf16le: Result:= FRegExpW.MatchLen[Idx] * SizeOf(WideChar); end; end; function TRegExprEx.GetMatchPos(Idx: Integer): PtrInt; begin case FType of retAnsi: Result:= FRegExpA.MatchPos[Idx]; retUtf8: Result:= FRegExpU.MatchPos[Idx]; retUtf16le: Result:= FRegExpW.MatchPos[Idx] * SizeOf(WideChar); end; end; constructor TRegExprEx.Create(const AEncoding: String; ASetEncoding: Boolean = False); begin FRegExpW:= TRegExprW.Create; FRegExpU:= TRegExprU.Create; FRegExpA:= TRegExpr.Create(AEncoding); if ASetEncoding then ChangeEncoding(AEncoding); end; destructor TRegExprEx.Destroy; begin FRegExpA.Free; FRegExpW.Free; FRegExpU.Free; inherited Destroy; end; function TRegExprEx.Exec(AOffset: UIntPtr): Boolean; begin case FType of retAnsi: Result:= FRegExpA.Exec(AOffset); retUtf8: Result:= FRegExpU.Exec(AOffset); retUtf16le: Result:= FRegExpW.Exec((AOffset + 1) div SizeOf(WideChar)); end; end; function TRegExprEx.ReplaceAll(const AExpression, AStr, AReplacement: String): String; var InputString: String; begin case FType of retAnsi: Result := FRegExpA.ReplaceRegExpr(AExpression, AStr, AReplacement, True); retUtf8: begin FRegExpU.Expression := AExpression; InputString := AStr; FRegExpU.SetInputString(PAnsiChar(InputString), Length(InputString)); if not FRegExpU.ReplaceAll(AReplacement, Result) then Result := InputString; end; retUtf16le: Result := AStr; // TODO : Implement ReplaceAll for TRegExprW end; end; procedure TRegExprEx.ChangeEncoding(const AEncoding: String); begin FEncoding:= NormalizeEncoding(AEncoding); if FEncoding = EncodingDefault then FEncoding:= GetDefaultTextEncoding; if FEncoding = EncodingUTF16LE then FType:= retUtf16le else if (FEncoding = EncodingUTF8) or (FEncoding = EncodingUTF8BOM) then FType:= retUtf8 else begin FType:= retAnsi; FRegExpA.ChangeEncoding(FEncoding); end; end; procedure TRegExprEx.SetInputString(AInputString: Pointer; ALength: UIntPtr); begin case FType of retAnsi: FRegExpA.SetInputString(AInputString, ALength); retUtf8: FRegExpU.SetInputString(AInputString, ALength); retUtf16le: FRegExpW.SetInputString(AInputString, ALength div SizeOf(WideChar)); end; end; end. doublecmd-1.1.22/src/uregexpra.pas0000644000175000001440000061635014743153644016117 0ustar alexxusersunit uRegExprA; { TRegExpr class library Delphi Regular Expressions Copyright (c) 1999-2004 Andrey V. Sorokin, St.Petersburg, Russia You can choose to use this Pascal unit in one of the two following licenses: Option 1> You may use this software in any kind of development, including comercial, redistribute, and modify it freely, under the following restrictions : 1. This software is provided as it is, without any kind of warranty given. Use it at Your own risk.The author is not responsible for any consequences of use of this software. 2. The origin of this software may not be mispresented, You must not claim that You wrote the original software. If You use this software in any kind of product, it would be appreciated that there in a information box, or in the documentation would be an acknowledgement like Partial Copyright (c) 2004 Andrey V. Sorokin https://sorokin.engineer/ andrey@sorokin.engineer 3. You may not have any income from distributing this source (or altered version of it) to other developers. When You use this product in a comercial package, the source may not be charged seperatly. 4. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 5. RegExp Studio application and all the visual components as well as documentation is not part of the TRegExpr library and is not free for usage. https://sorokin.engineer/ andrey@sorokin.engineer Option 2> The same modified LGPL with static linking exception as the Free Pascal RTL } { program is essentially a linear encoding of a nondeterministic finite-state machine (aka syntax charts or "railroad normal form" in parsing technology). Each node is an opcode plus a "next" pointer, possibly plus an operand. "Next" pointers of all nodes except BRANCH implement concatenation; a "next" pointer with a BRANCH on both ends of it connects two alternatives. (Here we have one of the subtle syntax dependencies: an individual BRANCH (as opposed to a collection of them) is never concatenated with anything because of operator precedence.) The operand of some types of node is a literal string; for others, it is a node leading into a sub-FSM. In particular, the operand of a BRANCH node is the first node of the branch. (NB this is *not* a tree structure: the tail of the branch connects to the thing following the set of BRANCHes.) } interface { off $DEFINE DebugSynRegExpr } // ======== Determine compiler {.$I regexpr_compilers.inc} // ======== Define base compiler options {$BOOLEVAL OFF} {$EXTENDEDSYNTAX ON} {$LONGSTRINGS ON} {$OPTIMIZATION ON} {$IFDEF FPC} {$MODE DELPHI} // Delphi-compatible mode in FreePascal {$INLINE ON} {$ENDIF} // ======== Define options for TRegExpr engine {.$DEFINE Unicode} // Use WideChar for characters and UnicodeString/WideString for strings { off $DEFINE UnicodeEx} // Support Unicode >0xFFFF, e.g. emoji, e.g. "." must find 2 WideChars of 1 emoji { off $DEFINE UseWordChars} // Use WordChars property, otherwise fixed list 'a'..'z','A'..'Z','0'..'9','_' { off $DEFINE UseSpaceChars} // Use SpaceChars property, otherwise fixed list { off $DEFINE UseLineSep} // Use LineSeparators property, otherwise fixed line-break chars {.$DEFINE FastUnicodeData} // Use arrays for UpperCase/LowerCase/IsWordChar, they take 320K more memory {$DEFINE UseFirstCharSet} // Enable optimization, which finds possible first chars of input string {$DEFINE RegExpPCodeDump} // Enable method Dump() to show opcode as string {$IFNDEF FPC} // Not supported in FreePascal {$DEFINE reRealExceptionAddr} // Exceptions will point to appropriate source line, not to Error procedure {$ENDIF} {$DEFINE ComplexBraces} // Support braces in complex cases {$IFNDEF Unicode} {$UNDEF UnicodeEx} {$UNDEF FastUnicodeData} {$ENDIF} // ======== Define Pascal-language options // Define 'UseAsserts' option (do not edit this definitions). // Asserts used to catch 'strange bugs' in TRegExpr implementation (when something goes // completely wrong). You can swith asserts on/off with help of {$C+}/{$C-} compiler options. {$IFDEF D3} {$DEFINE UseAsserts} {$ENDIF} {$IFDEF FPC} {$DEFINE UseAsserts} {$ENDIF} // Define 'use subroutine parameters default values' option (do not edit this definition). {$IFDEF D4} {$DEFINE DefParam} {$ENDIF} {$IFDEF FPC} {$DEFINE DefParam} {$ENDIF} // Define 'OverMeth' options, to use method overloading (do not edit this definitions). {$IFDEF D5} {$DEFINE OverMeth} {$ENDIF} {$IFDEF FPC} {$DEFINE OverMeth} {$ENDIF} // Define 'InlineFuncs' options, to use inline keyword (do not edit this definitions). {$IFDEF D8} {$DEFINE InlineFuncs} {$ENDIF} {$IFDEF FPC} {$DEFINE InlineFuncs} {$ENDIF} uses Classes, // TStrings in Split method SysUtils, // Exception {$IFDEF D2009} {$IFDEF D_XE}System.{$ENDIF}Character, {$ENDIF} Math; {$IFNDEF UniCode} type TRecodeTable = array[Byte] of Byte; {$ENDIF} type {$IFNDEF FPC} // Delphi doesn't have PtrInt but has NativeInt PtrInt = NativeInt; PtrUInt = NativeInt; {$ENDIF} {$IFDEF UniCode} PRegExprChar = PUnicodeChar; {$IFDEF FPC} RegExprString = UnicodeString; {$ELSE} {$IFDEF D2009} RegExprString = UnicodeString; {$ELSE} RegExprString = WideString; {$ENDIF} {$ENDIF} REChar = UnicodeChar; {$ELSE} PRegExprChar = PAnsiChar; RegExprString = AnsiString; REChar = AnsiChar; {$ENDIF} TREOp = REChar; // internal opcode type PREOp = ^TREOp; type TRegExprCharset = set of byte; const // Escape char ('\' in common r.e.) used for escaping metachars (\w, \d etc) EscChar = '\'; // Substitute method: prefix of group reference: $1 .. $9 and $ SubstituteGroupChar = '$'; RegExprModifierI: boolean = False; // default value for ModifierI RegExprModifierR: boolean = True; // default value for ModifierR RegExprModifierS: boolean = True; // default value for ModifierS RegExprModifierG: boolean = True; // default value for ModifierG RegExprModifierM: boolean = False; // default value for ModifierM RegExprModifierX: boolean = False; // default value for ModifierX {$IFDEF UseSpaceChars} // default value for SpaceChars RegExprSpaceChars: RegExprString = ' '#$9#$A#$D#$C; {$ENDIF} {$IFDEF UseWordChars} // default value for WordChars RegExprWordChars: RegExprString = '0123456789' + 'abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'; {$ENDIF} {$IFDEF UseLineSep} // default value for LineSeparators RegExprLineSeparators: RegExprString = #$d#$a#$b#$c {$IFDEF UniCode} + #$2028#$2029#$85 {$ENDIF}; {$ENDIF} // Tab and Unicode category "Space Separator": // https://www.compart.com/en/unicode/category/Zs RegExprHorzSeparators: RegExprString = #9#$20#$A0 {$IFDEF UniCode} + #$1680#$2000#$2001#$2002#$2003#$2004#$2005#$2006#$2007#$2008#$2009#$200A#$202F#$205F#$3000 {$ENDIF}; RegExprUsePairedBreak: boolean = True; RegExprReplaceLineBreak: RegExprString = sLineBreak; RegExprLookaheadIsAtomic: boolean = False; RegExprLookbehindIsAtomic: boolean = True; const RegexMaxGroups = 90; // Max number of groups. // Be carefull - don't use values which overflow OP_CLOSE* opcode // (in this case you'll get compiler error). // Big value causes slower work and more stack required. RegexMaxMaxGroups = 255; // Max possible value for RegexMaxGroups. // Don't change it! It's defined by internal TRegExpr design. {$IFDEF ComplexBraces} const LoopStackMax = 10; // max depth of loops stack //###0.925 type TRegExprLoopStack = array [1 .. LoopStackMax] of integer; {$ENDIF} type TRegExprModifiers = record I: boolean; // Case-insensitive. R: boolean; // Extended syntax for Russian ranges in []. // If True, then а-я additionally includes letter 'ё', // А-Я additionally includes 'Ё', and а-Я includes all Russian letters. // Turn it off if it interferes with your national alphabet. S: boolean; // Dot '.' matches any char, otherwise only [^\n]. G: boolean; // Greedy. Switching it off switches all operators to non-greedy style, // so if G=False, then '*' works like '*?', '+' works like '+?' and so on. M: boolean; // Treat string as multiple lines. It changes `^' and `$' from // matching at only the very start/end of the string to the start/end // of any line anywhere within the string. X: boolean; // Allow comments in regex using # char. end; function IsModifiersEqual(const A, B: TRegExprModifiers): boolean; type TRegExpr = class; TRegExprReplaceFunction = function(ARegExpr: TRegExpr): RegExprString of object; TRegExprCharChecker = function(ch: REChar): boolean of object; TRegExprCharCheckerArray = array[0 .. 30] of TRegExprCharChecker; TRegExprCharCheckerInfo = record CharBegin, CharEnd: REChar; CheckerIndex: integer; end; TRegExprCharCheckerInfos = array of TRegExprCharCheckerInfo; { TRegExpr } TRegExpr = class private GrpStart: array [0 .. RegexMaxGroups - 1] of PRegExprChar; // pointer to group start in InputString GrpEnd: array [0 .. RegexMaxGroups - 1] of PRegExprChar; // pointer to group end in InputString GrpIndexes: array [0 .. RegexMaxGroups - 1] of integer; // map global group index to _capturing_ group index GrpNames: array [0 .. RegexMaxGroups - 1] of RegExprString; // names of groups, if non-empty GrpAtomic: array [0 .. RegexMaxGroups - 1] of boolean; // group[i] is atomic (filled in Compile) GrpAtomicDone: array [0 .. RegexMaxGroups - 1] of boolean; // atomic group[i] is "done" (used in Exec* only) GrpOpCodes: array [0 .. RegexMaxGroups - 1] of PRegExprChar; // pointer to opcode of group[i] (used by OP_SUBCALL*) GrpSubCalled: array [0 .. RegexMaxGroups - 1] of boolean; // group[i] is called by OP_SUBCALL* GrpCount: integer; {$IFDEF ComplexBraces} LoopStack: TRegExprLoopStack; // state before entering loop LoopStackIdx: integer; // 0 - out of all loops {$ENDIF} // The "internal use only" fields to pass info from compile // to execute that permits the execute phase to run lots faster on // simple cases. regAnchored: REChar; // is the match anchored (at beginning-of-line only)? // regAnchored permits very fast decisions on suitable starting points // for a match, cutting down the work a lot. regMust permits fast rejection // of lines that cannot possibly match. The regMust tests are costly enough // that regcomp() supplies a regMust only if the r.e. contains something // potentially expensive (at present, the only such thing detected is * or + // at the start of the r.e., which can involve a lot of backup). regMustLen is // supplied because the test in regexec() needs it and regcomp() is computing // it anyway. regMust: PRegExprChar; // string (pointer into program) that match must include, or nil regMustLen: integer; // length of regMust string regMustString: RegExprString; // string which must occur in match (got from regMust/regMustLen) regLookahead: boolean; // regex has _some_ lookahead regLookaheadNeg: boolean; // regex has _nagative_ lookahead regLookaheadGroup: integer; // index of group for lookahead regLookbehind: boolean; // regex has positive lookbehind regNestedCalls: integer; // some attempt to prevent 'catastrophic backtracking' but not used {$IFDEF UseFirstCharSet} FirstCharSet: TRegExprCharset; FirstCharArray: array[byte] of boolean; {$ENDIF} // work variables for Exec routines - save stack in recursion regInput: PRegExprChar; // pointer to currently handling char of input string fInputStart: PRegExprChar; // pointer to first char of input string fInputEnd: PRegExprChar; // pointer after last char of input string fRegexStart: PRegExprChar; // pointer to first char of regex fRegexEnd: PRegExprChar; // pointer after last char of regex regCurrentGrp: integer; // index of group handling by OP_OPEN* opcode // work variables for compiler's routines regParse: PRegExprChar; // pointer to currently handling char of regex regNumBrackets: integer; // count of () brackets regDummy: REChar; // dummy pointer, used to detect 1st/2nd pass of Compile // if p=@regDummy, it is pass-1: opcode memory is not yet allocated programm: PRegExprChar; // pointer to opcode, =nil in pass-1 regCode: PRegExprChar; // pointer to last emitted opcode; changing in pass-2, but =@regDummy in pass-1 regCodeSize: integer; // total opcode size in REChars regCodeWork: PRegExprChar; // pointer to opcode, to first code after MAGIC regExactlyLen: PLongInt; // pointer to length of substring of OP_EXACTLY* inside opcode fSecondPass: boolean; // true inside pass-2 of Compile fExpression: RegExprString; // regex string fInputString: RegExprString; // input string fInputLength : UIntPtr; // input string length fLastError: integer; // Error call sets code of LastError fLastErrorOpcode: TREOp; fLastErrorSymbol: REChar; fModifiers: TRegExprModifiers; // regex modifiers fCompModifiers: TRegExprModifiers; // compiler's copy of modifiers fProgModifiers: TRegExprModifiers; // modifiers values from last programm compilation {$IFDEF UseSpaceChars} fSpaceChars: RegExprString; {$ENDIF} {$IFDEF UseWordChars} fWordChars: RegExprString; {$ENDIF} {$IFDEF UseLineSep} fLineSeparators: RegExprString; {$ENDIF} fUsePairedBreak: boolean; fReplaceLineEnd: RegExprString; // string to use for "\n" in Substitute method fSlowChecksSizeMax: integer; // Exec() param ASlowChecks is set to True, when Length(InputString) '1$ is \rub\' // If you want to place any number after '$' you must enclose it // with curly braces: '${12}'. // Example: 'a$12bc' -> 'abc' // 'a${1}2bc' -> 'a2bc'. function Substitute(const ATemplate: RegExprString): RegExprString; // Splits AInputStr to list by positions of all r.e. occurencies. // Internally calls Exec, ExecNext. procedure Split(const AInputStr: RegExprString; APieces: TStrings); function Replace(const AInputStr: RegExprString; const AReplaceStr: RegExprString; AUseSubstitution: boolean{$IFDEF DefParam} = False{$ENDIF}) // ###0.946 : RegExprString; {$IFDEF OverMeth} overload; function Replace(const AInputStr: RegExprString; AReplaceFunc: TRegExprReplaceFunction): RegExprString; overload; {$ENDIF} // Returns AInputStr with r.e. occurencies replaced by AReplaceStr. // If AUseSubstitution is true, then AReplaceStr will be used // as template for Substitution methods. // For example: // Expression := '({-i}block|var)\s*\(\s*([^ ]*)\s*\)\s*'; // Replace ('BLOCK( test1)', 'def "$1" value "$2"', True); // will return: def 'BLOCK' value 'test1' // Replace ('BLOCK( test1)', 'def "$1" value "$2"') // will return: def "$1" value "$2" // Internally calls Exec, ExecNext. // Overloaded version and ReplaceEx operate with callback function, // so you can implement really complex functionality. function ReplaceEx(const AInputStr: RegExprString; AReplaceFunc: TRegExprReplaceFunction): RegExprString; // Returns ID of last error, 0 if no errors (unusable if // Error method raises exception) and clear internal status // into 0 (no errors). function LastError: integer; // Returns Error message for error with ID = AErrorID. function ErrorMsg(AErrorID: integer): RegExprString; virtual; // Re-compile regex procedure Compile; {$IFDEF RegExpPCodeDump} // Show compiled regex in textual form function Dump: RegExprString; // Show single opcode in textual form function DumpOp(op: TREOp): RegExprString; {$ENDIF} function IsCompiled: boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} // Opcode contains only operations for fixed match length: EXACTLY*, ANY*, etc function IsFixedLength(var op: TREOp; var ALen: integer): boolean; // Regular expression. // For optimization, TRegExpr will automatically compiles it into 'P-code' // (You can see it with help of Dump method) and stores in internal // structures. Real [re]compilation occures only when it really needed - // while calling Exec, ExecNext, Substitute, Dump, etc // and only if Expression or other P-code affected properties was changed // after last [re]compilation. // If any errors while [re]compilation occures, Error method is called // (by default Error raises exception - see below) property Expression: RegExprString read fExpression write SetExpression; // Set/get default values of r.e.syntax modifiers. Modifiers in // r.e. (?ismx-ismx) will replace this default values. // If you try to set unsupported modifier, Error will be called // (by defaul Error raises exception ERegExpr). property ModifierStr: RegExprString read GetModifierStr write SetModifierStr; property ModifierI: boolean read GetModifierI write SetModifierI; property ModifierR: boolean read GetModifierR write SetModifierR; property ModifierS: boolean read GetModifierS write SetModifierS; property ModifierG: boolean read GetModifierG write SetModifierG; property ModifierM: boolean read GetModifierM write SetModifierM; property ModifierX: boolean read GetModifierX write SetModifierX; // returns current input string (from last Exec call or last assign // to this property). // Any assignment to this property clear Match* properties ! property InputString: RegExprString read fInputString write SetInputString; // Number of subexpressions has been found in last Exec* call. // If there are no subexpr. but whole expr was found (Exec* returned True), // then SubExprMatchCount=0, if no subexpressions nor whole // r.e. found (Exec* returned false) then SubExprMatchCount=-1. // Note, that some subexpr. may be not found and for such // subexpr. MathPos=MatchLen=-1 and Match=''. // For example: Expression := '(1)?2(3)?'; // Exec ('123'): SubExprMatchCount=2, Match[0]='123', [1]='1', [2]='3' // Exec ('12'): SubExprMatchCount=1, Match[0]='12', [1]='1' // Exec ('23'): SubExprMatchCount=2, Match[0]='23', [1]='', [2]='3' // Exec ('2'): SubExprMatchCount=0, Match[0]='2' // Exec ('7') - return False: SubExprMatchCount=-1 property SubExprMatchCount: integer read GetSubExprCount; // pos of entrance subexpr. #Idx into tested in last Exec* // string. First subexpr. has Idx=1, last - MatchCount, // whole r.e. has Idx=0. // Returns -1 if in r.e. no such subexpr. or this subexpr. // not found in input string. property MatchPos[Idx: integer]: PtrInt read GetMatchPos; // len of entrance subexpr. #Idx r.e. into tested in last Exec* // string. First subexpr. has Idx=1, last - MatchCount, // whole r.e. has Idx=0. // Returns -1 if in r.e. no such subexpr. or this subexpr. // not found in input string. // Remember - MatchLen may be 0 (if r.e. match empty string) ! property MatchLen[Idx: integer]: PtrInt read GetMatchLen; // == copy (InputString, MatchPos [Idx], MatchLen [Idx]) // Returns '' if in r.e. no such subexpr. or this subexpr. // not found in input string. property Match[Idx: integer]: RegExprString read GetMatch; // get index of group (subexpression) by name, to support named groups // like in Python: (?Pregex) function MatchIndexFromName(const AName: RegExprString): integer; function MatchFromName(const AName: RegExprString): RegExprString; // Returns position in r.e. where compiler stopped. // Useful for error diagnostics property CompilerErrorPos: PtrInt read GetCompilerErrorPos; {$IFDEF UseSpaceChars} // Contains chars, treated as /s (initially filled with RegExprSpaceChars // global constant) property SpaceChars: RegExprString read fSpaceChars write fSpaceChars; // ###0.927 {$ENDIF} {$IFDEF UseWordChars} // Contains chars, treated as /w (initially filled with RegExprWordChars // global constant) property WordChars: RegExprString read fWordChars write fWordChars; // ###0.929 {$ENDIF} {$IFDEF UseLineSep} // line separators (like \n in Unix) property LineSeparators: RegExprString read fLineSeparators write SetLineSeparators; // ###0.941 {$ENDIF} // support paired line-break CR LF property UseLinePairedBreak: boolean read fUsePairedBreak write SetUsePairedBreak; property ReplaceLineEnd: RegExprString read fReplaceLineEnd write fReplaceLineEnd; property SlowChecksSizeMax: integer read fSlowChecksSizeMax write fSlowChecksSizeMax; public function ExecRegExpr(const ARegExpr, AInputStr: RegExprString): Boolean; function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; AUseSubstitution: Boolean = False): RegExprString; end; type ERegExpr = class(Exception) public ErrorCode: integer; CompilerErrorPos: PtrInt; end; // true if string AInputString match regular expression ARegExpr // ! will raise exeption if syntax errors in ARegExpr function ExecRegExpr(const ARegExpr, AInputStr: RegExprString): boolean; // Split AInputStr into APieces by r.e. ARegExpr occurencies procedure SplitRegExpr(const ARegExpr, AInputStr: RegExprString; APieces: TStrings); // Returns AInputStr with r.e. occurencies replaced by AReplaceStr // If AUseSubstitution is true, then AReplaceStr will be used // as template for Substitution methods. // For example: // ReplaceRegExpr ('({-i}block|var)\s*\(\s*([^ ]*)\s*\)\s*', // 'BLOCK( test1)', 'def "$1" value "$2"', True) // will return: def 'BLOCK' value 'test1' // ReplaceRegExpr ('({-i}block|var)\s*\(\s*([^ ]*)\s*\)\s*', // 'BLOCK( test1)', 'def "$1" value "$2"') // will return: def "$1" value "$2" function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; AUseSubstitution: boolean{$IFDEF DefParam} = False{$ENDIF}): RegExprString; {$IFDEF OverMeth}overload; // ###0.947 // Alternate form allowing to set more parameters. type TRegexReplaceOption = ( rroModifierI, rroModifierR, rroModifierS, rroModifierG, rroModifierM, rroModifierX, rroUseSubstitution, rroUseOsLineEnd ); TRegexReplaceOptions = set of TRegexReplaceOption; function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; Options: TRegexReplaceOptions): RegExprString; overload; {$ENDIF} // Replace all metachars with its safe representation, // for example 'abc$cd.(' converts into 'abc\$cd\.\(' // This function useful for r.e. autogeneration from // user input function QuoteRegExprMetaChars(const AStr: RegExprString): RegExprString; // Makes list of subexpressions found in ARegExpr r.e. // In ASubExps every item represent subexpression, // from first to last, in format: // String - subexpression text (without '()') // low word of Object - starting position in ARegExpr, including '(' // if exists! (first position is 1) // high word of Object - length, including starting '(' and ending ')' // if exist! // AExtendedSyntax - must be True if modifier /m will be On while // using the r.e. // Useful for GUI editors of r.e. etc (You can find example of using // in TestRExp.dpr project) // Returns // 0 Success. No unbalanced brackets was found; // -1 There are not enough closing brackets ')'; // -(n+1) At position n was found opening '[' without //###0.942 // corresponding closing ']'; // n At position n was found closing bracket ')' without // corresponding opening '('. // If Result <> 0, then ASubExpr can contain empty items or illegal ones function RegExprSubExpressions(const ARegExpr: string; ASubExprs: TStrings; AExtendedSyntax: boolean{$IFDEF DefParam} = False{$ENDIF}): integer; implementation {$IFDEF FastUnicodeData} uses unicodedata; {$ENDIF} {$IFNDEF UNICODE} uses LazUTF8, LConvEncoding, uConvEncoding; {$ENDIF} const // TRegExpr.VersionMajor/Minor return values of these constants: REVersionMajor = 1; REVersionMinor = 153; OpKind_End = REChar(1); OpKind_MetaClass = REChar(2); OpKind_Range = REChar(3); OpKind_Char = REChar(4); OpKind_CategoryYes = REChar(5); OpKind_CategoryNo = REChar(6); RegExprAllSet = [0 .. 255]; RegExprWordSet = [Ord('a') .. Ord('z'), Ord('A') .. Ord('Z'), Ord('0') .. Ord('9'), Ord('_')]; RegExprDigitSet = [Ord('0') .. Ord('9')]; RegExprLowerAzSet = [Ord('a') .. Ord('z')]; RegExprUpperAzSet = [Ord('A') .. Ord('Z')]; RegExprAllAzSet = RegExprLowerAzSet + RegExprUpperAzSet; RegExprSpaceSet = [Ord(' '), $9, $A, $D, $C]; RegExprLineSeparatorsSet = [$d, $a, $b, $c] {$IFDEF UniCode} + [$85] {$ENDIF}; RegExprHorzSeparatorsSet = [9, $20, $A0]; MaxBracesArg = $7FFFFFFF - 1; // max value for {n,m} arguments //###0.933 type TRENextOff = PtrInt; // internal Next "pointer" (offset to current p-code) //###0.933 PRENextOff = ^TRENextOff; // used for extracting Next "pointers" from compiled r.e. //###0.933 TREBracesArg = integer; // type of {m,n} arguments PREBracesArg = ^TREBracesArg; TREGroupKind = ( gkNormalGroup, gkNonCapturingGroup, gkNamedGroupReference, gkComment, gkModifierString, gkLookahead, gkLookaheadNeg, gkLookbehind, gkLookbehindNeg, gkRecursion, gkSubCall ); const REOpSz = SizeOf(TREOp) div SizeOf(REChar); // size of OP_ command in REChars {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT} // add space for aligning pointer // -1 is the correct max size but also needed for InsertOperator that needs a multiple of pointer size RENextOffSz = (2 * SizeOf(TRENextOff) div SizeOf(REChar)) - 1; REBracesArgSz = (2 * SizeOf(TREBracesArg) div SizeOf(REChar)); // add space for aligning pointer {$ELSE} RENextOffSz = (SizeOf(TRENextOff) div SizeOf(REChar)); // size of Next pointer in REChars REBracesArgSz = SizeOf(TREBracesArg) div SizeOf(REChar); // size of BRACES arguments in REChars {$ENDIF} RENumberSz = SizeOf(LongInt) div SizeOf(REChar); function IsPairedBreak(p: PRegExprChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} const cBreak = {$IFDEF Unicode} $000D000A; {$ELSE} $0D0A; {$ENDIF} type PtrPair = {$IFDEF Unicode} ^LongInt; {$ELSE} ^Word; {$ENDIF} begin Result := PtrPair(p)^ = cBreak; end; function _FindCharInBuffer(SBegin, SEnd: PRegExprChar; Ch: REChar): PRegExprChar; {$IFDEF InlineFuncs}inline;{$ENDIF} begin while SBegin < SEnd do begin if SBegin^ = Ch then begin Result := SBegin; Exit; end; Inc(SBegin); end; Result := nil; end; function IsIgnoredChar(AChar: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case AChar of ' ', #9, #$d, #$a: Result := True else Result := False; end; end; function _IsMetaChar(AChar: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case AChar of 'd', 'D', 's', 'S', 'w', 'W', 'v', 'V', 'h', 'H': Result := True else Result := False; end; end; function AlignToPtr(const p: Pointer): Pointer; {$IFDEF InlineFuncs}inline;{$ENDIF} begin {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT} Result := Align(p, SizeOf(Pointer)); {$ELSE} Result := p; {$ENDIF} end; function AlignToInt(const p: Pointer): Pointer; {$IFDEF InlineFuncs}inline;{$ENDIF} begin {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT} Result := Align(p, SizeOf(integer)); {$ELSE} Result := p; {$ENDIF} end; function TRegExpr._UpperCase(Ch: REChar): REChar; begin Result := Ch; if (Ch >= 'a') and (Ch <= 'z') then begin Dec(Result, 32); Exit; end; if Ord(Ch) < 128 then Exit; {$IFDEF FPC} {$IFDEF UniCode} Result := UnicodeUpperCase(Ch)[1]; {$ELSE} Result := Chr(FUpperCase[Ord(Ch)]); {$ENDIF} {$ELSE} {$IFDEF UniCode} {$IFDEF D_XE4} Result := Ch.ToUpper; {$ELSE} {$IFDEF D2009} Result := TCharacter.ToUpper(Ch); {$ENDIF} {$ENDIF} {$ELSE} Result := AnsiUpperCase(Ch)[1]; {$ENDIF} {$ENDIF} end; function TRegExpr._LowerCase(Ch: REChar): REChar; begin Result := Ch; if (Ch >= 'A') and (Ch <= 'Z') then begin Inc(Result, 32); Exit; end; if Ord(Ch) < 128 then Exit; {$IFDEF FPC} {$IFDEF UniCode} Result := UnicodeLowerCase(Ch)[1]; {$ELSE} Result := Chr(FLowerCase[Ord(Ch)]); {$ENDIF} {$ELSE} {$IFDEF UniCode} {$IFDEF D_XE4} Result := Ch.ToLower; {$ELSE} {$IFDEF D2009} Result := TCharacter.ToLower(Ch); {$ENDIF} {$ENDIF} {$ELSE} Result := AnsiLowerCase(Ch)[1]; {$ENDIF} {$ENDIF} end; function TRegExpr.InvertCase(const Ch: REChar): REChar; {$IFDEF InlineFuncs}inline;{$ENDIF} begin Result := _UpperCase(Ch); if Result = Ch then Result := _LowerCase(Ch); end; function _FindClosingBracket(P, PEnd: PRegExprChar): PRegExprChar; var Level: integer; begin Result := nil; Level := 1; repeat if P >= PEnd then Exit; case P^ of EscChar: Inc(P); '(': begin Inc(Level); end; ')': begin Dec(Level); if Level = 0 then begin Result := P; Exit; end; end; end; Inc(P); until False; end; {$IFDEF UNICODEEX} procedure IncUnicode(var p: PRegExprChar); {$IFDEF InlineFuncs}inline;{$ENDIF} // make additional increment if we are on low-surrogate char // no need to check p= $DC00) and (Ord(ch) <= $DFFF) then Inc(p); end; procedure IncUnicode2(var p: PRegExprChar; var N: integer); {$IFDEF InlineFuncs}inline;{$ENDIF} var ch: REChar; begin Inc(p); Inc(N); ch := p^; if (Ord(ch) >= $DC00) and (Ord(ch) <= $DFFF) then begin Inc(p); Inc(N); end; end; {$ENDIF} { ============================================================= } { ===================== Global functions ====================== } { ============================================================= } function IsModifiersEqual(const A, B: TRegExprModifiers): boolean; begin Result := (A.I = B.I) and (A.G = B.G) and (A.M = B.M) and (A.S = B.S) and (A.R = B.R) and (A.X = B.X); end; function ParseModifiers(const APtr: PRegExprChar; ALen: integer; var AValue: TRegExprModifiers): boolean; // Parse string and set AValue if it's in format 'ismxrg-ismxrg' var IsOn: boolean; i: integer; begin Result := True; IsOn := True; for i := 0 to ALen-1 do case APtr[i] of '-': IsOn := False; 'I', 'i': AValue.I := IsOn; 'R', 'r': AValue.R := IsOn; 'S', 's': AValue.S := IsOn; 'G', 'g': AValue.G := IsOn; 'M', 'm': AValue.M := IsOn; 'X', 'x': AValue.X := IsOn; else begin Result := False; Exit; end; end; end; function ExecRegExpr(const ARegExpr, AInputStr: RegExprString): boolean; var r: TRegExpr; begin r := TRegExpr.Create; try r.Expression := ARegExpr; Result := r.Exec(AInputStr); finally r.Free; end; end; { of function ExecRegExpr -------------------------------------------------------------- } procedure SplitRegExpr(const ARegExpr, AInputStr: RegExprString; APieces: TStrings); var r: TRegExpr; begin APieces.Clear; r := TRegExpr.Create; try r.Expression := ARegExpr; r.Split(AInputStr, APieces); finally r.Free; end; end; { of procedure SplitRegExpr -------------------------------------------------------------- } function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; AUseSubstitution: boolean{$IFDEF DefParam} = False{$ENDIF}): RegExprString; begin with TRegExpr.Create do try Expression := ARegExpr; Result := Replace(AInputStr, AReplaceStr, AUseSubstitution); finally Free; end; end; { of function ReplaceRegExpr -------------------------------------------------------------- } {$IFDEF OverMeth} function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; Options: TRegexReplaceOptions): RegExprString; overload; begin with TRegExpr.Create do try ModifierI := (rroModifierI in Options); ModifierR := (rroModifierR in Options); ModifierS := (rroModifierS in Options); ModifierG := (rroModifierG in Options); ModifierM := (rroModifierM in Options); ModifierX := (rroModifierX in Options); // Set this after the above, if the regex contains modifiers, they will be applied. Expression := ARegExpr; if rroUseOsLineEnd in Options then ReplaceLineEnd := sLineBreak else ReplaceLineEnd := #10; Result := Replace(AInputStr, AReplaceStr, rroUseSubstitution in Options); finally Free; end; end; {$ENDIF} (* const MetaChars_Init = '^$.[()|?+*' + EscChar + '{'; MetaChars = MetaChars_Init; // not needed to be a variable, const is faster MetaAll = MetaChars_Init + ']}'; // Very similar to MetaChars, but slighly changed. *) function _IsMetaSymbol1(ch: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case ch of '^', '$', '.', '[', '(', ')', '|', '?', '+', '*', EscChar, '{': Result := True else Result := False end; end; function _IsMetaSymbol2(ch: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case ch of '^', '$', '.', '[', '(', ')', '|', '?', '+', '*', EscChar, '{', ']', '}': Result := True else Result := False end; end; function QuoteRegExprMetaChars(const AStr: RegExprString): RegExprString; var i, i0, Len: integer; ch: REChar; begin Result := ''; Len := Length(AStr); i := 1; i0 := i; while i <= Len do begin ch := AStr[i]; if _IsMetaSymbol2(ch) then begin Result := Result + System.Copy(AStr, i0, i - i0) + EscChar + ch; i0 := i + 1; end; Inc(i); end; Result := Result + System.Copy(AStr, i0, MaxInt); // Tail end; { of function QuoteRegExprMetaChars -------------------------------------------------------------- } function RegExprSubExpressions(const ARegExpr: string; ASubExprs: TStrings; AExtendedSyntax: boolean{$IFDEF DefParam} = False{$ENDIF}): integer; type TStackItemRec = record // ###0.945 SubExprIdx: integer; StartPos: PtrInt; end; TStackArray = packed array [0 .. RegexMaxMaxGroups - 1] of TStackItemRec; var Len, SubExprLen: integer; i, i0: integer; Modif: TRegExprModifiers; Stack: ^TStackArray; // ###0.945 StackIdx, StackSz: integer; begin Result := 0; // no unbalanced brackets found at this very moment FillChar(Modif, SizeOf(Modif), 0); ASubExprs.Clear; // I don't think that adding to non empty list // can be useful, so I simplified algorithm to work only with empty list Len := Length(ARegExpr); // some optimization tricks // first we have to calculate number of subexpression to reserve // space in Stack array (may be we'll reserve more than needed, but // it's faster then memory reallocation during parsing) StackSz := 1; // add 1 for entire r.e. for i := 1 to Len do if ARegExpr[i] = '(' then Inc(StackSz); // SetLength (Stack, StackSz); //###0.945 GetMem(Stack, SizeOf(TStackItemRec) * StackSz); try StackIdx := 0; i := 1; while (i <= Len) do begin case ARegExpr[i] of '(': begin if (i < Len) and (ARegExpr[i + 1] = '?') then begin // this is not subexpression, but comment or other // Perl extension. We must check is it (?ismxrg-ismxrg) // and change AExtendedSyntax if /x is changed. Inc(i, 2); // skip '(?' i0 := i; while (i <= Len) and (ARegExpr[i] <> ')') do Inc(i); if i > Len then Result := -1 // unbalansed '(' else if ParseModifiers(@ARegExpr[i0], i - i0, Modif) then // Alexey-T: original code had copy from i, not from i0 AExtendedSyntax := Modif.X; end else begin // subexpression starts ASubExprs.Add(''); // just reserve space with Stack[StackIdx] do begin SubExprIdx := ASubExprs.Count - 1; StartPos := i; end; Inc(StackIdx); end; end; ')': begin if StackIdx = 0 then Result := i // unbalanced ')' else begin Dec(StackIdx); with Stack[StackIdx] do begin SubExprLen := i - StartPos + 1; ASubExprs.Objects[SubExprIdx] := TObject(StartPos or (SubExprLen ShL 16)); ASubExprs[SubExprIdx] := System.Copy(ARegExpr, StartPos + 1, SubExprLen - 2); // add without brackets end; end; end; EscChar: Inc(i); // skip quoted symbol '[': begin // we have to skip character ranges at once, because they can // contain '#', and '#' in it must NOT be recognized as eXtended // comment beginning! i0 := i; Inc(i); if ARegExpr[i] = ']' // first ']' inside [] treated as simple char, no need to check '[' then Inc(i); while (i <= Len) and (ARegExpr[i] <> ']') do if ARegExpr[i] = EscChar // ###0.942 then Inc(i, 2) // skip 'escaped' char to prevent stopping at '\]' else Inc(i); if (i > Len) or (ARegExpr[i] <> ']') // ###0.942 then Result := -(i0 + 1); // unbalansed '[' //###0.942 end; '#': if AExtendedSyntax then begin // skip eXtended comments while (i <= Len) and (ARegExpr[i] <> #$d) and (ARegExpr[i] <> #$a) // do not use [#$d, #$a] due to UniCode compatibility do Inc(i); while (i + 1 <= Len) and ((ARegExpr[i + 1] = #$d) or (ARegExpr[i + 1] = #$a)) do Inc(i); // attempt to work with different kinds of line separators // now we are at the line separator that must be skipped. end; // here is no 'else' clause - we simply skip ordinary chars end; // of case Inc(i); // skip scanned char // ! can move after Len due to skipping quoted symbol end; // check brackets balance if StackIdx <> 0 then Result := -1; // unbalansed '(' // check if entire r.e. added if (ASubExprs.Count = 0) or ((PtrInt(ASubExprs.Objects[0]) and $FFFF) <> 1) or (((PtrInt(ASubExprs.Objects[0]) ShR 16) and $FFFF) <> Len) // whole r.e. wasn't added because it isn't bracketed // well, we add it now: then ASubExprs.InsertObject(0, ARegExpr, TObject((Len ShL 16) or 1)); finally FreeMem(Stack); end; end; { of function RegExprSubExpressions -------------------------------------------------------------- } const OP_MAGIC = TREOp(216); // programm signature // name opcode opnd? meaning OP_EEND = TREOp(0); // - End of program OP_BOL = TREOp(1); // - Match "" at beginning of line OP_EOL = TREOp(2); // - Match "" at end of line OP_ANY = TREOp(3); // - Match any one character OP_ANYOF = TREOp(4); // Str Match any character in string Str OP_ANYBUT = TREOp(5); // Str Match any char. not in string Str OP_BRANCH = TREOp(6); // Node Match this alternative, or the next OP_BACK = TREOp(7); // - Jump backward (Next < 0) OP_EXACTLY = TREOp(8); // Str Match string Str OP_NOTHING = TREOp(9); // - Match empty string OP_STAR = TREOp(10); // Node Match this (simple) thing 0 or more times OP_PLUS = TREOp(11); // Node Match this (simple) thing 1 or more times OP_ANYDIGIT = TREOp(12); // - Match any digit (equiv [0-9]) OP_NOTDIGIT = TREOp(13); // - Match not digit (equiv [0-9]) OP_ANYLETTER = TREOp(14); // - Match any letter from property WordChars OP_NOTLETTER = TREOp(15); // - Match not letter from property WordChars OP_ANYSPACE = TREOp(16); // - Match any space char (see property SpaceChars) OP_NOTSPACE = TREOp(17); // - Match not space char (see property SpaceChars) OP_BRACES = TREOp(18); // Node,Min,Max Match this (simple) thing from Min to Max times. // Min and Max are TREBracesArg OP_COMMENT = TREOp(19); // - Comment ;) OP_EXACTLYCI = TREOp(20); // Str Match string Str case insensitive OP_ANYOFCI = TREOp(21); // Str Match any character in string Str, case insensitive OP_ANYBUTCI = TREOp(22); // Str Match any char. not in string Str, case insensitive OP_LOOPENTRY = TREOp(23); // Node Start of loop (Node - LOOP for this loop) OP_LOOP = TREOp(24); // Node,Min,Max,LoopEntryJmp - back jump for LOOPENTRY. // Min and Max are TREBracesArg // Node - next node in sequence, // LoopEntryJmp - associated LOOPENTRY node addr OP_EOL2 = TReOp(25); // like OP_EOL but also matches before final line-break OP_BSUBEXP = TREOp(28); // Idx Match previously matched subexpression #Idx (stored as REChar) //###0.936 OP_BSUBEXPCI = TREOp(29); // Idx -"- in case-insensitive mode // Non-Greedy Style Ops //###0.940 OP_STARNG = TREOp(30); // Same as OP_START but in non-greedy mode OP_PLUSNG = TREOp(31); // Same as OP_PLUS but in non-greedy mode OP_BRACESNG = TREOp(32); // Same as OP_BRACES but in non-greedy mode OP_LOOPNG = TREOp(33); // Same as OP_LOOP but in non-greedy mode // Multiline mode \m OP_BOLML = TREOp(34); // - Match "" at beginning of line OP_EOLML = TREOp(35); // - Match "" at end of line OP_ANYML = TREOp(36); // - Match any one character // Word boundary OP_BOUND = TREOp(37); // Match "" between words //###0.943 OP_NOTBOUND = TREOp(38); // Match "" not between words //###0.943 OP_ANYHORZSEP = TREOp(39); // Any horizontal whitespace \h OP_NOTHORZSEP = TREOp(40); // Not horizontal whitespace \H OP_ANYVERTSEP = TREOp(41); // Any vertical whitespace \v OP_NOTVERTSEP = TREOp(42); // Not vertical whitespace \V OP_ANYCATEGORY = TREOp(43); // \p{L} OP_NOTCATEGORY = TREOp(44); // \P{L} OP_STAR_POSS = TReOp(45); OP_PLUS_POSS = TReOp(46); OP_BRACES_POSS = TReOp(47); OP_RECUR = TReOp(48); // !!! Change OP_OPEN value if you add new opcodes !!! OP_OPEN = TREOp(50); // Opening of group; OP_OPEN+i is for group i OP_OPEN_FIRST = Succ(OP_OPEN); OP_OPEN_LAST = TREOp(Ord(OP_OPEN) + RegexMaxGroups - 1); OP_CLOSE = Succ(OP_OPEN_LAST); // Closing of group; OP_CLOSE+i is for group i OP_CLOSE_FIRST = Succ(OP_CLOSE); OP_CLOSE_LAST = TReOp(Ord(OP_CLOSE) + RegexMaxGroups - 1); OP_SUBCALL = Succ(OP_CLOSE_LAST); // Call of subroutine; OP_SUBCALL+i is for group i OP_SUBCALL_FIRST = Succ(OP_SUBCALL); OP_SUBCALL_LAST = {$IFDEF Unicode} TReOp(Ord(OP_SUBCALL) + RegexMaxGroups - 1); {$ELSE} High(REChar); // must fit to 0..255 range {$ENDIF} // We work with p-code through pointers, compatible with PRegExprChar. // Note: all code components (TRENextOff, TREOp, TREBracesArg, etc) // must have lengths that can be divided by SizeOf (REChar) ! // A node is TREOp of opcode followed Next "pointer" of TRENextOff type. // The Next is a offset from the opcode of the node containing it. // An operand, if any, simply follows the node. (Note that much of // the code generation knows about this implicit relationship!) // Using TRENextOff=PtrInt speed up p-code processing. // Opcodes description: // // BRANCH The set of branches constituting a single choice are hooked // together with their "next" pointers, since precedence prevents // anything being concatenated to any individual branch. The // "next" pointer of the last BRANCH in a choice points to the // thing following the whole choice. This is also where the // final "next" pointer of each individual branch points; each // branch starts with the operand node of a BRANCH node. // BACK Normal "next" pointers all implicitly point forward; BACK // exists to make loop structures possible. // STAR,PLUS,BRACES '?', and complex '*' and '+', are implemented as // circular BRANCH structures using BACK. Complex '{min,max}' // - as pair LOOPENTRY-LOOP (see below). Simple cases (one // character per match) are implemented with STAR, PLUS and // BRACES for speed and to minimize recursive plunges. // LOOPENTRY,LOOP {min,max} are implemented as special pair // LOOPENTRY-LOOP. Each LOOPENTRY initialize loopstack for // current level. // OPEN,CLOSE are numbered at compile time. { ============================================================= } { ================== Error handling section =================== } { ============================================================= } const reeOk = 0; reeCompNullArgument = 100; reeUnknownMetaSymbol = 101; reeCompParseRegTooManyBrackets = 102; reeCompParseRegUnmatchedBrackets = 103; reeCompParseRegUnmatchedBrackets2 = 104; reeCompParseRegJunkOnEnd = 105; reePlusStarOperandCouldBeEmpty = 106; reeNestedQuantif = 107; reeBadHexDigit = 108; reeInvalidRange = 109; reeParseAtomTrailingBackSlash = 110; reeNoHexCodeAfterBSlashX = 111; reeHexCodeAfterBSlashXTooBig = 112; reeUnmatchedSqBrackets = 113; reeInternalUrp = 114; reeQuantifFollowsNothing = 115; reeTrailingBackSlash = 116; reeNoLetterAfterBSlashC = 117; reeMetaCharAfterMinusInRange = 118; reeRarseAtomInternalDisaster = 119; reeIncorrectSpecialBrackets = 120; reeIncorrectBraces = 121; reeBRACESArgTooBig = 122; reeUnknownOpcodeInFillFirst = 123; reeBracesMinParamGreaterMax = 124; reeUnclosedComment = 125; reeComplexBracesNotImplemented = 126; reeUnrecognizedModifier = 127; reeBadLinePairedSeparator = 128; reeBadUnicodeCategory = 129; reeTooSmallCheckersArray = 130; reePossessiveAfterComplexBraces = 131; reeBadRecursion = 132; reeBadSubCall = 133; reeNamedGroupBad = 140; reeNamedGroupBadName = 141; reeNamedGroupBadRef = 142; reeNamedGroupDupName = 143; reeLookaheadBad = 150; reeLookbehindBad = 152; reeLookbehindTooComplex = 153; reeLookaroundNotAtEdge = 154; // Runtime errors must be >= reeFirstRuntimeCode reeFirstRuntimeCode = 1000; reeRegRepeatCalledInappropriately = 1000; reeMatchPrimMemoryCorruption = 1001; reeMatchPrimCorruptedPointers = 1002; reeNoExpression = 1003; reeCorruptedProgram = 1004; reeOffsetMustBePositive = 1006; reeExecNextWithoutExec = 1007; reeBadOpcodeInCharClass = 1008; reeDumpCorruptedOpcode = 1011; reeModifierUnsupported = 1013; reeLoopStackExceeded = 1014; reeLoopWithoutEntry = 1015; function TRegExpr.ErrorMsg(AErrorID: integer): RegExprString; begin case AErrorID of reeOk: Result := 'No errors'; reeCompNullArgument: Result := 'TRegExpr compile: null argument'; reeUnknownMetaSymbol: Result := 'TRegExpr compile: unknown meta-character: \' + fLastErrorSymbol; reeCompParseRegTooManyBrackets: Result := 'TRegExpr compile: ParseReg: too many ()'; reeCompParseRegUnmatchedBrackets: Result := 'TRegExpr compile: ParseReg: unmatched ()'; reeCompParseRegUnmatchedBrackets2: Result := 'TRegExpr compile: ParseReg: unmatched ()'; reeCompParseRegJunkOnEnd: Result := 'TRegExpr compile: ParseReg: junk at end'; reePlusStarOperandCouldBeEmpty: Result := 'TRegExpr compile: *+ operand could be empty'; reeNestedQuantif: Result := 'TRegExpr compile: nested quantifier *?+'; reeBadHexDigit: Result := 'TRegExpr compile: bad hex digit'; reeInvalidRange: Result := 'TRegExpr compile: invalid [] range'; reeParseAtomTrailingBackSlash: Result := 'TRegExpr compile: parse atom trailing \'; reeNoHexCodeAfterBSlashX: Result := 'TRegExpr compile: no hex code after \x'; reeNoLetterAfterBSlashC: Result := 'TRegExpr compile: no letter "A".."Z" after \c'; reeMetaCharAfterMinusInRange: Result := 'TRegExpr compile: metachar after "-" in [] range'; reeHexCodeAfterBSlashXTooBig: Result := 'TRegExpr compile: hex code after \x is too big'; reeUnmatchedSqBrackets: Result := 'TRegExpr compile: unmatched []'; reeInternalUrp: Result := 'TRegExpr compile: internal fail on char "|", ")"'; reeQuantifFollowsNothing: Result := 'TRegExpr compile: quantifier ?+*{ follows nothing'; reeTrailingBackSlash: Result := 'TRegExpr compile: trailing \'; reeRarseAtomInternalDisaster: Result := 'TRegExpr compile: RarseAtom internal disaster'; reeIncorrectSpecialBrackets: Result := 'TRegExpr compile: incorrect expression in (?...) brackets'; reeIncorrectBraces: Result := 'TRegExpr compile: incorrect {} braces'; reeBRACESArgTooBig: Result := 'TRegExpr compile: braces {} argument too big'; reeUnknownOpcodeInFillFirst: Result := 'TRegExpr compile: unknown opcode in FillFirstCharSet ('+DumpOp(fLastErrorOpcode)+')'; reeBracesMinParamGreaterMax: Result := 'TRegExpr compile: braces {} min param greater then max'; reeUnclosedComment: Result := 'TRegExpr compile: unclosed (?#comment)'; reeComplexBracesNotImplemented: Result := 'TRegExpr compile: if you use braces {} and non-greedy ops *?, +?, ?? for complex cases, enable {$DEFINE ComplexBraces}'; reeUnrecognizedModifier: Result := 'TRegExpr compile: incorrect modifier in (?...)'; reeBadLinePairedSeparator: Result := 'TRegExpr compile: LinePairedSeparator must countain two different chars or be empty'; reeBadUnicodeCategory: Result := 'TRegExpr compile: invalid category after \p or \P'; reeTooSmallCheckersArray: Result := 'TRegExpr compile: too small CharCheckers array'; reePossessiveAfterComplexBraces: Result := 'TRegExpr compile: possessive + after complex braces: (foo){n,m}+'; reeBadRecursion: Result := 'TRegExpr compile: bad recursion (?R)'; reeBadSubCall: Result := 'TRegExpr compile: bad subroutine call'; reeNamedGroupBad: Result := 'TRegExpr compile: bad named group'; reeNamedGroupBadName: Result := 'TRegExpr compile: bad identifier in named group'; reeNamedGroupBadRef: Result := 'TRegExpr compile: bad back-reference to named group'; reeNamedGroupDupName: Result := 'TRegExpr compile: named group defined more than once'; reeLookaheadBad: Result := 'TRegExpr compile: bad lookahead'; reeLookbehindBad: Result := 'TRegExpr compile: bad lookbehind'; reeLookbehindTooComplex: Result := 'TRegExpr compile: lookbehind (?0'; reeExecNextWithoutExec: Result := 'TRegExpr exec: ExecNext without Exec(Pos)'; reeBadOpcodeInCharClass: Result := 'TRegExpr exec: invalid opcode in char class'; reeDumpCorruptedOpcode: Result := 'TRegExpr dump: corrupted opcode'; reeLoopStackExceeded: Result := 'TRegExpr exec: loop stack exceeded'; reeLoopWithoutEntry: Result := 'TRegExpr exec: loop without loop entry'; else Result := 'Unknown error'; end; end; { of procedure TRegExpr.Error -------------------------------------------------------------- } function TRegExpr.LastError: integer; begin Result := fLastError; fLastError := reeOk; end; { of function TRegExpr.LastError -------------------------------------------------------------- } { ============================================================= } { ===================== Common section ======================== } { ============================================================= } class function TRegExpr.VersionMajor: integer; begin Result := REVersionMajor; end; class function TRegExpr.VersionMinor: integer; begin Result := REVersionMinor; end; constructor TRegExpr.Create; begin inherited; programm := nil; fExpression := ''; fInputString := ''; FillChar(fModifiers, SizeOf(fModifiers), 0); fModifiers.I := RegExprModifierI; fModifiers.R := RegExprModifierR; fModifiers.S := RegExprModifierS; fModifiers.G := RegExprModifierG; fModifiers.M := RegExprModifierM; fModifiers.X := RegExprModifierX; {$IFDEF UseSpaceChars} SpaceChars := RegExprSpaceChars; {$ENDIF} {$IFDEF UseWordChars} WordChars := RegExprWordChars; {$ENDIF} {$IFDEF UseLineSep} fLineSeparators := RegExprLineSeparators; {$ENDIF} fUsePairedBreak := RegExprUsePairedBreak; fReplaceLineEnd := RegExprReplaceLineBreak; fSlowChecksSizeMax := 2000; {$IFDEF UseLineSep} InitLineSepArray; {$ENDIF} InitCharCheckers; end; { of constructor TRegExpr.Create -------------------------------------------------------------- } {$IFDEF UNICODE} constructor TRegExpr.Create(const AExpression : RegExprString); begin Create; Expression := AExpression; end; {$ELSE} type TUTF8ChangeCase = function(const AInStr: String; ALanguage: String = ''): String; function InitRecodeTable(const Encoding: String; AChangeCase: TUTF8ChangeCase): TRecodeTable; var I: Byte; C: String; begin for I:= 0 to 255 do begin C:= ConvertEncoding(Chr(I), Encoding, EncodingUTF8); C:= AChangeCase(C); C:= ConvertEncoding(C, EncodingUTF8, Encoding); if Length(C) > 0 then Result[I]:= Ord(C[1]); end; end; procedure TRegExpr.ChangeEncoding(const AEncoding: String); begin FLowerCase:= InitRecodeTable(AEncoding, @UTF8LowerCase); FUpperCase:= InitRecodeTable(AEncoding, @UTF8UpperCase); end; constructor TRegExpr.Create(const AEncoding: String); begin Create; ChangeEncoding(AEncoding); end; {$ENDIF} destructor TRegExpr.Destroy; begin if programm <> nil then begin FreeMem(programm); programm := nil; end; if Assigned(fHelper) then FreeAndNil(fHelper); end; procedure TRegExpr.SetExpression(const AStr: RegExprString); begin if (AStr <> fExpression) or not IsCompiled then begin fExpression := AStr; UniqueString(fExpression); fRegexStart := PRegExprChar(fExpression); fRegexEnd := fRegexStart + Length(fExpression); InvalidateProgramm; end; end; { of procedure TRegExpr.SetExpression -------------------------------------------------------------- } function TRegExpr.GetSubExprCount: integer; begin // if nothing found, we must return -1 per TRegExpr docs if GrpStart[0] = nil then Result := -1 else Result := GrpCount; end; function TRegExpr.GetMatchPos(Idx: integer): PtrInt; begin Idx := GrpIndexes[Idx]; if (Idx >= 0) and (GrpStart[Idx] <> nil) then Result := GrpStart[Idx] - fInputStart + 1 else Result := -1; end; { of function TRegExpr.GetMatchPos -------------------------------------------------------------- } function TRegExpr.GetMatchLen(Idx: integer): PtrInt; begin Idx := GrpIndexes[Idx]; if (Idx >= 0) and (GrpStart[Idx] <> nil) then Result := GrpEnd[Idx] - GrpStart[Idx] else Result := -1; end; { of function TRegExpr.GetMatchLen -------------------------------------------------------------- } function TRegExpr.GetMatch(Idx: integer): RegExprString; begin Result := ''; Idx := GrpIndexes[Idx]; if (Idx >= 0) and (GrpEnd[Idx] > GrpStart[Idx]) then SetString(Result, GrpStart[Idx], GrpEnd[Idx] - GrpStart[Idx]); end; { of function TRegExpr.GetMatch -------------------------------------------------------------- } function TRegExpr.MatchIndexFromName(const AName: RegExprString): integer; var i: integer; begin for i := 1 {not 0} to GrpCount do if GrpNames[i] = AName then begin Result := i; Exit; end; Result := -1; end; function TRegExpr.MatchFromName(const AName: RegExprString): RegExprString; var Idx: integer; begin Idx := MatchIndexFromName(AName); if Idx >= 0 then Result := GetMatch(Idx) else Result := ''; end; function TRegExpr.ExecRegExpr(const ARegExpr, AInputStr: RegExprString): Boolean; begin Self.Expression:= ARegExpr; Result:= Self.Exec(AInputStr); end; function TRegExpr.ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; AUseSubstitution: Boolean): RegExprString; begin Self.Expression:= ARegExpr; Result:= Self.Replace(AInputStr, AReplaceStr, AUseSubstitution); end; function TRegExpr.GetModifierStr: RegExprString; begin Result := '-'; if ModifierI then Result := 'i' + Result else Result := Result + 'i'; if ModifierR then Result := 'r' + Result else Result := Result + 'r'; if ModifierS then Result := 's' + Result else Result := Result + 's'; if ModifierG then Result := 'g' + Result else Result := Result + 'g'; if ModifierM then Result := 'm' + Result else Result := Result + 'm'; if ModifierX then Result := 'x' + Result else Result := Result + 'x'; if Result[Length(Result)] = '-' // remove '-' if all modifiers are 'On' then System.Delete(Result, Length(Result), 1); end; { of function TRegExpr.GetModifierStr -------------------------------------------------------------- } procedure TRegExpr.SetModifierG(AValue: boolean); begin if fModifiers.G <> AValue then begin fModifiers.G := AValue; InvalidateProgramm; end; end; procedure TRegExpr.SetModifierI(AValue: boolean); begin if fModifiers.I <> AValue then begin fModifiers.I := AValue; InvalidateProgramm; end; end; procedure TRegExpr.SetModifierM(AValue: boolean); begin if fModifiers.M <> AValue then begin fModifiers.M := AValue; InvalidateProgramm; end; end; procedure TRegExpr.SetModifierR(AValue: boolean); begin if fModifiers.R <> AValue then begin fModifiers.R := AValue; InvalidateProgramm; end; end; procedure TRegExpr.SetModifierS(AValue: boolean); begin if fModifiers.S <> AValue then begin fModifiers.S := AValue; InvalidateProgramm; end; end; procedure TRegExpr.SetModifierX(AValue: boolean); begin if fModifiers.X <> AValue then begin fModifiers.X := AValue; InvalidateProgramm; end; end; procedure TRegExpr.SetModifierStr(const AStr: RegExprString); begin if ParseModifiers(PRegExprChar(AStr), Length(AStr), fModifiers) then InvalidateProgramm else Error(reeModifierUnsupported); end; { ============================================================= } { ==================== Compiler section ======================= } { ============================================================= } {$IFDEF FastUnicodeData} function TRegExpr.IsWordChar(AChar: REChar): boolean; var NType: Byte; begin if AChar = '_' then Exit(True); if Ord(AChar) >= LOW_SURROGATE_BEGIN then Exit(False); NType := GetProps(Ord(AChar))^.Category; Result := (NType <= UGC_OtherNumber); end; (* // Unicode General Category UGC_UppercaseLetter = 0; Lu UGC_LowercaseLetter = 1; Ll UGC_TitlecaseLetter = 2; Lt UGC_ModifierLetter = 3; Lm UGC_OtherLetter = 4; Lo UGC_NonSpacingMark = 5; Mn UGC_CombiningMark = 6; Mc UGC_EnclosingMark = 7; Me UGC_DecimalNumber = 8; Nd UGC_LetterNumber = 9; Nl UGC_OtherNumber = 10; No UGC_ConnectPunctuation = 11; Pc UGC_DashPunctuation = 12; Pd UGC_OpenPunctuation = 13; Ps UGC_ClosePunctuation = 14; Pe UGC_InitialPunctuation = 15; Pi UGC_FinalPunctuation = 16; Pf UGC_OtherPunctuation = 17; Po UGC_MathSymbol = 18; Sm UGC_CurrencySymbol = 19; Sc UGC_ModifierSymbol = 20; Sk UGC_OtherSymbol = 21; So UGC_SpaceSeparator = 22; Zs UGC_LineSeparator = 23; Zl UGC_ParagraphSeparator = 24; Zp UGC_Control = 25; Cc UGC_Format = 26; Cf UGC_Surrogate = 27; Cs UGC_PrivateUse = 28; Co UGC_Unassigned = 29; Cn *) const CategoryNames: array[0..29] of array[0..1] of REChar = ( ('L', 'u'), ('L', 'l'), ('L', 't'), ('L', 'm'), ('L', 'o'), ('M', 'n'), ('M', 'c'), ('M', 'e'), ('N', 'd'), ('N', 'l'), ('N', 'o'), ('P', 'c'), ('P', 'd'), ('P', 's'), ('P', 'e'), ('P', 'i'), ('P', 'f'), ('P', 'o'), ('S', 'm'), ('S', 'c'), ('S', 'k'), ('S', 'o'), ('Z', 's'), ('Z', 'l'), ('Z', 'p'), ('C', 'c'), ('C', 'f'), ('C', 's'), ('C', 'o'), ('C', 'n') ); function IsCategoryFirstChar(AChar: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case AChar of 'L', 'M', 'N', 'P', 'S', 'C', 'Z': Result := True; else Result := False; end; end; function IsCategoryChars(AChar, AChar2: REChar): boolean; var i: integer; begin for i := Low(CategoryNames) to High(CategoryNames) do if (AChar = CategoryNames[i][0]) then if (AChar2 = CategoryNames[i][1]) then begin Result := True; Exit end; Result := False; end; function CheckCharCategory(AChar: REChar; Ch0, Ch1: REChar): boolean; // AChar: check this char against opcode // Ch0, Ch1: opcode operands after OP_*CATEGORY var N: byte; Name0, Name1: REChar; begin Result := False; N := GetProps(Ord(AChar))^.Category; if N <= High(CategoryNames) then begin Name0 := CategoryNames[N][0]; Name1 := CategoryNames[N][1]; if Ch0 <> Name0 then Exit; if Ch1 <> #0 then if Ch1 <> Name1 then Exit; Result := True; end; end; function MatchOneCharCategory(opnd, scan: PRegExprChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} // opnd: points to opcode operands after OP_*CATEGORY // scan: points into InputString begin Result := CheckCharCategory(scan^, opnd^, (opnd + 1)^); end; {$ELSE} function TRegExpr.IsWordChar(AChar: REChar): boolean; begin {$IFDEF UseWordChars} Result := Pos(AChar, fWordChars) > 0; {$ELSE} case AChar of 'a' .. 'z', 'A' .. 'Z', '0' .. '9', '_': Result := True else Result := False; end; {$ENDIF} end; {$ENDIF} function TRegExpr.IsSpaceChar(AChar: REChar): boolean; begin {$IFDEF UseSpaceChars} Result := Pos(AChar, fSpaceChars) > 0; {$ELSE} case AChar of ' ', #$9, #$A, #$D, #$C: Result := True else Result := False; end; {$ENDIF} end; function TRegExpr.IsCustomLineSeparator(AChar: REChar): boolean; begin {$IFDEF UseLineSep} {$IFDEF UniCode} Result := Pos(AChar, fLineSeparators) > 0; {$ELSE} Result := fLineSepArray[byte(AChar)]; {$ENDIF} {$ELSE} case AChar of #$d, #$a, {$IFDEF UniCode} #$85, #$2028, #$2029, {$ENDIF} #$b, #$c: Result := True; else Result := False; end; {$ENDIF} end; function IsDigitChar(AChar: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case AChar of '0' .. '9': Result := True; else Result := False; end; end; function IsHorzSeparator(AChar: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin // Tab and Unicode categoty "Space Separator": https://www.compart.com/en/unicode/category/Zs case AChar of #9, #$20, #$A0: Result := True; {$IFDEF UniCode} #$1680, #$2000 .. #$200A, #$202F, #$205F, #$3000: Result := True; {$ENDIF} else Result := False; end; end; function IsVertLineSeparator(AChar: REChar): boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} begin case AChar of #$d, #$a, #$b, #$c: Result := True; {$IFDEF UniCode} #$2028, #$2029, #$85: Result := True; {$ENDIF} else Result := False; end; end; procedure TRegExpr.InvalidateProgramm; begin if programm <> nil then begin FreeMem(programm); programm := nil; end; end; { of procedure TRegExpr.InvalidateProgramm -------------------------------------------------------------- } procedure TRegExpr.Compile; begin if fExpression = '' then begin Error(reeNoExpression); Exit; end; CompileRegExpr(fRegexStart); end; { of procedure TRegExpr.Compile -------------------------------------------------------------- } {$IFDEF UseLineSep} procedure TRegExpr.InitLineSepArray; {$IFNDEF UniCode} var i: integer; {$ENDIF} begin {$IFNDEF UniCode} FillChar(fLineSepArray, SizeOf(fLineSepArray), 0); for i := 1 to Length(fLineSeparators) do fLineSepArray[byte(fLineSeparators[i])] := True; {$ENDIF} end; {$ENDIF} function TRegExpr.IsProgrammOk: boolean; begin Result := False; // check modifiers if not IsModifiersEqual(fModifiers, fProgModifiers) then InvalidateProgramm; // compile if needed if programm = nil then begin Compile; // Check compiled programm if programm = nil then Exit; end; if programm[0] <> OP_MAGIC then Error(reeCorruptedProgram) else Result := True; end; { of function TRegExpr.IsProgrammOk -------------------------------------------------------------- } procedure TRegExpr.Tail(p: PRegExprChar; val: PRegExprChar); // set the next-pointer at the end of a node chain var scan: PRegExprChar; temp: PRegExprChar; begin if p = @regDummy then Exit; // Find last node. scan := p; repeat temp := regNext(scan); if temp = nil then Break; scan := temp; until False; // Set Next 'pointer' if val < scan then PRENextOff(AlignToPtr(scan + REOpSz))^ := -(scan - val) // ###0.948 // work around PWideChar subtraction bug (Delphi uses // shr after subtraction to calculate widechar distance %-( ) // so, if difference is negative we have .. the "feature" :( // I could wrap it in $IFDEF UniCode, but I didn't because // "P – Q computes the difference between the address given // by P (the higher address) and the address given by Q (the // lower address)" - Delphi help quotation. else PRENextOff(AlignToPtr(scan + REOpSz))^ := val - scan; // ###0.933 end; { of procedure TRegExpr.Tail -------------------------------------------------------------- } procedure TRegExpr.OpTail(p: PRegExprChar; val: PRegExprChar); // regtail on operand of first argument; nop if operandless begin // "Operandless" and "op != OP_BRANCH" are synonymous in practice. if (p = nil) or (p = @regDummy) or (PREOp(p)^ <> OP_BRANCH) then Exit; Tail(p + REOpSz + RENextOffSz, val); // ###0.933 end; { of procedure TRegExpr.OpTail -------------------------------------------------------------- } function TRegExpr.EmitNode(op: TREOp): PRegExprChar; // ###0.933 // emit a node, return location begin Result := regCode; if Result <> @regDummy then begin PREOp(regCode)^ := op; Inc(regCode, REOpSz); PRENextOff(AlignToPtr(regCode))^ := 0; // Next "pointer" := nil Inc(regCode, RENextOffSz); if (op = OP_EXACTLY) or (op = OP_EXACTLYCI) then regExactlyLen := PLongInt(regCode) else regExactlyLen := nil; {$IFDEF DebugSynRegExpr} if regcode - programm > regsize then raise Exception.Create('TRegExpr.EmitNode buffer overrun'); {$ENDIF} end else Inc(regCodeSize, REOpSz + RENextOffSz); // compute code size without code generation end; { of function TRegExpr.EmitNode -------------------------------------------------------------- } procedure TRegExpr.EmitC(ch: REChar); begin if regCode <> @regDummy then begin regCode^ := ch; Inc(regCode); {$IFDEF DebugSynRegExpr} if regcode - programm > regsize then raise Exception.Create('TRegExpr.EmitC buffer overrun'); {$ENDIF} end else Inc(regCodeSize, REOpSz); // Type of p-code pointer always is ^REChar end; { of procedure TRegExpr.EmitC -------------------------------------------------------------- } procedure TRegExpr.EmitInt(AValue: LongInt); begin if regCode <> @regDummy then begin PLongInt(regCode)^ := AValue; Inc(regCode, RENumberSz); {$IFDEF DebugSynRegExpr} if regcode - programm > regsize then raise Exception.Create('TRegExpr.EmitInt buffer overrun'); {$ENDIF} end else Inc(regCodeSize, RENumberSz); end; function TRegExpr.EmitGroupRef(AIndex: integer; AIgnoreCase: boolean): PRegExprChar; begin if AIgnoreCase then Result := EmitNode(OP_BSUBEXPCI) else Result := EmitNode(OP_BSUBEXP); EmitC(REChar(AIndex)); end; {$IFDEF FastUnicodeData} procedure TRegExpr.FindCategoryName(var scan: PRegExprChar; var ch1, ch2: REChar); // scan: points into regex string after '\p', to find category name // ch1, ch2: 2-char name of category; ch2 can be #0 var ch: REChar; pos1, pos2, namePtr: PRegExprChar; nameLen: integer; begin ch1 := #0; ch2 := #0; ch := scan^; if IsCategoryFirstChar(ch) then begin ch1 := ch; Exit; end; if ch = '{' then begin pos1 := scan; pos2 := pos1; while (pos2 < fRegexEnd) and (pos2^ <> '}') do Inc(pos2); if pos2 >= fRegexEnd then Error(reeIncorrectBraces); namePtr := pos1+1; nameLen := pos2-pos1-1; Inc(scan, nameLen+1); if nameLen<1 then Error(reeBadUnicodeCategory); if nameLen>2 then Error(reeBadUnicodeCategory); if nameLen = 1 then begin ch1 := namePtr^; ch2 := #0; if not IsCategoryFirstChar(ch1) then Error(reeBadUnicodeCategory); Exit; end; if nameLen = 2 then begin ch1 := namePtr^; ch2 := (namePtr+1)^; if not IsCategoryChars(ch1, ch2) then Error(reeBadUnicodeCategory); Exit; end; end else Error(reeBadUnicodeCategory); end; function TRegExpr.EmitCategoryMain(APositive: boolean): PRegExprChar; var ch, ch2: REChar; begin Inc(regParse); if regParse >= fRegexEnd then Error(reeBadUnicodeCategory); FindCategoryName(regParse, ch, ch2); if APositive then Result := EmitNode(OP_ANYCATEGORY) else Result := EmitNode(OP_NOTCATEGORY); EmitC(ch); EmitC(ch2); end; {$ENDIF} procedure TRegExpr.InsertOperator(op: TREOp; opnd: PRegExprChar; sz: integer); // insert an operator in front of already-emitted operand // Means relocating the operand. var src, dst, place: PRegExprChar; i: integer; begin if regCode = @regDummy then begin Inc(regCodeSize, sz); Exit; end; // move code behind insert position src := regCode; Inc(regCode, sz); {$IFDEF DebugSynRegExpr} if regCode - programm > regCodeSize then raise Exception.Create('TRegExpr.InsertOperator buffer overrun'); // if (opndregCodeSize) then // raise Exception.Create('TRegExpr.InsertOperator invalid opnd'); {$ENDIF} dst := regCode; while src > opnd do begin Dec(dst); Dec(src); dst^ := src^; end; place := opnd; // Op node, where operand used to be. PREOp(place)^ := op; Inc(place, REOpSz); for i := 1 + REOpSz to sz do begin place^ := #0; Inc(place); end; end; { of procedure TRegExpr.InsertOperator -------------------------------------------------------------- } function FindSkippedMetaLen(PStart, PEnd: PRegExprChar): integer; {$IFDEF InlineFuncs}inline;{$ENDIF} // find length of initial segment of PStart string consisting // entirely of characters not from IsMetaSymbol1. begin Result := 0; while PStart < PEnd do begin if _IsMetaSymbol1(PStart^) then Exit; Inc(Result); Inc(PStart) end; end; const // Flags to be passed up and down. FLAG_WORST = 0; // Worst case FLAG_HASWIDTH = 1; // Cannot match empty string FLAG_SIMPLE = 2; // Simple enough to be OP_STAR/OP_PLUS/OP_BRACES operand FLAG_SPECSTART = 4; // Starts with * or + {$IFDEF UniCode} RusRangeLoLow = #$430; // 'а' RusRangeLoHigh = #$44F; // 'я' RusRangeHiLow = #$410; // 'А' RusRangeHiHigh = #$42F; // 'Я' {$ELSE} RusRangeLoLow = #$E0; // 'а' in cp1251 RusRangeLoHigh = #$FF; // 'я' in cp1251 RusRangeHiLow = #$C0; // 'А' in cp1251 RusRangeHiHigh = #$DF; // 'Я' in cp1251 {$ENDIF} function TRegExpr.FindInCharClass(ABuffer: PRegExprChar; AChar: REChar; AIgnoreCase: boolean): boolean; // Buffer contains char pairs: (Kind, Data), where Kind is one of OpKind_ values, // and Data depends on Kind var OpKind: REChar; ch, ch2: REChar; N, i: integer; begin if AIgnoreCase then AChar := _UpperCase(AChar); repeat OpKind := ABuffer^; case OpKind of OpKind_End: begin Result := False; Exit; end; OpKind_Range: begin Inc(ABuffer); ch := ABuffer^; Inc(ABuffer); ch2 := ABuffer^; Inc(ABuffer); { // if AIgnoreCase, ch, ch2 are upcased in opcode if AIgnoreCase then begin ch := _UpperCase(ch); ch2 := _UpperCase(ch2); end; } if (AChar >= ch) and (AChar <= ch2) then begin Result := True; Exit; end; end; OpKind_MetaClass: begin Inc(ABuffer); N := Ord(ABuffer^); Inc(ABuffer); if CharCheckers[N](AChar) then begin Result := True; Exit end; end; OpKind_Char: begin Inc(ABuffer); N := PLongInt(ABuffer)^; Inc(ABuffer, RENumberSz); for i := 1 to N do begin ch := ABuffer^; Inc(ABuffer); { // already upcased in opcode if AIgnoreCase then ch := _UpperCase(ch); } if ch = AChar then begin Result := True; Exit; end; end; end; {$IFDEF FastUnicodeData} OpKind_CategoryYes, OpKind_CategoryNo: begin Inc(ABuffer); ch := ABuffer^; Inc(ABuffer); ch2 := ABuffer^; Inc(ABuffer); Result := CheckCharCategory(AChar, ch, ch2); if OpKind = OpKind_CategoryNo then Result := not Result; if Result then Exit; end; {$ENDIF} else Error(reeBadOpcodeInCharClass); end; until False; // assume that Buffer is ended correctly end; procedure TRegExpr.GetCharSetFromWordChars(var ARes: TRegExprCharSet); {$IFDEF UseWordChars} var i: integer; ch: REChar; {$ENDIF} begin {$IFDEF UseWordChars} ARes := []; for i := 1 to Length(fWordChars) do begin ch := fWordChars[i]; {$IFDEF UniCode} if Ord(ch) <= $FF then {$ENDIF} Include(ARes, byte(ch)); end; {$ELSE} ARes := RegExprWordSet; {$ENDIF} end; procedure TRegExpr.GetCharSetFromSpaceChars(var ARes: TRegExprCharset); {$IFDEF UseSpaceChars} var i: integer; ch: REChar; {$ENDIF} begin {$IFDEF UseSpaceChars} ARes := []; for i := 1 to Length(fSpaceChars) do begin ch := fSpaceChars[i]; {$IFDEF UniCode} if Ord(ch) <= $FF then {$ENDIF} Include(ARes, byte(ch)); end; {$ELSE} ARes := RegExprSpaceSet; {$ENDIF} end; procedure TRegExpr.GetCharSetFromCharClass(ABuffer: PRegExprChar; AIgnoreCase: boolean; var ARes: TRegExprCharset); var ch, ch2: REChar; TempSet: TRegExprCharSet; N, i: integer; begin ARes := []; TempSet := []; repeat case ABuffer^ of OpKind_End: Exit; OpKind_Range: begin Inc(ABuffer); ch := ABuffer^; Inc(ABuffer); ch2 := ABuffer^; Inc(ABuffer); for i := Ord(ch) to {$IFDEF UniCode} Min(Ord(ch2), $FF) {$ELSE} Ord(ch2) {$ENDIF} do begin Include(ARes, byte(i)); if AIgnoreCase then Include(ARes, byte(InvertCase(REChar(i)))); end; end; OpKind_MetaClass: begin Inc(ABuffer); N := Ord(ABuffer^); Inc(ABuffer); if N = CheckerIndex_Word then begin GetCharSetFromWordChars(TempSet); ARes := ARes + TempSet; end else if N = CheckerIndex_NotWord then begin GetCharSetFromWordChars(TempSet); ARes := ARes + (RegExprAllSet - TempSet); end else if N = CheckerIndex_Space then begin GetCharSetFromSpaceChars(TempSet); ARes := ARes + TempSet; end else if N = CheckerIndex_NotSpace then begin GetCharSetFromSpaceChars(TempSet); ARes := ARes + (RegExprAllSet - TempSet); end else if N = CheckerIndex_Digit then ARes := ARes + RegExprDigitSet else if N = CheckerIndex_NotDigit then ARes := ARes + (RegExprAllSet - RegExprDigitSet) else if N = CheckerIndex_VertSep then ARes := ARes + RegExprLineSeparatorsSet else if N = CheckerIndex_NotVertSep then ARes := ARes + (RegExprAllSet - RegExprLineSeparatorsSet) else if N = CheckerIndex_HorzSep then ARes := ARes + RegExprHorzSeparatorsSet else if N = CheckerIndex_NotHorzSep then ARes := ARes + (RegExprAllSet - RegExprHorzSeparatorsSet) else if N = CheckerIndex_LowerAZ then begin if AIgnoreCase then ARes := ARes + RegExprAllAzSet else ARes := ARes + RegExprLowerAzSet; end else if N = CheckerIndex_UpperAZ then begin if AIgnoreCase then ARes := ARes + RegExprAllAzSet else ARes := ARes + RegExprUpperAzSet; end else Error(reeBadOpcodeInCharClass); end; OpKind_Char: begin Inc(ABuffer); N := PLongInt(ABuffer)^; Inc(ABuffer, RENumberSz); for i := 1 to N do begin ch := ABuffer^; Inc(ABuffer); {$IFDEF UniCode} if Ord(ch) <= $FF then {$ENDIF} begin Include(ARes, byte(ch)); if AIgnoreCase then Include(ARes, byte(InvertCase(ch))); end; end; end; {$IFDEF FastUnicodeData} OpKind_CategoryYes, OpKind_CategoryNo: begin // usage of FirstCharSet makes no sense for regex with \p \P ARes := RegExprAllSet; Exit; end; {$ENDIF} else Error(reeBadOpcodeInCharClass); end; until False; // assume that Buffer is ended correctly end; function TRegExpr.GetModifierG: boolean; begin Result := fModifiers.G; end; function TRegExpr.GetModifierI: boolean; begin Result := fModifiers.I; end; function TRegExpr.GetModifierM: boolean; begin Result := fModifiers.M; end; function TRegExpr.GetModifierR: boolean; begin Result := fModifiers.R; end; function TRegExpr.GetModifierS: boolean; begin Result := fModifiers.S; end; function TRegExpr.GetModifierX: boolean; begin Result := fModifiers.X; end; function TRegExpr.CompileRegExpr(ARegExp: PRegExprChar): boolean; // Compile a regular expression into internal code // We can't allocate space until we know how big the compiled form will be, // but we can't compile it (and thus know how big it is) until we've got a // place to put the code. So we cheat: we compile it twice, once with code // generation turned off and size counting turned on, and once "for real". // This also means that we don't allocate space until we are sure that the // thing really will compile successfully, and we never have to move the // code and thus invalidate pointers into it. (Note that it has to be in // one piece because free() must be able to free it all.) // Beware that the optimization-preparation code in here knows about some // of the structure of the compiled regexp. var scan, longest, longestTemp: PRegExprChar; Len, LenTemp: integer; FlagTemp: integer; begin Result := False; FlagTemp := 0; regParse := nil; // for correct error handling regExactlyLen := nil; ClearInternalIndexes; fLastError := reeOk; fLastErrorOpcode := TREOp(0); if Assigned(fHelper) then FreeAndNil(fHelper); fHelperLen := 0; try if programm <> nil then begin FreeMem(programm); programm := nil; end; if ARegExp = nil then begin Error(reeCompNullArgument); Exit; end; fProgModifiers := fModifiers; // well, may it's paranoia. I'll check it later. // First pass: calculate opcode size, validate regex fSecondPass := False; fCompModifiers := fModifiers; regParse := ARegExp; regNumBrackets := 1; regCodeSize := 0; regCode := @regDummy; regCodeWork := nil; regLookahead := False; regLookaheadNeg := False; regLookaheadGroup := -1; regLookbehind := False; EmitC(OP_MAGIC); if ParseReg(False, FlagTemp) = nil then Exit; // Allocate memory GetMem(programm, regCodeSize * SizeOf(REChar)); // Second pass: emit opcode fSecondPass := True; fCompModifiers := fModifiers; regParse := ARegExp; regNumBrackets := 1; regCode := programm; regCodeWork := programm + REOpSz; EmitC(OP_MAGIC); if ParseReg(False, FlagTemp) = nil then Exit; // Dig out information for optimizations. {$IFDEF UseFirstCharSet} // ###0.929 FirstCharSet := []; FillFirstCharSet(regCodeWork); for Len := 0 to 255 do FirstCharArray[Len] := byte(Len) in FirstCharSet; {$ENDIF} regAnchored := #0; regMust := nil; regMustLen := 0; regMustString := ''; scan := regCodeWork; // First OP_BRANCH. if PREOp(regNext(scan))^ = OP_EEND then begin // Only one top-level choice. scan := scan + REOpSz + RENextOffSz; // Starting-point info. if PREOp(scan)^ = OP_BOL then Inc(regAnchored); // If there's something expensive in the r.e., find the longest // literal string that must appear and make it the regMust. Resolve // ties in favor of later strings, since the regstart check works // with the beginning of the r.e. and avoiding duplication // strengthens checking. Not a strong reason, but sufficient in the // absence of others. if (FlagTemp and FLAG_SPECSTART) <> 0 then begin longest := nil; Len := 0; while scan <> nil do begin if PREOp(scan)^ = OP_EXACTLY then begin longestTemp := scan + REOpSz + RENextOffSz + RENumberSz; LenTemp := PLongInt(scan + REOpSz + RENextOffSz)^; if LenTemp >= Len then begin longest := longestTemp; Len := LenTemp; end; end; scan := regNext(scan); end; regMust := longest; regMustLen := Len; if regMustLen > 1 then // don't use regMust if too short SetString(regMustString, regMust, regMustLen); end; end; Result := True; finally begin if not Result then InvalidateProgramm; end; end; end; { of function TRegExpr.CompileRegExpr -------------------------------------------------------------- } function TRegExpr.ParseReg(InBrackets: boolean; var FlagParse: integer): PRegExprChar; // regular expression, i.e. main body or parenthesized thing // Caller must absorb opening parenthesis. // Combining parenthesis handling with the base level of regular expression // is a trifle forced, but the need to tie the tails of the branches to what // follows makes it hard to avoid. var ret, br, ender: PRegExprChar; NBrackets: integer; FlagTemp: integer; SavedModifiers: TRegExprModifiers; begin Result := nil; FlagTemp := 0; FlagParse := FLAG_HASWIDTH; // Tentatively. NBrackets := 0; SavedModifiers := fCompModifiers; // Make an OP_OPEN node, if parenthesized. if InBrackets then begin if regNumBrackets >= RegexMaxGroups then begin Error(reeCompParseRegTooManyBrackets); Exit; end; NBrackets := regNumBrackets; Inc(regNumBrackets); ret := EmitNode(TREOp(Ord(OP_OPEN) + NBrackets)); GrpOpCodes[NBrackets] := ret; end else ret := nil; // Pick up the branches, linking them together. br := ParseBranch(FlagTemp); if br = nil then begin Result := nil; Exit; end; if ret <> nil then Tail(ret, br) // OP_OPEN -> first. else ret := br; if (FlagTemp and FLAG_HASWIDTH) = 0 then FlagParse := FlagParse and not FLAG_HASWIDTH; FlagParse := FlagParse or FlagTemp and FLAG_SPECSTART; while (regParse^ = '|') do begin Inc(regParse); br := ParseBranch(FlagTemp); if br = nil then begin Result := nil; Exit; end; Tail(ret, br); // OP_BRANCH -> OP_BRANCH. if (FlagTemp and FLAG_HASWIDTH) = 0 then FlagParse := FlagParse and not FLAG_HASWIDTH; FlagParse := FlagParse or FlagTemp and FLAG_SPECSTART; end; // Make a closing node, and hook it on the end. if InBrackets then ender := EmitNode(TREOp(Ord(OP_CLOSE) + NBrackets)) else ender := EmitNode(OP_EEND); Tail(ret, ender); // Hook the tails of the branches to the closing node. br := ret; while br <> nil do begin OpTail(br, ender); br := regNext(br); end; // Check for proper termination. if InBrackets then if regParse^ <> ')' then begin Error(reeCompParseRegUnmatchedBrackets); Exit; end else Inc(regParse); // skip trailing ')' if (not InBrackets) and (regParse < fRegexEnd) then begin if regParse^ = ')' then Error(reeCompParseRegUnmatchedBrackets2) else Error(reeCompParseRegJunkOnEnd); Exit; end; fCompModifiers := SavedModifiers; // restore modifiers of parent Result := ret; end; { of function TRegExpr.ParseReg -------------------------------------------------------------- } function TRegExpr.ParseBranch(var FlagParse: integer): PRegExprChar; // one alternative of an | operator // Implements the concatenation operator. var ret, chain, latest: PRegExprChar; FlagTemp: integer; begin FlagTemp := 0; FlagParse := FLAG_WORST; // Tentatively. ret := EmitNode(OP_BRANCH); chain := nil; while (regParse < fRegexEnd) and (regParse^ <> '|') and (regParse^ <> ')') do begin latest := ParsePiece(FlagTemp); if latest = nil then begin Result := nil; Exit; end; FlagParse := FlagParse or FlagTemp and FLAG_HASWIDTH; if chain = nil // First piece. then FlagParse := FlagParse or FlagTemp and FLAG_SPECSTART else Tail(chain, latest); chain := latest; end; if chain = nil // Loop ran zero times. then EmitNode(OP_NOTHING); Result := ret; end; { of function TRegExpr.ParseBranch -------------------------------------------------------------- } function TRegExpr.ParsePiece(var FlagParse: integer): PRegExprChar; // something followed by possible [*+?{] // Note that the branching code sequences used for ? and the general cases // of * and + and { are somewhat optimized: they use the same OP_NOTHING node as // both the endmarker for their branch list and the body of the last branch. // It might seem that this node could be dispensed with entirely, but the // endmarker role is not redundant. function ParseNumber(AStart, AEnd: PRegExprChar): TREBracesArg; begin Result := 0; if AEnd - AStart + 1 > 8 then begin // prevent stupid scanning Error(reeBRACESArgTooBig); Exit; end; while AStart <= AEnd do begin Result := Result * 10 + (Ord(AStart^) - Ord('0')); Inc(AStart); end; if (Result > MaxBracesArg) or (Result < 0) then begin Error(reeBRACESArgTooBig); Exit; end; end; var TheOp: TREOp; NextNode: PRegExprChar; procedure EmitComplexBraces(ABracesMin, ABracesMax: TREBracesArg; ANonGreedyOp: boolean); // ###0.940 {$IFDEF ComplexBraces} var off: TRENextOff; {$ENDIF} begin {$IFNDEF ComplexBraces} Error(reeComplexBracesNotImplemented); {$ELSE} if ANonGreedyOp then TheOp := OP_LOOPNG else TheOp := OP_LOOP; InsertOperator(OP_LOOPENTRY, Result, REOpSz + RENextOffSz); NextNode := EmitNode(TheOp); if regCode <> @regDummy then begin off := (Result + REOpSz + RENextOffSz) - (regCode - REOpSz - RENextOffSz); // back to Atom after OP_LOOPENTRY PREBracesArg(AlignToInt(regCode))^ := ABracesMin; Inc(regCode, REBracesArgSz); PREBracesArg(AlignToInt(regCode))^ := ABracesMax; Inc(regCode, REBracesArgSz); PRENextOff(AlignToPtr(regCode))^ := off; Inc(regCode, RENextOffSz); {$IFDEF DebugSynRegExpr} if regcode - programm > regsize then raise Exception.Create ('TRegExpr.ParsePiece.EmitComplexBraces buffer overrun'); {$ENDIF} end else Inc(regCodeSize, REBracesArgSz * 2 + RENextOffSz); Tail(Result, NextNode); // OP_LOOPENTRY -> OP_LOOP if regCode <> @regDummy then Tail(Result + REOpSz + RENextOffSz, NextNode); // Atom -> OP_LOOP {$ENDIF} end; procedure EmitSimpleBraces(ABracesMin, ABracesMax: TREBracesArg; ANonGreedyOp, APossessive: boolean); begin if APossessive then TheOp := OP_BRACES_POSS else if ANonGreedyOp then TheOp := OP_BRACESNG else TheOp := OP_BRACES; InsertOperator(TheOp, Result, REOpSz + RENextOffSz + REBracesArgSz * 2); if regCode <> @regDummy then begin PREBracesArg(AlignToInt(Result + REOpSz + RENextOffSz))^ := ABracesMin; PREBracesArg(AlignToInt(Result + REOpSz + RENextOffSz + REBracesArgSz))^ := ABracesMax; end; end; var op, nextch: REChar; NonGreedyOp, NonGreedyCh, PossessiveCh: boolean; FlagTemp: integer; BracesMin, BracesMax: TREBracesArg; p: PRegExprChar; begin FlagTemp := 0; Result := ParseAtom(FlagTemp); if Result = nil then Exit; op := regParse^; if not ((op = '*') or (op = '+') or (op = '?') or (op = '{')) then begin FlagParse := FlagTemp; Exit; end; if ((FlagTemp and FLAG_HASWIDTH) = 0) and (op <> '?') then begin Error(reePlusStarOperandCouldBeEmpty); Exit; end; case op of '*': begin FlagParse := FLAG_WORST or FLAG_SPECSTART; nextch := (regParse + 1)^; PossessiveCh := nextch = '+'; if PossessiveCh then begin NonGreedyCh := False; NonGreedyOp := False; end else begin NonGreedyCh := nextch = '?'; NonGreedyOp := NonGreedyCh or not fCompModifiers.G; end; if (FlagTemp and FLAG_SIMPLE) = 0 then begin if NonGreedyOp then EmitComplexBraces(0, MaxBracesArg, NonGreedyOp) else begin // Emit x* as (x&|), where & means "self". InsertOperator(OP_BRANCH, Result, REOpSz + RENextOffSz); // Either x OpTail(Result, EmitNode(OP_BACK)); // and loop OpTail(Result, Result); // back Tail(Result, EmitNode(OP_BRANCH)); // or Tail(Result, EmitNode(OP_NOTHING)); // nil. end end else begin // Simple if PossessiveCh then TheOp := OP_STAR_POSS else if NonGreedyOp then TheOp := OP_STARNG else TheOp := OP_STAR; InsertOperator(TheOp, Result, REOpSz + RENextOffSz); end; if NonGreedyCh or PossessiveCh then Inc(regParse); // Skip extra char ('?') end; { of case '*' } '+': begin FlagParse := FLAG_WORST or FLAG_SPECSTART or FLAG_HASWIDTH; nextch := (regParse + 1)^; PossessiveCh := nextch = '+'; if PossessiveCh then begin NonGreedyCh := False; NonGreedyOp := False; end else begin NonGreedyCh := nextch = '?'; NonGreedyOp := NonGreedyCh or not fCompModifiers.G; end; if (FlagTemp and FLAG_SIMPLE) = 0 then begin if NonGreedyOp then EmitComplexBraces(1, MaxBracesArg, NonGreedyOp) else begin // Emit x+ as x(&|), where & means "self". NextNode := EmitNode(OP_BRANCH); // Either Tail(Result, NextNode); Tail(EmitNode(OP_BACK), Result); // loop back Tail(NextNode, EmitNode(OP_BRANCH)); // or Tail(Result, EmitNode(OP_NOTHING)); // nil. end end else begin // Simple if PossessiveCh then TheOp := OP_PLUS_POSS else if NonGreedyOp then TheOp := OP_PLUSNG else TheOp := OP_PLUS; InsertOperator(TheOp, Result, REOpSz + RENextOffSz); end; if NonGreedyCh or PossessiveCh then Inc(regParse); // Skip extra char ('?') end; { of case '+' } '?': begin FlagParse := FLAG_WORST; nextch := (regParse + 1)^; PossessiveCh := nextch = '+'; if PossessiveCh then begin NonGreedyCh := False; NonGreedyOp := False; end else begin NonGreedyCh := nextch = '?'; NonGreedyOp := NonGreedyCh or not fCompModifiers.G; end; if NonGreedyOp or PossessiveCh then begin // ###0.940 // We emit x?? as x{0,1}? if (FlagTemp and FLAG_SIMPLE) = 0 then begin if PossessiveCh then Error(reePossessiveAfterComplexBraces); EmitComplexBraces(0, 1, NonGreedyOp); end else EmitSimpleBraces(0, 1, NonGreedyOp, PossessiveCh); end else begin // greedy '?' InsertOperator(OP_BRANCH, Result, REOpSz + RENextOffSz); // Either x Tail(Result, EmitNode(OP_BRANCH)); // or NextNode := EmitNode(OP_NOTHING); // nil. Tail(Result, NextNode); OpTail(Result, NextNode); end; if NonGreedyCh or PossessiveCh then Inc(regParse); // Skip extra char ('?') end; { of case '?' } '{': begin Inc(regParse); p := regParse; while IsDigitChar(regParse^) do // MUST appear Inc(regParse); if (regParse^ <> '}') and (regParse^ <> ',') or (p = regParse) then begin Error(reeIncorrectBraces); Exit; end; BracesMin := ParseNumber(p, regParse - 1); if regParse^ = ',' then begin Inc(regParse); p := regParse; while IsDigitChar(regParse^) do Inc(regParse); if regParse^ <> '}' then begin Error(reeIncorrectBraces); Exit; end; if p = regParse then BracesMax := MaxBracesArg else BracesMax := ParseNumber(p, regParse - 1); end else BracesMax := BracesMin; // {n} == {n,n} if BracesMin > BracesMax then begin Error(reeBracesMinParamGreaterMax); Exit; end; if BracesMin > 0 then FlagParse := FLAG_WORST; if BracesMax > 0 then FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SPECSTART; nextch := (regParse + 1)^; PossessiveCh := nextch = '+'; if PossessiveCh then begin NonGreedyCh := False; NonGreedyOp := False; end else begin NonGreedyCh := nextch = '?'; NonGreedyOp := NonGreedyCh or not fCompModifiers.G; end; if (FlagTemp and FLAG_SIMPLE) <> 0 then EmitSimpleBraces(BracesMin, BracesMax, NonGreedyOp, PossessiveCh) else begin if PossessiveCh then Error(reePossessiveAfterComplexBraces); EmitComplexBraces(BracesMin, BracesMax, NonGreedyOp); end; if NonGreedyCh or PossessiveCh then Inc(regParse); // Skip extra char '?' end; // of case '{' // else // here we can't be end; { of case op } Inc(regParse); op := regParse^; if (op = '*') or (op = '+') or (op = '?') or (op = '{') then Error(reeNestedQuantif); end; { of function TRegExpr.ParsePiece -------------------------------------------------------------- } function TRegExpr.HexDig(Ch: REChar): integer; begin case Ch of '0' .. '9': Result := Ord(Ch) - Ord('0'); 'a' .. 'f': Result := Ord(Ch) - Ord('a') + 10; 'A' .. 'F': Result := Ord(Ch) - Ord('A') + 10; else begin Result := 0; Error(reeBadHexDigit); end; end; end; function TRegExpr.UnQuoteChar(var APtr: PRegExprChar): REChar; var Ch: REChar; begin case APtr^ of 't': Result := #$9; // \t => tab (HT/TAB) 'n': Result := #$a; // \n => newline (NL) 'r': Result := #$d; // \r => carriage return (CR) 'f': Result := #$c; // \f => form feed (FF) 'a': Result := #$7; // \a => alarm (bell) (BEL) 'e': Result := #$1b; // \e => escape (ESC) 'c': begin // \cK => code for Ctrl+K Result := #0; Inc(APtr); if APtr >= fRegexEnd then Error(reeNoLetterAfterBSlashC); Ch := APtr^; case Ch of 'a' .. 'z': Result := REChar(Ord(Ch) - Ord('a') + 1); 'A' .. 'Z': Result := REChar(Ord(Ch) - Ord('A') + 1); else Error(reeNoLetterAfterBSlashC); end; end; 'x': begin // \x: hex char Result := #0; Inc(APtr); if APtr >= fRegexEnd then begin Error(reeNoHexCodeAfterBSlashX); Exit; end; if APtr^ = '{' then begin // \x{nnnn} //###0.936 repeat Inc(APtr); if APtr >= fRegexEnd then begin Error(reeNoHexCodeAfterBSlashX); Exit; end; if APtr^ <> '}' then begin if (Ord(Result) ShR (SizeOf(REChar) * 8 - 4)) and $F <> 0 then begin Error(reeHexCodeAfterBSlashXTooBig); Exit; end; Result := REChar((Ord(Result) ShL 4) or HexDig(APtr^)); // HexDig will cause Error if bad hex digit found end else Break; until False; end else begin Result := REChar(HexDig(APtr^)); // HexDig will cause Error if bad hex digit found Inc(APtr); if APtr >= fRegexEnd then begin Error(reeNoHexCodeAfterBSlashX); Exit; end; Result := REChar((Ord(Result) ShL 4) or HexDig(APtr^)); // HexDig will cause Error if bad hex digit found end; end; else begin Result := APtr^; if (Result <> '_') and IsWordChar(Result) then begin fLastErrorSymbol := Result; Error(reeUnknownMetaSymbol); end; end; end; end; function TRegExpr.ParseAtom(var FlagParse: integer): PRegExprChar; // the lowest level // Optimization: gobbles an entire sequence of ordinary characters so that // it can turn them into a single node, which is smaller to store and // faster to run. Backslashed characters are exceptions, each becoming a // separate node; the code is simpler that way and it's not worth fixing. var ret: PRegExprChar; RangeBeg, RangeEnd: REChar; CanBeRange: boolean; AddrOfLen: PLongInt; procedure EmitExactly(Ch: REChar); begin if fCompModifiers.I then ret := EmitNode(OP_EXACTLYCI) else ret := EmitNode(OP_EXACTLY); EmitInt(1); EmitC(Ch); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; procedure EmitRangeChar(Ch: REChar; AStartOfRange: boolean); begin CanBeRange := AStartOfRange; if fCompModifiers.I then Ch := _UpperCase(Ch); if AStartOfRange then begin AddrOfLen := nil; RangeBeg := Ch; end else begin if AddrOfLen = nil then begin EmitC(OpKind_Char); Pointer(AddrOfLen) := regCode; EmitInt(0); end; Inc(AddrOfLen^); EmitC(Ch); end; end; procedure EmitRangePacked(ch1, ch2: REChar); var ChkIndex: integer; begin AddrOfLen := nil; CanBeRange := False; if fCompModifiers.I then begin ch1 := _UpperCase(ch1); ch2 := _UpperCase(ch2); end; for ChkIndex := Low(CharCheckerInfos) to High(CharCheckerInfos) do if (CharCheckerInfos[ChkIndex].CharBegin = ch1) and (CharCheckerInfos[ChkIndex].CharEnd = ch2) then begin EmitC(OpKind_MetaClass); EmitC(REChar(CharCheckerInfos[ChkIndex].CheckerIndex)); Exit; end; EmitC(OpKind_Range); EmitC(ch1); EmitC(ch2); end; {$IFDEF FastUnicodeData} procedure EmitCategoryInCharClass(APositive: boolean); var ch, ch2: REChar; begin AddrOfLen := nil; CanBeRange := False; Inc(regParse); FindCategoryName(regParse, ch, ch2); if APositive then EmitC(OpKind_CategoryYes) else EmitC(OpKind_CategoryNo); EmitC(ch); EmitC(ch2); end; {$ENDIF} var FlagTemp: integer; Len: integer; SavedPtr: PRegExprChar; EnderChar, TempChar: REChar; DashForRange: Boolean; GrpKind: TREGroupKind; GrpName: RegExprString; GrpIndex: integer; NextCh: REChar; begin Result := nil; FlagTemp := 0; FlagParse := FLAG_WORST; AddrOfLen := nil; Inc(regParse); case (regParse - 1)^ of '^': begin if not fCompModifiers.M {$IFDEF UseLineSep} or (fLineSeparators = '') {$ENDIF} then ret := EmitNode(OP_BOL) else ret := EmitNode(OP_BOLML); end; '$': begin if not fCompModifiers.M {$IFDEF UseLineSep} or (fLineSeparators = '') {$ENDIF} then ret := EmitNode(OP_EOL) else ret := EmitNode(OP_EOLML); end; '.': begin if fCompModifiers.S then begin ret := EmitNode(OP_ANY); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end else begin // not /s, so emit [^:LineSeparators:] ret := EmitNode(OP_ANYML); FlagParse := FlagParse or FLAG_HASWIDTH; // not so simple ;) end; end; '[': begin if regParse^ = '^' then begin // Complement of range. if fCompModifiers.I then ret := EmitNode(OP_ANYBUTCI) else ret := EmitNode(OP_ANYBUT); Inc(regParse); end else if fCompModifiers.I then ret := EmitNode(OP_ANYOFCI) else ret := EmitNode(OP_ANYOF); CanBeRange := False; if regParse^ = ']' then begin // first ']' inside [] treated as simple char, no need to check '[' EmitRangeChar(regParse^, (regParse + 1)^ = '-'); Inc(regParse); end; while (regParse < fRegexEnd) and (regParse^ <> ']') do begin // last '-' inside [] treated as simple dash if (regParse^ = '-') and ((regParse + 1) < fRegexEnd) and ((regParse + 1)^ = ']') then begin EmitRangeChar('-', False); Inc(regParse); Break; end; // char '-' which (maybe) makes a range if (regParse^ = '-') and ((regParse + 1) < fRegexEnd) and CanBeRange then begin Inc(regParse); RangeEnd := regParse^; if RangeEnd = EscChar then begin if _IsMetaChar((regParse + 1)^) then begin Error(reeMetaCharAfterMinusInRange); Exit; end; Inc(regParse); RangeEnd := UnQuoteChar(regParse); end; // special handling for Russian range a-YA, add 2 ranges: a-ya and A-YA if fCompModifiers.R and (RangeBeg = RusRangeLoLow) and (RangeEnd = RusRangeHiHigh) then begin EmitRangePacked(RusRangeLoLow, RusRangeLoHigh); EmitRangePacked(RusRangeHiLow, RusRangeHiHigh); end else begin // standard r.e. handling if RangeBeg > RangeEnd then begin Error(reeInvalidRange); Exit; end; EmitRangePacked(RangeBeg, RangeEnd); end; Inc(regParse); end else begin if regParse^ = EscChar then begin Inc(regParse); if regParse >= fRegexEnd then begin Error(reeParseAtomTrailingBackSlash); Exit; end; if _IsMetaChar(regParse^) then begin AddrOfLen := nil; CanBeRange := False; EmitC(OpKind_MetaClass); case regParse^ of 'w': EmitC(REChar(CheckerIndex_Word)); 'W': EmitC(REChar(CheckerIndex_NotWord)); 's': EmitC(REChar(CheckerIndex_Space)); 'S': EmitC(REChar(CheckerIndex_NotSpace)); 'd': EmitC(REChar(CheckerIndex_Digit)); 'D': EmitC(REChar(CheckerIndex_NotDigit)); 'v': EmitC(REChar(CheckerIndex_VertSep)); 'V': EmitC(REChar(CheckerIndex_NotVertSep)); 'h': EmitC(REChar(CheckerIndex_HorzSep)); 'H': EmitC(REChar(CheckerIndex_NotHorzSep)); else Error(reeBadOpcodeInCharClass); end; end else {$IFDEF FastUnicodeData} if regParse^ = 'p' then EmitCategoryInCharClass(True) else if regParse^ = 'P' then EmitCategoryInCharClass(False) else {$ENDIF} begin TempChar := UnQuoteChar(regParse); // False if '-' is last char in [] DashForRange := (regParse + 2 < fRegexEnd) and ((regParse + 1)^ = '-') and ((regParse + 2)^ <> ']'); EmitRangeChar(TempChar, DashForRange); end; end else begin // False if '-' is last char in [] DashForRange := (regParse + 2 < fRegexEnd) and ((regParse + 1)^ = '-') and ((regParse + 2)^ <> ']'); EmitRangeChar(regParse^, DashForRange); end; Inc(regParse); end; end; { of while } AddrOfLen := nil; CanBeRange := False; EmitC(OpKind_End); if regParse^ <> ']' then begin Error(reeUnmatchedSqBrackets); Exit; end; Inc(regParse); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; '(': begin GrpKind := gkNormalGroup; GrpName := ''; // A: detect kind of expression in brackets if regParse^ = '?' then begin NextCh := (regParse + 1)^; case NextCh of ':': begin // non-capturing group: (?:regex) GrpKind := gkNonCapturingGroup; Inc(regParse, 2); end; '>': begin // atomic group: (?>regex) GrpKind := gkNonCapturingGroup; Inc(regParse, 2); GrpAtomic[regNumBrackets] := True; end; 'P': begin if (regParse + 4 >= fRegexEnd) then Error(reeNamedGroupBad); case (regParse + 2)^ of '<': begin // named group: (?Pregex) GrpKind := gkNormalGroup; FindGroupName(regParse + 3, fRegexEnd, '>', GrpName); Inc(regParse, Length(GrpName) + 4); end; '=': begin // back-reference to named group: (?P=name) GrpKind := gkNamedGroupReference; FindGroupName(regParse + 3, fRegexEnd, ')', GrpName); Inc(regParse, Length(GrpName) + 4); end; '>': begin // subroutine call to named group: (?P>name) GrpKind := gkSubCall; FindGroupName(regParse + 3, fRegexEnd, ')', GrpName); Inc(regParse, Length(GrpName) + 4); GrpIndex := MatchIndexFromName(GrpName); if GrpIndex < 1 then Error(reeNamedGroupBadRef); end; else Error(reeNamedGroupBad); end; end; '<': begin // lookbehind: (?<=foo)bar if (regParse + 4 >= fRegexEnd) then Error(reeLookbehindBad); case (regParse + 2)^ of '=': begin // allow lookbehind only at the beginning if regParse <> fRegexStart + 1 then Error(reeLookaroundNotAtEdge); GrpKind := gkLookbehind; GrpAtomic[regNumBrackets] := RegExprLookbehindIsAtomic; regLookbehind := True; Inc(regParse, 3); end; '!': begin // allow lookbehind only at the beginning if regParse <> fRegexStart + 1 then Error(reeLookaroundNotAtEdge); GrpKind := gkLookbehindNeg; Inc(regParse, 3); SavedPtr := _FindClosingBracket(regParse, fRegexEnd); if SavedPtr = nil then Error(reeCompParseRegUnmatchedBrackets); // for '(?= fRegexEnd) then Error(reeLookaheadBad); regLookahead := True; regLookaheadGroup := regNumBrackets; if NextCh = '=' then begin GrpKind := gkLookahead; end else begin GrpKind := gkLookaheadNeg; regLookaheadNeg := True; end; GrpAtomic[regNumBrackets] := RegExprLookaheadIsAtomic; // check that these brackets are last in regex SavedPtr := _FindClosingBracket(regParse + 1, fRegexEnd); if (SavedPtr <> fRegexEnd - 1) then Error(reeLookaroundNotAtEdge); Inc(regParse, 2); end; '#': begin // (?#comment) GrpKind := gkComment; Inc(regParse, 2); end; 'a'..'z', '-': begin // modifiers string like (?mxr) GrpKind := gkModifierString; Inc(regParse); end; 'R', '0': begin // recursion (?R), (?0) GrpKind := gkRecursion; Inc(regParse, 2); if regParse^ <> ')' then Error(reeBadRecursion); Inc(regParse); end; '1'..'9': begin // subroutine call (?1)..(?99) GrpKind := gkSubCall; GrpIndex := Ord(NextCh) - Ord('0'); Inc(regParse, 2); // support 2-digit group numbers case regParse^ of ')': begin Inc(regParse); end; '0'..'9': begin GrpIndex := GrpIndex * 10 + Ord(regParse^) - Ord('0'); if GrpIndex >= RegexMaxGroups then Error(reeBadSubCall); Inc(regParse); if regParse^ <> ')' then Error(reeBadSubCall); Inc(regParse); end else Error(reeBadRecursion); end; end; '''': begin // named group: (?'name'regex) if (regParse + 4 >= fRegexEnd) then Error(reeNamedGroupBad); GrpKind := gkNormalGroup; FindGroupName(regParse + 2, fRegexEnd, '''', GrpName); Inc(regParse, Length(GrpName) + 3); end; '&': begin // subroutine call to named group: (?&name) if (regParse + 2 >= fRegexEnd) then Error(reeBadSubCall); GrpKind := gkSubCall; FindGroupName(regParse + 2, fRegexEnd, ')', GrpName); Inc(regParse, Length(GrpName) + 3); GrpIndex := MatchIndexFromName(GrpName); if GrpIndex < 1 then Error(reeNamedGroupBadRef); end; else Error(reeIncorrectSpecialBrackets); end; end; // B: process found kind of brackets case GrpKind of gkNormalGroup, gkNonCapturingGroup, gkLookahead, gkLookaheadNeg, gkLookbehind: begin // skip this block for one of passes, to not double groups count; // must take first pass (we need GrpNames filled) if (GrpKind = gkNormalGroup) and not fSecondPass then if GrpCount < RegexMaxGroups - 1 then begin Inc(GrpCount); GrpIndexes[GrpCount] := regNumBrackets; if GrpName <> '' then begin if MatchIndexFromName(GrpName) >= 0 then Error(reeNamedGroupDupName); GrpNames[GrpCount] := GrpName; end; end; ret := ParseReg(True, FlagTemp); if ret = nil then begin Result := nil; Exit; end; FlagParse := FlagParse or FlagTemp and (FLAG_HASWIDTH or FLAG_SPECSTART); end; gkLookbehindNeg: begin // don't make opcode ret := EmitNode(OP_COMMENT); FlagParse := FLAG_WORST; end; gkNamedGroupReference: begin Len := MatchIndexFromName(GrpName); if Len < 0 then Error(reeNamedGroupBadRef); ret := EmitGroupRef(Len, fCompModifiers.I); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; gkModifierString: begin SavedPtr := regParse; while (regParse < fRegexEnd) and (regParse^ <> ')') do Inc(regParse); if (regParse^ <> ')') or not ParseModifiers(SavedPtr, regParse - SavedPtr, fCompModifiers) then begin Error(reeUnrecognizedModifier); Exit; end; Inc(regParse); // skip ')' ret := EmitNode(OP_COMMENT); // comment // Error (reeQuantifFollowsNothing); // Exit; end; gkComment: begin while (regParse < fRegexEnd) and (regParse^ <> ')') do Inc(regParse); if regParse^ <> ')' then begin Error(reeUnclosedComment); Exit; end; Inc(regParse); // skip ')' ret := EmitNode(OP_COMMENT); // comment end; gkRecursion: begin // set FLAG_HASWIDTH to allow compiling of such regex: b(?:m|(?R))*e FlagParse := FlagParse or FLAG_HASWIDTH; ret := EmitNode(OP_RECUR); end; gkSubCall: begin // set FLAG_HASWIDTH like for (?R) FlagParse := FlagParse or FLAG_HASWIDTH; ret := EmitNode(TReOp(Ord(OP_SUBCALL) + GrpIndex)); end; end; // case GrpKind of end; '|', ')': begin // Supposed to be caught earlier. Error(reeInternalUrp); Exit; end; '?', '+', '*': begin Error(reeQuantifFollowsNothing); Exit; end; EscChar: begin if regParse >= fRegexEnd then begin Error(reeTrailingBackSlash); Exit; end; case regParse^ of 'b': ret := EmitNode(OP_BOUND); 'B': ret := EmitNode(OP_NOTBOUND); 'A': ret := EmitNode(OP_BOL); 'z': ret := EmitNode(OP_EOL); 'Z': ret := EmitNode(OP_EOL2); 'd': begin // r.e.extension - any digit ('0' .. '9') ret := EmitNode(OP_ANYDIGIT); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'D': begin // r.e.extension - not digit ('0' .. '9') ret := EmitNode(OP_NOTDIGIT); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 's': begin // r.e.extension - any space char ret := EmitNode(OP_ANYSPACE); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'S': begin // r.e.extension - not space char ret := EmitNode(OP_NOTSPACE); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'w': begin // r.e.extension - any english char / digit / '_' ret := EmitNode(OP_ANYLETTER); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'W': begin // r.e.extension - not english char / digit / '_' ret := EmitNode(OP_NOTLETTER); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'v': begin ret := EmitNode(OP_ANYVERTSEP); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'V': begin ret := EmitNode(OP_NOTVERTSEP); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'h': begin ret := EmitNode(OP_ANYHORZSEP); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'H': begin ret := EmitNode(OP_NOTHORZSEP); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; '1' .. '9': begin ret := EmitGroupRef(Ord(regParse^) - Ord('0'), fCompModifiers.I); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; {$IFDEF FastUnicodeData} 'p': begin ret := EmitCategoryMain(True); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; 'P': begin ret := EmitCategoryMain(False); FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; end; {$ENDIF} else EmitExactly(UnQuoteChar(regParse)); end; { of case } Inc(regParse); end; else begin Dec(regParse); if fCompModifiers.X and // check for eXtended syntax ((regParse^ = '#') or IsIgnoredChar(regParse^)) then begin // ###0.941 \x if regParse^ = '#' then begin // Skip eXtended comment // find comment terminator (group of \n and/or \r) while (regParse < fRegexEnd) and (regParse^ <> #$d) and (regParse^ <> #$a) do Inc(regParse); while (regParse^ = #$d) or (regParse^ = #$a) // skip comment terminator do Inc(regParse); // attempt to support different type of line separators end else begin // Skip the blanks! while IsIgnoredChar(regParse^) do Inc(regParse); end; ret := EmitNode(OP_COMMENT); // comment end else begin Len := FindSkippedMetaLen(regParse, fRegexEnd); if Len <= 0 then if regParse^ <> '{' then begin Error(reeRarseAtomInternalDisaster); Exit; end else Len := FindSkippedMetaLen(regParse + 1, fRegexEnd) + 1; // bad {n,m} - compile as EXACTLY EnderChar := (regParse + Len)^; if (Len > 1) and ((EnderChar = '*') or (EnderChar = '+') or (EnderChar = '?') or (EnderChar = '{')) then Dec(Len); // back off clear of ?+*{ operand. FlagParse := FlagParse or FLAG_HASWIDTH; if Len = 1 then FlagParse := FlagParse or FLAG_SIMPLE; if fCompModifiers.I then ret := EmitNode(OP_EXACTLYCI) else ret := EmitNode(OP_EXACTLY); EmitInt(0); while (Len > 0) and ((not fCompModifiers.X) or (regParse^ <> '#')) do begin if not fCompModifiers.X or not IsIgnoredChar(regParse^) then begin EmitC(regParse^); if regCode <> @regDummy then Inc(regExactlyLen^); end; Inc(regParse); Dec(Len); end; end; { of if not comment } end; { of case else } end; { of case } Result := ret; end; { of function TRegExpr.ParseAtom -------------------------------------------------------------- } function TRegExpr.GetCompilerErrorPos: PtrInt; begin Result := 0; if (fRegexStart = nil) or (regParse = nil) then Exit; // not in compiling mode ? Result := regParse - fRegexStart; end; { of function TRegExpr.GetCompilerErrorPos -------------------------------------------------------------- } { ============================================================= } { ===================== Matching section ====================== } { ============================================================= } procedure TRegExpr.FindGroupName(APtr, AEndPtr: PRegExprChar; AEndChar: REChar; var AName: RegExprString); // check that group name is valid identifier, started from non-digit // this is to be like in Python regex var P: PRegExprChar; begin P := APtr; if IsDigitChar(P^) or not IsWordChar(P^) then Error(reeNamedGroupBadName); repeat if P >= AEndPtr then Error(reeNamedGroupBad); if P^ = AEndChar then Break; if not IsWordChar(P^) then Error(reeNamedGroupBadName); Inc(P); until False; SetString(AName, APtr, P-APtr); end; function TRegExpr.FindRepeated(p: PRegExprChar; AMax: IntPtr): IntPtr; // repeatedly match something simple, report how many // p: points to current opcode var scan: PRegExprChar; opnd: PRegExprChar; TheMax: PtrInt; // PtrInt, gets diff of 2 pointers InvChar: REChar; CurStart, CurEnd: PRegExprChar; ArrayIndex, i: integer; begin Result := 0; scan := regInput; // points into InputString opnd := p + REOpSz + RENextOffSz; // points to operand of opcode (after OP_nnn code) TheMax := fInputEnd - scan; if TheMax > AMax then TheMax := AMax; case PREOp(p)^ of OP_ANY: begin // note - OP_ANYML cannot be proceeded in FindRepeated because can skip // more than one char at once {$IFDEF UnicodeEx} for i := 1 to TheMax do IncUnicode2(scan, Result); {$ELSE} Result := TheMax; Inc(scan, Result); {$ENDIF} end; OP_EXACTLY: begin // in opnd can be only ONE char !!! { // Alexey: commented because of https://github.com/andgineer/TRegExpr/issues/145 NLen := PLongInt(opnd)^; if TheMax > NLen then TheMax := NLen; } Inc(opnd, RENumberSz); while (Result < TheMax) and (opnd^ = scan^) do begin Inc(Result); Inc(scan); end; end; OP_EXACTLYCI: begin // in opnd can be only ONE char !!! { // Alexey: commented because of https://github.com/andgineer/TRegExpr/issues/145 NLen := PLongInt(opnd)^; if TheMax > NLen then TheMax := NLen; } Inc(opnd, RENumberSz); while (Result < TheMax) and (opnd^ = scan^) do begin // prevent unneeded InvertCase //###0.931 Inc(Result); Inc(scan); end; if Result < TheMax then begin // ###0.931 InvChar := InvertCase(opnd^); // store in register while (Result < TheMax) and ((opnd^ = scan^) or (InvChar = scan^)) do begin Inc(Result); Inc(scan); end; end; end; OP_BSUBEXP: begin // ###0.936 ArrayIndex := GrpIndexes[Ord(opnd^)]; if ArrayIndex < 0 then Exit; CurStart := GrpStart[ArrayIndex]; if CurStart = nil then Exit; CurEnd := GrpEnd[ArrayIndex]; if CurEnd = nil then Exit; repeat opnd := CurStart; while opnd < CurEnd do begin if (scan >= fInputEnd) or (scan^ <> opnd^) then Exit; Inc(scan); Inc(opnd); end; Inc(Result); regInput := scan; until Result >= AMax; end; OP_BSUBEXPCI: begin // ###0.936 ArrayIndex := GrpIndexes[Ord(opnd^)]; if ArrayIndex < 0 then Exit; CurStart := GrpStart[ArrayIndex]; if CurStart = nil then Exit; CurEnd := GrpEnd[ArrayIndex]; if CurEnd = nil then Exit; repeat opnd := CurStart; while opnd < CurEnd do begin if (scan >= fInputEnd) or ((scan^ <> opnd^) and (scan^ <> InvertCase(opnd^))) then Exit; Inc(scan); Inc(opnd); end; Inc(Result); regInput := scan; until Result >= AMax; end; OP_ANYDIGIT: while (Result < TheMax) and IsDigitChar(scan^) do begin Inc(Result); Inc(scan); end; OP_NOTDIGIT: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not IsDigitChar(scan^) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not IsDigitChar(scan^) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYLETTER: while (Result < TheMax) and IsWordChar(scan^) do // ###0.940 begin Inc(Result); Inc(scan); end; OP_NOTLETTER: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not IsWordChar(scan^) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not IsWordChar(scan^) do // ###0.940 begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYSPACE: while (Result < TheMax) and IsSpaceChar(scan^) do begin Inc(Result); Inc(scan); end; OP_NOTSPACE: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not IsSpaceChar(scan^) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not IsSpaceChar(scan^) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYVERTSEP: while (Result < TheMax) and IsVertLineSeparator(scan^) do begin Inc(Result); Inc(scan); end; OP_NOTVERTSEP: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not IsVertLineSeparator(scan^) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not IsVertLineSeparator(scan^) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYHORZSEP: while (Result < TheMax) and IsHorzSeparator(scan^) do begin Inc(Result); Inc(scan); end; OP_NOTHORZSEP: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not IsHorzSeparator(scan^) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not IsHorzSeparator(scan^) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYOF: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and FindInCharClass(opnd, scan^, False) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and FindInCharClass(opnd, scan^, False) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYBUT: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not FindInCharClass(opnd, scan^, False) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not FindInCharClass(opnd, scan^, False) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYOFCI: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and FindInCharClass(opnd, scan^, True) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and FindInCharClass(opnd, scan^, True) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_ANYBUTCI: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not FindInCharClass(opnd, scan^, True) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not FindInCharClass(opnd, scan^, True) do begin Inc(Result); Inc(scan); end; {$ENDIF} {$IFDEF FastUnicodeData} OP_ANYCATEGORY: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and MatchOneCharCategory(opnd, scan) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and MatchOneCharCategory(opnd, scan) do begin Inc(Result); Inc(scan); end; {$ENDIF} OP_NOTCATEGORY: {$IFDEF UNICODEEX} begin i := 0; while (i < TheMax) and not MatchOneCharCategory(opnd, scan) do begin Inc(i); IncUnicode2(scan, Result); end; end; {$ELSE} while (Result < TheMax) and not MatchOneCharCategory(opnd, scan) do begin Inc(Result); Inc(scan); end; {$ENDIF} {$ENDIF} else begin // Oh dear. Called inappropriately. Result := 0; Error(reeRegRepeatCalledInappropriately); Exit; end; end; { of case } regInput := scan; end; { of function TRegExpr.FindRepeated -------------------------------------------------------------- } function TRegExpr.regNext(p: PRegExprChar): PRegExprChar; // dig the "next" pointer out of a node var offset: TRENextOff; begin if p = @regDummy then begin Result := nil; Exit; end; offset := PRENextOff(AlignToPtr(p + REOpSz))^; // ###0.933 inlined NEXT if offset = 0 then Result := nil else Result := p + offset; end; { of function TRegExpr.regNext -------------------------------------------------------------- } function TRegExpr.MatchPrim(prog: PRegExprChar): boolean; // recursively matching routine // Conceptually the strategy is simple: check to see whether the current // node matches, call self recursively to see whether the rest matches, // and then act accordingly. In practice we make some effort to avoid // recursion, in particular by going through "ordinary" nodes (that don't // need to know whether the rest of the match failed) by a loop instead of // by recursion. var scan: PRegExprChar; // Current node. next: PRegExprChar; // Next node. Len: PtrInt; opnd: PRegExprChar; no: integer; save: PRegExprChar; saveCurrentGrp: integer; nextch: REChar; BracesMin, BracesMax: integer; // we use integer instead of TREBracesArg for better support */+ {$IFDEF ComplexBraces} SavedLoopStack: TRegExprLoopStack; // :(( very bad for recursion SavedLoopStackIdx: integer; // ###0.925 {$ENDIF} bound1, bound2: boolean; checkAtomicGroup: boolean; begin Result := False; { // Alexey: not sure it's ok for long searches in big texts, so disabled if regNestedCalls > MaxRegexBackTracking then Exit; Inc(regNestedCalls); } scan := prog; while scan <> nil do begin Len := PRENextOff(AlignToPtr(scan + 1))^; // ###0.932 inlined regNext if Len = 0 then next := nil else next := scan + Len; case scan^ of OP_BOUND: begin bound1 := (regInput = fInputStart) or not IsWordChar((regInput - 1)^); bound2 := (regInput >= fInputEnd) or not IsWordChar(regInput^); if bound1 = bound2 then Exit; end; OP_NOTBOUND: begin bound1 := (regInput = fInputStart) or not IsWordChar((regInput - 1)^); bound2 := (regInput >= fInputEnd) or not IsWordChar(regInput^); if bound1 <> bound2 then Exit; end; OP_BOL: begin if regInput <> fInputStart then Exit; end; OP_EOL: begin // \z matches at the very end if regInput < fInputEnd then Exit; end; OP_EOL2: begin // \Z matches at the very and + before the final line-break (LF and CR LF) if regInput < fInputEnd then begin if (regInput = fInputEnd - 1) and (regInput^ = #10) then begin end else if (regInput = fInputEnd - 2) and (regInput^ = #13) and ((regInput + 1) ^ = #10) then begin end else Exit; end; end; OP_BOLML: if regInput > fInputStart then begin if ((regInput - 1) <= fInputStart) or not IsPairedBreak(regInput - 2) then begin // don't stop between paired separator if IsPairedBreak(regInput - 1) then Exit; if not IsCustomLineSeparator((regInput - 1)^) then Exit; end; end; OP_EOLML: if regInput < fInputEnd then begin if not IsPairedBreak(regInput) then begin // don't stop between paired separator if (regInput > fInputStart) and IsPairedBreak(regInput - 1) then Exit; if not IsCustomLineSeparator(regInput^) then Exit; end; end; OP_ANY: begin if regInput >= fInputEnd then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYML: begin if (regInput >= fInputEnd) or IsPairedBreak(regInput) or IsCustomLineSeparator(regInput^) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYDIGIT: begin if (regInput >= fInputEnd) or not IsDigitChar(regInput^) then Exit; Inc(regInput); end; OP_NOTDIGIT: begin if (regInput >= fInputEnd) or IsDigitChar(regInput^) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYLETTER: begin if (regInput >= fInputEnd) or not IsWordChar(regInput^) then Exit; Inc(regInput); end; OP_NOTLETTER: begin if (regInput >= fInputEnd) or IsWordChar(regInput^) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYSPACE: begin if (regInput >= fInputEnd) or not IsSpaceChar(regInput^) then Exit; Inc(regInput); end; OP_NOTSPACE: begin if (regInput >= fInputEnd) or IsSpaceChar(regInput^) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYVERTSEP: begin if (regInput >= fInputEnd) or not IsVertLineSeparator(regInput^) then Exit; Inc(regInput); end; OP_NOTVERTSEP: begin if (regInput >= fInputEnd) or IsVertLineSeparator(regInput^) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYHORZSEP: begin if (regInput >= fInputEnd) or not IsHorzSeparator(regInput^) then Exit; Inc(regInput); end; OP_NOTHORZSEP: begin if (regInput >= fInputEnd) or IsHorzSeparator(regInput^) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_EXACTLYCI: begin opnd := scan + REOpSz + RENextOffSz; // OPERAND Len := PLongInt(opnd)^; Inc(opnd, RENumberSz); // Inline the first character, for speed. if (opnd^ <> regInput^) and (InvertCase(opnd^) <> regInput^) then Exit; // ###0.929 begin no := Len; save := regInput; while no > 1 do begin Inc(save); Inc(opnd); if (opnd^ <> save^) and (InvertCase(opnd^) <> save^) then Exit; Dec(no); end; // ###0.929 end Inc(regInput, Len); end; OP_EXACTLY: begin opnd := scan + REOpSz + RENextOffSz; // OPERAND Len := PLongInt(opnd)^; Inc(opnd, RENumberSz); // Inline the first character, for speed. if opnd^ <> regInput^ then Exit; // ###0.929 begin no := Len; save := regInput; while no > 1 do begin Inc(save); Inc(opnd); if opnd^ <> save^ then Exit; Dec(no); end; // ###0.929 end Inc(regInput, Len); end; OP_BSUBEXP: begin // ###0.936 no := Ord((scan + REOpSz + RENextOffSz)^); no := GrpIndexes[no]; if no < 0 then Exit; if GrpStart[no] = nil then Exit; if GrpEnd[no] = nil then Exit; save := regInput; opnd := GrpStart[no]; while opnd < GrpEnd[no] do begin if (save >= fInputEnd) or (save^ <> opnd^) then Exit; Inc(save); Inc(opnd); end; regInput := save; end; OP_BSUBEXPCI: begin // ###0.936 no := Ord((scan + REOpSz + RENextOffSz)^); no := GrpIndexes[no]; if no < 0 then Exit; if GrpStart[no] = nil then Exit; if GrpEnd[no] = nil then Exit; save := regInput; opnd := GrpStart[no]; while opnd < GrpEnd[no] do begin if (save >= fInputEnd) or ((save^ <> opnd^) and (save^ <> InvertCase(opnd^))) then Exit; Inc(save); Inc(opnd); end; regInput := save; end; OP_ANYOF: begin if (regInput >= fInputEnd) or not FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, False) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYBUT: begin if (regInput >= fInputEnd) or FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, False) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYOFCI: begin if (regInput >= fInputEnd) or not FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, True) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_ANYBUTCI: begin if (regInput >= fInputEnd) or FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, True) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_NOTHING: ; OP_COMMENT: ; OP_BACK: ; OP_OPEN_FIRST .. OP_OPEN_LAST: begin no := Ord(scan^) - Ord(OP_OPEN); regCurrentGrp := no; save := GrpStart[no]; // ###0.936 GrpStart[no] := regInput; // ###0.936 Result := MatchPrim(next); if not Result then // ###0.936 GrpStart[no] := save; // handle negative lookahead if regLookaheadNeg then if no = regLookaheadGroup then begin Result := not Result; if Result then begin // we need zero length of "lookahead group", // it is later used to adjust the match GrpStart[no] := regInput; GrpEnd[no]:= regInput; end else GrpStart[no] := save; end; Exit; end; OP_CLOSE_FIRST .. OP_CLOSE_LAST: begin no := Ord(scan^) - Ord(OP_CLOSE); regCurrentGrp := -1; // handle atomic group, mark it as "done" // (we are here because some OP_BRANCH is matched) if GrpAtomic[no] then GrpAtomicDone[no] := True; save := GrpEnd[no]; // ###0.936 GrpEnd[no] := regInput; // ###0.936 // if we are in OP_SUBCALL* call, it called OP_OPEN*, so we must return // in OP_CLOSE, without going to next opcode if GrpSubCalled[no] then begin Result := True; Exit; end; Result := MatchPrim(next); if not Result then // ###0.936 GrpEnd[no] := save; Exit; end; OP_BRANCH: begin saveCurrentGrp := regCurrentGrp; checkAtomicGroup := (regCurrentGrp >= 0) and GrpAtomic[regCurrentGrp]; if (next^ <> OP_BRANCH) // No next choice in group then next := scan + REOpSz + RENextOffSz // Avoid recursion else begin repeat save := regInput; Result := MatchPrim(scan + REOpSz + RENextOffSz); regCurrentGrp := saveCurrentGrp; if Result then Exit; // if branch worked until OP_CLOSE, and marked atomic group as "done", then exit if checkAtomicGroup then if GrpAtomicDone[regCurrentGrp] then Exit; regInput := save; scan := regNext(scan); until (scan = nil) or (scan^ <> OP_BRANCH); Exit; end; end; {$IFDEF ComplexBraces} OP_LOOPENTRY: begin // ###0.925 no := LoopStackIdx; Inc(LoopStackIdx); if LoopStackIdx > LoopStackMax then begin Error(reeLoopStackExceeded); Exit; end; save := regInput; LoopStack[LoopStackIdx] := 0; // init loop counter Result := MatchPrim(next); // execute loop LoopStackIdx := no; // cleanup if Result then Exit; regInput := save; Exit; end; OP_LOOP, OP_LOOPNG: begin // ###0.940 if LoopStackIdx <= 0 then begin Error(reeLoopWithoutEntry); Exit; end; opnd := scan + PRENextOff(AlignToPtr(scan + REOpSz + RENextOffSz + 2 * REBracesArgSz))^; BracesMin := PREBracesArg(AlignToInt(scan + REOpSz + RENextOffSz))^; BracesMax := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz))^; save := regInput; if LoopStack[LoopStackIdx] >= BracesMin then begin // Min alredy matched - we can work if scan^ = OP_LOOP then begin // greedy way - first try to max deep of greed ;) if LoopStack[LoopStackIdx] < BracesMax then begin Inc(LoopStack[LoopStackIdx]); no := LoopStackIdx; Result := MatchPrim(opnd); LoopStackIdx := no; if Result then Exit; regInput := save; end; Dec(LoopStackIdx); // Fail. May be we are too greedy? ;) Result := MatchPrim(next); if not Result then regInput := save; Exit; end else begin // non-greedy - try just now Result := MatchPrim(next); if Result then Exit else regInput := save; // failed - move next and try again if LoopStack[LoopStackIdx] < BracesMax then begin Inc(LoopStack[LoopStackIdx]); no := LoopStackIdx; Result := MatchPrim(opnd); LoopStackIdx := no; if Result then Exit; regInput := save; end; Dec(LoopStackIdx); // Failed - back up Exit; end end else begin // first match a min_cnt times Inc(LoopStack[LoopStackIdx]); no := LoopStackIdx; Result := MatchPrim(opnd); LoopStackIdx := no; if Result then Exit; Dec(LoopStack[LoopStackIdx]); regInput := save; Exit; end; end; {$ENDIF} OP_STAR, OP_PLUS, OP_BRACES, OP_STARNG, OP_PLUSNG, OP_BRACESNG: begin // Lookahead to avoid useless match attempts when we know // what character comes next. nextch := #0; if next^ = OP_EXACTLY then nextch := (next + REOpSz + RENextOffSz + RENumberSz)^; BracesMax := MaxInt; // infinite loop for * and + //###0.92 if (scan^ = OP_STAR) or (scan^ = OP_STARNG) then BracesMin := 0 // star else if (scan^ = OP_PLUS) or (scan^ = OP_PLUSNG) then BracesMin := 1 // plus else begin // braces BracesMin := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; BracesMax := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz))^; end; save := regInput; opnd := scan + REOpSz + RENextOffSz; if (scan^ = OP_BRACES) or (scan^ = OP_BRACESNG) then Inc(opnd, 2 * REBracesArgSz); if (scan^ = OP_PLUSNG) or (scan^ = OP_STARNG) or (scan^ = OP_BRACESNG) then begin // non-greedy mode BracesMax := FindRepeated(opnd, BracesMax); // don't repeat more than BracesMax // Now we know real Max limit to move forward (for recursion 'back up') // In some cases it can be faster to check only Min positions first, // but after that we have to check every position separtely instead // of fast scannig in loop. no := BracesMin; while no <= BracesMax do begin regInput := save + no; // If it could work, try it. if (nextch = #0) or (regInput^ = nextch) then begin {$IFDEF ComplexBraces} System.Move(LoopStack, SavedLoopStack, SizeOf(LoopStack)); // ###0.925 SavedLoopStackIdx := LoopStackIdx; {$ENDIF} if MatchPrim(next) then begin Result := True; Exit; end; {$IFDEF ComplexBraces} System.Move(SavedLoopStack, LoopStack, SizeOf(LoopStack)); LoopStackIdx := SavedLoopStackIdx; {$ENDIF} end; Inc(no); // Couldn't or didn't - move forward. end; { of while } Exit; end else begin // greedy mode no := FindRepeated(opnd, BracesMax); // don't repeat more than max_cnt while no >= BracesMin do begin // If it could work, try it. if (nextch = #0) or (regInput^ = nextch) then begin {$IFDEF ComplexBraces} System.Move(LoopStack, SavedLoopStack, SizeOf(LoopStack)); // ###0.925 SavedLoopStackIdx := LoopStackIdx; {$ENDIF} if MatchPrim(next) then begin Result := True; Exit; end; {$IFDEF ComplexBraces} System.Move(SavedLoopStack, LoopStack, SizeOf(LoopStack)); LoopStackIdx := SavedLoopStackIdx; {$ENDIF} end; Dec(no); // Couldn't or didn't - back up. regInput := save + no; end; { of while } Exit; end; end; OP_STAR_POSS, OP_PLUS_POSS, OP_BRACES_POSS: begin // Lookahead to avoid useless match attempts when we know // what character comes next. nextch := #0; if next^ = OP_EXACTLY then nextch := (next + REOpSz + RENextOffSz + RENumberSz)^; opnd := scan + REOpSz + RENextOffSz; case scan^ of OP_STAR_POSS: begin BracesMin := 0; BracesMax := MaxInt; end; OP_PLUS_POSS: begin BracesMin := 1; BracesMax := MaxInt; end; else begin // braces BracesMin := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; BracesMax := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz))^; Inc(opnd, 2 * REBracesArgSz); end; end; no := FindRepeated(opnd, BracesMax); if no >= BracesMin then if (nextch = #0) or (regInput^ = nextch) then Result := MatchPrim(next); Exit; end; OP_EEND: begin Result := True; // Success! Exit; end; {$IFDEF FastUnicodeData} OP_ANYCATEGORY: begin if (regInput >= fInputEnd) then Exit; if not MatchOneCharCategory(scan + REOpSz + RENextOffSz, regInput) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; OP_NOTCATEGORY: begin if (regInput >= fInputEnd) then Exit; if MatchOneCharCategory(scan + REOpSz + RENextOffSz, regInput) then Exit; {$IFDEF UNICODEEX} IncUnicode(regInput); {$ELSE} Inc(regInput); {$ENDIF} end; {$ENDIF} OP_RECUR: begin // call opcode start if not MatchPrim(regCodeWork) then Exit; end; OP_SUBCALL_FIRST .. OP_SUBCALL_LAST: begin // call subroutine no := GrpIndexes[Ord(scan^) - Ord(OP_SUBCALL)]; if no < 0 then Exit; save := GrpOpCodes[no]; if save = nil then Exit; checkAtomicGroup := GrpSubCalled[no]; // mark group in GrpSubCalled array so opcode can detect subcall GrpSubCalled[no] := True; if not MatchPrim(save) then begin GrpSubCalled[no] := checkAtomicGroup; Exit; end; GrpSubCalled[no] := checkAtomicGroup; end; else begin Error(reeMatchPrimMemoryCorruption); Exit; end; end; { of case scan^ } scan := next; end; { of while scan <> nil } // We get here only if there's trouble -- normally "case EEND" is the // terminating point. Error(reeMatchPrimCorruptedPointers); end; { of function TRegExpr.MatchPrim -------------------------------------------------------------- } function TRegExpr.Exec(const AInputString: RegExprString): boolean; begin InputString := AInputString; Result := ExecPrim(1, False, False, False); end; { of function TRegExpr.Exec -------------------------------------------------------------- } {$IFDEF OverMeth} function TRegExpr.Exec: boolean; var SlowChecks: boolean; begin SlowChecks := fInputLength < fSlowChecksSizeMax; Result := ExecPrim(1, False, SlowChecks, False); end; { of function TRegExpr.Exec -------------------------------------------------------------- } function TRegExpr.Exec(AOffset: IntPtr): boolean; begin Result := ExecPrim(AOffset, False, False, False); end; { of function TRegExpr.Exec -------------------------------------------------------------- } {$ENDIF} function TRegExpr.ExecPos(AOffset: IntPtr {$IFDEF DefParam} = 1{$ENDIF}): boolean; begin Result := ExecPrim(AOffset, False, False, False); end; { of function TRegExpr.ExecPos -------------------------------------------------------------- } {$IFDEF OverMeth} function TRegExpr.ExecPos(AOffset: IntPtr; ATryOnce, ABackward: boolean): boolean; begin Result := ExecPrim(AOffset, ATryOnce, False, ABackward); end; {$ENDIF} procedure TRegExpr.SetInputString(AInputString: PRegExprChar; ALength: UIntPtr); begin fInputString := ''; fInputLength := ALength; fInputStart := AInputString; fInputEnd := fInputStart + fInputLength; end; { of procedure TRegExpr.SetInputString --------------------------------------------------------------} function TRegExpr.MatchAtOnePos(APos: PRegExprChar): boolean; begin // test for lookbehind '(?= fInputStart then begin fHelper.SetInputRange(APos - fHelperLen, APos); if fHelper.MatchAtOnePos(APos - fHelperLen) then begin Result := False; Exit; end; end; regInput := APos; regCurrentGrp := -1; regNestedCalls := 0; Result := MatchPrim(regCodeWork); if Result then begin GrpStart[0] := APos; GrpEnd[0] := regInput; // with lookbehind, increase found position by the len of group=1 if regLookbehind then Inc(GrpStart[0], GrpEnd[1] - GrpStart[1]); // with lookahead, decrease ending by the len of group=regLookaheadGroup if regLookahead and (regLookaheadGroup > 0) then Dec(GrpEnd[0], GrpEnd[regLookaheadGroup] - GrpStart[regLookaheadGroup]); end; end; procedure TRegExpr.ClearMatches; begin FillChar(GrpStart, SizeOf(GrpStart), 0); FillChar(GrpEnd, SizeOf(GrpEnd), 0); FillChar(GrpAtomicDone, SizeOf(GrpAtomicDone), 0); FillChar(GrpSubCalled, SizeOf(GrpSubCalled), 0); end; procedure TRegExpr.ClearInternalIndexes; var i: integer; begin FillChar(GrpStart, SizeOf(GrpStart), 0); FillChar(GrpEnd, SizeOf(GrpEnd), 0); FillChar(GrpAtomic, SizeOf(GrpAtomic), 0); FillChar(GrpAtomicDone, SizeOf(GrpAtomicDone), 0); FillChar(GrpSubCalled, SizeOf(GrpSubCalled), 0); FillChar(GrpOpCodes, SizeOf(GrpOpCodes), 0); for i := 0 to RegexMaxGroups - 1 do begin GrpIndexes[i] := -1; GrpNames[i] := ''; end; GrpIndexes[0] := 0; GrpCount := 0; end; function TRegExpr.ExecPrim(AOffset: IntPtr; ATryOnce, ASlowChecks, ABackward: boolean): boolean; var Ptr: PRegExprChar; begin Result := False; // Ensure that Match cleared either if optimization tricks or some error // will lead to leaving ExecPrim without actual search. That is // important for ExecNext logic and so on. ClearMatches; // Don't check IsProgrammOk here! it causes big slowdown in test_benchmark! if programm = nil then begin Compile; if programm = nil then Exit; end; if fInputLength = 0 then begin // Empty string can match e.g. '^$' if regMustLen > 0 then Exit; end; // Check that the start position is not negative if AOffset < 1 then begin Error(reeOffsetMustBePositive); Exit; end; // Check that the start position is not longer than the line if AOffset > (fInputLength + 1) then Exit; Ptr := fInputStart + AOffset - 1; // If there is a "must appear" string, look for it. if ASlowChecks then if regMustString <> '' then if StrPos(PRegExprChar(regMustString), fInputStart) = nil then Exit; {$IFDEF ComplexBraces} // no loops started LoopStackIdx := 0; // ###0.925 {$ENDIF} // ATryOnce or anchored match (it needs to be tried only once). if ATryOnce or (regAnchored <> #0) then begin {$IFDEF UseFirstCharSet} {$IFDEF UniCode} if Ord(Ptr^) <= $FF then {$ENDIF} if not FirstCharArray[byte(Ptr^)] then Exit; {$ENDIF} Result := MatchAtOnePos(Ptr); Exit; end; // Messy cases: unanchored match. if ABackward then Inc(Ptr, 2) else Dec(Ptr); repeat if ABackward then begin Dec(Ptr); if Ptr < fInputStart then Exit; end else begin Inc(Ptr); if Ptr > fInputEnd then Exit; end; {$IFDEF UseFirstCharSet} {$IFDEF UniCode} if Ord(Ptr^) <= $FF then {$ENDIF} if not FirstCharArray[byte(Ptr^)] then Continue; {$ENDIF} Result := MatchAtOnePos(Ptr); // Exit on a match or after testing the end-of-string if Result then Exit; until False; end; { of function TRegExpr.ExecPrim -------------------------------------------------------------- } function TRegExpr.ExecNext(ABackward: boolean {$IFDEF DefParam} = False{$ENDIF}): boolean; var PtrBegin, PtrEnd: PRegExprChar; Offset: PtrInt; begin PtrBegin := GrpStart[0]; PtrEnd := GrpEnd[0]; if (PtrBegin = nil) or (PtrEnd = nil) then begin Error(reeExecNextWithoutExec); Result := False; Exit; end; Offset := PtrEnd - fInputStart + 1; // prevent infinite looping if empty string matches r.e. if PtrBegin = PtrEnd then Inc(Offset); Result := ExecPrim(Offset, False, False, ABackward); end; { of function TRegExpr.ExecNext -------------------------------------------------------------- } procedure TRegExpr.SetInputString(const AInputString: RegExprString); begin ClearMatches; fInputString := AInputString; UniqueString(fInputString); fInputLength := Length(fInputString); fInputStart := PRegExprChar(fInputString); fInputEnd := fInputStart + Length(fInputString); end; procedure TRegExpr.SetInputRange(AStart, AEnd: PRegExprChar); begin fInputLength := 0; fInputString := ''; fInputStart := AStart; fInputEnd := AEnd; end; {$IFDEF UseLineSep} procedure TRegExpr.SetLineSeparators(const AStr: RegExprString); begin if AStr <> fLineSeparators then begin fLineSeparators := AStr; InitLineSepArray; InvalidateProgramm; end; end; { of procedure TRegExpr.SetLineSeparators -------------------------------------------------------------- } {$ENDIF} procedure TRegExpr.SetUsePairedBreak(AValue: boolean); begin if AValue <> fUsePairedBreak then begin fUsePairedBreak := AValue; InvalidateProgramm; end; end; function TRegExpr.Substitute(const ATemplate: RegExprString): RegExprString; // perform substitutions after a regexp match var TemplateBeg, TemplateEnd: PRegExprChar; function ParseVarName(var APtr: PRegExprChar): integer; // extract name of variable: $1 or ${1} or ${name} // from APtr^, uses TemplateEnd var p: PRegExprChar; Delimited: boolean; GrpName: RegExprString; begin Result := 0; p := APtr; Delimited := (p < TemplateEnd) and (p^ = '{'); if Delimited then Inc(p); // skip left curly brace if (p < TemplateEnd) and (p^ = '&') then Inc(p) // this is '$&' or '${&}' else begin if IsDigitChar(p^) then begin while (p < TemplateEnd) and IsDigitChar(p^) do begin Result := Result * 10 + (Ord(p^) - Ord('0')); Inc(p); end end else if Delimited then begin FindGroupName(p, TemplateEnd, '}', GrpName); Result := MatchIndexFromName(GrpName); Inc(p, Length(GrpName)); end; end; if Delimited then if (p < TemplateEnd) and (p^ = '}') then Inc(p) // skip right curly brace else p := APtr; // isn't properly terminated if p = APtr then Result := -1; // no valid digits found or no right curly brace APtr := p; end; procedure FindSubstGroupIndex(var p: PRegExprChar; var Idx: integer); begin Idx := ParseVarName(p); if (Idx >= 0) and (Idx <= High(GrpIndexes)) then Idx := GrpIndexes[Idx]; end; type TSubstMode = (smodeNormal, smodeOneUpper, smodeOneLower, smodeAllUpper, smodeAllLower); var Mode: TSubstMode; p, p0, p1, ResultPtr: PRegExprChar; ResultLen, n: integer; Ch, QuotedChar: REChar; begin // Check programm and input string if not IsProgrammOk then Exit; // Note: don't check for empty fInputString, it's valid case, // e.g. user needs to replace regex "\b" to "_", it's zero match length if ATemplate = '' then begin Result := ''; Exit; end; TemplateBeg := PRegExprChar(ATemplate); TemplateEnd := TemplateBeg + Length(ATemplate); // Count result length for speed optimization. ResultLen := 0; p := TemplateBeg; while p < TemplateEnd do begin Ch := p^; Inc(p); n := -1; if Ch = SubstituteGroupChar then FindSubstGroupIndex(p, n); if n >= 0 then begin Inc(ResultLen, GrpEnd[n] - GrpStart[n]); end else begin if (Ch = EscChar) and (p < TemplateEnd) then begin // quoted or special char followed Ch := p^; Inc(p); case Ch of 'n': Inc(ResultLen, Length(fReplaceLineEnd)); 'u', 'l', 'U', 'L': { nothing } ; 'x': begin Inc(ResultLen); if (p^ = '{') then begin // skip \x{....} while ((p^ <> '}') and (p < TemplateEnd)) do p := p + 1; p := p + 1; end else p := p + 2 // skip \x.. end; else Inc(ResultLen); end; end else Inc(ResultLen); end; end; // Get memory. We do it once and it significant speed up work ! if ResultLen = 0 then begin Result := ''; Exit; end; SetLength(Result, ResultLen); // Fill Result ResultPtr := PRegExprChar(Result); p := TemplateBeg; Mode := smodeNormal; while p < TemplateEnd do begin Ch := p^; p0 := p; Inc(p); p1 := p; n := -1; if Ch = SubstituteGroupChar then FindSubstGroupIndex(p, n); if (n >= 0) then begin p0 := GrpStart[n]; p1 := GrpEnd[n]; end else begin if (Ch = EscChar) and (p < TemplateEnd) then begin // quoted or special char followed Ch := p^; Inc(p); case Ch of 'n': begin p0 := PRegExprChar(fReplaceLineEnd); p1 := p0 + Length(fReplaceLineEnd); end; 'x', 't', 'r', 'f', 'a', 'e': begin p := p - 1; // UnquoteChar expects the escaped char under the pointer QuotedChar := UnQuoteChar(p); p := p + 1; // Skip after last part of the escaped sequence - UnquoteChar stops on the last symbol of it p0 := @QuotedChar; p1 := p0 + 1; end; 'l': begin Mode := smodeOneLower; p1 := p0; end; 'L': begin Mode := smodeAllLower; p1 := p0; end; 'u': begin Mode := smodeOneUpper; p1 := p0; end; 'U': begin Mode := smodeAllUpper; p1 := p0; end; else begin Inc(p0); Inc(p1); end; end; end end; if p0 < p1 then begin while p0 < p1 do begin case Mode of smodeOneLower: begin ResultPtr^ := _LowerCase(p0^); Mode := smodeNormal; end; smodeAllLower: begin ResultPtr^ := _LowerCase(p0^); end; smodeOneUpper: begin ResultPtr^ := _UpperCase(p0^); Mode := smodeNormal; end; smodeAllUpper: begin ResultPtr^ := _UpperCase(p0^); end; else ResultPtr^ := p0^; end; Inc(ResultPtr); Inc(p0); end; Mode := smodeNormal; end; end; end; { of function TRegExpr.Substitute -------------------------------------------------------------- } procedure TRegExpr.Split(const AInputStr: RegExprString; APieces: TStrings); var PrevPos: PtrInt; begin PrevPos := 1; if Exec(AInputStr) then repeat APieces.Add(System.Copy(AInputStr, PrevPos, MatchPos[0] - PrevPos)); PrevPos := MatchPos[0] + MatchLen[0]; until not ExecNext; APieces.Add(System.Copy(AInputStr, PrevPos, MaxInt)); // Tail end; { of procedure TRegExpr.Split -------------------------------------------------------------- } function TRegExpr.Replace(const AInputStr: RegExprString; const AReplaceStr: RegExprString; AUseSubstitution: boolean{$IFDEF DefParam} = False{$ENDIF}): RegExprString; var PrevPos: PtrInt; begin Result := ''; PrevPos := 1; if Exec(AInputStr) then repeat Result := Result + System.Copy(AInputStr, PrevPos, MatchPos[0] - PrevPos); if AUseSubstitution // ###0.946 then Result := Result + Substitute(AReplaceStr) else Result := Result + AReplaceStr; PrevPos := MatchPos[0] + MatchLen[0]; until not ExecNext; Result := Result + System.Copy(AInputStr, PrevPos, MaxInt); // Tail end; { of function TRegExpr.Replace -------------------------------------------------------------- } function TRegExpr.ReplaceEx(const AInputStr: RegExprString; AReplaceFunc: TRegExprReplaceFunction): RegExprString; var PrevPos: PtrInt; begin Result := ''; PrevPos := 1; if Exec(AInputStr) then repeat Result := Result + System.Copy(AInputStr, PrevPos, MatchPos[0] - PrevPos) + AReplaceFunc(Self); PrevPos := MatchPos[0] + MatchLen[0]; until not ExecNext; Result := Result + System.Copy(AInputStr, PrevPos, MaxInt); // Tail end; { of function TRegExpr.ReplaceEx -------------------------------------------------------------- } {$IFDEF OverMeth} function TRegExpr.Replace(const AInputStr: RegExprString; AReplaceFunc: TRegExprReplaceFunction): RegExprString; begin Result := ReplaceEx(AInputStr, AReplaceFunc); end; { of function TRegExpr.Replace -------------------------------------------------------------- } {$ENDIF} { ============================================================= } { ====================== Debug section ======================== } { ============================================================= } {$IFDEF UseFirstCharSet} procedure TRegExpr.FillFirstCharSet(prog: PRegExprChar); var scan: PRegExprChar; // Current node. Next: PRegExprChar; // Next node. opnd: PRegExprChar; Oper: TREOp; ch: REChar; min_cnt, i: integer; TempSet: TRegExprCharset; begin TempSet := []; scan := prog; while scan <> nil do begin Next := regNext(scan); Oper := PREOp(scan)^; case Oper of OP_BSUBEXP, OP_BSUBEXPCI: begin // we cannot optimize r.e. if it starts with back reference FirstCharSet := RegExprAllSet; //###0.930 Exit; end; OP_BOL, OP_BOLML: ; // Exit; //###0.937 OP_EOL, OP_EOL2, OP_EOLML: begin //###0.948 was empty in 0.947, was EXIT in 0.937 Include(FirstCharSet, 0); if ModifierM then begin {$IFDEF UseLineSep} for i := 1 to Length(LineSeparators) do Include(FirstCharSet, byte(LineSeparators[i])); {$ELSE} FirstCharSet := FirstCharSet + RegExprLineSeparatorsSet; {$ENDIF} end; Exit; end; OP_BOUND, OP_NOTBOUND: ; //###0.943 ?!! OP_ANY, OP_ANYML: begin // we can better define ANYML !!! FirstCharSet := RegExprAllSet; //###0.930 Exit; end; OP_ANYDIGIT: begin FirstCharSet := FirstCharSet + RegExprDigitSet; Exit; end; OP_NOTDIGIT: begin FirstCharSet := FirstCharSet + (RegExprAllSet - RegExprDigitSet); Exit; end; OP_ANYLETTER: begin GetCharSetFromWordChars(TempSet); FirstCharSet := FirstCharSet + TempSet; Exit; end; OP_NOTLETTER: begin GetCharSetFromWordChars(TempSet); FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); Exit; end; OP_ANYSPACE: begin GetCharSetFromSpaceChars(TempSet); FirstCharSet := FirstCharSet + TempSet; Exit; end; OP_NOTSPACE: begin GetCharSetFromSpaceChars(TempSet); FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); Exit; end; OP_ANYVERTSEP: begin FirstCharSet := FirstCharSet + RegExprLineSeparatorsSet; Exit; end; OP_NOTVERTSEP: begin FirstCharSet := FirstCharSet + (RegExprAllSet - RegExprLineSeparatorsSet); Exit; end; OP_ANYHORZSEP: begin FirstCharSet := FirstCharSet + RegExprHorzSeparatorsSet; Exit; end; OP_NOTHORZSEP: begin FirstCharSet := FirstCharSet + (RegExprAllSet - RegExprHorzSeparatorsSet); Exit; end; OP_EXACTLYCI: begin ch := (scan + REOpSz + RENextOffSz + RENumberSz)^; {$IFDEF UniCode} if Ord(ch) <= $FF then {$ENDIF} begin Include(FirstCharSet, byte(ch)); Include(FirstCharSet, byte(InvertCase(ch))); end; Exit; end; OP_EXACTLY: begin ch := (scan + REOpSz + RENextOffSz + RENumberSz)^; {$IFDEF UniCode} if Ord(ch) <= $FF then {$ENDIF} Include(FirstCharSet, byte(ch)); Exit; end; OP_ANYOF: begin GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, False, TempSet); FirstCharSet := FirstCharSet + TempSet; Exit; end; OP_ANYBUT: begin GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, False, TempSet); FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); Exit; end; OP_ANYOFCI: begin GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, True, TempSet); FirstCharSet := FirstCharSet + TempSet; Exit; end; OP_ANYBUTCI: begin GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, True, TempSet); FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); Exit; end; OP_NOTHING: ; OP_COMMENT: ; OP_BACK: ; OP_OPEN_FIRST .. OP_OPEN_LAST: begin FillFirstCharSet(Next); Exit; end; OP_CLOSE_FIRST .. OP_CLOSE_LAST: begin FillFirstCharSet(Next); Exit; end; OP_BRANCH: begin if (PREOp(Next)^ <> OP_BRANCH) // No choice. then Next := scan + REOpSz + RENextOffSz // Avoid recursion. else begin repeat FillFirstCharSet(scan + REOpSz + RENextOffSz); scan := regNext(scan); until (scan = nil) or (PREOp(scan)^ <> OP_BRANCH); Exit; end; end; {$IFDEF ComplexBraces} OP_LOOPENTRY: begin //###0.925 //LoopStack [LoopStackIdx] := 0; //###0.940 line removed FillFirstCharSet(Next); // execute LOOP Exit; end; OP_LOOP, OP_LOOPNG: begin //###0.940 opnd := scan + PRENextOff(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz * 2))^; min_cnt := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; FillFirstCharSet(opnd); if min_cnt = 0 then FillFirstCharSet(Next); Exit; end; {$ENDIF} OP_STAR, OP_STARNG, OP_STAR_POSS: //###0.940 FillFirstCharSet(scan + REOpSz + RENextOffSz); OP_PLUS, OP_PLUSNG, OP_PLUS_POSS: begin //###0.940 FillFirstCharSet(scan + REOpSz + RENextOffSz); Exit; end; OP_BRACES, OP_BRACESNG, OP_BRACES_POSS: begin //###0.940 opnd := scan + REOpSz + RENextOffSz + REBracesArgSz * 2; min_cnt := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; // BRACES FillFirstCharSet(opnd); if min_cnt > 0 then Exit; end; OP_EEND: begin FirstCharSet := RegExprAllSet; //###0.948 Exit; end; OP_ANYCATEGORY, OP_NOTCATEGORY: begin FirstCharSet := RegExprAllSet; Exit; end; OP_RECUR, OP_SUBCALL_FIRST .. OP_SUBCALL_LAST: begin end else begin fLastErrorOpcode := Oper; Error(reeUnknownOpcodeInFillFirst); Exit; end; end; { of case scan^} scan := Next; end; { of while scan <> nil} end; { of procedure FillFirstCharSet --------------------------------------------------------------} {$ENDIF} procedure TRegExpr.InitCharCheckers; var Cnt: integer; // function Add(AChecker: TRegExprCharChecker): byte; begin Inc(Cnt); if Cnt > High(CharCheckers) then Error(reeTooSmallCheckersArray); CharCheckers[Cnt - 1] := AChecker; Result := Cnt - 1; end; // begin Cnt := 0; FillChar(CharCheckers, SizeOf(CharCheckers), 0); CheckerIndex_Word := Add(CharChecker_Word); CheckerIndex_NotWord := Add(CharChecker_NotWord); CheckerIndex_Space := Add(CharChecker_Space); CheckerIndex_NotSpace := Add(CharChecker_NotSpace); CheckerIndex_Digit := Add(CharChecker_Digit); CheckerIndex_NotDigit := Add(CharChecker_NotDigit); CheckerIndex_VertSep := Add(CharChecker_VertSep); CheckerIndex_NotVertSep := Add(CharChecker_NotVertSep); CheckerIndex_HorzSep := Add(CharChecker_HorzSep); CheckerIndex_NotHorzSep := Add(CharChecker_NotHorzSep); //CheckerIndex_AllAZ := Add(CharChecker_AllAZ); CheckerIndex_LowerAZ := Add(CharChecker_LowerAZ); CheckerIndex_UpperAZ := Add(CharChecker_UpperAZ); SetLength(CharCheckerInfos, 3); with CharCheckerInfos[0] do begin CharBegin := 'a'; CharEnd:= 'z'; CheckerIndex := CheckerIndex_LowerAZ; end; with CharCheckerInfos[1] do begin CharBegin := 'A'; CharEnd := 'Z'; CheckerIndex := CheckerIndex_UpperAZ; end; with CharCheckerInfos[2] do begin CharBegin := '0'; CharEnd := '9'; CheckerIndex := CheckerIndex_Digit; end; end; function TRegExpr.CharChecker_Word(ch: REChar): boolean; begin Result := IsWordChar(ch); end; function TRegExpr.CharChecker_NotWord(ch: REChar): boolean; begin Result := not IsWordChar(ch); end; function TRegExpr.CharChecker_Space(ch: REChar): boolean; begin Result := IsSpaceChar(ch); end; function TRegExpr.CharChecker_NotSpace(ch: REChar): boolean; begin Result := not IsSpaceChar(ch); end; function TRegExpr.CharChecker_Digit(ch: REChar): boolean; begin Result := IsDigitChar(ch); end; function TRegExpr.CharChecker_NotDigit(ch: REChar): boolean; begin Result := not IsDigitChar(ch); end; function TRegExpr.CharChecker_VertSep(ch: REChar): boolean; begin Result := IsVertLineSeparator(ch); end; function TRegExpr.CharChecker_NotVertSep(ch: REChar): boolean; begin Result := not IsVertLineSeparator(ch); end; function TRegExpr.CharChecker_HorzSep(ch: REChar): boolean; begin Result := IsHorzSeparator(ch); end; function TRegExpr.CharChecker_NotHorzSep(ch: REChar): boolean; begin Result := not IsHorzSeparator(ch); end; function TRegExpr.CharChecker_LowerAZ(ch: REChar): boolean; begin case ch of 'a' .. 'z': Result := True; else Result := False; end; end; function TRegExpr.CharChecker_UpperAZ(ch: REChar): boolean; begin case ch of 'A' .. 'Z': Result := True; else Result := False; end; end; {$IFDEF RegExpPCodeDump} function TRegExpr.DumpOp(op: TREOp): RegExprString; // printable representation of opcode begin case op of OP_BOL: Result := 'BOL'; OP_EOL: Result := 'EOL'; OP_EOL2: Result := 'EOL2'; OP_BOLML: Result := 'BOLML'; OP_EOLML: Result := 'EOLML'; OP_BOUND: Result := 'BOUND'; OP_NOTBOUND: Result := 'NOTBOUND'; OP_ANY: Result := 'ANY'; OP_ANYML: Result := 'ANYML'; OP_ANYLETTER: Result := 'ANYLETTER'; OP_NOTLETTER: Result := 'NOTLETTER'; OP_ANYDIGIT: Result := 'ANYDIGIT'; OP_NOTDIGIT: Result := 'NOTDIGIT'; OP_ANYSPACE: Result := 'ANYSPACE'; OP_NOTSPACE: Result := 'NOTSPACE'; OP_ANYHORZSEP: Result := 'ANYHORZSEP'; OP_NOTHORZSEP: Result := 'NOTHORZSEP'; OP_ANYVERTSEP: Result := 'ANYVERTSEP'; OP_NOTVERTSEP: Result := 'NOTVERTSEP'; OP_ANYOF: Result := 'ANYOF'; OP_ANYBUT: Result := 'ANYBUT'; OP_ANYOFCI: Result := 'ANYOF/CI'; OP_ANYBUTCI: Result := 'ANYBUT/CI'; OP_BRANCH: Result := 'BRANCH'; OP_EXACTLY: Result := 'EXACTLY'; OP_EXACTLYCI: Result := 'EXACTLY/CI'; OP_NOTHING: Result := 'NOTHING'; OP_COMMENT: Result := 'COMMENT'; OP_BACK: Result := 'BACK'; OP_EEND: Result := 'END'; OP_BSUBEXP: Result := 'BSUBEXP'; OP_BSUBEXPCI: Result := 'BSUBEXP/CI'; OP_OPEN_FIRST .. OP_OPEN_LAST: Result := Format('OPEN[%d]', [Ord(op) - Ord(OP_OPEN)]); OP_CLOSE_FIRST .. OP_CLOSE_LAST: Result := Format('CLOSE[%d]', [Ord(op) - Ord(OP_CLOSE)]); OP_STAR: Result := 'STAR'; OP_PLUS: Result := 'PLUS'; OP_BRACES: Result := 'BRACES'; {$IFDEF ComplexBraces} OP_LOOPENTRY: Result := 'LOOPENTRY'; OP_LOOP: Result := 'LOOP'; OP_LOOPNG: Result := 'LOOPNG'; {$ENDIF} OP_STARNG: Result := 'STARNG'; OP_PLUSNG: Result := 'PLUSNG'; OP_BRACESNG: Result := 'BRACESNG'; OP_STAR_POSS: Result := 'STAR_POSS'; OP_PLUS_POSS: Result := 'PLUS_POSS'; OP_BRACES_POSS: Result := 'BRACES_POSS'; OP_ANYCATEGORY: Result := 'ANYCATEG'; OP_NOTCATEGORY: Result := 'NOTCATEG'; OP_RECUR: Result := 'RECURSION'; OP_SUBCALL_FIRST .. OP_SUBCALL_LAST: Result := Format('SUBCALL[%d]', [Ord(op) - Ord(OP_SUBCALL)]); else Error(reeDumpCorruptedOpcode); end; end; { of function TRegExpr.DumpOp -------------------------------------------------------------- } function TRegExpr.IsCompiled: boolean; begin Result := programm <> nil; end; function PrintableChar(AChar: REChar): RegExprString; {$IFDEF InlineFuncs}inline;{$ENDIF} begin if AChar < ' ' then Result := '#' + IntToStr(Ord(AChar)) else Result := AChar; end; function TRegExpr.DumpCheckerIndex(N: byte): RegExprString; begin Result := '?'; if N = CheckerIndex_Word then Result := '\w' else if N = CheckerIndex_NotWord then Result := '\W' else if N = CheckerIndex_Digit then Result := '\d' else if N = CheckerIndex_NotDigit then Result := '\D' else if N = CheckerIndex_Space then Result := '\s' else if N = CheckerIndex_NotSpace then Result := '\S' else if N = CheckerIndex_HorzSep then Result := '\h' else if N = CheckerIndex_NotHorzSep then Result := '\H' else if N = CheckerIndex_VertSep then Result := '\v' else if N = CheckerIndex_NotVertSep then Result := '\V' else if N = CheckerIndex_LowerAZ then Result := 'az' else if N = CheckerIndex_UpperAZ then Result := 'AZ' else ; end; function TRegExpr.DumpCategoryChars(ch, ch2: REChar; Positive: boolean): RegExprString; const S: array[boolean] of RegExprString = ('P', 'p'); begin Result := '\' + S[Positive] + '{' + ch; if ch2 <> #0 then Result := Result + ch2; Result := Result + '} '; end; function TRegExpr.Dump: RegExprString; // dump a regexp in vaguely comprehensible form var s: PRegExprChar; op: TREOp; // Arbitrary non-END op. next: PRegExprChar; i, NLen: integer; Diff: PtrInt; iByte: byte; ch, ch2: REChar; begin if not IsProgrammOk then Exit; op := OP_EXACTLY; Result := ''; s := regCodeWork; while op <> OP_EEND do begin // While that wasn't END last time... op := s^; Result := Result + Format('%2d: %s', [s - programm, DumpOp(s^)]); // Where, what. next := regNext(s); if next = nil // Next ptr. then Result := Result + ' (0)' else begin if next > s // ###0.948 PWideChar subtraction workaround (see comments in Tail method for details) then Diff := next - s else Diff := -(s - next); Result := Result + Format(' (%d) ', [(s - programm) + Diff]); end; Inc(s, REOpSz + RENextOffSz); if (op = OP_ANYOF) or (op = OP_ANYOFCI) or (op = OP_ANYBUT) or (op = OP_ANYBUTCI) then begin repeat case s^ of OpKind_End: begin Inc(s); Break; end; OpKind_Range: begin Result := Result + 'Rng('; Inc(s); Result := Result + PrintableChar(s^) + '-'; Inc(s); Result := Result + PrintableChar(s^); Result := Result + ') '; Inc(s); end; OpKind_MetaClass: begin Inc(s); Result := Result + DumpCheckerIndex(byte(s^)) + ' '; Inc(s); end; OpKind_Char: begin Inc(s); NLen := PLongInt(s)^; Inc(s, RENumberSz); Result := Result + 'Ch('; for i := 1 to NLen do begin Result := Result + PrintableChar(s^); Inc(s); end; Result := Result + ') '; end; OpKind_CategoryYes: begin Inc(s); ch := s^; Inc(s); ch2 := s^; Result := Result + DumpCategoryChars(ch, ch2, True); Inc(s); end; OpKind_CategoryNo: begin Inc(s); ch := s^; Inc(s); ch2 := s^; Result := Result + DumpCategoryChars(ch, ch2, False); Inc(s); end; else Error(reeDumpCorruptedOpcode); end; until false; end; if (op = OP_EXACTLY) or (op = OP_EXACTLYCI) then begin // Literal string, where present. NLen := PLongInt(s)^; Inc(s, RENumberSz); for i := 1 to NLen do begin Result := Result + PrintableChar(s^); Inc(s); end; end; if (op = OP_BSUBEXP) or (op = OP_BSUBEXPCI) then begin Result := Result + ' \' + IntToStr(Ord(s^)); Inc(s); end; if (op = OP_BRACES) or (op = OP_BRACESNG) or (op = OP_BRACES_POSS) then begin // ###0.941 // show min/max argument of braces operator Result := Result + Format('{%d,%d}', [PREBracesArg(AlignToInt(s))^, PREBracesArg(AlignToInt(s + REBracesArgSz))^]); Inc(s, REBracesArgSz * 2); end; {$IFDEF ComplexBraces} if (op = OP_LOOP) or (op = OP_LOOPNG) then begin // ###0.940 Result := Result + Format(' -> (%d) {%d,%d}', [(s - programm - (REOpSz + RENextOffSz)) + PRENextOff(AlignToPtr(s + 2 * REBracesArgSz))^, PREBracesArg(AlignToInt(s))^, PREBracesArg(AlignToInt(s + REBracesArgSz))^]); Inc(s, 2 * REBracesArgSz + RENextOffSz); end; {$ENDIF} if (op = OP_ANYCATEGORY) or (op = OP_NOTCATEGORY) then begin ch := s^; Inc(s); ch2 := s^; Inc(s); if ch2<>#0 then Result := Result + '{' + ch + ch2 + '}' else Result := Result + '{' + ch + '}'; end; Result := Result + #$d#$a; end; { of while } // Header fields of interest. if regAnchored <> #0 then Result := Result + 'Anchored; '; if regMustString <> '' then Result := Result + 'Must have: "' + regMustString + '"; '; {$IFDEF UseFirstCharSet} // ###0.929 Result := Result + #$d#$a'First charset: '; if FirstCharSet = [] then Result := Result + '' else if FirstCharSet = RegExprAllSet then Result := Result + '' else for iByte := 0 to 255 do if iByte in FirstCharSet then Result := Result + PrintableChar(REChar(iByte)); {$ENDIF} Result := Result + #$d#$a; end; { of function TRegExpr.Dump -------------------------------------------------------------- } {$ENDIF} function TRegExpr.IsFixedLength(var op: TREOp; var ALen: integer): boolean; var s, next: PRegExprChar; N, N2: integer; begin Result := False; ALen := 0; if not IsCompiled then Exit; s := regCodeWork; repeat next := regNext(s); op := s^; Inc(s, REOpSz + RENextOffSz); case op of OP_EEND: begin Result := True; Exit; end; OP_BRANCH: begin op := next^; if op <> OP_EEND then Exit; end; OP_COMMENT, OP_BOUND, OP_NOTBOUND: Continue; OP_ANY, OP_ANYML, OP_ANYDIGIT, OP_NOTDIGIT, OP_ANYLETTER, OP_NOTLETTER, OP_ANYSPACE, OP_NOTSPACE, OP_ANYHORZSEP, OP_NOTHORZSEP, OP_ANYVERTSEP, OP_NOTVERTSEP: begin Inc(ALen); Continue; end; OP_ANYOF, OP_ANYOFCI, OP_ANYBUT, OP_ANYBUTCI: begin Inc(ALen); repeat case s^ of OpKind_End: begin Inc(s); Break; end; OpKind_Range: begin Inc(s); Inc(s); Inc(s); end; OpKind_MetaClass: begin Inc(s); Inc(s); end; OpKind_Char: begin Inc(s); Inc(s, RENumberSz + PLongInt(s)^); end; OpKind_CategoryYes, OpKind_CategoryNo: begin Inc(s); Inc(s); Inc(s); end; end; until False; end; OP_EXACTLY, OP_EXACTLYCI: begin N := PLongInt(s)^; Inc(ALen, N); Inc(s, RENumberSz + N); Continue; end; OP_ANYCATEGORY, OP_NOTCATEGORY: begin Inc(ALen); Inc(s, 2); Continue; end; OP_BRACES, OP_BRACESNG, OP_BRACES_POSS: begin // allow only d{n,n} N := PREBracesArg(AlignToInt(s))^; N2 := PREBracesArg(AlignToInt(s + REBracesArgSz))^; if N <> N2 then Exit; Inc(ALen, N-1); Inc(s, REBracesArgSz * 2); end; else Exit; end; until False; end; {$IFDEF reRealExceptionAddr} {$OPTIMIZATION ON} // ReturnAddr works correctly only if compiler optimization is ON // I placed this method at very end of unit because there are no // way to restore compiler optimization flag ... {$ENDIF} procedure TRegExpr.Error(AErrorID: integer); {$IFDEF reRealExceptionAddr} function ReturnAddr: Pointer; // ###0.938 asm mov eax,[ebp+4] end; {$ENDIF} var e: ERegExpr; Msg: string; begin fLastError := AErrorID; // dummy stub - useless because will raise exception Msg := ErrorMsg(AErrorID); // compilation error ? if AErrorID < reeFirstRuntimeCode then Msg := Msg + ' (pos ' + IntToStr(CompilerErrorPos) + ')'; e := ERegExpr.Create(Msg); e.ErrorCode := AErrorID; e.CompilerErrorPos := CompilerErrorPos; raise e {$IFDEF reRealExceptionAddr} at ReturnAddr {$ENDIF}; end; { of procedure TRegExpr.Error -------------------------------------------------------------- } end. doublecmd-1.1.22/src/uregexpru.pas0000644000175000001440000003134414743153644016135 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- PCRE - Perl Compatible Regular Expressions Copyright (C) 2019-2024 Alexander Koblov (alexx2000@mail.ru) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } unit uRegExprU; {$mode delphi} interface uses Classes, SysUtils, CTypes; type { TRegExprU } TRegExprU = class private FCode: Pointer; FMatch: Pointer; FOptions: UInt32; FInput: PAnsiChar; FVector: pcsize_t; FVectorLength: cint; FExpression: String; FInputLength: UIntPtr; FOvector: array[Byte] of cint; function GetModifierI: Boolean; procedure SetModifierI(AValue: Boolean); procedure SetExpression(const AValue: String); function GetMatchLen(Idx : integer): PtrInt; function GetMatchPos(Idx : integer): PtrInt; public destructor Destroy; override; class function Available: Boolean; class function AvailableNew: Boolean; function Exec(AOffset: UIntPtr): Boolean; procedure SetInputString(AInputString : PAnsiChar; ALength : UIntPtr); function ReplaceAll(const Replacement: AnsiString; out Output: AnsiString): Boolean; public property Expression : String read FExpression write SetExpression; property MatchPos [Idx : integer] : PtrInt read GetMatchPos; property MatchLen [Idx : integer] : PtrInt read GetMatchLen; property ModifierI: Boolean read GetModifierI write SetModifierI; end; function ExecRegExpr(const ARegExpr, AInputStr: String): Boolean; implementation uses DynLibs, DCOSUtils, uDebug; // PCRE 2 const libpcre2 = {$IF DEFINED(MSWINDOWS)} 'libpcre2-8.dll' {$ELSEIF DEFINED(DARWIN)} 'libpcre2-8.dylib' {$ELSEIF DEFINED(UNIX)} 'libpcre2-8.so.0' {$IFEND}; const PCRE2_CONFIG_UNICODE = 9; PCRE2_CASELESS = $00000008; PCRE2_UTF = $00080000; PCRE2_SUBSTITUTE_GLOBAL = $00000100; //PCRE2_SUBSTITUTE_EXTENDED = $00000200; PCRE2_SUBSTITUTE_UNSET_EMPTY = $00000400; PCRE2_SUBSTITUTE_UNKNOWN_UNSET = $00000800; PCRE2_SUBSTITUTE_OVERFLOW_LENGTH = $00001000; PCRE2_ERROR_NOMEMORY = -48; var pcre2_compile: function(pattern: PAnsiChar; length: csize_t; options: cuint32; errorcode: pcint; erroroffset: pcsize_t; ccontext: Pointer): Pointer; cdecl; pcre2_code_free: procedure(code: Pointer); cdecl; pcre2_get_error_message: function(errorcode: cint; buffer: PAnsiChar; bufflen: csize_t): cint; cdecl; pcre2_match: function(code: Pointer; subject: PAnsiChar; length: csize_t; startoffset: csize_t; options: cuint32; match_data: Pointer; mcontext: Pointer): cint; cdecl; pcre2_get_ovector_pointer: function(match_data: Pointer): pcsize_t; cdecl; pcre2_match_data_create_from_pattern: function(code: Pointer; gcontext: Pointer): Pointer; cdecl; pcre2_match_data_free: procedure(match_data: Pointer); cdecl; pcre2_config: function(what: cuint32; where: pointer): cint; cdecl; pcre2_substitute: function(code: Pointer; subject: PAnsiChar; length: csize_t; startoffset: csize_t; options: cuint32; match_data: Pointer; mcontext: Pointer; replacement: PAnsiChar; rlength: csize_t; outputbuffer: PAnsiChar; var outlength: csize_t): cint; cdecl; // PCRE 1 const libpcre = {$IF DEFINED(MSWINDOWS)} 'libpcre.dll' {$ELSEIF DEFINED(DARWIN)} 'libpcre.dylib' {$ELSEIF DEFINED(UNIX)} 'libpcre.so.1' {$IFEND}; const PCRE_CONFIG_UTF8 = 0; PCRE_CASELESS = $00000001; PCRE_UTF8 = $00000800; var pcre_compile: function(pattern: PAnsiChar; options: cint; errptr: PPAnsiChar; erroffset: pcint; tableptr: PAnsiChar): pointer; cdecl; pcre_exec: function(code: pointer; extra: Pointer; subject: PAnsiChar; length: cint; startoffset: cint; options: cint; ovector: pcint; ovecsize: cint): cint; cdecl; pcre_free: procedure(code: pointer); cdecl; pcre_study: function(code: Pointer; options: cint; errptr: PPAnsiChar): Pointer; cdecl; pcre_free_study: procedure(extra: Pointer); cdecl; pcre_config: function(what: cint; where: pointer): cint; cdecl; var pcre_new: Boolean; hLib: TLibHandle = NilHandle; { TRegExprU } procedure TRegExprU.SetExpression(const AValue: String); var Message: String; error: PAnsiChar; errornumber: cint; erroroffset: cint; len: cint; begin FExpression:= AValue; if pcre_new then begin FOptions := FOptions or PCRE2_UTF; FCode := pcre2_compile(PAnsiChar(AValue), Length(AValue), FOptions, @errornumber, @erroroffset, nil); if Assigned(FCode) then FMatch := pcre2_match_data_create_from_pattern(FCode, nil) else begin SetLength(Message, MAX_PATH + 1); len := pcre2_get_error_message(errornumber, PAnsiChar(Message), MAX_PATH); if len < 0 then len := Length(PAnsiChar(Message)); // PCRE2_ERROR_NOMEMORY SetLength(Message, len); raise Exception.Create(Message); end; end else begin FOptions := FOptions or PCRE_UTF8; FCode := pcre_compile(PAnsiChar(AValue), cint(FOptions), @error, @erroroffset, nil); if Assigned(FCode) then FMatch:= pcre_study(FCode, 0, @error) else raise Exception.Create(StrPas(error)); end; end; function TRegExprU.GetMatchLen(Idx : integer): PtrInt; begin if (Idx < FVectorLength) then begin if pcre_new then Result := UIntPtr(FVector[Idx * 2 + 1]) - UIntPtr(FVector[Idx * 2]) else Result := UIntPtr(FOvector[Idx * 2 + 1]) - UIntPtr(FOvector[Idx * 2]); end else Result:= 0; end; function TRegExprU.GetMatchPos(Idx : integer): PtrInt; begin if (Idx < FVectorLength) then begin if pcre_new then Result := UIntPtr(FVector[Idx * 2]) + 1 else Result := UIntPtr(FOvector[Idx * 2]) + 1; end else Result:= 0; end; function TRegExprU.GetModifierI: Boolean; begin if pcre_new then begin Result:= (FOptions and PCRE2_CASELESS) <> 0; end else begin Result:= (FOptions and PCRE_CASELESS) <> 0; end; end; procedure TRegExprU.SetModifierI(AValue: Boolean); begin if GetModifierI <> AValue then begin if pcre_new then begin if AValue then FOptions:= FOptions or PCRE2_CASELESS else begin FOptions:= FOptions and (not PCRE2_CASELESS); end; end else begin if AValue then FOptions:= FOptions or PCRE_CASELESS else begin FOptions:= FOptions and (not PCRE_CASELESS); end; end; SetExpression(FExpression); end; end; destructor TRegExprU.Destroy; begin if Assigned(FCode) then begin if pcre_new then pcre2_code_free(FCode) else pcre_free(FCode); end; if Assigned(FMatch) then begin if pcre_new then pcre2_match_data_free(FMatch) else pcre_free_study(FMatch); end; inherited Destroy; end; class function TRegExprU.Available: Boolean; begin Result:= (hLib <> NilHandle); end; class function TRegExprU.AvailableNew: Boolean; begin Result:= (hLib <> NilHandle) and pcre_new; end; function TRegExprU.Exec(AOffset: UIntPtr): Boolean; begin Dec(AOffset); if pcre_new then begin FVectorLength:= pcre2_match(FCode, FInput, FInputLength, AOffset, 0, FMatch, nil); Result:= (FVectorLength >= 0); if Result then FVector := pcre2_get_ovector_pointer(FMatch); end else begin FVectorLength := pcre_exec(FCode, FMatch, FInput, FInputLength, AOffset, 0, FOvector, SizeOf(FOvector)); // The output vector wasn't big enough if (FVectorLength = 0) then FVectorLength:= SizeOf(FOvector) div 3; Result:= (FVectorLength >= 0); end; end; procedure TRegExprU.SetInputString(AInputString: PAnsiChar; ALength: UIntPtr); begin FInput:= AInputString; FInputLength:= ALength; end; function TRegExprU.ReplaceAll(const Replacement: AnsiString; out Output: AnsiString): Boolean; var outlength: csize_t; options: cuint32; res: cint; begin if not pcre_new then begin Output := ''; Exit(False); end; if FInputLength = 0 then begin Output := ''; Exit(True); end; options := PCRE2_SUBSTITUTE_OVERFLOW_LENGTH or PCRE2_SUBSTITUTE_UNKNOWN_UNSET or PCRE2_SUBSTITUTE_UNSET_EMPTY; //options := options or PCRE2_SUBSTITUTE_EXTENDED; options := options or PCRE2_SUBSTITUTE_GLOBAL; outlength := FInputLength * 2 + 1; // + space for #0 if outlength < 2048 then outlength := 2048; SetLength(Output, outlength - 1); res := pcre2_substitute(FCode, FInput, FInputLength, 0, options, FMatch, nil, PAnsiChar(Replacement), Length(Replacement), PAnsiChar(Output), outlength); if res >= 0 then // if res = 0 then nothing found SetLength(Output, outlength) else if res = PCRE2_ERROR_NOMEMORY then begin SetLength(Output, outlength - 1); res := pcre2_substitute(FCode, FInput, FInputLength, 0, options, FMatch, nil, PAnsiChar(Replacement), Length(Replacement), PAnsiChar(Output), outlength); end; Result := res >= 0; end; function ExecRegExpr(const ARegExpr, AInputStr: String): Boolean; var r: TRegExprU; begin r := TRegExprU.Create; try r.Expression := ARegExpr; r.SetInputString(PChar(AInputStr), Length(AInputStr)); Result := r.Exec(1); finally r.Free; end; end; procedure Initialize; var Where: IntPtr; begin hLib:= LoadLibrary(libpcre2); if (hLib <> NilHandle) then begin pcre_new:= True; try @pcre2_config:= SafeGetProcAddress(hLib, 'pcre2_config_8'); if (pcre2_config(PCRE2_CONFIG_UNICODE, @Where) <> 0) or (Where = 0) then raise Exception.Create('pcre2_config(PCRE2_CONFIG_UNICODE)'); @pcre2_compile:= SafeGetProcAddress(hLib, 'pcre2_compile_8'); @pcre2_code_free:= SafeGetProcAddress(hLib, 'pcre2_code_free_8'); @pcre2_get_error_message:= SafeGetProcAddress(hLib, 'pcre2_get_error_message_8'); @pcre2_match:= SafeGetProcAddress(hLib, 'pcre2_match_8'); @pcre2_get_ovector_pointer:= SafeGetProcAddress(hLib, 'pcre2_get_ovector_pointer_8'); @pcre2_match_data_create_from_pattern:= SafeGetProcAddress(hLib, 'pcre2_match_data_create_from_pattern_8'); @pcre2_match_data_free:= SafeGetProcAddress(hLib, 'pcre2_match_data_free_8'); @pcre2_substitute:= SafeGetProcAddress(hLib, 'pcre2_substitute_8'); except on E: Exception do begin FreeLibrary(hLib); hLib:= NilHandle; DCDebug(E.Message); end; end; end else begin hLib:= LoadLibrary(libpcre); {$IF DEFINED(LINUX)} // Debian use another library name if (hLib = NilHandle) then hLib:= LoadLibrary('libpcre.so.3'); {$ENDIF} if (hLib <> NilHandle) then begin pcre_new:= False; try @pcre_config:= SafeGetProcAddress(hLib, 'pcre_config'); if (pcre_config(PCRE_CONFIG_UTF8, @Where) <> 0) or (Where = 0) then raise Exception.Create('pcre_config(PCRE_CONFIG_UTF8)'); @pcre_compile:= SafeGetProcAddress(hLib, 'pcre_compile'); @pcre_exec:= SafeGetProcAddress(hLib, 'pcre_exec'); @pcre_free:= PPointer(SafeGetProcAddress(hLib, 'pcre_free'))^; @pcre_study:= SafeGetProcAddress(hLib, 'pcre_study'); @pcre_free_study:= SafeGetProcAddress(hLib, 'pcre_free_study'); except on E: Exception do begin FreeLibrary(hLib); hLib:= NilHandle; DCDebug(E.Message); end; end; end; end; end; initialization Initialize; end. doublecmd-1.1.22/src/uregexprw.pas0000644000175000001440000000023214743153644016127 0ustar alexxusers{$define unicode} {$macro on} {$define FastUnicodeData} {$define uRegExprA := uRegExprW} {$define TRegExpr := TRegExprW} {$include uregexpra.pas} doublecmd-1.1.22/src/uresample.pas0000644000175000001440000004776514743153644016122 0ustar alexxusers// ----------------------------------------------------------------------------- // Project: bitmap resampler // Module: resample // Description: Interpolated Bitmap Resampling using filters. // Version: 01.03 // Release: 1 // Date: 19-DEC-2009 // Target: Free Pascal 2.2.4, Lazarus 0.9.29 // Author(s): anme: Anders Melander, anders@melander.dk // Alexx2000: Alexander Koblov, alexx2000@mail.ru // Copyright (c) 1997,98 by Anders Melander // Copyright (c) 2009 by Alexander Koblov // Formatting: 2 space indent, 8 space tabs, 80 columns. // ----------------------------------------------------------------------------- // This software is copyrighted as noted above. It may be freely copied, // modified, and redistributed, provided that the copyright notice(s) is // preserved on all copies. // // There is no warranty or other guarantee of fitness for this software, // it is provided solely "as is". Bug reports or fixes may be sent // to the author, who may or may not act on them as he desires. // // You may not include this software in a program or other software product // without supplying the source, or without informing the end-user that the // source is available for no extra charge. // // If you modify this software, you should include a notice in the "Revision // history" section giving the name of the person performing the modification, // the date of modification, and the reason for such modification. // ----------------------------------------------------------------------------- // Here's some additional copyrights for you: // // From filter.c: // The authors and the publisher hold no copyright restrictions // on any of these files; this source code is public domain, and // is freely available to the entire computer graphics community // for study, use, and modification. We do request that the // comment at the top of each file, identifying the original // author and its original publication in the book Graphics // Gems, be retained in all programs that use these files. // // ----------------------------------------------------------------------------- // Revision history: // // 0100 110997 anme - Adapted from fzoom v0.20 by Dale Schumacher. // // 0101 110198 anme - Added Lanczos3 and Mitchell filters. // - Fixed range bug. // Min value was not checked on conversion from Single to // byte. // - Numerous optimizations. // - Added TImage stretch on form resize. // - Added support for Delphi 2 via TCanvas.Pixels. // - Renamed module from stretch to resample. // - Moved demo code to separate module. // // 0102 150398 anme - Fixed a problem that caused all pixels to be shifted // 1/2 pixel down and to the right (in source // coordinates). Thanks to David Ullrich for the // solution. // 0103 191209 Alexx2000 // - Ported to FreePascal/Lazarus // - Added alpha channel support // ----------------------------------------------------------------------------- // Credits: // The algorithms and methods used in this library are based on the article // "General Filtered Image Rescaling" by Dale Schumacher which appeared in the // book Graphics Gems III, published by Academic Press, Inc. // // The edge offset problem was fixed by: // * David Ullrich // ----------------------------------------------------------------------------- // To do (in rough order of priority): // * Implement Dale Schumacher's "Optimized Bitmap Scaling Routines". // * Fix BoxFilter. // * Optimize to use integer math instead of floating point where possible. // ----------------------------------------------------------------------------- unit uReSample; interface {$mode delphi}{$R-} {$IF (FPC_VERSION > 2) or ((FPC_VERSION = 2) and (FPC_RELEASE >= 5))} {$POINTERMATH ON} {$ENDIF} uses SysUtils, Classes, Graphics; type // Type of a filter for use with Stretch() TFilterProc = function(Value: Single): Single; // Sample filters for use with Stretch() function SplineFilter(Value: Single): Single; function BellFilter(Value: Single): Single; function TriangleFilter(Value: Single): Single; function BoxFilter(Value: Single): Single; function HermiteFilter(Value: Single): Single; function Lanczos3Filter(Value: Single): Single; function MitchellFilter(Value: Single): Single; // Interpolator // Src: Source bitmap // Dst: Destination bitmap // filter: Weight calculation filter // fwidth: Relative sample radius procedure Stretch(Src, Dst: TRasterImage; filter: TFilterProc; fwidth: single); // ----------------------------------------------------------------------------- // // List of Filters // // ----------------------------------------------------------------------------- const ResampleFilters: array[0..6] of record Name: string; // Filter name Filter: TFilterProc;// Filter implementation Width: Single; // Suggested sampling width/radius end = ( (Name: 'Box'; Filter: BoxFilter; Width: 0.5), (Name: 'Triangle'; Filter: TriangleFilter; Width: 1.0), (Name: 'Hermite'; Filter: HermiteFilter; Width: 1.0), (Name: 'Bell'; Filter: BellFilter; Width: 1.5), (Name: 'B-Spline'; Filter: SplineFilter; Width: 2.0), (Name: 'Lanczos3'; Filter: Lanczos3Filter; Width: 3.0), (Name: 'Mitchell'; Filter: MitchellFilter; Width: 2.0) ); implementation uses Math, IntfGraphics, GraphType, FPImage; // ----------------------------------------------------------------------------- // // Filter functions // // ----------------------------------------------------------------------------- // Hermite filter function HermiteFilter(Value: Single): Single; begin // f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 if (Value < 0.0) then Value := -Value; if (Value < 1.0) then Result := (2.0 * Value - 3.0) * Sqr(Value) + 1.0 else Result := 0.0; end; // Box filter // a.k.a. "Nearest Neighbour" filter // anme: I have not been able to get acceptable // results with this filter for subsampling. function BoxFilter(Value: Single): Single; begin if (Value > -0.5) and (Value <= 0.5) then Result := 1.0 else Result := 0.0; end; // Triangle filter // a.k.a. "Linear" or "Bilinear" filter function TriangleFilter(Value: Single): Single; begin if (Value < 0.0) then Value := -Value; if (Value < 1.0) then Result := 1.0 - Value else Result := 0.0; end; // Bell filter function BellFilter(Value: Single): Single; begin if (Value < 0.0) then Value := -Value; if (Value < 0.5) then Result := 0.75 - Sqr(Value) else if (Value < 1.5) then begin Value := Value - 1.5; Result := 0.5 * Sqr(Value); end else Result := 0.0; end; // B-spline filter function SplineFilter(Value: Single): Single; var tt : single; begin if (Value < 0.0) then Value := -Value; if (Value < 1.0) then begin tt := Sqr(Value); Result := 0.5*tt*Value - tt + 2.0 / 3.0; end else if (Value < 2.0) then begin Value := 2.0 - Value; Result := 1.0/6.0 * Sqr(Value) * Value; end else Result := 0.0; end; // Lanczos3 filter function Lanczos3Filter(Value: Single): Single; function SinC(Value: Single): Single; begin if (Value <> 0.0) then begin Value := Value * Pi; Result := sin(Value) / Value end else Result := 1.0; end; begin if (Value < 0.0) then Value := -Value; if (Value < 3.0) then Result := SinC(Value) * SinC(Value / 3.0) else Result := 0.0; end; function MitchellFilter(Value: Single): Single; const B = (1.0 / 3.0); C = (1.0 / 3.0); var tt : single; begin if (Value < 0.0) then Value := -Value; tt := Sqr(Value); if (Value < 1.0) then begin Value := (((12.0 - 9.0 * B - 6.0 * C) * (Value * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2 * B)); Result := Value / 6.0; end else if (Value < 2.0) then begin Value := (((-1.0 * B - 6.0 * C) * (Value * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * Value) + (8.0 * B + 24 * C)); Result := Value / 6.0; end else Result := 0.0; end; // ----------------------------------------------------------------------------- // // Interpolator // // ----------------------------------------------------------------------------- type // Contributor for a pixel TContributor = record pixel: integer; // Source pixel weight: single; // Pixel weight end; TContributorList = array[0..0] of TContributor; PContributorList = ^TContributorList; // List of source pixels contributing to a destination pixel TCList = record n : integer; p : PContributorList; end; TCListList = array[0..0] of TCList; PCListList = ^TCListList; TRGBA = packed record r, g, b, a : single; end; // Physical bitmap pixel TColorRGBA = packed record r, g, b, a : BYTE; end; PColorRGBA = ^TColorRGBA; // Physical bitmap scanline (row) TRGBAList = packed array[0..0] of TColorRGBA; PRGBAList = ^TRGBAList; function CreateAlphaFromMask(Bitmap: TRasterImage): TLazIntfImage; var SrcIntfImage: TLazIntfImage; x, y, xStop, yStop: Integer; Color: TFPColor; begin SrcIntfImage := TLazIntfImage.Create(Bitmap.RawImage, False); with SrcIntfImage do begin if MaskData = nil then Exit(SrcIntfImage); Result := TLazIntfImage.Create(Width, Height, [riqfRGB, riqfAlpha]); Result.CreateData; xStop := Width - 1; yStop := Height - 1; end; for x:= 0 to xStop do for y:= 0 to yStop do begin Color := SrcIntfImage.Colors[x, y]; if SrcIntfImage.Masked[x, y] then Color.Alpha := Low(Color.Alpha) else Color.Alpha := High(Color.Alpha); Result.Colors[x, y] := Color; end; SrcIntfImage.Free; end; procedure Stretch(Src, Dst: TRasterImage; filter: TFilterProc; fwidth: single); var xscale, yscale : single; // Zoom scale factors i, j, k : integer; // Loop variables center : single; // Filter calculation variables width, fscale, weight : single; // Filter calculation variables left, right : integer; // Filter calculation variables n : integer; // Pixel number Work : PRGBAList; contrib : PCListList; rgba : TRGBA; color : TColorRGBA; SourceLine , DestLine : PRGBAList; SrcDelta : integer; SrcIntfImage, DstIntfImage : TLazIntfImage; SrcWidth , SrcHeight , DstWidth , DstHeight : integer; ARawImage : TRawImage; function Color2RGBA(Color: TFPColor): TColorRGBA; inline; begin Result.r := Color.Red shr 8; Result.g := Color.Green shr 8; Result.b := Color.Blue shr 8; Result.a := Color.Alpha shr 8; end; function RGBA2Color(Color: TColorRGBA): TFPColor; inline; begin Result.Red := Color.r shl 8; Result.Green := Color.g shl 8; Result.Blue := Color.b shl 8; Result.Alpha := Color.a shl 8; end; begin DstWidth := Dst.Width; DstHeight := Dst.Height; SrcWidth := Src.Width; SrcHeight := Src.Height; if (SrcWidth < 1) or (SrcHeight < 1) then raise Exception.Create('Source bitmap too small'); // Create intermediate buffer to hold horizontal zoom Work := GetMem(DstWidth * SrcHeight * SizeOf(TColorRGBA)); try // xscale := DstWidth / SrcWidth; // yscale := DstHeight / SrcHeight; // Improvement suggested by David Ullrich: if (SrcWidth = 1) then xscale:= DstWidth / SrcWidth else xscale:= (DstWidth - 1) / (SrcWidth - 1); if (SrcHeight = 1) then yscale:= DstHeight / SrcHeight else yscale:= (DstHeight - 1) / (SrcHeight - 1); {++++++++++++++++++++} if Src.RawImage.Description.AlphaPrec = 0 then // if bitmap has not alpha channel SrcIntfImage := CreateAlphaFromMask(Src) else begin SrcIntfImage := TLazIntfImage.Create(Src.RawImage, False); end; DstIntfImage := TLazIntfImage.Create(DstWidth, DstHeight, [riqfRGB, riqfAlpha]); DstIntfImage.CreateData; {++++++++++++++++++++} // -------------------------------------------- // Pre-calculate filter contributions for a row // ----------------------------------------------- GetMem(contrib, DstWidth* sizeof(TCList)); // Horizontal sub-sampling // Scales from bigger to smaller width if (xscale < 1.0) then begin width := fwidth / xscale; fscale := 1.0 / xscale; for i := 0 to DstWidth-1 do begin contrib^[i].n := 0; GetMem(contrib^[i].p, trunc(width * 2.0 + 1) * sizeof(TContributor)); center := i / xscale; // Original code: // left := ceil(center - width); // right := floor(center + width); left := floor(center - width); right := ceil(center + width); for j := left to right do begin weight := filter((center - j) / fscale) / fscale; if (weight = 0.0) then continue; if (j < 0) then n := -j else if (j >= SrcWidth) then n := SrcWidth - j + SrcWidth - 1 else n := j; k := contrib^[i].n; contrib^[i].n := contrib^[i].n + 1; contrib^[i].p^[k].pixel := n; contrib^[i].p^[k].weight := weight; end; end; end else // Horizontal super-sampling // Scales from smaller to bigger width begin for i := 0 to DstWidth-1 do begin contrib^[i].n := 0; GetMem(contrib^[i].p, trunc(fwidth * 2.0 + 1) * sizeof(TContributor)); center := i / xscale; // Original code: // left := ceil(center - fwidth); // right := floor(center + fwidth); left := floor(center - fwidth); right := ceil(center + fwidth); for j := left to right do begin weight := filter(center - j); if (weight = 0.0) then continue; if (j < 0) then n := -j else if (j >= SrcWidth) then n := SrcWidth - j + SrcWidth - 1 else n := j; k := contrib^[i].n; contrib^[i].n := contrib^[i].n + 1; contrib^[i].p^[k].pixel := n; contrib^[i].p^[k].weight := weight; end; end; end; // ---------------------------------------------------- // Apply filter to sample horizontally from Src to Work // ---------------------------------------------------- for k := 0 to SrcHeight-1 do begin {++++++++++++++++++++} DestLine := Work + k * DstWidth; {++++++++++++++++++++} for i := 0 to DstWidth-1 do begin rgba.r := 0.0; rgba.g := 0.0; rgba.b := 0.0; rgba.a := 0.0; for j := 0 to contrib^[i].n-1 do begin {++++++++++++++++++++} color := Color2RGBA(SrcIntfImage.Colors[contrib^[i].p^[j].pixel, k]); {++++++++++++++++++++} weight := contrib^[i].p^[j].weight; if (weight = 0.0) then continue; rgba.r := rgba.r + color.r * weight; rgba.g := rgba.g + color.g * weight; rgba.b := rgba.b + color.b * weight; rgba.a := rgba.a + color.a * weight; end; if (rgba.r > 255.0) then color.r := 255 else if (rgba.r < 0.0) then color.r := 0 else color.r := round(rgba.r); if (rgba.g > 255.0) then color.g := 255 else if (rgba.g < 0.0) then color.g := 0 else color.g := round(rgba.g); if (rgba.b > 255.0) then color.b := 255 else if (rgba.b < 0.0) then color.b := 0 else color.b := round(rgba.b); if (rgba.a > 255.0) then color.a := 255 else if (rgba.a < 0.0) then color.a := 0 else color.a := round(rgba.a); {++++++++++++++++++++} // Set new pixel value DestLine^[i] := color; {++++++++++++++++++++} end; end; // Free the memory allocated for horizontal filter weights for i := 0 to DstWidth-1 do FreeMem(contrib^[i].p); FreeMem(contrib); // ----------------------------------------------- // Pre-calculate filter contributions for a column // ----------------------------------------------- GetMem(contrib, DstHeight* sizeof(TCList)); // Vertical sub-sampling // Scales from bigger to smaller height if (yscale < 1.0) then begin width := fwidth / yscale; fscale := 1.0 / yscale; for i := 0 to DstHeight-1 do begin contrib^[i].n := 0; GetMem(contrib^[i].p, trunc(width * 2.0 + 1) * sizeof(TContributor)); center := i / yscale; // Original code: // left := ceil(center - width); // right := floor(center + width); left := floor(center - width); right := ceil(center + width); for j := left to right do begin weight := filter((center - j) / fscale) / fscale; if (weight = 0.0) then continue; if (j < 0) then n := -j else if (j >= SrcHeight) then n := SrcHeight - j + SrcHeight - 1 else n := j; k := contrib^[i].n; contrib^[i].n := contrib^[i].n + 1; contrib^[i].p^[k].pixel := n; contrib^[i].p^[k].weight := weight; end; end end else // Vertical super-sampling // Scales from smaller to bigger height begin for i := 0 to DstHeight-1 do begin contrib^[i].n := 0; GetMem(contrib^[i].p, trunc(fwidth * 2.0 + 1) * sizeof(TContributor)); center := i / yscale; // Original code: // left := ceil(center - fwidth); // right := floor(center + fwidth); left := floor(center - fwidth); right := ceil(center + fwidth); for j := left to right do begin weight := filter(center - j); if (weight = 0.0) then continue; if (j < 0) then n := -j else if (j >= SrcHeight) then n := SrcHeight - j + SrcHeight - 1 else n := j; k := contrib^[i].n; contrib^[i].n := contrib^[i].n + 1; contrib^[i].p^[k].pixel := n; contrib^[i].p^[k].weight := weight; end; end; end; // -------------------------------------------------- // Apply filter to sample vertically from Work to Dst // -------------------------------------------------- {++++++++++++++++++++} SourceLine := Work; SrcDelta := DstWidth; {++++++++++++++++++++} for k := 0 to DstWidth-1 do begin for i := 0 to DstHeight-1 do begin rgba.r := 0; rgba.g := 0; rgba.b := 0; rgba.a := 0; // weight := 0.0; for j := 0 to contrib^[i].n-1 do begin {++++++++++++++++++++} color := PColorRGBA(SourceLine+contrib^[i].p^[j].pixel*SrcDelta)^; {++++++++++++++++++++} weight := contrib^[i].p^[j].weight; if (weight = 0.0) then continue; rgba.r := rgba.r + color.r * weight; rgba.g := rgba.g + color.g * weight; rgba.b := rgba.b + color.b * weight; rgba.a := rgba.a + color.a * weight; end; if (rgba.r > 255.0) then color.r := 255 else if (rgba.r < 0.0) then color.r := 0 else color.r := round(rgba.r); if (rgba.g > 255.0) then color.g := 255 else if (rgba.g < 0.0) then color.g := 0 else color.g := round(rgba.g); if (rgba.b > 255.0) then color.b := 255 else if (rgba.b < 0.0) then color.b := 0 else color.b := round(rgba.b); if (rgba.a > 255.0) then color.a := 255 else if (rgba.a < 0.0) then color.a := 0 else color.a := round(rgba.a); {++++++++++++++++++++} DstIntfImage.Colors[k, i]:= RGBA2Color(color); {++++++++++++++++++++} end; {++++++++++++++++++++} Inc(SourceLine); {++++++++++++++++++++} end; // Free the memory allocated for vertical filter weights for i := 0 to DstHeight-1 do FreeMem(contrib^[i].p); FreeMem(contrib); DstIntfImage.GetRawImage(ARawImage, True); Dst.LoadFromRawImage(ARawImage, True); finally FreeMem(Work); DstIntfImage.Free; SrcIntfImage.Free; end; end; end. doublecmd-1.1.22/src/usearchcontent.pas0000644000175000001440000003133014743153644017127 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Content plugin search control Copyright (C) 2014-2023 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uSearchContent; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, StdCtrls, ExtCtrls, LCLType, uFindFiles; type { TPluginPanel } TPluginPanel = class(TPanel) private FComboPlugin, FComboField, // <---The text of this combo is filled from localized string. The "objects" pointed from the its list are "TWdxField" type. FComboOperator, FComboValue, FComboUnit: TComboBox; private function GetCompare: TPluginOperator; function GetField: String; function GetFieldType: Integer; function GetPlugin: String; function GetUnitName: String; function GetValue: Variant; procedure PluginChange(Sender: TObject); procedure FieldChange(Sender: TObject); procedure SetCompare(AValue: TPluginOperator); procedure SetField(AValue: String); procedure SetPlugin(AValue: String); procedure SetUnitName(AValue: String); procedure SetValue(AValue: Variant); procedure SetComboBox(ComboBox: TComboBox; const Value, Error: String); procedure ComboValueKeyPress(Sender: TObject; var Key: Char); procedure ComboValueUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; public property Plugin: String read GetPlugin write SetPlugin; property Field: String read GetField write SetField; property UnitName: String read GetUnitName write SetUnitName; property FieldType: Integer read GetFieldType; property Compare: TPluginOperator read GetCompare write SetCompare; property Value: Variant read GetValue write SetValue; end; implementation uses uLng, Variants, WdxPlugin, uGlobs, uWDXModule, Graphics, uShowMsg; { TPluginPanel } function TPluginPanel.GetCompare: TPluginOperator; begin Result:= TPluginOperator(PtrInt(FComboOperator.Items.Objects[FComboOperator.ItemIndex])); end; function TPluginPanel.GetField: String; begin Result := TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]).FName; end; function TPluginPanel.GetFieldType: Integer; begin Result := TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]).FType end; function TPluginPanel.GetPlugin: String; begin Result:= FComboPlugin.Text; end; function TPluginPanel.GetUnitName: String; begin if (FComboField.ItemIndex < 0) or (FComboUnit.ItemIndex < 0) then Result:= FComboUnit.Text else begin Result:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]).FUnits[FComboUnit.ItemIndex]; end; end; function TPluginPanel.GetValue: Variant; var WdxField: TWdxField; begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); if (WdxField.FType <> ft_multiplechoice) then Result:= StrToVar(FComboValue.Text, WdxField.FType) else begin Result:= StrToVar(WdxField.FUnits[FComboValue.ItemIndex], WdxField.FType) end; end; // When a plugin is selected from the plugin combo, we populate the others in cascade. // In the field combo, each element references a corresding "TWdxField" object. // Since this combo is for the user we populate text of it from localized strings. procedure TPluginPanel.PluginChange(Sender: TObject); var I: Integer; Module: TWDXModule; begin if FComboPlugin.ItemIndex < 0 then Exit; FComboField.Clear; Module:= gWdxPlugins.GetWdxModule(FComboPlugin.Text); if Assigned(Module) then for I:= 0 to Module.FieldList.Count - 1 do FComboField.Items.AddObject(TWdxField(Module.FieldList.Objects[I]).LName, TObject(Module.FieldList.Objects[I])); if FComboField.Items.Count > 0 then begin FComboField.ItemIndex:= 0; FieldChange(FComboField); end; end; procedure TPluginPanel.FieldChange(Sender: TObject); var WdxField: TWdxField; begin FComboUnit.Items.Clear; FComboValue.Items.Clear; FComboOperator.Items.Clear; FComboValue.Text:= EmptyStr; if (FComboField.ItemIndex < 0) then Exit; WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); if (WdxField.FType <> FT_MULTIPLECHOICE) then begin FComboUnit.Items.AddStrings(WdxField.LUnits); end; FComboUnit.Enabled := (WdxField.FType <> FT_MULTIPLECHOICE) and (FComboUnit.Items.Count > 0); if FComboUnit.Enabled then FComboUnit.ItemIndex:= 0; case WdxField.FType of FT_NUMERIC_32, FT_NUMERIC_64, FT_NUMERIC_FLOATING, FT_DATE, FT_TIME, FT_DATETIME: begin FComboValue.Style:= csDropDown; FComboOperator.Items.AddObject('=', TObject(PtrInt(poEqualCaseSensitive))); FComboOperator.Items.AddObject('!=', TObject(PtrInt(poNotEqualCaseSensitive))); FComboOperator.Items.AddObject('>', TObject(PtrInt(poMore))); FComboOperator.Items.AddObject('<', TObject(PtrInt(poLess))); FComboOperator.Items.AddObject('>=', TObject(PtrInt(poMoreEqual))); FComboOperator.Items.AddObject('<=', TObject(PtrInt(poLessEqual))); end; FT_BOOLEAN: begin FComboValue.Items.Add(rsSimpleWordTrue); FComboValue.Items.Add(rsSimpleWordFalse); FComboValue.ItemIndex:= 0; FComboValue.Style:= csDropDownList; FComboOperator.Items.AddObject('=', TObject(PtrInt(poEqualCaseSensitive))); end; FT_MULTIPLECHOICE: begin begin FComboValue.Style:= csDropDownList; FComboOperator.Items.AddObject('=', TObject(PtrInt(poEqualCaseSensitive))); FComboOperator.Items.AddObject('!=', TObject(PtrInt(poNotEqualCaseSensitive))); FComboValue.Items.AddStrings(WdxField.LUnits); if FComboValue.Items.Count > 0 then FComboValue.ItemIndex:= 0; end; end; FT_STRING, FT_STRINGW: begin FComboValue.Style:= csDropDown; FComboOperator.Items.AddObject(rsPluginSearchEqualNotCase, TObject(PtrInt(poEqualCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotEqualNotCase, TObject(PtrInt(poNotEqualCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchEqualCaseSensitive, TObject(PtrInt(poEqualCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotEquaCaseSensitive, TObject(PtrInt(poNotEqualCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchContainsNotCase, TObject(PtrInt(poContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsNotCase, TObject(PtrInt(poNotContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchContainsCaseSenstive, TObject(PtrInt(poContainsCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsCaseSenstive, TObject(PtrInt(poNotContainsCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchRegExpr, TObject(PtrInt(poRegExpr))); FComboOperator.Items.AddObject(rsPluginSearchNotRegExpr, TObject(PtrInt(poNotRegExpr))); end; FT_FULLTEXT, FT_FULLTEXTW: begin FComboValue.Style:= csDropDown; FComboOperator.Items.AddObject(rsPluginSearchContainsNotCase, TObject(PtrInt(poContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsNotCase, TObject(PtrInt(poNotContainsCaseInsensitive))); FComboOperator.Items.AddObject(rsPluginSearchContainsCaseSenstive, TObject(PtrInt(poContainsCaseSensitive))); FComboOperator.Items.AddObject(rsPluginSearchNotContainsCaseSenstive, TObject(PtrInt(poNotContainsCaseSensitive))); end; end; if FComboOperator.Items.Count > 0 then FComboOperator.ItemIndex:= 0; end; procedure TPluginPanel.SetCompare(AValue: TPluginOperator); var Index: Integer; begin Index:= FComboOperator.Items.IndexOfObject(TObject(PtrInt(AValue))); if Index >= 0 then FComboOperator.ItemIndex:= Index; end; // The "AValue" parameter received here is not localized. // We can't search it in combo box directly so we go by index. procedure TPluginPanel.SetField(AValue: String); var Module: TWDXModule; begin Module := gWdxPlugins.GetWdxModule(FComboPlugin.Text); if Module = nil then exit; FComboField.ItemIndex := Module.GetFieldIndex(AValue); if FComboField.ItemIndex <> -1 then begin if Assigned(FComboField.OnChange) then FComboField.OnChange(FComboField); end else begin msgError(rsPluginSearchFieldNotFound); end; end; procedure TPluginPanel.SetPlugin(AValue: String); begin SetComboBox(FComboPlugin, AValue, Format(rsPluginSearchPluginNotFound, [AValue])); end; procedure TPluginPanel.SetUnitName(AValue: String); var Index: Integer; WdxField: TWdxField; begin if FComboUnit.Enabled then begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); Index := WdxField.GetUnitIndex(AValue); if Index >= 0 then AValue:= WdxField.LUnits[Index]; SetComboBox(FComboUnit, AValue, Format(rsPluginSearchUnitNotFoundForField, [AValue, Self.Field])); end; end; procedure TPluginPanel.SetValue(AValue: Variant); var Index: Integer; WdxField: TWdxField; begin if VarIsBool(AValue) then begin if AValue then FComboValue.Text := rsSimpleWordTrue else FComboValue.Text := rsSimpleWordFalse; end else begin WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); if (WdxField.FType <> FT_MULTIPLECHOICE) then FComboValue.Text := AValue else begin Index:= WdxField.GetUnitIndex(AValue); if Index < 0 then FComboValue.Text := AValue else FComboValue.Text := WdxField.LUnits[Index]; end; end; end; procedure TPluginPanel.SetComboBox(ComboBox: TComboBox; const Value, Error: String); var Index: Integer; begin Index:= ComboBox.Items.IndexOf(Value); if Index < 0 then msgError(Error) else begin ComboBox.ItemIndex:= Index; if Assigned(ComboBox.OnChange) then ComboBox.OnChange(ComboBox); end; end; procedure TPluginPanel.ComboValueKeyPress(Sender: TObject; var Key: Char); var WdxField: TWdxField; begin if (FComboField.ItemIndex < 0) then Exit; WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); case WdxField.FType of FT_NUMERIC_32, FT_NUMERIC_64: begin if not (Key in ['0'..'9', Chr(VK_BACK)]) then Key:= #0; end; FT_NUMERIC_FLOATING: begin if not (Key in ['0'..'9', Chr(VK_BACK), DefaultFormatSettings.DecimalSeparator]) then Key:= #0; end; end; end; procedure TPluginPanel.ComboValueUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); var WdxField: TWdxField; begin if (FComboField.ItemIndex < 0) then Exit; WdxField:= TWdxField(FComboField.Items.Objects[FComboField.ItemIndex]); case WdxField.FType of FT_NUMERIC_32, FT_NUMERIC_64, FT_NUMERIC_FLOATING: begin if (Length(UTF8Key) > 1) then UTF8Key:= #0; end; end; end; constructor TPluginPanel.Create(TheOwner: TComponent); var I: Integer; begin inherited Create(TheOwner); AutoSize:= True; BevelOuter:= bvNone; ChildSizing.ControlsPerLine:= 5; ChildSizing.Layout:= cclLeftToRightThenTopToBottom; ChildSizing.EnlargeHorizontal:= crsScaleChilds; FComboPlugin:= TComboBox.Create(Self); FComboPlugin.Parent:= Self; FComboPlugin.Style:= csDropDownList; FComboPlugin.OnChange:= @PluginChange; FComboField:= TComboBox.Create(Self); FComboField.Parent:= Self; FComboField.Style:= csDropDownList; FComboField.OnChange:= @FieldChange; FComboOperator:= TComboBox.Create(Self); FComboOperator.Parent:= Self; FComboOperator.Style:= csDropDownList; FComboValue:= TComboBox.Create(Self); FComboValue.OnKeyPress:= @ComboValueKeyPress; FComboValue.OnUTF8KeyPress:= @ComboValueUTF8KeyPress; FComboValue.Parent:= Self; FComboUnit:= TComboBox.Create(Self); FComboUnit.Style:= csDropDownList; FComboUnit.Parent:= Self; for I:= 0 to gWDXPlugins.Count - 1do begin if gWdxPlugins.GetWdxModule(I).IsLoaded or gWdxPlugins.GetWdxModule(I).LoadModule then begin FComboPlugin.Items.Add(gWdxPlugins.GetWdxModule(I).Name); end; end; if FComboPlugin.Items.Count > 0 then begin FComboPlugin.ItemIndex:= 0; PluginChange(FComboPlugin); end; end; destructor TPluginPanel.Destroy; begin FComboPlugin.Free; FComboField.Free; FComboOperator.Free; FComboValue.Free; FComboUnit.Free; inherited Destroy; end; end. doublecmd-1.1.22/src/usearchtemplate.pas0000644000175000001440000003452014743153644017274 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Load/Save search templates Copyright (C) 2009-2018 Alexander Koblov (alexx2000@mail.ru) 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 } unit uSearchTemplate; {$mode objfpc}{$H+} interface uses Classes, SysUtils, DCClassesUtf8, uFile, DCXmlConfig, uFindFiles; type { TSearchTemplate } TSearchTemplate = class private FTemplateName: String; FSearchRecord: TSearchTemplateRec; FFileChecks: TFindFileChecks; procedure MakeFileChecks; procedure SetSearchRecord(const AValue: TSearchTemplateRec); public constructor Create; function CheckFile(const AFile: TFile): Boolean; property FileChecks: TFindFileChecks read FFileChecks; property SearchRecord: TSearchTemplateRec read FSearchRecord write SetSearchRecord; property TemplateName: String read FTemplateName write FTemplateName; end; { TSearchTemplateList } TSearchTemplateList = class(TList) private function GetTemplate(Index: Integer): TSearchTemplate; function GetTemplate(const AName: String): TSearchTemplate; public procedure Clear; override; function Add(SearchTemplate: TSearchTemplate): Integer; procedure DeleteTemplate(Index: Integer); procedure LoadToStringList(StringList: TStrings); procedure LoadFromXml(AConfig: TXmlConfig; ANode: TXmlNode); procedure SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode); property TemplateByName[const AName: String]: TSearchTemplate read GetTemplate; property Templates[Index: Integer]: TSearchTemplate read GetTemplate; end; const cTemplateSign = '>'; function IsMaskSearchTemplate(const sMask: String): Boolean; inline; implementation uses Variants, DCFileAttributes, DCBasicTypes, WdxPlugin, uWdxModule; function IsMaskSearchTemplate(const sMask: String): Boolean; inline; begin Result:= (Length(sMask) > 0) and (sMask[1] = cTemplateSign); end; { TSearchTemplate } constructor TSearchTemplate.Create; begin inherited Create; FillByte(FSearchRecord, SizeOf(FSearchRecord), 0); end; procedure TSearchTemplate.MakeFileChecks; begin SearchTemplateToFindFileChecks(FSearchRecord, FFileChecks); end; procedure TSearchTemplate.SetSearchRecord(const AValue: TSearchTemplateRec); begin FSearchRecord := AValue; MakeFileChecks; end; function TSearchTemplate.CheckFile(const AFile: TFile): Boolean; begin // If template has IsNotOlderThan option then DateTime checks must be recalculated // everytime because they depend on current time. if FSearchRecord.IsNotOlderThan then DateTimeOptionsToChecks(FSearchRecord, FFileChecks); Result := uFindFiles.CheckFile(FSearchRecord, FFileChecks, AFile); end; { TSearchTemplateList } function TSearchTemplateList.GetTemplate(Index: Integer): TSearchTemplate; begin Result:= TSearchTemplate(Items[Index]); end; function TSearchTemplateList.GetTemplate(const AName: String): TSearchTemplate; var I: Integer; sName: String; begin Result:= nil; if IsMaskSearchTemplate(AName) then sName:= PChar(AName) + 1 // skip template sign else sName:= AName; for I:= 0 to Count - 1 do if SameText(TSearchTemplate(Items[I]).TemplateName, sName) then begin Result:= TSearchTemplate(Items[I]); Exit; end; end; procedure TSearchTemplateList.Clear; var i: Integer; begin for i := 0 to Count - 1 do Templates[i].Free; inherited Clear; end; function TSearchTemplateList.Add(SearchTemplate: TSearchTemplate): Integer; begin Result:= inherited Add(SearchTemplate); end; procedure TSearchTemplateList.DeleteTemplate(Index: Integer); begin Templates[Index].Free; Delete(Index); end; procedure TSearchTemplateList.LoadToStringList(StringList: TStrings); var I: Integer; begin StringList.Clear; for I:= 0 to Count - 1 do StringList.Add(Templates[I].TemplateName); end; const cSection = 'SearchTemplates'; procedure TSearchTemplateList.LoadFromXml(AConfig: TXmlConfig; ANode: TXmlNode); var Index: Integer; SearchTemplate: TSearchTemplate; FloatNotOlderThan: Double; Node: TXmlNode; begin Clear; ANode := ANode.FindNode(cSection); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('Template') = 0 then begin SearchTemplate:= TSearchTemplate.Create; with SearchTemplate.FSearchRecord do begin SearchTemplate.TemplateName:= AConfig.GetValue(ANode, 'Name', ''); StartPath:= AConfig.GetValue(ANode, 'StartPath', ''); ExcludeDirectories:= AConfig.GetValue(ANode, 'ExcludeDirectories', ''); FilesMasks:= AConfig.GetValue(ANode, 'FilesMasks', '*'); ExcludeFiles:= AConfig.GetValue(ANode, 'ExcludeFiles', ''); SearchDepth:= AConfig.GetValue(ANode, 'SearchDepth', -1); IsPartialNameSearch:= AConfig.GetValue(ANode, 'IsPartialNameSearch', False); RegExp:= AConfig.GetValue(ANode, 'RegExp', False); FollowSymLinks:= AConfig.GetValue(ANode, 'FollowSymLinks', False); FindInArchives:= AConfig.GetValue(ANode, 'FindInArchives', False); AttributesPattern:= AConfig.GetValue(ANode, 'AttributesPattern', ''); // date/time IsDateFrom:= AConfig.GetValue(ANode, 'IsDateFrom', False); IsDateTo:= AConfig.GetValue(ANode, 'IsDateTo', False); IsTimeFrom:= AConfig.GetValue(ANode, 'IsTimeFrom', False); IsTimeTo:= AConfig.GetValue(ANode, 'IsTimeTo', False); if IsDateFrom or IsTimeFrom then DateTimeFrom:= AConfig.GetValue(ANode, 'DateTimeFrom', TDateTime(0)); if IsDateTo or IsTimeTo then DateTimeTo:= AConfig.GetValue(ANode, 'DateTimeTo', Now); // not older than IsNotOlderThan:= AConfig.GetValue(ANode, 'IsNotOlderThan', False); if IsNotOlderThan then begin // Workaround because old value was floating point. FloatNotOlderThan:= AConfig.GetValue(ANode, 'NotOlderThan', Double(0)); NotOlderThan:= Trunc(FloatNotOlderThan); NotOlderThanUnit:= TTimeUnit(AConfig.GetValue(ANode, 'NotOlderThanUnit', 0)); end; // file size IsFileSizeFrom:= AConfig.GetValue(ANode, 'IsFileSizeFrom', False); IsFileSizeTo:= AConfig.GetValue(ANode, 'IsFileSizeTo', False); if IsFileSizeFrom then FileSizeFrom:= AConfig.GetValue(ANode, 'FileSizeFrom', Int64(0)); if IsFileSizeTo then FileSizeTo:= AConfig.GetValue(ANode, 'FileSizeTo', High(Int64)); FileSizeUnit:= TFileSizeUnit(AConfig.GetValue(ANode, 'FileSizeUnit', 0)); // find text IsFindText:= AConfig.GetValue(ANode, 'IsFindText', False); if IsFindText then FindText:= AConfig.GetValue(ANode, 'FindText', ''); // replace text IsReplaceText:= AConfig.GetValue(ANode, 'IsReplaceText', False); if IsReplaceText then ReplaceText:= AConfig.GetValue(ANode, 'ReplaceText', ''); // text search options HexValue:= AConfig.GetValue(ANode, 'HexValue', False); CaseSensitive:= AConfig.GetValue(ANode, 'CaseSensitive', False); NotContainingText:= AConfig.GetValue(ANode, 'NotContainingText', False); TextRegExp:= AConfig.GetValue(ANode, 'TextRegExp', False); OfficeXML:= AConfig.GetValue(ANode, 'OfficeXML', False); TextEncoding:= AConfig.GetValue(ANode, 'TextEncoding', ''); if TextEncoding = 'UTF-8BOM' then TextEncoding:= 'UTF-8'; if TextEncoding = 'UCS-2LE' then TextEncoding:= 'UTF-16LE'; if TextEncoding = 'UCS-2BE' then TextEncoding:= 'UTF-16BE'; // duplicates Node := AConfig.FindNode(ANode, 'Duplicates', True); Duplicates:= AConfig.GetAttr(Node, 'Enabled', False); if Duplicates then begin DuplicateName:= AConfig.GetValue(Node, 'Name', False); DuplicateSize:= AConfig.GetValue(Node, 'Size', False); DuplicateHash:= AConfig.GetValue(Node, 'Hash', False); DuplicateContent:= AConfig.GetValue(Node, 'Content', False); end; // plugins SearchPlugin:= AConfig.GetValue(ANode, 'SearchPlugin', ''); Node := AConfig.FindNode(ANode, 'ContentPlugins', True); ContentPlugin:= AConfig.GetAttr(Node, 'Enabled', False); if ContentPlugin then begin ContentPluginCombine:= AConfig.GetAttr(Node, 'Combine', True); Node := Node.FirstChild; while Assigned(Node) do begin if Node.CompareName('Plugin') = 0 then begin Index:= Length(ContentPlugins); SetLength(ContentPlugins, Index + 1); ContentPlugins[Index].Plugin:= AConfig.GetValue(Node, 'Name', EmptyStr); ContentPlugins[Index].Field:= AConfig.GetValue(Node, 'Field', EmptyStr); ContentPlugins[Index].UnitName:= AConfig.GetValue(Node, 'Unit', EmptyStr); ContentPlugins[Index].FieldType:= AConfig.GetValue(Node, 'FieldType', ft_string); ContentPlugins[Index].Compare:= TPluginOperator(AConfig.GetValue(Node, 'Compare', 0)); ContentPlugins[Index].Value:= StrToVar(AConfig.GetValue(Node, 'Value', EmptyStr), ContentPlugins[Index].FieldType); end; Node := Node.NextSibling; end; end; end; SearchTemplate.MakeFileChecks; Add(SearchTemplate); end; ANode := ANode.NextSibling; end; end; end; procedure TSearchTemplateList.SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode); var I, J: Integer; Node, SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, cSection, True); AConfig.ClearNode(ANode); for I:= 0 to Count - 1 do with Templates[I].SearchRecord do begin SubNode := AConfig.AddNode(ANode, 'Template'); AConfig.AddValue(SubNode, 'Name', Templates[I].TemplateName); AConfig.AddValue(SubNode, 'StartPath', StartPath); AConfig.AddValue(SubNode, 'ExcludeDirectories', ExcludeDirectories); AConfig.AddValue(SubNode, 'FilesMasks', FilesMasks); AConfig.AddValue(SubNode, 'ExcludeFiles', ExcludeFiles); AConfig.AddValue(SubNode, 'SearchDepth', SearchDepth); AConfig.AddValue(SubNode, 'IsPartialNameSearch', IsPartialNameSearch); AConfig.AddValue(SubNode, 'RegExp', RegExp); AConfig.AddValue(SubNode, 'FollowSymLinks', FollowSymLinks); AConfig.AddValue(SubNode, 'FindInArchives', FindInArchives); AConfig.AddValue(SubNode, 'AttributesPattern', AttributesPattern); // date/time AConfig.AddValue(SubNode, 'IsDateFrom', IsDateFrom); AConfig.AddValue(SubNode, 'IsDateTo', IsDateTo); AConfig.AddValue(SubNode, 'IsTimeFrom', IsTimeFrom); AConfig.AddValue(SubNode, 'IsTimeTo', IsTimeTo); if IsDateFrom or IsTimeFrom then AConfig.AddValue(SubNode, 'DateTimeFrom', DateTimeFrom); if IsDateTo or IsTimeTo then AConfig.AddValue(SubNode, 'DateTimeTo', DateTimeTo); // not older than AConfig.AddValue(SubNode, 'IsNotOlderThan', IsNotOlderThan); if IsNotOlderThan then begin AConfig.AddValue(SubNode, 'NotOlderThan', NotOlderThan); AConfig.AddValue(SubNode, 'NotOlderThanUnit', Integer(NotOlderThanUnit)); end; // file size AConfig.AddValue(SubNode, 'IsFileSizeFrom', IsFileSizeFrom); AConfig.AddValue(SubNode, 'IsFileSizeTo', IsFileSizeTo); if IsFileSizeFrom then AConfig.AddValue(SubNode, 'FileSizeFrom', FileSizeFrom); if IsFileSizeTo then AConfig.AddValue(SubNode, 'FileSizeTo', FileSizeTo); AConfig.AddValue(SubNode, 'FileSizeUnit', Integer(FileSizeUnit)); // find text AConfig.AddValue(SubNode, 'IsFindText', IsFindText); if IsFindText then AConfig.AddValue(SubNode, 'FindText', FindText); // replace text AConfig.AddValue(SubNode, 'IsReplaceText', IsReplaceText); if IsReplaceText then AConfig.AddValue(SubNode, 'ReplaceText', ReplaceText); // text search options AConfig.AddValue(SubNode, 'HexValue', HexValue); AConfig.AddValue(SubNode, 'CaseSensitive', CaseSensitive); AConfig.AddValue(SubNode, 'NotContainingText', NotContainingText); AConfig.AddValue(SubNode, 'TextRegExp', TextRegExp); AConfig.AddValue(SubNode, 'TextEncoding', TextEncoding); AConfig.AddValue(SubNode, 'OfficeXML', OfficeXML); // duplicates Node := AConfig.AddNode(SubNode, 'Duplicates'); AConfig.SetAttr(Node, 'Enabled', Duplicates); if Duplicates then begin AConfig.AddValue(Node, 'Name', DuplicateName); AConfig.AddValue(Node, 'Size', DuplicateSize); AConfig.AddValue(Node, 'Hash', DuplicateHash); AConfig.AddValue(Node, 'Content', DuplicateContent); end; // plugins AConfig.AddValue(SubNode, 'SearchPlugin', SearchPlugin); Node := AConfig.FindNode(SubNode, 'ContentPlugins', True); AConfig.SetAttr(Node, 'Enabled', ContentPlugin); if ContentPlugin then begin AConfig.SetAttr(Node, 'Combine', ContentPluginCombine); for J:= Low(ContentPlugins) to High(ContentPlugins) do begin SubNode := AConfig.AddNode(Node, 'Plugin'); AConfig.SetValue(SubNode, 'Name', ContentPlugins[J].Plugin); AConfig.SetValue(SubNode, 'Field', ContentPlugins[J].Field); AConfig.SetValue(SubNode, 'Unit', ContentPlugins[J].UnitName); AConfig.SetValue(SubNode, 'FieldType', ContentPlugins[J].FieldType); AConfig.SetValue(SubNode, 'Compare', Integer(ContentPlugins[J].Compare)); AConfig.SetValue(SubNode, 'Value', VarToStr(ContentPlugins[J].Value)); end; end; end; end; end. doublecmd-1.1.22/src/ushellexecute.pas0000644000175000001440000011635714743153644016776 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- This unit contains some functions for open files in associated applications. Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uShellExecute; {$mode objfpc}{$H+} interface uses Classes, uFile, uFileView, fMain; const ASCII_DLE = #16; type TPrepareParameterOption = (ppoNormalizePathDelims, ppoReplaceTilde); TPrepareParameterOptions = set of TPrepareParameterOption; procedure PrepareOutput(var sParams: String; const sWorkPath: String; const ATemp: String = ''); function PrepareParameter(sParam: string; paramFile: TFile = nil; options: TPrepareParameterOptions = []; pbShowCommandLinePriorToExecute: PBoolean = nil; pbRunInTerminal: PBoolean = nil; pbKeepTerminalOpen: PBoolean = nil; pbAbortOperation: PBoolean = nil): string; overload; {en Replace variable parameters that depend on files in panels. } function ReplaceVarParams(sSourceStr: string; paramFile: TFile = nil; pbShowCommandLinePriorToExecute: PBoolean = nil; pbRunInTerminal: PBoolean = nil; pbKeepTerminalOpen: PBoolean = nil; pbAbortOperation: PBoolean = nil): string; overload; {en Replace variable parameters that depend on the file in active dir. } function ProcessExtCommandFork(sCmd: string; sParams: string = ''; sWorkPath: string = ''; paramFile: TFile = nil; bTerm: boolean = False; bKeepTerminalOpen: boolean = False): boolean; function ShellExecuteEx(sActionName, sFileName, sActiveDir: string): boolean; implementation uses //Notes: StrUtils is here first, so because of visibility rules, if a called // routine name is present both in "StrUtils" and one of the following // it will be one of the following that will be used and not the one // "StrUtils". Make sure to let "StrUtils" at the first position. // "StrUtils" is here to have the "PosEx". //Lazarus, Free-Pascal, etc. StrUtils, Dialogs, SysUtils, Process, UTF8Process, LazUTF8, LConvEncoding, DCUnicodeUtils, DCConvertEncoding, //DC uShowMsg, uDCUtils, uLng, uFormCommands, fViewer, fEditor, uShowForm, uGlobs, uOSUtils, uFileSystemFileSource, DCOSUtils, DCStrUtils, DCClassesUtf8; //Dialogs, //LConvEncoding; (* Functions (without parameters they give output for all selected files): Miscellaneous: %? - as first parameter only, it will show report to show command line prior to execute %% - to use one time the percent sign "File related": ------------------------------------------------------------------------------ %f - only filename %d - only path of the file %z - last directory of path of the file %p - path + filename %o - only the filename with no extension %e - only the file extension %v - only relative path + filename %D - current path in active or chosen panel %Z - last directory of path of active or chosen panel %a - address + path + filename %A - current address in active or chosen panel %F - file list with file name only %L - file list with full file name %R - file list with relative path + file name %F, %L and %R - create a list file in the TEMP directory with the names of the selected files and directories, and appends the name of the list file to the command line "Choosing encoding" for %F, $L and %R (if not given, system encoding used): --------------------------------------------------------------------------- %X[U|W|Q] - where X is function %F, %L or %R U - UTF-8, W - UTF-16 (with byte order marker), Q - quote file name by double quotes "Choosing panel" (if not given, active panel is used): ------------------------------------------------------------------------------ %X[l|r|s|t] - where X is function (l - left, r - right, s - source, t - target) s - source or active panel (no matter if it's left or right) t - target or inactive panel (no matter if it's left or right) l - left panel r - right panel b - both panels, left first, right second p - both panels, active first, inactive second "Choosing selected files" (only for %f, %d, %p, %o and %e): ------------------------------------------------------------------------------ %X[] - where X is function is 1..n, where n is number of selected files. Also can be 0, file under cursor is used in this case. If there are no selected files, currently active file is nr 1. If is invalid or there is no selected file by that number the result for the whole function will be empty string. "Adding prefix, postfix before or after the result string": ------------------------------------------------------------------------------ %X[{}][{}] If applied to multiple files, each name is prefixed/postfixed. Control if %f, %d, etc... will return name between quotes or not ---------------------------------------------------------------- %" - will set default. For DC legacy is quoted %"0 - will make the result unquoted %"1 - will make the result quoted Control if %D, %d etc... will return path name with the ending delimiter or not ------------------------------------------------------------------------------- %/ - will set default. For DC legacy it was without ending delimited %/0 - will exclude the ending delimiter %/1 - will include the ending delimiter Prompt the user with a sentence, propose a default, and use what the user typed ------------------------------------------------------------------------------- %[This required the \\DB-2010\ server to be online!] - if no default value is given, DC will simply shows the message, assuming it's simply to echo a message. %[Enter with required;1024] - This is an example. The text following the ";" indicates that default value is 1024 %[First name;%o] - The text proposed in the parameter value may be parsed prior to be displayed to user. For example here, the %o will be substituted to the filename with no extension prior to be displayed to user. Control what will be the effective "%" char (for situation where we want the "%" to be the "#" sign instead ----------------------------------------------------------------------------------------------------------- %# - Will set the percent-variable indicator to be the "#" character from now on when evaluating the line. Note that it will be evaluated -only- when the current percent-variable indicator is "%". #% - Will set the percent-variable indicator to be the "%" character from now on when evaluating the line. Note that it will be evaluated -only- when the current percent-variable indicator is "#". Control if it run in terminal, if it close it at the end or not --------------------------------------------------------------- %t - Will have it run in terminal for sure, close or not depend of the action requested %t0 - Will run in terminal AND request to close it at the end %t1 - Will run in terminal AND let it run at the end Above parameters can be combined together. ------------------------------------------------------------------------------ Order of params: - %function - quoting and encoding (only for %F, %L and %R) - left or right or source or target panel (optional) - nr of file (optional) - prefix, postfix (optional) Examples: %f1 - first selected file in active panel %pr2 - full path of second selected file in right panel %fl - only filenames from left panel %pr - full filenames from right panel %Dl - current path in left panel %f{-f } - prepend each name with "-f " (ex.: -f -f ) %f{"}{"} - enclose each name in quotes (ex.: "" "") %f1{-first }%f2{ -second } - if only 1 file selected : -first - if 2 (or more) files selected: -first -second *) function ReplaceVarParams(sSourceStr: string; paramFile: TFile; pbShowCommandLinePriorToExecute: PBoolean; pbRunInTerminal: PBoolean; pbKeepTerminalOpen: PBoolean; pbAbortOperation: PBoolean = nil): string; type TFunctType = (ftNone, ftName, ftDir, ftLastDir, ftPath, ftSingleDir, ftLastSingleDir, ftSource, ftSourcePath, ftFileFullList, ftFileNameList, ftRelativeFileNameList, ftNameNoExt, ftExtension, ftRelativePath, ftProcessPercentSignIndicator, ftJustSetTheShowFlag, ftSetTrailingDelimiter, ftSetQuoteOrNot, ftSetTerminalOptions, ftEchoSimpleMessage, ftPromptUserForParam, ftExecuteConsoleCommand); TFuncModifiers = set of (fmQuote, fmUTF8, fmUTF16); TStatePos = (spNone, spPercent, spFunction, spPrefix, spPostfix, spGotPrefix, spSide, spIndex, spUserInputOrEcho, spGotInputHintWaitEndDefaultVal, spGetExecuteConsoleCommand, spComplete); var leftFiles: TFiles = nil; rightFiles: TFiles = nil; singleFileFiles: TFiles = nil; leftFile: TFile; rightFile: TFile; activeFile: TFile; inactiveFile: TFile; activeFiles: TFiles; inactiveFiles: TFiles; activeDir: string; inactiveDir: string; activeAddress: string; inactiveAddress: string; bTrailingDelimiter: boolean = False; bQuoteOrNot: boolean = True; CurrentPercentIndicator: char = '%'; bKeepProcessParameter:boolean = true; // There is a inside recursive function because of the %[ that could have a parameter that could be parsed using the same function. // It would have been possible to simply call again "ReplaceVarParams" without an inner function... // ...but there are a few things that would have not work as what the user would expect. // For example, if user would have wrote previously %"0 to have the following not include the quote, by simply recalling "ReplaceVarParams" itself, if he would have used then a %o in the default parameter value for the %[ , the filename would have been quoted again since it's the default when entering into the "ReplaceVarParams" function originally... // Same similar problem with the bTrailingDelimiter, etc. // So that's why there is an inner recursive functions where the kind of local-global flag like the ones mentionned above have to be global for the current parsed string. function InnerRecursiveReplaceVarParams(sSourceStr: string; paramFile: TFile; pbShowCommandLinePriorToExecute: PBoolean; pbRunInTerminal: PBoolean; pbKeepTerminalOpen: PBoolean; pbAbortOperation: PBoolean = nil): string; type Tstate = record pos: TStatePos; functStartIndex: integer; funct: TFunctType; functMod: TFuncModifiers; files: TFiles; otherfiles: TFiles; fil: TFile; otherfil: TFile; dir: string; address: string; sFileIndex: string; prefix, postfix: string; // a string to add before/after each output // (for functions giving output of multiple strings) sSubParam: string; sUserMessage: string; end; var index: integer; state: Tstate; sOutput: string = ''; parseStartIndex: integer; function BuildName(aFile: TFile): string; begin //1. Processing according to function requested case state.funct of ftName, ftDir, ftLastDir, ftPath, ftNameNoExt, ftExtension, ftSingleDir, ftLastSingleDir, ftRelativePath, ftSource, ftSourcePath: begin case state.funct of ftName: Result := aFile.Name; ftDir: Result := aFile.Path; ftLastDir: Result := GetLastDir(aFile.Path); ftPath: Result := aFile.FullPath; ftNameNoExt: Result := aFile.NameNoExt; ftExtension: Result := aFile.Extension; ftRelativePath: Result := ExtractRelativepath(state.dir, aFile.FullPath); ftSingleDir: Result := state.dir; ftLastSingleDir: Result := GetLastDir(state.dir); ftSource: Result := state.address; ftSourcePath: Result := state.address + aFile.FullPath; end; end; else Exit(''); end; //2. Processing the prefix/postfix requested Result := state.prefix + Result + state.postfix; //3. Processing the trailing path delimiter requested case state.funct of ftDir, ftLastDir, ftSingleDir, ftLastSingleDir: begin if bTrailingDelimiter then Result := IncludeTrailingPathDelimiter(Result) else Result := ExcludeBackPathDelimiter(Result); end; end; //4. Processing the quotes requested if bQuoteOrNot then Result := QuoteStr(Result); end; function BuildAllNames: string; var i: integer; begin Result := ''; if Assigned(state.files) then for i := 0 to pred(state.files.Count) do Result := ConcatenateStrWithSpace(Result, BuildName(state.files[i])); if Assigned(state.otherfiles) then for i := 0 to pred(state.otherfiles.Count) do Result := ConcatenateStrWithSpace(Result, BuildName(state.otherfiles[i])); end; function BuildFile(aFile: TFile): string; begin case state.funct of ftFileFullList: Result := aFile.FullPath; ftFileNameList: Result := aFile.Name; ftRelativeFileNameList: Result := ExtractRelativepath(state.dir, aFile.FullPath); else Result := aFile.Name; end; if aFile.isDirectory then begin if bTrailingDelimiter then Result := IncludeTrailingPathDelimiter(Result) else Result := ExcludeBackPathDelimiter(Result); end; if (fmQuote in state.functMod) then Result := '"' + Result + '"'; if (fmUTF16 in state.functMod) then Result := Utf8ToUtf16LE(Result) else if not (fmUTF8 in state.functMod) then Result := CeUtf8ToSys(Result); end; function BuildFileList: String; var I: integer; FileName: ansistring; FileList: TFileStreamEx; LineEndingA: ansistring = LineEnding; begin Result := GetTempName(GetTempFolderDeletableAtTheEnd + 'Filelist', 'lst'); try FileList := TFileStreamEx.Create(Result, fmCreate); try if fmUTF16 in state.functMod then begin FileName := UTF16LEBOM; LineEndingA := Utf8ToUtf16LE(LineEnding); end; if Assigned(state.files) then begin if state.files.Count > 0 then begin for I := 0 to state.files.Count - 1 do FileName += BuildFile(state.files[I]) + LineEndingA; end; end; if Assigned(state.otherfiles) then begin if state.otherfiles.Count > 0 then begin FileName += LineEndingA; for I := 0 to state.otherfiles.Count - 1 do FileName += BuildFile(state.otherfiles[I]) + LineEndingA; end; end; FileList.Write(FileName[1], Length(FileName)); finally FileList.Free; end; except Result := EmptyStr; end; end; procedure ResetState(var aState: TState); begin with aState do begin pos := spNone; fil := activeFile; otherfil := nil; if paramFile <> nil then files := singleFileFiles else files := activeFiles; otherfiles := nil; dir := activeDir; address := activeAddress; sFileIndex := ''; funct := ftNone; functMod := []; functStartIndex := 0; prefix := ''; postfix := ''; sSubParam := ''; sUserMessage := ''; end; end; procedure AddParsedText(limit: integer); begin // Copy [parseStartIndex .. limit - 1]. if limit > parseStartIndex then sOutput := sOutput + Copy(sSourceStr, parseStartIndex, limit - parseStartIndex); parseStartIndex := index; end; procedure SetTrailingPathDelimiter; begin bTrailingDelimiter := state.sSubParam = '1'; // Currently in the code, anything else than "0" will include the trailing delimiter. // BUT, officially, in the documentation, just state that 0 or 1 is required. // This could give room for future addition maybe. end; procedure SetQuoteOrNot; begin bQuoteOrNot := not (state.sSubParam = '0'); // Currently in the code, anything else than "0" will indicate we want to quote // BUT, officially, in the documentation, just state that 0 or 1 is required. // This could give room for future addition maybe. end; procedure SetTerminalOptions; begin if pbRunInTerminal <> nil then begin pbRunInTerminal^ := True; if pbKeepTerminalOpen <> nil then pbKeepTerminalOpen^ := not (state.sSubParam = '0'); end; end; procedure JustEchoTheMessage; begin state.sUserMessage := InnerRecursiveReplaceVarParams(state.sUserMessage, paramFile, pbShowCommandLinePriorToExecute, pbRunInTerminal, pbKeepTerminalOpen, pbAbortOperation); msgOK(state.sUserMessage); end; procedure AskUserParamAndReplace; begin state.sSubParam := InnerRecursiveReplaceVarParams(state.sSubParam, paramFile, pbShowCommandLinePriorToExecute, pbRunInTerminal, pbKeepTerminalOpen, pbAbortOperation); if ShowInputQuery(rsMsgCofirmUserParam, state.sUserMessage, state.sSubParam) then begin sOutput := sOutput + state.sSubParam; end else begin bKeepProcessParameter:=False; end; end; procedure ExecuteConsoleCommand; var sTmpFilename, sShellCmdLine: string; Process: TProcessUTF8; begin sTmpFilename := GetTempName(GetTempFolderDeletableAtTheEnd); //sShellCmdLine := Copy(state.sSubParam, 3, length(state.sSubParam)-2) + ' > ' + QuoteStr(sTmpFilename); sShellCmdLine := state.sSubParam + ' > ' + QuoteStr(sTmpFilename); Process := TProcessUTF8.Create(nil); try Process.CommandLine := FormatShell(sShellCmdLine); Process.Options := [poNoConsole, poWaitOnExit]; Process.Execute; finally Process.Free; end; sOutput := sOutput + sTmpFilename; end; procedure ProcessPercentSignIndicator; begin if CurrentPercentIndicator = state.sSubParam then sOutput := sOutput + state.sSubParam else if CurrentPercentIndicator = '%' then CurrentPercentIndicator := '#' else CurrentPercentIndicator := '%'; end; procedure DoFunction; var fileIndex: integer = -2; OffsetFromStart: integer = 0; begin AddParsedText(state.functStartIndex); if state.sFileIndex <> '' then try fileIndex := StrToInt(state.sFileIndex); fileIndex := fileIndex - 1; // Files are counted from 0, but user enters 1..n. except on EConvertError do fileIndex := -2; end; if fileIndex = -1 then begin if Assigned(state.fil) then sOutput := sOutput + BuildName(state.fil); if Assigned(state.otherfil) then sOutput := ConcatenateStrWithSpace(sOutput, BuildName(state.otherfil)); end else if fileIndex > -1 then begin if (fileIndex >= 0) and Assigned(state.files) then begin if fileIndex < state.files.Count then sOutput := sOutput + BuildName(state.files[fileIndex]); OffsetFromStart := state.files.Count; end; if ((fileIndex - OffsetFromStart) >= 0) and Assigned(state.otherfiles) then if (fileIndex - OffsetFromStart) < state.otherfiles.Count then sOutput := sOutput + BuildName(state.otherfiles[fileIndex - OffsetFromStart]); end else begin if state.funct in [ftName, ftPath, ftDir, ftLastDir, ftNameNoExt, ftSourcePath, ftExtension, ftRelativePath] then sOutput := sOutput + BuildAllNames else if state.funct in [ftSingleDir, ftLastSingleDir, ftSource] then // only single current dir sOutput := sOutput + BuildName(nil) else if state.funct in [ftFileFullList, ftFileNameList, ftRelativeFileNameList] then // for list of file sOutput := sOutput + BuildFileList else if state.funct in [ftProcessPercentSignIndicator] then // only add % sign ProcessPercentSignIndicator else if state.funct in [ftJustSetTheShowFlag] then //only set the flag to show the params prior to execute begin if pbShowCommandLinePriorToExecute <> nil then pbShowCommandLinePriorToExecute^ := True; end else if state.funct in [ftSetTrailingDelimiter] then //set the trailing path delimiter SetTrailingPathDelimiter else if state.funct in [ftSetQuoteOrNot] then SetQuoteOrNot else if state.funct in [ftEchoSimpleMessage] then JustEchoTheMessage else if state.funct in [ftPromptUserForParam] then AskUserParamAndReplace else if state.funct in [ftSetTerminalOptions] then SetTerminalOptions else if state.funct in [ftExecuteConsoleCommand] then ExecuteConsoleCommand; end; ResetState(state); end; procedure ProcessNumber; begin case state.funct of ftSingleDir, ftLastSingleDir: state.pos := spComplete; // Numbers not allowed for %D and %Z ftSetTrailingDelimiter, ftSetQuoteOrNot, ftSetTerminalOptions: begin state.sSubParam := state.sSubParam + sSourceStr[index]; state.pos := spComplete; Inc(Index); end; else begin state.sFileIndex := state.sFileIndex + sSourceStr[index]; state.pos := spIndex; end; end; end; procedure ProcessOpenBracket; // '{' begin if state.pos <> spGotPrefix then state.pos := spPrefix else state.pos := spPostfix; end; begin index := 1; parseStartIndex := index; ResetState(state); while (index <= Length(sSourceStr)) AND (bKeepProcessParameter) do begin case state.pos of spNone: if sSourceStr[index] = CurrentPercentIndicator then begin state.pos := spPercent; state.functStartIndex := index; end; spPercent: case sSourceStr[index] of '?': begin state.funct := ftJustSetTheShowFlag; state.pos := spComplete; Inc(Index); end; ASCII_DLE: begin AddParsedText(state.functStartIndex); parseStartIndex := Index + 1; Index := Length(sSourceStr) + 1; state.pos := spComplete; Break; end; '%', '#': begin state.funct := ftProcessPercentSignIndicator; state.sSubParam := sSourceStr[index]; state.pos := spComplete; Inc(Index); end; 'f', 'd', 'z', 'p', 'o', 'e', 'v', 'D', 'Z', 'A', 'a', 'n', 'h', '/', '"', 't': begin case sSourceStr[index] of 'f': state.funct := ftName; 'd': state.funct := ftDir; 'z': state.funct := ftLastDir; 'p': state.funct := ftPath; 'o': state.funct := ftNameNoExt; 'e': state.funct := ftExtension; 'v': state.funct := ftRelativePath; 'D': state.funct := ftSingleDir; 'Z': state.funct := ftLastSingleDir; 'A': state.funct := ftSource; 'a': state.funct := ftSourcePath; '/': state.funct := ftSetTrailingDelimiter; '"': state.funct := ftSetQuoteOrNot; 't': state.funct := ftSetTerminalOptions; end; state.pos := spFunction; end; 'L', 'F', 'R': begin case sSourceStr[index] of 'L': state.funct := ftFileFullList; 'F': state.funct := ftFileNameList; 'R': state.funct := ftRelativeFileNameList; end; state.pos := spFunction; end; '[': begin state.pos := spUserInputOrEcho; end; '<': begin state.pos := spGetExecuteConsoleCommand; end; else ResetState(state); end; spFunction: case sSourceStr[index] of 'l', 'b': begin state.files := leftFiles; state.fil := leftFile; state.dir := frmMain.FrameLeft.CurrentPath; state.address := frmMain.FrameLeft.CurrentAddress; state.pos := spSide; if sSourceStr[index] = 'b' then begin state.otherfiles := rightFiles; state.otherfil := rightFile; end; end; 'r': begin state.files := rightFiles; state.fil := rightFile; state.dir := frmMain.FrameRight.CurrentPath; state.address := frmMain.FrameRight.CurrentAddress; state.pos := spSide; end; 's', 'p': begin state.files := activeFiles; state.fil := activeFile; state.dir := activeDir; state.address := activeAddress; state.pos := spSide; if sSourceStr[index] = 'p' then begin state.otherfil := inactiveFile; state.otherfiles := inactiveFiles; end; end; 't': begin state.files := inactiveFiles; state.fil := inactiveFile; state.dir := inactiveDir; state.address := inactiveAddress; state.pos := spSide; end; 'U': begin state.functMod += [fmUTF8]; state.pos := spFunction; end; 'W': begin state.functMod += [fmUTF16]; state.pos := spFunction; end; 'Q': begin state.functMod += [fmQuote]; state.pos := spFunction; end; '0'..'9': ProcessNumber; '{': ProcessOpenBracket; else state.pos := spComplete; end; spSide: case sSourceStr[index] of '0'..'9': ProcessNumber; '{': ProcessOpenBracket; else state.pos := spComplete; end; spIndex: case sSourceStr[index] of '0'..'9': ProcessNumber; '{': ProcessOpenBracket; else state.pos := spComplete; end; spPrefix, spPostfix: case sSourceStr[index] of '}': begin if state.pos = spPostfix then begin Inc(index); // include closing bracket in the function state.pos := spComplete; end else state.pos := spGotPrefix; end; else begin case state.pos of spPrefix: state.prefix := state.prefix + sSourceStr[index]; spPostfix: state.postfix := state.postfix + sSourceStr[index]; end; end; end; spGotPrefix: case sSourceStr[index] of '{': ProcessOpenBracket; else state.pos := spComplete; end; spUserInputOrEcho: begin case sSourceStr[index] of ';': begin state.pos := spGotInputHintWaitEndDefaultVal; end; ']': begin state.funct := ftEchoSimpleMessage; state.pos := spComplete; Inc(Index); end; else State.sUserMessage := State.sUserMessage + sSourceStr[index]; end; end; spGotInputHintWaitEndDefaultVal: begin case sSourceStr[index] of ']': begin state.funct := ftPromptUserForParam; state.pos := spComplete; Inc(Index); end; else State.sSubParam := State.sSubParam + sSourceStr[index]; end; end; spGetExecuteConsoleCommand: begin case sSourceStr[index] of '>': begin state.funct := ftExecuteConsoleCommand; state.pos := spComplete; Inc(Index); end; else State.sSubParam := State.sSubParam + sSourceStr[index]; end; end; end; if state.pos <> spComplete then Inc(index) // check next character else // Process function and then check current character again after resetting state. DoFunction; end; // Finish current parse. if bKeepProcessParameter then begin if state.pos in [spFunction, spSide, spIndex, spGotPrefix] then DoFunction else AddParsedText(index); end; if bKeepProcessParameter then Result := sOutput else if pbAbortOperation<>nil then pbAbortOperation^ := True; end; begin result := ''; try leftFiles := frmMain.FrameLeft.CloneSelectedOrActiveFiles; rightFiles := frmMain.FrameRight.CloneSelectedOrActiveFiles; if paramFile <> nil then begin singleFileFiles := TFiles.Create(paramFile.Path); singleFileFiles.Add(paramFile.Clone); end; leftFile:= frmMain.FrameLeft.CloneActiveFile; rightFile:= frmMain.FrameRight.CloneActiveFile; if Assigned(leftFile) and (not leftFile.IsNameValid) then FreeAndNil(leftFile); if Assigned(rightFile) and (not rightFile.IsNameValid) then FreeAndNil(rightFile); if frmMain.ActiveFrame = frmMain.FrameLeft then begin activeFiles := leftFiles; activeFile:= leftFile; inactiveFile:= rightFile; activeDir := frmMain.FrameLeft.CurrentPath; activeAddress := frmMain.FrameLeft.CurrentAddress; inactiveFiles := rightFiles; inactiveDir := frmMain.FrameRight.CurrentPath; inactiveAddress := frmMain.FrameRight.CurrentAddress; end else begin activeFiles := rightFiles; activeFile:= rightFile; inactiveFile:= leftFile; activeDir := frmMain.FrameRight.CurrentPath; activeAddress := frmMain.FrameRight.CurrentAddress; inactiveFiles := leftFiles; inactiveDir := frmMain.FrameLeft.CurrentPath; inactiveAddress := frmMain.FrameLeft.CurrentAddress; end; result:=InnerRecursiveReplaceVarParams(sSourceStr, paramFile, pbShowCommandLinePriorToExecute, pbRunInTerminal, pbKeepTerminalOpen, pbAbortOperation); finally FreeAndNil(leftFile); FreeAndNil(rightFile); FreeAndNil(leftFiles); FreeAndNil(rightFiles); FreeAndNil(singleFileFiles); end; end; procedure PrepareOutput(var sParams: String; const sWorkPath: String; const ATemp: String); var Process: TProcessUTF8; iStart, iCount: Integer; sTmpFile, sShellCmdLine: String; iLastConsoleCommandPos: Integer = 0; begin repeat iStart := Posex('', sParams, iStart) - iStart; if (iStart <> 0) and (iCount >= 0) then begin if Length(ATemp) > 0 then sTmpFile:= ATemp else begin sTmpFile:= GetTempFolderDeletableAtTheEnd; end; sTmpFile := GetTempName(sTmpFile); sShellCmdLine := Copy(sParams, iStart, iCount) + ' > ' + QuoteStr(sTmpFile); Process := TProcessUTF8.Create(nil); try Process.CommandLine := FormatShell(sShellCmdLine); Process.CurrentDirectory := sWorkPath; Process.Options := [poWaitOnExit]; Process.ShowWindow := swoHide; Process.Execute; finally Process.Free; end; sParams := Copy(sParams, 1, iStart - 3) + sTmpFile + Copy(sParams, iStart + iCount + 2, MaxInt); iLastConsoleCommandPos := iStart; end; until ((iStart = 0) or (iCount < 0)); end; { PrepareParameter } function PrepareParameter(sParam: string; paramFile: TFile; options: TPrepareParameterOptions; pbShowCommandLinePriorToExecute: PBoolean; pbRunInTerminal: PBoolean; pbKeepTerminalOpen: PBoolean; pbAbortOperation: PBoolean = nil): string; overload; begin Result := sParam; if ppoNormalizePathDelims in Options then Result := NormalizePathDelimiters(Result); if ppoReplaceTilde in Options then Result := ReplaceTilde(Result); Result := ReplaceEnvVars(Result); Result := ReplaceVarParams(Result, paramFile, pbShowCommandLinePriorToExecute, pbRunInTerminal, pbKeepTerminalOpen,pbAbortOperation); Result := Trim(Result); end; { ProcessExtCommandFork } function ProcessExtCommandFork(sCmd, sParams, sWorkPath: string; paramFile: TFile; bTerm: boolean; bKeepTerminalOpen: boolean): boolean; var sl: TStringList; bShowCommandLinePriorToExecute: boolean = False; bAbortOperationFlag: boolean = false; begin Result := False; // 1. Parse the command, parameters and working directory for the percent-variable substitution. sCmd := PrepareParameter(sCmd, paramFile, [ppoReplaceTilde]); sParams := PrepareParameter(sParams, paramFile, [], @bShowCommandLinePriorToExecute, @bTerm, @bKeepTerminalOpen, @bAbortOperationFlag); if not bAbortOperationFlag then sWorkPath := PrepareParameter(sWorkPath, paramFile, [ppoNormalizePathDelims, ppoReplaceTilde]); if not bAbortOperationFlag then begin // 2. If working directory has been specified, let's switch to it. if sWorkPath <> '' then mbSetCurrentDir(sWorkPath); // 3. If user has command-line to execute and get the result to a file, let's execute it. // Check for command. // This command is used to put output of some console program to a file so // that the file can then be viewed. The command is between ''. // The whole expression is replaced with a path to the temporary file // containing output of the command. // For example: // {!VIEWER} // Show in Viewer information about RPM package PrepareOutput(sParams, sWorkPath); //4. If user user wanted to execute an internal command, let's do it. if frmMain.Commands.Commands.ExecuteCommand(sCmd, [sParams]) = cfrSuccess then begin Result := True; exit; end; //5. From legacy, invoking shell seems to be similar to "run in terminal with stay open" with param as-is if Pos('{!SHELL}', sCmd) > 0 then begin sCmd := sParams; sParams := ''; bTerm := True; bKeepTerminalOpen := True; end; //6. If user wants to process via terminal (and close at the end), let's flag it. if Pos('{!TERMANDCLOSE}', sCmd) > 0 then begin sCmd := RemoveQuotation(sParams); sParams := ''; bTerm := True; end; //7. If user wants to process via terminal (and close at the end), let's flag it. if Pos('{!TERMSTAYOPEN}', sCmd) > 0 then begin sCmd := RemoveQuotation(sParams); sParams := ''; bTerm := True; bKeepTerminalOpen := True; end; //8. If our end-job is to EDIT a file via what's configured as editor, let's do it. if Pos('{!EDITOR}', sCmd) > 0 then begin uShowForm.ShowEditorByGlob(RemoveQuotation(sParams)); Result := True; Exit; end; //9. If our end-job is to EDIT a file via internal editor, let's do it. if Pos('{!DC-EDITOR}', sCmd) > 0 then begin fEditor.ShowEditor(RemoveQuotation(sParams)); Result := True; Exit; end; //10. If our end-job is to VIEW a file via what's configured as viewer, let's do it. if Pos('{!VIEWER}', sCmd) > 0 then begin uShowForm.ShowViewerByGlob(RemoveQuotation(sParams)); Result := True; Exit; end; //11. If our end-job is to VIEW a file or files via internal viewer, let's do it. if Pos('{!DC-VIEWER}', sCmd) > 0 then begin sl := TStringList.Create; try sl.Add(RemoveQuotation(sParams)); fViewer.ShowViewer(sl); Result := True; finally FreeAndNil(sl); end; Exit; end; //12. Ok. If we're here now it's to execute something external so let's launch it! try Result := ExecCmdFork(sCmd, sParams, sWorkPath, bShowCommandLinePriorToExecute, bTerm, bKeepTerminalOpen); except on e: EInvalidCommandLine do begin MessageDlg(rsMsgInvalidCommandLine, rsMsgInvalidCommandLine + ': ' + e.Message, mtError, [mbOK], 0); Result := False; end; end; end; //if not bAbortOperationFlag end; function ShellExecuteEx(sActionName, sFileName, sActiveDir: string): boolean; var aFile: TFile; sCmd, sParams, sStartPath: string; begin Result := False; // Executing files directly only works for FileSystem. aFile := TFileSystemFileSource.CreateFileFromFile(sFileName); try if gExts.GetExtActionCmd(aFile, sActionName, sCmd, sParams, sStartPath) then begin Result := ProcessExtCommandFork(sCmd, sParams, sStartPath, aFile); end; if not Result then begin mbSetCurrentDir(sActiveDir); Result := ShellExecute(sFileName); end; finally FreeAndNil(aFile); end; end; end. doublecmd-1.1.22/src/ushowform.pas0000644000175000001440000007452714743153644016152 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Execute internal or external viewer, editor or differ Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uShowForm; {$mode objfpc}{$H+} interface uses Classes, Forms, DCBasicTypes, uFileSource, uFileSourceOperation, uFile, uFileSourceCopyOperation; type { TWaitData } TWaitData = class private procedure ShowOnTopAsync(Data: PtrInt); public procedure ShowOnTop(AForm: TCustomForm); procedure ShowWaitForm; virtual; abstract; procedure Done; virtual; abstract; end; { TViewerWaitData } TViewerWaitData = class(TWaitData) private FFileSource: IFileSource; public constructor Create(aFileSource: IFileSource); destructor Destroy; override; procedure ShowWaitForm; override; procedure Done; override; end; { TEditorWaitData } TEditorWaitData = class(TWaitData) public Files: TFiles; function GetFileList: TStringList; protected FileTimes: array of TFileTime; TargetPath: String; SourceFileSource: IFileSource; TargetFileSource: IFileSource; FModal: Boolean; function GetRelativeFileName(const FullPath: string): string; function GetRelativeFileNames: string; function GetFromPath: string; public constructor Create(aCopyOutOperation: TFileSourceCopyOperation; Modal: Boolean = False); destructor Destroy; override; procedure ShowWaitForm; override; procedure Done; override; protected procedure OnCopyInStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); end; { TViewerModeData } TViewerModeData = class private FMode: Integer; public constructor Create(AMode: Integer); procedure OnCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); end; TToolDataPreparedProc = procedure(const FileList: TStringList; WaitData: TWaitData; Modal: Boolean = False); // Callback may be called either asynchoronously or synchronously (for modal operations) // pdrInCallback is returned when FunctionToCall either will be called or was already called TPrepareDataResult = (pdrFailed, pdrSynchronous, pdrInCallback); function PrepareData(FileSource: IFileSource; var SelectedFiles: TFiles; FunctionToCall: TFileSourceOperationStateChangedNotify; Modal: Boolean = False): TPrepareDataResult; procedure PrepareToolData(FileSource: IFileSource; var SelectedFiles: TFiles; FunctionToCall: TToolDataPreparedProc); overload; procedure PrepareToolData(FileSource1: IFileSource; var SelectedFiles1: TFiles; FileSource2: IFileSource; var SelectedFiles2: TFiles; FunctionToCall: TToolDataPreparedProc); overload; procedure PrepareToolData(FileSource1: IFileSource; File1: TFile; FileSource2: IFileSource; File2: TFile; FunctionToCall: TToolDataPreparedProc; Modal: Boolean = False); overload; procedure RunExtDiffer(CompareList: TStringList); procedure ShowEditorByGlob(const sFileName: String); procedure ShowEditorByGlob(WaitData: TEditorWaitData); overload; procedure ShowDifferByGlob(const LeftName, RightName: String); procedure ShowDifferByGlobList(const CompareList: TStringList; WaitData: TWaitData; Modal: Boolean = False); procedure ShowViewerByGlob(const sFileName: String); procedure ShowViewerByGlobList(const FilesToView: TStringList; const aFileSource: IFileSource); implementation uses SysUtils, Process, DCProcessUtf8, Dialogs, LCLIntf, DCDateTimeUtils, uShellExecute, uGlobs, uOSUtils, fEditor, fViewer, uDCUtils, uTempFileSystemFileSource, uLng, fDiffer, uDebug, DCOSUtils, uShowMsg, DCStrUtils, uFileSourceProperty, uWfxPluginCopyOutOperation, uFileSourceOperationOptions, uOperationsManager, uFileSourceOperationTypes, uMultiArchiveFileSource, fFileExecuteYourSelf, uFileProcs, uFileSystemFileSource; type { TWaitDataDouble } TWaitDataDouble = class(TWaitData) private FWaitData1, FWaitData2: TEditorWaitData; public constructor Create(WaitData1: TEditorWaitData; WaitData2: TEditorWaitData); procedure ShowWaitForm; override; procedure Done; override; destructor Destroy; override; end; { TViewerWaitThread } TViewerWaitThread = class(TThread) private FFileList : TStringList; FFileSource: IFileSource; protected procedure Execute; override; public constructor Create(const FilesToView: TStringList; const aFileSource: IFileSource); destructor Destroy; override; end; { TExtToolWaitThread } TExtToolWaitThread = class(TThread) private FExternalTool: TExternalTool; FFileList: TStringList; FWaitData: TWaitData; private procedure RunEditDone; procedure ShowWaitForm; protected procedure Execute; override; public constructor Create(ExternalTool: TExternalTool; const FileList: TStringList; WaitData: TWaitData); destructor Destroy; override; end; procedure RunExtTool(const ExtTool: TExternalToolOptions; sFileName: String); var sCmd: String; sParams: String = ''; begin sCmd := ExtTool.Path; sParams := ExtTool.Parameters; // If there is %p already configured in the parameter, we assume user configured it the way he wants. // This might be in non-common case where there are parameters AFTER the filename to open. // If there is not %p, let's do thing like legacy was and let's add the filename received as parameter. if (Pos('%p', sParams) = 0) and (Pos('%f', sParams) = 0) then begin sParams := ConcatenateStrWithSpace(sParams, '%' + ASCII_DLE); sParams := ConcatenateStrWithSpace(sParams, QuoteStr(sFileName)); end; ProcessExtCommandFork(sCmd, sParams, '', nil, ExtTool.RunInTerminal, ExtTool.KeepTerminalOpen); end; procedure RunExtDiffer(CompareList: TStringList); var i : Integer; sCmd: String; sParams:string=''; begin with gExternalTools[etDiffer] do begin sCmd := QuoteStr(ReplaceEnvVars(Path)); if Parameters <> EmptyStr then begin sParams := sParams + ' ' + Parameters; end; sParams := ConcatenateStrWithSpace(sParams, '%' + ASCII_DLE); for i := 0 to CompareList.Count - 1 do sParams := sParams + ' ' + QuoteStr(CompareList.Strings[i]); try ProcessExtCommandFork(sCmd, sParams, '', nil, RunInTerminal, KeepTerminalOpen); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningDiffer, rsMsgInvalidCommandLine + ' (' + rsToolDiffer + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; end; end; procedure ShowEditorByGlob(const sFileName: String); begin if gExternalTools[etEditor].Enabled then begin try RunExtTool(gExternalTools[etEditor], sFileName); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningEditor, rsMsgInvalidCommandLine + ' (' + rsToolEditor + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; end else ShowEditor(sFileName); end; procedure ShowEditorByGlob(WaitData: TEditorWaitData); var FileList: TStringList; begin if gExternalTools[etEditor].Enabled then begin FileList := TStringList.Create; try FileList.Add(WaitData.Files[0].FullPath); with TExtToolWaitThread.Create(etEditor, FileList, WaitData) do Start; finally FileList.Free end; end else begin ShowEditor(WaitData.Files[0].FullPath, WaitData); end; end; procedure ShowViewerByGlob(const sFileName: String); var sl:TStringList; begin if gExternalTools[etViewer].Enabled then begin try RunExtTool(gExternalTools[etViewer], sFileName); except on e: EInvalidCommandLine do MessageDlg(rsToolErrorOpeningViewer, rsMsgInvalidCommandLine + ' (' + rsToolViewer + '):' + LineEnding + e.Message, mtError, [mbOK], 0); end; end else begin sl:=TStringList.Create; try sl.Add(sFileName); ShowViewer(sl); finally FreeAndNil(sl); end; end; end; procedure ShowDifferByGlob(const LeftName, RightName: String); var sl: TStringList; begin if gExternalTools[etDiffer].Enabled then begin sl:= TStringList.Create; try sl.add(LeftName); sl.add(RightName); RunExtDiffer(sl); finally sl.free; end; end else ShowDiffer(LeftName, RightName); end; procedure ShowDifferByGlobList(const CompareList: TStringList; WaitData: TWaitData; Modal: Boolean = False); begin if gExternalTools[etDiffer].Enabled then begin if Assigned(WaitData) then with TExtToolWaitThread.Create(etDiffer, CompareList, WaitData) do Start else RunExtDiffer(CompareList); end else ShowDiffer(CompareList[0], CompareList[1], WaitData, Modal); end; procedure ShowViewerByGlobList(const FilesToView : TStringList; const aFileSource: IFileSource); var I : Integer; WaitThread : TViewerWaitThread; begin if gExternalTools[etViewer].Enabled then begin if aFileSource.IsClass(TTempFileSystemFileSource) then begin WaitThread := TViewerWaitThread.Create(FilesToView, aFileSource); WaitThread.Start; end else begin // TODO: If possible should run one instance of external viewer // with multiple file names as parameters. for i:=0 to FilesToView.Count-1 do RunExtTool(gExternalTools[etViewer], FilesToView.Strings[i]); end; end // gUseExtView else begin if aFileSource.IsClass(TTempFileSystemFileSource) then ShowViewer(FilesToView, TViewerWaitData.Create(aFileSource)) else ShowViewer(FilesToView); end; end; { TWaitData } procedure TWaitData.ShowOnTopAsync(Data: PtrInt); var Form: TCustomForm absolute Data; begin Form.ShowOnTop; end; procedure TWaitData.ShowOnTop(AForm: TCustomForm); var Data: PtrInt absolute AForm; begin Application.QueueAsyncCall(@ShowOnTopAsync, Data); end; { TViewerWaitData } constructor TViewerWaitData.Create(aFileSource: IFileSource); begin FFileSource:= aFileSource; end; destructor TViewerWaitData.Destroy; begin inherited Destroy; FFileSource:= nil; end; procedure TViewerWaitData.ShowWaitForm; begin end; procedure TViewerWaitData.Done; begin end; { TWaitDataDouble } constructor TWaitDataDouble.Create(WaitData1: TEditorWaitData; WaitData2: TEditorWaitData); begin FWaitData1 := WaitData1; FWaitData2 := WaitData2; end; procedure TWaitDataDouble.ShowWaitForm; begin try if Assigned(FWaitData1) then FWaitData1.ShowWaitForm; finally if Assigned(FWaitData2) then FWaitData2.ShowWaitForm; end; end; procedure TWaitDataDouble.Done; begin try if Assigned(FWaitData1) then FWaitData1.Done; finally FWaitData1 := nil; try if Assigned(FWaitData2) then FWaitData2.Done; finally FWaitData2 := nil; Free; end; end; end; destructor TWaitDataDouble.Destroy; begin inherited Destroy; if Assigned(FWaitData1) then FWaitData1.Free; if Assigned(FWaitData2) then FWaitData2.Free; end; { TEditorWaitData } constructor TEditorWaitData.Create(aCopyOutOperation: TFileSourceCopyOperation; Modal: Boolean = False); var I: Integer; aFileSource: ITempFileSystemFileSource; begin aFileSource := aCopyOutOperation.TargetFileSource as ITempFileSystemFileSource; TargetPath := aCopyOutOperation.SourceFiles.Path; Files := aCopyOutOperation.SourceFiles.Clone; ChangeFileListRoot(aFileSource.FileSystemRoot, Files); SetLength(FileTimes, Files.Count); for I := 0 to Files.Count - 1 do FileTimes[I] := mbFileAge(Files[I].FullPath); // Special case for bzip2 like archivers which don't store file size if Files.Count = 1 then Files[0].Size := mbFileSize(Files[0].FullPath); SourceFileSource := aFileSource; TargetFileSource := aCopyOutOperation.FileSource as IFileSource; FModal := Modal; end; destructor TEditorWaitData.Destroy; begin inherited Destroy; Files.Free; SourceFileSource:= nil; TargetFileSource:= nil; end; function TEditorWaitData.GetRelativeFileName(const FullPath: string): string; begin Result := ExtractDirLevel(IncludeTrailingPathDelimiter(Files.Path), FullPath); end; function TEditorWaitData.GetRelativeFileNames: string; var I: Integer; begin Result := GetRelativeFileName(Files[0].FullPath); for I := 1 to Files.Count - 1 do Result := Result + ', ' + GetRelativeFileName(Files[I].FullPath); end; function TEditorWaitData.GetFromPath: string; begin if StrBegins(TargetPath, TargetFileSource.CurrentAddress) then Result := TargetPath // Workaround for TGioFileSource else Result := TargetFileSource.CurrentAddress + TargetPath; end; procedure TEditorWaitData.ShowWaitForm; begin ShowFileEditExternal(GetRelativeFileNames, GetFromPath, Self, FModal); end; procedure TEditorWaitData.Done; var I: Integer; Msg: String; FileTime: TFileTime; DoNotFreeYet: Boolean = False; Operation: TFileSourceCopyOperation; begin try for I := Files.Count - 1 downto 0 do begin FileTime:= mbFileAge(Files[I].FullPath); if (FileTime = FileTimes[I]) or (not msgYesNo(Format(rsMsgCopyBackward, [GetRelativeFileName(Files[I].FullPath)]) + LineEnding + LineEnding + GetFromPath)) then begin Files.Delete(I); end else begin Files[I].ModificationTime:= FileTimeToDateTime(FileTime); end; end; // Files were modified if Files.Count > 0 then begin if (fsoCopyIn in TargetFileSource.GetOperationsTypes) and (not (TargetFileSource is TMultiArchiveFileSource)) then begin Operation:= TargetFileSource.CreateCopyInOperation(SourceFileSource, Files, TargetPath) as TFileSourceCopyOperation; // Copy files back if Assigned(Operation) then begin Operation.AddStateChangedListener([fsosStopped], @OnCopyInStateChanged); Operation.FileExistsOption:= fsoofeOverwrite; if FModal then OperationsManager.AddOperationModal(Operation) else OperationsManager.AddOperation(Operation); DoNotFreeYet:= True; // Will be free in operation end; end else begin Msg := rsMsgCouldNotCopyBackward + LineEnding; for I := 0 to Files.Count-1 do Msg := Msg + LineEnding + Files[I].FullPath; if msgYesNo(Msg) then (SourceFileSource as ITempFileSystemFileSource).DeleteOnDestroy:= False; end; end; finally if not DoNotFreeYet then Free; end; end; procedure TEditorWaitData.OnCopyInStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); var I: Integer; Msg: string; aFileSource: ITempFileSystemFileSource; aCopyOperation: TFileSourceCopyOperation; begin if (State = fsosStopped) then begin aCopyOperation := Operation as TFileSourceCopyOperation; aFileSource := aCopyOperation.SourceFileSource as ITempFileSystemFileSource; with aCopyOperation.RetrieveStatistics do begin if DoneFiles <> TotalFiles then begin Msg := rsMsgCouldNotCopyBackward + LineEnding; for I := 0 to aCopyOperation.SourceFiles.Count-1 do Msg := Msg + LineEnding + aCopyOperation.SourceFiles[I].FullPath; if msgYesNo(Operation.Thread, Msg) then begin aFileSource.DeleteOnDestroy:= False; end; end; end; Free; end; end; function TEditorWaitData.GetFileList: TStringList; var I: Integer; begin Result := TStringList.Create; for I := 0 to Files.Count - 1 do Result.Add(Files[I].FullPath); end; { TViewerModeData } constructor TViewerModeData.Create(AMode: Integer); begin FMode:= AMode; end; procedure TViewerModeData.OnCopyOutStateChanged( Operation: TFileSourceOperation; State: TFileSourceOperationState); var aFileList: TStringList; aFileSource: ITempFileSystemFileSource; aCopyOutOperation: TFileSourceCopyOperation; begin try if (State = fsosStopped) and (Operation.Result = fsorFinished) then begin aFileList := TStringList.Create; try aCopyOutOperation := Operation as TFileSourceCopyOperation; aFileSource := aCopyOutOperation.TargetFileSource as ITempFileSystemFileSource; ChangeFileListRoot(aFileSource.FileSystemRoot, aCopyOutOperation.SourceFiles); aFileList.Add(aCopyOutOperation.SourceFiles[0].FullPath); ShowViewer(aFileList, FMode, TViewerWaitData.Create(aFileSource)); finally aFileList.Free; end; end; finally Free; end; end; { TExtToolWaitThread } procedure TExtToolWaitThread.RunEditDone; begin FWaitData.Done; end; procedure TExtToolWaitThread.ShowWaitForm; begin FWaitData.ShowWaitForm; end; procedure TExtToolWaitThread.Execute; var I: Integer; StartTime: QWord; Process : TProcessUTF8; sCmd, sSecureEmptyStr: String; begin try Process := TProcessUTF8.Create(nil); try with gExternalTools[FExternalTool] do begin sCmd := ReplaceEnvVars(Path); // TProcess arguments must be enclosed with double quotes and not escaped. if RunInTerminal then begin sCmd := QuoteStr(sCmd); if Parameters <> EmptyStr then sCmd := sCmd + ' ' + Parameters; for I := 0 to FFileList.Count - 1 do sCmd := sCmd + ' ' + QuoteStr(FFileList[I]); sSecureEmptyStr := EmptyStr; // Let's play safe and don't let EmptyStr being passed as "VAR" parameter of "FormatTerminal" FormatTerminal(sCmd, sSecureEmptyStr, False); end else begin sCmd := '"' + sCmd + '"'; if Parameters <> EmptyStr then sCmd := sCmd + ' ' + Parameters; for I := 0 to FFileList.Count - 1 do sCmd := sCmd + ' "' + FFileList[I] + '"'; end; end; Process.CommandLine := sCmd; Process.Options := [poWaitOnExit]; StartTime:= GetTickCount64; Process.Execute; // If an editor closes within gEditWaitTime amount of milliseconds, // assume that it's a multiple document editor and show dialog where // user can confirm when editing has ended. if GetTickCount64 - StartTime < gEditWaitTime then begin Synchronize(@ShowWaitForm); end else begin Synchronize(@RunEditDone); end; finally Process.Free; end; except FWaitData.Free; end; end; constructor TExtToolWaitThread.Create(ExternalTool: TExternalTool; const FileList: TStringList; WaitData: TWaitData); begin inherited Create(True); FreeOnTerminate := True; FExternalTool := ExternalTool; FFileList := TStringList.Create; // Make a copy of list elements. FFileList.Assign(FileList); FWaitData := WaitData; end; destructor TExtToolWaitThread.Destroy; begin FFileList.Free; inherited Destroy; end; { TViewerWaitThread } constructor TViewerWaitThread.Create(const FilesToView: TStringList; const aFileSource: IFileSource); begin inherited Create(True); FreeOnTerminate := True; FFileList := TStringList.Create; // Make a copy of list elements. FFileList.Assign(FilesToView); FFileSource := aFileSource; end; destructor TViewerWaitThread.Destroy; begin if Assigned(FFileList) then FreeAndNil(FFileList); // Delete the temporary file source and all files inside. FFileSource := nil; inherited Destroy; end; procedure TViewerWaitThread.Execute; var Process : TProcessUTF8; sCmd, sSecureEmptyStr: String; begin Process := TProcessUTF8.Create(nil); with gExternalTools[etViewer] do begin sCmd := ReplaceEnvVars(Path); // TProcess arguments must be enclosed with double quotes and not escaped. if RunInTerminal then begin sCmd := QuoteStr(sCmd); if Parameters <> EmptyStr then sCmd := sCmd + ' ' + Parameters; sCmd := sCmd + ' ' + QuoteStr(FFileList.Strings[0]); sSecureEmptyStr := EmptyStr; //Let's play safe and don't let EmptyStr being passed as "VAR" parameter of "FormatTerminal" FormatTerminal(sCmd, sSecureEmptyStr, False); end else begin sCmd := '"' + sCmd + '"'; if Parameters <> EmptyStr then sCmd := sCmd + ' ' + Parameters; sCmd := sCmd + ' "' + FFileList.Strings[0] + '"'; end; end; Process.CommandLine := sCmd; Process.Options := [poWaitOnExit]; Process.Execute; Process.Free; end; { PrepareData } function PrepareData(FileSource: IFileSource; var SelectedFiles: TFiles; FunctionToCall: TFileSourceOperationStateChangedNotify; Modal: Boolean = False): TPrepareDataResult; var I: Integer; aFile: TFile; Directory: String; TempFiles: TFiles = nil; TempFileSource: ITempFileSystemFileSource = nil; Operation: TFileSourceOperation; begin // If files are links to local files if (fspLinksToLocalFiles in FileSource.Properties) then begin for I := 0 to SelectedFiles.Count - 1 do begin aFile := SelectedFiles[I]; FileSource.GetLocalName(aFile); end; end // If files not directly accessible copy them to temp file source. else if not (fspDirectAccess in FileSource.Properties) then begin if not (fsoCopyOut in FileSource.GetOperationsTypes) then begin msgWarning(rsMsgErrNotSupported); Exit(pdrFailed); end; Directory := GetTempName(GetTempFolderDeletableAtTheEnd, EmptyStr); if not mbForceDirectory(Directory) then begin MessageDlg(mbSysErrorMessage(GetLastOSError), mtError, [mbOK], 0); Exit(pdrFailed); end; TempFileSource := TTempFileSystemFileSource.Create(Directory); TempFiles := SelectedFiles.Clone; try Operation := FileSource.CreateCopyOutOperation( TempFileSource, TempFiles, TempFileSource.FileSystemRoot); if Operation is TWfxPluginCopyOutOperation then (Operation as TWfxPluginCopyOutOperation).NeedsConnection := False; // use separate connection finally TempFiles.Free; end; if not Assigned(Operation) then begin msgWarning(rsMsgErrNotSupported); Exit(pdrFailed); end; Operation.AddStateChangedListener([fsosStopped], FunctionToCall); if Modal then OperationsManager.AddOperationModal(Operation) else OperationsManager.AddOperation(Operation); Exit(pdrInCallback); end; Exit(pdrSynchronous); end; { TToolDataPreparator } type TToolDataPreparator = class protected FFunc: TToolDataPreparedProc; FCallOnFail: Boolean; procedure OnCopyOutStateChanged(Operation: TFileSourceOperation; State: TFileSourceOperationState); public constructor Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False); procedure Prepare(FileSource: IFileSource; var SelectedFiles: TFiles); end; constructor TToolDataPreparator.Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False); begin FFunc := FunctionToCall; FCallOnFail := CallOnFail; end; procedure TToolDataPreparator.Prepare(FileSource: IFileSource; var SelectedFiles: TFiles); var I: Integer; FileList: TStringList; begin case PrepareData(FileSource, SelectedFiles, @OnCopyOutStateChanged) of pdrSynchronous: try FileList := TStringList.Create; for I := 0 to SelectedFiles.Count - 1 do FileList.Add(SelectedFiles[i].FullPath); FFunc(FileList, nil); finally Free; end; pdrFailed: try if FCallOnFail then FFunc(nil, nil); finally Free; end; end; end; procedure TToolDataPreparator.OnCopyOutStateChanged( Operation: TFileSourceOperation; State: TFileSourceOperationState); var WaitData: TEditorWaitData; begin if (State <> fsosStopped) then Exit; try if Operation.Result = fsorFinished then begin WaitData := TEditorWaitData.Create(Operation as TFileSourceCopyOperation); FFunc(WaitData.GetFileList, WaitData); end else begin if FCallOnFail then FFunc(nil, nil); end; finally Free; end; end; { TToolDataPreparator2 } type TToolDataPreparator2 = class protected FFunc: TToolDataPreparedProc; FCallOnFail: Boolean; FModal: Boolean; FFailed: Boolean; FFileList1: TStringList; FFileList2: TStringList; FPrepared1: Boolean; FPrepared2: Boolean; FWaitData1: TEditorWaitData; FWaitData2: TEditorWaitData; procedure OnCopyOutStateChanged1(Operation: TFileSourceOperation; State: TFileSourceOperationState); procedure OnCopyOutStateChanged2(Operation: TFileSourceOperation; State: TFileSourceOperationState); procedure TryFinish; public constructor Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False); procedure Prepare(FileSource1: IFileSource; var SelectedFiles1: TFiles; FileSource2: IFileSource; var SelectedFiles2: TFiles; Modal: Boolean = False); destructor Destroy; override; end; constructor TToolDataPreparator2.Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False); begin FFunc := FunctionToCall; FCallOnFail := CallOnFail; end; procedure TToolDataPreparator2.Prepare(FileSource1: IFileSource; var SelectedFiles1: TFiles; FileSource2: IFileSource; var SelectedFiles2: TFiles; Modal: Boolean = False); var I: Integer; begin FModal := Modal; case PrepareData(FileSource1, SelectedFiles1, @OnCopyOutStateChanged1, Modal) of pdrSynchronous: begin FFileList1 := TStringList.Create; for I := 0 to SelectedFiles1.Count - 1 do FFileList1.Add(SelectedFiles1[I].FullPath); FPrepared1 := True; end; pdrFailed: begin try if FCallOnFail then FFunc(nil, nil, FModal); finally Free; end; Exit; end; end; case PrepareData(FileSource2, SelectedFiles2, @OnCopyOutStateChanged2, Modal) of pdrSynchronous: begin FFileList2 := TStringList.Create; for I := 0 to SelectedFiles2.Count - 1 do FFileList2.Add(SelectedFiles2[I].FullPath); FPrepared2 := True; TryFinish; end; pdrFailed: begin FPrepared2 := True; FFailed := True; TryFinish; end; end; end; procedure TToolDataPreparator2.OnCopyOutStateChanged1( Operation: TFileSourceOperation; State: TFileSourceOperationState); begin if (State <> fsosStopped) then Exit; FPrepared1 := True; if not FFailed then begin if Operation.Result = fsorFinished then begin FWaitData1 := TEditorWaitData.Create(Operation as TFileSourceCopyOperation, FModal); FFileList1 := FWaitData1.GetFileList; end else begin FFailed := True; // if not FPrepared2 and Assigned(FOperation2) then // FOperation2.Stop(); end; end; TryFinish; end; procedure TToolDataPreparator2.OnCopyOutStateChanged2( Operation: TFileSourceOperation; State: TFileSourceOperationState); begin if (State <> fsosStopped) then Exit; FPrepared2 := True; if not FFailed then begin if Operation.Result = fsorFinished then begin FWaitData2 := TEditorWaitData.Create(Operation as TFileSourceCopyOperation, FModal); FFileList2 := FWaitData2.GetFileList; end else begin FFailed := True; // if not FPrepared1 and Assigned(FOperation1) then // FOperation1.Stop(); end; end; TryFinish; end; procedure TToolDataPreparator2.TryFinish; var s: string; WaitData: TWaitDataDouble; begin if FPrepared1 and FPrepared2 then try if FFailed then begin if FCallOnFail then FFunc(nil, nil, FModal); Exit; end; if Assigned(FFileList2) then for s in FFileList2 do FFileList1.Append(s); if Assigned(FWaitData1) or Assigned(FWaitData2) then begin WaitData := TWaitDataDouble.Create(FWaitData1, FWaitData2); FWaitData1 := nil; FWaitData2 := nil; FFunc(FFileList1, WaitData, FModal); end else FFunc(FFileList1, nil, FModal); finally Free; end; end; destructor TToolDataPreparator2.Destroy; begin inherited Destroy; if Assigned(FFileList1) then FFileList1.Free; if Assigned(FFileList2) then FFileList2.Free; if Assigned(FWaitData1) then FWaitData1.Free; if Assigned(FWaitData2) then FWaitData2.Free; end; procedure PrepareToolData(FileSource: IFileSource; var SelectedFiles: TFiles; FunctionToCall: TToolDataPreparedProc); begin with TToolDataPreparator.Create(FunctionToCall) do Prepare(FileSource, SelectedFiles); end; procedure PrepareToolData(FileSource1: IFileSource; var SelectedFiles1: TFiles; FileSource2: IFileSource; var SelectedFiles2: TFiles; FunctionToCall: TToolDataPreparedProc); begin with TToolDataPreparator2.Create(FunctionToCall) do Prepare(FileSource1, SelectedFiles1, FileSource2, SelectedFiles2); end; procedure PrepareToolData(FileSource1: IFileSource; File1: TFile; FileSource2: IFileSource; File2: TFile; FunctionToCall: TToolDataPreparedProc; Modal: Boolean = False); var Files1, Files2: TFiles; begin Files1 := TFiles.Create(File1.Path); try Files1.Add(File1.Clone); Files2 := TFiles.Create(File2.Path); try Files2.Add(File2.Clone); with TToolDataPreparator2.Create(FunctionToCall) do Prepare(FileSource1, Files1, FileSource2, Files2, Modal); finally Files2.Free; end; finally Files1.Free; end; end; end. doublecmd-1.1.22/src/uspecialdir.pas0000644000175000001440000007646614743153644016431 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Working with SpecialDir Copyright (C) 2009-2016 Alexander Koblov (alexx2000@mail.ru) 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 -This unit has been added in 2014. -Inspired a lot from "usearchtemplate" -Icon used for button to work with path is called "folder_wrench.png" and was taken from "http://www.famfamfam.com/lab/icons/silk/". It is already mentionned in the "about" section of the application that icons are coming from this site. } unit uSpecialDir; {$mode objfpc}{$H+} interface uses Menus, Classes, SysUtils; const TAGOFFSET_FORHOTDIRUSEINPATHHELPER = $10000; TAGOFFSET_FORHOTDIRRELATIVEINPATHHELPER = $20000; type { TKindOfPathFile } TKindOfPathFile = (pfFILE, pfPATH); { TKindOfSpecialDir } TKindOfSpecialDir = (sd_NULL, sd_DOUBLECOMMANDER, sd_WINDOWSTC, sd_WINDOWSNONTC, sd_ENVIRONMENTVARIABLE); { TKindSpecialDirMenuPopulation } TKindSpecialDirMenuPopulation = (mp_PATHHELPER, mp_CHANGEDIR); { TProcedureWithJustASender } TProcedureWithJustASender = procedure(Sender: TObject) of Object; { TSpecialDir } TSpecialDir = class private fDispatcher: TKindOfSpecialDir; fVariableName: string; fPathValue: string; public constructor Create; property Dispatcher: TKindOfSpecialDir read fDispatcher write fDispatcher; property VariableName: string read fVariableName write fVariableName; property PathValue: string read fPathValue write fPathValue; end; { TSpecialDirList } TSpecialDirList = class(TList) private fIndexOfSpecialDirComptibleTC:longint; //Index of first windows SpecialDir compatible with TC fIndexOfNewVariableNotInTC:longint; //Index of first SpecialDir non-compatible TC fIndexOfEnvironmentVariable:longint; //Index of first EnvironmentVariable fRecipientComponent:TComponent; fRecipientType:TKindOfPathFile; function GetSpecialDir(Index: Integer): TSpecialDir; public constructor Create; procedure Clear; override; procedure PopulateMenuWithSpecialDir(mncmpMenuComponentToPopulate:TComponent; KindSpecialDirMenuPopulation:TKindSpecialDirMenuPopulation; ProcedureIfChangeDirClick:TProcedureWithJustASender); procedure SpecialDirMenuClick(Sender: TObject); procedure PopulateSpecialDir; procedure SetSpecialDirRecipientAndItsType(ParamComponent:TComponent; ParamKindOfPathFile:TKindOfPathFile); property SpecialDir[Index: Integer]: TSpecialDir read GeTSpecialDir; property IndexOfSpecialDirComptibleTC: longint read fIndexOfSpecialDirComptibleTC write fIndexOfSpecialDirComptibleTC; //Index of first windows Special Dir compatible with TC property IndexOfNewVariableNotInTC: longint read fIndexOfNewVariableNotInTC write fIndexOfNewVariableNotInTC; //Index of first non-compatible Total Commander path property IndexOfEnvironmentVariable: longint read fIndexOfEnvironmentVariable write fIndexOfEnvironmentVariable; //Index of first EnvironmentVariable end; function GetMenuCaptionAccordingToOptions(const WantedCaption:string; const MatchingPath:string):string; procedure LoadWindowsSpecialDir; implementation uses //Lazarus, Free-Pascal, etc. EditBtn, Dialogs, ExtCtrls, StrUtils, StdCtrls, lazutf8, {$IFDEF MSWINDOWS} ShlObj, uShellFolder, {$ENDIF} //DC DCOSUtils, uDCUtils, uGlobsPaths, fmain, uLng, uGlobs, uHotDir, uOSUtils, DCStrUtils; { The special path are sorted first by type of special path they represent (DC, Windows, Environment...) Then, by alphabetical order. But also, the most commun useful path could be placed first to be more user friendly.} function CompareSpecialDir(Item1,Item2:Pointer):integer; function GetWeigth(sSpecialDir:string):longint; begin result:=10; if sSpecialDir='%$PERSONAL%' then result:=1; if sSpecialDir='%$DESKTOP%' then result:=2; if sSpecialDir='%$APPDATA%' then result:=3; end; var Weight1,Weight2:longint; begin if TSpecialDir(Item1).Dispatcher<>TSpecialDir(Item2).Dispatcher then begin if TSpecialDir(Item1).DispatcherWeight2 then begin if Weight1'-') AND (ProcedureWhenClickOnMenuItem<>nil) then begin miMainTree.Tag:=TagForMenuItem; miMainTree.OnClick:=ProcedureWhenClickOnMenuItem; end; if mncmpMenuComponentToPopulate.ClassType=TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType=TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); end; procedure AddToSubMenu(ParamMenuItem:TMenuItem; TagRequested:longint; ProcedureWhenClickOnMenuItem:TProcedureWhenClickOnMenuItem); var localmi:TMenuItem; begin localmi:=TMenuItem.Create(ParamMenuItem); localmi.Caption:=GetMenuCaptionAccordingToOptions(SpecialDir[IndexVariable].VariableName,SpecialDir[IndexVariable].PathValue); localmi.tag:=TagRequested; localmi.OnClick:=ProcedureWhenClickOnMenuItem; ParamMenuItem.Add(localmi); end; procedure AddBatchOfMenuItems(SubMenuTitle:string; StartingIndex,StopIndex,TagOffset:longint; ProcedureWhenClickOnMenuItem:TProcedureWhenClickOnMenuItem); begin if StopIndex>StartingIndex then begin miMainTree:=TMenuItem.Create(mncmpMenuComponentToPopulate); miMainTree.Caption:=SubMenuTitle; if mncmpMenuComponentToPopulate.ClassType=TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree) else if mncmpMenuComponentToPopulate.ClassType=TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree); IndexVariable:=StartingIndex; while IndexVariableSubWorkingPath then result:=IncludeTrailingPathDelimiter(WindowsVariableName)+MaybeSubstitionPossible; end; var Dispatcher:longint; //Indicate wich menuitem user selected RememberFilename, OriginalPath, MaybeResultingOutputPath, sSelectedPath:string; begin with Sender as TComponent do Dispatcher:=tag; OriginalPath:=''; if fRecipientComponent.ClassType=TLabeledEdit then OriginalPath:=TLabeledEdit(fRecipientComponent).Text else if fRecipientComponent.ClassType=TFileNameEdit then OriginalPath:=TFileNameEdit(fRecipientComponent).FileName else if fRecipientComponent.ClassType=TEdit then OriginalPath:=TEdit(fRecipientComponent).Text else if fRecipientComponent.ClassType=TDirectoryEdit then OriginalPath:=TDirectoryEdit(fRecipientComponent).Text; if fRecipientType=pfFILE then begin RememberFilename:=ExtractFilename(OriginalPath); OriginalPath:=ExtractFilePath(OriginalPath); end; MaybeResultingOutputPath:=OriginalPath; //Let's play safe: returned path, by default, if nothing is trig, is the same as the original one, so, no change... case Dispatcher of 1: //Make path absolute begin MaybeResultingOutputPath:=mbExpandFileName(OriginalPath); end; 2: //Add path from active frame begin MaybeResultingOutputPath:=frmMain.ActiveFrame.CurrentLocation; end; 3: //Add path from inactive frame begin MaybeResultingOutputPath:=frmMain.NotActiveFrame.CurrentLocation; end; 4: //Browse and use selected path begin //by default, let's try to initialise dir browser to current dir value and if it's not present, let's take the current path of the active frame if MaybeResultingOutputPath='' then MaybeResultingOutputPath:=frmMain.ActiveFrame.CurrentPath; if SelectDirectory(rsSelectDir, mbExpandFileName(MaybeResultingOutputPath), sSelectedPath, False) then MaybeResultingOutputPath:=sSelectedPath; end; 100..1099: //Use... begin MaybeResultingOutputPath:=gSpecialDirList.SpecialDir[Dispatcher-100].VariableName; end; 1100..2099: //Make relative to... begin MaybeResultingOutputPath:=GetCorrectPathForHotDirFromHints(OriginalPath,gSpecialDirList.SpecialDir[Dispatcher-1100].VariableName,gSpecialDirList.SpecialDir[Dispatcher-1100].PathValue); end; TAGOFFSET_FORHOTDIRUSEINPATHHELPER..(TAGOFFSET_FORHOTDIRUSEINPATHHELPER+$FFFF): begin MaybeResultingOutputPath:=gDirectoryHotlist.HotDir[Dispatcher-TAGOFFSET_FORHOTDIRUSEINPATHHELPER].HotDirPath; end; TAGOFFSET_FORHOTDIRRELATIVEINPATHHELPER..(TAGOFFSET_FORHOTDIRRELATIVEINPATHHELPER+$FFFF): begin MaybeResultingOutputPath:=GetCorrectPathForHotDirFromHints(OriginalPath,gDirectoryHotlist.HotDir[Dispatcher-TAGOFFSET_FORHOTDIRRELATIVEINPATHHELPER].HotDirPath,gDirectoryHotlist.HotDir[Dispatcher-TAGOFFSET_FORHOTDIRRELATIVEINPATHHELPER].HotDirPath); end; end; if (MaybeResultingOutputPath<>'') then MaybeResultingOutputPath:=IncludeTrailingPathDelimiter(MaybeResultingOutputPath); if fRecipientType=pfFILE then MaybeResultingOutputPath:=MaybeResultingOutputPath+RememberFilename; if lowercase(OriginalPath)<>lowercase(MaybeResultingOutputPath) then begin if fRecipientComponent.ClassType=TLabeledEdit then TLabeledEdit(fRecipientComponent).Text:=MaybeResultingOutputPath else if fRecipientComponent.ClassType=TFileNameEdit then TFileNameEdit(fRecipientComponent).FileName:=MaybeResultingOutputPath else if fRecipientComponent.ClassType=TEdit then TEdit(fRecipientComponent).Text:=MaybeResultingOutputPath else if fRecipientComponent.ClassType=TDirectoryEdit then TDirectoryEdit(fRecipientComponent).Text:=MaybeResultingOutputPath; end; end; { TSpecialDirList.PopulateSpecialDir } procedure TSpecialDirList.PopulateSpecialDir; var NbOfEnvVar, IndexVar, EqualPos:integer; EnvVar, EnvValue:string; LocalSpecialDir:TSpecialDir; MyYear,MyMonth,MyDay:word; {$IFDEF MSWINDOWS} procedure GetAndStoreSpecialDirInfos(SpecialConstant:integer; VariableName:string; ParamKindOfSpecialDir: TKindOfSpecialDir); var FilePath: array [0..Pred(MAX_PATH)] of WideChar; begin FillChar(FilePath, MAX_PATH, 0); SHGetSpecialFolderPathW(0, @FilePath[0], SpecialConstant, FALSE); if FilePath<>'' then begin LocalSpecialDir:=TSpecialDir.Create; LocalSpecialDir.fDispatcher:=ParamKindOfSpecialDir; LocalSpecialDir.VariableName:=VariableName; LocalSpecialDir.PathValue:= UTF16ToUTF8(UnicodeString(FilePath)); Add(LocalSpecialDir); end; end; procedure GetAndStoreKnownDirInfos(const rfid: TGUID; VariableName: String; ParamKindOfSpecialDir: TKindOfSpecialDir); var FilePath: String; begin if GetKnownFolderPath(rfid, FilePath) then begin LocalSpecialDir:= TSpecialDir.Create; LocalSpecialDir.fDispatcher:= ParamKindOfSpecialDir; LocalSpecialDir.VariableName:= VariableName; LocalSpecialDir.PathValue:= FilePath; Add(LocalSpecialDir); end; end; {$ENDIF} begin //Since in configuration we might need to recall this routine, let's clear the list if gSpecialDirList.Count>0 then gSpecialDirList.Clear; LocalSpecialDir:=TSpecialDir.Create; LocalSpecialDir.fDispatcher:=sd_DOUBLECOMMANDER; LocalSpecialDir.VariableName:=VARDELIMITER+'COMMANDER_PATH'+VARDELIMITER_END; LocalSpecialDir.PathValue:=ExcludeTrailingPathDelimiter(gpExePath); Add(LocalSpecialDir); LocalSpecialDir:=TSpecialDir.Create; LocalSpecialDir.fDispatcher:=sd_DOUBLECOMMANDER; LocalSpecialDir.VariableName:=VARDELIMITER+'DC_CONFIG_PATH'+VARDELIMITER_END; LocalSpecialDir.PathValue:=ExcludeTrailingPathDelimiter(gpCfgDir); Add(LocalSpecialDir); LocalSpecialDir:=TSpecialDir.Create; LocalSpecialDir.fDispatcher:=sd_DOUBLECOMMANDER; LocalSpecialDir.VariableName:=ENVVARTODAYSDATE; LocalSpecialDir.PathValue:=Format('%d-%2.2d-%2.2d',[1980,01,01]); //Don't worry for the exact date: the routine "ReplaceEnvVars" will substitue for the correct date value Add(LocalSpecialDir); DecodeDate(now,MyYear,MyMonth,MyDay); LocalSpecialDir:=TSpecialDir.Create; LocalSpecialDir.fDispatcher:=sd_DOUBLECOMMANDER; LocalSpecialDir.VariableName:=VARDELIMITER+'CURRENTUSER'+VARDELIMITER_END; LocalSpecialDir.PathValue:=GetCurrentUserName; Add(LocalSpecialDir); IndexOfSpecialDirComptibleTC:=count; {$IFDEF MSWINDOWS} //Done with the help of: http://stackoverflow.com/questions/471123/accessing-localapplicationdata-equivalent-in-delphi //Also with the help of: http://www.ghisler.ch/board/viewtopic.php?t=12709 //The following ones are compatible with Total Commander //The first three ones are the most susceptible to be used so to speed up time when searching, we'll placed them first in the list //Please note that TC is using this convention for variable name: %$varname% GetAndStoreSpecialDirInfos(CSIDL_PERSONAL,'%$PERSONAL%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_DESKTOP,'%$DESKTOP%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_APPDATA,'%$APPDATA%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_APPDATA,'%$COMMON_APPDATA%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_DESKTOPDIRECTORY,'%$COMMON_DESKTOPDIRECTORY%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_DOCUMENTS,'%$COMMON_DOCUMENTS%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_PICTURES,'%$COMMON_PICTURES%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_PROGRAMS,'%$COMMON_PROGRAMS%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_STARTMENU,'%$COMMON_STARTMENU%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_COMMON_STARTUP,'%$COMMON_STARTUP%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_FONTS,'%$FONTS%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_LOCAL_APPDATA,'%$LOCAL_APPDATA%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_MYMUSIC,'%$MYMUSIC%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_MYPICTURES,'%$MYPICTURES%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_MYVIDEO,'%$MYVIDEO%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_PROGRAMS,'%$PROGRAMS%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_STARTMENU,'%$STARTMENU%',sd_WINDOWSTC); GetAndStoreSpecialDirInfos(CSIDL_STARTUP,'%$STARTUP%',sd_WINDOWSTC); if Win32MajorVersion > 5 then begin GetAndStoreKnownDirInfos(FOLDERID_AccountPictures, '%$AccountPictures%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_CameraRoll, '%$CameraRoll%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Contacts, '%$Contacts%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_DeviceMetadataStore, '%$DeviceMetadataStore%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Downloads, '%$Downloads%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_GameTasks, '%$GameTasks%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_ImplicitAppShortcuts, '%$ImplicitAppShortcuts%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Libraries, '%$Libraries%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Links, '%$Links%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_LocalAppDataLow, '%$LocalAppDataLow%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_OriginalImages, '%$OriginalImages%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_PhotoAlbums, '%$PhotoAlbums%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Playlists, '%$Playlists%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_ProgramFilesCommonX64, '%$ProgramFilesCommonX64%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_ProgramFilesX64, '%$ProgramFilesX64%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Public, '%$Public%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_PublicDownloads, '%$PublicDownloads%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_PublicGameTasks, '%$PublicGameTasks%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_PublicLibraries, '%$PublicLibraries%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_PublicRingtones, '%$PublicRingtones%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_PublicUserTiles, '%$PublicUserTiles%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_QuickLaunch, '%$QuickLaunch%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Ringtones, '%$Ringtones%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_RoamedTileImages, '%$RoamedTileImages%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_RoamingTiles, '%$RoamingTiles%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SampleMusic, '%$SampleMusic%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SamplePictures, '%$SamplePictures%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SamplePlaylists, '%$SamplePlaylists%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SampleVideos, '%$SampleVideos%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SavedGames, '%$SavedGames%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SavedPictures, '%$SavedPictures%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SavedSearches, '%$SavedSearches%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_Screenshots, '%$Screenshots%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SearchHistory, '%$SearchHistory%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SearchTemplates, '%$SearchTemplates%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SidebarDefaultParts, '%$SidebarDefaultParts%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SidebarParts, '%$SidebarParts%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SkyDrive, '%$SkyDrive%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SkyDriveCameraRoll, '%$SkyDriveCameraRoll%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SkyDriveDocuments, '%$SkyDriveDocuments%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_SkyDrivePictures, '%$SkyDrivePictures%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_UserPinned, '%$UserPinned%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_UserProfiles, '%$UserProfiles%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_UserProgramFiles, '%$UserProgramFiles%', sd_WINDOWSTC); GetAndStoreKnownDirInfos(FOLDERID_UserProgramFilesCommon, '%$UserProgramFilesCommon%', sd_WINDOWSTC); end; //These ones are new ones non-compatible on 2014-05-21 with Total Commander IndexOfNewVariableNotInTC:=count; GetAndStoreSpecialDirInfos(CSIDL_ADMINTOOLS,'%$ADMINTOOLS%',sd_WINDOWSNONTC); // { \Start Menu\Programs\Administrative Tools } GetAndStoreSpecialDirInfos(CSIDL_ALTSTARTUP,'%$ALTSTARTUP%',sd_WINDOWSNONTC); //{ non localized startup } GetAndStoreSpecialDirInfos(CSIDL_BITBUCKET,'%$BITBUCKET%',sd_WINDOWSNONTC); //{ \Recycle Bin } GetAndStoreSpecialDirInfos(CSIDL_CDBURN_AREA,'%$CDBURN_AREA%',sd_WINDOWSNONTC); // { USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning } GetAndStoreSpecialDirInfos(CSIDL_COMMON_ADMINTOOLS,'%$COMMON_ADMINTOOLS%',sd_WINDOWSNONTC); // { All Users\Start Menu\Programs\Administrative Tools } GetAndStoreSpecialDirInfos(CSIDL_COMMON_ALTSTARTUP,'%$COMMON_ALTSTARTUP%',sd_WINDOWSNONTC); // { non localized common startup } GetAndStoreSpecialDirInfos(CSIDL_COMMON_FAVORITES,'%$COMMON_FAVORITES%',sd_WINDOWSNONTC); // GetAndStoreSpecialDirInfos(CSIDL_COMMON_MUSIC,'%$COMMON_MUSIC%',sd_WINDOWSNONTC); // { All Users\My Music } GetAndStoreSpecialDirInfos(CSIDL_COMMON_OEM_LINKS,'%$COMMON_OEM_LINKS%',sd_WINDOWSNONTC); // { Links to All Users OEM specific apps } GetAndStoreSpecialDirInfos(CSIDL_COMMON_TEMPLATES,'%$COMMON_TEMPLATES%',sd_WINDOWSNONTC); // { All Users\Templates } GetAndStoreSpecialDirInfos(CSIDL_COMMON_VIDEO,'%$COMMON_VIDEO%',sd_WINDOWSNONTC); // { All Users\My Video } GetAndStoreSpecialDirInfos(CSIDL_COMPUTERSNEARME,'%$COMPUTERSNEARME%',sd_WINDOWSNONTC); // { Computers Near Me (computered from Workgroup membership) } GetAndStoreSpecialDirInfos(CSIDL_CONNECTIONS,'%$CONNECTIONS%',sd_WINDOWSNONTC); // { Network and Dial-up Connections } GetAndStoreSpecialDirInfos(CSIDL_CONTROLS,'%$CONTROLS%',sd_WINDOWSNONTC); //{ My Computer\Control Panel } GetAndStoreSpecialDirInfos(CSIDL_COOKIES,'%$COOKIES%',sd_WINDOWSNONTC); // GetAndStoreSpecialDirInfos(CSIDL_DESKTOPDIRECTORY,'%$DESKTOPDIRECTORY%',sd_WINDOWSNONTC); //{ \Desktop } GetAndStoreSpecialDirInfos(CSIDL_DRIVES,'%$DRIVES%',sd_WINDOWSNONTC); //{ My Computer } GetAndStoreSpecialDirInfos(CSIDL_FAVORITES,'%$FAVORITES%',sd_WINDOWSNONTC); //{ \Favorites } GetAndStoreSpecialDirInfos(CSIDL_HISTORY,'%$HISTORY%',sd_WINDOWSNONTC); // GetAndStoreSpecialDirInfos(CSIDL_INTERNET,'%$INTERNET%',sd_WINDOWSNONTC); //{ Internet Explorer (icon on desktop) } GetAndStoreSpecialDirInfos(CSIDL_INTERNET_CACHE,'%$INTERNET_CACHE%',sd_WINDOWSNONTC); // GetAndStoreSpecialDirInfos(CSIDL_NETHOOD,'%$NETHOOD%',sd_WINDOWSNONTC); //{ \nethood } GetAndStoreSpecialDirInfos(CSIDL_NETWORK,'%$NETWORK%',sd_WINDOWSNONTC); //{ Network Neighborhood (My Network Places) } GetAndStoreSpecialDirInfos(CSIDL_PERSONAL,'%$PERSONALXP%',sd_WINDOWSNONTC); //{ My Documents. This is equivalent to CSIDL_MYDOCUMENTS in XP and above } GetAndStoreSpecialDirInfos(CSIDL_PRINTERS,'%$PRINTERS%',sd_WINDOWSNONTC); //{ My Computer\Printers } GetAndStoreSpecialDirInfos(CSIDL_PRINTHOOD,'%$PRINTHOOD%',sd_WINDOWSNONTC); //{ \PrintHood } GetAndStoreSpecialDirInfos(CSIDL_PROFILE,'%$PROFILE%',sd_WINDOWSNONTC); // { USERPROFILE } //GetAndStoreSpecialDirInfos(CSIDL_PROFILES,'%PROFILES%'); //Does not work everywhere, let's remove it. GetAndStoreSpecialDirInfos(CSIDL_PROGRAM_FILES,'%$PROGRAM_FILES%',sd_WINDOWSNONTC); // { C:\Program Files } GetAndStoreSpecialDirInfos(CSIDL_PROGRAM_FILESX86,'%$PROGRAM_FILESX86%',sd_WINDOWSNONTC); // { x86 C:\Program Files on RISC } GetAndStoreSpecialDirInfos(CSIDL_PROGRAM_FILES_COMMON,'%$PROGRAM_FILES_COMMON%',sd_WINDOWSNONTC); // { C:\Program Files\Common } GetAndStoreSpecialDirInfos(CSIDL_PROGRAM_FILES_COMMONX86,'%$PROGRAM_FILES_COMMONX86%',sd_WINDOWSNONTC); // { x86 C:\Program Files\Common on RISC } GetAndStoreSpecialDirInfos(CSIDL_RECENT,'%$RECENT%',sd_WINDOWSNONTC); //{ \Recent } GetAndStoreSpecialDirInfos(CSIDL_RESOURCES,'%$RESOURCES%',sd_WINDOWSNONTC); // { Resource Directory } GetAndStoreSpecialDirInfos(CSIDL_RESOURCES_LOCALIZED,'%$RESOURCES_LOCALIZED%',sd_WINDOWSNONTC); // { Localized Resource Directory } GetAndStoreSpecialDirInfos(CSIDL_SENDTO,'%$SENDTO%',sd_WINDOWSNONTC); //{ \SendTo } GetAndStoreSpecialDirInfos(CSIDL_SYSTEM,'%$SYSTEM%',sd_WINDOWSNONTC); // { GetSystemDirectory() } GetAndStoreSpecialDirInfos(CSIDL_SYSTEMX86,'%$SYSTEMX86%',sd_WINDOWSNONTC); //{ x86 system directory on RISC } GetAndStoreSpecialDirInfos(CSIDL_TEMPLATES,'%$TEMPLATES%',sd_WINDOWSNONTC); // GetAndStoreSpecialDirInfos(CSIDL_WINDOWS,'%$WINDOWS%',sd_WINDOWSNONTC); // { GetWindowsDirectory() } if Win32MajorVersion > 5 then begin GetAndStoreKnownDirInfos(FOLDERID_ApplicationShortcuts, '%$ApplicationShortcuts%', sd_WINDOWSNONTC); end; {$ENDIF} IndexOfEnvironmentVariable:=count; //Let's store environment variable. It will be possible to search in faster eventually, if required NbOfEnvVar:= GetEnvironmentVariableCount; if NbOfEnvVar>0 then begin for IndexVar:= 1 to NbOfEnvVar do begin EnvVar:= mbGetEnvironmentString(IndexVar); EqualPos:= PosEx('=', EnvVar, 2); if EqualPos <> 0 then begin EnvValue:=copy(EnvVar, EqualPos + 1, MaxInt); {$IFDEF MSWINDOWS} if (not gShowOnlyValidEnv) OR (ExtractFileDrive(EnvValue)<>'') then {$ELSE} if (not gShowOnlyValidEnv) OR (UTF8LeftStr(EnvValue,1)=PathDelim) then {$ENDIF} begin LocalSpecialDir:=TSpecialDir.Create; LocalSpecialDir.fDispatcher:=sd_ENVIRONMENTVARIABLE; LocalSpecialDir.VariableName:=VARDELIMITER+copy(EnvVar, 1, EqualPos - 1)+VARDELIMITER_END; LocalSpecialDir.PathValue:=ExcludeTrailingPathDelimiter(EnvValue); // Other path variable values, like the few from DC or the ones from Windows, don't have the trailing path delimiter. So we do the same with path from environment variables. Add(LocalSpecialDir); end; end; end; end; Sort(@CompareSpecialDir); end; { TSpecialDirList.SetSpecialDirRecipientAndItsType } procedure TSpecialDirList.SetSpecialDirRecipientAndItsType(ParamComponent:TComponent; ParamKindOfPathFile:TKindOfPathFile); begin fRecipientComponent:=ParamComponent; fRecipientType:=ParamKindOfPathFile; end; function GetMenuCaptionAccordingToOptions(const WantedCaption:string; const MatchingPath:string):string; begin result:=WantedCaption; if gShowPathInPopup then begin if UTF8length(MatchingPath)<100 then result:=result + ' - ['+IncludeTrailingPathDelimiter(MatchingPath)+']' else result:=result + ' - ['+IncludeTrailingPathDelimiter('...'+UTF8RightStr(MatchingPath,100))+']'; end; end; procedure LoadWindowsSpecialDir; begin gSpecialDirList:=TSpecialDirList.Create; gSpecialDirList.PopulateSpecialDir; end; end. doublecmd-1.1.22/src/usyndiffcontrols.pas0000644000175000001440000004370414743153644017525 0ustar alexxusersunit uSynDiffControls; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, SynEdit, LCLVersion, SynEditMiscClasses, SynGutterBase, SynTextDrawer, SynGutter, LazSynEditText, uDiffOND; const { Default differ colors } clPaleGreen: TColor = $AAFFAA; clPaleRed : TColor = $AAAAFF; clPaleBlue : TColor = $FFAAAA; type TPaintStyle = (psForeground, psBackground); type { TDiffColors } TDiffColors = class(TPersistent) private fColors: array [TChangeKind] of TColor; fOnChange: TNotifyEvent; function GetColor(const AIndex: TChangeKind): TColor; procedure SetColor(const AIndex: TChangeKind; const AValue: TColor); public constructor Create; procedure Assign(aSource: TPersistent); override; property Colors[const aIndex: TChangeKind]: TColor read GetColor write SetColor; default; property OnChange: TNotifyEvent read fOnChange write fOnChange; published property Added: TColor index ckAdd read GetColor write SetColor; property Modified: TColor index ckModify read GetColor write SetColor; property Deleted: TColor index ckDelete read GetColor write SetColor; end; { TSynDiffGutter } TSynDiffGutter = class(TSynGutter) protected procedure CreateDefaultGutterParts; override; end; { TSynDiffGutterLineNumber } TSynDiffGutterLineNumber = class(TSynGutterPartBase) private FTextDrawer: TheTextDrawer; FDigitCount: integer; FAutoSizeDigitCount: integer; FLeadingZeros: boolean; procedure SetDigitCount(AValue : integer); procedure SetLeadingZeros(const AValue : boolean); function FormatLineNumber(Line: PtrInt; Kind: TChangeKind): string; protected procedure Init; override; function PreferedWidth: Integer; override; procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer); procedure BufferChanged(Sender: TObject); procedure FontChanged(Sender: TObject); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: Integer); override; published property MarkupInfo; property DigitCount: integer read FDigitCount write SetDigitCount; property LeadingZeros: boolean read FLeadingZeros write SetLeadingZeros; end; { TSynDiffGutterChanges } TSynDiffGutterChanges = class(TSynGutterPartBase) protected function PreferedWidth: Integer; override; public constructor Create(AOwner: TComponent); override; procedure Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: Integer); override; end; { TSynDiffEdit } TSynDiffEdit = class(TSynEdit) private FPaintStyle: TPaintStyle; FEncoding: String; FColors: TDiffColors; FOriginalFile, FModifiedFile: TSynDiffEdit; private procedure SetModifiedFile(const AValue: TSynDiffEdit); procedure SetOriginalFile(const AValue: TSynDiffEdit); procedure SetPaintStyle(const AValue: TPaintStyle); protected function CreateGutter(AOwner: TSynEditBase; ASide: TSynGutterSide; ATextDrawer: TheTextDrawer): TSynGutter; override; procedure SpecialLineMarkupEvent(Sender: TObject; Line: Integer; var Special: boolean; AMarkup: TSynSelectedColor); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; public procedure Renumber; procedure StartCompare; procedure FinishCompare; function DiffBegin(ALine: Integer): Integer; function DiffEnd(ALine: Integer): Integer; property PaintStyle: TPaintStyle read FPaintStyle write SetPaintStyle; property Encoding: String read FEncoding write FEncoding; property Colors: TDiffColors read FColors write FColors; property OriginalFile: TSynDiffEdit read FOriginalFile write SetOriginalFile; property ModifiedFile: TSynDiffEdit read FModifiedFile write SetModifiedFile; published property OnStatusChange; end; { TStringsHelper } TStringsHelper = class helper for TStrings private function GetKind(AIndex: Integer): TChangeKind; function GetNumber(AIndex: Integer): PtrInt; procedure SetKind(AIndex: Integer; AValue: TChangeKind); procedure SetNumber(AIndex: Integer; AValue: PtrInt); public procedure Renumber; procedure RemoveFake; procedure Append(const S: String; AKind: TChangeKind); procedure InsertFake(AIndex: Integer; AKind: TChangeKind); procedure SetKindAndNumber(AIndex: Integer; AKind: TChangeKind; ANumber: PtrInt); public property Kind[AIndex: Integer]: TChangeKind read GetKind write SetKind; property Number[AIndex: Integer]: PtrInt read GetNumber write SetNumber; end; implementation uses LCLIntf, LCLType, SynEditMiscProcs, SynEditTypes; const KindShift = 8; // Line kind shift KindMask = $FF; // Line kind mask FakeLine = PtrInt(High(PtrUInt) shr KindShift); { TDiffColors } function TDiffColors.GetColor(const AIndex: TChangeKind): TColor; begin Result:= fColors[AIndex]; end; procedure TDiffColors.SetColor(const AIndex: TChangeKind; const AValue: TColor); begin if fColors[AIndex] <> AValue then begin fColors[AIndex] := AValue; if Assigned(OnChange) then OnChange(Self); end; end; constructor TDiffColors.Create; begin fColors[ckAdd] := clPaleGreen; fColors[ckModify] := clPaleBlue; fColors[ckDelete] := clPaleRed; end; procedure TDiffColors.Assign(aSource: TPersistent); begin if (aSource is TDiffColors) then with (aSource as TDiffColors) do begin fColors[ckAdd]:= Added; fColors[ckModify]:= Modified; fColors[ckDelete]:= Deleted; end; end; { TSynDiffGutter } procedure TSynDiffGutter.CreateDefaultGutterParts; begin if Side <> gsLeft then Exit; with TSynDiffGutterLineNumber.Create(Parts) do Name:= 'SynDiffGutterLineNumber'; with TSynDiffGutterChanges.Create(Parts) do Name:= 'SynDiffGutterChanges'; end; { TSynDiffEdit } procedure TSynDiffEdit.SetModifiedFile(const AValue: TSynDiffEdit); begin if FModifiedFile <> AValue then begin if (AValue <> nil) and (FOriginalFile <> nil) then raise Exception.Create('Having both ModifiedFile and OriginalFile is not supported'); FModifiedFile := AValue; end; end; procedure TSynDiffEdit.SetOriginalFile(const AValue: TSynDiffEdit); begin if FOriginalFile <> AValue then begin if (AValue <> nil) and (FModifiedFile <> nil) then raise Exception.Create('Having both OriginalFile and ModifiedFile is not supported'); FOriginalFile := AValue; end; end; procedure TSynDiffEdit.SetPaintStyle(const AValue: TPaintStyle); begin if FPaintStyle <> AValue then begin FPaintStyle := AValue; Invalidate; end; end; function TSynDiffEdit.CreateGutter(AOwner: TSynEditBase; ASide: TSynGutterSide; ATextDrawer: TheTextDrawer): TSynGutter; begin Result := TSynDiffGutter.Create(AOwner, ASide, ATextDrawer); end; procedure TSynDiffEdit.SpecialLineMarkupEvent(Sender: TObject; Line: Integer; var Special: boolean; AMarkup: TSynSelectedColor); var Kind: TChangeKind; LineColor: TColor; begin if Line > Lines.Count then Exit; Kind:= Lines.Kind[Line - 1]; if (Kind <> ckNone) then with AMarkup do begin case Kind of ckDelete: LineColor := FColors.Deleted; ckAdd: LineColor := FColors.Added; ckModify: if Assigned(Highlighter) then Exit else LineColor := FColors.Modified; end; Special:= True; if FPaintStyle = psForeground then begin Foreground := LineColor; Background := clWindow; end else begin Foreground:= clWindowText; Background := LineColor; end; end; end; procedure TSynDiffEdit.StartCompare; begin BeginUpdate; // Remove fake lines Lines.RemoveFake; end; procedure TSynDiffEdit.FinishCompare; begin EndUpdate; Invalidate; end; function TSynDiffEdit.DiffBegin(ALine: Integer): Integer; var Kind: TChangeKind; begin Result:= ALine; if ALine = 0 then Exit; // Skip lines with current difference type Kind := Lines.Kind[ALine]; while (ALine > 0) and (Lines.Kind[ALine] = Kind) do Dec(ALine); Result:= ALine + 1; end; function TSynDiffEdit.DiffEnd(ALine: Integer): Integer; var Kind: TChangeKind; begin Result:= ALine; if ALine = Lines.Count - 1 then Exit; // Skip lines with current difference type Kind := Lines.Kind[ALine]; while (ALine < Lines.Count - 1) and (Lines.Kind[ALine] = Kind) do Inc(ALine); Result:= ALine - 1; end; constructor TSynDiffEdit.Create(AOwner: TComponent); begin inherited Create(AOwner); Color:= clWindow; Font.Color:= clWindowText; FPaintStyle:= psBackground; FColors:= TDiffColors.Create; OnSpecialLineMarkup:= @SpecialLineMarkupEvent; end; destructor TSynDiffEdit.Destroy; begin FreeAndNil(FColors); inherited Destroy; end; procedure TSynDiffEdit.Renumber; begin Lines.Renumber; Repaint; end; { TSynDiffGutterChanges } function TSynDiffGutterChanges.PreferedWidth: Integer; begin Result := 4; end; constructor TSynDiffGutterChanges.Create(AOwner: TComponent); begin inherited Create(AOwner); MarkupInfo.Background := clNone; end; procedure TSynDiffGutterChanges.Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: Integer); var rcLine: TRect; LineCount: Integer; LineHeight: Integer; I, LineNumber: Integer; SynDiffEdit: TSynDiffEdit; LineTop: Integer; AliasMode: TAntialiasingMode; begin if not Visible then Exit; SynDiffEdit:= TSynDiffEdit(SynEdit); LineHeight:= SynDiffEdit.LineHeight; LineCount:= SynDiffEdit.Lines.Count; LineTop:= ToIdx(GutterArea.TextArea.TopLine); if MarkupInfo.Background <> clNone then begin Canvas.Brush.Color := MarkupInfo.Background; Canvas.FillRect(AClip); end; Canvas.Pen.Width := Width; Canvas.Pen.EndCap:= pecFlat; AliasMode:= Canvas.AntialiasingMode; Canvas.AntialiasingMode:= amOff; rcLine := AClip; rcLine.Left := rcLine.Left + Width div 2; rcLine.Bottom := AClip.Top; for I := LineTop + FirstLine to LineTop + LastLine do begin LineNumber := ViewedTextBuffer.DisplayView.ViewToTextIndex(I); // next line rect rcLine.Top := rcLine.Bottom; Inc(rcLine.Bottom, LineHeight); if (LineNumber >= 0) and (LineNumber < LineCount) then begin case SynDiffEdit.Lines.Kind[LineNumber] of ckNone: Continue; ckAdd: Canvas.Pen.Color := SynDiffEdit.FColors.Added; ckDelete: Canvas.Pen.Color := SynDiffEdit.FColors.Deleted; ckModify: Canvas.Pen.Color := SynDiffEdit.FColors.Modified; end; Canvas.Line(rcLine.Left, rcLine.Top + 1, rcLine.Left, rcLine.Bottom - 1); end; end; Canvas.AntialiasingMode := AliasMode; end; { TSynDiffGutterLineNumber } procedure TSynDiffGutterLineNumber.SetDigitCount(AValue: integer); begin AValue := MinMax(AValue, 2, 12); if FDigitCount <> AValue then begin FDigitCount := AValue; if AutoSize then begin FAutoSizeDigitCount := Max(FDigitCount, FAutoSizeDigitCount); DoAutoSize; end else FAutoSizeDigitCount := FDigitCount; DoChange(Self); end; end; procedure TSynDiffGutterLineNumber.SetLeadingZeros(const AValue: boolean); begin if FLeadingZeros <> AValue then begin FLeadingZeros := AValue; DoChange(Self); end; end; function TSynDiffGutterLineNumber.FormatLineNumber(Line: PtrInt; Kind: TChangeKind): string; var I: Integer; begin Result := EmptyStr; // if a symbol must be showed if (Line = 0) or (Line = FakeLine) then begin case Kind of ckAdd: Result := StringOfChar(' ', FAutoSizeDigitCount-1) + '+'; ckDelete: Result := StringOfChar(' ', FAutoSizeDigitCount-1) + '-'; else Result := StringOfChar(' ', FAutoSizeDigitCount-1) + '.'; end; end // else format the line number else begin Str(Line : FAutoSizeDigitCount, Result); if FLeadingZeros then for I := 1 to FAutoSizeDigitCount - 1 do begin if (Result[I] <> ' ') then Break; Result[I] := '0'; end; end; end; function TSynDiffGutterLineNumber.PreferedWidth: Integer; begin Result := FAutoSizeDigitCount * FTextDrawer.CharWidth + 1; end; procedure TSynDiffGutterLineNumber.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer); var nDigits: Integer; begin if not (Visible and AutoSize) then Exit; nDigits := Max(Length(IntToStr(TextBuffer.Count)), FDigitCount); if FAutoSizeDigitCount <> nDigits then begin FAutoSizeDigitCount := nDigits; DoAutoSize; end; end; procedure TSynDiffGutterLineNumber.BufferChanged(Sender: TObject); begin LineCountChanged(nil, 0, 0); end; procedure TSynDiffGutterLineNumber.FontChanged(Sender: TObject); begin DoAutoSize; end; procedure TSynDiffGutterLineNumber.Init; begin inherited Init; FTextDrawer := Gutter.TextDrawer; ViewedTextBuffer.AddChangeHandler(senrLineCount, @LineCountChanged); ViewedTextBuffer.AddNotifyHandler(senrTextBufferChanged, @BufferChanged); FTextDrawer.RegisterOnFontChangeHandler(@FontChanged); LineCountchanged(nil, 0, 0); end; constructor TSynDiffGutterLineNumber.Create(AOwner: TComponent); begin FDigitCount := 4; FAutoSizeDigitCount := FDigitCount; FLeadingZeros := False; inherited Create(AOwner); end; destructor TSynDiffGutterLineNumber.Destroy; begin ViewedTextBuffer.RemoveHanlders(Self); FTextDrawer.UnRegisterOnFontChangeHandler(@FontChanged); inherited Destroy; end; procedure TSynDiffGutterLineNumber.Assign(Source: TPersistent); var Src: TSynDiffGutterLineNumber; begin if Assigned(Source) and (Source is TSynDiffGutterLineNumber) then begin Src := TSynDiffGutterLineNumber(Source); FLeadingZeros := Src.FLeadingZeros; FDigitCount := Src.FDigitCount; FAutoSizeDigitCount := Src.FAutoSizeDigitCount; end; inherited Assign(Source); end; procedure TSynDiffGutterLineNumber.Paint(Canvas: TCanvas; AClip: TRect; FirstLine, LastLine: Integer); var DC: HDC; S: String; rcLine: TRect; LineNumber: PtrInt; LineKind: TChangeKind; I, LineHeight: Integer; SynDiffEdit: TSynDiffEdit; LineCount: Integer; IRange: TLineRange; LineTop: TLinePos; begin if not Visible then Exit; SynDiffEdit:= TSynDiffEdit(SynEdit); LineHeight:= SynDiffEdit.LineHeight; LineCount:= SynDiffEdit.Lines.Count; LineTop:= ToIdx(GutterArea.TextArea.TopLine); // Changed to use fTextDrawer.BeginDrawing and fTextDrawer.EndDrawing only // when absolutely necessary. Note: Never change brush / pen / font of the // canvas inside of this block (only through methods of fTextDrawer)! if MarkupInfo.Background <> clNone then Canvas.Brush.Color := MarkupInfo.Background else begin Canvas.Brush.Color := Gutter.Color; end; DC := Canvas.Handle; LCLIntf.SetBkColor(DC, TColorRef(Canvas.Brush.Color)); FTextDrawer.BeginDrawing(DC); try if MarkupInfo.Background <> clNone then FTextDrawer.SetBackColor(MarkupInfo.Background) else FTextDrawer.SetBackColor(Gutter.Color); if MarkupInfo.Foreground <> clNone then fTextDrawer.SetForeColor(MarkupInfo.Foreground) else fTextDrawer.SetForeColor(SynDiffEdit.Font.Color); fTextDrawer.SetFrameColor(MarkupInfo.FrameColor); fTextDrawer.Style := MarkupInfo.Style; // prepare the rect initially rcLine := AClip; rcLine.Bottom := AClip.Top; for I := LineTop + FirstLine to LineTop + LastLine do begin LineNumber := ToPos(ViewedTextBuffer.DisplayView.ViewToTextIndexEx(I, IRange)); if (LineNumber < 1) or (LineNumber > LineCount) then Break; LineKind := SynDiffEdit.Lines.Kind[LineNumber - 1]; LineNumber:= SynDiffEdit.Lines.Number[LineNumber - 1]; // next line rect rcLine.Top := rcLine.Bottom; // Get the formatted line number or dot S := FormatLineNumber(LineNumber, LineKind); Inc(rcLine.Bottom, LineHeight); if I <> IRange.Top then S := ''; // erase the background and draw the line number string in one go fTextDrawer.ExtTextOut(rcLine.Left, rcLine.Top, ETO_OPAQUE or ETO_CLIPPED, rcLine, PChar(Pointer(S)),Length(S)); end; // now erase the remaining area if any if AClip.Bottom > rcLine.Bottom then begin rcLine.Top := rcLine.Bottom; rcLine.Bottom := AClip.Bottom; with rcLine do fTextDrawer.ExtTextOut(Left, Top, ETO_OPAQUE, rcLine, nil, 0); end; finally fTextDrawer.EndDrawing; end; end; { TStringsHelper } function TStringsHelper.GetKind(AIndex: Integer): TChangeKind; var AKind: PtrInt; begin AKind:= PtrInt(Objects[AIndex]); Result:= TChangeKind(AKind and KindMask); end; function TStringsHelper.GetNumber(AIndex: Integer): PtrInt; begin Result:= PtrInt(Objects[AIndex]) shr KindShift; end; procedure TStringsHelper.SetKind(AIndex: Integer; AValue: TChangeKind); var ANumber: PtrInt; begin ANumber:= GetNumber(AIndex); Objects[AIndex]:= TObject(PtrInt(AValue) or (ANumber shl KindShift)); end; procedure TStringsHelper.SetNumber(AIndex: Integer; AValue: PtrInt); var AKind: TChangeKind; begin AKind:= GetKind(AIndex); Objects[AIndex]:= TObject(PtrInt(AKind) or (AValue shl KindShift)); end; procedure TStringsHelper.RemoveFake; var I: Integer; begin for I:= Count - 1 downto 0 do begin if ((PtrInt(Objects[I]) shr KindShift) = FakeLine) and (Self[I] = EmptyStr) then Delete(I); end; end; procedure TStringsHelper.Renumber; var I, N: Integer; begin N:= 1; for I:= 0 to Count - 1 do begin if ((PtrInt(Objects[I]) shr KindShift) <> FakeLine) then begin Number[I] := N; Inc(N); end; end; end; procedure TStringsHelper.Append(const S: String; AKind: TChangeKind); begin InsertObject(Count, S, TObject(PtrInt(AKind) or (Count shl KindShift))); end; procedure TStringsHelper.InsertFake(AIndex: Integer; AKind: TChangeKind); begin InsertObject(AIndex, EmptyStr, TObject(PtrInt(AKind) or PtrInt(FakeLine shl KindShift))); end; procedure TStringsHelper.SetKindAndNumber(AIndex: Integer; AKind: TChangeKind; ANumber: PtrInt); begin Objects[AIndex]:= TObject(PtrInt(AKind) or (ANumber shl KindShift)); end; end. doublecmd-1.1.22/src/uthumbnails.pas0000644000175000001440000003006414743153644016440 0ustar alexxusersunit uThumbnails; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Graphics, Types, fgl, DCClassesUtf8, uFile; type { TCreatePreviewHandler } TCreatePreviewHandler = function(const aFileName: String; aSize: TSize): TBitmap; { TBitmapList } TBitmapList = specialize TFPGObjectList; { TThumbnailManager } TThumbnailManager = class private FBitmap: TBitmap; FBackColor: TColor; FFileName: String; FThumbPath: String; FProviderList: array of TCreatePreviewHandler; static; private procedure DoCreatePreviewText; function GetPreviewFileExt(const sFileExt: String): String; function GetPreviewFileName(const sFileName: String): String; function CreatePreviewImage(const Graphic: TGraphic): TBitmap; function ReadMetaData(const aFile: TFile; FileStream: TFileStreamEx): Boolean; function WriteMetaData(const aFile: TFile; FileStream: TFileStreamEx): Boolean; class function ReadFileName(const aThumb: String; out aFileName: String): Boolean; public constructor Create(BackColor: TColor); function CreatePreview(const aFile: TFile): TBitmap; function CreatePreview(const FullPathToFile: String): TBitmap; function RemovePreview(const FullPathToFile: String): Boolean; public class procedure CompactCache; class function RegisterProvider(Provider: TCreatePreviewHandler): Integer; class function GetPreviewScaleSize(aWidth, aHeight: Integer): TSize; class function GetPreviewFromProvider(const aFileName: String; aSize: TSize; aSkip: Integer): TBitmap; end; implementation uses StreamEx, URIParser, MD5, FileUtil, LazFileUtils, Forms, DCOSUtils, DCStrUtils, uDebug, uReSample, uGlobsPaths, uGlobs, uPixmapManager, uFileSystemFileSource, uGraphics, uFileProcs; const ThumbSign: QWord = $0000235448554D42; // '#0 #0 # T H U M B' function TThumbnailManager.GetPreviewFileExt(const sFileExt: String): String; begin if (sFileExt = 'jpg') or (sFileExt = 'jpeg') or (sFileExt = 'bmp') then Result:= 'jpg' else Result:= 'png'; end; function TThumbnailManager.GetPreviewFileName(const sFileName: String): String; begin Result:= MD5Print(MD5String(sFileName)); end; function TThumbnailManager.CreatePreviewImage(const Graphic: TGraphic): TBitmap; var aSize: TSize; bmpTemp: TBitmap = nil; begin try // Calculate aspect width and height of thumb aSize:= GetPreviewScaleSize(Graphic.Width, Graphic.Height); bmpTemp:= TBitMap.Create; bmpTemp.Assign(Graphic); Result:= TBitMap.Create; Result.SetSize(aSize.cx, aSize.cy); Stretch(bmpTemp, Result, ResampleFilters[2].Filter, ResampleFilters[2].Width); finally FreeAndNil(bmpTemp); end; end; procedure TThumbnailManager.DoCreatePreviewText; var S: String; Y: Integer; Stream: TFileStreamEx; Reader: TStreamReader; begin FBitmap:= TBitmap.Create; with FBitmap do begin SetSize(gThumbSize.cx, gThumbSize.cy); Canvas.Brush.Color:= clWindow; Canvas.FillRect(Canvas.ClipRect); Canvas.Font.Color:= clWindowText; Canvas.Font.Size := gThumbSize.cy div 16; try Stream:= TFileStreamEx.Create(FFileName, fmOpenRead or fmShareDenyNone); try Y:= 0; Reader:= TStreamReader.Create(Stream, BUFFER_SIZE, True); repeat S:= Reader.ReadLine; Canvas.TextOut(0, Y, S); Y += Canvas.TextHeight(S) + 2; until (Y >= gThumbSize.cy) or Reader.Eof; finally Reader.Free; end; except // Ignore end; end; end; function TThumbnailManager.ReadMetaData(const aFile: TFile; FileStream: TFileStreamEx): Boolean; var sFileName: AnsiString; begin Result:= True; try // Read metadata position from last 4 byte of file FileStream.Seek(-4, soEnd); FileStream.Seek(FileStream.ReadDWord, soBeginning); // Check signature if (FileStream.ReadQWord <> NtoBE(ThumbSign)) then Exit(False); // Read thumbnail metadata Result:= (URIToFilename(FileStream.ReadAnsiString, sFileName) and SameText(sFileName, aFile.FullPath)); if not Result then Exit; Result:= (aFile.Size = FileStream.ReadQWord) and (QWord(aFile.ModificationTime) = FileStream.ReadQWord); if not Result then Exit; Result:= (gThumbSize.cx = FileStream.ReadWord) and (gThumbSize.cy = FileStream.ReadWord); except Result:= False; end; end; function TThumbnailManager.WriteMetaData(const aFile: TFile; FileStream: TFileStreamEx): Boolean; var iEnd: Int64; begin Result:= True; try // Get original file size iEnd:= FileStream.Seek(0, soEnd); // Write signature FileStream.WriteQWord(NtoBE(ThumbSign)); // Write thumbnail meta data FileStream.WriteAnsiString(FilenameToURI(aFile.FullPath)); FileStream.WriteQWord(aFile.Size); FileStream.WriteQWord(QWord(aFile.ModificationTime)); FileStream.WriteWord(gThumbSize.cx); FileStream.WriteWord(gThumbSize.cy); // Write original file size FileStream.WriteDWord(iEnd); except Result:= False; end; end; class function TThumbnailManager.ReadFileName(const aThumb: String; out aFileName: String): Boolean; var fsFileStream: TFileStreamEx; begin try fsFileStream:= TFileStreamEx.Create(aThumb, fmOpenRead or fmShareDenyNone); try // Read metadata position from last 4 byte of file fsFileStream.Seek(-4, soEnd); fsFileStream.Seek(fsFileStream.ReadDWord, soBeginning); // Check signature if (fsFileStream.ReadQWord <> NtoBE(ThumbSign)) then Exit(False); // Read source file name Result:= URIToFilename(fsFileStream.ReadAnsiString, aFileName); finally fsFileStream.Free; end; except Result:= False; end; end; constructor TThumbnailManager.Create(BackColor: TColor); begin FBackColor:= BackColor; FThumbPath:= gpThumbCacheDir; // If directory not exists then create it if not mbDirectoryExists(FThumbPath) then mbForceDirectory(FThumbPath); end; function TThumbnailManager.RemovePreview(const FullPathToFile: String): Boolean; var sExt, sName: String; begin sExt:= GetPreviewFileExt(ExtractOnlyFileExt(FullPathToFile)); sName:= GetPreviewFileName(FullPathToFile); // Delete thumb from cache Result:= mbDeleteFile(FThumbPath + PathDelim + sName + '.' + sExt); end; function TThumbnailManager.CreatePreview(const aFile: TFile): TBitmap; var I: Integer; sFullPathToFile, sThumbFileName, sExt: String; fsFileStream: TFileStreamEx = nil; Picture: TPicture = nil; ABitmap: TBitmap; begin Result:= nil; try Picture:= TPicture.Create; try sFullPathToFile:= aFile.FullPath; sExt:= GetPreviewFileExt(ExtractOnlyFileExt(sFullPathToFile)); sThumbFileName:= FThumbPath + PathDelim + GetPreviewFileName(sFullPathToFile) + '.' + sExt; // If thumbnail already exists in cache for this file then load it if mbFileExists(sThumbFileName) then begin fsFileStream:= TFileStreamEx.Create(sThumbFileName, fmOpenRead or fmShareDenyNone or fmOpenNoATime); try if ReadMetaData(aFile, fsFileStream) then begin fsFileStream.Position:= 0; Picture.LoadFromStreamWithFileExt(fsFileStream, sExt); Result:= TBitmap.Create; Result.Assign(Picture.Graphic); Exit; end; finally FreeAndNil(fsFileStream); end; end; // Try to create thumnail using providers for I:= Low(FProviderList) to High(FProviderList) do begin Result:= FProviderList[I](sFullPathToFile, gThumbSize); if Assigned(Result) then Break; end; if Assigned(Result) then begin if (Result.Width > gThumbSize.cx) or (Result.Height > gThumbSize.cy) then begin ABitmap:= CreatePreviewImage(Result); BitmapAssign(Result, ABitmap); ABitmap.Free; end; end; if not Assigned(Result) then begin sExt:= ExtractOnlyFileExt(sFullPathToFile); // Create thumb for image files if GetGraphicClassForFileExtension(sExt) <> nil then begin fsFileStream:= TFileStreamEx.Create(sFullPathToFile, fmOpenRead or fmShareDenyNone or fmOpenNoATime); with Picture do try LoadFromStreamWithFileExt(fsFileStream, sExt); if (Graphic.Width > gThumbSize.cx) or (Graphic.Height > gThumbSize.cy) then Result:= CreatePreviewImage(Graphic) else begin Result:= TBitmap.Create; Result.Assign(Graphic); Exit; // No need to save in cache end; finally FreeAndNil(fsFileStream); end end // Create thumb for text files else if (mbFileExists(sFullPathToFile)) and (FileIsText(sFullPathToFile)) then begin FFileName:= sFullPathToFile; // Some widgetsets can not draw from background // thread so call draw text function from main thread TThread.Synchronize(nil, @DoCreatePreviewText); Exit(FBitmap); // No need to save in cache end; end; // Save created thumb to cache if gThumbSave and Assigned(Result) and not IsInPath(FThumbPath, sFullPathToFile, False, False) then begin Picture.Bitmap.Assign(Result); sExt:= GetPreviewFileExt(sExt); try fsFileStream:= TFileStreamEx.Create(sThumbFileName, fmCreate); try Picture.SaveToStreamWithFileExt(fsFileStream, sExt); WriteMetaData(aFile, fsFileStream); finally FreeAndNil(fsFileStream); end; except on e: EStreamError do DCDebug(['Cannot save thumbnail to file "', sThumbFileName, '": ', e.Message]); end; end; finally FreeAndNil(Picture); end; except Result:= nil; end; if not Assigned(Result) then Result:= PixMapManager.LoadBitmapEnhanced(sFullPathToFile, gIconsSize, True, FBackColor); end; function TThumbnailManager.CreatePreview(const FullPathToFile: String): TBitmap; var aFile: TFile; begin aFile := TFileSystemFileSource.CreateFileFromFile(FullPathToFile); try Result:= CreatePreview(aFile); finally FreeAndNil(AFile); end; end; class procedure TThumbnailManager.CompactCache; var I: Integer; aFileName: String; aFileList: TStringList; begin aFileList:= FindAllFiles(gpThumbCacheDir); for I:= 0 to Pred(aFileList.Count) do begin if not (ReadFileName(aFileList[I], aFileName) and mbFileExists(aFileName)) then begin mbDeleteFile(aFileList[I]); end; end; aFileList.Free; end; class function TThumbnailManager.RegisterProvider(Provider: TCreatePreviewHandler): Integer; begin SetLength(FProviderList, Length(FProviderList) + 1); FProviderList[High(FProviderList)]:= Provider; Result:= High(FProviderList); end; class function TThumbnailManager.GetPreviewScaleSize(aWidth, aHeight: Integer): TSize; begin if aWidth > aHeight then begin Result.cx:= gThumbSize.cx; Result.cy:= Result.cx * aHeight div aWidth; if Result.cy > gThumbSize.cy then begin Result.cy:= gThumbSize.cy; Result.cx:= Result.cy * aWidth div aHeight; end; end else begin Result.cy:= gThumbSize.cy; Result.cx:= Result.cy * aWidth div aHeight; end; end; class function TThumbnailManager.GetPreviewFromProvider(const aFileName: String; aSize: TSize; aSkip: Integer): TBitmap; var Index: Integer; begin for Index:= Low(FProviderList) to High(FProviderList) do begin if (Index <> aSkip) then begin Result:= FProviderList[Index](aFileName, aSize); if Assigned(Result) then Exit; end; end; Result:= nil; end; end. doublecmd-1.1.22/src/utranslator.pas0000644000175000001440000000463714743153644016472 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- This unit is needed for using translated form strings made by Lazarus IDE. It loads localized form strings from .po file. Copyright (C) 2007-2016 Alexander Koblov (alexx2000@mail.ru) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. } unit uTranslator; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, TypInfo, Translations; type { TTranslator } TTranslator = class(TAbstractTranslator) private FPOFile: TPOFile; public constructor Create(const FileName: String); destructor Destroy; override; procedure TranslateStringProperty(Sender: TObject; const Instance: TPersistent; PropInfo: PPropInfo; var Content: String); override; property POFile: TPOFile read FPOFile; end; implementation uses LCLProc; { TTranslator } constructor TTranslator.Create(const FileName: String); begin inherited Create; FPOFile := TPOFile.Create(FileName); end; destructor TTranslator.Destroy; begin FPOFile.Free; inherited Destroy; end; procedure TTranslator.TranslateStringProperty(Sender: TObject; const Instance: TPersistent; PropInfo: PPropInfo; var Content: String); var Reader: TReader; Identifier: String; begin if (PropInfo = nil) then Exit; if (CompareText(PropInfo^.PropType^.Name, 'TTRANSLATESTRING') <> 0) then Exit; if (Sender is TReader) then begin Reader := TReader(Sender); if Reader.Driver is TLRSObjectReader then Identifier := TLRSObjectReader(Reader.Driver).GetStackPath else begin Identifier := Instance.ClassName + '.' + PropInfo^.Name; end; // DebugLn(UpperCase(Identifier) + '=' + Content); Content := FPOFile.Translate(Identifier, Content); end; end; end. doublecmd-1.1.22/src/utypes.pas0000644000175000001440000000344314743153644015437 0ustar alexxusers{ Double commander ------------------------------------------------------------------------- Definitions of some common types. Copyright (C) 2012 Przemyslaw Nagay (cobines@gmail.com) Copyright (C) 2018 Alexander Koblov (Alexx2000@mail.ru) 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, see . } unit uTypes; // This unit should depend on as little other units as possible. interface type TCaseSensitivity = ( cstNotSensitive, // According to locale collation specs. Usually it means linguistic sorting // of character case "aAbBcC" taking numbers into consideration (aa1, aa2, aa10, aA1, aA2, aA10, ...). cstLocale, // Depending on character value, direct comparison of bytes, so usually ABCabc. // Might not work correctly for Unicode, just for Ansi. cstCharValue); TRange = record First: Integer; Last: Integer; end; //Note: If we add a format here, don't forget to update also "FILE_SIZE" string table in "uFileFunctions". TFileSizeFormat = (fsfFloat, fsfByte, fsfKilo, fsfMega, fsfGiga, fsfTera, fsfPersonalizedFloat, fsfPersonalizedByte, fsfPersonalizedKilo, fsfPersonalizedMega, fsfPersonalizedGiga, fsfPersonalizedTera); implementation end. doublecmd-1.1.22/src/uvariablemenusupport.pas0000644000175000001440000003136514743153644020406 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Support for popup menu to help to enter percent variable parameters. The idea here is: -Have something to help user who wants to use "%..." variable to have a quick hint built-in the application instead of having to seach in help of doc files. -Next to an edit box where we could type in "%...", have a speed button that would popup a menu where user sees to possible percent variables available. -User sees what he could use, select one and then it would type in the edit box the select "%...". -This unit is to build that popup instead of having it in different unit. -It creates the popup only the first time use click on "%" button. -If in the main session use again a "%" button, the popup menu is already created and almost ready. -"Almost", because we simply need to re-assign the possible different target edit box. Copyright (C) 2015-2019 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uVariableMenuSupport; {$mode objfpc}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, Menus, StdCtrls, //DC dmHelpManager; type TVariableMenuItem = class(TMenuItem) private FSubstitutionText: string; public constructor MyCreate(TheOwner: TComponent; ParamCaption, ParamSubstitutionText: string); procedure VariableHelperClick(Sender: TObject); procedure HelpOnVariablesClick(Sender: TObject); end; TPercentVariablePopupMenu = class(TPopUpMenu) private FAssociatedComponent: TComponent; procedure PopulateMenuWithVariableHelper; public constructor Create(AOnwer: TComponent); override; property AssociatedTComponent: TComponent read FAssociatedComponent write FAssociatedComponent; end; procedure BringPercentVariablePopupMenu(AComponent: TComponent); implementation uses //Lazarus, Free-Pascal, etc. EditBtn, SysUtils, Dialogs, //DC uLng; var PercentVariablePopupMenu: TPercentVariablePopupMenu = nil; { TPercentVariablePopupMenu.Create } constructor TPercentVariablePopupMenu.Create(AOnwer: TComponent); begin inherited Create(AOnwer); FAssociatedComponent := nil; PopulateMenuWithVariableHelper; end; { TPercentVariablePopupMenu.PopulateMenuWithVariableHelper } procedure TPercentVariablePopupMenu.PopulateMenuWithVariableHelper; type tHelperMenuDispatcher = set of (hmdNothing, hmdSeparator, hmdListLevel); tFunctionHelper = record sLetter: string; sDescription: string; HelperMenuDispatcher: tHelperMenuDispatcher; end; tFirstSubLevelHelper = record sLetter: string; sDescription: string; HelperMenuDispatcher: tHelperMenuDispatcher; end; const NbOfFunctions = 12; FunctionHelper: array[1..NbOfFunctions] of tFunctionHelper = ( (sLetter: 'f'; sDescription: rsVarOnlyFilename; HelperMenuDispatcher: []), (sLetter: 'd'; sDescription: rsVarPath; HelperMenuDispatcher: []), (sLetter: 'z'; sDescription: rsVarLastDirOfPath; HelperMenuDispatcher: []), (sLetter: 'p'; sDescription: rsVarFullPath; HelperMenuDispatcher: []), (sLetter: 'o'; sDescription: rsVarFilenameNoExt; HelperMenuDispatcher: []), (sLetter: 'e'; sDescription: rsVarOnlyExtension; HelperMenuDispatcher: []), (sLetter: 'v'; sDescription: rsVarRelativePathAndFilename; HelperMenuDispatcher: [hmdSeparator]), (sLetter: 'D'; sDescription: rsVarCurrentPath; HelperMenuDispatcher: []), (sLetter: 'Z'; sDescription: rsVarLastDirCurrentPath; HelperMenuDispatcher: [hmdSeparator]), (sLetter: 'L'; sDescription: rsVarListFullFilename; HelperMenuDispatcher: [hmdListLevel]), (sLetter: 'F'; sDescription: rsVarListFilename; HelperMenuDispatcher: [hmdListLevel]), (sLetter: 'R'; sDescription: rsVarListRelativeFilename; HelperMenuDispatcher: [hmdListLevel, hmdSeparator])); NbOfSubListLevel = 4; SubListLevelHelper: array[1..NbOfSubListLevel] of tFirstSubLevelHelper = ( (sLetter: 'U'; sDescription: rsVarListInUTF8; HelperMenuDispatcher: []), (sLetter: 'W'; sDescription: rsVarListInUTF16; HelperMenuDispatcher: []), (sLetter: 'UQ'; sDescription: rsVarListInUTF8Quoted; HelperMenuDispatcher: []), (sLetter: 'WQ'; sDescription: rsVarListInUTF16Quoted; HelperMenuDispatcher: [])); NbOfSubLevel = 6; SubLevelHelper: array[1..NbOfSubLevel] of tFirstSubLevelHelper = ( (sLetter: 's'; sDescription: rsVarSourcePanel; HelperMenuDispatcher: []), (sLetter: 't'; sDescription: rsVarTargetPanel; HelperMenuDispatcher: [hmdSeparator]), (sLetter: 'l'; sDescription: rsVarLeftPanel; HelperMenuDispatcher: []), (sLetter: 'r'; sDescription: rsVarRightPanel; HelperMenuDispatcher: [hmdSeparator]), (sLetter: 'b'; sDescription: rsVarBothPanelLeftToRight; HelperMenuDispatcher: []), (sLetter: 'p'; sDescription: rsVarBothPanelActiveToInactive; HelperMenuDispatcher: [])); NbOfSubLevelExamples = 15; SubLevelHelperExamples: array[1..NbOfSubLevelExamples] of tFirstSubLevelHelper = ( (sLetter: '%?'; sDescription: rsVarShowCommandPrior; HelperMenuDispatcher: []), (sLetter: '%%'; sDescription: rsVarPercentSign; HelperMenuDispatcher: []), (sLetter: '%#'; sDescription: rsVarPercentChangeToPound; HelperMenuDispatcher: []), (sLetter: '#%'; sDescription: rsVarPoundChangeToPercent; HelperMenuDispatcher: [hmdSeparator]), (sLetter: '%"0'; sDescription: rsVarWillNotBeQuoted; HelperMenuDispatcher: []), (sLetter: '%"1'; sDescription: rsVarWillBeQuoted; HelperMenuDispatcher: []), (sLetter: '%/0'; sDescription: rsVarWillNotHaveEndingDelimiter; HelperMenuDispatcher: []), (sLetter: '%/1'; sDescription: rsVarWillHaveEndingDelimiter; HelperMenuDispatcher: []), (sLetter: '%t0'; sDescription: rsVarWillNotDoInTerminal; HelperMenuDispatcher: []), (sLetter: '%t1'; sDescription: rsVarWillDoInTerminal; HelperMenuDispatcher: [hmdSeparator]), (sLetter: rsVarSimpleMessage; sDescription: rsVarSimpleShowMessage; HelperMenuDispatcher: []), (sLetter: rsVarPromptUserForParam; sDescription: rsVarInputParam; HelperMenuDispatcher: [hmdSeparator]), (sLetter: '%f{-a }'; sDescription: rsVarPrependElement; HelperMenuDispatcher: []), (sLetter: '%f{[}{]} '; sDescription: rsVarEncloseElement; HelperMenuDispatcher: []), (sLetter: '%pr2'; sDescription: rsVarSecondElementRightPanel; HelperMenuDispatcher: [])); var miMainTree, miSubTree, miSubListTree: TVariableMenuItem; iFunction, iSubLevel, iSubListLevel: integer; procedure InsertSeparatorInMainMenu; begin miMainTree := TVariableMenuItem.MyCreate(Self, '-', ''); Self.Items.Add(miMainTree); end; procedure InsertSeparatorInSubMenu; begin miSubTree := TVariableMenuItem.MyCreate(Self, '-', ''); miMainTree.Add(miSubTree); end; procedure InsertSeparatorInSubListMenu; begin miSubTree := TVariableMenuItem.MyCreate(Self, '-', ''); miSubListTree.Add(miSubTree); end; begin //Add the automatic helper for iFunction := 1 to NbOfFunctions do begin miMainTree := TVariableMenuItem.MyCreate(Self, '%' + FunctionHelper[iFunction].sLetter + ' - ' + FunctionHelper[iFunction].sDescription, ''); TPopupMenu(Self).Items.Add(miMainTree); miSubTree := TVariableMenuItem.MyCreate(Self, '%' + FunctionHelper[iFunction].sLetter + ' - ' + FunctionHelper[iFunction].sDescription, '%' + FunctionHelper[iFunction].sLetter); miMainTree.Add(miSubTree); InsertSeparatorInSubMenu; for iSubLevel := 1 to NbOfSubLevel do begin miSubTree := TVariableMenuItem.MyCreate(Self, '%' + FunctionHelper[iFunction].sLetter + SubLevelHelper[iSubLevel].sLetter + ' - ' + '...' + SubLevelHelper[iSubLevel].sDescription, '%' + FunctionHelper[iFunction].sLetter + SubLevelHelper[iSubLevel].sLetter); miMainTree.Add(miSubTree); if hmdSeparator in SubLevelHelper[iSubLevel].HelperMenuDispatcher then InsertSeparatorInSubMenu; end; if hmdListLevel in FunctionHelper[iFunction].HelperMenuDispatcher then begin InsertSeparatorInSubMenu; for iSubListLevel := 1 to NbOfSubListLevel do begin miSubListTree := TVariableMenuItem.MyCreate(Self, '%' + FunctionHelper[iFunction].sLetter + SubListLevelHelper[iSubListLevel].sLetter + ' - ' + '...' + SubListLevelHelper[iSubListLevel].sDescription + '...', ''); miMainTree.Add(miSubListTree); miSubTree := TVariableMenuItem.MyCreate(Self, '%' + FunctionHelper[iFunction].sLetter + SubListLevelHelper[iSubListLevel].sLetter + ' - ' + SubListLevelHelper[iSubListLevel].sDescription, '%' + FunctionHelper[iFunction].sLetter + SubListLevelHelper[iSubListLevel].sLetter); miSubListTree.Add(miSubTree); InsertSeparatorInSubListMenu; for iSubLevel := 1 to NbOfSubLevel do begin miSubTree := TVariableMenuItem.MyCreate(Self, '%' + FunctionHelper[iFunction].sLetter + SubListLevelHelper[iSubListLevel].sLetter + SubLevelHelper[iSubLevel].sLetter + ' - ' + '...' + SubLevelHelper[iSubLevel].sDescription, '%' + FunctionHelper[iFunction].sLetter + SubListLevelHelper[iSubListLevel].sLetter + SubLevelHelper[iSubLevel].sLetter); miSubListTree.Add(miSubTree); if hmdSeparator in SubLevelHelper[iSubLevel].HelperMenuDispatcher then InsertSeparatorInSubListMenu; end; end; end; if hmdSeparator in FunctionHelper[iFunction].HelperMenuDispatcher then InsertSeparatorInMainMenu; end; //Add the more complex-not-so-complex other examples miMainTree := TVariableMenuItem.MyCreate(Self, rsVarOtherExamples, ''); TPopupMenu(Self).Items.Add(miMainTree); for iSubLevel := 1 to NbOfSubLevelExamples do begin miSubTree := TVariableMenuItem.MyCreate(Self, SubLevelHelperExamples[iSubLevel].sLetter + ' - ' + SubLevelHelperExamples[iSubLevel].sDescription, SubLevelHelperExamples[iSubLevel].sLetter); miMainTree.Add(miSubTree); if hmdSeparator in SubLevelHelperExamples[iSubLevel].HelperMenuDispatcher then InsertSeparatorInSubMenu; end; //Add link for the help at the end InsertSeparatorInMainMenu; miMainTree := TVariableMenuItem.MyCreate(Self, rsVarHelpWith, ''); TPopupMenu(Self).Items.Add(miMainTree); end; { TVariableMenuItem.MyCreate } constructor TVariableMenuItem.MyCreate(TheOwner: TComponent; ParamCaption, ParamSubstitutionText: string); begin inherited Create(TheOwner); Caption := ParamCaption; if ParamCaption <> rsVarHelpWith then begin if ParamSubstitutionText <> '' then begin FSubstitutionText := ParamSubstitutionText; OnClick := @VariableHelperClick; end; end else begin OnClick := @HelpOnVariablesClick; end; end; { TVariableMenuItem.VariableHelperClick } //Our intention: //-If something is selected, we replace what's selected by the helper string //-If nothing is selected, we insert our helper string at the current cursor pos //-If nothing is there at all, we add, simply //Since "TDirectoryEdit" is not a descendant of "TCustomEdit", we need to treat it separately. procedure TVariableMenuItem.VariableHelperClick(Sender: TObject); begin if TPercentVariablePopupMenu(Owner).FAssociatedComponent.ClassNameIs('TDirectoryEdit') then TDirectoryEdit(TPercentVariablePopupMenu(Owner).FAssociatedComponent).SelText := FSubstitutionText else TCustomEdit(TPercentVariablePopupMenu(Owner).FAssociatedComponent).SelText := FSubstitutionText; end; { TVariableMenuItem.HelpOnVariablesClick } procedure TVariableMenuItem.HelpOnVariablesClick(Sender: TObject); begin ShowHelpForKeywordWithAnchor('/variables.html'); end; { BringPercentVariablePopupMenu } procedure BringPercentVariablePopupMenu(AComponent: TComponent); begin if PercentVariablePopupMenu = nil then PercentVariablePopupMenu := TPercentVariablePopupMenu.Create(nil); PercentVariablePopupMenu.AssociatedTComponent := AComponent; PercentVariablePopupMenu.PopUp; end; initialization //JEDI code formatter doesn't like a "finalization" section without prior an "initialization" one... finalization if PercentVariablePopupMenu <> nil then FreeAndNil(PercentVariablePopupMenu); end. doublecmd-1.1.22/src/uvectorimage.pas0000644000175000001440000000402614743153644016576 0ustar alexxusersunit uVectorImage; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Graphics, FPImage; type { TVectorReader } TVectorReader = class(TFPCustomImageReader) public class function CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; virtual; abstract; end; { TVectorImage } TVectorImage = class(TFPImageBitmap) protected class function GetSharedImageClass: TSharedRasterImageClass; override; public class procedure RegisterReaderClass(AReaderClass: TFPCustomImageReaderClass); virtual; abstract; class function CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; virtual; end; { TScalableVectorGraphics } TScalableVectorGraphics = class(TVectorImage) protected FReaderClass: TFPCustomImageReaderClass; static; public class function GetFileExtensions: String; override; class function GetReaderClass: TFPCustomImageReaderClass; override; class procedure RegisterReaderClass(AReaderClass: TFPCustomImageReaderClass); override; end; implementation uses uIconTheme; type TVectorReaderClass = class of TVectorReader; { TVectorImage } class function TVectorImage.GetSharedImageClass: TSharedRasterImageClass; begin Result:= TSharedBitmap; end; class function TVectorImage.CreateBitmap(const FileName: String; AWidth, AHeight: Integer): TBitmap; begin Result:= TVectorReaderClass(GetReaderClass).CreateBitmap(FileName, AWidth, AHeight); end; { TScalableVectorGraphics } class function TScalableVectorGraphics.GetReaderClass: TFPCustomImageReaderClass; begin Result:= FReaderClass; end; class function TScalableVectorGraphics.GetFileExtensions: String; begin Result:= 'svg;svgz'; end; class procedure TScalableVectorGraphics.RegisterReaderClass(AReaderClass: TFPCustomImageReaderClass); begin FReaderClass:= AReaderClass; end; procedure Initialize; begin TIconTheme.RegisterExtension('svg;svgz'); TPicture.RegisterFileFormat('svg;svgz', 'Scalable Vector Graphics', TScalableVectorGraphics); end; initialization Initialize; end. doublecmd-1.1.22/src/uvfsmodule.pas0000644000175000001440000000501014743153644016267 0ustar alexxusersunit uVfsModule; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uFileSource; type { TFileSourceClass } TFileSourceClass = class of TFileSource; { TVfsModule } TVfsModule = class Visible: Boolean; FileSourceClass: TFileSourceClass; end; { TVfsModuleList } TVfsModuleList = class(TStringList) private function GetVfsModule(const S: String): TVfsModule; public destructor Destroy; override; function GetFileSource(const Path: String): TFileSourceClass; function FindFileSource(const AClassName: String): TFileSourceClass; property VfsModule[const S: String]: TVfsModule read GetVfsModule; end; procedure RegisterVirtualFileSource(AName: String; AFileSourceClass: TFileSourceClass; Visible: Boolean = True); var // All of file sources from this list will be displayed // in the Virtual File System List. It can be used for example // for system specific virtual folders (Control Panel, Desktop, etc.) gVfsModuleList: TVfsModuleList; implementation procedure RegisterVirtualFileSource(AName: String; AFileSourceClass: TFileSourceClass; Visible: Boolean = True); var VfsModule: TVfsModule; begin VfsModule:= TVfsModule.Create; VfsModule.Visible:= Visible; VfsModule.FileSourceClass:= AFileSourceClass; gVfsModuleList.AddObject(AName, VfsModule); end; { TVfsModuleList } function TVfsModuleList.GetVfsModule(const S: String): TVfsModule; var I: Integer; begin I:= IndexOf(S); if I < 0 then Exit(nil); Result:= TVfsModule(Objects[I]); end; destructor TVfsModuleList.Destroy; var I: Integer; begin for I:= 0 to Count - 1 do TVfsModule(Objects[I]).Free; inherited Destroy; end; function TVfsModuleList.GetFileSource(const Path: String): TFileSourceClass; var I: Integer; begin Result:= nil; for I:= 0 to Count - 1 do with TVfsModule(Objects[I]) do begin if FileSourceClass.IsSupportedPath(Path) then begin Result:= FileSourceClass; Break; end; end; end; function TVfsModuleList.FindFileSource(const AClassName: String): TFileSourceClass; var I: Integer; begin Result:= nil; for I:= 0 to Count - 1 do with TVfsModule(Objects[I]) do begin if FileSourceClass.ClassNameIs(AClassName) then begin Result:= FileSourceClass; Break; end; end; end; initialization gVfsModuleList := TVfsModuleList.Create; finalization FreeAndNil(gVfsModuleList); end. doublecmd-1.1.22/src/uwcxmodule.pas0000644000175000001440000007176414743153644016315 0ustar alexxusers{ Double commander ------------------------------------------------------------------------- Archive File support - class for manage WCX plugins (Version 2.20) Copyright (C) 2006-2024 Alexander Koblov (alexx2000@mail.ru) 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 } unit uWCXmodule; {$mode objfpc}{$H+} {$include calling.inc} interface uses LCLType, Classes, Dialogs, DCClassesUtf8, dynlibs, SysUtils, uExtension, uWCXprototypes, WcxPlugin, Extension, DCBasicTypes, DCXmlConfig, uClassesEx; Type TWCXOperation = (OP_EXTRACT, OP_PACK, OP_DELETE); { EWcxModuleException } EWcxModuleException = class(EOSError) public constructor Create(AErrorCode: Integer); end; { TWCXHeaderData } { Handles THeaderData and THeaderDataEx } TWCXHeader = class(TObjectEx) private FileTime: LongInt; FDateTime: TDateTime; FNanoTime: TWinFileTime; private function GetDateTime: TDateTime; function PCharLToUTF8(CharString: PChar; MaxSize: Integer): String; public ArcName: String; FileName: String; Flags, HostOS, FileCRC, UnpVer, Method: Longint; FileAttr: TFileAttrs; PackSize, UnpSize: Int64; Cmt: String; CmtState: Longint; function Clone: TWCXHeader; override; constructor Create(const Data: PHeaderData); overload; constructor Create(const Data: PHeaderDataEx); overload; constructor Create(const Data: PHeaderDataExW); overload; constructor Create; overload; // allows creating empty record property DateTime: TDateTime read GetDateTime write FDateTime; end; { TWcxModule } TWcxModule = class(TDcxModule) private FModuleName: String; FBackgroundFlags: Integer; public // module's functions { Mandatory } OpenArchive : TOpenArchive; ReadHeader : TReadHeader; ProcessFile : TProcessFile; CloseArchive : TCloseArchive; { Optional } ReadHeaderEx : TReadHeaderEx; PackFiles : TPackFiles; DeleteFiles : TDeleteFiles; GetPackerCaps : TGetPackerCaps; ConfigurePacker : TConfigurePacker; SetChangeVolProc : TSetChangeVolProc; SetProcessDataProc : TSetProcessDataProc; StartMemPack : TStartMemPack; PackToMem : TPackToMem; DoneMemPack : TDoneMemPack; CanYouHandleThisFile : TCanYouHandleThisFile; PackSetDefaultParams : TPackSetDefaultParams; PkSetCryptCallback : TPkSetCryptCallback; GetBackgroundFlags: TGetBackgroundFlags; { Unicode } OpenArchiveW: TOpenArchiveW; ReadHeaderExW: TReadHeaderExW; ProcessFileW: TProcessFileW; SetChangeVolProcW: TSetChangeVolProcW; SetProcessDataProcW:TSetProcessDataProcW; PackFilesW: TPackFilesW; DeleteFilesW: TDeleteFilesW; StartMemPackW: TStartMemPackW; CanYouHandleThisFileW: TCanYouHandleThisFileW; PkSetCryptCallbackW : TPkSetCryptCallbackW; { Extension API } ExtensionInitialize: TExtensionInitializeProc; ExtensionFinalize: TExtensionFinalizeProc; private function LoadModule(const sName:String):Boolean; {Load WCX plugin} procedure UnloadModule; {UnLoad WCX plugin} public constructor Create; destructor Destroy; override; { Reads WCX header using ReadHeaderEx if available or ReadHeader. } function ReadWCXHeader(hArcData: TArcHandle; out HeaderData: TWCXHeader): Integer; function OpenArchiveHandle(FileName: String; anOpenMode: Longint; out OpenResult: Longint): TArcHandle; function WcxProcessFile(hArcData: TArcHandle; Operation: LongInt; DestPath, DestName: String): LongInt; function WcxPackFiles(PackedFile, SubPath, SrcPath, AddList: String; Flags: LongInt): LongInt; function WcxDeleteFiles(PackedFile, DeleteList: String): LongInt; function WcxCanYouHandleThisFile(FileName: String): Boolean; function WcxStartMemPack(Options: LongInt; FileName: String): TArcHandle; procedure WcxSetChangeVolProc(hArcData: TArcHandle); overload; procedure WcxSetChangeVolProc(hArcData: TArcHandle; ChangeVolProcA: TChangeVolProc; ChangeVolProcW: TChangeVolProcW); overload; procedure WcxSetProcessDataProc(hArcData: TArcHandle; ProcessDataProcA: TProcessDataProc; ProcessDataProcW: TProcessDataProcW); procedure WcxSetCryptCallback(CryptoNr, Flags: Integer; PkCryptProcA: TPkCryptProc; PkCryptProcW: TPkCryptProcW); procedure VFSConfigure(Parent: HWND); function GetPluginCapabilities: Integer; function IsLoaded: Boolean; property ModuleName: String read FModuleName; property BackgroundFlags: Integer read FBackgroundFlags write FBackgroundFlags; end; { TWCXModuleList } TWCXModuleList = class(TStringList) private FModuleList: TStringListEx; private function GetAEnabled(Index: Integer): Boolean; function GetAExt(Index: Integer): String; function GetAFileName(Index: Integer): String; function GetAFlags(Index: Integer): PtrInt; procedure SetAEnabled(Index: Integer; const AValue: Boolean); procedure SetAFileName(Index: Integer; const AValue: String); procedure SetAFlags(Index: Integer; const AValue: PtrInt); procedure SetExt(Index: Integer; const AValue: String); public constructor Create; reintroduce; destructor Destroy; override; public procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); function ComputeSignature(seed: dword): dword; function Add(Ext: String; Flags: PtrInt; FileName: String): Integer; reintroduce; function FindFirstEnabledByName(Name: String): Integer; function Find(const aFileName, aExt: String): Integer; overload; function LoadModule(const FileName: String): TWcxModule; property FileName[Index: Integer]: String read GetAFileName write SetAFileName; property Flags[Index: Integer]: PtrInt read GetAFlags write SetAFlags; property Ext[Index: Integer]: String read GetAExt write SetExt; property Enabled[Index: Integer]: Boolean read GetAEnabled write SetAEnabled; end; function GetErrorMsg(iErrorMsg : Integer): String; implementation uses //Lazarus, Free-Pascal, etc. SysConst, LazUTF8, FileUtil, //DC uDCUtils, uComponentsSignature, uGlobsPaths, uLng, uOSUtils, DCOSUtils, uOSForms, DCDateTimeUtils, DCConvertEncoding, fDialogBox, uDebug, uShowMsg, uLog, uGlobs; const WcxIniFileName = 'wcx.ini'; function ChangeVolProc(var ArcName : String; Mode: LongInt): LongInt; begin Result:= 1; case Mode of PK_VOL_ASK: begin if not ShowInputQuery('Double Commander', rsMsgSelLocNextVol, ArcName) then Result := 0; // Abort operation end; PK_VOL_NOTIFY: if log_arc_op in gLogOptions then LogWrite(rsMsgNextVolUnpack + #32 + ArcName); end; end; function ChangeVolProcA(ArcName : PAnsiChar; Mode: LongInt): LongInt; dcpcall; var sArcName: String; begin sArcName:= CeSysToUtf8(StrPas(ArcName)); Result:= ChangeVolProc(sArcName, Mode); if (Mode = PK_VOL_ASK) and (Result <> 0) then StrPLCopy(ArcName, CeUtf8ToSys(sArcName), MAX_PATH); end; function ChangeVolProcW(ArcName : PWideChar; Mode: LongInt): LongInt; dcpcall; var sArcName: String; begin sArcName:= UTF16ToUTF8(UnicodeString(ArcName)); Result:= ChangeVolProc(sArcName, Mode); if (Mode = PK_VOL_ASK) and (Result <> 0) then StrPLCopy(ArcName, CeUtf8ToUtf16(sArcName), MAX_PATH); end; { EWcxModuleException } constructor EWcxModuleException.Create(AErrorCode: Integer); begin ErrorCode:= AErrorCode; inherited Create(GetErrorMsg(ErrorCode)); end; constructor TWcxModule.Create; begin FModuleHandle := 0; end; destructor TWcxModule.Destroy; begin if IsLoaded then begin if Assigned(ExtensionFinalize) then ExtensionFinalize(nil); //------------------------------------------------------ UnloadModule; end; inherited Destroy; end; function TWcxModule.OpenArchiveHandle(FileName: String; anOpenMode: Longint; out OpenResult: Longint): TArcHandle; var ArcFile: tOpenArchiveData; ArcFileW: tOpenArchiveDataW; AnsiFileName: AnsiString; WideFileName: WideString; begin if (anOpenMode >= PK_OM_LIST) and (anOpenMode <= PK_OM_EXTRACT) then begin if Assigned(OpenArchiveW) then begin FillChar(ArcFileW, SizeOf(ArcFileW), #0); WideFileName := CeUtf8ToUtf16(FileName); ArcFileW.ArcName := PWideChar(WideFileName); // Pointer to local variable. ArcFileW.OpenMode := anOpenMode; Result := OpenArchiveW(ArcFileW); if Result = 0 then OpenResult := ArcFileW.OpenResult else OpenResult := E_SUCCESS; end else if Assigned(OpenArchive) then begin FillChar(ArcFile, SizeOf(ArcFile), #0); AnsiFileName := mbFileNameToSysEnc(FileName); ArcFile.ArcName := PAnsiChar(AnsiFileName); // Pointer to local variable. ArcFile.OpenMode := anOpenMode; Result := OpenArchive(ArcFile); if Result = 0 then OpenResult := ArcFile.OpenResult else OpenResult := E_SUCCESS; end; end else raise Exception.Create('Invalid WCX open mode'); end; function TWcxModule.WcxProcessFile(hArcData: TArcHandle; Operation: LongInt; DestPath, DestName: String): LongInt; begin if Assigned(ProcessFileW) then begin if DestPath = EmptyStr then Result:= ProcessFileW(hArcData, Operation, nil, PWideChar(CeUtf8ToUtf16(DestName))) else Result:= ProcessFileW(hArcData, Operation, PWideChar(CeUtf8ToUtf16(DestPath)), PWideChar(CeUtf8ToUtf16(DestName))); end else if Assigned(ProcessFile) then begin if DestPath = EmptyStr then Result:= ProcessFile(hArcData, Operation, nil, PAnsiChar(CeUtf8ToSys(DestName))) else Result:= ProcessFile(hArcData, Operation, PAnsiChar(CeUtf8ToSys(DestPath)), PAnsiChar(CeUtf8ToSys(DestName))); end; end; function TWcxModule.WcxPackFiles(PackedFile, SubPath, SrcPath, AddList: String; Flags: LongInt): LongInt; begin if Assigned(PackFilesW) then begin if SubPath = EmptyStr then Result:= PackFilesW(PWideChar(CeUtf8ToUtf16(PackedFile)), nil, PWideChar(CeUtf8ToUtf16(SrcPath)), PWideChar(CeUtf8ToUtf16(AddList)), Flags) else Result:= PackFilesW(PWideChar(CeUtf8ToUtf16(PackedFile)), PWideChar(CeUtf8ToUtf16(SubPath)), PWideChar(CeUtf8ToUtf16(SrcPath)), PWideChar(CeUtf8ToUtf16(AddList)), Flags); end else if Assigned(PackFiles) then begin if SubPath = EmptyStr then Result:= PackFiles(PAnsiChar(CeUtf8ToSys(PackedFile)), nil, PAnsiChar(CeUtf8ToSys(SrcPath)), PAnsiChar(CeUtf8ToSys(AddList)), Flags) else Result:= PackFiles(PAnsiChar(CeUtf8ToSys(PackedFile)), PAnsiChar(CeUtf8ToSys(SubPath)), PAnsiChar(CeUtf8ToSys(SrcPath)), PAnsiChar(CeUtf8ToSys(AddList)), Flags); end; end; function TWcxModule.WcxDeleteFiles(PackedFile, DeleteList: String): LongInt; begin if Assigned(DeleteFilesW) then Result:= DeleteFilesW(PWideChar(CeUtf8ToUtf16(PackedFile)), PWideChar(CeUtf8ToUtf16(DeleteList))) else if Assigned(DeleteFiles) then Result:= DeleteFiles(PAnsiChar(CeUtf8ToSys(PackedFile)), PAnsiChar(CeUtf8ToSys(DeleteList))); end; function TWcxModule.WcxCanYouHandleThisFile(FileName: String): Boolean; begin if Assigned(CanYouHandleThisFileW) then Result:= CanYouHandleThisFileW(PWideChar(CeUtf8ToUtf16(FileName))) else if Assigned(CanYouHandleThisFile) then Result:= CanYouHandleThisFile(PAnsiChar(CeUtf8ToSys(FileName))) else Result:= True; end; function TWcxModule.WcxStartMemPack(Options: LongInt; FileName: String): TArcHandle; begin if Assigned(StartMemPackW) then Result:= StartMemPackW(Options, PWideChar(CeUtf8ToUtf16(FileName))) else if Assigned(StartMemPack) then Result:= StartMemPack(Options, PAnsiChar(CeUtf8ToSys(FileName))); end; procedure TWcxModule.WcxSetChangeVolProc(hArcData: TArcHandle); begin WcxSetChangeVolProc(hArcData, @ChangeVolProcA, @ChangeVolProcW); end; procedure TWcxModule.WcxSetChangeVolProc(hArcData: TArcHandle; ChangeVolProcA: TChangeVolProc; ChangeVolProcW: TChangeVolProcW); begin if Assigned(SetChangeVolProcW) then SetChangeVolProcW(hArcData, ChangeVolProcW); if Assigned(SetChangeVolProc) then SetChangeVolProc(hArcData, ChangeVolProcA); end; procedure TWcxModule.WcxSetProcessDataProc(hArcData: TArcHandle; ProcessDataProcA: TProcessDataProc; ProcessDataProcW: TProcessDataProcW); begin if Assigned(SetProcessDataProcW) then SetProcessDataProcW(hArcData, ProcessDataProcW); if Assigned(SetProcessDataProc) then SetProcessDataProc(hArcData, ProcessDataProcA); end; procedure TWcxModule.WcxSetCryptCallback(CryptoNr, Flags: Integer; PkCryptProcA: TPkCryptProc; PkCryptProcW: TPkCryptProcW); begin if Assigned(PkSetCryptCallbackW) then PkSetCryptCallbackW(PkCryptProcW, CryptoNr, Flags); if Assigned(PkSetCryptCallback) then PkSetCryptCallback(PkCryptProcA, CryptoNr, Flags); end; function TWcxModule.LoadModule(const sName:String):Boolean; var StartupInfo: TExtensionStartupInfo; PackDefaultParamStruct : TPackDefaultParamStruct; begin FModuleName := ExtractFileName(sName); FModulePath := mbExpandFileName(sName); FModuleHandle := mbLoadLibrary(FModulePath); if FModuleHandle = 0 then Exit(False); DCDebug('WCX module loaded ' + sName + ' at ' + hexStr(Pointer(FModuleHandle))); // Mandatory functions OpenArchive:= TOpenArchive(GetProcAddress(FModuleHandle,'OpenArchive')); ReadHeader:= TReadHeader(GetProcAddress(FModuleHandle,'ReadHeader')); ReadHeaderEx:= TReadHeaderEx(GetProcAddress(FModuleHandle,'ReadHeaderEx')); ProcessFile:= TProcessFile(GetProcAddress(FModuleHandle,'ProcessFile')); CloseArchive:= TCloseArchive(GetProcAddress(FModuleHandle,'CloseArchive')); // Unicode OpenArchiveW:= TOpenArchiveW(GetProcAddress(FModuleHandle,'OpenArchiveW')); ReadHeaderExW:= TReadHeaderExW(GetProcAddress(FModuleHandle,'ReadHeaderExW')); ProcessFileW:= TProcessFileW(GetProcAddress(FModuleHandle,'ProcessFileW')); Result:= (OpenArchive <> nil) and (ReadHeader <> nil) and (ProcessFile <> nil); if (Result = False) then begin OpenArchive:= nil; ReadHeader:= nil; ProcessFile:= nil; Result:= (OpenArchiveW <> nil) and (ReadHeaderExW <> nil) and (ProcessFileW <> nil); end; if (Result = False) or (CloseArchive = nil) then begin OpenArchiveW:= nil; ReadHeaderExW:= nil; ProcessFileW:= nil; CloseArchive:= nil; Exit(False); end; // Optional functions PackFiles:= TPackFiles(GetProcAddress(FModuleHandle,'PackFiles')); DeleteFiles:= TDeleteFiles(GetProcAddress(FModuleHandle,'DeleteFiles')); GetPackerCaps:= TGetPackerCaps(GetProcAddress(FModuleHandle,'GetPackerCaps')); ConfigurePacker:= TConfigurePacker(GetProcAddress(FModuleHandle,'ConfigurePacker')); SetChangeVolProc:= TSetChangeVolProc(GetProcAddress(FModuleHandle,'SetChangeVolProc')); SetProcessDataProc:= TSetProcessDataProc(GetProcAddress(FModuleHandle,'SetProcessDataProc')); StartMemPack:= TStartMemPack(GetProcAddress(FModuleHandle,'StartMemPack')); PackToMem:= TPackToMem(GetProcAddress(FModuleHandle,'PackToMem')); DoneMemPack:= TDoneMemPack(GetProcAddress(FModuleHandle,'DoneMemPack')); CanYouHandleThisFile:= TCanYouHandleThisFile(GetProcAddress(FModuleHandle,'CanYouHandleThisFile')); PackSetDefaultParams:= TPackSetDefaultParams(GetProcAddress(FModuleHandle,'PackSetDefaultParams')); PkSetCryptCallback:= TPkSetCryptCallback(GetProcAddress(FModuleHandle,'PkSetCryptCallback')); GetBackgroundFlags:= TGetBackgroundFlags(GetProcAddress(FModuleHandle,'GetBackgroundFlags')); // Unicode SetChangeVolProcW:= TSetChangeVolProcW(GetProcAddress(FModuleHandle,'SetChangeVolProcW')); SetProcessDataProcW:= TSetProcessDataProcW(GetProcAddress(FModuleHandle,'SetProcessDataProcW')); PackFilesW:= TPackFilesW(GetProcAddress(FModuleHandle,'PackFilesW')); DeleteFilesW:= TDeleteFilesW(GetProcAddress(FModuleHandle,'DeleteFilesW')); StartMemPackW:= TStartMemPackW(GetProcAddress(FModuleHandle,'StartMemPackW')); CanYouHandleThisFileW:= TCanYouHandleThisFileW(GetProcAddress(FModuleHandle,'CanYouHandleThisFileW')); PkSetCryptCallbackW:= TPkSetCryptCallbackW(GetProcAddress(FModuleHandle,'PkSetCryptCallbackW')); // Extension API ExtensionInitialize:= TExtensionInitializeProc(GetProcAddress(FModuleHandle,'ExtensionInitialize')); ExtensionFinalize:= TExtensionFinalizeProc(GetProcAddress(FModuleHandle,'ExtensionFinalize')); if Assigned(PackSetDefaultParams) then begin with PackDefaultParamStruct do begin Size := SizeOf(PackDefaultParamStruct); PluginInterfaceVersionLow := 22; PluginInterfaceVersionHi := 2; DefaultIniName := mbFileNameToSysEnc(gpCfgDir + WcxIniFileName); end; PackSetDefaultParams(@PackDefaultParamStruct); end; if not Assigned(GetBackgroundFlags) then FBackgroundFlags:= 0 else FBackgroundFlags:= GetBackgroundFlags(); // Extension API if Assigned(ExtensionInitialize) then begin InitializeExtension(@StartupInfo); ExtensionInitialize(@StartupInfo); end; end; procedure TWcxModule.UnloadModule; begin if FModuleHandle <> NilHandle then begin FreeLibrary(FModuleHandle); FModuleHandle := NilHandle; end; // Mandatory OpenArchive:= nil; ReadHeader:= nil; ReadHeaderEx:= nil; ProcessFile:= nil; CloseArchive:= nil; // Optional PackFiles:= nil; DeleteFiles:= nil; GetPackerCaps:= nil; ConfigurePacker:= nil; SetChangeVolProc:= nil; SetProcessDataProc:= nil; StartMemPack:= nil; PackToMem:= nil; DoneMemPack:= nil; CanYouHandleThisFile:= nil; PackSetDefaultParams:= nil; PkSetCryptCallback:= nil; GetBackgroundFlags:= nil; // Unicode OpenArchiveW:= nil; ReadHeaderExW:= nil; ProcessFileW:= nil; SetChangeVolProcW:= nil; SetProcessDataProcW:= nil; PackFilesW:= nil; DeleteFilesW:= nil; StartMemPackW:= nil; CanYouHandleThisFileW:= nil; PkSetCryptCallbackW:= nil; // Extension API ExtensionInitialize:= nil; ExtensionFinalize:= nil; end; function GetErrorMsg(iErrorMsg : Integer): String; begin case iErrorMsg of E_END_ARCHIVE : Result := rsMsgErrEndArchive; E_NO_MEMORY : Result := rsMsgErrNoMemory; E_BAD_DATA : Result := rsMsgErrBadData; E_BAD_ARCHIVE : Result := rsMsgErrBadArchive; E_UNKNOWN_FORMAT : Result := rsMsgErrUnknownFormat; E_EOPEN : Result := rsMsgErrEOpen; E_ECREATE : Result := rsMsgErrECreate; E_ECLOSE : Result := rsMsgErrEClose; E_EREAD : Result := rsMsgErrERead; E_EWRITE : Result := rsMsgErrEWrite; E_SMALL_BUF : Result := rsMsgErrSmallBuf; E_EABORTED : Result := rsMsgErrEAborted; E_NO_FILES : Result := rsMsgErrNoFiles; E_TOO_MANY_FILES : Result := rsMsgErrTooManyFiles; E_NOT_SUPPORTED : Result := rsMsgErrNotSupported; else Result := Format(SUnknownErrorCode, [iErrorMsg]); end; end; procedure TWcxModule.VFSConfigure(Parent: HWND); begin if Assigned(ConfigurePacker) then ConfigurePacker(GetWindowHandle(Parent), FModuleHandle); end; function TWcxModule.ReadWCXHeader(hArcData: TArcHandle; out HeaderData: TWCXHeader): Integer; var ArcHeader : THeaderData; ArcHeaderEx : THeaderDataEx; ArcHeaderExW : THeaderDataExW; begin HeaderData := nil; if Assigned(ReadHeaderExW) then begin FillChar(ArcHeaderExW, SizeOf(ArcHeaderExW), #0); Result := ReadHeaderExW(hArcData, ArcHeaderExW); if Result = E_SUCCESS then begin HeaderData := TWCXHeader.Create(PHeaderDataExW(@ArcHeaderExW)); end; end else if Assigned(ReadHeaderEx) then begin FillChar(ArcHeaderEx, SizeOf(ArcHeaderEx), #0); Result := ReadHeaderEx(hArcData, ArcHeaderEx); if Result = E_SUCCESS then begin HeaderData := TWCXHeader.Create(PHeaderDataEx(@ArcHeaderEx)); end; end else if Assigned(ReadHeader) then begin FillChar(ArcHeader, SizeOf(ArcHeader), #0); Result := ReadHeader(hArcData, ArcHeader); if Result = E_SUCCESS then begin HeaderData := TWCXHeader.Create(PHeaderData(@ArcHeader)); end; end else begin Result := E_NOT_SUPPORTED; end; end; function TWcxModule.GetPluginCapabilities: Integer; begin if Assigned(GetPackerCaps) then Result := GetPackerCaps() else Result := 0; end; function TWcxModule.IsLoaded: Boolean; begin Result := (FModuleHandle <> NilHandle); end; { TWCXModuleList } function TWCXModuleList.GetAEnabled(Index: Integer): Boolean; begin Result:= Boolean(PtrInt(Objects[Index])); end; function TWCXModuleList.GetAExt(Index: Integer): String; begin Result:= Names[Index]; end; function TWCXModuleList.GetAFileName(Index: Integer): String; var sCurrPlugin: String; iPosComma : Integer; begin sCurrPlugin:= ValueFromIndex[Index]; iPosComma:= Pos(',', sCurrPlugin); //get file name Result:= Copy(sCurrPlugin, iPosComma + 1, Length(sCurrPlugin) - iPosComma); end; function TWCXModuleList.GetAFlags(Index: Integer): PtrInt; var sCurrPlugin: String; iPosComma : Integer; begin sCurrPlugin:= ValueFromIndex[Index]; iPosComma:= Pos(',', sCurrPlugin); // get packer flags Result:= StrToInt(Copy(sCurrPlugin, 1, iPosComma-1)); end; procedure TWCXModuleList.SetAEnabled(Index: Integer; const AValue: Boolean); begin Objects[Index]:= TObject(PtrInt(AValue)); end; procedure TWCXModuleList.SetAFileName(Index: Integer; const AValue: String); begin ValueFromIndex[Index]:= IntToStr(GetAFlags(Index)) + #44 + AValue; end; procedure TWCXModuleList.SetAFlags(Index: Integer; const AValue: PtrInt); begin ValueFromIndex[Index]:= IntToStr(AValue) + #44 + GetAFileName(Index); end; procedure TWCXModuleList.SetExt(Index: Integer; const AValue: String); var sValue : String; begin sValue:= ValueFromIndex[Index]; Self[Index]:= AValue + '=' + sValue; end; constructor TWCXModuleList.Create; begin FModuleList:= TStringListEx.Create; FModuleList.Sorted:= True; end; destructor TWCXModuleList.Destroy; var I: Integer; begin for I:= 0 to FModuleList.Count - 1 do begin TWcxModule(FModuleList.Objects[I]).Free; end; FreeAndNil(FModuleList); inherited Destroy; end; procedure TWCXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode); var I: Integer; AExt, APath: String; AFlags: Integer; begin Clear; ANode := ANode.FindNode('WcxPlugins'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('WcxPlugin') = 0 then begin if AConfig.TryGetValue(ANode, 'ArchiveExt', AExt) and AConfig.TryGetValue(ANode, 'Path', APath) then begin AFlags := AConfig.GetValue(ANode, 'Flags', 0); I := Add(AExt, AFlags, APath); Enabled[I] := AConfig.GetAttr(ANode, 'Enabled', True); end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; end; end; procedure TWCXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode); var I: Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'WcxPlugins', True); AConfig.ClearNode(ANode); for I := 0 to Count - 1 do begin SubNode := AConfig.AddNode(ANode, 'WcxPlugin'); AConfig.SetAttr(SubNode, 'Enabled', Enabled[I]); AConfig.AddValue(SubNode, 'ArchiveExt', Ext[I]); AConfig.AddValue(SubNode, 'Path', FileName[I]); AConfig.AddValue(SubNode, 'Flags', Flags[I]); end; end; { TWCXModuleList.ComputeSignature } function TWCXModuleList.ComputeSignature(seed: dword): dword; var iIndex: integer; begin result := seed; for iIndex := 0 to pred(Count) do begin result := ComputeSignatureBoolean(result, Enabled[iIndex]); result := ComputeSignatureString(result, Ext[iIndex]); result := ComputeSignatureString(result, FileName[iIndex]); result := ComputeSignaturePtrInt(result, Flags[iIndex]); end; end; { TWCXModuleList.Add } function TWCXModuleList.Add(Ext: String; Flags: PtrInt; FileName: String): Integer; begin Result:= AddObject(Ext + '=' + IntToStr(Flags) + #44 + FileName, TObject(True)); end; function TWCXModuleList.FindFirstEnabledByName(Name: String): Integer; begin Result:=0; while Result < Count do begin if Enabled[Result] and (DoCompareText(Names[Result], Name) = 0) then Exit else Result := Result + 1; end; if Result=Count then Result:=-1; end; function TWCXModuleList.Find(const aFileName, aExt: String): Integer; begin Result:=0; while Result < Count do begin if (DoCompareText(Ext[Result], aExt) = 0) and (DoCompareText(FileName[Result], aFileName) = 0) then Exit else Result := Result + 1; end; if Result=Count then Result:=-1; end; function TWCXModuleList.LoadModule(const FileName: String): TWcxModule; var Index: Integer; begin if FModuleList.Find(FileName, Index) then Result := TWcxModule(FModuleList.Objects[Index]) else begin Result := TWcxModule.Create; if not Result.LoadModule(FileName) then FreeAndNil(Result) else begin FModuleList.AddObject(FileName, Result); end; end; end; { TWCXHeader } constructor TWCXHeader.Create(const Data: PHeaderData); begin ArcName := PCharLToUTF8(Data^.ArcName, SizeOf(Data^.ArcName)); FileName := PCharLToUTF8(Data^.FileName, SizeOf(Data^.FileName)); Flags := Data^.Flags; HostOS := Data^.HostOS; FileCRC := Data^.FileCRC; FileTime := Data^.FileTime; UnpVer := Data^.UnpVer; Method := Data^.Method; FileAttr := TFileAttrs(Data^.FileAttr); PackSize := Data^.PackSize; UnpSize := Data^.UnpSize; if Assigned(Data^.CmtBuf) then Cmt := PCharLToUTF8(Data^.CmtBuf, Data^.CmtSize); CmtState := Data^.CmtState; end; constructor TWCXHeader.Create(const Data: PHeaderDataEx); function Combine64(High, Low: LongWord): Int64; begin Result := Int64(High) shl (SizeOf(Int64) shl 2); Result := Result + Int64(Low); end; begin ArcName := PCharLToUTF8(Data^.ArcName, SizeOf(Data^.ArcName)); FileName := PCharLToUTF8(Data^.FileName, SizeOf(Data^.FileName)); Flags := Data^.Flags; HostOS := Data^.HostOS; FileCRC := Data^.FileCRC; FileTime := Data^.FileTime; UnpVer := Data^.UnpVer; Method := Data^.Method; FileAttr := TFileAttrs(Data^.FileAttr); PackSize := Combine64(Data^.PackSizeHigh, Data^.PackSize); UnpSize := Combine64(Data^.UnpSizeHigh, Data^.UnpSize); if Assigned(Data^.CmtBuf) then Cmt := PCharLToUTF8(Data^.CmtBuf, Data^.CmtSize); CmtState := Data^.CmtState; end; constructor TWCXHeader.Create(const Data: PHeaderDataExW); function Combine64(High, Low: LongWord): Int64; begin Result := Int64(High) shl (SizeOf(Int64) shl 2); Result := Result + Int64(Low); end; begin ArcName := UTF16ToUTF8(UnicodeString(Data^.ArcName)); FileName := UTF16ToUTF8(UnicodeString(Data^.FileName)); Flags := Data^.Flags; HostOS := Data^.HostOS; FileCRC := Data^.FileCRC; FileTime := Data^.FileTime; UnpVer := Data^.UnpVer; Method := Data^.Method; FileAttr := TFileAttrs(Data^.FileAttr); PackSize := Combine64(Data^.PackSizeHigh, Data^.PackSize); UnpSize := Combine64(Data^.UnpSizeHigh, Data^.UnpSize); if Assigned(Data^.CmtBuf) then Cmt := PCharLToUTF8(Data^.CmtBuf, Data^.CmtSize); CmtState := Data^.CmtState; FNanoTime:= Data^.MfileTime; end; constructor TWCXHeader.Create; begin end; function TWCXHeader.GetDateTime: TDateTime; begin if FDateTime <> 0 then Result:= FDateTime else begin if (FNanoTime > 0) then FDateTime:= WinFileTimeToDateTime(FNanoTime) else begin if (FileTime = 0) then FDateTime:= DATE_TIME_NULL else begin FDateTime:= WcxFileTimeToDateTime(FileTime); end; end; Result:= FDateTime; end; end; function TWCXHeader.PCharLToUTF8(CharString: PChar; MaxSize: Integer): String; var NameLength: Integer; TempString: AnsiString; begin NameLength := strlen(CharString); if NameLength > MaxSize then NameLength := MaxSize; SetString(TempString, CharString, NameLength); Result := CeSysToUtf8(TempString); end; function TWCXHeader.Clone: TWCXHeader; begin Result:= TWCXHeader.Create; Result.ArcName:= ArcName; Result.FileName:= FileName; Result.Flags:= Flags; Result.HostOS:= HostOS; Result.FileCRC:= FileCRC; Result.FileTime:= FileTime; Result.UnpVer:= UnpVer; Result.Method:= Method; Result.FileAttr:=FileAttr; Result.PackSize:= PackSize; Result.UnpSize:= UnpSize; Result.Cmt:= Cmt; Result.CmtState:= CmtState; Result.FNanoTime:= FNanoTime; Result.FDateTime:= FDateTime; end; end. doublecmd-1.1.22/src/uwcxprototypes.pas0000644000175000001440000000516214743153644017245 0ustar alexxusersunit uWCXprototypes; {$mode objfpc}{$H+} interface uses LCLType, WcxPlugin; {$IFDEF MSWINDOWS}{$CALLING STDCALL}{$ELSE}{$CALLING CDECL}{$ENDIF} type { Mandatory } TOpenArchive = function (var ArchiveData : tOpenArchiveData): TArcHandle; TReadHeader = function (hArcData: TArcHandle; var HeaderData : THeaderData): Integer; TProcessFile = function (hArcData: TArcHandle; Operation: Integer; DestPath: PAnsiChar; DestName: PAnsiChar): Integer; TCloseArchive = function (hArcData: TArcHandle): Integer; { Optional } TPackFiles = function (PackedFile: PAnsiChar; SubPath: PAnsiChar; SrcPath: PAnsiChar; AddList: PAnsiChar; Flags: Integer): Integer; TDeleteFiles = function (PackedFile: PAnsiChar; DeleteList: PAnsiChar): Integer; TGetPackerCaps = function () : Integer; TConfigurePacker = procedure (Parent: HWND; DllInstance: THandle); TSetChangeVolProc = procedure (hArcData: TArcHandle; ChangeVolProc: tChangeVolProc); TSetProcessDataProc = procedure (hArcData: TArcHandle; ProcessDataProc: TProcessDataProc); TStartMemPack = function (Options: Integer; FileName: PAnsiChar): TArcHandle; TPackToMem = function (hMemPack: TArcHandle; BufIn: PByte; InLen: Integer; Taken: pInteger; BufOut: PByte; OutLen: Integer; Written: pInteger; SeekBy: pInteger): Integer; TDoneMemPack = function (hMemPack: TArcHandle): Integer; TCanYouHandleThisFile = function (FileName: PAnsiChar): boolean; TPackSetDefaultParams = procedure (dps: pPackDefaultParamStruct); TReadHeaderEx = function (hArcData: TArcHandle; var HeaderDataEx : THeaderDataEx): Integer; TPkSetCryptCallback = procedure (PkCryptProc: TPkCryptProc; CryptoNr, Flags: Integer); TGetBackgroundFlags = function(): Integer; { Unicode } TOpenArchiveW = function (var ArchiveData : tOpenArchiveDataW): TArcHandle; TReadHeaderExW = function (hArcData: TArcHandle; var HeaderDataExW : THeaderDataExW): Integer; TProcessFileW = function (hArcData: TArcHandle; Operation: Integer; DestPath, DestName: PWideChar): Integer; TSetChangeVolProcW = procedure (hArcData: TArcHandle; ChangeVolProc: tChangeVolProcW); TSetProcessDataProcW = procedure (hArcData: TArcHandle; ProcessDataProc: TProcessDataProcW); TPackFilesW = function (PackedFile, SubPath, SrcPath, AddList: PWideChar; Flags: Integer): Integer; TDeleteFilesW = function (PackedFile, DeleteList: PWideChar): Integer; TStartMemPackW = function (Options: Integer; FileName: PWideChar): TArcHandle; TCanYouHandleThisFileW = function (FileName: PWideChar): boolean; TPkSetCryptCallbackW = procedure (PkCryptProc: TPkCryptProcW; CryptoNr, Flags: Integer); {$CALLING DEFAULT} implementation end. doublecmd-1.1.22/src/uwdxmodule.pas0000644000175000001440000012565714743153644016317 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- WDX-API implementation. (TC WDX-API v1.5) Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2008-2024 Alexander Koblov (alexx2000@mail.ru) Some ideas were found in sources of WdxGuide by Alexey Torgashin and SuperWDX by Pavel Dubrovsky and Dmitry Vorotilin. 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, see . } unit uWDXModule; {$mode delphi}{$H+} interface uses //Lazarus, Free-Pascal, etc. Classes, SysUtils, dynlibs, //DC uLng, uWdxPrototypes, WdxPlugin, uDetectStr, lua, uFile, DCXmlConfig, uExtension; const WDX_MAX_LEN = 2048; type { TWdxField } TWdxField = class private OUnits: String; // Units (original) public FName: String; // Field name (english) LName: String; // Field name (localized) FType: Integer; FUnits: TStringArray; // Units (english) LUnits: TStringArray; // Units (localized) function GetUnitIndex(UnitName: String): Integer; end; { TWDXModule } TWDXModule = class(TDcxModule) private FFieldsList: TStringList; FParser: TParserControl; protected FFileName: String; FMutex: TRTLCriticalSection; protected procedure Translate; function GetADetectStr: String; virtual; procedure SetADetectStr(const AValue: String); virtual; procedure AddField(const AName, AUnits: String; AType: Integer); protected function GetAName: String; virtual; abstract; function GetAFileName: String; virtual; abstract; procedure SetAName(AValue: String); virtual; abstract; procedure SetAFileName(AValue: String); virtual; abstract; public //--------------------- constructor Create; virtual; destructor Destroy; override; //--------------------- function LoadModule: Boolean; virtual; abstract; procedure UnloadModule; virtual; abstract; function IsLoaded: Boolean; virtual; abstract; //--------------------- function FieldList: TStringList; virtual; function WdxFieldType(n: Integer): String; function GetFieldIndex(FieldName: String): Integer; virtual; function FileParamVSDetectStr(const aFile: TFile): Boolean; virtual; //------------------------------------------------------ procedure CallContentGetSupportedField; virtual; abstract; procedure CallContentSetDefaultParams; virtual; abstract; procedure CallContentStopGetValue(FileName: String); virtual; abstract; //--------------------- function CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; virtual; abstract; function CallContentGetDetectString: String; virtual; abstract; function CallContentGetValueV(FileName: String; FieldName: String; UnitName: String; flags: Integer): Variant; overload; virtual; function CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; overload; virtual; abstract; function CallContentGetValue(FileName: String; FieldName: String; UnitName: String; flags: Integer): String; overload; virtual; function CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; overload; virtual; abstract; function CallContentGetValue(FileName: String; FieldIndex: Integer; var UnitIndex: Integer): String; overload; virtual; abstract; function CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; virtual; abstract; {ContentSetValue ContentEditValue ContentSendStateInformation} //------------------------------------------------------ property Name: String read GetAName write SetAName; property FileName: String read GetAFileName write SetAFileName; property DetectStr: String read GetADetectStr write SetADetectStr; //--------------------- end; { TPluginWDX } TPluginWDX = class(TWDXModule) protected FForce: Boolean; FName: String; protected function GetAName: String; override; function GetAFileName: String; override; procedure SetAName(AValue: String); override; procedure SetAFileName(AValue: String); override; protected //a) Mandatory (must be implemented) ContentGetSupportedField: TContentGetSupportedField; ContentGetValue: TContentGetValue; //b) Optional (must NOT be implemented if unsupported!) ContentGetDetectString: TContentGetDetectString; ContentSetDefaultParams: TContentSetDefaultParams; ContentStopGetValue: TContentStopGetValue; ContentGetDefaultSortOrder: TContentGetDefaultSortOrder; ContentPluginUnloading: TContentPluginUnloading; ContentGetSupportedFieldFlags: TContentGetSupportedFieldFlags; ContentSetValue: TContentSetValue; ContentEditValue: TContentEditValue; ContentSendStateInformation: TContentSendStateInformation; //c) Unicode ContentGetValueW: TContentGetValueW; ContentStopGetValueW: TContentStopGetValueW; ContentSetValueW: TContentSetValueW; ContentSendStateInformationW: TContentSendStateInformationW; public //--------------------- function LoadModule: Boolean; override; procedure UnloadModule; override; function IsLoaded: Boolean; override; //--------------------- procedure CallContentGetSupportedField; override; procedure CallContentSetDefaultParams; override; procedure CallContentStopGetValue(FileName: String); override; //--------------------- function CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; override; function CallContentGetDetectString: String; override; function CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; overload; override; function CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; overload; override; function CallContentGetValue(FileName: String; FieldIndex: Integer; var UnitIndex: Integer): String; overload; override; function CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; override; {ContentSetValue ContentEditValue ContentSendStateInformation} //------------------------------------------------------ property ModuleHandle: TLibHandle read FModuleHandle; property Force: Boolean read FForce write FForce; //--------------------- end; { TLuaWdx } TLuaWdx = class(TWdxModule) private L: Plua_State; FForce: Boolean; FName: String; protected function GetAName: String; override; function GetAFileName: String; override; procedure SetAName(AValue: String); override; procedure SetAFileName(AValue: String); override; function DoScript(AName: String): Integer; function WdxLuaContentGetSupportedField(Index: Integer; var xFieldName, xUnits: String): Integer; procedure WdxLuaContentPluginUnloading; public constructor Create; override; //--------------------- function LoadModule: Boolean; override; procedure UnloadModule; override; function IsLoaded: Boolean; override; //--------------------- procedure CallContentGetSupportedField; override; procedure CallContentSetDefaultParams; override; procedure CallContentStopGetValue(FileName: String); override; //--------------------- function CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; override; function CallContentGetDetectString: String; override; function CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; overload; override; function CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; overload; override; function CallContentGetValue(FileName: String; FieldIndex: Integer; var UnitIndex: Integer): String; overload; override; function CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; override; //--------------------- property Force: Boolean read FForce write FForce; end; { TEmbeddedWDX } TEmbeddedWDX = class(TWDXModule) protected function GetAName: String; override; function GetAFileName: String; override; procedure SetAName({%H-}AValue: String); override; procedure SetAFileName({%H-}AValue: String); override; protected procedure AddField(const AName, XName: String; AType: Integer); public //--------------------- constructor Create; override; //--------------------- function LoadModule: Boolean; override; procedure UnloadModule; override; function IsLoaded: Boolean; override; //--------------------- function GetFieldIndex(FieldName: String): Integer; override; end; { TWDXModuleList } TWDXModuleList = class private Flist: TStringList; function GetCount: Integer; public //--------------------- constructor Create; destructor Destroy; override; //--------------------- procedure Assign(Source: TWDXModuleList); function IndexOfName(const AName: String): Integer; //--------------------- procedure Clear; procedure Exchange(Index1, Index2: Integer); procedure Move(CurIndex, NewIndex: Integer); procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload; function ComputeSignature(seed: dword): dword; procedure DeleteItem(Index: Integer); //--------------------- function Add(Item: TWDXModule): Integer; overload; function Add(FileName: String): Integer; overload; function Add(AName, FileName, DetectStr: String): Integer; overload; function IsLoaded(AName: String): Boolean; overload; function IsLoaded(Index: Integer): Boolean; overload; function LoadModule(AName: String): Boolean; overload; function LoadModule(Index: Integer): Boolean; overload; function GetWdxModule(Index: Integer): TWDXModule; overload; function GetWdxModule(AName: String): TWDXModule; overload; //--------------------- //property WdxList:TStringList read Flist; property Count: Integer read GetCount; end; function StrToVar(const Value: String; FieldType: Integer): Variant; implementation uses //Lazarus, Free-Pascal, etc. Math, StrUtils, LazUTF8, FileUtil, //DC DCClassesUtf8, DCStrUtils, uComponentsSignature, uGlobs, uGlobsPaths, uDebug, uDCUtils, uOSUtils, DCBasicTypes, DCOSUtils, DCDateTimeUtils, DCConvertEncoding, uLuaPas; const WdxIniFileName = 'wdx.ini'; type TWdxModuleClass = class of TWdxModule; // Language code conversion table // Double Commander <-> Total Commander const WdxLangTable: array[0..30, 0..1] of String = ( ('be', 'BEL'), ('bg', 'BUL'), ('ca', 'CAT'), ('zh_CN', 'CHN'), ('cs', 'CZ' ), ('da', 'DAN'), ('de', 'DEU'), ('nl', 'DUT'), ('el', 'ELL'), ('es', 'ESP'), ('fr', 'FRA'), ('hr', 'HR' ), ('hu', 'HUN'), ('it', 'ITA'), ('ja', 'JPN'), ('ko', 'KOR'), ('nb', 'NOR'), ('nn', 'NOR'), ('pl', 'POL'), ('pt', 'POR'), ('pt_BR', 'PTG'), ('ro', 'ROM'), ('ru', 'RUS'), ('sk', 'SK' ), ('sr', 'SRB'), ('sr@latin', 'SRL'), ('sl', 'SVN'), ('sv', 'SWE'), ('tr', 'TUR'), ('zh_TW', 'TW' ), ('uk', 'UKR') ); function GetWdxLang(const Code: String): String; var Index: Integer; begin for Index:= Low(WdxLangTable) to High(WdxLangTable) do begin if CompareStr(WdxLangTable[Index, 0], Code) = 0 then begin Exit(WdxLangTable[Index, 1]); end; end; Result:= Code; end; function StrToVar(const Value: String; FieldType: Integer): Variant; begin case FieldType of ft_fieldempty: Result := Unassigned; ft_numeric_32: Result := StrToInt(Value); ft_numeric_64: Result := StrToInt64(Value); ft_numeric_floating: Result := StrToFloat(Value); ft_date: Result := StrToDate(Value); ft_time: Result := StrToTime(Value); ft_datetime: Result := StrToDateTime(Value); ft_boolean: Result := ((LowerCase(Value) = 'true') OR (Value = rsSimpleWordTrue)); ft_multiplechoice, ft_string, ft_fulltext, ft_stringw: Result := Value; else Result := Unassigned; end; end; { TWDXModuleList } function TWDXModuleList.GetCount: Integer; begin if Assigned(Flist) then Result := Flist.Count else Result := 0; end; constructor TWDXModuleList.Create; begin Flist := TStringList.Create; end; destructor TWDXModuleList.Destroy; begin Clear; FreeAndNil(Flist); inherited Destroy; end; procedure TWDXModuleList.Assign(Source: TWDXModuleList); var I: Integer; Module: TWDXModule; begin if Assigned(Source) then begin Clear; for I := 0 to Source.Flist.Count - 1 do begin with TWdxModule(Source.Flist.Objects[I]) do begin Module:= TWdxModuleClass(ClassType).Create; Module.Name:= Name; Module.FileName:= FileName; Module.DetectStr:= DetectStr; Add(Module); end; end; end; end; function TWDXModuleList.IndexOfName(const AName: String): Integer; begin Result := Flist.IndexOf(UpCase(AName)); end; procedure TWDXModuleList.Clear; var i: Integer; begin for i := 0 to Flist.Count - 1 do TWDXModule(Flist.Objects[i]).Free; Flist.Clear; end; procedure TWDXModuleList.Exchange(Index1, Index2: Integer); begin FList.Exchange(Index1, Index2); end; procedure TWDXModuleList.Move(CurIndex, NewIndex: Integer); begin FList.Move(CurIndex, NewIndex); end; procedure TWDXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode); var AName, APath: String; AWdxModule: TWDXModule; begin Self.Clear; ANode := ANode.FindNode('WdxPlugins'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('WdxPlugin') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', AName) and AConfig.TryGetValue(ANode, 'Path', APath) then begin // Create a correct object based on plugin file extension. if UpCase(ExtractFileExt(APath)) = '.LUA' then AWdxModule := TLuaWdx.Create else AWdxModule := TPluginWDX.Create; AWdxModule.Name := AName; AWdxModule.FileName := APath; AWdxModule.DetectStr := AConfig.GetValue(ANode, 'DetectString', ''); Flist.AddObject(UpCase(AName), AWdxModule); end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; end; end; procedure TWDXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode); var i: Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'WdxPlugins', True); AConfig.ClearNode(ANode); For i := 0 to Flist.Count - 1 do begin if not (Flist.Objects[I] is TEmbeddedWDX) then begin SubNode := AConfig.AddNode(ANode, 'WdxPlugin'); AConfig.AddValue(SubNode, 'Name', TWDXModule(Flist.Objects[I]).Name); AConfig.AddValue(SubNode, 'Path', TWDXModule(Flist.Objects[I]).FileName); AConfig.AddValue(SubNode, 'DetectString', TWDXModule(Flist.Objects[I]).DetectStr); end; end; end; { TWDXModuleList.ComputeSignature } function TWDXModuleList.ComputeSignature(seed: dword): dword; var iIndex: integer; begin result := seed; for iIndex := 0 to pred(Count) do begin result := ComputeSignatureString(result, TWDXModule(Flist.Objects[iIndex]).Name); result := ComputeSignatureString(result, TWDXModule(Flist.Objects[iIndex]).FileName); result := ComputeSignatureString(result, TWDXModule(Flist.Objects[iIndex]).DetectStr); end; end; procedure TWDXModuleList.DeleteItem(Index: Integer); begin if (Index > -1) and (Index < Flist.Count) then begin TWDXModule(Flist.Objects[Index]).Free; Flist.Delete(Index); end; end; function TWDXModuleList.Add(Item: TWDXModule): Integer; begin Result := Flist.AddObject(UpCase(item.Name), Item); end; function TWDXModuleList.Add(FileName: String): Integer; var s: String; begin s := ExtractFileName(FileName); if pos('.', s) > 0 then Delete(s, pos('.', s), length(s)); if UpCase(ExtractFileExt(FileName)) = '.LUA' then Result := Flist.AddObject(UpCase(s), TLuaWdx.Create) else Result := Flist.AddObject(UpCase(s), TPluginWDX.Create); TWDXModule(Flist.Objects[Result]).Name := s; TWDXModule(Flist.Objects[Result]).FileName := FileName; if TWDXModule(Flist.Objects[Result]).LoadModule then begin TWDXModule(Flist.Objects[Result]).DetectStr := TWDXModule(Flist.Objects[Result]).CallContentGetDetectString; TWDXModule(Flist.Objects[Result]).UnloadModule; end; end; function TWDXModuleList.Add(AName, FileName, DetectStr: String): Integer; begin if UpCase(ExtractFileExt(FileName)) = '.LUA' then Result := Flist.AddObject(UpCase(AName), TLuaWdx.Create) else Result := Flist.AddObject(UpCase(AName), TPluginWDX.Create); TWDXModule(Flist.Objects[Result]).Name := AName; TWDXModule(Flist.Objects[Result]).DetectStr := DetectStr; TWDXModule(Flist.Objects[Result]).FileName := FileName; end; function TWDXModuleList.IsLoaded(AName: String): Boolean; var x: Integer; begin x := Flist.IndexOf(AName); if x = -1 then Result := False else begin Result := GetWdxModule(x).IsLoaded; end; end; function TWDXModuleList.IsLoaded(Index: Integer): Boolean; begin Result := GetWdxModule(Index).IsLoaded; end; function TWDXModuleList.LoadModule(AName: String): Boolean; var x: Integer; begin x := Flist.IndexOf(UpCase(AName)); if x = -1 then Result := False else begin Result := GetWdxModule(x).LoadModule; end; end; function TWDXModuleList.LoadModule(Index: Integer): Boolean; begin Result := GetWdxModule(Index).LoadModule; end; function TWDXModuleList.GetWdxModule(Index: Integer): TWDXModule; begin Result := TWDXModule(Flist.Objects[Index]); end; function TWDXModuleList.GetWdxModule(AName: String): TWDXModule; var tmp: Integer; begin tmp := Flist.IndexOf(upcase(AName)); if tmp < 0 then Exit(nil); Result := TWDXModule(Flist.Objects[tmp]) end; { TPluginWDX } function TPluginWDX.IsLoaded: Boolean; begin Result := FModuleHandle <> NilHandle; end; function TPluginWDX.GetAName: String; begin Result := FName; end; function TPluginWDX.GetAFileName: String; begin Result := FFileName; end; procedure TPluginWDX.SetAName(AValue: String); begin FName := AValue; end; procedure TPluginWDX.SetAFileName(AValue: String); begin FFileName := AValue; end; function TPluginWDX.LoadModule: Boolean; var AHandle: TLibHandle; begin EnterCriticalSection(FMutex); try if FModuleHandle <> NilHandle then Exit(True); AHandle := mbLoadLibrary(mbExpandFileName(Self.FileName)); Result := (AHandle <> NilHandle); if not Result then Exit; { Mandatory } ContentGetSupportedField := TContentGetSupportedField(GetProcAddress(AHandle, 'ContentGetSupportedField')); ContentGetValue := TContentGetValue(GetProcAddress(AHandle, 'ContentGetValue')); { Optional (must NOT be implemented if unsupported!) } ContentGetDetectString := TContentGetDetectString(GetProcAddress(AHandle, 'ContentGetDetectString')); ContentSetDefaultParams := TContentSetDefaultParams(GetProcAddress(AHandle, 'ContentSetDefaultParams')); ContentStopGetValue := TContentStopGetValue(GetProcAddress(AHandle, 'ContentStopGetValue')); ContentGetDefaultSortOrder := TContentGetDefaultSortOrder(GetProcAddress(AHandle, 'ContentGetDefaultSortOrder')); ContentPluginUnloading := TContentPluginUnloading(GetProcAddress(AHandle, 'ContentPluginUnloading')); ContentGetSupportedFieldFlags := TContentGetSupportedFieldFlags(GetProcAddress(AHandle, 'ContentGetSupportedFieldFlags')); ContentSetValue := TContentSetValue(GetProcAddress(AHandle, 'ContentSetValue')); ContentEditValue := TContentEditValue(GetProcAddress(AHandle, 'ContentEditValue')); ContentSendStateInformation := TContentSendStateInformation(GetProcAddress(AHandle, 'ContentSendStateInformation')); { Unicode } ContentGetValueW := TContentGetValueW(GetProcAddress(AHandle, 'ContentGetValueW')); ContentStopGetValueW := TContentStopGetValueW(GetProcAddress(AHandle, 'ContentStopGetValueW')); ContentSetValueW := TContentSetValueW(GetProcAddress(AHandle, 'ContentSetValueW')); ContentSendStateInformationW := TContentSendStateInformationW(GetProcAddress(AHandle, 'ContentSendStateInformationW')); CallContentSetDefaultParams; CallContentGetSupportedField; if Length(Self.DetectStr) = 0 then Self.DetectStr := CallContentGetDetectString; FModuleHandle := AHandle; finally LeaveCriticalSection(FMutex); end; end; procedure TPluginWDX.CallContentSetDefaultParams; var dps: tContentDefaultParamStruct; begin if assigned(ContentSetDefaultParams) then begin dps.DefaultIniName := mbFileNameToSysEnc(gpCfgDir + WdxIniFileName); dps.PluginInterfaceVersionHi := 1; dps.PluginInterfaceVersionLow := 50; dps.size := SizeOf(tContentDefaultParamStruct); ContentSetDefaultParams(@dps); end; end; procedure TPluginWDX.CallContentStopGetValue(FileName: String); begin if Assigned(ContentStopGetValueW) then ContentStopGetValueW(PWideChar(CeUtf8ToUtf16(FileName))) else if Assigned(ContentStopGetValue) then ContentStopGetValue(PAnsiChar(CeUtf8ToSys(FileName))); end; function TPluginWDX.CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; var x: Integer; begin if Assigned(ContentGetDefaultSortOrder) then begin x := ContentGetDefaultSortOrder(FieldIndex); case x of 1: Result := False; //a..z 1..9 -1: Result := True; //z..a 9..1 end; end; end; procedure TPluginWDX.UnloadModule; var AHandle: TLibHandle; begin EnterCriticalSection(FMutex); try if Assigned(ContentPluginUnloading) then ContentPluginUnloading; if FModuleHandle <> NilHandle then begin AHandle:= FModuleHandle; FModuleHandle := NilHandle; FreeLibrary(AHandle); end; { Mandatory } ContentGetSupportedField := nil; ContentGetValue := nil; { Optional (must NOT be implemented if unsupported!) } ContentGetDetectString := nil; ContentSetDefaultParams := nil; ContentStopGetValue := nil; ContentGetDefaultSortOrder := nil; ContentPluginUnloading := nil; ContentGetSupportedFieldFlags := nil; ContentSetValue := nil; ContentEditValue := nil; ContentSendStateInformation := nil; { Unicode } ContentGetValueW := nil; ContentStopGetValueW := nil; ContentSetValueW := nil; ContentSendStateInformationW := nil; finally LeaveCriticalSection(FMutex); end; end; procedure TPluginWDX.CallContentGetSupportedField; const MAX_LEN = 256; var sFieldName: String; Index, Rez: Integer; xFieldName, xUnits: array[0..Pred(MAX_LEN)] of AnsiChar; begin FFieldsList.Clear; if Assigned(ContentGetSupportedField) then begin Index := 0; xUnits[0] := #0; xFieldName[0] := #0; repeat Rez := ContentGetSupportedField(Index, xFieldName, xUnits, MAX_LEN); if Rez > ft_nomorefields then begin sFieldName := CeSysToUtf8(xFieldName); AddField(sFieldName, xUnits, Rez); end; Inc(Index); until (Rez <= ft_nomorefields); Translate; end; end; function TPluginWDX.CallContentGetDetectString: String; const MAX_LEN = 2048; // See contentplugin.hlp for details begin if not Assigned(ContentGetDetectString) then Result := EmptyStr else begin Result := StringOfChar(#0, MAX_LEN); ContentGetDetectString(PAnsiChar(Result), MAX_LEN); Result := Trim(PAnsiChar(Result)); end; end; function TPluginWDX.CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; var Rez: Integer; ATime: TDateTime; Buf: array[0..WDX_MAX_LEN] of Byte; fnval: Integer absolute buf; fnval64: Int64 absolute buf; ffval: Double absolute buf; fdate: TDateFormat absolute buf; ftime: TTimeFormat absolute buf; wtime: TWinFileTime absolute buf; begin EnterCriticalSection(FMutex); try if Assigned(ContentGetValueW) then Rez := ContentGetValueW(PWideChar(CeUtf8ToUtf16(FileName)), FieldIndex, UnitIndex, @Buf, SizeOf(buf), flags) else if Assigned(ContentGetValue) then Rez := ContentGetValue(PAnsiChar(mbFileNameToSysEnc(FileName)), FieldIndex, UnitIndex, @Buf, SizeOf(buf), flags); case Rez of ft_fieldempty: Result := Unassigned; ft_numeric_32: Result := fnval; ft_numeric_64: Result := fnval64; ft_numeric_floating: Result := ffval; ft_date: begin if TryEncodeDate(fdate.wYear, fdate.wMonth, fdate.wDay, ATime) then Result := ATime else Result := Unassigned; end; ft_time: begin if TryEncodeTime(ftime.wHour, ftime.wMinute, ftime.wSecond, 0, ATime) then Result := ATime else Result := Unassigned; end; ft_datetime: Result := WinFileTimeToDateTime(wtime); ft_boolean: Result := Boolean(fnval); ft_multiplechoice, ft_string, ft_fulltext: Result := CeSysToUtf8(AnsiString(PAnsiChar(@Buf[0]))); ft_stringw, ft_fulltextw: Result := UTF16ToUTF8(UnicodeString(PWideChar(@Buf[0]))); else Result := Unassigned; end; finally LeaveCriticalSection(FMutex); end; end; function TPluginWDX.CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; var Rez: Integer; Buf: array[0..WDX_MAX_LEN] of Byte; fnval: Integer absolute buf; fnval64: Int64 absolute buf; ffval: Double absolute buf; fdate: TDateFormat absolute buf; ftime: TTimeFormat absolute buf; wtime: TWinFileTime absolute buf; begin EnterCriticalSection(FMutex); try if Assigned(ContentGetValueW) then Rez := ContentGetValueW(PWideChar(CeUtf8ToUtf16(FileName)), FieldIndex, UnitIndex, @Buf, SizeOf(buf), flags) else if Assigned(ContentGetValue) then Rez := ContentGetValue(PAnsiChar(mbFileNameToSysEnc(FileName)), FieldIndex, UnitIndex, @Buf, SizeOf(buf), flags); case Rez of ft_fieldempty: Result := ''; ft_numeric_32: Result := IntToStr(fnval); ft_numeric_64: Result := IntToStr(fnval64); ft_numeric_floating: Result := FloatToStr(ffval); ft_date: Result := Format('%2.2d.%2.2d.%4.4d', [fdate.wDay, fdate.wMonth, fdate.wYear]); ft_time: Result := Format('%2.2d:%2.2d:%2.2d', [ftime.wHour, ftime.wMinute, ftime.wSecond]); ft_datetime: Result := DateTimeToStr(WinFileTimeToDateTime(wtime)); ft_boolean: Result := ifThen((fnval = 0), rsSimpleWordFalse, rsSimpleWordTrue); ft_multiplechoice, ft_string, ft_fulltext: Result := CeSysToUtf8(AnsiString(PAnsiChar(@Buf[0]))); ft_stringw, ft_fulltextw: Result := UTF16ToUTF8(UnicodeString(PWideChar(@Buf[0]))); //TODO: FT_DELAYED,ft_ondemand else Result := ''; end; finally LeaveCriticalSection(FMutex); end; end; function TPluginWDX.CallContentGetValue(FileName: String; FieldIndex: Integer; var UnitIndex: Integer): String; var Rez: Integer; ValueA: AnsiString; ValueW: UnicodeString; Buf: array[0..WDX_MAX_LEN] of Byte; begin EnterCriticalSection(FMutex); try if Assigned(ContentGetValueW) then Rez := ContentGetValueW(PWideChar(CeUtf8ToUtf16(FileName)), FieldIndex, UnitIndex, @Buf, SizeOf(buf), 0) else if Assigned(ContentGetValue) then Rez := ContentGetValue(PAnsiChar(mbFileNameToSysEnc(FileName)), FieldIndex, UnitIndex, @Buf, SizeOf(buf), 0); case Rez of ft_fieldempty: Result := EmptyStr; ft_fulltext: begin ValueA:= AnsiString(PAnsiChar(@Buf[0])); Inc(UnitIndex, Length(ValueA)); Result := CeSysToUtf8(ValueA); end; ft_fulltextw: begin ValueW:= UnicodeString(PWideChar(@Buf[0])); Inc(UnitIndex, Length(ValueW) * SizeOf(WideChar)); Result := UTF16ToUTF8(ValueW); end; else begin Result := EmptyStr; end; end; finally LeaveCriticalSection(FMutex); end; end; function TPluginWDX.CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; begin if assigned(ContentGetSupportedFieldFlags) then Result := ContentGetSupportedFieldFlags(FieldIndex); end; { TLuaWdx } function TLuaWdx.GetAName: String; begin Result := FName; end; function TLuaWdx.GetAFileName: String; begin Result := FFileName; end; procedure TLuaWdx.SetAName(AValue: String); begin FName := AValue; end; procedure TLuaWdx.SetAFileName(AValue: String); begin FFileName := AValue; end; function TLuaWdx.DoScript(AName: String): Integer; begin Result := LUA_ERRRUN; if not Assigned(L) then Exit; Result := luaL_dofile(L, PChar(AName)); if Result <> 0 then begin DCDebug('TLuaWdx.DoScript: ', lua_tostring(L, -1)); end; end; constructor TLuaWdx.Create; begin inherited Create; if not IsLuaLibLoaded then LoadLuaLib(mbExpandFileName(gLuaLib)); //Todo вынести загрузку либы в VmClass end; function TLuaWdx.LoadModule: Boolean; var sAbsolutePathFilename: string; begin EnterCriticalSection(FMutex); try Result := False; if (not IsLuaLibLoaded) or (L <> nil) then exit; L := lua_open; if not Assigned(L) then exit; luaL_openlibs(L); RegisterPackages(L); sAbsolutePathFilename := mbExpandFileName(FFilename); SetPackagePath(L, ExtractFilePath(sAbsolutePathFilename)); if DoScript(sAbsolutePathFilename) = 0 then Result := True else Result := False; CallContentSetDefaultParams; CallContentGetSupportedField; if Length(Self.DetectStr) = 0 then Self.DetectStr := CallContentGetDetectString; finally LeaveCriticalSection(FMutex); end; end; procedure TLuaWdx.UnloadModule; begin WdxLuaContentPluginUnloading; if Assigned(L) then begin lua_close(L); L := nil; end; end; function TLuaWdx.IsLoaded: Boolean; begin Result := IsLuaLibLoaded and Assigned(L); end; function TLuaWdx.WdxLuaContentGetSupportedField(Index: Integer; var xFieldName, xUnits: String): Integer; begin Result := ft_nomorefields; if not assigned(L) then exit; lua_getglobal(L, 'ContentGetSupportedField'); if not lua_isfunction(L, -1) then exit; lua_pushinteger(L, Index); LuaPCall(L, 1, 3); xFieldName := lua_tostring(L, -3); xUnits := lua_tostring(L, -2); Result := Integer(lua_tointeger(L, -1)); lua_pop(L, 3); end; procedure TLuaWdx.WdxLuaContentPluginUnloading; begin if not assigned(L) then exit; lua_getglobal(L, 'ContentPluginUnloading'); if not lua_isfunction(L, -1) then exit; LuaPCall(L, 0, 0); end; procedure TLuaWdx.CallContentGetSupportedField; var Index, Rez: Integer; xFieldName, xUnits: String; begin FFieldsList.Clear; Index := 0; repeat Rez := WdxLuaContentGetSupportedField(Index, xFieldName, xUnits); DCDebug('WDX:CallGetSupFields:' + IntToStr(Rez)); if Rez <> ft_nomorefields then begin AddField(xFieldName, xUnits, Rez); end; Inc(Index); until Rez = ft_nomorefields; Translate; end; procedure TLuaWdx.CallContentSetDefaultParams; begin if not assigned(L) then exit; lua_getglobal(L, 'ContentSetDefaultParams'); if not lua_isfunction(L, -1) then exit; lua_pushstring(L, PAnsiChar(gpCfgDir + WdxIniFileName)); lua_pushinteger(L, 1); lua_pushinteger(L, 50); LuaPCall(L, 3, 0); end; procedure TLuaWdx.CallContentStopGetValue(FileName: String); begin if not assigned(L) then exit; lua_getglobal(L, 'ContentStopGetValue'); if not lua_isfunction(L, -1) then exit; lua_pushstring(L, PAnsiChar(FileName)); LuaPCall(L, 1, 0); end; function TLuaWdx.CallContentGetDefaultSortOrder(FieldIndex: Integer): Boolean; var x: Integer; begin Result := False; if not assigned(L) then exit; lua_getglobal(L, 'ContentGetDefaultSortOrder'); if not lua_isfunction(L, -1) then exit; lua_pushinteger(L, FieldIndex); LuaPCall(L, 1, 1); x := lua_tointeger(L, -1); case x of 1: Result := False; //a..z 1..9 -1: Result := True; //z..a 9..1 end; lua_pop(L, 1); end; function TLuaWdx.CallContentGetDetectString: String; begin Result := ''; if not assigned(L) then exit; lua_getglobal(L, 'ContentGetDetectString'); if not lua_isfunction(L, -1) then exit; LuaPCall(L, 0, 1); Result := lua_tostring(L, -1); lua_pop(L, 1); end; function TLuaWdx.CallContentGetValueV(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): Variant; begin EnterCriticalSection(FMutex); try Result := Unassigned; if not Assigned(L) then Exit; lua_getglobal(L, 'ContentGetValue'); if not lua_isfunction(L, -1) then Exit; lua_pushstring(L, PAnsiChar(FileName)); lua_pushinteger(L, FieldIndex); lua_pushinteger(L, UnitIndex); lua_pushinteger(L, flags); LuaPCall(L, 4, 1); if not lua_isnil(L, -1) then begin case TWdxField(FieldList.Objects[FieldIndex]).FType of ft_string, ft_fulltext, ft_multiplechoice: Result := lua_tostring(L, -1); ft_numeric_32: Result := Int32(lua_tointeger(L, -1)); ft_numeric_64: Result := Int64(lua_tointeger(L, -1)); ft_boolean: Result := lua_toboolean(L, -1); ft_numeric_floating: Result := lua_tonumber(L, -1); ft_datetime: Result := WinFileTimeToDateTime(TWinFileTime(lua_tointeger(L, -1))); end; end; lua_pop(L, 1); finally LeaveCriticalSection(FMutex); end; end; function TLuaWdx.CallContentGetValue(FileName: String; FieldIndex, UnitIndex: Integer; flags: Integer): String; begin EnterCriticalSection(FMutex); try Result := ''; if not Assigned(L) then Exit; lua_getglobal(L, 'ContentGetValue'); if not lua_isfunction(L, -1) then Exit; lua_pushstring(L, PAnsiChar(FileName)); lua_pushinteger(L, FieldIndex); lua_pushinteger(L, UnitIndex); lua_pushinteger(L, flags); LuaPCall(L, 4, 1); if not lua_isnil(L, -1) then begin case TWdxField(FieldList.Objects[FieldIndex]).FType of ft_string, ft_fulltext, ft_multiplechoice: Result := lua_tostring(L, -1); ft_numeric_32: Result := IntToStr(Int32(lua_tointeger(L, -1))); ft_numeric_64: Result := IntToStr(Int64(lua_tointeger(L, -1))); ft_numeric_floating: Result := FloatToStr(lua_tonumber(L, -1)); ft_boolean: Result := IfThen(lua_toboolean(L, -1), rsSimpleWordTrue, rsSimpleWordFalse); ft_datetime: Result := DateTimeToStr(WinFileTimeToDateTime(TWinFileTime(lua_tointeger(L, -1)))); end; end; lua_pop(L, 1); finally LeaveCriticalSection(FMutex); end; end; function TLuaWdx.CallContentGetValue(FileName: String; FieldIndex: Integer; var UnitIndex: Integer): String; begin EnterCriticalSection(FMutex); try Result := EmptyStr; if not Assigned(L) then Exit; lua_getglobal(L, 'ContentGetValue'); if not lua_isfunction(L, -1) then Exit; lua_pushstring(L, PAnsiChar(FileName)); lua_pushinteger(L, FieldIndex); lua_pushinteger(L, UnitIndex); lua_pushinteger(L, 0); LuaPCall(L, 4, 1); if not lua_isnil(L, -1) then begin Result := lua_tostring(L, -1); Inc(UnitIndex, Length(Result)); end; lua_pop(L, 1); finally LeaveCriticalSection(FMutex); end; end; function TLuaWdx.CallContentGetSupportedFieldFlags(FieldIndex: Integer): Integer; begin Result := 0; if not assigned(L) then exit; lua_getglobal(L, 'ContentGetSupportedFieldFlags'); if not lua_isfunction(L, -1) then exit; lua_pushinteger(L, FieldIndex); LuaPCall(L, 1, 1); Result := lua_tointeger(L, -1); lua_pop(L, 1); end; { TEmbeddedWDX } function TEmbeddedWDX.GetAName: String; begin Result:= EmptyStr; end; function TEmbeddedWDX.GetAFileName: String; begin Result:= ParamStrUTF8(0); end; procedure TEmbeddedWDX.SetAName(AValue: String); begin end; procedure TEmbeddedWDX.SetAFileName(AValue: String); begin end; procedure TEmbeddedWDX.AddField(const AName, XName: String; AType: Integer); var I: Integer; begin I := FFieldsList.AddObject(AName, TWdxField.Create); with TWdxField(FFieldsList.Objects[I]) do begin FName := AName; LName := XName; FType := AType; end; end; constructor TEmbeddedWDX.Create; begin inherited Create; CallContentGetSupportedField; end; function TEmbeddedWDX.LoadModule: Boolean; begin Result:= True; end; procedure TEmbeddedWDX.UnloadModule; begin end; function TEmbeddedWDX.IsLoaded: Boolean; begin Result:= True; end; function TEmbeddedWDX.GetFieldIndex(FieldName: String): Integer; var Index: Integer; begin Result:= inherited GetFieldIndex(FieldName); if Result < 0 then begin for Index:= 0 to FFieldsList.Count - 1 do begin if AnsiSameText(FieldName, TWdxField(FFieldsList.Objects[Index]).LName) then Exit(Index); end; end; end; { TWDXModule } procedure TWDXModule.Translate; var I: Integer; SUnits: String; Ini: TIniFileEx; UserLang: String; AFileName: String; AUnits: TStringArray; begin AFileName:= mbExpandFileName(ChangeFileExt(Self.FileName, '.lng')); if mbFileExists(AFileName) then begin UserLang:= GetWdxLang(ExtractDelimited(2, gpoFileName, ['.'])); if Length(UserLang) > 0 then try Ini:= TIniFileEx.Create(AFileName, fmOpenRead); try for I:= 0 to FFieldsList.Count - 1 do begin with TWdxField(FFieldsList.Objects[I]) do begin LName:= CeRawToUtf8(Ini.ReadString(UserLang, FName, FName)); if Length(OUnits) > 0 then begin SUnits:= CeRawToUtf8(Ini.ReadString(UserLang, OUnits, OUnits)); AUnits:= SplitString(sUnits, '|'); // Check that translation is valid if Length(AUnits) = Length(FUnits) then LUnits:= CopyArray(AUnits); end; end; end; finally Ini.Free; end; except // Skip end; end; end; function TWDXModule.GetADetectStr: String; begin Result:= FParser.DetectStr; end; procedure TWDXModule.SetADetectStr(const AValue: String); begin FParser.DetectStr:= AValue; end; procedure TWDXModule.AddField(const AName, AUnits: String; AType: Integer); var WdxField: TWdxField; begin WdxField:= TWdxField.Create; FFieldsList.AddObject(AName, WdxField); with WdxField do begin FName := AName; LName := FName; OUnits := AUnits; FUnits := SplitString(OUnits, '|'); LUnits := CopyArray(FUnits); FType := AType; end; end; constructor TWDXModule.Create; begin InitCriticalSection(FMutex); FParser:= TParserControl.Create; FFieldsList:= TStringList.Create; FFieldsList.OwnsObjects:= True; end; destructor TWDXModule.Destroy; begin FParser.Free; FFieldsList.Free; Self.UnloadModule; inherited Destroy; DoneCriticalSection(FMutex); end; function TWDXModule.FieldList: TStringList; begin Result:= FFieldsList; end; function TWDXModule.WdxFieldType(n: Integer): String; begin case n of FT_NUMERIC_32: Result := 'FT_NUMERIC_32'; FT_NUMERIC_64: Result := 'FT_NUMERIC_64'; FT_NUMERIC_FLOATING: Result := 'FT_NUMERIC_FLOATING'; FT_DATE: Result := 'FT_DATE'; FT_TIME: Result := 'FT_TIME'; FT_DATETIME: Result := 'FT_DATETIME'; FT_BOOLEAN: Result := 'FT_BOOLEAN'; FT_MULTIPLECHOICE: Result := 'FT_MULTIPLECHOICE'; FT_STRING: Result := 'FT_STRING'; FT_FULLTEXT: Result := 'FT_FULLTEXT'; FT_NOSUCHFIELD: Result := 'FT_NOSUCHFIELD'; FT_FILEERROR: Result := 'FT_FILEERROR'; FT_FIELDEMPTY: Result := 'FT_FIELDEMPTY'; FT_DELAYED: Result := 'FT_DELAYED'; else Result := '?'; end; end; function TWDXModule.GetFieldIndex(FieldName: String): Integer; begin Result := FFieldsList.IndexOf(FieldName); end; function TWDXModule.FileParamVSDetectStr(const aFile: TFile): Boolean; begin EnterCriticalSection(FMutex); try Result := FParser.TestFileResult(aFile); finally LeaveCriticalsection(FMutex); end; end; function TWDXModule.CallContentGetValueV(FileName: String; FieldName: String; UnitName: String; flags: Integer): Variant; var FieldIndex, UnitIndex: Integer; begin FieldIndex := GetFieldIndex(FieldName); if FieldIndex <> -1 then begin UnitIndex := TWdxField(FieldList.Objects[FieldIndex]).GetUnitIndex(UnitName); Result := CallContentGetValueV(FileName, FieldIndex, UnitIndex, flags); end else Result := Unassigned; end; function TWDXModule.CallContentGetValue(FileName: String; FieldName: String; UnitName: String; flags: Integer): String; var FieldIndex, UnitIndex: Integer; begin FieldIndex := GetFieldIndex(FieldName); if FieldIndex <> -1 then begin UnitIndex := TWdxField(FieldList.Objects[FieldIndex]).GetUnitIndex(UnitName); Result := CallContentGetValue(FileName, FieldIndex, UnitIndex, flags); end else Result := EmptyStr; end; { TWdxField } function TWdxField.GetUnitIndex(UnitName: String): Integer; var Index: Integer; begin for Index:= 0 to High(FUnits) do begin if SameText(UnitName, FUnits[Index]) then Exit(Index); end; Result := IfThen(FType = FT_MULTIPLECHOICE, -1, 0); end; end. doublecmd-1.1.22/src/uwdxprototypes.pas0000644000175000001440000000400714743153644017243 0ustar alexxusersunit uwdxprototypes; {$mode objfpc}{$H+} interface uses Classes, SysUtils, WdxPlugin; {$IFDEF MSWINDOWS}{$CALLING STDCALL}{$ELSE}{$CALLING CDECL}{$ENDIF} type { Mandatory (must be implemented) } TContentGetSupportedField = function (FieldIndex:integer;FieldName:pchar; Units:pchar;maxlen:integer):integer; TContentGetValue = function (FileName:pchar;FieldIndex,UnitIndex:integer; FieldValue:pbyte; maxlen,flags:integer):integer; { Optional (must NOT be implemented if unsupported!) } TContentGetDetectString = procedure (DetectString:pchar;maxlen:integer); TContentSetDefaultParams = procedure (dps:pContentDefaultParamStruct); TContentStopGetValue = procedure (FileName:pchar); TContentGetDefaultSortOrder = function (FieldIndex:integer):integer; TContentPluginUnloading = procedure; TContentGetSupportedFieldFlags = function (FieldIndex:integer):integer; TContentSetValue = function (FileName:pchar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; TContentEditValue = function (handle:thandle;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pchar;maxlen:integer;flags:integer; langidentifier:pchar):integer; TContentSendStateInformation = procedure (state:integer;path:pchar); { Unicode } TContentGetValueW = function (FileName:pwidechar;FieldIndex,UnitIndex:integer; FieldValue:pbyte; maxlen,flags:integer):integer; TContentStopGetValueW = procedure (FileName:pwidechar); TContentSetValueW = function (FileName:pwidechar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; TContentSendStateInformationW = procedure (state:integer;path:pwidechar); {$CALLING DEFAULT} implementation end. doublecmd-1.1.22/src/uwfxmodule.pas0000644000175000001440000010153614743153644016307 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- Virtual File System - class for manage WFX plugins (Version 1.3) Copyright (C) 2007-2018 Alexander Koblov (alexx2000@mail.ru) Callback functions based on: Total Commander filesystem plugins debugger Author: Pavel Dubrovsky 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, see . } unit uWFXmodule; {$mode objfpc}{$H+} interface uses SysUtils, Classes, WfxPlugin, uWFXprototypes, dynlibs, DCClassesUtf8, Extension, DCBasicTypes, DCXmlConfig, uWdxPrototypes, uWdxModule, uFileSource; const WFX_SUCCESS = 0; WFX_NOTSUPPORTED = -10; WFX_ERROR = -20; type { TWfxFindData } TWfxFindData = record FileAttributes : TFileAttrs; CreationTime, LastAccessTime, LastWriteTime : TDateTime; FileSize : Int64; Reserved0, Reserved1 : LongWord; FileName : String; AlternateFileName : String; case Boolean of True: ( FindDataA: TWin32FindData; ); False: ( FindDataW: TWin32FindDataW; ); end; { TWFXModule } TWFXModule = class(TPluginWDX) private FBackgroundFlags: Integer; public { Mandatory } FsInit : TFsInit; FsFindFirst : TFsFindFirst; FsFindNext : TFsFindNext; FsFindClose : TFsFindClose; { Optional } FsSetCryptCallback: TFsSetCryptCallback; FsGetDefRootName : TFsGetDefRootName; FsGetFile : TFsGetFile; FsPutFile : TFsPutFile; FsDeleteFile : TFsDeleteFile; FsRemoveDir : TFsRemoveDir; FsExecuteFile : TFsExecuteFile; FsMkDir : TFsMkDir; FsStatusInfo : TFsStatusInfo; FsSetDefaultParams : TFsSetDefaultParams; //--------------------- FsSetAttr:TFsSetAttr; FsSetTime:TFsSetTime; FsExtractCustomIcon:TFsExtractCustomIcon; FsRenMovFile:TFsRenMovFile; FsDisconnect:TFsDisconnect; FsGetPreviewBitmap:TFsGetPreviewBitmap; FsLinksToLocalFiles:TFsLinksToLocalFiles; FsGetLocalName:TFsGetLocalName; //--------------------- FsGetBackgroundFlags: TFsGetBackgroundFlags; //--------------------- FsContentGetDefaultView:TFsContentGetDefaultView; { Unicode } FsInitW: TFsInitW; FsFindFirstW: TFsFindFirstW; FsFindNextW: TFsFindNextW; //--------------------- FsSetCryptCallbackW: TFsSetCryptCallbackW; FsMkDirW: TFsMkDirW; FsExecuteFileW: TFsExecuteFileW; FsRenMovFileW: TFsRenMovFileW; FsGetFileW: TFsGetFileW; FsPutFileW: TFsPutFileW; FsDeleteFileW: TFsDeleteFileW; FsRemoveDirW: TFsRemoveDirW; FsDisconnectW: TFsDisconnectW; FsSetAttrW: TFsSetAttrW; FsSetTimeW: TFsSetTimeW; FsStatusInfoW: TFsStatusInfoW; FsExtractCustomIconW: TFsExtractCustomIconW; FsGetPreviewBitmapW: TFsGetPreviewBitmapW; FsGetLocalNameW: TFsGetLocalNameW; //----------------------- FsContentGetDefaultViewW: TFsContentGetDefaultViewW; { Extension API } ExtensionInitialize: TExtensionInitializeProc; ExtensionFinalize: TExtensionFinalizeProc; public function WfxFindFirst(Path: String; var FindData: TWfxFindData): THandle; function WfxFindNext(Hdl: THandle; var FindData: TWfxFindData): Boolean; procedure WfxStatusInfo(RemoteDir: String; InfoStartEnd, InfoOperation: Integer); function WfxExecuteFile(MainWin: HWND; var RemoteName: String; Verb: String): Integer; function WfxRenMovFile(OldName, NewName: String; Move, OverWrite: Boolean; RemoteInfo: PRemoteInfo): Integer; function WfxGetFile(RemoteName, LocalName: String; CopyFlags: Integer; RemoteInfo: PRemoteInfo): Integer; function WfxPutFile(LocalName, RemoteName: String; CopyFlags: Integer): Integer; function WfxSetAttr(RemoteName: String; NewAttr: LongInt): Boolean; {en Each of CreationTime, LastAccessTime, LastWriteTime may be @nil to leave the value unchanged. } function WfxSetTime(RemoteName: String; pCreationTime, pLastAccessTime, pLastWriteTime: PWfxFileTime): Boolean; function WfxMkDir(const sBasePath, sDirName: String): LongInt; function WfxRemoveDir(const sDirName: String): Boolean; function WfxDeleteFile(const sFileName: String): Boolean; function WfxGetLocalName(var sFileName: String): Boolean; function WfxDisconnect(const DisconnectRoot: String): Boolean; function WfxContentGetDefaultView(out DefaultView: TFileSourceFields): Boolean; private function LoadModule(const sName: String):Boolean; overload; {Load plugin} procedure UnloadModule; override; public constructor Create; override; destructor Destroy; override; procedure VFSInit; function VFSConfigure(Parent: HWND):Boolean; function VFSRootName: String; function ContentPlugin: Boolean; property BackgroundFlags: Integer read FBackgroundFlags write FBackgroundFlags; end; { TWFXModuleList } TWFXModuleList = class(TStringList) private FModuleList: TStringListEx; private function GetAEnabled(Index: Integer): Boolean; function GetAFileName(Index: Integer): String; function GetAName(Index: Integer): String; procedure SetAEnabled(Index: Integer; const AValue: Boolean); procedure SetAFileName(Index: Integer; const AValue: String); procedure SetAName(Index: Integer; const AValue: String); public constructor Create; reintroduce; destructor Destroy; override; public procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload; function ComputeSignature(seed: dword): dword; function Add(Ext: String; FileName: String): Integer; reintroduce; function FindFirstEnabledByName(Name: String): Integer; function LoadModule(const FileName: String): TWfxModule; property Name[Index: Integer]: String read GetAName write SetAName; property FileName[Index: Integer]: String read GetAFileName write SetAFileName; property Enabled[Index: Integer]: Boolean read GetAEnabled write SetAEnabled; end; function GetErrorMsg(iErrorMsg: LongInt): String; implementation uses //Lazarus, Free-Pascal, etc. LazUTF8, FileUtil, //DC uDCUtils, uLng, uGlobsPaths, uOSUtils, uWfxPluginUtil, fDialogBox, DCOSUtils, DCStrUtils, DCConvertEncoding, uComponentsSignature, uOSForms, uExtension; const WfxIniFileName = 'wfx.ini'; function GetErrorMsg(iErrorMsg: LongInt): String; begin case iErrorMsg of WFX_ERROR: Result:= 'Unknown error!'; WFX_NOTSUPPORTED, FS_FILE_NOTSUPPORTED: Result:= rsMsgErrNotSupported; FS_FILE_NOTFOUND: Result:= 'File not found!'; FS_FILE_READERROR: Result:= rsMsgErrERead; FS_FILE_WRITEERROR: Result:= rsMsgErrEWrite; FS_FILE_USERABORT: Result:= rsMsgErrEAborted; end; end; function ConvertString(const S: String): TStringArray; var Item: String = ''; Index: Integer = 1; begin Result:= Default(TStringArray); while Index < High(S) do begin if S[Index] = '\' then begin case S[Index + 1] of '\': begin Item += '\'; Inc(Index, 2); Continue; end; 'n': begin AddString(Result, Item); Item:= EmptyStr; Inc(Index, 2); Continue; end; end; end; Item += S[Index]; Inc(Index); end; if Length(Item) > 0 then begin AddString(Result, Item + S[High(S)]); end; end; function ConvertFunction(const S: String): String; var AValues: TStringArray; Plugin, Field, Arg: String; begin Result:= EmptyStr; if Length(S) < 3 then Exit; if not StrBegins(S, '[=') then Exit(S); if (S[Low(S)] = '[') and (S[High(S)] = ']') then begin AValues:= (Copy(S, 2, Length(S) - 2)).Split(['.']); if (Length(AValues) > 1) then begin Plugin:= LowerCase(AValues[0]); if (Plugin = '=') then Result:= 'Plugin(FS)' else if (Plugin = '=tc') then begin Result:= 'DC()'; Field:= LowerCase(AValues[1]); if (Field = 'writedate') then AValues[1]:= 'GETFILETIME' else if (Field = 'attributestr') then AValues[1]:= 'GETFILEATTR' else if (Field = 'writetime') then begin AValues[1]:= 'GETFILETIME'; if (Length(AValues) = 2) then begin AddString(AValues, DefaultFormatSettings.LongTimeFormat); end; end else if (Field = 'size') then begin AValues[1]:= 'GETFILESIZE'; if (Length(AValues) = 3) then begin Arg:= LowerCase(AValues[2]); if (Arg = 'bytes') then AValues[2]:= 'BYTE' else if (Arg = 'kbytes') then AValues[2]:= 'KILO' else if (Arg = 'mbytes') then AValues[2]:= 'MEGA' else if (Arg = 'gbytes') then AValues[2]:= 'GIGA' else AValues[2]:= 'FLOAT'; end; end; end; if (Length(AValues) = 2) then Result+= '.' + AValues[1] + '{}' else begin Result+= '.' + AValues[1] + '{' + AValues[2] + '}'; end; Result:= '[' + Result + ']'; end; end; end; { TWfxFindData } procedure ConvertFindData(var FindData: TWfxFindData; AnsiData: Boolean); begin with FindData do begin // Convert file attributes FileAttributes:= FindDataW.dwFileAttributes; CreationTime:= WfxFileTimeToDateTime(FindDataW.ftCreationTime); LastAccessTime:= WfxFileTimeToDateTime(FindDataW.ftLastAccessTime); LastWriteTime:= WfxFileTimeToDateTime(FindDataW.ftLastWriteTime); Int64Rec(FileSize).Lo:= FindDataW.nFileSizeLow; Int64Rec(FileSize).Hi:= FindDataW.nFileSizeHigh; Reserved0:= FindDataW.dwReserved0; Reserved1:= FindDataW.dwReserved1; // Convert file name if AnsiData then begin FileName:= CeSysToUtf8(FindDataA.cFileName); AlternateFileName:= CeSysToUtf8(FindDataA.cAlternateFileName); end else begin FileName:= UTF16ToUTF8(UnicodeString(FindDataW.cFileName)); AlternateFileName:= UTF16ToUTF8(UnicodeString(FindDataW.cAlternateFileName)); end; end; end; { TWFXModule } function TWFXModule.WfxFindFirst(Path: String; var FindData: TWfxFindData): THandle; begin try if Assigned(FsFindFirstW) then begin Result:= FsFindFirstW(PWideChar(CeUtf8ToUtf16(Path)), FindData.FindDataW); if Result <> wfxInvalidHandle then ConvertFindData(FindData, False); end else if Assigned(FsFindFirst) then begin Result:= FsFindFirst(PAnsiChar(CeUtf8ToSys(Path)), FindData.FindDataA); if Result <> wfxInvalidHandle then ConvertFindData(FindData, True); end; except on E: Exception do begin Result:= wfxInvalidHandle; end; end; end; function TWFXModule.WfxFindNext(Hdl: THandle; var FindData: TWfxFindData): Boolean; begin if Assigned(FsFindFirstW) then begin Result:= FsFindNextW(Hdl, FindData.FindDataW); if Result then ConvertFindData(FindData, False); end else if Assigned(FsFindFirst) then begin Result:= FsFindNext(Hdl, FindData.FindDataA); if Result then ConvertFindData(FindData, True); end else Result:= False; end; procedure TWFXModule.WfxStatusInfo(RemoteDir: String; InfoStartEnd, InfoOperation: Integer); begin if Assigned(FsStatusInfoW) then FsStatusInfoW(PWideChar(CeUtf8ToUtf16(RemoteDir)), InfoStartEnd, InfoOperation) else if Assigned(FsStatusInfo) then FsStatusInfo(PAnsiChar(CeUtf8ToSys(RemoteDir)), InfoStartEnd, InfoOperation); end; function TWFXModule.WfxExecuteFile(MainWin: HWND; var RemoteName: String; Verb: String): Integer; var pacRemoteName: PAnsiChar; pwcRemoteName: PWideChar; begin Result:= WFX_NOTSUPPORTED; MainWin:= GetWindowHandle(MainWin); if Assigned(FsExecuteFileW) then begin pwcRemoteName:= GetMem(MAX_PATH * SizeOf(WideChar)); StrPCopyW(pwcRemoteName, CeUtf8ToUtf16(RemoteName)); Result:= FsExecuteFileW(MainWin, pwcRemoteName, PWideChar(CeUtf8ToUtf16(Verb))); if Result = FS_EXEC_SYMLINK then RemoteName:= UTF16ToUTF8(UnicodeString(pwcRemoteName)); FreeMem(pwcRemoteName); end else if Assigned(FsExecuteFile) then begin pacRemoteName:= GetMem(MAX_PATH); StrPCopy(pacRemoteName, CeUtf8ToSys(RemoteName)); Result:= FsExecuteFile(MainWin, pacRemoteName, PAnsiChar(CeUtf8ToSys(Verb))); if Result = FS_EXEC_SYMLINK then RemoteName:= CeSysToUtf8(StrPas(pacRemoteName)); FreeMem(pacRemoteName); end; end; function TWFXModule.WfxRenMovFile(OldName, NewName: String; Move, OverWrite: Boolean; RemoteInfo: PRemoteInfo): Integer; begin Result:= FS_FILE_NOTSUPPORTED; if Assigned(FsRenMovFileW) then Result:= FsRenMovFileW(PWideChar(CeUtf8ToUtf16(OldName)), PWideChar(CeUtf8ToUtf16(NewName)), Move, OverWrite, RemoteInfo) else if Assigned(FsRenMovFile) then Result:= FsRenMovFile(PAnsiChar(CeUtf8ToSys(OldName)), PAnsiChar(CeUtf8ToSys(NewName)), Move, OverWrite, RemoteInfo); end; function TWFXModule.WfxGetFile(RemoteName, LocalName: String; CopyFlags: Integer; RemoteInfo: PRemoteInfo): Integer; begin Result:= FS_FILE_NOTSUPPORTED; if Assigned(FsGetFileW) then Result:= FsGetFileW(PWideChar(CeUtf8ToUtf16(RemoteName)), PWideChar(CeUtf8ToUtf16(LocalName)), CopyFlags, RemoteInfo) else if Assigned(FsGetFile) then Result:= FsGetFile(PAnsiChar(CeUtf8ToSys(RemoteName)), PAnsiChar(CeUtf8ToSys(LocalName)), CopyFlags, RemoteInfo); end; function TWFXModule.WfxPutFile(LocalName, RemoteName: String; CopyFlags: Integer): Integer; begin Result:= FS_FILE_NOTSUPPORTED; if Assigned(FsPutFileW) then Result:= FsPutFileW(PWideChar(CeUtf8ToUtf16(LocalName)), PWideChar(CeUtf8ToUtf16(RemoteName)), CopyFlags) else if Assigned(FsPutFile) then Result:= FsPutFile(PAnsiChar(CeUtf8ToSys(LocalName)), PAnsiChar(CeUtf8ToSys(RemoteName)), CopyFlags); end; function TWFXModule.WfxSetAttr(RemoteName: String; NewAttr: LongInt): Boolean; begin Result:= False; if Assigned(FsSetAttrW) then Result:= FsSetAttrW(PWideChar(CeUtf8ToUtf16(RemoteName)), NewAttr) else if Assigned(FsSetAttr) then Result:= FsSetAttr(PAnsiChar(CeUtf8ToSys(RemoteName)), NewAttr); end; function TWFXModule.WfxSetTime(RemoteName: String; pCreationTime, pLastAccessTime, pLastWriteTime: PWfxFileTime): Boolean; begin Result:= False; if Assigned(FsSetTimeW) then Result:= FsSetTimeW(PWideChar(CeUtf8ToUtf16(RemoteName)), pCreationTime, pLastAccessTime, pLastWriteTime) else if Assigned(FsSetTime) then Result:= FsSetTime(PAnsiChar(CeUtf8ToSys(RemoteName)), pCreationTime, pLastAccessTime, pLastWriteTime); end; function TWFXModule.WfxMkDir(const sBasePath, sDirName: String): LongInt; begin Result:= WFX_NOTSUPPORTED; if Assigned(FsMkDirW) then begin WfxStatusInfo(sBasePath, FS_STATUS_START, FS_STATUS_OP_MKDIR); if FsMkDirW(PWideChar(CeUtf8ToUtf16(sDirName))) then Result:= WFX_SUCCESS else Result:= WFX_ERROR; WfxStatusInfo(sBasePath, FS_STATUS_END, FS_STATUS_OP_MKDIR); end else if Assigned(FsMkDir) then begin WfxStatusInfo(sBasePath, FS_STATUS_START, FS_STATUS_OP_MKDIR); if FsMkDir(PAnsiChar(CeUtf8ToSys(sDirName))) then Result:= WFX_SUCCESS else Result:= WFX_ERROR; WfxStatusInfo(sBasePath, FS_STATUS_END, FS_STATUS_OP_MKDIR); end; end; function TWFXModule.WfxRemoveDir(const sDirName: String): Boolean; begin Result:= False; if Assigned(FsRemoveDirW) then Result:= FsRemoveDirW(PWideChar(CeUtf8ToUtf16(sDirName))) else if Assigned(FsRemoveDir) then Result:= FsRemoveDir(PAnsiChar(CeUtf8ToSys(sDirName))); end; function TWFXModule.WfxDeleteFile(const sFileName: String): Boolean; begin Result:= False; if Assigned(FsDeleteFileW) then Result:= FsDeleteFileW(PWideChar(CeUtf8ToUtf16(sFileName))) else if Assigned(FsDeleteFile) then Result:= FsDeleteFile(PAnsiChar(CeUtf8ToSys(sFileName))); end; function TWFXModule.WfxGetLocalName(var sFileName: String): Boolean; var pacRemoteName: PAnsiChar; pwcRemoteName: PWideChar; begin Result:= False; if Assigned(FsGetLocalNameW) then begin pwcRemoteName:= GetMem(MAX_PATH * SizeOf(WideChar)); StrPCopyW(pwcRemoteName, CeUtf8ToUtf16(sFileName)); Result:= FsGetLocalNameW(pwcRemoteName, MAX_PATH); if Result = True then sFileName:= UTF16ToUTF8(UnicodeString(pwcRemoteName)); FreeMem(pwcRemoteName); end else if Assigned(FsGetLocalName) then begin pacRemoteName:= GetMem(MAX_PATH); StrPCopy(pacRemoteName, CeUtf8ToSys(sFileName)); Result:= FsGetLocalName(pacRemoteName, MAX_PATH); if Result = True then sFileName:= CeSysToUtf8(StrPas(pacRemoteName)); FreeMem(pacRemoteName); end; end; function TWFXModule.WfxDisconnect(const DisconnectRoot: String): Boolean; begin if Assigned(FsDisconnectW) then Result:= FsDisconnectW(PWideChar(CeUtf8ToUtf16(DisconnectRoot))) else if Assigned(FsDisconnect) then Result:= FsDisconnect(PAnsiChar(CeUtf8ToSys(DisconnectRoot))) else Result:= False; end; function TWFXModule.WfxContentGetDefaultView(out DefaultView: TFileSourceFields): Boolean; const MAX_LEN = 4096; var Index: Integer; ViewContents, ViewHeaders, ViewWidths, ViewOptions: TStringArray; usContents, usHeaders, usWidths, usOptions: String; asContents, asHeaders, asWidths, asOptions: array[0..MAX_LEN] of AnsiChar; wsContents, wsHeaders, wsWidths, wsOptions: array[0..MAX_LEN] of WideChar; begin Result:= False; DefaultView:= Default(TFileSourceFields); if Assigned(FsContentGetDefaultViewW) then begin Result:= FsContentGetDefaultViewW(wsContents, wsHeaders, wsWidths, wsOptions, MAX_LEN); if Result then begin usContents:= CeUtf16ToUtf8(wsContents); usHeaders:= CeUtf16ToUtf8(wsHeaders); usWidths:= CeUtf16ToUtf8(wsWidths); usOptions:= CeUtf16ToUtf8(wsOptions); end; end else if Assigned(FsContentGetDefaultView) then begin Result:= FsContentGetDefaultView(asContents, asHeaders, asWidths, asOptions, MAX_LEN); if Result then begin usContents:= CeSysToUtf8(asContents); usHeaders:= CeSysToUtf8(asHeaders); usWidths:= CeSysToUtf8(asWidths); usOptions:= CeSysToUtf8(asOptions); end; end; if Result then begin ViewHeaders:= ConvertString(usHeaders); ViewWidths:= SplitString(usWidths, ','); ViewOptions:= SplitString(usOptions,'|'); ViewContents:= ConvertString(usContents); SetLength(DefaultView, Length(ViewWidths)); for Index:= Low(DefaultView) to High(DefaultView) do begin if (Index = 0) then begin DefaultView[Index].Header:= rsColName; DefaultView[Index].Content:= '[DC().GETFILENAMENOEXT{}]'; end else if (Index = 1) then begin DefaultView[Index].Header:= rsColExt; DefaultView[Index].Content:= '[DC().GETFILEEXT{}]'; end else begin DefaultView[Index].Header:= ViewHeaders[Index - 2]; DefaultView[Index].Content:= ConvertFunction(ViewContents[Index - 2]); end; DefaultView[Index].Width:= StrToInt(ViewWidths[Index]); if (DefaultView[Index].Width < 0) then begin DefaultView[Index].Align:= taRightJustify; DefaultView[Index].Width:= Abs(DefaultView[Index].Width); end else begin DefaultView[Index].Align:= taLeftJustify; end; end; end; end; constructor TWFXModule.Create; begin inherited; FName:= 'FS'; end; destructor TWFXModule.Destroy; begin if IsLoaded then begin if Assigned(ContentPluginUnloading) then ContentPluginUnloading; if Assigned(ExtensionFinalize) then ExtensionFinalize(nil); end; inherited Destroy; end; function TWFXModule.LoadModule(const sName: String): Boolean; var AHandle: TLibHandle; begin EnterCriticalSection(FMutex); try if FModuleHandle <> NilHandle then Exit(True); FModulePath:= mbExpandFileName(sName); AHandle := mbLoadLibrary(FModulePath); Result := AHandle <> NilHandle; if not Result then Exit; { Mandatory } FsInit := TFsInit(GetProcAddress(AHandle,'FsInit')); FsFindFirst := TFsFindFirst(GetProcAddress(AHandle,'FsFindFirst')); FsFindNext := TFsFindNext(GetProcAddress(AHandle,'FsFindNext')); FsFindClose := TFsFindClose(GetProcAddress(AHandle,'FsFindClose')); { Unicode } FsInitW := TFsInitW(GetProcAddress(AHandle,'FsInitW')); FsFindFirstW := TFsFindFirstW(GetProcAddress(AHandle,'FsFindFirstW')); FsFindNextW := TFsFindNextW(GetProcAddress(AHandle,'FsFindNextW')); Result:= (FsInit <> nil) and (FsFindFirst <> nil) and (FsFindNext <> nil); if (Result = False) then begin FsInit:= nil; FsFindFirst:= nil; FsFindNext:= nil; Result:= (FsInitW <> nil) and (FsFindFirstW <> nil) and (FsFindNextW <> nil); end; if (Result = False) or (FsFindClose = nil) then begin FsInitW:= nil; FsFindFirstW:= nil; FsFindNextW:= nil; FsFindClose:= nil; FreeLibrary(AHandle); Exit(False); end; { Optional } FsSetCryptCallback:= TFsSetCryptCallback(GetProcAddress(AHandle,'FsSetCryptCallback')); FsGetDefRootName := TFsGetDefRootName(GetProcAddress(AHandle,'FsGetDefRootName')); FsExecuteFile := TFsExecuteFile(GetProcAddress(AHandle,'FsExecuteFile')); FsGetFile := TFsGetFile(GetProcAddress(AHandle,'FsGetFile')); FsPutFile := TFsPutFile(GetProcAddress(AHandle,'FsPutFile')); FsDeleteFile := TFsDeleteFile(GetProcAddress(AHandle,'FsDeleteFile')); FsMkDir := TFsMkDir(GetProcAddress(AHandle,'FsMkDir')); FsRemoveDir := TFsRemoveDir(GetProcAddress(AHandle,'FsRemoveDir')); FsStatusInfo := TFsStatusInfo(GetProcAddress(AHandle,'FsStatusInfo')); FsSetDefaultParams := TFsSetDefaultParams(GetProcAddress(AHandle,'FsSetDefaultParams')); //--------------------- FsSetAttr := TFsSetAttr (GetProcAddress(AHandle,'FsSetAttr')); FsSetTime := TFsSetTime (GetProcAddress(AHandle,'FsSetTime')); FsExtractCustomIcon := TFsExtractCustomIcon (GetProcAddress(AHandle,'FsExtractCustomIcon')); FsRenMovFile := TFsRenMovFile (GetProcAddress(AHandle,'FsRenMovFile')); FsDisconnect := TFsDisconnect (GetProcAddress(AHandle,'FsDisconnect')); FsGetPreviewBitmap := TFsGetPreviewBitmap (GetProcAddress(AHandle,'FsGetPreviewBitmap')); FsLinksToLocalFiles := TFsLinksToLocalFiles (GetProcAddress(AHandle,'FsLinksToLocalFiles')); FsGetLocalName := TFsGetLocalName (GetProcAddress(AHandle,'FsGetLocalName')); //--------------------- FsGetBackgroundFlags := TFsGetBackgroundFlags (GetProcAddress(AHandle,'FsGetBackgroundFlags')); //--------------------- FsContentGetDefaultView := TFsContentGetDefaultView (GetProcAddress(AHandle,'FsContentGetDefaultView')); ContentSetDefaultParams := TContentSetDefaultParams (GetProcAddress(AHandle,'FsContentSetDefaultParams')); ContentGetDetectString := TFsContentGetDetectString (GetProcAddress(AHandle,'FsContentGetDetectString')); ContentGetSupportedField := TFsContentGetSupportedField (GetProcAddress(AHandle,'FsContentGetSupportedField')); ContentGetValue := TFsContentGetValue (GetProcAddress(AHandle,'FsContentGetValue')); ContentStopGetValue := TFsContentStopGetValue (GetProcAddress(AHandle,'FsContentStopGetValue')); ContentGetDefaultSortOrder := TFsContentGetDefaultSortOrder (GetProcAddress(AHandle,'FsContentGetDefaultSortOrder')); ContentGetSupportedFieldFlags := TFsContentGetSupportedFieldFlags (GetProcAddress(AHandle,'FsContentGetSupportedFieldFlags')); ContentSetValue := TFsContentSetValue (GetProcAddress(AHandle,'FsContentSetValue')); ContentPluginUnloading := TFsContentPluginUnloading(GetProcAddress(AHandle,'FsContentPluginUnloading')); { Unicode } FsSetCryptCallbackW:= TFsSetCryptCallbackW(GetProcAddress(AHandle,'FsSetCryptCallbackW')); FsMkDirW := TFsMkDirW(GetProcAddress(AHandle,'FsMkDirW')); FsExecuteFileW := TFsExecuteFileW(GetProcAddress(AHandle,'FsExecuteFileW')); FsRenMovFileW := TFsRenMovFileW(GetProcAddress(AHandle,'FsRenMovFileW')); FsGetFileW := TFsGetFileW(GetProcAddress(AHandle,'FsGetFileW')); FsPutFileW := TFsPutFileW(GetProcAddress(AHandle,'FsPutFileW')); FsDeleteFileW := TFsDeleteFileW(GetProcAddress(AHandle,'FsDeleteFileW')); FsRemoveDirW := TFsRemoveDirW(GetProcAddress(AHandle,'FsRemoveDirW')); FsDisconnectW := TFsDisconnectW(GetProcAddress(AHandle,'FsDisconnectW')); FsSetAttrW := TFsSetAttrW (GetProcAddress(AHandle,'FsSetAttrW')); FsSetTimeW := TFsSetTimeW (GetProcAddress(AHandle,'FsSetTimeW')); FsStatusInfoW := TFsStatusInfoW(GetProcAddress(AHandle,'FsStatusInfoW')); FsExtractCustomIconW := TFsExtractCustomIconW(GetProcAddress(AHandle,'FsExtractCustomIconW')); FsGetLocalNameW := TFsGetLocalNameW(GetProcAddress(AHandle,'FsGetLocalNameW')); //-------------------------- FsContentGetDefaultViewW := TFsContentGetDefaultViewW(GetProcAddress(AHandle,'FsContentGetDefaultViewW')); ContentGetValueW := TFsContentGetValueW(GetProcAddress(AHandle, 'FsContentGetValueW')); ContentStopGetValueW := TFsContentStopGetValueW(GetProcAddress(AHandle, 'FsContentStopGetValueW')); ContentSetValueW := TFsContentSetValueW(GetProcAddress(AHandle, 'FsContentSetValueW')); { Extension API } ExtensionInitialize:= TExtensionInitializeProc(GetProcAddress(AHandle,'ExtensionInitialize')); ExtensionFinalize:= TExtensionFinalizeProc(GetProcAddress(AHandle,'ExtensionFinalize')); VFSInit; FModuleHandle := AHandle; finally LeaveCriticalSection(FMutex); end; end; procedure TWFXModule.UnloadModule; var AHandle: TLibHandle; begin EnterCriticalSection(FMutex); try if FModuleHandle <> NilHandle then begin AHandle:= FModuleHandle; FModuleHandle := NilHandle; FreeLibrary(AHandle); end; { Mandatory } FsInit := nil; FsFindFirst := nil; FsFindNext := nil; FsFindClose := nil; { Optional } FsSetCryptCallback := nil; FsGetDefRootName := nil; FsGetFile := nil; FsPutFile := nil; FsDeleteFile := nil; FsRemoveDir := nil; FsExecuteFile := nil; FsMkDir := nil; FsStatusInfo := nil; FsSetDefaultParams:=nil; //--------------------- FsSetAttr := nil; FsSetTime := nil; FsExtractCustomIcon := nil; FsRenMovFile := nil; FsDisconnect := nil; FsGetPreviewBitmap := nil; FsLinksToLocalFiles := nil; FsGetLocalName := nil; //--------------------- FsGetBackgroundFlags := nil; //--------------------- FsContentGetDefaultView := nil; ContentGetDetectString := nil; ContentGetSupportedField := nil; ContentGetValue := nil; ContentSetDefaultParams := nil; ContentStopGetValue := nil; ContentGetDefaultSortOrder := nil; ContentGetSupportedFieldFlags := nil; ContentSetValue := nil; ContentPluginUnloading := nil; { Unicode } FsInitW := nil; FsFindFirstW := nil; FsFindNextW := nil; //--------------------- FsSetCryptCallbackW:= nil; FsMkDirW := nil; FsExecuteFileW := nil; FsRenMovFileW := nil; FsGetFileW := nil; FsPutFileW := nil; FsDeleteFileW := nil; FsRemoveDirW := nil; FsDisconnectW := nil; FsSetAttrW := nil; FsSetTimeW := nil; FsStatusInfoW := nil; FsExtractCustomIconW := nil; FsGetLocalNameW := nil; //--------------------- FsContentGetDefaultViewW := nil; ContentGetValueW := nil; ContentStopGetValueW := nil; ContentSetValueW := nil; // Extension API ExtensionInitialize:= nil; ExtensionFinalize:= nil; finally LeaveCriticalSection(FMutex); end; end; procedure TWFXModule.VFSInit; var dps: tFsDefaultParamStruct; StartupInfo: TExtensionStartupInfo; begin if Assigned(FsSetDefaultParams) then begin dps.DefaultIniName := mbFileNameToSysEnc(gpCfgDir + WfxIniFileName); dps.PluginInterfaceVersionHi:= 2; dps.PluginInterfaceVersionLow:= 0; dps.Size:= SizeOf(dps); FsSetDefaultParams(@dps); end; if not Assigned(FsGetBackgroundFlags) then FBackgroundFlags:= 0 else FBackgroundFlags:= FsGetBackgroundFlags(); // Extension API if Assigned(ExtensionInitialize) then begin InitializeExtension(@StartupInfo); ExtensionInitialize(@StartupInfo); end; CallContentSetDefaultParams; CallContentGetSupportedField; if Length(Self.DetectStr) = 0 then Self.DetectStr := CallContentGetDetectString; end; function TWFXModule.VFSConfigure(Parent: HWND): Boolean; var RemoteName: String; begin try RemoteName:= PathDelim; WFXStatusInfo(PathDelim, FS_STATUS_START, FS_STATUS_OP_EXEC); Result:= (WfxExecuteFile(Parent, RemoteName, 'properties') = FS_EXEC_OK); WFXStatusInfo(PathDelim, FS_STATUS_END, FS_STATUS_OP_EXEC); except on E: Exception do begin Result:= False; end; end; end; function TWFXModule.VFSRootName: String; var pcRootName : PAnsiChar; begin Result:= EmptyStr; if Assigned(FsGetDefRootName) then begin pcRootName:= GetMem(MAX_PATH); Assert(Assigned(pcRootName)); try FsGetDefRootName(pcRootName, MAX_PATH); Result := RepairPluginName(StrPas(pcRootName)); finally FreeMem(pcRootName); end; end; end; function TWFXModule.ContentPlugin: Boolean; begin Result:= Assigned(ContentGetValue) or Assigned(ContentGetValueW); end; { TWFXModuleList } function TWFXModuleList.GetAEnabled(Index: Integer): Boolean; begin Result:= Boolean(PtrInt(Objects[Index])); end; function TWFXModuleList.GetAFileName(Index: Integer): String; begin Result:= ValueFromIndex[Index]; end; function TWFXModuleList.GetAName(Index: Integer): String; begin Result:= Names[Index]; end; procedure TWFXModuleList.SetAEnabled(Index: Integer; const AValue: Boolean); begin Objects[Index]:= TObject(PtrInt(AValue)); end; procedure TWFXModuleList.SetAFileName(Index: Integer; const AValue: String); begin ValueFromIndex[Index]:= AValue; end; procedure TWFXModuleList.SetAName(Index: Integer; const AValue: String); var sValue : String; begin sValue:= ValueFromIndex[Index]; Self[Index]:= AValue + '=' + sValue; end; constructor TWFXModuleList.Create; begin FModuleList:= TStringListEx.Create; FModuleList.Sorted:= True; end; destructor TWFXModuleList.Destroy; var I: Integer; begin for I:= 0 to FModuleList.Count - 1 do begin TWfxModule(FModuleList.Objects[I]).Free; end; FreeAndNil(FModuleList); inherited Destroy; end; procedure TWFXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode); var I: Integer; AName, APath: String; begin Clear; ANode := ANode.FindNode('WfxPlugins'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('WfxPlugin') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', AName) and AConfig.TryGetValue(ANode, 'Path', APath) then begin I := Add(RepairPluginName(AName), APath); Enabled[I] := AConfig.GetAttr(ANode, 'Enabled', True); end; end; ANode := ANode.NextSibling; end; end; end; procedure TWFXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode); var I: Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'WfxPlugins', True); AConfig.ClearNode(ANode); for I := 0 to Count - 1 do begin SubNode := AConfig.AddNode(ANode, 'WfxPlugin'); AConfig.SetAttr(SubNode, 'Enabled', Enabled[I]); AConfig.AddValue(SubNode, 'Name', Name[I]); AConfig.AddValue(SubNode, 'Path', FileName[I]); end; end; { TWFXModuleList.ComputeSignature } function TWFXModuleList.ComputeSignature(seed: dword): dword; var iIndex: integer; begin result := seed; for iIndex := 0 to pred(Count) do begin result := ComputeSignatureBoolean(result, Enabled[iIndex]); result := ComputeSignatureString(result, Name[iIndex]); result := ComputeSignatureString(result, FileName[iIndex]); end; end; function TWFXModuleList.Add(Ext: String; FileName: String): Integer; begin Result:= AddObject(Ext + '=' + FileName, TObject(True)); end; function TWFXModuleList.FindFirstEnabledByName(Name: String): Integer; begin for Result := 0 to Count - 1 do if Enabled[Result] and (DoCompareText(Names[Result], Name) = 0) then Exit; Result := -1; end; function TWFXModuleList.LoadModule(const FileName: String): TWfxModule; var Index: Integer; begin if FModuleList.Find(FileName, Index) then Result := TWfxModule(FModuleList.Objects[Index]) else begin Result := TWfxModule.Create; if not Result.LoadModule(FileName) then FreeAndNil(Result) else begin FModuleList.AddObject(FileName, Result); end; end; end; end. doublecmd-1.1.22/src/uwfxprototypes.pas0000644000175000001440000001247214743153644017252 0ustar alexxusersunit uWFXprototypes; {$mode objfpc}{$H+} interface uses WfxPlugin; {$IFDEF MSWINDOWS}{$CALLING STDCALL}{$ELSE}{$CALLING CDECL}{$ENDIF} type { File system plugins API (version 2.0) for TC } {R} //Realized {U} //Unrealized { Mandatory } {R} TFsInit=function(PluginNr:Integer; pProgressProc:tProgressProc; pLogProc:tlogProc; pRequestProc:tRequestProc):integer; {R} TFsFindFirst=function(path :pansichar;var FindData:tWIN32FINDDATA):thandle; {R} TFsFindNext=function(Hdl:thandle;var FindData:tWIN32FINDDATA):bool; {R} TFsFindClose=function(Hdl:thandle):integer; { Optional } {R} TFsSetCryptCallback = procedure(pCryptProc:TCryptProc;CryptoNr,Flags:integer); {R} TFsMkDir = function(RemoteDir:pansichar):bool; {R} TFsGetFile = function(RemoteName,LocalName:pansichar;CopyFlags:integer; RemoteInfo:pRemoteInfo):integer; {R} TFsPutFile=function(LocalName,RemoteName:pansichar;CopyFlags:integer):integer; {R} TFsDeleteFile=function(RemoteName:pansichar):bool; {R} TFsRemoveDir=function(RemoteName:pansichar):bool; {R} TFsStatusInfo = procedure(RemoteDir:pansichar;InfoStartEnd,InfoOperation:integer); {R} TFsSetDefaultParams = procedure (dps:pFsDefaultParamStruct); {R} TFsExecuteFile=Function(MainWin:HWND;RemoteName,Verb:pansichar):integer; {R} TFsGetDefRootName=procedure (DefRootName:pansichar;maxlen:integer); //------------------------------------------------------ {R} TFsSetAttr=function (RemoteName:pansichar;NewAttr:integer):bool; {R} TFsSetTime=Function(RemoteName:pansichar;CreationTime,LastAccessTime,LastWriteTime:PWfxFileTime):bool; {U} TFsExtractCustomIcon=function(RemoteName:pansichar;ExtractFlags:integer;var TheIcon:hicon):integer; {R} TFsRenMovFile= function(OldName,NewName:pansichar; Move, OverWrite:bool; ri:pRemoteInfo):Integer; {U} TFsDisconnect = function (DisconnectRoot:pansichar):bool; {U} TFsGetPreviewBitmap = function ( RemoteName:pansichar; width,height:integer; ReturnedBitmap:HBITMAP):integer; {R} TFsLinksToLocalFiles = function:bool; {R} TFsGetLocalName = function (RemoteName:pansichar;maxlen:integer):bool; //------------------------------------------------------ TFsGetBackgroundFlags = function: integer; //------------------------------------------------------ {R} TFsContentPluginUnloading = procedure; {U} TFsContentGetDetectString = procedure (DetectString:pansichar;maxlen:integer); {U} TFsContentGetSupportedField = function (FieldIndex:integer;FieldName:pansichar; Units:pansichar;maxlen:integer):integer; {U} TFsContentGetValue = function (FileName:pansichar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer; {U} TFsContentSetDefaultParams = procedure (dps:pContentDefaultParamStruct); {U} TFsContentStopGetValue = procedure (FileName:pansichar); {U} TFsContentGetDefaultSortOrder = function (FieldIndex:integer):integer; {U} TFsContentGetSupportedFieldFlags = function (FieldIndex:integer):integer; {U} TFsContentSetValue = function (FileName:pansichar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; {U} TFsContentGetDefaultView = function (ViewContents,ViewHeaders,ViewWidths, ViewOptions:pansichar;maxlen:integer):bool; { Unicode } TFsInitW = function(PluginNr:integer;pProgressProcW:tProgressProcW;pLogProcW:tLogProcW; pRequestProcW:tRequestProcW):integer; TFsFindFirstW = function(path :pwidechar;var FindData:tWIN32FINDDATAW):thandle; TFsFindNextW = function(Hdl:thandle;var FindDataW:tWIN32FINDDATAW):bool; //------------------------------------------------------ TFsSetCryptCallbackW = procedure(CryptProcW:TCryptProcW;CryptoNr,Flags:integer); TFsMkDirW = function(RemoteDir:pwidechar):bool; TFsExecuteFileW = function(MainWin:HWND;RemoteName,Verb:pwidechar):integer; TFsRenMovFileW = function(OldName,NewName:pwidechar;Move,OverWrite:bool; RemoteInfo:pRemoteInfo):integer; TFsGetFileW = function(RemoteName,LocalName:pwidechar;CopyFlags:integer; RemoteInfo:pRemoteInfo):integer; TFsPutFileW = function(LocalName,RemoteName:pwidechar;CopyFlags:integer):integer; TFsDeleteFileW = function(RemoteName:pwidechar):bool; TFsRemoveDirW = function(RemoteName:pwidechar):bool; TFsDisconnectW = function(DisconnectRoot:pwidechar):bool; TFsSetAttrW = function(RemoteName:pwidechar;NewAttr:integer):bool; TFsSetTimeW = function(RemoteName:pwidechar;CreationTime,LastAccessTime, LastWriteTime:PWfxFileTime):bool; TFsStatusInfoW = procedure(RemoteDir:pwidechar;InfoStartEnd,InfoOperation:integer); TFsExtractCustomIconW = function(RemoteName:pwidechar;ExtractFlags:integer; var TheIcon:hicon):integer; TFsGetPreviewBitmapW = function(RemoteName:pwidechar;width,height:integer; var ReturnedBitmap:hbitmap):integer; TFsGetLocalNameW = function(RemoteName:pwidechar;maxlen:integer):bool; //------------------------------------------------------ TFsContentGetValueW = function(FileName:pwidechar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer; TFsContentStopGetValueW = procedure(FileName:pwidechar); TFsContentSetValueW = function(FileName:pwidechar;FieldIndex,UnitIndex,FieldType:integer; FieldValue:pbyte;flags:integer):integer; TFsContentGetDefaultViewW = function(ViewContents,ViewHeaders,ViewWidths, ViewOptions:pwidechar;maxlen:integer):bool; //------------------------------------------------------ {$CALLING DEFAULT} implementation end. doublecmd-1.1.22/src/uwlxmodule.pas0000644000175000001440000006032614743153644016316 0ustar alexxusers{ Double Commander ------------------------------------------------------------------------- WLX-API implementation (TC WLX-API v2.0). Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru) Copyright (C) 2009-2023 Alexander Koblov (alexx2000@mail.ru) 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, see . } unit uWlxModule; {$mode objfpc}{$H+} {$IFDEF DARWIN} {$modeswitch objectivec1} {$ENDIF} interface uses Classes, SysUtils, dynlibs, uDetectStr, uWlxPrototypes, WlxPlugin, DCClassesUtf8, uDCUtils, LCLProc, LCLType, DCXmlConfig {$IFDEF MSWINDOWS} , Windows, LCLIntf, Controls {$ENDIF} {$IFDEF LCLGTK} , gtk, glib, gdk, gtkproc {$ENDIF} {$IFDEF LCLGTK2} , gtk2, glib2, gtk2proc {$ENDIF} {$IFDEF LCLQT} , qt4, qtwidgets // The Qt widgetset must be used to load plugins on qt {$ENDIF} {$IFDEF LCLQT5} , qt5, qtwidgets {$ENDIF} {$IFDEF LCLQT6} , qt6, qtwidgets {$ENDIF} {$IFDEF LCLCOCOA} , CocoaAll {$ENDIF} {$IF DEFINED(MSWINDOWS) and (DEFINED(LCLQT5) or DEFINED(DARKWIN))} , uDarkStyle {$ENDIF} ; type { TWlxModule } TWlxModule = class protected // a) Mandatory (must be implemented) ListLoad: TListLoad; // b) Optional (must NOT be implemented if unsupported!) ListLoadNext: TListLoadNext; ListCloseWindow: TListCloseWindow; ListGetDetectString: TListGetDetectString; ListSearchText: TListSearchText; ListSearchDialog: TListSearchDialog; ListSendCommand: TListSendCommand; ListPrint: TListPrint; ListNotificationReceived: TListNotificationReceived; ListSetDefaultParams: TListSetDefaultParams; ListGetPreviewBitmap: TListGetPreviewBitmap; // c) Unicode ListLoadW: TListLoadW; ListLoadNextW: TListLoadNextW; ListSearchTextW: TListSearchTextW; ListPrintW: TListPrintW; ListGetPreviewBitmapW: TListGetPreviewBitmapW; private FModuleHandle: TLibHandle; // Handle to .DLL or .so FParser: TParserControl; FPluginWindow: HWND; function GetCanPreview: Boolean; function GetCanPrint: Boolean; function GetDetectStr: String; function GIsLoaded: Boolean; procedure SetDetectStr(const AValue: String); procedure WlxPrepareContainer(var {%H-}ParentWin: HWND); public Name: String; FileName: String; pShowFlags: Integer; QuickView: Boolean; Enabled: Boolean; //--------------------- constructor Create; destructor Destroy; override; //--------------------- function LoadModule: Boolean; procedure UnloadModule; //--------------------- function CallListLoad(ParentWin: HWND; FileToLoad: String; ShowFlags: Integer): HWND; function CallListLoadNext(ParentWin: HWND; FileToLoad: String; ShowFlags: Integer): Integer; function CallListGetDetectString: String; procedure CallListSetDefaultParams; procedure CallListCloseWindow; function CallListGetPreviewBitmap(FileToLoad: String; Width, Height: Integer; ContentBuf: String): HBITMAP; function CallListNotificationReceived(Msg, wParam, lParam: Integer): Integer; function CallListPrint(FileToPrint, DefPrinter: String; PrintFlags: Integer; var Margins: trect): Integer; function CallListSearchDialog(FindNext: Integer): Integer; function CallListSearchText(SearchString: String; SearchParameter: Integer): Integer; function CallListSendCommand(Command, Parameter: Integer): Integer; //--------------------- function FileParamVSDetectStr(AFileName: String; bForce: Boolean): Boolean; //--------------------- procedure SetFocus; procedure ResizeWindow(aRect: TRect); //--------------------- property IsLoaded: Boolean read GIsLoaded; property DetectStr: String read GetDetectStr write SetDetectStr; property ModuleHandle: TLibHandle read FModuleHandle write FModuleHandle; property CanPreview: Boolean read GetCanPreview; property PluginWindow: HWND read FPluginWindow; property CanPrint: Boolean read GetCanPrint; end; { TWLXModuleList } TWLXModuleList = class private Flist: TStringList; function GetCount: Integer; public //--------------------- constructor Create; destructor Destroy; override; //--------------------- procedure Clear; procedure Exchange(Index1, Index2: Integer); procedure Move(CurIndex, NewIndex: Integer); procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload; procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload; function ComputeSignature(seed: dword): dword; procedure DeleteItem(Index: Integer); //--------------------- function Add(Item: TWlxModule): Integer; overload; function Add(FileName: String): Integer; overload; function Add(AName, FileName, DetectStr: String): Integer; overload; //--------------------- procedure Assign(OtherList: TWLXModuleList); function IndexOfName(const AName: string): Integer; //--------------------- function IsLoaded(AName: String): Boolean; overload; function IsLoaded(Index: Integer): Boolean; overload; function LoadModule(AName: String): Boolean; overload; function LoadModule(Index: Integer): Boolean; overload; //--------------------- function GetWlxModule(Index: Integer): TWlxModule; overload; function GetWlxModule(AName: String): TWlxModule; overload; //--------------------- //--------------------- //property WlxList:TStringList read Flist; property Count: Integer read GetCount; end; implementation uses //Lazarus, Free-Pascal, etc. FileUtil, //DC uComponentsSignature, uDebug, DCOSUtils, DCConvertEncoding, uOSUtils, uGlobsPaths, uGlobs; const WlxIniFileName = 'wlx.ini'; {$IF DEFINED(LCLWIN32)} var WindowProcAtom: PWideChar; function PluginProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var WindowProc: WNDPROC; begin WindowProc := WNDPROC(GetPropW(hWnd, WindowProcAtom)); if Assigned(WindowProc) then Result := CallWindowProc(WindowProc, hWnd, Msg, wParam, lParam) else begin Result := DefWindowProc(hWnd, Msg, wParam, lParam); end; if (Result = 0) and (Msg = WM_KEYDOWN) then begin PostMessage(GetParent(hWnd), Msg, wParam, lParam); end; end; function ListerProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var Lister: TControl; WindowProc: WNDPROC; begin WindowProc := WNDPROC(GetPropW(hWnd, WindowProcAtom)); if Assigned(WindowProc) then Result := CallWindowProc(WindowProc, hWnd, Msg, wParam, lParam) else begin Result := DefWindowProcW(hWnd, Msg, wParam, lParam); end; if (Result = 0) and (Msg = WM_COMMAND) and (lParam <> 0) then begin Lister:= TControl(GetLCLOwnerObject(hWnd)); if Assigned(Lister) then Lister.Perform(Msg, wParam, lParam); end; end; {$ENDIF} { TWlxModule } procedure TWlxModule.WlxPrepareContainer(var {%H-}ParentWin: HWND); begin {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} ParentWin := HWND(QWidget_winId(TQtWidget(ParentWin).GetContainerWidget)); if QuickView then ParentWin := Windows.GetAncestor(ParentWin, GA_PARENT) else begin ParentWin := Windows.GetAncestor(ParentWin, GA_ROOT); end; {$ELSEIF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} ParentWin := HWND(GetFixedWidget(Pointer(ParentWin))); {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} ParentWin := HWND(TQtWidget(ParentWin).GetContainerWidget); {$ENDIF} end; function TWlxModule.GIsLoaded: Boolean; begin Result := FModuleHandle <> 0; end; procedure TWlxModule.SetDetectStr(const AValue: String); begin FParser.DetectStr:= AValue; end; function TWlxModule.GetCanPrint: Boolean; begin Result := Assigned(ListPrint) or Assigned(ListPrintW); end; function TWlxModule.GetDetectStr: String; begin Result:= FParser.DetectStr; end; function TWlxModule.GetCanPreview: Boolean; begin Result:= Assigned(ListGetPreviewBitmap) or Assigned(ListGetPreviewBitmapW); end; constructor TWlxModule.Create; begin Enabled := True; FParser := TParserControl.Create; end; destructor TWlxModule.Destroy; begin {$IF NOT DEFINED(LCLWIN32)} if GIsLoaded then UnloadModule; {$ENDIF} if Assigned(FParser) then FParser.Free; inherited Destroy; end; function TWlxModule.LoadModule: Boolean; begin // DCDebug('WLXM LoadModule entered'); if (FModuleHandle <> NilHandle) then Exit(True); FModuleHandle := mbLoadLibrary(mbExpandFileName(Self.FileName)); Result := (FModuleHandle <> NilHandle); if FModuleHandle = NilHandle then Exit; { Mandatory } ListLoad := TListLoad(GetProcAddress(FModuleHandle, 'ListLoad')); { Optional } ListLoadNext := TListLoadNext(GetProcAddress(FModuleHandle, 'ListLoadNext')); ListCloseWindow := TListCloseWindow(GetProcAddress(FModuleHandle, 'ListCloseWindow')); ListGetDetectString := TListGetDetectString(GetProcAddress(FModuleHandle, 'ListGetDetectString')); ListSearchText := TListSearchText(GetProcAddress(FModuleHandle, 'ListSearchText')); ListSearchDialog := TListSearchDialog(GetProcAddress(FModuleHandle, 'ListSearchDialog')); ListSendCommand := TListSendCommand(GetProcAddress(FModuleHandle, 'ListSendCommand')); ListPrint := TListPrint(GetProcAddress(FModuleHandle, 'ListPrint')); ListNotificationReceived := TListNotificationReceived(GetProcAddress(FModuleHandle, 'ListNotificationReceived')); ListSetDefaultParams := TListSetDefaultParams(GetProcAddress(FModuleHandle, 'ListSetDefaultParams')); ListGetPreviewBitmap := TListGetPreviewBitmap(GetProcAddress(FModuleHandle, 'ListGetPreviewBitmap')); { Unicode } ListLoadW := TListLoadW(GetProcAddress(FModuleHandle, 'ListLoadW')); ListLoadNextW := TListLoadNextW(GetProcAddress(FModuleHandle, 'ListLoadNextW')); ListSearchTextW := TListSearchTextW(GetProcAddress(FModuleHandle, 'ListSearchTextW')); ListPrintW := TListPrintW(GetProcAddress(FModuleHandle, 'ListPrintW')); ListGetPreviewBitmapW := TListGetPreviewBitmapW(GetProcAddress(FModuleHandle, 'ListGetPreviewBitmapW')); // ListSetDefaultParams must be called immediately after loading the DLL, before ListLoad. CallListSetDefaultParams; // DCDebug('WLXM LoadModule Leaved'); end; procedure TWlxModule.UnloadModule; begin {$IF NOT (DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6) or DEFINED(LCLGTK2))} {$IF (not DEFINED(LINUX)) or ((FPC_VERSION > 2) or ((FPC_VERSION=2) and (FPC_RELEASE >= 5)))} if FModuleHandle <> 0 then FreeLibrary(FModuleHandle); {$ENDIF} FModuleHandle := 0; { Mandatory } ListLoad := nil; { Optional } ListLoadNext := nil; ListCloseWindow := nil; ListGetDetectString := nil; ListSearchText := nil; ListSearchDialog := nil; ListSendCommand := nil; ListPrint := nil; ListNotificationReceived := nil; ListSetDefaultParams := nil; ListGetPreviewBitmap := nil; { Unicode } ListLoadW := nil; ListLoadNextW := nil; ListSearchTextW := nil; ListPrintW := nil; ListGetPreviewBitmapW := nil; {$ENDIF} end; function TWlxModule.CallListLoad(ParentWin: HWND; FileToLoad: String; ShowFlags: Integer): HWND; begin WlxPrepareContainer(ParentWin); {$IF DEFINED(MSWINDOWS) and (DEFINED(LCLQT5) or DEFINED(DARKWIN))} if g_darkModeEnabled then begin ShowFlags:= ShowFlags or lcp_darkmode; if g_darkModeSupported then ShowFlags:= ShowFlags or lcp_darkmodenative; end; {$ENDIF} if Assigned(ListLoadW) then FPluginWindow := ListLoadW(ParentWin, PWideChar(CeUtf8ToUtf16(FileToLoad)), ShowFlags) else if Assigned(ListLoad) then FPluginWindow := ListLoad(ParentWin, PAnsiChar(CeUtf8ToSys(FileToLoad)), ShowFlags) else Exit(wlxInvalidHandle); {$IF DEFINED(LCLWIN32)} if FPluginWindow <> 0 then begin // Subclass viewer window to catch WM_COMMAND message. Result:= HWND(SetWindowLongPtrW(ParentWin, GWL_WNDPROC, LONG_PTR(@ListerProc))); Windows.SetPropW(ParentWin, WindowProcAtom, Result); // Subclass plugin window to catch some hotkeys like 'n' or 'p'. Result := HWND(SetWindowLongPtr(FPluginWindow, GWL_WNDPROC, LONG_PTR(@PluginProc))); Windows.SetPropW(FPluginWindow, WindowProcAtom, Result); end; {$ENDIF} {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} if FPluginWindow <> 0 then begin SetWindowLongPtr(FPluginWindow, GWL_HWNDPARENT, ParentWin); end; {$ENDIF} Result := FPluginWindow; end; function TWlxModule.CallListLoadNext(ParentWin: HWND; FileToLoad: String; ShowFlags: Integer): Integer; begin WlxPrepareContainer(ParentWin); {$IF DEFINED(MSWINDOWS) and (DEFINED(LCLQT5) or DEFINED(DARKWIN))} if g_darkModeEnabled then begin ShowFlags:= ShowFlags or lcp_darkmode; if g_darkModeSupported then ShowFlags:= ShowFlags or lcp_darkmodenative; end; {$ENDIF} if Assigned(ListLoadNextW) then Result := ListLoadNextW(ParentWin, FPluginWindow, PWideChar(CeUtf8ToUtf16(FileToLoad)), ShowFlags) else if Assigned(ListLoadNext) then Result := ListLoadNext(ParentWin, FPluginWindow, PAnsiChar(CeUtf8ToSys(FileToLoad)), ShowFlags) else Result := LISTPLUGIN_ERROR; end; procedure TWlxModule.CallListCloseWindow; begin // DCDebug('Try to call ListCloseWindow'); try {$IF DEFINED(LCLWIN32)} SetWindowLongPtr(FPluginWindow, GWL_WNDPROC, LONG_PTR(RemovePropW(FPluginWindow, WindowProcAtom))); SetWindowLongPtrW(GetParent(FPluginWindow), GWL_WNDPROC, LONG_PTR(RemovePropW(GetParent(FPluginWindow), WindowProcAtom))); {$ENDIF} if Assigned(ListCloseWindow) then ListCloseWindow(FPluginWindow) {$IF DEFINED(MSWINDOWS)} else DestroyWindow(FPluginWindow) {$ELSEIF DEFINED(LCLGTK) or DEFINED(LCLGTK2)} else gtk_widget_destroy(PGtkWidget(FPluginWindow)); {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} else QWidget_Destroy(QWidgetH(FPluginWindow)); {$ENDIF} finally FPluginWindow := 0; {$IF DEFINED(MSWINDOWS)} // Reset current directory SetCurrentDirectoryW(PWideChar(CeUtf8ToUtf16(gpExePath))); {$ENDIF} end; // DCDebug('Call ListCloseWindow success'); end; function TWlxModule.CallListGetDetectString: String; const MAX_LEN = 2048; // See listplugin.hlp for details begin if not Assigned(ListGetDetectString) then Result := EmptyStr else begin Result := StringOfChar(#0, MAX_LEN); ListGetDetectString(PAnsiChar(Result), MAX_LEN); Result := Trim(PAnsiChar(Result)); end; end; function TWlxModule.CallListSearchText(SearchString: String; SearchParameter: Integer): Integer; begin if Assigned(ListSearchTextW) then Result := ListSearchTextW(FPluginWindow, PWideChar(CeUtf8ToUtf16(SearchString)), SearchParameter) else if Assigned(ListSearchText) then Result := ListSearchText(FPluginWindow, PAnsiChar(CeUtf8ToSys(SearchString)), SearchParameter) else Result := LISTPLUGIN_ERROR; end; function TWlxModule.CallListSearchDialog(FindNext: Integer): Integer; begin if Assigned(ListSearchDialog) then begin Result := ListSearchDialog(FPluginWindow, FindNext); end else Result := LISTPLUGIN_ERROR; end; function TWlxModule.CallListSendCommand(Command, Parameter: Integer): Integer; begin if Assigned(ListSendCommand) then begin Result := ListSendCommand(FPluginWindow, Command, Parameter); end else Result := LISTPLUGIN_ERROR; end; function TWlxModule.FileParamVSDetectStr(AFileName: String; bForce: Boolean): Boolean; begin if not Enabled then Exit(False); FParser.IsForce:= bForce; // DCDebug('DetectStr = ' + FParser.DetectStr); // DCDebug('AFileName = ' + AFileName); Result := FParser.TestFileResult(AFileName); end; procedure TWlxModule.SetFocus; begin {$IF DEFINED(MSWINDOWS)} Windows.SetFocus(FPluginWindow); {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} QWidget_setFocus(QWidgetH(FPluginWindow)); {$ELSEIF DEFINED(LCLGTK2)} gtk_widget_grab_focus(PGtkWidget(FPluginWindow)); {$ENDIF} end; procedure TWlxModule.ResizeWindow(aRect: TRect); begin //ToDo: Implement for other widgetsets with aRect do begin {$IF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)} if not QuickView then begin OffsetRect(aRect, 0, GetSystemMetrics(SM_CYMENU)); end; MoveWindow(FPluginWindow, Left, Top, Right - Left, Bottom - Top, True); {$ELSEIF DEFINED(LCLWIN32)} MoveWindow(FPluginWindow, Left, Top, Right - Left, Bottom - Top, True); {$ELSEIF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)} QWidget_move(QWidgetH(FPluginWindow), Left, Top); QWidget_resize(QWidgetH(FPluginWindow), Right - Left, Bottom - Top); {$ELSEIF DEFINED(LCLGTK2)} gtk_widget_set_uposition(PGtkWidget(FPluginWindow), Left, -1); gtk_widget_set_usize(PGtkWidget(FPluginWindow), Right - Left, Bottom - Top); {$ELSEIF DEFINED(LCLCOCOA)} NSView(FPluginWindow).setFrame( NSMakeRect(Left,Top,Width,Height) ); {$ENDIF} end; end; function TWlxModule.CallListPrint(FileToPrint, DefPrinter: String; PrintFlags: Integer; var Margins: trect): Integer; begin if Assigned(ListPrintW) then Result := ListPrintW(FPluginWindow, PWideChar(CeUtf8ToUtf16(FileToPrint)), PWideChar(CeUtf8ToUtf16(DefPrinter)), PrintFlags, Margins) else if Assigned(ListPrint) then Result := ListPrint(FPluginWindow, PAnsiChar(CeUtf8ToSys(FileToPrint)), PAnsiChar(CeUtf8ToSys(DefPrinter)), PrintFlags, Margins) else Result := LISTPLUGIN_ERROR; end; function TWlxModule.CallListNotificationReceived(Msg, wParam, lParam: Integer): Integer; begin if Assigned(ListNotificationReceived) then begin Result := ListNotificationReceived(FPluginWindow, Msg, wParam, lParam); end; end; procedure TWlxModule.CallListSetDefaultParams; var dps: TListDefaultParamStruct; begin if Assigned(ListSetDefaultParams) then begin dps.DefaultIniName := mbFileNameToSysEnc(gpCfgDir + WlxIniFileName); dps.PluginInterfaceVersionHi := 2; dps.PluginInterfaceVersionLow := 0; dps.Size := SizeOf(TListDefaultParamStruct); ListSetDefaultParams(@dps); end; end; function TWlxModule.CallListGetPreviewBitmap(FileToLoad: String; Width, Height: Integer; ContentBuf: String): HBITMAP; begin if Assigned(ListGetPreviewBitmapW) then Result := ListGetPreviewBitmapW(PWideChar(CeUtf8ToUtf16(FileToLoad)), Width, Height, PByte(ContentBuf), Length(ContentBuf)) else if Assigned(ListGetPreviewBitmap) then Result := ListGetPreviewBitmap(PAnsiChar(CeUtf8ToSys(FileToLoad)), Width, Height, PByte(ContentBuf), Length(ContentBuf)) else Result := 0; end; { TWLXModuleList } function TWLXModuleList.GetCount: Integer; begin if Assigned(Flist) then Result := Flist.Count else Result := 0; end; constructor TWLXModuleList.Create; begin Flist := TStringList.Create; end; destructor TWLXModuleList.Destroy; begin Clear; FreeAndNil(Flist); inherited Destroy; end; procedure TWLXModuleList.Clear; begin while Flist.Count > 0 do begin TWlxModule(Flist.Objects[0]).Free; Flist.Delete(0); end; end; procedure TWLXModuleList.Exchange(Index1, Index2: Integer); begin FList.Exchange(Index1, Index2); end; procedure TWLXModuleList.Move(CurIndex, NewIndex: Integer); begin FList.Move(CurIndex, NewIndex); end; procedure TWLXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode); var AName, APath: String; AWlxModule: TWlxModule; begin Clear; ANode := ANode.FindNode('WlxPlugins'); if Assigned(ANode) then begin ANode := ANode.FirstChild; while Assigned(ANode) do begin if ANode.CompareName('WlxPlugin') = 0 then begin if AConfig.TryGetValue(ANode, 'Name', AName) and AConfig.TryGetValue(ANode, 'Path', APath) then begin AWlxModule := TWlxModule.Create; Flist.AddObject(UpCase(AName), AWlxModule); AWlxModule.Name := AName; AWlxModule.FileName := APath; AWlxModule.DetectStr := AConfig.GetValue(ANode, 'DetectString', ''); AWlxModule.Enabled:= AConfig.GetAttr(ANode, 'Enabled', True); end else DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.'); end; ANode := ANode.NextSibling; end; end; end; procedure TWLXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode); var i: Integer; SubNode: TXmlNode; begin ANode := AConfig.FindNode(ANode, 'WlxPlugins', True); AConfig.ClearNode(ANode); for i := 0 to Flist.Count - 1 do begin SubNode := AConfig.AddNode(ANode, 'WlxPlugin'); AConfig.SetAttr(SubNode, 'Enabled', TWlxModule(Flist.Objects[I]).Enabled); AConfig.AddValue(SubNode, 'Name', TWlxModule(Flist.Objects[I]).Name); AConfig.AddValue(SubNode, 'Path', TWlxModule(Flist.Objects[I]).FileName); AConfig.AddValue(SubNode, 'DetectString', TWlxModule(Flist.Objects[I]).DetectStr); end; end; { TWLXModuleList.ComputeSignature } function TWLXModuleList.ComputeSignature(seed: dword): dword; var iIndex: integer; begin result := seed; for iIndex := 0 to pred(Count) do begin result := ComputeSignatureBoolean(result, TWlxModule(Flist.Objects[iIndex]).Enabled); result := ComputeSignatureString(result, TWlxModule(Flist.Objects[iIndex]).Name); result := ComputeSignatureString(result, TWlxModule(Flist.Objects[iIndex]).FileName); result := ComputeSignatureString(result, TWlxModule(Flist.Objects[iIndex]).DetectStr); end; end; procedure TWLXModuleList.DeleteItem(Index: Integer); begin if (Index > -1) and (Index < Flist.Count) then begin TWlxModule(Flist.Objects[Index]).Free; Flist.Delete(Index); end; end; function TWLXModuleList.Add(Item: TWlxModule): Integer; begin Result := Flist.AddObject(UpCase(item.Name), Item); end; function TWLXModuleList.Add(FileName: String): Integer; var s: String; begin // DCDebug('WLXLIST Add entered'); s := ExtractFileName(FileName); if pos('.', s) > 0 then Delete(s, pos('.', s), length(s)); Result := Flist.AddObject(UpCase(s), TWlxModule.Create); TWlxModule(Flist.Objects[Result]).Name := s; TWlxModule(Flist.Objects[Result]).FileName := FileName; if TWlxModule(Flist.Objects[Result]).LoadModule then begin TWlxModule(Flist.Objects[Result]).DetectStr := TWlxModule(Flist.Objects[Result]).CallListGetDetectString; TWlxModule(Flist.Objects[Result]).UnloadModule; end; // DCDebug('WLXLIST ADD Leaved'); end; function TWLXModuleList.Add(AName, FileName, DetectStr: String): Integer; begin Result := Flist.AddObject(UpCase(AName), TWlxModule.Create); TWlxModule(Flist.Objects[Result]).Name := AName; TWlxModule(Flist.Objects[Result]).DetectStr := DetectStr; TWlxModule(Flist.Objects[Result]).FileName := FileName; end; procedure TWLXModuleList.Assign(OtherList: TWLXModuleList); var I, J: Integer; begin Clear; for I := 0 to OtherList.Flist.Count - 1 do begin with TWlxModule(OtherList.Flist.Objects[I]) do begin J:= Add(Name, FileName, DetectStr); GetWlxModule(J).Enabled:= Enabled; end; end; end; function TWLXModuleList.IndexOfName(const AName: string): Integer; begin Result := Flist.IndexOf(UpCase(AName)); end; function TWLXModuleList.IsLoaded(AName: String): Boolean; var x: Integer; begin x := Flist.IndexOf(AName); if x = -1 then Result := False else begin Result := GetWlxModule(x).IsLoaded; end; end; function TWLXModuleList.IsLoaded(Index: Integer): Boolean; begin Result := GetWlxModule(Index).IsLoaded; end; function TWLXModuleList.LoadModule(AName: String): Boolean; var x: Integer; begin x := Flist.IndexOf(UpCase(AName)); if x = -1 then Result := False else begin Result := GetWlxModule(x).LoadModule; end; end; function TWLXModuleList.LoadModule(Index: Integer): Boolean; begin Result := GetWlxModule(Index).LoadModule; end; function TWLXModuleList.GetWlxModule(Index: Integer): TWlxModule; begin Result := TWlxModule(Flist.Objects[Index]); end; function TWLXModuleList.GetWlxModule(AName: String): TWlxModule; var tmp: Integer; begin tmp := Flist.IndexOf(upcase(AName)); if tmp > -1 then Result := TWlxModule(Flist.Objects[tmp]); end; {$IF DEFINED(LCLWIN32)}{$WARNINGS OFF} initialization WindowProcAtom := Pointer(GlobalAddAtomW('Double Commander')); finalization Windows.GlobalDeleteAtom(ATOM(WindowProcAtom)); {$ENDIF} end. doublecmd-1.1.22/src/uwlxprototypes.pas0000644000175000001440000000350514743153644017255 0ustar alexxusersunit uwlxprototypes; {$mode objfpc}{$H+} interface uses Classes, SysUtils, WlxPlugin, LCLType; {$IFDEF MSWINDOWS}{$CALLING STDCALL}{$ELSE}{$CALLING CDECL}{$ENDIF} type { Mandatory } TListLoad = function (ParentWin: HWND; FileToLoad: PAnsiChar; ShowFlags: Integer): HWND; { Optional } TListLoadNext = function (ParentWin, PluginWin: HWND; FileToLoad: PAnsiChar; ShowFlags: Integer): Integer; TListCloseWindow = procedure (ListWin: HWND); TListGetDetectString = procedure (DetectString: PAnsiChar; MaxLen: Integer); TListSearchText = function (ListWin: HWND; SearchString: PAnsiChar; SearchParameter: Integer): Integer; TListSearchDialog = function (ListWin: HWND; FindNext: Integer): Integer; TListSendCommand = function (ListWin: HWND; Command, Parameter: Integer): Integer; TListPrint = function (ListWin: HWND; FileToPrint, DefPrinter: PAnsiChar; PrintFlags: Integer; var Margins: TRect): Integer; TListNotificationReceived = function (ListWin: HWND; Message, wParam, lParam: Integer): Integer; TListSetDefaultParams = procedure (dps: PListDefaultParamStruct); TListGetPreviewBitmap = function (FileToLoad: PAnsiChar; Width, Height: Integer; ContentBuf: PByte; ContentBufLen: Integer): HBITMAP; { Unicode } TListLoadW = function (ParentWin: HWND; FileToLoad: PWideChar; ShowFlags: Integer): HWND; TListLoadNextW = function (ParentWin, PluginWin: HWND; FileToLoad: PWideChar; ShowFlags: Integer): Integer; TListSearchTextW = function (ListWin: HWND; SearchString: PWideChar; SearchParameter: Integer): Integer; TListPrintW = function (ListWin: HWND; FileToPrint, DefPrinter: PWideChar; PrintFlags: Integer; var Margins: TRect): Integer; TListGetPreviewBitmapW = function (FileToLoad: PWideChar; Width, Height: Integer; ContentBuf: PByte; ContentBufLen: Integer): HBITMAP; {$CALLING DEFAULT} implementation end. doublecmd-1.1.22/tools/0000755000175000001440000000000014743153644013746 5ustar alexxusersdoublecmd-1.1.22/tools/extractdwrflnfo.lpi0000644000175000001440000000357214743153644017677 0ustar alexxusers doublecmd-1.1.22/tools/extractdwrflnfo.lpr0000755000175000001440000000440114743153644017703 0ustar alexxusers{ This file is part of the chelinfo library. Copyright (c) 2008 by Anton Rzheshevski Dwarf LineInfo Extractor See the file COPYING.FPC, included in this distribution, for details about the copyright. 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. **********************************************************************} { 2008, Anton Rzheshevski aka Cheb: Like dr. Frankenshtein I sewn this library together from the dead meat of the the FPC RTL modules lineinfo.pp and lnfodwrf.pp. These (as of Jan. 2008 / FPC 2.2.0) both didn't work and had several limitations (e.g. inability to be used from a DLL) } {note: DON'T FORGET to compile your program with the -gw key Lazarus: you must type it in Project -> Compiler Options -> Other -> User parameters } {$mode delphi} {$longstrings on} {$ifndef unix} {$apptype console} {$endif} //extracts the line info in the dwarf format from the executable program extractdwrflnfo; uses SysUtils, Classes, un_xtrctdwrflnfo, zstream; var _dwarf: pointer; DwarfSize, CompressedDwarfSize: QWord; base_addr: QWord; f: TFileStream; CS: TCompressionStream; dllname, iname: ansistring; begin if Paramcount = 0 then begin WriteLn('Usage: ' + ExtractFileName(GetModuleName(0)) + ' '); exit; end; dllname:= ParamStr(1); WriteLn('Extracting Dwarf line info from ', dllname); try iname:= DlnNameByExename(dllname); if ExtractDwarfLineInfo(dllname, _dwarf, DwarfSize, base_addr) then begin f:= TFileStream.Create(iname , fmCreate); CS:= TCompressionStream.Create(clMax, f); CS.Write(dwarfsize, sizeof(dwarfsize)); // 8 bytes (QWORD) CS.Write(base_addr, sizeof(base_addr)); // 8 bytes (QWORD) CS.Write(_dwarf^, dwarfsize); CS.Free; CompressedDwarfSize := f.Size; f.free; WriteLn('Ok, saved ', CompressedDwarfSize, ' bytes to ', iname); end else begin if FileExists(iname) then DeleteFile(iname); WriteLn('Error: ' + ExtractDwarfLineInfoError); end; except WriteLn((ExceptObject as Exception).Message); end; end. doublecmd-1.1.22/tools/fsgenerator/0000755000175000001440000000000014743153644016265 5ustar alexxusersdoublecmd-1.1.22/tools/fsgenerator/fsgenerator.lpi0000644000175000001440000000363014743153644021314 0ustar alexxusers doublecmd-1.1.22/tools/fsgenerator/fsgenerator.lpr0000644000175000001440000000637614743153644021337 0ustar alexxusers{ Filesystem traffic generator ------------------------------------------------------------------------- Creates, modifies, removes files, quickly and in large quantities. Useful for testing how a program behaves when there's a lot of traffic happening on the file system. Copyright (C) 2010-2012 Przemysław Nagay (cobines@gmail.com) 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 } program fsgenerator; {$mode objfpc}{$H+} uses SysUtils, Classes, Windows; var Path: UTF8String; fs: TFileStream; filenames: TStringList; nr: Integer; buffer: array[0..16383] of byte; procedure GenNames; var i, j: Integer; name: String; begin for i := 0 to Random(1000) do begin name := ''; for j := 0 to random(100) do name := name + chr(random(ord('z') - ord('a')) + ord('a')); filenames.Add(name); end; end; function RandomName: String; begin Result := Path + filenames[Random(Filenames.Count)]; end; procedure Create(name: String); begin fs := TFileStream.Create(name, fmCreate); fs.Write(buffer, random(sizeof(buffer))); fs.Free; end; procedure Modify(name: String); var P: Int64; count: Int64; Mode: Word; size: int64; begin if not FileExists(name) then mode := fmCreate else mode := fmOpenReadWrite; fs := TFileStream.Create(Name, mode); if mode = fmCreate then begin fs.Write(buffer, random(sizeof(buffer))); fs.Seek(0, soBeginning); end; size := fs.size; p := random(size); fs.Seek(p, soBeginning); count := min(sizeof(buffer),random(size-p)); fs.Write(buffer, count); //writeln('writing ',count, ' p=',p,' size=',size); fs.Free; end; procedure Delete(name: String); begin if FileExists(Name) then Sysutils.DeleteFile(Name); end; begin if Paramcount = 0 then begin WriteLn('File system traffic generator.'); WriteLn('Creates, modifies, removes files, quickly and in large quantities.'); Writeln; WriteLn('Usage:'); WriteLn(ExtractFileName(ParamStr(0)) + ' '); Exit; end; FileNames := TStringList.Create; GenNames; Path := IncludeTrailingPathDelimiter(ParamStr(1)); ForceDirectories(Path); WriteLn('Starting changing ', Path); while True do begin case Random(6) of 0: Sleep(10); 1: Modify(RandomName); 2: Create(RandomName); 3: Modify(RandomName); 4: Delete(RandomName); 5: Modify(RandomName); end; Sleep(10); if (GetKeyState(VK_SPACE) < 0) or (GetKeyState(VK_SHIFT) < 0) or (GetKeyState(VK_ESCAPE) < 0) then Break; end; WriteLn('Finished changing'); Filenames.Free; end. doublecmd-1.1.22/tools/jsonpack/0000755000175000001440000000000014743153644015556 5ustar alexxusersdoublecmd-1.1.22/tools/jsonpack/jsonpack.lpi0000644000175000001440000000275014743153644020100 0ustar alexxusers <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes> <Item Name="Default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> </RunParams> <Units> <Unit> <Filename Value="jsonpack.lpr"/> <IsPartOfProject Value="True"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="jsonpack"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> ������������������������doublecmd-1.1.22/tools/jsonpack/jsonpack.lpr��������������������������������������������������������0000644�0001750�0000144�00000002116�14743153644�020105� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program jsonpack; {$mode objfpc}{$H+} uses {$IFDEF UNIX} cthreads, {$ENDIF} SysUtils, Classes, JsonParser, fpJson; var AFileName: String; AConfig: TJSONData; AStream: TFileStream; AOptions: TFormatOptions; begin if ParamStr(1) = '-c' then begin AOptions:= AsCompactJSON; end else if ParamStr(1) = '-d' then begin AOptions:= [foDoNotQuoteMembers] end else begin WriteLn; WriteLn(ExtractFileName(ParamStr(0)), ' <Options> <json-file>'); WriteLn; WriteLn('Options:'); WriteLn(' -c compress json-file'); WriteLn(' -d decompress json-file'); WriteLn; Exit; end; AFileName:= ParamStr(2); AStream:= TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone); try AConfig:= GetJSON(AStream, True); finally AStream.Free; end; try with TStringList.Create do try Text:= AConfig.FormatJSON(AOptions); SaveToFile(AFileName); finally Free; end; finally AConfig.Free; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/units/�����������������������������������������������������������������������������0000755�0001750�0000144�00000000000�14743153644�013750� 5����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������doublecmd-1.1.22/units/dcrevision.inc���������������������������������������������������������������0000644�0001750�0000144�00000000126�14743153644�016607� 0����������������������������������������������������������������������������������������������������ustar �alexx���������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Created by Git2RevisionInc const dcRevision = '662'; const dcCommit = '6baafba86'; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������